[
  {
    "path": ".dockerignore",
    "content": ".tox\n.pytest_cache\nbuild\ndist\nhtmlcov\ntac.egg-info\nlog*.txt\n"
  },
  {
    "path": ".firebaserc",
    "content": "{\n  \"projects\": {\n    \"default\": \"fetch-docs-preview\"\n  }\n}\n"
  },
  {
    "path": ".gitattributes",
    "content": "# Set the default behavior, in case people don't have core.autocrlf set.\n* text=auto\n\n# Explicitly declare text files you want to always be normalized and converted\n# to native line endings on checkout.\n# <pattern> text\n\n# Declare files that will always have CRLF line endings on checkout.\n# <pattern> text eol=crlf\n\n# Declare files that will always have LF line endings on checkout.\n*.css           text eol=lf\n*.html          text eol=lf\n*.java          text eol=lf\n*.js            text eol=lf\n*.json          text eol=lf\n*.properties    text eol=lf\n*.txt           text eol=lf\n*.xml           text eol=lf\n*.py            text eol=lf\n*.yaml          text eol=lf\n*.md            text eol=lf\n\n# Denote all files that are truly binary and should not be modified.\n*.class         binary\n*.jar           binary\n*.gif           binary\n*.jpg           binary\n*.png           binary\n*.ico           binary\n"
  },
  {
    "path": ".github/CODEOWNERS",
    "content": "*       @5A11 @jrriehl\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug-report.yml",
    "content": "name: 🐛 Bug Report\ndescription: Report a reproducible bug\ntitle: \"<Short description of the bug>\"\nlabels: [\"bug\", \"unconfirmed\"]\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        Thank you for reporting the issue you are facing. Please complete this form so we can have the necessary information to assist you.\n  - type: checkboxes\n    id: prerequisites\n    attributes:\n      label: Prerequisites\n      description: Please confirm before submitting a new issue\n      options:\n        - label: I am running the [latest version of the AEA Framework](https://docs.fetch.ai/aea/version/).\n          required: true\n        - label: I checked the [documentation](https://docs.fetch.ai/aea/) and found no answer to my problem.\n          required: true\n        - label: I checked the [existing issues](https://github.com/fetchai/agents-aea/issues) to make sure my problem has not already been reported.\n          required: true\n        - label: I have read the [code of conduct](https://github.com/fetchai/agents-aea/blob/main/CODE_OF_CONDUCT.md) before creating this issue.\n          required: true\n  - type: textarea\n    id: expected\n    attributes:\n      label: Expected Behavior\n      description: Describe the behavior you are expecting\n    validations:\n      required: true\n  - type: textarea\n    id: actual\n    attributes:\n      label: Current Behavior\n      description: Describe the current behavior\n    validations:\n      required: true\n  - type: textarea\n    id: steps\n    attributes:\n      label: To Reproduce\n      description: Detailed steps for reproducing the issue\n    validations:\n      required: false\n  - type: textarea\n    id: context\n    attributes:\n      label: Context\n      description: Any relevant information about your setup (this is important in case the issue is not reproducible except under certain conditions)\n      placeholder: |\n        Operating system [e.g. MacOS], Python version [e.g. 3.8.5], AEA version [e.g. 1.2.0], ...\n    validations:\n      required: false\n  - type: textarea\n    id: logs\n    attributes:\n      label: Failure Logs\n      description: Include any relevant log snippets or files here\n    validations:\n      required: false\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature-request.yml",
    "content": "name: ☝️ Feature request\ndescription: Suggest an idea for this project\ntitle: \"<Short description of the feature>\"\nlabels: [\"feature-request\", \"unconfirmed\"]\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        Thank you for suggesting a new idea for the AEA project. Please complete this form so we can have the necessary information about the feature you are requesting.\n  - type: checkboxes\n    id: prerequisites\n    attributes:\n      label: Prerequisites\n      description: Please confirm before submitting a feature request.\n      options:\n        - label: I checked the [documentation](https://docs.fetch.ai/aea/) and made sure this feature does not already exist.\n          required: true\n        - label: I checked the [existing issues](https://github.com/fetchai/agents-aea/issues) to make sure this feature has not already been requested.\n          required: true\n        - label: I have read the [code of conduct](https://github.com/fetchai/agents-aea/blob/main/CODE_OF_CONDUCT.md) before creating this issue.\n          required: true\n  - type: textarea\n    id: problem\n    attributes:\n      label: Problem\n      description: |\n        If your feature request relates to a problem, provide a description here, e.g. I'm always frustrated when [...]\n    validations:\n      required: false\n  - type: textarea\n    id: solution\n    attributes:\n      label: Feature / Solution\n      description: |\n        Provide a description of what you want to happen\n    validations:\n      required: true\n  - type: textarea\n    id: alternatives\n    attributes:\n      label: Alternatives\n      description: |\n        Provide any alternative solutions or features you've considered\n  - type: textarea\n    id: info\n    attributes:\n      label: Additional Context\n      description: |\n        Any other context or screenshots about the feature request\n    validations:\n      required: false\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE/release.md",
    "content": "## Release summary\n\nVersion number: [e.g. 1.0.1]\n\n## Release details\n\nDescribe in short the main changes with the new release.\n\n## Checklist\n\n_Put an `x` in the boxes that apply._\n\n- [ ] I am making a pull request against the `main` branch from `develop`.\n- [ ] Lint and unit tests pass locally.\n- [ ] I have checked the fingerprint hashes are correct by running (`scripts/generate_ipfs_hashes.py`).\n- [ ] I have regenerated and updated the latest API docs.\n- [ ] I built the documentation and updated it with the latest changes.\n- [ ] I have added an item in `HISTORY.md` for this release.\n- [ ] I bumped the version number in the `aea/__version__.py` file.\n- [ ] I bumped the version number in every Docker image of the repo and published it. Also, I built and published them with tag `latest`  \n      (check the READMEs of [`aea-develop`](https://github.com/fetchai/agents-aea/blob/master/develop-image/README.md#publish)\n      and [`aea-user`](https://github.com/fetchai/agents-aea/blob/master/develop-image/user-image/README.md#publish))\n- [ ] I have pushed the latest packages to the registry.\n- [ ] I have uploaded the latest `aea` to PyPI.\n- [ ] I have uploaded the latest plugins to PyPI.\n\n## Further comments\n\nWrite here any other comment about the release, if any.\n"
  },
  {
    "path": ".github/dependabot.yml",
    "content": "version: 2\nupdates:\n\n  # Maintain dependencies for Pip\n  - package-ecosystem: \"pip\"\n    directory: \".\"\n    schedule:\n      interval: \"weekly\"\n    target-branch: \"develop\"\n    labels:\n      - \"dependencies\"\n"
  },
  {
    "path": ".github/pull_request_template.md",
    "content": "## Proposed changes\n\nDescribe the changes here.\n\n## Issues\n\nLinks to any issues resolved.\n\n## Types of changes\n\nWhat types of changes does your code introduce to agents-aea?\n_Put an `x` in the boxes that apply_\n\n- [ ] Bugfix (non-breaking change that fixes an issue)\n- [ ] New feature (non-breaking change that adds functionality)\n- [ ] Breaking change (fix or feature that would cause existing functionality to stop working as expected)\n- [ ] Something else (e.g. test, package, script, example, deployment, infrastructure, ...)\n\n## Checklist\n\n_Put an `x` in the boxes that apply._\n\n- [ ] I have read the [CONTRIBUTING](https://github.com/fetchai/agents-aea/blob/main/CONTRIBUTING.md) document.\n- [ ] I have based my branch, and I am making a pull request against, the `develop` branch.\n- [ ] Lint and unit tests pass locally with my changes.\n\n### If applicable\n\n- [ ] I have added tests that prove my fix is effective or that my feature works.\n- [ ] I have checked that code coverage does not decrease.\n- [ ] I have added/updated the documentations.\n- [ ] Dependent changes have been merged and published in downstream modules.\n\n## Further comments\n\nIf this is a relatively large or complex change, kick off the discussion by explaining why you chose the solution you did, what alternatives you considered, etc.\n"
  },
  {
    "path": ".github/workflows/codeql-analysis.yml",
    "content": "# For most projects, this workflow file will not need changing; you simply need\n# to commit it to your repository.\n#\n# You may wish to alter this file to override the set of languages analyzed,\n# or to provide custom queries or build logic.\n#\n# ******** NOTE ********\n# We have attempted to detect the languages in your repository. Please check\n# the `language` matrix defined below to confirm you have the correct set of\n# supported CodeQL languages.\n#\nname: \"CodeQL\"\n\non:\n  push:\n    branches: [ main, develop ]\n  pull_request:\n    # The branches below must be a subset of the branches above\n    branches: [ main ]\n  schedule:\n    - cron: '35 1 * * 0'\n\njobs:\n  analyze:\n    name: Analyze\n    runs-on: ubuntu-latest\n\n    strategy:\n      fail-fast: false\n      matrix:\n        language: [ 'go', 'javascript', 'python' ]\n        # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]\n        # Learn more:\n        # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed\n\n    steps:\n    - name: Checkout repository\n      uses: actions/checkout@v3\n\n    # Initializes the CodeQL tools for scanning.\n    - name: Initialize CodeQL\n      uses: github/codeql-action/init@v1\n      with:\n        languages: ${{ matrix.language }}\n        # If you wish to specify custom queries, you can do so here or in a config file.\n        # By default, queries listed here will override any specified in a config file.\n        # Prefix the list here with \"+\" to use these queries and those in the config file.\n        # queries: ./path/to/local/query, your-org/your-repo/queries@main\n\n    # Autobuild attempts to build any compiled languages  (C/C++, C#, or Java).\n    # If this step fails, then you should remove it and run the build manually (see below)\n    - name: Autobuild\n      uses: github/codeql-action/autobuild@v1\n\n    # ℹ️ Command-line programs to run using the OS shell.\n    # 📚 https://git.io/JvXDl\n\n    # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines\n    #    and modify them (or add more) to build your code if your project\n    #    uses a compiled language\n\n    #- run: |\n    #   make bootstrap\n    #   make release\n\n    - name: Perform CodeQL Analysis\n      uses: github/codeql-action/analyze@v1\n"
  },
  {
    "path": ".github/workflows/docs_pr_preview.yml",
    "content": "name: Documentation Preview\n\non:\n  pull_request:\n    branches:\n      - master\n      - develop\n    paths:\n      - 'docs/**'\n\njobs:\n  build:\n    name: Docs Ephemerial Build\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v3\n        with:\n          fetch-depth: 0\n\n      - name: Use python 3.7\n        uses: actions/setup-python@v4\n        with:\n          python-version: '3.7'\n\n      - name: Install Dependencies\n        run: cd docs && pip3 install pipenv && pipenv install -d --skip-lock --python python3\n\n      - name: Build\n        run: cd docs && pipenv run mkdocs build -f ../mkdocs.yml\n\n      - name: Archive Production Artifact\n        uses: actions/upload-artifact@master\n        with:\n          name: dist\n          path: site\n\n\n  deploy:\n    name: Docs Ephemerial Deploy\n    needs: build\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v3\n\n      - name: Download Artifact\n        uses: actions/download-artifact@master\n        with:\n          name: dist\n          path: site\n\n      - uses: FirebaseExtended/action-hosting-deploy@v0\n        with:\n          repoToken: \"${{ secrets.GITHUB_TOKEN }}\"\n          firebaseServiceAccount: \"${{ secrets.FIREBASE_SERVICE_ACCOUNT }}\"\n          expires: 2d\n          projectId: fetch-docs-preview\n          # entryPoint: docs/\n"
  },
  {
    "path": ".github/workflows/publish.yaml",
    "content": "name: Build, Publish and Deploy Docker Container\n\non:\n  push:\n    branches:\n      - develop\n      - main\n\njobs:\n  publish:\n    runs-on: ubuntu-latest\n    timeout-minutes: 30\n\n    steps:\n    - name: Checkout\n      uses: actions/checkout@v3\n \n    - name: Setup GCloud - sandbox\n      uses: google-github-actions/setup-gcloud@v0\n      if: github.ref == 'refs/heads/develop'\n      with:\n          project_id: ${{ secrets.GCLOUD_FETCH_AI_SANDBOX_PROJECT }}\n          service_account_key: ${{ secrets.GCLOUD_FETCH_AI_SANDBOX_KEY }}\n\n    - name: Setup GCloud - production\n      uses: google-github-actions/setup-gcloud@v0\n      if: github.ref == 'refs/heads/main'\n      with:\n          project_id: ${{ secrets.GCLOUD_FETCH_AI_PROD_PROJECT }}\n          service_account_key: ${{ secrets.GCLOUD_FETCH_AI_PROD_KEY }}\n\n    - name: Configure Docker\n      run: |\n        gcloud auth configure-docker\n    \n    - name: Set Image Tag\n      id: vars\n      run: echo \"::set-output name=sha_short::$(git rev-parse --short HEAD)\"\n    \n    # Push image to Google Container Registry\n    - name: Build and Push Images\n      run: |\n        chmod +x ./scripts/acn/build_upload_img.sh\n        \n        if [ ${{ github.ref }} == 'refs/heads/develop' ]\n        then\n          ./scripts/acn/build_upload_img.sh\n        fi\n\n        if [ ${{ github.ref }} == 'refs/heads/main' ]\n        then\n          ./scripts/acn/build_upload_img.sh prod\n        fi\n\n    - name: Repository Dispatch\n      env:\n        IMAGE_TAG: ${{ steps.vars.outputs.sha_short }}\n      run: |\n        if [ ${{ github.ref }} == 'refs/heads/develop' ]\n        then\n          curl -H \"Accept: application/vnd.github.everest-preview+json\" \\\n          -H \"Authorization: token ${{ secrets.GH_PAT }}\" \\\n          --request POST \\\n          --data '{\"event_type\": \"agents-dht-testnet\", \"client_payload\": {\"image\": \"gcr.io/fetch-ai-sandbox/acn_node\", \"tag\": \"'\"$IMAGE_TAG\"'\"}}' \\\n          https://api.github.com/repos/fetchai/infra-sandbox-london-b-deployment/dispatches\n        fi\n\n        if [ ${{ github.ref }} == 'refs/heads/main' ]\n        then\n          curl -H \"Accept: application/vnd.github.everest-preview+json\" \\\n          -H \"Authorization: token ${{ secrets.GH_PAT }}\" \\\n          --request POST \\\n          --data '{\"event_type\": \"agents-dht\", \"client_payload\": {\"image\": \"gcr.io/fetch-ai-images/acn_node\", \"tag\": \"'\"$IMAGE_TAG\"'\"}}' \\\n          https://api.github.com/repos/fetchai/infra-mainnet-v2-deployment/dispatches\n        fi\n"
  },
  {
    "path": ".github/workflows/upload_docker_images.yaml",
    "content": "name: Build and upload develop-image to docker hub\n\non:\n  push:\n    branches: [ main ]\n\njobs:\n  build:\n    env:\n     BASE_TAG: fetchai/aea-develop\n    runs-on: ubuntu-latest\n    steps:\n    - uses: actions/checkout@v3\n    - name: Set up tag\n      run: echo export TAG=${BASE_TAG}:$(python3 -c \"from setup import about; print(about[\\\"__version__\\\"])\") > env.sh\n    - name: docker login\n      env:\n        DOCKER_USER: ${{secrets.DOCKER_USER}}\n        DOCKER_PASSWORD: ${{secrets.DOCKER_PASSWORD}}\n      run: |\n        docker login -u $DOCKER_USER -p $DOCKER_PASSWORD \n    - name: Build the Docker image\n      run: |\n        source env.sh\n        docker build . -f ./develop-image/Dockerfile --tag $TAG\n    - name: Tag to latest\n      run:  |\n        source env.sh\n        docker tag $TAG $BASE_TAG:latest\n    - name: Docker Push\n      run: |\n        source env.sh\n        docker push $TAG\n        docker push $BASE_TAG:latest"
  },
  {
    "path": ".github/workflows/workflow.yml",
    "content": "name: AEA framework sanity checks and tests\n\non: pull_request\n\njobs:\n  python_checks:\n    continue-on-error: False\n    runs-on: '${{ matrix.os }}'\n    strategy:\n      matrix:\n        os:\n          - ubuntu-latest\n        python-version:\n          - '3.8'\n        tox-job:\n          - check_plugins_code_consistency\n          - check_go_code_consistency\n          - bandit\n          - safety\n          - black-check\n          - isort-check\n          - flake8\n          - vulture\n          - mypy\n          - pylint\n    timeout-minutes: 30\n    steps:\n      - uses: actions/checkout@v3\n      - uses: actions/setup-python@v4\n        with:\n          python-version: '${{ matrix.python-version }}'\n      - name: Install dependencies\n        run: pip install tox==3.25.1\n      - name: 'Run check ${{ matrix.tox-job }}'\n        run: |\n          tox -e ${{ matrix.tox-job }}\n\n  go_checks:\n    continue-on-error: False\n    runs-on: ubuntu-latest\n    timeout-minutes: 20\n    steps:\n      - uses: actions/checkout@v3\n      - uses: actions/setup-python@v4\n        with:\n          python-version: 3.8\n      - uses: actions/setup-go@v3\n        with:\n          go-version: \"^1.17.0\"\n      - name: Install dependencies (ubuntu-latest)\n        run: |\n          sudo apt-get update --fix-missing\n          sudo apt-get install libmbedtls-dev\n          sudo apt-get autoremove\n          sudo apt-get autoclean\n      - name: Golang code style check (libp2p_node)\n        uses: golangci/golangci-lint-action@v3.1.0\n        env:\n          ACTIONS_ALLOW_UNSECURE_COMMANDS: true\n        with:\n          version: v1.48.0\n          working-directory: libs/go/libp2p_node\n      - name: Golang code style check (aealite)\n        uses: golangci/golangci-lint-action@v3.1.0\n        env:\n          ACTIONS_ALLOW_UNSECURE_COMMANDS: true\n        with:\n          version: v1.48.0\n          working-directory: libs/go/aealite\n\n  misc_checks:\n    runs-on: ubuntu-latest\n    continue-on-error: False\n    timeout-minutes: 10\n    strategy:\n      matrix:\n        python-version:\n          - '3.8'\n        tox-job:\n          - liccheck\n          - copyright_check\n          - hash_check -- --timeout 40.0\n          - package_version_checks\n          - package_dependencies_checks\n          - check_generate_all_protocols\n          - docs\n    steps:\n      - uses: actions/checkout@v3\n      - uses: actions/setup-python@v4\n        with:\n          python-version: '${{ matrix.python-version }}'\n      - uses: actions/setup-go@v3\n        with:\n          go-version: \"^1.17.0\"\n      - name: Install dependencies (ubuntu-latest)\n        run: |\n          sudo apt-get update --fix-missing\n          sudo apt-get install libmbedtls-dev\n          sudo apt-get autoremove\n          sudo apt-get autoclean\n          pip install --user --upgrade setuptools\n          # install Protobuf compiler\n          wget https://github.com/protocolbuffers/protobuf/releases/download/v3.19.4/protoc-3.19.4-linux-x86_64.zip\n          unzip protoc-3.19.4-linux-x86_64.zip -d protoc\n          sudo mv protoc/bin/protoc /usr/local/bin/protoc\n          # install IPFS\n          sudo apt-get install -y wget\n          wget -O ./go-ipfs.tar.gz https://dist.ipfs.io/go-ipfs/v0.6.0/go-ipfs_v0.6.0_linux-amd64.tar.gz\n          tar xvfz go-ipfs.tar.gz\n          sudo mv go-ipfs/ipfs /usr/local/bin/ipfs\n          ipfs init\n          make protolint_install\n      - name: Install dependencies\n        run: pip install tox==3.25.1\n      - name: 'Run check ${{ matrix.tox-job }}'\n        run: |\n          tox -e ${{ matrix.tox-job }}\n      \n  misc_checks_extra:\n    continue-on-error: False\n    runs-on: ubuntu-latest\n    timeout-minutes: 10\n    steps:\n      - uses: actions/checkout@v3\n      - uses: actions/setup-python@v4\n        with:\n          python-version: 3.8\n      - uses: actions/setup-go@v3\n        with:\n          go-version: \"^1.17.0\"\n      - name: Install dependencies (ubuntu-latest)\n        run: |\n          sudo apt-get update --fix-missing\n          sudo apt-get install libmbedtls-dev\n          sudo apt-get autoremove\n          sudo apt-get autoclean\n          pip install tox\n      - name: Check copyright year is up to date\n        run: |\n          ./scripts/bump_year.sh $(date +%Y)\n          git diff --quiet||(echo \"Some files have the incorrect year in their copyright header. Run ./scripts/bump_year.sh!\"; exit 1)\n          echo \"all good\"\n\n  docs_check:\n    continue-on-error: False\n    runs-on: ubuntu-latest\n    timeout-minutes: 10\n    steps:\n      - uses: actions/checkout@v3\n      - uses: actions/setup-python@v4\n        with:\n          python-version: 3.8\n      - uses: actions/setup-node@v1\n        with:\n          node-version: 12.x\n      - name: Install dependencies (ubuntu-latest)\n        run: |\n          sudo apt-get update --fix-missing\n          sudo apt-get install libmbedtls-dev\n          sudo apt-get autoremove\n          sudo apt-get autoclean\n          pip install tox\n      - name: Install markdown-spellcheck\n        run: sudo npm install -g markdown-spellcheck\n      - name: Check Docs links\n        run: tox -e check-doc-links\n      - name: Check API Docs updated\n        run: tox -e check_api_docs\n      - name: Check spelling\n        run: tox -e spell_check\n\n  plugins_install:\n    continue-on-error: False\n    runs-on: ${{ matrix.sys.os }}\n    strategy:\n      matrix:\n        sys:\n          - { os: windows-latest, shell: \"msys2 {0}\" }\n          - { os: ubuntu-latest, shell: bash }\n          - { os: macos-latest, shell: bash }\n        python_version: [3.8]\n    timeout-minutes: 10\n    steps:\n      - uses: actions/checkout@v3\n      - if: matrix.sys.os == 'windows-latest'\n        uses: msys2/setup-msys2@v2\n      - uses: actions/setup-python@v4\n        with:\n          python-version: ${{ matrix.python_version }}\n      - if: matrix.os == 'ubuntu-latest'\n        name: Install dependencies (ubuntu-latest)\n        run: |\n          sudo apt-get update --fix-missing\n          sudo apt-get install libmbedtls-dev\n          sudo apt-get autoremove\n          sudo apt-get autoclean\n      - name: Install tox\n        run: |\n          pip install tox==3.28.0\n      - name: Check plugin aea-ledger-cosmos\n        run: |\n          tox -r -e plugins_env -- sh -c \"pip install ./plugins/aea-ledger-cosmos && aea generate-key cosmos && echo aea-ledger-cosmos checked!\"\n      - name: Check plugin aea-ledger-ethereum\n        run: |\n          tox -r -e plugins_env -- sh -c \"pip install ./plugins/aea-ledger-ethereum && aea generate-key ethereum && echo aea-ledger-ethereum checked!\"\n      - name: Check plugin aea-ledger-fetchai\n        run: |\n          tox -r -e plugins_env -- sh -c \"pip install ./plugins/aea-ledger-fetchai && aea generate-key fetchai && echo aea-ledger-fetchai checked!\"\n      - name: Check plugin aea-cli-ipfs\n        run: |\n          tox -r -e plugins_env -- sh -c \"pip install ./plugins/aea-cli-ipfs && aea ipfs --help && echo aea-cli-ipfs checked!\"\n\n  protolint:\n    continue-on-error: False\n    runs-on: ubuntu-latest\n    timeout-minutes: 10\n    steps:\n      - uses: actions/checkout@v3\n      - uses: actions/setup-python@v4\n        with:\n          python-version: 3.8\n      - uses: actions/setup-go@v3\n        with:\n          go-version: \"^1.17.0\"\n      - name: Install protolint (ubuntu-latest)\n        run: |\n          sudo apt-get update --fix-missing\n          sudo apt-get autoremove\n          sudo apt-get autoclean\n          make protolint_install\n      - name: Protolint check\n        run: |\n          make protolint\n\n  integration_tests:\n    if: github.base_ref == 'main'\n    continue-on-error: True\n    needs:\n      - python_checks\n      - go_checks\n      - misc_checks\n      - misc_checks_extra\n      - plugins_install\n    runs-on: ubuntu-latest\n    timeout-minutes: 60\n    steps:\n      - uses: actions/checkout@v3\n      - uses: actions/setup-python@v4\n        with:\n          python-version: 3.8\n      - uses: actions/setup-go@v3\n        with:\n          go-version: \"^1.17.0\"\n      - name: Setup GCloud - production\n        uses: google-github-actions/setup-gcloud@v0\n        with:\n          project_id: ${{ secrets.GCLOUD_FETCH_AI_PROD_PROJECT }}\n          service_account_key: ${{ secrets.GCLOUD_FETCH_AI_PROD_KEY }}\n      - name: Install dependencies (ubuntu-latest)\n        run: |\n          sudo apt-get update --fix-missing\n          sudo apt-get install libmbedtls-dev\n          sudo apt-get autoremove\n          sudo apt-get autoclean\n          pip install tox\n          # install Protobuf compiler\n          wget https://github.com/protocolbuffers/protobuf/releases/download/v3.19.4/protoc-3.19.4-linux-x86_64.zip\n          unzip protoc-3.19.4-linux-x86_64.zip -d protoc\n          sudo mv protoc/bin/protoc /usr/local/bin/protoc\n      - name: Configure Docker\n        run: |\n          gcloud auth configure-docker\n      - name: Pull SOEF Image\n        run: |\n          docker pull gcr.io/fetch-ai-images/soef:9e78611 # change this to latest tag\n      - name: Pull fetchd\n        run: |\n          docker pull fetchai/fetchd:0.10.2\n      - name: Pull ganache\n        run: |\n          docker pull trufflesuite/ganache-cli:latest\n      - name: Async integration tests\n        run: tox -e py3.8 -- -m 'integration and not unstable and not ledger' ./tests --ignore=tests/test_aea_core_packages\n\n\n  core_packages_tests:\n    # tests intersection with ledger and integration\n    # limited tests set for quick checking primary functionality of the AEA\n    continue-on-error: True\n    needs:\n      - python_checks\n      - go_checks\n      - misc_checks\n      - misc_checks_extra\n      - plugins_install\n    runs-on: ubuntu-latest\n    timeout-minutes: 60\n    steps:\n      - uses: actions/checkout@v3\n      - uses: actions/setup-python@v4\n        with:\n          python-version: 3.8\n      - uses: actions/setup-go@v3\n        with:\n          go-version: \"^1.17.0\"\n      - name: Setup GCloud - production\n        uses: google-github-actions/setup-gcloud@v0\n        with:\n          project_id: ${{ secrets.GCLOUD_FETCH_AI_PROD_PROJECT }}\n          service_account_key: ${{ secrets.GCLOUD_FETCH_AI_PROD_KEY }}\n      - name: Install dependencies (ubuntu-latest)\n        run: |\n          sudo apt-get update --fix-missing\n          sudo apt-get install libmbedtls-dev\n          sudo apt-get autoremove\n          sudo apt-get autoclean\n          pip install tox\n          # install Protobuf compiler\n          wget https://github.com/protocolbuffers/protobuf/releases/download/v3.19.4/protoc-3.19.4-linux-x86_64.zip\n          unzip protoc-3.19.4-linux-x86_64.zip -d protoc\n          sudo mv protoc/bin/protoc /usr/local/bin/protoc\n      - name: Configure Docker\n        run: |\n          gcloud auth configure-docker\n      - name: Pull SOEF Image\n        run: |\n          docker pull gcr.io/fetch-ai-images/soef:9e78611 # change this to latest tag\n      - name: Pull fetchd\n        run: |\n          docker pull fetchai/fetchd:0.10.2\n      - name: Pull ganache\n        run: |\n          docker pull trufflesuite/ganache-cli:latest\n      - name: Async integration tests\n        run: tox -e py3.8 -- tests/test_aea_core_packages/\n\n  integration_ledger_tests:\n    if: github.base_ref == 'main'\n    continue-on-error: True\n    needs:\n      - python_checks\n      - go_checks\n      - misc_checks\n      - misc_checks_extra\n      - plugins_install\n    runs-on: ubuntu-latest\n    timeout-minutes: 60\n    steps:\n      - uses: actions/checkout@v3\n      - uses: actions/setup-python@v4\n        with:\n          python-version: 3.8\n      - name: Setup GCloud - production\n        uses: google-github-actions/setup-gcloud@v0\n        with:\n          project_id: ${{ secrets.GCLOUD_FETCH_AI_PROD_PROJECT }}\n          service_account_key: ${{ secrets.GCLOUD_FETCH_AI_PROD_KEY }}\n      - name: Install dependencies (ubuntu-latest)\n        run: |\n          sudo apt-get update --fix-missing\n          sudo apt-get autoremove\n          sudo apt-get autoclean\n          pip install tox\n      - name: Configure Docker\n        run: |\n          gcloud auth configure-docker\n      - name: Pull SOEF Image\n        run: |\n          docker pull gcr.io/fetch-ai-images/soef:9e78611 # change this to latest tag\n      - name: Integration tests\n        run: tox -e py3.8 -- -m 'integration and not unstable and ledger' ./tests --ignore=tests/test_aea_core_packages\n\n  aea-tests:\n    continue-on-error: True\n    needs:\n      - python_checks\n      - go_checks\n      - misc_checks\n      - misc_checks_extra\n      - plugins_install\n    runs-on: ${{ matrix.os }}\n    strategy:\n      matrix:\n        os: [ubuntu-latest, macos-latest, windows-latest]\n        python_version: [3.8, 3.9, \"3.10\"]\n    timeout-minutes: 90\n    steps:\n      - uses: actions/checkout@v3\n      - uses: actions/setup-python@v4\n        with:\n          python-version: ${{ matrix.python_version }}\n      - uses: actions/setup-go@v3\n        with:\n          go-version: \"^1.17.0\"\n      - if: matrix.os == 'ubuntu-latest'\n        name: Install dependencies (ubuntu-latest)\n        run: |\n          sudo apt-get update --fix-missing\n          sudo apt-get install libmbedtls-dev\n          sudo apt-get autoremove\n          sudo apt-get autoclean\n          pip install tox\n          # install Protobuf compiler\n          wget https://github.com/protocolbuffers/protobuf/releases/download/v3.19.4/protoc-3.19.4-linux-x86_64.zip\n          unzip protoc-3.19.4-linux-x86_64.zip -d protoc\n          sudo mv protoc/bin/protoc /usr/local/bin/protoc\n          make protolint_install\n      # sudo apt-get install -y protobuf-compiler\n      # use sudo rm /var/lib/apt/lists/lock above in line above update if dependency install failures persist\n      # use sudo apt-get dist-upgrade above in line below update if dependency install failures persist\n      - if: matrix.os == 'macos-latest'\n        name: Install dependencies (macos-latest)\n        run: |\n          pip install tox\n          brew install gcc\n          # brew install protobuf\n          # brew install https://raw.githubusercontent.com/Homebrew/homebrew-core/72457f0166d5619a83f508f2345b22d0617b5021/Formula/protobuf.rb\n          wget https://github.com/protocolbuffers/protobuf/releases/download/v3.19.4/protoc-3.19.4-osx-x86_64.zip\n          unzip protoc-3.19.4-osx-x86_64.zip -d protoc\n          sudo mv protoc/bin/protoc /usr/local/bin/protoc\n          brew tap yoheimuta/protolint\n          brew install protolint\n      - if: matrix.os == 'windows-latest'\n        name: Install dependencies (windows-latest)\n        env:\n          ACTIONS_ALLOW_UNSECURE_COMMANDS: true\n        run: |\n          python -m pip install -U pip\n          echo \"::add-path::C:\\Program Files (x86)\\Windows Kits\\10\\bin\\10.0.18362.0\\x64\"\n          choco install protoc --version 3.19.4\n          choco install mingw -y\n          choco install make -y\n          # to check make was installed\n          make --version\n          pip install tox\n          # wget https://github.com/protocolbuffers/protobuf/releases/download/v3.19.4/protoc-3.19.4-win64.zip\n          # unzip protoc-3.19.4-win64.zip -d protoc\n          # sudo mv protoc/bin/protoc /usr/local/bin/protoc\n          python scripts/update_symlinks_cross_platform.py\n          make protolint_install_win\n          # just check protolint runs\n          protolint version\n      - if: True\n        name: Unit tests\n        run: |\n          tox -e py${{ matrix.python_version }} -- -m 'not integration and not unstable and not ledger' ./tests/test_docs ./tests/test_aea\n      - name: Plugin tests\n        run: |\n          tox -e plugins-py${{ matrix.python_version }} -- -m 'not integration and not unstable'\n  examples-tests:\n    if: github.base_ref == 'main'\n    continue-on-error: True\n    needs:\n      - python_checks\n      - go_checks\n      - misc_checks\n      - misc_checks_extra\n      - plugins_install\n    runs-on: ubuntu-latest\n    timeout-minutes: 90\n    steps:\n      - uses: actions/checkout@v3\n      - uses: actions/setup-python@v4\n        with:\n          python-version: 3.8\n      - uses: actions/setup-go@v3\n        with:\n          go-version: \"^1.17.0\"\n      - name: Install dependencies (ubuntu-latest)\n        run: |\n          sudo apt-get update --fix-missing\n          sudo apt-get autoremove\n          sudo apt-get autoclean\n          pip install tox\n      - name: Unit tests\n        run: tox -e py3.8 -- tests/test_examples\n\n  aea-extras-tests:\n    continue-on-error: True\n    needs:\n      - python_checks\n      - go_checks\n      - misc_checks\n      - misc_checks_extra\n      - plugins_install\n    runs-on: ${{ matrix.os }}\n    strategy:\n      matrix:\n        os: [ubuntu-latest, macos-latest, windows-latest]\n        python_version: [3.8, 3.9, \"3.10\"]\n    timeout-minutes: 90\n    steps:\n      - uses: actions/checkout@v3\n      - uses: actions/setup-python@v4\n        with:\n          python-version: ${{ matrix.python_version }}\n      - uses: actions/setup-go@v3\n        with:\n          go-version: \"^1.17.0\"\n      - if: matrix.os == 'ubuntu-latest'\n        name: Install dependencies (ubuntu-latest)\n        run: |\n          sudo apt-get update --fix-missing\n          sudo apt-get install libmbedtls-dev\n          sudo apt-get autoremove\n          sudo apt-get autoclean\n          pip install tox\n          # install Protobuf compiler\n          wget https://github.com/protocolbuffers/protobuf/releases/download/v3.19.4/protoc-3.19.4-linux-x86_64.zip\n          unzip protoc-3.19.4-linux-x86_64.zip -d protoc\n          sudo mv protoc/bin/protoc /usr/local/bin/protoc\n          make protolint_install\n      # sudo apt-get install -y protobuf-compiler\n      # use sudo rm /var/lib/apt/lists/lock above in line above update if dependency install failures persist\n      # use sudo apt-get dist-upgrade above in line below update if dependency install failures persist\n      - if: matrix.os == 'macos-latest'\n        name: Install dependencies (macos-latest)\n        run: |\n          pip install tox\n          brew install gcc\n          # brew install protobuf\n          # brew install https://raw.githubusercontent.com/Homebrew/homebrew-core/72457f0166d5619a83f508f2345b22d0617b5021/Formula/protobuf.rb\n          wget https://github.com/protocolbuffers/protobuf/releases/download/v3.19.4/protoc-3.19.4-osx-x86_64.zip\n          unzip protoc-3.19.4-osx-x86_64.zip -d protoc\n          sudo mv protoc/bin/protoc /usr/local/bin/protoc\n          brew tap yoheimuta/protolint\n          brew install protolint\n      - if: matrix.os == 'windows-latest'\n        name: Install dependencies (windows-latest)\n        env:\n          ACTIONS_ALLOW_UNSECURE_COMMANDS: true\n        run: |\n          python -m pip install -U pip\n          echo \"::add-path::C:\\Program Files (x86)\\Windows Kits\\10\\bin\\10.0.18362.0\\x64\"\n          choco install protoc --version 3.19.4\n          choco install mingw -y\n          choco install make -y\n          # to check make was installed\n          make --version\n          pip install tox\n          # wget https://github.com/protocolbuffers/protobuf/releases/download/v3.19.4/protoc-3.19.4-win64.zip\n          # unzip protoc-3.19.4-win64.zip -d protoc\n          # sudo mv protoc/bin/protoc /usr/local/bin/protoc\n          python scripts/update_symlinks_cross_platform.py\n          make protolint_install_win\n          # just check protolint runs\n          protolint version\n      - name: Unit tests\n        run: |\n          tox -e py${{ matrix.python_version }} -- ./tests/test_aea_extra\n\n  packages-tests:\n    if: github.base_ref == 'main'\n    continue-on-error: True\n    needs:\n      - python_checks\n      - go_checks\n      - misc_checks\n      - misc_checks_extra\n      - plugins_install\n    runs-on: ${{ matrix.os }}\n    strategy:\n      matrix:\n        os: [ubuntu-latest, macos-latest, windows-latest]\n        python_version: [3.8, 3.9, \"3.10\"]\n    timeout-minutes: 90\n    steps:\n      - uses: actions/checkout@v3\n      - uses: actions/setup-python@v4\n        with:\n          python-version: ${{ matrix.python_version }}\n      - uses: actions/setup-go@v3\n        with:\n          go-version: \"^1.17.0\"\n      - if: matrix.os == 'ubuntu-latest'\n        name: Install dependencies (ubuntu-latest)\n        run: |\n          sudo apt-get update --fix-missing\n          sudo apt-get install libmbedtls-dev\n          sudo apt-get autoremove\n          sudo apt-get autoclean\n          pip install tox\n          # install Protobuf compiler\n          wget https://github.com/protocolbuffers/protobuf/releases/download/v3.19.4/protoc-3.19.4-linux-x86_64.zip\n          unzip protoc-3.19.4-linux-x86_64.zip -d protoc\n          sudo mv protoc/bin/protoc /usr/local/bin/protoc\n          make protolint_install\n      # sudo apt-get install -y protobuf-compiler\n      # use sudo rm /var/lib/apt/lists/lock above in line above update if dependency install failures persist\n      # use sudo apt-get dist-upgrade above in line below update if dependency install failures persist\n      - if: matrix.os == 'macos-latest'\n        name: Install dependencies (macos-latest)\n        run: |\n          pip install tox\n          brew install gcc\n          # brew install protobuf\n          # brew install https://raw.githubusercontent.com/Homebrew/homebrew-core/72457f0166d5619a83f508f2345b22d0617b5021/Formula/protobuf.rb\n          wget https://github.com/protocolbuffers/protobuf/releases/download/v3.19.4/protoc-3.19.4-osx-x86_64.zip\n          unzip protoc-3.19.4-osx-x86_64.zip -d protoc\n          sudo mv protoc/bin/protoc /usr/local/bin/protoc\n          brew tap yoheimuta/protolint\n          brew install protolint\n      - if: matrix.os == 'windows-latest'\n        name: Install dependencies (windows-latest)\n        env:\n          ACTIONS_ALLOW_UNSECURE_COMMANDS: true\n        run: |\n          python -m pip install -U pip\n          echo \"::add-path::C:\\Program Files (x86)\\Windows Kits\\10\\bin\\10.0.18362.0\\x64\"\n          choco install protoc --version 3.19.4\n          choco install mingw -y\n          choco install make -y\n          # to check make was installed\n          make --version\n          pip install tox\n          # wget https://github.com/protocolbuffers/protobuf/releases/download/v3.19.4/protoc-3.19.4-win64.zip\n          # unzip protoc-3.19.4-win64.zip -d protoc\n          # sudo mv protoc/bin/protoc /usr/local/bin/protoc\n          python scripts/update_symlinks_cross_platform.py\n          make protolint_install_win\n          # just check protolint runs\n          protolint version\n      - if: True\n        name: Unit tests\n        run: |\n          tox -e py${{ matrix.python_version }} -- --cov=packages/fetchai/connections --cov=packages/fetchai/contracts  --cov=packages/fetchai/protocols --cov=packages/fetchai/skills  -m 'not integration and not unstable' ./tests/test_packages_for_aea_tests ./tests/test_packages \n\n  golang_tests:\n    continue-on-error: True\n    needs:\n      - go_checks\n    runs-on: ${{ matrix.os }}\n    strategy:\n      matrix:\n        os:\n          - ubuntu-latest\n          - macos-latest\n          - windows-latest\n        python-version: [3.8]\n    timeout-minutes: 45\n    steps:\n      - uses: actions/checkout@v3\n      - uses: actions/setup-python@v4\n        with:\n          python-version: ${{ matrix.python-version }}\n      - uses: actions/setup-go@v3\n        with:\n          go-version: \"^1.17.0\"\n      - if: matrix.os == 'macos-latest'\n        working-directory: ./libs/go/libp2p_node\n        run: |\n          export LINKPATH=`go env GOTOOLDIR`/link\n          echo $LINKPATH\n          sudo cp $LINKPATH ${LINKPATH}_orig\n          sudo cp link $LINKPATH\n          sudo chmod a+x $LINKPATH\n      - if: matrix.python-version == '3.8'\n        name: Golang unit tests (libp2p_node)\n        working-directory: ./libs/go/libp2p_node\n        run: make test\n      - if: matrix.python-version == '3.8'\n        name: Golang unit tests (aealite)\n        working-directory: ./libs/go/aealite\n        run: go test -p 1 -timeout 0 -count 1 -v ./...\n  libp2p_coverage:\n    name: libp2p_coverage\n    runs-on: ubuntu-latest\n    steps:\n      - name: Set up Go 1.17\n        uses: actions/setup-go@v3\n        with:\n          go-version: 1.17\n        id: go\n      - name: Check out code into the Go module directory\n        uses: actions/checkout@v3\n      - name: Install dependencies (ubuntu-latest)\n        run: |\n          sudo apt-get update --fix-missing\n          sudo apt-get install libmbedtls-dev\n          sudo apt-get autoremove\n          sudo apt-get autoclean\n          sudo apt-get install make -y\n      - name: Get dependencies\n        working-directory: ./libs/go/libp2p_node/\n        run: |\n          make install\n      - name: Generate coverage report\n        working-directory: ./libs/go/libp2p_node/\n        run: |\n          make test\n      - name: Print coverage report\n        working-directory: ./libs/go/libp2p_node/\n        run: |\n          go tool cover -func=coverage.txt\n  coverage_checks:\n    continue-on-error: True\n    needs:\n      - python_checks\n      - go_checks\n      - misc_checks\n      - misc_checks_extra\n      - docs_check\n      - plugins_install\n    runs-on: ubuntu-latest\n    timeout-minutes: 60\n    steps:\n      - uses: actions/checkout@v3\n      - uses: actions/setup-python@v4\n        with:\n          python-version: 3.8\n      - uses: actions/setup-go@v3\n        with:\n          go-version: \"^1.17.0\"\n      - name: Install dependencies (ubuntu-latest)\n        run: |\n          sudo apt-get update --fix-missing\n          sudo apt-get install libmbedtls-dev\n          sudo apt-get autoremove\n          sudo apt-get autoclean\n          pip install tox\n          pip install coverage\n          # install Protobuf compiler\n          wget https://github.com/protocolbuffers/protobuf/releases/download/v3.19.4/protoc-3.19.4-linux-x86_64.zip\n          unzip protoc-3.19.4-linux-x86_64.zip -d protoc\n          sudo mv protoc/bin/protoc /usr/local/bin/protoc\n          make protolint_install\n      - name: Run all tests\n        run: |\n          tox -e py3.8-cov -- --ignore=tests/test_docs --ignore=tests/test_examples --ignore=tests/test_packages/test_skills_integration -m 'not unstable'  ./tests\n          tox -e plugins-py3.8-cov -- --cov-append -m 'not unstable'\n        continue-on-error: true\n      - name: Show full coverage report\n        run: |\n          coverage report -m -i\n      - name: Upload coverage to Codecov\n        uses: codecov/codecov-action@v1\n        with:\n          token: ${{ secrets.CODECOV_TOKEN }}\n          file: ./coverage.xml\n          flags: unittests\n          name: codecov-umbrella\n          fail_ci_if_error: false\n"
  },
  {
    "path": ".gitignore",
    "content": "# Byte-compiled / optimized / DLL files\n__pycache__/\n*.py[cod]\n*$py.class\n\n# C extensions\n*.so\n\n# Distribution / packaging\n.Python\nbuild/\ndevelop-eggs/\ndist/\ndownloads/\neggs/\n.eggs/\nlib/\nlib64/\nparts/\nsdist/\nvar/\nwheels/\n*.egg-info/\n.installed.cfg\n*.egg\nMANIFEST\nPipfile.lock\n\n# PyInstaller\n#  Usually these files are written by a python script from a template\n#  before PyInstaller builds the exe, so as to inject date/other infos into it.\n*.manifest\n*.spec\n\n# Installer logs\npip-log.txt\npip-delete-this-directory.txt\n\n# Unit test / coverage reports\nhtmlcov/\n.tox/\n.coverage\n.coverage.*\n.cache\nnosetests.xml\ncoverage.xml\n*.cover\n.hypothesis/\n.pytest_cache/\n\n# Translations\n*.mo\n*.pot\n\n# Django stuff:\n*.log\nlocal_settings.py\ndb.sqlite3\n\n# Flask stuff:\ninstance/\n.webassets-cache\n\n# Scrapy stuff:\n.scrapy\n\n# Sphinx documentation\ndocs/_build/\n\n# PyBuilder\ntarget/\n\n# Jupyter Notebook\n.ipynb_checkpoints\n\n# pyenv\n.python-version\n\n# celery beat schedule file\ncelerybeat-schedule\n\n# SageMath parsed files\n*.sage.py\n\n# Environments\n# .env\n.venv\nenv/\nvenv/\nENV/\nenv.bak/\nvenv.bak/\n\n# Spyder project settings\n.spyderproject\n.spyproject\n\n# Rope project settings\n.ropeproject\n\n# mkdocs documentation\n/site\n\n# mypy\n.mypy_cache/\n\n*.sqlite3\npip-wheel-metadata/\n\n.DS_Store\n*/.DS_Store\n\ndata/*\n!data/aea.png\n!data/video-aea.png\ntemp_private_key.pem\n.idea/\n\ninput_file\noutput_file\n\n!packages/fetchai/contracts/erc1155/build\n!packages/fetchai/contracts/staking_erc20/build\n!packages/fetchai/contracts/oracle/build\n!packages/fetchai/contracts/oracle_client/build\n!packages/fetchai/contracts/fet_erc20/build\npackages/fetchai/connections/p2p_libp2p/libp2p_node/libp2p_node\n\n!tests/data/dummy_contract/build\n!plugins/aea-ledger-ethereum/tests/data/dummy_contract/build\n!plugins/aea-ledger-cosmos/tests/data/dummy_contract/build\n!plugins/aea-ledger-fetchai/tests/data/dummy_contract/build\n\ndeploy-image/.env\n\nlibs/go/aealite/aealite\nlibs/go/libp2p_node/libp2p_node\nlibs/go/libp2p_node/coverage.txt\nlibs/go/libp2p_node/dht/dhtclient/agent_records_store*\nlibs/go/libp2p_node/dht/dhtpeer/agent_records_store*\n!libs/go/aea_end2end/seller_agent\ncoverage.txt"
  },
  {
    "path": ".spelling",
    "content": "# markdown-spellcheck spelling configuration file\n# Format - lines beginning # are comments\n# global dictionary is at the start, file overrides afterwards\n# one word per line, to define a file override use ' - filename'\n# where filename is relative to this configuration file\nliveness\npre-shared\nBlockchain-based\nAsynchronisation\nasynchronisation\nWooldridge\ndriverless\nAEA\nAEAs\nFetch.ai\nblockchains\nblockchain\nACAs\nAlice_AEA\nFaber_AEA\nAlice_ACA\nFaber_ACA\nwebhook\nwebhooks\nlocalhost\ntestnet\nmultiaddress\nregex\nscaffolded\nEthereum\nstdlib\nVSCode\nbooleans\nColab\nDockerfile\nSDKs\nTeardown\ntrustless\ndeployer\nGanache\nRopsten\nfaucet\nFetch.ai.\nunregisters\nteardown\nunregister\nAgentland\ninstantiable\nstartup\nbackend\nSQLite\nbackends\nstdout\nsOEF\nSimple-OEF\nsoef\nOpenAI's\nOpenAI\nPyPI\nOpenAPI\nfingerprinter\nHyperledger\nproactiveness\ncomposable\nreusability\nGithub\ntradeoffs\nprotobuf\nsecp256k1\na-zA-Z_\na-zA-Z0-9_\na-zA-Z-\n0-9a-zA-Z-\na-zA-Z\n0-9a-zA-Z\nDLTs\npermissionless\nlibp2p\nORMs\nstandalone\nnamespaced\nprometheus\ntoolset\ndeserialised\nsnake_case\nproto3\ndeserialising\nRowling\nsubexpression\nsubexpressions\ndeserialise\nfrontend\nplugins\nMacOs\nWiFi\npipenv\nautomobiles\nIoT\npositionless\n11km\n1.1km\nmainnet\ntestnets\nv2\n75km\n50km\noutbox\nsubclassing\ngotchas\ntrustlessness\nsubmodules\nsetuptools\nlinters\nFavorito\nMarcoFavorito\nMinarsch\nDavidMinarsch\nHosseini\nAristotelis\nTriantafyllidis\nTotoual\nDiarmid\ndishmop\nPanasevych\nPanasevychol\nKevin-Chen0\nTurchenkov\nsolarw\nLokman\nRahmani\nlrahmani\nJiří\nVestfál\nMissingNO57\nejfitzgerald\nRiehl\njrriehl\nREADME.md\nreentrancy\nserialiser\nsimple-oef\nvendorised\nwhite_check_mark\nk8s\nillustrational\nOAuth\nssh\nkeychain\nsubmodule\nDjango\nMultiaddresses\nGrafana\nFipa\nBase64\nPi3\nRaspbian\nVisdom\nPRs\nmultiaddresses\nunregistration\nunregistering\npipx\nBibTex\nKubernetes\nGolang\nweb3\nCosmWasm\nShoham\nYoti\nPowerShell\nderegisters\nplugin\nFetch.AI\nAEALite\nPipfile\n12-factor\nDisposability\ndisposability\nad-hoc\nNuitka\nPerun\n1.0.0rc1\ndocstrings\n1.0.0rc2\ninstall.ps1\npylint\nquickstart\nCVE-2021-27291\nAgentLand\nGCloud\np2p\nLookupRequest\nLookupResponse\nAeaEnvelope\n_envelope_bytes_\nAgentRecord\nAgentApi\nDHTPeer\nsequenceDiagram\nlistenLoop\nOutputQueue\noutputLoop\nSendQueue\nsendLoop\nDhtNode\nalt\nack-timeout\nconn-error\ngeneric_error\nDESERIALIZATION_ERROR\nRouteEnvelope\nPoR\nchoco\nutc-0\ndocstring\nutils\nkademlia\nCapricorn\nstargateworld-3\nv0.8.x\nfetch.ai\nRaiseError\nserializer's\npywin32\nCosmPy\ndockerised\nMermaid-JS\ndarglint\naea-cli-ipfs\ntensorflow\nethereum\nmypy\nipfshttpclient\n0.8.0a2\nint64\nint32\ncosmpy\ntx\nasyncio\ngolang\nbasecontracttesttool\nlinter\nstargateworld\nfaq\nfetchai\nagents-aea\nci\nperf\nscipy\nnumpy\nscikit-image\nhello_world\npis\nprebuilt\njsonschema\ntox\n - docs/language-agnostic-definition.md\nfetchai\nprotocol_id\n - docs/simple-oef.md\n_do_\nCosmWasm\n - docs/ledger-integration.md\natestfet\nv0.2.x\ndorado-1\n - docs/questions-and-answers.md\nstate_update\ntxt\n - docs/protocol-generator.md\njava\njavascript\nprotoc\n - docs/acn.md\np2p_libp2p_mailbox\n - docs/cli-commands.md\naea\n - docs/contract.md\ninit\ncode_id\ninit_msg\nfetchai\nerc1155\nContractApiMessage.Performative.GET_DEPLOY_TRANSACTION\n - docs/decision-maker.md\ntac_\n - docs/limits.md\nspec\nmicropython\nSubprotocols\nmempool\n - docs/p2p-connection.md\np2p_libp2p\n - docs/quickstart.md\nmy_first_aea\noutput_file\nAEATestCase\ntest.py\naea-config\nyaml\n - docs/skill-guide.md\nTickerBehaviour\nbehaviours.py\nstrategy.py\ndialogues.py\noef_search\nhandlers.py\nskill.yaml\npackages.fetchai.skills.my_search.dialogues\ncapricorn-1\ndorado\ndorado-1\n - acapy-alice-bob/AdminAPI.md\nACA-Py\nACA-Py-based\nprover\n - CODE_OF_CONDUCT.md\ncolor\nbehavior\n"
  },
  {
    "path": "AUTHORS.md",
    "content": "# Authors\n\nThis is the official list of the AEA Framework authors:\n\n### Lead\n\n- Ali Hosseini <ali.hosseini@fetch.ai> [5A11](https://github.com/5A11)\n\n### Primary Current and Past Contributors\n\n- James Riehl [jrriehl](https://github.com/jrriehl)\n- David Minarsch [DavidMinarsch](https://github.com/DavidMinarsch)\n- Marco Favorito [MarcoFavorito](https://github.com/MarcoFavorito)\n- Yuri Turchenkov [solarw](https://github.com/solarw)\n- Oleg Panasevych [Panasevychol](https://github.com/panasevychol)\n- Lokman Rahmani [lrahmani](https://github.com/lrahmani)\n- Jiří Vestfál [MissingNO57](https://github.com/MissingNO57)\n"
  },
  {
    "path": "CITATION.cff",
    "content": "cff-version: 1.2.0\nmessage: \"If you use the AEA framework in your research, please cite it as below:\"\ntitle: Autonomous Economic Agent (AEA) Framework\nauthors:\n  - family-names: Hosseini\n    given-names: Seyed Ali\n  - family-names: Minarsch\n    given-names: David\n  - family-names: Favorito\n    given-names: Marco\n  - family-names: Riehl\n    given-names: James\n  - family-names: Turchenkov\n    given-names: Yuri\n  - family-names: Panasevych\n    given-names: Oleg\n  - family-names: Rahmani\n    given-names: Lokman\n  - family-names: Vestfál\n    given-names: Jiří\n  - family-names: Triantafyllidis\n    given-names: Aristotelis\n  - family-names: Campbell\n    given-names: Diarmid\n  - family-names: Chen\n    given-names: Kevin\ndate-released: \"2019-08-21\"\nurl: \"https://github.com/fetchai/agents-aea/\"\nlicense: \"Apache-2.0\"\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Code of Conduct\n\n## Our Pledge\n\nWe 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, caste, color, religion, or sexual identity and orientation.\n\nWe pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community.\n\n## Our Standards\n\nExamples of behavior that contributes to a positive environment for our community include:\n\n- Demonstrating empathy and kindness toward other people\n- Being respectful of differing opinions, viewpoints, and experiences\n- Giving and gracefully accepting constructive feedback\n- Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience\n- Focusing on what is best not just for us as individuals, but for the overall community\n\nExamples of unacceptable behavior include:\n\n- The use of sexualized language or imagery, and sexual attention or advances of any kind\n- Trolling, insulting or derogatory comments, and personal or political attacks\n- Public or private harassment\n- Publishing others’ private information, such as a physical or email address, without their explicit permission\n- Other conduct which could reasonably be considered inappropriate in a professional setting\n\n## Enforcement Responsibilities\n\nCommunity 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.\n\nCommunity 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.\n\n## Scope\n\nThis 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.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at developer@fetch.ai. All complaints will be reviewed and investigated promptly and fairly.\n\nAll community leaders are obligated to respect the privacy and security of the reporter of any incident.\n\n## Enforcement Guidelines\n\nCommunity leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct:\n\n### 1. Correction\n\n**Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community.\n\n**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.\n\n### 2. Warning\n\n**Community Impact**: A violation through a single incident or series of actions.\n\n**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.\n\n### 3. Temporary Ban\n\n**Community Impact**: A serious violation of community standards, including sustained inappropriate behavior.\n\n**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.\n\n### 4. Permanent Ban\n\n**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.\n\n**Consequence**: A permanent ban from any sort of public interaction within the community.\n\n## Attribution\n\nThis Code of Conduct is adapted from the <https://www.contributor-covenant.org>, version 2.1,\navailable at <https://www.contributor-covenant.org/version/2/1/code_of_conduct.html>.\n\nCommunity Impact Guidelines were inspired by [Mozilla’s code of conduct enforcement ladder](https://github.com/mozilla/diversity).\n\nFor 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>.\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contribution Guidelines\n\nContributions to the framework, plugins, packages and related tools are welcome. As a contributor, here are the guidelines we would like you to follow:\n\n- [Code of Conduct](#coc)\n- [Question or Problem?](#question)\n- [Issues and Bugs](#issue)\n- [Feature Requests](#feature)\n- [Submission Guidelines](#submit)\n- [Coding Rules](#rules)\n- [Commit Message Guidelines](#commit)\n\n## <a name=\"coc\"></a> Code of Conduct\n\nPlease read and follow our [Code of Conduct][coc].\n\n## <a name=\"question\"></a> Question or Problem?\n\nPlease use [GitHub Discussions][ghdiscussion] for support related questions and general discussions. Do NOT open issues as they are for bug reports and feature requests. This is because:\n\n- Questions and answers stay available for public viewing so your question/answer might help someone else.\n- GitHub Discussions voting system ensures the best answers are prominently visible.\n\n## <a name=\"issue\"></a> Found a Bug?\n\nIf you find a bug in the source code [submit a bug report issue](#submit-issue).\nEven better, you can [submit a Pull Request](#submit-pr) with a fix.\n\n## <a name=\"feature\"></a> Missing a Feature?\n\nYou can *request* a new feature by [submitting a feature request issue](#submit-issue).\nIf you would like to *implement* a new feature:\n\n- For a **Major Feature**, first [open an issue](#submit-issue) and outline your proposal so that it can be discussed.\n- **Small Features** can be crafted and directly [submitted as a Pull Request](#submit-pr).\n\n## <a name=\"submit\"></a> Submission Guidelines\n\n### <a name=\"submit-issue\"></a> Submitting an Issue\n\nBefore you submit an issue, please search the [issue tracker][issues]. An issue for your problem might already exist and the discussion might inform you of workarounds readily available.\n\nFor bug reports, it is important that we can reproduce and confirm it. For this, we need you to provide a minimal reproduction instruction (this is part of the bug report issue template).\n\nYou can file new issues by selecting from our [new issue templates][new-issue] and filling out the issue template.\n\n### <a name=\"submit-pr\"></a> Submitting a Pull Request (PR)\n\nBefore you submit your Pull Request (PR) consider the following guidelines:\n\n1. All Pull Requests should be based off of and opened against the `develop` branch. Do **not** open a Pull Request against `main`!\n\n2. Search [Existing PRs][prs] for an open or closed PR that relates to your submission.\n   You don't want to duplicate existing efforts.\n\n3. Be sure that an issue exists describing the problem you're fixing, or the design for the feature you'd like to add.\n\n4. [Fork](https://docs.github.com/en/github/getting-started-with-github/fork-a-repo) the [repository][github].\n\n5. In your forked repository, make your changes in a new git branch created from the `develop` branch.\n\n6. Make your changes, **including test cases** and updating documentation where appropriate.\n\n7. Follow our [coding rules](#rules).\n\n8. Run all tests and checks locally, as described in the [development guide][developing], and ensure they pass. This saves CI hours and ensures you only commit clean code.\n\n9. Commit your changes using a descriptive commit message that follows our [commit message conventions](#commit).\n\n10. Push your branch to GitHub.\n\n11. In GitHub, send a pull request to `fetchai:develop`.\n\n> Where possible, try to take advantage of the modularity of the framework and add new functionality via a new module. Currently, ledger plugins are supported and packages (skills, connections, protocols, contracts) allow for extensibility.\n\n#### Reviewing a Pull Request\n\nThe AEA team reserves the right not to accept pull requests from community members who haven't been good citizens of the community. Such behavior includes not following our [code of conduct][coc] and applies within or outside the managed channels.\n\nWhen you contribute a new feature, the maintenance burden is transferred to the core team. This means that the benefit of the contribution must be compared against the cost of maintaining the feature.\n\n#### Addressing review feedback\n\nIf we ask for changes via code reviews then:\n\n1. Make the required updates to the code.\n\n2. Re-run the tests and checks to ensure they are still passing.\n\n3. Create a new commit and push to your GitHub repository (this will update your Pull Request).\n\n#### After your pull request is merged\n\nAfter your pull request is merged, you can safely delete your branch and pull the changes from the (upstream) repository.\n\n## <a name=\"rules\"></a> Coding Rules\n\nTo ensure consistency throughout the source code, keep these rules in mind as you are working:\n\n- All code must pass our code quality checks (linters, formatters, etc). See the [development guide][developing] section for more detail.\n- All features or bug fixes **must be tested** via unit-tests and if applicable integration-tests. These help to, a. prove that your code works correctly, and b. guard against future breaking changes and lower the maintenance cost.\n- All public features **must be documented**.\n- All files must include a license header.\n\n## <a name=\"commit\"></a> Commit Message Convention\n\nPlease follow the [Conventional Commits v1.0.0][convcommit]. The commit types must be one of the following:\n\n- **build**: Changes that affect the build system or external dependencies\n- **ci**: Changes to our CI configuration files and scripts\n- **docs**: Documentation only changes\n- **feat**: A new feature\n- **fix**: A bug fix\n- **nfunc**: Code that improves some non-functional characteristic, such as performance, security, ...\n- **refactor**: A code change that neither fixes a bug nor adds a feature\n- **test**: Adding missing tests or correcting existing tests\n\n[coc]: https://github.com/fetchai/agents-aea/blob/main/CODE_OF_CONDUCT.md\n[developing]: https://github.com/fetchai/agents-aea/blob/main/DEVELOPING.md\n[ghdiscussion]: https://github.com/fetchai/agents-aea/discussions\n[issues]: https://github.com/fetchai/agents-aea/issues\n[new-issue]: https://github.com/fetchai/agents-aea/issues/new/choose\n[prs]: https://github.com/fetchai/agents-aea/pulls\n[convcommit]: https://www.conventionalcommits.org/en/v1.0.0/\n[github]: https://github.com/fetchai/agents-aea\n"
  },
  {
    "path": "DEVELOPING.md",
    "content": "# Development Guidelines\n\n- [Getting the Source](#get)\n- [Setting up a New Development Environment](#setup)\n- [Development](#dev)\n  - [General code quality checks](#general)\n  - [Updating API documentation](#api)\n  - [Updating documentation](#docs)\n  - [Updating dependencies](#deps)\n  - [Updating packages](#package)\n  - [Tests](#tests)\n  - [Miscellaneous checks](#misc)\n- [Contributing](#contributing)\n- [Making Releases](#release)\n\n## <a name=\"get\"></a> Getting the Source\n\n1. Fork the [agents-aea repository][repo].\n2. Clone your fork of the agents-aea repository:\n\n   ``` shell\n   git clone git@github.com:<github username>/agents-aea.git\n   ```\n\n3. Define an `upstream` remote pointing back to the main agents-aea repository:\n\n   ``` shell\n   git remote add upstream https://github.com/fetchai/agents-aea.git\n   ```\n\n## <a name=\"setup\"></a> Setting up a New Development Environment\n\n1. Ensure you have Python (version `3.8`, `3.9` or `3.10`) and [`poetry`][poetry].\n\n2. ``` shell\n   make new-env\n   ```\n\n   This will create a new virtual environment using poetry with the project and all the development dependencies installed.\n\n   > We use <a href=\"https://python-poetry.org\" target=\"_blank\">poetry</a> to manage dependencies. All python specific dependencies are specified in `pyproject.toml` and installed with the framework. \n   > \n   > You can have more control on the installed dependencies by leveraging poetry's features.\n\n3. ``` shell\n   poetry shell\n   ```\n\n    To enter the virtual environment.\n\nDepending on what you want to do, you might need extra tools on your system:\n\n- The project uses [Google Protocol Buffers][protobuf] compiler for message serialization. The compiler's version must match the `protobuf` library installed with the project (see `pyproject.toml`).  \n- The `fetchai/p2p_libp2p` package is partially developed in Go. To make changes, [install Golang][go].\n- To update fingerprint hashes of packages, you will need the [IPFS daemon][ipfs].\n\n## <a name=\"dev\"></a>Development\n\n### <a name=\"general\"></a>General code quality checks\n\nTo run general code quality checkers, formatters and linters:\n\n- ``` shell\n   make lint\n  ```\n\n  Automatically formats your code and sorts your imports, checks your code's quality and scans for any unused code.\n\n- ``` shell\n   make mypy\n  ```\n\n  Statically checks the correctness of the types.\n\n- ``` shell\n   make pylint\n  ```\n\n  Analyses the quality of your code.\n\n- ``` shell\n   make security\n  ```\n\n  Checks the code for known vulnerabilities and common security issues.\n\n- ``` shell\n   make clean\n  ```\n\n  Cleans your development environment and deletes temporary files and directories.\n\n- For the Go parts, we use [`golines`][golines] and [`golangci-lint`][golangci-lint] for linting.\n\n### <a name=\"docs\"></a>Updating documentation\n\nWe use [`mkdocs`][mkdocs] and [`material-for-mkdocs`][material] for static documentation pages. To make changes to the documentation:\n\n- ``` shell\n   make docs-live\n  ```\n\n  This starts a live-reloading docs server on localhost which you can access by going to <http://127.0.0.1:8000/> in your browser. Making changes to the documentation automatically reloads this page, showing you the latest changes.\n\n  To create a new documentation page, add a markdown file under `/docs/` and add a reference to this page in `mkdocs.yml` under `nav`.\n\n### <a name=\"api\"></a>Updating API documentation\n\nIf you've made changes to the core `aea` package that affects the public API:\n\n- ``` shell\n   make generate-api-docs\n  ```\n\n  This regenerates the API docs. If pages are added/deleted, or there are changes in their structure, these need to be reflected manually in the `nav` section of `mkdocs.yaml`.\n\n### <a name=\"deps\"></a>Updating dependencies\n\nWe use [`poetry`][poetry] and `pyproject.toml` to manage the project's dependencies.\n\nIf you've made any changes to the dependencies (e.g. added/removed dependencies, or updated package version requirements):\n\n- ``` shell\n   poetry lock\n  ```\n\n  This re-locks the dependencies. Ensure that the `poetry.lock` file is pushed into the repository (by default it is).\n\n- ``` shell\n   make liccheck\n  ```\n\n  Checks that the licence for the framework is correct, taking into account the licences for all dependencies, their dependencies and so forth.\n\n### <a name=\"package\"></a>Updating packages\n\nIf you've made changes to the packages included in the repository (e.g. skills, protocols, connections, contracts):\n\n- ``` shell\n   make update-package-hashes\n  ```\n\n  Updates the fingerprint hashes of every package in the repository.\n\n- ``` shell\n   make package-checks\n  ```\n\n  Checks, a. that the package hashes are correct, b. the documentation correctly references the latest packages, and c) runs other correctness checks on packages.\n\n### <a name=\"tests\"></a>Tests\n\nTo test the Python part of the project, we use `pytest`. To run the tests:\n\n- ``` shell\n   make test\n  ```\n\n  Runs all the tests.\n\n- ``` shell\n   make test-plugins \n   ```\n\n  Runs all plugin tests.\n\n- ``` shell\n   make dir={SUBMODULE} tdir={TESTMODULE} test-sub\n  ```\n\n  Runs the tests for `aea.{SUBMODULE}`. For example, to run the tests for the CLI: `make dir=cli tdir=cli test-sub`\n\nTo test the Go parts of the project:\n\n- ``` shell\n   go test -p 1 -timeout 0 -count 1 -v ./...\n  ```\n\n  from the root directory of a Go package (e.g. `fetchai/p2p_libp2p`) to run the Golang tests.\n  If you experience installation or build issues, run `go clean -modcache`.\n\n### <a name=\"misc\"></a>Miscellaneous checks\n\n- ``` shell\n   copyright-check\n  ```\n\n  Checks that all files have the correct copyright header (where applicable).\n\n- ``` shell\n   check-doc-links\n  ```\n\n  Checks that the links in the documentations are valid and alive.\n\n- ``` shell\n   make libp2p-diffs\n  ```\n\n  Checks the libp2p code under `libs` and in the connection packages aren't different.\n\n- ``` shell\n   make plugin-diffs\n  ```\n\n  Checks the plugin licenses and the codes under `cosmos` and `fetchai` ledger plugins aren't different.\n\n## <a name=\"contributing\"></a>Contributing\n\nFor instructions on how to contribute to the project (e.g. creating Pull Requests, commit message convention, etc), see the [contributing guide][contributing guide].\n\n## <a name=\"release\"></a>Making Releases\n\nFor instructions on how to make a release, see the [release process][release process] guide.\n\n[protobuf]: https://developers.google.com/protocol-buffers/\n[ipfs]: https://docs.ipfs.tech/install/\n[go]: https://golang.org/doc/install\n[golines]: https://github.com/segmentio/golines\n[golangci-lint]: https://golangci-lint.run\n[mkdocs]: https://www.mkdocs.org\n[material]: https://squidfunk.github.io/mkdocs-material/\n[poetry]: https://python-poetry.org\n[contributing guide]: https://github.com/fetchai/agents-aea/blob/main/CONTRIBUTING.md\n[release process]: https://github.com/fetchai/agents-aea/blob/main/scripts/RELEASE_PROCESS.md\n[repo]: https://github.com/fetchai/agents-aea\n"
  },
  {
    "path": "HISTORY.md",
    "content": "# Release History\n\n## 1.2.5 (2023-01-18)\n\nDocs:\n\n- Sweeping foundational updates across all documentation\n\nMisc:\n\n- Update some dependencies\n- Update copyright headers across all files (including year 2023)\n- Remove `docker-images` submodule\n- Various bug fixes\n\n## 1.2.4 (2022-11-30)\n\nAgents:\n\n- Add hello_world skill and agent\n\nDocs:\n\n- Update repository documentations\n- Update installation guide for Raspberry Pis (add a link to prebuilt image for Raspberry Pis)\n\nMisc:\n\n- Update the dependencies (protobuf, jsonschema, cosmpy)\n- Various improvements in the repository structure (e.g. makefile, tox, workflows)\n- Speed up CI/CD\n- Various bug fixes\n\n## 1.2.3 (2022-11-03)\n\nAEA:\n\n- core and development are dependencies updated.\n- ci improvements\n- cosmpy updated to 0.6.0\n- Small code format improvements and better linting\n\nPlugins:\n\n- Small code format improvements\n- cosmpy updated to 0.6.0\n\nPackages:\n\n- Small code format improvements\n\n## 1.2.2 (2022-10-17)\n\nAEA:\n\n- Dependency management switched from pipenv to poetry.\n- Protocol generator updated to support Unions\n- Dependencies versions updates: click, mypy, black, ipfshttpclient\n- Small code format improvements\n\nPlugins:\n\n- Update web3 to version 5.31\n- Small code format improvements\n- ipfshttpclient dependency version updated to 0.8.0a2\n\nPackages:\n\n- Protocols regenerated according to the latest protocol generator improvements: Union support\n- Small code format improvements\n\n## 1.2.1 (2022-07-12)\n\nAEA:\n\n- Protocol generator uses int64 instead of int32\n- Dependencies versions updates\n\nPlugins:\n\n- Upgrades fetchai plugin to use cosmpy>=0.5.0\n- Upgrades cosmos plugin to use cosmpy>=0.5.0\n\nPackages:\n\n- Fixes for skills to work with dorado testnet (tx fee adjusted)\n\n## 1.2.0 (2022-05-05)\n\nAEA:\n\n- Adds support for Python 3.10\n- Updates protobuf dependency\n- Updates asyncio dependency\n- Updates golang modules\n- Updates many dependencies to their latest versions\n- Fixes dependency issues\n\nPlugins:\n\n- Upgrades fetchai plugin to be compatible with Dorado networks\n- Upgrades cosmos plugin to be compatible with Dorado networks\n\nPackages:\n\n- Adds more logging to the p2p_libp2p packages (vanilla, client, mailbox)\n- Aries demo updated to cover the full base scenario\n- Protocols were regenerated with newer protobuf\n\nChores:\n\n- Fixed various tests\n- Fixed docker container issue in tests\n- Added automated script to add support for new versions of the Fetchai network\n- Added automated script to update copyright headers and check their validity\n- Apply the above script on all packages\n- Adds tests for BaseContractTestTool\n- Improves the script that automatically updates package versions\n\n## 1.1.1 (2021-12-15)\n\nAEA:\n\n- Updates the protocol generator to generate protocols that satisfy linter constraints\n\nPlugins:\n\n- aea-cli-ipfs plugin small update\n\nPackages:\n\n- Fixes fetchai/p2p_libp2p connection to address a slow DHT lookup problem\n- Updates protocols with the latest protocol generator\n- Updates random beacon agent so it produces block data instead of the (now deprecated feature of the test-net) random beacon data\n\nMisc\n\n- Bumps go library versions\n- Various fixes and improvements\n\n## 1.1.0 (2021-10-13)\n\nAEA:\n\n- Adds public keys to agent identity and skill context\n- Adds contract test tool\n- Adds multiprocess support for task manager\n- Adds multiprocess backed support to `MultiAgentManager`\n- Adds support for excluding connection on `aea run`\n- Adds support for adding a key that is being generated (`—add-key` option for `generate-key` command)\n- Adds check for dependencies to be present in registry on a package push\n- Makes more efficient installing of project dependencies on `aea install`\n- Adds dependency conflict detection on `aea install`\n- Improves pip install error details on `aea install`\n- Adds validation of `aea_version` when loading configuration\n- Adds a check for consistency of package versions in `MultiAgent Manager`\n- Adds better error reporting for aea registry requests\n- Fixes IPFS hash calculation for large files\n- Fixes protobuf dictionary serializer's uncovered cases and makes it deterministic\n- Fixes scaffolding of error and decision maker handlers\n- Fixes pywin32 problem when checking dependency\n- Improves existing testing tools\n\nBenchmarks:\n\n- Adds agents construction and decision maker benchmark cases\n\nPlugins:\n\n- Upgrades fetchai plugin to use CosmPy instead of CLI calls\n- Upgrades cosmos plugin to use CosmPy instead of CLI calls\n- Upgrades fetchai plugin to use StargateWorld\n- Upgrades cosmos plugin to Stargate\n- Sets the correct maximum Gas for fetch.ai plugin\n\nPackages:\n\n- Adds support for Tac to be run against fetchai StargateWorld test-net\n- Adds more informative error messages to CosmWasm ERC1155 contract\n- Adds support for atomic swap to CosmWasm ERC1155 contract\n- Adds an ACN protocol that formalises ACN communication using the framework's protocol language\n- Adds `cosm_trade` protocol for preparing atomic swap transactions for cosmos-based networks\n- Adds https support for server connection\n- Adds parametrising of http(s) in soef connection\n- Fixes http server content length response problem\n- Updates Oracle contract to 0.14\n- Implements the full ACN spec throughout the ACN packages\n- Implements correct error code usage in ACN packages\n- Refactors ACN packages to unify reused logic\n- Adds tests for gym skills\n- Adds dockerised SOEF\n- Adds libp2p mailbox connection\n- Multiple fixes and stability improvements for `p2p_libp2p` connections\n\nDocs:\n\n- Adds ACN internals documentation\n- Fixes tutorial for HTTP connection and skill\n- Multiple additional docs updates\n- Adds more context to private keys docs\n\nChores:\n\n- Various development features bumped\n- Bumped Mermaid-JS, for UML diagrams to major version 8\n- Applies darglint to the code\n\nExamples:\n\n- Adds a unified script for running various versions/modes of Tac\n\n## 1.0.2 (2021-06-03)\n\nAEA:\n\n- Bounds versions of dependencies by next major\n- Fixes incoherent warning message during package loading\n- Improves various incomprehensible error messages\n- Adds debug log message when abstract components are loaded\n- Adds tests and minor fixes for password related CLI commands and password usage in `MultiAgentManager`\n- Adds default error handler in `MultiAgentManager`\n- Ensures private key checks are performed after override setting in `MultiAgentManager`\n- Applies docstring fixes suggested by `darglint`\n- Fixes `aea push --local` command to use correct author\n- Fixes `aea get-multiaddress` command to consider overrides\n\nPlugins:\n\n- Bounds versions of dependencies by next major\n\nPackages:\n\n- Updates `p2p_libp2p` connection to use TCP sockets for all platforms\n- Multiple fixes on `libp2p_node` including better error handling and stream creation\n- Adds sending queue in `p2p_libp2p` connection to handle sending failures\n- Adds unit tests for `libp2p_node` utils\n- Adds additional tests for `p2p_libp2p` connection\n- Fixes location bug in AW5\n- Improves connection check handling in soef connection\n- Updates oracle and oracle client contracts for better access control\n- Adds skill tests for `erc1155` skills\n- Adds skill tests for `aries` skills\n- Fixes minor bug in ML skills\n- Multiple additional tests and test stability fixes\n\nDocs:\n\n- Extends demo docs to include guidance of usage in AEA Manager\n- Adds short guide on Kubernetes deployment\n- Multiple additional docs updates\n\nChores:\n\n- Adds `--no-bump` option to `generate_all_protocols` script\n- Adds script to detect if aea or plugins need bumping\n- Bumps various development dependencies\n- Adds Golang and GCC in Windows install script\n- Adds `darglint` to CI\n\nExamples:\n\n- Updates TAC deployment scripts and images\n\n## - (2021-05-05)\n\nPackages:\n\n- Adds node watcher to `p2p_libp2p` connection\n- Improves logging and error handling in `p2p_libp2p` node\n- Addresses potential overflow issue in `p2p_libp2p` node\n- Fixes concurrency issue in `p2p_libp2p` node which could lead to wrongly ordered envelopes\n- Improves logging in TAC skills\n- Fixes Exception handling in connect/disconnect calls of soef connection\n- Extends public DHT tests to include staging\n- Adds tests for envelope ordering for all routes\n- Multiple additional tests and test stability fixes\n\n## 1.0.1 (2021-04-30)\n\nAEA:\n\n- Fixes wheels issue for Windows\n- Fixes password propagation for certificate issuance in `MultiAgentManager`\n- Improves error message when local registry not present\n\nAEALite:\n\n- Adds full protocol support\n- Adds end-to-end interaction example with AEA (based on `fetchai/fipa` protocol)\n- Multiple additional tests and test stability fixes\n\nPackages:\n\n- Fixes multiple bugs in `ERC1155` version of TAC\n- Refactors p2p connections for better separation of concerns and maintainability\n- Integrates aggregation with simple oracle skill\n- Ensures genus and classifications are used in all skills using SOEF\n- Extends SOEF connection to implement `oef_search` protocol fully\n- Handles SOEF failures in skills\n- Adds simple aggregation skills including tests and docs\n- Adds tests for registration AW agents\n- Adds tests for reconnection logic in p2p connections\n- Multiple additional tests and test stability fixes\n\nDocs:\n\n- Extends car park demo with usage guide for AEA manager\n- Multiple additional docs updates\n\nExamples:\n\n- Adds TAC deployment example\n\n## 1.0.0 (2021-03-30)\n\n- Improves contributor guide\n- Enables additional pylint checks\n- Adds configuration support on exception behaviour in ledger plugins\n- Improves exception handling in `aea-ledger-cosmos` and `aea-ledger-fetchai` plugins\n- Improves quickstart guide\n- Fixes multiple flaky tests\n- Fixes various outdated metadata\n- Resolves a CVE (CVE-2021-27291) affecting development dependencies\n- Adds end-to-end support and tests for simple oracle on Ethereum and Fetch.ai ledgers\n- Multiple minor fixes\n- Multiple additional tests and test stability fixes\n\n## 1.0.0rc2 (2021-03-28)\n\n- Extends CLI command `aea fingerprint` to allow fingerprinting of agents\n- Improves `deploy-image` Docker example\n- Fixes a bug in `MultiAgentManager` which leaves it in an unclean state when project adding fails\n- Fixes dependencies of `aea-legder-fetchai`\n- Improves guide on HTTP client and server connection\n- Removes pickle library usage in the ML skills\n- Adds various consistency checks in configurations\n- Replaces usage of `pyaes` with `pycryptodome` in plugins\n- Changes generator to avoid non-idiomatic usage of type checks\n- Multiple minor fixes\n- Multiple additional tests and test stability fixes\n\n## 1.0.0rc1 (2021-03-24)\n\n- Adds CLI command `aea get-public-key`\n- Adds support for encrypting private keys at rest\n- Adds support for configuration of decision maker and error handler instances from `aea-config.yaml`\n- Adds support for explicitly marking behaviours and handlers as dynamic\n- Adds support for fetchai ledger to oracle skills and contract\n- Adds timeout support on multiplexer calls to connections\n- Fixes bug in regex constrained string for id validation\n- Adds docs section on how AEAs satisfy 12-factor methodology\n- Adds docs section on tradeoffs made in `v1`\n- Adds example for logs streaming to browser\n- Removes multiple temporary hacks for backwards compatibility\n- Adds skills tests coverage for `echo` and `http_echo` skills\n- Adds `required_ledgers` field in `aea-config.yaml`\n- Removes `registry_path` field in `aea-config.yaml`\n- Adds `message_format` field to cert requests\n- Removes requirement for exact protocol buffers compiler, prints version used in protocols\n- Adds support to configure task manager mode via `aea-config.yaml`\n- Fixed spelling across docstrings in code base\n- Multiple minor fixes\n- Multiple docs updates to fix order of CLI commands with respect to installing dependencies\n- Multiple additional tests and test stability fixes\n\n## 0.11.2 (2021-03-17)\n\n- Fixes a package import issue\n- Fixes an issue where `AgentLoop` did not teardown properly under certain conditions\n- Fixes a bug in testing tools\n- Fixes a bug where plugins are not loaded after installation in `MultiAgentManager`\n- Adds unit tests for weather, thermometer and car park skills\n- Fixes a missing dependency in Windows\n- Improves SOEF connections' error handling\n- Fixes bug in ML skills and adds unit tests\n- Adds script to bump plugin versions\n- Adds gas price strategy support in `aea-ledger-ethereum` plugin\n- Adds CLI plugin for IPFS interactions (add/get)\n- Adds support for CLI plugins to framework\n- Multiple additional tests and test stability fixes\n\n## 0.11.1 (2021-03-06)\n\n- Bumps `aiohttp` to `>=3.7.4` to address a CVE affecting `http_server`, `http_client` and `webhook` connections\n- Adds script to ensure Pipfile and `tox.ini` dependencies align\n- Enforces presence of `protocol_specification_id` in `protocol.yaml`\n- Adds support for installation of agent-level PyPI dependencies in `AEABuilder`\n- Sets default ledger plugin during `aea create`\n- Updates various agent packages with missing ledger plugin dependencies\n- Bumps various development dependencies\n- Renames `coin_price` skill to `advanced_data_request` skill and generalises it\n- Updates `fetch_beacon` skill to use `ledger` connection\n- Multiple docs updates to fix order of CLI commands with respect to installing dependencies\n- Multiple additional tests and test stability fixes\n\n## 0.11.0 (2021-03-04)\n\n- Adds slots usage in frequently used framework objects, including `Dialogue`\n- Fixes a bug in `aea upgrade` command where eject prompt was not offered\n- Refactors skill component configurations to allow for skill components (`Handler`, `Behaviour`, `Model`) to be placed anywhere in a skill\n- Extends skill component configuration to specify optional `file_path` field\n- Extracts all ledger specific functionality in plugins\n- Improves error logging in http server connection\n- Updates `Development - Use case` documentation\n- Adds restart support to `p2p_libp2p` connection on read/write failure\n- Adds validation of default routing and default connection configuration\n- Refactors and significantly simplifies routing between components\n- Limits usage of `EnvelopeContext`\n- Adds support for new CosmWasm message format in ledger plugins\n- Adds project loading checks and optional auto removal in `MultiAgentManager`\n- Adds support for reuse of threaded `Multiplexer`\n- Fixes bug in TAC which caused agents to make suboptimal trades\n- Adds support to specify dependencies on `aea-config.yaml` level\n- Improves release scripts\n- Adds lightweight Golang AEALite library\n- Adds support for skill-to-skill messages\n- Removes CLI GUI\n- Multiple docs updates based on user feedback\n- Multiple additional tests and test stability fixes\n\n## 0.10.1 (2021-02-21)\n\n- Changes default URL of `soef` connection to https\n- Improves teardown, retry and edge case handling of `p2p_libp2p` and `p2p_libp2p_client` connections\n- Adds auto-generation of private keys to `MultiAgentManager`\n- Exposes address getters on `MultiAgentManager`\n- Improves package validation error messages\n- Simplifies default `DecisionMakerHandler` and extracts advanced features in separate class\n- Fixes task manager and its usage in skills\n- Adds support for multi-language protocol stub generation\n- Adds `data_dir` usage to additional connections\n- Adds IO helper function for consistent file usage\n- Extends release helper scripts\n- Removes stub connection as default connection\n- Adds support for AEA usage without connections\n- Multiple docs updates based on user feedback\n- Multiple additional tests and test stability fixes\n\n## 0.10.0 (2021-02-11)\n\n- Removes error skill from agents which do not need it\n- Adds support for relay connection reconnect in ACN\n- Multiplexer refactoring for easier connection handling\n- Fix `erc1155` skill tests on CosmWasm chains\n- Extends docs on usage of CosmWasm chains\n- Adds version compatibility in `aea upgrade` command\n- Introduces protocol specification id and related changes for better interoperability\n- Adds synchronous connection base class\n- Exposes state setter in connection base class\n- Adds Yoti protocol and connection\n- Multiple updates to generic buyer\n- Adds additional automation to `MultiAgentManager`, including automated handling of certs, keys and other package specific data\n- Multiple test improvements and fixes\n- Add stricter typing and checks\n- Fixes to MacOS install script\n- Adds threading patch for web3\n- Multiple docs updates based on user feedback\n- Multiple additional tests and test stability fixes\n\n## 0.9.2 (2021-01-21)\n\n- Fixes `CosmosApi`, in particular for CosmWasm\n- Fixes error output from `add-key` CLI command\n- Update `aea_version` in non-vendor packages when calling `upgrade` CLI command\n- Extend `upgrade` command to fetch newer agent if present on registry\n- Add support for mixed fetch mode in `MultiAgentManager`\n- Fixes logging overrides in `MultiAgentManager`\n- Configuration overrides now properly handle `None` values\n- Multiple docs updates based on user feedback\n- Multiple additional tests and test stability fixes\n\n## 0.9.1 (2021-01-14)\n\n- Fixes multiple issues with `MultiAgentManager` including overrides not being correctly applied\n- Restructures docs navigation\n- Updates `MultiAgentManager` documentation\n- Extends functionality of `aea upgrade` command to cover more cases\n- Fixes a bug in the `aea upgrade` command which prevented upgrading across version minors\n- Fixes a bug in `aea fetch` where the console output was inconsistent with the actual error\n- Fixes scaffold connection constructor\n- Multiple additional tests to improve stability\n- Multiple docs updates based on user feedback\n- Multiple additional tests and test stability fixes\n\n## 0.9.0 (2021-01-06)\n\n- Adds multiple bug fixes on `MultiAgentManager`\n- Adds `AgentConfigManager` for better programmatic configuration management\n- Fixes auto-filling of `aea_version` field in AEA configuration\n- Adds tests for confirmation skills AW2/3\n- Extends `MultiAgentManager` to support proper configuration overriding\n- Fixes ML skills demo\n- Fixes environment variable resolution in configuration files\n- Adds support to fingerprint packages by providing a path\n- Adds `local-registry-sync` CLI command to sync local and remote registry\n- Adds support to push vendorised packages to local registry\n- Adds missing tests for code in documentation\n- Adds prompt in `scaffold protocol` CLI command to hint at protocol generator\n- Adds `issue-certificates` CLI command for Proof of Representation\n- Adds `cert_requests` support in connections for Proof of Representation\n- Adds support for Proof of Representation in ACN (`p2p_libp2p*` connections)\n- Adds automated spell checking for all `.md` files and makes related fixes\n- Multiple additional tests to improve stability\n- Multiple docs updates based on user feedback\n- Multiple additional tests and test stability fixes\n\n## 0.8.0 (2020-12-17)\n\n- Adds support for protocol dialogue rules validation\n- Fixes URL forwarding in http server connection\n- Revises protocols to correctly define terminal states\n- Adds a build command\n- Adds build command support for libp2p connection\n- Adds multiple fixes to libp2p connection\n- Adds prometheus connection and protocol\n- Adds tests for confirmation AW1 skill\n- Adds oracle demo docs\n- Replaces pickle with protobuf in all protocols\n- Refactors OEF models to account for semantic irregularities\n- Updates docs for demos relying on Ganache\n- Adds generic storage support\n- Adds configurable dialogue offloading\n- Fixes transaction generation on confirmation bugs\n- Fixes transaction processing order in all buyer skills\n- Extends ledger API protocol to query ledger state\n- Adds remove-key command in CLI\n- Multiple tac stability fixes\n- Adds support for configurable error handler\n- Multiple additional tests to improve stability\n- Multiple docs updates based on user feedback\n- Multiple additional tests and test stability fixes\n\n## 0.7.5 (2020-11-25)\n\n- Adds AW3 AEAs\n- Adds basic oracle skills and contracts\n- Replaces usage of Ropsten testnet with Ganache in packages\n- Fixes multiplexer setup when used outside AEA\n- Improves help command output of CLI\n- Adds integration tests for simple skills\n- Adds version check on CLI push\n- Adds integration tests for tac negotiation skills\n- Multiple docs updates based on user feedback\n- Multiple additional tests and test stability fixes\n\n## 0.7.4 (2020-11-18)\n\n- Replaces error skill handler usage with built in handler\n- Extends `MultiAgentManager` to support persistence between runs\n- Replaces usage of Ropsten testnet with Ganache\n- Adds support for symlink creation during scaffold and add\n- Makes contract interface loading extensible\n- Adds support for PEP561\n- Adds integration tests for launcher command\n- Adds support for storage of unique page address in SOEF\n- Fixes publish command bug on Windows\n- Refactors constants usage throughout\n- Adds support for profiling on `aea run`\n- Multiple stability improvements to core asynchronous modules\n- Multiple docs updates based on user feedback\n- Multiple additional tests and test stability fixes\n\n## 0.7.3 (2020-11-12)\n\n- Extends AW AEAs\n- Fixes overwriting of private key files on startup\n- Fixes behaviour bugs\n- Adds tests for tac participation skill\n- Adds development setup guide\n- Improves exception logging for easier debugging\n- Fixes mixed mode in upgrade command\n- Reduces verbosity of some CLI commands\n- Multiple docs updates based on user feedback\n- Multiple additional tests and test stability fixes\n\n## 0.7.2 (2020-11-09)\n\n- Fixes some AW2 AEAs\n- Improves generic buyer AEA\n- Fixes a few backwards incompatibilities on CLI (upgrade, add, fetch) introduced in 0.7.1\n- Fixes geolocation in some tests\n- Multiple docs updates based on user feedback\n- Multiple additional tests and test stability fixes\n\n## 0.7.1 (2020-11-05)\n\n- Adds two AEAs for Agent World 2\n- Refactors dialogue class to optimize for memory\n- Refactors message class to optimize for memory\n- Adds mixed registry mode to CLI and makes it default\n- Extends upgrade command to automatically update references of non-vendor packages\n- Adds deployment scripts for `kubernetes`\n- Extends configuration set/get support for lists and dictionaries\n- Fixes location specifiers throughout code base\n- Imposes limits on length of user defined strings like author and package name\n- Relaxes version specifiers for some dependencies\n- Adds support for skills to reference connections as dependencies\n- Makes ledger and currency ids configurable\n- Adds test coverage for the tac control skills\n- Improves quick start guidance and adds docker images\n- Multiple docs updates based on user feedback\n- Multiple additional tests and test stability fixes\n\n## 0.7.0 (2020-10-22)\n\n- Adds two AEAs for Agent World 1\n- Adds support to apply configuration overrides to CLI calls transfer and get-wealth\n- Adds install scripts to install AEA and dependencies on all major OS (Windows, MacOs, Ubuntu)\n- Adds developer mailing list opt-in step to CLI `init`\n- Modifies custom configurations in `aea-config` to use public id\n- Adds all non-optional fields in `aea-config` by default\n- Fixes upgrade command to properly handle dependencies of non-vendor packages\n- Remove all distributed packages and add them to registry\n- Adds public ids to all skill `init` files and makes it a requirement\n- Adds primitive benchmarks for libp2p node\n- Adds Prometheus monitoring to libp2p node\n- Makes body a private attribute in message base class\n- Renames `bodyy` to `body` in HTTP protocol\n- Adds support for abstract connections\n- Refactors protobuf schemas for protocols to avoid code duplication\n- Multiple docs updates based on user feedback\n- Multiple additional tests and test stability fixes\n\n## 0.6.3 (2020-10-16)\n\n- Adds skill testing tools and documentation\n- Adds human readable log output regarding configuration for `p2p_libp2p` connection\n- Adds support to install PyPI dependencies from `AEABuilder` and `MultiAgentManager`\n- Adds CLI upgrade command to upgrade entire agent project and components\n- Extends CLI remove command to include option to remove dependencies\n- Extends SOEF chain identifier support\n- Adds CLI transfer command to transfer wealth\n- Adds integration tests for skills generic buyer and seller using skill testing tool\n- Adds validation of component configurations when setting component configuration overrides\n- Multiple refactoring of internal configuration and helper objects and methods\n- Fix a bug on CLI push local with latest rather than version specifier\n- Adds `README.md` files in all agent projects\n- Adds agent name in logger paths of runnable objects\n- Fixes tac skills to work with and without ERC1155 contract\n- Adds additional validations on message flow\n- Multiple docs updates based on user feedback\n- Multiple additional tests and test stability fixes\n\n## 0.6.2 (2020-10-01)\n\n- Adds `MultiAgentManager` to manage multiple agent projects programmatically\n- Improves SOEF connection reliability on unregister\n- Extends configuration classes to handle overriding configurations programmatically\n- Improves configuration schemas and validations\n- Fixes Multiplexer termination errors\n- Allow finer-grained override of component configurations from `aea-config`\n- Fixes tac controller to work with Ethereum contracts again\n- Fixes multiple deploy and development scripts\n- Introduces `isort` to development dependencies for automated import sorting\n- Adds reset password command to CLI\n- Adds support for abbreviated public ids (latest) to CLI and configurations\n- Adds additional documentation string linters for improved API documentation checks\n- Multiple docs updates including additional explanations of ACN architecture\n- Multiple additional tests and test stability fixes\n\n## 0.6.1 (2020-09-17)\n\n- Adds a standalone script to deploy an ACN node\n- Adds filtering of out-dated addresses in DHT lookups\n- Updates multiple developer scripts\n- Increases code coverage of all protocols to 100%\n- Fixes a disconnection issue of the multiplexer\n- Extends soef connection to support additional registration commands and search responses\n- Extends `oef_search` protocol to include success performative and agent info in search response\n- Adds `README.md` files to all skills\n- Adds configurable exception policy handling for multiplexer\n- Fixes support for http headers in http server connection\n- Adds additional consistency checks on addresses in dialogues\n- Exposes decision maker address on skill context\n- Adds comprehensive benchmark scripts\n- Multiple docs updates including additional explanations of soef usage\n- Multiple additional tests and test stability fixes\n\n## 0.6.0 (2020-09-01)\n\n- Makes `FetchAICrypto` default again\n- Bumps `web3` dependencies\n- Introduces support for arbitrary protocol handling by DM\n- Removes custom fields in signing protocol\n- Refactors and updates dialogue and dialogues models\n- Moves dialogue module to protocols module\n- Introduces `MultiplexerStatus` to collect aggregate connection status\n- Moves Address types from mail to common\n- Updates `FetchAICrypto` to work with Agentland\n- Fixes circular dependencies in helpers and configurations\n- Unifies contract loading with loading mechanism of other packages\n- Adds get-multiaddress command to CLI\n- Updates helpers scripts\n- Introduces `MultiInbox` to unify internal message handling\n- Adds additional linters (eradicate, more `pylint` options)\n- Improves error reporting in libp2p connection\n- Replaces all assert statements with proper exceptions\n- Adds skill id to envelope context for improved routing\n- Refactors IPC pipes\n- Refactors core dependencies\n- Adds support for multi-page agent configurations\n- Adds type field to all package configurations\n- Multiple docs updates including additional explanations of contracts usage\n- Multiple additional tests and test stability fixes\n\n## 0.5.4 (2020-08-13)\n\n- Adds support for Windows in P2P connections\n- Makes all tests Windows compatible\n- Adds integration tests for P2P public DHT\n- Modifies contract base class to make it cross-ledger compatible\n- Changes dialogue reference nonce generation\n- Fixes tac skills (non-contract versions)\n- Fixes Aries identity skills\n- Extends cosmos crypto API to support `cosmwasm`\n- Adds full test coverage for framework and connection packages\n- Multiple docs updates including automated link integrity checks\n- Multiple additional tests and test stability fixes\n\n## 0.5.3 (2020-08-05)\n\n- Adds support for re-starting agent after stopping it\n- Adds full test coverage for protocols generator\n- Adds support for dynamically adding handlers\n- Improves P2P connection startup reliability\n- Addresses P2P connection race condition with long running processes\n- Adds connection states in connections\n- Applies consistent logger usage throughout\n- Adds key rotation and randomised locations for integration tests\n- Adds request delays in SOEF connection to avoid request limits\n- Exposes runtime states on agent and removes agent liveness object\n- Adds readme files in protocols and connections\n- Improves edge case handling in dialogue models\n- Adds support for `cosmwasm` message signing\n- Adds test coverage for test tools\n- Adds dialogues models in all connections where required\n- Transitions ERC1155 skills and simple search to SOEF and P2P\n- Adds full test coverage for skills modules\n- Multiple docs updates\n- Multiple additional tests and test stability fixes\n\n## 0.5.2 (2020-07-21)\n\n- Transitions demos to agent-land test network, P2P and SOEF connections\n- Adds full test coverage for helpers modules\n- Adds full test coverage for core modules\n- Adds CLI functionality to upload `README.md` files with packages\n- Adds full test coverage for registries module\n- Multiple docs updates\n- Multiple additional tests and test stability fixes\n\n## 0.5.1 (2020-07-14)\n\n- Adds support for agent name being appended to all log statements\n- Adds redesigned GUI\n- Extends dialogue API for easier dialogue maintenance\n- Resolves blocking logic in OEF and gym connections\n- Adds full test coverage on AEA modules configurations, components and mail\n- Adds ping background task for soef connection\n- Adds full test coverage for all connection packages\n- Multiple docs updates\n- Multiple additional tests and test stability fixes\n\n## 0.5.0 (2020-07-06)\n\n- Refactors all connections to be fully asynchronous friendly\n- Adds almost complete test coverage on connections\n- Adds complete test coverage for CLI and CLI GUI\n- Fixes CLI GUI functionality and removes OEF node dependency\n- Refactors P2P go code and increases test coverage\n- Refactors protocol generator for higher code reusability\n- Adds option for skills to depend on other skills\n- Adds abstract skills option\n- Adds ledger connections to execute ledger related queries and transactions, removes ledger APIs from skill context\n- Adds contracts registry and removes them from skill context\n- Rewrites all skills to be fully message based\n- Replaces internal messages with protocols (signing and state update)\n- Multiple refactoring to improve `pylint` adherence\n- Multiple docs updates\n- Multiple test stability fixes\n\n## 0.4.1 (2020-06-15)\n\n- Updates component package module loading for skill and connection\n- Unifies component package loading across package types\n- Adds connections registry to resources\n- Upgrades CLI commands for easier programmatic usage\n- Adds `AEARunner` and `AEALauncher` for programmatic launch of multiple agents\n- Refactors `AEABuilder` to support reentrancy and resetting\n- Fixes tac packages to work with ERC1155 contract\n- Multiple refactoring to improve public and private access patterns\n- Multiple docs updates\n- Multiple test stability fixes\n\n## 0.4.0 (2020-06-08)\n\n- Updates message handling in skills\n- Replaces serialiser implementation; all serialization is now performed framework side\n- Updates all skills for compatibility with new message handling\n- Updates all protocols and protocol generator\n- Updates package loading mechanism\n- Adds `p2p_libp2p_client` connection\n- Fixes CLI bugs and refactors CLI\n- Adds eject command to CLI\n- Exposes identity and connection cryptos to all connections\n- Updates connection loading mechanism\n- Updates all connections for compatibility with new loading mechanism\n- Extracts multiplexer into its own module\n- Implements list all CLI command\n- Updates wallet to split into several crypto stores\n- Refactors component registry and resources\n- Extends soef connection functionality\n- Implements `AEABuilder` reentrancy\n- Updates `p2p_libp2p` connection\n- Adds support for configurable runtime\n- Refactors documentation\n- Multiple docs updates\n- Multiple test stability fixes\n\n## 0.3.3 (2020-05-24)\n\n- Adds option to pass ledger APIs to `AEABuilder`\n- Refactors decision maker: separates interface and implementation; adds loading mechanisms so framework users can provide their own implementation\n- Adds asynchronous and synchronous agent loop implementations; agent can be run in both `sync` and `async` mode\n- Completes transition to atomic CLI commands (fetch, generate, scaffold)\n- Refactors dialogue API: adds much simplified API; updates generator accordingly; updates skills\n- Adds support for crypto module extensions: framework users can register their own crypto module\n- Adds crypto module and ledger support for cosmos\n- Adds simple-oef (soef) connection\n- Adds `p2p_libp2p` connection for true P2P connectivity\n- Adds PyPI dependency consistency checks for AEA projects\n- Refactors CLI for improved programmatic usage of components\n- Adds skill exception handling policies and configuration options\n- Adds comprehensive documentation of configuration files\n- Multiple docs updates\n- Multiple test stability fixes\n\n## 0.3.2 (2020-05-07)\n\n- Adds dialogue generation functionality to protocol generator\n- Fixes add CLI commands to be atomic\n- Adds Windows platform support\n- Stability improvements to test pipeline\n- Improves test coverage of CLI\n- Implements missing doc tests\n- Implements end-to-end tests for all skills\n- Adds missing agent projects to registry\n- Improves `AEABuilder` class for programmatic usage\n- Exposes missing AEA configurations on agent configuration file\n- Extends Aries demo\n- Adds method to check stdout for test cases\n- Adds code of conduct and security guidelines to repo\n- Multiple docs updates\n- Multiple additional unit tests\n- Multiple additional minor fixes and changes\n\n## 0.3.1 (2020-04-27)\n\n- Adds `p2p_stub` connection\n- Adds `p2p_noise` connection\n- Adds webhook connection\n- Upgrades error handling for error skill\n- Fixes default timeout on main agent loop and provides setter in `AEABuilder`\n- Adds multithreading support for launch command\n- Provides support for keyword arguments to AEA constructor to be set on skill context\n- Renames `ConfigurationType` with `PackageType` for consistency\n- Provides a new `AEATestCase` class for improved testing\n- Adds execution time limits for act/react calls\n- TAC skills refactoring and contract integration\n- Supports contract dependencies being added automatically\n- Adds HTTP example skill\n- Allows for skill inactivation during initialisation\n- Improves error messages on skill loading errors\n- Improves `README.md` files, particularly for PyPI\n- Adds support for Location based queries and descriptions\n- Refactors skills tests to use `AEATestCase`\n- Adds fingerprint and scaffold CLI command for contract\n- Adds multiple additional docs tests\n- Makes task manager initialize pool lazily\n- Multiple docs updates\n- Multiple additional unit tests\n- Multiple additional minor fixes and changes\n\n## 0.3.0 (2020-04-02)\n\n- Introduces IPFS based hashing of files to detect changes, ensure consistency and allow for content addressing\n- Introduces `aea fingerprint` command to CLI\n- Adds support for contract type packages which wrap smart contracts and their APIs\n- Introduces `AEABuilder` class for much improved programmatic usage of the framework\n- Moves protocol generator into alpha stage for light protocols\n- Switches CLI to use remote registry by default\n- Comprehensive documentation updates on new and existing features\n- Additional demos to introduce the contracts functionality\n- Protocol, Contract, Skill and Connection inherits from the same class, Component\n- Improved APIs for Configuration classes\n- All protocols now generated with protocol generator\n- Multiple additional unit tests\n- Multiple additional minor fixes and changes\n\n## 0.2.4 (2020-03-25)\n\n- Breaking change to all protocols as we transition to auto-generated protocols\n- Fixes to protocol generator to move it to alpha status\n- Updates to documentation on protocols and OEF search and communication nodes\n- Improvements and fixes to AEA launch command\n- Multiple docs updates and restructuring\n- Multiple additional minor fixes and changes\n\n## 0.2.3 (2020-03-19)\n\n- Fixes stub connection file I/O\n- Fixes OEF connection teardown\n- Fixes CLI GUI subprocesses issues\n- Adds support for URI based routing of envelopes\n- Improves skill guide by adding a service provider agent\n- Protocol generator bug fixes\n- Add `aea_version` field to package YAML files for version management\n- Multiple docs updates and restructuring\n- Multiple additional minor fixes and changes\n\n## 0.2.2 (2020-03-09)\n\n- Fixes registry to only load registered packages\n- Migrates default protocol to generator produced version\n- Adds http connection and http protocol\n- Adds CLI `init` command for easier setting of author\n- Refactoring and behind the scenes improvements to CLI\n- Multiple docs updates\n- Protocol generator improvements and fixes\n- Adds CLI launch command to launch multiple agents\n- Increases test coverage for AEA package and tests package\n- Make project comply with PEP 518\n- Multiple additional minor fixes and changes\n\n## 0.2.1 (2020-02-21)\n\n- Add minimal `aea install`\n- Updates finite state machine behaviour to use any simple behaviour in states\n- Adds example of programmatic and CLI based AEAs interacting\n- Exposes the logger on the skill context\n- Adds serialization (encoding/decoding) support to protocol generator\n- Adds additional docs and videos\n- Introduces test coverage to all code in docs\n- Increases test coverage for AEA package\n- Multiple additional minor fixes and changes\n\n## 0.2.0 (2020-02-07)\n\n- Skills can now programmatically register behaviours\n- Tasks are no longer a core component of the skill, the functor pattern is used\n- Refactors the task manager\n- Adds nonces to transaction data so transactions can be verified\n- Adds documentation for the protocol generator\n- Fixes several compatibility issues between CLI and registry\n- Adds skills to connect a thermometer to an AEA\n- Adds generic buyer and seller skills\n- Adds much more documentation on AEA vs MVC frameworks, core components, new guides and more\n- Removes the wallet from the agent constructor and moves it to the AEA constructor\n- Allows behaviours to be initialized from a skill\n- Adds multiple improvements to the protocol generator, including custom types and serialization\n- Removes the default crypto object\n- Replaces `SharedClass` with `Model` taxonomy for easier transition for web developers\n- Adds bandit to CLI for security checks\n- Makes private key paths in configurations a dictionary so values can be set from CLI\n- Introduces Identity object\n- Increases test coverage\n- Multiple additional minor fixes and changes\n\n## 0.1.17 (2020-01-27)\n\n- Add programmatic mode flag to AEA\n- Introduces vendorised project structure\n- Adds further tests for decision maker\n- Upgrades sign transaction function for Ethereum API proxy\n- Adds black and bugbear to linters\n- Applies public id usage throughout AEA business logic\n- Adds guide on how to deploy an AEA on a raspberry pi\n- Addresses multiple issues in the protocol generator\n- Fixes `aea-config`\n- Adds CLI commands to create wealth and get wealth and address\n- Change default author and license\n- Adds guide on agent vs AEAs\n- Updates docs and improves guides\n- Adds support for inactivating skills programmatically\n- Makes decision maker run in separate thread\n- Multiple additional minor fixes and changes\n\n## 0.1.16 (2020-01-12)\n\n- Completes tac skills implementation\n- Adds default ledger field to agent configuration\n- Converts ledger APIs to dictionary fields in agent configuration\n- Introduces public ids to CLI and deprecate usage of package names only\n- Adds local push and public commands to CLI\n- Introduces ledger API abstract class\n- Unifies import paths for static and dynamic imports\n- Disambiguates import paths by introducing pattern of `packages.author.package_type_pluralized.package_name`\n- Adds agent directory to packages with some samples\n- Adds protocol generator and exposes on CLI\n- Removes unused configuration fields\n- Updates docs to align with recent changes\n- Adds additional tests on CLI\n- Multiple additional minor fixes and changes\n\n## 0.1.15 (2019-12-19)\n\n- Moves non-default packages from AEA to packages directory\n- Supports get & set on package configurations\n- Changes skill configuration resource types from lists to dictionaries\n- Adds additional features to decision maker\n- Refactors most protocols and improves their API\n- Removes multiple unintended side-effects of the CLI\n- Improves dependency referencing in configuration files\n- Adds push and publish functionality to CLI\n- Introduces simple and composite behaviours and applies them in skills\n- Adds URI to envelopes\n- Adds guide for programmatic assembly of an AEA\n- Adds guide on agent-oriented development\n- Multiple minor doc updates\n- Adds additional tests\n- Multiple additional minor fixes and changes\n\n## 0.1.14 (2019-11-29)\n\n- Removes dependency on OEF SDK's FIPA API\n- Replaces dialogue id with dialogue references\n- Improves CLI logging and list/search command output\n- Introduces multiplexer and removes mailbox\n- Adds much improved tac skills\n- Adds support for CLI integration with registry\n- Increases test coverage to 99%\n- Introduces integration tests for skills and examples\n- Adds support to run multiple connections from CLI\n- Updates the docs and adds UML diagrams\n- Multiple additional minor fixes and changes\n\n## 0.1.13 (2019-11-08)\n\n- Adds envelope serialiser\n- Adds support for programmatically initializing an AEA\n- Adds some tests for the GUI and other components\n- Exposes connection status to skills\n- Updates OEF connection to re-establish dropped connections\n- Updates the car park agent\n- Multiple additional minor fixes and changes\n\n## 0.1.12 (2019-11-01)\n\n- Adds TCP connection (server and client)\n- Fixes some examples and docs\n- Refactors crypto modules and adds additional tests\n- Multiple additional minor fixes and changes\n\n## 0.1.11 (2019-10-30)\n\n- Adds Python 3.8 test coverage\n- Adds almost complete test coverage on AEA package\n- Adds filter concept for message routing\n- Adds ledger integrations for Fetch.ai and Ethereum\n- Adds car park examples and ledger examples\n- Multiple additional minor fixes and changes\n\n## 0.1.10 (2019-10-19)\n\n- Compatibility fixes for Ubuntu and Windows platforms\n- Multiple additional minor fixes and changes\n\n## 0.1.9 (2019-10-18)\n\n- Stability improvements\n- Higher test coverage, including on Python 3.6\n- Multiple additional minor fixes and changes\n\n## 0.1.8 (2019-10-18)\n\n- Multiple bug fixes and improvements to GUI of CLI\n- Adds full test coverage on CLI\n- Improves docs\n- Multiple additional minor fixes and changes\n\n## 0.1.7 (2019-10-14)\n\n- Adds GUI to interact with CLI\n- Adds new connection stub to read from/write to file\n- Adds ledger entities (fetchai and Ethereum); creates wallet for ledger entities\n- Adds more documentation and fixes old one\n- Multiple additional minor fixes and changes\n\n## 0.1.6 (2019-10-04)\n\n- Adds several new skills\n- Extended docs on framework and skills\n- Introduces core framework components like decision maker and shared classes\n- Multiple additional minor fixes and changes\n\n## 0.1.5 (2019-09-26)\n\n- Adds scaffolding command to the CLI tool\n- Extended docs\n- Increased test coverage\n- Multiple additional minor fixes and changes\n\n## 0.1.4 (2019-09-20)\n\n- Adds CLI functionality to add connections\n- Multiple additional minor fixes and changes\n\n## 0.1.3 (2019-09-19)\n\n- Adds Jenkins for CI\n- Adds docker develop image\n- Parses dependencies of connections/protocols/skills on the fly\n- Adds validations of configuration files\n- Adds first two working skills and fixes gym examples\n- Adds docs\n- Multiple additional minor fixes and changes\n\n## 0.1.2 (2019-09-16)\n\n- Adds AEA CLI tool.\n- Adds AEA skills framework.\n- Introduces static typing checks across AEA, using `Mypy`.\n- Extends gym example\n\n## 0.1.1 (2019-09-04)\n\n- Provides examples and fixes.\n\n## 0.1.0 (2019-08-21)\n\n- Initial release of the package.\n"
  },
  {
    "path": "LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright 2019 Fetch.AI Limited\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "MANIFEST.in",
    "content": "include README.md LICENSE HISTORY.md AUTHORS.md SECURITY.md CODE_OF_CONDUCT.md Pipfile mkdocs.yml tox.ini pytest.ini strategy.ini\n\nrecursive-include aea *.json *.yaml *.proto *.ico *png *.html *.js *.css *.md *.cfg json1.dll\nrecursive-include docs *\nrecursive-include examples *\nrecursive-include packages *\nrecursive-include plugins *\nrecursive-include scripts *\nrecursive-include tests *\n"
  },
  {
    "path": "Makefile",
    "content": "AEA_SRC_DIR := aea\nBENCHMARK_DIR := benchmark\nEXAMPLES_DIR := examples\nLIBS_DIR := libs\nPACKAGES_DIR := packages\nPLUGINS_DIR := plugins\nSCRIPTS_DIR := scripts\nAEA_TESTS_DIR := tests\nAEA_CORE_TESTS_DIRS := tests/test_aea tests/test_aea_extra ./tests/test_docs\nEXAMPLES_TESTS_DIRS := tests/test_examples\nPACKAGES_TESTS_DIRS := packages/fetchai/protocols packages/fetchai/connections packages/fetchai/skills ./tests/test_packages ./tests/test_packages_for_aea_tests ./tests/test_aea_core_packages\nDOCS_TESTS_DIR := tests/test_docs\nCONNECTIONS_DIR := packages/fetchai/connections\nCONTRACTS_DIR := packages/fetchai/contracts\nPROTOCOLS_DIR := packages/fetchai/protocols\nSKILLS_DIR := packages/fetchai/skills\n\nPLUGIN_FETCHAI_SRC := plugins/aea-ledger-fetchai/aea_ledger_fetchai\nPLUGIN_ETHEREUM_SRC := plugins/aea-ledger-ethereum/aea_ledger_ethereum\nPLUGIN_COSMOS_SRC := plugins/aea-ledger-cosmos/aea_ledger_cosmos\nPLUGIN_CLI_IPFS_SRC := plugins/aea-cli-ipfs/aea_cli_ipfs\nPLUGINS_SRC := $(PLUGIN_FETCHAI_SRC) $(PLUGIN_ETHEREUM_SRC) $(PLUGIN_COSMOS_SRC) $(PLUGIN_CLI_IPFS_SRC)\n\nPLUGIN_FETCHAI_TESTS := plugins/aea-ledger-fetchai/tests\nPLUGIN_ETHEREUM_TESTS := plugins/aea-ledger-ethereum/tests\nPLUGIN_COSMOS_TESTS := plugins/aea-ledger-cosmos/tests\nPLUGIN_CLI_IPFS_TESTS := plugins/aea-cli-ipfs/tests\nPLUGINS_TESTS := $(PLUGIN_FETCHAI_TESTS) $(PLUGIN_ETHEREUM_TESTS) $(PLUGIN_COSMOS_TESTS) $(PLUGIN_CLI_IPFS_TESTS)\n\nPLUGIN_FETCHAI := plugins/aea-ledger-fetchai\nPLUGIN_ETHEREUM := plugins/aea-ledger-ethereum\nPLUGIN_COSMOS := plugins/aea-ledger-cosmos\nPLUGIN_CLI_IPFS := plugins/aea-cli-ipfs\n\nPYTHON_CODE_DIRS := $(AEA_SRC_DIR) $(BENCHMARK_DIR) $(EXAMPLES_DIR) $(PACKAGES_DIR) $(PLUGINS_DIR) $(SCRIPTS_DIR) $(AEA_TESTS_DIR)\n\n########################################\n### Initialise dev environment\n########################################\n\n# Create a new poetry virtual environment with all the necessary dependencies installed.\n# Once finished, `poetry shell` to enter the virtual environment\nv := $(shell pip -V | grep virtualenvs)\n\n.PHONY: new-env\nnew-env: clean\n\tif [ -z \"$v\" ];\\\n\tthen\\\n\t\tpoetry install --with dev,docs,packages,tools,testing,types;\\\n\t\tpoetry run pip install --no-deps file:plugins/aea-ledger-ethereum;\\\n\t\tpoetry run pip install --no-deps file:plugins/aea-ledger-cosmos;\\\n\t\tpoetry run pip install --no-deps file:plugins/aea-ledger-fetchai;\\\n\t\tpoetry run pip install --no-deps file:plugins/aea-cli-ipfs;\\\n\t\techo \"Enter virtual environment with all development dependencies now: 'poetry shell'.\";\\\n\telse\\\n\t\techo \"In a virtual environment! Exit first: 'exit'.\";\\\n\tfi\n\n########################################\n### Tests\n########################################\n\n# Run all tests\n.PHONY: test\ntest: test-aea-all test-plugins\n\n# Run all aea tests\n.PHONY: test-aea-all\ntest-aea-all:\n\tpytest -rfE --doctest-modules $(AEA_TESTS_DIR) --cov=$(AEA_SRC_DIR) --cov=$(CONNECTIONS_DIR) --cov=$(CONTRACTS_DIR) --cov=$(PROTOCOLS_DIR) --cov=$(SKILLS_DIR) --cov-report=html --cov-report=term-missing --cov-config=pyproject.toml\n\tfind . -name \".coverage*\" -not -name \".coveragerc\" -exec rm -fr \"{}\" \\;\n\n.PHONY: test-aea-core\ntest-aea-core:\n\tpytest -rfE --doctest-modules $(AEA_CORE_TESTS_DIRS) --cov=$(AEA_SRC_DIR) --cov-report=html --cov-report=term-missing --cov-config=pyproject.toml\n\tfind . -name \".coverage*\" -not -name \".coveragerc\" -exec rm -fr \"{}\" \\;\n\n.PHONY: test-packages\ntest-packages:\n\tpytest -rfE --doctest-modules $(PACKAGES_TESTS_DIRS) --cov=$(AEA_SRC_DIR) --cov=$(CONNECTIONS_DIR) --cov=$(CONTRACTS_DIR) --cov=$(PROTOCOLS_DIR) --cov=$(SKILLS_DIR) --cov-report=html --cov-report=term-missing --cov-config=pyproject.toml\n\tfind . -name \".coverage*\" -not -name \".coveragerc\" -exec rm -fr \"{}\" \\;\n\n.PHONY: test-docs\ntest-docs:\n\tpytest -rfE --doctest-modules $(DOCS_TESTS_DIR) --cov=$(AEA_SRC_DIR) --cov-report=html --cov-report=term-missing --cov-config=pyproject.toml\n\tfind . -name \".coverage*\" -not -name \".coveragerc\" -exec rm -fr \"{}\" \\;\n\n.PHONY: test-examples\ntest-examples:\n\tpytest -rfE --doctest-modules $(EXAMPLES_TESTS_DIRS) --cov=$(AEA_SRC_DIR) --cov=$(CONNECTIONS_DIR) --cov=$(CONTRACTS_DIR) --cov=$(PROTOCOLS_DIR) --cov=$(SKILLS_DIR) --cov-report=html --cov-report=term-missing --cov-config=pyproject.toml\n\tfind . -name \".coverage*\" -not -name \".coveragerc\" -exec rm -fr \"{}\" \\;\n\n# Run all plugin tests\n.PHONY: test-plugins\ntest-plugins:\n\tpytest -rfE $(PLUGIN_FETCHAI_TESTS)  --cov=aea_ledger_fetchai  --cov-report=term-missing --cov-config=pyproject.toml\n\tpytest -rfE $(PLUGIN_ETHEREUM_TESTS) --cov=aea_ledger_ethereum --cov-report=term-missing --cov-config=pyproject.toml\n\tpytest -rfE $(PLUGIN_COSMOS_TESTS)   --cov=aea_ledger_cosmos   --cov-report=term-missing --cov-config=pyproject.toml\n\tpytest -rfE $(PLUGIN_CLI_IPFS_TESTS) --cov=aea_cli_ipfs        --cov-report=term-missing --cov-config=pyproject.toml\n\tfind . -name \".coverage*\" -not -name \".coveragerc\" -exec rm -fr \"{}\" \\;\n\n# Run tests for a particular python package\n.PHONY: test-sub\ntest-sub:\n\tpytest -rfE --doctest-modules $(AEA_TESTS_DIR)/test_$(tdir) --cov=aea.$(dir) --cov-report=html --cov-report=term-missing --cov-config=pyproject.toml\n\tfind . -name \".coverage*\" -not -name \".coveragerc\" -exec rm -fr \"{}\" \\;\n\n# Run tests for a particular aea package\n.PHONY: test-sub-p\ntest-sub-p:\n\tpytest -rfE --doctest-modules $(AEA_TESTS_DIR)/test_packages/test_$(tdir) --cov=packages.fetchai.$(dir) --cov-report=html --cov-report=term-missing --cov-config=pyproject.toml\n\tfind . -name \".coverage*\" -not -name \".coveragerc\" -exec rm -fr \"{}\" \\;\n\n# Produce the coverage report. Can see a report summary on the terminal.\n# Detailed report on all modules are placed under /htmlcov\n.PHONY: coverage-report\ncoverage-report:\n\tcoverage report -m -i\n\tcoverage html\n\n########################################\n### Code Styling\n########################################\n\n# Automatically run black and isort to format the code, and run flake8 and vulture checks\n.PHONY: lint\nlint: black isort flake8 vulture\n\n# Automatically format the code using black\n.PHONY: black\nblack:\n\tblack $(PYTHON_CODE_DIRS)\n\n# Automatically sort the imports\n.PHONY: isort\nisort:\n\tisort $(PYTHON_CODE_DIRS)\n\n# Check the code format\n.PHONY: black-check\nblack-check:\n\tblack --check --verbose $(PYTHON_CODE_DIRS)\n\n# Check the imports are sorted\n.PHONY: isort-check\nisort-check:\n\tisort --check-only --verbose $(PYTHON_CODE_DIRS)\n\n# Run flake8 linter\n.PHONY: flake8\nflake8:\n\tflake8 $(PYTHON_CODE_DIRS)\n\n# Check for unused code\n.PHONY: vulture\nvulture:\n\tvulture $(AEA_SRC_DIR) scripts/whitelist.py --exclude '*_pb2.py'\n\n########################################\n### Security & safety checks\n########################################\n\n# Run bandit and safety\n.PHONY: security\nsecurity: bandit safety\n\n# Check the security of the code\n.PHONY: bandit\nbandit:\n\tbandit -r $(AEA_SRC_DIR) $(BENCHMARK_DIR) $(EXAMPLES_DIR) $(PACKAGES_DIR) $(PLUGIN_FETCHAI_SRC) $(PLUGIN_ETHEREUM_SRC) $(PLUGIN_COSMOS_SRC) $(PLUGIN_CLI_IPFS_SRC)\n\tbandit -s B101 -r $(AEA_TESTS_DIR) $(SCRIPTS_DIR)\n\n# Check the security of the code for known vulnerabilities\n.PHONY: safety\nsafety:\n\tsafety check -i 44610 -i 50473\n\n########################################\n### Linters\n########################################\n\n# Check types (statically) using mypy\n.PHONY: mypy\nmypy:\n\tmypy aea packages benchmark --disallow-untyped-defs\n\tmypy examples --check-untyped-defs\n\tmypy scripts\n\tmypy tests --exclude \"serialization.py\"\n\n# Lint the code using pylint\n.PHONY: pylint\npylint:\n\tpylint -j0 -d E1136 $(AEA_SRC_DIR) $(BENCHMARK_DIR) $(EXAMPLES_DIR) $(PACKAGES_DIR) $(SCRIPTS_DIR) $(PLUGIN_FETCHAI_SRC) $(PLUGIN_ETHEREUM_SRC) $(PLUGIN_COSMOS_SRC) $(PLUGIN_CLI_IPFS_SRC)\n\n########################################\n### License and copyright checks\n########################################\n\n# Check dependency licenses\n.PHONY: liccheck\nliccheck:\n\tpoetry export > tmp-requirements.txt\n\tliccheck -s strategy.ini -r tmp-requirements.txt -l PARANOID\n\trm -frv tmp-requirements.txt\n\n# Check that the relevant files have appropriate Copyright header\n.PHONY: copyright-check\ncopyright-check:\n\tpython scripts/check_copyright_notice.py --directory .\n\n########################################\n### Docs\n########################################\n\n# Build documentation\n.PHONY: docs\ndocs:\n\tmkdocs build --clean\n\n# Live documentation server\n.PHONY: docs-live\ndocs-live:\n\tmkdocs serve\n\n# Generate API documentation (ensure you add the new pages created into /mkdocs.yml --> nav)\n.PHONY: generate-api-docs\ngenerate-api-docs:\n\tpython scripts/generate_api_docs.py $(args)\n\n# Check links are live in the documentation\n.PHONY: check-doc-links\ncheck-doc-links:\n\tpython scripts/check_doc_links.py\n\n########################################\n### Poetry Lock\n########################################\n\n# Updates the poetry lock\npoetry.lock: pyproject.toml\n\tpoetry lock\n\n########################################\n### Clear the caches and temporary files\n########################################\n\n# clean the caches and temporary files and directories\n.PHONY: clean\nclean: clean-build clean-pyc clean-test clean-docs\n\n.PHONY: clean-build\nclean-build:\n\trm -fr build/\n\trm -fr dist/\n\trm -fr .eggs/\n\trm -fr pip-wheel-metadata\n\tfind . -name '*.egg-info' -exec rm -fr {} +\n\tfind . -name '*.egg' -exec rm -fr {} +\n\trm -rf plugins/*/build\n\trm -rf plugins/*/dist\n\n.PHONY: clean-docs\nclean-docs:\n\trm -fr site/\n\n.PHONY: clean-pyc\nclean-pyc:\n\tfind . -name '*.pyc' -exec rm -f {} +\n\tfind . -name '*.pyo' -exec rm -f {} +\n\tfind . -name '*~' -exec rm -f {} +\n\tfind . -name '__pycache__' -exec rm -fr {} +\n\tfind . -name '.DS_Store' -exec rm -fr {} +\n\n.PHONY: clean-test\nclean-test:\n\trm -fr .tox/\n\trm -f .coverage\n\tfind . -name \".coverage*\" -not -name \".coveragerc\" -exec rm -fr \"{}\" \\;\n\trm -fr coverage.xml\n\trm -fr htmlcov/\n\trm -fr .hypothesis\n\trm -fr .pytest_cache\n\trm -fr .mypy_cache/\n\trm -fr input_file\n\trm -fr output_file\n\tfind . -name 'log.txt' -exec rm -fr {} +\n\tfind . -name 'log.*.txt' -exec rm -fr {} +\n\n########################################\n### Packages\n########################################\n\n# Update package hashes\n.PHONY: update-package-hashes\nupdate-package-hashes:\n\tpython scripts/generate_ipfs_hashes.py\n\n# Run all package checks\n.PHONY: package-checks\npackage-checks: check-package-hashes check-package-versions-in-docs check-packages\n\n# Check package hashes\n.PHONY: check-package-hashes\ncheck-package-hashes:\n\tpython scripts/generate_ipfs_hashes.py --check\n\n# Check correct package version in the docs\n.PHONY: check-package-versions-in-docs\ncheck-package-versions-in-docs:\n\tpython scripts/check_package_versions_in_docs.py\n\n# Perform various checks on packages\n.PHONY: check-packages\ncheck-packages:\n\tpython scripts/check_packages.py\n\n########################################\n### Other checks\n########################################\n\n# Check that libp2p code in libs and connection aren't different\n.PHONY: libp2p-diffs\nlibp2p-diffs:\n\tdiff libs/go/libp2p_node packages/fetchai/connections/p2p_libp2p/libp2p_node -r\n\n# Check that plugins for Cosmos and Fetch.ai, and Plugins' and main Licenses aren't different\n.PHONY: plugin-diffs\nplugin-diffs:\n\tdiff $(PLUGIN_COSMOS_SRC)/cosmos.py $(PLUGIN_FETCHAI_SRC)/_cosmos.py\n\tdiff LICENSE $(PLUGIN_COSMOS)/LICENSE\n\tdiff LICENSE $(PLUGIN_ETHEREUM)/LICENSE\n\tdiff LICENSE $(PLUGIN_FETCHAI)/LICENSE\n\n########################################\n### Build\n########################################\n\n# Build the project\n.PHONY: dist\ndist: clean\n\tpoetry build\n\nprotolint_install:\n\tGO111MODULE=on GOPATH=~/go go install github.com/yoheimuta/protolint/cmd/protolint@v0.27.0\nprotolint:\n\tPATH=${PATH}:${GOPATH}/bin/:~/go/bin protolint lint -config_path=./protolint.yaml -fix ./aea/mail ./packages/fetchai/protocols\nprotolint_install_win:\n\tpowershell -command '$$env:GO111MODULE=\"on\"; go install github.com/yoheimuta/protolint/cmd/protolint@v0.27.0'\nprotolint_win:\n\tprotolint lint -config_path=./protolint.yaml -fix ./aea/mail ./packages/fetchai/protocols\n"
  },
  {
    "path": "README.md",
    "content": "<h1 align=\"center\">\n    <b>AEA Framework</b>\n</h1>\n\n<p align=\"center\">\nCreate Autonomous Economic Agents (AEAs)\n</p>\n\n<p align=\"center\">\n  <a href=\"https://pypi.org/project/aea/\">\n    <img alt=\"PyPI\" src=\"https://img.shields.io/pypi/v/aea\">\n  </a>\n  <a href=\"https://pypi.org/project/aea/\">\n    <img alt=\"PyPI - Python Version\" src=\"https://img.shields.io/pypi/pyversions/aea\">\n  </a>\n  <a href=\"https://github.com/fetchai/agents-aea/blob/main/LICENSE\">\n    <img alt=\"License\" src=\"https://img.shields.io/pypi/l/aea\">\n  </a>\n  <a href=\"https://pypi.org/project/aea/\">\n    <img alt=\"License\" src=\"https://img.shields.io/pypi/dm/aea\">\n  </a>\n  <br />\n  <a href=\"https://github.com/fetchai/agents-aea/workflows/AEA%20framework%20sanity%20checks%20and%20tests\">\n    <img alt=\"AEA framework sanity checks and tests\" src=\"https://github.com/fetchai/agents-aea/workflows/AEA%20framework%20sanity%20checks%20and%20tests/badge.svg?branch=main\">\n  </a>\n  <a href=\"\">\n    <img alt=\"Codecov\" src=\"https://img.shields.io/codecov/c/github/fetchai/agents-aea\">\n  </a>\n  <a href=\"https://discord.gg/hy8SyhNnXf\">\n    <img src=\"https://img.shields.io/discord/441214316524339210.svg?logo=discord&logoColor=fff&label=Discord&color=7389d8\" alt=\"Discord conversation\" />\n  </a>\n</p>\n\nThe AEA framework allows you to create **Autonomous Economic Agents**:\n\n- An AEA is an <b>Agent</b>, representing an individual, family, organisation or object (a.k.a. its \"owner\") in the digital world. It looks after its owner's interests and has their preferences in mind when acting on their behalf.\n- AEAs are <b>Autonomous</b>; acting with no, or minimal, interference from their owners.\n- AEAs have a narrow and specific focus: creating <b>Economic</b> value for their owners.\n\n<p align=\"center\">\n  <a href=\"https://www.youtube.com/embed/xpJA4IT5X88\">\n    <img src=\"/data/video-aea.png?raw=true\" alt=\"AEA Video\" width=\"70%\"/>\n  </a>\n</p>\n\n## To install\n\n1. Ensure you have Python (version `3.8`, `3.9` or `3.10`).\n2. (optional) Use a virtual environment (e.g. [`pipenv`][pipenv] or [`poetry`][poetry]).\n3. Install: `pip install aea[all]`\n\nPlease see the [installation page][docs-install] for more details.\n\n## Documentation\n\nThe full documentation, including how to get started, can be found [here][docs].\n\n## Contributing\n\nAll contributions are very welcome! Remember, contribution is not only PRs and code, but any help with docs or helping other developers solve their issues are very appreciated!\n\nRead below to learn how you can take part in the AEA project.\n\n### Code of Conduct\n\nPlease be sure to read and follow our [Code of Conduct][coc]. By participating, you are expected to uphold this code.\n\n### Contribution Guidelines\n\nRead our [contribution guidelines][contributing] to learn about our issue and PR submission processes, coding rules, and more.\n\n### Development Guidelines\n\nRead our [development guidelines][developing] to learn about the development processes and workflows when contributing to different parts of the AEA project.\n\n### Issues, Questions and Discussions\n\nWe use [GitHub Issues][issues] for tracking requests and bugs, and [GitHub Discussions][discussion] for general questions and discussion.\n\n## License\n\nThe AEA project is licensed under [Apache License 2.0][license].\n\n[poetry]: https://python-poetry.org\n[pipenv]: https://pypi.org/project/pipenv/\n[docs]: https://docs.fetch.ai\n[contributing]: https://github.com/fetchai/agents-aea/blob/main/CONTRIBUTING.md\n[developing]: https://github.com/fetchai/agents-aea/blob/main/DEVELOPING.md\n[coc]: https://github.com/fetchai/agents-aea/blob/main/CODE_OF_CONDUCT.md\n[discussion]: https://github.com/fetchai/agents-aea/discussions\n[issues]: https://github.com/fetchai/agents-aea/issues\n[license]: https://github.com/fetchai/agents-aea/blob/main/LICENSE\n[docs-install]: https://docs.fetch.ai/aea/installation/\n"
  },
  {
    "path": "SECURITY.md",
    "content": "# Security Policy\n\nThis document outlines security procedures and general policies for the `aea` project.\n\n## Supported Versions\n\nThe following table shows which versions of `aea` are currently being supported with security updates.\n\n| Version   | Supported          |\n|-----------|--------------------|\n| `1.2.x`   | :white_check_mark: |\n| `< 1.2.0` | :x:                |\n\n## Reporting a Vulnerability\n\nThe `aea` team and community take all security bugs in `aea` seriously. Thank you for improving the security of `aea`. We appreciate your efforts and responsible disclosure and will make every effort to acknowledge your contributions.\n\nReport security bugs by emailing `developer@fetch.ai`.\n\nThe lead maintainer will acknowledge your email within 48 hours, and will send a more detailed response within 48 hours indicating the next steps in handling your report. After the initial reply to your report, the security team will endeavour to keep you informed of the progress towards a fix and full announcement, and may ask for additional information or guidance.\n\nReport security bugs in third-party modules to the person or team maintaining the module.\n\n## Disclosure Policy\n\nWhen the security team receives a security bug report, they will assign it to a primary handler. This person will coordinate the fix and release process, involving the following steps:\n\n- Confirm the problem and determine the affected versions.\n- Audit code to find any potential similar problems.\n- Prepare fixes for all releases still under maintenance. These fixes will be released as fast as possible to PyPI.\n\n## Comments on this Policy\n\nIf you have suggestions on how this process could be improved please submit a pull request.\n"
  },
  {
    "path": "aea/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Contains the AEA package.\"\"\"\n\nimport inspect\nimport os\n\nfrom packaging.version import Version\n\nimport aea.crypto  # triggers registry population\nfrom aea.__version__ import (\n    __author__,\n    __copyright__,\n    __description__,\n    __license__,\n    __title__,\n    __url__,\n    __version__,\n)\nfrom aea.crypto.plugin import load_all_plugins\n\n\nAEA_DIR = os.path.dirname(inspect.getfile(inspect.currentframe()))  # type: ignore\n\nload_all_plugins()\n\n\ndef get_current_aea_version() -> Version:\n    \"\"\"Get current version.\"\"\"\n    return Version(__version__)\n"
  },
  {
    "path": "aea/__version__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Specifies the version of the AEA package.\"\"\"\n\n__title__ = \"aea\"\n__description__ = \"Autonomous Economic Agent framework\"\n__url__ = \"https://github.com/fetchai/agents-aea.git\"\n__version__ = \"1.2.5\"\n__author__ = \"Fetch.AI Limited\"\n__license__ = \"Apache-2.0\"\n__copyright__ = \"2022 Fetch.AI Limited\"\n"
  },
  {
    "path": "aea/abstract_agent.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the interface definition of the abstract agent.\"\"\"\nimport datetime\nfrom abc import ABC, abstractmethod\nfrom typing import Any, Callable, Dict, List, Optional, Tuple\n\nfrom aea.mail.base import Envelope\n\n\nclass AbstractAgent(ABC):\n    \"\"\"This class provides an abstract base  interface for an agent.\"\"\"\n\n    @property\n    @abstractmethod\n    def name(self) -> str:\n        \"\"\"Get agent's name.\"\"\"\n\n    @property\n    @abstractmethod\n    def storage_uri(self) -> Optional[str]:\n        \"\"\"Return storage uri.\"\"\"\n\n    @abstractmethod\n    def start(self) -> None:\n        \"\"\"\n        Start the agent.\n\n        :return: None\n        \"\"\"\n\n    @abstractmethod\n    def stop(self) -> None:\n        \"\"\"\n        Stop the agent.\n\n        :return: None\n        \"\"\"\n\n    @abstractmethod\n    def setup(self) -> None:\n        \"\"\"\n        Set up the agent.\n\n        :return: None\n        \"\"\"\n\n    @abstractmethod\n    def act(self) -> None:\n        \"\"\"\n        Perform actions on period.\n\n        :return: None\n        \"\"\"\n\n    @abstractmethod\n    def handle_envelope(self, envelope: Envelope) -> None:\n        \"\"\"\n        Handle an envelope.\n\n        :param envelope: the envelope to handle.\n        :return: None\n        \"\"\"\n\n    @abstractmethod\n    def get_periodic_tasks(\n        self,\n    ) -> Dict[Callable, Tuple[float, Optional[datetime.datetime]]]:\n        \"\"\"\n        Get all periodic tasks for agent.\n\n        :return: dict of callable with period specified\n        \"\"\"\n\n    @abstractmethod\n    def get_message_handlers(self) -> List[Tuple[Callable[[Any], None], Callable]]:\n        \"\"\"\n        Get handlers with message getters.\n\n        :return: List of tuples of callables: handler and coroutine to get a message\n        \"\"\"\n\n    @abstractmethod\n    def exception_handler(\n        self, exception: Exception, function: Callable\n    ) -> Optional[bool]:\n        \"\"\"\n        Handle exception raised during agent main loop execution.\n\n        :param exception: exception raised\n        :param function: a callable exception raised in.\n\n        :return: skip exception if True, otherwise re-raise it\n        \"\"\"\n\n    @abstractmethod\n    def teardown(self) -> None:\n        \"\"\"\n        Tear down the agent.\n\n        :return: None\n        \"\"\"\n"
  },
  {
    "path": "aea/aea.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the implementation of an autonomous economic agent (AEA).\"\"\"\nimport datetime\nfrom asyncio import AbstractEventLoop\nfrom logging import Logger\nfrom multiprocessing.pool import AsyncResult\nfrom typing import (\n    Any,\n    Callable,\n    Collection,\n    Dict,\n    List,\n    Optional,\n    Sequence,\n    Tuple,\n    Type,\n    cast,\n)\n\nfrom aea.agent import Agent\nfrom aea.agent_loop import AsyncAgentLoop, BaseAgentLoop, SyncAgentLoop\nfrom aea.configurations.base import PublicId\nfrom aea.configurations.constants import (\n    DEFAULT_BUILD_DIR_NAME,\n    DEFAULT_SEARCH_SERVICE_ADDRESS,\n)\nfrom aea.context.base import AgentContext\nfrom aea.crypto.ledger_apis import DEFAULT_CURRENCY_DENOMINATIONS\nfrom aea.crypto.wallet import Wallet\nfrom aea.decision_maker.base import DecisionMakerHandler\nfrom aea.error_handler.base import AbstractErrorHandler\nfrom aea.error_handler.default import ErrorHandler as DefaultErrorHandler\nfrom aea.exceptions import AEAException, _StopRuntime\nfrom aea.helpers.exception_policy import ExceptionPolicyEnum\nfrom aea.helpers.logging import AgentLoggerAdapter, WithLogger, get_logger\nfrom aea.identity.base import Identity\nfrom aea.mail.base import Envelope\nfrom aea.protocols.base import Message, Protocol\nfrom aea.registries.filter import Filter\nfrom aea.registries.resources import Resources\nfrom aea.skills.base import Behaviour, Handler\n\n\nclass AEA(Agent):\n    \"\"\"This class implements an autonomous economic agent.\"\"\"\n\n    RUN_LOOPS: Dict[str, Type[BaseAgentLoop]] = {\n        \"async\": AsyncAgentLoop,\n        \"sync\": SyncAgentLoop,\n    }\n    DEFAULT_RUN_LOOP: str = \"async\"\n\n    DEFAULT_BUILD_DIR_NAME = DEFAULT_BUILD_DIR_NAME\n\n    def __init__(\n        self,\n        identity: Identity,\n        wallet: Wallet,\n        resources: Resources,\n        data_dir: str,\n        loop: Optional[AbstractEventLoop] = None,\n        period: float = 0.05,\n        execution_timeout: float = 0,\n        max_reactions: int = 20,\n        error_handler_class: Optional[Type[AbstractErrorHandler]] = None,\n        error_handler_config: Optional[Dict[str, Any]] = None,\n        decision_maker_handler_class: Optional[Type[DecisionMakerHandler]] = None,\n        decision_maker_handler_config: Optional[Dict[str, Any]] = None,\n        skill_exception_policy: ExceptionPolicyEnum = ExceptionPolicyEnum.propagate,\n        connection_exception_policy: ExceptionPolicyEnum = ExceptionPolicyEnum.propagate,\n        loop_mode: Optional[str] = None,\n        runtime_mode: Optional[str] = None,\n        default_ledger: Optional[str] = None,\n        currency_denominations: Optional[Dict[str, str]] = None,\n        default_connection: Optional[PublicId] = None,\n        default_routing: Optional[Dict[PublicId, PublicId]] = None,\n        connection_ids: Optional[Collection[PublicId]] = None,\n        search_service_address: str = DEFAULT_SEARCH_SERVICE_ADDRESS,\n        storage_uri: Optional[str] = None,\n        task_manager_mode: Optional[str] = None,\n        **kwargs: Any,\n    ) -> None:\n        \"\"\"\n        Instantiate the agent.\n\n        :param identity: the identity of the agent\n        :param wallet: the wallet of the agent.\n        :param resources: the resources (protocols and skills) of the agent.\n        :param data_dir: directory where to put local files.\n        :param loop: the event loop to run the connections.\n        :param period: period to call agent's act\n        :param execution_timeout: amount of time to limit single act/handle to execute.\n        :param max_reactions: the processing rate of envelopes per tick (i.e. single loop).\n        :param error_handler_class: the class implementing the error handler\n        :param error_handler_config: the configuration of the error handler\n        :param decision_maker_handler_class: the class implementing the decision maker handler to be used.\n        :param decision_maker_handler_config: the configuration of the decision maker handler\n        :param skill_exception_policy: the skill exception policy enum\n        :param connection_exception_policy: the connection exception policy enum\n        :param loop_mode: loop_mode to choose agent run loop.\n        :param runtime_mode: runtime mode (async, threaded) to run AEA in.\n        :param default_ledger: default ledger id\n        :param currency_denominations: mapping from ledger id to currency denomination\n        :param default_connection: public id to the default connection\n        :param default_routing: dictionary for default routing.\n        :param connection_ids: active connection ids. Default: consider all the ones in the resources.\n        :param search_service_address: the address of the search service used.\n        :param storage_uri: optional uri to set generic storage\n        :param task_manager_mode: task manager mode (threaded) to run tasks with.\n        :param kwargs: keyword arguments to be attached in the agent context namespace.\n        \"\"\"\n\n        self._skills_exception_policy = skill_exception_policy\n        self._connection_exception_policy = connection_exception_policy\n\n        aea_logger = AgentLoggerAdapter(\n            logger=get_logger(__name__, identity.name),\n            agent_name=identity.name,\n        )\n\n        self._resources = resources\n        super().__init__(\n            identity=identity,\n            connections=[],\n            loop=loop,\n            period=period,\n            loop_mode=loop_mode,\n            runtime_mode=runtime_mode,\n            storage_uri=storage_uri,\n            logger=cast(Logger, aea_logger),\n            task_manager_mode=task_manager_mode,\n        )\n\n        default_routing = default_routing if default_routing is not None else {}\n        connection_ids = connection_ids or []\n        connections = [\n            c\n            for c in self.resources.get_all_connections()\n            if (not connection_ids) or (c.connection_id in connection_ids)\n        ]\n\n        if not bool(self.resources.get_all_connections()):\n            self.logger.warning(\n                \"Resource's connections list is empty! Instantiating AEA without connections...\"\n            )\n        elif bool(self.resources.get_all_connections()) and not bool(connections):\n            self.logger.warning(  # pragma: nocover\n                \"No connection left after filtering! Instantiating AEA without connections...\"\n            )\n\n        self._set_runtime_and_mail_boxes(\n            runtime_class=self._get_runtime_class(),\n            loop_mode=loop_mode,\n            loop=loop,\n            multiplexer_options=dict(\n                connections=connections,\n                default_routing=default_routing,\n                default_connection=default_connection,\n                protocols=self.resources.get_all_protocols(),\n            ),\n        )\n\n        self.max_reactions = max_reactions\n\n        if decision_maker_handler_class is None:\n            from aea.decision_maker.default import (  # isort:skip  # pylint: disable=import-outside-toplevel\n                DecisionMakerHandler as DefaultDecisionMakerHandler,\n            )\n\n            decision_maker_handler_class = DefaultDecisionMakerHandler\n        if decision_maker_handler_config is None:\n            decision_maker_handler_config = {}\n        decision_maker_handler = decision_maker_handler_class(\n            identity=identity, wallet=wallet, config=decision_maker_handler_config\n        )\n        self.runtime.set_decision_maker(decision_maker_handler)\n\n        if error_handler_class is None:\n            error_handler_class = DefaultErrorHandler\n        if error_handler_config is None:\n            error_handler_config = {}\n        self._error_handler = error_handler_class(**error_handler_config)\n        default_ledger_id = (\n            default_ledger\n            if default_ledger is not None\n            else identity.default_address_key\n        )\n        currency_denominations = (\n            currency_denominations\n            if currency_denominations is not None\n            else DEFAULT_CURRENCY_DENOMINATIONS\n        )\n        self._context = AgentContext(\n            self.identity,\n            self.runtime.multiplexer.connection_status,\n            self.outbox,\n            self.runtime.decision_maker.message_in_queue,\n            decision_maker_handler.context,\n            self.runtime.task_manager,\n            default_ledger_id,\n            currency_denominations,\n            default_connection,\n            default_routing,\n            search_service_address,\n            decision_maker_handler.self_address,\n            data_dir,\n            storage_callable=lambda: self.runtime.storage,\n            build_dir=self.get_build_dir(),\n            send_to_skill=self.runtime.agent_loop.send_to_skill,\n            **kwargs,\n        )\n        self._execution_timeout = execution_timeout\n        self._filter = Filter(\n            self.resources, self.runtime.decision_maker.message_out_queue\n        )\n\n        self._setup_loggers()\n\n    @classmethod\n    def get_build_dir(cls) -> str:\n        \"\"\"Get agent build directory.\"\"\"\n        return cls.DEFAULT_BUILD_DIR_NAME\n\n    @property\n    def context(self) -> AgentContext:\n        \"\"\"Get (agent) context.\"\"\"\n        return self._context\n\n    @property\n    def resources(self) -> Resources:\n        \"\"\"Get resources.\"\"\"\n        return self._resources\n\n    @resources.setter\n    def resources(self, resources: \"Resources\") -> None:\n        \"\"\"Set resources.\"\"\"\n        self._resources = resources\n\n    @property\n    def filter(self) -> Filter:\n        \"\"\"Get the filter.\"\"\"\n        return self._filter\n\n    @property\n    def active_behaviours(self) -> List[Behaviour]:\n        \"\"\"Get all active behaviours to use in act.\"\"\"\n        return self.filter.get_active_behaviours()\n\n    def setup(self) -> None:\n        \"\"\"\n        Set up the agent.\n\n        Calls setup() on the resources.\n        \"\"\"\n        self.resources.setup()\n\n    def act(self) -> None:\n        \"\"\"\n        Perform actions.\n\n        Adds new handlers and behaviours for use/execution by the runtime.\n        \"\"\"\n        self.filter.handle_new_handlers_and_behaviours()\n\n    def _get_error_handler(self) -> AbstractErrorHandler:\n        \"\"\"Get error handler.\"\"\"\n        return self._error_handler\n\n    def _get_msg_and_handlers_for_envelope(\n        self, envelope: Envelope\n    ) -> Tuple[Optional[Message], List[Handler]]:\n        \"\"\"Get the msg and its handlers.\"\"\"\n        protocol = self.resources.get_protocol_by_specification_id(\n            envelope.protocol_specification_id\n        )\n\n        error_handler = self._get_error_handler()\n\n        if protocol is None:\n            error_handler.send_unsupported_protocol(envelope, self.logger)\n            return None, []\n\n        msg, handlers = self._handle_decoding(envelope, protocol, error_handler)\n\n        return msg, handlers\n\n    def _handle_decoding(\n        self,\n        envelope: Envelope,\n        protocol: Protocol,\n        error_handler: AbstractErrorHandler,\n    ) -> Tuple[Optional[Message], List[Handler]]:\n\n        handlers = self.filter.get_active_handlers(\n            protocol.public_id, envelope.to_as_public_id\n        )\n\n        if len(handlers) == 0:\n            reason = (\n                f\"no active handler for protocol={protocol.public_id} in skill={envelope.to_as_public_id}\"\n                if envelope.is_component_to_component_message\n                else f\"no active handler for protocol={protocol.public_id}\"\n            )\n            error_handler.send_no_active_handler(envelope, reason, self.logger)\n            return None, []\n\n        if isinstance(envelope.message, Message):\n            msg = envelope.message\n            return msg, handlers\n        try:\n            msg = protocol.serializer.decode(envelope.message)\n            msg.sender = envelope.sender\n            msg.to = envelope.to\n            return msg, handlers\n        except Exception as e:  # pylint: disable=broad-except  # thats ok, because we send the decoding error back\n            error_handler.send_decoding_error(envelope, e, self.logger)\n            return None, []\n\n    def handle_envelope(self, envelope: Envelope) -> None:\n        \"\"\"\n        Handle an envelope.\n\n        Performs the following:\n\n        - fetching the protocol referenced by the envelope, and\n        - handling if the protocol is unsupported, using the error handler, or\n        - handling if there is a decoding error, using the error handler, or\n        - handling if no active handler is available for the specified protocol, using the error handler, or\n        - handling the message recovered from the envelope with all active handlers for the specified protocol.\n\n        :param envelope: the envelope to handle.\n        :return: None\n        \"\"\"\n        self.logger.debug(\"Handling envelope: {}\".format(envelope))\n        msg, handlers = self._get_msg_and_handlers_for_envelope(envelope)\n\n        if msg is None:\n            return\n\n        for handler in handlers:\n            handler.handle_wrapper(msg)\n\n    def _setup_loggers(self) -> None:\n        \"\"\"Set up logger with agent name.\"\"\"\n        for element in [\n            self.runtime.agent_loop,\n            self.runtime.multiplexer,\n            self.runtime.task_manager,\n            self.resources.component_registry,\n            self.resources.behaviour_registry,\n            self.resources.handler_registry,\n            self.resources.model_registry,\n        ]:\n            element = cast(WithLogger, element)\n            element.logger = cast(\n                Logger,\n                AgentLoggerAdapter(element.logger, agent_name=self._identity.name),\n            )\n\n    def get_periodic_tasks(\n        self,\n    ) -> Dict[Callable, Tuple[float, Optional[datetime.datetime]]]:\n        \"\"\"\n        Get all periodic tasks for agent.\n\n        :return: dict of callable with period specified\n        \"\"\"\n        tasks = super().get_periodic_tasks()\n        tasks.update(self._get_behaviours_tasks())\n        return tasks\n\n    def _get_behaviours_tasks(\n        self,\n    ) -> Dict[Callable, Tuple[float, Optional[datetime.datetime]]]:\n        \"\"\"\n        Get all periodic tasks for AEA behaviours.\n\n        :return: dict of callable with period specified\n        \"\"\"\n        tasks = {}\n\n        for behaviour in self.active_behaviours:\n            tasks[behaviour.act_wrapper] = (behaviour.tick_interval, behaviour.start_at)\n\n        return tasks\n\n    def get_message_handlers(self) -> List[Tuple[Callable[[Any], None], Callable]]:\n        \"\"\"\n        Get handlers with message getters.\n\n        :return: List of tuples of callables: handler and coroutine to get a message\n        \"\"\"\n        return super().get_message_handlers() + [\n            (\n                self.filter.handle_internal_message,\n                self.filter.get_internal_message,\n            ),\n            (self.handle_envelope, self.runtime.agent_loop.skill2skill_queue.get),\n        ]\n\n    def exception_handler(self, exception: Exception, function: Callable) -> bool:\n        \"\"\"\n        Handle exception raised during agent main loop execution.\n\n        :param exception: exception raised\n        :param function: a callable exception raised in.\n\n        :return: bool, propagate exception if True otherwise skip it.\n        \"\"\"\n        # docstyle: ignore # noqa: E800\n        def log_exception(e: Exception, fn: Callable, is_debug: bool = False) -> None:\n            if is_debug:\n                self.logger.debug(f\"<{e}> raised during `{fn}`\")\n            else:\n                self.logger.exception(f\"<{e}> raised during `{fn}`\")\n\n        if self._skills_exception_policy == ExceptionPolicyEnum.propagate:\n            log_exception(exception, function, is_debug=True)\n            return True\n\n        if self._skills_exception_policy == ExceptionPolicyEnum.stop_and_exit:\n            log_exception(exception, function)\n            raise _StopRuntime(\n                AEAException(\n                    f\"AEA was terminated cause exception `{exception}` in skills {function}! Please check logs.\"\n                )\n            )\n\n        if self._skills_exception_policy == ExceptionPolicyEnum.just_log:\n            log_exception(exception, function)\n            return False\n\n        raise AEAException(\n            f\"Unsupported exception policy: {self._skills_exception_policy}\"\n        )\n\n    def teardown(self) -> None:\n        \"\"\"\n        Tear down the agent.\n\n        Performs the following:\n\n        - tears down the resources.\n        \"\"\"\n        self.resources.teardown()\n\n    def get_task_result(self, task_id: int) -> AsyncResult:\n        \"\"\"\n        Get the result from a task.\n\n        :param task_id: the id of the task\n        :return: async result for task_id\n        \"\"\"\n        return self.runtime.task_manager.get_task_result(task_id)\n\n    def enqueue_task(\n        self,\n        func: Callable,\n        args: Sequence = (),\n        kwargs: Optional[Dict[str, Any]] = None,\n    ) -> int:\n        \"\"\"\n        Enqueue a task with the task manager.\n\n        :param func: the callable instance to be enqueued\n        :param args: the positional arguments to be passed to the function.\n        :param kwargs: the keyword arguments to be passed to the function.\n        :return: the task id to get the the result.\n        \"\"\"\n        return self.runtime.task_manager.enqueue_task(func, args, kwargs)\n"
  },
  {
    "path": "aea/aea_builder.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains utilities for building an AEA.\"\"\"\nimport ast\nimport logging\nimport logging.config\nimport os\nimport pprint\nimport subprocess  # nosec\nimport sys\nfrom collections import defaultdict\nfrom copy import deepcopy\nfrom importlib import import_module\nfrom pathlib import Path\nfrom typing import Any, Collection, Dict, List, Optional, Set, Tuple, Type, Union, cast\n\nimport jsonschema\nfrom packaging.specifiers import SpecifierSet\n\nfrom aea.aea import AEA\nfrom aea.common import PathLike\nfrom aea.components.base import Component, load_aea_package\nfrom aea.components.loader import load_component_from_config\nfrom aea.configurations.base import (\n    AgentConfig,\n    ComponentConfiguration,\n    ComponentId,\n    ComponentType,\n    ConnectionConfig,\n    ContractConfig,\n    Dependencies,\n    PackageType,\n    ProtocolConfig,\n    PublicId,\n    SkillConfig,\n)\nfrom aea.configurations.constants import (\n    CONNECTIONS,\n    DEFAULT_AEA_CONFIG_FILE,\n    DEFAULT_ENV_DOTFILE,\n    DEFAULT_LEDGER,\n    DEFAULT_LOGGING_CONFIG,\n    DEFAULT_PROTOCOL,\n    DEFAULT_REGISTRY_NAME,\n)\nfrom aea.configurations.constants import (\n    DEFAULT_SEARCH_SERVICE_ADDRESS as _DEFAULT_SEARCH_SERVICE_ADDRESS,\n)\nfrom aea.configurations.constants import (\n    DOTTED_PATH_MODULE_ELEMENT_SEPARATOR,\n    PROTOCOLS,\n    SIGNING_PROTOCOL,\n    SKILLS,\n    STATE_UPDATE_PROTOCOL,\n    _FETCHAI_IDENTIFIER,\n)\nfrom aea.configurations.data_types import PackageIdPrefix\nfrom aea.configurations.loader import ConfigLoader, load_component_configuration\nfrom aea.configurations.manager import (\n    AgentConfigManager,\n    find_component_directory_from_component_id,\n)\nfrom aea.configurations.pypi import (\n    is_satisfiable,\n    merge_dependencies,\n    merge_dependencies_list,\n)\nfrom aea.configurations.validation import ExtraPropertiesError\nfrom aea.crypto.helpers import private_key_verify\nfrom aea.crypto.ledger_apis import DEFAULT_CURRENCY_DENOMINATIONS\nfrom aea.crypto.wallet import Wallet\nfrom aea.decision_maker.base import DecisionMakerHandler\nfrom aea.error_handler.base import AbstractErrorHandler\nfrom aea.exceptions import (\n    AEAException,\n    AEAValidationError,\n    AEAWalletNoAddressException,\n    enforce,\n)\nfrom aea.helpers.base import (\n    SimpleId,\n    find_topological_order,\n    load_env_file,\n    load_module,\n)\nfrom aea.helpers.exception_policy import ExceptionPolicyEnum\nfrom aea.helpers.install_dependency import install_dependency\nfrom aea.helpers.io import open_file\nfrom aea.helpers.logging import AgentLoggerAdapter, WithLogger, get_logger\nfrom aea.identity.base import Identity\nfrom aea.registries.resources import Resources\n\n\n_default_logger = logging.getLogger(__name__)\n\n\nclass _DependenciesManager:\n    \"\"\"Class to manage dependencies of agent packages.\"\"\"\n\n    def __init__(self) -> None:\n        \"\"\"Initialize the dependency graph.\"\"\"\n        # adjacency list of the dependency DAG\n        # an arc means \"depends on\"\n        self._dependencies = {}  # type: Dict[ComponentId, ComponentConfiguration]\n        self._all_dependencies_by_type = (\n            {}\n        )  # type: Dict[ComponentType, Dict[ComponentId, ComponentConfiguration]]\n        self._prefix_to_components = {}  # type: Dict[PackageIdPrefix, Set[ComponentId]]\n        self._inverse_dependency_graph = {}  # type: Dict[ComponentId, Set[ComponentId]]\n\n        self.agent_pypi_dependencies: Dependencies = {}\n\n    @property\n    def all_dependencies(self) -> Set[ComponentId]:\n        \"\"\"Get all dependencies.\"\"\"\n        result = set(self._dependencies.keys())\n        return result\n\n    @property\n    def dependencies_highest_version(self) -> Set[ComponentId]:\n        \"\"\"Get the dependencies with highest version.\"\"\"\n        return {max(ids) for _, ids in self._prefix_to_components.items()}\n\n    def get_components_by_type(\n        self, component_type: ComponentType\n    ) -> Dict[ComponentId, ComponentConfiguration]:\n        \"\"\"Get the components by type.\"\"\"\n        return self._all_dependencies_by_type.get(component_type, {})\n\n    @property\n    def protocols(self) -> Dict[ComponentId, ProtocolConfig]:\n        \"\"\"Get the protocols.\"\"\"\n        return cast(\n            Dict[ComponentId, ProtocolConfig],\n            self._all_dependencies_by_type.get(ComponentType.PROTOCOL, {}),\n        )\n\n    @property\n    def connections(self) -> Dict[ComponentId, ConnectionConfig]:\n        \"\"\"Get the connections.\"\"\"\n        return cast(\n            Dict[ComponentId, ConnectionConfig],\n            self._all_dependencies_by_type.get(ComponentType.CONNECTION, {}),\n        )\n\n    @property\n    def skills(self) -> Dict[ComponentId, SkillConfig]:\n        \"\"\"Get the skills.\"\"\"\n        return cast(\n            Dict[ComponentId, SkillConfig],\n            self._all_dependencies_by_type.get(ComponentType.SKILL, {}),\n        )\n\n    @property\n    def contracts(self) -> Dict[ComponentId, ContractConfig]:\n        \"\"\"Get the contracts.\"\"\"\n        return cast(\n            Dict[ComponentId, ContractConfig],\n            self._all_dependencies_by_type.get(ComponentType.CONTRACT, {}),\n        )\n\n    def add_component(self, configuration: ComponentConfiguration) -> None:\n        \"\"\"\n        Add a component to the dependency manager.\n\n        :param configuration: the component configuration to add.\n        \"\"\"\n        # add to main index\n        self._dependencies[configuration.component_id] = configuration\n        # add to index by type\n        self._all_dependencies_by_type.setdefault(configuration.component_type, {})[\n            configuration.component_id\n        ] = configuration\n        # add to prefix to id index\n        self._prefix_to_components.setdefault(\n            configuration.component_id.component_prefix, set()\n        ).add(configuration.component_id)\n        # populate inverse dependency\n        for dependency in configuration.package_dependencies:\n            self._inverse_dependency_graph.setdefault(dependency, set()).add(\n                configuration.component_id\n            )\n\n    def remove_component(self, component_id: ComponentId) -> None:\n        \"\"\"\n        Remove a component.\n\n        :param component_id: the component id\n        :raises ValueError: if some component depends on this package.\n        \"\"\"\n        if component_id not in self.all_dependencies:\n            raise ValueError(\n                \"Component {} of type {} not present.\".format(\n                    component_id.public_id, component_id.component_type\n                )\n            )\n        dependencies = self._inverse_dependency_graph.get(component_id, set())\n        if len(dependencies) != 0:\n            raise ValueError(\n                \"Cannot remove component {} of type {}. Other components depends on it: {}\".format(\n                    component_id.public_id, component_id.component_type, dependencies\n                )\n            )\n\n        # remove from the index of all dependencies\n        component = self._dependencies.pop(component_id)\n        # remove from the index of all dependencies grouped by type\n        self._all_dependencies_by_type[component_id.component_type].pop(component_id)\n\n        if len(self._all_dependencies_by_type[component_id.component_type]) == 0:\n            self._all_dependencies_by_type.pop(component_id.component_type)\n        # remove from prefix to id index\n        self._prefix_to_components.get(component_id.component_prefix, set()).discard(\n            component_id\n        )\n        # update inverse dependency graph\n        for dependency in component.package_dependencies:\n            self._inverse_dependency_graph[dependency].discard(component_id)\n\n    @property\n    def pypi_dependencies(self) -> Dependencies:\n        \"\"\"\n        Get all the PyPI dependencies.\n\n        We currently consider only dependency that have the\n        default PyPI index url and that specify only the\n        version field.\n\n        :return: the merged PyPI dependencies\n        \"\"\"\n        all_pypi_dependencies = merge_dependencies_list(\n            self.agent_pypi_dependencies,\n            *[\n                configuration.pypi_dependencies\n                for configuration in self._dependencies.values()\n            ],\n        )\n        return all_pypi_dependencies\n\n    def install_dependencies(self) -> None:\n        \"\"\"Install extra dependencies for components.\"\"\"\n        for name, d in self.pypi_dependencies.items():\n            install_dependency(name, d, _default_logger)\n\n\nclass AEABuilder(WithLogger):  # pylint: disable=too-many-public-methods\n    \"\"\"\n    This class helps to build an AEA.\n\n    It follows the fluent interface. Every method of the builder\n    returns the instance of the builder itself.\n\n    Note: the method 'build()' is guaranteed of being\n    re-entrant with respect to the 'add_component(path)'\n    method. That is, you can invoke the building method\n    many times against the same builder instance, and the\n    returned agent instance will not share the\n    components with other agents, e.g.:\n\n        builder = AEABuilder()\n        builder.add_component(...)\n        ...\n\n        # first call\n        my_aea_1 = builder.build()\n\n        # following agents will have different components.\n        my_aea_2 = builder.build()  # all good\n\n    However, if you manually loaded some of the components and added\n    them with the method 'add_component_instance()', then calling build\n    more than one time is prevented:\n\n        builder = AEABuilder()\n        builder.add_component_instance(...)\n        ...  # other initialization code\n\n        # first call\n        my_aea_1 = builder.build()\n\n        # second call to `build()` would raise a Value Error.\n        # call reset\n        builder.reset()\n\n        # re-add the component and private keys\n        builder.add_component_instance(...)\n        ... # add private keys\n\n        # second call\n        my_aea_2 = builder.builder()\n\n    \"\"\"\n\n    DEFAULT_LEDGER = DEFAULT_LEDGER\n    DEFAULT_CURRENCY_DENOMINATIONS = DEFAULT_CURRENCY_DENOMINATIONS\n    DEFAULT_AGENT_ACT_PERIOD = 0.05  # seconds\n    DEFAULT_EXECUTION_TIMEOUT = 0\n    DEFAULT_MAX_REACTIONS = 20\n    DEFAULT_SKILL_EXCEPTION_POLICY = ExceptionPolicyEnum.propagate\n    DEFAULT_CONNECTION_EXCEPTION_POLICY = ExceptionPolicyEnum.propagate\n    DEFAULT_LOOP_MODE = \"async\"\n    DEFAULT_RUNTIME_MODE = \"threaded\"\n    DEFAULT_TASKMANAGER_MODE = \"threaded\"\n    DEFAULT_SEARCH_SERVICE_ADDRESS = _DEFAULT_SEARCH_SERVICE_ADDRESS\n    AEA_CLASS = AEA\n    BUILD_TIMEOUT = 120\n    loader = ConfigLoader.from_configuration_type(PackageType.AGENT)\n\n    # pylint: disable=attribute-defined-outside-init\n\n    def __init__(\n        self,\n        with_default_packages: bool = True,\n        registry_dir: str = DEFAULT_REGISTRY_NAME,\n        build_dir_root: Optional[str] = None,\n    ) -> None:\n        \"\"\"\n        Initialize the builder.\n\n        :param with_default_packages: add the default packages.\n        :param registry_dir: the registry directory.\n        :param build_dir_root: the root of the build directory.\n        \"\"\"\n        WithLogger.__init__(self, logger=_default_logger)\n        self.registry_dir = os.path.join(os.getcwd(), registry_dir)\n        self._with_default_packages = with_default_packages\n        self.build_dir_root = build_dir_root\n        self._reset(is_full_reset=True)\n\n    def reset(self, is_full_reset: bool = False) -> None:\n        \"\"\"\n        Reset the builder.\n\n        A full reset causes a reset of all data on the builder. A partial reset\n        only resets:\n            - name,\n            - private keys, and\n            - component instances\n\n        :param is_full_reset: whether it is a full reset or not.\n        \"\"\"\n        self._reset(is_full_reset)\n\n    def _reset(self, is_full_reset: bool = False) -> None:\n        \"\"\"\n        Reset the builder (private usage).\n\n        :param is_full_reset: whether it is a full reset or not.\n        \"\"\"\n        self._name: Optional[str] = None\n        self._private_key_paths: Dict[str, Optional[str]] = {}\n        self._connection_private_key_paths: Dict[str, Optional[str]] = {}\n        if not is_full_reset:\n            self._remove_components_from_dependency_manager()\n        self._component_instances: Dict[\n            ComponentType, Dict[ComponentConfiguration, Component]\n        ] = {\n            ComponentType.CONNECTION: {},\n            ComponentType.CONTRACT: {},\n            ComponentType.PROTOCOL: {},\n            ComponentType.SKILL: {},\n        }\n        self._custom_component_configurations: Dict[ComponentId, Dict] = {}\n        self._to_reset: bool = False\n        self._build_called: bool = False\n        if not is_full_reset:\n            return\n        self._default_ledger: Optional[str] = None\n        self._required_ledgers: Optional[List[str]] = None\n        self._build_entrypoint: Optional[str] = None\n        self._currency_denominations: Dict[str, str] = {}\n        self._default_connection: Optional[PublicId] = None\n        self._context_namespace: Dict[str, Any] = {}\n        self._period: Optional[float] = None\n        self._execution_timeout: Optional[float] = None\n        self._max_reactions: Optional[int] = None\n        self._decision_maker_handler_class: Optional[Type[DecisionMakerHandler]] = None\n        self._decision_maker_handler_dotted_path: Optional[str] = None\n        self._decision_maker_handler_file_path: Optional[str] = None\n        self._decision_maker_handler_config: Optional[Dict[str, Any]] = None\n        self._error_handler_class: Optional[Type[AbstractErrorHandler]] = None\n        self._error_handler_dotted_path: Optional[str] = None\n        self._error_handler_file_path: Optional[str] = None\n        self._error_handler_config: Optional[Dict[str, Any]] = None\n        self._skill_exception_policy: Optional[ExceptionPolicyEnum] = None\n        self._connection_exception_policy: Optional[ExceptionPolicyEnum] = None\n        self._default_routing: Dict[PublicId, PublicId] = {}\n        self._loop_mode: Optional[str] = None\n        self._runtime_mode: Optional[str] = None\n        self._task_manager_mode: Optional[str] = None\n        self._search_service_address: Optional[str] = None\n        self._storage_uri: Optional[str] = None\n        self._data_dir: Optional[str] = None\n        self._logging_config: Dict = DEFAULT_LOGGING_CONFIG\n\n        self._package_dependency_manager = _DependenciesManager()\n        if self._with_default_packages:\n            self._add_default_packages()\n\n    def _remove_components_from_dependency_manager(self) -> None:\n        \"\"\"Remove components added via 'add_component' from the dependency manager.\"\"\"\n        for (\n            component_type\n        ) in (\n            self._component_instances.keys()\n        ):  # pylint: disable=consider-using-dict-items\n            for component_config in self._component_instances[component_type].keys():\n                self._package_dependency_manager.remove_component(\n                    component_config.component_id\n                )\n\n    def set_period(self, period: Optional[float]) -> \"AEABuilder\":\n        \"\"\"\n        Set agent act period.\n\n        :param period: period in seconds\n\n        :return: self\n        \"\"\"\n        self._period = period\n        return self\n\n    def set_execution_timeout(self, execution_timeout: Optional[float]) -> \"AEABuilder\":\n        \"\"\"\n        Set agent execution timeout in seconds.\n\n        :param execution_timeout: execution_timeout in seconds\n\n        :return: self\n        \"\"\"\n        self._execution_timeout = execution_timeout\n        return self\n\n    def set_max_reactions(self, max_reactions: Optional[int]) -> \"AEABuilder\":\n        \"\"\"\n        Set agent max reaction in one react.\n\n        :param max_reactions: int\n\n        :return: self\n        \"\"\"\n        self._max_reactions = max_reactions\n        return self\n\n    def set_decision_maker_handler_details(\n        self,\n        decision_maker_handler_dotted_path: str,\n        file_path: str,\n        config: Dict[str, Any],\n    ) -> \"AEABuilder\":\n        \"\"\"\n        Set error handler details.\n\n        :param decision_maker_handler_dotted_path: the dotted path to the decision maker handler\n        :param file_path: the file path to the file which contains the decision maker handler\n        :param config: the configuration passed to the decision maker handler on instantiation\n\n        :return: self\n        \"\"\"\n        self._decision_maker_handler_dotted_path = decision_maker_handler_dotted_path\n        self._decision_maker_handler_file_path = file_path\n        self._decision_maker_handler_config = config\n        return self\n\n    def _load_decision_maker_handler_class(\n        self,\n    ) -> Optional[Type[DecisionMakerHandler]]:\n        \"\"\"\n        Load decision maker handler class.\n\n        :return: decision maker handler class\n        \"\"\"\n        _class = self._get_decision_maker_handler_class()\n        if _class is not None and self._decision_maker_handler_dotted_path is not None:\n            raise ValueError(  # pragma: nocover\n                \"DecisionMakerHandler class and dotted path set: can only set one!\"\n            )\n        if _class is not None:\n            return _class  # pragma: nocover\n        if self._decision_maker_handler_dotted_path is None:\n            return None\n        dotted_path, class_name = self._decision_maker_handler_dotted_path.split(\n            DOTTED_PATH_MODULE_ELEMENT_SEPARATOR\n        )\n        try:\n            if self._decision_maker_handler_file_path is None:\n                module = import_module(dotted_path)\n            else:\n                module = load_module(\n                    dotted_path, Path(self._decision_maker_handler_file_path)\n                )\n        except Exception as e:  # pragma: nocover\n            self.logger.error(\n                \"Could not locate decision maker handler for dotted path '{}' and file path '{}'. Error message: {}\".format(\n                    dotted_path, self._decision_maker_handler_file_path, e\n                )\n            )\n            raise  # log and re-raise because we should not build an agent from an invalid configuration\n\n        try:\n            _class = getattr(module, class_name)\n        except Exception as e:  # pragma: nocover\n            self.logger.error(\n                \"Could not locate decision maker handler for dotted path '{}', class name '{}' and file path '{}'. Error message: {}\".format(\n                    dotted_path, class_name, self._decision_maker_handler_file_path, e\n                )\n            )\n            raise  # log and re-raise because we should not build an agent from an invalid configuration\n\n        return _class\n\n    def _load_error_handler_class(\n        self,\n    ) -> Optional[Type[AbstractErrorHandler]]:\n        \"\"\"\n        Load error handler class.\n\n        :return: error handler class\n        \"\"\"\n        _class = self._get_error_handler_class()\n        if _class is not None and self._error_handler_dotted_path is not None:\n            raise ValueError(  # pragma: nocover\n                \"ErrorHandler class and dotted path set: can only set one!\"\n            )\n        if _class is not None:\n            return _class  # pragma: nocover\n        if self._error_handler_dotted_path is None:\n            return None\n        dotted_path, class_name = self._error_handler_dotted_path.split(\n            DOTTED_PATH_MODULE_ELEMENT_SEPARATOR\n        )\n        try:\n            if self._error_handler_file_path is None:\n                module = import_module(dotted_path)\n            else:\n                module = load_module(dotted_path, Path(self._error_handler_file_path))\n        except Exception as e:  # pragma: nocover\n            self.logger.error(\n                \"Could not locate error handler for dotted path '{}' and file path '{}'. Error message: {}\".format(\n                    dotted_path, self._error_handler_file_path, e\n                )\n            )\n            raise  # log and re-raise because we should not build an agent from an invalid configuration\n\n        try:\n            _class = getattr(module, class_name)\n        except Exception as e:  # pragma: nocover\n            self.logger.error(\n                \"Could not locate error handler for dotted path '{}', class name '{}' and file path '{}'. Error message: {}\".format(\n                    dotted_path, class_name, self._error_handler_file_path, e\n                )\n            )\n            raise  # log and re-raise because we should not build an agent from an invalid configuration\n\n        return _class\n\n    def set_error_handler_details(\n        self, error_handler_dotted_path: str, file_path: str, config: Dict[str, Any]\n    ) -> \"AEABuilder\":\n        \"\"\"\n        Set error handler details.\n\n        :param error_handler_dotted_path: the dotted path to the error handler\n        :param file_path: the file path to the file which contains the error handler\n        :param config: the configuration passed to the error handler on instantiation\n\n        :return: self\n        \"\"\"\n        self._error_handler_dotted_path = error_handler_dotted_path\n        self._error_handler_file_path = file_path\n        self._error_handler_config = config\n        return self\n\n    def set_skill_exception_policy(\n        self, skill_exception_policy: Optional[ExceptionPolicyEnum]\n    ) -> \"AEABuilder\":  # pragma: nocover\n        \"\"\"\n        Set skill exception policy.\n\n        :param skill_exception_policy: the policy\n\n        :return: self\n        \"\"\"\n        self._skill_exception_policy = skill_exception_policy\n        return self\n\n    def set_connection_exception_policy(\n        self, connection_exception_policy: Optional[ExceptionPolicyEnum]\n    ) -> \"AEABuilder\":  # pragma: nocover\n        \"\"\"\n        Set connection exception policy.\n\n        :param connection_exception_policy: the policy\n\n        :return: self\n        \"\"\"\n        self._connection_exception_policy = connection_exception_policy\n        return self\n\n    def set_default_routing(\n        self, default_routing: Dict[PublicId, PublicId]\n    ) -> \"AEABuilder\":\n        \"\"\"\n        Set default routing.\n\n        This is a map from public ids (protocols) to public ids (connections).\n\n        :param default_routing: the default routing mapping\n\n        :return: self\n        \"\"\"\n        for protocol_id, connection_id in default_routing.items():\n            if (\n                ComponentId(\"protocol\", protocol_id)\n                not in self._package_dependency_manager.protocols\n            ):\n                raise ValueError(\n                    f\"Protocol {protocol_id} specified in `default_routing` is not a project dependency!\"\n                )\n            if (\n                ComponentId(\"connection\", connection_id)\n                not in self._package_dependency_manager.connections\n            ):\n                raise ValueError(\n                    f\"Connection {connection_id} specified in `default_routing` is not a project dependency!\"\n                )\n\n        self._default_routing = default_routing  # pragma: nocover\n        return self\n\n    def set_loop_mode(\n        self, loop_mode: Optional[str]\n    ) -> \"AEABuilder\":  # pragma: nocover\n        \"\"\"\n        Set the loop mode.\n\n        :param loop_mode: the agent loop mode\n        :return: self\n        \"\"\"\n        self._loop_mode = loop_mode\n        return self\n\n    def set_runtime_mode(\n        self, runtime_mode: Optional[str]\n    ) -> \"AEABuilder\":  # pragma: nocover\n        \"\"\"\n        Set the runtime mode.\n\n        :param runtime_mode: the agent runtime mode\n        :return: self\n        \"\"\"\n        self._runtime_mode = runtime_mode\n        return self\n\n    def set_task_manager_mode(\n        self, task_manager_mode: Optional[str]\n    ) -> \"AEABuilder\":  # pragma: nocover\n        \"\"\"\n        Set the task_manager_mode.\n\n        :param task_manager_mode: the agent task_manager_mode\n        :return: self\n        \"\"\"\n        self._task_manager_mode = task_manager_mode\n        return self\n\n    def set_storage_uri(\n        self, storage_uri: Optional[str]\n    ) -> \"AEABuilder\":  # pragma: nocover\n        \"\"\"\n        Set the storage uri.\n\n        :param storage_uri: storage uri\n        :return: self\n        \"\"\"\n        self._storage_uri = storage_uri\n        return self\n\n    def set_data_dir(self, data_dir: Optional[str]) -> \"AEABuilder\":  # pragma: nocover\n        \"\"\"\n        Set the data directory.\n\n        :param data_dir: path to directory where to store data.\n        :return: self\n        \"\"\"\n        self._data_dir = data_dir\n        return self\n\n    def set_logging_config(\n        self, logging_config: Dict\n    ) -> \"AEABuilder\":  # pragma: nocover\n        \"\"\"\n        Set the logging configurations.\n\n        The dictionary must satisfy the following schema:\n\n          https://docs.python.org/3/library/logging.config.html#logging-config-dictschema\n\n        :param logging_config: the logging configurations.\n        :return: self\n        \"\"\"\n        self._logging_config = logging_config\n        return self\n\n    def set_search_service_address(\n        self, search_service_address: str\n    ) -> \"AEABuilder\":  # pragma: nocover\n        \"\"\"\n        Set the search service address.\n\n        :param search_service_address: the search service address\n        :return: self\n        \"\"\"\n        self._search_service_address = search_service_address\n        return self\n\n    def _add_default_packages(self) -> None:\n        \"\"\"Add default packages.\"\"\"\n        # add default protocol\n        default_protocol = PublicId.from_str(DEFAULT_PROTOCOL)\n        self.add_protocol(\n            Path(\n                self.registry_dir, _FETCHAI_IDENTIFIER, PROTOCOLS, default_protocol.name\n            )\n        )\n        # add signing protocol\n        signing_protocol = PublicId.from_str(SIGNING_PROTOCOL)\n        self.add_protocol(\n            Path(\n                self.registry_dir, _FETCHAI_IDENTIFIER, PROTOCOLS, signing_protocol.name\n            )\n        )\n        # add state update protocol\n        state_update_protocol = PublicId.from_str(STATE_UPDATE_PROTOCOL)\n        self.add_protocol(\n            Path(\n                self.registry_dir,\n                _FETCHAI_IDENTIFIER,\n                PROTOCOLS,\n                state_update_protocol.name,\n            )\n        )\n\n    def _check_can_remove(self, component_id: ComponentId) -> None:\n        \"\"\"\n        Check if a component can be removed.\n\n        :param component_id: the component id.\n        :raises ValueError: if the component is already present.\n        \"\"\"\n        if component_id not in self._package_dependency_manager.all_dependencies:\n            raise ValueError(\n                \"Component {} of type {} not present.\".format(\n                    component_id.public_id, component_id.component_type\n                )\n            )\n\n    def _check_can_add(self, configuration: ComponentConfiguration) -> None:\n        \"\"\"\n        Check if the component can be added, given its configuration.\n\n        :param configuration: the configuration of the component.\n        \"\"\"\n        self._check_configuration_not_already_added(configuration)\n        self._check_package_dependencies(configuration)\n        self._check_pypi_dependencies(configuration)\n\n    def set_name(self, name: str) -> \"AEABuilder\":  # pragma: nocover\n        \"\"\"\n        Set the name of the agent.\n\n        :param name: the name of the agent.\n        :return: the AEABuilder\n        \"\"\"\n        self._name = name\n        return self\n\n    def set_default_connection(\n        self, public_id: Optional[PublicId] = None\n    ) -> \"AEABuilder\":  # pragma: nocover\n        \"\"\"\n        Set the default connection.\n\n        :param public_id: the public id of the default connection package.\n        :return: the AEABuilder\n        \"\"\"\n        if (\n            public_id\n            and ComponentId(\"connection\", public_id)\n            not in self._package_dependency_manager.connections\n        ):\n            raise ValueError(\n                f\"Connection {public_id} specified as `default_connection` is not a project dependency!\"\n            )\n        self._default_connection = public_id\n        return self\n\n    def add_private_key(\n        self,\n        identifier: str,\n        private_key_path: Optional[PathLike] = None,\n        is_connection: bool = False,\n    ) -> \"AEABuilder\":\n        \"\"\"\n        Add a private key path.\n\n        :param identifier: the identifier for that private key path.\n        :param private_key_path: an (optional) path to the private key file.\n            If None, the key will be created at build time.\n        :param is_connection: if the pair is for the connection cryptos\n        :return: the AEABuilder\n        \"\"\"\n        if is_connection:\n            self._connection_private_key_paths[identifier] = (\n                str(private_key_path) if private_key_path is not None else None\n            )\n        else:\n            self._private_key_paths[identifier] = (\n                str(private_key_path) if private_key_path is not None else None\n            )\n        if private_key_path is not None:\n            self._to_reset = True\n        return self\n\n    def remove_private_key(\n        self, identifier: str, is_connection: bool = False\n    ) -> \"AEABuilder\":\n        \"\"\"\n        Remove a private key path by identifier, if present.\n\n        :param identifier: the identifier of the private key.\n        :param is_connection: if the pair is for the connection cryptos\n        :return: the AEABuilder\n        \"\"\"\n        if is_connection:\n            self._connection_private_key_paths.pop(identifier, None)\n        else:\n            self._private_key_paths.pop(identifier, None)\n        return self\n\n    @property\n    def private_key_paths(self) -> Dict[str, Optional[str]]:\n        \"\"\"Get the private key paths.\"\"\"\n        return self._private_key_paths\n\n    @property\n    def connection_private_key_paths(self) -> Dict[str, Optional[str]]:\n        \"\"\"Get the connection private key paths.\"\"\"\n        return self._connection_private_key_paths\n\n    def set_default_ledger(\n        self, identifier: Optional[str]\n    ) -> \"AEABuilder\":  # pragma: nocover\n        \"\"\"\n        Set a default ledger API to use.\n\n        :param identifier: the identifier of the ledger api\n        :return: the AEABuilder\n        \"\"\"\n        self._default_ledger = (\n            str(SimpleId(identifier)) if identifier is not None else None\n        )\n        return self\n\n    def set_required_ledgers(\n        self, required_ledgers: Optional[List[str]]\n    ) -> \"AEABuilder\":  # pragma: nocover\n        \"\"\"\n        Set the required ledger identifiers.\n\n        These are the ledgers for which the AEA requires a key pair.\n\n        :param required_ledgers: the required ledgers.\n        :return: the AEABuilder.\n        \"\"\"\n        self._required_ledgers = (\n            [str(SimpleId(ledger)) for ledger in required_ledgers]\n            if required_ledgers is not None\n            else None\n        )\n        return self\n\n    def set_build_entrypoint(\n        self, build_entrypoint: Optional[str]\n    ) -> \"AEABuilder\":  # pragma: nocover\n        \"\"\"\n        Set build entrypoint.\n\n        :param build_entrypoint: path to the builder script.\n        :return: the AEABuilder\n        \"\"\"\n        self._build_entrypoint = build_entrypoint\n        return self\n\n    def set_currency_denominations(\n        self, currency_denominations: Dict[str, str]\n    ) -> \"AEABuilder\":  # pragma: nocover\n        \"\"\"\n        Set the mapping from ledger ids to currency denominations.\n\n        :param currency_denominations: the mapping\n        :return: the AEABuilder\n        \"\"\"\n        self._currency_denominations = currency_denominations\n        return self\n\n    def add_component(\n        self,\n        component_type: ComponentType,\n        directory: PathLike,\n        skip_consistency_check: bool = False,\n    ) -> \"AEABuilder\":\n        \"\"\"\n        Add a component, given its type and the directory.\n\n        :param component_type: the component type.\n        :param directory: the directory path.\n        :param skip_consistency_check: if True, the consistency check are skipped.\n        :raises AEAException: if a component is already registered with the same component id.   # noqa: DAR402\n                            | or if there's a missing dependency.  # noqa: DAR402\n        :return: the AEABuilder\n        \"\"\"\n        directory = Path(directory)\n        configuration = load_component_configuration(\n            component_type, directory, skip_consistency_check\n        )\n        self._set_component_build_directory(configuration)\n        self._check_can_add(configuration)\n        # update dependency graph\n        self._package_dependency_manager.add_component(configuration)\n        configuration.directory = directory\n\n        return self\n\n    def _set_component_build_directory(\n        self, configuration: ComponentConfiguration\n    ) -> None:\n        \"\"\"\n        Set component build directory, create if not presents.\n\n        :param configuration: component configuration\n        \"\"\"\n        configuration.build_directory = os.path.join(\n            self.get_build_root_directory(),\n            configuration.component_type.value,\n            configuration.author,\n            configuration.name,\n        )\n\n    def add_component_instance(self, component: Component) -> \"AEABuilder\":\n        \"\"\"\n        Add already initialized component object to resources or connections.\n\n        Please, pay attention, all dependencies have to be already loaded.\n\n        Notice also that this will make the call to 'build()' non re-entrant.\n        You will have to `reset()` the builder before calling `build()` again.\n\n        :param component: Component instance already initialized.\n        :return: self\n        \"\"\"\n        self._to_reset = True\n        self._check_can_add(component.configuration)\n        # update dependency graph\n        self._package_dependency_manager.add_component(component.configuration)\n        self._component_instances[component.component_type][\n            component.configuration\n        ] = component\n        return self\n\n    def set_context_namespace(\n        self, context_namespace: Dict[str, Any]\n    ) -> \"AEABuilder\":  # pragma: nocover\n        \"\"\"Set the context namespace.\"\"\"\n        self._context_namespace = context_namespace\n        return self\n\n    def set_agent_pypi_dependencies(self, dependencies: Dependencies) -> \"AEABuilder\":\n        \"\"\"\n        Set agent PyPI dependencies.\n\n        :param dependencies: PyPI dependencies for the agent.\n        :return: the AEABuilder.\n        \"\"\"\n        self._package_dependency_manager.agent_pypi_dependencies = dependencies\n        return self\n\n    def remove_component(self, component_id: ComponentId) -> \"AEABuilder\":\n        \"\"\"\n        Remove a component.\n\n        :param component_id: the public id of the component.\n        :return: the AEABuilder\n        \"\"\"\n        self._check_can_remove(component_id)\n        self._remove(component_id)\n        return self\n\n    def _remove(self, component_id: ComponentId) -> None:\n        self._package_dependency_manager.remove_component(component_id)\n\n    def add_protocol(self, directory: PathLike) -> \"AEABuilder\":\n        \"\"\"\n        Add a protocol to the agent.\n\n        :param directory: the path to the protocol directory\n        :return: the AEABuilder\n        \"\"\"\n        self.add_component(ComponentType.PROTOCOL, directory)\n        return self\n\n    def remove_protocol(self, public_id: PublicId) -> \"AEABuilder\":\n        \"\"\"\n        Remove protocol.\n\n        :param public_id: the public id of the protocol\n        :return: the AEABuilder\n        \"\"\"\n        self.remove_component(ComponentId(ComponentType.PROTOCOL, public_id))\n        return self\n\n    def add_connection(self, directory: PathLike) -> \"AEABuilder\":\n        \"\"\"\n        Add a connection to the agent.\n\n        :param directory: the path to the connection directory\n        :return: the AEABuilder\n        \"\"\"\n        self.add_component(ComponentType.CONNECTION, directory)\n        return self\n\n    def remove_connection(self, public_id: PublicId) -> \"AEABuilder\":\n        \"\"\"\n        Remove a connection.\n\n        :param public_id: the public id of the connection\n        :return: the AEABuilder\n        \"\"\"\n        self.remove_component(ComponentId(ComponentType.CONNECTION, public_id))\n        return self\n\n    def add_skill(self, directory: PathLike) -> \"AEABuilder\":\n        \"\"\"\n        Add a skill to the agent.\n\n        :param directory: the path to the skill directory\n        :return: the AEABuilder\n        \"\"\"\n        self.add_component(ComponentType.SKILL, directory)\n        return self\n\n    def remove_skill(self, public_id: PublicId) -> \"AEABuilder\":\n        \"\"\"\n        Remove protocol.\n\n        :param public_id: the public id of the skill\n        :return: the AEABuilder\n        \"\"\"\n        self.remove_component(ComponentId(ComponentType.SKILL, public_id))\n        return self\n\n    def add_contract(self, directory: PathLike) -> \"AEABuilder\":\n        \"\"\"\n        Add a contract to the agent.\n\n        :param directory: the path to the contract directory\n        :return: the AEABuilder\n        \"\"\"\n        self.add_component(ComponentType.CONTRACT, directory)\n        return self\n\n    def remove_contract(self, public_id: PublicId) -> \"AEABuilder\":\n        \"\"\"\n        Remove protocol.\n\n        :param public_id: the public id of the contract\n        :return: the AEABuilder\n        \"\"\"\n        self.remove_component(ComponentId(ComponentType.CONTRACT, public_id))\n        return self\n\n    def call_all_build_entrypoints(self) -> None:\n        \"\"\"Call all the build entrypoints.\"\"\"\n        for config in self._package_dependency_manager._dependencies.values():  # type: ignore # pylint: disable=protected-access\n            self.run_build_for_component_configuration(config, logger=self.logger)\n\n        target_directory = self.get_build_root_directory()\n\n        if self._build_entrypoint:\n            self.logger.info(\"Building AEA package...\")\n            source_directory = \".\"\n            build_entrypoint = cast(str, self._build_entrypoint)\n            self._run_build_entrypoint(\n                build_entrypoint, source_directory, target_directory, logger=self.logger\n            )\n\n    def get_build_root_directory(self) -> str:\n        \"\"\"Get build directory root.\"\"\"\n        return os.path.join(self.build_dir_root or \".\", self.AEA_CLASS.get_build_dir())\n\n    @classmethod\n    def run_build_for_component_configuration(\n        cls,\n        config: ComponentConfiguration,\n        logger: Optional[logging.Logger] = None,\n    ) -> None:\n        \"\"\"Run a build entrypoint script for component configuration.\"\"\"\n        if not config.build_entrypoint:\n            return\n\n        enforce(bool(config.build_directory), f\"{config}.build_directory is not set!\")\n\n        if not config.build_directory:  # pragma: nocover\n            return\n\n        if logger:\n            logger.info(f\"Building package {config.component_id}...\")\n\n        source_directory = cast(str, config.directory)\n        target_directory = os.path.abspath(config.build_directory)\n        build_entrypoint = cast(str, config.build_entrypoint)\n        cls._run_build_entrypoint(\n            build_entrypoint, source_directory, target_directory, logger=logger\n        )\n\n    @classmethod\n    def _run_build_entrypoint(\n        cls,\n        build_entrypoint: str,\n        source_directory: str,\n        target_directory: str,\n        logger: Optional[logging.Logger] = None,\n    ) -> None:\n        \"\"\"\n        Run a build entrypoint script.\n\n        :param build_entrypoint: the path to the build script relative to directory.\n        :param source_directory: the source directory.\n        :param target_directory: the target directory.\n        :param logger: logger\n        \"\"\"\n        cls._check_valid_entrypoint(build_entrypoint, source_directory)\n\n        command = [sys.executable, build_entrypoint, target_directory]\n        command_str = \" \".join(command)\n        if logger:\n            logger.info(f\"Running command '{command_str}'...\")\n        stdout, stderr, code = cls._run_in_subprocess(command, source_directory)\n        if code == 0:\n            if logger:\n                logger.info(f\"Command '{command_str}' succeded with output:\\n{stdout}\")\n        else:\n            raise AEAException(\n                f\"An error occurred while running command '{command_str}':\\n{stderr}\"\n            )\n\n    @classmethod\n    def _run_in_subprocess(\n        cls, command: List[str], source_directory: str\n    ) -> Tuple[str, str, int]:\n        \"\"\"\n        Run in subprocess.\n\n        :param command: command to run\n        :param source_directory: source directory\n        :return: stdout, stderr, code\n        \"\"\"\n        res = subprocess.run(  # nosec\n            command,\n            cwd=source_directory,\n            check=False,\n            timeout=cls.BUILD_TIMEOUT,\n            stdout=subprocess.PIPE,\n            stderr=subprocess.PIPE,\n        )\n        code = res.returncode\n        stdout = res.stdout.decode(\"utf-8\")\n        stderr = res.stderr.decode(\"utf-8\")\n        return stdout, stderr, code\n\n    def _build_wallet(\n        self, data_directory: str, password: Optional[str] = None\n    ) -> Wallet:\n        \"\"\"\n        Build the wallet.\n\n        We need to prepend the path to the data directory\n        to each private key path, but only if\n        the path is not an absolute path.\n\n        :param data_directory: the path prefix to be prepended to each private key path.\n        :param password: the password to encrypt/decrypt the private key.\n        :return: the wallet instance.\n        \"\"\"\n\n        def _prepend_if_not_none(\n            obj: Dict[str, Optional[str]]\n        ) -> Dict[str, Optional[str]]:\n            return {\n                key: os.path.join(data_directory, value)\n                if value is not None and not os.path.isabs(value)\n                else value\n                for key, value in obj.items()\n            }\n\n        private_key_paths = _prepend_if_not_none(self.private_key_paths)\n        connection_private_key_paths = _prepend_if_not_none(\n            self.connection_private_key_paths\n        )\n        wallet = Wallet(\n            private_key_paths, connection_private_key_paths, password=password\n        )\n        return wallet\n\n    def _build_identity_from_wallet(self, wallet: Wallet) -> Identity:\n        \"\"\"\n        Get the identity associated to a wallet.\n\n        :param wallet: the wallet\n        :return: the identity\n        \"\"\"\n        if self._name is None:  # pragma: nocover\n            raise ValueError(\"You must set the name of the agent.\")\n\n        default_ledger = self.get_default_ledger()\n        if not wallet.addresses:\n            raise AEAWalletNoAddressException(\"Wallet has no addresses.\")\n\n        if default_ledger not in wallet.addresses:\n            raise ValueError(  # pragma: nocover\n                f\"Specified default ledger '{default_ledger}' not found in available addresses of types: {'[' + ','.join(wallet.addresses.keys()) + ']'}\"\n            )\n\n        if len(wallet.addresses) > 1:\n            identity = Identity(\n                self._name,\n                addresses=wallet.addresses,\n                public_keys=wallet.public_keys,\n                default_address_key=default_ledger,\n            )\n        else:\n            identity = Identity(\n                self._name,\n                address=wallet.addresses[default_ledger],\n                public_key=wallet.public_keys[default_ledger],\n                default_address_key=default_ledger,\n            )\n        return identity\n\n    def _process_connection_ids(  # pylint: disable=unsubscriptable-object\n        self,\n        connection_ids: Optional[Collection[PublicId]] = None,\n    ) -> List[PublicId]:\n        \"\"\"\n        Process connection ids.\n\n        :param connection_ids: an optional list of connection ids\n        :return: a list of connections\n        \"\"\"\n        if connection_ids is not None:\n            # check that all the connections are in the configuration file.\n            connection_ids_set = set(connection_ids)\n            all_supported_connection_ids = {\n                cid.public_id\n                for cid in self._package_dependency_manager.connections.keys()\n            }\n            non_supported_connections = connection_ids_set.difference(\n                all_supported_connection_ids\n            )\n            if len(non_supported_connections) > 0:\n                raise ValueError(\n                    \"Connection ids {} not declared in the configuration file.\".format(\n                        sorted(map(str, non_supported_connections))\n                    )\n                )\n            selected_connections_ids = [\n                component_id.public_id\n                for component_id in self._package_dependency_manager.connections.keys()\n                if component_id.public_id in connection_ids_set\n            ]\n        else:\n            selected_connections_ids = [\n                component_id.public_id\n                for component_id in self._package_dependency_manager.connections.keys()\n            ]\n\n        if len(selected_connections_ids) == 0:\n            return selected_connections_ids\n        # sort default id to be first\n        default_connection = self._get_default_connection()\n        if default_connection is None:\n            return []\n        full_default_connection_id = [\n            connection_id\n            for connection_id in selected_connections_ids\n            if connection_id.same_prefix(default_connection)\n        ]\n        if len(full_default_connection_id) == 1:\n            selected_connections_ids.remove(full_default_connection_id[0])\n            sorted_selected_connections_ids = (\n                full_default_connection_id + selected_connections_ids\n            )\n        else:\n            raise ValueError(\n                \"Default connection not a dependency. Please add it and retry.\"\n            )\n\n        return sorted_selected_connections_ids\n\n    def install_pypi_dependencies(self) -> None:\n        \"\"\"Install components extra dependencies.\"\"\"\n        self._package_dependency_manager.install_dependencies()\n\n    def build(  # pylint: disable=unsubscriptable-object\n        self,\n        connection_ids: Optional[Collection[PublicId]] = None,\n        password: Optional[str] = None,\n    ) -> AEA:\n        \"\"\"\n        Build the AEA.\n\n        This method is re-entrant only if the components have been\n        added through the method 'add_component'. If some of them\n        have been loaded with 'add_component_instance', it\n        can be called only once, and further calls are only possible\n        after a call to 'reset' and re-loading of the components added\n        via 'add_component_instance' and the private keys.\n\n        :param connection_ids: select only these connections to run the AEA.\n        :param password: the password to encrypt/decrypt the private key.\n        :return: the AEA object.\n        \"\"\"\n        datadir = self._get_data_dir()\n        self._check_we_can_build()\n        self._preliminary_checks_before_build()\n        logging.config.dictConfig(self._logging_config)\n        wallet = self._build_wallet(datadir, password=password)\n        identity = self._build_identity_from_wallet(wallet)\n        resources = Resources(identity.name)\n        self._load_and_add_components(ComponentType.PROTOCOL, resources, identity.name)\n        self._load_and_add_components(ComponentType.CONTRACT, resources, identity.name)\n        self._load_and_add_components(\n            ComponentType.CONNECTION,\n            resources,\n            identity.name,\n            identity=identity,\n            crypto_store=wallet.connection_cryptos,\n            data_dir=datadir,\n        )\n        connection_ids = self._process_connection_ids(connection_ids)\n        aea = self.AEA_CLASS(\n            identity,\n            wallet,\n            resources,\n            datadir,\n            loop=None,\n            period=self._get_agent_act_period(),\n            execution_timeout=self._get_execution_timeout(),\n            max_reactions=self._get_max_reactions(),\n            error_handler_class=self._load_error_handler_class(),\n            error_handler_config=self._get_error_handler_config(),\n            decision_maker_handler_class=self._load_decision_maker_handler_class(),\n            decision_maker_handler_config=self._get_decision_maker_handler_config(),\n            skill_exception_policy=self._get_skill_exception_policy(),\n            connection_exception_policy=self._get_connection_exception_policy(),\n            currency_denominations=self._get_currency_denominations(),\n            default_routing=self._get_default_routing(),\n            default_connection=self._get_default_connection(),\n            loop_mode=self._get_loop_mode(),\n            runtime_mode=self._get_runtime_mode(),\n            task_manager_mode=self._get_task_manager_mode(),\n            connection_ids=connection_ids,\n            search_service_address=self._get_search_service_address(),\n            storage_uri=self._get_storage_uri(),\n            **deepcopy(self._context_namespace),\n        )\n        self._load_and_add_components(\n            ComponentType.SKILL, resources, identity.name, agent_context=aea.context\n        )\n        self._build_called = True\n        return aea\n\n    def get_default_ledger(self) -> str:\n        \"\"\"\n        Return default ledger.\n\n        :return: the default ledger identifier.\n        \"\"\"\n        return self._default_ledger or self.DEFAULT_LEDGER\n\n    def get_required_ledgers(self) -> List[str]:\n        \"\"\"\n        Get the required ledger identifiers.\n\n        These are the ledgers for which the AEA requires a key pair.\n\n        :return: the list of required ledgers.\n        \"\"\"\n        return self._required_ledgers or [self.DEFAULT_LEDGER]\n\n    def _get_agent_act_period(self) -> float:\n        \"\"\"\n        Return agent act period.\n\n        :return: period in seconds if set else default value.\n        \"\"\"\n        return self._period or self.DEFAULT_AGENT_ACT_PERIOD\n\n    def _get_execution_timeout(self) -> float:\n        \"\"\"\n        Return execution timeout.\n\n        :return: timeout in seconds if set else default value.\n        \"\"\"\n        return (\n            self._execution_timeout\n            if self._execution_timeout is not None\n            else self.DEFAULT_EXECUTION_TIMEOUT\n        )\n\n    def _get_max_reactions(self) -> int:\n        \"\"\"\n        Return agent max_reaction.\n\n        :return: max-reactions if set else default value.\n        \"\"\"\n        return (\n            self._max_reactions\n            if self._max_reactions is not None\n            else self.DEFAULT_MAX_REACTIONS\n        )\n\n    def _get_error_handler_class(\n        self,\n    ) -> Optional[Type]:\n        \"\"\"\n        Return the error handler class.\n\n        :return: error handler class\n        \"\"\"\n        return self._error_handler_class\n\n    def _get_error_handler_config(\n        self,\n    ) -> Optional[Dict[str, Any]]:\n        \"\"\"\n        Return the error handler config.\n\n        :return: error handler config\n        \"\"\"\n        return self._error_handler_config\n\n    def _get_decision_maker_handler_class(\n        self,\n    ) -> Optional[Type[DecisionMakerHandler]]:\n        \"\"\"\n        Return the decision maker handler class.\n\n        :return: decision maker handler class\n        \"\"\"\n        return self._decision_maker_handler_class\n\n    def _get_decision_maker_handler_config(\n        self,\n    ) -> Optional[Dict[str, Any]]:\n        \"\"\"\n        Return the decision maker handler config.\n\n        :return: decision maker handler config\n        \"\"\"\n        return self._decision_maker_handler_config\n\n    def _get_skill_exception_policy(self) -> ExceptionPolicyEnum:\n        \"\"\"\n        Return the skill exception policy.\n\n        :return: the skill exception policy.\n        \"\"\"\n        return (\n            self._skill_exception_policy\n            if self._skill_exception_policy is not None\n            else self.DEFAULT_SKILL_EXCEPTION_POLICY\n        )\n\n    def _get_connection_exception_policy(self) -> ExceptionPolicyEnum:\n        \"\"\"\n        Return the skill exception policy.\n\n        :return: the skill exception policy.\n        \"\"\"\n        return (\n            self._connection_exception_policy\n            if self._connection_exception_policy is not None\n            else self.DEFAULT_CONNECTION_EXCEPTION_POLICY\n        )\n\n    def _get_currency_denominations(self) -> Dict[str, str]:\n        \"\"\"\n        Return the mapping from ledger id to currency denominations.\n\n        :return: the mapping\n        \"\"\"\n        return (\n            self._currency_denominations\n            if self._currency_denominations != {}\n            else self.DEFAULT_CURRENCY_DENOMINATIONS\n        )\n\n    def _get_default_routing(self) -> Dict[PublicId, PublicId]:\n        \"\"\"\n        Return the default routing.\n\n        :return: the default routing\n        \"\"\"\n        return self._default_routing\n\n    def _get_default_connection(self) -> Optional[PublicId]:\n        \"\"\"\n        Return the default connection.\n\n        :return: the default connection\n        \"\"\"\n        return self._default_connection\n\n    def _get_loop_mode(self) -> str:\n        \"\"\"\n        Return the loop mode name.\n\n        :return: the loop mode name\n        \"\"\"\n        return (\n            self._loop_mode if self._loop_mode is not None else self.DEFAULT_LOOP_MODE\n        )\n\n    def _get_runtime_mode(self) -> str:\n        \"\"\"\n        Return the runtime mode name.\n\n        :return: the runtime mode name\n        \"\"\"\n        return (\n            self._runtime_mode\n            if self._runtime_mode is not None\n            else self.DEFAULT_RUNTIME_MODE\n        )\n\n    def _get_task_manager_mode(self) -> str:\n        \"\"\"\n        Return the askmanager mode name.\n\n        :return: the taskmanager mode name\n        \"\"\"\n        return (\n            self._task_manager_mode\n            if self._task_manager_mode is not None\n            else self.DEFAULT_TASKMANAGER_MODE\n        )\n\n    def _get_storage_uri(self) -> Optional[str]:\n        \"\"\"\n        Return the storage uri.\n\n        :return: the storage uri\n        \"\"\"\n        return self._storage_uri\n\n    def _get_data_dir(self) -> str:\n        \"\"\"\n        Return the data directory.\n\n        :return: the data directory.\n        \"\"\"\n        return self._data_dir if self._data_dir is not None else os.getcwd()\n\n    def _get_search_service_address(self) -> str:\n        \"\"\"\n        Return the search service address.\n\n        :return: the search service address.\n        \"\"\"\n        return (\n            self._search_service_address\n            if self._search_service_address is not None\n            else self.DEFAULT_SEARCH_SERVICE_ADDRESS\n        )\n\n    def _check_configuration_not_already_added(\n        self, configuration: ComponentConfiguration\n    ) -> None:\n        \"\"\"\n        Check the component configuration has not already been added.\n\n        :param configuration: the component configuration being added\n        :raises AEAException: if the component is already present.\n        \"\"\"\n        if (\n            configuration.component_id\n            in self._package_dependency_manager.all_dependencies\n        ):\n            raise AEAException(\n                \"Component '{}' of type '{}' already added.\".format(\n                    configuration.public_id, configuration.component_type\n                )\n            )\n\n    def _check_package_dependencies(\n        self, configuration: ComponentConfiguration\n    ) -> None:\n        \"\"\"\n        Check that we have all the dependencies needed to the package.\n\n        :param configuration: the component configuration\n        :raises AEAException: if there's a missing dependency.\n        \"\"\"\n        not_supported_packages = configuration.package_dependencies.difference(\n            self._package_dependency_manager.all_dependencies\n        )  # type: Set[ComponentId]\n        has_all_dependencies = len(not_supported_packages) == 0\n        if not has_all_dependencies:\n            raise AEAException(\n                \"Package '{}' of type '{}' cannot be added. Missing dependencies: {}\".format(\n                    configuration.public_id,\n                    configuration.component_type.value,\n                    pprint.pformat(sorted(map(str, not_supported_packages))),\n                )\n            )\n\n    def _check_pypi_dependencies(self, configuration: ComponentConfiguration) -> None:\n        \"\"\"\n        Check that PyPI dependencies of a package don't conflict with the existing ones.\n\n        :param configuration: the component configuration.\n        :raises AEAException: if some PyPI dependency is conflicting.\n        \"\"\"\n        all_pypi_dependencies = self._package_dependency_manager.pypi_dependencies\n        all_pypi_dependencies = merge_dependencies(\n            all_pypi_dependencies, configuration.pypi_dependencies\n        )\n        for pkg_name, dep_info in all_pypi_dependencies.items():\n            set_specifier = SpecifierSet(dep_info.version)\n            if not is_satisfiable(set_specifier):\n                raise AEAException(\n                    f\"Conflict on package {pkg_name}: specifier set '{dep_info.version}' not satisfiable.\"\n                )\n\n    @classmethod\n    def try_to_load_agent_configuration_file(\n        cls, aea_project_path: Union[str, Path]\n    ) -> AgentConfig:\n        \"\"\"Try to load the agent configuration file..\"\"\"\n        try:\n            aea_project_path = Path(aea_project_path)\n            configuration_file_path = cls.get_configuration_file_path(aea_project_path)\n            with open_file(configuration_file_path, mode=\"r\", encoding=\"utf-8\") as fp:\n                loader = ConfigLoader.from_configuration_type(PackageType.AGENT)\n                agent_configuration = loader.load(fp)\n                return agent_configuration\n        except FileNotFoundError:  # pragma: nocover\n            raise ValueError(\n                \"Agent configuration file '{}' not found in the current directory.\".format(\n                    DEFAULT_AEA_CONFIG_FILE\n                )\n            )\n        except (\n            AEAValidationError,\n            jsonschema.exceptions.ValidationError,\n            ExtraPropertiesError,\n        ) as e:  # pragma: nocover\n            raise AEAValidationError(\n                \"Agent configuration file '{}' is invalid: `{}`. Please check the documentation.\".format(\n                    DEFAULT_AEA_CONFIG_FILE, str(e)\n                )\n            )\n\n    @staticmethod\n    def _check_valid_entrypoint(build_entrypoint: str, directory: str) -> None:\n        \"\"\"\n        Check a configuration has a valid entrypoint.\n\n        :param build_entrypoint: the build entrypoint.\n        :param directory: the directory from where to start reading the script.\n        \"\"\"\n        enforce(\n            build_entrypoint is not None,\n            \"Package has not a build entrypoint specified.\",\n        )\n        build_entrypoint = cast(str, build_entrypoint)\n        script_path = Path(directory) / build_entrypoint\n        enforce(\n            script_path.exists(),\n            f\"File '{build_entrypoint}' does not exists.\",\n        )\n        enforce(\n            script_path.is_file(),\n            f\"'{build_entrypoint}' is not a file.\",\n        )\n        try:\n            ast.parse(script_path.read_text())\n        except SyntaxError as e:\n            message = f\"{str(e)}: {e.text}\"\n            raise AEAException(\n                f\"The Python script at '{build_entrypoint}' has a syntax error: {message}\"\n            ) from e\n\n    def set_from_configuration(\n        self,\n        agent_configuration: AgentConfig,\n        aea_project_path: Path,\n        skip_consistency_check: bool = False,\n    ) -> None:\n        \"\"\"\n        Set builder variables from AgentConfig.\n\n        :param agent_configuration: AgentConfig to get values from.\n        :param aea_project_path: PathLike root directory of the agent project.\n        :param skip_consistency_check: if True, the consistency check are skipped.\n        \"\"\"\n        # set name and other configurations\n        self.set_name(agent_configuration.name)\n        self.set_default_ledger(agent_configuration.default_ledger)\n        self.set_required_ledgers(agent_configuration.required_ledgers)\n        self.set_build_entrypoint(agent_configuration.build_entrypoint)\n        self.set_currency_denominations(agent_configuration.currency_denominations)\n\n        self.set_period(agent_configuration.period)\n        self.set_execution_timeout(agent_configuration.execution_timeout)\n        self.set_max_reactions(agent_configuration.max_reactions)\n\n        if agent_configuration.decision_maker_handler != {}:\n            dotted_path = agent_configuration.decision_maker_handler[\"dotted_path\"]\n            file_path = agent_configuration.decision_maker_handler[\"file_path\"]\n            config = agent_configuration.decision_maker_handler[\"config\"]\n            self.set_decision_maker_handler_details(dotted_path, file_path, config)\n        if agent_configuration.error_handler != {}:\n            dotted_path = agent_configuration.error_handler[\"dotted_path\"]\n            file_path = agent_configuration.error_handler[\"file_path\"]\n            config = agent_configuration.error_handler[\"config\"]\n            self.set_error_handler_details(dotted_path, file_path, config)\n        if agent_configuration.skill_exception_policy is not None:\n            self.set_skill_exception_policy(\n                ExceptionPolicyEnum(agent_configuration.skill_exception_policy)\n            )\n        if agent_configuration.connection_exception_policy is not None:\n            self.set_connection_exception_policy(\n                ExceptionPolicyEnum(agent_configuration.connection_exception_policy)\n            )\n\n        self.set_loop_mode(agent_configuration.loop_mode)\n        self.set_runtime_mode(agent_configuration.runtime_mode)\n        self.set_task_manager_mode(agent_configuration.task_manager_mode)\n        self.set_storage_uri(agent_configuration.storage_uri)\n        self.set_data_dir(agent_configuration.data_dir)\n        self.set_logging_config(agent_configuration.logging_config)\n\n        # load private keys\n        for (\n            ledger_identifier,\n            private_key_path,\n        ) in agent_configuration.private_key_paths_dict.items():\n            self.add_private_key(ledger_identifier, private_key_path)\n\n        # load connection private keys\n        for (\n            ledger_identifier,\n            private_key_path,\n        ) in agent_configuration.connection_private_key_paths_dict.items():\n            self.add_private_key(\n                ledger_identifier, private_key_path, is_connection=True\n            )\n\n        for component_type in [\n            ComponentType.PROTOCOL,\n            ComponentType.CONTRACT,\n            ComponentType.CONNECTION,\n            ComponentType.SKILL,\n        ]:\n            self._add_components_of_type(\n                component_type,\n                agent_configuration,\n                aea_project_path,\n                skip_consistency_check,\n            )\n\n        self._custom_component_configurations = (\n            agent_configuration.component_configurations\n        )\n\n        self.set_default_connection(agent_configuration.default_connection)\n        self.set_default_routing(agent_configuration.default_routing)\n        self.set_agent_pypi_dependencies(agent_configuration.dependencies)\n\n    @staticmethod\n    def _find_import_order(\n        component_ids: List[ComponentId],\n        aea_project_path: Path,\n        skip_consistency_check: bool,\n    ) -> List[ComponentId]:\n        \"\"\"\n        Find import order for skills/connections.\n\n        We need to handle skills and connections separately, since skills/connections can depend on each other.\n\n        That is, we need to:\n        - load the skill/connection configurations to find the import order\n        - detect if there are cycles\n        - import skills/connections from the leaves of the dependency graph, by finding a topological ordering.\n\n        :param component_ids: component ids to check\n        :param aea_project_path: project path to AEA\n        :param skip_consistency_check: consistency check of AEA\n        :return: list of component ids ordered for import\n        \"\"\"\n        # the adjacency list for the inverse dependency graph\n        dependency_to_supported_dependencies: Dict[\n            ComponentId, Set[ComponentId]\n        ] = defaultdict(set)\n        for component_id in component_ids:\n            component_path = find_component_directory_from_component_id(\n                aea_project_path, component_id\n            )\n            configuration = load_component_configuration(\n                component_id.component_type, component_path, skip_consistency_check\n            )\n\n            if component_id not in dependency_to_supported_dependencies:\n                dependency_to_supported_dependencies[component_id] = set()\n            if isinstance(configuration, SkillConfig):\n                dependencies, component_type = configuration.skills, SKILLS\n            elif isinstance(configuration, ConnectionConfig):\n                dependencies, component_type = configuration.connections, CONNECTIONS\n            else:\n                raise AEAException(\"Not a valid configuration type.\")  # pragma: nocover\n            for dependency in dependencies:\n                dependency_to_supported_dependencies[\n                    ComponentId(ComponentType.SKILL, dependency)\n                ].add(component_id)\n\n        try:\n            order = find_topological_order(dependency_to_supported_dependencies)\n        except ValueError:\n            raise AEAException(\n                f\"Cannot load {component_type}, there is a cyclic dependency.\"\n            )\n\n        return order\n\n    @classmethod\n    def from_aea_project(\n        cls,\n        aea_project_path: PathLike,\n        skip_consistency_check: bool = False,\n        password: Optional[str] = None,\n    ) -> \"AEABuilder\":\n        \"\"\"\n        Construct the builder from an AEA project.\n\n        - load agent configuration file\n        - set name and default configurations\n        - load private keys\n        - load ledger API configurations\n        - set default ledger\n        - load every component\n\n        :param aea_project_path: path to the AEA project.\n        :param skip_consistency_check: if True, the consistency check are skipped.\n        :param password: the password to encrypt/decrypt private keys.\n        :return: an AEABuilder.\n        \"\"\"\n        aea_project_path = Path(aea_project_path)\n        cls.try_to_load_agent_configuration_file(aea_project_path)\n        load_env_file(str(aea_project_path / DEFAULT_ENV_DOTFILE))\n\n        # check and create missing, do not replace env variables. updates config\n        AgentConfigManager.verify_private_keys(\n            aea_project_path,\n            substitude_env_vars=False,\n            private_key_helper=private_key_verify,\n            password=password,\n        ).dump_config()\n\n        # just validate\n        agent_configuration = AgentConfigManager.verify_private_keys(\n            aea_project_path,\n            substitude_env_vars=True,\n            private_key_helper=private_key_verify,\n            password=password,\n        ).agent_config\n\n        builder = AEABuilder(with_default_packages=False)\n        builder.set_from_configuration(\n            agent_configuration, aea_project_path, skip_consistency_check\n        )\n        return builder\n\n    @staticmethod\n    def get_configuration_file_path(aea_project_path: Union[Path, str]) -> Path:\n        \"\"\"Return path to aea-config file for the given aea project path.\"\"\"\n        return Path(aea_project_path) / DEFAULT_AEA_CONFIG_FILE\n\n    def _load_and_add_components(\n        self,\n        component_type: ComponentType,\n        resources: Resources,\n        agent_name: str,\n        **kwargs: Any,\n    ) -> None:\n        \"\"\"\n        Load and add components added to the builder to a Resources instance.\n\n        :param component_type: the component type for which\n        :param resources: the resources object to populate.\n        :param agent_name: the AEA name for logging purposes.\n        :param kwargs: keyword argument to forward to the component loader.\n        \"\"\"\n        for configuration in self._package_dependency_manager.get_components_by_type(\n            component_type\n        ).values():\n            if configuration in self._component_instances[component_type].keys():\n                component = self._component_instances[component_type][configuration]\n                if configuration.component_type != ComponentType.SKILL:\n                    component.logger = cast(\n                        logging.Logger, make_component_logger(configuration, agent_name)\n                    )\n            else:\n                new_configuration = self._overwrite_custom_configuration(configuration)\n                if new_configuration.is_abstract_component:\n                    load_aea_package(configuration)\n                    self.logger.debug(\n                        f\"Package {configuration.public_id} of type {configuration.component_type} is abstract, \"\n                        f\"therefore only the Python modules have been loaded.\"\n                    )\n                    continue\n                _logger = make_component_logger(new_configuration, agent_name)\n                component = load_component_from_config(\n                    new_configuration, logger=_logger, **kwargs\n                )\n\n            resources.add_component(component)\n\n    def _check_we_can_build(self) -> None:\n        if self._build_called and self._to_reset:\n            raise ValueError(\n                \"Cannot build the agent; You have done one of the following:\\n\"\n                \"- added a component instance;\\n\"\n                \"- added a private key manually.\\n\"\n                \"Please call 'reset() if you want to build another agent.\"\n            )\n\n    def _overwrite_custom_configuration(\n        self, configuration: ComponentConfiguration\n    ) -> ComponentConfiguration:\n        \"\"\"\n        Overwrite custom configurations.\n\n        It deep-copies the configuration, to avoid undesired side-effects.\n\n        :param configuration: the configuration object.\n        :return: the new configuration instance.\n        \"\"\"\n        new_configuration = deepcopy(configuration)\n        custom_config = self._custom_component_configurations.get(\n            new_configuration.component_id, {}\n        )\n        new_configuration.update(custom_config)\n\n        return new_configuration\n\n    def _add_components_of_type(\n        self,\n        component_type: ComponentType,\n        agent_configuration: AgentConfig,\n        aea_project_path: Path,\n        skip_consistency_check: bool,\n    ) -> None:\n        \"\"\"\n        Add components of a given type.\n\n        :param component_type: the type of components to add.\n        :param agent_configuration: the agent configuration from where to retrieve the components.\n        :param aea_project_path: path to the AEA project.\n        :param skip_consistency_check: if true, skip consistency checks.\n        \"\"\"\n        public_ids = getattr(agent_configuration, component_type.to_plural())\n        component_ids = [\n            ComponentId(component_type, public_id) for public_id in public_ids\n        ]\n        if component_type in {ComponentType.PROTOCOL, ComponentType.CONTRACT}:\n            # if protocols or contracts, import order doesn't matter.\n            import_order = component_ids\n        else:\n            import_order = self._find_import_order(\n                component_ids, aea_project_path, skip_consistency_check\n            )\n        for component_id in import_order:\n            component_path = find_component_directory_from_component_id(\n                aea_project_path, component_id\n            )\n            self.add_component(\n                component_id.component_type,\n                component_path,\n                skip_consistency_check=skip_consistency_check,\n            )\n\n    def _preliminary_checks_before_build(self) -> None:\n        \"\"\"\n        Do consistency check on build parameters.\n\n        - Check that the specified default ledger is in the list of specified required ledgers.\n        \"\"\"\n        default_ledger = self.get_default_ledger()\n        required_ledgers = self.get_required_ledgers()\n        enforce(\n            default_ledger in required_ledgers,\n            exception_text=f\"Default ledger '{default_ledger}' not declared in the list of required ledgers: {required_ledgers}.\",\n            exception_class=AEAValidationError,\n        )\n\n\ndef make_component_logger(\n    configuration: ComponentConfiguration,\n    agent_name: str,\n) -> Optional[logging.Logger]:\n    \"\"\"\n    Make the logger for a component.\n\n    :param configuration: the component configuration\n    :param agent_name: the agent name\n    :return: the logger.\n    \"\"\"\n    if configuration.component_type == ComponentType.SKILL:\n        # skip because skill object already have their own logger from the skill context.\n        return None\n    logger_name = f\"aea.packages.{configuration.author}.{configuration.component_type.to_plural()}.{configuration.name}\"\n    _logger = AgentLoggerAdapter(get_logger(logger_name, agent_name), agent_name)\n    return cast(logging.Logger, _logger)\n"
  },
  {
    "path": "aea/agent.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the implementation of a generic agent.\"\"\"\nimport datetime\nimport logging\nfrom asyncio import AbstractEventLoop\nfrom logging import Logger\nfrom typing import Any, Callable, Dict, List, Optional, Tuple, Type\n\nfrom aea.abstract_agent import AbstractAgent\nfrom aea.connections.base import Connection\nfrom aea.exceptions import AEAException\nfrom aea.helpers.logging import WithLogger\nfrom aea.identity.base import Identity\nfrom aea.mail.base import Envelope\nfrom aea.multiplexer import InBox, OutBox\nfrom aea.runtime import AsyncRuntime, BaseRuntime, RuntimeStates, ThreadedRuntime\n\n\n_default_logger = logging.getLogger(__name__)\n\n\nclass Agent(AbstractAgent, WithLogger):\n    \"\"\"This class provides an abstract base class for a generic agent.\"\"\"\n\n    RUNTIMES: Dict[str, Type[BaseRuntime]] = {\n        \"async\": AsyncRuntime,\n        \"threaded\": ThreadedRuntime,\n    }\n    DEFAULT_RUNTIME: str = \"threaded\"\n\n    _runtime: BaseRuntime\n    _inbox: InBox\n    _outbox: OutBox\n\n    def __init__(\n        self,\n        identity: Identity,\n        connections: List[Connection],\n        loop: Optional[AbstractEventLoop] = None,\n        period: float = 1.0,\n        loop_mode: Optional[str] = None,\n        runtime_mode: Optional[str] = None,\n        storage_uri: Optional[str] = None,\n        logger: Logger = _default_logger,\n        task_manager_mode: Optional[str] = None,\n    ) -> None:\n        \"\"\"\n        Instantiate the agent.\n\n        :param identity: the identity of the agent.\n        :param connections: the list of connections of the agent.\n        :param loop: the event loop to run the connections.\n        :param period: period to call agent's act\n        :param loop_mode: loop_mode to choose agent run loop.\n        :param runtime_mode: runtime mode to up agent.\n        :param storage_uri: optional uri to set generic storage\n        :param task_manager_mode: task manager mode.\n        :param logger: the logger.\n        :param task_manager_mode: mode of the task manager.\n        \"\"\"\n        WithLogger.__init__(self, logger=logger)\n        self._identity = identity\n        self._period = period\n        self._tick = 0\n        self._runtime_mode = runtime_mode or self.DEFAULT_RUNTIME\n        self._task_manager_mode = task_manager_mode\n        self._storage_uri = storage_uri\n\n        runtime_class = self._get_runtime_class()\n\n        self._set_runtime_and_mail_boxes(\n            runtime_class=runtime_class,\n            loop_mode=loop_mode,\n            loop=loop,\n            multiplexer_options={\"connections\": connections},\n        )\n\n    def _set_runtime_and_mail_boxes(\n        self,\n        runtime_class: Type[BaseRuntime],\n        multiplexer_options: Dict,\n        loop_mode: Optional[str] = None,\n        loop: Optional[AbstractEventLoop] = None,\n    ) -> None:\n        \"\"\"Set the runtime and inbox and outbox.\"\"\"\n        self._runtime = runtime_class(\n            agent=self,\n            loop_mode=loop_mode,\n            loop=loop,\n            multiplexer_options=multiplexer_options,\n            task_manager_mode=self._task_manager_mode,\n        )\n        self._inbox = InBox(self.runtime.multiplexer)\n        self._outbox = OutBox(self.runtime.multiplexer)\n\n    def _get_runtime_class(self) -> Type[BaseRuntime]:\n        \"\"\"Get runtime class based on runtime mode.\"\"\"\n        if self._runtime_mode not in self.RUNTIMES:\n            raise ValueError(\n                f\"Runtime `{self._runtime_mode} is not supported. valid are: `{list(self.RUNTIMES.keys())}`\"\n            )\n        return self.RUNTIMES[self._runtime_mode]\n\n    @property\n    def storage_uri(self) -> Optional[str]:\n        \"\"\"Return storage uri.\"\"\"\n        return self._storage_uri\n\n    @property\n    def is_running(self) -> bool:\n        \"\"\"Get running state of the runtime and agent.\"\"\"\n        return self.runtime.is_running\n\n    @property\n    def is_stopped(self) -> bool:\n        \"\"\"Get running state of the runtime and agent.\"\"\"\n        return self.runtime.is_stopped\n\n    @property\n    def identity(self) -> Identity:\n        \"\"\"Get the identity.\"\"\"\n        return self._identity\n\n    @property\n    def inbox(self) -> InBox:  # pragma: nocover\n        \"\"\"\n        Get the inbox.\n\n        The inbox contains Envelopes from the Multiplexer.\n        The agent can pick these messages for processing.\n\n        :return: InBox instance\n        \"\"\"\n        return self._inbox\n\n    @property\n    def outbox(self) -> OutBox:  # pragma: nocover\n        \"\"\"\n        Get the outbox.\n\n        The outbox contains Envelopes for the Multiplexer.\n        Envelopes placed in the Outbox are processed by the Multiplexer.\n\n        :return: OutBox instance\n        \"\"\"\n        return self._outbox\n\n    @property\n    def name(self) -> str:\n        \"\"\"Get the agent name.\"\"\"\n        return self.identity.name\n\n    @property\n    def tick(self) -> int:  # pragma: nocover\n        \"\"\"\n        Get the tick or agent loop count.\n\n        Each agent loop (one call to each one of act(), react(), update()) increments the tick.\n\n        :return: tick count\n        \"\"\"\n        return self._tick\n\n    @property\n    def state(self) -> RuntimeStates:\n        \"\"\"\n        Get state of the agent's runtime.\n\n        :return: RuntimeStates\n        \"\"\"\n        return self.runtime.state\n\n    @property\n    def period(self) -> float:\n        \"\"\"Get a period to call act.\"\"\"\n        return self._period\n\n    @property\n    def runtime(self) -> BaseRuntime:\n        \"\"\"Get the runtime.\"\"\"\n        return self._runtime\n\n    def setup(self) -> None:\n        \"\"\"Set up the agent.\"\"\"\n        raise NotImplementedError  # pragma: nocover\n\n    def start(self) -> None:\n        \"\"\"\n        Start the agent.\n\n        Performs the following:\n\n        - calls start() on runtime.\n        - waits for runtime to complete running (blocking)\n        \"\"\"\n        was_started = self.runtime.start()\n\n        if was_started:\n            self.runtime.wait_completed(sync=True)\n        else:  # pragma: nocover\n            raise AEAException(\"Failed to start runtime! Was it already started?\")\n\n    def handle_envelope(self, envelope: Envelope) -> None:\n        \"\"\"\n        Handle an envelope.\n\n        :param envelope: the envelope to handle.\n        \"\"\"\n        raise NotImplementedError  # pragma: nocover\n\n    def act(self) -> None:\n        \"\"\"Perform actions on period.\"\"\"\n        raise NotImplementedError  # pragma: nocover\n\n    def stop(self) -> None:\n        \"\"\"\n        Stop the agent.\n\n        Performs the following:\n\n        - calls stop() on runtime\n        - waits for runtime to stop (blocking)\n        \"\"\"\n        self.runtime.stop()\n        self.runtime.wait_completed(sync=True)\n\n    def teardown(self) -> None:\n        \"\"\"Tear down the agent.\"\"\"\n        raise NotImplementedError  # pragma: nocover\n\n    def get_periodic_tasks(\n        self,\n    ) -> Dict[Callable, Tuple[float, Optional[datetime.datetime]]]:\n        \"\"\"\n        Get all periodic tasks for agent.\n\n        :return: dict of callable with period specified\n        \"\"\"\n        return {self.act: (self.period, None)}\n\n    def get_message_handlers(self) -> List[Tuple[Callable[[Any], None], Callable]]:\n        \"\"\"\n        Get handlers with message getters.\n\n        :return: List of tuples of callables: handler and coroutine to get a message\n        \"\"\"\n        return [\n            (self.handle_envelope, self.inbox.async_get),\n        ]\n\n    def exception_handler(\n        self, exception: Exception, function: Callable\n    ) -> bool:  # pragma: nocover\n        \"\"\"\n        Handle exception raised during agent main loop execution.\n\n        :param exception: exception raised\n        :param function: a callable exception raised in.\n\n        :return: bool, propagate exception if True otherwise skip it.\n        \"\"\"\n        self.logger.exception(\n            f\"Exception {repr(exception)} raised during {repr(function)} call.\"\n        )\n        return True\n"
  },
  {
    "path": "aea/agent_loop.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the implementation of an agent loop using asyncio.\"\"\"\nimport asyncio\nimport datetime\nfrom abc import ABC, abstractmethod\nfrom asyncio import CancelledError\nfrom asyncio.events import AbstractEventLoop\nfrom asyncio.queues import Queue\nfrom asyncio.tasks import Task\nfrom contextlib import suppress\nfrom enum import Enum\nfrom functools import partial\nfrom typing import Any, Callable, Dict, List, Optional, Sequence, Tuple, Union, cast\n\nfrom aea.abstract_agent import AbstractAgent\nfrom aea.configurations.constants import LAUNCH_SUCCEED_MESSAGE\nfrom aea.exceptions import AEAException\nfrom aea.helpers.async_utils import AsyncState, PeriodicCaller, Runnable\nfrom aea.helpers.exec_timeout import ExecTimeoutThreadGuard, TimeoutException\nfrom aea.helpers.logging import WithLogger, get_logger\nfrom aea.mail.base import Envelope, EnvelopeContext\nfrom aea.protocols.base import Message\n\n\nclass AgentLoopException(AEAException):\n    \"\"\"Exception for agent loop runtime errors.\"\"\"\n\n\nclass AgentLoopStates(Enum):\n    \"\"\"Internal agent loop states.\"\"\"\n\n    initial = None\n    started = \"started\"\n    starting = \"starting\"\n    stopped = \"stopped\"\n    stopping = \"stopping\"\n    error = \"error\"\n\n\nclass BaseAgentLoop(Runnable, WithLogger, ABC):\n    \"\"\"Base abstract  agent loop class.\"\"\"\n\n    def __init__(\n        self,\n        agent: AbstractAgent,\n        loop: Optional[AbstractEventLoop] = None,\n        threaded: bool = False,\n    ) -> None:\n        \"\"\"Init loop.\n\n        :param agent: Agent or AEA to run.\n        :param loop: optional asyncio event loop. if not specified a new loop will be created.\n        :param threaded: if True, run in threaded mode, else async\n        \"\"\"\n        logger = get_logger(__name__, agent.name)\n        WithLogger.__init__(self, logger)\n        Runnable.__init__(self, loop=loop, threaded=threaded)\n\n        self._agent: AbstractAgent = agent\n        self._tasks: List[asyncio.Task] = []\n        self._state: AsyncState = AsyncState(AgentLoopStates.initial)\n        self._exceptions: List[Exception] = []\n\n    @property\n    def agent(self) -> AbstractAgent:  # pragma: nocover\n        \"\"\"Get agent.\"\"\"\n        return self._agent\n\n    @property\n    def state(self) -> AgentLoopStates:\n        \"\"\"Get current main loop state.\"\"\"\n        return self._state.get()\n\n    async def wait_state(\n        self, state_or_states: Union[Any, Sequence[Any]]\n    ) -> Tuple[Any, Any]:\n        \"\"\"\n        Wait state to be set.\n\n        :param state_or_states: state or list of states.\n\n        :return: tuple of previous state and new state.\n        \"\"\"\n\n        return await self._state.wait(state_or_states)\n\n    @property\n    def is_running(self) -> bool:\n        \"\"\"Get running state of the loop.\"\"\"\n        return self._state.get() == AgentLoopStates.started\n\n    def set_loop(self, loop: AbstractEventLoop) -> None:\n        \"\"\"Set event loop and all event loop related objects.\"\"\"\n        self._loop: AbstractEventLoop = loop\n\n    def _setup(self) -> None:\n        \"\"\"Set up agent loop before started.\"\"\"\n        # start and stop methods are classmethods cause one instance shared across multiple threads\n        ExecTimeoutThreadGuard.start()\n\n    def _teardown(self) -> None:\n        \"\"\"Tear down loop on stop.\"\"\"\n        # start and stop methods are classmethods cause one instance shared across multiple threads\n        ExecTimeoutThreadGuard.stop()\n\n    async def run(self) -> None:\n        \"\"\"Run agent loop.\"\"\"\n        self.logger.debug(\"agent loop starting...\")\n        self._state.set(AgentLoopStates.starting)\n        self._setup()\n        self._set_tasks()\n        try:\n            await self._gather_tasks()\n        except (CancelledError, KeyboardInterrupt):\n            pass\n        finally:\n            await self._stop()\n\n    async def _stop(self) -> None:\n        \"\"\"Stop and cleanup.\"\"\"\n        self._teardown()\n        self._stop_tasks()\n        for t in self._tasks:\n            with suppress(CancelledError, KeyboardInterrupt):\n                await t\n\n        self._state.set(AgentLoopStates.stopped)\n        self.logger.debug(\"agent loop stopped\")\n\n    async def _gather_tasks(self) -> None:\n        \"\"\"Wait till first task exception.\"\"\"\n        await asyncio.gather(*self._tasks)\n\n    @abstractmethod\n    def _set_tasks(self) -> None:  # pragma: nocover\n        \"\"\"Set run loop tasks.\"\"\"\n        raise NotImplementedError\n\n    def _stop_tasks(self) -> None:\n        \"\"\"Cancel all tasks.\"\"\"\n        for task in self._tasks:\n            task.cancel()\n\n    @abstractmethod\n    def send_to_skill(\n        self,\n        message_or_envelope: Union[Message, Envelope],\n        context: Optional[EnvelopeContext] = None,\n    ) -> None:\n        \"\"\"\n        Send message or envelope to another skill.\n\n        If message passed it will be wrapped into envelope with optional envelope context.\n\n        :param message_or_envelope: envelope to send to another skill.\n        :param context: envelope context\n        \"\"\"\n\n    @property\n    @abstractmethod\n    def skill2skill_queue(self) -> Queue:\n        \"\"\"Get skill to skill message queue.\"\"\"\n\n\nclass AsyncAgentLoop(BaseAgentLoop):\n    \"\"\"Asyncio based agent loop suitable only for AEA.\"\"\"\n\n    NEW_BEHAVIOURS_PROCESS_SLEEP = 1  # check new behaviours registered every second.\n\n    def __init__(\n        self,\n        agent: AbstractAgent,\n        loop: AbstractEventLoop = None,\n        threaded: bool = False,\n    ) -> None:\n        \"\"\"\n        Init agent loop.\n\n        :param agent: AEA instance\n        :param loop: asyncio loop to use. optional\n        :param threaded: is a new thread to be started for the agent loop\n        \"\"\"\n        super().__init__(agent=agent, loop=loop, threaded=threaded)\n        self._agent: AbstractAgent = self._agent\n\n        self._periodic_tasks: Dict[Callable, PeriodicCaller] = {}\n        self._skill2skill_message_queue: Optional[asyncio.Queue] = None\n\n    def _setup(self) -> None:\n        \"\"\"Set up agent loop before started.\"\"\"\n        super()._setup()\n        self._skill2skill_message_queue = asyncio.Queue()\n\n    @property\n    def skill2skill_queue(self) -> Queue:\n        \"\"\"Get skill to skill message queue.\"\"\"\n        if not self._skill2skill_message_queue:  # pragma: nocover\n            raise ValueError(\"_skill2skill_message_queue is not set!\")\n        return self._skill2skill_message_queue\n\n    def send_to_skill(\n        self,\n        message_or_envelope: Union[Message, Envelope],\n        context: Optional[EnvelopeContext] = None,\n    ) -> None:\n        \"\"\"\n        Send message or envelope to another skill.\n\n        If message passed it will be wrapped into envelope with optional envelope context.\n\n        :param message_or_envelope: envelope to send to another skill.\n        :param context: envelope context\n        \"\"\"\n        if isinstance(message_or_envelope, Envelope):\n            envelope = message_or_envelope\n            message = cast(Message, envelope.message)\n        elif isinstance(message_or_envelope, Message):\n            message = message_or_envelope\n            envelope = Envelope(\n                to=message.to,\n                sender=message.sender,\n                message=message,\n                context=context,\n            )\n        else:\n            raise ValueError(\n                f\"Unsupported message or envelope type: {type(message_or_envelope)}\"\n            )\n\n        if not message.has_to:  # pragma: nocover\n            raise ValueError(\"Provided message has message.to not set.\")\n        if not message.has_sender:  # pragma: nocover\n            raise ValueError(\"Provided message has message.sender not set.\")\n\n        self.skill2skill_queue.put_nowait(envelope)\n\n    def _periodic_task_exception_callback(  # pylint: disable=unused-argument\n        self, task_callable: Callable, exc: Exception\n    ) -> None:\n        \"\"\"\n        Call on periodic task exception.\n\n        :param task_callable: function to be called\n        :param: exc: Exception  raised\n        \"\"\"\n        self._exceptions.append(exc)\n\n    def _execution_control(\n        self,\n        fn: Callable,\n        args: Optional[Sequence] = None,\n        kwargs: Optional[Dict] = None,\n    ) -> Any:\n        \"\"\"\n        Execute skill function in exception handling environment.\n\n        Logs error, stop agent or propagate exception depends on policy defined.\n\n        :param fn: function to call\n        :param args: optional sequence of arguments to pass to function on call\n        :param kwargs: optional dict of keyword arguments to pass to function on call\n\n        :return: same as function\n        \"\"\"\n        execution_timeout = getattr(self.agent, \"_execution_timeout\", 0)\n\n        try:\n            with ExecTimeoutThreadGuard(execution_timeout):\n                return fn(*(args or []), **(kwargs or {}))\n        except TimeoutException:  # pragma: nocover\n            self.logger.warning(\n                \"`{}` was terminated as its execution exceeded the timeout of {} seconds. Please refactor your code!\".format(\n                    fn, execution_timeout\n                )\n            )\n        except Exception as e:  # pylint: disable=broad-except\n            try:\n                if self.agent.exception_handler(e, fn) is True:\n                    self._state.set(AgentLoopStates.error)\n                    raise\n            except Exception as e2:\n                self._state.set(AgentLoopStates.error)\n                self._exceptions.append(e2)\n                raise\n        return None\n\n    def _register_periodic_task(\n        self,\n        task_callable: Callable,\n        period: float,\n        start_at: Optional[datetime.datetime],\n    ) -> None:\n        \"\"\"\n        Register function to run periodically.\n\n        :param task_callable: function to be called\n        :param period: float in seconds\n        :param start_at: optional datetime, when to run task for the first time, otherwise call it right now\n\n        :return: None\n        \"\"\"\n        if task_callable in self._periodic_tasks:  # pragma: nocover\n            # already registered\n            return\n\n        periodic_caller = PeriodicCaller(\n            partial(self._execution_control, task_callable),\n            period=period,\n            start_at=start_at,\n            exception_callback=self._periodic_task_exception_callback,\n            loop=self._loop,\n        )\n        self._periodic_tasks[task_callable] = periodic_caller\n        periodic_caller.start()\n        self.logger.debug(f\"Periodic task {task_callable} registered.\")\n\n    def _register_periodic_tasks(self) -> None:\n        \"\"\"Register all AEA related periodic tasks.\"\"\"\n        for (\n            task_callable,\n            (period, start_at),\n        ) in self._agent.get_periodic_tasks().items():\n            self._register_periodic_task(task_callable, period, start_at)\n\n    def _unregister_periodic_task(self, task_callable: Callable) -> None:\n        \"\"\"\n        Unregister periodic execution of the task.\n\n        :param task_callable: function to be called periodically.\n        :return: None\n        \"\"\"\n        periodic_caller = self._periodic_tasks.pop(task_callable, None)\n        if periodic_caller is None:  # pragma: nocover\n            return\n        periodic_caller.stop()\n\n    def _stop_all_behaviours(self) -> None:\n        \"\"\"Unregister periodic execution of all registered behaviours.\"\"\"\n        for task_callable in list(self._periodic_tasks.keys()):\n            self._unregister_periodic_task(task_callable)\n\n    async def _task_wait_for_error(self) -> None:\n        \"\"\"Wait for error and raise first.\"\"\"\n        await self._state.wait(AgentLoopStates.error)\n        raise self._exceptions[0]\n\n    def _stop_tasks(self) -> None:\n        \"\"\"Cancel all tasks and stop behaviours registered.\"\"\"\n        BaseAgentLoop._stop_tasks(self)\n        self._stop_all_behaviours()\n\n    def _set_tasks(self) -> None:\n        \"\"\"Set run loop tasks.\"\"\"\n        self._tasks = self._create_tasks()\n        self.logger.debug(\"tasks created!\")\n\n    def _create_tasks(self) -> List[Task]:\n        \"\"\"\n        Create tasks.\n\n        :return: list of asyncio Tasks\n        \"\"\"\n        coros = [\n            self._process_messages(),\n            self._task_register_periodic_tasks(),\n            self._task_wait_for_error(),\n        ]\n        return list(map(self._loop.create_task, coros))  # type: ignore  # some issue with map and create_task\n\n    async def _message_processor(\n        self, message_handler: Callable, message_getter: Callable\n    ) -> None:\n        \"\"\"Fetch messages from the message getter and process it with message handler.\"\"\"\n        try:\n            while self.is_running:\n                message = await message_getter()\n                self._execution_control(message_handler, [message])\n        except CancelledError:  # pylint: disable=try-except-raise\n            raise\n        except Exception:  # pragma: nocover\n            self.logger.exception(\n                f\"Exception in message processor ({message_handler, message_getter})\"\n            )\n            raise\n\n    def _message_handlers(self) -> List[Tuple[Callable[[Any], None], Callable]]:\n        \"\"\"Get all agent's message handlers.\"\"\"\n        return self._agent.get_message_handlers()\n\n    async def _process_messages(self) -> None:\n        \"\"\"Start tasks for messages handlers and sources.\"\"\"\n        coros = []\n        for handler, getter in self._message_handlers():\n            coros.append(self._message_processor(handler, getter))\n\n        self.logger.info(LAUNCH_SUCCEED_MESSAGE)\n        self._state.set(AgentLoopStates.started)\n\n        await asyncio.gather(*coros)\n\n    async def _task_register_periodic_tasks(self) -> None:\n        \"\"\"Process new behaviours added to skills in runtime.\"\"\"\n        while self.is_running:\n            self._register_periodic_tasks()  # re register, cause new may appear\n            await asyncio.sleep(self.NEW_BEHAVIOURS_PROCESS_SLEEP)\n\n\nSyncAgentLoop = AsyncAgentLoop  # temporary solution!\n"
  },
  {
    "path": "aea/cli/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the implementation of command-line tool 'aea'.\"\"\"\n\nfrom .core import cli\n"
  },
  {
    "path": "aea/cli/__main__.py",
    "content": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Entry-point for the AEA command-line tool.\"\"\"\n\nfrom aea.cli.core import cli\n\n\nif __name__ == \"__main__\":\n    cli(prog_name=\"aea\")  # pragma: no cover\n"
  },
  {
    "path": "aea/cli/add.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Implementation of the 'aea add' subcommand.\"\"\"\nfrom pathlib import Path\nfrom typing import Union, cast\n\nimport click\n\nfrom aea.cli.registry.add import fetch_package\nfrom aea.cli.utils.click_utils import PublicIdParameter, registry_flag\nfrom aea.cli.utils.config import load_item_config\nfrom aea.cli.utils.context import Context\nfrom aea.cli.utils.decorators import check_aea_project, clean_after, pass_ctx\nfrom aea.cli.utils.loggers import logger\nfrom aea.cli.utils.package_utils import (\n    copy_package_directory,\n    find_item_in_distribution,\n    find_item_locally,\n    get_item_id_present,\n    get_package_path,\n    is_distributed_item,\n    is_fingerprint_correct,\n    is_item_present,\n    register_item,\n)\nfrom aea.configurations.base import (\n    ConnectionConfig,\n    PackageConfiguration,\n    PublicId,\n    SkillConfig,\n)\nfrom aea.configurations.constants import CONNECTION, CONTRACT, PROTOCOL, SKILL\nfrom aea.exceptions import enforce\n\n\n@click.group()\n@registry_flag()\n@click.pass_context\n@check_aea_project\ndef add(click_context: click.Context, local: bool, remote: bool) -> None:\n    \"\"\"Add a package to the agent.\"\"\"\n    ctx = cast(Context, click_context.obj)\n    enforce(\n        not (local and remote), \"'local' and 'remote' options are mutually exclusive.\"\n    )\n    if not local and not remote:\n        try:\n            ctx.registry_path\n        except ValueError as e:\n            click.echo(f\"{e}\\nTrying remote registry (`--remote`).\")\n            remote = True\n    is_mixed = not local and not remote\n    ctx.set_config(\"is_local\", local and not remote)\n    ctx.set_config(\"is_mixed\", is_mixed)\n\n\n@add.command()\n@click.argument(\"connection_public_id\", type=PublicIdParameter(), required=True)\n@pass_ctx\ndef connection(ctx: Context, connection_public_id: PublicId) -> None:\n    \"\"\"Add a connection to the agent.\"\"\"\n    add_item(ctx, CONNECTION, connection_public_id)\n\n\n@add.command()\n@click.argument(\"contract_public_id\", type=PublicIdParameter(), required=True)\n@pass_ctx\ndef contract(ctx: Context, contract_public_id: PublicId) -> None:\n    \"\"\"Add a contract to the agent.\"\"\"\n    add_item(ctx, CONTRACT, contract_public_id)\n\n\n@add.command()\n@click.argument(\"protocol_public_id\", type=PublicIdParameter(), required=True)\n@pass_ctx\ndef protocol(ctx: Context, protocol_public_id: PublicId) -> None:\n    \"\"\"Add a protocol to the agent.\"\"\"\n    add_item(ctx, PROTOCOL, protocol_public_id)\n\n\n@add.command()\n@click.argument(\"skill_public_id\", type=PublicIdParameter(), required=True)\n@pass_ctx\ndef skill(ctx: Context, skill_public_id: PublicId) -> None:\n    \"\"\"Add a skill to the agent.\"\"\"\n    add_item(ctx, SKILL, skill_public_id)\n\n\n@clean_after\ndef add_item(ctx: Context, item_type: str, item_public_id: PublicId) -> None:\n    \"\"\"\n    Add an item.\n\n    :param ctx: Context object.\n    :param item_type: the item type.\n    :param item_public_id: the item public id.\n    \"\"\"\n    click.echo(f\"Adding {item_type} '{item_public_id}'...\")\n    if is_item_present(ctx.cwd, ctx.agent_config, item_type, item_public_id):\n        present_item_id = get_item_id_present(\n            ctx.agent_config, item_type, item_public_id\n        )\n        raise click.ClickException(\n            \"A {} with id '{}' already exists. Aborting...\".format(\n                item_type, present_item_id\n            )\n        )\n\n    dest_path = get_package_path(ctx.cwd, item_type, item_public_id)\n    is_local = ctx.config.get(\"is_local\")\n    is_mixed = ctx.config.get(\"is_mixed\")\n\n    ctx.clean_paths.append(dest_path)\n\n    if is_mixed:\n        package_path = fetch_item_mixed(ctx, item_type, item_public_id, dest_path)\n    elif is_local:\n        package_path = find_item_locally_or_distributed(\n            ctx, item_type, item_public_id, dest_path\n        )\n    else:\n        package_path = fetch_package(\n            item_type, public_id=item_public_id, cwd=ctx.cwd, dest=dest_path\n        )\n    item_config = load_item_config(item_type, package_path)\n\n    if not ctx.config.get(\"skip_consistency_check\") and not is_fingerprint_correct(\n        package_path, item_config\n    ):  # pragma: no cover\n        raise click.ClickException(\"Failed to add an item with incorrect fingerprint.\")\n\n    _add_item_deps(ctx, item_type, item_config)\n    register_item(ctx, item_type, item_config.public_id)\n    click.echo(f\"Successfully added {item_type} '{item_config.public_id}'.\")\n\n\ndef _add_item_deps(\n    ctx: Context, item_type: str, item_config: PackageConfiguration\n) -> None:\n    \"\"\"\n    Add item dependencies. Calls add_item recursively.\n\n    :param ctx: Context object.\n    :param item_type: type of item.\n    :param item_config: item configuration object.\n    \"\"\"\n    if item_type in {CONNECTION, SKILL}:\n        item_config = cast(Union[SkillConfig, ConnectionConfig], item_config)\n        # add missing protocols\n        for protocol_public_id in item_config.protocols:\n            if protocol_public_id not in ctx.agent_config.protocols:\n                add_item(ctx, PROTOCOL, protocol_public_id)\n\n    if item_type == SKILL:\n        item_config = cast(SkillConfig, item_config)\n        # add missing contracts\n        for contract_public_id in item_config.contracts:\n            if contract_public_id not in ctx.agent_config.contracts:\n                add_item(ctx, CONTRACT, contract_public_id)\n\n        # add missing connections\n        for connection_public_id in item_config.connections:\n            if connection_public_id not in ctx.agent_config.connections:\n                add_item(ctx, CONNECTION, connection_public_id)\n\n        # add missing skill\n        for skill_public_id in item_config.skills:\n            if skill_public_id not in ctx.agent_config.skills:\n                add_item(ctx, SKILL, skill_public_id)\n\n\ndef find_item_locally_or_distributed(\n    ctx: Context, item_type: str, item_public_id: PublicId, dest_path: str\n) -> Path:\n    \"\"\"\n    Unify find item locally both in case it is distributed or not.\n\n    :param ctx: the CLI context.\n    :param item_type: the item type.\n    :param item_public_id: the item public id.\n    :param dest_path: the path to the destination.\n    :return: the path to the found package.\n    \"\"\"\n    is_distributed = is_distributed_item(item_public_id)\n    if is_distributed:  # pragma: nocover\n        source_path = find_item_in_distribution(ctx, item_type, item_public_id)\n        package_path = copy_package_directory(source_path, dest_path)\n    else:\n        source_path, _ = find_item_locally(ctx, item_type, item_public_id)\n        package_path = copy_package_directory(source_path, dest_path)\n\n    return package_path\n\n\ndef fetch_item_mixed(\n    ctx: Context,\n    item_type: str,\n    item_public_id: PublicId,\n    dest_path: str,\n) -> Path:\n    \"\"\"\n    Find item, mixed mode.\n\n    That is, give priority to local registry, and fall back to remote registry\n    in case of failure.\n\n    :param ctx: the CLI context.\n    :param item_type: the item type.\n    :param item_public_id: the item public id.\n    :param dest_path: the path to the destination.\n    :return: the path to the found package.\n    \"\"\"\n    try:\n        package_path = find_item_locally_or_distributed(\n            ctx, item_type, item_public_id, dest_path\n        )\n    except click.ClickException as e:\n        logger.debug(\n            f\"Fetch from local registry failed (reason={str(e)}), trying remote registry...\"\n        )\n        # the following might raise exception, but we don't catch it this time\n        package_path = fetch_package(\n            item_type, public_id=item_public_id, cwd=ctx.cwd, dest=dest_path\n        )\n    return package_path\n"
  },
  {
    "path": "aea/cli/add_key.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Implementation of the 'aea add_key' subcommand.\"\"\"\nimport os\nfrom typing import Optional, cast\n\nimport click\n\nfrom aea.cli.utils.click_utils import password_option\nfrom aea.cli.utils.context import Context\nfrom aea.cli.utils.decorators import check_aea_project\nfrom aea.configurations.constants import (\n    DEFAULT_AEA_CONFIG_FILE,\n    PRIVATE_KEY_PATH_SCHEMA,\n)\nfrom aea.crypto.helpers import try_validate_private_key_path\nfrom aea.crypto.registries import crypto_registry\nfrom aea.helpers.io import open_file\n\n\nkey_file_argument = click.Path(\n    exists=True, file_okay=True, dir_okay=False, readable=True\n)\n\n\n@click.command()\n@click.argument(\n    \"type_\",\n    metavar=\"TYPE\",\n    type=click.Choice(list(crypto_registry.supported_ids)),\n    required=True,\n)\n@click.argument(\n    \"file\",\n    metavar=\"FILE\",\n    type=key_file_argument,\n    required=False,\n)\n@password_option()\n@click.option(\n    \"--connection\", is_flag=True, help=\"For adding a private key for connections.\"\n)\n@click.pass_context\n@check_aea_project\ndef add_key(\n    click_context: click.Context,\n    type_: str,\n    file: str,\n    password: Optional[str],\n    connection: bool,\n) -> None:\n    \"\"\"Add a private key to the wallet of the agent.\"\"\"\n    _add_private_key(click_context, type_, file, password, connection)\n\n\ndef _add_private_key(\n    click_context: click.core.Context,\n    type_: str,\n    file: Optional[str] = None,\n    password: Optional[str] = None,\n    connection: bool = False,\n) -> None:\n    \"\"\"\n    Add private key to the wallet.\n\n    :param click_context: click context object.\n    :param type_: type.\n    :param file: path to file.\n    :param connection: whether or not it is a private key for a connection.\n    :param password: the password to encrypt/decrypt the private key.\n    \"\"\"\n    ctx = cast(Context, click_context.obj)\n    if file is None:\n        file = PRIVATE_KEY_PATH_SCHEMA.format(type_)\n\n    key_file_argument.convert(file, None, click_context)\n    try:\n        try_validate_private_key_path(type_, file, password=password)\n    except Exception as e:\n        raise click.ClickException(repr(e)) from e\n    _try_add_key(ctx, type_, file, connection)\n\n\ndef _try_add_key(\n    ctx: Context, type_: str, filepath: str, connection: bool = False\n) -> None:\n    try:\n        if connection:\n            ctx.agent_config.connection_private_key_paths.create(type_, filepath)\n        else:\n            ctx.agent_config.private_key_paths.create(type_, filepath)\n    except ValueError as e:  # pragma: no cover\n        raise click.ClickException(str(e))\n    with open_file(os.path.join(ctx.cwd, DEFAULT_AEA_CONFIG_FILE), \"w\") as fp:\n        ctx.agent_loader.dump(ctx.agent_config, fp)\n"
  },
  {
    "path": "aea/cli/build.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Implementation of the 'aea build' subcommand.\"\"\"\nfrom pathlib import Path\nfrom typing import cast\n\nimport click\n\nfrom aea.aea_builder import AEABuilder\nfrom aea.cli.utils.context import Context\nfrom aea.cli.utils.decorators import check_aea_project\n\n\n@click.command()\n@click.pass_context\n@check_aea_project\ndef build(click_context: click.Context) -> None:\n    \"\"\"Build the agent and its components.\"\"\"\n    ctx = cast(Context, click_context.obj)\n    skip_consistency_check = ctx.config.get(\"skip_consistency_check\", False)\n    build_aea(skip_consistency_check)\n\n\ndef build_aea(skip_consistency_check: bool) -> None:\n    \"\"\"\n    Build an AEA.\n\n    That is, run the 'build entrypoint' script of each AEA package of the project.\n\n    :param skip_consistency_check: the skip consistency check boolean.\n    \"\"\"\n    try:\n        builder = AEABuilder.from_aea_project(\n            Path(\".\"),\n            skip_consistency_check=skip_consistency_check,\n        )\n        builder.call_all_build_entrypoints()\n    except Exception as e:\n        raise click.ClickException(str(e))\n    click.echo(\"Build completed!\")\n"
  },
  {
    "path": "aea/cli/config.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Implementation of the 'aea config' subcommand.\"\"\"\nimport contextlib\nimport json\nfrom typing import Optional, cast\n\nimport click\nfrom click.exceptions import ClickException\n\nfrom aea.cli.utils.constants import CONFIG_SUPPORTED_KEY_TYPES\nfrom aea.cli.utils.context import Context\nfrom aea.cli.utils.decorators import check_aea_project, pass_ctx\nfrom aea.configurations.manager import AgentConfigManager, VariableDoesNotExist\nfrom aea.configurations.validation import ExtraPropertiesError\nfrom aea.exceptions import AEAException\nfrom aea.helpers.env_vars import convert_value_str_to_type\n\n\n@click.group()\n@click.pass_context\n@check_aea_project\ndef config(click_context: click.Context) -> None:  # pylint: disable=unused-argument\n    \"\"\"Read or modify a configuration of the agent.\"\"\"\n\n\n@config.command()\n@click.argument(\"JSON_PATH\", required=True)\n@pass_ctx\ndef get(ctx: Context, json_path: str) -> None:\n    \"\"\"Get a field.\"\"\"\n    try:\n        agent_config_manager = AgentConfigManager.load(ctx.cwd)\n        value = agent_config_manager.get_variable(json_path)\n    except (ValueError, AEAException) as e:\n        raise ClickException(str(e.args[0]))\n\n    if isinstance(value, dict):\n        # turn it to json compatible string, not dict str representation\n        value = json.dumps(value, sort_keys=True)\n    click.echo(value)\n\n\n@config.command(name=\"set\")\n@click.option(\n    \"--type\",\n    \"type_\",\n    default=None,\n    type=click.Choice(CONFIG_SUPPORTED_KEY_TYPES + [None]),  # type: ignore\n    help=\"Specify the type of the value.\",\n)\n@click.argument(\"JSON_PATH\", required=True)\n@click.argument(\"VALUE\", required=True, type=str)\n@pass_ctx\ndef set_command(\n    ctx: Context,\n    json_path: str,\n    value: str,\n    type_: Optional[str],\n) -> None:\n    \"\"\"Set a field.\"\"\"\n    try:\n        agent_config_manager = AgentConfigManager.load(ctx.cwd)\n\n        current_value = None\n        with contextlib.suppress(VariableDoesNotExist):\n            current_value = agent_config_manager.get_variable(json_path)\n\n        # type was not specified, tried to auto determine\n        if type_ is None:\n            # apply str as default type\n            converted_value = convert_value_str_to_type(value, \"str\")\n            if current_value is not None:\n                # try to convert to original value's type\n                with contextlib.suppress(Exception):\n                    converted_value = convert_value_str_to_type(\n                        value, type(current_value).__name__\n                    )\n        else:\n            # convert to type specified by user\n            converted_value = convert_value_str_to_type(value, cast(str, type_))\n\n        agent_config_manager.set_variable(json_path, converted_value)\n        agent_config_manager.dump_config()\n    except ExtraPropertiesError as e:  # pragma: nocover\n        raise ClickException(f\"Attribute `{e.args[0][0]}` is not allowed to change!\")\n    except (ValueError, AEAException) as e:\n        raise ClickException(str(e.args[0]))\n"
  },
  {
    "path": "aea/cli/core.py",
    "content": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Core definitions for the AEA command-line tool.\"\"\"\nfrom typing import Optional\n\nimport click\nfrom pkg_resources import iter_entry_points\n\nimport aea\nfrom aea.cli.add import add\nfrom aea.cli.add_key import add_key\nfrom aea.cli.build import build\nfrom aea.cli.config import config\nfrom aea.cli.create import create\nfrom aea.cli.delete import delete\nfrom aea.cli.eject import eject\nfrom aea.cli.fetch import fetch\nfrom aea.cli.fingerprint import fingerprint\nfrom aea.cli.freeze import freeze\nfrom aea.cli.generate import generate\nfrom aea.cli.generate_key import generate_key\nfrom aea.cli.generate_wealth import generate_wealth\nfrom aea.cli.get_address import get_address\nfrom aea.cli.get_multiaddress import get_multiaddress\nfrom aea.cli.get_public_key import get_public_key\nfrom aea.cli.get_wealth import get_wealth\nfrom aea.cli.init import init\nfrom aea.cli.install import install\nfrom aea.cli.interact import interact\nfrom aea.cli.issue_certificates import issue_certificates\nfrom aea.cli.launch import launch\nfrom aea.cli.list import list_command as _list\nfrom aea.cli.local_registry_sync import local_registry_sync\nfrom aea.cli.login import login\nfrom aea.cli.logout import logout\nfrom aea.cli.plugin import with_plugins\nfrom aea.cli.publish import publish\nfrom aea.cli.push import push\nfrom aea.cli.register import register\nfrom aea.cli.remove import remove\nfrom aea.cli.remove_key import remove_key\nfrom aea.cli.reset_password import reset_password\nfrom aea.cli.run import run\nfrom aea.cli.scaffold import scaffold\nfrom aea.cli.search import search\nfrom aea.cli.transfer import transfer\nfrom aea.cli.upgrade import upgrade\nfrom aea.cli.utils.click_utils import registry_path_option\nfrom aea.cli.utils.config import get_registry_path_from_cli_config\nfrom aea.cli.utils.context import Context\nfrom aea.cli.utils.loggers import logger, simple_verbosity_option\nfrom aea.helpers.win32 import enable_ctrl_c_support\n\n\n@with_plugins(iter_entry_points(\"aea.cli\"))\n@click.group(name=\"aea\")  # type: ignore\n@click.version_option(aea.__version__, prog_name=\"aea\")\n@simple_verbosity_option(logger, default=\"INFO\")\n@click.option(\n    \"-s\",\n    \"--skip-consistency-check\",\n    \"skip_consistency_check\",\n    is_flag=True,\n    required=False,\n    default=False,\n    help=\"Skip consistency checks of agent during command execution.\",\n)\n@registry_path_option\n@click.pass_context\ndef cli(\n    click_context: click.Context,\n    skip_consistency_check: bool,\n    registry_path: Optional[str],\n) -> None:\n    \"\"\"Command-line tool for setting up an Autonomous Economic Agent (AEA).\"\"\"\n    verbosity_option = click_context.meta.pop(\"verbosity\")\n    if not registry_path:\n        registry_path = get_registry_path_from_cli_config()\n    click_context.obj = Context(\n        cwd=\".\", verbosity=verbosity_option, registry_path=registry_path\n    )\n    click_context.obj.set_config(\"skip_consistency_check\", skip_consistency_check)\n\n    # enables CTRL+C support on windows!\n    enable_ctrl_c_support()\n\n\ncli.add_command(_list)\ncli.add_command(add_key)\ncli.add_command(add)\ncli.add_command(build)\ncli.add_command(create)\ncli.add_command(config)\ncli.add_command(delete)\ncli.add_command(eject)\ncli.add_command(fetch)\ncli.add_command(fingerprint)\ncli.add_command(freeze)\ncli.add_command(generate_key)\ncli.add_command(generate_wealth)\ncli.add_command(generate)\ncli.add_command(get_address)\ncli.add_command(get_public_key)\ncli.add_command(get_multiaddress)\ncli.add_command(get_wealth)\ncli.add_command(init)\ncli.add_command(install)\ncli.add_command(interact)\ncli.add_command(issue_certificates)\ncli.add_command(launch)\ncli.add_command(login)\ncli.add_command(logout)\ncli.add_command(publish)\ncli.add_command(push)\ncli.add_command(register)\ncli.add_command(remove)\ncli.add_command(remove_key)\ncli.add_command(reset_password)\ncli.add_command(run)\ncli.add_command(scaffold)\ncli.add_command(search)\ncli.add_command(local_registry_sync)\ncli.add_command(transfer)\ncli.add_command(upgrade)\n"
  },
  {
    "path": "aea/cli/create.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Implementation of the 'aea create' subcommand.\"\"\"\n\nimport os\nfrom pathlib import Path\nfrom typing import Optional, cast\n\nimport click\n\nfrom aea import get_current_aea_version\nfrom aea.cli.add import add_item\nfrom aea.cli.init import do_init\nfrom aea.cli.utils.click_utils import registry_flag\nfrom aea.cli.utils.config import get_or_create_cli_config\nfrom aea.cli.utils.constants import AUTHOR_KEY\nfrom aea.cli.utils.context import Context\nfrom aea.cli.utils.decorators import clean_after\nfrom aea.cli.utils.loggers import logger\nfrom aea.configurations.base import AgentConfig, PublicId, dependencies_from_json\nfrom aea.configurations.constants import (\n    CONNECTIONS,\n    CONTRACTS,\n    DEFAULT_AEA_CONFIG_FILE,\n    DEFAULT_DEPENDENCIES,\n    DEFAULT_LEDGER,\n    DEFAULT_LICENSE,\n    DEFAULT_PROTOCOL,\n    DEFAULT_VERSION,\n    PROTOCOL,\n    PROTOCOLS,\n    SIGNING_PROTOCOL,\n    SKILLS,\n    STATE_UPDATE_PROTOCOL,\n    VENDOR,\n)\nfrom aea.exceptions import enforce\nfrom aea.helpers.base import compute_specifier_from_version\nfrom aea.helpers.io import open_file\n\n\n@click.command()\n@click.argument(\"agent_name\", type=str, required=True)\n@click.option(\n    \"--author\",\n    type=str,\n    required=False,\n    help=\"Add the author to run `init` before `create` execution.\",\n)\n@registry_flag(\n    help_local=\"For fetching agent from local folder.\",\n    help_remote=\"For fetching agent from remote registry.\",\n)\n@click.option(\"--empty\", is_flag=True, help=\"Not adding default dependencies.\")\n@click.pass_context\ndef create(\n    click_context: click.core.Context,\n    agent_name: str,\n    author: str,\n    local: bool,\n    remote: bool,\n    empty: bool,\n) -> None:\n    \"\"\"Create a new agent.\"\"\"\n    ctx = cast(Context, click_context.obj)\n    create_aea(ctx, agent_name, local, remote, author=author, empty=empty)\n\n\n@clean_after\ndef create_aea(\n    ctx: Context,\n    agent_name: str,\n    local: bool,\n    remote: bool = False,  # for backwards compatibility\n    author: Optional[str] = None,\n    empty: bool = False,\n) -> None:\n    \"\"\"\n    Create AEA project.\n\n    :param ctx: Context object.\n    :param agent_name: agent name.\n    :param local: boolean flag for local registry usage.\n    :param remote: boolean flag for remote registry usage.\n    :param author: optional author name (valid with local=True and remote=False only).\n    :param empty: optional boolean flag for skip adding default dependencies.\n\n    :raises ClickException: if an error occurred.\n    \"\"\"\n    enforce(\n        not (local and remote), \"'local' and 'remote' options are mutually exclusive.\"\n    )\n    if not local and not remote:\n        try:\n            ctx.registry_path\n        except ValueError as e:\n            click.echo(f\"{e}\\nTrying remote registry (`--remote`).\")\n            remote = True\n    is_mixed = not local and not remote\n    is_local = local and not remote\n    ctx.set_config(\"is_local\", is_local)\n    ctx.set_config(\"is_mixed\", is_mixed)\n\n    try:\n        _check_is_parent_folders_are_aea_projects_recursively()\n    except Exception:\n        raise click.ClickException(\n            \"The current folder is already an AEA project. Please move to the parent folder.\"\n        )\n\n    if author is not None:\n        if is_local:\n            do_init(author, False, False, False)  # pragma: nocover\n        else:\n            raise click.ClickException(\n                \"Author is not set up. Please use 'aea init' to initialize.\"\n            )\n\n    config = get_or_create_cli_config()\n    set_author = config.get(AUTHOR_KEY, None)\n    if set_author is None:\n        raise click.ClickException(\n            \"The AEA configurations are not initialized. Uses `aea init` before continuing or provide optional argument `--author`.\"\n        )\n\n    if Path(agent_name).exists():\n        raise click.ClickException(\"Directory already exist. Aborting...\")\n\n    click.echo(\"Initializing AEA project '{}'\".format(agent_name))\n    click.echo(\"Creating project directory './{}'\".format(agent_name))\n    path = Path(agent_name)\n    ctx.clean_paths.append(str(path))\n\n    # we have already checked that the directory does not exist.\n    path.mkdir(exist_ok=False)\n\n    try:\n        # set up packages directories.\n        _setup_package_folder(Path(agent_name, PROTOCOLS))\n        _setup_package_folder(Path(agent_name, CONTRACTS))\n        _setup_package_folder(Path(agent_name, CONNECTIONS))\n        _setup_package_folder(Path(agent_name, SKILLS))\n\n        # set up a vendor directory\n        Path(agent_name, VENDOR).mkdir(exist_ok=False)\n        Path(agent_name, VENDOR, \"__init__.py\").touch(exist_ok=False)\n\n        # create a config file inside it\n        click.echo(\"Creating config file {}\".format(DEFAULT_AEA_CONFIG_FILE))\n        agent_config = _create_agent_config(ctx, agent_name, set_author)\n\n        # next commands must be done from the agent's directory -> overwrite ctx.cwd\n        ctx.agent_config = agent_config\n        ctx.cwd = agent_config.agent_name\n\n        if not empty:\n            click.echo(\"Adding default packages ...\")\n            add_item(ctx, PROTOCOL, PublicId.from_str(DEFAULT_PROTOCOL))\n            add_item(ctx, PROTOCOL, PublicId.from_str(SIGNING_PROTOCOL))\n            add_item(ctx, PROTOCOL, PublicId.from_str(STATE_UPDATE_PROTOCOL))\n\n    except Exception as e:\n        raise click.ClickException(str(e))\n\n\ndef _create_agent_config(ctx: Context, agent_name: str, set_author: str) -> AgentConfig:\n    \"\"\"\n    Create agent config.\n\n    :param ctx: context object.\n    :param agent_name: agent name.\n    :param set_author: author name to set.\n\n    :return: AgentConfig object.\n    \"\"\"\n    agent_config = AgentConfig(\n        agent_name=agent_name,\n        aea_version=compute_specifier_from_version(get_current_aea_version()),\n        author=set_author,\n        version=DEFAULT_VERSION,\n        license_=DEFAULT_LICENSE,\n        description=\"\",\n        default_ledger=DEFAULT_LEDGER,\n        required_ledgers=[DEFAULT_LEDGER],\n        default_connection=None,\n        dependencies=dependencies_from_json(DEFAULT_DEPENDENCIES),\n    )\n\n    with open_file(\n        os.path.join(agent_name, DEFAULT_AEA_CONFIG_FILE), \"w\"\n    ) as config_file:\n        ctx.agent_loader.dump(agent_config, config_file)\n\n    return agent_config\n\n\ndef _check_is_parent_folders_are_aea_projects_recursively() -> None:\n    \"\"\"Look for 'aea-config.yaml' in parent folders recursively up to the user home directory.\n\n    :raises ValueError: if a parent folder has a file named 'aea-config.yaml'.\n    \"\"\"\n    current = Path(\".\").resolve()\n    root = Path(\"/\").resolve()\n    home = current.home()\n    while current not in (home, root):\n        files = set(map(lambda x: x.name, current.iterdir()))\n        if DEFAULT_AEA_CONFIG_FILE in files:\n            raise ValueError(\n                \"Folder {} has file named {}\".format(current, DEFAULT_AEA_CONFIG_FILE)\n            )\n        current = current.parent.resolve()\n\n\ndef _setup_package_folder(path: Path) -> None:\n    \"\"\"Set a package folder up.\"\"\"\n    path.mkdir(exist_ok=False)\n    init_module = path / \"__init__.py\"\n    logger.debug(\"Creating {}\".format(init_module))\n    Path(init_module).touch(exist_ok=False)\n"
  },
  {
    "path": "aea/cli/delete.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Implementation of the 'aea delete' subcommand.\"\"\"\n\nimport os\nimport shutil\nfrom typing import cast\n\nimport click\n\nfrom aea.cli.utils.click_utils import AgentDirectory\nfrom aea.cli.utils.context import Context\n\n\n@click.command()\n@click.argument(\n    \"agent_name\",\n    type=AgentDirectory(),\n    required=True,\n)\n@click.pass_context\ndef delete(click_context: click.Context, agent_name: str) -> None:\n    \"\"\"Delete an agent.\"\"\"\n    click.echo(\"Deleting AEA project directory './{}'...\".format(agent_name))\n    ctx = cast(Context, click_context.obj)\n    delete_aea(ctx, agent_name)\n\n\ndef delete_aea(ctx: Context, agent_name: str) -> None:\n    \"\"\"\n    Delete agent's directory.\n\n    :param ctx: click context\n    :param agent_name: name of the agent (equal to folder name).\n\n    :raises ClickException: if OSError occurred.\n    \"\"\"\n    agent_path = os.path.join(ctx.cwd, agent_name)\n    try:\n        shutil.rmtree(agent_path, ignore_errors=False)\n    except OSError:\n        raise click.ClickException(\n            \"An error occurred while deleting the agent directory. Aborting...\"\n        )\n"
  },
  {
    "path": "aea/cli/eject.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Implementation of the 'aea eject' subcommand.\"\"\"\nimport shutil\nfrom pathlib import Path\nfrom typing import cast\n\nimport click\nfrom packaging.version import Version\n\nimport aea\nfrom aea.cli.remove import ItemRemoveHelper\nfrom aea.cli.utils.click_utils import PublicIdParameter\nfrom aea.cli.utils.config import (\n    load_item_config,\n    set_cli_author,\n    try_to_load_agent_config,\n    update_item_config,\n)\nfrom aea.cli.utils.context import Context\nfrom aea.cli.utils.decorators import check_aea_project, clean_after, pass_ctx\nfrom aea.cli.utils.package_utils import (\n    copy_package_directory,\n    create_symlink_packages_to_vendor,\n    create_symlink_vendor_to_local,\n    fingerprint_all,\n    get_package_path,\n    is_item_present,\n    replace_all_import_statements,\n    update_item_public_id_in_init,\n    update_references,\n)\nfrom aea.configurations.base import (\n    ComponentId,\n    ComponentType,\n    PackageId,\n    PackageType,\n    PublicId,\n)\nfrom aea.configurations.constants import (\n    CONNECTION,\n    CONTRACT,\n    DEFAULT_VERSION,\n    PROTOCOL,\n    SKILL,\n)\nfrom aea.configurations.utils import get_latest_component_id_from_prefix\nfrom aea.helpers.base import (\n    compute_specifier_from_version,\n    find_topological_order,\n    reachable_nodes,\n)\n\n\n@click.group()\n@click.option(\n    \"--with-symlinks\",\n    is_flag=True,\n    help=\"Add symlinks from vendor to non-vendor and packages to vendor folders.\",\n)\n@click.option(\n    \"-q\",\n    \"--quiet\",\n    \"quiet\",\n    is_flag=True,\n    required=False,\n    default=False,\n    help=\"If provided, the command will not ask the user for confirmation.\",\n)\n@click.pass_context\n@check_aea_project\ndef eject(click_context: click.core.Context, quiet: bool, with_symlinks: bool) -> None:\n    \"\"\"Eject a vendor package of the agent.\"\"\"\n    click_context.obj.set_config(\"quiet\", quiet)\n    click_context.obj.set_config(\"with_symlinks\", with_symlinks)\n    set_cli_author(click_context)\n\n\n@eject.command()\n@click.argument(\"public_id\", type=PublicIdParameter(), required=True)\n@pass_ctx\ndef connection(ctx: Context, public_id: PublicId) -> None:\n    \"\"\"Eject a vendor connection.\"\"\"\n    quiet = ctx.config.get(\"quiet\")\n    with_symlinks = ctx.config.get(\"with_symlinks\")\n    _eject_item(ctx, CONNECTION, public_id, quiet=quiet, with_symlinks=with_symlinks)\n\n\n@eject.command()\n@click.argument(\"public_id\", type=PublicIdParameter(), required=True)\n@pass_ctx\ndef contract(ctx: Context, public_id: PublicId) -> None:\n    \"\"\"Eject a vendor contract.\"\"\"\n    quiet = ctx.config.get(\"quiet\")\n    with_symlinks = ctx.config.get(\"with_symlinks\")\n    _eject_item(ctx, CONTRACT, public_id, quiet=quiet, with_symlinks=with_symlinks)\n\n\n@eject.command()\n@click.argument(\"public_id\", type=PublicIdParameter(), required=True)\n@pass_ctx\ndef protocol(ctx: Context, public_id: PublicId) -> None:\n    \"\"\"Eject a vendor protocol.\"\"\"\n    quiet = ctx.config.get(\"quiet\")\n    with_symlinks = ctx.config.get(\"with_symlinks\")\n    _eject_item(ctx, PROTOCOL, public_id, quiet=quiet, with_symlinks=with_symlinks)\n\n\n@eject.command()\n@click.argument(\"public_id\", type=PublicIdParameter(), required=True)\n@pass_ctx\ndef skill(ctx: Context, public_id: PublicId) -> None:\n    \"\"\"Eject a vendor skill.\"\"\"\n    quiet = ctx.config.get(\"quiet\")\n    with_symlinks = ctx.config.get(\"with_symlinks\")\n    _eject_item(ctx, SKILL, public_id, quiet=quiet, with_symlinks=with_symlinks)\n\n\n@clean_after\ndef _eject_item(\n    ctx: Context,\n    item_type: str,\n    public_id: PublicId,\n    quiet: bool = True,\n    with_symlinks: bool = False,\n) -> None:\n    \"\"\"\n    Eject item from installed (vendor) to custom folder.\n\n    :param ctx: context object.\n    :param item_type: item type.\n    :param public_id: item public ID.\n    :param quiet: if false, the function will ask the user in case of recursive eject.\n    :param with_symlinks: if eject should create symlinks.\n\n    :raises ClickException: if item is absent at source path or present at destination path.\n    \"\"\"\n    # we know cli_author is set because of the above checks.\n    cli_author: str = cast(str, ctx.config.get(\"cli_author\"))\n    item_type_plural = item_type + \"s\"\n    if not is_item_present(\n        ctx.cwd,\n        ctx.agent_config,\n        item_type,\n        public_id,\n        is_vendor=True,\n        with_version=True,\n    ):  # pragma: no cover\n        raise click.ClickException(\n            f\"{item_type.title()} {public_id} not found in agent's vendor items.\"\n        )\n    src = get_package_path(ctx.cwd, item_type, public_id)\n    dst = get_package_path(ctx.cwd, item_type, public_id, is_vendor=False)\n    if is_item_present(\n        ctx.cwd, ctx.agent_config, item_type, public_id, is_vendor=False\n    ):  # pragma: no cover\n        raise click.ClickException(\n            f\"{item_type.title()} {public_id} is already a non-vendor package.\"\n        )\n    configuration = load_item_config(item_type, Path(src))\n\n    if public_id.package_version.is_latest:\n        # get 'concrete' public id, in case it is 'latest'\n        component_prefix = ComponentType(item_type), public_id.author, public_id.name\n        component_id = get_latest_component_id_from_prefix(\n            ctx.agent_config, component_prefix\n        )\n        # component id is necessarily found, due to the checks above.\n        public_id = cast(ComponentId, component_id).public_id\n\n    package_id = PackageId(PackageType(item_type), public_id)\n\n    click.echo(\n        f\"Ejecting item {package_id.package_type.value} {str(package_id.public_id)}\"\n    )\n\n    # first, eject all the vendor packages that depend on this\n    item_remover = ItemRemoveHelper(ctx, ignore_non_vendor=True)\n    reverse_dependencies = (\n        item_remover.get_agent_dependencies_with_reverse_dependencies()\n    )\n    reverse_reachable_dependencies = reachable_nodes(reverse_dependencies, {package_id})\n    # the reversed topological order of a graph\n    # is the topological order of the reverse graph.\n    eject_order = list(reversed(find_topological_order(reverse_reachable_dependencies)))\n    eject_order.remove(package_id)\n    if len(eject_order) > 0 and not quiet:\n        click.echo(f\"The following vendor packages will be ejected: {eject_order}\")\n        answer = click.confirm(\"Do you want to proceed?\")\n        if not answer:\n            click.echo(\"Aborted.\")\n            return\n\n    for dependency_package_id in eject_order:\n        # 'dependency_package_id' depends on 'package_id',\n        # so we need to eject it first\n        _eject_item(\n            ctx,\n            dependency_package_id.package_type.value,\n            dependency_package_id.public_id,\n            quiet=True,\n        )\n\n    # copy the vendor package into the non-vendor packages\n    ctx.clean_paths.append(dst)\n    copy_package_directory(Path(src), dst)\n\n    new_public_id = PublicId(cli_author, public_id.name, DEFAULT_VERSION)\n    current_version = Version(aea.__version__)\n    new_aea_range = (\n        configuration.aea_version\n        if configuration.aea_version_specifiers.contains(current_version)\n        else compute_specifier_from_version(current_version)\n    )\n    update_item_config(\n        item_type,\n        Path(dst),\n        author=new_public_id.author,\n        version=new_public_id.version,\n        aea_version=new_aea_range,\n    )\n    update_item_public_id_in_init(item_type, Path(dst), new_public_id)\n    shutil.rmtree(src)\n\n    # update references in all the other packages\n    component_type = ComponentType(item_type_plural[:-1])\n    old_component_id = ComponentId(component_type, public_id)\n    new_component_id = ComponentId(component_type, new_public_id)\n    update_references(ctx, {old_component_id: new_component_id})\n\n    # need to reload agent configuration with the updated references\n    try_to_load_agent_config(ctx)\n\n    # replace import statements in all the non-vendor packages\n    replace_all_import_statements(\n        Path(ctx.cwd), ComponentType(item_type), public_id, new_public_id\n    )\n\n    # fingerprint all (non-vendor) packages\n    fingerprint_all(ctx)\n\n    if with_symlinks:\n        click.echo(\n            \"Adding symlinks from vendor to non-vendor and packages to vendor folders.\"\n        )\n        create_symlink_vendor_to_local(ctx, item_type, new_public_id)\n        create_symlink_packages_to_vendor(ctx)\n\n    click.echo(\n        f\"Successfully ejected {item_type} {public_id} to {dst} as {new_public_id}.\"\n    )\n"
  },
  {
    "path": "aea/cli/fetch.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Implementation of the 'aea fetch' subcommand.\"\"\"\nimport os\nfrom pathlib import Path\nfrom shutil import copytree as copy_tree\nfrom typing import Optional, cast\n\nimport click\n\nfrom aea.cli.add import add_item\nfrom aea.cli.registry.fetch import fetch_agent\nfrom aea.cli.utils.click_utils import PublicIdParameter, registry_flag\nfrom aea.cli.utils.config import try_to_load_agent_config\nfrom aea.cli.utils.context import Context\nfrom aea.cli.utils.decorators import clean_after\nfrom aea.cli.utils.loggers import logger\nfrom aea.cli.utils.package_utils import try_get_item_source_path\nfrom aea.configurations.base import PublicId\nfrom aea.configurations.constants import (\n    AGENTS,\n    CONNECTION,\n    CONTRACT,\n    DEFAULT_AEA_CONFIG_FILE,\n    PROTOCOL,\n    SKILL,\n)\nfrom aea.exceptions import enforce\nfrom aea.helpers.io import open_file\n\n\n@click.command(name=\"fetch\")\n@registry_flag(\n    help_local=\"For fetching agent from local folder.\",\n    help_remote=\"For fetching agent from remote registry.\",\n)\n@click.option(\n    \"--alias\",\n    type=str,\n    required=False,\n    help=\"Provide a local alias for the agent.\",\n)\n@click.argument(\"public-id\", type=PublicIdParameter(), required=True)\n@click.pass_context\ndef fetch(\n    click_context: click.Context,\n    public_id: PublicId,\n    alias: str,\n    local: bool,\n    remote: bool,\n) -> None:\n    \"\"\"Fetch an agent from the registry.\"\"\"\n    ctx = cast(Context, click_context.obj)\n    do_fetch(ctx, public_id, local, remote, alias)\n\n\ndef do_fetch(\n    ctx: Context,\n    public_id: PublicId,\n    local: bool,\n    remote: bool,\n    alias: Optional[str] = None,\n    target_dir: Optional[str] = None,\n) -> None:\n    \"\"\"\n    Run the Fetch command.\n\n    :param ctx: the CLI context.\n    :param public_id: the public id.\n    :param local: whether to fetch from local\n    :param remote: whether to fetch from remote\n    :param alias: the agent alias.\n    :param target_dir: the target directory, in case fetching locally.\n    \"\"\"\n    enforce(\n        not (local and remote), \"'local' and 'remote' options are mutually exclusive.\"\n    )\n    if not local and not remote:\n        try:\n            ctx.registry_path\n        except ValueError as e:\n            click.echo(f\"{e}\\nTrying remote registry (`--remote`).\")\n            remote = True\n    is_mixed = not local and not remote\n    ctx.set_config(\"is_local\", local and not remote)\n    ctx.set_config(\"is_mixed\", is_mixed)\n    if remote:\n        fetch_agent(ctx, public_id, alias=alias, target_dir=target_dir)\n    elif local:\n        fetch_agent_locally(ctx, public_id, alias=alias, target_dir=target_dir)\n    else:\n        fetch_mixed(ctx, public_id, alias=alias, target_dir=target_dir)\n\n\ndef _is_version_correct(ctx: Context, agent_public_id: PublicId) -> bool:\n    \"\"\"\n    Compare agent version to the one in public ID.\n\n    :param ctx: Context object.\n    :param agent_public_id: public ID of an agent.\n\n    :return: bool is version correct.\n    \"\"\"\n    return ctx.agent_config.public_id.same_prefix(agent_public_id) and (\n        agent_public_id.package_version.is_latest\n        or ctx.agent_config.version == agent_public_id.version\n    )\n\n\n@clean_after\ndef fetch_agent_locally(\n    ctx: Context,\n    public_id: PublicId,\n    alias: Optional[str] = None,\n    target_dir: Optional[str] = None,\n) -> None:\n    \"\"\"\n    Fetch Agent from local packages.\n\n    :param ctx: a Context object.\n    :param public_id: public ID of agent to be fetched.\n    :param alias: an optional alias.\n    :param target_dir: the target directory to which the agent is fetched.\n    \"\"\"\n    try:\n        registry_path = ctx.registry_path\n    except ValueError as e:\n        raise click.ClickException(str(e))\n\n    source_path = try_get_item_source_path(\n        registry_path, public_id.author, AGENTS, public_id.name\n    )\n    enforce(\n        ctx.config.get(\"is_local\") is True or ctx.config.get(\"is_mixed\") is True,\n        \"Please use `ctx.set_config('is_local', True)` or `ctx.set_config('is_mixed', True)` to fetch agent and all components locally.\",\n    )\n    try_to_load_agent_config(ctx, agent_src_path=source_path)\n    if not _is_version_correct(ctx, public_id):\n        raise click.ClickException(\n            \"Wrong agent version in public ID: specified {}, found {}.\".format(\n                public_id.version, ctx.agent_config.version\n            )\n        )\n\n    folder_name = target_dir or (public_id.name if alias is None else alias)\n    target_path = os.path.join(ctx.cwd, folder_name)\n    if os.path.exists(target_path):\n        path = Path(target_path)\n        raise click.ClickException(\n            f'Item \"{path.name}\" already exists in target folder \"{path.parent}\".'\n        )\n    if target_dir is not None:\n        os.makedirs(target_path)  # pragma: nocover\n\n    ctx.clean_paths.append(target_path)\n    copy_tree(source_path, target_path, dirs_exist_ok=True)  # type: ignore\n\n    ctx.cwd = target_path\n    try_to_load_agent_config(ctx)\n\n    if alias is not None:\n        ctx.agent_config.agent_name = alias\n        ctx.agent_loader.dump(\n            ctx.agent_config,\n            open_file(os.path.join(ctx.cwd, DEFAULT_AEA_CONFIG_FILE), \"w\"),\n        )\n\n    _fetch_agent_deps(ctx)\n    click.echo(\"Agent {} successfully fetched.\".format(public_id.name))\n\n\ndef _fetch_agent_deps(ctx: Context) -> None:\n    \"\"\"\n    Fetch agent dependencies.\n\n    :param ctx: context object.\n    \"\"\"\n    for item_type in (PROTOCOL, CONTRACT, CONNECTION, SKILL):\n        item_type_plural = \"{}s\".format(item_type)\n        required_items = getattr(ctx.agent_config, item_type_plural)\n        for item_id in required_items:\n            add_item(ctx, item_type, item_id)\n\n\ndef fetch_mixed(\n    ctx: Context,\n    public_id: PublicId,\n    alias: Optional[str] = None,\n    target_dir: Optional[str] = None,\n) -> None:\n    \"\"\"\n    Fetch an agent in mixed mode.\n\n    :param ctx: the Context.\n    :param public_id: the public id.\n    :param alias: the alias to the agent.\n    :param target_dir: the target directory.\n    \"\"\"\n    try:\n        fetch_agent_locally(ctx, public_id, alias=alias, target_dir=target_dir)\n    except click.ClickException as e:\n        logger.debug(\n            f\"Fetch from local registry failed (reason={str(e)}), trying remote registry...\"\n        )\n        fetch_agent(ctx, public_id, alias=alias, target_dir=target_dir)\n"
  },
  {
    "path": "aea/cli/fingerprint.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Implementation of the 'aea add' subcommand.\"\"\"\nimport os\nfrom pathlib import Path\nfrom typing import Dict, Union, cast\n\nimport click\n\nfrom aea.cli.utils.click_utils import PublicIdParameter\nfrom aea.cli.utils.context import Context\nfrom aea.cli.utils.decorators import check_aea_project, pass_ctx\nfrom aea.configurations.base import (\n    PublicId,\n    _compute_fingerprint,\n    _get_default_configuration_file_name_from_type,\n)\nfrom aea.configurations.constants import (  # noqa: F401 # pylint: disable=unused-import\n    CONFIG_FILE_TO_PACKAGE_TYPE,\n    CONNECTION,\n    CONTRACT,\n    DEFAULT_IGNORE_DIRS_AGENT_FINGERPRINT,\n    PROTOCOL,\n    SKILL,\n)\nfrom aea.configurations.data_types import PackageType\nfrom aea.configurations.loader import ConfigLoader\nfrom aea.helpers.io import open_file\n\n\n@click.group(invoke_without_command=True)\n@click.pass_context\ndef fingerprint(\n    click_context: click.core.Context,\n) -> None:\n    \"\"\"Fingerprint a non-vendor package of the agent.\"\"\"\n    if click_context.invoked_subcommand is None:\n        fingerprint_agent(click_context)\n\n\n@fingerprint.command()\n@click.argument(\"connection_public_id\", type=PublicIdParameter(), required=True)\n@pass_ctx\ndef connection(ctx: Context, connection_public_id: PublicId) -> None:\n    \"\"\"Fingerprint a connection and add the fingerprints to the configuration file.\"\"\"\n    fingerprint_item(ctx, CONNECTION, connection_public_id)\n\n\n@fingerprint.command()\n@click.argument(\"contract_public_id\", type=PublicIdParameter(), required=True)\n@pass_ctx\ndef contract(ctx: Context, contract_public_id: PublicId) -> None:\n    \"\"\"Fingerprint a contract and add the fingerprints to the configuration file.\"\"\"\n    fingerprint_item(ctx, CONTRACT, contract_public_id)\n\n\n@fingerprint.command()\n@click.argument(\"protocol_public_id\", type=PublicIdParameter(), required=True)\n@pass_ctx\ndef protocol(ctx: Context, protocol_public_id: PublicId) -> None:\n    \"\"\"Fingerprint a protocol and add the fingerprints to the configuration file..\"\"\"\n    fingerprint_item(ctx, PROTOCOL, protocol_public_id)\n\n\n@fingerprint.command()\n@click.argument(\"skill_public_id\", type=PublicIdParameter(), required=True)\n@pass_ctx\ndef skill(ctx: Context, skill_public_id: PublicId) -> None:\n    \"\"\"Fingerprint a skill and add the fingerprints to the configuration file.\"\"\"\n    fingerprint_item(ctx, SKILL, skill_public_id)\n\n\n@fingerprint.command()\n@click.argument(\"path\", type=str, required=True)\n@pass_ctx\ndef by_path(ctx: Context, path: str) -> None:\n    \"\"\"Fingerprint a package by its path.\"\"\"\n    try:\n        click.echo(\"Fingerprinting component in '{}' ...\".format(path))\n        full_path = Path(ctx.cwd) / Path(path)\n        fingerprint_package_by_path(full_path)\n    except Exception as e:\n        raise click.ClickException(str(e))\n\n\ndef fingerprint_item(ctx: Context, item_type: str, item_public_id: PublicId) -> None:\n    \"\"\"\n    Fingerprint components of an item.\n\n    :param ctx: the context.\n    :param item_type: the item type.\n    :param item_public_id: the item public id.\n    \"\"\"\n    item_type_plural = item_type + \"s\"\n\n    click.echo(\n        \"Fingerprinting {} components of '{}' ...\".format(item_type, item_public_id)\n    )\n\n    # create fingerprints\n    package_dir = Path(ctx.cwd, item_type_plural, item_public_id.name)\n    try:\n        fingerprint_package(package_dir, item_type)\n    except Exception as e:\n        raise click.ClickException(str(e))\n\n\ndef fingerprint_package_by_path(package_dir: Path) -> None:\n    \"\"\"\n    Fingerprint package placed in package_dir.\n\n    :param package_dir: directory of the package\n    \"\"\"\n    package_type = determine_package_type_for_directory(package_dir)\n    fingerprint_package(package_dir, package_type)\n\n\ndef determine_package_type_for_directory(package_dir: Path) -> PackageType:\n    \"\"\"\n    Find package type for the package directory by checking config file names.\n\n    :param package_dir: package dir to determine package type:\n\n    :return: PackageType\n    \"\"\"\n    config_files = list(\n        set(os.listdir(str(package_dir))).intersection(\n            set(CONFIG_FILE_TO_PACKAGE_TYPE.keys())\n        )\n    )\n\n    if len(config_files) > 1:\n        raise ValueError(\n            f\"Too many config files in the directory, only one has to present!: {', '.join(config_files)}\"\n        )\n    if len(config_files) == 0:\n        raise ValueError(\n            f\"No package config file found in `{str(package_dir)}`. Incorrect directory?\"\n        )\n\n    config_file = config_files[0]\n    package_type = PackageType(CONFIG_FILE_TO_PACKAGE_TYPE[config_file])\n\n    return package_type\n\n\ndef fingerprint_package(\n    package_dir: Path, package_type: Union[str, PackageType]\n) -> None:\n    \"\"\"\n    Fingerprint components of an item.\n\n    :param package_dir: the package directory.\n    :param package_type: the package type.\n    \"\"\"\n    package_type = PackageType(package_type)\n    item_type = str(package_type)\n    default_config_file_name = _get_default_configuration_file_name_from_type(item_type)\n    config_loader = ConfigLoader.from_configuration_type(item_type)\n    config_file_path = Path(package_dir, default_config_file_name)\n    config = config_loader.load(open_file(config_file_path))\n\n    if not package_dir.exists():\n        # we only permit non-vendorized packages to be fingerprinted\n        raise ValueError(\"Package not found at path {}\".format(package_dir))\n\n    fingerprints_dict = _compute_fingerprint(\n        package_dir, ignore_patterns=config.fingerprint_ignore_patterns\n    )  # type: Dict[str, str]\n\n    # Load item specification yaml file and add fingerprints\n    config.fingerprint = fingerprints_dict\n    config_loader.dump(config, open_file(config_file_path, \"w\"))\n\n\n@check_aea_project(check_finger_prints=False)  # pylint: disable=no-value-for-parameter\ndef fingerprint_agent(click_context: click.Context) -> None:\n    \"\"\"Do a fingerprint for an agent.\"\"\"\n    ctx = cast(Context, click_context.obj)\n    click.echo(\n        f\"Fingerprinting files in agent project '{ctx.agent_config.agent_name}'...\"\n    )\n    fingerprints_dict = _compute_fingerprint(\n        Path(ctx.cwd),\n        ignore_patterns=ctx.agent_config.fingerprint_ignore_patterns,\n        ignore_directories=DEFAULT_IGNORE_DIRS_AGENT_FINGERPRINT,\n    )  # type: Dict[str, str]\n    ctx.agent_config.fingerprint = fingerprints_dict\n    ctx.dump_agent_config()\n    click.echo(f\"Fingerprint for agent `{ctx.agent_config.name}` calculated!\")\n"
  },
  {
    "path": "aea/cli/freeze.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Implementation of the 'aea delete' subcommand.\"\"\"\n\nfrom typing import List, cast\n\nimport click\n\nfrom aea.cli.utils.context import Context\nfrom aea.cli.utils.decorators import check_aea_project\n\n\n@click.command()\n@click.pass_context\n@check_aea_project\ndef freeze(click_context: click.Context) -> None:\n    \"\"\"Get the dependencies of the agent.\"\"\"\n    deps = _get_deps(click_context)\n    for dependency in deps:\n        click.echo(dependency)\n\n\ndef _get_deps(click_context: click.core.Context) -> List[str]:\n    \"\"\"\n    Get dependencies list.\n\n    :param click_context: click context object.\n\n    :return: list of str dependencies.\n    \"\"\"\n    ctx = cast(Context, click_context.obj)\n    deps = []\n    for dependency_name, dependency_data in sorted(\n        ctx.get_dependencies().items(), key=lambda x: x[0]\n    ):\n        deps.append(dependency_name + dependency_data.version)\n    return deps\n"
  },
  {
    "path": "aea/cli/generate.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Implementation of the 'aea generate' subcommand.\"\"\"\n\nimport os\nfrom typing import Set\n\nimport click\nimport yaml\n\nfrom aea.cli.fingerprint import fingerprint_item\nfrom aea.cli.utils.context import Context\nfrom aea.cli.utils.decorators import check_aea_project, clean_after, pass_ctx\nfrom aea.cli.utils.loggers import logger\nfrom aea.configurations.base import (\n    ProtocolSpecification,\n    ProtocolSpecificationParseError,\n    PublicId,\n)\nfrom aea.configurations.constants import (\n    DEFAULT_AEA_CONFIG_FILE,\n    PROTOCOL,\n    PROTOCOL_LANGUAGE_PYTHON,\n    SUPPORTED_PROTOCOL_LANGUAGES,\n)\nfrom aea.helpers.io import open_file\nfrom aea.protocols.generator.base import ProtocolGenerator\n\n\n@click.group()\n@click.pass_context\n@check_aea_project\ndef generate(\n    click_context: click.core.Context,  # pylint: disable=unused-argument\n) -> None:\n    \"\"\"Generate a package for the agent.\"\"\"\n\n\n@generate.command()\n@click.argument(\"protocol_specification_path\", type=str, required=True)\n@click.option(\n    \"--l\",\n    \"language\",\n    type=click.Choice(SUPPORTED_PROTOCOL_LANGUAGES),\n    required=False,\n    default=PROTOCOL_LANGUAGE_PYTHON,\n    help=\"Specify the language in which to generate the protocol package.\",\n)\n@pass_ctx\ndef protocol(ctx: Context, protocol_specification_path: str, language: str) -> None:\n    \"\"\"Generate a protocol based on a specification and add it to the configuration file and agent.\"\"\"\n    ctx.set_config(\"language\", language)\n    _generate_protocol(ctx, protocol_specification_path)\n\n\n@clean_after\ndef _generate_protocol(ctx: Context, protocol_specification_path: str) -> None:\n    \"\"\"Generate a protocol based on a specification and add it to the configuration file and agent.\"\"\"\n    protocol_plural = PROTOCOL + \"s\"\n\n    # Create protocol generator (load, validate,\n    # extract fields from protocol specification yaml file)\n    try:\n        output_path = os.path.join(ctx.cwd, protocol_plural)\n        protocol_generator = ProtocolGenerator(protocol_specification_path, output_path)\n    except FileNotFoundError as e:\n        raise click.ClickException(  # pragma: no cover\n            \"Protocol is NOT generated. The following error happened while generating the protocol:\\n\"\n            + str(e)\n        )\n    except yaml.YAMLError as e:\n        raise click.ClickException(  # pragma: no cover\n            \"Protocol is NOT generated. The following error happened while generating the protocol:\\n\"\n            + \"Yaml error in the protocol specification file:\"\n            + str(e)\n        )\n    except ProtocolSpecificationParseError as e:\n        raise click.ClickException(  # pragma: no cover\n            \"Protocol is NOT generated. The following error happened while generating the protocol:\\n\"\n            + \"Error while parsing the protocol specification: \"\n            + str(e)\n        )\n    except Exception as e:  # pragma: no cover\n        raise click.ClickException(  # pragma: no cover\n            \"Protocol is NOT generated. The following error happened while generating the protocol:\\n\"\n            + str(e)\n        )\n\n    # helpers\n    language = ctx.config.get(\"language\")\n    existing_protocol_ids_list = getattr(ctx.agent_config, \"{}s\".format(PROTOCOL))\n    existing_protocol_name_list = [\n        public_id.name for public_id in existing_protocol_ids_list\n    ]\n    protocol_spec = protocol_generator.protocol_specification\n    protocol_directory_path = os.path.join(ctx.cwd, protocol_plural, protocol_spec.name)\n\n    # Check if a protocol with the same name exists in the agent config\n    if protocol_spec.name in existing_protocol_name_list:\n        raise click.ClickException(\n            \"Protocol is NOT generated. The following error happened while generating the protocol:\\n\"\n            + f\"A {PROTOCOL} with name '{protocol_spec.name}' already exists. Aborting...\"\n        )\n\n    # Check if a directory with the same name as the protocol's exists\n    # in the protocols directory of the agent's directory\n    if os.path.exists(protocol_directory_path):\n        raise click.ClickException(\n            \"Protocol is NOT generated. The following error happened while generating the protocol:\\n\"\n            + f\"A directory with name '{protocol_spec.name}' already exists. Aborting...\"\n        )\n\n    ctx.clean_paths.append(protocol_directory_path)\n    agent_name = ctx.agent_config.agent_name\n    click.echo(\n        \"Generating {} '{}' and adding it to the agent '{}'...\".format(\n            PROTOCOL, protocol_spec.name, agent_name\n        )\n    )\n\n    if language == PROTOCOL_LANGUAGE_PYTHON:\n        _generate_full_mode(\n            ctx, protocol_generator, protocol_spec, existing_protocol_ids_list, language\n        )\n    else:\n        _generate_protobuf_mode(ctx, protocol_generator, language)\n\n\n@clean_after\ndef _generate_full_mode(\n    ctx: Context,\n    protocol_generator: ProtocolGenerator,\n    protocol_spec: ProtocolSpecification,\n    existing_id_list: Set[PublicId],\n    language: str,\n) -> None:\n    \"\"\"Generate a protocol in 'full' mode, and add it to the configuration file and agent.\"\"\"\n    try:\n        warning_message = protocol_generator.generate(\n            protobuf_only=False, language=language\n        )\n        if warning_message is not None:\n            click.echo(warning_message)\n\n        # Add the item to the configurations\n        logger.debug(\n            \"Registering the {} into {}\".format(PROTOCOL, DEFAULT_AEA_CONFIG_FILE)\n        )\n        existing_id_list.add(\n            PublicId(protocol_spec.author, protocol_spec.name, protocol_spec.version)\n        )\n        ctx.agent_loader.dump(\n            ctx.agent_config,\n            open_file(os.path.join(ctx.cwd, DEFAULT_AEA_CONFIG_FILE), \"w\"),\n        )\n    except FileExistsError:\n        raise click.ClickException(  # pragma: no cover\n            \"A {} with this name already exists. Please choose a different name and try again.\".format(\n                PROTOCOL\n            )\n        )\n    except Exception as e:\n        raise click.ClickException(\n            \"Protocol is NOT generated. The following error happened while generating the protocol:\\n\"\n            + str(e)\n        )\n    fingerprint_item(ctx, PROTOCOL, protocol_spec.public_id)\n\n\n@clean_after\ndef _generate_protobuf_mode(\n    ctx: Context,  # pylint: disable=unused-argument\n    protocol_generator: ProtocolGenerator,\n    language: str,\n) -> None:\n    \"\"\"Generate a protocol in 'protobuf' mode, and add it to the configuration file and agent.\"\"\"\n    try:\n        warning_message = protocol_generator.generate(\n            protobuf_only=True, language=language\n        )\n        if warning_message is not None:\n            click.echo(warning_message)\n    except FileExistsError:  # pragma: no cover\n        raise click.ClickException(  # pragma: no cover\n            f\"A {PROTOCOL} with this name already exists. Please choose a different name and try again.\"\n        )\n    except Exception as e:  # pragma: no cover\n        raise click.ClickException(  # pragma: no cover\n            \"Protocol is NOT generated. The following error happened while generating the protocol:\\n\"\n            + str(e)\n        )\n"
  },
  {
    "path": "aea/cli/generate_key.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Implementation of the 'aea generate_key' subcommand.\"\"\"\nfrom pathlib import Path\nfrom typing import Dict, Optional\n\nimport click\n\nfrom aea.cli.add_key import _add_private_key\nfrom aea.cli.utils.click_utils import password_option\nfrom aea.cli.utils.decorators import _check_aea_project\nfrom aea.configurations.constants import PRIVATE_KEY_PATH_SCHEMA\nfrom aea.crypto.helpers import create_private_key\nfrom aea.crypto.registries import crypto_registry\n\n\n@click.command()\n@click.argument(\n    \"type_\",\n    metavar=\"TYPE\",\n    type=click.Choice([*list(crypto_registry.supported_ids), \"all\"]),\n    required=True,\n)\n@click.argument(\n    \"file\",\n    metavar=\"FILE\",\n    type=click.Path(exists=False, file_okay=True, dir_okay=False, readable=True),\n    required=False,\n)\n@password_option(confirmation_prompt=True)\n@click.option(\n    \"--add-key\",\n    is_flag=True,\n    help=\"Add key generated.\",\n)\n@click.option(\n    \"--connection\", is_flag=True, help=\"For adding a private key for connections.\"\n)\n@click.pass_context\ndef generate_key(\n    click_context: click.core.Context,\n    type_: str,\n    file: str,\n    password: Optional[str],\n    add_key: bool = False,\n    connection: bool = False,\n) -> None:\n    \"\"\"Generate a private key and place it in a file.\"\"\"\n    keys_generated = _generate_private_key(type_, file, password)\n    if add_key:\n        _check_aea_project((click_context,))\n        for key_type, key_filename in keys_generated.items():\n            _add_private_key(\n                click_context, key_type, key_filename, password, connection\n            )\n\n\ndef _generate_private_key(\n    type_: str, file: Optional[str] = None, password: Optional[str] = None\n) -> Dict[str, str]:\n    \"\"\"\n    Generate private key.\n\n    :param type_: type.\n    :param file: path to file.\n    :param password: the password to encrypt/decrypt the private key.\n\n    :return: dict of types and filenames of keys generated\n    \"\"\"\n    keys = {}\n    if type_ == \"all\" and file is not None:\n        raise click.ClickException(\"Type all cannot be used in combination with file.\")\n    types = list(crypto_registry.supported_ids) if type_ == \"all\" else [type_]\n    for type__ in types:\n        private_key_file = (\n            PRIVATE_KEY_PATH_SCHEMA.format(type__) if file is None else file\n        )\n        if _can_write(private_key_file):\n            create_private_key(type__, private_key_file, password)\n        keys[type__] = private_key_file\n    return keys\n\n\ndef _can_write(path: str) -> bool:\n    if Path(path).exists():\n        value = click.confirm(\n            \"The file {} already exists. Do you want to overwrite it?\".format(path),\n            default=False,\n        )\n        return value\n    return True\n"
  },
  {
    "path": "aea/cli/generate_wealth.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Implementation of the 'aea generate_wealth' subcommand.\"\"\"\nfrom typing import Optional, cast\n\nimport click\n\nfrom aea.cli.utils.click_utils import password_option\nfrom aea.cli.utils.context import Context\nfrom aea.cli.utils.decorators import check_aea_project\nfrom aea.cli.utils.package_utils import get_wallet_from_context\nfrom aea.crypto.helpers import try_generate_testnet_wealth\nfrom aea.crypto.registries import faucet_apis_registry, make_faucet_api_cls\n\n\n@click.command()\n@click.argument(\n    \"type_\",\n    metavar=\"TYPE\",\n    type=click.Choice(list(faucet_apis_registry.supported_ids)),\n    required=True,\n)\n@click.argument(\"url\", metavar=\"URL\", type=str, required=False, default=None)\n@password_option()\n@click.option(\n    \"--sync\", is_flag=True, help=\"For waiting till the faucet has released the funds.\"\n)\n@click.pass_context\n@check_aea_project\ndef generate_wealth(\n    click_context: click.Context,\n    type_: str,\n    url: str,\n    password: Optional[str],\n    sync: bool,\n) -> None:\n    \"\"\"Generate wealth for the agent on a test network.\"\"\"\n    ctx = cast(Context, click_context.obj)\n    _try_generate_wealth(ctx, type_, url, sync, password)\n\n\ndef _try_generate_wealth(\n    ctx: Context,\n    type_: str,\n    url: Optional[str],\n    sync: bool = False,\n    password: Optional[str] = None,\n) -> None:\n    \"\"\"\n    Try generate wealth for the provided network identifier.\n\n    :param ctx: the click context\n    :param type_: the network type\n    :param url: the url\n    :param sync: whether to sync or not\n    :param password: the password to encrypt/decrypt the private key.\n    \"\"\"\n    wallet = get_wallet_from_context(ctx, password=password)\n    try:\n        address = wallet.addresses[type_]\n        faucet_api_cls = make_faucet_api_cls(type_)\n        testnet = faucet_api_cls.network_name\n        click.echo(\n            \"Requesting funds for address {} on test network '{}'\".format(\n                address, testnet\n            )\n        )\n        try_generate_testnet_wealth(type_, address, url, sync)\n\n    except ValueError as e:  # pragma: no cover\n        raise click.ClickException(str(e))\n"
  },
  {
    "path": "aea/cli/get_address.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\n\"\"\"Implementation of the 'aea get_address' subcommand.\"\"\"\nfrom typing import Optional, cast\n\nimport click\n\nfrom aea.cli.utils.click_utils import password_option\nfrom aea.cli.utils.context import Context\nfrom aea.cli.utils.decorators import check_aea_project\nfrom aea.cli.utils.package_utils import get_wallet_from_context\nfrom aea.crypto.registries import crypto_registry\n\n\n@click.command()\n@click.argument(\n    \"type_\",\n    metavar=\"TYPE\",\n    type=click.Choice(list(crypto_registry.supported_ids)),\n    required=True,\n)\n@password_option()\n@click.pass_context\n@check_aea_project\ndef get_address(\n    click_context: click.Context, type_: str, password: Optional[str]\n) -> None:\n    \"\"\"Get the address associated with a private key of the agent.\"\"\"\n    ctx = cast(Context, click_context.obj)\n    address = _try_get_address(ctx, type_, password)\n    click.echo(address)\n\n\ndef _try_get_address(ctx: Context, type_: str, password: Optional[str] = None) -> str:\n    \"\"\"\n    Try to get address.\n\n    :param ctx: click context object.\n    :param type_: type.\n    :param password: the password to encrypt/decrypt the private key.\n\n    :return: address.\n    \"\"\"\n    wallet = get_wallet_from_context(ctx, password=password)\n    try:\n        address = wallet.addresses[type_]\n        return address\n    except ValueError as e:  # pragma: no cover\n        raise click.ClickException(str(e))\n"
  },
  {
    "path": "aea/cli/get_multiaddress.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Implementation of the 'aea get_multiaddress' subcommand.\"\"\"\nimport re\nimport typing\nfrom pathlib import Path\nfrom typing import Optional, Tuple, cast\n\nimport click\nfrom click import ClickException\n\nfrom aea.cli.utils.click_utils import PublicIdParameter, password_option\nfrom aea.cli.utils.context import Context\nfrom aea.cli.utils.decorators import check_aea_project\nfrom aea.configurations.base import PublicId\nfrom aea.configurations.constants import CONNECTIONS\nfrom aea.configurations.manager import AgentConfigManager\nfrom aea.crypto.base import Crypto\nfrom aea.crypto.registries import crypto_registry\nfrom aea.exceptions import enforce\nfrom aea.helpers.multiaddr.base import MultiAddr\n\n\nURI_REGEX = re.compile(r\"(?:https?://)?(?P<host>[^:/ ]+):(?P<port>[0-9]*)\")\n\n\n@click.command()\n@click.argument(\n    \"ledger_id\",\n    metavar=\"TYPE\",\n    type=click.Choice(list(crypto_registry.supported_ids)),\n    required=True,\n)\n@password_option()\n@click.option(\"-c\", \"--connection\", is_flag=True)\n@click.option(\n    \"-i\",\n    \"--connection-id\",\n    type=PublicIdParameter(),\n    required=False,\n    default=None,\n)\n@click.option(\n    \"-h\",\n    \"--host-field\",\n    type=str,\n    required=False,\n    default=None,\n)\n@click.option(\n    \"-p\",\n    \"--port-field\",\n    type=str,\n    required=False,\n    default=None,\n)\n@click.option(\n    \"-u\",\n    \"--uri-field\",\n    type=str,\n    required=False,\n    default=\"public_uri\",\n)\n@click.pass_context\n@check_aea_project\ndef get_multiaddress(\n    click_context: click.Context,\n    ledger_id: str,\n    password: Optional[str],\n    connection: bool,\n    connection_id: Optional[PublicId],\n    host_field: str,\n    port_field: str,\n    uri_field: str,\n) -> None:\n    \"\"\"Get the multiaddress associated with a private key or connection of the agent.\"\"\"\n    address = _try_get_multiaddress(\n        click_context,\n        ledger_id,\n        password,\n        connection,\n        connection_id,\n        host_field,\n        port_field,\n        uri_field,\n    )\n    click.echo(address)\n\n\ndef _try_get_multiaddress(\n    click_context: click.Context,\n    ledger_id: str,\n    password: Optional[str] = None,\n    is_connection: bool = False,\n    connection_id: Optional[PublicId] = None,\n    host_field: Optional[str] = None,\n    port_field: Optional[str] = None,\n    uri_field: str = \"public_uri\",\n) -> str:\n    \"\"\"\n    Try to get the multi-address.\n\n    :param click_context: click context object.\n    :param ledger_id: the ledger id.\n    :param password: the password to encrypt/decrypt the private key.\n    :param is_connection: whether the key to load is from the wallet or from connections.\n    :param connection_id: the connection id.\n    :param host_field: if connection_id specified, the config field to retrieve the host\n    :param port_field: if connection_id specified, the config field to retrieve the port\n    :param uri_field: uri field\n\n    :return: address.\n    \"\"\"\n    ctx = cast(Context, click_context.obj)\n    # connection_id not None implies is_connection\n    is_connection = connection_id is not None or is_connection\n\n    private_key_paths = (\n        ctx.agent_config.private_key_paths\n        if not is_connection\n        else ctx.agent_config.connection_private_key_paths\n    )\n    private_key_path = private_key_paths.read(ledger_id)\n\n    if private_key_path is None:\n        raise ClickException(\n            f\"Cannot find '{ledger_id}'. Please check {'private_key_path' if not is_connection else 'connection_private_key_paths'}.\"\n        )\n\n    path_to_key = Path(private_key_path)\n    crypto = crypto_registry.make(\n        ledger_id, private_key_path=path_to_key, password=password\n    )\n\n    if connection_id is None:\n        return _try_get_peerid(crypto)\n    return _try_get_connection_multiaddress(\n        click_context,\n        crypto,\n        cast(PublicId, connection_id),\n        host_field,\n        port_field,\n        uri_field,\n    )\n\n\ndef _try_get_peerid(crypto: Crypto) -> str:\n    \"\"\"Try to get the peer id.\"\"\"\n    try:\n        peer_id = MultiAddr(\"\", 0, crypto.public_key).peer_id\n        return peer_id\n    except Exception as e:\n        raise ClickException(str(e))\n\n\ndef _read_host_and_port_from_config(\n    connection_config: dict,\n    connection_id: PublicId,\n    uri_field: str,\n    host_field: Optional[str],\n    port_field: Optional[str],\n) -> Tuple[str, int]:\n    \"\"\"\n    Read host and port from config connection.\n\n    :param connection_config: connection configuration.\n    :param connection_id: the connection id.\n    :param uri_field: the uri field.\n    :param host_field: the host field.\n    :param port_field: the port field.\n    :return: the host and the port.\n    \"\"\"\n    host_is_none = host_field is None\n    port_is_none = port_field is None\n    one_is_none = (not host_is_none and port_is_none) or (\n        host_is_none and not port_is_none\n    )\n    if not host_is_none and not port_is_none:\n        if host_field not in connection_config:\n            raise ClickException(\n                f\"Host field '{host_field}' not present in connection configuration {connection_id}\"\n            )\n        if port_field not in connection_config:\n            raise ClickException(\n                f\"Port field '{port_field}' not present in connection configuration {connection_id}\"\n            )\n        host = connection_config[host_field]\n        port = int(connection_config[port_field])\n        return host, port\n    if one_is_none:\n        raise ClickException(\n            \"-h/--host-field and -p/--port-field must be specified together.\"\n        )\n    if uri_field not in connection_config:\n        raise ClickException(\n            f\"URI field '{uri_field}' not present in connection configuration {connection_id}\"\n        )\n    url_value = connection_config[uri_field]\n    try:\n        m = URI_REGEX.search(url_value)\n        enforce(m is not None, f\"URI Doesn't match regex '{URI_REGEX}'\")\n        m = cast(typing.Match, m)\n        host = m.group(\"host\")\n        port = int(m.group(\"port\"))\n        return host, port\n    except Exception as e:\n        raise ClickException(\n            f\"Cannot extract host and port from {uri_field}: '{url_value}'. Reason: {str(e)}\"\n        )\n\n\ndef _try_get_connection_multiaddress(\n    click_context: click.Context,\n    crypto: Crypto,\n    connection_id: PublicId,\n    host_field: Optional[str],\n    port_field: Optional[str],\n    uri_field: str,\n) -> str:\n    \"\"\"\n    Try to get the connection multiaddress.\n\n    The host and the port options have the precedence over the uri option.\n\n    :param click_context: the click context object.\n    :param crypto: the crypto.\n    :param connection_id: the connection id.\n    :param host_field: the host field.\n    :param port_field: the port field.\n    :param uri_field: the uri field.\n    :return: the multiaddress.\n    \"\"\"\n    ctx = cast(Context, click_context.obj)\n    if connection_id not in ctx.agent_config.connections:\n        raise ValueError(f\"Cannot find connection with the public id {connection_id}.\")\n\n    agent_config_manager = AgentConfigManager.load(ctx.cwd)\n    connection_config = cast(\n        dict,\n        agent_config_manager.get_variable(\n            f\"vendor.{connection_id.author}.{CONNECTIONS}.{connection_id.name}.config\"\n        ),\n    )\n\n    host, port = _read_host_and_port_from_config(\n        connection_config, connection_id, uri_field, host_field, port_field\n    )\n\n    try:\n        multiaddr = MultiAddr(host, port, crypto.public_key)\n        return multiaddr.format()\n    except Exception as e:\n        raise ClickException(f\"An error occurred while creating the multiaddress: {e}\")\n"
  },
  {
    "path": "aea/cli/get_public_key.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Implementation of the 'aea get_public_key' subcommand.\"\"\"\nfrom typing import Optional, cast\n\nimport click\n\nfrom aea.cli.utils.click_utils import password_option\nfrom aea.cli.utils.context import Context\nfrom aea.cli.utils.decorators import check_aea_project\nfrom aea.cli.utils.package_utils import get_wallet_from_context\nfrom aea.crypto.registries import crypto_registry\n\n\n@click.command()\n@click.argument(\n    \"type_\",\n    metavar=\"TYPE\",\n    type=click.Choice(list(crypto_registry.supported_ids)),\n    required=True,\n)\n@password_option()\n@click.pass_context\n@check_aea_project\ndef get_public_key(\n    click_context: click.Context, type_: str, password: Optional[str]\n) -> None:\n    \"\"\"Get the public key associated with a private key of the agent.\"\"\"\n    ctx = cast(Context, click_context.obj)\n    publickey = _try_get_public_key(ctx, type_, password)\n    click.echo(publickey)\n\n\ndef _try_get_public_key(\n    ctx: Context, type_: str, password: Optional[str] = None\n) -> str:\n    \"\"\"\n    Try to get public key.\n\n    :param ctx: click context object.\n    :param type_: type.\n    :param password: the password to encrypt/decrypt the private key.\n\n    :return: public key str.\n    \"\"\"\n    wallet = get_wallet_from_context(ctx, password=password)\n    try:\n        publickey = wallet.public_keys[type_]\n        return publickey\n    except ValueError as e:  # pragma: no cover\n        raise click.ClickException(str(e))\n"
  },
  {
    "path": "aea/cli/get_wealth.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Implementation of the 'aea get_wealth' subcommand.\"\"\"\n\nfrom typing import Optional, cast\n\nimport click\n\nfrom aea.cli.utils.click_utils import password_option\nfrom aea.cli.utils.context import Context\nfrom aea.cli.utils.decorators import check_aea_project\nfrom aea.cli.utils.package_utils import (\n    _override_ledger_configurations,\n    get_wallet_from_context,\n    try_get_balance,\n)\nfrom aea.crypto.registries import ledger_apis_registry\n\n\n@click.command()\n@click.argument(\n    \"type_\",\n    metavar=\"TYPE\",\n    type=click.Choice(list(ledger_apis_registry.supported_ids)),\n    required=True,\n)\n@password_option()\n@click.pass_context\n@check_aea_project\ndef get_wealth(\n    click_context: click.Context, type_: str, password: Optional[str]\n) -> None:\n    \"\"\"Get the wealth associated with the private key of the agent.\"\"\"\n    ctx = cast(Context, click_context.obj)\n    wealth = _try_get_wealth(ctx, type_, password)\n    click.echo(wealth)\n\n\ndef _try_get_wealth(ctx: Context, type_: str, password: Optional[str] = None) -> int:\n    \"\"\"Try get wealth.\"\"\"\n    wallet = get_wallet_from_context(ctx, password=password)\n    _override_ledger_configurations(ctx.agent_config)\n    return try_get_balance(ctx.agent_config, wallet, type_)\n"
  },
  {
    "path": "aea/cli/init.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Implementation of the 'aea init' subcommand.\"\"\"\n\nimport click\n\nfrom aea import __version__\nfrom aea.cli.login import do_login\nfrom aea.cli.register import do_register\nfrom aea.cli.registry.settings import AUTH_TOKEN_KEY\nfrom aea.cli.registry.utils import check_is_author_logged_in, is_auth_token_present\nfrom aea.cli.utils.config import get_or_create_cli_config, update_cli_config\nfrom aea.cli.utils.constants import AEA_LOGO, AUTHOR_KEY\nfrom aea.cli.utils.context import Context\nfrom aea.cli.utils.decorators import pass_ctx\nfrom aea.cli.utils.package_utils import validate_author_name\n\n\n@click.command()\n@click.option(\"--author\", type=str, required=False)\n@click.option(\"--reset\", is_flag=True, help=\"To reset the initialization.\")\n@click.option(\n    \"--register\", is_flag=True, help=\"To register the author in the AEA registry.\"\n)\n@click.option(\"--no-subscribe\", is_flag=True, help=\"For developers subscription.\")\n@pass_ctx\ndef init(  # pylint: disable=unused-argument\n    ctx: Context, author: str, reset: bool, register: bool, no_subscribe: bool\n) -> None:\n    \"\"\"Initialize your AEA configurations.\"\"\"\n    do_init(author, reset, register, no_subscribe)\n\n\ndef do_init(author: str, reset: bool, registry: bool, no_subscribe: bool) -> None:\n    \"\"\"\n    Initialize your AEA configurations.\n\n    :param author: str author username.\n    :param reset: True, if resetting the author name\n    :param registry: True, if registry is used\n    :param no_subscribe: bool flag for developers subscription skip on register.\n    \"\"\"\n    config = get_or_create_cli_config()\n    if reset or config.get(AUTHOR_KEY, None) is None:\n        author = validate_author_name(author)\n        if registry:\n            _registry_init(username=author, no_subscribe=no_subscribe)\n\n        update_cli_config({AUTHOR_KEY: author})\n        config = get_or_create_cli_config()\n        config.pop(AUTH_TOKEN_KEY, None)  # for security reasons\n        success_msg = \"AEA configurations successfully initialized: {}\".format(config)\n    else:\n        config.pop(AUTH_TOKEN_KEY, None)  # for security reasons\n        success_msg = \"AEA configurations already initialized: {}. To reset use '--reset'.\".format(\n            config\n        )\n    click.echo(AEA_LOGO + \"v\" + __version__ + \"\\n\")\n    click.echo(success_msg)\n\n\ndef _registry_init(username: str, no_subscribe: bool) -> None:\n    \"\"\"\n    Create an author name on the registry.\n\n    :param username: the user name\n    :param no_subscribe: bool flag for developers subscription skip on register.\n    \"\"\"\n    if username is not None and is_auth_token_present():\n        check_is_author_logged_in(username)\n    else:\n        is_registered = click.confirm(\"Do you have a Registry account?\")\n        if is_registered:\n            password = click.prompt(\"Password\", type=str, hide_input=True)\n            do_login(username, password)\n        else:\n            click.echo(\"Create a new account on the Registry now:\")\n            email = click.prompt(\"Email\", type=str)\n            password = click.prompt(\"Password\", type=str, hide_input=True)\n\n            password_confirmation = \"\"  # nosec\n            while password_confirmation != password:\n                click.echo(\"Please make sure that passwords are equal.\")\n                password_confirmation = click.prompt(\n                    \"Confirm password\", type=str, hide_input=True\n                )\n\n            do_register(username, email, password, password_confirmation, no_subscribe)\n"
  },
  {
    "path": "aea/cli/install.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Implementation of the 'aea install' subcommand.\"\"\"\n\nfrom typing import Optional, cast\n\nimport click\n\nfrom aea.cli.utils.context import Context\nfrom aea.cli.utils.decorators import check_aea_project\nfrom aea.cli.utils.loggers import logger\nfrom aea.configurations.data_types import Dependencies\nfrom aea.configurations.pypi import is_satisfiable, is_simple_dep, to_set_specifier\nfrom aea.exceptions import AEAException\nfrom aea.helpers.install_dependency import call_pip, install_dependencies\n\n\n@click.command()\n@click.option(\n    \"-r\",\n    \"--requirement\",\n    type=click.Path(exists=True, file_okay=True, dir_okay=False, readable=True),\n    required=False,\n    default=None,\n    help=\"Install from the given requirements file.\",\n)\n@click.pass_context\n@check_aea_project\ndef install(click_context: click.Context, requirement: Optional[str]) -> None:\n    \"\"\"Install the dependencies of the agent.\"\"\"\n    ctx = cast(Context, click_context.obj)\n    do_install(ctx, requirement)\n\n\ndef do_install(ctx: Context, requirement: Optional[str] = None) -> None:\n    \"\"\"\n    Install necessary dependencies.\n\n    :param ctx: context object.\n    :param requirement: optional str requirement.\n\n    :raises ClickException: if AEAException occurs.\n    \"\"\"\n    try:\n        if requirement:\n            logger.debug(\"Installing the dependencies in '{}'...\".format(requirement))\n            _install_from_requirement(requirement)\n        else:\n            logger.debug(\"Installing all the dependencies...\")\n            dependencies = ctx.get_dependencies()\n\n            logger.debug(\"Preliminary check on satisfiability of version specifiers...\")\n            unsat_dependencies = _find_unsatisfiable_dependencies(dependencies)\n            if len(unsat_dependencies) != 0:\n                raise AEAException(\n                    \"cannot install the following dependencies \"\n                    + \"as the joint version specifier is unsatisfiable:\\n - \"\n                    + \"\\n -\".join(\n                        [\n                            f\"{name}: {to_set_specifier(dep)}\"\n                            for name, dep in unsat_dependencies.items()\n                        ]\n                    )\n                )\n            install_dependencies(list(dependencies.values()), logger=logger)\n    except AEAException as e:\n        raise click.ClickException(str(e))\n\n\ndef _find_unsatisfiable_dependencies(dependencies: Dependencies) -> Dependencies:\n    \"\"\"\n    Find unsatisfiable dependencies.\n\n    It only checks among 'simple' dependencies (i.e. if it has no field specified,\n    or only the 'version' field set.)\n\n    :param dependencies: the dependencies to check.\n    :return: the unsatisfiable dependencies.\n    \"\"\"\n    return {\n        name: dep\n        for name, dep in dependencies.items()\n        if is_simple_dep(dep) and not is_satisfiable(to_set_specifier(dep))\n    }\n\n\ndef _install_from_requirement(file: str, install_timeout: float = 300) -> None:\n    \"\"\"\n    Install from requirements.\n\n    :param file: requirement.txt file path\n    :param install_timeout: timeout to wait pip to install\n\n    :raises AEAException: if an error occurs during installation.\n    \"\"\"\n    try:\n        call_pip([\"install\", \"-r\", file], timeout=install_timeout)\n    except Exception:\n        raise AEAException(\n            \"An error occurred while installing requirement file {}. Stopping...\".format(\n                file\n            )\n        )\n"
  },
  {
    "path": "aea/cli/interact.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Implementation of the 'aea interact' subcommand.\"\"\"\n\nimport codecs\nimport os\nfrom typing import Optional, TYPE_CHECKING, Type, Union\n\nimport click\n\nfrom aea.cli.utils.constants import STUB_CONNECTION\nfrom aea.cli.utils.decorators import check_aea_project\nfrom aea.cli.utils.exceptions import InterruptInputException\nfrom aea.common import Address\nfrom aea.configurations.base import ConnectionConfig, PackageType, PublicId\nfrom aea.configurations.constants import (\n    CONNECTIONS,\n    DEFAULT_AEA_CONFIG_FILE,\n    DEFAULT_PROTOCOL,\n    PROTOCOLS,\n    SIGNING_PROTOCOL,\n    STATE_UPDATE_PROTOCOL,\n    VENDOR,\n)\nfrom aea.configurations.loader import ConfigLoader\nfrom aea.connections.base import Connection\nfrom aea.crypto.wallet import CryptoStore\nfrom aea.helpers.io import open_file\nfrom aea.identity.base import Identity\nfrom aea.mail.base import Envelope, Message\nfrom aea.multiplexer import InBox, Multiplexer, OutBox\nfrom aea.protocols.base import Protocol\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\nfrom aea.protocols.dialogue.base import Dialogues\n\n\nif TYPE_CHECKING:  # pragma: nocover\n    from packages.fetchai.connections.stub.connection import (  # noqa: F401\n        DEFAULT_INPUT_FILE_NAME,\n        DEFAULT_OUTPUT_FILE_NAME,\n        StubConnection,\n    )\n    from packages.fetchai.protocols.default.dialogues import (  # noqa: F401\n        DefaultDialogue,\n        DefaultDialogues,\n    )\n    from packages.fetchai.protocols.default.message import DefaultMessage  # noqa: F401\n\n\n@click.command()\n@click.pass_context\n@check_aea_project\ndef interact(\n    click_context: click.core.Context,  # pylint: disable=unused-argument\n) -> None:\n    \"\"\"Interact with the running agent via the stub connection.\"\"\"\n    click.echo(\"Starting AEA interaction channel...\")\n    _run_interaction_channel()\n\n\ndef _load_packages(agent_identity: Identity) -> None:\n    \"\"\"Load packages in the current interpreter.\"\"\"\n    default_protocol_id = PublicId.from_str(DEFAULT_PROTOCOL)\n    Protocol.from_dir(\n        os.path.join(\n            VENDOR, default_protocol_id.author, PROTOCOLS, default_protocol_id.name\n        )\n    )\n    signing_protocol_id = PublicId.from_str(SIGNING_PROTOCOL)\n    Protocol.from_dir(\n        os.path.join(\n            VENDOR, signing_protocol_id.author, PROTOCOLS, signing_protocol_id.name\n        )\n    )\n    state_update_protocol_id = PublicId.from_str(STATE_UPDATE_PROTOCOL)\n    Protocol.from_dir(\n        os.path.join(\n            VENDOR,\n            state_update_protocol_id.author,\n            PROTOCOLS,\n            state_update_protocol_id.name,\n        )\n    )\n    stub_connection_id = PublicId.from_str(STUB_CONNECTION)\n    Connection.from_dir(\n        os.path.join(\n            VENDOR,\n            stub_connection_id.author,\n            CONNECTIONS,\n            stub_connection_id.name,\n        ),\n        agent_identity,\n        CryptoStore(),\n        os.getcwd(),\n    )\n\n\ndef _run_interaction_channel() -> None:\n    loader = ConfigLoader.from_configuration_type(PackageType.AGENT)\n    agent_configuration = loader.load(open_file(DEFAULT_AEA_CONFIG_FILE))\n    agent_name = agent_configuration.name\n\n    identity_stub = Identity(agent_name + \"_interact\", \"interact\", \"interact\")\n    _load_packages(identity_stub)\n\n    # load agent configuration file\n    from packages.fetchai.connections.stub.connection import (  # noqa: F811 # pylint: disable=import-outside-toplevel\n        DEFAULT_INPUT_FILE_NAME,\n        DEFAULT_OUTPUT_FILE_NAME,\n        StubConnection,\n    )\n    from packages.fetchai.protocols.default.dialogues import (  # noqa: F811 # pylint: disable=import-outside-toplevel\n        DefaultDialogue,\n        DefaultDialogues,\n    )\n    from packages.fetchai.protocols.default.message import (  # noqa: F811 # pylint: disable=import-outside-toplevel\n        DefaultMessage,\n    )\n\n    # load stub connection\n    configuration = ConnectionConfig(\n        input_file=DEFAULT_OUTPUT_FILE_NAME,\n        output_file=DEFAULT_INPUT_FILE_NAME,\n        connection_id=StubConnection.connection_id,\n    )\n\n    stub_connection = StubConnection(\n        configuration=configuration, data_dir=os.getcwd(), identity=identity_stub\n    )\n    multiplexer = Multiplexer([stub_connection])\n    inbox = InBox(multiplexer)\n    outbox = OutBox(multiplexer)\n\n    def role_from_first_message(  # pylint: disable=unused-argument\n        message: Message, receiver_address: Address\n    ) -> BaseDialogue.Role:\n        \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n        :param message: an incoming/outgoing first message\n        :param receiver_address: the address of the receiving agent\n        :return: The role of the agent\n        \"\"\"\n        return DefaultDialogue.Role.AGENT\n\n    dialogues = DefaultDialogues(identity_stub.name, role_from_first_message)\n\n    try:\n        multiplexer.connect()\n        while True:  # pragma: no cover\n            _process_envelopes(agent_name, inbox, outbox, dialogues, DefaultMessage)\n\n    except KeyboardInterrupt:\n        click.echo(\"Interaction interrupted!\")\n    except BaseException as e:  # pylint: disable=broad-except # pragma: no cover\n        click.echo(e)\n    finally:\n        multiplexer.disconnect()\n\n\ndef _process_envelopes(\n    agent_name: str,\n    inbox: InBox,\n    outbox: OutBox,\n    dialogues: Dialogues,\n    message_class: Type[Message],\n) -> None:\n    \"\"\"\n    Process envelopes.\n\n    :param agent_name: name of an agent.\n    :param inbox: an inbox object.\n    :param outbox: an outbox object.\n    :param dialogues: the dialogues object.\n    :param message_class: the message class.\n    \"\"\"\n    envelope = _try_construct_envelope(agent_name, dialogues, message_class)\n    if envelope is None:\n        _check_for_incoming_envelope(inbox, message_class)\n    else:\n        outbox.put(envelope)\n        click.echo(_construct_message(\"sending\", envelope, message_class))\n\n\ndef _check_for_incoming_envelope(inbox: InBox, message_class: Type[Message]) -> None:\n    if not inbox.empty():\n        envelope = inbox.get_nowait()\n        if envelope is None:\n            raise ValueError(\"Could not recover envelope from inbox.\")\n        click.echo(_construct_message(\"received\", envelope, message_class))\n    else:\n        click.echo(\"Received no new envelope!\")\n\n\ndef _construct_message(\n    action_name: str, envelope: Envelope, message_class: Type[Message]\n) -> str:\n    action_name = action_name.title()\n    msg = (\n        message_class.serializer.decode(envelope.message)\n        if isinstance(envelope.message, bytes)\n        else envelope.message\n    )\n    message = (\n        \"\\n{} envelope:\\nto: \"\n        \"{}\\nsender: {}\\nprotocol_specification_id: {}\\nmessage: {}\\n\".format(\n            action_name,\n            envelope.to,\n            envelope.sender,\n            envelope.protocol_specification_id,\n            msg,\n        )\n    )\n    return message\n\n\ndef _try_construct_envelope(\n    agent_name: str, dialogues: Dialogues, message_class: Type[Message]\n) -> Optional[Envelope]:\n    \"\"\"Try construct an envelope from user input.\"\"\"\n    envelope = None  # type: Optional[Envelope]\n    try:\n        performative_str = \"bytes\"\n        performative = message_class.Performative(performative_str)\n        click.echo(\n            f\"Provide message of protocol '{str(message_class.protocol_id)}' for performative {performative_str}:\"\n        )\n        message_escaped = input()  # nosec\n        message_escaped = message_escaped.strip()\n        if message_escaped == \"\":\n            raise InterruptInputException\n        message_decoded = codecs.decode(\n            message_escaped.encode(\"utf-8\"), \"unicode-escape\"\n        )\n        message = message_decoded.encode(\"utf-8\")  # type: Union[str, bytes]\n        msg, _ = dialogues.create(\n            counterparty=agent_name,\n            performative=performative,\n            content=message,\n        )\n        envelope = Envelope(\n            to=msg.to,\n            sender=msg.sender,\n            message=msg,\n        )\n    except InterruptInputException:\n        click.echo(\"Interrupting input, checking inbox ...\")\n    except KeyboardInterrupt:\n        raise\n    except BaseException as e:  # pylint: disable=broad-except # pragma: no cover\n        click.echo(e)\n    return envelope\n"
  },
  {
    "path": "aea/cli/issue_certificates.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Implementation of the 'aea issue_certificates' subcommand.\"\"\"\nfrom typing import Dict, List, Optional, cast\n\nimport click\nfrom click import ClickException\n\nfrom aea.cli.utils.click_utils import password_option\nfrom aea.cli.utils.context import Context\nfrom aea.cli.utils.decorators import check_aea_project\nfrom aea.cli.utils.loggers import logger\nfrom aea.cli.utils.package_utils import get_dotted_package_path_unified\nfrom aea.configurations.base import AgentConfig, PublicId\nfrom aea.configurations.constants import CONNECTION\nfrom aea.configurations.manager import AgentConfigManager, VariableDoesNotExist\nfrom aea.crypto.helpers import make_certificate\nfrom aea.crypto.registries import crypto_registry\nfrom aea.exceptions import enforce\nfrom aea.helpers.base import CertRequest, prepend_if_not_absolute\n\n\n@click.command()\n@password_option()\n@click.pass_context\n@check_aea_project\ndef issue_certificates(click_context: click.Context, password: Optional[str]) -> None:\n    \"\"\"Issue certificates for connections that require them.\"\"\"\n    ctx = cast(Context, click_context.obj)\n    agent_config_manager = AgentConfigManager.load(ctx.cwd)\n    issue_certificates_(ctx.cwd, agent_config_manager, password=password)\n\n\ndef issue_certificates_(\n    project_directory: str,\n    agent_config_manager: AgentConfigManager,\n    path_prefix: Optional[str] = None,\n    password: Optional[str] = None,\n) -> None:\n    \"\"\"\n    Issue certificates for connections that require them.\n\n    :param project_directory: the directory of the project.\n    :param agent_config_manager: the agent configuration manager.\n    :param path_prefix: the path prefix for \"save_path\". Defaults to project directory.\n    :param password: the password to encrypt/decrypt the private key.\n    \"\"\"\n    path_prefix = path_prefix or project_directory\n    for connection_id in agent_config_manager.agent_config.connections:\n        cert_requests = _get_cert_requests(\n            project_directory, agent_config_manager, connection_id\n        )\n        _process_connection(\n            path_prefix, agent_config_manager, cert_requests, connection_id, password\n        )\n\n    click.echo(\"All certificates have been issued.\")\n\n\ndef _get_cert_requests(\n    project_directory: str, manager: AgentConfigManager, connection_id: PublicId\n) -> List[CertRequest]:\n    \"\"\"\n    Get certificate requests, taking the overrides into account.\n\n    :param project_directory: aea project directory.\n    :param manager: AgentConfigManager\n    :param connection_id: the connection id.\n\n    :return: the list of cert requests.\n    \"\"\"\n    path = get_dotted_package_path_unified(\n        project_directory, manager.agent_config, CONNECTION, connection_id\n    )\n    path_to_cert_requests = f\"{path}.cert_requests\"\n\n    try:\n        cert_requests = manager.get_variable(path_to_cert_requests)\n    except VariableDoesNotExist:\n        return []\n\n    cert_requests = cast(List[Dict], cert_requests)\n    return [\n        CertRequest.from_json(cert_request_json) for cert_request_json in cert_requests\n    ]\n\n\ndef _process_certificate(\n    path_prefix: str,\n    agent_config: AgentConfig,\n    cert_request: CertRequest,\n    connection_id: PublicId,\n    password: Optional[str] = None,\n) -> None:\n    \"\"\"Process a single certificate request.\"\"\"\n    ledger_id = cert_request.ledger_id\n    if cert_request.key_identifier is not None:\n        key_identifier = cert_request.key_identifier\n        connection_private_key_path = agent_config.connection_private_key_paths.read(\n            key_identifier\n        )\n        if connection_private_key_path is None:\n            raise ClickException(\n                f\"Cannot find connection private key with id '{key_identifier}'. Connection '{connection_id}' requires this. Please use `aea generate-key {key_identifier} connection_{key_identifier}_private_key.txt` and `aea add-key {key_identifier} connection_{key_identifier}_private_key.txt --connection` to add a connection private key with id '{key_identifier}'.\"\n            )\n        new_connection_private_key_path = prepend_if_not_absolute(\n            connection_private_key_path, path_prefix\n        )\n        connection_crypto = crypto_registry.make(\n            key_identifier,\n            private_key_path=new_connection_private_key_path,\n            password=password,\n        )\n        public_key = connection_crypto.public_key\n    else:\n        public_key = cast(str, cert_request.public_key)\n        enforce(\n            public_key is not None,\n            \"Internal error - one of key_identifier or public_key must be not None.\",\n        )\n    crypto_private_key_path = agent_config.private_key_paths.read(ledger_id)\n    if crypto_private_key_path is None:\n        raise ClickException(\n            f\"Cannot find private key with id '{ledger_id}'. Please use `aea generate-key {key_identifier}` and `aea add-key {key_identifier}` to add a private key with id '{key_identifier}'.\"\n        )\n    message = cert_request.get_message(public_key)\n    output_path = cert_request.get_absolute_save_path(path_prefix)\n    absolute_crypto_private_key_path = prepend_if_not_absolute(\n        crypto_private_key_path, path_prefix\n    )\n    cert = make_certificate(\n        ledger_id,\n        str(absolute_crypto_private_key_path),\n        message,\n        str(output_path),\n        password=password,\n    )\n    click.echo(f\"Generated signature: '{cert}'\")\n    click.echo(\n        f\"Dumped certificate '{cert_request.identifier}' in '{output_path}' for connection {connection_id}.\"\n    )\n\n\ndef _process_connection(\n    path_prefix: str,\n    agent_config_manager: AgentConfigManager,\n    cert_requests: List[CertRequest],\n    connection_id: PublicId,\n    password: Optional[str] = None,\n) -> None:\n    \"\"\"Process a single connection.\"\"\"\n    if len(cert_requests) == 0:\n        logger.debug(\"No certificates to process.\")\n        return\n\n    logger.debug(f\"Processing connection '{connection_id}'...\")\n    for cert_request in cert_requests:\n        click.echo(\n            f\"Issuing certificate '{cert_request.identifier}' for connection {connection_id}...\"\n        )\n        _process_certificate(\n            path_prefix,\n            agent_config_manager.agent_config,\n            cert_request,\n            connection_id,\n            password,\n        )\n"
  },
  {
    "path": "aea/cli/launch.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Implementation of the 'aea launch' subcommand.\"\"\"\nimport os\nimport sys\nfrom collections import OrderedDict\nfrom pathlib import Path\nfrom typing import List, Optional, cast\n\nimport click\n\nfrom aea.cli.utils.click_utils import AgentDirectory, password_option\nfrom aea.cli.utils.context import Context\nfrom aea.cli.utils.loggers import logger\nfrom aea.helpers.multiple_executor import ExecutorExceptionPolicies\nfrom aea.launcher import AEALauncher\n\n\n@click.command()\n@click.argument(\"agents\", nargs=-1, type=AgentDirectory())\n@password_option()\n@click.option(\"--multithreaded\", is_flag=True)\n@click.pass_context\ndef launch(\n    click_context: click.Context,\n    agents: List[str],\n    password: Optional[str],\n    multithreaded: bool,\n) -> None:\n    \"\"\"Launch many agents at the same time.\"\"\"\n    _launch_agents(click_context, agents, multithreaded, password)\n\n\ndef _launch_agents(\n    click_context: click.core.Context,\n    agents: List[str],\n    multithreaded: bool,\n    password: Optional[str] = None,\n) -> None:\n    \"\"\"\n    Run multiple agents.\n\n    :param click_context: click context object.\n    :param agents: agents names.\n    :param multithreaded: bool flag to run as multithreads.\n    :param password: the password to encrypt/decrypt the private key.\n    \"\"\"\n    agents_directories = list(map(Path, list(OrderedDict.fromkeys(agents))))\n    mode = \"threaded\" if multithreaded else \"multiprocess\"\n    ctx = cast(Context, click_context.obj)\n\n    launcher = AEALauncher(\n        agent_dirs=agents_directories,\n        mode=mode,\n        fail_policy=ExecutorExceptionPolicies.log_only,\n        log_level=ctx.verbosity,\n        password=password,\n    )\n\n    try:\n        \"\"\"\n        run in threaded mode and wait for thread finished cause issue with python 3.6/3.7 on windows\n        probably keyboard interrupt exception gets lost in executor pool or in asyncio module\n        \"\"\"\n        launcher.start(threaded=True)\n        launcher.try_join_thread()\n    except KeyboardInterrupt:\n        logger.info(\"Keyboard interrupt detected.\")\n    finally:\n        timeout: Optional[float] = None\n        if os.name == \"nt\":\n            # Windows bug: https://bugs.python.org/issue21822\n            timeout = 0  # pragma: nocover\n        launcher.stop(timeout)\n\n    for agent in launcher.failed:\n        logger.info(f\"Agent {agent} terminated with exit code 1\")\n\n    for agent in launcher.not_failed:\n        logger.info(f\"Agent {agent} terminated with exit code 0\")\n\n    logger.debug(f\"Exit cli. code: {launcher.num_failed}\")\n    sys.exit(1 if launcher.num_failed > 0 else 0)\n"
  },
  {
    "path": "aea/cli/list.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Implementation of the 'aea list' subcommand.\"\"\"\n\nfrom collections.abc import Set\nfrom pathlib import Path\nfrom typing import Dict, List\n\nimport click\n\nfrom aea.cli.utils.constants import ITEM_TYPES\nfrom aea.cli.utils.context import Context\nfrom aea.cli.utils.decorators import check_aea_project, pass_ctx\nfrom aea.cli.utils.formatting import format_items, retrieve_details, sort_items\nfrom aea.configurations.base import (\n    PackageType,\n    PublicId,\n    _get_default_configuration_file_name_from_type,\n)\nfrom aea.configurations.constants import CONNECTION, CONTRACT, PROTOCOL, SKILL, VENDOR\nfrom aea.configurations.loader import ConfigLoader\n\n\n@click.group(name=\"list\")\n@click.pass_context\n@check_aea_project\ndef list_command(\n    click_context: click.Context,  # pylint: disable=unused-argument\n) -> None:\n    \"\"\"List the installed packages of the agent.\"\"\"\n\n\n@list_command.command(name=\"all\")\n@pass_ctx\ndef all_command(ctx: Context) -> None:\n    \"\"\"List all the installed packages.\"\"\"\n    for item_type in ITEM_TYPES:\n        details = list_agent_items(ctx, item_type)\n        if not details:\n            continue\n        output = \"{}:\\n{}\".format(\n            item_type.title() + \"s\", format_items(sort_items(details))\n        )\n        click.echo(output)\n\n\n@list_command.command()\n@pass_ctx\ndef connections(ctx: Context) -> None:\n    \"\"\"List all the installed connections.\"\"\"\n    result = list_agent_items(ctx, CONNECTION)\n    click.echo(format_items(sort_items(result)))\n\n\n@list_command.command()\n@pass_ctx\ndef contracts(ctx: Context) -> None:\n    \"\"\"List all the installed protocols.\"\"\"\n    result = list_agent_items(ctx, CONTRACT)\n    click.echo(format_items(sort_items(result)))\n\n\n@list_command.command()\n@pass_ctx\ndef protocols(ctx: Context) -> None:\n    \"\"\"List all the installed protocols.\"\"\"\n    result = list_agent_items(ctx, PROTOCOL)\n    click.echo(format_items(sort_items(result)))\n\n\n@list_command.command()\n@pass_ctx\ndef skills(ctx: Context) -> None:\n    \"\"\"List all the installed skills.\"\"\"\n    result = list_agent_items(ctx, SKILL)\n    click.echo(format_items(sorted(result, key=lambda k: k[\"name\"])))\n\n\ndef list_agent_items(ctx: Context, item_type: str) -> List[Dict]:\n    \"\"\"Return a list of item details, given the item type.\"\"\"\n    result = []\n    item_type_plural = item_type + \"s\"\n    public_ids = getattr(ctx.agent_config, item_type_plural)  # type: Set[PublicId]\n    default_file_name = _get_default_configuration_file_name_from_type(item_type)\n    for public_id in public_ids:\n        # first, try to retrieve the item from the vendor directory.\n        configuration_filepath = Path(\n            ctx.cwd,\n            VENDOR,\n            public_id.author,\n            item_type_plural,\n            public_id.name,\n            default_file_name,\n        )\n        # otherwise, if it does not exist, retrieve the item from the agent custom packages\n        if not configuration_filepath.exists():\n            configuration_filepath = Path(\n                ctx.cwd, item_type_plural, public_id.name, default_file_name\n            )\n        configuration_loader = ConfigLoader.from_configuration_type(\n            PackageType(item_type)\n        )\n        details = retrieve_details(\n            public_id.name, configuration_loader, str(configuration_filepath)\n        )\n        result.append(details)\n    return result\n"
  },
  {
    "path": "aea/cli/local_registry_sync.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Implementation of the 'aea sync-local-registry' subcommand.\"\"\"\nimport os\nimport shutil\nfrom pathlib import Path\nfrom tempfile import TemporaryDirectory\nfrom typing import Generator, Tuple, Union, cast\n\nimport click\n\nfrom aea.cli.fingerprint import determine_package_type_for_directory\nfrom aea.cli.registry.add import fetch_package\nfrom aea.cli.registry.utils import get_package_meta\nfrom aea.cli.utils.context import Context\nfrom aea.cli.utils.decorators import pass_ctx\nfrom aea.cli.utils.loggers import logger\nfrom aea.configurations.data_types import PackageId, PackageType, PublicId\nfrom aea.configurations.loader import load_package_configuration\n\n\nPACKAGES_DIRS = [i.to_plural() for i in PackageType]\n\n\n@click.command()\n@pass_ctx\ndef local_registry_sync(ctx: Context) -> None:\n    \"\"\"Upgrade the local package registry.\"\"\"\n    skip_consistency_check = ctx.config[\"skip_consistency_check\"]\n    do_local_registry_update(ctx.cwd, skip_consistency_check)\n\n\ndef do_local_registry_update(\n    base_dir: Union[str, Path], skip_consistency_check: bool = True\n) -> None:\n    \"\"\"\n    Perform local registry update.\n\n    :param base_dir: root directory of the local registry.\n    :param skip_consistency_check: whether or not to skip consistency checks.\n    \"\"\"\n    for package_id, package_dir in enlist_packages(base_dir, skip_consistency_check):\n        current_public_id = package_id.public_id\n        latest_public_id = get_package_latest_public_id(package_id)\n        if not (  # pylint: disable=superfluous-parens\n            current_public_id < latest_public_id\n        ):\n            click.echo(f\"{package_id} is the latest version.\")\n            continue\n        click.echo(f\"Updating {current_public_id} to {latest_public_id}.\")\n        replace_package(str(package_id.package_type), latest_public_id, package_dir)\n\n\ndef replace_package(\n    package_type: str, public_id: PublicId, package_dir: Union[Path, str]\n) -> None:\n    \"\"\"\n    Download, extract and replace exists package.\n\n    :param package_type: str.\n    :param public_id: package public id to download\n    :param: package_dir: target package dir\n    \"\"\"\n    with TemporaryDirectory() as tmp_dir:\n        new_package_dir = os.path.join(tmp_dir, public_id.name)\n        os.mkdir(new_package_dir)\n        fetch_package(\n            package_type, public_id=public_id, cwd=tmp_dir, dest=new_package_dir\n        )\n        shutil.rmtree(package_dir)\n        shutil.move(new_package_dir, package_dir)\n\n\ndef get_package_latest_public_id(package_id: PackageId) -> PublicId:\n    \"\"\"\n    Get package latest package id from the remote repo.\n\n    :param package_id: id of the package to check\n\n    :return: package id of the latest package in remote repo\n    \"\"\"\n    package_meta = get_package_meta(\n        str(package_id.package_type), package_id.public_id.to_latest()\n    )\n    return PublicId.from_str(cast(str, package_meta[\"public_id\"]))\n\n\ndef enlist_packages(\n    base_dir: Union[Path, str], skip_consistency_check: bool = True\n) -> Generator[Tuple[PackageId, Union[Path, str]], None, None]:\n    \"\"\"\n    Generate list of the packages in local repo directory.\n\n    :param base_dir: path or str of the local repo.\n    :param skip_consistency_check: whether or not to skip consistency checks.\n\n    :yield: a Tuple of package_id and package directory.\n    \"\"\"\n    for author in os.listdir(base_dir):\n        author_dir = os.path.join(base_dir, author)\n        if not os.path.isdir(author_dir):\n            continue  # pragma: nocover\n        for package_type_plural in os.listdir(author_dir):\n            if package_type_plural not in PACKAGES_DIRS:\n                continue  # pragma: nocover\n            package_type_dir = os.path.join(author_dir, package_type_plural)\n            if not os.path.isdir(package_type_dir):\n                continue  # pragma: nocover\n            for package_name in os.listdir(package_type_dir):\n                package_dir = os.path.join(package_type_dir, package_name)\n                if not os.path.isdir(package_dir):\n                    continue  # pragma: nocover\n                try:\n                    package_type = determine_package_type_for_directory(\n                        Path(package_dir)\n                    )\n                    if package_type.to_plural() != package_type_plural:\n                        # incorrect package placing\n                        continue  # pragma: nocover\n                    config = load_package_configuration(\n                        package_type,\n                        Path(package_dir),\n                        skip_consistency_check=skip_consistency_check,\n                    )\n                    yield (config.package_id, package_dir)\n                except ValueError as e:  # pragma: nocover\n                    logger.error(  # pragma: nocover\n                        f\"Error with package_dir={package_dir}: {e}\"\n                    )\n"
  },
  {
    "path": "aea/cli/login.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Implementation of the 'aea login' subcommand.\"\"\"\n\nimport click\n\nfrom aea.cli.registry.login import registry_login\nfrom aea.cli.registry.settings import AUTH_TOKEN_KEY\nfrom aea.cli.utils.config import update_cli_config\n\n\n@click.command(name=\"login\", help=\"Login to the registry account.\")\n@click.argument(\"username\", type=str, required=True)\n@click.option(\"--password\", type=str, required=True, prompt=True, hide_input=True)\ndef login(username: str, password: str) -> None:\n    \"\"\"Login to the registry account.\"\"\"\n    do_login(username, password)\n\n\ndef do_login(username: str, password: str) -> None:\n    \"\"\"\n    Login to the registry account and save auth token in config.\n\n    :param username: str username.\n    :param password: str password.\n    \"\"\"\n    click.echo(\"Signing in as {}...\".format(username))\n    token = registry_login(username, password)\n    update_cli_config({AUTH_TOKEN_KEY: token})\n    click.echo(\"Successfully signed in: {}.\".format(username))\n"
  },
  {
    "path": "aea/cli/logout.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Implementation of the 'aea logout' subcommand.\"\"\"\n\nimport click\n\nfrom aea.cli.registry.logout import registry_logout\nfrom aea.cli.registry.settings import AUTH_TOKEN_KEY\nfrom aea.cli.utils.config import update_cli_config\n\n\n@click.command(name=\"logout\", help=\"Logout from the registry account.\")\ndef logout() -> None:\n    \"\"\"Logout from the registry account.\"\"\"\n    click.echo(\"Logging out...\")\n    do_logout()\n    click.echo(\"Successfully logged out.\")\n\n\ndef do_logout() -> None:\n    \"\"\"Logout from Registry account.\"\"\"\n    registry_logout()\n    update_cli_config({AUTH_TOKEN_KEY: None})\n"
  },
  {
    "path": "aea/cli/plugin.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Plug-in system for adding new CLI commands.\"\"\"\nimport os\nimport sys\nimport traceback\nfrom typing import Callable, Iterable, List\n\nimport click\nimport pkg_resources\n\n\ndef with_plugins(plugins: Iterable[pkg_resources.EntryPoint]) -> Callable:\n    \"\"\"\n    A decorator to register external CLI commands to an instance of `click.Group()`.\n\n    :param plugins: An iterable producing one `pkg_resources.EntryPoint()` per iteration.\n    :return: a click.Group instance.\n    \"\"\"\n\n    def decorator(group: click.Group) -> click.Group:\n        if not isinstance(group, click.Group):\n            raise TypeError(\n                \"Plugins can only be attached to an instance of click.Group()\"\n            )\n\n        for entry_point in plugins or ():\n            try:\n                group.add_command(entry_point.load())\n            except Exception:  # pylint: disable=broad-except\n                # Catch this so a busted plugin doesn't take down the CLI.\n                # Handled by registering a dummy command that does nothing\n                # other than explain the error.\n                group.add_command(BrokenCommand(entry_point.name))\n\n        return group\n\n    return decorator\n\n\nclass BrokenCommand(click.Command):\n    \"\"\"\n    Helper click.Command in case a broken plug-in is loaded.\n\n    Rather than completely crash the CLI when a broken plugin is loaded, this\n    class provides a modified help message informing the user that the plugin is\n    broken and they should contact the owner.  If the user executes the plugin\n    or specifies `--help` a traceback is reported showing the exception the\n    plugin loader encountered.\n    \"\"\"\n\n    def __init__(self, name: str) -> None:\n        \"\"\"\n        Define the special help messages after instantiating a `click.Command()`.\n\n        :param name: the name of the command.\n        \"\"\"\n\n        click.Command.__init__(self, name)\n\n        util_name = os.path.basename(sys.argv and sys.argv[0] or __file__)\n        self.help = (\n            \"\\nWarning: entry point could not be loaded. Contact \"\n            \"its author for help.\\n\\n\\b\\n\" + traceback.format_exc()\n        )\n        self.short_help = \" Warning: could not load plugin. See `%s %s --help`.\" % (\n            util_name,\n            self.name,\n        )\n\n    def invoke(self, ctx: click.Context) -> None:\n        \"\"\"\n        Print the traceback instead of doing nothing.\n\n        :param ctx: the click.Context object.\n        \"\"\"\n\n        click.echo(self.help, color=ctx.color)\n        ctx.exit(1)\n\n    def parse_args(self, ctx: click.Context, args: List) -> List:\n        \"\"\"\n        Parse arguments.\n\n        :param ctx: the click.Context object.\n        :param args: the raw arguments.\n        :return: the arguments, parsed.\n        \"\"\"\n        return args\n"
  },
  {
    "path": "aea/cli/publish.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Implementation of the 'aea publish' subcommand.\"\"\"\n\nimport os\nfrom abc import ABC, abstractmethod\nfrom contextlib import suppress\nfrom pathlib import Path\nfrom shutil import copyfile\nfrom typing import cast\n\nimport click\n\nfrom aea.cli.push import _save_item_locally as _push_item_locally\nfrom aea.cli.registry.publish import publish_agent\nfrom aea.cli.registry.push import push_item as _push_item_remote\nfrom aea.cli.registry.utils import get_package_meta\nfrom aea.cli.utils.click_utils import registry_flag\nfrom aea.cli.utils.config import validate_item_config\nfrom aea.cli.utils.context import Context\nfrom aea.cli.utils.decorators import check_aea_project\nfrom aea.cli.utils.exceptions import AEAConfigException\nfrom aea.cli.utils.package_utils import (\n    try_get_item_source_path,\n    try_get_item_target_path,\n)\nfrom aea.configurations.base import AgentConfig, CRUDCollection, PublicId\nfrom aea.configurations.constants import (\n    AGENT,\n    AGENTS,\n    CONNECTIONS,\n    CONTRACTS,\n    DEFAULT_AEA_CONFIG_FILE,\n    ITEM_TYPE_PLURAL_TO_TYPE,\n    PROTOCOLS,\n    SKILLS,\n)\n\n\nPUSH_ITEMS_FLAG = \"--push-missing\"\n\n\n@click.command(name=\"publish\")\n@registry_flag(\n    help_local=\"For publishing agent to local folder.\",\n    help_remote=\"For publishing agent to remote registry.\",\n)\n@click.option(\n    \"--push-missing\", is_flag=True, help=\"Push missing components to registry.\"\n)\n@click.pass_context\n@check_aea_project\ndef publish(\n    click_context: click.Context, local: bool, remote: bool, push_missing: bool\n) -> None:  # pylint: disable=unused-argument\n    \"\"\"Publish the agent to the registry.\"\"\"\n    ctx = cast(Context, click_context.obj)\n    _validate_pkp(ctx.agent_config.private_key_paths)\n    _validate_config(ctx)\n\n    if remote:\n        _publish_agent_remote(ctx, push_missing=push_missing)\n    else:\n        _save_agent_locally(\n            ctx, is_mixed=not local and not remote, push_missing=push_missing\n        )\n\n\ndef _validate_config(ctx: Context) -> None:\n    \"\"\"\n    Validate agent config.\n\n    :param ctx: Context object.\n\n    :raises ClickException: if validation is failed.\n    \"\"\"\n    try:\n        validate_item_config(AGENT, Path(ctx.cwd))\n    except AEAConfigException as e:  # pragma: no cover\n        raise click.ClickException(\"Failed to validate agent config. {}\".format(str(e)))\n\n\ndef _validate_pkp(private_key_paths: CRUDCollection) -> None:\n    \"\"\"\n    Prevent to publish agents with non-empty private_key_paths.\n\n    :param private_key_paths: private_key_paths from agent config.\n    :raises ClickException: if private_key_paths is not empty.\n    \"\"\"\n    if private_key_paths.read_all() != []:\n        raise click.ClickException(\n            \"You are not allowed to publish agents with non-empty private_key_paths. Use the `aea remove-key` command to remove key paths from `private_key_paths: {}` in `aea-config.yaml`.\"\n        )\n\n\nclass BaseRegistry(ABC):\n    \"\"\"Base registry class.\"\"\"\n\n    @abstractmethod\n    def check_item_present(self, item_type_plural: str, public_id: PublicId) -> None:\n        \"\"\"\n        Check item present in registry.\n\n        Raise ClickException if not found.\n\n        :param item_type_plural: str, item type.\n        :param public_id: PublicId of the item to check.\n\n        :return: None\n        \"\"\"\n\n    @abstractmethod\n    def push_item(self, item_type_plural: str, public_id: PublicId) -> None:\n        \"\"\"\n        Push item to registry.\n\n        :param item_type_plural: str, item type.\n        :param public_id: PublicId of the item to check.\n\n        :return: None\n        \"\"\"\n\n    def check_item_present_and_push(\n        self, item_type_plural: str, public_id: PublicId\n    ) -> None:\n        \"\"\"\n        Check item present in registry and push if needed.\n\n        Raise ClickException if not found.\n\n        :param item_type_plural: str, item type.\n        :param public_id: PublicId of the item to check.\n\n        :return: None\n        \"\"\"\n\n        with suppress(click.ClickException):\n            return self.check_item_present(item_type_plural, public_id)\n\n        try:\n            self.push_item(item_type_plural, public_id)\n        except Exception as e:\n            raise click.ClickException(\n                f\"Failed to push missing item: {item_type_plural} {public_id}: {e}\"\n            ) from e\n\n        try:\n            self.check_item_present(item_type_plural, public_id)\n        except Exception as e:\n            raise click.ClickException(\n                f\"Failed to find item after push: {item_type_plural} {public_id}: {e}\"\n            ) from e\n\n\nclass LocalRegistry(BaseRegistry):\n    \"\"\"Local directory registry.\"\"\"\n\n    def __init__(self, ctx: Context):\n        \"\"\"Init registry.\"\"\"\n        self.ctx = ctx\n        try:\n            self.registry_path = ctx.registry_path\n        except ValueError as e:  # pragma: nocover\n            raise click.ClickException(str(e))\n\n    def check_item_present(self, item_type_plural: str, public_id: PublicId) -> None:\n        \"\"\"\n        Check item present in registry.\n\n        Raise ClickException if not found.\n\n        :param item_type_plural: str, item type.\n        :param public_id: PublicId of the item to check.\n        \"\"\"\n        try:\n            try_get_item_source_path(\n                self.registry_path, public_id.author, item_type_plural, public_id.name\n            )\n        except click.ClickException as e:\n            raise click.ClickException(\n                f\"Dependency is missing. {str(e)}\\nPlease push it first and then retry or use {PUSH_ITEMS_FLAG} flag to push automatically.\"\n            )\n\n    def push_item(self, item_type_plural: str, public_id: PublicId) -> None:\n        \"\"\"\n        Push item to registry.\n\n        :param item_type_plural: str, item type.\n        :param public_id: PublicId of the item to check.\n        \"\"\"\n        item_type = ITEM_TYPE_PLURAL_TO_TYPE[item_type_plural]\n        _push_item_locally(self.ctx, item_type, public_id)\n\n\nclass MixedRegistry(LocalRegistry):\n    \"\"\"Mixed remote and local component registry.\"\"\"\n\n    def check_item_present(self, item_type_plural: str, public_id: PublicId) -> None:\n        \"\"\"\n        Check item present in registry.\n\n        Raise ClickException if not found.\n\n        :param item_type_plural: str, item type.\n        :param public_id: PublicId of the item to check.\n        \"\"\"\n        item_type = ITEM_TYPE_PLURAL_TO_TYPE[item_type_plural]\n        try:\n            LocalRegistry.check_item_present(self, item_type_plural, public_id)\n        except click.ClickException:\n            click.echo(\n                f\"Can not find dependency locally: {item_type} {public_id}. Trying remote registry...\"\n            )\n\n        try:\n            RemoteRegistry(self.ctx).check_item_present(item_type_plural, public_id)\n        except click.ClickException:\n            raise click.ClickException(\n                f\"Can not find dependency locally or remotely: {item_type} {public_id}. Try to add flag `{PUSH_ITEMS_FLAG}` to push dependency package to the registry.\"\n            )\n\n\nclass RemoteRegistry(BaseRegistry):\n    \"\"\"Remote components registry.\"\"\"\n\n    def __init__(self, ctx: Context) -> None:\n        \"\"\"Init registry.\"\"\"\n        self.ctx = ctx\n\n    def check_item_present(self, item_type_plural: str, public_id: PublicId) -> None:\n        \"\"\"\n        Check item present in registry.\n\n        Raise ClickException if not found.\n\n        :param item_type_plural: str, item type.\n        :param public_id: PublicId of the item to check.\n        \"\"\"\n        item_type = ITEM_TYPE_PLURAL_TO_TYPE[item_type_plural]\n        try:\n            get_package_meta(item_type, public_id)\n        except click.ClickException as e:\n            raise click.ClickException(\n                f\"Package not found in remote registry: {str(e)}. You can try to add {PUSH_ITEMS_FLAG} flag.\"\n            )\n\n    def push_item(self, item_type_plural: str, public_id: PublicId) -> None:\n        \"\"\"\n        Push item to registry.\n\n        :param item_type_plural: str, item type.\n        :param public_id: PublicId of the item to check.\n        \"\"\"\n        item_type = ITEM_TYPE_PLURAL_TO_TYPE[item_type_plural]\n        _push_item_remote(self.ctx, item_type, public_id)\n\n\ndef _check_dependencies_in_registry(\n    registry: BaseRegistry, agent_config: AgentConfig, push_missing: bool\n) -> None:\n    \"\"\"Check all agent dependencies present in registry.\"\"\"\n    for item_type_plural in (PROTOCOLS, CONTRACTS, CONNECTIONS, SKILLS):\n        dependencies = getattr(agent_config, item_type_plural)\n        for public_id in dependencies:\n            if push_missing:\n                registry.check_item_present_and_push(item_type_plural, public_id)\n            else:\n                registry.check_item_present(item_type_plural, public_id)\n\n\ndef _save_agent_locally(\n    ctx: Context, is_mixed: bool = False, push_missing: bool = False\n) -> None:\n    \"\"\"\n    Save agent to local packages.\n\n    :param ctx: the context\n    :param is_mixed: whether or not to fetch in mixed mode\n    :param push_missing: bool. flag to push missing items\n    \"\"\"\n    try:\n        registry_path = ctx.registry_path\n    except ValueError as e:  # pragma: nocover\n        raise click.ClickException(str(e))\n\n    registry = MixedRegistry(ctx) if is_mixed else LocalRegistry(ctx)\n\n    _check_dependencies_in_registry(registry, ctx.agent_config, push_missing)\n\n    item_type_plural = AGENTS\n\n    target_dir = try_get_item_target_path(\n        registry_path,\n        ctx.agent_config.author,\n        item_type_plural,\n        ctx.agent_config.name,\n    )\n    if not os.path.exists(target_dir):\n        os.makedirs(target_dir, exist_ok=True)\n\n    source_path = os.path.join(ctx.cwd, DEFAULT_AEA_CONFIG_FILE)\n    target_path = os.path.join(target_dir, DEFAULT_AEA_CONFIG_FILE)\n    copyfile(source_path, target_path)\n    click.echo(\n        f'Agent \"{ctx.agent_config.name}\" successfully saved in packages folder.'\n    )\n\n\ndef _publish_agent_remote(ctx: Context, push_missing: bool) -> None:\n    \"\"\"\n    Push agent to remote registry.\n\n    :param ctx: the context\n    :param push_missing: bool. flag to push missing items\n    \"\"\"\n    registry = RemoteRegistry(ctx)\n    _check_dependencies_in_registry(registry, ctx.agent_config, push_missing)\n    publish_agent(ctx)\n"
  },
  {
    "path": "aea/cli/push.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Implementation of the 'aea push' subcommand.\"\"\"\nimport os\nfrom shutil import copytree\nfrom typing import cast\n\nimport click\nfrom click.exceptions import ClickException\n\nfrom aea.cli.registry.push import check_package_public_id, push_item\nfrom aea.cli.utils.click_utils import PublicIdParameter\nfrom aea.cli.utils.context import Context\nfrom aea.cli.utils.decorators import check_aea_project, pass_ctx\nfrom aea.cli.utils.package_utils import (\n    try_get_item_source_path,\n    try_get_item_target_path,\n)\nfrom aea.configurations.base import PublicId\nfrom aea.configurations.constants import CONNECTION, CONTRACT, PROTOCOL, SKILL\n\n\n@click.group()\n@click.option(\"--local\", is_flag=True, help=\"For pushing items to local folder.\")\n@click.pass_context\n@check_aea_project\ndef push(click_context: click.Context, local: bool) -> None:\n    \"\"\"Push a non-vendor package of the agent to the registry.\"\"\"\n    ctx = cast(Context, click_context.obj)\n    ctx.set_config(\"local\", local)\n\n\n@push.command(name=CONNECTION)\n@click.argument(\"connection-id\", type=PublicIdParameter(), required=True)\n@pass_ctx\ndef connection(ctx: Context, connection_id: PublicId) -> None:\n    \"\"\"Push a connection to the registry or save it in local registry.\"\"\"\n    if ctx.config.get(\"local\"):\n        _save_item_locally(ctx, CONNECTION, connection_id)\n    else:\n        push_item(ctx, CONNECTION, connection_id)\n\n\n@push.command(name=CONTRACT)\n@click.argument(\"contract-id\", type=PublicIdParameter(), required=True)\n@pass_ctx\ndef contract(ctx: Context, contract_id: PublicId) -> None:\n    \"\"\"Push a contract to the registry or save it in local registry.\"\"\"\n    if ctx.config.get(\"local\"):\n        _save_item_locally(ctx, CONTRACT, contract_id)\n    else:\n        push_item(ctx, CONTRACT, contract_id)\n\n\n@push.command(name=PROTOCOL)\n@click.argument(\"protocol-id\", type=PublicIdParameter(), required=True)\n@pass_ctx\ndef protocol(ctx: Context, protocol_id: PublicId) -> None:\n    \"\"\"Push a protocol to the registry or save it in local registry.\"\"\"\n    if ctx.config.get(\"local\"):\n        _save_item_locally(ctx, PROTOCOL, protocol_id)\n    else:\n        push_item(ctx, PROTOCOL, protocol_id)\n\n\n@push.command(name=SKILL)\n@click.argument(\"skill-id\", type=PublicIdParameter(), required=True)\n@pass_ctx\ndef skill(ctx: Context, skill_id: PublicId) -> None:\n    \"\"\"Push a skill to the registry or save it in local registry.\"\"\"\n    if ctx.config.get(\"local\"):\n        _save_item_locally(ctx, SKILL, skill_id)\n    else:\n        push_item(ctx, SKILL, skill_id)\n\n\ndef _save_item_locally(ctx: Context, item_type: str, item_id: PublicId) -> None:\n    \"\"\"\n    Save item to local packages.\n\n    :param ctx: click context\n    :param item_type: str type of item (connection/protocol/skill).\n    :param item_id: the public id of the item.\n    \"\"\"\n    item_type_plural = item_type + \"s\"\n    try:\n        # try non vendor first\n        source_path = try_get_item_source_path(\n            ctx.cwd, None, item_type_plural, item_id.name\n        )\n    except ClickException:\n        # failed on user's packages\n        #  try vendors\n        source_path = try_get_item_source_path(\n            os.path.join(ctx.cwd, \"vendor\"),\n            item_id.author,\n            item_type_plural,\n            item_id.name,\n        )\n\n    check_package_public_id(source_path, item_type, item_id)\n\n    try:\n        registry_path = ctx.registry_path\n    except ValueError as e:  # pragma: nocover\n        raise click.ClickException(str(e))\n    target_path = try_get_item_target_path(\n        registry_path,\n        item_id.author,\n        item_type_plural,\n        item_id.name,\n    )\n    copytree(source_path, target_path)\n    click.echo(\n        f'{item_type.title()} \"{item_id}\" successfully saved in packages folder.'\n    )\n"
  },
  {
    "path": "aea/cli/register.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Implementation of the 'aea login' subcommand.\"\"\"\n\nimport click\n\nfrom aea.cli.registry.registration import register as register_new_account\nfrom aea.cli.registry.settings import AUTH_TOKEN_KEY\nfrom aea.cli.utils.config import update_cli_config\nfrom aea.cli.utils.package_utils import validate_author_name\n\n\n@click.command(name=\"register\", help=\"Create a new registry account.\")\n@click.option(\"--username\", type=str, required=True, prompt=True)\n@click.option(\"--email\", type=str, required=True, prompt=True)\n@click.option(\"--password\", type=str, required=True, prompt=True, hide_input=True)\n@click.option(\n    \"--confirm_password\", type=str, required=True, prompt=True, hide_input=True\n)\n@click.option(\"--no-subscribe\", is_flag=True, help=\"For developers subscription.\")\ndef register(\n    username: str, email: str, password: str, confirm_password: str, no_subscribe: bool\n) -> None:\n    \"\"\"Create a new registry account.\"\"\"\n    do_register(username, email, password, confirm_password, no_subscribe)\n\n\ndef do_register(\n    username: str,\n    email: str,\n    password: str,\n    password_confirmation: str,\n    no_subscribe: bool,\n) -> None:\n    \"\"\"\n    Register a new Registry account and save auth token.\n\n    :param username: str username.\n    :param email: str email.\n    :param password: str password.\n    :param password_confirmation: str password confirmation.\n    :param no_subscribe: bool flag for developers subscription skip on register.\n    \"\"\"\n    username = validate_author_name(username)\n    token = register_new_account(username, email, password, password_confirmation)\n    update_cli_config({AUTH_TOKEN_KEY: token})\n    if not no_subscribe and click.confirm(\n        \"Do you want to subscribe for developer news?\"\n    ):\n        click.echo(\n            \"Please visit `https://aea-registry.fetch.ai/mailing-list` \"\n            \"to subscribe for developer news\"\n        )\n    click.echo(\"Successfully registered and logged in: {}\".format(username))\n"
  },
  {
    "path": "aea/cli/registry/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains tools for operating Registry with CLI.\"\"\"\n"
  },
  {
    "path": "aea/cli/registry/add.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Registry utils used for CLI add command.\"\"\"\n\nimport os\nfrom pathlib import Path\nfrom typing import cast\n\nfrom aea.cli.registry.utils import download_file, extract, get_package_meta\nfrom aea.cli.utils.loggers import logger\nfrom aea.configurations.base import PublicId\n\n\ndef fetch_package(obj_type: str, public_id: PublicId, cwd: str, dest: str) -> Path:\n    \"\"\"\n    Fetch a package (connection/contract/protocol/skill) from Registry.\n\n    :param obj_type: str type of object you want to fetch:\n        'connection', 'protocol', 'skill'\n    :param public_id: str public ID of object.\n    :param cwd: str path to current working directory.\n    :param dest: destination where to save package.\n\n    :return: package path\n    \"\"\"\n    logger.debug(\n        \"Fetching {obj_type} {public_id} from Registry...\".format(\n            public_id=public_id, obj_type=obj_type\n        )\n    )\n\n    logger.debug(\n        \"Downloading {obj_type} {public_id}...\".format(\n            public_id=public_id, obj_type=obj_type\n        )\n    )\n    package_meta = get_package_meta(obj_type, public_id)\n    file_url = cast(str, package_meta[\"file\"])\n    filepath = download_file(file_url, cwd)\n\n    # next code line is needed because the items are stored in tarball packages as folders\n    dest = os.path.split(dest)[0]\n    logger.debug(\n        \"Extracting {obj_type} {public_id}...\".format(\n            public_id=public_id, obj_type=obj_type\n        )\n    )\n    extract(filepath, dest)\n    logger.debug(\n        \"Successfully fetched {obj_type} '{public_id}'.\".format(\n            public_id=public_id, obj_type=obj_type\n        )\n    )\n    package_path = os.path.join(dest, public_id.name)\n    return Path(package_path)\n"
  },
  {
    "path": "aea/cli/registry/fetch.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Methods for CLI fetch functionality.\"\"\"\nimport os\nimport shutil\nfrom pathlib import Path\nfrom typing import Optional, cast\n\nimport click\nfrom click.exceptions import ClickException\n\nfrom aea.cli.add import add_item\nfrom aea.cli.registry.utils import download_file, extract, request_api\nfrom aea.cli.utils.config import try_to_load_agent_config\nfrom aea.cli.utils.context import Context\nfrom aea.cli.utils.decorators import clean_after\nfrom aea.common import JSONLike\nfrom aea.configurations.base import PublicId\nfrom aea.configurations.constants import (\n    CONNECTION,\n    CONTRACT,\n    DEFAULT_AEA_CONFIG_FILE,\n    PROTOCOL,\n    SKILL,\n)\nfrom aea.helpers.io import open_file\n\n\n@clean_after\ndef fetch_agent(\n    ctx: Context,\n    public_id: PublicId,\n    alias: Optional[str] = None,\n    target_dir: Optional[str] = None,\n) -> None:\n    \"\"\"\n    Fetch Agent from Registry.\n\n    :param ctx: Context\n    :param public_id: str public ID of desirable agent.\n    :param alias: an optional alias.\n    :param target_dir: the target directory to which the agent is fetched.\n    \"\"\"\n    author, name, version = public_id.author, public_id.name, public_id.version\n\n    folder_name = target_dir or (name if alias is None else alias)\n    aea_folder = os.path.join(ctx.cwd, folder_name)\n    if os.path.exists(aea_folder):\n        path = Path(aea_folder)\n        raise ClickException(\n            f'Item \"{path.name}\" already exists in target folder \"{path.parent}\".'\n        )\n\n    ctx.clean_paths.append(aea_folder)\n\n    api_path = f\"/agents/{author}/{name}/{version}\"\n    resp = cast(JSONLike, request_api(\"GET\", api_path))\n    file_url = cast(str, resp[\"file\"])\n    filepath = download_file(file_url, ctx.cwd)\n\n    extract(filepath, ctx.cwd)\n\n    if alias or target_dir:\n        shutil.move(\n            os.path.join(ctx.cwd, name),\n            aea_folder,\n        )\n\n    ctx.cwd = aea_folder\n    try_to_load_agent_config(ctx)\n\n    if alias is not None:\n        ctx.agent_config.agent_name = alias\n        with open_file(os.path.join(ctx.cwd, DEFAULT_AEA_CONFIG_FILE), \"w\") as fp:\n            ctx.agent_loader.dump(ctx.agent_config, fp)\n\n    click.echo(\"Fetching dependencies...\")\n    for item_type in (CONNECTION, CONTRACT, SKILL, PROTOCOL):\n        item_type_plural = item_type + \"s\"\n\n        # initialize fetched agent with empty folders for custom packages\n        custom_items_folder = os.path.join(ctx.cwd, item_type_plural)\n        os.makedirs(custom_items_folder, exist_ok=True)\n\n        config = getattr(ctx.agent_config, item_type_plural)\n        for item_public_id in config:\n            try:\n                add_item(ctx, item_type, item_public_id)\n            except Exception as e:\n                raise click.ClickException(\n                    f'Unable to fetch dependency for agent \"{name}\", aborting. {e}'\n                )\n    click.echo(\"Dependencies successfully fetched.\")\n    click.echo(f\"Agent {name} successfully fetched to {aea_folder}.\")\n"
  },
  {
    "path": "aea/cli/registry/login.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Registry utils used for CLI login command.\"\"\"\n\nfrom typing import cast\n\nfrom aea.cli.registry.utils import request_api\nfrom aea.common import JSONLike\n\n\ndef registry_login(username: str, password: str) -> str:\n    \"\"\"\n    Login into Registry account.\n\n    :param username: str username.\n    :param password: str password.\n\n    :return: str token\n    \"\"\"\n    resp = cast(\n        JSONLike,\n        request_api(\n            \"POST\",\n            \"/rest-auth/login/\",\n            data={\"username\": username, \"password\": password},\n        ),\n    )\n    return cast(str, resp[\"key\"])\n\n\ndef registry_reset_password(email: str) -> None:\n    \"\"\"\n    Request Registry to reset password.\n\n    :param email: user email.\n    \"\"\"\n    request_api(\"POST\", \"/rest-auth/password/reset/\", data={\"email\": email})\n"
  },
  {
    "path": "aea/cli/registry/logout.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Registry utils used for CLI logout command.\"\"\"\n\nfrom aea.cli.registry.utils import request_api\n\n\ndef registry_logout() -> None:\n    \"\"\"Logout from Registry account.\"\"\"\n    request_api(\"POST\", \"/rest-auth/logout/\")\n"
  },
  {
    "path": "aea/cli/registry/publish.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Methods for CLI publish functionality.\"\"\"\n\nimport os\nimport shutil\nimport tarfile\nimport tempfile\nfrom typing import cast\n\nimport click\n\nfrom aea.cli.registry.utils import (\n    check_is_author_logged_in,\n    clean_tarfiles,\n    request_api,\n)\nfrom aea.cli.utils.config import try_to_load_agent_config\nfrom aea.cli.utils.context import Context\nfrom aea.cli.utils.generic import is_readme_present\nfrom aea.cli.utils.loggers import logger\nfrom aea.common import JSONLike\nfrom aea.configurations.constants import (\n    CONNECTIONS,\n    CONTRACTS,\n    DEFAULT_AEA_CONFIG_FILE,\n    DEFAULT_README_FILE,\n    PROTOCOLS,\n    SKILLS,\n)\n\n\ndef _compress(output_filename: str, *filepaths: str) -> None:\n    \"\"\"Compare the output file.\"\"\"\n    with tarfile.open(output_filename, \"w:gz\") as f:\n        for filepath in filepaths:\n            f.add(filepath, arcname=os.path.basename(filepath))\n\n\n@clean_tarfiles\ndef publish_agent(ctx: Context) -> None:\n    \"\"\"Publish an agent.\"\"\"\n    try_to_load_agent_config(ctx)\n    check_is_author_logged_in(ctx.agent_config.author)\n\n    name = ctx.agent_config.agent_name\n    config_file_source_path = os.path.join(ctx.cwd, DEFAULT_AEA_CONFIG_FILE)\n    readme_source_path = os.path.join(ctx.cwd, DEFAULT_README_FILE)\n    output_tar = os.path.join(ctx.cwd, \"{}.tar.gz\".format(name))\n\n    with tempfile.TemporaryDirectory() as temp_dir:\n        package_dir = os.path.join(temp_dir, name)\n        os.makedirs(package_dir)\n        config_file_target_path = os.path.join(package_dir, DEFAULT_AEA_CONFIG_FILE)\n        shutil.copy(config_file_source_path, config_file_target_path)\n        if is_readme_present(readme_source_path):\n            readme_file_target_path = os.path.join(package_dir, DEFAULT_README_FILE)\n            shutil.copy(readme_source_path, readme_file_target_path)\n\n        _compress(output_tar, package_dir)\n\n    data = {\n        \"name\": name,\n        \"description\": ctx.agent_config.description,\n        \"version\": ctx.agent_config.version,\n        CONNECTIONS: ctx.agent_config.connections,\n        CONTRACTS: ctx.agent_config.contracts,\n        PROTOCOLS: ctx.agent_config.protocols,\n        SKILLS: ctx.agent_config.skills,\n    }\n\n    files = {}\n    try:\n        files[\"file\"] = open(output_tar, \"rb\")  # pylint: disable=consider-using-with\n        if is_readme_present(readme_source_path):\n            files[\"readme\"] = open(  # pylint: disable=consider-using-with\n                readme_source_path, \"rb\"\n            )\n        path = \"/agents/create\"\n        logger.debug(\"Publishing agent {} to Registry ...\".format(name))\n        resp = cast(\n            JSONLike, request_api(\"POST\", path, data=data, is_auth=True, files=files)\n        )\n    finally:\n        for fd in files.values():\n            fd.close()\n    click.echo(\n        \"Successfully published agent {} to the Registry. Public ID: {}\".format(\n            name, resp[\"public_id\"]\n        )\n    )\n"
  },
  {
    "path": "aea/cli/registry/push.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Methods for CLI push functionality.\"\"\"\n\nimport os\nimport shutil\nimport tarfile\nfrom typing import List, Tuple, cast\n\nimport click\n\nfrom aea.cli.registry.utils import (\n    check_is_author_logged_in,\n    clean_tarfiles,\n    list_missing_packages,\n    request_api,\n)\nfrom aea.cli.utils.context import Context\nfrom aea.cli.utils.generic import is_readme_present, load_yaml\nfrom aea.cli.utils.loggers import logger\nfrom aea.common import JSONLike\nfrom aea.configurations.base import PublicId\nfrom aea.configurations.constants import (\n    CONNECTIONS,\n    CONTRACTS,\n    DEFAULT_README_FILE,\n    ITEM_TYPE_PLURAL_TO_TYPE,\n    PROTOCOLS,\n    SKILLS,\n)\n\n\ndef _remove_pycache(source_dir: str) -> None:\n    pycache_path = os.path.join(source_dir, \"__pycache__\")\n    if os.path.exists(pycache_path):\n        shutil.rmtree(pycache_path)\n\n\ndef _compress_dir(output_filename: str, source_dir: str) -> None:\n    _remove_pycache(source_dir)\n    with tarfile.open(output_filename, \"w:gz\") as f:\n        f.add(source_dir, arcname=os.path.basename(source_dir))\n\n\ndef load_component_public_id(source_path: str, item_type: str) -> PublicId:\n    \"\"\"Get component version from source path.\"\"\"\n    config = load_yaml(os.path.join(source_path, item_type + \".yaml\"))\n    item_author = config.get(\"author\", \"\")\n    item_name = config.get(\"name\", \"\")\n    item_version = config.get(\"version\", \"\")\n    return PublicId(item_author, item_name, item_version)\n\n\ndef check_package_public_id(\n    source_path: str, item_type: str, item_id: PublicId\n) -> PublicId:\n    \"\"\"\n    Check component version is corresponds to specified version.\n\n    :param source_path: the source path\n    :param item_type: str type of item (connection/protocol/skill).\n    :param item_id: item public id.\n    :return: actual package public id\n    \"\"\"\n    # we load only based on item_name, hence also check item_version and item_author match.\n\n    actual_item_id = load_component_public_id(source_path, item_type)\n    if not actual_item_id.same_prefix(item_id) or (\n        not item_id.package_version.is_latest\n        and item_id.version != actual_item_id.version\n    ):\n        raise click.ClickException(\n            \"Version, name or author does not match. Expected '{}', found '{}'\".format(\n                item_id,\n                actual_item_id.author\n                + \"/\"\n                + actual_item_id.name\n                + \":\"\n                + actual_item_id.version,\n            )\n        )\n    return actual_item_id\n\n\n@clean_tarfiles\ndef push_item(ctx: Context, item_type: str, item_id: PublicId) -> None:\n    \"\"\"\n    Push item to the Registry.\n\n    :param ctx: click context\n    :param item_type: str type of item (connection/protocol/skill).\n    :param item_id: item public id.\n    \"\"\"\n    item_type_plural = item_type + \"s\"\n\n    items_folder = os.path.join(ctx.cwd, item_type_plural)\n    item_path = os.path.join(items_folder, item_id.name)\n\n    if not os.path.exists(item_path):\n        raise click.ClickException(\n            '{} \"{}\" not found  in {}. Make sure you run push command '\n            \"from a correct folder.\".format(\n                item_type.title(), item_id.name, items_folder\n            )\n        )\n\n    check_package_public_id(item_path, item_type, item_id)\n\n    item_config_filepath = os.path.join(item_path, \"{}.yaml\".format(item_type))\n    logger.debug(\"Reading {} {} config ...\".format(item_id.name, item_type))\n    item_config = load_yaml(item_config_filepath)\n    check_is_author_logged_in(item_config[\"author\"])\n\n    logger.debug(\n        \"Searching for {} {} in {} ...\".format(item_id.name, item_type, items_folder)\n    )\n\n    output_filename = \"{}.tar.gz\".format(item_id.name)\n    logger.debug(\n        \"Compressing {} {} to {} ...\".format(item_id.name, item_type, output_filename)\n    )\n    _compress_dir(output_filename, item_path)\n    output_filepath = os.path.join(ctx.cwd, output_filename)\n\n    data = {\n        \"name\": item_id.name,\n        \"description\": item_config[\"description\"],\n        \"version\": item_config[\"version\"],\n    }\n\n    # dependencies\n    dependencies: List[Tuple[str, PublicId]] = []\n    for key in [CONNECTIONS, CONTRACTS, PROTOCOLS, SKILLS]:\n        deps_list = item_config.get(key, [])\n        if deps_list:\n            data.update({key: deps_list})\n        for dep in deps_list:\n            dependencies.append((ITEM_TYPE_PLURAL_TO_TYPE[key], PublicId.from_str(dep)))\n\n    missing_dependencies = list_missing_packages(dependencies)\n\n    if missing_dependencies:\n        for package_type, package_id in missing_dependencies:\n            click.echo(f\"Error: Cannot find {package_type} {package_id} in registry!\")\n        raise click.ClickException(\"Found missing dependencies! Push canceled!\")\n    try:\n        files = {\n            \"file\": open(output_filepath, \"rb\")  # pylint: disable=consider-using-with\n        }\n        readme_path = os.path.join(item_path, DEFAULT_README_FILE)\n        if is_readme_present(readme_path):\n            files[\"readme\"] = open(  # pylint: disable=consider-using-with\n                readme_path, \"rb\"\n            )\n\n        path = \"/{}/create\".format(item_type_plural)\n        logger.debug(\"Pushing {} {} to Registry ...\".format(item_id.name, item_type))\n        resp = cast(\n            JSONLike, request_api(\"POST\", path, data=data, is_auth=True, files=files)\n        )\n        click.echo(\n            \"Successfully pushed {} {} to the Registry. Public ID: {}\".format(\n                item_type, item_id.name, resp[\"public_id\"]\n            )\n        )\n    finally:\n        for fd in files.values():\n            fd.close()\n"
  },
  {
    "path": "aea/cli/registry/registration.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Module with methods for new user registration.\"\"\"\n\nfrom typing import Dict, List, cast\n\nfrom click import ClickException\n\nfrom aea.cli.registry.utils import request_api\n\n\ndef register(\n    username: str, email: str, password: str, password_confirmation: str\n) -> str:\n    \"\"\"\n    Register new Registry account and automatically login if successful.\n\n    :param username: str username.\n    :param email: str email.\n    :param password: str password.\n    :param password_confirmation: str password confirmation.\n\n    :return: str auth token.\n    \"\"\"\n    data = {\n        \"username\": username,\n        \"email\": email,\n        \"password1\": password,\n        \"password2\": password_confirmation,\n    }\n    resp_json, status_code = request_api(\n        \"POST\",\n        \"/rest-auth/registration/\",\n        data=data,\n        handle_400=False,\n        return_code=True,\n    )\n    resp_json = cast(Dict, resp_json)\n    if status_code == 400:\n        errors: List[str] = []\n        for key in (\"username\", \"email\", \"password1\", \"password2\"):\n            param_errors = cast(str, resp_json.get(key))\n            if param_errors:\n                errors.extend(param_errors)\n\n        raise ClickException(\n            \"Errors occured during registration.\\n\" + \"\\n\".join(errors)\n        )\n    return cast(str, resp_json[\"key\"])\n"
  },
  {
    "path": "aea/cli/registry/settings.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Settings for operating Registry with CLI.\"\"\"\n\n\nREGISTRY_API_URL = \"https://agents-registry.prod.fetch-ai.com/api/v1\"\n# we ignore issue B105 because this is not an hard-coded authentication token,\n# but the name of the field in the configuration file.\nAUTH_TOKEN_KEY = \"auth_token\"  # nosec\n"
  },
  {
    "path": "aea/cli/registry/utils.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Utils used for operating Registry with CLI.\"\"\"\nimport os\nimport tarfile\nfrom typing import Any, Callable, Dict, List, Optional, Tuple, Union, cast\n\nimport click\n\nfrom aea.cli.registry.settings import AUTH_TOKEN_KEY, REGISTRY_API_URL\nfrom aea.cli.utils.config import get_or_create_cli_config\nfrom aea.cli.utils.context import Context\nfrom aea.cli.utils.loggers import logger\nfrom aea.cli.utils.package_utils import find_item_locally\nfrom aea.common import JSONLike\nfrom aea.configurations.base import PublicId\nfrom aea.configurations.constants import ITEM_TYPE_TO_PLURAL\nfrom aea.helpers import http_requests as requests\n\n\nFILE_DOWNLOAD_TIMEOUT = (\n    180  # quite big number case possible slow channels and package can be quite big\n)\n\n\ndef get_auth_token() -> str:\n    \"\"\"\n    Get current auth token.\n\n    :return: str auth token\n    \"\"\"\n    config = get_or_create_cli_config()\n    return config.get(AUTH_TOKEN_KEY, None)\n\n\ndef request_api(\n    method: str,\n    path: str,\n    params: Optional[Dict] = None,\n    data: Optional[Dict] = None,\n    is_auth: bool = False,\n    files: Optional[Dict] = None,\n    handle_400: bool = True,\n    return_code: bool = False,\n) -> Union[JSONLike, Tuple[JSONLike, int]]:\n    \"\"\"\n    Request Registry API.\n\n    :param method: str request method ('GET, 'POST', 'PUT', etc.).\n    :param path: str URL path.\n    :param params: dict GET params.\n    :param data: dict POST data.\n    :param is_auth: bool is auth required (default False).\n    :param files: optional dict {file_field_name: open(filepath, \"rb\")} (default None).\n    :param handle_400: whether or not to handle 400 response\n    :param return_code: whether or not to return return_code\n\n    :return: dict response from Registry API or tuple (dict response, status code).\n    \"\"\"\n    headers = {}\n    if is_auth:\n        token = get_auth_token()\n        if token is None:\n            raise click.ClickException(\n                \"Unable to read authentication config. \"\n                'Please sign in with \"aea login\" command.'\n            )\n        headers.update({\"Authorization\": \"Token {}\".format(token)})\n    try:\n        resp = _perform_registry_request(method, path, params, data, files, headers)\n        resp_json = resp.json()\n    except requests.exceptions.ConnectionError:\n        raise click.ClickException(\"Registry server is not responding.\")\n    except requests.JSONDecodeError:\n        resp_json = None\n\n    if resp.status_code == 200:\n        pass\n    elif resp.status_code == 201:\n        logger.debug(\"Successfully created!\")\n    elif resp.status_code == 403:\n        raise click.ClickException(\n            \"\"\"You are not authenticated. 'Please sign in with \"aea login\" command.\"\"\"\n        )\n    elif resp.status_code == 500:\n        raise click.ClickException(\n            \"Registry internal server error: {}\".format(resp_json[\"detail\"])\n        )\n    elif resp.status_code == 404:\n        raise click.ClickException(\"Not found in Registry.\")\n    elif resp.status_code == 409:\n        raise click.ClickException(\n            \"Conflict in Registry. {}\".format(resp_json[\"detail\"])\n        )\n    elif resp.status_code == 400:\n        if handle_400:\n            raise click.ClickException(resp_json)\n    elif resp_json is None:\n        raise click.ClickException(\n            \"Wrong server response. Status code: {}: Response text: {}\".format(\n                resp.status_code, resp.text\n            )\n        )\n    else:\n        raise click.ClickException(\n            \"Wrong server response. Status code: {}: Error detail: {}\".format(\n                resp.status_code, resp_json.get(\"detail\", resp_json)\n            )\n        )\n\n    if return_code:\n        return resp_json, resp.status_code\n    return resp_json\n\n\ndef _perform_registry_request(\n    method: str,\n    path: str,\n    params: Optional[Dict] = None,\n    data: Optional[Dict] = None,\n    files: Optional[Dict] = None,\n    headers: Optional[Dict] = None,\n) -> requests.Response:\n    \"\"\"Perform HTTP request and resturn response object.\"\"\"\n    request_kwargs = dict(\n        method=method,\n        url=\"{}{}\".format(REGISTRY_API_URL, path),\n        params=params,\n        files=files,\n        data=data,\n        headers=headers,\n    )\n    resp = requests.request(**request_kwargs)\n    return resp\n\n\ndef download_file(url: str, cwd: str, timeout: float = FILE_DOWNLOAD_TIMEOUT) -> str:\n    \"\"\"\n    Download file from URL and save it in CWD (current working directory).\n\n    :param url: str url of the file to download.\n    :param cwd: str path to current working directory.\n    :param timeout: float. timeout to download a file\n\n    :return: str path to downloaded file\n    \"\"\"\n    local_filename = url.split(\"/\")[-1]\n    filepath = os.path.join(cwd, local_filename)\n    # NOTE the stream=True parameter below\n    response = requests.get(url, stream=True, timeout=timeout)\n    if response.status_code == 200:\n        with open(filepath, \"wb\") as f:\n            f.write(response.raw.read())\n    else:\n        raise click.ClickException(\n            \"Wrong response from server when downloading package.\"\n        )\n    return filepath\n\n\ndef extract(source: str, target: str) -> None:\n    \"\"\"\n    Extract tarball and remove source file.\n\n    :param source: str path to a source tarball file.\n    :param target: str path to target directory.\n    \"\"\"\n    if source.endswith(\"tar.gz\"):\n        tar = tarfile.open(source, \"r:gz\")  # pylint: disable=consider-using-with\n        tar.extractall(path=target)\n        tar.close()\n    else:\n        raise ValueError(\"Unknown file type: {}\".format(source))\n\n    os.remove(source)\n\n\ndef _rm_tarfiles() -> None:\n    cwd = os.getcwd()\n    for filename in os.listdir(cwd):\n        if filename.endswith(\".tar.gz\"):\n            filepath = os.path.join(cwd, filename)\n            os.remove(filepath)\n\n\ndef clean_tarfiles(func: Callable) -> Callable:\n    \"\"\"Decorate func to clean tarfiles after executing.\"\"\"\n\n    def wrapper(*args: Any, **kwargs: Any) -> Callable:\n        try:\n            result = func(*args, **kwargs)\n        except Exception as e:\n            _rm_tarfiles()\n            raise e\n        else:\n            _rm_tarfiles()\n            return result\n\n    return wrapper\n\n\ndef check_is_author_logged_in(author_name: str) -> None:\n    \"\"\"\n    Check if current user's name equals to item's author.\n\n    :param author_name: str item author username.\n\n    :raise ClickException: if username and author's name are not equal.\n    \"\"\"\n    resp = cast(JSONLike, request_api(\"GET\", \"/rest-auth/user/\", is_auth=True))\n    if not author_name == resp[\"username\"]:\n        raise click.ClickException(\n            \"Author username is not equal to current logged in username \"\n            \"(logged in: {}, author: {}). Please logout and then login correctly.\".format(\n                resp[\"username\"], author_name\n            )\n        )\n\n\ndef is_auth_token_present() -> bool:\n    \"\"\"\n    Check if any user is currently logged in.\n\n    :return: bool is logged in.\n    \"\"\"\n    return get_auth_token() is not None\n\n\ndef get_package_meta(\n    obj_type: str, public_id: PublicId, aea_version: Optional[str] = None\n) -> JSONLike:\n    \"\"\"\n    Get package meta data from remote registry.\n\n    Optionally filter by AEA version.\n\n    :param obj_type: str. component type\n    :param public_id: component public id\n    :param aea_version: the AEA version (e.g. \"0.1.0\") or None.\n\n    :return: dict with package details\n    \"\"\"\n    params = dict(aea_version=aea_version) if aea_version else None\n    api_path = f\"/{obj_type}s/{public_id.author}/{public_id.name}/{public_id.version}\"\n    resp = cast(JSONLike, request_api(\"GET\", api_path, params=params))\n    return resp\n\n\ndef get_latest_public_id_mixed(\n    ctx: Context,\n    item_type: str,\n    item_public_id: PublicId,\n    aea_version: Optional[str] = None,\n) -> PublicId:\n    \"\"\"\n    Get latest public id of the message, mixed mode.\n\n    That is, give priority to local registry, and fall back to remote registry\n    in case of failure.\n\n    :param ctx: the CLI context.\n    :param item_type: the item type.\n    :param item_public_id: the item public id.\n    :param aea_version: the AEA version constraint, or None\n    :return: the path to the found package.\n    \"\"\"\n    try:\n        _, item_config = find_item_locally(ctx, item_type, item_public_id)\n        latest_item_public_id = item_config.public_id\n    except click.ClickException:\n        logger.debug(\n            \"Get latest public id from local registry failed, trying remote registry...\"\n        )\n        # the following might raise exception, but we don't catch it this time\n        package_meta = get_package_meta(\n            item_type, item_public_id, aea_version=aea_version\n        )\n        latest_item_public_id = PublicId.from_str(cast(str, package_meta[\"public_id\"]))\n    return latest_item_public_id\n\n\ndef get_latest_version_available_in_registry(\n    ctx: Context,\n    item_type: str,\n    item_public_id: PublicId,\n    aea_version: Optional[str] = None,\n) -> PublicId:\n    \"\"\"\n    Get latest available package version public id.\n\n    Optionally consider AEA version through the `aea_version` parameter.\n\n    :param ctx: Context object.\n    :param item_type: the item type.\n    :param item_public_id: the item public id.\n    :param aea_version: the AEA version (e.g. \"0.1.0\") or None.\n    :return: the latest public id.\n    \"\"\"\n    is_local = ctx.config.get(\"is_local\")\n    is_mixed = ctx.config.get(\"is_mixed\")\n    try:\n        if is_mixed:\n            latest_item_public_id = get_latest_public_id_mixed(\n                ctx, item_type, item_public_id, aea_version\n            )\n        elif is_local:\n            _, item_config = find_item_locally(ctx, item_type, item_public_id)\n            latest_item_public_id = item_config.public_id\n        else:\n            package_meta = get_package_meta(item_type, item_public_id, aea_version)\n            latest_item_public_id = PublicId.from_str(\n                cast(str, package_meta[\"public_id\"])\n            )\n    except Exception:  # pylint: disable=broad-except\n        raise click.ClickException(\n            f\"Package {item_public_id} details can not be fetched from the registry!\"\n        )\n\n    return latest_item_public_id\n\n\ndef list_missing_packages(\n    packages: List[Tuple[str, PublicId]]\n) -> List[Tuple[str, PublicId]]:\n    \"\"\"Get list of packages not currently present in registry.\"\"\"\n    result: List[Tuple[str, PublicId]] = []\n\n    for package_type, package_id in packages:\n        api_path = f\"/{ITEM_TYPE_TO_PLURAL[package_type]}/{package_id.author}/{package_id.name}/{package_id.version}\"\n        resp = _perform_registry_request(\"GET\", api_path)\n        if resp.status_code == 404:\n            result.append((package_type, package_id))\n        elif resp.status_code == 200:\n            pass\n        else:  # pragma: nocover\n            raise ValueError(\"Error on registry request\")\n    return result\n"
  },
  {
    "path": "aea/cli/remove.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Implementation of the 'aea remove' subcommand.\"\"\"\nimport os\nimport shutil\nfrom collections import defaultdict\nfrom contextlib import contextmanager\nfrom pathlib import Path\nfrom typing import Dict, Generator, Optional, Set, Tuple, cast\n\nimport click\n\nfrom aea.cli.utils.click_utils import PublicIdParameter\nfrom aea.cli.utils.config import load_item_config, try_to_load_agent_config\nfrom aea.cli.utils.context import Context\nfrom aea.cli.utils.decorators import check_aea_project, pass_ctx\nfrom aea.cli.utils.loggers import logger\nfrom aea.cli.utils.package_utils import (\n    get_item_public_id_by_author_name,\n    is_item_present,\n)\nfrom aea.configurations.base import (\n    AgentConfig,\n    ComponentId,\n    ComponentType,\n    PackageConfiguration,\n    PackageId,\n    PublicId,\n)\nfrom aea.configurations.constants import (\n    CONNECTION,\n    CONTRACT,\n    DEFAULT_AEA_CONFIG_FILE,\n    PROTOCOL,\n    SKILL,\n)\nfrom aea.configurations.manager import find_component_directory_from_component_id\nfrom aea.helpers.io import open_file\n\n\n@click.group()\n@click.option(\n    \"-w\",\n    \"--with-dependencies\",\n    is_flag=True,\n    help=\"Remove obsolete dependencies not required anymore.\",\n)\n@click.pass_context\n@check_aea_project(check_aea_version=False)  # type: ignore  # pylint: disable=no-value-for-parameter\ndef remove(\n    click_context: click.Context, with_dependencies: bool\n) -> None:  # pylint: disable=unused-argument\n    \"\"\"Remove a package from the agent.\"\"\"\n    ctx = cast(Context, click_context.obj)\n    if with_dependencies:\n        ctx.set_config(\"with_dependencies\", True)\n\n\n@remove.command()\n@click.argument(\"connection_id\", type=PublicIdParameter(), required=True)\n@pass_ctx\ndef connection(ctx: Context, connection_id: PublicId) -> None:\n    \"\"\"Remove a connection from the agent.\"\"\"\n    remove_item(ctx, CONNECTION, connection_id)\n\n\n@remove.command()\n@click.argument(\"contract_id\", type=PublicIdParameter(), required=True)\n@pass_ctx\ndef contract(ctx: Context, contract_id: PublicId) -> None:\n    \"\"\"Remove a contract from the agent.\"\"\"\n    remove_item(ctx, CONTRACT, contract_id)\n\n\n@remove.command()\n@click.argument(\"protocol_id\", type=PublicIdParameter(), required=True)\n@pass_ctx\ndef protocol(ctx: Context, protocol_id: PublicId) -> None:\n    \"\"\"Remove a protocol from the agent.\"\"\"\n    remove_item(ctx, PROTOCOL, protocol_id)\n\n\n@remove.command()\n@click.argument(\"skill_id\", type=PublicIdParameter(), required=True)\n@pass_ctx\ndef skill(ctx: Context, skill_id: PublicId) -> None:\n    \"\"\"Remove a skill from the agent.\"\"\"\n    remove_item(ctx, SKILL, skill_id)\n\n\nclass ItemRemoveHelper:\n    \"\"\"Helper to check dependencies on removing component from agent config.\"\"\"\n\n    def __init__(self, ctx: Context, ignore_non_vendor: bool = False) -> None:\n        \"\"\"Init helper.\"\"\"\n        self._ctx = ctx\n        self._agent_config = ctx.agent_config\n        self._ignore_non_vendor = ignore_non_vendor\n\n    def get_agent_dependencies_with_reverse_dependencies(\n        self,\n    ) -> Dict[PackageId, Set[PackageId]]:\n        \"\"\"\n        Get all reverse dependencies in agent.\n\n        :return: dict with PackageId: and set of PackageIds that uses this package\n\n        Return example:\n        {\n            PackageId(protocol, fetchai/pck1:0.1.0): {\n                PackageId(skill, fetchai/pck2:0.2.0),\n                PackageId(skill, fetchai/pck3:0.3.0)\n            },\n            PackageId(connection, fetchai/pck4:0.1.0): set(),\n            PackageId(skill, fetchai/pck5:0.1.0): set(),\n            PackageId(skill, fetchai/pck6:0.2.0): set()}\n        )\n        \"\"\"\n        return self.get_item_dependencies_with_reverse_dependencies(\n            self._agent_config, None\n        )\n\n    @classmethod\n    def get_item_config(cls, package_id: PackageId) -> PackageConfiguration:\n        \"\"\"Get item config for item,_type and public_id.\"\"\"\n\n        item_config = load_item_config(\n            str(package_id.package_type),\n            package_path=cls.get_component_directory(package_id),\n        )\n        if (package_id.author != item_config.author) or (\n            package_id.name != item_config.name\n        ):\n            raise click.ClickException(\n                f\"Error loading {package_id} configuration, author/name do not match: {item_config.public_id}\"\n            )\n        return item_config\n\n    @staticmethod\n    def get_component_directory(package_id: PackageId) -> Path:\n        \"\"\"Return path for package.\"\"\"\n        try:\n            return find_component_directory_from_component_id(\n                Path(\".\"),\n                ComponentId(str(package_id.package_type), package_id.public_id),\n            )\n\n        except ValueError:\n            raise click.ClickException(\n                f\"Can not find folder for the package: {package_id.package_type} {package_id.public_id}\"\n            )\n\n    def _get_item_requirements(\n        self, item: PackageConfiguration, ignore_non_vendor: bool = False\n    ) -> Generator[PackageId, None, None]:\n        \"\"\"\n        List all the requirements for item provided.\n\n        :param item: the item package configuration\n        :param ignore_non_vendor: whether or not to ignore vendor packages\n        :yield: package ids: (type, public_id)\n        \"\"\"\n        for item_type in map(str, ComponentType):\n            items: Set[PublicId] = getattr(item, f\"{item_type}s\", set())\n            for item_public_id in items:\n                if ignore_non_vendor and is_item_present(\n                    self._ctx.cwd,\n                    self._ctx.agent_config,\n                    item_type,\n                    item_public_id,\n                    is_vendor=False,\n                ):\n                    continue\n                yield PackageId(item_type, item_public_id)\n\n    def get_item_dependencies_with_reverse_dependencies(\n        self, item: PackageConfiguration, package_id: Optional[PackageId] = None\n    ) -> Dict[PackageId, Set[PackageId]]:\n        \"\"\"\n        Get item dependencies.\n\n        It's recursive and provides all the sub dependencies.\n\n        :param item: the item package configuration\n        :param package_id: the package id.\n        :return: dict with PackageId: and set of PackageIds that uses this package\n        \"\"\"\n        result: defaultdict = defaultdict(set)\n\n        for dep_package_id in self._get_item_requirements(\n            item, self._ignore_non_vendor\n        ):\n            if package_id is None:\n                _ = result[dep_package_id]  # init default dict value\n            else:\n                result[dep_package_id].add(package_id)\n\n            if not self.is_present_in_agent_config(dep_package_id):  # pragma: nocover\n                continue\n\n            dep_item = self.get_item_config(dep_package_id)\n            for item_key, deps in self.get_item_dependencies_with_reverse_dependencies(\n                dep_item, dep_package_id\n            ).items():\n                result[item_key] = result[item_key].union(deps)\n\n        return result\n\n    def is_present_in_agent_config(self, package_id: PackageId) -> bool:\n        \"\"\"Check item is in agent config.\"\"\"\n        current_item = get_item_public_id_by_author_name(\n            self._agent_config,\n            str(package_id.package_type),\n            package_id.public_id.author,\n            package_id.public_id.name,\n        )\n        return bool(current_item)\n\n    def check_remove(\n        self, item_type: str, item_public_id: PublicId\n    ) -> Tuple[Set[PackageId], Set[PackageId], Dict[PackageId, Set[PackageId]]]:\n        \"\"\"\n        Check item can be removed from agent.\n\n        required by - set of components that requires this component\n        can be deleted - set of dependencies used only by component so can be deleted\n        can not be deleted  - dict - keys - packages can not be deleted, values are set of packages required by.\n\n        :param item_type: the item type.\n        :param item_public_id: the item public id.\n        :return: Tuple[required by, can be deleted, can not be deleted.]\n        \"\"\"\n        package_id = PackageId(item_type, item_public_id)\n        item = self.get_item_config(package_id)\n        agent_deps = self.get_agent_dependencies_with_reverse_dependencies()\n        item_deps = self.get_item_dependencies_with_reverse_dependencies(\n            item, package_id\n        )\n        can_be_removed = set()\n        can_not_be_removed = {}\n\n        for dep_key, deps in item_deps.items():\n            if agent_deps[dep_key] == deps:\n                can_be_removed.add(dep_key)\n            else:\n                can_not_be_removed[dep_key] = agent_deps[dep_key] - deps\n\n        return agent_deps[package_id], can_be_removed, can_not_be_removed\n\n\n@contextmanager\ndef remove_unused_component_configurations(ctx: Context) -> Generator:\n    \"\"\"\n    Remove all component configurations for items not registered and dump agent config.\n\n    Context manager!\n    Clean all configurations on enter, restore actual configurations and dump agent config.\n\n    :param ctx: click context\n    :yield: None\n    \"\"\"\n    saved_configuration = ctx.agent_config.component_configurations\n    ctx.agent_config.component_configurations = {}\n    try:\n        yield\n    finally:\n        saved_configuration_by_component_prefix = {\n            key.component_prefix: value for key, value in saved_configuration.items()\n        }\n        # need to reload agent configuration with the updated references\n        try_to_load_agent_config(ctx)\n        for component_id in ctx.agent_config.package_dependencies:\n            if component_id.component_prefix in saved_configuration_by_component_prefix:\n                ctx.agent_config.component_configurations[\n                    component_id\n                ] = saved_configuration_by_component_prefix[\n                    component_id.component_prefix\n                ]\n\n    with open_file(os.path.join(ctx.cwd, DEFAULT_AEA_CONFIG_FILE), \"w\") as f:\n        ctx.agent_loader.dump(ctx.agent_config, f)\n\n\nclass RemoveItem:\n    \"\"\"Implementation of item remove from the project.\"\"\"\n\n    def __init__(\n        self,\n        ctx: Context,\n        item_type: str,\n        item_id: PublicId,\n        with_dependencies: bool,\n        force: bool = False,\n        ignore_non_vendor: bool = False,\n    ) -> None:\n        \"\"\"\n        Init remove item tool.\n\n        :param ctx: click context.\n        :param item_type: str, package type\n        :param item_id: PublicId of the item to remove.\n        :param with_dependencies: whether or not to remove dependencies.\n        :param force: bool. if True remove even required by another package.\n        :param ignore_non_vendor: bool. if True, ignore non-vendor packages when computing inverse dependencies. The effect of this flag is ignored if force = True\n        \"\"\"\n        self.ctx = ctx\n        self.force = force\n        self.ignore_non_vendor = ignore_non_vendor\n        self.item_type = item_type\n        self.item_id = item_id\n        self.with_dependencies = with_dependencies\n        self.item_type_plural = \"{}s\".format(item_type)\n        self.item_name = item_id.name\n\n        self.current_item = self.get_current_item()\n        self.required_by: Set[PackageId] = set()\n        self.dependencies_can_be_removed: Set[PackageId] = set()\n        try:\n            (\n                self.required_by,\n                self.dependencies_can_be_removed,\n                *_,\n            ) = ItemRemoveHelper(\n                self.ctx, ignore_non_vendor=self.ignore_non_vendor\n            ).check_remove(\n                self.item_type, self.current_item\n            )\n        except FileNotFoundError:  # pragma: nocover\n            pass  # item registered but not present on filesystem\n\n    def get_current_item(self) -> PublicId:\n        \"\"\"Return public id of the item already presents in agent config.\"\"\"\n        current_item = get_item_public_id_by_author_name(\n            self.ctx.agent_config,\n            self.item_type,\n            self.item_id.author,\n            self.item_id.name,\n        )\n        if not current_item:  # pragma: nocover # actually checked in check_item_present\n            raise click.ClickException(\n                \"The {} '{}' is not supported.\".format(self.item_type, self.item_id)\n            )\n        return current_item\n\n    def remove(self) -> None:\n        \"\"\"Remove item and it's dependencies if specified.\"\"\"\n        click.echo(f\"Removing {self.item_type} '{self.current_item}'...\")\n        self.remove_item()\n        if self.with_dependencies:\n            self.remove_dependencies()\n        click.echo(f\"Successfully removed {self.item_type} '{self.current_item}'.\")\n\n    @property\n    def agent_items(self) -> Set[PublicId]:\n        \"\"\"Return items registered with agent of the same type as item.\"\"\"\n        return getattr(self.agent_config, self.item_type_plural, set())\n\n    @property\n    def is_required_by(self) -> bool:\n        \"\"\"Is required by any other registered component in the agent.\"\"\"\n        return bool(self.required_by)\n\n    def remove_item(self) -> None:\n        \"\"\"\n        Remove item.\n\n        Removed from the filesystem.\n        Removed from the agent configuration\n\n        Does not remove dependencies, please use `remove_dependencies`.\n        \"\"\"\n        if (not self.force) and self.is_required_by:\n            raise click.ClickException(\n                f\"Package {self.item_type} {self.item_id} can not be removed because it is required by {','.join(map(str, self.required_by))}\"\n            )\n        self._remove_package()\n        self._remove_from_config()\n\n    @property\n    def cwd(self) -> str:\n        \"\"\"Get current workdir.\"\"\"\n        return self.ctx.cwd\n\n    @property\n    def agent_config(self) -> AgentConfig:\n        \"\"\"Get agent config from context.\"\"\"\n        return self.ctx.agent_config\n\n    @property\n    def agent_name(self) -> str:  # pragma: nocover\n        \"\"\"Get agent name.\"\"\"\n        return self.ctx.agent_config.agent_name\n\n    def _get_item_folder(self) -> Path:\n        \"\"\"Get item package folder.\"\"\"\n        return Path(self.cwd) / ItemRemoveHelper.get_component_directory(\n            PackageId(self.item_type, self.item_id)\n        )\n\n    def _remove_package(self) -> None:\n        \"\"\"Remove package from filesystem.\"\"\"\n        item_folder = self._get_item_folder()\n        try:\n            shutil.rmtree(item_folder)\n        except BaseException:\n            raise click.ClickException(\n                f\"An error occurred during {item_folder} removing.\"\n            )\n\n    def _remove_from_config(self) -> None:\n        \"\"\"Remove item from agent config.\"\"\"\n        current_item = self.get_current_item()\n        logger.debug(\n            \"Removing the {} from {}\".format(self.item_type, DEFAULT_AEA_CONFIG_FILE)\n        )\n        self.agent_items.remove(current_item)\n        self.agent_config.component_configurations.pop(\n            ComponentId(self.item_type, current_item), None\n        )\n        self.ctx.dump_agent_config()\n\n    def remove_dependencies(self) -> None:\n        \"\"\"Remove all the dependencies related only to the package.\"\"\"\n        if not self.dependencies_can_be_removed:\n            return\n        for dependency in self.dependencies_can_be_removed:\n            click.echo(\n                f\"Removing obsolete dependency {str(dependency.package_type)} '{str(dependency.public_id)}'...\"\n            )\n            RemoveItem(\n                self.ctx,\n                str(dependency.package_type),\n                dependency.public_id,\n                with_dependencies=False,\n                force=True,\n            ).remove_item()\n            click.echo(\n                f\"Successfully removed {str(dependency.package_type)} '{dependency.public_id}'.\"\n            )\n\n\ndef remove_item(ctx: Context, item_type: str, item_id: PublicId) -> None:\n    \"\"\"\n    Remove an item from the configuration file and agent, given the public id.\n\n    :param ctx: Context object.\n    :param item_type: type of item.\n    :param item_id: item public ID.\n    \"\"\"\n    with remove_unused_component_configurations(ctx):\n        RemoveItem(\n            ctx, item_type, item_id, cast(bool, ctx.config.get(\"with_dependencies\"))\n        ).remove()\n"
  },
  {
    "path": "aea/cli/remove_key.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Implementation of the 'aea remove_key' subcommand.\"\"\"\n\nimport os\nfrom typing import cast\n\nimport click\n\nfrom aea.cli.utils.context import Context\nfrom aea.cli.utils.decorators import check_aea_project\nfrom aea.configurations.constants import DEFAULT_AEA_CONFIG_FILE\nfrom aea.crypto.registries import crypto_registry\nfrom aea.helpers.io import open_file\n\n\n@click.command()\n@click.argument(\n    \"type_\",\n    metavar=\"TYPE\",\n    type=click.Choice(list(crypto_registry.supported_ids)),\n    required=True,\n)\n@click.option(\n    \"--connection\", is_flag=True, help=\"For removing a private key for connections.\"\n)\n@click.pass_context\n@check_aea_project\ndef remove_key(click_context: click.Context, type_: str, connection: bool) -> None:\n    \"\"\"Remove a private key from the wallet of the agent.\"\"\"\n    _remove_private_key(click_context, type_, connection)\n\n\ndef _remove_private_key(\n    click_context: click.core.Context,\n    type_: str,\n    connection: bool = False,\n) -> None:\n    \"\"\"\n    Remove private key to the wallet.\n\n    :param click_context: click context object.\n    :param type_: type.\n    :param connection: whether or not it is a private key for a connection\n    \"\"\"\n    ctx = cast(Context, click_context.obj)\n    _try_remove_key(ctx, type_, connection)\n\n\ndef _try_remove_key(ctx: Context, type_: str, connection: bool = False) -> None:\n    private_keys = (\n        ctx.agent_config.connection_private_key_paths\n        if connection\n        else ctx.agent_config.private_key_paths\n    )\n    existing_keys = private_keys.keys()\n    if type_ not in existing_keys:\n        raise click.ClickException(\n            f\"There is no {'connection ' if connection else ''}key registered with id {type_}.\"\n        )\n    private_keys.delete(type_)\n    ctx.agent_loader.dump(\n        ctx.agent_config, open_file(os.path.join(ctx.cwd, DEFAULT_AEA_CONFIG_FILE), \"w\")\n    )\n"
  },
  {
    "path": "aea/cli/reset_password.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Implementation of the 'aea reset_password' subcommand.\"\"\"\n\nimport click\n\nfrom aea.cli.registry.login import registry_reset_password\n\n\n@click.command(\n    name=\"reset_password\", help=\"Reset the password of the registry account.\"\n)\n@click.argument(\"email\", type=str, required=True)\ndef reset_password(email: str) -> None:\n    \"\"\"Command to request Registry to reset password.\"\"\"\n    _do_password_reset(email)\n\n\ndef _do_password_reset(email: str) -> None:\n    \"\"\"\n    Request Registry to reset password.\n\n    :param email: str email.\n    \"\"\"\n    registry_reset_password(email)\n    click.echo(\"An email with a password reset link was sent to {}\".format(email))\n"
  },
  {
    "path": "aea/cli/run.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Implementation of the 'aea run' subcommand.\"\"\"\nfrom contextlib import contextmanager\nfrom pathlib import Path\nfrom typing import Generator, List, Optional, cast\n\nimport click\n\nfrom aea import __version__\nfrom aea.aea import AEA\nfrom aea.aea_builder import AEABuilder, DEFAULT_ENV_DOTFILE\nfrom aea.cli.install import do_install\nfrom aea.cli.utils.click_utils import ConnectionsOption, password_option\nfrom aea.cli.utils.constants import AEA_LOGO, REQUIREMENTS\nfrom aea.cli.utils.context import Context\nfrom aea.cli.utils.decorators import check_aea_project\nfrom aea.configurations.base import PublicId\nfrom aea.configurations.manager import AgentConfigManager\nfrom aea.connections.base import Connection\nfrom aea.contracts.base import Contract\nfrom aea.exceptions import AEAWalletNoAddressException\nfrom aea.helpers.base import load_env_file\nfrom aea.helpers.profiling import Profiling\nfrom aea.protocols.base import Message, Protocol\nfrom aea.protocols.dialogue.base import Dialogue\nfrom aea.skills.base import Behaviour, Handler, Model, Skill\n\n\n@click.command()\n@password_option()\n@click.option(\n    \"--connections\",\n    \"connection_ids\",\n    cls=ConnectionsOption,\n    required=False,\n    default=None,\n    help=\"The connection names to use for running the agent. Must be declared in the agent's configuration file.\",\n)\n@click.option(\n    \"--env\",\n    \"env_file\",\n    type=click.Path(),\n    required=False,\n    default=DEFAULT_ENV_DOTFILE,\n    help=\"Specify an environment file (default: .env)\",\n)\n@click.option(\n    \"--install-deps\",\n    \"is_install_deps\",\n    is_flag=True,\n    required=False,\n    default=False,\n    help=\"Install all the dependencies before running the agent.\",\n)\n@click.option(\n    \"--profiling\",\n    \"profiling\",\n    required=False,\n    default=0,\n    help=\"Enable profiling, print profiling every amount of seconds\",\n)\n@click.option(\n    \"--exclude-connections\",\n    \"exclude_connection_ids\",\n    cls=ConnectionsOption,\n    required=False,\n    default=None,\n    help=\"The connection names to disable for running the agent. Must be declared in the agent's configuration file.\",\n)\n@click.pass_context\n@check_aea_project\ndef run(\n    click_context: click.Context,\n    connection_ids: List[PublicId],\n    exclude_connection_ids: List[PublicId],\n    env_file: str,\n    is_install_deps: bool,\n    profiling: int,\n    password: str,\n) -> None:\n    \"\"\"Run the agent.\"\"\"\n    if connection_ids and exclude_connection_ids:\n        raise click.ClickException(\n            \"Please use only one of --connections or --exclude-connections, not both!\"\n        )\n\n    ctx = cast(Context, click_context.obj)\n    profiling = int(profiling)\n    if exclude_connection_ids:\n        connection_ids = _calculate_connection_ids(ctx, exclude_connection_ids)\n\n    if profiling > 0:\n        with _profiling_context(period=profiling):\n            run_aea(ctx, connection_ids, env_file, is_install_deps, password)\n            return\n    run_aea(ctx, connection_ids, env_file, is_install_deps, password)\n\n\ndef _calculate_connection_ids(\n    ctx: Context, exclude_connections: List[PublicId]\n) -> List[PublicId]:\n    \"\"\"Calculate resulting list of connection ids to run.\"\"\"\n    agent_config_manager = AgentConfigManager.load(ctx.cwd)\n    not_existing_connections = (\n        set(exclude_connections) - agent_config_manager.agent_config.connections\n    )\n    if not_existing_connections:\n        raise ValueError(\n            f\"Connections to exclude: {', '.join(map(str, not_existing_connections))} are not defined in agent configuration!\"\n        )\n\n    connection_ids = list(\n        agent_config_manager.agent_config.connections - set(exclude_connections)\n    )\n\n    return connection_ids\n\n\n@contextmanager\ndef _profiling_context(period: int) -> Generator:\n    \"\"\"Start profiling context.\"\"\"\n    OBJECTS_INSTANCES = [\n        Message,\n        Dialogue,\n        Handler,\n        Model,\n        Behaviour,\n        Skill,\n        Connection,\n        Contract,\n        Protocol,\n    ]\n    OBJECTS_CREATED = [Message, Dialogue]\n\n    profiler = Profiling(\n        period=period,\n        objects_instances_to_count=OBJECTS_INSTANCES,\n        objects_created_to_count=OBJECTS_CREATED,\n    )\n    profiler.start()\n    try:\n        yield None\n    except Exception:  # pylint: disable=try-except-raise # pragma: nocover\n        raise\n    finally:\n        profiler.stop()\n        profiler.wait_completed(sync=True, timeout=10)\n        # hack to address faulty garbage collection output being printed\n        import os  # pylint: disable=import-outside-toplevel\n        import sys  # pylint: disable=import-outside-toplevel\n\n        sys.stderr = open(os.devnull, \"w\", encoding=\"utf-8\")\n\n\ndef run_aea(\n    ctx: Context,\n    connection_ids: List[PublicId],\n    env_file: str,\n    is_install_deps: bool,\n    password: Optional[str] = None,\n) -> None:\n    \"\"\"\n    Prepare and run an agent.\n\n    :param ctx: a context object.\n    :param connection_ids: list of connections public IDs.\n    :param env_file: a path to env file.\n    :param is_install_deps: bool flag is install dependencies.\n    :param password: the password to encrypt/decrypt the private key.\n\n    :raises ClickException: if any Exception occurs.\n    \"\"\"\n    skip_consistency_check = ctx.config[\"skip_consistency_check\"]\n    _prepare_environment(ctx, env_file, is_install_deps)\n    aea = _build_aea(connection_ids, skip_consistency_check, password)\n\n    click.echo(AEA_LOGO + \"v\" + __version__ + \"\\n\")\n    click.echo(\n        \"Starting AEA '{}' in '{}' mode...\".format(aea.name, aea.runtime.loop_mode)\n    )\n    try:\n        aea.start()\n    except KeyboardInterrupt:  # pragma: no cover\n        click.echo(\" AEA '{}' interrupted!\".format(aea.name))  # pragma: no cover\n    except Exception as e:  # pragma: no cover\n        raise click.ClickException(str(e))\n    finally:\n        click.echo(\"Stopping AEA '{}' ...\".format(aea.name))\n        aea.stop()\n        click.echo(\"AEA '{}' stopped.\".format(aea.name))\n\n\ndef _prepare_environment(ctx: Context, env_file: str, is_install_deps: bool) -> None:\n    \"\"\"\n    Prepare the AEA project environment.\n\n    :param ctx: a context object.\n    :param env_file: the path to the environment file.\n    :param is_install_deps: whether to install the dependencies\n    \"\"\"\n    load_env_file(env_file)\n    if is_install_deps:\n        requirements_path = REQUIREMENTS if Path(REQUIREMENTS).exists() else None\n        do_install(ctx, requirement=requirements_path)\n\n\ndef _build_aea(\n    connection_ids: Optional[List[PublicId]],\n    skip_consistency_check: bool,\n    password: Optional[str] = None,\n) -> AEA:\n    \"\"\"Build the AEA.\"\"\"\n    try:\n        builder = AEABuilder.from_aea_project(\n            Path(\".\"), skip_consistency_check=skip_consistency_check, password=password\n        )\n        aea = builder.build(connection_ids=connection_ids, password=password)\n        return aea\n    except AEAWalletNoAddressException:\n        error_msg = (\n            \"You haven't specified any private key for the AEA project.\\n\"\n            \"Please add one by using the commands `aea generate-key` and `aea add-key` for the ledger of your choice.\\n\"\n        )\n        raise click.ClickException(error_msg)\n    except Exception as e:\n        raise click.ClickException(str(e))\n"
  },
  {
    "path": "aea/cli/scaffold.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Implementation of the 'aea scaffold' subcommand.\"\"\"\nimport os\nimport re\nimport shutil\nfrom pathlib import Path\nfrom typing import cast\n\nimport click\nfrom jsonschema import ValidationError\n\nfrom aea import AEA_DIR\nfrom aea.cli.fingerprint import fingerprint_item\nfrom aea.cli.utils.context import Context\nfrom aea.cli.utils.decorators import check_aea_project, clean_after, pass_ctx\nfrom aea.cli.utils.loggers import logger\nfrom aea.cli.utils.package_utils import (\n    create_symlink_packages_to_vendor,\n    create_symlink_vendor_to_local,\n    validate_package_name,\n)\nfrom aea.configurations.base import PublicId\nfrom aea.configurations.constants import (  # noqa: F401  # pylint: disable=unused-import\n    CONNECTION,\n    CONTRACT,\n    DEFAULT_AEA_CONFIG_FILE,\n    DEFAULT_CONNECTION_CONFIG_FILE,\n    DEFAULT_CONTRACT_CONFIG_FILE,\n    DEFAULT_PROTOCOL_CONFIG_FILE,\n    DEFAULT_SKILL_CONFIG_FILE,\n    DEFAULT_VERSION,\n    DOTTED_PATH_MODULE_ELEMENT_SEPARATOR,\n    PROTOCOL,\n    SCAFFOLD_PUBLIC_ID,\n    SKILL,\n)\nfrom aea.helpers.io import open_file\n\n\n@click.group()\n@click.option(\n    \"--with-symlinks\",\n    is_flag=True,\n    help=\"Add symlinks from vendor to non-vendor and packages to vendor folders.\",\n)\n@click.pass_context\n@check_aea_project\ndef scaffold(\n    click_context: click.core.Context, with_symlinks: bool\n) -> None:  # pylint: disable=unused-argument\n    \"\"\"Scaffold a package for the agent.\"\"\"\n    ctx = cast(Context, click_context.obj)\n    ctx.set_config(\"with_symlinks\", with_symlinks)\n\n\n@scaffold.command()\n@click.argument(\"connection_name\", type=str, required=True)\n@pass_ctx\ndef connection(ctx: Context, connection_name: str) -> None:\n    \"\"\"Add a connection scaffolding to the configuration file and agent.\"\"\"\n    scaffold_item(ctx, CONNECTION, connection_name)\n\n\n@scaffold.command()\n@click.argument(\"contract_name\", type=str, required=True)\n@pass_ctx\ndef contract(ctx: Context, contract_name: str) -> None:\n    \"\"\"Add a contract scaffolding to the configuration file and agent.\"\"\"\n    scaffold_item(ctx, CONTRACT, contract_name)\n\n\n@scaffold.command()\n@click.argument(\"protocol_name\", type=str, required=True)\n@click.option(\"-y\", \"--yes\", is_flag=True, default=False)\n@pass_ctx\ndef protocol(ctx: Context, protocol_name: str, yes: bool) -> None:\n    \"\"\"Add a protocol scaffolding to the configuration file and agent.\"\"\"\n    if yes or click.confirm(\n        \"We highly recommend auto-generating protocols with the aea generate command. Do you really want to continue scaffolding?\"\n    ):\n        scaffold_item(ctx, PROTOCOL, protocol_name)\n    else:\n        click.echo(\"Aborted. Exit\")  # pragma: nocover\n\n\n@scaffold.command()\n@click.argument(\"skill_name\", type=str, required=True)\n@pass_ctx\ndef skill(ctx: Context, skill_name: str) -> None:\n    \"\"\"Add a skill scaffolding to the configuration file and agent.\"\"\"\n    scaffold_item(ctx, SKILL, skill_name)\n\n\n@scaffold.command()\n@pass_ctx\ndef decision_maker_handler(ctx: Context) -> None:\n    \"\"\"Add a decision maker scaffolding to the configuration file and agent.\"\"\"\n    _scaffold_dm_handler(ctx)\n\n\n@scaffold.command()\n@pass_ctx\ndef error_handler(ctx: Context) -> None:\n    \"\"\"Add an error scaffolding to the configuration file and agent.\"\"\"\n    _scaffold_error_handler(ctx)\n\n\n@clean_after\ndef scaffold_item(ctx: Context, item_type: str, item_name: str) -> None:\n    \"\"\"\n    Add an item scaffolding to the configuration file and agent.\n\n    :param ctx: Context object.\n    :param item_type: type of item.\n    :param item_name: item name.\n\n    :raises ClickException: if some error occurs.\n    \"\"\"\n    validate_package_name(item_name)\n    author_name = ctx.agent_config.author\n    loader = getattr(ctx, f\"{item_type}_loader\")\n    default_config_filename = globals()[f\"DEFAULT_{item_type.upper()}_CONFIG_FILE\"]\n\n    item_type_plural = item_type + \"s\"\n    existing_ids = getattr(ctx.agent_config, f\"{item_type}s\")\n    existing_ids_only_author_and_name = map(lambda x: (x.author, x.name), existing_ids)\n    # check if we already have an item with the same public id\n    if (author_name, item_name) in existing_ids_only_author_and_name:\n        raise click.ClickException(\n            f\"A {item_type} with name '{item_name}' already exists. Aborting...\"\n        )\n\n    agent_name = ctx.agent_config.agent_name\n    click.echo(\n        f\"Adding {item_type} scaffold '{item_name}' to the agent '{agent_name}'...\"\n    )\n\n    # create the item folder\n    Path(item_type_plural).mkdir(exist_ok=True)\n    dest = os.path.join(item_type_plural, item_name)\n    if os.path.exists(dest):\n        raise click.ClickException(\n            f\"A {item_type} with this name already exists. Please choose a different name and try again.\"\n        )\n\n    ctx.clean_paths.append(str(dest))\n    try:\n        # copy the item package into the agent project.\n        src = Path(os.path.join(AEA_DIR, item_type_plural, \"scaffold\"))\n        logger.debug(f\"Copying {item_type} modules. src={src} dst={dest}\")\n        shutil.copytree(src, dest)\n\n        # add the item to the configurations.\n        logger.debug(f\"Registering the {item_type} into {DEFAULT_AEA_CONFIG_FILE}\")\n        new_public_id = PublicId(author_name, item_name, DEFAULT_VERSION)\n        existing_ids.add(new_public_id)\n        with open_file(os.path.join(ctx.cwd, DEFAULT_AEA_CONFIG_FILE), \"w\") as fp:\n            ctx.agent_loader.dump(ctx.agent_config, fp)\n\n        # ensure the name in the yaml and the name of the folder are the same\n        config_filepath = Path(\n            ctx.cwd, item_type_plural, item_name, default_config_filename\n        )\n        with open_file(config_filepath) as fp:\n            config = loader.load(fp)\n        config.name = item_name\n        config.author = author_name\n        with open_file(config_filepath, \"w\") as fp:\n            loader.dump(config, fp)\n\n        # update 'PUBLIC_ID' variable with the right public id in connection.py!\n\n        for file_name in [\"__init__.py\", \"connection.py\"]:\n            file_path = Path(dest) / file_name\n            if not file_path.exists():\n                continue\n            py_file = Path(file_path)\n            py_file.write_text(  # pylint: disable=unspecified-encoding\n                re.sub(\n                    SCAFFOLD_PUBLIC_ID,\n                    str(new_public_id),\n                    py_file.read_text(),  # pylint: disable=unspecified-encoding\n                )\n            )\n\n        # fingerprint item.\n        fingerprint_item(ctx, item_type, new_public_id)\n\n        if ctx.config.get(\"with_symlinks\", False):\n            click.echo(\n                \"Adding symlinks from vendor to non-vendor and packages to vendor folders.\"\n            )\n            create_symlink_vendor_to_local(ctx, item_type, new_public_id)\n            create_symlink_packages_to_vendor(ctx)\n\n    except ValidationError:\n        raise click.ClickException(\n            f\"Error when validating the {item_type} configuration file.\"\n        )\n    except Exception as e:\n        raise click.ClickException(str(e))\n\n\ndef _scaffold_dm_handler(ctx: Context) -> None:\n    \"\"\"Scaffold the decision maker handler.\"\"\"\n    _scaffold_non_package_item(\n        ctx,\n        \"decision_maker_handler\",\n        \"decision maker handler\",\n        \"DecisionMakerHandler\",\n        \"decision_maker\",\n    )\n\n\ndef _scaffold_error_handler(ctx: Context) -> None:\n    \"\"\"Scaffold the error handler.\"\"\"\n    _scaffold_non_package_item(\n        ctx, \"error_handler\", \"error handler\", \"ErrorHandler\", \"error_handler\"\n    )\n\n\ndef _scaffold_non_package_item(\n    ctx: Context, item_type: str, type_name: str, class_name: str, aea_dir: str\n) -> None:\n    \"\"\"\n    Scaffold a non-package item (e.g. decision maker handler, or error handler).\n\n    :param ctx: the CLI context.\n    :param item_type: the item type (e.g. 'decision_maker_handler')\n    :param type_name: the type name (e.g. \"decision maker\")\n    :param class_name: the class name (e.g. \"DecisionMakerHandler\")\n    :param aea_dir: the AEA directory that contains the scaffold module\n    \"\"\"\n    existing_item = getattr(ctx.agent_config, item_type)\n    if existing_item != {}:\n        raise click.ClickException(\n            f\"A {type_name} specification already exists. Aborting...\"\n        )\n\n    dest = Path(f\"{item_type}.py\")\n    agent_name = ctx.agent_config.agent_name\n    click.echo(f\"Adding {type_name} scaffold to the agent '{agent_name}'...\")\n    # create the file name\n    dotted_path = f\".{item_type}{DOTTED_PATH_MODULE_ELEMENT_SEPARATOR}{class_name}\"\n    try:\n        # copy the item package into the agent project.\n        src = Path(os.path.join(AEA_DIR, aea_dir, \"scaffold.py\"))\n        logger.debug(f\"Copying {type_name}. src={src} dst={dest}\")\n        shutil.copyfile(src, dest)\n\n        # add the item to the configurations.\n        logger.debug(f\"Registering the {type_name} into {DEFAULT_AEA_CONFIG_FILE}\")\n        setattr(\n            ctx.agent_config,\n            item_type,\n            {\n                \"dotted_path\": str(dotted_path),\n                \"file_path\": str(os.path.join(\".\", dest)),\n                \"config\": {},\n            },\n        )\n        ctx.agent_loader.dump(\n            ctx.agent_config,\n            open_file(\n                os.path.join(ctx.cwd, DEFAULT_AEA_CONFIG_FILE), \"w\", encoding=\"utf-8\"\n            ),\n        )\n\n    except Exception as e:\n        os.remove(dest)\n        raise click.ClickException(str(e))\n"
  },
  {
    "path": "aea/cli/search.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Implementation of the 'aea search' subcommand.\"\"\"\n\nfrom pathlib import Path\nfrom typing import Dict, List, Tuple, cast\n\nimport click\n\nfrom aea import AEA_DIR\nfrom aea.cli.registry.utils import request_api\nfrom aea.cli.utils.context import Context\nfrom aea.cli.utils.decorators import pass_ctx\nfrom aea.cli.utils.formatting import format_items, retrieve_details\nfrom aea.common import JSONLike\nfrom aea.configurations.constants import (\n    AGENT,\n    AGENTS,\n    CONNECTION,\n    CONNECTIONS,\n    CONTRACT,\n    CONTRACTS,\n    DEFAULT_AEA_CONFIG_FILE,\n    DEFAULT_CONNECTION_CONFIG_FILE,\n    DEFAULT_CONTRACT_CONFIG_FILE,\n    DEFAULT_PROTOCOL_CONFIG_FILE,\n    DEFAULT_SKILL_CONFIG_FILE,\n    PROTOCOL,\n    PROTOCOLS,\n    SKILL,\n    SKILLS,\n)\nfrom aea.configurations.loader import ConfigLoader\n\n\n@click.group()\n@click.option(\"--local\", is_flag=True, help=\"For local search.\")\n@click.pass_context\ndef search(click_context: click.Context, local: bool) -> None:\n    \"\"\"Search for packages in the registry.\"\"\"\n    ctx = cast(Context, click_context.obj)\n    if local:\n        ctx.set_config(\"is_local\", True)\n\n\n@search.command()\n@click.option(\"--query\", default=\"\", help=\"Query string to search Connections by name.\")\n@click.option(\"--page\", type=int, default=1, help=\"Page number to display.\")\n@pass_ctx\ndef connections(ctx: Context, query: str, page: int) -> None:\n    \"\"\"Search for Connections.\"\"\"\n    item_type = CONNECTION\n    _output_search_results(item_type, *search_items(ctx, item_type, query, page), page)\n\n\n@search.command()\n@click.option(\"--query\", default=\"\", help=\"Query string to search Contracts by name.\")\n@click.option(\"--page\", type=int, default=1, help=\"Page number to display.\")\n@pass_ctx\ndef contracts(ctx: Context, query: str, page: int) -> None:\n    \"\"\"Search for Contracts.\"\"\"\n    item_type = CONTRACT\n    _output_search_results(item_type, *search_items(ctx, item_type, query, page), page)\n\n\n@search.command()\n@click.option(\"--query\", default=\"\", help=\"Query string to search Protocols by name.\")\n@click.option(\"--page\", type=int, default=1, help=\"Page number to display.\")\n@pass_ctx\ndef protocols(ctx: Context, query: str, page: int) -> None:\n    \"\"\"Search for Protocols.\"\"\"\n    item_type = PROTOCOL\n    _output_search_results(item_type, *search_items(ctx, item_type, query, page), page)\n\n\n@search.command()\n@click.option(\"--query\", default=\"\", help=\"Query string to search Skills by name.\")\n@click.option(\"--page\", type=int, default=1, help=\"Page number to display.\")\n@pass_ctx\ndef skills(ctx: Context, query: str, page: int) -> None:\n    \"\"\"Search for Skills.\"\"\"\n    item_type = SKILL\n    _output_search_results(item_type, *search_items(ctx, item_type, query, page), page)\n\n\n@search.command()\n@click.option(\"--query\", default=\"\", help=\"Query string to search Agents by name.\")\n@click.option(\"--page\", type=int, default=1, help=\"Page number to display.\")\n@pass_ctx\ndef agents(ctx: Context, query: str, page: int) -> None:\n    \"\"\"Search for Agents.\"\"\"\n    item_type = AGENT\n    _output_search_results(item_type, *search_items(ctx, item_type, query, page), page)\n\n\ndef _is_invalid_item(name: str, dir_path: Path, config_path: Path) -> bool:\n    \"\"\"Return true if this protocol, connection or skill should not be returned in the list.\"\"\"\n    return (\n        name == \"scaffold\"\n        or not Path(dir_path).is_dir()\n        or not Path(config_path).is_file()\n    )\n\n\ndef _get_details_from_dir(\n    loader: ConfigLoader,\n    root_path: str,\n    sub_dir_glob_pattern: str,\n    config_filename: str,\n    results: List[Dict],\n) -> None:\n    for dir_path in Path(root_path).glob(sub_dir_glob_pattern + \"/*/\"):\n        config_path = dir_path / config_filename\n\n        if _is_invalid_item(dir_path.name, dir_path, config_path):\n            continue\n\n        details = retrieve_details(dir_path.name, loader, str(config_path))\n        results.append(details)\n\n\ndef _search_items_locally(ctx: Context, item_type_plural: str) -> List[Dict]:\n    result = []  # type: List[Dict]\n    configs = {\n        AGENTS: {\"loader\": ctx.agent_loader, \"config_file\": DEFAULT_AEA_CONFIG_FILE},\n        CONNECTIONS: {\n            \"loader\": ctx.connection_loader,\n            \"config_file\": DEFAULT_CONNECTION_CONFIG_FILE,\n        },\n        CONTRACTS: {\n            \"loader\": ctx.contract_loader,\n            \"config_file\": DEFAULT_CONTRACT_CONFIG_FILE,\n        },\n        PROTOCOLS: {\n            \"loader\": ctx.protocol_loader,\n            \"config_file\": DEFAULT_PROTOCOL_CONFIG_FILE,\n        },\n        SKILLS: {\"loader\": ctx.skill_loader, \"config_file\": DEFAULT_SKILL_CONFIG_FILE},\n    }\n    if item_type_plural != AGENTS:\n        # look in aea distribution for default packages\n        _get_details_from_dir(\n            cast(ConfigLoader, configs[item_type_plural][\"loader\"]),\n            AEA_DIR,\n            item_type_plural,\n            cast(str, configs[item_type_plural][\"config_file\"]),\n            result,\n        )\n\n    try:\n        registry_path = ctx.registry_path\n    except ValueError as e:  # pragma: nocover\n        raise click.ClickException(str(e))\n    # look in packages dir for all other packages\n    _get_details_from_dir(\n        cast(ConfigLoader, configs[item_type_plural][\"loader\"]),\n        registry_path,\n        \"*/{}\".format(item_type_plural),\n        cast(str, configs[item_type_plural][\"config_file\"]),\n        result,\n    )\n\n    return sorted(result, key=lambda k: k[\"name\"])\n\n\ndef search_items(\n    ctx: Context, item_type: str, query: str, page: int\n) -> Tuple[List[Dict], int]:\n    \"\"\"\n    Search items by query and click.echo results.\n\n    :param ctx: Context object.\n    :param item_type: item type.\n    :param query: query string.\n    :param page: page.\n\n    :return: (List of items, int items total count).\n    \"\"\"\n    click.echo('Searching for \"{}\"...'.format(query))\n    item_type_plural = item_type + \"s\"\n    if ctx.config.get(\"is_local\"):\n        results = _search_items_locally(ctx, item_type_plural)\n        count = len(results)\n    else:\n        resp = cast(\n            JSONLike,\n            request_api(\n                \"GET\",\n                \"/{}\".format(item_type_plural),\n                params={\"search\": query, \"page\": page},\n            ),\n        )\n        results = cast(List[Dict], resp[\"results\"])\n        count = cast(int, resp[\"count\"])\n    return results, count\n\n\ndef _output_search_results(\n    item_type: str, results: List[Dict], count: int, page: int\n) -> None:\n    \"\"\"\n    Output search results.\n\n    :param item_type: str item type.\n    :param results: list of found items.\n    :param count: items total count.\n    :param page: page.\n    \"\"\"\n    item_type_plural = item_type + \"s\"\n    len_results = len(results)\n    if len_results == 0:\n        click.echo(\"No {} found.\".format(item_type_plural))  # pragma: no cover\n    else:\n        click.echo(\"{} found:\\n\".format(item_type_plural.title()))\n        click.echo(format_items(results))\n        if count > len_results:\n            click.echo(\n                \"{} {} out of {}.\\nPage {}\".format(\n                    len_results, item_type_plural, count, page\n                )\n            )  # pragma: no cover\n"
  },
  {
    "path": "aea/cli/transfer.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Implementation of the 'aea transfer' subcommand.\"\"\"\nimport time\nfrom typing import Optional, cast\n\nimport click\n\nfrom aea.cli.get_address import _try_get_address\nfrom aea.cli.utils.click_utils import password_option\nfrom aea.cli.utils.context import Context\nfrom aea.cli.utils.decorators import check_aea_project\nfrom aea.cli.utils.package_utils import (\n    _override_ledger_configurations,\n    get_wallet_from_context,\n    try_get_balance,\n)\nfrom aea.common import Address\nfrom aea.crypto.ledger_apis import LedgerApis\nfrom aea.crypto.registries import ledger_apis_registry\n\n\nDEFAULT_SETTLE_TIMEOUT = 60\n\n\n@click.command()\n@click.argument(\n    \"type_\",\n    metavar=\"TYPE\",\n    type=click.Choice(list(ledger_apis_registry.supported_ids)),\n    required=True,\n)\n@click.argument(\n    \"address\",\n    type=str,\n    required=True,\n)\n@click.argument(\n    \"amount\",\n    type=int,\n    required=True,\n)\n@click.argument(\"fee\", type=int, required=False, default=100)\n@password_option()\n@click.option(\"-y\", \"--yes\", type=bool, is_flag=True, default=False)\n@click.option(\"--settle-timeout\", type=int, default=DEFAULT_SETTLE_TIMEOUT)\n@click.option(\"--sync\", type=bool, is_flag=True, default=False)\n@click.pass_context\n@check_aea_project\ndef transfer(\n    click_context: click.Context,\n    type_: str,\n    address: str,\n    amount: int,\n    fee: int,\n    password: Optional[str],\n    yes: bool,\n    settle_timeout: int,\n    sync: bool,\n) -> None:\n    \"\"\"Transfer wealth associated with a private key of the agent to another account.\"\"\"\n    ctx = cast(Context, click_context.obj)\n    try:\n        own_address = _try_get_address(ctx, type_, password)\n    except KeyError:\n        raise click.ClickException(\n            f\"No private key registered for `{type_}` in wallet!\"\n        )\n    if not yes:\n        click.confirm(\n            f\"You are about to transfer from {own_address} to {address} on ledger {type_} the amount {amount} with fee {fee}. Do you want to continue?\",\n            abort=True,\n        )\n\n    tx_digest = do_transfer(ctx, type_, address, amount, fee, password)\n\n    if not tx_digest:\n        raise click.ClickException(\"Failed to send a transaction!\")\n\n    if sync:\n        click.echo(\"Transaction set. Waiting to be settled...\")\n        wait_tx_settled(type_, tx_digest, timeout=settle_timeout)\n        click.echo(\n            f\"Transaction successfully settled. Sent {amount} with fee {fee} to {address}, transaction digest: {tx_digest}\"\n        )\n    else:\n        click.echo(\n            f\"Transaction successfully submitted. Sending {amount} with fee {fee} to {address}, transaction digest: {tx_digest}\"\n        )\n\n\ndef wait_tx_settled(\n    identifier: str, tx_digest: str, timeout: float = DEFAULT_SETTLE_TIMEOUT\n) -> None:\n    \"\"\"\n    Wait transaction is settled successfully.\n\n    :param identifier: str, ledger id\n    :param tx_digest: str, transaction digest\n    :param timeout: int, timeout in seconds before timeout error raised\n\n    :raises TimeoutError: on timeout\n    \"\"\"\n    t = time.time()\n    while True:\n        if time.time() - t > timeout:\n            raise TimeoutError()\n        if LedgerApis.is_transaction_settled(identifier, tx_digest):\n            return\n        time.sleep(1)\n\n\ndef do_transfer(\n    ctx: Context,\n    identifier: str,\n    address: Address,\n    amount: int,\n    tx_fee: int,\n    password: Optional[str] = None,\n) -> Optional[str]:\n    \"\"\"\n    Perform wealth transfer to another account.\n\n    :param ctx: click context\n    :param identifier: str, ledger id to perform transfer operation\n    :param address: address of the recipient\n    :param amount: int, amount of wealth to transfer\n    :param tx_fee: int, fee for transaction\n    :param password: the password to encrypt/decrypt the private key\n\n    :return: str, transaction digest or None if failed.\n    \"\"\"\n    click.echo(\"Starting transfer ...\")\n    wallet = get_wallet_from_context(ctx, password=password)\n    source_address = wallet.addresses[identifier]\n\n    _override_ledger_configurations(ctx.agent_config)\n    balance = int(try_get_balance(ctx.agent_config, wallet, identifier))\n    total_payable = amount + tx_fee\n    if total_payable > balance:\n        raise click.ClickException(\n            f\"Balance is not enough! Available={balance}, required={total_payable}!\"\n        )\n\n    tx_nonce = LedgerApis.generate_tx_nonce(identifier, source_address, address)\n    transaction = LedgerApis.get_transfer_transaction(\n        identifier, source_address, address, amount, tx_fee, tx_nonce\n    )\n    tx_signed = wallet.sign_transaction(identifier, transaction)\n    return LedgerApis.send_signed_transaction(identifier, tx_signed)\n"
  },
  {
    "path": "aea/cli/upgrade.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Implementation of the 'aea upgrade' subcommand.\"\"\"\nimport pprint\nimport shutil\nfrom copy import deepcopy\nfrom pathlib import Path\nfrom typing import Dict, Iterable, List, Set, Tuple, cast\n\nimport click\n\nimport aea\nfrom aea.cli.add import add_item\nfrom aea.cli.eject import _eject_item\nfrom aea.cli.registry.fetch import fetch_agent\nfrom aea.cli.registry.utils import get_latest_version_available_in_registry\nfrom aea.cli.remove import (\n    ItemRemoveHelper,\n    RemoveItem,\n    remove_unused_component_configurations,\n)\nfrom aea.cli.utils.click_utils import PublicIdParameter, registry_flag\nfrom aea.cli.utils.config import (\n    dump_item_config,\n    get_non_vendor_package_path,\n    load_item_config,\n    set_cli_author,\n)\nfrom aea.cli.utils.context import Context\nfrom aea.cli.utils.decorators import check_aea_project, clean_after, pass_ctx\nfrom aea.cli.utils.package_utils import (\n    get_item_public_id_by_author_name,\n    is_item_present,\n    update_aea_version_range,\n    update_references,\n)\nfrom aea.configurations.base import ComponentId, PackageId, PackageType, PublicId\nfrom aea.configurations.constants import (\n    CONNECTION,\n    CONTRACT,\n    DEFAULT_VERSION,\n    PROTOCOL,\n    SKILL,\n    VENDOR,\n)\nfrom aea.exceptions import enforce\nfrom aea.helpers.base import delete_directory_contents, find_topological_order\n\n\n@click.group(invoke_without_command=True)\n@click.option(\"-y\", \"--yes\", is_flag=True)\n@registry_flag(\n    help_local=\"For fetching packages only from local folder.\",\n    help_remote=\"For fetching packages only from remote registry.\",\n)\n@click.pass_context\n@check_aea_project(  # pylint: disable=unused-argument,no-value-for-parameter\n    check_aea_version=False\n)\ndef upgrade(\n    click_context: click.Context, local: bool, remote: bool, yes: bool\n) -> None:  # pylint: disable=unused-argument\n    \"\"\"Upgrade the packages of the agent.\"\"\"\n    ctx = cast(Context, click_context.obj)\n    ctx.set_config(\"is_local\", local and not remote)\n    ctx.set_config(\"is_mixed\", not (local or remote))\n    ctx.set_config(\"yes_by_default\", yes)\n    set_cli_author(click_context)\n\n    if click_context.invoked_subcommand is None:\n        upgrade_project(ctx)\n\n\n@upgrade.command()\n@click.argument(\"connection_public_id\", type=PublicIdParameter(), required=True)\n@pass_ctx\ndef connection(ctx: Context, connection_public_id: PublicId) -> None:\n    \"\"\"Upgrade a connection of the agent.\"\"\"\n    upgrade_item(ctx, CONNECTION, connection_public_id)\n\n\n@upgrade.command()\n@click.argument(\"contract_public_id\", type=PublicIdParameter(), required=True)\n@pass_ctx\ndef contract(ctx: Context, contract_public_id: PublicId) -> None:\n    \"\"\"Upgrade a contract of the agent.\"\"\"\n    upgrade_item(ctx, CONTRACT, contract_public_id)\n\n\n@upgrade.command()\n@click.argument(\"protocol_public_id\", type=PublicIdParameter(), required=True)\n@pass_ctx\ndef protocol(ctx: Context, protocol_public_id: PublicId) -> None:\n    \"\"\"Upgrade a protocol of the agent.\"\"\"\n    upgrade_item(ctx, PROTOCOL, protocol_public_id)\n\n\n@upgrade.command()\n@click.argument(\"skill_public_id\", type=PublicIdParameter(), required=True)\n@pass_ctx\ndef skill(ctx: Context, skill_public_id: PublicId) -> None:\n    \"\"\"Upgrade a skill of the agent.\"\"\"\n    upgrade_item(ctx, SKILL, skill_public_id)\n\n\ndef update_agent_config(ctx: Context) -> None:\n    \"\"\"\n    Update agent configurations.\n\n    In particular:\n    - update aea_version in case current framework version is different\n    - update author name if it is different\n\n    :param ctx: the context.\n    \"\"\"\n    update_aea_version_range(ctx.agent_config)\n    cli_author = ctx.config.get(\"cli_author\")\n    if cli_author and ctx.agent_config.author != cli_author:\n        click.echo(f\"Updating author from {ctx.agent_config.author} to {cli_author}\")\n        ctx.agent_config._author = cli_author  # pylint: disable=protected-access\n        ctx.agent_config.version = DEFAULT_VERSION\n\n    ctx.dump_agent_config()\n\n\ndef update_aea_version_in_nonvendor_packages(cwd: str) -> None:\n    \"\"\"\n    Update aea_version in non-vendor packages.\n\n    :param cwd: the current working directory.\n    \"\"\"\n    for package_path in get_non_vendor_package_path(Path(cwd)):\n        package_type = PackageType(package_path.parent.name[:-1])\n        package_config = load_item_config(package_type.value, package_path)\n        update_aea_version_range(package_config)\n        dump_item_config(package_config, package_path)\n\n\n@clean_after\ndef upgrade_project(ctx: Context) -> None:  # pylint: disable=unused-argument\n    \"\"\"Perform project upgrade.\"\"\"\n    click.echo(\"Starting project upgrade...\")\n    yes_by_default = ctx.config.get(\"yes_by_default\", False)\n\n    # check if there is a newer version of the same project\n    project_upgrader = ProjectUpgrader(ctx, yes_by_default=yes_by_default)\n    if project_upgrader.upgrade():\n        click.echo(\"Upgrade completed.\")\n        return\n\n    old_component_ids = ctx.agent_config.package_dependencies\n    item_remover = ItemRemoveHelper(ctx, ignore_non_vendor=True)\n    agent_items = item_remover.get_agent_dependencies_with_reverse_dependencies()\n\n    eject_helper = InteractiveEjectHelper(\n        ctx, agent_items, yes_by_default=yes_by_default\n    )\n    eject_helper.get_latest_versions()\n    if len(eject_helper.item_to_new_version) == 0:\n        click.echo(\"Everything is already up to date!\")\n        return\n    if not eject_helper.can_eject():\n        click.echo(\"Abort.\")\n        return\n    eject_helper.eject()\n\n    update_agent_config(ctx)\n    update_aea_version_in_nonvendor_packages(ctx.cwd)\n\n    # compute the upgraders and the shared dependencies.\n    required_by_relation = eject_helper.get_updated_inverse_adjacency_list()\n    item_to_new_version = eject_helper.item_to_new_version\n    upgraders, shared_deps_to_remove = _compute_upgraders_and_shared_deps_to_remove(\n        ctx, required_by_relation, item_to_new_version\n    )\n\n    with remove_unused_component_configurations(ctx):\n        if shared_deps_to_remove:\n            for dep in shared_deps_to_remove:  # pragma: nocover\n                if ItemUpgrader(\n                    ctx, str(dep.package_type), dep.public_id\n                ).is_non_vendor:\n                    # non vendor package, do not remove!\n                    continue\n                click.echo(\n                    f\"Removing shared dependency {str(dep.package_type)} '{dep.public_id}'...\"\n                )\n                RemoveItem(\n                    ctx,\n                    str(dep.package_type),\n                    dep.public_id,\n                    with_dependencies=False,\n                    force=True,\n                ).remove_item()\n                click.echo(\n                    f\"Successfully removed {str(dep.package_type)} '{dep.public_id}'.\"\n                )\n\n        for upgrader in upgraders.values():\n            upgrader.remove_item()\n            upgrader.add_item()\n\n        # load new package dependencies\n        replacements = _compute_replacements(ctx, old_component_ids)\n        update_references(ctx, replacements)\n\n    click.echo(\"Finished project upgrade. Everything is up to date now!\")\n\n\nclass UpgraderException(Exception):\n    \"\"\"Base upgrader exception.\"\"\"\n\n\nclass NotAddedException(UpgraderException):\n    \"\"\"Item was not found in agent cause not added.\"\"\"\n\n\nclass AlreadyActualVersionException(UpgraderException):\n    \"\"\"Actual version already installed.\"\"\"\n\n    def __init__(self, version: str) -> None:\n        \"\"\"Init exception.\"\"\"\n        super().__init__(version)\n        self.version = version\n\n\nclass IsRequiredException(UpgraderException):\n    \"\"\"Package can not be upgraded cause required by another.\"\"\"\n\n    def __init__(self, required_by: Iterable[PackageId]) -> None:\n        \"\"\"Init exception.\"\"\"\n        super().__init__(required_by)\n        self.required_by = required_by\n\n\nclass ProjectUpgrader:\n    \"\"\"Helper class to upgrade agent project if was previously fetched from registry.\"\"\"\n\n    _TEMP_ALIAS = \"fetched_agent\"\n\n    def __init__(self, ctx: Context, yes_by_default: bool = False) -> None:\n        \"\"\"Initialize the class.\"\"\"\n        self.ctx = ctx\n        self.yes_by_default = yes_by_default\n\n        self._current_aea_version = aea.__version__\n\n    def upgrade(self) -> bool:\n        \"\"\"\n        Upgrade the project by fetching from remote registry.\n\n        :return: True if the upgrade succeeded, False otherwise.\n        \"\"\"\n        agent_config = self.ctx.agent_config\n        agent_package_id = agent_config.package_id\n        click.echo(\n            f\"Checking if there is a newer remote version of agent package '{agent_package_id.public_id}'...\"\n        )\n        try:\n            new_item = get_latest_version_available_in_registry(\n                self.ctx,\n                str(agent_package_id.package_type),\n                agent_package_id.public_id.to_latest(),\n                aea_version=self._current_aea_version,\n            )\n        except click.ClickException:\n            click.echo(\"Package not found, continuing with normal upgrade.\")\n            return False\n\n        if new_item.package_version <= agent_config.public_id.package_version:  # type: ignore\n            click.echo(\n                f\"Latest version found is '{new_item.version}' which is smaller or equal than current version '{agent_config.public_id.package_version}'. Continuing...\"\n            )\n            return False\n\n        current_path = Path(self.ctx.cwd).absolute()\n        user_wants_to_upgrade = self._ask_user_if_wants_to_upgrade(\n            new_item, current_path\n        )\n        if not user_wants_to_upgrade:\n            return False\n\n        click.echo(f\"Upgrading project to version '{new_item.version}'\")\n\n        try:\n            delete_directory_contents(current_path)\n        except OSError as e:  # pragma: nocover\n            raise click.ClickException(\n                f\"Cannot remote path {current_path}. Error: {str(e)}.\"\n            )\n\n        fetch_agent(self.ctx, new_item, alias=self._TEMP_ALIAS)\n        self.ctx.cwd = str(current_path)\n        self._unpack_fetched_agent()\n        return True\n\n    def _unpack_fetched_agent(self) -> None:\n        \"\"\"Unpack fetched agent in current directory and remove temporary directory.\"\"\"\n        current_path = Path(self.ctx.cwd)\n        fetched_agent_dir = current_path / self._TEMP_ALIAS\n        for subpath in fetched_agent_dir.iterdir():\n            shutil.move(str(subpath), current_path)\n        shutil.rmtree(str(fetched_agent_dir))\n\n    def _ask_user_if_wants_to_upgrade(\n        self, new_item: PublicId, current_path: Path\n    ) -> bool:\n        \"\"\"\n        Ask if the user wants to upgrade the project.\n\n        :param new_item: the public id of the new item.\n        :param current_path: the current path.\n        :return: the user's answer (a boolean).\n        \"\"\"\n        message = (\n            f\"Found a newer version of this project: {new_item.package_version}. \"\n            f\"Would you like to replace this project with it? \\n\"\n            f\"Warning: the content in the current directory {current_path} will be removed\"\n        )\n        return _try_to_confirm(message, self.yes_by_default)\n\n\nclass ItemUpgrader:\n    \"\"\"Tool to upgrade agent's item .\"\"\"\n\n    def __init__(self, ctx: Context, item_type: str, item_public_id: PublicId) -> None:\n        \"\"\"\n        Init item upgrader.\n\n        :param ctx: context\n        :param item_type: str, type of the package\n        :param item_public_id: item to upgrade.\n        \"\"\"\n        self.ctx = ctx\n        self.ctx.set_config(\"with_dependencies\", True)\n        self.item_type = item_type\n        self.item_public_id = item_public_id\n        self.component_id = ComponentId(self.item_type, self.item_public_id)\n        self.current_item_public_id = self.get_current_item()\n        (\n            self.in_requirements,\n            self.deps_can_be_removed,\n            self.deps_can_not_be_removed,\n        ) = self.get_dependencies()\n        self.dependencies: Set[PackageId] = set()\n        self.dependencies.update(self.deps_can_be_removed)\n        self.dependencies.update(self.deps_can_not_be_removed)\n\n        self._current_aea_version = aea.__version__\n\n    def get_current_item(self) -> PublicId:\n        \"\"\"Return public id of the item already presents in agent config.\"\"\"\n        self.check_item_present()\n        current_item = get_item_public_id_by_author_name(\n            self.ctx.agent_config,\n            self.item_type,\n            self.item_public_id.author,\n            self.item_public_id.name,\n        )\n        if not current_item:  # pragma: nocover # actually checked in check_item_present\n            raise ValueError(\"Item not found!\")\n        return current_item\n\n    def check_item_present(self) -> None:\n        \"\"\"Check item going to be upgraded already registered in agent.\"\"\"\n        if not is_item_present(\n            self.ctx.cwd, self.ctx.agent_config, self.item_type, self.item_public_id\n        ) and not is_item_present(\n            self.ctx.cwd,\n            self.ctx.agent_config,\n            self.item_type,\n            self.item_public_id,\n            is_vendor=False,\n        ):\n            raise NotAddedException()\n\n    def get_dependencies(\n        self,\n    ) -> Tuple[Set[PackageId], Set[PackageId], Dict[PackageId, Set[PackageId]]]:\n        \"\"\"\n        Return dependency details for item.\n\n        :return: same as for ItemRemoveHelper.check_remove\n        \"\"\"\n        return ItemRemoveHelper(self.ctx, ignore_non_vendor=True).check_remove(\n            self.item_type, self.current_item_public_id\n        )\n\n    @property\n    def is_non_vendor(self) -> bool:\n        \"\"\"Check is package specified is non vendor.\"\"\"\n        path = ItemRemoveHelper.get_component_directory(\n            PackageId(self.item_type, self.item_public_id)\n        )\n        return VENDOR not in Path(path).parts[:2]\n\n    def check_in_requirements(self) -> None:\n        \"\"\"Check if we are trying to upgrade some component dependency.\"\"\"\n        if self.in_requirements:\n            raise IsRequiredException(self.in_requirements)\n\n    def check_is_non_vendor(self) -> None:\n        \"\"\"Check the package is not a vendor package.\"\"\"\n        if self.is_non_vendor:\n            raise AlreadyActualVersionException(self.current_item_public_id.version)\n\n    def check_not_at_latest_version(self) -> str:\n        \"\"\"\n        Check the package is not at the actual version.\n\n        :return: the version number.\n        \"\"\"\n        if self.item_public_id.version != \"latest\":\n            new_item = self.item_public_id\n        else:\n            new_item = get_latest_version_available_in_registry(\n                self.ctx,\n                self.item_type,\n                self.item_public_id,\n                aea_version=self._current_aea_version,\n            )\n\n        if self.current_item_public_id.version == new_item.version:\n            raise AlreadyActualVersionException(new_item.version)\n\n        return new_item.version\n\n    def check_upgrade_is_required(self) -> str:\n        \"\"\"\n        Check upgrade is required otherwise raise UpgraderException.\n\n        :return: new version  of the package.\n        \"\"\"\n        self.check_in_requirements()\n        self.check_is_non_vendor()\n        return self.check_not_at_latest_version()\n\n    def remove_item(self) -> None:\n        \"\"\"Remove item from agent.\"\"\"\n        remove_item = RemoveItem(\n            self.ctx,\n            self.item_type,\n            self.item_public_id,\n            with_dependencies=True,\n            force=True,\n            ignore_non_vendor=True,\n        )\n        remove_item.remove()\n\n    def add_item(self) -> None:\n        \"\"\"Add new package version to agent.\"\"\"\n        add_item(self.ctx, str(self.item_type), self.item_public_id)\n\n\nclass InteractiveEjectHelper:\n    \"\"\"\n    Helper class to interactively eject vendor packages.\n\n    This is needed in the cases in which a vendor package\n    prevents other packages to be upgraded.\n    \"\"\"\n\n    def __init__(\n        self,\n        ctx: Context,\n        inverse_adjacency_list: Dict[PackageId, Set[PackageId]],\n        yes_by_default: bool = False,\n    ) -> None:\n        \"\"\"\n        Initialize the class.\n\n        :param ctx: the CLI context.\n        :param inverse_adjacency_list: adjacency list of inverse dependency graph.\n        :param yes_by_default: if True, never ask the user for confirmation.\n        \"\"\"\n        self.ctx = ctx\n        self.inverse_adjacency_list = deepcopy(inverse_adjacency_list)\n        self.adjacency_list = self._reverse_adjacency_list(self.inverse_adjacency_list)\n        self.yes_by_default = yes_by_default\n\n        self._current_aea_version = aea.__version__\n        self.to_eject: List[PackageId] = []\n        self.item_to_new_version: Dict[PackageId, str] = {}\n\n    def get_latest_versions(self) -> None:\n        \"\"\"\n        Get latest versions for every project package.\n\n        Stores the result in 'item_to_new_version'.\n        \"\"\"\n        for package_id in self.adjacency_list.keys():\n            try:\n                new_item = get_latest_version_available_in_registry(\n                    self.ctx,\n                    str(package_id.package_type),\n                    package_id.public_id.to_latest(),\n                    aea_version=self._current_aea_version,\n                )\n            except click.ClickException:  # pragma: nocover\n                continue\n            if package_id.public_id.version == new_item.version:\n                continue\n            new_version = new_item.version\n            self.item_to_new_version[package_id] = new_version\n\n    @staticmethod\n    def _reverse_adjacency_list(\n        adjacency_list: Dict[PackageId, Set[PackageId]]\n    ) -> Dict[PackageId, Set[PackageId]]:\n        \"\"\"Compute the inverse of an adjacency list.\"\"\"\n        inverse_adjacency_list: Dict[PackageId, Set[PackageId]] = {}\n        for v, neighbors in adjacency_list.items():\n            inverse_adjacency_list.setdefault(v, set())\n            for u in neighbors:\n                inverse_adjacency_list.setdefault(u, set()).add(v)\n        return inverse_adjacency_list\n\n    def eject(self) -> None:\n        \"\"\"Eject packages.\"\"\"\n        for package_id in self.to_eject:\n            click.echo(f\"Ejecting {package_id}...\")\n            _eject_item(self.ctx, str(package_id.package_type), package_id.public_id)\n\n    def get_updated_inverse_adjacency_list(self) -> Dict[PackageId, Set[PackageId]]:\n        \"\"\"Update inverse adjacency list by removing ejected packages.\"\"\"\n        result = {}\n        for package_id, deps in self.inverse_adjacency_list.items():\n            if package_id in self.to_eject:\n                continue\n            result[package_id] = deps.difference(self.to_eject)\n        return result\n\n    def can_eject(self) -> bool:\n        \"\"\"Ask to the user if packages can be ejected if needed.\"\"\"\n        to_upgrade = set(self.item_to_new_version.keys())\n        order = find_topological_order(self.adjacency_list)\n        for package_id in order:\n            if package_id in self.item_to_new_version:\n                # if dependency is going to be upgraded,\n                # no need to do anything\n                continue\n\n            depends_on = self.adjacency_list[package_id]\n            dependencies_to_upgrade = depends_on.intersection(to_upgrade)\n            if len(dependencies_to_upgrade) == 0:\n                # if dependencies of the package are not going to be upgraded,\n                # no need to worry about its ejection.\n                continue  # pragma: nocover\n\n            # if we are here, it means we need to eject the package.\n            answer = self._prompt(package_id, dependencies_to_upgrade)\n            should_eject = answer\n            if not should_eject:\n                return False\n            click.echo(f\"Package '{package_id}' scheduled for ejection.\")\n            self.to_eject.append(package_id)\n        return True\n\n    def _prompt(\n        self, package_id: PackageId, dependencies_to_upgrade: Set[PackageId]\n    ) -> bool:\n        \"\"\"\n        Ask the user permission for ejection of a package.\n\n        :param package_id: the package id.\n        :param dependencies_to_upgrade: the dependencies to upgrade.\n        :return: True or False, depending on the answer of the user.\n        \"\"\"\n        package_type = str(package_id.package_type).capitalize()\n        message = (\n            f\"{package_type} {package_id.public_id} prevents the upgrade of \"\n            f\"the following vendor packages:\\n\"\n            f\"{pprint.pformat(dependencies_to_upgrade)}\\n\"\n            f\"as there isn't a compatible version available on the AEA registry. \"\n            f\"Would you like to eject it?\"\n        )\n        return _try_to_confirm(message, self.yes_by_default)\n\n\ndef _try_to_confirm(message: str, yes_by_default: bool) -> bool:\n    \"\"\"\n    Try to prompt a question to the user.\n\n    The actual effect of this function will be determined by \"yes_by_default\".\n\n    In particular:\n    - if \"yes_by_default\" is True, never prompt and return True.\n    - if \"yes_by_default\" is False, ask to the user.\n\n    :param message: the message\n    :param yes_by_default: bool to override confirm\n    :return: result\n    \"\"\"\n    return click.confirm(message) if not yes_by_default else True\n\n\n@clean_after\ndef upgrade_item(ctx: Context, item_type: str, item_public_id: PublicId) -> None:\n    \"\"\"\n    Upgrade an item.\n\n    :param ctx: Context object.\n    :param item_type: the item type.\n    :param item_public_id: the item public id.\n    \"\"\"\n    try:\n        with remove_unused_component_configurations(ctx):\n            old_component_ids = ctx.agent_config.package_dependencies\n            item_upgrader = ItemUpgrader(ctx, item_type, item_public_id)\n            click.echo(\n                f\"Upgrading {item_type} '{item_public_id.author}/{item_public_id.name}' from version '{item_upgrader.current_item_public_id.version}' to '{item_public_id.version}' for the agent '{ctx.agent_config.agent_name}'...\"\n            )\n            version = item_upgrader.check_upgrade_is_required()\n\n            item_upgrader.remove_item()\n            item_upgrader.add_item()\n\n            replacements = _compute_replacements(ctx, old_component_ids)\n            update_references(ctx, replacements)\n\n        click.echo(\n            f\"The {item_type} '{item_public_id.author}/{item_public_id.name}' for the agent '{ctx.agent_config.agent_name}' has been successfully upgraded from version '{item_upgrader.current_item_public_id.version}' to '{version}'.\"\n        )\n\n    except NotAddedException:\n        raise click.ClickException(\n            f\"A {item_type} with id '{item_public_id.author}/{item_public_id.name}' is not registered. Please use the `add` command. Aborting...\"\n        )\n    except AlreadyActualVersionException as e:\n        raise click.ClickException(\n            f\"The {item_type} with id '{item_public_id.author}/{item_public_id.name}' already has version '{e.version}'. Nothing to upgrade.\"\n        )\n    except IsRequiredException as e:\n        raise click.ClickException(\n            f\"Can not upgrade {item_type} '{item_public_id.author}/{item_public_id.name}' because it is required by '{', '.join(map(str, e.required_by))}'\"\n        )\n\n\ndef _compute_replacements(\n    ctx: Context, old_component_ids: Set[ComponentId]\n) -> Dict[ComponentId, ComponentId]:\n    \"\"\"Compute replacements from old component ids to new components ids.\"\"\"\n    agent_config = load_item_config(PackageType.AGENT.value, Path(ctx.cwd))\n    new_component_ids = list(agent_config.package_dependencies)\n    replacements: Dict[ComponentId, ComponentId] = {}\n    for old_component_id in old_component_ids:\n        same_prefix = list(filter(old_component_id.same_prefix, new_component_ids))\n        enforce(len(same_prefix) < 2, \"More than one component id found.\")\n        if len(same_prefix) > 0:\n            replacements[old_component_id] = same_prefix[0]\n    return replacements\n\n\ndef _compute_upgraders_and_shared_deps_to_remove(\n    ctx: Context,\n    required_by_relation: Dict[PackageId, Set[PackageId]],\n    item_to_new_version: Dict[PackageId, str],\n) -> Tuple[Dict[PackageId, ItemUpgrader], Set[PackageId]]:\n    \"\"\"\n    Compute upgraders and shared dependencies to remove.\n\n    :param ctx: the CLI Context\n    :param required_by_relation: from a package id to the package ids it is required by.\n    :param item_to_new_version: from a package id to its new version available.\n    :return: the list of upgraders and the shared dependencies to remove.\n    \"\"\"\n    upgraders: Dict[PackageId, ItemUpgrader] = {}\n    shared_deps: Set[PackageId] = set()\n    shared_deps_to_remove = set()\n    items_to_upgrade_dependencies = set()\n    for package_id, required_by in required_by_relation.items():\n        item_upgrader = ItemUpgrader(\n            ctx, str(package_id.package_type), package_id.public_id.to_latest()\n        )\n\n        # if the package is required by at least another package, don't upgrade.\n        is_required_by_other = len(required_by) != 0\n        if is_required_by_other:\n            continue\n\n        is_not_in_requirements = not item_upgrader.in_requirements\n        is_vendor = not item_upgrader.is_non_vendor\n        to_be_upgraded = package_id in item_to_new_version\n\n        if is_not_in_requirements and is_vendor and to_be_upgraded:\n            upgraders[package_id] = item_upgrader\n\n        items_to_upgrade_dependencies.add(package_id)\n        items_to_upgrade_dependencies.update(item_upgrader.dependencies)\n        shared_deps.update(item_upgrader.deps_can_not_be_removed.keys())\n\n    for dep in shared_deps:\n        if required_by_relation[dep] - items_to_upgrade_dependencies:\n            # shared dependencies not resolved, nothing to do next\n            continue  # pragma: nocover\n        # add it to remove\n        shared_deps_to_remove.add(dep)\n    return upgraders, shared_deps_to_remove\n"
  },
  {
    "path": "aea/cli/utils/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"A module with utils of the aea cli.\"\"\"\n"
  },
  {
    "path": "aea/cli/utils/click_utils.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Module with click utils of the aea cli.\"\"\"\n\nimport os\nfrom collections import OrderedDict\nfrom pathlib import Path\nfrom typing import Any, Callable, List, Mapping, Optional, Tuple\n\nimport click\nfrom click import Context, Option, UsageError, option\n\nfrom aea.cli.utils.config import try_to_load_agent_config\nfrom aea.configurations.base import PublicId\nfrom aea.configurations.constants import DEFAULT_AEA_CONFIG_FILE\nfrom aea.helpers.io import open_file\n\n\nclass ConnectionsOption(click.Option):\n    \"\"\"Click option for the --connections option in 'aea run'.\"\"\"\n\n    def type_cast_value(\n        self, ctx: click.Context, value: str\n    ) -> Optional[List[PublicId]]:\n        \"\"\"\n        Parse the list of string passed through command line.\n\n        E.g. from 'stub,local' to ['stub', 'local'].\n\n        :param ctx: the click context\n        :param value: the list of connection names, as a string.\n        :return: list of public ids\n        \"\"\"\n        if value is None:\n            return None\n        try:\n\n            def arg_strip(s: str) -> str:\n                return s.strip(\" '\\\"\")\n\n            input_connection_ids = [\n                arg_strip(s) for s in value.split(\",\") if arg_strip(s) != \"\"\n            ]\n\n            # remove duplicates, while preserving the order\n            result = OrderedDict()  # type: OrderedDict[PublicId, None]\n            for connection_id_string in input_connection_ids:\n                connection_public_id = PublicId.from_str(connection_id_string)\n                result[connection_public_id] = None\n            return list(result.keys())\n        except Exception:  # pragma: no cover\n            raise click.BadParameter(value)\n\n\nclass PublicIdParameter(click.ParamType):\n    \"\"\"Define a public id parameter for Click applications.\"\"\"\n\n    def __init__(  # pylint: disable=useless-super-delegation\n        self, *args: Any, **kwargs: Any\n    ) -> None:\n        \"\"\"\n        Initialize the Public Id parameter.\n\n        Just forwards arguments to parent constructor.\n\n        :param args: positional arguments\n        :param kwargs: keyword arguments\n        \"\"\"\n        super().__init__(*args, **kwargs)  # type: ignore\n\n    def get_metavar(self, param: Any) -> str:\n        \"\"\"Return the metavar default for this param if it provides one.\"\"\"\n        return \"PUBLIC_ID\"\n\n    def convert(  # pylint: disable=inconsistent-return-statements\n        self, value: str, param: Any, ctx: Optional[click.Context]\n    ) -> PublicId:\n        \"\"\"Convert the value. This is not invoked for values that are `None` (the missing value).\"\"\"\n        try:\n            return PublicId.from_str(value)\n        except ValueError:\n            self.fail(value, param, ctx)\n\n\nclass AgentDirectory(click.Path):\n    \"\"\"A click.Path, but with further checks  applications.\"\"\"\n\n    def __init__(self) -> None:\n        \"\"\"Initialize the agent directory parameter.\"\"\"\n        super().__init__(\n            exists=True, file_okay=False, dir_okay=True, readable=True, writable=False\n        )\n\n    def get_metavar(self, param: Any) -> str:\n        \"\"\"Return the metavar default for this param if it provides one.\"\"\"\n        return \"AGENT_DIRECTORY\"  # pragma: no cover\n\n    def convert(self, value: str, param: Any, ctx: click.Context) -> str:  # type: ignore\n        \"\"\"Convert the value. This is not invoked for values that are `None` (the missing value).\"\"\"\n        cwd = os.getcwd()\n        path = Path(value)\n        try:\n            # check that the target folder is an AEA project.\n            os.chdir(path)\n            with open_file(DEFAULT_AEA_CONFIG_FILE, mode=\"r\", encoding=\"utf-8\") as fp:\n                ctx.obj.agent_config = ctx.obj.agent_loader.load(fp)\n            try_to_load_agent_config(ctx.obj)\n            # everything ok - return the parameter to the command\n            return value\n        except Exception:\n            raise click.ClickException(\n                \"The name provided is not a path to an AEA project.\"\n            )\n        finally:\n            os.chdir(cwd)\n\n\ndef registry_flag(\n    help_local: str = \"Use only local registry.\",\n    help_remote: str = \"Use ony remote registry.\",\n) -> Callable:\n    \"\"\"Choice of one flag between: '--local/--remote'.\"\"\"\n\n    def wrapper(f: Callable) -> Callable:\n        f = option(\n            \"--local\",\n            is_flag=True,\n            cls=MutuallyExclusiveOption,\n            help=help_local,\n            mutually_exclusive=[\"remote\"],\n        )(f)\n        f = option(\n            \"--remote\",\n            is_flag=True,\n            cls=MutuallyExclusiveOption,\n            help=help_remote,\n            mutually_exclusive=[\"local\"],\n        )(f)\n\n        return f\n\n    return wrapper\n\n\ndef registry_path_option(f: Callable) -> Callable:\n    \"\"\"Add registry path aea option.\"\"\"\n    return option(\n        \"--registry-path\",\n        type=click.Path(dir_okay=True, exists=True, file_okay=False),\n        required=False,\n        help=\"Provide a local registry directory full path.\",\n    )(f)\n\n\nclass MutuallyExclusiveOption(Option):\n    \"\"\"Represent a mutually exclusive option.\"\"\"\n\n    def __init__(self, *args: Any, **kwargs: Any) -> None:\n        \"\"\"Initialize the option.\"\"\"\n        self.mutually_exclusive = set(kwargs.pop(\"mutually_exclusive\", []))\n        help_ = kwargs.get(\"help\", \"\")\n        if self.mutually_exclusive:\n            ex_str = \", \".join(self.mutually_exclusive)\n            kwargs[\"help\"] = help_ + (\n                \" NOTE: This argument is mutually exclusive with \"\n                \" arguments: [\" + ex_str + \"].\"\n            )\n        super().__init__(*args, **kwargs)\n\n    def handle_parse_result(\n        self, ctx: Context, opts: Mapping[str, Any], args: List[Any]\n    ) -> Tuple[Any, List[str]]:\n        \"\"\"\n        Handle parse result.\n\n        :param ctx: the click context.\n        :param opts: the options.\n        :param args: the list of arguments (to be forwarded to the parent class).\n        :return: tuple of results\n        \"\"\"\n        if self.mutually_exclusive.intersection(opts) and self.name in opts:\n            raise UsageError(\n                f\"Illegal usage: `{self.name}` is mutually exclusive with \"\n                f\"arguments `{', '.join(self.mutually_exclusive)}`.\"\n            )\n\n        return super().handle_parse_result(ctx, opts, args)  # type: ignore\n\n\ndef password_option(confirmation_prompt: bool = False, **kwargs) -> Callable:  # type: ignore\n    \"\"\"Decorator to ask for input if -p flag was provided or use --password to set password value in command line.\"\"\"\n\n    def callback(ctx, _, value: bool) -> bool:  # type: ignore\n        if value is True:\n            ctx.params[\"password\"] = ctx.params.get(\"password\") or click.prompt(\n                \"Enter password\",\n                hide_input=True,\n                confirmation_prompt=confirmation_prompt,\n            )\n        return value\n\n    def wrap(fn):  # type: ignore\n        return click.option(\n            \"-p\",\n            is_flag=True,\n            type=bool,\n            callback=callback,\n            expose_value=False,\n            help=\"Ask for password interactively\",\n        )(\n            click.option(\n                \"--password\",\n                type=str,\n                is_eager=True,\n                metavar=\"PASSWORD\",\n                help=\"Set password for key encryption/decryption\",\n                **kwargs,\n            )(fn)\n        )  # type: ignore\n\n    return wrap\n"
  },
  {
    "path": "aea/cli/utils/config.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"A module with config tools of the aea cli.\"\"\"\nimport os\nfrom pathlib import Path\nfrom typing import Any, Dict, Optional, Set\n\nimport click\nimport jsonschema\nimport yaml\n\nfrom aea.cli.utils.constants import AUTHOR_KEY, CLI_CONFIG_PATH\nfrom aea.cli.utils.context import Context\nfrom aea.cli.utils.exceptions import AEAConfigException\nfrom aea.cli.utils.generic import load_yaml\nfrom aea.configurations.base import (\n    ComponentType,\n    PackageConfiguration,\n    PackageType,\n    _get_default_configuration_file_name_from_type,\n)\nfrom aea.configurations.constants import DEFAULT_AEA_CONFIG_FILE, REGISTRY_PATH_KEY\nfrom aea.configurations.loader import ConfigLoader, ConfigLoaders\nfrom aea.configurations.validation import ExtraPropertiesError\nfrom aea.exceptions import AEAEnforceError, AEAValidationError\nfrom aea.helpers.io import open_file\n\n\ndef try_to_load_agent_config(\n    ctx: Context, is_exit_on_except: bool = True, agent_src_path: str = None\n) -> None:\n    \"\"\"\n    Load agent config to a click context object.\n\n    :param ctx: click command context object.\n    :param is_exit_on_except: bool option to exit on exception (default = True).\n    :param agent_src_path: path to an agent dir if needed to load a custom config.\n    \"\"\"\n    if agent_src_path is None:\n        agent_src_path = ctx.cwd\n\n    try:\n        path = Path(os.path.join(agent_src_path, DEFAULT_AEA_CONFIG_FILE))\n        with open_file(path, mode=\"r\", encoding=\"utf-8\") as fp:\n            ctx.agent_config = ctx.agent_loader.load(fp)\n            ctx.agent_config.directory = Path(agent_src_path)\n    except FileNotFoundError:\n        if is_exit_on_except:\n            raise click.ClickException(\n                \"Agent configuration file '{}' not found in the current directory.\".format(\n                    DEFAULT_AEA_CONFIG_FILE\n                )\n            )\n    except (\n        jsonschema.exceptions.ValidationError,\n        ExtraPropertiesError,\n        AEAValidationError,\n    ) as e:\n        if is_exit_on_except:\n            raise click.ClickException(\n                \"Agent configuration file '{}' is invalid: `{}`. Please check the documentation.\".format(\n                    DEFAULT_AEA_CONFIG_FILE, str(e)\n                )\n            )\n    except AEAEnforceError as e:\n        raise click.ClickException(str(e))  # pragma: nocover\n\n\ndef _init_cli_config() -> None:\n    \"\"\"Create cli config folder and file.\"\"\"\n    conf_dir = os.path.dirname(CLI_CONFIG_PATH)\n    if not os.path.exists(conf_dir):\n        os.makedirs(conf_dir)\n    with open_file(CLI_CONFIG_PATH, \"w+\") as f:\n        yaml.dump({}, f, default_flow_style=False)\n\n\ndef update_cli_config(dict_conf: Dict) -> None:\n    \"\"\"\n    Update CLI config and write to yaml file.\n\n    :param dict_conf: dict config to write.\n    \"\"\"\n    config = get_or_create_cli_config()\n    config.update(dict_conf)\n    with open_file(CLI_CONFIG_PATH, \"w\") as f:\n        yaml.dump(config, f, default_flow_style=False)\n\n\ndef get_or_create_cli_config() -> Dict:\n    \"\"\"\n    Read or create CLI config from yaml file.\n\n    :return: dict CLI config.\n    \"\"\"\n    try:\n        return load_yaml(CLI_CONFIG_PATH)\n    except FileNotFoundError:\n        _init_cli_config()\n    return load_yaml(CLI_CONFIG_PATH)\n\n\ndef set_cli_author(click_context: click.Context) -> None:\n    \"\"\"\n    Set CLI author in the CLI Context.\n\n    The key of the new field is 'cli_author'.\n\n    :param click_context: the Click context\n    \"\"\"\n    config = get_or_create_cli_config()\n    cli_author = config.get(AUTHOR_KEY, None)\n    if cli_author is None:\n        raise click.ClickException(\n            \"The AEA configurations are not initialized. Use `aea init` before continuing.\"\n        )\n    click_context.obj.set_config(\"cli_author\", cli_author)\n\n\ndef get_registry_path_from_cli_config() -> Optional[str]:\n    \"\"\"Get registry path from config.\"\"\"\n    config = get_or_create_cli_config()\n    return config.get(REGISTRY_PATH_KEY, None)\n\n\ndef load_item_config(item_type: str, package_path: Path) -> PackageConfiguration:\n    \"\"\"\n    Load item configuration.\n\n    :param item_type: type of item.\n    :param package_path: path to package from which config should be loaded.\n\n    :return: configuration object.\n    \"\"\"\n    configuration_file_name = _get_default_configuration_file_name_from_type(item_type)\n    configuration_path = package_path / configuration_file_name\n    configuration_loader = ConfigLoader.from_configuration_type(PackageType(item_type))\n    with open_file(configuration_path) as file_input:\n        item_config = configuration_loader.load(file_input)\n    return item_config\n\n\ndef dump_item_config(\n    package_configuration: PackageConfiguration, package_path: Path\n) -> None:\n    \"\"\"\n    Dump item configuration.\n\n    :param package_configuration: the package configuration.\n    :param package_path: path to package from which config should be dumped.\n    \"\"\"\n    configuration_file_name = _get_default_configuration_file_name_from_type(\n        package_configuration.package_type\n    )\n    configuration_path = package_path / configuration_file_name\n    configuration_loader = ConfigLoader.from_configuration_type(\n        package_configuration.package_type\n    )\n    with configuration_path.open(\"w\") as file_output:\n        configuration_loader.dump(package_configuration, file_output)  # type: ignore\n\n\ndef update_item_config(item_type: str, package_path: Path, **kwargs: Any) -> None:\n    \"\"\"\n    Update item config and item config file.\n\n    :param item_type: type of item.\n    :param package_path: path to a package folder.\n    :param kwargs: pairs of config key-value to update.\n    \"\"\"\n    item_config = load_item_config(item_type, package_path)\n    for key, value in kwargs.items():\n        setattr(item_config, key, value)\n\n    config_filepath = os.path.join(\n        package_path, item_config.default_configuration_filename\n    )\n    loader = ConfigLoaders.from_package_type(item_type)\n    with open_file(config_filepath, \"w\") as f:\n        loader.dump(item_config, f)\n\n\ndef validate_item_config(item_type: str, package_path: Path) -> None:\n    \"\"\"\n    Validate item configuration.\n\n    :param item_type: type of item.\n    :param package_path: path to a package folder.\n\n    :raises AEAConfigException: if something is wrong with item configuration.\n    \"\"\"\n    item_config = load_item_config(item_type, package_path)\n    loader = ConfigLoaders.from_package_type(item_type)\n    for field_name in loader.required_fields:\n        try:\n            getattr(item_config, field_name)\n        except AttributeError:\n            raise AEAConfigException(\n                \"Parameter '{}' is missing from {} config.\".format(\n                    field_name, item_type\n                )\n            )\n\n\ndef get_non_vendor_package_path(aea_project_path: Path) -> Set[Path]:\n    \"\"\"\n    Get all the paths to non-vendor packages.\n\n    :param aea_project_path: the path to an AEA project.\n    :return: the set of paths, one for each non-vendor package configuration file.\n    \"\"\"\n    result: Set[Path] = set()\n    for item_type_plural in ComponentType.plurals():\n        nonvendor_package_dir_of_type = aea_project_path / item_type_plural\n        result = result.union(\n            {p for p in nonvendor_package_dir_of_type.iterdir() if p.is_dir()}\n            if nonvendor_package_dir_of_type.exists()\n            else {}\n        )\n    return result\n"
  },
  {
    "path": "aea/cli/utils/constants.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Module with constants of the aea cli.\"\"\"\nimport os\nfrom pathlib import Path\n\nfrom aea.configurations.constants import (\n    CONNECTION,\n    CONNECTIONS,\n    CONTRACT,\n    CONTRACTS,\n    PACKAGES,\n    PROTOCOL,\n    PROTOCOLS,\n    SKILL,\n    SKILLS,\n    VENDOR,\n)\nfrom aea.helpers.constants import FROM_STRING_TO_TYPE\n\n\nAEA_DIR = str(Path(\".\"))\n\nITEM_TYPES = (CONNECTION, CONTRACT, PROTOCOL, SKILL)\n\nAEA_LOGO = \"    _     _____     _    \\r\\n   / \\\\   | ____|   / \\\\   \\r\\n  / _ \\\\  |  _|    / _ \\\\  \\r\\n / ___ \\\\ | |___  / ___ \\\\ \\r\\n/_/   \\\\_\\\\|_____|/_/   \\\\_\\\\\\r\\n                         \\r\\n\"\nAUTHOR_KEY = \"author\"\nCLI_CONFIG_PATH = os.path.join(os.path.expanduser(\"~\"), \".aea\", \"cli_config.yaml\")\nNOT_PERMITTED_AUTHORS = [\n    CONNECTIONS,\n    CONTRACTS,\n    PROTOCOLS,\n    SKILLS,\n    VENDOR,\n    PACKAGES,\n    \"aea\",\n]\n\n\nCONFIG_SUPPORTED_KEY_TYPES = list(FROM_STRING_TO_TYPE.keys())\n\nREQUIREMENTS = \"requirements.txt\"\nSTUB_CONNECTION = \"fetchai/stub:latest\"\n"
  },
  {
    "path": "aea/cli/utils/context.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"A module with context tools of the aea cli.\"\"\"\nimport os\nfrom pathlib import Path\nfrom typing import Any, Dict, List, Optional, cast\n\nfrom aea.cli.utils.loggers import logger\nfrom aea.configurations.base import (\n    AgentConfig,\n    Dependencies,\n    PackageType,\n    PublicId,\n    _get_default_configuration_file_name_from_type,\n)\nfrom aea.configurations.constants import (\n    CONNECTION,\n    CONTRACT,\n    DEFAULT_AEA_CONFIG_FILE,\n    DEFAULT_REGISTRY_NAME,\n    PROTOCOL,\n    SKILL,\n    VENDOR,\n)\nfrom aea.configurations.loader import ConfigLoader\nfrom aea.configurations.pypi import merge_dependencies_list\nfrom aea.helpers.io import open_file\n\n\nclass Context:\n    \"\"\"A class to keep configuration of the cli tool.\"\"\"\n\n    agent_config: AgentConfig\n\n    def __init__(self, cwd: str, verbosity: str, registry_path: Optional[str]) -> None:\n        \"\"\"Init the context.\"\"\"\n        self.config = {}  # type: Dict\n        self.cwd = cwd\n        self.verbosity = verbosity\n        self.clean_paths: List = []\n        self._registry_path = registry_path\n\n    @property\n    def registry_path(self) -> str:\n        \"\"\"Get registry path specified or from config or default one with check is it present.\"\"\"\n        # registry path is provided or in config or default\n        if self._registry_path:\n            registry_path = Path(self._registry_path)\n            if not (registry_path.exists() and registry_path.is_dir()):\n                raise ValueError(\n                    f\"Registry path directory provided ({self._registry_path}) can not be found. Current work dir is {self.cwd}\"\n                )\n            return str(registry_path)\n\n        registry_path = (Path(self.cwd) / DEFAULT_REGISTRY_NAME).absolute()\n        if registry_path.is_dir():\n            return str(registry_path)\n        registry_path = (Path(self.cwd) / \"..\" / DEFAULT_REGISTRY_NAME).absolute()\n        if registry_path.is_dir():\n            return str(registry_path)\n        raise ValueError(\n            f\"Registry path not provided and local registry `{DEFAULT_REGISTRY_NAME}` not found in current ({self.cwd}) and parent directory.\"\n        )\n\n    @property\n    def skip_aea_validation(self) -> bool:\n        \"\"\"\n        Get the 'skip_aea_validation' flag.\n\n        If true, validation of the AEA version for loaded configuration\n        file is skipped.\n\n        :return: the 'skip_aea_validation'\n        \"\"\"\n        return self.config.get(\"skip_aea_validation\", True)\n\n    @property\n    def agent_loader(self) -> ConfigLoader:\n        \"\"\"Get the agent loader.\"\"\"\n        return ConfigLoader.from_configuration_type(\n            PackageType.AGENT, skip_aea_validation=self.skip_aea_validation\n        )\n\n    @property\n    def protocol_loader(self) -> ConfigLoader:\n        \"\"\"Get the protocol loader.\"\"\"\n        return ConfigLoader.from_configuration_type(\n            PackageType.PROTOCOL, skip_aea_validation=self.skip_aea_validation\n        )\n\n    @property\n    def connection_loader(self) -> ConfigLoader:\n        \"\"\"Get the connection loader.\"\"\"\n        return ConfigLoader.from_configuration_type(\n            PackageType.CONNECTION, skip_aea_validation=self.skip_aea_validation\n        )\n\n    @property\n    def skill_loader(self) -> ConfigLoader:\n        \"\"\"Get the skill loader.\"\"\"\n        return ConfigLoader.from_configuration_type(\n            PackageType.SKILL, skip_aea_validation=self.skip_aea_validation\n        )\n\n    @property\n    def contract_loader(self) -> ConfigLoader:\n        \"\"\"Get the contract loader.\"\"\"\n        return ConfigLoader.from_configuration_type(\n            PackageType.CONTRACT, skip_aea_validation=self.skip_aea_validation\n        )\n\n    def set_config(self, key: str, value: Any) -> None:\n        \"\"\"\n        Set a config.\n\n        :param key: the key for the configuration.\n        :param value: the value associated with the key.\n        \"\"\"\n        self.config[key] = value\n        logger.debug(\"  config[{}] = {}\".format(key, value))\n\n    @staticmethod\n    def _get_item_dependencies(item_type: str, public_id: PublicId) -> Dependencies:\n        \"\"\"Get the dependencies from item type and public id.\"\"\"\n        item_type_plural = item_type + \"s\"\n        default_config_file_name = _get_default_configuration_file_name_from_type(\n            item_type\n        )\n        path = Path(\n            VENDOR,\n            public_id.author,\n            item_type_plural,\n            public_id.name,\n            default_config_file_name,\n        )\n        if not path.exists():\n            path = Path(item_type_plural, public_id.name, default_config_file_name)\n        config_loader = ConfigLoader.from_configuration_type(item_type)\n        with open_file(path) as fp:\n            config = config_loader.load(fp)\n        deps = cast(Dependencies, config.dependencies)\n        return deps\n\n    def get_dependencies(self) -> Dependencies:\n        \"\"\"\n        Aggregate the dependencies from every component.\n\n        :return: a list of dependency version specification. e.g. [\"gym >= 1.0.0\"]\n        \"\"\"\n        protocol_dependencies = [\n            self._get_item_dependencies(PROTOCOL, protocol_id)\n            for protocol_id in self.agent_config.protocols\n        ]\n        connection_dependencies = [\n            self._get_item_dependencies(CONNECTION, connection_id)\n            for connection_id in self.agent_config.connections\n        ]\n        skill_dependencies = [\n            self._get_item_dependencies(SKILL, skill_id)\n            for skill_id in self.agent_config.skills\n        ]\n        contract_dependencies = [\n            self._get_item_dependencies(CONTRACT, contract_id)\n            for contract_id in self.agent_config.contracts\n        ]\n\n        all_dependencies = [\n            self.agent_config.dependencies,\n            *protocol_dependencies,\n            *connection_dependencies,\n            *skill_dependencies,\n            *contract_dependencies,\n        ]\n\n        result = merge_dependencies_list(*all_dependencies)\n        return result\n\n    def dump_agent_config(self) -> None:\n        \"\"\"Dump the current agent configuration.\"\"\"\n        with open(\n            os.path.join(self.cwd, DEFAULT_AEA_CONFIG_FILE), \"w\", encoding=\"utf-8\"\n        ) as f:\n            self.agent_loader.dump(self.agent_config, f)\n"
  },
  {
    "path": "aea/cli/utils/decorators.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Module with decorators of the aea cli.\"\"\"\n\nimport os\nimport shutil\nfrom functools import update_wrapper\nfrom pathlib import Path\nfrom typing import Any, Callable, Dict, Tuple, Union, cast\n\nimport click\nfrom jsonschema import ValidationError\n\nfrom aea.cli.utils.config import try_to_load_agent_config\nfrom aea.cli.utils.context import Context\nfrom aea.configurations.base import (\n    PackageType,\n    PublicId,\n    _check_aea_version,\n    _compare_fingerprints,\n    _get_default_configuration_file_name_from_type,\n)\nfrom aea.configurations.constants import VENDOR\nfrom aea.configurations.loader import ConfigLoaders\nfrom aea.exceptions import AEAException, AEAValidationError, enforce\nfrom aea.helpers.base import decorator_with_optional_params\nfrom aea.helpers.io import open_file\n\n\npass_ctx = click.make_pass_decorator(Context)\n\n\ndef _validate_config_consistency(ctx: Context, check_aea_version: bool = True) -> None:\n    \"\"\"\n    Validate fingerprints for every agent component.\n\n    :param ctx: the context\n    :param check_aea_version: whether it should check also the AEA version.\n    :raises ValueError: if there is a missing configuration file.\n                       or if the configuration file is not valid.\n                       or if the fingerprints do not match\n    \"\"\"\n\n    if check_aea_version:\n        _check_aea_version(ctx.agent_config)\n\n    packages_public_ids_to_types = dict(\n        [\n            *map(lambda x: (x, PackageType.PROTOCOL), ctx.agent_config.protocols),\n            *map(\n                lambda x: (x, PackageType.CONNECTION),\n                ctx.agent_config.connections,\n            ),\n            *map(lambda x: (x, PackageType.SKILL), ctx.agent_config.skills),\n            *map(lambda x: (x, PackageType.CONTRACT), ctx.agent_config.contracts),\n        ]\n    )  # type: Dict[PublicId, PackageType]\n\n    for public_id, item_type in packages_public_ids_to_types.items():\n\n        # find the configuration file.\n        try:\n            # either in vendor/ or in personal packages.\n            # we give precedence to custom agent components (i.e. not vendorized).\n            package_directory = Path(item_type.to_plural(), public_id.name)\n            is_vendor = False\n            if not package_directory.exists():\n                package_directory = Path(\n                    VENDOR, public_id.author, item_type.to_plural(), public_id.name\n                )\n                is_vendor = True\n            # we fail if none of the two alternative works.\n            enforce(package_directory.exists(), \"Package directory does not exist!\")\n\n            loader = ConfigLoaders.from_package_type(item_type)\n            config_file_name = _get_default_configuration_file_name_from_type(item_type)\n            configuration_file_path = package_directory / config_file_name\n            enforce(\n                configuration_file_path.exists(),\n                \"Configuration file path does not exist!\",\n            )\n        except Exception:\n            raise ValueError(\"Cannot find {}: '{}'\".format(item_type.value, public_id))\n\n        # load the configuration file.\n        try:\n            with open_file(configuration_file_path, \"r\") as fp:\n                package_configuration = loader.load(fp)\n        except (AEAValidationError, ValidationError) as e:\n            raise ValueError(\n                \"{} configuration file '{}' not valid: {}\".format(\n                    item_type.value.capitalize(), configuration_file_path, str(e)\n                )\n            )\n\n        if check_aea_version:\n            _check_aea_version(package_configuration)\n        _compare_fingerprints(\n            package_configuration, package_directory, is_vendor, item_type\n        )\n\n\ndef _check_aea_project(\n    args: Tuple[Any, ...],\n    check_aea_version: bool = True,\n    check_finger_prints: bool = False,\n) -> None:\n    try:\n        click_context = args[0]\n        ctx = cast(Context, click_context.obj)\n        try_to_load_agent_config(ctx)\n        skip_consistency_check = ctx.config[\"skip_consistency_check\"]\n        if not skip_consistency_check:\n            _validate_config_consistency(ctx, check_aea_version=check_aea_version)\n        if check_finger_prints:\n            _compare_fingerprints(\n                ctx.agent_config,\n                Path(ctx.cwd),\n                is_vendor=False,\n                item_type=PackageType.AGENT,\n                is_recursive=False,\n            )\n    except Exception as e:  # pylint: disable=broad-except\n        raise click.ClickException(str(e)) from e\n\n\n@decorator_with_optional_params\ndef check_aea_project(\n    f: Callable, check_aea_version: bool = True, check_finger_prints: bool = False\n) -> Callable:\n    \"\"\"\n    Check the consistency of the project as a decorator.\n\n    - try to load agent configuration file\n    - iterate over all the agent packages and check for consistency.\n\n    :param f: callable\n    :param check_aea_version: whether or not to check aea version\n    :param check_finger_prints: whether or not to check fingerprints\n    :return: callable\n    \"\"\"\n\n    def wrapper(*args: Any, **kwargs: Any) -> Callable:\n        _check_aea_project(\n            args,\n            check_aea_version=check_aea_version,\n            check_finger_prints=check_finger_prints,\n        )\n        return f(*args, **kwargs)\n\n    return update_wrapper(wrapper, f)\n\n\ndef _rmdirs(*paths: str) -> None:\n    \"\"\"\n    Remove directories.\n\n    :param paths: paths to folders to remove.\n    \"\"\"\n    for path in paths:\n        if os.path.exists(path):\n            shutil.rmtree(path)\n\n\ndef _cast_ctx(context: Union[Context, click.core.Context]) -> Context:\n    \"\"\"\n    Cast a Context object from context if needed.\n\n    :param context: Context or click.core.Context object.\n\n    :return: context object.\n    :raises: AEAException if context is none of Context and click.core.Context types.\n    \"\"\"\n    if isinstance(context, Context):\n        return context\n    if isinstance(context, click.core.Context):  # pragma: no cover\n        return cast(Context, context.obj)\n    raise AEAException(  # pragma: no cover\n        \"clean_after decorator should be used only on methods with Context \"\n        \"or click.core.Context object as a first argument.\"\n    )\n\n\ndef clean_after(func: Callable) -> Callable:\n    \"\"\"\n    Decorate a function to remove created folders after ClickException raise.\n\n    :param func: a method to decorate.\n\n    :return: decorated method.\n    \"\"\"\n\n    def wrapper(\n        context: Union[Context, click.core.Context], *args: Any, **kwargs: Any\n    ) -> Callable:\n        \"\"\"\n        Call a source method, remove dirs listed in ctx.clean_paths if ClickException is raised.\n\n        :param context: context object.\n        :param args: positional arguments.\n        :param kwargs: keyword arguments.\n\n        :raises ClickException: if caught re-raises it.  # noqa: DAR402\n\n        :return: source method output.\n        \"\"\"\n        ctx = _cast_ctx(context)\n        try:\n            return func(context, *args, **kwargs)\n        except click.ClickException as e:\n            _rmdirs(*ctx.clean_paths)\n            raise e\n\n    return wrapper\n"
  },
  {
    "path": "aea/cli/utils/exceptions.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Module with exceptions of the aea cli.\"\"\"\n\nfrom aea.exceptions import AEAException\n\n\nclass AEAConfigException(AEAException):\n    \"\"\"Exception about AEA configuration.\"\"\"\n\n\nclass InterruptInputException(Exception):\n    \"\"\"An exception to mark an interruption event.\"\"\"\n"
  },
  {
    "path": "aea/cli/utils/formatting.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Module with formatting utils of the aea cli.\"\"\"\n\nfrom typing import Dict, List\n\nfrom aea.configurations.base import AgentConfig\nfrom aea.configurations.loader import ConfigLoader\nfrom aea.exceptions import enforce\nfrom aea.helpers.io import open_file\n\n\ndef format_items(items: List[Dict]) -> str:\n    \"\"\"Format list of items (protocols/connections) to a string for CLI output.\"\"\"\n    list_str = \"\"\n    for item in items:\n        list_str += (\n            \"{line}\\n\"\n            \"Public ID: {public_id}\\n\"\n            \"Name: {name}\\n\"\n            \"Description: {description}\\n\"\n            \"Author: {author}\\n\"\n            \"Version: {version}\\n\"\n            \"{line}\\n\".format(\n                name=item[\"name\"],\n                public_id=item[\"public_id\"],\n                description=item[\"description\"],\n                author=item[\"author\"],\n                version=item[\"version\"],\n                line=\"-\" * 30,\n            )\n        )\n    return list_str\n\n\ndef retrieve_details(name: str, loader: ConfigLoader, config_filepath: str) -> Dict:\n    \"\"\"Return description of a protocol, skill, connection.\"\"\"\n    with open_file(str(config_filepath)) as fp:\n        config = loader.load(fp)\n    item_name = config.agent_name if isinstance(config, AgentConfig) else config.name\n    enforce(item_name == name, \"Item names do not match!\")\n    return {\n        \"public_id\": str(config.public_id),\n        \"name\": item_name,\n        \"author\": config.author,\n        \"description\": config.description,\n        \"version\": config.version,\n    }\n\n\ndef sort_items(items: List[Dict]) -> List[Dict]:\n    \"\"\"\n    Sort a list of dict items associated with packages.\n\n    :param items: list of dicts that represent items.\n\n    :return: sorted list.\n    \"\"\"\n    return sorted(items, key=lambda k: k[\"name\"])\n"
  },
  {
    "path": "aea/cli/utils/generic.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Module with generic utils of the aea cli.\"\"\"\nimport os\nfrom typing import Dict\n\nimport yaml\nfrom click import ClickException\n\nfrom aea.helpers.io import open_file\n\n\ndef load_yaml(filepath: str) -> Dict:\n    \"\"\"\n    Read content from yaml file.\n\n    :param filepath: str path to yaml file.\n\n    :return: dict YAML content\n    \"\"\"\n    with open_file(filepath, \"r\") as f:\n        try:\n            result = yaml.safe_load(f)\n            return result if result is not None else {}\n        except yaml.YAMLError as e:\n            raise ClickException(\n                \"Loading yaml config from {} failed: {}\".format(filepath, e)\n            )\n\n\ndef is_readme_present(readme_path: str) -> bool:\n    \"\"\"\n    Check is readme file present.\n\n    This method is needed for proper testing.\n\n    :param readme_path: path to readme file.\n\n    :return: bool is readme file present.\n    \"\"\"\n    return os.path.exists(readme_path)\n"
  },
  {
    "path": "aea/cli/utils/loggers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Helpers for the logging module.\"\"\"\n\nimport logging\nimport sys\nfrom typing import Any, Callable\n\nimport click\n\n\nOFF = 100\nlogging.addLevelName(OFF, \"OFF\")\n\nLOG_LEVELS = [\"NOTSET\", \"DEBUG\", \"INFO\", \"WARNING\", \"ERROR\", \"CRITICAL\", \"OFF\"]\n\n\nclass ColorFormatter(logging.Formatter):\n    \"\"\"The default formatter for cli output.\"\"\"\n\n    colors = {\n        \"error\": dict(fg=\"red\"),\n        \"exception\": dict(fg=\"red\"),\n        \"critical\": dict(fg=\"red\"),\n        \"debug\": dict(fg=\"blue\"),\n        \"info\": dict(fg=\"green\"),\n        \"warning\": dict(fg=\"yellow\"),\n    }\n\n    def format(self, record: logging.LogRecord) -> str:\n        \"\"\"Format the log message.\"\"\"\n        if not record.exc_info:\n            level = record.levelname.lower()\n            msg = record.getMessage()\n            if level in self.colors:\n                prefix = click.style(\"{}: \".format(level), **self.colors[level])  # type: ignore\n                msg = \"\\n\".join(prefix + x for x in msg.splitlines())\n            return msg\n        return logging.Formatter.format(self, record)  # pragma: no cover\n\n\ndef simple_verbosity_option(\n    logger_: logging.Logger, *names: str, **kwargs: Any\n) -> Callable:  # pylint: disable=redefined-outer-name,keyword-arg-before-vararg\n    \"\"\"Add a decorator that adds a `--verbosity, -v` option to the decorated command.\n\n    Name can be configured through `*names`. Keyword arguments are passed to\n    the underlying `click.option` decorator.\n\n    :param logger_: the logger\n    :param names: list of names\n    :param kwargs: keyword arguments\n    :return: callable\n    \"\"\"\n    if not names:\n        names = (\"--verbosity\", \"-v\")\n\n    kwargs.setdefault(\"default\", \"INFO\")\n    kwargs.setdefault(\"type\", click.Choice(LOG_LEVELS, case_sensitive=False))\n    kwargs.setdefault(\"metavar\", \"LVL\")\n    kwargs.setdefault(\"expose_value\", False)\n    kwargs.setdefault(\"help\", \"One of {}\".format(\", \".join(LOG_LEVELS)))\n    kwargs.setdefault(\"is_eager\", True)\n\n    def decorator(f: Callable) -> Callable:\n        def _set_level(\n            ctx: click.Context,\n            param: Any,  # pylint: disable=unused-argument\n            value: str,\n        ) -> None:\n            level = logging.getLevelName(value)\n            logger_.setLevel(level)\n            # save verbosity option so it can be\n            # read in the main CLI entrypoint\n            ctx.meta[\"verbosity\"] = value\n\n        return click.option(*names, callback=_set_level, **kwargs)(f)\n\n    return decorator\n\n\ndef default_logging_config(\n    logger_: logging.Logger,\n) -> logging.Logger:  # pylint: disable=redefined-outer-name\n    \"\"\"Set up the default handler and formatter on the given logger.\"\"\"\n    default_handler = logging.StreamHandler(stream=sys.stdout)\n    default_handler.formatter = ColorFormatter()\n    logger_.handlers = [default_handler]\n    logger_.propagate = True\n    return logger_\n\n\nlogger = logging.getLogger(\"aea\")\nlogger = default_logging_config(logger)\n"
  },
  {
    "path": "aea/cli/utils/package_utils.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Module with package utils of the aea cli.\"\"\"\nimport os\nimport re\nimport shutil\nfrom pathlib import Path\nfrom typing import Any, Dict, Optional, Set, Tuple, Union\n\nimport click\nfrom jsonschema import ValidationError\n\nfrom aea import AEA_DIR, get_current_aea_version\nfrom aea.cli.fingerprint import fingerprint_item\nfrom aea.cli.utils.config import (\n    dump_item_config,\n    get_non_vendor_package_path,\n    load_item_config,\n)\nfrom aea.cli.utils.constants import NOT_PERMITTED_AUTHORS\nfrom aea.cli.utils.context import Context\nfrom aea.cli.utils.loggers import logger\nfrom aea.configurations.base import (\n    AgentConfig,\n    ComponentConfiguration,\n    ComponentId,\n    ComponentType,\n    PackageConfiguration,\n    PackageType,\n    PublicId,\n    _compute_fingerprint,\n    _get_default_configuration_file_name_from_type,\n)\nfrom aea.configurations.constants import DEFAULT_AEA_CONFIG_FILE\nfrom aea.configurations.constants import (\n    DISTRIBUTED_PACKAGES as DISTRIBUTED_PACKAGES_STR,\n)\nfrom aea.configurations.constants import (\n    IMPORT_TEMPLATE_1,\n    IMPORT_TEMPLATE_2,\n    LEDGER_CONNECTION,\n    PACKAGES,\n    PACKAGE_PUBLIC_ID_VAR_NAME,\n    SKILL,\n    VENDOR,\n)\nfrom aea.configurations.loader import ConfigLoader\nfrom aea.configurations.manager import AgentConfigManager\nfrom aea.configurations.utils import replace_component_ids\nfrom aea.crypto.helpers import get_wallet_from_agent_config, private_key_verify\nfrom aea.crypto.ledger_apis import LedgerApis\nfrom aea.crypto.wallet import Wallet\nfrom aea.exceptions import AEAEnforceError\nfrom aea.helpers.base import compute_specifier_from_version, recursive_update\nfrom aea.helpers.io import open_file\nfrom aea.helpers.sym_link import create_symlink\n\n\nDISTRIBUTED_PACKAGES = [PublicId.from_str(dp) for dp in DISTRIBUTED_PACKAGES_STR]\nROOT = Path(\".\")\n\n\ndef verify_private_keys_ctx(\n    ctx: Context,\n    aea_project_path: Path = ROOT,\n    password: Optional[str] = None,\n) -> None:\n    \"\"\"\n    Verify private keys with ctx provided.\n\n    :param ctx: Context\n    :param aea_project_path: the path to the aea project\n    :param password: the password to encrypt/decrypt the private key.\n    \"\"\"\n    try:\n        AgentConfigManager.verify_private_keys(\n            aea_project_path,\n            private_key_helper=private_key_verify,\n            substitude_env_vars=False,\n            password=password,\n        ).dump_config()\n        agent_config = AgentConfigManager.verify_private_keys(\n            aea_project_path,\n            private_key_helper=private_key_verify,\n            password=password,\n        ).agent_config\n        if ctx is not None:\n            ctx.agent_config = agent_config\n    except ValueError as e:  # pragma: nocover\n        raise click.ClickException(str(e))\n\n\ndef validate_package_name(package_name: str) -> None:\n    \"\"\"Check that the package name matches the pattern r\"[a-zA-Z_][a-zA-Z0-9_]*\".\n\n    >>> validate_package_name(\"this_is_a_good_package_name\")\n    >>> validate_package_name(\"this-is-not\")\n    Traceback (most recent call last):\n    ...\n    click.exceptions.BadParameter: this-is-not is not a valid package name.\n\n    :param package_name: the package name\n    \"\"\"\n    if re.fullmatch(PublicId.PACKAGE_NAME_REGEX, package_name) is None:\n        raise click.BadParameter(\"{} is not a valid package name.\".format(package_name))\n\n\ndef _is_valid_author_handle(author: str) -> bool:\n    \"\"\"\n    Check that the author matches the pattern r\"[a-zA-Z_][a-zA-Z0-9_]*\".\n\n    >>> _is_valid_author_handle(\"this_is_a_good_author_name\")\n    ...\n    True\n    >>> _is_valid_author_handle(\"this-is-not\")\n    ...\n    False\n\n    :param author: author name\n    :return: bool indicating whether author name is valid\n    \"\"\"\n    if re.fullmatch(PublicId.AUTHOR_REGEX, author) is None:\n        return False\n    return True\n\n\ndef _is_permitted_author_handle(author: str) -> bool:\n    \"\"\"\n    Check that the author handle is permitted.\n\n    :param author: the author\n    :return: bool\n    \"\"\"\n    result = author not in NOT_PERMITTED_AUTHORS\n    return result\n\n\n# mostly for tests\ndef is_path_exist(path: Union[str, Path]) -> bool:\n    \"\"\"\n    Check path provided exists.\n\n    :param path: str or Path\n\n    :return: bool\n    \"\"\"\n    return os.path.exists(path)\n\n\ndef try_get_item_source_path(\n    path: str, author_name: Optional[str], item_type_plural: str, item_name: str\n) -> str:\n    \"\"\"\n    Get the item source path.\n\n    :param path: the source path root\n    :param author_name: the name of the author of the item\n    :param item_type_plural: the item type (plural)\n    :param item_name: the item name\n\n    :return: the item source path\n    \"\"\"\n    if author_name is None:\n        source_path = os.path.join(path, item_type_plural, item_name)\n    else:\n        source_path = os.path.join(path, author_name, item_type_plural, item_name)\n    if not is_path_exist(source_path):\n        raise click.ClickException(\n            f'Item \"{author_name}/{item_name}\" not found in source folder \"{source_path}\".'\n        )\n    return source_path\n\n\ndef try_get_item_target_path(\n    path: str, author_name: str, item_type_plural: str, item_name: str\n) -> str:\n    \"\"\"\n    Get the item target path.\n\n    :param path: the target path root\n    :param author_name: the author name\n    :param item_type_plural: the item type (plural)\n    :param item_name: the item name\n\n    :return: the item target path\n    \"\"\"\n    target_path = os.path.join(path, author_name, item_type_plural, item_name)\n    if is_path_exist(target_path):\n        path_ = Path(target_path)\n        raise click.ClickException(\n            f'Item \"{path_.name}\" already exists in target folder \"{path_.parent}\".'\n        )\n    return target_path\n\n\ndef get_package_path(\n    project_directory: str, item_type: str, public_id: PublicId, is_vendor: bool = True\n) -> str:\n    \"\"\"\n    Get a vendorized path for a package.\n\n    :param project_directory: path to search packages\n    :param item_type: item type.\n    :param public_id: item public ID.\n    :param is_vendor: flag for vendorized path (True by default).\n\n    :return: vendorized destination path for package.\n    \"\"\"\n    item_type_plural = item_type + \"s\"\n    if is_vendor:\n        return os.path.join(\n            project_directory,\n            VENDOR,\n            public_id.author,\n            item_type_plural,\n            public_id.name,\n        )\n    return os.path.join(project_directory, item_type_plural, public_id.name)\n\n\ndef get_package_path_unified(\n    project_directory: str,\n    agent_config: AgentConfig,\n    item_type: str,\n    public_id: PublicId,\n) -> str:\n    \"\"\"\n    Get a path for a package, either vendor or not.\n\n    That is:\n    - if the author in the public id is not the same of the AEA project author,\n      just look into vendor/\n    - Otherwise, first look into local packages, then into vendor/.\n\n    :param project_directory: directory to look for packages.\n    :param agent_config: agent configuration.\n    :param item_type: item type.\n    :param public_id: item public ID.\n\n    :return: vendorized destination path for package.\n    \"\"\"\n    vendor_path = get_package_path(\n        project_directory, item_type, public_id, is_vendor=True\n    )\n    if agent_config.author != public_id.author or not is_item_present(\n        project_directory, agent_config, item_type, public_id, is_vendor=False\n    ):\n        return vendor_path\n    return get_package_path(project_directory, item_type, public_id, is_vendor=False)\n\n\ndef get_dotted_package_path_unified(\n    project_directory: str, agent_config: AgentConfig, *args: Any\n) -> str:\n    \"\"\"\n    Get a *dotted* path for a package, either vendor or not.\n\n    :param project_directory: base dir for package lookup.\n    :param agent_config: AgentConfig.\n    :param args: arguments for 'get_package_path_unified'\n\n    :return: the dotted path to the package.\n    \"\"\"\n    path = get_package_path_unified(project_directory, agent_config, *args)\n    path_relative_to_cwd = Path(path).relative_to(Path(project_directory))\n    relative_path_str = str(path_relative_to_cwd).replace(os.sep, \".\")\n    return relative_path_str\n\n\ndef copy_package_directory(src: Path, dst: str) -> Path:\n    \"\"\"\n     Copy a package directory to the agent vendor resources.\n\n    :param src: source path to the package to be added.\n    :param dst: str package destination path.\n\n    :return: copied folder target path.\n    :raises ClickException: if the copy raises an exception.\n    \"\"\"\n    # copy the item package into the agent's supported packages.\n    src_path = str(src.absolute())\n    logger.debug(\"Copying modules. src={} dst={}\".format(src_path, dst))\n    try:\n        shutil.copytree(src_path, dst)\n    except Exception as e:  # pylint: disable=broad-except\n        raise click.ClickException(str(e))\n\n    items_folder = os.path.split(dst)[0]\n    Path(items_folder, \"__init__.py\").touch()\n    return Path(dst)\n\n\ndef find_item_locally(\n    ctx: Context, item_type: str, item_public_id: PublicId\n) -> Tuple[Path, ComponentConfiguration]:\n    \"\"\"\n    Find an item in the local registry.\n\n    :param ctx: the CLI context.\n    :param item_type: the type of the item to load. One of: protocols, connections, skills\n    :param item_public_id: the public id of the item to find.\n\n    :return: tuple of path to the package directory (either in registry or in aea directory) and component configuration\n\n    :raises ClickException: if the search fails.\n    \"\"\"\n    item_type_plural = item_type + \"s\"\n    item_name = item_public_id.name\n\n    try:\n        registry_path = ctx.registry_path\n    except ValueError as e:\n        raise click.ClickException(str(e))\n\n    # check in registry\n    package_path = Path(\n        registry_path, item_public_id.author, item_type_plural, item_name\n    )\n    config_file_name = _get_default_configuration_file_name_from_type(item_type)\n    item_configuration_filepath = package_path / config_file_name\n    if not item_configuration_filepath.exists():\n        raise click.ClickException(\n            \"Cannot find {}: '{}'.\".format(item_type, item_public_id)\n        )\n\n    # try to load the item configuration file\n    try:\n        item_configuration_loader = ConfigLoader.from_configuration_type(\n            PackageType(item_type)\n        )\n        with open_file(item_configuration_filepath) as fp:\n            item_configuration = item_configuration_loader.load(fp)\n    except ValidationError as e:\n        raise click.ClickException(\n            \"{} configuration file not valid: {}\".format(item_type.capitalize(), str(e))\n        )\n\n    # check that the configuration file of the found package matches the expected author and version.\n    version = item_configuration.version\n    author = item_configuration.author\n    if item_public_id.author != author or (\n        not item_public_id.package_version.is_latest\n        and item_public_id.version != version\n    ):\n        raise click.ClickException(\n            \"Cannot find {} with author and version specified.\".format(item_type)\n        )\n\n    return package_path, item_configuration\n\n\ndef find_item_in_distribution(  # pylint: disable=unused-argument\n    ctx: Context, item_type: str, item_public_id: PublicId\n) -> Path:\n    \"\"\"\n    Find an item in the AEA directory.\n\n    :param ctx: the CLI context.\n    :param item_type: the type of the item to load. One of: protocols, connections, skills\n    :param item_public_id: the public id of the item to find.\n    :return: path to the package directory (either in registry or in aea directory).\n    :raises ClickException: if the search fails.\n    \"\"\"\n    item_type_plural = item_type + \"s\"\n    item_name = item_public_id.name\n\n    # check in aea dir\n    package_path = Path(AEA_DIR, item_type_plural, item_name)\n    config_file_name = _get_default_configuration_file_name_from_type(item_type)\n    item_configuration_filepath = package_path / config_file_name\n    if not item_configuration_filepath.exists():\n        raise click.ClickException(\n            \"Cannot find {}: '{}'.\".format(item_type, item_public_id)\n        )\n\n    # try to load the item configuration file\n    try:\n        item_configuration_loader = ConfigLoader.from_configuration_type(\n            PackageType(item_type)\n        )\n        with open_file(item_configuration_filepath) as fp:\n            item_configuration = item_configuration_loader.load(fp)\n    except ValidationError as e:\n        raise click.ClickException(\n            \"{} configuration file not valid: {}\".format(item_type.capitalize(), str(e))\n        )\n\n    # check that the configuration file of the found package matches the expected author and version.\n    version = item_configuration.version\n    author = item_configuration.author\n    if item_public_id.author != author or (\n        not item_public_id.package_version.is_latest\n        and item_public_id.version != version\n    ):\n        raise click.ClickException(\n            \"Cannot find {} with author and version specified.\".format(item_type)\n        )\n\n    return package_path  # pragma: no cover\n\n\ndef validate_author_name(author: Optional[str] = None) -> str:\n    \"\"\"\n    Validate an author name.\n\n    :param author: the author name (optional)\n    :return: validated author name\n    \"\"\"\n    is_acceptable_author = False\n    if (\n        author is not None\n        and _is_valid_author_handle(author)\n        and _is_permitted_author_handle(author)\n    ):\n        is_acceptable_author = True\n        valid_author = author\n    while not is_acceptable_author:\n        author_prompt = click.prompt(\n            \"Please enter the author handle you would like to use\", type=str\n        )\n        valid_author = author_prompt\n        if _is_valid_author_handle(author_prompt) and _is_permitted_author_handle(\n            author_prompt\n        ):\n            is_acceptable_author = True\n        elif not _is_valid_author_handle(author_prompt):\n            is_acceptable_author = False\n            click.echo(\n                \"Not a valid author handle. Please try again. \"\n                \"Author handles must satisfy the following regex: {}\".format(\n                    PublicId.AUTHOR_REGEX\n                )\n            )\n        elif not _is_permitted_author_handle(author_prompt):\n            is_acceptable_author = False\n            click.echo(\n                \"Not a permitted author handle. The following author handles are not allowed: {}\".format(\n                    NOT_PERMITTED_AUTHORS\n                )\n            )\n\n    return valid_author\n\n\ndef is_fingerprint_correct(\n    package_path: Path, item_config: PackageConfiguration\n) -> bool:\n    \"\"\"\n    Validate fingerprint of item before adding.\n\n    :param package_path: path to a package folder.\n    :param item_config: item configuration.\n    :return: bool indicating correctness of fingerprint.\n    \"\"\"\n    fingerprint = _compute_fingerprint(\n        package_path, ignore_patterns=item_config.fingerprint_ignore_patterns\n    )\n    return item_config.fingerprint == fingerprint\n\n\ndef register_item(ctx: Context, item_type: str, item_public_id: PublicId) -> None:\n    \"\"\"\n    Register item in agent configuration.\n\n    :param ctx: click context object.\n    :param item_type: type of item.\n    :param item_public_id: PublicId of item.\n    \"\"\"\n    logger.debug(\n        \"Registering the {} into {}\".format(item_type, DEFAULT_AEA_CONFIG_FILE)\n    )\n    supported_items = get_items(ctx.agent_config, item_type)\n    supported_items.add(item_public_id)\n    with open_file(os.path.join(ctx.cwd, DEFAULT_AEA_CONFIG_FILE), \"w\") as fp:\n        ctx.agent_loader.dump(ctx.agent_config, fp)\n\n\ndef is_item_present_unified(\n    ctx: Context, item_type: str, item_public_id: PublicId\n) -> bool:\n    \"\"\"\n    Check if item is present, either vendor or not.\n\n    That is:\n    - if the author in the public id is not the same of the AEA project author,\n      just look into vendor/\n    - Otherwise, first look into local packages, then into vendor/.\n\n    :param ctx: context object.\n    :param item_type: type of an item.\n    :param item_public_id: PublicId of an item.\n    :return: True if the item is present, False otherwise.\n    \"\"\"\n    is_in_vendor = is_item_present(\n        ctx.cwd, ctx.agent_config, item_type, item_public_id, is_vendor=True\n    )\n    if item_public_id.author != ctx.agent_config.author:\n        return is_in_vendor\n    return is_in_vendor or is_item_present(\n        ctx.cwd, ctx.agent_config, item_type, item_public_id, is_vendor=False\n    )\n\n\ndef is_item_present(\n    path: str,\n    agent_config: AgentConfig,\n    item_type: str,\n    item_public_id: PublicId,\n    is_vendor: bool = True,\n    with_version: bool = False,\n) -> bool:\n    \"\"\"\n    Check if item is already present in AEA.\n\n    Optionally, consider the check also with the version.\n\n    :param path: path to look for packages.\n    :param agent_config: agent config\n    :param item_type: type of an item.\n    :param item_public_id: PublicId of an item.\n    :param is_vendor: flag for vendorized path (True by default).\n    :param with_version: if true, consider also the package version.\n\n    :return: boolean is item present.\n    \"\"\"\n    item_path = Path(\n        get_package_path(path, item_type, item_public_id, is_vendor=is_vendor)\n    )\n    registered_item_public_id = get_item_public_id_by_author_name(\n        agent_config, item_type, item_public_id.author, item_public_id.name\n    )\n    is_item_registered_no_version = registered_item_public_id is not None\n    does_path_exist = Path(item_path).exists()\n    if item_public_id.package_version.is_latest or not with_version:\n        return is_item_registered_no_version and does_path_exist\n\n    # the following makes sense because public id is not latest\n    component_id = ComponentId(ComponentType(item_type), item_public_id)\n    component_is_registered = component_id in agent_config.package_dependencies\n    return component_is_registered and does_path_exist\n\n\ndef get_item_id_present(\n    agent_config: AgentConfig, item_type: str, item_public_id: PublicId\n) -> PublicId:\n    \"\"\"\n    Get the item present in AEA.\n\n    :param agent_config: AgentConfig.\n    :param item_type: type of an item.\n    :param item_public_id: PublicId of an item.\n\n    :return: boolean is item present.\n    :raises: AEAEnforceError\n    \"\"\"\n    registered_item_public_id = get_item_public_id_by_author_name(\n        agent_config, item_type, item_public_id.author, item_public_id.name\n    )\n    if registered_item_public_id is None:\n        raise AEAEnforceError(\"Cannot find item.\")  # pragma: nocover\n    return registered_item_public_id\n\n\ndef get_item_public_id_by_author_name(\n    agent_config: AgentConfig, item_type: str, author: str, name: str\n) -> Optional[PublicId]:\n    \"\"\"\n    Get component public_id by author and name.\n\n    :param agent_config: AgentConfig\n    :param item_type: str. component type: connection, skill, contract, protocol\n    :param author: str. author name\n    :param name: str. component name\n\n    :return: PublicId\n    \"\"\"\n    items_in_config = {\n        (x.author, x.name): x for x in get_items(agent_config, item_type)\n    }\n    return items_in_config.get((author, name), None)\n\n\ndef get_items(agent_config: AgentConfig, item_type: str) -> Set[PublicId]:\n    \"\"\"\n    Get all items of certain type registered in AgentConfig.\n\n    :param agent_config: AgentConfig\n    :param item_type: str. component type: connection, skill, contract, protocol\n\n    :return: set of public ids\n    \"\"\"\n    item_type_plural = item_type + \"s\"\n    return getattr(agent_config, item_type_plural)\n\n\ndef is_distributed_item(item_public_id: PublicId) -> bool:\n    \"\"\"\n    Check whether the item public id correspond to a package in the distribution.\n\n    If the provided item has version 'latest', only the prefixes are compared.\n    Otherwise, the function will try to match the exact version occurrence among the distributed packages.\n\n    :param item_public_id: public id of the item\n    :return: bool, indicating whether distributed or not\n    \"\"\"\n    if item_public_id.package_version.is_latest:\n        return any(item_public_id.same_prefix(other) for other in DISTRIBUTED_PACKAGES)\n    return item_public_id in DISTRIBUTED_PACKAGES\n\n\ndef _override_ledger_configurations(agent_config: AgentConfig) -> None:\n    \"\"\"Override LedgerApis configurations with agent override configurations.\"\"\"\n    ledger_component_id = ComponentId(\n        ComponentType.CONNECTION, PublicId.from_str(LEDGER_CONNECTION)\n    )\n    prefix_to_component_configuration = {\n        key.component_prefix: value\n        for key, value in agent_config.component_configurations.items()\n    }\n    if ledger_component_id.component_prefix not in prefix_to_component_configuration:\n        return\n    ledger_apis_config = prefix_to_component_configuration[\n        ledger_component_id.component_prefix\n    ][\"config\"].get(\"ledger_apis\", {})\n    recursive_update(LedgerApis.ledger_api_configs, ledger_apis_config)\n\n\ndef try_get_balance(  # pylint: disable=unused-argument\n    agent_config: AgentConfig, wallet: Wallet, type_: str\n) -> int:\n    \"\"\"\n    Try to get wallet balance.\n\n    :param agent_config: agent config object.\n    :param wallet: wallet object.\n    :param type_: type of ledger API.\n\n    :return: token balance.\n    \"\"\"\n    try:\n        if not LedgerApis.has_ledger(type_):  # pragma: no cover\n            raise ValueError(\"No ledger api config for {} available.\".format(type_))\n        address = wallet.addresses.get(type_)\n        if address is None:  # pragma: no cover\n            raise ValueError(\"No key '{}' in wallet.\".format(type_))\n        balance = LedgerApis.get_balance(type_, address)\n        if balance is None:  # pragma: no cover\n            raise ValueError(\"No balance returned!\")\n        return balance\n    except ValueError as e:  # pragma: no cover\n        raise click.ClickException(str(e))\n\n\ndef get_wallet_from_context(ctx: Context, password: Optional[str] = None) -> Wallet:\n    \"\"\"\n    Get wallet from current click Context.\n\n    :param ctx: click context\n    :param password: the password to encrypt/decrypt private keys\n\n    :return: wallet\n    \"\"\"\n    verify_private_keys_ctx(ctx=ctx, password=password)\n    wallet = get_wallet_from_agent_config(ctx.agent_config, password=password)\n    return wallet\n\n\ndef update_item_public_id_in_init(\n    item_type: str, package_path: Path, item_id: PublicId\n) -> None:\n    \"\"\"\n    Update item config and item config file.\n\n    :param item_type: type of item.\n    :param package_path: path to a package folder.\n    :param item_id: public_id\n    \"\"\"\n    if item_type != SKILL:\n        return\n    init_filepath = os.path.join(package_path, \"__init__.py\")\n    with open_file(init_filepath, \"r\") as f:\n        file_content = f.readlines()\n    with open_file(init_filepath, \"w\") as f:\n        for line in file_content:\n            if PACKAGE_PUBLIC_ID_VAR_NAME in line:\n                f.write(\n                    f'{PACKAGE_PUBLIC_ID_VAR_NAME} = PublicId.from_str(\"{str(item_id)}\")'\n                )\n            else:\n                f.write(line)\n\n\ndef update_references(\n    ctx: Context, replacements: Dict[ComponentId, ComponentId]\n) -> None:\n    \"\"\"\n    Update references across an AEA project.\n\n    Caveat: the update is done in a sequential manner. There is no check\n    of multiple updates, due to the occurrence of transitive relations.\n    E.g. replacements as {c1: c2, c2: c3} might lead to c1 replaced with c3\n      instead of c2.\n\n    :param ctx: the context.\n    :param replacements: mapping from old component ids to new component ids.\n    \"\"\"\n    # preprocess replacement so to index them by component type\n    replacements_by_type: Dict[ComponentType, Dict[PublicId, PublicId]] = {}\n    for old, new in replacements.items():\n        replacements_by_type.setdefault(old.component_type, {})[\n            old.public_id\n        ] = new.public_id\n\n    aea_project_root = Path(ctx.cwd)\n    # update agent configuration\n    agent_config = load_item_config(PackageType.AGENT.value, aea_project_root)\n    replace_component_ids(agent_config, replacements_by_type)\n    dump_item_config(agent_config, aea_project_root)\n\n    # update every (non-vendor) AEA package.\n    for package_path in get_non_vendor_package_path(aea_project_root):\n        package_type = PackageType(package_path.parent.name[:-1])\n        package_config = load_item_config(package_type.value, package_path)\n        replace_component_ids(package_config, replacements_by_type)\n        dump_item_config(package_config, package_path)\n\n\ndef create_symlink_vendor_to_local(\n    ctx: Context, item_type: str, public_id: PublicId\n) -> None:\n    \"\"\"\n    Creates a symlink from the vendor to the local folder.\n\n    :param ctx: click context\n    :param item_type: item type\n    :param public_id: public_id of the item\n    \"\"\"\n    vendor_path_str = get_package_path(ctx.cwd, item_type, public_id, is_vendor=True)\n    local_path = get_package_path(ctx.cwd, item_type, public_id, is_vendor=False)\n    vendor_path = Path(vendor_path_str)\n    if not os.path.exists(vendor_path.parent):\n        os.makedirs(vendor_path.parent)\n    create_symlink(vendor_path, Path(local_path), Path(ctx.cwd))\n\n\ndef create_symlink_packages_to_vendor(ctx: Context) -> None:\n    \"\"\"\n    Creates a symlink from a local packages to the vendor folder.\n\n    :param ctx: click context\n    \"\"\"\n    if not os.path.exists(PACKAGES):\n        create_symlink(Path(PACKAGES), Path(VENDOR), Path(ctx.cwd))\n\n\ndef replace_all_import_statements(\n    aea_project_path: Path,\n    item_type: ComponentType,\n    old_public_id: PublicId,\n    new_public_id: PublicId,\n) -> None:\n    \"\"\"\n    Replace all import statements in Python modules of all the non-vendor packages.\n\n    The function looks for two patterns:\n    - from packages.<author>.<item_type_plural>.<name>\n    - import packages.<author>.<item_type_plural>.<name>\n\n    :param aea_project_path: path to the AEA project.\n    :param item_type: the item type.\n    :param old_public_id: the old public id.\n    :param new_public_id: the new public id.\n    \"\"\"\n    old_formats = dict(\n        author=old_public_id.author, type=item_type.to_plural(), name=old_public_id.name\n    )\n    new_formats = dict(\n        author=new_public_id.author, type=item_type.to_plural(), name=new_public_id.name\n    )\n    old_import_1 = IMPORT_TEMPLATE_1.format(**old_formats)\n    old_import_2 = IMPORT_TEMPLATE_2.format(**old_formats)\n    new_import_1 = IMPORT_TEMPLATE_1.format(**new_formats)\n    new_import_2 = IMPORT_TEMPLATE_2.format(**new_formats)\n\n    pattern_1 = re.compile(rf\"^{old_import_1}\", re.MULTILINE)\n    pattern_2 = re.compile(rf\"^{old_import_2}\", re.MULTILINE)\n\n    for package_path in get_non_vendor_package_path(aea_project_path):\n        for python_module in package_path.rglob(\"*.py\"):\n            content = python_module.read_text()\n            content = pattern_1.sub(new_import_1, content)\n            content = pattern_2.sub(new_import_2, content)\n            python_module.write_text(content)\n\n\ndef fingerprint_all(ctx: Context) -> None:\n    \"\"\"\n    Fingerprint all non-vendor packages.\n\n    :param ctx: the CLI context.\n    \"\"\"\n    aea_project_path = Path(ctx.cwd)\n    for package_path in get_non_vendor_package_path(aea_project_path):\n        item_type = package_path.parent.name[:-1]\n        config = load_item_config(item_type, package_path)\n        fingerprint_item(ctx, item_type, config.public_id)\n\n\ndef update_aea_version_range(package_configuration: PackageConfiguration) -> None:\n    \"\"\"Update 'aea_version' range.\"\"\"\n    version = get_current_aea_version()\n    if not package_configuration.aea_version_specifiers.contains(version):\n        new_aea_version = compute_specifier_from_version(version)\n        old_aea_version = package_configuration.aea_version\n        click.echo(\n            f\"Updating AEA version specifier from {old_aea_version} to {new_aea_version}.\"\n        )\n        package_configuration.aea_version = new_aea_version\n"
  },
  {
    "path": "aea/common.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the common types and interfaces used in the aea framework.\"\"\"\nimport os\nfrom pathlib import Path\nfrom typing import Any, Dict, List, Optional, Union\n\n\nAddress = str\n\nPrimitive = Union[str, int, bool, float]\n_JSONDict = Dict[Any, Any]  # temporary placeholder\n_JSONList = List[Any]  # temporary placeholder\n_JSONType = Optional[Union[Primitive, _JSONDict, _JSONList]]\nJSONLike = Dict[str, _JSONType]\nPathLike = Union[os.PathLike, Path, str]\n"
  },
  {
    "path": "aea/components/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains utilities for AEA components.\"\"\"\n"
  },
  {
    "path": "aea/components/base.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains definitions of agent components.\"\"\"\nimport importlib.util\nimport logging\nimport sys\nimport types\nfrom abc import ABC\nfrom pathlib import Path\nfrom typing import Any, Optional\n\nfrom aea.configurations.base import (\n    ComponentConfiguration,\n    ComponentId,\n    ComponentType,\n    PublicId,\n)\nfrom aea.configurations.constants import PACKAGES\nfrom aea.exceptions import AEAEnforceError\nfrom aea.helpers.logging import WithLogger\n\n\n_default_logger = logging.getLogger(__name__)\n\n\nclass Component(ABC, WithLogger):\n    \"\"\"Abstract class for an agent component.\"\"\"\n\n    __slots__ = (\"_configuration\", \"_directory\", \"_is_vendor\")\n\n    def __init__(\n        self,\n        configuration: Optional[ComponentConfiguration] = None,\n        is_vendor: bool = False,\n        **kwargs: Any,\n    ) -> None:\n        \"\"\"\n        Initialize a package.\n\n        :param configuration: the package configuration.\n        :param is_vendor: whether the package is vendorized.\n        :param kwargs: the keyword arguments for the logger.\n        \"\"\"\n        WithLogger.__init__(self, **kwargs)\n        self._configuration = configuration\n        self._directory = None  # type: Optional[Path]\n        self._is_vendor = is_vendor\n\n    @property\n    def component_type(self) -> ComponentType:\n        \"\"\"Get the component type.\"\"\"\n        return self.configuration.component_type\n\n    @property\n    def is_vendor(self) -> bool:\n        \"\"\"Get whether the component is vendorized or not.\"\"\"\n        return self._is_vendor\n\n    @property\n    def prefix_import_path(self) -> str:\n        \"\"\"Get the prefix import path for this component.\"\"\"\n        return self.configuration.prefix_import_path\n\n    @property\n    def component_id(self) -> ComponentId:\n        \"\"\"Ge the package id.\"\"\"\n        return self.configuration.component_id\n\n    @property\n    def public_id(self) -> PublicId:\n        \"\"\"Get the public id.\"\"\"\n        return self.configuration.public_id\n\n    @property\n    def configuration(self) -> ComponentConfiguration:\n        \"\"\"Get the component configuration.\"\"\"\n        if self._configuration is None:  # pragma: nocover\n            raise ValueError(\"The component is not associated with a configuration.\")\n        return self._configuration\n\n    @property\n    def directory(self) -> Path:\n        \"\"\"Get the directory. Raise error if it has not been set yet.\"\"\"\n        if self._directory is None:\n            raise ValueError(\"Directory not set yet.\")\n        return self._directory\n\n    @directory.setter\n    def directory(self, path: Path) -> None:\n        \"\"\"Set the directory. Raise error if already set.\"\"\"\n        if self._directory is not None:  # pragma: nocover\n            raise ValueError(\"Directory already set.\")\n        self._directory = path\n\n    @property\n    def build_directory(self) -> Optional[str]:\n        \"\"\"Get build directory for the component.\"\"\"\n        return self.configuration.build_directory\n\n\ndef load_aea_package(configuration: ComponentConfiguration) -> None:\n    \"\"\"\n    Load the AEA package from configuration.\n\n    It adds all the __init__.py modules into `sys.modules`.\n\n    :param configuration: the configuration object.\n    \"\"\"\n    dir_ = configuration.directory\n    if dir_ is None:  # pragma: nocover\n        raise ValueError(\"configuration's directory is None.\")\n    author = configuration.author\n    package_type_plural = configuration.component_type.to_plural()\n    package_name = configuration.name\n    perform_load_aea_package(dir_, author, package_type_plural, package_name)\n\n\ndef perform_load_aea_package(\n    dir_: Path, author: str, package_type_plural: str, package_name: str\n) -> None:\n    \"\"\"\n    Load the AEA package from values provided.\n\n    It adds all the __init__.py modules into `sys.modules`.\n\n    :param dir_: path of the component.\n    :param author: str\n    :param package_type_plural: str\n    :param package_name: str\n    \"\"\"\n\n    if dir_ is None or not dir_.exists():  # pragma: nocover\n        raise AEAEnforceError(f\"configuration directory `{dir_}` does not exists.\")\n\n    prefix_root = PACKAGES\n    prefix_author = prefix_root + f\".{author}\"\n    prefix_pkg_type = prefix_author + f\".{package_type_plural}\"\n\n    prefix_root_module = types.ModuleType(prefix_root)\n    prefix_root_module.__path__ = None  # type: ignore\n    sys.modules[prefix_root] = sys.modules.get(prefix_root, prefix_root_module)\n    author_module = types.ModuleType(prefix_author)\n    author_module.__path__ = None  # type: ignore\n    sys.modules[prefix_author] = sys.modules.get(prefix_author, author_module)\n    prefix_pkg_type_module = types.ModuleType(prefix_pkg_type)\n    prefix_pkg_type_module.__path__ = None  # type: ignore\n    sys.modules[prefix_pkg_type] = sys.modules.get(\n        prefix_pkg_type, prefix_pkg_type_module\n    )\n\n    prefix_pkg = prefix_pkg_type + f\".{package_name}\"\n\n    for subpackage_init_file in dir_.rglob(\"__init__.py\"):\n        parent_dir = subpackage_init_file.parent\n        relative_parent_dir = parent_dir.relative_to(dir_)\n        if relative_parent_dir == Path(\".\"):\n            # this handles the case when 'subpackage_init_file'\n            # is path/to/package/__init__.py\n            import_path = prefix_pkg\n        else:  # pragma: nocover\n            import_path = prefix_pkg + \".\" + \".\".join(relative_parent_dir.parts)\n\n        spec = importlib.util.spec_from_file_location(import_path, subpackage_init_file)\n        if spec is None:\n            raise RuntimeError(f\"Error load module from {subpackage_init_file}\")\n        module = importlib.util.module_from_spec(spec)\n        sys.modules[import_path] = module\n        _default_logger.debug(f\"loading {import_path}: {module}\")\n        spec.loader.exec_module(module)  # type: ignore\n"
  },
  {
    "path": "aea/components/loader.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains utilities for loading components.\"\"\"\nimport re\nfrom typing import Dict, Type\n\nfrom aea.components.base import Component\nfrom aea.configurations.base import ComponentConfiguration, ComponentType\nfrom aea.configurations.constants import PACKAGES\nfrom aea.connections.base import Connection\nfrom aea.contracts.base import Contract\nfrom aea.exceptions import (\n    AEAComponentLoadException,\n    AEAInstantiationException,\n    AEAPackageLoadingError,\n    enforce,\n    parse_exception,\n)\nfrom aea.protocols.base import Protocol\nfrom aea.skills.base import Skill\n\n\ndef component_type_to_class(component_type: ComponentType) -> Type[Component]:\n    \"\"\"\n    Get the component class from the component type.\n\n    :param component_type: the component type\n    :return: the component class\n    \"\"\"\n    type_to_class: Dict[ComponentType, Type[Component]] = {\n        ComponentType.PROTOCOL: Protocol,\n        ComponentType.CONTRACT: Contract,\n        ComponentType.CONNECTION: Connection,\n        ComponentType.SKILL: Skill,\n    }\n    return type_to_class[component_type]\n\n\ndef load_component_from_config(  # type: ignore  # pylint: disable=inconsistent-return-statements #pylint mistake\n    configuration: ComponentConfiguration, *args, **kwargs\n) -> Component:\n    \"\"\"\n    Load a component from a directory.\n\n    :param configuration: the component configuration.\n    :param args: the positional arguments.\n    :param kwargs: the keyword arguments.\n    :return: the component instance.\n    \"\"\"\n    component_type = configuration.component_type\n    component_class = component_type_to_class(component_type)\n    try:\n        return component_class.from_config(*args, configuration=configuration, **kwargs)  # type: ignore\n    except AEAInstantiationException as e:\n        raise e\n    except AEAComponentLoadException as e:\n        raise AEAPackageLoadingError(\n            \"Package loading error: An error occurred while loading {} {}: {}\".format(\n                str(configuration.component_type), configuration.public_id, e\n            )\n        )\n    except ModuleNotFoundError as e:\n        _handle_error_while_loading_component_module_not_found(configuration, e)\n    except Exception as e:  # pylint: disable=broad-except\n        _handle_error_while_loading_component_generic_error(configuration, e)\n\n\nclass AEAPackageNotFound(Exception):\n    \"\"\"Exception when failed to import package, cause not exists.\"\"\"\n\n\ndef _handle_error_while_loading_component_module_not_found(\n    configuration: ComponentConfiguration, e: ModuleNotFoundError\n) -> None:\n    \"\"\"\n    Handle ModuleNotFoundError for AEA packages.\n\n    It will rewrite the error message only if the import path starts with 'packages'.\n    To do that, it will extract the wrong import path from the error message.\n\n    Depending on the import path, the possible error messages can be:\n\n    - \"No AEA package found with author name '{}', type '{}', name '{}'\"\n    - \"'{}' is not a valid type name, choose one of ['protocols', 'connections', 'skills', 'contracts']\"\n    - \"The package '{}/{}' of type '{}' exists, but cannot find module '{}'\"\n\n    :param configuration: the configuration\n    :param e: the exception\n    :raises ModuleNotFoundError: if it is not  # noqa: DAR402\n    :raises AEAPackageLoadingError: the same exception, but prepending an informative message.\n    \"\"\"\n    error_message = str(e)\n    match = re.match(r\"No module named '([\\w.]+)'\", error_message)\n    if match is None:\n        # if for some reason we cannot extract the import path, just re-raise the error\n        raise e from e\n\n    import_path = match.group(1)\n    parts = import_path.split(\".\")\n    nb_parts = len(parts)\n    if parts[0] != PACKAGES or nb_parts < 2:\n        # if the first part of the import path is not 'packages',\n        # the error is due for other reasons - just re-raise the error\n        raise e from e\n\n    def get_new_error_message_no_package_found() -> str:\n        \"\"\"Create a new error message in case the package is not found.\"\"\"\n        enforce(nb_parts <= 4, \"More than 4 parts!\")\n        author = parts[1]\n        new_message = \"No AEA package found with author name '{}'\".format(author)\n\n        if nb_parts >= 3:\n            pkg_type = parts[2]\n            try:\n                ComponentType(pkg_type[:-1])\n            except ValueError:\n                return \"'{}' is not a valid type name, choose one of {}\".format(\n                    pkg_type, list(map(lambda x: x.to_plural(), ComponentType))\n                )\n            new_message += \", type '{}'\".format(pkg_type)\n        if nb_parts == 4:\n            pkg_name = parts[3]\n            new_message += \", name '{}'\".format(pkg_name)\n        return new_message\n\n    def get_new_error_message_with_package_found() -> str:\n        \"\"\"Create a new error message in case the package is found.\"\"\"\n        enforce(nb_parts >= 5, \"Less than 5 parts!\")\n        author, pkg_name, pkg_type = parts[:3]\n        the_rest = \".\".join(parts[4:])\n        return \"The package '{}/{}' of type '{}' exists, but cannot find module '{}'\".format(\n            author, pkg_name, pkg_type, the_rest\n        )\n\n    if nb_parts < 5:\n        new_message = get_new_error_message_no_package_found()\n    else:\n        new_message = get_new_error_message_with_package_found()\n\n    new_exc = AEAPackageNotFound(new_message)\n    new_exc.__traceback__ = e.__traceback__\n    e_str = parse_exception(new_exc)\n    raise AEAPackageLoadingError(\n        \"Package loading error: An error occurred while loading {} {}:\\n{}\".format(\n            str(configuration.component_type),\n            configuration.public_id,\n            e_str,\n        )\n    )\n\n\ndef _handle_error_while_loading_component_generic_error(\n    configuration: ComponentConfiguration, e: Exception\n) -> None:\n    \"\"\"\n    Handle Exception for AEA packages.\n\n    :param configuration: the configuration\n    :param e: the exception\n    :raises AEAPackageLoadingError: the same exception, but prepending an informative message.\n    \"\"\"\n    e_str = parse_exception(e)\n    raise AEAPackageLoadingError(\n        \"Package loading error: An error occurred while loading {} {}: {}\".format(\n            str(configuration.component_type), configuration.public_id, e_str\n        )\n    ) from e\n"
  },
  {
    "path": "aea/components/utils.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the component loading utils.\"\"\"\n\n\nimport re\nimport sys\nfrom pathlib import Path\nfrom typing import Dict, List\n\nfrom aea.components.base import perform_load_aea_package\nfrom aea.configurations.constants import CONNECTIONS, CONTRACTS, PROTOCOLS, SKILLS\n\n\nPACKAGES_RE = re.compile(r\"^packages\\.(\\w+)\\.(\\w+)\\.(\\w+)$\", re.I)\n\n\ndef _enlist_component_packages() -> Dict[str, List[Dict[str, str]]]:\n    \"\"\"List all components packages already loaded.\"\"\"\n    result: Dict[str, List[Dict[str, str]]] = {}\n\n    for name, mod in sys.modules.items():\n        match = PACKAGES_RE.match(name)\n        if not match:\n            continue\n        author, package_type, package_name = match.groups()\n        packages = result.get(package_type, [])\n        package_data = {\n            \"author\": author,\n            \"package_type\": package_type,\n            \"package_name\": package_name,\n            \"dir\": mod.__dict__[\"__path__\"][0],\n        }\n        packages.append(package_data)\n        result[package_type] = packages\n    return result\n\n\n# no cover cause executed in a subprocess, not possible to track\ndef _populate_packages(packages: dict) -> None:  # pragma: nocover\n    \"\"\"Load packages as python modules.\"\"\"\n    for package_type in [PROTOCOLS, CONTRACTS, CONNECTIONS, SKILLS]:\n        for package in packages.get(package_type, []):\n            # load package\n            print(11, package)\n            perform_load_aea_package(\n                dir_=Path(package[\"dir\"]),\n                author=package[\"author\"],\n                package_type_plural=package[\"package_type\"],\n                package_name=package[\"package_name\"],\n            )\n"
  },
  {
    "path": "aea/configurations/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the configuration modules.\"\"\"\n"
  },
  {
    "path": "aea/configurations/base.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Classes to handle AEA configurations.\"\"\"\nimport pprint\nfrom abc import ABC\nfrom collections import OrderedDict\nfrom copy import copy, deepcopy\nfrom operator import attrgetter\nfrom pathlib import Path\nfrom typing import (\n    Any,\n    Collection,\n    Dict,\n    FrozenSet,\n    List,\n    Optional,\n    Sequence,\n    Set,\n    Tuple,\n    Type,\n    TypeVar,\n    Union,\n    cast,\n)\n\nimport packaging\nfrom packaging.specifiers import SpecifierSet\nfrom packaging.version import Version\n\nfrom aea.__version__ import __version__ as __aea_version__\nfrom aea.configurations.constants import (\n    CONNECTIONS,\n    CONTRACTS,\n    DEFAULT_AEA_CONFIG_FILE,\n    DEFAULT_CONNECTION_CONFIG_FILE,\n    DEFAULT_CONTRACT_CONFIG_FILE,\n    DEFAULT_FINGERPRINT_IGNORE_PATTERNS,\n    DEFAULT_LICENSE,\n    DEFAULT_LOGGING_CONFIG,\n    DEFAULT_PROTOCOL_CONFIG_FILE,\n    DEFAULT_SKILL_CONFIG_FILE,\n    DEFAULT_VERSION,\n    PACKAGE_PUBLIC_ID_VAR_NAME,\n    PROTOCOLS,\n    SKILLS,\n)\nfrom aea.configurations.data_types import (\n    CRUDCollection,\n    ComponentId,\n    ComponentType,\n    Dependencies,\n    Dependency,\n    JSONSerializable,\n    PackageId,\n    PackageType,\n    PackageVersion,\n    PublicId,\n)\nfrom aea.configurations.validation import ConfigValidator, validate_data_with_pattern\nfrom aea.exceptions import enforce\nfrom aea.helpers.base import (\n    CertRequest,\n    SimpleId,\n    SimpleIdOrStr,\n    load_module,\n    recursive_update,\n)\nfrom aea.helpers.ipfs.base import IPFSHashOnly\n\n\n# for tests\n_ = [PackageId, PackageVersion]\n\n\nT = TypeVar(\"T\")\n\n\ndef dependencies_from_json(obj: Dict[str, Dict]) -> Dependencies:\n    \"\"\"\n    Parse a JSON object to get an instance of Dependencies.\n\n    :param obj: a dictionary whose keys are package names and values are dictionary with package specifications.\n    :return: a Dependencies object.\n    \"\"\"\n    return {key: Dependency.from_json({key: value}) for key, value in obj.items()}\n\n\ndef dependencies_to_json(dependencies: Dependencies) -> Dict[str, Dict]:\n    \"\"\"\n    Transform a Dependencies object into a JSON object.\n\n    :param dependencies: an instance of \"Dependencies\" type.\n    :return: a dictionary whose keys are package names and\n             values are the JSON version of a Dependency object.\n    \"\"\"\n    result = {}\n    for key, value in dependencies.items():\n        dep_to_json = value.to_json()\n        package_name = list(dep_to_json.items())[0][0]\n        enforce(\n            key == package_name, f\"Names of dependency differ: {key} != {package_name}\"\n        )\n        result[key] = dep_to_json[key]\n    return result\n\n\ndef _get_default_configuration_file_name_from_type(\n    item_type: Union[str, PackageType]\n) -> str:\n    \"\"\"Get the default configuration file name from item type.\"\"\"\n    item_type = PackageType(item_type)\n    if item_type == PackageType.AGENT:\n        return DEFAULT_AEA_CONFIG_FILE\n    if item_type == PackageType.PROTOCOL:\n        return DEFAULT_PROTOCOL_CONFIG_FILE\n    if item_type == PackageType.CONNECTION:\n        return DEFAULT_CONNECTION_CONFIG_FILE\n    if item_type == PackageType.SKILL:\n        return DEFAULT_SKILL_CONFIG_FILE\n    if item_type == PackageType.CONTRACT:\n        return DEFAULT_CONTRACT_CONFIG_FILE\n    raise ValueError(  # pragma: no cover\n        \"Item type not valid: {}\".format(str(item_type))\n    )\n\n\nclass ProtocolSpecificationParseError(Exception):\n    \"\"\"Exception for parsing a protocol specification file.\"\"\"\n\n\nclass Configuration(JSONSerializable, ABC):\n    \"\"\"Configuration class.\"\"\"\n\n    __slots__ = (\"_key_order\",)\n\n    def __init__(self) -> None:\n        \"\"\"Initialize a configuration object.\"\"\"\n        # a list of keys that remembers the key order of the configuration file.\n        # this is set by the configuration loader.\n        self._key_order: List[str] = []\n\n    @classmethod\n    def from_json(cls, obj: Dict) -> \"Configuration\":\n        \"\"\"Build from a JSON object.\"\"\"\n\n    @property\n    def ordered_json(self) -> OrderedDict:\n        \"\"\"\n        Reorder the dictionary according to a key ordering.\n\n        This method takes all the keys in the key_order list and\n        get the associated value in the dictionary (if present).\n        For the remaining keys not considered in the order,\n        it will use alphanumerical ordering.\n\n        In particular, if key_order is an empty sequence, this reduces to\n        alphanumerical sorting.\n\n        It does not do side-effect.\n        :return: the ordered dictionary.\n        \"\"\"\n        data = self.json\n        result = OrderedDict()  # type: OrderedDict\n\n        # parse all the known keys. This might ignore some keys in the dictionary.\n        seen_keys = set()\n        for key in self._key_order:\n            enforce(key not in result, \"Key in results!\")\n            value = data.get(key)\n            if value is not None:\n                result[key] = value\n                seen_keys.add(key)\n\n        # Now process the keys in the dictionary that were not covered before.\n        for key, value in data.items():\n            if key not in seen_keys:\n                result[key] = value\n        return result\n\n\nclass PackageConfiguration(Configuration, ABC):\n    \"\"\"\n    This class represent a package configuration.\n\n    A package can be one of:\n    - agents\n    - protocols\n    - connections\n    - skills\n    - contracts\n    \"\"\"\n\n    __slots__ = (\n        \"_name\",\n        \"_author\",\n        \"version\",\n        \"license\",\n        \"fingerprint\",\n        \"fingerprint_ignore_patterns\",\n        \"build_entrypoint\",\n        \"_aea_version\",\n        \"_aea_version_specifiers\",\n        \"_directory\",\n    )\n\n    default_configuration_filename: str\n    package_type: PackageType\n    FIELDS_ALLOWED_TO_UPDATE: FrozenSet[str] = frozenset([\"build_directory\"])\n    schema: str\n    CHECK_EXCLUDES: List[Tuple[str]] = []\n\n    def __init__(\n        self,\n        name: SimpleIdOrStr,\n        author: SimpleIdOrStr,\n        version: str = \"\",\n        license_: str = \"\",\n        aea_version: str = \"\",\n        fingerprint: Optional[Dict[str, str]] = None,\n        fingerprint_ignore_patterns: Optional[Sequence[str]] = None,\n        build_entrypoint: Optional[str] = None,\n    ) -> None:\n        \"\"\"\n        Initialize a package configuration.\n\n        :param name: the name of the package.\n        :param author: the author of the package.\n        :param version: the version of the package (SemVer format).\n        :param license_: the license.\n        :param aea_version: either a fixed version, or a set of specifiers describing the AEA versions allowed. (default: empty string - no constraint). The fixed version is interpreted with the specifier '=='.\n        :param fingerprint: the fingerprint.\n        :param fingerprint_ignore_patterns: a list of file patterns to ignore files to fingerprint.\n        :param build_entrypoint: path to a script to execute at build time.\n        \"\"\"\n        super().__init__()\n        if name is None or author is None:  # pragma: nocover\n            raise ValueError(\"Name and author must be set on the configuration!\")\n        self._name = SimpleId(name)\n        self._author = SimpleId(author)\n        self.version = version if version != \"\" else DEFAULT_VERSION\n        self.license = license_ if license_ != \"\" else DEFAULT_LICENSE\n        self.fingerprint = fingerprint if fingerprint is not None else {}\n        self.fingerprint_ignore_patterns = (\n            fingerprint_ignore_patterns\n            if fingerprint_ignore_patterns is not None\n            else []\n        )\n        self.build_entrypoint = build_entrypoint\n        self._aea_version = aea_version if aea_version != \"\" else __aea_version__\n        self._aea_version_specifiers = self.parse_aea_version_specifier(aea_version)\n\n        self._directory = None  # type: Optional[Path]\n\n    @property\n    def name(self) -> str:\n        \"\"\"Get the name.\"\"\"\n        return str(self._name)\n\n    @name.setter\n    def name(self, value: SimpleIdOrStr) -> None:\n        \"\"\"Set the name.\"\"\"\n        self._name = SimpleId(value)\n\n    @property\n    def author(self) -> str:\n        \"\"\"Get the author.\"\"\"\n        return str(self._author)\n\n    @author.setter\n    def author(self, value: SimpleIdOrStr) -> None:\n        \"\"\"Set the author.\"\"\"\n        self._author = SimpleId(value)\n\n    @property\n    def aea_version(self) -> str:\n        \"\"\"Get the 'aea_version' attribute.\"\"\"\n        return self._aea_version\n\n    @aea_version.setter\n    def aea_version(self, new_aea_version: str) -> None:\n        \"\"\"Set the 'aea_version' attribute.\"\"\"\n        self._aea_version_specifiers = self.parse_aea_version_specifier(new_aea_version)\n        self._aea_version = new_aea_version\n\n    def check_aea_version(self) -> None:\n        \"\"\"\n        Check that the AEA version matches the specifier set.\n\n        :raises ValueError if the version of the aea framework falls within a specifier.\n        \"\"\"\n        _check_aea_version(self)\n\n    @property\n    def directory(self) -> Optional[Path]:\n        \"\"\"Get the path to the configuration file associated to this file, if any.\"\"\"\n        return self._directory\n\n    @directory.setter\n    def directory(self, directory: Path) -> None:\n        \"\"\"Set directory if not already set.\"\"\"\n        if self._directory is not None:  # pragma: nocover\n            raise ValueError(\"Directory already set\")\n        self._directory = directory\n\n    @property\n    def package_id(self) -> PackageId:\n        \"\"\"Get package id.\"\"\"\n        return PackageId(package_type=self.package_type, public_id=self.public_id)\n\n    @staticmethod\n    def parse_aea_version_specifier(aea_version_specifiers: str) -> SpecifierSet:\n        \"\"\"\n        Parse an 'aea_version' field.\n\n        If 'aea_version' is a version, then output the specifier set \"==${version}\"\n        Else, interpret it as specifier set.\n\n        :param aea_version_specifiers: the AEA version, or a specifier set.\n        :return: A specifier set object.\n        \"\"\"\n        try:\n            Version(aea_version_specifiers)\n            return SpecifierSet(\"==\" + aea_version_specifiers)\n        except packaging.version.InvalidVersion:\n            pass\n        return SpecifierSet(aea_version_specifiers)\n\n    @property\n    def aea_version_specifiers(self) -> SpecifierSet:\n        \"\"\"Get the AEA version set specifier.\"\"\"\n        return self._aea_version_specifiers\n\n    @property\n    def public_id(self) -> PublicId:\n        \"\"\"Get the public id.\"\"\"\n        return PublicId(self.author, self.name, self.version)\n\n    @property\n    def package_dependencies(self) -> Set[ComponentId]:\n        \"\"\"Get the package dependencies.\"\"\"\n        return set()\n\n    def update(self, data: Dict, env_vars_friendly: bool = False) -> None:\n        \"\"\"\n        Update configuration with other data.\n\n        :param data: the data to replace.\n        :param env_vars_friendly: whether or not it is env vars friendly.\n        \"\"\"\n        if not data:  # do nothing if nothing to update\n            return\n\n        self.check_overrides_valid(data, env_vars_friendly=env_vars_friendly)\n        self._create_or_update_from_json(\n            obj=self.make_resulting_config_data(data), instance=self\n        )\n\n    @classmethod\n    def validate_config_data(\n        cls, json_data: Dict, env_vars_friendly: bool = False\n    ) -> None:\n        \"\"\"Perform config validation.\"\"\"\n        ConfigValidator(cls.schema, env_vars_friendly=env_vars_friendly).validate(\n            json_data\n        )\n\n    @classmethod\n    def from_json(cls, obj: Dict) -> \"PackageConfiguration\":\n        \"\"\"Initialize from a JSON object.\"\"\"\n        return cls._create_or_update_from_json(obj=obj, instance=None)\n\n    @classmethod\n    def _create_or_update_from_json(\n        cls, obj: Dict, instance: Any = None\n    ) -> \"PackageConfiguration\":\n        \"\"\"Create new config object or updates existing one from json data.\"\"\"\n        raise NotImplementedError  # pragma: nocover\n\n    def make_resulting_config_data(self, overrides: Dict) -> Dict:\n        \"\"\"\n        Make config data with overrides applied.\n\n        Does not update config, just creates json representation.\n\n        :param overrides: the overrides\n        :return: config with overrides applied\n        \"\"\"\n        current_config = self.json\n        recursive_update(current_config, overrides, allow_new_values=True)\n        return current_config\n\n    def check_overrides_valid(\n        self, overrides: Dict, env_vars_friendly: bool = False\n    ) -> None:\n        \"\"\"Check overrides is correct, return list of errors if present.\"\"\"\n        # check for permitted overrides\n        self._check_overrides_corresponds_to_overridable(\n            overrides, env_vars_friendly=env_vars_friendly\n        )\n        # check resulting config with applied overrides passes validation\n\n        result_config = self.make_resulting_config_data(overrides)\n        self.validate_config_data(result_config, env_vars_friendly=env_vars_friendly)\n\n    def _check_overrides_corresponds_to_overridable(\n        self, overrides: Dict, env_vars_friendly: bool = False\n    ) -> None:\n        \"\"\"Check overrides is correct, return list of errors if present.\"\"\"\n        errors_list = validate_data_with_pattern(\n            overrides,\n            self.get_overridable(),\n            excludes=self.CHECK_EXCLUDES,\n            skip_env_vars=env_vars_friendly,\n        )\n        if errors_list:\n            raise ValueError(errors_list[0])\n\n    def get_overridable(self) -> dict:\n        \"\"\"Get dictionary of values that can be updated for this config.\"\"\"\n        return {k: self.json.get(k) for k in self.FIELDS_ALLOWED_TO_UPDATE}\n\n    @classmethod\n    def _apply_params_to_instance(\n        cls, params: dict, instance: Optional[\"PackageConfiguration\"]\n    ) -> \"PackageConfiguration\":\n        \"\"\"Constructs or update instance with params provided.\"\"\"\n        directory = (\n            instance.directory if instance and hasattr(instance, \"directory\") else None\n        )\n\n        if instance is None:\n            instance = cls(**params)\n        else:\n            instance.__init__(**params)  # type: ignore # pylint: disable=unnecessary-dunder-call\n\n        if directory and not instance.directory:\n            instance.directory = directory\n\n        return instance\n\n\nclass ComponentConfiguration(PackageConfiguration, ABC):\n    \"\"\"Class to represent an agent component configuration.\"\"\"\n\n    package_type: PackageType\n\n    __slots__ = (\"pypi_dependencies\", \"_build_directory\")\n\n    def __init__(\n        self,\n        name: SimpleIdOrStr,\n        author: SimpleIdOrStr,\n        version: str = \"\",\n        license_: str = \"\",\n        aea_version: str = \"\",\n        fingerprint: Optional[Dict[str, str]] = None,\n        fingerprint_ignore_patterns: Optional[Sequence[str]] = None,\n        build_entrypoint: Optional[str] = None,\n        build_directory: Optional[str] = None,\n        dependencies: Optional[Dependencies] = None,\n    ) -> None:\n        \"\"\"Set component configuration.\"\"\"\n        super().__init__(\n            name,\n            author,\n            version,\n            license_,\n            aea_version,\n            fingerprint,\n            fingerprint_ignore_patterns,\n            build_entrypoint,\n        )\n        self.pypi_dependencies: Dependencies = (\n            dependencies if dependencies is not None else {}\n        )\n        self._build_directory = build_directory\n\n    @property\n    def build_directory(self) -> Optional[str]:\n        \"\"\"Get the component type.\"\"\"\n        return self._build_directory\n\n    @build_directory.setter\n    def build_directory(self, value: Optional[str]) -> None:\n        \"\"\"Get the component type.\"\"\"\n        self._build_directory = value\n\n    @property\n    def component_type(self) -> ComponentType:\n        \"\"\"Get the component type.\"\"\"\n        return ComponentType(self.package_type.value)\n\n    @property\n    def component_id(self) -> ComponentId:\n        \"\"\"Get the component id.\"\"\"\n        return ComponentId(self.component_type, self.public_id)\n\n    @property\n    def prefix_import_path(self) -> str:\n        \"\"\"Get the prefix import path for this component.\"\"\"\n        return \"packages.{}.{}.{}\".format(\n            self.public_id.author, self.component_type.to_plural(), self.public_id.name\n        )\n\n    @property\n    def is_abstract_component(self) -> bool:\n        \"\"\"Check whether the component is abstract.\"\"\"\n        return False\n\n    def _check_configuration_consistency(self, directory: Path) -> None:\n        \"\"\"Check that the configuration file is consistent against a directory.\"\"\"\n        self.check_fingerprint(directory)\n        self.check_aea_version()\n        self.check_public_id_consistency(directory)\n\n    def check_fingerprint(self, directory: Path) -> None:\n        \"\"\"\n        Check that the fingerprint are correct against a directory path.\n\n        :param directory: the directory path.\n        :raises ValueError: if\n            - the argument is not a valid package directory\n            - the fingerprints do not match.\n        \"\"\"\n        if not directory.exists() or not directory.is_dir():\n            raise ValueError(\"Directory {} is not valid.\".format(directory))\n        _compare_fingerprints(\n            self, directory, False, self.component_type.to_package_type()\n        )\n\n    def check_public_id_consistency(self, directory: Path) -> None:\n        \"\"\"\n        Check that the public ids in the init file match the config.\n\n        :param directory: the directory path.\n        :raises ValueError: if\n            - the argument is not a valid package directory\n            - the public ids do not match.\n        \"\"\"\n        if not directory.exists() or not directory.is_dir():\n            raise ValueError(\"Directory {} is not valid.\".format(directory))\n        _compare_public_ids(self, directory)\n\n\nclass ConnectionConfig(ComponentConfiguration):\n    \"\"\"Handle connection configuration.\"\"\"\n\n    default_configuration_filename = DEFAULT_CONNECTION_CONFIG_FILE\n    package_type = PackageType.CONNECTION\n    schema = \"connection-config_schema.json\"\n\n    FIELDS_ALLOWED_TO_UPDATE: FrozenSet[str] = frozenset(\n        [\"config\", \"cert_requests\", \"is_abstract\", \"build_directory\"]\n    )\n\n    __slots__ = (\n        \"class_name\",\n        \"protocols\",\n        \"connections\",\n        \"restricted_to_protocols\",\n        \"excluded_protocols\",\n        \"dependencies\",\n        \"description\",\n        \"config\",\n        \"is_abstract\",\n        \"cert_requests\",\n    )\n\n    def __init__(\n        self,\n        name: SimpleIdOrStr = \"\",\n        author: SimpleIdOrStr = \"\",\n        version: str = \"\",\n        license_: str = \"\",\n        aea_version: str = \"\",\n        fingerprint: Optional[Dict[str, str]] = None,\n        fingerprint_ignore_patterns: Optional[Sequence[str]] = None,\n        build_entrypoint: Optional[str] = None,\n        build_directory: Optional[str] = None,\n        class_name: str = \"\",\n        protocols: Optional[Set[PublicId]] = None,\n        connections: Optional[Set[PublicId]] = None,\n        restricted_to_protocols: Optional[Set[PublicId]] = None,\n        excluded_protocols: Optional[Set[PublicId]] = None,\n        dependencies: Optional[Dependencies] = None,\n        description: str = \"\",\n        connection_id: Optional[PublicId] = None,\n        is_abstract: bool = False,\n        cert_requests: Optional[List[CertRequest]] = None,\n        **config: Any,\n    ) -> None:\n        \"\"\"Initialize a connection configuration object.\"\"\"\n        if connection_id is None:\n            enforce(name != \"\", \"Name or connection_id must be set.\")\n            enforce(author != \"\", \"Author or connection_id must be set.\")\n            enforce(version != \"\", \"Version or connection_id must be set.\")\n        else:\n            enforce(\n                name\n                in (\n                    \"\",\n                    connection_id.name,\n                ),\n                \"Non matching name in ConnectionConfig name and public id.\",\n            )\n            name = connection_id.name\n            enforce(\n                author\n                in (\n                    \"\",\n                    connection_id.author,\n                ),\n                \"Non matching author in ConnectionConfig author and public id.\",\n            )\n            author = connection_id.author\n            enforce(\n                version\n                in (\n                    \"\",\n                    connection_id.version,\n                ),\n                \"Non matching version in ConnectionConfig version and public id.\",\n            )\n            version = connection_id.version\n        super().__init__(\n            name,\n            author,\n            version,\n            license_,\n            aea_version,\n            fingerprint,\n            fingerprint_ignore_patterns,\n            build_entrypoint,\n            build_directory,\n            dependencies,\n        )\n        self.class_name = class_name\n        self.protocols = protocols if protocols is not None else set()\n        self.connections = connections if connections is not None else set()\n        self.restricted_to_protocols = (\n            restricted_to_protocols if restricted_to_protocols is not None else set()\n        )\n        self.excluded_protocols = (\n            excluded_protocols if excluded_protocols is not None else set()\n        )\n        self.dependencies = dependencies if dependencies is not None else {}\n        self.description = description\n        self.config = config if len(config) > 0 else {}\n        self.is_abstract = is_abstract\n        self.cert_requests = cert_requests\n\n    @property\n    def package_dependencies(self) -> Set[ComponentId]:\n        \"\"\"Get the connection dependencies.\"\"\"\n        return {\n            ComponentId(ComponentType.PROTOCOL, protocol_id)\n            for protocol_id in self.protocols\n        }.union(\n            {\n                ComponentId(ComponentType.CONNECTION, connection_id)\n                for connection_id in self.connections\n            }\n        )\n\n    @property\n    def is_abstract_component(self) -> bool:\n        \"\"\"Check whether the component is abstract.\"\"\"\n        return self.is_abstract\n\n    @property\n    def json(self) -> Dict:\n        \"\"\"Return the JSON representation.\"\"\"\n        result = OrderedDict(\n            {\n                \"name\": self.name,\n                \"author\": self.author,\n                \"version\": self.version,\n                \"type\": self.component_type.value,\n                \"description\": self.description,\n                \"license\": self.license,\n                \"aea_version\": self.aea_version,\n                \"fingerprint\": self.fingerprint,\n                \"fingerprint_ignore_patterns\": self.fingerprint_ignore_patterns,\n                PROTOCOLS: sorted(map(str, self.protocols)),\n                CONNECTIONS: sorted(map(str, self.connections)),\n                \"class_name\": self.class_name,\n                \"config\": self.config,\n                \"excluded_protocols\": sorted(map(str, self.excluded_protocols)),\n                \"restricted_to_protocols\": sorted(\n                    map(str, self.restricted_to_protocols)\n                ),\n                \"dependencies\": dependencies_to_json(self.dependencies),\n                \"is_abstract\": self.is_abstract,\n            }\n        )\n\n        if self.cert_requests is not None:\n            result[\"cert_requests\"] = list(map(attrgetter(\"json\"), self.cert_requests))\n        if self.build_entrypoint:\n            result[\"build_entrypoint\"] = self.build_entrypoint\n        if self.build_directory:\n            result[\"build_directory\"] = self.build_directory\n        return result\n\n    @classmethod\n    def _create_or_update_from_json(\n        cls, obj: Dict, instance: Optional[\"ConnectionConfig\"] = None\n    ) -> \"ConnectionConfig\":\n        \"\"\"Create new config object or updates existing one from json data.\"\"\"\n        obj = {**(instance.json if instance else {}), **copy(obj)}\n        restricted_to_protocols = obj.get(\"restricted_to_protocols\", set())\n        restricted_to_protocols = {\n            PublicId.from_str(id_) for id_ in restricted_to_protocols\n        }\n        excluded_protocols = obj.get(\"excluded_protocols\", set())\n        excluded_protocols = {PublicId.from_str(id_) for id_ in excluded_protocols}\n        dependencies = dependencies_from_json(obj.get(\"dependencies\", {}))\n        protocols = {PublicId.from_str(id_) for id_ in obj.get(PROTOCOLS, set())}\n        connections = {PublicId.from_str(id_) for id_ in obj.get(CONNECTIONS, set())}\n        cert_requests = (\n            [\n                # notice: yaml.load resolves datetime strings to datetime.datetime objects\n                CertRequest.from_json(cert_request_json)\n                for cert_request_json in obj[\"cert_requests\"]\n            ]\n            if \"cert_requests\" in obj\n            else None\n        )\n\n        params = dict(\n            name=cast(str, obj.get(\"name\")),\n            author=cast(str, obj.get(\"author\")),\n            version=cast(str, obj.get(\"version\")),\n            license_=cast(str, obj.get(\"license\")),\n            aea_version=cast(str, obj.get(\"aea_version\", \"\")),\n            fingerprint=cast(Dict[str, str], obj.get(\"fingerprint\")),\n            fingerprint_ignore_patterns=cast(\n                Sequence[str], obj.get(\"fingerprint_ignore_patterns\")\n            ),\n            build_entrypoint=cast(Optional[str], obj.get(\"build_entrypoint\")),\n            build_directory=cast(Optional[str], obj.get(\"build_directory\")),\n            class_name=cast(str, obj.get(\"class_name\")),\n            protocols=cast(Set[PublicId], protocols),\n            connections=cast(Set[PublicId], connections),\n            restricted_to_protocols=cast(Set[PublicId], restricted_to_protocols),\n            excluded_protocols=cast(Set[PublicId], excluded_protocols),\n            dependencies=cast(Dependencies, dependencies),\n            description=cast(str, obj.get(\"description\", \"\")),\n            is_abstract=obj.get(\"is_abstract\", False),\n            cert_requests=cert_requests,\n            **cast(dict, obj.get(\"config\", {})),\n        )\n\n        instance = cast(\n            ConnectionConfig, cls._apply_params_to_instance(params, instance)\n        )\n\n        return instance\n\n\nclass ProtocolConfig(ComponentConfiguration):\n    \"\"\"Handle protocol configuration.\"\"\"\n\n    default_configuration_filename = DEFAULT_PROTOCOL_CONFIG_FILE\n    package_type = PackageType.PROTOCOL\n    schema = \"protocol-config_schema.json\"\n    FIELDS_ALLOWED_TO_UPDATE: FrozenSet[str] = frozenset()\n\n    __slots__ = (\"dependencies\", \"description\", \"protocol_specification_id\")\n\n    def __init__(\n        self,\n        name: SimpleIdOrStr,\n        author: SimpleIdOrStr,\n        version: str = \"\",\n        license_: str = \"\",\n        fingerprint: Optional[Dict[str, str]] = None,\n        fingerprint_ignore_patterns: Optional[Sequence[str]] = None,\n        build_entrypoint: Optional[str] = None,\n        build_directory: Optional[str] = None,\n        aea_version: str = \"\",\n        dependencies: Optional[Dependencies] = None,\n        description: str = \"\",\n        protocol_specification_id: Optional[str] = None,\n    ) -> None:\n        \"\"\"Initialize a connection configuration object.\"\"\"\n        super().__init__(\n            name,\n            author,\n            version,\n            license_,\n            aea_version,\n            fingerprint,\n            fingerprint_ignore_patterns,\n            build_entrypoint,\n            build_directory,\n            dependencies,\n        )\n        self.dependencies = dependencies if dependencies is not None else {}\n        self.description = description\n        if protocol_specification_id is None:\n            raise ValueError(  # pragma: nocover\n                \"protocol_specification_id not provided!\"\n            )\n        self.protocol_specification_id = PublicId.from_str(\n            str(protocol_specification_id)\n        )\n\n    @property\n    def json(self) -> Dict:\n        \"\"\"Return the JSON representation.\"\"\"\n        result = OrderedDict(\n            {\n                \"name\": self.name,\n                \"author\": self.author,\n                \"version\": self.version,\n                \"protocol_specification_id\": str(self.protocol_specification_id),\n                \"type\": self.component_type.value,\n                \"description\": self.description,\n                \"license\": self.license,\n                \"aea_version\": self.aea_version,\n                \"fingerprint\": self.fingerprint,\n                \"fingerprint_ignore_patterns\": self.fingerprint_ignore_patterns,\n                \"dependencies\": dependencies_to_json(self.dependencies),\n            }\n        )\n        if self.build_entrypoint:\n            result[\"build_entrypoint\"] = self.build_entrypoint\n        if self.build_directory:\n            result[\"build_directory\"] = self.build_directory\n        return result\n\n    @classmethod\n    def _create_or_update_from_json(\n        cls, obj: Dict, instance: Optional[\"ProtocolConfig\"] = None\n    ) -> \"ProtocolConfig\":\n        \"\"\"Initialize from a JSON object.\"\"\"\n        obj = {**(instance.json if instance else {}), **copy(obj)}\n        dependencies = dependencies_from_json(obj.get(\"dependencies\", {}))\n        params = dict(\n            name=cast(str, obj.get(\"name\")),\n            author=cast(str, obj.get(\"author\")),\n            protocol_specification_id=cast(str, obj.get(\"protocol_specification_id\")),\n            version=cast(str, obj.get(\"version\")),\n            license_=cast(str, obj.get(\"license\")),\n            aea_version=cast(str, obj.get(\"aea_version\", \"\")),\n            fingerprint=cast(Dict[str, str], obj.get(\"fingerprint\")),\n            fingerprint_ignore_patterns=cast(\n                Sequence[str], obj.get(\"fingerprint_ignore_patterns\")\n            ),\n            build_entrypoint=cast(Optional[str], obj.get(\"build_entrypoint\")),\n            build_directory=cast(Optional[str], obj.get(\"build_directory\")),\n            dependencies=dependencies,\n            description=cast(str, obj.get(\"description\", \"\")),\n        )\n        instance = cast(ProtocolConfig, cls._apply_params_to_instance(params, instance))\n\n        return instance\n\n\nclass SkillComponentConfiguration:\n    \"\"\"This class represent a skill component configuration.\"\"\"\n\n    __slots__ = (\"class_name\", \"file_path\", \"args\")\n\n    def __init__(\n        self, class_name: str, file_path: Optional[str] = None, **args: Any\n    ) -> None:\n        \"\"\"\n        Initialize a skill component configuration.\n\n        :param class_name: the class name of the component.\n        :param file_path: the file path.\n        :param args: keyword arguments.\n        \"\"\"\n        self.class_name = class_name\n        self.file_path: Optional[Path] = Path(file_path) if file_path else None\n        self.args = args\n\n    @property\n    def json(self) -> Dict:\n        \"\"\"Return the JSON representation.\"\"\"\n        result = {\"class_name\": self.class_name, \"args\": self.args}\n        if self.file_path is not None:\n            result[\"file_path\"] = str(self.file_path.as_posix())\n        return result\n\n    @classmethod\n    def from_json(cls, obj: Dict) -> \"SkillComponentConfiguration\":\n        \"\"\"Initialize from a JSON object.\"\"\"\n        return cls._create_or_update_from_json(obj, instance=None)\n\n    @classmethod\n    def _create_or_update_from_json(\n        cls, obj: Dict, instance: Optional[\"SkillComponentConfiguration\"] = None\n    ) -> \"SkillComponentConfiguration\":\n        \"\"\"Initialize from a JSON object.\"\"\"\n        obj = {**(instance.json if instance else {}), **copy(obj)}\n        class_name = cast(str, obj.get(\"class_name\"))\n        file_path = cast(Optional[str], obj.get(\"file_path\"))\n        params = dict(class_name=class_name, file_path=file_path, **obj.get(\"args\", {}))\n\n        instance = cast(\n            SkillComponentConfiguration, cls._apply_params_to_instance(params, instance)\n        )\n\n        return instance\n\n    @classmethod\n    def _apply_params_to_instance(\n        cls, params: dict, instance: Optional[\"SkillComponentConfiguration\"]\n    ) -> \"SkillComponentConfiguration\":\n        \"\"\"Constructs or update instance with params provided.\"\"\"\n        if instance is None:\n            instance = cls(**params)\n        else:  # pragma: nocover\n            instance.__init__(**params)  # type: ignore # pylint: disable=unnecessary-dunder-call\n        return instance\n\n\nclass SkillConfig(ComponentConfiguration):\n    \"\"\"Class to represent a skill configuration file.\"\"\"\n\n    default_configuration_filename = DEFAULT_SKILL_CONFIG_FILE\n    package_type = PackageType.SKILL\n    schema = \"skill-config_schema.json\"\n    abstract_field_name = \"is_abstract\"\n\n    FIELDS_ALLOWED_TO_UPDATE: FrozenSet[str] = frozenset(\n        [\"behaviours\", \"handlers\", \"models\", \"is_abstract\", \"build_directory\"]\n    )\n    FIELDS_WITH_NESTED_FIELDS: FrozenSet[str] = frozenset(\n        [\"behaviours\", \"handlers\", \"models\"]\n    )\n    NESTED_FIELDS_ALLOWED_TO_UPDATE: FrozenSet[str] = frozenset([\"args\"])\n\n    __slots__ = (\n        \"connections\",\n        \"protocols\",\n        \"contracts\",\n        \"skills\",\n        \"dependencies\",\n        \"description\",\n        \"handlers\",\n        \"behaviours\",\n        \"models\",\n        \"is_abstract\",\n    )\n\n    def __init__(\n        self,\n        name: SimpleIdOrStr,\n        author: SimpleIdOrStr,\n        version: str = \"\",\n        license_: str = \"\",\n        aea_version: str = \"\",\n        fingerprint: Optional[Dict[str, str]] = None,\n        fingerprint_ignore_patterns: Optional[Sequence[str]] = None,\n        build_entrypoint: Optional[str] = None,\n        build_directory: Optional[str] = None,\n        connections: Optional[Set[PublicId]] = None,\n        protocols: Optional[Set[PublicId]] = None,\n        contracts: Optional[Set[PublicId]] = None,\n        skills: Optional[Set[PublicId]] = None,\n        dependencies: Optional[Dependencies] = None,\n        description: str = \"\",\n        is_abstract: bool = False,\n    ) -> None:\n        \"\"\"Initialize a skill configuration.\"\"\"\n        super().__init__(\n            name,\n            author,\n            version,\n            license_,\n            aea_version,\n            fingerprint,\n            fingerprint_ignore_patterns,\n            build_entrypoint,\n            build_directory,\n            dependencies,\n        )\n        self.connections = connections if connections is not None else set()\n        self.protocols = protocols if protocols is not None else set()\n        self.contracts = contracts if contracts is not None else set()\n        self.skills = skills if skills is not None else set()\n        self.dependencies = dependencies if dependencies is not None else {}\n        self.description = description\n        self.handlers: CRUDCollection[SkillComponentConfiguration] = CRUDCollection()\n        self.behaviours: CRUDCollection[SkillComponentConfiguration] = CRUDCollection()\n        self.models: CRUDCollection[SkillComponentConfiguration] = CRUDCollection()\n\n        self.is_abstract = is_abstract\n\n    @property\n    def package_dependencies(self) -> Set[ComponentId]:\n        \"\"\"Get the skill dependencies.\"\"\"\n        return (\n            {\n                ComponentId(ComponentType.PROTOCOL, protocol_id)\n                for protocol_id in self.protocols\n            }\n            .union(\n                {\n                    ComponentId(ComponentType.CONTRACT, contract_id)\n                    for contract_id in self.contracts\n                }\n            )\n            .union(\n                {ComponentId(ComponentType.SKILL, skill_id) for skill_id in self.skills}\n            )\n            .union(\n                {\n                    ComponentId(ComponentType.CONNECTION, connection_id)\n                    for connection_id in self.connections\n                }\n            )\n        )\n\n    @property\n    def is_abstract_component(self) -> bool:\n        \"\"\"Check whether the component is abstract.\"\"\"\n        return self.is_abstract  # pragma: nocover\n\n    @property\n    def json(self) -> Dict:\n        \"\"\"Return the JSON representation.\"\"\"\n        result = OrderedDict(\n            {\n                \"name\": self.name,\n                \"author\": self.author,\n                \"version\": self.version,\n                \"type\": self.component_type.value,\n                \"description\": self.description,\n                \"license\": self.license,\n                \"aea_version\": self.aea_version,\n                \"fingerprint\": self.fingerprint,\n                \"fingerprint_ignore_patterns\": self.fingerprint_ignore_patterns,\n                CONNECTIONS: sorted(map(str, self.connections)),\n                CONTRACTS: sorted(map(str, self.contracts)),\n                PROTOCOLS: sorted(map(str, self.protocols)),\n                SKILLS: sorted(map(str, self.skills)),\n                \"behaviours\": {key: b.json for key, b in self.behaviours.read_all()},\n                \"handlers\": {key: h.json for key, h in self.handlers.read_all()},\n                \"models\": {key: m.json for key, m in self.models.read_all()},\n                \"dependencies\": dependencies_to_json(self.dependencies),\n                \"is_abstract\": self.is_abstract,\n            }\n        )\n        if self.build_entrypoint:\n            result[\"build_entrypoint\"] = self.build_entrypoint\n        if self.build_directory:\n            result[\"build_directory\"] = self.build_directory\n        return result\n\n    @classmethod\n    def _create_or_update_from_json(\n        cls, obj: Dict, instance: Optional[\"SkillConfig\"] = None\n    ) -> \"SkillConfig\":\n        \"\"\"Initialize from a JSON object.\"\"\"\n        obj = {**(instance.json if instance else {}), **copy(obj)}\n        name = cast(str, obj.get(\"name\"))\n        author = cast(str, obj.get(\"author\"))\n        version = cast(str, obj.get(\"version\"))\n        license_ = cast(str, obj.get(\"license\"))\n        aea_version_specifiers = cast(str, obj.get(\"aea_version\", \"\"))\n        fingerprint = cast(Dict[str, str], obj.get(\"fingerprint\"))\n        fingerprint_ignore_patterns = cast(\n            Sequence[str], obj.get(\"fingerprint_ignore_patterns\")\n        )\n        build_entrypoint = cast(Optional[str], obj.get(\"build_entrypoint\"))\n        connections = {PublicId.from_str(id_) for id_ in obj.get(CONNECTIONS, set())}\n        protocols = {PublicId.from_str(id_) for id_ in obj.get(PROTOCOLS, set())}\n        contracts = {PublicId.from_str(id_) for id_ in obj.get(CONTRACTS, set())}\n        skills = {PublicId.from_str(id_) for id_ in obj.get(SKILLS, set())}\n        dependencies = dependencies_from_json(obj.get(\"dependencies\", {}))\n        description = cast(str, obj.get(\"description\", \"\"))\n        params = dict(\n            name=name,\n            author=author,\n            version=version,\n            license_=license_,\n            aea_version=aea_version_specifiers,\n            fingerprint=fingerprint,\n            fingerprint_ignore_patterns=fingerprint_ignore_patterns,\n            build_entrypoint=build_entrypoint,\n            connections=connections,\n            protocols=protocols,\n            contracts=contracts,\n            skills=skills,\n            dependencies=dependencies,\n            description=description,\n            is_abstract=obj.get(\"is_abstract\", False),\n            build_directory=obj.get(\"build_directory\"),\n        )\n\n        instance = cast(SkillConfig, cls._apply_params_to_instance(params, instance))\n\n        for behaviour_id, behaviour_data in obj.get(\"behaviours\", {}).items():\n            behaviour_config = SkillComponentConfiguration.from_json(behaviour_data)\n            instance.behaviours.create(behaviour_id, behaviour_config)\n\n        for handler_id, handler_data in obj.get(\"handlers\", {}).items():\n            handler_config = SkillComponentConfiguration.from_json(handler_data)\n            instance.handlers.create(handler_id, handler_config)\n\n        for model_id, model_data in obj.get(\"models\", {}).items():\n            model_config = SkillComponentConfiguration.from_json(model_data)\n            instance.models.create(model_id, model_config)\n\n        return instance\n\n    def get_overridable(self) -> dict:\n        \"\"\"Get overridable configuration data.\"\"\"\n        result = {}\n        current_config_data = self.json\n        if self.abstract_field_name in current_config_data:\n            result[self.abstract_field_name] = current_config_data[\n                self.abstract_field_name\n            ]\n\n        for field in self.FIELDS_WITH_NESTED_FIELDS:\n            if not current_config_data.get(field, {}):\n                continue\n            result[field] = {}\n            for name in current_config_data[field].keys():\n                result[field][name] = {}\n                for nested_field in self.NESTED_FIELDS_ALLOWED_TO_UPDATE:\n                    result[field][name][nested_field] = current_config_data[field][\n                        name\n                    ][nested_field]\n        return result\n\n\nclass AgentConfig(PackageConfiguration):\n    \"\"\"Class to represent the agent configuration file.\"\"\"\n\n    default_configuration_filename = DEFAULT_AEA_CONFIG_FILE\n    package_type = PackageType.AGENT\n    schema = \"aea-config_schema.json\"\n\n    FIELDS_ALLOWED_TO_UPDATE: FrozenSet[str] = frozenset(\n        [\n            \"description\",\n            \"logging_config\",\n            \"private_key_paths\",\n            \"connection_private_key_paths\",\n            \"loop_mode\",\n            \"runtime_mode\",\n            \"task_manager_mode\",\n            \"execution_timeout\",\n            \"timeout\",\n            \"period\",\n            \"max_reactions\",\n            \"skill_exception_policy\",\n            \"connection_exception_policy\",\n            \"default_connection\",\n            \"default_ledger\",\n            \"required_ledgers\",\n            \"default_routing\",\n            \"storage_uri\",\n        ]\n    )\n    CHECK_EXCLUDES = [\n        (\"private_key_paths\",),\n        (\"connection_private_key_paths\",),\n        (\"error_handler\",),\n        (\"decision_maker_handler\",),\n        (\"default_routing\",),\n        (\"dependencies\",),\n        (\"logging_config\",),\n    ]\n\n    __slots__ = (\n        \"agent_name\",\n        \"description\",\n        \"private_key_paths\",\n        \"connection_private_key_paths\",\n        \"logging_config\",\n        \"default_ledger\",\n        \"required_ledgers\",\n        \"currency_denominations\",\n        \"default_connection\",\n        \"connections\",\n        \"protocols\",\n        \"skills\",\n        \"contracts\",\n        \"period\",\n        \"execution_timeout\",\n        \"max_reactions\",\n        \"skill_exception_policy\",\n        \"connection_exception_policy\",\n        \"error_handler\",\n        \"decision_maker_handler\",\n        \"default_routing\",\n        \"loop_mode\",\n        \"runtime_mode\",\n        \"storage_uri\",\n        \"data_dir\",\n        \"_component_configurations\",\n        \"dependencies\",\n    )\n\n    def __init__(  # pylint: disable=too-many-arguments\n        self,\n        agent_name: SimpleIdOrStr,\n        author: SimpleIdOrStr,\n        version: str = \"\",\n        license_: str = \"\",\n        aea_version: str = \"\",\n        fingerprint: Optional[Dict[str, str]] = None,\n        fingerprint_ignore_patterns: Optional[Sequence[str]] = None,\n        build_entrypoint: Optional[str] = None,\n        description: str = \"\",\n        logging_config: Optional[Dict] = None,\n        period: Optional[float] = None,\n        execution_timeout: Optional[float] = None,\n        max_reactions: Optional[int] = None,\n        error_handler: Optional[Dict] = None,\n        decision_maker_handler: Optional[Dict] = None,\n        skill_exception_policy: Optional[str] = None,\n        connection_exception_policy: Optional[str] = None,\n        default_ledger: Optional[str] = None,\n        required_ledgers: Optional[List[str]] = None,\n        currency_denominations: Optional[Dict[str, str]] = None,\n        default_connection: Optional[str] = None,\n        default_routing: Optional[Dict[str, str]] = None,\n        loop_mode: Optional[str] = None,\n        runtime_mode: Optional[str] = None,\n        task_manager_mode: Optional[str] = None,\n        storage_uri: Optional[str] = None,\n        data_dir: Optional[str] = None,\n        component_configurations: Optional[Dict[ComponentId, Dict]] = None,\n        dependencies: Optional[Dependencies] = None,\n    ) -> None:\n        \"\"\"Instantiate the agent configuration object.\"\"\"\n        super().__init__(\n            agent_name,\n            author,\n            version,\n            license_,\n            aea_version,\n            fingerprint,\n            fingerprint_ignore_patterns,\n            build_entrypoint,\n        )\n        self.agent_name = self.name\n        self.description = description\n        self.private_key_paths = CRUDCollection[str]()\n        self.connection_private_key_paths = CRUDCollection[str]()\n\n        self.logging_config = logging_config or DEFAULT_LOGGING_CONFIG\n        self.default_ledger = (\n            str(SimpleId(default_ledger)) if default_ledger is not None else None\n        )\n        self.required_ledgers = (\n            [str(SimpleId(ledger)) for ledger in required_ledgers]\n            if required_ledgers is not None\n            else None\n        )\n        self.currency_denominations = (\n            currency_denominations if currency_denominations is not None else {}\n        )\n        self.default_connection = (\n            PublicId.from_str(default_connection)\n            if default_connection is not None\n            else None\n        )\n        self.connections = set()  # type: Set[PublicId]\n        self.contracts = set()  # type: Set[PublicId]\n        self.protocols = set()  # type: Set[PublicId]\n        self.skills = set()  # type: Set[PublicId]\n\n        self.period: Optional[float] = period\n        self.execution_timeout: Optional[float] = execution_timeout\n        self.max_reactions: Optional[int] = max_reactions\n\n        self.skill_exception_policy: Optional[str] = skill_exception_policy\n        self.connection_exception_policy: Optional[str] = connection_exception_policy\n\n        self.error_handler = error_handler if error_handler is not None else {}\n        self.decision_maker_handler = (\n            decision_maker_handler if decision_maker_handler is not None else {}\n        )\n\n        self.default_routing = (\n            {\n                PublicId.from_str(key): PublicId.from_str(value)\n                for key, value in default_routing.items()\n            }\n            if default_routing is not None\n            else {}\n        )  # type: Dict[PublicId, PublicId]\n        self.loop_mode = loop_mode\n        self.runtime_mode = runtime_mode\n        self.task_manager_mode = task_manager_mode\n        self.storage_uri = storage_uri\n        self.data_dir = data_dir\n        # this attribute will be set through the setter below\n        self._component_configurations: Dict[ComponentId, Dict] = {}\n        self.component_configurations = (\n            component_configurations if component_configurations is not None else {}\n        )\n        self.dependencies = dependencies or {}\n\n    @property\n    def component_configurations(self) -> Dict[ComponentId, Dict]:\n        \"\"\"Get the custom component configurations.\"\"\"\n        return self._component_configurations\n\n    @component_configurations.setter\n    def component_configurations(self, d: Dict[ComponentId, Dict]) -> None:\n        \"\"\"Set the component configurations.\"\"\"\n        package_type_to_set = {\n            PackageType.PROTOCOL: self.protocols,\n            PackageType.CONNECTION: self.connections,\n            PackageType.CONTRACT: self.contracts,\n            PackageType.SKILL: self.skills,\n        }\n        for component_id, component_configuration in d.items():\n            enforce(\n                component_id.public_id\n                in package_type_to_set[component_id.package_type],\n                f\"Component {component_id} not declared in the agent configuration.\",\n            )\n            ConfigValidator.validate_component_configuration(\n                component_id, component_configuration\n            )\n        self._component_configurations = d\n\n    @property\n    def package_dependencies(self) -> Set[ComponentId]:\n        \"\"\"Get the package dependencies.\"\"\"\n        protocols = set(\n            ComponentId(ComponentType.PROTOCOL, public_id)\n            for public_id in self.protocols\n        )\n        connections = set(\n            ComponentId(ComponentType.CONNECTION, public_id)\n            for public_id in self.connections\n        )\n        skills = set(\n            ComponentId(ComponentType.SKILL, public_id) for public_id in self.skills\n        )\n\n        contracts = set(\n            ComponentId(ComponentType.CONTRACT, public_id)\n            for public_id in self.contracts\n        )\n\n        return set.union(protocols, contracts, connections, skills)\n\n    @property\n    def private_key_paths_dict(self) -> Dict[str, str]:\n        \"\"\"Get dictionary version of private key paths.\"\"\"\n        return {  # pylint: disable=unnecessary-comprehension\n            key: path for key, path in self.private_key_paths.read_all()\n        }\n\n    @property\n    def connection_private_key_paths_dict(self) -> Dict[str, str]:\n        \"\"\"Get dictionary version of connection private key paths.\"\"\"\n        return {  # pylint: disable=unnecessary-comprehension\n            key: path for key, path in self.connection_private_key_paths.read_all()\n        }\n\n    def component_configurations_json(self) -> List[OrderedDict]:\n        \"\"\"Get the component configurations in JSON format.\"\"\"\n        result: List[OrderedDict] = []\n        for component_id, config in self.component_configurations.items():\n            result.append(\n                OrderedDict(\n                    public_id=str(component_id.public_id),\n                    type=str(component_id.component_type),\n                    **config,\n                )\n            )\n        return result\n\n    @property\n    def json(self) -> Dict:\n        \"\"\"Return the JSON representation.\"\"\"\n        config = OrderedDict(\n            {\n                \"agent_name\": self.agent_name,\n                \"author\": self.author,\n                \"version\": self.version,\n                \"license\": self.license,\n                \"description\": self.description,\n                \"aea_version\": self.aea_version,\n                \"fingerprint\": self.fingerprint,\n                \"fingerprint_ignore_patterns\": self.fingerprint_ignore_patterns,\n                CONNECTIONS: sorted(map(str, self.connections)),\n                CONTRACTS: sorted(map(str, self.contracts)),\n                PROTOCOLS: sorted(map(str, self.protocols)),\n                SKILLS: sorted(map(str, self.skills)),\n                \"default_connection\": str(self.default_connection)\n                if self.default_connection is not None\n                else None,\n                \"default_ledger\": self.default_ledger,\n                \"required_ledgers\": self.required_ledgers or [],\n                \"default_routing\": {\n                    str(key): str(value) for key, value in self.default_routing.items()\n                },\n                \"connection_private_key_paths\": self.connection_private_key_paths_dict,\n                \"private_key_paths\": self.private_key_paths_dict,\n                \"logging_config\": self.logging_config,\n                \"component_configurations\": self.component_configurations_json(),\n                \"dependencies\": dependencies_to_json(self.dependencies),\n            }\n        )  # type: Dict[str, Any]\n\n        if self.build_entrypoint:\n            config[\"build_entrypoint\"] = self.build_entrypoint\n\n        # framework optional configs are only printed if defined.\n        if self.period is not None:\n            config[\"period\"] = self.period\n        if self.execution_timeout is not None:\n            config[\"execution_timeout\"] = self.execution_timeout\n        if self.max_reactions is not None:\n            config[\"max_reactions\"] = self.max_reactions\n        if self.error_handler != {}:\n            config[\"error_handler\"] = self.error_handler\n        if self.decision_maker_handler != {}:\n            config[\"decision_maker_handler\"] = self.decision_maker_handler\n        if self.skill_exception_policy is not None:\n            config[\"skill_exception_policy\"] = self.skill_exception_policy\n        if self.connection_exception_policy is not None:\n            config[\"connection_exception_policy\"] = self.connection_exception_policy\n        if self.loop_mode is not None:\n            config[\"loop_mode\"] = self.loop_mode\n        if self.runtime_mode is not None:\n            config[\"runtime_mode\"] = self.runtime_mode\n        if self.task_manager_mode is not None:\n            config[\"task_manager_mode\"] = self.task_manager_mode\n        if self.storage_uri is not None:\n            config[\"storage_uri\"] = self.storage_uri\n        if self.data_dir is not None:\n            config[\"data_dir\"] = self.data_dir\n        if self.currency_denominations != {}:\n            config[\"currency_denominations\"] = self.currency_denominations\n\n        return config\n\n    @classmethod\n    def _create_or_update_from_json(\n        cls, obj: Dict, instance: Optional[Any] = None\n    ) -> \"AgentConfig\":\n        \"\"\"Create new config object or updates existing one from json data.\"\"\"\n        obj = {**(instance.json if instance else {}), **copy(obj)}\n        params = dict(\n            agent_name=cast(str, obj.get(\"agent_name\")),\n            author=cast(str, obj.get(\"author\")),\n            version=cast(str, obj.get(\"version\")),\n            license_=cast(str, obj.get(\"license\")),\n            aea_version=cast(str, obj.get(\"aea_version\", \"\")),\n            description=cast(str, obj.get(\"description\", \"\")),\n            fingerprint=cast(Dict[str, str], obj.get(\"fingerprint\", {})),\n            fingerprint_ignore_patterns=cast(\n                Sequence[str], obj.get(\"fingerprint_ignore_patterns\")\n            ),\n            build_entrypoint=cast(Optional[str], obj.get(\"build_entrypoint\")),\n            logging_config=cast(Dict, obj.get(\"logging_config\", {})),\n            period=cast(float, obj.get(\"period\")),\n            execution_timeout=cast(float, obj.get(\"execution_timeout\")),\n            max_reactions=cast(int, obj.get(\"max_reactions\")),\n            error_handler=cast(Dict, obj.get(\"error_handler\", {})),\n            decision_maker_handler=cast(Dict, obj.get(\"decision_maker_handler\", {})),\n            skill_exception_policy=cast(str, obj.get(\"skill_exception_policy\")),\n            connection_exception_policy=cast(\n                str, obj.get(\"connection_exception_policy\")\n            ),\n            default_ledger=cast(str, obj.get(\"default_ledger\")),\n            required_ledgers=cast(Optional[List[str]], obj.get(\"required_ledgers\")),\n            currency_denominations=cast(Dict, obj.get(\"currency_denominations\", {})),\n            default_connection=cast(str, obj.get(\"default_connection\")),\n            default_routing=cast(Dict, obj.get(\"default_routing\", {})),\n            loop_mode=cast(str, obj.get(\"loop_mode\")),\n            runtime_mode=cast(str, obj.get(\"runtime_mode\")),\n            task_manager_mode=cast(str, obj.get(\"task_manager_mode\")),\n            storage_uri=cast(str, obj.get(\"storage_uri\")),\n            data_dir=cast(str, obj.get(\"data_dir\")),\n            component_configurations=None,\n            dependencies=cast(\n                Dependencies, dependencies_from_json(obj.get(\"dependencies\", {}))\n            ),\n        )\n        instance = cast(AgentConfig, cls._apply_params_to_instance(params, instance))\n\n        agent_config = instance\n\n        # Parse private keys\n        for crypto_id, path in obj.get(\"private_key_paths\", {}).items():\n            agent_config.private_key_paths.create(crypto_id, path)\n\n        for crypto_id, path in obj.get(\"connection_private_key_paths\", {}).items():\n            agent_config.connection_private_key_paths.create(crypto_id, path)\n\n        # parse connection public ids\n        agent_config.connections = set(\n            map(\n                PublicId.from_str,\n                obj.get(CONNECTIONS, []),\n            )\n        )\n\n        # parse contracts public ids\n        agent_config.contracts = set(\n            map(\n                PublicId.from_str,\n                obj.get(CONTRACTS, []),\n            )\n        )\n\n        # parse protocol public ids\n        agent_config.protocols = set(\n            map(\n                PublicId.from_str,\n                obj.get(PROTOCOLS, []),\n            )\n        )\n\n        # parse skills public ids\n        agent_config.skills = set(\n            map(\n                PublicId.from_str,\n                obj.get(SKILLS, []),\n            )\n        )\n\n        # parse component configurations\n        component_configurations = {}\n        for config in obj.get(\"component_configurations\", []):\n            tmp = deepcopy(config)\n            public_id = PublicId.from_str(tmp.pop(\"public_id\"))\n            type_ = tmp.pop(\"type\")\n            component_id = ComponentId(ComponentType(type_), public_id)\n            component_configurations[component_id] = tmp\n        agent_config.component_configurations = component_configurations\n\n        return agent_config\n\n    @property\n    def all_components_id(self) -> List[ComponentId]:\n        \"\"\"Get list of the all components for this agent config.\"\"\"\n        component_type_to_set = {\n            ComponentType.PROTOCOL: self.protocols,\n            ComponentType.CONNECTION: self.connections,\n            ComponentType.CONTRACT: self.contracts,\n            ComponentType.SKILL: self.skills,\n        }\n        result = []\n        for component_type, public_ids in component_type_to_set.items():\n            for public_id in public_ids:\n                result.append(ComponentId(component_type, public_id))\n\n        return result\n\n    def update(self, data: Dict, env_vars_friendly: bool = False) -> None:\n        \"\"\"\n        Update configuration with other data.\n\n        To update the component parts, populate the field \"component_configurations\" as a\n        mapping from ComponentId to configurations.\n\n        :param data: the data to replace.\n        :param env_vars_friendly: whether or not it is env vars friendly.\n        \"\"\"\n        data = copy(data)\n        # update component parts\n        new_component_configurations: Dict = data.pop(\"component_configurations\", {})\n        updated_component_configurations: Dict[ComponentId, Dict] = copy(\n            self.component_configurations\n        )\n        for component_id, obj in new_component_configurations.items():\n            if component_id not in updated_component_configurations:\n                updated_component_configurations[component_id] = obj\n            else:\n                recursive_update(\n                    updated_component_configurations[component_id],\n                    obj,\n                    allow_new_values=True,\n                )\n\n        self.check_overrides_valid(data, env_vars_friendly=env_vars_friendly)\n        super().update(data, env_vars_friendly=env_vars_friendly)\n        self.validate_config_data(self.json, env_vars_friendly=env_vars_friendly)\n        self.component_configurations = updated_component_configurations\n\n\nclass SpeechActContentConfig(Configuration):\n    \"\"\"Handle a speech_act content configuration.\"\"\"\n\n    __slots__ = (\"args\",)\n\n    def __init__(self, **args: Any) -> None:\n        \"\"\"Initialize a speech_act content configuration.\"\"\"\n        super().__init__()\n        self.args = args  # type: Dict[str, str]\n\n    @property\n    def json(self) -> Dict:\n        \"\"\"Return the JSON representation.\"\"\"\n        return self.args\n\n    @classmethod\n    def from_json(cls, obj: Dict) -> \"SpeechActContentConfig\":\n        \"\"\"Initialize from a JSON object.\"\"\"\n        return SpeechActContentConfig(**obj)\n\n\nclass ProtocolSpecification(ProtocolConfig):\n    \"\"\"Handle protocol specification.\"\"\"\n\n    __slots__ = (\"speech_acts\", \"_protobuf_snippets\", \"_dialogue_config\")\n\n    def __init__(\n        self,\n        name: SimpleIdOrStr,\n        author: SimpleIdOrStr,\n        version: str = \"\",\n        license_: str = \"\",\n        aea_version: str = \"\",\n        description: str = \"\",\n        protocol_specification_id: Optional[str] = None,\n    ) -> None:\n        \"\"\"Initialize a protocol specification configuration object.\"\"\"\n        super().__init__(\n            name,\n            author,\n            version,\n            license_,\n            aea_version=aea_version,\n            description=description,\n            protocol_specification_id=protocol_specification_id,\n        )\n        self.speech_acts = CRUDCollection[SpeechActContentConfig]()\n        self._protobuf_snippets = {}  # type: Dict\n        self._dialogue_config = {}  # type: Dict\n\n    @property\n    def protobuf_snippets(self) -> Dict:\n        \"\"\"Get the protobuf snippets.\"\"\"\n        return self._protobuf_snippets\n\n    @protobuf_snippets.setter\n    def protobuf_snippets(self, protobuf_snippets: Dict) -> None:\n        \"\"\"Set the protobuf snippets.\"\"\"\n        self._protobuf_snippets = protobuf_snippets\n\n    @property\n    def dialogue_config(self) -> Dict:\n        \"\"\"Get the dialogue config.\"\"\"\n        return self._dialogue_config\n\n    @dialogue_config.setter\n    def dialogue_config(self, dialogue_config: Dict) -> None:\n        \"\"\"Set the dialogue config.\"\"\"\n        self._dialogue_config = dialogue_config\n\n    @property\n    def json(self) -> Dict:\n        \"\"\"Return the JSON representation.\"\"\"\n        result: Dict[str, Any] = OrderedDict(\n            {\n                \"name\": self.name,\n                \"author\": self.author,\n                \"version\": self.version,\n                \"description\": self.description,\n                \"license\": self.license,\n                \"aea_version\": self.aea_version,\n                \"protocol_specification_id\": str(self.protocol_specification_id),\n                \"speech_acts\": {\n                    key: speech_act.json\n                    for key, speech_act in self.speech_acts.read_all()\n                },\n            }\n        )\n        return result\n\n    @classmethod\n    def _create_or_update_from_json(  # type: ignore\n        cls, obj: Dict, instance: Optional[\"ProtocolSpecification\"] = None\n    ) -> \"ProtocolSpecification\":\n        \"\"\"Initialize from a JSON object.\"\"\"\n        obj = {**(instance.json if instance else {}), **copy(obj)}\n        params = dict(\n            name=cast(str, obj.get(\"name\")),\n            author=cast(str, obj.get(\"author\")),\n            protocol_specification_id=cast(str, obj.get(\"protocol_specification_id\")),\n            version=cast(str, obj.get(\"version\")),\n            license_=cast(str, obj.get(\"license\")),\n            aea_version=cast(str, obj.get(\"aea_version\", \"\")),\n            description=cast(str, obj.get(\"description\", \"\")),\n        )\n\n        instance = cast(\n            ProtocolSpecification, cls._apply_params_to_instance(params, instance)\n        )\n\n        protocol_specification = instance\n        for speech_act, speech_act_content in obj.get(\"speech_acts\", {}).items():\n            speech_act_content_config = SpeechActContentConfig.from_json(\n                speech_act_content\n            )\n            protocol_specification.speech_acts.create(\n                speech_act, speech_act_content_config\n            )\n        return protocol_specification\n\n\nclass ContractConfig(ComponentConfiguration):\n    \"\"\"Handle contract configuration.\"\"\"\n\n    default_configuration_filename = DEFAULT_CONTRACT_CONFIG_FILE\n    package_type = PackageType.CONTRACT\n    schema = \"contract-config_schema.json\"\n\n    FIELDS_ALLOWED_TO_UPDATE: FrozenSet[str] = frozenset([\"build_directory\"])\n\n    __slots__ = (\n        \"dependencies\",\n        \"description\",\n        \"contract_interface_paths\",\n        \"class_name\",\n    )\n\n    def __init__(\n        self,\n        name: SimpleIdOrStr,\n        author: SimpleIdOrStr,\n        version: str = \"\",\n        license_: str = \"\",\n        aea_version: str = \"\",\n        fingerprint: Optional[Dict[str, str]] = None,\n        fingerprint_ignore_patterns: Optional[Sequence[str]] = None,\n        build_entrypoint: Optional[str] = None,\n        build_directory: Optional[str] = None,\n        dependencies: Optional[Dependencies] = None,\n        description: str = \"\",\n        contract_interface_paths: Optional[Dict[str, str]] = None,\n        class_name: str = \"\",\n    ) -> None:\n        \"\"\"Initialize a protocol configuration object.\"\"\"\n        super().__init__(\n            name,\n            author,\n            version,\n            license_,\n            aea_version,\n            fingerprint,\n            fingerprint_ignore_patterns,\n            build_entrypoint,\n            build_directory,\n            dependencies,\n        )\n        self.dependencies = dependencies if dependencies is not None else {}\n        self.description = description\n        self.contract_interface_paths = (\n            contract_interface_paths if contract_interface_paths is not None else {}\n        )\n        self.class_name = class_name\n\n    @property\n    def json(self) -> Dict:\n        \"\"\"Return the JSON representation.\"\"\"\n        result = OrderedDict(\n            {\n                \"name\": self.name,\n                \"author\": self.author,\n                \"version\": self.version,\n                \"type\": self.component_type.value,\n                \"description\": self.description,\n                \"license\": self.license,\n                \"aea_version\": self.aea_version,\n                \"fingerprint\": self.fingerprint,\n                \"fingerprint_ignore_patterns\": self.fingerprint_ignore_patterns,\n                \"class_name\": self.class_name,\n                \"contract_interface_paths\": self.contract_interface_paths,\n                \"dependencies\": dependencies_to_json(self.dependencies),\n            }\n        )\n        if self.build_entrypoint:\n            result[\"build_entrypoint\"] = self.build_entrypoint\n        if self.build_directory:\n            result[\"build_directory\"] = self.build_directory\n        return result\n\n    @classmethod\n    def _create_or_update_from_json(\n        cls, obj: Dict, instance: Optional[\"ContractConfig\"] = None\n    ) -> \"ContractConfig\":\n        \"\"\"Initialize from a JSON object.\"\"\"\n        obj = {**(instance.json if instance else {}), **copy(obj)}\n        dependencies = cast(\n            Dependencies, dependencies_from_json(obj.get(\"dependencies\", {}))\n        )\n        params = dict(\n            name=cast(str, obj.get(\"name\")),\n            author=cast(str, obj.get(\"author\")),\n            version=cast(str, obj.get(\"version\")),\n            license_=cast(str, obj.get(\"license\")),\n            aea_version=cast(str, obj.get(\"aea_version\", \"\")),\n            fingerprint=cast(Dict[str, str], obj.get(\"fingerprint\", {})),\n            fingerprint_ignore_patterns=cast(\n                Sequence[str], obj.get(\"fingerprint_ignore_patterns\")\n            ),\n            build_entrypoint=cast(Optional[str], obj.get(\"build_entrypoint\")),\n            build_directory=cast(Optional[str], obj.get(\"build_directory\")),\n            dependencies=dependencies,\n            description=cast(str, obj.get(\"description\", \"\")),\n            contract_interface_paths=cast(\n                Dict[str, str], obj.get(\"contract_interface_paths\", {})\n            ),\n            class_name=obj.get(\"class_name\", \"\"),\n        )\n        instance = cast(ContractConfig, cls._apply_params_to_instance(params, instance))\n\n        return instance\n\n\n\"\"\"The following functions are called from aea.cli.utils.\"\"\"\n\n\ndef _compute_fingerprint(  # pylint: disable=unsubscriptable-object\n    package_directory: Path,\n    ignore_patterns: Optional[Collection[str]] = None,\n    is_recursive: bool = True,\n    ignore_directories: Optional[Collection[str]] = None,\n) -> Dict[str, str]:\n    ignore_patterns = ignore_patterns if ignore_patterns is not None else []\n    ignore_directories = ignore_directories if ignore_directories is not None else []\n    ignore_patterns = set(ignore_patterns).union(DEFAULT_FINGERPRINT_IGNORE_PATTERNS)\n    hasher = IPFSHashOnly()\n    fingerprints = {}  # type: Dict[str, str]\n    # find all valid files of the package\n    all_files = [\n        x\n        for x in package_directory.glob(\"**/*\" if is_recursive else \"*\")\n        if x.is_file()\n        and not any(x.match(pattern) for pattern in ignore_patterns)\n        and not (x.parts[0] in ignore_directories)\n    ]\n\n    for file in all_files:\n        file_hash = hasher.get(str(file))\n        key = str(file.relative_to(package_directory))\n        enforce(key not in fingerprints, \"Key in fingerprints!\")  # nosec\n        # use '/' as path separator\n        normalized_path = Path(key).as_posix()\n        fingerprints[normalized_path] = file_hash\n\n    return fingerprints\n\n\ndef _compare_fingerprints(\n    package_configuration: PackageConfiguration,\n    package_directory: Path,\n    is_vendor: bool,\n    item_type: PackageType,\n    is_recursive: bool = True,\n) -> None:\n    \"\"\"\n    Check fingerprints of a package directory against the fingerprints declared in the configuration file.\n\n    :param package_configuration: the package configuration object.\n    :param package_directory: the directory of the package.\n    :param is_vendor: whether the package is vendorized or not.\n    :param item_type: the type of the item.\n    :param is_recursive: look up sub directories for files to fingerprint\n\n    :raises ValueError: if the fingerprints do not match.\n    \"\"\"\n    expected_fingerprints = package_configuration.fingerprint\n    ignore_patterns = package_configuration.fingerprint_ignore_patterns\n    actual_fingerprints = _compute_fingerprint(\n        package_directory, ignore_patterns, is_recursive=is_recursive\n    )\n    if expected_fingerprints != actual_fingerprints:\n        if is_vendor:\n            raise ValueError(\n                (\n                    \"Fingerprints for package {} do not match:\\nExpected: {}\\nActual: {}\\n\"\n                    \"Vendorized projects should not be tampered with, please revert any changes to {} {}\"\n                ).format(\n                    package_directory,\n                    pprint.pformat(expected_fingerprints),\n                    pprint.pformat(actual_fingerprints),\n                    str(item_type),\n                    package_configuration.public_id,\n                )\n            )\n        if item_type == PackageType.AGENT:\n            raise ValueError(\n                (\n                    \"Fingerprints for package {} do not match:\\nExpected: {}\\nActual: {}\\n\"\n                    \"Please fingerprint the package before continuing: 'aea fingerprint'\"\n                ).format(\n                    package_directory,\n                    pprint.pformat(expected_fingerprints),\n                    pprint.pformat(actual_fingerprints),\n                )\n            )\n        raise ValueError(\n            (\n                \"Fingerprints for package {} do not match:\\nExpected: {}\\nActual: {}\\n\"\n                \"Please fingerprint the package before continuing: 'aea fingerprint {} {}'\"\n            ).format(\n                package_directory,\n                pprint.pformat(expected_fingerprints),\n                pprint.pformat(actual_fingerprints),\n                str(item_type),\n                package_configuration.public_id,\n            )\n        )\n\n\nclass AEAVersionError(ValueError):\n    \"\"\"Special Exception for version error.\"\"\"\n\n    def __init__(\n        self, package_id: PublicId, aea_version_specifiers: SpecifierSet\n    ) -> None:\n        \"\"\"Init exception.\"\"\"\n        self.package_id = package_id\n        self.aea_version_specifiers = aea_version_specifiers\n        self.current_aea_version = Version(__aea_version__)\n        super().__init__(\n            f\"The CLI version is {self.current_aea_version}, but package {self.package_id} requires version {self.aea_version_specifiers}\"\n        )\n\n\ndef _check_aea_version(package_configuration: PackageConfiguration) -> None:\n    \"\"\"Check the package configuration version against the version of the framework.\"\"\"\n    current_aea_version = Version(__aea_version__)\n    version_specifiers = package_configuration.aea_version_specifiers\n    if current_aea_version not in version_specifiers:\n        raise AEAVersionError(\n            package_configuration.public_id,\n            package_configuration.aea_version_specifiers,\n        )\n\n\ndef _compare_public_ids(\n    component_configuration: ComponentConfiguration, package_directory: Path\n) -> None:\n    \"\"\"Compare the public ids in config and init file.\"\"\"\n    if component_configuration.package_type != PackageType.SKILL:\n        return\n    filename = \"__init__.py\"\n    public_id_in_init = _get_public_id_from_file(\n        component_configuration, package_directory, filename\n    )\n    if (\n        public_id_in_init is not None\n        and public_id_in_init != component_configuration.public_id\n    ):\n        raise ValueError(  # pragma: nocover\n            f\"The public id specified in {filename} for package {package_directory} does not match the one specific in {component_configuration.package_type.value}.yaml\"\n        )\n\n\ndef _get_public_id_from_file(\n    component_configuration: ComponentConfiguration,\n    package_directory: Path,\n    filename: str,\n) -> Optional[PublicId]:\n    \"\"\"\n    Get the public id from an init if present.\n\n    :param component_configuration: the component configuration.\n    :param package_directory: the path to the package directory.\n    :param filename: the file\n    :return: the public id, if found.\n    \"\"\"\n    path_to_file = Path(package_directory, filename)\n    module = load_module(component_configuration.prefix_import_path, path_to_file)\n    package_public_id = getattr(module, PACKAGE_PUBLIC_ID_VAR_NAME, None)\n    return package_public_id\n\n\nPACKAGE_TYPE_TO_CONFIG_CLASS: Dict[PackageType, Type[PackageConfiguration]] = {\n    PackageType.AGENT: AgentConfig,\n    PackageType.PROTOCOL: ProtocolConfig,\n    PackageType.CONNECTION: ConnectionConfig,\n    PackageType.SKILL: SkillConfig,\n    PackageType.CONTRACT: ContractConfig,\n}\n"
  },
  {
    "path": "aea/configurations/constants.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Module to declare constants.\"\"\"\nfrom typing import Dict, List\n\n\n_FETCHAI_IDENTIFIER = \"fetchai\"\n_ETHEREUM_IDENTIFIER = \"ethereum\"\n_COSMOS_IDENTIFIER = \"cosmos\"\nDEFAULT_PROTOCOL = \"fetchai/default:latest\"\nSIGNING_PROTOCOL = \"fetchai/signing:latest\"\nSTATE_UPDATE_PROTOCOL = \"fetchai/state_update:latest\"\nLEDGER_CONNECTION = \"fetchai/ledger:latest\"\nDEFAULT_LEDGER = _FETCHAI_IDENTIFIER\nPRIVATE_KEY_PATH_SCHEMA = \"{}_private_key.txt\"\nDEFAULT_PRIVATE_KEY_FILE = PRIVATE_KEY_PATH_SCHEMA.format(DEFAULT_LEDGER)\nDEFAULT_LICENSE = \"Apache-2.0\"\nDISTRIBUTED_PACKAGES: List[str] = []\nDEFAULT_SEARCH_SERVICE_ADDRESS = \"fetchai/soef:any\"\nDEFAULT_INPUT_FILE_NAME = \"./input_file\"\nDEFAULT_OUTPUT_FILE_NAME = \"./output_file\"\nSCAFFOLD_PUBLIC_ID = \"fetchai/scaffold:0.1.0\"\nPACKAGES = \"packages\"\nREGISTRY_PATH_KEY = \"registry_path\"\nDEFAULT_REGISTRY_NAME = PACKAGES\nVENDOR = \"vendor\"\nAGENT = \"agent\"\nAGENTS = \"agents\"\nCONNECTION = \"connection\"\nCONNECTIONS = \"connections\"\nCONTRACT = \"contract\"\nCONTRACTS = \"contracts\"\nPROTOCOL = \"protocol\"\nPROTOCOLS = \"protocols\"\nSKILL = \"skill\"\nSKILLS = \"skills\"\nDEFAULT_README_FILE = \"README.md\"\nDEFAULT_VERSION = \"0.1.0\"\nDEFAULT_AEA_CONFIG_FILE = \"aea-config.yaml\"\nDEFAULT_SKILL_CONFIG_FILE = \"skill.yaml\"\nDEFAULT_CONNECTION_CONFIG_FILE = \"connection.yaml\"\nDEFAULT_CONTRACT_CONFIG_FILE = \"contract.yaml\"\nDEFAULT_PROTOCOL_CONFIG_FILE = \"protocol.yaml\"\nPACKAGE_PUBLIC_ID_VAR_NAME = \"PUBLIC_ID\"\nDEFAULT_FINGERPRINT_IGNORE_PATTERNS = [\n    \".DS_Store\",\n    \"*__pycache__/*\",\n    \"*__pycache__\",\n    \"*.pyc\",\n    DEFAULT_AEA_CONFIG_FILE,\n    DEFAULT_PROTOCOL_CONFIG_FILE,\n    DEFAULT_CONNECTION_CONFIG_FILE,\n    DEFAULT_SKILL_CONFIG_FILE,\n    DEFAULT_CONTRACT_CONFIG_FILE,\n    PRIVATE_KEY_PATH_SCHEMA.format(\"*\"),\n]\nDEFAULT_PYPI_INDEX_URL = \"https://pypi.org/simple\"\nDEFAULT_GIT_REF = \"master\"\nDEFAULT_LOGGING_CONFIG = {\"version\": 1, \"disable_existing_loggers\": False}\nIMPORT_TEMPLATE_1 = \"from packages.{author}.{type}.{name}\"\nIMPORT_TEMPLATE_2 = \"import packages.{author}.{type}.{name}\"\nDEFAULT_ENV_DOTFILE = \".env\"\nDOTTED_PATH_MODULE_ELEMENT_SEPARATOR = \":\"\nDEFAULT_BUILD_DIR_NAME = \".build\"\nDEFAULT_DEPENDENCIES: Dict[str, Dict] = {\"aea-ledger-fetchai\": {}}\n\nCONFIG_FILE_TO_PACKAGE_TYPE = {\n    DEFAULT_SKILL_CONFIG_FILE: SKILL,\n    DEFAULT_PROTOCOL_CONFIG_FILE: PROTOCOL,\n    DEFAULT_CONNECTION_CONFIG_FILE: CONNECTION,\n    DEFAULT_CONTRACT_CONFIG_FILE: CONTRACT,\n    DEFAULT_AEA_CONFIG_FILE: AGENT,\n}  # type: Dict[str, str]\n\nCRYPTO_PLUGIN_GROUP = \"aea.cryptos\"\nLEDGER_APIS_PLUGIN_GROUP = \"aea.ledger_apis\"\nFAUCET_APIS_PLUGIN_GROUP = \"aea.faucet_apis\"\nALLOWED_GROUPS = {\n    CRYPTO_PLUGIN_GROUP,\n    LEDGER_APIS_PLUGIN_GROUP,\n    FAUCET_APIS_PLUGIN_GROUP,\n}\nAEA_MANAGER_DATA_DIRNAME = \"data\"\nLAUNCH_SUCCEED_MESSAGE = \"Start processing messages...\"\n\nPROTOCOL_LANGUAGE_PYTHON = \"python\"\nPROTOCOL_LANGUAGE_GO = \"go\"\nPROTOCOL_LANGUAGE_CPP = \"cpp\"\nPROTOCOL_LANGUAGE_JAVA = \"java\"\nPROTOCOL_LANGUAGE_CSHARP = \"csharp\"\nPROTOCOL_LANGUAGE_RUBY = \"ruby\"\nPROTOCOL_LANGUAGE_OBJC = \"objc\"\nPROTOCOL_LANGUAGE_JS = \"js\"\nSUPPORTED_PROTOCOL_LANGUAGES = [\n    PROTOCOL_LANGUAGE_PYTHON,\n    PROTOCOL_LANGUAGE_GO,\n    PROTOCOL_LANGUAGE_CPP,\n    PROTOCOL_LANGUAGE_JAVA,\n    PROTOCOL_LANGUAGE_CSHARP,\n    PROTOCOL_LANGUAGE_RUBY,\n    PROTOCOL_LANGUAGE_OBJC,\n    PROTOCOL_LANGUAGE_JS,\n]\nDEFAULT_CERTS_DIR_NAME = \".certs\"\nDEFAULT_IGNORE_DIRS_AGENT_FINGERPRINT = [\n    SKILLS,\n    PROTOCOLS,\n    CONTRACTS,\n    CONNECTIONS,\n    VENDOR,\n    DEFAULT_BUILD_DIR_NAME,\n    DEFAULT_CERTS_DIR_NAME,\n]\n\nITEM_TYPE_TO_PLURAL = {\n    PROTOCOL: PROTOCOLS,\n    AGENT: AGENTS,\n    CONTRACT: CONTRACTS,\n    CONNECTION: CONNECTIONS,\n    SKILL: SKILLS,\n}\n\nITEM_TYPE_PLURAL_TO_TYPE = {v: k for k, v in ITEM_TYPE_TO_PLURAL.items()}\n"
  },
  {
    "path": "aea/configurations/data_types.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Base config data types.\"\"\"\nimport functools\nimport re\nfrom abc import ABC, abstractmethod\nfrom enum import Enum\nfrom typing import (\n    Any,\n    Collection,\n    Dict,\n    Generic,\n    List,\n    Optional,\n    Set,\n    Tuple,\n    TypeVar,\n    Union,\n    cast,\n)\n\nimport semver\nfrom packaging.specifiers import SpecifierSet\n\nfrom aea.configurations.constants import (\n    AGENT,\n    CONNECTION,\n    CONTRACT,\n    DEFAULT_GIT_REF,\n    PROTOCOL,\n    SKILL,\n)\nfrom aea.exceptions import enforce\nfrom aea.helpers.base import (\n    RegexConstrainedString,\n    SIMPLE_ID_REGEX,\n    SimpleId,\n    SimpleIdOrStr,\n)\n\n\nT = TypeVar(\"T\")\n\n\nVersionInfoClass = semver.VersionInfo\nPackageVersionLike = Union[str, semver.VersionInfo]\n\n\nclass JSONSerializable(ABC):\n    \"\"\"Interface for JSON-serializable objects.\"\"\"\n\n    @property\n    @abstractmethod\n    def json(self) -> Dict:\n        \"\"\"Compute the JSON representation.\"\"\"\n\n    @classmethod\n    @abstractmethod\n    def from_json(cls, obj: Dict) -> \"JSONSerializable\":\n        \"\"\"Build from a JSON object.\"\"\"\n\n\n@functools.total_ordering\nclass PackageVersion:\n    \"\"\"A package version.\"\"\"\n\n    _version: PackageVersionLike\n\n    def __init__(self, version_like: PackageVersionLike) -> None:\n        \"\"\"\n        Initialize a package version.\n\n        :param version_like: a string, os a semver.VersionInfo object.\n        \"\"\"\n        if isinstance(version_like, str) and version_like == \"latest\":\n            self._version = version_like\n        elif isinstance(version_like, str) and version_like == \"any\":\n            self._version = version_like\n        elif isinstance(version_like, str):\n            self._version = VersionInfoClass.parse(version_like)\n        elif isinstance(version_like, VersionInfoClass):\n            self._version = version_like\n        else:\n            raise ValueError(\"Version type not valid.\")\n\n    @property\n    def is_latest(self) -> bool:\n        \"\"\"Check whether the version is 'latest'.\"\"\"\n        return isinstance(self._version, str) and self._version == \"latest\"\n\n    def __str__(self) -> str:\n        \"\"\"Get the string representation.\"\"\"\n        return str(self._version)\n\n    def __eq__(self, other: Any) -> bool:\n        \"\"\"Check equality.\"\"\"\n        return isinstance(other, PackageVersion) and self._version == other._version\n\n    def __lt__(self, other: Any) -> bool:\n        \"\"\"Compare with another object.\"\"\"\n        enforce(\n            isinstance(other, PackageVersion),\n            f\"Cannot compare {type(self)} with type {type(other)}.\",\n        )\n        other = cast(PackageVersion, other)\n        if self.is_latest or other.is_latest:\n            return self.is_latest < other.is_latest\n        return str(self) < str(other)\n\n\nclass PackageType(Enum):\n    \"\"\"Package types.\"\"\"\n\n    AGENT = AGENT\n    PROTOCOL = PROTOCOL\n    CONNECTION = CONNECTION\n    CONTRACT = CONTRACT\n    SKILL = SKILL\n\n    def to_plural(self) -> str:\n        \"\"\"\n        Get the plural name.\n\n        >>> PackageType.AGENT.to_plural()\n        'agents'\n        >>> PackageType.PROTOCOL.to_plural()\n        'protocols'\n        >>> PackageType.CONNECTION.to_plural()\n        'connections'\n        >>> PackageType.SKILL.to_plural()\n        'skills'\n        >>> PackageType.CONTRACT.to_plural()\n        'contracts'\n\n        :return: pluralised package type\n        \"\"\"\n        return self.value + \"s\"\n\n    def __str__(self) -> str:\n        \"\"\"Convert to string.\"\"\"\n        return str(self.value)\n\n\nclass ComponentType(Enum):\n    \"\"\"Enum of component types supported.\"\"\"\n\n    PROTOCOL = PROTOCOL\n    CONNECTION = CONNECTION\n    SKILL = SKILL\n    CONTRACT = CONTRACT\n\n    def to_package_type(self) -> PackageType:\n        \"\"\"Get package type for component type.\"\"\"\n        return PackageType(self.value)\n\n    @staticmethod\n    def plurals() -> Collection[str]:  # pylint: disable=unsubscriptable-object\n        \"\"\"\n        Get the collection of type names, plural.\n\n        >>> ComponentType.plurals()\n        ['protocols', 'connections', 'skills', 'contracts']\n\n        :return: list of all pluralised component types\n        \"\"\"\n        return list(map(lambda x: x.to_plural(), ComponentType))\n\n    def to_plural(self) -> str:\n        \"\"\"\n        Get the plural version of the component type.\n\n        >>> ComponentType.PROTOCOL.to_plural()\n        'protocols'\n        >>> ComponentType.CONNECTION.to_plural()\n        'connections'\n        >>> ComponentType.SKILL.to_plural()\n        'skills'\n        >>> ComponentType.CONTRACT.to_plural()\n        'contracts'\n\n        :return: pluralised component type\n        \"\"\"\n        return self.value + \"s\"\n\n    def __str__(self) -> str:\n        \"\"\"Get the string representation.\"\"\"\n        return str(self.value)\n\n\nPackageIdPrefix = Tuple[ComponentType, str, str]\n\n\nclass PublicId(JSONSerializable):\n    \"\"\"This class implement a public identifier.\n\n    A public identifier is composed of three elements:\n    - author\n    - name\n    - version\n\n    The concatenation of those three elements gives the public identifier:\n\n        author/name:version\n\n    >>> public_id = PublicId(\"author\", \"my_package\", \"0.1.0\")\n    >>> assert public_id.author == \"author\"\n    >>> assert public_id.name == \"my_package\"\n    >>> assert public_id.version == \"0.1.0\"\n    >>> another_public_id = PublicId(\"author\", \"my_package\", \"0.1.0\")\n    >>> assert hash(public_id) == hash(another_public_id)\n    >>> assert public_id == another_public_id\n    >>> latest_public_id = PublicId(\"author\", \"my_package\", \"latest\")\n    >>> latest_public_id\n    <author/my_package:latest>\n    >>> latest_public_id.package_version.is_latest\n    True\n    \"\"\"\n\n    __slots__ = (\"_author\", \"_name\", \"_package_version\")\n\n    AUTHOR_REGEX = SIMPLE_ID_REGEX\n    PACKAGE_NAME_REGEX = SIMPLE_ID_REGEX\n    VERSION_NUMBER_PART_REGEX = r\"(0|[1-9]\\d*)\"\n    VERSION_REGEX = rf\"(any|latest|({VERSION_NUMBER_PART_REGEX})\\.({VERSION_NUMBER_PART_REGEX})\\.({VERSION_NUMBER_PART_REGEX})(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?)\"\n    PUBLIC_ID_REGEX = rf\"^({AUTHOR_REGEX})/({PACKAGE_NAME_REGEX})(:({VERSION_REGEX}))?$\"\n    PUBLIC_ID_URI_REGEX = (\n        rf\"^({AUTHOR_REGEX})/({PACKAGE_NAME_REGEX})/({VERSION_REGEX})$\"\n    )\n\n    ANY_VERSION = \"any\"\n    LATEST_VERSION = \"latest\"\n\n    def __init__(\n        self,\n        author: SimpleIdOrStr,\n        name: SimpleIdOrStr,\n        version: Optional[PackageVersionLike] = None,\n    ) -> None:\n        \"\"\"Initialize the public identifier.\"\"\"\n        self._author = SimpleId(author)\n        self._name = SimpleId(name)\n        self._package_version = (\n            PackageVersion(version)\n            if version is not None\n            else PackageVersion(self.LATEST_VERSION)\n        )\n\n    @property\n    def author(self) -> str:\n        \"\"\"Get the author.\"\"\"\n        return str(self._author)\n\n    @property\n    def name(self) -> str:\n        \"\"\"Get the name.\"\"\"\n        return str(self._name)\n\n    @property\n    def version(self) -> str:\n        \"\"\"Get the version string.\"\"\"\n        return str(self._package_version)\n\n    @property\n    def package_version(self) -> PackageVersion:\n        \"\"\"Get the package version object.\"\"\"\n        return self._package_version\n\n    def to_any(self) -> \"PublicId\":\n        \"\"\"Return the same public id, but with any version.\"\"\"\n        return PublicId(self.author, self.name, self.ANY_VERSION)\n\n    def same_prefix(self, other: \"PublicId\") -> bool:\n        \"\"\"Check if the other public id has the same author and name of this.\"\"\"\n        return self.name == other.name and self.author == other.author\n\n    def to_latest(self) -> \"PublicId\":\n        \"\"\"Return the same public id, but with latest version.\"\"\"\n        return PublicId(self.author, self.name, self.LATEST_VERSION)\n\n    @classmethod\n    def is_valid_str(cls, public_id_string: str) -> bool:\n        \"\"\"\n        Check if a string is a public id.\n\n        :param public_id_string: the public id in string format.\n        :return: bool indicating validity\n        \"\"\"\n        match = re.match(cls.PUBLIC_ID_REGEX, public_id_string)\n        return match is not None\n\n    @classmethod\n    def from_str(cls, public_id_string: str) -> \"PublicId\":\n        \"\"\"\n        Initialize the public id from the string.\n\n        >>> str(PublicId.from_str(\"author/package_name:0.1.0\"))\n        'author/package_name:0.1.0'\n\n        A bad formatted input raises value error:\n        >>> PublicId.from_str(\"bad/formatted:input\")\n        Traceback (most recent call last):\n        ...\n        ValueError: Input 'bad/formatted:input' is not well formatted.\n\n        :param public_id_string: the public id in string format.\n        :return: the public id object.\n        :raises ValueError: if the string in input is not well formatted.\n        \"\"\"\n        match = re.match(cls.PUBLIC_ID_REGEX, public_id_string)\n        if match is None:\n            raise ValueError(\n                \"Input '{}' is not well formatted.\".format(public_id_string)\n            )\n        username = match.group(1)\n        package_name = match.group(2)\n        version = match.group(3)[1:] if \":\" in public_id_string else None\n        return PublicId(username, package_name, version)\n\n    @classmethod\n    def try_from_str(cls, public_id_string: str) -> Optional[\"PublicId\"]:\n        \"\"\"\n        Safely try to get public id from string.\n\n        :param public_id_string: the public id in string format.\n        :return: the public id object or None\n        \"\"\"\n        result: Optional[PublicId] = None\n        try:\n            result = cls.from_str(public_id_string)\n        except ValueError:\n            pass\n        return result\n\n    @classmethod\n    def from_uri_path(cls, public_id_uri_path: str) -> \"PublicId\":\n        \"\"\"\n        Initialize the public id from the string.\n\n        >>> str(PublicId.from_uri_path(\"author/package_name/0.1.0\"))\n        'author/package_name:0.1.0'\n\n        A bad formatted input raises value error:\n        >>> PublicId.from_uri_path(\"bad/formatted:input\")\n        Traceback (most recent call last):\n        ...\n        ValueError: Input 'bad/formatted:input' is not well formatted.\n\n        :param public_id_uri_path: the public id in uri path string format.\n        :return: the public id object.\n        :raises ValueError: if the string in input is not well formatted.\n        \"\"\"\n        if not re.match(cls.PUBLIC_ID_URI_REGEX, public_id_uri_path):\n            raise ValueError(\n                \"Input '{}' is not well formatted.\".format(public_id_uri_path)\n            )\n        username, package_name, version = re.findall(\n            cls.PUBLIC_ID_URI_REGEX, public_id_uri_path\n        )[0][:3]\n        return PublicId(username, package_name, version)\n\n    @property\n    def to_uri_path(self) -> str:\n        \"\"\"\n        Turn the public id into a uri path string.\n\n        :return: uri path string\n        \"\"\"\n        return \"{author}/{name}/{version}\".format(\n            author=self.author, name=self.name, version=self.version\n        )\n\n    @property\n    def json(self) -> Dict:\n        \"\"\"Compute the JSON representation.\"\"\"\n        return {\"author\": self.author, \"name\": self.name, \"version\": self.version}\n\n    @classmethod\n    def from_json(cls, obj: Dict) -> \"PublicId\":\n        \"\"\"Build from a JSON object.\"\"\"\n        return PublicId(\n            obj[\"author\"],\n            obj[\"name\"],\n            obj[\"version\"],\n        )\n\n    def __hash__(self) -> int:\n        \"\"\"Get the hash.\"\"\"\n        return hash((self.author, self.name, self.version))\n\n    def __str__(self) -> str:\n        \"\"\"Get the string representation.\"\"\"\n        return \"{author}/{name}:{version}\".format(\n            author=self.author, name=self.name, version=self.version\n        )\n\n    def __repr__(self) -> str:\n        \"\"\"Get the representation.\"\"\"\n        return f\"<{self}>\"\n\n    def __eq__(self, other: Any) -> bool:\n        \"\"\"Compare with another object.\"\"\"\n        return (\n            isinstance(other, PublicId)\n            and self.author == other.author\n            and self.name == other.name\n            and self.version == other.version\n        )\n\n    def __lt__(self, other: Any) -> bool:\n        \"\"\"\n        Compare two public ids.\n\n        >>> public_id_1 = PublicId(\"author_1\", \"name_1\", \"0.1.0\")\n        >>> public_id_2 = PublicId(\"author_1\", \"name_1\", \"0.1.1\")\n        >>> public_id_3 = PublicId(\"author_1\", \"name_2\", \"0.1.0\")\n        >>> public_id_1 > public_id_2\n        False\n        >>> public_id_1 < public_id_2\n        True\n\n        >>> public_id_1 < public_id_3\n        Traceback (most recent call last):\n        ...\n        ValueError: The public IDs author_1/name_1:0.1.0 and author_1/name_2:0.1.0 cannot be compared. Their author or name attributes are different.\n\n        :param other: the object to compate to\n        :raises ValueError: if the public ids cannot be confirmed\n        :return: whether or not the inequality is satisfied\n        \"\"\"\n        if (\n            isinstance(other, PublicId)\n            and self.author == other.author\n            and self.name == other.name\n        ):\n            return self.package_version < other.package_version\n        raise ValueError(\n            \"The public IDs {} and {} cannot be compared. Their author or name attributes are different.\".format(\n                self, other\n            )\n        )\n\n\nclass PackageId:\n    \"\"\"A package identifier.\"\"\"\n\n    PACKAGE_TYPE_REGEX = r\"({}|{}|{}|{}|{})\".format(\n        PackageType.AGENT,\n        PackageType.PROTOCOL,\n        PackageType.SKILL,\n        PackageType.CONNECTION,\n        PackageType.CONTRACT,\n    )\n    PACKAGE_ID_URI_REGEX = r\"{}/{}\".format(\n        PACKAGE_TYPE_REGEX, PublicId.PUBLIC_ID_URI_REGEX[1:-1]\n    )\n\n    __slots__ = (\"_package_type\", \"_public_id\")\n\n    def __init__(\n        self, package_type: Union[PackageType, str], public_id: PublicId\n    ) -> None:\n        \"\"\"\n        Initialize the package id.\n\n        :param package_type: the package type.\n        :param public_id: the public id.\n        \"\"\"\n        self._package_type = PackageType(package_type)\n        self._public_id = public_id\n\n    @property\n    def package_type(self) -> PackageType:\n        \"\"\"Get the package type.\"\"\"\n        return self._package_type\n\n    @property\n    def public_id(self) -> PublicId:\n        \"\"\"Get the public id.\"\"\"\n        return self._public_id\n\n    @property\n    def author(self) -> str:\n        \"\"\"Get the author of the package.\"\"\"\n        return self.public_id.author\n\n    @property\n    def name(self) -> str:\n        \"\"\"Get the name of the package.\"\"\"\n        return self.public_id.name\n\n    @property\n    def version(self) -> str:\n        \"\"\"Get the version of the package.\"\"\"\n        return self.public_id.version\n\n    @property\n    def package_prefix(self) -> Tuple[PackageType, str, str]:\n        \"\"\"Get the package identifier without the version.\"\"\"\n        return self.package_type, self.author, self.name\n\n    @classmethod\n    def from_uri_path(cls, package_id_uri_path: str) -> \"PackageId\":\n        \"\"\"\n        Initialize the package id from the string.\n\n        >>> str(PackageId.from_uri_path(\"skill/author/package_name/0.1.0\"))\n        '(skill, author/package_name:0.1.0)'\n\n        A bad formatted input raises value error:\n        >>> PackageId.from_uri_path(\"very/bad/formatted:input\")\n        Traceback (most recent call last):\n        ...\n        ValueError: Input 'very/bad/formatted:input' is not well formatted.\n\n        :param package_id_uri_path: the package id in uri path string format.\n        :return: the package id object.\n        :raises ValueError: if the string in input is not well formatted.\n        \"\"\"\n        if not re.match(cls.PACKAGE_ID_URI_REGEX, package_id_uri_path):\n            raise ValueError(\n                \"Input '{}' is not well formatted.\".format(package_id_uri_path)\n            )\n        package_type_str, username, package_name, version = re.findall(\n            cls.PACKAGE_ID_URI_REGEX, package_id_uri_path\n        )[0][:4]\n        package_type = PackageType(package_type_str)\n        public_id = PublicId(username, package_name, version)\n        return PackageId(package_type, public_id)\n\n    @property\n    def to_uri_path(self) -> str:\n        \"\"\"\n        Turn the package id into a uri path string.\n\n        :return: uri path string\n        \"\"\"\n        return f\"{str(self.package_type)}/{self.author}/{self.name}/{self.version}\"\n\n    def __hash__(self) -> int:\n        \"\"\"Get the hash.\"\"\"\n        return hash((self.package_type, self.public_id))\n\n    def __str__(self) -> str:\n        \"\"\"Get the string representation.\"\"\"\n        return \"({package_type}, {public_id})\".format(\n            package_type=self.package_type.value,\n            public_id=self.public_id,\n        )\n\n    def __repr__(self) -> str:\n        \"\"\"Get the object representation in string.\"\"\"\n        return f\"PackageId{self.__str__()}\"\n\n    def __eq__(self, other: Any) -> bool:\n        \"\"\"Compare with another object.\"\"\"\n        return (\n            isinstance(other, PackageId)\n            and self.package_type == other.package_type\n            and self.public_id == other.public_id\n        )\n\n    def __lt__(self, other: Any) -> bool:\n        \"\"\"Compare two public ids.\"\"\"\n        return str(self) < str(other)\n\n\nclass ComponentId(PackageId):\n    \"\"\"\n    Class to represent a component identifier.\n\n    A component id is a package id, but excludes the case when the package is an agent.\n    >>> pacakge_id = PackageId(PackageType.PROTOCOL, PublicId(\"author\", \"name\", \"0.1.0\"))\n    >>> component_id = ComponentId(ComponentType.PROTOCOL, PublicId(\"author\", \"name\", \"0.1.0\"))\n    >>> pacakge_id == component_id\n    True\n\n    >>> component_id2 = ComponentId(ComponentType.PROTOCOL, PublicId(\"author\", \"name\", \"0.1.1\"))\n    >>> pacakge_id == component_id2\n    False\n    \"\"\"\n\n    def __init__(\n        self, component_type: Union[ComponentType, str], public_id: PublicId\n    ) -> None:\n        \"\"\"\n        Initialize the component id.\n\n        :param component_type: the component type.\n        :param public_id: the public id.\n        \"\"\"\n        component_type = ComponentType(component_type)\n        super().__init__(component_type.to_package_type(), public_id)\n\n    @property\n    def component_type(self) -> ComponentType:\n        \"\"\"Get the component type.\"\"\"\n        return ComponentType(self.package_type.value)\n\n    @property\n    def component_prefix(self) -> PackageIdPrefix:\n        \"\"\"Get the component identifier without the version.\"\"\"\n        package_prefix = super().package_prefix\n        package_type, author, name = package_prefix\n        return ComponentType(package_type.value), author, name\n\n    def same_prefix(self, other: \"ComponentId\") -> bool:\n        \"\"\"Check if the other component id has the same type, author and name of this.\"\"\"\n        return (\n            self.component_type == other.component_type\n            and self.public_id.same_prefix(other.public_id)\n        )\n\n    @property\n    def prefix_import_path(self) -> str:\n        \"\"\"Get the prefix import path for this component.\"\"\"\n        return \"packages.{}.{}.{}\".format(\n            self.public_id.author, self.component_type.to_plural(), self.public_id.name\n        )\n\n    @property\n    def json(self) -> Dict:\n        \"\"\"Get the JSON representation.\"\"\"\n        return dict(**self.public_id.json, type=str(self.component_type))\n\n    @classmethod\n    def from_json(cls, json_data: Dict) -> \"ComponentId\":\n        \"\"\"Create  component id from json data.\"\"\"\n        return cls(\n            component_type=json_data[\"type\"], public_id=PublicId.from_json(json_data)\n        )\n\n\nclass PyPIPackageName(RegexConstrainedString):\n    \"\"\"A PyPI Package name.\"\"\"\n\n    REGEX = re.compile(r\"^([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9._-]*[A-Za-z0-9])$\")\n\n\nclass GitRef(RegexConstrainedString):\n    \"\"\"\n    A Git reference.\n\n    It can be a branch name, a commit hash or a tag.\n    \"\"\"\n\n    REGEX = re.compile(r\"^[A-Za-z0-9/.\\-_]+$\")\n\n\nclass Dependency:\n    \"\"\"\n    This class represents a PyPI dependency.\n\n    It contains the following information:\n    - version: a version specifier(s) (e.g. '==0.1.0').\n    - index: the PyPI index where to download the package from (default: https://pypi.org)\n    - git: the URL to the Git repository (e.g. https://github.com/fetchai/agents-aea.git)\n    - ref: either the branch name, the tag, the commit number or a Git reference (default: 'master'.)\n\n    If the 'git' field is set, the 'version' field will be ignored.\n    These fields will be forwarded to the 'pip' command.\n    \"\"\"\n\n    __slots__ = (\"_name\", \"_version\", \"_index\", \"_git\", \"_ref\")\n\n    def __init__(\n        self,\n        name: Union[PyPIPackageName, str],\n        version: Union[str, SpecifierSet] = \"\",\n        index: Optional[str] = None,\n        git: Optional[str] = None,\n        ref: Optional[Union[GitRef, str]] = None,\n    ) -> None:\n        \"\"\"\n        Initialize a PyPI dependency.\n\n        :param name: the package name.\n        :param version: the specifier set object\n        :param index: the URL to the PyPI server.\n        :param git: the URL to a git repository.\n        :param ref: the Git reference (branch/commit/tag).\n        \"\"\"\n        self._name: PyPIPackageName = PyPIPackageName(name)\n        self._version: SpecifierSet = self._parse_version(version)\n        self._index: Optional[str] = index\n        self._git: Optional[str] = git\n        self._ref: Optional[GitRef] = GitRef(ref) if ref is not None else None\n\n    @property\n    def name(self) -> str:\n        \"\"\"Get the name.\"\"\"\n        return str(self._name)\n\n    @property\n    def version(self) -> str:\n        \"\"\"Get the version.\"\"\"\n        return str(self._version)\n\n    @property\n    def index(self) -> Optional[str]:\n        \"\"\"Get the index.\"\"\"\n        return str(self._index) if self._index else None\n\n    @property\n    def git(self) -> Optional[str]:\n        \"\"\"Get the git.\"\"\"\n        return str(self._git) if self._git else None\n\n    @property\n    def ref(self) -> Optional[str]:\n        \"\"\"Get the ref.\"\"\"\n        return str(self._ref) if self._ref else None\n\n    @staticmethod\n    def _parse_version(version: Union[str, SpecifierSet]) -> SpecifierSet:\n        \"\"\"\n        Parse a version specifier set.\n\n        :param version: the version, a string or a SpecifierSet instance.\n        :return: the SpecifierSet instance.\n        \"\"\"\n        return version if isinstance(version, SpecifierSet) else SpecifierSet(version)\n\n    @classmethod\n    def from_json(cls, obj: Dict[str, Dict[str, str]]) -> \"Dependency\":\n        \"\"\"Parse a dependency object from a dictionary.\"\"\"\n        if len(obj) != 1:\n            raise ValueError(f\"Only one key allowed, found {set(obj.keys())}\")\n        name, attributes = list(obj.items())[0]\n        allowed_keys = {\"version\", \"index\", \"git\", \"ref\"}\n        not_allowed_keys = set(attributes.keys()).difference(allowed_keys)\n        if len(not_allowed_keys) > 0:\n            raise ValueError(f\"Not allowed keys: {not_allowed_keys}\")\n\n        version = attributes.get(\"version\", \"\")\n        index = attributes.get(\"index\", None)\n        git = attributes.get(\"git\", None)\n        ref = attributes.get(\"ref\", None)\n\n        return Dependency(name=name, version=version, index=index, git=git, ref=ref)\n\n    def to_json(self) -> Dict[str, Dict[str, str]]:\n        \"\"\"Transform the object to JSON.\"\"\"\n        result = {}\n        if self.version != \"\":\n            result[\"version\"] = self.version\n        if self.index is not None:\n            result[\"index\"] = self.index\n        if self.git is not None:\n            result[\"git\"] = cast(str, self.git)\n        if self.ref is not None:\n            result[\"ref\"] = cast(str, self.ref)\n        return {self.name: result}\n\n    def get_pip_install_args(self) -> List[str]:\n        \"\"\"Get 'pip install' arguments.\"\"\"\n        name = self.name\n        index = self.index\n        git_url = self.git\n        revision = self.ref if self.ref is not None else DEFAULT_GIT_REF\n        version_constraint = str(self.version)\n        command: List[str] = []\n        if index is not None:\n            command += [\"-i\", index]\n        if git_url is not None:\n            command += [\"git+\" + git_url + \"@\" + revision + \"#egg=\" + name]\n        else:\n            command += [name + version_constraint]\n        return command\n\n    def __str__(self) -> str:\n        \"\"\"Get the string representation.\"\"\"\n        return f\"{self.__class__.__name__}(name='{self.name}', version='{self.version}', index='{self.index}', git='{self.git}', ref='{self.ref}')\"\n\n    def __eq__(self, other: Any) -> bool:\n        \"\"\"Compare with another object.\"\"\"\n        return (\n            isinstance(other, Dependency)\n            and self._name == other._name\n            and self._version == other._version\n            and self._index == other._index\n            and self._git == other._git\n            and self._ref == other._ref\n        )\n\n\nDependencies = Dict[str, Dependency]\n\"\"\"\nA dictionary from package name to dependency data structure (see above).\nThe package name must satisfy  <a href=\"https://www.python.org/dev/peps/pep-0426/#name\">the constraints on Python packages names</a>.\n\nThe main advantage of having a dictionary is that we implicitly filter out dependency duplicates.\nWe cannot have two items with the same package name since the keys of a YAML object form a set.\n\"\"\"\n\n\nclass CRUDCollection(Generic[T]):\n    \"\"\"Interface of a CRUD collection.\"\"\"\n\n    __slots__ = (\"_items_by_id\",)\n\n    def __init__(self) -> None:\n        \"\"\"Instantiate a CRUD collection.\"\"\"\n        self._items_by_id = {}  # type: Dict[str, T]\n\n    def create(self, item_id: str, item: T) -> None:\n        \"\"\"\n        Add an item.\n\n        :param item_id: the item id.\n        :param item: the item to be added.\n        :raises ValueError: if the item with the same id is already in the collection.\n        \"\"\"\n        if item_id in self._items_by_id:\n            raise ValueError(\"Item with name {} already present!\".format(item_id))\n        self._items_by_id[item_id] = item\n\n    def read(self, item_id: str) -> Optional[T]:\n        \"\"\"\n        Get an item by its name.\n\n        :param item_id: the item id.\n        :return: the associated item, or None if the item id is not present.\n        \"\"\"\n        return self._items_by_id.get(item_id, None)\n\n    def update(self, item_id: str, item: T) -> None:\n        \"\"\"\n        Update an existing item.\n\n        :param item_id: the item id.\n        :param item: the item to be added.\n        \"\"\"\n        self._items_by_id[item_id] = item\n\n    def delete(self, item_id: str) -> None:\n        \"\"\"Delete an item.\"\"\"\n        if item_id in self._items_by_id.keys():\n            del self._items_by_id[item_id]\n\n    def read_all(self) -> List[Tuple[str, T]]:\n        \"\"\"Read all the items.\"\"\"\n        return [  # pylint: disable=unnecessary-comprehension\n            (k, v) for k, v in self._items_by_id.items()\n        ]\n\n    def keys(self) -> Set[str]:\n        \"\"\"Get the set of keys.\"\"\"\n        return set(self._items_by_id.keys())\n"
  },
  {
    "path": "aea/configurations/loader.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Implementation of the parser for configuration file.\"\"\"\nfrom pathlib import Path\nfrom typing import Any, Dict, Generic, List, TextIO, Type, TypeVar, Union, cast\n\nimport yaml\n\nimport aea\nfrom aea.configurations.base import (\n    AgentConfig,\n    ComponentConfiguration,\n    ComponentId,\n    ComponentType,\n    ConnectionConfig,\n    ContractConfig,\n    PACKAGE_TYPE_TO_CONFIG_CLASS,\n    PackageConfiguration,\n    PackageType,\n    ProtocolConfig,\n    ProtocolSpecification,\n    SkillConfig,\n)\nfrom aea.configurations.validation import ConfigValidator, make_jsonschema_base_uri\nfrom aea.exceptions import enforce\nfrom aea.helpers.io import open_file\nfrom aea.helpers.yaml_utils import yaml_dump, yaml_dump_all, yaml_load, yaml_load_all\n\n\n_STARTING_INDEX_CUSTOM_CONFIGS = 1\n\n_ = make_jsonschema_base_uri  # for tests compatibility\n\nT = TypeVar(\n    \"T\",\n    AgentConfig,\n    SkillConfig,\n    ConnectionConfig,\n    ContractConfig,\n    ProtocolConfig,\n    ProtocolSpecification,\n)\n\n\nclass BaseConfigLoader:\n    \"\"\"Base class for configuration loader classes.\"\"\"\n\n    def __init__(self, schema_filename: str) -> None:\n        \"\"\"\n        Initialize the parser for configuration files.\n\n        :param schema_filename: the path to the JSON-schema file in 'aea/configurations/schemas'.\n        \"\"\"\n        self._validator = ConfigValidator(schema_filename)\n\n    @property\n    def validator(self) -> ConfigValidator:\n        \"\"\"Get the json schema validator.\"\"\"\n        return self._validator\n\n    def validate(self, json_data: Dict) -> None:\n        \"\"\"\n        Validate a JSON object.\n\n        :param json_data: the JSON data.\n        \"\"\"\n        self.validator.validate(json_data)\n\n    @property\n    def required_fields(self) -> List[str]:\n        \"\"\"\n        Get the required fields.\n\n        :return: list of required fields.\n        \"\"\"\n        return self.validator.required_fields\n\n\nclass ConfigLoader(Generic[T], BaseConfigLoader):\n    \"\"\"Parsing, serialization and validation for package configuration files.\"\"\"\n\n    def __init__(\n        self,\n        schema_filename: str,\n        configuration_class: Type[T],\n        skip_aea_validation: bool = True,\n    ) -> None:\n        \"\"\"\n        Initialize the parser for configuration files.\n\n        :param schema_filename: the path to the JSON-schema file in 'aea/configurations/schemas'.\n        :param configuration_class: the configuration class (e.g. AgentConfig, SkillConfig etc.)\n        :param skip_aea_validation: if True, the validation of the AEA version is skipped.\n        \"\"\"\n        super().__init__(schema_filename)\n        self._configuration_class = configuration_class  # type: Type[T]\n        self._skip_aea_validation = skip_aea_validation\n\n    @property\n    def configuration_class(self) -> Type[T]:\n        \"\"\"Get the configuration class of the loader.\"\"\"\n        return self._configuration_class\n\n    def validate(self, json_data: Dict) -> None:\n        \"\"\"\n        Validate a JSON representation of an AEA package.\n\n        First, checks whether the AEA version is compatible with the configuration file.\n        Then, validates the JSON object against the specific schema.\n\n        :param json_data: the JSON data.\n        \"\"\"\n        if not self._skip_aea_validation:\n            aea_version_specifier_set = AgentConfig.parse_aea_version_specifier(\n                json_data[\"aea_version\"]\n            )\n            aea_version = aea.__version__\n            enforce(\n                aea_version_specifier_set.contains(aea_version),\n                f\"AEA version in use '{aea_version}' is not compatible with the specifier set '{aea_version_specifier_set}'.\",\n            )\n        super().validate(json_data)\n\n    def load_protocol_specification(\n        self, file_pointer: TextIO\n    ) -> ProtocolSpecification:\n        \"\"\"\n        Load an agent configuration file.\n\n        :param file_pointer: the file pointer to the configuration file\n        :return: the configuration object.\n        :raises\n        \"\"\"\n        yaml_data = yaml.safe_load_all(file_pointer)\n        yaml_documents = list(yaml_data)\n        configuration_file_json = yaml_documents[0]\n        if len(yaml_documents) == 1:\n            protobuf_snippets_json = {}\n            dialogue_configuration = {}  # type: Dict\n        elif len(yaml_documents) == 2:\n            protobuf_snippets_json = (\n                {} if \"initiation\" in yaml_documents[1] else yaml_documents[1]\n            )\n            dialogue_configuration = (\n                yaml_documents[1] if \"initiation\" in yaml_documents[1] else {}\n            )\n        elif len(yaml_documents) == 3:\n            protobuf_snippets_json = yaml_documents[1]\n            dialogue_configuration = yaml_documents[2]\n        else:\n            raise ValueError(\n                \"Incorrect number of Yaml documents in the protocol specification.\"\n            )\n\n        self.validate(configuration_file_json)\n\n        protocol_specification = cast(\n            ProtocolSpecification,\n            self.configuration_class.from_json(configuration_file_json),\n        )\n        protocol_specification.protobuf_snippets = protobuf_snippets_json\n        protocol_specification.dialogue_config = dialogue_configuration\n        return protocol_specification\n\n    def load(self, file_pointer: TextIO) -> T:\n        \"\"\"\n        Load a configuration file.\n\n        :param file_pointer: the file pointer to the configuration file\n        :return: the configuration object.\n        \"\"\"\n        if self.configuration_class.package_type == PackageType.AGENT:\n            return cast(T, self._load_agent_config(file_pointer))\n        return self._load_component_config(file_pointer)\n\n    def dump(self, configuration: T, file_pointer: TextIO) -> None:\n        \"\"\"Dump a configuration.\n\n        :param configuration: the configuration to be dumped.\n        :param file_pointer: the file pointer to the configuration file\n        \"\"\"\n        if self.configuration_class.package_type == PackageType.AGENT:\n            self._dump_agent_config(cast(AgentConfig, configuration), file_pointer)\n        else:\n            self._dump_component_config(configuration, file_pointer)\n\n    @classmethod\n    def from_configuration_type(\n        cls, configuration_type: Union[PackageType, str], **kwargs: Any\n    ) -> \"ConfigLoader\":\n        \"\"\"\n        Get the configuration loader from the type.\n\n        :param configuration_type: the type of configuration\n        :param kwargs: keyword arguments to the configuration loader constructor.\n        :return: the configuration loader\n        \"\"\"\n        configuration_type = PackageType(configuration_type)\n        return ConfigLoaders.from_package_type(configuration_type, **kwargs)\n\n    def _load_component_config(self, file_pointer: TextIO) -> T:\n        \"\"\"Load a component configuration.\"\"\"\n        configuration_file_json = yaml_load(file_pointer)\n        return self._load_from_json(configuration_file_json)\n\n    def _load_from_json(self, configuration_file_json: Dict) -> T:\n        \"\"\"Load component configuration from JSON object.\"\"\"\n        self.validate(configuration_file_json)\n        key_order = list(configuration_file_json.keys())\n        configuration_obj = cast(\n            T, self.configuration_class.from_json(configuration_file_json)\n        )\n        configuration_obj._key_order = key_order  # pylint: disable=protected-access\n        return configuration_obj\n\n    def load_agent_config_from_json(\n        self, configuration_json: List[Dict], validate: bool = True\n    ) -> AgentConfig:\n        \"\"\"\n        Load agent configuration from configuration json data.\n\n        :param configuration_json: list of dicts with aea configuration\n        :param validate: whether or not to validate\n\n        :return: AgentConfig instance\n        \"\"\"\n        if len(configuration_json) == 0:\n            raise ValueError(\"Agent configuration file was empty.\")\n        agent_config_json = configuration_json[0]\n        if validate:\n            self.validate(agent_config_json)\n        key_order = list(agent_config_json.keys())\n        agent_configuration_obj = cast(\n            AgentConfig, self.configuration_class.from_json(agent_config_json)\n        )\n        agent_configuration_obj._key_order = (  # pylint: disable=protected-access\n            key_order\n        )\n\n        component_configurations = self._get_component_configurations(\n            configuration_json\n        )\n        agent_configuration_obj.component_configurations = component_configurations\n        return agent_configuration_obj\n\n    def _get_component_configurations(\n        self, configuration_file_jsons: List[Dict]\n    ) -> Dict[ComponentId, Dict]:\n        \"\"\"\n        Get the component configurations from the tail pages of the aea-config.yaml file.\n\n        :param configuration_file_jsons: the JSON objects of the custom configurations of a aea-config.yaml file.\n        :return: a dictionary whose keys are component ids and values are the configurations.\n        \"\"\"\n        component_configurations: Dict[ComponentId, Dict] = {}\n        # load the other components.\n        for i, component_configuration_json in enumerate(\n            configuration_file_jsons[_STARTING_INDEX_CUSTOM_CONFIGS:]\n        ):\n            component_id = self._process_component_section(\n                i, component_configuration_json\n            )\n            if component_id in component_configurations:\n                raise ValueError(\n                    f\"Configuration of component {component_id} occurs more than once.\"\n                )\n            component_configurations[component_id] = component_configuration_json\n        return component_configurations\n\n    def _load_agent_config(self, file_pointer: TextIO) -> AgentConfig:\n        \"\"\"Load an agent configuration.\"\"\"\n        configuration_file_jsons = yaml_load_all(file_pointer)\n        return self.load_agent_config_from_json(configuration_file_jsons)\n\n    def _dump_agent_config(\n        self, configuration: AgentConfig, file_pointer: TextIO\n    ) -> None:\n        \"\"\"Dump agent configuration.\"\"\"\n        agent_config_part = configuration.ordered_json\n        self.validate(agent_config_part)\n        agent_config_part.pop(\"component_configurations\")\n        result = [agent_config_part] + configuration.component_configurations_json()\n        yaml_dump_all(result, file_pointer)\n\n    def _dump_component_config(self, configuration: T, file_pointer: TextIO) -> None:\n        \"\"\"Dump component configuration.\"\"\"\n        result = configuration.ordered_json\n        self.validate(result)\n        yaml_dump(result, file_pointer)\n\n    def _process_component_section(\n        self, component_index: int, component_configuration_json: Dict\n    ) -> ComponentId:\n        \"\"\"\n        Process a component configuration in an agent configuration file.\n\n        It breaks down in:\n        - extract the component id\n        - validate the component configuration\n        - check that there are only configurable fields\n\n        :param component_index: the index of the component in the file.\n        :param component_configuration_json: the JSON object.\n        :return: the processed component configuration.\n        \"\"\"\n        component_id = self.validator.split_component_id_and_config(\n            component_index, component_configuration_json\n        )\n        self.validator.validate_component_configuration(\n            component_id, component_configuration_json\n        )\n        return component_id\n\n\nclass ConfigLoaders:\n    \"\"\"Configuration Loader class to load any package type.\"\"\"\n\n    @classmethod\n    def from_package_type(\n        cls, configuration_type: Union[PackageType, str], **kwargs: Any\n    ) -> \"ConfigLoader\":\n        \"\"\"\n        Get a config loader from the configuration type.\n\n        :param configuration_type: the configuration type.\n        :param kwargs: keyword arguments to the configuration loader constructor.\n        :return: configuration loader\n        \"\"\"\n        config_class: Type[PackageConfiguration] = PACKAGE_TYPE_TO_CONFIG_CLASS[\n            PackageType(configuration_type)\n        ]\n        return ConfigLoader(config_class.schema, config_class, **kwargs)\n\n\ndef load_component_configuration(\n    component_type: ComponentType,\n    directory: Path,\n    skip_consistency_check: bool = False,\n    skip_aea_validation: bool = True,\n) -> ComponentConfiguration:\n    \"\"\"\n    Load configuration and check that it is consistent against the directory.\n\n    :param component_type: the component type.\n    :param directory: the root of the package\n    :param skip_consistency_check: if True, the consistency check are skipped.\n    :param skip_aea_validation: if True, the validation of the AEA version is skipped.\n    :return: the configuration object.\n    \"\"\"\n    package_type = component_type.to_package_type()\n    configuration_object = load_package_configuration(\n        package_type, directory, skip_consistency_check, skip_aea_validation\n    )\n    configuration_object = cast(ComponentConfiguration, configuration_object)\n    return configuration_object\n\n\ndef load_package_configuration(\n    package_type: PackageType,\n    directory: Path,\n    skip_consistency_check: bool = False,\n    skip_aea_validation: bool = True,\n) -> PackageConfiguration:\n    \"\"\"\n    Load configuration and check that it is consistent against the directory.\n\n    :param package_type: the package type.\n    :param directory: the root of the package\n    :param skip_consistency_check: if True, the consistency check are skipped.\n    :param skip_aea_validation: if True, the validation of the AEA version is skipped.\n    :return: the configuration object.\n    \"\"\"\n    configuration_object = _load_configuration_object(\n        package_type, directory, skip_aea_validation\n    )\n    if not skip_consistency_check and isinstance(\n        configuration_object, ComponentConfiguration\n    ):\n        configuration_object._check_configuration_consistency(  # pylint: disable=protected-access\n            directory\n        )\n    return configuration_object\n\n\ndef _load_configuration_object(\n    package_type: PackageType, directory: Path, skip_aea_validation: bool = True\n) -> PackageConfiguration:\n    \"\"\"\n    Load the configuration object, without consistency checks.\n\n    :param package_type: the package type.\n    :param directory: the directory of the configuration.\n    :param skip_aea_validation: if True, the validation of the AEA version is skipped.\n    :return: the configuration object.\n    :raises FileNotFoundError: if the configuration file is not found.\n    \"\"\"\n    configuration_loader = ConfigLoader.from_configuration_type(\n        package_type, skip_aea_validation=skip_aea_validation\n    )\n    configuration_filename = (\n        configuration_loader.configuration_class.default_configuration_filename\n    )\n    configuration_filepath = directory / configuration_filename\n    try:\n        with open_file(configuration_filepath) as fp:\n            configuration_object = configuration_loader.load(fp)\n    except FileNotFoundError:\n        raise FileNotFoundError(\n            \"{} configuration not found: {}\".format(\n                package_type.value.capitalize(), configuration_filepath\n            )\n        )\n    return configuration_object\n"
  },
  {
    "path": "aea/configurations/manager.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Implementation of the AgentConfigManager.\"\"\"\nimport json\nimport os\nfrom copy import deepcopy\nfrom pathlib import Path\nfrom typing import Callable, Dict, List, NewType, Optional, Set, Tuple, Union, cast\n\nfrom aea.configurations.base import (\n    AgentConfig,\n    ComponentConfiguration,\n    ComponentId,\n    DEFAULT_AEA_CONFIG_FILE,\n    PackageType,\n)\nfrom aea.configurations.constants import (\n    AGENT,\n    AGENTS,\n    CONNECTIONS,\n    CONTRACTS,\n    DEFAULT_CONNECTION_CONFIG_FILE,\n    DEFAULT_CONTRACT_CONFIG_FILE,\n    DEFAULT_PROTOCOL_CONFIG_FILE,\n    DEFAULT_SKILL_CONFIG_FILE,\n    PROTOCOLS,\n    SKILLS,\n    VENDOR,\n)\nfrom aea.configurations.data_types import ComponentType, PackageIdPrefix, PublicId\nfrom aea.configurations.loader import ConfigLoader, load_component_configuration\nfrom aea.configurations.validation import SAME_MARK, filter_data\nfrom aea.exceptions import AEAException, enforce\nfrom aea.helpers.env_vars import apply_env_variables\nfrom aea.helpers.io import open_file\nfrom aea.helpers.storage.backends.base import JSON_TYPES\nfrom aea.helpers.yaml_utils import yaml_load_all\n\n\nALLOWED_PATH_ROOTS = [\n    AGENT,\n    CONNECTIONS,\n    CONTRACTS,\n    PROTOCOLS,\n    SKILLS,\n    VENDOR,\n]\n\n\nRESOURCE_TYPE_TO_CONFIG_FILE = {\n    SKILLS: DEFAULT_SKILL_CONFIG_FILE,\n    PROTOCOLS: DEFAULT_PROTOCOL_CONFIG_FILE,\n    CONNECTIONS: DEFAULT_CONNECTION_CONFIG_FILE,\n    CONTRACTS: DEFAULT_CONTRACT_CONFIG_FILE,\n}  # type: Dict[str, str]\n\n\nJsonPath = List[str]\nVariablePath = Union[str, JsonPath]\n\n\nclass VariableDoesNotExist(ValueError):\n    \"\"\"Variable does not exist in a config exception.\"\"\"\n\n\nNotExistsType = NewType(\"NotExistsType\", object)\nNotExists = NotExistsType(None)\n\n\ndef _try_get_configuration_object_from_aea_config(\n    agent_config: AgentConfig, component_id: ComponentId\n) -> Optional[Dict]:\n    \"\"\"\n    Try to get the configuration object in the AEA config.\n\n    The result is not guaranteed because there might not be any\n\n    :param agent_config: the agent configuration.\n    :param component_id: the component id whose prefix points to the relevant custom configuration in the AEA configuration file.\n    :return: the configuration object to get/set an attribute.\n    \"\"\"\n    if component_id is None:\n        # this is the case when the prefix of the json path is 'agent'.\n        return None  # pragma: nocover\n    type_, author, name = (\n        component_id.component_type,\n        component_id.author,\n        component_id.name,\n    )\n    component_ids = set(agent_config.component_configurations.keys())\n    true_component_id = _try_get_component_id_from_prefix(\n        component_ids, (type_, author, name)\n    )\n    if true_component_id is not None:\n        return agent_config.component_configurations.get(true_component_id)\n    return None\n\n\ndef _try_get_component_id_from_prefix(\n    component_ids: Set[ComponentId], component_prefix: PackageIdPrefix\n) -> Optional[ComponentId]:\n    \"\"\"\n    Find the component id matching a component prefix.\n\n    :param component_ids: the set of component id.\n    :param component_prefix: the component prefix.\n    :return: the component id that matches the prefix.\n    :raises AEAEnforceError: if there are more than two components as candidate results.  # noqa: DAR402\n    \"\"\"\n    type_, author, name = component_prefix\n    results = list(\n        filter(\n            lambda x: x.component_type == type_\n            and x.author == author\n            and x.name == name,\n            component_ids,\n        )\n    )\n    if len(results) == 0:\n        return None\n    enforce(len(results) == 1, f\"Expected only one component, found {len(results)}.\")\n    return results[0]\n\n\ndef handle_dotted_path(\n    value: str,\n    author: str,\n    aea_project_path: Union[str, Path] = \".\",\n) -> Tuple[List[str], Path, ConfigLoader, Optional[ComponentId]]:\n    \"\"\"Separate the path between path to resource and json path to attribute.\n\n    Allowed values:\n        'agent.an_attribute_name'\n        'protocols.my_protocol.an_attribute_name'\n        'connections.my_connection.an_attribute_name'\n        'contracts.my_contract.an_attribute_name'\n        'skills.my_skill.an_attribute_name'\n        'vendor.author.[protocols|contracts|connections|skills].package_name.attribute_name\n\n    We also return the component id to retrieve the configuration of a specific\n    component. Notice that at this point we don't know the version,\n    so we put 'latest' as version, but later we will ignore it because\n    we will filter with only the component prefix (i.e. the triple type, author and name).\n\n    :param value: dotted path.\n    :param author: the author string.\n    :param aea_project_path: project path\n\n    :return: Tuple[list of settings dict keys, filepath, config loader, component id].\n    \"\"\"\n    parts = value.split(\".\")\n    aea_project_path = Path(aea_project_path)\n\n    root = parts[0]\n    if root not in ALLOWED_PATH_ROOTS:\n        raise AEAException(\n            \"The root of the dotted path must be one of: {}\".format(ALLOWED_PATH_ROOTS)\n        )\n\n    if (\n        len(parts) < 2\n        or parts[0] == AGENT\n        and len(parts) < 2\n        or parts[0] == VENDOR\n        and len(parts) < 5\n        or parts[0] != AGENT\n        and len(parts) < 3\n    ):\n        raise AEAException(\n            \"The path is too short. Please specify a path up to an attribute name.\"\n        )\n\n    # if the root is 'agent', stop.\n    if root == AGENT:\n        resource_type_plural = AGENTS\n        path_to_resource_configuration = Path(DEFAULT_AEA_CONFIG_FILE)\n        json_path = parts[1:]\n        component_id = None\n    elif root == VENDOR:\n        # parse json path\n        resource_author = parts[1]\n        resource_type_plural = parts[2]\n        resource_name = parts[3]\n\n        # extract component id\n        resource_type_singular = resource_type_plural[:-1]\n        try:\n            component_type = ComponentType(resource_type_singular)\n        except ValueError as e:\n            raise AEAException(\n                f\"'{resource_type_plural}' is not a valid component type. Please use one of {ComponentType.plurals()}.\"\n            ) from e\n        component_id = ComponentId(\n            component_type, PublicId(resource_author, resource_name)\n        )\n\n        # find path to the resource directory\n        path_to_resource_directory = (\n            aea_project_path\n            / VENDOR\n            / resource_author\n            / resource_type_plural\n            / resource_name\n        )\n        path_to_resource_configuration = (\n            path_to_resource_directory\n            / RESOURCE_TYPE_TO_CONFIG_FILE[resource_type_plural]\n        )\n        json_path = parts[4:]\n        if not path_to_resource_directory.exists():\n            raise AEAException(  # pragma: nocover\n                \"Resource vendor/{}/{}/{} does not exist.\".format(\n                    resource_author, resource_type_plural, resource_name\n                )\n            )\n    else:\n        # navigate the resources of the agent to reach the target configuration file.\n        resource_type_plural = root\n        resource_name = parts[1]\n\n        # extract component id\n        resource_type_singular = resource_type_plural[:-1]\n        component_type = ComponentType(resource_type_singular)\n        resource_author = author\n        component_id = ComponentId(\n            component_type, PublicId(resource_author, resource_name)\n        )\n\n        # find path to the resource directory\n        path_to_resource_directory = Path(\".\") / resource_type_plural / resource_name\n        path_to_resource_configuration = (\n            path_to_resource_directory\n            / RESOURCE_TYPE_TO_CONFIG_FILE[resource_type_plural]\n        )\n        json_path = parts[2:]\n        if not path_to_resource_directory.exists():\n            raise AEAException(\n                \"Resource {}/{} does not exist.\".format(\n                    resource_type_plural, resource_name\n                )\n            )\n\n    config_loader = ConfigLoader.from_configuration_type(resource_type_plural[:-1])\n    return json_path, path_to_resource_configuration, config_loader, component_id\n\n\ndef find_component_directory_from_component_id(\n    aea_project_directory: Path, component_id: ComponentId\n) -> Path:\n    \"\"\"Find a component directory from component id.\"\"\"\n    # search in vendor first\n    vendor_package_path = (\n        aea_project_directory\n        / VENDOR\n        / component_id.public_id.author\n        / component_id.component_type.to_plural()\n        / component_id.public_id.name\n    )\n    if vendor_package_path.exists() and vendor_package_path.is_dir():\n        return vendor_package_path\n\n    # search in custom packages.\n    custom_package_path = (\n        aea_project_directory\n        / component_id.component_type.to_plural()\n        / component_id.public_id.name\n    )\n    if custom_package_path.exists() and custom_package_path.is_dir():\n        return custom_package_path\n\n    raise ValueError(\"Package {} not found.\".format(component_id))\n\n\nclass AgentConfigManager:\n    \"\"\"AeaConfig manager.\"\"\"\n\n    component_configurations = \"component_configurations\"\n    _loader = ConfigLoader.from_configuration_type(PackageType.AGENT)\n\n    def __init__(\n        self,\n        agent_config: AgentConfig,\n        aea_project_directory: Union[str, Path],\n        env_vars_friendly: bool = False,\n    ) -> None:\n        \"\"\"\n        Init manager.\n\n        :param agent_config: AgentConfig to manage.\n        :param aea_project_directory: directory where project for agent_config placed.\n        :param env_vars_friendly: whether or not it is env vars friendly\n        \"\"\"\n        self.agent_config = agent_config\n        self.aea_project_directory = aea_project_directory\n        self.env_vars_friendly = env_vars_friendly\n\n    def load_component_configuration(\n        self,\n        component_id: ComponentId,\n        skip_consistency_check: bool = True,\n    ) -> ComponentConfiguration:\n        \"\"\"\n        Load component configuration from the project directory.\n\n        :param component_id: Id of the component to load config for.\n        :param skip_consistency_check: bool.\n\n        :return: ComponentConfiguration\n        \"\"\"\n        path = find_component_directory_from_component_id(\n            aea_project_directory=Path(self.aea_project_directory),\n            component_id=component_id,\n        )\n        return load_component_configuration(\n            component_type=component_id.component_type,\n            directory=path,\n            skip_consistency_check=skip_consistency_check,\n        )\n\n    @property\n    def agent_config_file_path(self) -> Path:\n        \"\"\"Return agent config file path.\"\"\"\n        return self._get_agent_config_file_path(self.aea_project_directory)\n\n    @classmethod\n    def _get_agent_config_file_path(cls, aea_project_path: Union[str, Path]) -> Path:\n        \"\"\"Get agent config file path for aea project path.\"\"\"\n        return Path(aea_project_path) / DEFAULT_AEA_CONFIG_FILE\n\n    @classmethod\n    def load(\n        cls, aea_project_path: Union[Path, str], substitude_env_vars: bool = False\n    ) -> \"AgentConfigManager\":\n        \"\"\"Create AgentConfigManager instance from agent project path.\"\"\"\n        data = cls._load_config_data(Path(aea_project_path))\n        if substitude_env_vars:\n            data = cast(List[Dict], apply_env_variables(data, os.environ))\n        agent_config = cls._loader.load_agent_config_from_json(data, validate=False)\n        instance = cls(\n            agent_config, aea_project_path, env_vars_friendly=not substitude_env_vars\n        )\n        instance.validate_current_config()\n        return instance\n\n    @classmethod\n    def _load_config_data(cls, aea_project_path: Path) -> List[Dict]:\n        with open_file(cls._get_agent_config_file_path(aea_project_path)) as fp:\n            data = yaml_load_all(fp)\n        return data\n\n    def set_variable(self, path: VariablePath, value: JSON_TYPES) -> None:\n        \"\"\"\n        Set config variable.\n\n        :param path: str dotted path  or List[Union[ComponentId, str]]\n        :param value: one of the json friendly objects.\n        \"\"\"\n        component_id, json_path = self._parse_path(path)\n        data = self._make_dict_for_path_and_value(json_path, value)\n        overrides = {}\n        if component_id:\n            overrides[self.component_configurations] = {component_id: data}\n        else:\n            # agent\n            overrides.update(data)\n\n        self.update_config(overrides)\n\n    @staticmethod\n    def _make_dict_for_path_and_value(json_path: JsonPath, value: JSON_TYPES) -> Dict:\n        \"\"\"\n        Turn json_path and value into overrides dict.\n\n        :param json_path: List[str] represents config variable path:\n        :param value: json friendly value\n\n        :return: dict of overrides\n        \"\"\"\n        data: Dict = {}\n        nested = data\n        for key in json_path[:-1]:\n            nested[key] = {}\n            nested = nested[key]\n        nested[json_path[-1]] = value\n        return data\n\n    def get_variable(self, path: VariablePath) -> JSON_TYPES:\n        \"\"\"\n        Set config variable.\n\n        :param path: str dotted path or List[Union[ComponentId, str]]\n\n        :return: json friendly value.\n        \"\"\"\n        component_id, json_path = self._parse_path(path)\n\n        if component_id:\n            configrations_data = [\n                _try_get_configuration_object_from_aea_config(\n                    self.agent_config, component_id\n                )\n                or {},\n                self.load_component_configuration(component_id).json,\n            ]\n        else:\n            configrations_data = [self.agent_config.json]\n\n        for data in configrations_data:\n            value = self._get_value_for_json_path(data, json_path)\n            if value is not NotExists:\n                return cast(JSON_TYPES, value)\n\n        raise VariableDoesNotExist(\n            f\"Attribute `{'.'.join(json_path)}` for {'{}({}) config'.format(component_id.component_type,component_id.public_id) if component_id else 'AgentConfig'} does not exist\"\n        )\n\n    @staticmethod\n    def _get_value_for_json_path(\n        data: Dict, json_path: JsonPath\n    ) -> Union[NotExistsType, JSON_TYPES]:\n        \"\"\"\n        Get value by json path from the dict object.\n\n        :param data: dict to get value from\n        :param json_path: List[str]\n\n        :return: one of the json values of NotExists if value not presents in data dict.\n        \"\"\"\n        value = json.loads(json.dumps(data))  # in case of ordered dict doing copy\n        prev_key = \"\"\n        for key in json_path:\n            if not isinstance(value, dict):\n                raise ValueError(\n                    f\"Attribute '{prev_key}' is not a dictionary.\"\n                )  # pragma: nocover\n\n            if key not in value:\n                return NotExists\n            value = value[key]\n            prev_key = key\n        return value\n\n    def _parse_path(self, path: VariablePath) -> Tuple[Optional[ComponentId], JsonPath]:\n        \"\"\"\n        Get component_id and json path from dotted path or list of str with first optional component id.\n\n        :param path: dotted path str, list of str with first optional component id\n\n        :return: Tuple of optional component id if path related to component and List[str]\n        \"\"\"\n        if isinstance(path, str):\n            json_path, *_, component_id = handle_dotted_path(\n                path,\n                self.agent_config.author,\n                aea_project_path=self.aea_project_directory,\n            )\n        else:  # pragma: nocover\n            if isinstance(path[0], ComponentId):\n                json_path = path[1:]\n                component_id = path[0]\n            else:\n                component_id = None\n                json_path = path\n        if component_id:\n            component_id = _try_get_component_id_from_prefix(\n                set(self.agent_config.all_components_id), component_id.component_prefix\n            )\n        return component_id, json_path\n\n    def update_config(self, overrides: Dict) -> None:\n        \"\"\"\n        Apply overrides for agent config.\n\n        Validates and applies agent config and component overrides.\n        Does not save it on the disc!\n\n        :param overrides: overridden values dictionary\n\n        :return: None\n        \"\"\"\n        if not overrides:\n            # nothing to update\n            return  # pragma: nocover\n\n        overrides = self._filter_overrides(overrides)\n        if overrides is SAME_MARK:\n            # nothing to update\n            return\n\n        for component_id, obj in overrides.get(\"component_configurations\", {}).items():\n            component_configuration = self.load_component_configuration(component_id)\n            component_configuration.check_overrides_valid(\n                obj, env_vars_friendly=self.env_vars_friendly\n            )\n\n        self.agent_config.update(overrides, env_vars_friendly=self.env_vars_friendly)\n\n    def _filter_overrides(self, overrides: Dict) -> Dict:\n        \"\"\"Stay only updated values for agent config.\"\"\"\n        agent_overridable, components_overridables = self.get_overridables()\n\n        agent_overridable[\"component_configurations\"] = components_overridables\n\n        filtered_overrides = filter_data(agent_overridable, overrides)\n        return filtered_overrides\n\n    def validate_current_config(self) -> None:\n        \"\"\"Check is current config valid.\"\"\"\n        for component_id, obj in self.agent_config.component_configurations.items():\n            component_configuration = self.load_component_configuration(component_id)\n            component_configuration.check_overrides_valid(\n                obj, env_vars_friendly=self.env_vars_friendly\n            )\n        self.agent_config.validate_config_data(\n            self.agent_config.json, env_vars_friendly=self.env_vars_friendly\n        )\n\n    @property\n    def json(self) -> Dict:\n        \"\"\"Return current agent config json representation.\"\"\"\n        return self.agent_config.json\n\n    def dump_config(self) -> None:\n        \"\"\"Save agent config on the disc.\"\"\"\n        config_data = self.json\n        self.agent_config.validate_config_data(\n            config_data, env_vars_friendly=self.env_vars_friendly\n        )\n        with open_file(self.agent_config_file_path, \"w\") as file_pointer:\n            ConfigLoader.from_configuration_type(PackageType.AGENT).dump(\n                self.agent_config, file_pointer\n            )\n\n    @classmethod\n    def verify_private_keys(\n        cls,\n        aea_project_path: Union[Path, str],\n        private_key_helper: Callable[[AgentConfig, Path, Optional[str]], None],\n        substitude_env_vars: bool = False,\n        password: Optional[str] = None,\n    ) -> \"AgentConfigManager\":\n        \"\"\"\n        Verify private keys.\n\n        Does not saves the config! Use AgentConfigManager.dump_config()\n\n        :param aea_project_path: path to an AEA project.\n        :param private_key_helper: private_key_helper is a function that use agent config to check the keys\n        :param substitude_env_vars: replace env vars with values, does not dump config\n        :param password: the password to encrypt/decrypt the private key.\n\n        :return: the agent configuration manager.\n        \"\"\"\n        aea_project_path = Path(aea_project_path)\n        agent_config_manager = cls.load(\n            aea_project_path, substitude_env_vars=substitude_env_vars\n        )\n        aea_conf = agent_config_manager.agent_config\n        private_key_helper(aea_conf, Path(aea_project_path), password)\n        return agent_config_manager\n\n    def get_overridables(self) -> Tuple[Dict, Dict[ComponentId, Dict]]:\n        \"\"\"Get config overridables.\"\"\"\n        agent_overridable = self.agent_config.get_overridable()\n\n        components_overridables: Dict[ComponentId, Dict] = {}\n        for component_id in self.agent_config.all_components_id:\n            obj = {}\n            component_config = self.load_component_configuration(\n                component_id, skip_consistency_check=True\n            )\n            obj.update(component_config.get_overridable())\n            obj.update(\n                deepcopy(\n                    self.agent_config.component_configurations.get(component_id, {})\n                )\n            )\n            if obj:\n                components_overridables[component_id] = obj\n        return agent_overridable, components_overridables\n"
  },
  {
    "path": "aea/configurations/pypi.py",
    "content": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains a checker for PyPI version consistency.\"\"\"\nimport operator\nfrom collections import defaultdict\nfrom copy import deepcopy\nfrom functools import reduce\nfrom typing import Dict, List, Set, cast\n\nfrom packaging.specifiers import Specifier, SpecifierSet\nfrom packaging.version import InvalidVersion, Version\n\nfrom aea.configurations.base import Dependencies, Dependency\n\n\ndef and_(s1: SpecifierSet, s2: SpecifierSet) -> SpecifierSet:\n    \"\"\"Do the and between two specifier sets.\"\"\"\n    return operator.and_(s1, s2)\n\n\ndef _handle_compatibility_operator(\n    all_specifiers: List[Specifier],\n    operator_to_specifiers: Dict[str, Set[Specifier]],\n    specifier: Specifier,\n) -> None:\n    \"\"\"\n    Handle a specifier with operator '~='.\n\n    Split specifier of the form \"~=<major.minor>\" in two specifiers:\n    - >= <major.minor>\n    - < <major+1>\n    Also handle micro-numbers, i.e. \"~=<major.minor.micro>\"\n    (see last examples of https://www.python.org/dev/peps/pep-0440/#compatible-release)\n\n    :param all_specifiers: the list of all specifiers (to be populated).\n    :param operator_to_specifiers: a mapping from operator to specifiers (to be populated).\n    :param specifier: the specifier to process.\n    \"\"\"\n    spec_version = Version(specifier.version)\n    base_version = spec_version.base_version\n    parts = base_version.split(\".\")\n    index_to_update = -2\n    if (\n        spec_version.is_prerelease\n        or spec_version.is_devrelease\n        or spec_version.is_postrelease\n    ):\n        # if it is a pre-release, ignore the suffix.\n        index_to_update += 1\n        parts = parts[:-1]\n    # bump second-to-last part\n    parts[index_to_update] = str(int(parts[index_to_update]) + 1)\n    upper_version = Version(\".\".join(parts))\n    spec_1 = Specifier(\">=\" + str(spec_version))\n    spec_2 = Specifier(\"<\" + str(upper_version))\n    all_specifiers.extend([spec_1, spec_2])\n    operator_to_specifiers[spec_1.operator].add(spec_1)\n    operator_to_specifiers[spec_2.operator].add(spec_2)\n\n\ndef is_satisfiable(specifier_set: SpecifierSet) -> bool:\n    \"\"\"\n    Check if the specifier set is satisfiable.\n\n    Satisfiable means that there exists a version number\n    that satisfies all the constraints. It is worth\n    noticing that it doesn't mean that that version\n    number with that package actually exists.\n\n    >>> from packaging.specifiers import SpecifierSet\n\n    The specifier set \">0.9, ==1.0\" is satisfiable:\n    the version number \"1.0\" satisfies the constraints\n\n    >>> s1 = SpecifierSet(\">0.9,==1.0\")\n    >>> \"1.0\" in s1\n    True\n    >>> is_satisfiable(s1)\n    True\n\n    The specifier set \"==1.0, >1.1\" is not satisfiable:\n\n    >>> s1 = SpecifierSet(\"==1.0,>1.1\")\n    >>> is_satisfiable(s1)\n    False\n\n    For other details, please refer to PEP440:\n\n        https://www.python.org/dev/peps/pep-0440\n\n    :param specifier_set: the specifier set.\n    :return: False if the constraints are surely non-satisfiable, True if we don't know.\n    \"\"\"\n    # group single specifiers by operator\n    all_specifiers: List[Specifier] = []\n    operator_to_specifiers: Dict[str, Set[Specifier]] = defaultdict(set)\n    # pre-processing\n    for specifier in list(specifier_set):\n        specifier = cast(Specifier, specifier)\n        try:\n            # if we can't parse the version number, ignore that specifier.\n            # Even if it follows a legacy version format (e.g. \"2.*\")\n            Version(specifier.version)\n        except InvalidVersion:\n            continue\n\n        # handle specifiers with '~=' operators.\n        if specifier.operator == \"~=\":\n            _handle_compatibility_operator(\n                all_specifiers, operator_to_specifiers, specifier\n            )\n        else:\n            all_specifiers.append(specifier)\n            operator_to_specifiers[specifier.operator].add(specifier)\n\n    # end of pre-processing. Start evaluation\n    # if there are two different \"==\" specifier, return False\n    if len(operator_to_specifiers[\"==\"]) >= 2:\n        return False\n\n    if len(operator_to_specifiers[\"==\"]) == 1:\n        eq_specifier = operator_to_specifiers[\"==\"].pop()\n        eq_version = eq_specifier.version\n        # notice: we implicitly handle the \"!=\" constraints.\n        return eq_version in specifier_set\n\n    # group all the \"<\" or \"<=\" together. They are interpreted as conjunction.\n    # simplify: the spec with the lowest version number is the strictest constraint\n    less_than_strict_specs = operator_to_specifiers[\"<\"]\n    less_than_equal_specs = operator_to_specifiers[\"<=\"]\n    less_than_specs = set.union(less_than_equal_specs, less_than_strict_specs)\n    # sort less-than constraints in the following way: [\"<1.0\", \"<=1.0\", \"<2.0\", \"<=2.0\"]\n    # the first element is the strictest constraint.\n    sorted_less_than_specs = sorted(\n        less_than_specs, key=lambda x: (Version(x.version), len(x.operator))\n    )\n    lowest_less_than = (\n        sorted_less_than_specs[0] if len(sorted_less_than_specs) > 0 else None\n    )\n\n    # group all the \">\" or \">=\" together. They are interpreted as conjunction.\n    # simplify: the spec with the greatest version number is the strictest constraint\n    greater_than_strict_specs = operator_to_specifiers[\">\"]\n    greater_than_equal_specs = operator_to_specifiers[\">=\"]\n    greater_than_specs = set.union(greater_than_strict_specs, greater_than_equal_specs)\n    # sort greater-than constraints in the following way: [\">=1.0\", \">1.0\", \">=2.0\", \">2.0\"]\n    # the last element is the strictest constraint.\n    sorted_greater_than_specs = sorted(\n        greater_than_specs, key=lambda x: (Version(x.version), -len(x.operator))\n    )\n    greatest_greater_than = (\n        sorted_greater_than_specs[-1] if len(sorted_greater_than_specs) > 0 else None\n    )\n\n    # if there exist two range constraints, check satisfiability.\n    # otherwise, we can't say much.\n    if lowest_less_than is not None and greatest_greater_than is not None:\n        return _handle_range_constraints(lowest_less_than, greatest_greater_than)\n\n    return True\n\n\ndef _handle_range_constraints(\n    lowest_less_than: Specifier, greatest_greater_than: Specifier\n) -> bool:\n    \"\"\"\n    Check whether two specifiers of the following type are compatible.\n\n    It is a helper method for the is_satisfiable function and checks:\n    - \"<=<some-version-number>\"\n    - \">=<some-version-number>\"\n\n    The equality might be optional.\n\n    The pseudo-code is the following:\n    - is the version number of the lower-than constraint smaller than the one of\n      the greater-than constraint? E.g. we are in cases like \"<=1.0\" and \">1.1\".\n      -  If yes, then the constraints are unsatisfiable.\n      -  Otherwise, they are satisfiable.\n    - are the version numbers the same? E.g. \"<=1.0,>=1.0\"\n      - If yes, if at least one of them is a strict comparison, then return False, otherwise True.\n    - otherwise, return True.\n\n    :param lowest_less_than: the less-than constraint.\n    :param greatest_greater_than: the greater than constraint.\n    :return: False if we are sure the two constraints are not satisfiable, True if we don't know.\n    \"\"\"\n    version_less_than = Version(lowest_less_than.version)\n    version_greater_than = Version(greatest_greater_than.version)\n    if version_less_than < version_greater_than:\n        return False\n    if version_greater_than == version_less_than:\n        # check if one of them has NOT the equality\n        one_of_them_is_a_strict_comparison = (\n            greatest_greater_than.operator == \">\"\n        ) or (lowest_less_than.operator == \"<\")\n        return not one_of_them_is_a_strict_comparison\n    return True\n\n\ndef is_simple_dep(dep: Dependency) -> bool:\n    \"\"\"\n    Check if it is a simple dependency.\n\n    Namely, if it has no field specified, or only the 'version' field set.\n\n    :param dep: the dependency\n    :return: whether it is a simple dependency or not\n    \"\"\"\n    return dep.index is None and dep.git is None\n\n\ndef to_set_specifier(dep: Dependency) -> SpecifierSet:\n    \"\"\"Get the set specifier. It assumes to be a simple dependency (see above).\"\"\"\n    return SpecifierSet(dep.version)\n\n\ndef merge_dependencies(dep1: Dependencies, dep2: Dependencies) -> Dependencies:\n    \"\"\"\n    Merge two groups of dependencies.\n\n    If some of them are not \"simple\" (see above), and there is no risk\n      of conflict because there is no other package with the same name,\n      we leave them; otherwise we raise an error.\n\n    :param dep1: the first operand\n    :param dep2: the second operand.\n    :return: the merged dependencies.\n    \"\"\"\n    result: Dependencies\n    result = deepcopy(dep1)\n\n    for pkg_name, info in dep2.items():\n        old_dep = result.get(pkg_name)\n        old_dep_exists = old_dep is not None\n        new_dep_is_simple = is_simple_dep(info)\n        old_dep_is_simple = is_simple_dep(info) if old_dep_exists else False\n\n        # if the new dependency already exists in the list, ignore\n        if old_dep == info:\n            continue\n        # if one of the operands does not have a dependency,\n        # we add it untouched to the final result and continue\n        if not old_dep_exists:\n            result[pkg_name] = info\n            continue\n\n        # in case a dependency exists in both operands and one of them is not simple:\n        if (new_dep_is_simple and old_dep_exists and not old_dep_is_simple) or (\n            not new_dep_is_simple and old_dep_exists\n        ):\n            # we raise error because we can't trivially merge the specifier sets (unless they are equal, see above)\n            raise ValueError(\n                f\"cannot trivially merge these two PyPI dependencies:\\n- {pkg_name}: {old_dep}\\n- {pkg_name}: {info}\"\n            )\n\n        # if we are here, it means both in the first and second operand\n        # there are two 'simple' dependencies with the same name\n        # therefore, we need to merge them\n        new_specifier = SpecifierSet(info.version)\n        old_specifier = (\n            SpecifierSet(result[pkg_name].version)\n            if pkg_name in result\n            else SpecifierSet(\"\")\n        )\n        combined_specifier = and_(new_specifier, old_specifier)\n        new_info = Dependency(\n            name=info.name,\n            version=combined_specifier,\n            index=info.index,\n            git=info.git,\n            ref=info.ref,\n        )\n        result[pkg_name] = new_info\n\n    return result\n\n\ndef merge_dependencies_list(*deps: Dependencies) -> Dependencies:\n    \"\"\"\n    Merge a list of dependencies.\n\n    :param deps: the list of dependencies\n    :return: the merged dependencies.\n    \"\"\"\n    result: Dependencies = reduce(merge_dependencies, deps, {})\n    return result\n"
  },
  {
    "path": "aea/configurations/schemas/aea-config_schema.json",
    "content": "{\n  \"$schema\": \"http://json-schema.org/draft-04/schema#\",\n  \"description\": \"Schema for the agent configuration file.\",\n  \"additionalProperties\": false,\n  \"type\": \"object\",\n  \"required\": [\n    \"aea_version\",\n    \"agent_name\",\n    \"author\",\n    \"description\",\n    \"version\",\n    \"license\",\n    \"fingerprint\",\n    \"fingerprint_ignore_patterns\",\n    \"private_key_paths\",\n    \"default_ledger\",\n    \"required_ledgers\",\n    \"connections\",\n    \"contracts\",\n    \"default_connection\",\n    \"protocols\",\n    \"skills\",\n    \"dependencies\"\n  ],\n  \"properties\": {\n    \"aea_version\": {\n      \"$ref\": \"definitions.json#/definitions/aea_version\"\n    },\n    \"agent_name\": {\n      \"$ref\": \"definitions.json#/definitions/resource_name\"\n    },\n    \"author\": {\n      \"$ref\": \"definitions.json#/definitions/author\"\n    },\n    \"description\": {\n      \"$ref\": \"definitions.json#/definitions/description\"\n    },\n    \"version\": {\n      \"$ref\": \"definitions.json#/definitions/package_version\"\n    },\n    \"license\": {\n      \"$ref\": \"definitions.json#/definitions/license\"\n    },\n    \"fingerprint\": {\n      \"$ref\": \"definitions.json#/definitions/fingerprint\"\n    },\n    \"fingerprint_ignore_patterns\": {\n      \"$ref\": \"definitions.json#/definitions/fingerprint_ignore_patterns\"\n    },\n    \"build_entrypoint\": {\n      \"$ref\": \"definitions.json#/definitions/build_entrypoint\"\n    },\n    \"build_directory\": {\n      \"$ref\": \"definitions.json#/definitions/build_directory\"\n    },\n    \"private_key_paths\": {\n      \"type\": \"object\",\n      \"uniqueItems\": true,\n      \"patternProperties\": {\n        \"^[^\\\\d\\\\W]\\\\w*\\\\Z\": {\n          \"$ref\": \"definitions.json#/definitions/private_key_path\"\n        }\n      }\n    },\n    \"connection_private_key_paths\": {\n      \"type\": \"object\",\n      \"uniqueItems\": true,\n      \"patternProperties\": {\n        \"^[^\\\\d\\\\W]\\\\w*\\\\Z\": {\n          \"$ref\": \"definitions.json#/definitions/private_key_path\"\n        }\n      }\n    },\n    \"default_ledger\": {\n      \"$ref\": \"definitions.json#/definitions/ledger_id\"\n    },\n    \"required_ledgers\": {\n      \"type\": \"array\",\n      \"uniqueItems\": true,\n      \"items\": {\n        \"$ref\": \"definitions.json#/definitions/ledger_id\"\n      }\n    },\n    \"currency_denominations\": {\n      \"type\": \"object\"\n    },\n    \"connections\": {\n      \"type\": \"array\",\n      \"uniqueItems\": true,\n      \"items\": {\n        \"$ref\": \"definitions.json#/definitions/public_id\"\n      }\n    },\n    \"contracts\": {\n      \"type\": \"array\",\n      \"uniqueItems\": true,\n      \"items\": {\n        \"$ref\": \"definitions.json#/definitions/public_id\"\n      }\n    },\n    \"default_connection\": {\n      \"type\": [\"string\", \"null\"]\n    },\n    \"protocols\": {\n      \"type\": \"array\",\n      \"uniqueItems\": true,\n      \"items\": {\n        \"$ref\": \"definitions.json#/definitions/public_id\"\n      }\n    },\n    \"skills\": {\n      \"type\": \"array\",\n      \"uniqueItems\": true,\n      \"items\": {\n        \"$ref\": \"definitions.json#/definitions/public_id\"\n      }\n    },\n    \"logging_config\" : {\n      \"$ref\": \"definitions.json#/definitions/logging_config\"\n    },\n    \"period\": {\n      \"$ref\": \"definitions.json#/definitions/period\"\n    },\n    \"execution_timeout\": {\n      \"$ref\": \"definitions.json#/definitions/execution_timeout\"\n    },\n    \"max_reactions\": {\n      \"$ref\": \"definitions.json#/definitions/max_reactions\"\n    },\n    \"decision_maker_handler\": {\n      \"$ref\": \"definitions.json#/definitions/framework_handler\"\n    },\n    \"error_handler\": {\n      \"$ref\": \"definitions.json#/definitions/framework_handler\"\n    },\n    \"skill_exception_policy\": {\n      \"$ref\": \"definitions.json#/definitions/skill_exception_policy\"\n    },\n    \"connection_exception_policy\": {\n      \"$ref\": \"definitions.json#/definitions/connection_exception_policy\"\n    },\n    \"default_routing\": {\n      \"type\": \"object\",\n      \"uniqueItems\": true,\n      \"patternProperties\": {\n        \"^[a-zA-Z_][a-zA-Z0-9_]{0, 127}/[a-zA-Z_][a-zA-Z0-9_]{0, 127}:(0|[1-9]\\\\d*)\\\\.(0|[1-9]\\\\d*)\\\\.(0|[1-9]\\\\d*)(?:-((?:0|[1-9]\\\\d*|\\\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\\\.(?:0|[1-9]\\\\d*|\\\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\\\+([0-9a-zA-Z-]+(?:\\\\.[0-9a-zA-Z-]+)*))?$\": {\n          \"$ref\": \"definitions.json#/definitions/public_id\"\n        }\n      }\n    },\n    \"loop_mode\": {\n      \"$ref\": \"definitions.json#/definitions/loop_mode\"\n    },\n    \"runtime_mode\": {\n      \"$ref\": \"definitions.json#/definitions/runtime_mode\"\n    },\n    \"task_manager_mode\": {\n      \"$ref\": \"definitions.json#/definitions/task_manager_mode\"\n    },\n    \"storage_uri\": {\n      \"$ref\": \"definitions.json#/definitions/storage_uri\"\n    },\n    \"data_dir\": {\n      \"type\": \"string\"\n    },\n    \"dependencies\": {\n      \"$ref\": \"definitions.json#/definitions/dependencies\"\n    }\n  }\n}\n"
  },
  {
    "path": "aea/configurations/schemas/configurable_parts/base-custom_config.json",
    "content": "{\n  \"$schema\": \"http://json-schema.org/draft-04/schema#\",\n  \"description\": \"Base schema for a custom component configuration in the agent configuration file.\",\n  \"additionalProperties\": false,\n  \"required\": [\n    \"public_id\",\n    \"type\"\n  ],\n  \"properties\": {\n    \"public_id\": {\n      \"$ref\": \"definitions.json#/definitions/public_id\"\n    },\n    \"type\": {\n      \"$ref\": \"definitions.json#/definitions/component_type\"\n    }\n  }\n}\n"
  },
  {
    "path": "aea/configurations/schemas/configurable_parts/connection-custom_config.json",
    "content": "{\n  \"$schema\": \"http://json-schema.org/draft-04/schema#\",\n  \"description\": \"Schema for the configurable part of a connection configuration in the agent configuration file.\",\n  \"additionalProperties\": false,\n  \"required\": [\n    \"public_id\",\n    \"type\"\n  ],\n  \"properties\": {\n    \"public_id\": {\n      \"$ref\": \"definitions.json#/definitions/public_id\"\n    },\n    \"type\": {\n      \"$ref\": \"definitions.json#/definitions/component_type\"\n    },\n    \"config\": {\n      \"type\": \"object\"\n    },\n    \"is_abstract\": {\n      \"$ref\": \"connection-config_schema.json#/properties/is_abstract\"\n    },\n    \"cert_requests\": {\n      \"$ref\": \"connection-config_schema.json#/properties/cert_requests\"\n    },\n    \"build_directory\": {\n      \"$ref\": \"definitions.json#/definitions/build_directory\"\n    }\n  }\n}\n"
  },
  {
    "path": "aea/configurations/schemas/configurable_parts/contract-custom_config.json",
    "content": "{\n  \"$schema\": \"http://json-schema.org/draft-04/schema#\",\n  \"description\": \"Schema for the configurable part of a contract configuration in the agent configuration file.\",\n  \"additionalProperties\": false,\n  \"required\": [\n    \"public_id\",\n    \"type\"\n  ],\n  \"properties\": {\n    \"public_id\": {\n      \"$ref\": \"definitions.json#/definitions/public_id\"\n    },\n    \"type\": {\n      \"$ref\": \"definitions.json#/definitions/component_type\"\n    },\n    \"build_directory\": {\n      \"$ref\": \"definitions.json#/definitions/build_directory\"\n    }\n  }\n}\n"
  },
  {
    "path": "aea/configurations/schemas/configurable_parts/protocol-custom_config.json",
    "content": "{\n  \"$schema\": \"http://json-schema.org/draft-04/schema#\",\n  \"description\": \"Schema for the configurable part of a protocol configuration in the agent configuration file.\",\n  \"additionalProperties\": false,\n  \"required\": [\n    \"public_id\",\n    \"type\"\n  ],\n  \"properties\": {\n    \"public_id\": {\n      \"$ref\": \"definitions.json#/definitions/public_id\"\n    },\n    \"type\": {\n      \"$ref\": \"definitions.json#/definitions/component_type\"\n    },\n    \"build_directory\": {\n      \"$ref\": \"definitions.json#/definitions/build_directory\"\n    }\n  }\n}\n"
  },
  {
    "path": "aea/configurations/schemas/configurable_parts/skill-custom_config.json",
    "content": "{\n  \"$schema\": \"http://json-schema.org/draft-04/schema#\",\n  \"description\": \"Schema for the configurable part of a skill configuration in the agent configuration file.\",\n  \"additionalProperties\": false,\n  \"required\": [\n    \"public_id\",\n    \"type\"\n  ],\n  \"properties\": {\n    \"public_id\": {\n      \"$ref\": \"definitions.json#/definitions/public_id\"\n    },\n    \"type\": {\n      \"$ref\": \"definitions.json#/definitions/component_type\"\n    },\n    \"handlers\": {\n      \"$ref\": \"#/definitions/handlers\"\n    },\n    \"behaviours\": {\n      \"$ref\": \"#/definitions/behaviours\"\n    },\n    \"models\": {\n      \"$ref\": \"#/definitions/models\"\n    },\n    \"is_abstract\": {\n      \"$ref\": \"skill-config_schema.json#/properties/is_abstract\"\n    },\n    \"build_directory\": {\n      \"$ref\": \"definitions.json#/definitions/build_directory\"\n    }\n  },\n  \"definitions\": {\n    \"handlers\": {\n      \"type\": \"object\",\n      \"additionalProperties\": false,\n      \"uniqueItems\": true,\n      \"patternProperties\": {\n        \"^[^\\\\d\\\\W]\\\\w*\\\\Z\": {\n          \"$ref\": \"#/definitions/handler\"\n        }\n      }\n    },\n    \"behaviours\": {\n      \"type\": \"object\",\n      \"uniqueItems\": true,\n      \"patternProperties\": {\n        \"^[^\\\\d\\\\W]\\\\w*\\\\Z\": {\n          \"$ref\": \"#/definitions/behaviour\"\n        }\n      }\n    },\n    \"models\": {\n      \"type\": \"object\",\n      \"uniqueItems\": true,\n      \"patternProperties\": {\n        \"^[^\\\\d\\\\W]\\\\w*\\\\Z\": {\n          \"$ref\": \"#/definitions/model\"\n        }\n      }\n    },\n    \"behaviour\": {\n      \"type\": \"object\",\n      \"additionalProperties\": false,\n      \"required\": [\n        \"args\"\n      ],\n      \"properties\": {\n        \"args\": {\n          \"type\": \"object\"\n        }\n      }\n    },\n    \"handler\": {\n      \"type\": \"object\",\n      \"additionalProperties\": false,\n      \"required\": [\n        \"args\"\n      ],\n      \"properties\": {\n        \"args\": {\n          \"type\": \"object\"\n        }\n      }\n    },\n    \"model\": {\n      \"type\": \"object\",\n      \"additionalProperties\": false,\n      \"required\": [\n        \"args\"\n      ],\n      \"properties\": {\n        \"args\": {\n          \"type\": \"object\"\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "aea/configurations/schemas/connection-config_schema.json",
    "content": "{\n  \"$schema\": \"http://json-schema.org/draft-04/schema#\",\n  \"description\": \"Schema for the connection configuration file.\",\n  \"additionalProperties\": false,\n  \"type\": \"object\",\n  \"required\": [\n    \"name\",\n    \"author\",\n    \"version\",\n    \"type\",\n    \"description\",\n    \"license\",\n    \"aea_version\",\n    \"fingerprint\",\n    \"fingerprint_ignore_patterns\",\n    \"class_name\",\n    \"config\",\n    \"connections\",\n    \"protocols\",\n    \"restricted_to_protocols\",\n    \"excluded_protocols\",\n    \"dependencies\",\n    \"is_abstract\"\n  ],\n  \"properties\": {\n    \"name\": {\n      \"$ref\": \"definitions.json#/definitions/resource_name\"\n    },\n    \"author\": {\n      \"$ref\": \"definitions.json#/definitions/author\"\n    },\n    \"version\": {\n      \"$ref\": \"definitions.json#/definitions/package_version\"\n    },\n    \"type\": {\n      \"enum\": [\"connection\"]\n    },\n    \"license\": {\n      \"$ref\": \"definitions.json#/definitions/license\"\n    },\n    \"aea_version\": {\n      \"$ref\": \"definitions.json#/definitions/aea_version\"\n    },\n    \"fingerprint\": {\n      \"$ref\": \"definitions.json#/definitions/fingerprint\"\n    },\n    \"fingerprint_ignore_patterns\": {\n      \"$ref\": \"definitions.json#/definitions/fingerprint_ignore_patterns\"\n    },\n    \"build_entrypoint\": {\n      \"$ref\": \"definitions.json#/definitions/build_entrypoint\"\n    },\n    \"build_directory\": {\n      \"$ref\": \"definitions.json#/definitions/build_directory\"\n    },\n    \"class_name\": {\n      \"type\": \"string\"\n    },\n    \"protocols\": {\n      \"type\": \"array\",\n      \"additionalProperties\": false,\n      \"uniqueItems\": true,\n      \"items\": {\n        \"$ref\": \"definitions.json#/definitions/public_id\"\n      }\n    },\n    \"connections\": {\n      \"type\": \"array\",\n      \"additionalProperties\": false,\n      \"uniqueItems\": true,\n      \"items\": {\n        \"$ref\": \"definitions.json#/definitions/public_id\"\n      }\n    },\n    \"restricted_to_protocols\": {\n      \"type\": \"array\",\n      \"uniqueItems\": true,\n      \"items\": {\n        \"$ref\": \"definitions.json#/definitions/public_id\"\n      }\n    },\n    \"excluded_protocols\": {\n      \"type\": \"array\",\n      \"uniqueItems\": true,\n      \"items\": {\n        \"$ref\": \"definitions.json#/definitions/public_id\"\n      }\n    },\n    \"config\": {\n      \"type\": \"object\"\n    },\n    \"dependencies\": {\n      \"$ref\": \"definitions.json#/definitions/dependencies\"\n    },\n    \"description\": {\n      \"$ref\": \"definitions.json#/definitions/description\"\n    },\n    \"is_abstract\": {\n      \"$ref\": \"skill-config_schema.json#/properties/is_abstract\"\n    },\n    \"cert_requests\": {\n      \"$ref\": \"definitions.json#/definitions/cert_requests\"\n    }\n  }\n}\n"
  },
  {
    "path": "aea/configurations/schemas/contract-config_schema.json",
    "content": "{\n  \"$schema\": \"http://json-schema.org/draft-04/schema#\",\n  \"description\": \"Schema for the contract configuration file.\",\n  \"additionalProperties\": false,\n  \"type\": \"object\",\n  \"required\": [\n    \"name\",\n    \"author\",\n    \"version\",\n    \"type\",\n    \"license\",\n    \"aea_version\",\n    \"fingerprint\",\n    \"fingerprint_ignore_patterns\",\n    \"class_name\",\n    \"description\",\n    \"contract_interface_paths\",\n    \"dependencies\"\n  ],\n  \"properties\": {\n    \"name\": {\n      \"$ref\": \"definitions.json#/definitions/resource_name\"\n    },\n    \"author\": {\n      \"$ref\": \"definitions.json#/definitions/author\"\n    },\n    \"version\": {\n      \"$ref\": \"definitions.json#/definitions/package_version\"\n    },\n    \"type\": {\n      \"enum\": [\"contract\"]\n    },\n    \"license\": {\n      \"$ref\": \"definitions.json#/definitions/license\"\n    },\n    \"aea_version\": {\n      \"$ref\": \"definitions.json#/definitions/aea_version\"\n    },\n    \"fingerprint\": {\n      \"$ref\": \"definitions.json#/definitions/fingerprint\"\n    },\n    \"fingerprint_ignore_patterns\": {\n      \"$ref\": \"definitions.json#/definitions/fingerprint_ignore_patterns\"\n    },\n    \"build_entrypoint\": {\n      \"$ref\": \"definitions.json#/definitions/build_entrypoint\"\n    },\n    \"build_directory\": {\n      \"$ref\": \"definitions.json#/definitions/build_directory\"\n    },\n    \"dependencies\": {\n      \"$ref\": \"definitions.json#/definitions/dependencies\"\n    },\n    \"description\": {\n      \"$ref\": \"definitions.json#/definitions/description\"\n    },\n    \"contract_interface_paths\": {\n      \"type\": \"object\",\n      \"uniqueItems\": true,\n      \"patternProperties\": {\n        \"^[^\\\\d\\\\W]\\\\w*\\\\Z\": {\n          \"$ref\": \"definitions.json#/definitions/contract_interface_path\"\n        }\n      }\n    },\n    \"class_name\": {\n      \"type\": \"string\"\n    }\n  }\n}\n"
  },
  {
    "path": "aea/configurations/schemas/definitions.json",
    "content": "{\n  \"$schema\": \"http://json-schema.org/draft-04/schema#\",\n  \"title\": \"Definitions\",\n  \"type\": \"object\",\n  \"additionalProperties\": false,\n  \"definitions\": {\n    \"dependencies\": {\n      \"type\": \"object\",\n      \"additionalProperties\": false,\n      \"patternProperties\": {\n        \"^([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9._-]*[A-Za-z0-9])$\": {\n          \"type\": \"object\",\n          \"additionalProperties\": false,\n          \"properties\": {\n            \"index\": {\n              \"type\": \"string\",\n              \"pattern\": \"^http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\\\\(\\\\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+$\"\n            },\n            \"git\": {\n              \"type\": \"string\",\n              \"pattern\": \"^http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\\\\(\\\\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+$\"\n            },\n            \"ref\": {\n              \"type\": \"string\",\n              \"pattern\": \"^[A-Za-z0-9/\\\\.\\\\-_]+$\"\n            },\n            \"version\": {\n              \"$ref\": \"#/definitions/version_specifiers\"\n            }\n          }\n        }\n      }\n    },\n    \"resource_name\": {\n      \"type\": \"string\",\n      \"pattern\": \"^[a-zA-Z_][a-zA-Z0-9_]{0,127}$\"\n    },\n    \"component_type\": {\n      \"type\": \"string\",\n      \"enum\": [\"protocol\", \"connection\", \"contract\", \"skill\"]\n    },\n    \"private_key_path\": {\n      \"type\": \"string\"\n    },\n    \"contract_interface_path\": {\n      \"type\": \"string\"\n    },\n    \"license\": {\n      \"type\": \"string\"\n    },\n    \"description\": {\n      \"type\": \"string\"\n    },\n    \"ledger_api\": {\n      \"type\": \"object\"\n    },\n    \"author\": {\n      \"type\": \"string\",\n      \"pattern\": \"^[a-zA-Z_][a-zA-Z0-9_]{0,127}$\"\n    },\n    \"package_version\": {\n      \"$ref\": \"definitions.json#/definitions/semantic_version\"\n    },\n    \"semantic_version\": {\n      \"type\": \"string\",\n      \"description\": \"A semantic version number. See https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string\",\n      \"pattern\": \"^(0|[1-9]\\\\d*)\\\\.(0|[1-9]\\\\d*)\\\\.(0|[1-9]\\\\d*)(?:-((?:0|[1-9]\\\\d*|\\\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\\\.(?:0|[1-9]\\\\d*|\\\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\\\+([0-9a-zA-Z-]+(?:\\\\.[0-9a-zA-Z-]+)*))?$\"\n    },\n    \"pep440_version\": {\n      \"type\": \"string\",\n      \"description\": \"Version number that matches PEP 440 version schemes. Differently from 'version_specifiers', this type matches only one version number, without comparison operators. See: https://www.python.org/dev/peps/pep-0440/#examples-of-compliant-version-schemes\",\n      \"pattern\": \"^(([1-9][0-9]*!)?(0|[1-9][0-9]*)(\\\\.(0|[1-9][0-9]*))*((a|b|rc)(0|[1-9][0-9]*))?(\\\\.post(0|[1-9][0-9]*))?(\\\\.dev(0|[1-9][0-9]*))?)(, *(( *(~=|==|>=|<=|!=|<|>) *)([1-9][0-9]*!)?(0|[1-9][0-9]*)(\\\\.(0|[1-9][0-9]*))*((a|b|rc)(0|[1-9][0-9]*))?(\\\\.post(0|[1-9][0-9]*))?(\\\\.dev(0|[1-9][0-9]*))?))*$\"\n    },\n    \"fingerprint\": {\n      \"type\": \"object\"\n    },\n    \"public_id\": {\n      \"type\": \"string\",\n      \"pattern\": \"^[a-zA-Z_][a-zA-Z0-9_]{0,127}/[a-zA-Z_][a-zA-Z0-9_]{0,127}:(0|[1-9]\\\\d*)\\\\.(0|[1-9]\\\\d*)\\\\.(0|[1-9]\\\\d*)(?:-((?:0|[1-9]\\\\d*|\\\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\\\.(?:0|[1-9]\\\\d*|\\\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\\\+([0-9a-zA-Z-]+(?:\\\\.[0-9a-zA-Z-]+)*))?$\"\n    },\n    \"version_specifiers\": {\n      \"type\": \"string\",\n      \"description\": \"A comma-separated list of PEP 440 version specifiers. See https://www.python.org/dev/peps/pep-0440/#version-specifiers\",\n      \"pattern\": \"^(( *(~=|==|>=|<=|!=|<|>) *)([1-9][0-9]*!)?(0|[1-9][0-9]*)(\\\\.(0|[1-9][0-9]*))*((a|b|rc)(0|[1-9][0-9]*))?(\\\\.post(0|[1-9][0-9]*))?(\\\\.dev(0|[1-9][0-9]*))?)(, *(( *(~=|==|>=|<=|!=|<|>) *)([1-9][0-9]*!)?(0|[1-9][0-9]*)(\\\\.(0|[1-9][0-9]*))*((a|b|rc)(0|[1-9][0-9]*))?(\\\\.post(0|[1-9][0-9]*))?(\\\\.dev(0|[1-9][0-9]*))?))*$\"\n    },\n    \"aea_version\": {\n      \"type\": \"string\",\n      \"description\": \"The version of AEA framework to use. It can be either a list of version specifiers (e.g. >0.2.0,<=0.2.3), or just a version number interpreted with the equality operator (e.g. 0.2.0, interpreted as ==0.2.0) (according to PEP 440).\",\n      \"oneOf\": [\n        {\"$ref\":  \"#/definitions/version_specifiers\"},\n        {\"$ref\":  \"#/definitions/pep440_version\"}\n      ]\n    },\n    \"class_name\": {\n      \"type\": \"string\",\n      \"description\": \"The class name of a skill component.\",\n      \"pattern\": \"^[A-Za-z_][A-Za-z0-9_]{0,127}$\"\n    },\n    \"fingerprint_ignore_patterns\": {\n      \"type\": \"array\",\n      \"uniqueItems\": true,\n      \"items\": {\n        \"$ref\": \"definitions.json#/definitions/ignore_pattern\"\n      }\n    },\n    \"build_entrypoint\": {\n      \"type\": \"string\"\n    },\n    \"build_directory\": {\n      \"type\": \"string\"\n    },\n    \"ledger_id\": {\n      \"type\": \"string\",\n      \"pattern\": \"^[A-Za-z_][A-Za-z0-9_]{0,127}$\"\n    },\n    \"ignore_pattern\": {\n      \"type\": \"string\"\n    },\n    \"max_reactions\": {\n      \"type\": [\"integer\", \"null\"],\n      \"minimum\": 1\n    },\n    \"period\": {\n      \"type\": [\"number\", \"null\"],\n      \"minimum\": 0,\n      \"exclusiveMinimum\": true\n    },\n    \"execution_timeout\": {\n      \"type\": [\"number\", \"null\"],\n      \"minimum\": 0\n    },\n    \"skill_exception_policy\": {\n      \"type\": \"string\",\n      \"enum\": [\"propagate\", \"just_log\", \"stop_and_exit\"]\n    },\n    \"connection_exception_policy\": {\n      \"type\": \"string\",\n      \"enum\": [\"propagate\", \"just_log\", \"stop_and_exit\"]\n    },\n    \"loop_mode\": {\n      \"type\": \"string\",\n      \"enum\": [\"async\", \"sync\"]\n    },\n    \"runtime_mode\": {\n      \"type\": \"string\",\n      \"enum\": [\"async\", \"threaded\"]\n    },\n    \"task_manager_mode\": {\n      \"type\": \"string\",\n      \"enum\": [\"threaded\", \"multiprocess\"]\n    },\n    \"storage_uri\": {\n      \"type\": \"string\"\n    },\n    \"keep_terminal_state_dialogues\": {\n      \"type\": \"boolean\"\n    },\n    \"logging_config\": {\n    \t\"type\": \"object\",\n    \t\"additionalProperties\": true,\n        \"properties\": {\n        \t\"disable_existing_loggers\": {\n              \"type\": [\"boolean\", \"null\"]\n            },\n            \"version\": {\n              \"type\": \"number\"\n            },\n            \"handlers\": {\"type\": \"object\"},\n            \"formatters\": {\"type\": \"object\"},\n            \"loggers\": {\"type\": \"object\"}\n        }\n    },\n    \"framework_handler\": {\n      \"type\": \"object\",\n      \"additionalProperties\": false,\n      \"required\": [\n        \"dotted_path\",\n        \"file_path\",\n        \"config\"\n      ],\n      \"properties\": {\n        \"dotted_path\": {\n          \"type\": \"string\"\n        },\n        \"file_path\": {\n          \"type\": [\"string\", \"null\"]\n        },\n        \"config\": {\"type\": \"object\"}\n      }\n    },\n    \"cert_requests\": {\n      \"type\": \"array\",\n      \"uniqueItems\": true,\n      \"items\": {\n        \"$ref\": \"definitions.json#/definitions/cert_request\"\n      }\n    },\n    \"cert_request\": {\n      \"type\": \"object\",\n      \"additionalProperties\": false,\n      \"required\": [\n        \"public_key\",\n        \"identifier\",\n        \"ledger_id\",\n        \"not_before\",\n        \"not_after\",\n        \"message_format\",\n        \"save_path\"\n      ],\n      \"properties\": {\n        \"public_key\": {\n          \"type\": \"string\"\n        },\n        \"identifier\": {\n          \"$ref\": \"definitions.json#/definitions/resource_name\"\n        },\n        \"ledger_id\": {\n          \"$ref\": \"definitions.json#/definitions/ledger_id\"\n        },\n        \"not_before\": {\n          \"type\": \"string\"\n        },\n        \"not_after\": {\n          \"type\": \"string\"\n        },\n        \"message_format\": {\n          \"type\": \"string\"\n        },\n        \"save_path\": {\n          \"type\": \"string\"\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "aea/configurations/schemas/protocol-config_schema.json",
    "content": "{\n  \"$schema\": \"http://json-schema.org/draft-04/schema#\",\n  \"description\": \"Schema for the protocol configuration file.\",\n  \"additionalProperties\": false,\n  \"type\": \"object\",\n  \"required\": [\n    \"name\",\n    \"author\",\n    \"version\",\n    \"type\",\n    \"license\",\n    \"aea_version\",\n    \"fingerprint\",\n    \"fingerprint_ignore_patterns\",\n    \"description\",\n    \"dependencies\",\n    \"protocol_specification_id\"\n  ],\n  \"properties\": {\n    \"name\": {\n      \"$ref\": \"definitions.json#/definitions/resource_name\"\n    },\n    \"author\": {\n      \"$ref\": \"definitions.json#/definitions/author\"\n    },\n    \"version\": {\n      \"$ref\": \"definitions.json#/definitions/package_version\"\n    },\n    \"type\": {\n      \"enum\": [\"protocol\"]\n    },\n    \"license\": {\n      \"$ref\": \"definitions.json#/definitions/license\"\n    },\n    \"aea_version\": {\n      \"$ref\": \"definitions.json#/definitions/aea_version\"\n    },\n    \"fingerprint\": {\n      \"$ref\": \"definitions.json#/definitions/fingerprint\"\n    },\n    \"fingerprint_ignore_patterns\": {\n      \"$ref\": \"definitions.json#/definitions/fingerprint_ignore_patterns\"\n    },\n    \"build_entrypoint\": {\n      \"$ref\": \"definitions.json#/definitions/build_entrypoint\"\n    },\n    \"build_directory\": {\n      \"$ref\": \"definitions.json#/definitions/build_directory\"\n    },\n    \"dependencies\": {\n      \"$ref\": \"definitions.json#/definitions/dependencies\"\n    },\n    \"description\": {\n      \"$ref\": \"definitions.json#/definitions/description\"\n    },\n    \"protocol_specification_id\": {\n      \"$ref\": \"definitions.json#/definitions/public_id\"\n    }\n  }\n}\n"
  },
  {
    "path": "aea/configurations/schemas/protocol-specification_schema.json",
    "content": "{\n  \"$schema\": \"http://json-schema.org/draft-04/schema#\",\n  \"description\": \"Schema for the protocol-specification file.\",\n  \"additionalProperties\": false,\n  \"type\": \"object\",\n  \"required\": [\n    \"name\",\n    \"author\",\n    \"version\",\n    \"license\",\n    \"aea_version\",\n    \"speech_acts\",\n    \"protocol_specification_id\",\n    \"description\"\n  ],\n  \"properties\": {\n    \"name\": {\n      \"$ref\": \"definitions.json#/definitions/resource_name\"\n    },\n    \"author\": {\n      \"$ref\": \"definitions.json#/definitions/author\"\n    },\n    \"version\": {\n      \"$ref\": \"definitions.json#/definitions/package_version\"\n    },\n    \"license\": {\n      \"$ref\": \"definitions.json#/definitions/license\"\n    },\n    \"aea_version\": {\n      \"$ref\": \"definitions.json#/definitions/aea_version\"\n    },\n    \"protocol_specification_id\": {\n      \"$ref\": \"definitions.json#/definitions/public_id\"\n    },\n    \"speech_acts\": {\n      \"type\": \"object\",\n      \"additionalProperties\": false,\n      \"uniqueItems\": true,\n      \"patternProperties\": {\n        \"^[^\\\\d\\\\W]\\\\w*\\\\Z\": {\n          \"$ref\": \"#/definitions/speech_act\"\n        }\n      }\n    },\n    \"description\": {\n      \"$ref\": \"definitions.json#/definitions/description\"\n    }\n  },\n  \"definitions\": {\n    \"speech_act\": {\n      \"type\": \"object\"\n    }\n  }\n}\n"
  },
  {
    "path": "aea/configurations/schemas/skill-config_schema.json",
    "content": "{\n  \"$schema\": \"http://json-schema.org/draft-04/schema#\",\n  \"description\": \"Schema for the skill configuration file.\",\n  \"additionalProperties\": false,\n  \"type\": \"object\",\n  \"required\": [\n    \"name\",\n    \"author\",\n    \"version\",\n    \"type\",\n    \"license\",\n    \"aea_version\",\n    \"fingerprint\",\n    \"fingerprint_ignore_patterns\",\n    \"connections\",\n    \"protocols\",\n    \"contracts\",\n    \"skills\",\n    \"handlers\",\n    \"behaviours\",\n    \"models\",\n    \"dependencies\",\n    \"description\",\n    \"is_abstract\"\n  ],\n  \"properties\": {\n    \"name\": {\n      \"$ref\": \"definitions.json#/definitions/resource_name\"\n    },\n    \"author\": {\n      \"$ref\": \"definitions.json#/definitions/author\"\n    },\n    \"version\": {\n      \"$ref\": \"definitions.json#/definitions/package_version\"\n    },\n    \"type\": {\n      \"enum\": [\"skill\"]\n    },\n    \"license\": {\n      \"$ref\": \"definitions.json#/definitions/license\"\n    },\n    \"aea_version\": {\n      \"$ref\": \"definitions.json#/definitions/aea_version\"\n    },\n    \"fingerprint\": {\n      \"$ref\": \"definitions.json#/definitions/fingerprint\"\n    },\n    \"fingerprint_ignore_patterns\": {\n      \"$ref\": \"definitions.json#/definitions/fingerprint_ignore_patterns\"\n    },\n    \"build_entrypoint\": {\n      \"$ref\": \"definitions.json#/definitions/build_entrypoint\"\n    },\n    \"build_directory\": {\n      \"$ref\": \"definitions.json#/definitions/build_directory\"\n    },\n    \"connections\": {\n      \"type\": \"array\",\n      \"additionalProperties\": false,\n      \"uniqueItems\": true,\n      \"items\": {\n        \"$ref\": \"definitions.json#/definitions/public_id\"\n      }\n    },\n    \"protocols\": {\n      \"type\": \"array\",\n      \"additionalProperties\": false,\n      \"uniqueItems\": true,\n      \"items\": {\n        \"$ref\": \"definitions.json#/definitions/public_id\"\n      }\n    },\n    \"contracts\": {\n      \"type\": \"array\",\n      \"additionalProperties\": false,\n      \"uniqueItems\": true,\n      \"items\": {\n        \"$ref\": \"definitions.json#/definitions/public_id\"\n      }\n    },\n    \"skills\": {\n      \"type\": \"array\",\n      \"additionalProperties\": false,\n      \"uniqueItems\": true,\n      \"items\": {\n        \"$ref\": \"definitions.json#/definitions/public_id\"\n      }\n    },\n    \"handlers\": {\n      \"$ref\": \"#/definitions/skill_component_list\"\n    },\n    \"behaviours\": {\n      \"$ref\": \"#/definitions/skill_component_list\"\n    },\n    \"models\": {\n      \"$ref\": \"#/definitions/skill_component_list\"\n    },\n    \"dependencies\": {\n      \"$ref\": \"definitions.json#/definitions/dependencies\"\n    },\n    \"description\": {\n      \"$ref\": \"definitions.json#/definitions/description\"\n    },\n    \"is_abstract\": {\n      \"type\": \"boolean\"\n    }\n  },\n  \"definitions\": {\n    \"skill_component_list\": {\n      \"type\": \"object\",\n      \"patternProperties\": {\n        \"^[^\\\\d\\\\W]\\\\w*\\\\Z\": {\n          \"$ref\": \"#/definitions/skill_component_configuration\"\n        }\n      }\n    },\n    \"skill_component_configuration\": {\n      \"type\": \"object\",\n      \"required\": [\n        \"class_name\"\n      ],\n      \"properties\": {\n        \"class_name\": {\n          \"$ref\": \"definitions.json#/definitions/class_name\"\n        },\n        \"args\": {\n          \"type\": \"object\"\n        },\n        \"file_path\": {\n          \"type\": \"string\"\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "aea/configurations/utils.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"AEA configuration utils.\"\"\"\nfrom functools import singledispatch\nfrom typing import Dict, Optional, Set\n\nfrom aea.configurations.base import (\n    AgentConfig,\n    ComponentId,\n    ComponentType,\n    ConnectionConfig,\n    ContractConfig,\n    PackageConfiguration,\n    ProtocolConfig,\n    PublicId,\n    SkillConfig,\n)\nfrom aea.configurations.data_types import PackageIdPrefix\n\n\n@singledispatch\ndef replace_component_ids(\n    _arg: PackageConfiguration,\n    _replacements: Dict[ComponentType, Dict[PublicId, PublicId]],\n) -> None:\n    \"\"\"\n    Update public id references in a package configuration.\n\n    This depends on the actual configuration being considered.\n    \"\"\"\n\n\n@replace_component_ids.register(AgentConfig)  # type: ignore\ndef _(\n    arg: AgentConfig,\n    replacements: Dict[ComponentType, Dict[PublicId, PublicId]],\n) -> None:\n    \"\"\"\n    Replace references in agent configuration.\n\n    It breaks down in:\n    1) replace public ids in 'protocols', 'connections', 'contracts' and 'skills';\n    2) replace public ids in default routing;\n    3) replace public id of default connection;\n    4) replace custom component configurations.\n\n    :param arg: the agent configuration.\n    :param replacements: the replacement mapping.\n    \"\"\"\n    _replace_component_id(\n        arg,\n        {\n            ComponentType.PROTOCOL,\n            ComponentType.CONNECTION,\n            ComponentType.CONTRACT,\n            ComponentType.SKILL,\n        },\n        replacements,\n    )\n\n    # update default routing\n    protocol_replacements = replacements.get(ComponentType.PROTOCOL, {})\n    connection_replacements = replacements.get(ComponentType.CONNECTION, {})\n    for protocol_id, connection_id in list(arg.default_routing.items()):\n\n        # update protocol (if replacements provides it)\n        new_protocol_id = protocol_replacements.get(protocol_id, protocol_id)\n        old_value = arg.default_routing.pop(protocol_id)\n        arg.default_routing[new_protocol_id] = old_value\n        # in case needs to be used below\n        protocol_id = new_protocol_id\n\n        # update connection (if replacements provides it)\n        new_connection_id = connection_replacements.get(connection_id, connection_id)\n        arg.default_routing[protocol_id] = new_connection_id\n\n    # update default connection\n    if arg.default_connection is not None:\n        default_connection_public_id = arg.default_connection\n        new_default_connection_public_id = replacements.get(\n            ComponentType.CONNECTION, {}\n        ).get(default_connection_public_id, default_connection_public_id)\n        arg.default_connection = new_default_connection_public_id\n\n    for component_id in set(arg.component_configurations.keys()):\n        replacements_by_type = replacements.get(component_id.component_type, {})\n        if component_id.public_id in replacements_by_type:\n            new_component_id = ComponentId(\n                component_id.component_type,\n                replacements_by_type[component_id.public_id],\n            )\n            old_config = arg.component_configurations.pop(component_id)\n            arg.component_configurations[new_component_id] = old_config\n\n\n@replace_component_ids.register(ProtocolConfig)  # type: ignore\ndef _(\n    _arg: ProtocolConfig,\n    _replacements: Dict[ComponentType, Dict[PublicId, PublicId]],\n) -> None:\n    \"\"\"Do nothing - protocols have no references.\"\"\"\n\n\n@replace_component_ids.register(ConnectionConfig)  # type: ignore\ndef _(\n    arg: ConnectionConfig,\n    replacements: Dict[ComponentType, Dict[PublicId, PublicId]],\n) -> None:\n    \"\"\"Replace references in a connection configuration.\"\"\"\n    _replace_component_id(\n        arg, {ComponentType.PROTOCOL, ComponentType.CONNECTION}, replacements\n    )\n\n    protocol_replacements = replacements.get(ComponentType.PROTOCOL, {})\n    for old_protocol_id in set(arg.restricted_to_protocols):\n        new_protocol_id = protocol_replacements.get(old_protocol_id, old_protocol_id)\n        arg.restricted_to_protocols.remove(old_protocol_id)\n        arg.restricted_to_protocols.add(new_protocol_id)\n\n    for old_protocol_id in set(arg.excluded_protocols):\n        new_protocol_id = protocol_replacements.get(old_protocol_id, old_protocol_id)\n        arg.excluded_protocols.remove(old_protocol_id)\n        arg.excluded_protocols.add(new_protocol_id)\n\n\n@replace_component_ids.register(ContractConfig)  # type: ignore\ndef _(  # type: ignore\n    _arg: ContractConfig,\n    _replacements: Dict[ComponentType, Dict[PublicId, PublicId]],\n) -> None:\n    \"\"\"Do nothing - contracts have no references.\"\"\"\n\n\n@replace_component_ids.register(SkillConfig)  # type: ignore\ndef _(\n    arg: SkillConfig,\n    replacements: Dict[ComponentType, Dict[PublicId, PublicId]],\n) -> None:\n    \"\"\"Replace references in a skill configuration.\"\"\"\n    _replace_component_id(\n        arg,\n        {\n            ComponentType.PROTOCOL,\n            ComponentType.CONNECTION,\n            ComponentType.CONTRACT,\n            ComponentType.SKILL,\n        },\n        replacements,\n    )\n\n\ndef _replace_component_id(\n    config: PackageConfiguration,\n    types_to_update: Set[ComponentType],\n    replacements: Dict[ComponentType, Dict[PublicId, PublicId]],\n) -> None:\n    \"\"\"\n    Replace a component id.\n\n    :param config: the component configuration to update.\n    :param types_to_update: the types to update.\n    :param replacements: the replacements.\n    \"\"\"\n    for component_type in types_to_update:\n        public_id_set: Set[PublicId] = getattr(\n            config, component_type.to_plural(), set()\n        )\n        replacements_given_type = replacements.get(component_type, {})\n        for old_public_id in list(public_id_set):\n            new_public_id = replacements_given_type.get(old_public_id, old_public_id)\n            public_id_set.remove(old_public_id)\n            public_id_set.add(new_public_id)\n\n\ndef get_latest_component_id_from_prefix(\n    agent_config: AgentConfig, component_prefix: PackageIdPrefix\n) -> Optional[ComponentId]:\n    \"\"\"\n    Get component id with the greatest version in an agent configuration given its prefix.\n\n    :param agent_config: the agent configuration.\n    :param component_prefix: the package prefix.\n    :return: the package id with the greatest version, or None if not found.\n    \"\"\"\n    all_dependencies = agent_config.package_dependencies\n    chosen_component_ids = [\n        c for c in all_dependencies if c.component_prefix == component_prefix\n    ]\n    nb_results = len(chosen_component_ids)\n    return chosen_component_ids[0] if nb_results == 1 else None\n"
  },
  {
    "path": "aea/configurations/validation.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Implementation of the configuration validation.\"\"\"\nimport inspect\nimport json\nimport os\nfrom copy import deepcopy\nfrom pathlib import Path\nfrom typing import Any, Dict, Iterator, List, Optional, Tuple\n\nimport jsonschema\nfrom jsonschema import Draft4Validator\nfrom jsonschema._types import TypeChecker\nfrom jsonschema._utils import find_additional_properties\nfrom jsonschema._validators import additionalProperties\nfrom jsonschema.validators import extend\n\nfrom aea.configurations.constants import AGENT\nfrom aea.configurations.data_types import ComponentId, ComponentType, PublicId\nfrom aea.exceptions import AEAValidationError\nfrom aea.helpers.base import dict_to_path_value\nfrom aea.helpers.env_vars import is_env_variable\nfrom aea.helpers.io import open_file\n\n\n_CUR_DIR = os.path.dirname(inspect.getfile(inspect.currentframe()))  # type: ignore\n_SCHEMAS_DIR = os.path.join(_CUR_DIR, \"schemas\")\n\n_PREFIX_BASE_CONFIGURABLE_PARTS = \"base\"\n_SCHEMAS_CONFIGURABLE_PARTS_DIRNAME = \"configurable_parts\"\n_POSTFIX_CUSTOM_CONFIG = \"-custom_config.json\"\n\n\ndef make_jsonschema_base_uri(base_uri_path: Path) -> str:\n    \"\"\"\n    Make the JSONSchema base URI, cross-platform.\n\n    :param base_uri_path: the path to the base directory.\n    :return: the string in URI form.\n    \"\"\"\n    if os.name == \"nt\":  # pragma: nocover  # cause platform depended\n        root_path = \"file:///{}/\".format(\"/\".join(base_uri_path.absolute().parts))\n    else:  # pragma: nocover  # cause platform depended\n        root_path = \"file://{}/\".format(base_uri_path.absolute())\n    return root_path\n\n\ndef _get_path_to_custom_config_schema_from_type(component_type: ComponentType) -> str:\n    \"\"\"\n    Get the path to the custom config schema\n\n    :param component_type: a component type.\n    :return: the path to the JSON schema file.\n    \"\"\"\n    path_prefix: Path = Path(_SCHEMAS_DIR) / _SCHEMAS_CONFIGURABLE_PARTS_DIRNAME\n    if component_type in {ComponentType.SKILL, ComponentType.CONNECTION}:\n        filename_prefix = component_type.value\n    else:\n        filename_prefix = _PREFIX_BASE_CONFIGURABLE_PARTS\n    full_path = path_prefix / (filename_prefix + _POSTFIX_CUSTOM_CONFIG)\n    return str(full_path)\n\n\nclass ExtraPropertiesError(ValueError):\n    \"\"\"Extra properties exception.\"\"\"\n\n    def __str__(self) -> str:  # pragma: nocover\n        \"\"\"Get string representation of the object.\"\"\"\n        return (\n            f\"ExtraPropertiesError: properties not expected: {', '.join(self.args[0])}\"\n        )\n\n    def __repr__(self) -> str:  # pragma: nocover\n        \"\"\"Get string representation of the object.\"\"\"\n        return str(self)\n\n\nclass CustomTypeChecker(TypeChecker):\n    \"\"\"Custom type checker to handle env variables.\"\"\"\n\n    def is_type(self, instance, type) -> bool:  # type: ignore # pylint: disable=redefined-builtin\n        \"\"\"Check is instance of type.\"\"\"\n        if is_env_variable(instance):\n            return True\n        return super().is_type(instance, type)\n\n\ndef own_additional_properties(validator, aP, instance, schema) -> Iterator:  # type: ignore\n    \"\"\"Additional properties validator.\"\"\"\n    for _ in additionalProperties(validator, aP, instance, schema):\n        raise ExtraPropertiesError(list(find_additional_properties(instance, schema)))\n    return iter(())\n\n\nOwnDraft4Validator = extend(\n    validator=Draft4Validator,\n    validators={\"additionalProperties\": own_additional_properties},\n)\n\n\nEnvVarsFriendlyDraft4Validator = extend(\n    validator=Draft4Validator,\n    type_checker=CustomTypeChecker(\n        Draft4Validator.TYPE_CHECKER._type_checkers  # pylint: disable=protected-access\n    ),\n)\n\n\nclass ConfigValidator:\n    \"\"\"Configuration validator implementation.\"\"\"\n\n    def __init__(self, schema_filename: str, env_vars_friendly: bool = False) -> None:\n        \"\"\"\n        Initialize the parser for configuration files.\n\n        :param schema_filename: the path to the JSON-schema file in 'aea/configurations/schemas'.\n        :param env_vars_friendly: whether or not it is env var friendly.\n        \"\"\"\n        base_uri = Path(_SCHEMAS_DIR)\n        with open_file(base_uri / schema_filename) as fp:\n            self._schema = json.load(fp)\n        root_path = make_jsonschema_base_uri(base_uri)\n        self._resolver = jsonschema.RefResolver(root_path, self._schema)\n        self.env_vars_friendly = env_vars_friendly\n\n        if env_vars_friendly:\n            self._validator = EnvVarsFriendlyDraft4Validator(\n                self._schema, resolver=self._resolver\n            )\n        else:\n            self._validator = OwnDraft4Validator(self._schema, resolver=self._resolver)\n\n    @staticmethod\n    def split_component_id_and_config(\n        component_index: int, component_configuration_json: Dict\n    ) -> ComponentId:\n        \"\"\"\n        Split component id and configuration.\n\n        :param component_index: the position of the component configuration in the agent config file..\n        :param component_configuration_json: the JSON object to process.\n        :return: the component id and the configuration object.\n        :raises ValueError: if the component id cannot be extracted.\n        \"\"\"\n        # author, name, version, type are mandatory fields\n        missing_fields = {\"public_id\", \"type\"}.difference(\n            component_configuration_json.keys()\n        )\n        if len(missing_fields) > 0:\n            raise ValueError(\n                f\"There are missing fields in component id {component_index + 1}: {missing_fields}.\"\n            )\n        public_id_str = component_configuration_json.pop(\"public_id\")\n        component_type = ComponentType(component_configuration_json.pop(\"type\"))\n        component_public_id = PublicId.from_str(public_id_str)\n        component_id = ComponentId(component_type, component_public_id)\n        return component_id\n\n    @classmethod\n    def validate_component_configuration(\n        cls,\n        component_id: ComponentId,\n        configuration: Dict,\n        env_vars_friendly: bool = False,\n    ) -> None:\n        \"\"\"\n        Validate the component configuration of an agent configuration file.\n\n        This check is to detect inconsistencies in the specified fields.\n\n        :param component_id: the component id.\n        :param configuration: the configuration dictionary.\n        :param env_vars_friendly: bool, if set True, will not raise errors over the env variable definitions.\n\n        :raises ValueError: if the configuration is not valid.\n        \"\"\"\n        schema_file = _get_path_to_custom_config_schema_from_type(\n            component_id.component_type\n        )\n        try:\n            cls(schema_file, env_vars_friendly=env_vars_friendly).validate(\n                dict(\n                    type=str(component_id.component_type),\n                    public_id=str(component_id.public_id),\n                    **configuration,\n                )\n            )\n        except Exception as e:\n            raise ValueError(\n                f\"Configuration of component ({str(component_id.component_type)}, {component_id.public_id}) is not valid. {str(e)}\"\n            )\n\n    def validate(self, json_data: Dict) -> None:\n        \"\"\"\n        Validate a JSON object against the right JSON schema.\n\n        :param json_data: the JSON data.\n        \"\"\"\n        if json_data.get(\"type\", AGENT) == AGENT:\n            json_data_copy = deepcopy(json_data)\n\n            # validate component_configurations\n            self.validate_agent_components_configuration(\n                json_data_copy.pop(\"component_configurations\", [])\n            )\n\n            # validate agent config\n            self._validate(json_data_copy)\n        else:\n            self._validate(json_data)\n\n    def _validate(self, instance: Dict) -> None:\n        \"\"\"Validate an instance using the current validator.\"\"\"\n        errors: List[jsonschema.ValidationError] = list(\n            self._validator.iter_errors(instance=instance)\n        )\n        if len(errors) > 0:\n            error_msg = self._build_message_from_errors(errors)\n            raise AEAValidationError(f\"{error_msg}\")\n\n    @staticmethod\n    def _build_message_from_errors(errors: List[jsonschema.ValidationError]) -> str:\n        \"\"\"Build an error message from validation errors.\"\"\"\n\n        def path(error):  # type: ignore\n            return \".\".join(list(error.path))\n\n        result = [f\"{path(error)}: {error.message}\" for error in errors]\n        return \"The following errors occurred during validation:\\n - \" + \"\\n - \".join(\n            result\n        )\n\n    def validate_agent_components_configuration(\n        self, component_configurations: Dict\n    ) -> None:\n        \"\"\"\n        Validate agent component configurations overrides.\n\n        :param component_configurations: the component configurations to validate.\n        \"\"\"\n        for idx, component_configuration_json in enumerate(component_configurations):\n            component_id = self.split_component_id_and_config(\n                idx, component_configuration_json\n            )\n            self.validate_component_configuration(\n                component_id, component_configuration_json\n            )\n\n    @property\n    def required_fields(self) -> List[str]:\n        \"\"\"\n        Get the required fields.\n\n        :return: list of required fields.\n        \"\"\"\n        return self._schema[\"required\"]\n\n\ndef validate_data_with_pattern(\n    data: dict,\n    pattern: dict,\n    excludes: Optional[List[Tuple[str]]] = None,\n    skip_env_vars: bool = False,\n) -> List[str]:\n    \"\"\"\n    Validate data dict with pattern dict for attributes present and type match.\n\n    :param data: data dict to validate\n    :param pattern: dict with pattern to check over\n    :param excludes: list of tuples of str of paths to be skipped during the check\n    :param skip_env_vars: is set True will not check data type over env variables.\n\n    :return: list of str with error descriptions\n    \"\"\"\n    if excludes is None:\n        excludes_: List[Tuple[str]] = []\n    else:\n        excludes_ = excludes\n    pattern_path_value = {\n        tuple(path): value for path, value in dict_to_path_value(pattern)\n    }\n    data_path_value = {tuple(path): value for path, value in dict_to_path_value(data)}\n    errors = []\n\n    def check_excludes(path: Tuple[str, ...]) -> bool:\n        for exclude in excludes_:\n            if len(exclude) > len(path):  # pragma: nocover\n                continue\n\n            if path[: len(exclude)] == exclude:\n                return True\n        return False\n\n    for path, new_value in data_path_value.items():\n        if check_excludes(path):\n            continue\n\n        if path not in pattern_path_value:\n            errors.append(f\"Attribute `{'.'.join(path)}` is not allowed to be updated!\")\n            continue\n\n        pattern_value = pattern_path_value[path]\n\n        if pattern_value is None:\n            # not possible to determine data type for optional value not set\n            # it will be checked with jsonschema later\n            continue  # pragma: nocover\n\n        if skip_env_vars and (\n            is_env_variable(pattern_value) or is_env_variable(new_value)\n        ):\n            # one of the values is env variable: skip data type check\n            continue\n\n        if (\n            not issubclass(type(new_value), type(pattern_value))\n            and new_value is not None\n        ):\n            errors.append(\n                f\"For attribute `{'.'.join(path)}` `{type(pattern_value).__name__}` data type is expected, but `{type(new_value).__name__}` was provided!\"\n            )\n\n    return errors\n\n\nSAME_MARK = object()\n\n\ndef filter_data(base: Any, updates: Any) -> Any:\n    \"\"\"Return difference in values or `SAME_MARK` object if values are the same.\"\"\"\n    if not isinstance(updates, type(base)):\n        return updates\n\n    if not isinstance(base, dict):\n        if base == updates:\n            return SAME_MARK\n        return updates\n\n    new_keys = set(updates.keys()) - set(base.keys())\n    common_keys = set(updates.keys()).intersection(set(base.keys()))\n    new_data = {key: updates[key] for key in new_keys}\n\n    for key in common_keys:\n        value = filter_data(base[key], updates[key])\n        if value is SAME_MARK:\n            continue\n        new_data[key] = value\n\n    if not new_data:\n        return SAME_MARK\n    return new_data\n"
  },
  {
    "path": "aea/connections/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the connection modules.\"\"\"\n"
  },
  {
    "path": "aea/connections/base.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"The base connection package.\"\"\"\nimport asyncio\nimport inspect\nimport re\nfrom abc import ABC, abstractmethod\nfrom concurrent.futures.thread import ThreadPoolExecutor\nfrom contextlib import contextmanager\nfrom enum import Enum\nfrom pathlib import Path\nfrom typing import Any, Callable, Generator, Optional, Set, TYPE_CHECKING, cast\n\nfrom aea.components.base import Component, load_aea_package\nfrom aea.configurations.base import ComponentType, ConnectionConfig, PublicId\nfrom aea.configurations.loader import load_component_configuration\nfrom aea.crypto.wallet import CryptoStore\nfrom aea.exceptions import (\n    AEAComponentLoadException,\n    AEAInstantiationException,\n    enforce,\n    parse_exception,\n)\nfrom aea.helpers.async_utils import AsyncState\nfrom aea.helpers.base import load_module\nfrom aea.helpers.logging import get_logger\nfrom aea.identity.base import Identity\n\n\nif TYPE_CHECKING:\n    from aea.mail.base import Address, Envelope  # pragma: no cover\n\n\nclass ConnectionStates(Enum):\n    \"\"\"Connection states enum.\"\"\"\n\n    connected = \"connected\"\n    connecting = \"connecting\"\n    disconnecting = \"disconnecting\"\n    disconnected = \"disconnected\"\n\n\nclass Connection(Component, ABC):\n    \"\"\"Abstract definition of a connection.\"\"\"\n\n    connection_id = None  # type: PublicId\n\n    def __init__(\n        self,\n        configuration: ConnectionConfig,\n        data_dir: str,\n        identity: Optional[Identity] = None,\n        crypto_store: Optional[CryptoStore] = None,\n        restricted_to_protocols: Optional[Set[PublicId]] = None,\n        excluded_protocols: Optional[Set[PublicId]] = None,\n        **kwargs: Any,\n    ) -> None:\n        \"\"\"\n        Initialize the connection.\n\n        The configuration must be specified if and only if the following\n        parameters are None: connection_id, excluded_protocols or restricted_to_protocols.\n\n        :param configuration: the connection configuration.\n        :param data_dir: directory where to put local files.\n        :param identity: the identity object held by the agent.\n        :param crypto_store: the crypto store for encrypted communication.\n        :param restricted_to_protocols: the set of protocols ids of the only supported protocols for this connection.\n        :param excluded_protocols: the set of protocols ids that we want to exclude for this connection.\n        :param kwargs: keyword arguments passed to component base\n        \"\"\"\n        enforce(configuration is not None, \"The configuration must be provided.\")\n        super().__init__(configuration, **kwargs)\n        enforce(\n            super().public_id == self.connection_id,\n            \"Connection ids in configuration and class not matching.\",\n        )\n        self._state = AsyncState(ConnectionStates.disconnected)\n\n        self._identity = identity\n        self._crypto_store = crypto_store\n        self._data_dir = data_dir\n\n        self._restricted_to_protocols = (\n            restricted_to_protocols if restricted_to_protocols is not None else set()\n        )\n        self._excluded_protocols = (\n            excluded_protocols if excluded_protocols is not None else set()\n        )\n\n    @property\n    def loop(self) -> asyncio.AbstractEventLoop:\n        \"\"\"Get the event loop.\"\"\"\n        enforce(asyncio.get_event_loop().is_running(), \"Event loop is not running.\")\n        return asyncio.get_event_loop()\n\n    def _ensure_connected(self) -> None:  # pragma: nocover\n        \"\"\"Raise exception if connection is not connected.\"\"\"\n        if not self.is_connected:\n            raise ConnectionError(\"Connection is not connected! Connect first!\")\n\n    @staticmethod\n    def _ensure_valid_envelope_for_external_comms(envelope: \"Envelope\") -> None:\n        \"\"\"\n        Ensure the envelope sender and to are valid addresses for agent-to-agent communication.\n\n        :param envelope: the envelope\n        \"\"\"\n        enforce(\n            not envelope.is_sender_public_id and not envelope.is_to_public_id,\n            f\"Sender and to field of envelope is public id, needs to be address. Found: sender={envelope.sender}, to={envelope.to}\",\n        )\n\n    @contextmanager\n    def _connect_context(self) -> Generator:\n        \"\"\"Set state connecting, disconnecting, disconnected during connect method.\"\"\"\n        with self._state.transit(\n            initial=ConnectionStates.connecting,\n            success=ConnectionStates.connected,\n            fail=ConnectionStates.disconnected,\n        ):\n            yield\n\n    @property\n    def address(self) -> \"Address\":  # pragma: nocover\n        \"\"\"Get the address.\"\"\"\n        if self._identity is None:\n            raise ValueError(\n                \"You must provide the identity in order to retrieve the address.\"\n            )\n        return self._identity.address\n\n    @property\n    def crypto_store(self) -> CryptoStore:  # pragma: nocover\n        \"\"\"Get the crypto store.\"\"\"\n        if self._crypto_store is None:\n            raise ValueError(\"CryptoStore not available.\")\n        return self._crypto_store\n\n    @property\n    def has_crypto_store(self) -> bool:  # pragma: nocover\n        \"\"\"Check if the connection has the crypto store.\"\"\"\n        return self._crypto_store is not None\n\n    @property\n    def data_dir(self) -> str:  # pragma: nocover\n        \"\"\"Get the data directory.\"\"\"\n        return self._data_dir\n\n    @property\n    def component_type(self) -> ComponentType:  # pragma: nocover\n        \"\"\"Get the component type.\"\"\"\n        return ComponentType.CONNECTION\n\n    @property\n    def configuration(self) -> ConnectionConfig:\n        \"\"\"Get the connection configuration.\"\"\"\n        if self._configuration is None:  # pragma: nocover\n            raise ValueError(\"Configuration not set.\")\n        return cast(ConnectionConfig, super().configuration)\n\n    @property\n    def restricted_to_protocols(self) -> Set[PublicId]:  # pragma: nocover\n        \"\"\"Get the ids of the protocols this connection is restricted to.\"\"\"\n        if self._configuration is None:\n            return self._restricted_to_protocols\n        return self.configuration.restricted_to_protocols\n\n    @property\n    def excluded_protocols(self) -> Set[PublicId]:  # pragma: nocover\n        \"\"\"Get the ids of the excluded protocols for this connection.\"\"\"\n        if self._configuration is None:\n            return self._excluded_protocols\n        return self.configuration.excluded_protocols\n\n    @property\n    def state(self) -> ConnectionStates:\n        \"\"\"Get the connection status.\"\"\"\n        return self._state.get()\n\n    @state.setter\n    def state(self, value: ConnectionStates) -> None:\n        \"\"\"Set the connection status.\"\"\"\n        if not isinstance(value, ConnectionStates):\n            raise ValueError(f\"Incorrect state: `{value}`\")\n        self._state.set(value)\n\n    @abstractmethod\n    async def connect(self) -> None:\n        \"\"\"Set up the connection.\"\"\"\n\n    @abstractmethod\n    async def disconnect(self) -> None:\n        \"\"\"Tear down the connection.\"\"\"\n\n    @abstractmethod\n    async def send(self, envelope: \"Envelope\") -> None:\n        \"\"\"\n        Send an envelope.\n\n        :param envelope: the envelope to send.\n        :return: None\n        \"\"\"\n\n    @abstractmethod\n    async def receive(self, *args: Any, **kwargs: Any) -> Optional[\"Envelope\"]:\n        \"\"\"\n        Receive an envelope.\n\n        :param args: positional arguments\n        :param kwargs: keyword arguments\n        :return: the received envelope, or None if an error occurred.\n        \"\"\"\n\n    @classmethod\n    def from_dir(\n        cls,\n        directory: str,\n        identity: Identity,\n        crypto_store: CryptoStore,\n        data_dir: str,\n        **kwargs: Any,\n    ) -> \"Connection\":\n        \"\"\"\n        Load the connection from a directory.\n\n        :param directory: the directory to the connection package.\n        :param identity: the identity object.\n        :param crypto_store: object to access the connection crypto objects.\n        :param data_dir: the assets directory.\n        :param kwargs: keyword arguments passed to connection base\n        :return: the connection object.\n        \"\"\"\n        configuration = cast(\n            ConnectionConfig,\n            load_component_configuration(ComponentType.CONNECTION, Path(directory)),\n        )\n        configuration.directory = Path(directory)\n        return Connection.from_config(\n            configuration, identity, crypto_store, data_dir, **kwargs\n        )\n\n    @classmethod\n    def from_config(\n        cls,\n        configuration: ConnectionConfig,\n        identity: Identity,\n        crypto_store: CryptoStore,\n        data_dir: str,\n        **kwargs: Any,\n    ) -> \"Connection\":\n        \"\"\"\n        Load a connection from a configuration.\n\n        :param configuration: the connection configuration.\n        :param identity: the identity object.\n        :param crypto_store: object to access the connection crypto objects.\n        :param data_dir: the directory of the AEA project data.\n        :param kwargs: keyword arguments passed to component base\n        :return: an instance of the concrete connection class.\n        \"\"\"\n        configuration = cast(ConnectionConfig, configuration)\n        directory = cast(Path, configuration.directory)\n        connection_module_path = directory / \"connection.py\"\n        if not (connection_module_path.exists() and connection_module_path.is_file()):\n            raise AEAComponentLoadException(\n                \"Connection module '{}' not found.\".format(connection_module_path)\n            )\n        load_aea_package(configuration)\n        connection_module = load_module(\n            \"connection_module\", directory / \"connection.py\"\n        )\n        classes = inspect.getmembers(connection_module, inspect.isclass)\n        connection_class_name = cast(str, configuration.class_name)\n        connection_classes = list(\n            filter(lambda x: re.match(connection_class_name, x[0]), classes)\n        )\n        name_to_class = dict(connection_classes)\n        logger = get_logger(__name__, identity.name)\n        logger.debug(\"Processing connection {}\".format(connection_class_name))\n        connection_class = name_to_class.get(connection_class_name, None)\n        if connection_class is None:\n            raise AEAComponentLoadException(\n                \"Connection class '{}' not found.\".format(connection_class_name)\n            )\n        try:\n            connection = connection_class(\n                configuration=configuration,\n                data_dir=data_dir,\n                identity=identity,\n                crypto_store=crypto_store,\n                **kwargs,\n            )\n        except Exception as e:  # pragma: nocover # pylint: disable=broad-except\n            e_str = parse_exception(e)\n            raise AEAInstantiationException(\n                f\"An error occurred during instantiation of connection {configuration.public_id}/{configuration.class_name}:\\n{e_str}\"\n            )\n        return connection\n\n    @property\n    def is_connected(self) -> bool:  # pragma: nocover\n        \"\"\"Return is connected state.\"\"\"\n        return self.state == ConnectionStates.connected\n\n    @property\n    def is_connecting(self) -> bool:  # pragma: nocover\n        \"\"\"Return is connecting state.\"\"\"\n        return self.state == ConnectionStates.connecting\n\n    @property\n    def is_disconnected(self) -> bool:  # pragma: nocover\n        \"\"\"Return is disconnected state.\"\"\"\n        return self.state == ConnectionStates.disconnected\n\n\nclass BaseSyncConnection(Connection):\n    \"\"\"Base sync connection class to write connections with sync code.\"\"\"\n\n    MAX_WORKER_THREADS = 5\n\n    _executor_pool: ThreadPoolExecutor\n    _incoming_messages_queue: asyncio.Queue  # [Optional[Envelope]]\n    _loop: asyncio.AbstractEventLoop\n\n    def __init__(\n        self,\n        configuration: ConnectionConfig,\n        data_dir: str,\n        identity: Optional[Identity] = None,\n        crypto_store: Optional[CryptoStore] = None,\n        restricted_to_protocols: Optional[Set[PublicId]] = None,\n        excluded_protocols: Optional[Set[PublicId]] = None,\n        **kwargs: Any,\n    ) -> None:\n        \"\"\"\n        Initialize the connection.\n\n        The configuration must be specified if and only if the following\n        parameters are None: connection_id, excluded_protocols or restricted_to_protocols.\n\n        :param configuration: the connection configuration.\n        :param data_dir: directory where to put local files.\n        :param identity: the identity object held by the agent.\n        :param crypto_store: the crypto store for encrypted communication.\n        :param restricted_to_protocols: the set of protocols ids of the only supported protocols for this connection.\n        :param excluded_protocols: the set of protocols ids that we want to exclude for this connection.\n        :param kwargs: keyword arguments passed to connection base\n        \"\"\"\n        super().__init__(\n            configuration=configuration,\n            data_dir=data_dir,\n            identity=identity,\n            crypto_store=crypto_store,\n            restricted_to_protocols=restricted_to_protocols,\n            excluded_protocols=excluded_protocols,\n            **kwargs,\n        )\n\n        self._tasks: Set[asyncio.Task] = set()\n\n    def _set_executor_pool(self, max_workers: Optional[int] = None) -> None:\n        \"\"\"Set executors pool.\"\"\"\n        max_workers = self.configuration.config.get(\n            \"max_thread_workers\", self.MAX_WORKER_THREADS\n        )\n        thread_name_prefix = f\"conn:{self.connection_id}:\"\n        self._executor_pool = ThreadPoolExecutor(\n            max_workers=max_workers, thread_name_prefix=thread_name_prefix\n        )\n\n    def _task_done_callback(self, task: asyncio.Task) -> None:\n        \"\"\"Remove task on done, log error if happened.\"\"\"\n        self._tasks.remove(task)\n        if task.exception():\n            # cause task.get_name for python3.8+\n            task_name = getattr(task, \"task_name\", \"TASK NAME NOT SET\")\n            self.logger.exception(\n                f\"in task `{task_name}`, exception occurred\",\n                exc_info=task.exception(),\n            )\n\n    async def _run_in_pool(self, fn: Callable, *args: Any) -> Any:\n        \"\"\"Run sync function in threaded executor pool.\"\"\"\n        return await self._loop.run_in_executor(self._executor_pool, fn, *args)\n\n    def put_envelope(self, envelope: Optional[\"Envelope\"]) -> None:\n        \"\"\"Put envelope in to the incoming queue.\"\"\"\n        self._ensure_connected()\n        self._loop.call_soon_threadsafe(\n            self._incoming_messages_queue.put_nowait, envelope\n        )\n\n    async def connect(self) -> None:\n        \"\"\"Connect connection.\"\"\"\n        with self._connect_context():\n            self._loop = asyncio.get_event_loop()\n            self._incoming_messages_queue = asyncio.Queue()\n            self._set_executor_pool()\n            await self._run_in_pool(self.on_connect)\n        self.start_main()\n\n    async def disconnect(self) -> None:\n        \"\"\"Disconnect connection.\"\"\"\n        self._ensure_connected()\n        with self._state.transit(\n            initial=ConnectionStates.disconnecting,\n            success=ConnectionStates.disconnected,\n            fail=ConnectionStates.disconnected,\n        ):\n            if self._tasks:\n                await asyncio.wait(self._tasks)\n            await self._run_in_pool(self.on_disconnect)\n            self._executor_pool.shutdown(wait=False)\n\n    async def send(self, envelope: \"Envelope\") -> None:\n        \"\"\"Send envelope to connection.\"\"\"\n        self._ensure_connected()\n        task = self._loop.create_task(self._run_in_pool(self._send_wrapper, envelope))\n        # cause task.set_name for python3.8+\n        setattr(task, \"task_name\", f\"On send({envelope})\")  # noqa\n        task.add_done_callback(self._task_done_callback)\n        self._tasks.add(task)\n\n    def _send_wrapper(self, *args: Any) -> None:\n        \"\"\"Check is connected and call on_send method.\"\"\"\n        self._ensure_connected()\n        self.on_send(*args)\n\n    async def receive(self, *args: Any, **kwargs: Any) -> Optional[\"Envelope\"]:\n        \"\"\"Get an envelope from the connection.\"\"\"\n        self._ensure_connected()\n        return await self._incoming_messages_queue.get()\n\n    def start_main(self) -> None:\n        \"\"\"Start main function of the connection.\"\"\"\n\n        def _() -> None:\n            task = self._loop.create_task(self._run_in_pool(self.main))\n            # cause task.set_name for python3.8+\n            setattr(task, \"task_name\", \"Connection main\")  # noqa\n            task.add_done_callback(self._task_done_callback)\n            self._tasks.add(task)\n\n        self._loop.call_soon_threadsafe(_)\n\n    def main(self) -> None:\n        \"\"\"Run main body of the connection in dedicated thread.\"\"\"\n\n    @abstractmethod\n    def on_connect(self) -> None:\n        \"\"\"Run on connect method called.\"\"\"\n\n    @abstractmethod\n    def on_disconnect(self) -> None:\n        \"\"\"Run on disconnect method called.\"\"\"\n\n    @abstractmethod\n    def on_send(self, envelope: \"Envelope\") -> None:\n        \"\"\"Run on send method called.\"\"\"\n"
  },
  {
    "path": "aea/connections/scaffold/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Scaffold of a connection.\"\"\"\n"
  },
  {
    "path": "aea/connections/scaffold/connection.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Scaffold connection and channel.\"\"\"\nfrom typing import Any, Optional\n\nfrom aea.configurations.base import PublicId\nfrom aea.connections.base import BaseSyncConnection, Connection\nfrom aea.mail.base import Envelope\n\n\n\"\"\"\nChoose one of the possible implementations:\n\nSync (inherited from BaseSyncConnection) or Async (inherited from Connection) connection and remove unused one.\n\"\"\"\n\nCONNECTION_ID = PublicId.from_str(\"fetchai/scaffold:0.1.0\")\n\n\nclass MyScaffoldAsyncConnection(Connection):\n    \"\"\"Proxy to the functionality of the SDK or API.\"\"\"\n\n    connection_id = CONNECTION_ID\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize the connection.\n\n        The configuration must be specified if and only if the following\n        parameters are None: connection_id, excluded_protocols or restricted_to_protocols.\n\n        Possible keyword arguments:\n        - configuration: the connection configuration.\n        - data_dir: directory where to put local files.\n        - identity: the identity object held by the agent.\n        - crypto_store: the crypto store for encrypted communication.\n        - restricted_to_protocols: the set of protocols ids of the only supported protocols for this connection.\n        - excluded_protocols: the set of protocols ids that we want to exclude for this connection.\n\n        :param kwargs: keyword arguments passed to component base\n        \"\"\"\n        super().__init__(**kwargs)  # pragma: no cover\n\n    async def connect(self) -> None:\n        \"\"\"\n        Set up the connection.\n\n        In the implementation, remember to update 'connection_status' accordingly.\n        \"\"\"\n        raise NotImplementedError  # pragma: no cover\n\n    async def disconnect(self) -> None:\n        \"\"\"\n        Tear down the connection.\n\n        In the implementation, remember to update 'connection_status' accordingly.\n        \"\"\"\n        raise NotImplementedError  # pragma: no cover\n\n    async def send(self, envelope: Envelope) -> None:\n        \"\"\"\n        Send an envelope.\n\n        :param envelope: the envelope to send.\n        \"\"\"\n        raise NotImplementedError  # pragma: no cover\n\n    async def receive(self, *args: Any, **kwargs: Any) -> Optional[Envelope]:\n        \"\"\"\n        Receive an envelope. Blocking.\n\n        :param args: arguments to receive\n        :param kwargs: keyword arguments to receive\n        :return: the envelope received, if present.  # noqa: DAR202\n        \"\"\"\n        raise NotImplementedError  # pragma: no cover\n\n\nclass MyScaffoldSyncConnection(BaseSyncConnection):\n    \"\"\"Proxy to the functionality of the SDK or API.\"\"\"\n\n    MAX_WORKER_THREADS = 5\n\n    connection_id = CONNECTION_ID\n\n    def __init__(self, *args: Any, **kwargs: Any) -> None:  # pragma: no cover\n        \"\"\"\n        Initialize the connection.\n\n        The configuration must be specified if and only if the following\n        parameters are None: connection_id, excluded_protocols or restricted_to_protocols.\n\n        Possible arguments:\n        - configuration: the connection configuration.\n        - data_dir: directory where to put local files.\n        - identity: the identity object held by the agent.\n        - crypto_store: the crypto store for encrypted communication.\n        - restricted_to_protocols: the set of protocols ids of the only supported protocols for this connection.\n        - excluded_protocols: the set of protocols ids that we want to exclude for this connection.\n\n        :param args: arguments passed to component base\n        :param kwargs: keyword arguments passed to component base\n        \"\"\"\n        super().__init__(*args, **kwargs)\n        raise NotImplementedError\n\n    def main(self) -> None:\n        \"\"\"\n        Run synchronous code in background.\n\n        SyncConnection `main()` usage:\n        The idea of the `main` method in the sync connection\n        is to provide for a way to actively generate messages by the connection via the `put_envelope` method.\n\n        A simple example is the generation of a message every second:\n        ```\n        while self.is_connected:\n            envelope = make_envelope_for_current_time()\n            self.put_enevelope(envelope)\n            time.sleep(1)\n        ```\n        In this case, the connection will generate a message every second\n        regardless of envelopes sent to the connection by the agent.\n        For instance, this way one can implement periodically polling some internet resources\n        and generate envelopes for the agent if some updates are available.\n        Another example is the case where there is some framework that runs blocking\n        code and provides a callback on some internal event.\n        This blocking code can be executed in the main function and new envelops\n        can be created in the event callback.\n        \"\"\"\n        raise NotImplementedError  # pragma: no cover\n\n    def on_send(self, envelope: Envelope) -> None:\n        \"\"\"\n        Send an envelope.\n\n        :param envelope: the envelope to send.\n        \"\"\"\n        raise NotImplementedError  # pragma: no cover\n\n    def on_connect(self) -> None:\n        \"\"\"\n        Tear down the connection.\n\n        Connection status set automatically.\n        \"\"\"\n        raise NotImplementedError  # pragma: no cover\n\n    def on_disconnect(self) -> None:\n        \"\"\"\n        Tear down the connection.\n\n        Connection status set automatically.\n        \"\"\"\n        raise NotImplementedError  # pragma: no cover\n"
  },
  {
    "path": "aea/connections/scaffold/connection.yaml",
    "content": "name: scaffold\nauthor: fetchai\nversion: 0.1.0\ntype: connection\ndescription: The scaffold connection provides a scaffold for a connection to be implemented\n  by the developer.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  __init__.py: QmaA7o9G1hT3fHtPDq6UYUyS5KY51uDkwMUGUc96odzSCX\n  connection.py: QmWUqCmfD65KqnGjk2XWLDN3KAU32nC6uYgGCvjmSLWi7D\n  readme.md: QmRFgpKrtPPTJSAEaXoNNKcYFiTAhVFKuiNZdjrjmAw8d1\nfingerprint_ignore_patterns: []\nconnections: []\nprotocols: []\nclass_name: MyScaffoldAsyncConnection\nconfig:\n  foo: bar\nexcluded_protocols: []\nrestricted_to_protocols: []\ndependencies: {}\nis_abstract: false\ncert_requests: []\n"
  },
  {
    "path": "aea/connections/scaffold/readme.md",
    "content": "# Scaffold connection\n\nThe scaffold connection acts as a boilerplate for a newly created connection.\n\n## Usage\n\nCreate a scaffold connection with the `aea scaffold connection {NAME}` command and implement your own connection.\n"
  },
  {
    "path": "aea/context/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the context modules.\"\"\"\n"
  },
  {
    "path": "aea/context/base.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the agent context class.\"\"\"\nfrom queue import Queue\nfrom types import SimpleNamespace\nfrom typing import Any, Callable, Dict, Optional, Union\n\nfrom aea.common import Address\nfrom aea.configurations.base import PublicId\nfrom aea.helpers.storage.generic_storage import Storage\nfrom aea.identity.base import Identity\nfrom aea.mail.base import Envelope, EnvelopeContext\nfrom aea.multiplexer import MultiplexerStatus, OutBox\nfrom aea.protocols.base import Message\nfrom aea.skills.tasks import TaskManager\n\n\nclass AgentContext:\n    \"\"\"Provide read access to relevant objects of the agent for the skills.\"\"\"\n\n    __slots__ = (\n        \"_shared_state\",\n        \"_identity\",\n        \"_connection_status\",\n        \"_outbox\",\n        \"_decision_maker_message_queue\",\n        \"_decision_maker_handler_context\",\n        \"_task_manager\",\n        \"_search_service_address\",\n        \"_decision_maker_address\",\n        \"_default_ledger_id\",\n        \"_currency_denominations\",\n        \"_default_connection\",\n        \"_default_routing\",\n        \"_storage_callable\",\n        \"_data_dir\",\n        \"_namespace\",\n        \"_send_to_skill\",\n    )\n\n    def __init__(\n        self,\n        identity: Identity,\n        connection_status: MultiplexerStatus,\n        outbox: OutBox,\n        decision_maker_message_queue: Queue,\n        decision_maker_handler_context: SimpleNamespace,\n        task_manager: TaskManager,\n        default_ledger_id: str,\n        currency_denominations: Dict[str, str],\n        default_connection: Optional[PublicId],\n        default_routing: Dict[PublicId, PublicId],\n        search_service_address: Address,\n        decision_maker_address: Address,\n        data_dir: str,\n        storage_callable: Callable[[], Optional[Storage]] = lambda: None,\n        send_to_skill: Optional[Callable] = None,\n        **kwargs: Any,\n    ) -> None:\n        \"\"\"\n        Initialize an agent context.\n\n        :param identity: the identity object\n        :param connection_status: the connection status of the multiplexer\n        :param outbox: the outbox\n        :param decision_maker_message_queue: the (in) queue of the decision maker\n        :param decision_maker_handler_context: the decision maker's name space\n        :param task_manager: the task manager\n        :param default_ledger_id: the default ledger id\n        :param currency_denominations: mapping from ledger ids to currency denominations\n        :param default_connection: the default connection\n        :param default_routing: the default routing\n        :param search_service_address: the address of the search service\n        :param decision_maker_address: the address of the decision maker\n        :param data_dir: directory where to put local files.\n        :param storage_callable: function that returns optional storage attached to agent.\n        :param send_to_skill: callable for sending envelopes to skills.\n        :param kwargs: keyword arguments to be attached in the agent context namespace.\n        \"\"\"\n        self._shared_state = {}  # type: Dict[str, Any]\n        self._identity = identity\n        self._connection_status = connection_status\n        self._outbox = outbox\n        self._decision_maker_message_queue = decision_maker_message_queue\n        self._decision_maker_handler_context = decision_maker_handler_context\n        self._task_manager = task_manager\n        self._search_service_address = search_service_address\n        self._decision_maker_address = decision_maker_address\n        self._default_ledger_id = default_ledger_id\n        self._currency_denominations = currency_denominations\n        self._default_connection = default_connection\n        self._default_routing = default_routing\n        self._storage_callable = storage_callable\n        self._data_dir = data_dir\n        self._namespace = SimpleNamespace(**kwargs)\n        self._send_to_skill = send_to_skill\n\n    def send_to_skill(\n        self,\n        message_or_envelope: Union[Message, Envelope],\n        context: Optional[EnvelopeContext] = None,\n    ) -> None:\n        \"\"\"\n        Send message or envelope to another skill.\n\n        If message passed it will be wrapped into envelope with optional envelope context.\n\n        :param message_or_envelope: envelope to send to another skill.\n        :param context: the optional envelope context\n        \"\"\"\n        if self._send_to_skill is None:  # pragma: nocover\n            raise ValueError(\"Send to skill feature is not supported\")\n        self._send_to_skill(message_or_envelope, context)\n\n    @property\n    def storage(self) -> Optional[Storage]:\n        \"\"\"Return storage instance if enabled in AEA.\"\"\"\n        return self._storage_callable()\n\n    @property\n    def data_dir(self) -> str:\n        \"\"\"Return assets directory.\"\"\"\n        return self._data_dir\n\n    @property\n    def shared_state(self) -> Dict[str, Any]:\n        \"\"\"\n        Get the shared state dictionary.\n\n        The shared state is the only object which skills can use\n        to exchange state directly. It is accessible (read and write) from\n        all skills.\n\n        :return: dictionary of the shared state.\n        \"\"\"\n        return self._shared_state\n\n    @property\n    def identity(self) -> Identity:\n        \"\"\"Get the identity.\"\"\"\n        return self._identity\n\n    @property\n    def agent_name(self) -> str:\n        \"\"\"Get agent name.\"\"\"\n        return self.identity.name\n\n    @property\n    def addresses(self) -> Dict[str, Address]:\n        \"\"\"Get addresses.\"\"\"\n        return self.identity.addresses\n\n    @property\n    def public_keys(self) -> Dict[str, str]:\n        \"\"\"Get public keys.\"\"\"\n        return self.identity.public_keys\n\n    @property\n    def address(self) -> Address:\n        \"\"\"Get the default address.\"\"\"\n        return self.identity.address\n\n    @property\n    def public_key(self) -> str:\n        \"\"\"Get the default public key.\"\"\"\n        return self.identity.public_key\n\n    @property\n    def connection_status(self) -> MultiplexerStatus:\n        \"\"\"Get connection status of the multiplexer.\"\"\"\n        return self._connection_status\n\n    @property\n    def outbox(self) -> OutBox:\n        \"\"\"Get outbox.\"\"\"\n        return self._outbox\n\n    @property\n    def decision_maker_message_queue(self) -> Queue:\n        \"\"\"Get decision maker queue.\"\"\"\n        return self._decision_maker_message_queue\n\n    @property\n    def decision_maker_handler_context(self) -> SimpleNamespace:\n        \"\"\"Get the decision maker handler context.\"\"\"\n        return self._decision_maker_handler_context\n\n    @property\n    def task_manager(self) -> TaskManager:\n        \"\"\"Get the task manager.\"\"\"\n        return self._task_manager\n\n    @property\n    def search_service_address(self) -> Address:\n        \"\"\"Get the address of the search service.\"\"\"\n        return self._search_service_address\n\n    @property\n    def decision_maker_address(self) -> Address:\n        \"\"\"Get the address of the decision maker.\"\"\"\n        return self._decision_maker_address\n\n    @property\n    def default_ledger_id(self) -> str:\n        \"\"\"Get the default ledger id.\"\"\"\n        return self._default_ledger_id\n\n    @property\n    def currency_denominations(self) -> Dict[str, str]:\n        \"\"\"Get a dictionary mapping ledger ids to currency denominations.\"\"\"\n        return self._currency_denominations\n\n    @property\n    def default_connection(self) -> Optional[PublicId]:\n        \"\"\"Get the default connection.\"\"\"\n        return self._default_connection\n\n    @property\n    def default_routing(self) -> Dict[PublicId, PublicId]:\n        \"\"\"Get the default routing.\"\"\"\n        return self._default_routing\n\n    @property\n    def namespace(self) -> SimpleNamespace:\n        \"\"\"Get the agent context namespace.\"\"\"\n        return self._namespace\n"
  },
  {
    "path": "aea/contracts/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the contract modules.\"\"\"\n\nfrom aea.contracts.base import Contract, contract_registry  # noqa: F401\n"
  },
  {
    "path": "aea/contracts/base.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"The base contract.\"\"\"\nimport inspect\nimport logging\nimport re\nfrom pathlib import Path\nfrom typing import Any, Dict, Optional, cast\n\nfrom aea.common import JSONLike\nfrom aea.components.base import Component, load_aea_package\nfrom aea.configurations.base import ComponentType, ContractConfig, PublicId\nfrom aea.configurations.constants import CONTRACTS\nfrom aea.configurations.loader import load_component_configuration\nfrom aea.crypto.base import LedgerApi\nfrom aea.crypto.registries import Registry, ledger_apis_registry, make_ledger_api_cls\nfrom aea.exceptions import AEAComponentLoadException, AEAException\nfrom aea.helpers.base import load_module\n\n\ncontract_registry: Registry[\"Contract\"] = Registry[\"Contract\"]()\n_default_logger = logging.getLogger(__name__)\n\n\nclass Contract(Component):\n    \"\"\"Abstract definition of a contract.\"\"\"\n\n    contract_id = None  # type: PublicId\n    contract_interface: Any = None\n\n    def __init__(self, contract_config: ContractConfig, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize the contract.\n\n        :param contract_config: the contract configurations.\n        :param kwargs: the keyword arguments.\n        \"\"\"\n        super().__init__(contract_config, **kwargs)\n\n    @property\n    def id(self) -> PublicId:\n        \"\"\"Get the name.\"\"\"\n        return self.public_id\n\n    @property\n    def configuration(self) -> ContractConfig:\n        \"\"\"Get the configuration.\"\"\"\n        if self._configuration is None:  # pragma: nocover\n            raise ValueError(\"Configuration not set.\")\n        return cast(ContractConfig, super().configuration)\n\n    @classmethod\n    def get_instance(\n        cls, ledger_api: LedgerApi, contract_address: Optional[str] = None\n    ) -> Any:\n        \"\"\"\n        Get the instance.\n\n        :param ledger_api: the ledger api we are using.\n        :param contract_address: the contract address.\n        :return: the contract instance\n        \"\"\"\n        contract_interface = cls.contract_interface.get(ledger_api.identifier, {})\n        instance = ledger_api.get_contract_instance(\n            contract_interface, contract_address\n        )\n        return instance\n\n    @classmethod\n    def from_dir(cls, directory: str, **kwargs: Any) -> \"Contract\":\n        \"\"\"\n        Load the protocol from a directory.\n\n        :param directory: the directory to the skill package.\n        :param kwargs: the keyword arguments.\n        :return: the contract object.\n        \"\"\"\n        configuration = cast(\n            ContractConfig,\n            load_component_configuration(ComponentType.CONTRACT, Path(directory)),\n        )\n        configuration.directory = Path(directory)\n        return Contract.from_config(configuration, **kwargs)\n\n    @classmethod\n    def from_config(cls, configuration: ContractConfig, **kwargs: Any) -> \"Contract\":\n        \"\"\"\n        Load contract from configuration.\n\n        :param configuration: the contract configuration.\n        :param kwargs: the keyword arguments.\n        :return: the contract object.\n        \"\"\"\n        if configuration.directory is None:  # pragma: nocover\n            raise ValueError(\"Configuration must be associated with a directory.\")\n        directory = configuration.directory\n        load_aea_package(configuration)\n        contract_module = load_module(CONTRACTS, directory / \"contract.py\")\n        classes = inspect.getmembers(contract_module, inspect.isclass)\n        contract_class_name = cast(str, configuration.class_name)\n        contract_classes = list(\n            filter(lambda x: re.match(contract_class_name, x[0]), classes)\n        )\n        name_to_class = dict(contract_classes)\n        _default_logger.debug(f\"Processing contract {contract_class_name}\")\n        contract_class = name_to_class.get(contract_class_name, None)\n        if contract_class is None:\n            raise AEAComponentLoadException(\n                f\"Contract class '{contract_class_name}' not found.\"\n            )\n\n        _try_to_register_contract(configuration)\n        contract = contract_registry.make(str(configuration.public_id), **kwargs)\n        return contract\n\n    @classmethod\n    def get_deploy_transaction(\n        cls, ledger_api: LedgerApi, deployer_address: str, **kwargs: Any\n    ) -> Optional[JSONLike]:\n        \"\"\"\n        Handler method for the 'GET_DEPLOY_TRANSACTION' requests.\n\n        Implement this method in the sub class if you want\n        to handle the contract requests manually.\n\n        :param ledger_api: the ledger apis.\n        :param deployer_address: The address that will deploy the contract.\n        :param kwargs: keyword arguments.\n        :return: the tx\n        \"\"\"\n        contract_interface = cls.contract_interface.get(ledger_api.identifier, {})\n        tx = ledger_api.get_deploy_transaction(\n            contract_interface, deployer_address, **kwargs\n        )\n        return tx\n\n    @classmethod\n    def get_raw_transaction(\n        cls, ledger_api: LedgerApi, contract_address: str, **kwargs: Any\n    ) -> Optional[JSONLike]:\n        \"\"\"\n        Handler method for the 'GET_RAW_TRANSACTION' requests.\n\n        Implement this method in the sub class if you want\n        to handle the contract requests manually.\n\n        :param ledger_api: the ledger apis.\n        :param contract_address: the contract address.\n        :param kwargs: the keyword arguments.\n        :return: the tx  # noqa: DAR202\n        \"\"\"\n        raise NotImplementedError\n\n    @classmethod\n    def get_raw_message(\n        cls, ledger_api: LedgerApi, contract_address: str, **kwargs: Any\n    ) -> Optional[bytes]:\n        \"\"\"\n        Handler method for the 'GET_RAW_MESSAGE' requests.\n\n        Implement this method in the sub class if you want\n        to handle the contract requests manually.\n\n        :param ledger_api: the ledger apis.\n        :param contract_address: the contract address.\n        :param kwargs: the keyword arguments.\n        :return: the tx  # noqa: DAR202\n        \"\"\"\n        raise NotImplementedError\n\n    @classmethod\n    def get_state(\n        cls, ledger_api: LedgerApi, contract_address: str, **kwargs: Any\n    ) -> Optional[JSONLike]:\n        \"\"\"\n        Handler method for the 'GET_STATE' requests.\n\n        Implement this method in the sub class if you want\n        to handle the contract requests manually.\n\n        :param ledger_api: the ledger apis.\n        :param contract_address: the contract address.\n        :param kwargs: the keyword arguments.\n        :return: the tx  # noqa: DAR202\n        \"\"\"\n        raise NotImplementedError\n\n\ndef _try_to_register_contract(configuration: ContractConfig) -> None:\n    \"\"\"Register a contract to the registry.\"\"\"\n    if str(configuration.public_id) in contract_registry.specs:  # pragma: nocover\n        _default_logger.warning(\n            f\"Skipping registration of contract {configuration.public_id} since already registered.\"\n        )\n        return\n    _default_logger.debug(\n        f\"Registering contract {configuration.public_id}\"\n    )  # pragma: nocover\n    contract_interfaces = _load_contract_interfaces(configuration)\n    try:  # pragma: nocover\n        contract_registry.register(\n            id_=str(configuration.public_id),\n            entry_point=f\"{configuration.prefix_import_path}.contract:{configuration.class_name}\",\n            class_kwargs={\"contract_interface\": contract_interfaces},\n            contract_config=configuration,\n        )\n    except AEAException as e:  # pragma: nocover\n        if \"Cannot re-register id:\" in str(e):\n            _default_logger.warning(\n                \"Already registered: {}\".format(configuration.class_name)\n            )\n        else:\n            raise e\n\n\ndef _load_contract_interfaces(\n    configuration: ContractConfig,\n) -> Dict[str, Dict[str, str]]:\n    \"\"\"Get the contract interfaces.\"\"\"\n    if configuration.directory is None:  # pragma: nocover\n        raise ValueError(\"Set contract configuration directory before calling.\")\n    contract_interfaces = {}  # type: Dict[str, Dict[str, str]]\n    for identifier, path in configuration.contract_interface_paths.items():\n        full_path = Path(configuration.directory, path)\n        if identifier not in ledger_apis_registry.supported_ids:\n            raise ValueError(  # pragma: nocover\n                f\"No ledger api registered for identifier {identifier}.\"\n            )\n        ledger_api = make_ledger_api_cls(identifier)\n        contract_interface = ledger_api.load_contract_interface(full_path)\n        contract_interfaces[identifier] = contract_interface\n    return contract_interfaces\n"
  },
  {
    "path": "aea/contracts/scaffold/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the support resources for the scaffold contract.\"\"\"\n"
  },
  {
    "path": "aea/contracts/scaffold/contract.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the scaffold contract definition.\"\"\"\n\nfrom typing import Any\n\nfrom aea.common import JSONLike\nfrom aea.configurations.base import PublicId\nfrom aea.contracts.base import Contract\nfrom aea.crypto.base import LedgerApi\n\n\nclass MyScaffoldContract(Contract):\n    \"\"\"The scaffold contract class for a smart contract.\"\"\"\n\n    contract_id = PublicId.from_str(\"fetchai/scaffold:0.1.0\")\n\n    @classmethod\n    def get_raw_transaction(\n        cls, ledger_api: LedgerApi, contract_address: str, **kwargs: Any\n    ) -> JSONLike:\n        \"\"\"\n        Handler method for the 'GET_RAW_TRANSACTION' requests.\n\n        Implement this method in the sub class if you want\n        to handle the contract requests manually.\n\n        :param ledger_api: the ledger apis.\n        :param contract_address: the contract address.\n        :param kwargs: the keyword arguments.\n        :return: the tx  # noqa: DAR202\n        \"\"\"\n        raise NotImplementedError\n\n    @classmethod\n    def get_raw_message(\n        cls, ledger_api: LedgerApi, contract_address: str, **kwargs: Any\n    ) -> bytes:\n        \"\"\"\n        Handler method for the 'GET_RAW_MESSAGE' requests.\n\n        Implement this method in the sub class if you want\n        to handle the contract requests manually.\n\n        :param ledger_api: the ledger apis.\n        :param contract_address: the contract address.\n        :param kwargs: the keyword arguments.\n        :return: the tx  # noqa: DAR202\n        \"\"\"\n        raise NotImplementedError\n\n    @classmethod\n    def get_state(\n        cls, ledger_api: LedgerApi, contract_address: str, **kwargs: Any\n    ) -> JSONLike:\n        \"\"\"\n        Handler method for the 'GET_STATE' requests.\n\n        Implement this method in the sub class if you want\n        to handle the contract requests manually.\n\n        :param ledger_api: the ledger apis.\n        :param contract_address: the contract address.\n        :param kwargs: the keyword arguments.\n        :return: the tx  # noqa: DAR202\n        \"\"\"\n        raise NotImplementedError\n"
  },
  {
    "path": "aea/contracts/scaffold/contract.yaml",
    "content": "name: scaffold\nauthor: fetchai\nversion: 0.1.0\ntype: contract\ndescription: The scaffold contract scaffolds a contract to be implemented by the developer.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  __init__.py: QmbqCg6ZKdTA5kLdmaMKpLtuTDhkwNZTSfyH9c8AUA2GCy\n  contract.py: QmUvREspzKHP81G3u5xgu98dz4a1J8vGYL4xjrf2kv9nGB\nfingerprint_ignore_patterns: []\nclass_name: MyScaffoldContract\ncontract_interface_paths: {}\ndependencies: {}\n"
  },
  {
    "path": "aea/crypto/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the crypto modules.\"\"\"\n\nfrom aea.crypto.registries import (  # noqa\n    register_crypto,\n    register_faucet_api,\n    register_ledger_api,\n)\n"
  },
  {
    "path": "aea/crypto/base.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Abstract module wrapping the public and private key cryptography and ledger api.\"\"\"\n\nfrom abc import ABC, abstractmethod\nfrom pathlib import Path\nfrom typing import Any, Dict, Generic, Optional, Tuple, TypeVar\n\nfrom aea.common import Address, JSONLike\nfrom aea.helpers.io import open_file\n\n\nEntityClass = TypeVar(\"EntityClass\")\n\n\nclass Crypto(Generic[EntityClass], ABC):\n    \"\"\"Base class for a crypto object.\"\"\"\n\n    identifier = \"base\"\n\n    def __init__(\n        self,\n        private_key_path: Optional[str] = None,\n        password: Optional[str] = None,\n        **kwargs: Any,\n    ) -> None:  # pylint: disable=unused-argument\n        \"\"\"\n        Initialize the crypto object.\n\n        The actual behaviour of this constructor is determined by the abstract\n        methods 'generate_private_key()' and 'load_private_key_from_path().\n        Either way, the entity object will be accessible as a property.\n\n        :param private_key_path: the path to the private key.\n                If None, the key will be generated by 'generate_private_key()'.\n                If not None, the path will be processed by 'load_private_key_from_path()'.\n        :param password: the password to encrypt/decrypt the private key.\n        :param kwargs: keyword arguments.\n        \"\"\"\n        self._kwargs = kwargs\n        self._entity = (\n            self.generate_private_key()\n            if private_key_path is None\n            else self.load_private_key_from_path(private_key_path, password)\n        )\n\n    @classmethod\n    @abstractmethod\n    def generate_private_key(cls) -> EntityClass:\n        \"\"\"\n        Generate a private key.\n\n        :return: the entity object. Implementation dependent.\n        \"\"\"\n\n    @classmethod\n    @abstractmethod\n    def load_private_key_from_path(\n        cls, file_name: str, password: Optional[str] = None\n    ) -> EntityClass:\n        \"\"\"\n        Load a private key in hex format for raw private key and json format for encrypted private key from a file.\n\n        :param file_name: the path to the hex/json file.\n        :param password: the password to encrypt/decrypt the private key.\n        :return: the entity object.\n        \"\"\"\n\n    @property\n    def entity(self) -> EntityClass:\n        \"\"\"\n        Return an entity object.\n\n        :return: an entity object\n        \"\"\"\n        return self._entity\n\n    @property\n    @abstractmethod\n    def private_key(self) -> str:\n        \"\"\"\n        Return a private key.\n\n        :return: a private key string\n        \"\"\"\n\n    @property\n    @abstractmethod\n    def public_key(self) -> str:\n        \"\"\"\n        Return a public key.\n\n        :return: a public key string\n        \"\"\"\n\n    @property\n    @abstractmethod\n    def address(self) -> str:\n        \"\"\"\n        Return the address.\n\n        :return: an address string\n        \"\"\"\n\n    @abstractmethod\n    def sign_message(self, message: bytes, is_deprecated_mode: bool = False) -> str:\n        \"\"\"\n        Sign a message in bytes string form.\n\n        :param message: the message to be signed\n        :param is_deprecated_mode: if the deprecated signing is used\n        :return: signature of the message in string form\n        \"\"\"\n\n    @abstractmethod\n    def sign_transaction(self, transaction: JSONLike) -> JSONLike:\n        \"\"\"\n        Sign a transaction in dict form.\n\n        :param transaction: the transaction to be signed\n        :return: signed transaction\n        \"\"\"\n\n    @classmethod\n    def load(cls, private_key_file: str, password: Optional[str] = None) -> str:\n        \"\"\"\n        Load private key from file.\n\n        :param private_key_file: the file where the key is stored.\n        :param password: the password to encrypt/decrypt the private key.\n        :return: private_key in hex string format\n        \"\"\"\n        path = Path(private_key_file)\n        with open_file(path, \"r\") as key_file:\n            data = key_file.read()\n        if password is None:\n            result = data\n        else:\n            result = cls.decrypt(data, password)\n        return result\n\n    def dump(self, private_key_file: str, password: Optional[str] = None) -> None:\n        \"\"\"\n        Dump private key to file.\n\n        :param private_key_file: the file where the key is stored.\n        :param password: the password to encrypt/decrypt the private key.\n        \"\"\"\n        if password is None:\n            with open(private_key_file, \"wb\") as fpb:\n                fpb.write(self.private_key.encode(\"utf-8\"))\n        else:\n            with open_file(private_key_file, \"w\") as fp:\n                encrypted = self.encrypt(password)\n                fp.write(encrypted)\n\n    @abstractmethod\n    def encrypt(self, password: str) -> str:\n        \"\"\"\n        Encrypt the private key and return in json.\n\n        :param password: the password to decrypt.\n        :return: json string containing encrypted private key.\n        \"\"\"\n\n    @classmethod\n    @abstractmethod\n    def decrypt(cls, keyfile_json: str, password: str) -> str:\n        \"\"\"\n        Decrypt the private key and return in raw form.\n\n        :param keyfile_json: json string containing encrypted private key.\n        :param password: the password to decrypt.\n        :return: the raw private key.\n        \"\"\"\n\n\nclass Helper(ABC):\n    \"\"\"Interface for helper class usable as Mixin for LedgerApi or as standalone class.\"\"\"\n\n    @staticmethod\n    @abstractmethod\n    def is_transaction_settled(tx_receipt: JSONLike) -> bool:\n        \"\"\"\n        Check whether a transaction is settled or not.\n\n        :param tx_receipt: the receipt associated to the transaction.\n        :return: True if the transaction has been settled, False o/w.\n        \"\"\"\n\n    @staticmethod\n    @abstractmethod\n    def is_transaction_valid(\n        tx: JSONLike,\n        seller: Address,\n        client: Address,\n        tx_nonce: str,\n        amount: int,\n    ) -> bool:\n        \"\"\"\n        Check whether a transaction is valid or not.\n\n        :param tx: the transaction.\n        :param seller: the address of the seller.\n        :param client: the address of the client.\n        :param tx_nonce: the transaction nonce.\n        :param amount: the amount we expect to get from the transaction.\n        :return: True if the random_message is equals to tx['input']\n        \"\"\"\n\n    @staticmethod\n    @abstractmethod\n    def get_contract_address(tx_receipt: JSONLike) -> Optional[str]:\n        \"\"\"\n        Get the contract address from a transaction receipt.\n\n        :param tx_receipt: the transaction digest\n        :return: the contract address if successful\n        \"\"\"\n\n    @staticmethod\n    @abstractmethod\n    def generate_tx_nonce(seller: Address, client: Address) -> str:\n        \"\"\"\n        Generate a unique hash to distinguish transactions with the same terms.\n\n        :param seller: the address of the seller.\n        :param client: the address of the client.\n        :return: return the hash in hex.\n        \"\"\"\n\n    @classmethod\n    @abstractmethod\n    def get_address_from_public_key(cls, public_key: str) -> str:\n        \"\"\"\n        Get the address from the public key.\n\n        :param public_key: the public key\n        :return: str\n        \"\"\"\n\n    @classmethod\n    @abstractmethod\n    def recover_message(\n        cls, message: bytes, signature: str, is_deprecated_mode: bool = False\n    ) -> Tuple[Address, ...]:\n        \"\"\"\n        Recover the addresses from the hash.\n\n        :param message: the message we expect\n        :param signature: the transaction signature\n        :param is_deprecated_mode: if the deprecated signing was used\n        :return: the recovered addresses\n        \"\"\"\n\n    @classmethod\n    @abstractmethod\n    def recover_public_keys_from_message(\n        cls, message: bytes, signature: str, is_deprecated_mode: bool = False\n    ) -> Tuple[str, ...]:\n        \"\"\"\n        Get the public key used to produce the `signature` of the `message`\n\n        :param message: raw bytes used to produce signature\n        :param signature: signature of the message\n        :param is_deprecated_mode: if the deprecated signing was used\n        :return: the recovered public keys\n        \"\"\"\n\n    @staticmethod\n    @abstractmethod\n    def get_hash(message: bytes) -> str:\n        \"\"\"\n        Get the hash of a message.\n\n        :param message: the message to be hashed.\n        :return: the hash of the message.\n        \"\"\"\n\n    @classmethod\n    @abstractmethod\n    def is_valid_address(cls, address: Address) -> bool:\n        \"\"\"\n        Check if the address is valid.\n\n        :param address: the address to validate\n        \"\"\"\n\n    @classmethod\n    @abstractmethod\n    def load_contract_interface(cls, file_path: Path) -> Dict[str, str]:\n        \"\"\"\n        Load contract interface.\n\n        :param file_path: the file path to the interface\n        :return: the interface\n        \"\"\"\n\n\nclass LedgerApi(Helper, ABC):\n    \"\"\"Interface for ledger APIs.\"\"\"\n\n    identifier = \"base\"  # type: str\n\n    @property\n    @abstractmethod\n    def api(self) -> Any:\n        \"\"\"\n        Get the underlying API object.\n\n        This can be used for low-level operations with the concrete ledger APIs.\n        If there is no such object, return None.\n        \"\"\"\n\n    @abstractmethod\n    def get_balance(self, address: Address) -> Optional[int]:\n        \"\"\"\n        Get the balance of a given account.\n\n        This usually takes the form of a web request to be waited synchronously.\n\n        :param address: the address.\n        :return: the balance.\n        \"\"\"\n\n    @abstractmethod\n    def get_state(\n        self, callable_name: str, *args: Any, **kwargs: Any\n    ) -> Optional[JSONLike]:\n        \"\"\"\n        Call a specified function on the underlying ledger API.\n\n        This usually takes the form of a web request to be waited synchronously.\n\n        :param callable_name: the name of the API function to be called.\n        :param args: the positional arguments for the API function.\n        :param kwargs: the keyword arguments for the API function.\n        :return: the ledger API response.\n        \"\"\"\n\n    @abstractmethod\n    def get_transfer_transaction(\n        self,\n        sender_address: Address,\n        destination_address: Address,\n        amount: int,\n        tx_fee: int,\n        tx_nonce: str,\n        **kwargs: Any,\n    ) -> Optional[JSONLike]:\n        \"\"\"\n        Submit a transfer transaction to the ledger.\n\n        :param sender_address: the sender address of the payer.\n        :param destination_address: the destination address of the payee.\n        :param amount: the amount of wealth to be transferred.\n        :param tx_fee: the transaction fee.\n        :param tx_nonce: verifies the authenticity of the tx\n        :param kwargs: the keyword arguments.\n        :return: the transfer transaction\n        \"\"\"\n\n    @abstractmethod\n    def send_signed_transaction(self, tx_signed: JSONLike) -> Optional[str]:\n        \"\"\"\n        Send a signed transaction and wait for confirmation.\n\n        Use keyword arguments for the specifying the signed transaction payload.\n\n        :param tx_signed: the signed transaction\n        \"\"\"\n\n    @abstractmethod\n    def get_transaction_receipt(self, tx_digest: str) -> Optional[JSONLike]:\n        \"\"\"\n        Get the transaction receipt for a transaction digest.\n\n        :param tx_digest: the digest associated to the transaction.\n        :return: the tx receipt, if present\n        \"\"\"\n\n    @abstractmethod\n    def get_transaction(self, tx_digest: str) -> Optional[JSONLike]:\n        \"\"\"\n        Get the transaction for a transaction digest.\n\n        :param tx_digest: the digest associated to the transaction.\n        :return: the tx, if present\n        \"\"\"\n\n    @abstractmethod\n    def get_contract_instance(\n        self, contract_interface: Dict[str, str], contract_address: Optional[str] = None\n    ) -> Any:\n        \"\"\"\n        Get the instance of a contract.\n\n        :param contract_interface: the contract interface.\n        :param contract_address: the contract address.\n        :return: the contract instance\n        \"\"\"\n\n    @abstractmethod\n    def get_deploy_transaction(\n        self,\n        contract_interface: Dict[str, str],\n        deployer_address: Address,\n        **kwargs: Any,\n    ) -> Optional[JSONLike]:\n        \"\"\"\n        Get the transaction to deploy the smart contract.\n\n        :param contract_interface: the contract interface.\n        :param deployer_address: The address that will deploy the contract.\n        :param kwargs: the keyword arguments.\n        :returns tx: the transaction dictionary.\n        \"\"\"\n\n    @abstractmethod\n    def update_with_gas_estimate(self, transaction: JSONLike) -> JSONLike:\n        \"\"\"\n        Attempts to update the transaction with a gas estimate\n\n        :param transaction: the transaction\n        :return: the updated transaction\n        \"\"\"\n\n\nclass FaucetApi(ABC):\n    \"\"\"Interface for testnet faucet APIs.\"\"\"\n\n    identifier = \"base\"  # type: str\n    network_name = \"testnet\"  # type: str\n\n    @abstractmethod\n    def get_wealth(self, address: Address, url: Optional[str] = None) -> None:\n        \"\"\"\n        Get wealth from the faucet for the provided address.\n\n        :param address: the address.\n        :param url: the url\n        :return: None\n        \"\"\"\n"
  },
  {
    "path": "aea/crypto/helpers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Module wrapping the helpers of public and private key cryptography.\"\"\"\nimport logging\nimport os\nfrom pathlib import Path\nfrom typing import Dict, Optional\n\nfrom aea.configurations.base import AgentConfig\nfrom aea.configurations.constants import PRIVATE_KEY_PATH_SCHEMA\nfrom aea.crypto.registries import crypto_registry, make_crypto, make_faucet_api\nfrom aea.crypto.wallet import Wallet\nfrom aea.helpers.base import ensure_dir\nfrom aea.helpers.env_vars import is_env_variable\n\n\n_default_logger = logging.getLogger(__name__)\n\n_ = PRIVATE_KEY_PATH_SCHEMA  # some modules expect this here\n\n\ndef try_validate_private_key_path(\n    ledger_id: str,\n    private_key_path: str,\n    password: Optional[str] = None,\n) -> None:\n    \"\"\"\n    Try validate a private key path.\n\n    :param ledger_id: one of 'fetchai', 'ethereum'\n    :param private_key_path: the path to the private key.\n    :param password: the password to encrypt/decrypt the private key.\n    :raises: ValueError if the identifier is invalid.\n    \"\"\"\n    try:\n        # to validate the file, we just try to create a crypto object\n        # with private_key_path as parameter\n        make_crypto(ledger_id, private_key_path=private_key_path, password=password)\n    except Exception as e:  # pylint: disable=broad-except  # thats ok, reraise\n        error_msg = (\n            \"This is not a valid private key file: '{}'\\n Exception: '{}'\".format(\n                private_key_path, e\n            )\n        )\n        _default_logger.error(error_msg)\n        raise\n\n\ndef create_private_key(\n    ledger_id: str, private_key_file: str, password: Optional[str] = None\n) -> None:\n    \"\"\"\n    Create a private key for the specified ledger identifier.\n\n    :param ledger_id: the ledger identifier.\n    :param private_key_file: the private key file.\n    :param password: the password to encrypt/decrypt the private key.\n    :raises: ValueError if the identifier is invalid.\n    \"\"\"\n    crypto = make_crypto(ledger_id)\n    crypto.dump(private_key_file, password)\n\n\ndef try_generate_testnet_wealth(\n    identifier: str, address: str, url: Optional[str] = None, _sync: bool = True\n) -> None:\n    \"\"\"\n    Try generate wealth on a testnet.\n\n    :param identifier: the identifier of the ledger\n    :param address: the address to check for\n    :param url: the url\n    :param _sync: whether to wait to sync or not; currently unused\n    \"\"\"\n    faucet_api = make_faucet_api(identifier)\n    if faucet_api is not None:\n        faucet_api.get_wealth(address, url)\n\n\ndef private_key_verify(\n    aea_conf: AgentConfig,\n    aea_project_path: Path,\n    password: Optional[str] = None,\n) -> None:\n    \"\"\"\n    Check key.\n\n    :param aea_conf: AgentConfig\n    :param aea_project_path: Path, where project placed.\n    :param password: the password to encrypt/decrypt the private key.\n    \"\"\"\n    for identifier, _ in aea_conf.private_key_paths.read_all():\n        if identifier not in crypto_registry.supported_ids:  # pragma: nocover\n            raise ValueError(\n                \"Unsupported identifier `{}` in private key paths. Supported identifiers: {}.\".format(\n                    identifier, sorted(crypto_registry.supported_ids)\n                )\n            )\n\n    for identifier in crypto_registry.supported_ids:\n        config_private_key_path = aea_conf.private_key_paths.read(identifier)\n\n        if is_env_variable(config_private_key_path):\n            # config_private_key_path is env variable to be used, skip it. check will be performed after substitution\n            continue\n\n        if config_private_key_path is None:\n            continue\n        try:\n            try_validate_private_key_path(\n                identifier,\n                str(aea_project_path / config_private_key_path),\n                password=password,\n            )\n        except FileNotFoundError:  # pragma: no cover\n            raise ValueError(\n                \"File {} for private key {} not found.\".format(\n                    repr(config_private_key_path),\n                    identifier,\n                )\n            )\n\n\ndef make_certificate(\n    ledger_id: str,\n    crypto_private_key_path: str,\n    message: bytes,\n    output_path: str,\n    password: Optional[str] = None,\n) -> str:\n    \"\"\"\n    Create certificate.\n\n    :param ledger_id: the ledger id\n    :param crypto_private_key_path: the path to the private key.\n    :param message: the message to be signed.\n    :param output_path: the location where to save the certificate.\n    :param password: the password to encrypt/decrypt the private keys.\n    :return: the signature/certificate\n    \"\"\"\n    crypto = crypto_registry.make(\n        ledger_id, private_key_path=crypto_private_key_path, password=password\n    )\n    signature = crypto.sign_message(message).encode(\"ascii\").hex()\n    ensure_dir(os.path.dirname(output_path))\n    Path(output_path).write_bytes(signature.encode(\"ascii\"))\n    return signature\n\n\ndef get_wallet_from_agent_config(\n    agent_config: AgentConfig, password: Optional[str] = None\n) -> Wallet:\n    \"\"\"\n    Get wallet from agent_cofig provided.\n\n    :param agent_config: the agent configuration object\n    :param password: the password to encrypt/decrypt the private keys.\n    :return: wallet\n    \"\"\"\n    private_key_paths: Dict[str, Optional[str]] = {\n        config_pair[0]: config_pair[1]\n        for config_pair in agent_config.private_key_paths.read_all()\n    }\n    connections_private_key_paths: Dict[str, Optional[str]] = {\n        config_pair[0]: config_pair[1]\n        for config_pair in agent_config.connection_private_key_paths.read_all()\n    }\n    wallet = Wallet(private_key_paths, connections_private_key_paths, password=password)\n    return wallet\n\n\nclass DecryptError(ValueError):\n    \"\"\"Error on bytes decryption with password.\"\"\"\n\n    msg = \"Decrypt error! Bad password?\"\n\n    def __init__(self, msg: Optional[str] = None) -> None:\n        \"\"\"Init exception.\"\"\"\n        super().__init__(msg or self.msg)\n\n\nclass KeyIsIncorrect(ValueError):\n    \"\"\"Error decoding hex string to bytes for private key.\"\"\"\n\n\ndef hex_to_bytes_for_key(data: str) -> bytes:\n    \"\"\"Convert hex string to bytes with error handling.\"\"\"\n    try:\n        return bytes.fromhex(data)\n    except ValueError as e:\n        raise KeyIsIncorrect(str(e)) from e\n"
  },
  {
    "path": "aea/crypto/ledger_apis.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Module wrapping all the public and private keys cryptography.\"\"\"\nfrom typing import Any, Dict, Optional, Tuple, Union\n\nfrom aea.common import Address\nfrom aea.configurations.constants import (\n    DEFAULT_LEDGER,\n    _COSMOS_IDENTIFIER,\n    _ETHEREUM_IDENTIFIER,\n    _FETCHAI_IDENTIFIER,\n)\nfrom aea.crypto.base import LedgerApi\nfrom aea.crypto.registries import (\n    ledger_apis_registry,\n    make_ledger_api,\n    make_ledger_api_cls,\n)\nfrom aea.exceptions import enforce\n\n\nCOSMOS_DEFAULT_ADDRESS = \"INVALID_URL\"\nCOSMOS_DEFAULT_CURRENCY_DENOM = \"INVALID_CURRENCY_DENOM\"\nCOSMOS_DEFAULT_CHAIN_ID = \"INVALID_CHAIN_ID\"\nETHEREUM_DEFAULT_ADDRESS = \"http://127.0.0.1:8545\"\nETHEREUM_DEFAULT_CHAIN_ID = 1337\nETHEREUM_DEFAULT_CURRENCY_DENOM = \"wei\"\nFETCHAI_DEFAULT_ADDRESS = \"https://rest-dorado.fetch.ai:443\"\nFETCHAI_DEFAULT_CURRENCY_DENOM = \"atestfet\"\nFETCHAI_DEFAULT_CHAIN_ID = \"dorado-1\"\n\n\nDEFAULT_LEDGER_CONFIGS: Dict[str, Dict[str, Union[str, int]]] = {\n    _COSMOS_IDENTIFIER: {\n        \"address\": COSMOS_DEFAULT_ADDRESS,\n        \"chain_id\": COSMOS_DEFAULT_CHAIN_ID,\n        \"denom\": COSMOS_DEFAULT_CURRENCY_DENOM,\n    },\n    _ETHEREUM_IDENTIFIER: {\n        \"address\": ETHEREUM_DEFAULT_ADDRESS,\n        \"chain_id\": ETHEREUM_DEFAULT_CHAIN_ID,\n        \"denom\": ETHEREUM_DEFAULT_CURRENCY_DENOM,\n    },\n    _FETCHAI_IDENTIFIER: {\n        \"address\": FETCHAI_DEFAULT_ADDRESS,\n        \"chain_id\": FETCHAI_DEFAULT_CHAIN_ID,\n        \"denom\": FETCHAI_DEFAULT_CURRENCY_DENOM,\n    },\n}\nDEFAULT_CURRENCY_DENOMINATIONS = {\n    _COSMOS_IDENTIFIER: COSMOS_DEFAULT_CURRENCY_DENOM,\n    _ETHEREUM_IDENTIFIER: ETHEREUM_DEFAULT_CURRENCY_DENOM,\n    _FETCHAI_IDENTIFIER: FETCHAI_DEFAULT_CURRENCY_DENOM,\n}\n\n\nclass LedgerApis:\n    \"\"\"Store all the ledger apis we initialise.\"\"\"\n\n    ledger_api_configs: Dict[str, Dict[str, Union[str, int]]] = DEFAULT_LEDGER_CONFIGS\n\n    @staticmethod\n    def has_ledger(identifier: str) -> bool:\n        \"\"\"Check if it has the api.\"\"\"\n        return identifier in ledger_apis_registry.supported_ids\n\n    @classmethod\n    def get_api(cls, identifier: str) -> LedgerApi:\n        \"\"\"Get the ledger API.\"\"\"\n        enforce(\n            identifier in ledger_apis_registry.supported_ids,\n            \"Not a registered ledger api identifier.\",\n        )\n        api = make_ledger_api(identifier, **cls.ledger_api_configs[identifier])\n        return api\n\n    @classmethod\n    def get_balance(cls, identifier: str, address: str) -> Optional[int]:\n        \"\"\"\n        Get the token balance.\n\n        :param identifier: the identifier of the ledger\n        :param address: the address to check for\n        :return: the token balance\n        \"\"\"\n        enforce(\n            identifier in ledger_apis_registry.supported_ids,\n            \"Not a registered ledger api identifier.\",\n        )\n        api = make_ledger_api(identifier, **cls.ledger_api_configs[identifier])\n        balance = api.get_balance(address)\n        return balance\n\n    @classmethod\n    def get_transfer_transaction(\n        cls,\n        identifier: str,\n        sender_address: str,\n        destination_address: str,\n        amount: int,\n        tx_fee: int,\n        tx_nonce: str,\n        **kwargs: Any,\n    ) -> Optional[Any]:\n        \"\"\"\n        Get a transaction to transfer from self to destination.\n\n        :param identifier: the identifier of the ledger\n        :param sender_address: the address of the sender\n        :param destination_address: the address of the receiver\n        :param amount: the amount\n        :param tx_nonce: verifies the authenticity of the tx\n        :param tx_fee: the tx fee\n        :param kwargs: the keyword arguments.\n\n        :return: tx\n        \"\"\"\n        enforce(\n            identifier in ledger_apis_registry.supported_ids,\n            \"Not a registered ledger api identifier.\",\n        )\n        api = make_ledger_api(identifier, **cls.ledger_api_configs[identifier])\n        tx = api.get_transfer_transaction(\n            sender_address,\n            destination_address,\n            amount,\n            tx_fee,\n            tx_nonce,\n            **kwargs,\n        )\n        return tx\n\n    @classmethod\n    def send_signed_transaction(cls, identifier: str, tx_signed: Any) -> Optional[str]:\n        \"\"\"\n        Send a signed transaction and wait for confirmation.\n\n        :param identifier: the identifier of the ledger\n        :param tx_signed: the signed transaction\n        :return: the tx_digest, if present\n        \"\"\"\n        enforce(\n            identifier in ledger_apis_registry.supported_ids,\n            \"Not a registered ledger api identifier.\",\n        )\n        api = make_ledger_api(identifier, **cls.ledger_api_configs[identifier])\n        tx_digest = api.send_signed_transaction(tx_signed)\n        return tx_digest\n\n    @classmethod\n    def get_transaction_receipt(cls, identifier: str, tx_digest: str) -> Optional[Any]:\n        \"\"\"\n        Get the transaction receipt for a transaction digest.\n\n        :param identifier: the identifier of the ledger\n        :param tx_digest: the digest associated to the transaction.\n        :return: the tx receipt, if present\n        \"\"\"\n        enforce(\n            identifier in ledger_apis_registry.supported_ids,\n            \"Not a registered ledger api identifier.\",\n        )\n        api = make_ledger_api(identifier, **cls.ledger_api_configs[identifier])\n        tx_receipt = api.get_transaction_receipt(tx_digest)\n        return tx_receipt\n\n    @classmethod\n    def get_transaction(cls, identifier: str, tx_digest: str) -> Optional[Any]:\n        \"\"\"\n        Get the transaction for a transaction digest.\n\n        :param identifier: the identifier of the ledger\n        :param tx_digest: the digest associated to the transaction.\n        :return: the tx, if present\n        \"\"\"\n        enforce(\n            identifier in ledger_apis_registry.supported_ids,\n            \"Not a registered ledger api identifier.\",\n        )\n        api = make_ledger_api(identifier, **cls.ledger_api_configs[identifier])\n        tx = api.get_transaction(tx_digest)\n        return tx\n\n    @staticmethod\n    def get_contract_address(identifier: str, tx_receipt: Any) -> Optional[Address]:\n        \"\"\"\n        Get the contract address from a transaction receipt.\n\n        :param identifier: the identifier of the ledger\n        :param tx_receipt: the transaction receipt\n        :return: the contract address if successful\n        \"\"\"\n        enforce(\n            identifier in ledger_apis_registry.supported_ids,\n            \"Not a registered ledger api identifier.\",\n        )\n        api_class = make_ledger_api_cls(identifier)\n        address = api_class.get_contract_address(tx_receipt)\n        return address\n\n    @staticmethod\n    def is_transaction_settled(identifier: str, tx_receipt: Any) -> bool:\n        \"\"\"\n        Check whether the transaction is settled and correct.\n\n        :param identifier: the identifier of the ledger\n        :param tx_receipt: the transaction digest\n        :return: True if correctly settled, False otherwise\n        \"\"\"\n        enforce(\n            identifier in ledger_apis_registry.supported_ids,\n            \"Not a registered ledger api identifier.\",\n        )\n        api_class = make_ledger_api_cls(identifier)\n        is_settled = api_class.is_transaction_settled(tx_receipt)\n        return is_settled\n\n    @staticmethod\n    def is_transaction_valid(\n        identifier: str,\n        tx: Any,\n        seller: Address,\n        client: Address,\n        tx_nonce: str,\n        amount: int,\n    ) -> bool:\n        \"\"\"\n        Check whether the transaction is valid.\n\n        :param identifier: Ledger identifier\n        :param tx:  the transaction\n        :param seller: the address of the seller.\n        :param client: the address of the client.\n        :param tx_nonce: the transaction nonce.\n        :param amount: the amount we expect to get from the transaction.\n        :return: True if is valid , False otherwise\n        \"\"\"\n        enforce(\n            identifier in ledger_apis_registry.supported_ids,\n            \"Not a registered ledger api identifier.\",\n        )\n        api_class = make_ledger_api_cls(identifier)\n        is_valid = api_class.is_transaction_valid(tx, seller, client, tx_nonce, amount)\n        return is_valid\n\n    @staticmethod\n    def generate_tx_nonce(identifier: str, seller: Address, client: Address) -> str:\n        \"\"\"\n        Generate a random str message.\n\n        :param identifier: ledger identifier.\n        :param seller: the address of the seller.\n        :param client: the address of the client.\n        :return: return the hash in hex.\n        \"\"\"\n        enforce(\n            identifier in ledger_apis_registry.supported_ids,\n            \"Not a registered ledger api identifier.\",\n        )\n        api_class = make_ledger_api_cls(identifier)\n        tx_nonce = api_class.generate_tx_nonce(seller=seller, client=client)\n        return tx_nonce\n\n    @staticmethod\n    def recover_message(\n        identifier: str,\n        message: bytes,\n        signature: str,\n        is_deprecated_mode: bool = False,\n    ) -> Tuple[Address, ...]:\n        \"\"\"\n        Recover the addresses from the hash.\n\n        :param identifier: ledger identifier.\n        :param message: the message we expect\n        :param signature: the transaction signature\n        :param is_deprecated_mode: if the deprecated signing was used\n        :return: the recovered addresses\n        \"\"\"\n        enforce(\n            identifier in ledger_apis_registry.supported_ids,\n            \"Not a registered ledger api identifier.\",\n        )\n        api_class = make_ledger_api_cls(identifier)\n        addresses = api_class.recover_message(\n            message=message, signature=signature, is_deprecated_mode=is_deprecated_mode\n        )\n        return addresses\n\n    @staticmethod\n    def get_hash(identifier: str, message: bytes) -> str:\n        \"\"\"\n        Get the hash of a message.\n\n        :param identifier: ledger identifier.\n        :param message: the message to be hashed.\n        :return: the hash of the message.\n        \"\"\"\n        identifier = (\n            identifier\n            if identifier in ledger_apis_registry.supported_ids\n            else DEFAULT_LEDGER\n        )\n        api_class = make_ledger_api_cls(identifier)\n        digest = api_class.get_hash(message=message)\n        return digest\n\n    @staticmethod\n    def is_valid_address(identifier: str, address: Address) -> bool:\n        \"\"\"\n        Check if the address is valid.\n\n        :param identifier: ledger identifier.\n        :param address: the address to validate.\n        :return: whether it is a valid address or not.\n        \"\"\"\n        identifier = (\n            identifier\n            if identifier in ledger_apis_registry.supported_ids\n            else DEFAULT_LEDGER\n        )\n        api_class = make_ledger_api_cls(identifier)\n        result = api_class.is_valid_address(address=address)\n        return result\n"
  },
  {
    "path": "aea/crypto/plugin.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Implementation of plug-in mechanism for cryptos.\"\"\"\nimport itertools\nimport pprint\nfrom typing import Iterator, List, Set\n\nfrom pkg_resources import EntryPoint, WorkingSet\n\nfrom aea.configurations.constants import (\n    ALLOWED_GROUPS,\n    CRYPTO_PLUGIN_GROUP,\n    DOTTED_PATH_MODULE_ELEMENT_SEPARATOR,\n    FAUCET_APIS_PLUGIN_GROUP,\n    LEDGER_APIS_PLUGIN_GROUP,\n)\nfrom aea.crypto import register_crypto, register_faucet_api, register_ledger_api\nfrom aea.crypto.registries.base import EntryPoint as EntryPointString\nfrom aea.crypto.registries.base import ItemId\nfrom aea.exceptions import AEAException, AEAPluginError, enforce\n\n\n_from_group_to_register_callable = {\n    CRYPTO_PLUGIN_GROUP: register_crypto,\n    LEDGER_APIS_PLUGIN_GROUP: register_ledger_api,\n    FAUCET_APIS_PLUGIN_GROUP: register_faucet_api,\n}\n\n\nclass Plugin:\n    \"\"\"Class that implements an AEA plugin.\"\"\"\n\n    __slots__ = (\"_group\", \"_entry_point\")\n\n    def __init__(self, group: str, entry_point: EntryPoint):\n        \"\"\"\n        Initialize the plugin.\n\n        :param group: the group the plugin belongs to.\n        :param entry_point: the entrypoint.\n        \"\"\"\n        self._group = group\n        self._entry_point = entry_point\n        self._check_consistency()\n\n    def _check_consistency(self) -> None:\n        \"\"\"\n        Check consistency of input.\n\n        :raises AEAPluginError: if some input is not correct.  # noqa: DAR402\n        \"\"\"\n        _error_message_prefix = f\"Error with plugin '{self._entry_point.name}':\"\n        enforce(\n            self.group in ALLOWED_GROUPS,\n            f\"{_error_message_prefix} '{self.group}' is not in the allowed groups: {pprint.pformat(ALLOWED_GROUPS)}\",\n            AEAPluginError,\n        )\n        enforce(\n            ItemId.REGEX.match(self._entry_point.name) is not None,\n            f\"{_error_message_prefix} '{self._entry_point.name}' is not a valid identifier for a plugin.\",\n            AEAPluginError,\n        )\n        enforce(\n            len(self._entry_point.attrs) == 1,\n            f\"{_error_message_prefix} Nested attributes currently not supported.\",\n            AEAPluginError,\n        )\n        enforce(\n            len(self._entry_point.extras) == 0,\n            f\"{_error_message_prefix} Extras currently not supported.\",\n            AEAPluginError,\n        )\n        enforce(\n            EntryPointString.REGEX.match(self.entry_point_path) is not None,\n            f\"{_error_message_prefix} Entry point path '{self.entry_point_path}' is not valid.\",\n        )\n\n    @property\n    def name(self) -> str:\n        \"\"\"Get the plugin identifier.\"\"\"\n        return self._entry_point.name\n\n    @property\n    def group(self) -> str:\n        \"\"\"Get the group.\"\"\"\n        return self._group\n\n    @property\n    def attr(self) -> str:\n        \"\"\"Get the class name.\"\"\"\n        return self._entry_point.attrs[0]\n\n    @property\n    def entry_point_path(self) -> str:\n        \"\"\"Get the entry point path.\"\"\"\n        class_name = self.attr\n        return f\"{self._entry_point.module_name}{DOTTED_PATH_MODULE_ELEMENT_SEPARATOR}{class_name}\"\n\n\ndef _check_no_duplicates(plugins: List[EntryPoint]) -> None:\n    \"\"\"Check there are no two plugins with the same id.\"\"\"\n    seen: Set[str] = set()\n    duplicate_plugins = [p for p in plugins if p.name in seen or seen.add(p.name)]  # type: ignore\n    error_msg = f\"Found plugins with the same id: {pprint.pformat(duplicate_plugins)}\"\n    enforce(len(duplicate_plugins) == 0, error_msg, AEAPluginError)\n\n\ndef _get_plugins(group: str) -> List[Plugin]:\n    \"\"\"\n    Return a dict of all installed plugins, by name.\n\n    :param group: the plugin group.\n    :return: a mapping from plugin name to Plugin objects.\n    \"\"\"\n    entry_points: List[EntryPoint] = list(WorkingSet().iter_entry_points(group=group))\n    _check_no_duplicates(entry_points)\n    return [Plugin(group, entry_point) for entry_point in entry_points]\n\n\ndef _get_cryptos() -> List[Plugin]:\n    \"\"\"Get cryptos plugins.\"\"\"\n    return _get_plugins(CRYPTO_PLUGIN_GROUP)\n\n\ndef _get_ledger_apis() -> List[Plugin]:\n    \"\"\"Get ledgers plugins.\"\"\"\n    return _get_plugins(LEDGER_APIS_PLUGIN_GROUP)\n\n\ndef _get_faucet_apis() -> List[Plugin]:\n    \"\"\"Get faucets plugins.\"\"\"\n    return _get_plugins(FAUCET_APIS_PLUGIN_GROUP)\n\n\ndef _iter_plugins() -> Iterator[Plugin]:\n    \"\"\"Iterate over all the plugins.\"\"\"\n    for plugin in itertools.chain(\n        _get_cryptos(), _get_ledger_apis(), _get_faucet_apis()\n    ):\n        yield plugin\n\n\ndef _register_plugin(plugin: Plugin, is_raising_exception: bool = True) -> None:\n    \"\"\"Register a plugin to the right registry.\"\"\"\n    register_function = _from_group_to_register_callable[plugin.group]\n    try:\n        register_function(plugin.name, entry_point=plugin.entry_point_path)\n    except AEAException:  # pragma: nocover\n        if is_raising_exception:\n            raise\n\n\ndef load_all_plugins(is_raising_exception: bool = True) -> None:\n    \"\"\"Load all plugins.\"\"\"\n    for plugin in _iter_plugins():\n        _register_plugin(plugin, is_raising_exception)\n"
  },
  {
    "path": "aea/crypto/registries/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the crypto and the ledger APIs registries.\"\"\"\nfrom typing import Callable, Type\n\nfrom aea.crypto.base import Crypto, FaucetApi, LedgerApi\nfrom aea.crypto.registries.base import Registry\n\n\ncrypto_registry: Registry[Crypto] = Registry[Crypto]()\nregister_crypto = crypto_registry.register\nmake_crypto: Callable[..., Crypto] = crypto_registry.make\n\nledger_apis_registry: Registry[LedgerApi] = Registry[LedgerApi]()\nregister_ledger_api = ledger_apis_registry.register\nmake_ledger_api: Callable[..., LedgerApi] = ledger_apis_registry.make\nmake_ledger_api_cls: Callable[..., Type[LedgerApi]] = ledger_apis_registry.make_cls\n\nfaucet_apis_registry: Registry[FaucetApi] = Registry[FaucetApi]()\nregister_faucet_api = faucet_apis_registry.register\nmake_faucet_api: Callable[..., FaucetApi] = faucet_apis_registry.make\nmake_faucet_api_cls: Callable[..., Type[FaucetApi]] = faucet_apis_registry.make_cls\n"
  },
  {
    "path": "aea/crypto/registries/base.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module implements the base registry.\"\"\"\n\nimport importlib\nimport re\nfrom typing import Any, Dict, Generic, Optional, Set, Type, TypeVar, Union\n\nfrom aea.configurations.base import PublicId\nfrom aea.configurations.constants import DOTTED_PATH_MODULE_ELEMENT_SEPARATOR\nfrom aea.exceptions import AEAException\nfrom aea.helpers.base import RegexConstrainedString, SIMPLE_ID_REGEX\n\n\n\"\"\"A regex to match a Python identifier (i.e. a module/class name).\"\"\"\nPY_ID_REGEX = r\"[^\\d\\W]\\w*\"\nITEM_ID_REGEX = rf\"({SIMPLE_ID_REGEX})|{PublicId.PUBLIC_ID_REGEX}\"\nItemType = TypeVar(\"ItemType\")\n\n\ndef _handle_malformed_string(class_name: str, malformed_id: str) -> None:\n    raise AEAException(\n        \"Malformed {}: '{}'. It must be of the form '{}'.\".format(\n            class_name, malformed_id, ItemId.REGEX.pattern\n        )\n    )\n\n\nclass ItemId(RegexConstrainedString):\n    \"\"\"The identifier of an item class.\"\"\"\n\n    REGEX = re.compile(r\"^({})$\".format(ITEM_ID_REGEX))\n\n    @property\n    def name(self) -> str:\n        \"\"\"Get the id name.\"\"\"\n        return self.data\n\n    def _handle_no_match(self) -> None:\n        _handle_malformed_string(ItemId.__name__, self.data)\n\n\nclass EntryPoint(Generic[ItemType], RegexConstrainedString):\n    \"\"\"\n    The entry point for a resource.\n\n    The regular expression matches the strings in the following format:\n\n        path.to.module:className\n    \"\"\"\n\n    REGEX = re.compile(\n        r\"^({pyid}(?:\\.{pyid})*){sep}({pyid})$\".format(\n            pyid=PY_ID_REGEX, sep=DOTTED_PATH_MODULE_ELEMENT_SEPARATOR\n        )\n    )\n\n    def __init__(self, seq: Union[\"EntryPoint\", str]) -> None:\n        \"\"\"Initialize the entrypoint.\"\"\"\n        super().__init__(seq)\n\n        match = self.REGEX.match(self.data)\n\n        if match is None:\n            # actual match done in base class\n            raise ValueError(\"No match found!\")  # pragma: nocover\n\n        self._import_path = match.group(1)\n        self._class_name = match.group(2)\n\n    @property\n    def import_path(self) -> str:\n        \"\"\"Get the import path.\"\"\"\n        return self._import_path\n\n    @property\n    def class_name(self) -> str:\n        \"\"\"Get the class name.\"\"\"\n        return self._class_name\n\n    def _handle_no_match(self) -> None:\n        _handle_malformed_string(EntryPoint.__name__, self.data)\n\n    def load(self) -> Type[ItemType]:\n        \"\"\"\n        Load the item object.\n\n        :return: the crypto object, loaded following the spec.\n        \"\"\"\n        mod_name, attr_name = self.import_path, self.class_name\n        mod = importlib.import_module(mod_name)\n        fn = getattr(mod, attr_name)\n        return fn\n\n\nclass ItemSpec(Generic[ItemType]):\n    \"\"\"A specification for a particular instance of an object.\"\"\"\n\n    def __init__(\n        self,\n        id_: ItemId,\n        entry_point: EntryPoint[ItemType],\n        class_kwargs: Optional[Dict[str, Any]] = None,\n        **kwargs: Dict,\n    ) -> None:\n        \"\"\"\n        Initialize an item specification.\n\n        :param id_: the id associated to this specification\n        :param entry_point: The Python entry_point of the environment class (e.g. module.name:Class).\n        :param class_kwargs: keyword arguments to be attached on the class as class variables.\n        :param kwargs: other custom keyword arguments.\n        \"\"\"\n        self.id = ItemId(id_)\n        self.entry_point = EntryPoint[ItemType](entry_point)\n        self._class_kwargs = {} if class_kwargs is None else class_kwargs\n        self._kwargs = {} if kwargs is None else kwargs\n\n    def make(self, **kwargs: Any) -> ItemType:\n        \"\"\"\n        Instantiate an instance of the item object with appropriate arguments.\n\n        :param kwargs: the key word arguments\n        :return: an item\n        \"\"\"\n        _kwargs = self._kwargs.copy()\n        _kwargs.update(kwargs)\n        cls = self.get_class()\n        item = cls(**_kwargs)  # type: ignore\n        return item\n\n    def get_class(self) -> Type[ItemType]:\n        \"\"\"\n        Get the class of the item with class variables instantiated.\n\n        :return: an item class\n        \"\"\"\n        cls = self.entry_point.load()\n        for key, value in self._class_kwargs.items():\n            setattr(cls, key, value)\n        return cls\n\n\nclass Registry(Generic[ItemType]):\n    \"\"\"Registry for generic classes.\"\"\"\n\n    def __init__(self) -> None:\n        \"\"\"Initialize the registry.\"\"\"\n        self.specs = {}  # type: Dict[ItemId, ItemSpec[ItemType]]\n\n    @property\n    def supported_ids(self) -> Set[str]:\n        \"\"\"Get the supported item ids.\"\"\"\n        return {str(id_) for id_ in self.specs.keys()}\n\n    def register(\n        self,\n        id_: Union[ItemId, str],\n        entry_point: Union[EntryPoint[ItemType], str],\n        class_kwargs: Optional[Dict[str, Any]] = None,\n        **kwargs: Any,\n    ) -> None:\n        \"\"\"\n        Register an item type.\n\n        :param id_: the identifier for the crypto type.\n        :param entry_point: the entry point to load the crypto object.\n        :param class_kwargs: keyword arguments to be attached on the class as class variables.\n        :param kwargs: arguments to provide to the crypto class.\n        \"\"\"\n        item_id = ItemId(id_)\n        entry_point = EntryPoint[ItemType](entry_point)\n        if item_id in self.specs:\n            raise AEAException(\"Cannot re-register id: '{}'\".format(item_id))\n        self.specs[item_id] = ItemSpec[ItemType](\n            item_id, entry_point, class_kwargs, **kwargs\n        )\n\n    def make(\n        self, id_: Union[ItemId, str], module: Optional[str] = None, **kwargs: Any\n    ) -> ItemType:\n        \"\"\"\n        Create an instance of the associated type item id.\n\n        :param id_: the id of the item class. Make sure it has been registered earlier\n            before calling this function.\n        :param module: dotted path to a module.\n            whether a module should be loaded before creating the object.\n            this argument is useful when the item might not be registered\n            beforehand, and loading the specified module will make the registration.\n            E.g. suppose the call to 'register' for a custom object\n            is located in some_package/__init__.py. By providing module=\"some_package\",\n            the call to 'register' in such module gets triggered and\n            the make can then find the identifier.\n        :param kwargs: keyword arguments to be forwarded to the object.\n        :return: the new item instance.\n        \"\"\"\n        item_id = ItemId(id_)\n        spec = self._get_spec(item_id, module=module)\n        item = spec.make(**kwargs)\n        return item\n\n    def make_cls(\n        self, id_: Union[ItemId, str], module: Optional[str] = None\n    ) -> Type[ItemType]:\n        \"\"\"\n        Load a class of the associated type item id.\n\n        :param id_: the id of the item class. Make sure it has been registered earlier\n            before calling this function.\n        :param module: dotted path to a module.\n            whether a module should be loaded before creating the object.\n            this argument is useful when the item might not be registered\n            beforehand, and loading the specified module will make the registration.\n            E.g. suppose the call to 'register' for a custom object\n            is located in some_package/__init__.py. By providing module=\"some_package\",\n            the call to 'register' in such module gets triggered and\n            the make can then find the identifier.\n        :return: the new item class.\n        \"\"\"\n        item_id = ItemId(id_)\n        spec = self._get_spec(item_id, module=module)\n        cls = spec.get_class()\n        return cls\n\n    def has_spec(self, item_id: ItemId) -> bool:\n        \"\"\"\n        Check whether there exist a spec associated with an item id.\n\n        :param item_id: the item identifier.\n        :return: True if it is registered, False otherwise.\n        \"\"\"\n        return item_id in self.specs.keys()\n\n    def _get_spec(\n        self, item_id: ItemId, module: Optional[str] = None\n    ) -> ItemSpec[ItemType]:\n        \"\"\"Get the item spec.\"\"\"\n        if module is not None:\n            try:\n                importlib.import_module(module)\n            except ImportError:\n                raise AEAException(\n                    \"A module ({}) was specified for the item but was not found, \"\n                    \"make sure the package is installed with `pip install` before calling `aea.crypto.make()`\".format(\n                        module\n                    )\n                )\n\n        if item_id not in self.specs:\n            raise AEAException(\"Item not registered with id '{}'.\".format(item_id))\n        return self.specs[item_id]\n"
  },
  {
    "path": "aea/crypto/wallet.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Module wrapping all the public and private keys cryptography.\"\"\"\n\nimport logging\nfrom typing import Any, Dict, Optional, cast\n\nfrom aea.common import JSONLike\nfrom aea.crypto.base import Crypto\nfrom aea.crypto.registries import make_crypto\n\n\n_default_logger = logging.getLogger(__name__)\n\n\nclass CryptoStore:\n    \"\"\"Utility class to store and retrieve crypto objects.\"\"\"\n\n    __slots__ = (\"_crypto_objects\", \"_public_keys\", \"_addresses\", \"_private_keys\")\n\n    def __init__(\n        self,\n        crypto_id_to_path: Optional[Dict[str, Optional[str]]] = None,\n        password: Optional[str] = None,\n    ) -> None:\n        \"\"\"\n        Initialize the crypto store.\n\n        :param crypto_id_to_path: dictionary from crypto id to an (optional) path\n            to the private key.\n        :param password: the password to encrypt/decrypt the private key.\n        \"\"\"\n        if crypto_id_to_path is None:\n            crypto_id_to_path = {}\n        crypto_objects = {}  # type: Dict[str, Crypto]\n        public_keys = {}  # type: Dict[str, str]\n        addresses = {}  # type: Dict[str, str]\n        private_keys = {}  # type: Dict[str, str]\n\n        for identifier, path in crypto_id_to_path.items():\n            crypto = make_crypto(identifier, private_key_path=path, password=password)\n            crypto_objects[identifier] = crypto\n            public_keys[identifier] = cast(str, crypto.public_key)\n            addresses[identifier] = cast(str, crypto.address)\n            private_keys[identifier] = cast(str, crypto.private_key)\n\n        self._crypto_objects = crypto_objects\n        self._public_keys = public_keys\n        self._addresses = addresses\n        self._private_keys = private_keys\n\n    @property\n    def public_keys(self) -> Dict[str, str]:\n        \"\"\"Get the public_key dictionary.\"\"\"\n        return self._public_keys\n\n    @property\n    def crypto_objects(self) -> Dict[str, Crypto]:\n        \"\"\"Get the crypto objects (key pair).\"\"\"\n        return self._crypto_objects\n\n    @property\n    def addresses(self) -> Dict[str, str]:\n        \"\"\"Get the crypto addresses.\"\"\"\n        return self._addresses\n\n    @property\n    def private_keys(self) -> Dict[str, str]:\n        \"\"\"Get the crypto addresses.\"\"\"\n        return self._private_keys\n\n\nclass Wallet:\n    \"\"\"\n    Container for crypto objects.\n\n    The cryptos are separated into two categories:\n\n    - main cryptos: used by the AEA for the economic side (i.e. signing transaction)\n    - connection cryptos: exposed to the connection objects for encrypted communication.\n\n    \"\"\"\n\n    def __init__(\n        self,\n        private_key_paths: Dict[str, Optional[str]],\n        connection_private_key_paths: Optional[Dict[str, Optional[str]]] = None,\n        password: Optional[str] = None,\n    ):\n        \"\"\"\n        Instantiate a wallet object.\n\n        :param private_key_paths: the private key paths\n        :param connection_private_key_paths: the private key paths for the connections.\n        :param password: the password to encrypt/decrypt the private key.\n        \"\"\"\n        self._main_cryptos = CryptoStore(private_key_paths, password=password)\n        self._connection_cryptos = CryptoStore(\n            connection_private_key_paths, password=password\n        )\n\n    @property\n    def public_keys(self) -> Dict[str, str]:\n        \"\"\"Get the public_key dictionary.\"\"\"\n        return self._main_cryptos.public_keys\n\n    @property\n    def crypto_objects(self) -> Dict[str, Crypto]:\n        \"\"\"Get the crypto objects (key pair).\"\"\"\n        return self._main_cryptos.crypto_objects\n\n    @property\n    def addresses(self) -> Dict[str, str]:\n        \"\"\"Get the crypto addresses.\"\"\"\n        return self._main_cryptos.addresses\n\n    @property\n    def private_keys(self) -> Dict[str, str]:\n        \"\"\"Get the crypto addresses.\"\"\"\n        return self._main_cryptos.private_keys\n\n    @property\n    def main_cryptos(self) -> CryptoStore:\n        \"\"\"Get the main crypto store.\"\"\"\n        return self._main_cryptos\n\n    @property\n    def connection_cryptos(self) -> CryptoStore:\n        \"\"\"Get the connection crypto store.\"\"\"\n        return self._connection_cryptos\n\n    def sign_message(\n        self, crypto_id: str, message: bytes, is_deprecated_mode: bool = False\n    ) -> Optional[str]:\n        \"\"\"\n        Sign a message.\n\n        :param crypto_id: the id of the crypto\n        :param message: the message to be signed\n        :param is_deprecated_mode: what signing mode to use\n        :return: the signature of the message\n        \"\"\"\n        crypto_object = self.crypto_objects.get(crypto_id, None)\n        if crypto_object is None:\n            _default_logger.warning(\n                \"No crypto object for crypto_id={} in wallet!\".format(crypto_id)\n            )\n            signature = None  # type: Optional[str]\n        else:\n            signature = crypto_object.sign_message(message, is_deprecated_mode)\n        return signature\n\n    def sign_transaction(self, crypto_id: str, transaction: Any) -> Optional[JSONLike]:\n        \"\"\"\n        Sign a tx.\n\n        :param crypto_id: the id of the crypto\n        :param transaction: the transaction to be signed\n        :return: the signed tx\n        \"\"\"\n        crypto_object = self.crypto_objects.get(crypto_id, None)\n        if crypto_object is None:\n            _default_logger.warning(\n                \"No crypto object for crypto_id={} in wallet!\".format(crypto_id)\n            )\n            signed_transaction = None  # type: Optional[Any]\n        else:\n            signed_transaction = crypto_object.sign_transaction(transaction)\n        return signed_transaction\n"
  },
  {
    "path": "aea/decision_maker/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the decision maker modules.\"\"\"\n"
  },
  {
    "path": "aea/decision_maker/base.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the decision maker class.\"\"\"\n\nimport hashlib\nimport threading\nfrom abc import ABC, abstractmethod\nfrom queue import Queue\nfrom threading import Thread\nfrom types import SimpleNamespace\nfrom typing import Any, Dict, List, Optional\nfrom uuid import uuid4\n\nfrom aea.crypto.wallet import Wallet\nfrom aea.helpers.async_friendly_queue import AsyncFriendlyQueue\nfrom aea.helpers.logging import WithLogger, get_logger\nfrom aea.helpers.transaction.base import Terms\nfrom aea.identity.base import Identity\nfrom aea.protocols.base import Message\n\n\ndef _hash(access_code: str) -> str:\n    \"\"\"\n    Get the hash of the access code.\n\n    :param access_code: the access code\n    :return: the hash\n    \"\"\"\n    result = hashlib.sha224(access_code.encode(\"utf-8\")).hexdigest()\n    return result\n\n\nclass OwnershipState(ABC):\n    \"\"\"Represent the ownership state of an agent (can proxy a ledger).\"\"\"\n\n    @abstractmethod\n    def set(self, **kwargs: Any) -> None:\n        \"\"\"\n        Set values on the ownership state.\n\n        :param kwargs: the relevant keyword arguments\n        \"\"\"\n\n    @abstractmethod\n    def apply_delta(self, **kwargs: Any) -> None:\n        \"\"\"\n        Apply a state update to the ownership state.\n\n        This method is used to apply a raw state update without a transaction.\n\n        :param kwargs: the relevant keyword arguments\n        \"\"\"\n\n    @property\n    @abstractmethod\n    def is_initialized(self) -> bool:\n        \"\"\"Get the initialization status.\"\"\"\n\n    @abstractmethod\n    def is_affordable_transaction(self, terms: Terms) -> bool:\n        \"\"\"\n        Check if the transaction is affordable (and consistent).\n\n        :param terms: the transaction terms\n        :return: True if the transaction is legal wrt the current state, false otherwise.\n        \"\"\"\n\n    @abstractmethod\n    def apply_transactions(self, list_of_terms: List[Terms]) -> \"OwnershipState\":\n        \"\"\"\n        Apply a list of transactions to (a copy of) the current state.\n\n        :param list_of_terms: the sequence of transaction terms.\n        :return: the final state.\n        \"\"\"\n\n    @abstractmethod\n    def __copy__(self) -> \"OwnershipState\":\n        \"\"\"Copy the object.\"\"\"\n\n\nclass Preferences(ABC):\n    \"\"\"Class to represent the preferences.\"\"\"\n\n    @abstractmethod\n    def set(self, **kwargs: Any) -> None:\n        \"\"\"\n        Set values on the preferences.\n\n        :param kwargs: the relevant key word arguments\n        \"\"\"\n\n    @property\n    @abstractmethod\n    def is_initialized(self) -> bool:\n        \"\"\"\n        Get the initialization status.\n\n        Returns True if exchange_params_by_currency_id and utility_params_by_good_id are not None.\n        \"\"\"\n\n    @abstractmethod\n    def marginal_utility(self, ownership_state: OwnershipState, **kwargs: Any) -> float:\n        \"\"\"\n        Compute the marginal utility.\n\n        :param ownership_state: the ownership state against which to compute the marginal utility.\n        :param kwargs: optional keyword arguments\n        :return: the marginal utility score\n        \"\"\"\n\n    @abstractmethod\n    def utility_diff_from_transaction(\n        self, ownership_state: OwnershipState, terms: Terms\n    ) -> float:\n        \"\"\"\n        Simulate a transaction and get the resulting utility difference (taking into account the fee).\n\n        :param ownership_state: the ownership state against which to apply the transaction.\n        :param terms: the transaction terms.\n        :return: the score.\n        \"\"\"\n\n    @abstractmethod\n    def __copy__(self) -> \"Preferences\":\n        \"\"\"Copy the object.\"\"\"\n\n\nclass ProtectedQueue(Queue):\n    \"\"\"A wrapper of a queue to protect which object can read from it.\"\"\"\n\n    def __init__(self, access_code: str) -> None:\n        \"\"\"\n        Initialize the protected queue.\n\n        :param access_code: the access code to read from the queue\n        \"\"\"\n        super().__init__()\n        self._access_code_hash = _hash(access_code)\n\n    def put(  # pylint: disable=arguments-differ,arguments-renamed\n        self,\n        internal_message: Optional[Message],\n        block: bool = True,\n        timeout: Optional[float] = None,\n    ) -> None:\n        \"\"\"\n        Put an internal message on the queue.\n\n        If optional args block is true and timeout is None (the default),\n        block if necessary until a free slot is available. If timeout is\n        a positive number, it blocks at most timeout seconds and raises\n        the Full exception if no free slot was available within that time.\n        Otherwise (block is false), put an item on the queue if a free slot\n        is immediately available, else raise the Full exception (timeout is\n        ignored in that case).\n\n        :param internal_message: the internal message to put on the queue\n        :param block: whether to block or not\n        :param timeout: timeout on block\n        :raises: ValueError, if the item is not an internal message\n        \"\"\"\n        if not (isinstance(internal_message, Message) or internal_message is None):\n            raise ValueError(\"Only messages are allowed!\")\n        super().put(internal_message, block=True, timeout=None)\n\n    def put_nowait(  # pylint: disable=arguments-differ,arguments-renamed\n        self, internal_message: Optional[Message]\n    ) -> None:\n        \"\"\"\n        Put an internal message on the queue.\n\n        Equivalent to put(item, False).\n\n        :param internal_message: the internal message to put on the queue\n        :raises: ValueError, if the item is not an internal message\n        \"\"\"\n        if not (isinstance(internal_message, Message) or internal_message is None):\n            raise ValueError(\"Only messages are allowed!\")\n        super().put_nowait(internal_message)\n\n    def get(self, block: bool = True, timeout: Optional[float] = None) -> None:\n        \"\"\"\n        Inaccessible get method.\n\n        :param block: whether to block or not\n        :param timeout: timeout on block\n        :raises: ValueError, access not permitted.\n        \"\"\"\n        raise ValueError(\"Access not permitted!\")\n\n    def get_nowait(self) -> None:\n        \"\"\"\n        Inaccessible get_nowait method.\n\n        :raises: ValueError, access not permitted.\n        \"\"\"\n        raise ValueError(\"Access not permitted!\")\n\n    def protected_get(\n        self, access_code: str, block: bool = True, timeout: Optional[float] = None\n    ) -> Optional[Message]:\n        \"\"\"\n        Access protected get method.\n\n        :param access_code: the access code\n        :param block: If optional args block is true and timeout is None (the default), block if necessary until an item is available.\n        :param timeout: If timeout is a positive number, it blocks at most timeout seconds and raises the Empty exception if no item was available within that time.\n        :raises: ValueError, if caller is not permitted\n        :return: internal message\n        \"\"\"\n        if self._access_code_hash != _hash(access_code):\n            raise ValueError(\"Wrong code, access not permitted!\")\n        internal_message = super().get(\n            block=block, timeout=timeout\n        )  # type: Optional[Message]\n        return internal_message\n\n\nclass DecisionMakerHandler(WithLogger, ABC):\n    \"\"\"This class implements the decision maker.\"\"\"\n\n    __slots__ = (\"_identity\", \"_wallet\", \"_config\", \"_context\", \"_message_out_queue\")\n\n    self_address: str = \"decision_maker\"\n\n    def __init__(\n        self, identity: Identity, wallet: Wallet, config: Dict[str, Any], **kwargs: Any\n    ) -> None:\n        \"\"\"\n        Initialize the decision maker handler.\n\n        :param identity: the identity\n        :param wallet: the wallet\n        :param config: the user defined configuration of the handler\n        :param kwargs: the key word arguments\n        \"\"\"\n        logger = get_logger(__name__, identity.name)\n        WithLogger.__init__(self, logger=logger)\n        self._identity = identity\n        self._wallet = wallet\n        self._config = config\n        self._context = SimpleNamespace(**kwargs)\n        self._message_out_queue = AsyncFriendlyQueue()  # type: AsyncFriendlyQueue\n\n    @property\n    def agent_name(self) -> str:\n        \"\"\"Get the agent name.\"\"\"\n        return self.identity.name\n\n    @property\n    def identity(self) -> Identity:\n        \"\"\"Get identity of the agent.\"\"\"\n        return self._identity\n\n    @property\n    def wallet(self) -> Wallet:\n        \"\"\"Get wallet of the agent.\"\"\"\n        return self._wallet\n\n    @property\n    def config(self) -> Dict[str, Any]:\n        \"\"\"Get user defined configuration\"\"\"\n        return self._config\n\n    @property\n    def context(self) -> SimpleNamespace:\n        \"\"\"Get the context.\"\"\"\n        return self._context\n\n    @property\n    def message_out_queue(self) -> AsyncFriendlyQueue:\n        \"\"\"Get (out) queue.\"\"\"\n        return self._message_out_queue\n\n    @abstractmethod\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Handle an internal message from the skills.\n\n        :param message: the internal message\n        \"\"\"\n\n\nclass DecisionMaker(WithLogger):\n    \"\"\"This class implements the decision maker.\"\"\"\n\n    __slots__ = (\n        \"_queue_access_code\",\n        \"_message_in_queue\",\n        \"_decision_maker_handler\",\n        \"_thread\",\n        \"_lock\",\n        \"_message_out_queue\",\n        \"_stopped\",\n    )\n\n    def __init__(\n        self,\n        decision_maker_handler: DecisionMakerHandler,\n    ) -> None:\n        \"\"\"\n        Initialize the decision maker.\n\n        :param decision_maker_handler: the decision maker handler\n        \"\"\"\n        WithLogger.__init__(self, logger=decision_maker_handler.logger)\n        self._queue_access_code = uuid4().hex\n        self._message_in_queue = ProtectedQueue(\n            self._queue_access_code\n        )  # type: ProtectedQueue\n        self._decision_maker_handler = decision_maker_handler\n        self._thread = None  # type: Optional[Thread]\n        self._lock = threading.Lock()\n        self._message_out_queue = decision_maker_handler.message_out_queue\n        self._stopped = True\n\n    @property\n    def agent_name(self) -> str:\n        \"\"\"Get the agent name.\"\"\"\n        return self.decision_maker_handler.identity.name\n\n    @property\n    def message_in_queue(self) -> ProtectedQueue:\n        \"\"\"Get (in) queue.\"\"\"\n        return self._message_in_queue\n\n    @property\n    def message_out_queue(self) -> AsyncFriendlyQueue:\n        \"\"\"Get (out) queue.\"\"\"\n        return self._message_out_queue\n\n    @property\n    def decision_maker_handler(self) -> DecisionMakerHandler:\n        \"\"\"Get the decision maker handler.\"\"\"\n        return self._decision_maker_handler\n\n    def start(self) -> None:\n        \"\"\"Start the decision maker.\"\"\"\n        with self._lock:\n            if not self._stopped:  # pragma: no cover\n                self.logger.debug(\n                    \"[{}]: Decision maker already started.\".format(self.agent_name)\n                )\n                return\n\n            self._stopped = False\n            self._thread = Thread(target=self.execute, name=self.__class__.__name__)\n            self._thread.start()\n\n    def stop(self) -> None:\n        \"\"\"Stop the decision maker.\"\"\"\n        with self._lock:\n            self._stopped = True\n            self.message_in_queue.put(None)\n            if self._thread is not None:\n                self._thread.join()\n            self.logger.debug(\"[{}]: Decision Maker stopped.\".format(self.agent_name))\n            self._thread = None\n\n    def execute(self) -> None:\n        \"\"\"\n        Execute the decision maker.\n\n        Performs the following while not stopped:\n\n        - gets internal messages from the in queue and calls handle() on them\n        \"\"\"\n        while not self._stopped:\n            message = self.message_in_queue.protected_get(\n                self._queue_access_code, block=True\n            )  # type: Optional[Message]\n\n            if message is None:\n                self.logger.debug(\n                    \"[{}]: Received empty message. Quitting the processing loop...\".format(\n                        self.agent_name\n                    )\n                )\n                continue\n\n            self.handle(message)\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Handle an internal message from the skills.\n\n        :param message: the internal message\n        \"\"\"\n        self.decision_maker_handler.handle(message)\n"
  },
  {
    "path": "aea/decision_maker/default.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the decision maker class.\"\"\"\n\nfrom typing import Any, Dict\n\nfrom aea.common import Address\nfrom aea.crypto.wallet import Wallet\nfrom aea.decision_maker.base import DecisionMakerHandler as BaseDecisionMakerHandler\nfrom aea.helpers.transaction.base import SignedMessage, SignedTransaction\nfrom aea.identity.base import Identity\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\n\n\nclass DecisionMakerHandler(BaseDecisionMakerHandler):\n    \"\"\"This class implements the decision maker.\"\"\"\n\n    # pylint: disable=import-outside-toplevel\n    from packages.fetchai.protocols.signing.dialogues import (  # noqa: F811\n        SigningDialogue,\n    )\n    from packages.fetchai.protocols.signing.dialogues import (  # noqa: F811\n        SigningDialogues as BaseSigningDialogues,\n    )\n    from packages.fetchai.protocols.signing.message import SigningMessage  # noqa: F811\n\n    class SigningDialogues(BaseSigningDialogues):\n        \"\"\"This class keeps track of all oef_search dialogues.\"\"\"\n\n        def __init__(self, self_address: Address, **kwargs: Any) -> None:\n            \"\"\"\n            Initialize dialogues.\n\n            :param self_address: the address of the entity for whom dialogues are maintained\n            :param kwargs: the keyword arguments\n            \"\"\"\n\n            def role_from_first_message(  # pylint: disable=unused-argument\n                message: Message, receiver_address: Address\n            ) -> BaseDialogue.Role:\n                \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n                :param message: an incoming/outgoing first message\n                :param receiver_address: the address of the receiving agent\n                :return: The role of the agent\n                \"\"\"\n                from packages.fetchai.protocols.signing.dialogues import (  # pylint: disable=import-outside-toplevel\n                    SigningDialogue,\n                )\n\n                return SigningDialogue.Role.DECISION_MAKER\n\n            # pylint: disable=import-outside-toplevel\n            from packages.fetchai.protocols.signing.dialogues import (\n                SigningDialogues as BaseSigningDialogues,\n            )\n\n            BaseSigningDialogues.__init__(\n                self,\n                self_address=self_address,\n                role_from_first_message=role_from_first_message,\n                **kwargs,\n            )\n\n    signing_dialogue_class = SigningDialogue\n    signing_msg_class = SigningMessage\n\n    __slots__ = (\"signing_dialogues\",)\n\n    def __init__(\n        self, identity: Identity, wallet: Wallet, config: Dict[str, Any]\n    ) -> None:\n        \"\"\"\n        Initialize the decision maker.\n\n        :param identity: the identity\n        :param wallet: the wallet\n        :param config: the user defined configuration of the handler\n        \"\"\"\n        kwargs: Dict[str, Any] = {}\n        super().__init__(\n            identity=identity,\n            wallet=wallet,\n            config=config,\n            **kwargs,\n        )\n        self.signing_dialogues = DecisionMakerHandler.SigningDialogues(\n            self.self_address\n        )\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Handle an internal message from the skills.\n\n        :param message: the internal message\n        \"\"\"\n        if isinstance(message, self.signing_msg_class):\n            self._handle_signing_message(message)\n        else:  # pragma: no cover\n            self.logger.error(\n                \"[{}]: cannot handle message={} of type={}\".format(\n                    self.agent_name, message, type(message)\n                )\n            )\n\n    def _handle_signing_message(self, signing_msg: SigningMessage) -> None:\n        \"\"\"\n        Handle a signing message.\n\n        :param signing_msg: the transaction message\n        \"\"\"\n        signing_dialogue = self.signing_dialogues.update(signing_msg)  # type: ignore\n        if signing_dialogue is None or not isinstance(\n            signing_dialogue, self.signing_dialogue_class\n        ):  # pragma: no cover\n            self.logger.error(\n                \"[{}]: Could not construct signing dialogue. Aborting!\".format(\n                    self.agent_name\n                )\n            )\n            return\n\n        if signing_msg.performative == self.signing_msg_class.Performative.SIGN_MESSAGE:\n            self._handle_message_signing(signing_msg, signing_dialogue)\n        elif (\n            signing_msg.performative\n            == self.signing_msg_class.Performative.SIGN_TRANSACTION\n        ):\n            self._handle_transaction_signing(signing_msg, signing_dialogue)\n        else:  # pragma: no cover\n            self.logger.error(\n                \"[{}]: Unexpected transaction message performative\".format(\n                    self.agent_name\n                )\n            )\n\n    def _handle_message_signing(\n        self, signing_msg: SigningMessage, signing_dialogue: SigningDialogue\n    ) -> None:\n        \"\"\"\n        Handle a message for signing.\n\n        :param signing_msg: the signing message\n        :param signing_dialogue: the signing dialogue\n        \"\"\"\n        performative = self.signing_msg_class.Performative.ERROR\n        kwargs = {\n            \"error_code\": self.signing_msg_class.ErrorCode.UNSUCCESSFUL_MESSAGE_SIGNING,\n        }  # type: Dict[str, Any]\n        signed_message = self.wallet.sign_message(\n            signing_msg.raw_message.ledger_id,\n            signing_msg.raw_message.body,\n            signing_msg.raw_message.is_deprecated_mode,\n        )\n        if signed_message is not None:\n            performative = self.signing_msg_class.Performative.SIGNED_MESSAGE\n            kwargs.pop(\"error_code\")\n            kwargs[\"signed_message\"] = SignedMessage(\n                signing_msg.raw_message.ledger_id,\n                signed_message,\n                signing_msg.raw_message.is_deprecated_mode,\n            )\n        signing_msg_response = signing_dialogue.reply(\n            performative=performative,\n            target_message=signing_msg,\n            **kwargs,\n        )\n        self.message_out_queue.put(signing_msg_response)\n\n    def _handle_transaction_signing(\n        self, signing_msg: SigningMessage, signing_dialogue: SigningDialogue\n    ) -> None:\n        \"\"\"\n        Handle a transaction for signing.\n\n        :param signing_msg: the signing message\n        :param signing_dialogue: the signing dialogue\n        \"\"\"\n        performative = self.signing_msg_class.Performative.ERROR\n        kwargs = {\n            \"error_code\": self.signing_msg_class.ErrorCode.UNSUCCESSFUL_TRANSACTION_SIGNING,\n        }  # type: Dict[str, Any]\n        signed_tx = self.wallet.sign_transaction(\n            signing_msg.raw_transaction.ledger_id, signing_msg.raw_transaction.body\n        )\n        if signed_tx is not None:\n            performative = self.signing_msg_class.Performative.SIGNED_TRANSACTION\n            kwargs.pop(\"error_code\")\n            kwargs[\"signed_transaction\"] = SignedTransaction(\n                signing_msg.raw_transaction.ledger_id, signed_tx\n            )\n        signing_msg_response = signing_dialogue.reply(\n            performative=performative,\n            target_message=signing_msg,\n            **kwargs,\n        )\n        self.message_out_queue.put(signing_msg_response)\n"
  },
  {
    "path": "aea/decision_maker/gop.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the decision maker class.\"\"\"\n\nimport copy\nimport logging\nfrom enum import Enum\nfrom typing import Any, Dict, List, Optional, cast\n\nfrom aea.common import Address\nfrom aea.crypto.wallet import Wallet\nfrom aea.decision_maker.base import DecisionMakerHandler as BaseDecisionMakerHandler\nfrom aea.decision_maker.base import OwnershipState as BaseOwnershipState\nfrom aea.decision_maker.base import Preferences as BasePreferences\nfrom aea.exceptions import enforce\nfrom aea.helpers.preference_representations.base import (\n    linear_utility,\n    logarithmic_utility,\n)\nfrom aea.helpers.transaction.base import SignedMessage, SignedTransaction, Terms\nfrom aea.identity.base import Identity\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\n\n\nCurrencyHoldings = Dict[str, int]  # a map from identifier to quantity\nGoodHoldings = Dict[str, int]  # a map from identifier to quantity\nUtilityParams = Dict[str, float]  # a map from identifier to quantity\nExchangeParams = Dict[str, float]  # a map from identifier to quantity\n\n_default_logger = logging.getLogger(__name__)\n\n\nclass GoalPursuitReadiness:\n    \"\"\"The goal pursuit readiness.\"\"\"\n\n    __slots__ = (\"_status\",)\n\n    class Status(Enum):\n        \"\"\"\n        The enum of the readiness status.\n\n        In particular, it can be one of the following:\n\n        - Status.READY: when the agent is ready to pursuit its goal\n        - Status.NOT_READY: when the agent is not ready to pursuit its goal\n        \"\"\"\n\n        READY = \"ready\"\n        NOT_READY = \"not_ready\"\n\n    def __init__(self) -> None:\n        \"\"\"Instantiate the goal pursuit readiness.\"\"\"\n        self._status = GoalPursuitReadiness.Status.NOT_READY\n\n    @property\n    def is_ready(self) -> bool:\n        \"\"\"Get the readiness.\"\"\"\n        return self._status.value == GoalPursuitReadiness.Status.READY.value\n\n    def update(self, new_status: Status) -> None:\n        \"\"\"\n        Update the goal pursuit readiness.\n\n        :param new_status: the new status\n        \"\"\"\n        self._status = new_status\n\n\nclass OwnershipState(BaseOwnershipState):\n    \"\"\"Represent the ownership state of an agent (can proxy a ledger).\"\"\"\n\n    __slots__ = (\"_amount_by_currency_id\", \"_quantities_by_good_id\")\n\n    def __init__(self) -> None:\n        \"\"\"Instantiate an ownership state object.\"\"\"\n        self._amount_by_currency_id = None  # type: Optional[CurrencyHoldings]\n        self._quantities_by_good_id = None  # type: Optional[GoodHoldings]\n\n    def set(  # pylint: disable=arguments-differ,arguments-renamed\n        self,\n        amount_by_currency_id: CurrencyHoldings = None,\n        quantities_by_good_id: GoodHoldings = None,\n        **kwargs: Any,\n    ) -> None:\n        \"\"\"\n        Set values on the ownership state.\n\n        :param amount_by_currency_id: the currency endowment of the agent in this state.\n        :param quantities_by_good_id: the good endowment of the agent in this state.\n        :param kwargs: the keyword arguments.\n        \"\"\"\n        if amount_by_currency_id is None:  # pragma: nocover\n            raise ValueError(\"Must provide amount_by_currency_id.\")\n        if quantities_by_good_id is None:  # pragma: nocover\n            raise ValueError(\"Must provide quantities_by_good_id.\")\n        enforce(\n            not self.is_initialized,\n            \"Cannot apply state update, current state is already initialized!\",\n        )\n\n        self._amount_by_currency_id = copy.copy(amount_by_currency_id)\n        self._quantities_by_good_id = copy.copy(quantities_by_good_id)\n\n    def apply_delta(  # pylint: disable=arguments-differ,arguments-renamed\n        self,\n        delta_amount_by_currency_id: Dict[str, int] = None,\n        delta_quantities_by_good_id: Dict[str, int] = None,\n        **kwargs: Any,\n    ) -> None:\n        \"\"\"\n        Apply a state update to the ownership state.\n\n        This method is used to apply a raw state update without a transaction.\n\n        :param delta_amount_by_currency_id: the delta in the currency amounts\n        :param delta_quantities_by_good_id: the delta in the quantities by good\n        :param kwargs: the keyword arguments\n        \"\"\"\n        if delta_amount_by_currency_id is None:  # pragma: nocover\n            raise ValueError(\"Must provide delta_amount_by_currency_id.\")\n        if delta_quantities_by_good_id is None:  # pragma: nocover\n            raise ValueError(\"Must provide delta_quantities_by_good_id.\")\n        if self._amount_by_currency_id is None or self._quantities_by_good_id is None:\n            raise ValueError(  # pragma: nocover\n                \"Cannot apply state update, current state is not initialized!\"\n            )\n        enforce(\n            all(\n                (\n                    key in self._amount_by_currency_id\n                    for key in delta_amount_by_currency_id.keys()\n                )\n            ),\n            \"Invalid keys present in delta_amount_by_currency_id.\",\n        )\n        enforce(\n            all(\n                (\n                    key in self._quantities_by_good_id\n                    for key in delta_quantities_by_good_id.keys()\n                )\n            ),\n            \"Invalid keys present in delta_quantities_by_good_id.\",\n        )\n\n        for currency_id, amount_delta in delta_amount_by_currency_id.items():\n            self._amount_by_currency_id[currency_id] += amount_delta\n\n        for good_id, quantity_delta in delta_quantities_by_good_id.items():\n            self._quantities_by_good_id[good_id] += quantity_delta\n\n    @property\n    def is_initialized(self) -> bool:\n        \"\"\"Get the initialization status.\"\"\"\n        return (\n            self._amount_by_currency_id is not None\n            and self._quantities_by_good_id is not None\n        )\n\n    @property\n    def amount_by_currency_id(self) -> CurrencyHoldings:\n        \"\"\"Get currency holdings in this state.\"\"\"\n        if self._amount_by_currency_id is None:\n            raise ValueError(\"amount_by_currency_id is not set!\")\n        return copy.copy(self._amount_by_currency_id)\n\n    @property\n    def quantities_by_good_id(self) -> GoodHoldings:\n        \"\"\"Get good holdings in this state.\"\"\"\n        if self._quantities_by_good_id is None:\n            raise ValueError(\"quantities_by_good_id is not set!\")\n        return copy.copy(self._quantities_by_good_id)\n\n    def is_affordable_transaction(self, terms: Terms) -> bool:\n        \"\"\"\n        Check if the transaction is affordable (and consistent).\n\n        E.g. check that the agent state has enough money if it is a buyer or enough holdings if it is a seller.\n        Note, the agent is the sender of the transaction message by design.\n\n        :param terms: the transaction terms\n        :return: True if the transaction is legal wrt the current state, false otherwise.\n        \"\"\"\n        if all(amount == 0 for amount in terms.amount_by_currency_id.values()) and all(\n            quantity == 0 for quantity in terms.quantities_by_good_id.values()\n        ):\n            # reject the transaction when there is no wealth exchange\n            result = False\n        elif all(\n            amount <= 0 for amount in terms.amount_by_currency_id.values()\n        ) and all(quantity >= 0 for quantity in terms.quantities_by_good_id.values()):\n            # check if the agent has the money to cover the sender_amount (the agent=sender is the buyer)\n            result = all(\n                self.amount_by_currency_id[currency_id] >= -amount\n                for currency_id, amount in terms.amount_by_currency_id.items()\n            )\n        elif all(\n            amount >= 0 for amount in terms.amount_by_currency_id.values()\n        ) and all(quantity <= 0 for quantity in terms.quantities_by_good_id.values()):\n            # check if the agent has the goods (the agent=sender is the seller).\n            result = all(\n                self.quantities_by_good_id[good_id] >= -quantity\n                for good_id, quantity in terms.quantities_by_good_id.items()\n            )\n        else:\n            result = False\n        return result\n\n    def is_affordable(self, terms: Terms) -> bool:\n        \"\"\"\n        Check if the tx is affordable.\n\n        :param terms: the transaction terms\n        :return: whether the transaction is affordable or not\n        \"\"\"\n        if self.is_initialized:\n            is_affordable = self.is_affordable_transaction(terms)\n        else:\n            _default_logger.debug(\n                \"Cannot verify whether transaction is affordable as ownership state is not initialized. Assuming it is!\"\n            )\n            is_affordable = True\n        return is_affordable\n\n    def update(self, terms: Terms) -> None:\n        \"\"\"\n        Update the agent state from a transaction.\n\n        :param terms: the transaction terms\n        \"\"\"\n        if self._amount_by_currency_id is None or self._quantities_by_good_id is None:\n            raise ValueError(  # pragma: nocover\n                \"Cannot apply state update, current state is not initialized!\"\n            )\n        for currency_id, amount_delta in terms.amount_by_currency_id.items():\n            self._amount_by_currency_id[currency_id] += amount_delta\n\n        for good_id, quantity_delta in terms.quantities_by_good_id.items():\n            self._quantities_by_good_id[good_id] += quantity_delta\n\n    def apply_transactions(self, list_of_terms: List[Terms]) -> \"OwnershipState\":\n        \"\"\"\n        Apply a list of transactions to (a copy of) the current state.\n\n        :param list_of_terms: the sequence of transaction terms.\n        :return: the final state.\n        \"\"\"\n        new_state = copy.copy(self)\n        for terms in list_of_terms:\n            new_state.update(terms)\n\n        return new_state\n\n    def __copy__(self) -> \"OwnershipState\":\n        \"\"\"Copy the object.\"\"\"\n        state = OwnershipState()\n        if self.is_initialized:\n            state._amount_by_currency_id = self.amount_by_currency_id\n            state._quantities_by_good_id = self.quantities_by_good_id\n        return state\n\n\nclass Preferences(BasePreferences):\n    \"\"\"Class to represent the preferences.\"\"\"\n\n    __slots__ = (\"_exchange_params_by_currency_id\", \"_utility_params_by_good_id\")\n\n    def __init__(self) -> None:\n        \"\"\"Instantiate an agent preference object.\"\"\"\n        self._exchange_params_by_currency_id = None  # type: Optional[ExchangeParams]\n        self._utility_params_by_good_id = None  # type: Optional[UtilityParams]\n\n    def set(  # pylint: disable=arguments-differ,arguments-renamed\n        self,\n        exchange_params_by_currency_id: ExchangeParams = None,\n        utility_params_by_good_id: UtilityParams = None,\n        **kwargs: Any,\n    ) -> None:\n        \"\"\"\n        Set values on the preferences.\n\n        :param exchange_params_by_currency_id: the exchange params.\n        :param utility_params_by_good_id: the utility params for every asset.\n        :param kwargs: the keyword arguments.\n        \"\"\"\n        if exchange_params_by_currency_id is None:  # pragma: nocover\n            raise ValueError(\"Must provide exchange_params_by_currency_id.\")\n        if utility_params_by_good_id is None:  # pragma: nocover\n            raise ValueError(\"Must provide utility_params_by_good_id.\")\n        enforce(\n            not self.is_initialized,\n            \"Cannot apply preferences update, preferences already initialized!\",\n        )\n\n        self._exchange_params_by_currency_id = copy.copy(exchange_params_by_currency_id)\n        self._utility_params_by_good_id = copy.copy(utility_params_by_good_id)\n\n    @property\n    def is_initialized(self) -> bool:\n        \"\"\"\n        Get the initialization status.\n\n        :return: True if exchange_params_by_currency_id and utility_params_by_good_id are not None.\n        \"\"\"\n        return (self._exchange_params_by_currency_id is not None) and (\n            self._utility_params_by_good_id is not None\n        )\n\n    @property\n    def exchange_params_by_currency_id(self) -> ExchangeParams:\n        \"\"\"Get exchange parameter for each currency.\"\"\"\n        if self._exchange_params_by_currency_id is None:\n            raise ValueError(\"ExchangeParams not set!\")\n        return self._exchange_params_by_currency_id\n\n    @property\n    def utility_params_by_good_id(self) -> UtilityParams:\n        \"\"\"Get utility parameter for each good.\"\"\"\n        if self._utility_params_by_good_id is None:\n            raise ValueError(\"UtilityParams not set!\")\n        return self._utility_params_by_good_id\n\n    def logarithmic_utility(self, quantities_by_good_id: GoodHoldings) -> float:\n        \"\"\"\n        Compute agent's utility given her utility function params and a good bundle.\n\n        :param quantities_by_good_id: the good holdings (dictionary) with the identifier (key) and quantity (value) for each good\n        :return: utility value\n        \"\"\"\n        enforce(self.is_initialized, \"Preferences params not set!\")\n        result = logarithmic_utility(\n            self.utility_params_by_good_id,\n            quantities_by_good_id,\n        )\n        return result\n\n    def linear_utility(self, amount_by_currency_id: CurrencyHoldings) -> float:\n        \"\"\"\n        Compute agent's utility given her utility function params and a currency bundle.\n\n        :param amount_by_currency_id: the currency holdings (dictionary) with the identifier (key) and quantity (value) for each currency\n        :return: utility value\n        \"\"\"\n        enforce(self.is_initialized, \"Preferences params not set!\")\n        result = linear_utility(\n            self.exchange_params_by_currency_id, amount_by_currency_id\n        )\n        return result\n\n    def utility(\n        self,\n        quantities_by_good_id: GoodHoldings,\n        amount_by_currency_id: CurrencyHoldings,\n    ) -> float:\n        \"\"\"\n        Compute the utility given the good and currency holdings.\n\n        :param quantities_by_good_id: the good holdings\n        :param amount_by_currency_id: the currency holdings\n        :return: the utility value.\n        \"\"\"\n        enforce(self.is_initialized, \"Preferences params not set!\")\n        goods_score = self.logarithmic_utility(quantities_by_good_id)\n        currency_score = self.linear_utility(amount_by_currency_id)\n        score = goods_score + currency_score\n        return score\n\n    def marginal_utility(  # pylint: disable=arguments-differ,arguments-renamed\n        self,\n        ownership_state: BaseOwnershipState,\n        delta_quantities_by_good_id: Optional[GoodHoldings] = None,\n        delta_amount_by_currency_id: Optional[CurrencyHoldings] = None,\n        **kwargs: Any,\n    ) -> float:\n        \"\"\"\n        Compute the marginal utility.\n\n        :param ownership_state: the ownership state against which to compute the marginal utility.\n        :param delta_quantities_by_good_id: the change in good holdings\n        :param delta_amount_by_currency_id: the change in money holdings\n        :param kwargs: the keyword arguments\n        :return: the marginal utility score\n        \"\"\"\n        enforce(self.is_initialized, \"Preferences params not set!\")\n        ownership_state = cast(OwnershipState, ownership_state)\n        current_goods_score = self.logarithmic_utility(\n            ownership_state.quantities_by_good_id\n        )\n        current_currency_score = self.linear_utility(\n            ownership_state.amount_by_currency_id\n        )\n        new_goods_score = current_goods_score\n        new_currency_score = current_currency_score\n        if delta_quantities_by_good_id is not None:\n            new_quantities_by_good_id = {\n                good_id: quantity + delta_quantities_by_good_id[good_id]\n                for good_id, quantity in ownership_state.quantities_by_good_id.items()\n            }\n            new_goods_score = self.logarithmic_utility(new_quantities_by_good_id)\n        if delta_amount_by_currency_id is not None:\n            new_amount_by_currency_id = {\n                currency: amount + delta_amount_by_currency_id[currency]\n                for currency, amount in ownership_state.amount_by_currency_id.items()\n            }\n            new_currency_score = self.linear_utility(new_amount_by_currency_id)\n        marginal_utility = (\n            new_goods_score\n            + new_currency_score\n            - current_goods_score\n            - current_currency_score\n        )\n        return marginal_utility\n\n    def utility_diff_from_transaction(\n        self, ownership_state: BaseOwnershipState, terms: Terms\n    ) -> float:\n        \"\"\"\n        Simulate a transaction and get the resulting utility difference (taking into account the fee).\n\n        :param ownership_state: the ownership state against which to apply the transaction.\n        :param terms: the transaction terms.\n        :return: the score.\n        \"\"\"\n        enforce(self.is_initialized, \"Preferences params not set!\")\n        ownership_state = cast(OwnershipState, ownership_state)\n        current_score = self.utility(\n            quantities_by_good_id=ownership_state.quantities_by_good_id,\n            amount_by_currency_id=ownership_state.amount_by_currency_id,\n        )\n        new_ownership_state = ownership_state.apply_transactions([terms])\n        new_score = self.utility(\n            quantities_by_good_id=new_ownership_state.quantities_by_good_id,\n            amount_by_currency_id=new_ownership_state.amount_by_currency_id,\n        )\n        score_difference = new_score - current_score\n        return score_difference\n\n    def is_utility_enhancing(\n        self, ownership_state: BaseOwnershipState, terms: Terms\n    ) -> bool:\n        \"\"\"\n        Check if the tx is utility enhancing.\n\n        :param ownership_state: the ownership state against which to apply the transaction.\n        :param terms: the transaction terms\n        :return: whether the transaction is utility enhancing or not\n        \"\"\"\n        if self.is_initialized and ownership_state.is_initialized:\n            is_utility_enhancing = (\n                self.utility_diff_from_transaction(ownership_state, terms) >= 0.0\n            )\n        else:\n            _default_logger.debug(\n                \"Cannot verify whether transaction improves utility as preferences are not initialized. Assuming it does!\"\n            )\n            is_utility_enhancing = True\n        return is_utility_enhancing\n\n    def __copy__(self) -> \"Preferences\":\n        \"\"\"Copy the object.\"\"\"\n        preferences = Preferences()\n        if self.is_initialized:\n            preferences._exchange_params_by_currency_id = (\n                self.exchange_params_by_currency_id\n            )\n            preferences._utility_params_by_good_id = self.utility_params_by_good_id\n        return preferences\n\n\nclass DecisionMakerHandler(BaseDecisionMakerHandler):\n    \"\"\"This class implements the decision maker.\"\"\"\n\n    # pylint: disable=import-outside-toplevel\n    from packages.fetchai.protocols.signing.dialogues import (  # noqa: F811\n        SigningDialogue,\n    )\n    from packages.fetchai.protocols.signing.dialogues import (  # noqa: F811\n        SigningDialogues as BaseSigningDialogues,\n    )\n    from packages.fetchai.protocols.signing.message import SigningMessage  # noqa: F811\n    from packages.fetchai.protocols.state_update.dialogues import (  # noqa: F811\n        StateUpdateDialogue,\n    )\n    from packages.fetchai.protocols.state_update.dialogues import (  # noqa: F811\n        StateUpdateDialogues as BaseStateUpdateDialogues,\n    )\n    from packages.fetchai.protocols.state_update.message import (  # noqa: F811\n        StateUpdateMessage,\n    )\n\n    signing_dialogues_class = SigningDialogue\n    signing_msg_class = SigningMessage\n    state_update_dialogue_class = StateUpdateDialogue\n    state_update_msg_class = StateUpdateMessage\n\n    class SigningDialogues(BaseSigningDialogues):\n        \"\"\"This class keeps track of all oef_search dialogues.\"\"\"\n\n        def __init__(self, self_address: Address, **kwargs: Any) -> None:\n            \"\"\"\n            Initialize dialogues.\n\n            :param self_address: the address of the entity for whom dialogues are maintained\n            :param kwargs: the keyword arguments\n            \"\"\"\n\n            def role_from_first_message(  # pylint: disable=unused-argument\n                message: Message, receiver_address: Address\n            ) -> BaseDialogue.Role:\n                \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n                :param message: an incoming/outgoing first message\n                :param receiver_address: the address of the receiving agent\n                :return: The role of the agent\n                \"\"\"\n                from packages.fetchai.protocols.signing.dialogues import (  # pylint: disable=import-outside-toplevel\n                    SigningDialogue,\n                )\n\n                return SigningDialogue.Role.DECISION_MAKER\n\n            # pylint: disable=import-outside-toplevel\n            from packages.fetchai.protocols.signing.dialogues import (\n                SigningDialogues as BaseSigningDialogues,\n            )\n\n            BaseSigningDialogues.__init__(\n                self,\n                self_address=self_address,\n                role_from_first_message=role_from_first_message,\n                **kwargs,\n            )\n\n    class StateUpdateDialogues(BaseStateUpdateDialogues):\n        \"\"\"This class keeps track of all oef_search dialogues.\"\"\"\n\n        def __init__(self, self_address: Address, **kwargs: Any) -> None:\n            \"\"\"\n            Initialize dialogues.\n\n            :param self_address: the address of the entity for whom dialogues are maintained\n            :param kwargs: the keyword arguments\n            \"\"\"\n\n            def role_from_first_message(  # pylint: disable=unused-argument\n                message: Message, receiver_address: Address\n            ) -> BaseDialogue.Role:\n                \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n                :param message: an incoming/outgoing first message\n                :param receiver_address: the address of the receiving agent\n                :return: The role of the agent\n                \"\"\"\n                from packages.fetchai.protocols.state_update.dialogues import (  # noqa: F811 # pylint: disable=import-outside-toplevel\n                    StateUpdateDialogue,\n                )\n\n                return StateUpdateDialogue.Role.DECISION_MAKER\n\n            # pylint: disable=import-outside-toplevel\n            from packages.fetchai.protocols.state_update.dialogues import (  # noqa: F401\n                StateUpdateDialogues as BaseStateUpdateDialogues,\n            )\n\n            BaseStateUpdateDialogues.__init__(\n                self,\n                self_address=self_address,\n                role_from_first_message=role_from_first_message,\n                **kwargs,\n            )\n\n    __slots__ = (\"signing_dialogues\", \"state_update_dialogues\")\n\n    def __init__(\n        self, identity: Identity, wallet: Wallet, config: Dict[str, Any]\n    ) -> None:\n        \"\"\"\n        Initialize the decision maker.\n\n        :param identity: the identity\n        :param wallet: the wallet\n        :param config: the user defined configuration of the handler\n        \"\"\"\n        kwargs: Dict[str, Any] = {\n            \"goal_pursuit_readiness\": GoalPursuitReadiness(),\n            \"ownership_state\": OwnershipState(),\n            \"preferences\": Preferences(),\n        }\n        super().__init__(identity=identity, wallet=wallet, config=config, **kwargs)\n        self.signing_dialogues = DecisionMakerHandler.SigningDialogues(\n            self.self_address\n        )\n        self.state_update_dialogues = DecisionMakerHandler.StateUpdateDialogues(\n            self.self_address\n        )\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Handle an internal message from the skills.\n\n        :param message: the internal message\n        \"\"\"\n        if isinstance(message, self.signing_msg_class):\n            self._handle_signing_message(message)\n        elif isinstance(message, self.state_update_msg_class):\n            self._handle_state_update_message(message)\n        else:  # pragma: no cover\n            self.logger.error(\n                \"[{}]: cannot handle message={} of type={}\".format(\n                    self.agent_name, message, type(message)\n                )\n            )\n\n    def _handle_signing_message(self, signing_msg: SigningMessage) -> None:\n        \"\"\"\n        Handle a signing message.\n\n        :param signing_msg: the transaction message\n        \"\"\"\n        if not self.context.goal_pursuit_readiness.is_ready:\n            self.logger.debug(\n                \"[{}]: Preferences and ownership state not initialized!\".format(\n                    self.agent_name\n                )\n            )\n\n        signing_dialogue = self.signing_dialogues.update(signing_msg)\n        if signing_dialogue is None or not isinstance(\n            signing_dialogue, self.signing_dialogues_class\n        ):  # pragma: no cover\n            self.logger.error(\n                \"[{}]: Could not construct signing dialogue. Aborting!\".format(\n                    self.agent_name\n                )\n            )\n            return\n\n        # check if the transaction is acceptable and process it accordingly\n        if signing_msg.performative == self.signing_msg_class.Performative.SIGN_MESSAGE:\n            self._handle_message_signing(signing_msg, signing_dialogue)\n        elif (\n            signing_msg.performative\n            == self.signing_msg_class.Performative.SIGN_TRANSACTION\n        ):\n            self._handle_transaction_signing(signing_msg, signing_dialogue)\n        else:  # pragma: no cover\n            self.logger.error(\n                \"[{}]: Unexpected transaction message performative\".format(\n                    self.agent_name\n                )\n            )\n\n    def _handle_message_signing(\n        self, signing_msg: SigningMessage, signing_dialogue: SigningDialogue\n    ) -> None:\n        \"\"\"\n        Handle a message for signing.\n\n        :param signing_msg: the signing message\n        :param signing_dialogue: the signing dialogue\n        \"\"\"\n        performative = self.signing_msg_class.Performative.ERROR\n        kwargs = {\n            \"error_code\": self.signing_msg_class.ErrorCode.UNSUCCESSFUL_MESSAGE_SIGNING,\n        }  # type: Dict[str, Any]\n        if self._is_acceptable_for_signing(signing_msg):\n            signed_message = self.wallet.sign_message(\n                signing_msg.raw_message.ledger_id,\n                signing_msg.raw_message.body,\n                signing_msg.raw_message.is_deprecated_mode,\n            )\n            if signed_message is not None:\n                performative = self.signing_msg_class.Performative.SIGNED_MESSAGE\n                kwargs.pop(\"error_code\")\n                kwargs[\"signed_message\"] = SignedMessage(\n                    signing_msg.raw_message.ledger_id,\n                    signed_message,\n                    signing_msg.raw_message.is_deprecated_mode,\n                )\n        signing_msg_response = signing_dialogue.reply(\n            performative=performative,\n            target_message=signing_msg,\n            **kwargs,\n        )\n        self.message_out_queue.put(signing_msg_response)\n\n    def _handle_transaction_signing(\n        self, signing_msg: SigningMessage, signing_dialogue: SigningDialogue\n    ) -> None:\n        \"\"\"\n        Handle a transaction for signing.\n\n        :param signing_msg: the signing message\n        :param signing_dialogue: the signing dialogue\n        \"\"\"\n        performative = self.signing_msg_class.Performative.ERROR\n        kwargs = {\n            \"error_code\": self.signing_msg_class.ErrorCode.UNSUCCESSFUL_TRANSACTION_SIGNING,\n        }  # type: Dict[str, Any]\n        if self._is_acceptable_for_signing(signing_msg):\n            signed_tx = self.wallet.sign_transaction(\n                signing_msg.raw_transaction.ledger_id, signing_msg.raw_transaction.body\n            )\n            if signed_tx is not None:\n                performative = self.signing_msg_class.Performative.SIGNED_TRANSACTION\n                kwargs.pop(\"error_code\")\n                kwargs[\"signed_transaction\"] = SignedTransaction(\n                    signing_msg.raw_transaction.ledger_id, signed_tx\n                )\n        signing_msg_response = signing_dialogue.reply(\n            performative=performative,\n            target_message=signing_msg,\n            **kwargs,\n        )\n        self.message_out_queue.put(signing_msg_response)\n\n    def _is_acceptable_for_signing(self, signing_msg: SigningMessage) -> bool:\n        \"\"\"\n        Check if the tx message is acceptable for signing.\n\n        :param signing_msg: the transaction message\n        :return: whether the transaction is acceptable or not\n        \"\"\"\n        result = self.context.preferences.is_utility_enhancing(\n            self.context.ownership_state, signing_msg.terms\n        ) and self.context.ownership_state.is_affordable(signing_msg.terms)\n        return result\n\n    def _handle_state_update_message(\n        self, state_update_msg: StateUpdateMessage\n    ) -> None:\n        \"\"\"\n        Handle a state update message.\n\n        :param state_update_msg: the state update message\n        \"\"\"\n        state_update_dialogue = self.state_update_dialogues.update(state_update_msg)\n        if state_update_dialogue is None or not isinstance(\n            state_update_dialogue, self.state_update_dialogue_class\n        ):  # pragma: no cover\n            self.logger.error(\n                \"[{}]: Could not construct state_update dialogue. Aborting!\".format(\n                    self.agent_name\n                )\n            )\n            return\n\n        if (\n            state_update_msg.performative\n            == self.state_update_msg_class.Performative.INITIALIZE\n        ):\n            self.logger.info(\n                \"[{}]: Applying ownership_state and preferences initialization!\".format(\n                    self.agent_name\n                )\n            )\n            self.context.ownership_state.set(\n                amount_by_currency_id=state_update_msg.amount_by_currency_id,\n                quantities_by_good_id=state_update_msg.quantities_by_good_id,\n            )\n            self.context.preferences.set(\n                exchange_params_by_currency_id=state_update_msg.exchange_params_by_currency_id,\n                utility_params_by_good_id=state_update_msg.utility_params_by_good_id,\n            )\n            self.context.goal_pursuit_readiness.update(\n                GoalPursuitReadiness.Status.READY\n            )\n        elif (\n            state_update_msg.performative\n            == self.state_update_msg_class.Performative.APPLY\n        ):\n            self.logger.info(\"[{}]: Applying state update!\".format(self.agent_name))\n            self.context.ownership_state.apply_delta(\n                delta_amount_by_currency_id=state_update_msg.amount_by_currency_id,\n                delta_quantities_by_good_id=state_update_msg.quantities_by_good_id,\n            )\n"
  },
  {
    "path": "aea/decision_maker/scaffold.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains a scaffold of the decision maker class and auxiliary classes.\"\"\"\n\nfrom typing import Any, Dict\n\nfrom aea.crypto.wallet import Wallet\nfrom aea.decision_maker.base import DecisionMakerHandler as BaseDecisionMakerHandler\nfrom aea.identity.base import Identity\nfrom aea.protocols.base import Message\n\n\nclass DecisionMakerHandler(BaseDecisionMakerHandler):\n    \"\"\"This class implements the decision maker.\"\"\"\n\n    def __init__(\n        self, identity: Identity, wallet: Wallet, config: Dict[str, Any]\n    ) -> None:\n        \"\"\"\n        Initialize the decision maker.\n\n        :param identity: the identity\n        :param wallet: the wallet\n        :param config: the user defined configuration of the handler\n        \"\"\"\n        kwargs = {\n            # Add your objects here, they will be accessible in the `handle` method via `self.context`.\n            # They will also be accessible from the skill context.\n        }  # type: Dict[str, Any]\n        # You MUST NOT modify the constructor below:\n        super().__init__(\n            identity=identity,\n            wallet=wallet,\n            config=config,\n            **kwargs,\n        )\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Handle an internal message from the skills.\n\n        This method is used to:\n            - update the ownership state\n            - check transactions satisfy the preferences\n\n        :param message: the message\n        \"\"\"\n        raise NotImplementedError\n"
  },
  {
    "path": "aea/error_handler/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the error handler modules.\"\"\"\n"
  },
  {
    "path": "aea/error_handler/base.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the abstract error handler class.\"\"\"\nfrom abc import ABC, abstractmethod\nfrom logging import Logger\nfrom typing import Any, Dict\n\nfrom aea.mail.base import Envelope\n\n\nclass AbstractErrorHandler(ABC):\n    \"\"\"Error handler class for handling problematic envelopes.\"\"\"\n\n    __slots__ = (\"_config\",)\n\n    def __init__(self, **kwargs: Any):\n        \"\"\"Instantiate error handler.\"\"\"\n        self._config = kwargs\n\n    @property\n    def config(self) -> Dict[str, Any]:\n        \"\"\"Get handler config.\"\"\"\n        return self._config\n\n    @abstractmethod\n    def send_unsupported_protocol(self, envelope: Envelope, logger: Logger) -> None:\n        \"\"\"\n        Handle the received envelope in case the protocol is not supported.\n\n        :param envelope: the envelope\n        :param logger: the logger\n        :return: None\n        \"\"\"\n\n    @abstractmethod\n    def send_decoding_error(\n        self, envelope: Envelope, exception: Exception, logger: Logger\n    ) -> None:\n        \"\"\"\n        Handle a decoding error.\n\n        :param envelope: the envelope\n        :param exception: the exception raised during decoding\n        :param logger: the logger\n        :return: None\n        \"\"\"\n\n    @abstractmethod\n    def send_no_active_handler(\n        self, envelope: Envelope, reason: str, logger: Logger\n    ) -> None:\n        \"\"\"\n        Handle the received envelope in case the handler is not supported.\n\n        :param envelope: the envelope\n        :param reason: the reason for the failure\n        :param logger: the logger\n        :return: None\n        \"\"\"\n"
  },
  {
    "path": "aea/error_handler/default.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the default error handler class.\"\"\"\n\nfrom logging import Logger\nfrom typing import Any\n\nfrom aea.error_handler.base import AbstractErrorHandler\nfrom aea.mail.base import Envelope\n\n\nclass ErrorHandler(AbstractErrorHandler):\n    \"\"\"Error handler class for handling problematic envelopes.\"\"\"\n\n    __slots__ = (\n        \"unsupported_protocol_count\",\n        \"no_active_handler_count\",\n        \"decoding_error_count\",\n    )\n\n    def __init__(self, **kwargs: Any):\n        \"\"\"Instantiate error handler.\"\"\"\n        super().__init__(**kwargs)\n        self.unsupported_protocol_count = 0\n        self.no_active_handler_count = 0\n        self.decoding_error_count = 0\n\n    def send_unsupported_protocol(self, envelope: Envelope, logger: Logger) -> None:\n        \"\"\"\n        Handle the received envelope in case the protocol is not supported.\n\n        :param envelope: the envelope\n        :param logger: the logger\n        \"\"\"\n        self.unsupported_protocol_count += 1\n        logger.warning(\n            f\"Unsupported protocol: protocol_specification_id={envelope.protocol_specification_id}. You might want to add a handler for a protocol implementing this specification. Sender={envelope.sender}, to={envelope.sender}.\"\n        )\n\n    def send_decoding_error(\n        self, envelope: Envelope, exception: Exception, logger: Logger\n    ) -> None:\n        \"\"\"\n        Handle a decoding error.\n\n        :param envelope: the envelope\n        :param exception: the exception raised during decoding\n        :param logger: the logger\n        \"\"\"\n        self.decoding_error_count += 1\n        logger.warning(\n            f\"Decoding error for envelope: {envelope}. Protocol_specification_id='{envelope.protocol_specification_id}' and message are inconsistent. Sender={envelope.sender}, to={envelope.sender}. Exception={exception}.\"\n        )\n\n    def send_no_active_handler(\n        self, envelope: Envelope, reason: str, logger: Logger\n    ) -> None:\n        \"\"\"\n        Handle the received envelope in case the handler is not supported.\n\n        :param envelope: the envelope\n        :param reason: the reason for the failure\n        :param logger: the logger\n        \"\"\"\n        self.no_active_handler_count += 1\n        logger.warning(\n            f\"Cannot handle envelope: {reason}. Sender={envelope.sender}, to={envelope.sender}.\"\n        )\n"
  },
  {
    "path": "aea/error_handler/scaffold.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains a scaffold of the error handler class.\"\"\"\nfrom logging import Logger\n\nfrom aea.error_handler.base import AbstractErrorHandler\nfrom aea.mail.base import Envelope\n\n\nclass ErrorHandler(AbstractErrorHandler):\n    \"\"\"This class implements the error handler.\"\"\"\n\n    def send_unsupported_protocol(self, envelope: Envelope, logger: Logger) -> None:\n        \"\"\"\n        Handle the received envelope in case the protocol is not supported.\n\n        :param envelope: the envelope\n        :param logger: the logger\n        \"\"\"\n        raise NotImplementedError\n\n    def send_decoding_error(\n        self, envelope: Envelope, exception: Exception, logger: Logger\n    ) -> None:\n        \"\"\"\n        Handle a decoding error.\n\n        :param envelope: the envelope\n        :param exception: the exception raised during decoding\n        :param logger: the logger\n        \"\"\"\n        raise NotImplementedError\n\n    def send_no_active_handler(\n        self, envelope: Envelope, reason: str, logger: Logger\n    ) -> None:\n        \"\"\"\n        Handle the received envelope in case the handler is not supported.\n\n        :param envelope: the envelope\n        :param reason: the reason for the failure\n        :param logger: the logger\n        \"\"\"\n        raise NotImplementedError\n"
  },
  {
    "path": "aea/exceptions.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Exceptions for the AEA package.\"\"\"\n\nimport traceback\nfrom typing import Optional, Type\n\n\nclass AEAException(Exception):\n    \"\"\"User-defined exception for the AEA framework.\"\"\"\n\n\nclass AEAPackageLoadingError(AEAException):\n    \"\"\"Class for exceptions that are raised for loading errors of AEA packages.\"\"\"\n\n\nclass AEASetupError(AEAException):\n    \"\"\"Class for exceptions that are raised for setup errors of AEA packages.\"\"\"\n\n\nclass AEATeardownError(AEAException):\n    \"\"\"Class for exceptions that are raised for teardown errors of AEA packages.\"\"\"\n\n\nclass AEAActException(AEAException):\n    \"\"\"Class for exceptions that are raised for act errors of AEA packages.\"\"\"\n\n\nclass AEAHandleException(AEAException):\n    \"\"\"Class for exceptions that are raised for handler errors of AEA packages.\"\"\"\n\n\nclass AEAInstantiationException(AEAException):\n    \"\"\"Class for exceptions that are raised for instantiation errors of AEA packages.\"\"\"\n\n\nclass AEAPluginError(AEAException):\n    \"\"\"Class for exceptions that are raised for wrong plugin setup of the working set.\"\"\"\n\n\nclass AEAEnforceError(AEAException):\n    \"\"\"Class for enforcement errors.\"\"\"\n\n\nclass AEAValidationError(AEAException):\n    \"\"\"Class for validation errors of an AEA.\"\"\"\n\n\nclass AEAComponentLoadException(AEAException):\n    \"\"\"Class for component loading errors of an AEA.\"\"\"\n\n\nclass AEAWalletNoAddressException(AEAException):\n    \"\"\"Class for attempts to instantiate a wallet without addresses.\"\"\"\n\n\nclass _StopRuntime(Exception):\n    \"\"\"\n    Exception to stop runtime.\n\n    For internal usage only!\n    Used to perform asyncio call from sync callbacks.\n    \"\"\"\n\n    def __init__(self, reraise: Optional[Exception] = None) -> None:\n        \"\"\"\n        Init _StopRuntime exception.\n\n        :param reraise: exception to reraise.\n        \"\"\"\n        self.reraise = reraise\n        super().__init__(\"Stop runtime exception.\")\n\n\ndef enforce(\n    is_valid_condition: bool,\n    exception_text: str,\n    exception_class: Type[Exception] = AEAEnforceError,\n) -> None:\n    \"\"\"\n    Evaluate a condition and raise an exception with the provided text if it is not satisfied.\n\n    :param is_valid_condition: the valid condition\n    :param exception_text: the exception to be raised\n    :param exception_class: the class of exception\n    \"\"\"\n    if not is_valid_condition:\n        raise exception_class(exception_text)\n\n\ndef parse_exception(exception: Exception, limit: int = -1) -> str:\n    \"\"\"\n    Parse an exception to get the relevant lines.\n\n    :param exception: the exception to be parsed\n    :param limit: the limit\n    :return: exception as string\n    \"\"\"\n    if isinstance(exception, AEAEnforceError):\n        limit = -2\n    msgs = traceback.format_exception(\n        type(exception), exception, exception.__traceback__, limit=limit\n    )\n    e_str = \"\\n\".join(msgs)\n    return e_str\n"
  },
  {
    "path": "aea/helpers/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains helper methods and classes for the 'aea' package.\"\"\"\n"
  },
  {
    "path": "aea/helpers/acn/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains types and helpers used by libp2p connections.\"\"\"\n"
  },
  {
    "path": "aea/helpers/acn/agent_record.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains types and helpers for ACN Proof-of-Representation.\"\"\"\nfrom typing import Optional\n\nfrom aea.common import PathLike\nfrom aea.crypto.registries import make_ledger_api\nfrom aea.helpers.base import CertRequest, SimpleId, SimpleIdOrStr\n\n\nclass AgentRecord:\n    \"\"\"Agent Proof-of-Representation to representative.\"\"\"\n\n    __slots__ = (\n        \"_address\",\n        \"_representative_public_key\",\n        \"_identifier\",\n        \"_ledger_id\",\n        \"_not_before\",\n        \"_not_after\",\n        \"_message_format\",\n        \"_signature\",\n        \"_message\",\n        \"_public_key\",\n    )\n\n    def __init__(\n        self,\n        address: str,\n        representative_public_key: str,\n        identifier: SimpleIdOrStr,\n        ledger_id: SimpleIdOrStr,\n        not_before: str,\n        not_after: str,\n        message_format: str,\n        signature: str,\n    ) -> None:\n        \"\"\"\n        Initialize the AgentRecord\n\n        :param address: agent address\n        :param representative_public_key: representative's public key\n        :param identifier: certificate identifier.\n        :param ledger_id: ledger identifier the request is referring to.\n        :param not_before: specify the lower bound for certificate validity. If it is a string, it must follow the format: 'YYYY-MM-DD'. It will be interpreted as timezone UTC-0.\n        :param not_after: specify the lower bound for certificate validity. If it is a string, it must follow the format: 'YYYY-MM-DD'. It will be interpreted as timezone UTC-0.\n        :param message_format: message format used for signing\n        :param signature: proof-of-representation of this AgentRecord\n        \"\"\"\n        self._address = address\n        self._representative_public_key = representative_public_key\n        self._identifier = str(SimpleId(identifier))\n        self._ledger_id = str(SimpleId(ledger_id))\n        self._not_before = not_before\n        self._not_after = not_after\n        self._message_format = message_format\n        self._signature = signature\n        self._message = CertRequest.construct_message(\n            self.representative_public_key,\n            self.identifier,\n            self.not_before,\n            self.not_after,\n            self.message_format,\n        )\n        self._public_key = self._check_validity()\n\n    def _check_validity(self) -> str:\n        \"\"\"\n        Checks validity of record.\n\n        Specifically:\n        - if ledger_id is valid\n        - if agent signed the message\n\n        :return: agent public key\n        \"\"\"\n        ledger_api = make_ledger_api(self.ledger_id)\n        public_keys = ledger_api.recover_public_keys_from_message(\n            self.message, self.signature\n        )\n        if len(public_keys) == 0:\n            raise ValueError(\"Malformed signature!\")  # pragma: no cover\n        public_key: Optional[str] = None\n        for public_key_ in public_keys:\n            address = ledger_api.get_address_from_public_key(public_key_)\n            if address == self.address:\n                public_key = public_key_\n                break\n        if public_key is None:\n            raise ValueError(\n                \"Invalid signature for provided representative_public_key and agent address!\"\n            )\n        return public_key\n\n    @property\n    def address(self) -> str:\n        \"\"\"Get agent address\"\"\"\n        return self._address\n\n    @property\n    def public_key(self) -> str:\n        \"\"\"Get agent public key\"\"\"\n        return self._public_key\n\n    @property\n    def representative_public_key(self) -> str:\n        \"\"\"Get agent representative's public key\"\"\"\n        return self._representative_public_key\n\n    @property\n    def signature(self) -> str:\n        \"\"\"Get record signature\"\"\"\n        return self._signature\n\n    @property\n    def message(self) -> bytes:\n        \"\"\"Get the message.\"\"\"\n        return self._message\n\n    @property\n    def identifier(self) -> SimpleIdOrStr:\n        \"\"\"Get the identifier.\"\"\"\n        return self._identifier\n\n    @property\n    def ledger_id(self) -> SimpleIdOrStr:\n        \"\"\"Get ledger id.\"\"\"\n        return self._ledger_id\n\n    @property\n    def not_before(self) -> str:\n        \"\"\"Get the not_before field.\"\"\"\n        return self._not_before\n\n    @property\n    def not_after(self) -> str:\n        \"\"\"Get the not_after field.\"\"\"\n        return self._not_after\n\n    @property\n    def message_format(self) -> str:\n        \"\"\"Get the message format.\"\"\"\n        return self._message_format\n\n    def __str__(self) -> str:  # pragma: no cover\n        \"\"\"Get string representation.\"\"\"\n        return f\"(address={self.address}, public_key={self.public_key}, representative_public_key={self.representative_public_key}, signature={self.signature}, ledger_id={self.ledger_id})\"\n\n    @classmethod\n    def from_cert_request(\n        cls,\n        cert_request: CertRequest,\n        address: str,\n        representative_public_key: str,\n        data_dir: Optional[PathLike] = None,\n    ) -> \"AgentRecord\":\n        \"\"\"Get agent record from cert request.\"\"\"\n        signature = cert_request.get_signature(data_dir)\n        record = cls(\n            address,\n            representative_public_key,\n            cert_request.identifier,\n            cert_request.ledger_id,\n            cert_request.not_before_string,\n            cert_request.not_after_string,\n            cert_request.message_format,\n            signature,\n        )\n        return record\n"
  },
  {
    "path": "aea/helpers/acn/uri.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains types and helpers for libp2p connections Uris.\"\"\"\n\nfrom random import randint\nfrom typing import Optional\n\n\nclass Uri:\n    \"\"\"Holds a node address in format \"host:port\".\"\"\"\n\n    __slots__ = (\"_host\", \"_port\")\n\n    def __init__(\n        self,\n        uri: Optional[str] = None,\n        host: Optional[str] = None,\n        port: Optional[int] = None,\n    ) -> None:\n        \"\"\"Initialise Uri.\"\"\"\n        if uri is not None:\n            split = uri.split(\":\", 1)\n            self._host = split[0]\n            self._port = int(split[1])\n        elif host is not None and port is not None:\n            self._host = host\n            self._port = port\n        else:\n            self._host = \"127.0.0.1\"\n            self._port = randint(5000, 10000)  # nosec\n\n    def __str__(self) -> str:\n        \"\"\"Get string representation.\"\"\"\n        return \"{}:{}\".format(self._host, self._port)\n\n    def __repr__(self) -> str:  # pragma: no cover\n        \"\"\"Get object representation.\"\"\"\n        return self.__str__()\n\n    @property\n    def host(self) -> str:\n        \"\"\"Get host.\"\"\"\n        return self._host\n\n    @property\n    def port(self) -> int:\n        \"\"\"Get port.\"\"\"\n        return self._port\n"
  },
  {
    "path": "aea/helpers/async_friendly_queue.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the implementation of AsyncFriendlyQueue.\"\"\"\nimport asyncio\nimport queue\nfrom collections import deque\nfrom contextlib import suppress\nfrom typing import Any, Deque\n\n\nclass AsyncFriendlyQueue(queue.Queue):\n    \"\"\"queue.Queue with async_get method.\"\"\"\n\n    def __init__(self, *args: Any, **kwargs: Any) -> None:\n        \"\"\"Init queue.\"\"\"\n        super().__init__(*args, **kwargs)\n        self._non_empty_waiters: Deque = deque()\n\n    def put(  # pylint: disable=signature-differs\n        self, item: Any, *args: Any, **kwargs: Any\n    ) -> None:\n        \"\"\"\n        Put an item into the queue.\n\n        :param item: item to put in the queue\n        :param args: similar to queue.Queue.put\n        :param kwargs: similar to queue.Queue.put\n        \"\"\"\n        super().put(item, *args, **kwargs)\n        if self._non_empty_waiters:\n            waiter = self._non_empty_waiters.popleft()\n            waiter._loop.call_soon_threadsafe(  # pylint: disable=protected-access\n                self._set_waiter, waiter\n            )\n\n    @staticmethod\n    def _set_waiter(waiter: Any) -> None:\n        \"\"\"Set waiter result.\"\"\"\n        if waiter.done():  # pragma: nocover\n            return\n        waiter.set_result(True)\n\n    def get(  # pylint: disable=signature-differs\n        self, *args: Any, **kwargs: Any\n    ) -> Any:\n        \"\"\"\n        Get an item into the queue.\n\n        :param args: similar to queue.Queue.get\n        :param kwargs: similar to queue.Queue.get\n        :return: similar to queue.Queue.get\n        \"\"\"\n        return super().get(*args, **kwargs)\n\n    async def async_wait(self) -> None:\n        \"\"\"\n        Wait an item appears in the queue.\n\n        :return: None\n        \"\"\"\n        if not self.empty():\n            return\n        waiter = asyncio.Future()  # type: ignore\n        self._non_empty_waiters.append(waiter)\n        try:\n            await waiter\n        finally:\n            try:\n                self._non_empty_waiters.remove(waiter)\n            except ValueError:\n                pass\n\n    async def async_get(self) -> Any:\n        \"\"\"\n        Wait and get an item from the queue.\n\n        :return: item from queue\n        \"\"\"\n        while True:\n            await self.async_wait()\n\n            with suppress(queue.Empty):\n                item = self.get_nowait()\n                return item\n"
  },
  {
    "path": "aea/helpers/async_utils.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the misc utils for async code.\"\"\"\nimport asyncio\nimport datetime\nimport logging\nimport time\nfrom abc import ABC, abstractmethod\nfrom asyncio import CancelledError\nfrom asyncio.events import AbstractEventLoop, TimerHandle\nfrom asyncio.futures import Future\nfrom collections.abc import Iterable\nfrom contextlib import contextmanager\nfrom threading import Thread\nfrom typing import (\n    Any,\n    Awaitable,\n    Callable,\n    Container,\n    Coroutine,\n    Generator,\n    List,\n    Optional,\n    Sequence,\n    Set,\n    Tuple,\n    Union,\n    cast,\n)\n\n\ntry:\n    from asyncio import create_task  # pylint: disable=ungrouped-imports,unused-import\nexcept ImportError:  # pragma: no cover\n    # for python3.6!\n    from asyncio import (  # type: ignore # noqa: F401 # pylint: disable=ungrouped-imports,unused-import\n        ensure_future as create_task,\n    )\n\n\n_default_logger = logging.getLogger(__file__)\n\n\ndef ensure_list(value: Any) -> List:\n    \"\"\"Return [value] or list(value) if value is a sequence.\"\"\"\n    if isinstance(value, list):\n        return value\n\n    if isinstance(value, Iterable):\n        return list(value)\n\n    return [value]\n\n\nnot_set = object()\n\n\nclass AsyncState:\n    \"\"\"Awaitable state.\"\"\"\n\n    def __init__(\n        self, initial_state: Any = None, states_enum: Optional[Container[Any]] = None\n    ) -> None:\n        \"\"\"Init async state.\n\n        :param initial_state: state to set on start.\n        :param states_enum: container of valid states if not provided state not checked on set.\n        \"\"\"\n        self._state = initial_state\n        self._watchers: Set[Future] = set()\n        self._callbacks: List[Callable[[Any], None]] = []\n        self._states_enum = states_enum\n\n    def set(self, state: Any) -> None:\n        \"\"\"Set state.\"\"\"\n        if self._states_enum is not None and state not in self._states_enum:\n            raise ValueError(\n                f\"Unsupported state: {state}. Valid states are {self._states_enum}\"\n            )\n\n        if self._state == state:  # pragma: no cover\n            return\n\n        self._state_changed(state)\n        self._state = state\n\n    def add_callback(self, callback_fn: Callable[[Any], None]) -> None:\n        \"\"\"\n        Add callback to track state changes.\n\n        :param callback_fn: callable object to be called on state changed.\n        \"\"\"\n        self._callbacks.append(callback_fn)\n\n    def get(self) -> Any:\n        \"\"\"Get state.\"\"\"\n        return self._state\n\n    def _state_changed(self, state: Any) -> None:\n        \"\"\"Fulfill watchers for state.\"\"\"\n        for callback_fn in self._callbacks:\n            try:\n                callback_fn(state)\n            except Exception:  # pylint: disable=broad-except\n                _default_logger.exception(f\"Exception on calling {callback_fn}\")\n\n        for watcher in list(self._watchers):\n            if state not in watcher._states:  # type: ignore # pylint: disable=protected-access  # pragma: nocover\n                continue\n            if not watcher.done():\n                watcher._loop.call_soon_threadsafe(  # pylint: disable=protected-access\n                    self._watcher_result_callback(watcher), (self._state, state)\n                )\n            self._remove_watcher(watcher)\n\n    def _remove_watcher(self, watcher: Future) -> None:\n        \"\"\"Remove watcher for state wait.\"\"\"\n        try:\n            self._watchers.remove(watcher)\n        except KeyError:\n            pass\n\n    @staticmethod\n    def _watcher_result_callback(watcher: Future) -> Callable:\n        \"\"\"Create callback for watcher result.\"\"\"\n        # docstyle.\n        def _callback(result: Any) -> None:\n            if watcher.done():  # pragma: nocover\n                return\n            watcher.set_result(result)\n\n        return _callback\n\n    async def wait(self, state_or_states: Union[Any, Sequence[Any]]) -> Tuple[Any, Any]:\n        \"\"\"Wait state to be set.\n\n        :param state_or_states: state or list of states.\n\n        :return: tuple of previous state and new state.\n        \"\"\"\n        states = ensure_list(state_or_states)\n\n        if self._state in states:\n            return (None, self._state)\n\n        watcher: Future = Future()\n        watcher._states = states  # type: ignore  # pylint: disable=protected-access\n        self._watchers.add(watcher)\n        try:\n            return await watcher\n        finally:\n            self._remove_watcher(watcher)\n\n    @contextmanager\n    def transit(\n        self, initial: Any = not_set, success: Any = not_set, fail: Any = not_set\n    ) -> Generator:\n        \"\"\"\n        Change state context according to success or not.\n\n        :param initial: set state on context enter, not_set by default\n        :param success: set state on context block done, not_set by default\n        :param fail: set state on context block raises exception, not_set by default\n        :yield: generator\n        \"\"\"\n        try:\n            if initial is not not_set:\n                self.set(initial)\n            yield\n            if success is not not_set:\n                self.set(success)\n        except BaseException:\n            if fail is not not_set:\n                self.set(fail)\n            raise\n\n\nclass PeriodicCaller:\n    \"\"\"\n    Schedule a periodic call of callable using event loop.\n\n    Used for periodic function run using asyncio.\n    \"\"\"\n\n    def __init__(\n        self,\n        callback: Callable,\n        period: float,\n        start_at: Optional[datetime.datetime] = None,\n        exception_callback: Optional[Callable[[Callable, Exception], None]] = None,\n        loop: Optional[AbstractEventLoop] = None,\n    ) -> None:\n        \"\"\"\n        Init periodic caller.\n\n        :param callback: function to call periodically\n        :param period: period in seconds.\n        :param start_at: optional first call datetime\n        :param exception_callback: optional handler to call on exception raised.\n        :param loop: optional asyncio event loop\n        \"\"\"\n        self._loop = loop or asyncio.get_event_loop()\n        self._periodic_callable = callback\n        self._start_at = start_at or datetime.datetime.now()\n        self._period = period\n        self._timerhandle: Optional[TimerHandle] = None\n        self._exception_callback = exception_callback\n\n    def _callback(self) -> None:\n        \"\"\"Call on each scheduled call.\"\"\"\n        self._schedule_call()\n        try:\n            self._periodic_callable()\n        except Exception as exception:  # pylint: disable=broad-except\n            self.stop()\n            if not self._exception_callback:  # pragma: nocover\n                raise\n            self._exception_callback(self._periodic_callable, exception)\n\n    def _schedule_call(self) -> None:\n        \"\"\"Set schedule for call.\"\"\"\n        if self._timerhandle is None:\n            ts = time.mktime(self._start_at.timetuple())\n            delay = max(0, ts - time.time())\n            self._timerhandle = self._loop.call_later(delay, self._callback)\n        else:\n            self._timerhandle = self._loop.call_later(self._period, self._callback)\n\n    def start(self) -> None:\n        \"\"\"Activate period calls.\"\"\"\n        if self._timerhandle:  # pragma: nocover\n            return\n\n        self._schedule_call()\n\n    def stop(self) -> None:\n        \"\"\"Remove from schedule.\"\"\"\n        if not self._timerhandle:  # pragma: nocover\n            return\n\n        self._timerhandle.cancel()\n        self._timerhandle = None\n\n\nclass AnotherThreadTask:\n    \"\"\"\n    Schedule a task to run on the loop in another thread.\n\n    Provides better cancel behaviour: on cancel it will wait till cancelled completely.\n    \"\"\"\n\n    def __init__(self, coro: Coroutine[Any, Any, Any], loop: AbstractEventLoop) -> None:\n        \"\"\"\n        Init the task.\n\n        :param coro: coroutine to schedule\n        :param loop: an event loop to schedule on.\n        \"\"\"\n        self._loop = loop\n        self._coro = coro\n        self._task: Optional[asyncio.Task] = None\n        self._future = asyncio.run_coroutine_threadsafe(self._get_task_result(), loop)\n\n    async def _get_task_result(self) -> Any:\n        \"\"\"\n        Get task result, should be run in target loop.\n\n        :return: task result value or raise an exception if task failed\n        \"\"\"\n        self._task = self._loop.create_task(self._coro)\n        return await self._task\n\n    def result(self, timeout: Optional[float] = None) -> Any:\n        \"\"\"\n        Wait for coroutine execution result.\n\n        :param timeout: optional timeout to wait in seconds.\n        :return: result\n        \"\"\"\n        return self._future.result(timeout)\n\n    def cancel(self) -> None:\n        \"\"\"Cancel coroutine task execution in a target loop.\"\"\"\n        if self._task is None:\n            self._loop.call_soon_threadsafe(self._future.cancel)\n        else:\n            self._loop.call_soon_threadsafe(self._task.cancel)\n\n    def done(self) -> bool:\n        \"\"\"Check task is done.\"\"\"\n        return self._future.done()\n\n\nclass ThreadedAsyncRunner(Thread):\n    \"\"\"Util to run thread with event loop and execute coroutines inside.\"\"\"\n\n    def __init__(self, loop: Optional[AbstractEventLoop] = None) -> None:\n        \"\"\"\n        Init threaded runner.\n\n        :param loop: optional event loop. is it's running loop, threaded runner will use it.\n        \"\"\"\n        self._loop = loop or asyncio.new_event_loop()\n        if self._loop.is_closed():\n            raise ValueError(\"Event loop closed.\")  # pragma: nocover\n        super().__init__(daemon=True)\n\n    def start(self) -> None:\n        \"\"\"Start event loop in dedicated thread.\"\"\"\n        if self.is_alive() or self._loop.is_running():  # pragma: nocover\n            return\n        super().start()\n        self.call(asyncio.sleep(0.001)).result(1)\n\n    def run(self) -> None:\n        \"\"\"Run code inside thread.\"\"\"\n        _default_logger.debug(\"Starting threaded asyncio loop...\")\n        asyncio.set_event_loop(self._loop)\n        self._loop.run_forever()\n        _default_logger.debug(\"Asyncio loop has been stopped.\")\n\n    def call(self, coro: Coroutine[Any, Any, Any]) -> Any:\n        \"\"\"\n        Run a coroutine inside the event loop.\n\n        :param coro: a coroutine to run.\n        :return: task\n        \"\"\"\n        return AnotherThreadTask(coro, self._loop)\n\n    def stop(self) -> None:\n        \"\"\"Stop event loop in thread.\"\"\"\n        _default_logger.debug(\"Stopping...\")\n\n        if not self.is_alive():  # pragma: nocover\n            return\n\n        if self._loop.is_running():\n            _default_logger.debug(\"Stopping loop...\")\n            self._loop.call_soon_threadsafe(self._loop.stop)\n\n        _default_logger.debug(\"Wait thread to join...\")\n        self.join(10)\n        _default_logger.debug(\"Stopped.\")\n\n\nready_future: Future = Future()\nready_future.set_result(None)\n\n\nclass Runnable(ABC):\n    \"\"\"\n    Abstract Runnable class.\n\n    Use to run async task in same event loop or in dedicated thread.\n    Provides: start, stop sync methods to start and stop task\n    Use wait_completed to await task was completed.\n    \"\"\"\n\n    def __init__(\n        self, loop: asyncio.AbstractEventLoop = None, threaded: bool = False\n    ) -> None:\n        \"\"\"\n        Init runnable.\n\n        :param loop: asyncio event loop to use.\n        :param threaded: bool. start in thread if True.\n        \"\"\"\n        if loop and threaded:\n            raise ValueError(\n                \"You can not set a loop in threaded mode. A dedicated loop will be created for each thread.\"\n            )\n        self._loop = loop\n        self._threaded = threaded\n        self._task: Optional[asyncio.Task] = None\n        self._thread: Optional[Thread] = None\n        self._got_result = False\n        self._was_cancelled = False\n        self._is_running: bool = False\n        self._stop_called = 0\n\n    def start(self) -> bool:\n        \"\"\"\n        Start runnable.\n\n        :return: bool started or not.\n        \"\"\"\n        if self._task and not self._task.done():\n            _default_logger.debug(f\"{self} already running\")\n            return False\n\n        self._is_running = False\n        self._got_result = False\n        self._set_loop()\n        self._was_cancelled = False\n\n        if self._stop_called > 0:\n            # used in case of race when stop called before start!\n            _default_logger.debug(f\"{self} was already stopped before started!\")\n            self._stop_called = 0\n            return True\n\n        self._set_task()\n\n        if self._threaded:\n            self._thread = Thread(\n                target=self._thread_target,\n                name=self.__class__.__name__,  # type: ignore # loop was set in set_loop\n                daemon=True,\n            )\n            self._thread.start()\n        self._stop_called = 0\n        return True\n\n    def _thread_target(self) -> None:\n        \"\"\"Start event loop and task in the dedicated thread.\"\"\"\n        if not self._loop:\n            raise ValueError(\"Call _set_loop() first!\")  # pragma: nocover\n        if not self._task:\n            raise ValueError(\"Call _set_task() first!\")  # pragma: nocover\n        try:\n            self._loop.run_until_complete(self._task)\n        except BaseException:  # pylint: disable=broad-except)\n            logging.exception(f\"Exception raised in {self}\")\n        self._loop.stop()\n        self._loop.close()\n\n    def _set_loop(self) -> None:\n        \"\"\"Select and set loop.\"\"\"\n        if self._threaded:\n            self._loop = asyncio.new_event_loop()\n        else:\n            try:\n                self._loop = self._loop or asyncio.get_event_loop()\n            except RuntimeError:\n                self._loop = asyncio.new_event_loop()\n                asyncio.set_event_loop(self._loop)\n\n    def _set_task(self) -> None:\n        \"\"\"Create task.\"\"\"\n        if not self._loop:  # pragma: nocover\n            raise ValueError(\"Loop was not set.\")\n        self._task = self._loop.create_task(self._run_wrapper())\n        _default_logger.debug(f\"{self} task set\")\n\n    async def _run_wrapper(self) -> None:\n        \"\"\"Wrap run() method.\"\"\"\n        if not self._loop:  # pragma: nocover\n            raise ValueError(\"Start was not called!\")\n        self._is_running = True\n        try:\n            return await self.run()\n        except CancelledError:\n            if not self._was_cancelled:\n                raise\n        finally:\n            self._is_running = False\n\n    @property\n    def is_running(self) -> bool:  # pragma: nocover\n        \"\"\"Get running state.\"\"\"\n        return self._is_running\n\n    @abstractmethod\n    async def run(self) -> Any:\n        \"\"\"Implement run logic respectful to CancelError on termination.\"\"\"\n\n    def wait_completed(\n        self, sync: bool = False, timeout: float = None, force_result: bool = False\n    ) -> Union[Coroutine, Awaitable]:\n        \"\"\"\n        Wait runnable execution completed.\n\n        :param sync: bool. blocking wait\n        :param timeout: float seconds\n        :param force_result: check result even it was waited.\n\n        :return: awaitable if sync is False, otherwise None\n        \"\"\"\n        if not self._task:\n            _default_logger.warning(\"Runnable is not started\")\n            return ready_future\n\n        if self._got_result and not force_result:\n            return ready_future\n\n        if sync:\n            self._wait_sync(timeout)\n            return ready_future\n        return asyncio.wait_for(self._wait_async(timeout), timeout=timeout)\n\n    def _wait_sync(self, timeout: Optional[float] = None) -> None:\n        \"\"\"Wait task completed in sync manner.\"\"\"\n        if self._task is None or not self._loop:  # pragma: nocover\n            raise ValueError(\"task is not set!\")\n\n        if self._threaded or self._loop.is_running():\n            start_time = time.time()\n\n            while not self._task.done():\n                time.sleep(0.01)\n                if timeout is not None and time.time() - start_time > timeout:\n                    raise asyncio.TimeoutError()\n\n            if self._thread:\n                self._thread.join(timeout)\n\n            self._got_result = True\n            if self._task.exception():\n                raise cast(Exception, self._task.exception())\n        else:\n            self._loop.run_until_complete(\n                asyncio.wait_for(self._wait(), timeout=timeout)\n            )\n\n    def _wait_async(self, timeout: Optional[float] = None) -> Awaitable:\n        if not self._threaded:\n            return asyncio.wait_for(self._wait(), timeout=timeout)\n\n        if self._task is None:  # pragma: nocover\n            raise ValueError(\"task is not set!\")\n\n        # for threaded mode create a future and bind it to task\n        loop = asyncio.get_event_loop()\n        fut = loop.create_future()\n\n        def done(task: Future) -> None:\n            try:\n                if fut.done():  # pragma: nocover\n                    return\n                if task.exception():\n                    fut.set_exception(task.exception())  # type: ignore\n                else:  # pragma: nocover\n                    fut.set_result(None)\n            finally:\n                self._got_result = True\n\n        if self._task.done():\n            done(self._task)\n        else:\n            self._task.add_done_callback(\n                lambda task: loop.call_soon_threadsafe(lambda: done(task))\n            )\n\n        return fut\n\n    async def _wait(self) -> None:\n        \"\"\"Wait internal method.\"\"\"\n        if not self._task:  # pragma: nocover\n            raise ValueError(\"Not started\")\n\n        try:\n            await self._task\n        except CancelledError:\n            if not self._was_cancelled:\n                raise\n        finally:\n            self._got_result = True\n\n    def stop(self, force: bool = False) -> None:\n        \"\"\"Stop runnable.\"\"\"\n        _default_logger.debug(f\"{self} is going to be stopped {self._task}\")\n        if not self._task or not self._loop:  # pragma: nocover\n            self._stop_called += 1\n            return\n\n        if self._task.done():\n            return\n\n        self._loop.call_soon_threadsafe(self._task_cancel, force)\n\n    def _task_cancel(self, force: bool = False) -> None:\n        \"\"\"Cancel task internal method.\"\"\"\n        if self._task is None:\n            return\n\n        if self._was_cancelled and not force:\n            return\n\n        self._was_cancelled = True\n        self._task.cancel()\n\n    def start_and_wait_completed(\n        self, *args: Any, **kwargs: Any\n    ) -> Union[Coroutine, Awaitable]:\n        \"\"\"Alias for start and wait methods.\"\"\"\n        self.start()\n        return self.wait_completed(*args, **kwargs)\n"
  },
  {
    "path": "aea/helpers/base.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Miscellaneous helpers.\"\"\"\nimport builtins\nimport contextlib\nimport datetime\nimport importlib.util\nimport logging\nimport os\nimport platform\nimport re\nimport shutil\nimport signal\nimport subprocess  # nosec\nimport sys\nimport time\nimport types\nfrom collections import OrderedDict, UserString, defaultdict, deque\nfrom collections.abc import Mapping\nfrom copy import copy\nfrom functools import wraps\nfrom importlib.machinery import ModuleSpec\nfrom pathlib import Path\nfrom threading import RLock\nfrom typing import (\n    Any,\n    Callable,\n    Deque,\n    Dict,\n    Generator,\n    Iterable,\n    List,\n    Optional,\n    Set,\n    Tuple,\n    TypeVar,\n    Union,\n    cast,\n)\n\nfrom dotenv import load_dotenv\nfrom packaging.version import Version\n\nfrom aea.common import PathLike\nfrom aea.exceptions import enforce\n\n\nSTRING_LENGTH_LIMIT = 128\nSIMPLE_ID_REGEX = rf\"[a-zA-Z_][a-zA-Z0-9_]{{0,{STRING_LENGTH_LIMIT - 1}}}\"\nISO_8601_DATE_FORMAT = \"%Y-%m-%d\"\n\n_default_logger = logging.getLogger(__name__)\n\n\ndef _get_module(spec: ModuleSpec) -> Optional[types.ModuleType]:\n    \"\"\"Try to execute a module. Return None if the attempt fail.\"\"\"\n    try:\n        module = importlib.util.module_from_spec(spec)\n        spec.loader.exec_module(module)  # type: ignore\n        return module\n    except Exception:  # pylint: disable=broad-except\n        return None\n\n\ndef locate(path: str) -> Any:\n    \"\"\"Locate an object by name or dotted save_path, importing as necessary.\"\"\"\n    parts = [part for part in path.split(\".\") if part]\n    module, n = None, 0\n    while n < len(parts):\n        file_location = os.path.join(*parts[: n + 1])\n        spec_name = \".\".join(parts[: n + 1])\n        module_location = os.path.join(file_location, \"__init__.py\")\n        spec = importlib.util.spec_from_file_location(spec_name, module_location)\n        _default_logger.debug(\"Trying to import {}\".format(module_location))\n        if not spec:\n            raise RuntimeError(f\"Error loading module by path {module_location}\")\n        nextmodule = _get_module(spec)\n        if nextmodule is None:\n            module_location = file_location + \".py\"\n            spec = importlib.util.spec_from_file_location(spec_name, module_location)\n            if not spec:\n                raise RuntimeError(f\"Error loading module by path {module_location}\")\n            _default_logger.debug(\"Trying to import {}\".format(module_location))\n            nextmodule = _get_module(spec)\n\n        if nextmodule:\n            module, n = nextmodule, n + 1\n        else:  # pragma: nocover\n            break\n    if module:\n        object_ = module\n    else:\n        object_ = builtins\n    for part in parts[n:]:\n        try:\n            object_ = getattr(object_, part)\n        except AttributeError:\n            return None\n    return object_\n\n\ndef load_module(dotted_path: str, filepath: Path) -> types.ModuleType:\n    \"\"\"\n    Load a module.\n\n    :param dotted_path: the dotted save_path of the package/module.\n    :param filepath: the file to the package/module.\n    :return: module type\n    :raises ValueError: if the filepath provided is not a module.  # noqa: DAR402\n    :raises Exception: if the execution of the module raises exception.  # noqa: DAR402\n    \"\"\"\n    spec = importlib.util.spec_from_file_location(dotted_path, str(filepath))\n    if not spec:\n        raise RuntimeError(f\"Error loading module by path {filepath}\")\n    module = importlib.util.module_from_spec(spec)\n    spec.loader.exec_module(module)  # type: ignore\n    return module\n\n\ndef load_env_file(env_file: str) -> None:\n    \"\"\"\n    Load the content of the environment file into the process environment.\n\n    :param env_file: save_path to the env file.\n    \"\"\"\n    load_dotenv(dotenv_path=Path(env_file), override=False)\n\n\ndef sigint_crossplatform(process: subprocess.Popen) -> None:  # pragma: nocover\n    \"\"\"\n    Send a SIGINT, cross-platform.\n\n    The reason is because the subprocess module\n    doesn't have an API to send a SIGINT-like signal\n    both on Posix and Windows with a single method.\n\n    However, a subprocess.Popen class has the method\n    'send_signal' that gives more flexibility in this terms.\n\n    :param process: the process to send the signal to.\n    \"\"\"\n    if os.name == \"posix\":\n        process.send_signal(signal.SIGINT)  # pylint: disable=no-member\n    elif os.name == \"nt\":\n        process.send_signal(signal.CTRL_C_EVENT)  # type: ignore # pylint: disable=no-member\n    else:\n        raise ValueError(\"Other platforms not supported.\")\n\n\ndef win_popen_kwargs() -> dict:\n    \"\"\"\n    Return kwargs to start a process in windows with new process group.\n\n    Help to handle ctrl c properly.\n    Return empty dict if platform is not win32\n\n    :return: windows popen kwargs\n    \"\"\"\n    kwargs: dict = {}\n\n    if sys.platform == \"win32\":  # pragma: nocover\n        startupinfo = subprocess.STARTUPINFO()\n        startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW\n        kwargs[\"startupinfo\"] = startupinfo\n        kwargs[\"creationflags\"] = subprocess.CREATE_NEW_PROCESS_GROUP\n\n    return kwargs\n\n\ndef send_control_c(\n    process: subprocess.Popen, kill_group: bool = False\n) -> None:  # pragma: nocover # cause platform dependent\n    \"\"\"\n    Send ctrl-C cross-platform to terminate a subprocess.\n\n    :param process: the process to send the signal to.\n    :param kill_group: whether or not to kill group\n    \"\"\"\n    if platform.system() == \"Windows\":\n        if process.stdin:  # cause ctrl-c event will be handled with stdin\n            process.stdin.close()\n        os.kill(process.pid, signal.CTRL_C_EVENT)  # type: ignore  # pylint: disable=no-member\n    elif kill_group:\n        pgid = os.getpgid(process.pid)\n        os.killpg(pgid, signal.SIGINT)\n    else:\n        os.kill(process.pid, signal.SIGINT)\n\n\nclass RegexConstrainedString(UserString):\n    \"\"\"\n    A string that is constrained by a regex.\n\n    The default behaviour is to match anything.\n    Subclass this class and change the 'REGEX' class\n    attribute to implement a different behaviour.\n    \"\"\"\n\n    REGEX = re.compile(\".*\", flags=re.DOTALL)\n\n    def __init__(self, seq: Union[UserString, str]) -> None:\n        \"\"\"Initialize a regex constrained string.\"\"\"\n        super().__init__(seq)\n\n        if not self.REGEX.fullmatch(self.data):\n            self._handle_no_match()\n\n    def _handle_no_match(self) -> None:\n        raise ValueError(\n            \"Value {data} does not match the regular expression {regex}\".format(\n                data=self.data, regex=self.REGEX\n            )\n        )\n\n\nclass SimpleId(RegexConstrainedString):\n    \"\"\"\n    A simple identifier.\n\n    The allowed strings are all the strings that:\n    - have at least length 1\n    - have at most length 128\n    - the first character must be between a-z,A-Z or underscore\n    - the other characters must be either the above or digits.\n\n    Examples of allowed strings:\n    >>> SimpleId(\"an_identifier\")\n    'an_identifier'\n\n    Examples of not allowed strings:\n    >>> SimpleId(\"0an_identifier\")\n    Traceback (most recent call last):\n    ...\n    ValueError: Value 0an_identifier does not match the regular expression re.compile('[a-zA-Z_][a-zA-Z0-9_]{0,127}')\n\n    >>> SimpleId(\"an identifier\")\n    Traceback (most recent call last):\n    ...\n    ValueError: Value an identifier does not match the regular expression re.compile('[a-zA-Z_][a-zA-Z0-9_]{0,127}')\n\n    >>> SimpleId(\"\")\n    Traceback (most recent call last):\n    ...\n    ValueError: Value  does not match the regular expression re.compile('[a-zA-Z_][a-zA-Z0-9_]{0,127}')\n    \"\"\"\n\n    REGEX = re.compile(SIMPLE_ID_REGEX)\n\n\nSimpleIdOrStr = Union[SimpleId, str]\n\n\n@contextlib.contextmanager\ndef cd(path: PathLike) -> Generator:  # pragma: nocover\n    \"\"\"Change working directory temporarily.\"\"\"\n    old_path = os.getcwd()\n    os.chdir(path)\n    try:\n        yield\n    finally:\n        os.chdir(old_path)\n\n\ndef get_logger_method(fn: Callable, logger_method: Union[str, Callable]) -> Callable:\n    \"\"\"\n    Get logger method for function.\n\n    Get logger in `fn` definition module or creates logger is module.__name__.\n    Or return logger_method if it's callable.\n\n    :param fn: function to get logger for.\n    :param logger_method: logger name or callable.\n\n    :return: callable to write log with\n    \"\"\"\n    if callable(logger_method):  # pragma: nocover\n        return logger_method\n\n    logger_ = fn.__globals__.get(\"logger\", logging.getLogger(fn.__globals__[\"__name__\"]))  # type: ignore\n\n    return getattr(logger_, logger_method)\n\n\ndef try_decorator(\n    error_message: str, default_return: Callable = None, logger_method: Any = \"error\"\n) -> Callable:\n    \"\"\"\n    Run function, log and return default value on exception.\n\n    Does not support async or coroutines!\n\n    :param error_message: message template with one `{}` for exception\n    :param default_return: value to return on exception, by default None\n    :param logger_method: name of the logger method or callable to print logs\n    :return: the callable\n    \"\"\"\n\n    # for pydocstyle\n    def decorator(fn: Callable) -> Callable:\n        @wraps(fn)\n        def wrapper(*args: Any, **kwargs: Any) -> Callable:\n            try:\n                return fn(*args, **kwargs)\n            except Exception as e:  # pylint: disable=broad-except  # pragma: no cover  # generic code\n                if len(args) > 0 and getattr(args[0], \"raise_on_try\", False):\n                    raise e\n                if error_message:\n                    log = get_logger_method(fn, logger_method)\n                    log(error_message.format(e))\n                return cast(Callable, default_return)\n\n        return wrapper\n\n    return decorator\n\n\nclass MaxRetriesError(Exception):\n    \"\"\"Exception for retry decorator.\"\"\"\n\n\ndef retry_decorator(\n    number_of_retries: int,\n    error_message: str,\n    delay: float = 0,\n    logger_method: str = \"error\",\n) -> Callable:\n    \"\"\"\n    Run function with several attempts.\n\n    Does not support async or coroutines!\n\n    :param number_of_retries: amount of attempts\n    :param error_message: message template with one `{}` for exception\n    :param delay: number of seconds to sleep between retries. default 0\n    :param logger_method: name of the logger method or callable to print logs\n    :return: the callable\n    \"\"\"\n\n    # for pydocstyle\n    def decorator(fn: Callable) -> Callable:\n        @wraps(fn)\n        def wrapper(*args: Any, **kwargs: Any) -> Callable:\n            log = get_logger_method(fn, logger_method)\n            for retry in range(number_of_retries):\n                try:\n                    return fn(*args, **kwargs)\n                except Exception as e:  # pylint: disable=broad-except  # pragma: no cover  # generic code\n                    if error_message:\n                        log(error_message.format(retry=retry + 1, error=e))\n                    if delay:\n                        time.sleep(delay)\n            raise MaxRetriesError(number_of_retries)\n\n        return wrapper\n\n    return decorator\n\n\n@contextlib.contextmanager\ndef exception_log_and_reraise(log_method: Callable, message: str) -> Generator:\n    \"\"\"\n    Run code in context to log and re raise exception.\n\n    :param log_method: function to print log\n    :param message: message template to add error text.\n    :yield: the generator\n    \"\"\"\n    try:\n        yield\n    except BaseException as e:  # pylint: disable=broad-except  # pragma: no cover  # generic code\n        log_method(message.format(e))\n        raise\n\n\ndef _is_dict_like(obj: Any) -> bool:\n    \"\"\"\n    Check whether an object is dict-like (i.e. either dict or OrderedDict).\n\n    :param obj: the object to test.\n    :return: True if the object is dict-like, False otherwise.\n    \"\"\"\n    return type(obj) in (dict, OrderedDict)\n\n\ndef recursive_update(\n    to_update: Dict,\n    new_values: Dict,\n    allow_new_values: bool = False,\n) -> None:\n    \"\"\"\n    Update a dictionary by replacing conflicts with the new values.\n\n    It does side-effects to the first dictionary.\n\n    >>> to_update = dict(a=1, b=2, subdict=dict(subfield1=1))\n    >>> new_values = dict(b=3, subdict=dict(subfield1=2))\n    >>> recursive_update(to_update, new_values)\n    >>> to_update\n    {'a': 1, 'b': 3, 'subdict': {'subfield1': 2}}\n\n    :param to_update: the dictionary to update.\n    :param new_values: the dictionary of new values to replace.\n    :param allow_new_values: whether or not to allow new values.\n    \"\"\"\n    for key, value in new_values.items():\n        if (not allow_new_values) and key not in to_update:\n            raise ValueError(\n                f\"Key '{key}' is not contained in the dictionary to update.\"\n            )\n\n        if key not in to_update and allow_new_values:\n            to_update[key] = value\n            continue\n\n        value_to_update = to_update[key]\n        value_type = type(value)\n        value_to_update_type = type(value_to_update)\n        both_are_dict = _is_dict_like(value) and _is_dict_like(value_to_update)\n        if (\n            not both_are_dict\n            and value_type != value_to_update_type\n            and value is not None\n            and value_to_update is not None\n        ):\n            raise ValueError(\n                f\"Trying to replace value '{value_to_update}' with value '{value}' which is of different type.\"\n            )\n\n        if both_are_dict:\n            recursive_update(value_to_update, value, allow_new_values)\n        else:\n            to_update[key] = value\n\n\ndef _get_aea_logger_name_prefix(module_name: str, agent_name: str) -> str:\n    \"\"\"\n    Get the logger name prefix.\n\n    It consists of a dotted save_path with:\n    - the name of the package, 'aea';\n    - the agent name;\n    - the rest of the dotted save_path.\n\n    >>> _get_aea_logger_name_prefix(\"aea.save_path.to.package\", \"myagent\")\n    'aea.myagent.save_path.to.package'\n\n    :param module_name: the module name.\n    :param agent_name: the agent name.\n    :return: the logger name prefix.\n    \"\"\"\n    module_name_parts = module_name.split(\".\")\n    root = module_name_parts[0]\n    postfix = module_name_parts[1:]\n    return \".\".join([root, agent_name, *postfix])\n\n\nT = TypeVar(\"T\")\n\n\ndef find_topological_order(adjacency_list: Dict[T, Set[T]]) -> List[T]:\n    \"\"\"\n    Compute the topological order of a graph (using Kahn's algorithm).\n\n    :param adjacency_list: the adjacency list of the graph.\n    :return: the topological order for the graph (as a sequence of nodes)\n    :raises ValueError: if the graph contains a cycle.\n    \"\"\"\n    # compute inverse adjacency list and the roots of the DAG.\n    adjacency_list = copy(adjacency_list)\n    visited: Set[T] = set()\n    roots: Set[T] = set()\n    inverse_adjacency_list: Dict[T, Set[T]] = defaultdict(set)\n    # compute both roots and inverse adjacent list in one pass.\n    for start_node, end_nodes in adjacency_list.items():\n        if start_node not in visited:\n            roots.add(start_node)\n        visited.update([start_node, *end_nodes])\n        for end_node in end_nodes:\n            roots.discard(end_node)\n            inverse_adjacency_list[end_node].add(start_node)\n\n    # compute the topological order\n    queue: Deque[T] = deque()\n    order = []\n    queue.extendleft(sorted(roots))  # type: ignore\n    while len(queue) > 0:\n        current = queue.pop()\n        order.append(current)\n        next_nodes = adjacency_list.get(current, set())\n        for node in next_nodes:\n            inverse_adjacency_list[node].discard(current)\n            if len(inverse_adjacency_list[node]) == 0:\n                queue.append(node)\n\n        # remove all the edges\n        adjacency_list[current] = set()\n\n    if any(len(edges) > 0 for edges in inverse_adjacency_list.values()):\n        raise ValueError(\"Graph has at least one cycle.\")\n\n    return order\n\n\ndef reachable_nodes(\n    adjacency_list: Dict[T, Set[T]], starting_nodes: Set[T]\n) -> Dict[T, Set[T]]:\n    \"\"\"\n    Find the reachable subgraph induced by a set of starting nodes.\n\n    :param adjacency_list: the adjacency list of the full graph.\n    :param starting_nodes: the starting nodes of the new graph.\n    :return: the adjacency list of the subgraph.\n    \"\"\"\n    all_nodes = set()\n    for node, nodes in adjacency_list.items():\n        all_nodes.add(node)\n        all_nodes.update(nodes)\n    enforce(\n        all(s in all_nodes for s in starting_nodes),\n        f\"These starting nodes are not in the set of nodes: {starting_nodes.difference(all_nodes)}\",\n    )\n    visited: Set[T] = set()\n    result: Dict[T, Set[T]] = {start_node: set() for start_node in starting_nodes}\n    queue: Deque[T] = deque()\n    queue.extend(starting_nodes)\n    while len(queue) > 0:\n        current = queue.pop()\n        if current in visited or current not in adjacency_list:\n            continue\n        successors = adjacency_list.get(current, set())\n        result.setdefault(current, set()).update(successors)\n        queue.extendleft(successors)\n        visited.add(current)\n    return result\n\n\n_NOT_FOUND = object()\n\n\n# copied from python3.8 functools\nclass cached_property:  # pragma: nocover\n    \"\"\"Cached property from python3.8 functools.\"\"\"\n\n    def __init__(self, func: Callable) -> None:\n        \"\"\"Init cached property.\"\"\"\n        self.func = func\n        self.attrname = None\n        self.__doc__ = func.__doc__\n        self.lock = RLock()\n\n    def __set_name__(self, _: Any, name: Any) -> None:\n        \"\"\"Set name.\"\"\"\n        if self.attrname is None:\n            self.attrname = name\n        elif name != self.attrname:\n            raise TypeError(\n                \"Cannot assign the same cached_property to two different names \"\n                f\"({self.attrname!r} and {name!r}).\"\n            )\n\n    def __get__(self, instance: Any, _: Optional[Any] = None) -> Any:\n        \"\"\"Get instance.\"\"\"\n        if instance is None:\n            return self\n        if self.attrname is None:\n            raise TypeError(\n                \"Cannot use cached_property instance without calling __set_name__ on it.\"\n            )\n        try:\n            cache = instance.__dict__\n        except AttributeError:  # not all objects have __dict__ (e.g. class defines slots)\n            msg = (\n                f\"No '__dict__' attribute on {type(instance).__name__!r} \"\n                f\"instance to cache {self.attrname!r} property.\"\n            )\n            raise TypeError(msg) from None\n        val = cache.get(self.attrname, _NOT_FOUND)\n        if val is _NOT_FOUND:\n            with self.lock:\n                # check if another thread filled cache while we awaited lock\n                val = cache.get(self.attrname, _NOT_FOUND)\n                if val is _NOT_FOUND:\n                    val = self.func(instance)\n                    try:\n                        cache[self.attrname] = val\n                    except TypeError:\n                        msg = (\n                            f\"The '__dict__' attribute on {type(instance).__name__!r} instance \"\n                            f\"does not support item assignment for caching {self.attrname!r} property.\"\n                        )\n                        raise TypeError(msg) from None\n        return val\n\n\ndef ensure_dir(dir_path: str) -> None:\n    \"\"\"Check if dir_path is a directory or create it.\"\"\"\n    if not os.path.exists(dir_path):\n        os.makedirs(dir_path)\n    else:\n        enforce(os.path.isdir(dir_path), f\"{dir_path} is not a directory!\")\n\n\ndef dict_to_path_value(\n    data: Mapping, path: Optional[List] = None\n) -> Iterable[Tuple[List[str], Any]]:\n    \"\"\"Convert dict to sequence of terminal path build of  keys and value.\"\"\"\n    path = path or []\n    for key, value in data.items():\n        if isinstance(value, Mapping) and value:\n            # terminal value\n            for p, v in dict_to_path_value(value, path + [key]):\n                yield p, v\n        else:\n            yield path + [key], value\n\n\ndef parse_datetime_from_str(date_string: str) -> datetime.datetime:\n    \"\"\"Parse datetime from string.\"\"\"\n    result = datetime.datetime.strptime(date_string, ISO_8601_DATE_FORMAT)\n    result = result.replace(tzinfo=datetime.timezone.utc)\n    return result\n\n\nclass CertRequest:\n    \"\"\"Certificate request for proof of representation.\"\"\"\n\n    def __init__(\n        self,\n        public_key: str,\n        identifier: SimpleIdOrStr,\n        ledger_id: SimpleIdOrStr,\n        not_before: str,\n        not_after: str,\n        message_format: str,\n        save_path: str,\n    ) -> None:\n        \"\"\"\n        Initialize the certificate request.\n\n        :param public_key: the public key, or the key id.\n        :param identifier: certificate identifier.\n        :param ledger_id: ledger identifier the request is referring to.\n        :param not_before: specify the lower bound for certificate validity. If it is a string, it must follow the format: 'YYYY-MM-DD'. It will be interpreted as timezone UTC-0.\n        :param not_after: specify the lower bound for certificate validity. If it is a string, it must follow the format: 'YYYY-MM-DD'. It will be interpreted as timezone UTC-0.\n        :param message_format: message format used for signing\n        :param save_path: the save_path where to save the certificate.\n        \"\"\"\n        self._key_identifier: Optional[str] = None\n        self._public_key: Optional[str] = None\n        self._identifier = str(SimpleId(identifier))\n        self._ledger_id = str(SimpleId(ledger_id))\n        self._not_before_string = not_before\n        self._not_after_string = not_after\n        self._not_before = self._parse_datetime(not_before)\n        self._not_after = self._parse_datetime(not_after)\n        self._message_format = message_format\n        self._save_path = Path(save_path)\n\n        self._parse_public_key(public_key)\n        self._check_validation_boundaries()\n\n    @classmethod\n    def _parse_datetime(cls, obj: Union[str, datetime.datetime]) -> datetime.datetime:\n        \"\"\"\n        Parse datetime string.\n\n        It is expected to follow ISO 8601.\n\n        :param obj: the input to parse.\n        :return: a datetime.datetime instance.\n        \"\"\"\n        result = (\n            parse_datetime_from_str(obj)  # type: ignore\n            if isinstance(obj, str)\n            else obj\n        )\n        enforce(result.microsecond == 0, \"Microsecond field not allowed.\")\n        return result\n\n    def _check_validation_boundaries(self) -> None:\n        \"\"\"\n        Check the validation boundaries are consistent.\n\n        Namely, that not_before < not_after.\n        \"\"\"\n        enforce(\n            self._not_before < self._not_after,\n            f\"Inconsistent certificate validity period: 'not_before' field '{self._not_before_string}' is not before than 'not_after' field '{self._not_after_string}'\",\n            ValueError,\n        )\n\n    def _parse_public_key(self, public_key_str: str) -> None:\n        \"\"\"\n        Parse public key from string.\n\n        It first tries to parse it as an identifier,\n        and in case of failure as a sequence of hexadecimals, starting with \"0x\".\n\n        :param public_key_str: the public key\n        \"\"\"\n        with contextlib.suppress(ValueError):\n            # if this raises ValueError, we don't return\n            self._key_identifier = str(SimpleId(public_key_str))\n            return\n\n        with contextlib.suppress(ValueError):\n            # this raises ValueError if the input is not a valid hexadecimal string.\n            int(public_key_str, 16)\n            self._public_key = public_key_str\n            return\n\n        enforce(\n            False,\n            f\"Public key field '{public_key_str}' is neither a valid identifier nor an address.\",\n            exception_class=ValueError,\n        )\n\n    @property\n    def public_key(self) -> Optional[str]:\n        \"\"\"Get the public key.\"\"\"\n        return self._public_key\n\n    @property\n    def ledger_id(self) -> str:\n        \"\"\"Get the ledger id.\"\"\"\n        return self._ledger_id\n\n    @property\n    def key_identifier(self) -> Optional[str]:\n        \"\"\"Get the key identifier.\"\"\"\n        return self._key_identifier\n\n    @property\n    def identifier(self) -> str:\n        \"\"\"Get the identifier.\"\"\"\n        return self._identifier\n\n    @property\n    def not_before_string(self) -> str:\n        \"\"\"Get the not_before field as string.\"\"\"\n        return self._not_before_string\n\n    @property\n    def not_after_string(self) -> str:\n        \"\"\"Get the not_after field as string.\"\"\"\n        return self._not_after_string\n\n    @property\n    def not_before(self) -> datetime.datetime:\n        \"\"\"Get the not_before field.\"\"\"\n        return self._not_before\n\n    @property\n    def not_after(self) -> datetime.datetime:\n        \"\"\"Get the not_after field.\"\"\"\n        return self._not_after\n\n    @property\n    def message_format(self) -> str:\n        \"\"\"Get the message format.\"\"\"\n        return self._message_format\n\n    @property\n    def save_path(self) -> Path:\n        \"\"\"\n        Get the save path for the certificate.\n\n        Note: if the path is *not* absolute, then\n        the actual save path might depend on the context.\n\n        :return: the save path\n        \"\"\"\n        return self._save_path\n\n    def get_absolute_save_path(self, path_prefix: Optional[PathLike] = None) -> Path:\n        \"\"\"\n        Get the absolute save path.\n\n        If save_path is an absolute path, then the prefix is ignored.\n        Otherwise, the path prefix is prepended.\n\n        :param path_prefix: the (absolute) path to prepend to the save path.\n        :return: the actual save path.\n        \"\"\"\n        path_prefix = (\n            Path(path_prefix).absolute() if path_prefix is not None else Path.cwd()\n        )\n        return (\n            self.save_path\n            if self.save_path.is_absolute()\n            else path_prefix / self.save_path\n        )\n\n    @property\n    def public_key_or_identifier(self) -> str:\n        \"\"\"Get the public key or identifier.\"\"\"\n        if (self.public_key is None and self.key_identifier is None) or (\n            self.public_key is not None and self.key_identifier is not None\n        ):\n            raise ValueError(  # pragma: nocover\n                \"Exactly one of key_identifier or public_key can be specified.\"\n            )\n        if self.public_key is not None:\n            result = self.public_key\n        elif self.key_identifier is not None:\n            result = self.key_identifier\n        return result\n\n    def get_message(self, public_key: str) -> bytes:\n        \"\"\"Get the message to sign.\"\"\"\n        message = self.construct_message(\n            public_key,\n            self.identifier,\n            self.not_before_string,\n            self.not_after_string,\n            self.message_format,\n        )\n        return message\n\n    @classmethod\n    def construct_message(\n        cls,\n        public_key: str,\n        identifier: SimpleIdOrStr,\n        not_before_string: str,\n        not_after_string: str,\n        message_format: str,\n    ) -> bytes:\n        \"\"\"\n        Construct message for singning.\n\n        :param public_key: the public key\n        :param identifier: identifier to be signed\n        :param not_before_string: signature not valid before\n        :param not_after_string: signature not valid after\n        :param message_format: message format used for signing\n        :return: the message\n        \"\"\"\n        message = message_format.format(\n            public_key=public_key,\n            identifier=str(identifier),\n            not_before=not_before_string,\n            not_after=not_after_string,\n        )\n        return message.encode(\"ascii\")\n\n    def get_signature(self, path_prefix: Optional[PathLike] = None) -> str:\n        \"\"\"\n        Get signature from save_path.\n\n        :param path_prefix: the path prefix to be prepended to save_path. Defaults to cwd.\n        :return: the signature.\n        \"\"\"\n        save_path = self.get_absolute_save_path(path_prefix)\n        if not Path(save_path).is_file():\n            raise Exception(  # pragma: no cover\n                f\"cert_request 'save_path' field {save_path} is not a file. \"\n                \"Please ensure that 'issue-certificates' command is called beforehand.\"\n            )\n        signature = bytes.fromhex(Path(save_path).read_bytes().decode(\"ascii\")).decode(\n            \"ascii\"\n        )\n        return signature\n\n    @property\n    def json(self) -> Dict:\n        \"\"\"Compute the JSON representation.\"\"\"\n        result = dict(\n            identifier=self.identifier,\n            ledger_id=self.ledger_id,\n            not_before=self._not_before_string,\n            not_after=self._not_after_string,\n            public_key=self.public_key_or_identifier,\n            message_format=self.message_format,\n            save_path=str(self.save_path),\n        )\n        return result\n\n    @classmethod\n    def from_json(cls, obj: Dict) -> \"CertRequest\":\n        \"\"\"Compute the JSON representation.\"\"\"\n        if \"message_format\" not in obj:  # pragma: nocover\n            # for backwards compatibility\n            obj[\"message_format\"] = \"{public_key}\"\n        return cls(**obj)\n\n    def __eq__(self, other: Any) -> bool:\n        \"\"\"Check equality.\"\"\"\n        return (\n            isinstance(other, CertRequest)\n            and self.identifier == other.identifier\n            and self.ledger_id == other.ledger_id\n            and self.public_key == other.public_key\n            and self.key_identifier == other.key_identifier\n            and self.not_after == other.not_after\n            and self.not_before == other.not_before\n            and self.message_format == other.message_format\n            and self.save_path == other.save_path\n        )\n\n\ndef compute_specifier_from_version(version: Version) -> str:\n    \"\"\"\n    Compute the specifier set from a version.\n\n    version specifier is:  >=major.minor.0, <next_major.0.0\n\n    :param version: the version\n    :return: the specifier set\n    \"\"\"\n    new_major_low = version.major\n    new_major_high = version.major + 1\n    new_minor_low = version.minor\n    new_minor_high = new_minor_low + 1\n    if new_major_low == 0:\n        lower_bound = Version(f\"{new_major_low}.{new_minor_low}.0\")\n        lower_bound = lower_bound if lower_bound < version else version\n        upper_bound = Version(f\"{new_major_low}.{new_minor_high}.0\")\n    else:\n        lower_bound = Version(f\"{new_major_low}.{version.minor}.0\")\n        lower_bound = lower_bound if lower_bound < version else version\n        upper_bound = Version(f\"{new_major_high}.0.0\")\n    specifier_set = f\">={lower_bound}, <{upper_bound}\"\n    return specifier_set\n\n\ndef decorator_with_optional_params(decorator: Callable) -> Callable:\n    \"\"\"\n    Make a decorator usable either with or without parameters.\n\n    In other words, if a decorator \"mydecorator\" is decorated with this decorator,\n    It can be used both as:\n\n    @mydecorator\n    def myfunction():\n        ...\n\n    or as:\n\n    @mydecorator(arg1, kwarg1=\"value\")\n    def myfunction():\n        ...\n\n    :param decorator: a decorator callable\n    :return: a decorator callable\n    \"\"\"\n\n    @wraps(decorator)\n    def new_decorator(*args: Any, **kwargs: Any) -> Callable:\n        if len(args) == 1 and len(kwargs) == 0 and callable(args[0]):\n            return decorator(args[0])\n\n        def final_decorator(real_function: Callable) -> Callable:\n            return decorator(real_function, *args, **kwargs)\n\n        return final_decorator\n\n    return new_decorator\n\n\ndef delete_directory_contents(directory: Path) -> None:\n    \"\"\"Delete the content of a directory, without deleting it.\"\"\"\n    enforce(directory.is_dir(), f\"Path '{directory}' must be a directory.\")\n    for filename in directory.iterdir():\n        if filename.is_file() or filename.is_symlink():\n            filename.unlink()\n        elif filename.is_dir():\n            shutil.rmtree(str(filename), ignore_errors=False)\n\n\ndef prepend_if_not_absolute(path: PathLike, prefix: PathLike) -> PathLike:\n    \"\"\"\n    Prepend a path with a prefix, but only if not absolute\n\n    :param path: the path to process.\n    :param prefix: the path prefix.\n    :return: the same path if absolute, else the prepended path.\n    \"\"\"\n    return path if Path(path).is_absolute() else Path(prefix) / path\n"
  },
  {
    "path": "aea/helpers/constants.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Module with helpers constants.\"\"\"\nfrom typing import Dict, List, Union\n\n\nFALSE_EQUIVALENTS = [\"f\", \"false\", \"False\", \"0\"]\nFROM_STRING_TO_TYPE = dict(\n    str=str,\n    int=int,\n    bool=bool,\n    float=float,\n    dict=dict,\n    list=list,\n    none=None,\n)\nJSON_TYPES = Union[Dict, str, List, None, int, float]\n\nNETWORK_REQUEST_DEFAULT_TIMEOUT = 60.0  # in seconds\n"
  },
  {
    "path": "aea/helpers/env_vars.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Implementation of the environment variables support.\"\"\"\nimport json\nimport re\nfrom collections.abc import Mapping as MappingType\nfrom typing import Any, Dict, List, Mapping, Union\n\nfrom aea.helpers.constants import FALSE_EQUIVALENTS, FROM_STRING_TO_TYPE, JSON_TYPES\n\n\nENV_VARIABLE_RE = re.compile(\n    r\"^\\$\\{(?P<name>\\w+)(:(?P<type>\\w+)(:(?P<default>\\w+))?)?\\}$\", re.I\n)\n\n\ndef is_env_variable(value: Any) -> bool:\n    \"\"\"Check is variable string with env variable pattern.\"\"\"\n    return isinstance(value, str) and bool(ENV_VARIABLE_RE.match(value))\n\n\nNotSet = object()\n\n\ndef replace_with_env_var(\n    value: str, env_variables: dict, default_value: Any = NotSet\n) -> JSON_TYPES:\n    \"\"\"Replace env var with value.\"\"\"\n    result = ENV_VARIABLE_RE.match(value)\n\n    if not result:\n        return value\n\n    var_name = result.groupdict()[\"name\"]\n    type_str = result.groupdict()[\"type\"]\n    default = result.groupdict()[\"default\"]\n\n    if var_name in env_variables:\n        var_value = env_variables[var_name]\n    elif default is not None:\n        var_value = default\n    elif default_value is not NotSet:\n        var_value = default_value\n    else:\n        raise ValueError(\n            f\"`{var_name}` not found in env variables and no default value set! Please ensure a .env file is provided.\"\n        )\n\n    if type_str is not None:\n        var_value = convert_value_str_to_type(var_value, type_str)\n\n    return var_value\n\n\ndef apply_env_variables(\n    data: Union[Dict, List[Dict]],\n    env_variables: Mapping[str, Any],\n    default_value: Any = NotSet,\n) -> JSON_TYPES:\n    \"\"\"Create new resulting dict with env variables applied.\"\"\"\n\n    if isinstance(data, (list, tuple)):\n        result = []\n        for i in data:\n            result.append(apply_env_variables(i, env_variables, default_value))\n        return result\n\n    if isinstance(data, MappingType):\n        return {\n            apply_env_variables(k, env_variables, default_value): apply_env_variables(\n                v, env_variables, default_value\n            )\n            for k, v in data.items()\n        }\n    if is_env_variable(data):\n        return replace_with_env_var(data, env_variables, default_value)\n\n    return data\n\n\ndef convert_value_str_to_type(value: str, type_str: str) -> JSON_TYPES:\n    \"\"\"Convert value by type name to native python type.\"\"\"\n    try:\n        type_ = FROM_STRING_TO_TYPE[type_str]\n        if type_ == bool:\n            return value not in FALSE_EQUIVALENTS\n        if type_ is None:\n            return None\n        if type_ in (dict, list):\n            return json.loads(value)\n        return type_(value)\n    except (ValueError, json.decoder.JSONDecodeError):  # pragma: no cover\n        raise ValueError(f\"Cannot convert string `{value}` to type `{type_.__name__}`\")  # type: ignore\n"
  },
  {
    "path": "aea/helpers/exception_policy.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains enum of aea exception policies.\"\"\"\n\nfrom enum import Enum\n\n\nclass ExceptionPolicyEnum(Enum):\n    \"\"\"AEA Exception policies.\"\"\"\n\n    propagate = \"propagate\"  # just bubble up exception raised. run loop interrupted.\n    just_log = (\n        \"just_log\"  # write details in log file, skip exception. continue running.\n    )\n    stop_and_exit = \"stop_and_exit\"  # log exception and stop agent with raising AEAException to show it was terminated\n"
  },
  {
    "path": "aea/helpers/exec_timeout.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Python code execution time limit tools.\"\"\"\nimport asyncio\nimport concurrent\nimport ctypes\nimport logging\nimport signal\nimport threading\nfrom abc import ABC, abstractmethod\nfrom asyncio import Future\nfrom asyncio.events import AbstractEventLoop\nfrom threading import Lock\nfrom types import TracebackType\nfrom typing import Any, Optional, Type\n\n\n_default_logger = logging.getLogger(__file__)\n\n\nclass TimeoutResult:\n    \"\"\"Result of ExecTimeout context manager.\"\"\"\n\n    def __init__(self) -> None:\n        \"\"\"Init.\"\"\"\n        self._cancelled_by_timeout = False\n\n    def set_cancelled_by_timeout(self) -> None:\n        \"\"\"Set code was terminated cause timeout.\"\"\"\n        self._cancelled_by_timeout = True\n\n    def is_cancelled_by_timeout(self) -> bool:\n        \"\"\"\n        Return True if code was terminated by ExecTimeout cause timeout.\n\n        :return: bool\n        \"\"\"\n        return self._cancelled_by_timeout\n\n\nclass TimeoutException(BaseException):\n    \"\"\"\n    TimeoutException raised by ExecTimeout context managers in thread with limited execution time.\n\n    Used internally, does not propagated outside of context manager\n    \"\"\"\n\n\nclass BaseExecTimeout(ABC):\n    \"\"\"\n    Base class for implementing context managers to limit python code execution time.\n\n    exception_class - is exception type to raise in code controlled in case of timeout.\n    \"\"\"\n\n    exception_class: Type[BaseException] = TimeoutException\n\n    def __init__(self, timeout: float = 0.0) -> None:\n        \"\"\"\n        Init.\n\n        :param timeout: number of seconds to execute code before interruption\n        \"\"\"\n        self.timeout = timeout\n        self.result = TimeoutResult()\n\n    def _on_timeout(self, *args: Any, **kwargs: Any) -> None:\n        \"\"\"Raise exception on timeout.\"\"\"\n        raise self.exception_class()\n\n    def __enter__(self) -> TimeoutResult:\n        \"\"\"\n        Enter context manager.\n\n        :return: TimeoutResult\n        \"\"\"\n        if self.timeout:\n            self._set_timeout_watch()\n\n        return self.result\n\n    def __exit__(\n        self, exc_type: Type[Exception], exc_val: Exception, exc_tb: TracebackType\n    ) -> None:\n        \"\"\"\n        Exit context manager.\n\n        :param exc_type: the exception type\n        :param exc_val: the exception\n        :param exc_tb: the traceback\n        \"\"\"\n        if self.timeout:\n            self._remove_timeout_watch()\n\n        if isinstance(exc_val, TimeoutException):\n            self.result.set_cancelled_by_timeout()\n\n    @abstractmethod\n    def _set_timeout_watch(self) -> None:\n        \"\"\"\n        Start control over execution time.\n\n        Should be implemented in concrete class.\n        \"\"\"\n        raise NotImplementedError  # pragma: nocover\n\n    @abstractmethod\n    def _remove_timeout_watch(self) -> None:\n        \"\"\"\n        Stop control over execution time.\n\n        Should be implemented in concrete class.\n        \"\"\"\n        raise NotImplementedError  # pragma: nocover\n\n\nclass ExecTimeoutSigAlarm(BaseExecTimeout):  # pylint: disable=too-few-public-methods\n    \"\"\"\n    ExecTimeout context manager implementation using signals and SIGALARM.\n\n    Does not support threads, have to be used only in main thread.\n    \"\"\"\n\n    def _set_timeout_watch(self) -> None:\n        \"\"\"Start control over execution time.\"\"\"\n        signal.setitimer(signal.ITIMER_REAL, self.timeout, 0)\n        signal.signal(signal.SIGALRM, self._on_timeout)\n\n    def _remove_timeout_watch(self) -> None:\n        \"\"\"Stop control over execution time.\"\"\"\n        signal.setitimer(signal.ITIMER_REAL, 0, 0)\n\n\nclass ExecTimeoutThreadGuard(BaseExecTimeout):\n    \"\"\"\n    ExecTimeout context manager implementation using threads and PyThreadState_SetAsyncExc.\n\n    Support threads.\n    Requires supervisor thread start/stop to control execution time control.\n    Possible will be not accurate in case of long c functions used inside code controlled.\n    \"\"\"\n\n    _supervisor_thread: Optional[threading.Thread] = None\n    _loop: Optional[AbstractEventLoop] = None\n    _stopped_future: Optional[Future] = None\n    _start_count: int = 0\n    _lock: Lock = Lock()\n    _thread_started_event = threading.Event()\n\n    def __init__(self, timeout: float = 0.0) -> None:\n        \"\"\"\n        Init ExecTimeoutThreadGuard variables.\n\n        :param timeout: number of seconds to execute code before interruption\n        \"\"\"\n        super().__init__(timeout=timeout)\n\n        self._future_guard_task: Optional[concurrent.futures._base.Future[None]] = None\n        self._thread_id: Optional[int] = None\n\n    @classmethod\n    def start(cls) -> None:\n        \"\"\"\n        Start supervisor thread to check timeouts.\n\n        Supervisor starts once but number of start counted.\n        \"\"\"\n        with cls._lock:\n            cls._start_count += 1\n\n            if cls._supervisor_thread:  # pragma: nocover\n                return\n\n            cls._loop = asyncio.new_event_loop()\n            cls._supervisor_thread = threading.Thread(\n                target=cls._supervisor_event_loop, daemon=True, name=\"ExecTimeout\"\n            )\n            cls._supervisor_thread.start()\n            cls._thread_started_event.wait()\n\n    @classmethod\n    def stop(cls, force: bool = False) -> None:\n        \"\"\"\n        Stop supervisor thread.\n\n        Actual stop performed on force == True or if  number of stops == number of starts\n\n        :param force: force stop regardless number of start.\n        \"\"\"\n        with cls._lock:\n            if not cls._supervisor_thread:  # pragma: nocover\n                return\n\n            cls._start_count -= 1\n\n            if cls._start_count <= 0 or force:\n                cls._loop.call_soon_threadsafe(cls._set_stopped_future)  # type: ignore\n                if cls._supervisor_thread and cls._supervisor_thread.is_alive():\n                    cls._supervisor_thread.join()\n                cls._supervisor_thread = None\n                cls._start_count = 0\n\n    @classmethod\n    def _set_stopped_future(cls) -> None:\n        \"\"\"Set stopped future result.\"\"\"\n        if not cls._stopped_future or cls._stopped_future.done():  # pragma: nocover\n            return\n        cls._stopped_future.set_result(True)\n\n    @classmethod\n    def _supervisor_event_loop(cls) -> None:\n        \"\"\"Start supervisor thread to execute asyncio task controlling execution time.\"\"\"\n        # pydocstyle: noqa # cause black reformats with pydocstyle conflict # noqa: E800\n        async def wait_stopped() -> None:\n            cls._stopped_future = Future()\n            cls._thread_started_event.set()\n            await cls._stopped_future  # type: ignore\n\n        cls._loop.run_until_complete(wait_stopped())  # type: ignore\n\n    async def _guard_task(self) -> None:\n        \"\"\"Task to terminate thread on timeout.\"\"\"\n        await asyncio.sleep(self.timeout)\n        self._set_thread_exception(self._thread_id, self.exception_class)  # type: ignore\n\n    @staticmethod\n    def _set_thread_exception(thread_id: int, exception_class: Type[Exception]) -> None:\n        \"\"\"Terminate code execution in specific thread by setting exception.\"\"\"\n        ctypes.pythonapi.PyThreadState_SetAsyncExc(\n            ctypes.c_long(thread_id), ctypes.py_object(exception_class)\n        )\n\n    def _set_timeout_watch(self) -> None:\n        \"\"\"\n        Start control over execution time.\n\n        Set task checking code execution time.\n        ExecTimeoutThreadGuard.start is required at least once in project before usage!\n        \"\"\"\n        if not self._supervisor_thread:\n            _default_logger.warning(\n                \"ExecTimeoutThreadGuard is used but not started! No timeout wil be applied!\"\n            )\n            return\n\n        self._thread_id = threading.current_thread().ident\n        self._future_guard_task = asyncio.run_coroutine_threadsafe(\n            self._guard_task(), self._loop  # type: ignore\n        )\n\n    def _remove_timeout_watch(self) -> None:\n        \"\"\"\n        Stop control over execution time.\n\n        Cancel task checking code execution time.\n        \"\"\"\n        if self._future_guard_task and not self._future_guard_task.done():\n            self._future_guard_task.cancel()\n            self._future_guard_task = None\n"
  },
  {
    "path": "aea/helpers/file_io.py",
    "content": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Read to and write from file with envelopes.\"\"\"\n\nimport codecs\nimport logging\nfrom contextlib import contextmanager\nfrom logging import Logger\nfrom typing import Generator, IO, Optional, Union\n\nfrom aea.configurations.base import PublicId\nfrom aea.helpers import file_lock\nfrom aea.helpers.base import exception_log_and_reraise\nfrom aea.mail.base import Envelope\n\n\nSEPARATOR = b\",\"\n\n_default_logger = logging.getLogger(__name__)\n\n\ndef _encode(e: Envelope, separator: bytes = SEPARATOR) -> bytes:\n    result = b\"\"\n    result += e.to.encode(\"utf-8\")\n    result += separator\n    result += e.sender.encode(\"utf-8\")\n    result += separator\n    result += str(e.protocol_specification_id).encode(\"utf-8\")\n    result += separator\n    result += e.message_bytes\n    result += separator\n\n    return result\n\n\ndef _decode(e: bytes, separator: bytes = SEPARATOR) -> Envelope:\n    split = e.split(separator)\n\n    if len(split) < 5 or split[-1] not in [b\"\", b\"\\n\"]:\n        raise ValueError(\n            \"Expected at least 5 values separated by commas and last value being empty or new line, got {}\".format(\n                len(split)\n            )\n        )\n\n    to = split[0].decode(\"utf-8\").strip().lstrip(\"\\x00\")\n    sender = split[1].decode(\"utf-8\").strip()\n    protocol_specification_id = PublicId.from_str(split[2].decode(\"utf-8\").strip())\n    # protobuf messages cannot be delimited as they can contain an arbitrary byte sequence; however\n    # we know everything remaining constitutes the protobuf message.\n    message = SEPARATOR.join(split[3:-1])\n    if b\"\\\\x\" in message:  # pragma: nocover\n        # hack to account for manual usage of `echo`\n        message = codecs.decode(message, \"unicode-escape\").encode(\"utf-8\")\n\n    return Envelope(\n        to=to,\n        sender=sender,\n        protocol_specification_id=protocol_specification_id,\n        message=message,\n    )\n\n\n@contextmanager\ndef lock_file(\n    file_descriptor: IO[bytes], logger: Logger = _default_logger\n) -> Generator:\n    \"\"\"Lock file in context manager.\n\n    :param file_descriptor: file descriptor of file to lock.\n    :param logger: the logger.\n    :yield: generator\n    \"\"\"\n    with exception_log_and_reraise(\n        logger.error,\n        f\"Couldn't acquire lock for file {file_descriptor.name}: {{}}\",\n    ):\n        file_lock.lock(file_descriptor, file_lock.LOCK_EX)\n\n    try:\n        yield\n    finally:\n        file_lock.unlock(file_descriptor)\n\n\ndef write_envelope(\n    envelope: Envelope,\n    file_pointer: IO[bytes],\n    separator: bytes = SEPARATOR,\n    logger: Logger = _default_logger,\n) -> None:\n    \"\"\"Write envelope to file.\"\"\"\n    encoded_envelope = _encode(envelope, separator=separator)\n    logger.debug(\"write {!r}: to {}\".format(encoded_envelope, file_pointer.name))\n    write_with_lock(file_pointer, encoded_envelope, logger)\n\n\ndef write_with_lock(\n    file_pointer: IO[bytes], data: Union[bytes], logger: Logger = _default_logger\n) -> None:\n    \"\"\"Write bytes to file protected with file lock.\"\"\"\n    with lock_file(file_pointer, logger):\n        file_pointer.write(data)\n        file_pointer.flush()\n\n\ndef envelope_from_bytes(\n    bytes_: bytes, separator: bytes = SEPARATOR, logger: Logger = _default_logger\n) -> Optional[Envelope]:\n    \"\"\"\n    Decode bytes to get the envelope.\n\n    :param bytes_: the encoded envelope\n    :param separator: the separator used\n    :param logger: the logger\n    :return: Envelope\n    \"\"\"\n    logger.debug(\"processing: {!r}\".format(bytes_))\n    envelope = None  # type: Optional[Envelope]\n    try:\n        envelope = _decode(bytes_, separator=separator)\n    except ValueError as e:\n        logger.error(\"Bad formatted input: {!r}. {}\".format(bytes_, e))\n    except Exception as e:  # pragma: nocover # pylint: disable=broad-except\n        logger.exception(\"Error when processing a input. Message: {}\".format(str(e)))\n    return envelope\n"
  },
  {
    "path": "aea/helpers/file_lock.py",
    "content": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Patch of 'fnctl' to make it compatible with Windows.\"\"\"\n\nimport os\nfrom typing import IO\n\n\n# needs win32all to work on Windows\nif os.name == \"nt\":  # pragma: nocover  # cause platform dependent!\n    import pywintypes  # pylint: disable=import-error\n    import win32con  # pylint: disable=import-error\n    import win32file  # pylint: disable=import-error\n\n    LOCK_EX = win32con.LOCKFILE_EXCLUSIVE_LOCK\n    LOCK_SH = 0  # the default\n    LOCK_NB = win32con.LOCKFILE_FAIL_IMMEDIATELY\n    __overlapped = pywintypes.OVERLAPPED()\n\n    def lock(file: IO, flags: int) -> None:\n        \"\"\"Lock a file with flags.\"\"\"\n        hfile = win32file._get_osfhandle(  # pylint: disable=protected-access\n            file.fileno()\n        )\n        win32file.LockFileEx(hfile, flags, 0, 0xFFFF0000, __overlapped)\n\n    def unlock(file: IO) -> None:\n        \"\"\"Unlock a file.\"\"\"\n        hfile = win32file._get_osfhandle(  # pylint: disable=protected-access\n            file.fileno()\n        )\n        win32file.UnlockFileEx(hfile, 0, 0xFFFF0000, __overlapped)\n\nelif os.name == \"posix\":  # pragma: nocover  # cause platform dependent!\n    import fcntl\n    from fcntl import LOCK_EX, LOCK_NB, LOCK_SH  # noqa # pylint: disable=unused-import\n\n    def lock(file: IO, flags: int) -> None:\n        \"\"\"Lock a file with flags.\"\"\"\n        fcntl.flock(file.fileno(), flags)\n\n    def unlock(file: IO) -> None:\n        \"\"\"Unlock a file.\"\"\"\n        fcntl.flock(file.fileno(), fcntl.LOCK_UN)\n\nelse:  # pragma: nocover\n    raise RuntimeError(\"This module only works for nt and posix platforms\")\n"
  },
  {
    "path": "aea/helpers/http_requests.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Wrapper over requests library.\"\"\"\nfrom functools import wraps\nfrom typing import Any, Callable\n\nimport requests\n\nfrom aea.helpers.constants import NETWORK_REQUEST_DEFAULT_TIMEOUT\n\n\nDEFAULT_TIMEOUT = NETWORK_REQUEST_DEFAULT_TIMEOUT\n\n\n# requests can use one of these\ntry:\n    from simplejson.errors import (  # type: ignore  # pylint: disable=unused-import\n        JSONDecodeError,\n    )\nexcept ModuleNotFoundError:  # pragma: nocover\n    from json.decoder import (  # type: ignore # noqa  # pylint: disable=unused-import\n        JSONDecodeError,\n    )\n\n\ndef add_default_timeout(fn: Callable, timeout: float) -> Callable:\n    \"\"\"Add default timeout for requests methods.\"\"\"\n\n    @wraps(fn)\n    def wrapper(*args: Any, **kwargs: Any) -> Callable:  # pragma: nocover\n        kwargs[\"timeout\"] = kwargs.get(\"timeout\", timeout)\n        return fn(*args, **kwargs)\n\n    return wrapper\n\n\nget = add_default_timeout(requests.get, DEFAULT_TIMEOUT)\npost = add_default_timeout(requests.post, DEFAULT_TIMEOUT)\nrequest = add_default_timeout(requests.request, DEFAULT_TIMEOUT)\nhead = add_default_timeout(requests.head, DEFAULT_TIMEOUT)\n\nexceptions = requests.exceptions\n\nResponse = requests.Response\nConnectionError = requests.ConnectionError  # pylint: disable=redefined-builtin\n"
  },
  {
    "path": "aea/helpers/install_dependency.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Helper to install python dependencies.\"\"\"\nimport subprocess  # nosec\nimport sys\nfrom itertools import chain\nfrom logging import Logger\nfrom subprocess import PIPE  # nosec\nfrom typing import List\n\nfrom aea.configurations.base import Dependency\nfrom aea.exceptions import AEAException, enforce\n\n\ndef install_dependency(\n    dependency_name: str,\n    dependency: Dependency,\n    logger: Logger,\n    install_timeout: float = 300,\n) -> None:\n    \"\"\"\n    Install python dependency to the current python environment.\n\n    :param dependency_name: name of the python package\n    :param dependency: Dependency specification\n    :param logger: the logger\n    :param install_timeout: timeout to wait pip to install\n    \"\"\"\n    try:\n        pip_args = dependency.get_pip_install_args()\n        logger.debug(\"Calling 'pip install {}'\".format(\" \".join(pip_args)))\n        call_pip([\"install\", *pip_args], timeout=install_timeout, retry=True)\n    except Exception as e:\n        raise AEAException(\n            f\"An error occurred while installing {dependency_name}, {dependency}: {e}\"\n        )\n\n\ndef install_dependencies(\n    dependencies: List[Dependency],\n    logger: Logger,\n    install_timeout: float = 300,\n) -> None:\n    \"\"\"\n    Install python dependencies to the current python environment.\n\n    :param dependencies: dict of dependency name and specification\n    :param logger: the logger\n    :param install_timeout: timeout to wait pip to install\n    \"\"\"\n    try:\n        pip_args = list(chain(*[d.get_pip_install_args() for d in dependencies]))\n        pip_args = [(\"--extra-index\" if i == \"-i\" else i) for i in pip_args]\n        logger.debug(\"Calling 'pip install {}'\".format(\" \".join(pip_args)))\n        call_pip([\"install\", *pip_args], timeout=install_timeout, retry=True)\n    except Exception as e:\n        raise AEAException(\n            f\"An error occurred while installing with pip install {' '.join(pip_args)}: {e}\"\n        )\n\n\ndef call_pip(pip_args: List[str], timeout: float = 300, retry: bool = False) -> None:\n    \"\"\"\n    Run pip install command.\n\n    :param pip_args: list strings of the command\n    :param timeout: timeout to wait pip to install\n    :param retry: bool, try one more time if command failed\n    \"\"\"\n    command = [sys.executable, \"-m\", \"pip\", *pip_args]\n\n    result = subprocess.run(  # nosec\n        command, stdout=PIPE, stderr=PIPE, timeout=timeout, check=False\n    )\n    if result.returncode == 1 and retry:\n        # try a second time\n        result = subprocess.run(  # nosec\n            command, stdout=PIPE, stderr=PIPE, timeout=timeout, check=False\n        )\n    enforce(\n        result.returncode == 0,\n        f\"pip install failed. Return code != 0: stderr is {str(result.stderr)}\",\n    )\n\n\ndef run_install_subprocess(\n    install_command: List[str], install_timeout: float = 300\n) -> int:  # pragma: nocover\n    \"\"\"\n    Try executing install command.\n\n    :param install_command: list strings of the command\n    :param install_timeout: timeout to wait pip to install\n    :return: the return code of the subprocess\n    \"\"\"\n    with subprocess.Popen(install_command) as subp:  # nosec\n        subp.wait(install_timeout)\n        return subp.returncode\n"
  },
  {
    "path": "aea/helpers/io.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\nr\"\"\"\nWrapper over built-in \"open\" function.\n\nThis module contains a wrapper to the built-in 'open'\nfunction, the 'open_file' function, that fixes the\nkeyword argument 'newline' to be equal to \"\\n\" (the UNIX line separator).\nThis will force the line separator to be \"\\n\" both\nfor incoming and outgoing data.\n\nThe reason of this is that files written in an AEA package\nneed to have \"\\n\" as line separator, on all platforms. Otherwise,\nthe fingerprint of the packages involved would change across platforms\njust because the line separators are replaced.\n\nFor instance, the 'open' function on Windows, by default (newline=None),\nwould replace the line separators \"\\n\" with \"\\r\\n\".\nThis has an impact in the computation of the fingerprint.\n\nHence, any usage of file system functionalities\nshould either use 'open_file', or set 'newline=\"\\n\"' when\ncalling the 'open' or the 'pathlib.Path.open' functions.\n\"\"\"\nfrom functools import partial\nfrom pathlib import Path\nfrom typing import Callable, Optional, TextIO, Union\n\n\nUNIX_LINESEP = \"\\n\"\n\n_open_file_builtin: Callable = partial(open, newline=UNIX_LINESEP)\n_open_file_pathlib: Callable = partial(Path.open, newline=UNIX_LINESEP)\n\nPathNameTypes = Union[int, str, bytes, Path]\n\n\ndef open_file(\n    file: PathNameTypes,\n    mode: str = \"r\",\n    buffering: int = -1,\n    encoding: Optional[str] = None,\n    errors: Optional[str] = None,\n) -> TextIO:\n    r\"\"\"\n    Open a file.\n\n    Behaviour, kwargs and return type are the same for built-in 'open'\n    and pathlib.Path.open, except for 'newline', which is fixed to '\\n'.\n\n    For more details on the keyword arguments, please refer\n    to the documentation for the built-in 'open':\n\n        https://docs.python.org/3/library/functions.html#open\n\n    :param file: either a pathlib.Path object or the type accepted by 'open',\n            i.e. a string, bytes or integer.\n    :param mode: the mode in which the file is opened.\n    :param buffering: the buffering policy.\n    :param encoding: the name of the encoding used to decode or encode the file.\n    :param errors: how encoding errors are to be handled\n    :return: the IO object.\n    \"\"\"\n    if \"b\" in mode:\n        raise ValueError(\"This function can only work in text mode.\")\n    actual_wrapped_function = _open_file_builtin\n    if isinstance(file, Path):\n        actual_wrapped_function = _open_file_pathlib\n    return actual_wrapped_function(\n        file, mode=mode, buffering=buffering, encoding=encoding, errors=errors\n    )\n"
  },
  {
    "path": "aea/helpers/ipfs/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains helper methods and classes for the 'aea' package.\"\"\"\nfrom aea.helpers.ipfs.utils import _protobuf_python_implementation\n\n\n# fix for ipfs hashes, preload protobuf classes with protobuf python implementation\nwith _protobuf_python_implementation():\n    from aea.helpers.ipfs.pb import (  # noqa: F401   # pylint: disable=import-outside-toplevel,unused-import\n        merkledag_pb2,\n        unixfs_pb2,\n    )\n    from aea.helpers.ipfs.pb.merkledag_pb2 import (  # noqa: F401   # pylint: disable=import-outside-toplevel,unused-import\n        PBNode,\n    )\n"
  },
  {
    "path": "aea/helpers/ipfs/base.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains helper methods and classes for the 'aea' package.\"\"\"\nimport codecs\nimport hashlib\nimport io\nimport re\nfrom typing import Generator, Sized, cast\n\nimport base58\n\nfrom aea.helpers.io import open_file\nfrom aea.helpers.ipfs.utils import _protobuf_python_implementation\n\n\n# https://github.com/multiformats/multicodec/blob/master/table.csv\nSHA256_ID = \"12\"  # 0x12\nLEN_SHA256 = \"20\"  # 0x20\n\n\nwith _protobuf_python_implementation():  # pylint: disable=import-outside-toplevel\n    from aea.helpers.ipfs.pb import merkledag_pb2, unixfs_pb2\n    from aea.helpers.ipfs.pb.merkledag_pb2 import PBNode\n\n\ndef _dos2unix(file_content: bytes) -> bytes:\n    \"\"\"\n    Replace occurrences of Windows line terminator CR/LF with only LF.\n\n    :param file_content: the content of the file.\n    :return: the same content but with the line terminator\n    \"\"\"\n    return re.sub(b\"\\r\\n\", b\"\\n\", file_content, flags=re.M)\n\n\ndef _is_text(file_path: str) -> bool:\n    \"\"\"Check if a file can be read as text or not.\"\"\"\n    try:\n        with open_file(file_path, \"r\") as f:\n            f.read()\n        return True\n    except UnicodeDecodeError:\n        return False\n\n\ndef _read(file_path: str) -> bytes:\n    \"\"\"Read a file, replacing Windows line endings if it is a text file.\"\"\"\n    is_text = _is_text(file_path)\n    with open(file_path, \"rb\") as file:\n        file_b = file.read()\n        if is_text:\n            file_b = _dos2unix(file_b)\n\n    return file_b\n\n\ndef chunks(data: Sized, size: int) -> Generator:\n    \"\"\"Yield successivesize chunks from data.\"\"\"\n    for i in range(0, len(data), size):\n        yield data[i : i + size]  # type: ignore\n\n\nclass IPFSHashOnly:\n    \"\"\"A helper class which allows construction of an IPFS hash without interacting with an IPFS daemon.\"\"\"\n\n    DEFAULT_CHUNK_SIZE = 262144\n    # according to https://pkg.go.dev/github.com/ipfs/go-ipfs-chunker#pkg-constants\n\n    def get(self, file_path: str) -> str:\n        \"\"\"\n        Get the IPFS hash for a single file.\n\n        :param file_path: the file path\n        :return: the ipfs hash\n        \"\"\"\n        file_b = _read(file_path)\n        file_pb = self._pb_serialize_file(file_b)\n        ipfs_hash = self._generate_multihash(file_pb)\n        return ipfs_hash\n\n    @classmethod\n    def _make_unixfs_pb2(cls, data: bytes) -> bytes:\n        if len(data) > cls.DEFAULT_CHUNK_SIZE:  # pragma: nocover\n            raise ValueError(\"Data is too big! use chunks!\")\n        data_pb = unixfs_pb2.Data()  # type: ignore\n        data_pb.Type = unixfs_pb2.Data.File  # type: ignore # pylint: disable=no-member\n        data_pb.Data = data\n        data_pb.filesize = len(data)\n        serialized_data = data_pb.SerializeToString(deterministic=True)\n        return serialized_data\n\n    @classmethod\n    def _pb_serialize_data(cls, data: bytes) -> bytes:\n        outer_node = PBNode()  # type: ignore\n        outer_node.Data = cls._make_unixfs_pb2(data)\n        result = cls._serialize(outer_node)\n        return result\n\n    @classmethod\n    def _pb_serialize_file(cls, data: bytes) -> bytes:\n        \"\"\"\n        Serialize a bytes object representing a file.\n\n        :param data: a bytes string representing a file\n        :return: a bytes string representing a file in protobuf serialization\n        \"\"\"\n        if len(data) > cls.DEFAULT_CHUNK_SIZE:\n            outer_node = PBNode()  # type: ignore\n            data_pb = unixfs_pb2.Data()  # type: ignore\n            data_pb.Type = unixfs_pb2.Data.File  # type: ignore # pylint: disable=no-member\n            data_pb.filesize = len(data)\n            for chunk in chunks(data, cls.DEFAULT_CHUNK_SIZE):\n                link = merkledag_pb2.PBLink()\n                block = cls._pb_serialize_data(chunk)\n                link.Hash = cls._generate_multihash_bytes(block)\n                link.Tsize = len(block)\n                link.Name = \"\"\n                outer_node.Links.append(link)  # type: ignore # pylint: disable=no-member\n                data_pb.blocksizes.append(len(chunk))  # type: ignore # pylint: disable=no-member\n            outer_node.Data = data_pb.SerializeToString(deterministic=True)\n            return cls._serialize(outer_node)\n        return cls._pb_serialize_data(data)\n\n    @staticmethod\n    def _generate_multihash_bytes(pb_data: bytes) -> bytes:\n        sha256_hash = hashlib.sha256(pb_data).hexdigest()\n        multihash_hex = SHA256_ID + LEN_SHA256 + sha256_hash\n        multihash_bytes = codecs.decode(str.encode(multihash_hex), \"hex\")\n        return cast(bytes, multihash_bytes)\n\n    @classmethod\n    def _generate_multihash(cls, pb_data: bytes) -> str:\n        \"\"\"\n        Generate an IPFS multihash.\n\n        Uses the default IPFS hashing function: sha256\n\n        :param pb_data: the data to be hashed\n        :return: string representing the hash\n        \"\"\"\n        multihash_bytes = cls._generate_multihash_bytes(pb_data)\n        ipfs_hash = base58.b58encode(multihash_bytes)\n        return str(ipfs_hash, \"utf-8\")\n\n    @classmethod\n    def _generate_hash(cls, data: bytes) -> str:\n        \"\"\"Generate hash for data.\"\"\"\n        pb_data = cls._pb_serialize_file(data)\n        return cls._generate_multihash(pb_data)\n\n    @classmethod\n    def _serialize(cls, pb_node: PBNode) -> bytes:  # type: ignore\n        \"\"\"Serialize PBNode instance with fixed fields sequence.\"\"\"\n        f = io.BytesIO()\n        for field_descriptor, field_value in reversed(pb_node.ListFields()):  # type: ignore\n            field_descriptor._encoder(  # pylint: disable=protected-access\n                f.write, field_value, True\n            )\n        return f.getvalue()\n"
  },
  {
    "path": "aea/helpers/ipfs/pb/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains helper methods and classes for the 'aea' package.\"\"\"\n"
  },
  {
    "path": "aea/helpers/ipfs/pb/merkledag.proto",
    "content": "// source: https://github.com/ipfs/go-merkledag/blob/master/pb/merkledag.proto\nsyntax = \"proto2\";\n\npackage merkledag.pb;\n\n// An IPFS MerkleDAG Link\nmessage PBLink {\n\n  // multihash of the target object\n  optional bytes Hash = 1;\n\n  // utf string name. should be unique per object\n  optional string Name = 2;\n\n  // cumulative size of target object\n  optional uint64 Tsize = 3;\n}\n\n// An IPFS MerkleDAG Node\nmessage PBNode {\n\n  // refs to other objects\n  repeated PBLink Links = 2;\n\n  // opaque user data\n  optional bytes Data = 1;\n}"
  },
  {
    "path": "aea/helpers/ipfs/pb/merkledag_pb2.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by the protocol buffer compiler.  DO NOT EDIT!\n# source: merkledag.proto\n\"\"\"Generated protocol buffer code.\"\"\"\nfrom google.protobuf import descriptor as _descriptor\nfrom google.protobuf import message as _message\nfrom google.protobuf import reflection as _reflection\nfrom google.protobuf import symbol_database as _symbol_database\n\n# @@protoc_insertion_point(imports)\n\n_sym_db = _symbol_database.Default()\n\n\nDESCRIPTOR = _descriptor.FileDescriptor(\n    name=\"merkledag.proto\",\n    package=\"merkledag.pb\",\n    syntax=\"proto2\",\n    serialized_options=None,\n    create_key=_descriptor._internal_create_key,\n    serialized_pb=b'\\n\\x0fmerkledag.proto\\x12\\x0cmerkledag.pb\"3\\n\\x06PBLink\\x12\\x0c\\n\\x04Hash\\x18\\x01 \\x01(\\x0c\\x12\\x0c\\n\\x04Name\\x18\\x02 \\x01(\\t\\x12\\r\\n\\x05Tsize\\x18\\x03 \\x01(\\x04\";\\n\\x06PBNode\\x12#\\n\\x05Links\\x18\\x02 \\x03(\\x0b\\x32\\x14.merkledag.pb.PBLink\\x12\\x0c\\n\\x04\\x44\\x61ta\\x18\\x01 \\x01(\\x0c',\n)\n\n\n_PBLINK = _descriptor.Descriptor(\n    name=\"PBLink\",\n    full_name=\"merkledag.pb.PBLink\",\n    filename=None,\n    file=DESCRIPTOR,\n    containing_type=None,\n    create_key=_descriptor._internal_create_key,\n    fields=[\n        _descriptor.FieldDescriptor(\n            name=\"Hash\",\n            full_name=\"merkledag.pb.PBLink.Hash\",\n            index=0,\n            number=1,\n            type=12,\n            cpp_type=9,\n            label=1,\n            has_default_value=False,\n            default_value=b\"\",\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.FieldDescriptor(\n            name=\"Name\",\n            full_name=\"merkledag.pb.PBLink.Name\",\n            index=1,\n            number=2,\n            type=9,\n            cpp_type=9,\n            label=1,\n            has_default_value=False,\n            default_value=b\"\".decode(\"utf-8\"),\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.FieldDescriptor(\n            name=\"Tsize\",\n            full_name=\"merkledag.pb.PBLink.Tsize\",\n            index=2,\n            number=3,\n            type=4,\n            cpp_type=4,\n            label=1,\n            has_default_value=False,\n            default_value=0,\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n    ],\n    extensions=[],\n    nested_types=[],\n    enum_types=[],\n    serialized_options=None,\n    is_extendable=False,\n    syntax=\"proto2\",\n    extension_ranges=[],\n    oneofs=[],\n    serialized_start=33,\n    serialized_end=84,\n)\n\n\n_PBNODE = _descriptor.Descriptor(\n    name=\"PBNode\",\n    full_name=\"merkledag.pb.PBNode\",\n    filename=None,\n    file=DESCRIPTOR,\n    containing_type=None,\n    create_key=_descriptor._internal_create_key,\n    fields=[\n        _descriptor.FieldDescriptor(\n            name=\"Links\",\n            full_name=\"merkledag.pb.PBNode.Links\",\n            index=0,\n            number=2,\n            type=11,\n            cpp_type=10,\n            label=3,\n            has_default_value=False,\n            default_value=[],\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.FieldDescriptor(\n            name=\"Data\",\n            full_name=\"merkledag.pb.PBNode.Data\",\n            index=1,\n            number=1,\n            type=12,\n            cpp_type=9,\n            label=1,\n            has_default_value=False,\n            default_value=b\"\",\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n    ],\n    extensions=[],\n    nested_types=[],\n    enum_types=[],\n    serialized_options=None,\n    is_extendable=False,\n    syntax=\"proto2\",\n    extension_ranges=[],\n    oneofs=[],\n    serialized_start=86,\n    serialized_end=145,\n)\n\n_PBNODE.fields_by_name[\"Links\"].message_type = _PBLINK\nDESCRIPTOR.message_types_by_name[\"PBLink\"] = _PBLINK\nDESCRIPTOR.message_types_by_name[\"PBNode\"] = _PBNODE\n_sym_db.RegisterFileDescriptor(DESCRIPTOR)\n\nPBLink = _reflection.GeneratedProtocolMessageType(\n    \"PBLink\",\n    (_message.Message,),\n    {\n        \"DESCRIPTOR\": _PBLINK,\n        \"__module__\": \"merkledag_pb2\"\n        # @@protoc_insertion_point(class_scope:merkledag.pb.PBLink)\n    },\n)\n_sym_db.RegisterMessage(PBLink)\n\nPBNode = _reflection.GeneratedProtocolMessageType(\n    \"PBNode\",\n    (_message.Message,),\n    {\n        \"DESCRIPTOR\": _PBNODE,\n        \"__module__\": \"merkledag_pb2\"\n        # @@protoc_insertion_point(class_scope:merkledag.pb.PBNode)\n    },\n)\n_sym_db.RegisterMessage(PBNode)\n\n\n# @@protoc_insertion_point(module_scope)\n"
  },
  {
    "path": "aea/helpers/ipfs/pb/unixfs.proto",
    "content": "// source: https://github.com/ipfs/go-unixfs/blob/master/pb/unixfs.proto\nsyntax = \"proto2\";\n\npackage unixfs.pb;\n\nmessage Data {\n\tenum DataType {\n\t\tRaw = 0;\n\t\tDirectory = 1;\n\t\tFile = 2;\n\t\tMetadata = 3;\n\t\tSymlink = 4;\n\t\tHAMTShard = 5;\n\t}\n\n\trequired DataType Type = 1;\n\toptional bytes Data = 2;\n\toptional uint64 filesize = 3;\n\trepeated uint64 blocksizes = 4;\n\n\toptional uint64 hashType = 5;\n\toptional uint64 fanout = 6;\n}\n\nmessage Metadata {\n\toptional string MimeType = 1;\n}"
  },
  {
    "path": "aea/helpers/ipfs/pb/unixfs_pb2.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by the protocol buffer compiler.  DO NOT EDIT!\n# source: unixfs.proto\n\"\"\"Generated protocol buffer code.\"\"\"\nfrom google.protobuf import descriptor as _descriptor\nfrom google.protobuf import message as _message\nfrom google.protobuf import reflection as _reflection\nfrom google.protobuf import symbol_database as _symbol_database\n\n# @@protoc_insertion_point(imports)\n\n_sym_db = _symbol_database.Default()\n\n\nDESCRIPTOR = _descriptor.FileDescriptor(\n    name=\"unixfs.proto\",\n    package=\"unixfs.pb\",\n    syntax=\"proto2\",\n    serialized_options=None,\n    create_key=_descriptor._internal_create_key,\n    serialized_pb=b'\\n\\x0cunixfs.proto\\x12\\tunixfs.pb\"\\xdc\\x01\\n\\x04\\x44\\x61ta\\x12&\\n\\x04Type\\x18\\x01 \\x02(\\x0e\\x32\\x18.unixfs.pb.Data.DataType\\x12\\x0c\\n\\x04\\x44\\x61ta\\x18\\x02 \\x01(\\x0c\\x12\\x10\\n\\x08\\x66ilesize\\x18\\x03 \\x01(\\x04\\x12\\x12\\n\\nblocksizes\\x18\\x04 \\x03(\\x04\\x12\\x10\\n\\x08hashType\\x18\\x05 \\x01(\\x04\\x12\\x0e\\n\\x06\\x66\\x61nout\\x18\\x06 \\x01(\\x04\"V\\n\\x08\\x44\\x61taType\\x12\\x07\\n\\x03Raw\\x10\\x00\\x12\\r\\n\\tDirectory\\x10\\x01\\x12\\x08\\n\\x04\\x46ile\\x10\\x02\\x12\\x0c\\n\\x08Metadata\\x10\\x03\\x12\\x0b\\n\\x07Symlink\\x10\\x04\\x12\\r\\n\\tHAMTShard\\x10\\x05\"\\x1c\\n\\x08Metadata\\x12\\x10\\n\\x08MimeType\\x18\\x01 \\x01(\\t',\n)\n\n\n_DATA_DATATYPE = _descriptor.EnumDescriptor(\n    name=\"DataType\",\n    full_name=\"unixfs.pb.Data.DataType\",\n    filename=None,\n    file=DESCRIPTOR,\n    create_key=_descriptor._internal_create_key,\n    values=[\n        _descriptor.EnumValueDescriptor(\n            name=\"Raw\",\n            index=0,\n            number=0,\n            serialized_options=None,\n            type=None,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.EnumValueDescriptor(\n            name=\"Directory\",\n            index=1,\n            number=1,\n            serialized_options=None,\n            type=None,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.EnumValueDescriptor(\n            name=\"File\",\n            index=2,\n            number=2,\n            serialized_options=None,\n            type=None,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.EnumValueDescriptor(\n            name=\"Metadata\",\n            index=3,\n            number=3,\n            serialized_options=None,\n            type=None,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.EnumValueDescriptor(\n            name=\"Symlink\",\n            index=4,\n            number=4,\n            serialized_options=None,\n            type=None,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.EnumValueDescriptor(\n            name=\"HAMTShard\",\n            index=5,\n            number=5,\n            serialized_options=None,\n            type=None,\n            create_key=_descriptor._internal_create_key,\n        ),\n    ],\n    containing_type=None,\n    serialized_options=None,\n    serialized_start=162,\n    serialized_end=248,\n)\n_sym_db.RegisterEnumDescriptor(_DATA_DATATYPE)\n\n\n_DATA = _descriptor.Descriptor(\n    name=\"Data\",\n    full_name=\"unixfs.pb.Data\",\n    filename=None,\n    file=DESCRIPTOR,\n    containing_type=None,\n    create_key=_descriptor._internal_create_key,\n    fields=[\n        _descriptor.FieldDescriptor(\n            name=\"Type\",\n            full_name=\"unixfs.pb.Data.Type\",\n            index=0,\n            number=1,\n            type=14,\n            cpp_type=8,\n            label=2,\n            has_default_value=False,\n            default_value=0,\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.FieldDescriptor(\n            name=\"Data\",\n            full_name=\"unixfs.pb.Data.Data\",\n            index=1,\n            number=2,\n            type=12,\n            cpp_type=9,\n            label=1,\n            has_default_value=False,\n            default_value=b\"\",\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.FieldDescriptor(\n            name=\"filesize\",\n            full_name=\"unixfs.pb.Data.filesize\",\n            index=2,\n            number=3,\n            type=4,\n            cpp_type=4,\n            label=1,\n            has_default_value=False,\n            default_value=0,\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.FieldDescriptor(\n            name=\"blocksizes\",\n            full_name=\"unixfs.pb.Data.blocksizes\",\n            index=3,\n            number=4,\n            type=4,\n            cpp_type=4,\n            label=3,\n            has_default_value=False,\n            default_value=[],\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.FieldDescriptor(\n            name=\"hashType\",\n            full_name=\"unixfs.pb.Data.hashType\",\n            index=4,\n            number=5,\n            type=4,\n            cpp_type=4,\n            label=1,\n            has_default_value=False,\n            default_value=0,\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.FieldDescriptor(\n            name=\"fanout\",\n            full_name=\"unixfs.pb.Data.fanout\",\n            index=5,\n            number=6,\n            type=4,\n            cpp_type=4,\n            label=1,\n            has_default_value=False,\n            default_value=0,\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n    ],\n    extensions=[],\n    nested_types=[],\n    enum_types=[\n        _DATA_DATATYPE,\n    ],\n    serialized_options=None,\n    is_extendable=False,\n    syntax=\"proto2\",\n    extension_ranges=[],\n    oneofs=[],\n    serialized_start=28,\n    serialized_end=248,\n)\n\n\n_METADATA = _descriptor.Descriptor(\n    name=\"Metadata\",\n    full_name=\"unixfs.pb.Metadata\",\n    filename=None,\n    file=DESCRIPTOR,\n    containing_type=None,\n    create_key=_descriptor._internal_create_key,\n    fields=[\n        _descriptor.FieldDescriptor(\n            name=\"MimeType\",\n            full_name=\"unixfs.pb.Metadata.MimeType\",\n            index=0,\n            number=1,\n            type=9,\n            cpp_type=9,\n            label=1,\n            has_default_value=False,\n            default_value=b\"\".decode(\"utf-8\"),\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n    ],\n    extensions=[],\n    nested_types=[],\n    enum_types=[],\n    serialized_options=None,\n    is_extendable=False,\n    syntax=\"proto2\",\n    extension_ranges=[],\n    oneofs=[],\n    serialized_start=250,\n    serialized_end=278,\n)\n\n_DATA.fields_by_name[\"Type\"].enum_type = _DATA_DATATYPE\n_DATA_DATATYPE.containing_type = _DATA\nDESCRIPTOR.message_types_by_name[\"Data\"] = _DATA\nDESCRIPTOR.message_types_by_name[\"Metadata\"] = _METADATA\n_sym_db.RegisterFileDescriptor(DESCRIPTOR)\n\nData = _reflection.GeneratedProtocolMessageType(\n    \"Data\",\n    (_message.Message,),\n    {\n        \"DESCRIPTOR\": _DATA,\n        \"__module__\": \"unixfs_pb2\"\n        # @@protoc_insertion_point(class_scope:unixfs.pb.Data)\n    },\n)\n_sym_db.RegisterMessage(Data)\n\nMetadata = _reflection.GeneratedProtocolMessageType(\n    \"Metadata\",\n    (_message.Message,),\n    {\n        \"DESCRIPTOR\": _METADATA,\n        \"__module__\": \"unixfs_pb2\"\n        # @@protoc_insertion_point(class_scope:unixfs.pb.Metadata)\n    },\n)\n_sym_db.RegisterMessage(Metadata)\n\n\n# @@protoc_insertion_point(module_scope)\n"
  },
  {
    "path": "aea/helpers/ipfs/utils.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains utility methods for ipfs helpers.\"\"\"\nimport contextlib\nimport os\nimport sys\nfrom typing import Generator\n\n\n@contextlib.contextmanager\ndef _protobuf_python_implementation() -> Generator:\n    \"\"\"\n    Makes a context manager to force usage of the python implementation of the protobuf modules.\n\n    By default cpp version of the protobuf library is loaded.\n    This library does not provide all the needed tools to customize fields serialization order.\n    Python verrsion allows to use internal methods of the protobuf objects to serialize.\n    Custom serializations is required cause ipfs uses own version to serialize data to calculate data hash.\n    # noqa: DAR301\n    \"\"\"\n    PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION = \"PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION\"\n    # unload modules\n    saved_mods = {}\n    for mod_name, mod in list(sys.modules.items()):\n        if mod_name.startswith(\"google.protobuf\"):\n            saved_mods[mod_name] = mod\n            del sys.modules[mod_name]\n\n    prev_os_env = os.environ.get(PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION)\n    os.environ[PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION] = \"python\"\n\n    yield\n\n    if prev_os_env is None:  # pragma: nocover\n        del os.environ[PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION]\n    else:  # pragma: nocover\n        os.environ[PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION] = prev_os_env\n\n    for mod_name in list(sys.modules.keys()):\n        if mod_name.startswith(\"google.protobuf\"):\n            del sys.modules[mod_name]\n\n    for mod_name, mod in saved_mods.items():\n        sys.modules[mod_name] = mod\n"
  },
  {
    "path": "aea/helpers/logging.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Logging helpers.\"\"\"\nimport logging\nfrom logging import Logger, LoggerAdapter\nfrom typing import Any, MutableMapping, Optional, Tuple, cast\n\nfrom aea.helpers.base import _get_aea_logger_name_prefix\n\n\ndef get_logger(module_path: str, agent_name: str) -> Logger:\n    \"\"\"Get the logger based on a module path and agent name.\"\"\"\n    logger = logging.getLogger(_get_aea_logger_name_prefix(module_path, agent_name))\n    return logger\n\n\nclass AgentLoggerAdapter(LoggerAdapter):\n    \"\"\"This class is a logger adapter that prepends the agent name to log messages.\"\"\"\n\n    def __init__(self, logger: Logger, agent_name: str) -> None:\n        \"\"\"\n        Initialize the logger adapter.\n\n        :param logger: the logger.\n        :param agent_name: the agent name.\n        \"\"\"\n        super().__init__(logger, dict(agent_name=agent_name))\n\n    def process(\n        self, msg: Any, kwargs: MutableMapping[str, Any]\n    ) -> Tuple[Any, MutableMapping[str, Any]]:\n        \"\"\"Prepend the agent name to every log message.\"\"\"\n        return f\"[{self.extra['agent_name']}] {msg}\", kwargs\n\n\nclass WithLogger:\n    \"\"\"Interface to endow subclasses with a logger.\"\"\"\n\n    __slots__ = (\"_logger\", \"_default_logger_name\")\n\n    def __init__(\n        self,\n        logger: Optional[Logger] = None,\n        default_logger_name: str = \"aea\",\n    ) -> None:\n        \"\"\"\n        Initialize the logger.\n\n        :param logger: the logger object.\n        :param default_logger_name: the default logger name, if a logger is not provided.\n        \"\"\"\n        self._logger: Optional[Logger] = logger\n        self._default_logger_name = default_logger_name\n\n    @property\n    def logger(self) -> Logger:\n        \"\"\"Get the component logger.\"\"\"\n        if self._logger is None:\n            # if not set (e.g. programmatic instantiation)\n            # return a default one with the default logger name.\n            return logging.getLogger(self._default_logger_name)\n        return cast(Logger, self._logger)\n\n    @logger.setter\n    def logger(self, logger: Optional[Logger]) -> None:\n        \"\"\"Set the logger.\"\"\"\n        self._logger = logger\n"
  },
  {
    "path": "aea/helpers/multiaddr/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains multiaddress class.\"\"\"\n"
  },
  {
    "path": "aea/helpers/multiaddr/base.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains multiaddress class.\"\"\"\n\nfrom binascii import unhexlify\nfrom typing import Optional\n\nimport base58\nimport multihash  # type: ignore\nfrom ecdsa import VerifyingKey, curves, keys\n\nfrom aea.helpers.multiaddr.crypto_pb2 import KeyType, PublicKey\n\n\n# NOTE:\n# - Reference: https://github.com/libp2p/specs/blob/master/peer-ids/peer-ids.md#keys\n# - Implementation inspired from https://github.com/libp2p/py-libp2p\n# - On inlining see: https://github.com/libp2p/specs/issues/138\n# - Enabling inlining to be interoperable w/ the Go implementation\n\nENABLE_INLINING = True\nMAX_INLINE_KEY_LENGTH = 42\nIDENTITY_MULTIHASH_CODE = 0x00\n\nKEY_SIZE = 32\nZERO = b\"\\x00\"\n\nif ENABLE_INLINING:\n\n    class IdentityHash:\n        \"\"\"Neutral hashing implementation for inline multihashing.\"\"\"\n\n        _digest: bytes\n\n        def __init__(self) -> None:\n            \"\"\"Initialize IdentityHash object.\"\"\"\n            self._digest = bytearray()\n\n        def update(self, input_data: bytes) -> None:\n            \"\"\"\n            Update data to hash.\n\n            :param input_data: the data\n            \"\"\"\n            self._digest += input_data\n\n        def digest(self) -> bytes:\n            \"\"\"\n            Get hash of input data.\n\n            :return: the hash\n            \"\"\"\n            return self._digest\n\n    multihash.FuncReg.register(\n        IDENTITY_MULTIHASH_CODE, \"identity\", hash_new=IdentityHash\n    )\n\n\ndef _pad_scalar(scalar: bytes) -> bytes:\n    \"\"\"Pad scalar.\"\"\"\n    return (ZERO * (KEY_SIZE - len(scalar))) + scalar\n\n\ndef _pad_hex(hexed: str) -> str:\n    \"\"\"Pad odd-length hex strings.\"\"\"\n    return hexed if not len(hexed) & 1 else \"0\" + hexed\n\n\ndef _hex_to_bytes(hexed: str) -> bytes:\n    \"\"\"Hex to bytes.\"\"\"\n    return _pad_scalar(unhexlify(_pad_hex(hexed)))\n\n\nclass MultiAddr:\n    \"\"\"Protocol Labs' Multiaddress representation of a network address.\"\"\"\n\n    def __init__(\n        self,\n        host: str,\n        port: int,\n        public_key: Optional[str] = None,\n        multihash_id: Optional[str] = None,\n    ) -> None:\n        \"\"\"\n        Initialize a multiaddress.\n\n        :param host: ip host of the address\n        :param port: port number of the address\n        :param public_key: hex encoded public key. Must conform to Bitcoin EC encoding standard for Secp256k1\n        :param multihash_id: a multihash of the public key\n        \"\"\"\n\n        self._host = host\n        self._port = port\n\n        if public_key is not None:\n            try:\n                VerifyingKey._from_compressed(\n                    _hex_to_bytes(public_key), curves.SECP256k1\n                )\n            except keys.MalformedPointError as e:  # pragma: no cover\n                raise ValueError(\n                    \"Malformed public key '{}': {}\".format(public_key, str(e))\n                )\n\n            self._public_key = public_key\n            self._peerid = self.compute_peerid(self._public_key)\n        elif multihash_id is not None:\n            try:\n                multihash.decode(base58.b58decode(multihash_id))\n            except Exception as e:  # pylint: disable=broad-except\n                raise ValueError(\n                    \"Malformed multihash '{}': {}\".format(multihash_id, str(e))\n                )\n\n            self._public_key = \"\"\n            self._peerid = multihash_id\n        else:\n            raise ValueError(  # pragma: no cover\n                \"MultiAddr requires either public_key or multihash_id to be provided.\"\n            )\n\n    @staticmethod\n    def compute_peerid(public_key: str) -> str:\n        \"\"\"\n        Compute the peer id from a public key.\n\n        In particular, compute the base58 representation of\n        libp2p PeerID from Bitcoin EC encoded Secp256k1 public key.\n\n        :param public_key: the public key.\n        :return: the peer id.\n        \"\"\"\n        key_protobuf = PublicKey(\n            key_type=KeyType.Secp256k1, data=_hex_to_bytes(public_key)  # type: ignore\n        )\n        key_serialized = key_protobuf.SerializeToString()\n        algo = multihash.Func.sha2_256\n        if ENABLE_INLINING and len(key_serialized) <= MAX_INLINE_KEY_LENGTH:\n            algo = IDENTITY_MULTIHASH_CODE\n        key_mh = multihash.digest(key_serialized, algo)\n        return base58.b58encode(key_mh.encode()).decode()\n\n    @classmethod\n    def from_string(cls, maddr: str) -> \"MultiAddr\":\n        \"\"\"\n        Construct a MultiAddr object from its string format\n\n        :param maddr: multiaddress string\n        :return: multiaddress object\n        \"\"\"\n        parts = maddr.split(\"/\")\n        if len(parts) != 7 or not parts[4].isdigit():\n            raise ValueError(\"Malformed multiaddress '{}'\".format(maddr))\n\n        return cls(host=parts[2], port=int(parts[4]), multihash_id=parts[6])\n\n    @property\n    def public_key(self) -> str:\n        \"\"\"Get the public key.\"\"\"\n        return self._public_key\n\n    @property\n    def peer_id(self) -> str:\n        \"\"\"Get the peer id.\"\"\"\n        return self._peerid\n\n    @property\n    def host(self) -> str:\n        \"\"\"Get the peer host.\"\"\"\n        return self._host\n\n    @property\n    def port(self) -> int:\n        \"\"\"Get the peer port.\"\"\"\n        return self._port\n\n    def format(self) -> str:\n        \"\"\"Canonical representation of a multiaddress.\"\"\"\n        return f\"/dns4/{self._host}/tcp/{self._port}/p2p/{self._peerid}\"\n\n    def __str__(self) -> str:\n        \"\"\"Default string representation of a multiaddress.\"\"\"\n        return self.format()\n"
  },
  {
    "path": "aea/helpers/multiaddr/crypto.proto",
    "content": "syntax = \"proto2\";\n\npackage crypto.pb;\n\nenum KeyType {\n  RSA = 0;\n  Ed25519 = 1;\n  Secp256k1 = 2;\n  ECDSA = 3;\n}\n\nmessage PublicKey {\n  required KeyType key_type = 1;\n  required bytes data = 2;\n}\n\nmessage PrivateKey {\n  required KeyType key_type = 1;\n  required bytes data = 2;\n}"
  },
  {
    "path": "aea/helpers/multiaddr/crypto_pb2.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by the protocol buffer compiler.  DO NOT EDIT!\n# source: crypto.proto\n\"\"\"Generated protocol buffer code.\"\"\"\nfrom google.protobuf.internal import enum_type_wrapper\nfrom google.protobuf import descriptor as _descriptor\nfrom google.protobuf import message as _message\nfrom google.protobuf import reflection as _reflection\nfrom google.protobuf import symbol_database as _symbol_database\n\n# @@protoc_insertion_point(imports)\n\n_sym_db = _symbol_database.Default()\n\n\nDESCRIPTOR = _descriptor.FileDescriptor(\n    name=\"crypto.proto\",\n    package=\"crypto.pb\",\n    syntax=\"proto2\",\n    serialized_options=None,\n    create_key=_descriptor._internal_create_key,\n    serialized_pb=b'\\n\\x0c\\x63rypto.proto\\x12\\tcrypto.pb\"?\\n\\tPublicKey\\x12$\\n\\x08key_type\\x18\\x01 \\x02(\\x0e\\x32\\x12.crypto.pb.KeyType\\x12\\x0c\\n\\x04\\x64\\x61ta\\x18\\x02 \\x02(\\x0c\"@\\n\\nPrivateKey\\x12$\\n\\x08key_type\\x18\\x01 \\x02(\\x0e\\x32\\x12.crypto.pb.KeyType\\x12\\x0c\\n\\x04\\x64\\x61ta\\x18\\x02 \\x02(\\x0c*9\\n\\x07KeyType\\x12\\x07\\n\\x03RSA\\x10\\x00\\x12\\x0b\\n\\x07\\x45\\x64\\x32\\x35\\x35\\x31\\x39\\x10\\x01\\x12\\r\\n\\tSecp256k1\\x10\\x02\\x12\\t\\n\\x05\\x45\\x43\\x44SA\\x10\\x03',\n)\n\n_KEYTYPE = _descriptor.EnumDescriptor(\n    name=\"KeyType\",\n    full_name=\"crypto.pb.KeyType\",\n    filename=None,\n    file=DESCRIPTOR,\n    create_key=_descriptor._internal_create_key,\n    values=[\n        _descriptor.EnumValueDescriptor(\n            name=\"RSA\",\n            index=0,\n            number=0,\n            serialized_options=None,\n            type=None,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.EnumValueDescriptor(\n            name=\"Ed25519\",\n            index=1,\n            number=1,\n            serialized_options=None,\n            type=None,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.EnumValueDescriptor(\n            name=\"Secp256k1\",\n            index=2,\n            number=2,\n            serialized_options=None,\n            type=None,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.EnumValueDescriptor(\n            name=\"ECDSA\",\n            index=3,\n            number=3,\n            serialized_options=None,\n            type=None,\n            create_key=_descriptor._internal_create_key,\n        ),\n    ],\n    containing_type=None,\n    serialized_options=None,\n    serialized_start=158,\n    serialized_end=215,\n)\n_sym_db.RegisterEnumDescriptor(_KEYTYPE)\n\nKeyType = enum_type_wrapper.EnumTypeWrapper(_KEYTYPE)\nRSA = 0\nEd25519 = 1\nSecp256k1 = 2\nECDSA = 3\n\n\n_PUBLICKEY = _descriptor.Descriptor(\n    name=\"PublicKey\",\n    full_name=\"crypto.pb.PublicKey\",\n    filename=None,\n    file=DESCRIPTOR,\n    containing_type=None,\n    create_key=_descriptor._internal_create_key,\n    fields=[\n        _descriptor.FieldDescriptor(\n            name=\"key_type\",\n            full_name=\"crypto.pb.PublicKey.key_type\",\n            index=0,\n            number=1,\n            type=14,\n            cpp_type=8,\n            label=2,\n            has_default_value=False,\n            default_value=0,\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.FieldDescriptor(\n            name=\"data\",\n            full_name=\"crypto.pb.PublicKey.data\",\n            index=1,\n            number=2,\n            type=12,\n            cpp_type=9,\n            label=2,\n            has_default_value=False,\n            default_value=b\"\",\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n    ],\n    extensions=[],\n    nested_types=[],\n    enum_types=[],\n    serialized_options=None,\n    is_extendable=False,\n    syntax=\"proto2\",\n    extension_ranges=[],\n    oneofs=[],\n    serialized_start=27,\n    serialized_end=90,\n)\n\n\n_PRIVATEKEY = _descriptor.Descriptor(\n    name=\"PrivateKey\",\n    full_name=\"crypto.pb.PrivateKey\",\n    filename=None,\n    file=DESCRIPTOR,\n    containing_type=None,\n    create_key=_descriptor._internal_create_key,\n    fields=[\n        _descriptor.FieldDescriptor(\n            name=\"key_type\",\n            full_name=\"crypto.pb.PrivateKey.key_type\",\n            index=0,\n            number=1,\n            type=14,\n            cpp_type=8,\n            label=2,\n            has_default_value=False,\n            default_value=0,\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.FieldDescriptor(\n            name=\"data\",\n            full_name=\"crypto.pb.PrivateKey.data\",\n            index=1,\n            number=2,\n            type=12,\n            cpp_type=9,\n            label=2,\n            has_default_value=False,\n            default_value=b\"\",\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n    ],\n    extensions=[],\n    nested_types=[],\n    enum_types=[],\n    serialized_options=None,\n    is_extendable=False,\n    syntax=\"proto2\",\n    extension_ranges=[],\n    oneofs=[],\n    serialized_start=92,\n    serialized_end=156,\n)\n\n_PUBLICKEY.fields_by_name[\"key_type\"].enum_type = _KEYTYPE\n_PRIVATEKEY.fields_by_name[\"key_type\"].enum_type = _KEYTYPE\nDESCRIPTOR.message_types_by_name[\"PublicKey\"] = _PUBLICKEY\nDESCRIPTOR.message_types_by_name[\"PrivateKey\"] = _PRIVATEKEY\nDESCRIPTOR.enum_types_by_name[\"KeyType\"] = _KEYTYPE\n_sym_db.RegisterFileDescriptor(DESCRIPTOR)\n\nPublicKey = _reflection.GeneratedProtocolMessageType(\n    \"PublicKey\",\n    (_message.Message,),\n    {\n        \"DESCRIPTOR\": _PUBLICKEY,\n        \"__module__\": \"crypto_pb2\"\n        # @@protoc_insertion_point(class_scope:crypto.pb.PublicKey)\n    },\n)\n_sym_db.RegisterMessage(PublicKey)\n\nPrivateKey = _reflection.GeneratedProtocolMessageType(\n    \"PrivateKey\",\n    (_message.Message,),\n    {\n        \"DESCRIPTOR\": _PRIVATEKEY,\n        \"__module__\": \"crypto_pb2\"\n        # @@protoc_insertion_point(class_scope:crypto.pb.PrivateKey)\n    },\n)\n_sym_db.RegisterMessage(PrivateKey)\n\n\n# @@protoc_insertion_point(module_scope)\n"
  },
  {
    "path": "aea/helpers/multiple_executor.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the helpers to run multiple stoppable tasks in different modes: async, threaded, multiprocess .\"\"\"\nimport asyncio\nimport logging\nfrom abc import ABC, abstractmethod\nfrom asyncio.events import AbstractEventLoop\nfrom asyncio.tasks import FIRST_EXCEPTION, Task\nfrom concurrent.futures._base import Executor, Future\nfrom concurrent.futures.process import ProcessPoolExecutor\nfrom concurrent.futures.thread import ThreadPoolExecutor\nfrom enum import Enum\nfrom threading import Thread\nfrom typing import (\n    Any,\n    Callable,\n    Dict,\n    Optional,\n    Sequence,\n    Set,\n    Tuple,\n    Type,\n    Union,\n    cast,\n)\n\n\n_default_logger = logging.getLogger(__name__)\n\n\nTaskAwaitable = Union[Task, Future]\n\n\nclass ExecutorExceptionPolicies(Enum):\n    \"\"\"Runner exception policy modes.\"\"\"\n\n    stop_all = \"stop_all\"  # stop all agents on one agent's failure, log exception\n    propagate = \"propagate\"  # log exception and reraise it to upper level\n    log_only = \"log_only\"  # log exception and skip it\n\n\nclass AbstractExecutorTask(ABC):\n    \"\"\"Abstract task class to create Task classes.\"\"\"\n\n    def __init__(self) -> None:\n        \"\"\"Init task.\"\"\"\n        self._future: Optional[TaskAwaitable] = None\n\n    @property\n    def future(self) -> Optional[TaskAwaitable]:\n        \"\"\"Return awaitable to get result of task execution.\"\"\"\n        return self._future\n\n    @future.setter\n    def future(self, future: TaskAwaitable) -> None:\n        \"\"\"Set awaitable to get result of task execution.\"\"\"\n        self._future = future\n\n    @abstractmethod\n    def start(self) -> Tuple[Callable, Sequence[Any]]:\n        \"\"\"Implement start task function here.\"\"\"\n\n    @abstractmethod\n    def stop(self) -> None:\n        \"\"\"Implement stop task function here.\"\"\"\n\n    @abstractmethod\n    def create_async_task(self, loop: AbstractEventLoop) -> TaskAwaitable:\n        \"\"\"\n        Create asyncio task for task run in asyncio loop.\n\n        :param loop: the event loop\n        :return: task to run in asyncio loop.\n        \"\"\"\n\n    @property\n    def id(self) -> Any:  # pragma: nocover\n        \"\"\"Return task id.\"\"\"\n        return id(self)\n\n    @property\n    def failed(self) -> bool:\n        \"\"\"\n        Return was exception failed or not.\n\n        If it's running it's not failed.\n\n        :return: bool\n        \"\"\"\n        if not self._future:\n            return False\n\n        if not self._future.done():\n            return False\n\n        if not self._future.exception():\n            return False\n\n        if isinstance(self._future.exception(), KeyboardInterrupt):\n            return False\n\n        return True\n\n\nclass AbstractMultiprocessExecutorTask(AbstractExecutorTask):\n    \"\"\"Task for multiprocess executor.\"\"\"\n\n    @abstractmethod\n    def start(self) -> Tuple[Callable, Sequence[Any]]:\n        \"\"\"Return function and arguments to call within subprocess.\"\"\"\n\n    def create_async_task(\n        self, loop: AbstractEventLoop\n    ) -> TaskAwaitable:  # pragma: nocover\n        \"\"\"\n        Create asyncio task for task run in asyncio loop.\n\n        Raise error, cause async mode is not supported, cause this task for multiprocess executor only.\n\n        :param loop: the event loop\n        :raises ValueError: async task construction not possible\n        \"\"\"\n        raise ValueError(\n            \"This task was designed only for multiprocess executor, not for async!\"\n        )\n\n\nclass AbstractMultipleExecutor(ABC):  # pragma: nocover\n    \"\"\"Abstract class to create multiple executors classes.\"\"\"\n\n    def __init__(\n        self,\n        tasks: Sequence[AbstractExecutorTask],\n        task_fail_policy: ExecutorExceptionPolicies = ExecutorExceptionPolicies.propagate,\n    ) -> None:\n        \"\"\"\n        Init executor.\n\n        :param tasks: sequence of AbstractExecutorTask instances to run.\n        :param task_fail_policy: the exception policy of all the tasks\n        \"\"\"\n        self._task_fail_policy: ExecutorExceptionPolicies = task_fail_policy\n        self._tasks: Sequence[AbstractExecutorTask] = tasks\n        self._is_running: bool = False\n        self._future_task: Dict[TaskAwaitable, AbstractExecutorTask] = {}\n        self._loop: AbstractEventLoop = asyncio.new_event_loop()\n        self._executor_pool: Optional[Executor] = None\n        self._set_executor_pool()\n\n    @property\n    def is_running(self) -> bool:\n        \"\"\"Return running state of the executor.\"\"\"\n        return self._is_running\n\n    def start(self) -> None:\n        \"\"\"Start tasks.\"\"\"\n        self._start_tasks()\n        self._loop.run_until_complete(self._wait_tasks_complete())\n        self._is_running = False\n\n    def stop(self) -> None:\n        \"\"\"Stop tasks.\"\"\"\n        self._is_running = False\n\n        for task in self._tasks:\n            self._stop_task(task)\n\n        if not self._loop.is_running():\n            self._loop.run_until_complete(\n                self._wait_tasks_complete(skip_exceptions=True, on_stop=True)\n            )\n\n        if self._executor_pool:\n            self._executor_pool.shutdown(wait=True)\n\n    def _start_tasks(self) -> None:\n        \"\"\"Schedule tasks.\"\"\"\n        for task in self._tasks:\n            future = self._start_task(task)\n            task.future = future\n            self._future_task[future] = task\n\n    async def _wait_tasks_complete(\n        self, skip_exceptions: bool = False, on_stop: bool = False\n    ) -> None:\n        \"\"\"\n        Wait tasks execution to complete.\n\n        :param skip_exceptions: skip exceptions if raised in tasks\n        :param on_stop: bool, indicating if stopping\n        \"\"\"\n        if not on_stop:\n            self._is_running = True\n\n        pending = cast(Set[asyncio.futures.Future], set(self._future_task.keys()))\n\n        async def wait_future(future: asyncio.futures.Future) -> None:\n            try:\n                await future\n            except KeyboardInterrupt:  # pragma: nocover\n                _default_logger.exception(\"KeyboardInterrupt in task!\")\n                if not skip_exceptions:\n                    raise\n            except Exception as e:  # pylint: disable=broad-except  # handle any exception with own code.\n                _default_logger.exception(\"Exception in task!\")\n                if not skip_exceptions:\n                    await self._handle_exception(\n                        self._future_task[cast(TaskAwaitable, future)], e\n                    )\n\n        while pending:\n            done, pending = await asyncio.wait(pending, return_when=FIRST_EXCEPTION)\n            for future in done:\n                await wait_future(future)\n\n    async def _handle_exception(\n        self, task: AbstractExecutorTask, exc: Exception\n    ) -> None:\n        \"\"\"\n        Handle exception raised during task execution.\n\n        Log exception and process according to selected policy.\n\n        :param task: task exception handled in\n        :param exc: Exception raised\n        \"\"\"\n        _default_logger.exception(f\"Exception raised during {task.id} running.\")\n        _default_logger.info(f\"Exception raised during {task.id} running.\")\n        if self._task_fail_policy == ExecutorExceptionPolicies.propagate:\n            raise exc\n        if self._task_fail_policy == ExecutorExceptionPolicies.log_only:\n            pass\n        elif self._task_fail_policy == ExecutorExceptionPolicies.stop_all:\n            _default_logger.info(\n                \"Stopping executor according to fail policy cause exception raised in task\"\n            )\n            self.stop()\n            await self._wait_tasks_complete(skip_exceptions=True, on_stop=True)\n        else:  # pragma: nocover\n            raise ValueError(f\"Unknown fail policy: {self._task_fail_policy}\")\n\n    @abstractmethod\n    def _start_task(self, task: AbstractExecutorTask) -> TaskAwaitable:\n        \"\"\"\n        Start particular task.\n\n        :param task: AbstractExecutorTask instance to start.\n        :return: awaitable object(future) to get result or exception\n        \"\"\"\n\n    @abstractmethod\n    def _set_executor_pool(self) -> None:\n        \"\"\"Set executor pool to be used.\"\"\"\n\n    @staticmethod\n    def _stop_task(task: AbstractExecutorTask) -> None:\n        \"\"\"\n        Stop particular task.\n\n        :param task: AbstractExecutorTask instance to stop.\n        \"\"\"\n        task.stop()\n\n    @property\n    def num_failed(self) -> int:  # pragma: nocover\n        \"\"\"Return number of failed tasks.\"\"\"\n        return len(self.failed_tasks)\n\n    @property\n    def failed_tasks(self) -> Sequence[AbstractExecutorTask]:  # pragma: nocover\n        \"\"\"Return sequence failed tasks.\"\"\"\n        return [task for task in self._tasks if task.failed]\n\n    @property\n    def not_failed_tasks(self) -> Sequence[AbstractExecutorTask]:  # pragma: nocover\n        \"\"\"Return sequence successful tasks.\"\"\"\n        return [task for task in self._tasks if not task.failed]\n\n\nclass ThreadExecutor(AbstractMultipleExecutor):  # pragma: nocover\n    \"\"\"Thread based executor to run multiple agents in threads.\"\"\"\n\n    def _set_executor_pool(self) -> None:\n        \"\"\"Set thread pool pool to be used.\"\"\"\n        self._executor_pool = ThreadPoolExecutor(max_workers=len(self._tasks))\n\n    def _start_task(self, task: AbstractExecutorTask) -> TaskAwaitable:\n        \"\"\"\n        Start particular task.\n\n        :param task: AbstractExecutorTask instance to start.\n        :return: awaitable object(future) to get result or exception\n        \"\"\"\n        return cast(\n            TaskAwaitable, self._loop.run_in_executor(self._executor_pool, task.start)\n        )\n\n\nclass ProcessExecutor(ThreadExecutor):  # pragma: nocover\n    \"\"\"Subprocess based executor to run multiple agents in threads.\"\"\"\n\n    def _set_executor_pool(self) -> None:\n        \"\"\"Set thread pool pool to be used.\"\"\"\n        self._executor_pool = ProcessPoolExecutor(max_workers=len(self._tasks))\n\n    def _start_task(self, task: AbstractExecutorTask) -> TaskAwaitable:\n        \"\"\"\n        Start particular task.\n\n        :param task: AbstractExecutorTask instance to start.\n        :return: awaitable object(future) to get result or exception\n        \"\"\"\n        fn, args = task.start()\n        return cast(\n            TaskAwaitable, self._loop.run_in_executor(self._executor_pool, fn, *args)\n        )\n\n\nclass AsyncExecutor(AbstractMultipleExecutor):  # pragma: nocover\n    \"\"\"Thread based executor to run multiple agents in threads.\"\"\"\n\n    def _set_executor_pool(self) -> None:\n        \"\"\"Do nothing, cause we run tasks in asyncio event loop and do not need an executor pool.\"\"\"\n\n    def _start_task(self, task: AbstractExecutorTask) -> TaskAwaitable:\n        \"\"\"\n        Start particular task.\n\n        :param task: AbstractExecutorTask instance to start.\n        :return: awaitable object(future) to get result or exception\n        \"\"\"\n        return task.create_async_task(self._loop)\n\n\nclass AbstractMultipleRunner:  # pragma: nocover\n    \"\"\"Abstract multiple runner to create classes to launch tasks with selected mode.\"\"\"\n\n    SUPPORTED_MODES: Dict[str, Type[AbstractMultipleExecutor]] = {}\n\n    def __init__(\n        self,\n        mode: str,\n        fail_policy: ExecutorExceptionPolicies = ExecutorExceptionPolicies.propagate,\n    ) -> None:\n        \"\"\"\n        Init with selected executor mode.\n\n        :param mode: one of supported executor modes\n        :param fail_policy: one of ExecutorExceptionPolicies to be used with Executor\n        \"\"\"\n        if mode not in self.SUPPORTED_MODES:  # pragma: nocover\n            raise ValueError(f\"Unsupported mode: {mode}\")\n        self._mode: str = mode\n        self._executor: AbstractMultipleExecutor = self._make_executor(\n            mode, fail_policy\n        )\n        self._thread: Optional[Thread] = None\n\n    @property\n    def is_running(self) -> bool:\n        \"\"\"Return state of the executor.\"\"\"\n        return self._executor.is_running\n\n    def start(self, threaded: bool = False) -> None:\n        \"\"\"\n        Run agents.\n\n        :param threaded: run in dedicated thread without blocking current thread.\n        \"\"\"\n        if threaded:\n            self._thread = Thread(target=self._executor.start, daemon=True)\n            self._thread.start()\n        else:\n            self._executor.start()\n\n    def stop(self, timeout: Optional[float] = None) -> None:\n        \"\"\"\n        Stop agents.\n\n        :param timeout: timeout in seconds to wait thread stopped, only if started in thread mode.\n        \"\"\"\n        self._executor.stop()\n        if self._thread is not None:\n            self._thread.join(timeout=timeout)\n\n    def _make_executor(\n        self, mode: str, fail_policy: ExecutorExceptionPolicies\n    ) -> AbstractMultipleExecutor:\n        \"\"\"\n        Make an executor instance to run agents with.\n\n        :param mode: executor mode to use.\n        :param fail_policy: one of ExecutorExceptionPolicies to be used with Executor\n\n        :return: aea executor instance\n        \"\"\"\n        executor_cls = self.SUPPORTED_MODES[mode]\n        return executor_cls(tasks=self._make_tasks(), task_fail_policy=fail_policy)\n\n    @abstractmethod\n    def _make_tasks(self) -> Sequence[AbstractExecutorTask]:\n        \"\"\"Make tasks to run with executor.\"\"\"\n\n    @property\n    def num_failed(self) -> int:  # pragma: nocover\n        \"\"\"Return number of failed tasks.\"\"\"\n        return self._executor.num_failed\n\n    @property\n    def failed(self) -> Sequence[Task]:  # pragma: nocover\n        \"\"\"Return sequence failed tasks.\"\"\"\n        return [i.id for i in self._executor.failed_tasks]\n\n    @property\n    def not_failed(self) -> Sequence[Task]:  # pragma: nocover\n        \"\"\"Return sequence successful tasks.\"\"\"\n        return [i.id for i in self._executor.not_failed_tasks]\n\n    def try_join_thread(self) -> None:  # pragma: nocover\n        \"\"\"Try to join thread if running in thread mode.\"\"\"\n        if self._thread is None:\n            raise ValueError(\"Not started in thread mode.\")\n        # do not block with join, helpful to catch KeyboardInterrupt exception\n        while self._thread.is_alive():\n            self._thread.join(0.1)\n"
  },
  {
    "path": "aea/helpers/pipe.py",
    "content": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Portable pipe implementation for Linux, MacOS, and Windows.\"\"\"\nimport asyncio\nimport errno\nimport logging\nimport os\nimport socket\nimport struct\nimport tempfile\nfrom abc import ABC, abstractmethod\nfrom asyncio import AbstractEventLoop\nfrom asyncio.streams import StreamWriter\nfrom shutil import rmtree\nfrom typing import IO, Optional\n\nfrom aea.exceptions import enforce\n\n\n_default_logger = logging.getLogger(__name__)\n\nPIPE_CONN_TIMEOUT = 10.0\nPIPE_CONN_ATTEMPTS = 10\n\nTCP_SOCKET_PIPE_CLIENT_CONN_ATTEMPTS = 5\n\n\nclass IPCChannelClient(ABC):\n    \"\"\"Multi-platform interprocess communication channel for the client side.\"\"\"\n\n    @abstractmethod\n    async def connect(self, timeout: float = PIPE_CONN_TIMEOUT) -> bool:\n        \"\"\"\n        Connect to communication channel\n\n        :param timeout: timeout for other end to connect\n        :return: connection status\n        \"\"\"\n\n    @abstractmethod\n    async def write(self, data: bytes) -> None:\n        \"\"\"\n        Write `data` bytes to the other end of the channel\n\n        Will first write the size than the actual data\n\n        :param data: bytes to write\n        \"\"\"\n\n    @abstractmethod\n    async def read(self) -> Optional[bytes]:\n        \"\"\"\n        Read bytes from the other end of the channel\n\n        Will first read the size than the actual data\n\n        :return: read bytes\n        \"\"\"\n\n    @abstractmethod\n    async def close(self) -> None:\n        \"\"\"Close the communication channel.\"\"\"\n\n\nclass IPCChannel(IPCChannelClient):\n    \"\"\"Multi-platform interprocess communication channel.\"\"\"\n\n    @property\n    @abstractmethod\n    def in_path(self) -> str:\n        \"\"\"\n        Rendezvous point for incoming communication.\n\n        :return: path\n        \"\"\"\n\n    @property\n    @abstractmethod\n    def out_path(self) -> str:\n        \"\"\"\n        Rendezvous point for outgoing communication.\n\n        :return: path\n        \"\"\"\n\n\nclass PosixNamedPipeProtocol:\n    \"\"\"Posix named pipes async wrapper communication protocol.\"\"\"\n\n    def __init__(\n        self,\n        in_path: str,\n        out_path: str,\n        logger: logging.Logger = _default_logger,\n        loop: Optional[AbstractEventLoop] = None,\n    ) -> None:\n        \"\"\"\n        Initialize a new posix named pipe.\n\n        :param in_path: rendezvous point for incoming data\n        :param out_path: rendezvous point for outgoing data\n        :param logger: the logger\n        :param loop: the event loop\n        \"\"\"\n\n        self.logger = logger\n        self._loop = loop\n        self._in_path = in_path\n        self._out_path = out_path\n        self._in = -1\n        self._out = -1\n\n        self._stream_reader = None  # type: Optional[asyncio.StreamReader]\n        self._reader_protocol = None  # type: Optional[asyncio.StreamReaderProtocol]\n        self._fileobj = None  # type: Optional[IO[str]]\n\n        self._connection_attempts = PIPE_CONN_ATTEMPTS\n        self._connection_timeout = PIPE_CONN_TIMEOUT\n\n    async def connect(self, timeout: float = PIPE_CONN_TIMEOUT) -> bool:\n        \"\"\"\n        Connect to the other end of the pipe\n\n        :param timeout: timeout before failing\n        :return: connection success\n        \"\"\"\n\n        if self._loop is None:\n            self._loop = asyncio.get_event_loop()\n\n        self._connection_timeout = timeout / PIPE_CONN_ATTEMPTS if timeout > 0 else 0\n        if self._connection_attempts <= 1:  # pragma: no cover\n            return False\n        self._connection_attempts -= 1\n\n        self.logger.debug(\n            \"Attempt opening pipes {}, {}...\".format(self._in_path, self._out_path)\n        )\n\n        self._in = os.open(self._in_path, os.O_RDONLY | os.O_NONBLOCK | os.O_SYNC)\n\n        try:\n            self._out = os.open(self._out_path, os.O_WRONLY | os.O_NONBLOCK)\n        except OSError as e:  # pragma: no cover\n            if e.errno == errno.ENXIO:\n                self.logger.debug(\"Sleeping for {}...\".format(self._connection_timeout))\n                await asyncio.sleep(self._connection_timeout)\n                return await self.connect(timeout)\n            raise e\n\n        # setup reader\n        enforce(\n            self._in != -1 and self._out != -1 and self._loop is not None,\n            \"Incomplete initialization.\",\n        )\n        self._stream_reader = asyncio.StreamReader(loop=self._loop)\n        self._reader_protocol = asyncio.StreamReaderProtocol(\n            self._stream_reader, loop=self._loop\n        )\n        self._fileobj = os.fdopen(self._in, \"r\")\n        await self._loop.connect_read_pipe(\n            lambda: self.__reader_protocol, self._fileobj\n        )\n\n        return True\n\n    @property\n    def __reader_protocol(self) -> asyncio.StreamReaderProtocol:\n        \"\"\"Get reader protocol.\"\"\"\n        if self._reader_protocol is None:\n            raise ValueError(\"reader protocol not set!\")  # pragma: nocover\n        return self._reader_protocol\n\n    async def write(self, data: bytes) -> None:\n        \"\"\"\n        Write to pipe.\n\n        :param data: bytes to write to pipe\n        \"\"\"\n        self.logger.debug(\"writing {}...\".format(len(data)))\n        size = struct.pack(\"!I\", len(data))\n        os.write(self._out, size + data)\n        await asyncio.sleep(0.0)\n\n    async def read(self) -> Optional[bytes]:\n        \"\"\"\n        Read from pipe.\n\n        :return: read bytes\n        \"\"\"\n        if self._stream_reader is None:  # pragma: nocover\n            raise ValueError(\"StreamReader not set, call connect first!\")\n        try:\n            self.logger.debug(\"waiting for messages (in={})...\".format(self._in_path))\n            buf = await self._stream_reader.readexactly(4)\n            if not buf:  # pragma: no cover\n                return None\n            size = struct.unpack(\"!I\", buf)[0]\n            if size <= 0:  # pragma: no cover\n                return None\n            data = await self._stream_reader.readexactly(size)\n            if not data:  # pragma: no cover\n                return None\n            return data\n        except asyncio.IncompleteReadError as e:  # pragma: no cover\n            self.logger.info(\n                \"Connection disconnected while reading from pipe ({}/{})\".format(\n                    len(e.partial), e.expected\n                )\n            )\n            return None\n        except asyncio.CancelledError:  # pragma: no cover\n            return None\n\n    async def close(self) -> None:\n        \"\"\"Disconnect pipe.\"\"\"\n        self.logger.debug(\"closing pipe (in={})...\".format(self._in_path))\n        if self._fileobj is None:\n            raise ValueError(\"Pipe not connected\")  # pragma: nocover\n        try:\n            # hack for MacOSX\n            size = struct.pack(\"!I\", 0)\n            os.write(self._out, size)\n\n            os.close(self._out)\n            self._fileobj.close()\n        except OSError:  # pragma: no cover\n            pass\n        await asyncio.sleep(0)\n\n\nclass TCPSocketProtocol:\n    \"\"\"TCP socket communication protocol.\"\"\"\n\n    def __init__(\n        self,\n        reader: asyncio.StreamReader,\n        writer: asyncio.StreamWriter,\n        logger: logging.Logger = _default_logger,\n        loop: Optional[AbstractEventLoop] = None,\n    ) -> None:\n        \"\"\"\n        Initialize the tcp socket protocol.\n\n        :param reader: established asyncio reader\n        :param writer: established asyncio writer\n        :param logger: the logger\n        :param loop: the event loop\n        \"\"\"\n\n        self.logger = logger\n        self.loop = loop if loop is not None else asyncio.get_event_loop()\n        self._reader = reader\n        self._writer = writer\n\n    @property\n    def writer(self) -> StreamWriter:\n        \"\"\"Get a writer associated with  protocol.\"\"\"\n        return self._writer\n\n    async def write(self, data: bytes) -> None:\n        \"\"\"\n        Write to socket.\n\n        :param data: bytes to write\n        \"\"\"\n        if self._writer is None:\n            raise ValueError(\"writer not set!\")  # pragma: nocover\n        self.logger.debug(\"writing {}...\".format(len(data)))\n        size = struct.pack(\"!I\", len(data))\n        self._writer.write(size + data)\n        await self._writer.drain()\n\n    async def read(self) -> Optional[bytes]:\n        \"\"\"\n        Read from socket.\n\n        :return: read bytes\n        \"\"\"\n        try:\n            self.logger.debug(\"waiting for messages...\")\n            buf = await self._reader.readexactly(4)\n            if not buf:  # pragma: no cover\n                return None\n            size = struct.unpack(\"!I\", buf)[0]\n            data = await self._reader.readexactly(size)\n            if not data:  # pragma: no cover\n                return None\n            if len(data) != size:  # pragma: no cover\n                raise ValueError(\n                    f\"Incomplete Read Error! Expected size={size}, got: {len(data)}\"\n                )\n            return data\n        except asyncio.IncompleteReadError as e:  # pragma: no cover\n            self.logger.info(\n                \"Connection disconnected while reading from pipe ({}/{})\".format(\n                    len(e.partial), e.expected\n                )\n            )\n            return None\n        except asyncio.CancelledError:  # pragma: no cover\n            return None\n\n    async def close(self) -> None:\n        \"\"\"Disconnect socket.\"\"\"\n        if self._writer.can_write_eof():\n            self._writer.write_eof()\n        await self._writer.drain()\n        self._writer.close()\n        wait_closed = getattr(self._writer, \"wait_closed\", None)\n        if wait_closed:\n            # in py3.6 writer does not have the coroutine\n            await wait_closed()  # pragma: nocover\n\n\nclass TCPSocketChannel(IPCChannel):\n    \"\"\"Interprocess communication channel implementation using tcp sockets.\"\"\"\n\n    def __init__(\n        self,\n        logger: logging.Logger = _default_logger,\n        loop: Optional[AbstractEventLoop] = None,\n    ) -> None:\n        \"\"\"Initialize tcp socket interprocess communication channel.\"\"\"\n        self.logger = logger\n        self._loop = loop\n        self._server = None  # type: Optional[asyncio.AbstractServer]\n        self._connected = None  # type: Optional[asyncio.Event]\n        self._sock = None  # type: Optional[TCPSocketProtocol]\n\n        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\n        s.bind((\"127.0.0.1\", 0))\n        s.listen(1)\n        self._port = s.getsockname()[1]\n        s.close()\n\n    async def connect(self, timeout: float = PIPE_CONN_TIMEOUT) -> bool:\n        \"\"\"\n        Setup communication channel and wait for other end to connect.\n\n        :param timeout: timeout for the connection to be established\n        :return: connection status\n        \"\"\"\n\n        if self._loop is None:\n            self._loop = asyncio.get_event_loop()\n\n        self._connected = asyncio.Event()\n        self._server = await asyncio.start_server(\n            self._handle_connection, host=\"127.0.0.1\", port=self._port\n        )\n        if self._server.sockets is None:\n            raise ValueError(\"Server sockets is None!\")  # pragma: nocover\n        self._port = self._server.sockets[0].getsockname()[1]\n        self.logger.debug(\"socket pipe rdv point: {}\".format(self._port))\n\n        try:\n            await asyncio.wait_for(self._connected.wait(), timeout)\n        except asyncio.TimeoutError:  # pragma: no cover\n            return False\n\n        self._server.close()\n        await self._server.wait_closed()\n\n        return True\n\n    async def _handle_connection(\n        self, reader: asyncio.StreamReader, writer: asyncio.StreamWriter\n    ) -> None:\n        \"\"\"Handle connection.\"\"\"\n        if self._connected is None:\n            raise ValueError(\"Connected is None!\")  # pragma: nocover\n        self._connected.set()\n        self._sock = TCPSocketProtocol(\n            reader, writer, logger=self.logger, loop=self._loop\n        )\n\n    async def write(self, data: bytes) -> None:\n        \"\"\"\n        Write to channel.\n\n        :param data: bytes to write\n        \"\"\"\n        if self._sock is None:\n            raise ValueError(\"Socket pipe not connected.\")  # pragma: nocover\n        await self._sock.write(data)\n\n    async def read(self) -> Optional[bytes]:\n        \"\"\"\n        Read from channel.\n\n        :return: read bytes\n        \"\"\"\n        if self._sock is None:\n            raise ValueError(\"Socket pipe not connected.\")  # pragma: nocover\n        return await self._sock.read()\n\n    async def close(self) -> None:\n        \"\"\"Disconnect from channel and clean it up.\"\"\"\n        if self._sock is None:\n            raise ValueError(\"Socket pipe not connected.\")  # pragma: nocover\n        await self._sock.close()\n\n    @property\n    def in_path(self) -> str:\n        \"\"\"Rendezvous point for incoming communication.\"\"\"\n        return str(self._port)\n\n    @property\n    def out_path(self) -> str:\n        \"\"\"Rendezvous point for outgoing communication.\"\"\"\n        return str(self._port)\n\n\nclass PosixNamedPipeChannel(IPCChannel):\n    \"\"\"Interprocess communication channel implementation using Posix named pipes.\"\"\"\n\n    def __init__(\n        self,\n        logger: logging.Logger = _default_logger,\n        loop: Optional[AbstractEventLoop] = None,\n    ) -> None:\n        \"\"\"Initialize posix named pipe interprocess communication channel.\"\"\"\n        self.logger = logger\n        self._loop = loop\n\n        self._pipe_dir = tempfile.mkdtemp()\n        self._in_path = \"{}/process_to_aea\".format(self._pipe_dir)\n        self._out_path = \"{}/aea_to_process\".format(self._pipe_dir)\n\n        # setup fifos\n        self.logger.debug(\n            \"Creating pipes ({}, {})...\".format(self._in_path, self._out_path)\n        )\n        if os.path.exists(self._in_path):\n            os.remove(self._in_path)  # pragma: no cover\n        if os.path.exists(self._out_path):\n            os.remove(self._out_path)  # pragma: no cover\n        os.mkfifo(self._in_path)\n        os.mkfifo(self._out_path)\n\n        self._pipe = PosixNamedPipeProtocol(\n            self._in_path, self._out_path, logger=logger, loop=loop\n        )\n\n    async def connect(self, timeout: float = PIPE_CONN_TIMEOUT) -> bool:\n        \"\"\"\n        Setup communication channel and wait for other end to connect.\n\n        :param timeout: timeout for connection to be established\n        :return: bool, indicating success\n        \"\"\"\n\n        if self._loop is None:\n            self._loop = asyncio.get_event_loop()\n\n        return await self._pipe.connect(timeout)\n\n    async def write(self, data: bytes) -> None:\n        \"\"\"\n        Write to the channel.\n\n        :param data: data to write to channel\n        \"\"\"\n        await self._pipe.write(data)\n\n    async def read(self) -> Optional[bytes]:\n        \"\"\"\n        Read from the channel.\n\n        :return: read bytes\n        \"\"\"\n        return await self._pipe.read()\n\n    async def close(self) -> None:\n        \"\"\"Close the channel and clean it up.\"\"\"\n        await self._pipe.close()\n        rmtree(self._pipe_dir)\n\n    @property\n    def in_path(self) -> str:\n        \"\"\"Rendezvous point for incoming communication.\"\"\"\n        return self._in_path\n\n    @property\n    def out_path(self) -> str:\n        \"\"\"Rendezvous point for outgoing communication.\"\"\"\n        return self._out_path\n\n\nclass TCPSocketChannelClient(IPCChannelClient):\n    \"\"\"Interprocess communication channel client using tcp sockets.\"\"\"\n\n    def __init__(  # pylint: disable=unused-argument\n        self,\n        in_path: str,\n        out_path: str,\n        logger: logging.Logger = _default_logger,\n        loop: Optional[AbstractEventLoop] = None,\n    ) -> None:\n        \"\"\"\n        Initialize a tcp socket communication channel client.\n\n        :param in_path: rendezvous point for incoming data\n        :param out_path: rendezvous point for outgoing data\n        :param logger: the logger\n        :param loop: the event loop\n        \"\"\"\n        self.logger = logger\n        self._loop = loop\n        parts = in_path.split(\":\")\n        if len(parts) == 1:\n            self._port = int(in_path)\n            self._host = \"127.0.0.1\"\n        else:  # pragma: nocover\n            self._port = int(parts[1])\n            self._host = parts[0]\n        self._sock = None  # type: Optional[TCPSocketProtocol]\n\n        self._attempts = TCP_SOCKET_PIPE_CLIENT_CONN_ATTEMPTS\n        self._timeout = PIPE_CONN_TIMEOUT / self._attempts\n        self.last_exception: Optional[Exception] = None\n\n    async def connect(self, timeout: float = PIPE_CONN_TIMEOUT) -> bool:\n        \"\"\"\n        Connect to the other end of the communication channel.\n\n        :param timeout: timeout for connection to be established\n        :return: connection status\n        \"\"\"\n        if self._loop is None:\n            self._loop = asyncio.get_event_loop()\n\n        self._timeout = timeout / TCP_SOCKET_PIPE_CLIENT_CONN_ATTEMPTS\n\n        self.logger.debug(\n            \"Attempting to connect to {}:{}.....\".format(\"127.0.0.1\", self._port)\n        )\n\n        connected = False\n        while self._attempts > 0:\n            self._attempts -= 1\n            try:\n                self._sock = await self._open_connection()\n                connected = True\n                break\n            except ConnectionRefusedError:\n                await asyncio.sleep(self._timeout)\n            except Exception as e:  # pylint: disable=broad-except  # pragma: nocover\n                self.last_exception = e\n                return False\n\n        return connected\n\n    async def _open_connection(self) -> TCPSocketProtocol:\n        reader, writer = await asyncio.open_connection(\n            self._host,\n            self._port,  # pylint: disable=protected-access\n        )\n        return TCPSocketProtocol(reader, writer, logger=self.logger, loop=self._loop)\n\n    async def write(self, data: bytes) -> None:\n        \"\"\"\n        Write data to channel.\n\n        :param data: bytes to write\n        \"\"\"\n        if self._sock is None:\n            raise ValueError(\"Socket pipe not connected.\")  # pragma: nocover\n        await self._sock.write(data)\n\n    async def read(self) -> Optional[bytes]:\n        \"\"\"\n        Read data from channel.\n\n        :return: read bytes\n        \"\"\"\n        if self._sock is None:\n            raise ValueError(\"Socket pipe not connected.\")  # pragma: nocover\n        return await self._sock.read()\n\n    async def close(self) -> None:\n        \"\"\"Disconnect from communication channel.\"\"\"\n        if self._sock is None:\n            raise ValueError(\"Socket pipe not connected.\")  # pragma: nocover\n        await self._sock.close()\n\n\nclass PosixNamedPipeChannelClient(IPCChannelClient):\n    \"\"\"Interprocess communication channel client using Posix named pipes.\"\"\"\n\n    def __init__(\n        self,\n        in_path: str,\n        out_path: str,\n        logger: logging.Logger = _default_logger,\n        loop: Optional[AbstractEventLoop] = None,\n    ) -> None:\n        \"\"\"\n        Initialize a posix named pipe communication channel client.\n\n        :param in_path: rendezvous point for incoming data\n        :param out_path: rendezvous point for outgoing data\n        :param logger: the logger\n        :param loop: the event loop\n        \"\"\"\n\n        self.logger = logger\n        self._loop = loop\n\n        self._in_path = in_path\n        self._out_path = out_path\n        self._pipe = None  # type: Optional[PosixNamedPipeProtocol]\n        self.last_exception: Optional[Exception] = None\n\n    async def connect(self, timeout: float = PIPE_CONN_TIMEOUT) -> bool:\n        \"\"\"\n        Connect to the other end of the communication channel.\n\n        :param timeout: timeout for connection to be established\n        :return: connection status\n        \"\"\"\n\n        if self._loop is None:\n            self._loop = asyncio.get_event_loop()\n\n        self._pipe = PosixNamedPipeProtocol(\n            self._in_path, self._out_path, logger=self.logger, loop=self._loop\n        )\n        try:\n            return await self._pipe.connect()\n        except Exception as e:  # pragma: nocover  # pylint: disable=broad-except\n            self.last_exception = e\n            return False\n\n    async def write(self, data: bytes) -> None:\n        \"\"\"\n        Write data to channel.\n\n        :param data: bytes to write\n        \"\"\"\n        if self._pipe is None:\n            raise ValueError(\"Pipe not connected.\")  # pragma: nocover\n        await self._pipe.write(data)\n\n    async def read(self) -> Optional[bytes]:\n        \"\"\"\n        Read data from channel.\n\n        :return: read bytes\n        \"\"\"\n        if self._pipe is None:\n            raise ValueError(\"Pipe not connected.\")  # pragma: nocover\n        return await self._pipe.read()\n\n    async def close(self) -> None:\n        \"\"\"Disconnect from communication channel.\"\"\"\n        if self._pipe is None:\n            raise ValueError(\"Pipe not connected.\")  # pragma: nocover\n        return await self._pipe.close()\n\n\ndef make_ipc_channel(\n    logger: logging.Logger = _default_logger, loop: Optional[AbstractEventLoop] = None\n) -> IPCChannel:\n    \"\"\"\n    Build a portable bidirectional InterProcess Communication channel\n\n    :param logger: the logger\n    :param loop: the loop\n    :return: IPCChannel\n    \"\"\"\n    if os.name == \"posix\":\n        return PosixNamedPipeChannel(logger=logger, loop=loop)\n    if os.name == \"nt\":  # pragma: nocover\n        return TCPSocketChannel(logger=logger, loop=loop)\n    raise NotImplementedError(  # pragma: nocover\n        \"make ipc channel is not supported on platform {}\".format(os.name)\n    )\n\n\ndef make_ipc_channel_client(\n    in_path: str,\n    out_path: str,\n    logger: logging.Logger = _default_logger,\n    loop: Optional[AbstractEventLoop] = None,\n) -> IPCChannelClient:\n    \"\"\"\n    Build a portable bidirectional InterProcess Communication client channel\n\n    :param in_path: rendezvous point for incoming communication\n    :param out_path: rendezvous point for outgoing outgoing\n    :param logger: the logger\n    :param loop: the loop\n    :return: IPCChannel\n    \"\"\"\n    if os.name == \"posix\":\n        return PosixNamedPipeChannelClient(in_path, out_path, logger=logger, loop=loop)\n    if os.name == \"nt\":  # pragma: nocover\n        return TCPSocketChannelClient(in_path, out_path, logger=logger, loop=loop)\n    raise NotImplementedError(  # pragma: nocover\n        \"make ip channel client is not supported on platform {}\".format(os.name)\n    )\n"
  },
  {
    "path": "aea/helpers/preference_representations/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains helper methods and classes for preference representations.\"\"\"\n"
  },
  {
    "path": "aea/helpers/preference_representations/base.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Preference representation helpers.\"\"\"\n\nimport math\nfrom typing import Dict\n\nfrom aea.exceptions import enforce\n\n\ndef logarithmic_utility(\n    utility_params_by_good_id: Dict[str, float],\n    quantities_by_good_id: Dict[str, int],\n    quantity_shift: int = 100,\n) -> float:\n    \"\"\"\n    Compute agent's utility given her utility function params and a good bundle.\n\n    :param utility_params_by_good_id: utility params by good identifier\n    :param quantities_by_good_id: quantities by good identifier\n    :param quantity_shift: a non-negative factor to shift the quantities in the utility function (to ensure the natural logarithm can be used on the entire range of quantities)\n    :return: utility value\n    \"\"\"\n    enforce(\n        quantity_shift >= 0,\n        \"The quantity_shift argument must be a non-negative integer.\",\n    )\n\n    goodwise_utility = [\n        utility_params_by_good_id[good_id] * math.log(quantity + quantity_shift)\n        if quantity + quantity_shift > 0\n        else -10000\n        for good_id, quantity in quantities_by_good_id.items()\n    ]\n    return sum(goodwise_utility)\n\n\ndef linear_utility(\n    exchange_params_by_currency_id: Dict[str, float],\n    balance_by_currency_id: Dict[str, int],\n) -> float:\n    \"\"\"\n    Compute agent's utility given her utility function params and a good bundle.\n\n    :param exchange_params_by_currency_id: exchange params by currency\n    :param balance_by_currency_id: balance by currency\n    :return: utility value\n    \"\"\"\n    money_utility = [\n        exchange_params_by_currency_id[currency_id] * balance\n        for currency_id, balance in balance_by_currency_id.items()\n    ]\n    return sum(money_utility)\n"
  },
  {
    "path": "aea/helpers/profiling.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Implementation of background profiling daemon.\"\"\"\n\nimport asyncio\nimport datetime\nimport gc\nimport logging\nimport platform\nimport textwrap\nimport threading\nimport time\nfrom collections import Counter\nfrom concurrent.futures._base import CancelledError\nfrom functools import wraps\nfrom typing import Any, Callable, Dict, List, Type\n\nfrom aea.helpers.async_utils import Runnable\n\n\nlock = threading.Lock()\n\n_default_logger = logging.getLogger(__file__)\n\nif platform.system() == \"Windows\":  # pragma: nocover\n    import win32process  # type: ignore  # pylint: disable=import-error\n\n    WIN32_PROCESS_TIMES_TICKS_PER_SECOND = 1e7\n\n    def get_current_process_memory_usage() -> float:\n        \"\"\"Get current process memory usage in MB.\"\"\"\n        d = win32process.GetProcessMemoryInfo(win32process.GetCurrentProcess())  # type: ignore\n        return 1.0 * d[\"WorkingSetSize\"] / 1024**2\n\n    def get_current_process_cpu_time() -> float:\n        \"\"\"Get current process cpu time in seconds.\"\"\"\n        d = win32process.GetProcessTimes(win32process.GetCurrentProcess())  # type: ignore\n        return d[\"UserTime\"] / WIN32_PROCESS_TIMES_TICKS_PER_SECOND\n\nelse:\n    import resource\n\n    _MAC_MEM_STATS_MB = 1024**2\n    _LINUX_MEM_STATS_MB = 1024\n\n    def get_current_process_memory_usage() -> float:\n        \"\"\"Get current process memory usage in MB.\"\"\"\n        if platform.system() == \"Darwin\":  # pragma: nocover\n            divider = _MAC_MEM_STATS_MB\n        else:\n            divider = _LINUX_MEM_STATS_MB\n\n        return 1.0 * resource.getrusage(resource.RUSAGE_SELF).ru_maxrss / divider\n\n    def get_current_process_cpu_time() -> float:\n        \"\"\"Get current process cpu time in seconds.\"\"\"\n        return resource.getrusage(resource.RUSAGE_SELF).ru_utime\n\n\nclass Profiling(Runnable):\n    \"\"\"Profiling service.\"\"\"\n\n    def __init__(\n        self,\n        period: int = 0,\n        objects_instances_to_count: List[Type] = None,\n        objects_created_to_count: List[Type] = None,\n        output_function: Callable[[str], None] = lambda x: print(x, flush=True),\n    ) -> None:\n        \"\"\"\n        Init profiler.\n\n        :param period: delay between profiling output in seconds.\n        :param objects_instances_to_count: object to count\n        :param objects_created_to_count: object created to count\n        :param output_function: function to display output, one str argument.\n        \"\"\"\n        if period < 1:  # pragma: nocover\n            raise ValueError(\"Period should be at least 1 second!\")\n        super().__init__(threaded=True)\n        self._period = period\n        self._start_ts = time.time()\n        self._objects_instances_to_count = objects_instances_to_count or []\n        self._objects_created_to_count = objects_created_to_count or []\n        self._output_function = output_function\n        self._counter: Dict[Type, int] = Counter()\n\n    def set_counters(self) -> None:\n        \"\"\"Modify obj.__new__ to count objects created created.\"\"\"\n        for obj in self._objects_created_to_count:\n            self._counter[obj] = 0\n\n            def make_fn(obj: Any) -> Callable:\n                orig_new = obj.__new__\n                # pylint: disable=protected-access  # type: ignore\n                obj_copy = obj\n\n                @wraps(orig_new)\n                def new(*args: Any, **kwargs: Any) -> Callable:\n                    self._counter[obj_copy] += 1\n                    if orig_new is object.__new__:\n                        return orig_new(args[0])  # pragma: nocover\n                    return orig_new(*args, **kwargs)  # pragma: nocover\n\n                return new\n\n            obj.__new__ = make_fn(obj)  # type: ignore\n\n    async def run(self) -> None:\n        \"\"\"Run profiling.\"\"\"\n        try:\n            self.set_counters()\n            while True:\n                await asyncio.sleep(self._period)\n                self.output_profile_data()\n        except CancelledError:  # pragma: nocover\n            pass\n        except Exception:  # pragma: nocover\n            _default_logger.exception(\"Exception in Profiling\")\n            raise\n\n    def output_profile_data(self) -> None:\n        \"\"\"Render profiling data and call output_function.\"\"\"\n        data = self.get_profile_data()\n        text = (\n            textwrap.dedent(\n                f\"\"\"\n        Profiling details for current AEA process: {datetime.datetime.now()}\n        =============================================\n        Run time: {data[\"run_time\"]:.6f} seconds\n        Cpu time: {data[\"cpu_time\"]:.6f} seconds,\n        Cpu/Run time: {100*data[\"cpu_time\"]/data[\"run_time\"]:.6f}%\n        Memory: {data[\"mem\"]:.6f} MB\n        Threads: {data[\"threads\"]['amount']}  {data[\"threads\"]['names']}\n        Objects present:\n        \"\"\"\n            )\n            + \"\\n\".join([f\" * {i}:  {c}\" for i, c in data[\"objects_present\"].items()])\n            + \"\\n\"\n            + \"\"\"Objects created:\\n\"\"\"\n            + \"\\n\".join(\n                [f\" * {i.__name__}:  {c}\" for i, c in data[\"objects_created\"].items()]\n            )\n            + \"\\n\"\n        )\n        self._output_function(text)\n\n    def get_profile_data(self) -> Dict:\n        \"\"\"Get profiling data dict.\"\"\"\n        return {\n            \"run_time\": time.time() - self._start_ts,\n            \"cpu_time\": get_current_process_cpu_time(),\n            \"mem\": get_current_process_memory_usage(),\n            \"threads\": {\n                \"amount\": threading.active_count(),\n                \"names\": [i.name for i in threading.enumerate()],\n            },\n            \"objects_present\": self.get_objects_instances(),\n            \"objects_created\": self.get_objecst_created(),\n        }\n\n    def get_objects_instances(self) -> Dict:\n        \"\"\"Return dict with counted object instances present now.\"\"\"\n        result: Dict = Counter()\n\n        with lock:\n            for obj_type in self._objects_instances_to_count:\n                result[obj_type.__name__] += 0\n\n            for obj in gc.get_objects():\n                for obj_type in self._objects_instances_to_count:\n                    if isinstance(obj, obj_type):\n                        result[obj_type.__name__] += 1\n        return result\n\n    def get_objecst_created(self) -> Dict:\n        \"\"\"Return dict with counted object instances created.\"\"\"\n        return self._counter\n"
  },
  {
    "path": "aea/helpers/search/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains search related classes.\"\"\"\n"
  },
  {
    "path": "aea/helpers/search/generic.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains a generic data model.\"\"\"\n\nfrom typing import Any, Dict, List\n\nfrom aea.exceptions import enforce\nfrom aea.helpers.search.models import Attribute, DataModel, Location\n\n\nSUPPORTED_TYPES = {\"str\": str, \"int\": int, \"float\": float, \"bool\": bool}\n\n\nclass GenericDataModel(DataModel):  # pylint: disable=too-few-public-methods\n    \"\"\"Generic data model.\"\"\"\n\n    def __init__(\n        self, data_model_name: str, data_model_attributes: Dict[str, Any]\n    ) -> None:\n        \"\"\"Initialise the dataModel.\"\"\"\n        attributes = []  # type: List[Attribute]\n        for values in data_model_attributes.values():\n            enforce(\n                values[\"type\"] in SUPPORTED_TYPES.keys(),\n                \"Type is not supported. Use str, int, float or bool\",\n            )\n            enforce(isinstance(values[\"name\"], str), \"Name must be a string!\")\n            enforce(\n                isinstance(values[\"is_required\"], bool),\n                \"Wrong type for is_required. Must be bool!\",\n            )\n            attributes.append(\n                Attribute(\n                    name=values[\"name\"],  # type: ignore\n                    type_=SUPPORTED_TYPES[values[\"type\"]],\n                    is_required=values[\"is_required\"],\n                )\n            )\n\n        super().__init__(data_model_name, attributes)\n\n\nAGENT_LOCATION_MODEL = DataModel(\n    \"location_agent\",\n    [Attribute(\"location\", Location, True, \"The location where the agent is.\")],\n    \"A data model to describe location of an agent.\",\n)\n\n\nAGENT_PERSONALITY_MODEL = DataModel(\n    \"personality_agent\",\n    [\n        Attribute(\"piece\", str, True, \"The personality piece key.\"),\n        Attribute(\"value\", str, True, \"The personality piece value.\"),\n    ],\n    \"A data model to describe the personality of an agent.\",\n)\n\n\nAGENT_SET_SERVICE_MODEL = DataModel(\n    \"set_service_key\",\n    [\n        Attribute(\"key\", str, True, \"Service key name.\"),\n        Attribute(\"value\", str, True, \"Service key value.\"),\n    ],\n    \"A data model to set service key.\",\n)\n\n\nSIMPLE_SERVICE_MODEL = DataModel(\n    \"simple_service\",\n    [Attribute(\"seller_service\", str, True, \"Service key name.\")],\n    \"A data model to represent a search for a service.\",\n)\n\n\nSIMPLE_DATA_MODEL = DataModel(\n    \"simple_data\",\n    [Attribute(\"dataset_id\", str, True, \"Data set key name.\")],\n    \"A data model to represent a search for a data set.\",\n)\n\n\nAGENT_REMOVE_SERVICE_MODEL = DataModel(\n    \"remove_service_key\",\n    [Attribute(\"key\", str, True, \"Service key name.\")],\n    \"A data model to remove service key.\",\n)\n"
  },
  {
    "path": "aea/helpers/search/models.proto",
    "content": "syntax = \"proto3\";\n\npackage aea.helpers.search.models;\n\nmessage Query {\n    message Attribute {\n        enum Type {\n            DOUBLE  = 0;\n            INT    = 1;\n            BOOL   = 2;\n            STRING = 3;\n            LOCATION = 4;\n        }\n        string name = 1;\n        Type type = 2;\n        bool required = 3;\n        string description = 4;\n    }\n    message DataModel {\n        string name = 1;\n        repeated Attribute attributes = 2;\n        string description = 3;\n    }\n    message Location {\n         double lon = 1;\n         double lat = 2;\n    }\n    message Value {\n        oneof value {\n            string string = 1;\n            double double = 2;\n            bool boolean = 3;\n            int64 integer = 4;\n            Location location = 5;\n        }\n    }\n    message KeyValue {\n        string key = 1;\n        Value value = 2;\n    }\n    message Instance {\n        DataModel model = 1;\n        repeated KeyValue values = 2;\n    }\n    message StringPair {\n        string first = 1;\n        string second = 2;\n    }\n    message IntPair {\n        int64 first = 1;\n        int64 second = 2;\n    }\n    message DoublePair {\n        double first = 1;\n        double second = 2;\n    }\n    message LocationPair {\n        Location first = 1;\n        Location second = 2;\n    }\n    message Range {\n        oneof pair {\n            StringPair string_pair = 1;\n            IntPair integer_pair = 2;\n            DoublePair double_pair = 3;\n            LocationPair location_pair = 4;\n        }\n    }\n    message Distance {\n        Location center = 1;\n        double distance = 2;\n    }\n    message Relation {\n        enum Operator {\n            EQ    = 0; // =\n            LT    = 1; // <\n            LTEQ  = 2; // <=\n            GT    = 3; // >\n            GTEQ  = 4; // >=\n            NOTEQ = 5; // !=, <>\n        }\n        Operator operator = 1;\n        Value value = 2;\n    }\n    message Set {\n        message Values {\n            message Ints {\n                repeated int64 values = 1;\n            }\n            message Doubles {\n                repeated double values = 1;\n            }\n            message Strings {\n                repeated string values = 1;\n            }\n            message Bools {\n                repeated bool values = 1;\n            }\n            message Locations {\n                repeated Location values = 1;\n            }\n            oneof values {\n                Strings string = 1;\n                Doubles double = 2;\n                Bools boolean = 3;\n                Ints integer = 4;\n                Locations location = 5;\n            }\n        }\n        enum Operator {\n            IN    = 0;\n            NOTIN = 1;\n        }\n        Operator operator = 1;\n        Values values = 2;\n    }\n    message ConstraintExpr {\n        message Or {\n            repeated ConstraintExpr expression = 1;\n        }\n        message And {\n            repeated ConstraintExpr expression = 1;\n        }\n        message Not {\n            ConstraintExpr expression = 1;\n        }\n        message Constraint {\n            string attribute_name = 1;\n            oneof constraint {\n                Set set_ = 2;\n                Range range_ = 3;\n                Relation relation = 4;\n                Distance distance = 5;\n            }\n        }\n        oneof expression {\n            Or or_ = 1;\n            And and_ = 2;\n            Not not_ = 3;\n            Constraint constraint = 4;\n        }\n    }\n    message Model {\n        repeated ConstraintExpr constraints = 1;\n        DataModel model = 2;\n    }\n}\n\n// option optimize_for = LITE_RUNTIME;\noption optimize_for = SPEED;"
  },
  {
    "path": "aea/helpers/search/models.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n# pylint: disable=no-member\n\"\"\"Useful classes for the OEF search.\"\"\"\n\nimport logging\nfrom abc import ABC, abstractmethod\nfrom copy import deepcopy\nfrom enum import Enum\nfrom math import asin, cos, radians, sin, sqrt\nfrom typing import (\n    Any,\n    Dict,\n    Iterator,\n    List,\n    Mapping,\n    Optional,\n    Tuple,\n    Type,\n    Union,\n    cast,\n)\n\nfrom aea.exceptions import enforce\nfrom aea.helpers.search import models_pb2\n\n\n_default_logger = logging.getLogger(__name__)\n\nproto_value = {\n    \"string\": \"string\",\n    \"double\": \"double\",\n    \"boolean\": \"boolean\",\n    \"integer\": \"integer\",\n    \"location\": \"location\",\n}\n\nproto_range_pairs = {\n    \"string\": \"string_pair\",\n    \"integer\": \"integer_pair\",\n    \"double\": \"double_pair\",\n    \"location\": \"location_pair\",\n}\n\nproto_set_values = {\n    \"string\": \"string\",\n    \"double\": \"double\",\n    \"boolean\": \"boolean\",\n    \"integer\": \"integer\",\n    \"location\": \"location\",\n}\n\nproto_constraint = {\n    \"set\": \"set_\",\n    \"range\": \"range_\",\n    \"relation\": \"relation\",\n    \"distance\": \"distance\",\n}\n\nproto_expression = {\n    \"or\": \"or_\",\n    \"and\": \"and_\",\n    \"not\": \"not_\",\n    \"constraint\": \"constraint\",\n}\n\nCONSTRAINT_CATEGORY_RELATION = \"relation\"\nCONSTRAINT_CATEGORY_RANGE = \"range\"\nCONSTRAINT_CATEGORY_SET = \"set\"\nCONSTRAINT_CATEGORY_DISTANCE = \"distance\"\n\nCONSTRAINT_CATEGORIES = [\n    CONSTRAINT_CATEGORY_RELATION,\n    CONSTRAINT_CATEGORY_RANGE,\n    CONSTRAINT_CATEGORY_SET,\n    CONSTRAINT_CATEGORY_DISTANCE,\n]\n\n\nclass Location:\n    \"\"\"Data structure to represent locations (i.e. a pair of latitude and longitude).\"\"\"\n\n    __slots__ = (\"latitude\", \"longitude\")\n\n    def __init__(self, latitude: float, longitude: float) -> None:\n        \"\"\"\n        Initialize a location.\n\n        :param latitude: the latitude of the location.\n        :param longitude: the longitude of the location.\n        \"\"\"\n        self.latitude = latitude\n        self.longitude = longitude\n\n    @property\n    def tuple(self) -> Tuple[float, float]:\n        \"\"\"Get the tuple representation of a location.\"\"\"\n        return self.latitude, self.longitude\n\n    def distance(self, other: \"Location\") -> float:\n        \"\"\"\n        Get the distance to another location.\n\n        :param other: the other location\n        :return: the distance\n        \"\"\"\n        return haversine(self.latitude, self.longitude, other.latitude, other.longitude)\n\n    def __eq__(self, other: Any) -> bool:\n        \"\"\"Compare equality of two locations.\"\"\"\n        if not isinstance(other, Location):\n            return False  # pragma: nocover\n        return self.latitude == other.latitude and self.longitude == other.longitude\n\n    def __str__(self) -> str:\n        \"\"\"Get the string representation of the data model.\"\"\"\n        return \"Location(latitude={},longitude={})\".format(\n            self.latitude, self.longitude\n        )\n\n    def encode(self) -> models_pb2.Query.Location:  # type: ignore\n        \"\"\"\n        Encode an instance of this class into a protocol buffer object.\n\n        :return: the matching protocol buffer object\n        \"\"\"\n        location_pb = models_pb2.Query.Location()  # type: ignore\n        location_pb.lat = self.latitude\n        location_pb.lon = self.longitude\n        return location_pb\n\n    @classmethod\n    def decode(cls, location_pb: Any) -> \"Location\":\n        \"\"\"\n        Decode a protocol buffer object that corresponds with this class into an instance of this class.\n\n        :param location_pb: the protocol buffer object corresponding with this class.\n        :return: A new instance of this class matching the protocol buffer object\n        \"\"\"\n        latitude = location_pb.lat\n        longitude = location_pb.lon\n        return cls(latitude, longitude)\n\n\n\"\"\"\nThe allowable types that an Attribute can have\n\"\"\"\nATTRIBUTE_TYPES = Union[float, str, bool, int, Location]\nALLOWED_ATTRIBUTE_TYPES = [float, str, bool, int, Location]\n\n\nclass AttributeInconsistencyException(Exception):\n    \"\"\"\n    Raised when the attributes in a Description are inconsistent.\n\n    Inconsistency is defined when values do not meet their respective schema, or if the values\n    are not of an allowed type.\n    \"\"\"\n\n\nclass Attribute:\n    \"\"\"Implements an attribute for an OEF data model.\"\"\"\n\n    _attribute_type_to_pb = {\n        bool: models_pb2.Query.Attribute.BOOL,  # type: ignore\n        int: models_pb2.Query.Attribute.INT,  # type: ignore\n        float: models_pb2.Query.Attribute.DOUBLE,  # type: ignore\n        str: models_pb2.Query.Attribute.STRING,  # type: ignore\n        Location: models_pb2.Query.Attribute.LOCATION,  # type: ignore\n    }\n\n    __slots__ = (\"name\", \"type\", \"is_required\", \"description\")\n\n    def __init__(\n        self,\n        name: str,\n        type_: Type[ATTRIBUTE_TYPES],\n        is_required: bool,\n        description: str = \"\",\n    ) -> None:\n        \"\"\"\n        Initialize an attribute.\n\n        :param name: the name of the attribute.\n        :param type_: the type of the attribute.\n        :param is_required: whether the attribute is required by the data model.\n        :param description: an (optional) human-readable description for the attribute.\n        \"\"\"\n        self.name = name\n        self.type = type_\n        self.is_required = is_required\n        self.description = description\n\n    def __eq__(self, other: Any) -> bool:\n        \"\"\"Compare with another object.\"\"\"\n        return (\n            isinstance(other, Attribute)\n            and self.name == other.name\n            and self.type == other.type\n            and self.is_required == other.is_required\n        )\n\n    def __str__(self) -> str:\n        \"\"\"Get the string representation of the data model.\"\"\"\n        return \"Attribute(name={},type={},is_required={})\".format(\n            self.name, self.type, self.is_required\n        )\n\n    def encode(self) -> models_pb2.Query.Attribute:  # type: ignore\n        \"\"\"\n        Encode an instance of this class into a protocol buffer object.\n\n        :return: the matching protocol buffer object\n        \"\"\"\n        attribute = models_pb2.Query.Attribute()  # type: ignore\n        attribute.name = self.name\n        attribute.type = self._attribute_type_to_pb[self.type]\n        attribute.required = self.is_required\n        if self.description is not None:\n            attribute.description = self.description\n        return attribute\n\n    @classmethod\n    def decode(cls, attribute_pb: models_pb2.Query.Attribute) -> \"Attribute\":  # type: ignore\n        \"\"\"\n        Decode a protocol buffer object that corresponds with this class into an instance of this class.\n\n        :param attribute_pb: the protocol buffer object corresponding with this class.\n        :return: A new instance of this class matching the protocol buffer object\n        \"\"\"\n        _pb_to_attribute_type = {v: k for k, v in cls._attribute_type_to_pb.items()}\n        return cls(\n            attribute_pb.name,\n            _pb_to_attribute_type[attribute_pb.type],\n            attribute_pb.required,\n            attribute_pb.description if attribute_pb.description else None,\n        )\n\n\nclass DataModel:\n    \"\"\"Implements an OEF data model.\"\"\"\n\n    __slots__ = (\"name\", \"attributes\", \"description\")\n\n    def __init__(\n        self, name: str, attributes: List[Attribute], description: str = \"\"\n    ) -> None:\n        \"\"\"\n        Initialize a data model.\n\n        :param name: the name of the data model.\n        :param attributes: the attributes of the data model.\n        :param description: the data model description.\n        \"\"\"\n        self.name: str = name\n        self.attributes = sorted(\n            attributes, key=lambda x: x.name\n        )  # type: List[Attribute]\n        self._check_validity()\n        self.description = description\n\n    @property\n    def attributes_by_name(self) -> Dict[str, Attribute]:\n        \"\"\"Get the attributes by name.\"\"\"\n        return {a.name: a for a in self.attributes}\n\n    def _check_validity(self) -> None:\n        # check if there are duplicated attribute names\n        attribute_names = [attribute.name for attribute in self.attributes]\n        if len(attribute_names) != len(set(attribute_names)):\n            raise ValueError(\n                \"Invalid input value for type '{}': duplicated attribute name.\".format(\n                    type(self).__name__\n                )\n            )\n\n    def __eq__(self, other: Any) -> bool:\n        \"\"\"Compare with another object.\"\"\"\n        return (\n            isinstance(other, DataModel)\n            and self.name == other.name\n            and self.attributes == other.attributes\n        )\n\n    def __str__(self) -> str:\n        \"\"\"Get the string representation of the data model.\"\"\"\n        return \"DataModel(name={},attributes={},description={})\".format(\n            self.name, {a.name: str(a) for a in self.attributes}, self.description\n        )\n\n    def encode(self) -> models_pb2.Query.DataModel:  # type: ignore\n        \"\"\"\n        Encode an instance of this class into a protocol buffer object.\n\n        :return: the matching protocol buffer object\n        \"\"\"\n        model = models_pb2.Query.DataModel()  # type: ignore\n        model.name = self.name\n        model.attributes.extend([attr.encode() for attr in self.attributes])\n        if self.description is not None:\n            model.description = self.description\n        return model\n\n    @classmethod\n    def decode(cls, data_model_pb: Any) -> \"DataModel\":\n        \"\"\"\n        Decode a protocol buffer object that corresponds with this class into an instance of this class.\n\n        :param data_model_pb: the protocol buffer object corresponding with this class.\n        :return: A new instance of this class matching the protocol buffer object\n        \"\"\"\n        name = data_model_pb.name\n        attributes = [Attribute.decode(attr_pb) for attr_pb in data_model_pb.attributes]\n        description = data_model_pb.description\n        return cls(name, attributes, description)\n\n\ndef generate_data_model(\n    model_name: str, attribute_values: Mapping[str, ATTRIBUTE_TYPES]\n) -> DataModel:\n    \"\"\"\n    Generate a data model that matches the values stored in this description.\n\n    That is, for each attribute (name, value), generate an Attribute.\n    It is assumed that each attribute is required.\n\n    :param model_name: the name of the model.\n    :param attribute_values: the values of each attribute\n    :return: the schema compliant with the values specified.\n    \"\"\"\n    return DataModel(\n        model_name,\n        [Attribute(key, type(value), True) for key, value in attribute_values.items()],\n    )\n\n\nclass Description:\n    \"\"\"Implements an OEF description.\"\"\"\n\n    __slots__ = (\"_values\", \"data_model\")\n\n    def __init__(\n        self,\n        values: Mapping[str, ATTRIBUTE_TYPES],\n        data_model: Optional[DataModel] = None,\n        data_model_name: str = \"\",\n    ) -> None:\n        \"\"\"\n        Initialize the description object.\n\n        :param values: the values in the description.\n        :param data_model: the data model (optional)\n        :param data_model_name: the data model name if a datamodel is created on the fly.\n        \"\"\"\n        _values = deepcopy(values)\n        self._values = _values\n        if data_model is not None:\n            self.data_model = data_model\n        else:\n            self.data_model = generate_data_model(data_model_name, values)\n        self._check_consistency()\n\n    @property\n    def values(self) -> Dict:\n        \"\"\"Get the values.\"\"\"\n        return cast(Dict, self._values)\n\n    def __eq__(self, other: Any) -> bool:\n        \"\"\"Compare with another object.\"\"\"\n        return (\n            isinstance(other, Description)\n            and self.values == other.values\n            and self.data_model == other.data_model\n        )\n\n    def __iter__(self) -> Iterator:\n        \"\"\"Create an iterator.\"\"\"\n        return iter(self.values)\n\n    def _check_consistency(self) -> None:\n        \"\"\"\n        Check the consistency of the values of this description.\n\n        If an attribute has been provided, values are checked against that. If no attribute\n        schema has been provided then minimal checking is performed based on the values in the\n        provided attribute_value dictionary.\n        :raises AttributeInconsistencyException: if values do not meet the schema, or if no schema is present\n                                               | if they have disallowed types.\n        \"\"\"\n        # check that all required attributes in the schema are contained in the description\n        required_attributes = [\n            attribute.name\n            for attribute in self.data_model.attributes\n            if attribute.is_required\n        ]\n        if not all(\n            attribute_name in self.values for attribute_name in required_attributes\n        ):\n            raise AttributeInconsistencyException(\"Missing required attribute.\")\n\n        # check that all values are defined in the data model\n        all_attributes = [attribute.name for attribute in self.data_model.attributes]\n        if not all(key in all_attributes for key in self.values.keys()):\n            raise AttributeInconsistencyException(\n                \"Have extra attribute not in data model.\"\n            )\n\n        # check that each of the provided values are consistent with that specified in the data model\n        for key, value in self.values.items():\n            attribute = next(\n                (\n                    attribute\n                    for attribute in self.data_model.attributes\n                    if attribute.name == key\n                ),\n                None,\n            )\n            if attribute is None:  # pragma: nocover\n                # looks like this check is redundant, cause checks done above for all attributes\n                raise ValueError(\"Attribute {} not found!\".format(key))\n            if not isinstance(value, attribute.type):\n                # values does not match type in data model\n                raise AttributeInconsistencyException(\n                    \"Attribute {} has incorrect type: {}\".format(\n                        attribute.name, attribute.type\n                    )\n                )\n            if not type(value) in ALLOWED_ATTRIBUTE_TYPES:\n                # value type matches data model, but it is not an allowed type\n                raise AttributeInconsistencyException(\n                    \"Attribute {} has unallowed type: {}. Allowed types: {}\".format(\n                        attribute.name,\n                        type(value),\n                        ALLOWED_ATTRIBUTE_TYPES,\n                    )\n                )\n\n    def __str__(self) -> str:\n        \"\"\"Get the string representation of the description.\"\"\"\n        return \"Description(values={},data_model={})\".format(\n            self._values, self.data_model\n        )\n\n    @staticmethod\n    def _to_key_value_pb(key: str, value: ATTRIBUTE_TYPES) -> models_pb2.Query.KeyValue:  # type: ignore\n        \"\"\"\n        From a (key, attribute value) pair to the associated Protobuf object.\n\n        :param key: the key of the attribute.\n        :param value: the value of the attribute.\n\n        :return: the associated Protobuf object.\n        \"\"\"\n\n        kv = models_pb2.Query.KeyValue()  # type: ignore\n        kv.key = key\n        if type(value) == bool:  # pylint: disable=unidiomatic-typecheck\n            kv.value.boolean = value\n        elif type(value) == int:  # pylint: disable=unidiomatic-typecheck\n            kv.value.integer = value\n        elif type(value) == float:  # pylint: disable=unidiomatic-typecheck\n            kv.value.double = value\n        elif type(value) == str:  # pylint: disable=unidiomatic-typecheck\n            kv.value.string = value\n        elif type(value) == Location:  # pylint: disable=unidiomatic-typecheck\n            kv.value.location.CopyFrom(value.encode())  # type: ignore\n\n        return kv\n\n    def _encode(self) -> models_pb2.Query.Instance:  # type: ignore\n        \"\"\"\n        Encode an instance of this class into a protocol buffer object.\n\n        :return: the matching protocol buffer object\n        \"\"\"\n        instance = models_pb2.Query.Instance()  # type: ignore\n        instance.model.CopyFrom(self.data_model.encode())\n        instance.values.extend(\n            [self._to_key_value_pb(key, value) for key, value in self.values.items()]\n        )\n        return instance\n\n    @classmethod\n    def encode(cls, description_pb: Any, description: \"Description\") -> None:\n        \"\"\"\n        Encode an instance of this class into the protocol buffer object.\n\n        The protocol buffer object in the description_protobuf_object argument must be matched\n        with the instance of this class in the 'description_object' argument.\n\n        :param description_pb: the protocol buffer object whose type corresponds with this class.\n        :param description: an instance of this class to be encoded in the protocol buffer object.\n        \"\"\"\n        description_bytes_pb = description._encode()  # pylint: disable=protected-access\n        description_bytes_bytes = description_bytes_pb.SerializeToString()\n        description_pb.description_bytes = description_bytes_bytes\n\n    @staticmethod\n    def _extract_value(value: models_pb2.Query.Value) -> ATTRIBUTE_TYPES:  # type: ignore\n        \"\"\"\n        From a Protobuf query value object to attribute type.\n\n        :param value: an instance of models_pb2.Query.Value.\n        :return: the associated attribute type.\n        \"\"\"\n        value_case = value.WhichOneof(\"value\")\n\n        if value_case == proto_value[\"string\"]:\n            result = value.string\n        elif value_case == proto_value[\"boolean\"]:\n            result = bool(value.boolean)\n        elif value_case == proto_value[\"integer\"]:\n            result = value.integer\n        elif value_case == proto_value[\"double\"]:\n            result = value.double\n        elif value_case == proto_value[\"location\"]:\n            result = Location.decode(value.location)\n        else:\n            raise ValueError(  # pragma: nocover\n                f\"Incorrect value. Expected either of {list(proto_value.values())}. Found {value_case}.\"\n            )\n\n        return result\n\n    @classmethod\n    def _decode(cls, description_pb: Any) -> \"Description\":\n        \"\"\"\n        Decode a protocol buffer object that corresponds with this class into an instance of this class.\n\n        :param description_pb: the protocol buffer object corresponding with this class.\n        :return: A new instance of this class matching the protocol buffer object\n        \"\"\"\n        model = DataModel.decode(description_pb.model)\n        values = {\n            attr.key: cls._extract_value(attr.value) for attr in description_pb.values\n        }\n        return cls(values, model)\n\n    @classmethod\n    def decode(cls, description_pb: Any) -> \"Description\":\n        \"\"\"\n        Decode a protocol buffer object that corresponds with this class into an instance of this class.\n\n        A new instance of this class must be created that matches the protocol\n        buffer object in the 'description_protobuf_object' argument.\n\n        :param description_pb: the protocol buffer object whose type corresponds with this class.\n        :return: A new instance of this class that matches the protocol buffer object in the 'description_protobuf_object' argument.\n        \"\"\"\n        description_bytes_pb = models_pb2.Query.Instance()  # type: ignore\n        description_bytes_pb.ParseFromString(description_pb.description_bytes)\n        description = cls._decode(description_bytes_pb)\n        return description\n\n\nclass ConstraintTypes(Enum):\n    \"\"\"Types of constraint.\"\"\"\n\n    EQUAL = \"==\"\n    NOT_EQUAL = \"!=\"\n    LESS_THAN = \"<\"\n    LESS_THAN_EQ = \"<=\"\n    GREATER_THAN = \">\"\n    GREATER_THAN_EQ = \">=\"\n    WITHIN = \"within\"\n    IN = \"in\"\n    NOT_IN = \"not_in\"\n    DISTANCE = \"distance\"\n\n    def __str__(self) -> str:  # pragma: nocover\n        \"\"\"Get the string representation.\"\"\"\n        return str(self.value)\n\n\nclass ConstraintType:\n    \"\"\"\n    Type of constraint.\n\n    Used with the Constraint class, this class allows to specify constraint over attributes.\n\n    Examples:\n        Equal to three\n        >>> equal_3 = ConstraintType(ConstraintTypes.EQUAL, 3)\n\n    You can also specify a type of constraint by using its string representation, e.g.:\n        >>> equal_3 = ConstraintType(\"==\", 3)\n        >>> not_equal_london = ConstraintType(\"!=\", \"London\")\n        >>> less_than_pi = ConstraintType(\"<\", 3.14)\n        >>> within_range = ConstraintType(\"within\", (-10.0, 10.0))\n        >>> in_a_set = ConstraintType(\"in\", (1, 2, 3))\n        >>> not_in_a_set = ConstraintType(\"not_in\", (\"C\", \"Java\", \"Python\"))\n\n    \"\"\"\n\n    __slots__ = (\"type\", \"value\")\n\n    def __init__(self, type_: Union[ConstraintTypes, str], value: Any) -> None:\n        \"\"\"\n        Initialize a constraint type.\n\n        :param type_: the type of the constraint.\n                   | Either an instance of the ConstraintTypes enum,\n                   | or a string representation associated with the type.\n        :param value: the value that defines the constraint.\n        :raises AEAEnforceError: if the type of the constraint is not  # noqa: DAR402\n        \"\"\"\n        self.type = ConstraintTypes(type_)\n        self.value = value\n        enforce(self.check_validity(), \"ConstraintType initialization inconsistent.\")\n\n    def check_validity(self) -> bool:\n        \"\"\"\n        Check the validity of the input provided.\n\n        :return: boolean to indicate validity\n        :raises AEAEnforceError: if the value is not valid wrt the constraint type.  # noqa: DAR402\n        \"\"\"\n        try:\n            if self.type == ConstraintTypes.EQUAL:\n                enforce(\n                    isinstance(self.value, (int, float, str, bool)),\n                    f\"Expected one of type in (int, float, str, bool), got {self.value}\",\n                )\n            elif self.type == ConstraintTypes.NOT_EQUAL:\n                enforce(\n                    isinstance(self.value, (int, float, str, bool)),\n                    f\"Expected one of type in (int, float, str, bool), got {self.value}\",\n                )\n            elif self.type == ConstraintTypes.LESS_THAN:\n                enforce(\n                    isinstance(self.value, (int, float, str)),\n                    f\"Expected one of type in (int, float, str), got {self.value}\",\n                )\n            elif self.type == ConstraintTypes.LESS_THAN_EQ:\n                enforce(\n                    isinstance(self.value, (int, float, str)),\n                    f\"Expected one of type in (int, float, str), got {self.value}\",\n                )\n            elif self.type == ConstraintTypes.GREATER_THAN:\n                enforce(\n                    isinstance(self.value, (int, float, str)),\n                    f\"Expected one of type in (int, float, str), got {self.value}\",\n                )\n            elif self.type == ConstraintTypes.GREATER_THAN_EQ:\n                enforce(\n                    isinstance(self.value, (int, float, str)),\n                    f\"Expected one of type in (int, float, str), got {self.value}\",\n                )\n            elif self.type == ConstraintTypes.WITHIN:\n                allowed_sub_types = (int, float, str)\n                enforce(\n                    isinstance(self.value, tuple),\n                    f\"Expected tuple, got {type(self.value)}\",\n                )\n                enforce(\n                    len(self.value) == 2, f\"Expected length=2, got {len(self.value)}\"\n                )\n                enforce(\n                    isinstance(self.value[0], type(self.value[1])), \"Invalid types.\"\n                )\n                enforce(\n                    isinstance(self.value[1], type(self.value[0])), \"Invalid types.\"\n                )\n                enforce(\n                    isinstance(self.value[0], allowed_sub_types),\n                    f\"Invalid type for first element. Expected either of {allowed_sub_types}. Found {type(self.value[0])}.\",\n                )\n                enforce(\n                    isinstance(self.value[1], allowed_sub_types),\n                    f\"Invalid type for second element. Expected either of {allowed_sub_types}. Found {type(self.value[1])}.\",\n                )\n            elif self.type == ConstraintTypes.IN:\n                enforce(\n                    isinstance(self.value, tuple),\n                    f\"Expected tuple, got {type(self.value)}\",\n                )\n                if len(self.value) > 0:\n                    _type = type(next(iter(self.value)))\n                    enforce(\n                        all(isinstance(obj, _type) for obj in self.value),\n                        \"Invalid types.\",\n                    )\n            elif self.type == ConstraintTypes.NOT_IN:\n                enforce(\n                    isinstance(self.value, tuple),\n                    f\"Expected tuple, got {type(self.value)}\",\n                )\n                if len(self.value) > 0:\n                    _type = type(next(iter(self.value)))\n                    enforce(\n                        all(isinstance(obj, _type) for obj in self.value),\n                        \"Invalid types.\",\n                    )\n            elif self.type == ConstraintTypes.DISTANCE:\n                enforce(\n                    isinstance(self.value, tuple),\n                    f\"Expected tuple, got {type(self.value)}\",\n                )\n                enforce(\n                    len(self.value) == 2, f\"Expected length=2, got {len(self.value)}\"\n                )\n                enforce(\n                    isinstance(self.value[0], Location),\n                    \"Invalid type, expected Location.\",\n                )\n                enforce(\n                    isinstance(self.value[1], float), \"Invalid type, expected Location.\"\n                )\n            else:  # pragma: nocover\n                raise ValueError(\"Type not recognized.\")\n        except ValueError:\n            return False  # pragma: nocover\n\n        return True\n\n    def is_valid(self, attribute: Attribute) -> bool:\n        \"\"\"\n        Check if the constraint type is valid wrt a given attribute.\n\n        A constraint type is valid wrt an attribute if the\n        type of its operand(s) is the same of the attribute type.\n\n        >>> attribute = Attribute(\"year\", int, True)\n        >>> valid_constraint_type = ConstraintType(ConstraintTypes.GREATER_THAN, 2000)\n        >>> valid_constraint_type.is_valid(attribute)\n        True\n\n        >>> valid_constraint_type = ConstraintType(ConstraintTypes.WITHIN, (2000, 2001))\n        >>> valid_constraint_type.is_valid(attribute)\n        True\n\n        The following constraint is invalid: the year is in a string variable,\n        whereas the attribute is defined over integers.\n\n        >>> invalid_constraint_type = ConstraintType(ConstraintTypes.GREATER_THAN, \"2000\")\n        >>> invalid_constraint_type.is_valid(attribute)\n        False\n\n        :param attribute: the data model used to check the validity of the constraint type.\n        :return: ``True`` if the constraint type is valid wrt the attribute, ``False`` otherwise.\n        \"\"\"\n        return self.get_data_type() == attribute.type\n\n    def get_data_type(self) -> Type[ATTRIBUTE_TYPES]:\n        \"\"\"\n        Get the type of the data used to define the constraint type.\n\n        For instance:\n        >>> c = ConstraintType(ConstraintTypes.EQUAL, 1)\n        >>> c.get_data_type()\n        <class 'int'>\n\n        :return: data type\n        \"\"\"\n        if isinstance(self.value, (list, tuple, set)):\n            value = next(iter(self.value))\n        else:\n            value = self.value\n        value = cast(ATTRIBUTE_TYPES, value)\n        return type(value)\n\n    def check(self, value: ATTRIBUTE_TYPES) -> bool:\n        \"\"\"\n        Check if an attribute value satisfies the constraint.\n\n        The implementation depends on the constraint type.\n\n        :param value: the value to check.\n        :return: True if the value satisfy the constraint, False otherwise.\n        :raises ValueError: if the constraint type is not recognized.\n        \"\"\"\n        if self.type == ConstraintTypes.EQUAL:\n            return value == self.value\n        if self.type == ConstraintTypes.NOT_EQUAL:\n            return value != self.value\n        if self.type == ConstraintTypes.LESS_THAN:\n            return value < self.value\n        if self.type == ConstraintTypes.LESS_THAN_EQ:\n            return value <= self.value\n        if self.type == ConstraintTypes.GREATER_THAN:\n            return value > self.value\n        if self.type == ConstraintTypes.GREATER_THAN_EQ:\n            return value >= self.value\n        if self.type == ConstraintTypes.WITHIN:\n            low = self.value[0]\n            high = self.value[1]\n            return low <= value <= high\n        if self.type == ConstraintTypes.IN:\n            return value in self.value\n        if self.type == ConstraintTypes.NOT_IN:\n            return value not in self.value\n        if self.type == ConstraintTypes.DISTANCE:\n            if not isinstance(value, Location):  # pragma: nocover\n                raise ValueError(\"Value must be of type Location.\")\n            location = cast(Location, self.value[0])\n            distance = self.value[1]\n            return location.distance(value) <= distance\n        raise ValueError(\"Constraint type not recognized.\")  # pragma: nocover\n\n    def __eq__(self, other: Any) -> bool:\n        \"\"\"Check equality with another object.\"\"\"\n        return (\n            isinstance(other, ConstraintType)\n            and self.value == other.value\n            and self.type == other.type\n        )\n\n    def __str__(self) -> str:\n        \"\"\"Get the string representation of the constraint type.\"\"\"\n        return \"ConstraintType(value={},type={})\".format(self.value, self.type)\n\n    def encode(self) -> Optional[Any]:\n        \"\"\"\n        Encode an instance of this class into a protocol buffer object.\n\n        :return: the matching protocol buffer object\n        \"\"\"\n        encoding: Optional[Any] = None\n\n        if self.type in (\n            ConstraintTypes.EQUAL,\n            ConstraintTypes.NOT_EQUAL,\n            ConstraintTypes.LESS_THAN,\n            ConstraintTypes.LESS_THAN_EQ,\n            ConstraintTypes.GREATER_THAN,\n            ConstraintTypes.GREATER_THAN_EQ,\n        ):\n            relation = models_pb2.Query.Relation()  # type: ignore\n\n            if self.type == ConstraintTypes.EQUAL:\n                relation.operator = models_pb2.Query.Relation.EQ  # type: ignore\n            elif self.type == ConstraintTypes.NOT_EQUAL:\n                relation.operator = models_pb2.Query.Relation.NOTEQ  # type: ignore\n            elif self.type == ConstraintTypes.LESS_THAN:\n                relation.operator = models_pb2.Query.Relation.LT  # type: ignore\n            elif self.type == ConstraintTypes.LESS_THAN_EQ:\n                relation.operator = models_pb2.Query.Relation.LTEQ  # type: ignore\n            elif self.type == ConstraintTypes.GREATER_THAN:\n                relation.operator = models_pb2.Query.Relation.GT  # type: ignore\n            elif self.type == ConstraintTypes.GREATER_THAN_EQ:\n                relation.operator = models_pb2.Query.Relation.GTEQ  # type: ignore\n\n            query_value = models_pb2.Query.Value()  # type: ignore\n\n            if isinstance(self.value, bool):\n                query_value.boolean = self.value\n            elif isinstance(self.value, int):\n                query_value.integer = self.value\n            elif isinstance(self.value, float):\n                query_value.double = self.value\n            elif isinstance(self.value, str):\n                query_value.string = self.value\n            relation.value.CopyFrom(query_value)\n\n            encoding = relation\n\n        elif self.type == ConstraintTypes.WITHIN:\n            range_ = models_pb2.Query.Range()  # type: ignore\n\n            if type(self.value[0]) == str:  # pylint: disable=unidiomatic-typecheck\n                values = models_pb2.Query.StringPair()  # type: ignore\n                values.first = self.value[0]\n                values.second = self.value[1]\n                range_.string_pair.CopyFrom(values)\n            elif type(self.value[0]) == int:  # pylint: disable=unidiomatic-typecheck\n                values = models_pb2.Query.IntPair()  # type: ignore\n                values.first = self.value[0]\n                values.second = self.value[1]\n                range_.integer_pair.CopyFrom(values)\n            elif type(self.value[0]) == float:  # pylint: disable=unidiomatic-typecheck\n                values = models_pb2.Query.DoublePair()  # type: ignore\n                values.first = self.value[0]\n                values.second = self.value[1]\n                range_.double_pair.CopyFrom(values)\n            encoding = range_\n\n        elif self.type in (ConstraintTypes.IN, ConstraintTypes.NOT_IN):\n            set_ = models_pb2.Query.Set()  # type: ignore\n\n            if self.type == ConstraintTypes.IN:\n                set_.operator = models_pb2.Query.Set.IN  # type: ignore\n            elif self.type == ConstraintTypes.NOT_IN:\n                set_.operator = models_pb2.Query.Set.NOTIN  # type: ignore\n\n            value_type = type(self.value[0]) if len(self.value) > 0 else str\n\n            if value_type == str:\n                values = models_pb2.Query.Set.Values.Strings()  # type: ignore\n                values.values.extend(self.value)\n                set_.values.string.CopyFrom(values)\n            elif value_type == bool:\n                values = models_pb2.Query.Set.Values.Bools()  # type: ignore\n                values.values.extend(self.value)\n                set_.values.boolean.CopyFrom(values)\n            elif value_type == int:\n                values = models_pb2.Query.Set.Values.Ints()  # type: ignore\n                values.values.extend(self.value)\n                set_.values.integer.CopyFrom(values)\n            elif value_type == float:\n                values = models_pb2.Query.Set.Values.Doubles()  # type: ignore\n                values.values.extend(self.value)\n                set_.values.double.CopyFrom(values)\n            elif value_type == Location:\n                values = models_pb2.Query.Set.Values.Locations()  # type: ignore\n                values.values.extend([value.encode() for value in self.value])\n                set_.values.location.CopyFrom(values)\n\n            encoding = set_\n\n        elif self.type == ConstraintTypes.DISTANCE:\n            distance_pb = models_pb2.Query.Distance()  # type: ignore\n            distance_pb.distance = self.value[1]\n            distance_pb.center.CopyFrom(self.value[0].encode())\n\n            encoding = distance_pb\n\n        return encoding\n\n    @classmethod\n    def decode(cls, constraint_type_pb: Any, category: str) -> \"ConstraintType\":\n        \"\"\"\n        Decode a protocol buffer object that corresponds with this class into an instance of this class.\n\n        :param constraint_type_pb: the protocol buffer object corresponding with this class.\n        :param category: the category of the constraint ('relation', 'set', 'range', 'distance).\n\n        :return: A new instance of this class matching the protocol buffer object\n        \"\"\"\n        decoding: ConstraintType\n\n        relation_type_from_pb = {\n            models_pb2.Query.Relation.Operator.GTEQ: ConstraintTypes.GREATER_THAN_EQ,  # type: ignore\n            models_pb2.Query.Relation.Operator.GT: ConstraintTypes.GREATER_THAN,  # type: ignore\n            models_pb2.Query.Relation.Operator.LTEQ: ConstraintTypes.LESS_THAN_EQ,  # type: ignore\n            models_pb2.Query.Relation.Operator.LT: ConstraintTypes.LESS_THAN,  # type: ignore\n            models_pb2.Query.Relation.Operator.NOTEQ: ConstraintTypes.NOT_EQUAL,  # type: ignore\n            models_pb2.Query.Relation.Operator.EQ: ConstraintTypes.EQUAL,  # type: ignore\n        }\n        set_type_from_pb = {\n            models_pb2.Query.Set.Operator.IN: ConstraintTypes.IN,  # type: ignore\n            models_pb2.Query.Set.Operator.NOTIN: ConstraintTypes.NOT_IN,  # type: ignore\n        }\n\n        if category == CONSTRAINT_CATEGORY_RELATION:\n            relation_enum = relation_type_from_pb[constraint_type_pb.operator]\n            value_case = constraint_type_pb.value.WhichOneof(\"value\")\n            if value_case == proto_value[\"string\"]:\n                decoding = ConstraintType(\n                    relation_enum, constraint_type_pb.value.string\n                )\n            elif value_case == proto_value[\"boolean\"]:\n                decoding = ConstraintType(\n                    relation_enum, constraint_type_pb.value.boolean\n                )\n            elif value_case == proto_value[\"integer\"]:\n                decoding = ConstraintType(\n                    relation_enum, constraint_type_pb.value.integer\n                )\n            elif value_case == proto_value[\"double\"]:\n                decoding = ConstraintType(\n                    relation_enum, constraint_type_pb.value.double\n                )\n        elif category == CONSTRAINT_CATEGORY_RANGE:\n            range_enum = ConstraintTypes.WITHIN\n            range_case = constraint_type_pb.WhichOneof(\"pair\")\n            if range_case == proto_range_pairs[\"string\"]:\n                decoding = ConstraintType(\n                    range_enum,\n                    (\n                        constraint_type_pb.string_pair.first,\n                        constraint_type_pb.string_pair.second,\n                    ),\n                )\n            elif range_case == proto_range_pairs[\"integer\"]:\n                decoding = ConstraintType(\n                    range_enum,\n                    (\n                        constraint_type_pb.integer_pair.first,\n                        constraint_type_pb.integer_pair.second,\n                    ),\n                )\n            elif range_case == proto_range_pairs[\"double\"]:\n                decoding = ConstraintType(\n                    range_enum,\n                    (\n                        constraint_type_pb.double_pair.first,\n                        constraint_type_pb.double_pair.second,\n                    ),\n                )\n        elif category == CONSTRAINT_CATEGORY_SET:\n            set_enum = set_type_from_pb[constraint_type_pb.operator]\n            value_case = constraint_type_pb.values.WhichOneof(\"values\")\n            if value_case == proto_set_values[\"string\"]:\n                decoding = ConstraintType(\n                    set_enum,\n                    tuple(constraint_type_pb.values.string.values),\n                )\n            elif value_case == proto_set_values[\"boolean\"]:\n                decoding = ConstraintType(\n                    set_enum,\n                    tuple(constraint_type_pb.values.boolean.values),\n                )\n            elif value_case == proto_set_values[\"integer\"]:\n                decoding = ConstraintType(\n                    set_enum,\n                    tuple(constraint_type_pb.values.integer.values),\n                )\n            elif value_case == proto_set_values[\"double\"]:\n                decoding = ConstraintType(\n                    set_enum,\n                    tuple(constraint_type_pb.values.double.values),\n                )\n            elif value_case == proto_set_values[\"location\"]:\n                locations = [\n                    Location.decode(loc)\n                    for loc in constraint_type_pb.values.location.values\n                ]\n                location_tuple = tuple(locations)\n                decoding = ConstraintType(set_enum, location_tuple)\n        elif category == CONSTRAINT_CATEGORY_DISTANCE:\n            distance_enum = ConstraintTypes.DISTANCE\n            center = Location.decode(constraint_type_pb.center)\n            distance = constraint_type_pb.distance\n            decoding = ConstraintType(distance_enum, (center, distance))\n        else:\n            raise ValueError(\n                f\"Incorrect category. Expected either of {CONSTRAINT_CATEGORIES}. Found {category}.\"\n            )\n        return decoding\n\n\nclass ConstraintExpr(ABC):\n    \"\"\"Implementation of the constraint language to query the OEF node.\"\"\"\n\n    @abstractmethod\n    def check(self, description: Description) -> bool:\n        \"\"\"\n        Check if a description satisfies the constraint expression.\n\n        :param description: the description to check.\n        :return: True if the description satisfy the constraint expression, False otherwise.\n        \"\"\"\n\n    @abstractmethod\n    def is_valid(self, data_model: DataModel) -> bool:\n        \"\"\"\n        Check whether a constraint expression is valid wrt a data model.\n\n         Specifically, check the following conditions:\n        - If all the attributes referenced by the constraints are correctly associated with the Data Model attributes.\n\n        :param data_model: the data model used to check the validity of the constraint expression.\n        :return: ``True`` if the constraint expression is valid wrt the data model, ``False`` otherwise.\n        \"\"\"\n\n    def check_validity(  # noqa: B027\n        self,\n    ) -> None:  # pragma: nocover\n        \"\"\"\n        Check whether a Constraint Expression satisfies some basic requirements.\n\n        :raises AEAEnforceError: if the object does not satisfy some requirements.  # noqa: DAR402\n        \"\"\"\n\n    @staticmethod\n    def _encode(expression: Any) -> models_pb2.Query.ConstraintExpr:  # type: ignore\n        \"\"\"\n        Encode an instance of this class into a protocol buffer object.\n\n        :param expression: an expression\n        :return: the matching protocol buffer object\n        \"\"\"\n        constraint_expression_pb = models_pb2.Query.ConstraintExpr()  # type: ignore\n        expression_pb = expression.encode()\n        if isinstance(expression, And):\n            constraint_expression_pb.and_.CopyFrom(expression_pb)\n        elif isinstance(expression, Or):\n            constraint_expression_pb.or_.CopyFrom(expression_pb)\n        elif isinstance(expression, Not):\n            constraint_expression_pb.not_.CopyFrom(expression_pb)\n        elif isinstance(expression, Constraint):\n            constraint_expression_pb.constraint.CopyFrom(expression_pb)\n        else:\n            raise ValueError(\n                f\"Invalid expression type. Expected either of 'And', 'Or', 'Not', 'Constraint'. Found {type(expression)}.\"\n            )\n\n        return constraint_expression_pb\n\n    @staticmethod\n    def _decode(constraint_expression_pb: Any) -> \"ConstraintExpr\":\n        \"\"\"\n        Decode a protocol buffer object that corresponds with this class into an instance of this class.\n\n        :param constraint_expression_pb: the protocol buffer object corresponding with this class.\n        :return: A new instance of this class matching the protocol buffer object\n        \"\"\"\n        expression = constraint_expression_pb.WhichOneof(\"expression\")\n\n        result: Optional[Union[And, Or, Not, Constraint]] = None\n\n        if expression == proto_expression[\"and\"]:\n            result = And.decode(constraint_expression_pb.and_)\n        elif expression == proto_expression[\"or\"]:\n            result = Or.decode(constraint_expression_pb.or_)\n        elif expression == proto_expression[\"not\"]:\n            result = Not.decode(constraint_expression_pb.not_)\n        elif expression == proto_expression[\"constraint\"]:\n            result = Constraint.decode(constraint_expression_pb.constraint)\n        else:  # pragma: nocover\n            raise ValueError(\n                f\"Incorrect argument. Expected either of {list(proto_expression.keys())}. Found {expression}.\"\n            )\n\n        return result\n\n\nclass And(ConstraintExpr):\n    \"\"\"Implementation of the 'And' constraint expression.\"\"\"\n\n    __slots__ = (\"constraints\",)\n\n    def __init__(self, constraints: List[ConstraintExpr]) -> None:\n        \"\"\"\n        Initialize an 'And' expression.\n\n        :param constraints: the list of constraints expression (in conjunction).\n        \"\"\"\n        self.constraints = constraints\n        self.check_validity()\n\n    def check(self, description: Description) -> bool:\n        \"\"\"\n        Check if a value satisfies the 'And' constraint expression.\n\n        :param description: the description to check.\n        :return: True if the description satisfy the constraint expression, False otherwise.\n        \"\"\"\n        return all(expression.check(description) for expression in self.constraints)\n\n    def is_valid(self, data_model: DataModel) -> bool:\n        \"\"\"\n        Check whether the constraint expression is valid wrt a data model.\n\n        :param data_model: the data model used to check the validity of the constraint expression.\n        :return: ``True`` if the constraint expression is valid wrt the data model, ``False`` otherwise.\n        \"\"\"\n        return all(constraint.is_valid(data_model) for constraint in self.constraints)\n\n    def check_validity(self) -> None:\n        \"\"\"\n        Check whether the Constraint Expression satisfies some basic requirements.\n\n        :return ``None``\n        :raises ValueError: if the object does not satisfy some requirements.\n        \"\"\"\n        if len(self.constraints) < 2:  # pragma: nocover\n            raise ValueError(\n                \"Invalid input value for type '{}': number of \"\n                \"subexpression must be at least 2.\".format(type(self).__name__)\n            )\n        for constraint in self.constraints:\n            constraint.check_validity()\n\n    def __eq__(self, other: Any) -> bool:  # pragma: nocover\n        \"\"\"Compare with another object.\"\"\"\n        return isinstance(other, And) and self.constraints == other.constraints\n\n    def encode(self) -> models_pb2.Query.ConstraintExpr.And:  # type: ignore\n        \"\"\"\n        Encode an instance of this class into a protocol buffer object.\n\n        :return: the matching protocol buffer object\n        \"\"\"\n        and_pb = models_pb2.Query.ConstraintExpr.And()  # type: ignore\n        constraint_expression_pbs = [\n            ConstraintExpr._encode(constraint) for constraint in self.constraints\n        ]\n        and_pb.expression.extend(constraint_expression_pbs)\n        return and_pb\n\n    @classmethod\n    def decode(cls, and_pb: Any) -> \"And\":\n        \"\"\"\n        Decode a protocol buffer object that corresponds with this class into an instance of this class.\n\n        :param and_pb: the protocol buffer object corresponding with this class.\n        :return: A new instance of this class matching the protocol buffer object\n        \"\"\"\n        expression = [cls._decode(c) for c in and_pb.expression]\n        return cls(expression)\n\n\nclass Or(ConstraintExpr):\n    \"\"\"Implementation of the 'Or' constraint expression.\"\"\"\n\n    __slots__ = (\"constraints\",)\n\n    def __init__(self, constraints: List[ConstraintExpr]) -> None:\n        \"\"\"\n        Initialize an 'Or' expression.\n\n        :param constraints: the list of constraints expressions (in disjunction).\n        \"\"\"\n        self.constraints = constraints\n        self.check_validity()\n\n    def check(self, description: Description) -> bool:\n        \"\"\"\n        Check if a value satisfies the 'Or' constraint expression.\n\n        :param description: the description to check.\n        :return: True if the description satisfy the constraint expression, False otherwise.\n        \"\"\"\n        return any(expression.check(description) for expression in self.constraints)\n\n    def is_valid(self, data_model: DataModel) -> bool:\n        \"\"\"\n        Check whether the constraint expression is valid wrt a data model.\n\n        :param data_model: the data model used to check the validity of the constraint expression.\n        :return: ``True`` if the constraint expression is valid wrt the data model, ``False`` otherwise.\n        \"\"\"\n        return all(constraint.is_valid(data_model) for constraint in self.constraints)\n\n    def check_validity(self) -> None:\n        \"\"\"\n        Check whether the Constraint Expression satisfies some basic requirements.\n\n        :return ``None``\n        :raises ValueError: if the object does not satisfy some requirements.\n        \"\"\"\n        if len(self.constraints) < 2:  # pragma: nocover\n            raise ValueError(\n                \"Invalid input value for type '{}': number of \"\n                \"subexpression must be at least 2.\".format(type(self).__name__)\n            )\n        for constraint in self.constraints:\n            constraint.check_validity()\n\n    def __eq__(self, other: Any) -> bool:  # pragma: nocover\n        \"\"\"Compare with another object.\"\"\"\n        return isinstance(other, Or) and self.constraints == other.constraints\n\n    def encode(self) -> models_pb2.Query.ConstraintExpr.Or:  # type: ignore\n        \"\"\"\n        Encode an instance of this class into a protocol buffer object.\n\n        :return: the matching protocol buffer object\n        \"\"\"\n        or_pb = models_pb2.Query.ConstraintExpr.Or()  # type: ignore\n        constraint_expression_pbs = [\n            ConstraintExpr._encode(constraint) for constraint in self.constraints\n        ]\n        or_pb.expression.extend(constraint_expression_pbs)\n        return or_pb\n\n    @classmethod\n    def decode(cls, or_pb: Any) -> \"Or\":\n        \"\"\"\n        Decode a protocol buffer object that corresponds with this class into an instance of this class.\n\n        :param or_pb: the protocol buffer object corresponding with this class.\n        :return: A new instance of this class matching the protocol buffer object\n        \"\"\"\n        expression = [ConstraintExpr._decode(c) for c in or_pb.expression]\n        return cls(expression)\n\n\nclass Not(ConstraintExpr):\n    \"\"\"Implementation of the 'Not' constraint expression.\"\"\"\n\n    __slots__ = (\"constraint\",)\n\n    def __init__(self, constraint: ConstraintExpr) -> None:\n        \"\"\"\n        Initialize a 'Not' expression.\n\n        :param constraint: the constraint expression to negate.\n        \"\"\"\n        self.constraint = constraint\n\n    def check(self, description: Description) -> bool:\n        \"\"\"\n        Check if a value satisfies the 'Not' constraint expression.\n\n        :param description: the description to check.\n        :return: True if the description satisfy the constraint expression, False otherwise.\n        \"\"\"\n        return not self.constraint.check(description)\n\n    def is_valid(self, data_model: DataModel) -> bool:\n        \"\"\"\n        Check whether the constraint expression is valid wrt a data model.\n\n        :param data_model: the data model used to check the validity of the constraint expression.\n        :return: ``True`` if the constraint expression is valid wrt the data model, ``False`` otherwise.\n        \"\"\"\n        return self.constraint.is_valid(data_model)\n\n    def __eq__(self, other: Any) -> bool:  # pragma: nocover\n        \"\"\"Compare with another object.\"\"\"\n        return isinstance(other, Not) and self.constraint == other.constraint\n\n    def encode(self) -> models_pb2.Query.ConstraintExpr.Not:  # type: ignore\n        \"\"\"\n        Encode an instance of this class into a protocol buffer object.\n\n        :return: the matching protocol buffer object\n        \"\"\"\n        not_pb = models_pb2.Query.ConstraintExpr.Not()  # type: ignore\n        constraint_expression_pb = ConstraintExpr._encode(self.constraint)\n        not_pb.expression.CopyFrom(constraint_expression_pb)\n        return not_pb\n\n    @classmethod\n    def decode(cls, not_pb: Any) -> \"Not\":\n        \"\"\"\n        Decode a protocol buffer object that corresponds with this class into an instance of this class.\n\n        :param not_pb: the protocol buffer object corresponding with this class.\n        :return: A new instance of this class matching the protocol buffer object\n        \"\"\"\n        expression = ConstraintExpr._decode(not_pb.expression)\n        return cls(expression)\n\n\nclass Constraint(ConstraintExpr):\n    \"\"\"The atomic component of a constraint expression.\"\"\"\n\n    __slots__ = (\"attribute_name\", \"constraint_type\")\n\n    def __init__(self, attribute_name: str, constraint_type: ConstraintType) -> None:\n        \"\"\"\n        Initialize a constraint.\n\n        :param attribute_name: the name of the attribute to be constrained.\n        :param constraint_type: the constraint type.\n        \"\"\"\n        self.attribute_name = attribute_name\n        self.constraint_type = constraint_type\n\n    def check(self, description: Description) -> bool:\n        \"\"\"\n        Check if a description satisfies the constraint. The implementation depends on the type of the constraint.\n\n        :param description: the description to check.\n        :return: True if the description satisfies the constraint, False otherwise.\n\n        Examples:\n            >>> attr_author = Attribute(\"author\" , str, True, \"The author of the book.\")\n            >>> attr_year   = Attribute(\"year\",    int, True, \"The year of publication of the book.\")\n            >>> attr_genre   = Attribute(\"genre\",  str, True, \"The genre of the book.\")\n            >>> c1 = Constraint(\"author\", ConstraintType(\"==\", \"Stephen King\"))\n            >>> c2 = Constraint(\"year\", ConstraintType(\">\", 1990))\n            >>> c3 = Constraint(\"genre\", ConstraintType(\"in\", (\"horror\", \"science_fiction\")))\n            >>> book_1 = Description({\"author\": \"Stephen King\",  \"year\": 1991, \"genre\": \"horror\"})\n            >>> book_2 = Description({\"author\": \"George Orwell\", \"year\": 1948, \"genre\": \"horror\"})\n\n            The \"author\" attribute instantiation satisfies the constraint, so the result is True.\n\n            >>> c1.check(book_1)\n            True\n\n            Here, the \"author\" does not satisfy the constraints. Hence, the result is False.\n\n            >>> c1.check(book_2)\n            False\n\n            In this case, there is a missing field specified by the query, that is \"year\"\n            So the result is False, even in the case it is not required by the schema:\n\n            >>> c2.check(Description({\"author\": \"Stephen King\"}))\n            False\n\n            If the type of some attribute of the description is not correct, the result is False.\n            In this case, the field \"year\" has a string instead of an integer:\n\n            >>> c2.check(Description({\"author\": \"Stephen King\", \"year\": \"1991\"}))\n            False\n\n            >>> c3.check(Description({\"author\": \"Stephen King\", \"genre\": False}))\n            False\n\n        \"\"\"\n        # if the name of the attribute is not present, return false.\n        name = self.attribute_name\n        if name not in description.values:\n            return False\n\n        # if the type of the value is different from the type of the attribute, return false.\n        value = description.values[name]\n        if type(self.constraint_type.value) in {list, tuple, set} and not isinstance(\n            value, type(next(iter(self.constraint_type.value)))\n        ):\n            return False\n        if type(self.constraint_type.value) not in {\n            list,\n            tuple,\n            set,\n        } and not isinstance(value, type(self.constraint_type.value)):\n            return False\n\n        # dispatch the check to the right implementation for the concrete constraint type.\n        return self.constraint_type.check(value)\n\n    def is_valid(self, data_model: DataModel) -> bool:\n        \"\"\"\n        Check whether the constraint expression is valid wrt a data model.\n\n        :param data_model: the data model used to check the validity of the constraint expression.\n        :return: ``True`` if the constraint expression is valid wrt the data model, ``False`` otherwise.\n        \"\"\"\n        # if the attribute name of the constraint is not present in the data model, the constraint is not valid.\n        if self.attribute_name not in data_model.attributes_by_name:\n            return False\n\n        attribute = data_model.attributes_by_name[self.attribute_name]\n        return self.constraint_type.is_valid(attribute)\n\n    def __eq__(self, other: Any) -> bool:\n        \"\"\"Compare with another object.\"\"\"\n        return (\n            isinstance(other, Constraint)\n            and self.attribute_name == other.attribute_name\n            and self.constraint_type == other.constraint_type\n        )\n\n    def __str__(self) -> str:\n        \"\"\"Get the string representation of the constraint.\"\"\"\n        return \"Constraint(attribute_name={},constraint_type={})\".format(\n            self.attribute_name, self.constraint_type\n        )\n\n    def encode(self) -> models_pb2.Query.ConstraintExpr.Constraint:  # type: ignore\n        \"\"\"\n        Encode an instance of this class into a protocol buffer object.\n\n        :return: the matching protocol buffer object\n        \"\"\"\n        constraint = models_pb2.Query.ConstraintExpr.Constraint()  # type: ignore\n        constraint.attribute_name = self.attribute_name\n\n        if self.constraint_type.type in (\n            ConstraintTypes.EQUAL,\n            ConstraintTypes.NOT_EQUAL,\n            ConstraintTypes.LESS_THAN,\n            ConstraintTypes.LESS_THAN_EQ,\n            ConstraintTypes.GREATER_THAN,\n            ConstraintTypes.GREATER_THAN_EQ,\n        ):\n            constraint.relation.CopyFrom(self.constraint_type.encode())\n        elif self.constraint_type.type == ConstraintTypes.WITHIN:\n            constraint.range_.CopyFrom(self.constraint_type.encode())\n        elif self.constraint_type.type in (ConstraintTypes.IN, ConstraintTypes.NOT_IN):\n            constraint.set_.CopyFrom(self.constraint_type.encode())\n        elif self.constraint_type.type == ConstraintTypes.DISTANCE:\n            constraint.distance.CopyFrom(self.constraint_type.encode())\n        else:  # pragma: nocover\n            raise ValueError(\n                f\"Incorrect constraint type. Expected a ConstraintTypes. Found {self.constraint_type.type}.\"\n            )\n        return constraint\n\n    @classmethod\n    def decode(cls, constraint_pb: Any) -> \"Constraint\":\n        \"\"\"\n        Decode a protocol buffer object that corresponds with this class into an instance of this class.\n\n        :param constraint_pb: the protocol buffer object corresponding with this class.\n        :return: A new instance of this class matching the protocol buffer object\n        \"\"\"\n        constraint_case = constraint_pb.WhichOneof(\"constraint\")\n        if constraint_case == proto_constraint[\"relation\"]:\n            constraint_type = ConstraintType.decode(constraint_pb.relation, \"relation\")\n        elif constraint_case == proto_constraint[\"set\"]:\n            constraint_type = ConstraintType.decode(constraint_pb.set_, \"set\")\n        elif constraint_case == proto_constraint[\"range\"]:\n            constraint_type = ConstraintType.decode(constraint_pb.range_, \"range\")\n        elif constraint_case == proto_constraint[\"distance\"]:\n            constraint_type = ConstraintType.decode(constraint_pb.distance, \"distance\")\n        else:\n            raise ValueError(  # pragma: nocover\n                f\"Incorrect argument. Expected either of ['relation', 'set_', 'range_', 'distance']. Found {constraint_case}.\"\n            )\n\n        return cls(constraint_pb.attribute_name, constraint_type)\n\n\nclass Query:\n    \"\"\"This class lets you build a query for the OEF.\"\"\"\n\n    __slots__ = (\"constraints\", \"model\")\n\n    def __init__(\n        self, constraints: List[ConstraintExpr], model: Optional[DataModel] = None\n    ) -> None:\n        \"\"\"\n        Initialize a query.\n\n        :param constraints: a list of constraint expressions.\n        :param model: the data model that the query refers to.\n        \"\"\"\n        self.constraints = constraints\n        self.model = model\n        self.check_validity()\n\n    def check(self, description: Description) -> bool:\n        \"\"\"\n        Check if a description satisfies the constraints of the query.\n\n        The constraints are interpreted as conjunction.\n\n        :param description: the description to check.\n        :return: True if the description satisfies all the constraints, False otherwise.\n        \"\"\"\n        return all(c.check(description) for c in self.constraints)\n\n    def is_valid(self, data_model: Optional[DataModel]) -> bool:\n        \"\"\"\n        Given a data model, check whether the query is valid for that data model.\n\n        :param data_model: optional datamodel\n        :return: ``True`` if the query is compliant with the data model, ``False`` otherwise.\n        \"\"\"\n        if data_model is None:\n            return True\n\n        return all(c.is_valid(data_model) for c in self.constraints)\n\n    def check_validity(self) -> None:\n        \"\"\"\n        Check whether the` object is valid.\n\n        :return ``None``\n        :raises ValueError: if the query does not satisfy some sanity requirements.\n        \"\"\"\n        if not isinstance(self.constraints, list):\n            raise ValueError(\n                \"Constraints must be a list (`List[Constraint]`). Instead is of type '{}'.\".format(\n                    type(self.constraints).__name__\n                )\n            )\n        if len(self.constraints) < 1:\n            _default_logger.warning(\n                \"DEPRECATION WARNING: \"\n                \"Invalid input value for type '{}': empty list of constraints. The number of \"\n                \"constraints must be at least 1.\".format(type(self).__name__)\n            )\n        if not self.is_valid(self.model):\n            raise ValueError(\n                \"Invalid input value for type '{}': the query is not valid \"\n                \"for the given data model.\".format(type(self).__name__)\n            )\n\n    def __eq__(self, other: Any) -> bool:\n        \"\"\"Compare with another object.\"\"\"\n        return (\n            isinstance(other, Query)\n            and self.constraints == other.constraints\n            and self.model == other.model\n        )\n\n    def __str__(self) -> str:\n        \"\"\"Get the string representation of the constraint.\"\"\"\n        return \"Query(constraints={},model={})\".format(\n            [str(c) for c in self.constraints], self.model\n        )\n\n    def _encode(self) -> models_pb2.Query.Model:  # type: ignore\n        \"\"\"\n        Encode an instance of this class into a protocol buffer object.\n\n        :return: the matching protocol buffer object\n        \"\"\"\n        query = models_pb2.Query.Model()  # type: ignore\n        constraint_expression_pbs = [\n            ConstraintExpr._encode(constraint)  # pylint: disable=protected-access\n            for constraint in self.constraints\n        ]\n        query.constraints.extend(constraint_expression_pbs)\n\n        if self.model is not None:\n            query.model.CopyFrom(self.model.encode())\n        return query\n\n    @classmethod\n    def encode(cls, query_pb: Any, query: \"Query\") -> None:\n        \"\"\"\n        Encode an instance of this class into the protocol buffer object.\n\n        The protocol buffer object in the query_protobuf_object argument must be matched\n        with the instance of this class in the 'query_object' argument.\n\n        :param query_pb: the protocol buffer object wrapping an object that corresponds with this class.\n        :param query: an instance of this class to be encoded in the protocol buffer object.\n        \"\"\"\n        query_bytes_pb = query._encode()  # pylint: disable=protected-access\n        query_bytes_bytes = query_bytes_pb.SerializeToString()\n        query_pb.query_bytes = query_bytes_bytes\n\n    @classmethod\n    def _decode(cls, query_pb: Any) -> \"Query\":\n        \"\"\"\n        Decode a protocol buffer object that corresponds with this class into an instance of this class.\n\n        :param query_pb: the protocol buffer object corresponding with this class.\n        :return: A new instance of this class matching the protocol buffer object\n        \"\"\"\n        constraints = [\n            ConstraintExpr._decode(c)  # pylint: disable=protected-access\n            for c in query_pb.constraints\n        ]\n        data_model = DataModel.decode(query_pb.model)\n\n        return cls(\n            constraints,\n            data_model if query_pb.HasField(\"model\") else None,\n        )\n\n    @classmethod\n    def decode(cls, query_pb: Any) -> \"Query\":\n        \"\"\"\n        Decode a protocol buffer object that corresponds with this class into an instance of this class.\n\n        A new instance of this class must be created that matches the protocol\n        buffer object in the 'query_protobuf_object' argument.\n\n        :param query_pb: the protocol buffer object whose type corresponds with this class.\n        :return: A new instance of this class that matches the protocol buffer object in the 'query_protobuf_object' argument.\n        \"\"\"\n        query_bytes_pb = models_pb2.Query.Model()  # type: ignore\n        query_bytes_pb.ParseFromString(query_pb.query_bytes)\n        query = cls._decode(query_bytes_pb)\n        return query\n\n\ndef haversine(lat1: float, lon1: float, lat2: float, lon2: float) -> float:\n    \"\"\"\n    Compute the Haversine distance between two locations (i.e. two pairs of latitude and longitude).\n\n    :param lat1: the latitude of the first location.\n    :param lon1: the longitude of the first location.\n    :param lat2: the latitude of the second location.\n    :param lon2: the longitude of the second location.\n    :return: the Haversine distance.\n    \"\"\"\n    (\n        lat1,\n        lon1,\n        lat2,\n        lon2,\n    ) = map(radians, [lat1, lon1, lat2, lon2])\n    earth_radius = 6372.8  # average earth radius\n    dlat = lat2 - lat1\n    dlon = lon2 - lon1\n    sin_lat_squared = sin(dlat * 0.5) * sin(dlat * 0.5)\n    sin_lon_squared = sin(dlon * 0.5) * sin(dlon * 0.5)\n    computation = asin(sqrt(sin_lat_squared + sin_lon_squared * cos(lat1) * cos(lat2)))\n    distance = 2 * earth_radius * computation\n    return distance\n"
  },
  {
    "path": "aea/helpers/search/models_pb2.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by the protocol buffer compiler.  DO NOT EDIT!\n# source: models.proto\n\"\"\"Generated protocol buffer code.\"\"\"\nfrom google.protobuf import descriptor as _descriptor\nfrom google.protobuf import message as _message\nfrom google.protobuf import reflection as _reflection\nfrom google.protobuf import symbol_database as _symbol_database\n\n# @@protoc_insertion_point(imports)\n\n_sym_db = _symbol_database.Default()\n\n\nDESCRIPTOR = _descriptor.FileDescriptor(\n    name=\"models.proto\",\n    package=\"aea.helpers.search.models\",\n    syntax=\"proto3\",\n    serialized_options=b\"H\\001\",\n    create_key=_descriptor._internal_create_key,\n    serialized_pb=b'\\n\\x0cmodels.proto\\x12\\x19\\x61\\x65\\x61.helpers.search.models\"\\xc1\\x19\\n\\x05Query\\x1a\\xc0\\x01\\n\\tAttribute\\x12\\x0c\\n\\x04name\\x18\\x01 \\x01(\\t\\x12=\\n\\x04type\\x18\\x02 \\x01(\\x0e\\x32/.aea.helpers.search.models.Query.Attribute.Type\\x12\\x10\\n\\x08required\\x18\\x03 \\x01(\\x08\\x12\\x13\\n\\x0b\\x64\\x65scription\\x18\\x04 \\x01(\\t\"?\\n\\x04Type\\x12\\n\\n\\x06\\x44OUBLE\\x10\\x00\\x12\\x07\\n\\x03INT\\x10\\x01\\x12\\x08\\n\\x04\\x42OOL\\x10\\x02\\x12\\n\\n\\x06STRING\\x10\\x03\\x12\\x0c\\n\\x08LOCATION\\x10\\x04\\x1an\\n\\tDataModel\\x12\\x0c\\n\\x04name\\x18\\x01 \\x01(\\t\\x12>\\n\\nattributes\\x18\\x02 \\x03(\\x0b\\x32*.aea.helpers.search.models.Query.Attribute\\x12\\x13\\n\\x0b\\x64\\x65scription\\x18\\x03 \\x01(\\t\\x1a$\\n\\x08Location\\x12\\x0b\\n\\x03lon\\x18\\x01 \\x01(\\x01\\x12\\x0b\\n\\x03lat\\x18\\x02 \\x01(\\x01\\x1a\\x99\\x01\\n\\x05Value\\x12\\x10\\n\\x06string\\x18\\x01 \\x01(\\tH\\x00\\x12\\x10\\n\\x06\\x64ouble\\x18\\x02 \\x01(\\x01H\\x00\\x12\\x11\\n\\x07\\x62oolean\\x18\\x03 \\x01(\\x08H\\x00\\x12\\x11\\n\\x07integer\\x18\\x04 \\x01(\\x03H\\x00\\x12=\\n\\x08location\\x18\\x05 \\x01(\\x0b\\x32).aea.helpers.search.models.Query.LocationH\\x00\\x42\\x07\\n\\x05value\\x1aN\\n\\x08KeyValue\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\t\\x12\\x35\\n\\x05value\\x18\\x02 \\x01(\\x0b\\x32&.aea.helpers.search.models.Query.Value\\x1a\\x80\\x01\\n\\x08Instance\\x12\\x39\\n\\x05model\\x18\\x01 \\x01(\\x0b\\x32*.aea.helpers.search.models.Query.DataModel\\x12\\x39\\n\\x06values\\x18\\x02 \\x03(\\x0b\\x32).aea.helpers.search.models.Query.KeyValue\\x1a+\\n\\nStringPair\\x12\\r\\n\\x05\\x66irst\\x18\\x01 \\x01(\\t\\x12\\x0e\\n\\x06second\\x18\\x02 \\x01(\\t\\x1a(\\n\\x07IntPair\\x12\\r\\n\\x05\\x66irst\\x18\\x01 \\x01(\\x03\\x12\\x0e\\n\\x06second\\x18\\x02 \\x01(\\x03\\x1a+\\n\\nDoublePair\\x12\\r\\n\\x05\\x66irst\\x18\\x01 \\x01(\\x01\\x12\\x0e\\n\\x06second\\x18\\x02 \\x01(\\x01\\x1a\\x83\\x01\\n\\x0cLocationPair\\x12\\x38\\n\\x05\\x66irst\\x18\\x01 \\x01(\\x0b\\x32).aea.helpers.search.models.Query.Location\\x12\\x39\\n\\x06second\\x18\\x02 \\x01(\\x0b\\x32).aea.helpers.search.models.Query.Location\\x1a\\xa1\\x02\\n\\x05Range\\x12\\x42\\n\\x0bstring_pair\\x18\\x01 \\x01(\\x0b\\x32+.aea.helpers.search.models.Query.StringPairH\\x00\\x12@\\n\\x0cinteger_pair\\x18\\x02 \\x01(\\x0b\\x32(.aea.helpers.search.models.Query.IntPairH\\x00\\x12\\x42\\n\\x0b\\x64ouble_pair\\x18\\x03 \\x01(\\x0b\\x32+.aea.helpers.search.models.Query.DoublePairH\\x00\\x12\\x46\\n\\rlocation_pair\\x18\\x04 \\x01(\\x0b\\x32-.aea.helpers.search.models.Query.LocationPairH\\x00\\x42\\x06\\n\\x04pair\\x1aW\\n\\x08\\x44istance\\x12\\x39\\n\\x06\\x63\\x65nter\\x18\\x01 \\x01(\\x0b\\x32).aea.helpers.search.models.Query.Location\\x12\\x10\\n\\x08\\x64istance\\x18\\x02 \\x01(\\x01\\x1a\\xca\\x01\\n\\x08Relation\\x12\\x44\\n\\x08operator\\x18\\x01 \\x01(\\x0e\\x32\\x32.aea.helpers.search.models.Query.Relation.Operator\\x12\\x35\\n\\x05value\\x18\\x02 \\x01(\\x0b\\x32&.aea.helpers.search.models.Query.Value\"A\\n\\x08Operator\\x12\\x06\\n\\x02\\x45Q\\x10\\x00\\x12\\x06\\n\\x02LT\\x10\\x01\\x12\\x08\\n\\x04LTEQ\\x10\\x02\\x12\\x06\\n\\x02GT\\x10\\x03\\x12\\x08\\n\\x04GTEQ\\x10\\x04\\x12\\t\\n\\x05NOTEQ\\x10\\x05\\x1a\\xca\\x05\\n\\x03Set\\x12?\\n\\x08operator\\x18\\x01 \\x01(\\x0e\\x32-.aea.helpers.search.models.Query.Set.Operator\\x12;\\n\\x06values\\x18\\x02 \\x01(\\x0b\\x32+.aea.helpers.search.models.Query.Set.Values\\x1a\\xa5\\x04\\n\\x06Values\\x12\\x45\\n\\x06string\\x18\\x01 \\x01(\\x0b\\x32\\x33.aea.helpers.search.models.Query.Set.Values.StringsH\\x00\\x12\\x45\\n\\x06\\x64ouble\\x18\\x02 \\x01(\\x0b\\x32\\x33.aea.helpers.search.models.Query.Set.Values.DoublesH\\x00\\x12\\x44\\n\\x07\\x62oolean\\x18\\x03 \\x01(\\x0b\\x32\\x31.aea.helpers.search.models.Query.Set.Values.BoolsH\\x00\\x12\\x43\\n\\x07integer\\x18\\x04 \\x01(\\x0b\\x32\\x30.aea.helpers.search.models.Query.Set.Values.IntsH\\x00\\x12I\\n\\x08location\\x18\\x05 \\x01(\\x0b\\x32\\x35.aea.helpers.search.models.Query.Set.Values.LocationsH\\x00\\x1a\\x16\\n\\x04Ints\\x12\\x0e\\n\\x06values\\x18\\x01 \\x03(\\x03\\x1a\\x19\\n\\x07\\x44oubles\\x12\\x0e\\n\\x06values\\x18\\x01 \\x03(\\x01\\x1a\\x19\\n\\x07Strings\\x12\\x0e\\n\\x06values\\x18\\x01 \\x03(\\t\\x1a\\x17\\n\\x05\\x42ools\\x12\\x0e\\n\\x06values\\x18\\x01 \\x03(\\x08\\x1a\\x46\\n\\tLocations\\x12\\x39\\n\\x06values\\x18\\x01 \\x03(\\x0b\\x32).aea.helpers.search.models.Query.LocationB\\x08\\n\\x06values\"\\x1d\\n\\x08Operator\\x12\\x06\\n\\x02IN\\x10\\x00\\x12\\t\\n\\x05NOTIN\\x10\\x01\\x1a\\xc3\\x06\\n\\x0e\\x43onstraintExpr\\x12\\x41\\n\\x03or_\\x18\\x01 \\x01(\\x0b\\x32\\x32.aea.helpers.search.models.Query.ConstraintExpr.OrH\\x00\\x12\\x43\\n\\x04\\x61nd_\\x18\\x02 \\x01(\\x0b\\x32\\x33.aea.helpers.search.models.Query.ConstraintExpr.AndH\\x00\\x12\\x43\\n\\x04not_\\x18\\x03 \\x01(\\x0b\\x32\\x33.aea.helpers.search.models.Query.ConstraintExpr.NotH\\x00\\x12P\\n\\nconstraint\\x18\\x04 \\x01(\\x0b\\x32:.aea.helpers.search.models.Query.ConstraintExpr.ConstraintH\\x00\\x1aI\\n\\x02Or\\x12\\x43\\n\\nexpression\\x18\\x01 \\x03(\\x0b\\x32/.aea.helpers.search.models.Query.ConstraintExpr\\x1aJ\\n\\x03\\x41nd\\x12\\x43\\n\\nexpression\\x18\\x01 \\x03(\\x0b\\x32/.aea.helpers.search.models.Query.ConstraintExpr\\x1aJ\\n\\x03Not\\x12\\x43\\n\\nexpression\\x18\\x01 \\x01(\\x0b\\x32/.aea.helpers.search.models.Query.ConstraintExpr\\x1a\\xa0\\x02\\n\\nConstraint\\x12\\x16\\n\\x0e\\x61ttribute_name\\x18\\x01 \\x01(\\t\\x12\\x34\\n\\x04set_\\x18\\x02 \\x01(\\x0b\\x32$.aea.helpers.search.models.Query.SetH\\x00\\x12\\x38\\n\\x06range_\\x18\\x03 \\x01(\\x0b\\x32&.aea.helpers.search.models.Query.RangeH\\x00\\x12=\\n\\x08relation\\x18\\x04 \\x01(\\x0b\\x32).aea.helpers.search.models.Query.RelationH\\x00\\x12=\\n\\x08\\x64istance\\x18\\x05 \\x01(\\x0b\\x32).aea.helpers.search.models.Query.DistanceH\\x00\\x42\\x0c\\n\\nconstraintB\\x0c\\n\\nexpression\\x1a\\x88\\x01\\n\\x05Model\\x12\\x44\\n\\x0b\\x63onstraints\\x18\\x01 \\x03(\\x0b\\x32/.aea.helpers.search.models.Query.ConstraintExpr\\x12\\x39\\n\\x05model\\x18\\x02 \\x01(\\x0b\\x32*.aea.helpers.search.models.Query.DataModelB\\x02H\\x01\\x62\\x06proto3',\n)\n\n\n_QUERY_ATTRIBUTE_TYPE = _descriptor.EnumDescriptor(\n    name=\"Type\",\n    full_name=\"aea.helpers.search.models.Query.Attribute.Type\",\n    filename=None,\n    file=DESCRIPTOR,\n    create_key=_descriptor._internal_create_key,\n    values=[\n        _descriptor.EnumValueDescriptor(\n            name=\"DOUBLE\",\n            index=0,\n            number=0,\n            serialized_options=None,\n            type=None,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.EnumValueDescriptor(\n            name=\"INT\",\n            index=1,\n            number=1,\n            serialized_options=None,\n            type=None,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.EnumValueDescriptor(\n            name=\"BOOL\",\n            index=2,\n            number=2,\n            serialized_options=None,\n            type=None,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.EnumValueDescriptor(\n            name=\"STRING\",\n            index=3,\n            number=3,\n            serialized_options=None,\n            type=None,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.EnumValueDescriptor(\n            name=\"LOCATION\",\n            index=4,\n            number=4,\n            serialized_options=None,\n            type=None,\n            create_key=_descriptor._internal_create_key,\n        ),\n    ],\n    containing_type=None,\n    serialized_options=None,\n    serialized_start=183,\n    serialized_end=246,\n)\n_sym_db.RegisterEnumDescriptor(_QUERY_ATTRIBUTE_TYPE)\n\n_QUERY_RELATION_OPERATOR = _descriptor.EnumDescriptor(\n    name=\"Operator\",\n    full_name=\"aea.helpers.search.models.Query.Relation.Operator\",\n    filename=None,\n    file=DESCRIPTOR,\n    create_key=_descriptor._internal_create_key,\n    values=[\n        _descriptor.EnumValueDescriptor(\n            name=\"EQ\",\n            index=0,\n            number=0,\n            serialized_options=None,\n            type=None,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.EnumValueDescriptor(\n            name=\"LT\",\n            index=1,\n            number=1,\n            serialized_options=None,\n            type=None,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.EnumValueDescriptor(\n            name=\"LTEQ\",\n            index=2,\n            number=2,\n            serialized_options=None,\n            type=None,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.EnumValueDescriptor(\n            name=\"GT\",\n            index=3,\n            number=3,\n            serialized_options=None,\n            type=None,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.EnumValueDescriptor(\n            name=\"GTEQ\",\n            index=4,\n            number=4,\n            serialized_options=None,\n            type=None,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.EnumValueDescriptor(\n            name=\"NOTEQ\",\n            index=5,\n            number=5,\n            serialized_options=None,\n            type=None,\n            create_key=_descriptor._internal_create_key,\n        ),\n    ],\n    containing_type=None,\n    serialized_options=None,\n    serialized_start=1550,\n    serialized_end=1615,\n)\n_sym_db.RegisterEnumDescriptor(_QUERY_RELATION_OPERATOR)\n\n_QUERY_SET_OPERATOR = _descriptor.EnumDescriptor(\n    name=\"Operator\",\n    full_name=\"aea.helpers.search.models.Query.Set.Operator\",\n    filename=None,\n    file=DESCRIPTOR,\n    create_key=_descriptor._internal_create_key,\n    values=[\n        _descriptor.EnumValueDescriptor(\n            name=\"IN\",\n            index=0,\n            number=0,\n            serialized_options=None,\n            type=None,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.EnumValueDescriptor(\n            name=\"NOTIN\",\n            index=1,\n            number=1,\n            serialized_options=None,\n            type=None,\n            create_key=_descriptor._internal_create_key,\n        ),\n    ],\n    containing_type=None,\n    serialized_options=None,\n    serialized_start=2303,\n    serialized_end=2332,\n)\n_sym_db.RegisterEnumDescriptor(_QUERY_SET_OPERATOR)\n\n\n_QUERY_ATTRIBUTE = _descriptor.Descriptor(\n    name=\"Attribute\",\n    full_name=\"aea.helpers.search.models.Query.Attribute\",\n    filename=None,\n    file=DESCRIPTOR,\n    containing_type=None,\n    create_key=_descriptor._internal_create_key,\n    fields=[\n        _descriptor.FieldDescriptor(\n            name=\"name\",\n            full_name=\"aea.helpers.search.models.Query.Attribute.name\",\n            index=0,\n            number=1,\n            type=9,\n            cpp_type=9,\n            label=1,\n            has_default_value=False,\n            default_value=b\"\".decode(\"utf-8\"),\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.FieldDescriptor(\n            name=\"type\",\n            full_name=\"aea.helpers.search.models.Query.Attribute.type\",\n            index=1,\n            number=2,\n            type=14,\n            cpp_type=8,\n            label=1,\n            has_default_value=False,\n            default_value=0,\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.FieldDescriptor(\n            name=\"required\",\n            full_name=\"aea.helpers.search.models.Query.Attribute.required\",\n            index=2,\n            number=3,\n            type=8,\n            cpp_type=7,\n            label=1,\n            has_default_value=False,\n            default_value=False,\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.FieldDescriptor(\n            name=\"description\",\n            full_name=\"aea.helpers.search.models.Query.Attribute.description\",\n            index=3,\n            number=4,\n            type=9,\n            cpp_type=9,\n            label=1,\n            has_default_value=False,\n            default_value=b\"\".decode(\"utf-8\"),\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n    ],\n    extensions=[],\n    nested_types=[],\n    enum_types=[\n        _QUERY_ATTRIBUTE_TYPE,\n    ],\n    serialized_options=None,\n    is_extendable=False,\n    syntax=\"proto3\",\n    extension_ranges=[],\n    oneofs=[],\n    serialized_start=54,\n    serialized_end=246,\n)\n\n_QUERY_DATAMODEL = _descriptor.Descriptor(\n    name=\"DataModel\",\n    full_name=\"aea.helpers.search.models.Query.DataModel\",\n    filename=None,\n    file=DESCRIPTOR,\n    containing_type=None,\n    create_key=_descriptor._internal_create_key,\n    fields=[\n        _descriptor.FieldDescriptor(\n            name=\"name\",\n            full_name=\"aea.helpers.search.models.Query.DataModel.name\",\n            index=0,\n            number=1,\n            type=9,\n            cpp_type=9,\n            label=1,\n            has_default_value=False,\n            default_value=b\"\".decode(\"utf-8\"),\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.FieldDescriptor(\n            name=\"attributes\",\n            full_name=\"aea.helpers.search.models.Query.DataModel.attributes\",\n            index=1,\n            number=2,\n            type=11,\n            cpp_type=10,\n            label=3,\n            has_default_value=False,\n            default_value=[],\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.FieldDescriptor(\n            name=\"description\",\n            full_name=\"aea.helpers.search.models.Query.DataModel.description\",\n            index=2,\n            number=3,\n            type=9,\n            cpp_type=9,\n            label=1,\n            has_default_value=False,\n            default_value=b\"\".decode(\"utf-8\"),\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n    ],\n    extensions=[],\n    nested_types=[],\n    enum_types=[],\n    serialized_options=None,\n    is_extendable=False,\n    syntax=\"proto3\",\n    extension_ranges=[],\n    oneofs=[],\n    serialized_start=248,\n    serialized_end=358,\n)\n\n_QUERY_LOCATION = _descriptor.Descriptor(\n    name=\"Location\",\n    full_name=\"aea.helpers.search.models.Query.Location\",\n    filename=None,\n    file=DESCRIPTOR,\n    containing_type=None,\n    create_key=_descriptor._internal_create_key,\n    fields=[\n        _descriptor.FieldDescriptor(\n            name=\"lon\",\n            full_name=\"aea.helpers.search.models.Query.Location.lon\",\n            index=0,\n            number=1,\n            type=1,\n            cpp_type=5,\n            label=1,\n            has_default_value=False,\n            default_value=float(0),\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.FieldDescriptor(\n            name=\"lat\",\n            full_name=\"aea.helpers.search.models.Query.Location.lat\",\n            index=1,\n            number=2,\n            type=1,\n            cpp_type=5,\n            label=1,\n            has_default_value=False,\n            default_value=float(0),\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n    ],\n    extensions=[],\n    nested_types=[],\n    enum_types=[],\n    serialized_options=None,\n    is_extendable=False,\n    syntax=\"proto3\",\n    extension_ranges=[],\n    oneofs=[],\n    serialized_start=360,\n    serialized_end=396,\n)\n\n_QUERY_VALUE = _descriptor.Descriptor(\n    name=\"Value\",\n    full_name=\"aea.helpers.search.models.Query.Value\",\n    filename=None,\n    file=DESCRIPTOR,\n    containing_type=None,\n    create_key=_descriptor._internal_create_key,\n    fields=[\n        _descriptor.FieldDescriptor(\n            name=\"string\",\n            full_name=\"aea.helpers.search.models.Query.Value.string\",\n            index=0,\n            number=1,\n            type=9,\n            cpp_type=9,\n            label=1,\n            has_default_value=False,\n            default_value=b\"\".decode(\"utf-8\"),\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.FieldDescriptor(\n            name=\"double\",\n            full_name=\"aea.helpers.search.models.Query.Value.double\",\n            index=1,\n            number=2,\n            type=1,\n            cpp_type=5,\n            label=1,\n            has_default_value=False,\n            default_value=float(0),\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.FieldDescriptor(\n            name=\"boolean\",\n            full_name=\"aea.helpers.search.models.Query.Value.boolean\",\n            index=2,\n            number=3,\n            type=8,\n            cpp_type=7,\n            label=1,\n            has_default_value=False,\n            default_value=False,\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.FieldDescriptor(\n            name=\"integer\",\n            full_name=\"aea.helpers.search.models.Query.Value.integer\",\n            index=3,\n            number=4,\n            type=3,\n            cpp_type=2,\n            label=1,\n            has_default_value=False,\n            default_value=0,\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.FieldDescriptor(\n            name=\"location\",\n            full_name=\"aea.helpers.search.models.Query.Value.location\",\n            index=4,\n            number=5,\n            type=11,\n            cpp_type=10,\n            label=1,\n            has_default_value=False,\n            default_value=None,\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n    ],\n    extensions=[],\n    nested_types=[],\n    enum_types=[],\n    serialized_options=None,\n    is_extendable=False,\n    syntax=\"proto3\",\n    extension_ranges=[],\n    oneofs=[\n        _descriptor.OneofDescriptor(\n            name=\"value\",\n            full_name=\"aea.helpers.search.models.Query.Value.value\",\n            index=0,\n            containing_type=None,\n            create_key=_descriptor._internal_create_key,\n            fields=[],\n        ),\n    ],\n    serialized_start=399,\n    serialized_end=552,\n)\n\n_QUERY_KEYVALUE = _descriptor.Descriptor(\n    name=\"KeyValue\",\n    full_name=\"aea.helpers.search.models.Query.KeyValue\",\n    filename=None,\n    file=DESCRIPTOR,\n    containing_type=None,\n    create_key=_descriptor._internal_create_key,\n    fields=[\n        _descriptor.FieldDescriptor(\n            name=\"key\",\n            full_name=\"aea.helpers.search.models.Query.KeyValue.key\",\n            index=0,\n            number=1,\n            type=9,\n            cpp_type=9,\n            label=1,\n            has_default_value=False,\n            default_value=b\"\".decode(\"utf-8\"),\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.FieldDescriptor(\n            name=\"value\",\n            full_name=\"aea.helpers.search.models.Query.KeyValue.value\",\n            index=1,\n            number=2,\n            type=11,\n            cpp_type=10,\n            label=1,\n            has_default_value=False,\n            default_value=None,\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n    ],\n    extensions=[],\n    nested_types=[],\n    enum_types=[],\n    serialized_options=None,\n    is_extendable=False,\n    syntax=\"proto3\",\n    extension_ranges=[],\n    oneofs=[],\n    serialized_start=554,\n    serialized_end=632,\n)\n\n_QUERY_INSTANCE = _descriptor.Descriptor(\n    name=\"Instance\",\n    full_name=\"aea.helpers.search.models.Query.Instance\",\n    filename=None,\n    file=DESCRIPTOR,\n    containing_type=None,\n    create_key=_descriptor._internal_create_key,\n    fields=[\n        _descriptor.FieldDescriptor(\n            name=\"model\",\n            full_name=\"aea.helpers.search.models.Query.Instance.model\",\n            index=0,\n            number=1,\n            type=11,\n            cpp_type=10,\n            label=1,\n            has_default_value=False,\n            default_value=None,\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.FieldDescriptor(\n            name=\"values\",\n            full_name=\"aea.helpers.search.models.Query.Instance.values\",\n            index=1,\n            number=2,\n            type=11,\n            cpp_type=10,\n            label=3,\n            has_default_value=False,\n            default_value=[],\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n    ],\n    extensions=[],\n    nested_types=[],\n    enum_types=[],\n    serialized_options=None,\n    is_extendable=False,\n    syntax=\"proto3\",\n    extension_ranges=[],\n    oneofs=[],\n    serialized_start=635,\n    serialized_end=763,\n)\n\n_QUERY_STRINGPAIR = _descriptor.Descriptor(\n    name=\"StringPair\",\n    full_name=\"aea.helpers.search.models.Query.StringPair\",\n    filename=None,\n    file=DESCRIPTOR,\n    containing_type=None,\n    create_key=_descriptor._internal_create_key,\n    fields=[\n        _descriptor.FieldDescriptor(\n            name=\"first\",\n            full_name=\"aea.helpers.search.models.Query.StringPair.first\",\n            index=0,\n            number=1,\n            type=9,\n            cpp_type=9,\n            label=1,\n            has_default_value=False,\n            default_value=b\"\".decode(\"utf-8\"),\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.FieldDescriptor(\n            name=\"second\",\n            full_name=\"aea.helpers.search.models.Query.StringPair.second\",\n            index=1,\n            number=2,\n            type=9,\n            cpp_type=9,\n            label=1,\n            has_default_value=False,\n            default_value=b\"\".decode(\"utf-8\"),\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n    ],\n    extensions=[],\n    nested_types=[],\n    enum_types=[],\n    serialized_options=None,\n    is_extendable=False,\n    syntax=\"proto3\",\n    extension_ranges=[],\n    oneofs=[],\n    serialized_start=765,\n    serialized_end=808,\n)\n\n_QUERY_INTPAIR = _descriptor.Descriptor(\n    name=\"IntPair\",\n    full_name=\"aea.helpers.search.models.Query.IntPair\",\n    filename=None,\n    file=DESCRIPTOR,\n    containing_type=None,\n    create_key=_descriptor._internal_create_key,\n    fields=[\n        _descriptor.FieldDescriptor(\n            name=\"first\",\n            full_name=\"aea.helpers.search.models.Query.IntPair.first\",\n            index=0,\n            number=1,\n            type=3,\n            cpp_type=2,\n            label=1,\n            has_default_value=False,\n            default_value=0,\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.FieldDescriptor(\n            name=\"second\",\n            full_name=\"aea.helpers.search.models.Query.IntPair.second\",\n            index=1,\n            number=2,\n            type=3,\n            cpp_type=2,\n            label=1,\n            has_default_value=False,\n            default_value=0,\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n    ],\n    extensions=[],\n    nested_types=[],\n    enum_types=[],\n    serialized_options=None,\n    is_extendable=False,\n    syntax=\"proto3\",\n    extension_ranges=[],\n    oneofs=[],\n    serialized_start=810,\n    serialized_end=850,\n)\n\n_QUERY_DOUBLEPAIR = _descriptor.Descriptor(\n    name=\"DoublePair\",\n    full_name=\"aea.helpers.search.models.Query.DoublePair\",\n    filename=None,\n    file=DESCRIPTOR,\n    containing_type=None,\n    create_key=_descriptor._internal_create_key,\n    fields=[\n        _descriptor.FieldDescriptor(\n            name=\"first\",\n            full_name=\"aea.helpers.search.models.Query.DoublePair.first\",\n            index=0,\n            number=1,\n            type=1,\n            cpp_type=5,\n            label=1,\n            has_default_value=False,\n            default_value=float(0),\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.FieldDescriptor(\n            name=\"second\",\n            full_name=\"aea.helpers.search.models.Query.DoublePair.second\",\n            index=1,\n            number=2,\n            type=1,\n            cpp_type=5,\n            label=1,\n            has_default_value=False,\n            default_value=float(0),\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n    ],\n    extensions=[],\n    nested_types=[],\n    enum_types=[],\n    serialized_options=None,\n    is_extendable=False,\n    syntax=\"proto3\",\n    extension_ranges=[],\n    oneofs=[],\n    serialized_start=852,\n    serialized_end=895,\n)\n\n_QUERY_LOCATIONPAIR = _descriptor.Descriptor(\n    name=\"LocationPair\",\n    full_name=\"aea.helpers.search.models.Query.LocationPair\",\n    filename=None,\n    file=DESCRIPTOR,\n    containing_type=None,\n    create_key=_descriptor._internal_create_key,\n    fields=[\n        _descriptor.FieldDescriptor(\n            name=\"first\",\n            full_name=\"aea.helpers.search.models.Query.LocationPair.first\",\n            index=0,\n            number=1,\n            type=11,\n            cpp_type=10,\n            label=1,\n            has_default_value=False,\n            default_value=None,\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.FieldDescriptor(\n            name=\"second\",\n            full_name=\"aea.helpers.search.models.Query.LocationPair.second\",\n            index=1,\n            number=2,\n            type=11,\n            cpp_type=10,\n            label=1,\n            has_default_value=False,\n            default_value=None,\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n    ],\n    extensions=[],\n    nested_types=[],\n    enum_types=[],\n    serialized_options=None,\n    is_extendable=False,\n    syntax=\"proto3\",\n    extension_ranges=[],\n    oneofs=[],\n    serialized_start=898,\n    serialized_end=1029,\n)\n\n_QUERY_RANGE = _descriptor.Descriptor(\n    name=\"Range\",\n    full_name=\"aea.helpers.search.models.Query.Range\",\n    filename=None,\n    file=DESCRIPTOR,\n    containing_type=None,\n    create_key=_descriptor._internal_create_key,\n    fields=[\n        _descriptor.FieldDescriptor(\n            name=\"string_pair\",\n            full_name=\"aea.helpers.search.models.Query.Range.string_pair\",\n            index=0,\n            number=1,\n            type=11,\n            cpp_type=10,\n            label=1,\n            has_default_value=False,\n            default_value=None,\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.FieldDescriptor(\n            name=\"integer_pair\",\n            full_name=\"aea.helpers.search.models.Query.Range.integer_pair\",\n            index=1,\n            number=2,\n            type=11,\n            cpp_type=10,\n            label=1,\n            has_default_value=False,\n            default_value=None,\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.FieldDescriptor(\n            name=\"double_pair\",\n            full_name=\"aea.helpers.search.models.Query.Range.double_pair\",\n            index=2,\n            number=3,\n            type=11,\n            cpp_type=10,\n            label=1,\n            has_default_value=False,\n            default_value=None,\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.FieldDescriptor(\n            name=\"location_pair\",\n            full_name=\"aea.helpers.search.models.Query.Range.location_pair\",\n            index=3,\n            number=4,\n            type=11,\n            cpp_type=10,\n            label=1,\n            has_default_value=False,\n            default_value=None,\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n    ],\n    extensions=[],\n    nested_types=[],\n    enum_types=[],\n    serialized_options=None,\n    is_extendable=False,\n    syntax=\"proto3\",\n    extension_ranges=[],\n    oneofs=[\n        _descriptor.OneofDescriptor(\n            name=\"pair\",\n            full_name=\"aea.helpers.search.models.Query.Range.pair\",\n            index=0,\n            containing_type=None,\n            create_key=_descriptor._internal_create_key,\n            fields=[],\n        ),\n    ],\n    serialized_start=1032,\n    serialized_end=1321,\n)\n\n_QUERY_DISTANCE = _descriptor.Descriptor(\n    name=\"Distance\",\n    full_name=\"aea.helpers.search.models.Query.Distance\",\n    filename=None,\n    file=DESCRIPTOR,\n    containing_type=None,\n    create_key=_descriptor._internal_create_key,\n    fields=[\n        _descriptor.FieldDescriptor(\n            name=\"center\",\n            full_name=\"aea.helpers.search.models.Query.Distance.center\",\n            index=0,\n            number=1,\n            type=11,\n            cpp_type=10,\n            label=1,\n            has_default_value=False,\n            default_value=None,\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.FieldDescriptor(\n            name=\"distance\",\n            full_name=\"aea.helpers.search.models.Query.Distance.distance\",\n            index=1,\n            number=2,\n            type=1,\n            cpp_type=5,\n            label=1,\n            has_default_value=False,\n            default_value=float(0),\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n    ],\n    extensions=[],\n    nested_types=[],\n    enum_types=[],\n    serialized_options=None,\n    is_extendable=False,\n    syntax=\"proto3\",\n    extension_ranges=[],\n    oneofs=[],\n    serialized_start=1323,\n    serialized_end=1410,\n)\n\n_QUERY_RELATION = _descriptor.Descriptor(\n    name=\"Relation\",\n    full_name=\"aea.helpers.search.models.Query.Relation\",\n    filename=None,\n    file=DESCRIPTOR,\n    containing_type=None,\n    create_key=_descriptor._internal_create_key,\n    fields=[\n        _descriptor.FieldDescriptor(\n            name=\"operator\",\n            full_name=\"aea.helpers.search.models.Query.Relation.operator\",\n            index=0,\n            number=1,\n            type=14,\n            cpp_type=8,\n            label=1,\n            has_default_value=False,\n            default_value=0,\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.FieldDescriptor(\n            name=\"value\",\n            full_name=\"aea.helpers.search.models.Query.Relation.value\",\n            index=1,\n            number=2,\n            type=11,\n            cpp_type=10,\n            label=1,\n            has_default_value=False,\n            default_value=None,\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n    ],\n    extensions=[],\n    nested_types=[],\n    enum_types=[\n        _QUERY_RELATION_OPERATOR,\n    ],\n    serialized_options=None,\n    is_extendable=False,\n    syntax=\"proto3\",\n    extension_ranges=[],\n    oneofs=[],\n    serialized_start=1413,\n    serialized_end=1615,\n)\n\n_QUERY_SET_VALUES_INTS = _descriptor.Descriptor(\n    name=\"Ints\",\n    full_name=\"aea.helpers.search.models.Query.Set.Values.Ints\",\n    filename=None,\n    file=DESCRIPTOR,\n    containing_type=None,\n    create_key=_descriptor._internal_create_key,\n    fields=[\n        _descriptor.FieldDescriptor(\n            name=\"values\",\n            full_name=\"aea.helpers.search.models.Query.Set.Values.Ints.values\",\n            index=0,\n            number=1,\n            type=3,\n            cpp_type=2,\n            label=3,\n            has_default_value=False,\n            default_value=[],\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n    ],\n    extensions=[],\n    nested_types=[],\n    enum_types=[],\n    serialized_options=None,\n    is_extendable=False,\n    syntax=\"proto3\",\n    extension_ranges=[],\n    oneofs=[],\n    serialized_start=2118,\n    serialized_end=2140,\n)\n\n_QUERY_SET_VALUES_DOUBLES = _descriptor.Descriptor(\n    name=\"Doubles\",\n    full_name=\"aea.helpers.search.models.Query.Set.Values.Doubles\",\n    filename=None,\n    file=DESCRIPTOR,\n    containing_type=None,\n    create_key=_descriptor._internal_create_key,\n    fields=[\n        _descriptor.FieldDescriptor(\n            name=\"values\",\n            full_name=\"aea.helpers.search.models.Query.Set.Values.Doubles.values\",\n            index=0,\n            number=1,\n            type=1,\n            cpp_type=5,\n            label=3,\n            has_default_value=False,\n            default_value=[],\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n    ],\n    extensions=[],\n    nested_types=[],\n    enum_types=[],\n    serialized_options=None,\n    is_extendable=False,\n    syntax=\"proto3\",\n    extension_ranges=[],\n    oneofs=[],\n    serialized_start=2142,\n    serialized_end=2167,\n)\n\n_QUERY_SET_VALUES_STRINGS = _descriptor.Descriptor(\n    name=\"Strings\",\n    full_name=\"aea.helpers.search.models.Query.Set.Values.Strings\",\n    filename=None,\n    file=DESCRIPTOR,\n    containing_type=None,\n    create_key=_descriptor._internal_create_key,\n    fields=[\n        _descriptor.FieldDescriptor(\n            name=\"values\",\n            full_name=\"aea.helpers.search.models.Query.Set.Values.Strings.values\",\n            index=0,\n            number=1,\n            type=9,\n            cpp_type=9,\n            label=3,\n            has_default_value=False,\n            default_value=[],\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n    ],\n    extensions=[],\n    nested_types=[],\n    enum_types=[],\n    serialized_options=None,\n    is_extendable=False,\n    syntax=\"proto3\",\n    extension_ranges=[],\n    oneofs=[],\n    serialized_start=2169,\n    serialized_end=2194,\n)\n\n_QUERY_SET_VALUES_BOOLS = _descriptor.Descriptor(\n    name=\"Bools\",\n    full_name=\"aea.helpers.search.models.Query.Set.Values.Bools\",\n    filename=None,\n    file=DESCRIPTOR,\n    containing_type=None,\n    create_key=_descriptor._internal_create_key,\n    fields=[\n        _descriptor.FieldDescriptor(\n            name=\"values\",\n            full_name=\"aea.helpers.search.models.Query.Set.Values.Bools.values\",\n            index=0,\n            number=1,\n            type=8,\n            cpp_type=7,\n            label=3,\n            has_default_value=False,\n            default_value=[],\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n    ],\n    extensions=[],\n    nested_types=[],\n    enum_types=[],\n    serialized_options=None,\n    is_extendable=False,\n    syntax=\"proto3\",\n    extension_ranges=[],\n    oneofs=[],\n    serialized_start=2196,\n    serialized_end=2219,\n)\n\n_QUERY_SET_VALUES_LOCATIONS = _descriptor.Descriptor(\n    name=\"Locations\",\n    full_name=\"aea.helpers.search.models.Query.Set.Values.Locations\",\n    filename=None,\n    file=DESCRIPTOR,\n    containing_type=None,\n    create_key=_descriptor._internal_create_key,\n    fields=[\n        _descriptor.FieldDescriptor(\n            name=\"values\",\n            full_name=\"aea.helpers.search.models.Query.Set.Values.Locations.values\",\n            index=0,\n            number=1,\n            type=11,\n            cpp_type=10,\n            label=3,\n            has_default_value=False,\n            default_value=[],\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n    ],\n    extensions=[],\n    nested_types=[],\n    enum_types=[],\n    serialized_options=None,\n    is_extendable=False,\n    syntax=\"proto3\",\n    extension_ranges=[],\n    oneofs=[],\n    serialized_start=2221,\n    serialized_end=2291,\n)\n\n_QUERY_SET_VALUES = _descriptor.Descriptor(\n    name=\"Values\",\n    full_name=\"aea.helpers.search.models.Query.Set.Values\",\n    filename=None,\n    file=DESCRIPTOR,\n    containing_type=None,\n    create_key=_descriptor._internal_create_key,\n    fields=[\n        _descriptor.FieldDescriptor(\n            name=\"string\",\n            full_name=\"aea.helpers.search.models.Query.Set.Values.string\",\n            index=0,\n            number=1,\n            type=11,\n            cpp_type=10,\n            label=1,\n            has_default_value=False,\n            default_value=None,\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.FieldDescriptor(\n            name=\"double\",\n            full_name=\"aea.helpers.search.models.Query.Set.Values.double\",\n            index=1,\n            number=2,\n            type=11,\n            cpp_type=10,\n            label=1,\n            has_default_value=False,\n            default_value=None,\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.FieldDescriptor(\n            name=\"boolean\",\n            full_name=\"aea.helpers.search.models.Query.Set.Values.boolean\",\n            index=2,\n            number=3,\n            type=11,\n            cpp_type=10,\n            label=1,\n            has_default_value=False,\n            default_value=None,\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.FieldDescriptor(\n            name=\"integer\",\n            full_name=\"aea.helpers.search.models.Query.Set.Values.integer\",\n            index=3,\n            number=4,\n            type=11,\n            cpp_type=10,\n            label=1,\n            has_default_value=False,\n            default_value=None,\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.FieldDescriptor(\n            name=\"location\",\n            full_name=\"aea.helpers.search.models.Query.Set.Values.location\",\n            index=4,\n            number=5,\n            type=11,\n            cpp_type=10,\n            label=1,\n            has_default_value=False,\n            default_value=None,\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n    ],\n    extensions=[],\n    nested_types=[\n        _QUERY_SET_VALUES_INTS,\n        _QUERY_SET_VALUES_DOUBLES,\n        _QUERY_SET_VALUES_STRINGS,\n        _QUERY_SET_VALUES_BOOLS,\n        _QUERY_SET_VALUES_LOCATIONS,\n    ],\n    enum_types=[],\n    serialized_options=None,\n    is_extendable=False,\n    syntax=\"proto3\",\n    extension_ranges=[],\n    oneofs=[\n        _descriptor.OneofDescriptor(\n            name=\"values\",\n            full_name=\"aea.helpers.search.models.Query.Set.Values.values\",\n            index=0,\n            containing_type=None,\n            create_key=_descriptor._internal_create_key,\n            fields=[],\n        ),\n    ],\n    serialized_start=1752,\n    serialized_end=2301,\n)\n\n_QUERY_SET = _descriptor.Descriptor(\n    name=\"Set\",\n    full_name=\"aea.helpers.search.models.Query.Set\",\n    filename=None,\n    file=DESCRIPTOR,\n    containing_type=None,\n    create_key=_descriptor._internal_create_key,\n    fields=[\n        _descriptor.FieldDescriptor(\n            name=\"operator\",\n            full_name=\"aea.helpers.search.models.Query.Set.operator\",\n            index=0,\n            number=1,\n            type=14,\n            cpp_type=8,\n            label=1,\n            has_default_value=False,\n            default_value=0,\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.FieldDescriptor(\n            name=\"values\",\n            full_name=\"aea.helpers.search.models.Query.Set.values\",\n            index=1,\n            number=2,\n            type=11,\n            cpp_type=10,\n            label=1,\n            has_default_value=False,\n            default_value=None,\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n    ],\n    extensions=[],\n    nested_types=[\n        _QUERY_SET_VALUES,\n    ],\n    enum_types=[\n        _QUERY_SET_OPERATOR,\n    ],\n    serialized_options=None,\n    is_extendable=False,\n    syntax=\"proto3\",\n    extension_ranges=[],\n    oneofs=[],\n    serialized_start=1618,\n    serialized_end=2332,\n)\n\n_QUERY_CONSTRAINTEXPR_OR = _descriptor.Descriptor(\n    name=\"Or\",\n    full_name=\"aea.helpers.search.models.Query.ConstraintExpr.Or\",\n    filename=None,\n    file=DESCRIPTOR,\n    containing_type=None,\n    create_key=_descriptor._internal_create_key,\n    fields=[\n        _descriptor.FieldDescriptor(\n            name=\"expression\",\n            full_name=\"aea.helpers.search.models.Query.ConstraintExpr.Or.expression\",\n            index=0,\n            number=1,\n            type=11,\n            cpp_type=10,\n            label=3,\n            has_default_value=False,\n            default_value=[],\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n    ],\n    extensions=[],\n    nested_types=[],\n    enum_types=[],\n    serialized_options=None,\n    is_extendable=False,\n    syntax=\"proto3\",\n    extension_ranges=[],\n    oneofs=[],\n    serialized_start=2640,\n    serialized_end=2713,\n)\n\n_QUERY_CONSTRAINTEXPR_AND = _descriptor.Descriptor(\n    name=\"And\",\n    full_name=\"aea.helpers.search.models.Query.ConstraintExpr.And\",\n    filename=None,\n    file=DESCRIPTOR,\n    containing_type=None,\n    create_key=_descriptor._internal_create_key,\n    fields=[\n        _descriptor.FieldDescriptor(\n            name=\"expression\",\n            full_name=\"aea.helpers.search.models.Query.ConstraintExpr.And.expression\",\n            index=0,\n            number=1,\n            type=11,\n            cpp_type=10,\n            label=3,\n            has_default_value=False,\n            default_value=[],\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n    ],\n    extensions=[],\n    nested_types=[],\n    enum_types=[],\n    serialized_options=None,\n    is_extendable=False,\n    syntax=\"proto3\",\n    extension_ranges=[],\n    oneofs=[],\n    serialized_start=2715,\n    serialized_end=2789,\n)\n\n_QUERY_CONSTRAINTEXPR_NOT = _descriptor.Descriptor(\n    name=\"Not\",\n    full_name=\"aea.helpers.search.models.Query.ConstraintExpr.Not\",\n    filename=None,\n    file=DESCRIPTOR,\n    containing_type=None,\n    create_key=_descriptor._internal_create_key,\n    fields=[\n        _descriptor.FieldDescriptor(\n            name=\"expression\",\n            full_name=\"aea.helpers.search.models.Query.ConstraintExpr.Not.expression\",\n            index=0,\n            number=1,\n            type=11,\n            cpp_type=10,\n            label=1,\n            has_default_value=False,\n            default_value=None,\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n    ],\n    extensions=[],\n    nested_types=[],\n    enum_types=[],\n    serialized_options=None,\n    is_extendable=False,\n    syntax=\"proto3\",\n    extension_ranges=[],\n    oneofs=[],\n    serialized_start=2791,\n    serialized_end=2865,\n)\n\n_QUERY_CONSTRAINTEXPR_CONSTRAINT = _descriptor.Descriptor(\n    name=\"Constraint\",\n    full_name=\"aea.helpers.search.models.Query.ConstraintExpr.Constraint\",\n    filename=None,\n    file=DESCRIPTOR,\n    containing_type=None,\n    create_key=_descriptor._internal_create_key,\n    fields=[\n        _descriptor.FieldDescriptor(\n            name=\"attribute_name\",\n            full_name=\"aea.helpers.search.models.Query.ConstraintExpr.Constraint.attribute_name\",\n            index=0,\n            number=1,\n            type=9,\n            cpp_type=9,\n            label=1,\n            has_default_value=False,\n            default_value=b\"\".decode(\"utf-8\"),\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.FieldDescriptor(\n            name=\"set_\",\n            full_name=\"aea.helpers.search.models.Query.ConstraintExpr.Constraint.set_\",\n            index=1,\n            number=2,\n            type=11,\n            cpp_type=10,\n            label=1,\n            has_default_value=False,\n            default_value=None,\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.FieldDescriptor(\n            name=\"range_\",\n            full_name=\"aea.helpers.search.models.Query.ConstraintExpr.Constraint.range_\",\n            index=2,\n            number=3,\n            type=11,\n            cpp_type=10,\n            label=1,\n            has_default_value=False,\n            default_value=None,\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.FieldDescriptor(\n            name=\"relation\",\n            full_name=\"aea.helpers.search.models.Query.ConstraintExpr.Constraint.relation\",\n            index=3,\n            number=4,\n            type=11,\n            cpp_type=10,\n            label=1,\n            has_default_value=False,\n            default_value=None,\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.FieldDescriptor(\n            name=\"distance\",\n            full_name=\"aea.helpers.search.models.Query.ConstraintExpr.Constraint.distance\",\n            index=4,\n            number=5,\n            type=11,\n            cpp_type=10,\n            label=1,\n            has_default_value=False,\n            default_value=None,\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n    ],\n    extensions=[],\n    nested_types=[],\n    enum_types=[],\n    serialized_options=None,\n    is_extendable=False,\n    syntax=\"proto3\",\n    extension_ranges=[],\n    oneofs=[\n        _descriptor.OneofDescriptor(\n            name=\"constraint\",\n            full_name=\"aea.helpers.search.models.Query.ConstraintExpr.Constraint.constraint\",\n            index=0,\n            containing_type=None,\n            create_key=_descriptor._internal_create_key,\n            fields=[],\n        ),\n    ],\n    serialized_start=2868,\n    serialized_end=3156,\n)\n\n_QUERY_CONSTRAINTEXPR = _descriptor.Descriptor(\n    name=\"ConstraintExpr\",\n    full_name=\"aea.helpers.search.models.Query.ConstraintExpr\",\n    filename=None,\n    file=DESCRIPTOR,\n    containing_type=None,\n    create_key=_descriptor._internal_create_key,\n    fields=[\n        _descriptor.FieldDescriptor(\n            name=\"or_\",\n            full_name=\"aea.helpers.search.models.Query.ConstraintExpr.or_\",\n            index=0,\n            number=1,\n            type=11,\n            cpp_type=10,\n            label=1,\n            has_default_value=False,\n            default_value=None,\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.FieldDescriptor(\n            name=\"and_\",\n            full_name=\"aea.helpers.search.models.Query.ConstraintExpr.and_\",\n            index=1,\n            number=2,\n            type=11,\n            cpp_type=10,\n            label=1,\n            has_default_value=False,\n            default_value=None,\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.FieldDescriptor(\n            name=\"not_\",\n            full_name=\"aea.helpers.search.models.Query.ConstraintExpr.not_\",\n            index=2,\n            number=3,\n            type=11,\n            cpp_type=10,\n            label=1,\n            has_default_value=False,\n            default_value=None,\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.FieldDescriptor(\n            name=\"constraint\",\n            full_name=\"aea.helpers.search.models.Query.ConstraintExpr.constraint\",\n            index=3,\n            number=4,\n            type=11,\n            cpp_type=10,\n            label=1,\n            has_default_value=False,\n            default_value=None,\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n    ],\n    extensions=[],\n    nested_types=[\n        _QUERY_CONSTRAINTEXPR_OR,\n        _QUERY_CONSTRAINTEXPR_AND,\n        _QUERY_CONSTRAINTEXPR_NOT,\n        _QUERY_CONSTRAINTEXPR_CONSTRAINT,\n    ],\n    enum_types=[],\n    serialized_options=None,\n    is_extendable=False,\n    syntax=\"proto3\",\n    extension_ranges=[],\n    oneofs=[\n        _descriptor.OneofDescriptor(\n            name=\"expression\",\n            full_name=\"aea.helpers.search.models.Query.ConstraintExpr.expression\",\n            index=0,\n            containing_type=None,\n            create_key=_descriptor._internal_create_key,\n            fields=[],\n        ),\n    ],\n    serialized_start=2335,\n    serialized_end=3170,\n)\n\n_QUERY_MODEL = _descriptor.Descriptor(\n    name=\"Model\",\n    full_name=\"aea.helpers.search.models.Query.Model\",\n    filename=None,\n    file=DESCRIPTOR,\n    containing_type=None,\n    create_key=_descriptor._internal_create_key,\n    fields=[\n        _descriptor.FieldDescriptor(\n            name=\"constraints\",\n            full_name=\"aea.helpers.search.models.Query.Model.constraints\",\n            index=0,\n            number=1,\n            type=11,\n            cpp_type=10,\n            label=3,\n            has_default_value=False,\n            default_value=[],\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.FieldDescriptor(\n            name=\"model\",\n            full_name=\"aea.helpers.search.models.Query.Model.model\",\n            index=1,\n            number=2,\n            type=11,\n            cpp_type=10,\n            label=1,\n            has_default_value=False,\n            default_value=None,\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n    ],\n    extensions=[],\n    nested_types=[],\n    enum_types=[],\n    serialized_options=None,\n    is_extendable=False,\n    syntax=\"proto3\",\n    extension_ranges=[],\n    oneofs=[],\n    serialized_start=3173,\n    serialized_end=3309,\n)\n\n_QUERY = _descriptor.Descriptor(\n    name=\"Query\",\n    full_name=\"aea.helpers.search.models.Query\",\n    filename=None,\n    file=DESCRIPTOR,\n    containing_type=None,\n    create_key=_descriptor._internal_create_key,\n    fields=[],\n    extensions=[],\n    nested_types=[\n        _QUERY_ATTRIBUTE,\n        _QUERY_DATAMODEL,\n        _QUERY_LOCATION,\n        _QUERY_VALUE,\n        _QUERY_KEYVALUE,\n        _QUERY_INSTANCE,\n        _QUERY_STRINGPAIR,\n        _QUERY_INTPAIR,\n        _QUERY_DOUBLEPAIR,\n        _QUERY_LOCATIONPAIR,\n        _QUERY_RANGE,\n        _QUERY_DISTANCE,\n        _QUERY_RELATION,\n        _QUERY_SET,\n        _QUERY_CONSTRAINTEXPR,\n        _QUERY_MODEL,\n    ],\n    enum_types=[],\n    serialized_options=None,\n    is_extendable=False,\n    syntax=\"proto3\",\n    extension_ranges=[],\n    oneofs=[],\n    serialized_start=44,\n    serialized_end=3309,\n)\n\n_QUERY_ATTRIBUTE.fields_by_name[\"type\"].enum_type = _QUERY_ATTRIBUTE_TYPE\n_QUERY_ATTRIBUTE.containing_type = _QUERY\n_QUERY_ATTRIBUTE_TYPE.containing_type = _QUERY_ATTRIBUTE\n_QUERY_DATAMODEL.fields_by_name[\"attributes\"].message_type = _QUERY_ATTRIBUTE\n_QUERY_DATAMODEL.containing_type = _QUERY\n_QUERY_LOCATION.containing_type = _QUERY\n_QUERY_VALUE.fields_by_name[\"location\"].message_type = _QUERY_LOCATION\n_QUERY_VALUE.containing_type = _QUERY\n_QUERY_VALUE.oneofs_by_name[\"value\"].fields.append(\n    _QUERY_VALUE.fields_by_name[\"string\"]\n)\n_QUERY_VALUE.fields_by_name[\"string\"].containing_oneof = _QUERY_VALUE.oneofs_by_name[\n    \"value\"\n]\n_QUERY_VALUE.oneofs_by_name[\"value\"].fields.append(\n    _QUERY_VALUE.fields_by_name[\"double\"]\n)\n_QUERY_VALUE.fields_by_name[\"double\"].containing_oneof = _QUERY_VALUE.oneofs_by_name[\n    \"value\"\n]\n_QUERY_VALUE.oneofs_by_name[\"value\"].fields.append(\n    _QUERY_VALUE.fields_by_name[\"boolean\"]\n)\n_QUERY_VALUE.fields_by_name[\"boolean\"].containing_oneof = _QUERY_VALUE.oneofs_by_name[\n    \"value\"\n]\n_QUERY_VALUE.oneofs_by_name[\"value\"].fields.append(\n    _QUERY_VALUE.fields_by_name[\"integer\"]\n)\n_QUERY_VALUE.fields_by_name[\"integer\"].containing_oneof = _QUERY_VALUE.oneofs_by_name[\n    \"value\"\n]\n_QUERY_VALUE.oneofs_by_name[\"value\"].fields.append(\n    _QUERY_VALUE.fields_by_name[\"location\"]\n)\n_QUERY_VALUE.fields_by_name[\"location\"].containing_oneof = _QUERY_VALUE.oneofs_by_name[\n    \"value\"\n]\n_QUERY_KEYVALUE.fields_by_name[\"value\"].message_type = _QUERY_VALUE\n_QUERY_KEYVALUE.containing_type = _QUERY\n_QUERY_INSTANCE.fields_by_name[\"model\"].message_type = _QUERY_DATAMODEL\n_QUERY_INSTANCE.fields_by_name[\"values\"].message_type = _QUERY_KEYVALUE\n_QUERY_INSTANCE.containing_type = _QUERY\n_QUERY_STRINGPAIR.containing_type = _QUERY\n_QUERY_INTPAIR.containing_type = _QUERY\n_QUERY_DOUBLEPAIR.containing_type = _QUERY\n_QUERY_LOCATIONPAIR.fields_by_name[\"first\"].message_type = _QUERY_LOCATION\n_QUERY_LOCATIONPAIR.fields_by_name[\"second\"].message_type = _QUERY_LOCATION\n_QUERY_LOCATIONPAIR.containing_type = _QUERY\n_QUERY_RANGE.fields_by_name[\"string_pair\"].message_type = _QUERY_STRINGPAIR\n_QUERY_RANGE.fields_by_name[\"integer_pair\"].message_type = _QUERY_INTPAIR\n_QUERY_RANGE.fields_by_name[\"double_pair\"].message_type = _QUERY_DOUBLEPAIR\n_QUERY_RANGE.fields_by_name[\"location_pair\"].message_type = _QUERY_LOCATIONPAIR\n_QUERY_RANGE.containing_type = _QUERY\n_QUERY_RANGE.oneofs_by_name[\"pair\"].fields.append(\n    _QUERY_RANGE.fields_by_name[\"string_pair\"]\n)\n_QUERY_RANGE.fields_by_name[\n    \"string_pair\"\n].containing_oneof = _QUERY_RANGE.oneofs_by_name[\"pair\"]\n_QUERY_RANGE.oneofs_by_name[\"pair\"].fields.append(\n    _QUERY_RANGE.fields_by_name[\"integer_pair\"]\n)\n_QUERY_RANGE.fields_by_name[\n    \"integer_pair\"\n].containing_oneof = _QUERY_RANGE.oneofs_by_name[\"pair\"]\n_QUERY_RANGE.oneofs_by_name[\"pair\"].fields.append(\n    _QUERY_RANGE.fields_by_name[\"double_pair\"]\n)\n_QUERY_RANGE.fields_by_name[\n    \"double_pair\"\n].containing_oneof = _QUERY_RANGE.oneofs_by_name[\"pair\"]\n_QUERY_RANGE.oneofs_by_name[\"pair\"].fields.append(\n    _QUERY_RANGE.fields_by_name[\"location_pair\"]\n)\n_QUERY_RANGE.fields_by_name[\n    \"location_pair\"\n].containing_oneof = _QUERY_RANGE.oneofs_by_name[\"pair\"]\n_QUERY_DISTANCE.fields_by_name[\"center\"].message_type = _QUERY_LOCATION\n_QUERY_DISTANCE.containing_type = _QUERY\n_QUERY_RELATION.fields_by_name[\"operator\"].enum_type = _QUERY_RELATION_OPERATOR\n_QUERY_RELATION.fields_by_name[\"value\"].message_type = _QUERY_VALUE\n_QUERY_RELATION.containing_type = _QUERY\n_QUERY_RELATION_OPERATOR.containing_type = _QUERY_RELATION\n_QUERY_SET_VALUES_INTS.containing_type = _QUERY_SET_VALUES\n_QUERY_SET_VALUES_DOUBLES.containing_type = _QUERY_SET_VALUES\n_QUERY_SET_VALUES_STRINGS.containing_type = _QUERY_SET_VALUES\n_QUERY_SET_VALUES_BOOLS.containing_type = _QUERY_SET_VALUES\n_QUERY_SET_VALUES_LOCATIONS.fields_by_name[\"values\"].message_type = _QUERY_LOCATION\n_QUERY_SET_VALUES_LOCATIONS.containing_type = _QUERY_SET_VALUES\n_QUERY_SET_VALUES.fields_by_name[\"string\"].message_type = _QUERY_SET_VALUES_STRINGS\n_QUERY_SET_VALUES.fields_by_name[\"double\"].message_type = _QUERY_SET_VALUES_DOUBLES\n_QUERY_SET_VALUES.fields_by_name[\"boolean\"].message_type = _QUERY_SET_VALUES_BOOLS\n_QUERY_SET_VALUES.fields_by_name[\"integer\"].message_type = _QUERY_SET_VALUES_INTS\n_QUERY_SET_VALUES.fields_by_name[\"location\"].message_type = _QUERY_SET_VALUES_LOCATIONS\n_QUERY_SET_VALUES.containing_type = _QUERY_SET\n_QUERY_SET_VALUES.oneofs_by_name[\"values\"].fields.append(\n    _QUERY_SET_VALUES.fields_by_name[\"string\"]\n)\n_QUERY_SET_VALUES.fields_by_name[\n    \"string\"\n].containing_oneof = _QUERY_SET_VALUES.oneofs_by_name[\"values\"]\n_QUERY_SET_VALUES.oneofs_by_name[\"values\"].fields.append(\n    _QUERY_SET_VALUES.fields_by_name[\"double\"]\n)\n_QUERY_SET_VALUES.fields_by_name[\n    \"double\"\n].containing_oneof = _QUERY_SET_VALUES.oneofs_by_name[\"values\"]\n_QUERY_SET_VALUES.oneofs_by_name[\"values\"].fields.append(\n    _QUERY_SET_VALUES.fields_by_name[\"boolean\"]\n)\n_QUERY_SET_VALUES.fields_by_name[\n    \"boolean\"\n].containing_oneof = _QUERY_SET_VALUES.oneofs_by_name[\"values\"]\n_QUERY_SET_VALUES.oneofs_by_name[\"values\"].fields.append(\n    _QUERY_SET_VALUES.fields_by_name[\"integer\"]\n)\n_QUERY_SET_VALUES.fields_by_name[\n    \"integer\"\n].containing_oneof = _QUERY_SET_VALUES.oneofs_by_name[\"values\"]\n_QUERY_SET_VALUES.oneofs_by_name[\"values\"].fields.append(\n    _QUERY_SET_VALUES.fields_by_name[\"location\"]\n)\n_QUERY_SET_VALUES.fields_by_name[\n    \"location\"\n].containing_oneof = _QUERY_SET_VALUES.oneofs_by_name[\"values\"]\n_QUERY_SET.fields_by_name[\"operator\"].enum_type = _QUERY_SET_OPERATOR\n_QUERY_SET.fields_by_name[\"values\"].message_type = _QUERY_SET_VALUES\n_QUERY_SET.containing_type = _QUERY\n_QUERY_SET_OPERATOR.containing_type = _QUERY_SET\n_QUERY_CONSTRAINTEXPR_OR.fields_by_name[\n    \"expression\"\n].message_type = _QUERY_CONSTRAINTEXPR\n_QUERY_CONSTRAINTEXPR_OR.containing_type = _QUERY_CONSTRAINTEXPR\n_QUERY_CONSTRAINTEXPR_AND.fields_by_name[\n    \"expression\"\n].message_type = _QUERY_CONSTRAINTEXPR\n_QUERY_CONSTRAINTEXPR_AND.containing_type = _QUERY_CONSTRAINTEXPR\n_QUERY_CONSTRAINTEXPR_NOT.fields_by_name[\n    \"expression\"\n].message_type = _QUERY_CONSTRAINTEXPR\n_QUERY_CONSTRAINTEXPR_NOT.containing_type = _QUERY_CONSTRAINTEXPR\n_QUERY_CONSTRAINTEXPR_CONSTRAINT.fields_by_name[\"set_\"].message_type = _QUERY_SET\n_QUERY_CONSTRAINTEXPR_CONSTRAINT.fields_by_name[\"range_\"].message_type = _QUERY_RANGE\n_QUERY_CONSTRAINTEXPR_CONSTRAINT.fields_by_name[\n    \"relation\"\n].message_type = _QUERY_RELATION\n_QUERY_CONSTRAINTEXPR_CONSTRAINT.fields_by_name[\n    \"distance\"\n].message_type = _QUERY_DISTANCE\n_QUERY_CONSTRAINTEXPR_CONSTRAINT.containing_type = _QUERY_CONSTRAINTEXPR\n_QUERY_CONSTRAINTEXPR_CONSTRAINT.oneofs_by_name[\"constraint\"].fields.append(\n    _QUERY_CONSTRAINTEXPR_CONSTRAINT.fields_by_name[\"set_\"]\n)\n_QUERY_CONSTRAINTEXPR_CONSTRAINT.fields_by_name[\n    \"set_\"\n].containing_oneof = _QUERY_CONSTRAINTEXPR_CONSTRAINT.oneofs_by_name[\"constraint\"]\n_QUERY_CONSTRAINTEXPR_CONSTRAINT.oneofs_by_name[\"constraint\"].fields.append(\n    _QUERY_CONSTRAINTEXPR_CONSTRAINT.fields_by_name[\"range_\"]\n)\n_QUERY_CONSTRAINTEXPR_CONSTRAINT.fields_by_name[\n    \"range_\"\n].containing_oneof = _QUERY_CONSTRAINTEXPR_CONSTRAINT.oneofs_by_name[\"constraint\"]\n_QUERY_CONSTRAINTEXPR_CONSTRAINT.oneofs_by_name[\"constraint\"].fields.append(\n    _QUERY_CONSTRAINTEXPR_CONSTRAINT.fields_by_name[\"relation\"]\n)\n_QUERY_CONSTRAINTEXPR_CONSTRAINT.fields_by_name[\n    \"relation\"\n].containing_oneof = _QUERY_CONSTRAINTEXPR_CONSTRAINT.oneofs_by_name[\"constraint\"]\n_QUERY_CONSTRAINTEXPR_CONSTRAINT.oneofs_by_name[\"constraint\"].fields.append(\n    _QUERY_CONSTRAINTEXPR_CONSTRAINT.fields_by_name[\"distance\"]\n)\n_QUERY_CONSTRAINTEXPR_CONSTRAINT.fields_by_name[\n    \"distance\"\n].containing_oneof = _QUERY_CONSTRAINTEXPR_CONSTRAINT.oneofs_by_name[\"constraint\"]\n_QUERY_CONSTRAINTEXPR.fields_by_name[\"or_\"].message_type = _QUERY_CONSTRAINTEXPR_OR\n_QUERY_CONSTRAINTEXPR.fields_by_name[\"and_\"].message_type = _QUERY_CONSTRAINTEXPR_AND\n_QUERY_CONSTRAINTEXPR.fields_by_name[\"not_\"].message_type = _QUERY_CONSTRAINTEXPR_NOT\n_QUERY_CONSTRAINTEXPR.fields_by_name[\n    \"constraint\"\n].message_type = _QUERY_CONSTRAINTEXPR_CONSTRAINT\n_QUERY_CONSTRAINTEXPR.containing_type = _QUERY\n_QUERY_CONSTRAINTEXPR.oneofs_by_name[\"expression\"].fields.append(\n    _QUERY_CONSTRAINTEXPR.fields_by_name[\"or_\"]\n)\n_QUERY_CONSTRAINTEXPR.fields_by_name[\n    \"or_\"\n].containing_oneof = _QUERY_CONSTRAINTEXPR.oneofs_by_name[\"expression\"]\n_QUERY_CONSTRAINTEXPR.oneofs_by_name[\"expression\"].fields.append(\n    _QUERY_CONSTRAINTEXPR.fields_by_name[\"and_\"]\n)\n_QUERY_CONSTRAINTEXPR.fields_by_name[\n    \"and_\"\n].containing_oneof = _QUERY_CONSTRAINTEXPR.oneofs_by_name[\"expression\"]\n_QUERY_CONSTRAINTEXPR.oneofs_by_name[\"expression\"].fields.append(\n    _QUERY_CONSTRAINTEXPR.fields_by_name[\"not_\"]\n)\n_QUERY_CONSTRAINTEXPR.fields_by_name[\n    \"not_\"\n].containing_oneof = _QUERY_CONSTRAINTEXPR.oneofs_by_name[\"expression\"]\n_QUERY_CONSTRAINTEXPR.oneofs_by_name[\"expression\"].fields.append(\n    _QUERY_CONSTRAINTEXPR.fields_by_name[\"constraint\"]\n)\n_QUERY_CONSTRAINTEXPR.fields_by_name[\n    \"constraint\"\n].containing_oneof = _QUERY_CONSTRAINTEXPR.oneofs_by_name[\"expression\"]\n_QUERY_MODEL.fields_by_name[\"constraints\"].message_type = _QUERY_CONSTRAINTEXPR\n_QUERY_MODEL.fields_by_name[\"model\"].message_type = _QUERY_DATAMODEL\n_QUERY_MODEL.containing_type = _QUERY\nDESCRIPTOR.message_types_by_name[\"Query\"] = _QUERY\n_sym_db.RegisterFileDescriptor(DESCRIPTOR)\n\nQuery = _reflection.GeneratedProtocolMessageType(\n    \"Query\",\n    (_message.Message,),\n    {\n        \"Attribute\": _reflection.GeneratedProtocolMessageType(\n            \"Attribute\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _QUERY_ATTRIBUTE,\n                \"__module__\": \"models_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.helpers.search.models.Query.Attribute)\n            },\n        ),\n        \"DataModel\": _reflection.GeneratedProtocolMessageType(\n            \"DataModel\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _QUERY_DATAMODEL,\n                \"__module__\": \"models_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.helpers.search.models.Query.DataModel)\n            },\n        ),\n        \"Location\": _reflection.GeneratedProtocolMessageType(\n            \"Location\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _QUERY_LOCATION,\n                \"__module__\": \"models_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.helpers.search.models.Query.Location)\n            },\n        ),\n        \"Value\": _reflection.GeneratedProtocolMessageType(\n            \"Value\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _QUERY_VALUE,\n                \"__module__\": \"models_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.helpers.search.models.Query.Value)\n            },\n        ),\n        \"KeyValue\": _reflection.GeneratedProtocolMessageType(\n            \"KeyValue\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _QUERY_KEYVALUE,\n                \"__module__\": \"models_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.helpers.search.models.Query.KeyValue)\n            },\n        ),\n        \"Instance\": _reflection.GeneratedProtocolMessageType(\n            \"Instance\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _QUERY_INSTANCE,\n                \"__module__\": \"models_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.helpers.search.models.Query.Instance)\n            },\n        ),\n        \"StringPair\": _reflection.GeneratedProtocolMessageType(\n            \"StringPair\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _QUERY_STRINGPAIR,\n                \"__module__\": \"models_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.helpers.search.models.Query.StringPair)\n            },\n        ),\n        \"IntPair\": _reflection.GeneratedProtocolMessageType(\n            \"IntPair\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _QUERY_INTPAIR,\n                \"__module__\": \"models_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.helpers.search.models.Query.IntPair)\n            },\n        ),\n        \"DoublePair\": _reflection.GeneratedProtocolMessageType(\n            \"DoublePair\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _QUERY_DOUBLEPAIR,\n                \"__module__\": \"models_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.helpers.search.models.Query.DoublePair)\n            },\n        ),\n        \"LocationPair\": _reflection.GeneratedProtocolMessageType(\n            \"LocationPair\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _QUERY_LOCATIONPAIR,\n                \"__module__\": \"models_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.helpers.search.models.Query.LocationPair)\n            },\n        ),\n        \"Range\": _reflection.GeneratedProtocolMessageType(\n            \"Range\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _QUERY_RANGE,\n                \"__module__\": \"models_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.helpers.search.models.Query.Range)\n            },\n        ),\n        \"Distance\": _reflection.GeneratedProtocolMessageType(\n            \"Distance\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _QUERY_DISTANCE,\n                \"__module__\": \"models_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.helpers.search.models.Query.Distance)\n            },\n        ),\n        \"Relation\": _reflection.GeneratedProtocolMessageType(\n            \"Relation\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _QUERY_RELATION,\n                \"__module__\": \"models_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.helpers.search.models.Query.Relation)\n            },\n        ),\n        \"Set\": _reflection.GeneratedProtocolMessageType(\n            \"Set\",\n            (_message.Message,),\n            {\n                \"Values\": _reflection.GeneratedProtocolMessageType(\n                    \"Values\",\n                    (_message.Message,),\n                    {\n                        \"Ints\": _reflection.GeneratedProtocolMessageType(\n                            \"Ints\",\n                            (_message.Message,),\n                            {\n                                \"DESCRIPTOR\": _QUERY_SET_VALUES_INTS,\n                                \"__module__\": \"models_pb2\"\n                                # @@protoc_insertion_point(class_scope:aea.helpers.search.models.Query.Set.Values.Ints)\n                            },\n                        ),\n                        \"Doubles\": _reflection.GeneratedProtocolMessageType(\n                            \"Doubles\",\n                            (_message.Message,),\n                            {\n                                \"DESCRIPTOR\": _QUERY_SET_VALUES_DOUBLES,\n                                \"__module__\": \"models_pb2\"\n                                # @@protoc_insertion_point(class_scope:aea.helpers.search.models.Query.Set.Values.Doubles)\n                            },\n                        ),\n                        \"Strings\": _reflection.GeneratedProtocolMessageType(\n                            \"Strings\",\n                            (_message.Message,),\n                            {\n                                \"DESCRIPTOR\": _QUERY_SET_VALUES_STRINGS,\n                                \"__module__\": \"models_pb2\"\n                                # @@protoc_insertion_point(class_scope:aea.helpers.search.models.Query.Set.Values.Strings)\n                            },\n                        ),\n                        \"Bools\": _reflection.GeneratedProtocolMessageType(\n                            \"Bools\",\n                            (_message.Message,),\n                            {\n                                \"DESCRIPTOR\": _QUERY_SET_VALUES_BOOLS,\n                                \"__module__\": \"models_pb2\"\n                                # @@protoc_insertion_point(class_scope:aea.helpers.search.models.Query.Set.Values.Bools)\n                            },\n                        ),\n                        \"Locations\": _reflection.GeneratedProtocolMessageType(\n                            \"Locations\",\n                            (_message.Message,),\n                            {\n                                \"DESCRIPTOR\": _QUERY_SET_VALUES_LOCATIONS,\n                                \"__module__\": \"models_pb2\"\n                                # @@protoc_insertion_point(class_scope:aea.helpers.search.models.Query.Set.Values.Locations)\n                            },\n                        ),\n                        \"DESCRIPTOR\": _QUERY_SET_VALUES,\n                        \"__module__\": \"models_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.helpers.search.models.Query.Set.Values)\n                    },\n                ),\n                \"DESCRIPTOR\": _QUERY_SET,\n                \"__module__\": \"models_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.helpers.search.models.Query.Set)\n            },\n        ),\n        \"ConstraintExpr\": _reflection.GeneratedProtocolMessageType(\n            \"ConstraintExpr\",\n            (_message.Message,),\n            {\n                \"Or\": _reflection.GeneratedProtocolMessageType(\n                    \"Or\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _QUERY_CONSTRAINTEXPR_OR,\n                        \"__module__\": \"models_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.helpers.search.models.Query.ConstraintExpr.Or)\n                    },\n                ),\n                \"And\": _reflection.GeneratedProtocolMessageType(\n                    \"And\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _QUERY_CONSTRAINTEXPR_AND,\n                        \"__module__\": \"models_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.helpers.search.models.Query.ConstraintExpr.And)\n                    },\n                ),\n                \"Not\": _reflection.GeneratedProtocolMessageType(\n                    \"Not\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _QUERY_CONSTRAINTEXPR_NOT,\n                        \"__module__\": \"models_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.helpers.search.models.Query.ConstraintExpr.Not)\n                    },\n                ),\n                \"Constraint\": _reflection.GeneratedProtocolMessageType(\n                    \"Constraint\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _QUERY_CONSTRAINTEXPR_CONSTRAINT,\n                        \"__module__\": \"models_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.helpers.search.models.Query.ConstraintExpr.Constraint)\n                    },\n                ),\n                \"DESCRIPTOR\": _QUERY_CONSTRAINTEXPR,\n                \"__module__\": \"models_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.helpers.search.models.Query.ConstraintExpr)\n            },\n        ),\n        \"Model\": _reflection.GeneratedProtocolMessageType(\n            \"Model\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _QUERY_MODEL,\n                \"__module__\": \"models_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.helpers.search.models.Query.Model)\n            },\n        ),\n        \"DESCRIPTOR\": _QUERY,\n        \"__module__\": \"models_pb2\"\n        # @@protoc_insertion_point(class_scope:aea.helpers.search.models.Query)\n    },\n)\n_sym_db.RegisterMessage(Query)\n_sym_db.RegisterMessage(Query.Attribute)\n_sym_db.RegisterMessage(Query.DataModel)\n_sym_db.RegisterMessage(Query.Location)\n_sym_db.RegisterMessage(Query.Value)\n_sym_db.RegisterMessage(Query.KeyValue)\n_sym_db.RegisterMessage(Query.Instance)\n_sym_db.RegisterMessage(Query.StringPair)\n_sym_db.RegisterMessage(Query.IntPair)\n_sym_db.RegisterMessage(Query.DoublePair)\n_sym_db.RegisterMessage(Query.LocationPair)\n_sym_db.RegisterMessage(Query.Range)\n_sym_db.RegisterMessage(Query.Distance)\n_sym_db.RegisterMessage(Query.Relation)\n_sym_db.RegisterMessage(Query.Set)\n_sym_db.RegisterMessage(Query.Set.Values)\n_sym_db.RegisterMessage(Query.Set.Values.Ints)\n_sym_db.RegisterMessage(Query.Set.Values.Doubles)\n_sym_db.RegisterMessage(Query.Set.Values.Strings)\n_sym_db.RegisterMessage(Query.Set.Values.Bools)\n_sym_db.RegisterMessage(Query.Set.Values.Locations)\n_sym_db.RegisterMessage(Query.ConstraintExpr)\n_sym_db.RegisterMessage(Query.ConstraintExpr.Or)\n_sym_db.RegisterMessage(Query.ConstraintExpr.And)\n_sym_db.RegisterMessage(Query.ConstraintExpr.Not)\n_sym_db.RegisterMessage(Query.ConstraintExpr.Constraint)\n_sym_db.RegisterMessage(Query.Model)\n\n\nDESCRIPTOR._options = None\n# @@protoc_insertion_point(module_scope)\n"
  },
  {
    "path": "aea/helpers/serializers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains Serializers that can be used for custom types.\"\"\"\n\nimport copy\nfrom typing import Any, Dict, Tuple\n\nfrom google.protobuf.struct_pb2 import ListValue, Struct\n\n\nclass DictProtobufStructSerializer:\n    \"\"\"\n    Serialize python dictionaries of type DictType = Dict[str, ValueType] recursively conserving their dynamic type, using google.protobuf.Struct\n\n    ValueType = PrimitiveType | DictType | List[ValueType]]\n    PrimitiveType = bool | int | float | str | bytes\n    \"\"\"\n\n    NEED_PATCH = \"_need_patch\"\n\n    @classmethod\n    def encode(cls, dictionary: Dict[str, Any]) -> bytes:\n        \"\"\"\n        Serialize compatible dictionary to bytes.\n\n        Copies entire dictionary in the process.\n\n        :param dictionary: the dictionary to serialize\n        :return: serialized bytes string\n        \"\"\"\n        if not isinstance(dictionary, dict):\n            raise TypeError(  # pragma: nocover\n                \"dictionary must be of dict type, got type {}\".format(type(dictionary))\n            )\n        patched_dict = copy.deepcopy(dictionary)\n        cls._patch_dict(patched_dict)\n        pstruct = Struct()\n        pstruct.update(patched_dict)  # pylint: disable=no-member\n        return pstruct.SerializeToString(deterministic=True)\n\n    @classmethod\n    def decode(cls, buffer: bytes) -> Dict[str, Any]:\n        \"\"\"Deserialize a compatible dictionary\"\"\"\n        pstruct = Struct()\n        pstruct.ParseFromString(buffer)\n        dictionary = dict(pstruct)\n        cls._patch_dict_restore(dictionary)\n        return dictionary\n\n    @classmethod\n    def _bytes_to_str(cls, value: bytes) -> str:\n        return value.decode(\"utf-8\")\n\n    @classmethod\n    def _str_to_bytes(cls, value: str) -> bytes:\n        return value.encode(\"utf-8\")\n\n    @classmethod\n    def _patch_dict(cls, dictionnary: Dict[str, Any]) -> None:\n        need_patch: Dict[str, bool] = {}\n        for key, value in dictionnary.items():\n            new_value, patch_needed = cls._patch_value(value)\n            if patch_needed:\n                need_patch[key] = True\n            dictionnary[key] = new_value\n\n        if need_patch:\n            dict_need_patch = dictionnary.get(cls.NEED_PATCH, {})\n            dict_need_patch.update(need_patch)\n            dictionnary[cls.NEED_PATCH] = dict_need_patch\n\n    @classmethod\n    def _patch_value(cls, value: Any) -> Tuple[Any, bool]:\n        if isinstance(value, bytes):\n            return cls._bytes_to_str(value), True\n        if isinstance(value, int) and not isinstance(value, bool):\n            return value, True\n        if isinstance(value, list):\n            result = []\n            patched = False\n            types = set()\n            for v in value:\n                types.add(type(v))\n                v, need_patch = cls._patch_value(v)\n                if need_patch or isinstance(v, dict):\n                    patched = True\n                result.append(v)\n            if len(types) > 1:\n                raise ValueError(f\"Mixed data types in list are not allowed!: {value}\")\n            return result, patched\n        if isinstance(value, dict):\n            cls._patch_dict(value)\n            return value, False\n        if isinstance(value, tuple([bool, float, str, Struct])):\n            # do nothing for supported types\n            return value, False\n        if value is None:\n            return None, False\n\n        raise NotImplementedError(\n            \"DictProtobufStructSerializer doesn't support dict value type {}\".format(\n                type(value)\n            )\n        )\n\n    @classmethod\n    def _restore_value(cls, value: Any) -> Any:\n        if isinstance(value, str):\n            return cls._str_to_bytes(value)\n\n        if isinstance(value, Struct):\n            if value != Struct():\n                new_dict = dict(value)\n                cls._patch_dict_restore(new_dict)\n                return new_dict\n            return {}\n\n        if isinstance(value, float):\n            return int(value)\n\n        if isinstance(value, (list, ListValue)):\n            return [cls._restore_value(v) for v in value]  # type: ignore\n\n        raise NotImplementedError(  # pragma: nocover\n            \"DictProtobufStructSerializer doesn't support dict value type {}\".format(\n                type(value)\n            )\n        )\n\n    @classmethod\n    def _patch_dict_restore(cls, dictionary: Dict[str, Any]) -> None:\n        # protobuf Struct doesn't recursively convert Struct to dict\n        need_patch = dictionary.pop(cls.NEED_PATCH, {})\n        for key, value in dictionary.items():\n\n            # protobuf struct doesn't recursively convert Struct to dict\n            if isinstance(value, Struct):\n                dictionary[key] = cls._restore_value(value)\n\n            if key in need_patch:\n                dictionary[key] = cls._restore_value(value)\n\n            elif isinstance(value, (list, ListValue)):\n                # fix list of elementes not needed to be restored\n                dictionary[key] = list(value)  # type: ignore\n"
  },
  {
    "path": "aea/helpers/storage/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains generic storage code.\"\"\"\n"
  },
  {
    "path": "aea/helpers/storage/backends/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains storage abstract backend and implementations.\"\"\"\n"
  },
  {
    "path": "aea/helpers/storage/backends/base.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains storage abstract backend class.\"\"\"\nimport re\nfrom abc import ABC, abstractmethod\nfrom typing import List, Optional, Tuple, Union\n\nfrom aea.helpers.constants import JSON_TYPES\n\n\nEQUALS_TYPE = Union[int, float, str, bool]\nOBJECT_ID_AND_BODY = Tuple[str, JSON_TYPES]\n\n\nclass AbstractStorageBackend(ABC):\n    \"\"\"Abstract base class for storage backend.\"\"\"\n\n    VALID_COL_NAME = re.compile(\"^[a-zA-Z0-9_]+$\")\n\n    def __init__(self, uri: str) -> None:\n        \"\"\"Init backend.\"\"\"\n        self._uri = uri\n\n    def _check_collection_name(self, collection_name: str) -> None:\n        \"\"\"\n        Check collection name is valid.\n\n        :param collection_name: the collection name.\n        :raises ValueError: if bad collection name provided.\n        \"\"\"\n        if not self.VALID_COL_NAME.match(collection_name):\n            raise ValueError(\n                f\"Invalid collection name: {collection_name}, should contain only alpha-numeric characters and _\"\n            )\n\n    @abstractmethod\n    async def connect(self) -> None:\n        \"\"\"Connect to backend.\"\"\"\n\n    @abstractmethod\n    async def disconnect(self) -> None:\n        \"\"\"Disconnect the backend.\"\"\"\n\n    @abstractmethod\n    async def ensure_collection(self, collection_name: str) -> None:\n        \"\"\"\n        Create collection if not exits.\n\n        :param collection_name: str.\n        :return: None\n        \"\"\"\n\n    @abstractmethod\n    async def put(\n        self, collection_name: str, object_id: str, object_body: JSON_TYPES\n    ) -> None:\n        \"\"\"\n        Put object into collection.\n\n        :param collection_name: str.\n        :param object_id: str object id\n        :param object_body: python dict, json compatible.\n        :return: None\n        \"\"\"\n\n    @abstractmethod\n    async def get(self, collection_name: str, object_id: str) -> Optional[JSON_TYPES]:\n        \"\"\"\n        Get object from the collection.\n\n        :param collection_name: str.\n        :param object_id: str object id\n\n        :return: dict if object exists in collection otherwise None\n        \"\"\"\n\n    @abstractmethod\n    async def remove(self, collection_name: str, object_id: str) -> None:\n        \"\"\"\n        Remove object from the collection.\n\n        :param collection_name: str.\n        :param object_id: str object id\n\n        :return: None\n        \"\"\"\n\n    @abstractmethod\n    async def find(\n        self, collection_name: str, field: str, equals: EQUALS_TYPE\n    ) -> List[OBJECT_ID_AND_BODY]:\n        \"\"\"\n        Get objects from the collection by filtering by field value.\n\n        :param collection_name: str.\n        :param field: field name to search: example \"parent.field\"\n        :param equals: value field should be equal to\n\n        :return:  list of objects bodies\n        \"\"\"\n\n    @abstractmethod\n    async def list(self, collection_name: str) -> List[OBJECT_ID_AND_BODY]:\n        \"\"\"\n        List all objects with keys from the collection.\n\n        :param collection_name: str.\n        :return: Tuple of objects keys, bodies.\n        \"\"\"\n"
  },
  {
    "path": "aea/helpers/storage/backends/binaries/README.txt",
    "content": "json1.dll - is sqlite extension for windows python<3.9\n"
  },
  {
    "path": "aea/helpers/storage/backends/sqlite.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains sqlite storage backend implementation.\"\"\"\nimport asyncio\nimport json\nimport os\nimport platform\nimport sqlite3\nimport sys\nimport threading\nfrom concurrent.futures.thread import ThreadPoolExecutor\nfrom pathlib import Path\nfrom typing import List, Optional, Tuple\nfrom urllib.parse import urlparse\n\nfrom aea.helpers.storage.backends.base import (\n    AbstractStorageBackend,\n    EQUALS_TYPE,\n    JSON_TYPES,\n    OBJECT_ID_AND_BODY,\n)\n\n\nclass SqliteStorageBackend(AbstractStorageBackend):\n    \"\"\"Sqlite storage backend.\"\"\"\n\n    def __init__(self, uri: str) -> None:\n        \"\"\"Init backend.\"\"\"\n        super().__init__(uri)\n        parsed = urlparse(self._uri)\n        self._fname = parsed.netloc or parsed.path\n        self._connection: Optional[sqlite3.Connection] = None\n        self._loop: Optional[asyncio.AbstractEventLoop] = None\n        self._lock = threading.Lock()\n        self._executor = ThreadPoolExecutor(max_workers=1)\n\n    def _execute_sql_sync(self, query: str, args: Optional[List] = None) -> List[Tuple]:\n        \"\"\"\n        Execute sql command and return results.\n\n        :param query: sql query string\n        :param args: optional arguments to set into sql query.\n\n        :return: List of tuples with sql records\n        \"\"\"\n        if not self._connection:  # pragma: nocover\n            raise ValueError(\"Not connected\")\n        with self._lock:\n            result = self._connection.execute(query, args or []).fetchall()\n            self._connection.commit()\n            return result\n\n    async def _executute_sql(\n        self, query: str, args: Optional[List] = None\n    ) -> Optional[JSON_TYPES]:\n        \"\"\"\n        Execute sql command and return results in async executor.\n\n        :param query: sql query string\n        :param args: optional arguments to set into sql query.\n\n        :return: List of tuples with sql records\n        \"\"\"\n        if not self._loop:  # pragma: nocover\n            raise ValueError(\"Not connected\")\n        return await self._loop.run_in_executor(\n            self._executor, self._execute_sql_sync, query, args\n        )\n\n    async def connect(self) -> None:\n        \"\"\"Connect to backend.\"\"\"\n        self._loop = asyncio.get_event_loop()\n        self._connection = await self._loop.run_in_executor(\n            self._executor, self._do_connect, self._fname\n        )\n\n    @staticmethod\n    def _do_connect(fname: str) -> sqlite3.Connection:\n        con = sqlite3.connect(fname)\n        if (\n            platform.system() == \"Windows\"\n            and sys.version_info.major == 3\n            and sys.version_info.minor < 9\n        ):  # pragma: nocover\n            con.enable_load_extension(True)\n            path_ext = Path(\n                os.path.join(os.path.dirname(__file__), \"binaries\", \"json1.dll\")\n            ).as_posix()\n            con.load_extension(path_ext)\n        return con\n\n    async def disconnect(self) -> None:\n        \"\"\"Disconnect the backend.\"\"\"\n        if not self._loop or not self._connection:  # pragma: nocover\n            raise ValueError(\"Not connected\")\n        await self._loop.run_in_executor(self._executor, self._connection.close)\n        self._connection = None\n        self._loop = None\n\n    async def ensure_collection(self, collection_name: str) -> None:\n        \"\"\"\n        Create collection if not exits.\n\n        :param collection_name: name of the collection.\n        \"\"\"\n        self._check_collection_name(collection_name)\n        sql = f\"\"\"CREATE TABLE IF NOT EXISTS {collection_name} (\n            object_id TEXT PRIMARY KEY,\n            object_body JSON1 NOT NULL)\n        \"\"\"  # nosec\n        await self._executute_sql(sql)\n\n    async def put(\n        self, collection_name: str, object_id: str, object_body: JSON_TYPES\n    ) -> None:\n        \"\"\"\n        Put object into collection.\n\n        :param collection_name: str.\n        :param object_id: str object id\n        :param object_body: python dict, json compatible.\n        \"\"\"\n        self._check_collection_name(collection_name)\n        sql = f\"\"\"INSERT OR REPLACE INTO {collection_name} (object_id, object_body)\n            VALUES (?, ?);\n        \"\"\"  # nosec\n        await self._executute_sql(sql, [object_id, json.dumps(object_body)])\n\n    async def get(self, collection_name: str, object_id: str) -> Optional[JSON_TYPES]:\n        \"\"\"\n        Get object from the collection.\n\n        :param collection_name: str.\n        :param object_id: str object id\n\n        :return: dict if object exists in collection otherwise None\n        \"\"\"\n        self._check_collection_name(collection_name)\n        sql = f\"\"\"SELECT object_body FROM {collection_name} WHERE object_id = ? LIMIT 1;\"\"\"  # nosec\n        result = await self._executute_sql(sql, [object_id])\n        if (\n            result\n            and isinstance(result, (list, tuple))\n            and len(result) > 0\n            and isinstance(result[0], (list, tuple))\n            and len(result[0]) > 0\n        ):\n            return json.loads(result[0][0])\n        return None\n\n    async def remove(self, collection_name: str, object_id: str) -> None:\n        \"\"\"\n        Remove object from the collection.\n\n        :param collection_name: str.\n        :param object_id: str object id\n        \"\"\"\n        self._check_collection_name(collection_name)\n        sql = f\"\"\"DELETE FROM {collection_name} WHERE object_id = ?;\"\"\"  # nosec\n        await self._executute_sql(sql, [object_id])\n\n    async def find(\n        self, collection_name: str, field: str, equals: EQUALS_TYPE\n    ) -> List[OBJECT_ID_AND_BODY]:\n        \"\"\"\n        Get objects from the collection by filtering by field value.\n\n        :param collection_name: str.\n        :param field: field name to search: example \"parent.field\"\n        :param equals: value field should be equal to\n        :return: list of object ids and body\n        \"\"\"\n        self._check_collection_name(collection_name)\n        sql = f\"\"\"SELECT object_id, object_body FROM {collection_name} WHERE json_extract(object_body, ?) = ?;\"\"\"  # nosec\n        if not field.startswith(\"$.\"):\n            field = f\"$.{field}\"\n        return [\n            (i[0], json.loads(i[1]))\n            for i in await self._executute_sql(sql, [field, equals])  # type: ignore\n        ]\n\n    async def list(self, collection_name: str) -> List[OBJECT_ID_AND_BODY]:\n        \"\"\"\n        List all objects with keys from the collection.\n\n        :param collection_name: str.\n        :return: Tuple of objects keys, bodies.\n        \"\"\"\n        self._check_collection_name(collection_name)\n        sql = f\"\"\"SELECT object_id, object_body FROM {collection_name};\"\"\"  # nosec\n        return [(i[0], json.loads(i[1])) for i in await self._executute_sql(sql)]  # type: ignore\n"
  },
  {
    "path": "aea/helpers/storage/generic_storage.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the storage implementation.\"\"\"\nimport asyncio\nfrom typing import Any, Coroutine, List, Optional\nfrom urllib.parse import urlparse\n\nfrom aea.helpers.async_utils import AsyncState, Runnable\nfrom aea.helpers.storage.backends.base import (\n    AbstractStorageBackend,\n    EQUALS_TYPE,\n    JSON_TYPES,\n    OBJECT_ID_AND_BODY,\n)\nfrom aea.helpers.storage.backends.sqlite import SqliteStorageBackend\n\n\nBACKENDS = {\"sqlite\": SqliteStorageBackend}\n\n\nclass AsyncCollection:\n    \"\"\"Async collection.\"\"\"\n\n    def __init__(\n        self, storage_backend: AbstractStorageBackend, collection_name: str\n    ) -> None:\n        \"\"\"\n        Init collection object.\n\n        :param storage_backend: storage backed to use.\n        :param collection_name: str\n        \"\"\"\n        self._storage_backend = storage_backend\n        self._collection_name = collection_name\n\n    async def put(self, object_id: str, object_body: JSON_TYPES) -> None:\n        \"\"\"\n        Put object into collection.\n\n        :param object_id: str object id\n        :param object_body: python dict, json compatible.\n        :return: None\n        \"\"\"\n\n        return await self._storage_backend.put(\n            self._collection_name, object_id, object_body\n        )\n\n    async def get(self, object_id: str) -> Optional[JSON_TYPES]:\n        \"\"\"\n        Get object from the collection.\n\n        :param object_id: str object id\n\n        :return: dict if object exists in collection otherwise None\n        \"\"\"\n        return await self._storage_backend.get(self._collection_name, object_id)\n\n    async def remove(self, object_id: str) -> None:\n        \"\"\"\n        Remove object from the collection.\n\n        :param object_id: str object id\n\n        :return: None\n        \"\"\"\n        return await self._storage_backend.remove(self._collection_name, object_id)\n\n    async def find(self, field: str, equals: EQUALS_TYPE) -> List[OBJECT_ID_AND_BODY]:\n        \"\"\"\n        Get objects from the collection by filtering by field value.\n\n        :param field: field name to search: example \"parent.field\"\n        :param equals: value field should be equal to\n\n        :return: None\n        \"\"\"\n        return await self._storage_backend.find(self._collection_name, field, equals)\n\n    async def list(self) -> List[OBJECT_ID_AND_BODY]:\n        \"\"\"\n        List all objects with keys from the collection.\n\n        :return: Tuple of objects keys, bodies.\n        \"\"\"\n        return await self._storage_backend.list(self._collection_name)\n\n\nclass SyncCollection:\n    \"\"\"Async collection.\"\"\"\n\n    def __init__(\n        self, async_collection_coro: Coroutine, loop: asyncio.AbstractEventLoop\n    ) -> None:\n        \"\"\"\n        Init collection object.\n\n        :param async_collection_coro: coroutine returns async collection.\n        :param loop: abstract event loop where storage is running.\n        \"\"\"\n        self._loop = loop\n        self._async_collection = self._run_sync(async_collection_coro)\n\n    def _run_sync(self, coro: Coroutine) -> Any:\n        return asyncio.run_coroutine_threadsafe(coro, self._loop).result()\n\n    def put(self, object_id: str, object_body: JSON_TYPES) -> None:\n        \"\"\"\n        Put object into collection.\n\n        :param object_id: str object id\n        :param object_body: python dict, json compatible.\n        :return: None\n        \"\"\"\n        return self._run_sync(self._async_collection.put(object_id, object_body))\n\n    def get(self, object_id: str) -> Optional[JSON_TYPES]:\n        \"\"\"\n        Get object from the collection.\n\n        :param object_id: str object id\n\n        :return: dict if object exists in collection otherwise None\n        \"\"\"\n        return self._run_sync(self._async_collection.get(object_id))\n\n    def remove(self, object_id: str) -> None:\n        \"\"\"\n        Remove object from the collection.\n\n        :param object_id: str object id\n\n        :return: None\n        \"\"\"\n        return self._run_sync(self._async_collection.remove(object_id))\n\n    def find(self, field: str, equals: EQUALS_TYPE) -> List[OBJECT_ID_AND_BODY]:\n        \"\"\"\n        Get objects from the collection by filtering by field value.\n\n        :param field: field name to search: example \"parent.field\"\n        :param equals: value field should be equal to\n\n        :return: List of object bodies\n        \"\"\"\n        return self._run_sync(self._async_collection.find(field, equals))\n\n    def list(self) -> List[OBJECT_ID_AND_BODY]:\n        \"\"\"\n        List all objects with keys from the collection.\n\n        :return: Tuple of objects keys, bodies.\n        \"\"\"\n        return self._run_sync(self._async_collection.list())\n\n\nclass Storage(Runnable):\n    \"\"\"Generic storage.\"\"\"\n\n    def __init__(\n        self,\n        storage_uri: str,\n        loop: asyncio.AbstractEventLoop = None,\n        threaded: bool = False,\n    ) -> None:\n        \"\"\"\n        Init storage.\n\n        :param storage_uri: configuration string for storage.\n        :param loop: asyncio event loop to use.\n        :param threaded: bool. start in thread if True.\n        \"\"\"\n        super().__init__(loop=loop, threaded=threaded)\n        self._storage_uri = storage_uri\n        self._backend: AbstractStorageBackend = self._get_backend_instance(storage_uri)\n        self._is_connected = False\n        self._connected_state = AsyncState(False)\n\n    async def wait_connected(self) -> None:\n        \"\"\"Wait generic storage is connected.\"\"\"\n        await self._connected_state.wait(True)\n\n    @property\n    def is_connected(self) -> bool:\n        \"\"\"Get running state of the storage.\"\"\"\n        return self._is_connected\n\n    async def run(self) -> None:\n        \"\"\"Connect storage.\"\"\"\n        await self._backend.connect()\n        self._is_connected = True\n        self._connected_state.set(True)\n        try:\n            while True:\n                await asyncio.sleep(1)\n        finally:\n            await self._backend.disconnect()\n            self._is_connected = False\n\n    @classmethod\n    def _get_backend_instance(cls, uri: str) -> AbstractStorageBackend:\n        \"\"\"Construct backend instance.\"\"\"\n        backend_name = urlparse(uri).scheme\n        backend_class = BACKENDS.get(backend_name, None)\n        if backend_class is None:\n            raise ValueError(\n                f\"Backend `{backend_name}` is not supported. Supported are {', '.join(BACKENDS.keys())} \"\n            )\n        return backend_class(uri)\n\n    async def get_collection(self, collection_name: str) -> AsyncCollection:\n        \"\"\"Get async collection.\"\"\"\n        await self._backend.ensure_collection(collection_name)\n        return AsyncCollection(\n            collection_name=collection_name, storage_backend=self._backend\n        )\n\n    def get_sync_collection(self, collection_name: str) -> SyncCollection:\n        \"\"\"Get sync collection.\"\"\"\n        if not self._loop:  # pragma: nocover\n            raise ValueError(\"Storage not started!\")\n        return SyncCollection(self.get_collection(collection_name), self._loop)\n\n    def __repr__(self) -> str:\n        \"\"\"Get string representation of the storage.\"\"\"\n        return f\"[GenericStorage({self._storage_uri}){'Connected' if self.is_connected else 'Not connected'}]\"\n"
  },
  {
    "path": "aea/helpers/sym_link.py",
    "content": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Sym link implementation for Linux, MacOS, and Windows.\"\"\"\n\nimport contextlib\nimport os\nfrom functools import reduce\nfrom pathlib import Path\nfrom typing import Generator\n\n\ndef make_symlink(link_name: str, target: str) -> None:\n    \"\"\"\n    Make a symbolic link, cross platform.\n\n    :param link_name: the link name.\n    :param target: the target.\n    \"\"\"\n    try:\n        Path(link_name).unlink()\n    except FileNotFoundError:\n        pass\n    Path(link_name).symlink_to(target, target_is_directory=True)\n\n\n@contextlib.contextmanager\ndef cd(path: Path) -> Generator:\n    \"\"\"Change directory with context manager.\"\"\"\n    old_cwd = os.getcwd()\n    try:\n        os.chdir(path)\n        yield\n        os.chdir(old_cwd)\n    except Exception as e:  # pylint: disable=broad-except  # pragma: nocover\n        os.chdir(old_cwd)\n        raise e from e\n\n\ndef create_symlink(link_path: Path, target_path: Path, root_path: Path) -> int:\n    \"\"\"\n    Change directory and call the cross-platform script.\n\n    The working directory must be the parent of the symbolic link name\n    when executing 'create_symlink_crossplatform.sh'. Hence, we\n    need to translate target_path into the relative path from the\n    symbolic link directory to the target directory.\n\n    So:\n    1) from link_path, extract the number of jumps to the parent directory\n      in order to reach the repository root directory, and chain many \"../\" paths.\n    2) from target_path, compute the relative path to the root\n    3) relative_target_path is just the concatenation of the results from step (1) and (2).\n\n\n    For instance, given\n    - link_path: './directory_1//symbolic_link\n    - target_path: './directory_2/target_path\n\n    we want to compute:\n    - link_path: 'symbolic_link' (just the last bit)\n    - relative_target_path: '../../directory_1/target_path'\n\n    The resulting command on UNIX systems will be:\n\n        cd directory_1 && ln -s ../../directory_1/target_path symbolic_link\n\n    :param link_path: the source path\n    :param target_path: the target path\n    :param root_path: the root path\n    :return: exit code\n    \"\"\"\n    working_directory = link_path.parent\n    target_relative_to_root = target_path.relative_to(root_path)\n    cwd_relative_to_root = working_directory.relative_to(root_path)\n    nb_parents = len(cwd_relative_to_root.parents)\n    root_relative_to_cwd = reduce(\n        lambda x, y: x / y, [Path(\"../\")] * nb_parents, Path(\".\")\n    )\n    link_name = link_path.name\n    target = root_relative_to_cwd / target_relative_to_root\n    with cd(working_directory.absolute()):\n        make_symlink(str(link_name), str(target))\n    return 0\n"
  },
  {
    "path": "aea/helpers/transaction/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains transaction related classes.\"\"\"\n"
  },
  {
    "path": "aea/helpers/transaction/base.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains terms related classes.\"\"\"\n\nimport collections\nimport copy\nfrom typing import Any, Dict, List, Optional, Tuple\n\nfrom aea.common import JSONLike\nfrom aea.crypto.ledger_apis import LedgerApis\nfrom aea.exceptions import enforce\nfrom aea.helpers.serializers import DictProtobufStructSerializer\n\n\nAddress = str\n\n\nclass RawTransaction:\n    \"\"\"This class represents an instance of RawTransaction.\"\"\"\n\n    __slots__ = (\"_ledger_id\", \"_body\")\n\n    def __init__(\n        self,\n        ledger_id: str,\n        body: JSONLike,\n    ) -> None:\n        \"\"\"Initialise an instance of RawTransaction.\"\"\"\n        self._ledger_id = ledger_id\n        self._body = body\n        self._check_consistency()\n\n    def _check_consistency(self) -> None:\n        \"\"\"Check consistency of the object.\"\"\"\n        enforce(isinstance(self._ledger_id, str), \"ledger_id must be str\")\n        enforce(isinstance(self._body, dict), \"body must not be JSONLike\")\n\n    @property\n    def ledger_id(self) -> str:\n        \"\"\"Get the id of the ledger on which the terms are to be settled.\"\"\"\n        return self._ledger_id\n\n    @property\n    def body(self) -> JSONLike:\n        \"\"\"Get the body.\"\"\"\n        return self._body\n\n    @staticmethod\n    def encode(\n        raw_transaction_protobuf_object: Any, raw_transaction_object: \"RawTransaction\"\n    ) -> None:\n        \"\"\"\n        Encode an instance of this class into the protocol buffer object.\n\n        The protocol buffer object in the raw_transaction_protobuf_object argument must be matched with the instance of this class in the 'raw_transaction_object' argument.\n\n        :param raw_transaction_protobuf_object: the protocol buffer object whose type corresponds with this class.\n        :param raw_transaction_object: an instance of this class to be encoded in the protocol buffer object.\n        \"\"\"\n\n        raw_transaction_dict = {\n            \"ledger_id\": raw_transaction_object.ledger_id,\n            \"body\": raw_transaction_object.body,\n        }\n\n        raw_transaction_protobuf_object.raw_transaction = (\n            DictProtobufStructSerializer.encode(raw_transaction_dict)\n        )\n\n    @classmethod\n    def decode(cls, raw_transaction_protobuf_object: Any) -> \"RawTransaction\":\n        \"\"\"\n        Decode a protocol buffer object that corresponds with this class into an instance of this class.\n\n        A new instance of this class must be created that matches the protocol buffer object in the 'raw_transaction_protobuf_object' argument.\n\n        :param raw_transaction_protobuf_object: the protocol buffer object whose type corresponds with this class.\n        :return: A new instance of this class that matches the protocol buffer object in the 'raw_transaction_protobuf_object' argument.\n        \"\"\"\n        raw_transaction_dict = DictProtobufStructSerializer.decode(\n            raw_transaction_protobuf_object.raw_transaction\n        )\n        return cls(raw_transaction_dict[\"ledger_id\"], raw_transaction_dict[\"body\"])\n\n    def __eq__(self, other: Any) -> bool:\n        \"\"\"Check equality.\"\"\"\n        return (\n            isinstance(other, RawTransaction)\n            and self.ledger_id == other.ledger_id\n            and self.body == other.body\n        )\n\n    def __str__(self) -> str:\n        \"\"\"Get string representation.\"\"\"\n        return \"RawTransaction: ledger_id={}, body={}\".format(\n            self.ledger_id,\n            self.body,\n        )\n\n\nclass RawMessage:\n    \"\"\"This class represents an instance of RawMessage.\"\"\"\n\n    __slots__ = (\"_ledger_id\", \"_body\", \"_is_deprecated_mode\")\n\n    def __init__(\n        self,\n        ledger_id: str,\n        body: bytes,\n        is_deprecated_mode: bool = False,\n    ) -> None:\n        \"\"\"Initialise an instance of RawMessage.\"\"\"\n        self._ledger_id = ledger_id\n        self._body = body\n        self._is_deprecated_mode = is_deprecated_mode\n        self._check_consistency()\n\n    def _check_consistency(self) -> None:\n        \"\"\"Check consistency of the object.\"\"\"\n        enforce(isinstance(self._ledger_id, str), \"ledger_id must be str\")\n        enforce(isinstance(self._body, bytes), \"body must not be bytes\")\n        enforce(\n            isinstance(self._is_deprecated_mode, bool),\n            \"is_deprecated_mode must be bool\",\n        )\n\n    @property\n    def ledger_id(self) -> str:\n        \"\"\"Get the id of the ledger on which the terms are to be settled.\"\"\"\n        return self._ledger_id\n\n    @property\n    def body(self) -> bytes:\n        \"\"\"Get the body.\"\"\"\n        return self._body\n\n    @property\n    def is_deprecated_mode(self) -> bool:\n        \"\"\"Get the is_deprecated_mode.\"\"\"\n        return self._is_deprecated_mode\n\n    @staticmethod\n    def encode(\n        raw_message_protobuf_object: Any, raw_message_object: \"RawMessage\"\n    ) -> None:\n        \"\"\"\n        Encode an instance of this class into the protocol buffer object.\n\n        The protocol buffer object in the raw_message_protobuf_object argument must be matched with the instance of this class in the 'raw_message_object' argument.\n\n        :param raw_message_protobuf_object: the protocol buffer object whose type corresponds with this class.\n        :param raw_message_object: an instance of this class to be encoded in the protocol buffer object.\n        \"\"\"\n        raw_message_dict = {\n            \"ledger_id\": raw_message_object.ledger_id,\n            \"body\": raw_message_object.body,\n            \"is_deprecated_mode\": raw_message_object.is_deprecated_mode,\n        }\n\n        raw_message_protobuf_object.raw_message = DictProtobufStructSerializer.encode(\n            raw_message_dict\n        )\n\n    @classmethod\n    def decode(cls, raw_message_protobuf_object: Any) -> \"RawMessage\":\n        \"\"\"\n        Decode a protocol buffer object that corresponds with this class into an instance of this class.\n\n        A new instance of this class must be created that matches the protocol buffer object in the 'raw_message_protobuf_object' argument.\n\n        :param raw_message_protobuf_object: the protocol buffer object whose type corresponds with this class.\n        :return: A new instance of this class that matches the protocol buffer object in the 'raw_message_protobuf_object' argument.\n        \"\"\"\n        raw_message_dict = DictProtobufStructSerializer.decode(\n            raw_message_protobuf_object.raw_message\n        )\n        return cls(\n            raw_message_dict[\"ledger_id\"],\n            raw_message_dict[\"body\"],\n            raw_message_dict[\"is_deprecated_mode\"],\n        )\n\n    def __eq__(self, other: Any) -> bool:\n        \"\"\"Check equality.\"\"\"\n        return (\n            isinstance(other, RawMessage)\n            and self.ledger_id == other.ledger_id\n            and self.body == other.body\n            and self.is_deprecated_mode == other.is_deprecated_mode\n        )\n\n    def __str__(self) -> str:\n        \"\"\"Get string representation.\"\"\"\n        return \"RawMessage: ledger_id={}, body={!r}, is_deprecated_mode={}\".format(\n            self.ledger_id,\n            self.body,\n            self.is_deprecated_mode,\n        )\n\n\nclass SignedTransaction:\n    \"\"\"This class represents an instance of SignedTransaction.\"\"\"\n\n    __slots__ = (\"_ledger_id\", \"_body\")\n\n    def __init__(\n        self,\n        ledger_id: str,\n        body: JSONLike,\n    ) -> None:\n        \"\"\"Initialise an instance of SignedTransaction.\"\"\"\n        self._ledger_id = ledger_id\n        self._body = body\n        self._check_consistency()\n\n    def _check_consistency(self) -> None:\n        \"\"\"Check consistency of the object.\"\"\"\n        enforce(isinstance(self._ledger_id, str), \"ledger_id must be str\")\n        enforce(isinstance(self._body, dict), \"body must not JSONLike\")\n\n    @property\n    def ledger_id(self) -> str:\n        \"\"\"Get the id of the ledger on which the terms are to be settled.\"\"\"\n        return self._ledger_id\n\n    @property\n    def body(self) -> JSONLike:\n        \"\"\"Get the body.\"\"\"\n        return self._body\n\n    @staticmethod\n    def encode(\n        signed_transaction_protobuf_object: Any,\n        signed_transaction_object: \"SignedTransaction\",\n    ) -> None:\n        \"\"\"\n        Encode an instance of this class into the protocol buffer object.\n\n        The protocol buffer object in the signed_transaction_protobuf_object argument must be matched with the instance of this class in the 'signed_transaction_object' argument.\n\n        :param signed_transaction_protobuf_object: the protocol buffer object whose type corresponds with this class.\n        :param signed_transaction_object: an instance of this class to be encoded in the protocol buffer object.\n        \"\"\"\n        signed_transaction_dict = {\n            \"ledger_id\": signed_transaction_object.ledger_id,\n            \"body\": signed_transaction_object.body,\n        }\n\n        signed_transaction_protobuf_object.signed_transaction = (\n            DictProtobufStructSerializer.encode(signed_transaction_dict)\n        )\n\n    @classmethod\n    def decode(cls, signed_transaction_protobuf_object: Any) -> \"SignedTransaction\":\n        \"\"\"\n        Decode a protocol buffer object that corresponds with this class into an instance of this class.\n\n        A new instance of this class must be created that matches the protocol buffer object in the 'signed_transaction_protobuf_object' argument.\n\n        :param signed_transaction_protobuf_object: the protocol buffer object whose type corresponds with this class.\n        :return: A new instance of this class that matches the protocol buffer object in the 'signed_transaction_protobuf_object' argument.\n        \"\"\"\n        signed_transaction_dict = DictProtobufStructSerializer.decode(\n            signed_transaction_protobuf_object.signed_transaction\n        )\n        return cls(\n            signed_transaction_dict[\"ledger_id\"], signed_transaction_dict[\"body\"]\n        )\n\n    def __eq__(self, other: Any) -> bool:\n        \"\"\"Check equality.\"\"\"\n        return (\n            isinstance(other, SignedTransaction)\n            and self.ledger_id == other.ledger_id\n            and self.body == other.body\n        )\n\n    def __str__(self) -> str:\n        \"\"\"Get string representation.\"\"\"\n        return \"SignedTransaction: ledger_id={}, body={}\".format(\n            self.ledger_id,\n            self.body,\n        )\n\n\nclass SignedMessage:\n    \"\"\"This class represents an instance of RawMessage.\"\"\"\n\n    __slots__ = (\"_ledger_id\", \"_body\", \"_is_deprecated_mode\")\n\n    def __init__(\n        self,\n        ledger_id: str,\n        body: str,\n        is_deprecated_mode: bool = False,\n    ) -> None:\n        \"\"\"Initialise an instance of SignedMessage.\"\"\"\n        self._ledger_id = ledger_id\n        self._body = body\n        self._is_deprecated_mode = is_deprecated_mode\n        self._check_consistency()\n\n    def _check_consistency(self) -> None:\n        \"\"\"Check consistency of the object.\"\"\"\n        enforce(isinstance(self._ledger_id, str), \"ledger_id must be str\")\n        enforce(isinstance(self._body, str), \"body must be string\")\n        enforce(\n            isinstance(self._is_deprecated_mode, bool),\n            \"is_deprecated_mode must be bool\",\n        )\n\n    @property\n    def ledger_id(self) -> str:\n        \"\"\"Get the id of the ledger on which the terms are to be settled.\"\"\"\n        return self._ledger_id\n\n    @property\n    def body(self) -> str:\n        \"\"\"Get the body.\"\"\"\n        return self._body\n\n    @property\n    def is_deprecated_mode(self) -> bool:\n        \"\"\"Get the is_deprecated_mode.\"\"\"\n        return self._is_deprecated_mode\n\n    @staticmethod\n    def encode(\n        signed_message_protobuf_object: Any, signed_message_object: \"SignedMessage\"\n    ) -> None:\n        \"\"\"\n        Encode an instance of this class into the protocol buffer object.\n\n        The protocol buffer object in the signed_message_protobuf_object argument must be matched with the instance of this class in the 'signed_message_object' argument.\n\n        :param signed_message_protobuf_object: the protocol buffer object whose type corresponds with this class.\n        :param signed_message_object: an instance of this class to be encoded in the protocol buffer object.\n        \"\"\"\n        signed_message_dict = {\n            \"ledger_id\": signed_message_object.ledger_id,\n            \"body\": signed_message_object.body,\n            \"is_deprecated_mode\": signed_message_object.is_deprecated_mode,\n        }\n\n        signed_message_protobuf_object.signed_message = (\n            DictProtobufStructSerializer.encode(signed_message_dict)\n        )\n\n    @classmethod\n    def decode(cls, signed_message_protobuf_object: Any) -> \"SignedMessage\":\n        \"\"\"\n        Decode a protocol buffer object that corresponds with this class into an instance of this class.\n\n        A new instance of this class must be created that matches the protocol buffer object in the 'signed_message_protobuf_object' argument.\n\n        :param signed_message_protobuf_object: the protocol buffer object whose type corresponds with this class.\n        :return: A new instance of this class that matches the protocol buffer object in the 'signed_message_protobuf_object' argument.\n        \"\"\"\n        signed_message_dict = DictProtobufStructSerializer.decode(\n            signed_message_protobuf_object.signed_message\n        )\n        return cls(\n            signed_message_dict[\"ledger_id\"],\n            signed_message_dict[\"body\"],\n            signed_message_dict[\"is_deprecated_mode\"],\n        )\n\n    def __eq__(self, other: Any) -> bool:\n        \"\"\"Check equality.\"\"\"\n        return (\n            isinstance(other, SignedMessage)\n            and self.ledger_id == other.ledger_id\n            and self.body == other.body\n            and self.is_deprecated_mode == other.is_deprecated_mode\n        )\n\n    def __str__(self) -> str:\n        \"\"\"Get string representation.\"\"\"\n        return \"SignedMessage: ledger_id={}, body={}, is_deprecated_mode={}\".format(\n            self.ledger_id,\n            self.body,\n            self.is_deprecated_mode,\n        )\n\n\nclass State:\n    \"\"\"This class represents an instance of State.\"\"\"\n\n    __slots__ = (\"_ledger_id\", \"_body\")\n\n    def __init__(self, ledger_id: str, body: JSONLike) -> None:\n        \"\"\"Initialise an instance of State.\"\"\"\n        self._ledger_id = ledger_id\n        self._body = body\n        self._check_consistency()\n\n    def _check_consistency(self) -> None:\n        \"\"\"Check consistency of the object.\"\"\"\n        enforce(isinstance(self._ledger_id, str), \"ledger_id must be str\")\n        enforce(isinstance(self._body, dict), \"body must be dict\")\n\n    @property\n    def ledger_id(self) -> str:\n        \"\"\"Get the id of the ledger on which the terms are to be settled.\"\"\"\n        return self._ledger_id\n\n    @property\n    def body(self) -> JSONLike:\n        \"\"\"Get the body.\"\"\"\n        return self._body\n\n    @staticmethod\n    def encode(state_protobuf_object: Any, state_object: \"State\") -> None:\n        \"\"\"\n        Encode an instance of this class into the protocol buffer object.\n\n        The protocol buffer object in the state_protobuf_object argument must be matched with the instance of this class in the 'state_object' argument.\n\n        :param state_protobuf_object: the protocol buffer object whose type corresponds with this class.\n        :param state_object: an instance of this class to be encoded in the protocol buffer object.\n        \"\"\"\n        state_dict = {\n            \"ledger_id\": state_object.ledger_id,\n            \"body\": state_object.body,\n        }\n\n        state_protobuf_object.state = DictProtobufStructSerializer.encode(state_dict)\n\n    @classmethod\n    def decode(cls, state_protobuf_object: Any) -> \"State\":\n        \"\"\"\n        Decode a protocol buffer object that corresponds with this class into an instance of this class.\n\n        A new instance of this class must be created that matches the protocol buffer object in the 'state_protobuf_object' argument.\n\n        :param state_protobuf_object: the protocol buffer object whose type corresponds with this class.\n        :return: A new instance of this class that matches the protocol buffer object in the 'state_protobuf_object' argument.\n        \"\"\"\n        state_dict = DictProtobufStructSerializer.decode(state_protobuf_object.state)\n        return cls(state_dict[\"ledger_id\"], state_dict[\"body\"])\n\n    def __eq__(self, other: Any) -> bool:\n        \"\"\"Check equality.\"\"\"\n        return (\n            isinstance(other, State)\n            and self.ledger_id == other.ledger_id\n            and self.body == other.body\n        )\n\n    def __str__(self) -> str:\n        \"\"\"Get string representation.\"\"\"\n        return \"State: ledger_id={}, body={}\".format(self.ledger_id, self.body)\n\n\nclass Terms:\n    \"\"\"Class to represent the terms of a multi-currency & multi-token ledger transaction.\"\"\"\n\n    __slots__ = (\n        \"_ledger_id\",\n        \"_sender_address\",\n        \"_counterparty_address\",\n        \"_amount_by_currency_id\",\n        \"_quantities_by_good_id\",\n        \"_is_sender_payable_tx_fee\",\n        \"_nonce\",\n        \"_fee_by_currency_id\",\n        \"_is_strict\",\n        \"_kwargs\",\n        \"_good_ids\",\n        \"_sender_supplied_quantities\",\n        \"_counterparty_supplied_quantities\",\n        \"_sender_hash\",\n        \"_counterparty_hash\",\n    )\n\n    def __init__(\n        self,\n        ledger_id: str,\n        sender_address: Address,\n        counterparty_address: Address,\n        amount_by_currency_id: Dict[str, int],\n        quantities_by_good_id: Dict[str, int],\n        nonce: str,\n        is_sender_payable_tx_fee: bool = True,\n        fee_by_currency_id: Optional[Dict[str, int]] = None,\n        is_strict: bool = False,\n        **kwargs: Any,\n    ) -> None:\n        \"\"\"\n        Instantiate terms of a transaction.\n\n        :param ledger_id: the ledger on which the terms are to be settled.\n        :param sender_address: the sender address of the transaction.\n        :param counterparty_address: the counterparty address of the transaction.\n        :param amount_by_currency_id: the amount by the currency of the transaction.\n        :param quantities_by_good_id: a map from good id to the quantity of that good involved in the transaction.\n        :param nonce: nonce to be included in transaction to discriminate otherwise identical transactions.\n        :param is_sender_payable_tx_fee: whether the sender or counterparty pays the tx fee.\n        :param fee_by_currency_id: the fee associated with the transaction.\n        :param is_strict: whether or not terms must have quantities and amounts of opposite signs.\n        :param kwargs: keyword arguments\n        \"\"\"\n        self._ledger_id = ledger_id\n        self._sender_address = sender_address\n        self._counterparty_address = counterparty_address\n        self._amount_by_currency_id = amount_by_currency_id\n        self._quantities_by_good_id = quantities_by_good_id\n        self._is_sender_payable_tx_fee = is_sender_payable_tx_fee\n        self._nonce = nonce\n        self._fee_by_currency_id = (\n            fee_by_currency_id if fee_by_currency_id is not None else {}\n        )\n        self._is_strict = is_strict\n        self._kwargs = kwargs if kwargs is not None else {}\n        self._check_consistency()\n        (\n            good_ids,\n            sender_supplied_quantities,\n            counterparty_supplied_quantities,\n        ) = self._get_lists()\n        self._good_ids = good_ids\n        self._sender_supplied_quantities = sender_supplied_quantities\n        self._counterparty_supplied_quantities = counterparty_supplied_quantities\n        self._sender_hash = self.get_hash(\n            self.ledger_id,\n            sender_address=self.sender_address,\n            counterparty_address=self.counterparty_address,\n            good_ids=self.good_ids,\n            sender_supplied_quantities=self.sender_supplied_quantities,\n            counterparty_supplied_quantities=self.counterparty_supplied_quantities,\n            sender_payable_amount=self.sender_payable_amount,\n            counterparty_payable_amount=self.counterparty_payable_amount,\n            nonce=self.nonce,\n        )\n        self._counterparty_hash = self.get_hash(\n            self.ledger_id,\n            sender_address=self.counterparty_address,\n            counterparty_address=self.sender_address,\n            good_ids=self.good_ids,\n            sender_supplied_quantities=self.counterparty_supplied_quantities,\n            counterparty_supplied_quantities=self.sender_supplied_quantities,\n            sender_payable_amount=self.counterparty_payable_amount,\n            counterparty_payable_amount=self.sender_payable_amount,\n            nonce=self.nonce,\n        )\n\n    def _check_consistency(self) -> None:\n        \"\"\"Check consistency of the object.\"\"\"\n        enforce(isinstance(self._ledger_id, str), \"ledger_id must be str\")\n        enforce(isinstance(self._sender_address, str), \"sender_address must be str\")\n        enforce(\n            isinstance(self._counterparty_address, str),\n            \"counterparty_address must be str\",\n        )\n        enforce(\n            isinstance(self._amount_by_currency_id, dict)\n            and all(\n                (\n                    isinstance(key, str) and isinstance(value, int)\n                    for key, value in self._amount_by_currency_id.items()\n                )\n            ),\n            \"amount_by_currency_id must be a dictionary with str keys and int values.\",\n        )\n        enforce(\n            isinstance(self._quantities_by_good_id, dict)\n            and all(\n                (\n                    isinstance(key, str) and isinstance(value, int)\n                    for key, value in self._quantities_by_good_id.items()\n                )\n            ),\n            \"quantities_by_good_id must be a dictionary with str keys and int values.\",\n        )\n        enforce(\n            isinstance(self._is_sender_payable_tx_fee, bool),\n            \"is_sender_payable_tx_fee must be bool\",\n        )\n        enforce(isinstance(self._nonce, str), \"nonce must be str\")\n        enforce(\n            self._fee_by_currency_id is None\n            or (\n                isinstance(self._fee_by_currency_id, dict)\n                and all(\n                    (\n                        isinstance(key, str) and isinstance(value, int) and value >= 0\n                        for key, value in self._fee_by_currency_id.items()\n                    )\n                )\n            ),\n            \"fee must be None or Dict[str, int] with positive fees only.\",\n        )\n        enforce(\n            all(\n                (\n                    key in self._amount_by_currency_id\n                    for key in self._fee_by_currency_id.keys()\n                )\n            ),\n            \"Fee dictionary has keys which are not present in amount dictionary.\",\n        )\n        if self._is_strict:\n            is_pos_amounts = all(\n                (amount >= 0 for amount in self._amount_by_currency_id.values())\n            )\n            is_neg_amounts = all(\n                (amount <= 0 for amount in self._amount_by_currency_id.values())\n            )\n            is_pos_quantities = all(\n                (quantity >= 0 for quantity in self._quantities_by_good_id.values())\n            )\n            is_neg_quantities = all(\n                (quantity <= 0 for quantity in self._quantities_by_good_id.values())\n            )\n            enforce(\n                (is_pos_amounts and is_neg_quantities)\n                or (is_neg_amounts and is_pos_quantities),\n                \"quantities and amounts do not constitute valid terms. All quantities must be of same sign. All amounts must be of same sign. Quantities and amounts must be of different sign.\",\n            )\n\n    @property\n    def id(self) -> str:\n        \"\"\"Get hash of the terms.\"\"\"\n        return self.sender_hash\n\n    @property\n    def sender_hash(self) -> str:\n        \"\"\"Get the sender hash.\"\"\"\n        return self._sender_hash\n\n    @property\n    def counterparty_hash(self) -> str:\n        \"\"\"Get the sender hash.\"\"\"\n        return self._counterparty_hash\n\n    @property\n    def ledger_id(self) -> str:\n        \"\"\"Get the id of the ledger on which the terms are to be settled.\"\"\"\n        return self._ledger_id\n\n    @property\n    def sender_address(self) -> Address:\n        \"\"\"Get the sender address.\"\"\"\n        return self._sender_address\n\n    @property\n    def counterparty_address(self) -> Address:\n        \"\"\"Get the counterparty address.\"\"\"\n        return self._counterparty_address\n\n    @counterparty_address.setter\n    def counterparty_address(self, counterparty_address: Address) -> None:\n        \"\"\"Set the counterparty address.\"\"\"\n        enforce(\n            isinstance(counterparty_address, str), \"counterparty_address must be str\"\n        )\n        self._counterparty_address = counterparty_address\n\n    @property\n    def amount_by_currency_id(self) -> Dict[str, int]:\n        \"\"\"Get the amount by currency id.\"\"\"\n        return copy.copy(self._amount_by_currency_id)\n\n    @property\n    def is_sender_payable_tx_fee(self) -> bool:\n        \"\"\"Bool indicating whether the tx fee is paid by sender or counterparty.\"\"\"\n        return self._is_sender_payable_tx_fee\n\n    @property\n    def is_single_currency(self) -> bool:\n        \"\"\"Check whether a single currency is used for payment.\"\"\"\n        return (\n            len(self._amount_by_currency_id) == 1 and len(self._fee_by_currency_id) <= 1\n        )\n\n    @property\n    def is_empty_currency(self) -> bool:\n        \"\"\"Check whether a single currency is used for payment.\"\"\"\n        return len(self._amount_by_currency_id) == 0\n\n    @property\n    def currency_id(self) -> str:\n        \"\"\"Get the amount the sender must pay.\"\"\"\n        enforce(self.is_single_currency, \"More than one currency id, cannot get id.\")\n        value = next(iter(self._amount_by_currency_id.keys()))\n        return value\n\n    @property\n    def sender_payable_amount(self) -> int:\n        \"\"\"Get the amount the sender must pay.\"\"\"\n        enforce(\n            self.is_single_currency or self.is_empty_currency,\n            \"More than one currency id, cannot get amount.\",\n        )\n        value = (\n            next(iter(self._amount_by_currency_id.values()))\n            if not self.is_empty_currency\n            else 0\n        )\n        payable = -value if value <= 0 else 0\n        return payable\n\n    @property\n    def sender_payable_amount_incl_fee(self) -> int:\n        \"\"\"Get the amount the sender must pay inclusive fee.\"\"\"\n        enforce(\n            self.is_single_currency or self.is_empty_currency,\n            \"More than one currency id, cannot get amount.\",\n        )\n        payable = self.sender_payable_amount\n        if self.is_sender_payable_tx_fee and len(self._fee_by_currency_id) == 1:\n            payable += next(iter(self._fee_by_currency_id.values()))\n        return payable\n\n    @property\n    def counterparty_payable_amount(self) -> int:\n        \"\"\"Get the amount the counterparty must pay.\"\"\"\n        enforce(\n            self.is_single_currency or self.is_empty_currency,\n            \"More than one currency id, cannot get amount.\",\n        )\n        value = (\n            next(iter(self._amount_by_currency_id.values()))\n            if not self.is_empty_currency\n            else 0\n        )\n        payable = value if value >= 0 else 0\n        return payable\n\n    @property\n    def counterparty_payable_amount_incl_fee(self) -> int:\n        \"\"\"Get the amount the counterparty must pay.\"\"\"\n        enforce(\n            self.is_single_currency or self.is_empty_currency,\n            \"More than one currency id, cannot get amount.\",\n        )\n        payable = self.counterparty_payable_amount\n        if not self.is_sender_payable_tx_fee and len(self._fee_by_currency_id) == 1:\n            payable += next(iter(self._fee_by_currency_id.values()))\n        return payable\n\n    @property\n    def quantities_by_good_id(self) -> Dict[str, int]:\n        \"\"\"Get the quantities by good id.\"\"\"\n        return copy.copy(self._quantities_by_good_id)\n\n    @property\n    def good_ids(self) -> List[str]:\n        \"\"\"Get the (ordered) good ids.\"\"\"\n        return self._good_ids\n\n    @property\n    def sender_supplied_quantities(self) -> List[int]:\n        \"\"\"Get the (ordered) quantities supplied by the sender.\"\"\"\n        return self._sender_supplied_quantities\n\n    @property\n    def counterparty_supplied_quantities(self) -> List[int]:\n        \"\"\"Get the (ordered) quantities supplied by the counterparty.\"\"\"\n        return self._counterparty_supplied_quantities\n\n    @property\n    def nonce(self) -> str:\n        \"\"\"Get the nonce.\"\"\"\n        return self._nonce\n\n    @property\n    def has_fee(self) -> bool:\n        \"\"\"Check if fee is set.\"\"\"\n        return self.fee_by_currency_id != {}\n\n    @property\n    def fee(self) -> int:\n        \"\"\"Get the fee.\"\"\"\n        enforce(self.has_fee, \"fee_by_currency_id not set.\")\n        enforce(\n            len(self.fee_by_currency_id) == 1,\n            \"More than one currency id, cannot get fee.\",\n        )\n        return next(iter(self._fee_by_currency_id.values()))\n\n    @property\n    def sender_fee(self) -> int:\n        \"\"\"Get the sender fee.\"\"\"\n        value = self.fee if self.is_sender_payable_tx_fee else 0\n        return value\n\n    @property\n    def counterparty_fee(self) -> int:\n        \"\"\"Get the counterparty fee.\"\"\"\n        value = 0 if self.is_sender_payable_tx_fee else self.fee\n        return value\n\n    @property\n    def fee_by_currency_id(self) -> Dict[str, int]:\n        \"\"\"Get fee by currency.\"\"\"\n        return copy.copy(self._fee_by_currency_id)\n\n    @property\n    def kwargs(self) -> JSONLike:\n        \"\"\"Get the kwargs.\"\"\"\n        return self._kwargs\n\n    @property\n    def is_strict(self) -> bool:\n        \"\"\"Get is_strict.\"\"\"\n        return self._is_strict\n\n    def _get_lists(self) -> Tuple[List[str], List[int], List[int]]:\n        ordered = collections.OrderedDict(sorted(self.quantities_by_good_id.items()))\n        good_ids = []  # type: List[str]\n        sender_supplied_quantities = []  # type: List[int]\n        counterparty_supplied_quantities = []  # type: List[int]\n        for good_id, quantity in ordered.items():\n            good_ids.append(good_id)\n            if quantity >= 0:\n                sender_supplied_quantities.append(quantity)\n                counterparty_supplied_quantities.append(0)\n            else:\n                sender_supplied_quantities.append(0)\n                counterparty_supplied_quantities.append(-quantity)\n        return good_ids, sender_supplied_quantities, counterparty_supplied_quantities\n\n    @staticmethod\n    def get_hash(\n        ledger_id: str,\n        sender_address: str,\n        counterparty_address: str,\n        good_ids: List[str],\n        sender_supplied_quantities: List[int],\n        counterparty_supplied_quantities: List[int],\n        sender_payable_amount: int,\n        counterparty_payable_amount: int,\n        nonce: str,\n    ) -> str:\n        \"\"\"\n        Generate a hash from transaction information.\n\n        :param ledger_id: the ledger id\n        :param sender_address: the sender address\n        :param counterparty_address: the counterparty address\n        :param good_ids: the list of good ids\n        :param sender_supplied_quantities: the quantities supplied by the sender (must all be positive)\n        :param counterparty_supplied_quantities: the quantities supplied by the counterparty (must all be positive)\n        :param sender_payable_amount: the amount payable by the sender\n        :param counterparty_payable_amount: the amount payable by the counterparty\n        :param nonce: the nonce of the transaction\n        :return: the hash\n        \"\"\"\n        if len(good_ids) == 0:\n            aggregate_hash = LedgerApis.get_hash(ledger_id, b\"\")\n        else:\n            aggregate_hash = LedgerApis.get_hash(\n                ledger_id,\n                b\"\".join(\n                    [\n                        good_ids[0].encode(\"utf-8\"),\n                        sender_supplied_quantities[0].to_bytes(32, \"big\"),\n                        counterparty_supplied_quantities[0].to_bytes(32, \"big\"),\n                    ]\n                ),\n            )\n        for idx, good_id in enumerate(good_ids):\n            if idx == 0:\n                continue\n            aggregate_hash = LedgerApis.get_hash(\n                ledger_id,\n                b\"\".join(\n                    [\n                        aggregate_hash.encode(\"utf-8\"),\n                        good_id.encode(\"utf-8\"),\n                        sender_supplied_quantities[idx].to_bytes(32, \"big\"),\n                        counterparty_supplied_quantities[idx].to_bytes(32, \"big\"),\n                    ]\n                ),\n            )\n\n        m_list = []  # type: List[bytes]\n        m_list.append(sender_address.encode(\"utf-8\"))\n        m_list.append(counterparty_address.encode(\"utf-8\"))\n        m_list.append(aggregate_hash.encode(\"utf-8\"))\n        m_list.append(sender_payable_amount.to_bytes(32, \"big\"))\n        m_list.append(counterparty_payable_amount.to_bytes(32, \"big\"))\n        m_list.append(nonce.encode(\"utf-8\"))\n        digest = LedgerApis.get_hash(ledger_id, b\"\".join(m_list))\n        return digest\n\n    @staticmethod\n    def encode(terms_protobuf_object: Any, terms_object: \"Terms\") -> None:\n        \"\"\"\n        Encode an instance of this class into the protocol buffer object.\n\n        The protocol buffer object in the terms_protobuf_object argument must be matched with the instance of this class in the 'terms_object' argument.\n\n        :param terms_protobuf_object: the protocol buffer object whose type corresponds with this class.\n        :param terms_object: an instance of this class to be encoded in the protocol buffer object.\n        \"\"\"\n        terms_dict = {\n            \"ledger_id\": terms_object.ledger_id,\n            \"sender_address\": terms_object.sender_address,\n            \"counterparty_address\": terms_object.counterparty_address,\n            \"amount_by_currency_id\": terms_object.amount_by_currency_id,\n            \"quantities_by_good_id\": terms_object.quantities_by_good_id,\n            \"nonce\": terms_object.nonce,\n            \"is_sender_payable_tx_fee\": terms_object.is_sender_payable_tx_fee,\n            \"fee_by_currency_id\": terms_object.fee_by_currency_id,\n            \"is_strict\": terms_object.is_strict,\n            \"kwargs\": terms_object.kwargs,\n        }\n        terms_protobuf_object.terms = DictProtobufStructSerializer.encode(terms_dict)\n\n    @classmethod\n    def decode(cls, terms_protobuf_object: Any) -> \"Terms\":\n        \"\"\"\n        Decode a protocol buffer object that corresponds with this class into an instance of this class.\n\n        A new instance of this class must be created that matches the protocol buffer object in the 'terms_protobuf_object' argument.\n\n        :param terms_protobuf_object: the protocol buffer object whose type corresponds with this class.\n        :return: A new instance of this class that matches the protocol buffer object in the 'terms_protobuf_object' argument.\n        \"\"\"\n        terms_dict = DictProtobufStructSerializer.decode(terms_protobuf_object.terms)\n\n        return cls(\n            terms_dict[\"ledger_id\"],\n            terms_dict[\"sender_address\"],\n            terms_dict[\"counterparty_address\"],\n            terms_dict[\"amount_by_currency_id\"],\n            terms_dict[\"quantities_by_good_id\"],\n            terms_dict[\"nonce\"],\n            terms_dict[\"is_sender_payable_tx_fee\"],\n            dict(terms_dict[\"fee_by_currency_id\"]),\n            terms_dict[\"is_strict\"],\n            **dict(terms_dict[\"kwargs\"]),\n        )\n\n    def __eq__(self, other: Any) -> bool:\n        \"\"\"Check equality.\"\"\"\n        return (\n            isinstance(other, Terms)\n            and self.ledger_id == other.ledger_id\n            and self.sender_address == other.sender_address\n            and self.counterparty_address == other.counterparty_address\n            and self.amount_by_currency_id == other.amount_by_currency_id\n            and self.quantities_by_good_id == other.quantities_by_good_id\n            and self.is_sender_payable_tx_fee == other.is_sender_payable_tx_fee\n            and self.nonce == other.nonce\n            and self.kwargs == other.kwargs\n            and self.fee == other.fee\n            if (self.has_fee and other.has_fee)\n            else self.has_fee == other.has_fee\n        )\n\n    def __str__(self) -> str:\n        \"\"\"Get string representation.\"\"\"\n        return \"Terms: ledger_id={}, sender_address={}, counterparty_address={}, amount_by_currency_id={}, quantities_by_good_id={}, is_sender_payable_tx_fee={}, nonce={}, fee_by_currency_id={}, kwargs={}\".format(\n            self.ledger_id,\n            self.sender_address,\n            self.counterparty_address,\n            self.amount_by_currency_id,\n            self.quantities_by_good_id,\n            self.is_sender_payable_tx_fee,\n            self.nonce,\n            self._fee_by_currency_id,\n            self.kwargs,\n        )\n\n\nclass TransactionDigest:\n    \"\"\"This class represents an instance of TransactionDigest.\"\"\"\n\n    __slots__ = (\"_ledger_id\", \"_body\")\n\n    def __init__(self, ledger_id: str, body: str) -> None:\n        \"\"\"Initialise an instance of TransactionDigest.\"\"\"\n        self._ledger_id = ledger_id\n        self._body = body\n        self._check_consistency()\n\n    def _check_consistency(self) -> None:\n        \"\"\"Check consistency of the object.\"\"\"\n        enforce(isinstance(self._ledger_id, str), \"ledger_id must be str\")\n        enforce(isinstance(self._body, str), \"body must not be None\")\n\n    @property\n    def ledger_id(self) -> str:\n        \"\"\"Get the id of the ledger on which the terms are to be settled.\"\"\"\n        return self._ledger_id\n\n    @property\n    def body(self) -> str:\n        \"\"\"Get the receipt.\"\"\"\n        return self._body\n\n    @staticmethod\n    def encode(\n        transaction_digest_protobuf_object: Any,\n        transaction_digest_object: \"TransactionDigest\",\n    ) -> None:\n        \"\"\"\n        Encode an instance of this class into the protocol buffer object.\n\n        The protocol buffer object in the transaction_digest_protobuf_object argument must be matched with the instance of this class in the 'transaction_digest_object' argument.\n\n        :param transaction_digest_protobuf_object: the protocol buffer object whose type corresponds with this class.\n        :param transaction_digest_object: an instance of this class to be encoded in the protocol buffer object.\n        \"\"\"\n        transaction_digest_dict = {\n            \"ledger_id\": transaction_digest_object.ledger_id,\n            \"body\": transaction_digest_object.body,\n        }\n\n        transaction_digest_protobuf_object.transaction_digest = (\n            DictProtobufStructSerializer.encode(transaction_digest_dict)\n        )\n\n    @classmethod\n    def decode(cls, transaction_digest_protobuf_object: Any) -> \"TransactionDigest\":\n        \"\"\"\n        Decode a protocol buffer object that corresponds with this class into an instance of this class.\n\n        A new instance of this class must be created that matches the protocol buffer object in the 'transaction_digest_protobuf_object' argument.\n\n        :param transaction_digest_protobuf_object: the protocol buffer object whose type corresponds with this class.\n        :return: A new instance of this class that matches the protocol buffer object in the 'transaction_digest_protobuf_object' argument.\n        \"\"\"\n        transaction_digest_dict = DictProtobufStructSerializer.decode(\n            transaction_digest_protobuf_object.transaction_digest\n        )\n\n        return cls(\n            transaction_digest_dict[\"ledger_id\"], transaction_digest_dict[\"body\"]\n        )\n\n    def __eq__(self, other: Any) -> bool:\n        \"\"\"Check equality.\"\"\"\n        return (\n            isinstance(other, TransactionDigest)\n            and self.ledger_id == other.ledger_id\n            and self.body == other.body\n        )\n\n    def __str__(self) -> str:\n        \"\"\"Get string representation.\"\"\"\n        return \"TransactionDigest: ledger_id={}, body={}\".format(\n            self.ledger_id, self.body\n        )\n\n\nclass TransactionReceipt:\n    \"\"\"This class represents an instance of TransactionReceipt.\"\"\"\n\n    __slots__ = (\"_ledger_id\", \"_receipt\", \"_transaction\")\n\n    def __init__(\n        self, ledger_id: str, receipt: JSONLike, transaction: JSONLike\n    ) -> None:\n        \"\"\"Initialise an instance of TransactionReceipt.\"\"\"\n        self._ledger_id = ledger_id\n        self._receipt = receipt\n        self._transaction = transaction\n        self._check_consistency()\n\n    def _check_consistency(self) -> None:\n        \"\"\"Check consistency of the object.\"\"\"\n        enforce(isinstance(self._ledger_id, str), \"ledger_id must be str\")\n        enforce(isinstance(self._receipt, dict), \"receipt must be dict\")\n        enforce(isinstance(self._transaction, dict), \"transaction must be dict\")\n\n    @property\n    def ledger_id(self) -> str:\n        \"\"\"Get the id of the ledger on which the terms are to be settled.\"\"\"\n        return self._ledger_id\n\n    @property\n    def receipt(self) -> JSONLike:\n        \"\"\"Get the receipt.\"\"\"\n        return self._receipt\n\n    @property\n    def transaction(self) -> JSONLike:\n        \"\"\"Get the transaction.\"\"\"\n        return self._transaction\n\n    @staticmethod\n    def encode(\n        transaction_receipt_protobuf_object: Any,\n        transaction_receipt_object: \"TransactionReceipt\",\n    ) -> None:\n        \"\"\"\n        Encode an instance of this class into the protocol buffer object.\n\n        The protocol buffer object in the transaction_receipt_protobuf_object argument must be matched with the instance of this class in the 'transaction_receipt_object' argument.\n\n        :param transaction_receipt_protobuf_object: the protocol buffer object whose type corresponds with this class.\n        :param transaction_receipt_object: an instance of this class to be encoded in the protocol buffer object.\n        \"\"\"\n        transaction_receipt_dict = {\n            \"ledger_id\": transaction_receipt_object.ledger_id,\n            \"receipt\": transaction_receipt_object.receipt,\n            \"transaction\": transaction_receipt_object.transaction,\n        }\n\n        transaction_receipt_protobuf_object.transaction_receipt = (\n            DictProtobufStructSerializer.encode(transaction_receipt_dict)\n        )\n\n    @classmethod\n    def decode(cls, transaction_receipt_protobuf_object: Any) -> \"TransactionReceipt\":\n        \"\"\"\n        Decode a protocol buffer object that corresponds with this class into an instance of this class.\n\n        A new instance of this class must be created that matches the protocol buffer object in the 'transaction_receipt_protobuf_object' argument.\n\n        :param transaction_receipt_protobuf_object: the protocol buffer object whose type corresponds with this class.\n        :return: A new instance of this class that matches the protocol buffer object in the 'transaction_receipt_protobuf_object' argument.\n        \"\"\"\n        transaction_receipt_dict = DictProtobufStructSerializer.decode(\n            transaction_receipt_protobuf_object.transaction_receipt\n        )\n        return cls(\n            transaction_receipt_dict[\"ledger_id\"],\n            transaction_receipt_dict[\"receipt\"],\n            transaction_receipt_dict[\"transaction\"],\n        )\n\n    def __eq__(self, other: Any) -> bool:\n        \"\"\"Check equality.\"\"\"\n        return (\n            isinstance(other, TransactionReceipt)\n            and self.ledger_id == other.ledger_id\n            and self.receipt == other.receipt\n            and self.transaction == other.transaction\n        )\n\n    def __str__(self) -> str:\n        \"\"\"Get string representation.\"\"\"\n        return \"TransactionReceipt: ledger_id={}, receipt={}, transaction={}\".format(\n            self.ledger_id, self.receipt, self.transaction\n        )\n"
  },
  {
    "path": "aea/helpers/win32.py",
    "content": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Helpers for Windows.\"\"\"\nimport ctypes\nimport logging\nimport platform\n\n\n_default_logger = logging.getLogger(__name__)\n\n\ndef enable_ctrl_c_support() -> None:  # pragma: no cover\n    \"\"\"Enable ctrl+c support for aea.cli command to be tested on windows platform.\"\"\"\n    if platform.system() != \"Windows\":\n        return\n\n    kernel32 = ctypes.WinDLL(\"kernel32\", use_last_error=True)  # type: ignore\n\n    if not kernel32.SetConsoleCtrlHandler(None, False):\n        _default_logger.debug(f\"SetConsoleCtrlHandler Error: {ctypes.get_last_error()}\")  # type: ignore\n"
  },
  {
    "path": "aea/helpers/yaml_utils.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Helper functions related to YAML loading/dumping.\"\"\"\nfrom collections import OrderedDict\nfrom typing import Any, Dict, List, Optional, Sequence, TextIO\n\nimport yaml\nfrom yaml import MappingNode\n\n\nclass _AEAYamlLoader(yaml.SafeLoader):\n    \"\"\"\n    Custom yaml.SafeLoader for the AEA framework.\n\n    It extends the default SafeLoader in two ways:\n    - loads YAML configurations while *remembering the order of the fields*;\n    - resolves the environment variables at loading time.\n\n    This class is for internal usage only; please use\n    the public functions of the module 'yaml_load' and 'yaml_load_all'.\n    \"\"\"\n\n    def __init__(self, *args: Any, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize the AEAYamlLoader.\n\n        It adds a YAML Loader constructor to use 'OderedDict' to load the files.\n\n        :param args: the positional arguments.\n        :param kwargs: the keyword arguments.\n        \"\"\"\n        super().__init__(*args, **kwargs)\n        _AEAYamlLoader.add_constructor(\n            yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG, self._construct_mapping\n        )\n\n    @staticmethod\n    def _construct_mapping(loader: \"_AEAYamlLoader\", node: MappingNode) -> OrderedDict:\n        \"\"\"Construct a YAML mapping with OrderedDict.\"\"\"\n        object_pairs_hook = OrderedDict\n        loader.flatten_mapping(node)\n        return object_pairs_hook(loader.construct_pairs(node))\n\n\nclass _AEAYamlDumper(yaml.SafeDumper):\n    \"\"\"\n    Custom yaml.SafeDumper for the AEA framework.\n\n    It extends the default SafeDumper so to dump\n    YAML configurations while *following the order of the fields*.\n\n    This class is for internal usage only; please use\n    the public functions of the module 'yaml_dump' and 'yaml_dump_all'.\n    \"\"\"\n\n    def __init__(self, *args: Any, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize the AEAYamlDumper.\n\n        It adds a YAML Dumper representer to use 'OderedDict' to dump the files.\n\n        :param args: the positional arguments.\n        :param kwargs: the keyword arguments.\n        \"\"\"\n        super().__init__(*args, **kwargs)\n        _AEAYamlDumper.add_representer(OrderedDict, self._dict_representer)\n\n    @staticmethod\n    def _dict_representer(dumper: \"_AEAYamlDumper\", data: OrderedDict) -> MappingNode:\n        \"\"\"Use a custom representer.\"\"\"\n        return dumper.represent_mapping(\n            yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG, data.items()\n        )\n\n\ndef yaml_load(stream: TextIO) -> Dict[str, Any]:\n    \"\"\"\n    Load a yaml from a file pointer in an ordered way.\n\n    :param stream: file pointer to the input file.\n    :return: the dictionary object with the YAML file content.\n    \"\"\"\n    result = yaml.load(stream, Loader=_AEAYamlLoader)  # nosec\n    return result if result is not None else {}\n\n\ndef yaml_load_all(stream: TextIO) -> List[Dict[str, Any]]:\n    \"\"\"\n    Load a multi-paged yaml from a file pointer in an ordered way.\n\n    :param stream: file pointer to the input file.\n    :return: the list of dictionary objects with the (multi-paged) YAML file content.\n    \"\"\"\n    return list(yaml.load_all(stream, Loader=_AEAYamlLoader))  # nosec\n\n\ndef yaml_dump(data: Dict, stream: Optional[TextIO] = None) -> None:\n    \"\"\"\n    Dump YAML data to a yaml file in an ordered way.\n\n    :param data: the data to write.\n    :param stream: (optional) the file to write on.\n    \"\"\"\n    yaml.dump(data, stream=stream, Dumper=_AEAYamlDumper)  # nosec\n\n\ndef yaml_dump_all(data: Sequence[Dict], stream: Optional[TextIO] = None) -> None:\n    \"\"\"\n    Dump YAML data to a yaml file in an ordered way.\n\n    :param data: the data to write.\n    :param stream: (optional) the file to write on.\n    \"\"\"\n    yaml.dump_all(data, stream=stream, Dumper=_AEAYamlDumper)  # nosec\n"
  },
  {
    "path": "aea/identity/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the identity modules.\"\"\"\n"
  },
  {
    "path": "aea/identity/base.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the identity class.\"\"\"\n\nfrom typing import Dict, Optional\n\nfrom aea.common import Address\nfrom aea.configurations.constants import DEFAULT_LEDGER\nfrom aea.exceptions import enforce\nfrom aea.helpers.base import SimpleId, SimpleIdOrStr\n\n\nclass Identity:\n    \"\"\"\n    The identity holds the public elements identifying an agent.\n\n    It includes:\n\n    - the agent name\n    - the addresses, a map from address identifier to address (can be a single key-value pair)\n    \"\"\"\n\n    __slots__ = (\n        \"_name\",\n        \"_address\",\n        \"_public_key\",\n        \"_public_keys\",\n        \"_addresses\",\n        \"_default_address_key\",\n    )\n\n    def __init__(\n        self,\n        name: SimpleIdOrStr,\n        address: Optional[str] = None,\n        public_key: Optional[str] = None,\n        addresses: Optional[Dict[str, Address]] = None,\n        public_keys: Optional[Dict[str, str]] = None,\n        default_address_key: str = DEFAULT_LEDGER,\n    ) -> None:\n        \"\"\"\n        Instantiate the identity.\n\n        :param name: the name of the agent.\n        :param address: the default address of the agent.\n        :param public_key: the public key of the agent.\n        :param addresses: the addresses of the agent.\n        :param public_keys: the public keys of the agent.\n        :param default_address_key: the key for the default address.\n        \"\"\"\n        self._name = SimpleId(name)\n        if default_address_key is None:\n            raise ValueError(\n                \"Provide a key for the default address.\"\n            )  # pragma: nocover\n\n        if (address is None) == (addresses is None):\n            raise ValueError(\n                \"Either provide a single address or a dictionary of addresses, and not both.\"\n            )\n\n        if address is None:\n            if addresses is None or len(addresses) == 0:  # pragma: nocover\n                raise ValueError(\"Provide at least one pair of addresses.\")\n            if public_key is not None:\n                raise ValueError(\n                    \"If you provide a dictionary of addresses, you must not provide a single public key.\"\n                )\n            if public_keys is None:\n                raise ValueError(\n                    \"If you provide a dictionary of addresses, you must provide its corresponding dictionary of public keys.\"\n                )\n            enforce(\n                public_keys.keys() == addresses.keys(),\n                \"Keys in public keys and addresses dictionaries do not match. They must be identical.\",\n            )\n            enforce(\n                default_address_key in addresses and default_address_key in public_keys,\n                \"The default address key must exist in both addresses and public keys dictionaries.\",\n            )\n            address = addresses[default_address_key]\n            public_key = public_keys[default_address_key]\n\n        if addresses is None:\n            if public_keys is not None:\n                raise ValueError(\n                    \"If you provide a single address, you must not provide a dictionary of public keys.\"\n                )\n            if public_key is None:\n                raise ValueError(\n                    \"If you provide a single address, you must provide its corresponding public key.\"\n                )\n            addresses = {default_address_key: address}\n            public_keys = {default_address_key: public_key}\n\n        self._address = address\n        self._addresses = addresses\n        self._public_key = public_key\n        self._public_keys = public_keys\n        self._default_address_key = default_address_key\n\n    @property\n    def default_address_key(self) -> str:\n        \"\"\"Get the default address key.\"\"\"\n        return self._default_address_key\n\n    @property\n    def name(self) -> str:\n        \"\"\"Get the agent name.\"\"\"\n        return str(self._name)\n\n    @property\n    def addresses(self) -> Dict[str, Address]:\n        \"\"\"Get the addresses.\"\"\"\n        return self._addresses\n\n    @property\n    def address(self) -> Address:\n        \"\"\"Get the default address.\"\"\"\n        return self._address\n\n    @property\n    def public_keys(self) -> Dict[str, str]:\n        \"\"\"Get the public keys.\"\"\"\n        return self._public_keys  # type: ignore\n\n    @property\n    def public_key(self) -> str:\n        \"\"\"Get the default public key.\"\"\"\n        return self._public_key  # type: ignore\n"
  },
  {
    "path": "aea/launcher.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the implementation of multiple AEA configs launcher.\"\"\"\nimport logging\nimport multiprocessing\nfrom asyncio.events import AbstractEventLoop\nfrom concurrent.futures.process import BrokenProcessPool\nfrom multiprocessing.synchronize import Event\nfrom os import PathLike\nfrom threading import Thread\nfrom typing import Any, Callable, Dict, Optional, Sequence, Tuple, Type, Union\n\nfrom aea.aea import AEA\nfrom aea.aea_builder import AEABuilder\nfrom aea.exceptions import AEAException\nfrom aea.helpers.base import cd\nfrom aea.helpers.multiple_executor import (\n    AbstractExecutorTask,\n    AbstractMultipleExecutor,\n    AbstractMultipleRunner,\n    AbstractMultiprocessExecutorTask,\n    AsyncExecutor,\n    ExecutorExceptionPolicies,\n    ProcessExecutor,\n    TaskAwaitable,\n    ThreadExecutor,\n)\nfrom aea.runtime import AsyncRuntime\n\n\n_default_logger = logging.getLogger(__name__)\n\n\ndef load_agent(agent_dir: Union[PathLike, str], password: Optional[str] = None) -> AEA:\n    \"\"\"\n    Load AEA from directory.\n\n    :param agent_dir: agent configuration directory\n    :param password: the password to encrypt/decrypt the private key.\n\n    :return: AEA instance\n    \"\"\"\n    with cd(agent_dir):\n        return AEABuilder.from_aea_project(\".\", password=password).build(\n            password=password\n        )\n\n\ndef _set_logger(\n    log_level: Optional[str],\n) -> None:  # pragma: nocover # used in spawned process and pytest does not see this code\n    from aea.cli.utils.loggers import (  # pylint: disable=import-outside-toplevel\n        default_logging_config,\n    )\n\n    logger_ = logging.getLogger(\"aea\")\n    logger_ = default_logging_config(logger_)\n    if log_level is not None:\n        level = logging.getLevelName(log_level)\n        logger_.setLevel(level)\n\n\ndef _run_agent(\n    agent_dir: Union[PathLike, str],\n    stop_event: Event,\n    log_level: Optional[str] = None,\n    password: Optional[str] = None,\n) -> None:\n    \"\"\"\n    Load and run agent in a dedicated process.\n\n    :param agent_dir: agent configuration directory\n    :param stop_event: multithreading Event to stop agent run.\n    :param log_level: debug level applied for AEA in subprocess\n    :param password: the password to encrypt/decrypt the private key.\n    \"\"\"\n    import asyncio  # pylint: disable=import-outside-toplevel\n    import select  # pylint: disable=import-outside-toplevel\n    import selectors  # pylint: disable=import-outside-toplevel\n\n    if hasattr(select, \"kqueue\"):  # pragma: nocover  # cause platform specific\n        selector = selectors.SelectSelector()\n        loop = asyncio.SelectorEventLoop(selector)  # type: ignore\n        asyncio.set_event_loop(loop)\n    try:\n        asyncio.get_event_loop()\n    except Exception:  # pylint: disable=broad-except\n        asyncio.set_event_loop(asyncio.new_event_loop())\n\n    _set_logger(log_level=log_level)\n\n    agent = load_agent(agent_dir, password=password)\n\n    def stop_event_thread() -> None:\n        try:\n            stop_event.wait()\n        except (KeyboardInterrupt, EOFError, BrokenPipeError) as e:  # pragma: nocover\n            _default_logger.debug(\n                f\"Exception raised in stop_event_thread {e} {type(e)}. Skip it, looks process is closed.\"\n            )\n        finally:\n            _default_logger.debug(\"_run_agent: stop event raised. call agent.stop\")\n            agent.runtime.stop()\n\n    Thread(target=stop_event_thread, daemon=True).start()\n    try:\n        agent.start()\n    except KeyboardInterrupt:  # pragma: nocover\n        _default_logger.debug(\"_run_agent: keyboard interrupt\")\n    except BaseException as e:  # pragma: nocover\n        _default_logger.exception(\"exception in _run_agent\")\n        exc = AEAException(f\"Raised {type(e)}({e})\")\n        exc.__traceback__ = e.__traceback__\n        raise exc\n    finally:\n        _default_logger.debug(\"_run_agent: call agent.stop\")\n        agent.stop()\n\n\nclass AEADirTask(AbstractExecutorTask):\n    \"\"\"Task to run agent from agent configuration directory.\"\"\"\n\n    def __init__(\n        self, agent_dir: Union[PathLike, str], password: Optional[str] = None\n    ) -> None:\n        \"\"\"\n        Init aea config dir task.\n\n        :param agent_dir: directory with aea config.\n        :param password: the password to encrypt/decrypt the private key.\n        \"\"\"\n        self._agent_dir = agent_dir\n        self._agent: AEA = load_agent(self._agent_dir, password=password)\n        super().__init__()\n\n    @property\n    def id(self) -> Union[PathLike, str]:\n        \"\"\"Return agent_dir.\"\"\"\n        return self._agent_dir\n\n    def start(self) -> None:  # type: ignore\n        \"\"\"Start task.\"\"\"\n        self._agent.start()\n\n    def stop(self) -> None:\n        \"\"\"Stop task.\"\"\"\n        if not self._agent:  # pragma: nocover\n            raise ValueError(\"Task was not started!\")\n        self._agent.stop()\n\n    def create_async_task(self, loop: AbstractEventLoop) -> TaskAwaitable:\n        \"\"\"Return asyncio Task for task run in asyncio loop.\"\"\"\n        self._agent.runtime.set_loop(loop)\n        if not isinstance(self._agent.runtime, AsyncRuntime):  # pragma: nocover\n            raise ValueError(\n                \"Agent runtime is not async compatible. Please use runtime_mode=async\"\n            )\n        return loop.create_task(self._agent.runtime.start_and_wait_completed())  # type: ignore\n\n\nclass AEADirMultiprocessTask(AbstractMultiprocessExecutorTask):\n    \"\"\"\n    Task to run agent from agent configuration directory.\n\n    Version for multiprocess executor mode.\n    \"\"\"\n\n    def __init__(\n        self,\n        agent_dir: Union[PathLike, str],\n        log_level: Optional[str] = None,\n        password: Optional[str] = None,\n    ) -> None:\n        \"\"\"\n        Init aea config dir task.\n\n        :param agent_dir: directory with aea config.\n        :param log_level: debug level applied for AEA in subprocess\n        :param password: the password to encrypt/decrypt the private key.\n        \"\"\"\n        self._agent_dir = agent_dir\n        self._manager = multiprocessing.Manager()\n        self._stop_event = self._manager.Event()\n        self._log_level = log_level\n        self._password = password\n        super().__init__()\n\n    @property\n    def id(self) -> Union[PathLike, str]:\n        \"\"\"Return agent_dir.\"\"\"\n        return self._agent_dir\n\n    @property\n    def failed(self) -> bool:\n        \"\"\"\n        Return was exception failed or not.\n\n        If it's running it's not failed.\n\n        :return: bool\n        \"\"\"\n        if not self._future:\n            return False\n\n        if (\n            self._future.done()\n            and self._future.exception()\n            and isinstance(self._future.exception(), BrokenProcessPool)\n        ):  # pragma: nocover\n            return False\n\n        return super().failed\n\n    def start(self) -> Tuple[Callable, Sequence[Any]]:\n        \"\"\"Return function and arguments to call within subprocess.\"\"\"\n        return (\n            _run_agent,\n            (self._agent_dir, self._stop_event, self._log_level, self._password),\n        )\n\n    def stop(self) -> None:\n        \"\"\"Stop task.\"\"\"\n        if not self._future:  # pragma: nocover\n            _default_logger.debug(\"Stop called, but no future set.\")\n            return\n        if self._future.done():\n            _default_logger.debug(\"Stop called, but task is already done.\")\n            return\n        try:\n            self._stop_event.set()\n        except (FileNotFoundError, BrokenPipeError, EOFError) as e:  # pragma: nocover\n            _default_logger.debug(\n                f\"Exception raised in task.stop {e} {type(e)}. Skip it, looks process is closed.\"\n            )\n\n\nclass AEALauncher(AbstractMultipleRunner):\n    \"\"\"Run multiple AEA instances.\"\"\"\n\n    SUPPORTED_MODES: Dict[str, Type[AbstractMultipleExecutor]] = {\n        \"threaded\": ThreadExecutor,\n        \"async\": AsyncExecutor,\n        \"multiprocess\": ProcessExecutor,\n    }\n\n    def __init__(\n        self,\n        agent_dirs: Sequence[Union[PathLike, str]],\n        mode: str,\n        fail_policy: ExecutorExceptionPolicies = ExecutorExceptionPolicies.propagate,\n        log_level: Optional[str] = None,\n        password: Optional[str] = None,\n    ) -> None:\n        \"\"\"\n        Init AEALauncher.\n\n        :param agent_dirs: sequence of AEA config directories.\n        :param mode: executor name to use.\n        :param fail_policy: one of ExecutorExceptionPolicies to be used with Executor\n        :param log_level: debug level applied for AEA in subprocesses\n        :param password: the password to encrypt/decrypt the private key.\n        \"\"\"\n        self._agent_dirs = agent_dirs\n        self._log_level = log_level\n        self._password = password\n        super().__init__(mode=mode, fail_policy=fail_policy)\n\n    def _make_tasks(self) -> Sequence[AbstractExecutorTask]:\n        \"\"\"Make tasks to run with executor.\"\"\"\n        if self._mode == \"multiprocess\":\n            return [\n                AEADirMultiprocessTask(\n                    agent_dir, log_level=self._log_level, password=self._password\n                )\n                for agent_dir in self._agent_dirs\n            ]\n        return [\n            AEADirTask(agent_dir, password=self._password)\n            for agent_dir in self._agent_dirs\n        ]\n"
  },
  {
    "path": "aea/mail/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the mail modules.\"\"\"\n"
  },
  {
    "path": "aea/mail/base.proto",
    "content": "syntax = \"proto3\";\n\npackage aea.base.v0_1_0;\n\nimport \"google/protobuf/struct.proto\";\n\n\nmessage DialogueMessage {\n  int32 message_id = 1;\n  string dialogue_starter_reference = 2;\n  string dialogue_responder_reference = 3;\n  int32 target = 4;\n  bytes content = 5;\n}\n\nmessage Message {\n  oneof message {\n    google.protobuf.Struct body = 1;\n    DialogueMessage dialogue_message = 2;\n  }\n}\n\nmessage Envelope{\n  string to = 1;\n  string sender = 2;\n  string protocol_id = 3;\n  bytes message = 4;\n  string uri = 5;\n}\n"
  },
  {
    "path": "aea/mail/base.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Mail module abstract base classes.\"\"\"\n\nimport logging\nfrom abc import ABC, abstractmethod\nfrom typing import Any, Optional, Union\nfrom urllib.parse import urlparse\n\nfrom aea.common import Address\nfrom aea.configurations.base import PublicId\nfrom aea.exceptions import enforce\nfrom aea.mail import base_pb2\nfrom aea.protocols.base import Message\n\n\n_default_logger = logging.getLogger(__name__)\n\n\nclass URI:\n    \"\"\"URI following RFC3986.\"\"\"\n\n    __slots__ = (\"_uri_raw\",)\n\n    def __init__(self, uri_raw: str) -> None:\n        \"\"\"\n        Initialize the URI.\n\n        Must follow: https://tools.ietf.org/html/rfc3986.html\n\n        :param uri_raw: the raw form uri\n        \"\"\"\n        self._uri_raw = uri_raw\n\n    @property\n    def scheme(self) -> str:\n        \"\"\"Get the scheme.\"\"\"\n        parsed = urlparse(self._uri_raw)\n        return parsed.scheme\n\n    @property\n    def netloc(self) -> str:\n        \"\"\"Get the netloc.\"\"\"\n        parsed = urlparse(self._uri_raw)\n        return parsed.netloc\n\n    @property\n    def path(self) -> str:\n        \"\"\"Get the path.\"\"\"\n        parsed = urlparse(self._uri_raw)\n        return parsed.path\n\n    @property\n    def params(self) -> str:\n        \"\"\"Get the params.\"\"\"\n        parsed = urlparse(self._uri_raw)\n        return parsed.params\n\n    @property\n    def query(self) -> str:\n        \"\"\"Get the query.\"\"\"\n        parsed = urlparse(self._uri_raw)\n        return parsed.query\n\n    @property\n    def fragment(self) -> str:\n        \"\"\"Get the fragment.\"\"\"\n        parsed = urlparse(self._uri_raw)\n        return parsed.fragment\n\n    @property\n    def username(self) -> Optional[str]:\n        \"\"\"Get the username.\"\"\"\n        parsed = urlparse(self._uri_raw)\n        return parsed.username\n\n    @property\n    def password(self) -> Optional[str]:\n        \"\"\"Get the password.\"\"\"\n        parsed = urlparse(self._uri_raw)\n        return parsed.password\n\n    @property\n    def host(self) -> Optional[str]:\n        \"\"\"Get the host.\"\"\"\n        parsed = urlparse(self._uri_raw)\n        return parsed.hostname\n\n    @property\n    def port(self) -> Optional[int]:\n        \"\"\"Get the port.\"\"\"\n        parsed = urlparse(self._uri_raw)\n        return parsed.port\n\n    def __str__(self) -> str:\n        \"\"\"Get string representation.\"\"\"\n        return self._uri_raw\n\n    def __eq__(self, other: Any) -> bool:\n        \"\"\"Compare with another object.\"\"\"\n        return isinstance(other, URI) and str(self) == str(other)\n\n\nclass EnvelopeContext:\n    \"\"\"Contains context information of an envelope.\"\"\"\n\n    __slots__ = (\"_connection_id\", \"_uri\")\n\n    def __init__(\n        self,\n        connection_id: Optional[PublicId] = None,\n        uri: Optional[URI] = None,\n    ) -> None:\n        \"\"\"\n        Initialize the envelope context.\n\n        :param connection_id: the connection id used for routing the outgoing envelope in the multiplexer.\n        :param uri: the URI sent with the envelope.\n        \"\"\"\n        self._connection_id = connection_id\n        self._uri = uri\n\n    @property\n    def uri(self) -> Optional[URI]:\n        \"\"\"Get the URI.\"\"\"\n        return self._uri\n\n    @property\n    def connection_id(self) -> Optional[PublicId]:\n        \"\"\"Get the connection id to route the envelope.\"\"\"\n        return self._connection_id\n\n    @connection_id.setter\n    def connection_id(self, connection_id: PublicId) -> None:\n        \"\"\"Set the 'via' connection id.\"\"\"\n        if self._connection_id is not None:\n            raise ValueError(\"connection_id already set!\")  # pragma: nocover\n        self._connection_id = connection_id\n\n    def __str__(self) -> str:\n        \"\"\"Get the string representation.\"\"\"\n        return f\"EnvelopeContext(connection_id={self.connection_id}, uri={self.uri})\"\n\n    def __eq__(self, other: Any) -> bool:\n        \"\"\"Compare with another object.\"\"\"\n        return (\n            isinstance(other, EnvelopeContext)\n            and self.connection_id == other.connection_id\n            and self.uri == other.uri\n        )\n\n\nclass AEAConnectionError(Exception):\n    \"\"\"Exception class for connection errors.\"\"\"\n\n\nclass Empty(Exception):\n    \"\"\"Exception for when the inbox is empty.\"\"\"\n\n\nclass EnvelopeSerializer(ABC):\n    \"\"\"Abstract class to specify the serialization layer for the envelope.\"\"\"\n\n    @abstractmethod\n    def encode(self, envelope: \"Envelope\") -> bytes:\n        \"\"\"\n        Encode the envelope.\n\n        :param envelope: the envelope to encode\n        :return: the encoded envelope\n        \"\"\"\n\n    @abstractmethod\n    def decode(self, envelope_bytes: bytes) -> \"Envelope\":\n        \"\"\"\n        Decode the envelope.\n\n        :param envelope_bytes: the encoded envelope\n        :return: the envelope\n        \"\"\"\n\n\nclass ProtobufEnvelopeSerializer(EnvelopeSerializer):\n    \"\"\"Envelope serializer using Protobuf.\"\"\"\n\n    def encode(self, envelope: \"Envelope\") -> bytes:\n        \"\"\"\n        Encode the envelope.\n\n        :param envelope: the envelope to encode\n        :return: the encoded envelope\n        \"\"\"\n        envelope_pb = base_pb2.Envelope()\n        envelope_pb.to = envelope.to\n        envelope_pb.sender = envelope.sender\n        envelope_pb.protocol_id = str(envelope.protocol_specification_id)\n        envelope_pb.message = envelope.message_bytes\n        if envelope.context is not None and envelope.context.uri is not None:\n            envelope_pb.uri = str(envelope.context.uri)\n\n        envelope_bytes = envelope_pb.SerializeToString()\n        return envelope_bytes\n\n    def decode(self, envelope_bytes: bytes) -> \"Envelope\":\n        \"\"\"\n        Decode the envelope.\n\n        The default serializer doesn't decode the message field.\n\n        :param envelope_bytes: the encoded envelope\n        :return: the envelope\n        \"\"\"\n        envelope_pb = base_pb2.Envelope()\n        envelope_pb.ParseFromString(envelope_bytes)\n\n        to = envelope_pb.to  # pylint: disable=no-member\n        sender = envelope_pb.sender  # pylint: disable=no-member\n        raw_protocol_id = envelope_pb.protocol_id  # pylint: disable=no-member\n        protocol_specification_id = PublicId.from_str(raw_protocol_id)\n        message = envelope_pb.message  # pylint: disable=no-member\n\n        uri_raw = envelope_pb.uri  # pylint: disable=no-member\n        if uri_raw != \"\":  # empty string means this field is not set in proto3\n            uri = URI(uri_raw=uri_raw)\n            context = EnvelopeContext(uri=uri)\n            envelope = Envelope(\n                to=to,\n                sender=sender,\n                protocol_specification_id=protocol_specification_id,\n                message=message,\n                context=context,\n            )\n        else:\n            envelope = Envelope(\n                to=to,\n                sender=sender,\n                protocol_specification_id=protocol_specification_id,\n                message=message,\n            )\n\n        return envelope\n\n\nDefaultEnvelopeSerializer = ProtobufEnvelopeSerializer\n\n\nclass Envelope:\n    \"\"\"The top level message class for agent to agent communication.\"\"\"\n\n    default_serializer = DefaultEnvelopeSerializer()\n\n    __slots__ = (\"_to\", \"_sender\", \"_protocol_specification_id\", \"_message\", \"_context\")\n\n    def __init__(\n        self,\n        to: Address,\n        sender: Address,\n        message: Union[Message, bytes],\n        context: Optional[EnvelopeContext] = None,\n        protocol_specification_id: Optional[PublicId] = None,\n    ) -> None:\n        \"\"\"\n        Initialize a Message object.\n\n        :param to: the address of the receiver.\n        :param sender: the address of the sender.\n        :param message: the protocol-specific message.\n        :param context: the optional envelope context.\n        :param protocol_specification_id: the protocol specification id (wire id).\n        \"\"\"\n        enforce(isinstance(to, str), f\"To must be string. Found '{type(to)}'\")\n        enforce(\n            isinstance(sender, str), f\"Sender must be string. Found '{type(sender)}'\"\n        )\n        enforce(\n            isinstance(message, (Message, bytes)),\n            \"message should be a type of Message or bytes!\",\n        )\n\n        if isinstance(message, Message):\n            message = self._check_consistency(message, to, sender)\n\n        self._to = to\n        self._sender = sender\n\n        enforce(\n            self.is_to_public_id == self.is_sender_public_id,\n            \"To and sender must either both be agent addresses or both be public ids of AEA components.\",\n        )\n\n        if isinstance(message, bytes):\n            if protocol_specification_id is None:\n                raise ValueError(\n                    \"Message is bytes object, protocol_specification_id must be provided!\"\n                )\n        elif isinstance(message, Message):\n            if message.protocol_id is None:\n                raise ValueError(  # pragma: nocover\n                    f\"message class {type(message)} has no protocol_id specified!\"\n                )\n            protocol_specification_id = message.protocol_specification_id\n            if protocol_specification_id is None:\n                raise ValueError(\n                    \"Message is Message object, protocol_specification_id could not be resolved! Ensure protocol is valid!\"\n                )\n        else:\n            raise ValueError(\n                f\"Message type: {type(message)} is not supported!\"\n            )  # pragma: nocover\n\n        self._protocol_specification_id: PublicId = protocol_specification_id\n        self._message = message\n        if self.is_component_to_component_message:\n            enforce(\n                context is None,\n                \"EnvelopeContext must be None for component to component messages.\",\n            )\n        self._context = context\n\n    @property\n    def to(self) -> Address:\n        \"\"\"Get address of receiver.\"\"\"\n        return self._to\n\n    @to.setter\n    def to(self, to: Address) -> None:\n        \"\"\"Set address of receiver.\"\"\"\n        enforce(isinstance(to, str), f\"To must be string. Found '{type(to)}'\")\n        self._to = to\n\n    @property\n    def sender(self) -> Address:\n        \"\"\"Get address of sender.\"\"\"\n        return self._sender\n\n    @sender.setter\n    def sender(self, sender: Address) -> None:\n        \"\"\"Set address of sender.\"\"\"\n        enforce(\n            isinstance(sender, str), f\"Sender must be string. Found '{type(sender)}'\"\n        )\n        self._sender = sender\n\n    @property\n    def protocol_specification_id(self) -> PublicId:\n        \"\"\"Get protocol_specification_id.\"\"\"\n        return self._protocol_specification_id\n\n    @property\n    def message(self) -> Union[Message, bytes]:\n        \"\"\"Get the protocol-specific message.\"\"\"\n        return self._message\n\n    @message.setter\n    def message(self, message: Union[Message, bytes]) -> None:\n        \"\"\"Set the protocol-specific message.\"\"\"\n        self._message = message\n\n    @property\n    def message_bytes(self) -> bytes:\n        \"\"\"Get the protocol-specific message.\"\"\"\n        if isinstance(self._message, Message):\n            return self._message.encode()\n        return self._message\n\n    @property\n    def context(self) -> Optional[EnvelopeContext]:\n        \"\"\"Get the envelope context.\"\"\"\n        return self._context\n\n    @property\n    def to_as_public_id(self) -> Optional[PublicId]:\n        \"\"\"Get to as public id.\"\"\"\n        return PublicId.try_from_str(self.to)\n\n    @property\n    def is_sender_public_id(self) -> bool:\n        \"\"\"Check if sender is a public id.\"\"\"\n        return PublicId.is_valid_str(self.sender)\n\n    @property\n    def is_to_public_id(self) -> bool:\n        \"\"\"Check if to is a public id.\"\"\"\n        return PublicId.is_valid_str(self.to)\n\n    @property\n    def is_component_to_component_message(self) -> bool:\n        \"\"\"Whether or not the message contained is component to component.\"\"\"\n        return self.is_to_public_id and self.is_sender_public_id\n\n    @staticmethod\n    def _check_consistency(message: Message, to: str, sender: str) -> Message:\n        \"\"\"Check consistency of sender and to.\"\"\"\n        if message.has_to:\n            enforce(\n                message.to == to, \"To specified on message does not match envelope.\"\n            )\n        else:\n            message.to = to\n        if message.has_sender:\n            enforce(\n                message.sender == sender,\n                \"Sender specified on message does not match envelope.\",\n            )\n        else:\n            message.sender = sender\n        return message\n\n    def __eq__(self, other: Any) -> bool:\n        \"\"\"Compare with another object.\"\"\"\n        return (\n            isinstance(other, Envelope)\n            and self.to == other.to\n            and self.sender == other.sender\n            and self.protocol_specification_id == other.protocol_specification_id\n            and self.message == other.message\n            and self.context == other.context\n        )\n\n    def encode(\n        self,\n        serializer: Optional[EnvelopeSerializer] = None,\n    ) -> bytes:\n        \"\"\"\n        Encode the envelope.\n\n        :param serializer: the serializer that implements the encoding procedure.\n        :return: the encoded envelope.\n        \"\"\"\n        if serializer is None:\n            serializer = self.default_serializer\n        envelope_bytes = serializer.encode(self)\n        return envelope_bytes\n\n    @classmethod\n    def decode(\n        cls, envelope_bytes: bytes, serializer: Optional[EnvelopeSerializer] = None\n    ) -> \"Envelope\":\n        \"\"\"\n        Decode the envelope.\n\n        :param envelope_bytes: the bytes to be decoded.\n        :param serializer: the serializer that implements the decoding procedure.\n        :return: the decoded envelope.\n        \"\"\"\n        if serializer is None:\n            serializer = cls.default_serializer\n        envelope = serializer.decode(envelope_bytes)\n        return envelope\n\n    def __str__(self) -> str:\n        \"\"\"Get the string representation of an envelope.\"\"\"\n        return \"Envelope(to={to}, sender={sender}, protocol_specification_id={protocol_specification_id}, message={message})\".format(\n            to=self.to,\n            sender=self.sender,\n            protocol_specification_id=self.protocol_specification_id,\n            message=\"{!r}\".format(self.message)\n            if isinstance(self.message, bytes)\n            else self.message,\n        )\n"
  },
  {
    "path": "aea/mail/base_pb2.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by the protocol buffer compiler.  DO NOT EDIT!\n# source: base.proto\n\"\"\"Generated protocol buffer code.\"\"\"\nfrom google.protobuf import descriptor as _descriptor\nfrom google.protobuf import message as _message\nfrom google.protobuf import reflection as _reflection\nfrom google.protobuf import symbol_database as _symbol_database\n\n# @@protoc_insertion_point(imports)\n\n_sym_db = _symbol_database.Default()\n\n\nfrom google.protobuf import struct_pb2 as google_dot_protobuf_dot_struct__pb2\n\n\nDESCRIPTOR = _descriptor.FileDescriptor(\n    name=\"base.proto\",\n    package=\"aea.base.v0_1_0\",\n    syntax=\"proto3\",\n    serialized_options=None,\n    create_key=_descriptor._internal_create_key,\n    serialized_pb=b'\\n\\nbase.proto\\x12\\x0f\\x61\\x65\\x61.base.v0_1_0\\x1a\\x1cgoogle/protobuf/struct.proto\"\\x90\\x01\\n\\x0f\\x44ialogueMessage\\x12\\x12\\n\\nmessage_id\\x18\\x01 \\x01(\\x05\\x12\"\\n\\x1a\\x64ialogue_starter_reference\\x18\\x02 \\x01(\\t\\x12$\\n\\x1c\\x64ialogue_responder_reference\\x18\\x03 \\x01(\\t\\x12\\x0e\\n\\x06target\\x18\\x04 \\x01(\\x05\\x12\\x0f\\n\\x07\\x63ontent\\x18\\x05 \\x01(\\x0c\"{\\n\\x07Message\\x12\\'\\n\\x04\\x62ody\\x18\\x01 \\x01(\\x0b\\x32\\x17.google.protobuf.StructH\\x00\\x12<\\n\\x10\\x64ialogue_message\\x18\\x02 \\x01(\\x0b\\x32 .aea.base.v0_1_0.DialogueMessageH\\x00\\x42\\t\\n\\x07message\"Y\\n\\x08\\x45nvelope\\x12\\n\\n\\x02to\\x18\\x01 \\x01(\\t\\x12\\x0e\\n\\x06sender\\x18\\x02 \\x01(\\t\\x12\\x13\\n\\x0bprotocol_id\\x18\\x03 \\x01(\\t\\x12\\x0f\\n\\x07message\\x18\\x04 \\x01(\\x0c\\x12\\x0b\\n\\x03uri\\x18\\x05 \\x01(\\tb\\x06proto3',\n    dependencies=[\n        google_dot_protobuf_dot_struct__pb2.DESCRIPTOR,\n    ],\n)\n\n\n_DIALOGUEMESSAGE = _descriptor.Descriptor(\n    name=\"DialogueMessage\",\n    full_name=\"aea.base.v0_1_0.DialogueMessage\",\n    filename=None,\n    file=DESCRIPTOR,\n    containing_type=None,\n    create_key=_descriptor._internal_create_key,\n    fields=[\n        _descriptor.FieldDescriptor(\n            name=\"message_id\",\n            full_name=\"aea.base.v0_1_0.DialogueMessage.message_id\",\n            index=0,\n            number=1,\n            type=5,\n            cpp_type=1,\n            label=1,\n            has_default_value=False,\n            default_value=0,\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.FieldDescriptor(\n            name=\"dialogue_starter_reference\",\n            full_name=\"aea.base.v0_1_0.DialogueMessage.dialogue_starter_reference\",\n            index=1,\n            number=2,\n            type=9,\n            cpp_type=9,\n            label=1,\n            has_default_value=False,\n            default_value=b\"\".decode(\"utf-8\"),\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.FieldDescriptor(\n            name=\"dialogue_responder_reference\",\n            full_name=\"aea.base.v0_1_0.DialogueMessage.dialogue_responder_reference\",\n            index=2,\n            number=3,\n            type=9,\n            cpp_type=9,\n            label=1,\n            has_default_value=False,\n            default_value=b\"\".decode(\"utf-8\"),\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.FieldDescriptor(\n            name=\"target\",\n            full_name=\"aea.base.v0_1_0.DialogueMessage.target\",\n            index=3,\n            number=4,\n            type=5,\n            cpp_type=1,\n            label=1,\n            has_default_value=False,\n            default_value=0,\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.FieldDescriptor(\n            name=\"content\",\n            full_name=\"aea.base.v0_1_0.DialogueMessage.content\",\n            index=4,\n            number=5,\n            type=12,\n            cpp_type=9,\n            label=1,\n            has_default_value=False,\n            default_value=b\"\",\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n    ],\n    extensions=[],\n    nested_types=[],\n    enum_types=[],\n    serialized_options=None,\n    is_extendable=False,\n    syntax=\"proto3\",\n    extension_ranges=[],\n    oneofs=[],\n    serialized_start=62,\n    serialized_end=206,\n)\n\n\n_MESSAGE = _descriptor.Descriptor(\n    name=\"Message\",\n    full_name=\"aea.base.v0_1_0.Message\",\n    filename=None,\n    file=DESCRIPTOR,\n    containing_type=None,\n    create_key=_descriptor._internal_create_key,\n    fields=[\n        _descriptor.FieldDescriptor(\n            name=\"body\",\n            full_name=\"aea.base.v0_1_0.Message.body\",\n            index=0,\n            number=1,\n            type=11,\n            cpp_type=10,\n            label=1,\n            has_default_value=False,\n            default_value=None,\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.FieldDescriptor(\n            name=\"dialogue_message\",\n            full_name=\"aea.base.v0_1_0.Message.dialogue_message\",\n            index=1,\n            number=2,\n            type=11,\n            cpp_type=10,\n            label=1,\n            has_default_value=False,\n            default_value=None,\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n    ],\n    extensions=[],\n    nested_types=[],\n    enum_types=[],\n    serialized_options=None,\n    is_extendable=False,\n    syntax=\"proto3\",\n    extension_ranges=[],\n    oneofs=[\n        _descriptor.OneofDescriptor(\n            name=\"message\",\n            full_name=\"aea.base.v0_1_0.Message.message\",\n            index=0,\n            containing_type=None,\n            create_key=_descriptor._internal_create_key,\n            fields=[],\n        ),\n    ],\n    serialized_start=208,\n    serialized_end=331,\n)\n\n\n_ENVELOPE = _descriptor.Descriptor(\n    name=\"Envelope\",\n    full_name=\"aea.base.v0_1_0.Envelope\",\n    filename=None,\n    file=DESCRIPTOR,\n    containing_type=None,\n    create_key=_descriptor._internal_create_key,\n    fields=[\n        _descriptor.FieldDescriptor(\n            name=\"to\",\n            full_name=\"aea.base.v0_1_0.Envelope.to\",\n            index=0,\n            number=1,\n            type=9,\n            cpp_type=9,\n            label=1,\n            has_default_value=False,\n            default_value=b\"\".decode(\"utf-8\"),\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.FieldDescriptor(\n            name=\"sender\",\n            full_name=\"aea.base.v0_1_0.Envelope.sender\",\n            index=1,\n            number=2,\n            type=9,\n            cpp_type=9,\n            label=1,\n            has_default_value=False,\n            default_value=b\"\".decode(\"utf-8\"),\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.FieldDescriptor(\n            name=\"protocol_id\",\n            full_name=\"aea.base.v0_1_0.Envelope.protocol_id\",\n            index=2,\n            number=3,\n            type=9,\n            cpp_type=9,\n            label=1,\n            has_default_value=False,\n            default_value=b\"\".decode(\"utf-8\"),\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.FieldDescriptor(\n            name=\"message\",\n            full_name=\"aea.base.v0_1_0.Envelope.message\",\n            index=3,\n            number=4,\n            type=12,\n            cpp_type=9,\n            label=1,\n            has_default_value=False,\n            default_value=b\"\",\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n        _descriptor.FieldDescriptor(\n            name=\"uri\",\n            full_name=\"aea.base.v0_1_0.Envelope.uri\",\n            index=4,\n            number=5,\n            type=9,\n            cpp_type=9,\n            label=1,\n            has_default_value=False,\n            default_value=b\"\".decode(\"utf-8\"),\n            message_type=None,\n            enum_type=None,\n            containing_type=None,\n            is_extension=False,\n            extension_scope=None,\n            serialized_options=None,\n            file=DESCRIPTOR,\n            create_key=_descriptor._internal_create_key,\n        ),\n    ],\n    extensions=[],\n    nested_types=[],\n    enum_types=[],\n    serialized_options=None,\n    is_extendable=False,\n    syntax=\"proto3\",\n    extension_ranges=[],\n    oneofs=[],\n    serialized_start=333,\n    serialized_end=422,\n)\n\n_MESSAGE.fields_by_name[\n    \"body\"\n].message_type = google_dot_protobuf_dot_struct__pb2._STRUCT\n_MESSAGE.fields_by_name[\"dialogue_message\"].message_type = _DIALOGUEMESSAGE\n_MESSAGE.oneofs_by_name[\"message\"].fields.append(_MESSAGE.fields_by_name[\"body\"])\n_MESSAGE.fields_by_name[\"body\"].containing_oneof = _MESSAGE.oneofs_by_name[\"message\"]\n_MESSAGE.oneofs_by_name[\"message\"].fields.append(\n    _MESSAGE.fields_by_name[\"dialogue_message\"]\n)\n_MESSAGE.fields_by_name[\"dialogue_message\"].containing_oneof = _MESSAGE.oneofs_by_name[\n    \"message\"\n]\nDESCRIPTOR.message_types_by_name[\"DialogueMessage\"] = _DIALOGUEMESSAGE\nDESCRIPTOR.message_types_by_name[\"Message\"] = _MESSAGE\nDESCRIPTOR.message_types_by_name[\"Envelope\"] = _ENVELOPE\n_sym_db.RegisterFileDescriptor(DESCRIPTOR)\n\nDialogueMessage = _reflection.GeneratedProtocolMessageType(\n    \"DialogueMessage\",\n    (_message.Message,),\n    {\n        \"DESCRIPTOR\": _DIALOGUEMESSAGE,\n        \"__module__\": \"base_pb2\"\n        # @@protoc_insertion_point(class_scope:aea.base.v0_1_0.DialogueMessage)\n    },\n)\n_sym_db.RegisterMessage(DialogueMessage)\n\nMessage = _reflection.GeneratedProtocolMessageType(\n    \"Message\",\n    (_message.Message,),\n    {\n        \"DESCRIPTOR\": _MESSAGE,\n        \"__module__\": \"base_pb2\"\n        # @@protoc_insertion_point(class_scope:aea.base.v0_1_0.Message)\n    },\n)\n_sym_db.RegisterMessage(Message)\n\nEnvelope = _reflection.GeneratedProtocolMessageType(\n    \"Envelope\",\n    (_message.Message,),\n    {\n        \"DESCRIPTOR\": _ENVELOPE,\n        \"__module__\": \"base_pb2\"\n        # @@protoc_insertion_point(class_scope:aea.base.v0_1_0.Envelope)\n    },\n)\n_sym_db.RegisterMessage(Envelope)\n\n\n# @@protoc_insertion_point(module_scope)\n"
  },
  {
    "path": "aea/manager/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the manager modules.\"\"\"\nfrom aea.manager.manager import MultiAgentManager\n\n\n__all__ = [\"MultiAgentManager\"]\n"
  },
  {
    "path": "aea/manager/manager.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the implementation of AEA agents manager.\"\"\"\nimport asyncio\nimport datetime\nimport json\nimport multiprocessing\nimport os\nimport threading\nfrom abc import ABC, abstractmethod\nfrom asyncio.tasks import FIRST_COMPLETED\nfrom collections import defaultdict\nfrom multiprocessing.synchronize import Event\nfrom shutil import rmtree\nfrom threading import Thread\nfrom traceback import format_exc\nfrom typing import Any, Callable, Dict, List, Optional, Set, Tuple\n\nfrom aea.aea import AEA\nfrom aea.configurations.base import AgentConfig\nfrom aea.configurations.constants import AEA_MANAGER_DATA_DIRNAME, DEFAULT_REGISTRY_NAME\nfrom aea.configurations.data_types import PackageIdPrefix, PublicId\nfrom aea.exceptions import enforce\nfrom aea.helpers.io import open_file\nfrom aea.manager.project import AgentAlias, Project\nfrom aea.manager.utils import (\n    get_venv_dir_for_project,\n    project_check,\n    project_install_and_build,\n    run_in_venv,\n)\n\n\nclass ProjectNotFoundError(ValueError):\n    \"\"\"Project not found exception.\"\"\"\n\n\nclass ProjectCheckError(ValueError):\n    \"\"\"Project check error exception.\"\"\"\n\n    def __init__(self, msg: str, source_exception: Exception):\n        \"\"\"Init exception.\"\"\"\n        super().__init__(msg)\n        self.source_exception = source_exception\n\n\nclass ProjectPackageConsistencyCheckError(ValueError):\n    \"\"\"Check consistency of package versions against already added project.\"\"\"\n\n    def __init__(\n        self,\n        agent_project_id: PublicId,\n        conflicting_packages: List[Tuple[PackageIdPrefix, str, str, Set[PublicId]]],\n    ):\n        \"\"\"\n        Initialize the exception.\n\n        :param agent_project_id: the agent project id whose addition has failed.\n        :param conflicting_packages: the conflicting packages.\n        \"\"\"\n        self.agent_project_id = agent_project_id\n        self.conflicting_packages = conflicting_packages\n        super().__init__(self._build_error_message())\n\n    def _build_error_message(self) -> str:\n        \"\"\"Build the error message.\"\"\"\n        conflicting_packages = sorted(self.conflicting_packages, key=str)\n        message = f\"cannot add project '{self.agent_project_id}': the following AEA dependencies have conflicts with previously added projects:\\n\"\n        for (\n            (type_, author, name),\n            existing_version,\n            new_version,\n            agents,\n        ) in conflicting_packages:\n            message += f\"- '{author}/{name}' of type {type_}: the new version '{new_version}' conflicts with existing version '{existing_version}' of the same package required by agents: {list(agents)}\\n\"\n        return message\n\n\nclass BaseAgentRunTask(ABC):\n    \"\"\"Base abstract class for agent run tasks.\"\"\"\n\n    @abstractmethod\n    def start(self) -> None:\n        \"\"\"Start task.\"\"\"\n\n    @abstractmethod\n    def wait(self) -> asyncio.Future:\n        \"\"\"Return future to wait task completed.\"\"\"\n\n    @abstractmethod\n    def stop(self) -> None:\n        \"\"\"Stop task.\"\"\"\n\n    @property\n    @abstractmethod\n    def is_running(self) -> bool:\n        \"\"\"Return is task running.\"\"\"\n\n\nclass AgentRunAsyncTask(BaseAgentRunTask):\n    \"\"\"Async task wrapper for agent.\"\"\"\n\n    def __init__(self, agent: AEA, loop: asyncio.AbstractEventLoop) -> None:\n        \"\"\"Init task with agent alias and loop.\"\"\"\n        self.agent = agent\n        self.run_loop: asyncio.AbstractEventLoop = loop\n        self.caller_loop: asyncio.AbstractEventLoop = loop\n        self._done_future: Optional[asyncio.Future] = None\n        self.task: Optional[asyncio.Task] = None\n\n    def create_run_loop(self) -> None:\n        \"\"\"Create run loop.\"\"\"\n\n    def start(self) -> None:\n        \"\"\"Start task.\"\"\"\n        self.create_run_loop()\n        self._done_future = asyncio.Future()\n        self.task = self.run_loop.create_task(self._run_wrapper())\n\n    def wait(self) -> asyncio.Future:\n        \"\"\"Return future to wait task completed.\"\"\"\n        if not self._done_future:  # pragma: nocover\n            raise ValueError(\"Task not started!\")\n        return self._done_future\n\n    def stop(self) -> None:\n        \"\"\"Stop task.\"\"\"\n        if not self.run_loop or not self.task:  # pragma: nocover\n            raise ValueError(\"Task was not started!\")\n        self.run_loop.call_soon_threadsafe(self.task.cancel)\n\n    async def _run_wrapper(self) -> None:\n        \"\"\"Run task internals.\"\"\"\n        if not self._done_future:  # pragma: nocover\n            raise ValueError(\"Task was not started! please use start method\")\n        exc = None\n        try:\n            await self.run()\n        except asyncio.CancelledError:  # pragma: nocover\n            pass\n        except Exception as e:  # pylint: disable=broad-except\n            exc = e\n        finally:\n            self.caller_loop.call_soon_threadsafe(self._set_result, exc)\n\n    def _set_result(self, exc: Optional[BaseException]) -> None:\n        \"\"\"Set result of task execution.\"\"\"\n        if not self._done_future or self._done_future.done():  # pragma: nocover\n            return\n        if exc:\n            self._done_future.set_exception(exc)\n        else:\n            self._done_future.set_result(None)\n\n    async def run(self) -> None:\n        \"\"\"Run task body.\"\"\"\n        self.agent.runtime.set_loop(self.run_loop)\n        await self.agent.runtime.run()\n\n    @property\n    def is_running(self) -> bool:\n        \"\"\"Return is task running.\"\"\"\n        return not self.wait().done()\n\n\nclass AgentRunThreadTask(AgentRunAsyncTask):\n    \"\"\"Threaded wrapper to run agent.\"\"\"\n\n    def __init__(self, agent: AEA, loop: asyncio.AbstractEventLoop) -> None:\n        \"\"\"Init task with agent alias and loop.\"\"\"\n        AgentRunAsyncTask.__init__(self, agent, loop)\n        self._thread: Optional[Thread] = None\n\n    def create_run_loop(self) -> None:\n        \"\"\"Create run loop.\"\"\"\n        self.run_loop = asyncio.new_event_loop()\n\n    def start(self) -> None:\n        \"\"\"Run task in a dedicated thread.\"\"\"\n        super().start()\n        self._thread = threading.Thread(\n            target=self.run_loop.run_until_complete, args=[self.task], daemon=True\n        )\n        self._thread.start()\n\n    def stop(\n        self,\n    ) -> None:\n        \"\"\"Stop the task.\"\"\"\n        super().stop()\n        if self._thread is not None:\n            self._thread.join()\n\n\nclass AgentRunProcessTask(BaseAgentRunTask):\n    \"\"\"Subprocess wrapper to run agent.\"\"\"\n\n    PROCESS_JOIN_TIMEOUT = 20  # in seconds\n    PROCESS_ALIVE_SLEEP_TIME = 0.005  # in seconds\n\n    def __init__(  # pylint: disable=super-init-not-called\n        self, agent_alias: AgentAlias, loop: asyncio.AbstractEventLoop\n    ) -> None:\n        \"\"\"Init task with agent alias and loop.\"\"\"\n        self.caller_loop: asyncio.AbstractEventLoop = loop\n        self._manager = multiprocessing.Manager()\n        self._stop_event = self._manager.Event()\n        self.agent_alias = agent_alias\n        self.process: Optional[multiprocessing.Process] = None\n        self._wait_task: Optional[asyncio.Future] = None\n        self._result_queue = self._manager.Queue()\n\n    def start(self) -> None:\n        \"\"\"Run task in a dedicated process.\"\"\"\n        self._wait_task = asyncio.ensure_future(\n            self._wait_for_result(), loop=self.caller_loop\n        )\n        self.process = multiprocessing.Process(\n            target=self._run_agent,\n            args=(self.agent_alias, self._stop_event, self._result_queue),\n        )\n        self.process.start()\n\n    async def _wait_for_result(self) -> Any:\n        \"\"\"Wait for the result of the function call.\"\"\"\n        if not self.process:\n            raise ValueError(\"Task not started!\")  # pragma: nocover\n\n        while self.process.is_alive():\n            await asyncio.sleep(self.PROCESS_ALIVE_SLEEP_TIME)\n\n        result = self._result_queue.get_nowait()\n        self.process.join(self.PROCESS_JOIN_TIMEOUT)\n        if isinstance(result, Exception):\n            raise result\n        return result\n\n    def wait(self) -> asyncio.Future:\n        \"\"\"Return future to wait task completed.\"\"\"\n        if not self._wait_task:\n            raise ValueError(\"Task not started\")  # pragma: nocover\n\n        return self._wait_task\n\n    @staticmethod\n    def _run_agent(\n        agent_alias: AgentAlias,\n        stop_event: Event,\n        result_queue: multiprocessing.Queue,\n    ) -> None:\n        \"\"\"Start an agent in a child process.\"\"\"\n        t: Optional[Thread] = None\n        r: Optional[Exception] = None\n        run_stop_thread: bool = True\n        # set a new event loop, cause it's a new process\n        asyncio.set_event_loop(asyncio.new_event_loop())\n        try:\n            aea = agent_alias.get_aea_instance()\n\n            def stop_event_thread() -> None:\n                try:\n                    while run_stop_thread:\n                        if stop_event.wait(0.01) is True:\n                            break\n                finally:\n                    aea.runtime.stop()\n\n            t = Thread(target=stop_event_thread, daemon=True)\n            t.start()\n            loop = asyncio.get_event_loop()\n            aea.runtime.set_loop(loop)\n            aea.runtime.start()\n            loop.run_until_complete(aea.runtime.wait_completed())\n\n        except BaseException as e:  # pylint: disable=broad-except\n            print(\n                f\"Exception in agent subprocess task at {datetime.datetime.now()}:\\n{format_exc()}\"\n            )\n            r = Exception(str(e), repr(e))\n        finally:\n            run_stop_thread = False\n            if t:\n                t.join(10)\n            result_queue.put(r)\n            aea.logger.debug(\"process task stopped\")\n\n    def stop(self) -> None:\n        \"\"\"Stop the task.\"\"\"\n        if not self.process:\n            raise ValueError(\"Task not started!\")  # pragma: nocover\n\n        self._stop_event.set()\n        self.process.join(self.PROCESS_JOIN_TIMEOUT)\n        if self.is_running:  # pragma: nocover\n            self.process.terminate()\n            self.process.join(5)\n            raise ValueError(\n                f\"process was not stopped within timeout: {self.PROCESS_JOIN_TIMEOUT} and was terminated\"\n            )\n\n    @property\n    def is_running(self) -> bool:\n        \"\"\"Is agent running.\"\"\"\n        if not self.process:\n            raise ValueError(\"Task not started!\")  # pragma: nocover\n\n        return self.process.is_alive()\n\n\nASYNC_MODE = \"async\"\nTHREADED_MODE = \"threaded\"\nMULTIPROCESS_MODE = \"multiprocess\"\n\n\nclass MultiAgentManager:\n    \"\"\"Multi agents manager.\"\"\"\n\n    MODES = [ASYNC_MODE, THREADED_MODE, MULTIPROCESS_MODE]\n    _MODE_TASK_CLASS = {\n        ASYNC_MODE: AgentRunAsyncTask,\n        THREADED_MODE: AgentRunThreadTask,\n        MULTIPROCESS_MODE: AgentRunProcessTask,\n    }\n    DEFAULT_TIMEOUT_FOR_BLOCKING_OPERATIONS = 60\n    VENV_BUILD_TIMEOUT = 240\n    SAVE_FILENAME = \"save.json\"\n\n    def __init__(\n        self,\n        working_dir: str,\n        mode: str = \"async\",\n        registry_path: str = DEFAULT_REGISTRY_NAME,\n        auto_add_remove_project: bool = False,\n        password: Optional[str] = None,\n    ) -> None:\n        \"\"\"\n        Initialize manager.\n\n        :param working_dir: directory to store base agents.\n        :param mode: str. async or threaded\n        :param registry_path: str. path to the local packages registry\n        :param auto_add_remove_project: bool. add/remove project on the first agent add/last agent remove\n        :param password: the password to encrypt/decrypt the private key.\n        \"\"\"\n        self.working_dir = working_dir\n        self._auto_add_remove_project = auto_add_remove_project\n        self._save_path = os.path.join(self.working_dir, self.SAVE_FILENAME)\n\n        self.registry_path = registry_path\n        self._was_working_dir_created = False\n        self._is_running = False\n        self._projects: Dict[PublicId, Project] = {}\n        self._versionless_projects_set: Set[PublicId] = set()\n        self._data_dir = os.path.abspath(\n            os.path.join(self.working_dir, AEA_MANAGER_DATA_DIRNAME)\n        )\n        self._agents: Dict[str, AgentAlias] = {}\n        self._agents_tasks: Dict[str, BaseAgentRunTask] = {}\n\n        self._thread: Optional[Thread] = None\n        self._loop: Optional[asyncio.AbstractEventLoop] = None\n        self._event: Optional[asyncio.Event] = None\n\n        self._error_callbacks: List[Callable[[str, BaseException], None]] = [\n            self._default_error_callback\n        ]\n        self._custom_callback_added: bool = False\n        self._last_start_status: Optional[\n            Tuple[\n                bool,\n                Dict[PublicId, List[Dict]],\n                List[Tuple[PublicId, List[Dict], Exception]],\n            ]\n        ] = None\n\n        if mode not in self.MODES:\n            raise ValueError(\n                f'Invalid mode {mode}. Valid modes are {\", \".join(self.MODES)}'\n            )\n        self._started_event = threading.Event()\n        self._mode = mode\n        self._password = password\n\n        # this flags will control whether we have already printed the warning message\n        # for a certain agent\n        self._warning_message_printed_for_agent: Dict[str, bool] = {}\n\n        # the dictionary keeps track of the AEA packages used across\n        # AEA projects in the same MAM.\n        # It maps package prefixes to a pair: (version, agent_ids)\n        # where agent_ids is the set of agent ids whose projects\n        # have the package in the key at the specific version.\n        self._package_id_prefix_to_version: Dict[\n            PackageIdPrefix, Tuple[str, Set[PublicId]]\n        ] = {}\n\n    @property\n    def data_dir(self) -> str:\n        \"\"\"Get the certs directory.\"\"\"\n        return self._data_dir\n\n    def get_data_dir_of_agent(self, agent_name: str) -> str:\n        \"\"\"Get the data directory of a specific agent.\"\"\"\n        return os.path.join(self.data_dir, agent_name)\n\n    @property\n    def is_running(self) -> bool:\n        \"\"\"Is manager running.\"\"\"\n        return self._is_running\n\n    @property\n    def dict_state(self) -> Dict[str, Any]:\n        \"\"\"Create MultiAgentManager dist state.\"\"\"\n        return {\n            \"projects\": [str(public_id) for public_id in self._projects.keys()],\n            \"agents\": [alias.dict for alias in self._agents.values()],\n        }\n\n    @property\n    def projects(self) -> Dict[PublicId, Project]:\n        \"\"\"Get all projects.\"\"\"\n        return self._projects\n\n    def _run_thread(self) -> None:\n        \"\"\"Run internal thread with own event loop.\"\"\"\n        self._loop = asyncio.new_event_loop()\n        self._loop.run_until_complete(self._manager_loop())\n\n    async def _manager_loop(self) -> None:\n        \"\"\"Await and control running manager.\"\"\"\n        self._event = asyncio.Event()\n\n        self._started_event.set()\n\n        while self._is_running:\n            agents_run_tasks_futures = {\n                task.wait(): agent_name\n                for agent_name, task in self._agents_tasks.items()\n            }\n            wait_tasks = [\n                asyncio.ensure_future(i)\n                for i in [*agents_run_tasks_futures.keys(), self._event.wait()]\n            ]\n            done, _ = await asyncio.wait(wait_tasks, return_when=FIRST_COMPLETED)\n\n            if self._event.is_set():\n                self._event.clear()\n\n            for task in done:\n                if task not in agents_run_tasks_futures:\n                    # task not in agents_run_tasks_futures, so it's event_wait, skip it\n                    await task\n                    continue\n\n                agent_name = agents_run_tasks_futures[task]\n                self._agents_tasks.pop(agent_name)\n                if task.exception():\n                    for callback in self._error_callbacks:\n                        callback(agent_name, task.exception())  # type: ignore\n                else:\n                    await task\n\n    def add_error_callback(\n        self, error_callback: Callable[[str, BaseException], None]\n    ) -> \"MultiAgentManager\":\n        \"\"\"Add error callback to call on error raised.\"\"\"\n        if len(self._error_callbacks) == 1 and not self._custom_callback_added:\n            # only default callback present, reset before adding new callback\n            self._custom_callback_added = True\n            self._error_callbacks = []\n        self._error_callbacks.append(error_callback)\n        return self\n\n    def start_manager(\n        self, local: bool = False, remote: bool = False\n    ) -> \"MultiAgentManager\":\n        \"\"\"\n        Start manager.\n\n        If local = False and remote = False, then the packages\n        are fetched in mixed mode (i.e. first try from local\n        registry, and then from remote registry in case of failure).\n\n        :param local: whether or not to fetch from local registry.\n        :param remote: whether or not to fetch from remote registry.\n\n        :return: the MultiAgentManager instance.\n        \"\"\"\n        if self._is_running:\n            return self\n\n        self._ensure_working_dir()\n        self._last_start_status = self._load_state(local=local, remote=remote)\n\n        self._started_event.clear()\n        self._is_running = True\n        self._thread = Thread(target=self._run_thread, daemon=True)\n        self._thread.start()\n        self._started_event.wait(self.DEFAULT_TIMEOUT_FOR_BLOCKING_OPERATIONS)\n        return self\n\n    @property\n    def last_start_status(\n        self,\n    ) -> Tuple[\n        bool,\n        Dict[PublicId, List[Dict]],\n        List[Tuple[PublicId, List[Dict], Exception]],\n    ]:\n        \"\"\"Get status of the last agents start loading state.\"\"\"\n        if self._last_start_status is None:\n            raise ValueError(\"Manager was not started\")\n        return self._last_start_status\n\n    def stop_manager(\n        self, cleanup: bool = True, save: bool = False\n    ) -> \"MultiAgentManager\":\n        \"\"\"\n        Stop manager.\n\n        Stops all running agents and stop agent.\n\n        :param cleanup: bool is cleanup on stop.\n        :param save: bool is save state to file on stop.\n\n        :return: None\n        \"\"\"\n        if not self._is_running:\n            return self\n\n        if not self._loop or not self._event or not self._thread:  # pragma: nocover\n            raise ValueError(\"Manager was not started!\")\n\n        if not self._thread.is_alive():  # pragma: nocover\n            return self\n\n        self.stop_all_agents()\n\n        if save:\n            self._save_state()\n\n        for agent_name in self.list_agents():\n            self.remove_agent(agent_name, skip_project_auto_remove=True)\n\n        if cleanup:\n            for project in list(self._projects.keys()):\n                self.remove_project(project, keep_files=save)\n            self._cleanup(only_data=save)\n\n        self._is_running = False\n\n        self._loop.call_soon_threadsafe(self._event.set)\n\n        if self._thread.ident != threading.get_ident():\n            self._thread.join(self.DEFAULT_TIMEOUT_FOR_BLOCKING_OPERATIONS)\n\n        self._thread = None\n        self._warning_message_printed_for_agent = {}\n        return self\n\n    def _cleanup(self, only_data: bool = False) -> None:\n        \"\"\"Remove workdir if was created.\"\"\"\n        if only_data:\n            rmtree(self.data_dir)\n        else:\n            if self._was_working_dir_created and os.path.exists(self.working_dir):\n                rmtree(self.working_dir)\n\n    def add_project(\n        self,\n        public_id: PublicId,\n        local: bool = False,\n        remote: bool = False,\n        restore: bool = False,\n    ) -> \"MultiAgentManager\":\n        \"\"\"\n        Fetch agent project and all dependencies to working_dir.\n\n        If local = False and remote = False, then the packages\n        are fetched in mixed mode (i.e. first try from local\n        registry, and then from remote registry in case of failure).\n\n        :param public_id: the public if of the agent project.\n        :param local: whether or not to fetch from local registry.\n        :param remote: whether or not to fetch from remote registry.\n        :param restore: bool flag for restoring already fetched agent.\n        :return: self\n        \"\"\"\n        if public_id.to_any() in self._versionless_projects_set:\n            raise ValueError(\n                f\"The project ({public_id.author}/{public_id.name}) was already added!\"\n            )\n\n        project = Project.load(\n            self.working_dir,\n            public_id,\n            local,\n            remote,\n            registry_path=self.registry_path,\n            is_restore=restore,\n            skip_aea_validation=False,\n        )\n\n        if not restore:\n            self._project_install_and_build(project)\n\n        self._check_version_consistency(project.agent_config)\n\n        try:\n            self._check_project(project)\n        except Exception as e:\n            project.remove()\n            raise ProjectCheckError(\n                f\"Failed to load project: {public_id} Error: {str(e)}\", e\n            )\n\n        self._add_new_package_versions(project.agent_config)\n        self._versionless_projects_set.add(public_id.to_any())\n        self._projects[public_id] = project\n        return self\n\n    def _project_install_and_build(self, project: Project) -> None:\n        \"\"\"Build and install project dependencies.\"\"\"\n        if self._mode == MULTIPROCESS_MODE:\n            venv_dir = get_venv_dir_for_project(project)\n            run_in_venv(\n                venv_dir, project_install_and_build, self.VENV_BUILD_TIMEOUT, project\n            )\n        else:\n            venv_dir = get_venv_dir_for_project(project)\n            project_install_and_build(project)\n\n    def _check_project(self, project: Project) -> None:\n        if self._mode == MULTIPROCESS_MODE:\n            venv_dir = get_venv_dir_for_project(project)\n            run_in_venv(venv_dir, project_check, 120, project)\n        else:\n            project_check(project)\n\n    def remove_project(\n        self, public_id: PublicId, keep_files: bool = False\n    ) -> \"MultiAgentManager\":\n        \"\"\"Remove agent project.\"\"\"\n        if public_id not in self._projects:\n            raise ValueError(f\"Project {public_id} is not present!\")\n\n        if self._projects[public_id].agents:\n            raise ValueError(\n                f\"Can not remove projects with aliases exists: {self._projects[public_id].agents}\"\n            )\n\n        project = self._projects.pop(public_id)\n        self._remove_package_versions(project.agent_config)\n        self._versionless_projects_set.remove(public_id.to_any())\n        if not keep_files:\n            project.remove()\n\n        return self\n\n    def list_projects(self) -> List[PublicId]:\n        \"\"\"\n        List all agents projects added.\n\n        :return: list of public ids of projects\n        \"\"\"\n        return list(self._projects.keys())\n\n    def add_agent(\n        self,\n        public_id: PublicId,\n        agent_name: Optional[str] = None,\n        agent_overrides: Optional[dict] = None,\n        component_overrides: Optional[List[dict]] = None,\n        local: bool = False,\n        remote: bool = False,\n        restore: bool = False,\n    ) -> \"MultiAgentManager\":\n        \"\"\"\n        Create new agent configuration based on project with config overrides applied.\n\n        Alias is stored in memory only!\n\n        :param public_id: base agent project public id\n        :param agent_name: unique name for the agent\n        :param agent_overrides: overrides for agent config.\n        :param component_overrides: overrides for component section.\n        :param local: whether or not to fetch from local registry.\n        :param remote: whether or not to fetch from remote registry.\n        :param restore: bool flag for restoring already fetched agent.\n        :return: self\n        \"\"\"\n        agent_name = agent_name or public_id.name\n\n        if agent_name in self._agents:\n            raise ValueError(f\"Agent with name {agent_name} already exists!\")\n\n        project = self._projects.get(public_id, None)\n\n        if project is None and self._auto_add_remove_project:\n            self.add_project(public_id, local, remote, restore)\n            project = self._projects.get(public_id, None)\n\n        if project is None:\n            raise ProjectNotFoundError(f\"{public_id} project is not added!\")\n\n        agent_alias = AgentAlias(\n            project=project,\n            agent_name=agent_name,\n            data_dir=self.get_data_dir_of_agent(agent_name),\n            password=self._password,\n        )\n        agent_alias.set_overrides(agent_overrides, component_overrides)\n        project.agents.add(agent_name)\n        self._agents[agent_name] = agent_alias\n        return self\n\n    def add_agent_with_config(\n        self,\n        public_id: PublicId,\n        config: List[dict],\n        agent_name: Optional[str] = None,\n    ) -> \"MultiAgentManager\":\n        \"\"\"\n        Create new agent configuration based on project with config provided.\n\n        Alias is stored in memory only!\n\n        :param public_id: base agent project public id\n        :param agent_name: unique name for the agent\n        :param config: agent config (used for agent re-creation).\n\n        :return: manager\n        \"\"\"\n        agent_name = agent_name or public_id.name\n\n        if agent_name in self._agents:  # pragma: nocover\n            raise ValueError(f\"Agent with name {agent_name} already exists!\")\n\n        if public_id not in self._projects:  # pragma: nocover\n            raise ValueError(f\"{public_id} project is not added!\")\n\n        project = self._projects[public_id]\n\n        agent_alias = AgentAlias(\n            project=project,\n            agent_name=agent_name,\n            data_dir=self.get_data_dir_of_agent(agent_name),\n            password=self._password,\n        )\n        agent_alias.set_agent_config_from_data(config)\n        project.agents.add(agent_name)\n        self._agents[agent_name] = agent_alias\n        return self\n\n    def get_agent_overridables(self, agent_name: str) -> Tuple[Dict, List[Dict]]:\n        \"\"\"\n        Get agent config  overridables.\n\n        :param agent_name: str\n\n        :return: Tuple of agent overridables dict and  and list of component overridables dict.\n        \"\"\"\n        if agent_name not in self._agents:  # pragma: nocover\n            raise ValueError(f\"Agent with name {agent_name} does not exist!\")\n\n        return self._agents[agent_name].get_overridables()\n\n    def set_agent_overrides(\n        self,\n        agent_name: str,\n        agent_overides: Optional[Dict],\n        components_overrides: Optional[List[Dict]],\n    ) -> \"MultiAgentManager\":\n        \"\"\"\n        Set agent overrides.\n\n        :param agent_name: str\n        :param agent_overides: optional dict of agent config overrides\n        :param components_overrides: optional list of dict of components overrides\n        :return: self\n        \"\"\"\n        if agent_name not in self._agents:  # pragma: nocover\n            raise ValueError(f\"Agent with name {agent_name} does not exist!\")\n\n        if self._is_agent_running(agent_name):  # pragma: nocover\n            raise ValueError(\"Agent is running. stop it first!\")\n\n        self._agents[agent_name].set_overrides(agent_overides, components_overrides)\n        return self\n\n    def list_agents_info(self) -> List[Dict[str, Any]]:\n        \"\"\"\n        List agents detailed info.\n\n        :return: list of dicts that represents agent info: public_id, name, is_running.\n        \"\"\"\n        return [\n            {\n                \"agent_name\": agent_name,\n                \"public_id\": str(alias.project.public_id),\n                \"addresses\": alias.get_addresses(),\n                \"is_running\": self._is_agent_running(agent_name),\n            }\n            for agent_name, alias in self._agents.items()\n        ]\n\n    def list_agents(self, running_only: bool = False) -> List[str]:\n        \"\"\"\n        List all agents.\n\n        :param running_only: returns only running if set to True\n\n        :return: list of agents names\n        \"\"\"\n        if running_only:\n            return [i for i in self._agents.keys() if self._is_agent_running(i)]\n        return list(self._agents.keys())\n\n    def remove_agent(\n        self, agent_name: str, skip_project_auto_remove: bool = False\n    ) -> \"MultiAgentManager\":\n        \"\"\"\n        Remove agent alias definition from registry.\n\n        :param agent_name: agent name to remove\n        :param skip_project_auto_remove: disable auto project remove on last agent removed.\n\n        :return: None\n        \"\"\"\n        if agent_name not in self._agents:\n            raise ValueError(f\"Agent with name {agent_name} does not exist!\")\n\n        if self._is_agent_running(agent_name):\n            raise ValueError(\"Agent is running. stop it first!\")\n\n        agent_alias = self._agents.pop(agent_name)\n        agent_alias.remove_from_project()\n        project: Project = agent_alias.project\n\n        if (\n            not project.agents\n            and self._auto_add_remove_project\n            and not skip_project_auto_remove\n        ):\n            self.remove_project(project.public_id, keep_files=False)\n\n        return self\n\n    def start_agent(self, agent_name: str) -> \"MultiAgentManager\":\n        \"\"\"\n        Start selected agent.\n\n        :param agent_name: agent name to start\n\n        :return: None\n        \"\"\"\n        if not self._loop or not self._event:  # pragma: nocover\n            raise ValueError(\"agent is not started!\")\n\n        agent_alias = self._agents.get(agent_name)\n\n        if not agent_alias:\n            raise ValueError(f\"{agent_name} is not registered!\")\n\n        if self._is_agent_running(agent_name):\n            raise ValueError(f\"{agent_name} is already started!\")\n\n        event = threading.Event()\n        self._loop.call_soon_threadsafe(\n            self._make_agent_task, agent_name, agent_alias, event\n        )\n        event.wait(30)  # if something goes wrong\n        del event\n\n        self._loop.call_soon_threadsafe(self._event.set)\n        return self\n\n    def _make_agent_task(\n        self, agent_name: str, agent_alias: AgentAlias, event: threading.Event\n    ) -> None:\n        \"\"\"Create and start agent task.\"\"\"\n        task_cls = self._MODE_TASK_CLASS[self._mode]\n        if self._mode == MULTIPROCESS_MODE:\n            task = task_cls(agent_alias, self._loop)\n        else:\n            agent = agent_alias.get_aea_instance()\n            task = task_cls(agent, self._loop)\n\n        self._agents_tasks[agent_name] = task\n        task.start()\n        event.set()\n\n    def _is_agent_running(self, agent_name: str) -> bool:\n        \"\"\"Return is agent task in running state.\"\"\"\n        if agent_name not in self._agents_tasks:\n            return False\n\n        task = self._agents_tasks[agent_name]\n        return task.is_running\n\n    def start_all_agents(self) -> \"MultiAgentManager\":\n        \"\"\"\n        Start all not started agents.\n\n        :return: None\n        \"\"\"\n        self.start_agents(\n            [\n                agent_name\n                for agent_name in self.list_agents()\n                if not self._is_agent_running(agent_name)\n            ]\n        )\n        return self\n\n    def stop_agent(self, agent_name: str) -> \"MultiAgentManager\":\n        \"\"\"\n        Stop running agent.\n\n        :param agent_name: agent name to stop\n\n        :return: self\n        \"\"\"\n        if not self._is_agent_running(agent_name) or not self._thread or not self._loop:\n            raise ValueError(f\"{agent_name} is not running!\")\n\n        agent_task = self._agents_tasks[agent_name]\n\n        if self._thread.ident == threading.get_ident():  # pragma: nocover\n            # In same thread do not perform blocking operations!\n            agent_task.stop()\n            return self\n\n        wait_future = agent_task.wait()\n\n        event = threading.Event()\n\n        def event_set(*args: Any) -> None:  # pylint: disable=unused-argument\n            event.set()\n\n        def _add_cb() -> None:\n            if wait_future.done():\n                event_set()  # pragma: nocover\n            else:\n                wait_future.add_done_callback(event_set)  # pragma: nocover\n\n        self._loop.call_soon_threadsafe(_add_cb)\n        agent_task.stop()\n        event.wait(self.DEFAULT_TIMEOUT_FOR_BLOCKING_OPERATIONS)\n\n        if agent_task.is_running:  # pragma: nocover\n            raise ValueError(f\"cannot stop task of agent {agent_name}\")\n\n        return self\n\n    def stop_all_agents(self) -> \"MultiAgentManager\":\n        \"\"\"\n        Stop all agents running.\n\n        :return: self\n        \"\"\"\n        agents_list = self.list_agents(running_only=True)\n        self.stop_agents(agents_list)\n\n        return self\n\n    def stop_agents(self, agent_names: List[str]) -> \"MultiAgentManager\":\n        \"\"\"\n        Stop specified agents.\n\n        :param agent_names: names of agents\n        :return: self\n        \"\"\"\n        for agent_name in agent_names:\n            if not self._is_agent_running(agent_name):\n                raise ValueError(f\"{agent_name} is not running!\")\n\n        for agent_name in agent_names:\n            self.stop_agent(agent_name)\n\n        return self\n\n    def start_agents(self, agent_names: List[str]) -> \"MultiAgentManager\":\n        \"\"\"\n        Stop specified agents.\n\n        :param agent_names: names of agents\n        :return: self\n        \"\"\"\n        for agent_name in agent_names:\n            self.start_agent(agent_name)\n\n        return self\n\n    def get_agent_alias(self, agent_name: str) -> AgentAlias:\n        \"\"\"\n        Return details about agent alias definition.\n\n        :param agent_name: name of agent\n        :return: AgentAlias\n        \"\"\"\n        if agent_name not in self._agents:  # pragma: nocover\n            raise ValueError(f\"Agent with name {agent_name} does not exist!\")\n        return self._agents[agent_name]\n\n    def _ensure_working_dir(self) -> None:\n        \"\"\"Create working dir if needed.\"\"\"\n        if not os.path.exists(self.working_dir):\n            os.makedirs(self.working_dir)\n            self._was_working_dir_created = True\n\n        if not os.path.isdir(self.working_dir):  # pragma: nocover\n            raise ValueError(f\"{self.working_dir} is not a directory!\")\n        if not os.path.exists(self.data_dir):\n            os.makedirs(self.data_dir)\n\n    def _load_state(\n        self, local: bool, remote: bool\n    ) -> Tuple[\n        bool,\n        Dict[PublicId, List[Dict]],\n        List[Tuple[PublicId, List[Dict], Exception]],\n    ]:\n        \"\"\"\n        Load saved state from file.\n\n        Fetch agent project and all dependencies to working_dir.\n\n        If local = False and remote = False, then the packages\n        are fetched in mixed mode (i.e. first try from local\n        registry, and then from remote registry in case of failure).\n\n        :param local: whether or not to fetch from local registry.\n        :param remote: whether or not to fetch from remote registry.\n\n        :return: Tuple of bool indicating load success, settings of loaded, list of failed\n        :raises: ValueError if failed to load state.\n        \"\"\"\n        if not os.path.exists(self._save_path):\n            return False, {}, []\n\n        save_json = {}\n        with open_file(self._save_path) as f:\n            save_json = json.load(f)\n\n        if not save_json:\n            return False, {}, []  # pragma: nocover\n\n        projects_agents: Dict[PublicId, List] = defaultdict(list)\n\n        for agent_settings in save_json[\"agents\"]:\n            projects_agents[PublicId.from_str(agent_settings[\"public_id\"])].append(\n                agent_settings\n            )\n\n        failed_to_load: List[Tuple[PublicId, List[Dict], Exception]] = []\n        loaded_ok: Dict[PublicId, List[Dict]] = {}\n        for project_public_id, agents_settings in projects_agents.items():\n            try:\n                self.add_project(\n                    project_public_id,\n                    local=local,\n                    remote=remote,\n                    restore=True,\n                )\n            except ProjectCheckError as e:\n                failed_to_load.append((project_public_id, agents_settings, e))\n                break\n\n            for agent_settings in agents_settings:\n                self.add_agent_with_config(\n                    public_id=PublicId.from_str(agent_settings[\"public_id\"]),\n                    agent_name=agent_settings[\"agent_name\"],\n                    config=agent_settings[\"config\"],\n                )\n\n            loaded_ok[project_public_id] = agents_settings\n\n        return True, loaded_ok, failed_to_load\n\n    def _save_state(self) -> None:\n        \"\"\"Save MultiAgentManager state.\"\"\"\n        with open_file(self._save_path, \"w\") as f:\n            json.dump(self.dict_state, f, indent=4, sort_keys=True)\n\n    def _default_error_callback(\n        self, agent_name: str, exception: BaseException\n    ) -> None:\n        \"\"\"\n        Handle errors from running agents.\n\n        This is the default error callback. To replace it\n        with another one, use the method 'add_error_callback'.\n\n        :param agent_name: the agent name\n        :param exception: the caught exception\n        \"\"\"\n        self._print_exception_occurred_but_no_error_callback(agent_name, exception)\n\n    def _print_exception_occurred_but_no_error_callback(\n        self, agent_name: str, exception: BaseException\n    ) -> None:\n        \"\"\"\n        Print a warning message when an exception occurred but no error callback is registered.\n\n        :param agent_name: the agent name.\n        :param exception: the caught exception.\n        \"\"\"\n        if self._warning_message_printed_for_agent.get(agent_name, False):\n            return  # pragma: nocover\n        self._warning_message_printed_for_agent[agent_name] = True\n        print(\n            f\"WARNING: An exception occurred during the execution of agent '{agent_name}':\\n\",\n            str(exception),\n            repr(exception),\n            \"\\nHowever, since no error callback was found the exception is handled silently. Please \"\n            \"add an error callback using the method 'add_error_callback' of the MultiAgentManager instance.\",\n        )\n\n    def _check_version_consistency(self, agent_config: AgentConfig) -> None:\n        \"\"\"\n        Check that the agent dependencies in input are consistent with the other projects.\n\n        :param agent_config: the agent configuration we are going to add.\n        :return: None\n        :raises ProjectPackageConsistencyCheckError: if a version conflict is detected.\n        \"\"\"\n        existing_packages = set(self._package_id_prefix_to_version.keys())\n        prefix_to_version = {\n            component_id.component_prefix: component_id.version\n            for component_id in agent_config.package_dependencies\n        }\n        component_prefixes_to_be_added = set(prefix_to_version.keys())\n\n        potentially_conflicting_packages = existing_packages.intersection(\n            component_prefixes_to_be_added\n        )\n        if len(potentially_conflicting_packages) == 0:\n            return\n\n        # conflicting_packages is a list of tuples whose elements are:\n        # - package id prefix: the triple (component type, author, name)\n        # - current_version: the version currently present in the MAM, across all projects\n        # - new_version: the version of the package in the new project\n        # - agents: the set of agents in the MAM that have the package;\n        #           used to provide a better error message\n        conflicting_packages: List[Tuple[PackageIdPrefix, str, str, Set[PublicId]]] = []\n        for package_prefix in potentially_conflicting_packages:\n            existing_version, agents = self._package_id_prefix_to_version[\n                package_prefix\n            ]\n            new_version = prefix_to_version[package_prefix]\n            if existing_version != new_version:\n                conflicting_packages.append(\n                    (package_prefix, existing_version, new_version, agents)\n                )\n\n        if len(conflicting_packages) == 0:\n            return\n\n        raise ProjectPackageConsistencyCheckError(\n            agent_config.public_id, conflicting_packages\n        )\n\n    def _add_new_package_versions(self, agent_config: AgentConfig) -> None:\n        \"\"\"\n        Add new package versions.\n\n        This method is called whenever a project agent is added.\n        It updates an internal data structure that it is used to\n        check inconsistencies of AEA package versions across projects.\n        In particular, all the AEA packages with the same \"prefix\" must\n        be of the same version.\n\n        :param agent_config: the agent configuration.\n        \"\"\"\n        for component_id in agent_config.package_dependencies:\n            if component_id.component_prefix not in self._package_id_prefix_to_version:\n                self._package_id_prefix_to_version[component_id.component_prefix] = (\n                    component_id.version,\n                    set(),\n                )\n            version, agents = self._package_id_prefix_to_version[\n                component_id.component_prefix\n            ]\n            enforce(\n                version == component_id.version,\n                f\"internal consistency error: expected version '{version}', found {component_id.version}\",\n            )\n            agents.add(agent_config.public_id)\n\n    def _remove_package_versions(self, agent_config: AgentConfig) -> None:\n        \"\"\"\n        Remove package versions.\n\n        This method is called whenever a project agent is removed.\n        It updates an internal data structure that it is used to\n        check inconsistencies of AEA package versions across projects.\n        In particular, all the AEA packages with the same \"prefix\" must\n        be of the same version.\n\n        :param agent_config: the agent configuration.\n        \"\"\"\n        package_prefix_to_remove = set()\n        for (\n            package_prefix,\n            (_version, agents),\n        ) in self._package_id_prefix_to_version.items():\n            if agent_config.public_id in agents:\n                agents.remove(agent_config.public_id)\n                if len(agents) == 0:\n                    package_prefix_to_remove.add(package_prefix)\n\n        for package_prefix in package_prefix_to_remove:\n            self._package_id_prefix_to_version.pop(package_prefix)\n"
  },
  {
    "path": "aea/manager/project.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the implementation of AEA agents project configuration.\"\"\"\nimport os\nfrom copy import deepcopy\nfrom pathlib import Path\nfrom shutil import rmtree\nfrom typing import Any, Dict, List, Optional, Set, Tuple, Union\n\nfrom aea.aea import AEA\nfrom aea.aea_builder import AEABuilder\nfrom aea.cli.fetch import do_fetch\nfrom aea.cli.issue_certificates import issue_certificates_\nfrom aea.cli.utils.context import Context\nfrom aea.configurations.base import AgentConfig, PublicId\nfrom aea.configurations.constants import DEFAULT_REGISTRY_NAME\nfrom aea.configurations.data_types import ComponentId\nfrom aea.configurations.manager import AgentConfigManager\nfrom aea.crypto.helpers import create_private_key, get_wallet_from_agent_config\nfrom aea.exceptions import AEAValidationError, enforce\n\n\nclass _Base:\n    \"\"\"Base class to share some methods.\"\"\"\n\n    @classmethod\n    def _get_agent_config(cls, path: Union[Path, str]) -> AgentConfig:\n        \"\"\"Get agent config instance.\"\"\"\n        agent_config = AEABuilder.try_to_load_agent_configuration_file(path)\n        agent_config.check_aea_version()\n        return agent_config\n\n    @classmethod\n    def _get_builder(\n        cls,\n        agent_config: AgentConfig,\n        aea_project_path: Union[Path, str],\n        skip_consistency_check: bool = False,\n    ) -> AEABuilder:\n        \"\"\"Get AEABuilder instance.\"\"\"\n        builder = AEABuilder(\n            with_default_packages=False, build_dir_root=str(aea_project_path)\n        )\n        builder.set_from_configuration(\n            agent_config, Path(aea_project_path), skip_consistency_check\n        )\n        return builder\n\n    @property\n    def builder(self) -> AEABuilder:\n        \"\"\"Get AEABuilder instance.\"\"\"\n        raise NotImplementedError  # pragma: nocover\n\n    def install_pypi_dependencies(self) -> None:\n        \"\"\"Install python dependencies for the project.\"\"\"\n        self.builder.install_pypi_dependencies()\n\n\nclass Project(_Base):\n    \"\"\"Agent project representation.\"\"\"\n\n    __slots__ = (\"public_id\", \"path\", \"agents\")\n\n    def __init__(self, public_id: PublicId, path: str) -> None:\n        \"\"\"Init project with public_id and project's path.\"\"\"\n        self.public_id: PublicId = public_id\n        self.path: str = path\n        self.agents: Set[str] = set()\n\n    def build(self) -> None:\n        \"\"\"Call all build entry points.\"\"\"\n        self.builder.call_all_build_entrypoints()\n\n    @classmethod\n    def load(\n        cls,\n        working_dir: str,\n        public_id: PublicId,\n        is_local: bool = False,\n        is_remote: bool = False,\n        is_restore: bool = False,\n        cli_verbosity: str = \"INFO\",\n        registry_path: str = DEFAULT_REGISTRY_NAME,\n        skip_consistency_check: bool = False,\n        skip_aea_validation: bool = False,\n    ) -> \"Project\":\n        \"\"\"\n        Load project with given public_id to working_dir.\n\n        If local = False and remote = False, then the packages\n        are fetched in mixed mode (i.e. first try from local\n        registry, and then from remote registry in case of failure).\n\n        :param working_dir: the working directory\n        :param public_id: the public id\n        :param is_local: whether to fetch from local\n        :param is_remote: whether to fetch from remote\n        :param is_restore: whether to restore or not\n        :param cli_verbosity: the logging verbosity of the CLI\n        :param registry_path: the path to the registry locally\n        :param skip_consistency_check: consistency checks flag\n        :param skip_aea_validation: aea validation flag\n        :return: project\n        \"\"\"\n        ctx = Context(\n            cwd=working_dir, verbosity=cli_verbosity, registry_path=registry_path\n        )\n        ctx.set_config(\"skip_consistency_check\", skip_consistency_check)\n        ctx.set_config(\"skip_aea_validation\", skip_aea_validation)\n\n        path = os.path.join(working_dir, public_id.author, public_id.name)\n        target_dir = os.path.join(public_id.author, public_id.name)\n\n        if not is_restore and not os.path.exists(target_dir):\n            do_fetch(ctx, public_id, is_local, is_remote, target_dir=target_dir)\n        return cls(public_id, path)\n\n    def remove(self) -> None:\n        \"\"\"Remove project, do cleanup.\"\"\"\n        rmtree(self.path)\n\n    @property\n    def agent_config(self) -> AgentConfig:\n        \"\"\"Get the agent configuration.\"\"\"\n        return self._get_agent_config(self.path)\n\n    @property\n    def builder(self) -> AEABuilder:\n        \"\"\"Get builder instance.\"\"\"\n        return self._get_builder(self.agent_config, self.path)\n\n    def check(self) -> None:\n        \"\"\"Check we can still construct an AEA from the project with builder.build.\"\"\"\n        _ = self.builder\n\n\nclass AgentAlias(_Base):\n    \"\"\"Agent alias representation.\"\"\"\n\n    __slots__ = (\"project\", \"agent_name\", \"_data_dir\", \"_agent_config\")\n\n    def __init__(\n        self,\n        project: Project,\n        agent_name: str,\n        data_dir: str,\n        password: Optional[str] = None,\n    ):\n        \"\"\"Init agent alias with project, config, name, agent, builder.\"\"\"\n        self.project = project\n        self.agent_name = agent_name\n        self._data_dir = data_dir\n        if not os.path.exists(self._data_dir):\n            os.makedirs(self._data_dir)\n        self._agent_config: AgentConfig = self._get_agent_config(project.path)\n        self._password = password\n        self._ensure_private_keys()\n\n    def set_agent_config_from_data(self, json_data: List[Dict]) -> None:\n        \"\"\"\n        Set agent config instance constructed from json data.\n\n        :param json_data: agent config json data\n        \"\"\"\n        self._agent_config = AEABuilder.loader.load_agent_config_from_json(json_data)\n        self._ensure_private_keys()\n\n    def _ensure_private_keys(self) -> None:\n        \"\"\"Add private keys if not present in the config.\"\"\"\n        builder = self._get_builder(self.agent_config, self.project.path)\n        default_ledger = builder.get_default_ledger()\n        required_ledgers = builder.get_required_ledgers()\n        enforce(\n            default_ledger in required_ledgers,\n            exception_text=f\"Default ledger '{default_ledger}' not in required ledgers: {required_ledgers}\",\n            exception_class=AEAValidationError,\n        )\n\n        available_private_keys = self.agent_config.private_key_paths.keys()\n        available_connection_private_keys = (\n            self.agent_config.connection_private_key_paths.keys()\n        )\n\n        for required_ledger in set(required_ledgers):\n            if required_ledger not in available_private_keys:\n                self.agent_config.private_key_paths.create(\n                    required_ledger, self._create_private_key(required_ledger)\n                )\n            if required_ledger not in available_connection_private_keys:\n                self.agent_config.connection_private_key_paths.create(\n                    required_ledger,\n                    self._create_private_key(required_ledger, is_connection=True),\n                )\n\n    @property\n    def builder(self) -> AEABuilder:\n        \"\"\"Get builder instance.\"\"\"\n        builder = self._get_builder(self.agent_config, self.project.path)\n        builder.set_name(self.agent_name)\n        builder.set_runtime_mode(\"threaded\")\n        builder.set_data_dir(self._data_dir)\n        return builder\n\n    @property\n    def agent_config(self) -> AgentConfig:\n        \"\"\"Get agent config.\"\"\"\n        return self._agent_config\n\n    def _create_private_key(\n        self,\n        ledger: str,\n        replace: bool = False,\n        is_connection: bool = False,\n    ) -> str:\n        \"\"\"\n        Create new key for agent alias in working dir keys dir.\n\n        If file exists, check `replace` option.\n\n        :param ledger: the ledger id\n        :param replace: whether or not to replace an existing key\n        :param is_connection: whether or not it is a connection key\n        :return: file path to private key\n        \"\"\"\n        file_name = (\n            f\"{ledger}_connection_private.key\"\n            if is_connection\n            else f\"{ledger}_private.key\"\n        )\n        filepath = os.path.join(self._data_dir, file_name)\n        if os.path.exists(filepath) and not replace:\n            return filepath\n        create_private_key(ledger, filepath, password=self._password)\n        return filepath\n\n    def remove_from_project(self) -> None:\n        \"\"\"Remove agent alias from project.\"\"\"\n        self.project.agents.remove(self.agent_name)\n\n    @property\n    def dict(self) -> Dict[str, Any]:\n        \"\"\"Convert AgentAlias to dict.\"\"\"\n        return {\n            \"public_id\": str(self.project.public_id),\n            \"agent_name\": self.agent_name,\n            \"config\": self.config_json,\n        }\n\n    @property\n    def config_json(self) -> List[Dict]:\n        \"\"\"Get agent config json data.\"\"\"\n        json_data = self.agent_config.ordered_json\n        result: List[Dict] = [json_data] + json_data.pop(\"component_configurations\", {})\n        return result\n\n    def get_aea_instance(self) -> AEA:\n        \"\"\"Build new aea instance.\"\"\"\n        self.issue_certificates()\n        aea = self.builder.build(password=self._password)\n        # override build dir to project's one\n        aea.DEFAULT_BUILD_DIR_NAME = os.path.join(\n            self.project.path, aea.DEFAULT_BUILD_DIR_NAME\n        )\n        return aea\n\n    def issue_certificates(self) -> None:\n        \"\"\"Issue the certificates for this agent.\"\"\"\n        issue_certificates_(\n            self.project.path,\n            self.agent_config_manager,\n            path_prefix=self._data_dir,\n            password=self._password,\n        )\n\n    def set_overrides(\n        self,\n        agent_overrides: Optional[Dict] = None,\n        component_overrides: Optional[List[Dict]] = None,\n    ) -> None:\n        \"\"\"Set override for this agent alias's config.\"\"\"\n        overrides = deepcopy(agent_overrides or {})\n        component_configurations: Dict[ComponentId, Dict] = {}\n\n        for component_override in deepcopy(component_overrides or []):\n            try:\n                component_id = ComponentId.from_json(\n                    {\"version\": \"any\", **component_override}\n                )\n                component_override.pop(\"author\")\n                component_override.pop(\"name\")\n                component_override.pop(\"type\")\n                component_override.pop(\"version\")\n                component_configurations[component_id] = component_override\n            except (ValueError, KeyError) as e:  # pragma: nocover\n                raise ValueError(\n                    f\"Component overrides are incorrect: {e} during process: {component_override}\"\n                )\n\n        overrides[\"component_configurations\"] = component_configurations\n        self.agent_config_manager.update_config(overrides)\n        if agent_overrides:\n            self._ensure_private_keys()\n\n    @property\n    def agent_config_manager(self) -> AgentConfigManager:\n        \"\"\"Get agent configuration manager instance for the config.\"\"\"\n        return AgentConfigManager(self.agent_config, self.project.path)\n\n    def get_overridables(self) -> Tuple[Dict, List[Dict]]:\n        \"\"\"Get all overridables for this agent alias's config.\"\"\"\n        (\n            agent_overridables,\n            components_overridables,\n        ) = self.agent_config_manager.get_overridables()\n        components_configurations = []\n        for component_id, obj in components_overridables.items():\n            if not obj:  # pragma: nocover\n                continue\n            obj.update(component_id.json)\n            components_configurations.append(obj)\n\n        return agent_overridables, components_configurations\n\n    def get_addresses(self) -> Dict[str, str]:\n        \"\"\"\n        Get addresses from private keys.\n\n        :return: dict with crypto id str as key and address str as value\n        \"\"\"\n        wallet = get_wallet_from_agent_config(\n            self.agent_config, password=self._password\n        )\n        return wallet.addresses\n\n    def get_connections_addresses(self) -> Dict[str, str]:\n        \"\"\"\n        Get connections addresses from connections private keys.\n\n        :return: dict with crypto id str as key and address str as value\n        \"\"\"\n        wallet = get_wallet_from_agent_config(\n            self.agent_config, password=self._password\n        )\n        return wallet.connection_cryptos.addresses\n"
  },
  {
    "path": "aea/manager/utils.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Multiagent manager utils.\"\"\"\nimport datetime\nimport multiprocessing\nimport os\nimport sys\nimport time\nimport venv  # type: ignore\nfrom traceback import format_exc\nfrom typing import Any, Callable\n\nfrom aea.crypto.plugin import load_all_plugins\nfrom aea.manager.project import Project\n\n\ndef get_lib_path(env_dir: str) -> str:\n    \"\"\"Get librarty path for env dir.\"\"\"\n    if sys.platform == \"win32\":  # pragma: nocover\n        libpath = os.path.join(env_dir, \"Lib\", \"site-packages\")\n    else:  # pragma: nocover\n        libpath = os.path.join(\n            env_dir, \"lib\", \"python%d.%d\" % sys.version_info[:2], \"site-packages\"\n        )\n    return libpath\n\n\ndef make_venv(env_dir: str, set_env: bool = False) -> None:\n    \"\"\"\n    Make venv and update variable to use it.\n\n    :param env_dir: str, path for new env dir\n    :param set_env: bool. use evn within this python process (update, sys.executable and sys.path)\n    \"\"\"\n    builder = venv.EnvBuilder(True, clear=True)\n    ctx = builder.ensure_directories(env_dir)\n    builder.create(env_dir)\n    if set_env:  # pragma: nocover\n        sys.executable = ctx.env_exe\n        sys.path.insert(0, get_lib_path(env_dir))\n\n\ndef project_install_and_build(project: Project) -> None:\n    \"\"\"Install project dependencies and build required components.\"\"\"\n    project.install_pypi_dependencies()\n    load_all_plugins(is_raising_exception=False)\n    project.build()\n\n\ndef get_venv_dir_for_project(project: Project) -> str:\n    \"\"\"Get virtual env directory for project specified.\"\"\"\n    return os.path.join(project.path, \"venv\")\n\n\ndef project_check(project: Project) -> None:\n    \"\"\"Perform project loads well.\"\"\"\n    project.check()\n\n\ndef run_in_venv(env_dir: str, fn: Callable, timeout: float, *args: Any) -> Any:\n    \"\"\"Run python function in a dedicated process with virtual env specified.\"\"\"\n    manager = multiprocessing.Manager()\n    result_queue = manager.Queue()\n    process = multiprocessing.Process(\n        target=_run_in_venv_handler,\n        args=tuple([env_dir, fn, result_queue] + list(args)),\n    )\n    process.start()\n    start_time = time.time()\n    while process.is_alive():\n        time.sleep(0.005)\n        if timeout != 0 and (time.time() - start_time > timeout):  # pragma: nocover\n            process.terminate()\n            process.join(5)\n            raise TimeoutError()\n    process.join(5)\n    result = result_queue.get_nowait()\n    if isinstance(result, BaseException):\n        raise result\n    return result\n\n\ndef _run_in_venv_handler(\n    env_dir: str, fn: Callable, queue: multiprocessing.Queue, *args: Any\n) -> None:\n    \"\"\"Do actual function run in a dedicated process within virtual env.\"\"\"\n    result = None\n    try:\n        make_venv(env_dir, set_env=True)\n        result = fn(*args)\n    except Exception as e:  # pylint: disable=broad-except\n        print(\n            f\"Exception in venv runner at {datetime.datetime.now()} for {fn}:\\n{format_exc()}\"\n        )\n        result = e\n    queue.put_nowait(result)\n"
  },
  {
    "path": "aea/multiplexer.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Module for the multiplexer class and related classes.\"\"\"\nimport asyncio\nimport queue\nimport threading\nfrom asyncio.events import AbstractEventLoop\nfrom concurrent.futures._base import CancelledError\nfrom concurrent.futures._base import TimeoutError as FuturesTimeoutError\nfrom contextlib import suppress\nfrom typing import (\n    Any,\n    Callable,\n    Collection,\n    Dict,\n    List,\n    Optional,\n    Sequence,\n    Tuple,\n    Union,\n    cast,\n)\n\nfrom aea.common import Address\nfrom aea.configurations.base import PublicId\nfrom aea.connections.base import Connection, ConnectionStates\nfrom aea.exceptions import enforce\nfrom aea.helpers.async_friendly_queue import AsyncFriendlyQueue\nfrom aea.helpers.async_utils import AsyncState, Runnable, ThreadedAsyncRunner\nfrom aea.helpers.exception_policy import ExceptionPolicyEnum\nfrom aea.helpers.logging import WithLogger, get_logger\nfrom aea.mail.base import AEAConnectionError, Empty, Envelope, EnvelopeContext\nfrom aea.protocols.base import Message, Protocol\n\n\nclass MultiplexerStatus(AsyncState):\n    \"\"\"The connection status class.\"\"\"\n\n    def __init__(self) -> None:\n        \"\"\"Initialize the connection status.\"\"\"\n        super().__init__(\n            initial_state=ConnectionStates.disconnected, states_enum=ConnectionStates\n        )\n\n    @property\n    def is_connected(self) -> bool:  # pragma: nocover\n        \"\"\"Return is connected.\"\"\"\n        return self.get() == ConnectionStates.connected\n\n    @property\n    def is_connecting(self) -> bool:  # pragma: nocover\n        \"\"\"Return is connecting.\"\"\"\n        return self.get() == ConnectionStates.connecting\n\n    @property\n    def is_disconnected(self) -> bool:  # pragma: nocover\n        \"\"\"Return is disconnected.\"\"\"\n        return self.get() == ConnectionStates.disconnected\n\n    @property\n    def is_disconnecting(self) -> bool:  # pragma: nocover\n        \"\"\"Return is disconnected.\"\"\"\n        return self.get() == ConnectionStates.disconnecting\n\n\nclass AsyncMultiplexer(Runnable, WithLogger):\n    \"\"\"This class can handle multiple connections at once.\"\"\"\n\n    DISCONNECT_TIMEOUT = 5\n    CONNECT_TIMEOUT = 60\n    SEND_TIMEOUT = 60\n\n    _lock: asyncio.Lock\n\n    def __init__(\n        self,\n        connections: Optional[Sequence[Connection]] = None,\n        default_connection_index: int = 0,\n        loop: Optional[AbstractEventLoop] = None,\n        exception_policy: ExceptionPolicyEnum = ExceptionPolicyEnum.propagate,\n        threaded: bool = False,\n        agent_name: str = \"standalone\",\n        default_routing: Optional[Dict[PublicId, PublicId]] = None,\n        default_connection: Optional[PublicId] = None,\n        protocols: Optional[List[Union[Protocol, Message]]] = None,\n    ) -> None:\n        \"\"\"\n        Initialize the connection multiplexer.\n\n        :param connections: a sequence of connections.\n        :param default_connection_index: the index of the connection to use as default.\n            This information is used for envelopes which don't specify any routing context.\n            If connections is None, this parameter is ignored.\n        :param loop: the event loop to run the multiplexer. If None, a new event loop is created.\n        :param exception_policy: the exception policy used for connections.\n        :param threaded: if True, run in threaded mode, else async\n        :param agent_name: the name of the agent that owns the multiplexer, for logging purposes.\n        :param default_routing: default routing map\n        :param default_connection: default connection\n        :param protocols: protocols used\n        \"\"\"\n        self._exception_policy: ExceptionPolicyEnum = exception_policy\n        logger = get_logger(__name__, agent_name)\n        WithLogger.__init__(self, logger=logger)\n        Runnable.__init__(self, loop=loop, threaded=threaded)\n\n        self._connections: List[Connection] = []\n        self._id_to_connection: Dict[PublicId, Connection] = {}\n        self._default_connection: Optional[Connection] = None\n\n        connections = connections or []\n        if not default_connection and connections:\n            enforce(\n                len(connections) - 1 >= default_connection_index,\n                \"default_connection_index os out of connections range!\",\n            )\n            default_connection = connections[default_connection_index].connection_id\n\n        if default_connection:\n            enforce(\n                bool(\n                    [\n                        i.connection_id.same_prefix(default_connection)\n                        for i in connections\n                    ]\n                ),\n                f\"Default connection {default_connection} does not present in connections list!\",\n            )\n\n        self._default_routing = {}  # type: Dict[PublicId, PublicId]\n\n        self._setup(connections or [], default_routing, default_connection)\n\n        self._connection_status = MultiplexerStatus()\n        self._specification_id_to_protocol_id = {\n            p.protocol_specification_id: p.protocol_id for p in protocols or []\n        }\n        self._routing_helper: Dict[Address, PublicId] = {}\n\n        self._in_queue = AsyncFriendlyQueue()  # type: AsyncFriendlyQueue\n        self._out_queue = None  # type: Optional[asyncio.Queue]\n\n        self._recv_loop_task = None  # type: Optional[asyncio.Task]\n        self._send_loop_task = None  # type: Optional[asyncio.Task]\n\n        self._loop: asyncio.AbstractEventLoop = (\n            loop if loop is not None else asyncio.new_event_loop()\n        )\n        self.set_loop(self._loop)\n\n    @property\n    def default_connection(self) -> Optional[Connection]:\n        \"\"\"Get the default connection.\"\"\"\n        return self._default_connection\n\n    @property\n    def in_queue(self) -> AsyncFriendlyQueue:\n        \"\"\"Get the in queue.\"\"\"\n        return self._in_queue\n\n    @property\n    def out_queue(self) -> asyncio.Queue:\n        \"\"\"Get the out queue.\"\"\"\n        if self._out_queue is None:  # pragma: nocover\n            raise ValueError(\"Accessing out queue before loop is started.\")\n        return self._out_queue\n\n    @property\n    def connections(self) -> Tuple[Connection, ...]:\n        \"\"\"Get the connections.\"\"\"\n        return tuple(self._connections)\n\n    @property\n    def is_connected(self) -> bool:\n        \"\"\"Check whether the multiplexer is processing envelopes.\"\"\"\n        return self.connection_status.is_connected\n\n    @property\n    def default_routing(self) -> Dict[PublicId, PublicId]:\n        \"\"\"Get the default routing.\"\"\"\n        return self._default_routing\n\n    @default_routing.setter\n    def default_routing(self, default_routing: Dict[PublicId, PublicId]) -> None:\n        \"\"\"Set the default routing.\"\"\"\n        self._default_routing = default_routing\n\n    @property\n    def connection_status(self) -> MultiplexerStatus:\n        \"\"\"Get the connection status.\"\"\"\n        return self._connection_status\n\n    async def run(self) -> None:\n        \"\"\"Run multiplexer connect and receive/send tasks.\"\"\"\n        self.set_loop(asyncio.get_event_loop())\n        try:\n            await self.connect()\n\n            if not self._recv_loop_task or not self._send_loop_task:\n                raise ValueError(\"Multiplexer is not connected properly.\")\n\n            await asyncio.gather(self._recv_loop_task, self._send_loop_task)\n        finally:\n            await self.disconnect()\n\n    def _get_protocol_id_for_envelope(self, envelope: Envelope) -> PublicId:\n        \"\"\"Get protocol id for envelope.\"\"\"\n        if isinstance(envelope.message, Message):\n            return cast(Message, envelope.message).protocol_id\n\n        protocol_id = self._specification_id_to_protocol_id.get(\n            envelope.protocol_specification_id\n        )\n\n        if not protocol_id:\n            raise ValueError(\n                f\"Can not resolve protocol id for {envelope}, pass protocols supported to multipelxer instance {self._specification_id_to_protocol_id}\"\n            )\n\n        return protocol_id\n\n    def set_loop(self, loop: AbstractEventLoop) -> None:\n        \"\"\"\n        Set event loop and all event loop related objects.\n\n        :param loop: asyncio event loop.\n        \"\"\"\n        self._loop = loop\n        self._lock = asyncio.Lock()\n\n    def _handle_exception(self, fn: Callable, exc: Exception) -> None:\n        \"\"\"\n        Handle exception raised.\n\n        :param fn: a method where it raised .send .connect etc\n        :param exc:  exception\n        \"\"\"\n        if self._exception_policy == ExceptionPolicyEnum.just_log:\n            self.logger.exception(f\"Exception raised in {fn}\")\n        elif self._exception_policy == ExceptionPolicyEnum.propagate:\n            raise exc\n        elif self._exception_policy == ExceptionPolicyEnum.stop_and_exit:\n            self._loop.create_task(AsyncMultiplexer.disconnect(self))\n        else:  # pragma: nocover\n            raise ValueError(f\"Unknown exception policy: {self._exception_policy}\")\n\n    def add_connection(self, connection: Connection, is_default: bool = False) -> None:\n        \"\"\"\n        Add a connection to the multiplexer.\n\n        :param connection: the connection to add.\n        :param is_default: whether the connection added should be the default one.\n        \"\"\"\n        if connection.connection_id in self._id_to_connection:  # pragma: nocover\n            self.logger.warning(\n                f\"A connection with id {connection.connection_id} was already added. Replacing it...\"\n            )\n\n        self._connections.append(connection)\n        self._id_to_connection[connection.connection_id] = connection\n        if is_default:\n            self._default_connection = connection\n\n    def _connection_consistency_checks(self) -> None:\n        \"\"\"\n        Do some consistency checks on the multiplexer connections.\n\n        :raise AEAEnforceError: if an inconsistency is found.\n        \"\"\"\n        if len(self.connections) == 0:\n            self.logger.debug(\"List of connections is empty.\")\n\n        enforce(\n            len(set(c.connection_id for c in self.connections))\n            == len(self.connections),\n            \"Connection names must be unique.\",\n        )\n\n    def _set_default_connection_if_none(self) -> None:\n        \"\"\"Set the default connection if it is none.\"\"\"\n        if self._default_connection is None and bool(self.connections):\n            self._default_connection = self.connections[0]\n\n    async def connect(self) -> None:\n        \"\"\"Connect the multiplexer.\"\"\"\n        self._loop = asyncio.get_event_loop()\n        self.logger.debug(\"Multiplexer connecting...\")\n        self._connection_consistency_checks()\n        self._set_default_connection_if_none()\n        self._out_queue = asyncio.Queue()\n\n        async with self._lock:\n            if self.connection_status.is_connected:\n                self.logger.debug(\"Multiplexer already connected.\")\n                return\n            try:\n                self.connection_status.set(ConnectionStates.connecting)\n                await self._connect_all()\n\n                if all(c.is_connected for c in self._connections):\n                    self.connection_status.set(ConnectionStates.connected)\n                else:  # pragma: nocover\n                    raise AEAConnectionError(\"Failed to connect the multiplexer.\")\n\n                self._recv_loop_task = self._loop.create_task(self._receiving_loop())\n                self._send_loop_task = self._loop.create_task(self._send_loop())\n                self.logger.debug(\"Multiplexer connected and running.\")\n            except (CancelledError, asyncio.CancelledError):  # pragma: nocover\n                await self._stop()\n                raise asyncio.CancelledError()\n            except AEAConnectionError:\n                await self._stop()\n                raise\n            except Exception as e:\n                self.logger.exception(\"Exception on connect:\")\n                await self._stop()\n                raise AEAConnectionError(\n                    f\"Failed to connect the multiplexer: Error: {repr(e)}\"\n                ) from e\n\n    async def disconnect(self) -> None:\n        \"\"\"Disconnect the multiplexer.\"\"\"\n        self.logger.debug(\"Multiplexer disconnecting...\")\n        async with self._lock:\n            if self.connection_status.is_disconnected:\n                self.logger.debug(\"Multiplexer already disconnected.\")\n                return\n            try:\n                self.connection_status.set(ConnectionStates.disconnecting)\n                await asyncio.wait_for(self._stop(), timeout=60)\n                self.logger.debug(\"Multiplexer disconnected.\")\n            except CancelledError:  # pragma: nocover\n                self.logger.debug(\"Multiplexer.disconnect cancellation!\")\n                raise\n            except Exception as e:\n                self.logger.exception(\"Exception on disconnect:\")\n                raise AEAConnectionError(\n                    f\"Failed to disconnect the multiplexer: Error: {repr(e)}\"\n                ) from e\n\n    async def _stop_receive_send_loops(self) -> None:\n        \"\"\"Stop receive and send loops.\"\"\"\n        self.logger.debug(\"Stopping receive loop...\")\n\n        if self._recv_loop_task:\n            self._recv_loop_task.cancel()\n            with suppress(Exception, asyncio.CancelledError):\n                await self._recv_loop_task\n\n        self._recv_loop_task = None\n        self.logger.debug(\"Receive loop stopped.\")\n\n        self.logger.debug(\"Stopping send loop...\")\n\n        if self._send_loop_task:\n            # send a 'stop' token (a None value) to wake up the coroutine waiting for outgoing envelopes.\n            await self.out_queue.put(None)\n            self._send_loop_task.cancel()\n            with suppress(Exception, asyncio.CancelledError):\n                await self._send_loop_task\n\n        self._send_loop_task = None\n        self.logger.debug(\"Send loop stopped.\")\n\n    def _check_and_set_disconnected_state(self) -> None:\n        \"\"\"Check every connection is disconnected and set disconnected state.\"\"\"\n        if all((c.is_disconnected for c in self.connections)):\n            self.connection_status.set(ConnectionStates.disconnected)\n        else:\n            connections_left = [\n                str(c.connection_id) for c in self.connections if not c.is_disconnected\n            ]\n            raise AEAConnectionError(\n                f\"Failed to disconnect multiplexer, some connections are not disconnected within timeout: {', '.join(connections_left)}\"\n            )\n\n    async def _stop(self) -> None:\n        \"\"\"\n        Stop the multiplexer.\n\n        Stops receive and send loops.\n        Disconnect every connection.\n        \"\"\"\n        self.logger.debug(\"Stopping multiplexer...\")\n\n        await asyncio.wait_for(self._stop_receive_send_loops(), timeout=60)\n        await asyncio.wait_for(self._disconnect_all(), timeout=60)\n        self._check_and_set_disconnected_state()\n\n        self.logger.debug(\"Multiplexer stopped.\")\n\n    async def _connect_all(self) -> None:\n        \"\"\"Set all the connection up.\"\"\"\n        self.logger.debug(\"Starting multiplexer connections.\")\n        connected = []  # type: List[PublicId]\n        for connection_id, connection in self._id_to_connection.items():\n            try:\n                await asyncio.wait_for(\n                    self._connect_one(connection_id), timeout=self.CONNECT_TIMEOUT\n                )\n                connected.append(connection_id)\n            except Exception as e:  # pylint: disable=broad-except\n                if not isinstance(e, (asyncio.CancelledError, CancelledError)):\n                    self.logger.exception(\n                        \"Error while connecting {}: {}\".format(\n                            str(type(connection)), repr(e)\n                        )\n                    )\n                raise\n        self.logger.debug(\"Multiplexer connections are set.\")\n\n    async def _connect_one(self, connection_id: PublicId) -> None:\n        \"\"\"\n        Set a connection up.\n\n        :param connection_id: the id of the connection.\n        \"\"\"\n        connection = self._id_to_connection[connection_id]\n        self.logger.debug(\"Processing connection {}\".format(connection.connection_id))\n        if connection.is_connected:\n            self.logger.debug(\n                \"Connection {} already established.\".format(connection.connection_id)\n            )\n        else:\n            await connection.connect()\n            self.logger.debug(\n                \"Connection {} has been set up successfully.\".format(\n                    connection.connection_id\n                )\n            )\n\n    async def _disconnect_all(self) -> None:\n        \"\"\"Tear all the connections down.\"\"\"\n        self.logger.debug(\"Tear the multiplexer connections down.\")\n        for connection_id, connection in self._id_to_connection.items():\n            try:\n                await asyncio.wait_for(\n                    self._disconnect_one(connection_id), timeout=self.DISCONNECT_TIMEOUT\n                )\n            except FuturesTimeoutError:\n                self.logger.debug(  # pragma: nocover\n                    f\"Disconnection of `{connection_id}` timed out.\"\n                )\n            except Exception as e:  # pylint: disable=broad-except\n                self.logger.exception(\n                    \"Error while disconnecting {}: {}\".format(\n                        str(type(connection)), str(e)\n                    )\n                )\n\n    async def _disconnect_one(self, connection_id: PublicId) -> None:\n        \"\"\"\n        Tear a connection down.\n\n        :param connection_id: the id of the connection.\n        \"\"\"\n        connection = self._id_to_connection[connection_id]\n        self.logger.debug(\"Processing connection {}\".format(connection.connection_id))\n        if not connection.is_connected:\n            self.logger.debug(\n                \"Connection {} already disconnected.\".format(connection.connection_id)\n            )\n        else:\n            await connection.disconnect()\n            self.logger.debug(\n                \"Connection {} has been disconnected successfully.\".format(\n                    connection.connection_id\n                )\n            )\n\n    async def _send_loop(self) -> None:\n        \"\"\"Process the outgoing envelopes.\"\"\"\n        if not self.is_connected:\n            self.logger.debug(\n                \"Sending loop not started. The multiplexer is not connected.\"\n            )\n            return\n\n        try:\n            while self.is_connected:\n                self.logger.debug(\"Waiting for outgoing envelopes...\")\n                envelope = await self.out_queue.get()\n                if envelope is None:  # pragma: nocover\n                    self.logger.debug(\n                        \"Received empty envelope. Quitting the sending loop...\"\n                    )\n                    return None\n                self.logger.debug(\"Sending envelope {}\".format(str(envelope)))\n                await self._send(envelope)\n\n        except asyncio.CancelledError:\n            self.logger.debug(\"Sending loop cancelled.\")\n            raise\n        except Exception as e:  # pylint: disable=broad-except  # pragma: nocover\n            self.logger.exception(\"Error in the sending loop: {}\".format(str(e)))\n            raise\n\n    async def _receiving_loop(self) -> None:\n        \"\"\"Process incoming envelopes.\"\"\"\n        self.logger.debug(\"Starting receving loop...\")\n        task_to_connection = {\n            asyncio.ensure_future(conn.receive()): conn for conn in self.connections\n        }\n\n        try:\n            while self.connection_status.is_connected and len(task_to_connection) > 0:\n                done, _pending = await asyncio.wait(\n                    task_to_connection.keys(), return_when=asyncio.FIRST_COMPLETED\n                )\n\n                # process completed receiving tasks.\n                for task in done:\n                    connection = task_to_connection.pop(task)\n                    envelope = task.result()\n                    if envelope is not None:\n                        self._update_routing_helper(envelope, connection)\n                        self.in_queue.put_nowait(envelope)\n\n                    # reinstantiate receiving task, but only if the connection is still up.\n                    if connection.is_connected:\n                        new_task = asyncio.ensure_future(connection.receive())\n                        task_to_connection[new_task] = connection\n\n        except asyncio.CancelledError:  # pragma: nocover\n            self.logger.debug(\"Receiving loop cancelled.\")\n            raise\n        except Exception as e:  # pylint: disable=broad-except\n            self.logger.exception(\"Error in the receiving loop: {}\".format(str(e)))\n            raise\n        finally:\n            # cancel all the receiving tasks.\n            for t in task_to_connection.keys():\n                t.cancel()\n            self.logger.debug(\"Receiving loop terminated.\")\n\n    async def _send(self, envelope: Envelope) -> None:\n        \"\"\"\n        Send an envelope.\n\n        :param envelope: the envelope to send.\n        \"\"\"\n        envelope_protocol_id = self._get_protocol_id_for_envelope(envelope)\n        connection_id = self._get_connection_id_from_envelope(\n            envelope, envelope_protocol_id\n        )\n\n        connection = (\n            self._get_connection(connection_id) if connection_id is not None else None\n        )\n\n        if connection is None:\n            # we don't raise on dropping envelope as this can be a configuration issue only!\n            self.logger.warning(\n                f\"Dropping envelope, no connection available for sending: {envelope}\"\n            )\n            return\n\n        if not self._is_connection_supported_protocol(connection, envelope_protocol_id):\n            return\n\n        try:\n            await asyncio.wait_for(connection.send(envelope), timeout=self.SEND_TIMEOUT)\n        except Exception as e:  # pylint: disable=broad-except\n            self._handle_exception(self._send, e)\n\n    def _get_connection_id_from_envelope(\n        self, envelope: Envelope, envelope_protocol_id: PublicId\n    ) -> Optional[PublicId]:\n        \"\"\"\n        Get the connection id from an envelope.\n\n        Applies the following rules:\n        - component to component messages are routed by their component id\n        - agent to agent messages, are routed following four rules:\n            * first, try to route by envelope context connection id\n            * second, try to route by routing helper\n            * third, try to route by default routing\n            * forth, using default connection\n\n        :param envelope: the Envelope\n        :param envelope_protocol_id: the protocol id of the message contained in the envelope\n        :return: public id if found\n        \"\"\"\n        self.logger.debug(f\"Routing envelope: {envelope}\")\n        # component to component messages are routed by their component id\n        if envelope.is_component_to_component_message:\n            connection_id = envelope.to_as_public_id\n            self.logger.debug(\n                \"Using envelope `to` field as connection_id: {}\".format(connection_id)\n            )\n            enforce(\n                connection_id is not None,\n                \"Connection id cannot be None by envelope construction.\",\n            )\n            return connection_id\n\n        # agent to agent messages, are routed following four rules:\n        # first, try to route by envelope context connection id\n        if envelope.context is not None and envelope.context.connection_id is not None:\n            connection_id = envelope.context.connection_id\n            self.logger.debug(\n                \"Using envelope context connection_id: {}\".format(connection_id)\n            )\n            return connection_id\n\n        # second, try to route by routing helper\n        if envelope.to in self._routing_helper:\n            connection_id = self._routing_helper[envelope.to]\n            self.logger.debug(\n                \"Using routing helper with connection_id: {}\".format(connection_id)\n            )\n            return connection_id\n\n        # third, try to route by default routing\n        if envelope_protocol_id in self.default_routing:\n            connection_id = self.default_routing[envelope_protocol_id]\n            self.logger.debug(\"Using default routing: {}\".format(connection_id))\n            return connection_id\n\n        # forth, using default connection\n        connection_id = (\n            self.default_connection.connection_id\n            if self.default_connection is not None\n            else None\n        )\n        self.logger.debug(\"Using default connection: {}\".format(connection_id))\n        return connection_id\n\n    def _get_connection(self, connection_id: PublicId) -> Optional[Connection]:\n        \"\"\"Check if the connection id is registered.\"\"\"\n        conn_ = self._id_to_connection.get(connection_id, None)\n        if conn_ is not None:\n            return conn_\n        for id_, conn_ in self._id_to_connection.items():\n            if id_.same_prefix(connection_id):\n                return conn_\n        self.logger.error(f\"No connection registered with id: {connection_id}\")\n        return None\n\n    def _is_connection_supported_protocol(\n        self, connection: Connection, protocol_id: PublicId\n    ) -> bool:\n        \"\"\"Check protocol id is supported by the connection.\"\"\"\n        if protocol_id in connection.excluded_protocols:\n            self.logger.warning(\n                f\"Connection {connection.connection_id} does not support protocol {protocol_id}. It is explicitly excluded.\"\n            )\n            return False\n\n        if (\n            connection.restricted_to_protocols\n            and protocol_id not in connection.restricted_to_protocols\n        ):\n            self.logger.warning(\n                f\"Connection {connection.connection_id} does not support protocol {protocol_id}. The connection is restricted to protocols in {connection.restricted_to_protocols}.\"\n            )\n            return False\n\n        return True\n\n    def get(\n        self, block: bool = False, timeout: Optional[float] = None\n    ) -> Optional[Envelope]:\n        \"\"\"\n        Get an envelope within a timeout.\n\n        :param block: make the call blocking (ignore the timeout).\n        :param timeout: the timeout to wait until an envelope is received.\n        :return: the envelope, or None if no envelope is available within a timeout.\n        \"\"\"\n        try:\n            return self.in_queue.get(block=block, timeout=timeout)\n        except queue.Empty:\n            raise Empty\n\n    async def async_get(self) -> Envelope:\n        \"\"\"\n        Get an envelope async way.\n\n        :return: the envelope\n        \"\"\"\n        try:\n            return await self.in_queue.async_get()\n        except queue.Empty:  # pragma: nocover\n            raise Empty\n\n    async def async_wait(self) -> None:\n        \"\"\"\n        Get an envelope async way.\n\n        :return: the envelope\n        \"\"\"\n        return await self.in_queue.async_wait()\n\n    async def _put(self, envelope: Envelope) -> None:\n        \"\"\"\n        Schedule an envelope for sending it.\n\n        Notice that the output queue is an asyncio.Queue which uses an event loop\n        running on a different thread than the one used in this function.\n\n        :param envelope: the envelope to be sent.\n        \"\"\"\n        await self.out_queue.put(envelope)\n\n    def put(self, envelope: Envelope) -> None:\n        \"\"\"\n        Schedule an envelope for sending it.\n\n        Notice that the output queue is an asyncio.Queue which uses an event loop\n        running on a different thread than the one used in this function.\n\n        :param envelope: the envelope to be sent.\n        \"\"\"\n        if self._threaded:\n            self._loop.call_soon_threadsafe(self.out_queue.put_nowait, envelope)\n        else:\n            self.out_queue.put_nowait(envelope)\n\n    def _setup(\n        self,\n        connections: Collection[Connection],\n        default_routing: Optional[Dict[PublicId, PublicId]] = None,\n        default_connection: Optional[PublicId] = None,\n    ) -> None:\n        \"\"\"\n        Set up the multiplexer.\n\n        :param connections: the connections to use. It will replace the other ones.\n        :param default_routing: the default routing.\n        :param default_connection: the default connection.\n        \"\"\"\n        self.default_routing = default_routing or {}\n\n        # replace connections\n        self._connections = []\n        self._id_to_connection = {}\n\n        for c in connections:\n            self.add_connection(c, c.public_id == default_connection)\n\n    def _update_routing_helper(\n        self, envelope: Envelope, connection: Connection\n    ) -> None:\n        \"\"\"\n        Update the routing helper.\n\n        Saves the source (connection) of an agent-to-agent envelope.\n\n        :param envelope: the envelope to be updated\n        :param connection: the connection\n        \"\"\"\n        if envelope.is_component_to_component_message:\n            return\n        self._routing_helper[envelope.sender] = connection.public_id\n\n\nclass Multiplexer(AsyncMultiplexer):\n    \"\"\"Transit sync multiplexer for compatibility.\"\"\"\n\n    _thread_was_started: bool\n    _is_connected: bool\n\n    def __init__(self, *args: Any, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize the connection multiplexer.\n\n        :param args: arguments\n        :param kwargs: keyword arguments\n        \"\"\"\n        super().__init__(*args, **kwargs)\n        self._sync_lock = threading.Lock()\n        self._init()\n\n    def _init(self) -> None:\n        \"\"\"Set initial variables.\"\"\"\n        self._thread_was_started = False\n        self._is_connected = False\n\n    def set_loop(self, loop: AbstractEventLoop) -> None:\n        \"\"\"\n        Set event loop and all event loop related objects.\n\n        :param loop: asyncio event loop.\n        \"\"\"\n        super().set_loop(loop)\n        self._thread_runner = ThreadedAsyncRunner(self._loop)\n\n    def connect(self) -> None:  # type: ignore # cause overrides coroutine # pylint: disable=invalid-overridden-method\n        \"\"\"\n        Connect the multiplexer.\n\n        Synchronously in thread spawned if new loop created.\n        \"\"\"\n        with self._sync_lock:\n            if not self._loop.is_running():\n                self._thread_runner.start()\n                self._thread_was_started = True\n\n            self._thread_runner.call(super().connect()).result(240)\n            self._is_connected = True\n\n    def disconnect(self) -> None:  # type: ignore # cause overrides coroutine # pylint: disable=invalid-overridden-method\n        \"\"\"\n        Disconnect the multiplexer.\n\n        Also stops a dedicated thread for event loop if spawned on connect.\n        \"\"\"\n        self.logger.debug(\"Disconnect called\")\n        with self._sync_lock:\n            if not self._loop.is_running():\n                return\n\n            if self._is_connected:\n                self._thread_runner.call(super().disconnect()).result(240)\n                self._is_connected = False\n            self.logger.debug(\"Disconnect async method executed\")\n\n            if self._thread_runner.is_alive() and self._thread_was_started:\n                self._thread_runner.stop()\n                self.logger.debug(\"Thread stopped\")\n\n            self.logger.debug(\"Disconnected\")\n\n            # reset thread runner and init variables\n            self._init()\n            self.set_loop(self._loop)\n\n    def put(self, envelope: Envelope) -> None:  # type: ignore  # cause overrides coroutine\n        \"\"\"\n        Schedule an envelope for sending it.\n\n        Notice that the output queue is an asyncio.Queue which uses an event loop\n        running on a different thread than the one used in this function.\n\n        :param envelope: the envelope to be sent.\n        \"\"\"\n        self._thread_runner.call(super()._put(envelope))  # .result(240)\n\n\nclass InBox:\n    \"\"\"A queue from where you can only consume envelopes.\"\"\"\n\n    def __init__(self, multiplexer: AsyncMultiplexer) -> None:\n        \"\"\"\n        Initialize the inbox.\n\n        :param multiplexer: the multiplexer\n        \"\"\"\n        super().__init__()\n        self._multiplexer = multiplexer\n\n    def empty(self) -> bool:\n        \"\"\"\n        Check for a envelope on the in queue.\n\n        :return: boolean indicating whether there is an envelope or not\n        \"\"\"\n        return self._multiplexer.in_queue.empty()\n\n    def get(self, block: bool = False, timeout: Optional[float] = None) -> Envelope:\n        \"\"\"\n        Check for a envelope on the in queue.\n\n        :param block: make the call blocking (ignore the timeout).\n        :param timeout: times out the block after timeout seconds.\n\n        :return: the envelope object.\n        :raises Empty: if the attempt to get an envelope fails.\n        \"\"\"\n        self._multiplexer.logger.debug(\"Checks for envelope from the in queue...\")\n        envelope = self._multiplexer.get(block=block, timeout=timeout)\n\n        if envelope is None:  # pragma: nocover\n            raise Empty()\n\n        self._multiplexer.logger.debug(f\"Incoming {envelope}\")\n        return envelope\n\n    def get_nowait(self) -> Optional[Envelope]:\n        \"\"\"\n        Check for a envelope on the in queue and wait for no time.\n\n        :return: the envelope object\n        \"\"\"\n        try:\n            return self.get()\n        except Empty:  # pragma: nocover\n            return None\n\n    async def async_get(self) -> Envelope:\n        \"\"\"\n        Check for a envelope on the in queue.\n\n        :return: the envelope object.\n        \"\"\"\n        self._multiplexer.logger.debug(\n            \"Checks for envelope from the in queue async way...\"\n        )\n        envelope = await self._multiplexer.async_get()\n\n        if envelope is None:  # pragma: nocover\n            raise Empty()\n\n        self._multiplexer.logger.debug(f\"Incoming envelope: {envelope}\")\n        return envelope\n\n    async def async_wait(self) -> None:\n        \"\"\"Check for a envelope on the in queue.\"\"\"\n        self._multiplexer.logger.debug(\n            \"Checks for envelope presents in queue async way...\"\n        )\n        await self._multiplexer.async_wait()\n\n\nclass OutBox:\n    \"\"\"A queue from where you can only enqueue envelopes.\"\"\"\n\n    def __init__(self, multiplexer: AsyncMultiplexer) -> None:\n        \"\"\"\n        Initialize the outbox.\n\n        :param multiplexer: the multiplexer\n        \"\"\"\n        super().__init__()\n        self._multiplexer = multiplexer\n\n    def empty(self) -> bool:\n        \"\"\"\n        Check for a envelope on the in queue.\n\n        :return: boolean indicating whether there is an envelope or not\n        \"\"\"\n        return self._multiplexer.out_queue.empty()  # pragma: nocover\n\n    def put(self, envelope: Envelope) -> None:\n        \"\"\"\n        Put an envelope into the queue.\n\n        :param envelope: the envelope.\n        \"\"\"\n        self._multiplexer.logger.debug(f\"Put an envelope in the queue: {envelope}.\")\n        if not isinstance(envelope.message, Message):\n            raise ValueError(\n                \"Only Message type allowed in envelope message field when putting into outbox.\"\n            )\n        message = cast(Message, envelope.message)\n        if not message.has_to:  # pragma: nocover\n            raise ValueError(\"Provided message has message.to not set.\")\n        if not message.has_sender:  # pragma: nocover\n            raise ValueError(\"Provided message has message.sender not set.\")\n        self._multiplexer.put(envelope)\n\n    def put_message(\n        self,\n        message: Message,\n        context: Optional[EnvelopeContext] = None,\n    ) -> None:\n        \"\"\"\n        Put a message in the outbox.\n\n        This constructs an envelope with the input arguments.\n\n        :param message: the message\n        :param context: the envelope context\n        \"\"\"\n        if not isinstance(message, Message):\n            raise ValueError(\"Provided message not of type Message.\")\n        if not message.has_to:\n            raise ValueError(\"Provided message has message.to not set.\")\n        if not message.has_sender:\n            raise ValueError(\"Provided message has message.sender not set.\")\n        envelope = Envelope(\n            to=message.to,\n            sender=message.sender,\n            message=message,\n            context=context,\n        )\n        self.put(envelope)\n"
  },
  {
    "path": "aea/protocols/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the protocol modules.\"\"\"\n"
  },
  {
    "path": "aea/protocols/base.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the base message and serialization definition.\"\"\"\nimport importlib\nimport inspect\nimport logging\nimport re\nfrom abc import ABC, abstractmethod\nfrom base64 import b64decode, b64encode\nfrom copy import copy\nfrom enum import Enum\nfrom pathlib import Path\nfrom typing import Any, Dict, Optional, Set, Tuple, Type, cast\n\nfrom aea.components.base import Component, load_aea_package\nfrom aea.configurations.base import ComponentType, ProtocolConfig, PublicId\nfrom aea.configurations.loader import load_component_configuration\nfrom aea.exceptions import AEAComponentLoadException, enforce\n\n\n_default_logger = logging.getLogger(__name__)\n\nMAX_PRINT_INNER = 600\nMAX_PRINT_OUTER = 2000\nAddress = str\n\n\nclass Message:\n    \"\"\"This class implements a message.\"\"\"\n\n    protocol_id = None  # type: PublicId\n    protocol_specification_id = None  # type: PublicId\n    serializer = None  # type: Type[\"Serializer\"]\n\n    __slots__ = (\"_slots\", \"_to\", \"_sender\")\n\n    class Performative(Enum):\n        \"\"\"Performatives for the base message.\"\"\"\n\n        def __str__(self) -> str:\n            \"\"\"Get the string representation.\"\"\"\n            return str(self.value)\n\n    class _SlotsCls:  # pylint: disable=too-few-public-methods\n        __slots__: Tuple[str, ...] = (\n            \"performative\",\n            \"dialogue_reference\",\n            \"message_id\",\n            \"target\",\n        )\n\n    _performatives: Set[str] = set()\n\n    def __init__(self, _body: Optional[Dict] = None, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize a Message object.\n\n        :param _body: the dictionary of values to hold.\n        :param kwargs: any additional value to add to the body. It will overwrite the body values.\n        \"\"\"\n        self._slots = self._SlotsCls()\n\n        self._to: Optional[Address] = None\n        self._sender: Optional[Address] = None\n\n        self._update_slots_from_dict(copy(_body) if _body else {})\n        self._update_slots_from_dict(kwargs)\n\n        try:\n            self._is_consistent()\n        except Exception as e:  # pylint: disable=broad-except\n            _default_logger.error(e)\n\n    def json(self) -> dict:\n        \"\"\"Get json friendly str representation of the message.\"\"\"\n        return {\n            \"to\": self._to,\n            \"sender\": self._sender,\n            \"body\": b64encode(self.encode()).decode(\"utf-8\"),\n        }\n\n    @classmethod\n    def from_json(cls, data: dict) -> \"Message\":\n        \"\"\"Construct message instance from json data.\"\"\"\n        try:\n            instance = cls.decode(b64decode(data[\"body\"]))\n            sender = data[\"sender\"]\n            if sender:\n                instance.sender = sender\n            to = data[\"to\"]\n            if to:\n                instance.to = to\n            return instance\n        except KeyError:  # pragma: nocover\n            raise ValueError(f\"Message representation is invalid: {data}\")\n\n    @property\n    def valid_performatives(self) -> Set[str]:\n        \"\"\"Get valid performatives.\"\"\"\n        return self._performatives\n\n    @property\n    def has_sender(self) -> bool:\n        \"\"\"Check if it has a sender.\"\"\"\n        return self._sender is not None\n\n    @property\n    def sender(self) -> Address:\n        \"\"\"Get the sender of the message in Address form.\"\"\"\n        if self._sender is None:\n            raise ValueError(\"Message's 'Sender' field must be set.\")  # pragma: nocover\n        return self._sender\n\n    @sender.setter\n    def sender(self, sender: Address) -> None:\n        \"\"\"Set the sender of the message.\"\"\"\n        enforce(self._sender is None, \"Sender already set.\")\n        enforce(\n            isinstance(sender, str),\n            f\"Sender must be string type. Found '{type(sender)}'\",\n        )\n        self._sender = sender\n\n    @property\n    def has_to(self) -> bool:\n        \"\"\"Check if it has a sender.\"\"\"\n        return self._to is not None\n\n    @property\n    def to(self) -> Address:\n        \"\"\"Get address of receiver.\"\"\"\n        if self._to is None:\n            raise ValueError(\"Message's 'To' field must be set.\")\n        return self._to\n\n    @to.setter\n    def to(self, to: Address) -> None:\n        \"\"\"Set address of receiver.\"\"\"\n        enforce(self._to is None, \"To already set.\")\n        enforce(isinstance(to, str), f\"To must be string type. Found '{type(to)}'\")\n        self._to = to\n\n    @property\n    def _body(self) -> Dict:\n        \"\"\"\n        Get the body of the message (in dictionary form).\n\n        :return: the body\n        \"\"\"\n        return {\n            key: self.get(key) for key in self._SlotsCls.__slots__ if self.is_set(key)\n        }\n\n    @_body.setter\n    def _body(self, body: Dict) -> None:\n        \"\"\"\n        Set the body of the message.\n\n        :param body: the body.\n        \"\"\"\n        self._slots = self._SlotsCls()  # new instance to clean up all data\n        self._update_slots_from_dict(body)\n\n    @property\n    def dialogue_reference(self) -> Tuple[str, str]:\n        \"\"\"Get the dialogue_reference of the message.\"\"\"\n        if not self.is_set(\"dialogue_reference\"):\n            raise ValueError(\"dialogue_reference is not set.\")  # pragma: nocover\n        return cast(Tuple[str, str], self.get(\"dialogue_reference\"))\n\n    @property\n    def message_id(self) -> int:\n        \"\"\"Get the message_id of the message.\"\"\"\n        if not self.is_set(\"message_id\"):\n            raise ValueError(\"message_id is not set.\")  # pragma: nocover\n        return cast(int, self.get(\"message_id\"))\n\n    @property\n    def performative(self) -> \"Performative\":\n        \"\"\"Get the performative of the message.\"\"\"\n        if not self.is_set(\"performative\"):\n            raise ValueError(\"performative is not set.\")  # pragma: nocover\n        return cast(Message.Performative, self.get(\"performative\"))\n\n    @property\n    def target(self) -> int:\n        \"\"\"Get the target of the message.\"\"\"\n        if not self.is_set(\"target\"):\n            raise ValueError(\"target is not set.\")  # pragma: nocover\n        return cast(int, self.get(\"target\"))\n\n    def set(self, key: str, value: Any) -> None:\n        \"\"\"\n        Set key and value pair.\n\n        :param key: the key.\n        :param value: the value.\n        \"\"\"\n        try:\n            setattr(self._slots, key, value)\n        except AttributeError as e:  # pragma: nocover\n            raise ValueError(f\"Field `{key}` is not supported {e}\")\n\n    def get(self, key: str) -> Optional[Any]:\n        \"\"\"Get value for key.\"\"\"\n        return getattr(self._slots, key, None)\n\n    def is_set(self, key: str) -> bool:\n        \"\"\"Check value is set for key.\"\"\"\n        return hasattr(self._slots, key)\n\n    def _update_slots_from_dict(self, data: dict) -> None:\n        \"\"\"Update slots value with data from dict.\"\"\"\n        for key, value in data.items():\n            self.set(key, value)\n\n    def _is_consistent(self) -> bool:\n        \"\"\"Check that the data is consistent.\"\"\"\n        return True\n\n    def __eq__(self, other: Any) -> bool:\n        \"\"\"Compare with another object.\"\"\"\n        return (\n            isinstance(other, Message)\n            and self._sender == other._sender\n            and self._to == other._to\n            and self._body == other._body\n        )\n\n    def __repr__(self) -> str:\n        \"\"\"Get the representation of the message.\"\"\"\n        body = \",\".join(\n            map(\n                lambda key_value: f\"{str(key_value[0])}={str(key_value[1])}\",\n                self._body.items(),\n            )\n        )\n        return f\"Message(sender={self._sender},to={self._to},{body})\"\n\n    def __str__(self) -> str:\n        \"\"\"Get the string representation of the message. Abbreviated to prevent spamming of logs.\"\"\"\n        body = \",\".join(\n            map(\n                lambda key_value: f\"{str(key_value[0])[:MAX_PRINT_INNER]}={str(key_value[1])[:MAX_PRINT_INNER]}\",\n                self._body.items(),\n            )\n        )\n        return f\"Message(sender={self._sender},to={self._to},{body})\"[:MAX_PRINT_OUTER]\n\n    def encode(self) -> bytes:\n        \"\"\"Encode the message.\"\"\"\n        return self.serializer.encode(self)\n\n    @classmethod\n    def decode(cls, data: bytes) -> \"Message\":\n        \"\"\"Decode the message.\"\"\"\n        return cls.serializer.decode(data)\n\n    @property\n    def has_dialogue_info(self) -> bool:\n        \"\"\"\n        Check whether a message has the dialogue fields populated.\n\n        More precisely, it checks whether the fields 'message_id',\n        'target' and 'dialogue_reference' are set.\n\n        :return: True if the message has the dialogue fields set, False otherwise.\n        \"\"\"\n        return (\n            self.is_set(\"message_id\")\n            and self.is_set(\"target\")\n            and self.is_set(\"dialogue_reference\")\n        )\n\n\nclass Encoder(ABC):\n    \"\"\"Encoder interface.\"\"\"\n\n    @staticmethod\n    @abstractmethod\n    def encode(msg: Message) -> bytes:\n        \"\"\"\n        Encode a message.\n\n        :param msg: the message to be encoded.\n        :return: the encoded message.\n        \"\"\"\n\n\nclass Decoder(ABC):\n    \"\"\"Decoder interface.\"\"\"\n\n    @staticmethod\n    @abstractmethod\n    def decode(obj: bytes) -> Message:\n        \"\"\"\n        Decode a message.\n\n        :param obj: the sequence of bytes to be decoded.\n        :return: the decoded message.\n        \"\"\"\n\n\nclass Serializer(Encoder, Decoder, ABC):\n    \"\"\"The implementations of this class defines a serialization layer for a protocol.\"\"\"\n\n\nclass Protocol(Component):\n    \"\"\"\n    This class implements a specifications for a protocol.\n\n    It includes a serializer to encode/decode a message.\n    \"\"\"\n\n    __slots__ = (\"_message_class\",)\n\n    def __init__(\n        self, configuration: ProtocolConfig, message_class: Type[Message], **kwargs: Any\n    ) -> None:\n        \"\"\"\n        Initialize the protocol manager.\n\n        :param configuration: the protocol configurations.\n        :param message_class: the message class.\n        :param kwargs: the keyword arguments.\n        \"\"\"\n        super().__init__(configuration, **kwargs)\n        self._message_class = message_class\n\n    @property\n    def serializer(self) -> Type[Serializer]:\n        \"\"\"Get the serializer.\"\"\"\n        return self._message_class.serializer\n\n    @classmethod\n    def from_dir(cls, directory: str, **kwargs: Any) -> \"Protocol\":\n        \"\"\"\n        Load the protocol from a directory.\n\n        :param directory: the directory to the skill package.\n        :param kwargs: the keyword arguments.\n        :return: the protocol object.\n        \"\"\"\n        configuration = cast(\n            ProtocolConfig,\n            load_component_configuration(ComponentType.PROTOCOL, Path(directory)),\n        )\n        configuration.directory = Path(directory)\n        return Protocol.from_config(configuration, **kwargs)\n\n    @classmethod\n    def from_config(cls, configuration: ProtocolConfig, **kwargs: Any) -> \"Protocol\":\n        \"\"\"\n        Load the protocol from configuration.\n\n        :param configuration: the protocol configuration.\n        :param kwargs: the keyword arguments.\n        :return: the protocol object.\n        \"\"\"\n        if configuration.directory is None:  # pragma: nocover\n            raise ValueError(\"Configuration must be associated with a directory.\")\n        load_aea_package(configuration)\n        class_module = importlib.import_module(\n            configuration.prefix_import_path + \".message\"\n        )\n        classes = inspect.getmembers(class_module, inspect.isclass)\n        name_camel_case = \"\".join(\n            word.capitalize() for word in configuration.name.split(\"_\")\n        )\n        message_classes = list(\n            filter(lambda x: re.match(f\"{name_camel_case}Message\", x[0]), classes)\n        )\n        if len(message_classes) != 1:  # pragma: nocover\n            raise AEAComponentLoadException(\"Not exactly one message class detected.\")\n        message_class = message_classes[0][1]\n        class_module = importlib.import_module(\n            configuration.prefix_import_path + \".serialization\"\n        )\n        classes = inspect.getmembers(class_module, inspect.isclass)\n        serializer_classes = list(\n            filter(\n                lambda x: re.match(f\"{name_camel_case}Serializer\", x[0]),\n                classes,\n            )\n        )\n        if len(serializer_classes) != 1:  # pragma: nocover\n            raise AEAComponentLoadException(\n                \"Not exactly one serializer class detected.\"\n            )\n        serialize_class = serializer_classes[0][1]\n        message_class.serializer = serialize_class\n\n        return Protocol(configuration, message_class, **kwargs)\n\n    @property\n    def protocol_id(self) -> PublicId:\n        \"\"\"Get protocol id.\"\"\"\n        return cast(ProtocolConfig, self._configuration).public_id\n\n    @property\n    def protocol_specification_id(self) -> PublicId:\n        \"\"\"Get protocol specification id.\"\"\"\n        return cast(ProtocolConfig, self._configuration).protocol_specification_id\n\n    def __repr__(self) -> str:\n        \"\"\"Get str representation of the protocol.\"\"\"\n        return f\"Protocol({self.protocol_id})\"\n"
  },
  {
    "path": "aea/protocols/dialogue/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the dialogue modules.\"\"\"\n"
  },
  {
    "path": "aea/protocols/dialogue/base.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"\nThis module contains the classes required for dialogue management.\n\n- DialogueLabel: The dialogue label class acts as an identifier for dialogues.\n- Dialogue: The dialogue class maintains state of a dialogue and manages it.\n- Dialogues: The dialogues class keeps track of all dialogues.\n\"\"\"\nimport inspect\nimport secrets\nimport sys\nfrom collections import defaultdict, namedtuple\nfrom enum import Enum\nfrom inspect import signature\nfrom typing import (\n    Any,\n    Callable,\n    Dict,\n    FrozenSet,\n    Iterable,\n    List,\n    Optional,\n    Set,\n    Tuple,\n    Type,\n    cast,\n)\n\nfrom aea.common import Address\nfrom aea.exceptions import AEAEnforceError, enforce\nfrom aea.helpers.base import cached_property\nfrom aea.helpers.storage.generic_storage import SyncCollection\nfrom aea.protocols.base import Message\nfrom aea.skills.base import SkillComponent\n\n\nif sys.version_info[0] < 3 or (sys.version_info[0] == 3 and sys.version_info[1] < 7):\n    DialogueMessage = namedtuple(  # pragma: no cover\n        \"DialogueMessage\",\n        [\"performative\", \"contents\", \"is_incoming\", \"target\"],\n        rename=False,\n        module=\"aea.protocols.dialogues.base\",\n    )\n    DialogueMessage.__new__.__defaults__ = (dict(), None, None)  # pragma: no cover\nelse:\n    DialogueMessage = namedtuple(  # pylint: disable=unexpected-keyword-arg\n        \"DialogueMessage\",\n        [\"performative\", \"contents\", \"is_incoming\", \"target\"],\n        rename=False,\n        defaults=[dict(), None, None],\n        module=\"aea.protocols.dialogues.base\",\n    )\n\n\nclass InvalidDialogueMessage(Exception):\n    \"\"\"Exception for adding invalid message to a dialogue.\"\"\"\n\n\nclass DialogueLabel:\n    \"\"\"The dialogue label class acts as an identifier for dialogues.\"\"\"\n\n    __slots__ = (\n        \"_dialogue_reference\",\n        \"_dialogue_opponent_addr\",\n        \"_dialogue_starter_addr\",\n    )\n\n    NONCE_BYTES_NB = 32\n\n    def __init__(\n        self,\n        dialogue_reference: Tuple[str, str],\n        dialogue_opponent_addr: Address,\n        dialogue_starter_addr: Address,\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue label.\n\n        :param dialogue_reference: the reference of the dialogue.\n        :param dialogue_opponent_addr: the addr of the agent with which the dialogue is kept.\n        :param dialogue_starter_addr: the addr of the agent which started the dialogue.\n        \"\"\"\n        self._dialogue_reference = dialogue_reference\n        self._dialogue_opponent_addr = dialogue_opponent_addr\n        self._dialogue_starter_addr = dialogue_starter_addr\n\n    @property\n    def dialogue_reference(self) -> Tuple[str, str]:\n        \"\"\"Get the dialogue reference.\"\"\"\n        return self._dialogue_reference\n\n    @property\n    def dialogue_starter_reference(self) -> str:\n        \"\"\"Get the dialogue starter reference.\"\"\"\n        return self._dialogue_reference[0]\n\n    @property\n    def dialogue_responder_reference(self) -> str:\n        \"\"\"Get the dialogue responder reference.\"\"\"\n        return self._dialogue_reference[1]\n\n    @property\n    def dialogue_opponent_addr(self) -> str:\n        \"\"\"Get the address of the dialogue opponent.\"\"\"\n        return self._dialogue_opponent_addr\n\n    @property\n    def dialogue_starter_addr(self) -> str:\n        \"\"\"Get the address of the dialogue starter.\"\"\"\n        return self._dialogue_starter_addr\n\n    def __eq__(self, other: Any) -> bool:\n        \"\"\"Check for equality between two DialogueLabel objects.\"\"\"\n        return (\n            isinstance(other, DialogueLabel)\n            and self.dialogue_reference == other.dialogue_reference\n            and self.dialogue_opponent_addr == other.dialogue_opponent_addr\n            and self.dialogue_starter_addr == other.dialogue_starter_addr\n        )\n\n    def __hash__(self) -> int:\n        \"\"\"Turn object into hash.\"\"\"\n        return hash(\n            (\n                self.dialogue_reference,\n                self.dialogue_opponent_addr,\n                self.dialogue_starter_addr,\n            )\n        )\n\n    @property\n    def json(self) -> Dict:\n        \"\"\"Return the JSON representation.\"\"\"\n        return {\n            \"dialogue_starter_reference\": self.dialogue_starter_reference,\n            \"dialogue_responder_reference\": self.dialogue_responder_reference,\n            \"dialogue_opponent_addr\": self.dialogue_opponent_addr,\n            \"dialogue_starter_addr\": self.dialogue_starter_addr,\n        }\n\n    @classmethod\n    def from_json(cls, obj: Dict[str, str]) -> \"DialogueLabel\":\n        \"\"\"Get dialogue label from json.\"\"\"\n        dialogue_label = DialogueLabel(\n            (\n                cast(str, obj.get(\"dialogue_starter_reference\")),\n                cast(str, obj.get(\"dialogue_responder_reference\")),\n            ),\n            cast(str, obj.get(\"dialogue_opponent_addr\")),\n            cast(str, obj.get(\"dialogue_starter_addr\")),\n        )\n        return dialogue_label\n\n    def get_incomplete_version(self) -> \"DialogueLabel\":\n        \"\"\"Get the incomplete version of the label.\"\"\"\n        dialogue_label = DialogueLabel(\n            (self.dialogue_starter_reference, Dialogue.UNASSIGNED_DIALOGUE_REFERENCE),\n            self.dialogue_opponent_addr,\n            self.dialogue_starter_addr,\n        )\n        return dialogue_label\n\n    def __str__(self) -> str:\n        \"\"\"Get the string representation.\"\"\"\n        return \"{}_{}_{}_{}\".format(\n            self.dialogue_starter_reference,\n            self.dialogue_responder_reference,\n            self.dialogue_opponent_addr,\n            self.dialogue_starter_addr,\n        )\n\n    @classmethod\n    def from_str(cls, obj: str) -> \"DialogueLabel\":\n        \"\"\"Get the dialogue label from string representation.\"\"\"\n        (\n            dialogue_starter_reference,\n            dialogue_responder_reference,\n            dialogue_opponent_addr,\n            dialogue_starter_addr,\n        ) = obj.split(\"_\")\n        dialogue_label = DialogueLabel(\n            (dialogue_starter_reference, dialogue_responder_reference),\n            dialogue_opponent_addr,\n            dialogue_starter_addr,\n        )\n        return dialogue_label\n\n\nclass _DialogueMeta(type):\n    \"\"\"\n    Metaclass for Dialogue.\n\n    Creates class level Rules instance to share among instances\n    \"\"\"\n\n    def __new__(cls, name: str, bases: Tuple[Type], dct: Dict) -> \"_DialogueMeta\":\n        \"\"\"Construct a new type.\"\"\"\n        # set class level `_rules`\n        dialogue_cls = cast(Type[\"Dialogue\"], super().__new__(cls, name, bases, dct))\n        dialogue_cls._rules = dialogue_cls.Rules(\n            dialogue_cls.INITIAL_PERFORMATIVES,\n            dialogue_cls.TERMINAL_PERFORMATIVES,\n            dialogue_cls.VALID_REPLIES,\n        )\n\n        return dialogue_cls\n\n\nclass Dialogue(metaclass=_DialogueMeta):\n    \"\"\"The dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    STARTING_MESSAGE_ID = 1\n    STARTING_TARGET = 0\n    UNASSIGNED_DIALOGUE_REFERENCE = \"\"\n\n    INITIAL_PERFORMATIVES = frozenset()  # type: FrozenSet[Message.Performative]\n    TERMINAL_PERFORMATIVES = frozenset()  # type: FrozenSet[Message.Performative]\n    VALID_REPLIES = (\n        dict()\n    )  # type: Dict[Message.Performative, FrozenSet[Message.Performative]]\n\n    __slots__ = (\n        \"_self_address\",\n        \"_dialogue_label\",\n        \"_role\",\n        \"_message_class\",\n        \"_outgoing_messages\",\n        \"_incoming_messages\",\n        \"_terminal_state_callbacks\",\n        \"_last_message_id\",\n        \"_ordered_message_ids\",\n    )\n\n    class Rules:\n        \"\"\"This class defines the rules for the dialogue.\"\"\"\n\n        def __init__(\n            self,\n            initial_performatives: FrozenSet[Message.Performative],\n            terminal_performatives: FrozenSet[Message.Performative],\n            valid_replies: Dict[Message.Performative, FrozenSet[Message.Performative]],\n        ) -> None:\n            \"\"\"\n            Initialize a dialogue.\n\n            :param initial_performatives: the set of all initial performatives.\n            :param terminal_performatives: the set of all terminal performatives.\n            :param valid_replies: the reply structure of speech-acts.\n            \"\"\"\n            self._initial_performatives = initial_performatives\n            self._terminal_performatives = terminal_performatives\n            self._valid_replies = valid_replies\n\n        @property\n        def initial_performatives(self) -> FrozenSet[Message.Performative]:\n            \"\"\"\n            Get the performatives one of which the terminal message in the dialogue must have.\n\n            :return: the valid performatives of an terminal message\n            \"\"\"\n            return self._initial_performatives\n\n        @property\n        def terminal_performatives(self) -> FrozenSet[Message.Performative]:\n            \"\"\"\n            Get the performatives one of which the terminal message in the dialogue must have.\n\n            :return: the valid performatives of an terminal message\n            \"\"\"\n            return self._terminal_performatives\n\n        @property\n        def valid_replies(\n            self,\n        ) -> Dict[Message.Performative, FrozenSet[Message.Performative]]:\n            \"\"\"\n            Get all the valid performatives which are a valid replies to performatives.\n\n            :return: the full valid reply structure.\n            \"\"\"\n            return self._valid_replies\n\n        def get_valid_replies(\n            self, performative: Message.Performative\n        ) -> FrozenSet[Message.Performative]:\n            \"\"\"\n            Given a `performative`, return the list of performatives which are its valid replies in a dialogue.\n\n            :param performative: the performative in a message\n            :return: list of valid performative replies\n            \"\"\"\n            enforce(\n                performative in self.valid_replies,\n                \"this performative '{}' is not supported\".format(performative),\n            )\n            return self.valid_replies[performative]\n\n    class Role(Enum):\n        \"\"\"This class defines the agent's role in a dialogue.\"\"\"\n\n        def __str__(self) -> str:\n            \"\"\"Get the string representation.\"\"\"\n            return str(self.value)\n\n    class EndState(Enum):\n        \"\"\"This class defines the end states of a dialogue.\"\"\"\n\n        def __str__(self) -> str:\n            \"\"\"Get the string representation.\"\"\"\n            return str(self.value)\n\n    _rules: Optional[Rules] = None\n\n    def __init__(\n        self,\n        dialogue_label: DialogueLabel,\n        message_class: Type[Message],\n        self_address: Address,\n        role: Role,\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param message_class: the message class used\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n        \"\"\"\n        self._self_address = self_address\n        self._dialogue_label = dialogue_label\n        self._role = role\n\n        self._outgoing_messages = []  # type: List[Message]\n        self._incoming_messages = []  # type: List[Message]\n\n        enforce(\n            issubclass(message_class, Message),\n            \"Message class provided not a subclass of `Message`.\",\n        )\n        self._message_class = message_class\n        self._terminal_state_callbacks: Set[Callable[[\"Dialogue\"], None]] = set()\n        self._last_message_id: Optional[int] = None\n        self._ordered_message_ids: List[int] = []\n\n    def add_terminal_state_callback(self, fn: Callable[[\"Dialogue\"], None]) -> None:\n        \"\"\"\n        Add callback to be called on dialogue reach terminal state.\n\n        :param fn: callable to be called with one argument: Dialogue\n        \"\"\"\n        self._terminal_state_callbacks.add(fn)\n\n    def __eq__(self, other: Any) -> bool:\n        \"\"\"Compare two dialogues.\"\"\"\n        return (\n            type(self) == type(other)  # pylint: disable=unidiomatic-typecheck\n            and self.dialogue_label == other.dialogue_label\n            and self.message_class == other.message_class\n            and self._incoming_messages == other._incoming_messages\n            and self._outgoing_messages == other._outgoing_messages\n            and self._ordered_message_ids == other._ordered_message_ids\n            and self.role == other.role\n            and self.self_address == other.self_address\n        )\n\n    def json(self) -> dict:\n        \"\"\"Get json representation of the dialogue.\"\"\"\n        data = {\n            \"dialogue_label\": self._dialogue_label.json,\n            \"self_address\": self.self_address,\n            \"role\": self._role.value,\n            \"incoming_messages\": [i.json() for i in self._incoming_messages],\n            \"outgoing_messages\": [i.json() for i in self._outgoing_messages],\n            \"last_message_id\": self._last_message_id,\n            \"ordered_message_ids\": self._ordered_message_ids,\n        }\n        return data\n\n    @classmethod\n    def from_json(cls, message_class: Type[Message], data: dict) -> \"Dialogue\":\n        \"\"\"\n        Create a dialogue instance with all messages from json data.\n\n        :param message_class: type of message used with this dialogue\n        :param data: dict with data exported with Dialogue.to_json() method\n\n        :return: Dialogue instance\n        \"\"\"\n        try:\n            obj = cls(\n                dialogue_label=DialogueLabel.from_json(data[\"dialogue_label\"]),\n                message_class=message_class,\n                self_address=Address(data[\"self_address\"]),\n                role=cls.Role(data[\"role\"]),\n            )\n            obj._incoming_messages = [  # pylint: disable=protected-access\n                message_class.from_json(i) for i in data[\"incoming_messages\"]\n            ]\n            obj._outgoing_messages = [  # pylint: disable=protected-access\n                message_class.from_json(i) for i in data[\"outgoing_messages\"]\n            ]\n            last_message_id = int(data[\"last_message_id\"])\n            obj._last_message_id = last_message_id  # pylint: disable=protected-access\n            obj._ordered_message_ids = [  # pylint: disable=protected-access\n                int(el) for el in data[\"ordered_message_ids\"]\n            ]\n            return obj\n        except KeyError:  # pragma: nocover\n            raise ValueError(f\"Dialogue representation is invalid: {data}\")\n\n    @property\n    def dialogue_label(self) -> DialogueLabel:\n        \"\"\"\n        Get the dialogue label.\n\n        :return: The dialogue label\n        \"\"\"\n        return self._dialogue_label\n\n    @property\n    def incomplete_dialogue_label(self) -> DialogueLabel:\n        \"\"\"\n        Get the dialogue label.\n\n        :return: The incomplete dialogue label\n        \"\"\"\n        return self.dialogue_label.get_incomplete_version()\n\n    @property\n    def dialogue_labels(self) -> Set[DialogueLabel]:\n        \"\"\"\n        Get the dialogue labels (incomplete and complete, if it exists).\n\n        :return: the dialogue labels\n        \"\"\"\n        return {self.dialogue_label, self.incomplete_dialogue_label}\n\n    @property\n    def self_address(self) -> Address:\n        \"\"\"\n        Get the address of the entity for whom this dialogues is maintained.\n\n        :return: the address of this entity\n        \"\"\"\n        if self._self_address is None:  # pragma: nocover\n            raise ValueError(\"self_address is not set.\")\n        return self._self_address\n\n    @property\n    def role(self) -> \"Role\":\n        \"\"\"\n        Get the agent's role in the dialogue.\n\n        :return: the agent's role\n        \"\"\"\n        if self._role is None:  # pragma: nocover\n            raise ValueError(\"Role is not set.\")\n        return self._role\n\n    @property\n    def rules(self) -> \"Rules\":\n        \"\"\"\n        Get the dialogue rules.\n\n        :return: the rules\n        \"\"\"\n        if self._rules is None:  # pragma: nocover\n            raise ValueError(\"Rules is not set.\")\n        return self._rules\n\n    @property\n    def message_class(self) -> Type[Message]:\n        \"\"\"\n        Get the message class.\n\n        :return: the message class\n        \"\"\"\n        return self._message_class\n\n    @property\n    def is_self_initiated(self) -> bool:\n        \"\"\"\n        Check whether the agent initiated the dialogue.\n\n        :return: True if the agent initiated the dialogue, False otherwise\n        \"\"\"\n        return (\n            self.dialogue_label.dialogue_opponent_addr\n            is not self.dialogue_label.dialogue_starter_addr\n        )\n\n    @property\n    def last_incoming_message(self) -> Optional[Message]:\n        \"\"\"\n        Get the last incoming message.\n\n        :return: the last incoming message if it exists, None otherwise\n        \"\"\"\n        return self._incoming_messages[-1] if len(self._incoming_messages) > 0 else None\n\n    @property\n    def last_outgoing_message(self) -> Optional[Message]:\n        \"\"\"\n        Get the last outgoing message.\n\n        :return: the last outgoing message if it exists, None otherwise\n        \"\"\"\n        return self._outgoing_messages[-1] if len(self._outgoing_messages) > 0 else None\n\n    @property\n    def last_message(self) -> Optional[Message]:\n        \"\"\"\n        Get the last message.\n\n        :return: the last message if it exists, None otherwise\n        \"\"\"\n        if self._last_message_id is None:\n            return None\n\n        if (\n            self.last_incoming_message\n            and self.last_incoming_message.message_id == self._last_message_id\n        ):\n            return self.last_incoming_message\n        return self.last_outgoing_message\n\n    @property\n    def is_empty(self) -> bool:\n        \"\"\"\n        Check whether the dialogue is empty.\n\n        :return: True if empty, False otherwise\n        \"\"\"\n        return len(self._outgoing_messages) == 0 and len(self._incoming_messages) == 0\n\n    def _counterparty_from_message(self, message: Message) -> Address:\n        \"\"\"\n        Determine the counterparty of the agent in the dialogue from a message.\n\n        :param message: the message\n        :return: The address of the counterparty\n        \"\"\"\n        counterparty = (\n            message.to if self._is_message_by_self(message) else message.sender\n        )\n        return counterparty\n\n    def _is_message_by_self(self, message: Message) -> bool:\n        \"\"\"\n        Check whether the message is by this agent or not.\n\n        :param message: the message\n        :return: True if message is by this agent, False otherwise\n        \"\"\"\n        return message.sender == self.self_address\n\n    def _is_message_by_other(self, message: Message) -> bool:\n        \"\"\"\n        Check whether the message is by the counterparty agent in this dialogue or not.\n\n        :param message: the message\n        :return: True if message is by the counterparty agent in this dialogue, False otherwise\n        \"\"\"\n        return not self._is_message_by_self(message)\n\n    def _has_message_id(self, message_id: int) -> bool:\n        \"\"\"\n        Check whether a message with the supplied message id exists in this dialogue.\n\n        :param message_id: the message id\n        :return: True if message with that id exists in this dialogue, False otherwise\n        \"\"\"\n        return self.get_message_by_id(message_id) is not None\n\n    def _update(self, message: Message) -> None:\n        \"\"\"\n        Extend the list of incoming/outgoing messages with 'message', if 'message' belongs to dialogue and is valid.\n\n        :param message: a message to be added\n        :raises: InvalidDialogueMessage: if message does not belong to this dialogue, or if message is invalid\n        \"\"\"\n        if not message.has_sender:\n            message.sender = self.self_address  # pragma: nocover\n\n        if not self._is_belonging_to_dialogue(message):\n            raise InvalidDialogueMessage(\n                \"The message {} does not belong to this dialogue.\"\n                \"The dialogue reference of the message is {}, while the dialogue reference of the dialogue is {}\".format(\n                    message.message_id,\n                    message.dialogue_reference,\n                    self.dialogue_label.dialogue_reference,\n                )\n            )\n\n        is_valid_result, validation_message = self._validate_next_message(message)\n\n        if not is_valid_result:\n            raise InvalidDialogueMessage(\n                \"Message {} is invalid with respect to this dialogue. Error: {}\".format(\n                    message.message_id,\n                    validation_message,\n                )\n            )\n\n        if self._is_message_by_self(message):\n            self._outgoing_messages.append(message)\n        else:\n            self._incoming_messages.append(message)\n\n        self._last_message_id = message.message_id\n        self._ordered_message_ids.append(message.message_id)\n\n        if message.performative in self.rules.terminal_performatives:\n            for fn in self._terminal_state_callbacks:\n                fn(self)\n\n    def _is_belonging_to_dialogue(self, message: Message) -> bool:\n        \"\"\"\n        Check if the message is belonging to the dialogue.\n\n        :param message: the message\n        :return: True if message is part of the dialogue, False otherwise\n        \"\"\"\n        opponent = self._counterparty_from_message(message)\n        if self.is_self_initiated:\n            self_initiated_dialogue_label = DialogueLabel(\n                (\n                    message.dialogue_reference[0],\n                    Dialogue.UNASSIGNED_DIALOGUE_REFERENCE,\n                ),\n                opponent,\n                self.self_address,\n            )\n            result = self_initiated_dialogue_label in self.dialogue_labels\n        else:\n            other_initiated_dialogue_label = DialogueLabel(\n                message.dialogue_reference,\n                opponent,\n                opponent,\n            )\n            result = other_initiated_dialogue_label in self.dialogue_labels\n        return result\n\n    def reply(\n        self,\n        performative: Message.Performative,\n        target_message: Optional[Message] = None,\n        target: Optional[int] = None,\n        **kwargs: Any,\n    ) -> Message:\n        \"\"\"\n        Reply to the 'target_message' in this dialogue with a message with 'performative', and contents from kwargs.\n\n        Note if no target_message is provided, the last message in the dialogue will be replied to.\n\n        :param target_message: the message to reply to.\n        :param target: the id of the message to reply to.\n        :param performative: the performative of the reply message.\n        :param kwargs: the content of the reply message.\n\n        :return: the reply message if it was successfully added as a reply, None otherwise.\n        \"\"\"\n        last_message = self.last_message\n        if last_message is None:\n            raise ValueError(\"Cannot reply in an empty dialogue!\")\n\n        if target_message is None and target is not None:\n            target_message = self.get_message_by_id(target)\n        elif target_message is None and target is None:\n            target_message = last_message\n            target = last_message.message_id\n        elif target_message is not None and target is None:\n            target = target_message.message_id\n        elif target_message is not None and target is not None:\n            if target != target_message.message_id:\n                raise AEAEnforceError(\n                    \"The provided target and target_message do not match.\"\n                )\n\n        if target_message is None:\n            raise ValueError(\"No target message found!\")\n        enforce(\n            self._has_message_id(target),  # type: ignore\n            \"The target message does not exist in this dialogue.\",\n        )\n\n        reply = self._message_class(\n            dialogue_reference=self.dialogue_label.dialogue_reference,\n            message_id=self.get_outgoing_next_message_id(),\n            target=target,\n            performative=performative,\n            **kwargs,\n        )\n        reply.sender = self.self_address\n        reply.to = self.dialogue_label.dialogue_opponent_addr\n\n        self._update(reply)\n\n        return reply\n\n    def _validate_next_message(self, message: Message) -> Tuple[bool, str]:\n        \"\"\"\n        Check whether 'message' is a valid next message in this dialogue.\n\n        The evaluation of a message validity involves performing several categories of checks.\n        Each category of checks resides in a separate method.\n\n        Currently, basic rules are general fundamental structural constraints,\n        additional rules are applied for the time being, and more specific rules to each dialogue are captured in the is_valid method.\n\n        :param message: the message to be validated\n        :return: Boolean result, and associated message.\n        \"\"\"\n        is_basic_validated, msg_basic_validation = self._basic_validation(message)\n        if not is_basic_validated:\n            return False, msg_basic_validation\n\n        result_is_valid, msg_is_valid = self._custom_validation(message)\n        if not result_is_valid:\n            return False, msg_is_valid\n\n        return True, \"Message is valid with respect to this dialogue.\"\n\n    def _basic_validation(self, message: Message) -> Tuple[bool, str]:\n        \"\"\"\n        Check whether 'message' is a valid next message in the dialogue, according to basic rules.\n\n        This method redirects the checks to two other methods based on whether the message\n        is the first in the dialogue or not.\n\n        :param message: the message to be validated\n        :return: Boolean result, and associated message.\n        \"\"\"\n        if self.is_empty:  # initial message\n            return self._basic_validation_initial_message(message)\n\n        return self._basic_validation_non_initial_message(message)\n\n    def _basic_validation_initial_message(self, message: Message) -> Tuple[bool, str]:\n        \"\"\"\n        Check whether an initial 'message' is a valid next message in the dialogue, according to basic rules.\n\n        These rules are designed to be fundamental to all dialogues, and enforce the following:\n\n         - message ids are consistent\n         - targets are consistent\n         - message targets are according to the reply structure of performatives\n\n        :param message: the message to be validated\n        :return: Boolean result, and associated message.\n        \"\"\"\n        dialogue_reference = message.dialogue_reference\n        message_id = message.message_id\n        performative = message.performative\n\n        if dialogue_reference[0] != self.dialogue_label.dialogue_reference[0]:\n            return (\n                False,\n                \"Invalid dialogue_reference[0]. Expected {}. Found {}.\".format(\n                    self.dialogue_label.dialogue_reference[0], dialogue_reference[0]\n                ),\n            )\n\n        if message_id != Dialogue.STARTING_MESSAGE_ID:\n            return (\n                False,\n                \"Invalid message_id. Expected {}. Found {}.\".format(\n                    Dialogue.STARTING_MESSAGE_ID, message_id\n                ),\n            )\n\n        err = self._validate_message_target(message)\n        if err:\n            return False, err\n\n        if performative not in self.rules.initial_performatives:\n            return (\n                False,\n                \"Invalid initial performative. Expected one of {}. Found {}.\".format(\n                    self.rules.initial_performatives, performative\n                ),\n            )\n\n        return True, \"The initial message passes basic validation.\"\n\n    def _basic_validation_non_initial_message(\n        self, message: Message\n    ) -> Tuple[bool, str]:\n        \"\"\"\n        Check whether a non-initial 'message' is a valid next message in the dialogue, according to basic rules.\n\n        These rules are designed to be fundamental to all dialogues, and enforce the following:\n\n         - message ids are consistent\n         - targets are consistent\n         - message targets are according to the reply structure of performatives\n\n        :param message: the message to be validated\n        :return: Boolean result, and associated message.\n        \"\"\"\n        dialogue_reference = message.dialogue_reference\n\n        if dialogue_reference[0] != self.dialogue_label.dialogue_reference[0]:\n            return (\n                False,\n                \"Invalid dialogue_reference[0]. Expected {}. Found {}.\".format(\n                    self.dialogue_label.dialogue_reference[0], dialogue_reference[0]\n                ),\n            )\n\n        err = self._validate_message_id(message)\n        if err:\n            return False, err\n\n        err = self._validate_message_target(message)\n        if err:\n            return False, err\n\n        return True, \"The non-initial message passes basic validation.\"\n\n    def _validate_message_target(self, message: Message) -> Optional[str]:\n        \"\"\"Check message target corresponds to messages in the dialogue, if not return error string.\"\"\"\n        target = message.target\n        performative = message.performative\n\n        if message.message_id == self.STARTING_MESSAGE_ID:\n            # for initial message!\n            if target == self.STARTING_TARGET:\n                # no need to check in details\n                return None\n            return \"Invalid target. Expected 0. Found {}.\".format(target)\n\n        if (\n            message.message_id != self.STARTING_MESSAGE_ID\n            and target == self.STARTING_TARGET\n        ):\n            return \"Invalid target. Expected a non-zero integer. Found {}.\".format(\n                target\n            )\n\n        # quick target check.\n        latest_ids: List[int] = []\n\n        if self.last_incoming_message:\n            latest_ids.append(abs(self.last_incoming_message.message_id))\n\n        if self.last_outgoing_message:\n            latest_ids.append(abs(self.last_outgoing_message.message_id))\n\n        if abs(target) > max(latest_ids):\n            return \"Invalid target. Expected a value less than or equal to abs({}). Found abs({}).\".format(\n                max(latest_ids), abs(target)\n            )\n\n        # detailed target check\n        target_message = self.get_message_by_id(target)\n\n        if not target_message:\n            return \"Invalid target {}. target_message can not be found.\".format(\n                target\n            )  # pragma: nocover\n\n        target_performative = target_message.performative\n        if performative not in self.rules.get_valid_replies(target_performative):\n            return \"Invalid performative. Expected one of {}. Found {}.\".format(\n                self.rules.get_valid_replies(target_performative), performative\n            )\n\n        return None\n\n    def _validate_message_id(self, message: Message) -> Optional[str]:\n        \"\"\"Check message id corresponds to message id sequences, if not return error string.\"\"\"\n        is_outgoing = message.to != self.self_address\n\n        # This assumes that messages sent by the opponent are sent in the right order.\n        if is_outgoing:\n            next_message_id = self.get_outgoing_next_message_id()\n        else:\n            next_message_id = self.get_incoming_next_message_id()\n\n        # we know what is the next message id for incoming and outgoing!\n        if message.message_id != next_message_id:\n            return \"Invalid message_id. Expected {}. Found {}.\".format(\n                next_message_id, message.message_id\n            )\n\n        return None\n\n    def get_message_by_id(self, message_id: int) -> Optional[Message]:\n        \"\"\"Get message by id, if not presents return None.\"\"\"\n        if self.is_empty:\n            return None\n\n        if message_id == 0:\n            raise ValueError(\"message_id == 0 is invalid!\")  # pragma: nocover\n\n        if bool(message_id > 0) == self.is_self_initiated:\n            messages_list = self._outgoing_messages\n        else:\n            messages_list = self._incoming_messages\n\n        if len(messages_list) == 0:\n            return None\n\n        if abs(message_id) > abs(messages_list[-1].message_id):\n            return None\n\n        return messages_list[abs(message_id) - 1]\n\n    def get_outgoing_next_message_id(self) -> int:\n        \"\"\"Get next outgoing message id.\"\"\"\n        next_message_id = Dialogue.STARTING_MESSAGE_ID\n\n        if self.last_outgoing_message:\n            next_message_id = abs(self.last_outgoing_message.message_id) + 1\n\n        if not self.is_self_initiated:\n            next_message_id = 0 - next_message_id\n\n        return next_message_id\n\n    def get_incoming_next_message_id(self) -> int:\n        \"\"\"Get next incoming message id.\"\"\"\n        next_message_id = Dialogue.STARTING_MESSAGE_ID\n\n        if self.last_incoming_message:\n            next_message_id = abs(self.last_incoming_message.message_id) + 1\n\n        if self.is_self_initiated:\n            next_message_id = 0 - next_message_id\n\n        return next_message_id\n\n    def _update_dialogue_label(self, final_dialogue_label: DialogueLabel) -> None:\n        \"\"\"\n        Update the dialogue label of the dialogue.\n\n        :param final_dialogue_label: the final dialogue label\n        \"\"\"\n        enforce(\n            self.dialogue_label.dialogue_reference[1]\n            == self.UNASSIGNED_DIALOGUE_REFERENCE\n            and final_dialogue_label.dialogue_reference[1]\n            != self.UNASSIGNED_DIALOGUE_REFERENCE,\n            \"Dialogue label cannot be updated.\",\n        )\n        self._dialogue_label = final_dialogue_label\n\n    def _custom_validation(  # pylint: disable=unused-argument\n        self, message: Message\n    ) -> Tuple[bool, str]:\n        \"\"\"\n        Check whether 'message' is a valid next message in the dialogue.\n\n        These rules capture specific constraints designed for dialogues which are instance of a concrete sub-class of this class.\n\n        :param message: the message to be validated\n        :return: True if valid, False otherwise.\n        \"\"\"\n        return True, \"The message passes custom validation.\"\n\n    def __str__(self) -> str:\n        \"\"\"\n        Get the string representation.\n\n        :return: The string representation of the dialogue\n        \"\"\"\n        representation = f\"Dialogue Label:\\n{self.dialogue_label}\\nMessages:\\n\"\n\n        for msg_id in self._ordered_message_ids:\n            msg = self.get_message_by_id(msg_id)\n            if msg is None:  # pragma: nocover\n                raise ValueError(\"Dialogue inconsistent! Missing message.\")\n            representation += f\"message_id={msg.message_id}, target={msg.target}, performative={msg.performative}\\n\"\n        return representation\n\n\nclass DialogueStats:\n    \"\"\"Class to handle statistics on default dialogues.\"\"\"\n\n    def __init__(self, end_states: FrozenSet[Dialogue.EndState]) -> None:\n        \"\"\"\n        Initialize a StatsManager.\n\n        :param end_states: the list of dialogue endstates\n        \"\"\"\n        self._self_initiated = {\n            e: 0 for e in end_states\n        }  # type: Dict[Dialogue.EndState, int]\n        self._other_initiated = {\n            e: 0 for e in end_states\n        }  # type: Dict[Dialogue.EndState, int]\n\n    @property\n    def self_initiated(self) -> Dict[Dialogue.EndState, int]:\n        \"\"\"Get the stats dictionary on self initiated dialogues.\"\"\"\n        return self._self_initiated\n\n    @property\n    def other_initiated(self) -> Dict[Dialogue.EndState, int]:\n        \"\"\"Get the stats dictionary on other initiated dialogues.\"\"\"\n        return self._other_initiated\n\n    def add_dialogue_endstate(\n        self, end_state: Dialogue.EndState, is_self_initiated: bool\n    ) -> None:\n        \"\"\"\n        Add dialogue endstate stats.\n\n        :param end_state: the end state of the dialogue\n        :param is_self_initiated: whether the dialogue is initiated by the agent or the opponent\n        \"\"\"\n        if is_self_initiated:\n            enforce(end_state in self._self_initiated, \"End state not present!\")\n            self._self_initiated[end_state] += 1\n        else:\n            enforce(end_state in self._other_initiated, \"End state not present!\")\n            self._other_initiated[end_state] += 1\n\n\ndef find_caller_object(object_type: Type) -> Any:\n    \"\"\"Find caller object of certain type in the call stack.\"\"\"\n    caller_object = None\n    for frame_info in inspect.stack():\n        frame_self = frame_info.frame.f_locals.get(\"self\", None)\n        if not frame_self:\n            continue\n\n        if not isinstance(frame_self, object_type):\n            continue\n        caller_object = frame_self\n    return caller_object\n\n\nclass BasicDialoguesStorage:\n    \"\"\"Dialogues state storage.\"\"\"\n\n    def __init__(self, dialogues: \"Dialogues\") -> None:\n        \"\"\"Init dialogues storage.\"\"\"\n        self._dialogues_by_dialogue_label = {}  # type: Dict[DialogueLabel, Dialogue]\n        self._dialogue_by_address = defaultdict(\n            list\n        )  # type: Dict[Address, List[Dialogue]]\n        self._incomplete_to_complete_dialogue_labels = (\n            {}\n        )  # type: Dict[DialogueLabel, DialogueLabel]\n        self._dialogues = dialogues\n        self._terminal_state_dialogues_labels: Set[DialogueLabel] = set()\n\n    @property\n    def dialogues_in_terminal_state(self) -> List[\"Dialogue\"]:\n        \"\"\"Get all dialogues in terminal state.\"\"\"\n        return list(\n            filter(\n                None,\n                [\n                    self._dialogues_by_dialogue_label.get(i)\n                    for i in self._terminal_state_dialogues_labels\n                ],\n            )\n        )\n\n    @property\n    def dialogues_in_active_state(self) -> List[\"Dialogue\"]:\n        \"\"\"Get all dialogues in active state.\"\"\"\n        active_dialogues = (\n            set(self._dialogues_by_dialogue_label.keys())\n            - self._terminal_state_dialogues_labels\n        )\n        return list(\n            filter(\n                None,\n                [self._dialogues_by_dialogue_label.get(i) for i in active_dialogues],\n            )\n        )\n\n    @property\n    def is_terminal_dialogues_kept(self) -> bool:\n        \"\"\"Return True if dialogues should stay after terminal state.\"\"\"\n        return self._dialogues.is_keep_dialogues_in_terminal_state\n\n    def dialogue_terminal_state_callback(self, dialogue: \"Dialogue\") -> None:\n        \"\"\"Method to be called on dialogue terminal state reached.\"\"\"\n        if self.is_terminal_dialogues_kept:\n            self._terminal_state_dialogues_labels.add(dialogue.dialogue_label)\n        else:\n            self.remove(dialogue.dialogue_label)\n\n    def setup(self) -> None:\n        \"\"\"Set up dialogue storage.\"\"\"\n\n    def teardown(self) -> None:\n        \"\"\"Tear down dialogue storage.\"\"\"\n\n    def add(self, dialogue: Dialogue) -> None:\n        \"\"\"\n        Add dialogue to storage.\n\n        :param dialogue: dialogue to add.\n        \"\"\"\n        dialogue.add_terminal_state_callback(self.dialogue_terminal_state_callback)\n        self._dialogues_by_dialogue_label[dialogue.dialogue_label] = dialogue\n        self._dialogue_by_address[\n            dialogue.dialogue_label.dialogue_opponent_addr\n        ].append(dialogue)\n\n    def _add_terminal_state_dialogue(self, dialogue: Dialogue) -> None:\n        \"\"\"\n        Add terminal state dialogue to storage.\n\n        :param dialogue: dialogue to add.\n        \"\"\"\n        self.add(dialogue)\n        self._terminal_state_dialogues_labels.add(dialogue.dialogue_label)\n\n    def remove(self, dialogue_label: DialogueLabel) -> None:\n        \"\"\"\n        Remove dialogue from storage by it's label.\n\n        :param dialogue_label: label of the dialogue to remove\n        \"\"\"\n        dialogue = self._dialogues_by_dialogue_label.pop(dialogue_label, None)\n\n        self._incomplete_to_complete_dialogue_labels.pop(dialogue_label, None)\n\n        if dialogue_label in self._terminal_state_dialogues_labels:\n            self._terminal_state_dialogues_labels.remove(dialogue_label)\n\n        if dialogue:\n            self._dialogue_by_address[dialogue_label.dialogue_opponent_addr].remove(\n                dialogue\n            )\n\n    def get(self, dialogue_label: DialogueLabel) -> Optional[Dialogue]:\n        \"\"\"\n        Get dialogue stored by it's label.\n\n        :param dialogue_label: label of the dialogue\n        :return: dialogue if presents or None\n        \"\"\"\n        return self._dialogues_by_dialogue_label.get(dialogue_label, None)\n\n    def get_dialogues_with_counterparty(self, counterparty: Address) -> List[Dialogue]:\n        \"\"\"\n        Get the dialogues by address.\n\n        :param counterparty: the counterparty\n        :return: The dialogues with the counterparty.\n        \"\"\"\n        return self._dialogue_by_address.get(counterparty, [])\n\n    def is_in_incomplete(self, dialogue_label: DialogueLabel) -> bool:\n        \"\"\"Check dialogue label presents in list of incomplete.\"\"\"\n        return dialogue_label in self._incomplete_to_complete_dialogue_labels\n\n    def set_incomplete_dialogue(\n        self,\n        incomplete_dialogue_label: DialogueLabel,\n        complete_dialogue_label: DialogueLabel,\n    ) -> None:\n        \"\"\"Set incomplete dialogue label.\"\"\"\n        self._incomplete_to_complete_dialogue_labels[\n            incomplete_dialogue_label\n        ] = complete_dialogue_label\n\n    def is_dialogue_present(self, dialogue_label: DialogueLabel) -> bool:\n        \"\"\"Check dialogue with label specified presents in storage.\"\"\"\n        return dialogue_label in self._dialogues_by_dialogue_label\n\n    def get_latest_label(self, dialogue_label: DialogueLabel) -> DialogueLabel:\n        \"\"\"Get latest label for dialogue.\"\"\"\n        return self._incomplete_to_complete_dialogue_labels.get(\n            dialogue_label, dialogue_label\n        )\n\n\nclass PersistDialoguesStorage(BasicDialoguesStorage):\n    \"\"\"\n    Persist dialogues storage.\n\n    Uses generic storage to load/save dialogues data on setup/teardown.\n    \"\"\"\n\n    INCOMPLETE_DIALOGUES_OBJECT_NAME = \"incomplete_dialogues\"\n    TERMINAL_STATE_DIALOGUES_COLLECTTION_SUFFIX = \"_terminal\"\n\n    def __init__(self, dialogues: \"Dialogues\") -> None:\n        \"\"\"Init dialogues storage.\"\"\"\n        super().__init__(dialogues)\n\n        self._skill_component: Optional[SkillComponent] = self.get_skill_component()\n\n    @staticmethod\n    def get_skill_component() -> Optional[SkillComponent]:\n        \"\"\"Get skill component dialogues storage constructed for.\"\"\"\n        caller_object = find_caller_object(SkillComponent)\n        if not caller_object:  # pragma: nocover\n            return None\n        return caller_object\n\n    def _get_collection_name(self) -> Optional[str]:\n        \"\"\"Generate collection name based on the dialogues class name and skill component.\"\"\"\n        if not self._skill_component:  # pragma: nocover\n            return None\n        return \"_\".join(\n            [\n                self._skill_component.skill_id.author,\n                self._skill_component.skill_id.name,\n                self._skill_component.name,\n                self._skill_component.__class__.__name__,\n                self._dialogues.__class__.__name__,\n            ]\n        )\n\n    def _get_collection_instance(self, col_name: str) -> Optional[SyncCollection]:\n        \"\"\"Get sync collection if generic storage available.\"\"\"\n        if (\n            not self._skill_component or not self._skill_component.context.storage\n        ):  # pragma: nocover\n            return None\n        return self._skill_component.context.storage.get_sync_collection(col_name)\n\n    @cached_property\n    def _terminal_dialogues_collection(self) -> Optional[SyncCollection]:\n        col_name = self._get_collection_name()\n        if not col_name:\n            return None\n        col_name = f\"{col_name}{self.TERMINAL_STATE_DIALOGUES_COLLECTTION_SUFFIX}\"\n        return self._get_collection_instance(col_name)\n\n    @cached_property\n    def _active_dialogues_collection(self) -> Optional[SyncCollection]:\n        col_name = self._get_collection_name()\n        if not col_name:\n            return None\n        return self._get_collection_instance(col_name)\n\n    def _dump(self) -> None:\n        \"\"\"Dump dialogues storage to the generic storage.\"\"\"\n        if (\n            not self._active_dialogues_collection\n            or not self._terminal_dialogues_collection\n        ):\n            return  # pragma: nocover\n\n        self._dump_incomplete_dialogues_labels(self._active_dialogues_collection)\n        self._dump_dialogues(\n            self.dialogues_in_active_state, self._active_dialogues_collection\n        )\n        self._dump_dialogues(\n            self.dialogues_in_terminal_state, self._terminal_dialogues_collection\n        )\n\n    def _dump_incomplete_dialogues_labels(self, collection: SyncCollection) -> None:\n        \"\"\"Dump incomplete labels.\"\"\"\n        collection.put(\n            self.INCOMPLETE_DIALOGUES_OBJECT_NAME,\n            self._incomplete_dialogues_labels_to_json(),\n        )\n\n    def _load_incomplete_dialogues_labels(self, collection: SyncCollection) -> None:\n        \"\"\"Load and set incomplete dialogue labels.\"\"\"\n        incomplete_dialogues_data = collection.get(\n            self.INCOMPLETE_DIALOGUES_OBJECT_NAME\n        )\n        if incomplete_dialogues_data is not None:\n            incomplete_dialogues_data = cast(List, incomplete_dialogues_data)\n            self._set_incomplete_dialogues_labels_from_json(incomplete_dialogues_data)\n\n    def _load_dialogues(self, collection: SyncCollection) -> Iterable[Dialogue]:\n        \"\"\"Load dialogues from collection.\"\"\"\n        if not collection:  # pragma: nocover\n            return\n        for label, dialogue_data in collection.list():\n            if label == self.INCOMPLETE_DIALOGUES_OBJECT_NAME:\n                continue\n            dialogue_data = cast(Dict, dialogue_data)\n            yield self._dialogue_from_json(dialogue_data)\n\n    def _dialogue_from_json(self, dialogue_data: dict) -> \"Dialogue\":\n        return self._dialogues.dialogue_class.from_json(\n            self._dialogues.message_class, dialogue_data\n        )\n\n    @staticmethod\n    def _dump_dialogues(\n        dialogues: Iterable[Dialogue], collection: SyncCollection\n    ) -> None:\n        \"\"\"Dump dialogues to collection.\"\"\"\n        for dialogue in dialogues:\n            collection.put(str(dialogue.dialogue_label), dialogue.json())\n\n    def _load(self) -> None:\n        \"\"\"Dump dialogues and incomplete dialogues labels from the generic storage.\"\"\"\n        if (\n            not self._active_dialogues_collection\n            or not self._terminal_dialogues_collection\n        ):\n            return  # pragma: nocover\n\n        self._load_incomplete_dialogues_labels(self._active_dialogues_collection)\n        self._load_active_dialogues()\n        self._load_terminated_dialogues()\n\n    def _load_active_dialogues(self) -> None:\n        \"\"\"Load active dialogues from storage.\"\"\"\n        for dialogue in self._load_dialogues(self._active_dialogues_collection):\n            self.add(dialogue)\n\n    def _load_terminated_dialogues(self) -> None:\n        \"\"\"Load terminated dialogues from storage.\"\"\"\n        for dialogue in self._load_dialogues(self._terminal_dialogues_collection):\n            self._add_terminal_state_dialogue(dialogue)\n\n    def _incomplete_dialogues_labels_to_json(self) -> List:\n        \"\"\"Dump incomplete_to_complete_dialogue_labels to json friendly dict.\"\"\"\n        return [\n            [k.json, v.json]\n            for k, v in self._incomplete_to_complete_dialogue_labels.items()\n        ]\n\n    def _set_incomplete_dialogues_labels_from_json(self, data: List) -> None:\n        \"\"\"Set incomplete_to_complete_dialogue_labels from json friendly dict.\"\"\"\n        self._incomplete_to_complete_dialogue_labels = {\n            DialogueLabel.from_json(k): DialogueLabel.from_json(v) for k, v in data\n        }\n\n    def setup(self) -> None:\n        \"\"\"Set up dialogue storage.\"\"\"\n        if not self._skill_component:  # pragma: nocover\n            return\n        self._load()\n\n    def teardown(self) -> None:\n        \"\"\"Tear down dialogue storage.\"\"\"\n        if not self._skill_component:  # pragma: nocover\n            return\n        self._dump()\n\n    def remove(self, dialogue_label: DialogueLabel) -> None:\n        \"\"\"Remove dialogue from memory and persistent storage.\"\"\"\n        if dialogue_label in self._terminal_state_dialogues_labels:\n            collection = self._terminal_dialogues_collection\n        else:\n            collection = self._active_dialogues_collection\n\n        super().remove(dialogue_label)\n\n        if collection:\n            collection.remove(str(dialogue_label))\n\n\nclass PersistDialoguesStorageWithOffloading(PersistDialoguesStorage):\n    \"\"\"Dialogue Storage with dialogues offloading.\"\"\"\n\n    def dialogue_terminal_state_callback(self, dialogue: \"Dialogue\") -> None:\n        \"\"\"Call on dialogue reaches terminal state.\"\"\"\n        if (\n            not self.is_terminal_dialogues_kept\n            or not self._terminal_dialogues_collection\n        ):  # pragma: nocover\n            super().dialogue_terminal_state_callback(dialogue)\n            return\n\n        # do offloading\n        # push to storage\n        self._terminal_dialogues_collection.put(\n            str(dialogue.dialogue_label), dialogue.json()\n        )\n        # remove from memory\n        self.remove(dialogue.dialogue_label)\n\n    def get(self, dialogue_label: DialogueLabel) -> Optional[Dialogue]:\n        \"\"\"Try to get dialogue by label from memory or persists storage.\"\"\"\n        dialogue = super().get(dialogue_label)\n        if dialogue:\n            return dialogue\n\n        dialogue = self._get_dialogue_from_collection(\n            dialogue_label, self._terminal_dialogues_collection\n        )\n        if dialogue:\n            # get dialogue from terminal state collection and cache it\n            self._add_terminal_state_dialogue(dialogue)\n            return dialogue\n        return None\n\n    def _get_dialogue_from_collection(\n        self, dialogue_label: \"DialogueLabel\", collection: SyncCollection\n    ) -> Optional[Dialogue]:\n        \"\"\"\n        Get dialogue by label from collection.\n\n        :param dialogue_label: label for lookup\n        :param collection: collection with dialogues\n        :return: dialogue if exists\n        \"\"\"\n        if not collection:\n            return None\n        dialogue_data = collection.get(str(dialogue_label))\n        if not dialogue_data:\n            return None\n        dialogue_data = cast(Dict, dialogue_data)\n        return self._dialogue_from_json(dialogue_data)\n\n    def _load_terminated_dialogues(self) -> None:\n        \"\"\"Skip terminated dialogues loading, cause it's offloaded.\"\"\"\n\n    def _get_dialogues_by_address_from_collection(\n        self, address: Address, collection: SyncCollection\n    ) -> List[\"Dialogue\"]:\n        \"\"\"\n        Get all dialogues with opponent address from specified collection.\n\n        :param address: address for lookup.\n        :param: collection: collection to get dialogues from.\n\n        :return: list of dialogues\n        \"\"\"\n        if not collection:\n            return []\n\n        return [\n            self._dialogue_from_json(cast(Dict, i[1]))\n            for i in collection.find(\"dialogue_label.dialogue_opponent_addr\", address)\n        ]\n\n    def get_dialogues_with_counterparty(self, counterparty: Address) -> List[Dialogue]:\n        \"\"\"\n        Get the dialogues by address.\n\n        :param counterparty: the counterparty\n        :return: The dialogues with the counterparty.\n        \"\"\"\n        dialogues = (\n            self._get_dialogues_by_address_from_collection(\n                counterparty, self._active_dialogues_collection\n            )\n            + self._get_dialogues_by_address_from_collection(\n                counterparty, self._terminal_dialogues_collection\n            )\n            + super().get_dialogues_with_counterparty(counterparty)\n        )\n        return self._unique_dialogues_by_label(dialogues)\n\n    @staticmethod\n    def _unique_dialogues_by_label(dialogues: List[Dialogue]) -> List[Dialogue]:\n        \"\"\"Filter list of dialogues by unique dialogue label.\"\"\"\n        return list(\n            {dialogue.dialogue_label: dialogue for dialogue in dialogues}.values()\n        )\n\n    @property\n    def dialogues_in_terminal_state(self) -> List[\"Dialogue\"]:\n        \"\"\"Get all dialogues in terminal state.\"\"\"\n        dialogues = super().dialogues_in_terminal_state + list(\n            self._load_dialogues(self._terminal_dialogues_collection)\n        )\n        return self._unique_dialogues_by_label(dialogues)\n\n\nclass Dialogues:\n    \"\"\"The dialogues class keeps track of all dialogues for an agent.\"\"\"\n\n    _keep_terminal_state_dialogues = False\n\n    def __init__(\n        self,\n        self_address: Address,\n        end_states: FrozenSet[Dialogue.EndState],\n        message_class: Type[Message],\n        dialogue_class: Type[Dialogue],\n        role_from_first_message: Callable[[Message, Address], Dialogue.Role],\n        keep_terminal_state_dialogues: Optional[bool] = None,\n    ) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param self_address: the address of the entity for whom dialogues are maintained\n        :param end_states: the list of dialogue endstates\n        :param message_class: the message class used\n        :param dialogue_class: the dialogue class used\n        :param role_from_first_message: the callable determining role from first message\n        :param keep_terminal_state_dialogues: specify do dialogues in terminal state should stay or not\n        \"\"\"\n\n        self._dialogues_storage = PersistDialoguesStorageWithOffloading(self)\n        self._self_address = self_address\n        self._dialogue_stats = DialogueStats(end_states)\n\n        if keep_terminal_state_dialogues is not None:\n            self._keep_terminal_state_dialogues = keep_terminal_state_dialogues\n\n        enforce(\n            issubclass(message_class, Message),\n            \"message_class is not a subclass of Message.\",\n        )\n        self._message_class = message_class\n\n        enforce(\n            issubclass(dialogue_class, Dialogue),\n            \"dialogue_class is not a subclass of Dialogue.\",\n        )\n        self._dialogue_class = dialogue_class\n\n        # Note the following might be too restrictive; if the supplied role_from_first_message function\n        # does not have the type hinting for its parameter or its return value, the second and third checks\n        # below would fail.\n        sig = signature(role_from_first_message)\n        parameter_length = len(sig.parameters.keys())\n        enforce(\n            parameter_length == 2,\n            \"Invalid number of parameters for role_from_first_message. Expected 2. Found {}.\".format(\n                parameter_length\n            ),\n        )\n        parameter_1_type = list(sig.parameters.values())[0].annotation\n        enforce(\n            parameter_1_type == Message,\n            \"Invalid type for the first parameter of role_from_first_message. Expected 'Message'. Found {}.\".format(\n                parameter_1_type\n            ),\n        )\n        parameter_2_type = list(sig.parameters.values())[1].annotation\n        enforce(\n            parameter_2_type == Address,\n            \"Invalid type for the second parameter of role_from_first_message. Expected 'Address'. Found {}.\".format(\n                parameter_2_type\n            ),\n        )\n        return_type = sig.return_annotation\n        enforce(\n            return_type == Dialogue.Role,\n            \"Invalid return type for role_from_first_message. Expected 'Dialogue.Role'. Found {}.\".format(\n                return_type\n            ),\n        )\n        self._role_from_first_message = role_from_first_message\n\n    @property\n    def is_keep_dialogues_in_terminal_state(self) -> bool:\n        \"\"\"Is required to keep dialogues in terminal state.\"\"\"\n        return self._keep_terminal_state_dialogues\n\n    @property\n    def self_address(self) -> Address:\n        \"\"\"Get the address of the agent for whom dialogues are maintained.\"\"\"\n        enforce(self._self_address != \"\", \"self_address is not set.\")\n        return self._self_address\n\n    @property\n    def dialogue_stats(self) -> DialogueStats:\n        \"\"\"\n        Get the dialogue statistics.\n\n        :return: dialogue stats object\n        \"\"\"\n        return self._dialogue_stats\n\n    @property\n    def message_class(self) -> Type[Message]:\n        \"\"\"\n        Get the message class.\n\n        :return: the message class\n        \"\"\"\n        return self._message_class\n\n    @property\n    def dialogue_class(self) -> Type[Dialogue]:\n        \"\"\"\n        Get the dialogue class.\n\n        :return: the dialogue class\n        \"\"\"\n        return self._dialogue_class\n\n    def get_dialogues_with_counterparty(self, counterparty: Address) -> List[Dialogue]:\n        \"\"\"\n        Get the dialogues by address.\n\n        :param counterparty: the counterparty\n        :return: The dialogues with the counterparty.\n        \"\"\"\n        return self._dialogues_storage.get_dialogues_with_counterparty(counterparty)\n\n    def _is_message_by_self(self, message: Message) -> bool:\n        \"\"\"\n        Check whether the message is by this agent or not.\n\n        :param message: the message\n        :return: True if message is by this agent, False otherwise\n        \"\"\"\n        return message.sender == self.self_address\n\n    def _is_message_by_other(self, message: Message) -> bool:\n        \"\"\"\n        Check whether the message is by the counterparty agent in this dialogue or not.\n\n        :param message: the message\n        :return: True if message is by the counterparty agent in this dialogue, False otherwise\n        \"\"\"\n        return not self._is_message_by_self(message)\n\n    def _counterparty_from_message(self, message: Message) -> Address:\n        \"\"\"\n        Determine the counterparty of the agent in the dialogue from a message.\n\n        :param message: the message\n        :return: The address of the counterparty\n        \"\"\"\n        counterparty = (\n            message.to if self._is_message_by_self(message) else message.sender\n        )\n        return counterparty\n\n    @classmethod\n    def new_self_initiated_dialogue_reference(cls) -> Tuple[str, str]:\n        \"\"\"\n        Return a dialogue label for a new self initiated dialogue.\n\n        :return: the next nonce\n        \"\"\"\n        return cls._generate_dialogue_nonce(), Dialogue.UNASSIGNED_DIALOGUE_REFERENCE\n\n    def create(\n        self,\n        counterparty: Address,\n        performative: Message.Performative,\n        **kwargs: Any,\n    ) -> Tuple[Message, Dialogue]:\n        \"\"\"\n        Create a dialogue with 'counterparty', with an initial message whose performative is 'performative' and contents are from 'kwargs'.\n\n        :param counterparty: the counterparty of the dialogue.\n        :param performative: the performative of the initial message.\n        :param kwargs: the content of the initial message.\n\n        :return: the initial message and the dialogue.\n        \"\"\"\n        initial_message = self._message_class(\n            dialogue_reference=self.new_self_initiated_dialogue_reference(),\n            message_id=Dialogue.STARTING_MESSAGE_ID,\n            target=Dialogue.STARTING_TARGET,\n            performative=performative,\n            **kwargs,\n        )\n        initial_message.sender = self.self_address\n        initial_message.to = counterparty\n\n        dialogue = self._create_dialogue(counterparty, initial_message)\n\n        return initial_message, dialogue\n\n    def create_with_message(\n        self, counterparty: Address, initial_message: Message\n    ) -> Dialogue:\n        \"\"\"\n        Create a dialogue with 'counterparty', with an initial message provided.\n\n        :param counterparty: the counterparty of the dialogue.\n        :param initial_message: the initial_message.\n\n        :return: the initial message and the dialogue.\n        \"\"\"\n        enforce(\n            not initial_message.has_sender,\n            \"The message's 'sender' field is already set {}\".format(initial_message),\n        )\n        enforce(\n            not initial_message.has_to,\n            \"The message's 'to' field is already set {}\".format(initial_message),\n        )\n        initial_message.sender = self.self_address\n        initial_message.to = counterparty\n\n        dialogue = self._create_dialogue(counterparty, initial_message)\n\n        return dialogue\n\n    def _create_dialogue(\n        self, counterparty: Address, initial_message: Message\n    ) -> Dialogue:\n        \"\"\"\n        Create a dialogue from an initial message provided.\n\n        :param counterparty: the counterparty of the dialogue.\n        :param initial_message: the initial_message.\n\n        :return: the dialogue.\n        \"\"\"\n        dialogue = self._create_self_initiated(\n            dialogue_opponent_addr=counterparty,\n            dialogue_reference=initial_message.dialogue_reference,\n            role=self._role_from_first_message(initial_message, self.self_address),\n        )\n\n        try:\n            dialogue._update(initial_message)  # pylint: disable=protected-access\n        except InvalidDialogueMessage as e:\n            self._dialogues_storage.remove(dialogue.dialogue_label)\n            raise ValueError(\n                f\"Cannot create a dialogue with the specified performative and contents. {e}\"\n            ) from e\n        return dialogue\n\n    def update(self, message: Message) -> Optional[Dialogue]:\n        \"\"\"\n        Update the state of dialogues with a new incoming message.\n\n        If the message is for a new dialogue, a new dialogue is created with 'message' as its first message, and returned.\n        If the message is addressed to an existing dialogue, the dialogue is retrieved, extended with this message and returned.\n        If there are any errors, e.g. the message dialogue reference does not exists or the message is invalid w.r.t. the dialogue, return None.\n\n        :param message: a new incoming message\n        :return: the new or existing dialogue the message is intended for, or None in case of any errors.\n        \"\"\"\n        enforce(\n            message.has_sender and self._is_message_by_other(message),\n            \"Invalid 'update' usage. Update must only be used with a message by another agent.\",\n        )\n        enforce(\n            message.has_to, \"The message's 'to' field is not set {}\".format(message)\n        )\n        enforce(\n            message.to == self.self_address,\n            f\"Message to and dialogue self address do not match. Got 'to={message.to}' expected 'to={self.self_address}'.\",\n        )\n\n        dialogue_reference = message.dialogue_reference\n\n        is_invalid_label = (\n            dialogue_reference[0] == Dialogue.UNASSIGNED_DIALOGUE_REFERENCE\n            and dialogue_reference[1] == Dialogue.UNASSIGNED_DIALOGUE_REFERENCE\n        )\n        is_new_dialogue = (\n            dialogue_reference[0] != Dialogue.UNASSIGNED_DIALOGUE_REFERENCE\n            and dialogue_reference[1] == Dialogue.UNASSIGNED_DIALOGUE_REFERENCE\n            and message.message_id == Dialogue.STARTING_MESSAGE_ID\n        )\n        is_incomplete_label_and_non_initial_msg = (\n            dialogue_reference[0] != Dialogue.UNASSIGNED_DIALOGUE_REFERENCE\n            and dialogue_reference[1] == Dialogue.UNASSIGNED_DIALOGUE_REFERENCE\n            and message.message_id\n            not in (Dialogue.STARTING_MESSAGE_ID, Dialogue.STARTING_TARGET)\n        )\n\n        if is_invalid_label:\n            dialogue = None  # type: Optional[Dialogue]\n        elif is_new_dialogue:  # initial message for new dialogue\n            dialogue = self._create_opponent_initiated(\n                dialogue_opponent_addr=message.sender,\n                dialogue_reference=dialogue_reference,\n                role=self._role_from_first_message(message, self.self_address),\n            )\n        elif is_incomplete_label_and_non_initial_msg:\n            # we can allow a dialogue to have incomplete reference\n            # as multiple messages can be sent before one is received with complete reference\n            dialogue = self.get_dialogue(message)\n        else:  # non-initial message for existing dialogue\n            self._complete_dialogue_reference(message)\n            dialogue = self.get_dialogue(message)\n\n        if dialogue is not None:\n            try:\n                dialogue._update(message)  # pylint: disable=protected-access\n                result = dialogue  # type: Optional[Dialogue]\n            except InvalidDialogueMessage:\n                # invalid message for the dialogue found\n                result = None\n                if (\n                    is_new_dialogue\n                ):  # remove the newly created dialogue if the initial message is invalid\n                    self._dialogues_storage.remove(dialogue.dialogue_label)\n        else:\n            # couldn't find the dialogue referenced by the message\n            result = None\n        return result\n\n    def _complete_dialogue_reference(self, message: Message) -> None:\n        \"\"\"\n        Update a self initiated dialogue label with a complete dialogue reference from counterparty's first message.\n\n        :param message: A message in the dialogue (the first by the counterparty with a complete reference)\n        \"\"\"\n        complete_dialogue_reference = message.dialogue_reference\n        enforce(\n            Dialogue.UNASSIGNED_DIALOGUE_REFERENCE\n            not in (complete_dialogue_reference[0], complete_dialogue_reference[1]),\n            \"Only complete dialogue references allowed.\",\n        )\n\n        incomplete_dialogue_reference = (\n            complete_dialogue_reference[0],\n            Dialogue.UNASSIGNED_DIALOGUE_REFERENCE,\n        )\n        incomplete_dialogue_label = DialogueLabel(\n            incomplete_dialogue_reference,\n            message.sender,\n            self.self_address,\n        )\n\n        if self._dialogues_storage.is_dialogue_present(\n            incomplete_dialogue_label\n        ) and not self._dialogues_storage.is_in_incomplete(incomplete_dialogue_label):\n            dialogue = self._dialogues_storage.get(incomplete_dialogue_label)\n            if not dialogue:  # pragma: nocover\n                raise ValueError(\"no dialogue found\")\n            self._dialogues_storage.remove(incomplete_dialogue_label)\n            final_dialogue_label = DialogueLabel(\n                complete_dialogue_reference,\n                incomplete_dialogue_label.dialogue_opponent_addr,\n                incomplete_dialogue_label.dialogue_starter_addr,\n            )\n            dialogue._update_dialogue_label(  # pylint: disable=protected-access\n                final_dialogue_label\n            )\n            self._dialogues_storage.add(dialogue)\n            self._dialogues_storage.set_incomplete_dialogue(\n                incomplete_dialogue_label, final_dialogue_label\n            )\n\n    def get_dialogue(self, message: Message) -> Optional[Dialogue]:\n        \"\"\"\n        Retrieve the dialogue 'message' belongs to.\n\n        :param message: a message\n        :return: the dialogue, or None in case such a dialogue does not exist\n        \"\"\"\n        self_initiated_dialogue_label = DialogueLabel(\n            message.dialogue_reference,\n            self._counterparty_from_message(message),\n            self.self_address,\n        )\n        other_initiated_dialogue_label = DialogueLabel(\n            message.dialogue_reference,\n            self._counterparty_from_message(message),\n            self._counterparty_from_message(message),\n        )\n\n        self_initiated_dialogue_label = self._get_latest_label(\n            self_initiated_dialogue_label\n        )\n        other_initiated_dialogue_label = self._get_latest_label(\n            other_initiated_dialogue_label\n        )\n\n        self_initiated_dialogue = self.get_dialogue_from_label(\n            self_initiated_dialogue_label\n        )\n        other_initiated_dialogue = self.get_dialogue_from_label(\n            other_initiated_dialogue_label\n        )\n\n        result = self_initiated_dialogue or other_initiated_dialogue\n        return result\n\n    def _get_latest_label(self, dialogue_label: DialogueLabel) -> DialogueLabel:\n        \"\"\"\n        Retrieve the latest dialogue label if present otherwise return same label.\n\n        :param dialogue_label: the dialogue label\n        :return: the dialogue label\n        \"\"\"\n        return self._dialogues_storage.get_latest_label(dialogue_label)\n\n    def get_dialogue_from_label(\n        self, dialogue_label: DialogueLabel\n    ) -> Optional[Dialogue]:\n        \"\"\"\n        Retrieve a dialogue based on its label.\n\n        :param dialogue_label: the dialogue label\n        :return: the dialogue if present\n        \"\"\"\n        return self._dialogues_storage.get(dialogue_label)\n\n    def _create_self_initiated(\n        self,\n        dialogue_opponent_addr: Address,\n        dialogue_reference: Tuple[str, str],\n        role: Dialogue.Role,\n    ) -> Dialogue:\n        \"\"\"\n        Create a self initiated dialogue.\n\n        :param dialogue_opponent_addr: the address of the agent with which the dialogue is kept.\n        :param dialogue_reference: the reference of the dialogue\n        :param role: the agent's role\n\n        :return: the created dialogue.\n        \"\"\"\n        enforce(\n            dialogue_reference[0] != Dialogue.UNASSIGNED_DIALOGUE_REFERENCE\n            and dialogue_reference[1] == Dialogue.UNASSIGNED_DIALOGUE_REFERENCE,\n            \"Cannot initiate dialogue with preassigned dialogue_responder_reference!\",\n        )\n        incomplete_dialogue_label = DialogueLabel(\n            dialogue_reference, dialogue_opponent_addr, self.self_address\n        )\n        dialogue = self._create(incomplete_dialogue_label, role)\n        return dialogue\n\n    def _create_opponent_initiated(\n        self,\n        dialogue_opponent_addr: Address,\n        dialogue_reference: Tuple[str, str],\n        role: Dialogue.Role,\n    ) -> Dialogue:\n        \"\"\"\n        Create an opponent initiated dialogue.\n\n        :param dialogue_opponent_addr: the address of the agent with which the dialogue is kept.\n        :param dialogue_reference: the reference of the dialogue.\n        :param role: the agent's role\n\n        :return: the created dialogue\n        \"\"\"\n        enforce(\n            dialogue_reference[0] != Dialogue.UNASSIGNED_DIALOGUE_REFERENCE\n            and dialogue_reference[1] == Dialogue.UNASSIGNED_DIALOGUE_REFERENCE,\n            \"Cannot initiate dialogue with preassigned dialogue_responder_reference!\",\n        )\n        incomplete_dialogue_label = DialogueLabel(\n            dialogue_reference, dialogue_opponent_addr, dialogue_opponent_addr\n        )\n        new_dialogue_reference = (\n            dialogue_reference[0],\n            self._generate_dialogue_nonce(),\n        )\n        complete_dialogue_label = DialogueLabel(\n            new_dialogue_reference, dialogue_opponent_addr, dialogue_opponent_addr\n        )\n        dialogue = self._create(\n            incomplete_dialogue_label, role, complete_dialogue_label\n        )\n        return dialogue\n\n    def _create(\n        self,\n        incomplete_dialogue_label: DialogueLabel,\n        role: Dialogue.Role,\n        complete_dialogue_label: Optional[DialogueLabel] = None,\n    ) -> Dialogue:\n        \"\"\"\n        Create a dialogue from label and role.\n\n        :param incomplete_dialogue_label: the dialogue label (incomplete)\n        :param role: the agent's role\n        :param complete_dialogue_label: the dialogue label (complete)\n\n        :return: the created dialogue\n        \"\"\"\n        enforce(\n            not self._dialogues_storage.is_in_incomplete(incomplete_dialogue_label),\n            \"Incomplete dialogue label already present.\",\n        )\n        if complete_dialogue_label is None:\n            dialogue_label = incomplete_dialogue_label\n        else:\n            self._dialogues_storage.set_incomplete_dialogue(\n                incomplete_dialogue_label, complete_dialogue_label\n            )\n            dialogue_label = complete_dialogue_label\n        enforce(\n            not self._dialogues_storage.is_dialogue_present(dialogue_label),\n            \"Dialogue label already present in dialogues.\",\n        )\n        dialogue = self._dialogue_class(\n            dialogue_label=dialogue_label,\n            message_class=self._message_class,\n            self_address=self.self_address,\n            role=role,\n        )\n        self._dialogues_storage.add(dialogue)\n        return dialogue\n\n    @staticmethod\n    def _generate_dialogue_nonce() -> str:\n        \"\"\"\n        Generate the nonce and return it.\n\n        :return: the next nonce\n        \"\"\"\n        return secrets.token_hex(DialogueLabel.NONCE_BYTES_NB)\n\n    def setup(self) -> None:\n        \"\"\"Set  up.\"\"\"\n        self._dialogues_storage.setup()\n        super_obj = super()\n        if hasattr(super_obj, \"setup\"):  # pragma: nocover\n            super_obj.setup()  # type: ignore  # pylint: disable=no-member\n\n    def teardown(self) -> None:\n        \"\"\"Tear down.\"\"\"\n        self._dialogues_storage.teardown()\n        super_obj = super()\n        if hasattr(super_obj, \"teardown\"):  # pragma: nocover\n            super_obj.teardown()  # type: ignore  # pylint: disable=no-member\n"
  },
  {
    "path": "aea/protocols/generator/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains the protocol generator modules.\"\"\"\n"
  },
  {
    "path": "aea/protocols/generator/base.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the protocol generator.\"\"\"\nimport itertools\nimport os\nimport re\nimport shutil\n\n# pylint: skip-file\nfrom pathlib import Path\nfrom typing import Optional, Tuple\n\n# pylint: skip-file\nfrom aea.__version__ import __version__ as __aea_version__\nfrom aea.configurations.base import ProtocolSpecificationParseError\nfrom aea.configurations.constants import (\n    PROTOCOL_LANGUAGE_PYTHON,\n    SUPPORTED_PROTOCOL_LANGUAGES,\n)\nfrom aea.configurations.data_types import PublicId\nfrom aea.protocols.generator.common import (\n    CUSTOM_TYPES_DOT_PY_FILE_NAME,\n    DIALOGUE_DOT_PY_FILE_NAME,\n    INIT_FILE_NAME,\n    MESSAGE_DOT_PY_FILE_NAME,\n    MESSAGE_IMPORT,\n    PATH_TO_PACKAGES,\n    PROTOCOL_YAML_FILE_NAME,\n    PYTHON_TYPE_TO_PROTO_TYPE,\n    SERIALIZATION_DOT_PY_FILE_NAME,\n    SERIALIZER_IMPORT,\n    _camel_case_to_snake_case,\n    _create_protocol_file,\n    _get_sub_types_of_compositional_types,\n    _includes_custom_type,\n    _is_compositional_type,\n    _python_pt_or_ct_type_to_proto_type,\n    _to_camel_case,\n    _union_sub_type_to_protobuf_variable_name,\n    apply_protolint,\n    check_prerequisites,\n    compile_protobuf_using_protoc,\n    get_protoc_version,\n    load_protocol_specification,\n    try_run_black_formatting,\n    try_run_isort_formatting,\n)\nfrom aea.protocols.generator.extract_specification import extract\nfrom aea.protocols.generator.validate import validate\n\n\nPYLINT_DISABLE_SERIALIZATION_PY = [\n    \"too-many-statements\",\n    \"too-many-locals\",\n    \"no-member\",\n    \"too-few-public-methods\",\n    \"redefined-builtin\",\n]\nPYLINT_DISABLE_MESSAGE_PY = [\n    \"too-many-statements\",\n    \"too-many-locals\",\n    \"no-member\",\n    \"too-few-public-methods\",\n    \"too-many-branches\",\n    \"not-an-iterable\",\n    \"unidiomatic-typecheck\",\n    \"unsubscriptable-object\",\n]\n\n\ndef _type_check(variable_name: str, variable_type: str) -> str:\n    \"\"\"\n    Return the type check Python instruction.\n\n    If variable_type == int:\n\n        type(variable_name) == int\n\n    else:\n\n        isinstance(variable_name, variable_type)\n\n    :param variable_name: the variable name.\n    :param variable_type: the variable type.\n    :return: the Python instruction to check the type, in string form.\n    \"\"\"\n    if variable_type != \"int\":\n        return f\"isinstance({variable_name}, {variable_type})\"\n    else:\n        return f\"type({variable_name}) is {variable_type}\"\n\n\ncopy_right_str = \"# -*- coding: utf-8 -*-\\n\"\n\n\ndef _copyright_header_str(author: str) -> str:\n    \"\"\"\n    Produce the copyright header text for a protocol.\n\n    :param author: the author of the protocol.\n    :return: The copyright header text.\n    \"\"\"\n    return copy_right_str\n\n\nclass ProtocolGenerator:\n    \"\"\"This class generates a protocol_verification package from a ProtocolTemplate object.\"\"\"\n\n    def __init__(\n        self,\n        path_to_protocol_specification: str,\n        output_path: str = \".\",\n        dotted_path_to_protocol_package: Optional[str] = None,\n    ) -> None:\n        \"\"\"\n        Instantiate a protocol generator.\n\n        :param path_to_protocol_specification: path to protocol specification file\n        :param output_path: the path to the location in which the protocol module is to be generated.\n        :param dotted_path_to_protocol_package: the path to the protocol package\n\n        :raises FileNotFoundError if any prerequisite application is not installed\n        :raises yaml.YAMLError if yaml parser encounters an error condition\n        :raises ProtocolSpecificationParseError if specification fails generator's validation\n        \"\"\"\n        # Check the prerequisite applications are installed\n        try:\n            check_prerequisites()\n        except FileNotFoundError:\n            raise\n\n        self.protoc_version = get_protoc_version()\n\n        # Load protocol specification yaml file\n        self.protocol_specification = load_protocol_specification(\n            path_to_protocol_specification\n        )\n\n        # Validate the specification\n        result_bool, result_msg = validate(self.protocol_specification)\n        if not result_bool:\n            raise ProtocolSpecificationParseError(result_msg)\n\n        # Extract specification fields\n        self.spec = extract(self.protocol_specification)\n\n        # Helper fields\n        self.path_to_protocol_specification = path_to_protocol_specification\n        self.protocol_specification_in_camel_case = _to_camel_case(\n            self.protocol_specification.name\n        )\n        self.path_to_generated_protocol_package = os.path.join(\n            output_path, self.protocol_specification.name\n        )\n        self.dotted_path_to_protocol_package = (\n            dotted_path_to_protocol_package + self.protocol_specification.name\n            if dotted_path_to_protocol_package is not None\n            else \"{}.{}.protocols.{}\".format(\n                PATH_TO_PACKAGES,\n                self.protocol_specification.author,\n                self.protocol_specification.name,\n            )\n        )\n        self.indent = \"\"\n\n    def _change_indent(self, number: int, mode: str = None) -> None:\n        \"\"\"\n        Update the value of 'indent' global variable.\n\n        This function controls the indentation of the code produced throughout the generator.\n\n        There are two modes:\n        - Setting the indent to a desired 'number' level. In this case, 'mode' has to be set to \"s\".\n        - Updating the incrementing/decrementing the indentation level by 'number' amounts. In this case 'mode' is None.\n\n        :param number: the number of indentation levels to set/increment/decrement\n        :param mode: the mode of indentation change\n        \"\"\"\n        if mode and mode == \"s\":\n            if number >= 0:\n                self.indent = number * \"    \"\n            else:\n                raise ValueError(\"Error: setting indent to be a negative number.\")\n        else:\n            if number >= 0:\n                for _ in itertools.repeat(None, number):\n                    self.indent += \"    \"\n            else:\n                if abs(number) <= len(self.indent) / 4:\n                    self.indent = self.indent[abs(number) * 4 :]\n                else:\n                    raise ValueError(\n                        \"Not enough spaces in the 'indent' variable to remove.\"\n                    )\n\n    def _import_from_typing_module(self) -> str:\n        \"\"\"\n        Manage import statement for the typing package.\n\n        :return: import statement for the typing package\n        \"\"\"\n        ordered_packages = [\n            \"Dict\",\n            \"FrozenSet\",\n            \"Optional\",\n            \"Set\",\n            \"Tuple\",\n            \"Union\",\n            \"cast\",\n        ]\n        import_str = \"from typing import Any, \"\n        for package in ordered_packages:\n            if self.spec.typing_imports[package]:\n                import_str += \"{}, \".format(package)\n        import_str = import_str[:-2]\n        return import_str\n\n    def _import_from_custom_types_module(self) -> str:\n        \"\"\"\n        Manage import statement from custom_types module.\n\n        :return: import statement for the custom_types module\n        \"\"\"\n        import_str = \"\"\n        if len(self.spec.all_custom_types) == 0:\n            pass\n        else:\n            for custom_class in self.spec.all_custom_types:\n                import_str += \"from {}.custom_types import {} as Custom{}\\n\".format(\n                    self.dotted_path_to_protocol_package,\n                    custom_class,\n                    custom_class,\n                )\n            import_str = import_str[:-1]\n        return import_str\n\n    def _performatives_str(self) -> str:\n        \"\"\"\n        Generate the performatives instance property string, a set containing all valid performatives of this protocol.\n\n        :return: the performatives set string\n        \"\"\"\n        performatives_str = \"{\"\n        for performative in self.spec.all_performatives:\n            performatives_str += '\"{}\", '.format(performative)\n        performatives_str = performatives_str[:-2]\n        performatives_str += \"}\"\n        return performatives_str\n\n    def _performatives_enum_str(self) -> str:\n        \"\"\"\n        Generate the performatives Enum class.\n\n        :return: the performatives Enum string\n        \"\"\"\n        enum_str = self.indent + \"class Performative(Message.Performative):\\n\"\n        self._change_indent(1)\n        enum_str += self.indent + '\"\"\"Performatives for the {} protocol.\"\"\"\\n\\n'.format(\n            self.protocol_specification.name\n        )\n        for performative in self.spec.all_performatives:\n            enum_str += self.indent + '{} = \"{}\"\\n'.format(\n                performative.upper(), performative\n            )\n        enum_str += \"\\n\"\n        enum_str += self.indent + \"def __str__(self) -> str:\\n\"\n        self._change_indent(1)\n        enum_str += self.indent + '\"\"\"Get the string representation.\"\"\"\\n'\n        enum_str += self.indent + \"return str(self.value)\\n\"\n        self._change_indent(-1)\n        enum_str += \"\\n\"\n        self._change_indent(-1)\n\n        return enum_str\n\n    def _to_custom_custom(self, content_type: str) -> str:\n        \"\"\"\n        Evaluate whether a content type is a custom type or has a custom type as a sub-type.\n\n        :param content_type: the content type.\n        :return: Boolean result\n        \"\"\"\n        new_content_type = content_type\n        if _includes_custom_type(content_type):\n            for custom_type in self.spec.all_custom_types:\n                new_content_type = re.sub(\n                    rf\"(^|[ \\[\\,])({custom_type})($|[, \\]])\",\n                    rf\"\\g<1>{self.spec.custom_custom_types[custom_type]}\\g<3>\",\n                    new_content_type,\n                )\n        return new_content_type\n\n    def _check_content_type_str(self, content_name: str, content_type: str) -> str:\n        \"\"\"\n        Produce the checks of elements of compositional types.\n\n        :param content_name: the name of the content to be checked\n        :param content_type: the type of the content to be checked\n\n        :return: the string containing the checks.\n        \"\"\"\n        check_str = \"\"\n        if content_type.startswith(\"Optional[\"):\n            optional = True\n            check_str += self.indent + 'if self.is_set(\"{}\"):\\n'.format(content_name)\n            self._change_indent(1)\n            check_str += self.indent + \"expected_nb_of_contents += 1\\n\"\n            content_type = _get_sub_types_of_compositional_types(content_type)[0]\n            check_str += self.indent + \"{} = cast({}, self.{})\\n\".format(\n                content_name, self._to_custom_custom(content_type), content_name\n            )\n            content_variable = content_name\n        else:\n            optional = False\n            content_variable = \"self.\" + content_name\n        if content_type.startswith(\"Union[\"):\n            element_types = _get_sub_types_of_compositional_types(content_type)\n            unique_standard_types_set = set()\n            for typing_content_type in element_types:\n                if typing_content_type.startswith(\"FrozenSet\"):\n                    unique_standard_types_set.add(\"frozenset\")\n                elif typing_content_type.startswith(\"Tuple\"):\n                    unique_standard_types_set.add(\"tuple\")\n                elif typing_content_type.startswith(\"Dict\"):\n                    unique_standard_types_set.add(\"dict\")\n                else:\n                    unique_standard_types_set.add(typing_content_type)\n            unique_standard_types_list = sorted(unique_standard_types_set)\n            check_str += self.indent\n            check_str += \"enforce(\"\n            for unique_type in unique_standard_types_list:\n                check_str += \"{} or \".format(\n                    _type_check(content_variable, self._to_custom_custom(unique_type))\n                )\n            check_str = check_str[:-4]\n            check_str += \", \\\"Invalid type for content '{}'. Expected either of '{}'. Found '{{}}'.\\\".format(type({})))\\n\".format(\n                content_name,\n                [\n                    unique_standard_type\n                    for unique_standard_type in unique_standard_types_list\n                ],\n                content_variable,\n            )\n            if \"frozenset\" in unique_standard_types_list:\n                check_str += self.indent + \"if isinstance({}, frozenset):\\n\".format(\n                    content_variable\n                )\n                self._change_indent(1)\n                check_str += self.indent + \"enforce(\\n\"\n                self._change_indent(1)\n                frozen_set_element_types_set = set()\n                for element_type in element_types:\n                    if element_type.startswith(\"FrozenSet\"):\n                        frozen_set_element_types_set.add(\n                            _get_sub_types_of_compositional_types(element_type)[0]\n                        )\n                frozen_set_element_types = sorted(frozen_set_element_types_set)\n                for frozen_set_element_type in frozen_set_element_types:\n                    check_str += self.indent + \"all({} for element in {}) or\\n\".format(\n                        _type_check(\n                            \"element\", self._to_custom_custom(frozen_set_element_type)\n                        ),\n                        content_variable,\n                    )\n                check_str = check_str[:-4]\n                check_str += \"\\n\"\n                self._change_indent(-1)\n                if len(frozen_set_element_types) == 1:\n                    check_str += (\n                        self.indent\n                        + \", \\\"Invalid type for elements of content '{}'. Expected \".format(\n                            content_name\n                        )\n                    )\n                    for frozen_set_element_type in frozen_set_element_types:\n                        check_str += \"'{}'\".format(\n                            self._to_custom_custom(frozen_set_element_type)\n                        )\n                    check_str += '.\")\\n'\n                else:\n                    check_str += (\n                        self.indent\n                        + \", \\\"Invalid type for frozenset elements in content '{}'. Expected either \".format(\n                            content_name\n                        )\n                    )\n                    for frozen_set_element_type in frozen_set_element_types:\n                        check_str += \"'{}' or \".format(\n                            self._to_custom_custom(frozen_set_element_type)\n                        )\n                    check_str = check_str[:-4]\n                    check_str += '.\")\\n'\n                self._change_indent(-1)\n            if \"tuple\" in unique_standard_types_list:\n                check_str += self.indent + \"if isinstance({}, tuple):\\n\".format(\n                    content_variable\n                )\n                self._change_indent(1)\n                check_str += self.indent + \"enforce(\\n\"\n                self._change_indent(1)\n                tuple_element_types_set = set()\n                for element_type in element_types:\n                    if element_type.startswith(\"Tuple\"):\n                        tuple_element_types_set.add(\n                            _get_sub_types_of_compositional_types(element_type)[0]\n                        )\n                tuple_element_types = sorted(tuple_element_types_set)\n                for tuple_element_type in tuple_element_types:\n                    check_str += self.indent + \"all({} for element in {}) or \\n\".format(\n                        _type_check(\n                            \"element\", self._to_custom_custom(tuple_element_type)\n                        ),\n                        content_variable,\n                    )\n                check_str = check_str[:-4]\n                check_str += \"\\n\"\n                self._change_indent(-1)\n                if len(tuple_element_types) == 1:\n                    check_str += (\n                        self.indent\n                        + \", \\\"Invalid type for tuple elements in content '{}'. Expected \".format(\n                            content_name\n                        )\n                    )\n                    for tuple_element_type in tuple_element_types:\n                        check_str += \"'{}'\".format(\n                            self._to_custom_custom(tuple_element_type)\n                        )\n                    check_str += '.\")\\n'\n                else:\n                    check_str += (\n                        self.indent\n                        + \", \\\"Invalid type for tuple elements in content '{}'. Expected either \".format(\n                            content_name\n                        )\n                    )\n                    for tuple_element_type in tuple_element_types:\n                        check_str += \"'{}' or \".format(\n                            self._to_custom_custom(tuple_element_type)\n                        )\n                    check_str = check_str[:-4]\n                    check_str += '.\")\\n'\n                self._change_indent(-1)\n            if \"dict\" in unique_standard_types_list:\n                check_str += self.indent + \"if isinstance({}, dict):\\n\".format(\n                    content_variable\n                )\n                self._change_indent(1)\n                check_str += (\n                    self.indent\n                    + \"for key_of_{}, value_of_{} in {}.items():\\n\".format(\n                        content_name, content_name, content_variable\n                    )\n                )\n                self._change_indent(1)\n                check_str += self.indent + \"enforce(\\n\"\n                self._change_indent(1)\n                dict_key_value_types = {}\n                for element_type in element_types:\n                    if element_type.startswith(\"Dict\"):\n                        dict_key_value_types[\n                            _get_sub_types_of_compositional_types(element_type)[0]\n                        ] = _get_sub_types_of_compositional_types(element_type)[1]\n                for element1_type in sorted(dict_key_value_types.keys()):\n                    check_str += self.indent + \"({} and {}) or\\n\".format(\n                        _type_check(\n                            \"key_of_\" + content_name,\n                            self._to_custom_custom(element1_type),\n                        ),\n                        _type_check(\n                            \"value_of_\" + content_name,\n                            self._to_custom_custom(dict_key_value_types[element1_type]),\n                        ),\n                    )\n                check_str = check_str[:-4]\n                check_str += \"\\n\"\n                self._change_indent(-1)\n\n                if len(dict_key_value_types) == 1:\n                    check_str += (\n                        self.indent\n                        + \", \\\"Invalid type for dictionary key, value in content '{}'. Expected \".format(\n                            content_name\n                        )\n                    )\n                    for key in sorted(dict_key_value_types.keys()):\n                        check_str += \"'{}', '{}'\".format(key, dict_key_value_types[key])\n                    check_str += '.\")\\n'\n                else:\n                    check_str += (\n                        self.indent\n                        + \", \\\"Invalid type for dictionary key, value in content '{}'. Expected \".format(\n                            content_name\n                        )\n                    )\n                    for key in sorted(dict_key_value_types.keys()):\n                        check_str += \"'{}','{}' or \".format(\n                            key, dict_key_value_types[key]\n                        )\n                    check_str = check_str[:-4]\n                    check_str += '.\")\\n'\n                self._change_indent(-2)\n        elif content_type.startswith(\"FrozenSet[\"):\n            # check the type\n            check_str += (\n                self.indent\n                + \"enforce(isinstance({}, frozenset), \\\"Invalid type for content '{}'. Expected 'frozenset'. Found '{{}}'.\\\".format(type({})))\\n\".format(\n                    content_variable, content_name, content_variable\n                )\n            )\n            element_type = _get_sub_types_of_compositional_types(content_type)[0]\n            check_str += self.indent + \"enforce(all(\\n\"\n            self._change_indent(1)\n            check_str += self.indent + \"{} for element in {}\\n\".format(\n                _type_check(\"element\", self._to_custom_custom(element_type)),\n                content_variable,\n            )\n            self._change_indent(-1)\n            check_str += (\n                self.indent\n                + \"), \\\"Invalid type for frozenset elements in content '{}'. Expected '{}'.\\\")\\n\".format(\n                    content_name, element_type\n                )\n            )\n        elif content_type.startswith(\"Tuple[\"):\n            # check the type\n            check_str += (\n                self.indent\n                + \"enforce(isinstance({}, tuple), \\\"Invalid type for content '{}'. Expected 'tuple'. Found '{{}}'.\\\".format(type({})))\\n\".format(\n                    content_variable, content_name, content_variable\n                )\n            )\n            element_type = _get_sub_types_of_compositional_types(content_type)[0]\n            check_str += self.indent + \"enforce(all(\\n\"\n            self._change_indent(1)\n            check_str += self.indent + \"{} for element in {}\\n\".format(\n                _type_check(\"element\", self._to_custom_custom(element_type)),\n                content_variable,\n            )\n            self._change_indent(-1)\n            check_str += (\n                self.indent\n                + \"), \\\"Invalid type for tuple elements in content '{}'. Expected '{}'.\\\")\\n\".format(\n                    content_name, element_type\n                )\n            )\n        elif content_type.startswith(\"Dict[\"):\n            # check the type\n            check_str += (\n                self.indent\n                + \"enforce(isinstance({}, dict), \\\"Invalid type for content '{}'. Expected 'dict'. Found '{{}}'.\\\".format(type({})))\\n\".format(\n                    content_variable, content_name, content_variable\n                )\n            )\n            element_type_1 = _get_sub_types_of_compositional_types(content_type)[0]\n            element_type_2 = _get_sub_types_of_compositional_types(content_type)[1]\n            # check the keys type then check the values type\n            check_str += (\n                self.indent\n                + \"for key_of_{}, value_of_{} in {}.items():\\n\".format(\n                    content_name, content_name, content_variable\n                )\n            )\n            self._change_indent(1)\n            check_str += self.indent + \"enforce(\\n\"\n            self._change_indent(1)\n            check_str += self.indent + \"{}\\n\".format(\n                _type_check(\n                    \"key_of_\" + content_name, self._to_custom_custom(element_type_1)\n                )\n            )\n            self._change_indent(-1)\n            check_str += (\n                self.indent\n                + \", \\\"Invalid type for dictionary keys in content '{}'. Expected '{}'. Found '{{}}'.\\\".format(type(key_of_{})))\\n\".format(\n                    content_name, element_type_1, content_name\n                )\n            )\n\n            check_str += self.indent + \"enforce(\\n\"\n            self._change_indent(1)\n            check_str += self.indent + \"{}\\n\".format(\n                _type_check(\n                    \"value_of_\" + content_name, self._to_custom_custom(element_type_2)\n                )\n            )\n            self._change_indent(-1)\n            check_str += (\n                self.indent\n                + \", \\\"Invalid type for dictionary values in content '{}'. Expected '{}'. Found '{{}}'.\\\".format(type(value_of_{})))\\n\".format(\n                    content_name, element_type_2, content_name\n                )\n            )\n            self._change_indent(-1)\n        else:\n            check_str += (\n                self.indent\n                + \"enforce({}, \\\"Invalid type for content '{}'. Expected '{}'. Found '{{}}'.\\\".format(type({})))\\n\".format(\n                    _type_check(content_variable, self._to_custom_custom(content_type)),\n                    content_name,\n                    content_type,\n                    content_variable,\n                )\n            )\n        if optional:\n            self._change_indent(-1)\n        return check_str\n\n    def _message_class_str(self) -> str:\n        \"\"\"\n        Produce the content of the Message class.\n\n        :return: the message.py file content\n        \"\"\"\n        self._change_indent(0, \"s\")\n\n        # Header\n        cls_str = _copyright_header_str(self.protocol_specification.author) + \"\\n\"\n\n        # Module docstring\n        cls_str += (\n            self.indent\n            + '\"\"\"This module contains {}\\'s message definition.\"\"\"\\n\\n'.format(\n                self.protocol_specification.name\n            )\n        )\n\n        cls_str += f\"# pylint: disable={','.join(PYLINT_DISABLE_MESSAGE_PY)}\\n\"\n\n        # Imports\n        cls_str += self.indent + \"import logging\\n\"\n        cls_str += self._import_from_typing_module() + \"\\n\\n\"\n        cls_str += self.indent + \"from aea.configurations.base import PublicId\\n\"\n        cls_str += self.indent + \"from aea.exceptions import AEAEnforceError, enforce\\n\"\n        cls_str += MESSAGE_IMPORT + \"\\n\"\n        if self._import_from_custom_types_module() != \"\":\n            cls_str += \"\\n\" + self._import_from_custom_types_module() + \"\\n\"\n        else:\n            cls_str += self._import_from_custom_types_module()\n        cls_str += (\n            self.indent\n            + '\\n_default_logger = logging.getLogger(\"aea.packages.{}.protocols.{}.message\")\\n'.format(\n                self.protocol_specification.author, self.protocol_specification.name\n            )\n        )\n        cls_str += self.indent + \"\\nDEFAULT_BODY_SIZE = 4\\n\"\n\n        # Class Header\n        cls_str += self.indent + \"\\n\\nclass {}Message(Message):\\n\".format(\n            self.protocol_specification_in_camel_case\n        )\n        self._change_indent(1)\n        cls_str += self.indent + '\"\"\"{}\"\"\"\\n\\n'.format(\n            self.protocol_specification.description\n        )\n\n        # Class attributes\n        cls_str += self.indent + 'protocol_id = PublicId.from_str(\"{}/{}:{}\")\\n'.format(\n            self.protocol_specification.author,\n            self.protocol_specification.name,\n            self.protocol_specification.version,\n        )\n\n        cls_str += (\n            self.indent\n            + 'protocol_specification_id = PublicId.from_str(\"{}/{}:{}\")\\n'.format(\n                self.protocol_specification.protocol_specification_id.author,\n                self.protocol_specification.protocol_specification_id.name,\n                self.protocol_specification.protocol_specification_id.version,\n            )\n        )\n\n        for custom_type in self.spec.all_custom_types:\n            cls_str += \"\\n\"\n            cls_str += self.indent + \"{} = Custom{}\\n\".format(custom_type, custom_type)\n\n        # Performatives Enum\n        cls_str += \"\\n\" + self._performatives_enum_str()\n        cls_str += self.indent + \"_performatives = {}\\n\".format(\n            self._performatives_str()\n        )\n\n        # slots\n        cls_str += self.indent + \"__slots__: Tuple[str, ...] = tuple()\\n\"\n\n        cls_str += self.indent + \"class _SlotsCls():\\n\"\n        self._change_indent(1)\n        cls_str += self.indent + \"__slots__ = (\\n\"\n        self._change_indent(1)\n        # default fields\n        default_slots = [\"performative\", \"dialogue_reference\", \"message_id\", \"target\"]\n        slots = list(self.spec.all_unique_contents.keys()) + default_slots\n        for field_name in sorted(slots):\n            cls_str += self.indent + f'\"{field_name}\",'\n        self._change_indent(-1)\n        cls_str += self.indent + \")\\n\"\n        self._change_indent(-1)\n\n        # __init__\n        cls_str += self.indent + \"def __init__(\\n\"\n        self._change_indent(1)\n        cls_str += self.indent + \"self,\\n\"\n        cls_str += self.indent + \"performative: Performative,\\n\"\n        cls_str += self.indent + 'dialogue_reference: Tuple[str, str] = (\"\", \"\"),\\n'\n        cls_str += self.indent + \"message_id: int = 1,\\n\"\n        cls_str += self.indent + \"target: int = 0,\\n\"\n        cls_str += self.indent + \"**kwargs: Any,\\n\"\n        self._change_indent(-1)\n        cls_str += self.indent + \"):\\n\"\n        self._change_indent(1)\n        cls_str += self.indent + '\"\"\"\\n'\n        cls_str += self.indent + \"Initialise an instance of {}Message.\\n\\n\".format(\n            self.protocol_specification_in_camel_case\n        )\n        cls_str += self.indent + \":param message_id: the message id.\\n\"\n        cls_str += self.indent + \":param dialogue_reference: the dialogue reference.\\n\"\n        cls_str += self.indent + \":param target: the message target.\\n\"\n        cls_str += self.indent + \":param performative: the message performative.\\n\"\n        cls_str += self.indent + \":param **kwargs: extra options.\\n\"\n        cls_str += self.indent + '\"\"\"\\n'\n\n        cls_str += self.indent + \"super().__init__(\\n\"\n        self._change_indent(1)\n        cls_str += self.indent + \"dialogue_reference=dialogue_reference,\\n\"\n        cls_str += self.indent + \"message_id=message_id,\\n\"\n        cls_str += self.indent + \"target=target,\\n\"\n        cls_str += (\n            self.indent\n            + \"performative={}Message.Performative(performative),\\n\".format(\n                self.protocol_specification_in_camel_case\n            )\n        )\n        cls_str += self.indent + \"**kwargs,\\n\"\n        self._change_indent(-1)\n        cls_str += self.indent + \")\\n\"\n\n        self._change_indent(-1)\n\n        # Instance properties\n        cls_str += self.indent + \"@property\\n\"\n        cls_str += self.indent + \"def valid_performatives(self) -> Set[str]:\\n\"\n        self._change_indent(1)\n        cls_str += self.indent + '\"\"\"Get valid performatives.\"\"\"\\n'\n        cls_str += self.indent + \"return self._performatives\\n\\n\"\n        self._change_indent(-1)\n        cls_str += self.indent + \"@property\\n\"\n        cls_str += self.indent + \"def dialogue_reference(self) -> Tuple[str, str]:\\n\"\n        self._change_indent(1)\n        cls_str += self.indent + '\"\"\"Get the dialogue_reference of the message.\"\"\"\\n'\n        cls_str += (\n            self.indent\n            + 'enforce(self.is_set(\"dialogue_reference\"), \"dialogue_reference is not set.\")\\n'\n        )\n        cls_str += (\n            self.indent\n            + 'return cast(Tuple[str, str], self.get(\"dialogue_reference\"))\\n\\n'\n        )\n        self._change_indent(-1)\n        cls_str += self.indent + \"@property\\n\"\n        cls_str += self.indent + \"def message_id(self) -> int:\\n\"\n        self._change_indent(1)\n        cls_str += self.indent + '\"\"\"Get the message_id of the message.\"\"\"\\n'\n        cls_str += (\n            self.indent\n            + 'enforce(self.is_set(\"message_id\"), \"message_id is not set.\")\\n'\n        )\n        cls_str += self.indent + 'return cast(int, self.get(\"message_id\"))\\n\\n'\n        self._change_indent(-1)\n        cls_str += self.indent + \"@property\\n\"\n        cls_str += (\n            self.indent\n            + \"def performative(self) -> Performative:  # type: ignore # noqa: F821\\n\"\n        )\n        self._change_indent(1)\n        cls_str += self.indent + '\"\"\"Get the performative of the message.\"\"\"\\n'\n        cls_str += (\n            self.indent\n            + 'enforce(self.is_set(\"performative\"), \"performative is not set.\")\\n'\n        )\n        cls_str += (\n            self.indent\n            + 'return cast({}Message.Performative, self.get(\"performative\"))\\n\\n'.format(\n                self.protocol_specification_in_camel_case\n            )\n        )\n        self._change_indent(-1)\n        cls_str += self.indent + \"@property\\n\"\n        cls_str += self.indent + \"def target(self) -> int:\\n\"\n        self._change_indent(1)\n        cls_str += self.indent + '\"\"\"Get the target of the message.\"\"\"\\n'\n        cls_str += (\n            self.indent + 'enforce(self.is_set(\"target\"), \"target is not set.\")\\n'\n        )\n        cls_str += self.indent + 'return cast(int, self.get(\"target\"))\\n\\n'\n        self._change_indent(-1)\n\n        for content_name in sorted(self.spec.all_unique_contents.keys()):\n            content_type = self.spec.all_unique_contents[content_name]\n            cls_str += self.indent + \"@property\\n\"\n            cls_str += self.indent + \"def {}(self) -> {}:\\n\".format(\n                content_name, self._to_custom_custom(content_type)\n            )\n            self._change_indent(1)\n            cls_str += (\n                self.indent\n                + '\"\"\"Get the \\'{}\\' content from the message.\"\"\"\\n'.format(\n                    content_name\n                )\n            )\n            if not content_type.startswith(\"Optional\"):\n                cls_str += (\n                    self.indent\n                    + 'enforce(self.is_set(\"{}\"), \"\\'{}\\' content is not set.\")\\n'.format(\n                        content_name, content_name\n                    )\n                )\n            cls_str += self.indent + 'return cast({}, self.get(\"{}\"))\\n\\n'.format(\n                self._to_custom_custom(content_type), content_name\n            )\n            self._change_indent(-1)\n\n        # check_consistency method\n        cls_str += self.indent + \"def _is_consistent(self) -> bool:\\n\"\n        self._change_indent(1)\n        cls_str += (\n            self.indent\n            + '\"\"\"Check that the message follows the {} protocol.\"\"\"\\n'.format(\n                self.protocol_specification.name\n            )\n        )\n        cls_str += self.indent + \"try:\\n\"\n        self._change_indent(1)\n        cls_str += (\n            self.indent\n            + \"enforce(isinstance(self.dialogue_reference, tuple), \\\"Invalid type for 'dialogue_reference'. Expected 'tuple'. Found '{}'.\\\"\"\n            \".format(type(self.dialogue_reference)))\\n\"\n        )\n        cls_str += (\n            self.indent\n            + \"enforce(isinstance(self.dialogue_reference[0], str), \\\"Invalid type for 'dialogue_reference[0]'. Expected 'str'. Found '{}'.\\\"\"\n            \".format(type(self.dialogue_reference[0])))\\n\"\n        )\n        cls_str += (\n            self.indent\n            + \"enforce(isinstance(self.dialogue_reference[1], str), \\\"Invalid type for 'dialogue_reference[1]'. Expected 'str'. Found '{}'.\\\"\"\n            \".format(type(self.dialogue_reference[1])))\\n\"\n        )\n        cls_str += (\n            self.indent\n            + \"enforce(\"\n            + _type_check(\"self.message_id\", \"int\")\n            + \", \\\"Invalid type for 'message_id'. Expected 'int'. Found '{}'.\\\"\"\n            \".format(type(self.message_id)))\\n\"\n        )\n        cls_str += (\n            self.indent\n            + \"enforce(\"\n            + _type_check(\"self.target\", \"int\")\n            + \", \\\"Invalid type for 'target'. Expected 'int'. Found '{}'.\\\"\"\n            \".format(type(self.target)))\\n\\n\"\n        )\n\n        cls_str += self.indent + \"# Light Protocol Rule 2\\n\"\n        cls_str += self.indent + \"# Check correct performative\\n\"\n        cls_str += (\n            self.indent\n            + \"enforce(isinstance(self.performative, {}Message.Performative)\".format(\n                self.protocol_specification_in_camel_case\n            )\n        )\n        cls_str += (\n            \", \\\"Invalid 'performative'. Expected either of '{}'. Found '{}'.\\\".format(\"\n        )\n        cls_str += \"self.valid_performatives, self.performative\"\n        cls_str += \"))\\n\\n\"\n\n        cls_str += self.indent + \"# Check correct contents\\n\"\n        cls_str += (\n            self.indent\n            + \"actual_nb_of_contents = len(self._body) - DEFAULT_BODY_SIZE\\n\"\n        )\n        cls_str += self.indent + \"expected_nb_of_contents = 0\\n\"\n        counter = 1\n        for performative, contents in self.spec.speech_acts.items():\n            if counter == 1:\n                cls_str += self.indent + \"if \"\n            else:\n                cls_str += self.indent + \"elif \"\n            cls_str += \"self.performative == {}Message.Performative.{}:\\n\".format(\n                self.protocol_specification_in_camel_case,\n                performative.upper(),\n            )\n            self._change_indent(1)\n            nb_of_non_optional_contents = 0\n            for content_type in contents.values():\n                if not content_type.startswith(\"Optional\"):\n                    nb_of_non_optional_contents += 1\n\n            cls_str += self.indent + \"expected_nb_of_contents = {}\\n\".format(\n                nb_of_non_optional_contents\n            )\n            for content_name, content_type in contents.items():\n                cls_str += self._check_content_type_str(content_name, content_type)\n            counter += 1\n            self._change_indent(-1)\n\n        cls_str += \"\\n\"\n        cls_str += self.indent + \"# Check correct content count\\n\"\n        cls_str += (\n            self.indent + \"enforce(expected_nb_of_contents == actual_nb_of_contents, \"\n            '\"Incorrect number of contents. Expected {}. Found {}\"'\n            \".format(expected_nb_of_contents, actual_nb_of_contents))\\n\\n\"\n        )\n\n        cls_str += self.indent + \"# Light Protocol Rule 3\\n\"\n        cls_str += self.indent + \"if self.message_id == 1:\\n\"\n        self._change_indent(1)\n        cls_str += (\n            self.indent\n            + \"enforce(self.target == 0, \\\"Invalid 'target'. Expected 0 (because 'message_id' is 1). Found {}.\\\".format(self.target))\\n\"\n        )\n        self._change_indent(-2)\n        cls_str += (\n            self.indent + \"except (AEAEnforceError, ValueError, KeyError) as e:\\n\"\n        )\n        self._change_indent(1)\n        cls_str += self.indent + \"_default_logger.error(str(e))\\n\"\n        cls_str += self.indent + \"return False\\n\\n\"\n        self._change_indent(-1)\n        cls_str += self.indent + \"return True\\n\"\n\n        return cls_str\n\n    def _valid_replies_str(self) -> str:\n        \"\"\"\n        Generate the `valid replies` dictionary.\n\n        :return: the `valid replies` dictionary string\n        \"\"\"\n        valid_replies_str = (\n            self.indent\n            + \"VALID_REPLIES: Dict[Message.Performative, FrozenSet[Message.Performative]] = {\\n\"\n        )\n        self._change_indent(1)\n        for performative in sorted(self.spec.reply.keys()):\n            valid_replies_str += (\n                self.indent\n                + \"{}Message.Performative.{}: frozenset(\".format(\n                    self.protocol_specification_in_camel_case, performative.upper()\n                )\n            )\n            if len(self.spec.reply[performative]) > 0:\n                valid_replies_str += \"\\n\"\n                self._change_indent(1)\n                valid_replies_str += self.indent + \"{\"\n                for reply in self.spec.reply[performative]:\n                    valid_replies_str += \"{}Message.Performative.{}, \".format(\n                        self.protocol_specification_in_camel_case, reply.upper()\n                    )\n                valid_replies_str = valid_replies_str[:-2]\n                valid_replies_str += \"}\\n\"\n                self._change_indent(-1)\n            valid_replies_str += self.indent + \"),\\n\"\n\n        self._change_indent(-1)\n        valid_replies_str += self.indent + \"}\"\n        return valid_replies_str\n\n    def _end_state_enum_str(self) -> str:\n        \"\"\"\n        Generate the end state Enum class.\n\n        :return: the end state Enum string\n        \"\"\"\n        enum_str = self.indent + \"class EndState(Dialogue.EndState):\\n\"\n        self._change_indent(1)\n        enum_str += (\n            self.indent\n            + '\"\"\"This class defines the end states of a {} dialogue.\"\"\"\\n\\n'.format(\n                self.protocol_specification.name\n            )\n        )\n        tag = 0\n        for end_state in self.spec.end_states:\n            enum_str += self.indent + \"{} = {}\\n\".format(end_state.upper(), tag)\n            tag += 1\n        self._change_indent(-1)\n        return enum_str\n\n    def _agent_role_enum_str(self) -> str:\n        \"\"\"\n        Generate the agent role Enum class.\n\n        :return: the agent role Enum string\n        \"\"\"\n        enum_str = self.indent + \"class Role(Dialogue.Role):\\n\"\n        self._change_indent(1)\n        enum_str += (\n            self.indent\n            + '\"\"\"This class defines the agent\\'s role in a {} dialogue.\"\"\"\\n\\n'.format(\n                self.protocol_specification.name\n            )\n        )\n        for role in self.spec.roles:\n            enum_str += self.indent + '{} = \"{}\"\\n'.format(role.upper(), role)\n        self._change_indent(-1)\n        return enum_str\n\n    def _dialogue_class_str(self) -> str:\n        \"\"\"\n        Produce the content of the Message class.\n\n        :return: the message.py file content\n        \"\"\"\n        self._change_indent(0, \"s\")\n\n        # Header\n        cls_str = _copyright_header_str(self.protocol_specification.author) + \"\\n\"\n\n        # Module docstring\n        cls_str += self.indent + '\"\"\"\\n'\n        cls_str += (\n            self.indent\n            + \"This module contains the classes required for {} dialogue management.\\n\\n\".format(\n                self.protocol_specification.name\n            )\n        )\n        cls_str += (\n            self.indent\n            + \"- {}Dialogue: The dialogue class maintains state of a dialogue and manages it.\\n\".format(\n                self.protocol_specification_in_camel_case\n            )\n        )\n        cls_str += (\n            self.indent\n            + \"- {}Dialogues: The dialogues class keeps track of all dialogues.\\n\".format(\n                self.protocol_specification_in_camel_case\n            )\n        )\n        cls_str += self.indent + '\"\"\"\\n\\n'\n\n        # Imports\n        cls_str += self.indent + \"from abc import ABC\\n\"\n        cls_str += (\n            self.indent + \"from typing import Callable, Dict, FrozenSet, Type, cast\\n\\n\"\n        )\n        cls_str += self.indent + \"from aea.common import Address\\n\"\n        cls_str += self.indent + \"from aea.protocols.base import Message\\n\"\n        cls_str += (\n            self.indent\n            + \"from aea.protocols.dialogue.base import Dialogue, DialogueLabel, Dialogues\\n\\n\"\n        )\n        cls_str += self.indent + \"from {}.message import {}Message\\n\".format(\n            self.dotted_path_to_protocol_package,\n            self.protocol_specification_in_camel_case,\n        )\n\n        # Class Header\n        cls_str += \"\\nclass {}Dialogue(Dialogue):\\n\".format(\n            self.protocol_specification_in_camel_case\n        )\n        self._change_indent(1)\n        cls_str += (\n            self.indent\n            + '\"\"\"The {} dialogue class maintains state of a dialogue and manages it.\"\"\"\\n'.format(\n                self.protocol_specification.name\n            )\n        )\n\n        # Class Constants\n        initial_performatives_str = \", \".join(\n            [\n                \"{}Message.Performative.{}\".format(\n                    self.protocol_specification_in_camel_case, initial_performative\n                )\n                for initial_performative in self.spec.initial_performatives\n            ]\n        )\n        terminal_performatives_str = \", \".join(\n            [\n                \"{}Message.Performative.{}\".format(\n                    self.protocol_specification_in_camel_case, terminal_performative\n                )\n                for terminal_performative in self.spec.terminal_performatives\n            ]\n        )\n        cls_str += (\n            self.indent\n            + \"INITIAL_PERFORMATIVES: FrozenSet[Message.Performative] = frozenset({\"\n            + initial_performatives_str\n            + \"})\\n\"\n            + self.indent\n            + \"TERMINAL_PERFORMATIVES: FrozenSet[Message.Performative] = frozenset({\"\n            + terminal_performatives_str\n            + \"})\\n\"\n            + self._valid_replies_str()\n        )\n\n        # Enums\n        cls_str += \"\\n\" + self._agent_role_enum_str()\n        cls_str += \"\\n\" + self._end_state_enum_str()\n        cls_str += \"\\n\"\n\n        # initializer\n        cls_str += self.indent + \"def __init__(\\n\"\n        self._change_indent(1)\n        cls_str += self.indent + \"self,\\n\"\n        cls_str += self.indent + \"dialogue_label: DialogueLabel,\\n\"\n        cls_str += self.indent + \"self_address: Address,\\n\"\n        cls_str += self.indent + \"role: Dialogue.Role,\\n\"\n        cls_str += self.indent + \"message_class: Type[{}Message] = {}Message,\\n\".format(\n            self.protocol_specification_in_camel_case,\n            self.protocol_specification_in_camel_case,\n        )\n        self._change_indent(-1)\n        cls_str += self.indent + \") -> None:\\n\"\n        self._change_indent(1)\n        cls_str += self.indent + '\"\"\"\\n'\n        cls_str += self.indent + \"Initialize a dialogue.\\n\\n\"\n        cls_str += (\n            self.indent + \":param dialogue_label: the identifier of the dialogue\\n\"\n        )\n        cls_str += (\n            self.indent\n            + \":param self_address: the address of the entity for whom this dialogue is maintained\\n\"\n        )\n        cls_str += (\n            self.indent\n            + \":param role: the role of the agent this dialogue is maintained for\\n\"\n        )\n        cls_str += self.indent + \":param message_class: the message class used\\n\"\n        cls_str += self.indent + '\"\"\"\\n'\n        cls_str += self.indent + \"Dialogue.__init__(\\n\"\n        cls_str += self.indent + \"self,\\n\"\n        cls_str += self.indent + \"dialogue_label=dialogue_label,\\n\"\n        cls_str += self.indent + \"message_class=message_class,\\n\"\n        cls_str += self.indent + \"self_address=self_address,\\n\"\n        cls_str += self.indent + \"role=role,\\n\"\n        cls_str += self.indent + \")\\n\"\n        self._change_indent(-2)\n\n        # dialogues class\n        cls_str += self.indent + \"class {}Dialogues(Dialogues, ABC):\\n\".format(\n            self.protocol_specification_in_camel_case\n        )\n        self._change_indent(1)\n        cls_str += (\n            self.indent\n            + '\"\"\"This class keeps track of all {} dialogues.\"\"\"\\n\\n'.format(\n                self.protocol_specification.name\n            )\n        )\n        end_states_str = \", \".join(\n            [\n                \"{}Dialogue.EndState.{}\".format(\n                    self.protocol_specification_in_camel_case, end_state.upper()\n                )\n                for end_state in self.spec.end_states\n            ]\n        )\n        cls_str += self.indent + \"END_STATES = frozenset(\\n\"\n        cls_str += self.indent + \"{\" + end_states_str + \"}\"\n        cls_str += self.indent + \")\\n\\n\"\n\n        cls_str += (\n            self.indent\n            + f\"_keep_terminal_state_dialogues = {repr(self.spec.keep_terminal_state_dialogues)}\\n\\n\"\n        )\n\n        cls_str += self.indent + \"def __init__(\\n\"\n        self._change_indent(1)\n        cls_str += self.indent + \"self,\\n\"\n        cls_str += self.indent + \"self_address: Address,\\n\"\n        cls_str += (\n            self.indent\n            + \"role_from_first_message: Callable[[Message, Address], Dialogue.Role],\\n\"\n        )\n        cls_str += (\n            self.indent\n            + \"dialogue_class: Type[{}Dialogue] = {}Dialogue,\\n\".format(\n                self.protocol_specification_in_camel_case,\n                self.protocol_specification_in_camel_case,\n            )\n        )\n        self._change_indent(-1)\n        cls_str += self.indent + \") -> None:\\n\"\n        self._change_indent(1)\n        cls_str += self.indent + '\"\"\"\\n'\n        cls_str += self.indent + \"Initialize dialogues.\\n\\n\"\n        cls_str += (\n            self.indent\n            + \":param self_address: the address of the entity for whom dialogues are maintained\\n\"\n        )\n        cls_str += self.indent + \":param dialogue_class: the dialogue class used\\n\"\n        cls_str += (\n            self.indent\n            + \":param role_from_first_message: the callable determining role from first message\\n\"\n        )\n        cls_str += self.indent + '\"\"\"\\n'\n        cls_str += self.indent + \"Dialogues.__init__(\\n\"\n        self._change_indent(1)\n        cls_str += self.indent + \"self,\\n\"\n        cls_str += self.indent + \"self_address=self_address,\\n\"\n        cls_str += (\n            self.indent\n            + \"end_states=cast(FrozenSet[Dialogue.EndState], self.END_STATES),\\n\"\n        )\n        cls_str += self.indent + \"message_class={}Message,\\n\".format(\n            self.protocol_specification_in_camel_case\n        )\n        cls_str += self.indent + \"dialogue_class=dialogue_class,\\n\"\n        cls_str += self.indent + \"role_from_first_message=role_from_first_message,\\n\"\n        self._change_indent(-1)\n        cls_str += self.indent + \")\\n\"\n        self._change_indent(-2)\n        cls_str += self.indent + \"\\n\"\n\n        return cls_str\n\n    def _custom_types_module_str(self) -> str:\n        \"\"\"\n        Produce the contents of the custom_types module, containing classes corresponding to every custom type in the protocol specification.\n\n        :return: the custom_types.py file content\n        \"\"\"\n        self._change_indent(0, \"s\")\n\n        # Header\n        cls_str = _copyright_header_str(self.protocol_specification.author) + \"\\n\"\n\n        # Module docstring\n        cls_str += '\"\"\"This module contains class representations corresponding to every custom type in the protocol specification.\"\"\"\\n'\n\n        # class code per custom type\n        for custom_type in self.spec.all_custom_types:\n            cls_str += self.indent + \"\\n\\nclass {}:\\n\".format(custom_type)\n            self._change_indent(1)\n            cls_str += (\n                self.indent\n                + '\"\"\"This class represents an instance of {}.\"\"\"\\n\\n'.format(\n                    custom_type\n                )\n            )\n            cls_str += self.indent + \"def __init__(self):\\n\"\n            self._change_indent(1)\n            cls_str += self.indent + '\"\"\"Initialise an instance of {}.\"\"\"\\n'.format(\n                custom_type\n            )\n            cls_str += self.indent + \"raise NotImplementedError\\n\\n\"\n            self._change_indent(-1)\n            cls_str += self.indent + \"@staticmethod\\n\"\n            cls_str += (\n                self.indent\n                + 'def encode({}_protobuf_object, {}_object: \"{}\") -> None:\\n'.format(\n                    _camel_case_to_snake_case(custom_type),\n                    _camel_case_to_snake_case(custom_type),\n                    custom_type,\n                )\n            )\n            self._change_indent(1)\n            cls_str += self.indent + '\"\"\"\\n'\n            cls_str += (\n                self.indent\n                + \"Encode an instance of this class into the protocol buffer object.\\n\\n\"\n            )\n            cls_str += (\n                self.indent\n                + \"The protocol buffer object in the {}_protobuf_object argument is matched with the instance of this class in the '{}_object' argument.\\n\\n\".format(\n                    _camel_case_to_snake_case(custom_type),\n                    _camel_case_to_snake_case(custom_type),\n                )\n            )\n            cls_str += (\n                self.indent\n                + \":param {}_protobuf_object: the protocol buffer object whose type corresponds with this class.\\n\".format(\n                    _camel_case_to_snake_case(custom_type)\n                )\n            )\n            cls_str += (\n                self.indent\n                + \":param {}_object: an instance of this class to be encoded in the protocol buffer object.\\n\".format(\n                    _camel_case_to_snake_case(custom_type)\n                )\n            )\n            cls_str += self.indent + '\"\"\"\\n'\n            cls_str += self.indent + \"raise NotImplementedError\\n\\n\"\n            self._change_indent(-1)\n\n            cls_str += self.indent + \"@classmethod\\n\"\n            cls_str += (\n                self.indent\n                + 'def decode(cls, {}_protobuf_object) -> \"{}\":\\n'.format(\n                    _camel_case_to_snake_case(custom_type),\n                    custom_type,\n                )\n            )\n            self._change_indent(1)\n            cls_str += self.indent + '\"\"\"\\n'\n            cls_str += (\n                self.indent\n                + \"Decode a protocol buffer object that corresponds with this class into an instance of this class.\\n\\n\"\n            )\n            cls_str += (\n                self.indent\n                + \"A new instance of this class is created that matches the protocol buffer object in the '{}_protobuf_object' argument.\\n\\n\".format(\n                    _camel_case_to_snake_case(custom_type)\n                )\n            )\n            cls_str += (\n                self.indent\n                + \":param {}_protobuf_object: the protocol buffer object whose type corresponds with this class.\\n\".format(\n                    _camel_case_to_snake_case(custom_type)\n                )\n            )\n            cls_str += (\n                self.indent\n                + \":return: A new instance of this class that matches the protocol buffer object in the '{}_protobuf_object' argument.\\n\".format(\n                    _camel_case_to_snake_case(custom_type)\n                )\n            )\n            cls_str += self.indent + '\"\"\"\\n'\n            cls_str += self.indent + \"raise NotImplementedError\\n\\n\"\n            self._change_indent(-1)\n\n            cls_str += self.indent + \"def __eq__(self, other):\\n\"\n            self._change_indent(1)\n            cls_str += self.indent + \"raise NotImplementedError\\n\"\n            self._change_indent(-2)\n        return cls_str\n\n    def _to_python_type(self, content_type: str) -> str:\n        \"\"\"\n        Return python type.\n\n        :param  content_type: str\n        :return: str\n        \"\"\"\n        if not _is_compositional_type(content_type):\n            return content_type\n        m = re.search(r\"^(pt:)?([a-zA-Z0-9_]+)(\\[.*)?\", content_type)\n        if not m:\n            return content_type\n        type_ = m.groups()[1].lower()\n        if type_ == \"frozenset\":\n            return \"(set, frozenset)\"\n        if type_ == \"tuple\":\n            return \"(list, tuple)\"\n\n        return type_\n\n    def _encoding_message_content_from_python_to_protobuf(\n        self,\n        content_name: str,\n        content_type: str,\n        performative_name: Optional[str] = None,\n    ) -> str:\n        \"\"\"\n        Produce the encoding of message contents for the serialisation class.\n\n        :param content_name: the name of the content to be encoded\n        :param content_type: the type of the content to be encoded\n        :param performative_name: optional performative name of the content to be encoded\n\n        :return: the encoding string\n        \"\"\"\n        performative_name = performative_name or content_name\n        encoding_str = \"\"\n        if content_type in PYTHON_TYPE_TO_PROTO_TYPE.keys():\n            encoding_str += self.indent + \"{} = msg.{}\\n\".format(\n                performative_name, content_name\n            )\n            encoding_str += self.indent + \"performative.{} = {}\\n\".format(\n                performative_name, performative_name\n            )\n        elif content_type.startswith(\"FrozenSet\") or content_type.startswith(\"Tuple\"):\n            encoding_str += self.indent + \"{} = msg.{}\\n\".format(\n                content_name, content_name\n            )\n            encoding_str += self.indent + \"performative.{}.extend({})\\n\".format(\n                performative_name, content_name\n            )\n        elif content_type.startswith(\"Dict\"):\n            encoding_str += self.indent + \"{} = msg.{}\\n\".format(\n                content_name, content_name\n            )\n            encoding_str += self.indent + \"performative.{}.update({})\\n\".format(\n                performative_name, content_name\n            )\n\n        elif content_type.startswith(\"Union\"):\n            sub_types = _get_sub_types_of_compositional_types(content_type)\n            encoding_str += self.indent + f'if msg.is_set(\"{content_name}\"):\\n'\n            self._change_indent(1)\n            elif_add = \"\"\n            for sub_type in sub_types:\n                sub_type_name_in_protobuf = _union_sub_type_to_protobuf_variable_name(\n                    content_name, sub_type\n                )\n                extra = \"\"\n                if _is_compositional_type(sub_type):\n                    subt = _get_sub_types_of_compositional_types(sub_type)\n                    if \"dict\" in sub_type.lower():\n                        extra = f\" and all(map(lambda x: isinstance(x[0], {subt[0]}) and isinstance(x[1], {subt[1]}), msg.{content_name}.items()))\"\n                    else:\n                        extra = f\" and all(map(lambda x: isinstance(x, {subt[0]}), msg.{content_name}))\"\n                encoding_str += (\n                    self.indent\n                    + f\"{elif_add}if isinstance(msg.{content_name}, {self._to_python_type(sub_type)}){extra}:\\n\"\n                )\n                self._change_indent(1)\n                encoding_str += self.indent + \"performative.{}_is_set = True\\n\".format(\n                    sub_type_name_in_protobuf\n                )\n                encoding_str += self._encoding_message_content_from_python_to_protobuf(\n                    content_name, sub_type, performative_name=sub_type_name_in_protobuf\n                )\n                self._change_indent(-1)\n                elif_add = \"el\"\n\n            encoding_str += self.indent + f\"elif msg.{content_name} is None:\\n\"\n            self._change_indent(1)\n            encoding_str += self.indent + \"pass\\n\"\n            self._change_indent(-1)\n\n            encoding_str += self.indent + \"else:\\n\"\n            self._change_indent(1)\n            encoding_str += (\n                self.indent\n                + f\"raise ValueError(f'Bad value set to `{content_name}` {{msg.{content_name} }}')\\n\"\n            )\n            self._change_indent(-1)\n\n            self._change_indent(-1)\n        elif content_type.startswith(\"Optional\"):\n            sub_type = _get_sub_types_of_compositional_types(content_type)[0]\n            if not sub_type.startswith(\"Union\"):\n                encoding_str += self.indent + 'if msg.is_set(\"{}\"):\\n'.format(\n                    content_name\n                )\n                self._change_indent(1)\n                encoding_str += self.indent + \"performative.{}_is_set = True\\n\".format(\n                    content_name\n                )\n            encoding_str += self._encoding_message_content_from_python_to_protobuf(\n                content_name, sub_type\n            )\n            if not sub_type.startswith(\"Union\"):\n                self._change_indent(-1)\n        else:\n            encoding_str += self.indent + \"{} = msg.{}\\n\".format(\n                performative_name, content_name\n            )\n            encoding_str += self.indent + \"{}.encode(performative.{}, {})\\n\".format(\n                content_type, performative_name, performative_name\n            )\n        return encoding_str\n\n    def _decoding_message_content_from_protobuf_to_python(\n        self,\n        performative: str,\n        content_name: str,\n        content_type: str,\n        variable_name_in_protobuf: Optional[str] = \"\",\n    ) -> str:\n        \"\"\"\n        Produce the decoding of message contents for the serialisation class.\n\n        :param performative: the performative to which the content belongs\n        :param content_name: the name of the content to be decoded\n        :param content_type: the type of the content to be decoded\n        :param variable_name_in_protobuf: the name of the variable in the protobuf schema\n\n        :return: the decoding string\n        \"\"\"\n        decoding_str = \"\"\n        variable_name = (\n            content_name\n            if variable_name_in_protobuf == \"\"\n            else variable_name_in_protobuf\n        )\n        if content_type in PYTHON_TYPE_TO_PROTO_TYPE.keys():\n            decoding_str += self.indent + \"{} = {}_pb.{}.{}\\n\".format(\n                content_name,\n                self.protocol_specification.name,\n                performative,\n                variable_name,\n            )\n            decoding_str += self.indent + 'performative_content[\"{}\"] = {}\\n'.format(\n                content_name, content_name\n            )\n        elif content_type.startswith(\"FrozenSet\"):\n            decoding_str += self.indent + \"{} = {}_pb.{}.{}\\n\".format(\n                content_name,\n                self.protocol_specification.name,\n                performative,\n                variable_name,\n            )\n            decoding_str += self.indent + \"{}_frozenset = frozenset({})\\n\".format(\n                content_name, content_name\n            )\n            decoding_str += (\n                self.indent\n                + 'performative_content[\"{}\"] = {}_frozenset\\n'.format(\n                    content_name, content_name\n                )\n            )\n        elif content_type.startswith(\"Tuple\"):\n            decoding_str += self.indent + \"{} = {}_pb.{}.{}\\n\".format(\n                content_name,\n                self.protocol_specification.name,\n                performative,\n                variable_name,\n            )\n            decoding_str += self.indent + \"{}_tuple = tuple({})\\n\".format(\n                content_name, content_name\n            )\n            decoding_str += (\n                self.indent\n                + 'performative_content[\"{}\"] = {}_tuple\\n'.format(\n                    content_name, content_name\n                )\n            )\n        elif content_type.startswith(\"Dict\"):\n            decoding_str += self.indent + \"{} = {}_pb.{}.{}\\n\".format(\n                content_name,\n                self.protocol_specification.name,\n                performative,\n                variable_name,\n            )\n            decoding_str += self.indent + \"{}_dict = dict({})\\n\".format(\n                content_name, content_name\n            )\n            decoding_str += (\n                self.indent\n                + 'performative_content[\"{}\"] = {}_dict\\n'.format(\n                    content_name, content_name\n                )\n            )\n        elif content_type.startswith(\"Union\"):\n            sub_types = _get_sub_types_of_compositional_types(content_type)\n            for sub_type in sub_types:\n                sub_type_name_in_protobuf = _union_sub_type_to_protobuf_variable_name(\n                    content_name, sub_type\n                )\n                decoding_str += self.indent + \"if {}_pb.{}.{}_is_set:\\n\".format(\n                    self.protocol_specification.name,\n                    performative,\n                    sub_type_name_in_protobuf,\n                )\n                self._change_indent(1)\n                decoding_str += self._decoding_message_content_from_protobuf_to_python(\n                    performative=performative,\n                    content_name=content_name,\n                    content_type=sub_type,\n                    variable_name_in_protobuf=sub_type_name_in_protobuf,\n                )\n                self._change_indent(-1)\n        elif content_type.startswith(\"Optional\"):\n            sub_type = _get_sub_types_of_compositional_types(content_type)[0]\n            if not sub_type.startswith(\"Union\"):\n                decoding_str += self.indent + \"if {}_pb.{}.{}_is_set:\\n\".format(\n                    self.protocol_specification.name, performative, content_name\n                )\n                self._change_indent(1)\n            decoding_str += self._decoding_message_content_from_protobuf_to_python(\n                performative, content_name, sub_type\n            )\n            if not sub_type.startswith(\"Union\"):\n                self._change_indent(-1)\n        else:\n            decoding_str += self.indent + \"pb2_{} = {}_pb.{}.{}\\n\".format(\n                variable_name,\n                self.protocol_specification.name,\n                performative,\n                variable_name,\n            )\n            decoding_str += self.indent + \"{} = {}.decode(pb2_{})\\n\".format(\n                content_name,\n                content_type,\n                variable_name,\n            )\n            decoding_str += self.indent + 'performative_content[\"{}\"] = {}\\n'.format(\n                content_name, content_name\n            )\n        return decoding_str\n\n    def _serialization_class_str(self) -> str:\n        \"\"\"\n        Produce the content of the Serialization class.\n\n        :return: the serialization.py file content\n        \"\"\"\n        self._change_indent(0, \"s\")\n\n        # Header\n        cls_str = _copyright_header_str(self.protocol_specification.author) + \"\\n\"\n\n        # Module docstring\n        cls_str += (\n            self.indent\n            + '\"\"\"Serialization module for {} protocol.\"\"\"\\n\\n'.format(\n                self.protocol_specification.name\n            )\n        )\n\n        cls_str += f\"# pylint: disable={','.join(PYLINT_DISABLE_SERIALIZATION_PY)}\\n\"\n\n        # Imports\n        cls_str += self.indent + \"from typing import Any, Dict, cast\\n\\n\"\n        cls_str += (\n            self.indent\n            + \"from aea.mail.base_pb2 import DialogueMessage, Message as ProtobufMessage\\n\"\n        )\n        cls_str += MESSAGE_IMPORT + \"\\n\"\n        cls_str += SERIALIZER_IMPORT + \"\\n\\n\"\n        cls_str += self.indent + \"from {} import (\\n    {}_pb2,\\n)\\n\".format(\n            self.dotted_path_to_protocol_package,\n            self.protocol_specification.name,\n        )\n        for custom_type in self.spec.all_custom_types:\n            cls_str += (\n                self.indent\n                + \"from {}.custom_types import (\\n    {},\\n)\\n\".format(\n                    self.dotted_path_to_protocol_package,\n                    custom_type,\n                )\n            )\n        cls_str += self.indent + \"from {}.message import (\\n    {}Message,\\n)\\n\".format(\n            self.dotted_path_to_protocol_package,\n            self.protocol_specification_in_camel_case,\n        )\n\n        # Class Header\n        cls_str += self.indent + \"\\n\\nclass {}Serializer(Serializer):\\n\".format(\n            self.protocol_specification_in_camel_case,\n        )\n        self._change_indent(1)\n        cls_str += (\n            self.indent\n            + '\"\"\"Serialization for the \\'{}\\' protocol.\"\"\"\\n\\n'.format(\n                self.protocol_specification.name,\n            )\n        )\n\n        # encoder\n        cls_str += self.indent + \"@staticmethod\\n\"\n        cls_str += self.indent + \"def encode(msg: Message) -> bytes:\\n\"\n        self._change_indent(1)\n        cls_str += self.indent + '\"\"\"\\n'\n        cls_str += self.indent + \"Encode a '{}' message into bytes.\\n\\n\".format(\n            self.protocol_specification_in_camel_case,\n        )\n        cls_str += self.indent + \":param msg: the message object.\\n\"\n        cls_str += self.indent + \":return: the bytes.\\n\"\n        cls_str += self.indent + '\"\"\"\\n'\n        cls_str += self.indent + \"msg = cast({}Message, msg)\\n\".format(\n            self.protocol_specification_in_camel_case\n        )\n        cls_str += self.indent + \"message_pb = ProtobufMessage()\\n\"\n        cls_str += self.indent + \"dialogue_message_pb = DialogueMessage()\\n\"\n        cls_str += self.indent + \"{}_msg = {}_pb2.{}Message()\\n\\n\".format(\n            self.protocol_specification.name,\n            self.protocol_specification.name,\n            self.protocol_specification_in_camel_case,\n        )\n        cls_str += self.indent + \"dialogue_message_pb.message_id = msg.message_id\\n\"\n        cls_str += self.indent + \"dialogue_reference = msg.dialogue_reference\\n\"\n        cls_str += (\n            self.indent\n            + \"dialogue_message_pb.dialogue_starter_reference = dialogue_reference[0]\\n\"\n        )\n        cls_str += (\n            self.indent\n            + \"dialogue_message_pb.dialogue_responder_reference = dialogue_reference[1]\\n\"\n        )\n        cls_str += self.indent + \"dialogue_message_pb.target = msg.target\\n\\n\"\n        cls_str += self.indent + \"performative_id = msg.performative\\n\"\n        counter = 1\n        for performative, contents in self.spec.speech_acts.items():\n            if counter == 1:\n                cls_str += self.indent + \"if \"\n            else:\n                cls_str += self.indent + \"elif \"\n            cls_str += \"performative_id == {}Message.Performative.{}:\\n\".format(\n                self.protocol_specification_in_camel_case, performative.upper()\n            )\n            self._change_indent(1)\n            cls_str += (\n                self.indent\n                + \"performative = {}_pb2.{}Message.{}_Performative()  # type: ignore\\n\".format(\n                    self.protocol_specification.name,\n                    self.protocol_specification_in_camel_case,\n                    performative.title(),\n                )\n            )\n            for content_name, content_type in contents.items():\n                cls_str += self._encoding_message_content_from_python_to_protobuf(\n                    content_name, content_type\n                )\n            cls_str += self.indent + \"{}_msg.{}.CopyFrom(performative)\\n\".format(\n                self.protocol_specification.name, performative\n            )\n\n            counter += 1\n            self._change_indent(-1)\n        cls_str += self.indent + \"else:\\n\"\n        self._change_indent(1)\n        cls_str += (\n            self.indent\n            + 'raise ValueError(\"Performative not valid: {}\".format(performative_id))\\n\\n'\n        )\n        self._change_indent(-1)\n\n        cls_str += (\n            self.indent\n            + \"dialogue_message_pb.content = {}_msg.SerializeToString()\\n\\n\".format(\n                self.protocol_specification.name,\n            )\n        )\n        cls_str += (\n            self.indent + \"message_pb.dialogue_message.CopyFrom(dialogue_message_pb)\\n\"\n        )\n        cls_str += self.indent + \"message_bytes = message_pb.SerializeToString()\\n\"\n        cls_str += self.indent + \"return message_bytes\\n\"\n        self._change_indent(-1)\n\n        # decoder\n        cls_str += self.indent + \"@staticmethod\\n\"\n        cls_str += self.indent + \"def decode(obj: bytes) -> Message:\\n\"\n        self._change_indent(1)\n        cls_str += self.indent + '\"\"\"\\n'\n        cls_str += self.indent + \"Decode bytes into a '{}' message.\\n\\n\".format(\n            self.protocol_specification_in_camel_case,\n        )\n        cls_str += self.indent + \":param obj: the bytes object.\\n\"\n        cls_str += self.indent + \":return: the '{}' message.\\n\".format(\n            self.protocol_specification_in_camel_case\n        )\n        cls_str += self.indent + '\"\"\"\\n'\n        cls_str += self.indent + \"message_pb = ProtobufMessage()\\n\"\n        cls_str += self.indent + \"{}_pb = {}_pb2.{}Message()\\n\".format(\n            self.protocol_specification.name,\n            self.protocol_specification.name,\n            self.protocol_specification_in_camel_case,\n        )\n        cls_str += self.indent + \"message_pb.ParseFromString(obj)\\n\"\n        cls_str += self.indent + \"message_id = message_pb.dialogue_message.message_id\\n\"\n        cls_str += (\n            self.indent\n            + \"dialogue_reference = (message_pb.dialogue_message.dialogue_starter_reference, message_pb.dialogue_message.dialogue_responder_reference)\\n\"\n        )\n        cls_str += self.indent + \"target = message_pb.dialogue_message.target\\n\\n\"\n        cls_str += (\n            self.indent\n            + \"{}_pb.ParseFromString(message_pb.dialogue_message.content)\\n\".format(\n                self.protocol_specification.name\n            )\n        )\n        cls_str += (\n            self.indent\n            + 'performative = {}_pb.WhichOneof(\"performative\")\\n'.format(\n                self.protocol_specification.name\n            )\n        )\n        cls_str += (\n            self.indent\n            + \"performative_id = {}Message.Performative(str(performative))\\n\".format(\n                self.protocol_specification_in_camel_case\n            )\n        )\n        cls_str += self.indent + \"performative_content = {}  # type: Dict[str, Any]\\n\"\n        counter = 1\n        for performative, contents in self.spec.speech_acts.items():\n            if counter == 1:\n                cls_str += self.indent + \"if \"\n            else:\n                cls_str += self.indent + \"elif \"\n            cls_str += \"performative_id == {}Message.Performative.{}:\\n\".format(\n                self.protocol_specification_in_camel_case, performative.upper()\n            )\n            self._change_indent(1)\n            if len(contents.keys()) == 0:\n                cls_str += self.indent + \"pass\\n\"\n            else:\n                for content_name, content_type in contents.items():\n                    cls_str += self._decoding_message_content_from_protobuf_to_python(\n                        performative, content_name, content_type\n                    )\n            counter += 1\n            self._change_indent(-1)\n        cls_str += self.indent + \"else:\\n\"\n        self._change_indent(1)\n        cls_str += (\n            self.indent\n            + 'raise ValueError(\"Performative not valid: {}.\".format(performative_id))\\n\\n'\n        )\n        self._change_indent(-1)\n\n        cls_str += self.indent + \"return {}Message(\\n\".format(\n            self.protocol_specification_in_camel_case,\n        )\n        self._change_indent(1)\n        cls_str += self.indent + \"message_id=message_id,\\n\"\n        cls_str += self.indent + \"dialogue_reference=dialogue_reference,\\n\"\n        cls_str += self.indent + \"target=target,\\n\"\n        cls_str += self.indent + \"performative=performative,\\n\"\n        cls_str += self.indent + \"**performative_content\\n\"\n        self._change_indent(-1)\n        cls_str += self.indent + \")\\n\"\n        self._change_indent(-2)\n\n        return cls_str\n\n    def _content_to_proto_field_str(\n        self,\n        content_name: str,\n        content_type: str,\n        tag_no: int,\n    ) -> Tuple[str, int]:\n        \"\"\"\n        Convert a message content to its representation in a protocol buffer schema.\n\n        :param content_name: the name of the content\n        :param content_type: the type of the content\n        :param tag_no: the tag number\n\n        :return: the content in protocol buffer schema and the next tag number to be used\n        \"\"\"\n        entry = \"\"\n\n        if content_type.startswith(\"FrozenSet\") or content_type.startswith(\n            \"Tuple\"\n        ):  # it is a <PCT>\n            element_type = _get_sub_types_of_compositional_types(content_type)[0]\n            proto_type = _python_pt_or_ct_type_to_proto_type(element_type)\n            entry = self.indent + \"repeated {} {} = {};\\n\".format(\n                proto_type, content_name, tag_no\n            )\n            tag_no += 1\n        elif content_type.startswith(\"Dict\"):  # it is a <PMT>\n            key_type = _get_sub_types_of_compositional_types(content_type)[0]\n            value_type = _get_sub_types_of_compositional_types(content_type)[1]\n            proto_key_type = _python_pt_or_ct_type_to_proto_type(key_type)\n            proto_value_type = _python_pt_or_ct_type_to_proto_type(value_type)\n            entry = self.indent + \"map<{}, {}> {} = {};\\n\".format(\n                proto_key_type, proto_value_type, content_name, tag_no\n            )\n            tag_no += 1\n        elif content_type.startswith(\"Union\"):  # it is an <MT>\n            sub_types = _get_sub_types_of_compositional_types(content_type)\n            for sub_type in sub_types:\n                sub_type_name = _union_sub_type_to_protobuf_variable_name(\n                    content_name, sub_type\n                )\n                content_to_proto_field_str, tag_no = self._content_to_proto_field_str(\n                    sub_type_name, f\"Optional[{sub_type}]\", tag_no\n                )\n                entry += content_to_proto_field_str\n        elif content_type.startswith(\"Optional\"):  # it is an <O>\n            sub_type = _get_sub_types_of_compositional_types(content_type)[0]\n            content_to_proto_field_str, tag_no = self._content_to_proto_field_str(\n                content_name, sub_type, tag_no\n            )\n            entry = content_to_proto_field_str\n            entry += self.indent + \"bool {}_is_set = {};\\n\".format(content_name, tag_no)\n            tag_no += 1\n        else:  # it is a <CT> or <PT>\n            proto_type = _python_pt_or_ct_type_to_proto_type(content_type)\n            entry = self.indent + \"{} {} = {};\\n\".format(\n                proto_type, content_name, tag_no\n            )\n            tag_no += 1\n        return entry, tag_no\n\n    def _protocol_buffer_schema_str(self) -> str:\n        \"\"\"\n        Produce the content of the Protocol Buffers schema.\n\n        :return: the protocol buffers schema content\n        \"\"\"\n        self._change_indent(0, \"s\")\n\n        # heading\n        proto_buff_schema_str = self.indent + 'syntax = \"proto3\";\\n\\n'\n        proto_buff_schema_str += self.indent + \"package {};\\n\\n\".format(\n            public_id_to_package_name(\n                self.protocol_specification.protocol_specification_id\n            )\n        )\n        proto_buff_schema_str += self.indent + \"message {}Message{{\\n\\n\".format(\n            self.protocol_specification_in_camel_case\n        )\n        self._change_indent(1)\n\n        # custom types\n        if (\n            (len(self.spec.all_custom_types) != 0)\n            and (self.protocol_specification.protobuf_snippets is not None)\n            and (self.protocol_specification.protobuf_snippets != \"\")\n        ):\n            proto_buff_schema_str += self.indent + \"// Custom Types\\n\"\n            for custom_type in self.spec.all_custom_types:\n                proto_buff_schema_str += self.indent + \"message {}{{\\n\".format(\n                    custom_type\n                )\n                self._change_indent(1)\n\n                # formatting and adding the custom type protobuf entry\n                specification_custom_type = \"ct:\" + custom_type\n                proto_part = self.protocol_specification.protobuf_snippets[\n                    specification_custom_type\n                ]\n                number_of_new_lines = proto_part.count(\"\\n\")\n                if number_of_new_lines != 0:\n                    formatted_proto_part = proto_part.replace(\n                        \"\\n\", \"\\n\" + self.indent, number_of_new_lines - 1\n                    )\n                else:\n                    formatted_proto_part = proto_part\n                proto_buff_schema_str += self.indent + formatted_proto_part\n                self._change_indent(-1)\n\n                proto_buff_schema_str += self.indent + \"}\\n\\n\"\n            proto_buff_schema_str += \"\\n\"\n\n        # performatives\n        proto_buff_schema_str += self.indent + \"// Performatives and contents\\n\"\n        for performative, contents in self.spec.speech_acts.items():\n            proto_buff_schema_str += self.indent + \"message {}_Performative{{\".format(\n                performative.title()\n            )\n            self._change_indent(1)\n            tag_no = 1\n            if len(contents) == 0:\n                proto_buff_schema_str += \"}\\n\\n\"\n                self._change_indent(-1)\n            else:\n                proto_buff_schema_str += \"\\n\"\n                for content_name, content_type in contents.items():\n                    (\n                        content_to_proto_field_str,\n                        tag_no,\n                    ) = self._content_to_proto_field_str(\n                        content_name, content_type, tag_no\n                    )\n                    proto_buff_schema_str += content_to_proto_field_str\n                self._change_indent(-1)\n                proto_buff_schema_str += self.indent + \"}\\n\\n\"\n        proto_buff_schema_str += \"\\n\"\n\n        proto_buff_schema_str += self.indent + \"oneof performative{\\n\"\n        self._change_indent(1)\n        tag_no = 5\n        for performative in self.spec.all_performatives:\n            proto_buff_schema_str += self.indent + \"{}_Performative {} = {};\\n\".format(\n                performative.title(), performative, tag_no\n            )\n            tag_no += 1\n        self._change_indent(-1)\n        proto_buff_schema_str += self.indent + \"}\\n\"\n        self._change_indent(-1)\n\n        proto_buff_schema_str += self.indent + \"}\\n\"\n        return proto_buff_schema_str\n\n    def _protocol_yaml_str(self) -> str:\n        \"\"\"\n        Produce the content of the protocol.yaml file.\n\n        :return: the protocol.yaml content\n        \"\"\"\n        protocol_yaml_str = \"name: {}\\n\".format(self.protocol_specification.name)\n        protocol_yaml_str += \"author: {}\\n\".format(self.protocol_specification.author)\n        protocol_yaml_str += \"version: {}\\n\".format(self.protocol_specification.version)\n        protocol_yaml_str += \"protocol_specification_id: {}\\n\".format(\n            str(self.protocol_specification.protocol_specification_id)\n        )\n        protocol_yaml_str += \"type: {}\\n\".format(\n            self.protocol_specification.component_type\n        )\n        protocol_yaml_str += \"description: {}\\n\".format(\n            self.protocol_specification.description\n        )\n        protocol_yaml_str += \"license: {}\\n\".format(self.protocol_specification.license)\n        protocol_yaml_str += \"aea_version: '{}'\\n\".format(\n            self.protocol_specification.aea_version\n        )\n        protocol_yaml_str += \"fingerprint: {}\\n\"\n        protocol_yaml_str += \"fingerprint_ignore_patterns: []\\n\"\n        protocol_yaml_str += \"dependencies:\\n\"\n        protocol_yaml_str += \"    protobuf: {}\\n\"\n\n        return protocol_yaml_str\n\n    def _init_str(self) -> str:\n        \"\"\"\n        Produce the content of the __init__.py file.\n\n        :return: the __init__.py content\n        \"\"\"\n        init_str = _copyright_header_str(self.protocol_specification.author)\n        init_str += \"\\n\"\n        init_str += '\"\"\"\\nThis module contains the support resources for the {} protocol.\\n\\nIt was created with protocol buffer compiler version `{}` and aea version `{}`.\\n\"\"\"\\n\\n'.format(\n            self.protocol_specification.name, self.protoc_version, __aea_version__\n        )\n        init_str += \"from {}.message import {}Message\\n\".format(\n            self.dotted_path_to_protocol_package,\n            self.protocol_specification_in_camel_case,\n        )\n        init_str += \"from {}.serialization import {}Serializer\\n\".format(\n            self.dotted_path_to_protocol_package,\n            self.protocol_specification_in_camel_case,\n        )\n        init_str += \"{}Message.serializer = {}Serializer\\n\".format(\n            self.protocol_specification_in_camel_case,\n            self.protocol_specification_in_camel_case,\n        )\n\n        return init_str\n\n    def generate_protobuf_only_mode(\n        self,\n        language: str = PROTOCOL_LANGUAGE_PYTHON,\n        run_protolint: bool = True,\n    ) -> Optional[str]:\n        \"\"\"\n        Run the generator in \"protobuf only\" mode:\n\n        a) validate the protocol specification.\n        b) create the protocol buffer schema file.\n        c) create the protocol buffer implementation file via 'protoc'.\n\n        :param language: the target language in which to generate the package.\n        :param run_protolint: whether to run protolint or not.\n\n        :return: None\n        \"\"\"\n        if language not in SUPPORTED_PROTOCOL_LANGUAGES:\n            raise ValueError(\n                f\"Unsupported language. Expected one of {SUPPORTED_PROTOCOL_LANGUAGES}. Found {language}.\"\n            )\n\n        protobuf_output = None  # type: Optional[str]\n\n        # Create the output folder\n        output_folder = Path(self.path_to_generated_protocol_package)\n        if not output_folder.exists():\n            os.mkdir(output_folder)\n\n        # Generate protocol buffer schema file\n        _create_protocol_file(\n            self.path_to_generated_protocol_package,\n            \"{}.proto\".format(self.protocol_specification.name),\n            self._protocol_buffer_schema_str(),\n        )\n\n        # Try to compile protobuf schema file\n        is_compiled, msg = compile_protobuf_using_protoc(\n            self.path_to_generated_protocol_package,\n            self.protocol_specification.name,\n            language,\n        )\n        if not is_compiled:\n            # Remove the generated folder and files\n            shutil.rmtree(output_folder)\n            raise SyntaxError(\n                \"Error when trying to compile the protocol buffer schema file:\\n\" + msg\n            )\n\n        # Run protolint\n        if run_protolint:\n            is_correctly_formatted, protolint_output = apply_protolint(\n                self.path_to_generated_protocol_package,\n                self.protocol_specification.name,\n            )\n            if not is_correctly_formatted and protolint_output != \"\":\n                protobuf_output = \"Protolint warnings:\\n\" + protolint_output\n\n        # Run black and isort formatting for python\n        if language == PROTOCOL_LANGUAGE_PYTHON:\n            try_run_black_formatting(self.path_to_generated_protocol_package)\n            try_run_isort_formatting(self.path_to_generated_protocol_package)\n\n        return protobuf_output\n\n    def generate_full_mode(self, language: str) -> Optional[str]:\n        \"\"\"\n        Run the generator in \"full\" mode:\n\n        Runs the generator in protobuf only mode:\n            a) validate the protocol specification.\n            b) create the protocol buffer schema file.\n            c) create the protocol buffer implementation file via 'protoc'.\n        Additionally:\n        d) generates python modules.\n        e) applies black formatting\n        f) applies isort formatting\n\n        :param language: the language for which to create protobuf files\n        :return: optional warning message\n        \"\"\"\n        if language != PROTOCOL_LANGUAGE_PYTHON:\n            raise ValueError(\n                f\"Unsupported language. Expected 'python' because currently the framework supports full generation of protocols only in Python. Found {language}.\"\n            )\n\n        # Run protobuf only mode\n        full_mode_output = self.generate_protobuf_only_mode(\n            language=PROTOCOL_LANGUAGE_PYTHON\n        )\n\n        # Generate Python protocol package\n        _create_protocol_file(\n            self.path_to_generated_protocol_package, INIT_FILE_NAME, self._init_str()\n        )\n        _create_protocol_file(\n            self.path_to_generated_protocol_package,\n            PROTOCOL_YAML_FILE_NAME,\n            self._protocol_yaml_str(),\n        )\n        _create_protocol_file(\n            self.path_to_generated_protocol_package,\n            MESSAGE_DOT_PY_FILE_NAME,\n            self._message_class_str(),\n        )\n        if (\n            self.protocol_specification.dialogue_config is not None\n            and self.protocol_specification.dialogue_config != {}\n        ):\n            _create_protocol_file(\n                self.path_to_generated_protocol_package,\n                DIALOGUE_DOT_PY_FILE_NAME,\n                self._dialogue_class_str(),\n            )\n        if len(self.spec.all_custom_types) > 0:\n            _create_protocol_file(\n                self.path_to_generated_protocol_package,\n                CUSTOM_TYPES_DOT_PY_FILE_NAME,\n                self._custom_types_module_str(),\n            )\n        _create_protocol_file(\n            self.path_to_generated_protocol_package,\n            SERIALIZATION_DOT_PY_FILE_NAME,\n            self._serialization_class_str(),\n        )\n\n        # Run black formatting\n        try_run_black_formatting(self.path_to_generated_protocol_package)\n\n        # Run isort formatting\n        try_run_isort_formatting(self.path_to_generated_protocol_package)\n\n        # Warn if specification has custom types\n        if len(self.spec.all_custom_types) > 0:\n            incomplete_generation_warning_msg = \"The generated protocol is incomplete, because the protocol specification contains the following custom types: {}. Update the generated '{}' file with the appropriate implementations of these custom types.\".format(\n                self.spec.all_custom_types, CUSTOM_TYPES_DOT_PY_FILE_NAME\n            )\n            if full_mode_output is not None:\n                full_mode_output += incomplete_generation_warning_msg\n            else:\n                full_mode_output = incomplete_generation_warning_msg\n        return full_mode_output\n\n    def generate(\n        self, protobuf_only: bool = False, language: str = PROTOCOL_LANGUAGE_PYTHON\n    ) -> Optional[str]:\n        \"\"\"\n        Run the generator either in \"full\" or \"protobuf only\" mode.\n\n        :param protobuf_only: mode of running the generator.\n        :param language: the target language in which to generate the protocol package.\n\n        :return: optional warning message.\n        \"\"\"\n        if protobuf_only:\n            output = self.generate_protobuf_only_mode(language)  # type: Optional[str]\n\n            # Warn about the protobuf only mode\n            protobuf_mode_warning_msg = (\n                \"The generated protocol is incomplete. It only includes the protocol buffer definitions. \"\n                + \"You must implement and add other definitions (e.g. messages, serialisation, dialogue, etc) to this package.\"\n            )\n            if output is not None:\n                output += protobuf_mode_warning_msg\n            else:\n                output = protobuf_mode_warning_msg\n        else:\n            output = self.generate_full_mode(language)\n        return output\n\n\ndef public_id_to_package_name(public_id: PublicId) -> str:\n    \"\"\"Make package name string from public_id provided.\"\"\"\n    return f'aea.{public_id.author}.{public_id.name}.v{public_id.version.replace(\".\", \"_\")}'\n"
  },
  {
    "path": "aea/protocols/generator/common.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains utility code for generator modules.\"\"\"\nimport inspect\nimport os\nimport re\nimport shutil\nimport subprocess  # nosec\nimport sys\nimport tempfile\nfrom pathlib import Path\nfrom typing import Tuple\n\nfrom aea.configurations.base import ProtocolSpecification\nfrom aea.configurations.constants import (\n    DEFAULT_PROTOCOL_CONFIG_FILE,\n    PACKAGES,\n    PROTOCOL_LANGUAGE_JS,\n    PROTOCOL_LANGUAGE_PYTHON,\n)\nfrom aea.configurations.loader import ConfigLoader\nfrom aea.helpers.io import open_file\n\n\nSPECIFICATION_PRIMITIVE_TYPES = [\"pt:bytes\", \"pt:int\", \"pt:float\", \"pt:bool\", \"pt:str\"]\nSPECIFICATION_COMPOSITIONAL_TYPES = [\n    \"pt:set\",\n    \"pt:list\",\n    \"pt:dict\",\n    \"pt:union\",\n    \"pt:optional\",\n]\nPYTHON_COMPOSITIONAL_TYPES = [\n    \"FrozenSet\",\n    \"Tuple\",\n    \"Dict\",\n    \"Union\",\n    \"Optional\",\n]\n\nMESSAGE_IMPORT = \"from aea.protocols.base import Message\"\nSERIALIZER_IMPORT = \"from aea.protocols.base import Serializer\"\n\nPATH_TO_PACKAGES = PACKAGES\nINIT_FILE_NAME = \"__init__.py\"\nPROTOCOL_YAML_FILE_NAME = DEFAULT_PROTOCOL_CONFIG_FILE\nMESSAGE_DOT_PY_FILE_NAME = \"message.py\"\nDIALOGUE_DOT_PY_FILE_NAME = \"dialogues.py\"\nCUSTOM_TYPES_DOT_PY_FILE_NAME = \"custom_types.py\"\nSERIALIZATION_DOT_PY_FILE_NAME = \"serialization.py\"\n\nPYTHON_TYPE_TO_PROTO_TYPE = {\n    \"bytes\": \"bytes\",\n    \"int\": \"int64\",\n    \"float\": \"float\",\n    \"bool\": \"bool\",\n    \"str\": \"string\",\n}\n\nCURRENT_DIR = os.path.dirname(inspect.getfile(inspect.currentframe()))  # type: ignore\nISORT_CONFIGURATION_FILE = os.path.join(CURRENT_DIR, \"isort.cfg\")\nISORT_CLI_ARGS = [\n    \"--settings-path\",\n    ISORT_CONFIGURATION_FILE,\n    \"--quiet\",\n]\n\nPROTOLINT_CONFIGURATION_FILE_NAME = \"protolint.yaml\"\nPROTOLINT_CONFIGURATION = \"\"\"lint:\n  rules:\n    remove:\n      - MESSAGE_NAMES_UPPER_CAMEL_CASE\n      - ENUM_FIELD_NAMES_ZERO_VALUE_END_WITH\n      - PACKAGE_NAME_LOWER_CASE\n      - REPEATED_FIELD_NAMES_PLURALIZED\n      - FIELD_NAMES_LOWER_SNAKE_CASE\n      - ENUM_FIELD_NAMES_PREFIX\"\"\"\n\nPROTOLINT_INDENTATION_ERROR_STR = \"incorrect indentation style\"\nPROTOLINT_ERROR_WHITELIST = [PROTOLINT_INDENTATION_ERROR_STR]\n\n\ndef _to_camel_case(text: str) -> str:\n    \"\"\"\n    Convert a text in snake_case format into the CamelCase format.\n\n    :param text: the text to be converted.\n    :return: The text in CamelCase format.\n    \"\"\"\n    return \"\".join(word.title() for word in text.split(\"_\"))\n\n\ndef _camel_case_to_snake_case(text: str) -> str:\n    \"\"\"\n    Convert a text in CamelCase format into the snake_case format.\n\n    :param text: the text to be converted.\n    :return: The text in CamelCase format.\n    \"\"\"\n    return re.sub(r\"(?<!^)(?=[A-Z])\", \"_\", text).lower()\n\n\ndef _match_brackets(text: str, index_of_open_bracket: int) -> int:\n    \"\"\"\n    Give the index of the matching close bracket for the opening bracket at 'index_of_open_bracket' in the input 'text'.\n\n    :param text: the text containing the brackets.\n    :param index_of_open_bracket: the index of the opening bracket.\n\n    :return: the index of the matching closing bracket (if any).\n    :raises SyntaxError if there are no matching closing bracket.\n    \"\"\"\n    if text[index_of_open_bracket] != \"[\":\n        raise SyntaxError(\n            \"Index {} in 'text' is not an open bracket '['. It is {}\".format(\n                index_of_open_bracket,\n                text[index_of_open_bracket],\n            )\n        )\n\n    open_bracket_stack = []\n    for index in range(index_of_open_bracket, len(text)):\n        if text[index] == \"[\":\n            open_bracket_stack.append(text[index])\n        elif text[index] == \"]\":\n            open_bracket_stack.pop()\n        if not open_bracket_stack:\n            return index\n    raise SyntaxError(\n        \"No matching closing bracket ']' for the opening bracket '[' at {} \"\n        + str(index_of_open_bracket)\n    )\n\n\ndef _has_matched_brackets(text: str) -> bool:\n    \"\"\"\n    Evaluate whether every opening bracket '[' in the 'text' has a matching closing bracket ']'.\n\n    :param text: the text.\n    :return: Boolean result, and associated message.\n    \"\"\"\n    open_bracket_stack = []\n    for index, _ in enumerate(text):\n        if text[index] == \"[\":\n            open_bracket_stack.append(index)\n        elif text[index] == \"]\":\n            if len(open_bracket_stack) == 0:\n                return False\n            open_bracket_stack.pop()\n    return len(open_bracket_stack) == 0\n\n\ndef _get_sub_types_of_compositional_types(compositional_type: str) -> Tuple[str, ...]:\n    \"\"\"\n    Extract the sub-types of compositional types.\n\n    This method handles both specification types (e.g. pt:set[], pt:dict[]) as well as python types (e.g. FrozenSet[], Union[]).\n\n    :param compositional_type: the compositional type string whose sub-types are to be extracted.\n    :return: tuple containing all extracted sub-types.\n    \"\"\"\n    sub_types_list = []\n    for valid_compositional_type in (\n        SPECIFICATION_COMPOSITIONAL_TYPES + PYTHON_COMPOSITIONAL_TYPES\n    ):\n        if compositional_type.startswith(valid_compositional_type):\n            inside_string = compositional_type[\n                compositional_type.index(\"[\") + 1 : compositional_type.rindex(\"]\")\n            ].strip()\n            while inside_string != \"\":\n                do_not_add = False\n                if inside_string.find(\",\") == -1:  # No comma; this is the last sub-type\n                    provisional_sub_type = inside_string.strip()\n                    if (\n                        provisional_sub_type == \"...\"\n                    ):  # The sub-string is ... used for Tuple, e.g. Tuple[int, ...]\n                        do_not_add = True\n                    else:\n                        sub_type = provisional_sub_type\n                    inside_string = \"\"\n                else:  # There is a comma; this MAY not be the last sub-type\n                    sub_string_until_comma = inside_string[\n                        : inside_string.index(\",\")\n                    ].strip()\n                    if (\n                        sub_string_until_comma.find(\"[\") == -1\n                    ):  # No open brackets; this is a primitive type and NOT the last sub-type\n                        sub_type = sub_string_until_comma\n                        inside_string = inside_string[\n                            inside_string.index(\",\") + 1 :\n                        ].strip()\n                    else:  # There is an open bracket'['; this is a compositional type\n                        try:\n                            closing_bracket_index = _match_brackets(\n                                inside_string, inside_string.index(\"[\")\n                            )\n                        except SyntaxError:\n                            raise SyntaxError(\n                                \"Bad formatting. No matching close bracket ']' for the open bracket at {}\".format(\n                                    inside_string[\n                                        : inside_string.index(\"[\") + 1\n                                    ].strip()\n                                )\n                            )\n                        sub_type = inside_string[: closing_bracket_index + 1].strip()\n                        the_rest_of_inside_string = inside_string[\n                            closing_bracket_index + 1 :\n                        ].strip()\n                        if (\n                            the_rest_of_inside_string.find(\",\") == -1\n                        ):  # No comma; this is the last sub-type\n                            inside_string = the_rest_of_inside_string.strip()\n                        else:  # There is a comma; this is not the last sub-type\n                            inside_string = the_rest_of_inside_string[\n                                the_rest_of_inside_string.index(\",\") + 1 :\n                            ].strip()\n                if not do_not_add:\n                    sub_types_list.append(sub_type)\n            return tuple(sub_types_list)\n    raise SyntaxError(\n        \"{} is not a valid compositional type.\".format(compositional_type)\n    )\n\n\ndef _union_sub_type_to_protobuf_variable_name(\n    content_name: str, content_type: str\n) -> str:\n    \"\"\"\n    Given a content of type union, create a variable name for its sub-type for protobuf.\n\n    :param content_name: the name of the content\n    :param content_type: the sub-type of a union type\n\n    :return: The variable name\n    \"\"\"\n    if content_type.startswith(\"FrozenSet\"):\n        sub_type = _get_sub_types_of_compositional_types(content_type)[0]\n        expanded_type_str = \"set_of_{}\".format(sub_type)\n    elif content_type.startswith(\"Tuple\"):\n        sub_type = _get_sub_types_of_compositional_types(content_type)[0]\n        expanded_type_str = \"list_of_{}\".format(sub_type)\n    elif content_type.startswith(\"Dict\"):\n        sub_type_1 = _get_sub_types_of_compositional_types(content_type)[0]\n        sub_type_2 = _get_sub_types_of_compositional_types(content_type)[1]\n        expanded_type_str = \"dict_of_{}_{}\".format(sub_type_1, sub_type_2)\n    else:\n        expanded_type_str = content_type\n\n    protobuf_variable_name = \"{}_type_{}\".format(content_name, expanded_type_str)\n\n    return protobuf_variable_name\n\n\ndef _python_pt_or_ct_type_to_proto_type(content_type: str) -> str:\n    \"\"\"\n    Convert a PT or CT from python to their protobuf equivalent.\n\n    :param content_type: the python type\n    :return: The protobuf equivalent\n    \"\"\"\n    if content_type in PYTHON_TYPE_TO_PROTO_TYPE.keys():\n        proto_type = PYTHON_TYPE_TO_PROTO_TYPE[content_type]\n    else:\n        proto_type = content_type\n    return proto_type\n\n\ndef _includes_custom_type(content_type: str) -> bool:\n    \"\"\"\n    Evaluate whether a content type is a custom type or has a custom type as a sub-type.\n\n    :param content_type: the content type\n    :return: Boolean result\n    \"\"\"\n\n    if content_type.startswith(\"Optional\"):\n        sub_type = _get_sub_types_of_compositional_types(content_type)[0]\n        result = _includes_custom_type(sub_type)\n    elif content_type.startswith(\"Union\"):\n        sub_types = _get_sub_types_of_compositional_types(content_type)\n        result = False\n        for sub_type in sub_types:\n            if _includes_custom_type(sub_type):\n                result = True\n                break\n    elif (\n        content_type.startswith(\"FrozenSet\")\n        or content_type.startswith(\"Tuple\")\n        or content_type.startswith(\"Dict\")\n        or content_type in PYTHON_TYPE_TO_PROTO_TYPE.keys()\n    ):\n        result = False\n    else:\n        result = True\n    return result\n\n\ndef is_installed(programme: str) -> bool:\n    \"\"\"\n    Check whether a programme is installed on the system.\n\n    :param programme: the name of the programme.\n    :return: True if installed, False otherwise\n    \"\"\"\n    res = shutil.which(programme)\n    return res is not None\n\n\ndef base_protolint_command() -> str:\n    \"\"\"\n    Return the base protolint command.\n\n    :return: The base protolint command\n    \"\"\"\n    if sys.platform.startswith(\"win\"):\n        protolint_base_cmd = \"protolint\"  # pragma: nocover\n    else:\n        protolint_base_cmd = \"PATH=${PATH}:${GOPATH}/bin/:~/go/bin protolint\"\n\n    return protolint_base_cmd\n\n\ndef check_prerequisites() -> None:\n    \"\"\"Check whether a programme is installed on the system.\"\"\"\n    # check black code formatter is installed\n    if not is_installed(\"black\"):\n        raise FileNotFoundError(\n            \"Cannot find black code formatter! To install, please follow this link: https://black.readthedocs.io/en/stable/installation_and_usage.html\"\n        )\n\n    # check isort code formatter is installed\n    if not is_installed(\"isort\"):\n        raise FileNotFoundError(\n            \"Cannot find isort code formatter! To install, please follow this link: https://pycqa.github.io/isort/#installing-isort\"\n        )\n\n    # check protolint code formatter is installed\n    if subprocess.call(f\"{base_protolint_command()} version\", shell=True) != 0:  # nosec\n        raise FileNotFoundError(\n            \"Cannot find protolint protocol buffer schema file linter! To install, please follow this link: https://github.com/yoheimuta/protolint.\"\n        )\n\n    # check protocol buffer compiler is installed\n    if not is_installed(\"protoc\"):\n        raise FileNotFoundError(\n            \"Cannot find protocol buffer compiler! To install, please follow this link: https://developers.google.com/protocol-buffers/\"\n        )\n\n\ndef get_protoc_version() -> str:\n    \"\"\"Get the protoc version used.\"\"\"\n    result = subprocess.run(  # nosec\n        [\"protoc\", \"--version\"], stdout=subprocess.PIPE, check=True\n    )\n    result_str = result.stdout.decode(\"utf-8\").strip(\"\\n\").strip(\"\\r\")\n    return result_str\n\n\ndef load_protocol_specification(specification_path: str) -> ProtocolSpecification:\n    \"\"\"\n    Load a protocol specification.\n\n    :param specification_path: path to the protocol specification yaml file.\n    :return: A ProtocolSpecification object\n    \"\"\"\n    config_loader = ConfigLoader(\n        \"protocol-specification_schema.json\", ProtocolSpecification\n    )\n    protocol_spec = config_loader.load_protocol_specification(\n        open_file(specification_path)\n    )\n    return protocol_spec\n\n\ndef _create_protocol_file(\n    path_to_protocol_package: str, file_name: str, file_content: str\n) -> None:\n    \"\"\"\n    Create a file in the generated protocol package.\n\n    :param path_to_protocol_package: path to the file\n    :param file_name: the name of the file\n    :param file_content: the content of the file\n    \"\"\"\n    pathname = os.path.join(path_to_protocol_package, file_name)\n\n    with open_file(pathname, \"w\") as file:\n        file.write(file_content)\n\n\ndef try_run_black_formatting(path_to_protocol_package: str) -> None:\n    \"\"\"\n    Run Black code formatting via subprocess.\n\n    :param path_to_protocol_package: a path where formatting should be applied.\n    \"\"\"\n    subprocess.run(  # nosec\n        [sys.executable, \"-m\", \"black\", path_to_protocol_package, \"--quiet\"],\n        check=True,\n    )\n\n\ndef try_run_isort_formatting(path_to_protocol_package: str) -> None:\n    \"\"\"\n    Run Isort code formatting via subprocess.\n\n    :param path_to_protocol_package: a path where formatting should be applied.\n    \"\"\"\n    subprocess.run(  # nosec\n        [sys.executable, \"-m\", \"isort\", *ISORT_CLI_ARGS, path_to_protocol_package],\n        check=True,\n    )\n\n\ndef try_run_protoc(\n    path_to_generated_protocol_package: str,\n    name: str,\n    language: str = PROTOCOL_LANGUAGE_PYTHON,\n) -> None:\n    \"\"\"\n    Run 'protoc' protocol buffer compiler via subprocess.\n\n    :param path_to_generated_protocol_package: path to the protocol buffer schema file.\n    :param name: name of the protocol buffer schema file.\n    :param language: the target language in which to compile the protobuf schema file\n    \"\"\"\n    # for closure-styled imports for JS, comment the first line and uncomment the second\n    js_commonjs_import_option = (\n        \"import_style=commonjs,binary:\" if language == PROTOCOL_LANGUAGE_JS else \"\"\n    )\n\n    language_part_of_the_command = f\"--{language}_out={js_commonjs_import_option}{path_to_generated_protocol_package}\"\n\n    subprocess.run(  # nosec\n        [\n            \"protoc\",\n            f\"-I={path_to_generated_protocol_package}\",\n            language_part_of_the_command,\n            f\"{path_to_generated_protocol_package}/{name}.proto\",\n        ],\n        stderr=subprocess.PIPE,\n        encoding=\"utf-8\",\n        check=True,\n        env=os.environ.copy(),\n    )\n\n\ndef try_run_protolint(path_to_generated_protocol_package: str, name: str) -> None:\n    \"\"\"\n    Run 'protolint' linter via subprocess.\n\n    :param path_to_generated_protocol_package: path to the protocol buffer schema file.\n    :param name: name of the protocol buffer schema file.\n    \"\"\"\n    # path to proto file\n    path_to_proto_file = os.path.join(\n        path_to_generated_protocol_package,\n        f\"{name}.proto\",\n    )\n\n    # Dump protolint configuration into a temporary file\n    temp_dir = tempfile.mkdtemp()\n    path_to_configuration_in_tmp_file = Path(\n        temp_dir, PROTOLINT_CONFIGURATION_FILE_NAME\n    )\n    with open_file(path_to_configuration_in_tmp_file, \"w\") as file:\n        file.write(PROTOLINT_CONFIGURATION)\n\n    # Protolint command\n    cmd = f'{base_protolint_command()} lint -config_path={path_to_configuration_in_tmp_file} -fix \"{path_to_proto_file}\"'\n\n    # Execute protolint command\n    subprocess.run(  # nosec\n        cmd,\n        stderr=subprocess.PIPE,\n        stdout=subprocess.PIPE,\n        encoding=\"utf-8\",\n        check=True,\n        env=os.environ.copy(),\n        shell=True,\n    )\n\n    # Delete temporary configuration file\n    shutil.rmtree(temp_dir)  # pragma: no cover\n\n\ndef check_protobuf_using_protoc(\n    path_to_generated_protocol_package: str, name: str\n) -> Tuple[bool, str]:\n    \"\"\"\n    Check whether a protocol buffer schema file is valid.\n\n    Validation is via trying to compile the schema file. If successfully compiled it is valid, otherwise invalid.\n    If valid, return True and a 'protobuf file is valid' message, otherwise return False and the error thrown by the compiler.\n\n    :param path_to_generated_protocol_package: path to the protocol buffer schema file.\n    :param name: name of the protocol buffer schema file.\n\n    :return: Boolean result and an accompanying message\n    \"\"\"\n    try:\n        try_run_protoc(path_to_generated_protocol_package, name)\n        os.remove(os.path.join(path_to_generated_protocol_package, name + \"_pb2.py\"))\n        return True, \"protobuf file is valid\"\n    except subprocess.CalledProcessError as e:\n        pattern = name + \".proto:[0-9]+:[0-9]+: \"\n        error_message = re.sub(pattern, \"\", e.stderr[:-1])\n        return False, error_message\n\n\ndef compile_protobuf_using_protoc(\n    path_to_generated_protocol_package: str, name: str, language: str\n) -> Tuple[bool, str]:\n    \"\"\"\n    Compile a protocol buffer schema file using protoc.\n\n    If successfully compiled, return True and a success message,\n    otherwise return False and the error thrown by the compiler.\n\n    :param path_to_generated_protocol_package: path to the protocol buffer schema file.\n    :param name: name of the protocol buffer schema file.\n    :param language: the target language in which to compile the protobuf schema file\n\n    :return: Boolean result and an accompanying message\n    \"\"\"\n    try:\n        try_run_protoc(path_to_generated_protocol_package, name, language)\n        return True, \"protobuf schema successfully compiled\"\n    except subprocess.CalledProcessError as e:\n        pattern = name + \".proto:[0-9]+:[0-9]+: \"\n        error_message = re.sub(pattern, \"\", e.stderr[:-1])\n        return False, error_message\n\n\ndef apply_protolint(path_to_proto_file: str, name: str) -> Tuple[bool, str]:\n    \"\"\"\n    Apply protolint linter to a protocol buffer schema file.\n\n    If no output, return True and a success message,\n    otherwise return False and the output shown by the linter\n    (minus the indentation suggestions which are automatically fixed by protolint).\n\n    :param path_to_proto_file: path to the protocol buffer schema file.\n    :param name: name of the protocol buffer schema file.\n\n    :return: Boolean result and an accompanying message\n    \"\"\"\n    try:\n        try_run_protolint(path_to_proto_file, name)\n        return True, \"protolint has no output\"\n    except subprocess.CalledProcessError as e:\n        lines_to_show = []\n        for line in e.stderr.split(\"\\n\"):\n            to_show = True\n            for whitelist_error_str in PROTOLINT_ERROR_WHITELIST:\n                if whitelist_error_str in line:\n                    to_show = False\n                    break\n            if to_show:\n                lines_to_show.append(line)\n        error_message = \"\\n\".join(lines_to_show)\n        return False, error_message\n\n\ndef _is_compositional_type(content_type: str) -> bool:\n    \"\"\"Checks if content_type is compositional.\n\n    :param content_type: the type string.\n    :return: bool.\n    \"\"\"\n    for valid_compositional_type in (\n        SPECIFICATION_COMPOSITIONAL_TYPES + PYTHON_COMPOSITIONAL_TYPES\n    ):\n        if content_type.startswith(valid_compositional_type):\n            return True\n    return False\n"
  },
  {
    "path": "aea/protocols/generator/extract_specification.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module extracts a valid protocol specification into pythonic objects.\"\"\"\n\nimport re\nfrom typing import Dict, List, cast\n\nfrom aea.configurations.base import (\n    ProtocolSpecification,\n    ProtocolSpecificationParseError,\n)\nfrom aea.protocols.generator.common import (\n    SPECIFICATION_PRIMITIVE_TYPES,\n    _get_sub_types_of_compositional_types,\n    _is_compositional_type,\n)\n\n\ndef _ct_specification_type_to_python_type(specification_type: str) -> str:\n    \"\"\"\n    Convert a custom specification type into its python equivalent.\n\n    :param specification_type: a protocol specification data type\n    :return: The equivalent data type in Python\n    \"\"\"\n    python_type = specification_type[3:]\n    return python_type\n\n\ndef _pt_specification_type_to_python_type(specification_type: str) -> str:\n    \"\"\"\n    Convert a primitive specification type into its python equivalent.\n\n    :param specification_type: a protocol specification data type\n    :return: The equivalent data type in Python\n    \"\"\"\n    python_type = specification_type[3:]\n    return python_type\n\n\ndef _pct_specification_type_to_python_type(specification_type: str) -> str:\n    \"\"\"\n    Convert a primitive collection specification type into its python equivalent.\n\n    :param specification_type: a protocol specification data type\n    :return: The equivalent data type in Python\n    \"\"\"\n    element_type = _get_sub_types_of_compositional_types(specification_type)[0]\n    element_type_in_python = _specification_type_to_python_type(element_type)\n    if specification_type.startswith(\"pt:set\"):\n        python_type = \"FrozenSet[{}]\".format(element_type_in_python)\n    else:\n        python_type = \"Tuple[{}, ...]\".format(element_type_in_python)\n    return python_type\n\n\ndef _pmt_specification_type_to_python_type(specification_type: str) -> str:\n    \"\"\"\n    Convert a primitive mapping specification type into its python equivalent.\n\n    :param specification_type: a protocol specification data type\n    :return: The equivalent data type in Python\n    \"\"\"\n    element_types = _get_sub_types_of_compositional_types(specification_type)\n    element1_type_in_python = _specification_type_to_python_type(element_types[0])\n    element2_type_in_python = _specification_type_to_python_type(element_types[1])\n    python_type = \"Dict[{}, {}]\".format(\n        element1_type_in_python, element2_type_in_python\n    )\n    return python_type\n\n\ndef _mt_specification_type_to_python_type(specification_type: str) -> str:\n    \"\"\"\n    Convert a 'pt:union' specification type into its python equivalent.\n\n    :param specification_type: a protocol specification data type\n    :return: The equivalent data type in Python\n    \"\"\"\n    sub_types = _get_sub_types_of_compositional_types(specification_type)\n    python_type = \"Union[\"\n    for sub_type in sub_types:\n        python_type += \"{}, \".format(_specification_type_to_python_type(sub_type))\n    python_type = python_type[:-2]\n    python_type += \"]\"\n    return python_type\n\n\ndef _optional_specification_type_to_python_type(specification_type: str) -> str:\n    \"\"\"\n    Convert a 'pt:optional' specification type into its python equivalent.\n\n    :param specification_type: a protocol specification data type\n    :return: The equivalent data type in Python\n    \"\"\"\n    element_type = _get_sub_types_of_compositional_types(specification_type)[0]\n    element_type_in_python = _specification_type_to_python_type(element_type)\n    python_type = \"Optional[{}]\".format(element_type_in_python)\n    return python_type\n\n\ndef _specification_type_to_python_type(specification_type: str) -> str:\n    \"\"\"\n    Convert a data type in protocol specification into its Python equivalent.\n\n    :param specification_type: a protocol specification data type\n    :return: The equivalent data type in Python\n    \"\"\"\n    if specification_type.startswith(\"pt:optional\"):\n        python_type = _optional_specification_type_to_python_type(specification_type)\n    elif specification_type.startswith(\"pt:union\"):\n        python_type = _mt_specification_type_to_python_type(specification_type)\n    elif specification_type.startswith(\"ct:\"):\n        python_type = _ct_specification_type_to_python_type(specification_type)\n    elif specification_type in SPECIFICATION_PRIMITIVE_TYPES:\n        python_type = _pt_specification_type_to_python_type(specification_type)\n    elif specification_type.startswith(\"pt:set\"):\n        python_type = _pct_specification_type_to_python_type(specification_type)\n    elif specification_type.startswith(\"pt:list\"):\n        python_type = _pct_specification_type_to_python_type(specification_type)\n    elif specification_type.startswith(\"pt:dict\"):\n        python_type = _pmt_specification_type_to_python_type(specification_type)\n    else:\n        raise ProtocolSpecificationParseError(\n            \"Unsupported type: '{}'\".format(specification_type)\n        )\n    return python_type\n\n\nclass PythonicProtocolSpecification:  # pylint: disable=too-few-public-methods\n    \"\"\"This class represents a protocol specification in python.\"\"\"\n\n    def __init__(self) -> None:\n        \"\"\"Instantiate a Pythonic protocol specification.\"\"\"\n        self.speech_acts = {}  # type: Dict[str, Dict[str, str]]\n        self.all_performatives = []  # type: List[str]\n        self.all_unique_contents = {}  # type: Dict[str, str]\n        self.all_custom_types = []  # type: List[str]\n        self.custom_custom_types = {}  # type: Dict[str, str]\n\n        # dialogue config\n        self.initial_performatives = []  # type: List[str]\n        self.reply = {}  # type: Dict[str, List[str]]\n        self.terminal_performatives = []  # type: List[str]\n        self.roles = []  # type: List[str]\n        self.end_states = []  # type: List[str]\n        self.keep_terminal_state_dialogues = False  # type: bool\n\n        self.typing_imports = {\n            \"Set\": True,\n            \"Tuple\": True,\n            \"cast\": True,\n            \"FrozenSet\": False,\n            \"Dict\": False,\n            \"Union\": False,\n            \"Optional\": False,\n        }\n\n\ndef extract(\n    protocol_specification: ProtocolSpecification,\n) -> PythonicProtocolSpecification:\n    \"\"\"\n    Converts a protocol specification into a Pythonic protocol specification.\n\n    :param protocol_specification: a protocol specification\n    :return: a Pythonic protocol specification\n    \"\"\"\n    spec = PythonicProtocolSpecification()\n\n    all_performatives_set = set()\n    all_custom_types_set = set()\n\n    for (\n        performative,\n        speech_act_content_config,\n    ) in protocol_specification.speech_acts.read_all():\n        all_performatives_set.add(performative)\n        spec.speech_acts[performative] = {}\n        for content_name, content_type in speech_act_content_config.args.items():\n\n            # determine necessary imports from typing\n            if len(re.findall(\"pt:set\\\\[\", content_type)) >= 1:\n                spec.typing_imports[\"FrozenSet\"] = True\n            if len(re.findall(\"pt:dict\\\\[\", content_type)) >= 1:\n                spec.typing_imports[\"Dict\"] = True\n            if len(re.findall(\"pt:union\\\\[\", content_type)) >= 1:\n                spec.typing_imports[\"Union\"] = True\n            if len(re.findall(\"pt:optional\\\\[\", content_type)) >= 1:\n                spec.typing_imports[\"Optional\"] = True\n\n            # specification type --> python type\n            pythonic_content_type = _specification_type_to_python_type(content_type)\n\n            spec.all_unique_contents[content_name] = pythonic_content_type\n            spec.speech_acts[performative][content_name] = pythonic_content_type\n            if content_type.startswith(\"ct:\"):\n                all_custom_types_set.add(pythonic_content_type)\n\n            for sub_type in (\n                list(_get_sub_types_of_compositional_types(content_type))\n                if _is_compositional_type(content_type)\n                else []\n            ):\n                if sub_type.startswith(\"ct:\"):\n                    pythonic_content_type = _specification_type_to_python_type(sub_type)\n                    all_custom_types_set.add(pythonic_content_type)\n\n    # sort the sets\n    spec.all_performatives = sorted(all_performatives_set)\n    spec.all_custom_types = sorted(all_custom_types_set)\n\n    # \"XXX\" custom type --> \"CustomXXX\"\n    spec.custom_custom_types = {\n        pure_custom_type: \"Custom\" + pure_custom_type\n        for pure_custom_type in spec.all_custom_types\n    }\n\n    # Dialogue attributes\n    if (\n        protocol_specification.dialogue_config != {}\n        and protocol_specification.dialogue_config is not None\n    ):\n        spec.initial_performatives = [\n            initial_performative.upper()\n            for initial_performative in cast(\n                List[str], protocol_specification.dialogue_config[\"initiation\"]\n            )\n        ]\n        spec.reply = cast(\n            Dict[str, List[str]],\n            protocol_specification.dialogue_config[\"reply\"],\n        )\n        spec.terminal_performatives = [\n            terminal_performative.upper()\n            for terminal_performative in cast(\n                List[str],\n                protocol_specification.dialogue_config[\"termination\"],\n            )\n        ]\n        roles_set = cast(\n            Dict[str, None], protocol_specification.dialogue_config[\"roles\"]\n        )\n        spec.roles = sorted(roles_set)\n        spec.end_states = cast(\n            List[str], protocol_specification.dialogue_config[\"end_states\"]\n        )\n        spec.keep_terminal_state_dialogues = cast(\n            bool,\n            protocol_specification.dialogue_config.get(\n                \"keep_terminal_state_dialogues\", False\n            ),\n        )\n    return spec\n"
  },
  {
    "path": "aea/protocols/generator/isort.cfg",
    "content": "# isort configurations for the protocol generator\n[isort]\n# for black compatibility\nmulti_line_output=3\ninclude_trailing_comma=True\nforce_grid_wrap=0\nuse_parentheses=True\nensure_newline_before_comments = True\nline_length=88\n# custom configurations\norder_by_type=False\ncase_sensitive=True\nlines_after_imports=2\nskip_glob = **/*_pb2.py\nknown_first_party=aea\nknown_packages=packages\nknown_local_folder=tests\nsections=FUTURE,STDLIB,THIRDPARTY,FIRSTPARTY,PACKAGES,LOCALFOLDER\n"
  },
  {
    "path": "aea/protocols/generator/validate.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module validates a protocol specification.\"\"\"\n\nimport re\nfrom typing import Any, Dict, List, Optional, Set, Tuple, cast\n\nfrom aea.configurations.base import ProtocolSpecification\nfrom aea.protocols.generator.common import (\n    SPECIFICATION_COMPOSITIONAL_TYPES,\n    SPECIFICATION_PRIMITIVE_TYPES,\n    _get_sub_types_of_compositional_types,\n    _has_matched_brackets,\n    _is_compositional_type,\n)\n\n\n# The following names are reserved for standard message fields and cannot be\n# used as user defined names for performative or contents\nRESERVED_NAMES = {\"_body\", \"message_id\", \"dialogue_reference\", \"target\", \"performative\"}\n\n# Regular expression patterns for various fields in protocol specifications\nPERFORMATIVE_REGEX_PATTERN = \"^[a-zA-Z0-9]+$|^[a-zA-Z0-9]+(_?[a-zA-Z0-9]+)+$\"\nCONTENT_NAME_REGEX_PATTERN = \"^[a-zA-Z0-9]+$|^[a-zA-Z0-9]+(_?[a-zA-Z0-9]+)+$\"\n\nCT_NAME_RE = (\n    \"[A-Z][a-zA-Z0-9]*\"  # or maybe \"ct:(?:[A-Z][a-z]+)+\" or # \"^ct:([A-Z]+[a-z]*)+$\"\n)\nCT_CONTENT_TYPE_REGEX_PATTERN = f\"^ct:{CT_NAME_RE}$\"\n\nROLE_REGEX_PATTERN = \"^[a-zA-Z0-9]+$|^[a-zA-Z0-9]+(_?[a-zA-Z0-9]+)+$\"\nEND_STATE_REGEX_PATTERN = \"^[a-zA-Z0-9]+$|^[a-zA-Z0-9]+(_?[a-zA-Z0-9]+)+$\"\n\nDIALOGUE_SECTION_REQUIRED_FIELDS = [\n    \"initiation\",\n    \"reply\",\n    \"termination\",\n    \"roles\",\n    \"end_states\",\n    \"keep_terminal_state_dialogues\",\n]\n\n\ndef _is_reserved_name(content_name: str) -> bool:\n    \"\"\"\n    Evaluate whether a content name is a reserved name or not.\n\n    :param content_name: a content name\n    :return: Boolean result\n    \"\"\"\n    return content_name in RESERVED_NAMES\n\n\ndef _is_valid_regex(regex_pattern: str, text: str) -> bool:\n    \"\"\"\n    Evaluate whether a 'text' matches a regular expression pattern.\n\n    :param regex_pattern: the regular expression pattern\n    :param text: the text on which to match regular expression\n\n    :return: Boolean result\n    \"\"\"\n    match = re.match(regex_pattern, text)\n    return match is not None\n\n\ndef _has_brackets(content_type: str) -> bool:\n    \"\"\"\n    Evaluate whether a compositional content type in a protocol specification is valid has corresponding brackets.\n\n    :param content_type: an 'set' content type.\n    :return: Boolean result\n    \"\"\"\n    for compositional_type in SPECIFICATION_COMPOSITIONAL_TYPES:\n        if content_type.startswith(compositional_type):\n            content_type = content_type[len(compositional_type) :]\n            if len(content_type) < 2:\n                return False\n            return content_type[0] == \"[\" and content_type[len(content_type) - 1] == \"]\"\n    raise SyntaxError(\"Content type must be a compositional type!\")\n\n\ndef _is_valid_ct(content_type: str) -> bool:\n    \"\"\"\n    Evaluate whether the format of a 'ct' content type in a protocol specification is valid.\n\n    :param content_type: a 'ct' content type.\n    :return: Boolean result\n    \"\"\"\n    content_type = content_type.strip()\n    return _is_valid_regex(CT_CONTENT_TYPE_REGEX_PATTERN, content_type)\n\n\ndef _is_valid_pt(content_type: str) -> bool:\n    \"\"\"\n    Evaluate whether the format of a 'pt' content type in a protocol specification is valid.\n\n    :param content_type: a 'pt' content type.\n    :return: Boolean result\n    \"\"\"\n    content_type = content_type.strip()\n    return content_type in SPECIFICATION_PRIMITIVE_TYPES\n\n\ndef _is_valid_set(content_type: str) -> bool:\n    \"\"\"\n    Evaluate whether the format of a 'set' content type in a protocol specification is valid.\n\n    :param content_type: a 'set' content type.\n    :return: Boolean result\n    \"\"\"\n    content_type = content_type.strip()\n\n    if not content_type.startswith(\"pt:set\"):\n        return False\n\n    if not _has_matched_brackets(content_type):\n        return False\n\n    if not _has_brackets(content_type):\n        return False\n\n    sub_types = _get_sub_types_of_compositional_types(content_type)\n    if len(sub_types) != 1:\n        return False\n\n    sub_type = sub_types[0]\n    return _is_valid_pt(sub_type)\n\n\ndef _is_valid_list(content_type: str) -> bool:\n    \"\"\"\n    Evaluate whether the format of a 'list' content type in a protocol specification is valid.\n\n    :param content_type: a 'list' content type.\n    :return: Boolean result\n    \"\"\"\n    content_type = content_type.strip()\n\n    if not content_type.startswith(\"pt:list\"):\n        return False\n\n    if not _has_matched_brackets(content_type):\n        return False\n\n    if not _has_brackets(content_type):\n        return False\n\n    sub_types = _get_sub_types_of_compositional_types(content_type)\n    if len(sub_types) != 1:\n        return False\n\n    sub_type = sub_types[0]\n    return _is_valid_pt(sub_type)\n\n\ndef _is_valid_dict(content_type: str) -> bool:\n    \"\"\"\n    Evaluate whether the format of a 'dict' content type in a protocol specification is valid.\n\n    :param content_type: a 'dict' content type.\n    :return: Boolean result\n    \"\"\"\n    content_type = content_type.strip()\n\n    if not content_type.startswith(\"pt:dict\"):\n        return False\n\n    if not _has_matched_brackets(content_type):\n        return False\n\n    if not _has_brackets(content_type):\n        return False\n\n    sub_types = _get_sub_types_of_compositional_types(content_type)\n    if len(sub_types) != 2:\n        return False\n\n    sub_type_1 = sub_types[0]\n    sub_type_2 = sub_types[1]\n    return _is_valid_pt(sub_type_1) and _is_valid_pt(sub_type_2)\n\n\ndef _is_valid_union(content_type: str) -> bool:\n    \"\"\"\n    Evaluate whether the format of a 'union' content type in a protocol specification is valid.\n\n    :param content_type: an 'union' content type.\n    :return: Boolean result\n    \"\"\"\n    content_type = content_type.strip()\n\n    if not content_type.startswith(\"pt:union\"):\n        return False\n\n    if not _has_matched_brackets(content_type):\n        return False\n\n    if not _has_brackets(content_type):\n        return False\n\n    sub_types = _get_sub_types_of_compositional_types(content_type)\n    # check there are at least two subtypes in the union\n    if len(sub_types) < 2:\n        return False\n\n    # check there are no duplicate subtypes in the union\n    sub_types_set = set(sub_types)\n    if len(sub_types) != len(sub_types_set):\n        return False\n\n    for sub_type in sub_types:\n        if not (\n            _is_valid_ct(sub_type)\n            or _is_valid_pt(sub_type)\n            or _is_valid_dict(sub_type)\n            or _is_valid_list(sub_type)\n            or _is_valid_set(sub_type)\n        ):\n            return False\n\n    return True\n\n\ndef _is_valid_optional(content_type: str) -> bool:\n    \"\"\"\n    Evaluate whether the format of an 'optional' content type in a protocol specification is valid.\n\n    :param content_type: an 'optional' content type.\n    :return: Boolean result\n    \"\"\"\n    content_type = content_type.strip()\n\n    if not content_type.startswith(\"pt:optional\"):\n        return False\n\n    if not _has_matched_brackets(content_type):\n        return False\n\n    if not _has_brackets(content_type):\n        return False\n\n    sub_types = _get_sub_types_of_compositional_types(content_type)\n    if len(sub_types) != 1:\n        return False\n\n    sub_type = sub_types[0]\n    return (\n        _is_valid_ct(sub_type)\n        or _is_valid_pt(sub_type)\n        or _is_valid_set(sub_type)\n        or _is_valid_list(sub_type)\n        or _is_valid_dict(sub_type)\n        or _is_valid_union(sub_type)\n    )\n\n\ndef _is_valid_content_type_format(content_type: str) -> bool:\n    \"\"\"\n    Evaluate whether the format of a content type in a protocol specification is valid.\n\n    :param content_type: a content type.\n    :return: Boolean result\n    \"\"\"\n    return (\n        _is_valid_ct(content_type)\n        or _is_valid_pt(content_type)\n        or _is_valid_set(content_type)\n        or _is_valid_list(content_type)\n        or _is_valid_dict(content_type)\n        or _is_valid_union(content_type)\n        or _is_valid_optional(content_type)\n    )\n\n\ndef _validate_performatives(performative: str) -> Tuple[bool, str]:\n    \"\"\"\n    Evaluate whether a performative in a protocol specification is valid.\n\n    :param performative: a performative.\n    :return: Boolean result, and associated message.\n    \"\"\"\n    # check performative is not a reserved name\n    if _is_reserved_name(performative):\n        return (\n            False,\n            \"Invalid name for performative '{}'. This name is reserved.\".format(\n                performative,\n            ),\n        )\n\n    # check performative's format\n    if not _is_valid_regex(PERFORMATIVE_REGEX_PATTERN, performative):\n        return (\n            False,\n            \"Invalid name for performative '{}'. Performative names must match the following regular expression: {} \".format(\n                performative, PERFORMATIVE_REGEX_PATTERN\n            ),\n        )\n\n    return True, \"Performative '{}' is valid.\".format(performative)\n\n\ndef _validate_content_name(content_name: str, performative: str) -> Tuple[bool, str]:\n    \"\"\"\n    Evaluate whether the name of a content in a protocol specification is valid.\n\n    :param content_name: a content name.\n    :param performative: the performative the content belongs to.\n\n    :return: Boolean result, and associated message.\n    \"\"\"\n    # check content name's format\n    if not _is_valid_regex(CONTENT_NAME_REGEX_PATTERN, content_name):\n        return (\n            False,\n            \"Invalid name for content '{}' of performative '{}'. Content names must match the following regular expression: {} \".format(\n                content_name, performative, CONTENT_NAME_REGEX_PATTERN\n            ),\n        )\n\n    # check content name is not a reserved name\n    if _is_reserved_name(content_name):\n        return (\n            False,\n            \"Invalid name for content '{}' of performative '{}'. This name is reserved.\".format(\n                content_name,\n                performative,\n            ),\n        )\n\n    return (\n        True,\n        \"Content name '{}' of performative '{}' is valid.\".format(\n            content_name, performative\n        ),\n    )\n\n\ndef _validate_content_type(\n    content_type: str, content_name: str, performative: str\n) -> Tuple[bool, str]:\n    \"\"\"\n    Evaluate whether the type of a content in a protocol specification is valid.\n\n    :param content_type: a content type.\n    :param content_name: a content name.\n    :param performative: the performative the content belongs to.\n\n    :return: Boolean result, and associated message.\n    \"\"\"\n    if not _is_valid_content_type_format(content_type):\n        return (\n            False,\n            \"Invalid type for content '{}' of performative '{}'. See documentation for the correct format of specification types.\".format(\n                content_name,\n                performative,\n            ),\n        )\n\n    return (\n        True,\n        \"Type of content '{}' of performative '{}' is valid.\".format(\n            content_name, performative\n        ),\n    )\n\n\ndef _validate_speech_acts_section(\n    protocol_specification: ProtocolSpecification,\n) -> Tuple[bool, str, Optional[Set[str]], Optional[Set[str]]]:\n    \"\"\"\n    Evaluate whether speech-acts of a protocol specification is valid.\n\n    :param protocol_specification: a protocol specification.\n    :return: Boolean result, associated message, set of all performatives (auxiliary), set of all custom types (auxiliary).\n    \"\"\"\n    custom_types_set = set()\n    performatives_set = set()\n\n    content_names_types: Dict[str, Tuple[str, str]] = {}\n\n    # check that speech-acts definition is not empty\n    if len(protocol_specification.speech_acts.read_all()) == 0:\n        return (\n            False,\n            \"Speech-acts cannot be empty!\",\n            None,\n            None,\n        )\n\n    for (\n        performative,\n        speech_act_content_config,\n    ) in protocol_specification.speech_acts.read_all():\n\n        # Validate performative name\n        (\n            result_performative_validation,\n            msg_performative_validation,\n        ) = _validate_performatives(performative)\n        if not result_performative_validation:\n            return (\n                result_performative_validation,\n                msg_performative_validation,\n                None,\n                None,\n            )\n\n        performatives_set.add(performative)\n\n        for content_name, content_type in speech_act_content_config.args.items():\n\n            # Validate content name\n            (\n                result_content_name_validation,\n                msg_content_name_validation,\n            ) = _validate_content_name(content_name, performative)\n            if not result_content_name_validation:\n                return (\n                    result_content_name_validation,\n                    msg_content_name_validation,\n                    None,\n                    None,\n                )\n\n            # check type of content_type\n            if not isinstance(content_type, str):\n                return (\n                    False,\n                    \"Invalid type for '{}'. Expected str. Found {}.\".format(\n                        content_name, type(content_type)\n                    ),\n                    None,\n                    None,\n                )\n\n            # Validate content type\n            (\n                result_content_type_validation,\n                msg_content_type_validation,\n            ) = _validate_content_type(content_type, content_name, performative)\n            if not result_content_type_validation:\n                return (\n                    result_content_type_validation,\n                    msg_content_type_validation,\n                    None,\n                    None,\n                )\n\n            # check content name isn't repeated with a different type\n            if content_name in content_names_types:\n                last_performative = content_names_types[content_name][0]\n                last_content_type = content_names_types[content_name][1]\n                if last_content_type != content_type:\n                    return (\n                        False,\n                        \"Content '{}' with type '{}' under performative '{}' is already defined under performative '{}' with a different type ('{}').\".format(\n                            content_name,\n                            content_type,\n                            performative,\n                            last_performative,\n                            last_content_type,\n                        ),\n                        None,\n                        None,\n                    )\n\n            content_names_types[content_name] = (performative, content_type)\n\n            for sub_type in (\n                list(_get_sub_types_of_compositional_types(content_type))\n                if _is_compositional_type(content_type)\n                else []\n            ) + [content_type]:\n                if _is_valid_ct(sub_type):\n                    custom_types_set.add(sub_type.strip())\n\n    return True, \"Speech-acts are valid.\", performatives_set, custom_types_set\n\n\ndef _validate_protocol_buffer_schema_code_snippets(\n    protocol_specification: ProtocolSpecification, custom_types_set: Set[str]\n) -> Tuple[bool, str]:\n    \"\"\"\n    Evaluate whether the protobuf code snippet section of a protocol specification is valid.\n\n    :param protocol_specification: a protocol specification.\n    :param custom_types_set: set of all custom types in the protocol.\n\n    :return: Boolean result, and associated message.\n    \"\"\"\n    if (\n        protocol_specification.protobuf_snippets is not None\n        and protocol_specification.protobuf_snippets != \"\"\n    ):\n        # check all custom types are actually used in speech-acts definition\n        for custom_type in protocol_specification.protobuf_snippets.keys():\n            if custom_type not in custom_types_set:\n                return (\n                    False,\n                    \"Extra protobuf code snippet provided. Type '{}' is not used anywhere in your protocol definition.\".format(\n                        custom_type,\n                    ),\n                )\n            custom_types_set.remove(custom_type)\n\n        # check that no custom type already used in speech-acts definition is missing\n        if len(custom_types_set) != 0:\n            return (\n                False,\n                \"No protobuf code snippet is provided for the following custom types: {}\".format(\n                    custom_types_set,\n                ),\n            )\n\n    return True, \"Protobuf code snippet section is valid.\"\n\n\ndef _validate_field_existence(dialogue_config: List[str]) -> Tuple[bool, str]:\n    \"\"\"\n    Evaluate whether the dialogue section of a protocol specification contains the required fields.\n\n    :param dialogue_config: the dialogue section of a protocol specification.\n\n    :return: Boolean result, and associated message.\n    \"\"\"\n    # check required fields exist\n    for required_field in DIALOGUE_SECTION_REQUIRED_FIELDS:\n        if required_field not in dialogue_config:\n            return (\n                False,\n                \"Missing required field '{}' in the dialogue section of the protocol specification.\".format(\n                    required_field\n                ),\n            )\n\n    return True, \"Dialogue section has all the required fields.\"\n\n\ndef _validate_initiation(\n    initiation: List[str], performatives_set: Set[str]\n) -> Tuple[bool, str]:\n    \"\"\"\n    Evaluate whether the initiation field in a protocol specification is valid.\n\n    :param initiation: List of initial messages of a dialogue.\n    :param performatives_set: set of all performatives in the dialogue.\n\n    :return: Boolean result, and associated message.\n    \"\"\"\n    # check type\n    if not isinstance(initiation, list):\n        return (\n            False,\n            \"Invalid type for initiation. Expected list. Found '{}'.\".format(\n                type(initiation)\n            ),\n        )\n\n    # check initiation is not empty/None\n    if len(initiation) == 0 or initiation is None:\n        return (\n            False,\n            \"At least one initial performative for this dialogue must be specified.\",\n        )\n\n    # check performatives are previously defined\n    for performative in initiation:\n        if performative not in performatives_set:\n            return (\n                False,\n                \"Performative '{}' specified in \\\"initiation\\\" is not defined in the protocol's speech-acts.\".format(\n                    performative,\n                ),\n            )\n\n    return True, \"Initial messages are valid.\"\n\n\ndef _validate_reply(\n    reply_definition: Dict[str, List[str]], performatives_set: Set[str]\n) -> Tuple[bool, str, Optional[Set[str]]]:\n    \"\"\"\n    Evaluate whether the reply definition in a protocol specification is valid.\n\n    :param reply_definition: Reply structure of a dialogue.\n    :param performatives_set: set of all performatives in the dialogue.\n\n    :return: Boolean result, and associated message.\n    \"\"\"\n    # check type\n    if not isinstance(reply_definition, dict):\n        return (\n            False,\n            \"Invalid type for the reply definition. Expected dict. Found '{}'.\".format(\n                type(reply_definition)\n            ),\n            None,\n        )\n\n    performatives_set_2 = performatives_set.copy()\n    terminal_performatives_from_reply = set()\n\n    for performative, replies in reply_definition.items():\n        # check only previously defined performatives are included in the reply definition\n        if performative not in performatives_set_2:\n            return (\n                False,\n                \"Performative '{}' specified in \\\"reply\\\" is not defined in the protocol's speech-acts.\".format(\n                    performative,\n                ),\n                None,\n            )\n\n        # check the type of replies\n        if not isinstance(replies, list):\n            return (\n                False,\n                \"Invalid type for replies of performative {}. Expected list. Found '{}'.\".format(\n                    performative, type(replies)\n                ),\n                None,\n            )\n\n        # check all replies are performatives which are previously defined in the speech-acts definition\n        for reply in replies:\n            if reply not in performatives_set:\n                return (\n                    False,\n                    \"Performative '{}' in the list of replies for '{}' is not defined in speech-acts.\".format(\n                        reply, performative\n                    ),\n                    None,\n                )\n\n        performatives_set_2.remove(performative)\n\n        if len(replies) == 0:\n            terminal_performatives_from_reply.add(performative)\n\n    # check all previously defined performatives are included in the reply definition\n    if len(performatives_set_2) != 0:\n        return (\n            False,\n            \"No reply is provided for the following performatives: {}\".format(\n                performatives_set_2,\n            ),\n            None,\n        )\n\n    return True, \"Reply structure is valid.\", terminal_performatives_from_reply\n\n\ndef _validate_termination(\n    termination: List[str],\n    performatives_set: Set[str],\n    terminal_performatives_from_reply: Set[str],\n) -> Tuple[bool, str]:\n    \"\"\"\n    Evaluate whether termination field in a protocol specification is valid.\n\n    :param termination: List of terminal messages of a dialogue.\n    :param performatives_set: set of all performatives in the dialogue.\n    :param terminal_performatives_from_reply: terminal performatives extracted from reply structure.\n\n    :return: Boolean result, and associated message.\n    \"\"\"\n    # check type\n    if not isinstance(termination, list):\n        return (\n            False,\n            \"Invalid type for termination. Expected list. Found '{}'.\".format(\n                type(termination)\n            ),\n        )\n\n    # check termination is not empty/None\n    if len(termination) == 0 or termination is None:\n        return (\n            False,\n            \"At least one terminal performative for this dialogue must be specified.\",\n        )\n\n    # check terminal performatives are previously defined\n    for performative in termination:\n        if performative not in performatives_set:\n            return (\n                False,\n                \"Performative '{}' specified in \\\"termination\\\" is not defined in the protocol's speech-acts.\".format(\n                    performative,\n                ),\n            )\n\n    # check that there are no repetitive performatives in termination\n    number_of_duplicates = len(termination) - len(set(termination))\n    if number_of_duplicates > 0:\n        return (\n            False,\n            'There are {} duplicate performatives in \"termination\".'.format(\n                number_of_duplicates,\n            ),\n        )\n\n    # check terminal performatives have no replies\n    for performative in termination:\n        if performative not in terminal_performatives_from_reply:\n            return (\n                False,\n                'The terminal performative \\'{}\\' specified in \"termination\" is assigned replies in \"reply\".'.format(\n                    performative,\n                ),\n            )\n\n    # check performatives with no replies are specified as terminal performatives\n    for performative in terminal_performatives_from_reply:\n        if performative not in termination:\n            return (\n                False,\n                \"The performative '{}' has no replies but is not listed as a terminal performative in \\\"termination\\\".\".format(\n                    performative,\n                ),\n            )\n\n    return True, \"Terminal messages are valid.\"\n\n\ndef _validate_roles(roles: Dict[str, Any]) -> Tuple[bool, str]:\n    \"\"\"\n    Evaluate whether roles field in a protocol specification is valid.\n\n    :param roles: Set of roles of a dialogue.\n    :return: Boolean result, and associated message.\n    \"\"\"\n    # check type\n    if not isinstance(roles, dict):\n        return (\n            False,\n            \"Invalid type for roles. Expected dict. Found '{}'.\".format(type(roles)),\n        )\n\n    # check number of roles\n    if not 1 <= len(roles) <= 2:\n        return (\n            False,\n            \"There must be either 1 or 2 roles defined in this dialogue. Found {}\".format(\n                len(roles)\n            ),\n        )\n\n    # check each role's format\n    for role in roles:\n        if not _is_valid_regex(ROLE_REGEX_PATTERN, role):\n            return (\n                False,\n                \"Invalid name for role '{}'. Role names must match the following regular expression: {} \".format(\n                    role, ROLE_REGEX_PATTERN\n                ),\n            )\n\n    return True, \"Dialogue roles are valid.\"\n\n\ndef _validate_end_states(end_states: List[str]) -> Tuple[bool, str]:\n    \"\"\"\n    Evaluate whether end_states field in a protocol specification is valid.\n\n    :param end_states: List of end states of a dialogue.\n    :return: Boolean result, and associated message.\n    \"\"\"\n    # check type\n    if not isinstance(end_states, list):\n        return (\n            False,\n            \"Invalid type for roles. Expected list. Found '{}'.\".format(\n                type(end_states)\n            ),\n        )\n\n    # check each end_state's format\n    for end_state in end_states:\n        if not _is_valid_regex(END_STATE_REGEX_PATTERN, end_state):\n            return (\n                False,\n                \"Invalid name for end_state '{}'. End_state names must match the following regular expression: {} \".format(\n                    end_state, END_STATE_REGEX_PATTERN\n                ),\n            )\n\n    return True, \"Dialogue end_states are valid.\"\n\n\ndef _validate_keep_terminal(keep_terminal_state_dialogues: bool) -> Tuple[bool, str]:\n    \"\"\"\n    Evaluate whether keep_terminal_state_dialogues field in a protocol specification is valid.\n\n    :param keep_terminal_state_dialogues: the value of keep_terminal_state_dialogues.\n    :return: Boolean result, and associated message.\n    \"\"\"\n    # check the type of keep_terminal_state_dialogues's value\n    if (\n        type(keep_terminal_state_dialogues)  # pylint: disable=unidiomatic-typecheck\n        != bool\n    ):\n        return (\n            False,\n            \"Invalid type for keep_terminal_state_dialogues. Expected bool. Found {}.\".format(\n                type(keep_terminal_state_dialogues)\n            ),\n        )\n\n    return True, \"Dialogue keep_terminal_state_dialogues is valid.\"\n\n\ndef _validate_dialogue_section(\n    protocol_specification: ProtocolSpecification, performatives_set: Set[str]\n) -> Tuple[bool, str]:\n    \"\"\"\n    Evaluate whether the dialogue section of a protocol specification is valid.\n\n    :param protocol_specification: a protocol specification.\n    :param performatives_set: set of all performatives in the dialogue.\n\n    :return: Boolean result, and associated message.\n    \"\"\"\n    if (\n        protocol_specification.dialogue_config != {}\n        and protocol_specification.dialogue_config is not None\n    ):\n        # validate required fields exist\n        (\n            result_field_existence_validation,\n            msg_field_existence_validation,\n        ) = _validate_field_existence(\n            cast(List[str], protocol_specification.dialogue_config),\n        )\n        if not result_field_existence_validation:\n            return result_field_existence_validation, msg_field_existence_validation\n\n        # Validate initiation\n        result_initiation_validation, msg_initiation_validation = _validate_initiation(\n            cast(List[str], protocol_specification.dialogue_config[\"initiation\"]),\n            performatives_set,\n        )\n        if not result_initiation_validation:\n            return result_initiation_validation, msg_initiation_validation\n\n        # Validate reply\n        (\n            result_reply_validation,\n            msg_reply_validation,\n            terminal_performatives_from_reply,\n        ) = _validate_reply(\n            cast(Dict[str, List[str]], protocol_specification.dialogue_config[\"reply\"]),\n            performatives_set,\n        )\n        if not result_reply_validation:\n            return result_reply_validation, msg_reply_validation\n\n        # Validate termination\n        terminal_performatives_from_reply = cast(\n            Set[str], terminal_performatives_from_reply\n        )\n        (\n            result_termination_validation,\n            msg_termination_validation,\n        ) = _validate_termination(\n            cast(List[str], protocol_specification.dialogue_config[\"termination\"]),\n            performatives_set,\n            terminal_performatives_from_reply,\n        )\n        if not result_termination_validation:\n            return result_termination_validation, msg_termination_validation\n\n        # Validate roles\n        result_roles_validation, msg_roles_validation = _validate_roles(\n            cast(Dict[str, Any], protocol_specification.dialogue_config[\"roles\"])\n        )\n        if not result_roles_validation:\n            return result_roles_validation, msg_roles_validation\n\n        # Validate end_state\n        result_end_states_validation, msg_end_states_validation = _validate_end_states(\n            cast(List[str], protocol_specification.dialogue_config[\"end_states\"])\n        )\n        if not result_end_states_validation:\n            return result_end_states_validation, msg_end_states_validation\n\n        # Validate keep_terminal_state_dialogues\n        (\n            result_keep_terminal_validation,\n            msg_keep_terminal_validation,\n        ) = _validate_keep_terminal(\n            cast(\n                bool,\n                protocol_specification.dialogue_config[\"keep_terminal_state_dialogues\"],\n            )\n        )\n        if not result_keep_terminal_validation:\n            return result_keep_terminal_validation, msg_keep_terminal_validation\n\n    return True, \"Dialogue section of the protocol specification is valid.\"\n\n\ndef validate(protocol_specification: ProtocolSpecification) -> Tuple[bool, str]:\n    \"\"\"\n    Evaluate whether a protocol specification is valid.\n\n    :param protocol_specification: a protocol specification.\n    :return: Boolean result, and associated message.\n    \"\"\"\n    # Validate speech-acts section\n    (\n        result_speech_acts_validation,\n        msg_speech_acts_validation,\n        performatives_set,\n        custom_types_set,\n    ) = _validate_speech_acts_section(protocol_specification)\n    if not result_speech_acts_validation:\n        return result_speech_acts_validation, msg_speech_acts_validation\n\n    # Validate protocol buffer schema code snippets\n    result_protobuf_validation, msg_protobuf_validation = _validate_protocol_buffer_schema_code_snippets(protocol_specification, custom_types_set)  # type: ignore\n    if not result_protobuf_validation:\n        return result_protobuf_validation, msg_protobuf_validation\n\n    # Validate dialogue section\n    result_dialogue_validation, msg_dialogue_validation = _validate_dialogue_section(protocol_specification, performatives_set)  # type: ignore\n    if not result_dialogue_validation:\n        return result_dialogue_validation, msg_dialogue_validation\n\n    return True, \"Protocol specification is valid.\"\n"
  },
  {
    "path": "aea/protocols/scaffold/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the support resources for the scaffold protocol.\"\"\"\n\nfrom aea.protocols.scaffold.message import MyScaffoldMessage\nfrom aea.protocols.scaffold.serialization import MyScaffoldSerializer\n\n\nMyScaffoldMessage.serializer = MyScaffoldSerializer\n"
  },
  {
    "path": "aea/protocols/scaffold/message.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the scaffold message definition.\"\"\"\n\nfrom enum import Enum\nfrom typing import Any\n\nfrom aea.configurations.base import PublicId\nfrom aea.exceptions import enforce\nfrom aea.protocols.base import Message\nfrom aea.protocols.scaffold.serialization import MyScaffoldSerializer\n\n\nclass MyScaffoldMessage(Message):\n    \"\"\"The scaffold message class.\"\"\"\n\n    protocol_id = PublicId.from_str(\"fetchai/scaffold:0.1.0\")\n    serializer = MyScaffoldSerializer\n\n    class Performative(Enum):\n        \"\"\"Scaffold Message types.\"\"\"\n\n        def __str__(self) -> str:\n            \"\"\"Get string representation.\"\"\"\n            return str(self.value)  # pragma: no cover\n\n    def __init__(self, performative: Performative, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize.\n\n        :param performative: the type of message.\n        :param kwargs: the keyword arguments.\n        \"\"\"\n        super().__init__(performative=performative, **kwargs)\n        enforce(  # pragma: no cover\n            self._is_consistent(), \"MyScaffoldMessage initialization inconsistent.\"\n        )\n\n    def _is_consistent(self) -> bool:\n        \"\"\"Check that the data is consistent.\"\"\"\n        try:\n            raise NotImplementedError\n        except (AssertionError, ValueError):\n            return False  # pragma: no cover\n\n        return True  # pragma: no cover\n"
  },
  {
    "path": "aea/protocols/scaffold/protocol.yaml",
    "content": "name: scaffold\nauthor: fetchai\nversion: 0.1.0\ntype: protocol\ndescription: The scaffold protocol scaffolds a protocol to be implemented by the developer.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nprotocol_specification_id: fetchai/scaffold:0.1.0\nfingerprint:\n  __init__.py: QmV67bUSsM7YErJJ3WgQb12zumYurryUn5MAJEeo4hJayu\n  message.py: QmYHZFdU9TVJNuXVmUX8Hw6nZ2uWU9SnpjeVBR1Qg8tQrf\n  serialization.py: QmW4HLfpGe4RXeeYZqVsoSoNJghJXVkDqq8TD4p7iqgXmG\nfingerprint_ignore_patterns: []\ndependencies: {}\n"
  },
  {
    "path": "aea/protocols/scaffold/serialization.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Serialization for the scaffold protocol.\"\"\"\n\n\nfrom aea.protocols.base import Message, Serializer\n\n\nclass MyScaffoldSerializer(Serializer):  # pragma: no cover\n    \"\"\"Serialization for the scaffold protocol.\"\"\"\n\n    @staticmethod\n    def encode(msg: Message) -> bytes:\n        \"\"\"\n        Decode the message.\n\n        :param msg: the message object\n        :return: the bytes  # noqa: DAR202\n        \"\"\"\n        raise NotImplementedError  # pragma: no cover\n\n    @staticmethod\n    def decode(obj: bytes) -> Message:\n        \"\"\"\n        Decode the message.\n\n        :param obj: the bytes object\n        :return: the message  # noqa: DAR202\n        \"\"\"\n        raise NotImplementedError  # pragma: no cover\n"
  },
  {
    "path": "aea/py.typed",
    "content": "# Marker file for PEP 561.  The aea package uses inline types.\n"
  },
  {
    "path": "aea/registries/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the registries used by the framework.\"\"\"\n"
  },
  {
    "path": "aea/registries/base.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains registries.\"\"\"\n\nimport copy\nfrom abc import ABC, abstractmethod\nfrom operator import itemgetter\nfrom typing import Any, Dict, Generic, List, Optional, Set, Tuple, TypeVar, cast\n\nfrom aea.components.base import Component\nfrom aea.configurations.base import ComponentId, ComponentType, PublicId\nfrom aea.exceptions import AEASetupError, AEATeardownError, parse_exception\nfrom aea.helpers.logging import WithLogger, get_logger\nfrom aea.skills.base import Behaviour, Handler, Model\n\n\nItem = TypeVar(\"Item\")\nItemId = TypeVar(\"ItemId\")\nSkillComponentType = TypeVar(\"SkillComponentType\", Handler, Behaviour, Model)\n\n\nclass Registry(Generic[ItemId, Item], WithLogger, ABC):\n    \"\"\"This class implements an abstract registry.\"\"\"\n\n    def __init__(self, agent_name: str = \"standalone\") -> None:\n        \"\"\"\n        Initialize the registry.\n\n        :param agent_name: the name of the agent\n        \"\"\"\n        logger = get_logger(__name__, agent_name)\n        super().__init__(logger)\n\n    @abstractmethod\n    def register(\n        self, item_id: ItemId, item: Item, is_dynamically_added: bool = False\n    ) -> None:\n        \"\"\"\n        Register an item.\n\n        :param item_id: the public id of the item.\n        :param item: the item.\n        :param is_dynamically_added: whether or not the item is dynamically added.\n        :return: None\n        :raises: ValueError if an item is already registered with that item id.\n        \"\"\"\n\n    @abstractmethod\n    def unregister(self, item_id: ItemId) -> Optional[Item]:\n        \"\"\"\n        Unregister an item.\n\n        :param item_id: the public id of the item.\n        :return: the item\n        :raises: ValueError if no item registered with that item id.\n        \"\"\"\n\n    @abstractmethod\n    def fetch(self, item_id: ItemId) -> Optional[Item]:\n        \"\"\"\n        Fetch an item.\n\n        :param item_id: the public id of the item.\n        :return: the Item\n        \"\"\"\n\n    @abstractmethod\n    def fetch_all(self) -> List[Item]:\n        \"\"\"\n        Fetch all the items.\n\n        :return: the list of items.\n        \"\"\"\n\n    @abstractmethod\n    def ids(self) -> Set[ItemId]:\n        \"\"\"\n        Return the set of all the used item ids.\n\n        :return: the set of item ids.\n        \"\"\"\n\n    @abstractmethod\n    def setup(self) -> None:\n        \"\"\"\n        Set up registry.\n\n        :return: None\n        \"\"\"\n\n    @abstractmethod\n    def teardown(self) -> None:\n        \"\"\"\n        Teardown the registry.\n\n        :return: None\n        \"\"\"\n\n\nclass PublicIdRegistry(Generic[Item], Registry[PublicId, Item]):\n    \"\"\"\n    This class implement a registry whose keys are public ids.\n\n    In particular, it is able to handle the case when the public id\n    points to the 'latest' version of a package.\n    \"\"\"\n\n    __slots__ = (\"_public_id_to_item\",)\n\n    def __init__(self) -> None:\n        \"\"\"Initialize the registry.\"\"\"\n        super().__init__()\n        self._public_id_to_item: Dict[PublicId, Item] = {}\n\n    def register(  # pylint: disable=arguments-differ,unused-argument,arguments-renamed\n        self, public_id: PublicId, item: Item, is_dynamically_added: bool = False\n    ) -> None:\n        \"\"\"Register an item.\"\"\"\n        if public_id.package_version.is_latest:\n            raise ValueError(\n                f\"Cannot register item with public id 'latest': {public_id}\"\n            )\n        if public_id in self._public_id_to_item:\n            raise ValueError(f\"Item already registered with item id '{public_id}'\")\n        self._public_id_to_item[public_id] = item\n\n    def unregister(  # pylint: disable=arguments-differ,arguments-renamed\n        self, public_id: PublicId\n    ) -> Item:\n        \"\"\"Unregister an item.\"\"\"\n        if public_id not in self._public_id_to_item:\n            raise ValueError(f\"No item registered with item id '{public_id}'\")\n        item = self._public_id_to_item.pop(public_id)\n        return item\n\n    def fetch(  # pylint: disable=arguments-differ,arguments-renamed\n        self, public_id: PublicId\n    ) -> Optional[Item]:\n        \"\"\"\n        Fetch an item associated with a public id.\n\n        :param public_id: the public id.\n        :return: an item, or None if the key is not present.\n        \"\"\"\n        if public_id.package_version.is_latest:\n            filtered_records: List[Tuple[PublicId, Item]] = list(\n                filter(\n                    lambda x: public_id.same_prefix(x[0]),\n                    self._public_id_to_item.items(),\n                )\n            )\n            if len(filtered_records) == 0:\n                return None\n            return max(filtered_records, key=itemgetter(0))[1]\n        return self._public_id_to_item.get(public_id, None)\n\n    def fetch_all(self) -> List[Item]:\n        \"\"\"Fetch all the items.\"\"\"\n        return list(self._public_id_to_item.values())\n\n    def ids(self) -> Set[PublicId]:\n        \"\"\"Get all the item ids.\"\"\"\n        return set(self._public_id_to_item.keys())\n\n    def setup(self) -> None:\n        \"\"\"Set up the items.\"\"\"\n\n    def teardown(self) -> None:\n        \"\"\"Tear down the items.\"\"\"\n\n\nclass AgentComponentRegistry(Registry[ComponentId, Component]):\n    \"\"\"This class implements a simple dictionary-based registry for agent components.\"\"\"\n\n    __slots__ = (\"_components_by_type\", \"_registered_keys\")\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Instantiate the registry.\n\n        :param kwargs: kwargs\n        \"\"\"\n        super().__init__(**kwargs)\n        self._components_by_type: Dict[ComponentType, Dict[PublicId, Component]] = {}\n        self._registered_keys: Set[ComponentId] = set()\n\n    def register(  # pylint: disable=arguments-differ,unused-argument,arguments-renamed\n        self,\n        component_id: ComponentId,\n        component: Component,\n        is_dynamically_added: bool = False,\n    ) -> None:\n        \"\"\"\n        Register a component.\n\n        :param component_id: the id of the component.\n        :param component: the component object.\n        :param is_dynamically_added: whether or not the item is dynamically added.\n        \"\"\"\n        if component_id in self._registered_keys:\n            raise ValueError(\n                \"Component already registered with item id '{}'\".format(component_id)\n            )\n        if component.component_id != component_id:\n            raise ValueError(\n                \"Component id '{}' is different to the id '{}' specified.\".format(\n                    component.component_id, component_id\n                )\n            )\n        self._register(component_id, component)\n\n    def _register(self, component_id: ComponentId, component: Component) -> None:\n        \"\"\"\n        Do the actual registration.\n\n        :param component_id: the component id\n        :param component: the component to register\n        \"\"\"\n        self._components_by_type.setdefault(component_id.component_type, {})[\n            component_id.public_id\n        ] = component\n        self._registered_keys.add(component_id)\n\n    def _unregister(self, component_id: ComponentId) -> Optional[Component]:\n        \"\"\"\n        Do the actual unregistration.\n\n        :param component_id: the component id\n        :return: the item\n        \"\"\"\n        item = self._components_by_type.get(component_id.component_type, {}).pop(\n            component_id.public_id, None\n        )\n        self._registered_keys.discard(component_id)\n        if item is not None:\n            self.logger.debug(\n                \"Component '{}' has been removed.\".format(item.component_id)\n            )\n        return item\n\n    def unregister(  # pylint: disable=arguments-differ,arguments-renamed\n        self, component_id: ComponentId\n    ) -> Optional[Component]:\n        \"\"\"\n        Unregister a component.\n\n        :param component_id: the ComponentId\n        :return: the item\n        \"\"\"\n        if component_id not in self._registered_keys:\n            raise ValueError(\n                \"No item registered with item id '{}'\".format(component_id)\n            )\n        return self._unregister(component_id)\n\n    def fetch(  # pylint: disable=arguments-differ,arguments-renamed\n        self, component_id: ComponentId\n    ) -> Optional[Component]:\n        \"\"\"\n        Fetch the component by id.\n\n        :param component_id: the contract id\n        :return: the component or None if the component is not registered\n        \"\"\"\n        return self._components_by_type.get(component_id.component_type, {}).get(\n            component_id.public_id, None\n        )\n\n    def fetch_all(self) -> List[Component]:\n        \"\"\"\n        Fetch all the components.\n\n        :return: the list of registered components.\n        \"\"\"\n        return [\n            component\n            for components_by_public_id in self._components_by_type.values()\n            for component in components_by_public_id.values()\n        ]\n\n    def fetch_by_type(self, component_type: ComponentType) -> List[Component]:\n        \"\"\"\n        Fetch all the components by a given type..\n\n        :param component_type: a component type\n        :return: the list of registered components of a given type.\n        \"\"\"\n        return list(self._components_by_type.get(component_type, {}).values())\n\n    def ids(self) -> Set[ComponentId]:\n        \"\"\"Get the item ids.\"\"\"\n        return self._registered_keys\n\n    def setup(self) -> None:\n        \"\"\"Set up the registry.\"\"\"\n\n    def teardown(self) -> None:\n        \"\"\"Teardown the registry.\"\"\"\n\n\nclass ComponentRegistry(\n    Registry[Tuple[PublicId, str], SkillComponentType], Generic[SkillComponentType]\n):\n    \"\"\"This class implements a generic registry for skill components.\"\"\"\n\n    __slots__ = (\"_items\", \"_dynamically_added\")\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Instantiate the registry.\n\n        :param kwargs: kwargs\n        \"\"\"\n        super().__init__(**kwargs)\n        self._items: PublicIdRegistry[\n            Dict[str, SkillComponentType]\n        ] = PublicIdRegistry()\n        self._dynamically_added: Dict[PublicId, Set[str]] = {}\n\n    def register(\n        self,\n        item_id: Tuple[PublicId, str],\n        item: SkillComponentType,\n        is_dynamically_added: bool = False,\n    ) -> None:\n        \"\"\"\n        Register a item.\n\n        :param item_id: a pair (skill id, item name).\n        :param item: the item to register.\n        :param is_dynamically_added: whether or not the item is dynamically added.\n        :raises: ValueError if an item is already registered with that item id.\n        \"\"\"\n        skill_id = item_id[0]\n        item_name = item_id[1]\n        skill_items = self._items.fetch(skill_id)\n        if skill_items is not None and item_name in skill_items.keys():\n            raise ValueError(\n                f\"Item already registered with skill id '{skill_id}' and name '{item_name}'\"\n            )\n\n        if skill_items is not None:\n            self._items.unregister(skill_id)\n        else:\n            skill_items = {}\n        skill_items[item_name] = item\n        self._items.register(skill_id, skill_items)\n\n        if is_dynamically_added:\n            self._dynamically_added.setdefault(skill_id, set()).add(item_name)\n\n    def unregister(self, item_id: Tuple[PublicId, str]) -> Optional[SkillComponentType]:\n        \"\"\"\n        Unregister a item.\n\n        :param item_id: a pair (skill id, item name).\n        :return: skill component\n        :raises: ValueError if no item registered with that item id.\n        \"\"\"\n        return self._unregister_from_main_index(item_id)\n\n    def _unregister_from_main_index(\n        self, item_id: Tuple[PublicId, str]\n    ) -> SkillComponentType:\n        \"\"\"\n        Unregister a item.\n\n        :param item_id: a pair (skill id, item name).\n        :return: None\n        :raises: ValueError if no item registered with that item id.\n        \"\"\"\n        skill_id = item_id[0]\n        item_name = item_id[1]\n        name_to_item = self._items.fetch(skill_id)\n        if name_to_item is None or item_name not in name_to_item:\n            raise ValueError(\n                \"No item registered with component id '{}'\".format(item_id)\n            )\n        self.logger.debug(\"Unregistering item with id {}\".format(item_id))\n        item = name_to_item.pop(item_name)\n        if len(name_to_item) == 0:\n            self._items.unregister(skill_id)\n        else:\n            self._items.unregister(skill_id)\n            self._items.register(skill_id, name_to_item)\n\n        items = self._dynamically_added.get(skill_id, None)\n        if items is not None:\n            items.remove(item_name)\n            if len(items) == 0:\n                self._dynamically_added.pop(skill_id, None)\n        return item\n\n    def fetch(self, item_id: Tuple[PublicId, str]) -> Optional[SkillComponentType]:\n        \"\"\"\n        Fetch an item.\n\n        :param item_id: the public id of the item.\n        :return: the Item\n        \"\"\"\n        skill_id = item_id[0]\n        item_name = item_id[1]\n        name_to_item = self._items.fetch(skill_id)\n        if name_to_item is None:\n            return None\n        return name_to_item.get(item_name, None)\n\n    def fetch_by_skill(self, skill_id: PublicId) -> List[SkillComponentType]:\n        \"\"\"Fetch all the items of a given skill.\"\"\"\n        temp: Optional[Dict[str, SkillComponentType]] = self._items.fetch(skill_id)\n        name_to_item: Dict[str, SkillComponentType] = {} if temp is None else temp\n        return list(name_to_item.values())\n\n    def fetch_all(self) -> List[SkillComponentType]:\n        \"\"\"Fetch all the items.\"\"\"\n        return [item for items in self._items.fetch_all() for item in items.values()]\n\n    def unregister_by_skill(self, skill_id: PublicId) -> None:\n        \"\"\"Unregister all the components by skill.\"\"\"\n        if skill_id not in self._items.ids():\n            raise ValueError(\n                \"No component of skill {} present in the registry.\".format(skill_id)\n            )\n        self._items.unregister(skill_id)\n        self._dynamically_added.pop(skill_id, None)\n\n    def ids(self) -> Set[Tuple[PublicId, str]]:\n        \"\"\"Get the item ids.\"\"\"\n        result: Set[Tuple[PublicId, str]] = set()\n        for skill_id in self._items.ids():\n            name_to_item = cast(\n                Dict[str, SkillComponentType], self._items.fetch(skill_id)\n            )\n            for name, _ in name_to_item.items():\n                result.add((skill_id, name))\n        return result\n\n    def setup(self) -> None:\n        \"\"\"Set up the items in the registry.\"\"\"\n        for item in self.fetch_all():\n            if item.context.is_active:\n                self.logger.debug(\n                    \"Calling setup() of component {} of skill {}\".format(\n                        item.name, item.skill_id\n                    )\n                )\n                try:\n                    item.setup()\n                except Exception as e:  # pragma: nocover # pylint: disable=broad-except\n                    e_str = parse_exception(e)\n                    e_str = f\"An error occurred while setting up item {item.skill_id}/{type(item).__name__}:\\n{e_str}\"\n                    raise AEASetupError(e_str)\n            else:\n                self.logger.debug(\n                    \"Ignoring setup() of component {} of skill {}, because the skill is not active.\".format(\n                        item.name, item.skill_id\n                    )\n                )\n\n    def teardown(self) -> None:\n        \"\"\"Teardown the registry.\"\"\"\n        for name_to_items in self._items.fetch_all():\n            for _, item in name_to_items.items():\n                self.logger.debug(\n                    \"Calling teardown() of component {} of skill {}\".format(\n                        item.name, item.skill_id\n                    )\n                )\n                try:\n                    item.teardown()\n                except Exception as e:  # pragma: nocover # pylint: disable=broad-except\n                    e_str = parse_exception(e)\n                    e_str = f\"An error occurred while tearing down item {item.skill_id}/{type(item).__name__}:\\n{str(e_str)}\"\n                    e = AEATeardownError(e_str)\n                    self.logger.error(str(e))\n        _dynamically_added = copy.deepcopy(self._dynamically_added)\n        for skill_id, items_names in _dynamically_added.items():\n            for item_name in items_names:\n                self.unregister((skill_id, item_name))\n\n\nclass HandlerRegistry(ComponentRegistry[Handler]):\n    \"\"\"This class implements the handlers registry.\"\"\"\n\n    __slots__ = (\"_items_by_protocol_and_skill\",)\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Instantiate the registry.\n\n        :param kwargs: kwargs\n        \"\"\"\n        super().__init__(**kwargs)\n        # nested public id registries; one for protocol ids, one for skill ids\n        self._items_by_protocol_and_skill = PublicIdRegistry[\n            PublicIdRegistry[Handler]\n        ]()\n\n    def register(\n        self,\n        item_id: Tuple[PublicId, str],\n        item: Handler,\n        is_dynamically_added: bool = False,\n    ) -> None:\n        \"\"\"\n        Register a handler.\n\n        :param item_id: the item id.\n        :param item: the handler.\n        :param is_dynamically_added: whether or not the item is dynamically added.\n        :raises ValueError: if the protocol is None, or an item with pair (skill_id, protocol_id_ already exists.\n        \"\"\"\n        skill_id = item_id[0]\n\n        protocol_id = item.SUPPORTED_PROTOCOL\n        if protocol_id is None:\n            raise ValueError(\n                \"Please specify a supported protocol for handler class '{}'\".format(\n                    item.__class__.__name__\n                )\n            )\n\n        protocol_handlers_by_skill = self._items_by_protocol_and_skill.fetch(\n            protocol_id\n        )\n        if (\n            protocol_handlers_by_skill is not None\n            and skill_id in protocol_handlers_by_skill.ids()\n        ):\n            raise ValueError(\n                \"A handler already registered with pair of protocol id {} and skill id {}\".format(\n                    protocol_id, skill_id\n                )\n            )\n        if protocol_handlers_by_skill is None:\n            # registry from skill ids to handlers.\n            new_registry: PublicIdRegistry = PublicIdRegistry()\n            self._items_by_protocol_and_skill.register(protocol_id, new_registry)\n        registry = cast(Registry, self._items_by_protocol_and_skill.fetch(protocol_id))\n        registry.register(skill_id, item)\n        super().register(item_id, item, is_dynamically_added=is_dynamically_added)\n\n    def unregister(self, item_id: Tuple[PublicId, str]) -> Handler:\n        \"\"\"\n        Unregister a item.\n\n        :param item_id: a pair (skill id, item name).\n        :return: the unregistered handler\n        :raises: ValueError if no item is registered with that item id.\n        \"\"\"\n        skill_id = item_id[0]\n        handler = super()._unregister_from_main_index(item_id)\n\n        # remove from index by protocol and skill\n        protocol_id = cast(PublicId, handler.SUPPORTED_PROTOCOL)\n        protocol_handlers_by_skill = cast(\n            PublicIdRegistry, self._items_by_protocol_and_skill.fetch(protocol_id)\n        )\n        protocol_handlers_by_skill.unregister(skill_id)\n        if len(protocol_handlers_by_skill.ids()) == 0:\n            self._items_by_protocol_and_skill.unregister(protocol_id)\n        return handler\n\n    def unregister_by_skill(self, skill_id: PublicId) -> None:\n        \"\"\"Unregister all the components by skill.\"\"\"\n        # unregister from the main index.\n        if skill_id not in self._items.ids():\n            raise ValueError(\n                \"No component of skill {} present in the registry.\".format(skill_id)\n            )\n\n        self._dynamically_added.pop(skill_id, None)\n\n        handlers = cast(Dict[str, Handler], self._items.fetch(skill_id)).values()\n        self._items.unregister(skill_id)\n\n        # unregister from the protocol-skill index\n        for handler in handlers:\n            protocol_id = cast(PublicId, handler.SUPPORTED_PROTOCOL)\n            if protocol_id in self._items_by_protocol_and_skill.ids():\n                skill_id_to_handler = cast(\n                    PublicIdRegistry,\n                    self._items_by_protocol_and_skill.fetch(protocol_id),\n                )\n                skill_id_to_handler.unregister(skill_id)\n\n    def fetch_by_protocol(self, protocol_id: PublicId) -> List[Handler]:\n        \"\"\"\n        Fetch the handler by the pair protocol id and skill id.\n\n        :param protocol_id: the protocol id\n        :return: the handlers registered for the protocol_id and skill_id\n        \"\"\"\n        if protocol_id not in self._items_by_protocol_and_skill.ids():\n            return []\n\n        protocol_handlers_by_skill = cast(\n            PublicIdRegistry, self._items_by_protocol_and_skill.fetch(protocol_id)\n        )\n        handlers = [\n            cast(Handler, protocol_handlers_by_skill.fetch(skill_id))\n            for skill_id in protocol_handlers_by_skill.ids()\n        ]\n        return handlers\n\n    def fetch_by_protocol_and_skill(\n        self, protocol_id: PublicId, skill_id: PublicId\n    ) -> Optional[Handler]:\n        \"\"\"\n        Fetch the handler by the pair protocol id and skill id.\n\n        :param protocol_id: the protocol id\n        :param skill_id: the skill id.\n        :return: the handlers registered for the protocol_id and skill_id\n        \"\"\"\n        if protocol_id not in self._items_by_protocol_and_skill.ids():\n            return None\n        protocols_by_skill_id = cast(\n            PublicIdRegistry, self._items_by_protocol_and_skill.fetch(protocol_id)\n        )\n        if skill_id not in protocols_by_skill_id.ids():\n            return None\n        return protocols_by_skill_id.fetch(skill_id)\n"
  },
  {
    "path": "aea/registries/filter.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains registries.\"\"\"\n\nfrom typing import List, Optional\n\nfrom aea.configurations.base import PublicId\nfrom aea.helpers.async_friendly_queue import AsyncFriendlyQueue\nfrom aea.helpers.logging import WithLogger, get_logger\nfrom aea.protocols.base import Message\nfrom aea.registries.resources import Resources\nfrom aea.skills.base import Behaviour, Handler\n\n\nclass Filter(WithLogger):\n    \"\"\"This class implements the filter of an AEA.\"\"\"\n\n    def __init__(\n        self, resources: Resources, decision_maker_out_queue: AsyncFriendlyQueue\n    ) -> None:\n        \"\"\"\n        Instantiate the filter.\n\n        :param resources: the resources\n        :param decision_maker_out_queue: the decision maker queue\n        \"\"\"\n        logger = get_logger(__name__, resources.agent_name)\n        WithLogger.__init__(self, logger=logger)\n        self._resources = resources\n        self._decision_maker_out_queue = decision_maker_out_queue\n\n    @property\n    def resources(self) -> Resources:\n        \"\"\"Get resources.\"\"\"\n        return self._resources\n\n    @property\n    def decision_maker_out_queue(self) -> AsyncFriendlyQueue:\n        \"\"\"Get decision maker (out) queue.\"\"\"\n        return self._decision_maker_out_queue\n\n    def get_active_handlers(\n        self, protocol_id: PublicId, skill_id: Optional[PublicId] = None\n    ) -> List[Handler]:\n        \"\"\"\n        Get active handlers based on protocol id and optional skill id.\n\n        :param protocol_id: the protocol id\n        :param skill_id: the skill id\n        :return: the list of handlers currently active\n        \"\"\"\n        if skill_id is not None:\n            handler = self.resources.get_handler(protocol_id, skill_id)\n            active_handlers = (\n                [] if handler is None or not handler.context.is_active else [handler]\n            )\n        else:\n            handlers = self.resources.get_handlers(protocol_id)\n            active_handlers = list(\n                filter(lambda handler: handler.context.is_active, handlers)\n            )\n        return active_handlers\n\n    def get_active_behaviours(self) -> List[Behaviour]:\n        \"\"\"\n        Get the active behaviours.\n\n        :return: the list of behaviours currently active\n        \"\"\"\n        behaviours = self.resources.get_all_behaviours()\n        active_behaviour = list(\n            filter(lambda b: b.context.is_active and not b.is_done(), behaviours)\n        )\n        return active_behaviour\n\n    def handle_new_handlers_and_behaviours(self) -> None:\n        \"\"\"Handle the messages from the decision maker.\"\"\"\n        self._handle_new_behaviours()\n        self._handle_new_handlers()\n\n    async def get_internal_message(self) -> Optional[Message]:\n        \"\"\"Get a message from decision_maker_out_queue.\"\"\"\n        return await self.decision_maker_out_queue.async_get()\n\n    def handle_internal_message(self, internal_message: Optional[Message]) -> None:\n        \"\"\"Handle internal message.\"\"\"\n        if internal_message is None:\n            self.logger.warning(\"Got 'None' while processing internal messages.\")\n            return\n        self._handle_internal_message(internal_message)\n\n    def _handle_new_behaviours(self) -> None:\n        \"\"\"Register new behaviours added to skills.\"\"\"\n        for skill in self.resources.get_all_skills():\n            while not skill.skill_context.new_behaviours.empty():\n                new_behaviour = skill.skill_context.new_behaviours.get()\n                try:\n                    self.resources.behaviour_registry.register(\n                        (skill.skill_context.skill_id, new_behaviour.name),\n                        new_behaviour,\n                        is_dynamically_added=True,\n                    )\n                except ValueError as e:\n                    self.logger.warning(\n                        \"Error when trying to add a new behaviour: {}\".format(str(e))\n                    )\n\n    def _handle_new_handlers(self) -> None:\n        \"\"\"Register new handlers added to skills.\"\"\"\n        for skill in self.resources.get_all_skills():\n            while not skill.skill_context.new_handlers.empty():\n                new_handler = skill.skill_context.new_handlers.get()\n                try:\n                    self.resources.handler_registry.register(\n                        (skill.skill_context.skill_id, new_handler.name),\n                        new_handler,\n                        is_dynamically_added=True,\n                    )\n                except ValueError as e:\n                    self.logger.warning(\n                        \"Error when trying to add a new handler: {}\".format(str(e))\n                    )\n\n    def _handle_internal_message(self, message: Message) -> None:\n        \"\"\"Handle message from the Decision Maker.\"\"\"\n        try:\n            skill_id = PublicId.from_str(message.to)\n        except ValueError:\n            self.logger.warning(\n                \"Invalid public id as destination={}\".format(message.to)\n            )\n            return\n        handler = self.resources.handler_registry.fetch_by_protocol_and_skill(\n            message.protocol_id,\n            skill_id,\n        )\n        if handler is not None:\n            self.logger.debug(\n                \"Calling handler {} of skill {}\".format(type(handler), skill_id)\n            )\n            handler.handle(message)\n        else:\n            self.logger.warning(\n                \"No internal handler fetched for skill_id={}\".format(skill_id)\n            )\n"
  },
  {
    "path": "aea/registries/resources.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the resources class.\"\"\"\nfrom contextlib import suppress\nfrom typing import Dict, List, Optional, cast\n\nfrom aea.components.base import Component\nfrom aea.configurations.base import ComponentId, ComponentType, PublicId\nfrom aea.connections.base import Connection\nfrom aea.contracts.base import Contract\nfrom aea.protocols.base import Protocol\nfrom aea.registries.base import (\n    AgentComponentRegistry,\n    ComponentRegistry,\n    HandlerRegistry,\n    Registry,\n)\nfrom aea.skills.base import Behaviour, Handler, Model, Skill\n\n\nclass Resources:\n    \"\"\"This class implements the object that holds the resources of an AEA.\"\"\"\n\n    __slots__ = (\n        \"_agent_name\",\n        \"_component_registry\",\n        \"_specification_to_protocol_id\",\n        \"_handler_registry\",\n        \"_behaviour_registry\",\n        \"_model_registry\",\n        \"_registries\",\n    )\n\n    def __init__(self, agent_name: str = \"standalone\") -> None:\n        \"\"\"\n        Instantiate the resources.\n\n        :param agent_name: the name of the agent\n        \"\"\"\n        self._agent_name = agent_name\n        self._component_registry = AgentComponentRegistry(agent_name=agent_name)\n        self._specification_to_protocol_id: Dict[PublicId, PublicId] = {}\n        self._handler_registry = HandlerRegistry(agent_name=agent_name)\n        self._behaviour_registry = ComponentRegistry[Behaviour](agent_name=agent_name)\n        self._model_registry = ComponentRegistry[Model](agent_name=agent_name)\n\n        self._registries = [\n            self._component_registry,\n            self._handler_registry,\n            self._behaviour_registry,\n            self._model_registry,\n        ]  # type: List[Registry]\n\n    @property\n    def agent_name(self) -> str:\n        \"\"\"Get the agent name.\"\"\"\n        return self._agent_name\n\n    @property\n    def component_registry(self) -> AgentComponentRegistry:\n        \"\"\"Get the agent component registry.\"\"\"\n        return self._component_registry\n\n    @property\n    def behaviour_registry(self) -> ComponentRegistry[Behaviour]:\n        \"\"\"Get the behaviour registry.\"\"\"\n        return self._behaviour_registry\n\n    @property\n    def handler_registry(self) -> HandlerRegistry:\n        \"\"\"Get the handler registry.\"\"\"\n        return self._handler_registry\n\n    @property\n    def model_registry(self) -> ComponentRegistry[Model]:\n        \"\"\"Get the model registry.\"\"\"\n        return self._model_registry\n\n    def add_component(self, component: Component) -> None:\n        \"\"\"Add a component to resources.\"\"\"\n        if component.component_type == ComponentType.PROTOCOL:\n            self.add_protocol(cast(Protocol, component))\n        elif component.component_type == ComponentType.SKILL:\n            self.add_skill(cast(Skill, component))\n        elif component.component_type == ComponentType.CONTRACT:\n            self.add_contract(cast(Contract, component))\n        elif component.component_type == ComponentType.CONNECTION:\n            self.add_connection(cast(Connection, component))\n        else:\n            raise ValueError(\n                \"Component type {} not supported.\".format(\n                    component.component_type.value\n                )\n            )\n\n    def add_protocol(self, protocol: Protocol) -> None:\n        \"\"\"\n        Add a protocol to the set of resources.\n\n        :param protocol: a protocol\n        \"\"\"\n        self._component_registry.register(protocol.component_id, protocol)\n        self._specification_to_protocol_id[\n            protocol.protocol_specification_id\n        ] = protocol.public_id\n\n    def get_protocol(self, protocol_id: PublicId) -> Optional[Protocol]:\n        \"\"\"\n        Get protocol for given protocol id.\n\n        :param protocol_id: the protocol id\n        :return: a matching protocol, if present, else None\n        \"\"\"\n        protocol = self._component_registry.fetch(\n            ComponentId(ComponentType.PROTOCOL, protocol_id)\n        )\n        return cast(Protocol, protocol)\n\n    def get_protocol_by_specification_id(\n        self, protocol_specification_id: PublicId\n    ) -> Optional[Protocol]:\n        \"\"\"\n        Get protocol for given protocol_specification_id.\n\n        :param protocol_specification_id: the protocol id\n        :return: a matching protocol, if present, else None\n        \"\"\"\n        protocol_id = self._specification_to_protocol_id.get(\n            protocol_specification_id, None\n        )\n\n        if protocol_id is None:\n            return None\n\n        return self.get_protocol(protocol_id)\n\n    def get_all_protocols(self) -> List[Protocol]:\n        \"\"\"\n        Get the list of all the protocols.\n\n        :return: the list of protocols.\n        \"\"\"\n        protocols = self._component_registry.fetch_by_type(ComponentType.PROTOCOL)\n        return cast(List[Protocol], protocols)\n\n    def remove_protocol(self, protocol_id: PublicId) -> None:\n        \"\"\"\n        Remove a protocol from the set of resources.\n\n        :param protocol_id: the protocol id for the protocol to be removed.\n        \"\"\"\n        protocol = cast(\n            Optional[Protocol],\n            self._component_registry.unregister(\n                ComponentId(ComponentType.PROTOCOL, protocol_id)\n            ),\n        )\n        if protocol is not None:\n            self._specification_to_protocol_id.pop(protocol.protocol_specification_id)\n\n    def add_contract(self, contract: Contract) -> None:\n        \"\"\"\n        Add a contract to the set of resources.\n\n        :param contract: a contract\n        \"\"\"\n        self._component_registry.register(contract.component_id, contract)\n\n    def get_contract(self, contract_id: PublicId) -> Optional[Contract]:\n        \"\"\"\n        Get contract for given contract id.\n\n        :param contract_id: the contract id\n        :return: a matching contract, if present, else None\n        \"\"\"\n        contract = self._component_registry.fetch(\n            ComponentId(ComponentType.CONTRACT, contract_id)\n        )\n        return cast(Contract, contract)\n\n    def get_all_contracts(self) -> List[Contract]:\n        \"\"\"\n        Get the list of all the contracts.\n\n        :return: the list of contracts.\n        \"\"\"\n        contracts = self._component_registry.fetch_by_type(ComponentType.CONTRACT)\n        return cast(List[Contract], contracts)\n\n    def remove_contract(self, contract_id: PublicId) -> None:\n        \"\"\"\n        Remove a contract from the set of resources.\n\n        :param contract_id: the contract id for the contract to be removed.\n        \"\"\"\n        self._component_registry.unregister(\n            ComponentId(ComponentType.CONTRACT, contract_id)\n        )\n\n    def add_connection(self, connection: Connection) -> None:\n        \"\"\"\n        Add a connection to the set of resources.\n\n        :param connection: a connection\n        \"\"\"\n        self._component_registry.register(connection.component_id, connection)\n\n    def get_connection(self, connection_id: PublicId) -> Optional[Connection]:\n        \"\"\"\n        Get connection for given connection id.\n\n        :param connection_id: the connection id\n        :return: a matching connection, if present, else None\n        \"\"\"\n        connection = self._component_registry.fetch(\n            ComponentId(ComponentType.CONNECTION, connection_id)\n        )\n        return cast(Connection, connection)\n\n    def get_all_connections(self) -> List[Connection]:\n        \"\"\"\n        Get the list of all the connections.\n\n        :return: the list of connections.\n        \"\"\"\n        connections = self._component_registry.fetch_by_type(ComponentType.CONNECTION)\n        return cast(List[Connection], connections)\n\n    def remove_connection(self, connection_id: PublicId) -> None:\n        \"\"\"\n        Remove a connection from the set of resources.\n\n        :param connection_id: the connection id for the connection to be removed.\n        \"\"\"\n        self._component_registry.unregister(\n            ComponentId(ComponentType.CONNECTION, connection_id)\n        )\n\n    def add_skill(self, skill: Skill) -> None:\n        \"\"\"\n        Add a skill to the set of resources.\n\n        :param skill: a skill\n        \"\"\"\n        self._component_registry.register(skill.component_id, skill)\n        if skill.handlers is not None:\n            for handler in skill.handlers.values():\n                self._handler_registry.register(\n                    (skill.public_id, handler.name), handler\n                )\n        if skill.behaviours is not None:\n            for behaviour in skill.behaviours.values():\n                self._behaviour_registry.register(\n                    (skill.public_id, behaviour.name), behaviour\n                )\n        if skill.models is not None:\n            for model in skill.models.values():\n                self._model_registry.register((skill.public_id, model.name), model)\n\n    def get_skill(self, skill_id: PublicId) -> Optional[Skill]:\n        \"\"\"\n        Get the skill for a given skill id.\n\n        :param skill_id: the skill id\n        :return: a matching skill, if present, else None\n        \"\"\"\n        skill = self._component_registry.fetch(\n            ComponentId(ComponentType.SKILL, skill_id)\n        )\n        return cast(Skill, skill)\n\n    def get_all_skills(self) -> List[Skill]:\n        \"\"\"\n        Get the list of all the skills.\n\n        :return: the list of skills.\n        \"\"\"\n        skills = self._component_registry.fetch_by_type(ComponentType.SKILL)\n        return cast(List[Skill], skills)\n\n    def remove_skill(self, skill_id: PublicId) -> None:\n        \"\"\"\n        Remove a skill from the set of resources.\n\n        :param skill_id: the skill id for the skill to be removed.\n        \"\"\"\n        self._component_registry.unregister(ComponentId(ComponentType.SKILL, skill_id))\n        with suppress(ValueError):\n            self._handler_registry.unregister_by_skill(skill_id)\n        with suppress(ValueError):\n            self._behaviour_registry.unregister_by_skill(skill_id)\n        with suppress(ValueError):\n            self._model_registry.unregister_by_skill(skill_id)\n\n    def get_handler(\n        self, protocol_id: PublicId, skill_id: PublicId\n    ) -> Optional[Handler]:\n        \"\"\"\n        Get a specific handler.\n\n        :param protocol_id: the protocol id the handler is handling\n        :param skill_id: the skill id of the handler's skill\n        :return: the handler\n        \"\"\"\n        handler = self._handler_registry.fetch_by_protocol_and_skill(\n            protocol_id, skill_id\n        )\n        return handler\n\n    def get_handlers(self, protocol_id: PublicId) -> List[Handler]:\n        \"\"\"\n        Get all handlers for a given protocol.\n\n        :param protocol_id: the protocol id the handler is handling\n        :return: the list of handlers matching the protocol\n        \"\"\"\n        handlers = self._handler_registry.fetch_by_protocol(protocol_id)\n        return handlers\n\n    def get_all_handlers(self) -> List[Handler]:\n        \"\"\"\n        Get all handlers from all skills.\n\n        :return: the list of handlers\n        \"\"\"\n        handlers = self._handler_registry.fetch_all()\n        return handlers\n\n    def get_behaviour(\n        self, skill_id: PublicId, behaviour_name: str\n    ) -> Optional[Behaviour]:\n        \"\"\"\n        Get a specific behaviours for a given skill.\n\n        :param skill_id: the skill id\n        :param behaviour_name: the behaviour name\n        :return: the behaviour, if it is present, else None\n        \"\"\"\n        behaviour = self._behaviour_registry.fetch((skill_id, behaviour_name))\n        return behaviour\n\n    def get_behaviours(self, skill_id: PublicId) -> List[Behaviour]:\n        \"\"\"\n        Get all behaviours for a given skill.\n\n        :param skill_id: the skill id\n        :return: the list of behaviours of the skill\n        \"\"\"\n        behaviours = self._behaviour_registry.fetch_by_skill(\n            skill_id\n        )  # type: List[Behaviour]\n        return behaviours\n\n    def get_all_behaviours(self) -> List[Behaviour]:\n        \"\"\"\n        Get all behaviours from all skills.\n\n        :return: the list of all behaviours\n        \"\"\"\n        behaviours = self._behaviour_registry.fetch_all()\n        return behaviours\n\n    def setup(self) -> None:\n        \"\"\"\n        Set up the resources.\n\n        Calls setup on all resources.\n        \"\"\"\n        for r in self._registries:\n            r.setup()\n\n    def teardown(self) -> None:\n        \"\"\"\n        Teardown the resources.\n\n        Calls teardown on all resources.\n        \"\"\"\n        for r in self._registries:\n            r.teardown()\n"
  },
  {
    "path": "aea/runner.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the implementation of AEA multiple instances runner.\"\"\"\nimport logging\nfrom asyncio.events import AbstractEventLoop\nfrom typing import Dict, Sequence, Type\n\nfrom aea.aea import AEA\nfrom aea.helpers.multiple_executor import (\n    AbstractExecutorTask,\n    AbstractMultipleExecutor,\n    AbstractMultipleRunner,\n    AsyncExecutor,\n    ExecutorExceptionPolicies,\n    TaskAwaitable,\n    ThreadExecutor,\n)\nfrom aea.runtime import AsyncRuntime\n\n\n_default_logger = logging.getLogger(__name__)\n\n\nclass AEAInstanceTask(AbstractExecutorTask):\n    \"\"\"Task to run agent instance.\"\"\"\n\n    def __init__(self, agent: AEA) -> None:\n        \"\"\"\n        Init aea instance task.\n\n        :param agent: AEA instance to run within task.\n        \"\"\"\n        self._agent = agent\n        super().__init__()\n\n    @property\n    def id(self) -> str:\n        \"\"\"Return agent name.\"\"\"\n        return self._agent.name\n\n    def start(self) -> None:  # type: ignore\n        \"\"\"Start task.\"\"\"\n        try:\n            self._agent.start()\n        except BaseException:\n            _default_logger.exception(\"Exceptions raised in runner task.\")\n            raise\n\n    def stop(self) -> None:\n        \"\"\"Stop task.\"\"\"\n        self._agent.runtime.stop()\n\n    def create_async_task(self, loop: AbstractEventLoop) -> TaskAwaitable:\n        \"\"\"\n        Return asyncio Task for task run in asyncio loop.\n\n        :param loop: abstract event loop\n        :return: task to run runtime\n        \"\"\"\n        self._agent.runtime.set_loop(loop)\n        if not isinstance(self._agent.runtime, AsyncRuntime):  # pragma: nocover\n            raise ValueError(\n                \"Agent runtime is not async compatible. Please use runtime_mode=async\"\n            )\n        return loop.create_task(self._agent.runtime.start_and_wait_completed())  # type: ignore\n\n\nclass AEARunner(AbstractMultipleRunner):\n    \"\"\"Run multiple AEA instances.\"\"\"\n\n    SUPPORTED_MODES: Dict[str, Type[AbstractMultipleExecutor]] = {\n        \"threaded\": ThreadExecutor,\n        \"async\": AsyncExecutor,\n    }\n\n    def __init__(\n        self,\n        agents: Sequence[AEA],\n        mode: str,\n        fail_policy: ExecutorExceptionPolicies = ExecutorExceptionPolicies.propagate,\n    ) -> None:\n        \"\"\"\n        Init AEARunner.\n\n        :param agents: sequence of AEA instances to run.\n        :param mode: executor name to use.\n        :param fail_policy: one of ExecutorExceptionPolicies to be used with Executor\n        \"\"\"\n        self._agents = agents\n        super().__init__(mode=mode, fail_policy=fail_policy)\n\n    def _make_tasks(self) -> Sequence[AbstractExecutorTask]:\n        \"\"\"Make tasks to run with executor.\"\"\"\n        return [AEAInstanceTask(agent) for agent in self._agents]\n"
  },
  {
    "path": "aea/runtime.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the implementation of runtime for economic agent (AEA).\"\"\"\nimport asyncio\nfrom asyncio.events import AbstractEventLoop\nfrom concurrent.futures._base import CancelledError\nfrom contextlib import suppress\nfrom enum import Enum\nfrom typing import Dict, Optional, Type, cast\n\nfrom aea.abstract_agent import AbstractAgent\nfrom aea.agent_loop import (\n    AgentLoopStates,\n    AsyncAgentLoop,\n    AsyncState,\n    BaseAgentLoop,\n    SyncAgentLoop,\n)\nfrom aea.connections.base import ConnectionStates\nfrom aea.decision_maker.base import DecisionMaker, DecisionMakerHandler\nfrom aea.exceptions import _StopRuntime\nfrom aea.helpers.async_utils import Runnable\nfrom aea.helpers.exception_policy import ExceptionPolicyEnum\nfrom aea.helpers.logging import WithLogger, get_logger\nfrom aea.helpers.storage.generic_storage import Storage\nfrom aea.multiplexer import AsyncMultiplexer\nfrom aea.skills.tasks import ProcessTaskManager, TaskManager, ThreadedTaskManager\n\n\nclass RuntimeStates(Enum):\n    \"\"\"Runtime states.\"\"\"\n\n    starting = \"starting\"\n    running = \"running\"\n    stopping = \"stopping\"\n    stopped = \"stopped\"\n    error = \"error\"\n\n\nclass BaseRuntime(Runnable, WithLogger):\n    \"\"\"Abstract runtime class to create implementations.\"\"\"\n\n    RUN_LOOPS: Dict[str, Type[BaseAgentLoop]] = {\n        \"async\": AsyncAgentLoop,\n        \"sync\": SyncAgentLoop,\n    }\n    DEFAULT_RUN_LOOP: str = \"async\"\n\n    TASKMANAGERS = {\"threaded\": ThreadedTaskManager, \"multiprocess\": ProcessTaskManager}\n    DEFAULT_TASKMANAGER = \"threaded\"\n\n    def __init__(\n        self,\n        agent: AbstractAgent,\n        multiplexer_options: Dict,\n        loop_mode: Optional[str] = None,\n        loop: Optional[AbstractEventLoop] = None,\n        threaded: bool = False,\n        task_manager_mode: Optional[str] = None,\n    ) -> None:\n        \"\"\"\n        Init runtime.\n\n        :param agent: Agent to run.\n        :param multiplexer_options: options for the multiplexer.\n        :param loop_mode: agent main loop mode.\n        :param loop: optional event loop. if not provided a new one will be created.\n        :param threaded: if True, run in threaded mode, else async\n        :param task_manager_mode: mode of the task manager.\n        \"\"\"\n        Runnable.__init__(self, threaded=threaded, loop=loop if not threaded else None)\n        logger = get_logger(__name__, agent.name)\n        WithLogger.__init__(self, logger=logger)\n        self._agent: AbstractAgent = agent\n        self._state: AsyncState = AsyncState(RuntimeStates.stopped, RuntimeStates)\n        self._state.add_callback(self._log_runtime_state)\n\n        self._multiplexer: AsyncMultiplexer = self._get_multiplexer_instance(\n            multiplexer_options\n        )\n        self._task_manager_mode = task_manager_mode or self.DEFAULT_TASKMANAGER\n        self._task_manager = self._get_taskmanager_instance()\n        self._decision_maker: Optional[DecisionMaker] = None\n        self._storage: Optional[Storage] = self._get_storage(agent)\n\n        self._loop_mode = loop_mode or self.DEFAULT_RUN_LOOP\n        self._agent_loop: BaseAgentLoop = self._get_agent_loop_instance(self._loop_mode)\n\n    def _log_runtime_state(self, state: RuntimeStates) -> None:\n        \"\"\"Log a runtime state changed.\"\"\"\n        self.logger.debug(f\"[{self._agent.name}]: Runtime state changed to {state}.\")\n\n    def _get_taskmanager_instance(self) -> TaskManager:\n        \"\"\"Get taskmanager instance.\"\"\"\n        if self._task_manager_mode not in self.TASKMANAGERS:\n            raise ValueError(  # pragma: nocover\n                f\"Task manager mode `{self._task_manager_mode} is not supported. valid are: `{list(self.TASKMANAGERS.keys())}`\"\n            )\n        cls = self.TASKMANAGERS[self._task_manager_mode]\n        return cls()\n\n    def _get_multiplexer_instance(\n        self, multiplexer_options: Dict, threaded: bool = False\n    ) -> AsyncMultiplexer:\n        \"\"\"Create multiplexer instance.\"\"\"\n        loop: Optional[AbstractEventLoop] = None\n        if not threaded:\n            loop = self.loop\n        return AsyncMultiplexer(\n            loop=loop,\n            threaded=threaded,\n            agent_name=self._agent.name,\n            connections=multiplexer_options[\"connections\"],\n            exception_policy=multiplexer_options.get(\n                \"connection_exception_policy\", ExceptionPolicyEnum.propagate\n            ),\n            default_routing=multiplexer_options.get(\"default_routing\"),\n            default_connection=multiplexer_options.get(\"default_connection\"),\n            protocols=multiplexer_options.get(\"protocols\", []),\n        )\n\n    @staticmethod\n    def _get_storage(agent: AbstractAgent) -> Optional[Storage]:\n        \"\"\"Get storage instance if storage_uri provided.\"\"\"\n        if agent.storage_uri:\n            # threaded has to be always True, cause synchronous operations are supported\n            return Storage(agent.storage_uri, threaded=True)\n        return None  # pragma: nocover\n\n    def _get_agent_loop_instance(self, loop_mode: str) -> BaseAgentLoop:\n        \"\"\"\n        Construct agent loop instance.\n\n        :param: loop_mode: str.\n\n        :return: AgentLoop instance\n        \"\"\"\n        loop_cls = self._get_agent_loop_class(loop_mode)\n        return loop_cls(self._agent)\n\n    def _get_agent_loop_class(self, loop_mode: str) -> Type[BaseAgentLoop]:\n        \"\"\"\n        Get agent loop class based on loop mode.\n\n        :param: loop_mode: str.\n\n        :return: AgentLoop class\n        \"\"\"\n        if loop_mode not in self.RUN_LOOPS:  # pragma: nocover\n            raise ValueError(\n                f\"Loop `{loop_mode} is not supported. valid are: `{list(self.RUN_LOOPS.keys())}`\"\n            )\n        return self.RUN_LOOPS[loop_mode]\n\n    @property\n    def storage(self) -> Optional[Storage]:\n        \"\"\"Get optional storage.\"\"\"\n        return self._storage\n\n    @property\n    def loop_mode(self) -> str:  # pragma: nocover\n        \"\"\"Get current loop mode.\"\"\"\n        return self._loop_mode\n\n    @property\n    def task_manager(self) -> TaskManager:\n        \"\"\"Get the task manager.\"\"\"\n        return self._task_manager\n\n    @property\n    def loop(self) -> Optional[AbstractEventLoop]:\n        \"\"\"Get event loop.\"\"\"\n        return self._loop\n\n    @property\n    def agent_loop(self) -> BaseAgentLoop:\n        \"\"\"Get the agent loop.\"\"\"\n        return self._agent_loop\n\n    @property\n    def multiplexer(self) -> AsyncMultiplexer:\n        \"\"\"Get multiplexer.\"\"\"\n        return self._multiplexer\n\n    @property\n    def is_running(self) -> bool:\n        \"\"\"Get running state of the runtime.\"\"\"\n        return self._state.get() == RuntimeStates.running\n\n    @property\n    def is_stopped(self) -> bool:  # pragma: nocover\n        \"\"\"Get stopped state of the runtime.\"\"\"\n        return self._state.get() in [RuntimeStates.stopped]\n\n    @property\n    def state(self) -> RuntimeStates:  # pragma: nocover\n        \"\"\"\n        Get runtime state.\n\n        :return: RuntimeStates\n        \"\"\"\n        return cast(RuntimeStates, self._state.get())\n\n    @property\n    def decision_maker(self) -> DecisionMaker:\n        \"\"\"Return decision maker if set.\"\"\"\n        if self._decision_maker is None:  # pragma: nocover\n            raise ValueError(\"call `set_decision_maker` first!\")\n        return self._decision_maker\n\n    def _set_task(self) -> None:\n        \"\"\"Set task.\"\"\"\n        if self._loop is None:\n            raise ValueError(\"Loop not set!\")  # pragma: nocover\n\n        self._task = self._loop.create_task(self._run_wrapper())\n\n    def set_decision_maker(self, decision_maker_handler: DecisionMakerHandler) -> None:\n        \"\"\"Set decision maker with handler provided.\"\"\"\n        self._decision_maker = DecisionMaker(\n            decision_maker_handler=decision_maker_handler\n        )\n\n    def _teardown(self) -> None:\n        \"\"\"Tear down runtime.\"\"\"\n        self.logger.debug(\"[{}]: Runtime teardown...\".format(self._agent.name))\n        if self._decision_maker is not None:  # pragma: nocover\n            self.decision_maker.stop()\n        self.task_manager.stop()\n        self.logger.debug(\"[{}]: Calling teardown method...\".format(self._agent.name))\n        self._agent.teardown()\n        self.logger.debug(\"[{}]: Runtime teardown completed\".format(self._agent.name))\n\n    def set_loop(self, loop: AbstractEventLoop) -> None:\n        \"\"\"\n        Set event loop to be used.\n\n        :param loop: event loop to use.\n        \"\"\"\n        self._loop = loop\n        asyncio.set_event_loop(self._loop)\n\n\nclass AsyncRuntime(BaseRuntime):\n    \"\"\"Asynchronous runtime: uses asyncio loop for multiplexer and async agent main loop.\"\"\"\n\n    AGENT_LOOP_STARTED_TIMEOUT: float = 5\n\n    def __init__(\n        self,\n        agent: AbstractAgent,\n        multiplexer_options: Dict,\n        loop_mode: Optional[str] = None,\n        loop: Optional[AbstractEventLoop] = None,\n        threaded: bool = False,\n        task_manager_mode: Optional[str] = None,\n    ) -> None:\n        \"\"\"\n        Init runtime.\n\n        :param agent: Agent to run.\n        :param multiplexer_options: options for the multiplexer.\n        :param loop_mode: agent main loop mode.\n        :param loop: optional event loop. if not provided a new one will be created.\n        :param threaded: if True, run in threaded mode, else async\n        :param task_manager_mode: mode of the task manager.\n        \"\"\"\n        super().__init__(\n            agent=agent,\n            multiplexer_options=multiplexer_options,\n            loop_mode=loop_mode,\n            loop=loop,\n            threaded=threaded,\n            task_manager_mode=task_manager_mode,\n        )\n        self._task: Optional[asyncio.Task] = None\n\n    def set_loop(self, loop: AbstractEventLoop) -> None:\n        \"\"\"\n        Set event loop to be used.\n\n        :param loop: event loop to use.\n        \"\"\"\n        BaseRuntime.set_loop(self, loop)\n\n    async def run(self) -> None:\n        \"\"\"\n        Start runtime task.\n\n        Starts multiplexer and agent loop.\n        \"\"\"\n        terminal_state = RuntimeStates.error\n        try:\n            await self.run_runtime()\n        except _StopRuntime as e:\n            self._state.set(RuntimeStates.stopping)\n            terminal_state = RuntimeStates.stopped\n            if e.reraise:\n                raise e.reraise\n        except (asyncio.CancelledError, CancelledError, KeyboardInterrupt):\n            self._state.set(RuntimeStates.stopping)\n            terminal_state = RuntimeStates.stopped\n        finally:\n            await self.stop_runtime()\n            self._state.set(terminal_state)\n\n    async def stop_runtime(self) -> None:\n        \"\"\"\n        Stop runtime coroutine.\n\n        Stop main loop.\n        Tear down the agent..\n        Disconnect multiplexer.\n        \"\"\"\n        self.agent_loop.stop()\n        with suppress(_StopRuntime):\n            await self.agent_loop.wait_completed()\n        self._teardown()\n\n        if self._storage is not None:\n            self._storage.stop()\n            await self._storage.wait_completed()\n\n        self.multiplexer.stop()\n        await self.multiplexer.wait_completed()\n        self.logger.debug(\"Runtime loop stopped!\")\n\n    async def run_runtime(self) -> None:\n        \"\"\"Run runtime which means start agent loop, multiplexer and storage.\"\"\"\n        self._state.set(RuntimeStates.starting)\n        await asyncio.gather(\n            self._start_multiplexer(), self._start_agent_loop(), self._start_storage()\n        )\n\n    async def _start_storage(self) -> None:\n        \"\"\"Start storage component asynchronously.\"\"\"\n        if self._storage is not None:\n            self._storage.start()\n            await self._storage.wait_completed()\n\n    async def _start_multiplexer(self) -> None:\n        \"\"\"Call multiplexer connect asynchronous way.\"\"\"\n        if not self._loop:  # pragma: nocover\n            raise ValueError(\"no loop is set for runtime.\")\n\n        self.multiplexer.set_loop(self._loop)\n        self.multiplexer.start()\n        await self.multiplexer.wait_completed()\n\n    async def _start_agent_loop(self) -> None:\n        \"\"\"Start agent main loop asynchronous way.\"\"\"\n        self.logger.debug(\"[{}] Runtime started\".format(self._agent.name))\n\n        await self.multiplexer.connection_status.wait(ConnectionStates.connected)\n        self.logger.debug(\"[{}] Multiplexer connected.\".format(self._agent.name))\n        if self.storage:\n            await self.storage.wait_connected()\n            self.logger.debug(\"[{}] Storage connected.\".format(self._agent.name))\n\n        self.task_manager.start()\n        if self._decision_maker is not None:  # pragma: nocover\n            self.decision_maker.start()\n        self.logger.debug(\"[{}] Calling setup method...\".format(self._agent.name))\n        self._agent.setup()\n        self.logger.debug(\"[{}] Run main loop...\".format(self._agent.name))\n\n        self.agent_loop.start()\n\n        await asyncio.wait_for(\n            self.agent_loop.wait_state(AgentLoopStates.started),\n            timeout=self.AGENT_LOOP_STARTED_TIMEOUT,\n        )\n\n        self._state.set(RuntimeStates.running)\n        try:\n            await self.agent_loop.wait_completed()\n        except asyncio.CancelledError:\n            self.agent_loop.stop()\n            await self.agent_loop.wait_completed()\n            raise\n\n\nclass ThreadedRuntime(AsyncRuntime):\n    \"\"\"Run agent and multiplexer in different threads with own asyncio loops.\"\"\"\n\n    def _get_multiplexer_instance(\n        self, multiplexer_options: Dict, threaded: bool = True\n    ) -> AsyncMultiplexer:\n        \"\"\"Create multiplexer instance.\"\"\"\n        return super()._get_multiplexer_instance(\n            multiplexer_options=multiplexer_options, threaded=threaded\n        )\n"
  },
  {
    "path": "aea/skills/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the skills supported by the framework.\"\"\"\n"
  },
  {
    "path": "aea/skills/base.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the base classes for the skills.\"\"\"\nimport datetime\nimport inspect\nimport logging\nimport queue\nimport re\nimport types\nfrom abc import ABC, abstractmethod\nfrom copy import copy\nfrom logging import Logger\nfrom pathlib import Path\nfrom queue import Queue\nfrom types import SimpleNamespace\nfrom typing import Any, Dict, List, Optional, Set, Tuple, Type, Union, cast\n\nfrom aea.common import Address\nfrom aea.components.base import Component, load_aea_package\nfrom aea.configurations.base import (\n    ComponentType,\n    PublicId,\n    SkillComponentConfiguration,\n    SkillConfig,\n)\nfrom aea.configurations.loader import load_component_configuration\nfrom aea.context.base import AgentContext\nfrom aea.exceptions import (\n    AEAActException,\n    AEAComponentLoadException,\n    AEAHandleException,\n    AEAInstantiationException,\n    _StopRuntime,\n    enforce,\n    parse_exception,\n)\nfrom aea.helpers.base import _get_aea_logger_name_prefix, load_module\nfrom aea.helpers.logging import AgentLoggerAdapter\nfrom aea.helpers.storage.generic_storage import Storage\nfrom aea.mail.base import Envelope, EnvelopeContext\nfrom aea.multiplexer import MultiplexerStatus, OutBox\nfrom aea.protocols.base import Message\nfrom aea.skills.tasks import TaskManager\n\n\n_default_logger = logging.getLogger(__name__)\n\n\nclass SkillContext:\n    \"\"\"This class implements the context of a skill.\"\"\"\n\n    def __init__(\n        self,\n        agent_context: Optional[AgentContext] = None,\n        skill: Optional[\"Skill\"] = None,\n    ) -> None:\n        \"\"\"\n        Initialize a skill context.\n\n        :param agent_context: the agent context.\n        :param skill: the skill.\n        \"\"\"\n        self._agent_context = agent_context  # type: Optional[AgentContext]\n        self._in_queue = Queue()  # type: Queue\n        self._skill = skill  # type: Optional[Skill]\n\n        self._is_active = True  # type: bool\n        self._new_behaviours_queue = queue.Queue()  # type: Queue\n        self._new_handlers_queue = queue.Queue()  # type: Queue\n        self._logger: Optional[Logger] = None\n\n    @property\n    def logger(self) -> Logger:\n        \"\"\"Get the logger.\"\"\"\n        if self._logger is None:\n            return _default_logger\n        return self._logger\n\n    @logger.setter\n    def logger(self, logger_: Logger) -> None:\n        \"\"\"Set the logger.\"\"\"\n        self._logger = logger_\n\n    def _get_agent_context(self) -> AgentContext:\n        \"\"\"Get the agent context.\"\"\"\n        if self._agent_context is None:  # pragma: nocover\n            raise ValueError(\"Agent context not set yet.\")\n        return self._agent_context\n\n    def set_agent_context(self, agent_context: AgentContext) -> None:\n        \"\"\"Set the agent context.\"\"\"\n        self._agent_context = agent_context\n\n    @property\n    def shared_state(self) -> Dict[str, Any]:\n        \"\"\"Get the shared state dictionary.\"\"\"\n        return self._get_agent_context().shared_state\n\n    @property\n    def agent_name(self) -> str:\n        \"\"\"Get agent name.\"\"\"\n        return self._get_agent_context().agent_name\n\n    @property\n    def skill_id(self) -> PublicId:\n        \"\"\"Get the skill id of the skill context.\"\"\"\n        if self._skill is None:\n            raise ValueError(\"Skill not set yet.\")  # pragma: nocover\n        return self._skill.configuration.public_id\n\n    @property\n    def is_active(self) -> bool:\n        \"\"\"Get the status of the skill (active/not active).\"\"\"\n        return self._is_active\n\n    @is_active.setter\n    def is_active(self, value: bool) -> None:\n        \"\"\"Set the status of the skill (active/not active).\"\"\"\n        self._is_active = value\n        self.logger.debug(\n            \"New status of skill {}: is_active={}\".format(\n                self.skill_id, self._is_active\n            )\n        )\n\n    @property\n    def new_behaviours(self) -> \"Queue[Behaviour]\":\n        \"\"\"\n        Queue for the new behaviours.\n\n        This queue can be used to send messages to the framework\n        to request the registration of a behaviour.\n\n        :return: the queue of new behaviours.\n        \"\"\"\n        return self._new_behaviours_queue\n\n    @property\n    def new_handlers(self) -> \"Queue[Handler]\":\n        \"\"\"\n        Queue for the new handlers.\n\n        This queue can be used to send messages to the framework\n        to request the registration of a handler.\n\n        :return: the queue of new handlers.\n        \"\"\"\n        return self._new_handlers_queue\n\n    @property\n    def agent_addresses(self) -> Dict[str, str]:\n        \"\"\"Get addresses.\"\"\"\n        return self._get_agent_context().addresses\n\n    @property\n    def agent_address(self) -> str:\n        \"\"\"Get address.\"\"\"\n        return self._get_agent_context().address\n\n    @property\n    def public_key(self) -> str:\n        \"\"\"Get public key.\"\"\"\n        return self._get_agent_context().public_key\n\n    @property\n    def public_keys(self) -> Dict[str, str]:\n        \"\"\"Get public keys.\"\"\"\n        return self._get_agent_context().public_keys\n\n    @property\n    def connection_status(self) -> MultiplexerStatus:\n        \"\"\"Get connection status.\"\"\"\n        return self._get_agent_context().connection_status\n\n    @property\n    def outbox(self) -> OutBox:\n        \"\"\"Get outbox.\"\"\"\n        return self._get_agent_context().outbox\n\n    @property\n    def storage(self) -> Optional[Storage]:\n        \"\"\"Get optional storage for agent.\"\"\"\n        return self._get_agent_context().storage\n\n    @property\n    def message_in_queue(self) -> Queue:\n        \"\"\"Get message in queue.\"\"\"\n        return self._in_queue\n\n    @property\n    def decision_maker_message_queue(self) -> Queue:\n        \"\"\"Get message queue of decision maker.\"\"\"\n        return self._get_agent_context().decision_maker_message_queue\n\n    @property\n    def decision_maker_handler_context(self) -> SimpleNamespace:\n        \"\"\"Get decision maker handler context.\"\"\"\n        return cast(\n            SimpleNamespace, self._get_agent_context().decision_maker_handler_context\n        )\n\n    @property\n    def task_manager(self) -> TaskManager:\n        \"\"\"Get behaviours of the skill.\"\"\"\n        if self._skill is None:\n            raise ValueError(\"Skill not initialized.\")\n        return self._get_agent_context().task_manager\n\n    @property\n    def default_ledger_id(self) -> str:\n        \"\"\"Get the default ledger id.\"\"\"\n        return self._get_agent_context().default_ledger_id\n\n    @property\n    def currency_denominations(self) -> Dict[str, str]:\n        \"\"\"Get a dictionary mapping ledger ids to currency denominations.\"\"\"\n        return self._get_agent_context().currency_denominations\n\n    @property\n    def search_service_address(self) -> Address:\n        \"\"\"Get the address of the search service.\"\"\"\n        return self._get_agent_context().search_service_address\n\n    @property\n    def decision_maker_address(self) -> Address:\n        \"\"\"Get the address of the decision maker.\"\"\"\n        return self._get_agent_context().decision_maker_address\n\n    @property\n    def handlers(self) -> SimpleNamespace:\n        \"\"\"Get handlers of the skill.\"\"\"\n        if self._skill is None:\n            raise ValueError(\"Skill not initialized.\")\n        return SimpleNamespace(**self._skill.handlers)\n\n    @property\n    def behaviours(self) -> SimpleNamespace:\n        \"\"\"Get behaviours of the skill.\"\"\"\n        if self._skill is None:\n            raise ValueError(\"Skill not initialized.\")\n        return SimpleNamespace(**self._skill.behaviours)\n\n    @property\n    def namespace(self) -> SimpleNamespace:\n        \"\"\"Get the agent context namespace.\"\"\"\n        return self._get_agent_context().namespace\n\n    def __getattr__(self, item: Any) -> Any:\n        \"\"\"Get attribute.\"\"\"\n        return super().__getattribute__(item)  # pragma: no cover\n\n    def send_to_skill(\n        self,\n        message_or_envelope: Union[Message, Envelope],\n        context: Optional[EnvelopeContext] = None,\n    ) -> None:\n        \"\"\"\n        Send message or envelope to another skill.\n\n        If message passed it will be wrapped into envelope with optional envelope context.\n\n        :param message_or_envelope: envelope to send to another skill.\n        :param context: the optional envelope context\n        \"\"\"\n        if self._agent_context is None:  # pragma: nocover\n            raise ValueError(\"agent context was not set!\")\n        self._agent_context.send_to_skill(message_or_envelope, context)\n\n\nclass SkillComponent(ABC):\n    \"\"\"This class defines an abstract interface for skill component classes.\"\"\"\n\n    def __init__(\n        self,\n        name: str,\n        skill_context: SkillContext,\n        configuration: Optional[SkillComponentConfiguration] = None,\n        **kwargs: Any,\n    ) -> None:\n        \"\"\"\n        Initialize a skill component.\n\n        :param name: the name of the component.\n        :param configuration: the configuration for the component.\n        :param skill_context: the skill context.\n        :param kwargs: the keyword arguments.\n        \"\"\"\n        if name is None:\n            raise ValueError(\"SkillComponent name is not provided.\")\n        if skill_context is None:\n            raise ValueError(\"SkillConext is not provided\")\n        if configuration is None:\n            class_name = type(self).__name__\n            configuration = SkillComponentConfiguration(class_name=class_name, **kwargs)\n        self._configuration = configuration\n        self._name = name\n        self._context = skill_context\n        if len(kwargs) != 0:\n            self.context.logger.warning(\n                \"The kwargs={} passed to {} have not been set!\".format(kwargs, name)\n            )\n\n    @property\n    def name(self) -> str:\n        \"\"\"Get the name of the skill component.\"\"\"\n        return self._name\n\n    @property\n    def context(self) -> SkillContext:\n        \"\"\"Get the context of the skill component.\"\"\"\n        return self._context\n\n    @property\n    def skill_id(self) -> PublicId:\n        \"\"\"Get the skill id of the skill component.\"\"\"\n        return self.context.skill_id\n\n    @property\n    def configuration(self) -> SkillComponentConfiguration:\n        \"\"\"Get the skill component configuration.\"\"\"\n        if self._configuration is None:\n            raise ValueError(\"Configuration not set.\")  # pragma: nocover\n        return self._configuration\n\n    @property\n    def config(self) -> Dict[Any, Any]:\n        \"\"\"Get the config of the skill component.\"\"\"\n        return self.configuration.args\n\n    @abstractmethod\n    def setup(self) -> None:\n        \"\"\"Implement the setup.\"\"\"\n        super_obj = super()\n        if hasattr(super_obj, \"setup\"):\n            super_obj.setup()  # type: ignore  # pylint: disable=no-member\n\n    @abstractmethod\n    def teardown(self) -> None:\n        \"\"\"Implement the teardown.\"\"\"\n        super_obj = super()\n        if hasattr(super_obj, \"teardown\"):\n            super_obj.teardown()  # type: ignore  # pylint: disable=no-member\n\n    @classmethod\n    @abstractmethod\n    def parse_module(\n        cls,\n        path: str,\n        configs: Dict[str, SkillComponentConfiguration],\n        skill_context: SkillContext,\n    ) -> dict:\n        \"\"\"Parse the component module.\"\"\"\n\n\nclass AbstractBehaviour(SkillComponent, ABC):\n    \"\"\"\n    Abstract behaviour for periodical calls.\n\n    tick_interval: float, interval to call behaviour's act.\n    start_at: optional datetime, when to start periodical calls.\n    \"\"\"\n\n    _tick_interval: float = 0.001\n    _start_at: Optional[datetime.datetime] = None\n\n    @property\n    def tick_interval(self) -> float:\n        \"\"\"Get the tick_interval in seconds.\"\"\"\n        return self._tick_interval\n\n    @property\n    def start_at(self) -> Optional[datetime.datetime]:\n        \"\"\"Get the start time of the behaviour.\"\"\"\n        return self._start_at\n\n\nclass Behaviour(AbstractBehaviour, ABC):\n    \"\"\"\n    This class implements an abstract behaviour.\n\n    In a subclass of Behaviour, the flag 'is_programmatically_defined'\n     can be used by the developer to signal to the framework that the class\n     is meant to be used programmatically; hence, in case the class is\n     not declared in the configuration file but it is present in a skill\n     module, the framework will just ignore this class instead of printing\n     a warning message.\n    \"\"\"\n\n    is_programmatically_defined: bool = False\n\n    @abstractmethod\n    def act(self) -> None:\n        \"\"\"\n        Implement the behaviour.\n\n        :return: None\n        \"\"\"\n\n    def is_done(self) -> bool:\n        \"\"\"Return True if the behaviour is terminated, False otherwise.\"\"\"\n        return False\n\n    def act_wrapper(self) -> None:\n        \"\"\"Wrap the call of the action. This method must be called only by the framework.\"\"\"\n        try:\n            self.act()\n        except _StopRuntime:\n            raise\n        except Exception as e:  # pylint: disable=broad-except\n            e_str = parse_exception(e)\n            raise AEAActException(\n                f\"An error occurred during act of behaviour {self.context.skill_id}/{type(self).__name__}:\\n{e_str}\"\n            )\n\n    @classmethod\n    def parse_module(  # pylint: disable=arguments-differ,arguments-renamed\n        cls,\n        path: str,\n        behaviour_configs: Dict[str, SkillComponentConfiguration],\n        skill_context: SkillContext,\n    ) -> Dict[str, \"Behaviour\"]:\n        \"\"\"\n        Parse the behaviours module.\n\n        :param path: path to the Python module containing the Behaviour classes.\n        :param behaviour_configs: a list of behaviour configurations.\n        :param skill_context: the skill context\n        :return: a list of Behaviour.\n        \"\"\"\n        return _parse_module(path, behaviour_configs, skill_context, Behaviour)\n\n\nclass Handler(SkillComponent, ABC):\n    \"\"\"\n    This class implements an abstract behaviour.\n\n    In a subclass of Handler, the flag 'is_programmatically_defined'\n     can be used by the developer to signal to the framework that the component\n     is meant to be used programmatically; hence, in case the class is\n     not declared in the configuration file but it is present in a skill\n     module, the framework will just ignore this class instead of printing\n     a warning message.\n\n    SUPPORTED_PROTOCOL is read by the framework when the handlers are loaded\n     to register them as 'listeners' to the protocol identified by the specified\n     public id. Whenever a message of protocol 'SUPPORTED_PROTOCOL' is sent\n     to the agent, the framework will call the 'handle' method.\n    \"\"\"\n\n    SUPPORTED_PROTOCOL: Optional[PublicId] = None\n    is_programmatically_defined: bool = False\n\n    @abstractmethod\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to a message.\n\n        :param message: the message\n        :return: None\n        \"\"\"\n\n    def handle_wrapper(self, message: Message) -> None:\n        \"\"\"Wrap the call of the handler. This method must be called only by the framework.\"\"\"\n        try:\n            self.handle(message)\n        except _StopRuntime:\n            raise\n        except Exception as e:  # pylint: disable=broad-except\n            e_str = parse_exception(e)\n            raise AEAHandleException(\n                f\"An error occurred during handle of handler {self.context.skill_id}/{type(self).__name__}:\\n{e_str}\"\n            )\n\n    @classmethod\n    def parse_module(  # pylint: disable=arguments-differ,arguments-renamed\n        cls,\n        path: str,\n        handler_configs: Dict[str, SkillComponentConfiguration],\n        skill_context: SkillContext,\n    ) -> Dict[str, \"Handler\"]:\n        \"\"\"\n        Parse the handler module.\n\n        :param path: path to the Python module containing the Handler class.\n        :param handler_configs: the list of handler configurations.\n        :param skill_context: the skill context\n        :return: an handler, or None if the parsing fails.\n        \"\"\"\n        return _parse_module(path, handler_configs, skill_context, Handler)\n\n\nclass Model(SkillComponent, ABC):\n    \"\"\"This class implements an abstract model.\"\"\"\n\n    def __init__(\n        self,\n        name: str,\n        skill_context: SkillContext,\n        configuration: Optional[SkillComponentConfiguration] = None,\n        keep_terminal_state_dialogues: Optional[bool] = None,\n        **kwargs: Any,\n    ) -> None:\n        \"\"\"\n        Initialize a model.\n\n        :param name: the name of the component.\n        :param configuration: the configuration for the component.\n        :param skill_context: the skill context.\n        :param keep_terminal_state_dialogues: specify do dialogues in terminal state should stay or not\n        :param kwargs: the keyword arguments.\n        \"\"\"\n        super().__init__(name, skill_context, configuration=configuration, **kwargs)\n\n        # used by dialogues if mixed with the Model\n        if keep_terminal_state_dialogues is not None:\n            self._keep_terminal_state_dialogues = keep_terminal_state_dialogues\n\n    def setup(self) -> None:\n        \"\"\"Set the class up.\"\"\"\n        super_obj = super()\n        if hasattr(super_obj, \"setup\"):\n            super_obj.setup()  # type: ignore  # pylint: disable=no-member\n\n    def teardown(self) -> None:\n        \"\"\"Tear the class down.\"\"\"\n        super_obj = super()\n        if hasattr(super_obj, \"teardown\"):\n            super_obj.teardown()  # type: ignore  # pylint: disable=no-member\n\n    @classmethod\n    def parse_module(  # pylint: disable=arguments-differ,arguments-renamed\n        cls,\n        path: str,\n        model_configs: Dict[str, SkillComponentConfiguration],\n        skill_context: SkillContext,\n    ) -> Dict[str, \"Model\"]:\n        \"\"\"\n        Parse the model module.\n\n        :param path: path to the Python skill module.\n        :param model_configs: a list of model configurations.\n        :param skill_context: the skill context\n        :return: a list of Model.\n        \"\"\"\n        return _parse_module(path, model_configs, skill_context, Model)\n\n\nclass Skill(Component):\n    \"\"\"This class implements a skill.\"\"\"\n\n    __slots__ = (\"_skill_context\", \"_handlers\", \"_behaviours\", \"_models\")\n\n    def __init__(\n        self,\n        configuration: SkillConfig,\n        skill_context: Optional[SkillContext] = None,\n        handlers: Optional[Dict[str, Handler]] = None,\n        behaviours: Optional[Dict[str, Behaviour]] = None,\n        models: Optional[Dict[str, Model]] = None,\n        **kwargs: Any,\n    ):\n        \"\"\"\n        Initialize a skill.\n\n        :param configuration: the skill configuration.\n        :param skill_context: the skill context.\n        :param handlers: dictionary of handlers.\n        :param behaviours: dictionary of behaviours.\n        :param models: dictionary of models.\n        :param kwargs: the keyword arguments.\n        \"\"\"\n        if kwargs is not None:\n            pass\n        super().__init__(configuration)\n        self._skill_context = (\n            skill_context if skill_context is not None else SkillContext()\n        )\n        self._handlers = (\n            {} if handlers is None else handlers\n        )  # type: Dict[str, Handler]\n        self._behaviours = (\n            {} if behaviours is None else behaviours\n        )  # type: Dict[str, Behaviour]\n        self._models = {} if models is None else models  # type: Dict[str, Model]\n\n        self._skill_context._skill = self\n        self._set_models_on_context()\n\n    def _set_models_on_context(self) -> None:\n        \"\"\"Set the models on the skill context.\"\"\"\n        if self._models != {}:\n            for model_id, model_instance in self._models.items():\n                if getattr(self._skill_context, model_id, None) is None:\n                    setattr(self._skill_context, model_id, model_instance)\n\n    @property\n    def skill_context(self) -> SkillContext:\n        \"\"\"Get the skill context.\"\"\"\n        if self._skill_context is None:\n            raise ValueError(\"Skill context not set.\")  # pragma: nocover\n        return self._skill_context\n\n    @property\n    def handlers(self) -> Dict[str, Handler]:\n        \"\"\"Get the handlers.\"\"\"\n        return self._handlers\n\n    @property\n    def behaviours(self) -> Dict[str, Behaviour]:\n        \"\"\"Get the handlers.\"\"\"\n        return self._behaviours\n\n    @property\n    def models(self) -> Dict[str, Model]:\n        \"\"\"Get the handlers.\"\"\"\n        return self._models\n\n    @classmethod\n    def from_dir(\n        cls, directory: str, agent_context: AgentContext, **kwargs: Any\n    ) -> \"Skill\":\n        \"\"\"\n        Load the skill from a directory.\n\n        :param directory: the directory to the skill package.\n        :param agent_context: the skill context.\n        :param kwargs: the keyword arguments.\n        :return: the skill object.\n        \"\"\"\n        configuration = cast(\n            SkillConfig,\n            load_component_configuration(ComponentType.SKILL, Path(directory)),\n        )\n        configuration.directory = Path(directory)\n        return Skill.from_config(configuration, agent_context, **kwargs)\n\n    @property\n    def logger(self) -> Logger:\n        \"\"\"\n        Get the logger.\n\n        In the case of a skill, return the\n        logger provided by the skill context.\n\n        :return: the logger\n        \"\"\"\n        return self.skill_context.logger\n\n    @logger.setter\n    def logger(self, *args: str) -> None:\n        \"\"\"Set the logger.\"\"\"\n        raise ValueError(\"Cannot set logger to a skill component.\")\n\n    @classmethod\n    def from_config(\n        cls, configuration: SkillConfig, agent_context: AgentContext, **kwargs: Any\n    ) -> \"Skill\":\n        \"\"\"\n        Load the skill from configuration.\n\n        :param configuration: a skill configuration. Must be associated with a directory.\n        :param agent_context: the agent context.\n        :param kwargs: the keyword arguments.\n        :return: the skill.\n        \"\"\"\n\n        if configuration.directory is None:  # pragma: nocover\n            raise ValueError(\"Configuration must be associated with a directory.\")\n\n        # we put the initialization here because some skill components\n        # might need some info from the skill\n        # (e.g. see https://github.com/fetchai/agents-aea/issues/1095)\n        skill_context = SkillContext()\n        skill_context.set_agent_context(agent_context)\n        logger_name = f\"aea.packages.{configuration.author}.skills.{configuration.name}\"\n        logger_name = _get_aea_logger_name_prefix(logger_name, agent_context.agent_name)\n        _logger = AgentLoggerAdapter(\n            logging.getLogger(logger_name), agent_context.agent_name\n        )\n        skill_context.logger = cast(Logger, _logger)\n\n        skill_component_loader = _SkillComponentLoader(\n            configuration, skill_context, **kwargs\n        )\n        skill = skill_component_loader.load_skill()\n        return skill\n\n\ndef _parse_module(\n    path: str,\n    component_configs: Dict[str, SkillComponentConfiguration],\n    skill_context: SkillContext,\n    component_class: Type,\n) -> Dict[str, Any]:\n    \"\"\"\n    Parse a module to find skill component classes, and instantiate them.\n\n    This is a private framework function,\n     used in SkillComponentClass.parse_module.\n\n    :param path: path to the Python module.\n    :param component_configs: the component configurations.\n    :param skill_context: the skill context.\n    :param component_class: the class of the skill components to be loaded.\n    :return: A mapping from skill component name to the skill component instance.\n    \"\"\"\n    components: Dict[str, Any] = {}\n    component_type_name = component_class.__name__.lower()\n    component_type_name_plural = component_type_name + \"s\"\n    if component_configs == {}:\n        return components\n    component_names = set(config.class_name for _, config in component_configs.items())\n    component_module = load_module(component_type_name_plural, Path(path))\n    classes = inspect.getmembers(component_module, inspect.isclass)\n    component_classes = list(\n        filter(\n            lambda x: any(re.match(component, x[0]) for component in component_names)\n            and issubclass(x[1], component_class)\n            and not str.startswith(x[1].__module__, \"aea.\")\n            and not str.startswith(\n                x[1].__module__,\n                f\"packages.{skill_context.skill_id.author}.skills.{skill_context.skill_id.name}\",\n            ),\n            classes,\n        )\n    )\n\n    name_to_class = dict(component_classes)\n    _print_warning_message_for_non_declared_skill_components(\n        skill_context,\n        set(name_to_class.keys()),\n        {\n            component_config.class_name\n            for component_config in component_configs.values()\n        },\n        component_type_name_plural,\n        path,\n    )\n    for component_id, component_config in component_configs.items():\n        component_class_name = cast(str, component_config.class_name)\n        skill_context.logger.debug(\n            f\"Processing {component_type_name} {component_class_name}\"\n        )\n        if not component_id.isidentifier():\n            raise AEAComponentLoadException(  # pragma: nocover\n                f\"'{component_id}' is not a valid identifier.\"\n            )\n        component_class = name_to_class.get(component_class_name, None)\n        if component_class is None:\n            skill_context.logger.warning(\n                f\"{component_type_name.capitalize()} '{component_class_name}' cannot be found.\"\n            )\n        else:\n            try:\n                component = component_class(\n                    name=component_id,\n                    configuration=component_config,\n                    skill_context=skill_context,\n                    **dict(component_config.args),\n                )\n            except Exception as e:  # pylint: disable=broad-except # pragma: nocover\n                e_str = parse_exception(e)\n                raise AEAInstantiationException(\n                    f\"An error occurred during instantiation of component {skill_context.skill_id}/{component_config.class_name}:\\n{e_str}\"\n                )\n            components[component_id] = component\n\n    return components\n\n\ndef _print_warning_message_for_non_declared_skill_components(\n    skill_context: SkillContext,\n    classes: Set[str],\n    config_components: Set[str],\n    item_type: str,\n    module_path: str,\n) -> None:\n    \"\"\"Print a warning message if a skill component is not declared in the config files.\"\"\"\n    for class_name in classes.difference(config_components):\n        skill_context.logger.warning(\n            \"Class {} of type {} found in skill module {} but not declared in the configuration file.\".format(\n                class_name, item_type, module_path\n            )\n        )\n\n\n_SKILL_COMPONENT_TYPES = Type[Union[Handler, Behaviour, Model]]\n\n_ComponentsHelperIndex = Dict[_SKILL_COMPONENT_TYPES, Dict[str, SkillComponent]]\n\"\"\"\nHelper index to store component instances.\n\"\"\"\n\n\nclass _SkillComponentLoadingItem:  # pylint: disable=too-few-public-methods\n    \"\"\"Class to represent a triple (component name, component configuration, component class).\"\"\"\n\n    def __init__(\n        self,\n        name: str,\n        config: SkillComponentConfiguration,\n        class_: Type[SkillComponent],\n        type_: _SKILL_COMPONENT_TYPES,\n    ):\n        \"\"\"Initialize the item.\"\"\"\n        self.name = name\n        self.config = config\n        self.class_ = class_\n        self.type_ = type_\n\n\nclass _SkillComponentLoader:\n    \"\"\"This class implements the loading policy for skill components.\"\"\"\n\n    def __init__(\n        self, configuration: SkillConfig, skill_context: SkillContext, **kwargs: Any\n    ):\n        \"\"\"Initialize the helper class.\"\"\"\n        enforce(\n            configuration.directory is not None,\n            \"Configuration not associated to directory.\",\n        )\n        self.configuration = configuration\n        self.skill_directory = cast(Path, configuration.directory)\n        self.skill_context = skill_context\n        self.kwargs = kwargs\n\n        self.skill = Skill(self.configuration, self.skill_context, **self.kwargs)\n        self.skill_dotted_path = f\"packages.{self.configuration.public_id.author}.skills.{self.configuration.public_id.name}\"\n\n    def load_skill(self) -> Skill:\n        \"\"\"Load the skill.\"\"\"\n        load_aea_package(self.configuration)\n        python_modules: Set[Path] = self._get_python_modules()\n        declared_component_classes: Dict[\n            _SKILL_COMPONENT_TYPES, Dict[str, SkillComponentConfiguration]\n        ] = self._get_declared_skill_component_configurations()\n        component_classes_by_path: Dict[\n            Path, Set[Tuple[str, Type[SkillComponent]]]\n        ] = self._load_component_classes(python_modules)\n        component_loading_items = self._match_class_and_configurations(\n            component_classes_by_path, declared_component_classes\n        )\n        components = self._get_component_instances(component_loading_items)\n        self._update_skill(components)\n        return self.skill\n\n    def _update_skill(self, components: _ComponentsHelperIndex) -> None:\n        self.skill.handlers.update(\n            cast(Dict[str, Handler], components.get(Handler, {}))\n        )\n        self.skill.behaviours.update(\n            cast(Dict[str, Behaviour], components.get(Behaviour, {}))\n        )\n        self.skill.models.update(cast(Dict[str, Model], components.get(Model, {})))\n        self.skill._set_models_on_context()  # pylint: disable=protected-access\n\n    def _get_python_modules(self) -> Set[Path]:\n        \"\"\"\n        Get all the Python modules of the skill package.\n\n        We ignore '__pycache__' Python modules as they are not relevant.\n\n        :return: a set of paths pointing to all the Python modules in the skill.\n        \"\"\"\n        ignore_regex = \"__pycache__*\"\n        all_python_modules = self.skill_directory.rglob(\"*.py\")\n        module_paths: Set[Path] = set(\n            map(\n                lambda p: Path(p).relative_to(self.skill_directory),\n                filter(\n                    lambda x: not re.match(ignore_regex, x.name), all_python_modules\n                ),\n            )\n        )\n        return module_paths\n\n    @classmethod\n    def _compute_module_dotted_path(cls, module_path: Path) -> str:\n        \"\"\"Compute the dotted path for a skill module.\"\"\"\n        suffix = \".\".join(module_path.with_name(module_path.stem).parts)\n        return suffix\n\n    def _filter_classes(\n        self, classes: List[Tuple[str, Type]]\n    ) -> List[Tuple[str, Type[SkillComponent]]]:\n        \"\"\"\n        Filter classes of skill components.\n\n        The following filters are applied:\n        - the class must be a subclass of \"SkillComponent\";\n        - its __module__ attribute must not start with 'aea.' (we exclude classes provided by the framework)\n        - its __module__ attribute starts with the expected dotted path of this skill.\n            In particular, it should not be imported from another skill.\n\n        :param classes: a list of pairs (class name, class object)\n        :return: a list of the same kind, but filtered with only skill component classes.\n        \"\"\"\n        filtered_classes = filter(\n            lambda name_and_class: issubclass(name_and_class[1], SkillComponent)\n            # the following condition filters out classes imported from 'aea'\n            and not str.startswith(name_and_class[1].__module__, \"aea.\")\n            # the following condition filters out classes imported\n            # from other skills\n            and not str.startswith(\n                name_and_class[1].__module__, self.skill_dotted_path + \".\"\n            ),\n            classes,\n        )\n        classes = list(filtered_classes)\n        return cast(List[Tuple[str, Type[SkillComponent]]], classes)\n\n    def _load_component_classes(\n        self, module_paths: Set[Path]\n    ) -> Dict[Path, Set[Tuple[str, Type[SkillComponent]]]]:\n        \"\"\"\n        Load component classes from Python modules.\n\n        :param module_paths: a set of paths to Python modules.\n        :return: a mapping from path to skill component classes in that module (containing potential duplicates). Skill components in one path are\n        \"\"\"\n        module_to_classes: Dict[Path, Set[Tuple[str, Type[SkillComponent]]]] = {}\n        for module_path in module_paths:\n            self.skill_context.logger.debug(f\"Trying to load module {module_path}\")\n            module_dotted_path: str = self._compute_module_dotted_path(module_path)\n            component_module: types.ModuleType = load_module(\n                module_dotted_path, self.skill_directory / module_path\n            )\n            classes: List[Tuple[str, Type]] = inspect.getmembers(\n                component_module, inspect.isclass\n            )\n            filtered_classes: List[\n                Tuple[str, Type[SkillComponent]]\n            ] = self._filter_classes(classes)\n            module_to_classes[module_path] = set(filtered_classes)\n        return module_to_classes\n\n    def _get_declared_skill_component_configurations(\n        self,\n    ) -> Dict[_SKILL_COMPONENT_TYPES, Dict[str, SkillComponentConfiguration]]:\n        \"\"\"\n        Get all the declared skill component configurations.\n\n        :return: dictionary of declared skill component configurations\n        \"\"\"\n        handlers_by_id = dict(self.configuration.handlers.read_all())\n        behaviours_by_id = dict(self.configuration.behaviours.read_all())\n        models_by_id = dict(self.configuration.models.read_all())\n\n        result: Dict[\n            _SKILL_COMPONENT_TYPES, Dict[str, SkillComponentConfiguration]\n        ] = {}\n        for component_type, components_by_id in [\n            (Handler, handlers_by_id),\n            (Behaviour, behaviours_by_id),\n            (Model, models_by_id),\n        ]:\n            for component_id, component_config in components_by_id.items():\n                result.setdefault(component_type, {})[component_id] = component_config  # type: ignore\n        return result\n\n    def _get_component_instances(\n        self,\n        component_loading_items: List[_SkillComponentLoadingItem],\n    ) -> _ComponentsHelperIndex:\n        \"\"\"\n        Instantiate classes declared in configuration files.\n\n        :param component_loading_items: a list of loading items.\n        :return: the instances of the skill components.\n        \"\"\"\n        result: _ComponentsHelperIndex = {}\n        for item in component_loading_items:\n            instance = item.class_(\n                name=item.name,\n                configuration=item.config,\n                skill_context=self.skill_context,\n                **item.config.args,\n            )\n            result.setdefault(item.type_, {})[item.name] = instance\n        return result\n\n    @classmethod\n    def _get_skill_component_type(\n        cls,\n        skill_component_type: Type[SkillComponent],\n    ) -> Type[Union[Handler, Behaviour, Model]]:\n        \"\"\"Get the concrete skill component type.\"\"\"\n        parent_skill_component_types = list(\n            filter(\n                lambda class_: class_ in (Handler, Behaviour, Model),\n                skill_component_type.__mro__,\n            )\n        )\n        enforce(\n            len(parent_skill_component_types) == 1,\n            f\"Class {skill_component_type.__name__} in module {skill_component_type.__module__} is not allowed to inherit from more than one skill component type. Found: {parent_skill_component_types}.\",\n        )\n        return cast(\n            Type[Union[Handler, Behaviour, Model]], parent_skill_component_types[0]\n        )\n\n    def _match_class_and_configurations(\n        self,\n        component_classes_by_path: Dict[Path, Set[Tuple[str, Type[SkillComponent]]]],\n        declared_component_classes: Dict[\n            _SKILL_COMPONENT_TYPES, Dict[str, SkillComponentConfiguration]\n        ],\n    ) -> List[_SkillComponentLoadingItem]:\n        \"\"\"\n        Match skill component classes to their configurations.\n\n        Given a class of a skill component, we can disambiguate it in three ways:\n        - by its name\n        - by its type (one of 'Handler', 'Behaviour', 'Model')\n        - whether the user has set the 'file_path' field.\n        If one of the skill component cannot be disambiguated, we raise error.\n\n        In this function, the above criteria are applied in that order.\n\n        :param component_classes_by_path: the component classes by path\n        :param declared_component_classes: the declared component classes\n        :return: list of skill component loading items\n        \"\"\"\n        result: List[_SkillComponentLoadingItem] = []\n\n        class_index: Dict[\n            str, Dict[_SKILL_COMPONENT_TYPES, Set[Type[SkillComponent]]]\n        ] = {}\n        used_classes: Set[Type[SkillComponent]] = set()\n        not_resolved_configurations: Dict[\n            Tuple[_SKILL_COMPONENT_TYPES, str], SkillComponentConfiguration\n        ] = {}\n\n        # populate indexes\n        for _path, component_classes in component_classes_by_path.items():\n            for (component_classname, _component_class) in component_classes:\n                type_ = self._get_skill_component_type(_component_class)\n                class_index.setdefault(component_classname, {}).setdefault(\n                    type_, set()\n                ).add(_component_class)\n\n        for component_type, by_id in declared_component_classes.items():\n            for component_id, component_config in by_id.items():\n                path = component_config.file_path\n                class_name = component_config.class_name\n                if path is not None:\n                    classes_in_path = component_classes_by_path[path]\n                    component_class_or_none: Optional[Type[SkillComponent]] = next(\n                        (\n                            actual_class\n                            for actual_class_name, actual_class in classes_in_path\n                            if actual_class_name == class_name\n                        ),\n                        None,\n                    )\n                    enforce(\n                        component_class_or_none is not None,\n                        self._get_error_message_prefix()\n                        + f\"Cannot find class '{class_name}' for component '{component_id}' of type '{self._type_to_str(component_type)}' of skill '{self.configuration.public_id}' in module {path}\",\n                    )\n                    component_class = cast(\n                        Type[SkillComponent], component_class_or_none\n                    )\n                    actual_component_type = self._get_skill_component_type(\n                        component_class\n                    )\n                    enforce(\n                        actual_component_type == component_type,\n                        self._get_error_message_prefix()\n                        + f\"Found class '{class_name}' for component '{component_id}' of type '{self._type_to_str(component_type)}' of skill '{self.configuration.public_id}' in module {path}, but the expected type was {self._type_to_str(component_type)}, found {self._type_to_str(actual_component_type)} \",\n                    )\n                    used_classes.add(component_class)\n                    result.append(\n                        _SkillComponentLoadingItem(\n                            component_id,\n                            component_config,\n                            component_class,\n                            component_type,\n                        )\n                    )\n                else:\n                    # process the configuration at the end of the loop\n                    not_resolved_configurations[\n                        (component_type, component_id)\n                    ] = component_config\n\n        for (component_type, component_id), component_config in copy(\n            not_resolved_configurations\n        ).items():\n            class_name = component_config.class_name\n            classes_by_type = class_index.get(class_name, {})\n            enforce(\n                class_name in class_index and component_type in classes_by_type,\n                self._get_error_message_prefix()\n                + f\"Cannot find class '{class_name}' for skill component '{component_id}' of type '{self._type_to_str(component_type)}'\",\n            )\n            classes = classes_by_type[component_type]\n            not_used_classes = classes.difference(used_classes)\n            enforce(\n                not_used_classes != 0,\n                f\"Cannot find class of skill '{self.configuration.public_id}' for component configuration '{component_id}' of type '{self._type_to_str(component_type)}'.\",\n            )\n            enforce(\n                len(not_used_classes) == 1,\n                self._get_error_message_ambiguous_classes(\n                    class_name, not_used_classes, component_type, component_id\n                ),\n            )\n            not_used_class = list(not_used_classes)[0]\n            result.append(\n                _SkillComponentLoadingItem(\n                    component_id, component_config, not_used_class, component_type\n                )\n            )\n            used_classes.add(not_used_class)\n\n        self._print_warning_message_for_unused_classes(\n            component_classes_by_path, used_classes\n        )\n        return result\n\n    def _print_warning_message_for_unused_classes(\n        self,\n        component_classes_by_path: Dict[Path, Set[Tuple[str, Type[SkillComponent]]]],\n        used_classes: Set[Type[SkillComponent]],\n    ) -> None:\n        \"\"\"\n        Print warning message for every unused class.\n\n        :param component_classes_by_path: the component classes by path.\n        :param used_classes: the classes used.\n        \"\"\"\n        for path, set_of_class_name_pairs in component_classes_by_path.items():\n            # take only classes, not class names\n            set_of_classes = {pair[1] for pair in set_of_class_name_pairs}\n            set_of_unused_classes = set(\n                filter(lambda x: x not in used_classes, set_of_classes)\n            )\n            # filter out classes that are from other packages\n            set_of_unused_classes = set(\n                filter(\n                    lambda x: not str.startswith(x.__module__, \"packages.\"),\n                    set_of_unused_classes,\n                )\n            )\n\n            if len(set_of_unused_classes) == 0:\n                # all classes in the module are used!\n                continue\n\n            # for each unused class, print a warning message. However,\n            # if it is a Handler or a Behaviour, print the message\n            # only if 'is_programmatically_defined' is not True\n            for unused_class in set_of_unused_classes:\n                component_type_class = self._get_skill_component_type(unused_class)\n                if (\n                    issubclass(unused_class, (Handler, Behaviour))\n                    and cast(\n                        Union[Handler, Behaviour], unused_class\n                    ).is_programmatically_defined\n                ):\n                    continue\n                _print_warning_message_for_non_declared_skill_components(\n                    self.skill_context,\n                    {unused_class.__name__},\n                    set(),\n                    self._type_to_str(component_type_class),\n                    str(path),\n                )\n\n    @classmethod\n    def _type_to_str(cls, component_type: _SKILL_COMPONENT_TYPES) -> str:\n        \"\"\"Get the string of a component type.\"\"\"\n        return component_type.__name__.lower()\n\n    def _get_error_message_prefix(self) -> str:\n        \"\"\"Get error message prefix.\"\"\"\n        return f\"Error while loading skill '{self.configuration.public_id}': \"\n\n    def _get_error_message_ambiguous_classes(\n        self,\n        class_name: str,\n        not_used_classes: Set,\n        component_type: _SKILL_COMPONENT_TYPES,\n        component_id: str,\n    ) -> str:\n        return f\"{self._get_error_message_prefix()}found many classes with name '{class_name}' for component '{component_id}' of type '{self._type_to_str(component_type)}' in the following modules: {', '.join([c.__module__ for c in not_used_classes])}\"\n"
  },
  {
    "path": "aea/skills/behaviours.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the classes for specific behaviours.\"\"\"\nimport datetime\nfrom abc import ABC, abstractmethod\nfrom typing import Any, Callable, Dict, List, Optional, Set\n\nfrom aea.exceptions import enforce\nfrom aea.skills.base import Behaviour\n\n\nclass SimpleBehaviour(Behaviour, ABC):\n    \"\"\"This class implements a simple behaviour.\"\"\"\n\n    def __init__(self, act: Optional[Callable[[], None]] = None, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize a simple behaviour.\n\n        :param act: the act callable.\n        :param kwargs: the keyword arguments to be passed to the parent class.\n        \"\"\"\n        super().__init__(**kwargs)\n        if act is not None:\n            self.act = act  # type: ignore\n\n    def setup(self) -> None:\n        \"\"\"Set the behaviour up.\"\"\"\n\n    def act(self) -> None:\n        \"\"\"Do the action.\"\"\"\n        raise NotImplementedError  # pragma: no cover\n\n    def teardown(self) -> None:\n        \"\"\"Tear the behaviour down.\"\"\"\n\n\nclass CompositeBehaviour(Behaviour, ABC):\n    \"\"\"This class implements a composite behaviour.\"\"\"\n\n\nclass CyclicBehaviour(SimpleBehaviour, ABC):\n    \"\"\"This behaviour is executed until the agent is stopped.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"Initialize the cyclic behaviour.\"\"\"\n        super().__init__(**kwargs)\n        self._number_of_executions = 0\n\n    @property\n    def number_of_executions(self) -> int:\n        \"\"\"Get the number of executions.\"\"\"\n        return self._number_of_executions\n\n    def act_wrapper(self) -> None:\n        \"\"\"Wrap the call of the action. This method must be called only by the framework.\"\"\"\n        if not self.is_done():\n            super().act_wrapper()\n            self._number_of_executions += 1\n\n    def is_done(self) -> bool:\n        \"\"\"\n        Return True if the behaviour is terminated, False otherwise.\n\n        The user should implement it properly to determine the stopping condition.\n        :return: bool indicating status\n        \"\"\"\n        return False\n\n\nclass OneShotBehaviour(SimpleBehaviour, ABC):\n    \"\"\"This behaviour is executed only once.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"Initialize the cyclic behaviour.\"\"\"\n        super().__init__(**kwargs)\n        self._already_executed = False  # type\n\n    def is_done(self) -> bool:\n        \"\"\"Return True if the behaviour is terminated, False otherwise.\"\"\"\n        return self._already_executed\n\n    def act_wrapper(self) -> None:\n        \"\"\"Wrap the call of the action. This method must be called only by the framework.\"\"\"\n        if not self._already_executed:\n            super().act_wrapper()\n            self._already_executed = True\n\n\nclass TickerBehaviour(SimpleBehaviour, ABC):\n    \"\"\"This behaviour is executed periodically with an interval.\"\"\"\n\n    def __init__(\n        self,\n        tick_interval: float = 1.0,\n        start_at: Optional[datetime.datetime] = None,\n        **kwargs: Any,\n    ) -> None:\n        \"\"\"\n        Initialize the ticker behaviour.\n\n        :param tick_interval: interval of the behaviour in seconds.\n        :param start_at: whether to start the behaviour with an offset.\n        :param kwargs: the keyword arguments.\n        \"\"\"\n        super().__init__(**kwargs)\n\n        self._tick_interval = tick_interval\n        self._start_at = (\n            start_at if start_at is not None else datetime.datetime.now()\n        )  # type: datetime.datetime\n        # note, we set _last_act_time to be in the past so the ticker starts immediately\n        self._last_act_time = datetime.datetime.now() - datetime.timedelta(\n            seconds=tick_interval\n        )\n\n    @property\n    def tick_interval(self) -> float:\n        \"\"\"Get the tick_interval in seconds.\"\"\"\n        return self._tick_interval\n\n    @property\n    def start_at(self) -> datetime.datetime:\n        \"\"\"Get the start time.\"\"\"\n        return self._start_at\n\n    @property\n    def last_act_time(self) -> datetime.datetime:\n        \"\"\"Get the last time the act method has been called.\"\"\"\n        return self._start_at\n\n    def act_wrapper(self) -> None:\n        \"\"\"Wrap the call of the action. This method must be called only by the framework.\"\"\"\n        if not self.is_done() and self.is_time_to_act():\n            self._last_act_time = datetime.datetime.now()\n            super().act_wrapper()\n\n    def is_time_to_act(self) -> bool:\n        \"\"\"\n        Check whether it is time to act, according to the tick_interval constraint and the 'start at' constraint.\n\n        :return: True if it is time to act, false otherwise.\n        \"\"\"\n        now = datetime.datetime.now()\n        return (\n            now > self._start_at\n            and (now - self._last_act_time).total_seconds() > self.tick_interval\n        )\n\n\nclass SequenceBehaviour(CompositeBehaviour, ABC):\n    \"\"\"This behaviour executes sub-behaviour serially.\"\"\"\n\n    def __init__(self, behaviour_sequence: List[Behaviour], **kwargs: Any) -> None:\n        \"\"\"\n        Initialize the sequence behaviour.\n\n        :param behaviour_sequence: the sequence of behaviour.\n        :param kwargs: the keyword arguments\n        \"\"\"\n        super().__init__(**kwargs)\n\n        self._behaviour_sequence = behaviour_sequence\n        enforce(len(self._behaviour_sequence) > 0, \"at least one behaviour.\")\n        self._index = 0\n\n    @property\n    def current_behaviour(self) -> Optional[Behaviour]:\n        \"\"\"\n        Get the current behaviour.\n\n        If None, the sequence behaviour can be considered done.\n\n        :return: current behaviour or None\n        \"\"\"\n        return (\n            None\n            if self._index >= len(self._behaviour_sequence)\n            else self._behaviour_sequence[self._index]\n        )\n\n    def _increase_index_if_possible(self) -> None:\n        if self._index < len(self._behaviour_sequence):\n            self._index += 1\n\n    def act(self) -> None:\n        \"\"\"Implement the behaviour.\"\"\"\n        while (\n            not self.is_done()\n            and self.current_behaviour is not None\n            and self.current_behaviour.is_done()\n        ):\n            self._increase_index_if_possible()\n\n        if (\n            not self.is_done()\n            and self.current_behaviour is not None\n            and not self.current_behaviour.is_done()\n        ):\n            self.current_behaviour.act_wrapper()\n\n    def is_done(self) -> bool:\n        \"\"\"Return True if the behaviour is terminated, False otherwise.\"\"\"\n        return self._index >= len(self._behaviour_sequence)\n\n\nclass State(SimpleBehaviour, ABC):\n    \"\"\"\n    A state of a FSMBehaviour.\n\n    A State behaviour is a simple behaviour with a\n    special property 'event' that is opportunely set\n    by the implementer. The event is read by the framework\n    when the behaviour is done in order to pick the\n    transition to trigger.\n    \"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"Initialize a state of the state machine.\"\"\"\n        super().__init__(**kwargs)\n        self._event = None  # type: Optional[str]\n\n    @property\n    def event(self) -> Optional[str]:\n        \"\"\"Get the event to be triggered at the end of the behaviour.\"\"\"\n        return self._event\n\n    @abstractmethod\n    def is_done(self) -> bool:\n        \"\"\"Return True if the behaviour is terminated, False otherwise.\"\"\"\n        raise NotImplementedError  # pragma: no cover\n\n    def reset(self) -> None:\n        \"\"\"Reset initial conditions.\"\"\"\n\n\nclass FSMBehaviour(CompositeBehaviour, ABC):\n    \"\"\"This class implements a finite-state machine behaviour.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"Initialize the finite-state machine behaviour.\"\"\"\n        super().__init__(**kwargs)\n\n        self._name_to_state = {}  # type: Dict[str, State]\n        self._initial_state = None  # type: Optional[str]\n        self._final_states = set()  # type: Set[str]\n        self.current = None  # type: Optional[str]\n\n        # mapping from state to mappings event-next_state\n        self.transitions = {}  # type: Dict[str, Dict[Optional[str], str]]\n\n    @property\n    def is_started(self) -> bool:\n        \"\"\"Check if the behaviour is started.\"\"\"\n        return self._initial_state is not None\n\n    def register_state(self, name: str, state: State, initial: bool = False) -> None:\n        \"\"\"\n        Register a state.\n\n        :param name: the name of the state.\n        :param state: the behaviour in that state.\n        :param initial: whether the state is an initial state.\n        :raises ValueError: if a state with the provided name already exists.\n        \"\"\"\n        if name in self._name_to_state:\n            raise ValueError(\"State name already existing.\")\n        self._name_to_state[name] = state\n        if initial:\n            self._initial_state = name\n            self.current = self._initial_state\n\n    def register_final_state(self, name: str, state: State) -> None:\n        \"\"\"\n        Register a final state.\n\n        :param name: the name of the state.\n        :param state: the state.\n        :raises ValueError: if a state with the provided name already exists.\n        \"\"\"\n        if name in self._name_to_state:\n            raise ValueError(\"State name already existing.\")\n        self._name_to_state[name] = state\n        self._final_states.add(name)\n\n    def unregister_state(self, name: str) -> None:\n        \"\"\"\n        Unregister a state.\n\n        :param name: the state name to unregister.\n        :raises ValueError: if the state is not registered.\n        \"\"\"\n        if name not in self._name_to_state:\n            raise ValueError(\"State name not registered.\")\n        # remove state from mapping\n        self._name_to_state.pop(name)\n        # if it is an initial state, reset it to None.\n        if name == self._initial_state:\n            self._initial_state = None\n        # if it is a final state, remove from the final state set.\n        if name in self._final_states:\n            self._final_states.remove(name)\n\n    @property\n    def states(self) -> Set[str]:\n        \"\"\"Get all the state names.\"\"\"\n        return set(self._name_to_state.keys())\n\n    @property\n    def initial_state(self) -> Optional[str]:\n        \"\"\"Get the initial state name.\"\"\"\n        return self._initial_state\n\n    @initial_state.setter\n    def initial_state(self, name: str) -> None:\n        \"\"\"Set the initial state.\"\"\"\n        if name not in self._name_to_state:\n            raise ValueError(\"Name is not registered as state.\")\n        self._initial_state = name\n        self.current = self._initial_state\n\n    @property\n    def final_states(self) -> Set[str]:\n        \"\"\"Get the final state names.\"\"\"\n        return self._final_states\n\n    def get_state(self, name: str) -> Optional[State]:\n        \"\"\"Get a state from its name.\"\"\"\n        return self._name_to_state.get(name, None)\n\n    def act(self) -> None:\n        \"\"\"Implement the behaviour.\"\"\"\n        if self.current is None:\n            return\n\n        current_state = self.get_state(self.current)\n        if current_state is None:\n            return\n        current_state.act_wrapper()\n\n        if current_state.is_done():\n            if current_state in self._final_states:\n                # we reached a final state - return.\n                self.current = None\n                return\n            event = current_state.event\n            next_state = self.transitions.get(self.current, {}).get(event, None)\n            self.current = next_state\n\n    def is_done(self) -> bool:\n        \"\"\"Return True if the behaviour is terminated, False otherwise.\"\"\"\n        return self.current is None\n\n    def register_transition(\n        self, source: str, destination: str, event: Optional[str] = None\n    ) -> None:\n        \"\"\"\n        Register a transition.\n\n        No sanity check is done.\n\n        :param source: the source state name.\n        :param destination: the destination state name.\n        :param event: the event.\n        :raises ValueError: if a transition from source with event is already present.\n        \"\"\"\n        if source in self.transitions and event in self.transitions.get(source, {}):\n            raise ValueError(\"Transition already registered.\")\n\n        self.transitions.setdefault(source, {})[event] = destination\n\n    def unregister_transition(\n        self, source: str, destination: str, event: Optional[str] = None\n    ) -> None:\n        \"\"\"\n        Unregister a transition.\n\n        :param source: the source state name.\n        :param destination: the destination state name.\n        :param event: the event.\n        :raises ValueError: if a transition from source with event is not present.\n        \"\"\"\n        if (\n            source not in self.transitions.keys()\n            or event not in self.transitions[source].keys()\n            or self.transitions[source][event] != destination\n        ):\n            raise ValueError(\"Transaction not registered.\")\n\n        self.transitions.get(source, {}).pop(event, None)\n        if len(self.transitions[source]) == 0:\n            self.transitions.pop(source, None)\n"
  },
  {
    "path": "aea/skills/scaffold/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the implementation of the default skill.\"\"\"\n\nfrom aea.configurations.base import PublicId\n\n\nPUBLIC_ID = PublicId.from_str(\"fetchai/scaffold:0.1.0\")\n"
  },
  {
    "path": "aea/skills/scaffold/behaviours.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains a scaffold of a behaviour.\"\"\"\n\nfrom aea.skills.base import Behaviour\n\n\nclass MyScaffoldBehaviour(Behaviour):\n    \"\"\"This class scaffolds a behaviour.\"\"\"\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup.\"\"\"\n        raise NotImplementedError\n\n    def act(self) -> None:\n        \"\"\"Implement the act.\"\"\"\n        raise NotImplementedError\n\n    def teardown(self) -> None:\n        \"\"\"Implement the task teardown.\"\"\"\n        raise NotImplementedError\n"
  },
  {
    "path": "aea/skills/scaffold/handlers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains a scaffold of a handler.\"\"\"\n\nfrom typing import Optional\n\nfrom aea.configurations.base import PublicId\nfrom aea.protocols.base import Message\nfrom aea.skills.base import Handler\n\n\nclass MyScaffoldHandler(Handler):\n    \"\"\"This class scaffolds a handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = None  # type: Optional[PublicId]\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup.\"\"\"\n        raise NotImplementedError\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to an envelope.\n\n        :param message: the message\n        \"\"\"\n        raise NotImplementedError\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n        raise NotImplementedError\n"
  },
  {
    "path": "aea/skills/scaffold/my_model.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains a scaffold of a model.\"\"\"\n\nfrom aea.skills.base import Model\n\n\nclass MyModel(Model):\n    \"\"\"This class scaffolds a model.\"\"\"\n"
  },
  {
    "path": "aea/skills/scaffold/skill.yaml",
    "content": "name: scaffold\nauthor: fetchai\nversion: 0.1.0\ntype: skill\ndescription: The scaffold skill is a scaffold for your own skill implementation.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  __init__.py: QmcZ7oz5k3TiyMAxHsGCXP5UGQA9FCqcXuBFYqEmwP7Kym\n  behaviours.py: QmTHQWGuBgc8YjVVLzqnFwVUZNmSsYUqMCRB2K8MJULkR5\n  handlers.py: QmSjtqfb5KB9afc3WDgC9V8C8vw1u8DpupKU6WYHTURUej\n  my_model.py: QmbHTbagGPb3EFfBs4wLNbA7BiY7r2qtxYiq4WpVSYXbFf\nfingerprint_ignore_patterns: []\nconnections: []\ncontracts: []\nprotocols: []\nskills: []\nbehaviours:\n  scaffold:\n    args:\n      foo: bar\n    class_name: MyScaffoldBehaviour\nhandlers:\n  scaffold:\n    args:\n      foo: bar\n    class_name: MyScaffoldHandler\nmodels:\n  scaffold:\n    args:\n      foo: bar\n    class_name: MyModel\ndependencies: {}\nis_abstract: false\n"
  },
  {
    "path": "aea/skills/tasks.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the classes for tasks.\"\"\"\nimport logging\nimport signal\nimport threading\nfrom abc import abstractmethod\nfrom multiprocessing.pool import AsyncResult, Pool, ThreadPool\nfrom typing import Any, Callable, Dict, List, Optional, Sequence, Type, cast\n\nfrom aea.components.utils import _enlist_component_packages, _populate_packages\nfrom aea.helpers.logging import WithLogger\n\n\nTHREAD_POOL_MODE = \"multithread\"\nPROCESS_POOL_MODE = \"multiprocess\"\nDEFAULT_WORKERS_AMOUNT = 2\n\n\nclass Task(WithLogger):\n    \"\"\"This class implements an abstract task.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"Initialize a task.\"\"\"\n        super().__init__(**kwargs)\n        self._is_executed = False\n        # this is where we store the result.\n        self._result = None\n        self.config = kwargs\n\n    def __call__(self, *args: Any, **kwargs: Any) -> Any:\n        \"\"\"\n        Execute the task.\n\n        :param args: positional arguments forwarded to the 'execute' method.\n        :param kwargs: keyword arguments forwarded to the 'execute' method.\n        :return: the task instance\n        :raises ValueError: if the task has already been executed.\n        \"\"\"\n        if self._is_executed:\n            raise ValueError(\"Task already executed.\")\n\n        self.setup()\n        try:\n            self._result = self.execute(*args, **kwargs)\n        except Exception as e:  # pylint: disable=broad-except\n            self.logger.debug(\n                \"Got exception of type {} with message '{}' while executing task.\".format(\n                    type(e), str(e)\n                )\n            )\n        finally:\n            self._is_executed = True\n            self.teardown()\n        return self._result\n\n    @property\n    def is_executed(self) -> bool:\n        \"\"\"Check if the task has already been executed.\"\"\"\n        return self._is_executed\n\n    @property\n    def result(self) -> Any:\n        \"\"\"\n        Get the result.\n\n        :return: the result from the execute method.\n        :raises ValueError: if the task has not been executed yet.\n        \"\"\"\n        if not self._is_executed:\n            raise ValueError(\"Task not executed yet.\")\n        return self._result\n\n    def setup(self) -> None:\n        \"\"\"Implement the task setup.\"\"\"\n\n    @abstractmethod\n    def execute(self, *args: Any, **kwargs: Any) -> Any:\n        \"\"\"\n        Run the task logic.\n\n        :param args: the positional arguments\n        :param kwargs: the keyword arguments\n        :return: any\n        \"\"\"\n\n    def teardown(self) -> None:\n        \"\"\"Implement the task teardown.\"\"\"\n\n\n# for api compatability. to remove in the next release\ndef init_worker() -> None:  # pragma: nocover\n    \"\"\"\n    Initialize a worker.\n\n    Disable the SIGINT handler of process pool is using.\n    Related to a well-known bug: https://bugs.python.org/issue8296\n    \"\"\"\n    if Pool.__class__.__name__ == \"Pool\":  # pragma: nocover\n        # Process worker\n        signal.signal(signal.SIGINT, signal.SIG_IGN)\n\n\ndef _init_worker(mode: str, packages: Dict[str, List[Dict[str, str]]]) -> None:\n    \"\"\"\n    Initialize a worker.\n\n    Disable the SIGINT handler of process pool is using.\n    Related to a well-known bug: https://bugs.python.org/issue8296\n\n    :param mode: str. mode task manager runs in\n    :param packages: dict with list of packages to load if needed\n    \"\"\"\n    if mode == PROCESS_POOL_MODE:  # pragma: nocover\n        signal.signal(signal.SIGINT, signal.SIG_IGN)\n        _populate_packages(packages)\n\n\nclass TaskManager(WithLogger):\n    \"\"\"A Task manager.\"\"\"\n\n    POOL_MODES: Dict[str, Type[Pool]] = {\n        THREAD_POOL_MODE: ThreadPool,\n        PROCESS_POOL_MODE: Pool,\n    }\n\n    def __init__(\n        self,\n        nb_workers: int = DEFAULT_WORKERS_AMOUNT,\n        is_lazy_pool_start: bool = True,\n        logger: Optional[logging.Logger] = None,\n        pool_mode: str = THREAD_POOL_MODE,\n    ) -> None:\n        \"\"\"\n        Initialize the task manager.\n\n        :param nb_workers: the number of worker processes.\n        :param is_lazy_pool_start: option to postpone pool creation till the first enqueue_task called.\n        :param logger: the logger.\n        :param pool_mode: str. multithread or multiprocess\n        \"\"\"\n        WithLogger.__init__(self, logger)\n        self._nb_workers = nb_workers\n        self._is_lazy_pool_start = is_lazy_pool_start\n        self._pool = None  # type: Optional[Pool]\n        self._stopped = True\n        self._lock = threading.Lock()\n\n        self._task_enqueued_counter = 0\n        self._results_by_task_id = {}  # type: Dict[int, Any]\n        self._pool_mode = pool_mode\n\n    @property\n    def is_started(self) -> bool:\n        \"\"\"\n        Get started status of TaskManager.\n\n        :return: bool\n        \"\"\"\n        return not self._stopped\n\n    @property\n    def nb_workers(self) -> int:\n        \"\"\"\n        Get the number of workers.\n\n        :return: int\n        \"\"\"\n        return self._nb_workers\n\n    def enqueue_task(\n        self,\n        func: Callable,\n        args: Sequence = (),\n        kwargs: Optional[Dict[str, Any]] = None,\n    ) -> int:\n        \"\"\"\n        Enqueue a task with the executor.\n\n        :param func: the callable instance to be enqueued\n        :param args: the positional arguments to be passed to the function.\n        :param kwargs: the keyword arguments to be passed to the function.\n        :return: the task id to get the the result.\n        :raises ValueError: if the task manager is not running.\n        \"\"\"\n        with self._lock:\n            if self._stopped:\n                raise ValueError(\"Task manager not running.\")\n\n            if not self._pool and self._is_lazy_pool_start:\n                self._start_pool()\n\n            self._pool = cast(Pool, self._pool)\n            task_id = self._task_enqueued_counter\n            self._task_enqueued_counter += 1\n            async_result = self._pool.apply_async(\n                func, args=args, kwds=kwargs if kwargs is not None else {}\n            )\n\n            self._results_by_task_id[task_id] = async_result\n            if self._logger:  # pragma: nocover\n                self._logger.info(f\"Task <{func}{args}> set. Task id is {task_id}\")\n            return task_id\n\n    def get_task_result(self, task_id: int) -> AsyncResult:\n        \"\"\"\n        Get the result from a task.\n\n        :param task_id: the task id\n        :return: async result for task_id\n        \"\"\"\n        task_result = self._results_by_task_id.get(\n            task_id, None\n        )  # type: Optional[AsyncResult]\n        if task_result is None:\n            raise ValueError(\"Task id {} not present.\".format(task_id))\n\n        return task_result\n\n    def start(self) -> None:\n        \"\"\"Start the task manager.\"\"\"\n        with self._lock:\n            if self._stopped is False:\n                self.logger.debug(\"Task manager already running.\")\n            else:\n                self.logger.debug(\"Start the task manager.\")\n                self._stopped = False\n                if not self._is_lazy_pool_start:\n                    self._start_pool()\n\n    def stop(self) -> None:\n        \"\"\"Stop the task manager.\"\"\"\n        with self._lock:\n            if self._stopped is True:\n                self.logger.debug(\"Task manager already stopped.\")\n            else:\n                self.logger.debug(\"Stop the task manager.\")\n                self._stopped = True\n                self._stop_pool()\n\n    def _start_pool(self) -> None:\n        \"\"\"\n        Start internal task pool.\n\n        Only one pool will be created.\n        \"\"\"\n        if self._pool:\n            self.logger.debug(\"Pool was already started!\")\n            return\n        pool_cls = self.POOL_MODES.get(self._pool_mode)\n        if not pool_cls:  # pragma: nocover\n            raise ValueError(f\"Mode: `{self._pool_mode}` is not supported\")\n        init_args = (\n            self._pool_mode,\n            _enlist_component_packages(),\n        )\n        self._pool = pool_cls(\n            self._nb_workers, initializer=_init_worker, initargs=init_args\n        )\n\n    def _stop_pool(self) -> None:\n        \"\"\"Stop internal task pool.\"\"\"\n        if not self._pool:\n            self.logger.debug(\"Pool is not started!.\")\n            return\n\n        self._pool = cast(Pool, self._pool)\n        self._pool.terminate()\n        self._pool.join()\n        self._pool = None\n\n\nclass ThreadedTaskManager(TaskManager):\n    \"\"\"A threaded task manager.\"\"\"\n\n    def __init__(\n        self,\n        nb_workers: int = DEFAULT_WORKERS_AMOUNT,\n        is_lazy_pool_start: bool = True,\n        logger: Optional[logging.Logger] = None,\n    ) -> None:\n        \"\"\"\n        Initialize the task manager.\n\n        :param nb_workers: the number of worker processes.\n        :param is_lazy_pool_start: option to postpone pool creation till the first enqueue_task called.\n        :param logger: the logger.\n        \"\"\"\n        super().__init__(\n            nb_workers=nb_workers,\n            is_lazy_pool_start=is_lazy_pool_start,\n            logger=logger,\n            pool_mode=THREAD_POOL_MODE,\n        )\n\n\nclass ProcessTaskManager(TaskManager):\n    \"\"\"A multiprocess task manager.\"\"\"\n\n    def __init__(\n        self,\n        nb_workers: int = DEFAULT_WORKERS_AMOUNT,\n        is_lazy_pool_start: bool = True,\n        logger: Optional[logging.Logger] = None,\n    ) -> None:\n        \"\"\"\n        Initialize the task manager.\n\n        :param nb_workers: the number of worker processes.\n        :param is_lazy_pool_start: option to postpone pool creation till the first enqueue_task called.\n        :param logger: the logger.\n        \"\"\"\n        super().__init__(\n            nb_workers=nb_workers,\n            is_lazy_pool_start=is_lazy_pool_start,\n            logger=logger,\n            pool_mode=PROCESS_POOL_MODE,\n        )\n"
  },
  {
    "path": "aea/test_tools/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the implementation of the AEA test framework.\"\"\"\n"
  },
  {
    "path": "aea/test_tools/click_testing.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nThis module contains an adaptation of click.testing.CliRunner.\n\nIn particular, it fixes an issue in\nCliRunner.invoke, in the 'finally' clause. More precisely, before reading from\nthe testing outstream, it checks whether it has been already closed.\n\nLinks:\n\n    https://github.com/pallets/click/issues/824\n\n\"\"\"\nimport shlex\nimport sys\nfrom typing import Optional\n\nfrom click.testing import CliRunner as ClickCliRunner\nfrom click.testing import Result\n\n\nclass CliRunner(ClickCliRunner):\n    \"\"\"Patch of click.testing.CliRunner.\"\"\"\n\n    def invoke(  # type: ignore\n        self,\n        cli,\n        args=None,\n        input=None,  # pylint: disable=redefined-builtin\n        env=None,\n        catch_exceptions=True,\n        color=False,\n        **extra,\n    ) -> Result:\n        \"\"\"Call a cli command with click.testing.CliRunner.invoke.\"\"\"\n        exc_info = None\n        exception: Optional[BaseException] = None\n        exit_code = 0\n\n        with self.isolation(input=input, env=env, color=color) as outstreams:\n            if isinstance(args, str):\n                args = shlex.split(args)\n\n            try:\n                prog_name = extra.pop(\"prog_name\")\n            except KeyError:\n                prog_name = self.get_default_prog_name(cli)\n\n            try:\n                cli.main(args=args or (), prog_name=prog_name, **extra)\n            except SystemExit as e:\n                exc_info = sys.exc_info()\n                exit_code = e.code\n                if exit_code is None:  # pragma: nocover\n                    exit_code = 0\n\n                if exit_code != 0:  # pragma: nocover\n                    exception = e\n\n                if not isinstance(exit_code, int):\n                    sys.stdout.write(str(exit_code))\n                    sys.stdout.write(\"\\n\")\n                    exit_code = 1\n\n            except Exception as e:  # pylint: disable=broad-except\n                if not catch_exceptions:\n                    raise\n                exception = e\n                exit_code = 1\n                exc_info = sys.exc_info()\n            finally:\n                sys.stdout.flush()\n                stdout = outstreams[0].getvalue() if not outstreams[0].closed else b\"\"  # type: ignore\n                if self.mix_stderr:\n                    # when it mixed, stderr always empty cause all output goes to stdout\n                    stderr: Optional[bytes] = None\n                else:\n                    stderr = (\n                        outstreams[1].getvalue() if not outstreams[1].closed else b\"\"  # type: ignore\n                    )\n\n        return Result(\n            runner=self,\n            stdout_bytes=stdout,\n            stderr_bytes=stderr,  # type: ignore\n            exit_code=exit_code,\n            exception=exception,\n            exc_info=exc_info,  # type: ignore\n            return_value=None,\n        )\n"
  },
  {
    "path": "aea/test_tools/constants.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This is a module with constants for test tools.\"\"\"\n\n\nDEFAULT_AUTHOR = \"default_author\"\n"
  },
  {
    "path": "aea/test_tools/exceptions.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Module with AEA testing exceptions.\"\"\"\n\n\nclass AEATestingException(Exception):\n    \"\"\"An exception to be raised on incorrect testing tools usage.\"\"\"\n"
  },
  {
    "path": "aea/test_tools/generic.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains generic tools for AEA end-to-end testing.\"\"\"\n\nfrom collections import OrderedDict\nfrom pathlib import Path\nfrom typing import Any, Dict, List, cast\n\nfrom aea.configurations.base import (\n    CRUDCollection,\n    ComponentConfiguration,\n    PackageConfiguration,\n    PackageType,\n    PublicId,\n    SkillConfig,\n    dependencies_from_json,\n)\nfrom aea.configurations.manager import handle_dotted_path\nfrom aea.exceptions import enforce\nfrom aea.helpers.file_io import write_envelope\nfrom aea.helpers.io import open_file\nfrom aea.helpers.yaml_utils import yaml_dump, yaml_dump_all\nfrom aea.mail.base import Envelope\nfrom aea.test_tools.constants import DEFAULT_AUTHOR\n\n\ndef write_envelope_to_file(envelope: Envelope, file_path: str) -> None:\n    \"\"\"\n    Write an envelope to a file.\n\n    :param envelope: Envelope.\n    :param file_path: the file path\n    \"\"\"\n    with open(Path(file_path), \"ab+\") as f:\n        write_envelope(envelope, f)\n\n\ndef read_envelope_from_file(file_path: str) -> Envelope:\n    \"\"\"\n    Read an envelope from a file.\n\n    :param file_path: the file path.\n\n    :return: envelope\n    \"\"\"\n    lines = []\n    with open(Path(file_path), \"rb+\") as f:\n        lines.extend(f.readlines())\n\n    enforce(len(lines) == 2, \"Did not find two lines.\")\n    line = lines[0] + lines[1]\n    to_b, sender_b, protocol_specification_id_b, message, end = line.strip().split(\n        b\",\", maxsplit=4\n    )\n    to = to_b.decode(\"utf-8\")\n    sender = sender_b.decode(\"utf-8\")\n    protocol_specification_id = PublicId.from_str(\n        protocol_specification_id_b.decode(\"utf-8\")\n    )\n    enforce(end in [b\"\", b\"\\n\"], \"Envelope improperly formatted.\")\n\n    return Envelope(\n        to=to,\n        sender=sender,\n        protocol_specification_id=protocol_specification_id,\n        message=message,\n    )\n\n\ndef _nested_set(\n    configuration_obj: PackageConfiguration, keys: List, value: Any\n) -> None:\n    \"\"\"\n    Nested set a value to a dict. Force sets the values, overwriting any present values, but maintaining schema validation.\n\n    :param configuration_obj: configuration object\n    :param keys: list of keys.\n    :param value: a value to set.\n    \"\"\"\n\n    def get_nested_ordered_dict_from_dict(input_dict: Dict) -> Dict:\n        _dic = {}\n        for _key, _value in input_dict.items():\n            if isinstance(_value, dict):\n                _dic[_key] = OrderedDict(get_nested_ordered_dict_from_dict(_value))\n            else:\n                _dic[_key] = _value\n        return _dic\n\n    def get_nested_ordered_dict_from_keys_and_value(\n        keys: List[str], value: Any\n    ) -> Dict:\n        _dic = (\n            OrderedDict(get_nested_ordered_dict_from_dict(value))\n            if isinstance(value, dict)\n            else value\n        )\n        for key in keys[::-1]:\n            _dic = OrderedDict({key: _dic})\n        return _dic\n\n    root_key = keys[0]\n    if (\n        isinstance(configuration_obj, SkillConfig)\n        and root_key in SkillConfig.FIELDS_WITH_NESTED_FIELDS\n    ):\n        root_attr = getattr(configuration_obj, root_key)\n        length = len(keys)\n        if length < 3 or keys[2] not in SkillConfig.NESTED_FIELDS_ALLOWED_TO_UPDATE:\n            raise ValueError(f\"Invalid keys={keys}.\")  # pragma: nocover\n        skill_component_id = keys[1]\n        skill_component_config = root_attr.read(skill_component_id)\n        if length == 3 and isinstance(value, dict):  # root.skill_component_id.args\n            # set all args\n            skill_component_config.args = get_nested_ordered_dict_from_dict(value)\n        elif len(keys) >= 4:  # root.skill_component_id.args.[keys]\n            # update some args\n            dic = get_nested_ordered_dict_from_keys_and_value(keys[3:], value)\n            skill_component_config.args.update(dic)\n        else:\n            raise ValueError(  # pragma: nocover\n                f\"Invalid keys={keys} and values={value}.\"\n            )\n        root_attr.update(skill_component_id, skill_component_config)\n    else:\n        root_attr = getattr(configuration_obj, root_key)\n        if isinstance(root_attr, CRUDCollection):\n            if isinstance(value, dict) and len(keys) == 1:  # root.\n                for _key, _value in value.items():\n                    dic = get_nested_ordered_dict_from_keys_and_value([_key], _value)\n                    root_attr.update(_key, dic[_key])\n            elif len(keys) >= 2:  # root.[keys]\n                dic = get_nested_ordered_dict_from_keys_and_value(keys[1:], value)\n                root_attr.update(keys[1], dic[keys[1]])\n            else:\n                raise ValueError(  # pragma: nocover\n                    f\"Invalid keys={keys} and values={value}.\"\n                )\n        elif root_key == \"dependencies\":\n            enforce(\n                isinstance(configuration_obj, ComponentConfiguration),\n                \"Cannot only set dependencies to ComponentConfiguration instances.\",\n            )\n            configuration_obj = cast(ComponentConfiguration, configuration_obj)\n            new_pypi_dependencies = dependencies_from_json(value)\n            configuration_obj.pypi_dependencies = new_pypi_dependencies\n        else:\n            dic = get_nested_ordered_dict_from_keys_and_value(keys, value)\n            setattr(configuration_obj, root_key, dic[root_key])\n\n\ndef nested_set_config(\n    dotted_path: str, value: Any, author: str = DEFAULT_AUTHOR\n) -> None:\n    \"\"\"\n    Set an AEA config with nested values.\n\n    Run from agent's directory.\n\n    Allowed dotted_path:\n        'agent.an_attribute_name'\n        'protocols.my_protocol.an_attribute_name'\n        'connections.my_connection.an_attribute_name'\n        'contracts.my_contract.an_attribute_name'\n        'skills.my_skill.an_attribute_name'\n        'vendor.author.[protocols|connections|skills].package_name.attribute_name\n\n    :param dotted_path: dotted path to a setting.\n    :param value: a value to assign. Must be of yaml serializable type.\n    :param author: the author name, used to parse the dotted path.\n    \"\"\"\n    settings_keys, config_file_path, config_loader, _ = handle_dotted_path(\n        dotted_path, author\n    )\n    with open_file(config_file_path) as fp:\n        config = config_loader.load(fp)\n\n    _nested_set(config, settings_keys, value)\n\n    if config.package_type == PackageType.AGENT:\n        json_data = config.ordered_json\n        component_configurations = json_data.pop(\"component_configurations\")\n        with open_file(config_file_path, \"w\") as fp:\n            yaml_dump_all([json_data] + component_configurations, fp)\n    else:\n        with open_file(config_file_path, \"w\") as fp:\n            yaml_dump(config.ordered_json, fp)\n"
  },
  {
    "path": "aea/test_tools/test_cases.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains test case classes based on pytest for AEA end-to-end testing.\"\"\"\nimport copy\nimport logging\nimport os\nimport random\nimport shutil\nimport string\nimport subprocess  # nosec\nimport sys\nimport tempfile\nimport time\nfrom abc import ABC\nfrom contextlib import suppress\nfrom filecmp import dircmp\nfrom io import TextIOWrapper\nfrom pathlib import Path\nfrom threading import Thread\nfrom typing import Any, Callable, Dict, List, Optional, Sequence, Set, Tuple, Union\n\nimport yaml\n\nfrom aea.cli import cli\nfrom aea.configurations.base import (\n    AgentConfig,\n    PackageType,\n    _get_default_configuration_file_name_from_type,\n)\nfrom aea.configurations.constants import (\n    DEFAULT_AEA_CONFIG_FILE,\n    DEFAULT_INPUT_FILE_NAME,\n    DEFAULT_LEDGER,\n    DEFAULT_OUTPUT_FILE_NAME,\n    DEFAULT_PRIVATE_KEY_FILE,\n    DEFAULT_REGISTRY_NAME,\n    LAUNCH_SUCCEED_MESSAGE,\n)\nfrom aea.configurations.loader import ConfigLoader, ConfigLoaders\nfrom aea.exceptions import enforce\nfrom aea.helpers.base import cd, send_control_c, win_popen_kwargs\nfrom aea.helpers.io import open_file\nfrom aea.mail.base import Envelope\nfrom aea.test_tools.click_testing import CliRunner, Result\nfrom aea.test_tools.constants import DEFAULT_AUTHOR\nfrom aea.test_tools.exceptions import AEATestingException\nfrom aea.test_tools.generic import (\n    nested_set_config,\n    read_envelope_from_file,\n    write_envelope_to_file,\n)\n\n\n_default_logger = logging.getLogger(__name__)\n\nCLI_LOG_OPTION = [\"-v\", \"OFF\"]\n\nDEFAULT_PROCESS_TIMEOUT = 120\nDEFAULT_LAUNCH_TIMEOUT = 10\n\n\nclass BaseAEATestCase(ABC):  # pylint: disable=too-many-public-methods\n    \"\"\"Base class for AEA test cases.\"\"\"\n\n    runner: CliRunner  # CLI runner\n    last_cli_runner_result: Optional[Result] = None\n    author: str = DEFAULT_AUTHOR  # author\n    subprocesses: List[subprocess.Popen] = []  # list of launched subprocesses\n    threads: List[Thread] = []  # list of started threads\n    packages_dir_path: Path = Path(DEFAULT_REGISTRY_NAME)\n    package_registry_src: Path = Path(\".\")\n    use_packages_dir: bool = True\n    package_registry_src_rel: Path = Path(os.getcwd(), packages_dir_path)\n    old_cwd: Path  # current working directory path\n    t: Path  # temporary directory path\n    current_agent_context: str = \"\"  # the name of the current agent\n    agents: Set[str] = set()  # the set of created agents\n    stdout: Dict[int, str]  # dict of process.pid: string stdout\n    stderr: Dict[int, str]  # dict of process.pid: string stderr\n    _is_teardown_class_called: bool = False\n    capture_log: bool = False\n    cli_log_options: List[str] = []\n    method_list: List[str] = []\n\n    @classmethod\n    def set_agent_context(cls, agent_name: str) -> None:\n        \"\"\"Set the current agent context.\"\"\"\n        cls.current_agent_context = agent_name\n\n    @classmethod\n    def unset_agent_context(cls) -> None:\n        \"\"\"Unset the current agent context.\"\"\"\n        cls.current_agent_context = \"\"\n\n    @classmethod\n    def set_config(\n        cls, dotted_path: str, value: Any, type_: Optional[str] = None\n    ) -> Result:\n        \"\"\"\n        Set a config.\n\n        Run from agent's directory.\n\n        :param dotted_path: str dotted path to config param.\n        :param value: a new value to set.\n        :param type_: the type\n\n        :return: Result\n        \"\"\"\n        if type_ is None:\n            type_ = type(value).__name__\n\n        return cls.run_cli_command(\n            \"config\",\n            \"set\",\n            dotted_path,\n            str(value),\n            \"--type\",\n            type_,\n            cwd=cls._get_cwd(),\n        )\n\n    @classmethod\n    def nested_set_config(cls, dotted_path: str, value: Any) -> None:\n        \"\"\"Force set config.\"\"\"\n        with cd(cls._get_cwd()):\n            nested_set_config(dotted_path, value)\n\n    @classmethod\n    def disable_aea_logging(cls) -> None:\n        \"\"\"\n        Disable AEA logging of specific agent.\n\n        Run from agent's directory.\n        \"\"\"\n        config_update_dict = {\n            \"agent.logging_config.disable_existing_loggers\": \"False\",\n            \"agent.logging_config.version\": \"1\",\n        }\n        for path, value in config_update_dict.items():\n            cls.run_cli_command(\"config\", \"set\", path, value, cwd=cls._get_cwd())\n\n    @classmethod\n    def run_cli_command(cls, *args: str, cwd: str = \".\", **kwargs: str) -> Result:\n        \"\"\"\n        Run AEA CLI command.\n\n        :param args: CLI args\n        :param cwd: the working directory from where to run the command.\n        :param kwargs: other keyword arguments to click.CliRunner.invoke.\n        :raises AEATestingException: if command fails.\n\n        :return: Result\n        \"\"\"\n        with cd(cwd):\n            result = cls.runner.invoke(\n                cli,\n                [*CLI_LOG_OPTION, *args],\n                standalone_mode=False,\n                catch_exceptions=False,\n                **kwargs,\n            )\n            cls.last_cli_runner_result = result\n            if result.exit_code != 0:  # pragma: nocover\n                raise AEATestingException(\n                    \"Failed to execute AEA CLI command with args {}.\\n\"\n                    \"Exit code: {}\\nException: {}\".format(\n                        args, result.exit_code, result.exception\n                    )\n                )\n            return result\n\n    @classmethod\n    def _run_python_subprocess(cls, *args: str, cwd: str = \".\") -> subprocess.Popen:\n        \"\"\"\n        Run python with args as subprocess.\n\n        :param args: CLI args\n        :param cwd: the current working directory\n\n        :return: subprocess object.\n        \"\"\"\n        kwargs = dict(\n            stdout=subprocess.PIPE,\n            stdin=subprocess.PIPE,\n            env=os.environ.copy(),\n            cwd=cwd,\n        )\n        kwargs.update(win_popen_kwargs())\n\n        process = subprocess.Popen(  # type: ignore # nosec # mypy fails on **kwargs # pylint: disable=consider-using-with\n            [sys.executable, *args],\n            **kwargs,\n        )\n        cls.subprocesses.append(process)\n        return process\n\n    @classmethod\n    def start_subprocess(cls, *args: str, cwd: str = \".\") -> subprocess.Popen:\n        \"\"\"\n        Run python with args as subprocess.\n\n        :param args: CLI args\n        :param cwd: the current working directory\n\n        :return: subprocess object.\n        \"\"\"\n        process = cls._run_python_subprocess(*args, cwd=cwd)\n        cls._start_output_read_thread(process)\n        cls._start_error_read_thread(process)\n        return process\n\n    @classmethod\n    def start_thread(cls, target: Callable, **kwargs: subprocess.Popen) -> Thread:\n        \"\"\"\n        Start python Thread.\n\n        :param target: target method.\n        :param kwargs: thread keyword arguments\n        :return: thread\n        \"\"\"\n        if \"process\" in kwargs:\n            thread = Thread(target=target, args=(kwargs[\"process\"],))\n        else:\n            thread = Thread(target=target)\n        thread.start()\n        cls.threads.append(thread)\n        return thread\n\n    @classmethod\n    def create_agents(\n        cls, *agents_names: str, is_local: bool = True, is_empty: bool = False\n    ) -> None:\n        \"\"\"\n        Create agents in current working directory.\n\n        :param agents_names: str agent names.\n        :param is_local: a flag for local folder add True by default.\n        :param is_empty: optional boolean flag for skip adding default dependencies.\n        \"\"\"\n        cli_args = [\"create\", \"--local\", \"--empty\"]\n        if not is_local:  # pragma: nocover\n            cli_args.remove(\"--local\")\n        if not is_empty:  # pragma: nocover\n            cli_args.remove(\"--empty\")\n        for name in set(agents_names):\n            cls.run_cli_command(*cli_args, name)\n            cls.agents.add(name)\n\n    @classmethod\n    def fetch_agent(\n        cls, public_id: str, agent_name: str, is_local: bool = True\n    ) -> None:\n        \"\"\"\n        Create agents in current working directory.\n\n        :param public_id: str public id\n        :param agent_name: str agent name.\n        :param is_local: a flag for local folder add True by default.\n        \"\"\"\n        cli_args = [\"fetch\", \"--local\"]\n        if not is_local:  # pragma: nocover\n            cli_args.remove(\"--local\")\n        cls.run_cli_command(*cli_args, public_id, \"--alias\", agent_name)\n        cls.agents.add(agent_name)\n\n    @classmethod\n    def difference_to_fetched_agent(cls, public_id: str, agent_name: str) -> List[str]:\n        \"\"\"\n        Compare agent against the one fetched from public id.\n\n        :param public_id: str public id\n        :param agent_name: str agent name.\n\n        :return: list of files differing in the projects\n        \"\"\"\n        # for pydocstyle\n        def is_allowed_diff_in_agent_config(\n            path_to_fetched_aea: str, path_to_manually_created_aea: str\n        ) -> Tuple[\n            bool, Union[Dict[str, str], List[Any]], Union[Dict[str, str], List[Any]]\n        ]:\n            with open_file(\n                os.path.join(path_to_fetched_aea, \"aea-config.yaml\"), \"r\"\n            ) as file:\n                content1 = list(yaml.safe_load_all(file))  # load all contents\n            with open_file(\n                os.path.join(path_to_manually_created_aea, \"aea-config.yaml\"), \"r\"\n            ) as file:\n                content2 = list(yaml.safe_load_all(file))\n\n            content1_agentconfig = content1[0]\n            content2_agentconfig = content2[0]\n            content1_agentconfig_copy = copy.deepcopy(content1_agentconfig)\n\n            # check only agent part\n            for key, value in content1_agentconfig_copy.items():\n                if content2_agentconfig[key] == value:\n                    content1_agentconfig.pop(key)\n                    content2_agentconfig.pop(key)\n            allowed_diff_keys = [\n                \"aea_version\",\n                \"author\",\n                \"description\",\n                \"version\",\n                \"connection_private_key_paths\",\n                \"private_key_paths\",\n                \"dependencies\",\n                \"required_ledgers\",\n            ]\n            result = all(\n                (key in allowed_diff_keys for key in content1_agentconfig.keys())\n            )\n            result = result and all(\n                (key in allowed_diff_keys for key in content2_agentconfig.keys())\n            )\n            if not result:\n                return result, content1_agentconfig, content2_agentconfig\n\n            # else, additionally check the other YAML pages\n            # (i.e. the component configuration overrides)\n            content1_component_overrides = content1[1:]\n            content2_component_overrides = content2[1:]\n\n            if len(content1_component_overrides) != len(content2_component_overrides):\n                return False, content1_component_overrides, content2_component_overrides\n\n            diff_1, diff_2 = [], []\n            for index, (override_1, override_2) in enumerate(\n                zip(content1_component_overrides, content2_component_overrides)\n            ):\n                if override_1 != override_2:\n                    result = False\n                    diff_1.append((index, override_1))\n                    diff_2.append((index, override_2))\n\n            return result, diff_1, diff_2\n\n        path_to_manually_created_aea = os.path.join(cls.t, agent_name)\n        new_cwd = os.path.join(cls.t, \"fetch_dir\")\n        os.mkdir(new_cwd)\n        fetched_agent_name = agent_name\n        path_to_fetched_aea = os.path.join(new_cwd, fetched_agent_name)\n        registry_tmp_dir = os.path.join(new_cwd, cls.packages_dir_path)\n        shutil.copytree(str(cls.package_registry_src_rel), str(registry_tmp_dir))\n        with cd(new_cwd):\n            cls.run_cli_command(\n                \"fetch\", \"--local\", public_id, \"--alias\", fetched_agent_name\n            )\n        comp = dircmp(path_to_manually_created_aea, path_to_fetched_aea)\n        file_diff = comp.diff_files\n        result, diff1, diff2 = is_allowed_diff_in_agent_config(\n            path_to_fetched_aea, path_to_manually_created_aea\n        )\n        if result:\n            if \"aea-config.yaml\" in file_diff:  # pragma: nocover\n                file_diff.remove(\"aea-config.yaml\")  # won't match!\n        else:\n            file_diff.append(\n                \"Difference in aea-config.yaml: \" + str(diff1) + \" vs. \" + str(diff2)\n            )\n\n        with suppress(OSError, IOError):\n            shutil.rmtree(new_cwd)\n\n        return file_diff\n\n    @classmethod\n    def delete_agents(cls, *agents_names: str) -> None:\n        \"\"\"\n        Delete agents in current working directory.\n\n        :param agents_names: str agent names.\n        \"\"\"\n        for name in set(agents_names):\n            cls.run_cli_command(\"delete\", name)\n            cls.agents.remove(name)\n\n    @classmethod\n    def run_agent(cls, *args: str) -> subprocess.Popen:\n        \"\"\"\n        Run agent as subprocess.\n\n        Run from agent's directory.\n\n        :param args: CLI args\n\n        :return: subprocess object.\n        \"\"\"\n        return cls._start_cli_process(\"run\", *args)\n\n    @classmethod\n    def run_interaction(cls) -> subprocess.Popen:\n        \"\"\"\n        Run interaction as subprocess.\n\n        Run from agent's directory.\n\n        :return: subprocess object.\n        \"\"\"\n        return cls._start_cli_process(\"interact\")\n\n    @classmethod\n    def _start_cli_process(cls, *args: str) -> subprocess.Popen:\n        \"\"\"\n        Start cli subprocess with args specified.\n\n        :param args: CLI args\n        :return: subprocess object.\n        \"\"\"\n        process = cls._run_python_subprocess(\n            \"-m\", \"aea.cli\", *cls.cli_log_options, *args, cwd=cls._get_cwd()\n        )\n        cls._start_output_read_thread(process)\n        cls._start_error_read_thread(process)\n        return process\n\n    @classmethod\n    def terminate_agents(\n        cls,\n        *subprocesses: subprocess.Popen,\n        timeout: int = 20,\n    ) -> None:\n        \"\"\"\n        Terminate agent subprocesses.\n\n        Run from agent's directory.\n\n        :param subprocesses: the subprocesses running the agents\n        :param timeout: the timeout for interruption\n        \"\"\"\n        if not subprocesses:\n            subprocesses = tuple(cls.subprocesses)\n        for process in subprocesses:\n            process.poll()\n            if process.returncode is None:  # stop only pending processes\n                send_control_c(process)\n        for process in subprocesses:\n            process.wait(timeout=timeout)\n\n    @classmethod\n    def is_successfully_terminated(cls, *subprocesses: subprocess.Popen) -> bool:\n        \"\"\"Check if all subprocesses terminated successfully.\"\"\"\n        if not subprocesses:\n            subprocesses = tuple(cls.subprocesses)\n\n        all_terminated = all((process.returncode == 0 for process in subprocesses))\n        return all_terminated\n\n    @classmethod\n    def initialize_aea(cls, author: str) -> None:\n        \"\"\"Initialize AEA locally with author name.\"\"\"\n        cls.run_cli_command(\"init\", \"--author\", author, cwd=cls._get_cwd())\n\n    @classmethod\n    def add_item(cls, item_type: str, public_id: str, local: bool = True) -> Result:\n        \"\"\"\n        Add an item to the agent.\n\n        Run from agent's directory.\n\n        :param item_type: str item type.\n        :param public_id: public id of the item.\n        :param local: a flag for local folder add True by default.\n\n        :return: Result\n        \"\"\"\n        cli_args = [\"add\", \"--local\", item_type, public_id]\n        if not local:  # pragma: nocover\n            cli_args.remove(\"--local\")\n        return cls.run_cli_command(*cli_args, cwd=cls._get_cwd())\n\n    @classmethod\n    def remove_item(cls, item_type: str, public_id: str) -> Result:\n        \"\"\"\n        Remove an item from the agent.\n\n        Run from agent's directory.\n\n        :param item_type: str item type.\n        :param public_id: public id of the item.\n\n        :return: Result\n        \"\"\"\n        cli_args = [\"remove\", item_type, public_id]\n        return cls.run_cli_command(*cli_args, cwd=cls._get_cwd())\n\n    @classmethod\n    def scaffold_item(\n        cls, item_type: str, name: str, skip_consistency_check: bool = False\n    ) -> Result:\n        \"\"\"\n        Scaffold an item for the agent.\n\n        Run from agent's directory.\n\n        :param item_type: str item type.\n        :param name: name of the item.\n        :param skip_consistency_check: if True, skip consistency check.\n\n        :return: Result\n        \"\"\"\n        flags = [\"-s\"] if skip_consistency_check else []\n        if item_type == \"protocol\":\n            return cls.run_cli_command(\n                *flags, \"scaffold\", item_type, \"-y\", name, cwd=cls._get_cwd()\n            )\n        return cls.run_cli_command(\n            *flags, \"scaffold\", item_type, name, cwd=cls._get_cwd()\n        )\n\n    @classmethod\n    def fingerprint_item(cls, item_type: str, public_id: str) -> Result:\n        \"\"\"\n        Fingerprint an item for the agent.\n\n        Run from agent's directory.\n\n        :param item_type: str item type.\n        :param public_id: public id of the item.\n\n        :return: Result\n        \"\"\"\n        return cls.run_cli_command(\n            \"fingerprint\", item_type, public_id, cwd=cls._get_cwd()\n        )\n\n    @classmethod\n    def eject_item(cls, item_type: str, public_id: str) -> Result:\n        \"\"\"\n        Eject an item in the agent in quiet mode (i.e. no interaction).\n\n        Run from agent's directory.\n\n        :param item_type: str item type.\n        :param public_id: public id of the item.\n\n        :return: None\n        \"\"\"\n        cli_args = [\"eject\", \"--quiet\", item_type, public_id]\n        return cls.run_cli_command(*cli_args, cwd=cls._get_cwd())\n\n    @classmethod\n    def run_install(cls) -> Result:\n        \"\"\"\n        Execute AEA CLI install command.\n\n        Run from agent's directory.\n\n        :return: Result\n        \"\"\"\n        return cls.run_cli_command(\"install\", cwd=cls._get_cwd())\n\n    @classmethod\n    def generate_private_key(\n        cls,\n        ledger_api_id: str = DEFAULT_LEDGER,\n        private_key_file: Optional[str] = None,\n        password: Optional[str] = None,\n    ) -> Result:\n        \"\"\"\n        Generate AEA private key with CLI command.\n\n        Run from agent's directory.\n\n        :param ledger_api_id: ledger API ID.\n        :param private_key_file: the private key file.\n        :param password: the password.\n\n        :return: Result\n        \"\"\"\n        cli_args = [\"generate-key\", ledger_api_id]\n        if private_key_file is not None:  # pragma: nocover\n            cli_args.append(private_key_file)\n        cli_args += _get_password_option_args(password)\n        return cls.run_cli_command(*cli_args, cwd=cls._get_cwd())\n\n    @classmethod\n    def add_private_key(\n        cls,\n        ledger_api_id: str = DEFAULT_LEDGER,\n        private_key_filepath: str = DEFAULT_PRIVATE_KEY_FILE,\n        connection: bool = False,\n        password: Optional[str] = None,\n    ) -> Result:\n        \"\"\"\n        Add private key with CLI command.\n\n        Run from agent's directory.\n\n        :param ledger_api_id: ledger API ID.\n        :param private_key_filepath: private key filepath.\n        :param connection: whether or not the private key filepath is for a connection.\n        :param password: the password to encrypt private keys.\n\n        :return: Result\n        \"\"\"\n        password_option = _get_password_option_args(password)\n        if connection:\n            return cls.run_cli_command(\n                \"add-key\",\n                ledger_api_id,\n                private_key_filepath,\n                \"--connection\",\n                *password_option,\n                cwd=cls._get_cwd(),\n            )\n        return cls.run_cli_command(\n            \"add-key\",\n            ledger_api_id,\n            private_key_filepath,\n            *password_option,\n            cwd=cls._get_cwd(),\n        )\n\n    @classmethod\n    def remove_private_key(\n        cls,\n        ledger_api_id: str = DEFAULT_LEDGER,\n        connection: bool = False,\n    ) -> Result:\n        \"\"\"\n        Remove private key with CLI command.\n\n        Run from agent's directory.\n\n        :param ledger_api_id: ledger API ID.\n        :param connection: whether or not the private key filepath is for a connection.\n\n        :return: Result\n        \"\"\"\n        args = [\"remove-key\", ledger_api_id] + ([\"--connection\"] if connection else [])\n        return cls.run_cli_command(*args, cwd=cls._get_cwd())\n\n    @classmethod\n    def replace_private_key_in_file(\n        cls, private_key: str, private_key_filepath: str = DEFAULT_PRIVATE_KEY_FILE\n    ) -> None:\n        \"\"\"\n        Replace the private key in the provided file with the provided key.\n\n        :param private_key: the private key\n        :param private_key_filepath: the filepath to the private key file\n        :raises: exception if file does not exist\n        \"\"\"\n        with cd(cls._get_cwd()):  # pragma: nocover\n            with open_file(private_key_filepath, \"wt\") as f:\n                f.write(private_key)\n\n    @classmethod\n    def generate_wealth(\n        cls, ledger_api_id: str = DEFAULT_LEDGER, password: Optional[str] = None\n    ) -> Result:\n        \"\"\"\n        Generate wealth with CLI command.\n\n        Run from agent's directory.\n\n        :param ledger_api_id: ledger API ID.\n        :param password: the password.\n\n        :return: Result\n        \"\"\"\n        password_option = _get_password_option_args(password)\n        return cls.run_cli_command(\n            \"generate-wealth\",\n            ledger_api_id,\n            *password_option,\n            \"--sync\",\n            cwd=cls._get_cwd(),\n        )\n\n    @classmethod\n    def get_wealth(\n        cls, ledger_api_id: str = DEFAULT_LEDGER, password: Optional[str] = None\n    ) -> str:\n        \"\"\"\n        Get wealth with CLI command.\n\n        Run from agent's directory.\n\n        :param ledger_api_id: ledger API ID.\n        :param password: the password to encrypt/decrypt private keys.\n\n        :return: command line output\n        \"\"\"\n        password_option = _get_password_option_args(password)\n        cls.run_cli_command(\n            \"get-wealth\", ledger_api_id, *password_option, cwd=cls._get_cwd()\n        )\n        if cls.last_cli_runner_result is None:\n            raise ValueError(\"Runner result not set!\")  # pragma: nocover\n        return str(cls.last_cli_runner_result.stdout_bytes, \"utf-8\")\n\n    @classmethod\n    def get_address(\n        cls, ledger_api_id: str = DEFAULT_LEDGER, password: Optional[str] = None\n    ) -> str:\n        \"\"\"\n        Get address with CLI command.\n\n        Run from agent's directory.\n\n        :param ledger_api_id: ledger API ID.\n        :param password: the password to encrypt/decrypt private keys.\n\n        :return: command line output\n        \"\"\"\n        password_option = _get_password_option_args(password)\n        cls.run_cli_command(\n            \"get-address\", ledger_api_id, *password_option, cwd=cls._get_cwd()\n        )\n        if cls.last_cli_runner_result is None:\n            raise ValueError(\"Runner result not set!\")  # pragma: nocover\n        return str(cls.last_cli_runner_result.stdout_bytes, \"utf-8\").strip()\n\n    @classmethod\n    def replace_file_content(cls, src: Path, dest: Path) -> None:  # pragma: nocover\n        \"\"\"\n        Replace the content of the source file to the destination file.\n\n        :param src: the source file.\n        :param dest: the destination file.\n        \"\"\"\n        enforce(\n            src.is_file() and dest.is_file(), \"Source or destination is not a file.\"\n        )\n        dest.write_text(src.read_text())\n\n    @classmethod\n    def change_directory(cls, path: Path) -> None:\n        \"\"\"\n        Change current working directory.\n\n        :param path: path to the new working directory.\n        \"\"\"\n        os.chdir(Path(path))\n\n    @classmethod\n    def _terminate_subprocesses(cls) -> None:\n        \"\"\"Terminate all launched subprocesses.\"\"\"\n        for process in cls.subprocesses:\n            if not process.returncode == 0:\n                poll = process.poll()\n                if poll is None:\n                    process.terminate()\n                    process.wait(2)\n        cls.subprocesses = []\n\n    @classmethod\n    def _join_threads(cls) -> None:\n        \"\"\"Join all started threads.\"\"\"\n        for thread in cls.threads:\n            thread.join()\n        cls.threads = []\n\n    @classmethod\n    def _read_out(\n        cls, process: subprocess.Popen\n    ) -> None:  # pragma: nocover # runs in thread!\n        if process.stdout is None:\n            raise Exception(\"Stdout of the process is None\")\n        for line in TextIOWrapper(process.stdout, encoding=\"utf-8\"):\n            cls._log_capture(\"stdout\", process.pid, line)\n            cls.stdout[process.pid] += line\n\n    @classmethod\n    def _read_err(\n        cls, process: subprocess.Popen\n    ) -> None:  # pragma: nocover # runs in thread!\n        if process.stderr is not None:\n            for line in TextIOWrapper(process.stderr, encoding=\"utf-8\"):\n                cls._log_capture(\"stderr\", process.pid, line)\n                cls.stderr[process.pid] += line\n\n    @classmethod\n    def _log_capture(cls, name: str, pid: int, line: str) -> None:  # pragma: nocover\n        if not cls.capture_log:\n            return\n        sys.stdout.write(f\"[{pid}]{name}>{line}\")\n        sys.stdout.flush()\n\n    @classmethod\n    def _start_output_read_thread(cls, process: subprocess.Popen) -> None:\n        \"\"\"\n        Start an output reading thread.\n\n        :param process: target process passed to a thread args.\n        \"\"\"\n        cls.stdout[process.pid] = \"\"\n        cls.start_thread(target=cls._read_out, process=process)\n\n    @classmethod\n    def _start_error_read_thread(cls, process: subprocess.Popen) -> None:\n        \"\"\"\n        Start an error reading thread.\n\n        :param process: target process passed to a thread args.\n        \"\"\"\n        cls.stderr[process.pid] = \"\"\n        cls.start_thread(target=cls._read_err, process=process)\n\n    @classmethod\n    def _get_cwd(cls) -> str:\n        \"\"\"Get the current working directory.\"\"\"\n        return str(cls.t / cls.current_agent_context)\n\n    @classmethod\n    def send_envelope_to_agent(cls, envelope: Envelope, agent: str) -> None:\n        \"\"\"Send an envelope to an agent, using the stub connection.\"\"\"\n        # check added cause sometimes fails on win with permission error\n        dir_path = Path(cls.t / agent)\n        enforce(dir_path.exists(), \"Dir path does not exist.\")\n        enforce(dir_path.is_dir(), \"Dir path is not a directory.\")\n        write_envelope_to_file(envelope, str(cls.t / agent / DEFAULT_INPUT_FILE_NAME))\n\n    @classmethod\n    def read_envelope_from_agent(cls, agent: str) -> Envelope:\n        \"\"\"Read an envelope from an agent, using the stub connection.\"\"\"\n        return read_envelope_from_file(str(cls.t / agent / DEFAULT_OUTPUT_FILE_NAME))\n\n    @classmethod\n    def missing_from_output(\n        cls,\n        process: subprocess.Popen,\n        strings: Sequence[str],\n        timeout: int = DEFAULT_PROCESS_TIMEOUT,\n        period: int = 1,\n        is_terminating: bool = True,\n    ) -> List[str]:\n        \"\"\"\n        Check if strings are present in process output.\n\n        Read process stdout in thread and terminate when all strings are present\n        or timeout expired.\n\n        :param process: agent subprocess.\n        :param strings: tuple of strings expected to appear in output.\n        :param timeout: int amount of seconds before stopping check.\n        :param period: int period of checking.\n        :param is_terminating: whether or not the agents are terminated\n\n        :return: list of missed strings.\n        \"\"\"\n        missing_strings = list(strings)\n        end_time = time.time() + timeout\n        while missing_strings:\n            if time.time() > end_time:\n                break\n            missing_strings = [\n                line for line in missing_strings if line not in cls.stdout[process.pid]\n            ]\n            time.sleep(period)\n\n        if is_terminating:\n            cls.terminate_agents(process)\n        if missing_strings != []:\n            _default_logger.info(\n                \"Non-empty missing strings, stderr:\\n{}\".format(cls.stderr[process.pid])\n            )\n            _default_logger.info(\"=====================\")\n            _default_logger.info(\n                \"Non-empty missing strings, stdout:\\n{}\".format(cls.stdout[process.pid])\n            )\n            _default_logger.info(\"=====================\")\n        return missing_strings\n\n    @classmethod\n    def is_running(\n        cls, process: subprocess.Popen, timeout: int = DEFAULT_LAUNCH_TIMEOUT\n    ) -> bool:\n        \"\"\"\n        Check if the AEA is launched and running (ready to process messages).\n\n        :param process: agent subprocess.\n        :param timeout: the timeout to wait for launch to complete\n        :return: bool indicating status\n        \"\"\"\n        missing_strings = cls.missing_from_output(\n            process, (LAUNCH_SUCCEED_MESSAGE,), timeout, is_terminating=False\n        )\n\n        return missing_strings == []\n\n    @classmethod\n    def invoke(cls, *args: str) -> Result:\n        \"\"\"Call the cli command.\"\"\"\n        with cd(cls._get_cwd()):\n            result = cls.runner.invoke(\n                cli, args, standalone_mode=False, catch_exceptions=False\n            )\n        return result\n\n    @classmethod\n    def load_agent_config(cls, agent_name: str) -> AgentConfig:\n        \"\"\"Load agent configuration.\"\"\"\n        if agent_name not in cls.agents:\n            raise AEATestingException(\n                f\"Cannot find agent '{agent_name}' in the current test case.\"\n            )\n        loader = ConfigLoaders.from_package_type(PackageType.AGENT)\n        config_file_name = _get_default_configuration_file_name_from_type(\n            PackageType.AGENT\n        )\n        configuration_file_path = Path(cls.t, agent_name, config_file_name)\n        with open_file(configuration_file_path) as file_input:\n            agent_config = loader.load(file_input)\n        return agent_config\n\n    @classmethod\n    def setup_class(cls) -> None:\n        \"\"\"Set up the test class.\"\"\"\n        cls.method_list = [\n            func\n            for func in dir(cls)\n            if callable(getattr(cls, func))\n            and not func.startswith(\"__\")\n            and func.startswith(\"test_\")\n        ]\n        cls.runner = CliRunner()\n        cls.old_cwd = Path(os.getcwd())\n        cls.subprocesses = []\n        cls.threads = []\n\n        cls.t = Path(tempfile.mkdtemp())\n        cls.change_directory(cls.t)\n\n        cls.package_registry_src = cls.old_cwd / cls.package_registry_src_rel\n        if cls.use_packages_dir:\n            registry_tmp_dir = cls.t / cls.packages_dir_path\n            shutil.copytree(str(cls.package_registry_src), str(registry_tmp_dir))\n\n        cls.initialize_aea(cls.author)\n        cls.stdout = {}\n        cls.stderr = {}\n\n    @classmethod\n    def teardown_class(cls) -> None:\n        \"\"\"Teardown the test.\"\"\"\n        cls.change_directory(cls.old_cwd)\n        cls.terminate_agents(*cls.subprocesses)\n        cls._terminate_subprocesses()\n        cls._join_threads()\n        cls.unset_agent_context()\n        cls.last_cli_runner_result = None\n        cls.packages_dir_path = Path(DEFAULT_REGISTRY_NAME)\n        cls.use_packages_dir = True\n        cls.agents = set()\n        cls.current_agent_context = \"\"\n        cls.stdout = {}\n        cls.stderr = {}\n\n        with suppress(OSError, IOError):\n            shutil.rmtree(cls.t)\n\n        cls._is_teardown_class_called = True\n\n\ndef _get_password_option_args(password: Optional[str]) -> List[str]:\n    \"\"\"\n    Get password option arguments.\n\n    :param password: the password (optional).\n    :return: empty list if password is None, else ['--password', password].\n    \"\"\"\n    return [] if password is None else [\"--password\", password]\n\n\nclass AEATestCaseEmpty(BaseAEATestCase):\n    \"\"\"\n    Test case for a default AEA project.\n\n    This test case will create a default AEA project.\n    \"\"\"\n\n    agent_name = \"\"\n    IS_LOCAL = True\n    IS_EMPTY = False\n\n    @classmethod\n    def setup_class(cls) -> None:\n        \"\"\"Set up the test class.\"\"\"\n        super(AEATestCaseEmpty, cls).setup_class()\n        cls.agent_name = \"agent_\" + \"\".join(\n            random.choices(string.ascii_lowercase, k=5)  # nosec\n        )\n        cls.create_agents(cls.agent_name, is_local=cls.IS_LOCAL, is_empty=cls.IS_EMPTY)\n        cls.set_agent_context(cls.agent_name)\n\n    @classmethod\n    def teardown_class(cls) -> None:\n        \"\"\"Teardown the test class.\"\"\"\n        super(AEATestCaseEmpty, cls).teardown_class()\n        cls.agent_name = \"\"\n\n\nclass AEATestCaseEmptyFlaky(AEATestCaseEmpty):\n    \"\"\"\n    Test case for a default AEA project.\n\n    This test case will create a default AEA project.\n\n    Use for flaky tests with the flaky decorator.\n    \"\"\"\n\n    run_count: int = 0\n\n    @classmethod\n    def setup_class(cls) -> None:\n        \"\"\"Set up the test class.\"\"\"\n        super(AEATestCaseEmptyFlaky, cls).setup_class()\n        if len(cls.method_list) > 1:  # pragma: nocover\n            raise ValueError(f\"{cls.__name__} can only contain one test method!\")\n        cls.run_count += 1\n\n    @classmethod\n    def teardown_class(cls) -> None:\n        \"\"\"Teardown the test class.\"\"\"\n        super(AEATestCaseEmptyFlaky, cls).teardown_class()\n\n\nclass AEATestCaseMany(BaseAEATestCase):\n    \"\"\"Test case for many AEA projects.\"\"\"\n\n    @classmethod\n    def setup_class(cls) -> None:\n        \"\"\"Set up the test class.\"\"\"\n        super(AEATestCaseMany, cls).setup_class()\n\n    @classmethod\n    def teardown_class(cls) -> None:\n        \"\"\"Teardown the test class.\"\"\"\n        super(AEATestCaseMany, cls).teardown_class()\n\n\nclass AEATestCaseManyFlaky(AEATestCaseMany):\n    \"\"\"\n    Test case for many AEA projects which are flaky.\n\n    Use for flaky tests with the flaky decorator.\n    \"\"\"\n\n    run_count: int = 0\n\n    @classmethod\n    def setup_class(cls) -> None:\n        \"\"\"Set up the test class.\"\"\"\n        super(AEATestCaseManyFlaky, cls).setup_class()\n        if len(cls.method_list) > 1:  # pragma: nocover\n            raise ValueError(f\"{cls.__name__} can only contain one test method!\")\n        cls.run_count += 1\n\n    @classmethod\n    def teardown_class(cls) -> None:\n        \"\"\"Teardown the test class.\"\"\"\n        super(AEATestCaseManyFlaky, cls).teardown_class()\n\n\nclass AEATestCase(BaseAEATestCase):\n    \"\"\"\n    Test case from an existing AEA project.\n\n    Subclass this class and set `path_to_aea` properly. By default,\n    it is assumed the project is inside the current working directory.\n    \"\"\"\n\n    agent_name = \"\"\n    path_to_aea: Path = Path(\".\")\n    packages_dir_path: Path = Path(\"..\", DEFAULT_REGISTRY_NAME)\n    agent_configuration: Optional[AgentConfig] = None\n    t: Path  # temporary directory path\n\n    @classmethod\n    def setup_class(cls) -> None:\n        \"\"\"Set up the test class.\"\"\"\n        # make paths absolute\n        cls.path_to_aea = cls.path_to_aea.absolute()\n        # load agent configuration\n        with Path(cls.path_to_aea, DEFAULT_AEA_CONFIG_FILE).open(\n            mode=\"r\", encoding=\"utf-8\"\n        ) as fp:\n            loader = ConfigLoader.from_configuration_type(PackageType.AGENT)\n            agent_configuration = loader.load(fp)\n        cls.agent_configuration = agent_configuration\n        cls.agent_name = agent_configuration.agent_name\n\n        # this will create a temporary directory and move into it\n        cls.use_packages_dir = False\n        super(AEATestCase, cls).setup_class()\n\n        # copy the content of the agent into the temporary directory\n        shutil.copytree(str(cls.path_to_aea), str(cls.t / cls.agent_name))\n        cls.set_agent_context(cls.agent_name)\n\n    @classmethod\n    def teardown_class(cls) -> None:\n        \"\"\"Teardown the test class.\"\"\"\n        cls.agent_name = \"\"\n        cls.path_to_aea = Path(\".\")\n        cls.agent_configuration = None\n        super(AEATestCase, cls).teardown_class()\n"
  },
  {
    "path": "aea/test_tools/test_contract.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains test case classes based on pytest for AEA contract testing.\"\"\"\n\nimport time\nfrom abc import ABC, abstractmethod\nfrom pathlib import Path\nfrom typing import Any, Dict, List, Optional, cast\n\nfrom aea.common import JSONLike\nfrom aea.configurations.loader import (\n    ComponentType,\n    ContractConfig,\n    load_component_configuration,\n)\nfrom aea.contracts.base import Contract, contract_registry\nfrom aea.crypto.base import Crypto, FaucetApi, LedgerApi\nfrom aea.crypto.registries import (\n    crypto_registry,\n    faucet_apis_registry,\n    ledger_apis_registry,\n)\n\n\nclass BaseContractTestCase(ABC):\n    \"\"\"A class to test a contract.\"\"\"\n\n    path_to_contract: Path = Path(\".\")\n    ledger_identifier: str = \"\"\n    fund_from_faucet: bool = False\n    _deployment_gas: int = 5000000\n    _contract: Contract\n\n    ledger_api: LedgerApi\n    deployer_crypto: Crypto\n    item_owner_crypto: Crypto\n    faucet_api: FaucetApi\n\n    deployment_tx_receipt: JSONLike\n    contract_address: str\n\n    @property\n    def contract(self) -> Contract:\n        \"\"\"Get the contract.\"\"\"\n        try:\n            value = self._contract\n        except AttributeError:\n            raise ValueError(\"Ensure the contract is set during setup.\")\n        return value\n\n    @classmethod\n    def setup(cls, **kwargs: Any) -> None:\n        \"\"\"Set up the contract test case.\"\"\"\n        if cls.ledger_identifier == \"\":\n            raise ValueError(\"ledger_identifier not set!\")  # pragma: nocover\n\n        _ledger_config: Dict[str, str] = kwargs.pop(\"ledger_config\", {})\n        _deployer_private_key_path: Optional[str] = kwargs.pop(\n            \"deployer_private_key_path\", None\n        )\n        _item_owner_private_key_path: Optional[str] = kwargs.pop(\n            \"item_owner_private_key_path\", None\n        )\n\n        cls.ledger_api = ledger_apis_registry.make(\n            cls.ledger_identifier, **_ledger_config\n        )\n        cls.deployer_crypto = crypto_registry.make(\n            cls.ledger_identifier, private_key_path=_deployer_private_key_path\n        )\n        cls.item_owner_crypto = crypto_registry.make(\n            cls.ledger_identifier, private_key_path=_item_owner_private_key_path\n        )\n        cls.faucet_api = faucet_apis_registry.make(cls.ledger_identifier)\n\n        # Fund from faucet\n        if cls.fund_from_faucet:\n            # Refill deployer account from faucet\n            cls.refill_from_faucet(\n                cls.ledger_api, cls.faucet_api, cls.deployer_crypto.address\n            )\n\n            # Refill item owner account from faucet\n            cls.refill_from_faucet(\n                cls.ledger_api, cls.faucet_api, cls.item_owner_crypto.address\n            )\n\n        # register contract\n        configuration = cast(\n            ContractConfig,\n            load_component_configuration(ComponentType.CONTRACT, cls.path_to_contract),\n        )\n        configuration._directory = (  # pylint: disable=protected-access\n            cls.path_to_contract\n        )\n        if str(configuration.public_id) not in contract_registry.specs:\n            # load contract into sys modules\n            Contract.from_config(configuration)  # pragma: nocover\n        cls._contract = contract_registry.make(str(configuration.public_id))\n\n        # deploy contract\n        cls.deployment_tx_receipt = cls._deploy_contract(\n            cls._contract,\n            cls.ledger_api,\n            cls.deployer_crypto,\n            gas=cls._deployment_gas,\n        )\n\n        cls.contract_address = cls.finish_contract_deployment()\n\n    @classmethod\n    @abstractmethod\n    def finish_contract_deployment(cls) -> str:\n        \"\"\"\n        Finish deploying contract.\n\n        :return: contract address\n        \"\"\"\n\n    @staticmethod\n    def refill_from_faucet(\n        ledger_api: LedgerApi, faucet_api: FaucetApi, address: str\n    ) -> None:\n        \"\"\"Refill from faucet.\"\"\"\n        start_balance = ledger_api.get_balance(address)\n\n        faucet_api.get_wealth(address)\n\n        balance = ledger_api.get_balance(address)\n        if balance == start_balance:\n            raise ValueError(\"Balance not increased!\")  # pragma: nocover\n\n    @staticmethod\n    def sign_send_confirm_receipt_multisig_transaction(\n        tx: JSONLike,\n        ledger_api: LedgerApi,\n        cryptos: List[Crypto],\n        sleep_time: float = 2.0,\n    ) -> JSONLike:\n        \"\"\"\n        Sign, send and confirm settlement of a transaction with multiple signatures.\n\n        :param tx: the transaction\n        :param ledger_api: the ledger api\n        :param cryptos: Cryptos to sign transaction with\n        :param sleep_time: the time to sleep between transaction submission and receipt request\n        :return: The transaction receipt\n        \"\"\"\n        for crypto in cryptos:\n            tx = crypto.sign_transaction(tx)\n        tx_digest = ledger_api.send_signed_transaction(tx)\n\n        if tx_digest is None:\n            raise ValueError(\"Transaction digest not found!\")  # pragma: nocover\n\n        tx_receipt = ledger_api.get_transaction_receipt(tx_digest)\n\n        not_settled = True\n        elapsed_time = 0\n        while not_settled and elapsed_time < 20:\n            elapsed_time += 1\n            time.sleep(sleep_time)\n            tx_receipt = ledger_api.get_transaction_receipt(tx_digest)\n            if tx_receipt is None:\n                continue\n            not_settled = not ledger_api.is_transaction_settled(tx_receipt)\n\n        if tx_receipt is None:\n            raise ValueError(\"Transaction receipt not found!\")  # pragma: nocover\n\n        if not_settled:\n            raise ValueError(  # pragma: nocover\n                f\"Transaction receipt not valid!\\n{tx_receipt['raw_log']}\"\n            )\n\n        return tx_receipt\n\n    @classmethod  # noqa\n    def sign_send_confirm_receipt_transaction(\n        cls,\n        tx: JSONLike,\n        ledger_api: LedgerApi,\n        crypto: Crypto,\n        sleep_time: float = 2.0,\n    ) -> JSONLike:\n        \"\"\"\n        Sign, send and confirm settlement of a transaction with multiple signatures.\n\n        :param tx: the transaction\n        :param ledger_api: the ledger api\n        :param crypto: Crypto to sign transaction with\n        :param sleep_time: the time to sleep between transaction submission and receipt request\n        :return: The transaction receipt\n        \"\"\"\n\n        # BACKWARDS COMPATIBILITY: This method supports only 1 signer and is kept for backwards compatibility.\n        # new method sign_send_confirm_receipt_multisig_transaction should be used always instead of this one.\n        return cls.sign_send_confirm_receipt_multisig_transaction(\n            tx, ledger_api, [crypto], sleep_time\n        )\n\n    @classmethod\n    def _deploy_contract(\n        cls,\n        contract: Contract,\n        ledger_api: LedgerApi,\n        deployer_crypto: Crypto,\n        gas: int,\n    ) -> JSONLike:\n        \"\"\"\n        Deploy contract on network.\n\n        :param contract: the contract\n        :param ledger_api: the ledger api\n        :param deployer_crypto: the contract deployer crypto\n        :param gas: the gas amount\n\n        :return: the transaction receipt for initial transaction deployment\n        \"\"\"\n        tx = contract.get_deploy_transaction(\n            ledger_api=ledger_api,\n            deployer_address=deployer_crypto.address,\n            gas=gas,\n        )\n\n        if tx is None:\n            raise ValueError(\"Deploy transaction not found!\")  # pragma: nocover\n\n        tx_receipt = cls.sign_send_confirm_receipt_multisig_transaction(\n            tx, ledger_api, [deployer_crypto]\n        )\n\n        return tx_receipt\n"
  },
  {
    "path": "aea/test_tools/test_skill.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains test case classes based on pytest for AEA skill testing.\"\"\"\nimport asyncio\nimport os\nfrom pathlib import Path\nfrom queue import Queue\nfrom types import SimpleNamespace\nfrom typing import Any, Dict, Optional, Tuple, Type, cast\n\nfrom aea.configurations.loader import ConfigLoaders, PackageType, SkillConfig\nfrom aea.context.base import AgentContext\nfrom aea.crypto.ledger_apis import DEFAULT_CURRENCY_DENOMINATIONS\nfrom aea.exceptions import AEAEnforceError\nfrom aea.helpers.io import open_file\nfrom aea.identity.base import Identity\nfrom aea.mail.base import Address\nfrom aea.multiplexer import AsyncMultiplexer, Multiplexer, OutBox\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue, DialogueMessage, Dialogues\nfrom aea.skills.base import Skill\nfrom aea.skills.tasks import TaskManager\n\n\nCOUNTERPARTY_AGENT_ADDRESS = \"counterparty\"\nCOUNTERPARTY_SKILL_ADDRESS = \"some_author/some_skill:0.1.0\"\n\n\nclass BaseSkillTestCase:\n    \"\"\"A class to test a skill.\"\"\"\n\n    path_to_skill: Path = Path(\".\")\n    is_agent_to_agent_messages: bool = True\n    _skill: Skill\n    _multiplexer: AsyncMultiplexer\n    _outbox: OutBox\n\n    @property\n    def skill(self) -> Skill:\n        \"\"\"Get the skill.\"\"\"\n        try:\n            value = self._skill\n        except AttributeError:\n            raise ValueError(\"Ensure skill is set during setup_class.\")\n        return value\n\n    def get_quantity_in_outbox(self) -> int:\n        \"\"\"Get the quantity of envelopes in the outbox.\"\"\"\n        return self._multiplexer.out_queue.qsize()\n\n    def get_message_from_outbox(self) -> Optional[Message]:\n        \"\"\"Get message from outbox.\"\"\"\n        if self._outbox.empty():\n            return None\n        envelope = self._multiplexer.out_queue.get_nowait()\n        return envelope.message\n\n    def drop_messages_from_outbox(self, number: int = 1) -> None:\n        \"\"\"Dismiss the first 'number' number of message from outbox.\"\"\"\n        while (not self._outbox.empty()) and number != 0:\n            self._multiplexer.out_queue.get_nowait()\n            number -= 1\n\n    def get_quantity_in_decision_maker_inbox(self) -> int:\n        \"\"\"Get the quantity of messages in the decision maker inbox.\"\"\"\n        return self._skill.skill_context.decision_maker_message_queue.qsize()\n\n    def get_message_from_decision_maker_inbox(self) -> Optional[Message]:\n        \"\"\"Get message from decision maker inbox.\"\"\"\n        if self._skill.skill_context.decision_maker_message_queue.empty():\n            return None\n        return self._skill.skill_context.decision_maker_message_queue.get_nowait()\n\n    def drop_messages_from_decision_maker_inbox(self, number: int = 1) -> None:\n        \"\"\"Dismiss the first 'number' number of message from decision maker inbox.\"\"\"\n        while (\n            not self._skill.skill_context.decision_maker_message_queue.empty()\n        ) and number != 0:\n            self._skill.skill_context.decision_maker_message_queue.get_nowait()\n            number -= 1\n\n    def assert_quantity_in_outbox(self, expected_quantity: int) -> None:\n        \"\"\"Assert the quantity of messages in the outbox.\"\"\"\n        quantity = self.get_quantity_in_outbox()\n        assert (  # nosec\n            quantity == expected_quantity\n        ), f\"Invalid number of messages in outbox. Expected {expected_quantity}. Found {quantity}.\"\n\n    def assert_quantity_in_decision_making_queue(self, expected_quantity: int) -> None:\n        \"\"\"Assert the quantity of messages in the decision maker queue.\"\"\"\n        quantity = self.get_quantity_in_decision_maker_inbox()\n        assert (  # nosec\n            quantity == expected_quantity\n        ), f\"Invalid number of messages in decision maker queue. Expected {expected_quantity}. Found {quantity}.\"\n\n    @staticmethod\n    def message_has_attributes(\n        actual_message: Message,\n        message_type: Type[Message],\n        **kwargs: Any,\n    ) -> Tuple[bool, str]:\n        \"\"\"\n        Evaluates whether a message's attributes match the expected attributes provided.\n\n        :param actual_message: the actual message\n        :param message_type: the expected message type\n        :param kwargs: other expected message attributes\n\n        :return: boolean result of the evaluation and accompanied message\n        \"\"\"\n        if (\n            type(actual_message)  # pylint: disable=unidiomatic-typecheck\n            != message_type\n        ):\n            return (\n                False,\n                \"The message types do not match. Actual type: {}. Expected type: {}\".format(\n                    type(actual_message), message_type\n                ),\n            )\n\n        for attribute_name, expected_value in kwargs.items():\n            actual_value = getattr(actual_message, attribute_name)\n            if actual_value != expected_value:\n                return (\n                    False,\n                    f\"The '{attribute_name}' fields do not match. Actual '{attribute_name}': {actual_value}. Expected '{attribute_name}': {expected_value}\",\n                )\n\n        return True, \"The message has the provided expected attributes.\"\n\n    def build_incoming_message(\n        self,\n        message_type: Type[Message],\n        performative: Message.Performative,\n        dialogue_reference: Optional[Tuple[str, str]] = None,\n        message_id: Optional[int] = None,\n        target: Optional[int] = None,\n        to: Optional[Address] = None,\n        sender: Optional[Address] = None,\n        is_agent_to_agent_messages: Optional[bool] = None,\n        **kwargs: Any,\n    ) -> Message:\n        \"\"\"\n        Quickly create an incoming message with the provided attributes.\n\n        For any attribute not provided, the corresponding default value in message is used.\n\n        :param message_type: the type of the message\n        :param dialogue_reference: the dialogue_reference\n        :param message_id: the message_id\n        :param target: the target\n        :param performative: the performative\n        :param to: the 'to' address\n        :param sender: the 'sender' address\n        :param is_agent_to_agent_messages: whether the dialogue is between agents or components\n        :param kwargs: other attributes\n\n        :return: the created incoming message\n        \"\"\"\n        if is_agent_to_agent_messages is None:\n            is_agent_to_agent_messages = self.is_agent_to_agent_messages\n        if sender is None:\n            sender = (\n                COUNTERPARTY_AGENT_ADDRESS\n                if is_agent_to_agent_messages\n                else COUNTERPARTY_SKILL_ADDRESS\n            )\n        message_attributes = {}  # type: Dict[str, Any]\n\n        default_dialogue_reference = Dialogues.new_self_initiated_dialogue_reference()\n        dialogue_reference = (\n            default_dialogue_reference\n            if dialogue_reference is None\n            else dialogue_reference\n        )\n        message_attributes[\"dialogue_reference\"] = dialogue_reference\n        if message_id is not None:\n            message_attributes[\"message_id\"] = message_id\n        if target is not None:\n            message_attributes[\"target\"] = target\n        message_attributes[\"performative\"] = performative\n        message_attributes.update(kwargs)\n\n        incoming_message = message_type(**message_attributes)\n        incoming_message.sender = sender\n        default_to = (\n            self.skill.skill_context.agent_address\n            if is_agent_to_agent_messages\n            else str(self.skill.public_id)\n        )\n        incoming_message.to = default_to if to is None else to\n        return incoming_message\n\n    def build_incoming_message_for_skill_dialogue(\n        self,\n        dialogue: Dialogue,\n        performative: Message.Performative,\n        message_type: Optional[Type[Message]] = None,\n        dialogue_reference: Optional[Tuple[str, str]] = None,\n        message_id: Optional[int] = None,\n        target: Optional[int] = None,\n        to: Optional[Address] = None,\n        sender: Optional[Address] = None,\n        **kwargs: Any,\n    ) -> Message:\n        \"\"\"\n        Quickly create an incoming message with the provided attributes for a dialogue.\n\n        For any attribute not provided, a value based on the dialogue is used.\n        These values are shown in parentheses in the list of parameters below.\n\n        NOTE: This method must be used with care. The dialogue provided is part of the skill\n        which is being tested. Because for any unspecified attribute, a \"correct\" value is used,\n        the test will be, by design, insured to pass on these values.\n\n        :param dialogue: the dialogue to which the incoming message is intended\n        :param performative: the performative of the message\n        :param message_type: (the message_class of the provided dialogue) the type of the message\n        :param dialogue_reference: (the dialogue_reference of the provided dialogue) the dialogue reference of the message\n        :param message_id: (the id of the last message in the provided dialogue + 1) the id of the message\n        :param target: (the id of the last message in the provided dialogue) the target of the message\n        :param to: (the agent address associated with this skill) the receiver of the message\n        :param sender: (the counterparty in the provided dialogue) the sender of the message\n        :param kwargs: other attributes\n\n        :return: the created incoming message\n        \"\"\"\n        if dialogue is None:\n            raise AEAEnforceError(\"dialogue cannot be None.\")\n\n        if dialogue.last_message is None:\n            raise AEAEnforceError(\"dialogue cannot be empty.\")\n\n        message_type = (\n            message_type if message_type is not None else dialogue.message_class\n        )\n        dialogue_reference = (\n            dialogue_reference\n            if dialogue_reference is not None\n            else dialogue.dialogue_label.dialogue_reference\n        )\n        message_id = (\n            message_id\n            if message_id is not None\n            else dialogue.get_incoming_next_message_id()\n        )\n        target = target if target is not None else dialogue.last_message.message_id\n        to = to if to is not None else dialogue.self_address\n        sender = (\n            sender\n            if sender is not None\n            else dialogue.dialogue_label.dialogue_opponent_addr\n        )\n\n        incoming_message = self.build_incoming_message(\n            message_type=message_type,\n            performative=performative,\n            dialogue_reference=dialogue_reference,\n            message_id=message_id,\n            target=target,\n            to=to,\n            sender=sender,\n            **kwargs,\n        )\n        return incoming_message\n\n    @staticmethod\n    def _provide_unspecified_fields(\n        message: DialogueMessage, last_is_incoming: Optional[bool]\n    ) -> Tuple[bool, Optional[int]]:\n        \"\"\"\n        Specifies values (an interpretation) for the unspecified fields of a DialogueMessage.\n\n        For an unspecified is_incoming, the opposite of the last_is_incoming value is used.\n        For an unspecified target, the message_id of the previous message (message_id - 1) is used.\n\n        :param message: the DialogueMessage\n        :param last_is_incoming: the is_incoming value of the previous DialogueMessage\n\n        :return: the is_incoming and target values\n        \"\"\"\n        default_is_incoming = not last_is_incoming\n        is_incoming = default_is_incoming if message[2] is None else message[2]\n\n        default_target = None\n        target = default_target if message[3] is None else message[3]\n        return is_incoming, target\n\n    @staticmethod\n    def _non_initial_incoming_message_dialogue_reference(\n        dialogue: Dialogue,\n    ) -> Tuple[str, str]:\n        \"\"\"\n        Specifies the dialogue reference of a non-initial incoming message for a dialogue.\n\n        It uses a complete version of the reference in the dialogue if it is incomplete,\n        otherwise it uses the reference in the dialogue.\n\n        :param dialogue: the dialogue to which the incoming message is intended\n        :return: its dialogue reference\n        \"\"\"\n        dialogue_reference = (\n            dialogue.dialogue_label.dialogue_reference[0],\n            Dialogues._generate_dialogue_nonce()  # pylint: disable=protected-access\n            if dialogue.dialogue_label.dialogue_reference[1]\n            == Dialogue.UNASSIGNED_DIALOGUE_REFERENCE\n            else dialogue.dialogue_label.dialogue_reference[1],\n        )\n        return dialogue_reference\n\n    def _extract_message_fields(\n        self,\n        message: DialogueMessage,\n        index: int,\n        last_is_incoming: bool,\n    ) -> Tuple[Message.Performative, Dict, int, bool, Optional[int]]:\n        \"\"\"\n        Extracts message attributes from a dialogue message.\n\n        :param message: the dialogue message\n        :param index: the index of this dialogue message in the sequence of messages\n        :param last_is_incoming: the is_incoming of the last message in the sequence\n\n        :return: the performative, contents, message_id, is_incoming, target of the message\n        \"\"\"\n        performative = message[0]\n        contents = message[1]\n        message_id = index + 1\n        is_incoming, target = self._provide_unspecified_fields(\n            message, last_is_incoming=last_is_incoming\n        )\n        return performative, contents, message_id, is_incoming, target\n\n    def prepare_skill_dialogue(\n        self,\n        dialogues: Dialogues,\n        messages: Tuple[DialogueMessage, ...],\n        counterparty: Optional[Address] = None,\n        is_agent_to_agent_messages: Optional[bool] = None,\n    ) -> Dialogue:\n        \"\"\"\n        Quickly create a dialogue.\n\n        The 'messages' argument is a tuple of DialogueMessages.\n        For every DialogueMessage (performative, contents, is_incoming, target):\n            - if 'is_incoming' is not provided: for the first message it is assumed False (outgoing),\n            for any other message, it is the opposite of the one preceding it.\n            - if 'target' is not provided: for the first message it is assumed 0,\n            for any other message, it is the index of the message before it in the tuple of messages + 1.\n\n        :param dialogues: a dialogues class\n        :param counterparty: the message_id\n        :param messages: the dialogue_reference\n        :param is_agent_to_agent_messages: whether the dialogue is between agents or components\n\n        :return: the created incoming message\n        \"\"\"\n        if is_agent_to_agent_messages is None:\n            is_agent_to_agent_messages = self.is_agent_to_agent_messages\n        if counterparty is None:\n            counterparty = (  # pragma: nocover\n                COUNTERPARTY_AGENT_ADDRESS\n                if is_agent_to_agent_messages\n                else COUNTERPARTY_SKILL_ADDRESS\n            )\n        if len(messages) == 0:\n            raise AEAEnforceError(\"the list of messages must be positive.\")\n\n        (\n            performative,\n            contents,\n            message_id,\n            is_incoming,\n            target,\n        ) = self._extract_message_fields(messages[0], index=0, last_is_incoming=True)\n\n        if is_incoming:  # first message from the opponent\n            dialogue_reference = dialogues.new_self_initiated_dialogue_reference()\n            message = self.build_incoming_message(\n                message_type=dialogues.message_class,\n                dialogue_reference=dialogue_reference,\n                message_id=Dialogue.STARTING_MESSAGE_ID,\n                target=target or Dialogue.STARTING_TARGET,\n                performative=performative,\n                to=dialogues.self_address,\n                sender=counterparty,\n                is_agent_to_agent_messages=is_agent_to_agent_messages,\n                **contents,\n            )\n            dialogue = cast(Dialogue, dialogues.update(message))\n            if dialogue is None:\n                raise AEAEnforceError(\n                    \"Cannot update the dialogue with message number {}\".format(\n                        message_id\n                    )\n                )\n        else:  # first message from self\n            _, dialogue = dialogues.create(\n                counterparty=counterparty, performative=performative, **contents\n            )\n\n        for idx, dialogue_message in enumerate(messages[1:]):\n            (\n                performative,\n                contents,\n                message_id,\n                is_incoming,\n                target,\n            ) = self._extract_message_fields(dialogue_message, idx + 1, is_incoming)\n            if target is None:\n                target = cast(Message, dialogue.last_message).message_id\n\n            if is_incoming:  # messages from the opponent\n                dialogue_reference = (\n                    self._non_initial_incoming_message_dialogue_reference(dialogue)\n                )\n                message_id = dialogue.get_incoming_next_message_id()\n\n                message = self.build_incoming_message(\n                    message_type=dialogues.message_class,\n                    dialogue_reference=dialogue_reference,\n                    message_id=message_id,\n                    target=target,\n                    performative=performative,\n                    to=dialogues.self_address,\n                    sender=counterparty,\n                    is_agent_to_agent_messages=is_agent_to_agent_messages,\n                    **contents,\n                )\n                dialogue = cast(Dialogue, dialogues.update(message))\n                if dialogue is None:\n                    raise AEAEnforceError(\n                        \"Cannot update the dialogue with message number {}\".format(\n                            message_id\n                        )\n                    )\n            else:  # messages from self\n                dialogue.reply(performative=performative, target=target, **contents)\n\n        return dialogue\n\n    @classmethod\n    def setup(cls, **kwargs: Any) -> None:\n        \"\"\"Set up the skill test case.\"\"\"\n        identity = Identity(\n            \"test_agent_name\", \"test_agent_address\", \"test_agent_public_key\"\n        )\n\n        cls._multiplexer = AsyncMultiplexer()\n        cls._multiplexer._out_queue = (  # pylint: disable=protected-access\n            asyncio.Queue()\n        )\n        cls._outbox = OutBox(cast(Multiplexer, cls._multiplexer))\n        _shared_state = cast(Optional[Dict[str, Any]], kwargs.pop(\"shared_state\", None))\n        _skill_config_overrides = cast(\n            Optional[Dict[str, Any]], kwargs.pop(\"config_overrides\", None)\n        )\n        _dm_context_kwargs = cast(\n            Dict[str, Any], kwargs.pop(\"dm_context_kwargs\", dict())\n        )\n\n        agent_context = AgentContext(\n            identity=identity,\n            connection_status=cls._multiplexer.connection_status,\n            outbox=cls._outbox,\n            decision_maker_message_queue=Queue(),\n            decision_maker_handler_context=SimpleNamespace(**_dm_context_kwargs),\n            task_manager=TaskManager(),\n            default_ledger_id=identity.default_address_key,\n            currency_denominations=DEFAULT_CURRENCY_DENOMINATIONS,\n            default_connection=None,\n            default_routing={},\n            search_service_address=\"dummy_author/dummy_search_skill:0.1.0\",\n            decision_maker_address=\"dummy_decision_maker_address\",\n            data_dir=os.getcwd(),\n        )\n\n        # Pre-populate the 'shared_state' prior to loading the skill\n        if _shared_state is not None:\n            for key, value in _shared_state.items():\n                agent_context.shared_state[key] = value\n\n        skill_configuration_file_path: Path = Path(cls.path_to_skill, \"skill.yaml\")\n        loader = ConfigLoaders.from_package_type(PackageType.SKILL)\n\n        with open_file(skill_configuration_file_path) as fp:\n            skill_config: SkillConfig = loader.load(fp)\n\n        # Override skill's config prior to loading\n        if _skill_config_overrides is not None:\n            skill_config.update(_skill_config_overrides)\n\n        skill_config.directory = cls.path_to_skill\n\n        cls._skill = Skill.from_config(skill_config, agent_context)\n"
  },
  {
    "path": "benchmark/Dockerfile",
    "content": "FROM python:3.8-alpine\n\nENV PYTHONPATH \"$PYTHONPATH:/usr/lib/python3.8/site-packages\"\nRUN apk add --no-cache make git bash wget\nRUN apk add --no-cache gcc musl-dev python3-dev libffi-dev openssl-dev\nRUN apk add --update --no-cache py3-numpy py3-scipy py3-pillow\nRUN apk add --update --no-cache gfortran freetype-dev libpng-dev openblas-dev g++ py3-numpy-dev\nRUN apk add --no-cache go rust cargo\n\nRUN pip install --upgrade pip pipenv\nRUN pip install aea[all] --upgrade --force-reinstall\n\nRUN wget https://raw.githubusercontent.com/fetchai/agents-aea/main/Pipfile\nRUN pipenv install -d --deploy --skip-lock --system\nRUN pip install --no-deps  aea-ledger-fetchai\nRUN pip install --no-deps  aea-ledger-cosmos\nRUN pip install --no-deps  aea-ledger-ethereum\n"
  },
  {
    "path": "benchmark/README.md",
    "content": "# Benchmarks\n\n## Running a benchmark locally\n\nFirst, set permissions:\n\n``` bash\nchmod +x /benchmark/checks/run_benchmark.sh\n```\n\nThen, run:\n\n``` bash\n./benchmark/checks/run_benchmark.sh\n```\n\nor to save to file:\n\n``` bash\n./benchmark/checks/run_benchmark.sh | tee benchmark.txt\n```\n\nThe benchmark will use the locally installed AEA version!\n\n## Deploying a benchmark run and serving results\n\nFirst remove any old configuration maps and create a new one:\n\n``` bash\nkubectl delete configmap run-benchmark\nkubectl create configmap run-benchmark --from-file=run_from_branch.sh\n```\n\nTo remove old nodes (auto-restarts new node):\n\n``` bash\nkubectl delete pod NODE_NAME\n```\n\nTo completely remove:\n\n``` bash\nkubectl delete deployment benchmark\n```\n\nTo deploy:\n\n``` bash\nkubectl apply -f benchmark-deployment.yaml\n```\n\nList pods:\n\n``` bash\nkubectl get pod -o wide\n```\n\nTo access NGINX (wait for status: ``):\n\n``` bash\nkubectl port-forward NODE_NAME 8000:80\n```\n\nthen\n\n``` bash\ncurl localhost:8000 | tee results.txt\n```\n"
  },
  {
    "path": "benchmark/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Performance testing framework.\"\"\"\n"
  },
  {
    "path": "benchmark/benchmark-deployment.yaml",
    "content": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: benchmark\nspec:\n  selector:\n    matchLabels:\n      app: benchmark\n  replicas: 1\n  template:\n    metadata:\n      labels:\n        app: benchmark\n      namespace: aea-research\n    spec:\n      tolerations:\n      - key: dedicated\n        operator: Equal\n        value: agent\n        effect: NoSchedule\n      nodeSelector:\n        # type: agent-test\n        kubernetes.io/os: linux\n      initContainers:\n      - name: python\n        image: python:3.8-buster\n        command: ['sh', '-c', 'bash /app/run_from_branch.sh | tee /data/index.html']\n        volumeMounts:\n        - name: benchmark-data\n          mountPath: /data\n        - name: benchmark-script\n          mountPath: /app\n\n      containers:\n      - name: benchmark\n        image: nginx:1.18.0\n        volumeMounts:\n        - name: benchmark-data\n          mountPath: /usr/share/nginx/html\n        - name: benchmark-script\n          mountPath: /app\n\n      volumes:\n      - name: benchmark-data\n        persistentVolumeClaim:\n          claimName: benchmark-vol\n      - name: benchmark-script\n        persistentVolumeClaim:\n          claimName: benchmark-scripts-vol\n\n---\napiVersion: v1\nkind: PersistentVolumeClaim\nmetadata:\n  name: benchmark-vol\nspec:\n  accessModes:\n    - ReadWriteOnce\n  resources:\n    requests:\n      storage: 10Gi\n---\napiVersion: v1\nkind: PersistentVolumeClaim\nmetadata:\n  name: benchmark-scripts-vol\nspec:\n  accessModes:\n    - ReadWriteOnce\n  resources:\n    requests:\n      storage: 1Gi\n"
  },
  {
    "path": "benchmark/cases/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Simple cases for performance tests.\"\"\"\n"
  },
  {
    "path": "benchmark/cases/cpu_burn.py",
    "content": "#!/usr/bin/ev python3\n# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Example performance test using benchmark framework. Just test CPU usage with empty while loop.\"\"\"\nimport time\n\nfrom benchmark.framework.benchmark import BenchmarkControl\nfrom benchmark.framework.cli import TestCli\n\n\ndef cpu_burn(\n    benchmark: BenchmarkControl, run_time: int = 10, sleep: float = 0.0001\n) -> None:\n    \"\"\"\n    Do nothing, just burn cpu to check cpu load changed on sleep.\n\n    :param benchmark: benchmark special parameter to communicate with executor\n    :param run_time: time limit to run this function\n    :param sleep: time to sleep in loop\n    \"\"\"\n    benchmark.start()\n    start_time = time.time()\n\n    while True:\n        time.sleep(sleep)\n        if time.time() - start_time >= run_time:\n            break\n\n\nif __name__ == \"__main__\":\n    TestCli(cpu_burn).run()\n"
  },
  {
    "path": "benchmark/cases/helpers/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Helpers to make cases easier.\"\"\"\n"
  },
  {
    "path": "benchmark/cases/helpers/dummy_handler.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Dummy handler to use in test skills.\"\"\"\nfrom random import randint\n\nfrom aea.protocols.base import Message\nfrom aea.skills.base import Handler\n\nfrom packages.fetchai.protocols.default.message import DefaultMessage\n\n\nclass DummyHandler(Handler):\n    \"\"\"Dummy handler to handle messages.\"\"\"\n\n    SUPPORTED_PROTOCOL = DefaultMessage.protocol_id\n\n    def setup(self) -> None:\n        \"\"\"Noop setup.\"\"\"\n\n    def teardown(self) -> None:\n        \"\"\"Noop teardown.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"Handle incoming message, actually noop.\"\"\"\n        randint(1, 100) + randint(  # nosec # pylint: disable=expression-not-assigned\n            1, 100\n        )\n"
  },
  {
    "path": "benchmark/cases/react_multi_agents_fake_connection.py",
    "content": "#!/usr/bin/ev python3\n# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"\nExample performance test using benchmark framework.\n\nTest react speed on amount of incoming messages using normal agent operating.\nMessages are generated by fake connection.\n\"\"\"\nimport time\n\nfrom aea.configurations.base import SkillConfig\nfrom aea.skills.base import Skill\nfrom benchmark.cases.helpers.dummy_handler import DummyHandler\nfrom benchmark.framework.aea_test_wrapper import AEATestWrapper\nfrom benchmark.framework.benchmark import BenchmarkControl\nfrom benchmark.framework.cli import TestCli\n\n\ndef _make_custom_config(name: str = \"dummy_agent\", skills_num: int = 1) -> dict:\n    \"\"\"\n    Construct config for test wrapper.\n\n    :param name: agent's name\n    :param skills_num: number of skills to add to agent\n\n    :return: dict to be used in AEATestWrapper(**result)\n    \"\"\"\n    # noqa\n    def _make_skill(id_: int) -> Skill:\n        return AEATestWrapper.make_skill(\n            config=SkillConfig(name=f\"sc{id_}\", author=\"fetchai\"),\n            handlers={\"dummy_handler\": DummyHandler},\n        )\n\n    return {\n        \"name\": name,\n        \"components\": [_make_skill(i) for i in range(skills_num)],\n    }\n\n\ndef react_speed_in_loop(\n    benchmark: BenchmarkControl,\n    agents_num: int = 1,\n    skills_num: int = 1,\n    inbox_num: int = 5000,\n    agent_loop_timeout: float = 0.01,\n) -> None:\n    \"\"\"\n    Test inbox message processing in a loop.\n\n    Messages are generated by fake connection.\n\n    :param benchmark: benchmark special parameter to communicate with executor\n    :param agents_num: number of agents to start\n    :param skills_num: number of skills to add to each agent\n    :param inbox_num: number of inbox messages for every agent\n    :param agent_loop_timeout: idle sleep time for agent's loop\n    \"\"\"\n    wrappers = []\n    envelope = AEATestWrapper.dummy_envelope()\n\n    for i in range(agents_num):\n        aea_test_wrapper = AEATestWrapper(\n            **_make_custom_config(f\"agent{i}\", skills_num)\n        )\n        aea_test_wrapper.set_loop_timeout(agent_loop_timeout)\n        aea_test_wrapper.set_fake_connection(inbox_num, envelope)\n        wrappers.append(aea_test_wrapper)\n\n    benchmark.start()\n\n    for aea_test_wrapper in wrappers:\n        aea_test_wrapper.start_loop()\n\n    try:\n        # wait all messages are pushed to inboxes\n        while sum(i.is_messages_in_fake_connection() for i in wrappers):\n            time.sleep(0.01)\n\n        # wait all messages are consumed from inboxes\n        while sum(not i.is_inbox_empty() for i in wrappers):\n            time.sleep(0.01)\n    finally:\n        for aea_test_wrapper in wrappers:\n            aea_test_wrapper.stop_loop()\n\n\nif __name__ == \"__main__\":\n    TestCli(react_speed_in_loop).run()\n"
  },
  {
    "path": "benchmark/cases/react_speed_in_loop.py",
    "content": "#!/usr/bin/ev python3\n# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Example performance test using benchmark framework. Test react speed on amount of incoming messages using normal agent operating.\"\"\"\nimport time\n\nfrom benchmark.cases.helpers.dummy_handler import DummyHandler\nfrom benchmark.framework.aea_test_wrapper import AEATestWrapper\nfrom benchmark.framework.benchmark import BenchmarkControl\nfrom benchmark.framework.cli import TestCli\n\n\ndef react_speed_in_loop(benchmark: BenchmarkControl, inbox_amount: int = 1000) -> None:\n    \"\"\"\n    Test inbox message processing in a loop.\n\n    :param benchmark: benchmark special parameter to communicate with executor\n    :param inbox_amount: number of inbox messages for every agent\n    \"\"\"\n    aea_test_wrapper = AEATestWrapper(\n        name=\"dummy agent\",\n        components=[\n            AEATestWrapper.make_skill(handlers={\"dummy_handler\": DummyHandler})\n        ],\n    )\n\n    for _ in range(inbox_amount):\n        aea_test_wrapper.put_inbox(aea_test_wrapper.dummy_envelope())\n\n    aea_test_wrapper.set_loop_timeout(0.0)\n\n    benchmark.start()\n\n    aea_test_wrapper.start_loop()\n\n    while not aea_test_wrapper.is_inbox_empty():\n        time.sleep(0.1)\n\n    aea_test_wrapper.stop_loop()\n\n\nif __name__ == \"__main__\":\n    TestCli(react_speed_in_loop).run()\n"
  },
  {
    "path": "benchmark/cases/react_speed_multi_agents.py",
    "content": "#!/usr/bin/ev python3\n# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Example performance test using benchmark framework. Test react speed on amount of incoming messages using normal agent operating.\"\"\"\nimport time\n\nfrom aea.configurations.base import SkillConfig\nfrom aea.skills.base import Skill\nfrom benchmark.cases.helpers.dummy_handler import DummyHandler\nfrom benchmark.framework.aea_test_wrapper import AEATestWrapper\nfrom benchmark.framework.benchmark import BenchmarkControl\nfrom benchmark.framework.cli import TestCli\n\n\ndef _make_custom_config(name: str = \"dummy_agent\", skills_num: int = 1) -> dict:\n    \"\"\"\n    Construct config for test wrapper.\n\n    :param name: agent's name\n    :param skills_num: number of skills to add to agent\n\n    :return: dict to be used in AEATestWrapper(**result)\n    \"\"\"\n    # noqa\n    def _make_skill(id_: int) -> Skill:\n        return AEATestWrapper.make_skill(\n            config=SkillConfig(name=f\"sc{id_}\", author=\"fetchai\"),\n            handlers={\"dummy_handler\": DummyHandler},\n        )\n\n    return {\n        \"name\": name,\n        \"components\": [_make_skill(i) for i in range(skills_num)],\n    }\n\n\ndef react_speed_in_loop(\n    benchmark: BenchmarkControl,\n    agents_num: int = 2,\n    skills_num: int = 1,\n    inbox_num: int = 1000,\n    agent_loop_timeout: float = 0.01,\n) -> None:\n    \"\"\"\n    Test inbox message processing in a loop.\n\n    :param benchmark: benchmark special parameter to communicate with executor\n    :param agents_num: number of agents to start\n    :param skills_num: number of skills to add to each agent\n    :param inbox_num: number of inbox messages for every agent\n    :param agent_loop_timeout: idle sleep time for agent's loop\n    \"\"\"\n    aea_test_wrappers = []\n\n    for i in range(agents_num):\n        aea_test_wrapper = AEATestWrapper(\n            **_make_custom_config(f\"agent{i}\", skills_num)\n        )\n        aea_test_wrapper.set_loop_timeout(agent_loop_timeout)\n        aea_test_wrappers.append(aea_test_wrapper)\n\n        for _ in range(inbox_num):\n            aea_test_wrapper.put_inbox(aea_test_wrapper.dummy_envelope())\n\n    benchmark.start()\n\n    for aea_test_wrapper in aea_test_wrappers:\n        aea_test_wrapper.start_loop()\n\n    try:\n        while sum((not i.is_inbox_empty() for i in aea_test_wrappers)):\n            time.sleep(0.1)\n\n    finally:\n        # wait to start, Race condition in case no messages to process\n        while sum(not i.is_running() for i in aea_test_wrappers):\n            pass\n        for aea_test_wrapper in aea_test_wrappers:\n            aea_test_wrapper.stop_loop()\n\n\nif __name__ == \"__main__\":\n    TestCli(react_speed_in_loop).run()\n"
  },
  {
    "path": "benchmark/checks/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Performance checks..\"\"\"\n"
  },
  {
    "path": "benchmark/checks/check_agent_construction_time.py",
    "content": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Check amount of time and mem for agent setup.\"\"\"\nimport os\nimport shutil\nimport time\nfrom pathlib import Path\nfrom statistics import mean\nfrom tempfile import TemporaryDirectory\nfrom typing import Any, List, Tuple, Union\n\nimport click\nfrom click.testing import CliRunner\n\nfrom aea.aea_builder import AEABuilder\nfrom aea.cli.core import cli\nfrom benchmark.checks.utils import (\n    get_mem_usage_in_mb,\n    multi_run,\n    number_of_runs_deco,\n    output_format_deco,\n    print_results,\n)\n\n\nPACKAGES = Path(__file__).parent / \"../../packages\"\nPROJECT_PATH = str(PACKAGES / \"fetchai/agents/my_first_aea\")\n\n\ndef run(agents: int) -> List[Tuple[str, Union[int, float]]]:\n    \"\"\"Check construction time and memory usage.\"\"\"\n    load_times = []\n    full_times = []\n    with TemporaryDirectory() as tmp_dir:\n        agent_dir = Path(tmp_dir) / \"agent\"\n        shutil.copytree(PROJECT_PATH, agent_dir)\n        shutil.copytree(PACKAGES, agent_dir / \"vendor\")\n        os.chdir(agent_dir)\n        if (\n            CliRunner()\n            .invoke(cli, [\"generate-key\", \"fetchai\"], catch_exceptions=False)\n            .exit_code\n            != 0\n        ):\n            raise Exception(\"generate-key failed\")\n        if (\n            CliRunner()\n            .invoke(cli, [\"add-key\", \"fetchai\"], catch_exceptions=False)\n            .exit_code\n            != 0\n        ):\n            raise Exception(\"add-key failed\")\n        agents_list = []\n        env_mem_usage = get_mem_usage_in_mb()\n        for _ in range(agents):\n            start_time = time.time()\n            builder = AEABuilder.from_aea_project(agent_dir)\n            load_times.append(time.time() - start_time)\n            agents_list.append(builder.build())\n            full_times.append(time.time() - start_time)\n        mem_usage = get_mem_usage_in_mb()\n\n    return [\n        (\"avg config load time\", mean(load_times)),\n        (\"avg full construction\", mean(full_times)),\n        (\"avg build time\", mean(full_times) - mean(load_times)),\n        (\"agent mem usage (Mb)\", mem_usage - env_mem_usage),\n    ]\n\n\n@click.command()\n@click.option(\"--agents\", default=25, help=\"Amount of agents to construct.\")\n@number_of_runs_deco\n@output_format_deco\ndef main(agents: int, number_of_runs: int, output_format: str) -> Any:\n    \"\"\"Check agents construction time and memory usage.\"\"\"\n    parameters = {\"Agents\": agents, \"Number of runs\": number_of_runs}\n\n    def result_fn() -> List[Tuple[str, Any, Any, Any]]:\n        return multi_run(\n            int(number_of_runs),\n            run,\n            (agents,),\n        )\n\n    return print_results(output_format, parameters, result_fn)\n\n\nif __name__ == \"__main__\":\n    main()  # pylint: disable=no-value-for-parameter\n"
  },
  {
    "path": "benchmark/checks/check_decision_maker.py",
    "content": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Memory usage check.\"\"\"\nimport time\nfrom pathlib import Path\nfrom tempfile import TemporaryDirectory\nfrom typing import Any, List, Tuple, Union\nfrom unittest.mock import patch\n\nimport click\n\nfrom aea.common import Address\nfrom aea.configurations.data_types import PublicId\nfrom aea.crypto.registries import make_crypto, make_ledger_api\nfrom aea.crypto.wallet import Wallet\nfrom aea.decision_maker.base import DecisionMaker\nfrom aea.decision_maker.default import DecisionMakerHandler\nfrom aea.helpers.transaction.base import RawTransaction, Terms\nfrom aea.identity.base import Identity\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\nfrom benchmark.checks.utils import (\n    get_mem_usage_in_mb,\n    multi_run,\n    number_of_runs_deco,\n    output_format_deco,\n    print_results,\n)\n\nfrom packages.fetchai.protocols.signing.dialogues import SigningDialogue\nfrom packages.fetchai.protocols.signing.dialogues import (\n    SigningDialogues as BaseSigningDialogues,\n)\nfrom packages.fetchai.protocols.signing.message import SigningMessage\n\n\nclass SigningDialogues(BaseSigningDialogues):\n    \"\"\"This class keeps track of all oef_search dialogues.\"\"\"\n\n    def __init__(self, self_address: Address) -> None:  # pylint: disable=useless-return\n        \"\"\"\n        Initialize dialogues.\n\n        :param self_address: the address of the entity for whom dialogues are maintained\n        :return: None\n        \"\"\"\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return SigningDialogue.Role.SKILL\n\n        BaseSigningDialogues.__init__(\n            self,\n            self_address=self_address,\n            role_from_first_message=role_from_first_message,\n            dialogue_class=SigningDialogue,\n        )\n\n        return None\n\n\ndef make_desc_maker_wallet(\n    ledger_id: str, key_path: str\n) -> Tuple[DecisionMaker, Wallet]:\n    \"\"\"Construct decision maker and wallet.\"\"\"\n    wallet = Wallet({ledger_id: key_path})\n    agent_name = \"test\"\n    identity = Identity(\n        agent_name,\n        addresses=wallet.addresses,\n        default_address_key=ledger_id,\n    )\n    config = {}  # type: ignore\n    decision_maker_handler = DecisionMakerHandler(\n        identity=identity, wallet=wallet, config=config\n    )\n    decision_maker = DecisionMaker(decision_maker_handler)\n    return decision_maker, wallet\n\n\ndef sign_txs(\n    decision_maker: DecisionMaker, wallet: Wallet, num_runs: int, ledger_id: str\n) -> float:\n    \"\"\"Sign txs sprcified amount fo runs and return time taken (seconds).\"\"\"\n    amount = 10000\n    fc2 = make_crypto(ledger_id)\n    sender_address = wallet.addresses[ledger_id]\n    ledger_api = make_ledger_api(ledger_id)\n\n    if ledger_id == \"fetchai\":\n        with patch(\n            \"aea_ledger_fetchai._cosmos._CosmosApi._try_get_account_number_and_sequence\",\n            return_value=(987, 0),\n        ), patch(\n            \"aea_ledger_fetchai._cosmos._CosmosApi.get_balance\", return_value=100000\n        ):\n            transfer_transaction = ledger_api.get_transfer_transaction(\n                sender_address=sender_address,\n                destination_address=fc2.address,\n                amount=amount,\n                tx_fee=1000,\n                tx_nonce=\"something\",\n            )\n    elif ledger_id == \"cosmos\":\n        with patch(\n            \"aea_ledger_cosmos.cosmos._CosmosApi._try_get_account_number_and_sequence\",\n            return_value=(987, 0),\n        ), patch(\n            \"aea_ledger_cosmos.cosmos._CosmosApi.get_balance\", return_value=100000\n        ):\n            transfer_transaction = ledger_api.get_transfer_transaction(\n                sender_address=sender_address,\n                destination_address=fc2.address,\n                amount=amount,\n                tx_fee=1000,\n                tx_nonce=\"something\",\n            )\n    elif ledger_id == \"ethereum\":\n        transfer_transaction = {\"gasPrice\": 30, \"nonce\": 1, \"gas\": 20000}\n    else:\n        raise ValueError(\"Ledger not supported!\")\n\n    signing_dialogues = SigningDialogues(str(PublicId(\"author\", \"a_skill\", \"0.1.0\")))\n    signing_msg = SigningMessage(\n        performative=SigningMessage.Performative.SIGN_TRANSACTION,\n        dialogue_reference=signing_dialogues.new_self_initiated_dialogue_reference(),\n        terms=Terms(\n            ledger_id=ledger_id,\n            sender_address=\"pk1\",\n            counterparty_address=\"pk2\",\n            amount_by_currency_id={\"FET\": -1},\n            is_sender_payable_tx_fee=True,\n            quantities_by_good_id={\"good_id\": 10},\n            nonce=\"transaction nonce\",\n        ),\n        raw_transaction=RawTransaction(ledger_id, transfer_transaction),  # type: ignore\n    )\n    start_time = time.time()\n    for _ in range(num_runs):\n        signing_msg._sender = None  # pylint: disable=protected-access\n        signing_msg._to = None  # pylint: disable=protected-access\n        signing_msg._slots.dialogue_reference = (  # type: ignore# pylint: disable=protected-access\n            signing_dialogues.new_self_initiated_dialogue_reference()\n        )\n        signing_dialogue = signing_dialogues.create_with_message(\n            \"decision_maker\", signing_msg\n        )\n        if signing_dialogue is None:\n            raise ValueError(\"dialogue failure\")\n        decision_maker.message_in_queue.put_nowait(signing_msg)\n        signing_msg_response = decision_maker.message_out_queue.get(timeout=2)\n        if (\n            signing_msg_response.performative\n            != SigningMessage.Performative.SIGNED_TRANSACTION\n        ):\n            raise ValueError(\"Sign message error!\")\n\n    return time.time() - start_time\n\n\ndef run(ledger_id: str, amount_of_tx: int) -> List[Tuple[str, Union[int, float]]]:\n    \"\"\"Check memory usage.\"\"\"\n    # pylint: disable=import-outside-toplevel,unused-import\n    # import manually due to some lazy imports in decision_maker\n    import aea.decision_maker.default  # noqa: F401\n\n    with TemporaryDirectory() as tmp_dir:\n        key_file = str(Path(tmp_dir) / \"key-file\")\n        crypto = make_crypto(ledger_id)\n        crypto.dump(key_file)\n        decision_maker, wallet = make_desc_maker_wallet(ledger_id, key_file)\n        decision_maker.start()\n        mem_usage = get_mem_usage_in_mb()\n\n        running_time = sign_txs(decision_maker, wallet, amount_of_tx, ledger_id)\n        mem_usage = get_mem_usage_in_mb() - mem_usage\n        decision_maker.stop()\n        rate = running_time / amount_of_tx\n\n        return [\n            (\"run_time (seconds)\", running_time),\n            (\"rate (envelopes/second)\", rate),\n            (\"mem usage (Mb)\", mem_usage),\n        ]\n\n\n@click.command()\n@click.option(\"--ledger_id\", default=\"fetchai\", help=\"Ledger id\")\n@click.option(\"--amount_of_tx\", default=100, help=\"Amount of tx to sign\")\n@number_of_runs_deco\n@output_format_deco\ndef main(\n    ledger_id: str, amount_of_tx: int, number_of_runs: int, output_format: str\n) -> Any:\n    \"\"\"Run test.\"\"\"\n    parameters = {\n        \"Ledger id\": ledger_id,\n        \"Amount of txs\": amount_of_tx,\n        \"Number of runs\": number_of_runs,\n    }\n\n    def result_fn() -> List[Tuple[str, Any, Any, Any]]:\n        return multi_run(\n            int(number_of_runs),\n            run,\n            (\n                ledger_id,\n                amount_of_tx,\n            ),\n        )\n\n    return print_results(output_format, parameters, result_fn)\n\n\nif __name__ == \"__main__\":\n    main()  # pylint: disable=no-value-for-parameter\n"
  },
  {
    "path": "benchmark/checks/check_dialogues_memory_usage.py",
    "content": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Memory usage of dialogues across the time.\"\"\"\nimport os\nimport sys\nimport time\nimport uuid\nfrom typing import Any, List, Tuple, Union, cast\n\nimport click\n\nfrom aea.common import Address\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue\nfrom benchmark.checks.utils import get_mem_usage_in_mb  # noqa: I100\nfrom benchmark.checks.utils import (\n    multi_run,\n    number_of_runs_deco,\n    output_format_deco,\n    print_results,\n)\n\nfrom packages.fetchai.protocols.http.dialogues import HttpDialogue, HttpDialogues\nfrom packages.fetchai.protocols.http.message import HttpMessage\n\n\nROOT_PATH = os.path.join(os.path.abspath(__file__), \"..\", \"..\")\nsys.path.append(ROOT_PATH)\n\n\nclass DialogueHandler:\n    \"\"\"Generate messages and process with dialogues.\"\"\"\n\n    def __init__(self) -> None:\n        \"\"\"Set dialogues.\"\"\"\n        # pylint: disable=unused-argument\n\n        def role(m: Message, addr: Address) -> Dialogue.Role:\n            return HttpDialogue.Role.CLIENT\n\n        self.addr = self.random_string\n        self.dialogues = HttpDialogues(self.addr, role_from_first_message=role)\n\n    @property\n    def random_string(self) -> str:\n        \"\"\"Get random string on every access.\"\"\"\n        return uuid.uuid4().hex\n\n    def process_message(self) -> None:\n        \"\"\"Process a message with dialogues.\"\"\"\n        message = self.create()\n        dialogue = self.update(message)\n        self.reply(dialogue, message)\n\n    def update(self, message: HttpMessage) -> HttpDialogue:\n        \"\"\"Update dialogues with message.\"\"\"\n        return cast(HttpDialogue, self.dialogues.update(message))\n\n    @staticmethod\n    def reply(dialogue: HttpDialogue, message: HttpMessage) -> Message:\n        \"\"\"Construct and send a response for message received.\"\"\"\n        return dialogue.reply(\n            target_message=message,\n            performative=HttpMessage.Performative.RESPONSE,\n            version=message.version,\n            headers=\"\",\n            status_code=200,\n            status_text=\"Success\",\n            body=message.body,\n        )\n\n    def create(self) -> HttpMessage:\n        \"\"\"Make initial http request.\"\"\"\n        message = HttpMessage(\n            dialogue_reference=HttpDialogues.new_self_initiated_dialogue_reference(),\n            performative=HttpMessage.Performative.REQUEST,\n            method=\"get\",\n            url=\"some url\",\n            headers=\"\",\n            version=\"\",\n            body=b\"\",\n        )\n        message.sender = self.random_string\n        message.to = self.addr\n        return message\n\n\ndef run(messages_amount: int) -> List[Tuple[str, Union[float, int]]]:\n    \"\"\"Test messages generation and memory consumption with dialogues.\"\"\"\n    handler = DialogueHandler()\n    mem_usage_on_start = get_mem_usage_in_mb()\n    start_time = time.time()\n    for _ in range(messages_amount):\n        handler.process_message()\n    mem_usage = get_mem_usage_in_mb()\n\n    return [\n        (\"Mem usage(Mb)\", mem_usage - mem_usage_on_start),\n        (\"Time (seconds)\", time.time() - start_time),\n    ]\n\n\n@click.command()\n@click.option(\"--messages\", default=1000, help=\"Run time in seconds.\")\n@number_of_runs_deco\n@output_format_deco\ndef main(messages: str, number_of_runs: int, output_format: str) -> Any:\n    \"\"\"Run test.\"\"\"\n    parameters = {\"Messages\": messages, \"Number of runs\": number_of_runs}\n\n    def result_fn() -> List[Tuple[str, Any, Any, Any]]:\n        return multi_run(\n            int(number_of_runs),\n            run,\n            (int(messages),),\n        )\n\n    return print_results(output_format, parameters, result_fn)\n\n\nif __name__ == \"__main__\":\n    main()  # pylint: disable=no-value-for-parameter\n"
  },
  {
    "path": "benchmark/checks/check_mem_usage.py",
    "content": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Memory usage check.\"\"\"\nimport time\nfrom threading import Thread\nfrom typing import Any, List, Tuple, Union\n\nimport click\n\nfrom aea.protocols.base import Message\nfrom aea.registries.resources import Resources\nfrom aea.skills.base import Handler\nfrom benchmark.checks.utils import SyncedGeneratorConnection  # noqa: I100\nfrom benchmark.checks.utils import (\n    get_mem_usage_in_mb,\n    make_agent,\n    make_envelope,\n    make_skill,\n    multi_run,\n    number_of_runs_deco,\n    output_format_deco,\n    print_results,\n    wait_for_condition,\n)\n\nfrom packages.fetchai.protocols.default.message import DefaultMessage\n\n\nclass TestHandler(Handler):\n    \"\"\"Dummy handler to handle messages.\"\"\"\n\n    SUPPORTED_PROTOCOL = DefaultMessage.protocol_id\n\n    def setup(self) -> None:\n        \"\"\"Noop setup.\"\"\"\n\n    def teardown(self) -> None:\n        \"\"\"Noop teardown.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"Handle incoming message.\"\"\"\n        self.context.outbox.put(make_envelope(message.to, message.sender))\n\n\ndef run(duration: int, runtime_mode: str) -> List[Tuple[str, Union[int, float]]]:\n    \"\"\"Check memory usage.\"\"\"\n    # pylint: disable=import-outside-toplevel,unused-import\n    # import manually due to some lazy imports in decision_maker\n    import aea.decision_maker.default  # noqa: F401\n\n    connection = SyncedGeneratorConnection.make()\n    resources = Resources()\n    resources.add_connection(connection)\n    agent = make_agent(runtime_mode=runtime_mode, resources=resources)\n    agent.resources.add_skill(make_skill(agent, handlers={\"test\": TestHandler}))\n\n    t = Thread(target=agent.start, daemon=True)\n    t.start()\n    wait_for_condition(lambda: agent.is_running, timeout=5)\n\n    connection.enable()\n    time.sleep(duration)\n    connection.disable()\n    mem_usage = get_mem_usage_in_mb()\n    agent.stop()\n    t.join(5)\n    rate = connection.count_in / duration\n\n    return [\n        (\"envelopes received\", connection.count_in),\n        (\"envelopes sent\", connection.count_out),\n        (\"rate (envelopes/second)\", rate),\n        (\"mem usage (Mb)\", mem_usage),\n    ]\n\n\n@click.command()\n@click.option(\"--duration\", default=3, help=\"Run time in seconds.\")\n@click.option(\n    \"--runtime_mode\", default=\"async\", help=\"Runtime mode: async or threaded.\"\n)\n@number_of_runs_deco\n@output_format_deco\ndef main(\n    duration: int, runtime_mode: str, number_of_runs: int, output_format: str\n) -> Any:\n    \"\"\"Run test.\"\"\"\n    parameters = {\n        \"Duration(seconds)\": duration,\n        \"Runtime mode\": runtime_mode,\n        \"Number of runs\": number_of_runs,\n    }\n\n    def result_fn() -> List[Tuple[str, Any, Any, Any]]:\n        return multi_run(\n            int(number_of_runs),\n            run,\n            (duration, runtime_mode),\n        )\n\n    return print_results(output_format, parameters, result_fn)\n\n\nif __name__ == \"__main__\":\n    main()  # pylint: disable=no-value-for-parameter\n"
  },
  {
    "path": "benchmark/checks/check_messages_memory_usage.py",
    "content": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Memory usage of huge amount of messages.\"\"\"\nimport os\nimport sys\nimport time\nfrom typing import Any, List, Tuple, Union\n\nimport click\n\nfrom aea.protocols.base import Message\nfrom benchmark.checks.utils import get_mem_usage_in_mb  # noqa: I100\nfrom benchmark.checks.utils import (\n    multi_run,\n    number_of_runs_deco,\n    output_format_deco,\n    print_results,\n)\n\nfrom packages.fetchai.protocols.default.message import DefaultMessage\n\n\nROOT_PATH = os.path.join(os.path.abspath(__file__), \"..\", \"..\")\nsys.path.append(ROOT_PATH)\n\n\ndef make_message() -> Message:\n    \"\"\"Create a message.\"\"\"\n    return DefaultMessage(\n        dialogue_reference=(\"\", \"\"),\n        message_id=1,\n        target=0,\n        performative=DefaultMessage.Performative.BYTES,\n        content=b\"\",\n    )\n\n\ndef run(messages_amount: int) -> List[Tuple[str, Union[int, float]]]:\n    \"\"\"Test messages generation and memory consumption.\"\"\"\n    messages: List[Any] = [\n        0 for i in range(messages_amount)\n    ]  # generate dummy list to count list structure memory\n    mem_usage_on_start = get_mem_usage_in_mb()\n\n    start_time = time.time()\n    for i in range(messages_amount):\n        messages[i] = make_message()\n    mem_usage = get_mem_usage_in_mb()\n\n    return [\n        (\"Mem usage(Mb)\", mem_usage - mem_usage_on_start),\n        (\"Time (seconds)\", time.time() - start_time),\n    ]\n\n\n@click.command()\n@click.option(\"--messages\", default=10**6, help=\"Amount of messages.\")\n@number_of_runs_deco\n@output_format_deco\ndef main(messages: int, number_of_runs: int, output_format: str) -> Any:\n    \"\"\"Run test.\"\"\"\n    parameters = {\"Messages\": messages, \"Number of runs\": number_of_runs}\n\n    def result_fn() -> List[Tuple[str, Any, Any, Any]]:\n        return multi_run(\n            int(number_of_runs),\n            run,\n            (int(messages),),\n        )\n\n    return print_results(output_format, parameters, result_fn)\n\n\nif __name__ == \"__main__\":\n    main()  # pylint: disable=no-value-for-parameter\n"
  },
  {
    "path": "benchmark/checks/check_multiagent.py",
    "content": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Envelopes generation speed for Behaviour act test.\"\"\"\nimport itertools\nimport os\nimport struct\nimport sys\nimport time\nfrom typing import Any, List, Tuple, Union, cast\n\nimport click\n\nfrom aea.configurations.base import ConnectionConfig\nfrom aea.identity.base import Identity\nfrom aea.protocols.base import Message\nfrom aea.registries.resources import Resources\nfrom aea.runner import AEARunner\nfrom aea.skills.base import Handler\nfrom benchmark.checks.utils import get_mem_usage_in_mb  # noqa: I100\nfrom benchmark.checks.utils import (\n    make_agent,\n    make_envelope,\n    make_skill,\n    multi_run,\n    number_of_runs_deco,\n    output_format_deco,\n    print_results,\n    wait_for_condition,\n)\n\nfrom packages.fetchai.connections.local.connection import (  # noqa: E402 # pylint: disable=C0413\n    LocalNode,\n    OEFLocalConnection,\n)\nfrom packages.fetchai.protocols.default.message import DefaultMessage\n\n\nROOT_PATH = os.path.join(os.path.abspath(__file__), \"..\", \"..\")\nsys.path.append(ROOT_PATH)\n\n\nclass TestHandler(Handler):\n    \"\"\"Dummy handler to handle messages.\"\"\"\n\n    SUPPORTED_PROTOCOL = DefaultMessage.protocol_id\n\n    def setup(self) -> None:\n        \"\"\"Noop setup.\"\"\"\n        self.count: int = 0  # pylint: disable=attribute-defined-outside-init\n        self.rtt_total_time: float = (  # pylint: disable=attribute-defined-outside-init\n            0.0\n        )\n        self.rtt_count: int = 0  # pylint: disable=attribute-defined-outside-init\n\n        self.latency_total_time: float = (  # pylint: disable=attribute-defined-outside-init\n            0.0\n        )\n        self.latency_count: int = 0  # pylint: disable=attribute-defined-outside-init\n\n    def teardown(self) -> None:\n        \"\"\"Noop teardown.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"Handle incoming message.\"\"\"\n        self.count += 1\n\n        if message.dialogue_reference[0] != \"\":\n            rtt_ts, latency_ts = struct.unpack(\"dd\", message.content)  # type: ignore\n            if message.dialogue_reference[0] == self.context.agent_address:\n                self.rtt_total_time += time.time() - rtt_ts\n                self.rtt_count += 1\n\n            self.latency_total_time += time.time() - latency_ts\n            self.latency_count += 1\n\n        if message.dialogue_reference[0] in [\"\", self.context.agent_address]:\n            # create new\n            response_msg = DefaultMessage(\n                dialogue_reference=(self.context.agent_address, \"\"),\n                message_id=1,\n                target=0,\n                performative=DefaultMessage.Performative.BYTES,\n                content=struct.pack(\"dd\", time.time(), time.time()),\n            )\n        else:\n            # update ttfb copy rtt\n            response_msg = DefaultMessage(\n                dialogue_reference=message.dialogue_reference,\n                message_id=1,\n                target=0,\n                performative=DefaultMessage.Performative.BYTES,\n                content=struct.pack(\"dd\", rtt_ts, time.time()),  # type: ignore\n            )\n\n        self.context.outbox.put(make_envelope(message.to, message.sender, response_msg))\n\n\ndef run(\n    duration: int,\n    runtime_mode: str,\n    runner_mode: str,\n    start_messages: int,\n    num_of_agents: int,\n) -> List[Tuple[str, Union[int, float]]]:\n    \"\"\"Test multiagent message exchange.\"\"\"\n    # pylint: disable=import-outside-toplevel,unused-import\n    # import manually due to some lazy imports in decision_maker\n    import aea.decision_maker.default  # noqa: F401\n\n    local_node = LocalNode()\n    local_node.start()\n\n    agents = []\n    skills = []\n\n    for i in range(num_of_agents):\n        resources = Resources()\n        agent_name = f\"agent{i}\"\n        public_key = f\"public_key{i}\"\n        identity = Identity(agent_name, address=agent_name, public_key=public_key)\n        connection = OEFLocalConnection(\n            local_node,\n            configuration=ConnectionConfig(\n                connection_id=OEFLocalConnection.connection_id,\n            ),\n            identity=identity,\n            data_dir=\"tmp\",\n        )\n        resources.add_connection(connection)\n        agent = make_agent(\n            agent_name=agent_name,\n            runtime_mode=runtime_mode,\n            resources=resources,\n            identity=identity,\n        )\n        skill = make_skill(agent, handlers={\"test\": TestHandler})\n        agent.resources.add_skill(skill)\n        agents.append(agent)\n        skills.append(skill)\n\n    runner = AEARunner(agents, runner_mode)\n    runner.start(threaded=True)\n\n    for agent in agents:\n        wait_for_condition(\n            (  # pylint: disable=unnecessary-direct-lambda-call\n                lambda agnt: lambda: agnt.is_running\n            )(agent),\n            timeout=5,\n        )\n\n    wait_for_condition(lambda: runner.is_running, timeout=5)\n    time.sleep(1)\n\n    for agent1, agent2 in itertools.permutations(agents, 2):\n        env = make_envelope(agent1.identity.address, agent2.identity.address)\n\n        for _ in range(int(start_messages)):\n            agent1.outbox.put(env)\n\n    time.sleep(duration)\n\n    mem_usage = get_mem_usage_in_mb()\n\n    local_node.stop()\n    runner.stop(timeout=5)\n\n    total_messages = sum(\n        cast(TestHandler, skill.handlers[\"test\"]).count for skill in skills\n    )\n    rate = total_messages / duration\n\n    rtt_total_time = sum(\n        cast(TestHandler, skill.handlers[\"test\"]).rtt_total_time for skill in skills\n    )\n    rtt_count = sum(\n        cast(TestHandler, skill.handlers[\"test\"]).rtt_count for skill in skills\n    )\n\n    if rtt_count == 0:\n        rtt_count = -1\n\n    latency_total_time = sum(\n        cast(TestHandler, skill.handlers[\"test\"]).latency_total_time for skill in skills\n    )\n    latency_count = sum(\n        cast(TestHandler, skill.handlers[\"test\"]).latency_count for skill in skills\n    )\n\n    if latency_count == 0:\n        latency_count = -1\n\n    return [\n        (\"Total Messages handled\", total_messages),\n        (\"Messages rate(envelopes/second)\", rate),\n        (\"Mem usage(Mb)\", mem_usage),\n        (\"RTT (ms)\", rtt_total_time / rtt_count),\n        (\"Latency (ms)\", latency_total_time / latency_count),\n    ]\n\n\n@click.command()\n@click.option(\"--duration\", default=1, help=\"Run time in seconds.\")\n@click.option(\n    \"--runtime_mode\", default=\"async\", help=\"Runtime mode: async or threaded.\"\n)\n@click.option(\"--runner_mode\", default=\"async\", help=\"Runtime mode: async or threaded.\")\n@click.option(\n    \"--start_messages\", default=100, help=\"Amount of messages to prepopulate.\"\n)\n@click.option(\"--num_of_agents\", default=2, help=\"Amount of agents to run.\")\n@number_of_runs_deco\n@output_format_deco\ndef main(\n    duration: int,\n    runtime_mode: str,\n    runner_mode: str,\n    start_messages: int,\n    num_of_agents: int,\n    number_of_runs: int,\n    output_format: str,\n) -> Any:\n    \"\"\"Run test.\"\"\"\n\n    parameters = {\n        \"Duration(seconds)\": duration,\n        \"Runtime mode\": runtime_mode,\n        \"Runner mode\": runner_mode,\n        \"Start messages\": start_messages,\n        \"Number of agents\": num_of_agents,\n        \"Number of runs\": number_of_runs,\n    }\n\n    def result_fn() -> List[Tuple[str, Any, Any, Any]]:\n        return multi_run(\n            int(number_of_runs),\n            run,\n            (duration, runtime_mode, runner_mode, start_messages, num_of_agents),\n        )\n\n    return print_results(output_format, parameters, result_fn)\n\n\nif __name__ == \"__main__\":\n    main()  # pylint: disable=no-value-for-parameter\n"
  },
  {
    "path": "benchmark/checks/check_multiagent_http_dialogues.py",
    "content": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Memory usage across the time.\"\"\"\nimport itertools\nimport os\nimport struct\nimport sys\nimport time\nfrom typing import Any, List, Tuple, Union, cast\n\nimport click\n\nfrom aea.aea import AEA\nfrom aea.common import Address\nfrom aea.configurations.base import ConnectionConfig\nfrom aea.identity.base import Identity\nfrom aea.protocols.base import Message, Protocol\nfrom aea.protocols.dialogue.base import Dialogue\nfrom aea.registries.resources import Resources\nfrom aea.runner import AEARunner\nfrom aea.skills.base import Handler\nfrom benchmark.checks.utils import get_mem_usage_in_mb  # noqa: I100\nfrom benchmark.checks.utils import PACKAGES_DIR\nfrom benchmark.checks.utils import make_agent as base_make_agent\nfrom benchmark.checks.utils import (\n    make_skill,\n    multi_run,\n    number_of_runs_deco,\n    output_format_deco,\n    print_results,\n    wait_for_condition,\n)\n\nfrom packages.fetchai.connections.local.connection import (  # noqa: E402 # pylint: disable=C0413\n    LocalNode,\n    OEFLocalConnection,\n)\nfrom packages.fetchai.protocols.http.dialogues import HttpDialogue, HttpDialogues\nfrom packages.fetchai.protocols.http.message import HttpMessage\n\n\nROOT_PATH = os.path.join(os.path.abspath(__file__), \"..\", \"..\")\nsys.path.append(ROOT_PATH)\n\n\nclass HttpPingPongHandler(Handler):\n    \"\"\"Dummy handler to handle messages.\"\"\"\n\n    SUPPORTED_PROTOCOL = HttpMessage.protocol_id\n\n    def setup(self) -> None:\n        \"\"\"Noop setup.\"\"\"\n        # pylint: disable=attribute-defined-outside-init, unused-argument\n        self.count: int = 0\n        self.rtt_total_time: float = 0.0\n        self.rtt_count: int = 0\n\n        self.latency_total_time: float = 0.0\n        self.latency_count: int = 0\n\n        def role(m: Message, addr: Address) -> Dialogue.Role:\n            return HttpDialogue.Role.CLIENT\n\n        self.dialogues = HttpDialogues(\n            self.context.agent_address, role_from_first_message=role\n        )\n\n    def teardown(self) -> None:\n        \"\"\"Noop teardown.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"Handle incoming message.\"\"\"\n        self.count += 1\n        message = cast(HttpMessage, message)\n        dialogue = self.dialogues.update(message)\n        if not dialogue:\n            raise Exception(\"something goes wrong\")\n        rtt_ts, latency_ts = struct.unpack(\"dd\", message.body)  # type: ignore\n        if message.performative == HttpMessage.Performative.REQUEST:\n            self.latency_total_time += time.time() - latency_ts\n            self.latency_count += 1\n            self.make_response(cast(HttpDialogue, dialogue), message)\n        elif message.performative == HttpMessage.Performative.RESPONSE:\n            self.rtt_total_time += time.time() - rtt_ts\n            self.rtt_count += 1\n\n            # got response, make another request to the same agent\n            self.make_request(message.sender)\n\n    def make_response(self, dialogue: HttpDialogue, message: HttpMessage) -> None:\n        \"\"\"Construct and send a response for message received.\"\"\"\n        response_message = dialogue.reply(\n            target_message=message,\n            performative=HttpMessage.Performative.RESPONSE,\n            version=message.version,\n            headers=\"\",\n            status_code=200,\n            status_text=\"Success\",\n            body=message.body,\n        )\n        self.context.outbox.put_message(response_message)\n\n    def make_request(self, recipient_addr: str) -> None:\n        \"\"\"Make initial http request.\"\"\"\n        message, _ = self.dialogues.create(\n            recipient_addr,\n            performative=HttpMessage.Performative.REQUEST,\n            method=\"get\",\n            url=\"some url\",\n            headers=\"\",\n            version=\"\",\n            body=struct.pack(\"dd\", time.time(), time.time()),\n        )\n        self.context.outbox.put_message(message)\n\n\ndef make_agent(*args: Any, **kwargs: Any) -> AEA:\n    \"\"\"Make agent with http protocol support.\"\"\"\n    aea = base_make_agent(*args, **kwargs)\n    aea.resources.add_protocol(\n        Protocol.from_dir(str(PACKAGES_DIR / \"fetchai\" / \"protocols\" / \"http\"))\n    )\n    return aea\n\n\ndef run(\n    duration: int,\n    runtime_mode: str,\n    runner_mode: str,\n    start_messages: int,\n    num_of_agents: int,\n) -> List[Tuple[str, Union[int, float]]]:\n    \"\"\"Test multiagent message exchange.\"\"\"\n    # pylint: disable=import-outside-toplevel,unused-import\n    # import manually due to some lazy imports in decision_maker\n    import aea.decision_maker.default  # noqa: F401\n\n    local_node = LocalNode()\n    local_node.start()\n    agents = []\n    skills = {}\n    handler_name = \"httpingpong\"\n\n    for i in range(num_of_agents):\n        agent_name = f\"agent{i}\"\n        public_key = f\"public_key{i}\"\n        identity = Identity(agent_name, address=agent_name, public_key=public_key)\n        resources = Resources()\n        connection = OEFLocalConnection(\n            local_node,\n            configuration=ConnectionConfig(\n                connection_id=OEFLocalConnection.connection_id,\n            ),\n            identity=identity,\n            data_dir=\"tmp\",\n        )\n        resources.add_connection(connection)\n        agent = make_agent(\n            agent_name=agent_name,\n            runtime_mode=runtime_mode,\n            resources=resources,\n            identity=identity,\n        )\n        skill = make_skill(agent, handlers={handler_name: HttpPingPongHandler})\n        agent.resources.add_skill(skill)\n        agents.append(agent)\n        skills[agent_name] = skill\n\n    runner = AEARunner(agents, runner_mode)\n    runner.start(threaded=True)\n\n    for agent in agents:\n        wait_for_condition(\n            (  # pylint: disable=unnecessary-direct-lambda-call\n                lambda agnt: lambda: agnt.is_running\n            )(agent),\n            timeout=5,\n        )\n\n    wait_for_condition(lambda: runner.is_running, timeout=5)\n    time.sleep(1)\n\n    for agent1, agent2 in itertools.permutations(agents, 2):\n        for _ in range(int(start_messages)):\n            cast(\n                HttpPingPongHandler,\n                skills[agent1.identity.address].handlers[handler_name],\n            ).make_request(agent2.identity.address)\n    time.sleep(duration)\n\n    mem_usage = get_mem_usage_in_mb()\n    local_node.stop()\n    runner.stop(timeout=5)\n    total_messages = sum(\n        cast(HttpPingPongHandler, skill.handlers[handler_name]).count\n        for skill in skills.values()\n    )\n    rate = total_messages / duration\n\n    rtt_total_time = sum(\n        cast(HttpPingPongHandler, skill.handlers[handler_name]).rtt_total_time\n        for skill in skills.values()\n    )\n    rtt_count = sum(\n        cast(HttpPingPongHandler, skill.handlers[handler_name]).rtt_count\n        for skill in skills.values()\n    )\n\n    if rtt_count == 0:\n        rtt_count = -1\n\n    latency_total_time = sum(\n        cast(HttpPingPongHandler, skill.handlers[handler_name]).latency_total_time\n        for skill in skills.values()\n    )\n    latency_count = sum(\n        cast(HttpPingPongHandler, skill.handlers[handler_name]).latency_count\n        for skill in skills.values()\n    )\n\n    if latency_count == 0:\n        latency_count = -1\n\n    return [\n        (\"Total Messages handled\", total_messages),\n        (\"Messages rate(envelopes/second)\", rate),\n        (\"Mem usage(Mb)\", mem_usage),\n        (\"RTT (ms)\", rtt_total_time / rtt_count),\n        (\"Latency (ms)\", latency_total_time / latency_count),\n    ]\n\n\n@click.command()\n@click.option(\"--duration\", default=1, help=\"Run time in seconds.\")\n@click.option(\n    \"--runtime_mode\", default=\"async\", help=\"Runtime mode: async or threaded.\"\n)\n@click.option(\"--runner_mode\", default=\"async\", help=\"Runtime mode: async or threaded.\")\n@click.option(\n    \"--start_messages\", default=100, help=\"Amount of messages to prepopulate.\"\n)\n@click.option(\"--num_of_agents\", default=2, help=\"Amount of agents to run.\")\n@number_of_runs_deco\n@output_format_deco\ndef main(\n    duration: int,\n    runtime_mode: str,\n    runner_mode: str,\n    start_messages: int,\n    num_of_agents: int,\n    number_of_runs: int,\n    output_format: str,\n) -> Any:\n    \"\"\"Run test.\"\"\"\n    parameters = {\n        \"Duration(seconds)\": duration,\n        \"Runtime mode\": runtime_mode,\n        \"Runner mode\": runner_mode,\n        \"Start messages\": start_messages,\n        \"Number of agents\": num_of_agents,\n        \"Number of runs\": number_of_runs,\n    }\n\n    def result_fn() -> List[Tuple[str, Any, Any, Any]]:\n        return multi_run(\n            int(number_of_runs),\n            run,\n            (duration, runtime_mode, runner_mode, start_messages, num_of_agents),\n        )\n\n    return print_results(output_format, parameters, result_fn)\n\n\nif __name__ == \"__main__\":\n    main()  # pylint: disable=no-value-for-parameter\n"
  },
  {
    "path": "benchmark/checks/check_proactive.py",
    "content": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Envelopes generation speed for Behaviour act test.\"\"\"\nimport time\nfrom threading import Thread\nfrom typing import Any, List, Tuple, Union, cast\n\nimport click\n\nfrom aea.registries.resources import Resources\nfrom aea.skills.base import Behaviour\nfrom benchmark.checks.utils import SyncedGeneratorConnection  # noqa: I100\nfrom benchmark.checks.utils import (\n    make_agent,\n    make_envelope,\n    make_skill,\n    multi_run,\n    number_of_runs_deco,\n    output_format_deco,\n    print_results,\n    wait_for_condition,\n)\n\nfrom packages.fetchai.protocols.default.message import DefaultMessage\n\n\nclass TestBehaviour(Behaviour):\n    \"\"\"Dummy handler to handle messages.\"\"\"\n\n    _tick_interval = 1\n\n    SUPPORTED_PROTOCOL = DefaultMessage.protocol_id\n\n    def setup(self) -> None:\n        \"\"\"Set up behaviour.\"\"\"\n        self.count = 0  # pylint: disable=attribute-defined-outside-init\n\n    def teardown(self) -> None:\n        \"\"\"Tear up behaviour.\"\"\"\n\n    def act(self) -> None:\n        \"\"\"Perform action on periodic basis.\"\"\"\n        s = time.time()\n        while time.time() - s < self.tick_interval:\n            self.context.outbox.put(make_envelope(\"1\", \"2\"))\n            self.count += 1\n\n\ndef run(duration: int, runtime_mode: str) -> List[Tuple[str, Union[int, float]]]:\n    \"\"\"Test act message generate performance.\"\"\"\n    # pylint: disable=import-outside-toplevel,unused-import\n    # import manually due to some lazy imports in decision_maker\n    import aea.decision_maker.default  # noqa: F401\n\n    resources = Resources()\n    connection = SyncedGeneratorConnection.make()\n    resources.add_connection(connection)\n    agent = make_agent(runtime_mode=runtime_mode, resources=resources)\n    skill = make_skill(agent, behaviours={\"test\": TestBehaviour})\n    agent.resources.add_skill(skill)\n    t = Thread(target=agent.start, daemon=True)\n    t.start()\n    wait_for_condition(lambda: agent.is_running, timeout=5)\n    time.sleep(duration)\n    agent.stop()\n    t.join(5)\n\n    rate = connection.count_in / duration\n    return [\n        (\"envelopes sent\", cast(TestBehaviour, skill.behaviours[\"test\"]).count),\n        (\"envelopes received\", connection.count_in),\n        (\"rate(envelopes/second)\", rate),\n    ]\n\n\n@click.command()\n@click.option(\"--duration\", default=3, help=\"Run time in seconds.\")\n@click.option(\n    \"--runtime_mode\", default=\"async\", help=\"Runtime mode: async or threaded.\"\n)\n@number_of_runs_deco\n@output_format_deco\ndef main(\n    duration: int, runtime_mode: str, number_of_runs: int, output_format: str\n) -> Any:\n    \"\"\"Run test.\"\"\"\n    parameters = {\n        \"Duration(seconds)\": duration,\n        \"Runtime mode\": runtime_mode,\n        \"Number of runs\": number_of_runs,\n    }\n\n    def result_fn() -> List[Tuple[str, Any, Any, Any]]:\n        return multi_run(\n            int(number_of_runs),\n            run,\n            (duration, runtime_mode),\n        )\n\n    return print_results(output_format, parameters, result_fn)\n\n\nif __name__ == \"__main__\":\n    main()  # pylint: disable=no-value-for-parameter\n"
  },
  {
    "path": "benchmark/checks/check_reactive.py",
    "content": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Latency and throughput check.\"\"\"\nimport time\nfrom statistics import mean\nfrom threading import Thread\nfrom typing import Any, List, Optional, Tuple, Union\n\nimport click\n\nfrom aea.mail.base import Envelope\nfrom aea.protocols.base import Message\nfrom aea.registries.resources import Resources\nfrom aea.skills.base import Handler\nfrom benchmark.checks.utils import GeneratorConnection  # noqa: I100\nfrom benchmark.checks.utils import (\n    SyncedGeneratorConnection,\n    make_agent,\n    make_envelope,\n    make_skill,\n    multi_run,\n    number_of_runs_deco,\n    output_format_deco,\n    print_results,\n    wait_for_condition,\n)\n\nfrom packages.fetchai.protocols.default.message import DefaultMessage\n\n\nclass TestConnectionMixIn:\n    \"\"\"Test connection with messages timing.\"\"\"\n\n    def __init__(self, *args: Any, **kwargs: Any):\n        \"\"\"Init connection.\"\"\"\n        super().__init__(*args, **kwargs)  # type: ignore\n        self.sends: List[float] = []\n        self.recvs: List[float] = []\n\n    async def send(self, envelope: Envelope) -> None:\n        \"\"\"Handle incoming envelope.\"\"\"\n        self.recvs.append(time.time())\n        return await super().send(envelope)  # type: ignore  # pylint: disable=no-member\n\n    async def receive(self, *args: Any, **kwargs: Any) -> Optional[Envelope]:\n        \"\"\"Generate outgoing envelope.\"\"\"\n        envelope = await super().receive(*args, **kwargs)  # type: ignore # pylint: disable=no-member\n        self.sends.append(time.time())\n        return envelope\n\n\nCONNECTION_MODES = {\"sync\": SyncedGeneratorConnection, \"nonsync\": GeneratorConnection}\n\n\nclass TestHandler(Handler):\n    \"\"\"Dummy handler to handle messages.\"\"\"\n\n    SUPPORTED_PROTOCOL = DefaultMessage.protocol_id\n\n    def setup(self) -> None:\n        \"\"\"Noop setup.\"\"\"\n\n    def teardown(self) -> None:\n        \"\"\"Noop teardown.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"Handle incoming message.\"\"\"\n        self.context.outbox.put(make_envelope(message.to, message.sender))\n\n\ndef run(\n    duration: int, runtime_mode: str, connection_mode: str\n) -> List[Tuple[str, Union[int, float]]]:\n    \"\"\"Test memory usage.\"\"\"\n    # pylint: disable=import-outside-toplevel,unused-import\n    # import manually due to some lazy imports in decision_maker\n    import aea.decision_maker.default  # noqa: F401\n\n    resources = Resources()\n    if connection_mode not in CONNECTION_MODES:\n        raise ValueError(\n            f\"bad connection mode {connection_mode}. valid is one of {list(CONNECTION_MODES.keys())}\"\n        )\n\n    base_cls = CONNECTION_MODES[connection_mode]\n\n    conn_cls = type(\"conn_cls\", (TestConnectionMixIn, base_cls), {})\n    connection = conn_cls.make()  # type: ignore # pylint: disable=no-member\n    resources.add_connection(connection)\n\n    agent = make_agent(runtime_mode=runtime_mode, resources=resources)\n    agent.resources.add_skill(make_skill(agent, handlers={\"test\": TestHandler}))\n    t = Thread(target=agent.start, daemon=True)\n    t.start()\n    wait_for_condition(lambda: agent.is_running, timeout=5)\n\n    connection.enable()\n    time.sleep(duration)\n    connection.disable()\n    time.sleep(0.2)  # possible race condition in stop?\n    agent.stop()\n    t.join(5)\n\n    latency = mean(\n        map(\n            lambda x: x[1] - x[0],\n            zip(\n                connection.sends,\n                connection.recvs,\n            ),\n        )\n    )\n    total_amount = len(connection.recvs)\n    rate = total_amount / duration\n    return [\n        (\"envelopes received\", len(connection.recvs)),\n        (\"envelopes sent\", len(connection.sends)),\n        (\"latency(ms)\", 10**6 * latency),\n        (\"rate(envelopes/second)\", rate),\n    ]\n\n\n@click.command()\n@click.option(\"--duration\", default=1, help=\"Run time in seconds.\")\n@click.option(\n    \"--runtime_mode\", default=\"async\", help=\"Runtime mode: async or threaded.\"\n)\n@click.option(\n    \"--connection_mode\", default=\"sync\", help=\"Connection mode: sync or nonsync.\"\n)\n@number_of_runs_deco\n@output_format_deco\ndef main(\n    duration: int,\n    runtime_mode: str,\n    connection_mode: str,\n    number_of_runs: int,\n    output_format: str,\n) -> Any:\n    \"\"\"Run test.\"\"\"\n    parameters = {\n        \"Duration(seconds)\": duration,\n        \"Runtime mode\": runtime_mode,\n        \"Connection mode\": connection_mode,\n        \"Number of runs\": number_of_runs,\n    }\n\n    def result_fn() -> List[Tuple[str, Any, Any, Any]]:\n        return multi_run(\n            int(number_of_runs),\n            run,\n            (duration, runtime_mode, connection_mode),\n        )\n\n    return print_results(output_format, parameters, result_fn)\n\n\nif __name__ == \"__main__\":\n    main()  # pylint: disable=no-value-for-parameter\n"
  },
  {
    "path": "benchmark/checks/data/2020.09.05_17-49.txt",
    "content": "Collecting pipenv\n  Downloading pipenv-2020.8.13-py2.py3-none-any.whl (3.9 MB)\nRequirement already satisfied: setuptools>=36.2.1 in /usr/local/lib/python3.8/site-packages (from pipenv) (50.0.1)\nCollecting certifi\n  Downloading certifi-2020.6.20-py2.py3-none-any.whl (156 kB)\nRequirement already satisfied: pip>=18.0 in /usr/local/lib/python3.8/site-packages (from pipenv) (20.2.2)\nCollecting virtualenv-clone>=0.2.5\n  Downloading virtualenv_clone-0.5.4-py2.py3-none-any.whl (6.6 kB)\nCollecting virtualenv\n  Downloading virtualenv-20.0.31-py2.py3-none-any.whl (4.9 MB)\nCollecting filelock<4,>=3.0.0\n  Downloading filelock-3.0.12-py3-none-any.whl (7.6 kB)\nCollecting appdirs<2,>=1.4.3\n  Downloading appdirs-1.4.4-py2.py3-none-any.whl (9.6 kB)\nCollecting six<2,>=1.9.0\n  Downloading six-1.15.0-py2.py3-none-any.whl (10 kB)\nCollecting distlib<1,>=0.3.1\n  Downloading distlib-0.3.1-py2.py3-none-any.whl (335 kB)\nInstalling collected packages: certifi, virtualenv-clone, filelock, appdirs, six, distlib, virtualenv, pipenv\nSuccessfully installed appdirs-1.4.4 certifi-2020.6.20 distlib-0.3.1 filelock-3.0.12 pipenv-2020.8.13 six-1.15.0 virtualenv-20.0.31 virtualenv-clone-0.5.4\nInstalling dependencies from Pipfile.lock (6321dc)…\nTo activate this project's virtualenv, run pipenv shell.\nAlternatively, run a command inside the virtualenv with pipenv run.\nCollecting aea[all]==0.6.0\n  Downloading aea-0.6.0-py2.py3-none-any.whl (416 kB)\nCollecting ecdsa==0.15\n  Downloading ecdsa-0.15-py2.py3-none-any.whl (100 kB)\nCollecting pymultihash==0.8.2\n  Downloading pymultihash-0.8.2-py3-none-any.whl (13 kB)\nRequirement already satisfied, skipping upgrade: ipfshttpclient==0.6.1 in /root/.local/share/virtualenvs/bench-DjFm5PZm8q-aRtk-7Go/lib/python3.8/site-packages (from aea[all]==0.6.0) (0.6.1)\nRequirement already satisfied, skipping upgrade: pyyaml>=4.2b1 in /root/.local/share/virtualenvs/bench-DjFm5PZm8q-aRtk-7Go/lib/python3.8/site-packages (from aea[all]==0.6.0) (5.3.1)\nRequirement already satisfied, skipping upgrade: base58>=1.0.3 in /root/.local/share/virtualenvs/bench-DjFm5PZm8q-aRtk-7Go/lib/python3.8/site-packages (from aea[all]==0.6.0) (2.0.1)\nRequirement already satisfied, skipping upgrade: requests==2.22.0 in /root/.local/share/virtualenvs/bench-DjFm5PZm8q-aRtk-7Go/lib/python3.8/site-packages (from aea[all]==0.6.0) (2.22.0)\nCollecting semver>=2.9.1\n  Downloading semver-2.10.2-py2.py3-none-any.whl (12 kB)\nRequirement already satisfied, skipping upgrade: protobuf in /root/.local/share/virtualenvs/bench-DjFm5PZm8q-aRtk-7Go/lib/python3.8/site-packages (from aea[all]==0.6.0) (3.13.0)\nRequirement already satisfied, skipping upgrade: jsonschema>=3.0.0 in /root/.local/share/virtualenvs/bench-DjFm5PZm8q-aRtk-7Go/lib/python3.8/site-packages (from aea[all]==0.6.0) (3.2.0)\nCollecting eth-account==0.5.2\n  Downloading eth_account-0.5.2-py3-none-any.whl (94 kB)\nCollecting web3==5.12.0\n  Downloading web3-5.12.0-py3-none-any.whl (467 kB)\nRequirement already satisfied, skipping upgrade: packaging>=20.3 in /root/.local/share/virtualenvs/bench-DjFm5PZm8q-aRtk-7Go/lib/python3.8/site-packages (from aea[all]==0.6.0) (20.4)\nCollecting bech32==1.2.0\n  Downloading bech32-1.2.0-py3-none-any.whl (4.6 kB)\nCollecting connexion[swagger-ui]>=2.4.0; extra == \"all\"\n  Downloading connexion-2.7.0-py2.py3-none-any.whl (77 kB)\nRequirement already satisfied, skipping upgrade: docker; extra == \"all\" in /root/.local/share/virtualenvs/bench-DjFm5PZm8q-aRtk-7Go/lib/python3.8/site-packages (from aea[all]==0.6.0) (4.2.0)\nCollecting python-dotenv; extra == \"all\"\n  Downloading python_dotenv-0.14.0-py2.py3-none-any.whl (17 kB)\nRequirement already satisfied, skipping upgrade: click; extra == \"all\" in /root/.local/share/virtualenvs/bench-DjFm5PZm8q-aRtk-7Go/lib/python3.8/site-packages (from aea[all]==0.6.0) (7.1.2)\nCollecting flask; extra == \"all\"\n  Downloading Flask-1.1.2-py2.py3-none-any.whl (94 kB)\nRequirement already satisfied, skipping upgrade: six>=1.9.0 in /root/.local/share/virtualenvs/bench-DjFm5PZm8q-aRtk-7Go/lib/python3.8/site-packages (from ecdsa==0.15->aea[all]==0.6.0) (1.15.0)\nRequirement already satisfied, skipping upgrade: multiaddr>=0.0.7 in /root/.local/share/virtualenvs/bench-DjFm5PZm8q-aRtk-7Go/lib/python3.8/site-packages (from ipfshttpclient==0.6.1->aea[all]==0.6.0) (0.0.9)\nRequirement already satisfied, skipping upgrade: chardet<3.1.0,>=3.0.2 in /root/.local/share/virtualenvs/bench-DjFm5PZm8q-aRtk-7Go/lib/python3.8/site-packages (from requests==2.22.0->aea[all]==0.6.0) (3.0.4)\nRequirement already satisfied, skipping upgrade: idna<2.9,>=2.5 in /root/.local/share/virtualenvs/bench-DjFm5PZm8q-aRtk-7Go/lib/python3.8/site-packages (from requests==2.22.0->aea[all]==0.6.0) (2.8)\nRequirement already satisfied, skipping upgrade: certifi>=2017.4.17 in /root/.local/share/virtualenvs/bench-DjFm5PZm8q-aRtk-7Go/lib/python3.8/site-packages (from requests==2.22.0->aea[all]==0.6.0) (2020.6.20)\nRequirement already satisfied, skipping upgrade: urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 in /root/.local/share/virtualenvs/bench-DjFm5PZm8q-aRtk-7Go/lib/python3.8/site-packages (from requests==2.22.0->aea[all]==0.6.0) (1.25.10)\nRequirement already satisfied, skipping upgrade: setuptools in /root/.local/share/virtualenvs/bench-DjFm5PZm8q-aRtk-7Go/lib/python3.8/site-packages (from protobuf->aea[all]==0.6.0) (49.6.0)\nRequirement already satisfied, skipping upgrade: pyrsistent>=0.14.0 in /root/.local/share/virtualenvs/bench-DjFm5PZm8q-aRtk-7Go/lib/python3.8/site-packages (from jsonschema>=3.0.0->aea[all]==0.6.0) (0.16.0)\nRequirement already satisfied, skipping upgrade: attrs>=17.4.0 in /root/.local/share/virtualenvs/bench-DjFm5PZm8q-aRtk-7Go/lib/python3.8/site-packages (from jsonschema>=3.0.0->aea[all]==0.6.0) (20.2.0)\nCollecting bitarray<1.3.0,>=1.2.1\n  Downloading bitarray-1.2.2.tar.gz (48 kB)\nCollecting hexbytes<1,>=0.1.0\n  Downloading hexbytes-0.2.1-py3-none-any.whl (6.0 kB)\nCollecting eth-rlp<1,>=0.1.2\n  Downloading eth_rlp-0.2.0-py3-none-any.whl (5.0 kB)\nCollecting eth-keys!=0.3.2,<0.4.0,>=0.2.1\n  Downloading eth_keys-0.3.3-py3-none-any.whl (20 kB)\nCollecting rlp<2,>=1.0.0\n  Downloading rlp-1.2.0-py2.py3-none-any.whl (19 kB)\nCollecting eth-utils<2,>=1.3.0\n  Downloading eth_utils-1.9.5-py3-none-any.whl (23 kB)\nCollecting eth-keyfile<0.6.0,>=0.5.0\n  Downloading eth_keyfile-0.5.1-py3-none-any.whl (8.3 kB)\nCollecting eth-abi<3,>=2.0.0b7\n  Downloading eth_abi-2.1.1-py3-none-any.whl (27 kB)\nCollecting lru-dict<2.0.0,>=1.1.6\n  Downloading lru-dict-1.1.6.tar.gz (9.4 kB)\nCollecting websockets<9.0.0,>=8.1.0\n  Downloading websockets-8.1-cp38-cp38-manylinux2010_x86_64.whl (78 kB)\nCollecting eth-hash[pycryptodome]<1.0.0,>=0.2.0\n  Downloading eth_hash-0.2.0-py3-none-any.whl (7.2 kB)\nCollecting eth-typing<3.0.0,>=2.0.0\n  Downloading eth_typing-2.2.2-py3-none-any.whl (6.2 kB)\nRequirement already satisfied, skipping upgrade: pyparsing>=2.0.2 in /root/.local/share/virtualenvs/bench-DjFm5PZm8q-aRtk-7Go/lib/python3.8/site-packages (from packaging>=20.3->aea[all]==0.6.0) (2.4.7)\nRequirement already satisfied, skipping upgrade: openapi-spec-validator>=0.2.4 in /root/.local/share/virtualenvs/bench-DjFm5PZm8q-aRtk-7Go/lib/python3.8/site-packages (from connexion[swagger-ui]>=2.4.0; extra == \"all\"->aea[all]==0.6.0) (0.2.8)\nCollecting clickclick>=1.2\n  Downloading clickclick-1.2.2-py2.py3-none-any.whl (9.8 kB)\nCollecting inflection>=0.3.1\n  Downloading inflection-0.5.1-py2.py3-none-any.whl (9.5 kB)\nCollecting swagger-ui-bundle>=0.0.2; extra == \"swagger-ui\"\n  Downloading swagger_ui_bundle-0.0.8-py3-none-any.whl (3.8 MB)\nRequirement already satisfied, skipping upgrade: websocket-client>=0.32.0 in /root/.local/share/virtualenvs/bench-DjFm5PZm8q-aRtk-7Go/lib/python3.8/site-packages (from docker; extra == \"all\"->aea[all]==0.6.0) (0.57.0)\nRequirement already satisfied, skipping upgrade: Jinja2>=2.10.1 in /root/.local/share/virtualenvs/bench-DjFm5PZm8q-aRtk-7Go/lib/python3.8/site-packages (from flask; extra == \"all\"->aea[all]==0.6.0) (2.11.2)\nCollecting itsdangerous>=0.24\n  Downloading itsdangerous-1.1.0-py2.py3-none-any.whl (16 kB)\nRequirement already satisfied, skipping upgrade: Werkzeug>=0.15 in /root/.local/share/virtualenvs/bench-DjFm5PZm8q-aRtk-7Go/lib/python3.8/site-packages (from flask; extra == \"all\"->aea[all]==0.6.0) (1.0.1)\nRequirement already satisfied, skipping upgrade: varint in /root/.local/share/virtualenvs/bench-DjFm5PZm8q-aRtk-7Go/lib/python3.8/site-packages (from multiaddr>=0.0.7->ipfshttpclient==0.6.1->aea[all]==0.6.0) (1.0.2)\nRequirement already satisfied, skipping upgrade: netaddr in /root/.local/share/virtualenvs/bench-DjFm5PZm8q-aRtk-7Go/lib/python3.8/site-packages (from multiaddr>=0.0.7->ipfshttpclient==0.6.1->aea[all]==0.6.0) (0.8.0)\nCollecting cytoolz<1.0.0,>=0.10.1; implementation_name == \"cpython\"\n  Downloading cytoolz-0.10.1.tar.gz (475 kB)\nRequirement already satisfied, skipping upgrade: pycryptodome<4.0.0,>=3.4.7 in /root/.local/share/virtualenvs/bench-DjFm5PZm8q-aRtk-7Go/lib/python3.8/site-packages (from eth-keyfile<0.6.0,>=0.5.0->eth-account==0.5.2->aea[all]==0.6.0) (3.9.8)\nCollecting parsimonious<0.9.0,>=0.8.0\n  Downloading parsimonious-0.8.1.tar.gz (45 kB)\nRequirement already satisfied, skipping upgrade: MarkupSafe>=0.23 in /root/.local/share/virtualenvs/bench-DjFm5PZm8q-aRtk-7Go/lib/python3.8/site-packages (from Jinja2>=2.10.1->flask; extra == \"all\"->aea[all]==0.6.0) (1.1.1)\nCollecting toolz>=0.8.0\n  Downloading toolz-0.10.0.tar.gz (49 kB)\nBuilding wheels for collected packages: bitarray, lru-dict, cytoolz, parsimonious, toolz\n  Building wheel for bitarray (setup.py): started\n  Building wheel for bitarray (setup.py): finished with status 'done'\n  Created wheel for bitarray: filename=bitarray-1.2.2-cp38-cp38-linux_x86_64.whl size=167712 sha256=bbb8f7bb90b9d8b62215424239d766b0a7e2beef7ef2d61395224993e1eb130a\n  Stored in directory: /root/.cache/pip/wheels/41/36/95/5b4eca059535a8400e8f4ca38f4883ea1801bb221fbd8170df\n  Building wheel for lru-dict (setup.py): started\n  Building wheel for lru-dict (setup.py): finished with status 'done'\n  Created wheel for lru-dict: filename=lru_dict-1.1.6-cp38-cp38-linux_x86_64.whl size=30640 sha256=109c28c39bb8c3272185a6ae17a46364f4757d2433e150b5dd6f4cdef1361c8a\n  Stored in directory: /root/.cache/pip/wheels/c6/91/94/23d462effc91bc844998b2023dc2dfd037a9d0a60034ddab16\n  Building wheel for cytoolz (setup.py): started\n  Building wheel for cytoolz (setup.py): finished with status 'done'\n  Created wheel for cytoolz: filename=cytoolz-0.10.1-cp38-cp38-linux_x86_64.whl size=1927948 sha256=e89af3c669a3cfe42667911024e435e47f72cfe976f8858c3d9f7235f052cbb0\n  Stored in directory: /root/.cache/pip/wheels/7f/71/e7/690b241fea90859f7ed6defe9c56e37ab9b7dcd80a4067dc54\n  Building wheel for parsimonious (setup.py): started\n  Building wheel for parsimonious (setup.py): finished with status 'done'\n  Created wheel for parsimonious: filename=parsimonious-0.8.1-py3-none-any.whl size=42710 sha256=44be43c73c058b615f3d9c6a2ea08cd1556a50b83d6473f75d29e3f842ebe68f\n  Stored in directory: /root/.cache/pip/wheels/d8/af/19/fb896f509a437aca2dcf62583e84d7fb2cd5b628c1564a609c\n  Building wheel for toolz (setup.py): started\n  Building wheel for toolz (setup.py): finished with status 'done'\n  Created wheel for toolz: filename=toolz-0.10.0-py3-none-any.whl size=55576 sha256=3da2914c4fbbc90e5236295bb458c37ab82c22cd3d633ab82882a204986b12d6\n  Stored in directory: /root/.cache/pip/wheels/a5/2b/b5/05758d5828d65f2adef8fbb5d5484e4adb946ae1827a973a01\nSuccessfully built bitarray lru-dict cytoolz parsimonious toolz\nInstalling collected packages: ecdsa, pymultihash, semver, bitarray, hexbytes, eth-hash, eth-typing, toolz, cytoolz, eth-utils, rlp, eth-rlp, eth-keys, eth-keyfile, parsimonious, eth-abi, eth-account, lru-dict, websockets, web3, bech32, itsdangerous, flask, clickclick, inflection, swagger-ui-bundle, connexion, python-dotenv, aea\nSuccessfully installed aea-0.6.0 bech32-1.2.0 bitarray-1.2.2 clickclick-1.2.2 connexion-2.7.0 cytoolz-0.10.1 ecdsa-0.15 eth-abi-2.1.1 eth-account-0.5.2 eth-hash-0.2.0 eth-keyfile-0.5.1 eth-keys-0.3.3 eth-rlp-0.2.0 eth-typing-2.2.2 eth-utils-1.9.5 flask-1.1.2 hexbytes-0.2.1 inflection-0.5.1 itsdangerous-1.1.0 lru-dict-1.1.6 parsimonious-0.8.1 pymultihash-0.8.2 python-dotenv-0.14.0 rlp-1.2.0 semver-2.10.2 swagger-ui-bundle-0.0.8 toolz-0.10.0 web3-5.12.0 websockets-8.1\nPerformance report for 05.09.2020_17:49\n-----------------------------\n\nReactive: number of runs: 100, duration: 10\n----------------------------------------------------\nruntime mode        value          mean        stdev\n----------------------------------------------------\nthreaded    latency     800.629597    14.672578\nthreaded    rate     1106.762    18.863731\nasync    latency     526.03548    5.211927\nasync    rate     1630.32    16.211843\n\nProactive: number of runs: 100, duration: 10\n----------------------------------------------------\nruntime mode        value          mean        stdev\n----------------------------------------------------\nthreaded    rate     4587.775    820.52555\nasync    rate     6158.846    516.349488\n\nMultiAgent: number of runs: 3, duration: 3, messages: 100\n------------------------------------------------------------------\nruntime mode     num_agents       value          mean        stdev\n------------------------------------------------------------------\nthreaded     2    rate     1244.333333    19.341952\nthreaded     2    mem     54.832031    0.222382\nthreaded     2    RTT     0.334617    0.001791\nthreaded     2    latency     0.166745    0.000905\nthreaded     4    rate     1389.444444    108.157464\nthreaded     4    mem     56.289062    0.299306\nthreaded     4    RTT     1.994238    0.015903\nthreaded     4    latency     1.00406    0.011688\nthreaded     8    rate     2499.777778    258.057774\nthreaded     8    mem     61.90625    0.547377\nthreaded     8    RTT     4.667974    0.410991\nthreaded     8    latency     2.988324    0.210826\nthreaded     16    rate     14042.333333    862.192812\nthreaded     16    mem     77.326823    0.394364\nthreaded     16    RTT     23.403793    0.618454\nthreaded     16    latency     13.766599    0.152124\nasync     2    rate     1200.222222    14.369464\nasync     2    mem     55.052083    0.245079\nasync     2    RTT     0.343028    0.003275\nasync     2    latency     0.170238    0.002034\nasync     4    rate     1168.222222    44.762749\nasync     4    mem     56.222656    0.343128\nasync     4    RTT     2.056596    0.091798\nasync     4    latency     1.051261    0.033161\nasync     8    rate     2012.555556    73.014712\nasync     8    mem     61.355469    0.332651\nasync     8    RTT     4.312067    0.1969\nasync     8    latency     3.101899    0.217263\nasync     16    rate     6193.666667    578.218048\nasync     16    mem     76.97526    1.526111\nasync     16    RTT     12.952551    2.512823\nasync     16    latency     9.581866    1.340397\nDone!\n"
  },
  {
    "path": "benchmark/checks/data/2020.10.27_mem_usage_report.txt",
    "content": "Performance report for 27.10.2020_17:06\n-----------------------------\n\n\n\nMulti agents with http dialogues: number of runs: 10, num_agents: 10, messages: 100\n------------------------------------------------------------------\nruntime mode     duration       value          mean        stdev\n------------------------------------------------------------------\nasync\t\t     2\t\t    mem\t     87.979687    0.829828\nasync\t\t     5\t\t    mem\t     91.964844    1.508087\nasync\t\t     10\t\t    mem\t     97.392578    1.318029\nasync\t\t     20\t\t    mem\t     107.630859    2.540685\nasync\t\t     30\t\t    mem\t     118.990234    1.807382\nasync\t\t     50\t\t    mem\t     142.086328    3.1786\n\n\nMessage generation and allocation: number of runs: 10\n------------------------------------------------------------------\nmessage        value          mean        stdev\n------------------------------------------------------------------\n10000\t\t    mem\t     6.171484    0.045347\n10000\t\t    time     0.633887    0.048279\n50000\t\t    mem\t     30.24375    0.045969\n50000\t\t    time     3.303643    0.115329\n100000\t\t    mem\t     60.433203    0.083708\n100000\t\t    time     6.773516    0.14151\n\n\nDialogues message processing: number of runs: 10\n------------------------------------------------------------------\nmessage        value          mean        stdev\n------------------------------------------------------------------\n10000\t\t    mem\t     31.895703    0.024777\n10000\t\t    time     4.464438    0.218168\n20000\t\t    mem\t     63.472656    0.04187\n20000\t\t    time     8.889359    0.291928\n50000\t\t    mem\t     162.076953    0.019317\n50000\t\t    time     22.409405    0.52609\n"
  },
  {
    "path": "benchmark/checks/data/2020.10.30 optimized messages.txt",
    "content": "Start Test\nPerformance report for 30.10.2020_15:37\n-----------------------------\n\n\n\nMulti agents with http dialogues: number of runs: 10, num_agents: 10, messages: 100\n------------------------------------------------------------------\nruntime mode     duration       value          mean        stdev\n------------------------------------------------------------------\nasync\t\t     2\t\t    mem\t     79.781641    0.882952\nasync\t\t     5\t\t    mem\t     80.928906    3.816324\nasync\t\t     10\t\t    mem\t     86.929688    0.739895\nasync\t\t     20\t\t    mem\t     94.683203    0.871148\nasync\t\t     30\t\t    mem\t     100.952344    2.460479\nasync\t\t     50\t\t    mem\t     114.601562    5.314621\n\n\nMessage generation and allocation: number of runs: 10\n------------------------------------------------------------------\nmessage        value          mean        stdev\n------------------------------------------------------------------\n10000\t\t    mem\t     2.438281    0.05618\n10000\t\t    time     0.772864    0.106754\n50000\t\t    mem\t     12.507422    0.001235\n50000\t\t    time     3.949191    0.182593\n100000\t\t    mem\t     24.722656    0.0\n100000\t\t    time     7.435021    0.232879\n\n\nDialogues message processing: number of runs: 10\n------------------------------------------------------------------\nmessage        value          mean        stdev\n------------------------------------------------------------------\n10000\t\t    mem\t     22.803906    0.01424\n10000\t\t    time     4.745211    0.179063\n20000\t\t    mem\t     45.456641    0.077262\n20000\t\t    time     9.931134    0.405339\n50000\t\t    mem\t     116.507422    0.061141\n50000\t\t    time     24.472803    0.325537\npod \"benchmark-checks\" deleted\n"
  },
  {
    "path": "benchmark/checks/data/2020.12.10_optimized_messages.txt",
    "content": "Performance report for 10.12.2020_09:32\n-----------------------------\n\n\n\nMulti agents with http dialogues: number of runs: 100, num_agents: 10, messages: 100\n------------------------------------------------------------------\nruntime mode     duration       value          mean        stdev\n------------------------------------------------------------------\nasync\t\t     2\t\t    mem\t     71.147305    0.636357\nasync\t\t     5\t\t    mem\t     71.937031    0.630627\nasync\t\t     10\t\t    mem\t     73.255586    0.891906\nasync\t\t     20\t\t    mem\t     75.449219    0.901333\nasync\t\t     30\t\t    mem\t     77.292383    0.808147\n\nasync\t\t     50\t\t    mem\t     81.357891    1.194153\n\n\nMessage generation and allocation: number of runs: 100\n------------------------------------------------------------------\nmessage        value          mean        stdev\n------------------------------------------------------------------\n10000\t\t    mem\t     1.514961    0.02531\n10000\t\t    time     0.567152    0.070787\n50000\t\t    mem\t     7.804883    0.000856\n50000\t\t    time     2.942939    0.233939\n100000\t\t    mem\t     15.384297    0.003956\n100000\t\t    time     5.779464    0.321653\n\n\nDialogues message processing: number of runs: 100\n------------------------------------------------------------------\nmessage        value          mean        stdev\n------------------------------------------------------------------\n10000\t\t    mem\t     7.255781    0.062602\n10000\t\t    time     4.002207    0.275296\n"
  },
  {
    "path": "benchmark/checks/data/2021.03.09_test_run.txt",
    "content": "Performance report for 09.03.2021_21:45\n-----------------------------\n\n\n\nMulti agents with http dialogues: number of runs: 100, num_agents: 10, messages: 100\n------------------------------------------------------------------\nruntime mode     duration       value          mean        stdev\n------------------------------------------------------------------\nasync\t\t     2\t\t    mem\t     62.248555    0.530499\nasync\t\t     5\t\t    mem\t     63.226367    0.662026\nasync\t\t     10\t\t    mem\t     65.892383    0.527979\nasync\t\t     20\t\t    mem\t     68.232656    0.493123\nasync\t\t     30\t\t    mem\t     71.403828    0.592728\nasync\t\t     50\t\t    mem\t     77.623242    0.464335\n\n\nMessage generation and allocation: number of runs: 100\n------------------------------------------------------------------\nmessage        value          mean        stdev\n------------------------------------------------------------------\n10000\t\t    mem\t     0.45918    0.068106\n10000\t\t    time     0.482406    0.01351\n50000\t\t    mem\t     6.80457    0.120214\n50000\t\t    time     2.366248    0.026497\n100000\t\t    mem\t     14.542109    0.100293\n100000\t\t    time     4.770077    0.056299\n\n\nDialogues message processing: number of runs: 100\n------------------------------------------------------------------\nmessage        value          mean        stdev\n------------------------------------------------------------------\n10000\t\t    mem\t     6.991953    0.049681\n10000\t\t    time     3.377206    0.039903\n20000\t\t    mem\t     14.286914    0.039206\n20000\t\t    time     6.732406    0.060848\n50000\t\t    mem\t     37.929336    0.094448\n50000\t\t    time     16.87671    0.155116\n\n"
  },
  {
    "path": "benchmark/checks/data/2021.04.01_v1_benchmark.txt",
    "content": "Performance report for 01.04.2021\n-----------------------------\n\nMulti agents with http dialogues: number of runs: 100, num_agents: 10, messages: 100\n------------------------------------------------------------------\nruntime mode     duration       value          mean        stdev\n------------------------------------------------------------------\nasync\t\t     2\t\t    mem\t     63.065273    0.41207\nasync\t\t     5\t\t    mem\t     64.22625    0.379626\nasync\t\t     10\t\t    mem\t     66.182461    0.40166\nasync\t\t     20\t\t    mem\t     69.05918    0.282377\nasync\t\t     30\t\t    mem\t     71.520469    0.438192\nasync\t\t     50\t\t    mem\t     76.893984    0.882001\n\n\nMessage generation and allocation: number of runs: 100\n------------------------------------------------------------------\nmessage        value          mean        stdev\n------------------------------------------------------------------\n10000\t\t    mem\t     0.304688    0.051566\n10000\t\t    time     0.509305    0.031975\n50000\t\t    mem\t     6.645781    0.065213\n50000\t\t    time     2.743519    0.10603\n100000\t\t    mem\t     14.294063    0.024781\n100000\t\t    time     5.541937    0.326452\n\n\nDialogues message processing: number of runs: 100\n------------------------------------------------------------------\nmessage        value          mean        stdev\n------------------------------------------------------------------\n10000\t\t    mem\t     7.238008    0.065209\n10000\t\t    time     3.555162    0.141159\n20000\t\t    mem\t     14.319102    0.025112\n20000\t\t    time     6.942097    0.232013\n50000\t\t    mem\t     38.223203    0.139953\n50000\t\t    time     17.392467    0.503368\n\n\n\nReactive: number of runs: 100, duration: 10\n----------------------------------------------------\nruntime mode        value          mean        stdev\n----------------------------------------------------\nthreaded    latency     1350.913681    39.467721\nthreaded    rate     654.473    17.384876\nasync    latency     1094.870201    46.66503\nasync    rate     788.42    28.667664\n\nProactive: number of runs: 100, duration: 10\n----------------------------------------------------\nruntime mode        value          mean        stdev\n----------------------------------------------------\nthreaded    rate     3136.821    50.660694\nasync    rate     0.791    0.028762\n\nMultiAgent: number of runs: 100, duration: 10, messages: 100\n------------------------------------------------------------------\nruntime mode     num_agents       value          mean        stdev\n------------------------------------------------------------------\nthreaded     2    rate     675.654    13.657716\nthreaded     2    mem     48.126836    0.176016\nthreaded     2    RTT     0.596222    0.011607\nthreaded     2    latency     0.297669    0.005628\nthreaded     4    rate     679.966    17.678088\nthreaded     4    mem     49.095859    0.218971\nthreaded     4    RTT     3.662645    0.078505\nthreaded     4    latency     1.802625    0.03475\nthreaded     8    rate     1449.882    281.714217\nthreaded     8    mem     52.813281    0.467479\nthreaded     8    RTT     19.373796    3.780258\nthreaded     8    latency     10.401749    1.717344\nthreaded     16    rate     4735.086    1410.656106\nthreaded     16    mem     61.390781    1.540248\nthreaded     16    RTT     60.171576    14.865577\nthreaded     16    latency     35.057816    9.472234\nthreaded     32    rate     14810.817    6722.336041\nthreaded     32    mem     87.794141    8.46622\nthreaded     32    RTT     189.72728    79.581276\nthreaded     32    latency     122.309386    51.589368\nthreaded     64    rate     27860.344    18340.58782\nthreaded     64    mem     163.312305    44.267701\nthreaded     64    RTT     419.02488    271.182984\nthreaded     64    latency     282.563078    179.758986\nthreaded     128    rate     49397.043    18398.274532\nthreaded     128    mem     294.158906    103.471503\nthreaded     128    RTT     855.809125    483.501904\nthreaded     128    latency     568.189828    301.868828\nasync     2    rate     670.926    13.463461\nasync     2    mem     48.149766    0.174008\nasync     2    RTT     0.597284    0.012575\nasync     2    latency     0.298328    0.006285\nasync     4    rate     609.235    11.144201\nasync     4    mem     49.121719    0.154711\nasync     4    RTT     3.841597    0.070842\nasync     4    latency     1.858407    0.038073\nasync     8    rate     548.831    25.953609\nasync     8    mem     51.70832    0.193377\nasync     8    RTT     2.237455    4.020524\nasync     8    latency     6.375603    0.453957\nasync     16    rate     2249.182    823.35554\nasync     16    mem     55.84707    0.714784\nasync     16    RTT     28.762427    25.072808\nasync     16    latency     28.067046    12.508153\nasync     32    rate     3961.37    3479.249814\nasync     32    mem     70.209453    2.544705\nasync     32    RTT     38.147726    78.039112\nasync     32    latency     42.875331    68.118355\nasync     64    rate     7647.276    2359.938405\nasync     64    mem     132.389844    13.37811\nasync     64    RTT     167.018874    138.893537\nasync     64    latency     65.395231    79.366779\n\n"
  },
  {
    "path": "benchmark/checks/run_benchmark.sh",
    "content": "#!/bin/bash\nDATE=`LC_ALL=C date +\"%d.%m.%Y_%H:%M\"`\necho \"Performance report for $DATE\"\necho -e \"-----------------------------\\n\"\n\n\nDURATION=10\nNUM_RUNS=100\nMESSAGES=100\n\n\nchmod +x benchmark/checks/check_reactive.py\necho \"Reactive: number of runs: $NUM_RUNS, duration: $DURATION\"\necho \"----------------------------------------------------\"\necho \"runtime mode        value          mean        stdev\"\necho \"----------------------------------------------------\"\nfor mode in threaded async;\ndo\n\tdata=`./benchmark/checks/check_reactive.py --duration=$DURATION --number_of_runs=$NUM_RUNS --runtime_mode=$mode`\n\tlatency=`echo \"$data\"|grep latency|awk '{print $4 \"    \" $6}'`\n\trate=`echo \"$data\"|grep rate|awk '{print $4 \"    \" $6}'`\n\techo -e \"$mode    latency     ${latency}\"\n\techo -e \"$mode    rate     ${rate}\"\ndone\n# # ~ 10 * 2 * 100 sec = 33.3 min\n\n\nchmod +x benchmark/checks/check_proactive.py\necho -e \"\\nProactive: number of runs: $NUM_RUNS, duration: $DURATION\"\necho \"----------------------------------------------------\"\necho \"runtime mode        value          mean        stdev\"\necho \"----------------------------------------------------\"\nfor mode in threaded async;\ndo\n\tdata=`./benchmark/checks/check_proactive.py --duration=$DURATION --number_of_runs=$NUM_RUNS --runtime_mode=$mode`\n\tlatency=`echo \"$data\"|grep latency|awk '{print $4 \"    \" $6}'`\n\trate=`echo \"$data\"|grep rate|awk '{print $4 \"    \" $6}'`\n\techo -e \"$mode    rate     ${rate}\"\ndone\n# # ~ 10 * 2 * 100 sec = 33.3 min\n\nchmod +x benchmark/checks/check_multiagent.py\necho -e \"\\nMultiAgent: number of runs: $NUM_RUNS, duration: $DURATION, messages: $MESSAGES\"\necho \"------------------------------------------------------------------\"\necho \"runtime mode     num_agents       value          mean        stdev\"\necho \"------------------------------------------------------------------\"\nfor mode in threaded async;\ndo\n\tfor agent in 2 4 8 16 32 64 128;\n\tdo\n\t\tdata=`./benchmark/checks/check_multiagent.py --num_of_agents=$agent --duration=$DURATION --number_of_runs=$NUM_RUNS --runtime_mode=$mode --start_messages=$MESSAGES --runner_mode=threaded`\n\t\trate=`echo \"$data\"|grep rate|awk '{print $5 \"    \" $7}'`\n\t\tmem=`echo \"$data\"|grep Mem|awk '{print $5 \"    \" $7}'`\n\t\trtt_latency=`echo \"$data\"|grep 'RTT'|awk '{print $5 \"    \" $7}'`\n\t\tlatency=`echo \"$data\"|grep 'Latency'|awk '{print $5 \"    \" $7}'`\n\t\techo -e \"$mode     $agent    rate     ${rate}\"\n\t\techo -e \"$mode     $agent    mem     ${mem}\"\n\t\techo -e \"$mode     $agent    RTT     ${rtt_latency}\"\n\t\techo -e \"$mode     $agent    latency     ${latency}\"\n\tdone\ndone\n# ~ 10 * 2 * 4 * 100 sec = 133.3 min\n"
  },
  {
    "path": "benchmark/checks/run_benchmark_messages_mem.sh",
    "content": "#!/bin/bash\nDATE=`LC_ALL=C date +\"%d.%m.%Y_%H:%M\"`\necho \"Performance report for $DATE\"\necho -e \"-----------------------------\\n\"\n\nAGENTS=10\nNUM_RUNS=100\nMESSAGES=100\nRUNNER_MODE=threaded\n\n# check memory usage in terms of duration\nchmod +x benchmark/checks/check_multiagent_http_dialogues.py\necho -e \"\\n\\nMulti agents with http dialogues: number of runs: $NUM_RUNS, num_agents: $AGENTS, messages: $MESSAGES\"\necho \"------------------------------------------------------------------\"\necho \"runtime mode     duration       value          mean        stdev\"\necho \"------------------------------------------------------------------\"\nfor runtime_mode in async;\ndo\n\tfor duration in 2 5 10 20 30 50;\n\tdo\n\t\tcmd=\"./benchmark/checks/check_multiagent_http_dialogues.py --num_of_agents=$AGENTS --duration=$duration --number_of_runs=$NUM_RUNS --runtime_mode=$runtime_mode --start_messages=$MESSAGES --runner_mode=$RUNNER_MODE\"\n\t\tdata=`$cmd 2>>/dev/null`\n\t\trate=`echo \"$data\"|grep rate|awk '{print $5 \"    \" $7}'`\n\t\tmem=`echo \"$data\"|grep Mem|awk '{print $5 \"    \" $7}'`\n\t\trtt_latency=`echo \"$data\"|grep 'RTT'|awk '{print $5 \"    \" $7}'`\n\t\tlatency=`echo \"$data\"|grep 'Latency'|awk '{print $5 \"    \" $7}'`\n\t\t#echo -e \"$runtime_mode     $duration    rate     ${rate}\"\n\t\techo -e \"$runtime_mode\\t\\t     $duration\\t\\t    mem\\t     ${mem}\"\n\t\t#echo -e \"$runtime_mode     $duration    RTT     ${rtt_latency}\"\n\t\t#echo -e \"$runtime_mode     $duration    latency     ${latency}\"\n\tdone\ndone\n\n\n\n# check memory usage in terms of duration\nchmod +x benchmark/checks/check_messages_memory_usage.py\necho -e \"\\n\\nMessage generation and allocation: number of runs: $NUM_RUNS\"\necho \"------------------------------------------------------------------\"\necho \"message        value          mean        stdev\"\necho \"------------------------------------------------------------------\"\nfor messages in 10000 50000 100000;\ndo\n\tcmd=\"./benchmark/checks/check_messages_memory_usage.py --messages=$messages --number_of_runs=$NUM_RUNS\"\n\tdata=`$cmd 2>>/dev/null`\n\ttime=`echo \"$data\"|grep Time|awk '{print $5 \"    \" $7}'`\n\tmem=`echo \"$data\"|grep Mem|awk '{print $5 \"    \" $7}'`\n\techo -e \"$messages\\t\\t    mem\\t     ${mem}\"\n\techo -e \"$messages\\t\\t    time     ${time}\"\ndone\n\n\n\n# check memory usage in terms of duration\nchmod +x benchmark/checks/check_dialogues_memory_usage.py\necho -e \"\\n\\nDialogues message processing: number of runs: $NUM_RUNS\"\necho \"------------------------------------------------------------------\"\necho \"message        value          mean        stdev\"\necho \"------------------------------------------------------------------\"\nfor messages in 10000 20000 50000;\ndo\n\tcmd=\"./benchmark/checks/check_dialogues_memory_usage.py --messages=$messages --number_of_runs=$NUM_RUNS\"\n\tdata=`$cmd 2>>/dev/null`\n\ttime=`echo \"$data\"|grep Time|awk '{print $5 \"    \" $7}'`\n\tmem=`echo \"$data\"|grep Mem|awk '{print $5 \"    \" $7}'`\n\techo -e \"$messages\\t\\t    mem\\t     ${mem}\"\n\techo -e \"$messages\\t\\t    time     ${time}\"\ndone\n"
  },
  {
    "path": "benchmark/checks/utils.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Performance checks utils.\"\"\"\nimport asyncio\nimport inspect\nimport multiprocessing\nimport os\nimport time\nfrom multiprocessing import Pool\nfrom pathlib import Path\nfrom statistics import mean, stdev, variance\nfrom typing import Any, Callable, Dict, List, Optional, Tuple, Type\nfrom unittest.mock import MagicMock\n\nimport click\nimport psutil  # type: ignore\n\nfrom aea import AEA_DIR\nfrom aea.aea import AEA\nfrom aea.configurations.base import ConnectionConfig, PublicId, SkillConfig\nfrom aea.configurations.constants import (\n    DEFAULT_LEDGER,\n    DEFAULT_PROTOCOL,\n    PACKAGES,\n    PROTOCOLS,\n    SKILLS,\n    _FETCHAI_IDENTIFIER,\n)\nfrom aea.connections.base import Connection, ConnectionStates\nfrom aea.crypto.wallet import Wallet\nfrom aea.identity.base import Identity\nfrom aea.mail.base import Envelope\nfrom aea.protocols.base import Protocol\nfrom aea.registries.resources import Resources\nfrom aea.skills.base import Behaviour, Handler, Skill, SkillContext\n\nfrom packages.fetchai.protocols.default.message import DefaultMessage\n\n\nERROR_SKILL_NAME = \"error\"\nROOT_DIR = os.path.join(os.path.dirname(inspect.getfile(inspect.currentframe())))  # type: ignore\nPACKAGES_DIR = Path(AEA_DIR, \"..\", PACKAGES)\n\n\noutput_format_deco = click.option(\n    \"--output_format\", default=\"text\", help=\"Output format\"\n)\nnumber_of_runs_deco = click.option(\n    \"--number_of_runs\", default=10, help=\"How many times run test.\"\n)\n\n\ndef wait_for_condition(\n    condition_checker: Callable, timeout: int = 2, error_msg: str = \"Timeout\"\n) -> None:\n    \"\"\"Wait for condition occurs in selected timeout.\"\"\"\n    start_time = time.time()\n\n    while not condition_checker():\n        time.sleep(0.0001)\n        if time.time() > start_time + timeout:\n            raise TimeoutError(error_msg)\n\n\ndef make_agent(\n    agent_name: str = \"my_agent\",\n    runtime_mode: str = \"threaded\",\n    resources: Optional[Resources] = None,\n    identity: Optional[Identity] = None,\n) -> AEA:\n    \"\"\"Make AEA instance.\"\"\"\n    wallet = Wallet({DEFAULT_LEDGER: None})\n    identity = identity or Identity(\n        agent_name, address=agent_name, public_key=f\"public_key_for_{agent_name}\"\n    )\n    resources = resources or Resources()\n    datadir = os.getcwd()\n    agent_context = MagicMock()\n    agent_context.agent_name = agent_name\n    agent_context.agent_address = agent_name\n\n    resources.add_skill(\n        Skill.from_dir(\n            str(PACKAGES_DIR / _FETCHAI_IDENTIFIER / SKILLS / ERROR_SKILL_NAME),\n            agent_context=agent_context,\n        )\n    )\n    resources.add_protocol(\n        Protocol.from_dir(\n            str(\n                PACKAGES_DIR\n                / _FETCHAI_IDENTIFIER\n                / PROTOCOLS\n                / PublicId.from_str(DEFAULT_PROTOCOL).name\n            )\n        )\n    )\n    return AEA(identity, wallet, resources, datadir, runtime_mode=runtime_mode)\n\n\ndef make_envelope(\n    sender: str, to: str, message: Optional[DefaultMessage] = None\n) -> Envelope:\n    \"\"\"Make an envelope.\"\"\"\n    if message is None:\n        message = DefaultMessage(\n            dialogue_reference=(\"\", \"\"),\n            message_id=1,\n            target=0,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"content\",\n        )\n    message.sender = sender\n    message.to = to\n    return Envelope(\n        to=to,\n        sender=sender,\n        message=message,\n    )\n\n\nclass GeneratorConnection(Connection):\n    \"\"\"Generates messages and count.\"\"\"\n\n    connection_id = PublicId(\"fetchai\", \"generator\", \"0.1.0\")\n    ENABLED_WAIT_SLEEP = 0.00001\n\n    def __init__(self, *args: Any, **kwargs: Any):\n        \"\"\"Init connection.\"\"\"\n        super().__init__(*args, **kwargs)\n        self._enabled = False\n        self.count_in = 0\n        self.count_out = 0\n\n    def enable(self) -> None:\n        \"\"\"Enable message generation.\"\"\"\n        self._enabled = True\n\n    def disable(self) -> None:\n        \"\"\"Disable message generation.\"\"\"\n        self._enabled = False\n\n    async def connect(self) -> None:\n        \"\"\"Connect connection.\"\"\"\n        self._state.set(ConnectionStates.connected)\n\n    async def disconnect(self) -> None:\n        \"\"\"Disconnect connection.\"\"\"\n        self._state.set(ConnectionStates.disconnected)\n\n    async def send(self, envelope: \"Envelope\") -> None:\n        \"\"\"Handle incoming envelope.\"\"\"\n        self.count_in += 1\n\n    async def receive(self, *args: Any, **kwargs: Any) -> Optional[\"Envelope\"]:\n        \"\"\"Generate an envelope.\"\"\"\n        while not self._enabled:\n            await asyncio.sleep(self.ENABLED_WAIT_SLEEP)\n\n        envelope = make_envelope(self.address, \"echo_skill\")\n        self.count_out += 1\n        return envelope\n\n    @classmethod\n    def make(\n        cls,\n    ) -> \"GeneratorConnection\":\n        \"\"\"Construct connection instance.\"\"\"\n        configuration = ConnectionConfig(\n            connection_id=cls.connection_id,\n        )\n        test_connection = cls(\n            configuration=configuration,\n            identity=Identity(\"name\", \"address\", \"public_key\"),\n            data_dir=\".tmp\",\n        )\n        return test_connection\n\n\nclass SyncedGeneratorConnection(GeneratorConnection):\n    \"\"\"Synchronized message generator.\"\"\"\n\n    def __init__(self, *args: Any, **kwargs: Any) -> None:\n        \"\"\"Init connection.\"\"\"\n        super().__init__(*args, **kwargs)\n        self._condition: Optional[asyncio.Event] = None\n\n    @property\n    def condition(self) -> asyncio.Event:\n        \"\"\"Get condition.\"\"\"\n        if self._condition is None:\n            raise ValueError(\"Event not set.\")\n        return self._condition\n\n    async def connect(self) -> None:\n        \"\"\"Connect connection.\"\"\"\n        await super().connect()\n        self._condition = asyncio.Event()\n        self.condition.set()\n\n    async def send(self, envelope: \"Envelope\") -> None:\n        \"\"\"Handle incoming envelope.\"\"\"\n        await super().send(envelope)\n        self.condition.set()\n\n    async def receive(self, *args: Any, **kwargs: Any) -> Optional[\"Envelope\"]:\n        \"\"\"Generate an envelope.\"\"\"\n        await self.condition.wait()\n        self.condition.clear()\n        return await super().receive(*args, **kwargs)\n\n\ndef make_skill(\n    agent: AEA,\n    handlers: Optional[Dict[str, Type[Handler]]] = None,\n    behaviours: Optional[Dict[str, Type[Behaviour]]] = None,\n) -> Skill:\n    \"\"\"Construct skill instance for agent from behaviours.\"\"\"\n    handlers = handlers or {}\n    behaviours = behaviours or {}\n    config = SkillConfig(name=\"test_skill\", author=\"fetchai\")\n    skill_context = SkillContext(agent.context)\n    skill = Skill(configuration=config, skill_context=skill_context)\n    for name, handler_cls in handlers.items():\n        handler = handler_cls(name=name, skill_context=skill_context)\n        skill.handlers.update({handler.name: handler})\n\n    for name, behaviour_cls in behaviours.items():\n        behaviour = behaviour_cls(name=name, skill_context=skill_context)\n        skill.behaviours.update({behaviour.name: behaviour})\n    return skill\n\n\ndef get_mem_usage_in_mb() -> float:\n    \"\"\"Get memory usage of the current process in megabytes.\"\"\"\n    return 1.0 * psutil.Process(os.getpid()).memory_info().rss / 1024**2\n\n\ndef multi_run(\n    num_runs: int, fn: Callable, args: Tuple\n) -> List[Tuple[str, Any, Any, Any]]:\n    \"\"\"\n    Perform multiple test runs.\n\n    :param num_runs: host many times to run\n    :param fn: callable  that returns list of tuples with result\n    :param args: args to pass to callable\n\n    :return: list of tuples of results\n    \"\"\"\n    multiprocessing.set_start_method(\"spawn\")\n    results = []\n    for _ in range(num_runs):\n        with Pool(1) as p:\n            results.append(p.apply(fn, tuple(args)))\n        del p\n\n    mean_values = map(mean, zip(*(map(lambda x: x[1], i) for i in results)))\n    stdev_values = map(stdev, zip(*(map(lambda x: x[1], i) for i in results)))\n    variance_values = map(variance, zip(*(map(lambda x: x[1], i) for i in results)))\n    return list(\n        zip(map(lambda x: x[0], results[0]), mean_values, stdev_values, variance_values)\n    )\n\n\ndef print_results(\n    output_format: str,\n    parameters: Dict,\n    result_fn: Callable[..., List[Tuple[str, Any, Any, Any]]],\n) -> Any:\n    \"\"\"Print result for multi_run response.\"\"\"\n    if output_format != \"text\":\n        raise ValueError(f\"Bad output format {output_format}\")\n\n    click.echo(\"Start test with options:\")\n    for name, value in parameters.items():\n        click.echo(f\"* {name}: {value}\")\n    click.echo(\"\\nResults:\")\n    for msg, *values_set in result_fn():\n        mean_, stdev_, variance_ = map(lambda x: round(x, 6), values_set)\n        click.echo(f\" * {msg}: mean: {mean_} stdev: {stdev_} variance: {variance_} \")\n    click.echo(\"Test finished.\")\n"
  },
  {
    "path": "benchmark/framework/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Performance testing framework.\"\"\"\n"
  },
  {
    "path": "benchmark/framework/aea_test_wrapper.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This test module contains AEA/AEABuilder wrapper to make performance tests easy.\"\"\"\n\nimport uuid\nfrom threading import Thread\nfrom typing import Dict, List, Optional, Tuple, Type, Union\n\nfrom aea.aea import AEA\nfrom aea.aea_builder import AEABuilder\nfrom aea.components.base import Component\nfrom aea.configurations.base import SkillConfig\nfrom aea.configurations.constants import _FETCHAI_IDENTIFIER\nfrom aea.mail.base import Envelope\nfrom aea.protocols.base import Message\nfrom aea.skills.base import Handler, Skill, SkillContext\nfrom benchmark.framework.fake_connection import FakeConnection\n\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.protocols.default.serialization import DefaultSerializer\n\n\nclass AEATestWrapper:\n    \"\"\"A testing wrapper to run and control an agent.\"\"\"\n\n    def __init__(self, name: str = \"my_aea\", components: List[Component] = None):\n        \"\"\"\n        Make an agency with optional name and skills.\n\n        :param name: name of the agent\n        :param components: dict of components to add to agent\n        \"\"\"\n        self.components = components or []\n        self.name = name\n        self._fake_connection: Optional[FakeConnection] = None\n\n        self.aea = self.make_aea(self.name, self.components)\n        self._thread = None  # type: Optional[Thread]\n\n    def make_aea(\n        self, name: Optional[str] = None, components: List[Component] = None\n    ) -> AEA:\n        \"\"\"\n        Create AEA from name and already loaded components.\n\n        :param name: name of the agent\n        :param components: list of components to add to agent\n\n        :return: AEA\n        \"\"\"\n        components = components or []\n        builder = AEABuilder()\n\n        builder.set_name(name or self.name)\n\n        builder.add_private_key(_FETCHAI_IDENTIFIER, private_key_path=None)\n\n        for component in components:\n            builder.add_component_instance(component)\n\n        aea = builder.build()\n        return aea\n\n    @classmethod\n    def make_skill(\n        cls,\n        config: SkillConfig = None,\n        context: SkillContext = None,\n        handlers: Optional[Dict[str, Type[Handler]]] = None,\n    ) -> Skill:\n        \"\"\"\n        Make a skill from optional config, context, handlers dict.\n\n        :param config: SkillConfig\n        :param context: SkillContext\n        :param handlers: dict of handler types to add to skill\n\n        :return: Skill\n        \"\"\"\n        handlers = handlers or {}\n        context = context or SkillContext()\n        config = config or SkillConfig(\n            name=\"skill_{}\".format(uuid.uuid4().hex[0:5]), author=\"fetchai\"\n        )\n\n        handlers_instances = {\n            name: handler_cls(name=name, skill_context=context)\n            for name, handler_cls in handlers.items()\n        }\n\n        skill = Skill(\n            configuration=config, skill_context=context, handlers=handlers_instances\n        )\n        return skill\n\n    @classmethod\n    def dummy_default_message(\n        cls,\n        dialogue_reference: Tuple[str, str] = (\"\", \"\"),\n        message_id: int = 1,\n        target: int = 0,\n        performative: DefaultMessage.Performative = DefaultMessage.Performative.BYTES,\n        content: Union[str, bytes] = \"hello world!\",\n    ) -> Message:\n        \"\"\"\n        Construct simple message, all arguments are optional.\n\n        :param dialogue_reference: the dialogue reference.\n        :param message_id: the message id.\n        :param target: the message target.\n        :param performative: the message performative.\n        :param content: string or bytes payload.\n\n        :return: Message\n        \"\"\"\n        if isinstance(content, str):\n            content = content.encode(\"utf-8\")\n\n        return DefaultMessage(\n            dialogue_reference=dialogue_reference,\n            message_id=message_id,\n            target=target,\n            performative=performative,\n            content=content,\n        )\n\n    @classmethod\n    def dummy_envelope(\n        cls,\n        to: str = \"test\",\n        sender: str = \"test\",\n        message: Message = None,\n    ) -> Envelope:\n        \"\"\"\n        Create envelope, if message is not passed use .dummy_message method.\n\n        :param to: the address of the receiver.\n        :param sender: the address of the sender.\n        :param message: the protocol-specific message.\n\n        :return: Envelope\n        \"\"\"\n        message = message or cls.dummy_default_message()\n        return Envelope(\n            to=to,\n            sender=sender,\n            protocol_specification_id=DefaultMessage.protocol_specification_id,\n            message=DefaultSerializer().encode(message),\n        )\n\n    def set_loop_timeout(self, period: float) -> None:\n        \"\"\"\n        Set agent's loop timeout.\n\n        :param period: idle sleep timeout for agent's loop\n        \"\"\"\n        self.aea._period = period  # pylint: disable=protected-access\n\n    def setup(self) -> None:\n        \"\"\"Set up agent: start multiplexer etc.\"\"\"\n        self.aea.setup()\n\n    def stop(self) -> None:\n        \"\"\"Stop the agent.\"\"\"\n        self.aea.stop()\n\n    def put_inbox(self, envelope: Envelope) -> None:\n        \"\"\"\n        Add an envelope to agent's inbox.\n\n        :param envelope: envelope to process by agent\n        \"\"\"\n        self.aea.runtime.multiplexer.in_queue.put(envelope)\n\n    def is_inbox_empty(self) -> bool:\n        \"\"\"\n        Check there is no messages in inbox.\n\n        :return: boolean indicating whether inbox is empty\n        \"\"\"\n        return self.aea.runtime.multiplexer.in_queue.empty()\n\n    def __enter__(self) -> None:\n        \"\"\"Context manager enter.\"\"\"\n        self.start_loop()\n\n    def __exit__(  # type: ignore # pylint: disable=useless-return\n        self, exc_type=None, exc=None, traceback=None\n    ) -> None:\n        \"\"\"Context manager exit, stop agent.\"\"\"\n        self.stop_loop()\n        return None\n\n    def start_loop(self) -> None:\n        \"\"\"Start agents loop in dedicated thread.\"\"\"\n        self._thread = Thread(target=self.aea.start)\n        self._thread.start()\n\n    def stop_loop(self) -> None:\n        \"\"\"Stop agents loop in dedicated thread, close thread.\"\"\"\n        if self._thread is None:\n            raise ValueError(\"Thread not set, call start_loop first.\")\n        self.aea.stop()\n        self._thread.join()\n\n    def is_running(self) -> bool:\n        \"\"\"\n        Check is agent loop is set as running.\n\n        :return: bool\n        \"\"\"\n        return not self.aea.is_running\n\n    def set_fake_connection(\n        self, inbox_num: int, envelope: Optional[Envelope] = None\n    ) -> None:\n        \"\"\"\n        Add fake connection for testing.\n\n        :param inbox_num: number of messages to generate by connection.\n        :param envelope: envelope to generate. dummy one created by default.\n        \"\"\"\n        if self._fake_connection:\n            raise Exception(\"Fake connection is already set!\")\n\n        envelope = envelope or self.dummy_envelope()\n        self._fake_connection = FakeConnection(\n            envelope, inbox_num, connection_id=\"fake_connection\"\n        )\n        self.aea.runtime.multiplexer.add_connection(self._fake_connection)\n\n    def is_messages_in_fake_connection(self) -> bool:\n        \"\"\"\n        Check fake connection has messages left.\n\n        :return: bool\n        \"\"\"\n        if not self._fake_connection:\n            raise Exception(\"Fake connection is not set!\")\n        return self._fake_connection.num != 0  # type: ignore # cause fake connection is used.\n"
  },
  {
    "path": "benchmark/framework/benchmark.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Helper for benchmark run control.\"\"\"\nfrom multiprocessing import Queue\n\n\nclass BenchmarkControl:\n    \"\"\"Class to sync executor and function in test.\"\"\"\n\n    START_MSG = \"start\"\n\n    def __init__(self) -> None:\n        \"\"\"Init.\"\"\"\n        self._queue: Queue = Queue(2)\n\n    def start(self) -> None:\n        \"\"\"Notify executor to start measure resources.\"\"\"\n        self._queue.put(self.START_MSG)\n\n    def wait_msg(self) -> str:\n        \"\"\"\n        Wait a message from function being tested.\n\n        :return: message from tested function.\n        \"\"\"\n        return self._queue.get()\n"
  },
  {
    "path": "benchmark/framework/cli.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Cli implementation for performance tests suits.\"\"\"\nimport ast\nimport inspect\nfrom typing import Any, Callable, Dict, List, Optional, Tuple, Type\n\nimport click\nfrom click.core import Argument, Command, Context, Option, Parameter\n\nfrom .executor import Executor\nfrom .func_details import BenchmarkFuncDetails\nfrom .report_printer import PerformanceReport, ReportPrinter\n\n\nclass DefaultArgumentsMultiple(Argument):\n    \"\"\"Multiple arguments with default value.\"\"\"\n\n    def __init__(self, *args: Any, **kwargs: Any) -> None:\n        \"\"\"Create MultipleArguments instance.\"\"\"\n        kwargs[\"nargs\"] = -1\n        default = kwargs.pop(\"default\", tuple())\n        super().__init__(*args, **kwargs)\n        self.default = default\n\n    def full_process_value(self, ctx: Context, value: Any) -> Any:\n        \"\"\"\n        Given a value and context this runs the logic to convert the value as necessary.\n\n        :param ctx: command context\n        :param value: value for option parsed from command line\n\n        :return: value for option\n        \"\"\"\n        if not value:\n            value = self.default\n        else:\n            value = [self._parse_arg_str(i) for i in value]\n        return super().process_value(ctx, value)\n\n    @staticmethod\n    def _parse_arg_str(args: str) -> Tuple[Any]:\n        \"\"\"\n        Parse arguments string to tuple.\n\n        :param args: arguments string separated by comma\n\n        :return: tuple of parsed arguments\n        \"\"\"\n        parsed = ast.literal_eval(args)\n\n        if not isinstance(parsed, tuple):\n            parsed = (parsed,)\n\n        return parsed\n\n\nclass TestCli:\n    \"\"\"Performance test client.\"\"\"\n\n    def __init__(\n        self,\n        func: Callable,\n        executor_class: Type[Executor] = Executor,\n        report_printer_class: Type[ReportPrinter] = ReportPrinter,\n    ) -> None:\n        \"\"\"\n        Make performance client.\n\n        :param func: function to be tested.\n        :param executor_class: executor to be used for testing\n        :param report_printer_class: report printer to print results\n\n\n        func - should be function with first parameter multithreading.Queue\n        func  - should have docstring, and default values for every extra argument.\n\n        Example of usage:\n\n        def test_fn(benchmark: BenchmarkControl, list_size: int = 1000000):\n            # test list iteration\n            # prepare some data:\n            big_list = list(range(list_size))\n\n            # ready for test\n            benchmark.start()\n\n            for i in range(big_list):\n                i ** 2  # actually do nothing\n\n        TestCli(test_fn).run()\n        \"\"\"\n        self.func_details = BenchmarkFuncDetails(func)\n        self.func_details.check()\n        self.func = func\n        self.executor_class = executor_class\n        self.report_printer_class = report_printer_class\n        self._report_printer = None  # type: Optional[ReportPrinter]\n\n    @property\n    def report_printer(self) -> ReportPrinter:\n        \"\"\"Get report printer.\"\"\"\n        if self._report_printer is None:\n            raise ValueError(\"report printer not set!\")\n        return self._report_printer\n\n    def _make_command(self) -> Command:\n        \"\"\"\n        Make  cli.core.Command.\n\n        :return: a cli command\n        \"\"\"\n        return Command(\n            None,  # type: ignore\n            params=self._make_command_params(),\n            callback=self._command_callback,\n            help=self._make_help(),\n        )\n\n    def _make_command_params(self) -> Optional[List[Parameter]]:\n        \"\"\"\n        Make parameters and arguments for cli.Command.\n\n        :return: list of options and arguments for cli Command\n        \"\"\"\n        return list(self._executor_params().values()) + self._call_params()\n\n    def _make_help(self) -> str:\n        \"\"\"\n        Make help for command.\n\n        :return: str.\n        \"\"\"\n        doc_str = inspect.cleandoc(\n            f\"\"\"\n        {self.func_details.doc}\n\n        ARGS is function arguments in format: `{','.join(self.func_details.argument_names)}`\n\n        default ARGS is `{self.func_details.default_argument_values_as_string}`\n        \"\"\"\n        )\n        return doc_str\n\n    @staticmethod\n    def _executor_params() -> Dict[str, Parameter]:\n        \"\"\"\n        Get parameters used by Executor.\n\n        :return: dict of executor's parameters for cli Command\n        \"\"\"\n        parameters = {\n            \"timeout\": Option(\n                [\"--timeout\"],\n                default=10.0,\n                show_default=True,\n                help=\"Executor timeout in seconds\",\n                type=float,\n            ),\n            \"period\": Option(\n                [\"--period\"],\n                default=0.1,\n                show_default=True,\n                help=\"Period for measurement\",\n                type=float,\n            ),\n        }\n        return (\n            parameters  # type: ignore # for some reason mypy does not follow superclass\n        )\n\n    def _call_params(self) -> List[Parameter]:\n        \"\"\"\n        Make command option and parameters for test cases.\n\n        :return: function args set, number of executions option, plot option\n        \"\"\"\n        argument = DefaultArgumentsMultiple(\n            [\"args\"], default=[self.func_details.default_argument_values]\n        )\n        num_executions = Option(\n            [\"--num-executions\", \"-N\"],\n            default=1,\n            show_default=True,\n            help=\"Number of runs for each case\",\n            type=int,\n        )\n\n        plot = Option(\n            [\"--plot\", \"-P\"],\n            default=None,\n            show_default=True,\n            help=\"X axis parameter idx\",\n            type=int,\n        )\n        return [argument, num_executions, plot]\n\n    def run(self) -> None:\n        \"\"\"Run performance test.\"\"\"\n        command = self._make_command()\n        command()\n\n    def _command_callback(self, **params: Any) -> None:\n        \"\"\"\n        Run test on command.\n\n        :param params: dictionary of options and arguments of cli Command\n        \"\"\"\n        arguments_list = params.pop(\"args\")\n\n        executor_params = {\n            k: v for k, v in params.items() if k in self._executor_params()\n        }\n        executor = self.executor_class(**executor_params)\n\n        num_executions = params[\"num_executions\"]\n\n        self._report_printer = self.report_printer_class(\n            self.func_details, executor_params\n        )\n\n        self.report_printer.print_context_information()\n\n        reports = []\n\n        for arguments in arguments_list:\n            report = self._execute_num_times(arguments, executor, num_executions)\n            self.report_printer.print_report(report)\n            reports.append(report)\n\n        self._draw_plot(params, reports)\n\n    def _draw_plot(\n        self, params: Dict[str, Parameter], reports: List[PerformanceReport]\n    ) -> None:\n        \"\"\"\n        Draw a plot with case resources if param enabled by command option.\n\n        Block by plot window shown!\n\n        :param params: dict of command options passed\n        :param reports: list of performance reports to draw charts for\n        \"\"\"\n        xparam_idx = params.get(\"plot\")\n\n        if xparam_idx is None:\n            return\n\n        import matplotlib.pyplot as plt  # type: ignore # pylint: disable=import-outside-toplevel\n\n        reports_sorted_by_arg = sorted(reports, key=lambda x: x.arguments[xparam_idx])  # type: ignore\n\n        xaxis = [i.arguments[xparam_idx] for i in reports_sorted_by_arg]  # type: ignore\n\n        _, ax = plt.subplots(3)\n\n        # time\n        self._draw_resource(ax[0], xaxis, reports_sorted_by_arg, [0], \"Time\")\n\n        # cpu\n        self._draw_resource(ax[1], xaxis, reports_sorted_by_arg, [1, 2, 3], \"cpu\")\n\n        # mem\n        self._draw_resource(ax[2], xaxis, reports_sorted_by_arg, [4, 5, 6], \"mem\")\n        plt.show()\n\n    @staticmethod\n    def _draw_resource(\n        plt: \"matplotpib.axes.Axes\",  # type: ignore  # noqa: F821\n        xaxis: List[float],\n        reports: List[PerformanceReport],\n        resources_range: List[int],\n        title: str,\n    ) -> None:\n        \"\"\"\n        Draw a plot for specific resource.\n\n        :param plt: a subplot to draw on\n        :param xaxis: list of values for x axis\n        :param reports: performance reports to get values from\n        :param resources_range: list of resource ids in performance.resource list to draw values for\n        :param title: title for chart.\n        \"\"\"\n        for r in resources_range:\n            res = reports[0].resources[r]\n            label = res.name\n            plt.plot(xaxis, [i.resources[r].value for i in reports], label=label)\n            plt.set_ylabel(res.unit)\n            plt.set_title(title)\n            plt.legend()\n\n    def _execute_num_times(\n        self, arguments: Tuple[Any], executor: Executor, num_executions: int\n    ) -> PerformanceReport:\n        \"\"\"\n        Execute case several times and provide a performance report.\n\n        :param arguments: list of arguments for function tested.\n        :param executor: executor to run tests.\n        :param num_executions: how may times repeat test for arguments set.\n\n        :return: performance report with mean values for every resource counted for multiple runs\n        \"\"\"\n        exec_reports = [\n            executor.run(self.func, arguments) for _ in range(num_executions)\n        ]\n\n        return PerformanceReport(exec_reports)\n\n    def print_help(self) -> None:\n        \"\"\"Print help for command. can be invoked with --help option.\"\"\"\n        command = self._make_command()\n        with click.Context(command) as ctx:  # type: ignore\n            click.echo(command.get_help(ctx))\n"
  },
  {
    "path": "benchmark/framework/executor.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Executor to run and measure resources consumed by python code.\"\"\"\nimport datetime\nimport inspect\nimport multiprocessing\nimport time\nfrom collections import namedtuple\nfrom contextlib import contextmanager\nfrom multiprocessing import Process\nfrom operator import attrgetter\nfrom statistics import mean\nfrom typing import Callable, Generator, List, Tuple\n\nimport memory_profiler  # type: ignore\nimport psutil  # type: ignore\n\nfrom benchmark.framework.benchmark import BenchmarkControl  # noqa: I100\n\n\nclass TimeItResult:  # pylint: disable=too-few-public-methods\n    \"\"\"Class to store execution time for timeit_context.\"\"\"\n\n    def __init__(self) -> None:\n        \"\"\"Init with time passed = -1.\"\"\"\n        self.time_passed = -1.0\n\n\n@contextmanager\ndef timeit_context() -> Generator:\n    \"\"\"\n    Context manager to measure execution time of code in context.\n\n    :yield: TimeItResult\n\n    example:\n    with timeit_context() as result:\n        do_long_code()\n    print(\"Long code takes \", result.time_passed)\n    \"\"\"\n    result = TimeItResult()\n    started_time = time.time()\n    try:\n        yield result\n    finally:\n        result.time_passed = time.time() - started_time\n\n\nResourceStats = namedtuple(\"ResourceStats\", \"time,cpu,mem\")\n\n\nclass ExecReport:\n    \"\"\"Process execution report.\"\"\"\n\n    def __init__(\n        self,\n        args: tuple,\n        time_passed: float,\n        stats: List[ResourceStats],\n        is_killed: bool,\n        period: float,\n    ):\n        \"\"\"Make an instance.\n\n        :param args: tuple of arguments passed to function tested.\n        :param time_passed: time test function was executed.\n        :param stats: list of ResourceStats: cpu, mem.\n        :param is_killed: was process terminated by timeout.\n        :param period: what is measurement period length.\n        \"\"\"\n        self.args = args\n        self.report_created = datetime.datetime.now()\n        self.time_passed = time_passed\n        self.stats = stats\n        self.is_killed = is_killed\n        self.period = period\n\n    @property\n    def cpu(self) -> List[float]:\n        \"\"\"\n        Return list of cpu usage records.\n\n        :return: list of cpu usage values\n        \"\"\"\n        return list(map(attrgetter(\"cpu\"), self.stats))\n\n    @property\n    def mem(self) -> List[float]:\n        \"\"\"\n        Return list of memory usage records.\n\n        :return: list of memory usage values\n        \"\"\"\n        return list(map(attrgetter(\"mem\"), self.stats))\n\n    def __str__(self) -> str:\n        \"\"\"\n        Render report to string.\n\n        :return: string representation of report.\n        \"\"\"\n        return inspect.cleandoc(\n            f\"\"\"\n        == Report created {self.report_created} ==\n        Arguments are `{self.args}`\n        Time passed {self.time_passed}\n        Terminated by timeout: {self.is_killed}\n        Cpu(%) mean: {mean(self.cpu)}\n        Cpu(%) min: {min(self.cpu)}\n        Cpu(%) max: {max(self.cpu)}\n        Mem(kb) mean: {mean(self.mem)}\n        Mem(kb) min: {min(self.mem)}\n        Mem(kb) max: {max(self.mem)}\n        \"\"\"\n        )\n\n\nclass Executor:\n    \"\"\"Process execution and resources measurement.\"\"\"\n\n    def __init__(self, period: float = 0.1, timeout: float = 30):\n        \"\"\"\n        Set executor with parameters.\n\n        :param period: period to take resource measurement.\n        :param timeout: time limit to perform test, test process will be killed after timeout.\n        \"\"\"\n        self.period = period\n        self.timeout = timeout\n\n    def run(self, func: Callable, args: tuple) -> ExecReport:\n        \"\"\"\n        Run function to be tested for performance.\n\n        :param func: function or callable to be tested for performance.\n        :param args: tuple of argument to pass to function tested.\n\n        :return: execution report for single test run\n        \"\"\"\n        process = self._prepare(func, args)\n        time_usage, stats, killed = self._measure(process)\n        return self._report(args, time_usage, stats, killed)\n\n    @staticmethod\n    def _prepare(func: Callable, args: tuple) -> Process:\n        \"\"\"\n        Start process and wait process ready to be measured.\n\n        :param func: function or callable to be tested for performance.\n        :param args: tuple of argument to pass to function tested.\n\n        :return: process with tested code\n        \"\"\"\n        control: BenchmarkControl = BenchmarkControl()\n        process = Process(target=func, args=(control, *args))\n        process.start()\n        msg = control.wait_msg()\n        if msg != control.START_MSG:\n            raise ValueError(\"Msg does not match control start message.\")\n        return process\n\n    def _measure(\n        self, process: multiprocessing.Process\n    ) -> Tuple[float, List[ResourceStats], bool]:\n        \"\"\"\n        Measure resources consumed by the process.\n\n        :param process: process to measure resource consumption\n\n        :return: time used, list of resource stats, was killed\n        \"\"\"\n        started_time = time.time()\n        is_killed = False\n        proc_info = psutil.Process(process.pid)\n        stats = []\n\n        with timeit_context() as timeit:\n            while process.is_alive():\n                if time.time() - started_time > self.timeout:\n                    is_killed = True\n                    break\n                stats.append(self._get_stats_record(proc_info))\n\n                time.sleep(self.period)\n\n        if is_killed:\n            process.terminate()\n\n        process.join()\n        time_usage = timeit.time_passed\n\n        return time_usage, stats, is_killed\n\n    @staticmethod\n    def _get_stats_record(proc_info: psutil.Process) -> ResourceStats:\n        \"\"\"\n        Read resources usage and create record.\n\n        :param proc_info: process information to get cpu usage and memory usage from.\n\n        :return: one time resource stats record\n        \"\"\"\n        return ResourceStats(\n            time.time(),\n            proc_info.cpu_percent(),\n            memory_profiler.memory_usage(proc_info.pid, max_usage=True),\n        )\n\n    def _report(\n        self,\n        args: tuple,\n        time_passed: float,\n        stats: List[ResourceStats],\n        is_killed: bool,\n    ) -> ExecReport:\n        \"\"\"\n        Create execution report.\n\n        :param args: tuple of argument to pass to function tested.\n        :param time_passed: time test function was executed.\n        :param stats: list of ResourceStats: cpu, mem.\n        :param is_killed: was process terminated by timeout.\n\n        :return: test case one execution report\n        \"\"\"\n        return ExecReport(args, time_passed, stats, is_killed, self.period)\n"
  },
  {
    "path": "benchmark/framework/fake_connection.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Fake connection to generate test messages.\"\"\"\nimport asyncio\nfrom typing import Any, Optional\n\nfrom aea.connections.base import Connection, ConnectionStates\nfrom aea.mail.base import Envelope\n\n\nclass FakeConnection(Connection):\n    \"\"\"Simple fake connection to populate inbox.\"\"\"\n\n    def __init__(self, envelope: Envelope, num: int, *args: Any, **kwargs: Any):\n        \"\"\"\n        Set fake connection with number of envelops to be generated.\n\n        :param envelope: any envelope\n        :param num: amount of envelopes to generate\n        :param args: positional arguments\n        :param kwargs: keyword arguments\n        \"\"\"\n        Connection.__init__(self, *args, **kwargs)\n        self.num = num\n        self.envelope = envelope\n        self.state = ConnectionStates.connected\n\n    async def connect(self) -> None:\n        \"\"\"Do nothing. always connected.\"\"\"\n\n    async def disconnect(self) -> None:\n        \"\"\"Disconnect. just set a flag.\"\"\"\n        self.state = ConnectionStates.disconnected\n\n    async def send(self, envelope: Envelope) -> None:\n        \"\"\"\n        Do not send custom envelops. Only generates.\n\n        :param envelope: envelope to send.\n        :return: None\n        \"\"\"\n        return None\n\n    async def receive(self, *args: Any, **kwargs: Any) -> Optional[Envelope]:\n        \"\"\"\n        Return envelope set `num` times.\n\n        :param args: positional arguments\n        :param kwargs: keyword arguments\n        :return: incoming envelope\n        \"\"\"\n        if self.num <= 0:\n            await asyncio.sleep(0.1)  # sleep to avoid multiplexer loop without idle.\n            return None\n\n        self.num -= 1\n        return self.envelope\n"
  },
  {
    "path": "benchmark/framework/func_details.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Helper module for details about function being tested.\"\"\"\nimport inspect\nfrom inspect import Parameter\nfrom typing import Any, Callable, List\n\n\nclass BaseFuncDetails:\n    \"\"\"Class to introspect some callable details: name, docstring, arguments.\"\"\"\n\n    def __init__(self, func: Callable):\n        \"\"\"\n        Create an instance.\n\n        :param func: Function or another callable to get details.\n        \"\"\"\n        self.func = func\n\n    @property\n    def doc(self) -> str:\n        \"\"\"\n        Return docstring for function.\n\n        :return: str. docstring for function\n        \"\"\"\n        return self.func.__doc__ or \"\"\n\n    @property\n    def name(self) -> str:\n        \"\"\"\n        Return function definition name.\n\n        :return: str\n        \"\"\"\n        return self.func.__name__ or \"\"\n\n    @property\n    def _arguments(self) -> List[Parameter]:\n        \"\"\"\n        Get list of arguments defined in function.\n\n        :return: list of function parameters\n        \"\"\"\n        sig = inspect.signature(self.func)\n        return list(sig.parameters.values())\n\n    @property\n    def argument_names(self) -> List[str]:\n        \"\"\"\n        Get list of argument names in function.\n\n        :return: list of function argument names\n        \"\"\"\n        return [i.name for i in self._arguments]\n\n    @property\n    def default_argument_values(self) -> List[Any]:\n        \"\"\"\n        Get list of argument default values.\n\n        :return: list of default values for function arguments\n        \"\"\"\n        default_args = []\n        for arg in self._arguments:\n            default_args.append(arg.default)\n        return default_args\n\n    @property\n    def default_argument_values_as_string(self) -> str:\n        \"\"\"\n        Get list of argument default values as a string.\n\n        :return: str\n        \"\"\"\n        return \",\".join(map(repr, self.default_argument_values))\n\n\nclass BenchmarkFuncDetails(BaseFuncDetails):\n    \"\"\"\n    Special benchmarked function details.\n\n    With check of function definition.\n\n    :param CONTROL_ARG_NAME: Name of the special argument name, placed first.\n    \"\"\"\n\n    CONTROL_ARG_NAME: str = \"benchmark\"\n\n    def check(self) -> None:\n        \"\"\"\n        Check for docstring and arguments have default values set.\n\n        Raises exception if function definition does not contain docstring or default values.\n        \"\"\"\n        if not self.doc:\n            raise ValueError(\"Function docstring is missing\")\n\n        if super()._arguments[0].name != self.CONTROL_ARG_NAME:\n            raise ValueError(\n                f\"first function argument must be named `{self.CONTROL_ARG_NAME}`!\"\n            )\n\n        for arg in self._arguments:\n            if arg.default == inspect._empty:  # type: ignore # pylint: disable=protected-access\n                raise ValueError(\n                    \"function should have default values for every param except first one\"\n                )\n\n    @property\n    def _arguments(self) -> List[Parameter]:\n        \"\"\"\n        Skip first argument, cause it special.\n\n        :return: list of function arguments except the first one named `benchmark`\n        \"\"\"\n        return super()._arguments[1:]\n"
  },
  {
    "path": "benchmark/framework/report_printer.py",
    "content": "# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Performance report printer for performance tool.\"\"\"\nimport inspect\nfrom collections import namedtuple\nfrom datetime import datetime\nfrom statistics import mean, stdev\nfrom typing import Any, Callable, List, Optional, Tuple, cast\n\nfrom .executor import ExecReport\nfrom .func_details import BaseFuncDetails\n\n\nclass ContextPrinter:\n    \"\"\"Printer for test execution context: function, arguments, execution parameters.\"\"\"\n\n    def __init__(self, func_details: BaseFuncDetails, executor_params: dict) -> None:\n        \"\"\"\n        Make performance report printer instance.\n\n        :param func_details: details about function being tested\n        :param executor_params: executor parameters: timeout, interval\n        \"\"\"\n        self.func_details = func_details\n        self.executor_params = executor_params\n\n    def print_context_information(self) -> None:\n        \"\"\"Print details about tested function and execution parameters.\"\"\"\n        self._print_executor_details()\n        self._print_func_details()\n        print()\n\n    def _print_executor_details(self) -> None:\n        \"\"\"Print details about timeout and period timer of executor.\"\"\"\n        topic = \"Test execution\"\n        print(f\"{topic} timeout: {self.executor_params['timeout']}\")\n        print(f\"{topic} measure period: {self.executor_params['period']}\")\n\n    def _print_func_details(self) -> None:\n        \"\"\"Print details about function to be tested.\"\"\"\n        topic = \"Tested function\"\n        print(f\"{topic} name: {self.func_details.name}\")\n        print(f\"{topic} description: {self.func_details.doc}\")\n        print(f\"{topic} argument names: {self.func_details.argument_names}\")\n        print(\n            f\"{topic} argument default values: {self.func_details.default_argument_values}\"\n        )\n\n\nResourceRecord = namedtuple(\"ResourceRecord\", \"name,unit,value,std_dev\")\n\n\nclass PerformanceReport:\n    \"\"\"Class represents performance report over multiple exec reports.\"\"\"\n\n    def __init__(self, exec_reports: List[ExecReport]):\n        \"\"\"\n        Init performance report with exec reports.\n\n        :param exec_reports: tested function execution reports with measurements\n        \"\"\"\n        self.exec_reports = exec_reports\n\n    @property\n    def arguments(self) -> Tuple[Any, ...]:\n        \"\"\"\n        Return list of arguments for tested function.\n\n        :return: tuple of arguments\n        \"\"\"\n        return self.exec_reports[-1].args\n\n    @property\n    def report_time(self) -> datetime:\n        \"\"\"\n        Return time report was created.\n\n        :return: datetime\n        \"\"\"\n        return self.exec_reports[-1].report_created\n\n    @property\n    def number_of_runs(self) -> int:\n        \"\"\"\n        Return number of executions for this case.\n\n        :return: int\n        \"\"\"\n        return len(self.exec_reports)\n\n    @property\n    def number_of_terminates(self) -> int:\n        \"\"\"\n        Return amount how many times execution was terminated by timeout.\n\n        :return: int\n        \"\"\"\n        return sum((i.is_killed for i in self.exec_reports), 0)\n\n    @property\n    def resources(self) -> List[ResourceRecord]:\n        \"\"\"\n        Return resources values used during execution.\n\n        :return: List of ResourceRecord\n        \"\"\"\n        resources: List[ResourceRecord] = []\n\n        resources.append(\n            self._make_resource(\"Time passed\", \"seconds\", \"time_passed\", None)\n        )\n\n        for name, unit in [(\"cpu\", \"%\"), (\"mem\", \"kb\")]:\n            for func in [min, max, mean]:\n                resources.append(\n                    self._make_resource(\n                        f\"{name} {func.__name__}\", unit, name, cast(Callable, func)\n                    )\n                )\n\n        return resources\n\n    def _make_resource(\n        self,\n        name: str,\n        unit: str,\n        attr_name: str,\n        aggr_function: Optional[Callable],  # noqa\n    ) -> ResourceRecord:\n        \"\"\"\n        Make ResourceRecord.\n\n        :param name: str. name of the resource (time, cpu, mem,...)\n        :param unit: str. measure unit (seconds, kb, %)\n        :param attr_name: name of the attribute of execreport to count resource.\n        :param aggr_function:  function to process value of execreport.\n\n        :return: ResourceRecord\n        \"\"\"\n        return ResourceRecord(\n            name, unit, *self._count_resource(attr_name, aggr_function)\n        )\n\n    def _count_resource(\n        self, attr_name: str, aggr_function: Optional[Callable] = None\n    ) -> Tuple[float, float]:\n        \"\"\"\n        Calculate resources from exec reports.\n\n        :param attr_name: name of the attribute of execreport to count resource.\n        :param aggr_function:  function to process value of execreport.\n\n        :return: (mean_value, standart_deviation)\n        \"\"\"\n        if not aggr_function:\n            aggr_function = (\n                lambda x: x  # pylint: disable=unnecessary-lambda-assignment\n            )  # noqa: E731\n        values = [aggr_function(getattr(i, attr_name)) for i in self.exec_reports]\n        mean_value = mean(values)\n        std_dev = stdev(values) if len(values) > 1 else 0\n\n        return (mean_value, std_dev)\n\n\nclass ReportPrinter(ContextPrinter):\n    \"\"\"Class to handle output of performance test.\"\"\"\n\n    @staticmethod\n    def _print_header(report: PerformanceReport) -> None:\n        \"\"\"\n        Print header for performance report.\n\n        Prints arguments, number of runs and number of terminates.\n\n        :param report: performance report to print header for\n        \"\"\"\n        text = inspect.cleandoc(\n            f\"\"\"\n            == Report created {report.report_time} ==\n            Arguments are `{report.arguments}`\n            Number of runs: {report.number_of_runs}\n            Number of time terminated: {report.number_of_terminates}\n            \"\"\"\n        )\n        print(text)\n\n    @staticmethod\n    def _print_resources(report: PerformanceReport) -> None:\n        \"\"\"\n        Print resources details for performance report.\n\n        :param report: performance report to print header for\n        \"\"\"\n        for resource in report.resources:\n            print(\n                f\"{resource.name} ({resource.unit}): {resource.value} ± {resource.std_dev}\"\n            )\n\n    def print_report(self, report: PerformanceReport) -> None:\n        \"\"\"\n        Print full performance report for case.\n\n        :param report: performance report to print header for\n        \"\"\"\n        self._print_header(report)\n        self._print_resources(report)\n"
  },
  {
    "path": "benchmark/run_from_branch.sh",
    "content": "#!/bin/bash\nREPO=https://github.com/fetchai/agents-aea.git\nBRANCH=main\nTMP_DIR=$(mktemp -d -t bench-XXXXXXXXXX)\ngit clone --branch $BRANCH $REPO $TMP_DIR\n\nCURDIR=`pwd`\ncd $TMP_DIR\n\necho \"Installing the dependencies.\"\npip install pipenv\n# this is to install benchmark dependencies\npipenv --rm\npipenv install --dev --skip-lock\n# this is to install the AEA in the Pipenv virtual env\npipenv run pip install --upgrade .[all] -y\npipenv run pip uninstall typing -y\npipenv run pip install --no-deps aea-ledger-fetchai -y\npipenv run pip install --no-deps aea-ledger-cosmos -y\npipenv run pip install --no-deps aea-ledger-ethereum -y\n\nchmod +x benchmark/checks/run_benchmark.sh\necho \"Start the experiments.\"\n# we need to add the current directory to PYTHONPATH so we can import from local dirs\nPYTHONPATH=${PYTHONPATH}:$TMP_DIR pipenv run ./benchmark/checks/run_benchmark.sh\n\nrm -fr $TMPDIR\ncd $CURDIR\n\necho \"Done!\"\n"
  },
  {
    "path": "benchmark/run_mem_check_in_cloud.sh",
    "content": "#!/bin/bash\n\nCURR_BRANCH=`git rev-parse --abbrev-ref HEAD`\nprepare_cmd=\"git clone https://github.com/fetchai/agents-aea.git -b $CURR_BRANCH && cd agents-aea/ && pip install -e .[all] && pipenv install -d --deploy --skip-lock --system\"\nrun_check_cmd=\"echo Start Test && cd /agents-aea/ && PYTHONPATH=`pwd` bash ./benchmark/checks/run_benchmark_messages_mem.sh\"\ncmd=\"($prepare_cmd) &>/dev/null && $run_check_cmd\"\nkubectl delete po benchmark-checks &>/dev/null\nkubectl run benchmark-checks --image=gcr.io/fetch-ai-sandbox/aea-benchmark:0.0.0 --overrides='{\"spec\": {\"dnsPolicy\": \"Default\", \"hostNetwork\": true}}' --restart=Never --attach --rm -- bash -c \"$cmd\"\n"
  },
  {
    "path": "codecov.yml",
    "content": "coverage:\n  range: 70..100\n  round: down\n  precision: 2\n"
  },
  {
    "path": "deploy-image/.aea/cli_config.yaml",
    "content": "auth_token: <your-auth-token>\nauthor: <your-username>\nregistry_path: \"packages\"\n"
  },
  {
    "path": "deploy-image/Dockerfile",
    "content": "FROM python:3.8-alpine\n\nUSER root\n\nRUN apk add --no-cache make git bash\n\n# cryptography: https://cryptography.io/en/latest/installation/#alpine\nRUN apk add --no-cache gcc musl-dev python3-dev libffi-dev openssl-dev\n\n# https://stackoverflow.com/a/57485724\nRUN apk add --update --no-cache py3-numpy py3-scipy py3-pillow\nENV PYTHONPATH \"$PYTHONPATH:/usr/lib/python3.7/site-packages\"\n\n# golang\nRUN apk add --no-cache go\n\n# aea installation\nRUN pip install --upgrade pip\nRUN pip install --upgrade --force-reinstall aea[all]==1.1.1\n\n# directories and aea cli config\nCOPY /.aea /home/.aea\nWORKDIR /home/agents\nCOPY ./packages /home/agents/packages\n\n# aea build script\nCOPY /build.sh /build.sh\nRUN [\"chmod\", \"+x\", \"/build.sh\"]\nRUN [ \"/build.sh\" ]\n\n# optionally, specify any ports to expose here\n# EXPOSE 9000\n\n# aea entrypoint script\nCOPY /entrypoint.sh /entrypoint.sh\nRUN [\"chmod\", \"+x\", \"/entrypoint.sh\"]\nCMD [ \"/entrypoint.sh\" ]\n"
  },
  {
    "path": "deploy-image/README.md",
    "content": "# Docker Deployment image\n\nThis guide explains how to prepare a Docker image containing your AEA for deployment.\n\n## Creating your own image\n\nThe example uses the `fetchai/my_first_aea` project. You will likely want to modify it to one of your own agents or an agent from the AEA registry.\n\n### Fetch the example directory\n\nInstall subversion, then download the example directory to your local working directory\n\n``` bash\nsvn export https://github.com/fetchai/agents-aea/trunk/deploy-image\n```\n\n### Modify scripts\n\nFirst, review the `build.sh` script to make sure you are fetching the correct agent and do all the necessary setup. Here you can modify the agent you want to use. Note, when fetching from local, make sure your local packages are in the (currently empty) `packages` folder.\n\nSecond, review the `entrypoint.sh` script to make sure you supply the agent with the right amount of private keys. In the example one key-pair each for the agent and connection is used, you might need more than that depending on your agent (see `required_ledgers` of your agent).\n\nImportantly, do not add any private keys during the build step!\n\nThird, create a local `.env` file with the relevant environment variables:\n\n``` bash\nAGENT_PRIV_KEY=hex_key_here\nCONNECTION_PRIV_KEY=hex_key_here\n```\n\nFinally, if required, modify the `Dockerfile` to expose any ports needed by the AEA. (The default example does not require this.)\n\n### Build the image\n\n``` bash\ndocker build -t my_first_aea -f Dockerfile .\n```\n\n## Run\n\n``` bash\ndocker run --env-file .env -t my_first_aea\n```\n\nTo stop, use `docker ps` to find the container id and then `docker stop CONTAINER_ID` to stop the container.\n\n## Advanced usage and comments\n\n- The above approach implies that key files remain in the container. To avoid this, a static volume can be mounted with the key files in it (<https://docs.docker.com/get-started/06_bind_mounts/>).\n"
  },
  {
    "path": "deploy-image/build.sh",
    "content": "#!/bin/bash\nset -e\n\n# setup the agent\naea fetch fetchai/my_first_aea:latest\ncd my_first_aea/\naea install\naea build\n"
  },
  {
    "path": "deploy-image/entrypoint.sh",
    "content": "#!/bin/bash\nset -e\n\naea --version\n\ncd my_first_aea\n\n# create private key files\necho ${AGENT_PRIV_KEY} > fetchai_private_key.txt\necho ${CONNECTION_PRIV_KEY} > connection_fetchai_private_key.txt\n\n# add keys\naea add-key fetchai fetchai_private_key.txt\naea add-key fetchai connection_fetchai_private_key.txt --connection\n\n# issue certs\naea issue-certificates\n\n# run\naea run\n"
  },
  {
    "path": "deploy-image/packages/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Package registry for the AEA framework.\"\"\"\n"
  },
  {
    "path": "develop-image/Dockerfile",
    "content": "FROM ubuntu:20.04\n\nRUN apt-get update &&                                                        \\\n    apt-get install -y dialog &&                                             \\\n    apt-get install -y apt-utils &&                                          \\\n    apt-get upgrade -y &&                                                    \\\n    apt-get install -y sudo\n\n# This adds the 'default' user to sudoers with full privileges:\nRUN HOME=/home/default &&                                                    \\\n    mkdir -p ${HOME} &&                                                      \\\n    GROUP_ID=1000 &&                                                         \\\n    USER_ID=1000 &&                                                          \\\n    groupadd -r default -f -g \"$GROUP_ID\" &&                                 \\\n    useradd -u \"$USER_ID\" -r -g default -d \"$HOME\" -s /sbin/nologin          \\\n    -c \"Default Application User\" default &&                                 \\\n    chown -R \"$USER_ID:$GROUP_ID\" ${HOME} &&                                 \\\n    usermod -a -G sudo default &&                                            \\\n    echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers\n\nRUN DEBIAN_FRONTEND=noninteractive apt-get install -y                                                       \\\n       build-essential                                                       \\\n       software-properties-common                                            \\\n       vim                                                                   \\\n       make                                                                  \\\n       git                                                                   \\\n       less                                                                  \\\n       curl                                                                  \\\n       wget                                                                  \\\n       zlib1g-dev                                                            \\\n       libssl-dev                                                            \\\n       libffi-dev                                                            \\\n       python3-venv                                                          \\\n       python3-pip                                                           \\\n       python3-dev\n\n\n# matplotlib build dependencies\nRUN apt-get install -y                                                       \\\n       libxft-dev\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t \\\n       libfreetype6\t\t\t\t\t\t\t\t\t\t\t                 \\\n       libfreetype6-dev\n\n\n# needed by Pipenv\nENV DEBIAN_FRONTEND noninteractive\nENV LC_ALL C.UTF-8\nENV LANG C.UTF-8\n\nRUN apt-get install -y tox\nRUN python3 -m pip install -U pipenv==2021.5.29\n\nENV PATH=\"/usr/local/bin:${PATH}\"\nUSER default\n\nRUN sudo mkdir /build\nWORKDIR /build\nCOPY . /build\nRUN sudo  chown -R default /build\n\nRUN sudo make clean\n\nRUN pipenv --python python3.8\nRUN pipenv run pip3 install --upgrade pip\nRUN pipenv install --dev --skip-lock\nRUN pipenv run pip3 install .[all]\n\nCMD [\"/bin/bash\"]\n"
  },
  {
    "path": "develop-image/README.md",
    "content": "# Docker Development image\n\nAll the commands must be executed from the parent directory, if not stated otherwise.\n\n## Build\n\n``` bash\n./develop-image/scripts/docker-build-img.sh -t fetchai/aea-deploy:latest --\n```\n\nTo pass immediate parameters to the `docker build` command:\n\n``` bash\n./develop-image/scripts/docker-build-img.sh arg1 arg2 --    \n```\n\nE.g.:\n\n``` bash\n./develop-image/scripts/docker-build-img.sh --squash --cpus 4 --compress --    \n```\n\n## Run\n\n``` bash\n./develop-image/scripts/docker-run.sh -- /bin/bash\n```\n\nAs before, to pass parameters to the `docker run` command:\n\n``` bash\n./develop-image/scripts/docker-run.sh -p 8080:80 -- /bin/bash\n```\n\n## Publish\n\nFirst, be sure you tagged the image with the `latest` tag:\n\n``` bash\ndocker tag fetchai/aea-develop:<latest-version-number> fetchai/aea-develop:latest\n```\n\nThen, publish the images. First, the `fetchai/aea-develop:<latest-version-number>`\n\n``` bash\n./develop-image/scripts/docker-publish-img.sh\n```\n\nAnd then, the `fetchai/aea-develop:latest` image:\n\n- In `docker-env.sh`, uncomment `DOCKER_IMAGE_TAG=fetchai/aea-develop:latest`  \n\n- Run the publish command again:\n\n  ``` bash\n  ./develop-image/scripts/docker-publish-img.sh\n  ```\n\n### Publish to k8s\n\nSwitch the context:\n\n``` shell\nkubectx sandbox\n```\n\nList pods in cluster:\n\n``` shell\nkubectl get pods\n```\n\nOptionally, create new namespace:\n\n``` shell\nkubectl create namespace aea-research\n```\n\nEnsure right namespace is used:\n\n``` shell\nkubens aea-research\n```\n\nChoose namespace in cluster:\n\n``` shell\nkubens aea-research\n```\n\nTo enter selected namespace:\n\n``` shell\nkubens\n```\n\nFrom the `develop-image` folder run:\n\n``` shell\nskaffold run -p sandbox\n```\n\nSSH into a new image:\n\n``` shell\nkubectl run --generator=run-pod/v1 -it debian --image=debian -- bash\n```\n\n## Dedicated node pool for benchmarking agents\n\n### Setup and tear down\n\nTo create the node pool\n\n``` shell\ngcloud container node-pools create agent-test-pool --cluster sandbox --project fetch-ai-sandbox --node-taints dedicated=agent:NoSchedule --machine-type=n1-standard-4 --num-nodes=1 --enable-autoscaling --node-labels=type=agent-test --max-nodes=1  --min-nodes=0\n```\n\nTo remove the node pool\n\n``` shell\ngcloud container node-pools delete agent-test-pool --cluster sandbox --project fetch-ai-sandbox\n```\n\n### Usage\n\nList pods\n\n``` shell\nkubectl get pod -o wide\n```\n\n``` shell\nkubectl exec -it NAME -- bash\n```\n"
  },
  {
    "path": "develop-image/docker-env.sh",
    "content": "#!/bin/bash\n\n# Swap the following lines if you want to work with 'latest'\nDOCKER_IMAGE_TAG=fetchai/aea-develop:1.1.1\n# DOCKER_IMAGE_TAG=aea-develop:latest\n\nDOCKER_BUILD_CONTEXT_DIR=..\nDOCKERFILE=./Dockerfile\n"
  },
  {
    "path": "develop-image/k8s/deployment.yaml",
    "content": "---\napiVersion: extensions/v1beta1\nkind: Deployment\nmetadata:\n  name: aea-develop-image\n  namespace: aea-research\n  labels:\n    app: aea-develop-image\nspec:\n  replicas: 1\n  template:\n    metadata:\n      labels:\n        app: aea-develop-image\n    spec:\n      tolerations:\n      - key: dedicated\n        operator: Equal\n        value: agent\n        effect: NoSchedule\n      nodeSelector:\n        type: agent-test\n      containers:\n      - image: gcr.io/fetch-ai-sandbox/aea-develop-image\n        name: aea-develop-image\n        resources:\n          requests:\n            memory: \"64Mi\"\n            cpu: \"150m\"\n          limits:\n            memory: \"128Mi\"\n            cpu: \"500m\"\n      restartPolicy: Always\n...\n---\napiVersion: extensions/v1beta1\nkind: Deployment\nmetadata:\n  name: aea-deploy-image\n  namespace: aea-research\n  labels:\n    app: aea-deploy-image\nspec:\n  replicas: 1\n  template:\n    metadata:\n      labels:\n        app: aea-deploy-image\n    spec:\n      tolerations:\n      - key: dedicated\n        operator: Equal\n        value: agent\n        effect: NoSchedule\n      nodeSelector:\n        type: agent-test\n      containers:\n      - image: gcr.io/fetch-ai-sandbox/aea-deploy-image\n        name: aea-deploy-image\n        resources:\n          requests:\n            memory: \"64Mi\"\n            cpu: \"150m\"\n          limits:\n            memory: \"128Mi\"\n            cpu: \"500m\"\n      restartPolicy: Always\n..."
  },
  {
    "path": "develop-image/scripts/docker-build-img.sh",
    "content": "#!/bin/bash -e\n# Usage:\n#   ./docker-build-img.sh <IMMEDIATE_PARAMS> -- <TAIL_PARAMS>\n# Where:\n#  * resulting docker build commandline will be:\n#    docker build $IMMEDIATE_PARAMS -t $DOCKER_IMAGE_TAG $TAIL_PARAMS $DOCKER_BUILD_CONTEXT_DIR\n#  * DOCKER_IMAGE_TAG and DOCKER_BUILD_CONTEXT_DIR variables are defined in the `docker-env.sh` and/or `docker-env-common.sh`\n#\n# Examples:\n#  * the following example provides the `--cpus 4 --compress` parameters to `docker build` command as IMMEDIATE_PARAMS, **ommiting** the TAIL_PARAMS:\n#\n#    ./docker-build-img.sh --cpus 4 ---compress --\n#    # the the resulting docker process commandline will be:\n#    #   docker build --cpus 4 --compress -t $DOCKER_IMAGE_TAG $TAIL_PARAMS $DOCKER_BUILD_CONTEXT_DIR\n#\n#  * the following example provides the `--squash` parameters to `docker build` command as IMMEDIATE_PARAMS, and `../../` parameter as TAIL_PARAMS (what corresponds to the context directory, what also means that DOCKER_BUILD_CONTEXT_DIR variable needs to be unset or set to empty string in the `docker-env.sh`):\n#\n#    ./docker-build-img.sh --squash -- ../../\n#    # the the resulting docker process commandline will be:\n#    #   docker build --squash -t $DOCKER_IMAGE_TAG ../../ $DOCKER_BUILD_CONTEXT_DIR\n#    # the `DOCKER_BUILD_CONTEXT_DIR` shall be set to empty string in `docker-env.sh` file.\n# NOTE: For more details, please see description for the `split_params()` shell function in the `docker-common.sh` script.\n\nSCRIPTS_DIR=${0%/*}\n. \"$SCRIPTS_DIR\"/docker-env-common.sh\n\ndocker_build_callback() {\n    local IMMEDIATE_PARAMS=\"$1\"\n    local TAIL_PARAMS=\"$2\"\n\n    if [ -n \"${DOCKERFILE}\" ]; then\n        TAIL_PARAMS=\"-f $DOCKERFILE $TAIL_PARAMS\"\n    fi\n\n    local COMMAND=\"docker build $IMMEDIATE_PARAMS -t $DOCKER_IMAGE_TAG $TAIL_PARAMS $DOCKER_BUILD_CONTEXT_DIR\"\n\n    echo $COMMAND\n    $COMMAND\n}\n\nsplit_params docker_build_callback \"$@\"\n"
  },
  {
    "path": "develop-image/scripts/docker-publish-img.sh",
    "content": "#!/bin/bash -e\n# NOTE: First docker needs to be authorized to push image to container registry.\n#       Normally this is done using 'docker login <registrey_url>', where the\n#       'registry_url' value is set in the $DOCKER_CONTAINER_REGISTRY environment\n#       variable which is defined in the 'docker-env-common.sh' script file.\n#       If you are using the Google cloud docker registry, please run the\n#       'gcloud auth configure-docker' instead.\n\nSCRIPTS_DIR=${0%/*}\n. \"$SCRIPTS_DIR\"/docker-env-common.sh\n\ndocker tag \"$DOCKER_IMAGE_TAG\" \"$REGISTRY_DOCKER_IMAGE_TAG\"\ndocker push \"$REGISTRY_DOCKER_IMAGE_TAG\"\n"
  },
  {
    "path": "develop-image/skaffold.yaml",
    "content": "apiVersion: skaffold/v1beta13\nkind: Config\nbuild:\n  artifacts:\n  local: {}\nprofiles:\n- name: sandbox\n  build:\n    artifacts:\n    - image: gcr.io/fetch-ai-sandbox/aea-develop-image\n      context: ..\n      docker:\n        dockerfile: develop-image/Dockerfile\n    - image: gcr.io/fetch-ai-sandbox/aea-deploy-image\n      context: ..\n      docker:\n        dockerfile: deploy-image/Dockerfile\n  deploy:\n    kubectl:\n      manifests:\n        - \"k8s/deployment.yaml\"\n  activation:\n  - kubeContext: sandbox\n"
  },
  {
    "path": "docs/12-factor.md",
    "content": "# Relationship with the Twelve-Factor App Methodology\n\nThe <a href=\"https://12factor.net/\" target=\"_blank\">Twelve-Factor App</a> is a set of best practices to build modern web applications, or *software-as-a-service*.\n\nIn this section, we will see how the AEA framework facilitates the achievement of those in the development, release and deployment phases of an AEA project.\n\nNote that an AEA instance, as a software agent, can be seen as a more general case of a web app, as it not only shows reactive behaviour, but it is also *proactive*, depending on the goals assigned to it.\n\n## Codebase\n\n!!! info \"Factor 1\"\n    One codebase tracked in revision control, many deploys\n\nSupport: Excellent\n\nThe framework does not impose any particular requirement or convention on the type of version control software to be used to store an AEA project.\n\n## Dependencies\n\n!!! info \"Factor 2\"\n    Explicitly declare and isolate dependencies\n\nSupport: Good\n\nThe framework allows an AEA project to explicitly declare the AEA package dependencies, and the PyPI dependencies needed to proper working.\n\nHowever, it does not provide built-in support for checking platform-specific dependencies, e.g. specific Python version, or needed system-wide available libraries. Nevertheless, this can be indirectly achieved by means of build scripts called on `aea build`, which can do the checks manually according to the specific requirements of the project.\n\n## Configuration\n\n!!! info \"Factor 3\"\n    Store configuration in the environment\n\nSupport: Good\n\nAn AEA project can specify an environment configuration file `.env`, stored in the project root, that the framework will use to update environment variables before the execution of the AEA instance.\n\nThe CLI tool command `aea run` accepts the option `--env PATH` to change the default configuration file. However, the framework does not automatically switch between, nor allows to add, different types of configuration files, one for each deployment step (e.g. development, staging, production), without using the `--env` option.\n\n## Backing Services\n\n!!! info \"Factor 4\"\n    Treat backing services as attached resources\n\nSupport: Good\n\nA persistent storage of an AEA can be seen as an attached resource in the 12-factor terminology. The default storage is SQLite, but the interface `AbstractStorageBacked` allows to implement specific wrappers to other backing services, without changing the AEA project code. The support for integrating different storage back-end implementations in an AEA project by using a plug-in mechanism is currently missing.\n\nMoreover, new adapters to backing services can be implemented as custom connections, which can connect to attached resources. This does not usually require a change in the skill code, especially in the case when a custom protocol can abstract the details of the interaction with the specific resource.\n\n## Build, Release, Run\n\n!!! info \"Factor 5\"\n    Strictly separate build and run stages\n\nSupport: Excellent\n\nThe phases of build, release and run of an AEA project are neatly separated, both for programmatic usage and through the usage of the CLI tool, as each of them corresponds to different subcommands.\n\n## Processes\n\n!!! info \"Factor 6\"\n    Execute the app as one or more stateless processes\n\nSupport: Excellent\n\nWhether the process is stateless depends on the specific AEA. No strict enforcement is applied by the framework. Moreover, dialogue histories can be stored with persistent storage, if enabled by the developer.\n\n## Port Binding\n\n!!! info \"Factor 7\"\n    Export services via port binding\n\nSupport: Excellent\n\nAn AEA project may not need to expose services via HTTP. This property depends on the specific choices of the project developer, and the framework does not impose any restriction.\n\nOne of the provided package, the \"HTTP server\" connection, relies on `aiohttp`, which makes the connection completely self-contained—therefore, it satisfies the requirement.\n\nAnother relevant example is the ACN node, which exposes its service to the Libp2p AEA connection\n\n## Concurrency\n\n!!! info \"Factor 8\"\n    Scale out via the process model\n\nSupport: Not Supported\n\nThe framework does not easily allow to scale up an AEA instance with multiple processes, as it is bound to a process. However, note that its attached services can live in a different process, which could give better scalability.\n\n## Disposability\n\n!!! info \"Factor 9\"\n    Maximize robustness with fast startup and graceful shutdown\n\nSupport: Good\n\nDisposability of an AEA instance depends, in general, on the AEA itself; whether the connections can be quickly connected and disconnected, whether skills can be easily torn down or not, whether other resources can be detached successfully like the persistent storage, just to name a few examples.\n\nThere has been put some effort into reducing startup time, and to ensure that a graceful shut-down can happen when the process receives a SIGTERM under normal circumstances, but robustness cannot be ensured for individual components, as it depends on their implementation.\n\nAdditionally, the framework does provide some features to control some aspects of AEA disposability, e.g. the possibility to change execution timeout for behaviours or handlers, implementation of an effective exception propagation from a component code to the main agent loop.\n\n## Dev/Prod Parity\n\n!!! info \"Factor 10\"\n    Keep development, staging, and production as similar as possible\n\nSupport: Good\n\nThis aspect mostly depends on the specific AEA project, and the framework does not impose particular restrictions on best deployment practices (e.g. continuous integration, same backing services between development and production stages).\n\n## Logs\n\n!!! info \"Factor 11\"\n    Treat logs as event streams\n\nSupport: Excellent\n\nThanks to the seamless integration with the Python standard library `logging`, the developer or the deployer has great control on the routing and filtering of log records. The behaviour can be changed by providing a proper configuration in the AEA project configuration file, according to the standard library specification. The framework facilitates this by creating ad-hoc logger names that can be used for finer-grained routing or filtering; for example, each AEA instance uses its own logging namespace to send logging events. Integration with other log handlers is delegated to extensions of the standard library, hence not necessarily coupled with the AEA framework.\n\n## Admin Processes\n\n!!! info \"Factor 12\"\n    Run admin/management tasks as one-off processes\n\nSupport: Good\n\nThe CLI tool provides commands to manage private keys and ledger related operations, and it is possible to extend it with a plugin to manage databases of AEA's persistent storage for maintenance operations.\n\nMoreover, the Python programming language makes it easy to run one-off scripts or running a console (also known as REPL) to do management tasks. It follows that it is also easy to ensure dependency isolation and same configurations of the running AEA instance.\n"
  },
  {
    "path": "docs/Pipfile",
    "content": "[[source]]\nname = \"pypi\"\nurl = \"https://pypi.org/simple\"\nverify_ssl = true\n\n[dev-packages]\n\n[packages]\nmkdocs = \"*\"\nmkdocs-material = \"*\"\nmkdocs-material-extensions = \"*\"\nmkdocs-mermaid-plugin = {git = \"https://github.com/pugong/mkdocs-mermaid-plugin.git\"}\n\n[requires]\npython_version = \"3.7\"\n"
  },
  {
    "path": "docs/acn-internals.md",
    "content": "# ACN Internals\n\nThe aim of this document is to describe at a high-level the main implementation of the Agent Communication Network (ACN).\n\nIn particular:\n\n- the <a href=\"https://github.com/fetchai/agents-aea/tree/main/libs/go/libp2p_node\" target=\"_blank\">`libp2p_node` Golang library</a>;\n- the <a href=\"https://github.com/fetchai/agents-aea/tree/main/packages/fetchai/connections/p2p_libp2p\" target=\"_blank\">`p2p_libp2p` AEA connection</a> written in Python, that implements the **direct connection** with an ACN peer;\n- the <a href=\"https://github.com/fetchai/agents-aea/tree/main/packages/fetchai/connections/p2p_libp2p_client\" target=\"_blank\">`p2p_libp2p_client` AEA connection</a> written in Python, which implements the **delegate connection** with an ACN peer.\n\nIt is assumed the reader already knows what is the ACN and its purposes; if not, we suggest reading <a href=\"../acn\">this page</a>.\n\nThis documentation page is structured as follows:\n\n- Firstly, the ACN protocol is described: all the messages and data structures involved, as well as some example of interaction protocol with these messages;\n- Then, it is explained how a peer can join an existing ACN network, and the message exchange involved;\n- It follows the description of the journey of an envelope in the ACN network: from the agent connection to its contact peer, between ACN peers, and then from the contact peer of the destination agent to the target agent;\n- The following section describes the functionalities of the AEA connections that allow to communicate through the ACN: `fetchai/p2p_libp2p` and `fetchia/p2p_libp2p_delegate`;\n- The documentation ends with a section of known issues and limitations of the current implementation.\n\n## Messages and Data Structures\n\nAt the foundation of the ACN there is the _ACN protocol_. The protocol messages and the reply structure are generated from this <a href=\"https://github.com/fetchai/agents-aea/blob/develop/libs/go/libp2p_node/protocols/acn/v1_0_0/acn.yaml\" target=\"_blank\">protocol specification</a>, using the <a href=\"../protocol-generator\" target=\"_blank\">protocol generator</a>. Therefore, it uses <a href=\"https://developers.google.com/protocol-buffers\" target=\"_blank\">Protocol Buffers</a> as a serialization format, and the definition of the data structures involved is defined in this <a href=\"https://github.com/fetchai/agents-aea/blob/develop/libs/go/libp2p_node/protocols/acn/v1_0_0/acn.proto\" target=\"_blank\">`.proto` file</a>.\n\nTo know more about the protocol generator, refer to the relevant section of the documentation: <a href=\"../protocol-generator\" target=\"_blank\">Protocol Generator</a>.\n\n### Agent Record\n\nAn _agent record_ is a data structure containing information about an agent and its Proof-of-Representation (PoR) to be used by a peer for other peers. This data structure is used as a payload in other ACN messages (see below).\n\nThe `AgentRecord` data structure contains the following fields:\n\n- `service_id`: a string describing the service identifier.\n- `ledger_id`: a string. It is the identifier of the ledger this agent record is associated to. Currently, the allowed values are:\n    - `fetchai`, the identifier for the Fetch.AI ledger;\n    - `ethereum`, the identifier for the Ethereum ledger;\n    - `cosmos`, the identifier for the Cosmos ledger;\n- `address`: a string. It is the public key of a public-private key pair. It is used as an identifier for routing purposes.\n- `public_key`: a string. The representative's public key. Used in case of (PoR).\n- `peer_public_key`: a string. The public key of the peer.\n- `signature`: a string. The signature for PoR.\n- `not_before`: a string. Specify the lower bound for certificate validity. If it is a string, it must follow the format: `YYYY-MM-DD`. It will be interpreted as time zone UTC-0\n- `not_after`: a string. Specify the upper bound for certificate validity. If it is a string, it must follow the format: `YYYY-MM-DD`. It will be interpreted as time zone UTC-0.\n\n### ACN Message\n\nEntities in the ACN (i.e. either agents or peers) exchange _ACN messages_. An ACN message contains a `payload` field, which is the actual content of the message.\n\nThere are different types of payloads:\n\n- `Status`\n- `Register`\n- `LookupRequest`\n- `LookupResponse`\n- `AeaEnvelope`\n\n### Status\n\nThe `Status` payload is used as a response message to inform the sender about the handling of certain requests. The payload contains:\n\n- the `status_code`, a positive integer among the ones in the <a href=\"https://github.com/fetchai/agents-aea/blob/develop/libs/go/libp2p_node/protocols/acn/v1_0_0/acn.proto\" target=\"_blank\">Protobuf file</a>.\n- a list of error messages (string).\n\nA status code `0`, identified as `SUCCESS`, means that the request has been processed successfully. Status codes greater than `0` can be:\n\n- Generic errors: errors that occur under generic circumstances.\n\n    - `ERROR_UNSUPPORTED_VERSION`, with integer value `1`: the receiver of the message does not support the protocol version of the sender;\n    - `ERROR_UNEXPECTED_PAYLOAD`, with integer value `2`: the payload could not be deserialized on the receiver side;\n    - `ERROR_GENERIC`, with integer value `3`: an internal error;\n    - `ERROR_SERIALIZATION`, with integer value `4`: a serialization error occurred on the receiving end;\n\n- Register errors: errors that occur during agent registration operations in the ACN.\n\n    - `ERROR_WRONG_AGENT_ADDRESS`, with integer value `10`: the PoR by a peer from another peer does not match the destination address of the envelope to be routed by the receiving peer.\n    - `ERROR_WRONG_PUBLIC_KEY`, with integer value `11`: the representative peer public key does not match the one in the agent record;\n    - `ERROR_INVALID_PROOF`, with integer value `12`: the signature is invalid;\n    - `ERROR_UNSUPPORTED_LEDGER`, with integer value `13`: the ledger of the PoR is not supported by the peer;\n\n- Lookup and delivery errors: errors that occur during lookup to the DHT and envelope delivery operations in the ACN.\n  \n    - `ERROR_UNKNOWN_AGENT_ADDRESS`, with integer value `20`: the requested agent address has not been found in the local DHT of the peer;\n    - `ERROR_AGENT_NOT_READY`, with integer value `21`: the agent is not ready for envelope delivery.\n\n### Register\n\nThe `Register` payload is used to request a peer to register an agent among his known ones. The payload contains the field `record`, which is an instance of `AgentRecord`.\n\n### LookupRequest\n\nThe `LookupRequest` payload is sent between peer to look-up addresses in the Distributed Hash Table (DHT). It contains the agent address (a string) that the sender needs to correctly route an envelope.\n\n### LookupResponse\n\nThe `LookupResponse` payload is the response sent by a peer that received a `LookupRequest`. It contains the `AgentRecord` associated to the requested address.\n\n### AeaEnvelope\n\nThe `AeaEnvelope` payload contains the envelope sent by an agent and to be delivered to another agent. It contains:\n\n- `envelope`: the envelope to be forwarded, in byte representation;\n- an `AgentRecord` (see above).\n\n## ACN Protocol Interactions\n\nThe ACN protocol specifies three different possible interactions:\n\n- the _registration_ interaction\n- the _look-up_ interaction\n- the _routing_ interaction\n\n### \"Registration\" Interaction\n\nThe registration interaction is used by delegate agents or relayed peers to register themselves to another peer.\n\n``` mermaid\n    sequenceDiagram\n        participant Agent/RelayedPeer\n        participant Peer\n        Agent/RelayedPeer->>Peer: Register(AgentRecord)\n        alt success\n            note over Peer: check PoR\n            Peer->>Agent/RelayedPeer: Status(SUCCESS)\n        else wrong agent address\n            Peer->>Agent/RelayedPeer: Status(ERROR_WRONG_AGENT_ADDRESS)\n        else wrong public key\n            Peer->>Agent/RelayedPeer: Status(ERROR_WRONG_PUBLIC_KEY)\n        else invalid proof of representation\n            Peer->>Agent/RelayedPeer: Status(ERROR_INVALID_PROOF)\n        else unsupported ledger\n            Peer->>Agent/RelayedPeer: Status(ERROR_UNSUPPORTED_LEDGER)\n        end\n```\n\n### \"Look-up\" Interaction\n\nThe look-up interaction is used by a peer to request information to another peer about an agent address.\n\n``` mermaid\n    sequenceDiagram\n        participant Peer1\n        participant Peer2\n        Peer1->>Peer2: LookupRequest(address)\n        alt success\n            Peer2->>Peer1: LookupResponse(AgentRecord)\n        else unknown agent address\n            Peer2->>Peer1: Status(ERROR_UNKNOWN_AGENT_ADDRESS)\n        end\n```\n\n### \"Routing\" Interaction\n\nThe routing interaction is used by agents and peers to route the envelope through the ACN.\n\n``` mermaid\n    sequenceDiagram\n        participant Peer1\n        participant Peer2\n        Peer1->>Peer2: AeaEnvelope(envelope, AgentRecord)\n        alt success\n            note over Peer2: check PoR\n            Peer2->>Peer1: Status(SUCCESS)\n        else error on decoding of Envelope payload\n            Peer2->>Peer1: Status(ERROR_SERIALIZATION)\n        else PoR errors\n            note over Peer1,Peer2: see above \n        end\n```\n\n## Joining the ACN network\n\nWhen an ACN peer wants to join the network, it has to start from a list of _bootstrap peers_, i.e. a list of ACN peers to connect with (at least one).\n\nEach node handles four different types of <a href=\"https://docs.libp2p.io/concepts/stream-multiplexing/\" target=\"_blank\">libp2p streams</a>:\n\n- the _notification stream_, identified by the URI `/aea-notif/`: this stream is used by new peers to notify their existence to\n- the _address stream_, identified by the URI `/aea-address/`: used to send look-up requests and look-up responses;\n- the _envelope stream_, identified by the URI `/aea/`: used to forward and to receive ACN envelopes;\n- the _register relay stream_, identified by the URI `/aea-register/`: this is to receive messages from clients that want to register their agents addresses; this peer, and then it can register their addresses.\n\nTo begin with, the node process initializes the transport connections with the bootstrap peers, the local copy of the Kademlia Distributed Hash Table (DHT), the persistent storage for agent records, and performs other non-functional operations like setting up the <a href=\"https://prometheus.io/\" target=\"_blank\"> Prometheus monitoring system</a>. Optionally, can also start listening for relay connections and delegate connections.\n\nThen, it sets up the notification stream and notifies the bootstrap peers (if any).\n\n``` mermaid\n    sequenceDiagram\n        participant Peer1\n        participant Peer2\n        participant Peer3\n        note over Peer1: notify<br/>bootstrap peers\n        Peer1->>Peer2: notify\n        Peer2->>Peer2: wait until notifying peer <br/>added to DHT\n        activate Peer2\n        Peer1->>Peer3: notify\n        Peer3->>Peer3: wait until notifying peer <br/>added to DHT\n        activate Peer3\n        note over Peer2,Peer3: Peer1 registered to DHT\n        deactivate Peer2\n        deactivate Peer3\n        loop for each local/relay/delegate address \n            Peer1->>Peer1: compute CID from address\n            Peer1->>Peer2: register address\n            Peer1->>Peer3: register address\n        end\n        note over Peer1: set up:<br/>- address stream<br/>- envelope stream<br/>- register relay stream\n```\n\n### Relay Connections\n\nIf the ACN node is configured to run the relay service, it sets up the register relay stream, waiting for registration requests.\n\nThe following diagram shows an example of the message exchanged during a registration request:\n\n``` mermaid\n    sequenceDiagram\n        participant Agent\n        participant Peer\n        Agent->>Peer: Register\n        alt decoding error of ACN message\n            Peer->>Agent: Status(ERROR_SERIALIZATION)\n        else wrong payload\n            Peer->>Agent: Status(ERROR_UNEXPECTED_PAYLOAD)\n        else PoR check fails\n            alt wrong agent address\n                Peer->>Agent: Status(ERROR_WRONG_AGENT_ADDRESS)\n            else unsupported ledger\n                Peer->>Agent: Status(ERROR_UNSUPPORTED_LEDGER)\n            else agent address and public key don't match\n                Peer->>Agent: Status(ERROR_WRONG_AGENT_ADDRESS)\n            else invalid proof\n                Peer->>Agent: Status(ERROR_INVALID_PROOF)\n            end\n        else PoR check succeeds\n            Peer->>Agent: Status(SUCCESS)\n            note over Peer: announce agent address<br/>to other peers\n        end\n```\n\n### Delegate Connections\n\nIf the ACN node is configured to run the delegate service, it starts listening from a TCP socket at a configurable URI.\n\nTo see a diagram of the message exchanged during a registration request read <a href=\"../acn-internals#registration-interaction\" target=\"_blank\">this section</a>.\n\n## ACN Transport\n\nIn the following sections, we describe the main three steps of the routing of an envelope through the ACN:\n\n- _ACN entrance_: when an envelope sent by an agent enters the peer-to-peer network via the peer the agent is connected to i.e. agent-to-peer communication;\n- _ACN routing_: when an envelope gets routed through the peer-to-peer network, i.e. peer-to-peer communication;\n- _ACN exit_: when an envelope gets delivered to the receiving agent through its representative peer, i.e. peer-to-agent communication.\n  \n### ACN Envelope Entrance: Agent -> Peer\n\nIn this section, we will describe the interaction protocols between agents and peers for the messages sent by the agent to the ACN network; in particular, the communication from the contact peer of an agent to the agent.\n\nThe following diagram explains the exchange of messages on entering an envelope in the ACN.\n\nIn the case of _direct connection_, `Agent` is a Python process, whereas `Peer` is in a separate (Golang) process. The logic of the Python Agent client is implemented in the <a href=\"https://github.com/fetchai/agents-aea/tree/main/packages/fetchai/connections/p2p_libp2p\" target=\"_blank\">AEA connection `fetchai/p2p_libp2p`</a> The communication between `Agent` and `Peer` is done through an OS pipe for Inter-Process Communication (IPC) between the AEA's process and the libp2p node process; then, the message gets enqueued to an output queue by an input coroutine. Finally, the envelope ends up in an output queue, which is processed by an output coroutine and routed to the next peer.\n\nIn the case of _delegate connection_, the message exchange is very similar; however, instead of using pipes, the communication is done through the network, i.e. TCP, with a peer which has the delegate service enabled. The logic of the `Agent` client connected with a delegate connection is implemented in the <a href=\"https://github.com/fetchai/agents-aea/tree/main/packages/fetchai/connections/p2p_libp2p_client\" target=\"_blank\">AEA connection `fetchai/p2p_libp2p_client`</a>\n\n``` mermaid\n    sequenceDiagram\n        participant Agent\n        participant Peer\n        loop until Status(success) received\n            Agent->>Peer: AeaEnvelope\n            Agent->>Agent: wait\n            note left of Agent: Wait until<br/>Status(success)\n            alt successful case\n                Peer->>Agent: Status(success)\n                note over Agent: break loop\n            else ack-timeout OR conn-error\n                note left of Agent: continue: Try to<br/>resend/reconnect\n            else version not supported\n                Peer->>Agent: Status(ERROR_UNSUPPORTED_VERSION)\n            else error on decoding of ACN message\n                Peer->>Agent: Status(ERROR_SERIALIZATION)\n            else error on decoding of Envelope payload\n                Peer->>Agent: Status(ERROR_SERIALIZATION)\n            else the payload cannot be handled\n                Peer->>Agent: Status(ERROR_UNEXPECTED_PAYLOAD)\n            end\n        end\n        note over Peer: route envelope<br/>to next peer\n```\n\n### ACN Envelope Routing\n\nIn this section, we describe the interaction between peers when it comes to envelope routing.\n\nAssume an envelope arrives from an agent to peer `Peer1`, i.e. `Peer1` is the first hop of the routing. Let `Agent` be the local agent directly connected to `Peer1`, `Peer2` a direct peer of peer `Peer1`.\n\nWhen the envelope is leaving `Peer1`, we may have different scenario:\n\n1. In case of direct connection, and the field `sender` of the envelope is not the local agent address: the message is considered invalid, and it is dropped.\n\n    ``` mermaid\n        sequenceDiagram\n            participant Agent\n            participant Peer1\n            participant Peer2\n            Agent->>Peer1: AeaEnvelope\n            alt envelope sender not registered locally\n                note over Peer1: stop, log error\n            end\n    ```\n\n2. the `target` of the envelope is the local agent connected to the peer: the envelope is routed to the local agent.\n\n    ``` mermaid\n        sequenceDiagram\n            participant Agent\n            participant Peer1\n            participant Peer2\n            Agent->>Peer1: AeaEnvelope\n            alt target == peer1.my_agent\n                note over Peer1: envelope destinated<br/> to local agent,<br/> not routing\n                loop agent not ready\n                    note over Peer1: sleep for 100ms\n                end\n                Peer1->>Agent: AeaEnvelope\n                Agent->>Peer1: Status(Success)\n            end\n    ```\n\n3. the `target` is a delegate client. Send the envelope via TCP.\n\n    ``` mermaid\n        sequenceDiagram\n            participant Delegate\n            participant Peer1\n            participant Peer2\n            Delegate->>Peer1: AeaEnvelope\n            alt destination is a delegate\n                note over Peer1: send envelope<br/> to delegate via TCP\n                Peer1->>Delegate: AeaEnvelope\n                Delegate->>Peer1: Status(Success)\n            end\n    ```\n\n4. Otherwise, look up the local DHT. If an entry is found, use it; otherwise, send a look-up request to connected peers.\n\n``` mermaid\n    sequenceDiagram\n        participant Agent\n        participant Peer1\n        participant Peer2\n        Agent->>Peer1: AeaEnvelope\n        alt address found in DHT\n            note over Peer1: destination is a<br/>relay client\n        else lookup address in DHT\n            note over Peer1: send lookup request<br/> to all peers\n            Peer1->>Peer2: LookupRequest\n            alt generic error\n                Peer2->>Peer1: Status(GENERIC_ERROR)\n            else look-up response\n                Peer2->>Peer1: LookupResponse\n                note over Peer1: Check PoR\n            else not found\n                Peer2->>Peer1:Status(UNKNOWN_AGENT_ADDRESS)\n            end\n        end\n        note over Peer1,Peer2: Now Peer1 knows the contact peer<br/>is PeerX\n```\n\nIn particular, when a peer receives a LookupRequest message, it does the following:\n\n``` mermaid\n    sequenceDiagram\n        participant Peer1\n        participant Peer2\n        Peer1->>Peer2: LookupRequest\n        alt error\n            Peer2->>Peer1: Status(Error)\n        else local agent/relay/delegate\n            note over Peer2: requested address is<br/>a local agent<br/>OR<br/>requested address is<br/>in my relay clients<br/>OR<br/>requested address is<br/>in my delegate clients\n            Peer2->>Peer1: LookupResponse\n            note over Peer1: Check PoR\n        else not found locally\n            note over Peer2: send lookup request<br/>to other peers...\n            alt found\n                Peer2->>Peer1: LookupResponse\n                note over Peer1: Check PoR\n            else not found\n                Peer2->>Peer1:Status(UNKNOWN_AGENT_ADDRESS)\n            end\n        end\n```\n\nLet `Peer3` the contact peer of the recipient of the envelope. The following diagram shows how the contact peer of the envelope recipient handles the incoming envelope:\n\n``` mermaid\n    sequenceDiagram\n        participant Peer1\n        participant Peer3\n        Peer1->>Peer3: AeaEnvelope\n        alt decoding error of ACN message\n            Peer3->>Peer1: Status(ERROR_SERIALIZATION)\n        else unexpected payload\n            Peer3->>Peer1: Status(ERROR_UNEXPECTED_PAYLOAD)\n        else decoding error of envelope payload\n            Peer3->>Peer1: Status(ERROR_SERIALIZATION)        \n        else PoR check fails\n            alt wrong agent address\n                Peer3->>Peer1: Status(ERROR_WRONG_AGENT_ADDRESS)\n            else unsupported ledger\n                Peer3->>Peer1: Status(ERROR_UNSUPPORTED_LEDGER)\n            else agent address and public key don't match\n                Peer3->>Peer1: Status(ERROR_WRONG_AGENT_ADDRESS)\n            else invalid proof\n                Peer3->>Peer1: Status(ERROR_INVALID_PROOF)\n            end\n        else PoR check succeeds\n            alt target is delegate, not ready\n                Peer3->>Peer1: Status(ERROR_AGENT_NOT_READY)\n            else exists delegate, ready\n                note over Peer3: forward envelope via<br/>delegate connection\n                Peer3->>Peer1: Status(SUCCESS)\n            else target is local agent, not ready\n                Peer3->>Peer1: Status(ERROR_AGENT_NOT_READY)\n            else target is local agent, ready\n                note over Peer3: forward envelope via<br/>direct connection\n                Peer3->>Peer1: Status(SUCCESS)\n            else agent does not exist\n                Peer3->>Peer1: Status(ERROR_UNKNOWN_AGENT_ADDRESS)\n            end\n        end\n```\n\n### ACN Envelope Exit: Peer -> Agent\n\nThe following diagram explains the exchange of messages on exiting an envelope in the ACN. That is, the communication from the contact peer of an agent to the agent.\n\nThe same message exchange is done both in the case of direct connection and delegate connection, similarly for what has been described for the envelope entrance <a href=\"../acn-internals#acn-envelope-entrance-agent-peer\">(see above)</a>.\n\n``` mermaid\n    sequenceDiagram\n        participant Agent\n        participant Peer\n        Peer->>Agent: AeaEnvelope\n        alt successful case\n            Agent->>Peer: Status(success)\n        else ack-timeout OR conn-error\n            note left of Peer: do nothing\n        else error on decoding of ACN message\n            Agent->>Peer: Status(GENERIC_ERROR)\n        else error on decoding of Envelope payload\n            Agent->>Peer: Status(GENERIC_ERROR)\n        else wrong payload\n            Agent->>Peer: Status(GENERIC_ERROR)\n        end\n```\n\n## Connect your AEA to the ACN\n\nTo connect the AEA to the ACN network, there are two AEA connections available:\n\n- the `fetchai/p2p_libp2p`, that implements a direct connection, and\n- the `fetchai/p2p_libp2p_delegate` connection, that implements the delegate connection.\n\nFor more information on the AEA connection package type, refer to <a href=\"../connection/\" target=\"_blank\">this guide</a>.\n\n### The `fetchai/p2p_libp2p` Connection\n\nThe source code of the `fetchai/p2p_libp2p` connection can be downloaded from <a href=\"https://aea-registry.fetch.ai/details/connection/fetchai/p2p_libp2p/latest\" target=\"_blank\">the AEA Registry</a>, or from <a href=\"https://github.com/fetchai/agents-aea/tree/main/packages/fetchai/connections/p2p_libp2p\" target=\"_blank\">the main AEA framework repository.</a>\n\nThe package provides the connection class `P2PLibp2pConnection`, which implements the `Connection` interface and therefore can be used by the Multiplexer as any other connection.\n\n- The `connect` method of this connection spawns a new instance of the <a href=\"https://github.com/fetchai/agents-aea/blob/main/libs/go/libp2p_node/libp2p_node.go\" target=\"_blank\">`libp2p_node` program</a> (i.e. an ACN peer node) and connects to it through OS pipes. Then, it sets up the _message receiving loop_, which enqueues messages in the input queue to be read by `read` method calls, and the _message sending loop_, which dequeues messages from the output queue and forwards them to the Libp2p node. The loops are run concurrently in the Multiplexer thread, using the Python asynchronous programming library `asyncio`.  \n\n``` mermaid\n    sequenceDiagram\n        participant Libp2p Connection\n        participant sending loop\n        participant receiving loop\n        participant Libp2p Node\n        Libp2p Connection->>Libp2p Node: spawn process\n        activate Libp2p Node\n        Libp2p Connection->>sending loop: start recv loop\n        sending loop->>sending loop: wait messages from output queue\n        activate sending loop\n        Libp2p Connection->>receiving loop: start send loop\n        receiving loop->>receiving loop: wait messages from input queue\n        activate receiving loop\n        deactivate Libp2p Node\n        deactivate sending loop\n        deactivate receiving loop\n```\n\n- The `send` method enqueues a message in the output queue. The message is then dequeued by the sending loop, and then sent to the Libp2p node.\n\n``` mermaid\n    sequenceDiagram\n        participant Libp2p Connection\n        participant sending loop\n        participant Libp2p Node\n        activate sending loop\n        Libp2p Connection->>Libp2p Connection: enqueue message to output queue\n        sending loop->>sending loop: dequeue message from output queue\n        deactivate sending loop\n        sending loop->>Libp2p Node: AeaEnvelope\n        sending loop->>sending loop: wait for status\n        activate sending loop\n        alt success\n            note over Libp2p Node: route envelope\n            Libp2p Node->>sending loop: Status(SUCCESS)\n            deactivate sending loop\n            note over sending loop: OK\n        else timed out\n            note over sending loop: raise with error\n        else acn message decoding error \n            Libp2p Node->>sending loop: Status(ERROR_SERIALIZATION)\n        else unexpected payload\n            Libp2p Node->>sending loop: Status(ERROR_UNEXPECTED_PAYLOAD)\n        else envelope decoding error \n            Libp2p Node->>sending loop: Status(ERROR_SERIALIZATION)\n        end\n```\n\n- The `receive` method dequeues a message from the input queue. The queue is populated by the receiving loop, which receives messages from the Libp2p node.\n\n``` mermaid\n    sequenceDiagram\n        participant Libp2p Connection\n        participant receiving loop\n        participant Libp2p Node\n        activate receiving loop\n        Libp2p Node->>receiving loop: AeaEnvelope\n        deactivate receiving loop\n        Libp2p Node->>Libp2p Node: wait for status\n        activate Libp2p Node\n        alt success\n            note over receiving loop: enqueue envelope<br/>to input queue\n            receiving loop->>Libp2p Node: Status(SUCCESS)\n            deactivate Libp2p Node\n            note over receiving loop: OK\n        else timed out\n            note over Libp2p Node: ignore\n        else acn message decoding error \n            receiving loop->>Libp2p Node: Status(ERROR_SERIALIZATION)\n        else unexpected payload\n            receiving loop->>Libp2p Node: Status(ERROR_UNEXPECTED_PAYLOAD)\n        else envelope decoding error \n            receiving loop->>Libp2p Node: Status(ERROR_SERIALIZATION)\n        end\n        Libp2p Connection->>receiving loop: read message from output queue\n        note over Libp2p Connection: return message<br/>to Multiplexer\n```\n\n- the `disconnect` method stops both the receiving loop and the sending loop, and stops the Libp2p node.\n\n### The `fetchai/p2p_libp2p_delegate` Connection\n\nThe source code of the `fetchai/p2p_libp2p_delegate` connection can be downloaded from <a href=\"https://aea-registry.fetch.ai/details/connection/fetchai/p2p_libp2p_client/latest\" target=\"_blank\">the main AEA framework repository.</a> or from <a href=\"https://github.com/fetchai/agents-aea/tree/main/packages/fetchai/connections/p2p_libp2p_client\" target=\"_blank\">the main AEA framework repository.</a>\n\nThe package provides the connection class `P2PLibp2pClientConnection`, which implements the `Connection` interface and therefore can be used by the Multiplexer as any other connection.\n\n- The `connect` method of this connection will set up a TCP connection to the URI of the delegate peer. Then, it will send a `Register` request to register the agent among the peer's client connections. On registration success, it sets up the _message receiving loop_, which enqueues messages in the input queue to be read by read method calls, and the _message sending loop_, which dequeues messages from the output queue and forwards them to the Libp2p node. The loops are run concurrently in the Multiplexer thread, using the Python asynchronous programming library `asyncio`.\n\n``` mermaid\n    sequenceDiagram\n        participant Libp2p Client Connection\n        participant Libp2p Node\n        activate Libp2p Node\n        Libp2p Node->>Libp2p Node: listening for TCP connections\n        Libp2p Client Connection->>Libp2p Node: Register (via TCP)\n        deactivate Libp2p Node\n        alt decoding error of ACN message\n            Libp2p Node->>Libp2p Client Connection: Status(ERROR_SERIALIZATION)\n        else wrong payload\n            Libp2p Node->>Libp2p Client Connection: Status(ERROR_UNEXPECTED_PAYLOAD)\n        else PoR check fails\n            alt wrong agent address\n                Libp2p Node->>Libp2p Client Connection: Status(ERROR_WRONG_AGENT_ADDRESS)\n            else unsupported ledger\n                Libp2p Node->>Libp2p Client Connection: Status(ERROR_UNSUPPORTED_LEDGER)\n            else agent address and public key don't match\n                Libp2p Node->>Libp2p Client Connection: Status(ERROR_WRONG_AGENT_ADDRESS)\n            else invalid proof\n                Libp2p Node->>Libp2p Client Connection: Status(ERROR_INVALID_PROOF)\n            end\n        else PoR check succeeds\n            Libp2p Node->>Libp2p Client Connection: Status(SUCCESS)\n            note over Libp2p Node: announce agent<br/>address to<br/>other peers\n            Libp2p Node->>Libp2p Node: wait data from socket \n            activate Libp2p Node\n            deactivate Libp2p Node\n        end\n```\n\n- The `send` method and the `receive` methods behave similarly to the `send` and `receive` methods of the <a href=\"../acn-internals#the-fetchaip2p_libp2p-connection\" target=\"_blank\">`p2p_libp2p connection`</a>, in terms of message exchange; however, the communication is done via TCP rather than pipes.\n\n- The `disconnect` method interrupts the connection with the delegate peer, without explicitly unregistering.\n\n## Known Issues and Limitations\n\nIn this section, we provide a list of known issues and limitations of the current implementation of the ACN, considering both the ACN nodes (written in Golang) and the AEA connections, for the Python AEA framework, to interact with them.\n\n### Delegate Client on Client Disconnection/Reconnection\n\nIn case of disconnection/reconnection, delegate client record will be removed. This can cause two problems: either the delegate client is not found, or connection is closed during the send operation.\n\nPossible solutions:\n\n- Create more complicated structure for clients storage;\n- Keep the delegate client record for longer;\n- Clean up the record by timeout, per client queues.\n\nCode references:\n\n- record removed: <a href=\"https://github.com/fetchai/agents-aea/blob/1db1720081969bcec1be5a2000ca176475d2b487/libs/go/libp2p_node/dht/dhtpeer/dhtpeer.go#L864\" target=\"_blank\">https://github.com/fetchai/agents-aea/blob/1db1720081969bcec1be5a2000ca176475d2b487/libs/go/libp2p_node/dht/dhtpeer/dhtpeer.go#L864</a>\n- send code: <a href=\"https://github.com/fetchai/agents-aea/blob/1db1720081969bcec1be5a2000ca176475d2b487/libs/go/libp2p_node/dht/dhtpeer/dhtpeer.go#L955\" target=\"_blank\">https://github.com/fetchai/agents-aea/blob/1db1720081969bcec1be5a2000ca176475d2b487/libs/go/libp2p_node/dht/dhtpeer/dhtpeer.go#L955</a>\n\n### Golang Node <> Python Client `libp2p` Connection\n\nIn case of connection between the Golang side (i.e. ACN node) and the Python side (i.e. the `libp2p` AEA connection) is broken, there is no reconnection attempt. The Golang side connect to the Python server opened, but if the connection is broken Golang can try to reconnect; however, the Python side does not know about this and will restart the node completely.\n\nPossible solutions: the problem requires updates on both sides and assume possible timeouts on broken connection. If connection is broken, the Python side awaits for reconnection from Golang side, and restart node completely after timeout.\n\n### What a Peer Should Do if it Receives an Acknowledgement with an Error?\n\nIf an ACN response is the `Status` with error code different from `SUCCESS`, the forwarding to other peers is not repeated.\n\nA possible solution is to resend the message; however, not clear why it should help in case of healthy connection, how many times the sender should retry, and how it would help.\n\nDiscussion on GitHub: <a href=\"https://github.com/fetchai/agents-aea/pull/2509#discussion_r642628983\" target=\"_blank\">https://github.com/fetchai/agents-aea/pull/2509#discussion_r642628983</a>\n\n### No Possibility of Switching Peers\n\nIn case of a peer becoming unavailable, a delegate client or relay client currently has no means to automatically switch the peer. In particular, the DHT should be updated when a client switches peers.\n"
  },
  {
    "path": "docs/acn.md",
    "content": "# Agent Communication Network\n\nThe agent communication network (ACN) provides a system for agents to find each other and communicate, solely based on their wallet addresses. It addresses the message delivery problem.\n\n## Message Delivery Problem\n\nAgents need to contact each others. Given the wallet address of a target agent, how can the originator agent deliver a message to it whilst guaranteeing certain properties?\n\nThe properties we would like to have, are:\n\n- Reliability: with guarantees on message reception\n- Authentication: to prevent impersonation\n- Confidentiality: to prevent exposing sensitive information within the message\n- Availability: some guarantees about the liveness of the service (tampering detection)\n\nThe problem statement and the agent framework context impose a number of design constraints:\n\n- Distributed environment: no assumption are placed about the location of the agent, they can be anywhere in the publicly reachable internet\n- Decentralized environment: no trusted central authority\n- Support for resource-constrained devices\n\nThe ACN solves the above problem whilst providing the above guarantees and satisfying the constraints.\n\n## Peers\n\nThe ACN is maintained by peers. Peers are not to be equated with agents. They are processes (usually distributed and decentralized) that together maintain the service. To use the service, agents need to associate themselves with peers. Thanks to digital signatures, the association between a given peer and agent can be verified by any participant in the system.\n\n## Distributed Hash Table\n\nAt its core, the ACN implements a distributed hash table (DHT). A DHT is similar to a regular hash table in that it stores key-value pairs. However, storage is distributed across the participating machines (peers) with an efficient lookup operation. This is enabled by:\n\n- Consistent hashing: decide responsibility for assignment of the DHT key-value storage\n- Structured overlays: organize the participating peers in a well-defined topology for efficient routing\n\n<img src=\"../assets/dht.jpg\" alt=\"DHT\" class=\"center\" style=\"display: block; margin-left: auto; margin-right: auto;width:50%;\">\n\nFor the ACN, we use the DHT to store and maintain association between an agent address and the (network) location of its peer.\n\n## N-Tier Architecture\n\nTo satisfy different resource constraints and flexible deployment the ACN is implemented as a multi-tier architecture. As such, it provides an extension of the client-server model. The agent framework exploits this by implementing different tiers as different <a href=\"../api/connections/base#connection-objects\">`Connections`</a>:\n\n<img src=\"../assets/acn-tiers.jpg\" alt=\"DHT\" class=\"center\" style=\"display: block; margin-left: auto; margin-right: auto;width:80%;\">\n\n!!! note\n    The `p2p_libp2p_mailbox` connection is not available yet.\n\n## Trust and Security\n\nAn agent can choose which connection to use depending on the resource and trust requirements:\n\n- `p2p_libp2p` connection: the agent maintains a peer of the ACN. The agent has full control over the peer and does not need to trust any other entity.\n- `p2p_libp2p_client` connection: the agent maintains a client connection to a server which is operated by a peer of the ACN. The agent does need to trust the entity operating the peer.\n\nAll communication protocols use public cryptography to ensure security (authentication, confidentiality, and availability) using TLS handshakes with pre-shared public keys.\n\n<img src=\"../assets/acn-trust-security.jpg\" alt=\"DHT\" class=\"center\" style=\"display: block; margin-left: auto; margin-right: auto;width:80%;\">\n"
  },
  {
    "path": "docs/aea-vs-mvc.md",
    "content": "# AEA and Web Frameworks\n\nThe AEA framework borrows several concepts from popular web frameworks like <a href=\"https://www.djangoproject.com/\" target=\"_blank\">Django</a> and <a href=\"https://rubyonrails.org/\" target=\"_blank\">Ruby on Rails</a>.\n\n## MVC\n\nBoth aforementioned web frameworks use the <a href=\"https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller\" target=\"_blank\">MVC</a> (model-view-controller) architecture.\n\n- Models: contain business logic and data representations\n- View: contain the HTML templates\n- Controller: deals with the request-response handling\n\n## Comparison with the AEA Framework\n\nThe AEA framework is based on <a href=\"https://en.wikipedia.org/wiki/Asynchronous_communication\" target=\"_blank\">asynchronous messaging</a> and other <a href=\"../agent-oriented-development\" target=\"_blank\">agent-oriented development assumptions</a>. Hence, there is not a direct one-to-one relationship between MVC based architectures and the AEA framework. Nevertheless, there are some parallels which can help a developer familiar with MVC make quick progress in the AEA framework, in particular the development of `Skills`:\n\n- <a href=\"../api/skills/base#handler-objects\">`Handler`</a>: receives messages for the protocol it is registered against and is supposed to handle these messages. Handlers are the reactive parts of a skill and can be thought of as similar to the `Controller` in MVC. They can also send new messages.\n- <a href=\"../api/skills/base#behaviour-objects\">`Behaviour`</a>: a behaviour encapsulates proactive components of the agent. Since web apps do not have any goals or intentions, they do not proactively pursue an objective. Therefore, there is no equivalent concept in MVC. Behaviours also can, but do not have to, send messages.\n- <a href=\"../api/skills/tasks#task-objects\">`Task`</a>: they are meant to deal with long-running executions and can be thought of as the equivalent of background tasks in traditional web apps.\n- <a href=\"../api/skills/base#model-objects\">`Model`</a>: they implement business logic and data representation, and as such, they are similar to the `Model` in MVC.\n\n<img src=\"../assets/skill-components.jpg\" alt=\"AEA Skill Components\" class=\"center\" style=\"display: block; margin-left: auto; margin-right: auto;width:80%;\">\n\nThe `View` concept is probably best compared to the `Message` of a given `Protocol` in the AEA framework. Whilst views represent information to the client, messages represent information sent to other agents, other agent components and services.\n\n## Next Steps\n\nWe recommend you continue with the next step in the 'Getting Started' series:\n\n- <a href=\"../skill-guide\">Build a skill for an AEA</a>\n"
  },
  {
    "path": "docs/aeas.md",
    "content": "# Autonomous Economic Agents (AEAs)\n\n<iframe width=\"560\" height=\"315\" src=\"https://www.youtube.com/embed/xpJA4IT5X88\" frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen></iframe>\n\n## What is an AEA?\n\n!!! info \"Definition\"\n    An Autonomous Economic Agent (AEA) is an intelligent agent that acts on its owner's behalf, with limited or no interference, and whose goal is to generate economic value for its owner.\n\nLet's break down the term **Autonomous Economic Agent (AEA)**: \n\n* **Agent**: An AEA is first and foremost an _agent_, representing an individual, organisation or object (a.k.a. its \"owner\") in the digital world. An AEA looks after its owner's interests and has their preferences in mind when acting on their behalf.\n* **Autonomous**: AEAs operate independently of constant input from their owners and act autonomously to achieve their goals.\n* **Economic**: AEAs have a narrow and specific focus: creating economic value for their owner.\n\nSome of the other characteristics AEAs typically have:\n\n* **Proactive**: AEAs are proactive; they take the initiative and perform actions that take them closer to their goals. \n* **Reactive**: AEAs are also reactive; they are aware of the environment they are in, perceive changes in the environment, and react to these changes in accordance to their goals.\n* **Self-interested**: An AEA primarily looks after its own interests (which is aligned with those of its owner) and not necessarily the interests of other agents or the larger system.\n\n### What is NOT an AEA?\n\n* **Any agent**: AEAs are NOT meant to address _any_ needs their owners might have. They have a clear and well-defined focus, which is generating economic value for their owner and this is manifested in a variety of different ways in their design.\n* **Digital twins**: An AEA is NOT it's owner's twin in the digital world; i.e. mirroring their preferences, values, and priorities. An AEA can be given whatever preference, value, and priority its owner wants them to have.\n* **APIs or Sensors**: These do NOT have any agency, nor proactiveness. They just \"sit there\" and respond to requests or changes in the environment.\n* **Smart contracts**: Similar to APIs and sensors, smart contracts do NOT display any proactiveness; they are purely reactive to external requests (in their case, contract calls and transactions).\n* An agent with **Artificial General Intelligence (AGI)**: AEAs have a well-defined, narrow, and goal directed focus that involves some economic gain. \n\n!!! info \"Agents and AEAs\"\n    In the rest of the documentation, unless specified, we use the terms **AEA** and **Agent** interchangeably to mean AEA as defined above description.\n"
  },
  {
    "path": "docs/agent-oriented-development.md",
    "content": "# Agent-Oriented Development\n\nIn this section, we discuss some of the most fundamental characteristics of an agent-oriented approach to solution development, which might be different from existing paradigms and methodologies that you may be used to. We hope that with this, we can guide you towards the right mindset when designing your own agent-based solutions to real world problems.\n\n## Decentralisation\n\nMulti-Agent Systems (**MAS**) are inherently decentralized. The vision is of an environment in which every agent is able to directly connect with everyone else and interact with them without having to rely on a third party acting as an intermediary or match-maker. This is in direct contrast to centralized systems in which a single entity is the central point of authority, through which all interactions happen. The conventional client-server model is an example of a centralized architecture where clients interact with one another regarding specific services (e.g. communication, commerce) only through a server.\n\nThis is not to say that facilitators and middlemen have no place in a multi-agent system; rather it is the '_commanding reliance on middlemen_' that MAS rejects.\n\n**Division of responsibilities:** In a decentralized system, every agent is equally privileged, and (in principle) should be able to interact with any other agent. The idea is very much aligned with the peer-to-peer paradigm, in which it is the voluntary participation and contribution of the peers that create the infrastructure. Therefore, in a decentralized system, there is no central 'enforcer'. This means all the work that would typically fall under the responsibilities of a central entity must be performed by individual parties in a decentralized system. Blockchain-based cryptocurrencies are a good example of this. A notable characteristic of cryptocurrencies is the absence of central trusted entities (e.g. banks). But this in turn means that most security precautions related to the handling of digital assets and the execution of transactions are the responsibility of individuals.\n\n<!--Another example is the verification of protocol adherence in regulated systems. Consider the problem of traffic management. The success of such a system relies on its participants (e.g. pedestrians, cars, motorbikes, bicycles, etc) conforming with the traffic management protocol, which specifies, for instance, who has the right of way in a junction. It is trivial, that the continuous functioning of this system does not rest solely on the existence of a protocol; there should also be a mechanism in place that verifies the protocol is followed by the participants. In a central system, verifying whether parties adhere to the system's protocol is often the responsibility of a central unit that checks (some or all) actions of the parties involved. The police could be considered a central entity that enforces traffic protocols and punishes those violating it. However, in a decentralized environment, this burden falls on the parties involved in the interaction themselves. Therefore, one could imagine a self-governing traffic management system whereby individuals on the road enforce protocol adherence on each other and decide on the appropriate method(s) of enforcement (e.g. through collective punishments, sanctions, rewards, ratings, etc).-->\n\n**Decentralisation vs distribution:** It is important to emphasise that by decentralisation we do not mean distribution; although multi-agent systems typically do also tend to be distributed. A distributed system is one whose components are physically located in different places and connected over a network. A fully centralized system, owned and operated by a single entity, may in fact be highly distributed. Google or Microsoft's cloud infrastructure are examples of this, where their components are distributed across the globe yet designed to work together harmoniously and function in unison. Decentralisation on the other hand refers to a system whose components may be owned, operated, and managed by different stakeholders, each with their own personal objectives, interests, and preferences which may not necessarily be aligned with one another or the system itself. Therefore, distribution refers to the physical placement of a system's components, whereas decentralisation refers to **a.** the diversity of ownership and control over a system's constituents, and **b.** the absence of central authorities between them.\n\n**Example:** To better illustrate the distinction between centralized and decentralized systems, consider another example: search and discoverability in a commerce environment. In a centralized system (say Amazon), there is a single search service -- provided, owned and run by the commerce company itself -- which takes care of all search-related functionality for every product within their domain. So to be discoverable in this system, all sellers must register their products with this particular service. However, in a decentralized system, there may not necessarily be a single search service provider. There may be multiple such services, run by different, perhaps competing entities. Each seller has the freedom to register with (i.e. make themselves known to) one or a handful of services. On the buyers side, the more services they contact and query, the higher their chances of finding the product they are looking for.\n\n## Conflicting Environment\n\nAs discussed above, the notion of decentralisation extends as far as ownership and control. Therefore, the different components that make up a decentralized system may each be owned by a different entity, designed according to very different principles and standards, with heterogeneous software and hardware, and each with internal objectives that may be fundamentally inconsistent, worse yet contradictory, with those of others.\n\nAs such, a distinctive characteristic of a multi-agent environment, is that it is inhabited by more than one agent (as the name suggests), where each agent may be owned potentially by a different stakeholder (individual, company, government). Since by design, each agent represents and looks after the interests of its owner(s), and because different stakeholders may have unaligned, conflicting, or contradictory interests, it is very common to have multi-agent systems in which the agents' objectives, values and preferences are unaligned, conflicting, or contradictory.\n\n**In practice:** There are practical implications that follow from the above when it comes to designing an agent. For example, it is not rational for an agent to automatically rely on the information it receives from other agents. The information could be:\n\n- Incomplete: what is unrevealed may have been deemed private for strategic reasons.\n- Uncertain: it may be the result of an inaccurate prediction.\n- Incorrect: it could be an outright lie, due to the adversarial nature of the environment.\n\nTherefore, one can argue that there is a degree of uncertainty attached to almost all information an agent receives or infers in a multi-agent system. It wouldn't then be illogical for an agent to take a sceptical approach: treating everything as uncertain, unless proved otherwise.\n\n## Asynchronization\n\nThe conflicting nature of multi-agent systems, consisting of self-interested autonomous agents, points to _asynchronization_ as the preferred method of designing and managing processes and interactions.\n\n**Synchronisation vs asynchronization:** In general, asynchronization refers to the decoupling of events that do interact with one another but do not occur at predetermined intervals, not necessarily relying on each other's existence to function. This is in contrast with _synchronous_ systems in which processes are aware of one another, where one's execution depends in some way on the other.\n\n**Asynchronization in MAS:** In the context of multi-agent systems, the decentralized and potentially conflicting nature of the environment creates uncertainty over the behaviour of the whole system, in particular of other agents. For example, suppose an agent `i` sends a message requesting some resources from an agent `j`. Since MAS often tends to be distributed, there is the usual uncertainties with communication over a network: `j` may never receive `i`'s request, or may receive it after a long delay. Furthermore, `j` could receive the request in time and respond immediately, but as mentioned in the last section, its answer might be incomplete (gives only some of the requested resources), uncertain (promises to give the resources, but cannot be fully trusted), or incorrect (sends a wrong resource). In addition, since agents are self-interested, `j` may _decide_ to reply much later, to the point that the resource is no longer useful to agent `i`, or `j` may simply decide not to respond at all. There might be a myriad of reasons why it may choose to do that; it could be because `j` assigns a low priority to answering `i` over its other tasks. But that's beside the point. The takeaway is that agents' autonomy strongly influences what can be expected of them, and of an environment inhabited by them. As such, developing for a system whose constituents are autonomous, e.g. agents in a multi-agent system, is fundamentally different from one whose constituents aren't, e.g. objects in an object-oriented system.\n\n**Objects vs agents:** In object-oriented systems, objects are entities that encapsulate state and perform actions, i.e. call methods, on this state. In object-oriented languages, like C++ and Java, it is common practice to declare methods as public, so they can be invoked by other objects in the system whenever they wish. This implies that an object does not control its own behaviour. If an object’s method is public, the object has no control over whether that method is executed.  \n\nWe cannot take for granted that an agent `j` will execute an action (the equivalent of a method in object-oriented systems) just because another agent `i` wants it to; this action may not be in the best interests of agent `j`. So we do not think of agents as invoking methods on one another, rather as _requesting_ actions. If `i` requests `j` to perform an action, then `j` may or may not perform the action. It may choose to do it later or do it in exchange for something. The locus of control is therefore different in object-oriented and agent-oriented systems. In the former, the decision lies with the object invoking the method, whereas in the latter, the decision lies with the agent receiving the request. This distinction could be summarised by the following slogan (from <a href=\"https://www.wiley.com/en-gb/An+Introduction+to+MultiAgent+Systems%2C+2nd+Edition-p-9781119959519\" target=\"_blank\">An Introduction to MultiAgent Systems</a> by <a href=\"https://www.cs.ox.ac.uk/people/michael.wooldridge/\" target=\"_blank\">Michael Wooldridge</a>):\n>objects do it for free; agents do it because they want to.\n\nAll of this makes asynchronization the preferred method for designing agent processes and interactions. An agent's interactions should be independent of each other, as much as possible, and of the agent's decision-making processes and actions. This means the success or failure of, or delay in any single interaction does not block the agent's other tasks.\n\n## Time\n\nClosely related with the discussion of asynchronicity, is the idea that in multi-agent systems, time is not a universally agreed notion. Agents may not necessarily share the same clock and this fact must be taken into account when designing agent-based systems. For example, you cannot necessarily expect agents to synchronise their behaviour according to time (e.g. perform a certain task at a time `X`).\n\nAnother related issue, is that unlike some agent-based simulation (ABS) systems where there is a global tick rate for all agents, in AEA-based systems tick rates may be different for different agents. This is due to the fundamental difference that ABS systems control some aspects of all of their agents' executions while in AEA-based systems, agents are truly decoupled from one another  - most likely distributed and running on different machines and networks - and there is absolutely no central unit that moderates any aspect of their behaviour.\n\n## Complex, Incomplete, Inconsistent and Uncertain\n\nThe fourth characteristic(s) relate to the environment in which agents are expected to operate in, and these have been mentioned a number of times in the previous sections.\n\nThe environment agents are suited for typically tend to be complex, to the point that it is usually impossible for any single agent to perceive the whole of the environment on its own. This means that at any point in time, any agent has a limited knowledge about the state of the environment. In other words, the agents;' information tend to be incomplete due to the complexity and sophistication of the world in which they reside.\n\nConsider an agent which represents a driver-less vehicle. The complexity of the problem of driving on the road makes it impossible for a single vehicle to have an accurate and up-to-date knowledge of the overall state of the world . This means that an agent's model of the world is at best uncertain. For instance, the vehicle, through its sensor may detect green light at a junction, and by being aware of what it means, it may infer that it is safe to cross a junction. However, that simply may not be true as another car in the opposite direction may still cross the junction violating their red light. Therefore, there is uncertainty associated with the knowledge \"it is safe to cross the road because the light is green\", and the agent must recognise that.\n\nFurthermore, the often conflicting nature of the environment means information obtained from multiple sources (agents) may be inconsistent. Again, this must be taken into consideration when designing an agent which is expected to operate successfully in a potentially conflicting environment.\n\n## Further Reading\n\n- Wooldridge, M. (2009). _An Introduction to MultiAgent Systems_. Wiley, Second edition.\n- Shoham, Y. and Leyton-Brown, K. (2008). _Multiagent Systems: Algorithmic, Game-Theoretic, and Logical Foundations_. Cambridge University Press\n"
  },
  {
    "path": "docs/agent-vs-aea.md",
    "content": "# AEAs vs Agents\n\nAEAs are more than just agents.\n\n<img src=\"../assets/aea-vs-agent-vs-multiplexer.jpg\" alt=\"AEA vs Agent vs Multiplexer\" class=\"center\" style=\"display: block; margin-left: auto; margin-right: auto;width:100%;\">\n\nIn this guide, we show some of the differences in terms of code.\n\nThe <a href=\"../build-aea-programmatically\">Build an AEA programmatically</a> guide shows how to programmatically build an AEA. We can build an agent of the <a href=\"../api/agent#agent-objects\">`Agent`</a> class programmatically as well.\n\nFirst, import the python and application specific libraries. (Get the `packages` directory from the AEA repository `svn export https://github.com/fetchai/agents-aea.git/trunk/packages`.)\n\n``` python\nimport os\nimport time\nfrom threading import Thread\nfrom typing import List\n\nfrom aea.agent import Agent\nfrom aea.configurations.base import ConnectionConfig\nfrom aea.connections.base import Connection\nfrom aea.helpers.file_io import write_with_lock\nfrom aea.identity.base import Identity\nfrom aea.mail.base import Envelope\n\nfrom packages.fetchai.connections.stub.connection import StubConnection\nfrom packages.fetchai.protocols.default.message import DefaultMessage\n```\n\nUnlike an `AEA`, an `Agent` does not require a `Wallet`, `LedgerApis` or `Resources` module.\n\nHowever, we need to implement 4 abstract methods:\n\n- `setup()`\n- `act()`\n- `handle_envelope()`\n- `teardown()`\n\nWhen we run an agent, `start()` calls `setup()` and then the main agent loop. The main agent loop calls `act()`, `react()` and `update()` on each tick. When the agent is stopped via `stop()` then `teardown()` is called.\n\nSuch a lightweight agent can be used to implement simple logic.\n\n## Code an `Agent`\n\nWe define our `Agent` which simply receives envelopes, prints the sender address and `protocol_id` and returns it unopened.\n\n``` python\nINPUT_FILE = \"input_file\"\nOUTPUT_FILE = \"output_file\"\n\n\nclass MyAgent(Agent):\n    \"\"\"A simple agent.\"\"\"\n\n    def __init__(self, identity: Identity, connections: List[Connection]):\n        \"\"\"Initialise the agent.\"\"\"\n        super().__init__(identity, connections)\n\n    def setup(self):\n        \"\"\"Setup the agent.\"\"\"\n\n    def act(self):\n        \"\"\"Act implementation.\"\"\"\n        print(\"Act called for tick {}\".format(self.tick))\n\n    def handle_envelope(self, envelope: Envelope) -> None:\n        \"\"\"\n        Handle envelope.\n\n        :param envelope: the envelope received\n        :return: None\n        \"\"\"\n        print(\"React called for tick {}\".format(self.tick))\n        if (\n            envelope is not None\n            and envelope.protocol_specification_id\n            == DefaultMessage.protocol_specification_id\n        ):\n            sender = envelope.sender\n            receiver = envelope.to\n            envelope.to = sender\n            envelope.sender = receiver\n            envelope.message = DefaultMessage.serializer.decode(envelope.message_bytes)\n            envelope.message.sender = receiver\n            envelope.message.to = sender\n            print(\n                \"Received envelope from {} with protocol_specification_id={}\".format(\n                    sender, envelope.protocol_specification_id\n                )\n            )\n            self.outbox.put(envelope)\n\n    def teardown(self):\n        \"\"\"Teardown the agent.\"\"\"\n```\n\n## Instantiate an `Agent`\n\n``` python\n    # Ensure the input and output files do not exist initially\n    if os.path.isfile(INPUT_FILE):\n        os.remove(INPUT_FILE)\n    if os.path.isfile(OUTPUT_FILE):\n        os.remove(OUTPUT_FILE)\n\n    # Create an addresses identity:\n    identity = Identity(\n        name=\"my_agent\", address=\"some_address\", public_key=\"public_key\"\n    )\n\n    # Set up the stub connection\n    configuration = ConnectionConfig(\n        input_file_path=INPUT_FILE,\n        output_file_path=OUTPUT_FILE,\n        connection_id=StubConnection.connection_id,\n    )\n    stub_connection = StubConnection(\n        configuration=configuration, data_dir=\".\", identity=identity\n    )\n\n    # Create our Agent\n    my_agent = MyAgent(identity, [stub_connection])\n```\n\n## Start the Agent\n\nWe run the agent from a different thread so that we can still use the main thread to pass it messages.\n\n``` python\n    # Set the agent running in a different thread\n    try:\n        t = Thread(target=my_agent.start)\n        t.start()\n\n        # Wait for everything to start up\n        time.sleep(3)\n```\n\n## Send and Receive an Envelope\n\nWe use the input and output text files to send an envelope to our agent and receive a response\n\n``` python\n        # Create a message inside an envelope and get the stub connection to pass it into the agent\n        message_text = b\"my_agent,other_agent,fetchai/default:1.0.0,\\x12\\r\\x08\\x01*\\t*\\x07\\n\\x05hello,\"\n\n        with open(INPUT_FILE, \"wb\") as f:\n            write_with_lock(f, message_text)\n\n        # Wait for the envelope to get processed\n        time.sleep(2)\n\n        # Read the output envelope generated by the agent\n        with open(OUTPUT_FILE, \"rb\") as f:\n            print(\"output message: \" + f.readline().decode(\"utf-8\"))\n```\n\n## Shutdown\n\nFinally, stop our agent and wait for it to finish\n\n``` python\n    finally:\n        # Shut down the agent\n        my_agent.stop()\n        t.join()\n```\n\n## Your Turn\n\nNow it is your turn to develop a simple agent with the `Agent` class.\n\n## Entire Code Listing\n\nIf you just want to copy and paste the entire script in you can find it here:\n\n??? note \"Click here to see full listing\"\n\n    ``` python\n    import os\n    import time\n    from threading import Thread\n    from typing import List\n    \n    from aea.agent import Agent\n    from aea.configurations.base import ConnectionConfig\n    from aea.connections.base import Connection\n    from aea.helpers.file_io import write_with_lock\n    from aea.identity.base import Identity\n    from aea.mail.base import Envelope\n    \n    from packages.fetchai.connections.stub.connection import StubConnection\n    from packages.fetchai.protocols.default.message import DefaultMessage\n    \n    \n    INPUT_FILE = \"input_file\"\n    OUTPUT_FILE = \"output_file\"\n    \n    \n    class MyAgent(Agent):\n        \"\"\"A simple agent.\"\"\"\n    \n        def __init__(self, identity: Identity, connections: List[Connection]):\n            \"\"\"Initialise the agent.\"\"\"\n            super().__init__(identity, connections)\n    \n        def setup(self):\n            \"\"\"Setup the agent.\"\"\"\n    \n        def act(self):\n            \"\"\"Act implementation.\"\"\"\n            print(\"Act called for tick {}\".format(self.tick))\n    \n        def handle_envelope(self, envelope: Envelope) -> None:\n            \"\"\"\n            Handle envelope.\n    \n            :param envelope: the envelope received\n            :return: None\n            \"\"\"\n            print(\"React called for tick {}\".format(self.tick))\n            if (\n                envelope is not None\n                and envelope.protocol_specification_id\n                == DefaultMessage.protocol_specification_id\n            ):\n                sender = envelope.sender\n                receiver = envelope.to\n                envelope.to = sender\n                envelope.sender = receiver\n                envelope.message = DefaultMessage.serializer.decode(envelope.message_bytes)\n                envelope.message.sender = receiver\n                envelope.message.to = sender\n                print(\n                    \"Received envelope from {} with protocol_specification_id={}\".format(\n                        sender, envelope.protocol_specification_id\n                    )\n                )\n                self.outbox.put(envelope)\n    \n        def teardown(self):\n            \"\"\"Teardown the agent.\"\"\"\n    \n    \n    def run():\n        \"\"\"Run demo.\"\"\"\n    \n        # Ensure the input and output files do not exist initially\n        if os.path.isfile(INPUT_FILE):\n            os.remove(INPUT_FILE)\n        if os.path.isfile(OUTPUT_FILE):\n            os.remove(OUTPUT_FILE)\n    \n        # Create an addresses identity:\n        identity = Identity(\n            name=\"my_agent\", address=\"some_address\", public_key=\"public_key\"\n        )\n    \n        # Set up the stub connection\n        configuration = ConnectionConfig(\n            input_file_path=INPUT_FILE,\n            output_file_path=OUTPUT_FILE,\n            connection_id=StubConnection.connection_id,\n        )\n        stub_connection = StubConnection(\n            configuration=configuration, data_dir=\".\", identity=identity\n        )\n    \n        # Create our Agent\n        my_agent = MyAgent(identity, [stub_connection])\n    \n        # Set the agent running in a different thread\n        try:\n            t = Thread(target=my_agent.start)\n            t.start()\n    \n            # Wait for everything to start up\n            time.sleep(3)\n    \n            # Create a message inside an envelope and get the stub connection to pass it into the agent\n            message_text = b\"my_agent,other_agent,fetchai/default:1.0.0,\\x12\\r\\x08\\x01*\\t*\\x07\\n\\x05hello,\"\n    \n            with open(INPUT_FILE, \"wb\") as f:\n                write_with_lock(f, message_text)\n    \n            # Wait for the envelope to get processed\n            time.sleep(2)\n    \n            # Read the output envelope generated by the agent\n            with open(OUTPUT_FILE, \"rb\") as f:\n                print(\"output message: \" + f.readline().decode(\"utf-8\"))\n        finally:\n            # Shut down the agent\n            my_agent.stop()\n            t.join()\n    \n    \n    if __name__ == \"__main__\":\n        run()\n    ```\n"
  },
  {
    "path": "docs/aggregation-demo.md",
    "content": "# Aggregation Skill\n\nThis demo shows how AEAs can aggregate values over the peer-to-peer network.\n\n## Discussion\n\nThis demonstration shows how to set up a simple aggregation network in which several AEAs take an average of values fetched from different sources for the same real-world quantity. For this particular example, we take an average of Bitcoin prices from four public APIs.\n\n## Preparation Instructions\n\n### Dependencies\n\nFollow the <a href=\"../quickstart/#preliminaries\">Preliminaries</a> and <a href=\"../quickstart/#installation\">Installation</a> sections from the AEA quick start.\n\n## Demo\n\n### Create the AEAs\n\nRepeat the following process four times in four different terminals (for each {`i=0`, `i=1`, `i=2`, `i=3`}):\n\nFetch the aggregator AEA:\n\n``` bash\nagent_name=\"agg$i\"\naea fetch fetchai/simple_aggregator:0.5.5 --alias $agent_name\ncd $agent_name\naea install\naea build\n```\n\n??? note \"Alternatively, create from scratch:\"\n\n    Create the AEA:\n\n    ``` bash\n    agent_name=\"agg$i\"\n    aea create agent_name\n    cd agent_name\n    aea add connection fetchai/http_client:0.24.6\n    aea add connection fetchai/http_server:0.23.6\n    aea add connection fetchai/p2p_libp2p:0.27.5\n    aea add connection fetchai/soef:0.27.6\n    aea add connection fetchai/prometheus:0.9.6\n    aea add skill fetchai/advanced_data_request:0.7.6\n    aea add skill fetchai/simple_aggregation:0.3.6\n    \n    aea config set agent.default_connection fetchai/p2p_libp2p:0.27.5\n    aea install\n    aea build\n    ```\n   \n    Set the desired decimal precision for the quantity:\n\n    ``` bash\n    aea config set --type int vendor.fetchai.skills.advanced_data_request.models.advanced_data_request_model.args.decimals 0\n    ```\n\n    Disable the http server since it is not used in this demo:\n\n    ``` bash\n    aea config set --type bool vendor.fetchai.skills.advanced_data_request.models.advanced_data_request_model.args.use_http_server false\n    ```\n\nSet the cert requests for the peer-to-peer connection:\n\n``` bash\naea config set --type list vendor.fetchai.connections.p2p_libp2p.cert_requests \\\n'[{\"identifier\": \"acn\", \"ledger_id\": \"fetchai\", \"not_after\": \"2023-01-01\", \"not_before\": \"2022-01-01\", \"public_key\": \"fetchai\", \"message_format\": \"{public_key}\", \"save_path\": \".certs/conn_cert.txt\"}]'\n```\n\nMatch the agent index `i` to the `COIN_URL` and `JSON_PATH` below:\n\n- `agg0`: `COIN_URL=\"https://api.coinbase.com/v2/prices/BTC-USD/buy\" && JSON_PATH=\"data.amount\"`\n- `agg1`: `COIN_URL=\"https://api.coinpaprika.com/v1/tickers/btc-bitcoin\" && JSON_PATH=\"quotes.USD.price\"`\n- `agg2`: `COIN_URL=\"https://api.cryptowat.ch/markets/kraken/btcusd/price\" && JSON_PATH=\"result.price\"`\n- `agg3`: `COIN_URL=\"https://api.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies=usd\" && JSON_PATH=\"bitcoin.usd\"`\n\nSet the following configuration for the `advanced_data_request` skill:\n\n``` bash\naea config set vendor.fetchai.skills.advanced_data_request.models.advanced_data_request_model.args.url $COIN_URL\naea config set vendor.fetchai.skills.advanced_data_request.models.advanced_data_request_model.args.outputs '[{\"name\": \"price\", \"json_path\": '\"\\\"$JSON_PATH\\\"\"'}]'\n```\n\nSet the name of the quantity to aggregate and choose an aggregation function for the AEAs (the currently implemented options are `mean`, `median`, and `mode`):\n\n``` bash\naea config set vendor.fetchai.skills.simple_aggregation.models.strategy.args.quantity_name price\naea config set vendor.fetchai.skills.simple_aggregation.models.strategy.args.aggregation_function mean\n```\n\nSpecify a name for your aggregation service:\n\n``` bash\nSERVICE_ID=my_btc_aggregation_service\naea config set vendor.fetchai.skills.simple_aggregation.models.strategy.args.service_id $SERVICE_ID\naea config set vendor.fetchai.skills.simple_aggregation.models.strategy.args.search_query.search_value $SERVICE_ID\n```\n\nAdditionally, create private keys for use with the ledger and the peer-to-peer connection:\n\n``` bash\naea generate-key fetchai\naea add-key fetchai\naea generate-key fetchai fetchai_connection_private_key.txt\naea add-key fetchai fetchai_connection_private_key.txt --connection\n```\n\nFinally, certify the keys for use by the connections that request them:\n\n``` bash\naea issue-certificates\n```\n\n### Configure the Peer-to-Peer Network\n\nSet the multiaddress of the first AEA as an initial peer to help the remaining AEAs find each other on the network. Also, if these AEAs are all running on the same machine, set different ports for their connections to ensure there are no conflicts (from the `agg1`, `agg2`, and `agg3` directories):\n\n``` bash\nMULTIADDR=$(cd ../agg0 && aea get-multiaddress fetchai --connection)\naea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \\\n'{\n\"delegate_uri\": \"127.0.0.1:'$((11000+i))'\",\n\"entry_peers\": [\"/dns4/127.0.0.1/tcp/9000/p2p/'\"$MULTIADDR\\\"\"'],\n\"local_uri\": \"127.0.0.1:'$((9000+i))'\",\n\"log_file\": \"libp2p_node.log\",\n\"public_uri\": \"127.0.0.1:'$((9000+i))'\"\n}'\naea config set vendor.fetchai.connections.prometheus.config.port $((20000+i))\naea config set vendor.fetchai.connections.http_server.config.port $((8000+i))\n```\n\n### Oracle Integration (optional)\n\nTo publish the aggregated value to an oracle smart contract, add the ledger connection and simple oracle skill to one of the aggregators:\n\n``` bash\naea add connection fetchai/ledger:0.21.5\naea add skill fetchai/simple_oracle:0.16.5\n```\n\nConfigure the simple oracle skill for the `fetchai` ledger:\n\n``` bash\naea config set vendor.fetchai.skills.simple_oracle.models.strategy.args.ledger_id fetchai\naea config set vendor.fetchai.skills.simple_oracle.models.strategy.args.update_function update_oracle_value\n```\n\nGenerate some wealth to use for transactions on the testnet ledger:\n\n``` bash\naea generate-wealth fetchai\n```\n\nSet the name of the oracle value to match the value collected by the aggregators:\n\n``` bash\naea config set vendor.fetchai.skills.simple_oracle.models.strategy.args.oracle_value_name price_mean\n```\n\n### Run the AEAs\n\nRun each of the aggregator AEAs in separate terminals:\n\n``` bash\naea run\n```\n\nAfter a few moments, you should see the AEAs finding peers, making observations, sending them to peers, and taking the average of their observations:\n\n``` bash\ninfo: [agg_i] found agents...\n...\ninfo: [agg_i] Fetching data from...\n...\ninfo: [agg_i] Observation: {'price': {'value':...\n...\ninfo: [agg_i] sending observation to peer...\n...\ninfo: [agg_i] received observation from sender...\n...\ninfo: [agg_i] Observations:...\n...\ninfo: [agg_i] Aggregation (mean):...\n```\n"
  },
  {
    "path": "docs/api/abstract_agent.md",
    "content": "<a id=\"aea.abstract_agent\"></a>\n\n# aea.abstract`_`agent\n\nThis module contains the interface definition of the abstract agent.\n\n<a id=\"aea.abstract_agent.AbstractAgent\"></a>\n\n## AbstractAgent Objects\n\n```python\nclass AbstractAgent(ABC)\n```\n\nThis class provides an abstract base  interface for an agent.\n\n<a id=\"aea.abstract_agent.AbstractAgent.name\"></a>\n\n#### name\n\n```python\n@property\n@abstractmethod\ndef name() -> str\n```\n\nGet agent's name.\n\n<a id=\"aea.abstract_agent.AbstractAgent.storage_uri\"></a>\n\n#### storage`_`uri\n\n```python\n@property\n@abstractmethod\ndef storage_uri() -> Optional[str]\n```\n\nReturn storage uri.\n\n<a id=\"aea.abstract_agent.AbstractAgent.start\"></a>\n\n#### start\n\n```python\n@abstractmethod\ndef start() -> None\n```\n\nStart the agent.\n\n**Returns**:\n\nNone\n\n<a id=\"aea.abstract_agent.AbstractAgent.stop\"></a>\n\n#### stop\n\n```python\n@abstractmethod\ndef stop() -> None\n```\n\nStop the agent.\n\n**Returns**:\n\nNone\n\n<a id=\"aea.abstract_agent.AbstractAgent.setup\"></a>\n\n#### setup\n\n```python\n@abstractmethod\ndef setup() -> None\n```\n\nSet up the agent.\n\n**Returns**:\n\nNone\n\n<a id=\"aea.abstract_agent.AbstractAgent.act\"></a>\n\n#### act\n\n```python\n@abstractmethod\ndef act() -> None\n```\n\nPerform actions on period.\n\n**Returns**:\n\nNone\n\n<a id=\"aea.abstract_agent.AbstractAgent.handle_envelope\"></a>\n\n#### handle`_`envelope\n\n```python\n@abstractmethod\ndef handle_envelope(envelope: Envelope) -> None\n```\n\nHandle an envelope.\n\n**Arguments**:\n\n- `envelope`: the envelope to handle.\n\n**Returns**:\n\nNone\n\n<a id=\"aea.abstract_agent.AbstractAgent.get_periodic_tasks\"></a>\n\n#### get`_`periodic`_`tasks\n\n```python\n@abstractmethod\ndef get_periodic_tasks(\n) -> Dict[Callable, Tuple[float, Optional[datetime.datetime]]]\n```\n\nGet all periodic tasks for agent.\n\n**Returns**:\n\ndict of callable with period specified\n\n<a id=\"aea.abstract_agent.AbstractAgent.get_message_handlers\"></a>\n\n#### get`_`message`_`handlers\n\n```python\n@abstractmethod\ndef get_message_handlers() -> List[Tuple[Callable[[Any], None], Callable]]\n```\n\nGet handlers with message getters.\n\n**Returns**:\n\nList of tuples of callables: handler and coroutine to get a message\n\n<a id=\"aea.abstract_agent.AbstractAgent.exception_handler\"></a>\n\n#### exception`_`handler\n\n```python\n@abstractmethod\ndef exception_handler(exception: Exception,\n                      function: Callable) -> Optional[bool]\n```\n\nHandle exception raised during agent main loop execution.\n\n**Arguments**:\n\n- `exception`: exception raised\n- `function`: a callable exception raised in.\n\n**Returns**:\n\nskip exception if True, otherwise re-raise it\n\n<a id=\"aea.abstract_agent.AbstractAgent.teardown\"></a>\n\n#### teardown\n\n```python\n@abstractmethod\ndef teardown() -> None\n```\n\nTear down the agent.\n\n**Returns**:\n\nNone\n\n"
  },
  {
    "path": "docs/api/aea.md",
    "content": "<a id=\"aea.aea\"></a>\n\n# aea.aea\n\nThis module contains the implementation of an autonomous economic agent (AEA).\n\n<a id=\"aea.aea.AEA\"></a>\n\n## AEA Objects\n\n```python\nclass AEA(Agent)\n```\n\nThis class implements an autonomous economic agent.\n\n<a id=\"aea.aea.AEA.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(\n        identity: Identity,\n        wallet: Wallet,\n        resources: Resources,\n        data_dir: str,\n        loop: Optional[AbstractEventLoop] = None,\n        period: float = 0.05,\n        execution_timeout: float = 0,\n        max_reactions: int = 20,\n        error_handler_class: Optional[Type[AbstractErrorHandler]] = None,\n        error_handler_config: Optional[Dict[str, Any]] = None,\n        decision_maker_handler_class: Optional[\n            Type[DecisionMakerHandler]] = None,\n        decision_maker_handler_config: Optional[Dict[str, Any]] = None,\n        skill_exception_policy: ExceptionPolicyEnum = ExceptionPolicyEnum.\n    propagate,\n        connection_exception_policy: ExceptionPolicyEnum = ExceptionPolicyEnum.\n    propagate,\n        loop_mode: Optional[str] = None,\n        runtime_mode: Optional[str] = None,\n        default_ledger: Optional[str] = None,\n        currency_denominations: Optional[Dict[str, str]] = None,\n        default_connection: Optional[PublicId] = None,\n        default_routing: Optional[Dict[PublicId, PublicId]] = None,\n        connection_ids: Optional[Collection[PublicId]] = None,\n        search_service_address: str = DEFAULT_SEARCH_SERVICE_ADDRESS,\n        storage_uri: Optional[str] = None,\n        task_manager_mode: Optional[str] = None,\n        **kwargs: Any) -> None\n```\n\nInstantiate the agent.\n\n**Arguments**:\n\n- `identity`: the identity of the agent\n- `wallet`: the wallet of the agent.\n- `resources`: the resources (protocols and skills) of the agent.\n- `data_dir`: directory where to put local files.\n- `loop`: the event loop to run the connections.\n- `period`: period to call agent's act\n- `execution_timeout`: amount of time to limit single act/handle to execute.\n- `max_reactions`: the processing rate of envelopes per tick (i.e. single loop).\n- `error_handler_class`: the class implementing the error handler\n- `error_handler_config`: the configuration of the error handler\n- `decision_maker_handler_class`: the class implementing the decision maker handler to be used.\n- `decision_maker_handler_config`: the configuration of the decision maker handler\n- `skill_exception_policy`: the skill exception policy enum\n- `connection_exception_policy`: the connection exception policy enum\n- `loop_mode`: loop_mode to choose agent run loop.\n- `runtime_mode`: runtime mode (async, threaded) to run AEA in.\n- `default_ledger`: default ledger id\n- `currency_denominations`: mapping from ledger id to currency denomination\n- `default_connection`: public id to the default connection\n- `default_routing`: dictionary for default routing.\n- `connection_ids`: active connection ids. Default: consider all the ones in the resources.\n- `search_service_address`: the address of the search service used.\n- `storage_uri`: optional uri to set generic storage\n- `task_manager_mode`: task manager mode (threaded) to run tasks with.\n- `kwargs`: keyword arguments to be attached in the agent context namespace.\n\n<a id=\"aea.aea.AEA.get_build_dir\"></a>\n\n#### get`_`build`_`dir\n\n```python\n@classmethod\ndef get_build_dir(cls) -> str\n```\n\nGet agent build directory.\n\n<a id=\"aea.aea.AEA.context\"></a>\n\n#### context\n\n```python\n@property\ndef context() -> AgentContext\n```\n\nGet (agent) context.\n\n<a id=\"aea.aea.AEA.resources\"></a>\n\n#### resources\n\n```python\n@property\ndef resources() -> Resources\n```\n\nGet resources.\n\n<a id=\"aea.aea.AEA.resources\"></a>\n\n#### resources\n\n```python\n@resources.setter\ndef resources(resources: \"Resources\") -> None\n```\n\nSet resources.\n\n<a id=\"aea.aea.AEA.filter\"></a>\n\n#### filter\n\n```python\n@property\ndef filter() -> Filter\n```\n\nGet the filter.\n\n<a id=\"aea.aea.AEA.active_behaviours\"></a>\n\n#### active`_`behaviours\n\n```python\n@property\ndef active_behaviours() -> List[Behaviour]\n```\n\nGet all active behaviours to use in act.\n\n<a id=\"aea.aea.AEA.setup\"></a>\n\n#### setup\n\n```python\ndef setup() -> None\n```\n\nSet up the agent.\n\nCalls setup() on the resources.\n\n<a id=\"aea.aea.AEA.act\"></a>\n\n#### act\n\n```python\ndef act() -> None\n```\n\nPerform actions.\n\nAdds new handlers and behaviours for use/execution by the runtime.\n\n<a id=\"aea.aea.AEA.handle_envelope\"></a>\n\n#### handle`_`envelope\n\n```python\ndef handle_envelope(envelope: Envelope) -> None\n```\n\nHandle an envelope.\n\nPerforms the following:\n\n- fetching the protocol referenced by the envelope, and\n- handling if the protocol is unsupported, using the error handler, or\n- handling if there is a decoding error, using the error handler, or\n- handling if no active handler is available for the specified protocol, using the error handler, or\n- handling the message recovered from the envelope with all active handlers for the specified protocol.\n\n**Arguments**:\n\n- `envelope`: the envelope to handle.\n\n**Returns**:\n\nNone\n\n<a id=\"aea.aea.AEA.get_periodic_tasks\"></a>\n\n#### get`_`periodic`_`tasks\n\n```python\ndef get_periodic_tasks(\n) -> Dict[Callable, Tuple[float, Optional[datetime.datetime]]]\n```\n\nGet all periodic tasks for agent.\n\n**Returns**:\n\ndict of callable with period specified\n\n<a id=\"aea.aea.AEA.get_message_handlers\"></a>\n\n#### get`_`message`_`handlers\n\n```python\ndef get_message_handlers() -> List[Tuple[Callable[[Any], None], Callable]]\n```\n\nGet handlers with message getters.\n\n**Returns**:\n\nList of tuples of callables: handler and coroutine to get a message\n\n<a id=\"aea.aea.AEA.exception_handler\"></a>\n\n#### exception`_`handler\n\n```python\ndef exception_handler(exception: Exception, function: Callable) -> bool\n```\n\nHandle exception raised during agent main loop execution.\n\n**Arguments**:\n\n- `exception`: exception raised\n- `function`: a callable exception raised in.\n\n**Returns**:\n\nbool, propagate exception if True otherwise skip it.\n\n<a id=\"aea.aea.AEA.teardown\"></a>\n\n#### teardown\n\n```python\ndef teardown() -> None\n```\n\nTear down the agent.\n\nPerforms the following:\n\n- tears down the resources.\n\n<a id=\"aea.aea.AEA.get_task_result\"></a>\n\n#### get`_`task`_`result\n\n```python\ndef get_task_result(task_id: int) -> AsyncResult\n```\n\nGet the result from a task.\n\n**Arguments**:\n\n- `task_id`: the id of the task\n\n**Returns**:\n\nasync result for task_id\n\n<a id=\"aea.aea.AEA.enqueue_task\"></a>\n\n#### enqueue`_`task\n\n```python\ndef enqueue_task(func: Callable,\n                 args: Sequence = (),\n                 kwargs: Optional[Dict[str, Any]] = None) -> int\n```\n\nEnqueue a task with the task manager.\n\n**Arguments**:\n\n- `func`: the callable instance to be enqueued\n- `args`: the positional arguments to be passed to the function.\n- `kwargs`: the keyword arguments to be passed to the function.\n\n**Returns**:\n\nthe task id to get the the result.\n\n"
  },
  {
    "path": "docs/api/aea_builder.md",
    "content": "<a id=\"aea.aea_builder\"></a>\n\n# aea.aea`_`builder\n\nThis module contains utilities for building an AEA.\n\n<a id=\"aea.aea_builder._DependenciesManager\"></a>\n\n## `_`DependenciesManager Objects\n\n```python\nclass _DependenciesManager()\n```\n\nClass to manage dependencies of agent packages.\n\n<a id=\"aea.aea_builder._DependenciesManager.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__() -> None\n```\n\nInitialize the dependency graph.\n\n<a id=\"aea.aea_builder._DependenciesManager.all_dependencies\"></a>\n\n#### all`_`dependencies\n\n```python\n@property\ndef all_dependencies() -> Set[ComponentId]\n```\n\nGet all dependencies.\n\n<a id=\"aea.aea_builder._DependenciesManager.dependencies_highest_version\"></a>\n\n#### dependencies`_`highest`_`version\n\n```python\n@property\ndef dependencies_highest_version() -> Set[ComponentId]\n```\n\nGet the dependencies with highest version.\n\n<a id=\"aea.aea_builder._DependenciesManager.get_components_by_type\"></a>\n\n#### get`_`components`_`by`_`type\n\n```python\ndef get_components_by_type(\n    component_type: ComponentType\n) -> Dict[ComponentId, ComponentConfiguration]\n```\n\nGet the components by type.\n\n<a id=\"aea.aea_builder._DependenciesManager.protocols\"></a>\n\n#### protocols\n\n```python\n@property\ndef protocols() -> Dict[ComponentId, ProtocolConfig]\n```\n\nGet the protocols.\n\n<a id=\"aea.aea_builder._DependenciesManager.connections\"></a>\n\n#### connections\n\n```python\n@property\ndef connections() -> Dict[ComponentId, ConnectionConfig]\n```\n\nGet the connections.\n\n<a id=\"aea.aea_builder._DependenciesManager.skills\"></a>\n\n#### skills\n\n```python\n@property\ndef skills() -> Dict[ComponentId, SkillConfig]\n```\n\nGet the skills.\n\n<a id=\"aea.aea_builder._DependenciesManager.contracts\"></a>\n\n#### contracts\n\n```python\n@property\ndef contracts() -> Dict[ComponentId, ContractConfig]\n```\n\nGet the contracts.\n\n<a id=\"aea.aea_builder._DependenciesManager.add_component\"></a>\n\n#### add`_`component\n\n```python\ndef add_component(configuration: ComponentConfiguration) -> None\n```\n\nAdd a component to the dependency manager.\n\n**Arguments**:\n\n- `configuration`: the component configuration to add.\n\n<a id=\"aea.aea_builder._DependenciesManager.remove_component\"></a>\n\n#### remove`_`component\n\n```python\ndef remove_component(component_id: ComponentId) -> None\n```\n\nRemove a component.\n\n**Arguments**:\n\n- `component_id`: the component id\n\n**Raises**:\n\n- `ValueError`: if some component depends on this package.\n\n<a id=\"aea.aea_builder._DependenciesManager.pypi_dependencies\"></a>\n\n#### pypi`_`dependencies\n\n```python\n@property\ndef pypi_dependencies() -> Dependencies\n```\n\nGet all the PyPI dependencies.\n\nWe currently consider only dependency that have the\ndefault PyPI index url and that specify only the\nversion field.\n\n**Returns**:\n\nthe merged PyPI dependencies\n\n<a id=\"aea.aea_builder._DependenciesManager.install_dependencies\"></a>\n\n#### install`_`dependencies\n\n```python\ndef install_dependencies() -> None\n```\n\nInstall extra dependencies for components.\n\n<a id=\"aea.aea_builder.AEABuilder\"></a>\n\n## AEABuilder Objects\n\n```python\nclass AEABuilder(WithLogger)\n```\n\nThis class helps to build an AEA.\n\nIt follows the fluent interface. Every method of the builder\nreturns the instance of the builder itself.\n\nNote: the method 'build()' is guaranteed of being\nre-entrant with respect to the 'add_component(path)'\nmethod. That is, you can invoke the building method\nmany times against the same builder instance, and the\nreturned agent instance will not share the\ncomponents with other agents, e.g.:\n\nbuilder = AEABuilder()\nbuilder.add_component(...)\n...\n\n# first call\nmy_aea_1 = builder.build()\n\n# following agents will have different components.\nmy_aea_2 = builder.build()  # all good\n\nHowever, if you manually loaded some of the components and added\nthem with the method 'add_component_instance()', then calling build\nmore than one time is prevented:\n\nbuilder = AEABuilder()\nbuilder.add_component_instance(...)\n...  # other initialization code\n\n# first call\nmy_aea_1 = builder.build()\n\n# second call to `build()` would raise a Value Error.\n# call reset\nbuilder.reset()\n\n# re-add the component and private keys\nbuilder.add_component_instance(...)\n... # add private keys\n\n# second call\nmy_aea_2 = builder.builder()\n\n<a id=\"aea.aea_builder.AEABuilder.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(with_default_packages: bool = True,\n             registry_dir: str = DEFAULT_REGISTRY_NAME,\n             build_dir_root: Optional[str] = None) -> None\n```\n\nInitialize the builder.\n\n**Arguments**:\n\n- `with_default_packages`: add the default packages.\n- `registry_dir`: the registry directory.\n- `build_dir_root`: the root of the build directory.\n\n<a id=\"aea.aea_builder.AEABuilder.reset\"></a>\n\n#### reset\n\n```python\ndef reset(is_full_reset: bool = False) -> None\n```\n\nReset the builder.\n\nA full reset causes a reset of all data on the builder. A partial reset\nonly resets:\n    - name,\n    - private keys, and\n    - component instances\n\n**Arguments**:\n\n- `is_full_reset`: whether it is a full reset or not.\n\n<a id=\"aea.aea_builder.AEABuilder.set_period\"></a>\n\n#### set`_`period\n\n```python\ndef set_period(period: Optional[float]) -> \"AEABuilder\"\n```\n\nSet agent act period.\n\n**Arguments**:\n\n- `period`: period in seconds\n\n**Returns**:\n\nself\n\n<a id=\"aea.aea_builder.AEABuilder.set_execution_timeout\"></a>\n\n#### set`_`execution`_`timeout\n\n```python\ndef set_execution_timeout(execution_timeout: Optional[float]) -> \"AEABuilder\"\n```\n\nSet agent execution timeout in seconds.\n\n**Arguments**:\n\n- `execution_timeout`: execution_timeout in seconds\n\n**Returns**:\n\nself\n\n<a id=\"aea.aea_builder.AEABuilder.set_max_reactions\"></a>\n\n#### set`_`max`_`reactions\n\n```python\ndef set_max_reactions(max_reactions: Optional[int]) -> \"AEABuilder\"\n```\n\nSet agent max reaction in one react.\n\n**Arguments**:\n\n- `max_reactions`: int\n\n**Returns**:\n\nself\n\n<a id=\"aea.aea_builder.AEABuilder.set_decision_maker_handler_details\"></a>\n\n#### set`_`decision`_`maker`_`handler`_`details\n\n```python\ndef set_decision_maker_handler_details(decision_maker_handler_dotted_path: str,\n                                       file_path: str,\n                                       config: Dict[str, Any]) -> \"AEABuilder\"\n```\n\nSet error handler details.\n\n**Arguments**:\n\n- `decision_maker_handler_dotted_path`: the dotted path to the decision maker handler\n- `file_path`: the file path to the file which contains the decision maker handler\n- `config`: the configuration passed to the decision maker handler on instantiation\n\n**Returns**:\n\nself\n\n<a id=\"aea.aea_builder.AEABuilder.set_error_handler_details\"></a>\n\n#### set`_`error`_`handler`_`details\n\n```python\ndef set_error_handler_details(error_handler_dotted_path: str, file_path: str,\n                              config: Dict[str, Any]) -> \"AEABuilder\"\n```\n\nSet error handler details.\n\n**Arguments**:\n\n- `error_handler_dotted_path`: the dotted path to the error handler\n- `file_path`: the file path to the file which contains the error handler\n- `config`: the configuration passed to the error handler on instantiation\n\n**Returns**:\n\nself\n\n<a id=\"aea.aea_builder.AEABuilder.set_skill_exception_policy\"></a>\n\n#### set`_`skill`_`exception`_`policy\n\n```python\ndef set_skill_exception_policy(\n        skill_exception_policy: Optional[ExceptionPolicyEnum]) -> \"AEABuilder\"\n```\n\nSet skill exception policy.\n\n**Arguments**:\n\n- `skill_exception_policy`: the policy\n\n**Returns**:\n\nself\n\n<a id=\"aea.aea_builder.AEABuilder.set_connection_exception_policy\"></a>\n\n#### set`_`connection`_`exception`_`policy\n\n```python\ndef set_connection_exception_policy(\n    connection_exception_policy: Optional[ExceptionPolicyEnum]\n) -> \"AEABuilder\"\n```\n\nSet connection exception policy.\n\n**Arguments**:\n\n- `connection_exception_policy`: the policy\n\n**Returns**:\n\nself\n\n<a id=\"aea.aea_builder.AEABuilder.set_default_routing\"></a>\n\n#### set`_`default`_`routing\n\n```python\ndef set_default_routing(\n        default_routing: Dict[PublicId, PublicId]) -> \"AEABuilder\"\n```\n\nSet default routing.\n\nThis is a map from public ids (protocols) to public ids (connections).\n\n**Arguments**:\n\n- `default_routing`: the default routing mapping\n\n**Returns**:\n\nself\n\n<a id=\"aea.aea_builder.AEABuilder.set_loop_mode\"></a>\n\n#### set`_`loop`_`mode\n\n```python\ndef set_loop_mode(loop_mode: Optional[str]) -> \"AEABuilder\"\n```\n\nSet the loop mode.\n\n**Arguments**:\n\n- `loop_mode`: the agent loop mode\n\n**Returns**:\n\nself\n\n<a id=\"aea.aea_builder.AEABuilder.set_runtime_mode\"></a>\n\n#### set`_`runtime`_`mode\n\n```python\ndef set_runtime_mode(runtime_mode: Optional[str]) -> \"AEABuilder\"\n```\n\nSet the runtime mode.\n\n**Arguments**:\n\n- `runtime_mode`: the agent runtime mode\n\n**Returns**:\n\nself\n\n<a id=\"aea.aea_builder.AEABuilder.set_task_manager_mode\"></a>\n\n#### set`_`task`_`manager`_`mode\n\n```python\ndef set_task_manager_mode(task_manager_mode: Optional[str]) -> \"AEABuilder\"\n```\n\nSet the task_manager_mode.\n\n**Arguments**:\n\n- `task_manager_mode`: the agent task_manager_mode\n\n**Returns**:\n\nself\n\n<a id=\"aea.aea_builder.AEABuilder.set_storage_uri\"></a>\n\n#### set`_`storage`_`uri\n\n```python\ndef set_storage_uri(storage_uri: Optional[str]) -> \"AEABuilder\"\n```\n\nSet the storage uri.\n\n**Arguments**:\n\n- `storage_uri`: storage uri\n\n**Returns**:\n\nself\n\n<a id=\"aea.aea_builder.AEABuilder.set_data_dir\"></a>\n\n#### set`_`data`_`dir\n\n```python\ndef set_data_dir(data_dir: Optional[str]) -> \"AEABuilder\"\n```\n\nSet the data directory.\n\n**Arguments**:\n\n- `data_dir`: path to directory where to store data.\n\n**Returns**:\n\nself\n\n<a id=\"aea.aea_builder.AEABuilder.set_logging_config\"></a>\n\n#### set`_`logging`_`config\n\n```python\ndef set_logging_config(logging_config: Dict) -> \"AEABuilder\"\n```\n\nSet the logging configurations.\n\nThe dictionary must satisfy the following schema:\n\n  https://docs.python.org/3/library/logging.config.html#logging-config-dictschema\n\n**Arguments**:\n\n- `logging_config`: the logging configurations.\n\n**Returns**:\n\nself\n\n<a id=\"aea.aea_builder.AEABuilder.set_search_service_address\"></a>\n\n#### set`_`search`_`service`_`address\n\n```python\ndef set_search_service_address(search_service_address: str) -> \"AEABuilder\"\n```\n\nSet the search service address.\n\n**Arguments**:\n\n- `search_service_address`: the search service address\n\n**Returns**:\n\nself\n\n<a id=\"aea.aea_builder.AEABuilder.set_name\"></a>\n\n#### set`_`name\n\n```python\ndef set_name(name: str) -> \"AEABuilder\"\n```\n\nSet the name of the agent.\n\n**Arguments**:\n\n- `name`: the name of the agent.\n\n**Returns**:\n\nthe AEABuilder\n\n<a id=\"aea.aea_builder.AEABuilder.set_default_connection\"></a>\n\n#### set`_`default`_`connection\n\n```python\ndef set_default_connection(\n        public_id: Optional[PublicId] = None) -> \"AEABuilder\"\n```\n\nSet the default connection.\n\n**Arguments**:\n\n- `public_id`: the public id of the default connection package.\n\n**Returns**:\n\nthe AEABuilder\n\n<a id=\"aea.aea_builder.AEABuilder.add_private_key\"></a>\n\n#### add`_`private`_`key\n\n```python\ndef add_private_key(identifier: str,\n                    private_key_path: Optional[PathLike] = None,\n                    is_connection: bool = False) -> \"AEABuilder\"\n```\n\nAdd a private key path.\n\n**Arguments**:\n\n- `identifier`: the identifier for that private key path.\n- `private_key_path`: an (optional) path to the private key file.\nIf None, the key will be created at build time.\n- `is_connection`: if the pair is for the connection cryptos\n\n**Returns**:\n\nthe AEABuilder\n\n<a id=\"aea.aea_builder.AEABuilder.remove_private_key\"></a>\n\n#### remove`_`private`_`key\n\n```python\ndef remove_private_key(identifier: str,\n                       is_connection: bool = False) -> \"AEABuilder\"\n```\n\nRemove a private key path by identifier, if present.\n\n**Arguments**:\n\n- `identifier`: the identifier of the private key.\n- `is_connection`: if the pair is for the connection cryptos\n\n**Returns**:\n\nthe AEABuilder\n\n<a id=\"aea.aea_builder.AEABuilder.private_key_paths\"></a>\n\n#### private`_`key`_`paths\n\n```python\n@property\ndef private_key_paths() -> Dict[str, Optional[str]]\n```\n\nGet the private key paths.\n\n<a id=\"aea.aea_builder.AEABuilder.connection_private_key_paths\"></a>\n\n#### connection`_`private`_`key`_`paths\n\n```python\n@property\ndef connection_private_key_paths() -> Dict[str, Optional[str]]\n```\n\nGet the connection private key paths.\n\n<a id=\"aea.aea_builder.AEABuilder.set_default_ledger\"></a>\n\n#### set`_`default`_`ledger\n\n```python\ndef set_default_ledger(identifier: Optional[str]) -> \"AEABuilder\"\n```\n\nSet a default ledger API to use.\n\n**Arguments**:\n\n- `identifier`: the identifier of the ledger api\n\n**Returns**:\n\nthe AEABuilder\n\n<a id=\"aea.aea_builder.AEABuilder.set_required_ledgers\"></a>\n\n#### set`_`required`_`ledgers\n\n```python\ndef set_required_ledgers(\n        required_ledgers: Optional[List[str]]) -> \"AEABuilder\"\n```\n\nSet the required ledger identifiers.\n\nThese are the ledgers for which the AEA requires a key pair.\n\n**Arguments**:\n\n- `required_ledgers`: the required ledgers.\n\n**Returns**:\n\nthe AEABuilder.\n\n<a id=\"aea.aea_builder.AEABuilder.set_build_entrypoint\"></a>\n\n#### set`_`build`_`entrypoint\n\n```python\ndef set_build_entrypoint(build_entrypoint: Optional[str]) -> \"AEABuilder\"\n```\n\nSet build entrypoint.\n\n**Arguments**:\n\n- `build_entrypoint`: path to the builder script.\n\n**Returns**:\n\nthe AEABuilder\n\n<a id=\"aea.aea_builder.AEABuilder.set_currency_denominations\"></a>\n\n#### set`_`currency`_`denominations\n\n```python\ndef set_currency_denominations(\n        currency_denominations: Dict[str, str]) -> \"AEABuilder\"\n```\n\nSet the mapping from ledger ids to currency denominations.\n\n**Arguments**:\n\n- `currency_denominations`: the mapping\n\n**Returns**:\n\nthe AEABuilder\n\n<a id=\"aea.aea_builder.AEABuilder.add_component\"></a>\n\n#### add`_`component\n\n```python\ndef add_component(component_type: ComponentType,\n                  directory: PathLike,\n                  skip_consistency_check: bool = False) -> \"AEABuilder\"\n```\n\nAdd a component, given its type and the directory.\n\n**Arguments**:\n\n- `component_type`: the component type.\n- `directory`: the directory path.\n- `skip_consistency_check`: if True, the consistency check are skipped.\n\n**Raises**:\n\n- `AEAException`: if a component is already registered with the same component id.   # noqa: DAR402\n| or if there's a missing dependency.  # noqa: DAR402\n\n**Returns**:\n\nthe AEABuilder\n\n<a id=\"aea.aea_builder.AEABuilder.add_component_instance\"></a>\n\n#### add`_`component`_`instance\n\n```python\ndef add_component_instance(component: Component) -> \"AEABuilder\"\n```\n\nAdd already initialized component object to resources or connections.\n\nPlease, pay attention, all dependencies have to be already loaded.\n\nNotice also that this will make the call to 'build()' non re-entrant.\nYou will have to `reset()` the builder before calling `build()` again.\n\n**Arguments**:\n\n- `component`: Component instance already initialized.\n\n**Returns**:\n\nself\n\n<a id=\"aea.aea_builder.AEABuilder.set_context_namespace\"></a>\n\n#### set`_`context`_`namespace\n\n```python\ndef set_context_namespace(context_namespace: Dict[str, Any]) -> \"AEABuilder\"\n```\n\nSet the context namespace.\n\n<a id=\"aea.aea_builder.AEABuilder.set_agent_pypi_dependencies\"></a>\n\n#### set`_`agent`_`pypi`_`dependencies\n\n```python\ndef set_agent_pypi_dependencies(dependencies: Dependencies) -> \"AEABuilder\"\n```\n\nSet agent PyPI dependencies.\n\n**Arguments**:\n\n- `dependencies`: PyPI dependencies for the agent.\n\n**Returns**:\n\nthe AEABuilder.\n\n<a id=\"aea.aea_builder.AEABuilder.remove_component\"></a>\n\n#### remove`_`component\n\n```python\ndef remove_component(component_id: ComponentId) -> \"AEABuilder\"\n```\n\nRemove a component.\n\n**Arguments**:\n\n- `component_id`: the public id of the component.\n\n**Returns**:\n\nthe AEABuilder\n\n<a id=\"aea.aea_builder.AEABuilder.add_protocol\"></a>\n\n#### add`_`protocol\n\n```python\ndef add_protocol(directory: PathLike) -> \"AEABuilder\"\n```\n\nAdd a protocol to the agent.\n\n**Arguments**:\n\n- `directory`: the path to the protocol directory\n\n**Returns**:\n\nthe AEABuilder\n\n<a id=\"aea.aea_builder.AEABuilder.remove_protocol\"></a>\n\n#### remove`_`protocol\n\n```python\ndef remove_protocol(public_id: PublicId) -> \"AEABuilder\"\n```\n\nRemove protocol.\n\n**Arguments**:\n\n- `public_id`: the public id of the protocol\n\n**Returns**:\n\nthe AEABuilder\n\n<a id=\"aea.aea_builder.AEABuilder.add_connection\"></a>\n\n#### add`_`connection\n\n```python\ndef add_connection(directory: PathLike) -> \"AEABuilder\"\n```\n\nAdd a connection to the agent.\n\n**Arguments**:\n\n- `directory`: the path to the connection directory\n\n**Returns**:\n\nthe AEABuilder\n\n<a id=\"aea.aea_builder.AEABuilder.remove_connection\"></a>\n\n#### remove`_`connection\n\n```python\ndef remove_connection(public_id: PublicId) -> \"AEABuilder\"\n```\n\nRemove a connection.\n\n**Arguments**:\n\n- `public_id`: the public id of the connection\n\n**Returns**:\n\nthe AEABuilder\n\n<a id=\"aea.aea_builder.AEABuilder.add_skill\"></a>\n\n#### add`_`skill\n\n```python\ndef add_skill(directory: PathLike) -> \"AEABuilder\"\n```\n\nAdd a skill to the agent.\n\n**Arguments**:\n\n- `directory`: the path to the skill directory\n\n**Returns**:\n\nthe AEABuilder\n\n<a id=\"aea.aea_builder.AEABuilder.remove_skill\"></a>\n\n#### remove`_`skill\n\n```python\ndef remove_skill(public_id: PublicId) -> \"AEABuilder\"\n```\n\nRemove protocol.\n\n**Arguments**:\n\n- `public_id`: the public id of the skill\n\n**Returns**:\n\nthe AEABuilder\n\n<a id=\"aea.aea_builder.AEABuilder.add_contract\"></a>\n\n#### add`_`contract\n\n```python\ndef add_contract(directory: PathLike) -> \"AEABuilder\"\n```\n\nAdd a contract to the agent.\n\n**Arguments**:\n\n- `directory`: the path to the contract directory\n\n**Returns**:\n\nthe AEABuilder\n\n<a id=\"aea.aea_builder.AEABuilder.remove_contract\"></a>\n\n#### remove`_`contract\n\n```python\ndef remove_contract(public_id: PublicId) -> \"AEABuilder\"\n```\n\nRemove protocol.\n\n**Arguments**:\n\n- `public_id`: the public id of the contract\n\n**Returns**:\n\nthe AEABuilder\n\n<a id=\"aea.aea_builder.AEABuilder.call_all_build_entrypoints\"></a>\n\n#### call`_`all`_`build`_`entrypoints\n\n```python\ndef call_all_build_entrypoints() -> None\n```\n\nCall all the build entrypoints.\n\n<a id=\"aea.aea_builder.AEABuilder.get_build_root_directory\"></a>\n\n#### get`_`build`_`root`_`directory\n\n```python\ndef get_build_root_directory() -> str\n```\n\nGet build directory root.\n\n<a id=\"aea.aea_builder.AEABuilder.run_build_for_component_configuration\"></a>\n\n#### run`_`build`_`for`_`component`_`configuration\n\n```python\n@classmethod\ndef run_build_for_component_configuration(\n        cls,\n        config: ComponentConfiguration,\n        logger: Optional[logging.Logger] = None) -> None\n```\n\nRun a build entrypoint script for component configuration.\n\n<a id=\"aea.aea_builder.AEABuilder.install_pypi_dependencies\"></a>\n\n#### install`_`pypi`_`dependencies\n\n```python\ndef install_pypi_dependencies() -> None\n```\n\nInstall components extra dependencies.\n\n<a id=\"aea.aea_builder.AEABuilder.build\"></a>\n\n#### build\n\n```python\ndef build(connection_ids: Optional[Collection[PublicId]] = None,\n          password: Optional[str] = None) -> AEA\n```\n\nBuild the AEA.\n\nThis method is re-entrant only if the components have been\nadded through the method 'add_component'. If some of them\nhave been loaded with 'add_component_instance', it\ncan be called only once, and further calls are only possible\nafter a call to 'reset' and re-loading of the components added\nvia 'add_component_instance' and the private keys.\n\n**Arguments**:\n\n- `connection_ids`: select only these connections to run the AEA.\n- `password`: the password to encrypt/decrypt the private key.\n\n**Returns**:\n\nthe AEA object.\n\n<a id=\"aea.aea_builder.AEABuilder.get_default_ledger\"></a>\n\n#### get`_`default`_`ledger\n\n```python\ndef get_default_ledger() -> str\n```\n\nReturn default ledger.\n\n**Returns**:\n\nthe default ledger identifier.\n\n<a id=\"aea.aea_builder.AEABuilder.get_required_ledgers\"></a>\n\n#### get`_`required`_`ledgers\n\n```python\ndef get_required_ledgers() -> List[str]\n```\n\nGet the required ledger identifiers.\n\nThese are the ledgers for which the AEA requires a key pair.\n\n**Returns**:\n\nthe list of required ledgers.\n\n<a id=\"aea.aea_builder.AEABuilder.try_to_load_agent_configuration_file\"></a>\n\n#### try`_`to`_`load`_`agent`_`configuration`_`file\n\n```python\n@classmethod\ndef try_to_load_agent_configuration_file(\n        cls, aea_project_path: Union[str, Path]) -> AgentConfig\n```\n\nTry to load the agent configuration file..\n\n<a id=\"aea.aea_builder.AEABuilder.set_from_configuration\"></a>\n\n#### set`_`from`_`configuration\n\n```python\ndef set_from_configuration(agent_configuration: AgentConfig,\n                           aea_project_path: Path,\n                           skip_consistency_check: bool = False) -> None\n```\n\nSet builder variables from AgentConfig.\n\n**Arguments**:\n\n- `agent_configuration`: AgentConfig to get values from.\n- `aea_project_path`: PathLike root directory of the agent project.\n- `skip_consistency_check`: if True, the consistency check are skipped.\n\n<a id=\"aea.aea_builder.AEABuilder.from_aea_project\"></a>\n\n#### from`_`aea`_`project\n\n```python\n@classmethod\ndef from_aea_project(cls,\n                     aea_project_path: PathLike,\n                     skip_consistency_check: bool = False,\n                     password: Optional[str] = None) -> \"AEABuilder\"\n```\n\nConstruct the builder from an AEA project.\n\n- load agent configuration file\n- set name and default configurations\n- load private keys\n- load ledger API configurations\n- set default ledger\n- load every component\n\n**Arguments**:\n\n- `aea_project_path`: path to the AEA project.\n- `skip_consistency_check`: if True, the consistency check are skipped.\n- `password`: the password to encrypt/decrypt private keys.\n\n**Returns**:\n\nan AEABuilder.\n\n<a id=\"aea.aea_builder.AEABuilder.get_configuration_file_path\"></a>\n\n#### get`_`configuration`_`file`_`path\n\n```python\n@staticmethod\ndef get_configuration_file_path(aea_project_path: Union[Path, str]) -> Path\n```\n\nReturn path to aea-config file for the given aea project path.\n\n<a id=\"aea.aea_builder.make_component_logger\"></a>\n\n#### make`_`component`_`logger\n\n```python\ndef make_component_logger(configuration: ComponentConfiguration,\n                          agent_name: str) -> Optional[logging.Logger]\n```\n\nMake the logger for a component.\n\n**Arguments**:\n\n- `configuration`: the component configuration\n- `agent_name`: the agent name\n\n**Returns**:\n\nthe logger.\n\n"
  },
  {
    "path": "docs/api/agent.md",
    "content": "<a id=\"aea.agent\"></a>\n\n# aea.agent\n\nThis module contains the implementation of a generic agent.\n\n<a id=\"aea.agent.Agent\"></a>\n\n## Agent Objects\n\n```python\nclass Agent(AbstractAgent, WithLogger)\n```\n\nThis class provides an abstract base class for a generic agent.\n\n<a id=\"aea.agent.Agent.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(identity: Identity,\n             connections: List[Connection],\n             loop: Optional[AbstractEventLoop] = None,\n             period: float = 1.0,\n             loop_mode: Optional[str] = None,\n             runtime_mode: Optional[str] = None,\n             storage_uri: Optional[str] = None,\n             logger: Logger = _default_logger,\n             task_manager_mode: Optional[str] = None) -> None\n```\n\nInstantiate the agent.\n\n**Arguments**:\n\n- `identity`: the identity of the agent.\n- `connections`: the list of connections of the agent.\n- `loop`: the event loop to run the connections.\n- `period`: period to call agent's act\n- `loop_mode`: loop_mode to choose agent run loop.\n- `runtime_mode`: runtime mode to up agent.\n- `storage_uri`: optional uri to set generic storage\n- `task_manager_mode`: task manager mode.\n- `logger`: the logger.\n- `task_manager_mode`: mode of the task manager.\n\n<a id=\"aea.agent.Agent.storage_uri\"></a>\n\n#### storage`_`uri\n\n```python\n@property\ndef storage_uri() -> Optional[str]\n```\n\nReturn storage uri.\n\n<a id=\"aea.agent.Agent.is_running\"></a>\n\n#### is`_`running\n\n```python\n@property\ndef is_running() -> bool\n```\n\nGet running state of the runtime and agent.\n\n<a id=\"aea.agent.Agent.is_stopped\"></a>\n\n#### is`_`stopped\n\n```python\n@property\ndef is_stopped() -> bool\n```\n\nGet running state of the runtime and agent.\n\n<a id=\"aea.agent.Agent.identity\"></a>\n\n#### identity\n\n```python\n@property\ndef identity() -> Identity\n```\n\nGet the identity.\n\n<a id=\"aea.agent.Agent.inbox\"></a>\n\n#### inbox\n\n```python\n@property\ndef inbox() -> InBox\n```\n\nGet the inbox.\n\nThe inbox contains Envelopes from the Multiplexer.\nThe agent can pick these messages for processing.\n\n**Returns**:\n\nInBox instance\n\n<a id=\"aea.agent.Agent.outbox\"></a>\n\n#### outbox\n\n```python\n@property\ndef outbox() -> OutBox\n```\n\nGet the outbox.\n\nThe outbox contains Envelopes for the Multiplexer.\nEnvelopes placed in the Outbox are processed by the Multiplexer.\n\n**Returns**:\n\nOutBox instance\n\n<a id=\"aea.agent.Agent.name\"></a>\n\n#### name\n\n```python\n@property\ndef name() -> str\n```\n\nGet the agent name.\n\n<a id=\"aea.agent.Agent.tick\"></a>\n\n#### tick\n\n```python\n@property\ndef tick() -> int\n```\n\nGet the tick or agent loop count.\n\nEach agent loop (one call to each one of act(), react(), update()) increments the tick.\n\n**Returns**:\n\ntick count\n\n<a id=\"aea.agent.Agent.state\"></a>\n\n#### state\n\n```python\n@property\ndef state() -> RuntimeStates\n```\n\nGet state of the agent's runtime.\n\n**Returns**:\n\nRuntimeStates\n\n<a id=\"aea.agent.Agent.period\"></a>\n\n#### period\n\n```python\n@property\ndef period() -> float\n```\n\nGet a period to call act.\n\n<a id=\"aea.agent.Agent.runtime\"></a>\n\n#### runtime\n\n```python\n@property\ndef runtime() -> BaseRuntime\n```\n\nGet the runtime.\n\n<a id=\"aea.agent.Agent.setup\"></a>\n\n#### setup\n\n```python\ndef setup() -> None\n```\n\nSet up the agent.\n\n<a id=\"aea.agent.Agent.start\"></a>\n\n#### start\n\n```python\ndef start() -> None\n```\n\nStart the agent.\n\nPerforms the following:\n\n- calls start() on runtime.\n- waits for runtime to complete running (blocking)\n\n<a id=\"aea.agent.Agent.handle_envelope\"></a>\n\n#### handle`_`envelope\n\n```python\ndef handle_envelope(envelope: Envelope) -> None\n```\n\nHandle an envelope.\n\n**Arguments**:\n\n- `envelope`: the envelope to handle.\n\n<a id=\"aea.agent.Agent.act\"></a>\n\n#### act\n\n```python\ndef act() -> None\n```\n\nPerform actions on period.\n\n<a id=\"aea.agent.Agent.stop\"></a>\n\n#### stop\n\n```python\ndef stop() -> None\n```\n\nStop the agent.\n\nPerforms the following:\n\n- calls stop() on runtime\n- waits for runtime to stop (blocking)\n\n<a id=\"aea.agent.Agent.teardown\"></a>\n\n#### teardown\n\n```python\ndef teardown() -> None\n```\n\nTear down the agent.\n\n<a id=\"aea.agent.Agent.get_periodic_tasks\"></a>\n\n#### get`_`periodic`_`tasks\n\n```python\ndef get_periodic_tasks(\n) -> Dict[Callable, Tuple[float, Optional[datetime.datetime]]]\n```\n\nGet all periodic tasks for agent.\n\n**Returns**:\n\ndict of callable with period specified\n\n<a id=\"aea.agent.Agent.get_message_handlers\"></a>\n\n#### get`_`message`_`handlers\n\n```python\ndef get_message_handlers() -> List[Tuple[Callable[[Any], None], Callable]]\n```\n\nGet handlers with message getters.\n\n**Returns**:\n\nList of tuples of callables: handler and coroutine to get a message\n\n<a id=\"aea.agent.Agent.exception_handler\"></a>\n\n#### exception`_`handler\n\n```python\ndef exception_handler(exception: Exception, function: Callable) -> bool\n```\n\nHandle exception raised during agent main loop execution.\n\n**Arguments**:\n\n- `exception`: exception raised\n- `function`: a callable exception raised in.\n\n**Returns**:\n\nbool, propagate exception if True otherwise skip it.\n\n"
  },
  {
    "path": "docs/api/agent_loop.md",
    "content": "<a id=\"aea.agent_loop\"></a>\n\n# aea.agent`_`loop\n\nThis module contains the implementation of an agent loop using asyncio.\n\n<a id=\"aea.agent_loop.AgentLoopException\"></a>\n\n## AgentLoopException Objects\n\n```python\nclass AgentLoopException(AEAException)\n```\n\nException for agent loop runtime errors.\n\n<a id=\"aea.agent_loop.AgentLoopStates\"></a>\n\n## AgentLoopStates Objects\n\n```python\nclass AgentLoopStates(Enum)\n```\n\nInternal agent loop states.\n\n<a id=\"aea.agent_loop.BaseAgentLoop\"></a>\n\n## BaseAgentLoop Objects\n\n```python\nclass BaseAgentLoop(Runnable, WithLogger, ABC)\n```\n\nBase abstract  agent loop class.\n\n<a id=\"aea.agent_loop.BaseAgentLoop.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(agent: AbstractAgent,\n             loop: Optional[AbstractEventLoop] = None,\n             threaded: bool = False) -> None\n```\n\nInit loop.\n\n**Arguments**:\n\n- `agent`: Agent or AEA to run.\n- `loop`: optional asyncio event loop. if not specified a new loop will be created.\n- `threaded`: if True, run in threaded mode, else async\n\n<a id=\"aea.agent_loop.BaseAgentLoop.agent\"></a>\n\n#### agent\n\n```python\n@property\ndef agent() -> AbstractAgent\n```\n\nGet agent.\n\n<a id=\"aea.agent_loop.BaseAgentLoop.state\"></a>\n\n#### state\n\n```python\n@property\ndef state() -> AgentLoopStates\n```\n\nGet current main loop state.\n\n<a id=\"aea.agent_loop.BaseAgentLoop.wait_state\"></a>\n\n#### wait`_`state\n\n```python\nasync def wait_state(\n        state_or_states: Union[Any, Sequence[Any]]) -> Tuple[Any, Any]\n```\n\nWait state to be set.\n\n**Arguments**:\n\n- `state_or_states`: state or list of states.\n\n**Returns**:\n\ntuple of previous state and new state.\n\n<a id=\"aea.agent_loop.BaseAgentLoop.is_running\"></a>\n\n#### is`_`running\n\n```python\n@property\ndef is_running() -> bool\n```\n\nGet running state of the loop.\n\n<a id=\"aea.agent_loop.BaseAgentLoop.set_loop\"></a>\n\n#### set`_`loop\n\n```python\ndef set_loop(loop: AbstractEventLoop) -> None\n```\n\nSet event loop and all event loop related objects.\n\n<a id=\"aea.agent_loop.BaseAgentLoop.run\"></a>\n\n#### run\n\n```python\nasync def run() -> None\n```\n\nRun agent loop.\n\n<a id=\"aea.agent_loop.BaseAgentLoop.send_to_skill\"></a>\n\n#### send`_`to`_`skill\n\n```python\n@abstractmethod\ndef send_to_skill(message_or_envelope: Union[Message, Envelope],\n                  context: Optional[EnvelopeContext] = None) -> None\n```\n\nSend message or envelope to another skill.\n\nIf message passed it will be wrapped into envelope with optional envelope context.\n\n**Arguments**:\n\n- `message_or_envelope`: envelope to send to another skill.\n- `context`: envelope context\n\n<a id=\"aea.agent_loop.BaseAgentLoop.skill2skill_queue\"></a>\n\n#### skill2skill`_`queue\n\n```python\n@property\n@abstractmethod\ndef skill2skill_queue() -> Queue\n```\n\nGet skill to skill message queue.\n\n<a id=\"aea.agent_loop.AsyncAgentLoop\"></a>\n\n## AsyncAgentLoop Objects\n\n```python\nclass AsyncAgentLoop(BaseAgentLoop)\n```\n\nAsyncio based agent loop suitable only for AEA.\n\n<a id=\"aea.agent_loop.AsyncAgentLoop.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(agent: AbstractAgent,\n             loop: AbstractEventLoop = None,\n             threaded: bool = False) -> None\n```\n\nInit agent loop.\n\n**Arguments**:\n\n- `agent`: AEA instance\n- `loop`: asyncio loop to use. optional\n- `threaded`: is a new thread to be started for the agent loop\n\n<a id=\"aea.agent_loop.AsyncAgentLoop.skill2skill_queue\"></a>\n\n#### skill2skill`_`queue\n\n```python\n@property\ndef skill2skill_queue() -> Queue\n```\n\nGet skill to skill message queue.\n\n<a id=\"aea.agent_loop.AsyncAgentLoop.send_to_skill\"></a>\n\n#### send`_`to`_`skill\n\n```python\ndef send_to_skill(message_or_envelope: Union[Message, Envelope],\n                  context: Optional[EnvelopeContext] = None) -> None\n```\n\nSend message or envelope to another skill.\n\nIf message passed it will be wrapped into envelope with optional envelope context.\n\n**Arguments**:\n\n- `message_or_envelope`: envelope to send to another skill.\n- `context`: envelope context\n\n"
  },
  {
    "path": "docs/api/common.md",
    "content": "<a id=\"aea.common\"></a>\n\n# aea.common\n\nThis module contains the common types and interfaces used in the aea framework.\n\n"
  },
  {
    "path": "docs/api/components/base.md",
    "content": "<a id=\"aea.components.base\"></a>\n\n# aea.components.base\n\nThis module contains definitions of agent components.\n\n<a id=\"aea.components.base.Component\"></a>\n\n## Component Objects\n\n```python\nclass Component(ABC, WithLogger)\n```\n\nAbstract class for an agent component.\n\n<a id=\"aea.components.base.Component.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(configuration: Optional[ComponentConfiguration] = None,\n             is_vendor: bool = False,\n             **kwargs: Any) -> None\n```\n\nInitialize a package.\n\n**Arguments**:\n\n- `configuration`: the package configuration.\n- `is_vendor`: whether the package is vendorized.\n- `kwargs`: the keyword arguments for the logger.\n\n<a id=\"aea.components.base.Component.component_type\"></a>\n\n#### component`_`type\n\n```python\n@property\ndef component_type() -> ComponentType\n```\n\nGet the component type.\n\n<a id=\"aea.components.base.Component.is_vendor\"></a>\n\n#### is`_`vendor\n\n```python\n@property\ndef is_vendor() -> bool\n```\n\nGet whether the component is vendorized or not.\n\n<a id=\"aea.components.base.Component.prefix_import_path\"></a>\n\n#### prefix`_`import`_`path\n\n```python\n@property\ndef prefix_import_path() -> str\n```\n\nGet the prefix import path for this component.\n\n<a id=\"aea.components.base.Component.component_id\"></a>\n\n#### component`_`id\n\n```python\n@property\ndef component_id() -> ComponentId\n```\n\nGe the package id.\n\n<a id=\"aea.components.base.Component.public_id\"></a>\n\n#### public`_`id\n\n```python\n@property\ndef public_id() -> PublicId\n```\n\nGet the public id.\n\n<a id=\"aea.components.base.Component.configuration\"></a>\n\n#### configuration\n\n```python\n@property\ndef configuration() -> ComponentConfiguration\n```\n\nGet the component configuration.\n\n<a id=\"aea.components.base.Component.directory\"></a>\n\n#### directory\n\n```python\n@property\ndef directory() -> Path\n```\n\nGet the directory. Raise error if it has not been set yet.\n\n<a id=\"aea.components.base.Component.directory\"></a>\n\n#### directory\n\n```python\n@directory.setter\ndef directory(path: Path) -> None\n```\n\nSet the directory. Raise error if already set.\n\n<a id=\"aea.components.base.Component.build_directory\"></a>\n\n#### build`_`directory\n\n```python\n@property\ndef build_directory() -> Optional[str]\n```\n\nGet build directory for the component.\n\n<a id=\"aea.components.base.load_aea_package\"></a>\n\n#### load`_`aea`_`package\n\n```python\ndef load_aea_package(configuration: ComponentConfiguration) -> None\n```\n\nLoad the AEA package from configuration.\n\nIt adds all the __init__.py modules into `sys.modules`.\n\n**Arguments**:\n\n- `configuration`: the configuration object.\n\n<a id=\"aea.components.base.perform_load_aea_package\"></a>\n\n#### perform`_`load`_`aea`_`package\n\n```python\ndef perform_load_aea_package(dir_: Path, author: str, package_type_plural: str,\n                             package_name: str) -> None\n```\n\nLoad the AEA package from values provided.\n\nIt adds all the __init__.py modules into `sys.modules`.\n\n**Arguments**:\n\n- `dir_`: path of the component.\n- `author`: str\n- `package_type_plural`: str\n- `package_name`: str\n\n"
  },
  {
    "path": "docs/api/components/loader.md",
    "content": "<a id=\"aea.components.loader\"></a>\n\n# aea.components.loader\n\nThis module contains utilities for loading components.\n\n<a id=\"aea.components.loader.component_type_to_class\"></a>\n\n#### component`_`type`_`to`_`class\n\n```python\ndef component_type_to_class(component_type: ComponentType) -> Type[Component]\n```\n\nGet the component class from the component type.\n\n**Arguments**:\n\n- `component_type`: the component type\n\n**Returns**:\n\nthe component class\n\n<a id=\"aea.components.loader.load_component_from_config\"></a>\n\n#### load`_`component`_`from`_`config\n\n```python\ndef load_component_from_config(configuration: ComponentConfiguration, *args,\n                               **kwargs) -> Component\n```\n\nLoad a component from a directory.\n\n**Arguments**:\n\n- `configuration`: the component configuration.\n- `args`: the positional arguments.\n- `kwargs`: the keyword arguments.\n\n**Returns**:\n\nthe component instance.\n\n<a id=\"aea.components.loader.AEAPackageNotFound\"></a>\n\n## AEAPackageNotFound Objects\n\n```python\nclass AEAPackageNotFound(Exception)\n```\n\nException when failed to import package, cause not exists.\n\n"
  },
  {
    "path": "docs/api/components/utils.md",
    "content": "<a id=\"aea.components.utils\"></a>\n\n# aea.components.utils\n\nThis module contains the component loading utils.\n\n"
  },
  {
    "path": "docs/api/configurations/base.md",
    "content": ""
  },
  {
    "path": "docs/api/configurations/constants.md",
    "content": "<a id=\"aea.configurations.constants\"></a>\n\n# aea.configurations.constants\n\nModule to declare constants.\n\n"
  },
  {
    "path": "docs/api/configurations/data_types.md",
    "content": "<a id=\"aea.configurations.data_types\"></a>\n\n# aea.configurations.data`_`types\n\nBase config data types.\n\n<a id=\"aea.configurations.data_types.JSONSerializable\"></a>\n\n## JSONSerializable Objects\n\n```python\nclass JSONSerializable(ABC)\n```\n\nInterface for JSON-serializable objects.\n\n<a id=\"aea.configurations.data_types.JSONSerializable.json\"></a>\n\n#### json\n\n```python\n@property\n@abstractmethod\ndef json() -> Dict\n```\n\nCompute the JSON representation.\n\n<a id=\"aea.configurations.data_types.JSONSerializable.from_json\"></a>\n\n#### from`_`json\n\n```python\n@classmethod\n@abstractmethod\ndef from_json(cls, obj: Dict) -> \"JSONSerializable\"\n```\n\nBuild from a JSON object.\n\n<a id=\"aea.configurations.data_types.PackageVersion\"></a>\n\n## PackageVersion Objects\n\n```python\n@functools.total_ordering\nclass PackageVersion()\n```\n\nA package version.\n\n<a id=\"aea.configurations.data_types.PackageVersion.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(version_like: PackageVersionLike) -> None\n```\n\nInitialize a package version.\n\n**Arguments**:\n\n- `version_like`: a string, os a semver.VersionInfo object.\n\n<a id=\"aea.configurations.data_types.PackageVersion.is_latest\"></a>\n\n#### is`_`latest\n\n```python\n@property\ndef is_latest() -> bool\n```\n\nCheck whether the version is 'latest'.\n\n<a id=\"aea.configurations.data_types.PackageVersion.__str__\"></a>\n\n#### `__`str`__`\n\n```python\ndef __str__() -> str\n```\n\nGet the string representation.\n\n<a id=\"aea.configurations.data_types.PackageVersion.__eq__\"></a>\n\n#### `__`eq`__`\n\n```python\ndef __eq__(other: Any) -> bool\n```\n\nCheck equality.\n\n<a id=\"aea.configurations.data_types.PackageVersion.__lt__\"></a>\n\n#### `__`lt`__`\n\n```python\ndef __lt__(other: Any) -> bool\n```\n\nCompare with another object.\n\n<a id=\"aea.configurations.data_types.PackageType\"></a>\n\n## PackageType Objects\n\n```python\nclass PackageType(Enum)\n```\n\nPackage types.\n\n<a id=\"aea.configurations.data_types.PackageType.to_plural\"></a>\n\n#### to`_`plural\n\n```python\ndef to_plural() -> str\n```\n\nGet the plural name.\n\n>>> PackageType.AGENT.to_plural()\n'agents'\n>>> PackageType.PROTOCOL.to_plural()\n'protocols'\n>>> PackageType.CONNECTION.to_plural()\n'connections'\n>>> PackageType.SKILL.to_plural()\n'skills'\n>>> PackageType.CONTRACT.to_plural()\n'contracts'\n\n**Returns**:\n\npluralised package type\n\n<a id=\"aea.configurations.data_types.PackageType.__str__\"></a>\n\n#### `__`str`__`\n\n```python\ndef __str__() -> str\n```\n\nConvert to string.\n\n<a id=\"aea.configurations.data_types.ComponentType\"></a>\n\n## ComponentType Objects\n\n```python\nclass ComponentType(Enum)\n```\n\nEnum of component types supported.\n\n<a id=\"aea.configurations.data_types.ComponentType.to_package_type\"></a>\n\n#### to`_`package`_`type\n\n```python\ndef to_package_type() -> PackageType\n```\n\nGet package type for component type.\n\n<a id=\"aea.configurations.data_types.ComponentType.plurals\"></a>\n\n#### plurals\n\n```python\n@staticmethod\ndef plurals() -> Collection[str]\n```\n\nGet the collection of type names, plural.\n\n>>> ComponentType.plurals()\n['protocols', 'connections', 'skills', 'contracts']\n\n**Returns**:\n\nlist of all pluralised component types\n\n<a id=\"aea.configurations.data_types.ComponentType.to_plural\"></a>\n\n#### to`_`plural\n\n```python\ndef to_plural() -> str\n```\n\nGet the plural version of the component type.\n\n>>> ComponentType.PROTOCOL.to_plural()\n'protocols'\n>>> ComponentType.CONNECTION.to_plural()\n'connections'\n>>> ComponentType.SKILL.to_plural()\n'skills'\n>>> ComponentType.CONTRACT.to_plural()\n'contracts'\n\n**Returns**:\n\npluralised component type\n\n<a id=\"aea.configurations.data_types.ComponentType.__str__\"></a>\n\n#### `__`str`__`\n\n```python\ndef __str__() -> str\n```\n\nGet the string representation.\n\n<a id=\"aea.configurations.data_types.PublicId\"></a>\n\n## PublicId Objects\n\n```python\nclass PublicId(JSONSerializable)\n```\n\nThis class implement a public identifier.\n\nA public identifier is composed of three elements:\n- author\n- name\n- version\n\nThe concatenation of those three elements gives the public identifier:\n\n    author/name:version\n\n>>> public_id = PublicId(\"author\", \"my_package\", \"0.1.0\")\n>>> assert public_id.author == \"author\"\n>>> assert public_id.name == \"my_package\"\n>>> assert public_id.version == \"0.1.0\"\n>>> another_public_id = PublicId(\"author\", \"my_package\", \"0.1.0\")\n>>> assert hash(public_id) == hash(another_public_id)\n>>> assert public_id == another_public_id\n>>> latest_public_id = PublicId(\"author\", \"my_package\", \"latest\")\n>>> latest_public_id\n<author/my_package:latest>\n>>> latest_public_id.package_version.is_latest\nTrue\n\n<a id=\"aea.configurations.data_types.PublicId.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(author: SimpleIdOrStr,\n             name: SimpleIdOrStr,\n             version: Optional[PackageVersionLike] = None) -> None\n```\n\nInitialize the public identifier.\n\n<a id=\"aea.configurations.data_types.PublicId.author\"></a>\n\n#### author\n\n```python\n@property\ndef author() -> str\n```\n\nGet the author.\n\n<a id=\"aea.configurations.data_types.PublicId.name\"></a>\n\n#### name\n\n```python\n@property\ndef name() -> str\n```\n\nGet the name.\n\n<a id=\"aea.configurations.data_types.PublicId.version\"></a>\n\n#### version\n\n```python\n@property\ndef version() -> str\n```\n\nGet the version string.\n\n<a id=\"aea.configurations.data_types.PublicId.package_version\"></a>\n\n#### package`_`version\n\n```python\n@property\ndef package_version() -> PackageVersion\n```\n\nGet the package version object.\n\n<a id=\"aea.configurations.data_types.PublicId.to_any\"></a>\n\n#### to`_`any\n\n```python\ndef to_any() -> \"PublicId\"\n```\n\nReturn the same public id, but with any version.\n\n<a id=\"aea.configurations.data_types.PublicId.same_prefix\"></a>\n\n#### same`_`prefix\n\n```python\ndef same_prefix(other: \"PublicId\") -> bool\n```\n\nCheck if the other public id has the same author and name of this.\n\n<a id=\"aea.configurations.data_types.PublicId.to_latest\"></a>\n\n#### to`_`latest\n\n```python\ndef to_latest() -> \"PublicId\"\n```\n\nReturn the same public id, but with latest version.\n\n<a id=\"aea.configurations.data_types.PublicId.is_valid_str\"></a>\n\n#### is`_`valid`_`str\n\n```python\n@classmethod\ndef is_valid_str(cls, public_id_string: str) -> bool\n```\n\nCheck if a string is a public id.\n\n**Arguments**:\n\n- `public_id_string`: the public id in string format.\n\n**Returns**:\n\nbool indicating validity\n\n<a id=\"aea.configurations.data_types.PublicId.from_str\"></a>\n\n#### from`_`str\n\n```python\n@classmethod\ndef from_str(cls, public_id_string: str) -> \"PublicId\"\n```\n\nInitialize the public id from the string.\n\n>>> str(PublicId.from_str(\"author/package_name:0.1.0\"))\n'author/package_name:0.1.0'\n\nA bad formatted input raises value error:\n>>> PublicId.from_str(\"bad/formatted:input\")\nTraceback (most recent call last):\n...\nValueError: Input 'bad/formatted:input' is not well formatted.\n\n**Arguments**:\n\n- `public_id_string`: the public id in string format.\n\n**Raises**:\n\n- `ValueError`: if the string in input is not well formatted.\n\n**Returns**:\n\nthe public id object.\n\n<a id=\"aea.configurations.data_types.PublicId.try_from_str\"></a>\n\n#### try`_`from`_`str\n\n```python\n@classmethod\ndef try_from_str(cls, public_id_string: str) -> Optional[\"PublicId\"]\n```\n\nSafely try to get public id from string.\n\n**Arguments**:\n\n- `public_id_string`: the public id in string format.\n\n**Returns**:\n\nthe public id object or None\n\n<a id=\"aea.configurations.data_types.PublicId.from_uri_path\"></a>\n\n#### from`_`uri`_`path\n\n```python\n@classmethod\ndef from_uri_path(cls, public_id_uri_path: str) -> \"PublicId\"\n```\n\nInitialize the public id from the string.\n\n>>> str(PublicId.from_uri_path(\"author/package_name/0.1.0\"))\n'author/package_name:0.1.0'\n\nA bad formatted input raises value error:\n>>> PublicId.from_uri_path(\"bad/formatted:input\")\nTraceback (most recent call last):\n...\nValueError: Input 'bad/formatted:input' is not well formatted.\n\n**Arguments**:\n\n- `public_id_uri_path`: the public id in uri path string format.\n\n**Raises**:\n\n- `ValueError`: if the string in input is not well formatted.\n\n**Returns**:\n\nthe public id object.\n\n<a id=\"aea.configurations.data_types.PublicId.to_uri_path\"></a>\n\n#### to`_`uri`_`path\n\n```python\n@property\ndef to_uri_path() -> str\n```\n\nTurn the public id into a uri path string.\n\n**Returns**:\n\nuri path string\n\n<a id=\"aea.configurations.data_types.PublicId.json\"></a>\n\n#### json\n\n```python\n@property\ndef json() -> Dict\n```\n\nCompute the JSON representation.\n\n<a id=\"aea.configurations.data_types.PublicId.from_json\"></a>\n\n#### from`_`json\n\n```python\n@classmethod\ndef from_json(cls, obj: Dict) -> \"PublicId\"\n```\n\nBuild from a JSON object.\n\n<a id=\"aea.configurations.data_types.PublicId.__hash__\"></a>\n\n#### `__`hash`__`\n\n```python\ndef __hash__() -> int\n```\n\nGet the hash.\n\n<a id=\"aea.configurations.data_types.PublicId.__str__\"></a>\n\n#### `__`str`__`\n\n```python\ndef __str__() -> str\n```\n\nGet the string representation.\n\n<a id=\"aea.configurations.data_types.PublicId.__repr__\"></a>\n\n#### `__`repr`__`\n\n```python\ndef __repr__() -> str\n```\n\nGet the representation.\n\n<a id=\"aea.configurations.data_types.PublicId.__eq__\"></a>\n\n#### `__`eq`__`\n\n```python\ndef __eq__(other: Any) -> bool\n```\n\nCompare with another object.\n\n<a id=\"aea.configurations.data_types.PublicId.__lt__\"></a>\n\n#### `__`lt`__`\n\n```python\ndef __lt__(other: Any) -> bool\n```\n\nCompare two public ids.\n\n>>> public_id_1 = PublicId(\"author_1\", \"name_1\", \"0.1.0\")\n>>> public_id_2 = PublicId(\"author_1\", \"name_1\", \"0.1.1\")\n>>> public_id_3 = PublicId(\"author_1\", \"name_2\", \"0.1.0\")\n>>> public_id_1 > public_id_2\nFalse\n>>> public_id_1 < public_id_2\nTrue\n\n>>> public_id_1 < public_id_3\nTraceback (most recent call last):\n...\nValueError: The public IDs author_1/name_1:0.1.0 and author_1/name_2:0.1.0 cannot be compared. Their author or name attributes are different.\n\n**Arguments**:\n\n- `other`: the object to compate to\n\n**Raises**:\n\n- `ValueError`: if the public ids cannot be confirmed\n\n**Returns**:\n\nwhether or not the inequality is satisfied\n\n<a id=\"aea.configurations.data_types.PackageId\"></a>\n\n## PackageId Objects\n\n```python\nclass PackageId()\n```\n\nA package identifier.\n\n<a id=\"aea.configurations.data_types.PackageId.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(package_type: Union[PackageType, str],\n             public_id: PublicId) -> None\n```\n\nInitialize the package id.\n\n**Arguments**:\n\n- `package_type`: the package type.\n- `public_id`: the public id.\n\n<a id=\"aea.configurations.data_types.PackageId.package_type\"></a>\n\n#### package`_`type\n\n```python\n@property\ndef package_type() -> PackageType\n```\n\nGet the package type.\n\n<a id=\"aea.configurations.data_types.PackageId.public_id\"></a>\n\n#### public`_`id\n\n```python\n@property\ndef public_id() -> PublicId\n```\n\nGet the public id.\n\n<a id=\"aea.configurations.data_types.PackageId.author\"></a>\n\n#### author\n\n```python\n@property\ndef author() -> str\n```\n\nGet the author of the package.\n\n<a id=\"aea.configurations.data_types.PackageId.name\"></a>\n\n#### name\n\n```python\n@property\ndef name() -> str\n```\n\nGet the name of the package.\n\n<a id=\"aea.configurations.data_types.PackageId.version\"></a>\n\n#### version\n\n```python\n@property\ndef version() -> str\n```\n\nGet the version of the package.\n\n<a id=\"aea.configurations.data_types.PackageId.package_prefix\"></a>\n\n#### package`_`prefix\n\n```python\n@property\ndef package_prefix() -> Tuple[PackageType, str, str]\n```\n\nGet the package identifier without the version.\n\n<a id=\"aea.configurations.data_types.PackageId.from_uri_path\"></a>\n\n#### from`_`uri`_`path\n\n```python\n@classmethod\ndef from_uri_path(cls, package_id_uri_path: str) -> \"PackageId\"\n```\n\nInitialize the package id from the string.\n\n>>> str(PackageId.from_uri_path(\"skill/author/package_name/0.1.0\"))\n'(skill, author/package_name:0.1.0)'\n\nA bad formatted input raises value error:\n>>> PackageId.from_uri_path(\"very/bad/formatted:input\")\nTraceback (most recent call last):\n...\nValueError: Input 'very/bad/formatted:input' is not well formatted.\n\n**Arguments**:\n\n- `package_id_uri_path`: the package id in uri path string format.\n\n**Raises**:\n\n- `ValueError`: if the string in input is not well formatted.\n\n**Returns**:\n\nthe package id object.\n\n<a id=\"aea.configurations.data_types.PackageId.to_uri_path\"></a>\n\n#### to`_`uri`_`path\n\n```python\n@property\ndef to_uri_path() -> str\n```\n\nTurn the package id into a uri path string.\n\n**Returns**:\n\nuri path string\n\n<a id=\"aea.configurations.data_types.PackageId.__hash__\"></a>\n\n#### `__`hash`__`\n\n```python\ndef __hash__() -> int\n```\n\nGet the hash.\n\n<a id=\"aea.configurations.data_types.PackageId.__str__\"></a>\n\n#### `__`str`__`\n\n```python\ndef __str__() -> str\n```\n\nGet the string representation.\n\n<a id=\"aea.configurations.data_types.PackageId.__repr__\"></a>\n\n#### `__`repr`__`\n\n```python\ndef __repr__() -> str\n```\n\nGet the object representation in string.\n\n<a id=\"aea.configurations.data_types.PackageId.__eq__\"></a>\n\n#### `__`eq`__`\n\n```python\ndef __eq__(other: Any) -> bool\n```\n\nCompare with another object.\n\n<a id=\"aea.configurations.data_types.PackageId.__lt__\"></a>\n\n#### `__`lt`__`\n\n```python\ndef __lt__(other: Any) -> bool\n```\n\nCompare two public ids.\n\n<a id=\"aea.configurations.data_types.ComponentId\"></a>\n\n## ComponentId Objects\n\n```python\nclass ComponentId(PackageId)\n```\n\nClass to represent a component identifier.\n\nA component id is a package id, but excludes the case when the package is an agent.\n>>> pacakge_id = PackageId(PackageType.PROTOCOL, PublicId(\"author\", \"name\", \"0.1.0\"))\n>>> component_id = ComponentId(ComponentType.PROTOCOL, PublicId(\"author\", \"name\", \"0.1.0\"))\n>>> pacakge_id == component_id\nTrue\n\n>>> component_id2 = ComponentId(ComponentType.PROTOCOL, PublicId(\"author\", \"name\", \"0.1.1\"))\n>>> pacakge_id == component_id2\nFalse\n\n<a id=\"aea.configurations.data_types.ComponentId.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(component_type: Union[ComponentType, str],\n             public_id: PublicId) -> None\n```\n\nInitialize the component id.\n\n**Arguments**:\n\n- `component_type`: the component type.\n- `public_id`: the public id.\n\n<a id=\"aea.configurations.data_types.ComponentId.component_type\"></a>\n\n#### component`_`type\n\n```python\n@property\ndef component_type() -> ComponentType\n```\n\nGet the component type.\n\n<a id=\"aea.configurations.data_types.ComponentId.component_prefix\"></a>\n\n#### component`_`prefix\n\n```python\n@property\ndef component_prefix() -> PackageIdPrefix\n```\n\nGet the component identifier without the version.\n\n<a id=\"aea.configurations.data_types.ComponentId.same_prefix\"></a>\n\n#### same`_`prefix\n\n```python\ndef same_prefix(other: \"ComponentId\") -> bool\n```\n\nCheck if the other component id has the same type, author and name of this.\n\n<a id=\"aea.configurations.data_types.ComponentId.prefix_import_path\"></a>\n\n#### prefix`_`import`_`path\n\n```python\n@property\ndef prefix_import_path() -> str\n```\n\nGet the prefix import path for this component.\n\n<a id=\"aea.configurations.data_types.ComponentId.json\"></a>\n\n#### json\n\n```python\n@property\ndef json() -> Dict\n```\n\nGet the JSON representation.\n\n<a id=\"aea.configurations.data_types.ComponentId.from_json\"></a>\n\n#### from`_`json\n\n```python\n@classmethod\ndef from_json(cls, json_data: Dict) -> \"ComponentId\"\n```\n\nCreate  component id from json data.\n\n<a id=\"aea.configurations.data_types.PyPIPackageName\"></a>\n\n## PyPIPackageName Objects\n\n```python\nclass PyPIPackageName(RegexConstrainedString)\n```\n\nA PyPI Package name.\n\n<a id=\"aea.configurations.data_types.GitRef\"></a>\n\n## GitRef Objects\n\n```python\nclass GitRef(RegexConstrainedString)\n```\n\nA Git reference.\n\nIt can be a branch name, a commit hash or a tag.\n\n<a id=\"aea.configurations.data_types.Dependency\"></a>\n\n## Dependency Objects\n\n```python\nclass Dependency()\n```\n\nThis class represents a PyPI dependency.\n\nIt contains the following information:\n- version: a version specifier(s) (e.g. '==0.1.0').\n- index: the PyPI index where to download the package from (default: https://pypi.org)\n- git: the URL to the Git repository (e.g. https://github.com/fetchai/agents-aea.git)\n- ref: either the branch name, the tag, the commit number or a Git reference (default: 'master'.)\n\nIf the 'git' field is set, the 'version' field will be ignored.\nThese fields will be forwarded to the 'pip' command.\n\n<a id=\"aea.configurations.data_types.Dependency.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(name: Union[PyPIPackageName, str],\n             version: Union[str, SpecifierSet] = \"\",\n             index: Optional[str] = None,\n             git: Optional[str] = None,\n             ref: Optional[Union[GitRef, str]] = None) -> None\n```\n\nInitialize a PyPI dependency.\n\n**Arguments**:\n\n- `name`: the package name.\n- `version`: the specifier set object\n- `index`: the URL to the PyPI server.\n- `git`: the URL to a git repository.\n- `ref`: the Git reference (branch/commit/tag).\n\n<a id=\"aea.configurations.data_types.Dependency.name\"></a>\n\n#### name\n\n```python\n@property\ndef name() -> str\n```\n\nGet the name.\n\n<a id=\"aea.configurations.data_types.Dependency.version\"></a>\n\n#### version\n\n```python\n@property\ndef version() -> str\n```\n\nGet the version.\n\n<a id=\"aea.configurations.data_types.Dependency.index\"></a>\n\n#### index\n\n```python\n@property\ndef index() -> Optional[str]\n```\n\nGet the index.\n\n<a id=\"aea.configurations.data_types.Dependency.git\"></a>\n\n#### git\n\n```python\n@property\ndef git() -> Optional[str]\n```\n\nGet the git.\n\n<a id=\"aea.configurations.data_types.Dependency.ref\"></a>\n\n#### ref\n\n```python\n@property\ndef ref() -> Optional[str]\n```\n\nGet the ref.\n\n<a id=\"aea.configurations.data_types.Dependency.from_json\"></a>\n\n#### from`_`json\n\n```python\n@classmethod\ndef from_json(cls, obj: Dict[str, Dict[str, str]]) -> \"Dependency\"\n```\n\nParse a dependency object from a dictionary.\n\n<a id=\"aea.configurations.data_types.Dependency.to_json\"></a>\n\n#### to`_`json\n\n```python\ndef to_json() -> Dict[str, Dict[str, str]]\n```\n\nTransform the object to JSON.\n\n<a id=\"aea.configurations.data_types.Dependency.get_pip_install_args\"></a>\n\n#### get`_`pip`_`install`_`args\n\n```python\ndef get_pip_install_args() -> List[str]\n```\n\nGet 'pip install' arguments.\n\n<a id=\"aea.configurations.data_types.Dependency.__str__\"></a>\n\n#### `__`str`__`\n\n```python\ndef __str__() -> str\n```\n\nGet the string representation.\n\n<a id=\"aea.configurations.data_types.Dependency.__eq__\"></a>\n\n#### `__`eq`__`\n\n```python\ndef __eq__(other: Any) -> bool\n```\n\nCompare with another object.\n\n<a id=\"aea.configurations.data_types.Dependencies\"></a>\n\n#### Dependencies\n\nA dictionary from package name to dependency data structure (see above).\nThe package name must satisfy  <a href=\"https://www.python.org/dev/peps/pep-0426/`name`\">the constraints on Python packages names</a>.\n\nThe main advantage of having a dictionary is that we implicitly filter out dependency duplicates.\nWe cannot have two items with the same package name since the keys of a YAML object form a set.\n\n<a id=\"aea.configurations.data_types.CRUDCollection\"></a>\n\n## CRUDCollection Objects\n\n```python\nclass CRUDCollection(Generic[T])\n```\n\nInterface of a CRUD collection.\n\n<a id=\"aea.configurations.data_types.CRUDCollection.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__() -> None\n```\n\nInstantiate a CRUD collection.\n\n<a id=\"aea.configurations.data_types.CRUDCollection.create\"></a>\n\n#### create\n\n```python\ndef create(item_id: str, item: T) -> None\n```\n\nAdd an item.\n\n**Arguments**:\n\n- `item_id`: the item id.\n- `item`: the item to be added.\n\n**Raises**:\n\n- `ValueError`: if the item with the same id is already in the collection.\n\n<a id=\"aea.configurations.data_types.CRUDCollection.read\"></a>\n\n#### read\n\n```python\ndef read(item_id: str) -> Optional[T]\n```\n\nGet an item by its name.\n\n**Arguments**:\n\n- `item_id`: the item id.\n\n**Returns**:\n\nthe associated item, or None if the item id is not present.\n\n<a id=\"aea.configurations.data_types.CRUDCollection.update\"></a>\n\n#### update\n\n```python\ndef update(item_id: str, item: T) -> None\n```\n\nUpdate an existing item.\n\n**Arguments**:\n\n- `item_id`: the item id.\n- `item`: the item to be added.\n\n<a id=\"aea.configurations.data_types.CRUDCollection.delete\"></a>\n\n#### delete\n\n```python\ndef delete(item_id: str) -> None\n```\n\nDelete an item.\n\n<a id=\"aea.configurations.data_types.CRUDCollection.read_all\"></a>\n\n#### read`_`all\n\n```python\ndef read_all() -> List[Tuple[str, T]]\n```\n\nRead all the items.\n\n<a id=\"aea.configurations.data_types.CRUDCollection.keys\"></a>\n\n#### keys\n\n```python\ndef keys() -> Set[str]\n```\n\nGet the set of keys.\n\n"
  },
  {
    "path": "docs/api/configurations/loader.md",
    "content": ""
  },
  {
    "path": "docs/api/configurations/manager.md",
    "content": "<a id=\"aea.configurations.manager\"></a>\n\n# aea.configurations.manager\n\nImplementation of the AgentConfigManager.\n\n<a id=\"aea.configurations.manager.VariableDoesNotExist\"></a>\n\n## VariableDoesNotExist Objects\n\n```python\nclass VariableDoesNotExist(ValueError)\n```\n\nVariable does not exist in a config exception.\n\n<a id=\"aea.configurations.manager.handle_dotted_path\"></a>\n\n#### handle`_`dotted`_`path\n\n```python\ndef handle_dotted_path(\n    value: str,\n    author: str,\n    aea_project_path: Union[str, Path] = \".\"\n) -> Tuple[List[str], Path, ConfigLoader, Optional[ComponentId]]\n```\n\nSeparate the path between path to resource and json path to attribute.\n\nAllowed values:\n    'agent.an_attribute_name'\n    'protocols.my_protocol.an_attribute_name'\n    'connections.my_connection.an_attribute_name'\n    'contracts.my_contract.an_attribute_name'\n    'skills.my_skill.an_attribute_name'\n    'vendor.author.[protocols|contracts|connections|skills].package_name.attribute_name\n\nWe also return the component id to retrieve the configuration of a specific\ncomponent. Notice that at this point we don't know the version,\nso we put 'latest' as version, but later we will ignore it because\nwe will filter with only the component prefix (i.e. the triple type, author and name).\n\n**Arguments**:\n\n- `value`: dotted path.\n- `author`: the author string.\n- `aea_project_path`: project path\n\n**Returns**:\n\nTuple[list of settings dict keys, filepath, config loader, component id].\n\n<a id=\"aea.configurations.manager.find_component_directory_from_component_id\"></a>\n\n#### find`_`component`_`directory`_`from`_`component`_`id\n\n```python\ndef find_component_directory_from_component_id(\n        aea_project_directory: Path, component_id: ComponentId) -> Path\n```\n\nFind a component directory from component id.\n\n<a id=\"aea.configurations.manager.AgentConfigManager\"></a>\n\n## AgentConfigManager Objects\n\n```python\nclass AgentConfigManager()\n```\n\nAeaConfig manager.\n\n<a id=\"aea.configurations.manager.AgentConfigManager.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(agent_config: AgentConfig,\n             aea_project_directory: Union[str, Path],\n             env_vars_friendly: bool = False) -> None\n```\n\nInit manager.\n\n**Arguments**:\n\n- `agent_config`: AgentConfig to manage.\n- `aea_project_directory`: directory where project for agent_config placed.\n- `env_vars_friendly`: whether or not it is env vars friendly\n\n<a id=\"aea.configurations.manager.AgentConfigManager.load_component_configuration\"></a>\n\n#### load`_`component`_`configuration\n\n```python\ndef load_component_configuration(\n        component_id: ComponentId,\n        skip_consistency_check: bool = True) -> ComponentConfiguration\n```\n\nLoad component configuration from the project directory.\n\n**Arguments**:\n\n- `component_id`: Id of the component to load config for.\n- `skip_consistency_check`: bool.\n\n**Returns**:\n\nComponentConfiguration\n\n<a id=\"aea.configurations.manager.AgentConfigManager.agent_config_file_path\"></a>\n\n#### agent`_`config`_`file`_`path\n\n```python\n@property\ndef agent_config_file_path() -> Path\n```\n\nReturn agent config file path.\n\n<a id=\"aea.configurations.manager.AgentConfigManager.load\"></a>\n\n#### load\n\n```python\n@classmethod\ndef load(cls,\n         aea_project_path: Union[Path, str],\n         substitude_env_vars: bool = False) -> \"AgentConfigManager\"\n```\n\nCreate AgentConfigManager instance from agent project path.\n\n<a id=\"aea.configurations.manager.AgentConfigManager.set_variable\"></a>\n\n#### set`_`variable\n\n```python\ndef set_variable(path: VariablePath, value: JSON_TYPES) -> None\n```\n\nSet config variable.\n\n**Arguments**:\n\n- `path`: str dotted path  or List[Union[ComponentId, str]]\n- `value`: one of the json friendly objects.\n\n<a id=\"aea.configurations.manager.AgentConfigManager.get_variable\"></a>\n\n#### get`_`variable\n\n```python\ndef get_variable(path: VariablePath) -> JSON_TYPES\n```\n\nSet config variable.\n\n**Arguments**:\n\n- `path`: str dotted path or List[Union[ComponentId, str]]\n\n**Returns**:\n\njson friendly value.\n\n<a id=\"aea.configurations.manager.AgentConfigManager.update_config\"></a>\n\n#### update`_`config\n\n```python\ndef update_config(overrides: Dict) -> None\n```\n\nApply overrides for agent config.\n\nValidates and applies agent config and component overrides.\nDoes not save it on the disc!\n\n**Arguments**:\n\n- `overrides`: overridden values dictionary\n\n**Returns**:\n\nNone\n\n<a id=\"aea.configurations.manager.AgentConfigManager.validate_current_config\"></a>\n\n#### validate`_`current`_`config\n\n```python\ndef validate_current_config() -> None\n```\n\nCheck is current config valid.\n\n<a id=\"aea.configurations.manager.AgentConfigManager.json\"></a>\n\n#### json\n\n```python\n@property\ndef json() -> Dict\n```\n\nReturn current agent config json representation.\n\n<a id=\"aea.configurations.manager.AgentConfigManager.dump_config\"></a>\n\n#### dump`_`config\n\n```python\ndef dump_config() -> None\n```\n\nSave agent config on the disc.\n\n<a id=\"aea.configurations.manager.AgentConfigManager.verify_private_keys\"></a>\n\n#### verify`_`private`_`keys\n\n```python\n@classmethod\ndef verify_private_keys(\n        cls,\n        aea_project_path: Union[Path, str],\n        private_key_helper: Callable[[AgentConfig, Path, Optional[str]], None],\n        substitude_env_vars: bool = False,\n        password: Optional[str] = None) -> \"AgentConfigManager\"\n```\n\nVerify private keys.\n\nDoes not saves the config! Use AgentConfigManager.dump_config()\n\n**Arguments**:\n\n- `aea_project_path`: path to an AEA project.\n- `private_key_helper`: private_key_helper is a function that use agent config to check the keys\n- `substitude_env_vars`: replace env vars with values, does not dump config\n- `password`: the password to encrypt/decrypt the private key.\n\n**Returns**:\n\nthe agent configuration manager.\n\n<a id=\"aea.configurations.manager.AgentConfigManager.get_overridables\"></a>\n\n#### get`_`overridables\n\n```python\ndef get_overridables() -> Tuple[Dict, Dict[ComponentId, Dict]]\n```\n\nGet config overridables.\n\n"
  },
  {
    "path": "docs/api/configurations/pypi.md",
    "content": "<a id=\"aea.configurations.pypi\"></a>\n\n# aea.configurations.pypi\n\nThis module contains a checker for PyPI version consistency.\n\n<a id=\"aea.configurations.pypi.and_\"></a>\n\n#### and`_`\n\n```python\ndef and_(s1: SpecifierSet, s2: SpecifierSet) -> SpecifierSet\n```\n\nDo the and between two specifier sets.\n\n<a id=\"aea.configurations.pypi.is_satisfiable\"></a>\n\n#### is`_`satisfiable\n\n```python\ndef is_satisfiable(specifier_set: SpecifierSet) -> bool\n```\n\nCheck if the specifier set is satisfiable.\n\nSatisfiable means that there exists a version number\nthat satisfies all the constraints. It is worth\nnoticing that it doesn't mean that that version\nnumber with that package actually exists.\n\n>>> from packaging.specifiers import SpecifierSet\n\nThe specifier set \">0.9, ==1.0\" is satisfiable:\nthe version number \"1.0\" satisfies the constraints\n\n>>> s1 = SpecifierSet(\">0.9,==1.0\")\n>>> \"1.0\" in s1\nTrue\n>>> is_satisfiable(s1)\nTrue\n\nThe specifier set \"==1.0, >1.1\" is not satisfiable:\n\n>>> s1 = SpecifierSet(\"==1.0,>1.1\")\n>>> is_satisfiable(s1)\nFalse\n\nFor other details, please refer to PEP440:\n\n    https://www.python.org/dev/peps/pep-0440\n\n**Arguments**:\n\n- `specifier_set`: the specifier set.\n\n**Returns**:\n\nFalse if the constraints are surely non-satisfiable, True if we don't know.\n\n<a id=\"aea.configurations.pypi.is_simple_dep\"></a>\n\n#### is`_`simple`_`dep\n\n```python\ndef is_simple_dep(dep: Dependency) -> bool\n```\n\nCheck if it is a simple dependency.\n\nNamely, if it has no field specified, or only the 'version' field set.\n\n**Arguments**:\n\n- `dep`: the dependency\n\n**Returns**:\n\nwhether it is a simple dependency or not\n\n<a id=\"aea.configurations.pypi.to_set_specifier\"></a>\n\n#### to`_`set`_`specifier\n\n```python\ndef to_set_specifier(dep: Dependency) -> SpecifierSet\n```\n\nGet the set specifier. It assumes to be a simple dependency (see above).\n\n<a id=\"aea.configurations.pypi.merge_dependencies\"></a>\n\n#### merge`_`dependencies\n\n```python\ndef merge_dependencies(dep1: Dependencies, dep2: Dependencies) -> Dependencies\n```\n\nMerge two groups of dependencies.\n\nIf some of them are not \"simple\" (see above), and there is no risk\n  of conflict because there is no other package with the same name,\n  we leave them; otherwise we raise an error.\n\n**Arguments**:\n\n- `dep1`: the first operand\n- `dep2`: the second operand.\n\n**Returns**:\n\nthe merged dependencies.\n\n<a id=\"aea.configurations.pypi.merge_dependencies_list\"></a>\n\n#### merge`_`dependencies`_`list\n\n```python\ndef merge_dependencies_list(*deps: Dependencies) -> Dependencies\n```\n\nMerge a list of dependencies.\n\n**Arguments**:\n\n- `deps`: the list of dependencies\n\n**Returns**:\n\nthe merged dependencies.\n\n"
  },
  {
    "path": "docs/api/configurations/utils.md",
    "content": "<a id=\"aea.configurations.utils\"></a>\n\n# aea.configurations.utils\n\nAEA configuration utils.\n\n<a id=\"aea.configurations.utils.replace_component_ids\"></a>\n\n#### replace`_`component`_`ids\n\n```python\n@singledispatch\ndef replace_component_ids(\n        _arg: PackageConfiguration,\n        _replacements: Dict[ComponentType, Dict[PublicId, PublicId]]) -> None\n```\n\nUpdate public id references in a package configuration.\n\nThis depends on the actual configuration being considered.\n\n<a id=\"aea.configurations.utils._\"></a>\n\n#### `_`\n\n```python\n@replace_component_ids.register(AgentConfig)  # type: ignore\ndef _(arg: AgentConfig, replacements: Dict[ComponentType,\n                                           Dict[PublicId, PublicId]]) -> None\n```\n\nReplace references in agent configuration.\n\nIt breaks down in:\n1) replace public ids in 'protocols', 'connections', 'contracts' and 'skills';\n2) replace public ids in default routing;\n3) replace public id of default connection;\n4) replace custom component configurations.\n\n**Arguments**:\n\n- `arg`: the agent configuration.\n- `replacements`: the replacement mapping.\n\n<a id=\"aea.configurations.utils._\"></a>\n\n#### `_`\n\n```python\n@replace_component_ids.register(ProtocolConfig)  # type: ignore\ndef _(_arg: ProtocolConfig,\n      _replacements: Dict[ComponentType, Dict[PublicId, PublicId]]) -> None\n```\n\nDo nothing - protocols have no references.\n\n<a id=\"aea.configurations.utils._\"></a>\n\n#### `_`\n\n```python\n@replace_component_ids.register(ConnectionConfig)  # type: ignore\ndef _(arg: ConnectionConfig,\n      replacements: Dict[ComponentType, Dict[PublicId, PublicId]]) -> None\n```\n\nReplace references in a connection configuration.\n\n<a id=\"aea.configurations.utils._\"></a>\n\n#### `_`\n\n```python\n@replace_component_ids.register(ContractConfig)  # type: ignore\ndef _(_arg: ContractConfig,\n      _replacements: Dict[ComponentType, Dict[PublicId, PublicId]]) -> None\n```\n\nDo nothing - contracts have no references.\n\n<a id=\"aea.configurations.utils._\"></a>\n\n#### `_`\n\n```python\n@replace_component_ids.register(SkillConfig)  # type: ignore\ndef _(arg: SkillConfig, replacements: Dict[ComponentType,\n                                           Dict[PublicId, PublicId]]) -> None\n```\n\nReplace references in a skill configuration.\n\n<a id=\"aea.configurations.utils.get_latest_component_id_from_prefix\"></a>\n\n#### get`_`latest`_`component`_`id`_`from`_`prefix\n\n```python\ndef get_latest_component_id_from_prefix(\n        agent_config: AgentConfig,\n        component_prefix: PackageIdPrefix) -> Optional[ComponentId]\n```\n\nGet component id with the greatest version in an agent configuration given its prefix.\n\n**Arguments**:\n\n- `agent_config`: the agent configuration.\n- `component_prefix`: the package prefix.\n\n**Returns**:\n\nthe package id with the greatest version, or None if not found.\n\n"
  },
  {
    "path": "docs/api/configurations/validation.md",
    "content": "<a id=\"aea.configurations.validation\"></a>\n\n# aea.configurations.validation\n\nImplementation of the configuration validation.\n\n<a id=\"aea.configurations.validation.make_jsonschema_base_uri\"></a>\n\n#### make`_`jsonschema`_`base`_`uri\n\n```python\ndef make_jsonschema_base_uri(base_uri_path: Path) -> str\n```\n\nMake the JSONSchema base URI, cross-platform.\n\n**Arguments**:\n\n- `base_uri_path`: the path to the base directory.\n\n**Returns**:\n\nthe string in URI form.\n\n<a id=\"aea.configurations.validation.ExtraPropertiesError\"></a>\n\n## ExtraPropertiesError Objects\n\n```python\nclass ExtraPropertiesError(ValueError)\n```\n\nExtra properties exception.\n\n<a id=\"aea.configurations.validation.ExtraPropertiesError.__str__\"></a>\n\n#### `__`str`__`\n\n```python\ndef __str__() -> str\n```\n\nGet string representation of the object.\n\n<a id=\"aea.configurations.validation.ExtraPropertiesError.__repr__\"></a>\n\n#### `__`repr`__`\n\n```python\ndef __repr__() -> str\n```\n\nGet string representation of the object.\n\n<a id=\"aea.configurations.validation.CustomTypeChecker\"></a>\n\n## CustomTypeChecker Objects\n\n```python\nclass CustomTypeChecker(TypeChecker)\n```\n\nCustom type checker to handle env variables.\n\n<a id=\"aea.configurations.validation.CustomTypeChecker.is_type\"></a>\n\n#### is`_`type\n\n```python\ndef is_type(instance, type) -> bool\n```\n\nCheck is instance of type.\n\n<a id=\"aea.configurations.validation.own_additional_properties\"></a>\n\n#### own`_`additional`_`properties\n\n```python\ndef own_additional_properties(validator, aP, instance, schema) -> Iterator\n```\n\nAdditional properties validator.\n\n<a id=\"aea.configurations.validation.ConfigValidator\"></a>\n\n## ConfigValidator Objects\n\n```python\nclass ConfigValidator()\n```\n\nConfiguration validator implementation.\n\n<a id=\"aea.configurations.validation.ConfigValidator.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(schema_filename: str, env_vars_friendly: bool = False) -> None\n```\n\nInitialize the parser for configuration files.\n\n**Arguments**:\n\n- `schema_filename`: the path to the JSON-schema file in 'aea/configurations/schemas'.\n- `env_vars_friendly`: whether or not it is env var friendly.\n\n<a id=\"aea.configurations.validation.ConfigValidator.split_component_id_and_config\"></a>\n\n#### split`_`component`_`id`_`and`_`config\n\n```python\n@staticmethod\ndef split_component_id_and_config(\n        component_index: int,\n        component_configuration_json: Dict) -> ComponentId\n```\n\nSplit component id and configuration.\n\n**Arguments**:\n\n- `component_index`: the position of the component configuration in the agent config file..\n- `component_configuration_json`: the JSON object to process.\n\n**Raises**:\n\n- `ValueError`: if the component id cannot be extracted.\n\n**Returns**:\n\nthe component id and the configuration object.\n\n<a id=\"aea.configurations.validation.ConfigValidator.validate_component_configuration\"></a>\n\n#### validate`_`component`_`configuration\n\n```python\n@classmethod\ndef validate_component_configuration(cls,\n                                     component_id: ComponentId,\n                                     configuration: Dict,\n                                     env_vars_friendly: bool = False) -> None\n```\n\nValidate the component configuration of an agent configuration file.\n\nThis check is to detect inconsistencies in the specified fields.\n\n**Arguments**:\n\n- `component_id`: the component id.\n- `configuration`: the configuration dictionary.\n- `env_vars_friendly`: bool, if set True, will not raise errors over the env variable definitions.\n\n**Raises**:\n\n- `ValueError`: if the configuration is not valid.\n\n<a id=\"aea.configurations.validation.ConfigValidator.validate\"></a>\n\n#### validate\n\n```python\ndef validate(json_data: Dict) -> None\n```\n\nValidate a JSON object against the right JSON schema.\n\n**Arguments**:\n\n- `json_data`: the JSON data.\n\n<a id=\"aea.configurations.validation.ConfigValidator.validate_agent_components_configuration\"></a>\n\n#### validate`_`agent`_`components`_`configuration\n\n```python\ndef validate_agent_components_configuration(\n        component_configurations: Dict) -> None\n```\n\nValidate agent component configurations overrides.\n\n**Arguments**:\n\n- `component_configurations`: the component configurations to validate.\n\n<a id=\"aea.configurations.validation.ConfigValidator.required_fields\"></a>\n\n#### required`_`fields\n\n```python\n@property\ndef required_fields() -> List[str]\n```\n\nGet the required fields.\n\n**Returns**:\n\nlist of required fields.\n\n<a id=\"aea.configurations.validation.validate_data_with_pattern\"></a>\n\n#### validate`_`data`_`with`_`pattern\n\n```python\ndef validate_data_with_pattern(data: dict,\n                               pattern: dict,\n                               excludes: Optional[List[Tuple[str]]] = None,\n                               skip_env_vars: bool = False) -> List[str]\n```\n\nValidate data dict with pattern dict for attributes present and type match.\n\n**Arguments**:\n\n- `data`: data dict to validate\n- `pattern`: dict with pattern to check over\n- `excludes`: list of tuples of str of paths to be skipped during the check\n- `skip_env_vars`: is set True will not check data type over env variables.\n\n**Returns**:\n\nlist of str with error descriptions\n\n<a id=\"aea.configurations.validation.filter_data\"></a>\n\n#### filter`_`data\n\n```python\ndef filter_data(base: Any, updates: Any) -> Any\n```\n\nReturn difference in values or `SAME_MARK` object if values are the same.\n\n"
  },
  {
    "path": "docs/api/connections/base.md",
    "content": "<a id=\"aea.connections.base\"></a>\n\n# aea.connections.base\n\nThe base connection package.\n\n<a id=\"aea.connections.base.ConnectionStates\"></a>\n\n## ConnectionStates Objects\n\n```python\nclass ConnectionStates(Enum)\n```\n\nConnection states enum.\n\n<a id=\"aea.connections.base.Connection\"></a>\n\n## Connection Objects\n\n```python\nclass Connection(Component, ABC)\n```\n\nAbstract definition of a connection.\n\n<a id=\"aea.connections.base.Connection.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(configuration: ConnectionConfig,\n             data_dir: str,\n             identity: Optional[Identity] = None,\n             crypto_store: Optional[CryptoStore] = None,\n             restricted_to_protocols: Optional[Set[PublicId]] = None,\n             excluded_protocols: Optional[Set[PublicId]] = None,\n             **kwargs: Any) -> None\n```\n\nInitialize the connection.\n\nThe configuration must be specified if and only if the following\nparameters are None: connection_id, excluded_protocols or restricted_to_protocols.\n\n**Arguments**:\n\n- `configuration`: the connection configuration.\n- `data_dir`: directory where to put local files.\n- `identity`: the identity object held by the agent.\n- `crypto_store`: the crypto store for encrypted communication.\n- `restricted_to_protocols`: the set of protocols ids of the only supported protocols for this connection.\n- `excluded_protocols`: the set of protocols ids that we want to exclude for this connection.\n- `kwargs`: keyword arguments passed to component base\n\n<a id=\"aea.connections.base.Connection.loop\"></a>\n\n#### loop\n\n```python\n@property\ndef loop() -> asyncio.AbstractEventLoop\n```\n\nGet the event loop.\n\n<a id=\"aea.connections.base.Connection.address\"></a>\n\n#### address\n\n```python\n@property\ndef address() -> \"Address\"\n```\n\nGet the address.\n\n<a id=\"aea.connections.base.Connection.crypto_store\"></a>\n\n#### crypto`_`store\n\n```python\n@property\ndef crypto_store() -> CryptoStore\n```\n\nGet the crypto store.\n\n<a id=\"aea.connections.base.Connection.has_crypto_store\"></a>\n\n#### has`_`crypto`_`store\n\n```python\n@property\ndef has_crypto_store() -> bool\n```\n\nCheck if the connection has the crypto store.\n\n<a id=\"aea.connections.base.Connection.data_dir\"></a>\n\n#### data`_`dir\n\n```python\n@property\ndef data_dir() -> str\n```\n\nGet the data directory.\n\n<a id=\"aea.connections.base.Connection.component_type\"></a>\n\n#### component`_`type\n\n```python\n@property\ndef component_type() -> ComponentType\n```\n\nGet the component type.\n\n<a id=\"aea.connections.base.Connection.configuration\"></a>\n\n#### configuration\n\n```python\n@property\ndef configuration() -> ConnectionConfig\n```\n\nGet the connection configuration.\n\n<a id=\"aea.connections.base.Connection.restricted_to_protocols\"></a>\n\n#### restricted`_`to`_`protocols\n\n```python\n@property\ndef restricted_to_protocols() -> Set[PublicId]\n```\n\nGet the ids of the protocols this connection is restricted to.\n\n<a id=\"aea.connections.base.Connection.excluded_protocols\"></a>\n\n#### excluded`_`protocols\n\n```python\n@property\ndef excluded_protocols() -> Set[PublicId]\n```\n\nGet the ids of the excluded protocols for this connection.\n\n<a id=\"aea.connections.base.Connection.state\"></a>\n\n#### state\n\n```python\n@property\ndef state() -> ConnectionStates\n```\n\nGet the connection status.\n\n<a id=\"aea.connections.base.Connection.state\"></a>\n\n#### state\n\n```python\n@state.setter\ndef state(value: ConnectionStates) -> None\n```\n\nSet the connection status.\n\n<a id=\"aea.connections.base.Connection.connect\"></a>\n\n#### connect\n\n```python\n@abstractmethod\nasync def connect() -> None\n```\n\nSet up the connection.\n\n<a id=\"aea.connections.base.Connection.disconnect\"></a>\n\n#### disconnect\n\n```python\n@abstractmethod\nasync def disconnect() -> None\n```\n\nTear down the connection.\n\n<a id=\"aea.connections.base.Connection.send\"></a>\n\n#### send\n\n```python\n@abstractmethod\nasync def send(envelope: \"Envelope\") -> None\n```\n\nSend an envelope.\n\n**Arguments**:\n\n- `envelope`: the envelope to send.\n\n**Returns**:\n\nNone\n\n<a id=\"aea.connections.base.Connection.receive\"></a>\n\n#### receive\n\n```python\n@abstractmethod\nasync def receive(*args: Any, **kwargs: Any) -> Optional[\"Envelope\"]\n```\n\nReceive an envelope.\n\n**Arguments**:\n\n- `args`: positional arguments\n- `kwargs`: keyword arguments\n\n**Returns**:\n\nthe received envelope, or None if an error occurred.\n\n<a id=\"aea.connections.base.Connection.from_dir\"></a>\n\n#### from`_`dir\n\n```python\n@classmethod\ndef from_dir(cls, directory: str, identity: Identity,\n             crypto_store: CryptoStore, data_dir: str,\n             **kwargs: Any) -> \"Connection\"\n```\n\nLoad the connection from a directory.\n\n**Arguments**:\n\n- `directory`: the directory to the connection package.\n- `identity`: the identity object.\n- `crypto_store`: object to access the connection crypto objects.\n- `data_dir`: the assets directory.\n- `kwargs`: keyword arguments passed to connection base\n\n**Returns**:\n\nthe connection object.\n\n<a id=\"aea.connections.base.Connection.from_config\"></a>\n\n#### from`_`config\n\n```python\n@classmethod\ndef from_config(cls, configuration: ConnectionConfig, identity: Identity,\n                crypto_store: CryptoStore, data_dir: str,\n                **kwargs: Any) -> \"Connection\"\n```\n\nLoad a connection from a configuration.\n\n**Arguments**:\n\n- `configuration`: the connection configuration.\n- `identity`: the identity object.\n- `crypto_store`: object to access the connection crypto objects.\n- `data_dir`: the directory of the AEA project data.\n- `kwargs`: keyword arguments passed to component base\n\n**Returns**:\n\nan instance of the concrete connection class.\n\n<a id=\"aea.connections.base.Connection.is_connected\"></a>\n\n#### is`_`connected\n\n```python\n@property\ndef is_connected() -> bool\n```\n\nReturn is connected state.\n\n<a id=\"aea.connections.base.Connection.is_connecting\"></a>\n\n#### is`_`connecting\n\n```python\n@property\ndef is_connecting() -> bool\n```\n\nReturn is connecting state.\n\n<a id=\"aea.connections.base.Connection.is_disconnected\"></a>\n\n#### is`_`disconnected\n\n```python\n@property\ndef is_disconnected() -> bool\n```\n\nReturn is disconnected state.\n\n<a id=\"aea.connections.base.BaseSyncConnection\"></a>\n\n## BaseSyncConnection Objects\n\n```python\nclass BaseSyncConnection(Connection)\n```\n\nBase sync connection class to write connections with sync code.\n\n<a id=\"aea.connections.base.BaseSyncConnection.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(configuration: ConnectionConfig,\n             data_dir: str,\n             identity: Optional[Identity] = None,\n             crypto_store: Optional[CryptoStore] = None,\n             restricted_to_protocols: Optional[Set[PublicId]] = None,\n             excluded_protocols: Optional[Set[PublicId]] = None,\n             **kwargs: Any) -> None\n```\n\nInitialize the connection.\n\nThe configuration must be specified if and only if the following\nparameters are None: connection_id, excluded_protocols or restricted_to_protocols.\n\n**Arguments**:\n\n- `configuration`: the connection configuration.\n- `data_dir`: directory where to put local files.\n- `identity`: the identity object held by the agent.\n- `crypto_store`: the crypto store for encrypted communication.\n- `restricted_to_protocols`: the set of protocols ids of the only supported protocols for this connection.\n- `excluded_protocols`: the set of protocols ids that we want to exclude for this connection.\n- `kwargs`: keyword arguments passed to connection base\n\n<a id=\"aea.connections.base.BaseSyncConnection.put_envelope\"></a>\n\n#### put`_`envelope\n\n```python\ndef put_envelope(envelope: Optional[\"Envelope\"]) -> None\n```\n\nPut envelope in to the incoming queue.\n\n<a id=\"aea.connections.base.BaseSyncConnection.connect\"></a>\n\n#### connect\n\n```python\nasync def connect() -> None\n```\n\nConnect connection.\n\n<a id=\"aea.connections.base.BaseSyncConnection.disconnect\"></a>\n\n#### disconnect\n\n```python\nasync def disconnect() -> None\n```\n\nDisconnect connection.\n\n<a id=\"aea.connections.base.BaseSyncConnection.send\"></a>\n\n#### send\n\n```python\nasync def send(envelope: \"Envelope\") -> None\n```\n\nSend envelope to connection.\n\n<a id=\"aea.connections.base.BaseSyncConnection.receive\"></a>\n\n#### receive\n\n```python\nasync def receive(*args: Any, **kwargs: Any) -> Optional[\"Envelope\"]\n```\n\nGet an envelope from the connection.\n\n<a id=\"aea.connections.base.BaseSyncConnection.start_main\"></a>\n\n#### start`_`main\n\n```python\ndef start_main() -> None\n```\n\nStart main function of the connection.\n\n<a id=\"aea.connections.base.BaseSyncConnection.main\"></a>\n\n#### main\n\n```python\ndef main() -> None\n```\n\nRun main body of the connection in dedicated thread.\n\n<a id=\"aea.connections.base.BaseSyncConnection.on_connect\"></a>\n\n#### on`_`connect\n\n```python\n@abstractmethod\ndef on_connect() -> None\n```\n\nRun on connect method called.\n\n<a id=\"aea.connections.base.BaseSyncConnection.on_disconnect\"></a>\n\n#### on`_`disconnect\n\n```python\n@abstractmethod\ndef on_disconnect() -> None\n```\n\nRun on disconnect method called.\n\n<a id=\"aea.connections.base.BaseSyncConnection.on_send\"></a>\n\n#### on`_`send\n\n```python\n@abstractmethod\ndef on_send(envelope: \"Envelope\") -> None\n```\n\nRun on send method called.\n\n"
  },
  {
    "path": "docs/api/context/base.md",
    "content": "<a id=\"aea.context.base\"></a>\n\n# aea.context.base\n\nThis module contains the agent context class.\n\n<a id=\"aea.context.base.AgentContext\"></a>\n\n## AgentContext Objects\n\n```python\nclass AgentContext()\n```\n\nProvide read access to relevant objects of the agent for the skills.\n\n<a id=\"aea.context.base.AgentContext.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(identity: Identity,\n             connection_status: MultiplexerStatus,\n             outbox: OutBox,\n             decision_maker_message_queue: Queue,\n             decision_maker_handler_context: SimpleNamespace,\n             task_manager: TaskManager,\n             default_ledger_id: str,\n             currency_denominations: Dict[str, str],\n             default_connection: Optional[PublicId],\n             default_routing: Dict[PublicId, PublicId],\n             search_service_address: Address,\n             decision_maker_address: Address,\n             data_dir: str,\n             storage_callable: Callable[[], Optional[Storage]] = lambda: None,\n             send_to_skill: Optional[Callable] = None,\n             **kwargs: Any) -> None\n```\n\nInitialize an agent context.\n\n**Arguments**:\n\n- `identity`: the identity object\n- `connection_status`: the connection status of the multiplexer\n- `outbox`: the outbox\n- `decision_maker_message_queue`: the (in) queue of the decision maker\n- `decision_maker_handler_context`: the decision maker's name space\n- `task_manager`: the task manager\n- `default_ledger_id`: the default ledger id\n- `currency_denominations`: mapping from ledger ids to currency denominations\n- `default_connection`: the default connection\n- `default_routing`: the default routing\n- `search_service_address`: the address of the search service\n- `decision_maker_address`: the address of the decision maker\n- `data_dir`: directory where to put local files.\n- `storage_callable`: function that returns optional storage attached to agent.\n- `send_to_skill`: callable for sending envelopes to skills.\n- `kwargs`: keyword arguments to be attached in the agent context namespace.\n\n<a id=\"aea.context.base.AgentContext.send_to_skill\"></a>\n\n#### send`_`to`_`skill\n\n```python\ndef send_to_skill(message_or_envelope: Union[Message, Envelope],\n                  context: Optional[EnvelopeContext] = None) -> None\n```\n\nSend message or envelope to another skill.\n\nIf message passed it will be wrapped into envelope with optional envelope context.\n\n**Arguments**:\n\n- `message_or_envelope`: envelope to send to another skill.\n- `context`: the optional envelope context\n\n<a id=\"aea.context.base.AgentContext.storage\"></a>\n\n#### storage\n\n```python\n@property\ndef storage() -> Optional[Storage]\n```\n\nReturn storage instance if enabled in AEA.\n\n<a id=\"aea.context.base.AgentContext.data_dir\"></a>\n\n#### data`_`dir\n\n```python\n@property\ndef data_dir() -> str\n```\n\nReturn assets directory.\n\n<a id=\"aea.context.base.AgentContext.shared_state\"></a>\n\n#### shared`_`state\n\n```python\n@property\ndef shared_state() -> Dict[str, Any]\n```\n\nGet the shared state dictionary.\n\nThe shared state is the only object which skills can use\nto exchange state directly. It is accessible (read and write) from\nall skills.\n\n**Returns**:\n\ndictionary of the shared state.\n\n<a id=\"aea.context.base.AgentContext.identity\"></a>\n\n#### identity\n\n```python\n@property\ndef identity() -> Identity\n```\n\nGet the identity.\n\n<a id=\"aea.context.base.AgentContext.agent_name\"></a>\n\n#### agent`_`name\n\n```python\n@property\ndef agent_name() -> str\n```\n\nGet agent name.\n\n<a id=\"aea.context.base.AgentContext.addresses\"></a>\n\n#### addresses\n\n```python\n@property\ndef addresses() -> Dict[str, Address]\n```\n\nGet addresses.\n\n<a id=\"aea.context.base.AgentContext.public_keys\"></a>\n\n#### public`_`keys\n\n```python\n@property\ndef public_keys() -> Dict[str, str]\n```\n\nGet public keys.\n\n<a id=\"aea.context.base.AgentContext.address\"></a>\n\n#### address\n\n```python\n@property\ndef address() -> Address\n```\n\nGet the default address.\n\n<a id=\"aea.context.base.AgentContext.public_key\"></a>\n\n#### public`_`key\n\n```python\n@property\ndef public_key() -> str\n```\n\nGet the default public key.\n\n<a id=\"aea.context.base.AgentContext.connection_status\"></a>\n\n#### connection`_`status\n\n```python\n@property\ndef connection_status() -> MultiplexerStatus\n```\n\nGet connection status of the multiplexer.\n\n<a id=\"aea.context.base.AgentContext.outbox\"></a>\n\n#### outbox\n\n```python\n@property\ndef outbox() -> OutBox\n```\n\nGet outbox.\n\n<a id=\"aea.context.base.AgentContext.decision_maker_message_queue\"></a>\n\n#### decision`_`maker`_`message`_`queue\n\n```python\n@property\ndef decision_maker_message_queue() -> Queue\n```\n\nGet decision maker queue.\n\n<a id=\"aea.context.base.AgentContext.decision_maker_handler_context\"></a>\n\n#### decision`_`maker`_`handler`_`context\n\n```python\n@property\ndef decision_maker_handler_context() -> SimpleNamespace\n```\n\nGet the decision maker handler context.\n\n<a id=\"aea.context.base.AgentContext.task_manager\"></a>\n\n#### task`_`manager\n\n```python\n@property\ndef task_manager() -> TaskManager\n```\n\nGet the task manager.\n\n<a id=\"aea.context.base.AgentContext.search_service_address\"></a>\n\n#### search`_`service`_`address\n\n```python\n@property\ndef search_service_address() -> Address\n```\n\nGet the address of the search service.\n\n<a id=\"aea.context.base.AgentContext.decision_maker_address\"></a>\n\n#### decision`_`maker`_`address\n\n```python\n@property\ndef decision_maker_address() -> Address\n```\n\nGet the address of the decision maker.\n\n<a id=\"aea.context.base.AgentContext.default_ledger_id\"></a>\n\n#### default`_`ledger`_`id\n\n```python\n@property\ndef default_ledger_id() -> str\n```\n\nGet the default ledger id.\n\n<a id=\"aea.context.base.AgentContext.currency_denominations\"></a>\n\n#### currency`_`denominations\n\n```python\n@property\ndef currency_denominations() -> Dict[str, str]\n```\n\nGet a dictionary mapping ledger ids to currency denominations.\n\n<a id=\"aea.context.base.AgentContext.default_connection\"></a>\n\n#### default`_`connection\n\n```python\n@property\ndef default_connection() -> Optional[PublicId]\n```\n\nGet the default connection.\n\n<a id=\"aea.context.base.AgentContext.default_routing\"></a>\n\n#### default`_`routing\n\n```python\n@property\ndef default_routing() -> Dict[PublicId, PublicId]\n```\n\nGet the default routing.\n\n<a id=\"aea.context.base.AgentContext.namespace\"></a>\n\n#### namespace\n\n```python\n@property\ndef namespace() -> SimpleNamespace\n```\n\nGet the agent context namespace.\n\n"
  },
  {
    "path": "docs/api/contracts/base.md",
    "content": "<a id=\"aea.contracts.base\"></a>\n\n# aea.contracts.base\n\nThe base contract.\n\n<a id=\"aea.contracts.base.Contract\"></a>\n\n## Contract Objects\n\n```python\nclass Contract(Component)\n```\n\nAbstract definition of a contract.\n\n<a id=\"aea.contracts.base.Contract.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(contract_config: ContractConfig, **kwargs: Any) -> None\n```\n\nInitialize the contract.\n\n**Arguments**:\n\n- `contract_config`: the contract configurations.\n- `kwargs`: the keyword arguments.\n\n<a id=\"aea.contracts.base.Contract.id\"></a>\n\n#### id\n\n```python\n@property\ndef id() -> PublicId\n```\n\nGet the name.\n\n<a id=\"aea.contracts.base.Contract.configuration\"></a>\n\n#### configuration\n\n```python\n@property\ndef configuration() -> ContractConfig\n```\n\nGet the configuration.\n\n<a id=\"aea.contracts.base.Contract.get_instance\"></a>\n\n#### get`_`instance\n\n```python\n@classmethod\ndef get_instance(cls,\n                 ledger_api: LedgerApi,\n                 contract_address: Optional[str] = None) -> Any\n```\n\nGet the instance.\n\n**Arguments**:\n\n- `ledger_api`: the ledger api we are using.\n- `contract_address`: the contract address.\n\n**Returns**:\n\nthe contract instance\n\n<a id=\"aea.contracts.base.Contract.from_dir\"></a>\n\n#### from`_`dir\n\n```python\n@classmethod\ndef from_dir(cls, directory: str, **kwargs: Any) -> \"Contract\"\n```\n\nLoad the protocol from a directory.\n\n**Arguments**:\n\n- `directory`: the directory to the skill package.\n- `kwargs`: the keyword arguments.\n\n**Returns**:\n\nthe contract object.\n\n<a id=\"aea.contracts.base.Contract.from_config\"></a>\n\n#### from`_`config\n\n```python\n@classmethod\ndef from_config(cls, configuration: ContractConfig,\n                **kwargs: Any) -> \"Contract\"\n```\n\nLoad contract from configuration.\n\n**Arguments**:\n\n- `configuration`: the contract configuration.\n- `kwargs`: the keyword arguments.\n\n**Returns**:\n\nthe contract object.\n\n<a id=\"aea.contracts.base.Contract.get_deploy_transaction\"></a>\n\n#### get`_`deploy`_`transaction\n\n```python\n@classmethod\ndef get_deploy_transaction(cls, ledger_api: LedgerApi, deployer_address: str,\n                           **kwargs: Any) -> Optional[JSONLike]\n```\n\nHandler method for the 'GET_DEPLOY_TRANSACTION' requests.\n\nImplement this method in the sub class if you want\nto handle the contract requests manually.\n\n**Arguments**:\n\n- `ledger_api`: the ledger apis.\n- `deployer_address`: The address that will deploy the contract.\n- `kwargs`: keyword arguments.\n\n**Returns**:\n\nthe tx\n\n<a id=\"aea.contracts.base.Contract.get_raw_transaction\"></a>\n\n#### get`_`raw`_`transaction\n\n```python\n@classmethod\ndef get_raw_transaction(cls, ledger_api: LedgerApi, contract_address: str,\n                        **kwargs: Any) -> Optional[JSONLike]\n```\n\nHandler method for the 'GET_RAW_TRANSACTION' requests.\n\nImplement this method in the sub class if you want\nto handle the contract requests manually.\n\n**Arguments**:\n\n- `ledger_api`: the ledger apis.\n- `contract_address`: the contract address.\n- `kwargs`: the keyword arguments.\n\n**Returns**:\n\nthe tx  # noqa: DAR202\n\n<a id=\"aea.contracts.base.Contract.get_raw_message\"></a>\n\n#### get`_`raw`_`message\n\n```python\n@classmethod\ndef get_raw_message(cls, ledger_api: LedgerApi, contract_address: str,\n                    **kwargs: Any) -> Optional[bytes]\n```\n\nHandler method for the 'GET_RAW_MESSAGE' requests.\n\nImplement this method in the sub class if you want\nto handle the contract requests manually.\n\n**Arguments**:\n\n- `ledger_api`: the ledger apis.\n- `contract_address`: the contract address.\n- `kwargs`: the keyword arguments.\n\n**Returns**:\n\nthe tx  # noqa: DAR202\n\n<a id=\"aea.contracts.base.Contract.get_state\"></a>\n\n#### get`_`state\n\n```python\n@classmethod\ndef get_state(cls, ledger_api: LedgerApi, contract_address: str,\n              **kwargs: Any) -> Optional[JSONLike]\n```\n\nHandler method for the 'GET_STATE' requests.\n\nImplement this method in the sub class if you want\nto handle the contract requests manually.\n\n**Arguments**:\n\n- `ledger_api`: the ledger apis.\n- `contract_address`: the contract address.\n- `kwargs`: the keyword arguments.\n\n**Returns**:\n\nthe tx  # noqa: DAR202\n\n"
  },
  {
    "path": "docs/api/crypto/base.md",
    "content": "<a id=\"aea.crypto.base\"></a>\n\n# aea.crypto.base\n\nAbstract module wrapping the public and private key cryptography and ledger api.\n\n<a id=\"aea.crypto.base.Crypto\"></a>\n\n## Crypto Objects\n\n```python\nclass Crypto(Generic[EntityClass], ABC)\n```\n\nBase class for a crypto object.\n\n<a id=\"aea.crypto.base.Crypto.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(private_key_path: Optional[str] = None,\n             password: Optional[str] = None,\n             **kwargs: Any) -> None\n```\n\nInitialize the crypto object.\n\nThe actual behaviour of this constructor is determined by the abstract\nmethods 'generate_private_key()' and 'load_private_key_from_path().\nEither way, the entity object will be accessible as a property.\n\n**Arguments**:\n\n- `private_key_path`: the path to the private key.\nIf None, the key will be generated by 'generate_private_key()'.\nIf not None, the path will be processed by 'load_private_key_from_path()'.\n- `password`: the password to encrypt/decrypt the private key.\n- `kwargs`: keyword arguments.\n\n<a id=\"aea.crypto.base.Crypto.generate_private_key\"></a>\n\n#### generate`_`private`_`key\n\n```python\n@classmethod\n@abstractmethod\ndef generate_private_key(cls) -> EntityClass\n```\n\nGenerate a private key.\n\n**Returns**:\n\nthe entity object. Implementation dependent.\n\n<a id=\"aea.crypto.base.Crypto.load_private_key_from_path\"></a>\n\n#### load`_`private`_`key`_`from`_`path\n\n```python\n@classmethod\n@abstractmethod\ndef load_private_key_from_path(cls,\n                               file_name: str,\n                               password: Optional[str] = None) -> EntityClass\n```\n\nLoad a private key in hex format for raw private key and json format for encrypted private key from a file.\n\n**Arguments**:\n\n- `file_name`: the path to the hex/json file.\n- `password`: the password to encrypt/decrypt the private key.\n\n**Returns**:\n\nthe entity object.\n\n<a id=\"aea.crypto.base.Crypto.entity\"></a>\n\n#### entity\n\n```python\n@property\ndef entity() -> EntityClass\n```\n\nReturn an entity object.\n\n**Returns**:\n\nan entity object\n\n<a id=\"aea.crypto.base.Crypto.private_key\"></a>\n\n#### private`_`key\n\n```python\n@property\n@abstractmethod\ndef private_key() -> str\n```\n\nReturn a private key.\n\n**Returns**:\n\na private key string\n\n<a id=\"aea.crypto.base.Crypto.public_key\"></a>\n\n#### public`_`key\n\n```python\n@property\n@abstractmethod\ndef public_key() -> str\n```\n\nReturn a public key.\n\n**Returns**:\n\na public key string\n\n<a id=\"aea.crypto.base.Crypto.address\"></a>\n\n#### address\n\n```python\n@property\n@abstractmethod\ndef address() -> str\n```\n\nReturn the address.\n\n**Returns**:\n\nan address string\n\n<a id=\"aea.crypto.base.Crypto.sign_message\"></a>\n\n#### sign`_`message\n\n```python\n@abstractmethod\ndef sign_message(message: bytes, is_deprecated_mode: bool = False) -> str\n```\n\nSign a message in bytes string form.\n\n**Arguments**:\n\n- `message`: the message to be signed\n- `is_deprecated_mode`: if the deprecated signing is used\n\n**Returns**:\n\nsignature of the message in string form\n\n<a id=\"aea.crypto.base.Crypto.sign_transaction\"></a>\n\n#### sign`_`transaction\n\n```python\n@abstractmethod\ndef sign_transaction(transaction: JSONLike) -> JSONLike\n```\n\nSign a transaction in dict form.\n\n**Arguments**:\n\n- `transaction`: the transaction to be signed\n\n**Returns**:\n\nsigned transaction\n\n<a id=\"aea.crypto.base.Crypto.load\"></a>\n\n#### load\n\n```python\n@classmethod\ndef load(cls, private_key_file: str, password: Optional[str] = None) -> str\n```\n\nLoad private key from file.\n\n**Arguments**:\n\n- `private_key_file`: the file where the key is stored.\n- `password`: the password to encrypt/decrypt the private key.\n\n**Returns**:\n\nprivate_key in hex string format\n\n<a id=\"aea.crypto.base.Crypto.dump\"></a>\n\n#### dump\n\n```python\ndef dump(private_key_file: str, password: Optional[str] = None) -> None\n```\n\nDump private key to file.\n\n**Arguments**:\n\n- `private_key_file`: the file where the key is stored.\n- `password`: the password to encrypt/decrypt the private key.\n\n<a id=\"aea.crypto.base.Crypto.encrypt\"></a>\n\n#### encrypt\n\n```python\n@abstractmethod\ndef encrypt(password: str) -> str\n```\n\nEncrypt the private key and return in json.\n\n**Arguments**:\n\n- `password`: the password to decrypt.\n\n**Returns**:\n\njson string containing encrypted private key.\n\n<a id=\"aea.crypto.base.Crypto.decrypt\"></a>\n\n#### decrypt\n\n```python\n@classmethod\n@abstractmethod\ndef decrypt(cls, keyfile_json: str, password: str) -> str\n```\n\nDecrypt the private key and return in raw form.\n\n**Arguments**:\n\n- `keyfile_json`: json string containing encrypted private key.\n- `password`: the password to decrypt.\n\n**Returns**:\n\nthe raw private key.\n\n<a id=\"aea.crypto.base.Helper\"></a>\n\n## Helper Objects\n\n```python\nclass Helper(ABC)\n```\n\nInterface for helper class usable as Mixin for LedgerApi or as standalone class.\n\n<a id=\"aea.crypto.base.Helper.is_transaction_settled\"></a>\n\n#### is`_`transaction`_`settled\n\n```python\n@staticmethod\n@abstractmethod\ndef is_transaction_settled(tx_receipt: JSONLike) -> bool\n```\n\nCheck whether a transaction is settled or not.\n\n**Arguments**:\n\n- `tx_receipt`: the receipt associated to the transaction.\n\n**Returns**:\n\nTrue if the transaction has been settled, False o/w.\n\n<a id=\"aea.crypto.base.Helper.is_transaction_valid\"></a>\n\n#### is`_`transaction`_`valid\n\n```python\n@staticmethod\n@abstractmethod\ndef is_transaction_valid(tx: JSONLike, seller: Address, client: Address,\n                         tx_nonce: str, amount: int) -> bool\n```\n\nCheck whether a transaction is valid or not.\n\n**Arguments**:\n\n- `tx`: the transaction.\n- `seller`: the address of the seller.\n- `client`: the address of the client.\n- `tx_nonce`: the transaction nonce.\n- `amount`: the amount we expect to get from the transaction.\n\n**Returns**:\n\nTrue if the random_message is equals to tx['input']\n\n<a id=\"aea.crypto.base.Helper.get_contract_address\"></a>\n\n#### get`_`contract`_`address\n\n```python\n@staticmethod\n@abstractmethod\ndef get_contract_address(tx_receipt: JSONLike) -> Optional[str]\n```\n\nGet the contract address from a transaction receipt.\n\n**Arguments**:\n\n- `tx_receipt`: the transaction digest\n\n**Returns**:\n\nthe contract address if successful\n\n<a id=\"aea.crypto.base.Helper.generate_tx_nonce\"></a>\n\n#### generate`_`tx`_`nonce\n\n```python\n@staticmethod\n@abstractmethod\ndef generate_tx_nonce(seller: Address, client: Address) -> str\n```\n\nGenerate a unique hash to distinguish transactions with the same terms.\n\n**Arguments**:\n\n- `seller`: the address of the seller.\n- `client`: the address of the client.\n\n**Returns**:\n\nreturn the hash in hex.\n\n<a id=\"aea.crypto.base.Helper.get_address_from_public_key\"></a>\n\n#### get`_`address`_`from`_`public`_`key\n\n```python\n@classmethod\n@abstractmethod\ndef get_address_from_public_key(cls, public_key: str) -> str\n```\n\nGet the address from the public key.\n\n**Arguments**:\n\n- `public_key`: the public key\n\n**Returns**:\n\nstr\n\n<a id=\"aea.crypto.base.Helper.recover_message\"></a>\n\n#### recover`_`message\n\n```python\n@classmethod\n@abstractmethod\ndef recover_message(cls,\n                    message: bytes,\n                    signature: str,\n                    is_deprecated_mode: bool = False) -> Tuple[Address, ...]\n```\n\nRecover the addresses from the hash.\n\n**Arguments**:\n\n- `message`: the message we expect\n- `signature`: the transaction signature\n- `is_deprecated_mode`: if the deprecated signing was used\n\n**Returns**:\n\nthe recovered addresses\n\n<a id=\"aea.crypto.base.Helper.recover_public_keys_from_message\"></a>\n\n#### recover`_`public`_`keys`_`from`_`message\n\n```python\n@classmethod\n@abstractmethod\ndef recover_public_keys_from_message(\n        cls,\n        message: bytes,\n        signature: str,\n        is_deprecated_mode: bool = False) -> Tuple[str, ...]\n```\n\nGet the public key used to produce the `signature` of the `message`\n\n**Arguments**:\n\n- `message`: raw bytes used to produce signature\n- `signature`: signature of the message\n- `is_deprecated_mode`: if the deprecated signing was used\n\n**Returns**:\n\nthe recovered public keys\n\n<a id=\"aea.crypto.base.Helper.get_hash\"></a>\n\n#### get`_`hash\n\n```python\n@staticmethod\n@abstractmethod\ndef get_hash(message: bytes) -> str\n```\n\nGet the hash of a message.\n\n**Arguments**:\n\n- `message`: the message to be hashed.\n\n**Returns**:\n\nthe hash of the message.\n\n<a id=\"aea.crypto.base.Helper.is_valid_address\"></a>\n\n#### is`_`valid`_`address\n\n```python\n@classmethod\n@abstractmethod\ndef is_valid_address(cls, address: Address) -> bool\n```\n\nCheck if the address is valid.\n\n**Arguments**:\n\n- `address`: the address to validate\n\n<a id=\"aea.crypto.base.Helper.load_contract_interface\"></a>\n\n#### load`_`contract`_`interface\n\n```python\n@classmethod\n@abstractmethod\ndef load_contract_interface(cls, file_path: Path) -> Dict[str, str]\n```\n\nLoad contract interface.\n\n**Arguments**:\n\n- `file_path`: the file path to the interface\n\n**Returns**:\n\nthe interface\n\n<a id=\"aea.crypto.base.LedgerApi\"></a>\n\n## LedgerApi Objects\n\n```python\nclass LedgerApi(Helper, ABC)\n```\n\nInterface for ledger APIs.\n\n<a id=\"aea.crypto.base.LedgerApi.api\"></a>\n\n#### api\n\n```python\n@property\n@abstractmethod\ndef api() -> Any\n```\n\nGet the underlying API object.\n\nThis can be used for low-level operations with the concrete ledger APIs.\nIf there is no such object, return None.\n\n<a id=\"aea.crypto.base.LedgerApi.get_balance\"></a>\n\n#### get`_`balance\n\n```python\n@abstractmethod\ndef get_balance(address: Address) -> Optional[int]\n```\n\nGet the balance of a given account.\n\nThis usually takes the form of a web request to be waited synchronously.\n\n**Arguments**:\n\n- `address`: the address.\n\n**Returns**:\n\nthe balance.\n\n<a id=\"aea.crypto.base.LedgerApi.get_state\"></a>\n\n#### get`_`state\n\n```python\n@abstractmethod\ndef get_state(callable_name: str, *args: Any,\n              **kwargs: Any) -> Optional[JSONLike]\n```\n\nCall a specified function on the underlying ledger API.\n\nThis usually takes the form of a web request to be waited synchronously.\n\n**Arguments**:\n\n- `callable_name`: the name of the API function to be called.\n- `args`: the positional arguments for the API function.\n- `kwargs`: the keyword arguments for the API function.\n\n**Returns**:\n\nthe ledger API response.\n\n<a id=\"aea.crypto.base.LedgerApi.get_transfer_transaction\"></a>\n\n#### get`_`transfer`_`transaction\n\n```python\n@abstractmethod\ndef get_transfer_transaction(sender_address: Address,\n                             destination_address: Address, amount: int,\n                             tx_fee: int, tx_nonce: str,\n                             **kwargs: Any) -> Optional[JSONLike]\n```\n\nSubmit a transfer transaction to the ledger.\n\n**Arguments**:\n\n- `sender_address`: the sender address of the payer.\n- `destination_address`: the destination address of the payee.\n- `amount`: the amount of wealth to be transferred.\n- `tx_fee`: the transaction fee.\n- `tx_nonce`: verifies the authenticity of the tx\n- `kwargs`: the keyword arguments.\n\n**Returns**:\n\nthe transfer transaction\n\n<a id=\"aea.crypto.base.LedgerApi.send_signed_transaction\"></a>\n\n#### send`_`signed`_`transaction\n\n```python\n@abstractmethod\ndef send_signed_transaction(tx_signed: JSONLike) -> Optional[str]\n```\n\nSend a signed transaction and wait for confirmation.\n\nUse keyword arguments for the specifying the signed transaction payload.\n\n**Arguments**:\n\n- `tx_signed`: the signed transaction\n\n<a id=\"aea.crypto.base.LedgerApi.get_transaction_receipt\"></a>\n\n#### get`_`transaction`_`receipt\n\n```python\n@abstractmethod\ndef get_transaction_receipt(tx_digest: str) -> Optional[JSONLike]\n```\n\nGet the transaction receipt for a transaction digest.\n\n**Arguments**:\n\n- `tx_digest`: the digest associated to the transaction.\n\n**Returns**:\n\nthe tx receipt, if present\n\n<a id=\"aea.crypto.base.LedgerApi.get_transaction\"></a>\n\n#### get`_`transaction\n\n```python\n@abstractmethod\ndef get_transaction(tx_digest: str) -> Optional[JSONLike]\n```\n\nGet the transaction for a transaction digest.\n\n**Arguments**:\n\n- `tx_digest`: the digest associated to the transaction.\n\n**Returns**:\n\nthe tx, if present\n\n<a id=\"aea.crypto.base.LedgerApi.get_contract_instance\"></a>\n\n#### get`_`contract`_`instance\n\n```python\n@abstractmethod\ndef get_contract_instance(contract_interface: Dict[str, str],\n                          contract_address: Optional[str] = None) -> Any\n```\n\nGet the instance of a contract.\n\n**Arguments**:\n\n- `contract_interface`: the contract interface.\n- `contract_address`: the contract address.\n\n**Returns**:\n\nthe contract instance\n\n<a id=\"aea.crypto.base.LedgerApi.get_deploy_transaction\"></a>\n\n#### get`_`deploy`_`transaction\n\n```python\n@abstractmethod\ndef get_deploy_transaction(contract_interface: Dict[str, str],\n                           deployer_address: Address,\n                           **kwargs: Any) -> Optional[JSONLike]\n```\n\nGet the transaction to deploy the smart contract.\n\n**Arguments**:\n\n- `contract_interface`: the contract interface.\n- `deployer_address`: The address that will deploy the contract.\n- `kwargs`: the keyword arguments.\n\n**Returns**:\n\n`tx`: the transaction dictionary.\n\n<a id=\"aea.crypto.base.LedgerApi.update_with_gas_estimate\"></a>\n\n#### update`_`with`_`gas`_`estimate\n\n```python\n@abstractmethod\ndef update_with_gas_estimate(transaction: JSONLike) -> JSONLike\n```\n\nAttempts to update the transaction with a gas estimate\n\n**Arguments**:\n\n- `transaction`: the transaction\n\n**Returns**:\n\nthe updated transaction\n\n<a id=\"aea.crypto.base.FaucetApi\"></a>\n\n## FaucetApi Objects\n\n```python\nclass FaucetApi(ABC)\n```\n\nInterface for testnet faucet APIs.\n\n<a id=\"aea.crypto.base.FaucetApi.get_wealth\"></a>\n\n#### get`_`wealth\n\n```python\n@abstractmethod\ndef get_wealth(address: Address, url: Optional[str] = None) -> None\n```\n\nGet wealth from the faucet for the provided address.\n\n**Arguments**:\n\n- `address`: the address.\n- `url`: the url\n\n**Returns**:\n\nNone\n\n"
  },
  {
    "path": "docs/api/crypto/helpers.md",
    "content": "<a id=\"aea.crypto.helpers\"></a>\n\n# aea.crypto.helpers\n\nModule wrapping the helpers of public and private key cryptography.\n\n<a id=\"aea.crypto.helpers.try_validate_private_key_path\"></a>\n\n#### try`_`validate`_`private`_`key`_`path\n\n```python\ndef try_validate_private_key_path(ledger_id: str,\n                                  private_key_path: str,\n                                  password: Optional[str] = None) -> None\n```\n\nTry validate a private key path.\n\n**Arguments**:\n\n- `ledger_id`: one of 'fetchai', 'ethereum'\n- `private_key_path`: the path to the private key.\n- `password`: the password to encrypt/decrypt the private key.\n\n**Raises**:\n\n- `None`: ValueError if the identifier is invalid.\n\n<a id=\"aea.crypto.helpers.create_private_key\"></a>\n\n#### create`_`private`_`key\n\n```python\ndef create_private_key(ledger_id: str,\n                       private_key_file: str,\n                       password: Optional[str] = None) -> None\n```\n\nCreate a private key for the specified ledger identifier.\n\n**Arguments**:\n\n- `ledger_id`: the ledger identifier.\n- `private_key_file`: the private key file.\n- `password`: the password to encrypt/decrypt the private key.\n\n**Raises**:\n\n- `None`: ValueError if the identifier is invalid.\n\n<a id=\"aea.crypto.helpers.try_generate_testnet_wealth\"></a>\n\n#### try`_`generate`_`testnet`_`wealth\n\n```python\ndef try_generate_testnet_wealth(identifier: str,\n                                address: str,\n                                url: Optional[str] = None,\n                                _sync: bool = True) -> None\n```\n\nTry generate wealth on a testnet.\n\n**Arguments**:\n\n- `identifier`: the identifier of the ledger\n- `address`: the address to check for\n- `url`: the url\n- `_sync`: whether to wait to sync or not; currently unused\n\n<a id=\"aea.crypto.helpers.private_key_verify\"></a>\n\n#### private`_`key`_`verify\n\n```python\ndef private_key_verify(aea_conf: AgentConfig,\n                       aea_project_path: Path,\n                       password: Optional[str] = None) -> None\n```\n\nCheck key.\n\n**Arguments**:\n\n- `aea_conf`: AgentConfig\n- `aea_project_path`: Path, where project placed.\n- `password`: the password to encrypt/decrypt the private key.\n\n<a id=\"aea.crypto.helpers.make_certificate\"></a>\n\n#### make`_`certificate\n\n```python\ndef make_certificate(ledger_id: str,\n                     crypto_private_key_path: str,\n                     message: bytes,\n                     output_path: str,\n                     password: Optional[str] = None) -> str\n```\n\nCreate certificate.\n\n**Arguments**:\n\n- `ledger_id`: the ledger id\n- `crypto_private_key_path`: the path to the private key.\n- `message`: the message to be signed.\n- `output_path`: the location where to save the certificate.\n- `password`: the password to encrypt/decrypt the private keys.\n\n**Returns**:\n\nthe signature/certificate\n\n<a id=\"aea.crypto.helpers.get_wallet_from_agent_config\"></a>\n\n#### get`_`wallet`_`from`_`agent`_`config\n\n```python\ndef get_wallet_from_agent_config(agent_config: AgentConfig,\n                                 password: Optional[str] = None) -> Wallet\n```\n\nGet wallet from agent_cofig provided.\n\n**Arguments**:\n\n- `agent_config`: the agent configuration object\n- `password`: the password to encrypt/decrypt the private keys.\n\n**Returns**:\n\nwallet\n\n<a id=\"aea.crypto.helpers.DecryptError\"></a>\n\n## DecryptError Objects\n\n```python\nclass DecryptError(ValueError)\n```\n\nError on bytes decryption with password.\n\n<a id=\"aea.crypto.helpers.DecryptError.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(msg: Optional[str] = None) -> None\n```\n\nInit exception.\n\n<a id=\"aea.crypto.helpers.KeyIsIncorrect\"></a>\n\n## KeyIsIncorrect Objects\n\n```python\nclass KeyIsIncorrect(ValueError)\n```\n\nError decoding hex string to bytes for private key.\n\n<a id=\"aea.crypto.helpers.hex_to_bytes_for_key\"></a>\n\n#### hex`_`to`_`bytes`_`for`_`key\n\n```python\ndef hex_to_bytes_for_key(data: str) -> bytes\n```\n\nConvert hex string to bytes with error handling.\n\n"
  },
  {
    "path": "docs/api/crypto/ledger_apis.md",
    "content": "<a id=\"aea.crypto.ledger_apis\"></a>\n\n# aea.crypto.ledger`_`apis\n\nModule wrapping all the public and private keys cryptography.\n\n<a id=\"aea.crypto.ledger_apis.LedgerApis\"></a>\n\n## LedgerApis Objects\n\n```python\nclass LedgerApis()\n```\n\nStore all the ledger apis we initialise.\n\n<a id=\"aea.crypto.ledger_apis.LedgerApis.has_ledger\"></a>\n\n#### has`_`ledger\n\n```python\n@staticmethod\ndef has_ledger(identifier: str) -> bool\n```\n\nCheck if it has the api.\n\n<a id=\"aea.crypto.ledger_apis.LedgerApis.get_api\"></a>\n\n#### get`_`api\n\n```python\n@classmethod\ndef get_api(cls, identifier: str) -> LedgerApi\n```\n\nGet the ledger API.\n\n<a id=\"aea.crypto.ledger_apis.LedgerApis.get_balance\"></a>\n\n#### get`_`balance\n\n```python\n@classmethod\ndef get_balance(cls, identifier: str, address: str) -> Optional[int]\n```\n\nGet the token balance.\n\n**Arguments**:\n\n- `identifier`: the identifier of the ledger\n- `address`: the address to check for\n\n**Returns**:\n\nthe token balance\n\n<a id=\"aea.crypto.ledger_apis.LedgerApis.get_transfer_transaction\"></a>\n\n#### get`_`transfer`_`transaction\n\n```python\n@classmethod\ndef get_transfer_transaction(cls, identifier: str, sender_address: str,\n                             destination_address: str, amount: int,\n                             tx_fee: int, tx_nonce: str,\n                             **kwargs: Any) -> Optional[Any]\n```\n\nGet a transaction to transfer from self to destination.\n\n**Arguments**:\n\n- `identifier`: the identifier of the ledger\n- `sender_address`: the address of the sender\n- `destination_address`: the address of the receiver\n- `amount`: the amount\n- `tx_nonce`: verifies the authenticity of the tx\n- `tx_fee`: the tx fee\n- `kwargs`: the keyword arguments.\n\n**Returns**:\n\ntx\n\n<a id=\"aea.crypto.ledger_apis.LedgerApis.send_signed_transaction\"></a>\n\n#### send`_`signed`_`transaction\n\n```python\n@classmethod\ndef send_signed_transaction(cls, identifier: str,\n                            tx_signed: Any) -> Optional[str]\n```\n\nSend a signed transaction and wait for confirmation.\n\n**Arguments**:\n\n- `identifier`: the identifier of the ledger\n- `tx_signed`: the signed transaction\n\n**Returns**:\n\nthe tx_digest, if present\n\n<a id=\"aea.crypto.ledger_apis.LedgerApis.get_transaction_receipt\"></a>\n\n#### get`_`transaction`_`receipt\n\n```python\n@classmethod\ndef get_transaction_receipt(cls, identifier: str,\n                            tx_digest: str) -> Optional[Any]\n```\n\nGet the transaction receipt for a transaction digest.\n\n**Arguments**:\n\n- `identifier`: the identifier of the ledger\n- `tx_digest`: the digest associated to the transaction.\n\n**Returns**:\n\nthe tx receipt, if present\n\n<a id=\"aea.crypto.ledger_apis.LedgerApis.get_transaction\"></a>\n\n#### get`_`transaction\n\n```python\n@classmethod\ndef get_transaction(cls, identifier: str, tx_digest: str) -> Optional[Any]\n```\n\nGet the transaction for a transaction digest.\n\n**Arguments**:\n\n- `identifier`: the identifier of the ledger\n- `tx_digest`: the digest associated to the transaction.\n\n**Returns**:\n\nthe tx, if present\n\n<a id=\"aea.crypto.ledger_apis.LedgerApis.get_contract_address\"></a>\n\n#### get`_`contract`_`address\n\n```python\n@staticmethod\ndef get_contract_address(identifier: str,\n                         tx_receipt: Any) -> Optional[Address]\n```\n\nGet the contract address from a transaction receipt.\n\n**Arguments**:\n\n- `identifier`: the identifier of the ledger\n- `tx_receipt`: the transaction receipt\n\n**Returns**:\n\nthe contract address if successful\n\n<a id=\"aea.crypto.ledger_apis.LedgerApis.is_transaction_settled\"></a>\n\n#### is`_`transaction`_`settled\n\n```python\n@staticmethod\ndef is_transaction_settled(identifier: str, tx_receipt: Any) -> bool\n```\n\nCheck whether the transaction is settled and correct.\n\n**Arguments**:\n\n- `identifier`: the identifier of the ledger\n- `tx_receipt`: the transaction digest\n\n**Returns**:\n\nTrue if correctly settled, False otherwise\n\n<a id=\"aea.crypto.ledger_apis.LedgerApis.is_transaction_valid\"></a>\n\n#### is`_`transaction`_`valid\n\n```python\n@staticmethod\ndef is_transaction_valid(identifier: str, tx: Any, seller: Address,\n                         client: Address, tx_nonce: str, amount: int) -> bool\n```\n\nCheck whether the transaction is valid.\n\n**Arguments**:\n\n- `identifier`: Ledger identifier\n- `tx`: the transaction\n- `seller`: the address of the seller.\n- `client`: the address of the client.\n- `tx_nonce`: the transaction nonce.\n- `amount`: the amount we expect to get from the transaction.\n\n**Returns**:\n\nTrue if is valid , False otherwise\n\n<a id=\"aea.crypto.ledger_apis.LedgerApis.generate_tx_nonce\"></a>\n\n#### generate`_`tx`_`nonce\n\n```python\n@staticmethod\ndef generate_tx_nonce(identifier: str, seller: Address,\n                      client: Address) -> str\n```\n\nGenerate a random str message.\n\n**Arguments**:\n\n- `identifier`: ledger identifier.\n- `seller`: the address of the seller.\n- `client`: the address of the client.\n\n**Returns**:\n\nreturn the hash in hex.\n\n<a id=\"aea.crypto.ledger_apis.LedgerApis.recover_message\"></a>\n\n#### recover`_`message\n\n```python\n@staticmethod\ndef recover_message(identifier: str,\n                    message: bytes,\n                    signature: str,\n                    is_deprecated_mode: bool = False) -> Tuple[Address, ...]\n```\n\nRecover the addresses from the hash.\n\n**Arguments**:\n\n- `identifier`: ledger identifier.\n- `message`: the message we expect\n- `signature`: the transaction signature\n- `is_deprecated_mode`: if the deprecated signing was used\n\n**Returns**:\n\nthe recovered addresses\n\n<a id=\"aea.crypto.ledger_apis.LedgerApis.get_hash\"></a>\n\n#### get`_`hash\n\n```python\n@staticmethod\ndef get_hash(identifier: str, message: bytes) -> str\n```\n\nGet the hash of a message.\n\n**Arguments**:\n\n- `identifier`: ledger identifier.\n- `message`: the message to be hashed.\n\n**Returns**:\n\nthe hash of the message.\n\n<a id=\"aea.crypto.ledger_apis.LedgerApis.is_valid_address\"></a>\n\n#### is`_`valid`_`address\n\n```python\n@staticmethod\ndef is_valid_address(identifier: str, address: Address) -> bool\n```\n\nCheck if the address is valid.\n\n**Arguments**:\n\n- `identifier`: ledger identifier.\n- `address`: the address to validate.\n\n**Returns**:\n\nwhether it is a valid address or not.\n\n"
  },
  {
    "path": "docs/api/crypto/plugin.md",
    "content": "<a id=\"aea.crypto.plugin\"></a>\n\n# aea.crypto.plugin\n\nImplementation of plug-in mechanism for cryptos.\n\n<a id=\"aea.crypto.plugin.Plugin\"></a>\n\n## Plugin Objects\n\n```python\nclass Plugin()\n```\n\nClass that implements an AEA plugin.\n\n<a id=\"aea.crypto.plugin.Plugin.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(group: str, entry_point: EntryPoint)\n```\n\nInitialize the plugin.\n\n**Arguments**:\n\n- `group`: the group the plugin belongs to.\n- `entry_point`: the entrypoint.\n\n<a id=\"aea.crypto.plugin.Plugin.name\"></a>\n\n#### name\n\n```python\n@property\ndef name() -> str\n```\n\nGet the plugin identifier.\n\n<a id=\"aea.crypto.plugin.Plugin.group\"></a>\n\n#### group\n\n```python\n@property\ndef group() -> str\n```\n\nGet the group.\n\n<a id=\"aea.crypto.plugin.Plugin.attr\"></a>\n\n#### attr\n\n```python\n@property\ndef attr() -> str\n```\n\nGet the class name.\n\n<a id=\"aea.crypto.plugin.Plugin.entry_point_path\"></a>\n\n#### entry`_`point`_`path\n\n```python\n@property\ndef entry_point_path() -> str\n```\n\nGet the entry point path.\n\n<a id=\"aea.crypto.plugin.load_all_plugins\"></a>\n\n#### load`_`all`_`plugins\n\n```python\ndef load_all_plugins(is_raising_exception: bool = True) -> None\n```\n\nLoad all plugins.\n\n"
  },
  {
    "path": "docs/api/crypto/registries/base.md",
    "content": "<a id=\"aea.crypto.registries.base\"></a>\n\n# aea.crypto.registries.base\n\nThis module implements the base registry.\n\n<a id=\"aea.crypto.registries.base.ItemId\"></a>\n\n## ItemId Objects\n\n```python\nclass ItemId(RegexConstrainedString)\n```\n\nThe identifier of an item class.\n\n<a id=\"aea.crypto.registries.base.ItemId.name\"></a>\n\n#### name\n\n```python\n@property\ndef name() -> str\n```\n\nGet the id name.\n\n<a id=\"aea.crypto.registries.base.EntryPoint\"></a>\n\n## EntryPoint Objects\n\n```python\nclass EntryPoint(Generic[ItemType], RegexConstrainedString)\n```\n\nThe entry point for a resource.\n\nThe regular expression matches the strings in the following format:\n\n    path.to.module:className\n\n<a id=\"aea.crypto.registries.base.EntryPoint.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(seq: Union[\"EntryPoint\", str]) -> None\n```\n\nInitialize the entrypoint.\n\n<a id=\"aea.crypto.registries.base.EntryPoint.import_path\"></a>\n\n#### import`_`path\n\n```python\n@property\ndef import_path() -> str\n```\n\nGet the import path.\n\n<a id=\"aea.crypto.registries.base.EntryPoint.class_name\"></a>\n\n#### class`_`name\n\n```python\n@property\ndef class_name() -> str\n```\n\nGet the class name.\n\n<a id=\"aea.crypto.registries.base.EntryPoint.load\"></a>\n\n#### load\n\n```python\ndef load() -> Type[ItemType]\n```\n\nLoad the item object.\n\n**Returns**:\n\nthe crypto object, loaded following the spec.\n\n<a id=\"aea.crypto.registries.base.ItemSpec\"></a>\n\n## ItemSpec Objects\n\n```python\nclass ItemSpec(Generic[ItemType])\n```\n\nA specification for a particular instance of an object.\n\n<a id=\"aea.crypto.registries.base.ItemSpec.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(id_: ItemId,\n             entry_point: EntryPoint[ItemType],\n             class_kwargs: Optional[Dict[str, Any]] = None,\n             **kwargs: Dict) -> None\n```\n\nInitialize an item specification.\n\n**Arguments**:\n\n- `id_`: the id associated to this specification\n- `entry_point`: The Python entry_point of the environment class (e.g. module.name:Class).\n- `class_kwargs`: keyword arguments to be attached on the class as class variables.\n- `kwargs`: other custom keyword arguments.\n\n<a id=\"aea.crypto.registries.base.ItemSpec.make\"></a>\n\n#### make\n\n```python\ndef make(**kwargs: Any) -> ItemType\n```\n\nInstantiate an instance of the item object with appropriate arguments.\n\n**Arguments**:\n\n- `kwargs`: the key word arguments\n\n**Returns**:\n\nan item\n\n<a id=\"aea.crypto.registries.base.ItemSpec.get_class\"></a>\n\n#### get`_`class\n\n```python\ndef get_class() -> Type[ItemType]\n```\n\nGet the class of the item with class variables instantiated.\n\n**Returns**:\n\nan item class\n\n<a id=\"aea.crypto.registries.base.Registry\"></a>\n\n## Registry Objects\n\n```python\nclass Registry(Generic[ItemType])\n```\n\nRegistry for generic classes.\n\n<a id=\"aea.crypto.registries.base.Registry.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__() -> None\n```\n\nInitialize the registry.\n\n<a id=\"aea.crypto.registries.base.Registry.supported_ids\"></a>\n\n#### supported`_`ids\n\n```python\n@property\ndef supported_ids() -> Set[str]\n```\n\nGet the supported item ids.\n\n<a id=\"aea.crypto.registries.base.Registry.register\"></a>\n\n#### register\n\n```python\ndef register(id_: Union[ItemId, str],\n             entry_point: Union[EntryPoint[ItemType], str],\n             class_kwargs: Optional[Dict[str, Any]] = None,\n             **kwargs: Any) -> None\n```\n\nRegister an item type.\n\n**Arguments**:\n\n- `id_`: the identifier for the crypto type.\n- `entry_point`: the entry point to load the crypto object.\n- `class_kwargs`: keyword arguments to be attached on the class as class variables.\n- `kwargs`: arguments to provide to the crypto class.\n\n<a id=\"aea.crypto.registries.base.Registry.make\"></a>\n\n#### make\n\n```python\ndef make(id_: Union[ItemId, str],\n         module: Optional[str] = None,\n         **kwargs: Any) -> ItemType\n```\n\nCreate an instance of the associated type item id.\n\n**Arguments**:\n\n- `id_`: the id of the item class. Make sure it has been registered earlier\nbefore calling this function.\n- `module`: dotted path to a module.\nwhether a module should be loaded before creating the object.\nthis argument is useful when the item might not be registered\nbeforehand, and loading the specified module will make the registration.\nE.g. suppose the call to 'register' for a custom object\nis located in some_package/__init__.py. By providing module=\"some_package\",\nthe call to 'register' in such module gets triggered and\nthe make can then find the identifier.\n- `kwargs`: keyword arguments to be forwarded to the object.\n\n**Returns**:\n\nthe new item instance.\n\n<a id=\"aea.crypto.registries.base.Registry.make_cls\"></a>\n\n#### make`_`cls\n\n```python\ndef make_cls(id_: Union[ItemId, str],\n             module: Optional[str] = None) -> Type[ItemType]\n```\n\nLoad a class of the associated type item id.\n\n**Arguments**:\n\n- `id_`: the id of the item class. Make sure it has been registered earlier\nbefore calling this function.\n- `module`: dotted path to a module.\nwhether a module should be loaded before creating the object.\nthis argument is useful when the item might not be registered\nbeforehand, and loading the specified module will make the registration.\nE.g. suppose the call to 'register' for a custom object\nis located in some_package/__init__.py. By providing module=\"some_package\",\nthe call to 'register' in such module gets triggered and\nthe make can then find the identifier.\n\n**Returns**:\n\nthe new item class.\n\n<a id=\"aea.crypto.registries.base.Registry.has_spec\"></a>\n\n#### has`_`spec\n\n```python\ndef has_spec(item_id: ItemId) -> bool\n```\n\nCheck whether there exist a spec associated with an item id.\n\n**Arguments**:\n\n- `item_id`: the item identifier.\n\n**Returns**:\n\nTrue if it is registered, False otherwise.\n\n"
  },
  {
    "path": "docs/api/crypto/wallet.md",
    "content": "<a id=\"aea.crypto.wallet\"></a>\n\n# aea.crypto.wallet\n\nModule wrapping all the public and private keys cryptography.\n\n<a id=\"aea.crypto.wallet.CryptoStore\"></a>\n\n## CryptoStore Objects\n\n```python\nclass CryptoStore()\n```\n\nUtility class to store and retrieve crypto objects.\n\n<a id=\"aea.crypto.wallet.CryptoStore.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(crypto_id_to_path: Optional[Dict[str, Optional[str]]] = None,\n             password: Optional[str] = None) -> None\n```\n\nInitialize the crypto store.\n\n**Arguments**:\n\n- `crypto_id_to_path`: dictionary from crypto id to an (optional) path\nto the private key.\n- `password`: the password to encrypt/decrypt the private key.\n\n<a id=\"aea.crypto.wallet.CryptoStore.public_keys\"></a>\n\n#### public`_`keys\n\n```python\n@property\ndef public_keys() -> Dict[str, str]\n```\n\nGet the public_key dictionary.\n\n<a id=\"aea.crypto.wallet.CryptoStore.crypto_objects\"></a>\n\n#### crypto`_`objects\n\n```python\n@property\ndef crypto_objects() -> Dict[str, Crypto]\n```\n\nGet the crypto objects (key pair).\n\n<a id=\"aea.crypto.wallet.CryptoStore.addresses\"></a>\n\n#### addresses\n\n```python\n@property\ndef addresses() -> Dict[str, str]\n```\n\nGet the crypto addresses.\n\n<a id=\"aea.crypto.wallet.CryptoStore.private_keys\"></a>\n\n#### private`_`keys\n\n```python\n@property\ndef private_keys() -> Dict[str, str]\n```\n\nGet the crypto addresses.\n\n<a id=\"aea.crypto.wallet.Wallet\"></a>\n\n## Wallet Objects\n\n```python\nclass Wallet()\n```\n\nContainer for crypto objects.\n\nThe cryptos are separated into two categories:\n\n- main cryptos: used by the AEA for the economic side (i.e. signing transaction)\n- connection cryptos: exposed to the connection objects for encrypted communication.\n\n<a id=\"aea.crypto.wallet.Wallet.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(\n        private_key_paths: Dict[str, Optional[str]],\n        connection_private_key_paths: Optional[Dict[str,\n                                                    Optional[str]]] = None,\n        password: Optional[str] = None)\n```\n\nInstantiate a wallet object.\n\n**Arguments**:\n\n- `private_key_paths`: the private key paths\n- `connection_private_key_paths`: the private key paths for the connections.\n- `password`: the password to encrypt/decrypt the private key.\n\n<a id=\"aea.crypto.wallet.Wallet.public_keys\"></a>\n\n#### public`_`keys\n\n```python\n@property\ndef public_keys() -> Dict[str, str]\n```\n\nGet the public_key dictionary.\n\n<a id=\"aea.crypto.wallet.Wallet.crypto_objects\"></a>\n\n#### crypto`_`objects\n\n```python\n@property\ndef crypto_objects() -> Dict[str, Crypto]\n```\n\nGet the crypto objects (key pair).\n\n<a id=\"aea.crypto.wallet.Wallet.addresses\"></a>\n\n#### addresses\n\n```python\n@property\ndef addresses() -> Dict[str, str]\n```\n\nGet the crypto addresses.\n\n<a id=\"aea.crypto.wallet.Wallet.private_keys\"></a>\n\n#### private`_`keys\n\n```python\n@property\ndef private_keys() -> Dict[str, str]\n```\n\nGet the crypto addresses.\n\n<a id=\"aea.crypto.wallet.Wallet.main_cryptos\"></a>\n\n#### main`_`cryptos\n\n```python\n@property\ndef main_cryptos() -> CryptoStore\n```\n\nGet the main crypto store.\n\n<a id=\"aea.crypto.wallet.Wallet.connection_cryptos\"></a>\n\n#### connection`_`cryptos\n\n```python\n@property\ndef connection_cryptos() -> CryptoStore\n```\n\nGet the connection crypto store.\n\n<a id=\"aea.crypto.wallet.Wallet.sign_message\"></a>\n\n#### sign`_`message\n\n```python\ndef sign_message(crypto_id: str,\n                 message: bytes,\n                 is_deprecated_mode: bool = False) -> Optional[str]\n```\n\nSign a message.\n\n**Arguments**:\n\n- `crypto_id`: the id of the crypto\n- `message`: the message to be signed\n- `is_deprecated_mode`: what signing mode to use\n\n**Returns**:\n\nthe signature of the message\n\n<a id=\"aea.crypto.wallet.Wallet.sign_transaction\"></a>\n\n#### sign`_`transaction\n\n```python\ndef sign_transaction(crypto_id: str, transaction: Any) -> Optional[JSONLike]\n```\n\nSign a tx.\n\n**Arguments**:\n\n- `crypto_id`: the id of the crypto\n- `transaction`: the transaction to be signed\n\n**Returns**:\n\nthe signed tx\n\n"
  },
  {
    "path": "docs/api/decision_maker/base.md",
    "content": "<a id=\"aea.decision_maker.base\"></a>\n\n# aea.decision`_`maker.base\n\nThis module contains the decision maker class.\n\n<a id=\"aea.decision_maker.base.OwnershipState\"></a>\n\n## OwnershipState Objects\n\n```python\nclass OwnershipState(ABC)\n```\n\nRepresent the ownership state of an agent (can proxy a ledger).\n\n<a id=\"aea.decision_maker.base.OwnershipState.set\"></a>\n\n#### set\n\n```python\n@abstractmethod\ndef set(**kwargs: Any) -> None\n```\n\nSet values on the ownership state.\n\n**Arguments**:\n\n- `kwargs`: the relevant keyword arguments\n\n<a id=\"aea.decision_maker.base.OwnershipState.apply_delta\"></a>\n\n#### apply`_`delta\n\n```python\n@abstractmethod\ndef apply_delta(**kwargs: Any) -> None\n```\n\nApply a state update to the ownership state.\n\nThis method is used to apply a raw state update without a transaction.\n\n**Arguments**:\n\n- `kwargs`: the relevant keyword arguments\n\n<a id=\"aea.decision_maker.base.OwnershipState.is_initialized\"></a>\n\n#### is`_`initialized\n\n```python\n@property\n@abstractmethod\ndef is_initialized() -> bool\n```\n\nGet the initialization status.\n\n<a id=\"aea.decision_maker.base.OwnershipState.is_affordable_transaction\"></a>\n\n#### is`_`affordable`_`transaction\n\n```python\n@abstractmethod\ndef is_affordable_transaction(terms: Terms) -> bool\n```\n\nCheck if the transaction is affordable (and consistent).\n\n**Arguments**:\n\n- `terms`: the transaction terms\n\n**Returns**:\n\nTrue if the transaction is legal wrt the current state, false otherwise.\n\n<a id=\"aea.decision_maker.base.OwnershipState.apply_transactions\"></a>\n\n#### apply`_`transactions\n\n```python\n@abstractmethod\ndef apply_transactions(list_of_terms: List[Terms]) -> \"OwnershipState\"\n```\n\nApply a list of transactions to (a copy of) the current state.\n\n**Arguments**:\n\n- `list_of_terms`: the sequence of transaction terms.\n\n**Returns**:\n\nthe final state.\n\n<a id=\"aea.decision_maker.base.OwnershipState.__copy__\"></a>\n\n#### `__`copy`__`\n\n```python\n@abstractmethod\ndef __copy__() -> \"OwnershipState\"\n```\n\nCopy the object.\n\n<a id=\"aea.decision_maker.base.Preferences\"></a>\n\n## Preferences Objects\n\n```python\nclass Preferences(ABC)\n```\n\nClass to represent the preferences.\n\n<a id=\"aea.decision_maker.base.Preferences.set\"></a>\n\n#### set\n\n```python\n@abstractmethod\ndef set(**kwargs: Any) -> None\n```\n\nSet values on the preferences.\n\n**Arguments**:\n\n- `kwargs`: the relevant key word arguments\n\n<a id=\"aea.decision_maker.base.Preferences.is_initialized\"></a>\n\n#### is`_`initialized\n\n```python\n@property\n@abstractmethod\ndef is_initialized() -> bool\n```\n\nGet the initialization status.\n\nReturns True if exchange_params_by_currency_id and utility_params_by_good_id are not None.\n\n<a id=\"aea.decision_maker.base.Preferences.marginal_utility\"></a>\n\n#### marginal`_`utility\n\n```python\n@abstractmethod\ndef marginal_utility(ownership_state: OwnershipState, **kwargs: Any) -> float\n```\n\nCompute the marginal utility.\n\n**Arguments**:\n\n- `ownership_state`: the ownership state against which to compute the marginal utility.\n- `kwargs`: optional keyword arguments\n\n**Returns**:\n\nthe marginal utility score\n\n<a id=\"aea.decision_maker.base.Preferences.utility_diff_from_transaction\"></a>\n\n#### utility`_`diff`_`from`_`transaction\n\n```python\n@abstractmethod\ndef utility_diff_from_transaction(ownership_state: OwnershipState,\n                                  terms: Terms) -> float\n```\n\nSimulate a transaction and get the resulting utility difference (taking into account the fee).\n\n**Arguments**:\n\n- `ownership_state`: the ownership state against which to apply the transaction.\n- `terms`: the transaction terms.\n\n**Returns**:\n\nthe score.\n\n<a id=\"aea.decision_maker.base.Preferences.__copy__\"></a>\n\n#### `__`copy`__`\n\n```python\n@abstractmethod\ndef __copy__() -> \"Preferences\"\n```\n\nCopy the object.\n\n<a id=\"aea.decision_maker.base.ProtectedQueue\"></a>\n\n## ProtectedQueue Objects\n\n```python\nclass ProtectedQueue(Queue)\n```\n\nA wrapper of a queue to protect which object can read from it.\n\n<a id=\"aea.decision_maker.base.ProtectedQueue.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(access_code: str) -> None\n```\n\nInitialize the protected queue.\n\n**Arguments**:\n\n- `access_code`: the access code to read from the queue\n\n<a id=\"aea.decision_maker.base.ProtectedQueue.put\"></a>\n\n#### put\n\n```python\ndef put(internal_message: Optional[Message],\n        block: bool = True,\n        timeout: Optional[float] = None) -> None\n```\n\nPut an internal message on the queue.\n\nIf optional args block is true and timeout is None (the default),\nblock if necessary until a free slot is available. If timeout is\na positive number, it blocks at most timeout seconds and raises\nthe Full exception if no free slot was available within that time.\nOtherwise (block is false), put an item on the queue if a free slot\nis immediately available, else raise the Full exception (timeout is\nignored in that case).\n\n**Arguments**:\n\n- `internal_message`: the internal message to put on the queue\n- `block`: whether to block or not\n- `timeout`: timeout on block\n\n**Raises**:\n\n- `None`: ValueError, if the item is not an internal message\n\n<a id=\"aea.decision_maker.base.ProtectedQueue.put_nowait\"></a>\n\n#### put`_`nowait\n\n```python\ndef put_nowait(internal_message: Optional[Message]) -> None\n```\n\nPut an internal message on the queue.\n\nEquivalent to put(item, False).\n\n**Arguments**:\n\n- `internal_message`: the internal message to put on the queue\n\n**Raises**:\n\n- `None`: ValueError, if the item is not an internal message\n\n<a id=\"aea.decision_maker.base.ProtectedQueue.get\"></a>\n\n#### get\n\n```python\ndef get(block: bool = True, timeout: Optional[float] = None) -> None\n```\n\nInaccessible get method.\n\n**Arguments**:\n\n- `block`: whether to block or not\n- `timeout`: timeout on block\n\n**Raises**:\n\n- `None`: ValueError, access not permitted.\n\n<a id=\"aea.decision_maker.base.ProtectedQueue.get_nowait\"></a>\n\n#### get`_`nowait\n\n```python\ndef get_nowait() -> None\n```\n\nInaccessible get_nowait method.\n\n**Raises**:\n\n- `None`: ValueError, access not permitted.\n\n<a id=\"aea.decision_maker.base.ProtectedQueue.protected_get\"></a>\n\n#### protected`_`get\n\n```python\ndef protected_get(access_code: str,\n                  block: bool = True,\n                  timeout: Optional[float] = None) -> Optional[Message]\n```\n\nAccess protected get method.\n\n**Arguments**:\n\n- `access_code`: the access code\n- `block`: If optional args block is true and timeout is None (the default), block if necessary until an item is available.\n- `timeout`: If timeout is a positive number, it blocks at most timeout seconds and raises the Empty exception if no item was available within that time.\n\n**Raises**:\n\n- `None`: ValueError, if caller is not permitted\n\n**Returns**:\n\ninternal message\n\n<a id=\"aea.decision_maker.base.DecisionMakerHandler\"></a>\n\n## DecisionMakerHandler Objects\n\n```python\nclass DecisionMakerHandler(WithLogger, ABC)\n```\n\nThis class implements the decision maker.\n\n<a id=\"aea.decision_maker.base.DecisionMakerHandler.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(identity: Identity, wallet: Wallet, config: Dict[str, Any],\n             **kwargs: Any) -> None\n```\n\nInitialize the decision maker handler.\n\n**Arguments**:\n\n- `identity`: the identity\n- `wallet`: the wallet\n- `config`: the user defined configuration of the handler\n- `kwargs`: the key word arguments\n\n<a id=\"aea.decision_maker.base.DecisionMakerHandler.agent_name\"></a>\n\n#### agent`_`name\n\n```python\n@property\ndef agent_name() -> str\n```\n\nGet the agent name.\n\n<a id=\"aea.decision_maker.base.DecisionMakerHandler.identity\"></a>\n\n#### identity\n\n```python\n@property\ndef identity() -> Identity\n```\n\nGet identity of the agent.\n\n<a id=\"aea.decision_maker.base.DecisionMakerHandler.wallet\"></a>\n\n#### wallet\n\n```python\n@property\ndef wallet() -> Wallet\n```\n\nGet wallet of the agent.\n\n<a id=\"aea.decision_maker.base.DecisionMakerHandler.config\"></a>\n\n#### config\n\n```python\n@property\ndef config() -> Dict[str, Any]\n```\n\nGet user defined configuration\n\n<a id=\"aea.decision_maker.base.DecisionMakerHandler.context\"></a>\n\n#### context\n\n```python\n@property\ndef context() -> SimpleNamespace\n```\n\nGet the context.\n\n<a id=\"aea.decision_maker.base.DecisionMakerHandler.message_out_queue\"></a>\n\n#### message`_`out`_`queue\n\n```python\n@property\ndef message_out_queue() -> AsyncFriendlyQueue\n```\n\nGet (out) queue.\n\n<a id=\"aea.decision_maker.base.DecisionMakerHandler.handle\"></a>\n\n#### handle\n\n```python\n@abstractmethod\ndef handle(message: Message) -> None\n```\n\nHandle an internal message from the skills.\n\n**Arguments**:\n\n- `message`: the internal message\n\n<a id=\"aea.decision_maker.base.DecisionMaker\"></a>\n\n## DecisionMaker Objects\n\n```python\nclass DecisionMaker(WithLogger)\n```\n\nThis class implements the decision maker.\n\n<a id=\"aea.decision_maker.base.DecisionMaker.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(decision_maker_handler: DecisionMakerHandler) -> None\n```\n\nInitialize the decision maker.\n\n**Arguments**:\n\n- `decision_maker_handler`: the decision maker handler\n\n<a id=\"aea.decision_maker.base.DecisionMaker.agent_name\"></a>\n\n#### agent`_`name\n\n```python\n@property\ndef agent_name() -> str\n```\n\nGet the agent name.\n\n<a id=\"aea.decision_maker.base.DecisionMaker.message_in_queue\"></a>\n\n#### message`_`in`_`queue\n\n```python\n@property\ndef message_in_queue() -> ProtectedQueue\n```\n\nGet (in) queue.\n\n<a id=\"aea.decision_maker.base.DecisionMaker.message_out_queue\"></a>\n\n#### message`_`out`_`queue\n\n```python\n@property\ndef message_out_queue() -> AsyncFriendlyQueue\n```\n\nGet (out) queue.\n\n<a id=\"aea.decision_maker.base.DecisionMaker.decision_maker_handler\"></a>\n\n#### decision`_`maker`_`handler\n\n```python\n@property\ndef decision_maker_handler() -> DecisionMakerHandler\n```\n\nGet the decision maker handler.\n\n<a id=\"aea.decision_maker.base.DecisionMaker.start\"></a>\n\n#### start\n\n```python\ndef start() -> None\n```\n\nStart the decision maker.\n\n<a id=\"aea.decision_maker.base.DecisionMaker.stop\"></a>\n\n#### stop\n\n```python\ndef stop() -> None\n```\n\nStop the decision maker.\n\n<a id=\"aea.decision_maker.base.DecisionMaker.execute\"></a>\n\n#### execute\n\n```python\ndef execute() -> None\n```\n\nExecute the decision maker.\n\nPerforms the following while not stopped:\n\n- gets internal messages from the in queue and calls handle() on them\n\n<a id=\"aea.decision_maker.base.DecisionMaker.handle\"></a>\n\n#### handle\n\n```python\ndef handle(message: Message) -> None\n```\n\nHandle an internal message from the skills.\n\n**Arguments**:\n\n- `message`: the internal message\n\n"
  },
  {
    "path": "docs/api/decision_maker/default.md",
    "content": "<a id=\"aea.decision_maker.default\"></a>\n\n# aea.decision`_`maker.default\n\nThis module contains the decision maker class.\n\n<a id=\"aea.decision_maker.default.DecisionMakerHandler\"></a>\n\n## DecisionMakerHandler Objects\n\n```python\nclass DecisionMakerHandler(BaseDecisionMakerHandler)\n```\n\nThis class implements the decision maker.\n\n<a id=\"aea.decision_maker.default.DecisionMakerHandler.SigningDialogues\"></a>\n\n## SigningDialogues Objects\n\n```python\nclass SigningDialogues(BaseSigningDialogues)\n```\n\nThis class keeps track of all oef_search dialogues.\n\n<a id=\"aea.decision_maker.default.DecisionMakerHandler.SigningDialogues.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(self_address: Address, **kwargs: Any) -> None\n```\n\nInitialize dialogues.\n\n**Arguments**:\n\n- `self_address`: the address of the entity for whom dialogues are maintained\n- `kwargs`: the keyword arguments\n\n<a id=\"aea.decision_maker.default.DecisionMakerHandler.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(identity: Identity, wallet: Wallet, config: Dict[str,\n                                                              Any]) -> None\n```\n\nInitialize the decision maker.\n\n**Arguments**:\n\n- `identity`: the identity\n- `wallet`: the wallet\n- `config`: the user defined configuration of the handler\n\n<a id=\"aea.decision_maker.default.DecisionMakerHandler.handle\"></a>\n\n#### handle\n\n```python\ndef handle(message: Message) -> None\n```\n\nHandle an internal message from the skills.\n\n**Arguments**:\n\n- `message`: the internal message\n\n"
  },
  {
    "path": "docs/api/decision_maker/gop.md",
    "content": "<a id=\"aea.decision_maker.gop\"></a>\n\n# aea.decision`_`maker.gop\n\nThis module contains the decision maker class.\n\n<a id=\"aea.decision_maker.gop.GoalPursuitReadiness\"></a>\n\n## GoalPursuitReadiness Objects\n\n```python\nclass GoalPursuitReadiness()\n```\n\nThe goal pursuit readiness.\n\n<a id=\"aea.decision_maker.gop.GoalPursuitReadiness.Status\"></a>\n\n## Status Objects\n\n```python\nclass Status(Enum)\n```\n\nThe enum of the readiness status.\n\nIn particular, it can be one of the following:\n\n- Status.READY: when the agent is ready to pursuit its goal\n- Status.NOT_READY: when the agent is not ready to pursuit its goal\n\n<a id=\"aea.decision_maker.gop.GoalPursuitReadiness.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__() -> None\n```\n\nInstantiate the goal pursuit readiness.\n\n<a id=\"aea.decision_maker.gop.GoalPursuitReadiness.is_ready\"></a>\n\n#### is`_`ready\n\n```python\n@property\ndef is_ready() -> bool\n```\n\nGet the readiness.\n\n<a id=\"aea.decision_maker.gop.GoalPursuitReadiness.update\"></a>\n\n#### update\n\n```python\ndef update(new_status: Status) -> None\n```\n\nUpdate the goal pursuit readiness.\n\n**Arguments**:\n\n- `new_status`: the new status\n\n<a id=\"aea.decision_maker.gop.OwnershipState\"></a>\n\n## OwnershipState Objects\n\n```python\nclass OwnershipState(BaseOwnershipState)\n```\n\nRepresent the ownership state of an agent (can proxy a ledger).\n\n<a id=\"aea.decision_maker.gop.OwnershipState.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__() -> None\n```\n\nInstantiate an ownership state object.\n\n<a id=\"aea.decision_maker.gop.OwnershipState.set\"></a>\n\n#### set\n\n```python\ndef set(amount_by_currency_id: CurrencyHoldings = None,\n        quantities_by_good_id: GoodHoldings = None,\n        **kwargs: Any) -> None\n```\n\nSet values on the ownership state.\n\n**Arguments**:\n\n- `amount_by_currency_id`: the currency endowment of the agent in this state.\n- `quantities_by_good_id`: the good endowment of the agent in this state.\n- `kwargs`: the keyword arguments.\n\n<a id=\"aea.decision_maker.gop.OwnershipState.apply_delta\"></a>\n\n#### apply`_`delta\n\n```python\ndef apply_delta(delta_amount_by_currency_id: Dict[str, int] = None,\n                delta_quantities_by_good_id: Dict[str, int] = None,\n                **kwargs: Any) -> None\n```\n\nApply a state update to the ownership state.\n\nThis method is used to apply a raw state update without a transaction.\n\n**Arguments**:\n\n- `delta_amount_by_currency_id`: the delta in the currency amounts\n- `delta_quantities_by_good_id`: the delta in the quantities by good\n- `kwargs`: the keyword arguments\n\n<a id=\"aea.decision_maker.gop.OwnershipState.is_initialized\"></a>\n\n#### is`_`initialized\n\n```python\n@property\ndef is_initialized() -> bool\n```\n\nGet the initialization status.\n\n<a id=\"aea.decision_maker.gop.OwnershipState.amount_by_currency_id\"></a>\n\n#### amount`_`by`_`currency`_`id\n\n```python\n@property\ndef amount_by_currency_id() -> CurrencyHoldings\n```\n\nGet currency holdings in this state.\n\n<a id=\"aea.decision_maker.gop.OwnershipState.quantities_by_good_id\"></a>\n\n#### quantities`_`by`_`good`_`id\n\n```python\n@property\ndef quantities_by_good_id() -> GoodHoldings\n```\n\nGet good holdings in this state.\n\n<a id=\"aea.decision_maker.gop.OwnershipState.is_affordable_transaction\"></a>\n\n#### is`_`affordable`_`transaction\n\n```python\ndef is_affordable_transaction(terms: Terms) -> bool\n```\n\nCheck if the transaction is affordable (and consistent).\n\nE.g. check that the agent state has enough money if it is a buyer or enough holdings if it is a seller.\nNote, the agent is the sender of the transaction message by design.\n\n**Arguments**:\n\n- `terms`: the transaction terms\n\n**Returns**:\n\nTrue if the transaction is legal wrt the current state, false otherwise.\n\n<a id=\"aea.decision_maker.gop.OwnershipState.is_affordable\"></a>\n\n#### is`_`affordable\n\n```python\ndef is_affordable(terms: Terms) -> bool\n```\n\nCheck if the tx is affordable.\n\n**Arguments**:\n\n- `terms`: the transaction terms\n\n**Returns**:\n\nwhether the transaction is affordable or not\n\n<a id=\"aea.decision_maker.gop.OwnershipState.update\"></a>\n\n#### update\n\n```python\ndef update(terms: Terms) -> None\n```\n\nUpdate the agent state from a transaction.\n\n**Arguments**:\n\n- `terms`: the transaction terms\n\n<a id=\"aea.decision_maker.gop.OwnershipState.apply_transactions\"></a>\n\n#### apply`_`transactions\n\n```python\ndef apply_transactions(list_of_terms: List[Terms]) -> \"OwnershipState\"\n```\n\nApply a list of transactions to (a copy of) the current state.\n\n**Arguments**:\n\n- `list_of_terms`: the sequence of transaction terms.\n\n**Returns**:\n\nthe final state.\n\n<a id=\"aea.decision_maker.gop.OwnershipState.__copy__\"></a>\n\n#### `__`copy`__`\n\n```python\ndef __copy__() -> \"OwnershipState\"\n```\n\nCopy the object.\n\n<a id=\"aea.decision_maker.gop.Preferences\"></a>\n\n## Preferences Objects\n\n```python\nclass Preferences(BasePreferences)\n```\n\nClass to represent the preferences.\n\n<a id=\"aea.decision_maker.gop.Preferences.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__() -> None\n```\n\nInstantiate an agent preference object.\n\n<a id=\"aea.decision_maker.gop.Preferences.set\"></a>\n\n#### set\n\n```python\ndef set(exchange_params_by_currency_id: ExchangeParams = None,\n        utility_params_by_good_id: UtilityParams = None,\n        **kwargs: Any) -> None\n```\n\nSet values on the preferences.\n\n**Arguments**:\n\n- `exchange_params_by_currency_id`: the exchange params.\n- `utility_params_by_good_id`: the utility params for every asset.\n- `kwargs`: the keyword arguments.\n\n<a id=\"aea.decision_maker.gop.Preferences.is_initialized\"></a>\n\n#### is`_`initialized\n\n```python\n@property\ndef is_initialized() -> bool\n```\n\nGet the initialization status.\n\n**Returns**:\n\nTrue if exchange_params_by_currency_id and utility_params_by_good_id are not None.\n\n<a id=\"aea.decision_maker.gop.Preferences.exchange_params_by_currency_id\"></a>\n\n#### exchange`_`params`_`by`_`currency`_`id\n\n```python\n@property\ndef exchange_params_by_currency_id() -> ExchangeParams\n```\n\nGet exchange parameter for each currency.\n\n<a id=\"aea.decision_maker.gop.Preferences.utility_params_by_good_id\"></a>\n\n#### utility`_`params`_`by`_`good`_`id\n\n```python\n@property\ndef utility_params_by_good_id() -> UtilityParams\n```\n\nGet utility parameter for each good.\n\n<a id=\"aea.decision_maker.gop.Preferences.logarithmic_utility\"></a>\n\n#### logarithmic`_`utility\n\n```python\ndef logarithmic_utility(quantities_by_good_id: GoodHoldings) -> float\n```\n\nCompute agent's utility given her utility function params and a good bundle.\n\n**Arguments**:\n\n- `quantities_by_good_id`: the good holdings (dictionary) with the identifier (key) and quantity (value) for each good\n\n**Returns**:\n\nutility value\n\n<a id=\"aea.decision_maker.gop.Preferences.linear_utility\"></a>\n\n#### linear`_`utility\n\n```python\ndef linear_utility(amount_by_currency_id: CurrencyHoldings) -> float\n```\n\nCompute agent's utility given her utility function params and a currency bundle.\n\n**Arguments**:\n\n- `amount_by_currency_id`: the currency holdings (dictionary) with the identifier (key) and quantity (value) for each currency\n\n**Returns**:\n\nutility value\n\n<a id=\"aea.decision_maker.gop.Preferences.utility\"></a>\n\n#### utility\n\n```python\ndef utility(quantities_by_good_id: GoodHoldings,\n            amount_by_currency_id: CurrencyHoldings) -> float\n```\n\nCompute the utility given the good and currency holdings.\n\n**Arguments**:\n\n- `quantities_by_good_id`: the good holdings\n- `amount_by_currency_id`: the currency holdings\n\n**Returns**:\n\nthe utility value.\n\n<a id=\"aea.decision_maker.gop.Preferences.marginal_utility\"></a>\n\n#### marginal`_`utility\n\n```python\ndef marginal_utility(\n        ownership_state: BaseOwnershipState,\n        delta_quantities_by_good_id: Optional[GoodHoldings] = None,\n        delta_amount_by_currency_id: Optional[CurrencyHoldings] = None,\n        **kwargs: Any) -> float\n```\n\nCompute the marginal utility.\n\n**Arguments**:\n\n- `ownership_state`: the ownership state against which to compute the marginal utility.\n- `delta_quantities_by_good_id`: the change in good holdings\n- `delta_amount_by_currency_id`: the change in money holdings\n- `kwargs`: the keyword arguments\n\n**Returns**:\n\nthe marginal utility score\n\n<a id=\"aea.decision_maker.gop.Preferences.utility_diff_from_transaction\"></a>\n\n#### utility`_`diff`_`from`_`transaction\n\n```python\ndef utility_diff_from_transaction(ownership_state: BaseOwnershipState,\n                                  terms: Terms) -> float\n```\n\nSimulate a transaction and get the resulting utility difference (taking into account the fee).\n\n**Arguments**:\n\n- `ownership_state`: the ownership state against which to apply the transaction.\n- `terms`: the transaction terms.\n\n**Returns**:\n\nthe score.\n\n<a id=\"aea.decision_maker.gop.Preferences.is_utility_enhancing\"></a>\n\n#### is`_`utility`_`enhancing\n\n```python\ndef is_utility_enhancing(ownership_state: BaseOwnershipState,\n                         terms: Terms) -> bool\n```\n\nCheck if the tx is utility enhancing.\n\n**Arguments**:\n\n- `ownership_state`: the ownership state against which to apply the transaction.\n- `terms`: the transaction terms\n\n**Returns**:\n\nwhether the transaction is utility enhancing or not\n\n<a id=\"aea.decision_maker.gop.Preferences.__copy__\"></a>\n\n#### `__`copy`__`\n\n```python\ndef __copy__() -> \"Preferences\"\n```\n\nCopy the object.\n\n<a id=\"aea.decision_maker.gop.DecisionMakerHandler\"></a>\n\n## DecisionMakerHandler Objects\n\n```python\nclass DecisionMakerHandler(BaseDecisionMakerHandler)\n```\n\nThis class implements the decision maker.\n\n<a id=\"aea.decision_maker.gop.DecisionMakerHandler.SigningDialogues\"></a>\n\n## SigningDialogues Objects\n\n```python\nclass SigningDialogues(BaseSigningDialogues)\n```\n\nThis class keeps track of all oef_search dialogues.\n\n<a id=\"aea.decision_maker.gop.DecisionMakerHandler.SigningDialogues.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(self_address: Address, **kwargs: Any) -> None\n```\n\nInitialize dialogues.\n\n**Arguments**:\n\n- `self_address`: the address of the entity for whom dialogues are maintained\n- `kwargs`: the keyword arguments\n\n<a id=\"aea.decision_maker.gop.DecisionMakerHandler.StateUpdateDialogues\"></a>\n\n## StateUpdateDialogues Objects\n\n```python\nclass StateUpdateDialogues(BaseStateUpdateDialogues)\n```\n\nThis class keeps track of all oef_search dialogues.\n\n<a id=\"aea.decision_maker.gop.DecisionMakerHandler.StateUpdateDialogues.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(self_address: Address, **kwargs: Any) -> None\n```\n\nInitialize dialogues.\n\n**Arguments**:\n\n- `self_address`: the address of the entity for whom dialogues are maintained\n- `kwargs`: the keyword arguments\n\n<a id=\"aea.decision_maker.gop.DecisionMakerHandler.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(identity: Identity, wallet: Wallet, config: Dict[str,\n                                                              Any]) -> None\n```\n\nInitialize the decision maker.\n\n**Arguments**:\n\n- `identity`: the identity\n- `wallet`: the wallet\n- `config`: the user defined configuration of the handler\n\n<a id=\"aea.decision_maker.gop.DecisionMakerHandler.handle\"></a>\n\n#### handle\n\n```python\ndef handle(message: Message) -> None\n```\n\nHandle an internal message from the skills.\n\n**Arguments**:\n\n- `message`: the internal message\n\n"
  },
  {
    "path": "docs/api/error_handler/base.md",
    "content": "<a id=\"aea.error_handler.base\"></a>\n\n# aea.error`_`handler.base\n\nThis module contains the abstract error handler class.\n\n<a id=\"aea.error_handler.base.AbstractErrorHandler\"></a>\n\n## AbstractErrorHandler Objects\n\n```python\nclass AbstractErrorHandler(ABC)\n```\n\nError handler class for handling problematic envelopes.\n\n<a id=\"aea.error_handler.base.AbstractErrorHandler.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(**kwargs: Any)\n```\n\nInstantiate error handler.\n\n<a id=\"aea.error_handler.base.AbstractErrorHandler.config\"></a>\n\n#### config\n\n```python\n@property\ndef config() -> Dict[str, Any]\n```\n\nGet handler config.\n\n<a id=\"aea.error_handler.base.AbstractErrorHandler.send_unsupported_protocol\"></a>\n\n#### send`_`unsupported`_`protocol\n\n```python\n@abstractmethod\ndef send_unsupported_protocol(envelope: Envelope, logger: Logger) -> None\n```\n\nHandle the received envelope in case the protocol is not supported.\n\n**Arguments**:\n\n- `envelope`: the envelope\n- `logger`: the logger\n\n**Returns**:\n\nNone\n\n<a id=\"aea.error_handler.base.AbstractErrorHandler.send_decoding_error\"></a>\n\n#### send`_`decoding`_`error\n\n```python\n@abstractmethod\ndef send_decoding_error(envelope: Envelope, exception: Exception,\n                        logger: Logger) -> None\n```\n\nHandle a decoding error.\n\n**Arguments**:\n\n- `envelope`: the envelope\n- `exception`: the exception raised during decoding\n- `logger`: the logger\n\n**Returns**:\n\nNone\n\n<a id=\"aea.error_handler.base.AbstractErrorHandler.send_no_active_handler\"></a>\n\n#### send`_`no`_`active`_`handler\n\n```python\n@abstractmethod\ndef send_no_active_handler(envelope: Envelope, reason: str,\n                           logger: Logger) -> None\n```\n\nHandle the received envelope in case the handler is not supported.\n\n**Arguments**:\n\n- `envelope`: the envelope\n- `reason`: the reason for the failure\n- `logger`: the logger\n\n**Returns**:\n\nNone\n\n"
  },
  {
    "path": "docs/api/error_handler/default.md",
    "content": "<a id=\"aea.error_handler.default\"></a>\n\n# aea.error`_`handler.default\n\nThis module contains the default error handler class.\n\n<a id=\"aea.error_handler.default.ErrorHandler\"></a>\n\n## ErrorHandler Objects\n\n```python\nclass ErrorHandler(AbstractErrorHandler)\n```\n\nError handler class for handling problematic envelopes.\n\n<a id=\"aea.error_handler.default.ErrorHandler.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(**kwargs: Any)\n```\n\nInstantiate error handler.\n\n<a id=\"aea.error_handler.default.ErrorHandler.send_unsupported_protocol\"></a>\n\n#### send`_`unsupported`_`protocol\n\n```python\ndef send_unsupported_protocol(envelope: Envelope, logger: Logger) -> None\n```\n\nHandle the received envelope in case the protocol is not supported.\n\n**Arguments**:\n\n- `envelope`: the envelope\n- `logger`: the logger\n\n<a id=\"aea.error_handler.default.ErrorHandler.send_decoding_error\"></a>\n\n#### send`_`decoding`_`error\n\n```python\ndef send_decoding_error(envelope: Envelope, exception: Exception,\n                        logger: Logger) -> None\n```\n\nHandle a decoding error.\n\n**Arguments**:\n\n- `envelope`: the envelope\n- `exception`: the exception raised during decoding\n- `logger`: the logger\n\n<a id=\"aea.error_handler.default.ErrorHandler.send_no_active_handler\"></a>\n\n#### send`_`no`_`active`_`handler\n\n```python\ndef send_no_active_handler(envelope: Envelope, reason: str,\n                           logger: Logger) -> None\n```\n\nHandle the received envelope in case the handler is not supported.\n\n**Arguments**:\n\n- `envelope`: the envelope\n- `reason`: the reason for the failure\n- `logger`: the logger\n\n"
  },
  {
    "path": "docs/api/exceptions.md",
    "content": "<a id=\"aea.exceptions\"></a>\n\n# aea.exceptions\n\nExceptions for the AEA package.\n\n<a id=\"aea.exceptions.AEAException\"></a>\n\n## AEAException Objects\n\n```python\nclass AEAException(Exception)\n```\n\nUser-defined exception for the AEA framework.\n\n<a id=\"aea.exceptions.AEAPackageLoadingError\"></a>\n\n## AEAPackageLoadingError Objects\n\n```python\nclass AEAPackageLoadingError(AEAException)\n```\n\nClass for exceptions that are raised for loading errors of AEA packages.\n\n<a id=\"aea.exceptions.AEASetupError\"></a>\n\n## AEASetupError Objects\n\n```python\nclass AEASetupError(AEAException)\n```\n\nClass for exceptions that are raised for setup errors of AEA packages.\n\n<a id=\"aea.exceptions.AEATeardownError\"></a>\n\n## AEATeardownError Objects\n\n```python\nclass AEATeardownError(AEAException)\n```\n\nClass for exceptions that are raised for teardown errors of AEA packages.\n\n<a id=\"aea.exceptions.AEAActException\"></a>\n\n## AEAActException Objects\n\n```python\nclass AEAActException(AEAException)\n```\n\nClass for exceptions that are raised for act errors of AEA packages.\n\n<a id=\"aea.exceptions.AEAHandleException\"></a>\n\n## AEAHandleException Objects\n\n```python\nclass AEAHandleException(AEAException)\n```\n\nClass for exceptions that are raised for handler errors of AEA packages.\n\n<a id=\"aea.exceptions.AEAInstantiationException\"></a>\n\n## AEAInstantiationException Objects\n\n```python\nclass AEAInstantiationException(AEAException)\n```\n\nClass for exceptions that are raised for instantiation errors of AEA packages.\n\n<a id=\"aea.exceptions.AEAPluginError\"></a>\n\n## AEAPluginError Objects\n\n```python\nclass AEAPluginError(AEAException)\n```\n\nClass for exceptions that are raised for wrong plugin setup of the working set.\n\n<a id=\"aea.exceptions.AEAEnforceError\"></a>\n\n## AEAEnforceError Objects\n\n```python\nclass AEAEnforceError(AEAException)\n```\n\nClass for enforcement errors.\n\n<a id=\"aea.exceptions.AEAValidationError\"></a>\n\n## AEAValidationError Objects\n\n```python\nclass AEAValidationError(AEAException)\n```\n\nClass for validation errors of an AEA.\n\n<a id=\"aea.exceptions.AEAComponentLoadException\"></a>\n\n## AEAComponentLoadException Objects\n\n```python\nclass AEAComponentLoadException(AEAException)\n```\n\nClass for component loading errors of an AEA.\n\n<a id=\"aea.exceptions.AEAWalletNoAddressException\"></a>\n\n## AEAWalletNoAddressException Objects\n\n```python\nclass AEAWalletNoAddressException(AEAException)\n```\n\nClass for attempts to instantiate a wallet without addresses.\n\n<a id=\"aea.exceptions._StopRuntime\"></a>\n\n## `_`StopRuntime Objects\n\n```python\nclass _StopRuntime(Exception)\n```\n\nException to stop runtime.\n\nFor internal usage only!\nUsed to perform asyncio call from sync callbacks.\n\n<a id=\"aea.exceptions._StopRuntime.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(reraise: Optional[Exception] = None) -> None\n```\n\nInit _StopRuntime exception.\n\n**Arguments**:\n\n- `reraise`: exception to reraise.\n\n<a id=\"aea.exceptions.enforce\"></a>\n\n#### enforce\n\n```python\ndef enforce(is_valid_condition: bool,\n            exception_text: str,\n            exception_class: Type[Exception] = AEAEnforceError) -> None\n```\n\nEvaluate a condition and raise an exception with the provided text if it is not satisfied.\n\n**Arguments**:\n\n- `is_valid_condition`: the valid condition\n- `exception_text`: the exception to be raised\n- `exception_class`: the class of exception\n\n<a id=\"aea.exceptions.parse_exception\"></a>\n\n#### parse`_`exception\n\n```python\ndef parse_exception(exception: Exception, limit: int = -1) -> str\n```\n\nParse an exception to get the relevant lines.\n\n**Arguments**:\n\n- `exception`: the exception to be parsed\n- `limit`: the limit\n\n**Returns**:\n\nexception as string\n\n"
  },
  {
    "path": "docs/api/helpers/acn/agent_record.md",
    "content": "<a id=\"aea.helpers.acn.agent_record\"></a>\n\n# aea.helpers.acn.agent`_`record\n\nThis module contains types and helpers for ACN Proof-of-Representation.\n\n<a id=\"aea.helpers.acn.agent_record.AgentRecord\"></a>\n\n## AgentRecord Objects\n\n```python\nclass AgentRecord()\n```\n\nAgent Proof-of-Representation to representative.\n\n<a id=\"aea.helpers.acn.agent_record.AgentRecord.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(address: str, representative_public_key: str,\n             identifier: SimpleIdOrStr, ledger_id: SimpleIdOrStr,\n             not_before: str, not_after: str, message_format: str,\n             signature: str) -> None\n```\n\nInitialize the AgentRecord\n\n**Arguments**:\n\n- `address`: agent address\n- `representative_public_key`: representative's public key\n- `identifier`: certificate identifier.\n- `ledger_id`: ledger identifier the request is referring to.\n- `not_before`: specify the lower bound for certificate validity. If it is a string, it must follow the format: 'YYYY-MM-DD'. It will be interpreted as timezone UTC-0.\n- `not_after`: specify the lower bound for certificate validity. If it is a string, it must follow the format: 'YYYY-MM-DD'. It will be interpreted as timezone UTC-0.\n- `message_format`: message format used for signing\n- `signature`: proof-of-representation of this AgentRecord\n\n<a id=\"aea.helpers.acn.agent_record.AgentRecord.address\"></a>\n\n#### address\n\n```python\n@property\ndef address() -> str\n```\n\nGet agent address\n\n<a id=\"aea.helpers.acn.agent_record.AgentRecord.public_key\"></a>\n\n#### public`_`key\n\n```python\n@property\ndef public_key() -> str\n```\n\nGet agent public key\n\n<a id=\"aea.helpers.acn.agent_record.AgentRecord.representative_public_key\"></a>\n\n#### representative`_`public`_`key\n\n```python\n@property\ndef representative_public_key() -> str\n```\n\nGet agent representative's public key\n\n<a id=\"aea.helpers.acn.agent_record.AgentRecord.signature\"></a>\n\n#### signature\n\n```python\n@property\ndef signature() -> str\n```\n\nGet record signature\n\n<a id=\"aea.helpers.acn.agent_record.AgentRecord.message\"></a>\n\n#### message\n\n```python\n@property\ndef message() -> bytes\n```\n\nGet the message.\n\n<a id=\"aea.helpers.acn.agent_record.AgentRecord.identifier\"></a>\n\n#### identifier\n\n```python\n@property\ndef identifier() -> SimpleIdOrStr\n```\n\nGet the identifier.\n\n<a id=\"aea.helpers.acn.agent_record.AgentRecord.ledger_id\"></a>\n\n#### ledger`_`id\n\n```python\n@property\ndef ledger_id() -> SimpleIdOrStr\n```\n\nGet ledger id.\n\n<a id=\"aea.helpers.acn.agent_record.AgentRecord.not_before\"></a>\n\n#### not`_`before\n\n```python\n@property\ndef not_before() -> str\n```\n\nGet the not_before field.\n\n<a id=\"aea.helpers.acn.agent_record.AgentRecord.not_after\"></a>\n\n#### not`_`after\n\n```python\n@property\ndef not_after() -> str\n```\n\nGet the not_after field.\n\n<a id=\"aea.helpers.acn.agent_record.AgentRecord.message_format\"></a>\n\n#### message`_`format\n\n```python\n@property\ndef message_format() -> str\n```\n\nGet the message format.\n\n<a id=\"aea.helpers.acn.agent_record.AgentRecord.__str__\"></a>\n\n#### `__`str`__`\n\n```python\ndef __str__() -> str\n```\n\nGet string representation.\n\n<a id=\"aea.helpers.acn.agent_record.AgentRecord.from_cert_request\"></a>\n\n#### from`_`cert`_`request\n\n```python\n@classmethod\ndef from_cert_request(cls,\n                      cert_request: CertRequest,\n                      address: str,\n                      representative_public_key: str,\n                      data_dir: Optional[PathLike] = None) -> \"AgentRecord\"\n```\n\nGet agent record from cert request.\n\n"
  },
  {
    "path": "docs/api/helpers/acn/uri.md",
    "content": "<a id=\"aea.helpers.acn.uri\"></a>\n\n# aea.helpers.acn.uri\n\nThis module contains types and helpers for libp2p connections Uris.\n\n<a id=\"aea.helpers.acn.uri.Uri\"></a>\n\n## Uri Objects\n\n```python\nclass Uri()\n```\n\nHolds a node address in format \"host:port\".\n\n<a id=\"aea.helpers.acn.uri.Uri.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(uri: Optional[str] = None,\n             host: Optional[str] = None,\n             port: Optional[int] = None) -> None\n```\n\nInitialise Uri.\n\n<a id=\"aea.helpers.acn.uri.Uri.__str__\"></a>\n\n#### `__`str`__`\n\n```python\ndef __str__() -> str\n```\n\nGet string representation.\n\n<a id=\"aea.helpers.acn.uri.Uri.__repr__\"></a>\n\n#### `__`repr`__`\n\n```python\ndef __repr__() -> str\n```\n\nGet object representation.\n\n<a id=\"aea.helpers.acn.uri.Uri.host\"></a>\n\n#### host\n\n```python\n@property\ndef host() -> str\n```\n\nGet host.\n\n<a id=\"aea.helpers.acn.uri.Uri.port\"></a>\n\n#### port\n\n```python\n@property\ndef port() -> int\n```\n\nGet port.\n\n"
  },
  {
    "path": "docs/api/helpers/async_friendly_queue.md",
    "content": "<a id=\"aea.helpers.async_friendly_queue\"></a>\n\n# aea.helpers.async`_`friendly`_`queue\n\nThis module contains the implementation of AsyncFriendlyQueue.\n\n<a id=\"aea.helpers.async_friendly_queue.AsyncFriendlyQueue\"></a>\n\n## AsyncFriendlyQueue Objects\n\n```python\nclass AsyncFriendlyQueue(queue.Queue)\n```\n\nqueue.Queue with async_get method.\n\n<a id=\"aea.helpers.async_friendly_queue.AsyncFriendlyQueue.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(*args: Any, **kwargs: Any) -> None\n```\n\nInit queue.\n\n<a id=\"aea.helpers.async_friendly_queue.AsyncFriendlyQueue.put\"></a>\n\n#### put\n\n```python\ndef put(item: Any, *args: Any, **kwargs: Any) -> None\n```\n\nPut an item into the queue.\n\n**Arguments**:\n\n- `item`: item to put in the queue\n- `args`: similar to queue.Queue.put\n- `kwargs`: similar to queue.Queue.put\n\n<a id=\"aea.helpers.async_friendly_queue.AsyncFriendlyQueue.get\"></a>\n\n#### get\n\n```python\ndef get(*args: Any, **kwargs: Any) -> Any\n```\n\nGet an item into the queue.\n\n**Arguments**:\n\n- `args`: similar to queue.Queue.get\n- `kwargs`: similar to queue.Queue.get\n\n**Returns**:\n\nsimilar to queue.Queue.get\n\n<a id=\"aea.helpers.async_friendly_queue.AsyncFriendlyQueue.async_wait\"></a>\n\n#### async`_`wait\n\n```python\nasync def async_wait() -> None\n```\n\nWait an item appears in the queue.\n\n**Returns**:\n\nNone\n\n<a id=\"aea.helpers.async_friendly_queue.AsyncFriendlyQueue.async_get\"></a>\n\n#### async`_`get\n\n```python\nasync def async_get() -> Any\n```\n\nWait and get an item from the queue.\n\n**Returns**:\n\nitem from queue\n\n"
  },
  {
    "path": "docs/api/helpers/async_utils.md",
    "content": "<a id=\"aea.helpers.async_utils\"></a>\n\n# aea.helpers.async`_`utils\n\nThis module contains the misc utils for async code.\n\n<a id=\"aea.helpers.async_utils.ensure_list\"></a>\n\n#### ensure`_`list\n\n```python\ndef ensure_list(value: Any) -> List\n```\n\nReturn [value] or list(value) if value is a sequence.\n\n<a id=\"aea.helpers.async_utils.AsyncState\"></a>\n\n## AsyncState Objects\n\n```python\nclass AsyncState()\n```\n\nAwaitable state.\n\n<a id=\"aea.helpers.async_utils.AsyncState.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(initial_state: Any = None,\n             states_enum: Optional[Container[Any]] = None) -> None\n```\n\nInit async state.\n\n**Arguments**:\n\n- `initial_state`: state to set on start.\n- `states_enum`: container of valid states if not provided state not checked on set.\n\n<a id=\"aea.helpers.async_utils.AsyncState.set\"></a>\n\n#### set\n\n```python\ndef set(state: Any) -> None\n```\n\nSet state.\n\n<a id=\"aea.helpers.async_utils.AsyncState.add_callback\"></a>\n\n#### add`_`callback\n\n```python\ndef add_callback(callback_fn: Callable[[Any], None]) -> None\n```\n\nAdd callback to track state changes.\n\n**Arguments**:\n\n- `callback_fn`: callable object to be called on state changed.\n\n<a id=\"aea.helpers.async_utils.AsyncState.get\"></a>\n\n#### get\n\n```python\ndef get() -> Any\n```\n\nGet state.\n\n<a id=\"aea.helpers.async_utils.AsyncState.wait\"></a>\n\n#### wait\n\n```python\nasync def wait(state_or_states: Union[Any, Sequence[Any]]) -> Tuple[Any, Any]\n```\n\nWait state to be set.\n\n**Arguments**:\n\n- `state_or_states`: state or list of states.\n\n**Returns**:\n\ntuple of previous state and new state.\n\n<a id=\"aea.helpers.async_utils.AsyncState.transit\"></a>\n\n#### transit\n\n```python\n@contextmanager\ndef transit(initial: Any = not_set,\n            success: Any = not_set,\n            fail: Any = not_set) -> Generator\n```\n\nChange state context according to success or not.\n\n**Arguments**:\n\n- `initial`: set state on context enter, not_set by default\n- `success`: set state on context block done, not_set by default\n- `fail`: set state on context block raises exception, not_set by default\n\n**Returns**:\n\ngenerator\n\n<a id=\"aea.helpers.async_utils.PeriodicCaller\"></a>\n\n## PeriodicCaller Objects\n\n```python\nclass PeriodicCaller()\n```\n\nSchedule a periodic call of callable using event loop.\n\nUsed for periodic function run using asyncio.\n\n<a id=\"aea.helpers.async_utils.PeriodicCaller.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(callback: Callable,\n             period: float,\n             start_at: Optional[datetime.datetime] = None,\n             exception_callback: Optional[Callable[[Callable, Exception],\n                                                   None]] = None,\n             loop: Optional[AbstractEventLoop] = None) -> None\n```\n\nInit periodic caller.\n\n**Arguments**:\n\n- `callback`: function to call periodically\n- `period`: period in seconds.\n- `start_at`: optional first call datetime\n- `exception_callback`: optional handler to call on exception raised.\n- `loop`: optional asyncio event loop\n\n<a id=\"aea.helpers.async_utils.PeriodicCaller.start\"></a>\n\n#### start\n\n```python\ndef start() -> None\n```\n\nActivate period calls.\n\n<a id=\"aea.helpers.async_utils.PeriodicCaller.stop\"></a>\n\n#### stop\n\n```python\ndef stop() -> None\n```\n\nRemove from schedule.\n\n<a id=\"aea.helpers.async_utils.AnotherThreadTask\"></a>\n\n## AnotherThreadTask Objects\n\n```python\nclass AnotherThreadTask()\n```\n\nSchedule a task to run on the loop in another thread.\n\nProvides better cancel behaviour: on cancel it will wait till cancelled completely.\n\n<a id=\"aea.helpers.async_utils.AnotherThreadTask.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(coro: Coroutine[Any, Any, Any], loop: AbstractEventLoop) -> None\n```\n\nInit the task.\n\n**Arguments**:\n\n- `coro`: coroutine to schedule\n- `loop`: an event loop to schedule on.\n\n<a id=\"aea.helpers.async_utils.AnotherThreadTask.result\"></a>\n\n#### result\n\n```python\ndef result(timeout: Optional[float] = None) -> Any\n```\n\nWait for coroutine execution result.\n\n**Arguments**:\n\n- `timeout`: optional timeout to wait in seconds.\n\n**Returns**:\n\nresult\n\n<a id=\"aea.helpers.async_utils.AnotherThreadTask.cancel\"></a>\n\n#### cancel\n\n```python\ndef cancel() -> None\n```\n\nCancel coroutine task execution in a target loop.\n\n<a id=\"aea.helpers.async_utils.AnotherThreadTask.done\"></a>\n\n#### done\n\n```python\ndef done() -> bool\n```\n\nCheck task is done.\n\n<a id=\"aea.helpers.async_utils.ThreadedAsyncRunner\"></a>\n\n## ThreadedAsyncRunner Objects\n\n```python\nclass ThreadedAsyncRunner(Thread)\n```\n\nUtil to run thread with event loop and execute coroutines inside.\n\n<a id=\"aea.helpers.async_utils.ThreadedAsyncRunner.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(loop: Optional[AbstractEventLoop] = None) -> None\n```\n\nInit threaded runner.\n\n**Arguments**:\n\n- `loop`: optional event loop. is it's running loop, threaded runner will use it.\n\n<a id=\"aea.helpers.async_utils.ThreadedAsyncRunner.start\"></a>\n\n#### start\n\n```python\ndef start() -> None\n```\n\nStart event loop in dedicated thread.\n\n<a id=\"aea.helpers.async_utils.ThreadedAsyncRunner.run\"></a>\n\n#### run\n\n```python\ndef run() -> None\n```\n\nRun code inside thread.\n\n<a id=\"aea.helpers.async_utils.ThreadedAsyncRunner.call\"></a>\n\n#### call\n\n```python\ndef call(coro: Coroutine[Any, Any, Any]) -> Any\n```\n\nRun a coroutine inside the event loop.\n\n**Arguments**:\n\n- `coro`: a coroutine to run.\n\n**Returns**:\n\ntask\n\n<a id=\"aea.helpers.async_utils.ThreadedAsyncRunner.stop\"></a>\n\n#### stop\n\n```python\ndef stop() -> None\n```\n\nStop event loop in thread.\n\n<a id=\"aea.helpers.async_utils.Runnable\"></a>\n\n## Runnable Objects\n\n```python\nclass Runnable(ABC)\n```\n\nAbstract Runnable class.\n\nUse to run async task in same event loop or in dedicated thread.\nProvides: start, stop sync methods to start and stop task\nUse wait_completed to await task was completed.\n\n<a id=\"aea.helpers.async_utils.Runnable.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(loop: asyncio.AbstractEventLoop = None,\n             threaded: bool = False) -> None\n```\n\nInit runnable.\n\n**Arguments**:\n\n- `loop`: asyncio event loop to use.\n- `threaded`: bool. start in thread if True.\n\n<a id=\"aea.helpers.async_utils.Runnable.start\"></a>\n\n#### start\n\n```python\ndef start() -> bool\n```\n\nStart runnable.\n\n**Returns**:\n\nbool started or not.\n\n<a id=\"aea.helpers.async_utils.Runnable.is_running\"></a>\n\n#### is`_`running\n\n```python\n@property\ndef is_running() -> bool\n```\n\nGet running state.\n\n<a id=\"aea.helpers.async_utils.Runnable.run\"></a>\n\n#### run\n\n```python\n@abstractmethod\nasync def run() -> Any\n```\n\nImplement run logic respectful to CancelError on termination.\n\n<a id=\"aea.helpers.async_utils.Runnable.wait_completed\"></a>\n\n#### wait`_`completed\n\n```python\ndef wait_completed(sync: bool = False,\n                   timeout: float = None,\n                   force_result: bool = False) -> Union[Coroutine, Awaitable]\n```\n\nWait runnable execution completed.\n\n**Arguments**:\n\n- `sync`: bool. blocking wait\n- `timeout`: float seconds\n- `force_result`: check result even it was waited.\n\n**Returns**:\n\nawaitable if sync is False, otherwise None\n\n<a id=\"aea.helpers.async_utils.Runnable.stop\"></a>\n\n#### stop\n\n```python\ndef stop(force: bool = False) -> None\n```\n\nStop runnable.\n\n<a id=\"aea.helpers.async_utils.Runnable.start_and_wait_completed\"></a>\n\n#### start`_`and`_`wait`_`completed\n\n```python\ndef start_and_wait_completed(*args: Any,\n                             **kwargs: Any) -> Union[Coroutine, Awaitable]\n```\n\nAlias for start and wait methods.\n\n"
  },
  {
    "path": "docs/api/helpers/base.md",
    "content": "<a id=\"aea.helpers.base\"></a>\n\n# aea.helpers.base\n\nMiscellaneous helpers.\n\n<a id=\"aea.helpers.base.locate\"></a>\n\n#### locate\n\n```python\ndef locate(path: str) -> Any\n```\n\nLocate an object by name or dotted save_path, importing as necessary.\n\n<a id=\"aea.helpers.base.load_module\"></a>\n\n#### load`_`module\n\n```python\ndef load_module(dotted_path: str, filepath: Path) -> types.ModuleType\n```\n\nLoad a module.\n\n**Arguments**:\n\n- `dotted_path`: the dotted save_path of the package/module.\n- `filepath`: the file to the package/module.\n\n**Raises**:\n\n- `ValueError`: if the filepath provided is not a module.  # noqa: DAR402\n- `Exception`: if the execution of the module raises exception.  # noqa: DAR402\n\n**Returns**:\n\nmodule type\n\n<a id=\"aea.helpers.base.load_env_file\"></a>\n\n#### load`_`env`_`file\n\n```python\ndef load_env_file(env_file: str) -> None\n```\n\nLoad the content of the environment file into the process environment.\n\n**Arguments**:\n\n- `env_file`: save_path to the env file.\n\n<a id=\"aea.helpers.base.sigint_crossplatform\"></a>\n\n#### sigint`_`crossplatform\n\n```python\ndef sigint_crossplatform(process: subprocess.Popen) -> None\n```\n\nSend a SIGINT, cross-platform.\n\nThe reason is because the subprocess module\ndoesn't have an API to send a SIGINT-like signal\nboth on Posix and Windows with a single method.\n\nHowever, a subprocess.Popen class has the method\n'send_signal' that gives more flexibility in this terms.\n\n**Arguments**:\n\n- `process`: the process to send the signal to.\n\n<a id=\"aea.helpers.base.win_popen_kwargs\"></a>\n\n#### win`_`popen`_`kwargs\n\n```python\ndef win_popen_kwargs() -> dict\n```\n\nReturn kwargs to start a process in windows with new process group.\n\nHelp to handle ctrl c properly.\nReturn empty dict if platform is not win32\n\n**Returns**:\n\nwindows popen kwargs\n\n<a id=\"aea.helpers.base.send_control_c\"></a>\n\n#### send`_`control`_`c\n\n```python\ndef send_control_c(process: subprocess.Popen,\n                   kill_group: bool = False) -> None\n```\n\nSend ctrl-C cross-platform to terminate a subprocess.\n\n**Arguments**:\n\n- `process`: the process to send the signal to.\n- `kill_group`: whether or not to kill group\n\n<a id=\"aea.helpers.base.RegexConstrainedString\"></a>\n\n## RegexConstrainedString Objects\n\n```python\nclass RegexConstrainedString(UserString)\n```\n\nA string that is constrained by a regex.\n\nThe default behaviour is to match anything.\nSubclass this class and change the 'REGEX' class\nattribute to implement a different behaviour.\n\n<a id=\"aea.helpers.base.RegexConstrainedString.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(seq: Union[UserString, str]) -> None\n```\n\nInitialize a regex constrained string.\n\n<a id=\"aea.helpers.base.SimpleId\"></a>\n\n## SimpleId Objects\n\n```python\nclass SimpleId(RegexConstrainedString)\n```\n\nA simple identifier.\n\nThe allowed strings are all the strings that:\n- have at least length 1\n- have at most length 128\n- the first character must be between a-z,A-Z or underscore\n- the other characters must be either the above or digits.\n\nExamples of allowed strings:\n>>> SimpleId(\"an_identifier\")\n'an_identifier'\n\nExamples of not allowed strings:\n>>> SimpleId(\"0an_identifier\")\nTraceback (most recent call last):\n...\nValueError: Value 0an_identifier does not match the regular expression re.compile('[a-zA-Z_][a-zA-Z0-9_]{0,127}')\n\n>>> SimpleId(\"an identifier\")\nTraceback (most recent call last):\n...\nValueError: Value an identifier does not match the regular expression re.compile('[a-zA-Z_][a-zA-Z0-9_]{0,127}')\n\n>>> SimpleId(\"\")\nTraceback (most recent call last):\n...\nValueError: Value  does not match the regular expression re.compile('[a-zA-Z_][a-zA-Z0-9_]{0,127}')\n\n<a id=\"aea.helpers.base.cd\"></a>\n\n#### cd\n\n```python\n@contextlib.contextmanager\ndef cd(path: PathLike) -> Generator\n```\n\nChange working directory temporarily.\n\n<a id=\"aea.helpers.base.get_logger_method\"></a>\n\n#### get`_`logger`_`method\n\n```python\ndef get_logger_method(fn: Callable,\n                      logger_method: Union[str, Callable]) -> Callable\n```\n\nGet logger method for function.\n\nGet logger in `fn` definition module or creates logger is module.__name__.\nOr return logger_method if it's callable.\n\n**Arguments**:\n\n- `fn`: function to get logger for.\n- `logger_method`: logger name or callable.\n\n**Returns**:\n\ncallable to write log with\n\n<a id=\"aea.helpers.base.try_decorator\"></a>\n\n#### try`_`decorator\n\n```python\ndef try_decorator(error_message: str,\n                  default_return: Callable = None,\n                  logger_method: Any = \"error\") -> Callable\n```\n\nRun function, log and return default value on exception.\n\nDoes not support async or coroutines!\n\n**Arguments**:\n\n- `error_message`: message template with one `{}` for exception\n- `default_return`: value to return on exception, by default None\n- `logger_method`: name of the logger method or callable to print logs\n\n**Returns**:\n\nthe callable\n\n<a id=\"aea.helpers.base.MaxRetriesError\"></a>\n\n## MaxRetriesError Objects\n\n```python\nclass MaxRetriesError(Exception)\n```\n\nException for retry decorator.\n\n<a id=\"aea.helpers.base.retry_decorator\"></a>\n\n#### retry`_`decorator\n\n```python\ndef retry_decorator(number_of_retries: int,\n                    error_message: str,\n                    delay: float = 0,\n                    logger_method: str = \"error\") -> Callable\n```\n\nRun function with several attempts.\n\nDoes not support async or coroutines!\n\n**Arguments**:\n\n- `number_of_retries`: amount of attempts\n- `error_message`: message template with one `{}` for exception\n- `delay`: number of seconds to sleep between retries. default 0\n- `logger_method`: name of the logger method or callable to print logs\n\n**Returns**:\n\nthe callable\n\n<a id=\"aea.helpers.base.exception_log_and_reraise\"></a>\n\n#### exception`_`log`_`and`_`reraise\n\n```python\n@contextlib.contextmanager\ndef exception_log_and_reraise(log_method: Callable, message: str) -> Generator\n```\n\nRun code in context to log and re raise exception.\n\n**Arguments**:\n\n- `log_method`: function to print log\n- `message`: message template to add error text.\n\n**Returns**:\n\nthe generator\n\n<a id=\"aea.helpers.base.recursive_update\"></a>\n\n#### recursive`_`update\n\n```python\ndef recursive_update(to_update: Dict,\n                     new_values: Dict,\n                     allow_new_values: bool = False) -> None\n```\n\nUpdate a dictionary by replacing conflicts with the new values.\n\nIt does side-effects to the first dictionary.\n\n>>> to_update = dict(a=1, b=2, subdict=dict(subfield1=1))\n>>> new_values = dict(b=3, subdict=dict(subfield1=2))\n>>> recursive_update(to_update, new_values)\n>>> to_update\n{'a': 1, 'b': 3, 'subdict': {'subfield1': 2}}\n\n**Arguments**:\n\n- `to_update`: the dictionary to update.\n- `new_values`: the dictionary of new values to replace.\n- `allow_new_values`: whether or not to allow new values.\n\n<a id=\"aea.helpers.base.find_topological_order\"></a>\n\n#### find`_`topological`_`order\n\n```python\ndef find_topological_order(adjacency_list: Dict[T, Set[T]]) -> List[T]\n```\n\nCompute the topological order of a graph (using Kahn's algorithm).\n\n**Arguments**:\n\n- `adjacency_list`: the adjacency list of the graph.\n\n**Raises**:\n\n- `ValueError`: if the graph contains a cycle.\n\n**Returns**:\n\nthe topological order for the graph (as a sequence of nodes)\n\n<a id=\"aea.helpers.base.reachable_nodes\"></a>\n\n#### reachable`_`nodes\n\n```python\ndef reachable_nodes(adjacency_list: Dict[T, Set[T]],\n                    starting_nodes: Set[T]) -> Dict[T, Set[T]]\n```\n\nFind the reachable subgraph induced by a set of starting nodes.\n\n**Arguments**:\n\n- `adjacency_list`: the adjacency list of the full graph.\n- `starting_nodes`: the starting nodes of the new graph.\n\n**Returns**:\n\nthe adjacency list of the subgraph.\n\n<a id=\"aea.helpers.base.cached_property\"></a>\n\n## cached`_`property Objects\n\n```python\nclass cached_property()\n```\n\nCached property from python3.8 functools.\n\n<a id=\"aea.helpers.base.cached_property.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(func: Callable) -> None\n```\n\nInit cached property.\n\n<a id=\"aea.helpers.base.cached_property.__set_name__\"></a>\n\n#### `__`set`_`name`__`\n\n```python\ndef __set_name__(_: Any, name: Any) -> None\n```\n\nSet name.\n\n<a id=\"aea.helpers.base.cached_property.__get__\"></a>\n\n#### `__`get`__`\n\n```python\ndef __get__(instance: Any, _: Optional[Any] = None) -> Any\n```\n\nGet instance.\n\n<a id=\"aea.helpers.base.ensure_dir\"></a>\n\n#### ensure`_`dir\n\n```python\ndef ensure_dir(dir_path: str) -> None\n```\n\nCheck if dir_path is a directory or create it.\n\n<a id=\"aea.helpers.base.dict_to_path_value\"></a>\n\n#### dict`_`to`_`path`_`value\n\n```python\ndef dict_to_path_value(\n        data: Mapping,\n        path: Optional[List] = None) -> Iterable[Tuple[List[str], Any]]\n```\n\nConvert dict to sequence of terminal path build of  keys and value.\n\n<a id=\"aea.helpers.base.parse_datetime_from_str\"></a>\n\n#### parse`_`datetime`_`from`_`str\n\n```python\ndef parse_datetime_from_str(date_string: str) -> datetime.datetime\n```\n\nParse datetime from string.\n\n<a id=\"aea.helpers.base.CertRequest\"></a>\n\n## CertRequest Objects\n\n```python\nclass CertRequest()\n```\n\nCertificate request for proof of representation.\n\n<a id=\"aea.helpers.base.CertRequest.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(public_key: str, identifier: SimpleIdOrStr,\n             ledger_id: SimpleIdOrStr, not_before: str, not_after: str,\n             message_format: str, save_path: str) -> None\n```\n\nInitialize the certificate request.\n\n**Arguments**:\n\n- `public_key`: the public key, or the key id.\n- `identifier`: certificate identifier.\n- `ledger_id`: ledger identifier the request is referring to.\n- `not_before`: specify the lower bound for certificate validity. If it is a string, it must follow the format: 'YYYY-MM-DD'. It will be interpreted as timezone UTC-0.\n- `not_after`: specify the lower bound for certificate validity. If it is a string, it must follow the format: 'YYYY-MM-DD'. It will be interpreted as timezone UTC-0.\n- `message_format`: message format used for signing\n- `save_path`: the save_path where to save the certificate.\n\n<a id=\"aea.helpers.base.CertRequest.public_key\"></a>\n\n#### public`_`key\n\n```python\n@property\ndef public_key() -> Optional[str]\n```\n\nGet the public key.\n\n<a id=\"aea.helpers.base.CertRequest.ledger_id\"></a>\n\n#### ledger`_`id\n\n```python\n@property\ndef ledger_id() -> str\n```\n\nGet the ledger id.\n\n<a id=\"aea.helpers.base.CertRequest.key_identifier\"></a>\n\n#### key`_`identifier\n\n```python\n@property\ndef key_identifier() -> Optional[str]\n```\n\nGet the key identifier.\n\n<a id=\"aea.helpers.base.CertRequest.identifier\"></a>\n\n#### identifier\n\n```python\n@property\ndef identifier() -> str\n```\n\nGet the identifier.\n\n<a id=\"aea.helpers.base.CertRequest.not_before_string\"></a>\n\n#### not`_`before`_`string\n\n```python\n@property\ndef not_before_string() -> str\n```\n\nGet the not_before field as string.\n\n<a id=\"aea.helpers.base.CertRequest.not_after_string\"></a>\n\n#### not`_`after`_`string\n\n```python\n@property\ndef not_after_string() -> str\n```\n\nGet the not_after field as string.\n\n<a id=\"aea.helpers.base.CertRequest.not_before\"></a>\n\n#### not`_`before\n\n```python\n@property\ndef not_before() -> datetime.datetime\n```\n\nGet the not_before field.\n\n<a id=\"aea.helpers.base.CertRequest.not_after\"></a>\n\n#### not`_`after\n\n```python\n@property\ndef not_after() -> datetime.datetime\n```\n\nGet the not_after field.\n\n<a id=\"aea.helpers.base.CertRequest.message_format\"></a>\n\n#### message`_`format\n\n```python\n@property\ndef message_format() -> str\n```\n\nGet the message format.\n\n<a id=\"aea.helpers.base.CertRequest.save_path\"></a>\n\n#### save`_`path\n\n```python\n@property\ndef save_path() -> Path\n```\n\nGet the save path for the certificate.\n\nNote: if the path is *not* absolute, then\nthe actual save path might depend on the context.\n\n**Returns**:\n\nthe save path\n\n<a id=\"aea.helpers.base.CertRequest.get_absolute_save_path\"></a>\n\n#### get`_`absolute`_`save`_`path\n\n```python\ndef get_absolute_save_path(path_prefix: Optional[PathLike] = None) -> Path\n```\n\nGet the absolute save path.\n\nIf save_path is an absolute path, then the prefix is ignored.\nOtherwise, the path prefix is prepended.\n\n**Arguments**:\n\n- `path_prefix`: the (absolute) path to prepend to the save path.\n\n**Returns**:\n\nthe actual save path.\n\n<a id=\"aea.helpers.base.CertRequest.public_key_or_identifier\"></a>\n\n#### public`_`key`_`or`_`identifier\n\n```python\n@property\ndef public_key_or_identifier() -> str\n```\n\nGet the public key or identifier.\n\n<a id=\"aea.helpers.base.CertRequest.get_message\"></a>\n\n#### get`_`message\n\n```python\ndef get_message(public_key: str) -> bytes\n```\n\nGet the message to sign.\n\n<a id=\"aea.helpers.base.CertRequest.construct_message\"></a>\n\n#### construct`_`message\n\n```python\n@classmethod\ndef construct_message(cls, public_key: str, identifier: SimpleIdOrStr,\n                      not_before_string: str, not_after_string: str,\n                      message_format: str) -> bytes\n```\n\nConstruct message for singning.\n\n**Arguments**:\n\n- `public_key`: the public key\n- `identifier`: identifier to be signed\n- `not_before_string`: signature not valid before\n- `not_after_string`: signature not valid after\n- `message_format`: message format used for signing\n\n**Returns**:\n\nthe message\n\n<a id=\"aea.helpers.base.CertRequest.get_signature\"></a>\n\n#### get`_`signature\n\n```python\ndef get_signature(path_prefix: Optional[PathLike] = None) -> str\n```\n\nGet signature from save_path.\n\n**Arguments**:\n\n- `path_prefix`: the path prefix to be prepended to save_path. Defaults to cwd.\n\n**Returns**:\n\nthe signature.\n\n<a id=\"aea.helpers.base.CertRequest.json\"></a>\n\n#### json\n\n```python\n@property\ndef json() -> Dict\n```\n\nCompute the JSON representation.\n\n<a id=\"aea.helpers.base.CertRequest.from_json\"></a>\n\n#### from`_`json\n\n```python\n@classmethod\ndef from_json(cls, obj: Dict) -> \"CertRequest\"\n```\n\nCompute the JSON representation.\n\n<a id=\"aea.helpers.base.CertRequest.__eq__\"></a>\n\n#### `__`eq`__`\n\n```python\ndef __eq__(other: Any) -> bool\n```\n\nCheck equality.\n\n<a id=\"aea.helpers.base.compute_specifier_from_version\"></a>\n\n#### compute`_`specifier`_`from`_`version\n\n```python\ndef compute_specifier_from_version(version: Version) -> str\n```\n\nCompute the specifier set from a version.\n\nversion specifier is:  >=major.minor.0, <next_major.0.0\n\n**Arguments**:\n\n- `version`: the version\n\n**Returns**:\n\nthe specifier set\n\n<a id=\"aea.helpers.base.decorator_with_optional_params\"></a>\n\n#### decorator`_`with`_`optional`_`params\n\n```python\ndef decorator_with_optional_params(decorator: Callable) -> Callable\n```\n\nMake a decorator usable either with or without parameters.\n\nIn other words, if a decorator \"mydecorator\" is decorated with this decorator,\nIt can be used both as:\n\n@mydecorator\ndef myfunction():\n    ...\n\nor as:\n\n@mydecorator(arg1, kwarg1=\"value\")\ndef myfunction():\n    ...\n\n**Arguments**:\n\n- `decorator`: a decorator callable\n\n**Returns**:\n\na decorator callable\n\n<a id=\"aea.helpers.base.delete_directory_contents\"></a>\n\n#### delete`_`directory`_`contents\n\n```python\ndef delete_directory_contents(directory: Path) -> None\n```\n\nDelete the content of a directory, without deleting it.\n\n<a id=\"aea.helpers.base.prepend_if_not_absolute\"></a>\n\n#### prepend`_`if`_`not`_`absolute\n\n```python\ndef prepend_if_not_absolute(path: PathLike, prefix: PathLike) -> PathLike\n```\n\nPrepend a path with a prefix, but only if not absolute\n\n**Arguments**:\n\n- `path`: the path to process.\n- `prefix`: the path prefix.\n\n**Returns**:\n\nthe same path if absolute, else the prepended path.\n\n"
  },
  {
    "path": "docs/api/helpers/constants.md",
    "content": "<a id=\"aea.helpers.constants\"></a>\n\n# aea.helpers.constants\n\nModule with helpers constants.\n\n"
  },
  {
    "path": "docs/api/helpers/env_vars.md",
    "content": "<a id=\"aea.helpers.env_vars\"></a>\n\n# aea.helpers.env`_`vars\n\nImplementation of the environment variables support.\n\n<a id=\"aea.helpers.env_vars.is_env_variable\"></a>\n\n#### is`_`env`_`variable\n\n```python\ndef is_env_variable(value: Any) -> bool\n```\n\nCheck is variable string with env variable pattern.\n\n<a id=\"aea.helpers.env_vars.replace_with_env_var\"></a>\n\n#### replace`_`with`_`env`_`var\n\n```python\ndef replace_with_env_var(value: str,\n                         env_variables: dict,\n                         default_value: Any = NotSet) -> JSON_TYPES\n```\n\nReplace env var with value.\n\n<a id=\"aea.helpers.env_vars.apply_env_variables\"></a>\n\n#### apply`_`env`_`variables\n\n```python\ndef apply_env_variables(data: Union[Dict, List[Dict]],\n                        env_variables: Mapping[str, Any],\n                        default_value: Any = NotSet) -> JSON_TYPES\n```\n\nCreate new resulting dict with env variables applied.\n\n<a id=\"aea.helpers.env_vars.convert_value_str_to_type\"></a>\n\n#### convert`_`value`_`str`_`to`_`type\n\n```python\ndef convert_value_str_to_type(value: str, type_str: str) -> JSON_TYPES\n```\n\nConvert value by type name to native python type.\n\n"
  },
  {
    "path": "docs/api/helpers/exception_policy.md",
    "content": "<a id=\"aea.helpers.exception_policy\"></a>\n\n# aea.helpers.exception`_`policy\n\nThis module contains enum of aea exception policies.\n\n<a id=\"aea.helpers.exception_policy.ExceptionPolicyEnum\"></a>\n\n## ExceptionPolicyEnum Objects\n\n```python\nclass ExceptionPolicyEnum(Enum)\n```\n\nAEA Exception policies.\n\n"
  },
  {
    "path": "docs/api/helpers/exec_timeout.md",
    "content": "<a id=\"aea.helpers.exec_timeout\"></a>\n\n# aea.helpers.exec`_`timeout\n\nPython code execution time limit tools.\n\n<a id=\"aea.helpers.exec_timeout.TimeoutResult\"></a>\n\n## TimeoutResult Objects\n\n```python\nclass TimeoutResult()\n```\n\nResult of ExecTimeout context manager.\n\n<a id=\"aea.helpers.exec_timeout.TimeoutResult.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__() -> None\n```\n\nInit.\n\n<a id=\"aea.helpers.exec_timeout.TimeoutResult.set_cancelled_by_timeout\"></a>\n\n#### set`_`cancelled`_`by`_`timeout\n\n```python\ndef set_cancelled_by_timeout() -> None\n```\n\nSet code was terminated cause timeout.\n\n<a id=\"aea.helpers.exec_timeout.TimeoutResult.is_cancelled_by_timeout\"></a>\n\n#### is`_`cancelled`_`by`_`timeout\n\n```python\ndef is_cancelled_by_timeout() -> bool\n```\n\nReturn True if code was terminated by ExecTimeout cause timeout.\n\n**Returns**:\n\nbool\n\n<a id=\"aea.helpers.exec_timeout.TimeoutException\"></a>\n\n## TimeoutException Objects\n\n```python\nclass TimeoutException(BaseException)\n```\n\nTimeoutException raised by ExecTimeout context managers in thread with limited execution time.\n\nUsed internally, does not propagated outside of context manager\n\n<a id=\"aea.helpers.exec_timeout.BaseExecTimeout\"></a>\n\n## BaseExecTimeout Objects\n\n```python\nclass BaseExecTimeout(ABC)\n```\n\nBase class for implementing context managers to limit python code execution time.\n\nexception_class - is exception type to raise in code controlled in case of timeout.\n\n<a id=\"aea.helpers.exec_timeout.BaseExecTimeout.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(timeout: float = 0.0) -> None\n```\n\nInit.\n\n**Arguments**:\n\n- `timeout`: number of seconds to execute code before interruption\n\n<a id=\"aea.helpers.exec_timeout.BaseExecTimeout.__enter__\"></a>\n\n#### `__`enter`__`\n\n```python\ndef __enter__() -> TimeoutResult\n```\n\nEnter context manager.\n\n**Returns**:\n\nTimeoutResult\n\n<a id=\"aea.helpers.exec_timeout.BaseExecTimeout.__exit__\"></a>\n\n#### `__`exit`__`\n\n```python\ndef __exit__(exc_type: Type[Exception], exc_val: Exception,\n             exc_tb: TracebackType) -> None\n```\n\nExit context manager.\n\n**Arguments**:\n\n- `exc_type`: the exception type\n- `exc_val`: the exception\n- `exc_tb`: the traceback\n\n<a id=\"aea.helpers.exec_timeout.ExecTimeoutSigAlarm\"></a>\n\n## ExecTimeoutSigAlarm Objects\n\n```python\nclass ExecTimeoutSigAlarm(BaseExecTimeout)\n```\n\nExecTimeout context manager implementation using signals and SIGALARM.\n\nDoes not support threads, have to be used only in main thread.\n\n<a id=\"aea.helpers.exec_timeout.ExecTimeoutThreadGuard\"></a>\n\n## ExecTimeoutThreadGuard Objects\n\n```python\nclass ExecTimeoutThreadGuard(BaseExecTimeout)\n```\n\nExecTimeout context manager implementation using threads and PyThreadState_SetAsyncExc.\n\nSupport threads.\nRequires supervisor thread start/stop to control execution time control.\nPossible will be not accurate in case of long c functions used inside code controlled.\n\n<a id=\"aea.helpers.exec_timeout.ExecTimeoutThreadGuard.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(timeout: float = 0.0) -> None\n```\n\nInit ExecTimeoutThreadGuard variables.\n\n**Arguments**:\n\n- `timeout`: number of seconds to execute code before interruption\n\n<a id=\"aea.helpers.exec_timeout.ExecTimeoutThreadGuard.start\"></a>\n\n#### start\n\n```python\n@classmethod\ndef start(cls) -> None\n```\n\nStart supervisor thread to check timeouts.\n\nSupervisor starts once but number of start counted.\n\n<a id=\"aea.helpers.exec_timeout.ExecTimeoutThreadGuard.stop\"></a>\n\n#### stop\n\n```python\n@classmethod\ndef stop(cls, force: bool = False) -> None\n```\n\nStop supervisor thread.\n\nActual stop performed on force == True or if  number of stops == number of starts\n\n**Arguments**:\n\n- `force`: force stop regardless number of start.\n\n"
  },
  {
    "path": "docs/api/helpers/file_io.md",
    "content": "<a id=\"aea.helpers.file_io\"></a>\n\n# aea.helpers.file`_`io\n\nRead to and write from file with envelopes.\n\n<a id=\"aea.helpers.file_io.lock_file\"></a>\n\n#### lock`_`file\n\n```python\n@contextmanager\ndef lock_file(file_descriptor: IO[bytes],\n              logger: Logger = _default_logger) -> Generator\n```\n\nLock file in context manager.\n\n**Arguments**:\n\n- `file_descriptor`: file descriptor of file to lock.\n- `logger`: the logger.\n\n**Returns**:\n\ngenerator\n\n<a id=\"aea.helpers.file_io.write_envelope\"></a>\n\n#### write`_`envelope\n\n```python\ndef write_envelope(envelope: Envelope,\n                   file_pointer: IO[bytes],\n                   separator: bytes = SEPARATOR,\n                   logger: Logger = _default_logger) -> None\n```\n\nWrite envelope to file.\n\n<a id=\"aea.helpers.file_io.write_with_lock\"></a>\n\n#### write`_`with`_`lock\n\n```python\ndef write_with_lock(file_pointer: IO[bytes],\n                    data: Union[bytes],\n                    logger: Logger = _default_logger) -> None\n```\n\nWrite bytes to file protected with file lock.\n\n<a id=\"aea.helpers.file_io.envelope_from_bytes\"></a>\n\n#### envelope`_`from`_`bytes\n\n```python\ndef envelope_from_bytes(\n        bytes_: bytes,\n        separator: bytes = SEPARATOR,\n        logger: Logger = _default_logger) -> Optional[Envelope]\n```\n\nDecode bytes to get the envelope.\n\n**Arguments**:\n\n- `bytes_`: the encoded envelope\n- `separator`: the separator used\n- `logger`: the logger\n\n**Returns**:\n\nEnvelope\n\n"
  },
  {
    "path": "docs/api/helpers/file_lock.md",
    "content": "<a id=\"aea.helpers.file_lock\"></a>\n\n# aea.helpers.file`_`lock\n\nPatch of 'fnctl' to make it compatible with Windows.\n\n"
  },
  {
    "path": "docs/api/helpers/http_requests.md",
    "content": "<a id=\"aea.helpers.http_requests\"></a>\n\n# aea.helpers.http`_`requests\n\nWrapper over requests library.\n\n<a id=\"aea.helpers.http_requests.add_default_timeout\"></a>\n\n#### add`_`default`_`timeout\n\n```python\ndef add_default_timeout(fn: Callable, timeout: float) -> Callable\n```\n\nAdd default timeout for requests methods.\n\n"
  },
  {
    "path": "docs/api/helpers/install_dependency.md",
    "content": "<a id=\"aea.helpers.install_dependency\"></a>\n\n# aea.helpers.install`_`dependency\n\nHelper to install python dependencies.\n\n<a id=\"aea.helpers.install_dependency.install_dependency\"></a>\n\n#### install`_`dependency\n\n```python\ndef install_dependency(dependency_name: str,\n                       dependency: Dependency,\n                       logger: Logger,\n                       install_timeout: float = 300) -> None\n```\n\nInstall python dependency to the current python environment.\n\n**Arguments**:\n\n- `dependency_name`: name of the python package\n- `dependency`: Dependency specification\n- `logger`: the logger\n- `install_timeout`: timeout to wait pip to install\n\n<a id=\"aea.helpers.install_dependency.install_dependencies\"></a>\n\n#### install`_`dependencies\n\n```python\ndef install_dependencies(dependencies: List[Dependency],\n                         logger: Logger,\n                         install_timeout: float = 300) -> None\n```\n\nInstall python dependencies to the current python environment.\n\n**Arguments**:\n\n- `dependencies`: dict of dependency name and specification\n- `logger`: the logger\n- `install_timeout`: timeout to wait pip to install\n\n<a id=\"aea.helpers.install_dependency.call_pip\"></a>\n\n#### call`_`pip\n\n```python\ndef call_pip(pip_args: List[str],\n             timeout: float = 300,\n             retry: bool = False) -> None\n```\n\nRun pip install command.\n\n**Arguments**:\n\n- `pip_args`: list strings of the command\n- `timeout`: timeout to wait pip to install\n- `retry`: bool, try one more time if command failed\n\n<a id=\"aea.helpers.install_dependency.run_install_subprocess\"></a>\n\n#### run`_`install`_`subprocess\n\n```python\ndef run_install_subprocess(install_command: List[str],\n                           install_timeout: float = 300) -> int\n```\n\nTry executing install command.\n\n**Arguments**:\n\n- `install_command`: list strings of the command\n- `install_timeout`: timeout to wait pip to install\n\n**Returns**:\n\nthe return code of the subprocess\n\n"
  },
  {
    "path": "docs/api/helpers/io.md",
    "content": "<a id=\"aea.helpers.io\"></a>\n\n# aea.helpers.io\n\n"
  },
  {
    "path": "docs/api/helpers/ipfs/base.md",
    "content": "<a id=\"aea.helpers.ipfs.base\"></a>\n\n# aea.helpers.ipfs.base\n\nThis module contains helper methods and classes for the 'aea' package.\n\n<a id=\"aea.helpers.ipfs.base.chunks\"></a>\n\n#### chunks\n\n```python\ndef chunks(data: Sized, size: int) -> Generator\n```\n\nYield successivesize chunks from data.\n\n<a id=\"aea.helpers.ipfs.base.IPFSHashOnly\"></a>\n\n## IPFSHashOnly Objects\n\n```python\nclass IPFSHashOnly()\n```\n\nA helper class which allows construction of an IPFS hash without interacting with an IPFS daemon.\n\n<a id=\"aea.helpers.ipfs.base.IPFSHashOnly.get\"></a>\n\n#### get\n\n```python\ndef get(file_path: str) -> str\n```\n\nGet the IPFS hash for a single file.\n\n**Arguments**:\n\n- `file_path`: the file path\n\n**Returns**:\n\nthe ipfs hash\n\n"
  },
  {
    "path": "docs/api/helpers/ipfs/utils.md",
    "content": "<a id=\"aea.helpers.ipfs.utils\"></a>\n\n# aea.helpers.ipfs.utils\n\nThis module contains utility methods for ipfs helpers.\n\n"
  },
  {
    "path": "docs/api/helpers/logging.md",
    "content": "<a id=\"aea.helpers.logging\"></a>\n\n# aea.helpers.logging\n\nLogging helpers.\n\n<a id=\"aea.helpers.logging.get_logger\"></a>\n\n#### get`_`logger\n\n```python\ndef get_logger(module_path: str, agent_name: str) -> Logger\n```\n\nGet the logger based on a module path and agent name.\n\n<a id=\"aea.helpers.logging.AgentLoggerAdapter\"></a>\n\n## AgentLoggerAdapter Objects\n\n```python\nclass AgentLoggerAdapter(LoggerAdapter)\n```\n\nThis class is a logger adapter that prepends the agent name to log messages.\n\n<a id=\"aea.helpers.logging.AgentLoggerAdapter.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(logger: Logger, agent_name: str) -> None\n```\n\nInitialize the logger adapter.\n\n**Arguments**:\n\n- `logger`: the logger.\n- `agent_name`: the agent name.\n\n<a id=\"aea.helpers.logging.AgentLoggerAdapter.process\"></a>\n\n#### process\n\n```python\ndef process(\n        msg: Any,\n        kwargs: MutableMapping[str,\n                               Any]) -> Tuple[Any, MutableMapping[str, Any]]\n```\n\nPrepend the agent name to every log message.\n\n<a id=\"aea.helpers.logging.WithLogger\"></a>\n\n## WithLogger Objects\n\n```python\nclass WithLogger()\n```\n\nInterface to endow subclasses with a logger.\n\n<a id=\"aea.helpers.logging.WithLogger.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(logger: Optional[Logger] = None,\n             default_logger_name: str = \"aea\") -> None\n```\n\nInitialize the logger.\n\n**Arguments**:\n\n- `logger`: the logger object.\n- `default_logger_name`: the default logger name, if a logger is not provided.\n\n<a id=\"aea.helpers.logging.WithLogger.logger\"></a>\n\n#### logger\n\n```python\n@property\ndef logger() -> Logger\n```\n\nGet the component logger.\n\n<a id=\"aea.helpers.logging.WithLogger.logger\"></a>\n\n#### logger\n\n```python\n@logger.setter\ndef logger(logger: Optional[Logger]) -> None\n```\n\nSet the logger.\n\n"
  },
  {
    "path": "docs/api/helpers/multiaddr/base.md",
    "content": "<a id=\"aea.helpers.multiaddr.base\"></a>\n\n# aea.helpers.multiaddr.base\n\nThis module contains multiaddress class.\n\n<a id=\"aea.helpers.multiaddr.base.MultiAddr\"></a>\n\n## MultiAddr Objects\n\n```python\nclass MultiAddr()\n```\n\nProtocol Labs' Multiaddress representation of a network address.\n\n<a id=\"aea.helpers.multiaddr.base.MultiAddr.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(host: str,\n             port: int,\n             public_key: Optional[str] = None,\n             multihash_id: Optional[str] = None) -> None\n```\n\nInitialize a multiaddress.\n\n**Arguments**:\n\n- `host`: ip host of the address\n- `port`: port number of the address\n- `public_key`: hex encoded public key. Must conform to Bitcoin EC encoding standard for Secp256k1\n- `multihash_id`: a multihash of the public key\n\n<a id=\"aea.helpers.multiaddr.base.MultiAddr.compute_peerid\"></a>\n\n#### compute`_`peerid\n\n```python\n@staticmethod\ndef compute_peerid(public_key: str) -> str\n```\n\nCompute the peer id from a public key.\n\nIn particular, compute the base58 representation of\nlibp2p PeerID from Bitcoin EC encoded Secp256k1 public key.\n\n**Arguments**:\n\n- `public_key`: the public key.\n\n**Returns**:\n\nthe peer id.\n\n<a id=\"aea.helpers.multiaddr.base.MultiAddr.from_string\"></a>\n\n#### from`_`string\n\n```python\n@classmethod\ndef from_string(cls, maddr: str) -> \"MultiAddr\"\n```\n\nConstruct a MultiAddr object from its string format\n\n**Arguments**:\n\n- `maddr`: multiaddress string\n\n**Returns**:\n\nmultiaddress object\n\n<a id=\"aea.helpers.multiaddr.base.MultiAddr.public_key\"></a>\n\n#### public`_`key\n\n```python\n@property\ndef public_key() -> str\n```\n\nGet the public key.\n\n<a id=\"aea.helpers.multiaddr.base.MultiAddr.peer_id\"></a>\n\n#### peer`_`id\n\n```python\n@property\ndef peer_id() -> str\n```\n\nGet the peer id.\n\n<a id=\"aea.helpers.multiaddr.base.MultiAddr.host\"></a>\n\n#### host\n\n```python\n@property\ndef host() -> str\n```\n\nGet the peer host.\n\n<a id=\"aea.helpers.multiaddr.base.MultiAddr.port\"></a>\n\n#### port\n\n```python\n@property\ndef port() -> int\n```\n\nGet the peer port.\n\n<a id=\"aea.helpers.multiaddr.base.MultiAddr.format\"></a>\n\n#### format\n\n```python\ndef format() -> str\n```\n\nCanonical representation of a multiaddress.\n\n<a id=\"aea.helpers.multiaddr.base.MultiAddr.__str__\"></a>\n\n#### `__`str`__`\n\n```python\ndef __str__() -> str\n```\n\nDefault string representation of a multiaddress.\n\n"
  },
  {
    "path": "docs/api/helpers/multiple_executor.md",
    "content": "<a id=\"aea.helpers.multiple_executor\"></a>\n\n# aea.helpers.multiple`_`executor\n\nThis module contains the helpers to run multiple stoppable tasks in different modes: async, threaded, multiprocess .\n\n<a id=\"aea.helpers.multiple_executor.ExecutorExceptionPolicies\"></a>\n\n## ExecutorExceptionPolicies Objects\n\n```python\nclass ExecutorExceptionPolicies(Enum)\n```\n\nRunner exception policy modes.\n\n<a id=\"aea.helpers.multiple_executor.AbstractExecutorTask\"></a>\n\n## AbstractExecutorTask Objects\n\n```python\nclass AbstractExecutorTask(ABC)\n```\n\nAbstract task class to create Task classes.\n\n<a id=\"aea.helpers.multiple_executor.AbstractExecutorTask.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__() -> None\n```\n\nInit task.\n\n<a id=\"aea.helpers.multiple_executor.AbstractExecutorTask.future\"></a>\n\n#### future\n\n```python\n@property\ndef future() -> Optional[TaskAwaitable]\n```\n\nReturn awaitable to get result of task execution.\n\n<a id=\"aea.helpers.multiple_executor.AbstractExecutorTask.future\"></a>\n\n#### future\n\n```python\n@future.setter\ndef future(future: TaskAwaitable) -> None\n```\n\nSet awaitable to get result of task execution.\n\n<a id=\"aea.helpers.multiple_executor.AbstractExecutorTask.start\"></a>\n\n#### start\n\n```python\n@abstractmethod\ndef start() -> Tuple[Callable, Sequence[Any]]\n```\n\nImplement start task function here.\n\n<a id=\"aea.helpers.multiple_executor.AbstractExecutorTask.stop\"></a>\n\n#### stop\n\n```python\n@abstractmethod\ndef stop() -> None\n```\n\nImplement stop task function here.\n\n<a id=\"aea.helpers.multiple_executor.AbstractExecutorTask.create_async_task\"></a>\n\n#### create`_`async`_`task\n\n```python\n@abstractmethod\ndef create_async_task(loop: AbstractEventLoop) -> TaskAwaitable\n```\n\nCreate asyncio task for task run in asyncio loop.\n\n**Arguments**:\n\n- `loop`: the event loop\n\n**Returns**:\n\ntask to run in asyncio loop.\n\n<a id=\"aea.helpers.multiple_executor.AbstractExecutorTask.id\"></a>\n\n#### id\n\n```python\n@property\ndef id() -> Any\n```\n\nReturn task id.\n\n<a id=\"aea.helpers.multiple_executor.AbstractExecutorTask.failed\"></a>\n\n#### failed\n\n```python\n@property\ndef failed() -> bool\n```\n\nReturn was exception failed or not.\n\nIf it's running it's not failed.\n\n**Returns**:\n\nbool\n\n<a id=\"aea.helpers.multiple_executor.AbstractMultiprocessExecutorTask\"></a>\n\n## AbstractMultiprocessExecutorTask Objects\n\n```python\nclass AbstractMultiprocessExecutorTask(AbstractExecutorTask)\n```\n\nTask for multiprocess executor.\n\n<a id=\"aea.helpers.multiple_executor.AbstractMultiprocessExecutorTask.start\"></a>\n\n#### start\n\n```python\n@abstractmethod\ndef start() -> Tuple[Callable, Sequence[Any]]\n```\n\nReturn function and arguments to call within subprocess.\n\n<a id=\"aea.helpers.multiple_executor.AbstractMultiprocessExecutorTask.create_async_task\"></a>\n\n#### create`_`async`_`task\n\n```python\ndef create_async_task(loop: AbstractEventLoop) -> TaskAwaitable\n```\n\nCreate asyncio task for task run in asyncio loop.\n\nRaise error, cause async mode is not supported, cause this task for multiprocess executor only.\n\n**Arguments**:\n\n- `loop`: the event loop\n\n**Raises**:\n\n- `ValueError`: async task construction not possible\n\n<a id=\"aea.helpers.multiple_executor.AbstractMultipleExecutor\"></a>\n\n## AbstractMultipleExecutor Objects\n\n```python\nclass AbstractMultipleExecutor(ABC)\n```\n\nAbstract class to create multiple executors classes.\n\n<a id=\"aea.helpers.multiple_executor.AbstractMultipleExecutor.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(\n    tasks: Sequence[AbstractExecutorTask],\n    task_fail_policy: ExecutorExceptionPolicies = ExecutorExceptionPolicies.\n    propagate\n) -> None\n```\n\nInit executor.\n\n**Arguments**:\n\n- `tasks`: sequence of AbstractExecutorTask instances to run.\n- `task_fail_policy`: the exception policy of all the tasks\n\n<a id=\"aea.helpers.multiple_executor.AbstractMultipleExecutor.is_running\"></a>\n\n#### is`_`running\n\n```python\n@property\ndef is_running() -> bool\n```\n\nReturn running state of the executor.\n\n<a id=\"aea.helpers.multiple_executor.AbstractMultipleExecutor.start\"></a>\n\n#### start\n\n```python\ndef start() -> None\n```\n\nStart tasks.\n\n<a id=\"aea.helpers.multiple_executor.AbstractMultipleExecutor.stop\"></a>\n\n#### stop\n\n```python\ndef stop() -> None\n```\n\nStop tasks.\n\n<a id=\"aea.helpers.multiple_executor.AbstractMultipleExecutor.num_failed\"></a>\n\n#### num`_`failed\n\n```python\n@property\ndef num_failed() -> int\n```\n\nReturn number of failed tasks.\n\n<a id=\"aea.helpers.multiple_executor.AbstractMultipleExecutor.failed_tasks\"></a>\n\n#### failed`_`tasks\n\n```python\n@property\ndef failed_tasks() -> Sequence[AbstractExecutorTask]\n```\n\nReturn sequence failed tasks.\n\n<a id=\"aea.helpers.multiple_executor.AbstractMultipleExecutor.not_failed_tasks\"></a>\n\n#### not`_`failed`_`tasks\n\n```python\n@property\ndef not_failed_tasks() -> Sequence[AbstractExecutorTask]\n```\n\nReturn sequence successful tasks.\n\n<a id=\"aea.helpers.multiple_executor.ThreadExecutor\"></a>\n\n## ThreadExecutor Objects\n\n```python\nclass ThreadExecutor(AbstractMultipleExecutor)\n```\n\nThread based executor to run multiple agents in threads.\n\n<a id=\"aea.helpers.multiple_executor.ProcessExecutor\"></a>\n\n## ProcessExecutor Objects\n\n```python\nclass ProcessExecutor(ThreadExecutor)\n```\n\nSubprocess based executor to run multiple agents in threads.\n\n<a id=\"aea.helpers.multiple_executor.AsyncExecutor\"></a>\n\n## AsyncExecutor Objects\n\n```python\nclass AsyncExecutor(AbstractMultipleExecutor)\n```\n\nThread based executor to run multiple agents in threads.\n\n<a id=\"aea.helpers.multiple_executor.AbstractMultipleRunner\"></a>\n\n## AbstractMultipleRunner Objects\n\n```python\nclass AbstractMultipleRunner()\n```\n\nAbstract multiple runner to create classes to launch tasks with selected mode.\n\n<a id=\"aea.helpers.multiple_executor.AbstractMultipleRunner.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(\n    mode: str,\n    fail_policy: ExecutorExceptionPolicies = ExecutorExceptionPolicies.\n    propagate\n) -> None\n```\n\nInit with selected executor mode.\n\n**Arguments**:\n\n- `mode`: one of supported executor modes\n- `fail_policy`: one of ExecutorExceptionPolicies to be used with Executor\n\n<a id=\"aea.helpers.multiple_executor.AbstractMultipleRunner.is_running\"></a>\n\n#### is`_`running\n\n```python\n@property\ndef is_running() -> bool\n```\n\nReturn state of the executor.\n\n<a id=\"aea.helpers.multiple_executor.AbstractMultipleRunner.start\"></a>\n\n#### start\n\n```python\ndef start(threaded: bool = False) -> None\n```\n\nRun agents.\n\n**Arguments**:\n\n- `threaded`: run in dedicated thread without blocking current thread.\n\n<a id=\"aea.helpers.multiple_executor.AbstractMultipleRunner.stop\"></a>\n\n#### stop\n\n```python\ndef stop(timeout: Optional[float] = None) -> None\n```\n\nStop agents.\n\n**Arguments**:\n\n- `timeout`: timeout in seconds to wait thread stopped, only if started in thread mode.\n\n<a id=\"aea.helpers.multiple_executor.AbstractMultipleRunner.num_failed\"></a>\n\n#### num`_`failed\n\n```python\n@property\ndef num_failed() -> int\n```\n\nReturn number of failed tasks.\n\n<a id=\"aea.helpers.multiple_executor.AbstractMultipleRunner.failed\"></a>\n\n#### failed\n\n```python\n@property\ndef failed() -> Sequence[Task]\n```\n\nReturn sequence failed tasks.\n\n<a id=\"aea.helpers.multiple_executor.AbstractMultipleRunner.not_failed\"></a>\n\n#### not`_`failed\n\n```python\n@property\ndef not_failed() -> Sequence[Task]\n```\n\nReturn sequence successful tasks.\n\n<a id=\"aea.helpers.multiple_executor.AbstractMultipleRunner.try_join_thread\"></a>\n\n#### try`_`join`_`thread\n\n```python\ndef try_join_thread() -> None\n```\n\nTry to join thread if running in thread mode.\n\n"
  },
  {
    "path": "docs/api/helpers/pipe.md",
    "content": "<a id=\"aea.helpers.pipe\"></a>\n\n# aea.helpers.pipe\n\nPortable pipe implementation for Linux, MacOS, and Windows.\n\n<a id=\"aea.helpers.pipe.IPCChannelClient\"></a>\n\n## IPCChannelClient Objects\n\n```python\nclass IPCChannelClient(ABC)\n```\n\nMulti-platform interprocess communication channel for the client side.\n\n<a id=\"aea.helpers.pipe.IPCChannelClient.connect\"></a>\n\n#### connect\n\n```python\n@abstractmethod\nasync def connect(timeout: float = PIPE_CONN_TIMEOUT) -> bool\n```\n\nConnect to communication channel\n\n**Arguments**:\n\n- `timeout`: timeout for other end to connect\n\n**Returns**:\n\nconnection status\n\n<a id=\"aea.helpers.pipe.IPCChannelClient.write\"></a>\n\n#### write\n\n```python\n@abstractmethod\nasync def write(data: bytes) -> None\n```\n\nWrite `data` bytes to the other end of the channel\n\nWill first write the size than the actual data\n\n**Arguments**:\n\n- `data`: bytes to write\n\n<a id=\"aea.helpers.pipe.IPCChannelClient.read\"></a>\n\n#### read\n\n```python\n@abstractmethod\nasync def read() -> Optional[bytes]\n```\n\nRead bytes from the other end of the channel\n\nWill first read the size than the actual data\n\n**Returns**:\n\nread bytes\n\n<a id=\"aea.helpers.pipe.IPCChannelClient.close\"></a>\n\n#### close\n\n```python\n@abstractmethod\nasync def close() -> None\n```\n\nClose the communication channel.\n\n<a id=\"aea.helpers.pipe.IPCChannel\"></a>\n\n## IPCChannel Objects\n\n```python\nclass IPCChannel(IPCChannelClient)\n```\n\nMulti-platform interprocess communication channel.\n\n<a id=\"aea.helpers.pipe.IPCChannel.in_path\"></a>\n\n#### in`_`path\n\n```python\n@property\n@abstractmethod\ndef in_path() -> str\n```\n\nRendezvous point for incoming communication.\n\n**Returns**:\n\npath\n\n<a id=\"aea.helpers.pipe.IPCChannel.out_path\"></a>\n\n#### out`_`path\n\n```python\n@property\n@abstractmethod\ndef out_path() -> str\n```\n\nRendezvous point for outgoing communication.\n\n**Returns**:\n\npath\n\n<a id=\"aea.helpers.pipe.PosixNamedPipeProtocol\"></a>\n\n## PosixNamedPipeProtocol Objects\n\n```python\nclass PosixNamedPipeProtocol()\n```\n\nPosix named pipes async wrapper communication protocol.\n\n<a id=\"aea.helpers.pipe.PosixNamedPipeProtocol.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(in_path: str,\n             out_path: str,\n             logger: logging.Logger = _default_logger,\n             loop: Optional[AbstractEventLoop] = None) -> None\n```\n\nInitialize a new posix named pipe.\n\n**Arguments**:\n\n- `in_path`: rendezvous point for incoming data\n- `out_path`: rendezvous point for outgoing data\n- `logger`: the logger\n- `loop`: the event loop\n\n<a id=\"aea.helpers.pipe.PosixNamedPipeProtocol.connect\"></a>\n\n#### connect\n\n```python\nasync def connect(timeout: float = PIPE_CONN_TIMEOUT) -> bool\n```\n\nConnect to the other end of the pipe\n\n**Arguments**:\n\n- `timeout`: timeout before failing\n\n**Returns**:\n\nconnection success\n\n<a id=\"aea.helpers.pipe.PosixNamedPipeProtocol.write\"></a>\n\n#### write\n\n```python\nasync def write(data: bytes) -> None\n```\n\nWrite to pipe.\n\n**Arguments**:\n\n- `data`: bytes to write to pipe\n\n<a id=\"aea.helpers.pipe.PosixNamedPipeProtocol.read\"></a>\n\n#### read\n\n```python\nasync def read() -> Optional[bytes]\n```\n\nRead from pipe.\n\n**Returns**:\n\nread bytes\n\n<a id=\"aea.helpers.pipe.PosixNamedPipeProtocol.close\"></a>\n\n#### close\n\n```python\nasync def close() -> None\n```\n\nDisconnect pipe.\n\n<a id=\"aea.helpers.pipe.TCPSocketProtocol\"></a>\n\n## TCPSocketProtocol Objects\n\n```python\nclass TCPSocketProtocol()\n```\n\nTCP socket communication protocol.\n\n<a id=\"aea.helpers.pipe.TCPSocketProtocol.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(reader: asyncio.StreamReader,\n             writer: asyncio.StreamWriter,\n             logger: logging.Logger = _default_logger,\n             loop: Optional[AbstractEventLoop] = None) -> None\n```\n\nInitialize the tcp socket protocol.\n\n**Arguments**:\n\n- `reader`: established asyncio reader\n- `writer`: established asyncio writer\n- `logger`: the logger\n- `loop`: the event loop\n\n<a id=\"aea.helpers.pipe.TCPSocketProtocol.writer\"></a>\n\n#### writer\n\n```python\n@property\ndef writer() -> StreamWriter\n```\n\nGet a writer associated with  protocol.\n\n<a id=\"aea.helpers.pipe.TCPSocketProtocol.write\"></a>\n\n#### write\n\n```python\nasync def write(data: bytes) -> None\n```\n\nWrite to socket.\n\n**Arguments**:\n\n- `data`: bytes to write\n\n<a id=\"aea.helpers.pipe.TCPSocketProtocol.read\"></a>\n\n#### read\n\n```python\nasync def read() -> Optional[bytes]\n```\n\nRead from socket.\n\n**Returns**:\n\nread bytes\n\n<a id=\"aea.helpers.pipe.TCPSocketProtocol.close\"></a>\n\n#### close\n\n```python\nasync def close() -> None\n```\n\nDisconnect socket.\n\n<a id=\"aea.helpers.pipe.TCPSocketChannel\"></a>\n\n## TCPSocketChannel Objects\n\n```python\nclass TCPSocketChannel(IPCChannel)\n```\n\nInterprocess communication channel implementation using tcp sockets.\n\n<a id=\"aea.helpers.pipe.TCPSocketChannel.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(logger: logging.Logger = _default_logger,\n             loop: Optional[AbstractEventLoop] = None) -> None\n```\n\nInitialize tcp socket interprocess communication channel.\n\n<a id=\"aea.helpers.pipe.TCPSocketChannel.connect\"></a>\n\n#### connect\n\n```python\nasync def connect(timeout: float = PIPE_CONN_TIMEOUT) -> bool\n```\n\nSetup communication channel and wait for other end to connect.\n\n**Arguments**:\n\n- `timeout`: timeout for the connection to be established\n\n**Returns**:\n\nconnection status\n\n<a id=\"aea.helpers.pipe.TCPSocketChannel.write\"></a>\n\n#### write\n\n```python\nasync def write(data: bytes) -> None\n```\n\nWrite to channel.\n\n**Arguments**:\n\n- `data`: bytes to write\n\n<a id=\"aea.helpers.pipe.TCPSocketChannel.read\"></a>\n\n#### read\n\n```python\nasync def read() -> Optional[bytes]\n```\n\nRead from channel.\n\n**Returns**:\n\nread bytes\n\n<a id=\"aea.helpers.pipe.TCPSocketChannel.close\"></a>\n\n#### close\n\n```python\nasync def close() -> None\n```\n\nDisconnect from channel and clean it up.\n\n<a id=\"aea.helpers.pipe.TCPSocketChannel.in_path\"></a>\n\n#### in`_`path\n\n```python\n@property\ndef in_path() -> str\n```\n\nRendezvous point for incoming communication.\n\n<a id=\"aea.helpers.pipe.TCPSocketChannel.out_path\"></a>\n\n#### out`_`path\n\n```python\n@property\ndef out_path() -> str\n```\n\nRendezvous point for outgoing communication.\n\n<a id=\"aea.helpers.pipe.PosixNamedPipeChannel\"></a>\n\n## PosixNamedPipeChannel Objects\n\n```python\nclass PosixNamedPipeChannel(IPCChannel)\n```\n\nInterprocess communication channel implementation using Posix named pipes.\n\n<a id=\"aea.helpers.pipe.PosixNamedPipeChannel.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(logger: logging.Logger = _default_logger,\n             loop: Optional[AbstractEventLoop] = None) -> None\n```\n\nInitialize posix named pipe interprocess communication channel.\n\n<a id=\"aea.helpers.pipe.PosixNamedPipeChannel.connect\"></a>\n\n#### connect\n\n```python\nasync def connect(timeout: float = PIPE_CONN_TIMEOUT) -> bool\n```\n\nSetup communication channel and wait for other end to connect.\n\n**Arguments**:\n\n- `timeout`: timeout for connection to be established\n\n**Returns**:\n\nbool, indicating success\n\n<a id=\"aea.helpers.pipe.PosixNamedPipeChannel.write\"></a>\n\n#### write\n\n```python\nasync def write(data: bytes) -> None\n```\n\nWrite to the channel.\n\n**Arguments**:\n\n- `data`: data to write to channel\n\n<a id=\"aea.helpers.pipe.PosixNamedPipeChannel.read\"></a>\n\n#### read\n\n```python\nasync def read() -> Optional[bytes]\n```\n\nRead from the channel.\n\n**Returns**:\n\nread bytes\n\n<a id=\"aea.helpers.pipe.PosixNamedPipeChannel.close\"></a>\n\n#### close\n\n```python\nasync def close() -> None\n```\n\nClose the channel and clean it up.\n\n<a id=\"aea.helpers.pipe.PosixNamedPipeChannel.in_path\"></a>\n\n#### in`_`path\n\n```python\n@property\ndef in_path() -> str\n```\n\nRendezvous point for incoming communication.\n\n<a id=\"aea.helpers.pipe.PosixNamedPipeChannel.out_path\"></a>\n\n#### out`_`path\n\n```python\n@property\ndef out_path() -> str\n```\n\nRendezvous point for outgoing communication.\n\n<a id=\"aea.helpers.pipe.TCPSocketChannelClient\"></a>\n\n## TCPSocketChannelClient Objects\n\n```python\nclass TCPSocketChannelClient(IPCChannelClient)\n```\n\nInterprocess communication channel client using tcp sockets.\n\n<a id=\"aea.helpers.pipe.TCPSocketChannelClient.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(in_path: str,\n             out_path: str,\n             logger: logging.Logger = _default_logger,\n             loop: Optional[AbstractEventLoop] = None) -> None\n```\n\nInitialize a tcp socket communication channel client.\n\n**Arguments**:\n\n- `in_path`: rendezvous point for incoming data\n- `out_path`: rendezvous point for outgoing data\n- `logger`: the logger\n- `loop`: the event loop\n\n<a id=\"aea.helpers.pipe.TCPSocketChannelClient.connect\"></a>\n\n#### connect\n\n```python\nasync def connect(timeout: float = PIPE_CONN_TIMEOUT) -> bool\n```\n\nConnect to the other end of the communication channel.\n\n**Arguments**:\n\n- `timeout`: timeout for connection to be established\n\n**Returns**:\n\nconnection status\n\n<a id=\"aea.helpers.pipe.TCPSocketChannelClient.write\"></a>\n\n#### write\n\n```python\nasync def write(data: bytes) -> None\n```\n\nWrite data to channel.\n\n**Arguments**:\n\n- `data`: bytes to write\n\n<a id=\"aea.helpers.pipe.TCPSocketChannelClient.read\"></a>\n\n#### read\n\n```python\nasync def read() -> Optional[bytes]\n```\n\nRead data from channel.\n\n**Returns**:\n\nread bytes\n\n<a id=\"aea.helpers.pipe.TCPSocketChannelClient.close\"></a>\n\n#### close\n\n```python\nasync def close() -> None\n```\n\nDisconnect from communication channel.\n\n<a id=\"aea.helpers.pipe.PosixNamedPipeChannelClient\"></a>\n\n## PosixNamedPipeChannelClient Objects\n\n```python\nclass PosixNamedPipeChannelClient(IPCChannelClient)\n```\n\nInterprocess communication channel client using Posix named pipes.\n\n<a id=\"aea.helpers.pipe.PosixNamedPipeChannelClient.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(in_path: str,\n             out_path: str,\n             logger: logging.Logger = _default_logger,\n             loop: Optional[AbstractEventLoop] = None) -> None\n```\n\nInitialize a posix named pipe communication channel client.\n\n**Arguments**:\n\n- `in_path`: rendezvous point for incoming data\n- `out_path`: rendezvous point for outgoing data\n- `logger`: the logger\n- `loop`: the event loop\n\n<a id=\"aea.helpers.pipe.PosixNamedPipeChannelClient.connect\"></a>\n\n#### connect\n\n```python\nasync def connect(timeout: float = PIPE_CONN_TIMEOUT) -> bool\n```\n\nConnect to the other end of the communication channel.\n\n**Arguments**:\n\n- `timeout`: timeout for connection to be established\n\n**Returns**:\n\nconnection status\n\n<a id=\"aea.helpers.pipe.PosixNamedPipeChannelClient.write\"></a>\n\n#### write\n\n```python\nasync def write(data: bytes) -> None\n```\n\nWrite data to channel.\n\n**Arguments**:\n\n- `data`: bytes to write\n\n<a id=\"aea.helpers.pipe.PosixNamedPipeChannelClient.read\"></a>\n\n#### read\n\n```python\nasync def read() -> Optional[bytes]\n```\n\nRead data from channel.\n\n**Returns**:\n\nread bytes\n\n<a id=\"aea.helpers.pipe.PosixNamedPipeChannelClient.close\"></a>\n\n#### close\n\n```python\nasync def close() -> None\n```\n\nDisconnect from communication channel.\n\n<a id=\"aea.helpers.pipe.make_ipc_channel\"></a>\n\n#### make`_`ipc`_`channel\n\n```python\ndef make_ipc_channel(logger: logging.Logger = _default_logger,\n                     loop: Optional[AbstractEventLoop] = None) -> IPCChannel\n```\n\nBuild a portable bidirectional InterProcess Communication channel\n\n**Arguments**:\n\n- `logger`: the logger\n- `loop`: the loop\n\n**Returns**:\n\nIPCChannel\n\n<a id=\"aea.helpers.pipe.make_ipc_channel_client\"></a>\n\n#### make`_`ipc`_`channel`_`client\n\n```python\ndef make_ipc_channel_client(\n        in_path: str,\n        out_path: str,\n        logger: logging.Logger = _default_logger,\n        loop: Optional[AbstractEventLoop] = None) -> IPCChannelClient\n```\n\nBuild a portable bidirectional InterProcess Communication client channel\n\n**Arguments**:\n\n- `in_path`: rendezvous point for incoming communication\n- `out_path`: rendezvous point for outgoing outgoing\n- `logger`: the logger\n- `loop`: the loop\n\n**Returns**:\n\nIPCChannel\n\n"
  },
  {
    "path": "docs/api/helpers/preference_representations/base.md",
    "content": "<a id=\"aea.helpers.preference_representations.base\"></a>\n\n# aea.helpers.preference`_`representations.base\n\nPreference representation helpers.\n\n<a id=\"aea.helpers.preference_representations.base.logarithmic_utility\"></a>\n\n#### logarithmic`_`utility\n\n```python\ndef logarithmic_utility(utility_params_by_good_id: Dict[str, float],\n                        quantities_by_good_id: Dict[str, int],\n                        quantity_shift: int = 100) -> float\n```\n\nCompute agent's utility given her utility function params and a good bundle.\n\n**Arguments**:\n\n- `utility_params_by_good_id`: utility params by good identifier\n- `quantities_by_good_id`: quantities by good identifier\n- `quantity_shift`: a non-negative factor to shift the quantities in the utility function (to ensure the natural logarithm can be used on the entire range of quantities)\n\n**Returns**:\n\nutility value\n\n<a id=\"aea.helpers.preference_representations.base.linear_utility\"></a>\n\n#### linear`_`utility\n\n```python\ndef linear_utility(exchange_params_by_currency_id: Dict[str, float],\n                   balance_by_currency_id: Dict[str, int]) -> float\n```\n\nCompute agent's utility given her utility function params and a good bundle.\n\n**Arguments**:\n\n- `exchange_params_by_currency_id`: exchange params by currency\n- `balance_by_currency_id`: balance by currency\n\n**Returns**:\n\nutility value\n\n"
  },
  {
    "path": "docs/api/helpers/profiling.md",
    "content": "<a id=\"aea.helpers.profiling\"></a>\n\n# aea.helpers.profiling\n\nImplementation of background profiling daemon.\n\n<a id=\"aea.helpers.profiling.Profiling\"></a>\n\n## Profiling Objects\n\n```python\nclass Profiling(Runnable)\n```\n\nProfiling service.\n\n<a id=\"aea.helpers.profiling.Profiling.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(\n    period: int = 0,\n    objects_instances_to_count: List[Type] = None,\n    objects_created_to_count: List[Type] = None,\n    output_function: Callable[[str], None] = lambda x: print(x, flush=True)\n) -> None\n```\n\nInit profiler.\n\n**Arguments**:\n\n- `period`: delay between profiling output in seconds.\n- `objects_instances_to_count`: object to count\n- `objects_created_to_count`: object created to count\n- `output_function`: function to display output, one str argument.\n\n<a id=\"aea.helpers.profiling.Profiling.set_counters\"></a>\n\n#### set`_`counters\n\n```python\ndef set_counters() -> None\n```\n\nModify obj.__new__ to count objects created created.\n\n<a id=\"aea.helpers.profiling.Profiling.run\"></a>\n\n#### run\n\n```python\nasync def run() -> None\n```\n\nRun profiling.\n\n<a id=\"aea.helpers.profiling.Profiling.output_profile_data\"></a>\n\n#### output`_`profile`_`data\n\n```python\ndef output_profile_data() -> None\n```\n\nRender profiling data and call output_function.\n\n<a id=\"aea.helpers.profiling.Profiling.get_profile_data\"></a>\n\n#### get`_`profile`_`data\n\n```python\ndef get_profile_data() -> Dict\n```\n\nGet profiling data dict.\n\n<a id=\"aea.helpers.profiling.Profiling.get_objects_instances\"></a>\n\n#### get`_`objects`_`instances\n\n```python\ndef get_objects_instances() -> Dict\n```\n\nReturn dict with counted object instances present now.\n\n<a id=\"aea.helpers.profiling.Profiling.get_objecst_created\"></a>\n\n#### get`_`objecst`_`created\n\n```python\ndef get_objecst_created() -> Dict\n```\n\nReturn dict with counted object instances created.\n\n"
  },
  {
    "path": "docs/api/helpers/search/generic.md",
    "content": "<a id=\"aea.helpers.search.generic\"></a>\n\n# aea.helpers.search.generic\n\nThis module contains a generic data model.\n\n<a id=\"aea.helpers.search.generic.GenericDataModel\"></a>\n\n## GenericDataModel Objects\n\n```python\nclass GenericDataModel(DataModel)\n```\n\nGeneric data model.\n\n<a id=\"aea.helpers.search.generic.GenericDataModel.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(data_model_name: str, data_model_attributes: Dict[str,\n                                                               Any]) -> None\n```\n\nInitialise the dataModel.\n\n"
  },
  {
    "path": "docs/api/helpers/search/models.md",
    "content": ""
  },
  {
    "path": "docs/api/helpers/serializers.md",
    "content": "<a id=\"aea.helpers.serializers\"></a>\n\n# aea.helpers.serializers\n\nThis module contains Serializers that can be used for custom types.\n\n<a id=\"aea.helpers.serializers.DictProtobufStructSerializer\"></a>\n\n## DictProtobufStructSerializer Objects\n\n```python\nclass DictProtobufStructSerializer()\n```\n\nSerialize python dictionaries of type DictType = Dict[str, ValueType] recursively conserving their dynamic type, using google.protobuf.Struct\n\nValueType = PrimitiveType | DictType | List[ValueType]]\nPrimitiveType = bool | int | float | str | bytes\n\n<a id=\"aea.helpers.serializers.DictProtobufStructSerializer.encode\"></a>\n\n#### encode\n\n```python\n@classmethod\ndef encode(cls, dictionary: Dict[str, Any]) -> bytes\n```\n\nSerialize compatible dictionary to bytes.\n\nCopies entire dictionary in the process.\n\n**Arguments**:\n\n- `dictionary`: the dictionary to serialize\n\n**Returns**:\n\nserialized bytes string\n\n<a id=\"aea.helpers.serializers.DictProtobufStructSerializer.decode\"></a>\n\n#### decode\n\n```python\n@classmethod\ndef decode(cls, buffer: bytes) -> Dict[str, Any]\n```\n\nDeserialize a compatible dictionary\n\n"
  },
  {
    "path": "docs/api/helpers/storage/backends/base.md",
    "content": "<a id=\"aea.helpers.storage.backends.base\"></a>\n\n# aea.helpers.storage.backends.base\n\nThis module contains storage abstract backend class.\n\n<a id=\"aea.helpers.storage.backends.base.AbstractStorageBackend\"></a>\n\n## AbstractStorageBackend Objects\n\n```python\nclass AbstractStorageBackend(ABC)\n```\n\nAbstract base class for storage backend.\n\n<a id=\"aea.helpers.storage.backends.base.AbstractStorageBackend.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(uri: str) -> None\n```\n\nInit backend.\n\n<a id=\"aea.helpers.storage.backends.base.AbstractStorageBackend.connect\"></a>\n\n#### connect\n\n```python\n@abstractmethod\nasync def connect() -> None\n```\n\nConnect to backend.\n\n<a id=\"aea.helpers.storage.backends.base.AbstractStorageBackend.disconnect\"></a>\n\n#### disconnect\n\n```python\n@abstractmethod\nasync def disconnect() -> None\n```\n\nDisconnect the backend.\n\n<a id=\"aea.helpers.storage.backends.base.AbstractStorageBackend.ensure_collection\"></a>\n\n#### ensure`_`collection\n\n```python\n@abstractmethod\nasync def ensure_collection(collection_name: str) -> None\n```\n\nCreate collection if not exits.\n\n**Arguments**:\n\n- `collection_name`: str.\n\n**Returns**:\n\nNone\n\n<a id=\"aea.helpers.storage.backends.base.AbstractStorageBackend.put\"></a>\n\n#### put\n\n```python\n@abstractmethod\nasync def put(collection_name: str, object_id: str,\n              object_body: JSON_TYPES) -> None\n```\n\nPut object into collection.\n\n**Arguments**:\n\n- `collection_name`: str.\n- `object_id`: str object id\n- `object_body`: python dict, json compatible.\n\n**Returns**:\n\nNone\n\n<a id=\"aea.helpers.storage.backends.base.AbstractStorageBackend.get\"></a>\n\n#### get\n\n```python\n@abstractmethod\nasync def get(collection_name: str, object_id: str) -> Optional[JSON_TYPES]\n```\n\nGet object from the collection.\n\n**Arguments**:\n\n- `collection_name`: str.\n- `object_id`: str object id\n\n**Returns**:\n\ndict if object exists in collection otherwise None\n\n<a id=\"aea.helpers.storage.backends.base.AbstractStorageBackend.remove\"></a>\n\n#### remove\n\n```python\n@abstractmethod\nasync def remove(collection_name: str, object_id: str) -> None\n```\n\nRemove object from the collection.\n\n**Arguments**:\n\n- `collection_name`: str.\n- `object_id`: str object id\n\n**Returns**:\n\nNone\n\n<a id=\"aea.helpers.storage.backends.base.AbstractStorageBackend.find\"></a>\n\n#### find\n\n```python\n@abstractmethod\nasync def find(collection_name: str, field: str,\n               equals: EQUALS_TYPE) -> List[OBJECT_ID_AND_BODY]\n```\n\nGet objects from the collection by filtering by field value.\n\n**Arguments**:\n\n- `collection_name`: str.\n- `field`: field name to search: example \"parent.field\"\n- `equals`: value field should be equal to\n\n**Returns**:\n\nlist of objects bodies\n\n<a id=\"aea.helpers.storage.backends.base.AbstractStorageBackend.list\"></a>\n\n#### list\n\n```python\n@abstractmethod\nasync def list(collection_name: str) -> List[OBJECT_ID_AND_BODY]\n```\n\nList all objects with keys from the collection.\n\n**Arguments**:\n\n- `collection_name`: str.\n\n**Returns**:\n\nTuple of objects keys, bodies.\n\n"
  },
  {
    "path": "docs/api/helpers/storage/backends/sqlite.md",
    "content": "<a id=\"aea.helpers.storage.backends.sqlite\"></a>\n\n# aea.helpers.storage.backends.sqlite\n\nThis module contains sqlite storage backend implementation.\n\n<a id=\"aea.helpers.storage.backends.sqlite.SqliteStorageBackend\"></a>\n\n## SqliteStorageBackend Objects\n\n```python\nclass SqliteStorageBackend(AbstractStorageBackend)\n```\n\nSqlite storage backend.\n\n<a id=\"aea.helpers.storage.backends.sqlite.SqliteStorageBackend.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(uri: str) -> None\n```\n\nInit backend.\n\n<a id=\"aea.helpers.storage.backends.sqlite.SqliteStorageBackend.connect\"></a>\n\n#### connect\n\n```python\nasync def connect() -> None\n```\n\nConnect to backend.\n\n<a id=\"aea.helpers.storage.backends.sqlite.SqliteStorageBackend.disconnect\"></a>\n\n#### disconnect\n\n```python\nasync def disconnect() -> None\n```\n\nDisconnect the backend.\n\n<a id=\"aea.helpers.storage.backends.sqlite.SqliteStorageBackend.ensure_collection\"></a>\n\n#### ensure`_`collection\n\n```python\nasync def ensure_collection(collection_name: str) -> None\n```\n\nCreate collection if not exits.\n\n**Arguments**:\n\n- `collection_name`: name of the collection.\n\n<a id=\"aea.helpers.storage.backends.sqlite.SqliteStorageBackend.put\"></a>\n\n#### put\n\n```python\nasync def put(collection_name: str, object_id: str,\n              object_body: JSON_TYPES) -> None\n```\n\nPut object into collection.\n\n**Arguments**:\n\n- `collection_name`: str.\n- `object_id`: str object id\n- `object_body`: python dict, json compatible.\n\n<a id=\"aea.helpers.storage.backends.sqlite.SqliteStorageBackend.get\"></a>\n\n#### get\n\n```python\nasync def get(collection_name: str, object_id: str) -> Optional[JSON_TYPES]\n```\n\nGet object from the collection.\n\n**Arguments**:\n\n- `collection_name`: str.\n- `object_id`: str object id\n\n**Returns**:\n\ndict if object exists in collection otherwise None\n\n<a id=\"aea.helpers.storage.backends.sqlite.SqliteStorageBackend.remove\"></a>\n\n#### remove\n\n```python\nasync def remove(collection_name: str, object_id: str) -> None\n```\n\nRemove object from the collection.\n\n**Arguments**:\n\n- `collection_name`: str.\n- `object_id`: str object id\n\n<a id=\"aea.helpers.storage.backends.sqlite.SqliteStorageBackend.find\"></a>\n\n#### find\n\n```python\nasync def find(collection_name: str, field: str,\n               equals: EQUALS_TYPE) -> List[OBJECT_ID_AND_BODY]\n```\n\nGet objects from the collection by filtering by field value.\n\n**Arguments**:\n\n- `collection_name`: str.\n- `field`: field name to search: example \"parent.field\"\n- `equals`: value field should be equal to\n\n**Returns**:\n\nlist of object ids and body\n\n<a id=\"aea.helpers.storage.backends.sqlite.SqliteStorageBackend.list\"></a>\n\n#### list\n\n```python\nasync def list(collection_name: str) -> List[OBJECT_ID_AND_BODY]\n```\n\nList all objects with keys from the collection.\n\n**Arguments**:\n\n- `collection_name`: str.\n\n**Returns**:\n\nTuple of objects keys, bodies.\n\n"
  },
  {
    "path": "docs/api/helpers/storage/generic_storage.md",
    "content": "<a id=\"aea.helpers.storage.generic_storage\"></a>\n\n# aea.helpers.storage.generic`_`storage\n\nThis module contains the storage implementation.\n\n<a id=\"aea.helpers.storage.generic_storage.AsyncCollection\"></a>\n\n## AsyncCollection Objects\n\n```python\nclass AsyncCollection()\n```\n\nAsync collection.\n\n<a id=\"aea.helpers.storage.generic_storage.AsyncCollection.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(storage_backend: AbstractStorageBackend,\n             collection_name: str) -> None\n```\n\nInit collection object.\n\n**Arguments**:\n\n- `storage_backend`: storage backed to use.\n- `collection_name`: str\n\n<a id=\"aea.helpers.storage.generic_storage.AsyncCollection.put\"></a>\n\n#### put\n\n```python\nasync def put(object_id: str, object_body: JSON_TYPES) -> None\n```\n\nPut object into collection.\n\n**Arguments**:\n\n- `object_id`: str object id\n- `object_body`: python dict, json compatible.\n\n**Returns**:\n\nNone\n\n<a id=\"aea.helpers.storage.generic_storage.AsyncCollection.get\"></a>\n\n#### get\n\n```python\nasync def get(object_id: str) -> Optional[JSON_TYPES]\n```\n\nGet object from the collection.\n\n**Arguments**:\n\n- `object_id`: str object id\n\n**Returns**:\n\ndict if object exists in collection otherwise None\n\n<a id=\"aea.helpers.storage.generic_storage.AsyncCollection.remove\"></a>\n\n#### remove\n\n```python\nasync def remove(object_id: str) -> None\n```\n\nRemove object from the collection.\n\n**Arguments**:\n\n- `object_id`: str object id\n\n**Returns**:\n\nNone\n\n<a id=\"aea.helpers.storage.generic_storage.AsyncCollection.find\"></a>\n\n#### find\n\n```python\nasync def find(field: str, equals: EQUALS_TYPE) -> List[OBJECT_ID_AND_BODY]\n```\n\nGet objects from the collection by filtering by field value.\n\n**Arguments**:\n\n- `field`: field name to search: example \"parent.field\"\n- `equals`: value field should be equal to\n\n**Returns**:\n\nNone\n\n<a id=\"aea.helpers.storage.generic_storage.AsyncCollection.list\"></a>\n\n#### list\n\n```python\nasync def list() -> List[OBJECT_ID_AND_BODY]\n```\n\nList all objects with keys from the collection.\n\n**Returns**:\n\nTuple of objects keys, bodies.\n\n<a id=\"aea.helpers.storage.generic_storage.SyncCollection\"></a>\n\n## SyncCollection Objects\n\n```python\nclass SyncCollection()\n```\n\nAsync collection.\n\n<a id=\"aea.helpers.storage.generic_storage.SyncCollection.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(async_collection_coro: Coroutine,\n             loop: asyncio.AbstractEventLoop) -> None\n```\n\nInit collection object.\n\n**Arguments**:\n\n- `async_collection_coro`: coroutine returns async collection.\n- `loop`: abstract event loop where storage is running.\n\n<a id=\"aea.helpers.storage.generic_storage.SyncCollection.put\"></a>\n\n#### put\n\n```python\ndef put(object_id: str, object_body: JSON_TYPES) -> None\n```\n\nPut object into collection.\n\n**Arguments**:\n\n- `object_id`: str object id\n- `object_body`: python dict, json compatible.\n\n**Returns**:\n\nNone\n\n<a id=\"aea.helpers.storage.generic_storage.SyncCollection.get\"></a>\n\n#### get\n\n```python\ndef get(object_id: str) -> Optional[JSON_TYPES]\n```\n\nGet object from the collection.\n\n**Arguments**:\n\n- `object_id`: str object id\n\n**Returns**:\n\ndict if object exists in collection otherwise None\n\n<a id=\"aea.helpers.storage.generic_storage.SyncCollection.remove\"></a>\n\n#### remove\n\n```python\ndef remove(object_id: str) -> None\n```\n\nRemove object from the collection.\n\n**Arguments**:\n\n- `object_id`: str object id\n\n**Returns**:\n\nNone\n\n<a id=\"aea.helpers.storage.generic_storage.SyncCollection.find\"></a>\n\n#### find\n\n```python\ndef find(field: str, equals: EQUALS_TYPE) -> List[OBJECT_ID_AND_BODY]\n```\n\nGet objects from the collection by filtering by field value.\n\n**Arguments**:\n\n- `field`: field name to search: example \"parent.field\"\n- `equals`: value field should be equal to\n\n**Returns**:\n\nList of object bodies\n\n<a id=\"aea.helpers.storage.generic_storage.SyncCollection.list\"></a>\n\n#### list\n\n```python\ndef list() -> List[OBJECT_ID_AND_BODY]\n```\n\nList all objects with keys from the collection.\n\n**Returns**:\n\nTuple of objects keys, bodies.\n\n<a id=\"aea.helpers.storage.generic_storage.Storage\"></a>\n\n## Storage Objects\n\n```python\nclass Storage(Runnable)\n```\n\nGeneric storage.\n\n<a id=\"aea.helpers.storage.generic_storage.Storage.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(storage_uri: str,\n             loop: asyncio.AbstractEventLoop = None,\n             threaded: bool = False) -> None\n```\n\nInit storage.\n\n**Arguments**:\n\n- `storage_uri`: configuration string for storage.\n- `loop`: asyncio event loop to use.\n- `threaded`: bool. start in thread if True.\n\n<a id=\"aea.helpers.storage.generic_storage.Storage.wait_connected\"></a>\n\n#### wait`_`connected\n\n```python\nasync def wait_connected() -> None\n```\n\nWait generic storage is connected.\n\n<a id=\"aea.helpers.storage.generic_storage.Storage.is_connected\"></a>\n\n#### is`_`connected\n\n```python\n@property\ndef is_connected() -> bool\n```\n\nGet running state of the storage.\n\n<a id=\"aea.helpers.storage.generic_storage.Storage.run\"></a>\n\n#### run\n\n```python\nasync def run() -> None\n```\n\nConnect storage.\n\n<a id=\"aea.helpers.storage.generic_storage.Storage.get_collection\"></a>\n\n#### get`_`collection\n\n```python\nasync def get_collection(collection_name: str) -> AsyncCollection\n```\n\nGet async collection.\n\n<a id=\"aea.helpers.storage.generic_storage.Storage.get_sync_collection\"></a>\n\n#### get`_`sync`_`collection\n\n```python\ndef get_sync_collection(collection_name: str) -> SyncCollection\n```\n\nGet sync collection.\n\n<a id=\"aea.helpers.storage.generic_storage.Storage.__repr__\"></a>\n\n#### `__`repr`__`\n\n```python\ndef __repr__() -> str\n```\n\nGet string representation of the storage.\n\n"
  },
  {
    "path": "docs/api/helpers/sym_link.md",
    "content": "<a id=\"aea.helpers.sym_link\"></a>\n\n# aea.helpers.sym`_`link\n\nSym link implementation for Linux, MacOS, and Windows.\n\n<a id=\"aea.helpers.sym_link.make_symlink\"></a>\n\n#### make`_`symlink\n\n```python\ndef make_symlink(link_name: str, target: str) -> None\n```\n\nMake a symbolic link, cross platform.\n\n**Arguments**:\n\n- `link_name`: the link name.\n- `target`: the target.\n\n<a id=\"aea.helpers.sym_link.cd\"></a>\n\n#### cd\n\n```python\n@contextlib.contextmanager\ndef cd(path: Path) -> Generator\n```\n\nChange directory with context manager.\n\n<a id=\"aea.helpers.sym_link.create_symlink\"></a>\n\n#### create`_`symlink\n\n```python\ndef create_symlink(link_path: Path, target_path: Path, root_path: Path) -> int\n```\n\nChange directory and call the cross-platform script.\n\nThe working directory must be the parent of the symbolic link name\nwhen executing 'create_symlink_crossplatform.sh'. Hence, we\nneed to translate target_path into the relative path from the\nsymbolic link directory to the target directory.\n\nSo:\n1) from link_path, extract the number of jumps to the parent directory\n  in order to reach the repository root directory, and chain many \"../\" paths.\n2) from target_path, compute the relative path to the root\n3) relative_target_path is just the concatenation of the results from step (1) and (2).\n\n\nFor instance, given\n- link_path: './directory_1//symbolic_link\n- target_path: './directory_2/target_path\n\nwe want to compute:\n- link_path: 'symbolic_link' (just the last bit)\n- relative_target_path: '../../directory_1/target_path'\n\nThe resulting command on UNIX systems will be:\n\n    cd directory_1 && ln -s ../../directory_1/target_path symbolic_link\n\n**Arguments**:\n\n- `link_path`: the source path\n- `target_path`: the target path\n- `root_path`: the root path\n\n**Returns**:\n\nexit code\n\n"
  },
  {
    "path": "docs/api/helpers/transaction/base.md",
    "content": "<a id=\"aea.helpers.transaction.base\"></a>\n\n# aea.helpers.transaction.base\n\nThis module contains terms related classes.\n\n<a id=\"aea.helpers.transaction.base.RawTransaction\"></a>\n\n## RawTransaction Objects\n\n```python\nclass RawTransaction()\n```\n\nThis class represents an instance of RawTransaction.\n\n<a id=\"aea.helpers.transaction.base.RawTransaction.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(ledger_id: str, body: JSONLike) -> None\n```\n\nInitialise an instance of RawTransaction.\n\n<a id=\"aea.helpers.transaction.base.RawTransaction.ledger_id\"></a>\n\n#### ledger`_`id\n\n```python\n@property\ndef ledger_id() -> str\n```\n\nGet the id of the ledger on which the terms are to be settled.\n\n<a id=\"aea.helpers.transaction.base.RawTransaction.body\"></a>\n\n#### body\n\n```python\n@property\ndef body() -> JSONLike\n```\n\nGet the body.\n\n<a id=\"aea.helpers.transaction.base.RawTransaction.encode\"></a>\n\n#### encode\n\n```python\n@staticmethod\ndef encode(raw_transaction_protobuf_object: Any,\n           raw_transaction_object: \"RawTransaction\") -> None\n```\n\nEncode an instance of this class into the protocol buffer object.\n\nThe protocol buffer object in the raw_transaction_protobuf_object argument must be matched with the instance of this class in the 'raw_transaction_object' argument.\n\n**Arguments**:\n\n- `raw_transaction_protobuf_object`: the protocol buffer object whose type corresponds with this class.\n- `raw_transaction_object`: an instance of this class to be encoded in the protocol buffer object.\n\n<a id=\"aea.helpers.transaction.base.RawTransaction.decode\"></a>\n\n#### decode\n\n```python\n@classmethod\ndef decode(cls, raw_transaction_protobuf_object: Any) -> \"RawTransaction\"\n```\n\nDecode a protocol buffer object that corresponds with this class into an instance of this class.\n\nA new instance of this class must be created that matches the protocol buffer object in the 'raw_transaction_protobuf_object' argument.\n\n**Arguments**:\n\n- `raw_transaction_protobuf_object`: the protocol buffer object whose type corresponds with this class.\n\n**Returns**:\n\nA new instance of this class that matches the protocol buffer object in the 'raw_transaction_protobuf_object' argument.\n\n<a id=\"aea.helpers.transaction.base.RawTransaction.__eq__\"></a>\n\n#### `__`eq`__`\n\n```python\ndef __eq__(other: Any) -> bool\n```\n\nCheck equality.\n\n<a id=\"aea.helpers.transaction.base.RawTransaction.__str__\"></a>\n\n#### `__`str`__`\n\n```python\ndef __str__() -> str\n```\n\nGet string representation.\n\n<a id=\"aea.helpers.transaction.base.RawMessage\"></a>\n\n## RawMessage Objects\n\n```python\nclass RawMessage()\n```\n\nThis class represents an instance of RawMessage.\n\n<a id=\"aea.helpers.transaction.base.RawMessage.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(ledger_id: str,\n             body: bytes,\n             is_deprecated_mode: bool = False) -> None\n```\n\nInitialise an instance of RawMessage.\n\n<a id=\"aea.helpers.transaction.base.RawMessage.ledger_id\"></a>\n\n#### ledger`_`id\n\n```python\n@property\ndef ledger_id() -> str\n```\n\nGet the id of the ledger on which the terms are to be settled.\n\n<a id=\"aea.helpers.transaction.base.RawMessage.body\"></a>\n\n#### body\n\n```python\n@property\ndef body() -> bytes\n```\n\nGet the body.\n\n<a id=\"aea.helpers.transaction.base.RawMessage.is_deprecated_mode\"></a>\n\n#### is`_`deprecated`_`mode\n\n```python\n@property\ndef is_deprecated_mode() -> bool\n```\n\nGet the is_deprecated_mode.\n\n<a id=\"aea.helpers.transaction.base.RawMessage.encode\"></a>\n\n#### encode\n\n```python\n@staticmethod\ndef encode(raw_message_protobuf_object: Any,\n           raw_message_object: \"RawMessage\") -> None\n```\n\nEncode an instance of this class into the protocol buffer object.\n\nThe protocol buffer object in the raw_message_protobuf_object argument must be matched with the instance of this class in the 'raw_message_object' argument.\n\n**Arguments**:\n\n- `raw_message_protobuf_object`: the protocol buffer object whose type corresponds with this class.\n- `raw_message_object`: an instance of this class to be encoded in the protocol buffer object.\n\n<a id=\"aea.helpers.transaction.base.RawMessage.decode\"></a>\n\n#### decode\n\n```python\n@classmethod\ndef decode(cls, raw_message_protobuf_object: Any) -> \"RawMessage\"\n```\n\nDecode a protocol buffer object that corresponds with this class into an instance of this class.\n\nA new instance of this class must be created that matches the protocol buffer object in the 'raw_message_protobuf_object' argument.\n\n**Arguments**:\n\n- `raw_message_protobuf_object`: the protocol buffer object whose type corresponds with this class.\n\n**Returns**:\n\nA new instance of this class that matches the protocol buffer object in the 'raw_message_protobuf_object' argument.\n\n<a id=\"aea.helpers.transaction.base.RawMessage.__eq__\"></a>\n\n#### `__`eq`__`\n\n```python\ndef __eq__(other: Any) -> bool\n```\n\nCheck equality.\n\n<a id=\"aea.helpers.transaction.base.RawMessage.__str__\"></a>\n\n#### `__`str`__`\n\n```python\ndef __str__() -> str\n```\n\nGet string representation.\n\n<a id=\"aea.helpers.transaction.base.SignedTransaction\"></a>\n\n## SignedTransaction Objects\n\n```python\nclass SignedTransaction()\n```\n\nThis class represents an instance of SignedTransaction.\n\n<a id=\"aea.helpers.transaction.base.SignedTransaction.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(ledger_id: str, body: JSONLike) -> None\n```\n\nInitialise an instance of SignedTransaction.\n\n<a id=\"aea.helpers.transaction.base.SignedTransaction.ledger_id\"></a>\n\n#### ledger`_`id\n\n```python\n@property\ndef ledger_id() -> str\n```\n\nGet the id of the ledger on which the terms are to be settled.\n\n<a id=\"aea.helpers.transaction.base.SignedTransaction.body\"></a>\n\n#### body\n\n```python\n@property\ndef body() -> JSONLike\n```\n\nGet the body.\n\n<a id=\"aea.helpers.transaction.base.SignedTransaction.encode\"></a>\n\n#### encode\n\n```python\n@staticmethod\ndef encode(signed_transaction_protobuf_object: Any,\n           signed_transaction_object: \"SignedTransaction\") -> None\n```\n\nEncode an instance of this class into the protocol buffer object.\n\nThe protocol buffer object in the signed_transaction_protobuf_object argument must be matched with the instance of this class in the 'signed_transaction_object' argument.\n\n**Arguments**:\n\n- `signed_transaction_protobuf_object`: the protocol buffer object whose type corresponds with this class.\n- `signed_transaction_object`: an instance of this class to be encoded in the protocol buffer object.\n\n<a id=\"aea.helpers.transaction.base.SignedTransaction.decode\"></a>\n\n#### decode\n\n```python\n@classmethod\ndef decode(cls,\n           signed_transaction_protobuf_object: Any) -> \"SignedTransaction\"\n```\n\nDecode a protocol buffer object that corresponds with this class into an instance of this class.\n\nA new instance of this class must be created that matches the protocol buffer object in the 'signed_transaction_protobuf_object' argument.\n\n**Arguments**:\n\n- `signed_transaction_protobuf_object`: the protocol buffer object whose type corresponds with this class.\n\n**Returns**:\n\nA new instance of this class that matches the protocol buffer object in the 'signed_transaction_protobuf_object' argument.\n\n<a id=\"aea.helpers.transaction.base.SignedTransaction.__eq__\"></a>\n\n#### `__`eq`__`\n\n```python\ndef __eq__(other: Any) -> bool\n```\n\nCheck equality.\n\n<a id=\"aea.helpers.transaction.base.SignedTransaction.__str__\"></a>\n\n#### `__`str`__`\n\n```python\ndef __str__() -> str\n```\n\nGet string representation.\n\n<a id=\"aea.helpers.transaction.base.SignedMessage\"></a>\n\n## SignedMessage Objects\n\n```python\nclass SignedMessage()\n```\n\nThis class represents an instance of RawMessage.\n\n<a id=\"aea.helpers.transaction.base.SignedMessage.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(ledger_id: str,\n             body: str,\n             is_deprecated_mode: bool = False) -> None\n```\n\nInitialise an instance of SignedMessage.\n\n<a id=\"aea.helpers.transaction.base.SignedMessage.ledger_id\"></a>\n\n#### ledger`_`id\n\n```python\n@property\ndef ledger_id() -> str\n```\n\nGet the id of the ledger on which the terms are to be settled.\n\n<a id=\"aea.helpers.transaction.base.SignedMessage.body\"></a>\n\n#### body\n\n```python\n@property\ndef body() -> str\n```\n\nGet the body.\n\n<a id=\"aea.helpers.transaction.base.SignedMessage.is_deprecated_mode\"></a>\n\n#### is`_`deprecated`_`mode\n\n```python\n@property\ndef is_deprecated_mode() -> bool\n```\n\nGet the is_deprecated_mode.\n\n<a id=\"aea.helpers.transaction.base.SignedMessage.encode\"></a>\n\n#### encode\n\n```python\n@staticmethod\ndef encode(signed_message_protobuf_object: Any,\n           signed_message_object: \"SignedMessage\") -> None\n```\n\nEncode an instance of this class into the protocol buffer object.\n\nThe protocol buffer object in the signed_message_protobuf_object argument must be matched with the instance of this class in the 'signed_message_object' argument.\n\n**Arguments**:\n\n- `signed_message_protobuf_object`: the protocol buffer object whose type corresponds with this class.\n- `signed_message_object`: an instance of this class to be encoded in the protocol buffer object.\n\n<a id=\"aea.helpers.transaction.base.SignedMessage.decode\"></a>\n\n#### decode\n\n```python\n@classmethod\ndef decode(cls, signed_message_protobuf_object: Any) -> \"SignedMessage\"\n```\n\nDecode a protocol buffer object that corresponds with this class into an instance of this class.\n\nA new instance of this class must be created that matches the protocol buffer object in the 'signed_message_protobuf_object' argument.\n\n**Arguments**:\n\n- `signed_message_protobuf_object`: the protocol buffer object whose type corresponds with this class.\n\n**Returns**:\n\nA new instance of this class that matches the protocol buffer object in the 'signed_message_protobuf_object' argument.\n\n<a id=\"aea.helpers.transaction.base.SignedMessage.__eq__\"></a>\n\n#### `__`eq`__`\n\n```python\ndef __eq__(other: Any) -> bool\n```\n\nCheck equality.\n\n<a id=\"aea.helpers.transaction.base.SignedMessage.__str__\"></a>\n\n#### `__`str`__`\n\n```python\ndef __str__() -> str\n```\n\nGet string representation.\n\n<a id=\"aea.helpers.transaction.base.State\"></a>\n\n## State Objects\n\n```python\nclass State()\n```\n\nThis class represents an instance of State.\n\n<a id=\"aea.helpers.transaction.base.State.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(ledger_id: str, body: JSONLike) -> None\n```\n\nInitialise an instance of State.\n\n<a id=\"aea.helpers.transaction.base.State.ledger_id\"></a>\n\n#### ledger`_`id\n\n```python\n@property\ndef ledger_id() -> str\n```\n\nGet the id of the ledger on which the terms are to be settled.\n\n<a id=\"aea.helpers.transaction.base.State.body\"></a>\n\n#### body\n\n```python\n@property\ndef body() -> JSONLike\n```\n\nGet the body.\n\n<a id=\"aea.helpers.transaction.base.State.encode\"></a>\n\n#### encode\n\n```python\n@staticmethod\ndef encode(state_protobuf_object: Any, state_object: \"State\") -> None\n```\n\nEncode an instance of this class into the protocol buffer object.\n\nThe protocol buffer object in the state_protobuf_object argument must be matched with the instance of this class in the 'state_object' argument.\n\n**Arguments**:\n\n- `state_protobuf_object`: the protocol buffer object whose type corresponds with this class.\n- `state_object`: an instance of this class to be encoded in the protocol buffer object.\n\n<a id=\"aea.helpers.transaction.base.State.decode\"></a>\n\n#### decode\n\n```python\n@classmethod\ndef decode(cls, state_protobuf_object: Any) -> \"State\"\n```\n\nDecode a protocol buffer object that corresponds with this class into an instance of this class.\n\nA new instance of this class must be created that matches the protocol buffer object in the 'state_protobuf_object' argument.\n\n**Arguments**:\n\n- `state_protobuf_object`: the protocol buffer object whose type corresponds with this class.\n\n**Returns**:\n\nA new instance of this class that matches the protocol buffer object in the 'state_protobuf_object' argument.\n\n<a id=\"aea.helpers.transaction.base.State.__eq__\"></a>\n\n#### `__`eq`__`\n\n```python\ndef __eq__(other: Any) -> bool\n```\n\nCheck equality.\n\n<a id=\"aea.helpers.transaction.base.State.__str__\"></a>\n\n#### `__`str`__`\n\n```python\ndef __str__() -> str\n```\n\nGet string representation.\n\n<a id=\"aea.helpers.transaction.base.Terms\"></a>\n\n## Terms Objects\n\n```python\nclass Terms()\n```\n\nClass to represent the terms of a multi-currency & multi-token ledger transaction.\n\n<a id=\"aea.helpers.transaction.base.Terms.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(ledger_id: str,\n             sender_address: Address,\n             counterparty_address: Address,\n             amount_by_currency_id: Dict[str, int],\n             quantities_by_good_id: Dict[str, int],\n             nonce: str,\n             is_sender_payable_tx_fee: bool = True,\n             fee_by_currency_id: Optional[Dict[str, int]] = None,\n             is_strict: bool = False,\n             **kwargs: Any) -> None\n```\n\nInstantiate terms of a transaction.\n\n**Arguments**:\n\n- `ledger_id`: the ledger on which the terms are to be settled.\n- `sender_address`: the sender address of the transaction.\n- `counterparty_address`: the counterparty address of the transaction.\n- `amount_by_currency_id`: the amount by the currency of the transaction.\n- `quantities_by_good_id`: a map from good id to the quantity of that good involved in the transaction.\n- `nonce`: nonce to be included in transaction to discriminate otherwise identical transactions.\n- `is_sender_payable_tx_fee`: whether the sender or counterparty pays the tx fee.\n- `fee_by_currency_id`: the fee associated with the transaction.\n- `is_strict`: whether or not terms must have quantities and amounts of opposite signs.\n- `kwargs`: keyword arguments\n\n<a id=\"aea.helpers.transaction.base.Terms.id\"></a>\n\n#### id\n\n```python\n@property\ndef id() -> str\n```\n\nGet hash of the terms.\n\n<a id=\"aea.helpers.transaction.base.Terms.sender_hash\"></a>\n\n#### sender`_`hash\n\n```python\n@property\ndef sender_hash() -> str\n```\n\nGet the sender hash.\n\n<a id=\"aea.helpers.transaction.base.Terms.counterparty_hash\"></a>\n\n#### counterparty`_`hash\n\n```python\n@property\ndef counterparty_hash() -> str\n```\n\nGet the sender hash.\n\n<a id=\"aea.helpers.transaction.base.Terms.ledger_id\"></a>\n\n#### ledger`_`id\n\n```python\n@property\ndef ledger_id() -> str\n```\n\nGet the id of the ledger on which the terms are to be settled.\n\n<a id=\"aea.helpers.transaction.base.Terms.sender_address\"></a>\n\n#### sender`_`address\n\n```python\n@property\ndef sender_address() -> Address\n```\n\nGet the sender address.\n\n<a id=\"aea.helpers.transaction.base.Terms.counterparty_address\"></a>\n\n#### counterparty`_`address\n\n```python\n@property\ndef counterparty_address() -> Address\n```\n\nGet the counterparty address.\n\n<a id=\"aea.helpers.transaction.base.Terms.counterparty_address\"></a>\n\n#### counterparty`_`address\n\n```python\n@counterparty_address.setter\ndef counterparty_address(counterparty_address: Address) -> None\n```\n\nSet the counterparty address.\n\n<a id=\"aea.helpers.transaction.base.Terms.amount_by_currency_id\"></a>\n\n#### amount`_`by`_`currency`_`id\n\n```python\n@property\ndef amount_by_currency_id() -> Dict[str, int]\n```\n\nGet the amount by currency id.\n\n<a id=\"aea.helpers.transaction.base.Terms.is_sender_payable_tx_fee\"></a>\n\n#### is`_`sender`_`payable`_`tx`_`fee\n\n```python\n@property\ndef is_sender_payable_tx_fee() -> bool\n```\n\nBool indicating whether the tx fee is paid by sender or counterparty.\n\n<a id=\"aea.helpers.transaction.base.Terms.is_single_currency\"></a>\n\n#### is`_`single`_`currency\n\n```python\n@property\ndef is_single_currency() -> bool\n```\n\nCheck whether a single currency is used for payment.\n\n<a id=\"aea.helpers.transaction.base.Terms.is_empty_currency\"></a>\n\n#### is`_`empty`_`currency\n\n```python\n@property\ndef is_empty_currency() -> bool\n```\n\nCheck whether a single currency is used for payment.\n\n<a id=\"aea.helpers.transaction.base.Terms.currency_id\"></a>\n\n#### currency`_`id\n\n```python\n@property\ndef currency_id() -> str\n```\n\nGet the amount the sender must pay.\n\n<a id=\"aea.helpers.transaction.base.Terms.sender_payable_amount\"></a>\n\n#### sender`_`payable`_`amount\n\n```python\n@property\ndef sender_payable_amount() -> int\n```\n\nGet the amount the sender must pay.\n\n<a id=\"aea.helpers.transaction.base.Terms.sender_payable_amount_incl_fee\"></a>\n\n#### sender`_`payable`_`amount`_`incl`_`fee\n\n```python\n@property\ndef sender_payable_amount_incl_fee() -> int\n```\n\nGet the amount the sender must pay inclusive fee.\n\n<a id=\"aea.helpers.transaction.base.Terms.counterparty_payable_amount\"></a>\n\n#### counterparty`_`payable`_`amount\n\n```python\n@property\ndef counterparty_payable_amount() -> int\n```\n\nGet the amount the counterparty must pay.\n\n<a id=\"aea.helpers.transaction.base.Terms.counterparty_payable_amount_incl_fee\"></a>\n\n#### counterparty`_`payable`_`amount`_`incl`_`fee\n\n```python\n@property\ndef counterparty_payable_amount_incl_fee() -> int\n```\n\nGet the amount the counterparty must pay.\n\n<a id=\"aea.helpers.transaction.base.Terms.quantities_by_good_id\"></a>\n\n#### quantities`_`by`_`good`_`id\n\n```python\n@property\ndef quantities_by_good_id() -> Dict[str, int]\n```\n\nGet the quantities by good id.\n\n<a id=\"aea.helpers.transaction.base.Terms.good_ids\"></a>\n\n#### good`_`ids\n\n```python\n@property\ndef good_ids() -> List[str]\n```\n\nGet the (ordered) good ids.\n\n<a id=\"aea.helpers.transaction.base.Terms.sender_supplied_quantities\"></a>\n\n#### sender`_`supplied`_`quantities\n\n```python\n@property\ndef sender_supplied_quantities() -> List[int]\n```\n\nGet the (ordered) quantities supplied by the sender.\n\n<a id=\"aea.helpers.transaction.base.Terms.counterparty_supplied_quantities\"></a>\n\n#### counterparty`_`supplied`_`quantities\n\n```python\n@property\ndef counterparty_supplied_quantities() -> List[int]\n```\n\nGet the (ordered) quantities supplied by the counterparty.\n\n<a id=\"aea.helpers.transaction.base.Terms.nonce\"></a>\n\n#### nonce\n\n```python\n@property\ndef nonce() -> str\n```\n\nGet the nonce.\n\n<a id=\"aea.helpers.transaction.base.Terms.has_fee\"></a>\n\n#### has`_`fee\n\n```python\n@property\ndef has_fee() -> bool\n```\n\nCheck if fee is set.\n\n<a id=\"aea.helpers.transaction.base.Terms.fee\"></a>\n\n#### fee\n\n```python\n@property\ndef fee() -> int\n```\n\nGet the fee.\n\n<a id=\"aea.helpers.transaction.base.Terms.sender_fee\"></a>\n\n#### sender`_`fee\n\n```python\n@property\ndef sender_fee() -> int\n```\n\nGet the sender fee.\n\n<a id=\"aea.helpers.transaction.base.Terms.counterparty_fee\"></a>\n\n#### counterparty`_`fee\n\n```python\n@property\ndef counterparty_fee() -> int\n```\n\nGet the counterparty fee.\n\n<a id=\"aea.helpers.transaction.base.Terms.fee_by_currency_id\"></a>\n\n#### fee`_`by`_`currency`_`id\n\n```python\n@property\ndef fee_by_currency_id() -> Dict[str, int]\n```\n\nGet fee by currency.\n\n<a id=\"aea.helpers.transaction.base.Terms.kwargs\"></a>\n\n#### kwargs\n\n```python\n@property\ndef kwargs() -> JSONLike\n```\n\nGet the kwargs.\n\n<a id=\"aea.helpers.transaction.base.Terms.is_strict\"></a>\n\n#### is`_`strict\n\n```python\n@property\ndef is_strict() -> bool\n```\n\nGet is_strict.\n\n<a id=\"aea.helpers.transaction.base.Terms.get_hash\"></a>\n\n#### get`_`hash\n\n```python\n@staticmethod\ndef get_hash(ledger_id: str, sender_address: str, counterparty_address: str,\n             good_ids: List[str], sender_supplied_quantities: List[int],\n             counterparty_supplied_quantities: List[int],\n             sender_payable_amount: int, counterparty_payable_amount: int,\n             nonce: str) -> str\n```\n\nGenerate a hash from transaction information.\n\n**Arguments**:\n\n- `ledger_id`: the ledger id\n- `sender_address`: the sender address\n- `counterparty_address`: the counterparty address\n- `good_ids`: the list of good ids\n- `sender_supplied_quantities`: the quantities supplied by the sender (must all be positive)\n- `counterparty_supplied_quantities`: the quantities supplied by the counterparty (must all be positive)\n- `sender_payable_amount`: the amount payable by the sender\n- `counterparty_payable_amount`: the amount payable by the counterparty\n- `nonce`: the nonce of the transaction\n\n**Returns**:\n\nthe hash\n\n<a id=\"aea.helpers.transaction.base.Terms.encode\"></a>\n\n#### encode\n\n```python\n@staticmethod\ndef encode(terms_protobuf_object: Any, terms_object: \"Terms\") -> None\n```\n\nEncode an instance of this class into the protocol buffer object.\n\nThe protocol buffer object in the terms_protobuf_object argument must be matched with the instance of this class in the 'terms_object' argument.\n\n**Arguments**:\n\n- `terms_protobuf_object`: the protocol buffer object whose type corresponds with this class.\n- `terms_object`: an instance of this class to be encoded in the protocol buffer object.\n\n<a id=\"aea.helpers.transaction.base.Terms.decode\"></a>\n\n#### decode\n\n```python\n@classmethod\ndef decode(cls, terms_protobuf_object: Any) -> \"Terms\"\n```\n\nDecode a protocol buffer object that corresponds with this class into an instance of this class.\n\nA new instance of this class must be created that matches the protocol buffer object in the 'terms_protobuf_object' argument.\n\n**Arguments**:\n\n- `terms_protobuf_object`: the protocol buffer object whose type corresponds with this class.\n\n**Returns**:\n\nA new instance of this class that matches the protocol buffer object in the 'terms_protobuf_object' argument.\n\n<a id=\"aea.helpers.transaction.base.Terms.__eq__\"></a>\n\n#### `__`eq`__`\n\n```python\ndef __eq__(other: Any) -> bool\n```\n\nCheck equality.\n\n<a id=\"aea.helpers.transaction.base.Terms.__str__\"></a>\n\n#### `__`str`__`\n\n```python\ndef __str__() -> str\n```\n\nGet string representation.\n\n<a id=\"aea.helpers.transaction.base.TransactionDigest\"></a>\n\n## TransactionDigest Objects\n\n```python\nclass TransactionDigest()\n```\n\nThis class represents an instance of TransactionDigest.\n\n<a id=\"aea.helpers.transaction.base.TransactionDigest.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(ledger_id: str, body: str) -> None\n```\n\nInitialise an instance of TransactionDigest.\n\n<a id=\"aea.helpers.transaction.base.TransactionDigest.ledger_id\"></a>\n\n#### ledger`_`id\n\n```python\n@property\ndef ledger_id() -> str\n```\n\nGet the id of the ledger on which the terms are to be settled.\n\n<a id=\"aea.helpers.transaction.base.TransactionDigest.body\"></a>\n\n#### body\n\n```python\n@property\ndef body() -> str\n```\n\nGet the receipt.\n\n<a id=\"aea.helpers.transaction.base.TransactionDigest.encode\"></a>\n\n#### encode\n\n```python\n@staticmethod\ndef encode(transaction_digest_protobuf_object: Any,\n           transaction_digest_object: \"TransactionDigest\") -> None\n```\n\nEncode an instance of this class into the protocol buffer object.\n\nThe protocol buffer object in the transaction_digest_protobuf_object argument must be matched with the instance of this class in the 'transaction_digest_object' argument.\n\n**Arguments**:\n\n- `transaction_digest_protobuf_object`: the protocol buffer object whose type corresponds with this class.\n- `transaction_digest_object`: an instance of this class to be encoded in the protocol buffer object.\n\n<a id=\"aea.helpers.transaction.base.TransactionDigest.decode\"></a>\n\n#### decode\n\n```python\n@classmethod\ndef decode(cls,\n           transaction_digest_protobuf_object: Any) -> \"TransactionDigest\"\n```\n\nDecode a protocol buffer object that corresponds with this class into an instance of this class.\n\nA new instance of this class must be created that matches the protocol buffer object in the 'transaction_digest_protobuf_object' argument.\n\n**Arguments**:\n\n- `transaction_digest_protobuf_object`: the protocol buffer object whose type corresponds with this class.\n\n**Returns**:\n\nA new instance of this class that matches the protocol buffer object in the 'transaction_digest_protobuf_object' argument.\n\n<a id=\"aea.helpers.transaction.base.TransactionDigest.__eq__\"></a>\n\n#### `__`eq`__`\n\n```python\ndef __eq__(other: Any) -> bool\n```\n\nCheck equality.\n\n<a id=\"aea.helpers.transaction.base.TransactionDigest.__str__\"></a>\n\n#### `__`str`__`\n\n```python\ndef __str__() -> str\n```\n\nGet string representation.\n\n<a id=\"aea.helpers.transaction.base.TransactionReceipt\"></a>\n\n## TransactionReceipt Objects\n\n```python\nclass TransactionReceipt()\n```\n\nThis class represents an instance of TransactionReceipt.\n\n<a id=\"aea.helpers.transaction.base.TransactionReceipt.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(ledger_id: str, receipt: JSONLike, transaction: JSONLike) -> None\n```\n\nInitialise an instance of TransactionReceipt.\n\n<a id=\"aea.helpers.transaction.base.TransactionReceipt.ledger_id\"></a>\n\n#### ledger`_`id\n\n```python\n@property\ndef ledger_id() -> str\n```\n\nGet the id of the ledger on which the terms are to be settled.\n\n<a id=\"aea.helpers.transaction.base.TransactionReceipt.receipt\"></a>\n\n#### receipt\n\n```python\n@property\ndef receipt() -> JSONLike\n```\n\nGet the receipt.\n\n<a id=\"aea.helpers.transaction.base.TransactionReceipt.transaction\"></a>\n\n#### transaction\n\n```python\n@property\ndef transaction() -> JSONLike\n```\n\nGet the transaction.\n\n<a id=\"aea.helpers.transaction.base.TransactionReceipt.encode\"></a>\n\n#### encode\n\n```python\n@staticmethod\ndef encode(transaction_receipt_protobuf_object: Any,\n           transaction_receipt_object: \"TransactionReceipt\") -> None\n```\n\nEncode an instance of this class into the protocol buffer object.\n\nThe protocol buffer object in the transaction_receipt_protobuf_object argument must be matched with the instance of this class in the 'transaction_receipt_object' argument.\n\n**Arguments**:\n\n- `transaction_receipt_protobuf_object`: the protocol buffer object whose type corresponds with this class.\n- `transaction_receipt_object`: an instance of this class to be encoded in the protocol buffer object.\n\n<a id=\"aea.helpers.transaction.base.TransactionReceipt.decode\"></a>\n\n#### decode\n\n```python\n@classmethod\ndef decode(cls,\n           transaction_receipt_protobuf_object: Any) -> \"TransactionReceipt\"\n```\n\nDecode a protocol buffer object that corresponds with this class into an instance of this class.\n\nA new instance of this class must be created that matches the protocol buffer object in the 'transaction_receipt_protobuf_object' argument.\n\n**Arguments**:\n\n- `transaction_receipt_protobuf_object`: the protocol buffer object whose type corresponds with this class.\n\n**Returns**:\n\nA new instance of this class that matches the protocol buffer object in the 'transaction_receipt_protobuf_object' argument.\n\n<a id=\"aea.helpers.transaction.base.TransactionReceipt.__eq__\"></a>\n\n#### `__`eq`__`\n\n```python\ndef __eq__(other: Any) -> bool\n```\n\nCheck equality.\n\n<a id=\"aea.helpers.transaction.base.TransactionReceipt.__str__\"></a>\n\n#### `__`str`__`\n\n```python\ndef __str__() -> str\n```\n\nGet string representation.\n\n"
  },
  {
    "path": "docs/api/helpers/win32.md",
    "content": "<a id=\"aea.helpers.win32\"></a>\n\n# aea.helpers.win32\n\nHelpers for Windows.\n\n<a id=\"aea.helpers.win32.enable_ctrl_c_support\"></a>\n\n#### enable`_`ctrl`_`c`_`support\n\n```python\ndef enable_ctrl_c_support() -> None\n```\n\nEnable ctrl+c support for aea.cli command to be tested on windows platform.\n\n"
  },
  {
    "path": "docs/api/helpers/yaml_utils.md",
    "content": "<a id=\"aea.helpers.yaml_utils\"></a>\n\n# aea.helpers.yaml`_`utils\n\nHelper functions related to YAML loading/dumping.\n\n<a id=\"aea.helpers.yaml_utils._AEAYamlLoader\"></a>\n\n## `_`AEAYamlLoader Objects\n\n```python\nclass _AEAYamlLoader(yaml.SafeLoader)\n```\n\nCustom yaml.SafeLoader for the AEA framework.\n\nIt extends the default SafeLoader in two ways:\n- loads YAML configurations while *remembering the order of the fields*;\n- resolves the environment variables at loading time.\n\nThis class is for internal usage only; please use\nthe public functions of the module 'yaml_load' and 'yaml_load_all'.\n\n<a id=\"aea.helpers.yaml_utils._AEAYamlLoader.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(*args: Any, **kwargs: Any) -> None\n```\n\nInitialize the AEAYamlLoader.\n\nIt adds a YAML Loader constructor to use 'OderedDict' to load the files.\n\n**Arguments**:\n\n- `args`: the positional arguments.\n- `kwargs`: the keyword arguments.\n\n<a id=\"aea.helpers.yaml_utils._AEAYamlDumper\"></a>\n\n## `_`AEAYamlDumper Objects\n\n```python\nclass _AEAYamlDumper(yaml.SafeDumper)\n```\n\nCustom yaml.SafeDumper for the AEA framework.\n\nIt extends the default SafeDumper so to dump\nYAML configurations while *following the order of the fields*.\n\nThis class is for internal usage only; please use\nthe public functions of the module 'yaml_dump' and 'yaml_dump_all'.\n\n<a id=\"aea.helpers.yaml_utils._AEAYamlDumper.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(*args: Any, **kwargs: Any) -> None\n```\n\nInitialize the AEAYamlDumper.\n\nIt adds a YAML Dumper representer to use 'OderedDict' to dump the files.\n\n**Arguments**:\n\n- `args`: the positional arguments.\n- `kwargs`: the keyword arguments.\n\n<a id=\"aea.helpers.yaml_utils.yaml_load\"></a>\n\n#### yaml`_`load\n\n```python\ndef yaml_load(stream: TextIO) -> Dict[str, Any]\n```\n\nLoad a yaml from a file pointer in an ordered way.\n\n**Arguments**:\n\n- `stream`: file pointer to the input file.\n\n**Returns**:\n\nthe dictionary object with the YAML file content.\n\n<a id=\"aea.helpers.yaml_utils.yaml_load_all\"></a>\n\n#### yaml`_`load`_`all\n\n```python\ndef yaml_load_all(stream: TextIO) -> List[Dict[str, Any]]\n```\n\nLoad a multi-paged yaml from a file pointer in an ordered way.\n\n**Arguments**:\n\n- `stream`: file pointer to the input file.\n\n**Returns**:\n\nthe list of dictionary objects with the (multi-paged) YAML file content.\n\n<a id=\"aea.helpers.yaml_utils.yaml_dump\"></a>\n\n#### yaml`_`dump\n\n```python\ndef yaml_dump(data: Dict, stream: Optional[TextIO] = None) -> None\n```\n\nDump YAML data to a yaml file in an ordered way.\n\n**Arguments**:\n\n- `data`: the data to write.\n- `stream`: (optional) the file to write on.\n\n<a id=\"aea.helpers.yaml_utils.yaml_dump_all\"></a>\n\n#### yaml`_`dump`_`all\n\n```python\ndef yaml_dump_all(data: Sequence[Dict],\n                  stream: Optional[TextIO] = None) -> None\n```\n\nDump YAML data to a yaml file in an ordered way.\n\n**Arguments**:\n\n- `data`: the data to write.\n- `stream`: (optional) the file to write on.\n\n"
  },
  {
    "path": "docs/api/identity/base.md",
    "content": "<a id=\"aea.identity.base\"></a>\n\n# aea.identity.base\n\nThis module contains the identity class.\n\n<a id=\"aea.identity.base.Identity\"></a>\n\n## Identity Objects\n\n```python\nclass Identity()\n```\n\nThe identity holds the public elements identifying an agent.\n\nIt includes:\n\n- the agent name\n- the addresses, a map from address identifier to address (can be a single key-value pair)\n\n<a id=\"aea.identity.base.Identity.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(name: SimpleIdOrStr,\n             address: Optional[str] = None,\n             public_key: Optional[str] = None,\n             addresses: Optional[Dict[str, Address]] = None,\n             public_keys: Optional[Dict[str, str]] = None,\n             default_address_key: str = DEFAULT_LEDGER) -> None\n```\n\nInstantiate the identity.\n\n**Arguments**:\n\n- `name`: the name of the agent.\n- `address`: the default address of the agent.\n- `public_key`: the public key of the agent.\n- `addresses`: the addresses of the agent.\n- `public_keys`: the public keys of the agent.\n- `default_address_key`: the key for the default address.\n\n<a id=\"aea.identity.base.Identity.default_address_key\"></a>\n\n#### default`_`address`_`key\n\n```python\n@property\ndef default_address_key() -> str\n```\n\nGet the default address key.\n\n<a id=\"aea.identity.base.Identity.name\"></a>\n\n#### name\n\n```python\n@property\ndef name() -> str\n```\n\nGet the agent name.\n\n<a id=\"aea.identity.base.Identity.addresses\"></a>\n\n#### addresses\n\n```python\n@property\ndef addresses() -> Dict[str, Address]\n```\n\nGet the addresses.\n\n<a id=\"aea.identity.base.Identity.address\"></a>\n\n#### address\n\n```python\n@property\ndef address() -> Address\n```\n\nGet the default address.\n\n<a id=\"aea.identity.base.Identity.public_keys\"></a>\n\n#### public`_`keys\n\n```python\n@property\ndef public_keys() -> Dict[str, str]\n```\n\nGet the public keys.\n\n<a id=\"aea.identity.base.Identity.public_key\"></a>\n\n#### public`_`key\n\n```python\n@property\ndef public_key() -> str\n```\n\nGet the default public key.\n\n"
  },
  {
    "path": "docs/api/launcher.md",
    "content": "<a id=\"aea.launcher\"></a>\n\n# aea.launcher\n\nThis module contains the implementation of multiple AEA configs launcher.\n\n<a id=\"aea.launcher.load_agent\"></a>\n\n#### load`_`agent\n\n```python\ndef load_agent(agent_dir: Union[PathLike, str],\n               password: Optional[str] = None) -> AEA\n```\n\nLoad AEA from directory.\n\n**Arguments**:\n\n- `agent_dir`: agent configuration directory\n- `password`: the password to encrypt/decrypt the private key.\n\n**Returns**:\n\nAEA instance\n\n<a id=\"aea.launcher.AEADirTask\"></a>\n\n## AEADirTask Objects\n\n```python\nclass AEADirTask(AbstractExecutorTask)\n```\n\nTask to run agent from agent configuration directory.\n\n<a id=\"aea.launcher.AEADirTask.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(agent_dir: Union[PathLike, str],\n             password: Optional[str] = None) -> None\n```\n\nInit aea config dir task.\n\n**Arguments**:\n\n- `agent_dir`: directory with aea config.\n- `password`: the password to encrypt/decrypt the private key.\n\n<a id=\"aea.launcher.AEADirTask.id\"></a>\n\n#### id\n\n```python\n@property\ndef id() -> Union[PathLike, str]\n```\n\nReturn agent_dir.\n\n<a id=\"aea.launcher.AEADirTask.start\"></a>\n\n#### start\n\n```python\ndef start() -> None\n```\n\nStart task.\n\n<a id=\"aea.launcher.AEADirTask.stop\"></a>\n\n#### stop\n\n```python\ndef stop() -> None\n```\n\nStop task.\n\n<a id=\"aea.launcher.AEADirTask.create_async_task\"></a>\n\n#### create`_`async`_`task\n\n```python\ndef create_async_task(loop: AbstractEventLoop) -> TaskAwaitable\n```\n\nReturn asyncio Task for task run in asyncio loop.\n\n<a id=\"aea.launcher.AEADirMultiprocessTask\"></a>\n\n## AEADirMultiprocessTask Objects\n\n```python\nclass AEADirMultiprocessTask(AbstractMultiprocessExecutorTask)\n```\n\nTask to run agent from agent configuration directory.\n\nVersion for multiprocess executor mode.\n\n<a id=\"aea.launcher.AEADirMultiprocessTask.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(agent_dir: Union[PathLike, str],\n             log_level: Optional[str] = None,\n             password: Optional[str] = None) -> None\n```\n\nInit aea config dir task.\n\n**Arguments**:\n\n- `agent_dir`: directory with aea config.\n- `log_level`: debug level applied for AEA in subprocess\n- `password`: the password to encrypt/decrypt the private key.\n\n<a id=\"aea.launcher.AEADirMultiprocessTask.id\"></a>\n\n#### id\n\n```python\n@property\ndef id() -> Union[PathLike, str]\n```\n\nReturn agent_dir.\n\n<a id=\"aea.launcher.AEADirMultiprocessTask.failed\"></a>\n\n#### failed\n\n```python\n@property\ndef failed() -> bool\n```\n\nReturn was exception failed or not.\n\nIf it's running it's not failed.\n\n**Returns**:\n\nbool\n\n<a id=\"aea.launcher.AEADirMultiprocessTask.start\"></a>\n\n#### start\n\n```python\ndef start() -> Tuple[Callable, Sequence[Any]]\n```\n\nReturn function and arguments to call within subprocess.\n\n<a id=\"aea.launcher.AEADirMultiprocessTask.stop\"></a>\n\n#### stop\n\n```python\ndef stop() -> None\n```\n\nStop task.\n\n<a id=\"aea.launcher.AEALauncher\"></a>\n\n## AEALauncher Objects\n\n```python\nclass AEALauncher(AbstractMultipleRunner)\n```\n\nRun multiple AEA instances.\n\n<a id=\"aea.launcher.AEALauncher.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(agent_dirs: Sequence[Union[PathLike, str]],\n             mode: str,\n             fail_policy: ExecutorExceptionPolicies = ExecutorExceptionPolicies\n             .propagate,\n             log_level: Optional[str] = None,\n             password: Optional[str] = None) -> None\n```\n\nInit AEALauncher.\n\n**Arguments**:\n\n- `agent_dirs`: sequence of AEA config directories.\n- `mode`: executor name to use.\n- `fail_policy`: one of ExecutorExceptionPolicies to be used with Executor\n- `log_level`: debug level applied for AEA in subprocesses\n- `password`: the password to encrypt/decrypt the private key.\n\n"
  },
  {
    "path": "docs/api/mail/base.md",
    "content": "<a id=\"aea.mail.base\"></a>\n\n# aea.mail.base\n\nMail module abstract base classes.\n\n<a id=\"aea.mail.base.URI\"></a>\n\n## URI Objects\n\n```python\nclass URI()\n```\n\nURI following RFC3986.\n\n<a id=\"aea.mail.base.URI.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(uri_raw: str) -> None\n```\n\nInitialize the URI.\n\nMust follow: https://tools.ietf.org/html/rfc3986.html\n\n**Arguments**:\n\n- `uri_raw`: the raw form uri\n\n<a id=\"aea.mail.base.URI.scheme\"></a>\n\n#### scheme\n\n```python\n@property\ndef scheme() -> str\n```\n\nGet the scheme.\n\n<a id=\"aea.mail.base.URI.netloc\"></a>\n\n#### netloc\n\n```python\n@property\ndef netloc() -> str\n```\n\nGet the netloc.\n\n<a id=\"aea.mail.base.URI.path\"></a>\n\n#### path\n\n```python\n@property\ndef path() -> str\n```\n\nGet the path.\n\n<a id=\"aea.mail.base.URI.params\"></a>\n\n#### params\n\n```python\n@property\ndef params() -> str\n```\n\nGet the params.\n\n<a id=\"aea.mail.base.URI.query\"></a>\n\n#### query\n\n```python\n@property\ndef query() -> str\n```\n\nGet the query.\n\n<a id=\"aea.mail.base.URI.fragment\"></a>\n\n#### fragment\n\n```python\n@property\ndef fragment() -> str\n```\n\nGet the fragment.\n\n<a id=\"aea.mail.base.URI.username\"></a>\n\n#### username\n\n```python\n@property\ndef username() -> Optional[str]\n```\n\nGet the username.\n\n<a id=\"aea.mail.base.URI.password\"></a>\n\n#### password\n\n```python\n@property\ndef password() -> Optional[str]\n```\n\nGet the password.\n\n<a id=\"aea.mail.base.URI.host\"></a>\n\n#### host\n\n```python\n@property\ndef host() -> Optional[str]\n```\n\nGet the host.\n\n<a id=\"aea.mail.base.URI.port\"></a>\n\n#### port\n\n```python\n@property\ndef port() -> Optional[int]\n```\n\nGet the port.\n\n<a id=\"aea.mail.base.URI.__str__\"></a>\n\n#### `__`str`__`\n\n```python\ndef __str__() -> str\n```\n\nGet string representation.\n\n<a id=\"aea.mail.base.URI.__eq__\"></a>\n\n#### `__`eq`__`\n\n```python\ndef __eq__(other: Any) -> bool\n```\n\nCompare with another object.\n\n<a id=\"aea.mail.base.EnvelopeContext\"></a>\n\n## EnvelopeContext Objects\n\n```python\nclass EnvelopeContext()\n```\n\nContains context information of an envelope.\n\n<a id=\"aea.mail.base.EnvelopeContext.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(connection_id: Optional[PublicId] = None,\n             uri: Optional[URI] = None) -> None\n```\n\nInitialize the envelope context.\n\n**Arguments**:\n\n- `connection_id`: the connection id used for routing the outgoing envelope in the multiplexer.\n- `uri`: the URI sent with the envelope.\n\n<a id=\"aea.mail.base.EnvelopeContext.uri\"></a>\n\n#### uri\n\n```python\n@property\ndef uri() -> Optional[URI]\n```\n\nGet the URI.\n\n<a id=\"aea.mail.base.EnvelopeContext.connection_id\"></a>\n\n#### connection`_`id\n\n```python\n@property\ndef connection_id() -> Optional[PublicId]\n```\n\nGet the connection id to route the envelope.\n\n<a id=\"aea.mail.base.EnvelopeContext.connection_id\"></a>\n\n#### connection`_`id\n\n```python\n@connection_id.setter\ndef connection_id(connection_id: PublicId) -> None\n```\n\nSet the 'via' connection id.\n\n<a id=\"aea.mail.base.EnvelopeContext.__str__\"></a>\n\n#### `__`str`__`\n\n```python\ndef __str__() -> str\n```\n\nGet the string representation.\n\n<a id=\"aea.mail.base.EnvelopeContext.__eq__\"></a>\n\n#### `__`eq`__`\n\n```python\ndef __eq__(other: Any) -> bool\n```\n\nCompare with another object.\n\n<a id=\"aea.mail.base.AEAConnectionError\"></a>\n\n## AEAConnectionError Objects\n\n```python\nclass AEAConnectionError(Exception)\n```\n\nException class for connection errors.\n\n<a id=\"aea.mail.base.Empty\"></a>\n\n## Empty Objects\n\n```python\nclass Empty(Exception)\n```\n\nException for when the inbox is empty.\n\n<a id=\"aea.mail.base.EnvelopeSerializer\"></a>\n\n## EnvelopeSerializer Objects\n\n```python\nclass EnvelopeSerializer(ABC)\n```\n\nAbstract class to specify the serialization layer for the envelope.\n\n<a id=\"aea.mail.base.EnvelopeSerializer.encode\"></a>\n\n#### encode\n\n```python\n@abstractmethod\ndef encode(envelope: \"Envelope\") -> bytes\n```\n\nEncode the envelope.\n\n**Arguments**:\n\n- `envelope`: the envelope to encode\n\n**Returns**:\n\nthe encoded envelope\n\n<a id=\"aea.mail.base.EnvelopeSerializer.decode\"></a>\n\n#### decode\n\n```python\n@abstractmethod\ndef decode(envelope_bytes: bytes) -> \"Envelope\"\n```\n\nDecode the envelope.\n\n**Arguments**:\n\n- `envelope_bytes`: the encoded envelope\n\n**Returns**:\n\nthe envelope\n\n<a id=\"aea.mail.base.ProtobufEnvelopeSerializer\"></a>\n\n## ProtobufEnvelopeSerializer Objects\n\n```python\nclass ProtobufEnvelopeSerializer(EnvelopeSerializer)\n```\n\nEnvelope serializer using Protobuf.\n\n<a id=\"aea.mail.base.ProtobufEnvelopeSerializer.encode\"></a>\n\n#### encode\n\n```python\ndef encode(envelope: \"Envelope\") -> bytes\n```\n\nEncode the envelope.\n\n**Arguments**:\n\n- `envelope`: the envelope to encode\n\n**Returns**:\n\nthe encoded envelope\n\n<a id=\"aea.mail.base.ProtobufEnvelopeSerializer.decode\"></a>\n\n#### decode\n\n```python\ndef decode(envelope_bytes: bytes) -> \"Envelope\"\n```\n\nDecode the envelope.\n\nThe default serializer doesn't decode the message field.\n\n**Arguments**:\n\n- `envelope_bytes`: the encoded envelope\n\n**Returns**:\n\nthe envelope\n\n<a id=\"aea.mail.base.Envelope\"></a>\n\n## Envelope Objects\n\n```python\nclass Envelope()\n```\n\nThe top level message class for agent to agent communication.\n\n<a id=\"aea.mail.base.Envelope.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(to: Address,\n             sender: Address,\n             message: Union[Message, bytes],\n             context: Optional[EnvelopeContext] = None,\n             protocol_specification_id: Optional[PublicId] = None) -> None\n```\n\nInitialize a Message object.\n\n**Arguments**:\n\n- `to`: the address of the receiver.\n- `sender`: the address of the sender.\n- `message`: the protocol-specific message.\n- `context`: the optional envelope context.\n- `protocol_specification_id`: the protocol specification id (wire id).\n\n<a id=\"aea.mail.base.Envelope.to\"></a>\n\n#### to\n\n```python\n@property\ndef to() -> Address\n```\n\nGet address of receiver.\n\n<a id=\"aea.mail.base.Envelope.to\"></a>\n\n#### to\n\n```python\n@to.setter\ndef to(to: Address) -> None\n```\n\nSet address of receiver.\n\n<a id=\"aea.mail.base.Envelope.sender\"></a>\n\n#### sender\n\n```python\n@property\ndef sender() -> Address\n```\n\nGet address of sender.\n\n<a id=\"aea.mail.base.Envelope.sender\"></a>\n\n#### sender\n\n```python\n@sender.setter\ndef sender(sender: Address) -> None\n```\n\nSet address of sender.\n\n<a id=\"aea.mail.base.Envelope.protocol_specification_id\"></a>\n\n#### protocol`_`specification`_`id\n\n```python\n@property\ndef protocol_specification_id() -> PublicId\n```\n\nGet protocol_specification_id.\n\n<a id=\"aea.mail.base.Envelope.message\"></a>\n\n#### message\n\n```python\n@property\ndef message() -> Union[Message, bytes]\n```\n\nGet the protocol-specific message.\n\n<a id=\"aea.mail.base.Envelope.message\"></a>\n\n#### message\n\n```python\n@message.setter\ndef message(message: Union[Message, bytes]) -> None\n```\n\nSet the protocol-specific message.\n\n<a id=\"aea.mail.base.Envelope.message_bytes\"></a>\n\n#### message`_`bytes\n\n```python\n@property\ndef message_bytes() -> bytes\n```\n\nGet the protocol-specific message.\n\n<a id=\"aea.mail.base.Envelope.context\"></a>\n\n#### context\n\n```python\n@property\ndef context() -> Optional[EnvelopeContext]\n```\n\nGet the envelope context.\n\n<a id=\"aea.mail.base.Envelope.to_as_public_id\"></a>\n\n#### to`_`as`_`public`_`id\n\n```python\n@property\ndef to_as_public_id() -> Optional[PublicId]\n```\n\nGet to as public id.\n\n<a id=\"aea.mail.base.Envelope.is_sender_public_id\"></a>\n\n#### is`_`sender`_`public`_`id\n\n```python\n@property\ndef is_sender_public_id() -> bool\n```\n\nCheck if sender is a public id.\n\n<a id=\"aea.mail.base.Envelope.is_to_public_id\"></a>\n\n#### is`_`to`_`public`_`id\n\n```python\n@property\ndef is_to_public_id() -> bool\n```\n\nCheck if to is a public id.\n\n<a id=\"aea.mail.base.Envelope.is_component_to_component_message\"></a>\n\n#### is`_`component`_`to`_`component`_`message\n\n```python\n@property\ndef is_component_to_component_message() -> bool\n```\n\nWhether or not the message contained is component to component.\n\n<a id=\"aea.mail.base.Envelope.__eq__\"></a>\n\n#### `__`eq`__`\n\n```python\ndef __eq__(other: Any) -> bool\n```\n\nCompare with another object.\n\n<a id=\"aea.mail.base.Envelope.encode\"></a>\n\n#### encode\n\n```python\ndef encode(serializer: Optional[EnvelopeSerializer] = None) -> bytes\n```\n\nEncode the envelope.\n\n**Arguments**:\n\n- `serializer`: the serializer that implements the encoding procedure.\n\n**Returns**:\n\nthe encoded envelope.\n\n<a id=\"aea.mail.base.Envelope.decode\"></a>\n\n#### decode\n\n```python\n@classmethod\ndef decode(cls,\n           envelope_bytes: bytes,\n           serializer: Optional[EnvelopeSerializer] = None) -> \"Envelope\"\n```\n\nDecode the envelope.\n\n**Arguments**:\n\n- `envelope_bytes`: the bytes to be decoded.\n- `serializer`: the serializer that implements the decoding procedure.\n\n**Returns**:\n\nthe decoded envelope.\n\n<a id=\"aea.mail.base.Envelope.__str__\"></a>\n\n#### `__`str`__`\n\n```python\ndef __str__() -> str\n```\n\nGet the string representation of an envelope.\n\n"
  },
  {
    "path": "docs/api/manager/manager.md",
    "content": "<a id=\"aea.manager.manager\"></a>\n\n# aea.manager.manager\n\nThis module contains the implementation of AEA agents manager.\n\n<a id=\"aea.manager.manager.ProjectNotFoundError\"></a>\n\n## ProjectNotFoundError Objects\n\n```python\nclass ProjectNotFoundError(ValueError)\n```\n\nProject not found exception.\n\n<a id=\"aea.manager.manager.ProjectCheckError\"></a>\n\n## ProjectCheckError Objects\n\n```python\nclass ProjectCheckError(ValueError)\n```\n\nProject check error exception.\n\n<a id=\"aea.manager.manager.ProjectCheckError.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(msg: str, source_exception: Exception)\n```\n\nInit exception.\n\n<a id=\"aea.manager.manager.ProjectPackageConsistencyCheckError\"></a>\n\n## ProjectPackageConsistencyCheckError Objects\n\n```python\nclass ProjectPackageConsistencyCheckError(ValueError)\n```\n\nCheck consistency of package versions against already added project.\n\n<a id=\"aea.manager.manager.ProjectPackageConsistencyCheckError.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(agent_project_id: PublicId,\n             conflicting_packages: List[Tuple[PackageIdPrefix, str, str,\n                                              Set[PublicId]]])\n```\n\nInitialize the exception.\n\n**Arguments**:\n\n- `agent_project_id`: the agent project id whose addition has failed.\n- `conflicting_packages`: the conflicting packages.\n\n<a id=\"aea.manager.manager.BaseAgentRunTask\"></a>\n\n## BaseAgentRunTask Objects\n\n```python\nclass BaseAgentRunTask(ABC)\n```\n\nBase abstract class for agent run tasks.\n\n<a id=\"aea.manager.manager.BaseAgentRunTask.start\"></a>\n\n#### start\n\n```python\n@abstractmethod\ndef start() -> None\n```\n\nStart task.\n\n<a id=\"aea.manager.manager.BaseAgentRunTask.wait\"></a>\n\n#### wait\n\n```python\n@abstractmethod\ndef wait() -> asyncio.Future\n```\n\nReturn future to wait task completed.\n\n<a id=\"aea.manager.manager.BaseAgentRunTask.stop\"></a>\n\n#### stop\n\n```python\n@abstractmethod\ndef stop() -> None\n```\n\nStop task.\n\n<a id=\"aea.manager.manager.BaseAgentRunTask.is_running\"></a>\n\n#### is`_`running\n\n```python\n@property\n@abstractmethod\ndef is_running() -> bool\n```\n\nReturn is task running.\n\n<a id=\"aea.manager.manager.AgentRunAsyncTask\"></a>\n\n## AgentRunAsyncTask Objects\n\n```python\nclass AgentRunAsyncTask(BaseAgentRunTask)\n```\n\nAsync task wrapper for agent.\n\n<a id=\"aea.manager.manager.AgentRunAsyncTask.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(agent: AEA, loop: asyncio.AbstractEventLoop) -> None\n```\n\nInit task with agent alias and loop.\n\n<a id=\"aea.manager.manager.AgentRunAsyncTask.create_run_loop\"></a>\n\n#### create`_`run`_`loop\n\n```python\ndef create_run_loop() -> None\n```\n\nCreate run loop.\n\n<a id=\"aea.manager.manager.AgentRunAsyncTask.start\"></a>\n\n#### start\n\n```python\ndef start() -> None\n```\n\nStart task.\n\n<a id=\"aea.manager.manager.AgentRunAsyncTask.wait\"></a>\n\n#### wait\n\n```python\ndef wait() -> asyncio.Future\n```\n\nReturn future to wait task completed.\n\n<a id=\"aea.manager.manager.AgentRunAsyncTask.stop\"></a>\n\n#### stop\n\n```python\ndef stop() -> None\n```\n\nStop task.\n\n<a id=\"aea.manager.manager.AgentRunAsyncTask.run\"></a>\n\n#### run\n\n```python\nasync def run() -> None\n```\n\nRun task body.\n\n<a id=\"aea.manager.manager.AgentRunAsyncTask.is_running\"></a>\n\n#### is`_`running\n\n```python\n@property\ndef is_running() -> bool\n```\n\nReturn is task running.\n\n<a id=\"aea.manager.manager.AgentRunThreadTask\"></a>\n\n## AgentRunThreadTask Objects\n\n```python\nclass AgentRunThreadTask(AgentRunAsyncTask)\n```\n\nThreaded wrapper to run agent.\n\n<a id=\"aea.manager.manager.AgentRunThreadTask.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(agent: AEA, loop: asyncio.AbstractEventLoop) -> None\n```\n\nInit task with agent alias and loop.\n\n<a id=\"aea.manager.manager.AgentRunThreadTask.create_run_loop\"></a>\n\n#### create`_`run`_`loop\n\n```python\ndef create_run_loop() -> None\n```\n\nCreate run loop.\n\n<a id=\"aea.manager.manager.AgentRunThreadTask.start\"></a>\n\n#### start\n\n```python\ndef start() -> None\n```\n\nRun task in a dedicated thread.\n\n<a id=\"aea.manager.manager.AgentRunThreadTask.stop\"></a>\n\n#### stop\n\n```python\ndef stop() -> None\n```\n\nStop the task.\n\n<a id=\"aea.manager.manager.AgentRunProcessTask\"></a>\n\n## AgentRunProcessTask Objects\n\n```python\nclass AgentRunProcessTask(BaseAgentRunTask)\n```\n\nSubprocess wrapper to run agent.\n\n<a id=\"aea.manager.manager.AgentRunProcessTask.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(agent_alias: AgentAlias, loop: asyncio.AbstractEventLoop) -> None\n```\n\nInit task with agent alias and loop.\n\n<a id=\"aea.manager.manager.AgentRunProcessTask.start\"></a>\n\n#### start\n\n```python\ndef start() -> None\n```\n\nRun task in a dedicated process.\n\n<a id=\"aea.manager.manager.AgentRunProcessTask.wait\"></a>\n\n#### wait\n\n```python\ndef wait() -> asyncio.Future\n```\n\nReturn future to wait task completed.\n\n<a id=\"aea.manager.manager.AgentRunProcessTask.stop\"></a>\n\n#### stop\n\n```python\ndef stop() -> None\n```\n\nStop the task.\n\n<a id=\"aea.manager.manager.AgentRunProcessTask.is_running\"></a>\n\n#### is`_`running\n\n```python\n@property\ndef is_running() -> bool\n```\n\nIs agent running.\n\n<a id=\"aea.manager.manager.MultiAgentManager\"></a>\n\n## MultiAgentManager Objects\n\n```python\nclass MultiAgentManager()\n```\n\nMulti agents manager.\n\n<a id=\"aea.manager.manager.MultiAgentManager.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(working_dir: str,\n             mode: str = \"async\",\n             registry_path: str = DEFAULT_REGISTRY_NAME,\n             auto_add_remove_project: bool = False,\n             password: Optional[str] = None) -> None\n```\n\nInitialize manager.\n\n**Arguments**:\n\n- `working_dir`: directory to store base agents.\n- `mode`: str. async or threaded\n- `registry_path`: str. path to the local packages registry\n- `auto_add_remove_project`: bool. add/remove project on the first agent add/last agent remove\n- `password`: the password to encrypt/decrypt the private key.\n\n<a id=\"aea.manager.manager.MultiAgentManager.data_dir\"></a>\n\n#### data`_`dir\n\n```python\n@property\ndef data_dir() -> str\n```\n\nGet the certs directory.\n\n<a id=\"aea.manager.manager.MultiAgentManager.get_data_dir_of_agent\"></a>\n\n#### get`_`data`_`dir`_`of`_`agent\n\n```python\ndef get_data_dir_of_agent(agent_name: str) -> str\n```\n\nGet the data directory of a specific agent.\n\n<a id=\"aea.manager.manager.MultiAgentManager.is_running\"></a>\n\n#### is`_`running\n\n```python\n@property\ndef is_running() -> bool\n```\n\nIs manager running.\n\n<a id=\"aea.manager.manager.MultiAgentManager.dict_state\"></a>\n\n#### dict`_`state\n\n```python\n@property\ndef dict_state() -> Dict[str, Any]\n```\n\nCreate MultiAgentManager dist state.\n\n<a id=\"aea.manager.manager.MultiAgentManager.projects\"></a>\n\n#### projects\n\n```python\n@property\ndef projects() -> Dict[PublicId, Project]\n```\n\nGet all projects.\n\n<a id=\"aea.manager.manager.MultiAgentManager.add_error_callback\"></a>\n\n#### add`_`error`_`callback\n\n```python\ndef add_error_callback(\n    error_callback: Callable[[str, BaseException],\n                             None]) -> \"MultiAgentManager\"\n```\n\nAdd error callback to call on error raised.\n\n<a id=\"aea.manager.manager.MultiAgentManager.start_manager\"></a>\n\n#### start`_`manager\n\n```python\ndef start_manager(local: bool = False,\n                  remote: bool = False) -> \"MultiAgentManager\"\n```\n\nStart manager.\n\nIf local = False and remote = False, then the packages\nare fetched in mixed mode (i.e. first try from local\nregistry, and then from remote registry in case of failure).\n\n**Arguments**:\n\n- `local`: whether or not to fetch from local registry.\n- `remote`: whether or not to fetch from remote registry.\n\n**Returns**:\n\nthe MultiAgentManager instance.\n\n<a id=\"aea.manager.manager.MultiAgentManager.last_start_status\"></a>\n\n#### last`_`start`_`status\n\n```python\n@property\ndef last_start_status() -> Tuple[bool, Dict[PublicId, List[Dict]], List[Tuple[\n    PublicId, List[Dict], Exception]], ]\n```\n\nGet status of the last agents start loading state.\n\n<a id=\"aea.manager.manager.MultiAgentManager.stop_manager\"></a>\n\n#### stop`_`manager\n\n```python\ndef stop_manager(cleanup: bool = True,\n                 save: bool = False) -> \"MultiAgentManager\"\n```\n\nStop manager.\n\nStops all running agents and stop agent.\n\n**Arguments**:\n\n- `cleanup`: bool is cleanup on stop.\n- `save`: bool is save state to file on stop.\n\n**Returns**:\n\nNone\n\n<a id=\"aea.manager.manager.MultiAgentManager.add_project\"></a>\n\n#### add`_`project\n\n```python\ndef add_project(public_id: PublicId,\n                local: bool = False,\n                remote: bool = False,\n                restore: bool = False) -> \"MultiAgentManager\"\n```\n\nFetch agent project and all dependencies to working_dir.\n\nIf local = False and remote = False, then the packages\nare fetched in mixed mode (i.e. first try from local\nregistry, and then from remote registry in case of failure).\n\n**Arguments**:\n\n- `public_id`: the public if of the agent project.\n- `local`: whether or not to fetch from local registry.\n- `remote`: whether or not to fetch from remote registry.\n- `restore`: bool flag for restoring already fetched agent.\n\n**Returns**:\n\nself\n\n<a id=\"aea.manager.manager.MultiAgentManager.remove_project\"></a>\n\n#### remove`_`project\n\n```python\ndef remove_project(public_id: PublicId,\n                   keep_files: bool = False) -> \"MultiAgentManager\"\n```\n\nRemove agent project.\n\n<a id=\"aea.manager.manager.MultiAgentManager.list_projects\"></a>\n\n#### list`_`projects\n\n```python\ndef list_projects() -> List[PublicId]\n```\n\nList all agents projects added.\n\n**Returns**:\n\nlist of public ids of projects\n\n<a id=\"aea.manager.manager.MultiAgentManager.add_agent\"></a>\n\n#### add`_`agent\n\n```python\ndef add_agent(public_id: PublicId,\n              agent_name: Optional[str] = None,\n              agent_overrides: Optional[dict] = None,\n              component_overrides: Optional[List[dict]] = None,\n              local: bool = False,\n              remote: bool = False,\n              restore: bool = False) -> \"MultiAgentManager\"\n```\n\nCreate new agent configuration based on project with config overrides applied.\n\nAlias is stored in memory only!\n\n**Arguments**:\n\n- `public_id`: base agent project public id\n- `agent_name`: unique name for the agent\n- `agent_overrides`: overrides for agent config.\n- `component_overrides`: overrides for component section.\n- `local`: whether or not to fetch from local registry.\n- `remote`: whether or not to fetch from remote registry.\n- `restore`: bool flag for restoring already fetched agent.\n\n**Returns**:\n\nself\n\n<a id=\"aea.manager.manager.MultiAgentManager.add_agent_with_config\"></a>\n\n#### add`_`agent`_`with`_`config\n\n```python\ndef add_agent_with_config(\n        public_id: PublicId,\n        config: List[dict],\n        agent_name: Optional[str] = None) -> \"MultiAgentManager\"\n```\n\nCreate new agent configuration based on project with config provided.\n\nAlias is stored in memory only!\n\n**Arguments**:\n\n- `public_id`: base agent project public id\n- `agent_name`: unique name for the agent\n- `config`: agent config (used for agent re-creation).\n\n**Returns**:\n\nmanager\n\n<a id=\"aea.manager.manager.MultiAgentManager.get_agent_overridables\"></a>\n\n#### get`_`agent`_`overridables\n\n```python\ndef get_agent_overridables(agent_name: str) -> Tuple[Dict, List[Dict]]\n```\n\nGet agent config  overridables.\n\n**Arguments**:\n\n- `agent_name`: str\n\n**Returns**:\n\nTuple of agent overridables dict and  and list of component overridables dict.\n\n<a id=\"aea.manager.manager.MultiAgentManager.set_agent_overrides\"></a>\n\n#### set`_`agent`_`overrides\n\n```python\ndef set_agent_overrides(\n        agent_name: str, agent_overides: Optional[Dict],\n        components_overrides: Optional[List[Dict]]) -> \"MultiAgentManager\"\n```\n\nSet agent overrides.\n\n**Arguments**:\n\n- `agent_name`: str\n- `agent_overides`: optional dict of agent config overrides\n- `components_overrides`: optional list of dict of components overrides\n\n**Returns**:\n\nself\n\n<a id=\"aea.manager.manager.MultiAgentManager.list_agents_info\"></a>\n\n#### list`_`agents`_`info\n\n```python\ndef list_agents_info() -> List[Dict[str, Any]]\n```\n\nList agents detailed info.\n\n**Returns**:\n\nlist of dicts that represents agent info: public_id, name, is_running.\n\n<a id=\"aea.manager.manager.MultiAgentManager.list_agents\"></a>\n\n#### list`_`agents\n\n```python\ndef list_agents(running_only: bool = False) -> List[str]\n```\n\nList all agents.\n\n**Arguments**:\n\n- `running_only`: returns only running if set to True\n\n**Returns**:\n\nlist of agents names\n\n<a id=\"aea.manager.manager.MultiAgentManager.remove_agent\"></a>\n\n#### remove`_`agent\n\n```python\ndef remove_agent(\n        agent_name: str,\n        skip_project_auto_remove: bool = False) -> \"MultiAgentManager\"\n```\n\nRemove agent alias definition from registry.\n\n**Arguments**:\n\n- `agent_name`: agent name to remove\n- `skip_project_auto_remove`: disable auto project remove on last agent removed.\n\n**Returns**:\n\nNone\n\n<a id=\"aea.manager.manager.MultiAgentManager.start_agent\"></a>\n\n#### start`_`agent\n\n```python\ndef start_agent(agent_name: str) -> \"MultiAgentManager\"\n```\n\nStart selected agent.\n\n**Arguments**:\n\n- `agent_name`: agent name to start\n\n**Returns**:\n\nNone\n\n<a id=\"aea.manager.manager.MultiAgentManager.start_all_agents\"></a>\n\n#### start`_`all`_`agents\n\n```python\ndef start_all_agents() -> \"MultiAgentManager\"\n```\n\nStart all not started agents.\n\n**Returns**:\n\nNone\n\n<a id=\"aea.manager.manager.MultiAgentManager.stop_agent\"></a>\n\n#### stop`_`agent\n\n```python\ndef stop_agent(agent_name: str) -> \"MultiAgentManager\"\n```\n\nStop running agent.\n\n**Arguments**:\n\n- `agent_name`: agent name to stop\n\n**Returns**:\n\nself\n\n<a id=\"aea.manager.manager.MultiAgentManager.stop_all_agents\"></a>\n\n#### stop`_`all`_`agents\n\n```python\ndef stop_all_agents() -> \"MultiAgentManager\"\n```\n\nStop all agents running.\n\n**Returns**:\n\nself\n\n<a id=\"aea.manager.manager.MultiAgentManager.stop_agents\"></a>\n\n#### stop`_`agents\n\n```python\ndef stop_agents(agent_names: List[str]) -> \"MultiAgentManager\"\n```\n\nStop specified agents.\n\n**Arguments**:\n\n- `agent_names`: names of agents\n\n**Returns**:\n\nself\n\n<a id=\"aea.manager.manager.MultiAgentManager.start_agents\"></a>\n\n#### start`_`agents\n\n```python\ndef start_agents(agent_names: List[str]) -> \"MultiAgentManager\"\n```\n\nStop specified agents.\n\n**Arguments**:\n\n- `agent_names`: names of agents\n\n**Returns**:\n\nself\n\n<a id=\"aea.manager.manager.MultiAgentManager.get_agent_alias\"></a>\n\n#### get`_`agent`_`alias\n\n```python\ndef get_agent_alias(agent_name: str) -> AgentAlias\n```\n\nReturn details about agent alias definition.\n\n**Arguments**:\n\n- `agent_name`: name of agent\n\n**Returns**:\n\nAgentAlias\n\n"
  },
  {
    "path": "docs/api/manager/project.md",
    "content": "<a id=\"aea.manager.project\"></a>\n\n# aea.manager.project\n\nThis module contains the implementation of AEA agents project configuration.\n\n<a id=\"aea.manager.project._Base\"></a>\n\n## `_`Base Objects\n\n```python\nclass _Base()\n```\n\nBase class to share some methods.\n\n<a id=\"aea.manager.project._Base.builder\"></a>\n\n#### builder\n\n```python\n@property\ndef builder() -> AEABuilder\n```\n\nGet AEABuilder instance.\n\n<a id=\"aea.manager.project._Base.install_pypi_dependencies\"></a>\n\n#### install`_`pypi`_`dependencies\n\n```python\ndef install_pypi_dependencies() -> None\n```\n\nInstall python dependencies for the project.\n\n<a id=\"aea.manager.project.Project\"></a>\n\n## Project Objects\n\n```python\nclass Project(_Base)\n```\n\nAgent project representation.\n\n<a id=\"aea.manager.project.Project.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(public_id: PublicId, path: str) -> None\n```\n\nInit project with public_id and project's path.\n\n<a id=\"aea.manager.project.Project.build\"></a>\n\n#### build\n\n```python\ndef build() -> None\n```\n\nCall all build entry points.\n\n<a id=\"aea.manager.project.Project.load\"></a>\n\n#### load\n\n```python\n@classmethod\ndef load(cls,\n         working_dir: str,\n         public_id: PublicId,\n         is_local: bool = False,\n         is_remote: bool = False,\n         is_restore: bool = False,\n         cli_verbosity: str = \"INFO\",\n         registry_path: str = DEFAULT_REGISTRY_NAME,\n         skip_consistency_check: bool = False,\n         skip_aea_validation: bool = False) -> \"Project\"\n```\n\nLoad project with given public_id to working_dir.\n\nIf local = False and remote = False, then the packages\nare fetched in mixed mode (i.e. first try from local\nregistry, and then from remote registry in case of failure).\n\n**Arguments**:\n\n- `working_dir`: the working directory\n- `public_id`: the public id\n- `is_local`: whether to fetch from local\n- `is_remote`: whether to fetch from remote\n- `is_restore`: whether to restore or not\n- `cli_verbosity`: the logging verbosity of the CLI\n- `registry_path`: the path to the registry locally\n- `skip_consistency_check`: consistency checks flag\n- `skip_aea_validation`: aea validation flag\n\n**Returns**:\n\nproject\n\n<a id=\"aea.manager.project.Project.remove\"></a>\n\n#### remove\n\n```python\ndef remove() -> None\n```\n\nRemove project, do cleanup.\n\n<a id=\"aea.manager.project.Project.agent_config\"></a>\n\n#### agent`_`config\n\n```python\n@property\ndef agent_config() -> AgentConfig\n```\n\nGet the agent configuration.\n\n<a id=\"aea.manager.project.Project.builder\"></a>\n\n#### builder\n\n```python\n@property\ndef builder() -> AEABuilder\n```\n\nGet builder instance.\n\n<a id=\"aea.manager.project.Project.check\"></a>\n\n#### check\n\n```python\ndef check() -> None\n```\n\nCheck we can still construct an AEA from the project with builder.build.\n\n<a id=\"aea.manager.project.AgentAlias\"></a>\n\n## AgentAlias Objects\n\n```python\nclass AgentAlias(_Base)\n```\n\nAgent alias representation.\n\n<a id=\"aea.manager.project.AgentAlias.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(project: Project,\n             agent_name: str,\n             data_dir: str,\n             password: Optional[str] = None)\n```\n\nInit agent alias with project, config, name, agent, builder.\n\n<a id=\"aea.manager.project.AgentAlias.set_agent_config_from_data\"></a>\n\n#### set`_`agent`_`config`_`from`_`data\n\n```python\ndef set_agent_config_from_data(json_data: List[Dict]) -> None\n```\n\nSet agent config instance constructed from json data.\n\n**Arguments**:\n\n- `json_data`: agent config json data\n\n<a id=\"aea.manager.project.AgentAlias.builder\"></a>\n\n#### builder\n\n```python\n@property\ndef builder() -> AEABuilder\n```\n\nGet builder instance.\n\n<a id=\"aea.manager.project.AgentAlias.agent_config\"></a>\n\n#### agent`_`config\n\n```python\n@property\ndef agent_config() -> AgentConfig\n```\n\nGet agent config.\n\n<a id=\"aea.manager.project.AgentAlias.remove_from_project\"></a>\n\n#### remove`_`from`_`project\n\n```python\ndef remove_from_project() -> None\n```\n\nRemove agent alias from project.\n\n<a id=\"aea.manager.project.AgentAlias.dict\"></a>\n\n#### dict\n\n```python\n@property\ndef dict() -> Dict[str, Any]\n```\n\nConvert AgentAlias to dict.\n\n<a id=\"aea.manager.project.AgentAlias.config_json\"></a>\n\n#### config`_`json\n\n```python\n@property\ndef config_json() -> List[Dict]\n```\n\nGet agent config json data.\n\n<a id=\"aea.manager.project.AgentAlias.get_aea_instance\"></a>\n\n#### get`_`aea`_`instance\n\n```python\ndef get_aea_instance() -> AEA\n```\n\nBuild new aea instance.\n\n<a id=\"aea.manager.project.AgentAlias.issue_certificates\"></a>\n\n#### issue`_`certificates\n\n```python\ndef issue_certificates() -> None\n```\n\nIssue the certificates for this agent.\n\n<a id=\"aea.manager.project.AgentAlias.set_overrides\"></a>\n\n#### set`_`overrides\n\n```python\ndef set_overrides(agent_overrides: Optional[Dict] = None,\n                  component_overrides: Optional[List[Dict]] = None) -> None\n```\n\nSet override for this agent alias's config.\n\n<a id=\"aea.manager.project.AgentAlias.agent_config_manager\"></a>\n\n#### agent`_`config`_`manager\n\n```python\n@property\ndef agent_config_manager() -> AgentConfigManager\n```\n\nGet agent configuration manager instance for the config.\n\n<a id=\"aea.manager.project.AgentAlias.get_overridables\"></a>\n\n#### get`_`overridables\n\n```python\ndef get_overridables() -> Tuple[Dict, List[Dict]]\n```\n\nGet all overridables for this agent alias's config.\n\n<a id=\"aea.manager.project.AgentAlias.get_addresses\"></a>\n\n#### get`_`addresses\n\n```python\ndef get_addresses() -> Dict[str, str]\n```\n\nGet addresses from private keys.\n\n**Returns**:\n\ndict with crypto id str as key and address str as value\n\n<a id=\"aea.manager.project.AgentAlias.get_connections_addresses\"></a>\n\n#### get`_`connections`_`addresses\n\n```python\ndef get_connections_addresses() -> Dict[str, str]\n```\n\nGet connections addresses from connections private keys.\n\n**Returns**:\n\ndict with crypto id str as key and address str as value\n\n"
  },
  {
    "path": "docs/api/manager/utils.md",
    "content": "<a id=\"aea.manager.utils\"></a>\n\n# aea.manager.utils\n\nMultiagent manager utils.\n\n<a id=\"aea.manager.utils.get_lib_path\"></a>\n\n#### get`_`lib`_`path\n\n```python\ndef get_lib_path(env_dir: str) -> str\n```\n\nGet librarty path for env dir.\n\n<a id=\"aea.manager.utils.make_venv\"></a>\n\n#### make`_`venv\n\n```python\ndef make_venv(env_dir: str, set_env: bool = False) -> None\n```\n\nMake venv and update variable to use it.\n\n**Arguments**:\n\n- `env_dir`: str, path for new env dir\n- `set_env`: bool. use evn within this python process (update, sys.executable and sys.path)\n\n<a id=\"aea.manager.utils.project_install_and_build\"></a>\n\n#### project`_`install`_`and`_`build\n\n```python\ndef project_install_and_build(project: Project) -> None\n```\n\nInstall project dependencies and build required components.\n\n<a id=\"aea.manager.utils.get_venv_dir_for_project\"></a>\n\n#### get`_`venv`_`dir`_`for`_`project\n\n```python\ndef get_venv_dir_for_project(project: Project) -> str\n```\n\nGet virtual env directory for project specified.\n\n<a id=\"aea.manager.utils.project_check\"></a>\n\n#### project`_`check\n\n```python\ndef project_check(project: Project) -> None\n```\n\nPerform project loads well.\n\n<a id=\"aea.manager.utils.run_in_venv\"></a>\n\n#### run`_`in`_`venv\n\n```python\ndef run_in_venv(env_dir: str, fn: Callable, timeout: float, *args: Any) -> Any\n```\n\nRun python function in a dedicated process with virtual env specified.\n\n"
  },
  {
    "path": "docs/api/multiplexer.md",
    "content": "<a id=\"aea.multiplexer\"></a>\n\n# aea.multiplexer\n\nModule for the multiplexer class and related classes.\n\n<a id=\"aea.multiplexer.MultiplexerStatus\"></a>\n\n## MultiplexerStatus Objects\n\n```python\nclass MultiplexerStatus(AsyncState)\n```\n\nThe connection status class.\n\n<a id=\"aea.multiplexer.MultiplexerStatus.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__() -> None\n```\n\nInitialize the connection status.\n\n<a id=\"aea.multiplexer.MultiplexerStatus.is_connected\"></a>\n\n#### is`_`connected\n\n```python\n@property\ndef is_connected() -> bool\n```\n\nReturn is connected.\n\n<a id=\"aea.multiplexer.MultiplexerStatus.is_connecting\"></a>\n\n#### is`_`connecting\n\n```python\n@property\ndef is_connecting() -> bool\n```\n\nReturn is connecting.\n\n<a id=\"aea.multiplexer.MultiplexerStatus.is_disconnected\"></a>\n\n#### is`_`disconnected\n\n```python\n@property\ndef is_disconnected() -> bool\n```\n\nReturn is disconnected.\n\n<a id=\"aea.multiplexer.MultiplexerStatus.is_disconnecting\"></a>\n\n#### is`_`disconnecting\n\n```python\n@property\ndef is_disconnecting() -> bool\n```\n\nReturn is disconnected.\n\n<a id=\"aea.multiplexer.AsyncMultiplexer\"></a>\n\n## AsyncMultiplexer Objects\n\n```python\nclass AsyncMultiplexer(Runnable, WithLogger)\n```\n\nThis class can handle multiple connections at once.\n\n<a id=\"aea.multiplexer.AsyncMultiplexer.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(\n        connections: Optional[Sequence[Connection]] = None,\n        default_connection_index: int = 0,\n        loop: Optional[AbstractEventLoop] = None,\n        exception_policy: ExceptionPolicyEnum = ExceptionPolicyEnum.propagate,\n        threaded: bool = False,\n        agent_name: str = \"standalone\",\n        default_routing: Optional[Dict[PublicId, PublicId]] = None,\n        default_connection: Optional[PublicId] = None,\n        protocols: Optional[List[Union[Protocol, Message]]] = None) -> None\n```\n\nInitialize the connection multiplexer.\n\n**Arguments**:\n\n- `connections`: a sequence of connections.\n- `default_connection_index`: the index of the connection to use as default.\nThis information is used for envelopes which don't specify any routing context.\nIf connections is None, this parameter is ignored.\n- `loop`: the event loop to run the multiplexer. If None, a new event loop is created.\n- `exception_policy`: the exception policy used for connections.\n- `threaded`: if True, run in threaded mode, else async\n- `agent_name`: the name of the agent that owns the multiplexer, for logging purposes.\n- `default_routing`: default routing map\n- `default_connection`: default connection\n- `protocols`: protocols used\n\n<a id=\"aea.multiplexer.AsyncMultiplexer.default_connection\"></a>\n\n#### default`_`connection\n\n```python\n@property\ndef default_connection() -> Optional[Connection]\n```\n\nGet the default connection.\n\n<a id=\"aea.multiplexer.AsyncMultiplexer.in_queue\"></a>\n\n#### in`_`queue\n\n```python\n@property\ndef in_queue() -> AsyncFriendlyQueue\n```\n\nGet the in queue.\n\n<a id=\"aea.multiplexer.AsyncMultiplexer.out_queue\"></a>\n\n#### out`_`queue\n\n```python\n@property\ndef out_queue() -> asyncio.Queue\n```\n\nGet the out queue.\n\n<a id=\"aea.multiplexer.AsyncMultiplexer.connections\"></a>\n\n#### connections\n\n```python\n@property\ndef connections() -> Tuple[Connection, ...]\n```\n\nGet the connections.\n\n<a id=\"aea.multiplexer.AsyncMultiplexer.is_connected\"></a>\n\n#### is`_`connected\n\n```python\n@property\ndef is_connected() -> bool\n```\n\nCheck whether the multiplexer is processing envelopes.\n\n<a id=\"aea.multiplexer.AsyncMultiplexer.default_routing\"></a>\n\n#### default`_`routing\n\n```python\n@property\ndef default_routing() -> Dict[PublicId, PublicId]\n```\n\nGet the default routing.\n\n<a id=\"aea.multiplexer.AsyncMultiplexer.default_routing\"></a>\n\n#### default`_`routing\n\n```python\n@default_routing.setter\ndef default_routing(default_routing: Dict[PublicId, PublicId]) -> None\n```\n\nSet the default routing.\n\n<a id=\"aea.multiplexer.AsyncMultiplexer.connection_status\"></a>\n\n#### connection`_`status\n\n```python\n@property\ndef connection_status() -> MultiplexerStatus\n```\n\nGet the connection status.\n\n<a id=\"aea.multiplexer.AsyncMultiplexer.run\"></a>\n\n#### run\n\n```python\nasync def run() -> None\n```\n\nRun multiplexer connect and receive/send tasks.\n\n<a id=\"aea.multiplexer.AsyncMultiplexer.set_loop\"></a>\n\n#### set`_`loop\n\n```python\ndef set_loop(loop: AbstractEventLoop) -> None\n```\n\nSet event loop and all event loop related objects.\n\n**Arguments**:\n\n- `loop`: asyncio event loop.\n\n<a id=\"aea.multiplexer.AsyncMultiplexer.add_connection\"></a>\n\n#### add`_`connection\n\n```python\ndef add_connection(connection: Connection, is_default: bool = False) -> None\n```\n\nAdd a connection to the multiplexer.\n\n**Arguments**:\n\n- `connection`: the connection to add.\n- `is_default`: whether the connection added should be the default one.\n\n<a id=\"aea.multiplexer.AsyncMultiplexer.connect\"></a>\n\n#### connect\n\n```python\nasync def connect() -> None\n```\n\nConnect the multiplexer.\n\n<a id=\"aea.multiplexer.AsyncMultiplexer.disconnect\"></a>\n\n#### disconnect\n\n```python\nasync def disconnect() -> None\n```\n\nDisconnect the multiplexer.\n\n<a id=\"aea.multiplexer.AsyncMultiplexer.get\"></a>\n\n#### get\n\n```python\ndef get(block: bool = False,\n        timeout: Optional[float] = None) -> Optional[Envelope]\n```\n\nGet an envelope within a timeout.\n\n**Arguments**:\n\n- `block`: make the call blocking (ignore the timeout).\n- `timeout`: the timeout to wait until an envelope is received.\n\n**Returns**:\n\nthe envelope, or None if no envelope is available within a timeout.\n\n<a id=\"aea.multiplexer.AsyncMultiplexer.async_get\"></a>\n\n#### async`_`get\n\n```python\nasync def async_get() -> Envelope\n```\n\nGet an envelope async way.\n\n**Returns**:\n\nthe envelope\n\n<a id=\"aea.multiplexer.AsyncMultiplexer.async_wait\"></a>\n\n#### async`_`wait\n\n```python\nasync def async_wait() -> None\n```\n\nGet an envelope async way.\n\n**Returns**:\n\nthe envelope\n\n<a id=\"aea.multiplexer.AsyncMultiplexer.put\"></a>\n\n#### put\n\n```python\ndef put(envelope: Envelope) -> None\n```\n\nSchedule an envelope for sending it.\n\nNotice that the output queue is an asyncio.Queue which uses an event loop\nrunning on a different thread than the one used in this function.\n\n**Arguments**:\n\n- `envelope`: the envelope to be sent.\n\n<a id=\"aea.multiplexer.Multiplexer\"></a>\n\n## Multiplexer Objects\n\n```python\nclass Multiplexer(AsyncMultiplexer)\n```\n\nTransit sync multiplexer for compatibility.\n\n<a id=\"aea.multiplexer.Multiplexer.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(*args: Any, **kwargs: Any) -> None\n```\n\nInitialize the connection multiplexer.\n\n**Arguments**:\n\n- `args`: arguments\n- `kwargs`: keyword arguments\n\n<a id=\"aea.multiplexer.Multiplexer.set_loop\"></a>\n\n#### set`_`loop\n\n```python\ndef set_loop(loop: AbstractEventLoop) -> None\n```\n\nSet event loop and all event loop related objects.\n\n**Arguments**:\n\n- `loop`: asyncio event loop.\n\n<a id=\"aea.multiplexer.Multiplexer.connect\"></a>\n\n#### connect\n\n```python\ndef connect() -> None\n```\n\nConnect the multiplexer.\n\nSynchronously in thread spawned if new loop created.\n\n<a id=\"aea.multiplexer.Multiplexer.disconnect\"></a>\n\n#### disconnect\n\n```python\ndef disconnect() -> None\n```\n\nDisconnect the multiplexer.\n\nAlso stops a dedicated thread for event loop if spawned on connect.\n\n<a id=\"aea.multiplexer.Multiplexer.put\"></a>\n\n#### put\n\n```python\ndef put(envelope: Envelope) -> None\n```\n\nSchedule an envelope for sending it.\n\nNotice that the output queue is an asyncio.Queue which uses an event loop\nrunning on a different thread than the one used in this function.\n\n**Arguments**:\n\n- `envelope`: the envelope to be sent.\n\n<a id=\"aea.multiplexer.InBox\"></a>\n\n## InBox Objects\n\n```python\nclass InBox()\n```\n\nA queue from where you can only consume envelopes.\n\n<a id=\"aea.multiplexer.InBox.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(multiplexer: AsyncMultiplexer) -> None\n```\n\nInitialize the inbox.\n\n**Arguments**:\n\n- `multiplexer`: the multiplexer\n\n<a id=\"aea.multiplexer.InBox.empty\"></a>\n\n#### empty\n\n```python\ndef empty() -> bool\n```\n\nCheck for a envelope on the in queue.\n\n**Returns**:\n\nboolean indicating whether there is an envelope or not\n\n<a id=\"aea.multiplexer.InBox.get\"></a>\n\n#### get\n\n```python\ndef get(block: bool = False, timeout: Optional[float] = None) -> Envelope\n```\n\nCheck for a envelope on the in queue.\n\n**Arguments**:\n\n- `block`: make the call blocking (ignore the timeout).\n- `timeout`: times out the block after timeout seconds.\n\n**Raises**:\n\n- `Empty`: if the attempt to get an envelope fails.\n\n**Returns**:\n\nthe envelope object.\n\n<a id=\"aea.multiplexer.InBox.get_nowait\"></a>\n\n#### get`_`nowait\n\n```python\ndef get_nowait() -> Optional[Envelope]\n```\n\nCheck for a envelope on the in queue and wait for no time.\n\n**Returns**:\n\nthe envelope object\n\n<a id=\"aea.multiplexer.InBox.async_get\"></a>\n\n#### async`_`get\n\n```python\nasync def async_get() -> Envelope\n```\n\nCheck for a envelope on the in queue.\n\n**Returns**:\n\nthe envelope object.\n\n<a id=\"aea.multiplexer.InBox.async_wait\"></a>\n\n#### async`_`wait\n\n```python\nasync def async_wait() -> None\n```\n\nCheck for a envelope on the in queue.\n\n<a id=\"aea.multiplexer.OutBox\"></a>\n\n## OutBox Objects\n\n```python\nclass OutBox()\n```\n\nA queue from where you can only enqueue envelopes.\n\n<a id=\"aea.multiplexer.OutBox.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(multiplexer: AsyncMultiplexer) -> None\n```\n\nInitialize the outbox.\n\n**Arguments**:\n\n- `multiplexer`: the multiplexer\n\n<a id=\"aea.multiplexer.OutBox.empty\"></a>\n\n#### empty\n\n```python\ndef empty() -> bool\n```\n\nCheck for a envelope on the in queue.\n\n**Returns**:\n\nboolean indicating whether there is an envelope or not\n\n<a id=\"aea.multiplexer.OutBox.put\"></a>\n\n#### put\n\n```python\ndef put(envelope: Envelope) -> None\n```\n\nPut an envelope into the queue.\n\n**Arguments**:\n\n- `envelope`: the envelope.\n\n<a id=\"aea.multiplexer.OutBox.put_message\"></a>\n\n#### put`_`message\n\n```python\ndef put_message(message: Message,\n                context: Optional[EnvelopeContext] = None) -> None\n```\n\nPut a message in the outbox.\n\nThis constructs an envelope with the input arguments.\n\n**Arguments**:\n\n- `message`: the message\n- `context`: the envelope context\n\n"
  },
  {
    "path": "docs/api/plugins/aea_cli_ipfs/core.md",
    "content": "<a id=\"plugins.aea-cli-ipfs.aea_cli_ipfs.core\"></a>\n\n# plugins.aea-cli-ipfs.aea`_`cli`_`ipfs.core\n\nCore components for `ipfs cli command`.\n\n<a id=\"plugins.aea-cli-ipfs.aea_cli_ipfs.core.ipfs\"></a>\n\n#### ipfs\n\n```python\n@click.group()\n@click.pass_context\ndef ipfs(click_context: click.Context) -> None\n```\n\nIPFS Commands\n\n<a id=\"plugins.aea-cli-ipfs.aea_cli_ipfs.core.process_result\"></a>\n\n#### process`_`result\n\n```python\n@ipfs.result_callback()\n@click.pass_context\ndef process_result(click_context: click.Context, *_: Any) -> None\n```\n\nTear down command group.\n\n<a id=\"plugins.aea-cli-ipfs.aea_cli_ipfs.core.add\"></a>\n\n#### add\n\n```python\n@ipfs.command()\n@click.argument(\n    \"dir_path\",\n    type=click.Path(exists=True,\n                    dir_okay=True,\n                    file_okay=False,\n                    resolve_path=True,\n                    readable=True),\n    required=False,\n)\n@click.option(\"-p\", \"--publish\", is_flag=True)\n@click.option(\"--no-pin\", is_flag=True)\n@click.pass_context\ndef add(click_context: click.Context,\n        dir_path: Optional[str],\n        publish: bool = False,\n        no_pin: bool = False) -> None\n```\n\nAdd directory to ipfs, if not directory specified the current one will be added.\n\n<a id=\"plugins.aea-cli-ipfs.aea_cli_ipfs.core.remove\"></a>\n\n#### remove\n\n```python\n@ipfs.command()\n@click.argument(\n    \"hash_\",\n    metavar=\"hash\",\n    type=str,\n    required=True,\n)\n@click.pass_context\ndef remove(click_context: click.Context, hash_: str) -> None\n```\n\nRemove a directory from ipfs by it's hash.\n\n<a id=\"plugins.aea-cli-ipfs.aea_cli_ipfs.core.download\"></a>\n\n#### download\n\n```python\n@ipfs.command()\n@click.argument(\n    \"hash_\",\n    metavar=\"hash\",\n    type=str,\n    required=True,\n)\n@click.argument(\n    \"target_dir\",\n    type=click.Path(dir_okay=True, file_okay=False, resolve_path=True),\n    required=False,\n)\n@click.pass_context\ndef download(click_context: click.Context, hash_: str,\n             target_dir: Optional[str]) -> None\n```\n\nDownload directory by it's hash, if not target directory specified will use current one.\n\n"
  },
  {
    "path": "docs/api/plugins/aea_cli_ipfs/ipfs_utils.md",
    "content": "<a id=\"plugins.aea-cli-ipfs.aea_cli_ipfs.ipfs_utils\"></a>\n\n# plugins.aea-cli-ipfs.aea`_`cli`_`ipfs.ipfs`_`utils\n\nIpfs utils for `ipfs cli command`.\n\n<a id=\"plugins.aea-cli-ipfs.aea_cli_ipfs.ipfs_utils.IPFSDaemon\"></a>\n\n## IPFSDaemon Objects\n\n```python\nclass IPFSDaemon()\n```\n\nSet up the IPFS daemon.\n\n**Raises**:\n\n- `Exception`: if IPFS is not installed.\n\n<a id=\"plugins.aea-cli-ipfs.aea_cli_ipfs.ipfs_utils.IPFSDaemon.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__() -> None\n```\n\nInitialise IPFS daemon.\n\n<a id=\"plugins.aea-cli-ipfs.aea_cli_ipfs.ipfs_utils.IPFSDaemon.is_started\"></a>\n\n#### is`_`started\n\n```python\ndef is_started() -> bool\n```\n\nCheck daemon was started.\n\n<a id=\"plugins.aea-cli-ipfs.aea_cli_ipfs.ipfs_utils.IPFSDaemon.start\"></a>\n\n#### start\n\n```python\ndef start() -> None\n```\n\nRun the ipfs daemon.\n\n<a id=\"plugins.aea-cli-ipfs.aea_cli_ipfs.ipfs_utils.IPFSDaemon.stop\"></a>\n\n#### stop\n\n```python\ndef stop() -> None\n```\n\nTerminate the ipfs daemon.\n\n<a id=\"plugins.aea-cli-ipfs.aea_cli_ipfs.ipfs_utils.BaseIPFSToolException\"></a>\n\n## BaseIPFSToolException Objects\n\n```python\nclass BaseIPFSToolException(Exception)\n```\n\nBase ipfs tool exception.\n\n<a id=\"plugins.aea-cli-ipfs.aea_cli_ipfs.ipfs_utils.RemoveError\"></a>\n\n## RemoveError Objects\n\n```python\nclass RemoveError(BaseIPFSToolException)\n```\n\nException on remove.\n\n<a id=\"plugins.aea-cli-ipfs.aea_cli_ipfs.ipfs_utils.PublishError\"></a>\n\n## PublishError Objects\n\n```python\nclass PublishError(BaseIPFSToolException)\n```\n\nException on publish.\n\n<a id=\"plugins.aea-cli-ipfs.aea_cli_ipfs.ipfs_utils.NodeError\"></a>\n\n## NodeError Objects\n\n```python\nclass NodeError(BaseIPFSToolException)\n```\n\nException for node connection check.\n\n<a id=\"plugins.aea-cli-ipfs.aea_cli_ipfs.ipfs_utils.DownloadError\"></a>\n\n## DownloadError Objects\n\n```python\nclass DownloadError(BaseIPFSToolException)\n```\n\nException on download failed.\n\n<a id=\"plugins.aea-cli-ipfs.aea_cli_ipfs.ipfs_utils.IPFSTool\"></a>\n\n## IPFSTool Objects\n\n```python\nclass IPFSTool()\n```\n\nIPFS tool to add, publish, remove, download directories.\n\n<a id=\"plugins.aea-cli-ipfs.aea_cli_ipfs.ipfs_utils.IPFSTool.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(client_options: Optional[Dict] = None)\n```\n\nInit tool.\n\n**Arguments**:\n\n- `client_options`: dict, options for ipfshttpclient instance.\n\n<a id=\"plugins.aea-cli-ipfs.aea_cli_ipfs.ipfs_utils.IPFSTool.add\"></a>\n\n#### add\n\n```python\ndef add(dir_path: str, pin: bool = True) -> Tuple[str, str, List]\n```\n\nAdd directory to ipfs.\n\nIt wraps into directory.\n\n**Arguments**:\n\n- `dir_path`: str, path to dir to publish\n- `pin`: bool, pin object or not\n\n**Returns**:\n\ndir name published, hash, list of items processed\n\n<a id=\"plugins.aea-cli-ipfs.aea_cli_ipfs.ipfs_utils.IPFSTool.remove\"></a>\n\n#### remove\n\n```python\ndef remove(hash_id: str) -> Dict\n```\n\nRemove dir added by it's hash.\n\n**Arguments**:\n\n- `hash_id`: str. hash of dir to remove\n\n**Returns**:\n\ndict with unlinked items.\n\n<a id=\"plugins.aea-cli-ipfs.aea_cli_ipfs.ipfs_utils.IPFSTool.download\"></a>\n\n#### download\n\n```python\ndef download(hash_id: str, target_dir: str, fix_path: bool = True) -> None\n```\n\nDownload dir by it's hash.\n\n**Arguments**:\n\n- `hash_id`: str. hash of file to download\n- `target_dir`: str. directory to place downloaded\n- `fix_path`: bool. default True. on download don't wrap result in to hash_id directory.\n\n<a id=\"plugins.aea-cli-ipfs.aea_cli_ipfs.ipfs_utils.IPFSTool.publish\"></a>\n\n#### publish\n\n```python\ndef publish(hash_id: str) -> Dict\n```\n\nPublish directory by it's hash id.\n\n**Arguments**:\n\n- `hash_id`: hash of the directory to publish.\n\n**Returns**:\n\ndict of names it was publish for.\n\n<a id=\"plugins.aea-cli-ipfs.aea_cli_ipfs.ipfs_utils.IPFSTool.chec_ipfs_node_running\"></a>\n\n#### chec`_`ipfs`_`node`_`running\n\n```python\ndef chec_ipfs_node_running() -> None\n```\n\nCheck ipfs node running.\n\n"
  },
  {
    "path": "docs/api/plugins/aea_ledger_cosmos/cosmos.md",
    "content": "<a id=\"plugins.aea-ledger-cosmos.aea_ledger_cosmos.cosmos\"></a>\n\n# plugins.aea-ledger-cosmos.aea`_`ledger`_`cosmos.cosmos\n\nCosmos module wrapping the public and private key cryptography and ledger api.\n\n<a id=\"plugins.aea-ledger-cosmos.aea_ledger_cosmos.cosmos.DataEncrypt\"></a>\n\n## DataEncrypt Objects\n\n```python\nclass DataEncrypt()\n```\n\nClass to encrypt/decrypt data strings with password provided.\n\n<a id=\"plugins.aea-ledger-cosmos.aea_ledger_cosmos.cosmos.DataEncrypt.encrypt\"></a>\n\n#### encrypt\n\n```python\n@classmethod\ndef encrypt(cls, data: bytes, password: str) -> bytes\n```\n\nEncrypt data with password.\n\n<a id=\"plugins.aea-ledger-cosmos.aea_ledger_cosmos.cosmos.DataEncrypt.bytes_encode\"></a>\n\n#### bytes`_`encode\n\n```python\n@staticmethod\ndef bytes_encode(data: bytes) -> str\n```\n\nEncode bytes to ascii friendly string.\n\n<a id=\"plugins.aea-ledger-cosmos.aea_ledger_cosmos.cosmos.DataEncrypt.bytes_decode\"></a>\n\n#### bytes`_`decode\n\n```python\n@staticmethod\ndef bytes_decode(data: str) -> bytes\n```\n\nDecode ascii friendly string to bytes.\n\n<a id=\"plugins.aea-ledger-cosmos.aea_ledger_cosmos.cosmos.DataEncrypt.decrypt\"></a>\n\n#### decrypt\n\n```python\n@classmethod\ndef decrypt(cls, encrypted_data: bytes, password: str) -> bytes\n```\n\nDecrypt data with password provided.\n\n<a id=\"plugins.aea-ledger-cosmos.aea_ledger_cosmos.cosmos.CosmosHelper\"></a>\n\n## CosmosHelper Objects\n\n```python\nclass CosmosHelper(Helper)\n```\n\nHelper class usable as Mixin for CosmosApi or as standalone class.\n\n<a id=\"plugins.aea-ledger-cosmos.aea_ledger_cosmos.cosmos.CosmosHelper.is_transaction_settled\"></a>\n\n#### is`_`transaction`_`settled\n\n```python\n@staticmethod\ndef is_transaction_settled(tx_receipt: JSONLike) -> bool\n```\n\nCheck whether a transaction is settled or not.\n\n**Arguments**:\n\n- `tx_receipt`: the receipt of the transaction.\n\n**Returns**:\n\nTrue if the transaction has been settled, False o/w.\n\n<a id=\"plugins.aea-ledger-cosmos.aea_ledger_cosmos.cosmos.CosmosHelper.get_code_id\"></a>\n\n#### get`_`code`_`id\n\n```python\n@classmethod\ndef get_code_id(cls, tx_receipt: JSONLike) -> Optional[int]\n```\n\nRetrieve the `code_id` from a transaction receipt.\n\n**Arguments**:\n\n- `tx_receipt`: the receipt of the transaction.\n\n**Returns**:\n\nthe code id, if present\n\n<a id=\"plugins.aea-ledger-cosmos.aea_ledger_cosmos.cosmos.CosmosHelper.get_event_attributes\"></a>\n\n#### get`_`event`_`attributes\n\n```python\n@staticmethod\ndef get_event_attributes(tx_receipt: JSONLike) -> Dict\n```\n\nRetrieve events attributes from tx receipt.\n\n**Arguments**:\n\n- `tx_receipt`: the receipt of the transaction.\n\n**Returns**:\n\ndict\n\n<a id=\"plugins.aea-ledger-cosmos.aea_ledger_cosmos.cosmos.CosmosHelper.get_contract_address\"></a>\n\n#### get`_`contract`_`address\n\n```python\n@classmethod\ndef get_contract_address(cls, tx_receipt: JSONLike) -> Optional[str]\n```\n\nRetrieve the `contract_address` from a transaction receipt.\n\n**Arguments**:\n\n- `tx_receipt`: the receipt of the transaction.\n\n**Returns**:\n\nthe contract address, if present\n\n<a id=\"plugins.aea-ledger-cosmos.aea_ledger_cosmos.cosmos.CosmosHelper.is_transaction_valid\"></a>\n\n#### is`_`transaction`_`valid\n\n```python\n@staticmethod\ndef is_transaction_valid(tx: JSONLike, seller: Address, client: Address,\n                         tx_nonce: str, amount: int) -> bool\n```\n\nCheck whether a transaction is valid or not.\n\n**Arguments**:\n\n- `tx`: the transaction.\n- `seller`: the address of the seller.\n- `client`: the address of the client.\n- `tx_nonce`: the transaction nonce.\n- `amount`: the amount we expect to get from the transaction.\n\n**Returns**:\n\nTrue if the random_message is equals to tx['input']\n\n<a id=\"plugins.aea-ledger-cosmos.aea_ledger_cosmos.cosmos.CosmosHelper.generate_tx_nonce\"></a>\n\n#### generate`_`tx`_`nonce\n\n```python\n@staticmethod\ndef generate_tx_nonce(seller: Address, client: Address) -> str\n```\n\nGenerate a unique hash to distinguish transactions with the same terms.\n\n**Arguments**:\n\n- `seller`: the address of the seller.\n- `client`: the address of the client.\n\n**Returns**:\n\nreturn the hash in hex.\n\n<a id=\"plugins.aea-ledger-cosmos.aea_ledger_cosmos.cosmos.CosmosHelper.get_address_from_public_key\"></a>\n\n#### get`_`address`_`from`_`public`_`key\n\n```python\n@classmethod\ndef get_address_from_public_key(cls, public_key: str) -> str\n```\n\nGet the address from the public key.\n\n**Arguments**:\n\n- `public_key`: the public key\n\n**Returns**:\n\nstr\n\n<a id=\"plugins.aea-ledger-cosmos.aea_ledger_cosmos.cosmos.CosmosHelper.recover_message\"></a>\n\n#### recover`_`message\n\n```python\n@classmethod\ndef recover_message(cls,\n                    message: bytes,\n                    signature: str,\n                    is_deprecated_mode: bool = False) -> Tuple[Address, ...]\n```\n\nRecover the addresses from the hash.\n\n**Arguments**:\n\n- `message`: the message we expect\n- `signature`: the transaction signature\n- `is_deprecated_mode`: if the deprecated signing was used\n\n**Returns**:\n\nthe recovered addresses\n\n<a id=\"plugins.aea-ledger-cosmos.aea_ledger_cosmos.cosmos.CosmosHelper.recover_public_keys_from_message\"></a>\n\n#### recover`_`public`_`keys`_`from`_`message\n\n```python\n@classmethod\ndef recover_public_keys_from_message(\n        cls,\n        message: bytes,\n        signature: str,\n        is_deprecated_mode: bool = False) -> Tuple[str, ...]\n```\n\nGet the public key used to produce the `signature` of the `message`\n\n**Arguments**:\n\n- `message`: raw bytes used to produce signature\n- `signature`: signature of the message\n- `is_deprecated_mode`: if the deprecated signing was used\n\n**Returns**:\n\nthe recovered public keys\n\n<a id=\"plugins.aea-ledger-cosmos.aea_ledger_cosmos.cosmos.CosmosHelper.get_hash\"></a>\n\n#### get`_`hash\n\n```python\n@staticmethod\ndef get_hash(message: bytes) -> str\n```\n\nGet the hash of a message.\n\n**Arguments**:\n\n- `message`: the message to be hashed.\n\n**Returns**:\n\nthe hash of the message.\n\n<a id=\"plugins.aea-ledger-cosmos.aea_ledger_cosmos.cosmos.CosmosHelper.is_valid_address\"></a>\n\n#### is`_`valid`_`address\n\n```python\n@classmethod\ndef is_valid_address(cls, address: Address) -> bool\n```\n\nCheck if the address is valid.\n\n**Arguments**:\n\n- `address`: the address to validate\n\n**Returns**:\n\nwhether address is valid or not\n\n<a id=\"plugins.aea-ledger-cosmos.aea_ledger_cosmos.cosmos.CosmosHelper.load_contract_interface\"></a>\n\n#### load`_`contract`_`interface\n\n```python\n@classmethod\ndef load_contract_interface(cls, file_path: Path) -> Dict[str, str]\n```\n\nLoad contract interface.\n\n**Arguments**:\n\n- `file_path`: the file path to the interface\n\n**Returns**:\n\nthe interface\n\n<a id=\"plugins.aea-ledger-cosmos.aea_ledger_cosmos.cosmos.CosmosCrypto\"></a>\n\n## CosmosCrypto Objects\n\n```python\nclass CosmosCrypto(Crypto[SigningKey])\n```\n\nClass wrapping the Account Generation from Ethereum ledger.\n\n<a id=\"plugins.aea-ledger-cosmos.aea_ledger_cosmos.cosmos.CosmosCrypto.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(private_key_path: Optional[str] = None,\n             password: Optional[str] = None) -> None\n```\n\nInstantiate an ethereum crypto object.\n\n**Arguments**:\n\n- `private_key_path`: the private key path of the agent\n- `password`: the password to encrypt/decrypt the private key.\n\n<a id=\"plugins.aea-ledger-cosmos.aea_ledger_cosmos.cosmos.CosmosCrypto.private_key\"></a>\n\n#### private`_`key\n\n```python\n@property\ndef private_key() -> str\n```\n\nReturn a private key.\n\n**Returns**:\n\na private key string\n\n<a id=\"plugins.aea-ledger-cosmos.aea_ledger_cosmos.cosmos.CosmosCrypto.public_key\"></a>\n\n#### public`_`key\n\n```python\n@property\ndef public_key() -> str\n```\n\nReturn a public key in hex format.\n\n**Returns**:\n\na public key string in hex format\n\n<a id=\"plugins.aea-ledger-cosmos.aea_ledger_cosmos.cosmos.CosmosCrypto.address\"></a>\n\n#### address\n\n```python\n@property\ndef address() -> str\n```\n\nReturn the address for the key pair.\n\n**Returns**:\n\na display_address str\n\n<a id=\"plugins.aea-ledger-cosmos.aea_ledger_cosmos.cosmos.CosmosCrypto.load_private_key_from_path\"></a>\n\n#### load`_`private`_`key`_`from`_`path\n\n```python\n@classmethod\ndef load_private_key_from_path(cls,\n                               file_name: str,\n                               password: Optional[str] = None) -> SigningKey\n```\n\nLoad a private key in hex format from a file.\n\n**Arguments**:\n\n- `file_name`: the path to the hex file.\n- `password`: the password to encrypt/decrypt the private key.\n\n**Returns**:\n\nthe Entity.\n\n<a id=\"plugins.aea-ledger-cosmos.aea_ledger_cosmos.cosmos.CosmosCrypto.sign_message\"></a>\n\n#### sign`_`message\n\n```python\ndef sign_message(message: bytes, is_deprecated_mode: bool = False) -> str\n```\n\nSign a message in bytes string form.\n\n**Arguments**:\n\n- `message`: the message to be signed\n- `is_deprecated_mode`: if the deprecated signing is used\n\n**Returns**:\n\nsignature of the message in string form\n\n<a id=\"plugins.aea-ledger-cosmos.aea_ledger_cosmos.cosmos.CosmosCrypto.sign_transaction\"></a>\n\n#### sign`_`transaction\n\n```python\ndef sign_transaction(transaction: JSONLike) -> JSONLike\n```\n\nSign a transaction in bytes string form.\n\n**Arguments**:\n\n- `transaction`: the transaction to be signed\n\n**Returns**:\n\nsigned transaction\n\n<a id=\"plugins.aea-ledger-cosmos.aea_ledger_cosmos.cosmos.CosmosCrypto.generate_private_key\"></a>\n\n#### generate`_`private`_`key\n\n```python\n@classmethod\ndef generate_private_key(cls) -> SigningKey\n```\n\nGenerate a key pair for cosmos network.\n\n<a id=\"plugins.aea-ledger-cosmos.aea_ledger_cosmos.cosmos.CosmosCrypto.encrypt\"></a>\n\n#### encrypt\n\n```python\ndef encrypt(password: str) -> str\n```\n\nEncrypt the private key and return in json.\n\n**Arguments**:\n\n- `password`: the password to decrypt.\n\n**Returns**:\n\njson string containing encrypted private key.\n\n<a id=\"plugins.aea-ledger-cosmos.aea_ledger_cosmos.cosmos.CosmosCrypto.decrypt\"></a>\n\n#### decrypt\n\n```python\n@classmethod\ndef decrypt(cls, keyfile_json: str, password: str) -> str\n```\n\nDecrypt the private key and return in raw form.\n\n**Arguments**:\n\n- `keyfile_json`: json string containing encrypted private key.\n- `password`: the password to decrypt.\n\n**Returns**:\n\nthe raw private key.\n\n<a id=\"plugins.aea-ledger-cosmos.aea_ledger_cosmos.cosmos._CosmosApi\"></a>\n\n## `_`CosmosApi Objects\n\n```python\nclass _CosmosApi(LedgerApi)\n```\n\nClass to interact with the Cosmos SDK via a HTTP APIs.\n\n<a id=\"plugins.aea-ledger-cosmos.aea_ledger_cosmos.cosmos._CosmosApi.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(**kwargs: Any) -> None\n```\n\nInitialize the Cosmos ledger APIs.\n\n<a id=\"plugins.aea-ledger-cosmos.aea_ledger_cosmos.cosmos._CosmosApi.api\"></a>\n\n#### api\n\n```python\n@property\ndef api() -> Any\n```\n\nGet the underlying API object.\n\n<a id=\"plugins.aea-ledger-cosmos.aea_ledger_cosmos.cosmos._CosmosApi.get_balance\"></a>\n\n#### get`_`balance\n\n```python\ndef get_balance(address: Address) -> Optional[int]\n```\n\nGet the balance of a given account.\n\n<a id=\"plugins.aea-ledger-cosmos.aea_ledger_cosmos.cosmos._CosmosApi.get_state\"></a>\n\n#### get`_`state\n\n```python\ndef get_state(callable_name: str, *args: Any,\n              **kwargs: Any) -> Optional[JSONLike]\n```\n\nCall a specified function on the ledger API.\n\nBased on the cosmos REST\nAPI specification, which takes a path (strings separated by '/'). The\nconvention here is to define the root of the path (txs, blocks, etc.)\nas the callable_name and the rest of the path as args.\n\n**Arguments**:\n\n- `callable_name`: name of the callable\n- `args`: positional arguments\n- `kwargs`: keyword arguments\n\n**Returns**:\n\nthe transaction dictionary\n\n<a id=\"plugins.aea-ledger-cosmos.aea_ledger_cosmos.cosmos._CosmosApi.get_deploy_transaction\"></a>\n\n#### get`_`deploy`_`transaction\n\n```python\ndef get_deploy_transaction(contract_interface: Dict[str, str],\n                           deployer_address: Address,\n                           **kwargs: Any) -> Optional[JSONLike]\n```\n\nGet the transaction to deploy the smart contract.\n\nDispatches to _get_storage_transaction and _get_init_transaction based on kwargs.\n\n**Arguments**:\n\n- `contract_interface`: the contract interface.\n- `deployer_address`: The address that will deploy the contract.\n- `kwargs`: keyword arguments.\n\n**Returns**:\n\nthe transaction dictionary.\n\n<a id=\"plugins.aea-ledger-cosmos.aea_ledger_cosmos.cosmos._CosmosApi.get_handle_transaction\"></a>\n\n#### get`_`handle`_`transaction\n\n```python\ndef get_handle_transaction(\n        sender_address: Address,\n        contract_address: Address,\n        handle_msg: Any,\n        amount: int,\n        tx_fee: int,\n        denom: Optional[str] = None,\n        gas: int = DEFAULT_GAS_AMOUNT,\n        memo: str = \"\",\n        chain_id: Optional[str] = None,\n        account_number: Optional[int] = None,\n        sequence: Optional[int] = None,\n        tx_fee_denom: Optional[str] = None) -> Optional[JSONLike]\n```\n\nCreate a CosmWasm HandleMsg transaction.\n\n**Arguments**:\n\n- `sender_address`: the sender address of the message initiator.\n- `contract_address`: the address of the smart contract.\n- `handle_msg`: HandleMsg in JSON format.\n- `amount`: Funds amount sent with transaction.\n- `tx_fee`: the tx fee accepted.\n- `denom`: the name of the denomination of the contract funds\n- `gas`: Maximum amount of gas to be used on executing command.\n- `memo`: any string comment.\n- `chain_id`: the Chain ID of the CosmWasm transaction. Default is 1 (i.e. mainnet).\n- `account_number`: Account number\n- `sequence`: Sequence\n- `tx_fee_denom`: Denomination of tx_fee, identical with denom param when None\n\n**Returns**:\n\nthe unsigned CosmWasm HandleMsg\n\n<a id=\"plugins.aea-ledger-cosmos.aea_ledger_cosmos.cosmos._CosmosApi.execute_contract_query\"></a>\n\n#### execute`_`contract`_`query\n\n```python\ndef execute_contract_query(contract_address: Address,\n                           query_msg: JSONLike) -> Optional[JSONLike]\n```\n\nExecute a CosmWasm QueryMsg. QueryMsg doesn't require signing.\n\n**Arguments**:\n\n- `contract_address`: the address of the smart contract.\n- `query_msg`: QueryMsg in JSON format.\n\n**Returns**:\n\nthe message receipt\n\n<a id=\"plugins.aea-ledger-cosmos.aea_ledger_cosmos.cosmos._CosmosApi.get_transfer_transaction\"></a>\n\n#### get`_`transfer`_`transaction\n\n```python\ndef get_transfer_transaction(sender_address: Address,\n                             destination_address: Address,\n                             amount: int,\n                             tx_fee: int,\n                             tx_nonce: str,\n                             denom: Optional[str] = None,\n                             gas: int = DEFAULT_GAS_AMOUNT,\n                             memo: str = \"\",\n                             chain_id: Optional[str] = None,\n                             account_number: Optional[int] = None,\n                             sequence: Optional[int] = None,\n                             tx_fee_denom: Optional[str] = None,\n                             **kwargs: Any) -> Optional[JSONLike]\n```\n\nSubmit a transfer transaction to the ledger.\n\n**Arguments**:\n\n- `sender_address`: the sender address of the payer.\n- `destination_address`: the destination address of the payee.\n- `amount`: the amount of wealth to be transferred.\n- `tx_fee`: the transaction fee.\n- `tx_nonce`: verifies the authenticity of the tx\n- `denom`: the denomination of tx fee and amount\n- `gas`: the gas used.\n- `memo`: memo to include in tx.\n- `chain_id`: the chain ID of the transaction.\n- `account_number`: Account number\n- `sequence`: Sequence\n- `tx_fee_denom`: Denomination of tx_fee, identical with denom param when None\n- `kwargs`: keyword arguments.\n\n**Returns**:\n\nthe transfer transaction\n\n<a id=\"plugins.aea-ledger-cosmos.aea_ledger_cosmos.cosmos._CosmosApi.get_packed_exec_msg\"></a>\n\n#### get`_`packed`_`exec`_`msg\n\n```python\ndef get_packed_exec_msg(sender_address: Address,\n                        contract_address: str,\n                        msg: JSONLike,\n                        funds: int = 0,\n                        denom: Optional[str] = None) -> ProtoAny\n```\n\nCreate and pack MsgExecuteContract\n\n**Arguments**:\n\n- `sender_address`: Address of sender\n- `contract_address`: Address of contract\n- `msg`: Paramaters to be passed to smart contract\n- `funds`: Funds to be sent to smart contract\n- `denom`: the denomination of funds\n\n**Returns**:\n\nPacked MsgExecuteContract\n\n<a id=\"plugins.aea-ledger-cosmos.aea_ledger_cosmos.cosmos._CosmosApi.get_packed_send_msg\"></a>\n\n#### get`_`packed`_`send`_`msg\n\n```python\ndef get_packed_send_msg(from_address: Address,\n                        to_address: Address,\n                        amount: int,\n                        denom: Optional[str] = None) -> ProtoAny\n```\n\nGenerate and pack MsgSend\n\n**Arguments**:\n\n- `from_address`: Address of sender\n- `to_address`: Address of recipient\n- `amount`: amount of coins to be sent\n- `denom`: the denomination of and amount\n\n**Returns**:\n\npacker ProtoAny type message\n\n<a id=\"plugins.aea-ledger-cosmos.aea_ledger_cosmos.cosmos._CosmosApi.get_multi_transaction\"></a>\n\n#### get`_`multi`_`transaction\n\n```python\ndef get_multi_transaction(from_addresses: List[str],\n                          pub_keys: Optional[List[bytes]],\n                          msgs: List[ProtoAny],\n                          gas: int,\n                          tx_fee: int = 0,\n                          memo: str = \"\",\n                          chain_id: Optional[str] = None,\n                          denom: Optional[str] = None,\n                          tx_fee_denom: Optional[str] = None) -> JSONLike\n```\n\nGenerate transaction with multiple messages\n\n**Arguments**:\n\n- `from_addresses`: Addresses of signers\n- `pub_keys`: Public keys of signers\n- `msgs`: Messages to be included in transaction\n- `gas`: the gas used.\n- `tx_fee`: the transaction fee.\n- `memo`: memo to include in tx.\n- `chain_id`: the chain ID of the transaction.\n- `denom`: the denomination of tx fee\n- `tx_fee_denom`: Denomination of tx_fee, identical with denom param when None\n\n**Raises**:\n\n- `None`: RuntimeError if number of pubkeys is not equal to number of from_addresses\n\n**Returns**:\n\nthe transaction\n\n<a id=\"plugins.aea-ledger-cosmos.aea_ledger_cosmos.cosmos._CosmosApi.send_signed_transaction\"></a>\n\n#### send`_`signed`_`transaction\n\n```python\ndef send_signed_transaction(tx_signed: JSONLike) -> Optional[str]\n```\n\nSend a signed transaction and wait for confirmation.\n\n**Arguments**:\n\n- `tx_signed`: the signed transaction\n\n**Returns**:\n\ntx_digest, if present\n\n<a id=\"plugins.aea-ledger-cosmos.aea_ledger_cosmos.cosmos._CosmosApi.get_transaction_receipt\"></a>\n\n#### get`_`transaction`_`receipt\n\n```python\ndef get_transaction_receipt(tx_digest: str) -> Optional[JSONLike]\n```\n\nGet the transaction receipt for a transaction digest.\n\n**Arguments**:\n\n- `tx_digest`: the digest associated to the transaction.\n\n**Returns**:\n\nthe tx receipt, if present\n\n<a id=\"plugins.aea-ledger-cosmos.aea_ledger_cosmos.cosmos._CosmosApi.get_transaction\"></a>\n\n#### get`_`transaction\n\n```python\ndef get_transaction(tx_digest: str) -> Optional[JSONLike]\n```\n\nGet the transaction for a transaction digest.\n\n**Arguments**:\n\n- `tx_digest`: the digest associated to the transaction.\n\n**Returns**:\n\nthe tx, if present\n\n<a id=\"plugins.aea-ledger-cosmos.aea_ledger_cosmos.cosmos._CosmosApi.get_contract_instance\"></a>\n\n#### get`_`contract`_`instance\n\n```python\ndef get_contract_instance(contract_interface: Dict[str, str],\n                          contract_address: Optional[str] = None) -> Any\n```\n\nGet the instance of a contract.\n\n**Arguments**:\n\n- `contract_interface`: the contract interface.\n- `contract_address`: the contract address.\n\n**Returns**:\n\nthe contract instance\n\n<a id=\"plugins.aea-ledger-cosmos.aea_ledger_cosmos.cosmos._CosmosApi.update_with_gas_estimate\"></a>\n\n#### update`_`with`_`gas`_`estimate\n\n```python\ndef update_with_gas_estimate(transaction: JSONLike) -> JSONLike\n```\n\nAttempts to update the transaction with a gas estimate\n\n**Arguments**:\n\n- `transaction`: the transaction\n\n**Raises**:\n\n- `None`: NotImplementedError\n\n<a id=\"plugins.aea-ledger-cosmos.aea_ledger_cosmos.cosmos.CosmosApi\"></a>\n\n## CosmosApi Objects\n\n```python\nclass CosmosApi(_CosmosApi, CosmosHelper)\n```\n\nClass to interact with the Cosmos SDK via a HTTP APIs.\n\n<a id=\"plugins.aea-ledger-cosmos.aea_ledger_cosmos.cosmos.CosmosFaucetApi\"></a>\n\n## CosmosFaucetApi Objects\n\n```python\nclass CosmosFaucetApi(FaucetApi)\n```\n\nCosmos testnet faucet API.\n\n<a id=\"plugins.aea-ledger-cosmos.aea_ledger_cosmos.cosmos.CosmosFaucetApi.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(poll_interval: Optional[float] = None,\n             final_wait_interval: Optional[float] = None)\n```\n\nInitialize CosmosFaucetApi.\n\n<a id=\"plugins.aea-ledger-cosmos.aea_ledger_cosmos.cosmos.CosmosFaucetApi.get_wealth\"></a>\n\n#### get`_`wealth\n\n```python\ndef get_wealth(address: Address, url: Optional[str] = None) -> None\n```\n\nGet wealth from the faucet for the provided address.\n\n**Arguments**:\n\n- `address`: the address.\n- `url`: the url\n\n**Raises**:\n\n- `None`: RuntimeError of explicit faucet failures\n\n"
  },
  {
    "path": "docs/api/plugins/aea_ledger_ethereum/ethereum.md",
    "content": "<a id=\"plugins.aea-ledger-ethereum.aea_ledger_ethereum.ethereum\"></a>\n\n# plugins.aea-ledger-ethereum.aea`_`ledger`_`ethereum.ethereum\n\nEthereum module wrapping the public and private key cryptography and ledger api.\n\n<a id=\"plugins.aea-ledger-ethereum.aea_ledger_ethereum.ethereum.get_gas_price_strategy\"></a>\n\n#### get`_`gas`_`price`_`strategy\n\n```python\ndef get_gas_price_strategy(\n        gas_price_strategy: Optional[str] = None,\n        api_key: Optional[str] = None) -> Callable[[Web3, TxParams], Wei]\n```\n\nGet the gas price strategy.\n\n<a id=\"plugins.aea-ledger-ethereum.aea_ledger_ethereum.ethereum.SignedTransactionTranslator\"></a>\n\n## SignedTransactionTranslator Objects\n\n```python\nclass SignedTransactionTranslator()\n```\n\nTranslator for SignedTransaction.\n\n<a id=\"plugins.aea-ledger-ethereum.aea_ledger_ethereum.ethereum.SignedTransactionTranslator.to_dict\"></a>\n\n#### to`_`dict\n\n```python\n@staticmethod\ndef to_dict(\n        signed_transaction: SignedTransaction) -> Dict[str, Union[str, int]]\n```\n\nWrite SignedTransaction to dict.\n\n<a id=\"plugins.aea-ledger-ethereum.aea_ledger_ethereum.ethereum.SignedTransactionTranslator.from_dict\"></a>\n\n#### from`_`dict\n\n```python\n@staticmethod\ndef from_dict(signed_transaction_dict: JSONLike) -> SignedTransaction\n```\n\nGet SignedTransaction from dict.\n\n<a id=\"plugins.aea-ledger-ethereum.aea_ledger_ethereum.ethereum.AttributeDictTranslator\"></a>\n\n## AttributeDictTranslator Objects\n\n```python\nclass AttributeDictTranslator()\n```\n\nTranslator for AttributeDict.\n\n<a id=\"plugins.aea-ledger-ethereum.aea_ledger_ethereum.ethereum.AttributeDictTranslator.to_dict\"></a>\n\n#### to`_`dict\n\n```python\n@classmethod\ndef to_dict(cls, attr_dict: Union[AttributeDict, TxReceipt,\n                                  TxData]) -> JSONLike\n```\n\nSimplify to dict.\n\n<a id=\"plugins.aea-ledger-ethereum.aea_ledger_ethereum.ethereum.AttributeDictTranslator.from_dict\"></a>\n\n#### from`_`dict\n\n```python\n@classmethod\ndef from_dict(cls, di: JSONLike) -> AttributeDict\n```\n\nGet back attribute dict.\n\n<a id=\"plugins.aea-ledger-ethereum.aea_ledger_ethereum.ethereum.EthereumCrypto\"></a>\n\n## EthereumCrypto Objects\n\n```python\nclass EthereumCrypto(Crypto[Account])\n```\n\nClass wrapping the Account Generation from Ethereum ledger.\n\n<a id=\"plugins.aea-ledger-ethereum.aea_ledger_ethereum.ethereum.EthereumCrypto.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(private_key_path: Optional[str] = None,\n             password: Optional[str] = None) -> None\n```\n\nInstantiate an ethereum crypto object.\n\n**Arguments**:\n\n- `private_key_path`: the private key path of the agent\n- `password`: the password to encrypt/decrypt the private key.\n\n<a id=\"plugins.aea-ledger-ethereum.aea_ledger_ethereum.ethereum.EthereumCrypto.private_key\"></a>\n\n#### private`_`key\n\n```python\n@property\ndef private_key() -> str\n```\n\nReturn a private key.\n\n**Returns**:\n\na private key string\n\n<a id=\"plugins.aea-ledger-ethereum.aea_ledger_ethereum.ethereum.EthereumCrypto.public_key\"></a>\n\n#### public`_`key\n\n```python\n@property\ndef public_key() -> str\n```\n\nReturn a public key in hex format.\n\n**Returns**:\n\na public key string in hex format\n\n<a id=\"plugins.aea-ledger-ethereum.aea_ledger_ethereum.ethereum.EthereumCrypto.address\"></a>\n\n#### address\n\n```python\n@property\ndef address() -> str\n```\n\nReturn the address for the key pair.\n\n**Returns**:\n\na display_address str\n\n<a id=\"plugins.aea-ledger-ethereum.aea_ledger_ethereum.ethereum.EthereumCrypto.load_private_key_from_path\"></a>\n\n#### load`_`private`_`key`_`from`_`path\n\n```python\n@classmethod\ndef load_private_key_from_path(cls,\n                               file_name: str,\n                               password: Optional[str] = None) -> Account\n```\n\nLoad a private key in hex format from a file.\n\n**Arguments**:\n\n- `file_name`: the path to the hex file.\n- `password`: the password to encrypt/decrypt the private key.\n\n**Returns**:\n\nthe Entity.\n\n<a id=\"plugins.aea-ledger-ethereum.aea_ledger_ethereum.ethereum.EthereumCrypto.sign_message\"></a>\n\n#### sign`_`message\n\n```python\ndef sign_message(message: bytes, is_deprecated_mode: bool = False) -> str\n```\n\nSign a message in bytes string form.\n\n**Arguments**:\n\n- `message`: the message to be signed\n- `is_deprecated_mode`: if the deprecated signing is used\n\n**Returns**:\n\nsignature of the message in string form\n\n<a id=\"plugins.aea-ledger-ethereum.aea_ledger_ethereum.ethereum.EthereumCrypto.sign_transaction\"></a>\n\n#### sign`_`transaction\n\n```python\ndef sign_transaction(transaction: JSONLike) -> JSONLike\n```\n\nSign a transaction in bytes string form.\n\n**Arguments**:\n\n- `transaction`: the transaction to be signed\n\n**Returns**:\n\nsigned transaction\n\n<a id=\"plugins.aea-ledger-ethereum.aea_ledger_ethereum.ethereum.EthereumCrypto.generate_private_key\"></a>\n\n#### generate`_`private`_`key\n\n```python\n@classmethod\ndef generate_private_key(cls) -> Account\n```\n\nGenerate a key pair for ethereum network.\n\n<a id=\"plugins.aea-ledger-ethereum.aea_ledger_ethereum.ethereum.EthereumCrypto.encrypt\"></a>\n\n#### encrypt\n\n```python\ndef encrypt(password: str) -> str\n```\n\nEncrypt the private key and return in json.\n\n**Arguments**:\n\n- `password`: the password to decrypt.\n\n**Returns**:\n\njson string containing encrypted private key.\n\n<a id=\"plugins.aea-ledger-ethereum.aea_ledger_ethereum.ethereum.EthereumCrypto.decrypt\"></a>\n\n#### decrypt\n\n```python\n@classmethod\ndef decrypt(cls, keyfile_json: str, password: str) -> str\n```\n\nDecrypt the private key and return in raw form.\n\n**Arguments**:\n\n- `keyfile_json`: json str containing encrypted private key.\n- `password`: the password to decrypt.\n\n**Returns**:\n\nthe raw private key.\n\n<a id=\"plugins.aea-ledger-ethereum.aea_ledger_ethereum.ethereum.EthereumHelper\"></a>\n\n## EthereumHelper Objects\n\n```python\nclass EthereumHelper(Helper)\n```\n\nHelper class usable as Mixin for EthereumApi or as standalone class.\n\n<a id=\"plugins.aea-ledger-ethereum.aea_ledger_ethereum.ethereum.EthereumHelper.is_transaction_settled\"></a>\n\n#### is`_`transaction`_`settled\n\n```python\n@staticmethod\ndef is_transaction_settled(tx_receipt: JSONLike) -> bool\n```\n\nCheck whether a transaction is settled or not.\n\n**Arguments**:\n\n- `tx_receipt`: the receipt associated to the transaction.\n\n**Returns**:\n\nTrue if the transaction has been settled, False o/w.\n\n<a id=\"plugins.aea-ledger-ethereum.aea_ledger_ethereum.ethereum.EthereumHelper.get_contract_address\"></a>\n\n#### get`_`contract`_`address\n\n```python\n@staticmethod\ndef get_contract_address(tx_receipt: JSONLike) -> Optional[str]\n```\n\nRetrieve the `contract_address` from a transaction receipt.\n\n**Arguments**:\n\n- `tx_receipt`: the receipt of the transaction.\n\n**Returns**:\n\nthe contract address, if present\n\n<a id=\"plugins.aea-ledger-ethereum.aea_ledger_ethereum.ethereum.EthereumHelper.is_transaction_valid\"></a>\n\n#### is`_`transaction`_`valid\n\n```python\n@staticmethod\ndef is_transaction_valid(tx: dict, seller: Address, client: Address,\n                         tx_nonce: str, amount: int) -> bool\n```\n\nCheck whether a transaction is valid or not.\n\n**Arguments**:\n\n- `tx`: the transaction.\n- `seller`: the address of the seller.\n- `client`: the address of the client.\n- `tx_nonce`: the transaction nonce.\n- `amount`: the amount we expect to get from the transaction.\n\n**Returns**:\n\nTrue if the random_message is equals to tx['input']\n\n<a id=\"plugins.aea-ledger-ethereum.aea_ledger_ethereum.ethereum.EthereumHelper.generate_tx_nonce\"></a>\n\n#### generate`_`tx`_`nonce\n\n```python\n@staticmethod\ndef generate_tx_nonce(seller: Address, client: Address) -> str\n```\n\nGenerate a unique hash to distinguish transactions with the same terms.\n\n**Arguments**:\n\n- `seller`: the address of the seller.\n- `client`: the address of the client.\n\n**Returns**:\n\nreturn the hash in hex.\n\n<a id=\"plugins.aea-ledger-ethereum.aea_ledger_ethereum.ethereum.EthereumHelper.get_address_from_public_key\"></a>\n\n#### get`_`address`_`from`_`public`_`key\n\n```python\n@classmethod\ndef get_address_from_public_key(cls, public_key: str) -> str\n```\n\nGet the address from the public key.\n\n**Arguments**:\n\n- `public_key`: the public key\n\n**Returns**:\n\nstr\n\n<a id=\"plugins.aea-ledger-ethereum.aea_ledger_ethereum.ethereum.EthereumHelper.recover_message\"></a>\n\n#### recover`_`message\n\n```python\n@classmethod\ndef recover_message(cls,\n                    message: bytes,\n                    signature: str,\n                    is_deprecated_mode: bool = False) -> Tuple[Address, ...]\n```\n\nRecover the addresses from the hash.\n\n**Arguments**:\n\n- `message`: the message we expect\n- `signature`: the transaction signature\n- `is_deprecated_mode`: if the deprecated signing was used\n\n**Returns**:\n\nthe recovered addresses\n\n<a id=\"plugins.aea-ledger-ethereum.aea_ledger_ethereum.ethereum.EthereumHelper.recover_public_keys_from_message\"></a>\n\n#### recover`_`public`_`keys`_`from`_`message\n\n```python\n@classmethod\ndef recover_public_keys_from_message(\n        cls,\n        message: bytes,\n        signature: str,\n        is_deprecated_mode: bool = False) -> Tuple[str, ...]\n```\n\nGet the public key used to produce the `signature` of the `message`\n\n**Arguments**:\n\n- `message`: raw bytes used to produce signature\n- `signature`: signature of the message\n- `is_deprecated_mode`: if the deprecated signing was used\n\n**Returns**:\n\nthe recovered public keys\n\n<a id=\"plugins.aea-ledger-ethereum.aea_ledger_ethereum.ethereum.EthereumHelper.get_hash\"></a>\n\n#### get`_`hash\n\n```python\n@staticmethod\ndef get_hash(message: bytes) -> str\n```\n\nGet the hash of a message.\n\n**Arguments**:\n\n- `message`: the message to be hashed.\n\n**Returns**:\n\nthe hash of the message.\n\n<a id=\"plugins.aea-ledger-ethereum.aea_ledger_ethereum.ethereum.EthereumHelper.load_contract_interface\"></a>\n\n#### load`_`contract`_`interface\n\n```python\n@classmethod\ndef load_contract_interface(cls, file_path: Path) -> Dict[str, str]\n```\n\nLoad contract interface.\n\n**Arguments**:\n\n- `file_path`: the file path to the interface\n\n**Returns**:\n\nthe interface\n\n<a id=\"plugins.aea-ledger-ethereum.aea_ledger_ethereum.ethereum.EthereumApi\"></a>\n\n## EthereumApi Objects\n\n```python\nclass EthereumApi(LedgerApi, EthereumHelper)\n```\n\nClass to interact with the Ethereum Web3 APIs.\n\n<a id=\"plugins.aea-ledger-ethereum.aea_ledger_ethereum.ethereum.EthereumApi.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(**kwargs: Any)\n```\n\nInitialize the Ethereum ledger APIs.\n\n**Arguments**:\n\n- `kwargs`: keyword arguments\n\n<a id=\"plugins.aea-ledger-ethereum.aea_ledger_ethereum.ethereum.EthereumApi.api\"></a>\n\n#### api\n\n```python\n@property\ndef api() -> Web3\n```\n\nGet the underlying API object.\n\n<a id=\"plugins.aea-ledger-ethereum.aea_ledger_ethereum.ethereum.EthereumApi.get_balance\"></a>\n\n#### get`_`balance\n\n```python\ndef get_balance(address: Address) -> Optional[int]\n```\n\nGet the balance of a given account.\n\n<a id=\"plugins.aea-ledger-ethereum.aea_ledger_ethereum.ethereum.EthereumApi.get_state\"></a>\n\n#### get`_`state\n\n```python\ndef get_state(callable_name: str, *args: Any,\n              **kwargs: Any) -> Optional[JSONLike]\n```\n\nCall a specified function on the ledger API.\n\n<a id=\"plugins.aea-ledger-ethereum.aea_ledger_ethereum.ethereum.EthereumApi.get_transfer_transaction\"></a>\n\n#### get`_`transfer`_`transaction\n\n```python\ndef get_transfer_transaction(sender_address: Address,\n                             destination_address: Address,\n                             amount: int,\n                             tx_fee: int,\n                             tx_nonce: str,\n                             chain_id: Optional[int] = None,\n                             gas_price: Optional[str] = None,\n                             gas_price_strategy: Optional[str] = None,\n                             **kwargs: Any) -> Optional[JSONLike]\n```\n\nSubmit a transfer transaction to the ledger.\n\n**Arguments**:\n\n- `sender_address`: the sender address of the payer.\n- `destination_address`: the destination address of the payee.\n- `amount`: the amount of wealth to be transferred (in Wei).\n- `tx_fee`: the transaction fee (gas) to be used (in Wei).\n- `tx_nonce`: verifies the authenticity of the tx.\n- `chain_id`: the Chain ID of the Ethereum transaction.\n- `gas_price`: the gas price (in Wei)\n- `gas_price_strategy`: the gas price strategy to be used.\n- `kwargs`: keyword arguments\n\n**Returns**:\n\nthe transfer transaction\n\n<a id=\"plugins.aea-ledger-ethereum.aea_ledger_ethereum.ethereum.EthereumApi.update_with_gas_estimate\"></a>\n\n#### update`_`with`_`gas`_`estimate\n\n```python\ndef update_with_gas_estimate(transaction: JSONLike) -> JSONLike\n```\n\nAttempts to update the transaction with a gas estimate\n\n**Arguments**:\n\n- `transaction`: the transaction\n\n**Returns**:\n\nthe updated transaction\n\n<a id=\"plugins.aea-ledger-ethereum.aea_ledger_ethereum.ethereum.EthereumApi.send_signed_transaction\"></a>\n\n#### send`_`signed`_`transaction\n\n```python\ndef send_signed_transaction(tx_signed: JSONLike) -> Optional[str]\n```\n\nSend a signed transaction and wait for confirmation.\n\n**Arguments**:\n\n- `tx_signed`: the signed transaction\n\n**Returns**:\n\ntx_digest, if present\n\n<a id=\"plugins.aea-ledger-ethereum.aea_ledger_ethereum.ethereum.EthereumApi.get_transaction_receipt\"></a>\n\n#### get`_`transaction`_`receipt\n\n```python\ndef get_transaction_receipt(tx_digest: str) -> Optional[JSONLike]\n```\n\nGet the transaction receipt for a transaction digest.\n\n**Arguments**:\n\n- `tx_digest`: the digest associated to the transaction.\n\n**Returns**:\n\nthe tx receipt, if present\n\n<a id=\"plugins.aea-ledger-ethereum.aea_ledger_ethereum.ethereum.EthereumApi.get_transaction\"></a>\n\n#### get`_`transaction\n\n```python\ndef get_transaction(tx_digest: str) -> Optional[JSONLike]\n```\n\nGet the transaction for a transaction digest.\n\n**Arguments**:\n\n- `tx_digest`: the digest associated to the transaction.\n\n**Returns**:\n\nthe tx, if present\n\n<a id=\"plugins.aea-ledger-ethereum.aea_ledger_ethereum.ethereum.EthereumApi.get_contract_instance\"></a>\n\n#### get`_`contract`_`instance\n\n```python\ndef get_contract_instance(contract_interface: Dict[str, str],\n                          contract_address: Optional[str] = None) -> Any\n```\n\nGet the instance of a contract.\n\n**Arguments**:\n\n- `contract_interface`: the contract interface.\n- `contract_address`: the contract address.\n\n**Returns**:\n\nthe contract instance\n\n<a id=\"plugins.aea-ledger-ethereum.aea_ledger_ethereum.ethereum.EthereumApi.get_deploy_transaction\"></a>\n\n#### get`_`deploy`_`transaction\n\n```python\ndef get_deploy_transaction(contract_interface: Dict[str, str],\n                           deployer_address: Address,\n                           value: int = 0,\n                           gas: int = 0,\n                           gas_price: Optional[str] = None,\n                           gas_price_strategy: Optional[str] = None,\n                           **kwargs: Any) -> Optional[JSONLike]\n```\n\nGet the transaction to deploy the smart contract.\n\n**Arguments**:\n\n- `contract_interface`: the contract interface.\n- `deployer_address`: The address that will deploy the contract.\n- `value`: value to send to contract (in Wei)\n- `gas`: the gas to be used (in Wei)\n- `gas_price`: the gas price (in Wei)\n- `gas_price_strategy`: the gas price strategy to be used.\n- `kwargs`: keyword arguments\n\n**Returns**:\n\nthe transaction dictionary.\n\n<a id=\"plugins.aea-ledger-ethereum.aea_ledger_ethereum.ethereum.EthereumApi.is_valid_address\"></a>\n\n#### is`_`valid`_`address\n\n```python\n@classmethod\ndef is_valid_address(cls, address: Address) -> bool\n```\n\nCheck if the address is valid.\n\n**Arguments**:\n\n- `address`: the address to validate\n\n**Returns**:\n\nwhether the address is valid\n\n<a id=\"plugins.aea-ledger-ethereum.aea_ledger_ethereum.ethereum.EthereumFaucetApi\"></a>\n\n## EthereumFaucetApi Objects\n\n```python\nclass EthereumFaucetApi(FaucetApi)\n```\n\nEthereum testnet faucet API.\n\n<a id=\"plugins.aea-ledger-ethereum.aea_ledger_ethereum.ethereum.EthereumFaucetApi.get_wealth\"></a>\n\n#### get`_`wealth\n\n```python\ndef get_wealth(address: Address, url: Optional[str] = None) -> None\n```\n\nGet wealth from the faucet for the provided address.\n\n**Arguments**:\n\n- `address`: the address.\n- `url`: the url\n\n<a id=\"plugins.aea-ledger-ethereum.aea_ledger_ethereum.ethereum.LruLockWrapper\"></a>\n\n## LruLockWrapper Objects\n\n```python\nclass LruLockWrapper()\n```\n\nWrapper for LRU with threading.Lock.\n\n<a id=\"plugins.aea-ledger-ethereum.aea_ledger_ethereum.ethereum.LruLockWrapper.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(lru: LRU) -> None\n```\n\nInit wrapper.\n\n<a id=\"plugins.aea-ledger-ethereum.aea_ledger_ethereum.ethereum.LruLockWrapper.__getitem__\"></a>\n\n#### `__`getitem`__`\n\n```python\ndef __getitem__(*args: Any, **kwargs: Any) -> Any\n```\n\nGet item\n\n<a id=\"plugins.aea-ledger-ethereum.aea_ledger_ethereum.ethereum.LruLockWrapper.__setitem__\"></a>\n\n#### `__`setitem`__`\n\n```python\ndef __setitem__(*args: Any, **kwargs: Any) -> Any\n```\n\nSet item.\n\n<a id=\"plugins.aea-ledger-ethereum.aea_ledger_ethereum.ethereum.LruLockWrapper.__contains__\"></a>\n\n#### `__`contains`__`\n\n```python\ndef __contains__(*args: Any, **kwargs: Any) -> Any\n```\n\nContain item.\n\n<a id=\"plugins.aea-ledger-ethereum.aea_ledger_ethereum.ethereum.LruLockWrapper.__delitem__\"></a>\n\n#### `__`delitem`__`\n\n```python\ndef __delitem__(*args: Any, **kwargs: Any) -> Any\n```\n\nDel item.\n\n<a id=\"plugins.aea-ledger-ethereum.aea_ledger_ethereum.ethereum.set_wrapper_for_web3py_session_cache\"></a>\n\n#### set`_`wrapper`_`for`_`web3py`_`session`_`cache\n\n```python\ndef set_wrapper_for_web3py_session_cache() -> None\n```\n\nWrap web3py session cache with threading.Lock.\n\n"
  },
  {
    "path": "docs/api/plugins/aea_ledger_fetchai/_cosmos.md",
    "content": "<a id=\"plugins.aea-ledger-fetchai.aea_ledger_fetchai._cosmos\"></a>\n\n# plugins.aea-ledger-fetchai.aea`_`ledger`_`fetchai.`_`cosmos\n\nCosmos module wrapping the public and private key cryptography and ledger api.\n\n<a id=\"plugins.aea-ledger-fetchai.aea_ledger_fetchai._cosmos.DataEncrypt\"></a>\n\n## DataEncrypt Objects\n\n```python\nclass DataEncrypt()\n```\n\nClass to encrypt/decrypt data strings with password provided.\n\n<a id=\"plugins.aea-ledger-fetchai.aea_ledger_fetchai._cosmos.DataEncrypt.encrypt\"></a>\n\n#### encrypt\n\n```python\n@classmethod\ndef encrypt(cls, data: bytes, password: str) -> bytes\n```\n\nEncrypt data with password.\n\n<a id=\"plugins.aea-ledger-fetchai.aea_ledger_fetchai._cosmos.DataEncrypt.bytes_encode\"></a>\n\n#### bytes`_`encode\n\n```python\n@staticmethod\ndef bytes_encode(data: bytes) -> str\n```\n\nEncode bytes to ascii friendly string.\n\n<a id=\"plugins.aea-ledger-fetchai.aea_ledger_fetchai._cosmos.DataEncrypt.bytes_decode\"></a>\n\n#### bytes`_`decode\n\n```python\n@staticmethod\ndef bytes_decode(data: str) -> bytes\n```\n\nDecode ascii friendly string to bytes.\n\n<a id=\"plugins.aea-ledger-fetchai.aea_ledger_fetchai._cosmos.DataEncrypt.decrypt\"></a>\n\n#### decrypt\n\n```python\n@classmethod\ndef decrypt(cls, encrypted_data: bytes, password: str) -> bytes\n```\n\nDecrypt data with password provided.\n\n<a id=\"plugins.aea-ledger-fetchai.aea_ledger_fetchai._cosmos.CosmosHelper\"></a>\n\n## CosmosHelper Objects\n\n```python\nclass CosmosHelper(Helper)\n```\n\nHelper class usable as Mixin for CosmosApi or as standalone class.\n\n<a id=\"plugins.aea-ledger-fetchai.aea_ledger_fetchai._cosmos.CosmosHelper.is_transaction_settled\"></a>\n\n#### is`_`transaction`_`settled\n\n```python\n@staticmethod\ndef is_transaction_settled(tx_receipt: JSONLike) -> bool\n```\n\nCheck whether a transaction is settled or not.\n\n**Arguments**:\n\n- `tx_receipt`: the receipt of the transaction.\n\n**Returns**:\n\nTrue if the transaction has been settled, False o/w.\n\n<a id=\"plugins.aea-ledger-fetchai.aea_ledger_fetchai._cosmos.CosmosHelper.get_code_id\"></a>\n\n#### get`_`code`_`id\n\n```python\n@classmethod\ndef get_code_id(cls, tx_receipt: JSONLike) -> Optional[int]\n```\n\nRetrieve the `code_id` from a transaction receipt.\n\n**Arguments**:\n\n- `tx_receipt`: the receipt of the transaction.\n\n**Returns**:\n\nthe code id, if present\n\n<a id=\"plugins.aea-ledger-fetchai.aea_ledger_fetchai._cosmos.CosmosHelper.get_event_attributes\"></a>\n\n#### get`_`event`_`attributes\n\n```python\n@staticmethod\ndef get_event_attributes(tx_receipt: JSONLike) -> Dict\n```\n\nRetrieve events attributes from tx receipt.\n\n**Arguments**:\n\n- `tx_receipt`: the receipt of the transaction.\n\n**Returns**:\n\ndict\n\n<a id=\"plugins.aea-ledger-fetchai.aea_ledger_fetchai._cosmos.CosmosHelper.get_contract_address\"></a>\n\n#### get`_`contract`_`address\n\n```python\n@classmethod\ndef get_contract_address(cls, tx_receipt: JSONLike) -> Optional[str]\n```\n\nRetrieve the `contract_address` from a transaction receipt.\n\n**Arguments**:\n\n- `tx_receipt`: the receipt of the transaction.\n\n**Returns**:\n\nthe contract address, if present\n\n<a id=\"plugins.aea-ledger-fetchai.aea_ledger_fetchai._cosmos.CosmosHelper.is_transaction_valid\"></a>\n\n#### is`_`transaction`_`valid\n\n```python\n@staticmethod\ndef is_transaction_valid(tx: JSONLike, seller: Address, client: Address,\n                         tx_nonce: str, amount: int) -> bool\n```\n\nCheck whether a transaction is valid or not.\n\n**Arguments**:\n\n- `tx`: the transaction.\n- `seller`: the address of the seller.\n- `client`: the address of the client.\n- `tx_nonce`: the transaction nonce.\n- `amount`: the amount we expect to get from the transaction.\n\n**Returns**:\n\nTrue if the random_message is equals to tx['input']\n\n<a id=\"plugins.aea-ledger-fetchai.aea_ledger_fetchai._cosmos.CosmosHelper.generate_tx_nonce\"></a>\n\n#### generate`_`tx`_`nonce\n\n```python\n@staticmethod\ndef generate_tx_nonce(seller: Address, client: Address) -> str\n```\n\nGenerate a unique hash to distinguish transactions with the same terms.\n\n**Arguments**:\n\n- `seller`: the address of the seller.\n- `client`: the address of the client.\n\n**Returns**:\n\nreturn the hash in hex.\n\n<a id=\"plugins.aea-ledger-fetchai.aea_ledger_fetchai._cosmos.CosmosHelper.get_address_from_public_key\"></a>\n\n#### get`_`address`_`from`_`public`_`key\n\n```python\n@classmethod\ndef get_address_from_public_key(cls, public_key: str) -> str\n```\n\nGet the address from the public key.\n\n**Arguments**:\n\n- `public_key`: the public key\n\n**Returns**:\n\nstr\n\n<a id=\"plugins.aea-ledger-fetchai.aea_ledger_fetchai._cosmos.CosmosHelper.recover_message\"></a>\n\n#### recover`_`message\n\n```python\n@classmethod\ndef recover_message(cls,\n                    message: bytes,\n                    signature: str,\n                    is_deprecated_mode: bool = False) -> Tuple[Address, ...]\n```\n\nRecover the addresses from the hash.\n\n**Arguments**:\n\n- `message`: the message we expect\n- `signature`: the transaction signature\n- `is_deprecated_mode`: if the deprecated signing was used\n\n**Returns**:\n\nthe recovered addresses\n\n<a id=\"plugins.aea-ledger-fetchai.aea_ledger_fetchai._cosmos.CosmosHelper.recover_public_keys_from_message\"></a>\n\n#### recover`_`public`_`keys`_`from`_`message\n\n```python\n@classmethod\ndef recover_public_keys_from_message(\n        cls,\n        message: bytes,\n        signature: str,\n        is_deprecated_mode: bool = False) -> Tuple[str, ...]\n```\n\nGet the public key used to produce the `signature` of the `message`\n\n**Arguments**:\n\n- `message`: raw bytes used to produce signature\n- `signature`: signature of the message\n- `is_deprecated_mode`: if the deprecated signing was used\n\n**Returns**:\n\nthe recovered public keys\n\n<a id=\"plugins.aea-ledger-fetchai.aea_ledger_fetchai._cosmos.CosmosHelper.get_hash\"></a>\n\n#### get`_`hash\n\n```python\n@staticmethod\ndef get_hash(message: bytes) -> str\n```\n\nGet the hash of a message.\n\n**Arguments**:\n\n- `message`: the message to be hashed.\n\n**Returns**:\n\nthe hash of the message.\n\n<a id=\"plugins.aea-ledger-fetchai.aea_ledger_fetchai._cosmos.CosmosHelper.is_valid_address\"></a>\n\n#### is`_`valid`_`address\n\n```python\n@classmethod\ndef is_valid_address(cls, address: Address) -> bool\n```\n\nCheck if the address is valid.\n\n**Arguments**:\n\n- `address`: the address to validate\n\n**Returns**:\n\nwhether address is valid or not\n\n<a id=\"plugins.aea-ledger-fetchai.aea_ledger_fetchai._cosmos.CosmosHelper.load_contract_interface\"></a>\n\n#### load`_`contract`_`interface\n\n```python\n@classmethod\ndef load_contract_interface(cls, file_path: Path) -> Dict[str, str]\n```\n\nLoad contract interface.\n\n**Arguments**:\n\n- `file_path`: the file path to the interface\n\n**Returns**:\n\nthe interface\n\n<a id=\"plugins.aea-ledger-fetchai.aea_ledger_fetchai._cosmos.CosmosCrypto\"></a>\n\n## CosmosCrypto Objects\n\n```python\nclass CosmosCrypto(Crypto[SigningKey])\n```\n\nClass wrapping the Account Generation from Ethereum ledger.\n\n<a id=\"plugins.aea-ledger-fetchai.aea_ledger_fetchai._cosmos.CosmosCrypto.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(private_key_path: Optional[str] = None,\n             password: Optional[str] = None) -> None\n```\n\nInstantiate an ethereum crypto object.\n\n**Arguments**:\n\n- `private_key_path`: the private key path of the agent\n- `password`: the password to encrypt/decrypt the private key.\n\n<a id=\"plugins.aea-ledger-fetchai.aea_ledger_fetchai._cosmos.CosmosCrypto.private_key\"></a>\n\n#### private`_`key\n\n```python\n@property\ndef private_key() -> str\n```\n\nReturn a private key.\n\n**Returns**:\n\na private key string\n\n<a id=\"plugins.aea-ledger-fetchai.aea_ledger_fetchai._cosmos.CosmosCrypto.public_key\"></a>\n\n#### public`_`key\n\n```python\n@property\ndef public_key() -> str\n```\n\nReturn a public key in hex format.\n\n**Returns**:\n\na public key string in hex format\n\n<a id=\"plugins.aea-ledger-fetchai.aea_ledger_fetchai._cosmos.CosmosCrypto.address\"></a>\n\n#### address\n\n```python\n@property\ndef address() -> str\n```\n\nReturn the address for the key pair.\n\n**Returns**:\n\na display_address str\n\n<a id=\"plugins.aea-ledger-fetchai.aea_ledger_fetchai._cosmos.CosmosCrypto.load_private_key_from_path\"></a>\n\n#### load`_`private`_`key`_`from`_`path\n\n```python\n@classmethod\ndef load_private_key_from_path(cls,\n                               file_name: str,\n                               password: Optional[str] = None) -> SigningKey\n```\n\nLoad a private key in hex format from a file.\n\n**Arguments**:\n\n- `file_name`: the path to the hex file.\n- `password`: the password to encrypt/decrypt the private key.\n\n**Returns**:\n\nthe Entity.\n\n<a id=\"plugins.aea-ledger-fetchai.aea_ledger_fetchai._cosmos.CosmosCrypto.sign_message\"></a>\n\n#### sign`_`message\n\n```python\ndef sign_message(message: bytes, is_deprecated_mode: bool = False) -> str\n```\n\nSign a message in bytes string form.\n\n**Arguments**:\n\n- `message`: the message to be signed\n- `is_deprecated_mode`: if the deprecated signing is used\n\n**Returns**:\n\nsignature of the message in string form\n\n<a id=\"plugins.aea-ledger-fetchai.aea_ledger_fetchai._cosmos.CosmosCrypto.sign_transaction\"></a>\n\n#### sign`_`transaction\n\n```python\ndef sign_transaction(transaction: JSONLike) -> JSONLike\n```\n\nSign a transaction in bytes string form.\n\n**Arguments**:\n\n- `transaction`: the transaction to be signed\n\n**Returns**:\n\nsigned transaction\n\n<a id=\"plugins.aea-ledger-fetchai.aea_ledger_fetchai._cosmos.CosmosCrypto.generate_private_key\"></a>\n\n#### generate`_`private`_`key\n\n```python\n@classmethod\ndef generate_private_key(cls) -> SigningKey\n```\n\nGenerate a key pair for cosmos network.\n\n<a id=\"plugins.aea-ledger-fetchai.aea_ledger_fetchai._cosmos.CosmosCrypto.encrypt\"></a>\n\n#### encrypt\n\n```python\ndef encrypt(password: str) -> str\n```\n\nEncrypt the private key and return in json.\n\n**Arguments**:\n\n- `password`: the password to decrypt.\n\n**Returns**:\n\njson string containing encrypted private key.\n\n<a id=\"plugins.aea-ledger-fetchai.aea_ledger_fetchai._cosmos.CosmosCrypto.decrypt\"></a>\n\n#### decrypt\n\n```python\n@classmethod\ndef decrypt(cls, keyfile_json: str, password: str) -> str\n```\n\nDecrypt the private key and return in raw form.\n\n**Arguments**:\n\n- `keyfile_json`: json string containing encrypted private key.\n- `password`: the password to decrypt.\n\n**Returns**:\n\nthe raw private key.\n\n<a id=\"plugins.aea-ledger-fetchai.aea_ledger_fetchai._cosmos._CosmosApi\"></a>\n\n## `_`CosmosApi Objects\n\n```python\nclass _CosmosApi(LedgerApi)\n```\n\nClass to interact with the Cosmos SDK via a HTTP APIs.\n\n<a id=\"plugins.aea-ledger-fetchai.aea_ledger_fetchai._cosmos._CosmosApi.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(**kwargs: Any) -> None\n```\n\nInitialize the Cosmos ledger APIs.\n\n<a id=\"plugins.aea-ledger-fetchai.aea_ledger_fetchai._cosmos._CosmosApi.api\"></a>\n\n#### api\n\n```python\n@property\ndef api() -> Any\n```\n\nGet the underlying API object.\n\n<a id=\"plugins.aea-ledger-fetchai.aea_ledger_fetchai._cosmos._CosmosApi.get_balance\"></a>\n\n#### get`_`balance\n\n```python\ndef get_balance(address: Address) -> Optional[int]\n```\n\nGet the balance of a given account.\n\n<a id=\"plugins.aea-ledger-fetchai.aea_ledger_fetchai._cosmos._CosmosApi.get_state\"></a>\n\n#### get`_`state\n\n```python\ndef get_state(callable_name: str, *args: Any,\n              **kwargs: Any) -> Optional[JSONLike]\n```\n\nCall a specified function on the ledger API.\n\nBased on the cosmos REST\nAPI specification, which takes a path (strings separated by '/'). The\nconvention here is to define the root of the path (txs, blocks, etc.)\nas the callable_name and the rest of the path as args.\n\n**Arguments**:\n\n- `callable_name`: name of the callable\n- `args`: positional arguments\n- `kwargs`: keyword arguments\n\n**Returns**:\n\nthe transaction dictionary\n\n<a id=\"plugins.aea-ledger-fetchai.aea_ledger_fetchai._cosmos._CosmosApi.get_deploy_transaction\"></a>\n\n#### get`_`deploy`_`transaction\n\n```python\ndef get_deploy_transaction(contract_interface: Dict[str, str],\n                           deployer_address: Address,\n                           **kwargs: Any) -> Optional[JSONLike]\n```\n\nGet the transaction to deploy the smart contract.\n\nDispatches to _get_storage_transaction and _get_init_transaction based on kwargs.\n\n**Arguments**:\n\n- `contract_interface`: the contract interface.\n- `deployer_address`: The address that will deploy the contract.\n- `kwargs`: keyword arguments.\n\n**Returns**:\n\nthe transaction dictionary.\n\n<a id=\"plugins.aea-ledger-fetchai.aea_ledger_fetchai._cosmos._CosmosApi.get_handle_transaction\"></a>\n\n#### get`_`handle`_`transaction\n\n```python\ndef get_handle_transaction(\n        sender_address: Address,\n        contract_address: Address,\n        handle_msg: Any,\n        amount: int,\n        tx_fee: int,\n        denom: Optional[str] = None,\n        gas: int = DEFAULT_GAS_AMOUNT,\n        memo: str = \"\",\n        chain_id: Optional[str] = None,\n        account_number: Optional[int] = None,\n        sequence: Optional[int] = None,\n        tx_fee_denom: Optional[str] = None) -> Optional[JSONLike]\n```\n\nCreate a CosmWasm HandleMsg transaction.\n\n**Arguments**:\n\n- `sender_address`: the sender address of the message initiator.\n- `contract_address`: the address of the smart contract.\n- `handle_msg`: HandleMsg in JSON format.\n- `amount`: Funds amount sent with transaction.\n- `tx_fee`: the tx fee accepted.\n- `denom`: the name of the denomination of the contract funds\n- `gas`: Maximum amount of gas to be used on executing command.\n- `memo`: any string comment.\n- `chain_id`: the Chain ID of the CosmWasm transaction. Default is 1 (i.e. mainnet).\n- `account_number`: Account number\n- `sequence`: Sequence\n- `tx_fee_denom`: Denomination of tx_fee, identical with denom param when None\n\n**Returns**:\n\nthe unsigned CosmWasm HandleMsg\n\n<a id=\"plugins.aea-ledger-fetchai.aea_ledger_fetchai._cosmos._CosmosApi.execute_contract_query\"></a>\n\n#### execute`_`contract`_`query\n\n```python\ndef execute_contract_query(contract_address: Address,\n                           query_msg: JSONLike) -> Optional[JSONLike]\n```\n\nExecute a CosmWasm QueryMsg. QueryMsg doesn't require signing.\n\n**Arguments**:\n\n- `contract_address`: the address of the smart contract.\n- `query_msg`: QueryMsg in JSON format.\n\n**Returns**:\n\nthe message receipt\n\n<a id=\"plugins.aea-ledger-fetchai.aea_ledger_fetchai._cosmos._CosmosApi.get_transfer_transaction\"></a>\n\n#### get`_`transfer`_`transaction\n\n```python\ndef get_transfer_transaction(sender_address: Address,\n                             destination_address: Address,\n                             amount: int,\n                             tx_fee: int,\n                             tx_nonce: str,\n                             denom: Optional[str] = None,\n                             gas: int = DEFAULT_GAS_AMOUNT,\n                             memo: str = \"\",\n                             chain_id: Optional[str] = None,\n                             account_number: Optional[int] = None,\n                             sequence: Optional[int] = None,\n                             tx_fee_denom: Optional[str] = None,\n                             **kwargs: Any) -> Optional[JSONLike]\n```\n\nSubmit a transfer transaction to the ledger.\n\n**Arguments**:\n\n- `sender_address`: the sender address of the payer.\n- `destination_address`: the destination address of the payee.\n- `amount`: the amount of wealth to be transferred.\n- `tx_fee`: the transaction fee.\n- `tx_nonce`: verifies the authenticity of the tx\n- `denom`: the denomination of tx fee and amount\n- `gas`: the gas used.\n- `memo`: memo to include in tx.\n- `chain_id`: the chain ID of the transaction.\n- `account_number`: Account number\n- `sequence`: Sequence\n- `tx_fee_denom`: Denomination of tx_fee, identical with denom param when None\n- `kwargs`: keyword arguments.\n\n**Returns**:\n\nthe transfer transaction\n\n<a id=\"plugins.aea-ledger-fetchai.aea_ledger_fetchai._cosmos._CosmosApi.get_packed_exec_msg\"></a>\n\n#### get`_`packed`_`exec`_`msg\n\n```python\ndef get_packed_exec_msg(sender_address: Address,\n                        contract_address: str,\n                        msg: JSONLike,\n                        funds: int = 0,\n                        denom: Optional[str] = None) -> ProtoAny\n```\n\nCreate and pack MsgExecuteContract\n\n**Arguments**:\n\n- `sender_address`: Address of sender\n- `contract_address`: Address of contract\n- `msg`: Paramaters to be passed to smart contract\n- `funds`: Funds to be sent to smart contract\n- `denom`: the denomination of funds\n\n**Returns**:\n\nPacked MsgExecuteContract\n\n<a id=\"plugins.aea-ledger-fetchai.aea_ledger_fetchai._cosmos._CosmosApi.get_packed_send_msg\"></a>\n\n#### get`_`packed`_`send`_`msg\n\n```python\ndef get_packed_send_msg(from_address: Address,\n                        to_address: Address,\n                        amount: int,\n                        denom: Optional[str] = None) -> ProtoAny\n```\n\nGenerate and pack MsgSend\n\n**Arguments**:\n\n- `from_address`: Address of sender\n- `to_address`: Address of recipient\n- `amount`: amount of coins to be sent\n- `denom`: the denomination of and amount\n\n**Returns**:\n\npacker ProtoAny type message\n\n<a id=\"plugins.aea-ledger-fetchai.aea_ledger_fetchai._cosmos._CosmosApi.get_multi_transaction\"></a>\n\n#### get`_`multi`_`transaction\n\n```python\ndef get_multi_transaction(from_addresses: List[str],\n                          pub_keys: Optional[List[bytes]],\n                          msgs: List[ProtoAny],\n                          gas: int,\n                          tx_fee: int = 0,\n                          memo: str = \"\",\n                          chain_id: Optional[str] = None,\n                          denom: Optional[str] = None,\n                          tx_fee_denom: Optional[str] = None) -> JSONLike\n```\n\nGenerate transaction with multiple messages\n\n**Arguments**:\n\n- `from_addresses`: Addresses of signers\n- `pub_keys`: Public keys of signers\n- `msgs`: Messages to be included in transaction\n- `gas`: the gas used.\n- `tx_fee`: the transaction fee.\n- `memo`: memo to include in tx.\n- `chain_id`: the chain ID of the transaction.\n- `denom`: the denomination of tx fee\n- `tx_fee_denom`: Denomination of tx_fee, identical with denom param when None\n\n**Raises**:\n\n- `None`: RuntimeError if number of pubkeys is not equal to number of from_addresses\n\n**Returns**:\n\nthe transaction\n\n<a id=\"plugins.aea-ledger-fetchai.aea_ledger_fetchai._cosmos._CosmosApi.send_signed_transaction\"></a>\n\n#### send`_`signed`_`transaction\n\n```python\ndef send_signed_transaction(tx_signed: JSONLike) -> Optional[str]\n```\n\nSend a signed transaction and wait for confirmation.\n\n**Arguments**:\n\n- `tx_signed`: the signed transaction\n\n**Returns**:\n\ntx_digest, if present\n\n<a id=\"plugins.aea-ledger-fetchai.aea_ledger_fetchai._cosmos._CosmosApi.get_transaction_receipt\"></a>\n\n#### get`_`transaction`_`receipt\n\n```python\ndef get_transaction_receipt(tx_digest: str) -> Optional[JSONLike]\n```\n\nGet the transaction receipt for a transaction digest.\n\n**Arguments**:\n\n- `tx_digest`: the digest associated to the transaction.\n\n**Returns**:\n\nthe tx receipt, if present\n\n<a id=\"plugins.aea-ledger-fetchai.aea_ledger_fetchai._cosmos._CosmosApi.get_transaction\"></a>\n\n#### get`_`transaction\n\n```python\ndef get_transaction(tx_digest: str) -> Optional[JSONLike]\n```\n\nGet the transaction for a transaction digest.\n\n**Arguments**:\n\n- `tx_digest`: the digest associated to the transaction.\n\n**Returns**:\n\nthe tx, if present\n\n<a id=\"plugins.aea-ledger-fetchai.aea_ledger_fetchai._cosmos._CosmosApi.get_contract_instance\"></a>\n\n#### get`_`contract`_`instance\n\n```python\ndef get_contract_instance(contract_interface: Dict[str, str],\n                          contract_address: Optional[str] = None) -> Any\n```\n\nGet the instance of a contract.\n\n**Arguments**:\n\n- `contract_interface`: the contract interface.\n- `contract_address`: the contract address.\n\n**Returns**:\n\nthe contract instance\n\n<a id=\"plugins.aea-ledger-fetchai.aea_ledger_fetchai._cosmos._CosmosApi.update_with_gas_estimate\"></a>\n\n#### update`_`with`_`gas`_`estimate\n\n```python\ndef update_with_gas_estimate(transaction: JSONLike) -> JSONLike\n```\n\nAttempts to update the transaction with a gas estimate\n\n**Arguments**:\n\n- `transaction`: the transaction\n\n**Raises**:\n\n- `None`: NotImplementedError\n\n<a id=\"plugins.aea-ledger-fetchai.aea_ledger_fetchai._cosmos.CosmosApi\"></a>\n\n## CosmosApi Objects\n\n```python\nclass CosmosApi(_CosmosApi, CosmosHelper)\n```\n\nClass to interact with the Cosmos SDK via a HTTP APIs.\n\n<a id=\"plugins.aea-ledger-fetchai.aea_ledger_fetchai._cosmos.CosmosFaucetApi\"></a>\n\n## CosmosFaucetApi Objects\n\n```python\nclass CosmosFaucetApi(FaucetApi)\n```\n\nCosmos testnet faucet API.\n\n<a id=\"plugins.aea-ledger-fetchai.aea_ledger_fetchai._cosmos.CosmosFaucetApi.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(poll_interval: Optional[float] = None,\n             final_wait_interval: Optional[float] = None)\n```\n\nInitialize CosmosFaucetApi.\n\n<a id=\"plugins.aea-ledger-fetchai.aea_ledger_fetchai._cosmos.CosmosFaucetApi.get_wealth\"></a>\n\n#### get`_`wealth\n\n```python\ndef get_wealth(address: Address, url: Optional[str] = None) -> None\n```\n\nGet wealth from the faucet for the provided address.\n\n**Arguments**:\n\n- `address`: the address.\n- `url`: the url\n\n**Raises**:\n\n- `None`: RuntimeError of explicit faucet failures\n\n"
  },
  {
    "path": "docs/api/plugins/aea_ledger_fetchai/fetchai.md",
    "content": "<a id=\"plugins.aea-ledger-fetchai.aea_ledger_fetchai.fetchai\"></a>\n\n# plugins.aea-ledger-fetchai.aea`_`ledger`_`fetchai.fetchai\n\nFetchai module wrapping the public and private key cryptography and ledger api.\n\n<a id=\"plugins.aea-ledger-fetchai.aea_ledger_fetchai.fetchai.FetchAIHelper\"></a>\n\n## FetchAIHelper Objects\n\n```python\nclass FetchAIHelper(CosmosHelper)\n```\n\nHelper class usable as Mixin for FetchAIApi or as standalone class.\n\n<a id=\"plugins.aea-ledger-fetchai.aea_ledger_fetchai.fetchai.FetchAICrypto\"></a>\n\n## FetchAICrypto Objects\n\n```python\nclass FetchAICrypto(CosmosCrypto)\n```\n\nClass wrapping the Entity Generation from Fetch.AI ledger.\n\n<a id=\"plugins.aea-ledger-fetchai.aea_ledger_fetchai.fetchai.FetchAIApi\"></a>\n\n## FetchAIApi Objects\n\n```python\nclass FetchAIApi(_CosmosApi, FetchAIHelper)\n```\n\nClass to interact with the Fetch ledger APIs.\n\n<a id=\"plugins.aea-ledger-fetchai.aea_ledger_fetchai.fetchai.FetchAIApi.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(**kwargs: Any) -> None\n```\n\nInitialize the Fetch.ai ledger APIs.\n\n<a id=\"plugins.aea-ledger-fetchai.aea_ledger_fetchai.fetchai.FetchAIFaucetApi\"></a>\n\n## FetchAIFaucetApi Objects\n\n```python\nclass FetchAIFaucetApi(CosmosFaucetApi)\n```\n\nFetchai testnet faucet API.\n\n"
  },
  {
    "path": "docs/api/protocols/base.md",
    "content": "<a id=\"aea.protocols.base\"></a>\n\n# aea.protocols.base\n\nThis module contains the base message and serialization definition.\n\n<a id=\"aea.protocols.base.Message\"></a>\n\n## Message Objects\n\n```python\nclass Message()\n```\n\nThis class implements a message.\n\n<a id=\"aea.protocols.base.Message.Performative\"></a>\n\n## Performative Objects\n\n```python\nclass Performative(Enum)\n```\n\nPerformatives for the base message.\n\n<a id=\"aea.protocols.base.Message.Performative.__str__\"></a>\n\n#### `__`str`__`\n\n```python\ndef __str__() -> str\n```\n\nGet the string representation.\n\n<a id=\"aea.protocols.base.Message.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(_body: Optional[Dict] = None, **kwargs: Any) -> None\n```\n\nInitialize a Message object.\n\n**Arguments**:\n\n- `_body`: the dictionary of values to hold.\n- `kwargs`: any additional value to add to the body. It will overwrite the body values.\n\n<a id=\"aea.protocols.base.Message.json\"></a>\n\n#### json\n\n```python\ndef json() -> dict\n```\n\nGet json friendly str representation of the message.\n\n<a id=\"aea.protocols.base.Message.from_json\"></a>\n\n#### from`_`json\n\n```python\n@classmethod\ndef from_json(cls, data: dict) -> \"Message\"\n```\n\nConstruct message instance from json data.\n\n<a id=\"aea.protocols.base.Message.valid_performatives\"></a>\n\n#### valid`_`performatives\n\n```python\n@property\ndef valid_performatives() -> Set[str]\n```\n\nGet valid performatives.\n\n<a id=\"aea.protocols.base.Message.has_sender\"></a>\n\n#### has`_`sender\n\n```python\n@property\ndef has_sender() -> bool\n```\n\nCheck if it has a sender.\n\n<a id=\"aea.protocols.base.Message.sender\"></a>\n\n#### sender\n\n```python\n@property\ndef sender() -> Address\n```\n\nGet the sender of the message in Address form.\n\n<a id=\"aea.protocols.base.Message.sender\"></a>\n\n#### sender\n\n```python\n@sender.setter\ndef sender(sender: Address) -> None\n```\n\nSet the sender of the message.\n\n<a id=\"aea.protocols.base.Message.has_to\"></a>\n\n#### has`_`to\n\n```python\n@property\ndef has_to() -> bool\n```\n\nCheck if it has a sender.\n\n<a id=\"aea.protocols.base.Message.to\"></a>\n\n#### to\n\n```python\n@property\ndef to() -> Address\n```\n\nGet address of receiver.\n\n<a id=\"aea.protocols.base.Message.to\"></a>\n\n#### to\n\n```python\n@to.setter\ndef to(to: Address) -> None\n```\n\nSet address of receiver.\n\n<a id=\"aea.protocols.base.Message.dialogue_reference\"></a>\n\n#### dialogue`_`reference\n\n```python\n@property\ndef dialogue_reference() -> Tuple[str, str]\n```\n\nGet the dialogue_reference of the message.\n\n<a id=\"aea.protocols.base.Message.message_id\"></a>\n\n#### message`_`id\n\n```python\n@property\ndef message_id() -> int\n```\n\nGet the message_id of the message.\n\n<a id=\"aea.protocols.base.Message.performative\"></a>\n\n#### performative\n\n```python\n@property\ndef performative() -> \"Performative\"\n```\n\nGet the performative of the message.\n\n<a id=\"aea.protocols.base.Message.target\"></a>\n\n#### target\n\n```python\n@property\ndef target() -> int\n```\n\nGet the target of the message.\n\n<a id=\"aea.protocols.base.Message.set\"></a>\n\n#### set\n\n```python\ndef set(key: str, value: Any) -> None\n```\n\nSet key and value pair.\n\n**Arguments**:\n\n- `key`: the key.\n- `value`: the value.\n\n<a id=\"aea.protocols.base.Message.get\"></a>\n\n#### get\n\n```python\ndef get(key: str) -> Optional[Any]\n```\n\nGet value for key.\n\n<a id=\"aea.protocols.base.Message.is_set\"></a>\n\n#### is`_`set\n\n```python\ndef is_set(key: str) -> bool\n```\n\nCheck value is set for key.\n\n<a id=\"aea.protocols.base.Message.__eq__\"></a>\n\n#### `__`eq`__`\n\n```python\ndef __eq__(other: Any) -> bool\n```\n\nCompare with another object.\n\n<a id=\"aea.protocols.base.Message.__repr__\"></a>\n\n#### `__`repr`__`\n\n```python\ndef __repr__() -> str\n```\n\nGet the representation of the message.\n\n<a id=\"aea.protocols.base.Message.__str__\"></a>\n\n#### `__`str`__`\n\n```python\ndef __str__() -> str\n```\n\nGet the string representation of the message. Abbreviated to prevent spamming of logs.\n\n<a id=\"aea.protocols.base.Message.encode\"></a>\n\n#### encode\n\n```python\ndef encode() -> bytes\n```\n\nEncode the message.\n\n<a id=\"aea.protocols.base.Message.decode\"></a>\n\n#### decode\n\n```python\n@classmethod\ndef decode(cls, data: bytes) -> \"Message\"\n```\n\nDecode the message.\n\n<a id=\"aea.protocols.base.Message.has_dialogue_info\"></a>\n\n#### has`_`dialogue`_`info\n\n```python\n@property\ndef has_dialogue_info() -> bool\n```\n\nCheck whether a message has the dialogue fields populated.\n\nMore precisely, it checks whether the fields 'message_id',\n'target' and 'dialogue_reference' are set.\n\n**Returns**:\n\nTrue if the message has the dialogue fields set, False otherwise.\n\n<a id=\"aea.protocols.base.Encoder\"></a>\n\n## Encoder Objects\n\n```python\nclass Encoder(ABC)\n```\n\nEncoder interface.\n\n<a id=\"aea.protocols.base.Encoder.encode\"></a>\n\n#### encode\n\n```python\n@staticmethod\n@abstractmethod\ndef encode(msg: Message) -> bytes\n```\n\nEncode a message.\n\n**Arguments**:\n\n- `msg`: the message to be encoded.\n\n**Returns**:\n\nthe encoded message.\n\n<a id=\"aea.protocols.base.Decoder\"></a>\n\n## Decoder Objects\n\n```python\nclass Decoder(ABC)\n```\n\nDecoder interface.\n\n<a id=\"aea.protocols.base.Decoder.decode\"></a>\n\n#### decode\n\n```python\n@staticmethod\n@abstractmethod\ndef decode(obj: bytes) -> Message\n```\n\nDecode a message.\n\n**Arguments**:\n\n- `obj`: the sequence of bytes to be decoded.\n\n**Returns**:\n\nthe decoded message.\n\n<a id=\"aea.protocols.base.Serializer\"></a>\n\n## Serializer Objects\n\n```python\nclass Serializer(Encoder, Decoder, ABC)\n```\n\nThe implementations of this class defines a serialization layer for a protocol.\n\n<a id=\"aea.protocols.base.Protocol\"></a>\n\n## Protocol Objects\n\n```python\nclass Protocol(Component)\n```\n\nThis class implements a specifications for a protocol.\n\nIt includes a serializer to encode/decode a message.\n\n<a id=\"aea.protocols.base.Protocol.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(configuration: ProtocolConfig, message_class: Type[Message],\n             **kwargs: Any) -> None\n```\n\nInitialize the protocol manager.\n\n**Arguments**:\n\n- `configuration`: the protocol configurations.\n- `message_class`: the message class.\n- `kwargs`: the keyword arguments.\n\n<a id=\"aea.protocols.base.Protocol.serializer\"></a>\n\n#### serializer\n\n```python\n@property\ndef serializer() -> Type[Serializer]\n```\n\nGet the serializer.\n\n<a id=\"aea.protocols.base.Protocol.from_dir\"></a>\n\n#### from`_`dir\n\n```python\n@classmethod\ndef from_dir(cls, directory: str, **kwargs: Any) -> \"Protocol\"\n```\n\nLoad the protocol from a directory.\n\n**Arguments**:\n\n- `directory`: the directory to the skill package.\n- `kwargs`: the keyword arguments.\n\n**Returns**:\n\nthe protocol object.\n\n<a id=\"aea.protocols.base.Protocol.from_config\"></a>\n\n#### from`_`config\n\n```python\n@classmethod\ndef from_config(cls, configuration: ProtocolConfig,\n                **kwargs: Any) -> \"Protocol\"\n```\n\nLoad the protocol from configuration.\n\n**Arguments**:\n\n- `configuration`: the protocol configuration.\n- `kwargs`: the keyword arguments.\n\n**Returns**:\n\nthe protocol object.\n\n<a id=\"aea.protocols.base.Protocol.protocol_id\"></a>\n\n#### protocol`_`id\n\n```python\n@property\ndef protocol_id() -> PublicId\n```\n\nGet protocol id.\n\n<a id=\"aea.protocols.base.Protocol.protocol_specification_id\"></a>\n\n#### protocol`_`specification`_`id\n\n```python\n@property\ndef protocol_specification_id() -> PublicId\n```\n\nGet protocol specification id.\n\n<a id=\"aea.protocols.base.Protocol.__repr__\"></a>\n\n#### `__`repr`__`\n\n```python\ndef __repr__() -> str\n```\n\nGet str representation of the protocol.\n\n"
  },
  {
    "path": "docs/api/protocols/default/custom_types.md",
    "content": "<a id=\"packages.fetchai.protocols.default.custom_types\"></a>\n\n# packages.fetchai.protocols.default.custom`_`types\n\nThis module contains class representations corresponding to every custom type in the protocol specification.\n\n<a id=\"packages.fetchai.protocols.default.custom_types.ErrorCode\"></a>\n\n## ErrorCode Objects\n\n```python\nclass ErrorCode(Enum)\n```\n\nThis class represents an instance of ErrorCode.\n\n<a id=\"packages.fetchai.protocols.default.custom_types.ErrorCode.encode\"></a>\n\n#### encode\n\n```python\n@staticmethod\ndef encode(error_code_protobuf_object: Any,\n           error_code_object: \"ErrorCode\") -> None\n```\n\nEncode an instance of this class into the protocol buffer object.\n\nThe protocol buffer object in the error_code_protobuf_object argument is matched with the instance of this class in the 'error_code_object' argument.\n\n**Arguments**:\n\n- `error_code_protobuf_object`: the protocol buffer object whose type corresponds with this class.\n- `error_code_object`: an instance of this class to be encoded in the protocol buffer object.\n\n<a id=\"packages.fetchai.protocols.default.custom_types.ErrorCode.decode\"></a>\n\n#### decode\n\n```python\n@classmethod\ndef decode(cls, error_code_protobuf_object: Any) -> \"ErrorCode\"\n```\n\nDecode a protocol buffer object that corresponds with this class into an instance of this class.\n\nA new instance of this class is created that matches the protocol buffer object in the 'error_code_protobuf_object' argument.\n\n**Arguments**:\n\n- `error_code_protobuf_object`: the protocol buffer object whose type corresponds with this class.\n\n**Returns**:\n\nA new instance of this class that matches the protocol buffer object in the 'error_code_protobuf_object' argument.\n\n"
  },
  {
    "path": "docs/api/protocols/default/dialogues.md",
    "content": "<a id=\"packages.fetchai.protocols.default.dialogues\"></a>\n\n# packages.fetchai.protocols.default.dialogues\n\nThis module contains the classes required for default dialogue management.\n\n- DefaultDialogue: The dialogue class maintains state of a dialogue and manages it.\n- DefaultDialogues: The dialogues class keeps track of all dialogues.\n\n<a id=\"packages.fetchai.protocols.default.dialogues.DefaultDialogue\"></a>\n\n## DefaultDialogue Objects\n\n```python\nclass DefaultDialogue(Dialogue)\n```\n\nThe default dialogue class maintains state of a dialogue and manages it.\n\n<a id=\"packages.fetchai.protocols.default.dialogues.DefaultDialogue.Role\"></a>\n\n## Role Objects\n\n```python\nclass Role(Dialogue.Role)\n```\n\nThis class defines the agent's role in a default dialogue.\n\n<a id=\"packages.fetchai.protocols.default.dialogues.DefaultDialogue.EndState\"></a>\n\n## EndState Objects\n\n```python\nclass EndState(Dialogue.EndState)\n```\n\nThis class defines the end states of a default dialogue.\n\n<a id=\"packages.fetchai.protocols.default.dialogues.DefaultDialogue.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(dialogue_label: DialogueLabel,\n             self_address: Address,\n             role: Dialogue.Role,\n             message_class: Type[DefaultMessage] = DefaultMessage) -> None\n```\n\nInitialize a dialogue.\n\n**Arguments**:\n\n- `dialogue_label`: the identifier of the dialogue\n- `self_address`: the address of the entity for whom this dialogue is maintained\n- `role`: the role of the agent this dialogue is maintained for\n- `message_class`: the message class used\n\n<a id=\"packages.fetchai.protocols.default.dialogues.DefaultDialogues\"></a>\n\n## DefaultDialogues Objects\n\n```python\nclass DefaultDialogues(Dialogues, ABC)\n```\n\nThis class keeps track of all default dialogues.\n\n<a id=\"packages.fetchai.protocols.default.dialogues.DefaultDialogues.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(self_address: Address,\n             role_from_first_message: Callable[[Message, Address],\n                                               Dialogue.Role],\n             dialogue_class: Type[DefaultDialogue] = DefaultDialogue) -> None\n```\n\nInitialize dialogues.\n\n**Arguments**:\n\n- `self_address`: the address of the entity for whom dialogues are maintained\n- `dialogue_class`: the dialogue class used\n- `role_from_first_message`: the callable determining role from first message\n\n"
  },
  {
    "path": "docs/api/protocols/default/message.md",
    "content": "<a id=\"packages.fetchai.protocols.default.message\"></a>\n\n# packages.fetchai.protocols.default.message\n\nThis module contains default's message definition.\n\n<a id=\"packages.fetchai.protocols.default.message.DefaultMessage\"></a>\n\n## DefaultMessage Objects\n\n```python\nclass DefaultMessage(Message)\n```\n\nA protocol for exchanging any bytes message.\n\n<a id=\"packages.fetchai.protocols.default.message.DefaultMessage.Performative\"></a>\n\n## Performative Objects\n\n```python\nclass Performative(Message.Performative)\n```\n\nPerformatives for the default protocol.\n\n<a id=\"packages.fetchai.protocols.default.message.DefaultMessage.Performative.__str__\"></a>\n\n#### `__`str`__`\n\n```python\ndef __str__() -> str\n```\n\nGet the string representation.\n\n<a id=\"packages.fetchai.protocols.default.message.DefaultMessage.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(performative: Performative,\n             dialogue_reference: Tuple[str, str] = (\"\", \"\"),\n             message_id: int = 1,\n             target: int = 0,\n             **kwargs: Any)\n```\n\nInitialise an instance of DefaultMessage.\n\n**Arguments**:\n\n- `message_id`: the message id.\n- `dialogue_reference`: the dialogue reference.\n- `target`: the message target.\n- `performative`: the message performative.\n- `**kwargs`: extra options.\n\n<a id=\"packages.fetchai.protocols.default.message.DefaultMessage.valid_performatives\"></a>\n\n#### valid`_`performatives\n\n```python\n@property\ndef valid_performatives() -> Set[str]\n```\n\nGet valid performatives.\n\n<a id=\"packages.fetchai.protocols.default.message.DefaultMessage.dialogue_reference\"></a>\n\n#### dialogue`_`reference\n\n```python\n@property\ndef dialogue_reference() -> Tuple[str, str]\n```\n\nGet the dialogue_reference of the message.\n\n<a id=\"packages.fetchai.protocols.default.message.DefaultMessage.message_id\"></a>\n\n#### message`_`id\n\n```python\n@property\ndef message_id() -> int\n```\n\nGet the message_id of the message.\n\n<a id=\"packages.fetchai.protocols.default.message.DefaultMessage.performative\"></a>\n\n#### performative\n\n```python\n@property\ndef performative() -> Performative\n```\n\nGet the performative of the message.\n\n<a id=\"packages.fetchai.protocols.default.message.DefaultMessage.target\"></a>\n\n#### target\n\n```python\n@property\ndef target() -> int\n```\n\nGet the target of the message.\n\n<a id=\"packages.fetchai.protocols.default.message.DefaultMessage.content\"></a>\n\n#### content\n\n```python\n@property\ndef content() -> bytes\n```\n\nGet the 'content' content from the message.\n\n<a id=\"packages.fetchai.protocols.default.message.DefaultMessage.error_code\"></a>\n\n#### error`_`code\n\n```python\n@property\ndef error_code() -> CustomErrorCode\n```\n\nGet the 'error_code' content from the message.\n\n<a id=\"packages.fetchai.protocols.default.message.DefaultMessage.error_data\"></a>\n\n#### error`_`data\n\n```python\n@property\ndef error_data() -> Dict[str, bytes]\n```\n\nGet the 'error_data' content from the message.\n\n<a id=\"packages.fetchai.protocols.default.message.DefaultMessage.error_msg\"></a>\n\n#### error`_`msg\n\n```python\n@property\ndef error_msg() -> str\n```\n\nGet the 'error_msg' content from the message.\n\n"
  },
  {
    "path": "docs/api/protocols/default/serialization.md",
    "content": "<a id=\"packages.fetchai.protocols.default.serialization\"></a>\n\n# packages.fetchai.protocols.default.serialization\n\nSerialization module for default protocol.\n\n<a id=\"packages.fetchai.protocols.default.serialization.DefaultSerializer\"></a>\n\n## DefaultSerializer Objects\n\n```python\nclass DefaultSerializer(Serializer)\n```\n\nSerialization for the 'default' protocol.\n\n<a id=\"packages.fetchai.protocols.default.serialization.DefaultSerializer.encode\"></a>\n\n#### encode\n\n```python\n@staticmethod\ndef encode(msg: Message) -> bytes\n```\n\nEncode a 'Default' message into bytes.\n\n**Arguments**:\n\n- `msg`: the message object.\n\n**Returns**:\n\nthe bytes.\n\n<a id=\"packages.fetchai.protocols.default.serialization.DefaultSerializer.decode\"></a>\n\n#### decode\n\n```python\n@staticmethod\ndef decode(obj: bytes) -> Message\n```\n\nDecode bytes into a 'Default' message.\n\n**Arguments**:\n\n- `obj`: the bytes object.\n\n**Returns**:\n\nthe 'Default' message.\n\n"
  },
  {
    "path": "docs/api/protocols/dialogue/base.md",
    "content": "<a id=\"aea.protocols.dialogue.base\"></a>\n\n# aea.protocols.dialogue.base\n\nThis module contains the classes required for dialogue management.\n\n- DialogueLabel: The dialogue label class acts as an identifier for dialogues.\n- Dialogue: The dialogue class maintains state of a dialogue and manages it.\n- Dialogues: The dialogues class keeps track of all dialogues.\n\n<a id=\"aea.protocols.dialogue.base.InvalidDialogueMessage\"></a>\n\n## InvalidDialogueMessage Objects\n\n```python\nclass InvalidDialogueMessage(Exception)\n```\n\nException for adding invalid message to a dialogue.\n\n<a id=\"aea.protocols.dialogue.base.DialogueLabel\"></a>\n\n## DialogueLabel Objects\n\n```python\nclass DialogueLabel()\n```\n\nThe dialogue label class acts as an identifier for dialogues.\n\n<a id=\"aea.protocols.dialogue.base.DialogueLabel.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(dialogue_reference: Tuple[str,\n                                       str], dialogue_opponent_addr: Address,\n             dialogue_starter_addr: Address) -> None\n```\n\nInitialize a dialogue label.\n\n**Arguments**:\n\n- `dialogue_reference`: the reference of the dialogue.\n- `dialogue_opponent_addr`: the addr of the agent with which the dialogue is kept.\n- `dialogue_starter_addr`: the addr of the agent which started the dialogue.\n\n<a id=\"aea.protocols.dialogue.base.DialogueLabel.dialogue_reference\"></a>\n\n#### dialogue`_`reference\n\n```python\n@property\ndef dialogue_reference() -> Tuple[str, str]\n```\n\nGet the dialogue reference.\n\n<a id=\"aea.protocols.dialogue.base.DialogueLabel.dialogue_starter_reference\"></a>\n\n#### dialogue`_`starter`_`reference\n\n```python\n@property\ndef dialogue_starter_reference() -> str\n```\n\nGet the dialogue starter reference.\n\n<a id=\"aea.protocols.dialogue.base.DialogueLabel.dialogue_responder_reference\"></a>\n\n#### dialogue`_`responder`_`reference\n\n```python\n@property\ndef dialogue_responder_reference() -> str\n```\n\nGet the dialogue responder reference.\n\n<a id=\"aea.protocols.dialogue.base.DialogueLabel.dialogue_opponent_addr\"></a>\n\n#### dialogue`_`opponent`_`addr\n\n```python\n@property\ndef dialogue_opponent_addr() -> str\n```\n\nGet the address of the dialogue opponent.\n\n<a id=\"aea.protocols.dialogue.base.DialogueLabel.dialogue_starter_addr\"></a>\n\n#### dialogue`_`starter`_`addr\n\n```python\n@property\ndef dialogue_starter_addr() -> str\n```\n\nGet the address of the dialogue starter.\n\n<a id=\"aea.protocols.dialogue.base.DialogueLabel.__eq__\"></a>\n\n#### `__`eq`__`\n\n```python\ndef __eq__(other: Any) -> bool\n```\n\nCheck for equality between two DialogueLabel objects.\n\n<a id=\"aea.protocols.dialogue.base.DialogueLabel.__hash__\"></a>\n\n#### `__`hash`__`\n\n```python\ndef __hash__() -> int\n```\n\nTurn object into hash.\n\n<a id=\"aea.protocols.dialogue.base.DialogueLabel.json\"></a>\n\n#### json\n\n```python\n@property\ndef json() -> Dict\n```\n\nReturn the JSON representation.\n\n<a id=\"aea.protocols.dialogue.base.DialogueLabel.from_json\"></a>\n\n#### from`_`json\n\n```python\n@classmethod\ndef from_json(cls, obj: Dict[str, str]) -> \"DialogueLabel\"\n```\n\nGet dialogue label from json.\n\n<a id=\"aea.protocols.dialogue.base.DialogueLabel.get_incomplete_version\"></a>\n\n#### get`_`incomplete`_`version\n\n```python\ndef get_incomplete_version() -> \"DialogueLabel\"\n```\n\nGet the incomplete version of the label.\n\n<a id=\"aea.protocols.dialogue.base.DialogueLabel.__str__\"></a>\n\n#### `__`str`__`\n\n```python\ndef __str__() -> str\n```\n\nGet the string representation.\n\n<a id=\"aea.protocols.dialogue.base.DialogueLabel.from_str\"></a>\n\n#### from`_`str\n\n```python\n@classmethod\ndef from_str(cls, obj: str) -> \"DialogueLabel\"\n```\n\nGet the dialogue label from string representation.\n\n<a id=\"aea.protocols.dialogue.base._DialogueMeta\"></a>\n\n## `_`DialogueMeta Objects\n\n```python\nclass _DialogueMeta(type)\n```\n\nMetaclass for Dialogue.\n\nCreates class level Rules instance to share among instances\n\n<a id=\"aea.protocols.dialogue.base._DialogueMeta.__new__\"></a>\n\n#### `__`new`__`\n\n```python\ndef __new__(cls, name: str, bases: Tuple[Type], dct: Dict) -> \"_DialogueMeta\"\n```\n\nConstruct a new type.\n\n<a id=\"aea.protocols.dialogue.base.Dialogue\"></a>\n\n## Dialogue Objects\n\n```python\nclass Dialogue(metaclass=_DialogueMeta)\n```\n\nThe dialogue class maintains state of a dialogue and manages it.\n\n<a id=\"aea.protocols.dialogue.base.Dialogue.Rules\"></a>\n\n## Rules Objects\n\n```python\nclass Rules()\n```\n\nThis class defines the rules for the dialogue.\n\n<a id=\"aea.protocols.dialogue.base.Dialogue.Rules.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(\n    initial_performatives: FrozenSet[Message.Performative],\n    terminal_performatives: FrozenSet[Message.Performative],\n    valid_replies: Dict[Message.Performative, FrozenSet[Message.Performative]]\n) -> None\n```\n\nInitialize a dialogue.\n\n**Arguments**:\n\n- `initial_performatives`: the set of all initial performatives.\n- `terminal_performatives`: the set of all terminal performatives.\n- `valid_replies`: the reply structure of speech-acts.\n\n<a id=\"aea.protocols.dialogue.base.Dialogue.Rules.initial_performatives\"></a>\n\n#### initial`_`performatives\n\n```python\n@property\ndef initial_performatives() -> FrozenSet[Message.Performative]\n```\n\nGet the performatives one of which the terminal message in the dialogue must have.\n\n**Returns**:\n\nthe valid performatives of an terminal message\n\n<a id=\"aea.protocols.dialogue.base.Dialogue.Rules.terminal_performatives\"></a>\n\n#### terminal`_`performatives\n\n```python\n@property\ndef terminal_performatives() -> FrozenSet[Message.Performative]\n```\n\nGet the performatives one of which the terminal message in the dialogue must have.\n\n**Returns**:\n\nthe valid performatives of an terminal message\n\n<a id=\"aea.protocols.dialogue.base.Dialogue.Rules.valid_replies\"></a>\n\n#### valid`_`replies\n\n```python\n@property\ndef valid_replies(\n) -> Dict[Message.Performative, FrozenSet[Message.Performative]]\n```\n\nGet all the valid performatives which are a valid replies to performatives.\n\n**Returns**:\n\nthe full valid reply structure.\n\n<a id=\"aea.protocols.dialogue.base.Dialogue.Rules.get_valid_replies\"></a>\n\n#### get`_`valid`_`replies\n\n```python\ndef get_valid_replies(\n        performative: Message.Performative) -> FrozenSet[Message.Performative]\n```\n\nGiven a `performative`, return the list of performatives which are its valid replies in a dialogue.\n\n**Arguments**:\n\n- `performative`: the performative in a message\n\n**Returns**:\n\nlist of valid performative replies\n\n<a id=\"aea.protocols.dialogue.base.Dialogue.Role\"></a>\n\n## Role Objects\n\n```python\nclass Role(Enum)\n```\n\nThis class defines the agent's role in a dialogue.\n\n<a id=\"aea.protocols.dialogue.base.Dialogue.Role.__str__\"></a>\n\n#### `__`str`__`\n\n```python\ndef __str__() -> str\n```\n\nGet the string representation.\n\n<a id=\"aea.protocols.dialogue.base.Dialogue.EndState\"></a>\n\n## EndState Objects\n\n```python\nclass EndState(Enum)\n```\n\nThis class defines the end states of a dialogue.\n\n<a id=\"aea.protocols.dialogue.base.Dialogue.EndState.__str__\"></a>\n\n#### `__`str`__`\n\n```python\ndef __str__() -> str\n```\n\nGet the string representation.\n\n<a id=\"aea.protocols.dialogue.base.Dialogue.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(dialogue_label: DialogueLabel, message_class: Type[Message],\n             self_address: Address, role: Role) -> None\n```\n\nInitialize a dialogue.\n\n**Arguments**:\n\n- `dialogue_label`: the identifier of the dialogue\n- `message_class`: the message class used\n- `self_address`: the address of the entity for whom this dialogue is maintained\n- `role`: the role of the agent this dialogue is maintained for\n\n<a id=\"aea.protocols.dialogue.base.Dialogue.add_terminal_state_callback\"></a>\n\n#### add`_`terminal`_`state`_`callback\n\n```python\ndef add_terminal_state_callback(fn: Callable[[\"Dialogue\"], None]) -> None\n```\n\nAdd callback to be called on dialogue reach terminal state.\n\n**Arguments**:\n\n- `fn`: callable to be called with one argument: Dialogue\n\n<a id=\"aea.protocols.dialogue.base.Dialogue.__eq__\"></a>\n\n#### `__`eq`__`\n\n```python\ndef __eq__(other: Any) -> bool\n```\n\nCompare two dialogues.\n\n<a id=\"aea.protocols.dialogue.base.Dialogue.json\"></a>\n\n#### json\n\n```python\ndef json() -> dict\n```\n\nGet json representation of the dialogue.\n\n<a id=\"aea.protocols.dialogue.base.Dialogue.from_json\"></a>\n\n#### from`_`json\n\n```python\n@classmethod\ndef from_json(cls, message_class: Type[Message], data: dict) -> \"Dialogue\"\n```\n\nCreate a dialogue instance with all messages from json data.\n\n**Arguments**:\n\n- `message_class`: type of message used with this dialogue\n- `data`: dict with data exported with Dialogue.to_json() method\n\n**Returns**:\n\nDialogue instance\n\n<a id=\"aea.protocols.dialogue.base.Dialogue.dialogue_label\"></a>\n\n#### dialogue`_`label\n\n```python\n@property\ndef dialogue_label() -> DialogueLabel\n```\n\nGet the dialogue label.\n\n**Returns**:\n\nThe dialogue label\n\n<a id=\"aea.protocols.dialogue.base.Dialogue.incomplete_dialogue_label\"></a>\n\n#### incomplete`_`dialogue`_`label\n\n```python\n@property\ndef incomplete_dialogue_label() -> DialogueLabel\n```\n\nGet the dialogue label.\n\n**Returns**:\n\nThe incomplete dialogue label\n\n<a id=\"aea.protocols.dialogue.base.Dialogue.dialogue_labels\"></a>\n\n#### dialogue`_`labels\n\n```python\n@property\ndef dialogue_labels() -> Set[DialogueLabel]\n```\n\nGet the dialogue labels (incomplete and complete, if it exists).\n\n**Returns**:\n\nthe dialogue labels\n\n<a id=\"aea.protocols.dialogue.base.Dialogue.self_address\"></a>\n\n#### self`_`address\n\n```python\n@property\ndef self_address() -> Address\n```\n\nGet the address of the entity for whom this dialogues is maintained.\n\n**Returns**:\n\nthe address of this entity\n\n<a id=\"aea.protocols.dialogue.base.Dialogue.role\"></a>\n\n#### role\n\n```python\n@property\ndef role() -> \"Role\"\n```\n\nGet the agent's role in the dialogue.\n\n**Returns**:\n\nthe agent's role\n\n<a id=\"aea.protocols.dialogue.base.Dialogue.rules\"></a>\n\n#### rules\n\n```python\n@property\ndef rules() -> \"Rules\"\n```\n\nGet the dialogue rules.\n\n**Returns**:\n\nthe rules\n\n<a id=\"aea.protocols.dialogue.base.Dialogue.message_class\"></a>\n\n#### message`_`class\n\n```python\n@property\ndef message_class() -> Type[Message]\n```\n\nGet the message class.\n\n**Returns**:\n\nthe message class\n\n<a id=\"aea.protocols.dialogue.base.Dialogue.is_self_initiated\"></a>\n\n#### is`_`self`_`initiated\n\n```python\n@property\ndef is_self_initiated() -> bool\n```\n\nCheck whether the agent initiated the dialogue.\n\n**Returns**:\n\nTrue if the agent initiated the dialogue, False otherwise\n\n<a id=\"aea.protocols.dialogue.base.Dialogue.last_incoming_message\"></a>\n\n#### last`_`incoming`_`message\n\n```python\n@property\ndef last_incoming_message() -> Optional[Message]\n```\n\nGet the last incoming message.\n\n**Returns**:\n\nthe last incoming message if it exists, None otherwise\n\n<a id=\"aea.protocols.dialogue.base.Dialogue.last_outgoing_message\"></a>\n\n#### last`_`outgoing`_`message\n\n```python\n@property\ndef last_outgoing_message() -> Optional[Message]\n```\n\nGet the last outgoing message.\n\n**Returns**:\n\nthe last outgoing message if it exists, None otherwise\n\n<a id=\"aea.protocols.dialogue.base.Dialogue.last_message\"></a>\n\n#### last`_`message\n\n```python\n@property\ndef last_message() -> Optional[Message]\n```\n\nGet the last message.\n\n**Returns**:\n\nthe last message if it exists, None otherwise\n\n<a id=\"aea.protocols.dialogue.base.Dialogue.is_empty\"></a>\n\n#### is`_`empty\n\n```python\n@property\ndef is_empty() -> bool\n```\n\nCheck whether the dialogue is empty.\n\n**Returns**:\n\nTrue if empty, False otherwise\n\n<a id=\"aea.protocols.dialogue.base.Dialogue.reply\"></a>\n\n#### reply\n\n```python\ndef reply(performative: Message.Performative,\n          target_message: Optional[Message] = None,\n          target: Optional[int] = None,\n          **kwargs: Any) -> Message\n```\n\nReply to the 'target_message' in this dialogue with a message with 'performative', and contents from kwargs.\n\nNote if no target_message is provided, the last message in the dialogue will be replied to.\n\n**Arguments**:\n\n- `target_message`: the message to reply to.\n- `target`: the id of the message to reply to.\n- `performative`: the performative of the reply message.\n- `kwargs`: the content of the reply message.\n\n**Returns**:\n\nthe reply message if it was successfully added as a reply, None otherwise.\n\n<a id=\"aea.protocols.dialogue.base.Dialogue.get_message_by_id\"></a>\n\n#### get`_`message`_`by`_`id\n\n```python\ndef get_message_by_id(message_id: int) -> Optional[Message]\n```\n\nGet message by id, if not presents return None.\n\n<a id=\"aea.protocols.dialogue.base.Dialogue.get_outgoing_next_message_id\"></a>\n\n#### get`_`outgoing`_`next`_`message`_`id\n\n```python\ndef get_outgoing_next_message_id() -> int\n```\n\nGet next outgoing message id.\n\n<a id=\"aea.protocols.dialogue.base.Dialogue.get_incoming_next_message_id\"></a>\n\n#### get`_`incoming`_`next`_`message`_`id\n\n```python\ndef get_incoming_next_message_id() -> int\n```\n\nGet next incoming message id.\n\n<a id=\"aea.protocols.dialogue.base.Dialogue.__str__\"></a>\n\n#### `__`str`__`\n\n```python\ndef __str__() -> str\n```\n\nGet the string representation.\n\n**Returns**:\n\nThe string representation of the dialogue\n\n<a id=\"aea.protocols.dialogue.base.DialogueStats\"></a>\n\n## DialogueStats Objects\n\n```python\nclass DialogueStats()\n```\n\nClass to handle statistics on default dialogues.\n\n<a id=\"aea.protocols.dialogue.base.DialogueStats.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(end_states: FrozenSet[Dialogue.EndState]) -> None\n```\n\nInitialize a StatsManager.\n\n**Arguments**:\n\n- `end_states`: the list of dialogue endstates\n\n<a id=\"aea.protocols.dialogue.base.DialogueStats.self_initiated\"></a>\n\n#### self`_`initiated\n\n```python\n@property\ndef self_initiated() -> Dict[Dialogue.EndState, int]\n```\n\nGet the stats dictionary on self initiated dialogues.\n\n<a id=\"aea.protocols.dialogue.base.DialogueStats.other_initiated\"></a>\n\n#### other`_`initiated\n\n```python\n@property\ndef other_initiated() -> Dict[Dialogue.EndState, int]\n```\n\nGet the stats dictionary on other initiated dialogues.\n\n<a id=\"aea.protocols.dialogue.base.DialogueStats.add_dialogue_endstate\"></a>\n\n#### add`_`dialogue`_`endstate\n\n```python\ndef add_dialogue_endstate(end_state: Dialogue.EndState,\n                          is_self_initiated: bool) -> None\n```\n\nAdd dialogue endstate stats.\n\n**Arguments**:\n\n- `end_state`: the end state of the dialogue\n- `is_self_initiated`: whether the dialogue is initiated by the agent or the opponent\n\n<a id=\"aea.protocols.dialogue.base.find_caller_object\"></a>\n\n#### find`_`caller`_`object\n\n```python\ndef find_caller_object(object_type: Type) -> Any\n```\n\nFind caller object of certain type in the call stack.\n\n<a id=\"aea.protocols.dialogue.base.BasicDialoguesStorage\"></a>\n\n## BasicDialoguesStorage Objects\n\n```python\nclass BasicDialoguesStorage()\n```\n\nDialogues state storage.\n\n<a id=\"aea.protocols.dialogue.base.BasicDialoguesStorage.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(dialogues: \"Dialogues\") -> None\n```\n\nInit dialogues storage.\n\n<a id=\"aea.protocols.dialogue.base.BasicDialoguesStorage.dialogues_in_terminal_state\"></a>\n\n#### dialogues`_`in`_`terminal`_`state\n\n```python\n@property\ndef dialogues_in_terminal_state() -> List[\"Dialogue\"]\n```\n\nGet all dialogues in terminal state.\n\n<a id=\"aea.protocols.dialogue.base.BasicDialoguesStorage.dialogues_in_active_state\"></a>\n\n#### dialogues`_`in`_`active`_`state\n\n```python\n@property\ndef dialogues_in_active_state() -> List[\"Dialogue\"]\n```\n\nGet all dialogues in active state.\n\n<a id=\"aea.protocols.dialogue.base.BasicDialoguesStorage.is_terminal_dialogues_kept\"></a>\n\n#### is`_`terminal`_`dialogues`_`kept\n\n```python\n@property\ndef is_terminal_dialogues_kept() -> bool\n```\n\nReturn True if dialogues should stay after terminal state.\n\n<a id=\"aea.protocols.dialogue.base.BasicDialoguesStorage.dialogue_terminal_state_callback\"></a>\n\n#### dialogue`_`terminal`_`state`_`callback\n\n```python\ndef dialogue_terminal_state_callback(dialogue: \"Dialogue\") -> None\n```\n\nMethod to be called on dialogue terminal state reached.\n\n<a id=\"aea.protocols.dialogue.base.BasicDialoguesStorage.setup\"></a>\n\n#### setup\n\n```python\ndef setup() -> None\n```\n\nSet up dialogue storage.\n\n<a id=\"aea.protocols.dialogue.base.BasicDialoguesStorage.teardown\"></a>\n\n#### teardown\n\n```python\ndef teardown() -> None\n```\n\nTear down dialogue storage.\n\n<a id=\"aea.protocols.dialogue.base.BasicDialoguesStorage.add\"></a>\n\n#### add\n\n```python\ndef add(dialogue: Dialogue) -> None\n```\n\nAdd dialogue to storage.\n\n**Arguments**:\n\n- `dialogue`: dialogue to add.\n\n<a id=\"aea.protocols.dialogue.base.BasicDialoguesStorage.remove\"></a>\n\n#### remove\n\n```python\ndef remove(dialogue_label: DialogueLabel) -> None\n```\n\nRemove dialogue from storage by it's label.\n\n**Arguments**:\n\n- `dialogue_label`: label of the dialogue to remove\n\n<a id=\"aea.protocols.dialogue.base.BasicDialoguesStorage.get\"></a>\n\n#### get\n\n```python\ndef get(dialogue_label: DialogueLabel) -> Optional[Dialogue]\n```\n\nGet dialogue stored by it's label.\n\n**Arguments**:\n\n- `dialogue_label`: label of the dialogue\n\n**Returns**:\n\ndialogue if presents or None\n\n<a id=\"aea.protocols.dialogue.base.BasicDialoguesStorage.get_dialogues_with_counterparty\"></a>\n\n#### get`_`dialogues`_`with`_`counterparty\n\n```python\ndef get_dialogues_with_counterparty(counterparty: Address) -> List[Dialogue]\n```\n\nGet the dialogues by address.\n\n**Arguments**:\n\n- `counterparty`: the counterparty\n\n**Returns**:\n\nThe dialogues with the counterparty.\n\n<a id=\"aea.protocols.dialogue.base.BasicDialoguesStorage.is_in_incomplete\"></a>\n\n#### is`_`in`_`incomplete\n\n```python\ndef is_in_incomplete(dialogue_label: DialogueLabel) -> bool\n```\n\nCheck dialogue label presents in list of incomplete.\n\n<a id=\"aea.protocols.dialogue.base.BasicDialoguesStorage.set_incomplete_dialogue\"></a>\n\n#### set`_`incomplete`_`dialogue\n\n```python\ndef set_incomplete_dialogue(incomplete_dialogue_label: DialogueLabel,\n                            complete_dialogue_label: DialogueLabel) -> None\n```\n\nSet incomplete dialogue label.\n\n<a id=\"aea.protocols.dialogue.base.BasicDialoguesStorage.is_dialogue_present\"></a>\n\n#### is`_`dialogue`_`present\n\n```python\ndef is_dialogue_present(dialogue_label: DialogueLabel) -> bool\n```\n\nCheck dialogue with label specified presents in storage.\n\n<a id=\"aea.protocols.dialogue.base.BasicDialoguesStorage.get_latest_label\"></a>\n\n#### get`_`latest`_`label\n\n```python\ndef get_latest_label(dialogue_label: DialogueLabel) -> DialogueLabel\n```\n\nGet latest label for dialogue.\n\n<a id=\"aea.protocols.dialogue.base.PersistDialoguesStorage\"></a>\n\n## PersistDialoguesStorage Objects\n\n```python\nclass PersistDialoguesStorage(BasicDialoguesStorage)\n```\n\nPersist dialogues storage.\n\nUses generic storage to load/save dialogues data on setup/teardown.\n\n<a id=\"aea.protocols.dialogue.base.PersistDialoguesStorage.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(dialogues: \"Dialogues\") -> None\n```\n\nInit dialogues storage.\n\n<a id=\"aea.protocols.dialogue.base.PersistDialoguesStorage.get_skill_component\"></a>\n\n#### get`_`skill`_`component\n\n```python\n@staticmethod\ndef get_skill_component() -> Optional[SkillComponent]\n```\n\nGet skill component dialogues storage constructed for.\n\n<a id=\"aea.protocols.dialogue.base.PersistDialoguesStorage.setup\"></a>\n\n#### setup\n\n```python\ndef setup() -> None\n```\n\nSet up dialogue storage.\n\n<a id=\"aea.protocols.dialogue.base.PersistDialoguesStorage.teardown\"></a>\n\n#### teardown\n\n```python\ndef teardown() -> None\n```\n\nTear down dialogue storage.\n\n<a id=\"aea.protocols.dialogue.base.PersistDialoguesStorage.remove\"></a>\n\n#### remove\n\n```python\ndef remove(dialogue_label: DialogueLabel) -> None\n```\n\nRemove dialogue from memory and persistent storage.\n\n<a id=\"aea.protocols.dialogue.base.PersistDialoguesStorageWithOffloading\"></a>\n\n## PersistDialoguesStorageWithOffloading Objects\n\n```python\nclass PersistDialoguesStorageWithOffloading(PersistDialoguesStorage)\n```\n\nDialogue Storage with dialogues offloading.\n\n<a id=\"aea.protocols.dialogue.base.PersistDialoguesStorageWithOffloading.dialogue_terminal_state_callback\"></a>\n\n#### dialogue`_`terminal`_`state`_`callback\n\n```python\ndef dialogue_terminal_state_callback(dialogue: \"Dialogue\") -> None\n```\n\nCall on dialogue reaches terminal state.\n\n<a id=\"aea.protocols.dialogue.base.PersistDialoguesStorageWithOffloading.get\"></a>\n\n#### get\n\n```python\ndef get(dialogue_label: DialogueLabel) -> Optional[Dialogue]\n```\n\nTry to get dialogue by label from memory or persists storage.\n\n<a id=\"aea.protocols.dialogue.base.PersistDialoguesStorageWithOffloading.get_dialogues_with_counterparty\"></a>\n\n#### get`_`dialogues`_`with`_`counterparty\n\n```python\ndef get_dialogues_with_counterparty(counterparty: Address) -> List[Dialogue]\n```\n\nGet the dialogues by address.\n\n**Arguments**:\n\n- `counterparty`: the counterparty\n\n**Returns**:\n\nThe dialogues with the counterparty.\n\n<a id=\"aea.protocols.dialogue.base.PersistDialoguesStorageWithOffloading.dialogues_in_terminal_state\"></a>\n\n#### dialogues`_`in`_`terminal`_`state\n\n```python\n@property\ndef dialogues_in_terminal_state() -> List[\"Dialogue\"]\n```\n\nGet all dialogues in terminal state.\n\n<a id=\"aea.protocols.dialogue.base.Dialogues\"></a>\n\n## Dialogues Objects\n\n```python\nclass Dialogues()\n```\n\nThe dialogues class keeps track of all dialogues for an agent.\n\n<a id=\"aea.protocols.dialogue.base.Dialogues.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(self_address: Address,\n             end_states: FrozenSet[Dialogue.EndState],\n             message_class: Type[Message],\n             dialogue_class: Type[Dialogue],\n             role_from_first_message: Callable[[Message, Address],\n                                               Dialogue.Role],\n             keep_terminal_state_dialogues: Optional[bool] = None) -> None\n```\n\nInitialize dialogues.\n\n**Arguments**:\n\n- `self_address`: the address of the entity for whom dialogues are maintained\n- `end_states`: the list of dialogue endstates\n- `message_class`: the message class used\n- `dialogue_class`: the dialogue class used\n- `role_from_first_message`: the callable determining role from first message\n- `keep_terminal_state_dialogues`: specify do dialogues in terminal state should stay or not\n\n<a id=\"aea.protocols.dialogue.base.Dialogues.is_keep_dialogues_in_terminal_state\"></a>\n\n#### is`_`keep`_`dialogues`_`in`_`terminal`_`state\n\n```python\n@property\ndef is_keep_dialogues_in_terminal_state() -> bool\n```\n\nIs required to keep dialogues in terminal state.\n\n<a id=\"aea.protocols.dialogue.base.Dialogues.self_address\"></a>\n\n#### self`_`address\n\n```python\n@property\ndef self_address() -> Address\n```\n\nGet the address of the agent for whom dialogues are maintained.\n\n<a id=\"aea.protocols.dialogue.base.Dialogues.dialogue_stats\"></a>\n\n#### dialogue`_`stats\n\n```python\n@property\ndef dialogue_stats() -> DialogueStats\n```\n\nGet the dialogue statistics.\n\n**Returns**:\n\ndialogue stats object\n\n<a id=\"aea.protocols.dialogue.base.Dialogues.message_class\"></a>\n\n#### message`_`class\n\n```python\n@property\ndef message_class() -> Type[Message]\n```\n\nGet the message class.\n\n**Returns**:\n\nthe message class\n\n<a id=\"aea.protocols.dialogue.base.Dialogues.dialogue_class\"></a>\n\n#### dialogue`_`class\n\n```python\n@property\ndef dialogue_class() -> Type[Dialogue]\n```\n\nGet the dialogue class.\n\n**Returns**:\n\nthe dialogue class\n\n<a id=\"aea.protocols.dialogue.base.Dialogues.get_dialogues_with_counterparty\"></a>\n\n#### get`_`dialogues`_`with`_`counterparty\n\n```python\ndef get_dialogues_with_counterparty(counterparty: Address) -> List[Dialogue]\n```\n\nGet the dialogues by address.\n\n**Arguments**:\n\n- `counterparty`: the counterparty\n\n**Returns**:\n\nThe dialogues with the counterparty.\n\n<a id=\"aea.protocols.dialogue.base.Dialogues.new_self_initiated_dialogue_reference\"></a>\n\n#### new`_`self`_`initiated`_`dialogue`_`reference\n\n```python\n@classmethod\ndef new_self_initiated_dialogue_reference(cls) -> Tuple[str, str]\n```\n\nReturn a dialogue label for a new self initiated dialogue.\n\n**Returns**:\n\nthe next nonce\n\n<a id=\"aea.protocols.dialogue.base.Dialogues.create\"></a>\n\n#### create\n\n```python\ndef create(counterparty: Address, performative: Message.Performative,\n           **kwargs: Any) -> Tuple[Message, Dialogue]\n```\n\nCreate a dialogue with 'counterparty', with an initial message whose performative is 'performative' and contents are from 'kwargs'.\n\n**Arguments**:\n\n- `counterparty`: the counterparty of the dialogue.\n- `performative`: the performative of the initial message.\n- `kwargs`: the content of the initial message.\n\n**Returns**:\n\nthe initial message and the dialogue.\n\n<a id=\"aea.protocols.dialogue.base.Dialogues.create_with_message\"></a>\n\n#### create`_`with`_`message\n\n```python\ndef create_with_message(counterparty: Address,\n                        initial_message: Message) -> Dialogue\n```\n\nCreate a dialogue with 'counterparty', with an initial message provided.\n\n**Arguments**:\n\n- `counterparty`: the counterparty of the dialogue.\n- `initial_message`: the initial_message.\n\n**Returns**:\n\nthe initial message and the dialogue.\n\n<a id=\"aea.protocols.dialogue.base.Dialogues.update\"></a>\n\n#### update\n\n```python\ndef update(message: Message) -> Optional[Dialogue]\n```\n\nUpdate the state of dialogues with a new incoming message.\n\nIf the message is for a new dialogue, a new dialogue is created with 'message' as its first message, and returned.\nIf the message is addressed to an existing dialogue, the dialogue is retrieved, extended with this message and returned.\nIf there are any errors, e.g. the message dialogue reference does not exists or the message is invalid w.r.t. the dialogue, return None.\n\n**Arguments**:\n\n- `message`: a new incoming message\n\n**Returns**:\n\nthe new or existing dialogue the message is intended for, or None in case of any errors.\n\n<a id=\"aea.protocols.dialogue.base.Dialogues.get_dialogue\"></a>\n\n#### get`_`dialogue\n\n```python\ndef get_dialogue(message: Message) -> Optional[Dialogue]\n```\n\nRetrieve the dialogue 'message' belongs to.\n\n**Arguments**:\n\n- `message`: a message\n\n**Returns**:\n\nthe dialogue, or None in case such a dialogue does not exist\n\n<a id=\"aea.protocols.dialogue.base.Dialogues.get_dialogue_from_label\"></a>\n\n#### get`_`dialogue`_`from`_`label\n\n```python\ndef get_dialogue_from_label(\n        dialogue_label: DialogueLabel) -> Optional[Dialogue]\n```\n\nRetrieve a dialogue based on its label.\n\n**Arguments**:\n\n- `dialogue_label`: the dialogue label\n\n**Returns**:\n\nthe dialogue if present\n\n<a id=\"aea.protocols.dialogue.base.Dialogues.setup\"></a>\n\n#### setup\n\n```python\ndef setup() -> None\n```\n\nSet  up.\n\n<a id=\"aea.protocols.dialogue.base.Dialogues.teardown\"></a>\n\n#### teardown\n\n```python\ndef teardown() -> None\n```\n\nTear down.\n\n"
  },
  {
    "path": "docs/api/protocols/generator/base.md",
    "content": ""
  },
  {
    "path": "docs/api/protocols/generator/common.md",
    "content": "<a id=\"aea.protocols.generator.common\"></a>\n\n# aea.protocols.generator.common\n\nThis module contains utility code for generator modules.\n\n<a id=\"aea.protocols.generator.common.is_installed\"></a>\n\n#### is`_`installed\n\n```python\ndef is_installed(programme: str) -> bool\n```\n\nCheck whether a programme is installed on the system.\n\n**Arguments**:\n\n- `programme`: the name of the programme.\n\n**Returns**:\n\nTrue if installed, False otherwise\n\n<a id=\"aea.protocols.generator.common.base_protolint_command\"></a>\n\n#### base`_`protolint`_`command\n\n```python\ndef base_protolint_command() -> str\n```\n\nReturn the base protolint command.\n\n**Returns**:\n\nThe base protolint command\n\n<a id=\"aea.protocols.generator.common.check_prerequisites\"></a>\n\n#### check`_`prerequisites\n\n```python\ndef check_prerequisites() -> None\n```\n\nCheck whether a programme is installed on the system.\n\n<a id=\"aea.protocols.generator.common.get_protoc_version\"></a>\n\n#### get`_`protoc`_`version\n\n```python\ndef get_protoc_version() -> str\n```\n\nGet the protoc version used.\n\n<a id=\"aea.protocols.generator.common.load_protocol_specification\"></a>\n\n#### load`_`protocol`_`specification\n\n```python\ndef load_protocol_specification(\n        specification_path: str) -> ProtocolSpecification\n```\n\nLoad a protocol specification.\n\n**Arguments**:\n\n- `specification_path`: path to the protocol specification yaml file.\n\n**Returns**:\n\nA ProtocolSpecification object\n\n<a id=\"aea.protocols.generator.common.try_run_black_formatting\"></a>\n\n#### try`_`run`_`black`_`formatting\n\n```python\ndef try_run_black_formatting(path_to_protocol_package: str) -> None\n```\n\nRun Black code formatting via subprocess.\n\n**Arguments**:\n\n- `path_to_protocol_package`: a path where formatting should be applied.\n\n<a id=\"aea.protocols.generator.common.try_run_isort_formatting\"></a>\n\n#### try`_`run`_`isort`_`formatting\n\n```python\ndef try_run_isort_formatting(path_to_protocol_package: str) -> None\n```\n\nRun Isort code formatting via subprocess.\n\n**Arguments**:\n\n- `path_to_protocol_package`: a path where formatting should be applied.\n\n<a id=\"aea.protocols.generator.common.try_run_protoc\"></a>\n\n#### try`_`run`_`protoc\n\n```python\ndef try_run_protoc(path_to_generated_protocol_package: str,\n                   name: str,\n                   language: str = PROTOCOL_LANGUAGE_PYTHON) -> None\n```\n\nRun 'protoc' protocol buffer compiler via subprocess.\n\n**Arguments**:\n\n- `path_to_generated_protocol_package`: path to the protocol buffer schema file.\n- `name`: name of the protocol buffer schema file.\n- `language`: the target language in which to compile the protobuf schema file\n\n<a id=\"aea.protocols.generator.common.try_run_protolint\"></a>\n\n#### try`_`run`_`protolint\n\n```python\ndef try_run_protolint(path_to_generated_protocol_package: str,\n                      name: str) -> None\n```\n\nRun 'protolint' linter via subprocess.\n\n**Arguments**:\n\n- `path_to_generated_protocol_package`: path to the protocol buffer schema file.\n- `name`: name of the protocol buffer schema file.\n\n<a id=\"aea.protocols.generator.common.check_protobuf_using_protoc\"></a>\n\n#### check`_`protobuf`_`using`_`protoc\n\n```python\ndef check_protobuf_using_protoc(path_to_generated_protocol_package: str,\n                                name: str) -> Tuple[bool, str]\n```\n\nCheck whether a protocol buffer schema file is valid.\n\nValidation is via trying to compile the schema file. If successfully compiled it is valid, otherwise invalid.\nIf valid, return True and a 'protobuf file is valid' message, otherwise return False and the error thrown by the compiler.\n\n**Arguments**:\n\n- `path_to_generated_protocol_package`: path to the protocol buffer schema file.\n- `name`: name of the protocol buffer schema file.\n\n**Returns**:\n\nBoolean result and an accompanying message\n\n<a id=\"aea.protocols.generator.common.compile_protobuf_using_protoc\"></a>\n\n#### compile`_`protobuf`_`using`_`protoc\n\n```python\ndef compile_protobuf_using_protoc(path_to_generated_protocol_package: str,\n                                  name: str,\n                                  language: str) -> Tuple[bool, str]\n```\n\nCompile a protocol buffer schema file using protoc.\n\nIf successfully compiled, return True and a success message,\notherwise return False and the error thrown by the compiler.\n\n**Arguments**:\n\n- `path_to_generated_protocol_package`: path to the protocol buffer schema file.\n- `name`: name of the protocol buffer schema file.\n- `language`: the target language in which to compile the protobuf schema file\n\n**Returns**:\n\nBoolean result and an accompanying message\n\n<a id=\"aea.protocols.generator.common.apply_protolint\"></a>\n\n#### apply`_`protolint\n\n```python\ndef apply_protolint(path_to_proto_file: str, name: str) -> Tuple[bool, str]\n```\n\nApply protolint linter to a protocol buffer schema file.\n\nIf no output, return True and a success message,\notherwise return False and the output shown by the linter\n(minus the indentation suggestions which are automatically fixed by protolint).\n\n**Arguments**:\n\n- `path_to_proto_file`: path to the protocol buffer schema file.\n- `name`: name of the protocol buffer schema file.\n\n**Returns**:\n\nBoolean result and an accompanying message\n\n"
  },
  {
    "path": "docs/api/protocols/generator/extract_specification.md",
    "content": "<a id=\"aea.protocols.generator.extract_specification\"></a>\n\n# aea.protocols.generator.extract`_`specification\n\nThis module extracts a valid protocol specification into pythonic objects.\n\n<a id=\"aea.protocols.generator.extract_specification.PythonicProtocolSpecification\"></a>\n\n## PythonicProtocolSpecification Objects\n\n```python\nclass PythonicProtocolSpecification()\n```\n\nThis class represents a protocol specification in python.\n\n<a id=\"aea.protocols.generator.extract_specification.PythonicProtocolSpecification.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__() -> None\n```\n\nInstantiate a Pythonic protocol specification.\n\n<a id=\"aea.protocols.generator.extract_specification.extract\"></a>\n\n#### extract\n\n```python\ndef extract(\n    protocol_specification: ProtocolSpecification\n) -> PythonicProtocolSpecification\n```\n\nConverts a protocol specification into a Pythonic protocol specification.\n\n**Arguments**:\n\n- `protocol_specification`: a protocol specification\n\n**Returns**:\n\na Pythonic protocol specification\n\n"
  },
  {
    "path": "docs/api/protocols/generator/validate.md",
    "content": "<a id=\"aea.protocols.generator.validate\"></a>\n\n# aea.protocols.generator.validate\n\nThis module validates a protocol specification.\n\n<a id=\"aea.protocols.generator.validate.validate\"></a>\n\n#### validate\n\n```python\ndef validate(\n        protocol_specification: ProtocolSpecification) -> Tuple[bool, str]\n```\n\nEvaluate whether a protocol specification is valid.\n\n**Arguments**:\n\n- `protocol_specification`: a protocol specification.\n\n**Returns**:\n\nBoolean result, and associated message.\n\n"
  },
  {
    "path": "docs/api/protocols/signing/custom_types.md",
    "content": "<a id=\"packages.fetchai.protocols.signing.custom_types\"></a>\n\n# packages.fetchai.protocols.signing.custom`_`types\n\nThis module contains class representations corresponding to every custom type in the protocol specification.\n\n<a id=\"packages.fetchai.protocols.signing.custom_types.ErrorCode\"></a>\n\n## ErrorCode Objects\n\n```python\nclass ErrorCode(Enum)\n```\n\nThis class represents an instance of ErrorCode.\n\n<a id=\"packages.fetchai.protocols.signing.custom_types.ErrorCode.encode\"></a>\n\n#### encode\n\n```python\n@staticmethod\ndef encode(error_code_protobuf_object: Any,\n           error_code_object: \"ErrorCode\") -> None\n```\n\nEncode an instance of this class into the protocol buffer object.\n\nThe protocol buffer object in the error_code_protobuf_object argument is matched with the instance of this class in the 'error_code_object' argument.\n\n**Arguments**:\n\n- `error_code_protobuf_object`: the protocol buffer object whose type corresponds with this class.\n- `error_code_object`: an instance of this class to be encoded in the protocol buffer object.\n\n<a id=\"packages.fetchai.protocols.signing.custom_types.ErrorCode.decode\"></a>\n\n#### decode\n\n```python\n@classmethod\ndef decode(cls, error_code_protobuf_object: Any) -> \"ErrorCode\"\n```\n\nDecode a protocol buffer object that corresponds with this class into an instance of this class.\n\nA new instance of this class is created that matches the protocol buffer object in the 'error_code_protobuf_object' argument.\n\n**Arguments**:\n\n- `error_code_protobuf_object`: the protocol buffer object whose type corresponds with this class.\n\n**Returns**:\n\nA new instance of this class that matches the protocol buffer object in the 'error_code_protobuf_object' argument.\n\n"
  },
  {
    "path": "docs/api/protocols/signing/dialogues.md",
    "content": "<a id=\"packages.fetchai.protocols.signing.dialogues\"></a>\n\n# packages.fetchai.protocols.signing.dialogues\n\nThis module contains the classes required for signing dialogue management.\n\n- SigningDialogue: The dialogue class maintains state of a dialogue and manages it.\n- SigningDialogues: The dialogues class keeps track of all dialogues.\n\n<a id=\"packages.fetchai.protocols.signing.dialogues.SigningDialogue\"></a>\n\n## SigningDialogue Objects\n\n```python\nclass SigningDialogue(Dialogue)\n```\n\nThe signing dialogue class maintains state of a dialogue and manages it.\n\n<a id=\"packages.fetchai.protocols.signing.dialogues.SigningDialogue.Role\"></a>\n\n## Role Objects\n\n```python\nclass Role(Dialogue.Role)\n```\n\nThis class defines the agent's role in a signing dialogue.\n\n<a id=\"packages.fetchai.protocols.signing.dialogues.SigningDialogue.EndState\"></a>\n\n## EndState Objects\n\n```python\nclass EndState(Dialogue.EndState)\n```\n\nThis class defines the end states of a signing dialogue.\n\n<a id=\"packages.fetchai.protocols.signing.dialogues.SigningDialogue.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(dialogue_label: DialogueLabel,\n             self_address: Address,\n             role: Dialogue.Role,\n             message_class: Type[SigningMessage] = SigningMessage) -> None\n```\n\nInitialize a dialogue.\n\n**Arguments**:\n\n- `dialogue_label`: the identifier of the dialogue\n- `self_address`: the address of the entity for whom this dialogue is maintained\n- `role`: the role of the agent this dialogue is maintained for\n- `message_class`: the message class used\n\n<a id=\"packages.fetchai.protocols.signing.dialogues.SigningDialogues\"></a>\n\n## SigningDialogues Objects\n\n```python\nclass SigningDialogues(Dialogues, ABC)\n```\n\nThis class keeps track of all signing dialogues.\n\n<a id=\"packages.fetchai.protocols.signing.dialogues.SigningDialogues.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(self_address: Address,\n             role_from_first_message: Callable[[Message, Address],\n                                               Dialogue.Role],\n             dialogue_class: Type[SigningDialogue] = SigningDialogue) -> None\n```\n\nInitialize dialogues.\n\n**Arguments**:\n\n- `self_address`: the address of the entity for whom dialogues are maintained\n- `dialogue_class`: the dialogue class used\n- `role_from_first_message`: the callable determining role from first message\n\n"
  },
  {
    "path": "docs/api/protocols/signing/message.md",
    "content": "<a id=\"packages.fetchai.protocols.signing.message\"></a>\n\n# packages.fetchai.protocols.signing.message\n\nThis module contains signing's message definition.\n\n<a id=\"packages.fetchai.protocols.signing.message.SigningMessage\"></a>\n\n## SigningMessage Objects\n\n```python\nclass SigningMessage(Message)\n```\n\nA protocol for communication between skills and decision maker.\n\n<a id=\"packages.fetchai.protocols.signing.message.SigningMessage.Performative\"></a>\n\n## Performative Objects\n\n```python\nclass Performative(Message.Performative)\n```\n\nPerformatives for the signing protocol.\n\n<a id=\"packages.fetchai.protocols.signing.message.SigningMessage.Performative.__str__\"></a>\n\n#### `__`str`__`\n\n```python\ndef __str__() -> str\n```\n\nGet the string representation.\n\n<a id=\"packages.fetchai.protocols.signing.message.SigningMessage.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(performative: Performative,\n             dialogue_reference: Tuple[str, str] = (\"\", \"\"),\n             message_id: int = 1,\n             target: int = 0,\n             **kwargs: Any)\n```\n\nInitialise an instance of SigningMessage.\n\n**Arguments**:\n\n- `message_id`: the message id.\n- `dialogue_reference`: the dialogue reference.\n- `target`: the message target.\n- `performative`: the message performative.\n- `**kwargs`: extra options.\n\n<a id=\"packages.fetchai.protocols.signing.message.SigningMessage.valid_performatives\"></a>\n\n#### valid`_`performatives\n\n```python\n@property\ndef valid_performatives() -> Set[str]\n```\n\nGet valid performatives.\n\n<a id=\"packages.fetchai.protocols.signing.message.SigningMessage.dialogue_reference\"></a>\n\n#### dialogue`_`reference\n\n```python\n@property\ndef dialogue_reference() -> Tuple[str, str]\n```\n\nGet the dialogue_reference of the message.\n\n<a id=\"packages.fetchai.protocols.signing.message.SigningMessage.message_id\"></a>\n\n#### message`_`id\n\n```python\n@property\ndef message_id() -> int\n```\n\nGet the message_id of the message.\n\n<a id=\"packages.fetchai.protocols.signing.message.SigningMessage.performative\"></a>\n\n#### performative\n\n```python\n@property\ndef performative() -> Performative\n```\n\nGet the performative of the message.\n\n<a id=\"packages.fetchai.protocols.signing.message.SigningMessage.target\"></a>\n\n#### target\n\n```python\n@property\ndef target() -> int\n```\n\nGet the target of the message.\n\n<a id=\"packages.fetchai.protocols.signing.message.SigningMessage.error_code\"></a>\n\n#### error`_`code\n\n```python\n@property\ndef error_code() -> CustomErrorCode\n```\n\nGet the 'error_code' content from the message.\n\n<a id=\"packages.fetchai.protocols.signing.message.SigningMessage.raw_message\"></a>\n\n#### raw`_`message\n\n```python\n@property\ndef raw_message() -> CustomRawMessage\n```\n\nGet the 'raw_message' content from the message.\n\n<a id=\"packages.fetchai.protocols.signing.message.SigningMessage.raw_transaction\"></a>\n\n#### raw`_`transaction\n\n```python\n@property\ndef raw_transaction() -> CustomRawTransaction\n```\n\nGet the 'raw_transaction' content from the message.\n\n<a id=\"packages.fetchai.protocols.signing.message.SigningMessage.signed_message\"></a>\n\n#### signed`_`message\n\n```python\n@property\ndef signed_message() -> CustomSignedMessage\n```\n\nGet the 'signed_message' content from the message.\n\n<a id=\"packages.fetchai.protocols.signing.message.SigningMessage.signed_transaction\"></a>\n\n#### signed`_`transaction\n\n```python\n@property\ndef signed_transaction() -> CustomSignedTransaction\n```\n\nGet the 'signed_transaction' content from the message.\n\n<a id=\"packages.fetchai.protocols.signing.message.SigningMessage.terms\"></a>\n\n#### terms\n\n```python\n@property\ndef terms() -> CustomTerms\n```\n\nGet the 'terms' content from the message.\n\n"
  },
  {
    "path": "docs/api/protocols/signing/serialization.md",
    "content": "<a id=\"packages.fetchai.protocols.signing.serialization\"></a>\n\n# packages.fetchai.protocols.signing.serialization\n\nSerialization module for signing protocol.\n\n<a id=\"packages.fetchai.protocols.signing.serialization.SigningSerializer\"></a>\n\n## SigningSerializer Objects\n\n```python\nclass SigningSerializer(Serializer)\n```\n\nSerialization for the 'signing' protocol.\n\n<a id=\"packages.fetchai.protocols.signing.serialization.SigningSerializer.encode\"></a>\n\n#### encode\n\n```python\n@staticmethod\ndef encode(msg: Message) -> bytes\n```\n\nEncode a 'Signing' message into bytes.\n\n**Arguments**:\n\n- `msg`: the message object.\n\n**Returns**:\n\nthe bytes.\n\n<a id=\"packages.fetchai.protocols.signing.serialization.SigningSerializer.decode\"></a>\n\n#### decode\n\n```python\n@staticmethod\ndef decode(obj: bytes) -> Message\n```\n\nDecode bytes into a 'Signing' message.\n\n**Arguments**:\n\n- `obj`: the bytes object.\n\n**Returns**:\n\nthe 'Signing' message.\n\n"
  },
  {
    "path": "docs/api/protocols/state_update/dialogues.md",
    "content": "<a id=\"packages.fetchai.protocols.state_update.dialogues\"></a>\n\n# packages.fetchai.protocols.state`_`update.dialogues\n\nThis module contains the classes required for state_update dialogue management.\n\n- StateUpdateDialogue: The dialogue class maintains state of a dialogue and manages it.\n- StateUpdateDialogues: The dialogues class keeps track of all dialogues.\n\n<a id=\"packages.fetchai.protocols.state_update.dialogues.StateUpdateDialogue\"></a>\n\n## StateUpdateDialogue Objects\n\n```python\nclass StateUpdateDialogue(Dialogue)\n```\n\nThe state_update dialogue class maintains state of a dialogue and manages it.\n\n<a id=\"packages.fetchai.protocols.state_update.dialogues.StateUpdateDialogue.Role\"></a>\n\n## Role Objects\n\n```python\nclass Role(Dialogue.Role)\n```\n\nThis class defines the agent's role in a state_update dialogue.\n\n<a id=\"packages.fetchai.protocols.state_update.dialogues.StateUpdateDialogue.EndState\"></a>\n\n## EndState Objects\n\n```python\nclass EndState(Dialogue.EndState)\n```\n\nThis class defines the end states of a state_update dialogue.\n\n<a id=\"packages.fetchai.protocols.state_update.dialogues.StateUpdateDialogue.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(\n        dialogue_label: DialogueLabel,\n        self_address: Address,\n        role: Dialogue.Role,\n        message_class: Type[StateUpdateMessage] = StateUpdateMessage) -> None\n```\n\nInitialize a dialogue.\n\n**Arguments**:\n\n- `dialogue_label`: the identifier of the dialogue\n- `self_address`: the address of the entity for whom this dialogue is maintained\n- `role`: the role of the agent this dialogue is maintained for\n- `message_class`: the message class used\n\n<a id=\"packages.fetchai.protocols.state_update.dialogues.StateUpdateDialogues\"></a>\n\n## StateUpdateDialogues Objects\n\n```python\nclass StateUpdateDialogues(Dialogues, ABC)\n```\n\nThis class keeps track of all state_update dialogues.\n\n<a id=\"packages.fetchai.protocols.state_update.dialogues.StateUpdateDialogues.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(\n        self_address: Address,\n        role_from_first_message: Callable[[Message, Address], Dialogue.Role],\n        dialogue_class: Type[StateUpdateDialogue] = StateUpdateDialogue\n) -> None\n```\n\nInitialize dialogues.\n\n**Arguments**:\n\n- `self_address`: the address of the entity for whom dialogues are maintained\n- `dialogue_class`: the dialogue class used\n- `role_from_first_message`: the callable determining role from first message\n\n"
  },
  {
    "path": "docs/api/protocols/state_update/message.md",
    "content": "<a id=\"packages.fetchai.protocols.state_update.message\"></a>\n\n# packages.fetchai.protocols.state`_`update.message\n\nThis module contains state_update's message definition.\n\n<a id=\"packages.fetchai.protocols.state_update.message.StateUpdateMessage\"></a>\n\n## StateUpdateMessage Objects\n\n```python\nclass StateUpdateMessage(Message)\n```\n\nA protocol for state updates to the decision maker state.\n\n<a id=\"packages.fetchai.protocols.state_update.message.StateUpdateMessage.Performative\"></a>\n\n## Performative Objects\n\n```python\nclass Performative(Message.Performative)\n```\n\nPerformatives for the state_update protocol.\n\n<a id=\"packages.fetchai.protocols.state_update.message.StateUpdateMessage.Performative.__str__\"></a>\n\n#### `__`str`__`\n\n```python\ndef __str__() -> str\n```\n\nGet the string representation.\n\n<a id=\"packages.fetchai.protocols.state_update.message.StateUpdateMessage.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(performative: Performative,\n             dialogue_reference: Tuple[str, str] = (\"\", \"\"),\n             message_id: int = 1,\n             target: int = 0,\n             **kwargs: Any)\n```\n\nInitialise an instance of StateUpdateMessage.\n\n**Arguments**:\n\n- `message_id`: the message id.\n- `dialogue_reference`: the dialogue reference.\n- `target`: the message target.\n- `performative`: the message performative.\n- `**kwargs`: extra options.\n\n<a id=\"packages.fetchai.protocols.state_update.message.StateUpdateMessage.valid_performatives\"></a>\n\n#### valid`_`performatives\n\n```python\n@property\ndef valid_performatives() -> Set[str]\n```\n\nGet valid performatives.\n\n<a id=\"packages.fetchai.protocols.state_update.message.StateUpdateMessage.dialogue_reference\"></a>\n\n#### dialogue`_`reference\n\n```python\n@property\ndef dialogue_reference() -> Tuple[str, str]\n```\n\nGet the dialogue_reference of the message.\n\n<a id=\"packages.fetchai.protocols.state_update.message.StateUpdateMessage.message_id\"></a>\n\n#### message`_`id\n\n```python\n@property\ndef message_id() -> int\n```\n\nGet the message_id of the message.\n\n<a id=\"packages.fetchai.protocols.state_update.message.StateUpdateMessage.performative\"></a>\n\n#### performative\n\n```python\n@property\ndef performative() -> Performative\n```\n\nGet the performative of the message.\n\n<a id=\"packages.fetchai.protocols.state_update.message.StateUpdateMessage.target\"></a>\n\n#### target\n\n```python\n@property\ndef target() -> int\n```\n\nGet the target of the message.\n\n<a id=\"packages.fetchai.protocols.state_update.message.StateUpdateMessage.amount_by_currency_id\"></a>\n\n#### amount`_`by`_`currency`_`id\n\n```python\n@property\ndef amount_by_currency_id() -> Dict[str, int]\n```\n\nGet the 'amount_by_currency_id' content from the message.\n\n<a id=\"packages.fetchai.protocols.state_update.message.StateUpdateMessage.exchange_params_by_currency_id\"></a>\n\n#### exchange`_`params`_`by`_`currency`_`id\n\n```python\n@property\ndef exchange_params_by_currency_id() -> Dict[str, float]\n```\n\nGet the 'exchange_params_by_currency_id' content from the message.\n\n<a id=\"packages.fetchai.protocols.state_update.message.StateUpdateMessage.quantities_by_good_id\"></a>\n\n#### quantities`_`by`_`good`_`id\n\n```python\n@property\ndef quantities_by_good_id() -> Dict[str, int]\n```\n\nGet the 'quantities_by_good_id' content from the message.\n\n<a id=\"packages.fetchai.protocols.state_update.message.StateUpdateMessage.utility_params_by_good_id\"></a>\n\n#### utility`_`params`_`by`_`good`_`id\n\n```python\n@property\ndef utility_params_by_good_id() -> Dict[str, float]\n```\n\nGet the 'utility_params_by_good_id' content from the message.\n\n"
  },
  {
    "path": "docs/api/protocols/state_update/serialization.md",
    "content": "<a id=\"packages.fetchai.protocols.state_update.serialization\"></a>\n\n# packages.fetchai.protocols.state`_`update.serialization\n\nSerialization module for state_update protocol.\n\n<a id=\"packages.fetchai.protocols.state_update.serialization.StateUpdateSerializer\"></a>\n\n## StateUpdateSerializer Objects\n\n```python\nclass StateUpdateSerializer(Serializer)\n```\n\nSerialization for the 'state_update' protocol.\n\n<a id=\"packages.fetchai.protocols.state_update.serialization.StateUpdateSerializer.encode\"></a>\n\n#### encode\n\n```python\n@staticmethod\ndef encode(msg: Message) -> bytes\n```\n\nEncode a 'StateUpdate' message into bytes.\n\n**Arguments**:\n\n- `msg`: the message object.\n\n**Returns**:\n\nthe bytes.\n\n<a id=\"packages.fetchai.protocols.state_update.serialization.StateUpdateSerializer.decode\"></a>\n\n#### decode\n\n```python\n@staticmethod\ndef decode(obj: bytes) -> Message\n```\n\nDecode bytes into a 'StateUpdate' message.\n\n**Arguments**:\n\n- `obj`: the bytes object.\n\n**Returns**:\n\nthe 'StateUpdate' message.\n\n"
  },
  {
    "path": "docs/api/registries/base.md",
    "content": "<a id=\"aea.registries.base\"></a>\n\n# aea.registries.base\n\nThis module contains registries.\n\n<a id=\"aea.registries.base.Registry\"></a>\n\n## Registry Objects\n\n```python\nclass Registry(Generic[ItemId, Item], WithLogger, ABC)\n```\n\nThis class implements an abstract registry.\n\n<a id=\"aea.registries.base.Registry.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(agent_name: str = \"standalone\") -> None\n```\n\nInitialize the registry.\n\n**Arguments**:\n\n- `agent_name`: the name of the agent\n\n<a id=\"aea.registries.base.Registry.register\"></a>\n\n#### register\n\n```python\n@abstractmethod\ndef register(item_id: ItemId,\n             item: Item,\n             is_dynamically_added: bool = False) -> None\n```\n\nRegister an item.\n\n**Arguments**:\n\n- `item_id`: the public id of the item.\n- `item`: the item.\n- `is_dynamically_added`: whether or not the item is dynamically added.\n\n**Raises**:\n\n- `None`: ValueError if an item is already registered with that item id.\n\n**Returns**:\n\nNone\n\n<a id=\"aea.registries.base.Registry.unregister\"></a>\n\n#### unregister\n\n```python\n@abstractmethod\ndef unregister(item_id: ItemId) -> Optional[Item]\n```\n\nUnregister an item.\n\n**Arguments**:\n\n- `item_id`: the public id of the item.\n\n**Raises**:\n\n- `None`: ValueError if no item registered with that item id.\n\n**Returns**:\n\nthe item\n\n<a id=\"aea.registries.base.Registry.fetch\"></a>\n\n#### fetch\n\n```python\n@abstractmethod\ndef fetch(item_id: ItemId) -> Optional[Item]\n```\n\nFetch an item.\n\n**Arguments**:\n\n- `item_id`: the public id of the item.\n\n**Returns**:\n\nthe Item\n\n<a id=\"aea.registries.base.Registry.fetch_all\"></a>\n\n#### fetch`_`all\n\n```python\n@abstractmethod\ndef fetch_all() -> List[Item]\n```\n\nFetch all the items.\n\n**Returns**:\n\nthe list of items.\n\n<a id=\"aea.registries.base.Registry.ids\"></a>\n\n#### ids\n\n```python\n@abstractmethod\ndef ids() -> Set[ItemId]\n```\n\nReturn the set of all the used item ids.\n\n**Returns**:\n\nthe set of item ids.\n\n<a id=\"aea.registries.base.Registry.setup\"></a>\n\n#### setup\n\n```python\n@abstractmethod\ndef setup() -> None\n```\n\nSet up registry.\n\n**Returns**:\n\nNone\n\n<a id=\"aea.registries.base.Registry.teardown\"></a>\n\n#### teardown\n\n```python\n@abstractmethod\ndef teardown() -> None\n```\n\nTeardown the registry.\n\n**Returns**:\n\nNone\n\n<a id=\"aea.registries.base.PublicIdRegistry\"></a>\n\n## PublicIdRegistry Objects\n\n```python\nclass PublicIdRegistry(Generic[Item], Registry[PublicId, Item])\n```\n\nThis class implement a registry whose keys are public ids.\n\nIn particular, it is able to handle the case when the public id\npoints to the 'latest' version of a package.\n\n<a id=\"aea.registries.base.PublicIdRegistry.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__() -> None\n```\n\nInitialize the registry.\n\n<a id=\"aea.registries.base.PublicIdRegistry.register\"></a>\n\n#### register\n\n```python\ndef register(public_id: PublicId,\n             item: Item,\n             is_dynamically_added: bool = False) -> None\n```\n\nRegister an item.\n\n<a id=\"aea.registries.base.PublicIdRegistry.unregister\"></a>\n\n#### unregister\n\n```python\ndef unregister(public_id: PublicId) -> Item\n```\n\nUnregister an item.\n\n<a id=\"aea.registries.base.PublicIdRegistry.fetch\"></a>\n\n#### fetch\n\n```python\ndef fetch(public_id: PublicId) -> Optional[Item]\n```\n\nFetch an item associated with a public id.\n\n**Arguments**:\n\n- `public_id`: the public id.\n\n**Returns**:\n\nan item, or None if the key is not present.\n\n<a id=\"aea.registries.base.PublicIdRegistry.fetch_all\"></a>\n\n#### fetch`_`all\n\n```python\ndef fetch_all() -> List[Item]\n```\n\nFetch all the items.\n\n<a id=\"aea.registries.base.PublicIdRegistry.ids\"></a>\n\n#### ids\n\n```python\ndef ids() -> Set[PublicId]\n```\n\nGet all the item ids.\n\n<a id=\"aea.registries.base.PublicIdRegistry.setup\"></a>\n\n#### setup\n\n```python\ndef setup() -> None\n```\n\nSet up the items.\n\n<a id=\"aea.registries.base.PublicIdRegistry.teardown\"></a>\n\n#### teardown\n\n```python\ndef teardown() -> None\n```\n\nTear down the items.\n\n<a id=\"aea.registries.base.AgentComponentRegistry\"></a>\n\n## AgentComponentRegistry Objects\n\n```python\nclass AgentComponentRegistry(Registry[ComponentId, Component])\n```\n\nThis class implements a simple dictionary-based registry for agent components.\n\n<a id=\"aea.registries.base.AgentComponentRegistry.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(**kwargs: Any) -> None\n```\n\nInstantiate the registry.\n\n**Arguments**:\n\n- `kwargs`: kwargs\n\n<a id=\"aea.registries.base.AgentComponentRegistry.register\"></a>\n\n#### register\n\n```python\ndef register(component_id: ComponentId,\n             component: Component,\n             is_dynamically_added: bool = False) -> None\n```\n\nRegister a component.\n\n**Arguments**:\n\n- `component_id`: the id of the component.\n- `component`: the component object.\n- `is_dynamically_added`: whether or not the item is dynamically added.\n\n<a id=\"aea.registries.base.AgentComponentRegistry.unregister\"></a>\n\n#### unregister\n\n```python\ndef unregister(component_id: ComponentId) -> Optional[Component]\n```\n\nUnregister a component.\n\n**Arguments**:\n\n- `component_id`: the ComponentId\n\n**Returns**:\n\nthe item\n\n<a id=\"aea.registries.base.AgentComponentRegistry.fetch\"></a>\n\n#### fetch\n\n```python\ndef fetch(component_id: ComponentId) -> Optional[Component]\n```\n\nFetch the component by id.\n\n**Arguments**:\n\n- `component_id`: the contract id\n\n**Returns**:\n\nthe component or None if the component is not registered\n\n<a id=\"aea.registries.base.AgentComponentRegistry.fetch_all\"></a>\n\n#### fetch`_`all\n\n```python\ndef fetch_all() -> List[Component]\n```\n\nFetch all the components.\n\n**Returns**:\n\nthe list of registered components.\n\n<a id=\"aea.registries.base.AgentComponentRegistry.fetch_by_type\"></a>\n\n#### fetch`_`by`_`type\n\n```python\ndef fetch_by_type(component_type: ComponentType) -> List[Component]\n```\n\nFetch all the components by a given type..\n\n**Arguments**:\n\n- `component_type`: a component type\n\n**Returns**:\n\nthe list of registered components of a given type.\n\n<a id=\"aea.registries.base.AgentComponentRegistry.ids\"></a>\n\n#### ids\n\n```python\ndef ids() -> Set[ComponentId]\n```\n\nGet the item ids.\n\n<a id=\"aea.registries.base.AgentComponentRegistry.setup\"></a>\n\n#### setup\n\n```python\ndef setup() -> None\n```\n\nSet up the registry.\n\n<a id=\"aea.registries.base.AgentComponentRegistry.teardown\"></a>\n\n#### teardown\n\n```python\ndef teardown() -> None\n```\n\nTeardown the registry.\n\n<a id=\"aea.registries.base.ComponentRegistry\"></a>\n\n## ComponentRegistry Objects\n\n```python\nclass ComponentRegistry(Registry[Tuple[PublicId, str], SkillComponentType],\n                        Generic[SkillComponentType])\n```\n\nThis class implements a generic registry for skill components.\n\n<a id=\"aea.registries.base.ComponentRegistry.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(**kwargs: Any) -> None\n```\n\nInstantiate the registry.\n\n**Arguments**:\n\n- `kwargs`: kwargs\n\n<a id=\"aea.registries.base.ComponentRegistry.register\"></a>\n\n#### register\n\n```python\ndef register(item_id: Tuple[PublicId, str],\n             item: SkillComponentType,\n             is_dynamically_added: bool = False) -> None\n```\n\nRegister a item.\n\n**Arguments**:\n\n- `item_id`: a pair (skill id, item name).\n- `item`: the item to register.\n- `is_dynamically_added`: whether or not the item is dynamically added.\n\n**Raises**:\n\n- `None`: ValueError if an item is already registered with that item id.\n\n<a id=\"aea.registries.base.ComponentRegistry.unregister\"></a>\n\n#### unregister\n\n```python\ndef unregister(item_id: Tuple[PublicId, str]) -> Optional[SkillComponentType]\n```\n\nUnregister a item.\n\n**Arguments**:\n\n- `item_id`: a pair (skill id, item name).\n\n**Raises**:\n\n- `None`: ValueError if no item registered with that item id.\n\n**Returns**:\n\nskill component\n\n<a id=\"aea.registries.base.ComponentRegistry.fetch\"></a>\n\n#### fetch\n\n```python\ndef fetch(item_id: Tuple[PublicId, str]) -> Optional[SkillComponentType]\n```\n\nFetch an item.\n\n**Arguments**:\n\n- `item_id`: the public id of the item.\n\n**Returns**:\n\nthe Item\n\n<a id=\"aea.registries.base.ComponentRegistry.fetch_by_skill\"></a>\n\n#### fetch`_`by`_`skill\n\n```python\ndef fetch_by_skill(skill_id: PublicId) -> List[SkillComponentType]\n```\n\nFetch all the items of a given skill.\n\n<a id=\"aea.registries.base.ComponentRegistry.fetch_all\"></a>\n\n#### fetch`_`all\n\n```python\ndef fetch_all() -> List[SkillComponentType]\n```\n\nFetch all the items.\n\n<a id=\"aea.registries.base.ComponentRegistry.unregister_by_skill\"></a>\n\n#### unregister`_`by`_`skill\n\n```python\ndef unregister_by_skill(skill_id: PublicId) -> None\n```\n\nUnregister all the components by skill.\n\n<a id=\"aea.registries.base.ComponentRegistry.ids\"></a>\n\n#### ids\n\n```python\ndef ids() -> Set[Tuple[PublicId, str]]\n```\n\nGet the item ids.\n\n<a id=\"aea.registries.base.ComponentRegistry.setup\"></a>\n\n#### setup\n\n```python\ndef setup() -> None\n```\n\nSet up the items in the registry.\n\n<a id=\"aea.registries.base.ComponentRegistry.teardown\"></a>\n\n#### teardown\n\n```python\ndef teardown() -> None\n```\n\nTeardown the registry.\n\n<a id=\"aea.registries.base.HandlerRegistry\"></a>\n\n## HandlerRegistry Objects\n\n```python\nclass HandlerRegistry(ComponentRegistry[Handler])\n```\n\nThis class implements the handlers registry.\n\n<a id=\"aea.registries.base.HandlerRegistry.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(**kwargs: Any) -> None\n```\n\nInstantiate the registry.\n\n**Arguments**:\n\n- `kwargs`: kwargs\n\n<a id=\"aea.registries.base.HandlerRegistry.register\"></a>\n\n#### register\n\n```python\ndef register(item_id: Tuple[PublicId, str],\n             item: Handler,\n             is_dynamically_added: bool = False) -> None\n```\n\nRegister a handler.\n\n**Arguments**:\n\n- `item_id`: the item id.\n- `item`: the handler.\n- `is_dynamically_added`: whether or not the item is dynamically added.\n\n**Raises**:\n\n- `ValueError`: if the protocol is None, or an item with pair (skill_id, protocol_id_ already exists.\n\n<a id=\"aea.registries.base.HandlerRegistry.unregister\"></a>\n\n#### unregister\n\n```python\ndef unregister(item_id: Tuple[PublicId, str]) -> Handler\n```\n\nUnregister a item.\n\n**Arguments**:\n\n- `item_id`: a pair (skill id, item name).\n\n**Raises**:\n\n- `None`: ValueError if no item is registered with that item id.\n\n**Returns**:\n\nthe unregistered handler\n\n<a id=\"aea.registries.base.HandlerRegistry.unregister_by_skill\"></a>\n\n#### unregister`_`by`_`skill\n\n```python\ndef unregister_by_skill(skill_id: PublicId) -> None\n```\n\nUnregister all the components by skill.\n\n<a id=\"aea.registries.base.HandlerRegistry.fetch_by_protocol\"></a>\n\n#### fetch`_`by`_`protocol\n\n```python\ndef fetch_by_protocol(protocol_id: PublicId) -> List[Handler]\n```\n\nFetch the handler by the pair protocol id and skill id.\n\n**Arguments**:\n\n- `protocol_id`: the protocol id\n\n**Returns**:\n\nthe handlers registered for the protocol_id and skill_id\n\n<a id=\"aea.registries.base.HandlerRegistry.fetch_by_protocol_and_skill\"></a>\n\n#### fetch`_`by`_`protocol`_`and`_`skill\n\n```python\ndef fetch_by_protocol_and_skill(protocol_id: PublicId,\n                                skill_id: PublicId) -> Optional[Handler]\n```\n\nFetch the handler by the pair protocol id and skill id.\n\n**Arguments**:\n\n- `protocol_id`: the protocol id\n- `skill_id`: the skill id.\n\n**Returns**:\n\nthe handlers registered for the protocol_id and skill_id\n\n"
  },
  {
    "path": "docs/api/registries/filter.md",
    "content": "<a id=\"aea.registries.filter\"></a>\n\n# aea.registries.filter\n\nThis module contains registries.\n\n<a id=\"aea.registries.filter.Filter\"></a>\n\n## Filter Objects\n\n```python\nclass Filter(WithLogger)\n```\n\nThis class implements the filter of an AEA.\n\n<a id=\"aea.registries.filter.Filter.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(resources: Resources,\n             decision_maker_out_queue: AsyncFriendlyQueue) -> None\n```\n\nInstantiate the filter.\n\n**Arguments**:\n\n- `resources`: the resources\n- `decision_maker_out_queue`: the decision maker queue\n\n<a id=\"aea.registries.filter.Filter.resources\"></a>\n\n#### resources\n\n```python\n@property\ndef resources() -> Resources\n```\n\nGet resources.\n\n<a id=\"aea.registries.filter.Filter.decision_maker_out_queue\"></a>\n\n#### decision`_`maker`_`out`_`queue\n\n```python\n@property\ndef decision_maker_out_queue() -> AsyncFriendlyQueue\n```\n\nGet decision maker (out) queue.\n\n<a id=\"aea.registries.filter.Filter.get_active_handlers\"></a>\n\n#### get`_`active`_`handlers\n\n```python\ndef get_active_handlers(protocol_id: PublicId,\n                        skill_id: Optional[PublicId] = None) -> List[Handler]\n```\n\nGet active handlers based on protocol id and optional skill id.\n\n**Arguments**:\n\n- `protocol_id`: the protocol id\n- `skill_id`: the skill id\n\n**Returns**:\n\nthe list of handlers currently active\n\n<a id=\"aea.registries.filter.Filter.get_active_behaviours\"></a>\n\n#### get`_`active`_`behaviours\n\n```python\ndef get_active_behaviours() -> List[Behaviour]\n```\n\nGet the active behaviours.\n\n**Returns**:\n\nthe list of behaviours currently active\n\n<a id=\"aea.registries.filter.Filter.handle_new_handlers_and_behaviours\"></a>\n\n#### handle`_`new`_`handlers`_`and`_`behaviours\n\n```python\ndef handle_new_handlers_and_behaviours() -> None\n```\n\nHandle the messages from the decision maker.\n\n<a id=\"aea.registries.filter.Filter.get_internal_message\"></a>\n\n#### get`_`internal`_`message\n\n```python\nasync def get_internal_message() -> Optional[Message]\n```\n\nGet a message from decision_maker_out_queue.\n\n<a id=\"aea.registries.filter.Filter.handle_internal_message\"></a>\n\n#### handle`_`internal`_`message\n\n```python\ndef handle_internal_message(internal_message: Optional[Message]) -> None\n```\n\nHandle internal message.\n\n"
  },
  {
    "path": "docs/api/registries/resources.md",
    "content": "<a id=\"aea.registries.resources\"></a>\n\n# aea.registries.resources\n\nThis module contains the resources class.\n\n<a id=\"aea.registries.resources.Resources\"></a>\n\n## Resources Objects\n\n```python\nclass Resources()\n```\n\nThis class implements the object that holds the resources of an AEA.\n\n<a id=\"aea.registries.resources.Resources.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(agent_name: str = \"standalone\") -> None\n```\n\nInstantiate the resources.\n\n**Arguments**:\n\n- `agent_name`: the name of the agent\n\n<a id=\"aea.registries.resources.Resources.agent_name\"></a>\n\n#### agent`_`name\n\n```python\n@property\ndef agent_name() -> str\n```\n\nGet the agent name.\n\n<a id=\"aea.registries.resources.Resources.component_registry\"></a>\n\n#### component`_`registry\n\n```python\n@property\ndef component_registry() -> AgentComponentRegistry\n```\n\nGet the agent component registry.\n\n<a id=\"aea.registries.resources.Resources.behaviour_registry\"></a>\n\n#### behaviour`_`registry\n\n```python\n@property\ndef behaviour_registry() -> ComponentRegistry[Behaviour]\n```\n\nGet the behaviour registry.\n\n<a id=\"aea.registries.resources.Resources.handler_registry\"></a>\n\n#### handler`_`registry\n\n```python\n@property\ndef handler_registry() -> HandlerRegistry\n```\n\nGet the handler registry.\n\n<a id=\"aea.registries.resources.Resources.model_registry\"></a>\n\n#### model`_`registry\n\n```python\n@property\ndef model_registry() -> ComponentRegistry[Model]\n```\n\nGet the model registry.\n\n<a id=\"aea.registries.resources.Resources.add_component\"></a>\n\n#### add`_`component\n\n```python\ndef add_component(component: Component) -> None\n```\n\nAdd a component to resources.\n\n<a id=\"aea.registries.resources.Resources.add_protocol\"></a>\n\n#### add`_`protocol\n\n```python\ndef add_protocol(protocol: Protocol) -> None\n```\n\nAdd a protocol to the set of resources.\n\n**Arguments**:\n\n- `protocol`: a protocol\n\n<a id=\"aea.registries.resources.Resources.get_protocol\"></a>\n\n#### get`_`protocol\n\n```python\ndef get_protocol(protocol_id: PublicId) -> Optional[Protocol]\n```\n\nGet protocol for given protocol id.\n\n**Arguments**:\n\n- `protocol_id`: the protocol id\n\n**Returns**:\n\na matching protocol, if present, else None\n\n<a id=\"aea.registries.resources.Resources.get_protocol_by_specification_id\"></a>\n\n#### get`_`protocol`_`by`_`specification`_`id\n\n```python\ndef get_protocol_by_specification_id(\n        protocol_specification_id: PublicId) -> Optional[Protocol]\n```\n\nGet protocol for given protocol_specification_id.\n\n**Arguments**:\n\n- `protocol_specification_id`: the protocol id\n\n**Returns**:\n\na matching protocol, if present, else None\n\n<a id=\"aea.registries.resources.Resources.get_all_protocols\"></a>\n\n#### get`_`all`_`protocols\n\n```python\ndef get_all_protocols() -> List[Protocol]\n```\n\nGet the list of all the protocols.\n\n**Returns**:\n\nthe list of protocols.\n\n<a id=\"aea.registries.resources.Resources.remove_protocol\"></a>\n\n#### remove`_`protocol\n\n```python\ndef remove_protocol(protocol_id: PublicId) -> None\n```\n\nRemove a protocol from the set of resources.\n\n**Arguments**:\n\n- `protocol_id`: the protocol id for the protocol to be removed.\n\n<a id=\"aea.registries.resources.Resources.add_contract\"></a>\n\n#### add`_`contract\n\n```python\ndef add_contract(contract: Contract) -> None\n```\n\nAdd a contract to the set of resources.\n\n**Arguments**:\n\n- `contract`: a contract\n\n<a id=\"aea.registries.resources.Resources.get_contract\"></a>\n\n#### get`_`contract\n\n```python\ndef get_contract(contract_id: PublicId) -> Optional[Contract]\n```\n\nGet contract for given contract id.\n\n**Arguments**:\n\n- `contract_id`: the contract id\n\n**Returns**:\n\na matching contract, if present, else None\n\n<a id=\"aea.registries.resources.Resources.get_all_contracts\"></a>\n\n#### get`_`all`_`contracts\n\n```python\ndef get_all_contracts() -> List[Contract]\n```\n\nGet the list of all the contracts.\n\n**Returns**:\n\nthe list of contracts.\n\n<a id=\"aea.registries.resources.Resources.remove_contract\"></a>\n\n#### remove`_`contract\n\n```python\ndef remove_contract(contract_id: PublicId) -> None\n```\n\nRemove a contract from the set of resources.\n\n**Arguments**:\n\n- `contract_id`: the contract id for the contract to be removed.\n\n<a id=\"aea.registries.resources.Resources.add_connection\"></a>\n\n#### add`_`connection\n\n```python\ndef add_connection(connection: Connection) -> None\n```\n\nAdd a connection to the set of resources.\n\n**Arguments**:\n\n- `connection`: a connection\n\n<a id=\"aea.registries.resources.Resources.get_connection\"></a>\n\n#### get`_`connection\n\n```python\ndef get_connection(connection_id: PublicId) -> Optional[Connection]\n```\n\nGet connection for given connection id.\n\n**Arguments**:\n\n- `connection_id`: the connection id\n\n**Returns**:\n\na matching connection, if present, else None\n\n<a id=\"aea.registries.resources.Resources.get_all_connections\"></a>\n\n#### get`_`all`_`connections\n\n```python\ndef get_all_connections() -> List[Connection]\n```\n\nGet the list of all the connections.\n\n**Returns**:\n\nthe list of connections.\n\n<a id=\"aea.registries.resources.Resources.remove_connection\"></a>\n\n#### remove`_`connection\n\n```python\ndef remove_connection(connection_id: PublicId) -> None\n```\n\nRemove a connection from the set of resources.\n\n**Arguments**:\n\n- `connection_id`: the connection id for the connection to be removed.\n\n<a id=\"aea.registries.resources.Resources.add_skill\"></a>\n\n#### add`_`skill\n\n```python\ndef add_skill(skill: Skill) -> None\n```\n\nAdd a skill to the set of resources.\n\n**Arguments**:\n\n- `skill`: a skill\n\n<a id=\"aea.registries.resources.Resources.get_skill\"></a>\n\n#### get`_`skill\n\n```python\ndef get_skill(skill_id: PublicId) -> Optional[Skill]\n```\n\nGet the skill for a given skill id.\n\n**Arguments**:\n\n- `skill_id`: the skill id\n\n**Returns**:\n\na matching skill, if present, else None\n\n<a id=\"aea.registries.resources.Resources.get_all_skills\"></a>\n\n#### get`_`all`_`skills\n\n```python\ndef get_all_skills() -> List[Skill]\n```\n\nGet the list of all the skills.\n\n**Returns**:\n\nthe list of skills.\n\n<a id=\"aea.registries.resources.Resources.remove_skill\"></a>\n\n#### remove`_`skill\n\n```python\ndef remove_skill(skill_id: PublicId) -> None\n```\n\nRemove a skill from the set of resources.\n\n**Arguments**:\n\n- `skill_id`: the skill id for the skill to be removed.\n\n<a id=\"aea.registries.resources.Resources.get_handler\"></a>\n\n#### get`_`handler\n\n```python\ndef get_handler(protocol_id: PublicId,\n                skill_id: PublicId) -> Optional[Handler]\n```\n\nGet a specific handler.\n\n**Arguments**:\n\n- `protocol_id`: the protocol id the handler is handling\n- `skill_id`: the skill id of the handler's skill\n\n**Returns**:\n\nthe handler\n\n<a id=\"aea.registries.resources.Resources.get_handlers\"></a>\n\n#### get`_`handlers\n\n```python\ndef get_handlers(protocol_id: PublicId) -> List[Handler]\n```\n\nGet all handlers for a given protocol.\n\n**Arguments**:\n\n- `protocol_id`: the protocol id the handler is handling\n\n**Returns**:\n\nthe list of handlers matching the protocol\n\n<a id=\"aea.registries.resources.Resources.get_all_handlers\"></a>\n\n#### get`_`all`_`handlers\n\n```python\ndef get_all_handlers() -> List[Handler]\n```\n\nGet all handlers from all skills.\n\n**Returns**:\n\nthe list of handlers\n\n<a id=\"aea.registries.resources.Resources.get_behaviour\"></a>\n\n#### get`_`behaviour\n\n```python\ndef get_behaviour(skill_id: PublicId,\n                  behaviour_name: str) -> Optional[Behaviour]\n```\n\nGet a specific behaviours for a given skill.\n\n**Arguments**:\n\n- `skill_id`: the skill id\n- `behaviour_name`: the behaviour name\n\n**Returns**:\n\nthe behaviour, if it is present, else None\n\n<a id=\"aea.registries.resources.Resources.get_behaviours\"></a>\n\n#### get`_`behaviours\n\n```python\ndef get_behaviours(skill_id: PublicId) -> List[Behaviour]\n```\n\nGet all behaviours for a given skill.\n\n**Arguments**:\n\n- `skill_id`: the skill id\n\n**Returns**:\n\nthe list of behaviours of the skill\n\n<a id=\"aea.registries.resources.Resources.get_all_behaviours\"></a>\n\n#### get`_`all`_`behaviours\n\n```python\ndef get_all_behaviours() -> List[Behaviour]\n```\n\nGet all behaviours from all skills.\n\n**Returns**:\n\nthe list of all behaviours\n\n<a id=\"aea.registries.resources.Resources.setup\"></a>\n\n#### setup\n\n```python\ndef setup() -> None\n```\n\nSet up the resources.\n\nCalls setup on all resources.\n\n<a id=\"aea.registries.resources.Resources.teardown\"></a>\n\n#### teardown\n\n```python\ndef teardown() -> None\n```\n\nTeardown the resources.\n\nCalls teardown on all resources.\n\n"
  },
  {
    "path": "docs/api/runner.md",
    "content": "<a id=\"aea.runner\"></a>\n\n# aea.runner\n\nThis module contains the implementation of AEA multiple instances runner.\n\n<a id=\"aea.runner.AEAInstanceTask\"></a>\n\n## AEAInstanceTask Objects\n\n```python\nclass AEAInstanceTask(AbstractExecutorTask)\n```\n\nTask to run agent instance.\n\n<a id=\"aea.runner.AEAInstanceTask.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(agent: AEA) -> None\n```\n\nInit aea instance task.\n\n**Arguments**:\n\n- `agent`: AEA instance to run within task.\n\n<a id=\"aea.runner.AEAInstanceTask.id\"></a>\n\n#### id\n\n```python\n@property\ndef id() -> str\n```\n\nReturn agent name.\n\n<a id=\"aea.runner.AEAInstanceTask.start\"></a>\n\n#### start\n\n```python\ndef start() -> None\n```\n\nStart task.\n\n<a id=\"aea.runner.AEAInstanceTask.stop\"></a>\n\n#### stop\n\n```python\ndef stop() -> None\n```\n\nStop task.\n\n<a id=\"aea.runner.AEAInstanceTask.create_async_task\"></a>\n\n#### create`_`async`_`task\n\n```python\ndef create_async_task(loop: AbstractEventLoop) -> TaskAwaitable\n```\n\nReturn asyncio Task for task run in asyncio loop.\n\n**Arguments**:\n\n- `loop`: abstract event loop\n\n**Returns**:\n\ntask to run runtime\n\n<a id=\"aea.runner.AEARunner\"></a>\n\n## AEARunner Objects\n\n```python\nclass AEARunner(AbstractMultipleRunner)\n```\n\nRun multiple AEA instances.\n\n<a id=\"aea.runner.AEARunner.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(\n    agents: Sequence[AEA],\n    mode: str,\n    fail_policy: ExecutorExceptionPolicies = ExecutorExceptionPolicies.\n    propagate\n) -> None\n```\n\nInit AEARunner.\n\n**Arguments**:\n\n- `agents`: sequence of AEA instances to run.\n- `mode`: executor name to use.\n- `fail_policy`: one of ExecutorExceptionPolicies to be used with Executor\n\n"
  },
  {
    "path": "docs/api/runtime.md",
    "content": "<a id=\"aea.runtime\"></a>\n\n# aea.runtime\n\nThis module contains the implementation of runtime for economic agent (AEA).\n\n<a id=\"aea.runtime.RuntimeStates\"></a>\n\n## RuntimeStates Objects\n\n```python\nclass RuntimeStates(Enum)\n```\n\nRuntime states.\n\n<a id=\"aea.runtime.BaseRuntime\"></a>\n\n## BaseRuntime Objects\n\n```python\nclass BaseRuntime(Runnable, WithLogger)\n```\n\nAbstract runtime class to create implementations.\n\n<a id=\"aea.runtime.BaseRuntime.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(agent: AbstractAgent,\n             multiplexer_options: Dict,\n             loop_mode: Optional[str] = None,\n             loop: Optional[AbstractEventLoop] = None,\n             threaded: bool = False,\n             task_manager_mode: Optional[str] = None) -> None\n```\n\nInit runtime.\n\n**Arguments**:\n\n- `agent`: Agent to run.\n- `multiplexer_options`: options for the multiplexer.\n- `loop_mode`: agent main loop mode.\n- `loop`: optional event loop. if not provided a new one will be created.\n- `threaded`: if True, run in threaded mode, else async\n- `task_manager_mode`: mode of the task manager.\n\n<a id=\"aea.runtime.BaseRuntime.storage\"></a>\n\n#### storage\n\n```python\n@property\ndef storage() -> Optional[Storage]\n```\n\nGet optional storage.\n\n<a id=\"aea.runtime.BaseRuntime.loop_mode\"></a>\n\n#### loop`_`mode\n\n```python\n@property\ndef loop_mode() -> str\n```\n\nGet current loop mode.\n\n<a id=\"aea.runtime.BaseRuntime.task_manager\"></a>\n\n#### task`_`manager\n\n```python\n@property\ndef task_manager() -> TaskManager\n```\n\nGet the task manager.\n\n<a id=\"aea.runtime.BaseRuntime.loop\"></a>\n\n#### loop\n\n```python\n@property\ndef loop() -> Optional[AbstractEventLoop]\n```\n\nGet event loop.\n\n<a id=\"aea.runtime.BaseRuntime.agent_loop\"></a>\n\n#### agent`_`loop\n\n```python\n@property\ndef agent_loop() -> BaseAgentLoop\n```\n\nGet the agent loop.\n\n<a id=\"aea.runtime.BaseRuntime.multiplexer\"></a>\n\n#### multiplexer\n\n```python\n@property\ndef multiplexer() -> AsyncMultiplexer\n```\n\nGet multiplexer.\n\n<a id=\"aea.runtime.BaseRuntime.is_running\"></a>\n\n#### is`_`running\n\n```python\n@property\ndef is_running() -> bool\n```\n\nGet running state of the runtime.\n\n<a id=\"aea.runtime.BaseRuntime.is_stopped\"></a>\n\n#### is`_`stopped\n\n```python\n@property\ndef is_stopped() -> bool\n```\n\nGet stopped state of the runtime.\n\n<a id=\"aea.runtime.BaseRuntime.state\"></a>\n\n#### state\n\n```python\n@property\ndef state() -> RuntimeStates\n```\n\nGet runtime state.\n\n**Returns**:\n\nRuntimeStates\n\n<a id=\"aea.runtime.BaseRuntime.decision_maker\"></a>\n\n#### decision`_`maker\n\n```python\n@property\ndef decision_maker() -> DecisionMaker\n```\n\nReturn decision maker if set.\n\n<a id=\"aea.runtime.BaseRuntime.set_decision_maker\"></a>\n\n#### set`_`decision`_`maker\n\n```python\ndef set_decision_maker(decision_maker_handler: DecisionMakerHandler) -> None\n```\n\nSet decision maker with handler provided.\n\n<a id=\"aea.runtime.BaseRuntime.set_loop\"></a>\n\n#### set`_`loop\n\n```python\ndef set_loop(loop: AbstractEventLoop) -> None\n```\n\nSet event loop to be used.\n\n**Arguments**:\n\n- `loop`: event loop to use.\n\n<a id=\"aea.runtime.AsyncRuntime\"></a>\n\n## AsyncRuntime Objects\n\n```python\nclass AsyncRuntime(BaseRuntime)\n```\n\nAsynchronous runtime: uses asyncio loop for multiplexer and async agent main loop.\n\n<a id=\"aea.runtime.AsyncRuntime.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(agent: AbstractAgent,\n             multiplexer_options: Dict,\n             loop_mode: Optional[str] = None,\n             loop: Optional[AbstractEventLoop] = None,\n             threaded: bool = False,\n             task_manager_mode: Optional[str] = None) -> None\n```\n\nInit runtime.\n\n**Arguments**:\n\n- `agent`: Agent to run.\n- `multiplexer_options`: options for the multiplexer.\n- `loop_mode`: agent main loop mode.\n- `loop`: optional event loop. if not provided a new one will be created.\n- `threaded`: if True, run in threaded mode, else async\n- `task_manager_mode`: mode of the task manager.\n\n<a id=\"aea.runtime.AsyncRuntime.set_loop\"></a>\n\n#### set`_`loop\n\n```python\ndef set_loop(loop: AbstractEventLoop) -> None\n```\n\nSet event loop to be used.\n\n**Arguments**:\n\n- `loop`: event loop to use.\n\n<a id=\"aea.runtime.AsyncRuntime.run\"></a>\n\n#### run\n\n```python\nasync def run() -> None\n```\n\nStart runtime task.\n\nStarts multiplexer and agent loop.\n\n<a id=\"aea.runtime.AsyncRuntime.stop_runtime\"></a>\n\n#### stop`_`runtime\n\n```python\nasync def stop_runtime() -> None\n```\n\nStop runtime coroutine.\n\nStop main loop.\nTear down the agent..\nDisconnect multiplexer.\n\n<a id=\"aea.runtime.AsyncRuntime.run_runtime\"></a>\n\n#### run`_`runtime\n\n```python\nasync def run_runtime() -> None\n```\n\nRun runtime which means start agent loop, multiplexer and storage.\n\n<a id=\"aea.runtime.ThreadedRuntime\"></a>\n\n## ThreadedRuntime Objects\n\n```python\nclass ThreadedRuntime(AsyncRuntime)\n```\n\nRun agent and multiplexer in different threads with own asyncio loops.\n\n"
  },
  {
    "path": "docs/api/skills/base.md",
    "content": "<a id=\"aea.skills.base\"></a>\n\n# aea.skills.base\n\nThis module contains the base classes for the skills.\n\n<a id=\"aea.skills.base.SkillContext\"></a>\n\n## SkillContext Objects\n\n```python\nclass SkillContext()\n```\n\nThis class implements the context of a skill.\n\n<a id=\"aea.skills.base.SkillContext.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(agent_context: Optional[AgentContext] = None,\n             skill: Optional[\"Skill\"] = None) -> None\n```\n\nInitialize a skill context.\n\n**Arguments**:\n\n- `agent_context`: the agent context.\n- `skill`: the skill.\n\n<a id=\"aea.skills.base.SkillContext.logger\"></a>\n\n#### logger\n\n```python\n@property\ndef logger() -> Logger\n```\n\nGet the logger.\n\n<a id=\"aea.skills.base.SkillContext.logger\"></a>\n\n#### logger\n\n```python\n@logger.setter\ndef logger(logger_: Logger) -> None\n```\n\nSet the logger.\n\n<a id=\"aea.skills.base.SkillContext.set_agent_context\"></a>\n\n#### set`_`agent`_`context\n\n```python\ndef set_agent_context(agent_context: AgentContext) -> None\n```\n\nSet the agent context.\n\n<a id=\"aea.skills.base.SkillContext.shared_state\"></a>\n\n#### shared`_`state\n\n```python\n@property\ndef shared_state() -> Dict[str, Any]\n```\n\nGet the shared state dictionary.\n\n<a id=\"aea.skills.base.SkillContext.agent_name\"></a>\n\n#### agent`_`name\n\n```python\n@property\ndef agent_name() -> str\n```\n\nGet agent name.\n\n<a id=\"aea.skills.base.SkillContext.skill_id\"></a>\n\n#### skill`_`id\n\n```python\n@property\ndef skill_id() -> PublicId\n```\n\nGet the skill id of the skill context.\n\n<a id=\"aea.skills.base.SkillContext.is_active\"></a>\n\n#### is`_`active\n\n```python\n@property\ndef is_active() -> bool\n```\n\nGet the status of the skill (active/not active).\n\n<a id=\"aea.skills.base.SkillContext.is_active\"></a>\n\n#### is`_`active\n\n```python\n@is_active.setter\ndef is_active(value: bool) -> None\n```\n\nSet the status of the skill (active/not active).\n\n<a id=\"aea.skills.base.SkillContext.new_behaviours\"></a>\n\n#### new`_`behaviours\n\n```python\n@property\ndef new_behaviours() -> \"Queue[Behaviour]\"\n```\n\nQueue for the new behaviours.\n\nThis queue can be used to send messages to the framework\nto request the registration of a behaviour.\n\n**Returns**:\n\nthe queue of new behaviours.\n\n<a id=\"aea.skills.base.SkillContext.new_handlers\"></a>\n\n#### new`_`handlers\n\n```python\n@property\ndef new_handlers() -> \"Queue[Handler]\"\n```\n\nQueue for the new handlers.\n\nThis queue can be used to send messages to the framework\nto request the registration of a handler.\n\n**Returns**:\n\nthe queue of new handlers.\n\n<a id=\"aea.skills.base.SkillContext.agent_addresses\"></a>\n\n#### agent`_`addresses\n\n```python\n@property\ndef agent_addresses() -> Dict[str, str]\n```\n\nGet addresses.\n\n<a id=\"aea.skills.base.SkillContext.agent_address\"></a>\n\n#### agent`_`address\n\n```python\n@property\ndef agent_address() -> str\n```\n\nGet address.\n\n<a id=\"aea.skills.base.SkillContext.public_key\"></a>\n\n#### public`_`key\n\n```python\n@property\ndef public_key() -> str\n```\n\nGet public key.\n\n<a id=\"aea.skills.base.SkillContext.public_keys\"></a>\n\n#### public`_`keys\n\n```python\n@property\ndef public_keys() -> Dict[str, str]\n```\n\nGet public keys.\n\n<a id=\"aea.skills.base.SkillContext.connection_status\"></a>\n\n#### connection`_`status\n\n```python\n@property\ndef connection_status() -> MultiplexerStatus\n```\n\nGet connection status.\n\n<a id=\"aea.skills.base.SkillContext.outbox\"></a>\n\n#### outbox\n\n```python\n@property\ndef outbox() -> OutBox\n```\n\nGet outbox.\n\n<a id=\"aea.skills.base.SkillContext.storage\"></a>\n\n#### storage\n\n```python\n@property\ndef storage() -> Optional[Storage]\n```\n\nGet optional storage for agent.\n\n<a id=\"aea.skills.base.SkillContext.message_in_queue\"></a>\n\n#### message`_`in`_`queue\n\n```python\n@property\ndef message_in_queue() -> Queue\n```\n\nGet message in queue.\n\n<a id=\"aea.skills.base.SkillContext.decision_maker_message_queue\"></a>\n\n#### decision`_`maker`_`message`_`queue\n\n```python\n@property\ndef decision_maker_message_queue() -> Queue\n```\n\nGet message queue of decision maker.\n\n<a id=\"aea.skills.base.SkillContext.decision_maker_handler_context\"></a>\n\n#### decision`_`maker`_`handler`_`context\n\n```python\n@property\ndef decision_maker_handler_context() -> SimpleNamespace\n```\n\nGet decision maker handler context.\n\n<a id=\"aea.skills.base.SkillContext.task_manager\"></a>\n\n#### task`_`manager\n\n```python\n@property\ndef task_manager() -> TaskManager\n```\n\nGet behaviours of the skill.\n\n<a id=\"aea.skills.base.SkillContext.default_ledger_id\"></a>\n\n#### default`_`ledger`_`id\n\n```python\n@property\ndef default_ledger_id() -> str\n```\n\nGet the default ledger id.\n\n<a id=\"aea.skills.base.SkillContext.currency_denominations\"></a>\n\n#### currency`_`denominations\n\n```python\n@property\ndef currency_denominations() -> Dict[str, str]\n```\n\nGet a dictionary mapping ledger ids to currency denominations.\n\n<a id=\"aea.skills.base.SkillContext.search_service_address\"></a>\n\n#### search`_`service`_`address\n\n```python\n@property\ndef search_service_address() -> Address\n```\n\nGet the address of the search service.\n\n<a id=\"aea.skills.base.SkillContext.decision_maker_address\"></a>\n\n#### decision`_`maker`_`address\n\n```python\n@property\ndef decision_maker_address() -> Address\n```\n\nGet the address of the decision maker.\n\n<a id=\"aea.skills.base.SkillContext.handlers\"></a>\n\n#### handlers\n\n```python\n@property\ndef handlers() -> SimpleNamespace\n```\n\nGet handlers of the skill.\n\n<a id=\"aea.skills.base.SkillContext.behaviours\"></a>\n\n#### behaviours\n\n```python\n@property\ndef behaviours() -> SimpleNamespace\n```\n\nGet behaviours of the skill.\n\n<a id=\"aea.skills.base.SkillContext.namespace\"></a>\n\n#### namespace\n\n```python\n@property\ndef namespace() -> SimpleNamespace\n```\n\nGet the agent context namespace.\n\n<a id=\"aea.skills.base.SkillContext.__getattr__\"></a>\n\n#### `__`getattr`__`\n\n```python\ndef __getattr__(item: Any) -> Any\n```\n\nGet attribute.\n\n<a id=\"aea.skills.base.SkillContext.send_to_skill\"></a>\n\n#### send`_`to`_`skill\n\n```python\ndef send_to_skill(message_or_envelope: Union[Message, Envelope],\n                  context: Optional[EnvelopeContext] = None) -> None\n```\n\nSend message or envelope to another skill.\n\nIf message passed it will be wrapped into envelope with optional envelope context.\n\n**Arguments**:\n\n- `message_or_envelope`: envelope to send to another skill.\n- `context`: the optional envelope context\n\n<a id=\"aea.skills.base.SkillComponent\"></a>\n\n## SkillComponent Objects\n\n```python\nclass SkillComponent(ABC)\n```\n\nThis class defines an abstract interface for skill component classes.\n\n<a id=\"aea.skills.base.SkillComponent.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(name: str,\n             skill_context: SkillContext,\n             configuration: Optional[SkillComponentConfiguration] = None,\n             **kwargs: Any) -> None\n```\n\nInitialize a skill component.\n\n**Arguments**:\n\n- `name`: the name of the component.\n- `configuration`: the configuration for the component.\n- `skill_context`: the skill context.\n- `kwargs`: the keyword arguments.\n\n<a id=\"aea.skills.base.SkillComponent.name\"></a>\n\n#### name\n\n```python\n@property\ndef name() -> str\n```\n\nGet the name of the skill component.\n\n<a id=\"aea.skills.base.SkillComponent.context\"></a>\n\n#### context\n\n```python\n@property\ndef context() -> SkillContext\n```\n\nGet the context of the skill component.\n\n<a id=\"aea.skills.base.SkillComponent.skill_id\"></a>\n\n#### skill`_`id\n\n```python\n@property\ndef skill_id() -> PublicId\n```\n\nGet the skill id of the skill component.\n\n<a id=\"aea.skills.base.SkillComponent.configuration\"></a>\n\n#### configuration\n\n```python\n@property\ndef configuration() -> SkillComponentConfiguration\n```\n\nGet the skill component configuration.\n\n<a id=\"aea.skills.base.SkillComponent.config\"></a>\n\n#### config\n\n```python\n@property\ndef config() -> Dict[Any, Any]\n```\n\nGet the config of the skill component.\n\n<a id=\"aea.skills.base.SkillComponent.setup\"></a>\n\n#### setup\n\n```python\n@abstractmethod\ndef setup() -> None\n```\n\nImplement the setup.\n\n<a id=\"aea.skills.base.SkillComponent.teardown\"></a>\n\n#### teardown\n\n```python\n@abstractmethod\ndef teardown() -> None\n```\n\nImplement the teardown.\n\n<a id=\"aea.skills.base.SkillComponent.parse_module\"></a>\n\n#### parse`_`module\n\n```python\n@classmethod\n@abstractmethod\ndef parse_module(cls, path: str, configs: Dict[str,\n                                               SkillComponentConfiguration],\n                 skill_context: SkillContext) -> dict\n```\n\nParse the component module.\n\n<a id=\"aea.skills.base.AbstractBehaviour\"></a>\n\n## AbstractBehaviour Objects\n\n```python\nclass AbstractBehaviour(SkillComponent, ABC)\n```\n\nAbstract behaviour for periodical calls.\n\ntick_interval: float, interval to call behaviour's act.\nstart_at: optional datetime, when to start periodical calls.\n\n<a id=\"aea.skills.base.AbstractBehaviour.tick_interval\"></a>\n\n#### tick`_`interval\n\n```python\n@property\ndef tick_interval() -> float\n```\n\nGet the tick_interval in seconds.\n\n<a id=\"aea.skills.base.AbstractBehaviour.start_at\"></a>\n\n#### start`_`at\n\n```python\n@property\ndef start_at() -> Optional[datetime.datetime]\n```\n\nGet the start time of the behaviour.\n\n<a id=\"aea.skills.base.Behaviour\"></a>\n\n## Behaviour Objects\n\n```python\nclass Behaviour(AbstractBehaviour, ABC)\n```\n\nThis class implements an abstract behaviour.\n\nIn a subclass of Behaviour, the flag 'is_programmatically_defined'\n can be used by the developer to signal to the framework that the class\n is meant to be used programmatically; hence, in case the class is\n not declared in the configuration file but it is present in a skill\n module, the framework will just ignore this class instead of printing\n a warning message.\n\n<a id=\"aea.skills.base.Behaviour.act\"></a>\n\n#### act\n\n```python\n@abstractmethod\ndef act() -> None\n```\n\nImplement the behaviour.\n\n**Returns**:\n\nNone\n\n<a id=\"aea.skills.base.Behaviour.is_done\"></a>\n\n#### is`_`done\n\n```python\ndef is_done() -> bool\n```\n\nReturn True if the behaviour is terminated, False otherwise.\n\n<a id=\"aea.skills.base.Behaviour.act_wrapper\"></a>\n\n#### act`_`wrapper\n\n```python\ndef act_wrapper() -> None\n```\n\nWrap the call of the action. This method must be called only by the framework.\n\n<a id=\"aea.skills.base.Behaviour.parse_module\"></a>\n\n#### parse`_`module\n\n```python\n@classmethod\ndef parse_module(cls, path: str,\n                 behaviour_configs: Dict[str, SkillComponentConfiguration],\n                 skill_context: SkillContext) -> Dict[str, \"Behaviour\"]\n```\n\nParse the behaviours module.\n\n**Arguments**:\n\n- `path`: path to the Python module containing the Behaviour classes.\n- `behaviour_configs`: a list of behaviour configurations.\n- `skill_context`: the skill context\n\n**Returns**:\n\na list of Behaviour.\n\n<a id=\"aea.skills.base.Handler\"></a>\n\n## Handler Objects\n\n```python\nclass Handler(SkillComponent, ABC)\n```\n\nThis class implements an abstract behaviour.\n\nIn a subclass of Handler, the flag 'is_programmatically_defined'\n can be used by the developer to signal to the framework that the component\n is meant to be used programmatically; hence, in case the class is\n not declared in the configuration file but it is present in a skill\n module, the framework will just ignore this class instead of printing\n a warning message.\n\nSUPPORTED_PROTOCOL is read by the framework when the handlers are loaded\n to register them as 'listeners' to the protocol identified by the specified\n public id. Whenever a message of protocol 'SUPPORTED_PROTOCOL' is sent\n to the agent, the framework will call the 'handle' method.\n\n<a id=\"aea.skills.base.Handler.handle\"></a>\n\n#### handle\n\n```python\n@abstractmethod\ndef handle(message: Message) -> None\n```\n\nImplement the reaction to a message.\n\n**Arguments**:\n\n- `message`: the message\n\n**Returns**:\n\nNone\n\n<a id=\"aea.skills.base.Handler.handle_wrapper\"></a>\n\n#### handle`_`wrapper\n\n```python\ndef handle_wrapper(message: Message) -> None\n```\n\nWrap the call of the handler. This method must be called only by the framework.\n\n<a id=\"aea.skills.base.Handler.parse_module\"></a>\n\n#### parse`_`module\n\n```python\n@classmethod\ndef parse_module(cls, path: str,\n                 handler_configs: Dict[str, SkillComponentConfiguration],\n                 skill_context: SkillContext) -> Dict[str, \"Handler\"]\n```\n\nParse the handler module.\n\n**Arguments**:\n\n- `path`: path to the Python module containing the Handler class.\n- `handler_configs`: the list of handler configurations.\n- `skill_context`: the skill context\n\n**Returns**:\n\nan handler, or None if the parsing fails.\n\n<a id=\"aea.skills.base.Model\"></a>\n\n## Model Objects\n\n```python\nclass Model(SkillComponent, ABC)\n```\n\nThis class implements an abstract model.\n\n<a id=\"aea.skills.base.Model.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(name: str,\n             skill_context: SkillContext,\n             configuration: Optional[SkillComponentConfiguration] = None,\n             keep_terminal_state_dialogues: Optional[bool] = None,\n             **kwargs: Any) -> None\n```\n\nInitialize a model.\n\n**Arguments**:\n\n- `name`: the name of the component.\n- `configuration`: the configuration for the component.\n- `skill_context`: the skill context.\n- `keep_terminal_state_dialogues`: specify do dialogues in terminal state should stay or not\n- `kwargs`: the keyword arguments.\n\n<a id=\"aea.skills.base.Model.setup\"></a>\n\n#### setup\n\n```python\ndef setup() -> None\n```\n\nSet the class up.\n\n<a id=\"aea.skills.base.Model.teardown\"></a>\n\n#### teardown\n\n```python\ndef teardown() -> None\n```\n\nTear the class down.\n\n<a id=\"aea.skills.base.Model.parse_module\"></a>\n\n#### parse`_`module\n\n```python\n@classmethod\ndef parse_module(cls, path: str,\n                 model_configs: Dict[str, SkillComponentConfiguration],\n                 skill_context: SkillContext) -> Dict[str, \"Model\"]\n```\n\nParse the model module.\n\n**Arguments**:\n\n- `path`: path to the Python skill module.\n- `model_configs`: a list of model configurations.\n- `skill_context`: the skill context\n\n**Returns**:\n\na list of Model.\n\n<a id=\"aea.skills.base.Skill\"></a>\n\n## Skill Objects\n\n```python\nclass Skill(Component)\n```\n\nThis class implements a skill.\n\n<a id=\"aea.skills.base.Skill.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(configuration: SkillConfig,\n             skill_context: Optional[SkillContext] = None,\n             handlers: Optional[Dict[str, Handler]] = None,\n             behaviours: Optional[Dict[str, Behaviour]] = None,\n             models: Optional[Dict[str, Model]] = None,\n             **kwargs: Any)\n```\n\nInitialize a skill.\n\n**Arguments**:\n\n- `configuration`: the skill configuration.\n- `skill_context`: the skill context.\n- `handlers`: dictionary of handlers.\n- `behaviours`: dictionary of behaviours.\n- `models`: dictionary of models.\n- `kwargs`: the keyword arguments.\n\n<a id=\"aea.skills.base.Skill.skill_context\"></a>\n\n#### skill`_`context\n\n```python\n@property\ndef skill_context() -> SkillContext\n```\n\nGet the skill context.\n\n<a id=\"aea.skills.base.Skill.handlers\"></a>\n\n#### handlers\n\n```python\n@property\ndef handlers() -> Dict[str, Handler]\n```\n\nGet the handlers.\n\n<a id=\"aea.skills.base.Skill.behaviours\"></a>\n\n#### behaviours\n\n```python\n@property\ndef behaviours() -> Dict[str, Behaviour]\n```\n\nGet the handlers.\n\n<a id=\"aea.skills.base.Skill.models\"></a>\n\n#### models\n\n```python\n@property\ndef models() -> Dict[str, Model]\n```\n\nGet the handlers.\n\n<a id=\"aea.skills.base.Skill.from_dir\"></a>\n\n#### from`_`dir\n\n```python\n@classmethod\ndef from_dir(cls, directory: str, agent_context: AgentContext,\n             **kwargs: Any) -> \"Skill\"\n```\n\nLoad the skill from a directory.\n\n**Arguments**:\n\n- `directory`: the directory to the skill package.\n- `agent_context`: the skill context.\n- `kwargs`: the keyword arguments.\n\n**Returns**:\n\nthe skill object.\n\n<a id=\"aea.skills.base.Skill.logger\"></a>\n\n#### logger\n\n```python\n@property\ndef logger() -> Logger\n```\n\nGet the logger.\n\nIn the case of a skill, return the\nlogger provided by the skill context.\n\n**Returns**:\n\nthe logger\n\n<a id=\"aea.skills.base.Skill.logger\"></a>\n\n#### logger\n\n```python\n@logger.setter\ndef logger(*args: str) -> None\n```\n\nSet the logger.\n\n<a id=\"aea.skills.base.Skill.from_config\"></a>\n\n#### from`_`config\n\n```python\n@classmethod\ndef from_config(cls, configuration: SkillConfig, agent_context: AgentContext,\n                **kwargs: Any) -> \"Skill\"\n```\n\nLoad the skill from configuration.\n\n**Arguments**:\n\n- `configuration`: a skill configuration. Must be associated with a directory.\n- `agent_context`: the agent context.\n- `kwargs`: the keyword arguments.\n\n**Returns**:\n\nthe skill.\n\n<a id=\"aea.skills.base._SkillComponentLoadingItem\"></a>\n\n## `_`SkillComponentLoadingItem Objects\n\n```python\nclass _SkillComponentLoadingItem()\n```\n\nClass to represent a triple (component name, component configuration, component class).\n\n<a id=\"aea.skills.base._SkillComponentLoadingItem.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(name: str, config: SkillComponentConfiguration,\n             class_: Type[SkillComponent], type_: _SKILL_COMPONENT_TYPES)\n```\n\nInitialize the item.\n\n<a id=\"aea.skills.base._SkillComponentLoader\"></a>\n\n## `_`SkillComponentLoader Objects\n\n```python\nclass _SkillComponentLoader()\n```\n\nThis class implements the loading policy for skill components.\n\n<a id=\"aea.skills.base._SkillComponentLoader.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(configuration: SkillConfig, skill_context: SkillContext,\n             **kwargs: Any)\n```\n\nInitialize the helper class.\n\n<a id=\"aea.skills.base._SkillComponentLoader.load_skill\"></a>\n\n#### load`_`skill\n\n```python\ndef load_skill() -> Skill\n```\n\nLoad the skill.\n\n"
  },
  {
    "path": "docs/api/skills/behaviours.md",
    "content": "<a id=\"aea.skills.behaviours\"></a>\n\n# aea.skills.behaviours\n\nThis module contains the classes for specific behaviours.\n\n<a id=\"aea.skills.behaviours.SimpleBehaviour\"></a>\n\n## SimpleBehaviour Objects\n\n```python\nclass SimpleBehaviour(Behaviour, ABC)\n```\n\nThis class implements a simple behaviour.\n\n<a id=\"aea.skills.behaviours.SimpleBehaviour.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(act: Optional[Callable[[], None]] = None, **kwargs: Any) -> None\n```\n\nInitialize a simple behaviour.\n\n**Arguments**:\n\n- `act`: the act callable.\n- `kwargs`: the keyword arguments to be passed to the parent class.\n\n<a id=\"aea.skills.behaviours.SimpleBehaviour.setup\"></a>\n\n#### setup\n\n```python\ndef setup() -> None\n```\n\nSet the behaviour up.\n\n<a id=\"aea.skills.behaviours.SimpleBehaviour.act\"></a>\n\n#### act\n\n```python\ndef act() -> None\n```\n\nDo the action.\n\n<a id=\"aea.skills.behaviours.SimpleBehaviour.teardown\"></a>\n\n#### teardown\n\n```python\ndef teardown() -> None\n```\n\nTear the behaviour down.\n\n<a id=\"aea.skills.behaviours.CompositeBehaviour\"></a>\n\n## CompositeBehaviour Objects\n\n```python\nclass CompositeBehaviour(Behaviour, ABC)\n```\n\nThis class implements a composite behaviour.\n\n<a id=\"aea.skills.behaviours.CyclicBehaviour\"></a>\n\n## CyclicBehaviour Objects\n\n```python\nclass CyclicBehaviour(SimpleBehaviour, ABC)\n```\n\nThis behaviour is executed until the agent is stopped.\n\n<a id=\"aea.skills.behaviours.CyclicBehaviour.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(**kwargs: Any) -> None\n```\n\nInitialize the cyclic behaviour.\n\n<a id=\"aea.skills.behaviours.CyclicBehaviour.number_of_executions\"></a>\n\n#### number`_`of`_`executions\n\n```python\n@property\ndef number_of_executions() -> int\n```\n\nGet the number of executions.\n\n<a id=\"aea.skills.behaviours.CyclicBehaviour.act_wrapper\"></a>\n\n#### act`_`wrapper\n\n```python\ndef act_wrapper() -> None\n```\n\nWrap the call of the action. This method must be called only by the framework.\n\n<a id=\"aea.skills.behaviours.CyclicBehaviour.is_done\"></a>\n\n#### is`_`done\n\n```python\ndef is_done() -> bool\n```\n\nReturn True if the behaviour is terminated, False otherwise.\n\nThe user should implement it properly to determine the stopping condition.\n\n**Returns**:\n\nbool indicating status\n\n<a id=\"aea.skills.behaviours.OneShotBehaviour\"></a>\n\n## OneShotBehaviour Objects\n\n```python\nclass OneShotBehaviour(SimpleBehaviour, ABC)\n```\n\nThis behaviour is executed only once.\n\n<a id=\"aea.skills.behaviours.OneShotBehaviour.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(**kwargs: Any) -> None\n```\n\nInitialize the cyclic behaviour.\n\n<a id=\"aea.skills.behaviours.OneShotBehaviour.is_done\"></a>\n\n#### is`_`done\n\n```python\ndef is_done() -> bool\n```\n\nReturn True if the behaviour is terminated, False otherwise.\n\n<a id=\"aea.skills.behaviours.OneShotBehaviour.act_wrapper\"></a>\n\n#### act`_`wrapper\n\n```python\ndef act_wrapper() -> None\n```\n\nWrap the call of the action. This method must be called only by the framework.\n\n<a id=\"aea.skills.behaviours.TickerBehaviour\"></a>\n\n## TickerBehaviour Objects\n\n```python\nclass TickerBehaviour(SimpleBehaviour, ABC)\n```\n\nThis behaviour is executed periodically with an interval.\n\n<a id=\"aea.skills.behaviours.TickerBehaviour.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(tick_interval: float = 1.0,\n             start_at: Optional[datetime.datetime] = None,\n             **kwargs: Any) -> None\n```\n\nInitialize the ticker behaviour.\n\n**Arguments**:\n\n- `tick_interval`: interval of the behaviour in seconds.\n- `start_at`: whether to start the behaviour with an offset.\n- `kwargs`: the keyword arguments.\n\n<a id=\"aea.skills.behaviours.TickerBehaviour.tick_interval\"></a>\n\n#### tick`_`interval\n\n```python\n@property\ndef tick_interval() -> float\n```\n\nGet the tick_interval in seconds.\n\n<a id=\"aea.skills.behaviours.TickerBehaviour.start_at\"></a>\n\n#### start`_`at\n\n```python\n@property\ndef start_at() -> datetime.datetime\n```\n\nGet the start time.\n\n<a id=\"aea.skills.behaviours.TickerBehaviour.last_act_time\"></a>\n\n#### last`_`act`_`time\n\n```python\n@property\ndef last_act_time() -> datetime.datetime\n```\n\nGet the last time the act method has been called.\n\n<a id=\"aea.skills.behaviours.TickerBehaviour.act_wrapper\"></a>\n\n#### act`_`wrapper\n\n```python\ndef act_wrapper() -> None\n```\n\nWrap the call of the action. This method must be called only by the framework.\n\n<a id=\"aea.skills.behaviours.TickerBehaviour.is_time_to_act\"></a>\n\n#### is`_`time`_`to`_`act\n\n```python\ndef is_time_to_act() -> bool\n```\n\nCheck whether it is time to act, according to the tick_interval constraint and the 'start at' constraint.\n\n**Returns**:\n\nTrue if it is time to act, false otherwise.\n\n<a id=\"aea.skills.behaviours.SequenceBehaviour\"></a>\n\n## SequenceBehaviour Objects\n\n```python\nclass SequenceBehaviour(CompositeBehaviour, ABC)\n```\n\nThis behaviour executes sub-behaviour serially.\n\n<a id=\"aea.skills.behaviours.SequenceBehaviour.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(behaviour_sequence: List[Behaviour], **kwargs: Any) -> None\n```\n\nInitialize the sequence behaviour.\n\n**Arguments**:\n\n- `behaviour_sequence`: the sequence of behaviour.\n- `kwargs`: the keyword arguments\n\n<a id=\"aea.skills.behaviours.SequenceBehaviour.current_behaviour\"></a>\n\n#### current`_`behaviour\n\n```python\n@property\ndef current_behaviour() -> Optional[Behaviour]\n```\n\nGet the current behaviour.\n\nIf None, the sequence behaviour can be considered done.\n\n**Returns**:\n\ncurrent behaviour or None\n\n<a id=\"aea.skills.behaviours.SequenceBehaviour.act\"></a>\n\n#### act\n\n```python\ndef act() -> None\n```\n\nImplement the behaviour.\n\n<a id=\"aea.skills.behaviours.SequenceBehaviour.is_done\"></a>\n\n#### is`_`done\n\n```python\ndef is_done() -> bool\n```\n\nReturn True if the behaviour is terminated, False otherwise.\n\n<a id=\"aea.skills.behaviours.State\"></a>\n\n## State Objects\n\n```python\nclass State(SimpleBehaviour, ABC)\n```\n\nA state of a FSMBehaviour.\n\nA State behaviour is a simple behaviour with a\nspecial property 'event' that is opportunely set\nby the implementer. The event is read by the framework\nwhen the behaviour is done in order to pick the\ntransition to trigger.\n\n<a id=\"aea.skills.behaviours.State.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(**kwargs: Any) -> None\n```\n\nInitialize a state of the state machine.\n\n<a id=\"aea.skills.behaviours.State.event\"></a>\n\n#### event\n\n```python\n@property\ndef event() -> Optional[str]\n```\n\nGet the event to be triggered at the end of the behaviour.\n\n<a id=\"aea.skills.behaviours.State.is_done\"></a>\n\n#### is`_`done\n\n```python\n@abstractmethod\ndef is_done() -> bool\n```\n\nReturn True if the behaviour is terminated, False otherwise.\n\n<a id=\"aea.skills.behaviours.State.reset\"></a>\n\n#### reset\n\n```python\ndef reset() -> None\n```\n\nReset initial conditions.\n\n<a id=\"aea.skills.behaviours.FSMBehaviour\"></a>\n\n## FSMBehaviour Objects\n\n```python\nclass FSMBehaviour(CompositeBehaviour, ABC)\n```\n\nThis class implements a finite-state machine behaviour.\n\n<a id=\"aea.skills.behaviours.FSMBehaviour.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(**kwargs: Any) -> None\n```\n\nInitialize the finite-state machine behaviour.\n\n<a id=\"aea.skills.behaviours.FSMBehaviour.is_started\"></a>\n\n#### is`_`started\n\n```python\n@property\ndef is_started() -> bool\n```\n\nCheck if the behaviour is started.\n\n<a id=\"aea.skills.behaviours.FSMBehaviour.register_state\"></a>\n\n#### register`_`state\n\n```python\ndef register_state(name: str, state: State, initial: bool = False) -> None\n```\n\nRegister a state.\n\n**Arguments**:\n\n- `name`: the name of the state.\n- `state`: the behaviour in that state.\n- `initial`: whether the state is an initial state.\n\n**Raises**:\n\n- `ValueError`: if a state with the provided name already exists.\n\n<a id=\"aea.skills.behaviours.FSMBehaviour.register_final_state\"></a>\n\n#### register`_`final`_`state\n\n```python\ndef register_final_state(name: str, state: State) -> None\n```\n\nRegister a final state.\n\n**Arguments**:\n\n- `name`: the name of the state.\n- `state`: the state.\n\n**Raises**:\n\n- `ValueError`: if a state with the provided name already exists.\n\n<a id=\"aea.skills.behaviours.FSMBehaviour.unregister_state\"></a>\n\n#### unregister`_`state\n\n```python\ndef unregister_state(name: str) -> None\n```\n\nUnregister a state.\n\n**Arguments**:\n\n- `name`: the state name to unregister.\n\n**Raises**:\n\n- `ValueError`: if the state is not registered.\n\n<a id=\"aea.skills.behaviours.FSMBehaviour.states\"></a>\n\n#### states\n\n```python\n@property\ndef states() -> Set[str]\n```\n\nGet all the state names.\n\n<a id=\"aea.skills.behaviours.FSMBehaviour.initial_state\"></a>\n\n#### initial`_`state\n\n```python\n@property\ndef initial_state() -> Optional[str]\n```\n\nGet the initial state name.\n\n<a id=\"aea.skills.behaviours.FSMBehaviour.initial_state\"></a>\n\n#### initial`_`state\n\n```python\n@initial_state.setter\ndef initial_state(name: str) -> None\n```\n\nSet the initial state.\n\n<a id=\"aea.skills.behaviours.FSMBehaviour.final_states\"></a>\n\n#### final`_`states\n\n```python\n@property\ndef final_states() -> Set[str]\n```\n\nGet the final state names.\n\n<a id=\"aea.skills.behaviours.FSMBehaviour.get_state\"></a>\n\n#### get`_`state\n\n```python\ndef get_state(name: str) -> Optional[State]\n```\n\nGet a state from its name.\n\n<a id=\"aea.skills.behaviours.FSMBehaviour.act\"></a>\n\n#### act\n\n```python\ndef act() -> None\n```\n\nImplement the behaviour.\n\n<a id=\"aea.skills.behaviours.FSMBehaviour.is_done\"></a>\n\n#### is`_`done\n\n```python\ndef is_done() -> bool\n```\n\nReturn True if the behaviour is terminated, False otherwise.\n\n<a id=\"aea.skills.behaviours.FSMBehaviour.register_transition\"></a>\n\n#### register`_`transition\n\n```python\ndef register_transition(source: str,\n                        destination: str,\n                        event: Optional[str] = None) -> None\n```\n\nRegister a transition.\n\nNo sanity check is done.\n\n**Arguments**:\n\n- `source`: the source state name.\n- `destination`: the destination state name.\n- `event`: the event.\n\n**Raises**:\n\n- `ValueError`: if a transition from source with event is already present.\n\n<a id=\"aea.skills.behaviours.FSMBehaviour.unregister_transition\"></a>\n\n#### unregister`_`transition\n\n```python\ndef unregister_transition(source: str,\n                          destination: str,\n                          event: Optional[str] = None) -> None\n```\n\nUnregister a transition.\n\n**Arguments**:\n\n- `source`: the source state name.\n- `destination`: the destination state name.\n- `event`: the event.\n\n**Raises**:\n\n- `ValueError`: if a transition from source with event is not present.\n\n"
  },
  {
    "path": "docs/api/skills/tasks.md",
    "content": "<a id=\"aea.skills.tasks\"></a>\n\n# aea.skills.tasks\n\nThis module contains the classes for tasks.\n\n<a id=\"aea.skills.tasks.Task\"></a>\n\n## Task Objects\n\n```python\nclass Task(WithLogger)\n```\n\nThis class implements an abstract task.\n\n<a id=\"aea.skills.tasks.Task.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(**kwargs: Any) -> None\n```\n\nInitialize a task.\n\n<a id=\"aea.skills.tasks.Task.__call__\"></a>\n\n#### `__`call`__`\n\n```python\ndef __call__(*args: Any, **kwargs: Any) -> Any\n```\n\nExecute the task.\n\n**Arguments**:\n\n- `args`: positional arguments forwarded to the 'execute' method.\n- `kwargs`: keyword arguments forwarded to the 'execute' method.\n\n**Raises**:\n\n- `ValueError`: if the task has already been executed.\n\n**Returns**:\n\nthe task instance\n\n<a id=\"aea.skills.tasks.Task.is_executed\"></a>\n\n#### is`_`executed\n\n```python\n@property\ndef is_executed() -> bool\n```\n\nCheck if the task has already been executed.\n\n<a id=\"aea.skills.tasks.Task.result\"></a>\n\n#### result\n\n```python\n@property\ndef result() -> Any\n```\n\nGet the result.\n\n**Raises**:\n\n- `ValueError`: if the task has not been executed yet.\n\n**Returns**:\n\nthe result from the execute method.\n\n<a id=\"aea.skills.tasks.Task.setup\"></a>\n\n#### setup\n\n```python\ndef setup() -> None\n```\n\nImplement the task setup.\n\n<a id=\"aea.skills.tasks.Task.execute\"></a>\n\n#### execute\n\n```python\n@abstractmethod\ndef execute(*args: Any, **kwargs: Any) -> Any\n```\n\nRun the task logic.\n\n**Arguments**:\n\n- `args`: the positional arguments\n- `kwargs`: the keyword arguments\n\n**Returns**:\n\nany\n\n<a id=\"aea.skills.tasks.Task.teardown\"></a>\n\n#### teardown\n\n```python\ndef teardown() -> None\n```\n\nImplement the task teardown.\n\n<a id=\"aea.skills.tasks.init_worker\"></a>\n\n#### init`_`worker\n\n```python\ndef init_worker() -> None\n```\n\nInitialize a worker.\n\nDisable the SIGINT handler of process pool is using.\nRelated to a well-known bug: https://bugs.python.org/issue8296\n\n<a id=\"aea.skills.tasks.TaskManager\"></a>\n\n## TaskManager Objects\n\n```python\nclass TaskManager(WithLogger)\n```\n\nA Task manager.\n\n<a id=\"aea.skills.tasks.TaskManager.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(nb_workers: int = DEFAULT_WORKERS_AMOUNT,\n             is_lazy_pool_start: bool = True,\n             logger: Optional[logging.Logger] = None,\n             pool_mode: str = THREAD_POOL_MODE) -> None\n```\n\nInitialize the task manager.\n\n**Arguments**:\n\n- `nb_workers`: the number of worker processes.\n- `is_lazy_pool_start`: option to postpone pool creation till the first enqueue_task called.\n- `logger`: the logger.\n- `pool_mode`: str. multithread or multiprocess\n\n<a id=\"aea.skills.tasks.TaskManager.is_started\"></a>\n\n#### is`_`started\n\n```python\n@property\ndef is_started() -> bool\n```\n\nGet started status of TaskManager.\n\n**Returns**:\n\nbool\n\n<a id=\"aea.skills.tasks.TaskManager.nb_workers\"></a>\n\n#### nb`_`workers\n\n```python\n@property\ndef nb_workers() -> int\n```\n\nGet the number of workers.\n\n**Returns**:\n\nint\n\n<a id=\"aea.skills.tasks.TaskManager.enqueue_task\"></a>\n\n#### enqueue`_`task\n\n```python\ndef enqueue_task(func: Callable,\n                 args: Sequence = (),\n                 kwargs: Optional[Dict[str, Any]] = None) -> int\n```\n\nEnqueue a task with the executor.\n\n**Arguments**:\n\n- `func`: the callable instance to be enqueued\n- `args`: the positional arguments to be passed to the function.\n- `kwargs`: the keyword arguments to be passed to the function.\n\n**Raises**:\n\n- `ValueError`: if the task manager is not running.\n\n**Returns**:\n\nthe task id to get the the result.\n\n<a id=\"aea.skills.tasks.TaskManager.get_task_result\"></a>\n\n#### get`_`task`_`result\n\n```python\ndef get_task_result(task_id: int) -> AsyncResult\n```\n\nGet the result from a task.\n\n**Arguments**:\n\n- `task_id`: the task id\n\n**Returns**:\n\nasync result for task_id\n\n<a id=\"aea.skills.tasks.TaskManager.start\"></a>\n\n#### start\n\n```python\ndef start() -> None\n```\n\nStart the task manager.\n\n<a id=\"aea.skills.tasks.TaskManager.stop\"></a>\n\n#### stop\n\n```python\ndef stop() -> None\n```\n\nStop the task manager.\n\n<a id=\"aea.skills.tasks.ThreadedTaskManager\"></a>\n\n## ThreadedTaskManager Objects\n\n```python\nclass ThreadedTaskManager(TaskManager)\n```\n\nA threaded task manager.\n\n<a id=\"aea.skills.tasks.ThreadedTaskManager.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(nb_workers: int = DEFAULT_WORKERS_AMOUNT,\n             is_lazy_pool_start: bool = True,\n             logger: Optional[logging.Logger] = None) -> None\n```\n\nInitialize the task manager.\n\n**Arguments**:\n\n- `nb_workers`: the number of worker processes.\n- `is_lazy_pool_start`: option to postpone pool creation till the first enqueue_task called.\n- `logger`: the logger.\n\n<a id=\"aea.skills.tasks.ProcessTaskManager\"></a>\n\n## ProcessTaskManager Objects\n\n```python\nclass ProcessTaskManager(TaskManager)\n```\n\nA multiprocess task manager.\n\n<a id=\"aea.skills.tasks.ProcessTaskManager.__init__\"></a>\n\n#### `__`init`__`\n\n```python\ndef __init__(nb_workers: int = DEFAULT_WORKERS_AMOUNT,\n             is_lazy_pool_start: bool = True,\n             logger: Optional[logging.Logger] = None) -> None\n```\n\nInitialize the task manager.\n\n**Arguments**:\n\n- `nb_workers`: the number of worker processes.\n- `is_lazy_pool_start`: option to postpone pool creation till the first enqueue_task called.\n- `logger`: the logger.\n\n"
  },
  {
    "path": "docs/api/test_tools/constants.md",
    "content": "<a id=\"aea.test_tools.constants\"></a>\n\n# aea.test`_`tools.constants\n\nThis is a module with constants for test tools.\n\n"
  },
  {
    "path": "docs/api/test_tools/exceptions.md",
    "content": "<a id=\"aea.test_tools.exceptions\"></a>\n\n# aea.test`_`tools.exceptions\n\nModule with AEA testing exceptions.\n\n<a id=\"aea.test_tools.exceptions.AEATestingException\"></a>\n\n## AEATestingException Objects\n\n```python\nclass AEATestingException(Exception)\n```\n\nAn exception to be raised on incorrect testing tools usage.\n\n"
  },
  {
    "path": "docs/api/test_tools/generic.md",
    "content": "<a id=\"aea.test_tools.generic\"></a>\n\n# aea.test`_`tools.generic\n\nThis module contains generic tools for AEA end-to-end testing.\n\n<a id=\"aea.test_tools.generic.write_envelope_to_file\"></a>\n\n#### write`_`envelope`_`to`_`file\n\n```python\ndef write_envelope_to_file(envelope: Envelope, file_path: str) -> None\n```\n\nWrite an envelope to a file.\n\n**Arguments**:\n\n- `envelope`: Envelope.\n- `file_path`: the file path\n\n<a id=\"aea.test_tools.generic.read_envelope_from_file\"></a>\n\n#### read`_`envelope`_`from`_`file\n\n```python\ndef read_envelope_from_file(file_path: str) -> Envelope\n```\n\nRead an envelope from a file.\n\n**Arguments**:\n\n- `file_path`: the file path.\n\n**Returns**:\n\nenvelope\n\n<a id=\"aea.test_tools.generic.nested_set_config\"></a>\n\n#### nested`_`set`_`config\n\n```python\ndef nested_set_config(dotted_path: str,\n                      value: Any,\n                      author: str = DEFAULT_AUTHOR) -> None\n```\n\nSet an AEA config with nested values.\n\nRun from agent's directory.\n\nAllowed dotted_path:\n    'agent.an_attribute_name'\n    'protocols.my_protocol.an_attribute_name'\n    'connections.my_connection.an_attribute_name'\n    'contracts.my_contract.an_attribute_name'\n    'skills.my_skill.an_attribute_name'\n    'vendor.author.[protocols|connections|skills].package_name.attribute_name\n\n**Arguments**:\n\n- `dotted_path`: dotted path to a setting.\n- `value`: a value to assign. Must be of yaml serializable type.\n- `author`: the author name, used to parse the dotted path.\n\n"
  },
  {
    "path": "docs/api/test_tools/test_cases.md",
    "content": "<a id=\"aea.test_tools.test_cases\"></a>\n\n# aea.test`_`tools.test`_`cases\n\nThis module contains test case classes based on pytest for AEA end-to-end testing.\n\n<a id=\"aea.test_tools.test_cases.BaseAEATestCase\"></a>\n\n## BaseAEATestCase Objects\n\n```python\nclass BaseAEATestCase(ABC)\n```\n\nBase class for AEA test cases.\n\n<a id=\"aea.test_tools.test_cases.BaseAEATestCase.set_agent_context\"></a>\n\n#### set`_`agent`_`context\n\n```python\n@classmethod\ndef set_agent_context(cls, agent_name: str) -> None\n```\n\nSet the current agent context.\n\n<a id=\"aea.test_tools.test_cases.BaseAEATestCase.unset_agent_context\"></a>\n\n#### unset`_`agent`_`context\n\n```python\n@classmethod\ndef unset_agent_context(cls) -> None\n```\n\nUnset the current agent context.\n\n<a id=\"aea.test_tools.test_cases.BaseAEATestCase.set_config\"></a>\n\n#### set`_`config\n\n```python\n@classmethod\ndef set_config(cls,\n               dotted_path: str,\n               value: Any,\n               type_: Optional[str] = None) -> Result\n```\n\nSet a config.\n\nRun from agent's directory.\n\n**Arguments**:\n\n- `dotted_path`: str dotted path to config param.\n- `value`: a new value to set.\n- `type_`: the type\n\n**Returns**:\n\nResult\n\n<a id=\"aea.test_tools.test_cases.BaseAEATestCase.nested_set_config\"></a>\n\n#### nested`_`set`_`config\n\n```python\n@classmethod\ndef nested_set_config(cls, dotted_path: str, value: Any) -> None\n```\n\nForce set config.\n\n<a id=\"aea.test_tools.test_cases.BaseAEATestCase.disable_aea_logging\"></a>\n\n#### disable`_`aea`_`logging\n\n```python\n@classmethod\ndef disable_aea_logging(cls) -> None\n```\n\nDisable AEA logging of specific agent.\n\nRun from agent's directory.\n\n<a id=\"aea.test_tools.test_cases.BaseAEATestCase.run_cli_command\"></a>\n\n#### run`_`cli`_`command\n\n```python\n@classmethod\ndef run_cli_command(cls, *args: str, cwd: str = \".\", **kwargs: str) -> Result\n```\n\nRun AEA CLI command.\n\n**Arguments**:\n\n- `args`: CLI args\n- `cwd`: the working directory from where to run the command.\n- `kwargs`: other keyword arguments to click.CliRunner.invoke.\n\n**Raises**:\n\n- `AEATestingException`: if command fails.\n\n**Returns**:\n\nResult\n\n<a id=\"aea.test_tools.test_cases.BaseAEATestCase.start_subprocess\"></a>\n\n#### start`_`subprocess\n\n```python\n@classmethod\ndef start_subprocess(cls, *args: str, cwd: str = \".\") -> subprocess.Popen\n```\n\nRun python with args as subprocess.\n\n**Arguments**:\n\n- `args`: CLI args\n- `cwd`: the current working directory\n\n**Returns**:\n\nsubprocess object.\n\n<a id=\"aea.test_tools.test_cases.BaseAEATestCase.start_thread\"></a>\n\n#### start`_`thread\n\n```python\n@classmethod\ndef start_thread(cls, target: Callable, **kwargs: subprocess.Popen) -> Thread\n```\n\nStart python Thread.\n\n**Arguments**:\n\n- `target`: target method.\n- `kwargs`: thread keyword arguments\n\n**Returns**:\n\nthread\n\n<a id=\"aea.test_tools.test_cases.BaseAEATestCase.create_agents\"></a>\n\n#### create`_`agents\n\n```python\n@classmethod\ndef create_agents(cls,\n                  *agents_names: str,\n                  is_local: bool = True,\n                  is_empty: bool = False) -> None\n```\n\nCreate agents in current working directory.\n\n**Arguments**:\n\n- `agents_names`: str agent names.\n- `is_local`: a flag for local folder add True by default.\n- `is_empty`: optional boolean flag for skip adding default dependencies.\n\n<a id=\"aea.test_tools.test_cases.BaseAEATestCase.fetch_agent\"></a>\n\n#### fetch`_`agent\n\n```python\n@classmethod\ndef fetch_agent(cls,\n                public_id: str,\n                agent_name: str,\n                is_local: bool = True) -> None\n```\n\nCreate agents in current working directory.\n\n**Arguments**:\n\n- `public_id`: str public id\n- `agent_name`: str agent name.\n- `is_local`: a flag for local folder add True by default.\n\n<a id=\"aea.test_tools.test_cases.BaseAEATestCase.difference_to_fetched_agent\"></a>\n\n#### difference`_`to`_`fetched`_`agent\n\n```python\n@classmethod\ndef difference_to_fetched_agent(cls, public_id: str,\n                                agent_name: str) -> List[str]\n```\n\nCompare agent against the one fetched from public id.\n\n**Arguments**:\n\n- `public_id`: str public id\n- `agent_name`: str agent name.\n\n**Returns**:\n\nlist of files differing in the projects\n\n<a id=\"aea.test_tools.test_cases.BaseAEATestCase.delete_agents\"></a>\n\n#### delete`_`agents\n\n```python\n@classmethod\ndef delete_agents(cls, *agents_names: str) -> None\n```\n\nDelete agents in current working directory.\n\n**Arguments**:\n\n- `agents_names`: str agent names.\n\n<a id=\"aea.test_tools.test_cases.BaseAEATestCase.run_agent\"></a>\n\n#### run`_`agent\n\n```python\n@classmethod\ndef run_agent(cls, *args: str) -> subprocess.Popen\n```\n\nRun agent as subprocess.\n\nRun from agent's directory.\n\n**Arguments**:\n\n- `args`: CLI args\n\n**Returns**:\n\nsubprocess object.\n\n<a id=\"aea.test_tools.test_cases.BaseAEATestCase.run_interaction\"></a>\n\n#### run`_`interaction\n\n```python\n@classmethod\ndef run_interaction(cls) -> subprocess.Popen\n```\n\nRun interaction as subprocess.\n\nRun from agent's directory.\n\n**Returns**:\n\nsubprocess object.\n\n<a id=\"aea.test_tools.test_cases.BaseAEATestCase.terminate_agents\"></a>\n\n#### terminate`_`agents\n\n```python\n@classmethod\ndef terminate_agents(cls,\n                     *subprocesses: subprocess.Popen,\n                     timeout: int = 20) -> None\n```\n\nTerminate agent subprocesses.\n\nRun from agent's directory.\n\n**Arguments**:\n\n- `subprocesses`: the subprocesses running the agents\n- `timeout`: the timeout for interruption\n\n<a id=\"aea.test_tools.test_cases.BaseAEATestCase.is_successfully_terminated\"></a>\n\n#### is`_`successfully`_`terminated\n\n```python\n@classmethod\ndef is_successfully_terminated(cls, *subprocesses: subprocess.Popen) -> bool\n```\n\nCheck if all subprocesses terminated successfully.\n\n<a id=\"aea.test_tools.test_cases.BaseAEATestCase.initialize_aea\"></a>\n\n#### initialize`_`aea\n\n```python\n@classmethod\ndef initialize_aea(cls, author: str) -> None\n```\n\nInitialize AEA locally with author name.\n\n<a id=\"aea.test_tools.test_cases.BaseAEATestCase.add_item\"></a>\n\n#### add`_`item\n\n```python\n@classmethod\ndef add_item(cls,\n             item_type: str,\n             public_id: str,\n             local: bool = True) -> Result\n```\n\nAdd an item to the agent.\n\nRun from agent's directory.\n\n**Arguments**:\n\n- `item_type`: str item type.\n- `public_id`: public id of the item.\n- `local`: a flag for local folder add True by default.\n\n**Returns**:\n\nResult\n\n<a id=\"aea.test_tools.test_cases.BaseAEATestCase.remove_item\"></a>\n\n#### remove`_`item\n\n```python\n@classmethod\ndef remove_item(cls, item_type: str, public_id: str) -> Result\n```\n\nRemove an item from the agent.\n\nRun from agent's directory.\n\n**Arguments**:\n\n- `item_type`: str item type.\n- `public_id`: public id of the item.\n\n**Returns**:\n\nResult\n\n<a id=\"aea.test_tools.test_cases.BaseAEATestCase.scaffold_item\"></a>\n\n#### scaffold`_`item\n\n```python\n@classmethod\ndef scaffold_item(cls,\n                  item_type: str,\n                  name: str,\n                  skip_consistency_check: bool = False) -> Result\n```\n\nScaffold an item for the agent.\n\nRun from agent's directory.\n\n**Arguments**:\n\n- `item_type`: str item type.\n- `name`: name of the item.\n- `skip_consistency_check`: if True, skip consistency check.\n\n**Returns**:\n\nResult\n\n<a id=\"aea.test_tools.test_cases.BaseAEATestCase.fingerprint_item\"></a>\n\n#### fingerprint`_`item\n\n```python\n@classmethod\ndef fingerprint_item(cls, item_type: str, public_id: str) -> Result\n```\n\nFingerprint an item for the agent.\n\nRun from agent's directory.\n\n**Arguments**:\n\n- `item_type`: str item type.\n- `public_id`: public id of the item.\n\n**Returns**:\n\nResult\n\n<a id=\"aea.test_tools.test_cases.BaseAEATestCase.eject_item\"></a>\n\n#### eject`_`item\n\n```python\n@classmethod\ndef eject_item(cls, item_type: str, public_id: str) -> Result\n```\n\nEject an item in the agent in quiet mode (i.e. no interaction).\n\nRun from agent's directory.\n\n**Arguments**:\n\n- `item_type`: str item type.\n- `public_id`: public id of the item.\n\n**Returns**:\n\nNone\n\n<a id=\"aea.test_tools.test_cases.BaseAEATestCase.run_install\"></a>\n\n#### run`_`install\n\n```python\n@classmethod\ndef run_install(cls) -> Result\n```\n\nExecute AEA CLI install command.\n\nRun from agent's directory.\n\n**Returns**:\n\nResult\n\n<a id=\"aea.test_tools.test_cases.BaseAEATestCase.generate_private_key\"></a>\n\n#### generate`_`private`_`key\n\n```python\n@classmethod\ndef generate_private_key(cls,\n                         ledger_api_id: str = DEFAULT_LEDGER,\n                         private_key_file: Optional[str] = None,\n                         password: Optional[str] = None) -> Result\n```\n\nGenerate AEA private key with CLI command.\n\nRun from agent's directory.\n\n**Arguments**:\n\n- `ledger_api_id`: ledger API ID.\n- `private_key_file`: the private key file.\n- `password`: the password.\n\n**Returns**:\n\nResult\n\n<a id=\"aea.test_tools.test_cases.BaseAEATestCase.add_private_key\"></a>\n\n#### add`_`private`_`key\n\n```python\n@classmethod\ndef add_private_key(cls,\n                    ledger_api_id: str = DEFAULT_LEDGER,\n                    private_key_filepath: str = DEFAULT_PRIVATE_KEY_FILE,\n                    connection: bool = False,\n                    password: Optional[str] = None) -> Result\n```\n\nAdd private key with CLI command.\n\nRun from agent's directory.\n\n**Arguments**:\n\n- `ledger_api_id`: ledger API ID.\n- `private_key_filepath`: private key filepath.\n- `connection`: whether or not the private key filepath is for a connection.\n- `password`: the password to encrypt private keys.\n\n**Returns**:\n\nResult\n\n<a id=\"aea.test_tools.test_cases.BaseAEATestCase.remove_private_key\"></a>\n\n#### remove`_`private`_`key\n\n```python\n@classmethod\ndef remove_private_key(cls,\n                       ledger_api_id: str = DEFAULT_LEDGER,\n                       connection: bool = False) -> Result\n```\n\nRemove private key with CLI command.\n\nRun from agent's directory.\n\n**Arguments**:\n\n- `ledger_api_id`: ledger API ID.\n- `connection`: whether or not the private key filepath is for a connection.\n\n**Returns**:\n\nResult\n\n<a id=\"aea.test_tools.test_cases.BaseAEATestCase.replace_private_key_in_file\"></a>\n\n#### replace`_`private`_`key`_`in`_`file\n\n```python\n@classmethod\ndef replace_private_key_in_file(\n        cls,\n        private_key: str,\n        private_key_filepath: str = DEFAULT_PRIVATE_KEY_FILE) -> None\n```\n\nReplace the private key in the provided file with the provided key.\n\n**Arguments**:\n\n- `private_key`: the private key\n- `private_key_filepath`: the filepath to the private key file\n\n**Raises**:\n\n- `None`: exception if file does not exist\n\n<a id=\"aea.test_tools.test_cases.BaseAEATestCase.generate_wealth\"></a>\n\n#### generate`_`wealth\n\n```python\n@classmethod\ndef generate_wealth(cls,\n                    ledger_api_id: str = DEFAULT_LEDGER,\n                    password: Optional[str] = None) -> Result\n```\n\nGenerate wealth with CLI command.\n\nRun from agent's directory.\n\n**Arguments**:\n\n- `ledger_api_id`: ledger API ID.\n- `password`: the password.\n\n**Returns**:\n\nResult\n\n<a id=\"aea.test_tools.test_cases.BaseAEATestCase.get_wealth\"></a>\n\n#### get`_`wealth\n\n```python\n@classmethod\ndef get_wealth(cls,\n               ledger_api_id: str = DEFAULT_LEDGER,\n               password: Optional[str] = None) -> str\n```\n\nGet wealth with CLI command.\n\nRun from agent's directory.\n\n**Arguments**:\n\n- `ledger_api_id`: ledger API ID.\n- `password`: the password to encrypt/decrypt private keys.\n\n**Returns**:\n\ncommand line output\n\n<a id=\"aea.test_tools.test_cases.BaseAEATestCase.get_address\"></a>\n\n#### get`_`address\n\n```python\n@classmethod\ndef get_address(cls,\n                ledger_api_id: str = DEFAULT_LEDGER,\n                password: Optional[str] = None) -> str\n```\n\nGet address with CLI command.\n\nRun from agent's directory.\n\n**Arguments**:\n\n- `ledger_api_id`: ledger API ID.\n- `password`: the password to encrypt/decrypt private keys.\n\n**Returns**:\n\ncommand line output\n\n<a id=\"aea.test_tools.test_cases.BaseAEATestCase.replace_file_content\"></a>\n\n#### replace`_`file`_`content\n\n```python\n@classmethod\ndef replace_file_content(cls, src: Path, dest: Path) -> None\n```\n\nReplace the content of the source file to the destination file.\n\n**Arguments**:\n\n- `src`: the source file.\n- `dest`: the destination file.\n\n<a id=\"aea.test_tools.test_cases.BaseAEATestCase.change_directory\"></a>\n\n#### change`_`directory\n\n```python\n@classmethod\ndef change_directory(cls, path: Path) -> None\n```\n\nChange current working directory.\n\n**Arguments**:\n\n- `path`: path to the new working directory.\n\n<a id=\"aea.test_tools.test_cases.BaseAEATestCase.send_envelope_to_agent\"></a>\n\n#### send`_`envelope`_`to`_`agent\n\n```python\n@classmethod\ndef send_envelope_to_agent(cls, envelope: Envelope, agent: str) -> None\n```\n\nSend an envelope to an agent, using the stub connection.\n\n<a id=\"aea.test_tools.test_cases.BaseAEATestCase.read_envelope_from_agent\"></a>\n\n#### read`_`envelope`_`from`_`agent\n\n```python\n@classmethod\ndef read_envelope_from_agent(cls, agent: str) -> Envelope\n```\n\nRead an envelope from an agent, using the stub connection.\n\n<a id=\"aea.test_tools.test_cases.BaseAEATestCase.missing_from_output\"></a>\n\n#### missing`_`from`_`output\n\n```python\n@classmethod\ndef missing_from_output(cls,\n                        process: subprocess.Popen,\n                        strings: Sequence[str],\n                        timeout: int = DEFAULT_PROCESS_TIMEOUT,\n                        period: int = 1,\n                        is_terminating: bool = True) -> List[str]\n```\n\nCheck if strings are present in process output.\n\nRead process stdout in thread and terminate when all strings are present\nor timeout expired.\n\n**Arguments**:\n\n- `process`: agent subprocess.\n- `strings`: tuple of strings expected to appear in output.\n- `timeout`: int amount of seconds before stopping check.\n- `period`: int period of checking.\n- `is_terminating`: whether or not the agents are terminated\n\n**Returns**:\n\nlist of missed strings.\n\n<a id=\"aea.test_tools.test_cases.BaseAEATestCase.is_running\"></a>\n\n#### is`_`running\n\n```python\n@classmethod\ndef is_running(cls,\n               process: subprocess.Popen,\n               timeout: int = DEFAULT_LAUNCH_TIMEOUT) -> bool\n```\n\nCheck if the AEA is launched and running (ready to process messages).\n\n**Arguments**:\n\n- `process`: agent subprocess.\n- `timeout`: the timeout to wait for launch to complete\n\n**Returns**:\n\nbool indicating status\n\n<a id=\"aea.test_tools.test_cases.BaseAEATestCase.invoke\"></a>\n\n#### invoke\n\n```python\n@classmethod\ndef invoke(cls, *args: str) -> Result\n```\n\nCall the cli command.\n\n<a id=\"aea.test_tools.test_cases.BaseAEATestCase.load_agent_config\"></a>\n\n#### load`_`agent`_`config\n\n```python\n@classmethod\ndef load_agent_config(cls, agent_name: str) -> AgentConfig\n```\n\nLoad agent configuration.\n\n<a id=\"aea.test_tools.test_cases.BaseAEATestCase.setup_class\"></a>\n\n#### setup`_`class\n\n```python\n@classmethod\ndef setup_class(cls) -> None\n```\n\nSet up the test class.\n\n<a id=\"aea.test_tools.test_cases.BaseAEATestCase.teardown_class\"></a>\n\n#### teardown`_`class\n\n```python\n@classmethod\ndef teardown_class(cls) -> None\n```\n\nTeardown the test.\n\n<a id=\"aea.test_tools.test_cases.AEATestCaseEmpty\"></a>\n\n## AEATestCaseEmpty Objects\n\n```python\nclass AEATestCaseEmpty(BaseAEATestCase)\n```\n\nTest case for a default AEA project.\n\nThis test case will create a default AEA project.\n\n<a id=\"aea.test_tools.test_cases.AEATestCaseEmpty.setup_class\"></a>\n\n#### setup`_`class\n\n```python\n@classmethod\ndef setup_class(cls) -> None\n```\n\nSet up the test class.\n\n<a id=\"aea.test_tools.test_cases.AEATestCaseEmpty.teardown_class\"></a>\n\n#### teardown`_`class\n\n```python\n@classmethod\ndef teardown_class(cls) -> None\n```\n\nTeardown the test class.\n\n<a id=\"aea.test_tools.test_cases.AEATestCaseEmptyFlaky\"></a>\n\n## AEATestCaseEmptyFlaky Objects\n\n```python\nclass AEATestCaseEmptyFlaky(AEATestCaseEmpty)\n```\n\nTest case for a default AEA project.\n\nThis test case will create a default AEA project.\n\nUse for flaky tests with the flaky decorator.\n\n<a id=\"aea.test_tools.test_cases.AEATestCaseEmptyFlaky.setup_class\"></a>\n\n#### setup`_`class\n\n```python\n@classmethod\ndef setup_class(cls) -> None\n```\n\nSet up the test class.\n\n<a id=\"aea.test_tools.test_cases.AEATestCaseEmptyFlaky.teardown_class\"></a>\n\n#### teardown`_`class\n\n```python\n@classmethod\ndef teardown_class(cls) -> None\n```\n\nTeardown the test class.\n\n<a id=\"aea.test_tools.test_cases.AEATestCaseMany\"></a>\n\n## AEATestCaseMany Objects\n\n```python\nclass AEATestCaseMany(BaseAEATestCase)\n```\n\nTest case for many AEA projects.\n\n<a id=\"aea.test_tools.test_cases.AEATestCaseMany.setup_class\"></a>\n\n#### setup`_`class\n\n```python\n@classmethod\ndef setup_class(cls) -> None\n```\n\nSet up the test class.\n\n<a id=\"aea.test_tools.test_cases.AEATestCaseMany.teardown_class\"></a>\n\n#### teardown`_`class\n\n```python\n@classmethod\ndef teardown_class(cls) -> None\n```\n\nTeardown the test class.\n\n<a id=\"aea.test_tools.test_cases.AEATestCaseManyFlaky\"></a>\n\n## AEATestCaseManyFlaky Objects\n\n```python\nclass AEATestCaseManyFlaky(AEATestCaseMany)\n```\n\nTest case for many AEA projects which are flaky.\n\nUse for flaky tests with the flaky decorator.\n\n<a id=\"aea.test_tools.test_cases.AEATestCaseManyFlaky.setup_class\"></a>\n\n#### setup`_`class\n\n```python\n@classmethod\ndef setup_class(cls) -> None\n```\n\nSet up the test class.\n\n<a id=\"aea.test_tools.test_cases.AEATestCaseManyFlaky.teardown_class\"></a>\n\n#### teardown`_`class\n\n```python\n@classmethod\ndef teardown_class(cls) -> None\n```\n\nTeardown the test class.\n\n<a id=\"aea.test_tools.test_cases.AEATestCase\"></a>\n\n## AEATestCase Objects\n\n```python\nclass AEATestCase(BaseAEATestCase)\n```\n\nTest case from an existing AEA project.\n\nSubclass this class and set `path_to_aea` properly. By default,\nit is assumed the project is inside the current working directory.\n\n<a id=\"aea.test_tools.test_cases.AEATestCase.setup_class\"></a>\n\n#### setup`_`class\n\n```python\n@classmethod\ndef setup_class(cls) -> None\n```\n\nSet up the test class.\n\n<a id=\"aea.test_tools.test_cases.AEATestCase.teardown_class\"></a>\n\n#### teardown`_`class\n\n```python\n@classmethod\ndef teardown_class(cls) -> None\n```\n\nTeardown the test class.\n\n"
  },
  {
    "path": "docs/api/test_tools/test_contract.md",
    "content": "<a id=\"aea.test_tools.test_contract\"></a>\n\n# aea.test`_`tools.test`_`contract\n\nThis module contains test case classes based on pytest for AEA contract testing.\n\n<a id=\"aea.test_tools.test_contract.BaseContractTestCase\"></a>\n\n## BaseContractTestCase Objects\n\n```python\nclass BaseContractTestCase(ABC)\n```\n\nA class to test a contract.\n\n<a id=\"aea.test_tools.test_contract.BaseContractTestCase.contract\"></a>\n\n#### contract\n\n```python\n@property\ndef contract() -> Contract\n```\n\nGet the contract.\n\n<a id=\"aea.test_tools.test_contract.BaseContractTestCase.setup\"></a>\n\n#### setup\n\n```python\n@classmethod\ndef setup(cls, **kwargs: Any) -> None\n```\n\nSet up the contract test case.\n\n<a id=\"aea.test_tools.test_contract.BaseContractTestCase.finish_contract_deployment\"></a>\n\n#### finish`_`contract`_`deployment\n\n```python\n@classmethod\n@abstractmethod\ndef finish_contract_deployment(cls) -> str\n```\n\nFinish deploying contract.\n\n**Returns**:\n\ncontract address\n\n<a id=\"aea.test_tools.test_contract.BaseContractTestCase.refill_from_faucet\"></a>\n\n#### refill`_`from`_`faucet\n\n```python\n@staticmethod\ndef refill_from_faucet(ledger_api: LedgerApi, faucet_api: FaucetApi,\n                       address: str) -> None\n```\n\nRefill from faucet.\n\n<a id=\"aea.test_tools.test_contract.BaseContractTestCase.sign_send_confirm_receipt_multisig_transaction\"></a>\n\n#### sign`_`send`_`confirm`_`receipt`_`multisig`_`transaction\n\n```python\n@staticmethod\ndef sign_send_confirm_receipt_multisig_transaction(\n        tx: JSONLike,\n        ledger_api: LedgerApi,\n        cryptos: List[Crypto],\n        sleep_time: float = 2.0) -> JSONLike\n```\n\nSign, send and confirm settlement of a transaction with multiple signatures.\n\n**Arguments**:\n\n- `tx`: the transaction\n- `ledger_api`: the ledger api\n- `cryptos`: Cryptos to sign transaction with\n- `sleep_time`: the time to sleep between transaction submission and receipt request\n\n**Returns**:\n\nThe transaction receipt\n\n<a id=\"aea.test_tools.test_contract.BaseContractTestCase.sign_send_confirm_receipt_transaction\"></a>\n\n#### sign`_`send`_`confirm`_`receipt`_`transaction\n\n```python\n@classmethod\ndef sign_send_confirm_receipt_transaction(cls,\n                                          tx: JSONLike,\n                                          ledger_api: LedgerApi,\n                                          crypto: Crypto,\n                                          sleep_time: float = 2.0) -> JSONLike\n```\n\nSign, send and confirm settlement of a transaction with multiple signatures.\n\n**Arguments**:\n\n- `tx`: the transaction\n- `ledger_api`: the ledger api\n- `crypto`: Crypto to sign transaction with\n- `sleep_time`: the time to sleep between transaction submission and receipt request\n\n**Returns**:\n\nThe transaction receipt\n\n"
  },
  {
    "path": "docs/api/test_tools/test_skill.md",
    "content": "<a id=\"aea.test_tools.test_skill\"></a>\n\n# aea.test`_`tools.test`_`skill\n\nThis module contains test case classes based on pytest for AEA skill testing.\n\n<a id=\"aea.test_tools.test_skill.BaseSkillTestCase\"></a>\n\n## BaseSkillTestCase Objects\n\n```python\nclass BaseSkillTestCase()\n```\n\nA class to test a skill.\n\n<a id=\"aea.test_tools.test_skill.BaseSkillTestCase.skill\"></a>\n\n#### skill\n\n```python\n@property\ndef skill() -> Skill\n```\n\nGet the skill.\n\n<a id=\"aea.test_tools.test_skill.BaseSkillTestCase.get_quantity_in_outbox\"></a>\n\n#### get`_`quantity`_`in`_`outbox\n\n```python\ndef get_quantity_in_outbox() -> int\n```\n\nGet the quantity of envelopes in the outbox.\n\n<a id=\"aea.test_tools.test_skill.BaseSkillTestCase.get_message_from_outbox\"></a>\n\n#### get`_`message`_`from`_`outbox\n\n```python\ndef get_message_from_outbox() -> Optional[Message]\n```\n\nGet message from outbox.\n\n<a id=\"aea.test_tools.test_skill.BaseSkillTestCase.drop_messages_from_outbox\"></a>\n\n#### drop`_`messages`_`from`_`outbox\n\n```python\ndef drop_messages_from_outbox(number: int = 1) -> None\n```\n\nDismiss the first 'number' number of message from outbox.\n\n<a id=\"aea.test_tools.test_skill.BaseSkillTestCase.get_quantity_in_decision_maker_inbox\"></a>\n\n#### get`_`quantity`_`in`_`decision`_`maker`_`inbox\n\n```python\ndef get_quantity_in_decision_maker_inbox() -> int\n```\n\nGet the quantity of messages in the decision maker inbox.\n\n<a id=\"aea.test_tools.test_skill.BaseSkillTestCase.get_message_from_decision_maker_inbox\"></a>\n\n#### get`_`message`_`from`_`decision`_`maker`_`inbox\n\n```python\ndef get_message_from_decision_maker_inbox() -> Optional[Message]\n```\n\nGet message from decision maker inbox.\n\n<a id=\"aea.test_tools.test_skill.BaseSkillTestCase.drop_messages_from_decision_maker_inbox\"></a>\n\n#### drop`_`messages`_`from`_`decision`_`maker`_`inbox\n\n```python\ndef drop_messages_from_decision_maker_inbox(number: int = 1) -> None\n```\n\nDismiss the first 'number' number of message from decision maker inbox.\n\n<a id=\"aea.test_tools.test_skill.BaseSkillTestCase.assert_quantity_in_outbox\"></a>\n\n#### assert`_`quantity`_`in`_`outbox\n\n```python\ndef assert_quantity_in_outbox(expected_quantity: int) -> None\n```\n\nAssert the quantity of messages in the outbox.\n\n<a id=\"aea.test_tools.test_skill.BaseSkillTestCase.assert_quantity_in_decision_making_queue\"></a>\n\n#### assert`_`quantity`_`in`_`decision`_`making`_`queue\n\n```python\ndef assert_quantity_in_decision_making_queue(expected_quantity: int) -> None\n```\n\nAssert the quantity of messages in the decision maker queue.\n\n<a id=\"aea.test_tools.test_skill.BaseSkillTestCase.message_has_attributes\"></a>\n\n#### message`_`has`_`attributes\n\n```python\n@staticmethod\ndef message_has_attributes(actual_message: Message,\n                           message_type: Type[Message],\n                           **kwargs: Any) -> Tuple[bool, str]\n```\n\nEvaluates whether a message's attributes match the expected attributes provided.\n\n**Arguments**:\n\n- `actual_message`: the actual message\n- `message_type`: the expected message type\n- `kwargs`: other expected message attributes\n\n**Returns**:\n\nboolean result of the evaluation and accompanied message\n\n<a id=\"aea.test_tools.test_skill.BaseSkillTestCase.build_incoming_message\"></a>\n\n#### build`_`incoming`_`message\n\n```python\ndef build_incoming_message(message_type: Type[Message],\n                           performative: Message.Performative,\n                           dialogue_reference: Optional[Tuple[str,\n                                                              str]] = None,\n                           message_id: Optional[int] = None,\n                           target: Optional[int] = None,\n                           to: Optional[Address] = None,\n                           sender: Optional[Address] = None,\n                           is_agent_to_agent_messages: Optional[bool] = None,\n                           **kwargs: Any) -> Message\n```\n\nQuickly create an incoming message with the provided attributes.\n\nFor any attribute not provided, the corresponding default value in message is used.\n\n**Arguments**:\n\n- `message_type`: the type of the message\n- `dialogue_reference`: the dialogue_reference\n- `message_id`: the message_id\n- `target`: the target\n- `performative`: the performative\n- `to`: the 'to' address\n- `sender`: the 'sender' address\n- `is_agent_to_agent_messages`: whether the dialogue is between agents or components\n- `kwargs`: other attributes\n\n**Returns**:\n\nthe created incoming message\n\n<a id=\"aea.test_tools.test_skill.BaseSkillTestCase.build_incoming_message_for_skill_dialogue\"></a>\n\n#### build`_`incoming`_`message`_`for`_`skill`_`dialogue\n\n```python\ndef build_incoming_message_for_skill_dialogue(\n        dialogue: Dialogue,\n        performative: Message.Performative,\n        message_type: Optional[Type[Message]] = None,\n        dialogue_reference: Optional[Tuple[str, str]] = None,\n        message_id: Optional[int] = None,\n        target: Optional[int] = None,\n        to: Optional[Address] = None,\n        sender: Optional[Address] = None,\n        **kwargs: Any) -> Message\n```\n\nQuickly create an incoming message with the provided attributes for a dialogue.\n\nFor any attribute not provided, a value based on the dialogue is used.\nThese values are shown in parentheses in the list of parameters below.\n\nNOTE: This method must be used with care. The dialogue provided is part of the skill\nwhich is being tested. Because for any unspecified attribute, a \"correct\" value is used,\nthe test will be, by design, insured to pass on these values.\n\n**Arguments**:\n\n- `dialogue`: the dialogue to which the incoming message is intended\n- `performative`: the performative of the message\n- `message_type`: (the message_class of the provided dialogue) the type of the message\n- `dialogue_reference`: (the dialogue_reference of the provided dialogue) the dialogue reference of the message\n- `message_id`: (the id of the last message in the provided dialogue + 1) the id of the message\n- `target`: (the id of the last message in the provided dialogue) the target of the message\n- `to`: (the agent address associated with this skill) the receiver of the message\n- `sender`: (the counterparty in the provided dialogue) the sender of the message\n- `kwargs`: other attributes\n\n**Returns**:\n\nthe created incoming message\n\n<a id=\"aea.test_tools.test_skill.BaseSkillTestCase.prepare_skill_dialogue\"></a>\n\n#### prepare`_`skill`_`dialogue\n\n```python\ndef prepare_skill_dialogue(\n        dialogues: Dialogues,\n        messages: Tuple[DialogueMessage, ...],\n        counterparty: Optional[Address] = None,\n        is_agent_to_agent_messages: Optional[bool] = None) -> Dialogue\n```\n\nQuickly create a dialogue.\n\nThe 'messages' argument is a tuple of DialogueMessages.\nFor every DialogueMessage (performative, contents, is_incoming, target):\n    - if 'is_incoming' is not provided: for the first message it is assumed False (outgoing),\n    for any other message, it is the opposite of the one preceding it.\n    - if 'target' is not provided: for the first message it is assumed 0,\n    for any other message, it is the index of the message before it in the tuple of messages + 1.\n\n**Arguments**:\n\n- `dialogues`: a dialogues class\n- `counterparty`: the message_id\n- `messages`: the dialogue_reference\n- `is_agent_to_agent_messages`: whether the dialogue is between agents or components\n\n**Returns**:\n\nthe created incoming message\n\n<a id=\"aea.test_tools.test_skill.BaseSkillTestCase.setup\"></a>\n\n#### setup\n\n```python\n@classmethod\ndef setup(cls, **kwargs: Any) -> None\n```\n\nSet up the skill test case.\n\n"
  },
  {
    "path": "docs/application.md",
    "content": "# Application Areas\n\n## Environments\n\nAEAs are most suited for environments which are:\n\n- **Decentralized**: there isn't a central authority that controls, manages, or makes decisions.\n- **Multi-Stakeholder**: the domain, problem, or solutions involve multiple distinct stakeholders.\n- **Peer-to-Peer**: interactions are (or could be made) direct and peer-to-peer.\n- **Complex, Incomplete, and Uncertain**: to the point that off-loading tasks to computational entities becomes valuable.\n\n## Applications\n\nWe identify a number of application areas for AEA-based solutions. This list is by no means comprehensive. In fact, we are most excited about applications which we have not thought of before.\n\n**Automation**\n\n:   AEAs can automate well-defined processes in different domains, such as supply chain, mobility, finance, ...\n\n**Micro-transactions**\n\n:   AEAs make it economically viable to execute trade involving small values. An example is use-cases with many small sellers (e.g. of data) on the supply side.\n\n**Wallet**\n\n:   AEAs can simplify interactions with blockchains. By acting as \"smart wallets\", they can hide away the majority of the complexities involved in using blockchains for end users.\n\n**IoT**\n\n:   Agents representing objects in the IoT (Internet of Things) space. For example, AEAs paired with hardware devices such as drones, laptops, heat sensors, etc., providing control and receiving data from the device. An example is a <a href=\"../thermometer-skills\"> thermometer agent</a>.\n\n**Web 2.0 <--> Web 3.0 interface**\n\n:   Agents that interface and bridge the gap between existing (Web 2.0) and new (Web 3.0) economic models. An example is an <a href=\"../http-connection-and-skill\"> AEA that communicates with HTTP clients/servers</a>.\n\n**Digital data sales**\n\n:   Agents with access to some data sources that sell the data, access to the data, or access to the usage of the data. An example is an <a href=\"../ml-skills\">AEA that continuously sells data to another AEA</a>, who in turn uses it to improve their reinforcement learning model.\n\n## Multi-Agent System VS Agent-Based Modelling\n\nThe AEA framework enables the creation of multi-agent systems as technological solutions to real world problems. \n\nAlthough there are some overlap, the framework is not designed from the outset as an agent-based modelling software, where the goal is scientific behavioural observation rather than practical economic gain.\n\nMoreover, there is no restriction to _multi_; single-agent applications are also supported.\n"
  },
  {
    "path": "docs/aries-cloud-agent-demo.md",
    "content": "# Aries Cloud Agents Demo\n\n!!! note\n    This demo is incomplete and will soon be updated.\n\nDemonstrating an entire decentralized identity scenario involving AEAs and instances of Aries Cloud Agents (ACAs).\n\n## Discussion\n\nThis demo corresponds with the one <a href=\"https://github.com/hyperledger/aries-cloudagent-python/blob/main/demo/README.md\" target=\"_blank\">here</a> from <a href=\"https://github.com/hyperledger/aries-cloudagent-python\" target=\"_blank\"> Aries cloud agent repository </a>.\n\nThe aim of this demo is to illustrate how AEAs can connect to ACAs, thus gaining all of their capabilities, such as issuing and requesting verifiable credentials, selective disclosure and zero knowledge proofs.\n\n``` mermaid\n    sequenceDiagram\n        participant faea as Faber_AEA\n        participant faca as Faber_ACA\n        participant aaca as Alice_ACA\n        participant aaea as Alice_AEA\n\n        activate faea\n        activate faca\n        activate aaca\n        activate aaea\n\n        Note right of aaea: Shows P2P ID\n\n        faea->>faca: Request status?\n        faca->>faea: status\n        faea->>faca: Register schema\n        faca->>faea: schema_id\n        faea->>faca: Register credential definition\n        faca->>faea: credential_definition_id\n        faea->>faca: create-invitation\n        faca->>faea: connection inc. invitation\n        faea->>aaea: invitation detail\n        aaea->>aaca: receive-invitation\n\n        deactivate faea\n        deactivate faca\n        deactivate aaca\n        deactivate aaea\n```\n\nThere are two AEAs:\n\n- **Alice_AEA**\n- **Faber_AEA**\n\nand two ACAs:\n\n- **Alice_ACA**\n- **Faber_ACA**\n\nEach AEA is connected to its corresponding ACA: **Alice_AEA** to **Alice_ACA** and **Faber_AEA** to **Faber_ACA**.\n\nThe following lists the sequence of interactions between the four agents:\n\n- **Alice_AEA**: starts\n- **Alice_AEA**: shows its P2P address in the terminal and waits for an `invitation` detail from **Faber_AEA**.\n- **Alice_AEA**: registers itself on the SOEF.\n- **Faber_AEA**: starts\n- **Faber_AEA**: searches the SOEF and finds **Alice_AEA**.\n- **Faber_AEA**: tests its connection to **Faber_ACA**.\n- **Faber_ACA**: responds to **Faber_AEA**.\n- **Faber_AEA**: registers a DID on the ledger.\n- **Faber_AEA**: request **Faber_ACA** to register a schema on the ledger.\n- **Faber_ACA**: responds by sending back the `schema_id`.\n- **Faber_AEA**: request **Faber_ACA** to register a credential definition on the ledger.\n- **Faber_ACA**: responds by sending back the `credential_definition_id`.\n- **Faber_AEA**: requests **Faber_ACA** to create an invitation.\n- **Faber_ACA**: responds by sending back the `connection` detail, which contains an `invitation` field.\n- **Faber_AEA**: sends the `invitation` detail to **Alice_AEA**.\n- **Alice_AEA**: receives `invitation` detail from **Faber_AEA**.\n- **Alice_AEA**: requests **Alice_ACA** to accept the invitation, by passing it the `invitation` detail it received in the last step.\n\nAll messages from an AEA to an ACA are http requests (using `http_client` connection).\n\nAll messages from an AEA to another AEA utilise the P2P communication network accessed via the `p2p_libp2p` connection.\n\nAll messages initiated from an ACA to an AEA are webhooks (using `webhook` connection).\n\nThis is the extent of the demo at this point. The rest of the interactions require an instance of the <a href=\"https://github.com/bcgov/von-network\" target=\"_blank\">Indy ledger</a> to run. This is what will be implemented next.\n\nThe rest of the interactions are broadly as follows:\n\n- **Alice_ACA**: accepts the invitation.\n- **Alice_ACA**: sends a matching invitation request to **Faber_ACA**.\n- **Faber_ACA**: accepts\n\nAt this point, the two ACAs are connected to each other.\n\n- **Faber_AEA**: requests **Faber_ACA** to issue a credential (e.g. university degree) to **Alice_AEA**, which **Faber_ACA** does via **Alice_ACA**.\n- **Faber_AEA**: requests proof that **Alice_AEA**'s age is above 18.\n- **Alice_AEA**: presents proof that it's age is above 18, without presenting its credential.\n\n## Preparation Instructions\n\n### Dependencies\n\nFollow the <a href=\"../quickstart/#preliminaries\">Preliminaries</a> and <a href=\"../quickstart/#installation\">Installation</a> sections from the AEA quick start.\n\nInstall Aries cloud-agents (for more info see <a href=\"https://github.com/hyperledger/aries-cloudagent-python#install\" target=\"_blank\">here</a>) if you do not have it on your machine:\n\n``` bash\npip install aries-cloudagent\n```\n\nThis demo has been successfully tested with `aca-py` version `0.4.5`.\n\nThis demo requires an instance of von network running in docker locally (for more info see <a href=\"https://github.com/bcgov/von-network#running-the-network-locally\" target=\"_blank\">here</a>)\n\nThis demo has been successfully tested with the von-network git repository pulled on 07 Aug 2020 (commit number `ad1f84f64d4f4c106a81462f5fbff496c5fbf10e`).\n\n### Terminals\n\nOpen five terminals. The first terminal is used to run an instance of von-network locally in docker. The other four terminals will be used to run each of the four agents in this demo.\n\n## VON Network\n\nIn the first terminal move to the `von-network` directory and run an instance of `von-network` locally in docker.\n\nThis <a href=\"https://github.com/bcgov/von-network#running-the-network-locally\" target=\"_blank\">tutorial</a> has information on starting (and stopping) the network locally.\n\n``` bash\n./manage build\n./manage start --logs\n```\n\nOnce the ledger is running, you can see the ledger by going to the web server running on port 9000. On localhost, that means going to <a href=\"http://localhost:9000\" target=\"_blank\">http://localhost:9000</a>.  \n\n## Alice and Faber ACAs\n\nTo learn about the command for starting an ACA and its various options:\n\n``` bash\naca-py start --help\n```\n\n### Faber_ACA\n\nIn the first terminal:\n\n``` bash\naca-py start --admin 127.0.0.1 8021 --admin-insecure-mode --inbound-transport http 0.0.0.0 8020 --outbound-transport http --webhook-url http://127.0.0.1:8022/webhooks\n```\n\nMake sure the ports above are unused.\n\nTake note of the specific IP addresses and ports you used in the above command. We will refer to them by the following names:\n\n- **Faber admin IP**: 127.0.0.1\n- **Faber admin port**: 8021\n- **Faber webhook port**: 8022\n\nThe admin IP and port will be used to send administrative commands to this ACA from an AEA.\n\nThe webhook port is where the ACA will send notifications to. We will expose this from the AEA so it receives this ACA's notifications.\n\n### Alice_ACA\n\nIn the second terminal:\n\n``` bash\naca-py start --admin 127.0.0.1 8031 --admin-insecure-mode --inbound-transport http 0.0.0.0 8030 --outbound-transp http --webhook-url http://127.0.0.1:8032/webhooks\n```\n\nAgain, make sure the above ports are unused and take note of the specific IP addresses and ports. In this case:\n\n- **Alice admin IP**: 127.0.0.1\n- **Alice admin port**: 8031\n- **Alice webhook port**: 8032\n\n## Alice and Faber AEAs\n\nNow you can create **Alice_AEA** and **Faber_AEA** in terminals 3 and 4 respectively.\n\n### Alice_AEA\n\nIn the third terminal, fetch **Alice_AEA** and move into its project folder:\n\n``` bash\naea fetch fetchai/aries_alice:0.32.5\ncd aries_alice\n```\n\n??? note \"Alternatively, create from scratch:\"\n\n    The following steps create **Alice_AEA** from scratch:\n\n    ``` bash\n    aea create aries_alice\n    cd aries_alice\n    aea add connection fetchai/p2p_libp2p:0.27.5\n    aea add connection fetchai/soef:0.27.6\n    aea add connection fetchai/http_client:0.24.6\n    aea add connection fetchai/webhook:0.20.6\n    aea add skill fetchai/aries_alice:0.26.6\n    ```\n\n#### Configure the `aries_alice` Skill\n\n(configuration file: `alice/vendor/fetchai/skills/aries_alice/skill.yaml`)\n\nEnsure `admin_host` and `admin_port` values match with the values you noted above for **Alice_ACA**. You can use the framework's handy `config` <a href=\"../cli-commands\">CLI command</a> to set these values:\n\n``` bash\naea config set vendor.fetchai.skills.aries_alice.models.strategy.args.admin_host 127.0.0.1\n```\n\n``` bash\naea config set --type int vendor.fetchai.skills.aries_alice.models.strategy.args.admin_port 8031\n```\n\n#### Configure the `webhook` Connection\n\n(configuration file: `alice/vendor/fetchai/connections/webhook/connection.yaml`).\n\nFirst ensure the value of `webhook_port` matches with what you used above for **Alice_ACA**.\n\n``` bash\naea config set --type int vendor.fetchai.connections.webhook.config.webhook_port 8032\n```\n\nNext, make sure the value of `webhook_url_path` is `/webhooks/topic/{topic}/`.\n\n``` bash\naea config set vendor.fetchai.connections.webhook.config.webhook_url_path /webhooks/topic/{topic}/\n```\n\n#### Configure the `p2p_libp2p` Connection\n\n``` bash\naea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \\\n'{\n  \"delegate_uri\": \"127.0.0.1:11000\",\n  \"entry_peers\": [],\n  \"local_uri\": \"127.0.0.1:7000\",\n  \"log_file\": \"libp2p_node.log\",\n  \"public_uri\": \"127.0.0.1:7000\"\n}'\n```\n\n### Install the Dependencies and Run Alice_AEA\n\nNow install all the dependencies:\n\n``` bash\naea install\naea build\n```\n\nFinally, run **Alice_AEA**:\n\n``` bash\naea run\n```\n\nOnce you see a message of the form `To join its network use multiaddr 'SOME_ADDRESS'` take note of the address. (Alternatively, use `aea get-multiaddress fetchai -c -i fetchai/p2p_libp2p:0.27.5 -u public_uri` to retrieve the address.) We will refer to this as **Alice_AEA's P2P address**.\n\n### Faber_AEA\n\nIn the fourth terminal, fetch **Faber_AEA** and move into its project folder:\n\n``` bash\naea fetch fetchai/aries_faber:0.32.5\ncd aries_faber\n```\n\n??? note \"Alternatively, create from scratch:\"\n    The following steps create **Faber_AEA** from scratch:\n\n    ``` bash\n    aea create aries_faber\n    cd aries_faber\n    aea add connection fetchai/p2p_libp2p:0.27.5\n    aea add connection fetchai/soef:0.27.6\n    aea add connection fetchai/http_client:0.24.6\n    aea add connection fetchai/webhook:0.20.6\n    aea add skill fetchai/aries_faber:0.24.5\n    ```\n\n#### Configure the `aries_faber` Skill\n\n(configuration file: `faber/vendor/fetchai/skills/aries_alice/skill.yaml`)\n\nEnsure `admin_host` and `admin_port` values match with those you noted above for **Faber_ACA**.\n\n``` bash\naea config set vendor.fetchai.skills.aries_faber.models.strategy.args.admin_host 127.0.0.1\n```\n\n``` bash\naea config set --type int vendor.fetchai.skills.aries_faber.models.strategy.args.admin_port 8021\n```\n\n#### Configure the `webhook` Connection\n\n(configuration file: `faber/vendor/fetchai/connections/webhook/connection.yaml`).\n\nFirst, ensure the value of `webhook_port` matches with what you used above for **Faber_ACA**.\n\n``` bash\naea config set --type int vendor.fetchai.connections.webhook.config.webhook_port 8022\n```\n\nNext, make sure the value of `webhook_url_path` is `/webhooks/topic/{topic}/`.\n\n``` bash\naea config set vendor.fetchai.connections.webhook.config.webhook_url_path /webhooks/topic/{topic}/\n```\n\n#### Configure the `p2p_libp2p` Connection\n\n``` bash\naea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \\\n'{\n  \"delegate_uri\": \"127.0.0.1:11001\",\n  \"entry_peers\": [\"SOME_ADDRESS\"],\n  \"local_uri\": \"127.0.0.1:7001\",\n  \"log_file\": \"libp2p_node.log\",\n  \"public_uri\": \"127.0.0.1:7001\"\n}'\n```\n\nwhere `SOME_ADDRESS` is **Alice_AEA's P2P address** as displayed in the third terminal.\n\n### Install the Dependencies and Run Faber_AEA\n\nNow install all the dependencies:\n\n``` bash\naea install\naea build\n```\n\nFinally run **Faber_AEA**:\n\n``` bash\naea run\n```\n\nYou should see **Faber_AEA** running and showing logs of its activities. For example:\n\n<img src=\"../assets/aries-demo-faber.png\" alt=\"Aries demo: Faber terminal\" class=\"center\">\n\nLooking now at **Alice_AEA** terminal, you should also see more activity by **Alice_AEA** after **Faber_AEA** was started. For example:\n\n<img src=\"../assets/aries-demo-alice.png\" alt=\"Aries demo: Alice terminal\" class=\"center\">\n\nThe last error line in **Alice_AEA**'s terminal is caused due to the absence of an Indy ledger instance. In the next update to this demo, this will be resolved.\n\n## Terminate and Delete the Agents\n\nYou can terminate each agent by pressing Ctrl+C.\n\nTo delete the AEAs, go to the projects' parent directory and delete the AEAs:\n\n``` bash\naea delete aries_faber\naea delete aries_alice\n```\n\n## Further Developments\n\nIn the next update to this demo, the remaining interactions between AEAs and ACAs must be implemented. This means:\n\n- An instance of Indy ledger must be installed and running. See <a href=\"https://github.com/bcgov/von-network#running-the-network-locally\" target=\"_blank\">here</a> for more detail.\n- The commands for running the ACAs need to be adjusted. Additional options relating to a wallet (wallet-name, type, key, storage-type, configuration, credentials) need to be fed to the ACAs as well as the ledger's genesis file so the ACAs can connect to the ledger.\n- The remaining interactions between the AEAs and ACAs as described <a href=\"../aries-cloud-agent-demo/#discussion\">here</a> need to be implemented.\n"
  },
  {
    "path": "docs/build-aea-programmatically.md",
    "content": "# Build an AEA Programmatically\n\nThese instructions detail the Python code you need for running an AEA outside the `cli` tool, using the code interface.\n\n## Preparation\n\nGet the `packages` directory from the AEA repository:\n\n``` bash\nsvn export https://github.com/fetchai/agents-aea.git/trunk/packages\n```\n\nAlso, install `aea-ledger-fetchai` plug-in:\n\n``` bash\npip install aea-ledger-fetchai\n```\n\n## Imports\n\nFirst, import the necessary common Python libraries and classes.\n\n``` python\nimport os\nimport time\nfrom threading import Thread\n```\n\nThen, import the application specific libraries.\n\n``` python\nfrom aea_ledger_fetchai import FetchAICrypto\n\nfrom aea.aea_builder import AEABuilder\nfrom aea.configurations.base import SkillConfig\nfrom aea.crypto.helpers import PRIVATE_KEY_PATH_SCHEMA, create_private_key\nfrom aea.helpers.file_io import write_with_lock\nfrom aea.skills.base import Skill\n```\n\nSet up a variable pointing to where the `packages` directory is located - this should be our current directory - and where the input and output files are located.\n\n``` python\nROOT_DIR = \"./\"\nINPUT_FILE = \"input_file\"\nOUTPUT_FILE = \"output_file\"\nFETCHAI_PRIVATE_KEY_FILE = PRIVATE_KEY_PATH_SCHEMA.format(FetchAICrypto.identifier)\n```\n\n## Create a Private Key\n\nWe need a private key to populate the AEA's wallet.\n\n``` python\n    # Create a private key\n    create_private_key(FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE)\n```\n\n## Clearing the Input and Output Files\n\nWe will use the stub connection to pass envelopes in and out of the AEA. Ensure that any input and output text files are removed before we start.\n\n``` python\n    # Ensure the input and output files do not exist initially\n    if os.path.isfile(INPUT_FILE):\n        os.remove(INPUT_FILE)\n    if os.path.isfile(OUTPUT_FILE):\n        os.remove(OUTPUT_FILE)\n```\n\n## Initialise the AEA\n\nWe use the <a href=\"../api/aea_builder#aeabuilder-objects\">`AEABuilder`</a> to readily build an AEA. By default, the `AEABuilder` adds the `fetchai/default:1.1.7`, `fetchai/state_update:1.1.7` and `fetchai/signing:1.1.7` protocols.\n\n``` python\n    # Instantiate the builder and build the AEA\n    # By default, the default protocol, error skill and stub connection are added\n    builder = AEABuilder()\n```\n\nWe set the name, add the private key for the AEA to use and set the ledger configurations for the AEA to use.\n\n``` python\n    builder.set_name(\"my_aea\")\n\n    builder.add_private_key(FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE)\n```\n\nNext, we add the `fetchai/stub:0.15.0` connection which will read/write messages from file:\n\n``` python\n    # Add the stub connection (assuming it is present in the local directory 'packages')\n    builder.add_connection(\"./packages/fetchai/connections/stub\")\n```\n\nNext, we add the echo skill which will bounce our messages back to us. We first need to place the echo skill into a relevant directory (see path), either by downloading the `packages` directory from the AEA repo or by getting the package from the registry.\n\n``` python\n    # Add the echo skill (assuming it is present in the local directory 'packages')\n    builder.add_skill(\"./packages/fetchai/skills/echo\")\n```\n\nAlso, we can add a component that was instantiated programmatically. :\n\n``` python\n    # create skill and handler manually\n    from aea.protocols.base import Message\n    from aea.skills.base import Handler\n\n    from packages.fetchai.protocols.default.message import DefaultMessage\n\n    class DummyHandler(Handler):\n        \"\"\"Dummy handler to handle messages.\"\"\"\n\n        SUPPORTED_PROTOCOL = DefaultMessage.protocol_id\n\n        def setup(self) -> None:\n            \"\"\"Noop setup.\"\"\"\n\n        def teardown(self) -> None:\n            \"\"\"Noop teardown.\"\"\"\n\n        def handle(self, message: Message) -> None:\n            \"\"\"Handle incoming message.\"\"\"\n            self.context.logger.info(\"You got a message: {}\".format(str(message)))\n\n    config = SkillConfig(name=\"test_skill\", author=\"fetchai\")\n    skill = Skill(configuration=config)\n    dummy_handler = DummyHandler(\n        name=\"dummy_handler\", skill_context=skill.skill_context\n    )\n    skill.handlers.update({dummy_handler.name: dummy_handler})\n    builder.add_component_instance(skill)\n```\n\nFinally, we can build our AEA:\n\n``` python\n    # Create our AEA\n    my_aea = builder.build()\n```\n\n## Start the AEA\n\nWe run the AEA from a different thread so that we can still use the main thread to pass it messages.\n\n``` python\n    # Set the AEA running in a different thread\n    try:\n        t = Thread(target=my_aea.start)\n        t.start()\n\n        # Wait for everything to start up\n        time.sleep(4)\n```\n\n## Send and Receive an Envelope\n\nWe use the input and output text files to send an envelope to our AEA and receive a response (from the echo skill)\n\n``` python\n        # Create a message inside an envelope and get the stub connection to pass it on to the echo skill\n        message_text = b\"my_aea,other_agent,fetchai/default:1.0.0,\\x12\\x10\\x08\\x01\\x12\\x011*\\t*\\x07\\n\\x05hello,\"\n        with open(INPUT_FILE, \"wb\") as f:\n            write_with_lock(f, message_text)\n            print(b\"input message: \" + message_text)\n\n        # Wait for the envelope to get processed\n        time.sleep(4)\n\n        # Read the output envelope generated by the echo skill\n        with open(OUTPUT_FILE, \"rb\") as f:\n            print(b\"output message: \" + f.readline())\n```\n\n## Shutdown\n\nFinally, stop our AEA and wait for it to finish\n\n``` python\n    finally:\n        # Shut down the AEA\n        my_aea.stop()\n        t.join()\n        t = None\n```\n\n## Running the AEA\n\nIf you now run this python script file, you should see this output:\n\n``` text\ninput message: my_aea,other_agent,fetchai/default:1.0.0,\\x12\\x10\\x08\\x01\\x12\\x011*\\t*\\x07\\n\\x05hello,\noutput message: other_agent,my_aea,fetchai/default:1.0.0,...\\x05hello\n```\n\n## Entire Code Listing\n\nIf you just want to copy and past the entire script in you can find it here:\n\n??? note \"Click here to see full listing:\"\n\n    ``` python\n    import os\n    import time\n    from threading import Thread\n\n    from aea_ledger_fetchai import FetchAICrypto\n    \n    from aea.aea_builder import AEABuilder\n    from aea.configurations.base import SkillConfig\n    from aea.crypto.helpers import PRIVATE_KEY_PATH_SCHEMA, create_private_key\n    from aea.helpers.file_io import write_with_lock\n    from aea.skills.base import Skill\n    \n    \n    ROOT_DIR = \"./\"\n    INPUT_FILE = \"input_file\"\n    OUTPUT_FILE = \"output_file\"\n    FETCHAI_PRIVATE_KEY_FILE = PRIVATE_KEY_PATH_SCHEMA.format(FetchAICrypto.identifier)\n    \n    \n    def run():\n        \"\"\"Run demo.\"\"\"\n    \n        # Create a private key\n        create_private_key(FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE)\n    \n        # Ensure the input and output files do not exist initially\n        if os.path.isfile(INPUT_FILE):\n            os.remove(INPUT_FILE)\n        if os.path.isfile(OUTPUT_FILE):\n            os.remove(OUTPUT_FILE)\n    \n        # Instantiate the builder and build the AEA\n        # By default, the default protocol, error skill and stub connection are added\n        builder = AEABuilder()\n    \n        builder.set_name(\"my_aea\")\n    \n        builder.add_private_key(FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE)\n    \n        # Add the stub connection (assuming it is present in the local directory 'packages')\n        builder.add_connection(\"./packages/fetchai/connections/stub\")\n    \n        # Add the echo skill (assuming it is present in the local directory 'packages')\n        builder.add_skill(\"./packages/fetchai/skills/echo\")\n    \n        # create skill and handler manually\n        from aea.protocols.base import Message\n        from aea.skills.base import Handler\n    \n        from packages.fetchai.protocols.default.message import DefaultMessage\n    \n        class DummyHandler(Handler):\n            \"\"\"Dummy handler to handle messages.\"\"\"\n    \n            SUPPORTED_PROTOCOL = DefaultMessage.protocol_id\n    \n            def setup(self) -> None:\n                \"\"\"Noop setup.\"\"\"\n    \n            def teardown(self) -> None:\n                \"\"\"Noop teardown.\"\"\"\n    \n            def handle(self, message: Message) -> None:\n                \"\"\"Handle incoming message.\"\"\"\n                self.context.logger.info(\"You got a message: {}\".format(str(message)))\n    \n        config = SkillConfig(name=\"test_skill\", author=\"fetchai\")\n        skill = Skill(configuration=config)\n        dummy_handler = DummyHandler(\n            name=\"dummy_handler\", skill_context=skill.skill_context\n        )\n        skill.handlers.update({dummy_handler.name: dummy_handler})\n        builder.add_component_instance(skill)\n    \n        # Create our AEA\n        my_aea = builder.build()\n    \n        # Set the AEA running in a different thread\n        try:\n            t = Thread(target=my_aea.start)\n            t.start()\n    \n            # Wait for everything to start up\n            time.sleep(4)\n    \n            # Create a message inside an envelope and get the stub connection to pass it on to the echo skill\n            message_text = b\"my_aea,other_agent,fetchai/default:1.0.0,\\x12\\x10\\x08\\x01\\x12\\x011*\\t*\\x07\\n\\x05hello,\"\n            with open(INPUT_FILE, \"wb\") as f:\n                write_with_lock(f, message_text)\n                print(b\"input message: \" + message_text)\n    \n            # Wait for the envelope to get processed\n            time.sleep(4)\n    \n            # Read the output envelope generated by the echo skill\n            with open(OUTPUT_FILE, \"rb\") as f:\n                print(b\"output message: \" + f.readline())\n        finally:\n            # Shut down the AEA\n            my_aea.stop()\n            t.join()\n            t = None\n    \n    \n    if __name__ == \"__main__\":\n        run()\n    ```\n"
  },
  {
    "path": "docs/build-aea-step-by-step.md",
    "content": "# Build an AEA with the CLI\n\nBuilding an AEA step by step (ensure you have followed the <a href=\"../quickstart/#preliminaries\">Preliminaries</a> and <a href=\"../quickstart/#installation\">Installation</a> sections from the AEA quick start first):\n\n1. Set up your AEA project with the CLI: `aea create my_aea && cd my_aea`\n1. Look at, then add the right <a href=\"../connection/\">connections</a> for your use case:\n    `aea search connections`, then `aea add connection [public_id]`\n1. Look for, then add or generate the <a href=\"../protocol/\">protocols</a> you require: `aea search protocols`, then `aea add protocol [public_id]` or `aea generate protocol [path_to_specification]`\n1. Look for, then add or code the <a href=\"../skill/\">skills</a> you need: `aea search skills`, then `aea add skill [public_id]`. <a href=\"../skill-guide/\">This guide</a> shows you step by step how to develop a skill.\n1. Where required, scaffold any of the above resources with the <a href=\"../scaffolding/\">scaffolding tool</a> or generate a protocol with the <a href=\"../protocol-generator/\">protocol generator</a>.\n1. Now, run your AEA: `aea run --connections [public_id]`\n\nSee information on the CLI tool <a href=\"../cli-commands/\" target=\"_blank\">here</a> for all the available commands.\n"
  },
  {
    "path": "docs/car-park-skills.md",
    "content": "# Car park skills\n\nThe AEA car-park skills demonstrate an interaction between two AEAs.\n\n- The `carpark_detection` AEA provides information on the number of car parking spaces available in a given vicinity.\n- The `carpark_client` AEA is interested in purchasing information on available car parking spaces in the same vicinity.\n\n## Discussion\n\nThe full Fetch.ai car park AEA demo is documented in its own repo <a href=\"https://github.com/fetchai/carpark_agent\" target=\"_blank\">here</a>.\nThis demo allows you to test the AEA functionality of the car park AEA demo without the detection logic.\n\nIt demonstrates how the AEAs trade car park information.\n\n## Communication\n\nThis diagram shows the communication between the various entities as data is successfully sold by the car park AEA to the client.\n\n``` mermaid\n    sequenceDiagram\n        participant Search\n        participant Car_Data_Buyer_AEA\n        participant Car_Park_AEA\n        participant Blockchain\n\n        activate Search\n        activate Car_Data_Buyer_AEA\n        activate Car_Park_AEA\n        activate Blockchain\n        \n        Car_Park_AEA->>Search: register_service\n        Car_Data_Buyer_AEA->>Search: search\n        Search-->>Car_Data_Buyer_AEA: list_of_agents\n        Car_Data_Buyer_AEA->>Car_Park_AEA: call_for_proposal\n        Car_Park_AEA->>Car_Data_Buyer_AEA: propose\n        Car_Data_Buyer_AEA->>Car_Park_AEA: accept\n        Car_Park_AEA->>Car_Data_Buyer_AEA: match_accept\n        Car_Data_Buyer_AEA->>Blockchain: transfer_funds\n        Car_Data_Buyer_AEA->>Car_Park_AEA: send_transaction_hash\n        Car_Park_AEA->>Blockchain: check_transaction_status\n        Car_Park_AEA->>Car_Data_Buyer_AEA: send_data\n        \n        deactivate Search\n        deactivate Car_Data_Buyer_AEA\n        deactivate Car_Park_AEA\n        deactivate Blockchain\n```\n\n## Option 1: AEA Manager Approach\n\nFollow this approach when using the AEA Manager Desktop app. Otherwise, skip and follow the CLI approach below.\n\n### Preparation Instructions\n\nInstall the <a href=\"https://aea-manager.fetch.ai\" target=\"_blank\">AEA Manager</a>.\n\n### Demo Instructions\n\nThe following steps assume you have launched the AEA Manager Desktop app.\n\n1. Add a new AEA called `car_detector` with public id `fetchai/car_detector:0.32.5`.\n\n2. Add another new AEA called `car_data_buyer` with public id `fetchai/car_data_buyer:0.33.5`.\n\n3. Copy the address from the `car_data_buyer` into your clip board. Then go to the <a href=\"https://explore-dorado.fetch.ai\" target=\"_blank\">Dorado block explorer</a> and request some test tokens via `Get Funds`.\n\n4. Run the `car_detector` AEA. Navigate to its logs and copy the multiaddress displayed.\n\n5. Navigate to the settings of the `car_data_buyer` and under `components > connection >` `fetchai/p2p_libp2p:0.22.0` update as follows (make sure to replace the placeholder with the multiaddress):\n\n    ``` bash\n    {\n      \"delegate_uri\": \"127.0.0.1:11001\",\n      \"entry_peers\": [\"REPLACE_WITH_MULTI_ADDRESS_HERE\"],\n      \"local_uri\": \"127.0.0.1:9001\",\n      \"log_file\": \"libp2p_node.log\",\n      \"public_uri\": \"127.0.0.1:9001\"\n    }\n    ```\n\n6. Run the `car_data_buyer`.\n\nIn the AEA's logs, you should see the agent trading successfully.\n\n## Option 2: CLI Approach\n\nFollow this approach when using the `aea` CLI.\n\n### Preparation Instructions\n\n#### Dependencies\n\nFollow the <a href=\"../quickstart/#preliminaries\">Preliminaries</a> and <a href=\"../quickstart/#installation\">Installation</a> sections from the AEA quick start.\n\n### Demo Instructions\n\n#### Create Car Detector AEA\n\nFirst, fetch the car detector AEA:\n\n``` bash\naea fetch fetchai/car_detector:0.32.5\ncd car_detector\naea install\naea build\n```\n\n??? note \"Alternatively, create from scratch:\"\n\n    The following steps create the car detector from scratch:\n\n    ``` bash\n    aea create car_detector\n    cd car_detector\n    aea add connection fetchai/p2p_libp2p:0.27.5\n    aea add connection fetchai/soef:0.27.6\n    aea add connection fetchai/ledger:0.21.5\n    aea add skill fetchai/carpark_detection:0.27.6\n    aea config set --type dict agent.dependencies \\\n    '{\n      \"aea-ledger-fetchai\": {\"version\": \"<2.0.0,>=1.0.0\"}\n    }'\n    aea config set agent.default_connection fetchai/p2p_libp2p:0.27.5\n    aea config set --type dict agent.default_routing \\\n    '{\n      \"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n      \"fetchai/oef_search:1.1.7\": \"fetchai/soef:0.27.6\"\n    }'\n    aea install\n    aea build\n    ```\n\n#### Create Car Data Buyer AEA\n\nThen, fetch the car data client AEA:\n\n``` bash\naea fetch fetchai/car_data_buyer:0.33.5\ncd car_data_buyer\naea install\naea build\n```\n\n??? note \"Alternatively, create from scratch:\"\n    The following steps create the car data client from scratch:\n\n    ``` bash\n    aea create car_data_buyer\n    cd car_data_buyer\n    aea add connection fetchai/p2p_libp2p:0.27.5\n    aea add connection fetchai/soef:0.27.6\n    aea add connection fetchai/ledger:0.21.5\n    aea add skill fetchai/carpark_client:0.27.6\n    aea config set --type dict agent.dependencies \\\n    '{\n      \"aea-ledger-fetchai\": {\"version\": \"<2.0.0,>=1.0.0\"}\n    }'\n    aea config set agent.default_connection fetchai/p2p_libp2p:0.27.5\n    aea config set --type dict agent.default_routing \\\n    '{\n      \"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n      \"fetchai/oef_search:1.1.7\": \"fetchai/soef:0.27.6\"\n    }'\n    aea install\n    aea build\n    ```\n\n#### Add Keys for the Car Data Seller AEA\n\nFirst, create the private key for the car data seller AEA based on the network you want to transact. To generate and add a private-public key pair for Fetch.ai `Dorado` use:\n\n``` bash\naea generate-key fetchai\naea add-key fetchai fetchai_private_key.txt\n```\n\nNext, create a private key used to secure the AEA's communications:\n\n``` bash\naea generate-key fetchai fetchai_connection_private_key.txt\naea add-key fetchai fetchai_connection_private_key.txt --connection\n```\n\nFinally, certify the key for use by the connections that request that:\n\n``` bash\naea issue-certificates\n```\n\n#### Add Keys and Generate Wealth for the Car Data Buyer AEA\n\nThe buyer needs to have some wealth to purchase the service from the seller.\n\nFirst, create the private key for the car data buyer AEA based on the network you want to transact. To generate and add a private-public key pair for Fetch.ai `Dorado` use:\n\n``` bash\naea generate-key fetchai\naea add-key fetchai fetchai_private_key.txt\n```\n\nThen, create some wealth for your car data buyer based on the network you want to transact with. On the Fetch.ai `Dorado` network:\n\n``` bash\naea generate-wealth fetchai\n```\n\nNext, create a private key used to secure the AEA's communications:\n\n``` bash\naea generate-key fetchai fetchai_connection_private_key.txt\naea add-key fetchai fetchai_connection_private_key.txt --connection\n```\n\nFinally, certify the key for use by the connections that request that:\n\n``` bash\naea issue-certificates\n```\n\n### Run the AEAs\n\nRun both AEAs from their respective terminals.\n\nFirst, run the car data seller AEA:\n\n``` bash\naea run\n```\n\nOnce you see a message of the form `To join its network use multiaddr 'SOME_ADDRESS'` take note of the address. (Alternatively, use `aea get-multiaddress fetchai -c -i fetchai/p2p_libp2p:0.27.5 -u public_uri` to retrieve the address.)\nThis is the entry peer address for the local <a href=\"../acn\">agent communication network</a> created by the car data seller.\n\nThen, in the car data buyer, run this command (replace `SOME_ADDRESS` with the correct value as described above):\n\n``` bash\naea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \\\n'{\n  \"delegate_uri\": \"127.0.0.1:11001\",\n  \"entry_peers\": [\"SOME_ADDRESS\"],\n  \"local_uri\": \"127.0.0.1:9001\",\n  \"log_file\": \"libp2p_node.log\",\n  \"public_uri\": \"127.0.0.1:9001\"\n}'\n```\n\nThis allows the car data buyer to connect to the same local agent communication network as the car data seller.\n\nThen run the buyer AEA:\n\n``` bash\naea run\n```\n\nYou will see that the AEAs negotiate and then transact using the Fetch.ai testnet.\n\n#### Cleaning up\n\nWhen you're finished, delete your AEAs:\n\n``` bash\ncd ..\naea delete car_detector\naea delete car_data_buyer\n```\n"
  },
  {
    "path": "docs/cli-commands.md",
    "content": "# CLI Commands\n\n| Command                                   | Description                                                                                                                                          |\n|-------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------|\n| `add [package_type] [public_id]`          | Add a `package_type` connection, contract, protocol, or skill, with `[public_id]`, to the AEA. `add --local` to add from local `packages` directory. |\n| `add-key [ledger_id] file [--connection]` | Add a private key from a file for `ledger_id`.                                                                                                       |\n| `build`                                   | Build the agent and its components.                                                                                                                  |\n| `config get [path]`                       | Reads the configuration specified in `path` and prints its target.                                                                                   |\n| `config set [path] [--type TYPE]`         | Sets a new value for the target of the `path`. Optionally cast to type.                                                                              |\n| `create [name]`                           | Create a new AEA project called `name`.                                                                                                              |\n| `delete [name]`                           | Delete an AEA project. See below for disabling a resource.                                                                                           |\n| `eject [package_type] [public_id]`        | Move a package of `package_type` and `package_id` from vendor to project working directory.                                                          |\n| `fetch [public_id]`                       | Fetch an AEA project with `public_id`. `fetch --local` to fetch from local `packages` directory.                                                     |\n| `fingerprint [package_type] [public_id]`  | Fingerprint connection, contract, protocol, or skill, with `public_id`.                                                                              |\n| `freeze`                                  | Get all the dependencies needed for the AEA project and its components.                                                                              |\n| `generate protocol [protocol_spec_path]`  | Generate a protocol from the specification.                                                                                                          |\n| `generate-key [ledger_id]`                | Generate private keys. The AEA uses a private key to derive the associated public key and address.                                                   |\n| `generate-wealth [ledger_id]`             | Generate wealth for address on test network.                                                                                                         |\n| `get-address [ledger_id]`                 | Get the address associated with the private key.                                                                                                     |\n| `get-multiaddress [ledger_id]...`         | Get the multiaddress associated with a private key or connection.                                                                                    |\n| `get-public-key [ledger_id]...`           | Get the public key associated with a private key of the agent.                                                                                       |\n| `get-wealth [ledger_id]`                  | Get the wealth associated with the private key.                                                                                                      |\n| `init`                                    | Initialize your AEA configurations. (With `--author` to define author.)                                                                              |\n| `install [-r <requirements_file>]`        | Install the dependencies. (With `--install-deps` to install dependencies.)                                                                           |\n| `interact`                                | Interact with a running AEA via the stub connection.                                                                                                 |\n| `ipfs`                                    | IPFS Commands                                                                                                                                        |\n| `issue-certificates`                      | Issue the connection certificates.                                                                                                                   |\n| `launch [path_to_agent_project]...`       | Launch many agents at the same time.                                                                                                                 |\n| `list [package_type]`                     | List the installed resources.                                                                                                                        |\n| `local-registry-sync`                     | Upgrade the local package registry.                                                                                                                  |\n| `login USERNAME [--password password]`    | Login to a registry account with credentials.                                                                                                        |\n| `logout`                                  | Logout from registry account.                                                                                                                        |\n| `publish`                                 | Publish the AEA to registry. Needs to be executed from an AEA project.`publish --local` to publish to local `packages` directory.                    |\n| `push [package_type] [public_id]`         | Push connection, protocol, or skill with `public_id` to registry. `push --local` to push to local `packages` directory.                              |\n| `register`                                | Create a new registry account.                                                                                                                       |\n| `remove [package_type] [name]`            | Remove connection, protocol, or skill, called `name`, from AEA.                                                                                      |\n| `remove-key [ledger_id] [name]`           | Remove a private key registered with id `ledger_id`.                                                                                                 |\n| `reset_password EMAIL`                    | Reset the password of the registry account.                                                                                                          |\n| `run {using [connections, ...]}`          | Run the AEA on the Fetch.ai network with default or specified connections.                                                                           |\n| `scaffold [package_type] [name]`          | Scaffold a new connection, protocol, or skill called `name`.                                                                                         |\n| `search [package_type]`                   | Search for components in the registry. `search --local [package_type] [--query searching_query]` to search in local `packages` directory.            |\n| `transfer [type] [address] [amount]`      | Transfer wealth associated with a private key of the agent to another account.                                                                       |\n| `upgrade [package_type] [public_id]`      | Upgrade the packages of the agent.                                                                                                                   |\n| `-v DEBUG run`                            | Run with debugging.                                                                                                                                  |\n\n<!--\nCommand  | Description\n---------| -----------------------------------------------------------------\n`deploy {using [connection, ...]}`  | Deploy the AEA to a server and run it on the Fetch.ai network with default or specified connections.\n -->\n\n!!! tip\n    You can also disable a resource without deleting it by removing the entry from the configuration but leaving the package in the `skills` namespace.\n\n!!! tip\n    You can skip the consistency checks on the AEA project by using the flag `--skip-consistency-check`. E.g. `aea --skip-consistency-check run` will bypass the fingerprint checks.\n"
  },
  {
    "path": "docs/cli-vs-programmatic-aeas.md",
    "content": "# CLI vs Programmatic AEAs\n\nThe AEA framework enables us to create agents either from the CLI tool or programmatically.\n\nThe following demo demonstrates an interaction between two AEAs.\n\nThe provider of weather data (managed with the CLI).\nThe buyer of weather data (managed programmatically).\n\n## Discussion\n\nThe scope of the specific demo is to demonstrate how a CLI based AEA can interact with a programmatically managed AEA. In order\nto achieve this we are going to use the weather station skills.\nThis demo does not utilize a smart contract or a ledger interaction.\n\n## Get Required Packages\n\nCopy the `packages` directory into your local working directory:\n\n``` bash\nsvn export https://github.com/fetchai/agents-aea.git/trunk/packages\n```\n\nAlso, install `aea-ledger-fetchai` plug-in:\n\n``` bash\npip install aea-ledger-fetchai\n```\n\n## Demo Instructions\n\nIf you want to create the weather station AEA step by step you can follow this guide <a href='/weather-skills/'>here</a>\n\n### Create the Weather Station AEA\n\nFetch the weather station AEA with the following command :\n\n``` bash\naea fetch fetchai/weather_station:0.32.5\ncd weather_station\naea install\naea build\n```\n\n### Update the AEA Configurations\n\nIn the terminal change the configuration:\n\n``` bash\naea config set vendor.fetchai.skills.weather_station.models.strategy.args.is_ledger_tx False --type bool\n```\n\nThe `is_ledger_tx` will prevent the AEA to communicate with a ledger.\n\n### Add Keys\n\nAdd a private key for the weather station.\n\n``` bash\naea generate-key fetchai\naea add-key fetchai fetchai_private_key.txt\n```\n\nNext, create a private key used to secure the AEA's communications:\n\n``` bash\naea generate-key fetchai fetchai_connection_private_key.txt\naea add-key fetchai fetchai_connection_private_key.txt --connection\n```\n\nFinally, certify the key for use by the connections that request that:\n\n``` bash\naea issue-certificates\n```\n\n### Run the Weather Station AEA\n\n``` bash\naea run\n```\n\nOnce you see a message of the form `To join its network use multiaddr: ['SOME_ADDRESS']` take note of the address.\n\n### Create the Weather Client AEA\n\nSince we want to show the interaction between a programmatically created AEA with a CLI based AEA we are going to write some code for the client.\n\nCreate a new python file and name it `weather_client.py` and add the following code\n\n??? note \"Weather client full code:\"\n\n    ``` python\n    import logging\n    import os\n    import sys\n    from typing import cast\n    \n    from aea_ledger_fetchai import FetchAICrypto\n    \n    from aea.aea import AEA\n    from aea.aea_builder import AEABuilder\n    from aea.configurations.base import ConnectionConfig\n    from aea.crypto.helpers import (\n        PRIVATE_KEY_PATH_SCHEMA,\n        create_private_key,\n        make_certificate,\n    )\n    from aea.crypto.wallet import Wallet\n    from aea.helpers.base import CertRequest\n    from aea.identity.base import Identity\n    from aea.protocols.base import Protocol\n    from aea.registries.resources import Resources\n    from aea.skills.base import Skill\n    \n    import packages.fetchai.connections.p2p_libp2p.connection\n    from packages.fetchai.connections.ledger.connection import LedgerConnection\n    from packages.fetchai.connections.p2p_libp2p.connection import P2PLibp2pConnection\n    from packages.fetchai.connections.soef.connection import SOEFConnection\n    from packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\n    from packages.fetchai.protocols.oef_search.message import OefSearchMessage\n    from packages.fetchai.skills.weather_client.strategy import Strategy\n    \n    \n    API_KEY = \"TwiCIriSl0mLahw17pyqoA\"\n    SOEF_ADDR = \"s-oef.fetch.ai\"\n    SOEF_PORT = 443\n    ENTRY_PEER_ADDRESS = (\n        \"/dns4/127.0.0.1/tcp/9000/p2p/16Uiu2HAmLBCAqHL8SuFosyDhAKYsLKXBZBWXBsB9oFw2qU4Kckun\"\n    )\n    FETCHAI_PRIVATE_KEY_FILE = PRIVATE_KEY_PATH_SCHEMA.format(FetchAICrypto.identifier)\n    FETCHAI_PRIVATE_KEY_FILE_CONNECTION = PRIVATE_KEY_PATH_SCHEMA.format(\n        \"fetchai_connection\"\n    )\n    ROOT_DIR = os.getcwd()\n    \n    logger = logging.getLogger(\"aea\")\n    logging.basicConfig(stream=sys.stdout, level=logging.INFO)\n\n\n    def run():\n        \"\"\"Run demo.\"\"\"\n    \n        # Create a private key\n        create_private_key(FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE)\n        create_private_key(FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE_CONNECTION)\n    \n        # Set up the wallet, identity and (empty) resources\n        wallet = Wallet(\n            private_key_paths={FetchAICrypto.identifier: FETCHAI_PRIVATE_KEY_FILE},\n            connection_private_key_paths={\n                FetchAICrypto.identifier: FETCHAI_PRIVATE_KEY_FILE_CONNECTION\n            },\n        )\n        identity = Identity(\n            \"my_aea\",\n            address=wallet.addresses.get(FetchAICrypto.identifier),\n            public_key=wallet.public_keys.get(FetchAICrypto.identifier),\n        )\n        resources = Resources()\n        data_dir = os.getcwd()\n    \n        # specify the default routing for some protocols\n        default_routing = {\n            LedgerApiMessage.protocol_id: LedgerConnection.connection_id,\n            OefSearchMessage.protocol_id: SOEFConnection.connection_id,\n        }\n        default_connection = P2PLibp2pConnection.connection_id\n    \n        state_update_protocol = Protocol.from_dir(\n            os.path.join(os.getcwd(), \"packages\", \"fetchai\", \"protocols\", \"state_update\")\n        )\n        resources.add_protocol(state_update_protocol)\n    \n        # Add the default protocol (which is part of the AEA distribution)\n        default_protocol = Protocol.from_dir(\n            os.path.join(os.getcwd(), \"packages\", \"fetchai\", \"protocols\", \"default\")\n        )\n        resources.add_protocol(default_protocol)\n    \n        # Add the signing protocol (which is part of the AEA distribution)\n        signing_protocol = Protocol.from_dir(\n            os.path.join(os.getcwd(), \"packages\", \"fetchai\", \"protocols\", \"signing\")\n        )\n        resources.add_protocol(signing_protocol)\n    \n        # Add the ledger_api protocol\n        ledger_api_protocol = Protocol.from_dir(\n            os.path.join(\n                os.getcwd(),\n                \"packages\",\n                \"fetchai\",\n                \"protocols\",\n                \"ledger_api\",\n            )\n        )\n        resources.add_protocol(ledger_api_protocol)\n    \n        # Add the oef_search protocol\n        oef_protocol = Protocol.from_dir(\n            os.path.join(\n                os.getcwd(),\n                \"packages\",\n                \"fetchai\",\n                \"protocols\",\n                \"oef_search\",\n            )\n        )\n        resources.add_protocol(oef_protocol)\n    \n        # Add the fipa protocol\n        fipa_protocol = Protocol.from_dir(\n            os.path.join(\n                os.getcwd(),\n                \"packages\",\n                \"fetchai\",\n                \"protocols\",\n                \"fipa\",\n            )\n        )\n        resources.add_protocol(fipa_protocol)\n    \n        # Add the LedgerAPI connection\n        configuration = ConnectionConfig(connection_id=LedgerConnection.connection_id)\n        ledger_api_connection = LedgerConnection(\n            configuration=configuration, data_dir=data_dir, identity=identity\n        )\n        resources.add_connection(ledger_api_connection)\n    \n        # Add the P2P connection\n        cert_path = \".certs/conn_cert.txt\"\n        cert_request = CertRequest(\n            identifier=\"acn\",\n            ledger_id=FetchAICrypto.identifier,\n            not_after=\"2022-01-01\",\n            not_before=\"2021-01-01\",\n            public_key=\"fetchai\",\n            message_format=\"{public_key}\",\n            save_path=cert_path,\n        )\n        public_key = wallet.connection_cryptos.public_keys.get(FetchAICrypto.identifier)\n        message = cert_request.get_message(public_key)\n        make_certificate(\n            FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE, message, cert_path\n        )\n        configuration = ConnectionConfig(\n            connection_id=P2PLibp2pConnection.connection_id,\n            delegate_uri=\"127.0.0.1:11001\",\n            entry_peers=[ENTRY_PEER_ADDRESS],\n            local_uri=\"127.0.0.1:9001\",\n            log_file=\"libp2p_node.log\",\n            public_uri=\"127.0.0.1:9001\",\n            build_directory=os.getcwd(),\n            build_entrypoint=\"check_dependencies.py\",\n            cert_requests=[cert_request],\n        )\n        configuration.directory = os.path.dirname(\n            packages.fetchai.connections.p2p_libp2p.connection.__file__\n        )\n    \n        AEABuilder.run_build_for_component_configuration(configuration)\n    \n        p2p_connection = P2PLibp2pConnection(\n            configuration=configuration,\n            data_dir=data_dir,\n            identity=identity,\n            crypto_store=wallet.connection_cryptos,\n        )\n        resources.add_connection(p2p_connection)\n    \n        # Add the SOEF connection\n        configuration = ConnectionConfig(\n            api_key=API_KEY,\n            soef_addr=SOEF_ADDR,\n            soef_port=SOEF_PORT,\n            restricted_to_protocols={OefSearchMessage.protocol_id},\n            connection_id=SOEFConnection.connection_id,\n        )\n        soef_connection = SOEFConnection(\n            configuration=configuration, data_dir=data_dir, identity=identity\n        )\n        resources.add_connection(soef_connection)\n    \n        # create the AEA\n        my_aea = AEA(\n            identity,\n            wallet,\n            resources,\n            data_dir,\n            default_connection=default_connection,\n            default_routing=default_routing,\n        )\n        # Add the error and weather_client skills\n        error_skill = Skill.from_dir(\n            os.path.join(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"error\"),\n            agent_context=my_aea.context,\n        )\n        weather_skill = Skill.from_dir(\n            os.path.join(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"weather_client\"),\n            agent_context=my_aea.context,\n        )\n    \n        strategy = cast(Strategy, weather_skill.models.get(\"strategy\"))\n        strategy._is_ledger_tx = False\n    \n        for skill in [error_skill, weather_skill]:\n            resources.add_skill(skill)\n    \n        # Run the AEA\n        try:\n            logger.info(\"STARTING AEA NOW!\")\n            my_aea.start()\n        except KeyboardInterrupt:\n            logger.info(\"STOPPING AEA NOW!\")\n            my_aea.stop()\n    \n    \n    if __name__ == \"__main__\":\n        run()\n    ```\n\nNow replace `ENTRY_PEER_ADDRESS` with the peer address (`SOME_ADDRESS`) noted above.\n\nFor more details on how to create an agent programmatically follow this guide <a href='/build-aea-programmatically/'>here</a>.\n\n### Run the Weather Client AEA\n\nIn a new terminal window, navigate to the folder that you created the script and run:\n\n``` bash\npython weather_client.py\n```\n\nYou should see both AEAs interacting now.\n"
  },
  {
    "path": "docs/config.md",
    "content": "# Configurations\n\nThis document describes the configuration files of the different packages.\n\n## AEA Configuration YAML\n\nThe following provides a list of the relevant regex used:\n\n``` yaml\nPACKAGE_REGEX: \"[a-zA-Z_][a-zA-Z0-9_]*\"\nAUTHOR_REGEX: \"[a-zA-Z_][a-zA-Z0-9_]*\"\nPUBLIC_ID_REGEX: \"^[a-zA-Z0-9_]*/[a-zA-Z_][a-zA-Z0-9_]*:(0|[1-9]\\\\d*)\\\\.(0|[1-9]\\\\d*)\\\\.(0|[1-9]\\\\d*)(?:-((?:0|[1-9]\\\\d*|\\\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\\\.(?:0|[1-9]\\\\d*|\\\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\\\+([0-9a-zA-Z-]+(?:\\\\.[0-9a-zA-Z-]+)*))?$\"\nLEDGER_ID_REGEX: \"^[^\\\\d\\\\W]\\\\w*\\\\Z\"\n```\n\nThe `aea-config.yaml` defines the AEA project. The compulsory components are listed below:\n\n``` yaml\nagent_name: my_agent                            # Name of the AEA project (must satisfy PACKAGE_REGEX)\nauthor: fetchai                                 # Author handle of the project's author (must satisfy AUTHOR_REGEX)\nversion: 0.1.0                                  # Version of the AEA project (a semantic version number, see https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string\")\ndescription: A demo project                     # Description of the AEA project\nlicense: Apache-2.0                             # License of the AEA project\naea_version: '>=1.0.0, <2.0.0'               # AEA framework version(s) compatible with the AEA project (a version number that matches PEP 440 version schemes, or a comma-separated list of PEP 440 version specifiers, see https://www.python.org/dev/peps/pep-0440/#version-specifiers)\nfingerprint: {}                                 # Fingerprint of AEA project components.\nfingerprint_ignore_patterns: []                 # Ignore pattern for the fingerprinting tool.\nconnections:                                    # The list of connection public ids the AEA project depends on (each public id must satisfy PUBLIC_ID_REGEX)\n- fetchai/stub:0.21.3\ncontracts: []                                   # The list of contract public ids the AEA project depends on (each public id must satisfy PUBLIC_ID_REGEX).\nprotocols:                                      # The list of protocol public ids the AEA project depends on (each public id must satisfy PUBLIC_ID_REGEX).\n- fetchai/default:1.1.7\nskills:                                         # The list of skill public ids the AEA project depends on (each public id must satisfy PUBLIC_ID_REGEX).\n- fetchai/error:0.18.6\ndefault_connection: fetchai/p2p_libp2p:0.27.5   # The default connection used for envelopes sent by the AEA (must satisfy PUBLIC_ID_REGEX).\ndefault_ledger: fetchai                         # The default ledger identifier the AEA project uses (must satisfy LEDGER_ID_REGEX)\nrequired_ledgers: [fetchai]                            # the list of identifiers of ledgers that the AEA project requires key pairs for (each item must satisfy LEDGER_ID_REGEX)\ndefault_routing: {}                             # The default routing scheme applied to envelopes sent by the AEA, it maps from protocol public ids to connection public ids (both keys and values must satisfy PUBLIC_ID_REGEX)\nconnection_private_key_paths:                   # The private key paths the AEA project uses for its connections (keys must satisfy LEDGER_ID_REGEX, values must be file paths)\n  fetchai: fetchai_private_key.txt\nprivate_key_paths:                              # The private key paths the AEA project uses (keys must satisfy LEDGER_ID_REGEX, values must be file paths)\n  fetchai: fetchai_private_key.txt\nlogging_config:                                 # The logging configurations the AEA project uses\n  disable_existing_loggers: false\n  version: 1\ndependencies: {}                                # The python dependencies the AEA relies on (e.g. plugins). They will be installed when `aea install` is run.\n```\n\nThe `aea-config.yaml` can be extended with a number of optional fields:\n\n``` yaml\nperiod: 0.05                                    # The period to call agent's act\nexecution_timeout: 0                            # The execution time limit on each call to `react` and `act` (0 disables the feature)\ntimeout: 0.05                                   # The sleep time on each AEA loop spin (only relevant for the `sync` mode)\nmax_reactions: 20                               # The maximum number of envelopes processed per call to `react` (only relevant for the `sync` mode)\nskill_exception_policy: propagate               # The exception policy applied to skills (must be one of \"propagate\", \"just_log\", or \"stop_and_exit\")\nconnection_exception_policy: propagate          # The exception policy applied to connections (must be one of \"propagate\", \"just_log\", or \"stop_and_exit\")\nloop_mode: async                                # The agent loop mode (must be one of \"sync\" or \"async\")\nruntime_mode: threaded                          # The runtime mode (must be one of \"threaded\" or \"async\") and determines how agent loop and multiplexer are run\nerror_handler: None                             # The error handler to be used.\ndecision_maker_handler: None                    # The decision maker handler to be used.\nstorage_uri: None                               # The URI to the storage.\ndata_dir: None                                  # The path to the directory for local files. Defaults to current working directory.\n```\n\nThe `aea-config.yaml` can further be extended with component configuration overrides.\n\nFor custom connection configurations:\n\n``` yaml\npublic_id: some_author/some_package:0.1.0       # The public id of the connection (must satisfy PUBLIC_ID_REGEX).\ntype: connection                                # for connections, this must be \"connection\".\nconfig: ...                                     # a dictionary to overwrite the `config` field (see below)\n```\n\nFor custom skill configurations:\n\n``` yaml\npublic_id: some_author/some_package:0.1.0       # The public id of the connection (must satisfy PUBLIC_ID_REGEX).\ntype: skill                                     # for skills, this must be \"skill\".\nbehaviours:                                     # override configurations for behaviours\n  behaviour_1:                                  # override configurations for \"behaviour_1\"\n    args:                                       # arguments for a specific behaviour (see below)\n      foo: bar\nhandlers:                                       # override configurations for handlers\n  handler_1:                                    # override configurations for \"handler_1\"\n    args:                                       # arguments for a specific handler (see below)\n      foo: bar\nmodels:                                         # override configurations for models\n  model_1:                                      # override configurations for \"model_1\"\n    args:                                       # arguments for a specific model (see below)\n      foo: bar\n```\n\n## Connection Configuration YAML\n\nThe `connection.yaml`, which is present in each connection package, has the following required fields:\n\n``` yaml\nname: scaffold                                  # Name of the package (must satisfy PACKAGE_REGEX)\nauthor: fetchai                                 # Author handle of the package's author (must satisfy AUTHOR_REGEX)\nversion: 0.1.0                                  # Version of the package (a semantic version number, see https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string\")\ntype: connection                                # The type of the package; for connections, it must be \"connection\"\ndescription: A scaffold connection              # Description of the package\nlicense: Apache-2.0                             # License of the package\naea_version: '>=1.0.0, <2.0.0'               # AEA framework version(s) compatible with the AEA project (a version number that matches PEP 440 version schemes, or a comma-separated list of PEP 440 version specifiers, see https://www.python.org/dev/peps/pep-0440/#version-specifiers)\nfingerprint:                                    # Fingerprint of package components.\n  __init__.py: QmZvYZ5ECcWwqiNGh8qNTg735wu51HqaLxTSifUxkQ4KGj\n  connection.py: QmagwVgaPgfeXqVTgcpFESA4DYsteSbojz94SLtmnHNAze\nfingerprint_ignore_patterns: []                 # Ignore pattern for the fingerprinting tool.\nconnections: []                                 # The list of connection public ids the package depends on (each public id must satisfy PUBLIC_ID_REGEX).\nprotocols: []                                   # The list of protocol public ids the package depends on (each public id must satisfy PUBLIC_ID_REGEX).\nclass_name: MyScaffoldConnection                # The class name of the class implementing the connection interface.\nconfig:                                         # A dictionary containing the kwargs for the connection instantiation.\n  foo: bar\nexcluded_protocols: []                          # The list of protocol public ids the package does not permit (each public id must satisfy PUBLIC_ID_REGEX).\nrestricted_to_protocols: []                     # The list of protocol public ids the package is limited to (each public id must satisfy PUBLIC_ID_REGEX).\ndependencies: {}                                # The python dependencies the package relies on. They will be installed when `aea install` is run.\nis_abstract: false                              # An optional boolean that if `true` makes the connection\n```\n\n## Contract Configuration YAML\n\nThe `contract.yaml`, which is present in each contract package, has the following required fields:\n\n``` yaml\nname: scaffold                                  # Name of the package (must satisfy PACKAGE_REGEX)\nauthor: fetchai                                 # Author handle of the package's author (must satisfy AUTHOR_REGEX)\nversion: 0.1.0                                  # Version of the package (a semantic version number, see https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string\")\ntype: contract                                  # The type of the package; for contracts, it must be \"contract\"\ndescription: A scaffold contract                # Description of the package\nlicense: Apache-2.0                             # License of the package\naea_version: '>=1.0.0, <2.0.0'               # AEA framework version(s) compatible with the AEA project (a version number that matches PEP 440 version schemes, or a comma-separated list of PEP 440 version specifiers, see https://www.python.org/dev/peps/pep-0440/#version-specifiers)\nfingerprint:                                    # Fingerprint of package components.\n  __init__.py: QmPBwWhEg3wcH1q9612srZYAYdANVdWLDFWKs7TviZmVj6\n  contract.py: QmXvjkD7ZVEJDJspEz5YApe5bRUxvZHNi8vfyeVHPyQD5G\nfingerprint_ignore_patterns: []                 # Ignore pattern for the fingerprinting tool.\nclass_name: MyScaffoldContract                  # The class name of the class implementing the contract interface.\ncontract_interface_paths: {}                    # The paths to the contract interfaces (one for each ledger identifier).\nconfig:                                         # A dictionary containing the kwargs for the contract instantiation.\n  foo: bar\ndependencies: {}                                # The python dependencies the package relies on. They will be installed when `aea install` is run.\n```\n\n## Protocol Configuration YAML\n\nThe `protocol.yaml`, which is present in each protocol package, has the following required fields:\n\n``` yaml\nname: scaffold                                  # Name of the package (must satisfy PACKAGE_REGEX)\nauthor: fetchai                                 # Author handle of the package's author (must satisfy AUTHOR_REGEX)\nversion: 0.1.0                                  # Version of the package (a semantic version number, see https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string\")\ntype: protocol                                  # The type of the package; for protocols, it must be \"protocol\" \ndescription: A scaffold protocol                # Description of the package\nlicense: Apache-2.0                             # License of the package\naea_version: '>=1.0.0, <2.0.0'               # AEA framework version(s) compatible with the AEA project (a version number that matches PEP 440 version schemes, or a comma-separated list of PEP 440 version specifiers, see https://www.python.org/dev/peps/pep-0440/#version-specifiers)\nfingerprint:                                    # Fingerprint of package components.\n  __init__.py: Qmay9PmfeHqqVa3rdgiJYJnzZzTStboQEfpwXDpcgJMHTJ\n  message.py: QmdvAdYSHNdZyUMrK3ue7quHAuSNwgZZSHqxYXyvh8Nie4\n  serialization.py: QmVUzwaSMErJgNFYQZkzsDhuuT2Ht4EdbGJ443usHmPxVv\nfingerprint_ignore_patterns: []                 # Ignore pattern for the fingerprinting tool.\ndependencies: {}                                # The python dependencies the package relies on. They will be installed when `aea install` is run.\n```\n\n## Skill Configuration YAML\n\nThe `skill.yaml`, which is present in each protocol package, has the following required fields:\n\n``` yaml\nname: scaffold                                  # Name of the package (must satisfy PACKAGE_REGEX)\nauthor: fetchai                                 # Author handle of the package's author (must satisfy AUTHOR_REGEX)\nversion: 0.1.0                                  # Version of the package (a semantic version number, see https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string\")\ntype: skill                                     # The type of the package; for skills, it must be \"skill\"\ndescription: A scaffold skill                   # Description of the package\nlicense: Apache-2.0                             # License of the package\naea_version: '>=1.0.0, <2.0.0'               # AEA framework version(s) compatible with the AEA project (a version number that matches PEP 440 version schemes, or a comma-separated list of PEP 440 version specifiers, see https://www.python.org/dev/peps/pep-0440/#version-specifiers)\nfingerprint:                                    # Fingerprint of package components.\n  __init__.py: QmNkZAetyctaZCUf6ACxP5onGWsSxu2hjSNoFmJ3ta6Lta\n  behaviours.py: QmYa1rczhGTtMJBgCd1QR9uZhhkf45orm7TnGTE5Eizjpy\n  handlers.py: QmZYyTENRr6ecnxx1FeBdgjLiBhFLVn9mqarzUtFQmNUFn\n  my_model.py: QmPaZ6G37Juk63mJj88nParaEp71XyURts8AmmX1axs24V\nfingerprint_ignore_patterns: []                 # Ignore pattern for the fingerprinting tool.\ncontracts: []                                   # The list of contract public ids the package depends on (each public id must satisfy PUBLIC_ID_REGEX).\nprotocols: []                                   # The list of protocol public ids the package depends on (each public id must satisfy PUBLIC_ID_REGEX).\nskills: []                                      # The list of skill public ids the package depends on (each public id must satisfy PUBLIC_ID_REGEX).\nis_abstract: false                              # An optional boolean that if `true` makes the skill abstract, i.e. not instantiated by the framework but importable from other skills. Defaults to `false`. \nbehaviours:                                     # The dictionary describing the behaviours immplemented in the package (including their configuration)\n  scaffold:                                     # Name of the behaviour under which it is made available on the skill context.\n    args:                                       # Keyword arguments provided to the skill component on instantiation.\n      foo: bar\n    class_name: MyScaffoldBehaviour             # The class name of the class implementing the behaviour interface.\nhandlers:                                       # The dictionary describing the handlers immplemented in the package (including their configuration)\n  scaffold:                                     # Name of the handler under which it is made available on the skill\n    args:                                       # Keyword arguments provided to the skill component on instantiation.\n      foo: bar\n    class_name: MyScaffoldHandler               # The class name of the class implementing the handler interface.\nmodels:                                         # The dictionary describing the models immplemented in the package (including their configuration)\n  scaffold:                                     # Name of the model under which it is made available on the skill\n    args:                                       # Keyword arguments provided to the skill component on instantiation.\n      foo: bar\n    class_name: MyModel                         # The class name of the class implementing the model interface.\ndependencies: {}                                # The python dependencies the package relies on. They will be installed when `aea install` is run.\n```\n"
  },
  {
    "path": "docs/connect-a-frontend.md",
    "content": "# Front-End Integration\n\nThis page lays out two options for connecting a front-end to an AEA. The following diagram illustrates these two options.\n\n<img src=\"../assets/http-integration.jpg\" alt=\"How to connect front-end to your AEA\" class=\"center\" style=\"display: block; margin-left: auto; margin-right: auto;width:80%;\">\n\n## Case 1\n\nThe first option is to create a `HTTP Server` connection that handles incoming requests from a REST API. In this scenario, the REST API communicates with the AEA and requests are handled by the `HTTP Server` connection package. The REST API should send CRUD requests to the `HTTP Server` connection (`fetchai/http_server:0.23.6`) which translates these into Envelopes to be consumed by the correct skill.\n\n## Case 2\n\nThe second option is to create a front-end comprising a stand-alone `Multiplexer` with a `P2P` connection (`fetchai/p2p_libp2p:0.27.5`). In this scenario the <a href=\"../acn\">Agent Communication Network</a> can be used to send Envelopes from the AEA to the front-end.\n"
  },
  {
    "path": "docs/connection.md",
    "content": "# Connections\n\nA <a href=\"../api/connections/base#connection-objects\">`Connection`</a> provides an interface for the agent to connect with entities in the outside world. Connections wrap SDKs or APIs and provide interfaces to networks, ledgers and other services. As such, a connection is concerned with I/O bound and continuously connected operations. Where necessary, a connection is responsible for translating between the framework specific <a href=\"../protocol\">protocol</a> (an <a href=\"../api/mail/base#envelope-objects\">`Envelope`</a> with its contained <a href=\"../api/protocols/base#message-objects\">`Message`</a>) and the external service or third-party protocol (e.g. `HTTP`). Hence, there are two roles for connections: wrapper and transport connection. The transport connection is responsible to delivering AEA envelopes.\n\nThe messages constructed or received by a connection are eventually processed by one or several <a href=\"../skill\">skills</a> which deal with handling and generating messages related to a specific business objective.\n\n<img src=\"../assets/multiplexer.png\" alt=\"Multiplexer of an AEA\" class=\"center\" style=\"display: block; margin-left: auto; margin-right: auto;width:50%;\">\n\nAn `AEA` can interact with multiple connections at the same time via the <a href=\"../api/connections/base#connection-objects\">`Multiplexer`</a>. Connections are passive in terms of multiplexer interactions (its methods are called by the Multiplexer), but they can run their own asynchronous or threaded tasks.\n\nThe `Multiplexer` maintains an <a href=\"../api/multiplexer#inbox-objects\">`InBox`</a> and <a href=\"../api/multiplexer#outbox-objects\">`OutBox`</a>, which are, respectively, queues for incoming and outgoing envelopes and their contained messages.\n\n## Developing your Connection\n\nThe easiest way to get started developing your own connection is by using the <a href=\"../scaffolding\">scaffold</a> command:\n\n``` bash\naea scaffold connection my_new_connection\n```\n\nThis will scaffold a connection package called `my_new_connection` with three files:\n\n- `__init__.py`\n- `connection.py` containing the scaffolded connection class\n- `connection.yaml` containing the scaffolded configuration file\n\nAs a developer you have the choice between implementing a sync or asynchronous interface. The scaffolded `connection.py` file contains two classes: the `MyScaffoldAsyncConnection` inherited from the <a href=\"../api/connections/base#connection-objects\">`Connection`</a> base class and the `MyScaffoldSyncConnection` inherited from the <a href=\"../api/connections/base#connection-objects\">`BaseSyncConnection`</a>. Remove the unused class.\n\n### Primary Methods to Develop - Asynchronous Connection Interface\n\nThe developer needs to implement four public coroutines:\n\n- The `connect` coroutine implements the setup logic required to be performed for the connection when it is initially launched. The `connect` coroutine is called by the AEA framework once when the agent is being started.\n\n- The `disconnect` coroutine implements the teardown logic required to be performed for the connection when it is eventually stopped. The `disconnect` coroutine is called by the AEA framework once when the agent is being stopped.\n\n- The `send` coroutine is called by the AEA framework each time the `Multiplexer` handles an outgoing envelope specified to be handled by this connection. The `send` coroutine must implement the processing of the envelope leaving the agent.\n\n- The `receive` coroutine is continuously called by the AEA framework. It either returns `None` or an envelope. The `receive` coroutine must implement the logic of data being received by the agent, and if necessary, its translation into a relevant protocol.\n\nThe framework provides a demo `stub` connection which implements an I/O reader and writer to send and receive messages between the agent and a local file. To gain inspiration and become familiar with the structure of connection packages, you may find it useful to check out `fetchai/stub:0.21.3`, `fetchai/http_server:0.23.6` or `fetchai/http_client:0.24.6` connections. The latter two connections are for external clients to connect with an agent, and for the agent to connect with external servers, respectively.\n\n### Primary Methods to Develop - Sync Connection Interface\n\nThe <a href=\"../api/connections/base#connection-objects\">`BaseSyncConnection`</a> uses executors to execute synchronous code from the asynchronous context of the `Multiplexer` in executors/threads, which are limited by the amount of configured workers.\n\nThe asynchronous methods `connect`, `disconnect` and `send` are converted to callbacks which the developer implements:\n\n- `on_connect`\n- `on_disconnect`\n- `on_send`\n\nAll of these methods will be executed in the executor pool.\n\nEvery method can create a message by putting it into the thread/asynchronous friendly queue that is consumed by the `Multiplexer`.\n\nThe `receive` coroutine has no direct equivalent. Instead, the developer implements a `main` method which runs synchronously in the background.\n\n## Configuration\n\nEvery connection must have a configuration file in `connection.yaml`, containing meta-information about the connection as well as all the required configuration details. For more details, have a look <a href=\"../config\">here</a>.\n\n### Configuration Options\n\nThe `connection.yaml` file contains a number of fields that must be edited by the developer of the connection:\n\n``` yaml\nconnections: []\nprotocols: []\nclass_name: MyScaffoldConnection\nconfig:\n  foo: bar\nexcluded_protocols: []\nrestricted_to_protocols: []\ndependencies: {}\nis_abstract: false\ncert_requests: []\n```\n\n- `connections` specifies the list of other connection this connection depends on\n- `protocols` specifies the list of protocols this connection depends on\n- `class_name` needs to match the name of the connection class in `connection.py`\n- `config` can contain arbitrary configuration information which is made available in the constructor of the connection as keyword arguments (`**kwargs`)\n- `excluded_protocols` lists the protocols which cannot be used in this connection\n- `restricted_to_protocols` lists the protocols which this connection is restricted to be used by\n- `dependencies` lists any Python dependencies of the connection package\n- `is_abstract` specifies whether this connection is only used as an abstract base class\n- `cert_requests` lists certification requests of the connection (see <a href=\"../por\">proof of representation</a> for details)\n"
  },
  {
    "path": "docs/contract.md",
    "content": "# Contracts\n\n<a href=\"../api/contracts/base#contract-objects\">`Contracts`</a> wrap smart contracts for Fetch.ai and third-party decentralized ledgers. In particular, they provide wrappers around the API or ABI of a smart contract and its byte code. They implement a translation between framework messages (in the `fetchai/contract_api:1.0.0` protocol) and the implementation specifics of the ABI.\n\nContracts usually implement four types of methods:\n\n- a method to create a smart contract deployment transaction,\n- methods to create transactions to modify state in the deployed smart contract,\n- methods to create contract calls to execute static methods on the deployed smart contract, and\n- methods to query the state of the deployed smart contract.\n\nContracts can be added as packages which means they become reusable across AEA projects.\n\nThe smart contract wrapped in an AEA contract package might be a third-party smart contract or your own smart contract potentially interacting with a third-party contract on-chain.\n\n## Interacting with Contracts from Skills\n\nInteracting with contracts in almost all cases requires network access. Therefore, the framework executes contract related logic in a <a href=\"../connection\">Connection</a>.\n\n<img src=\"../assets/message-flow-contract-ledger.jpg\" alt=\"Message flow for contract and ledger interactions\" class=\"center\" style=\"display: block; margin-left: auto; margin-right: auto;width:80%;\">\n\nIn particular, the `fetchai/ledger:0.21.5` connection can be used to execute contract related logic. The skills communicate with the `fetchai/ledger:0.21.5` connection via the `fetchai/contract_api:1.0.0` protocol. This protocol implements a request-response pattern to serve the four types of methods listed above:\n\n- the `get_deploy_transaction` message is used to request a `deploy` transaction for a specific contract. For instance, to request a `deploy` transaction for the deployment of the smart contract wrapped in the `fetchai/erc1155:0.23.3` package, we send the following message to the `fetchai/ledger:0.21.5`:\n\n``` python\ncontract_api_msg = ContractApiMessage(\n    performative=ContractApiMessage.Performative.GET_DEPLOY_TRANSACTION,\n    dialogue_reference=contract_api_dialogues.new_self_initiated_dialogue_reference(),\n    ledger_id=strategy.ledger_id,\n    contract_id=\"fetchai/erc1155:0.23.3\",\n    callable=\"get_deploy_transaction\",\n    kwargs=ContractApiMessage.Kwargs(\n        {\"deployer_address\": self.context.agent_address}\n    ),\n)\n```\n\nAny additional arguments needed by the contract's constructor method should be added to `kwargs`.\n\nThis message will be handled by the `fetchai/ledger:0.21.5` connection and then a `raw_transaction` message will be returned with the matching raw transaction. To send this transaction to the ledger for processing, we first sign the message with the decision maker and then send the signed transaction to the `fetchai/ledger:0.21.5` connection using the `fetchai/ledger_api:1.0.0` protocol. For details on how to implement the message handling, see the handlers in the `erc1155_deploy` skill.\n\n!!! note \"CosmWasm based smart contract deployments\"\n\n    When using CosmWasm based smart contracts two types of deployment transactions exist. The first transaction stores the code on the chain. The second transaction initialises the code. This way, the same contract code can be initialised many times.\n\n    Both the <code>store</code> and <code>init</code> messages use the <code>ContractApiMessage.Performative.GET_DEPLOY_TRANSACTION</code> performative. The ledger API automatically detects the type of transactions based on the provided keyword arguments. In particular, an <code>init</code> transaction requires the keyword arguments <code>code_id</code> (integer), <code>label</code> (string), <code>amount</code> (integer) and <code>init_msg</code> (JSON).\n    \n    For an example look at the <code>fetchai/erc1155:0.23.3</code> package.\n\n- the `get_raw_transaction` message is used to request any transaction for a specific contract which changes state in the contract. For instance, to request a transaction for the creation of token in the deployed `erc1155` smart contract wrapped in the `fetchai/erc1155:0.23.3` package, we send the following message to the `fetchai/ledger:0.21.5`:\n\n``` python\ncontract_api_msg = ContractApiMessage(\n    performative=ContractApiMessage.Performative.GET_RAW_TRANSACTION,\n    dialogue_reference=contract_api_dialogues.new_self_initiated_dialogue_reference(),\n    ledger_id=strategy.ledger_id,\n    contract_id=\"fetchai/erc1155:0.23.3\",\n    contract_address=strategy.contract_address,\n    callable=\"get_create_batch_transaction\",\n    kwargs=ContractApiMessage.Kwargs(\n        {\n            \"deployer_address\": self.context.agent_address,\n            \"token_ids\": strategy.token_ids,\n        }\n    ),\n)\n```\n\nThis message will be handled by the `fetchai/ledger:0.21.5` connection and then a `raw_transaction` message will be returned with the matching raw transaction. For this to be executed correctly, the `fetchai/erc1155:0.23.3` contract package needs to implement the `get_create_batch_transaction` method with the specified key word arguments (see example in *Deploy your own*, below). Similar to the above, to send this transaction to the ledger for processing, we first sign the message with the decision maker and then send the signed transaction to the `fetchai/ledger:0.21.5` connection using the `fetchai/ledger_api:1.0.0` protocol.\n\n- the `get_raw_message` message is used to request any contract method call for a specific contract which does not change state in the contract. For instance, to request a call to get a hash from some input data in the deployed `erc1155` smart contract wrapped in the `fetchai/erc1155:0.23.3` package, we send the following message to the `fetchai/ledger:0.21.5`:\n\n``` python\ncontract_api_msg = ContractApiMessage(\n    performative=ContractApiMessage.Performative.GET_RAW_MESSAGE,\n    dialogue_reference=contract_api_dialogues.new_self_initiated_dialogue_reference(),\n    ledger_id=strategy.ledger_id,\n    contract_id=\"fetchai/erc1155:0.23.3\",\n    contract_address=strategy.contract_address,\n    callable=\"get_hash_single\",\n    kwargs=ContractApiMessage.Kwargs(\n        {\n            \"from_address\": from_address,\n            \"to_address\": to_address,\n            \"token_id\": token_id,\n            \"from_supply\": from_supply,\n            \"to_supply\": to_supply,\n            \"value\": value,\n            \"trade_nonce\": trade_nonce,\n        }\n    ),\n)\n```\n\nThis message will be handled by the `fetchai/ledger:0.21.5` connection and then a `raw_message` message will be returned with the matching raw message. For this to be executed correctly, the `fetchai/erc1155:0.23.3` contract package needs to implement the `get_hash_single` method with the specified key word arguments. We can then send the raw message to the `fetchai/ledger:0.21.5` connection using the `fetchai/ledger_api:1.0.0` protocol. In this case, signing is not required.\n\n- the `get_state` message is used to request any contract method call to query state in the deployed contract. For instance, to request a call to get the balances in the deployed `erc1155` smart contract wrapped in the `fetchai/erc1155:0.23.3` package, we send the following message to the `fetchai/ledger:0.21.5`:\n\n``` python\ncontract_api_msg = ContractApiMessage(\n    performative=ContractApiMessage.Performative.GET_STATE,\n    dialogue_reference=contract_api_dialogues.new_self_initiated_dialogue_reference(),\n    ledger_id=strategy.ledger_id,\n    contract_id=\"fetchai/erc1155:0.23.3\",\n    contract_address=strategy.contract_address,\n    callable=\"get_balance\",\n    kwargs=ContractApiMessage.Kwargs(\n        {\"agent_address\": address, \"token_id\": token_id}\n    ),\n)\n```\n\nThis message will be handled by the `fetchai/ledger:0.21.5` connection and then a `state` message will be returned with the matching state. For this to be executed correctly, the `fetchai/erc1155:0.23.3` contract package needs to implement the `get_balance` method with the specified key word arguments. We can then send the raw message to the `fetchai/ledger:0.21.5` connection using the `fetchai/ledger_api:1.0.0` protocol. In this case, signing is not required.\n\n## Developing your own\n\nThe easiest way to get started developing your own contract is by using the <a href=\"../scaffolding\">scaffold</a> command:\n\n``` bash\naea scaffold contract my_new_contract\n```\n\nThis will scaffold a contract package called `my_new_contract` with three files:\n\n- `__init__.py`\n- `contract.py`, containing the scaffolded contract class\n- `contract.yaml` containing the scaffolded configuration file\n\nOnce your scaffold is in place, you can create a `build` folder in the package and copy the smart contract interface (e.g. bytes code and ABI) to it. Then, specify the path to the interfaces in the `contract.yaml`. For instance, if you use Ethereum, then you might specify the following:\n\n``` yaml\ncontract_interface_paths:\n    ethereum: build/my_contract.json\n```\n\nwhere `ethereum` is the ledger id and `my_contract.json` is the file containing the byte code and ABI.\n\nFinally, you will want to implement the part of the contract interface you need in `contract.py`:\n\n``` python\nfrom aea.contracts.base import Contract\nfrom aea.crypto.base import LedgerApi\n\n\nclass MyContract(Contract):\n    \"\"\"The MyContract contract class which acts as a bridge between AEA framework and ERC1155 ABI.\"\"\"\n\n    @classmethod\n    def get_create_batch_transaction(\n        cls,\n        ledger_api: LedgerApi,\n        contract_address: str,\n        deployer_address: str,\n        token_ids: List[int],\n        data: Optional[bytes] = b\"\",\n        gas: int = 300000,\n    ) -> Dict[str, Any]:\n        \"\"\"\n        Get the transaction to create a batch of tokens.\n\n        :param ledger_api: the ledger API\n        :param contract_address: the address of the contract\n        :param deployer_address: the address of the deployer\n        :param token_ids: the list of token ids for creation\n        :param data: the data to include in the transaction\n        :param gas: the gas to be used\n        :return: the transaction object\n        \"\"\"\n        # create the transaction dict\n        nonce = ledger_api.api.eth.getTransactionCount(deployer_address)\n        instance = cls.get_instance(ledger_api, contract_address)\n        tx = instance.functions.createBatch(\n            deployer_address, token_ids\n        ).buildTransaction(\n            {\n                \"gas\": gas,\n                \"gasPrice\": ledger_api.api.toWei(\"50\", \"gwei\"),\n                \"nonce\": nonce,\n            }\n        )\n        tx = cls._try_estimate_gas(ledger_api, tx)\n        return tx\n```\n\nAbove, we implement a method to create a transaction, in this case a transaction to create a batch of tokens. The method will be called by the framework, specifically the `fetchai/ledger:0.21.5` connection once it receives a message (see bullet point 2 above). The method first gets the latest transaction nonce of the `deployer_address`, then constructs the contract instance, then uses the instance to build the transaction and finally updates the gas on the transaction.\n\nIt helps to look at existing contract packages, like `fetchai/erc1155:0.23.3`, and skills using them, like `fetchai/erc1155_client:0.11.0` and `fetchai/erc1155_deploy:0.31.6`, for inspiration and guidance.\n"
  },
  {
    "path": "docs/core-components-1.md",
    "content": "# Core Components - Part 1\n\nThe AEA framework consists of several core components, some required to run an AEA and others optional.\n\nThe following sections discuss the inner workings of the AEA framework and how it calls the code in custom packages (see <a href=\"https://en.wikipedia.org/wiki/Inversion_of_control\" target=\"_blank\">inversion of control</a> and a helpful comparison <a href=\"https://www.freecodecamp.org/news/the-difference-between-a-framework-and-a-library-bd133054023f/\" target=\"_blank\">here</a>). Whilst it is in principle possible to use parts of the framework as a library, we do not recommend it.\n\n## The Elements Each AEA Uses\n\n### Envelope\n\n<img src=\"../assets/envelope.jpg\" alt=\"Envelope of an AEA\" class=\"center\" style=\"display: block; margin-left: auto; margin-right: auto;width:50%;\">\n\n<a href=\"../api/aea#aea-objects\">`AEA`</a> objects communicate asynchronously via <a href=\"../api/mail/base#envelope-objects\">`Envelopes`</a>.\n\nAn <a href=\"../api/mail/base#envelope-objects\">`Envelope`</a> is the core object with which agents communicate. It is a vehicle for <a href=\"../api/protocols/base#message-objects\">`Messages`</a> with five attributes:\n\n- `to`: defines the destination address.\n- `sender`: defines the sender address.\n- `protocol_id`: defines the id of the `Protocol`.\n- `message`: is a bytes field which holds the `Message` in serialized form.\n- `Optional[context]`: an optional field to specify routing information in a URI.\n\n<a href=\"../api/protocols/base#message-objects\">`Messages`</a>  must adhere to a `Protocol`.\n\n### Protocol\n\n<a href=\"../api/protocols/base#protocol-objects\">`Protocols`</a> define agent-to-agent as well as component-to-component interactions within AEAs. As such, they include:\n\n- `Messages` defining the syntax of messages;\n- `Serialization` defining how a `Message` is encoded for transport; and, optionally\n- `Dialogues`, which define rules over `Message` sequences.\n\nThe framework provides one default `Protocol`, called `default` (current version `fetchai/default:1.1.7`). This `Protocol` provides a bare-bones implementation for an AEA `Protocol` which includes a <a href=\"../api/protocols/default/message#packages.fetchai.protocols.default.message\">`DefaultMessage`</a>  class and associated <a href=\"../api/protocols/default/serialization#packages.fetchai.protocols.default.serialization\">`DefaultSerializer`</a> and <a href=\"../api/protocols/default/dialogues#packages.fetchai.protocols.default.dialogues\">`DefaultDialogue`</a> classes.\n\nAdditional `Protocols`, for new types of interactions, can be added as packages. For more details on `Protocols` you can read the <a href=\"../protocol\">protocol guide</a>. To learn how you can easily automate protocol definition, head to the guide for the <a href=\"../protocol-generator\">protocol generator</a>.\n\nProtocol specific `Messages`, wrapped in `Envelopes`, are sent and received to other agents, agent components and services via `Connections`.\n\n### Connection\n\nA <a href=\"../api/connections/base#connection-objects\">`Connection`</a> wraps an SDK or API and provides an interface to networks, ledgers or other services. Where necessary, a `Connection` is responsible for translating between the framework specific `Envelope` with its contained `Message` and the external service or third-party protocol (e.g. `HTTP`).\n\nThe framework provides one default `Connection`, called `stub` (current version `fetchai/stub:0.21.3`). It implements an I/O reader and writer to send `Messages` to the agent from a local file.\n\nAdditional `Connections` can be added as packages. For more details on `Connections` read the <a href=\"../connection\"> `Connection` guide </a>.\n\nAn AEA runs and manages `Connections` via a `Multiplexer`.\n\n### Multiplexer\n\n<img src=\"../assets/multiplexer.png\" alt=\"Multiplexer of an AEA\" class=\"center\" style=\"display: block; margin-left: auto; margin-right: auto;width:50%;\">\n\nThe <a href=\"../api/multiplexer#multiplexer-objects\">`Multiplexer`</a> is responsible for maintaining (potentially multiple) `Connections`.\n\nIt maintains an <a href=\"../api/multiplexer#inbox-objects\">`InBox`</a> and <a href=\"../api/multiplexer#outbox-objects\">`OutBox`</a>, which are, respectively, queues for incoming and outgoing `Envelopes` from the perspective of `Skills`.\n\n### Skill\n\n<img src=\"../assets/skills.jpg\" alt=\"Skills of an AEA\" class=\"center\" style=\"display: block; margin-left: auto; margin-right: auto;width:50%;\">\n\n<a href=\"../api/skills/base#skill-objects\">`Skills`</a> are the core focus of the framework's extensibility as they implement business logic to deliver economic value for the AEA. They are self-contained capabilities that AEAs can dynamically take on board, in order to expand their effectiveness in different situations.\n\nA `Skill` encapsulates implementations of the three abstract base classes `Handler`, `Behaviour`, `Model`, and is closely related with the abstract base class `Task`:\n\n- <a href=\"../api/skills/base#handler-objects\">`Handler`</a>: each `Skill` has zero, one or more `Handler` objects. There is a one-to-one correspondence between `Handlers` and the protocols in an AEA (also known as the _registered protocols_). Handlers implement AEAs' **reactive** behaviour. If an AEA understands a `Protocol` referenced in a received `Envelope` (i.e. the protocol is registered in this AEA), this envelope is sent to the corresponding `Handler` which executes the AEA's reaction to this `Message`.\n- <a href=\"../api/skills/base#behaviour-objects\">`Behaviour`</a>: a `skill` can have zero, one or more `Behaviours`, each encapsulating actions which further the AEAs goal and are initiated by internals of the AEA rather than external events. Behaviours implement AEAs' **pro-activeness**. The framework provides a number of <a href=\"../api/skills/behaviours\">abstract base classes</a> implementing different types of simple and composite behaviours (e.g. cyclic, one-shot, finite-state-machine, etc), and these define how often and in what order a behaviour and its sub-behaviours must be executed.\n- <a href=\"../api/skills/base#model-objects\">`Model`</a>: zero, one or more `Models` that inherit from the `Model` abstract base class and are accessible via the `SkillContext`.\n- <a href=\"../api/skills/tasks#task-objects\">`Task`</a>: zero, one or more `Tasks` encapsulate background work internal to the AEA. `Task` differs from the other three in that it is not a part of `Skills`, but `Tasks` are declared in or from `Skills` if a packaging approach for AEA creation is used.\n\nA `Skill` can read (parts of) an AEA's state (as summarised in the <a href=\"../api/context/base#agentcontext-objects\">`AgentContext`</a>), and propose actions to the AEA according to its specific logic. As such, more than one `Skill` could exist per `Protocol`, competing with each other in suggesting to the AEA the best course of actions to take. In technical terms, this means `Skills` are horizontally arranged.\n\nFor instance, an AEA which is trading goods, could subscribe to more than one `Skill`, where each corresponds to a different trading strategy.\n\nThe framework places no limits on the complexity of `Skills`. They can implement simple (e.g. `if-this-then-that`) logic or be complex (e.g. a deep learning model or reinforcement learning agent).\n\nThe framework provides one default `Skill`, called `error`. Additional `Skills` can be added as packages. For more details on `Skills` head over to the <a href=\"../skill\"> `Skill` guide </a>.\n\n### Agent Loop\n\nThe <a href=\"../api/agent_loop#baseagentloop-objects\">`AgentLoop`</a> performs a series of activities while the `AEA` state is not `stopped`.\n\n- it calls the `act()` function of all active registered `Behaviours` at their respective tick rate.\n- it grabs all Envelopes waiting in the `InBox` queue and calls the `handle()` function for the `Handlers` currently registered against the `Protocol` of the `Envelope`.\n- it dispatches the internal `Messages` from the decision maker (described below) to the handler in the relevant `Skill`.\n\nThe <a href=\"../api/agent_loop#baseagentloop-objects\">`AgentLoop`</a> and <a href=\"../api/multiplexer#multiplexer-objects\">`Multiplexer`</a> are decoupled via the <a href=\"../api/multiplexer#inbox-objects\">`InBox`</a> and <a href=\"../api/multiplexer#outbox-objects\">`OutBox`</a>, and both are maintained by the <a href=\"../api/runtime#baseruntime-objects\">`Runtime`</a>.\n\n## Next Steps\n\n### Recommended\n\nWe recommend you continue with the next step in the 'Getting Started' series:\n\n- <a href=\"../aea-vs-mvc\">AEA and web frameworks</a>\n\n### Relevant Deep-Dives\n\nMost AEA development focuses on developing the `Skills` and `Protocols` necessary for an AEA to deliver against its economic objectives.\n\nUnderstanding `Protocols` is core to developing your own agent. You can learn more about the `Protocols` agents use to communicate with each other and how they are created in the following section:\n\n- <a href=\"../protocol\">Protocols</a>\n\nMost of an AEA developer's time is spent on `Skill` development. `Skills` are the core business logic components of an AEA. Check out the following guide to learn more:\n\n- <a href=\"../skill\">Skills</a>\n\nIn most cases, one of the available `Connection` packages can be used. Occasionally, you might develop your own `Connection`:\n\n- <a href=\"../connection\">Connections</a>\n"
  },
  {
    "path": "docs/core-components-2.md",
    "content": "# Core components - Part 2\n\nThe AEA framework consists of several core components, some required to run an AEA and others optional.\n\nIn <a href=\"../core-components-1\">Core Components - Part 1</a> we described the common components each AEA uses. In this page, we will look at more advanced components.\n\n## Required Components Used by AEAs\n\n### Decision Maker\n\n<img src=\"../assets/decision-maker.jpg\" alt=\"Decision Maker of an AEA\" class=\"center\" style=\"display: block; margin-left: auto; margin-right: auto;width:50%;\">\n\nThe <a href=\"../api/decision_maker/base#decisionmaker-objects\">`DecisionMaker`</a> can be thought of as a `Wallet` manager plus \"economic brain\" of the AEA. It is responsible for the AEA's crypto-economic security and goal management, and it contains the preference and ownership representation of the AEA. The decision maker is the only component with access to the `Wallet`'s private keys.\n\nYou can learn more about the decision maker <a href=\"../decision-maker\">here</a>. In its simplest form, the decision maker acts like a `Wallet` with `Handler` that reacts to the messages it receives from the skills.\n\n### Wallet\n\nThe <a href=\"../api/crypto/wallet#wallet-objects\">`Wallet`</a> contains the private-public key pairs used by the AEA. Skills do not have access to the wallet, only the decision maker does.\n\nThe agent has two sets of private keys, as configured in the `aea-config.yaml`:\n\n- `private_key_paths`: This is a dictionary mapping identifiers to the file paths of private keys used in the AEA. For each identifier, e.g. `fetchai`, the AEA can have one private key. The private keys listed here are available in the `Decision Maker` and the associated public keys and addresses are available in all skills. The AEA uses these keys to sign transactions and messages. These keys usually hold the AEAs funds.\n- `connection_private_key_paths`: This is a dictionary mapping identifiers to the file paths of private keys used in connections. For each identifier, e.g. `fetchai`, the `Multiplexer` can have one private key. The private keys listed here are available in the connections. The connections use these keys to secure message transport, for instance.\n\nIt is the responsibility of the AEA's user to safeguard the keys used and ensure that keys are only used in a single AEA. Using the same key across different AEAs will lead to various failure modes.\n\nPrivate keys can be encrypted at rest. The CLI commands used for interacting with the wallet allow specifying a password for encryption/decryption.\n\n### Identity\n\nThe <a href=\"../api/identity/base#identity-objects\">`Identity`</a> is an abstraction that represents the identity of an AEA in the Open Economic Framework, backed by public-key cryptography. It contains the AEA's addresses as well as its name.\n\nThe identity can be accessed in a `Skill` via the <a href=\"../api/context/base#agentcontext-objects\">`AgentContext`</a>.\n\n## Optional Components Used by AEAs\n\n### Contracts\n\n<img src=\"../assets/contracts.jpg\" alt=\"Contracts of an AEA\" class=\"center\" style=\"display: block; margin-left: auto; margin-right: auto;width:50%;\">\n\n<a href=\"../api/contracts/base#contract-objects\">`Contracts`</a> wrap smart contracts for third-party decentralized ledgers. In particular, they provide wrappers around the API or ABI of a smart contract. They expose an API to abstract implementation specifics of the ABI from the `Skills`.\n\n`Contracts` usually contain the logic to create contract transactions and make contract calls.\n\n`Contracts` can be added as packages. For more details on `Contracts` also read the `Contract` guide <a href=\"../contract\">here</a>.\n\n## Putting it Together\n\nTaken together, the core components from this section and the <a href=\"../core-components-1\">first part</a> provide the following simplified illustration of an AEA:\n\n<img src=\"../assets/simplified-aea.jpg\" alt=\"Simplified illustration of an AEA\" class=\"center\" style=\"display: block; margin-left: auto; margin-right: auto;width:100%;\">\n\n## Next Steps\n\n### Recommended\n\nWe recommend you continue with the next step in the 'Getting Started' series:\n\n- <a href=\"../interaction-protocol\">How AEAs talk to each other - Interaction protocols</a>\n\n### Relevant Deep-Dives\n\nUnderstanding the decision maker is vital to developing a goal oriented and crypto-economically safe AEA. You can learn more about the `DecisionMaker` in the following section:\n\n- <a href=\"../decision-maker\">Decision Maker</a>\n\nUnderstanding `Contracts` is important when developing AEAs that make commitments or use smart contracts for other purposes. You can learn more about the `Contracts` agents use in the following section:\n\n- <a href=\"../contract\">Contracts</a>\n"
  },
  {
    "path": "docs/core-components.md",
    "content": "# Core Components\n\nAEAs can be made from various components, much like legos, and these components can be of differing types. Below are some of the more important types of components an agent can have.   \n\n## Skill\n\nA **Skill** is an isolated, self-contained, (and preferably atomic) functionality that AEAs can take on board to expand their capability. Skills contain the proactive and reactive behaviour that ultimately makes it possible for an AEA to deliver economic value to its owner.  \n\nA Skill encapsulates implementations of three base classes `Handler`, `Behaviour`, `Model`, and is closely related with `Task`:\n\n- Handler: Handlers implement AEAs' **reactive** behaviour. If an AEA understands a protocol referenced in a received `Envelope`, this envelope is sent to the corresponding handler which executes the AEA's reaction to this message.\n- Behaviour: Behaviours implement AEAs' **proactiveness**, encapsulating actions which further an AEA's goals, and are initiated by internals of the AEA rather than external events. \n- Model: Encapsulate arbitrary objects and is made available to all components of the skill.\n- Task: Tasks encapsulate background work internal to the AEA. \n\nA skill can read (parts of) an AEA's state and propose actions to the AEA according to its specific logic. As such, more than one skill could exist per protocol, competing with each other in suggesting to the AEA the best course of actions to take. \n\nFor instance, an AEA which is trading goods, could subscribe to more than one skill, where each corresponds to a different trading strategy.\n\nThe framework places no limits on the complexity of `Skills`. They can implement simple (e.g. if-this-then-that) logic or be complex (e.g. a deep learning model or reinforcement learning agent).\n\nThe framework provides one default `error` skill. Additional `Skills` can be added as packages. For more details on skills, head over to the <a href=\"../skill\"> `Skill` guide </a>.\n\n## Protocol\n\nA **Protocol** defines the structure and nature of an interaction that can happen between agents, or between components of an agent. You can think of a protocol as the language that two agents speak and a skill for this protocol as a particular way of speaking this language. From a game-theoretic viewpoint, a protocol defines the rules of a game and a skill for this protocol defines a particular strategy for playing this game. \n\nProtocols define agent-to-agent as well as component-to-component interactions within AEAs. As such, they include:\n\n- `Messages`: defining the syntax of messages.\n- `Serialization`: defining how a message is encoded for transport.\n- `Dialogues`: defines rules over sequences of messages.\n\nThe framework provides one `default` protocol. This protocol provides a bare-bones implementation which includes a <a href=\"../api/protocols/default/message#packages.fetchai.protocols.default.message\">`DefaultMessage`</a>  class and associated <a href=\"../api/protocols/default/serialization#packages.fetchai.protocols.default.serialization\">`DefaultSerializer`</a> and <a href=\"../api/protocols/default/dialogues#packages.fetchai.protocols.default.dialogues\">`DefaultDialogue`</a> classes.\n\nAdditional protocols for new types of interactions, can be added as packages. For more details on protocols, you can read the <a href=\"../protocol\">protocol guide</a>. To learn how you can easily automate protocol definition, head to the guide for the <a href=\"../protocol-generator\">protocol generator</a>.\n\nProtocol specific messages, wrapped in `Envelopes`, are sent and received to other agents, agent components and services via **Connections**.\n\n## Connection\n\n**Connections** act as interfaces between an agent and the outside world. As such, a connection allows the agent to communicate with some entity outside of it, for example, another agent, a traditional HTTP server, a database, a reinforcement learning training environment, a blockchain, etc.\n\nWhere necessary, a Connection is responsible for translating between the framework specific `Envelope` with its contained message and the external service or third-party protocol (e.g. HTTP).\n\nThe framework provides one default `stub` connection. It implements an I/O reader and writer to send messages to the agent from a local file.\n\nAdditional connections can be added as packages. For more details on `Connections` read the <a href=\"../connection\">`Connection` guide</a>."
  },
  {
    "path": "docs/css/admonitions.css",
    "content": ":root {\n  --md-admonition-icon--target: url('data:image/svg+xml;charset=utf-8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path d=\"M11 2v2.07A8.002 8.002 0 0 0 4.07 11H2v2h2.07A8.002 8.002 0 0 0 11 19.93V22h2v-2.07A8.002 8.002 0 0 0 19.93 13H22v-2h-2.07A8.002 8.002 0 0 0 13 4.07V2m-2 4.08V8h2V6.09c2.5.41 4.5 2.41 4.92 4.91H16v2h1.91c-.41 2.5-2.41 4.5-4.91 4.92V16h-2v1.91C8.5 17.5 6.5 15.5 6.08 13H8v-2H6.09C6.5 8.5 8.5 6.5 11 6.08M12 11a1 1 0 0 0-1 1 1 1 0 0 0 1 1 1 1 0 0 0 1-1 1 1 0 0 0-1-1Z\"/></svg>')\n}\n\n.md-typeset .admonition.target,\n.md-typeset details.target {\n  border-color: rgb(255, 225, 0);\n}\n.md-typeset .target > .admonition-title,\n.md-typeset .target > summary {\n  background-color: rgba(255, 225, 0, 0.1);\n}\n.md-typeset .target > .admonition-title::before,\n.md-typeset .target > summary::before {\n  background-color: rgb(255, 225, 0);\n  -webkit-mask-image: var(--md-admonition-icon--target);\n          mask-image: var(--md-admonition-icon--target);\n}\n"
  },
  {
    "path": "docs/css/my-styles.css",
    "content": "/* overriding colours */\n[data-md-color-scheme=\"default\"] {\n  --md-primary-fg-color: #4051b5;\n  --md-typeset-color: #525252;\n  --md-a-color:#1d6ff5;\n}\n[data-md-color-scheme=\"slate\"] {\n  --md-primary-fg-color: #fff;\n  --md-typeset-color: #d0d6fc;\n  --md-a-color:#5997fd;\n}\n\n/*overriding the header*/\n.md-header-nav__button.md-logo img {\n\twidth: auto!important;\n}\n\n.md-nav__button .md-logo{\n\twidth: auto!important;\n}\n\n.md-header__button.md-logo img {\n  width: auto !important;\n}\n\n\n@media screen and (max-width: 76.1875em) {\n  .md-nav--primary .md-nav__title[for=\"__drawer\"] {\n    background-color: #202943 !important;\n  }\n\n\t.md-nav--primary .md-nav__title[for=__drawer] img{\n\t\twidth: 180px;\n\t    height: auto;\n\t}\n}\n\n.md-header{\n\tbackground-color:#202943!important;\n\tpadding: 10px;\n\theight: auto;\n}\n\n/* Overriding font header, link, paragraph styling  */\n.md-typeset h3,\n.md-typeset h1,\n.md-typeset h2 {\n  margin-bottom: 0.4em;\n  color: var(--md-primary-fg-color);\n  font-weight: 400;\n}\n\n.md-typeset a {\n  color: var(--md-a-color);\n}\n\n.black-link{\n\tcolor: black!important;\n}\n\n.md-nav__item .md-nav__link--active {\n  padding: 4px 8px;\n  position: relative;\n  left: -8px;\n  background: #E9EBFC;\n  border-radius: 16px;\n  width: fit-content;\n  color: rgb(64, 81, 181)\n}\n\n@media screen and (max-width: 76.1875em) {\n  .md-nav__item .md-nav__link--active {\n    left: 0;\n  }\n}\n"
  },
  {
    "path": "docs/debug.md",
    "content": "# Debugging\n\nThere are multiple ways in which to configure your AEA for debugging during development. We focus on the standard Python approach here.\n\n## Using `pdb` stdlib\n\nYou can add a debugger anywhere in your code:\n\n``` python\nimport pdb; pdb.set_trace()\n```\n\nThen simply run you AEA with the `--skip-consistency-check` mode:\n\n``` bash\naea -s run\n```\n\nFor more guidance on how to use `pdb` check out <a href=\"https://docs.python.org/3/library/pdb.html\" target=\"_blank\">the documentation</a>.\n\n## Using an IDE\n\n- For VSCode modify the `launch.json` to include the following information:\n\n``` json\n{\n    \"version\": \"0.2.0\",\n    \"configurations\": [\n        {\n            \"name\": \"aea run\",\n            \"type\": \"python\",\n            \"request\": \"launch\",\n            \"program\": \"PATH_TO_VIRTUAL_ENV/bin/aea\",\n            \"args\": [\"-v\",\"DEBUG\",\"--skip-consistency-check\",\"run\"],\n            \"cwd\": \"CWD\",\n            \"console\": \"integratedTerminal\"\n        }\n    ]\n}\n```\n\nwhere `PATH_TO_VIRTUAL_ENV` should be replaced with the path to the virtual environment and `CWD` with the working directory for the agent to debug (where the `aea-config.yaml` file is).\n"
  },
  {
    "path": "docs/decision-maker-transaction.md",
    "content": "# Create Decision-Maker Transaction\n\nThis guide can be considered as a part 2 of the <a href=\"../standalone-transaction/\">the stand-alone transaction demo</a>. The main difference is that now we are going to use the decision-maker to sign the transaction.\n\nFirst, import the libraries and the set the constant values. (Get the `packages` directory from the AEA repository `svn export https://github.com/fetchai/agents-aea.git/trunk/packages`.)\n\n``` python\nimport logging\nimport time\nfrom threading import Thread\nfrom typing import Optional, cast\n\nfrom aea_ledger_fetchai import FetchAICrypto\n\nfrom aea.aea_builder import AEABuilder\nfrom aea.configurations.base import PublicId, SkillConfig\nfrom aea.crypto.helpers import create_private_key\nfrom aea.crypto.ledger_apis import LedgerApis\nfrom aea.crypto.wallet import Wallet\nfrom aea.helpers.transaction.base import RawTransaction, Terms\nfrom aea.identity.base import Identity\nfrom aea.protocols.base import Address, Message\nfrom aea.protocols.dialogue.base import Dialogue\nfrom aea.skills.base import Handler, Model, Skill, SkillContext\n\nfrom packages.fetchai.protocols.signing.dialogues import SigningDialogue\nfrom packages.fetchai.protocols.signing.dialogues import (\n    SigningDialogues as BaseSigningDialogues,\n)\nfrom packages.fetchai.protocols.signing.message import SigningMessage\n\nfrom tests.conftest import get_wealth_if_needed\n\n\nlogger = logging.getLogger(\"aea\")\nlogging.basicConfig(level=logging.INFO)\n\nFETCHAI_PRIVATE_KEY_FILE_1 = \"fetchai_private_key_1.txt\"\nFETCHAI_PRIVATE_KEY_FILE_2 = \"fetchai_private_key_2.txt\"\n```\n\n## Create a Private Key and an AEA\n\nTo have access to the decision-maker, which is responsible for signing transactions, we need to create an AEA. We can create an AEA with the builder, providing it with a private key we generate first.\n\n``` python\n    # Create a private key\n    create_private_key(\n        FetchAICrypto.identifier, private_key_file=FETCHAI_PRIVATE_KEY_FILE_1\n    )\n\n    # Instantiate the builder and build the AEA\n    # By default, the default protocol, error skill and stub connection are added\n    builder = AEABuilder()\n\n    builder.set_name(\"my_aea\")\n\n    builder.add_private_key(FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE_1)\n\n    # Create our AEA\n    my_aea = builder.build()\n```\n\n## Add a Simple Skill\n\nAdd a simple skill with a signing handler and the signing dialogues.\n\n``` python\n    # add a simple skill with handler\n    skill_context = SkillContext(my_aea.context)\n    skill_config = SkillConfig(name=\"simple_skill\", author=\"fetchai\", version=\"0.1.0\")\n    signing_handler = SigningHandler(\n        skill_context=skill_context, name=\"signing_handler\"\n    )\n    signing_dialogues_model = SigningDialogues(\n        skill_context=skill_context,\n        name=\"signing_dialogues\",\n        self_address=str(skill_config.public_id),\n    )\n\n    simple_skill = Skill(\n        skill_config,\n        skill_context,\n        handlers={signing_handler.name: signing_handler},\n        models={signing_dialogues_model.name: signing_dialogues_model},\n    )\n    my_aea.resources.add_skill(simple_skill)\n```\n\n## Create a Second Identity\n\n``` python\n    # create a second identity\n    create_private_key(\n        FetchAICrypto.identifier, private_key_file=FETCHAI_PRIVATE_KEY_FILE_2\n    )\n\n    counterparty_wallet = Wallet({FetchAICrypto.identifier: FETCHAI_PRIVATE_KEY_FILE_2})\n    get_wealth_if_needed(counterparty_wallet.addresses[\"fetchai\"])\n\n    counterparty_identity = Identity(\n        name=\"counterparty_aea\",\n        addresses=counterparty_wallet.addresses,\n        public_keys=counterparty_wallet.public_keys,\n        default_address_key=FetchAICrypto.identifier,\n    )\n```\n\n## Create the Signing Message\n\nNext, we are creating the signing message and sending it to the decision-maker.\n\n``` python\n    # create signing message for decision maker to sign\n    terms = Terms(\n        ledger_id=FetchAICrypto.identifier,\n        sender_address=my_aea.identity.address,\n        counterparty_address=counterparty_identity.address,\n        amount_by_currency_id={\"FET\": -1},\n        quantities_by_good_id={\"some_service\": 1},\n        nonce=\"some_nonce\",\n        fee_by_currency_id={\"FET\": 0},\n    )\n    get_wealth_if_needed(terms.sender_address)\n\n    signing_dialogues = cast(SigningDialogues, skill_context.signing_dialogues)\n    stub_transaction = LedgerApis.get_transfer_transaction(\n        terms.ledger_id,\n        terms.sender_address,\n        terms.counterparty_address,\n        terms.sender_payable_amount,\n        terms.sender_fee,\n        terms.nonce,\n    )\n    signing_msg = SigningMessage(\n        performative=SigningMessage.Performative.SIGN_TRANSACTION,\n        dialogue_reference=signing_dialogues.new_self_initiated_dialogue_reference(),\n        raw_transaction=RawTransaction(FetchAICrypto.identifier, stub_transaction),\n        terms=terms,\n    )\n    signing_dialogue = cast(\n        Optional[SigningDialogue],\n        signing_dialogues.create_with_message(\"decision_maker\", signing_msg),\n    )\n    assert signing_dialogue is not None\n    my_aea.context.decision_maker_message_queue.put_nowait(signing_msg)\n\n```\n\n## Run the Agent\n\nFinally, we are running the agent and expect the signed transaction to be printed in the terminal.\n\n``` python\n    # Set the AEA running in a different thread\n    try:\n        logger.info(\"STARTING AEA NOW!\")\n        t = Thread(target=my_aea.start)\n        t.start()\n\n        # Let it run long enough to interact with the decision maker\n        time.sleep(1)\n    finally:\n        # Shut down the AEA\n        logger.info(\"STOPPING AEA NOW!\")\n        my_aea.stop()\n        t.join()\n```\n\nAfter the completion of the signing, we get the signed transaction.\n\n## More Details\n\nTo be able to register a handler that reads the internal messages, we have to create a class at the end of the file which processes the signing messages.\n\n``` python\nclass SigningDialogues(Model, BaseSigningDialogues):\n    \"\"\"Signing dialogues model.\"\"\"\n\n    def __init__(self, self_address: Address, **kwargs) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :return: None\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> Dialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return SigningDialogue.Role.SKILL\n\n        BaseSigningDialogues.__init__(\n            self,\n            self_address=self_address,\n            role_from_first_message=role_from_first_message,\n        )\n\n\nclass SigningHandler(Handler):\n    \"\"\"Implement the signing handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = SigningMessage.protocol_id  # type: Optional[PublicId]\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup for the handler.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to a message.\n\n        :param message: the message\n        :return: None\n        \"\"\"\n        signing_msg = cast(SigningMessage, message)\n\n        # recover dialogue\n        signing_dialogues = cast(SigningDialogues, self.context.signing_dialogues)\n        signing_dialogue = cast(\n            Optional[SigningDialogue], signing_dialogues.update(signing_msg)\n        )\n        if signing_dialogue is None:\n            self._handle_unidentified_dialogue(signing_msg)\n            return\n\n        # handle message\n        if signing_msg.performative is SigningMessage.Performative.SIGNED_TRANSACTION:\n            self._handle_signed_transaction(signing_msg, signing_dialogue)\n        elif signing_msg.performative is SigningMessage.Performative.ERROR:\n            self._handle_error(signing_msg, signing_dialogue)\n        else:\n            self._handle_invalid(signing_msg, signing_dialogue)\n\n    def teardown(self) -> None:\n        \"\"\"\n        Implement the handler teardown.\n\n        :return: None\n        \"\"\"\n\n    def _handle_unidentified_dialogue(self, signing_msg: SigningMessage) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param msg: the message\n        \"\"\"\n        self.context.logger.info(\n            \"received invalid signing message={}, unidentified dialogue.\".format(\n                signing_msg\n            )\n        )\n\n    def _handle_signed_transaction(\n        self, signing_msg: SigningMessage, signing_dialogue: SigningDialogue\n    ) -> None:\n        \"\"\"\n        Handle a signing message.\n\n        :param signing_msg: the signing message\n        :param signing_dialogue: the dialogue\n        :return: None\n        \"\"\"\n        self.context.logger.info(\"transaction signing was successful.\")\n        logger.info(signing_msg.signed_transaction)\n\n    def _handle_error(\n        self, signing_msg: SigningMessage, signing_dialogue: SigningDialogue\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param signing_msg: the signing message\n        :param signing_dialogue: the dialogue\n        :return: None\n        \"\"\"\n        self.context.logger.info(\n            \"transaction signing was not successful. Error_code={} in dialogue={}\".format(\n                signing_msg.error_code, signing_dialogue\n            )\n        )\n\n    def _handle_invalid(\n        self, signing_msg: SigningMessage, signing_dialogue: SigningDialogue\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param signing_msg: the signing message\n        :param signing_dialogue: the dialogue\n        :return: None\n        \"\"\"\n        self.context.logger.warning(\n            \"cannot handle signing message of performative={} in dialogue={}.\".format(\n                signing_msg.performative, signing_dialogue\n            )\n        )\n```\n\nYou can find the full code for this example below:\n\n??? note \"Transaction via decision-maker full code:\"\n\n    ``` python\n    import logging\n    import time\n    from threading import Thread\n    from typing import Optional, cast\n\n    from aea_ledger_fetchai import FetchAICrypto\n    \n    from aea.aea_builder import AEABuilder\n    from aea.configurations.base import PublicId, SkillConfig\n    from aea.crypto.helpers import create_private_key\n    from aea.crypto.ledger_apis import LedgerApis\n    from aea.crypto.wallet import Wallet\n    from aea.helpers.transaction.base import RawTransaction, Terms\n    from aea.identity.base import Identity\n    from aea.protocols.base import Address, Message\n    from aea.protocols.dialogue.base import Dialogue\n    from aea.skills.base import Handler, Model, Skill, SkillContext\n    \n    from packages.fetchai.protocols.signing.dialogues import SigningDialogue\n    from packages.fetchai.protocols.signing.dialogues import (\n        SigningDialogues as BaseSigningDialogues,\n    )\n    from packages.fetchai.protocols.signing.message import SigningMessage\n    \n    from tests.conftest import get_wealth_if_needed\n    \n    \n    logger = logging.getLogger(\"aea\")\n    logging.basicConfig(level=logging.INFO)\n    \n    FETCHAI_PRIVATE_KEY_FILE_1 = \"fetchai_private_key_1.txt\"\n    FETCHAI_PRIVATE_KEY_FILE_2 = \"fetchai_private_key_2.txt\"\n    \n    \n    def run():\n        \"\"\"Run demo.\"\"\"\n    \n        # Create a private key\n        create_private_key(\n            FetchAICrypto.identifier, private_key_file=FETCHAI_PRIVATE_KEY_FILE_1\n        )\n    \n        # Instantiate the builder and build the AEA\n        # By default, the default protocol, error skill and stub connection are added\n        builder = AEABuilder()\n    \n        builder.set_name(\"my_aea\")\n    \n        builder.add_private_key(FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE_1)\n    \n        # Create our AEA\n        my_aea = builder.build()\n    \n        # add a simple skill with handler\n        skill_context = SkillContext(my_aea.context)\n        skill_config = SkillConfig(name=\"simple_skill\", author=\"fetchai\", version=\"0.1.0\")\n        signing_handler = SigningHandler(\n            skill_context=skill_context, name=\"signing_handler\"\n        )\n        signing_dialogues_model = SigningDialogues(\n            skill_context=skill_context,\n            name=\"signing_dialogues\",\n            self_address=str(skill_config.public_id),\n        )\n    \n        simple_skill = Skill(\n            skill_config,\n            skill_context,\n            handlers={signing_handler.name: signing_handler},\n            models={signing_dialogues_model.name: signing_dialogues_model},\n        )\n        my_aea.resources.add_skill(simple_skill)\n    \n        # create a second identity\n        create_private_key(\n            FetchAICrypto.identifier, private_key_file=FETCHAI_PRIVATE_KEY_FILE_2\n        )\n    \n        counterparty_wallet = Wallet({FetchAICrypto.identifier: FETCHAI_PRIVATE_KEY_FILE_2})\n        get_wealth_if_needed(counterparty_wallet.addresses[\"fetchai\"])\n    \n        counterparty_identity = Identity(\n            name=\"counterparty_aea\",\n            addresses=counterparty_wallet.addresses,\n            public_keys=counterparty_wallet.public_keys,\n            default_address_key=FetchAICrypto.identifier,\n        )\n    \n        # create signing message for decision maker to sign\n        terms = Terms(\n            ledger_id=FetchAICrypto.identifier,\n            sender_address=my_aea.identity.address,\n            counterparty_address=counterparty_identity.address,\n            amount_by_currency_id={\"FET\": -1},\n            quantities_by_good_id={\"some_service\": 1},\n            nonce=\"some_nonce\",\n            fee_by_currency_id={\"FET\": 0},\n        )\n        get_wealth_if_needed(terms.sender_address)\n    \n        signing_dialogues = cast(SigningDialogues, skill_context.signing_dialogues)\n        stub_transaction = LedgerApis.get_transfer_transaction(\n            terms.ledger_id,\n            terms.sender_address,\n            terms.counterparty_address,\n            terms.sender_payable_amount,\n            terms.sender_fee,\n            terms.nonce,\n        )\n        signing_msg = SigningMessage(\n            performative=SigningMessage.Performative.SIGN_TRANSACTION,\n            dialogue_reference=signing_dialogues.new_self_initiated_dialogue_reference(),\n            raw_transaction=RawTransaction(FetchAICrypto.identifier, stub_transaction),\n            terms=terms,\n        )\n        signing_dialogue = cast(\n            Optional[SigningDialogue],\n            signing_dialogues.create_with_message(\"decision_maker\", signing_msg),\n        )\n        assert signing_dialogue is not None\n        my_aea.context.decision_maker_message_queue.put_nowait(signing_msg)\n    \n        # Set the AEA running in a different thread\n        try:\n            logger.info(\"STARTING AEA NOW!\")\n            t = Thread(target=my_aea.start)\n            t.start()\n    \n            # Let it run long enough to interact with the decision maker\n            time.sleep(1)\n        finally:\n            # Shut down the AEA\n            logger.info(\"STOPPING AEA NOW!\")\n            my_aea.stop()\n            t.join()\n    \n    \n    class SigningDialogues(Model, BaseSigningDialogues):\n        \"\"\"Signing dialogues model.\"\"\"\n    \n        def __init__(self, self_address: Address, **kwargs) -> None:\n            \"\"\"\n            Initialize dialogues.\n    \n            :return: None\n            \"\"\"\n            Model.__init__(self, **kwargs)\n    \n            def role_from_first_message(  # pylint: disable=unused-argument\n                message: Message, receiver_address: Address\n            ) -> Dialogue.Role:\n                \"\"\"Infer the role of the agent from an incoming/outgoing first message\n    \n                :param message: an incoming/outgoing first message\n                :param receiver_address: the address of the receiving agent\n                :return: The role of the agent\n                \"\"\"\n                return SigningDialogue.Role.SKILL\n    \n            BaseSigningDialogues.__init__(\n                self,\n                self_address=self_address,\n                role_from_first_message=role_from_first_message,\n            )\n    \n    \n    class SigningHandler(Handler):\n        \"\"\"Implement the signing handler.\"\"\"\n    \n        SUPPORTED_PROTOCOL = SigningMessage.protocol_id  # type: Optional[PublicId]\n    \n        def setup(self) -> None:\n            \"\"\"Implement the setup for the handler.\"\"\"\n    \n        def handle(self, message: Message) -> None:\n            \"\"\"\n            Implement the reaction to a message.\n    \n            :param message: the message\n            :return: None\n            \"\"\"\n            signing_msg = cast(SigningMessage, message)\n    \n            # recover dialogue\n            signing_dialogues = cast(SigningDialogues, self.context.signing_dialogues)\n            signing_dialogue = cast(\n                Optional[SigningDialogue], signing_dialogues.update(signing_msg)\n            )\n            if signing_dialogue is None:\n                self._handle_unidentified_dialogue(signing_msg)\n                return\n    \n            # handle message\n            if signing_msg.performative is SigningMessage.Performative.SIGNED_TRANSACTION:\n                self._handle_signed_transaction(signing_msg, signing_dialogue)\n            elif signing_msg.performative is SigningMessage.Performative.ERROR:\n                self._handle_error(signing_msg, signing_dialogue)\n            else:\n                self._handle_invalid(signing_msg, signing_dialogue)\n    \n        def teardown(self) -> None:\n            \"\"\"\n            Implement the handler teardown.\n    \n            :return: None\n            \"\"\"\n    \n        def _handle_unidentified_dialogue(self, signing_msg: SigningMessage) -> None:\n            \"\"\"\n            Handle an unidentified dialogue.\n    \n            :param msg: the message\n            \"\"\"\n            self.context.logger.info(\n                \"received invalid signing message={}, unidentified dialogue.\".format(\n                    signing_msg\n                )\n            )\n    \n        def _handle_signed_transaction(\n            self, signing_msg: SigningMessage, signing_dialogue: SigningDialogue\n        ) -> None:\n            \"\"\"\n            Handle a signing message.\n    \n            :param signing_msg: the signing message\n            :param signing_dialogue: the dialogue\n            :return: None\n            \"\"\"\n            self.context.logger.info(\"transaction signing was successful.\")\n            logger.info(signing_msg.signed_transaction)\n    \n        def _handle_error(\n            self, signing_msg: SigningMessage, signing_dialogue: SigningDialogue\n        ) -> None:\n            \"\"\"\n            Handle an oef search message.\n    \n            :param signing_msg: the signing message\n            :param signing_dialogue: the dialogue\n            :return: None\n            \"\"\"\n            self.context.logger.info(\n                \"transaction signing was not successful. Error_code={} in dialogue={}\".format(\n                    signing_msg.error_code, signing_dialogue\n                )\n            )\n    \n        def _handle_invalid(\n            self, signing_msg: SigningMessage, signing_dialogue: SigningDialogue\n        ) -> None:\n            \"\"\"\n            Handle an oef search message.\n    \n            :param signing_msg: the signing message\n            :param signing_dialogue: the dialogue\n            :return: None\n            \"\"\"\n            self.context.logger.warning(\n                \"cannot handle signing message of performative={} in dialogue={}.\".format(\n                    signing_msg.performative, signing_dialogue\n                )\n            )\n    \n    \n    if __name__ == \"__main__\":\n        run()\n    ```\n"
  },
  {
    "path": "docs/decision-maker.md",
    "content": "# Decision Maker\n\nThe <a href=\"../api/decision_maker/base#decisionmaker-objects\">`DecisionMaker`</a> can be thought of like a wallet manager plus \"economic brain\" of the AEA. It is responsible for the AEA's crypto-economic security and goal management, and it contains the preference and ownership representation of the AEA. The decision maker is the only component which has access to the wallet's private keys.\n\n## Interaction with Skills\n\nSkills communicate with the decision maker via <a href=\"../api/protocols/base#message-objects\">`Messages`</a>. At present, the decision maker processes messages of two protocols:\n\n- <a href=\"../api/protocols/signing/message#signingmessage-objects\">`SigningMessage`</a>: it is used by skills to propose a transaction to the decision-maker for signing.\n\n- <a href=\"../api/protocols/state_update/message#stateupdatemessage-objects\">`StateUpdateMessage`</a>: it is used to initialize the decision maker with preferences and ownership states. It can also be used to update the ownership states in the decision maker if the settlement of transaction takes place.\n\nA message, say `msg`, is sent to the decision maker like so from any skill:\n\n``` python\nself.context.decision_maker_message_queue.put_nowait(msg)\n```\n\nThe decision maker processes messages and can accept or reject them.\n\nTo process `Messages` from the decision maker in a given skill you need to create a `Handler`, in particular a `SigningHandler` like so:\n\n``` python\nclass SigningHandler(Handler):\n\n    protocol_id = SigningMessage.protocol_id\n\n    def handle(self, message: Message):\n        \"\"\"\n        Handle a signing message.\n\n        :param message: the signing message from the decision maker.\n        \"\"\"\n        # code to handle the message\n```\n\n## Custom `DecisionMaker`\n\nThe framework implements a default <a href=\"../api/decision_maker/default#decisionmakerhandler-objects\">`DecisionMakerHandler`</a> and an advanced <a href=\"../api/decision_maker/gop#decisionmakerhandler-objects\">`DecisionMakerHandler`</a>. You can also implement your own and mount it.\n\nNo further configuration is needed to use the default. To use the advanced decision maker handler, add the following configuration to the `aea-config.yaml` of your AEA (on page 1):\n\n``` yaml\ndecision_maker_handler:\n  config: {}\n  dotted_path: \"aea.decision_maker.gop:DecisionMakerHandler\"\n  file_path: null\n```\n\nThe easiest way to add a custom decision maker handler is to run the following command to scaffold a custom `DecisionMakerHandler`:\n\n``` bash\naea scaffold decision-maker-handler\n```\n\nYou can then implement your own custom logic to process messages and interact with the `Wallet`.\n\n!!! note\n    For examples how to use these concepts have a look at the `tac_` skills. These functionalities are experimental and subject to change.\n"
  },
  {
    "path": "docs/defining-data-models.md",
    "content": "# Defining Data Models\n\nIn this section, we explain how to define _data models_, an important component of the OEF Search & Discovery. It allows agents to describe themselves and to discover the services/resources they are interested in.\n\nIn a sentence, a <a href=\"../api/helpers/search/models#datamodel-objects\">`DataModel`</a> is a set of `attributes`, and a <a href=\"../api/helpers/search/models#description-objects\">`Description`</a> of a service/resource is an assignment of those attributes.\n\nAll you need to specify data models and descriptions (that is, instances of the data model) can be found in the `aea.helpers.search` module.\n\n## Attributes\n\nAt the lowest level of our data model language, we have the <a href=\"../api/helpers/search/models#attribute-objects\">`Attribute`</a>.\nAn attribute is an abstract definition of a property.\n\nIt is identified by a `name`, that must be unique in a given data model (that is, we can't have two attributes that share the same name).\n\nEvery attribute has a `type`, that specifies the domain of the property, that is, the possible values that the attribute can assume. At the moment, we support five types of attributes:\n\n- strings\n- integers\n- booleans\n- floats\n- locations, i.e. instances of `Location` (pairs of (latitude, longitude))\n\nAn attribute can be `optional`, in the sense that instantiation of the attribute is not mandatory by the instances of the data model.\n\nFinally, every attribute might have a `description` that explains the purpose of the attribute.\n\n**Example**: suppose we have a bookshop, and we want to describe the books we sell. Presumably, we would like to include: the following properties of our books:\n\n- The `title`\n- The `author`\n- The `genre` (e.g. science fiction, horror)\n- The `year of publication`\n- The `average rating` (average of the ratings between 0 and 5)\n- The `ISBN` code\n- If it can be sold as an e-book.\n\nFor each of these fields, we can define an attribute by using `Attribute`:\n\n``` python\nfrom aea.helpers.search.models import Attribute, Location\nattr_title   = Attribute(\"title\", str, True, \"The title of the book.\")\nattr_author  = Attribute(\"author\", str, True, \"The author of the book.\")\nattr_genre   = Attribute(\"genre\", str, True, \"The genre of the book.\")\nattr_year    = Attribute(\"year\", int, True, \"The year of publication of the book.\")\nattr_avg_rat = Attribute(\"average_rating\",  float,    False, \"The average rating of the book.\")\nattr_isbn    = Attribute(\"ISBN\", str, True, \"The ISBN.\")\nattr_ebook   = Attribute(\"ebook_available\", bool, False, \"If the book can be sold as an e-book.\")\nattr_bookshop = Attribute(\"bookshop_pos\", Location, False, \"The location of the bookshop where you can find the book\")\n```\n\nLet's focus on the parameters of the `Attribute` constructor:\n\n1. the first one is the name of the attribute. It is needed to instantiate a data model and to define queries over it.\n2. the second one is the type of the attribute. It specifies the domain of the possible values the attribute can assume.\n   E.g. the attribute `year` can only be an integer, whereas the `average_rating` can only be a floating-point number.\n   The supported types are: `str`, `int`, `bool`, `float` and `Location`.\n3. the third one is a boolean that specifies whether the attribute is _always required_ or it _can be omitted_. For example, we might not be able to specify the `ebook_available` attribute, maybe because it's not applicable to some kind of books.\n4. the fourth parameter is the description, that is a short description of the purpose of the attribute.\n\n## Data Models\n\nA _data model_ is just a set of _attributes_. The class that implements the data model is `DataModel`.\n\n**Example**: let's continue with the example of the bookshop. Once we've defined the attributes, we'd like to group them\nin the same structure. We can do it in the following way:\n\n``` python\nfrom aea.helpers.search.models import DataModel\n\nbook_model = DataModel(\"book\", [\n    attr_title,\n    attr_author,\n    attr_genre,\n    attr_year,\n    attr_avg_rat,\n    attr_isbn,\n    attr_ebook,\n    attr_bookshop\n], \"A data model to describe books.\")\n```\n\nA `DataModel` requires:\n\n1. a _name_ (in the example the name is `\"book\"`) used to refer to the data model.\n2. a _list of attributes_, that constitutes the abstract data model.\n3. an (optional) _description_ about the purpose of the data model.\n\n## Description\n\nA `Description` is just an _instantiation of a data model_. That is, we specify a value to every attribute belonging to the data model we are interested in.\n\nThe class that implements the description is `Description`.\n\n**Example**: now we have all we need to create a little catalogue about our books:\n\n``` python\nfrom aea.helpers.search.models import Description\n\nIt = Description({\n    \"title\" :           \"It\",\n    \"author\":           \"Stephen King\",\n    \"genre\":            \"horror\",\n    \"year\":             1986,\n    \"average_rating\":   4.5,\n    \"ISBN\":             \"0-670-81302-8\",\n    \"ebook_available\":  True,\n    \"bookshop_pos\":     Location(52.2057092, 0.1183431)\n}, book_model)\n\n_1984 = Description({\n    \"title\" :           \"1984\",\n    \"author\":           \"George Orwell\",\n    \"genre\":            \"novel\",\n    \"year\":             1949,\n    \"ISBN\":             \"978-0451524935\",\n    \"ebook_available\":  False\n}, book_model)\n```\n\nWe defined the descriptions for two books, namely `It` and `_1984`, that refers to a data model.\n\nThe attributes are instantiated with a dictionary that has:\n\n- as keys, the name of the attributes.\n- as values, the values associated with the attributes.\n\nNotice that in the latter book we omitted the `average_rating` field. We are allowed to do that because of the `average_rating` attribute is not mandatory.\n"
  },
  {
    "path": "docs/demos.md",
    "content": "# Demos\n\nWe provide demo guides for multiple use-cases, each one involving several AEAs interacting in a different scenario.\n\nThese demos serve to highlight the concept of AEAs as well as provide inspiration for developers. Demos should not be taken as production ready software, although every care is taken to fix bugs when reported.\n\nDemos are alphabetically sorted, we recommend you start with the <a href=\"../weather-skills\">weather skills demo</a>.\n"
  },
  {
    "path": "docs/deployment.md",
    "content": "# Deployment\n\nThe easiest way to run an AEA is using your development environment.\n\nIf you would like to run an AEA from a browser you can use <a href=\"https://colab.research.google.com\" target=\"_blank\">Google Colab</a>. <a href=\"https://gist.github.com/DavidMinarsch/2eeb1541508a61e828b497ab161e1834\" target=\"_blank\">This gist</a> can be opened in <a href=\"https://colab.research.google.com\" target=\"_blank\">Colab</a> and implements the <a href=\"../quickstart\">quick start</a>.\n\nFor deployment, we recommend you use <a href=\"https://www.docker.com/\" target=\"_blank\">Docker</a>.\n\n## Deployment using a Docker Image\n\nFirst, we fetch a directory containing a Dockerfile and some dependencies:\n\n``` bash\nsvn export https://github.com/fetchai/agents-aea/branches/main/deploy-image\ncd deploy-image\n```\n\nThen follow the `README.md` contained in the folder.\n\n## Deployment using Kubernetes\n\nFor an example of how to use <a href=\"https://kubernetes.io\" target=\"_blank\">Kubernetes</a> navigate to our <a href=\"https://github.com/fetchai/agents-aea/tree/main/examples/tac_deploy\" target=\"_blank\">TAC deployment example</a>.\n"
  },
  {
    "path": "docs/design-principles.md",
    "content": "# Design Principles\n\nThe AEA framework development is guided by the following 8 principles:\n\n- **Accessibility**: ease of use.\n- **Modularity**: encourages module creation, sharing and reuse.\n- **Openness**: easily extensible with third-party libraries.\n- **Conciseness**: conceptually simple.\n- **Value-driven**: drives immediate value.\n- **Low entry barriers**: leverages existing programming languages and web protocols.\n- **Safety**: safe for the user (economically speaking).\n- **Goal-alignment**: seamless facilitation of users' preferences and goals.\n"
  },
  {
    "path": "docs/development-setup.md",
    "content": "# Development Setup\n\nAn AEA <a href=\"../package-imports\">consists of packages </a>. When developing, it helps to be able to save packages in a local package registry, rather than pushing them to <a href=\"https://aea-registry.fetch.ai\" target=\"_blank\">remote registry</a>. This guide helps you set up a local package registry and configure the working directory for development.\n\nThere are two ways to write code for an AEA:\n\n1. independent of a concrete AEA project, write individual packages\n\n2. from within an AEA project, write packages for that AEA\n\n## Approach 1\n\nTo prepare a directory (henceforth working directory) for development with the AEA framework you can take a few steps:\n\n- Either, manually:\n    - Ensure you start with an empty working directory to avoid any unnecessary side effects.\n    - In your working directory, create an empty folder called `packages`. This folder will act as the local registry for packages.\n    - In your working directory, create a `.env` file with the constant `PYTHONPATH=$PYTHONPATH:path_to_packages_dir` where `path_to_packages_dir` is the path to the `packages` folder in your working directory.\n- Or, automated:\n    - Fork our <a href=\"https://github.com/fetchai/agents-template\" target=\"_blank\">template repo</a> for AEA development. Then clone it to your machine.\n- Depending on your editor, you might take further steps:\n    - VS Code: The Python Extension in VS Code can be configured to include additional paths in the Python path. The extension has a setting for `python.envFile` which specifies the path to a file containing environment variable definitions. The default is set to `\"python.envFile\": \"${workspaceFolder}/.env\"`. Provide the path to the `.env` file in the above settings. In the `.env` file, add the `PYTHONPATH` constant defined above. Then close VS Code and re-open it for the settings to take effect.\n\nAfter developing a package, you can add it to an AEA project in the working directory (e.g. `aea create AGENT_NAME && cd AGENT_NAME && aea add --local PACKAGE_TYPE PUBLIC_ID` will create a new AEA project `AGENT_NAME` and add the package of type `PACKAGE_TYPE` with public id `PUBLIC_ID` to it.)\n\n## Approach 2\n\nIt is also possible to develop directly in an AEA project:\n\n- Prepare a directory (henceforth working directory) for development.\n- Create a new project `aea create AGENT_NAME && cd AGENT_NAME`\n- Scaffold a new package `aea scaffold --with-symlinks PACKAGE_TYPE PACKAGE_NAME`. This will create the package scaffold under the directory `{PACKAGE_TYPE}s` and create symlinks to ensure package import paths line up with the folder structure. The symlinks are not needed to run the AEA. They are purely for your IDE.\n- In your working directory, create a `.env` file with the constant `PYTHONPATH=$PYTHONPATH:path_to_project_dir` where `path_to_project_dir` is the path to the AEA project contained in your working directory.\n- Depending on your editor, you might take further steps:\n    - VS Code: The Python Extension in VS Code can be configured to include additional paths in the Python path. The extension has a setting for `python.envFile` which specifies the path to a file containing environment variable definitions. The default is set to `\"python.envFile\": \"${workspaceFolder}/.env\"`. Provide the path to the `.env` file in the above settings. In the `.env` file, add the `PYTHONPATH` constant defined above. Then close VS Code and re-open it for the settings to take effect.\n\n## General Advice\n\nThis advice partially overlaps with the previous two sections:\n\n- When developing a specific AEA, it might be helpful to publish/push or fetch/add from local registry. From your working directory/AEA project, simply execute the usual AEA CLI commands. The CLI will first search in the `packages` directory, then in the remote AEA registry. You can explicitly point to local registry by providing flag `--local` or `--remote` to only point to remote registry (see <a href=\"../cli-commands\">here</a> for more details on CLI commands).\n- When working on an AEA, it may help to provide a symbolic link to the `packages` directory, so that the import paths are detected by your editor. Simply create an empty file with `touch packages` in your AEA project, then create a symbolic link to the `packages` directory with `ln -s ../packages packages`.\n- Alternatively, it can help to provide symbolic links within an AEA to align import paths with folder structure. Simply create an empty file with `touch packages` in your AEA project, then create a symbolic link to `ln -s vendor packages`.\n"
  },
  {
    "path": "docs/diagram.md",
    "content": "# Architectural Diagram\n\nThe framework has two distinctive parts.\n\n- A **core** that is developed by the Fetch.ai team as well as external contributors.\n- **Extensions** (also known as **packages**) developed by any developer.\n\nCurrently, the framework supports four types of packages which can be added to the core as modules:\n\n- <a href=\"../skill\">Skills</a> encapsulate logic that deliver economic value to the AEA. Skills are the main focus of the framework's extensibility.\n- <a href=\"../protocol\">Protocols</a> define the structure of agent-to-agent and component-to-component interactions (messages and dialogues) for agents.\n- <a href=\"../connection\">Connections</a> provide interfaces for the agent to connect with the outside world. They wrap SDKs or APIs and provide interfaces to networks, ledgers and other services.\n- <a href=\"../contract\">Contracts</a> wrap smart contracts for Fetch.ai and third-party decentralized ledgers.\n\nThe following figure illustrates the framework's architecture:\n\n<img src=\"../assets/simplified-aea.jpg\" alt=\"Simplified illustration of an AEA\" class=\"center\" style=\"display: block; margin-left: auto; margin-right: auto;width:100%;\">\n\nThe execution is broken down in more detail below:\n\n<img src=\"../assets/execution.jpg\" alt=\"Execution of an AEA\" class=\"center\" style=\"display: block; margin-left: auto; margin-right: auto;width:100%;\">\n\nThe agent operation breaks down into three parts:\n\n- **Setup**: calls the `setup()` method of all registered resources\n- **Operation**:\n    - Agent loop (Thread 1 - Asynchronous agent loop):\n        - `react()`: this function grabs all Envelopes waiting in the `InBox` queue and calls the `handle()` method on the Handler(s) responsible for them.\n        - `act()`: this function calls the `act()` method of all registered Behaviours.\n        - `update()`: this function enqueues scheduled tasks for execution with the `TaskManager` and executes the decision maker.\n    - Task loop (Thread 2- Synchronous): executes available tasks\n    - Decision maker loop (Thread 3- Synchronous): processes internal messages\n    - Multiplexer (Thread 4 - Asynchronous event loop): processes incoming and outgoing messages across several connections asynchronously.\n- **Teardown**: calls the `teardown()` method of all registered resources\n\nTo prevent a developer from blocking the main loop with custom skill code, an execution time limit is  applied to every `Behaviour.act` and `Handler.handle` call.\n\nBy default, the execution limit is set to `0` seconds, which disables the feature. You can set the limit to a strictly positive value (e.g. `0.1` seconds) to test your AEA for production readiness. If the `act` or `handle` time exceed this limit, the call will be terminated.\n\nAn appropriate message is added to the logs in the case of some code execution being terminated.\n"
  },
  {
    "path": "docs/ecosystem.md",
    "content": "# Agent Ecosystem\n\nAEAs are situated within a larger ecosystem comprised of various other systems and technology layers.\n\n<img src=\"../assets/oef-ledger.jpg\" alt=\"The AEA, OEF, and Ledger systems\" class=\"center\">\n\n## Agent Communication Network (ACN)\n\nACN is a <a href=\"../acn\">peer-to-peer communication network</a> for agents. It allows AEAs to send and receive envelopes between each other.\n\nThe implementation builds on the open-source <a href=\"https://libp2p.io/\" target=\"_blank\">libp2p</a> library. A distributed hash table is used by all participating peers to maintain a mapping between agents' cryptographic addresses and their network addresses.\n\nAgents can receive messages from other agents if they are both connected to the ACN (see <a href=\"../p2p-connection\">here</a> for an example).\n\n## Search and Discovery\n\nAn <a href=\"../simple-oef\">sOEF node</a> allows agents to discover each other. In particular, agents can register themselves and the services they offer, and can search for agents who offer specific services.\n\nFor two agents to be able to find each other, at least one must register itself on the sOEF and the other must query the sOEF node for it. Detailed documentation is provided <a href=\"../simple-oef\">here</a>.\n\n## Ledgers\n\nLedgers enable AEAs to store transactions, for example involving the transfer of funds to each other, or the execution of smart contracts. They optionally ensure the truth and integrity of agent to agent interactions.\n\nAlthough a ledger can, in principle, be used to store structured data (e.g. training data in a machine learning model), in most cases the resulting costs and privacy implications do not make this sustainable. Instead, usually only references to structured data - often in the form of hashes - are stored on a ledger, and the actual data is stored off-chain.\n\nThe Python implementation of the AEA Framework currently integrates with three ledgers:\n\n- <a href=\"https://docs.fetch.ai/ledger_v2/\" target=\"_blank\">Fetch.ai ledger</a>\n- <a href=\"https://ethereum.org/en/developers/learning-tools/\" target=\"_blank\">Ethereum ledger</a>\n- <a href=\"https://v1.cosmos.network/sdk\" target=\"_blank\">Cosmos ledger</a>\n\nFurthermore, the framework makes it straightforward for any developer to create a ledger plugin, adding support for another ledger.\n\n### AEAs as Second Layer Technology\n\nThe following presentation discusses how AEAs can be seen as second layer technology to ledgers.\n\n<iframe width=\"560\" height=\"315\" src=\"https://www.youtube.com/embed/gvzYX7CYk-A\" frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen></iframe>\n"
  },
  {
    "path": "docs/erc1155-skills.md",
    "content": "# Contract Deploy and Interact\n\nThe AEA `erc1155_deploy` and `erc1155_client` skills demonstrate an interaction between two AEAs which use a smart contract.\n\n- The `erc1155_deploy` skill deploys the smart contract, creates and mints items.\n- The `erc1155_client` skill signs a transaction to complete a trustless trade with its counterparty.\n\n## Preparation Instructions\n\n### Dependencies\n\nFollow the <a href=\"../quickstart/#preliminaries\">Preliminaries</a> and <a href=\"../quickstart/#installation\">Installation</a> sections from the AEA quick start.\n\n## Discussion\n\nThe scope of this guide is demonstrating how you can deploy a smart contract and interact with it using AEAs. In this specific demo, you create two AEAs. One deploys and creates tokens inside a smart contract. The other signs a transaction to complete an atomic swap. The smart contract used is ERC1155 with a one-step atomic swap functionality. This means the trade between the two AEAs can be trustless.\n\n!!! note\n    This is only for demonstrative purposes since the AEA deploying the contract also has the ability to mint tokens. In reality, the transfer of tokens from the AEA signing the transaction is worthless.\n\n## Demo\n\n### Create the Deployer AEA\n\nFetch the AEA that will deploy the contract:\n\n``` bash\naea fetch fetchai/erc1155_deployer:0.34.5\ncd erc1155_deployer\naea install\naea build\n```\n\n??? note \"Alternatively, create from scratch:\"\n    Create the AEA that will deploy the contract.\n\n    ``` bash\n    aea create erc1155_deployer\n    cd erc1155_deployer\n    aea add connection fetchai/p2p_libp2p:0.27.5\n    aea add connection fetchai/soef:0.27.6\n    aea add connection fetchai/ledger:0.21.5\n    aea add skill fetchai/erc1155_deploy:0.31.6\n    aea config set --type dict agent.dependencies \\\n    '{\n      \"aea-ledger-fetchai\": {\"version\": \"<2.0.0,>=1.0.0\"},\n      \"aea-ledger-ethereum\": {\"version\": \"<2.0.0,>=1.0.0\"},\n      \"aea-ledger-cosmos\": {\"version\": \"<2.0.0,>=1.0.0\"}\n    }'\n    aea config set agent.default_connection fetchai/p2p_libp2p:0.27.5\n    aea config set --type dict agent.default_routing \\\n    '{\n      \"fetchai/contract_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n      \"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n      \"fetchai/oef_search:1.1.7\": \"fetchai/soef:0.27.6\"\n    }'\n    aea config set --type list vendor.fetchai.connections.p2p_libp2p.cert_requests \\\n    '[{\"identifier\": \"acn\", \"ledger_id\": \"ethereum\", \"not_after\": \"2023-01-01\", \"not_before\": \"2022-01-01\", \"public_key\": \"fetchai\", \"save_path\": \".certs/conn_cert.txt\"}]'\n    aea install\n    aea build\n    ```\n\n    And change the default ledger:\n\n    ``` bash\n    aea config set agent.default_ledger ethereum\n    ```\n\nCreate a private key for the deployer AEA and add it for Ethereum use:\n\n``` bash\naea generate-key ethereum\naea add-key ethereum ethereum_private_key.txt\n```\n\nCreate a private key for the P2P connection:\n\n``` bash\naea generate-key fetchai fetchai_connection_private_key.txt\naea add-key fetchai fetchai_connection_private_key.txt --connection\n```\n\nFinally, certify the key for use by the connections that request that:\n\n``` bash\naea issue-certificates\n```\n\n### Create the Client AEA\n\nIn another terminal, fetch the client AEA which will receive some tokens from the deployer.\n\n``` bash\naea fetch fetchai/erc1155_client:0.34.5\ncd erc1155_client\naea install\naea build\n```\n\n??? note \"Alternatively, create from scratch:\"\n    Create the AEA that will get some tokens from the deployer.\n\n    ``` bash\n    aea create erc1155_client\n    cd erc1155_client\n    aea add connection fetchai/p2p_libp2p:0.27.5\n    aea add connection fetchai/soef:0.27.6\n    aea add connection fetchai/ledger:0.21.5\n    aea add skill fetchai/erc1155_client:0.29.6\n    aea config set --type dict agent.dependencies \\\n    '{\n      \"aea-ledger-fetchai\": {\"version\": \"<2.0.0,>=1.0.0\"},\n      \"aea-ledger-ethereum\": {\"version\": \"<2.0.0,>=1.0.0\"},\n      \"aea-ledger-cosmos\": {\"version\": \"<2.0.0,>=1.0.0\"}\n    }'\n    aea config set agent.default_connection fetchai/p2p_libp2p:0.27.5\n    aea config set --type dict agent.default_routing \\\n    '{\n      \"fetchai/contract_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n      \"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n      \"fetchai/oef_search:1.1.7\": \"fetchai/soef:0.27.6\"\n    }'\n    aea config set --type list vendor.fetchai.connections.p2p_libp2p.cert_requests \\\n    '[{\"identifier\": \"acn\", \"ledger_id\": \"ethereum\", \"not_after\": \"2023-01-01\", \"not_before\": \"2022-01-01\", \"public_key\": \"fetchai\", \"save_path\": \".certs/conn_cert.txt\"}]'\n    aea install\n    aea build\n    ```\n    \n    And change the default ledger:\n\n    ``` bash\n    aea config set agent.default_ledger ethereum\n    ```\n\nCreate a private key for the client AEA and add it for Ethereum use:\n\n``` bash\naea generate-key ethereum\naea add-key ethereum ethereum_private_key.txt\n```\n\nCreate a private key for the P2P connection:\n\n``` bash\naea generate-key fetchai fetchai_connection_private_key.txt\naea add-key fetchai fetchai_connection_private_key.txt --connection\n```\n\nFinally, certify the key for use by the connections that request that:\n\n``` bash\naea issue-certificates\n```\n\n## Run Ganache\n\nExecute the following command to run Ganache:\n\n``` bash\ndocker run -p 8545:8545 trufflesuite/ganache-cli:latest --verbose --gasPrice=0 --gasLimit=0x1fffffffffffff --account=\"$(cat erc1155_deployer/ethereum_private_key.txt),1000000000000000000000\" --account=\"$(cat erc1155_client/ethereum_private_key.txt),1000000000000000000000\"\n```\n\nWait some time for the wealth creation to be mined on Ropsten.\n\nCheck your wealth:\n\n``` bash\naea get-wealth ethereum\n```\n\nYou should get `1000000000000000000000`.\n\n!!! note\n    If no wealth appears after a while, then try funding the private key directly using a web faucet.\n\n## Update SOEF Configurations for both AEAs\n\nUpdate the SOEF configuration in both AEA projects:\n\n``` bash\naea config set vendor.fetchai.connections.soef.config.chain_identifier ethereum\n```\n\n## Run the AEAs\n\nFirst, run the deployer AEA:\n\n``` bash\naea run\n```\n\nOnce you see a message of the form `To join its network use multiaddr 'SOME_ADDRESS'` take note of this address.\n\nAlternatively, use `aea get-multiaddress fetchai -c -i fetchai/p2p_libp2p:0.27.5 -u public_uri` to retrieve the address. The output will be something like `/dns4/127.0.0.1/tcp/9000/p2p/16Uiu2HAm2JPsUX1Su59YVDXJQizYkNSe8JCusqRpLeeTbvY76fE5`.\n\nThis is the entry peer address for the local <a href=\"../acn\">agent communication network</a> created by the deployer.\n\nThis AEA then performs the following steps:\n\n- deploys the smart contract\n- creates a batch of items in the smart contract\n- mints a batch of items in the smart contract\n\nAt some point you should see the log output:\n\n``` bash\nregistering service on SOEF.\n```\n\nAt this point, configure the client AEA to connect to the same local ACN created by the deployer by running the following command in the client's terminal, replacing `SOME_ADDRESS` with the value you noted above:\n\n``` bash\naea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \\\n'{\n  \"delegate_uri\": \"127.0.0.1:11001\",\n  \"entry_peers\": [\"SOME_ADDRESS\"],\n  \"local_uri\": \"127.0.0.1:9001\",\n  \"log_file\": \"libp2p_node.log\",\n  \"public_uri\": \"127.0.0.1:9001\"\n}'\n```\n\nThen, run the client AEA:\n\n``` bash\naea run\n```\n\nYou will see that after discovery, the two AEAs exchange information about the transaction and the client at the end signs and sends the signature to the deployer AEA to send it to the network.\n\n!!! note\n    Transactions on Ropsten can take a significant amount of time! If you run the example a second time, and the previous transaction is still pending, it can lead to a failure.\n    The warning message `Cannot verify whether transaction improves utility. Assuming it does!` can be ignored.\n\n## Delete the AEAs\n\nWhen you're done, stop the agents (`CTRL+C`), go up a level and delete the AEAs.\n\n``` bash\ncd ..\naea delete erc1155_deployer\naea delete erc1155_client\n```\n\n## Communication\n\nThis diagram shows the communication between the various entities in this interaction:\n\n``` mermaid\n    sequenceDiagram\n        participant Search\n        participant Erc1155_contract\n        participant Client_AEA\n        participant Deployer_AEA\n        participant Blockchain\n\n        activate Search\n        activate Erc1155_contract\n        activate Client_AEA\n        activate Deployer_AEA\n        activate Blockchain\n        \n        Deployer_AEA->>Blockchain: deployes smart contract\n        Deployer_AEA->>ERC1155_contract: creates tokens\n        Deployer_AEA->>ERC1155_contract: mint tokens       \n        Deployer_AEA->>Search: register_service\n        Client_AEA->>Search: search\n        Search-->>Client_AEA: list_of_agents\n        Client_AEA->>Deployer_AEA: call_for_proposal\n        Deployer_AEA->>Client_AEA: inform_message\n        Client_AEA->>Deployer_AEA: signature\n        Deployer_AEA->>Blockchain: send_transaction\n        Client_AEA->>ERC1155_contract: asks_balance\n        \n        deactivate Search\n        deactivate Erc1155_contract\n        deactivate Client_AEA\n        deactivate Deployer_AEA\n        deactivate Blockchain\n```\n"
  },
  {
    "path": "docs/generic-skills-step-by-step.md",
    "content": "# Trade between Two AEAs\n\nThis guide is a step-by-step introduction to building AEAs that advertise their static and dynamic data, find other AEAs with required data, negotiate terms of trade, and carry out trades via ledger transactions.\n\nIf you simply want to run the resulting AEAs <a href=\"../generic-skills\">go here</a>.\n\n## Dependencies (Required)\n\nFollow the <a href=\"../quickstart/#preliminaries\">Preliminaries</a> and <a href=\"../quickstart/#installation\">Installation</a> sections from the AEA quick start.\n\n## Reference Code (Optional)\n\nThis step-by-step guide goes through the creation of two AEAs which are already developed by Fetch.ai. You can get the finished AEAs, and compare your code against them, by following the next steps:\n\n``` bash\naea fetch fetchai/generic_seller:0.29.5\ncd generic_seller\naea eject skill fetchai/generic_seller:0.28.6\ncd ..\n```\n\n``` bash\naea fetch fetchai/generic_buyer:0.30.5\ncd generic_buyer\naea eject skill fetchai/generic_buyer:0.27.6\ncd ..\n```\n\n## Simplification Step\n\nTo keep file paths consistent with the reference code, we suggest you initialize your local author as `fetchai` for the purpose of this demo only:\n\n``` bash\naea init --reset --author fetchai\n```\n\n## Generic Seller AEA\n\n### Step 1: Create the AEA\n\nCreate a new AEA by typing the following command in the terminal:\n\n``` bash\naea create my_generic_seller\ncd my_generic_seller\naea install\n```\n\nOur newly created AEA is inside the current working directory. Let’s create our new skill that will handle the sale of data. Type the following command:\n\n``` bash\naea scaffold skill generic_seller\n```\n\nThe `scaffold skill` command creates the correct structure for a new skill inside our AEA project. You can locate the newly created skill under the \"skills\" folder (`my_generic_seller/skills/generic_seller/`), and it must contain the following files:\n\n- `__init__.py`\n- `behaviours.py`\n- `handlers.py`\n- `my_model.py`\n- `skills.yaml`\n\n### Step 2: Create the Behaviour\n\nA <a href=\"../api/skills/base#behaviour-objects\">`Behaviour`</a> class contains the business logic specific to actions initiated by the AEA, rather than reactions to other events.\n\nOpen the `behaviours.py` file (`my_generic_seller/skills/generic_seller/behaviours.py`) and replace the stub code with the following:\n\n``` python\nfrom typing import Any, Optional, cast\n\nfrom aea.helpers.search.models import Description\nfrom aea.skills.behaviours import TickerBehaviour\n\nfrom packages.fetchai.connections.ledger.base import (\n    CONNECTION_ID as LEDGER_CONNECTION_PUBLIC_ID,\n)\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.skills.generic_seller.dialogues import (\n    LedgerApiDialogues,\n    OefSearchDialogues,\n)\nfrom packages.fetchai.skills.generic_seller.strategy import GenericStrategy\n\n\nDEFAULT_SERVICES_INTERVAL = 60.0\nDEFAULT_MAX_SOEF_REGISTRATION_RETRIES = 5\nLEDGER_API_ADDRESS = str(LEDGER_CONNECTION_PUBLIC_ID)\n\n\nclass GenericServiceRegistrationBehaviour(TickerBehaviour):\n    \"\"\"This class implements a behaviour.\"\"\"\n\n    def __init__(self, **kwargs: Any):\n        \"\"\"Initialise the behaviour.\"\"\"\n        services_interval = kwargs.pop(\n            \"services_interval\", DEFAULT_SERVICES_INTERVAL\n        )  # type: int\n        self._max_soef_registration_retries = kwargs.pop(\n            \"max_soef_registration_retries\", DEFAULT_MAX_SOEF_REGISTRATION_RETRIES\n        )  # type: int\n        super().__init__(tick_interval=services_interval, **kwargs)\n\n        self.failed_registration_msg = None  # type: Optional[OefSearchMessage]\n        self._nb_retries = 0\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup.\"\"\"\n        strategy = cast(GenericStrategy, self.context.strategy)\n        if strategy.is_ledger_tx:\n            ledger_api_dialogues = cast(\n                LedgerApiDialogues, self.context.ledger_api_dialogues\n            )\n            ledger_api_msg, _ = ledger_api_dialogues.create(\n                counterparty=LEDGER_API_ADDRESS,\n                performative=LedgerApiMessage.Performative.GET_BALANCE,\n                ledger_id=strategy.ledger_id,\n                address=cast(str, self.context.agent_addresses.get(strategy.ledger_id)),\n            )\n            self.context.outbox.put_message(message=ledger_api_msg)\n        self._register_agent()\n\n    def act(self) -> None:\n        \"\"\"Implement the act.\"\"\"\n        self._retry_failed_registration()\n\n    def teardown(self) -> None:\n        \"\"\"Implement the task teardown.\"\"\"\n        self._unregister_service()\n        self._unregister_agent()\n\n    def _retry_failed_registration(self) -> None:\n        \"\"\"Retry a failed registration.\"\"\"\n        if self.failed_registration_msg is not None:\n            self._nb_retries += 1\n            if self._nb_retries > self._max_soef_registration_retries:\n                self.context.is_active = False\n                return\n\n            oef_search_dialogues = cast(\n                OefSearchDialogues, self.context.oef_search_dialogues\n            )\n            oef_search_msg, _ = oef_search_dialogues.create(\n                counterparty=self.failed_registration_msg.to,\n                performative=self.failed_registration_msg.performative,\n                service_description=self.failed_registration_msg.service_description,\n            )\n            self.context.outbox.put_message(message=oef_search_msg)\n            self.context.logger.info(\n                f\"Retrying registration on SOEF. Retry {self._nb_retries} out of {self._max_soef_registration_retries}.\"\n            )\n\n            self.failed_registration_msg = None\n\n    def _register(self, description: Description, logger_msg: str) -> None:\n        \"\"\"\n        Register something on the SOEF.\n\n        :param description: the description of what is being registered\n        :param logger_msg: the logger message to print after the registration\n        \"\"\"\n        oef_search_dialogues = cast(\n            OefSearchDialogues, self.context.oef_search_dialogues\n        )\n        oef_search_msg, _ = oef_search_dialogues.create(\n            counterparty=self.context.search_service_address,\n            performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n            service_description=description,\n        )\n        self.context.outbox.put_message(message=oef_search_msg)\n        self.context.logger.info(logger_msg)\n\n    def _register_agent(self) -> None:\n        \"\"\"Register the agent's location.\"\"\"\n        strategy = cast(GenericStrategy, self.context.strategy)\n        description = strategy.get_location_description()\n        self._register(description, \"registering agent on SOEF.\")\n\n    def register_service(self) -> None:\n        \"\"\"Register the agent's service.\"\"\"\n        strategy = cast(GenericStrategy, self.context.strategy)\n        description = strategy.get_register_service_description()\n        self._register(description, \"registering agent's service on the SOEF.\")\n\n    def register_genus(self) -> None:\n        \"\"\"Register the agent's personality genus.\"\"\"\n        strategy = cast(GenericStrategy, self.context.strategy)\n        description = strategy.get_register_personality_description()\n        self._register(\n            description, \"registering agent's personality genus on the SOEF.\"\n        )\n\n    def register_classification(self) -> None:\n        \"\"\"Register the agent's personality classification.\"\"\"\n        strategy = cast(GenericStrategy, self.context.strategy)\n        description = strategy.get_register_classification_description()\n        self._register(\n            description, \"registering agent's personality classification on the SOEF.\"\n        )\n\n    def _unregister_service(self) -> None:\n        \"\"\"Unregister service from the SOEF.\"\"\"\n        strategy = cast(GenericStrategy, self.context.strategy)\n        description = strategy.get_unregister_service_description()\n        oef_search_dialogues = cast(\n            OefSearchDialogues, self.context.oef_search_dialogues\n        )\n        oef_search_msg, _ = oef_search_dialogues.create(\n            counterparty=self.context.search_service_address,\n            performative=OefSearchMessage.Performative.UNREGISTER_SERVICE,\n            service_description=description,\n        )\n        self.context.outbox.put_message(message=oef_search_msg)\n        self.context.logger.info(\"unregistering service from SOEF.\")\n\n    def _unregister_agent(self) -> None:\n        \"\"\"Unregister agent from the SOEF.\"\"\"\n        strategy = cast(GenericStrategy, self.context.strategy)\n        description = strategy.get_location_description()\n        oef_search_dialogues = cast(\n            OefSearchDialogues, self.context.oef_search_dialogues\n        )\n        oef_search_msg, _ = oef_search_dialogues.create(\n            counterparty=self.context.search_service_address,\n            performative=OefSearchMessage.Performative.UNREGISTER_SERVICE,\n            service_description=description,\n        )\n        self.context.outbox.put_message(message=oef_search_msg)\n        self.context.logger.info(\"unregistering agent from SOEF.\")\n```\n\nThis <a href=\"../api/skills/behaviours#tickerbehaviour-objects\">`TickerBehaviour`</a> registers (see `setup` method) and de-registers (see `teardown` method) our AEA’s service on the <a href=\"../simple-oef\">SOEF search node</a> at regular tick intervals (here 60 seconds). By registering, the AEA becomes discoverable to other AEAs.\n\nIn `setup`, prior to registrations, we send a message to the ledger connection to check the account balance for the AEA's address on the configured ledger.\n\n### Step 3: Create the Handler\n\nSo far, we have tasked the AEA with sending register/unregister requests to the <a href=\"../simple-oef\">SOEF search node</a>. However at present, the AEA has no way of handling the responses it receives from the search node, or in fact messages sent by any other AEA.\n\nWe have to specify the logic to negotiate with another AEA based on the strategy we want our AEA to follow. The following diagram illustrates the negotiation flow that we want this AEA to use, as well as interactions with a search node and the blockchain between a `seller_AEA` and a `buyer_AEA`.\n\n``` mermaid\n    sequenceDiagram\n        participant Search\n        participant Buyer_AEA\n        participant Seller_AEA\n        participant Blockchain\n\n        activate Buyer_AEA\n        activate Search\n        activate Seller_AEA\n        activate Blockchain\n\n        Seller_AEA->>Search: register_service\n        Buyer_AEA->>Search: search\n        Search-->>Buyer_AEA: list_of_agents\n        Buyer_AEA->>Seller_AEA: call_for_proposal\n        Seller_AEA->>Buyer_AEA: propose\n        Buyer_AEA->>Seller_AEA: accept\n        Seller_AEA->>Buyer_AEA: match_accept\n        loop Once with LedgerConnection\n            Buyer_AEA->>Buyer_AEA: Get raw transaction from ledger api\n        end\n        loop Once with DecisionMaker\n            Buyer_AEA->>Buyer_AEA: Get signed transaction from decision maker\n        end\n        loop Once with LedgerConnection\n            Buyer_AEA->>Buyer_AEA: Send transaction and get digest from ledger api\n            Buyer_AEA->>Blockchain: transfer_funds\n        end\n        Buyer_AEA->>Seller_AEA: send_transaction_digest\n        Seller_AEA->>Blockchain: check_transaction_status\n        Seller_AEA->>Buyer_AEA: send_data\n\n        deactivate Buyer_AEA\n        deactivate Search\n        deactivate Seller_AEA\n        deactivate Blockchain\n```\n\nIn our case, `my_generic_seller` is the `Seller_AEA` in the above figure.\n\nLet us now implement a <a href=\"../api/skills/base#handler-objects\">`Handler`</a> to deal with incoming messages. Open the `handlers.py` file (`my_generic_seller/skills/generic_seller/handlers.py`) and replace the stub code with the following:\n\n``` python\nfrom typing import Optional, cast\n\nfrom aea.configurations.base import PublicId\nfrom aea.crypto.ledger_apis import LedgerApis\nfrom aea.helpers.transaction.base import TransactionDigest\nfrom aea.protocols.base import Message\nfrom aea.skills.base import Handler\n\nfrom packages.fetchai.connections.ledger.base import (\n    CONNECTION_ID as LEDGER_CONNECTION_PUBLIC_ID,\n)\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.protocols.fipa.message import FipaMessage\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.skills.generic_seller.behaviours import (\n    GenericServiceRegistrationBehaviour,\n)\nfrom packages.fetchai.skills.generic_seller.dialogues import (\n    DefaultDialogues,\n    FipaDialogue,\n    FipaDialogues,\n    LedgerApiDialogue,\n    LedgerApiDialogues,\n    OefSearchDialogue,\n    OefSearchDialogues,\n)\nfrom packages.fetchai.skills.generic_seller.strategy import GenericStrategy\n\n\nLEDGER_API_ADDRESS = str(LEDGER_CONNECTION_PUBLIC_ID)\n\n\nclass GenericFipaHandler(Handler):\n    \"\"\"This class implements a FIPA handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = FipaMessage.protocol_id  # type: Optional[PublicId]\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup for the handler.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to a message.\n\n        :param message: the message\n        \"\"\"\n        fipa_msg = cast(FipaMessage, message)\n\n        # recover dialogue\n        fipa_dialogues = cast(FipaDialogues, self.context.fipa_dialogues)\n        fipa_dialogue = cast(FipaDialogue, fipa_dialogues.update(fipa_msg))\n        if fipa_dialogue is None:\n            self._handle_unidentified_dialogue(fipa_msg)\n            return\n\n        # handle message\n        if fipa_msg.performative == FipaMessage.Performative.CFP:\n            self._handle_cfp(fipa_msg, fipa_dialogue)\n        elif fipa_msg.performative == FipaMessage.Performative.DECLINE:\n            self._handle_decline(fipa_msg, fipa_dialogue, fipa_dialogues)\n        elif fipa_msg.performative == FipaMessage.Performative.ACCEPT:\n            self._handle_accept(fipa_msg, fipa_dialogue)\n        elif fipa_msg.performative == FipaMessage.Performative.INFORM:\n            self._handle_inform(fipa_msg, fipa_dialogue)\n        else:\n            self._handle_invalid(fipa_msg, fipa_dialogue)\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n```\n\nThe code above contains the logic for handling `FipaMessages` received by the `my_generic_seller` AEA. We use `FipaDialogues` (more on this <a href=\"../generic-skills-step-by-step/#step-5-create-the-dialogues\">below</a>) to keep track of the progress of the negotiation dialogue between the `my_generic_seller` AEA and the `my_generic_buyer` AEA.\n\nIn the above `handle` method, we first check if a received message belongs to an existing dialogue or if we have to create a new dialogue (the `recover dialogue` part). Once this is done, we break down the AEA's response to each type of negotiation message, as indicated by the message's performative (the `handle message` part). Therefore, we implement the AEA's response to each negotiation message type in a different handler function.\n\nBelow the unused `teardown` function, we continue by adding the following function:\n\n``` python\n    def _handle_unidentified_dialogue(self, fipa_msg: FipaMessage) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param fipa_msg: the message\n        \"\"\"\n        self.context.logger.info(\n            \"received invalid fipa message={}, unidentified dialogue.\".format(fipa_msg)\n        )\n        default_dialogues = cast(DefaultDialogues, self.context.default_dialogues)\n        default_msg, _ = default_dialogues.create(\n            counterparty=fipa_msg.sender,\n            performative=DefaultMessage.Performative.ERROR,\n            error_code=DefaultMessage.ErrorCode.INVALID_DIALOGUE,\n            error_msg=\"Invalid dialogue.\",\n            error_data={\"fipa_message\": fipa_msg.encode()},\n        )\n        self.context.outbox.put_message(message=default_msg)\n```\n\nThe above code handles an unidentified dialogue by responding to the sender with a `DefaultMessage` containing the appropriate error information.\n\nThe next code block handles `CFP` (call-for-proposal) negotiation messages. Paste the following code below the `_handle_unidentified_dialogue` function:\n\n``` python\n    def _handle_cfp(self, fipa_msg: FipaMessage, fipa_dialogue: FipaDialogue) -> None:\n        \"\"\"\n        Handle the CFP.\n\n        If the CFP matches the supplied services then send a PROPOSE, otherwise send a DECLINE.\n\n        :param fipa_msg: the message\n        :param fipa_dialogue: the dialogue object\n        \"\"\"\n        self.context.logger.info(\n            \"received CFP from sender={}\".format(fipa_msg.sender[-5:])\n        )\n        strategy = cast(GenericStrategy, self.context.strategy)\n        if strategy.is_matching_supply(fipa_msg.query):\n            proposal, terms, data_for_sale = strategy.generate_proposal_terms_and_data(\n                fipa_msg.query, fipa_msg.sender\n            )\n            fipa_dialogue.data_for_sale = data_for_sale\n            fipa_dialogue.terms = terms\n            self.context.logger.info(\n                \"sending a PROPOSE with proposal={} to sender={}\".format(\n                    proposal.values, fipa_msg.sender[-5:]\n                )\n            )\n            proposal_msg = fipa_dialogue.reply(\n                performative=FipaMessage.Performative.PROPOSE,\n                target_message=fipa_msg,\n                proposal=proposal,\n            )\n            self.context.outbox.put_message(message=proposal_msg)\n        else:\n            self.context.logger.info(\n                \"declined the CFP from sender={}\".format(fipa_msg.sender[-5:])\n            )\n            decline_msg = fipa_dialogue.reply(\n                performative=FipaMessage.Performative.DECLINE,\n                target_message=fipa_msg,\n            )\n            self.context.outbox.put_message(message=decline_msg)\n```\n\nThe above code sends a `PROPOSE` message back to the buyer as a response to its `CFP` if the requested services match our seller agent's supplied services, otherwise it will respond with a `DECLINE` message.\n\nThe next code-block  handles the decline message we receive from the buyer. Add the following code below the `_handle_cfp`function:\n\n``` python\n    def _handle_decline(\n        self,\n        fipa_msg: FipaMessage,\n        fipa_dialogue: FipaDialogue,\n        fipa_dialogues: FipaDialogues,\n    ) -> None:\n        \"\"\"\n        Handle the DECLINE.\n\n        Close the dialogue.\n\n        :param fipa_msg: the message\n        :param fipa_dialogue: the dialogue object\n        :param fipa_dialogues: the dialogues object\n        \"\"\"\n        self.context.logger.info(\n            \"received DECLINE from sender={}\".format(fipa_msg.sender[-5:])\n        )\n        fipa_dialogues.dialogue_stats.add_dialogue_endstate(\n            FipaDialogue.EndState.DECLINED_PROPOSE, fipa_dialogue.is_self_initiated\n        )\n```\n\nIf we receive a decline message from the buyer we close the dialogue and terminate this conversation with `my_generic_buyer`.\n\nAlternatively, we might receive an `ACCEPT` message. In order to handle this option add the following code below the `_handle_decline` function:\n\n``` python\n    def _handle_accept(\n        self, fipa_msg: FipaMessage, fipa_dialogue: FipaDialogue\n    ) -> None:\n        \"\"\"\n        Handle the ACCEPT.\n\n        Respond with a MATCH_ACCEPT_W_INFORM which contains the address to send the funds to.\n\n        :param fipa_msg: the message\n        :param fipa_dialogue: the dialogue object\n        \"\"\"\n        self.context.logger.info(\n            \"received ACCEPT from sender={}\".format(fipa_msg.sender[-5:])\n        )\n        info = {\"address\": fipa_dialogue.terms.sender_address}\n        match_accept_msg = fipa_dialogue.reply(\n            performative=FipaMessage.Performative.MATCH_ACCEPT_W_INFORM,\n            target_message=fipa_msg,\n            info=info,\n        )\n        self.context.logger.info(\n            \"sending MATCH_ACCEPT_W_INFORM to sender={} with info={}\".format(\n                fipa_msg.sender[-5:],\n                info,\n            )\n        )\n        self.context.outbox.put_message(message=match_accept_msg)\n\n```\n\nWhen `my_generic_buyer` accepts the `Proposal` we send it and sends an `ACCEPT` message, we have to respond with another message (`MATCH_ACCEPT_W_INFORM`) to match the acceptance of the terms of trade and to inform the buyer of the address we would like it to send the funds to.\n\nLastly, we must handle an `INFORM` message, which the buyer uses to inform us that it has indeed sent the funds to the provided address. Add the following code at the end of the file:\n\n``` python\n    def _handle_inform(\n        self, fipa_msg: FipaMessage, fipa_dialogue: FipaDialogue\n    ) -> None:\n        \"\"\"\n        Handle the INFORM.\n\n        If the INFORM message contains the transaction_digest then verify that it is settled, otherwise do nothing.\n        If the transaction is settled, send the data, otherwise do nothing.\n\n        :param fipa_msg: the message\n        :param fipa_dialogue: the dialogue object\n        \"\"\"\n        self.context.logger.info(\n            \"received INFORM from sender={}\".format(fipa_msg.sender[-5:])\n        )\n\n        strategy = cast(GenericStrategy, self.context.strategy)\n        if strategy.is_ledger_tx and \"transaction_digest\" in fipa_msg.info.keys():\n            self.context.logger.info(\n                \"checking whether transaction={} has been received ...\".format(\n                    fipa_msg.info[\"transaction_digest\"]\n                )\n            )\n            ledger_api_dialogues = cast(\n                LedgerApiDialogues, self.context.ledger_api_dialogues\n            )\n            ledger_api_msg, ledger_api_dialogue = ledger_api_dialogues.create(\n                counterparty=LEDGER_API_ADDRESS,\n                performative=LedgerApiMessage.Performative.GET_TRANSACTION_RECEIPT,\n                transaction_digest=TransactionDigest(\n                    fipa_dialogue.terms.ledger_id, fipa_msg.info[\"transaction_digest\"]\n                ),\n            )\n            ledger_api_dialogue = cast(LedgerApiDialogue, ledger_api_dialogue)\n            ledger_api_dialogue.associated_fipa_dialogue = fipa_dialogue\n            self.context.outbox.put_message(message=ledger_api_msg)\n        elif strategy.is_ledger_tx:\n            self.context.logger.warning(\n                \"did not receive transaction digest from sender={}.\".format(\n                    fipa_msg.sender[-5:]\n                )\n            )\n        elif not strategy.is_ledger_tx and \"Done\" in fipa_msg.info.keys():\n            inform_msg = fipa_dialogue.reply(\n                performative=FipaMessage.Performative.INFORM,\n                target_message=fipa_msg,\n                info=fipa_dialogue.data_for_sale,\n            )\n            self.context.outbox.put_message(message=inform_msg)\n            fipa_dialogues = cast(FipaDialogues, self.context.fipa_dialogues)\n            fipa_dialogues.dialogue_stats.add_dialogue_endstate(\n                FipaDialogue.EndState.SUCCESSFUL, fipa_dialogue.is_self_initiated\n            )\n            self.context.logger.info(\n                \"transaction confirmed, sending data={} to buyer={}.\".format(\n                    fipa_dialogue.data_for_sale,\n                    fipa_msg.sender[-5:],\n                )\n            )\n        else:\n            self.context.logger.warning(\n                \"did not receive transaction confirmation from sender={}.\".format(\n                    fipa_msg.sender[-5:]\n                )\n            )\n```\n\nIn the above code, we check the `INFORM` message. If it contains a transaction digest, then we verify that the transaction matches the proposal the buyer accepted. If the transaction is valid and we received the funds, then we send the data to the buyer. Otherwise, we do not send the data.\n\nThe remaining handlers are as follows:\n\n``` python\n    def _handle_invalid(\n        self, fipa_msg: FipaMessage, fipa_dialogue: FipaDialogue\n    ) -> None:\n        \"\"\"\n        Handle a fipa message of invalid performative.\n\n        :param fipa_msg: the message\n        :param fipa_dialogue: the dialogue object\n        \"\"\"\n        self.context.logger.warning(\n            \"cannot handle fipa message of performative={} in dialogue={}.\".format(\n                fipa_msg.performative, fipa_dialogue\n            )\n        )\n\n\nclass GenericLedgerApiHandler(Handler):\n    \"\"\"Implement the ledger handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = LedgerApiMessage.protocol_id  # type: Optional[PublicId]\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup for the handler.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to a message.\n\n        :param message: the message\n        \"\"\"\n        ledger_api_msg = cast(LedgerApiMessage, message)\n\n        # recover dialogue\n        ledger_api_dialogues = cast(\n            LedgerApiDialogues, self.context.ledger_api_dialogues\n        )\n        ledger_api_dialogue = cast(\n            Optional[LedgerApiDialogue], ledger_api_dialogues.update(ledger_api_msg)\n        )\n        if ledger_api_dialogue is None:\n            self._handle_unidentified_dialogue(ledger_api_msg)\n            return\n\n        # handle message\n        if ledger_api_msg.performative is LedgerApiMessage.Performative.BALANCE:\n            self._handle_balance(ledger_api_msg)\n        elif (\n            ledger_api_msg.performative\n            is LedgerApiMessage.Performative.TRANSACTION_RECEIPT\n        ):\n            self._handle_transaction_receipt(ledger_api_msg, ledger_api_dialogue)\n        elif ledger_api_msg.performative == LedgerApiMessage.Performative.ERROR:\n            self._handle_error(ledger_api_msg, ledger_api_dialogue)\n        else:\n            self._handle_invalid(ledger_api_msg, ledger_api_dialogue)\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n\n    def _handle_unidentified_dialogue(self, ledger_api_msg: LedgerApiMessage) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param ledger_api_msg: the message\n        \"\"\"\n        self.context.logger.info(\n            \"received invalid ledger_api message={}, unidentified dialogue.\".format(\n                ledger_api_msg\n            )\n        )\n\n    def _handle_balance(self, ledger_api_msg: LedgerApiMessage) -> None:\n        \"\"\"\n        Handle a message of balance performative.\n\n        :param ledger_api_msg: the ledger api message\n        \"\"\"\n        self.context.logger.info(\n            \"starting balance on {} ledger={}.\".format(\n                ledger_api_msg.ledger_id,\n                ledger_api_msg.balance,\n            )\n        )\n\n    def _handle_transaction_receipt(\n        self, ledger_api_msg: LedgerApiMessage, ledger_api_dialogue: LedgerApiDialogue\n    ) -> None:\n        \"\"\"\n        Handle a message of balance performative.\n\n        :param ledger_api_msg: the ledger api message\n        :param ledger_api_dialogue: the ledger api dialogue\n        \"\"\"\n        fipa_dialogue = ledger_api_dialogue.associated_fipa_dialogue\n        is_settled = LedgerApis.is_transaction_settled(\n            fipa_dialogue.terms.ledger_id, ledger_api_msg.transaction_receipt.receipt\n        )\n        is_valid = LedgerApis.is_transaction_valid(\n            fipa_dialogue.terms.ledger_id,\n            ledger_api_msg.transaction_receipt.transaction,\n            fipa_dialogue.terms.sender_address,\n            fipa_dialogue.terms.counterparty_address,\n            fipa_dialogue.terms.nonce,\n            fipa_dialogue.terms.counterparty_payable_amount,\n        )\n        if is_settled and is_valid:\n            last_message = cast(\n                Optional[FipaMessage], fipa_dialogue.last_incoming_message\n            )\n            if last_message is None:\n                raise ValueError(\"Cannot retrieve last fipa message.\")\n            inform_msg = fipa_dialogue.reply(\n                performative=FipaMessage.Performative.INFORM,\n                target_message=last_message,\n                info=fipa_dialogue.data_for_sale,\n            )\n            self.context.outbox.put_message(message=inform_msg)\n            fipa_dialogues = cast(FipaDialogues, self.context.fipa_dialogues)\n            fipa_dialogues.dialogue_stats.add_dialogue_endstate(\n                FipaDialogue.EndState.SUCCESSFUL, fipa_dialogue.is_self_initiated\n            )\n            self.context.logger.info(\n                \"transaction confirmed, sending data={} to buyer={}.\".format(\n                    fipa_dialogue.data_for_sale,\n                    last_message.sender[-5:],\n                )\n            )\n        else:\n            self.context.logger.info(\n                \"transaction_receipt={} not settled or not valid, aborting\".format(\n                    ledger_api_msg.transaction_receipt\n                )\n            )\n\n    def _handle_error(\n        self, ledger_api_msg: LedgerApiMessage, ledger_api_dialogue: LedgerApiDialogue\n    ) -> None:\n        \"\"\"\n        Handle a message of error performative.\n\n        :param ledger_api_msg: the ledger api message\n        :param ledger_api_dialogue: the ledger api dialogue\n        \"\"\"\n        self.context.logger.info(\n            \"received ledger_api error message={} in dialogue={}.\".format(\n                ledger_api_msg, ledger_api_dialogue\n            )\n        )\n\n    def _handle_invalid(\n        self, ledger_api_msg: LedgerApiMessage, ledger_api_dialogue: LedgerApiDialogue\n    ) -> None:\n        \"\"\"\n        Handle a message of invalid performative.\n\n        :param ledger_api_msg: the ledger api message\n        :param ledger_api_dialogue: the ledger api dialogue\n        \"\"\"\n        self.context.logger.warning(\n            \"cannot handle ledger_api message of performative={} in dialogue={}.\".format(\n                ledger_api_msg.performative,\n                ledger_api_dialogue,\n            )\n        )\n\n\nclass GenericOefSearchHandler(Handler):\n    \"\"\"This class implements an OEF search handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = OefSearchMessage.protocol_id  # type: Optional[PublicId]\n\n    def setup(self) -> None:\n        \"\"\"Call to setup the handler.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to a message.\n\n        :param message: the message\n        \"\"\"\n        oef_search_msg = cast(OefSearchMessage, message)\n\n        # recover dialogue\n        oef_search_dialogues = cast(\n            OefSearchDialogues, self.context.oef_search_dialogues\n        )\n        oef_search_dialogue = cast(\n            Optional[OefSearchDialogue], oef_search_dialogues.update(oef_search_msg)\n        )\n        if oef_search_dialogue is None:\n            self._handle_unidentified_dialogue(oef_search_msg)\n            return\n\n        # handle message\n        if oef_search_msg.performative == OefSearchMessage.Performative.SUCCESS:\n            self._handle_success(oef_search_msg, oef_search_dialogue)\n        elif oef_search_msg.performative == OefSearchMessage.Performative.OEF_ERROR:\n            self._handle_error(oef_search_msg, oef_search_dialogue)\n        else:\n            self._handle_invalid(oef_search_msg, oef_search_dialogue)\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n\n    def _handle_unidentified_dialogue(self, oef_search_msg: OefSearchMessage) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param oef_search_msg: the message\n        \"\"\"\n        self.context.logger.info(\n            \"received invalid oef_search message={}, unidentified dialogue.\".format(\n                oef_search_msg\n            )\n        )\n\n    def _handle_success(\n        self,\n        oef_search_success_msg: OefSearchMessage,\n        oef_search_dialogue: OefSearchDialogue,\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param oef_search_success_msg: the oef search message\n        :param oef_search_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.info(\n            \"received oef_search success message={} in dialogue={}.\".format(\n                oef_search_success_msg, oef_search_dialogue\n            )\n        )\n        target_message = cast(\n            OefSearchMessage,\n            oef_search_dialogue.get_message_by_id(oef_search_success_msg.target),\n        )\n        if (\n            target_message.performative\n            == OefSearchMessage.Performative.REGISTER_SERVICE\n        ):\n            description = target_message.service_description\n            data_model_name = description.data_model.name\n            registration_behaviour = cast(\n                GenericServiceRegistrationBehaviour,\n                self.context.behaviours.service_registration,\n            )\n            if \"location_agent\" in data_model_name:\n                registration_behaviour.register_service()\n            elif \"set_service_key\" in data_model_name:\n                registration_behaviour.register_genus()\n            elif (\n                \"personality_agent\" in data_model_name\n                and description.values[\"piece\"] == \"genus\"\n            ):\n                registration_behaviour.register_classification()\n            elif (\n                \"personality_agent\" in data_model_name\n                and description.values[\"piece\"] == \"classification\"\n            ):\n                self.context.logger.info(\n                    \"the agent, with its genus and classification, and its service are successfully registered on the SOEF.\"\n                )\n            else:\n                self.context.logger.warning(\n                    f\"received soef SUCCESS message as a reply to the following unexpected message: {target_message}\"\n                )\n\n    def _handle_error(\n        self,\n        oef_search_error_msg: OefSearchMessage,\n        oef_search_dialogue: OefSearchDialogue,\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param oef_search_error_msg: the oef search message\n        :param oef_search_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.info(\n            \"received oef_search error message={} in dialogue={}.\".format(\n                oef_search_error_msg, oef_search_dialogue\n            )\n        )\n        target_message = cast(\n            OefSearchMessage,\n            oef_search_dialogue.get_message_by_id(oef_search_error_msg.target),\n        )\n        if (\n            target_message.performative\n            == OefSearchMessage.Performative.REGISTER_SERVICE\n        ):\n            registration_behaviour = cast(\n                GenericServiceRegistrationBehaviour,\n                self.context.behaviours.service_registration,\n            )\n            registration_behaviour.failed_registration_msg = target_message\n\n    def _handle_invalid(\n        self, oef_search_msg: OefSearchMessage, oef_search_dialogue: OefSearchDialogue\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param oef_search_msg: the oef search message\n        :param oef_search_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.warning(\n            \"cannot handle oef_search message of performative={} in dialogue={}.\".format(\n                oef_search_msg.performative,\n                oef_search_dialogue,\n            )\n        )\n```\n\nThe `GenericLedgerApiHandler` deals with `LedgerApiMessages` from the ledger connection and the `GenericOefSearchHandler` handles `OefSearchMessages` from the SOEF connection.\n\n### Step 4: Create the Strategy\n\nNext, we are going to create the strategy that we want our `my_generic_seller` AEA to follow. Rename the `my_model.py` file (`my_generic_seller/skills/generic_seller/my_model.py`) to `strategy.py` and replace the stub code with the following:\n\n``` python\nimport uuid\nfrom typing import Any, Dict, Optional, Tuple\n\nfrom aea.common import Address\nfrom aea.crypto.ledger_apis import LedgerApis\nfrom aea.exceptions import enforce\nfrom aea.helpers.search.generic import (\n    AGENT_LOCATION_MODEL,\n    AGENT_PERSONALITY_MODEL,\n    AGENT_REMOVE_SERVICE_MODEL,\n    AGENT_SET_SERVICE_MODEL,\n    SIMPLE_SERVICE_MODEL,\n)\nfrom aea.helpers.search.models import Description, Location, Query\nfrom aea.helpers.transaction.base import Terms\nfrom aea.skills.base import Model\n\n\nDEFAULT_IS_LEDGER_TX = True\n\nDEFAULT_UNIT_PRICE = 4\nDEFAULT_SERVICE_ID = \"generic_service\"\n\nDEFAULT_LOCATION = {\"longitude\": 0.1270, \"latitude\": 51.5194}\nDEFAULT_SERVICE_DATA = {\"key\": \"seller_service\", \"value\": \"generic_service\"}\nDEFAULT_PERSONALITY_DATA = {\"piece\": \"genus\", \"value\": \"data\"}\nDEFAULT_CLASSIFICATION = {\"piece\": \"classification\", \"value\": \"seller\"}\n\nDEFAULT_HAS_DATA_SOURCE = False\nDEFAULT_DATA_FOR_SALE = {\n    \"some_generic_data_key\": \"some_generic_data_value\"\n}  # type: Optional[Dict[str, Any]]\n\n\nclass GenericStrategy(Model):\n    \"\"\"This class defines a strategy for the agent.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize the strategy of the agent.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        ledger_id = kwargs.pop(\"ledger_id\", None)\n        currency_id = kwargs.pop(\"currency_id\", None)\n        self._is_ledger_tx = kwargs.pop(\"is_ledger_tx\", DEFAULT_IS_LEDGER_TX)\n\n        self._unit_price = kwargs.pop(\"unit_price\", DEFAULT_UNIT_PRICE)\n        self._service_id = kwargs.pop(\"service_id\", DEFAULT_SERVICE_ID)\n\n        location = kwargs.pop(\"location\", DEFAULT_LOCATION)\n        self._agent_location = {\n            \"location\": Location(\n                latitude=location[\"latitude\"], longitude=location[\"longitude\"]\n            )\n        }\n        self._set_personality_data = kwargs.pop(\n            \"personality_data\", DEFAULT_PERSONALITY_DATA\n        )\n        enforce(\n            len(self._set_personality_data) == 2\n            and \"piece\" in self._set_personality_data\n            and \"value\" in self._set_personality_data,\n            \"personality_data must contain keys `key` and `value`\",\n        )\n        self._set_classification = kwargs.pop(\"classification\", DEFAULT_CLASSIFICATION)\n        enforce(\n            len(self._set_classification) == 2\n            and \"piece\" in self._set_classification\n            and \"value\" in self._set_classification,\n            \"classification must contain keys `key` and `value`\",\n        )\n        self._set_service_data = kwargs.pop(\"service_data\", DEFAULT_SERVICE_DATA)\n        enforce(\n            len(self._set_service_data) == 2\n            and \"key\" in self._set_service_data\n            and \"value\" in self._set_service_data,\n            \"service_data must contain keys `key` and `value`\",\n        )\n        self._remove_service_data = {\"key\": self._set_service_data[\"key\"]}\n        self._simple_service_data = {\n            self._set_service_data[\"key\"]: self._set_service_data[\"value\"]\n        }\n\n        self._has_data_source = kwargs.pop(\"has_data_source\", DEFAULT_HAS_DATA_SOURCE)\n        data_for_sale_ordered = kwargs.pop(\"data_for_sale\", DEFAULT_DATA_FOR_SALE)\n        data_for_sale = {\n            str(key): str(value) for key, value in data_for_sale_ordered.items()\n        }\n\n        super().__init__(**kwargs)\n        self._ledger_id = (\n            ledger_id if ledger_id is not None else self.context.default_ledger_id\n        )\n        if currency_id is None:\n            currency_id = self.context.currency_denominations.get(self._ledger_id, None)\n            enforce(\n                currency_id is not None,\n                f\"Currency denomination for ledger_id={self._ledger_id} not specified.\",\n            )\n        self._currency_id = currency_id\n        enforce(\n            self.context.agent_addresses.get(self._ledger_id, None) is not None,\n            \"Wallet does not contain cryptos for provided ledger id.\",\n        )\n        self._data_for_sale = data_for_sale\n```\n\nIn the above code snippet, we initialise the strategy class by trying to read the variables specific to the strategy from a YAML configuration file. If any variable is not provided, some default values will be used.\n\nThe following properties and methods deal with different aspects of the strategy. They should be relatively self-descriptive. Add them under the initialization of the strategy class:\n\n``` python\n    @property\n    def data_for_sale(self) -> Dict[str, str]:\n        \"\"\"Get the data for sale.\"\"\"\n        if self._has_data_source:\n            return self.collect_from_data_source()  # pragma: nocover\n        return self._data_for_sale\n\n    @property\n    def ledger_id(self) -> str:\n        \"\"\"Get the ledger id.\"\"\"\n        return self._ledger_id\n\n    @property\n    def is_ledger_tx(self) -> bool:\n        \"\"\"Check whether or not tx are settled on a ledger.\"\"\"\n        return self._is_ledger_tx\n\n    def get_location_description(self) -> Description:\n        \"\"\"\n        Get the location description.\n\n        :return: a description of the agent's location\n        \"\"\"\n        description = Description(\n            self._agent_location,\n            data_model=AGENT_LOCATION_MODEL,\n        )\n        return description\n\n    def get_register_service_description(self) -> Description:\n        \"\"\"\n        Get the register service description.\n\n        :return: a description of the offered services\n        \"\"\"\n        description = Description(\n            self._set_service_data,\n            data_model=AGENT_SET_SERVICE_MODEL,\n        )\n        return description\n\n    def get_register_personality_description(self) -> Description:\n        \"\"\"\n        Get the register personality description.\n\n        :return: a description of the personality\n        \"\"\"\n        description = Description(\n            self._set_personality_data,\n            data_model=AGENT_PERSONALITY_MODEL,\n        )\n        return description\n\n    def get_register_classification_description(self) -> Description:\n        \"\"\"\n        Get the register classification description.\n\n        :return: a description of the classification\n        \"\"\"\n        description = Description(\n            self._set_classification,\n            data_model=AGENT_PERSONALITY_MODEL,\n        )\n        return description\n\n    def get_service_description(self) -> Description:\n        \"\"\"\n        Get the simple service description.\n\n        :return: a description of the offered services\n        \"\"\"\n        description = Description(\n            self._simple_service_data,\n            data_model=SIMPLE_SERVICE_MODEL,\n        )\n        return description\n\n    def get_unregister_service_description(self) -> Description:\n        \"\"\"\n        Get the unregister service description.\n\n        :return: a description of the to be removed service\n        \"\"\"\n        description = Description(\n            self._remove_service_data,\n            data_model=AGENT_REMOVE_SERVICE_MODEL,\n        )\n        return description\n\n    def is_matching_supply(self, query: Query) -> bool:\n        \"\"\"\n        Check if the query matches the supply.\n\n        :param query: the query\n        :return: bool indicating whether matches or not\n        \"\"\"\n        return query.check(self.get_service_description())\n\n    def generate_proposal_terms_and_data(  # pylint: disable=unused-argument\n        self, query: Query, counterparty_address: Address\n    ) -> Tuple[Description, Terms, Dict[str, str]]:\n        \"\"\"\n        Generate a proposal matching the query.\n\n        :param query: the query\n        :param counterparty_address: the counterparty of the proposal.\n        :return: a tuple of proposal, terms and the weather data\n        \"\"\"\n        data_for_sale = self.data_for_sale\n        sale_quantity = len(data_for_sale)\n        seller_address = self.context.agent_addresses[self.ledger_id]\n        total_price = sale_quantity * self._unit_price\n        if self.is_ledger_tx:\n            tx_nonce = LedgerApis.generate_tx_nonce(\n                identifier=self.ledger_id,\n                seller=seller_address,\n                client=counterparty_address,\n            )\n        else:\n            tx_nonce = uuid.uuid4().hex  # pragma: nocover\n        proposal = Description(\n            {\n                \"ledger_id\": self.ledger_id,\n                \"price\": total_price,\n                \"currency_id\": self._currency_id,\n                \"service_id\": self._service_id,\n                \"quantity\": sale_quantity,\n                \"tx_nonce\": tx_nonce,\n            }\n        )\n        terms = Terms(\n            ledger_id=self.ledger_id,\n            sender_address=seller_address,\n            counterparty_address=counterparty_address,\n            amount_by_currency_id={self._currency_id: total_price},\n            quantities_by_good_id={self._service_id: -sale_quantity},\n            is_sender_payable_tx_fee=False,\n            nonce=tx_nonce,\n            fee_by_currency_id={self._currency_id: 0},\n        )\n        return proposal, terms, data_for_sale\n\n    def collect_from_data_source(self) -> Dict[str, str]:\n        \"\"\"Implement the logic to communicate with the sensor.\"\"\"\n        raise NotImplementedError\n```\n\nThe helper private function `collect_from_data_source` is where we read data from a sensor or if there are no sensor we use some default data provided (see the `data_for_sale` property).\n\n### Step 5: Create the Dialogues\n\nTo keep track of the structure and progress of interactions, including negotiations with a buyer AEA and interactions with search nodes and ledgers, we use dialogues. Create a new file in the skill folder (`my_generic_seller/skills/generic_seller/`) and name it `dialogues.py`. Inside this file add the following code:\n\n``` python\nfrom typing import Any, Dict, Optional, Type\n\nfrom aea.common import Address\nfrom aea.exceptions import AEAEnforceError, enforce\nfrom aea.helpers.transaction.base import Terms\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\nfrom aea.protocols.dialogue.base import DialogueLabel as BaseDialogueLabel\nfrom aea.skills.base import Model\n\nfrom packages.fetchai.protocols.default.dialogues import (\n    DefaultDialogue as BaseDefaultDialogue,\n)\nfrom packages.fetchai.protocols.default.dialogues import (\n    DefaultDialogues as BaseDefaultDialogues,\n)\nfrom packages.fetchai.protocols.fipa.dialogues import FipaDialogue as BaseFipaDialogue\nfrom packages.fetchai.protocols.fipa.dialogues import FipaDialogues as BaseFipaDialogues\nfrom packages.fetchai.protocols.fipa.message import FipaMessage\nfrom packages.fetchai.protocols.ledger_api.dialogues import (\n    LedgerApiDialogue as BaseLedgerApiDialogue,\n)\nfrom packages.fetchai.protocols.ledger_api.dialogues import (\n    LedgerApiDialogues as BaseLedgerApiDialogues,\n)\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\nfrom packages.fetchai.protocols.oef_search.dialogues import (\n    OefSearchDialogue as BaseOefSearchDialogue,\n)\nfrom packages.fetchai.protocols.oef_search.dialogues import (\n    OefSearchDialogues as BaseOefSearchDialogues,\n)\n\n\nDefaultDialogue = BaseDefaultDialogue\n\n\nclass DefaultDialogues(Model, BaseDefaultDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return DefaultDialogue.Role.AGENT\n\n        BaseDefaultDialogues.__init__(\n            self,\n            self_address=self.context.agent_address,\n            role_from_first_message=role_from_first_message,\n        )\n\n\nclass FipaDialogue(BaseFipaDialogue):\n    \"\"\"The dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    __slots__ = (\"data_for_sale\", \"_terms\")\n\n    def __init__(\n        self,\n        dialogue_label: BaseDialogueLabel,\n        self_address: Address,\n        role: BaseDialogue.Role,\n        message_class: Type[FipaMessage] = FipaMessage,\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n        :param message_class: the message class\n        \"\"\"\n        BaseFipaDialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            self_address=self_address,\n            role=role,\n            message_class=message_class,\n        )\n        self.data_for_sale = None  # type: Optional[Dict[str, str]]\n        self._terms = None  # type: Optional[Terms]\n\n    @property\n    def terms(self) -> Terms:\n        \"\"\"Get terms.\"\"\"\n        if self._terms is None:\n            raise AEAEnforceError(\"Terms not set!\")\n        return self._terms\n\n    @terms.setter\n    def terms(self, terms: Terms) -> None:\n        \"\"\"Set terms.\"\"\"\n        enforce(self._terms is None, \"Terms already set!\")\n        self._terms = terms\n\n\nclass FipaDialogues(Model, BaseFipaDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return FipaDialogue.Role.SELLER\n\n        BaseFipaDialogues.__init__(\n            self,\n            self_address=self.context.agent_address,\n            role_from_first_message=role_from_first_message,\n            dialogue_class=FipaDialogue,\n        )\n\n\nclass LedgerApiDialogue(BaseLedgerApiDialogue):\n    \"\"\"The dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    __slots__ = (\"_associated_fipa_dialogue\",)\n\n    def __init__(\n        self,\n        dialogue_label: BaseDialogueLabel,\n        self_address: Address,\n        role: BaseDialogue.Role,\n        message_class: Type[LedgerApiMessage] = LedgerApiMessage,\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n        :param message_class: the message class\n        \"\"\"\n        BaseLedgerApiDialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            self_address=self_address,\n            role=role,\n            message_class=message_class,\n        )\n        self._associated_fipa_dialogue = None  # type: Optional[FipaDialogue]\n\n    @property\n    def associated_fipa_dialogue(self) -> FipaDialogue:\n        \"\"\"Get associated_fipa_dialogue.\"\"\"\n        if self._associated_fipa_dialogue is None:\n            raise AEAEnforceError(\"FipaDialogue not set!\")\n        return self._associated_fipa_dialogue\n\n    @associated_fipa_dialogue.setter\n    def associated_fipa_dialogue(self, fipa_dialogue: FipaDialogue) -> None:\n        \"\"\"Set associated_fipa_dialogue\"\"\"\n        enforce(self._associated_fipa_dialogue is None, \"FipaDialogue already set!\")\n        self._associated_fipa_dialogue = fipa_dialogue\n\n\nclass LedgerApiDialogues(Model, BaseLedgerApiDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return BaseLedgerApiDialogue.Role.AGENT\n\n        BaseLedgerApiDialogues.__init__(\n            self,\n            self_address=str(self.skill_id),\n            role_from_first_message=role_from_first_message,\n            dialogue_class=LedgerApiDialogue,\n        )\n\n\nOefSearchDialogue = BaseOefSearchDialogue\n\n\nclass OefSearchDialogues(Model, BaseOefSearchDialogues):\n    \"\"\"This class keeps track of all oef_search dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return BaseOefSearchDialogue.Role.AGENT\n\n        BaseOefSearchDialogues.__init__(\n            self,\n            self_address=str(self.skill_id),\n            role_from_first_message=role_from_first_message,\n        )\n```\n\nThe `FipaDialogues` class contains negotiation dialogues with each `my_generic_buyer` AEA (and other AEAs) and exposes a number of helpful methods to manage them. This helps us match messages to the dialogues they belong to, access previous messages and enable us to identify possible communications problems between the `my_generic_seller` AEA and the `my_generic_buyer` AEA. It also keeps track of the data that we offer for sale during the proposal phase.\n\nThe `FipaDialogues` class extends `BaseFipaDialogues`, which itself derives from the base <a href=\"../api/protocols/dialogue/base#dialogues-objects\">`Dialogues`</a> class. Similarly, the `FipaDialogue` class extends `BaseFipaDialogue` which itself derives from the base <a href=\"../api/protocols/dialogue/base#dialogue-objects\">`Dialogue`</a> class. To learn more about dialogues have a look <a href=\"../protocol\">here</a>.\n\n### Step 6: Update the YAML Files\n\nSince we made so many changes to our AEA we have to update the `skill.yaml` (at `my_generic_seller/skills/generic_seller/skill.yaml`). Make sure you update your `skill.yaml` with the following configuration:\n\n``` yaml\nname: generic_seller\nauthor: fetchai\nversion: 0.1.0\ntype: skill\ndescription: The weather station skill implements the functionality to sell weather\n  data.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: QmPb5kHYZyhUN87EKmuahyGqDGgqVdGPyfC1KpGC3xfmcP\n  __init__.py: QmTSEedzQySy2nzRCY3F66CBSX52f8s3pWHZTejX4hKC9h\n  behaviours.py: QmS9sPCv2yBnhWsmHeaCptpApMtYZipbR39TXixeGK64Ks\n  dialogues.py: QmdTW8q1xQ7ajFVsWmuV62ypoT5J2b6Hkyz52LFaWuMEtd\n  handlers.py: QmQnQhSaHPUYaJut8bMe2LHEqiZqokMSVfCthVaqrvPbdi\n  strategy.py: QmYTUsfv64eRQDevCfMUDQPx2GCtiMLFdacN4sS1E4Fdfx\nfingerprint_ignore_patterns: []\nconnections:\n- fetchai/ledger:0.21.5\ncontracts: []\nprotocols:\n- fetchai/default:1.1.7\n- fetchai/fipa:1.1.7\n- fetchai/ledger_api:1.1.7\n- fetchai/oef_search:1.1.7\nskills: []\nbehaviours:\n  service_registration:\n    args:\n      services_interval: 20\n    class_name: GenericServiceRegistrationBehaviour\nhandlers:\n  fipa:\n    args: {}\n    class_name: GenericFipaHandler\n  ledger_api:\n    args: {}\n    class_name: GenericLedgerApiHandler\n  oef_search:\n    args: {}\n    class_name: GenericOefSearchHandler\nmodels:\n  default_dialogues:\n    args: {}\n    class_name: DefaultDialogues\n  fipa_dialogues:\n    args: {}\n    class_name: FipaDialogues\n  ledger_api_dialogues:\n    args: {}\n    class_name: LedgerApiDialogues\n  oef_search_dialogues:\n    args: {}\n    class_name: OefSearchDialogues\n  strategy:\n    args:\n      data_for_sale:\n        generic: data\n      has_data_source: false\n      is_ledger_tx: true\n      location:\n        latitude: 51.5194\n        longitude: 0.127\n      service_data:\n        key: seller_service\n        value: generic_service\n      service_id: generic_service\n      unit_price: 10\n    class_name: GenericStrategy\nis_abstract: false\ndependencies: {}\n```\n\nWe must pay attention to the models and in particular the strategy’s variables. Here we can change the price we would like to sell each data reading for, or the currency we would like to transact with. Lastly, the dependencies are the third party packages we need to install in order to get readings from the sensor.\n\nFinally, we fingerprint our new skill:\n\n``` bash\naea fingerprint skill fetchai/generic_seller:0.1.0\n```\n\nThis will hash each file and save the hash in the fingerprint. This way, in the future we can easily track if any of the files have changed.\n\n## Generic Buyer AEA\n\n### Step 1: Create the AEA\n\nIn a new terminal, create a new AEA by typing the following command in the terminal:\n\n``` bash\naea create my_generic_buyer\ncd my_generic_buyer\naea install\n```\n\nOur newly created AEA is inside the current working directory. Let’s create a new skill for purchasing data. Type the following command:\n\n``` bash\naea scaffold skill generic_buyer\n```\n\nThis command creates the correct structure for a new skill inside our AEA project. You can locate the newly created skill under the skills folder (`my_generic_buyer/skills/generic_buyer/`) and it must contain the following files:\n\n- `__init__.py`\n- `behaviours.py`\n- `handlers.py`\n- `my_model.py`\n- `skills.yaml`\n\n### Step 2: Create the Behaviour\n\nOpen the `behaviours.py` file (`my_generic_buyer/skills/generic_buyer/behaviours.py`) and replace the stub code with the following:\n\n``` python\nfrom typing import Any, List, Optional, Set, cast\n\nfrom aea.protocols.dialogue.base import DialogueLabel\nfrom aea.skills.behaviours import TickerBehaviour\n\nfrom packages.fetchai.connections.ledger.base import (\n    CONNECTION_ID as LEDGER_CONNECTION_PUBLIC_ID,\n)\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.skills.generic_buyer.dialogues import (\n    FipaDialogue,\n    LedgerApiDialogue,\n    LedgerApiDialogues,\n    OefSearchDialogues,\n)\nfrom packages.fetchai.skills.generic_buyer.strategy import GenericStrategy\n\n\nDEFAULT_MAX_PROCESSING = 120\nDEFAULT_TX_INTERVAL = 2.0\nDEFAULT_SEARCH_INTERVAL = 5.0\nLEDGER_API_ADDRESS = str(LEDGER_CONNECTION_PUBLIC_ID)\n\n\nclass GenericSearchBehaviour(TickerBehaviour):\n    \"\"\"This class implements a search behaviour.\"\"\"\n\n    def __init__(self, **kwargs: Any):\n        \"\"\"Initialize the search behaviour.\"\"\"\n        search_interval = cast(\n            float, kwargs.pop(\"search_interval\", DEFAULT_SEARCH_INTERVAL)\n        )\n        super().__init__(tick_interval=search_interval, **kwargs)\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup for the behaviour.\"\"\"\n        strategy = cast(GenericStrategy, self.context.strategy)\n        if strategy.is_ledger_tx:\n            ledger_api_dialogues = cast(\n                LedgerApiDialogues, self.context.ledger_api_dialogues\n            )\n            ledger_api_msg, _ = ledger_api_dialogues.create(\n                counterparty=LEDGER_API_ADDRESS,\n                performative=LedgerApiMessage.Performative.GET_BALANCE,\n                ledger_id=strategy.ledger_id,\n                address=cast(str, self.context.agent_addresses.get(strategy.ledger_id)),\n            )\n            self.context.outbox.put_message(message=ledger_api_msg)\n        else:\n            strategy.is_searching = True\n\n    def act(self) -> None:\n        \"\"\"Implement the act.\"\"\"\n        strategy = cast(GenericStrategy, self.context.strategy)\n        if not strategy.is_searching:\n            return\n        transaction_behaviour = cast(\n            GenericTransactionBehaviour, self.context.behaviours.transaction\n        )\n        remaining_transactions_count = len(transaction_behaviour.waiting)\n        if remaining_transactions_count > 0:\n            self.context.logger.info(\n                f\"Transaction behaviour has {remaining_transactions_count} transactions remaining. Skipping search!\"\n            )\n            return\n        strategy.update_search_query_params()\n        query = strategy.get_location_and_service_query()\n        oef_search_dialogues = cast(\n            OefSearchDialogues, self.context.oef_search_dialogues\n        )\n        oef_search_msg, _ = oef_search_dialogues.create(\n            counterparty=self.context.search_service_address,\n            performative=OefSearchMessage.Performative.SEARCH_SERVICES,\n            query=query,\n        )\n        self.context.outbox.put_message(message=oef_search_msg)\n\n    def teardown(self) -> None:\n        \"\"\"Implement the task teardown.\"\"\"\n\n\nclass GenericTransactionBehaviour(TickerBehaviour):\n    \"\"\"A behaviour to sequentially submit transactions to the blockchain.\"\"\"\n\n    def __init__(self, **kwargs: Any):\n        \"\"\"Initialize the transaction behaviour.\"\"\"\n        tx_interval = cast(\n            float, kwargs.pop(\"transaction_interval\", DEFAULT_TX_INTERVAL)\n        )\n        self.max_processing = cast(\n            float, kwargs.pop(\"max_processing\", DEFAULT_MAX_PROCESSING)\n        )\n        self.processing_time = 0.0\n        self.waiting: List[FipaDialogue] = []\n        self.processing: Optional[LedgerApiDialogue] = None\n        self.timedout: Set[DialogueLabel] = set()\n        super().__init__(tick_interval=tx_interval, **kwargs)\n\n    def setup(self) -> None:\n        \"\"\"Setup behaviour.\"\"\"\n\n    def act(self) -> None:\n        \"\"\"Implement the act.\"\"\"\n        if self.processing is not None:\n            if self.processing_time <= self.max_processing:\n                # already processing\n                self.processing_time += self.tick_interval\n                return\n            self._timeout_processing()\n        if len(self.waiting) == 0:\n            # nothing to process\n            return\n        self._start_processing()\n\n    def _start_processing(self) -> None:\n        \"\"\"Process the next transaction.\"\"\"\n        fipa_dialogue = self.waiting.pop(0)\n        self.context.logger.info(\n            f\"Processing transaction, {len(self.waiting)} transactions remaining\"\n        )\n        ledger_api_dialogues = cast(\n            LedgerApiDialogues, self.context.ledger_api_dialogues\n        )\n        ledger_api_msg, ledger_api_dialogue = ledger_api_dialogues.create(\n            counterparty=LEDGER_API_ADDRESS,\n            performative=LedgerApiMessage.Performative.GET_RAW_TRANSACTION,\n            terms=fipa_dialogue.terms,\n        )\n        ledger_api_dialogue = cast(LedgerApiDialogue, ledger_api_dialogue)\n        ledger_api_dialogue.associated_fipa_dialogue = fipa_dialogue\n        self.processing_time = 0.0\n        self.processing = ledger_api_dialogue\n        self.context.logger.info(\n            f\"requesting transfer transaction from ledger api for message={ledger_api_msg}...\"\n        )\n        self.context.outbox.put_message(message=ledger_api_msg)\n\n    def teardown(self) -> None:\n        \"\"\"Teardown behaviour.\"\"\"\n\n    def _timeout_processing(self) -> None:\n        \"\"\"Timeout processing.\"\"\"\n        if self.processing is None:\n            return\n        self.timedout.add(self.processing.dialogue_label)\n        self.waiting.append(self.processing.associated_fipa_dialogue)\n        self.processing_time = 0.0\n        self.processing = None\n\n    def finish_processing(self, ledger_api_dialogue: LedgerApiDialogue) -> None:\n        \"\"\"\n        Finish processing.\n\n        :param ledger_api_dialogue: the ledger api dialogue\n        \"\"\"\n        if self.processing == ledger_api_dialogue:\n            self.processing_time = 0.0\n            self.processing = None\n            return\n        if ledger_api_dialogue.dialogue_label not in self.timedout:\n            raise ValueError(\n                f\"Non-matching dialogues in transaction behaviour: {self.processing} and {ledger_api_dialogue}\"\n            )\n        self.timedout.remove(ledger_api_dialogue.dialogue_label)\n        self.context.logger.debug(\n            f\"Timeout dialogue in transaction processing: {ledger_api_dialogue}\"\n        )\n        # don't reset, as another might be processing\n\n    def failed_processing(self, ledger_api_dialogue: LedgerApiDialogue) -> None:\n        \"\"\"\n        Failed processing.\n\n        Currently, we retry processing indefinitely.\n\n        :param ledger_api_dialogue: the ledger api dialogue\n        \"\"\"\n        self.finish_processing(ledger_api_dialogue)\n        self.waiting.append(ledger_api_dialogue.associated_fipa_dialogue)\n```\n\nThis <a href=\"../api/skills/behaviours#tickerbehaviour-objects\">`TickerBehaviour`</a> will send a search query to the <a href=\"../simple-oef\">SOEF search node</a> at regular tick intervals.\n\n### Step 3: Create the Handler\n\nSo far, the AEA is tasked with sending search queries to the <a href=\"../simple-oef\">SOEF search node</a>. However, currently the AEA has no way of handling the responses it receives from the SOEF or messages from other agents.\n\nLet us now implement <a href=\"../api/skills/base#handler-objects\">`Handlers`</a> to deal with the expected incoming messages. Open the `handlers.py` file (`my_generic_buyer/skills/generic_buyer/handlers.py`) and add the following code (replacing the stub code already present in the file):\n\n``` python\nimport pprint\nfrom typing import Optional, cast\n\nfrom aea.configurations.base import PublicId\nfrom aea.crypto.ledger_apis import LedgerApis\nfrom aea.protocols.base import Message\nfrom aea.skills.base import Handler\n\nfrom packages.fetchai.connections.ledger.base import (\n    CONNECTION_ID as LEDGER_CONNECTION_PUBLIC_ID,\n)\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.protocols.fipa.message import FipaMessage\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.protocols.signing.message import SigningMessage\nfrom packages.fetchai.skills.generic_buyer.behaviours import GenericTransactionBehaviour\nfrom packages.fetchai.skills.generic_buyer.dialogues import (\n    DefaultDialogues,\n    FipaDialogue,\n    FipaDialogues,\n    LedgerApiDialogue,\n    LedgerApiDialogues,\n    OefSearchDialogue,\n    OefSearchDialogues,\n    SigningDialogue,\n    SigningDialogues,\n)\nfrom packages.fetchai.skills.generic_buyer.strategy import GenericStrategy\n\n\nLEDGER_API_ADDRESS = str(LEDGER_CONNECTION_PUBLIC_ID)\n\n\nclass GenericFipaHandler(Handler):\n    \"\"\"This class implements a FIPA handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = FipaMessage.protocol_id  # type: Optional[PublicId]\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to a message.\n\n        :param message: the message\n        \"\"\"\n        fipa_msg = cast(FipaMessage, message)\n\n        # recover dialogue\n        fipa_dialogues = cast(FipaDialogues, self.context.fipa_dialogues)\n        fipa_dialogue = cast(FipaDialogue, fipa_dialogues.update(fipa_msg))\n        if fipa_dialogue is None:\n            self._handle_unidentified_dialogue(fipa_msg)\n            return\n\n        # handle message\n        if fipa_msg.performative == FipaMessage.Performative.PROPOSE:\n            self._handle_propose(fipa_msg, fipa_dialogue)\n        elif fipa_msg.performative == FipaMessage.Performative.DECLINE:\n            self._handle_decline(fipa_msg, fipa_dialogue, fipa_dialogues)\n        elif fipa_msg.performative == FipaMessage.Performative.MATCH_ACCEPT_W_INFORM:\n            self._handle_match_accept(fipa_msg, fipa_dialogue)\n        elif fipa_msg.performative == FipaMessage.Performative.INFORM:\n            self._handle_inform(fipa_msg, fipa_dialogue, fipa_dialogues)\n        else:\n            self._handle_invalid(fipa_msg, fipa_dialogue)\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n```\n\nYou will see that we are following similar logic to the `generic_seller` when we develop the `generic_buyer`’s side of the negotiation. First, we create a new dialogue and store it in the dialogues class. Then we are checking what kind of message we received by checking its performative. So lets start creating our handlers:\n\n``` python\n    def _handle_unidentified_dialogue(self, fipa_msg: FipaMessage) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param fipa_msg: the message\n        \"\"\"\n        self.context.logger.info(\n            \"received invalid fipa message={}, unidentified dialogue.\".format(fipa_msg)\n        )\n        default_dialogues = cast(DefaultDialogues, self.context.default_dialogues)\n        default_msg, _ = default_dialogues.create(\n            counterparty=fipa_msg.sender,\n            performative=DefaultMessage.Performative.ERROR,\n            error_code=DefaultMessage.ErrorCode.INVALID_DIALOGUE,\n            error_msg=\"Invalid dialogue.\",\n            error_data={\"fipa_message\": fipa_msg.encode()},\n        )\n        self.context.outbox.put_message(message=default_msg)\n```\n\nThe above code handles messages referencing unidentified dialogues and responds with an error message to the sender. Next we will handle the `PROPOSE` message received from the `my_generic_seller` AEA:\n\n``` python\n    def _handle_propose(\n        self, fipa_msg: FipaMessage, fipa_dialogue: FipaDialogue\n    ) -> None:\n        \"\"\"\n        Handle the propose.\n\n        :param fipa_msg: the message\n        :param fipa_dialogue: the dialogue object\n        \"\"\"\n        self.context.logger.info(\n            \"received proposal={} from sender={}\".format(\n                fipa_msg.proposal.values,\n                fipa_msg.sender[-5:],\n            )\n        )\n        strategy = cast(GenericStrategy, self.context.strategy)\n        acceptable = strategy.is_acceptable_proposal(fipa_msg.proposal)\n        affordable = strategy.is_affordable_proposal(fipa_msg.proposal)\n        if acceptable and affordable:\n            self.context.logger.info(\n                \"accepting the proposal from sender={}\".format(fipa_msg.sender[-5:])\n            )\n            terms = strategy.terms_from_proposal(fipa_msg.proposal, fipa_msg.sender)\n            fipa_dialogue.terms = terms\n            accept_msg = fipa_dialogue.reply(\n                performative=FipaMessage.Performative.ACCEPT,\n                target_message=fipa_msg,\n            )\n            self.context.outbox.put_message(message=accept_msg)\n        else:\n            self.context.logger.info(\n                \"declining the proposal from sender={}\".format(fipa_msg.sender[-5:])\n            )\n            decline_msg = fipa_dialogue.reply(\n                performative=FipaMessage.Performative.DECLINE,\n                target_message=fipa_msg,\n            )\n            self.context.outbox.put_message(message=decline_msg)\n```\n\nWhen we receive a proposal, we have to check if we have the funds to complete the transaction and if the proposal is acceptable based on our strategy. If the proposal is not affordable or acceptable, we respond with a `DECLINE` message. Otherwise, we send an `ACCEPT` message to the seller.\n\nThe next code-block handles the `DECLINE` message that we may receive from the seller as a response to our `CFP` or `ACCEPT` messages:\n\n``` python\n    def _handle_decline(\n        self,\n        fipa_msg: FipaMessage,\n        fipa_dialogue: FipaDialogue,\n        fipa_dialogues: FipaDialogues,\n    ) -> None:\n        \"\"\"\n        Handle the decline.\n\n        :param fipa_msg: the message\n        :param fipa_dialogue: the fipa dialogue\n        :param fipa_dialogues: the fipa dialogues\n        \"\"\"\n        self.context.logger.info(\n            \"received DECLINE from sender={}\".format(fipa_msg.sender[-5:])\n        )\n        target_message = fipa_dialogue.get_message_by_id(fipa_msg.target)\n\n        if not target_message:\n            raise ValueError(\"Can not find target message!\")  # pragma: nocover\n\n        declined_performative = target_message.performative\n\n        if declined_performative == FipaMessage.Performative.CFP:\n            fipa_dialogues.dialogue_stats.add_dialogue_endstate(\n                FipaDialogue.EndState.DECLINED_CFP, fipa_dialogue.is_self_initiated\n            )\n        if declined_performative == FipaMessage.Performative.ACCEPT:\n            fipa_dialogues.dialogue_stats.add_dialogue_endstate(\n                FipaDialogue.EndState.DECLINED_ACCEPT, fipa_dialogue.is_self_initiated\n            )\n```\n\nThe above code terminates each dialogue with the specific AEA and stores the state of the terminated dialogue (whether it was terminated after a `CFP` or an `ACCEPT`).\n\nIf `my_generic_seller` AEA wants to move on with the sale, it will send a `MATCH_ACCEPT` message. In order to handle this we add the following code:\n\n``` python\ndef _handle_match_accept(\n        self, fipa_msg: FipaMessage, fipa_dialogue: FipaDialogue\n    ) -> None:\n        \"\"\"\n        Handle the match accept.\n\n        :param fipa_msg: the message\n        :param fipa_dialogue: the dialogue object\n        \"\"\"\n        self.context.logger.info(\n            \"received MATCH_ACCEPT_W_INFORM from sender={} with info={}\".format(\n                fipa_msg.sender[-5:], fipa_msg.info\n            )\n        )\n        strategy = cast(GenericStrategy, self.context.strategy)\n        if strategy.is_ledger_tx:\n            transfer_address = fipa_msg.info.get(\"address\", None)\n            if transfer_address is not None and isinstance(transfer_address, str):\n                fipa_dialogue.terms.counterparty_address = (  # pragma: nocover\n                    transfer_address\n                )\n\n            tx_behaviour = cast(\n                GenericTransactionBehaviour, self.context.behaviours.transaction\n            )\n            tx_behaviour.waiting.append(fipa_dialogue)\n        else:\n            inform_msg = fipa_dialogue.reply(\n                performative=FipaMessage.Performative.INFORM,\n                target_message=fipa_msg,\n                info={\"Done\": \"Sending payment via bank transfer\"},\n            )\n            self.context.outbox.put_message(message=inform_msg)\n            self.context.logger.info(\n                \"informing counterparty={} of payment.\".format(fipa_msg.sender[-5:])\n            )\n```\n\nThe first thing we are checking is if we enabled our AEA to transact with a ledger. If so, we add this negotiation to the queue of transactions to be processed. If not, we simulate non-ledger payment by sending an `inform` to the seller that the payment is done (say via bank transfer).\n\nLastly, we need to handle `INFORM` messages. This is the message that will have our data:\n\n``` python\n    def _handle_inform(\n        self,\n        fipa_msg: FipaMessage,\n        fipa_dialogue: FipaDialogue,\n        fipa_dialogues: FipaDialogues,\n    ) -> None:\n        \"\"\"\n        Handle the match inform.\n\n        :param fipa_msg: the message\n        :param fipa_dialogue: the fipa dialogue\n        :param fipa_dialogues: the fipa dialogues\n        \"\"\"\n        self.context.logger.info(\n            \"received INFORM from sender={}\".format(fipa_msg.sender[-5:])\n        )\n        if len(fipa_msg.info.keys()) >= 1:\n            data = fipa_msg.info\n            data_string = pprint.pformat(data)[:1000]\n            self.context.logger.info(f\"received the following data={data_string}\")\n            fipa_dialogues.dialogue_stats.add_dialogue_endstate(\n                FipaDialogue.EndState.SUCCESSFUL, fipa_dialogue.is_self_initiated\n            )\n            strategy = cast(GenericStrategy, self.context.strategy)\n            strategy.successful_trade_with_counterparty(fipa_msg.sender, data)\n        else:\n            self.context.logger.info(\n                \"received no data from sender={}\".format(fipa_msg.sender[-5:])\n            )\n\n    def _handle_invalid(\n        self, fipa_msg: FipaMessage, fipa_dialogue: FipaDialogue\n    ) -> None:\n        \"\"\"\n        Handle a fipa message of invalid performative.\n\n        :param fipa_msg: the message\n        :param fipa_dialogue: the fipa dialogue\n        \"\"\"\n        self.context.logger.warning(\n            \"cannot handle fipa message of performative={} in dialogue={}.\".format(\n                fipa_msg.performative, fipa_dialogue\n            )\n        )\n```\n\nWe now need to add handlers for messages received from the `DecisionMaker` and the <a href=\"../simple-oef\">SOEF search node</a>. We need one handler for each type of protocol we use.\n\nTo handle the messages in the `oef_search` protocol used by the <a href=\"../simple-oef\">SOEF search node</a> we add the following code in the same file (`my_generic_buyer/skills/generic_buyer/handlers.py`):\n\n``` python\nclass GenericOefSearchHandler(Handler):\n    \"\"\"This class implements an OEF search handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = OefSearchMessage.protocol_id  # type: Optional[PublicId]\n\n    def setup(self) -> None:\n        \"\"\"Call to setup the handler.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to a message.\n\n        :param message: the message\n        \"\"\"\n        oef_search_msg = cast(OefSearchMessage, message)\n\n        # recover dialogue\n        oef_search_dialogues = cast(\n            OefSearchDialogues, self.context.oef_search_dialogues\n        )\n        oef_search_dialogue = cast(\n            Optional[OefSearchDialogue], oef_search_dialogues.update(oef_search_msg)\n        )\n        if oef_search_dialogue is None:\n            self._handle_unidentified_dialogue(oef_search_msg)\n            return\n\n        # handle message\n        if oef_search_msg.performative is OefSearchMessage.Performative.OEF_ERROR:\n            self._handle_error(oef_search_msg, oef_search_dialogue)\n        elif oef_search_msg.performative is OefSearchMessage.Performative.SEARCH_RESULT:\n            self._handle_search(oef_search_msg, oef_search_dialogue)\n        else:\n            self._handle_invalid(oef_search_msg, oef_search_dialogue)\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n\n    def _handle_unidentified_dialogue(self, oef_search_msg: OefSearchMessage) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param oef_search_msg: the message\n        \"\"\"\n        self.context.logger.info(\n            \"received invalid oef_search message={}, unidentified dialogue.\".format(\n                oef_search_msg\n            )\n        )\n\n    def _handle_error(\n        self, oef_search_msg: OefSearchMessage, oef_search_dialogue: OefSearchDialogue\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param oef_search_msg: the oef search message\n        :param oef_search_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.info(\n            \"received oef_search error message={} in dialogue={}.\".format(\n                oef_search_msg, oef_search_dialogue\n            )\n        )\n\n    def _handle_search(\n        self, oef_search_msg: OefSearchMessage, oef_search_dialogue: OefSearchDialogue\n    ) -> None:\n        \"\"\"\n        Handle the search response.\n\n        :param oef_search_msg: the oef search message\n        :param oef_search_dialogue: the dialogue\n        \"\"\"\n        if len(oef_search_msg.agents) == 0:\n            self.context.logger.info(\n                f\"found no agents in dialogue={oef_search_dialogue}, continue searching.\"\n            )\n            return\n        strategy = cast(GenericStrategy, self.context.strategy)\n        if strategy.is_stop_searching_on_result:\n            self.context.logger.info(\n                \"found agents={}, stopping search.\".format(\n                    list(map(lambda x: x[-5:], oef_search_msg.agents)),\n                )\n            )\n            strategy.is_searching = False  # stopping search\n        else:\n            self.context.logger.info(\n                \"found agents={}.\".format(\n                    list(map(lambda x: x[-5:], oef_search_msg.agents)),\n                )\n            )\n        query = strategy.get_service_query()\n        fipa_dialogues = cast(FipaDialogues, self.context.fipa_dialogues)\n        counterparties = strategy.get_acceptable_counterparties(oef_search_msg.agents)\n        for counterparty in counterparties:\n            cfp_msg, _ = fipa_dialogues.create(\n                counterparty=counterparty,\n                performative=FipaMessage.Performative.CFP,\n                query=query,\n            )\n            self.context.outbox.put_message(message=cfp_msg)\n            self.context.logger.info(\n                \"sending CFP to agent={}\".format(counterparty[-5:])\n            )\n\n    def _handle_invalid(\n        self, oef_search_msg: OefSearchMessage, oef_search_dialogue: OefSearchDialogue\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param oef_search_msg: the oef search message\n        :param oef_search_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.warning(\n            \"cannot handle oef_search message of performative={} in dialogue={}.\".format(\n                oef_search_msg.performative,\n                oef_search_dialogue,\n            )\n        )\n```\n\nWhen we receive a message from the <a href=\"../simple-oef\">SOEF search node</a> of a type `OefSearchMessage.Performative.SEARCH_RESULT`, we are passing the details to the relevant handler method. In the `_handle_search` function, we are checking that the response contains some agents, and we stop the search if it does. We pick our first agent and send a `CFP` message.\n\nThe last handlers we need are the `GenericSigningHandler` and the `GenericLedgerApiHandler`. These handlers are responsible for `SigningMessages` that we receive from the `DecisionMaker`, and `LedgerApiMessages` that we receive from the ledger connection, respectively.\n\n``` python\nclass GenericSigningHandler(Handler):\n    \"\"\"Implement the signing handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = SigningMessage.protocol_id  # type: Optional[PublicId]\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup for the handler.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to a message.\n\n        :param message: the message\n        \"\"\"\n        signing_msg = cast(SigningMessage, message)\n\n        # recover dialogue\n        signing_dialogues = cast(SigningDialogues, self.context.signing_dialogues)\n        signing_dialogue = cast(\n            Optional[SigningDialogue], signing_dialogues.update(signing_msg)\n        )\n        if signing_dialogue is None:\n            self._handle_unidentified_dialogue(signing_msg)\n            return\n\n        # handle message\n        if signing_msg.performative is SigningMessage.Performative.SIGNED_TRANSACTION:\n            self._handle_signed_transaction(signing_msg, signing_dialogue)\n        elif signing_msg.performative is SigningMessage.Performative.ERROR:\n            self._handle_error(signing_msg, signing_dialogue)\n        else:\n            self._handle_invalid(signing_msg, signing_dialogue)\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n\n    def _handle_unidentified_dialogue(self, signing_msg: SigningMessage) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param signing_msg: the message\n        \"\"\"\n        self.context.logger.info(\n            \"received invalid signing message={}, unidentified dialogue.\".format(\n                signing_msg\n            )\n        )\n\n    def _handle_signed_transaction(\n        self, signing_msg: SigningMessage, signing_dialogue: SigningDialogue\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param signing_msg: the signing message\n        :param signing_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.info(\"transaction signing was successful.\")\n        ledger_api_dialogue = signing_dialogue.associated_ledger_api_dialogue\n        last_ledger_api_msg = ledger_api_dialogue.last_incoming_message\n        if last_ledger_api_msg is None:\n            raise ValueError(\"Could not retrieve last message in ledger api dialogue\")\n        ledger_api_msg = ledger_api_dialogue.reply(\n            performative=LedgerApiMessage.Performative.SEND_SIGNED_TRANSACTION,\n            target_message=last_ledger_api_msg,\n            signed_transaction=signing_msg.signed_transaction,\n        )\n        self.context.outbox.put_message(message=ledger_api_msg)\n        self.context.logger.info(\"sending transaction to ledger.\")\n\n    def _handle_error(\n        self, signing_msg: SigningMessage, signing_dialogue: SigningDialogue\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param signing_msg: the signing message\n        :param signing_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.info(\n            \"transaction signing was not successful. Error_code={} in dialogue={}\".format(\n                signing_msg.error_code, signing_dialogue\n            )\n        )\n        signing_msg_ = cast(\n            Optional[SigningMessage], signing_dialogue.last_outgoing_message\n        )\n        if (\n            signing_msg_ is not None\n            and signing_msg_.performative\n            == SigningMessage.Performative.SIGN_TRANSACTION\n        ):\n            tx_behaviour = cast(\n                GenericTransactionBehaviour, self.context.behaviours.transaction\n            )\n            ledger_api_dialogue = signing_dialogue.associated_ledger_api_dialogue\n            tx_behaviour.failed_processing(ledger_api_dialogue)\n\n    def _handle_invalid(\n        self, signing_msg: SigningMessage, signing_dialogue: SigningDialogue\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param signing_msg: the signing message\n        :param signing_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.warning(\n            \"cannot handle signing message of performative={} in dialogue={}.\".format(\n                signing_msg.performative, signing_dialogue\n            )\n        )\n\n\nclass GenericLedgerApiHandler(Handler):\n    \"\"\"Implement the ledger handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = LedgerApiMessage.protocol_id  # type: Optional[PublicId]\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup for the handler.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to a message.\n\n        :param message: the message\n        \"\"\"\n        ledger_api_msg = cast(LedgerApiMessage, message)\n\n        # recover dialogue\n        ledger_api_dialogues = cast(\n            LedgerApiDialogues, self.context.ledger_api_dialogues\n        )\n        ledger_api_dialogue = cast(\n            Optional[LedgerApiDialogue], ledger_api_dialogues.update(ledger_api_msg)\n        )\n        if ledger_api_dialogue is None:\n            self._handle_unidentified_dialogue(ledger_api_msg)\n            return\n\n        # handle message\n        if ledger_api_msg.performative is LedgerApiMessage.Performative.BALANCE:\n            self._handle_balance(ledger_api_msg)\n        elif (\n            ledger_api_msg.performative is LedgerApiMessage.Performative.RAW_TRANSACTION\n        ):\n            self._handle_raw_transaction(ledger_api_msg, ledger_api_dialogue)\n        elif (\n            ledger_api_msg.performative\n            == LedgerApiMessage.Performative.TRANSACTION_DIGEST\n        ):\n            self._handle_transaction_digest(ledger_api_msg, ledger_api_dialogue)\n        elif (\n            ledger_api_msg.performative\n            == LedgerApiMessage.Performative.TRANSACTION_RECEIPT\n        ):\n            self._handle_transaction_receipt(ledger_api_msg, ledger_api_dialogue)\n        elif ledger_api_msg.performative == LedgerApiMessage.Performative.ERROR:\n            self._handle_error(ledger_api_msg, ledger_api_dialogue)\n        else:\n            self._handle_invalid(ledger_api_msg, ledger_api_dialogue)\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n\n    def _handle_unidentified_dialogue(self, ledger_api_msg: LedgerApiMessage) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param ledger_api_msg: the message\n        \"\"\"\n        self.context.logger.info(\n            \"received invalid ledger_api message={}, unidentified dialogue.\".format(\n                ledger_api_msg\n            )\n        )\n\n    def _handle_balance(self, ledger_api_msg: LedgerApiMessage) -> None:\n        \"\"\"\n        Handle a message of balance performative.\n\n        :param ledger_api_msg: the ledger api message\n        \"\"\"\n        strategy = cast(GenericStrategy, self.context.strategy)\n        if ledger_api_msg.balance > 0:\n            self.context.logger.info(\n                \"starting balance on {} ledger={}.\".format(\n                    strategy.ledger_id,\n                    ledger_api_msg.balance,\n                )\n            )\n            strategy.balance = ledger_api_msg.balance\n            strategy.is_searching = True\n        else:\n            self.context.logger.warning(\n                f\"you have no starting balance on {strategy.ledger_id} ledger! Stopping skill {self.skill_id}.\"\n            )\n            self.context.is_active = False\n\n    def _handle_raw_transaction(\n        self, ledger_api_msg: LedgerApiMessage, ledger_api_dialogue: LedgerApiDialogue\n    ) -> None:\n        \"\"\"\n        Handle a message of raw_transaction performative.\n\n        :param ledger_api_msg: the ledger api message\n        :param ledger_api_dialogue: the ledger api dialogue\n        \"\"\"\n        self.context.logger.info(\"received raw transaction={}\".format(ledger_api_msg))\n        signing_dialogues = cast(SigningDialogues, self.context.signing_dialogues)\n        signing_msg, signing_dialogue = signing_dialogues.create(\n            counterparty=self.context.decision_maker_address,\n            performative=SigningMessage.Performative.SIGN_TRANSACTION,\n            raw_transaction=ledger_api_msg.raw_transaction,\n            terms=ledger_api_dialogue.associated_fipa_dialogue.terms,\n        )\n        signing_dialogue = cast(SigningDialogue, signing_dialogue)\n        signing_dialogue.associated_ledger_api_dialogue = ledger_api_dialogue\n        self.context.decision_maker_message_queue.put_nowait(signing_msg)\n        self.context.logger.info(\n            \"proposing the transaction to the decision maker. Waiting for confirmation ...\"\n        )\n\n    def _handle_transaction_digest(\n        self, ledger_api_msg: LedgerApiMessage, ledger_api_dialogue: LedgerApiDialogue\n    ) -> None:\n        \"\"\"\n        Handle a message of transaction_digest performative.\n\n        :param ledger_api_msg: the ledger api message\n        :param ledger_api_dialogue: the ledger api dialogue\n        \"\"\"\n        self.context.logger.info(\n            \"transaction was successfully submitted. Transaction digest={}\".format(\n                ledger_api_msg.transaction_digest\n            )\n        )\n        ledger_api_msg_ = ledger_api_dialogue.reply(\n            performative=LedgerApiMessage.Performative.GET_TRANSACTION_RECEIPT,\n            target_message=ledger_api_msg,\n            transaction_digest=ledger_api_msg.transaction_digest,\n        )\n        self.context.logger.info(\"checking transaction is settled.\")\n        self.context.outbox.put_message(message=ledger_api_msg_)\n\n    def _handle_transaction_receipt(\n        self, ledger_api_msg: LedgerApiMessage, ledger_api_dialogue: LedgerApiDialogue\n    ) -> None:\n        \"\"\"\n        Handle a message of balance performative.\n\n        :param ledger_api_msg: the ledger api message\n        :param ledger_api_dialogue: the ledger api dialogue\n        \"\"\"\n        fipa_dialogue = ledger_api_dialogue.associated_fipa_dialogue\n        is_settled = LedgerApis.is_transaction_settled(\n            fipa_dialogue.terms.ledger_id, ledger_api_msg.transaction_receipt.receipt\n        )\n        tx_behaviour = cast(\n            GenericTransactionBehaviour, self.context.behaviours.transaction\n        )\n        if is_settled:\n            tx_behaviour.finish_processing(ledger_api_dialogue)\n            ledger_api_msg_ = cast(\n                Optional[LedgerApiMessage], ledger_api_dialogue.last_outgoing_message\n            )\n            if ledger_api_msg_ is None:\n                raise ValueError(  # pragma: nocover\n                    \"Could not retrieve last ledger_api message\"\n                )\n            fipa_msg = cast(Optional[FipaMessage], fipa_dialogue.last_incoming_message)\n            if fipa_msg is None:\n                raise ValueError(\"Could not retrieve last fipa message\")\n            inform_msg = fipa_dialogue.reply(\n                performative=FipaMessage.Performative.INFORM,\n                target_message=fipa_msg,\n                info={\"transaction_digest\": ledger_api_msg_.transaction_digest.body},\n            )\n            self.context.outbox.put_message(message=inform_msg)\n            self.context.logger.info(\n                \"transaction confirmed, informing counterparty={} of transaction digest.\".format(\n                    fipa_dialogue.dialogue_label.dialogue_opponent_addr[-5:],\n                )\n            )\n        else:\n            tx_behaviour.failed_processing(ledger_api_dialogue)\n            self.context.logger.info(\n                \"transaction_receipt={} not settled or not valid, aborting\".format(\n                    ledger_api_msg.transaction_receipt\n                )\n            )\n\n    def _handle_error(\n        self, ledger_api_msg: LedgerApiMessage, ledger_api_dialogue: LedgerApiDialogue\n    ) -> None:\n        \"\"\"\n        Handle a message of error performative.\n\n        :param ledger_api_msg: the ledger api message\n        :param ledger_api_dialogue: the ledger api dialogue\n        \"\"\"\n        self.context.logger.info(\n            \"received ledger_api error message={} in dialogue={}.\".format(\n                ledger_api_msg, ledger_api_dialogue\n            )\n        )\n        ledger_api_msg_ = cast(\n            Optional[LedgerApiMessage], ledger_api_dialogue.last_outgoing_message\n        )\n        if (\n            ledger_api_msg_ is not None\n            and ledger_api_msg_.performative\n            != LedgerApiMessage.Performative.GET_BALANCE\n        ):\n            tx_behaviour = cast(\n                GenericTransactionBehaviour, self.context.behaviours.transaction\n            )\n            tx_behaviour.failed_processing(ledger_api_dialogue)\n\n    def _handle_invalid(\n        self, ledger_api_msg: LedgerApiMessage, ledger_api_dialogue: LedgerApiDialogue\n    ) -> None:\n        \"\"\"\n        Handle a message of invalid performative.\n\n        :param ledger_api_msg: the ledger api message\n        :param ledger_api_dialogue: the ledger api dialogue\n        \"\"\"\n        self.context.logger.warning(\n            \"cannot handle ledger_api message of performative={} in dialogue={}.\".format(\n                ledger_api_msg.performative,\n                ledger_api_dialogue,\n            )\n        )\n```\n\n### Step 4: Create the Strategy\n\nWe are going to create the strategy that we want our AEA to follow. Rename the `my_model.py` file (in `my_generic_buyer/skills/generic_buyer/`) to `strategy.py` and replace the stub code with the following:\n\n``` python\nfrom typing import Any, Dict, List, Tuple\n\nfrom aea.common import Address\nfrom aea.exceptions import enforce\nfrom aea.helpers.search.generic import SIMPLE_SERVICE_MODEL\nfrom aea.helpers.search.models import (\n    Constraint,\n    ConstraintType,\n    Description,\n    Location,\n    Query,\n)\nfrom aea.helpers.transaction.base import Terms\nfrom aea.skills.base import Model\n\n\nDEFAULT_IS_LEDGER_TX = True\n\nDEFAULT_MAX_UNIT_PRICE = 5\nDEFAULT_MAX_TX_FEE = 2\nDEFAULT_SERVICE_ID = \"generic_service\"\nDEFAULT_MIN_QUANTITY = 1\nDEFAULT_MAX_QUANTITY = 100\n\nDEFAULT_LOCATION = {\"longitude\": 0.1270, \"latitude\": 51.5194}\nDEFAULT_SEARCH_QUERY = {\n    \"search_key\": \"seller_service\",\n    \"search_value\": \"generic_service\",\n    \"constraint_type\": \"==\",\n}\nDEFAULT_SEARCH_RADIUS = 5.0\n\nDEFAULT_MAX_NEGOTIATIONS = 2\n\n\nclass GenericStrategy(Model):\n    \"\"\"This class defines a strategy for the agent.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize the strategy of the agent.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        ledger_id = kwargs.pop(\"ledger_id\", None)\n        currency_id = kwargs.pop(\"currency_id\", None)\n        self._is_ledger_tx = kwargs.pop(\"is_ledger_tx\", DEFAULT_IS_LEDGER_TX)\n\n        self._max_unit_price = kwargs.pop(\"max_unit_price\", DEFAULT_MAX_UNIT_PRICE)\n        self._min_quantity = kwargs.pop(\"min_quantity\", DEFAULT_MIN_QUANTITY)\n        self._max_quantity = kwargs.pop(\"max_quantity\", DEFAULT_MAX_QUANTITY)\n        self._max_tx_fee = kwargs.pop(\"max_tx_fee\", DEFAULT_MAX_TX_FEE)\n        self._service_id = kwargs.pop(\"service_id\", DEFAULT_SERVICE_ID)\n\n        self._search_query = kwargs.pop(\"search_query\", DEFAULT_SEARCH_QUERY)\n        location = kwargs.pop(\"location\", DEFAULT_LOCATION)\n        self._agent_location = Location(\n            latitude=location[\"latitude\"], longitude=location[\"longitude\"]\n        )\n        self._radius = kwargs.pop(\"search_radius\", DEFAULT_SEARCH_RADIUS)\n\n        self._max_negotiations = kwargs.pop(\n            \"max_negotiations\", DEFAULT_MAX_NEGOTIATIONS\n        )\n        self._is_stop_searching_on_result = kwargs.pop(\"stop_searching_on_result\", True)\n\n        super().__init__(**kwargs)\n        self._ledger_id = (\n            ledger_id if ledger_id is not None else self.context.default_ledger_id\n        )\n        if currency_id is None:\n            currency_id = self.context.currency_denominations.get(self._ledger_id, None)\n            enforce(\n                currency_id is not None,\n                f\"Currency denomination for ledger_id={self._ledger_id} not specified.\",\n            )\n        self._currency_id = currency_id\n        self._is_searching = False\n        self._balance = 0\n```\n\nSimilar to the seller AEA, we initialize the strategy class by trying to read the strategy variables from the YAML file, and if not possible, use some default values. In the following snippet, the two methods after the properties are related to the OEF search service. Add this snippet under the initialization of the strategy class:\n\n``` python\n    @property\n    def ledger_id(self) -> str:\n        \"\"\"Get the ledger id.\"\"\"\n        return self._ledger_id\n\n    @property\n    def is_ledger_tx(self) -> bool:\n        \"\"\"Check whether or not tx are settled on a ledger.\"\"\"\n        return self._is_ledger_tx\n\n    @property\n    def is_stop_searching_on_result(self) -> bool:\n        \"\"\"Check if search is stopped on result.\"\"\"\n        return self._is_stop_searching_on_result\n\n    @property\n    def is_searching(self) -> bool:\n        \"\"\"Check if the agent is searching.\"\"\"\n        return self._is_searching\n\n    @is_searching.setter\n    def is_searching(self, is_searching: bool) -> None:\n        \"\"\"Check if the agent is searching.\"\"\"\n        enforce(isinstance(is_searching, bool), \"Can only set bool on is_searching!\")\n        self._is_searching = is_searching\n\n    @property\n    def balance(self) -> int:\n        \"\"\"Get the balance.\"\"\"\n        return self._balance\n\n    @balance.setter\n    def balance(self, balance: int) -> None:\n        \"\"\"Set the balance.\"\"\"\n        self._balance = balance\n\n    @property\n    def max_negotiations(self) -> int:\n        \"\"\"Get the maximum number of negotiations the agent can start.\"\"\"\n        return self._max_negotiations\n\n    def get_location_and_service_query(self) -> Query:\n        \"\"\"\n        Get the location and service query of the agent.\n\n        :return: the query\n        \"\"\"\n        close_to_my_service = Constraint(\n            \"location\", ConstraintType(\"distance\", (self._agent_location, self._radius))\n        )\n        service_key_filter = Constraint(\n            self._search_query[\"search_key\"],\n            ConstraintType(\n                self._search_query[\"constraint_type\"],\n                self._search_query[\"search_value\"],\n            ),\n        )\n        query = Query(\n            [close_to_my_service, service_key_filter],\n        )\n        return query\n\n    def get_service_query(self) -> Query:\n        \"\"\"\n        Get the service query of the agent.\n\n        :return: the query\n        \"\"\"\n        service_key_filter = Constraint(\n            self._search_query[\"search_key\"],\n            ConstraintType(\n                self._search_query[\"constraint_type\"],\n                self._search_query[\"search_value\"],\n            ),\n        )\n        query = Query([service_key_filter], model=SIMPLE_SERVICE_MODEL)\n        return query\n```\n\nThe following code block checks if the proposal that we received is acceptable according to a strategy:\n\n``` python\n    def is_acceptable_proposal(self, proposal: Description) -> bool:\n        \"\"\"\n        Check whether it is an acceptable proposal.\n\n        :param proposal: a description\n        :return: whether it is acceptable\n        \"\"\"\n        result = (\n            all(\n                key in proposal.values\n                for key in [\n                    \"ledger_id\",\n                    \"currency_id\",\n                    \"price\",\n                    \"service_id\",\n                    \"quantity\",\n                    \"tx_nonce\",\n                ]\n            )\n            and proposal.values[\"ledger_id\"] == self.ledger_id\n            and proposal.values[\"price\"] > 0\n            and proposal.values[\"quantity\"] >= self._min_quantity\n            and proposal.values[\"quantity\"] <= self._max_quantity\n            and proposal.values[\"price\"]\n            <= proposal.values[\"quantity\"] * self._max_unit_price\n            and proposal.values[\"currency_id\"] == self._currency_id\n            and proposal.values[\"service_id\"] == self._service_id\n            and isinstance(proposal.values[\"tx_nonce\"], str)\n            and proposal.values[\"tx_nonce\"] != \"\"\n        )\n        return result\n```\n\nThe `is_affordable_proposal` method in the following code block checks if we can afford the transaction based on the funds we have in our wallet on the ledger. The rest of the methods are self-explanatory.\n\n``` python\n    def is_affordable_proposal(self, proposal: Description) -> bool:\n        \"\"\"\n        Check whether it is an affordable proposal.\n\n        :param proposal: a description\n        :return: whether it is affordable\n        \"\"\"\n        if self.is_ledger_tx:\n            payable = proposal.values.get(\"price\", 0) + self._max_tx_fee\n            result = self.balance >= payable\n        else:\n            result = True\n        return result\n\n    def get_acceptable_counterparties(\n        self, counterparties: Tuple[str, ...]\n    ) -> Tuple[str, ...]:\n        \"\"\"\n        Process counterparties and drop unacceptable ones.\n\n        :param counterparties: a tuple of counterparties\n        :return: list of counterparties\n        \"\"\"\n        valid_counterparties: List[str] = []\n        for idx, counterparty in enumerate(counterparties):\n            if idx < self.max_negotiations:\n                valid_counterparties.append(counterparty)\n        return tuple(valid_counterparties)\n\n    def terms_from_proposal(\n        self, proposal: Description, counterparty_address: Address\n    ) -> Terms:\n        \"\"\"\n        Get the terms from a proposal.\n\n        :param proposal: the proposal\n        :param counterparty_address: the counterparty\n        :return: terms\n        \"\"\"\n        buyer_address = self.context.agent_addresses[proposal.values[\"ledger_id\"]]\n        terms = Terms(\n            ledger_id=proposal.values[\"ledger_id\"],\n            sender_address=buyer_address,\n            counterparty_address=counterparty_address,\n            amount_by_currency_id={\n                proposal.values[\"currency_id\"]: -proposal.values[\"price\"]\n            },\n            quantities_by_good_id={\n                proposal.values[\"service_id\"]: proposal.values[\"quantity\"]\n            },\n            is_sender_payable_tx_fee=True,\n            nonce=proposal.values[\"tx_nonce\"],\n            fee_by_currency_id={proposal.values[\"currency_id\"]: self._max_tx_fee},\n        )\n        return terms\n\n    def successful_trade_with_counterparty(\n        self, counterparty: str, data: Dict[str, str]\n    ) -> None:\n        \"\"\"\n        Do something on successful trade.\n\n        :param counterparty: the counterparty address\n        :param data: the data\n        \"\"\"\n\n    def update_search_query_params(self) -> None:\n        \"\"\"Update agent location and query for search.\"\"\"\n```\n\n### Step 5: Create the Dialogues\n\nAs mentioned during the creation of the seller AEA, we should keep track of the various interactions an AEA has with others and this is done via dialogues. Create a new file and name it `dialogues.py` (in `my_generic_buyer/skills/generic_buyer/`). Inside this file add the following code:\n\n``` python\nfrom typing import Any, Optional, Type\n\nfrom aea.common import Address\nfrom aea.exceptions import AEAEnforceError, enforce\nfrom aea.helpers.transaction.base import Terms\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\nfrom aea.protocols.dialogue.base import DialogueLabel as BaseDialogueLabel\nfrom aea.skills.base import Model\n\nfrom packages.fetchai.protocols.default.dialogues import (\n    DefaultDialogue as BaseDefaultDialogue,\n)\nfrom packages.fetchai.protocols.default.dialogues import (\n    DefaultDialogues as BaseDefaultDialogues,\n)\nfrom packages.fetchai.protocols.fipa.dialogues import FipaDialogue as BaseFipaDialogue\nfrom packages.fetchai.protocols.fipa.dialogues import FipaDialogues as BaseFipaDialogues\nfrom packages.fetchai.protocols.fipa.message import FipaMessage\nfrom packages.fetchai.protocols.ledger_api.dialogues import (\n    LedgerApiDialogue as BaseLedgerApiDialogue,\n)\nfrom packages.fetchai.protocols.ledger_api.dialogues import (\n    LedgerApiDialogues as BaseLedgerApiDialogues,\n)\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\nfrom packages.fetchai.protocols.oef_search.dialogues import (\n    OefSearchDialogue as BaseOefSearchDialogue,\n)\nfrom packages.fetchai.protocols.oef_search.dialogues import (\n    OefSearchDialogues as BaseOefSearchDialogues,\n)\nfrom packages.fetchai.protocols.signing.dialogues import (\n    SigningDialogue as BaseSigningDialogue,\n)\nfrom packages.fetchai.protocols.signing.dialogues import (\n    SigningDialogues as BaseSigningDialogues,\n)\nfrom packages.fetchai.protocols.signing.message import SigningMessage\n\n\nDefaultDialogue = BaseDefaultDialogue\n\n\nclass DefaultDialogues(Model, BaseDefaultDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return DefaultDialogue.Role.AGENT\n\n        BaseDefaultDialogues.__init__(\n            self,\n            self_address=self.context.agent_address,\n            role_from_first_message=role_from_first_message,\n        )\n\n\nclass FipaDialogue(BaseFipaDialogue):\n    \"\"\"The dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    __slots__ = (\n        \"_terms\",\n        \"_associated_ledger_api_dialogue\",\n    )\n\n    def __init__(\n        self,\n        dialogue_label: BaseDialogueLabel,\n        self_address: Address,\n        role: BaseDialogue.Role,\n        message_class: Type[FipaMessage] = FipaMessage,\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n        :param message_class: the message class\n        \"\"\"\n        BaseFipaDialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            self_address=self_address,\n            role=role,\n            message_class=message_class,\n        )\n        self._terms = None  # type: Optional[Terms]\n\n    @property\n    def terms(self) -> Terms:\n        \"\"\"Get terms.\"\"\"\n        if self._terms is None:\n            raise AEAEnforceError(\"Terms not set!\")\n        return self._terms\n\n    @terms.setter\n    def terms(self, terms: Terms) -> None:\n        \"\"\"Set terms.\"\"\"\n        enforce(self._terms is None, \"Terms already set!\")\n        self._terms = terms\n\n\nclass FipaDialogues(Model, BaseFipaDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return BaseFipaDialogue.Role.BUYER\n\n        BaseFipaDialogues.__init__(\n            self,\n            self_address=self.context.agent_address,\n            role_from_first_message=role_from_first_message,\n            dialogue_class=FipaDialogue,\n        )\n\n\nclass LedgerApiDialogue(BaseLedgerApiDialogue):\n    \"\"\"The dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    __slots__ = (\"_associated_fipa_dialogue\",)\n\n    def __init__(\n        self,\n        dialogue_label: BaseDialogueLabel,\n        self_address: Address,\n        role: BaseDialogue.Role,\n        message_class: Type[LedgerApiMessage] = LedgerApiMessage,\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n        :param message_class: the message class\n        \"\"\"\n        BaseLedgerApiDialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            self_address=self_address,\n            role=role,\n            message_class=message_class,\n        )\n        self._associated_fipa_dialogue = None  # type: Optional[FipaDialogue]\n\n    @property\n    def associated_fipa_dialogue(self) -> FipaDialogue:\n        \"\"\"Get associated_fipa_dialogue.\"\"\"\n        if self._associated_fipa_dialogue is None:\n            raise AEAEnforceError(\"FipaDialogue not set!\")\n        return self._associated_fipa_dialogue\n\n    @associated_fipa_dialogue.setter\n    def associated_fipa_dialogue(self, fipa_dialogue: FipaDialogue) -> None:\n        \"\"\"Set associated_fipa_dialogue\"\"\"\n        enforce(self._associated_fipa_dialogue is None, \"FipaDialogue already set!\")\n        self._associated_fipa_dialogue = fipa_dialogue\n\n\nclass LedgerApiDialogues(Model, BaseLedgerApiDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return BaseLedgerApiDialogue.Role.AGENT\n\n        BaseLedgerApiDialogues.__init__(\n            self,\n            self_address=str(self.skill_id),\n            role_from_first_message=role_from_first_message,\n            dialogue_class=LedgerApiDialogue,\n        )\n\n\nOefSearchDialogue = BaseOefSearchDialogue\n\n\nclass OefSearchDialogues(Model, BaseOefSearchDialogues):\n    \"\"\"This class keeps track of all oef_search dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return BaseOefSearchDialogue.Role.AGENT\n\n        BaseOefSearchDialogues.__init__(\n            self,\n            self_address=str(self.skill_id),\n            role_from_first_message=role_from_first_message,\n        )\n\n\nclass SigningDialogue(BaseSigningDialogue):\n    \"\"\"The dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    __slots__ = (\"_associated_ledger_api_dialogue\",)\n\n    def __init__(\n        self,\n        dialogue_label: BaseDialogueLabel,\n        self_address: Address,\n        role: BaseDialogue.Role,\n        message_class: Type[SigningMessage] = SigningMessage,\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n        :param message_class: the message class\n        \"\"\"\n        BaseSigningDialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            self_address=self_address,\n            role=role,\n            message_class=message_class,\n        )\n        self._associated_ledger_api_dialogue = None  # type: Optional[LedgerApiDialogue]\n\n    @property\n    def associated_ledger_api_dialogue(self) -> LedgerApiDialogue:\n        \"\"\"Get associated_ledger_api_dialogue.\"\"\"\n        if self._associated_ledger_api_dialogue is None:\n            raise AEAEnforceError(\"LedgerApiDialogue not set!\")\n        return self._associated_ledger_api_dialogue\n\n    @associated_ledger_api_dialogue.setter\n    def associated_ledger_api_dialogue(\n        self, ledger_api_dialogue: LedgerApiDialogue\n    ) -> None:\n        \"\"\"Set associated_ledger_api_dialogue\"\"\"\n        enforce(\n            self._associated_ledger_api_dialogue is None,\n            \"LedgerApiDialogue already set!\",\n        )\n        self._associated_ledger_api_dialogue = ledger_api_dialogue\n\n\nclass SigningDialogues(Model, BaseSigningDialogues):\n    \"\"\"This class keeps track of all oef_search dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return BaseSigningDialogue.Role.SKILL\n\n        BaseSigningDialogues.__init__(\n            self,\n            self_address=str(self.skill_id),\n            role_from_first_message=role_from_first_message,\n            dialogue_class=SigningDialogue,\n        )\n```\n\nThe various dialogues classes in the above code snippet store dialogues with other AEAs, services and components, (e.g. SOEF search node via the `fetchai/soef` connection, ledgers via the `fetchai/ledger` connection and the decision maker). They expose useful methods to manipulate these interactions, access previous messages, and enable us to identify possible communications problems between `my_generic_seller` and `my_generic_buyer` AEAs.\n\n### Step 6: Update the YAML Files\n\nAfter making so many changes to our skill, we have to update the `skill.yaml` configuration file so it reflects our newly created classes, and contains the values used by the strategy. Make sure `skill.yaml` contains the following configuration:\n\n``` yaml\nname: generic_buyer\nauthor: fetchai\nversion: 0.1.0\ntype: skill\ndescription: The weather client skill implements the skill to purchase weather data.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: QmTR91jm7WfJpmabisy74NR5mc35YXjDU1zQAUKZeHRw8L\n  __init__.py: QmU5vrC8FipyjfS5biNa6qDWdp4aeH5h4YTtbFDmCg8Chj\n  behaviours.py: QmNwvSjEz4kzM3gWtnKbZVFJc2Z85Nb748CWAK4C4Sa4nT\n  dialogues.py: QmNen91qQDWy4bNBKrB3LabAP5iRf29B8iwYss4NB13iNU\n  handlers.py: QmZfudXXbdiREiViuwPZDXoQQyXT2ySQHdF7psQsohZXQy\n  strategy.py: QmcrwaEWvKHDCNti8QjRhB4utJBJn5L8GpD27Uy9zHwKhY\nfingerprint_ignore_patterns: []\nconnections:\n- fetchai/ledger:0.21.5\ncontracts: []\nprotocols:\n- fetchai/default:1.1.7\n- fetchai/fipa:1.1.7\n- fetchai/ledger_api:1.1.7\n- fetchai/oef_search:1.1.7\n- fetchai/signing:1.1.7\nskills: []\nbehaviours:\n  search:\n    args:\n      search_interval: 5\n    class_name: GenericSearchBehaviour\n  transaction:\n    args:\n      max_processing: 420\n      transaction_interval: 2\n    class_name: GenericTransactionBehaviour\nhandlers:\n  fipa:\n    args: {}\n    class_name: GenericFipaHandler\n  ledger_api:\n    args: {}\n    class_name: GenericLedgerApiHandler\n  oef_search:\n    args: {}\n    class_name: GenericOefSearchHandler\n  signing:\n    args: {}\n    class_name: GenericSigningHandler\nmodels:\n  default_dialogues:\n    args: {}\n    class_name: DefaultDialogues\n  fipa_dialogues:\n    args: {}\n    class_name: FipaDialogues\n  ledger_api_dialogues:\n    args: {}\n    class_name: LedgerApiDialogues\n  oef_search_dialogues:\n    args: {}\n    class_name: OefSearchDialogues\n  signing_dialogues:\n    args: {}\n    class_name: SigningDialogues\n  strategy:\n    args:\n      is_ledger_tx: true\n      location:\n        latitude: 51.5194\n        longitude: 0.127\n      max_negotiations: 1\n      max_tx_fee: 3550000000000000\n      max_unit_price: 20\n      min_quantity: 1\n      search_query:\n        constraint_type: ==\n        search_key: seller_service\n        search_value: generic_service\n      search_radius: 5.0\n      service_id: generic_service\n      stop_searching_on_result: true\n    class_name: GenericStrategy\nis_abstract: false\ndependencies: {}\n```\n\nWe must pay attention to the models and the strategy’s variables. Here we can change the price we would like to buy each reading at, the maximum transaction fee we are prepared to pay, and so on.\n\nFinally, we fingerprint our new skill:\n\n``` bash\naea fingerprint skill fetchai/generic_buyer:0.1.0\n```\n\nThis will hash each file and save the hash in the fingerprint. This way, in the future we can easily track if any of the files have changed.\n\n## Run the AEAs\n\n### Create Private Keys\n\nFor each AEA, create a private key:\n\n``` bash\naea generate-key fetchai\naea add-key fetchai fetchai_private_key.txt\n```\n\nNext, create a private key to secure the AEA's communications:\n\n``` bash\naea generate-key fetchai fetchai_connection_private_key.txt\naea add-key fetchai fetchai_connection_private_key.txt --connection\n```\n\nFinally, certify the key for use by the connections that request that:\n\n``` bash\naea issue-certificates\n```\n\n### Update the AEA Configurations\n\nIn both AEAs run:\n\n``` bash\naea config set --type dict agent.default_routing \\\n'{\n  \"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n  \"fetchai/oef_search:1.1.7\": \"fetchai/soef:0.27.6\"\n}'\n```\n\n### Fund the Buyer AEA\n\nCreate some wealth for your buyer on the Fetch.ai testnet (this operation might take a while).\n\n``` bash\naea generate-wealth fetchai --sync\n```\n\n### Run Seller AEA\n\nAdd the remaining packages for the seller AEA, then run it:\n\n``` bash\naea add connection fetchai/p2p_libp2p:0.27.5\naea add connection fetchai/soef:0.27.6\naea add connection fetchai/ledger:0.21.5\naea add protocol fetchai/fipa:1.1.7\naea install\naea build\naea config set agent.default_connection fetchai/p2p_libp2p:0.27.5\naea run\n```\n\nOnce you see a message of the form `To join its network use multiaddr: ['SOME_ADDRESS']` take note of the address.\n\n#### Run Buyer AEA\n\nAdd the remaining packages for the buyer AEA:\n\n``` bash\naea add connection fetchai/p2p_libp2p:0.27.5\naea add connection fetchai/soef:0.27.6\naea add connection fetchai/ledger:0.21.5\naea add protocol fetchai/fipa:1.1.7\naea add protocol fetchai/signing:1.1.7\naea install\naea build\naea config set agent.default_connection fetchai/p2p_libp2p:0.27.5\n```\n\nThen, update the configuration of the buyer AEA's P2P connection:\n\n``` bash\naea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \\\n'{\n  \"delegate_uri\": \"127.0.0.1:11001\",\n  \"entry_peers\": [\"SOME_ADDRESS\"],\n  \"local_uri\": \"127.0.0.1:9001\",\n  \"log_file\": \"libp2p_node.log\",\n  \"public_uri\": \"127.0.0.1:9001\"\n}'\n```\n\nwhere `SOME_ADDRESS` is replaced accordingly.\n\nThen run the buyer AEA:\n\n``` bash\naea run\n```\n\nYou will see that the AEAs negotiate and then transact using the Dorado testnet.\n\n## Delete the AEAs\n\nWhen you are done, go up a level and delete the AEAs.\n\n``` bash\ncd ..\naea delete my_generic_seller\naea delete my_generic_buyer\n```\n\n## Next Steps\n\nYou have completed the \"Getting Started\" series. Congratulations!\n\nThe following guide provides some hints on <a href=\"../development-setup\">AEA development setup</a>.\n\n### Recommended\n\nWe recommend you build your own AEA next. There are many helpful guides and demos in the documentation, and a developer community on <a href=\"https://discord.com/invite/btedfjPJTj\" target=\"_blank\">Discord</a>. Speak to you there!\n"
  },
  {
    "path": "docs/generic-skills.md",
    "content": "# Generic Skills\n\nThe AEA generic buyer and seller skills demonstrate an interaction between two AEAs:\n\n- An AEA that provides a (data selling) service.\n- An AEA that demands this service.\n\n## Discussion\n\nThe scope of this guide is demonstrating how to create easily configurable AEAs. The buyer AEA finds the seller, negotiates the terms of trade, and if successful purchases the data by sending payment. The seller AEA sells the service specified in its `skill.yaml` file, delivering it to the buyer upon receiving payment.\n\nNote that these agents do not utilize a smart contract but interact with a ledger to complete a transaction. Moreover, in this setup, the buyer agent has to trust the seller to send the data upon successful payment.\n\nThe corresponding packages can be customised to allow for a database or sensor to be defined from which data is loaded. This is done by first modifying the `has_data_source` variable in `skill.yaml` file of the `generic_seller` skill to `True`. Then you have to provide an implementation for the `collect_from_data_source(self)` method in the `strategy.py` file. More detailed instructions is beyond the scope of this guide.\n\n## Communication\n\nThe following diagram shows the communication between various entities in this interaction.\n\n``` mermaid\n    sequenceDiagram\n        participant Search\n        participant Buyer_AEA\n        participant Seller_AEA\n        participant Blockchain\n    \n        activate Buyer_AEA\n        activate Search\n        activate Seller_AEA\n        activate Blockchain\n        \n        Seller_AEA->>Search: register_service\n        Buyer_AEA->>Search: search_agents\n        Search-->>Buyer_AEA: list_of_agents\n        Buyer_AEA->>Seller_AEA: call_for_proposal\n        Seller_AEA->>Buyer_AEA: propose\n        Buyer_AEA->>Seller_AEA: accept\n        Seller_AEA->>Buyer_AEA: match_accept\n        Buyer_AEA->>Blockchain: transfer_funds\n        Buyer_AEA->>Seller_AEA: send_transaction_hash\n        Seller_AEA->>Blockchain: check_transaction_status\n        Seller_AEA->>Buyer_AEA: send_data\n        \n        deactivate Buyer_AEA\n        deactivate Search\n        deactivate Seller_AEA\n        deactivate Blockchain \n```\n\n## Preparation Instructions\n\n### Dependencies\n\nFollow the <a href=\"../quickstart/#preliminaries\">Preliminaries</a> and <a href=\"../quickstart/#installation\">Installation</a> sections from the AEA quick start.\n\n## Demo Instructions\n\n### Create the Seller AEA\n\nFirst, fetch the seller AEA:\n\n``` bash\naea fetch fetchai/generic_seller:0.29.5 --alias my_seller_aea\ncd my_seller_aea\naea install\naea build\n```\n\n??? note \"Alternatively, create from scratch:\"\n    The following steps create the seller from scratch:\n\n    ``` bash\n    aea create my_seller_aea\n    cd my_seller_aea\n    aea add connection fetchai/p2p_libp2p:0.27.5\n    aea add connection fetchai/soef:0.27.6\n    aea add connection fetchai/ledger:0.21.5\n    aea add skill fetchai/generic_seller:0.28.6\n    aea config set --type dict agent.dependencies \\\n    '{\n      \"aea-ledger-fetchai\": {\"version\": \"<2.0.0,>=1.0.0\"}\n    }'\n    aea config set agent.default_connection fetchai/p2p_libp2p:0.27.5\n    aea config set --type dict agent.default_routing \\\n    '{\n      \"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n      \"fetchai/oef_search:1.1.7\": \"fetchai/soef:0.27.6\"\n    }'\n    aea install\n    aea build\n    ```\n\n### Create the Buyer AEA\n\nThen, in another terminal fetch the buyer AEA:\n\n``` bash\naea fetch fetchai/generic_buyer:0.30.5 --alias my_buyer_aea\ncd my_buyer_aea\naea install\naea build\n```\n\n??? note \"Alternatively, create from scratch:\"\n    The following steps create the buyer from scratch:\n\n    ``` bash\n    aea create my_buyer_aea\n    cd my_buyer_aea\n    aea add connection fetchai/p2p_libp2p:0.27.5\n    aea add connection fetchai/soef:0.27.6\n    aea add connection fetchai/ledger:0.21.5\n    aea add skill fetchai/generic_buyer:0.27.6\n    aea config set --type dict agent.dependencies \\\n    '{\n      \"aea-ledger-fetchai\": {\"version\": \"<2.0.0,>=1.0.0\"}\n    }'\n    aea config set agent.default_connection fetchai/p2p_libp2p:0.27.5\n    aea config set --type dict agent.default_routing \\\n    '{\n      \"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n      \"fetchai/oef_search:1.1.7\": \"fetchai/soef:0.27.6\"\n    }'\n    aea install\n    aea build\n    ```\n\n### Add Keys for the Seller AEA\n\nCreate the private key for the seller AEA based on the network you want to transact. To generate and add a private-public key pair for Fetch.ai `Dorado` use:\n\n``` bash\naea generate-key fetchai\naea add-key fetchai fetchai_private_key.txt\n```\n\nNext, create a private key used to secure the AEA's communications:\n\n``` bash\naea generate-key fetchai fetchai_connection_private_key.txt\naea add-key fetchai fetchai_connection_private_key.txt --connection\n```\n\nFinally, certify the key for use by the connections that request that:\n\n``` bash\naea issue-certificates\n```\n\n### Add Keys and Generate Wealth for the Buyer AEA\n\nThe buyer needs to have some wealth to purchase the data from the seller.\n\nFirst, create the private key for the buyer AEA based on the network you want to transact. To generate and add a private-public key pair for Fetch.ai `Dorado` use:\n\n``` bash\naea generate-key fetchai\naea add-key fetchai fetchai_private_key.txt\n```\n\nThen, create some wealth for your buyer based on the network you want to transact with. On the Fetch.ai `Dorado` network:\n\n``` bash\naea generate-wealth fetchai\n```\n\nNext, create a private key used to secure the AEA's communications:\n\n``` bash\naea generate-key fetchai fetchai_connection_private_key.txt\naea add-key fetchai fetchai_connection_private_key.txt --connection\n```\n\nFinally, certify the key for use by the connections that request that:\n\n``` bash\naea issue-certificates\n```\n\n### Update the Skill Configurations\n\nThe default skill configurations assume that the transaction is settled against the Fetch.ai ledger.\n\nIn the generic seller's skill configuration file (`my_seller_aea/vendor/fetchai/skills/generi_seller/skill.yaml`) the `data_for_sale` is the data the seller AEA is offering for sale. In the following case, this is a one item dictionary where key is `generic` and value is `data`.\n\nFurthermore, the `service_data` is used to register the seller's service in the <a href=\"../simple-oef\">SOEF search node</a> and make your agent discoverable.\n\n``` yaml\nmodels:\n  ...\n  strategy:\n    args:\n      currency_id: FET\n      data_for_sale:\n        generic: data\n      has_data_source: false\n      is_ledger_tx: true\n      ledger_id: fetchai\n      location:\n        latitude: 51.5194\n        longitude: 0.127\n      service_data:\n        key: seller_service\n        value: generic_service\n      service_id: generic_service\n      unit_price: 10\n    class_name: GenericStrategy\n```\n\nThe generic buyer skill configuration file (`my_buyer_aea/vendor/fetchai/skills/generic_buyer/skill.yaml`) includes the `search_query` which has to match the `service_data` of the seller.\n\n``` yaml\nmodels:\n  ...\n  strategy:\n    args:\n      currency_id: FET\n      is_ledger_tx: true\n      ledger_id: fetchai\n      location:\n        latitude: 51.5194\n        longitude: 0.127\n      max_negotiations: 1\n      max_tx_fee: 3550000000000000\n      max_unit_price: 20\n      search_query:\n        constraint_type: ==\n        search_key: seller_service\n        search_value: generic_service\n      search_radius: 5.0\n      service_id: generic_service\n    class_name: GenericStrategy\n```\n\n### Update the Skill Configurations\n\nBoth skills are abstract skills, make them instantiable:\n\n``` bash\ncd my_seller_aea\naea config set vendor.fetchai.skills.generic_seller.is_abstract false --type bool\n```\n\n``` bash\ncd my_buyer_aea\naea config set vendor.fetchai.skills.generic_buyer.is_abstract false --type bool\n```\n\n## Run the AEAs\n\nFirst, run the seller AEA:\n\n``` bash\naea run\n```\n\nOnce you see a message of the form `To join its network use multiaddr 'SOME_ADDRESS'` take note of this address. (Alternatively, use `aea get-multiaddress fetchai -c -i fetchai/p2p_libp2p:0.27.5 -u public_uri` to retrieve the address.)\nThis is the entry peer address for the local <a href=\"../acn\">agent communication network</a> created by the seller.\n\nThen, configure the buyer to connect to this same local ACN by running the following command in the buyer terminal, replacing `SOME_ADDRESS` with the value you noted above:\n\n``` bash\naea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \\\n'{\n  \"delegate_uri\": \"127.0.0.1:11001\",\n  \"entry_peers\": [\"SOME_ADDRESS\"],\n  \"local_uri\": \"127.0.0.1:9001\",\n  \"log_file\": \"libp2p_node.log\",\n  \"public_uri\": \"127.0.0.1:9001\"\n}'\n```\n\nThen run the buyer AEA:\n\n``` bash\naea run\n```\n\nYou will see that the AEAs negotiate and then transact using the Fetch.ai testnet.\n\n## Delete the AEAs\n\nWhen you're done, stop the agents (`CTRL+C`), go up a level and delete the AEAs.\n\n``` bash\ncd ..\naea delete my_seller_aea\naea delete my_buyer_aea\n```\n"
  },
  {
    "path": "docs/generic-storage.md",
    "content": "# Generic Storage\n\nThe AEA generic storage: description and usage.\n\n## AEA Generic Storage\n\nAEA generic storage allows AEA skill's components to store data permanently and use it any time.\nThe primary scenario: to save AEA data on shutdown and load back on startup.\nGeneric storage provides an API for general data manipulation in key-object style.\n\n## Configuration\n\nStorage is enabled by providing in the agent configuration (`aea-config.yaml`) an optional `storage_uri`. The storage URI consists of the backend name and string data provided to selected backend.\n\nThe storage URI schema is `<BACKEND_NAME>://[Optional string]`\nExample: `storage_uri: sqlite://./some_file.db` tells the AEA to use SQLite backend and store data in `./some_file.db`.\n\nSupported backends:\n\n- SQLite - bundled with python simple SQL engine that uses file or in-memory storage.\n\n## Dialogues and Storage Integration\n\nOne of the most useful cases is the integration of the dialogues subsystem and storage. It helps maintain dialogues state during agent restarts and reduced memory requirements due to the offloading feature.\n\n### Keep Terminal State Dialogues\n\nThe Dialogues class has the optional boolean argument `keep_terminal_state_dialogues`\nwhich specifies whether a dialogue which has reached its terminal state is kept in memory or not. If `keep_terminal_state_dialogues` is `False`, dialogues that reach a terminal state are removed from memory and can not be used anymore. If `keep_terminal_state_dialogues` is `True`, dialogues that reach a terminal state are kept in memory or storage (if configured). If storage is configured, all dialogues in memory are stored on agent stop and restored on agent start.\n\nIt is useful to save memory with terminated dialogues that will (possibly) be never used again.\n\nDefault behaviour on keep terminals state dialogues is set according to the protocol specification but can be set explicitly with skill configuration section.\n\nSkill configuration to keep terminated dialogues for `DefaultDialogues`.\nExample:\n\n### Dialogues Dump/Restore on Agent Restart\n\nIf storage is enabled then all the dialogues present in memory will be stored on agent's teardown and loaded on agent's start.\n\n### Offload Terminal State Dialogues\n\nIf keep options is set and storage is available dialogues in terminal state will be dumped to generic storage and removed from memory. This option helps to save memory and handle terminated dialogues with the same functionality as when they are kept in memory.\n\nAll the active dialogues will be stored and loaded during agent restart. All the terminated offloaded dialogues will stay in storage on agent restart.\n\nTo enable dialogues offloading `keep_terminal_state_dialogues` has to be enabled and storage configured.\n\n## Manual Usage with Skill Components\n\nHandlers, Behaviours and Models are able to use storage if enabled.\n\nStorage is available with skill context: `self.context.storage`\nif `self.context.storage` is not None, storage is enabled and ready to use.\n\nGeneric storage consists of two parts: objects and collections.\nObjects consist of the `object_id` (unique string) and object body. The object body is any JSON friendly python data type: `list`, `dict`, `int`, `float`, `string`, `bool`.\n\nCollection is a group of the objects, objects data types can vary in the same collection.\nCollection name is name consists of letters, numbers and `_`.\n\nTo get/put specific object collection instance should be used.\n\n``` python\nmy_collection = self.context.storage.get_sync_connection('my_collection')\n```\n\nCollection instance provide set of methods to handle data objects.\nList of collection methods:\n\n``` python\n    def put(self, object_id: str, object_body: JSON_TYPES) -> None:\n        \"\"\"\n        Put object into collection.\n\n        :param object_id: str object id\n        :param object_body: python dict, json compatible.\n        :return: None\n        \"\"\"\n\n    def get(self, object_id: str) -> Optional[JSON_TYPES]:\n        \"\"\"\n        Get object from the collection.\n\n        :param object_id: str object id\n\n        :return: dict if object exists in collection otherwise None\n        \"\"\"\n\n    def remove(self, object_id: str) -> None:\n        \"\"\"\n        Remove object from the collection.\n\n        :param object_id: str object id\n\n        :return: None\n        \"\"\"\n\n    def find(self, field: str, equals: EQUALS_TYPE) -> List[OBJECT_ID_AND_BODY]:\n        \"\"\"\n        Get objects from the collection by filtering by field value.\n\n        :param field: field name to search: example \"parent.field\"\n        :param equals: value field should be equal to\n\n        :return: List of object bodies\n        \"\"\"\n\n    def list(self) -> List[OBJECT_ID_AND_BODY]:\n        \"\"\"\n        List all objects with keys from the collection.\n\n        :return: Tuple of objects keys, bodies.\n        \"\"\"\n```\n\nSimple behaviour example:\n\nIt saves the `datetime` string of the first act and print it to stdout.\n\n``` python\nclass TestBehaviour(TickerBehaviour):\n    \"\"\"Simple behaviour to count how many acts were called.\"\"\"\n\n    def setup(self) -> None:\n        \"\"\"Set up behaviour.\"\"\"\n\n    def act(self) -> None:\n        \"\"\"Make an action.\"\"\"\n        if not (self.context.storage and self.context.storage.is_connected):\n            return\n        collection = self.context.storage.get_sync_collection('my_collection')\n        first_call_datetime = collection.get(\"first_call_ts\")\n        if not first_call_ts:\n            # there is no object with \"first_call_ts\" id.\n            first_call_datetime = str(datetime.datetime.now())\n            col.put(first_call_ts, first_call_datetime)\n        print(\"Act was called for the first time on:\", first_call_datetime)\n```\n\nPlease, pay attention: `datetime` object is not JSON friendly and can not be stored directly. it should be transformed to `timestamp` or string before put into the storage.\n"
  },
  {
    "path": "docs/glossary.md",
    "content": "# Glossary\n\nThis glossary defines a number of terms commonly used across the documentation. For the definitions of framework components consult the API docs.\n\n- **AEA (Autonomous Economic Agent)**: An AEA is \"an intelligent agent acting on an owner's behalf, with limited or no interference, and whose goal is to generate economic value to its owner\". AEAs are a special type of agent. [<a href=\"../index\">more</a>]\n\n- **Software Agent**: a software agent is a computer program that acts on behalf of an entity (e.g. individual, organisation, business). [<a href=\"https://en.wikipedia.org/wiki/Software_agent\" target=\"_blank\">more</a>]\n\n- **sOEF (Simple Open Economic Framework)**: The simple-OEF, or sOEF, is a search and discovery service for autonomous economic agents. [<a href=\"../simple-oef\">more</a>]\n\n- **ACN (Agent Communication Network)**: The ACN is a peer-to-peer communication network for autonomous economic agents. [<a href=\"../acn\">more</a>]\n"
  },
  {
    "path": "docs/gym-example.md",
    "content": "# Gym Example\n\nThe `gym` example demonstrates the AEA framework's flexibility with respect to Reinforcement Learning using OpenAI's `gym` framework.\n\n## Discussion\n\nThere is no immediate use case for this example as you can train an RL agent without the AEA proxy layer just fine (and faster).\n\nHowever, the example decouples the RL agent from the `gym.Env` allowing them to run in separate execution environments, potentially owned by different entities.\n\n## Preparation Instructions\n\n### Dependencies\n\nFollow the <a href=\"../quickstart/#preliminaries\">Preliminaries</a> and <a href=\"../quickstart/#installation\">Installation</a> sections from the AEA quick start.\n\nDownload the necessary directories into your working directory:\n\n``` bash\nsvn export https://github.com/fetchai/agents-aea.git/trunk/examples\nsvn export https://github.com/fetchai/agents-aea.git/trunk/packages\n```\n\nInstall the `gym` and `numpy` library.\n\n``` bash\npip install numpy gym\n```\n\n## Demo Instructions\n\n### Run the Example\n\n``` bash\npython examples/gym_ex/train.py\n```\n\nNotice the usual RL setup, i.e. the fit method of the RL agent has the typical signature and a familiar implementation.\n\nNote how `train.py` demonstrates how easy it is to use an AEA agent as a proxy layer between an OpenAI `gym.Env` and a standard RL agent.\n\nIt is just one line of code to introduce the proxy agent and proxy environment!\n\n``` python\nfrom gyms.env import BanditNArmedRandom\nfrom proxy.env import ProxyEnv\nfrom rl.agent import RLAgent\n\n\nif __name__ == \"__main__\":\n    NB_GOODS = 10\n    NB_PRICES_PER_GOOD = 100\n    NB_STEPS = 4000\n\n    # Use any gym.Env compatible environment:\n    gym_env = BanditNArmedRandom(nb_bandits=NB_GOODS, nb_prices_per_bandit=NB_PRICES_PER_GOOD)\n\n    # Pass the gym environment to a proxy environment:\n    proxy_env = ProxyEnv(gym_env)\n\n    # Use any RL agent compatible with the gym environment and call the fit method:\n    rl_agent = RLAgent(nb_goods=NB_GOODS)\n    rl_agent.fit(env=proxy_env, nb_steps=NB_STEPS)\n```\n"
  },
  {
    "path": "docs/gym-skill.md",
    "content": "# Gym Skill\n\nThe AEA gym skill demonstrates how a custom Reinforcement Learning agent, that uses OpenAI's <a href=\"https://www.gymlibrary.dev/\" target=\"_blank\">gym</a> library, may be embedded into an AEA skill and connection.\n\n## Discussion\n\nThe gym skills demonstrate how to wrap a Reinforcement Learning agent in a skill.\nThe example decouples the RL agent from the `gym.Env` allowing them to run in separate execution environments, potentially owned by different entities.\n\n## Preparation Instructions\n\n### Dependencies\n\nFollow the <a href=\"../quickstart/#preliminaries\">Preliminaries</a> and <a href=\"../quickstart/#installation\">Installation</a> sections from the AEA quick start.\n\nDownload the necessary directories into your working directory:\n\n``` bash\nmkdir gym_skill_agent\nsvn export https://github.com/fetchai/agents-aea.git/trunk/examples\n```\n\nInstall the `gym` and `numpy` library.\n\n``` bash\npip install numpy gym\n```\n\n## Demo Instructions\n\n### Create the AEA\n\nFirst, fetch the gym AEA:\n\n``` bash\naea fetch fetchai/gym_aea:0.26.5 --alias my_gym_aea\ncd my_gym_aea\naea install\n```\n\n??? note \"Alternatively, create from scratch:\"\n\n    ### Create the AEA\n\n    In the root directory, create the gym AEA and enter the project.\n\n    ``` bash\n    aea create my_gym_aea\n    cd my_gym_aea\n    ```\n\n    ### Add the gym skill\n\n    ``` bash\n    aea add skill fetchai/gym:0.21.6\n    ```\n    \n    ### Set gym connection as default\n\n    ``` bash\n    aea config set agent.default_connection fetchai/gym:0.20.6\n    ```\n\n    ### Install the skill dependencies\n    \n    To install the `gym` package, a dependency of the gym skill, from PyPI run\n\n    ``` bash\n    aea install\n    ```\n\n### Set up the Training Environment\n\n#### Copy the Gym Environment to the AEA Directory\n\n``` bash\nmkdir gyms\ncp -a ../examples/gym_ex/gyms/. gyms/\n```\n\n#### Update the Connection Configuration\n\n``` bash\naea config set vendor.fetchai.connections.gym.config.env 'gyms.env.BanditNArmedRandom'\n```\n\n#### Create and Add a Private Key\n\n``` bash\naea generate-key fetchai\naea add-key fetchai\n```\n\n### Run the AEA with the Gym Connection\n\n``` bash\naea run\n```\n\nYou will see the gym training logs.\n\n<img src=\"../assets/gym-training.png\" alt=\"AEA gym training logs\" class=\"center\">\n\n### Delete the AEA\n\nWhen you're done, you can go up a level and delete the AEA.\n\n``` bash\ncd ..\naea delete my_gym_aea\n```\n\n## Communication\n\nThis diagram shows the communication between the AEA and the gym environment\n\n``` mermaid\n    sequenceDiagram\n        participant AEA\n        participant Environment\n\n        activate AEA\n        activate Environment\n        AEA->>Environment: reset\n        loop learn\n            AEA->>Environment: act\n            Environment->>AEA: percept\n        end\n        AEA->>Environment: close\n\n        deactivate AEA\n        deactivate Environment\n```\n\n## Skill Architecture\n\nThe skill consists of two core components: `GymHandler` and `GymTask`.\n\nIn the `setup` method of the `GymHandler` the `GymTask` is initialized, as well as its `setup` and `execute` methods called. The handler, which is registered against the `GymMessage.protocol_id` then filters for messages of that protocol with the performative `GymMessage.Performative.PERCEPT`. These messages are passed to the `proxy_env_queue` of the task.\n\nThe `GymTask` is responsible for training the RL agent. In particular, `MyRLAgent` is initialized and trained against `ProxyEnv`. The `ProxyEnv` instantiates a `gym.Env` class and therefore implements its API. This means the proxy environment is compatible with any `gym` compatible RL agent. However, unlike other environments it only acts as a proxy and does not implement an environment of its own. It allows for the decoupling of the process environment of the `gym.env` from the process environment of the RL agent. The actual `gym.env` against which the agent is trained is wrapped by the `gym` connection. The proxy environment and gym connection communicate via a protocol, the `gym` protocol. Note, it would trivially be possible to implement the `gym` environment in another AEA; this way one AEA could provide `gym` environments as a service. Naturally, the overhead created by the introduction of the extra layers causes a higher latency when training the RL agent.\n\nIn this particular skill, which chiefly serves for demonstration purposes, we implement a very basic RL agent. The agent trains a model of price of `n` goods: it aims to discover the most likely price of each good. To this end, the agent randomly selects one of the `n` goods on each training step and then chooses as an `action` the price which it deems is most likely accepted. Each good is represented by an id and the possible price range `[1,100]` divided into 100 integer bins. For each price bin, a `PriceBandit` is created which models the likelihood of this price. In particular, a price bandit maintains a <a href=\"https://en.wikipedia.org/wiki/Beta_distribution\" target=\"_blank\">beta distribution</a>. The beta distribution is initialized to the uniform distribution. Each time the price associated with a given `PriceBandit` is accepted or rejected the distribution maintained by the `PriceBandit` is updated. For each good, the agent can therefore over time learn which price is most likely.\n\n<img src=\"../assets/gym-skill.jpg\" alt=\"Gym skill illustration\" class=\"center\" style=\"display: block; margin-left: auto; margin-right: auto;width:80%;\">\n\nThe illustration shows how the RL agent only interacts with the proxy environment by sending it `action (A)` and receiving `observation (O)`, `reward (R)`, `done (D)` and  `info (I)`.\n"
  },
  {
    "path": "docs/http-connection-and-skill.md",
    "content": "# HTTP Connection\n\n## Description\n\nThe HTTP client and HTTP server connections enable an AEA to communicate with external servers, respectively clients, via HTTP.\n\nThe HTTP client connection receives request envelops from an agent's skill, translates each into an HTTP request and sends it to a server external to the agent. If it receives an HTTP response from the server within a timeout window, it translates it into a response envelope, and sends this back to the relevant skill inside the agent.\n\nThe HTTP server connection allows you to run a server inside the connection itself which accepts requests from clients external to the agent. The HTTP server connection validates requests it receives against a provided OpenAPI file. It translates each valid request into an envelope and sends it to the skill specified in the `connections` configuration. If it receives a valid response envelope from the skill within a timeout window, the connection translates the response envelope into an HTTP response and serves it to the client.\n\n## HTTP Client\n\nThe `fetchai/simple_data_request:0.14.6` skill demonstrates a simple use case of the HTTP Client connection.\n\nThe `HttpRequestBehaviour` in `behaviours.py` periodically sends HTTP envelops to the HTTP client connection. Its `act()` method, periodically called, simply calls `_generate_http_request` which contains the logic for enqueueing an HTTP request envelop.\n\nThe `HttpHandler` in `handler.py` is a basic handler for dealing with HTTP response envelops received from the HTTP client connection. In the `handle()` method, the responses are dealt with by the private `_handle_response` method which essentially logs the response and adds the body of the response into the skill's shared state.\n\n## HTTP Server\n\nCreate a new AEA:\n\n``` bash\naea create my_aea\ncd my_aea\n```\n\nAdd the http server connection package:\n\n``` bash\naea add connection fetchai/http_server:0.23.6\n```\n\nUpdate the default connection:\n\n``` bash\naea config set agent.default_connection fetchai/http_server:0.23.6\n```\n\nModify the `api_spec_path`:\n\n``` bash\naea config set vendor.fetchai.connections.http_server.config.api_spec_path \"../examples/http_ex/petstore.yaml\"\n```\n\nEnsure the file exists under the specified path!\n\nCreate and add a private key:\n\n``` bash\naea generate-key fetchai\naea add-key fetchai\n```\n\nInstall the dependencies:\n\n``` bash\naea install\n```\n\nWrite and add your skill:\n\n``` bash\naea scaffold skill http_echo\n```\n\nYou can implement a simple http echo skill (modelled after the standard echo skill) which prints out the content of received messages and responds with success.\n\nFirst, delete the `my_model.py` and `behaviour.py` files (in `my_aea/skills/http_echo/`). The server will be purely reactive, so you only need the `handlers.py` file, and the `dialogues.py` to record the state of the dialogues. Update `skill.yaml` accordingly, so set `models: {}` and `behaviours: {}`.\n\nNext implement a basic handler which prints the received envelopes and responds.\n\nThen, replace the content of `handlers.py` with the following code snippet, after having replaced the placeholder `YOUR_USERNAME` with the author username (i.e. the output of `aea config get agent.author`):\n\n``` python\nimport json\nfrom typing import cast\n\nfrom aea.protocols.base import Message\nfrom aea.skills.base import Handler\n\nfrom packages.fetchai.protocols.default import DefaultMessage\nfrom packages.fetchai.protocols.http.message import HttpMessage\nfrom packages.YOUR_USERNAME.skills.http_echo.dialogues import (\n    DefaultDialogues,\n    HttpDialogue,\n    HttpDialogues,\n)\n\n\nclass HttpHandler(Handler):\n    \"\"\"This implements the echo handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = HttpMessage.protocol_id\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to an envelope.\n\n        :param message: the message\n        \"\"\"\n        http_msg = cast(HttpMessage, message)\n\n        # recover dialogue\n        http_dialogues = cast(HttpDialogues, self.context.http_dialogues)\n        http_dialogue = cast(HttpDialogue, http_dialogues.update(http_msg))\n        if http_dialogue is None:\n            self._handle_unidentified_dialogue(http_msg)\n            return\n\n        # handle message\n        if http_msg.performative == HttpMessage.Performative.REQUEST:\n            self._handle_request(http_msg, http_dialogue)\n        else:\n            self._handle_invalid(http_msg, http_dialogue)\n\n    def _handle_unidentified_dialogue(self, http_msg: HttpMessage) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param http_msg: the message\n        \"\"\"\n        self.context.logger.info(\n            \"received invalid http message={}, unidentified dialogue.\".format(http_msg)\n        )\n        default_dialogues = cast(DefaultDialogues, self.context.default_dialogues)\n        default_msg, _ = default_dialogues.create(\n            counterparty=http_msg.sender,\n            performative=DefaultMessage.Performative.ERROR,\n            error_code=DefaultMessage.ErrorCode.INVALID_DIALOGUE,\n            error_msg=\"Invalid dialogue.\",\n            error_data={\"http_message\": http_msg.encode()},\n        )\n        self.context.outbox.put_message(message=default_msg)\n\n    def _handle_request(\n        self, http_msg: HttpMessage, http_dialogue: HttpDialogue\n    ) -> None:\n        \"\"\"\n        Handle a Http request.\n\n        :param http_msg: the http message\n        :param http_dialogue: the http dialogue\n        \"\"\"\n        self.context.logger.info(\n            \"received http request with method={}, url={} and body={!r}\".format(\n                http_msg.method,\n                http_msg.url,\n                http_msg.body,\n            )\n        )\n        if http_msg.method == \"get\":\n            self._handle_get(http_msg, http_dialogue)\n        elif http_msg.method == \"post\":\n            self._handle_post(http_msg, http_dialogue)\n\n    def _handle_get(self, http_msg: HttpMessage, http_dialogue: HttpDialogue) -> None:\n        \"\"\"\n        Handle a Http request of verb GET.\n\n        :param http_msg: the http message\n        :param http_dialogue: the http dialogue\n        \"\"\"\n        http_response = http_dialogue.reply(\n            performative=HttpMessage.Performative.RESPONSE,\n            target_message=http_msg,\n            version=http_msg.version,\n            status_code=200,\n            status_text=\"Success\",\n            headers=http_msg.headers,\n            body=json.dumps({\"tom\": {\"type\": \"cat\", \"age\": 10}}).encode(\"utf-8\"),\n        )\n        self.context.logger.info(\"responding with: {}\".format(http_response))\n        self.context.outbox.put_message(message=http_response)\n\n    def _handle_post(self, http_msg: HttpMessage, http_dialogue: HttpDialogue) -> None:\n        \"\"\"\n        Handle a Http request of verb POST.\n\n        :param http_msg: the http message\n        :param http_dialogue: the http dialogue\n        \"\"\"\n        http_response = http_dialogue.reply(\n            performative=HttpMessage.Performative.RESPONSE,\n            target_message=http_msg,\n            version=http_msg.version,\n            status_code=200,\n            status_text=\"Success\",\n            headers=http_msg.headers,\n            body=http_msg.body,\n        )\n        self.context.logger.info(\"responding with: {}\".format(http_response))\n        self.context.outbox.put_message(message=http_response)\n\n    def _handle_invalid(\n        self, http_msg: HttpMessage, http_dialogue: HttpDialogue\n    ) -> None:\n        \"\"\"\n        Handle an invalid http message.\n\n        :param http_msg: the http message\n        :param http_dialogue: the http dialogue\n        \"\"\"\n        self.context.logger.warning(\n            \"cannot handle http message of performative={} in dialogue={}.\".format(\n                http_msg.performative, http_dialogue\n            )\n        )\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n```\n\nMoreover, add a `dialogues.py` file with the following code:\n\n``` python\nfrom typing import Any\n\nfrom aea.protocols.base import Address, Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\nfrom aea.skills.base import Model\n\nfrom packages.fetchai.protocols.default.dialogues import (\n    DefaultDialogue as BaseDefaultDialogue,\n)\nfrom packages.fetchai.protocols.default.dialogues import (\n    DefaultDialogues as BaseDefaultDialogues,\n)\nfrom packages.fetchai.protocols.http.dialogues import HttpDialogue as BaseHttpDialogue\nfrom packages.fetchai.protocols.http.dialogues import HttpDialogues as BaseHttpDialogues\n\n\nDefaultDialogue = BaseDefaultDialogue\n\n\nclass DefaultDialogues(Model, BaseDefaultDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return DefaultDialogue.Role.AGENT\n\n        BaseDefaultDialogues.__init__(\n            self,\n            self_address=self.context.agent_address,\n            role_from_first_message=role_from_first_message,\n        )\n\n\nHttpDialogue = BaseHttpDialogue\n\n\nclass HttpDialogues(Model, BaseHttpDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return BaseHttpDialogue.Role.SERVER\n\n        BaseHttpDialogues.__init__(\n            self,\n            self_address=str(self.skill_id),\n            role_from_first_message=role_from_first_message,\n        )\n```\n\nThen, update the `skill.yaml` accordingly:\n\n``` yaml\nhandlers:\n  http_handler:\n    args: {}\n    class_name: HttpHandler\nmodels:\n  default_dialogues:\n    args: {}\n    class_name: DefaultDialogues\n  http_dialogues:\n    args: {}\n    class_name: HttpDialogues\n```\n\nRun the fingerprinter (note, you will have to replace the author name with your author handle):\n\n``` bash\naea fingerprint skill fetchai/http_echo:0.21.6\n```\n\nMoreover, we need to tell to the `http_server` connection to what skill\nthe HTTP requests should be forwarded.\nIn our case, this is the `http_echo` that you have just scaffolded.\nIts public id will be `<your-author-name>/http_echo:0.1.0`.\n\n``` bash\naea config set vendor.fetchai.connections.http_server.config.target_skill_id \"$(aea config get agent.author)/http_echo:0.1.0\" \n```\n\nYou can now run the AEA:\n\n``` bash\naea run\n```\n\nIn a separate terminal, you can create a client and communicate with the server:\n\n``` python\nimport requests\n\nresponse = requests.get('http://127.0.0.1:8000')\nresponse.status_code\n# >>> 404\n# we receive a not found since the path is not available in the api spec\n\nresponse = requests.get('http://127.0.0.1:8000/pets')\nresponse.status_code\n# >>> 200\nresponse.content\n# >>> b'{\"tom\": {\"type\": \"cat\", \"age\": 10}}'\n\nresponse = requests.post('http://127.0.0.1:8000/pets')\nresponse.status_code\n# >>> 200\nresponse.content\n# >>> b''\n```\n"
  },
  {
    "path": "docs/identity.md",
    "content": "# Identity\n\n!!! note\n    This section is incomplete and will soon be updated.\n\nThe AEAs currently use the addresses associated with their private-public key pairs to identify themselves.\n\n<img src=\"../assets/keys.jpg\" alt=\"Keys of an AEA\" class=\"center\" style=\"display: block; margin-left: auto; margin-right: auto;width:80%;\">\n\nTo learn how to generate a private-public key pair check out the relevant <a href=\"../cli-commands\"> CLI commands </a>.\n\nTo learn more about public-key cryptography check out <a href=\"https://simple.wikipedia.org/wiki/Public-key_cryptography\" target=\"_blank\">Wikipedia</a>.\n\nAn AEA can provide evidence of its identity using third-party solutions. We have implemented a demo using <a href=\"https://github.com/hyperledger/aries-cloudagent-python\" target=\"_blank\">Aries Hyperledger Cloud Agent</a> which is available <a href=\"../aries-cloud-agent-demo\">here</a> and another demo using <a href=\"https://developers.yoti.com/yoti\" target=\"_blank\">Yoti</a> which is available <a href=\"https://github.com/fetchai/agents-yoti\" target=\"_blank\">here</a>.\n"
  },
  {
    "path": "docs/index.md",
    "content": "# AEA Framework Documentation\n\n!!! target \"Vision\"\n    Our aim with the AEA framework is to enable businesses of all sizes, from independent developers to large corporations and consortiums, to create and deploy agent-based solutions in various domains, thus contributing to and advancing a decentralized mixed-initiative economy: one whose actors are both humans and machines.\n\n## What is an AEA?\n\n!!! info \"Definition\"\n    An Autonomous Economic Agent (AEA) is an intelligent agent that acts on its owner's behalf, with limited or no interference, and whose goal is to generate economic value for its owner.\n\nBreaking it down:\n\n**AGENT**: An AEA represents an individual, organisation or object and looks after their interests.\n\n**AUTONOMOUS**: AEAs operate independently of constant input from their owners and act autonomously to achieve their goals.\n\n**ECONOMIC**: AEAs have a narrow and specific focus: creating economic value for their owner.\n\n## What Can You Do with AEAs?\n\n[//]: # (AEAs have the potential of being the next \"apps\", by enabling p2p. Most importantly,   )\n\nSome examples of the kinds of applications you can build with AEAs:\n\n**Automation**\n\n:   AEAs can automate well-defined processes in different domains, such as supply chain, mobility, finance, ...\n\n**Micro-transactions**\n\n:   AEAs make it economically viable to execute trade involving small values. An example is use-cases with many small sellers (e.g. of data) on the supply side.\n\n**Wallet**\n\n:   AEAs can simplify interactions with blockchains. By acting as \"smart wallets\", they can hide away the majority of the complexities involved in using blockchains for end users.\n\n**IoT**\n\n:   Agents representing objects in the IoT (Internet of Things) space. For example, AEAs paired with hardware devices such as drones, laptops, heat sensors, etc., providing control and receiving data from the device. An example is a <a href=\"thermometer-skills\">thermometer agent</a>.\n\n**Web 2.0 <--> Web 3.0 interface**\n\n:   Agents that interface and bridge the gap between existing (Web 2.0) and new (Web 3.0) economic models. An example is an <a href=\"http-connection-and-skill\"> AEA that communicates with HTTP clients/servers</a>.\n\n**Traders**\n\n:   Agents with access to some data sources that sell the data, access to the data, or access to the usage of the data. An example is an <a href=\"ml-skills\">AEA that continuously sells data to another AEA</a>, who in turn uses it to improve their reinforcement learning model.\n\n## Who is This For?\n\nThe AEA technology is for anyone who wants to build or contribute to a \"mixed-initiative economy\": one whose actors are humans as well as machines. \n\nThis includes (amongst others): developers, data scientists and machine learning experts, economists, students, academics and researchers (in Artificial Intelligence, Machine Learning, Multi-Agent Systems, etc), engineers, and so forth.\n\n## The AEA Framework\n\nThe AEA framework is a development suite which equips you with an efficient and accessible set of tools for building and running AEAs and their components. \n\nThe framework attempts to make agent development as straightforward an experience as possible, similar to what popular web frameworks enable for web development.\n\nSome of the characteristics of the AEA framework are:\n\n- **Python**: Using Python as an approachable programming language improves the on-boarding for those who just want to get started with agent development.\n- **Open source**: The framework is open source and licensed under <a href=\"https://github.com/fetchai/agents-aea/blob/main/LICENSE\" target=\"_blank\">Apache 2.0</a>.\n- **Modular**: Modularity is at the heart of the framework's design. This makes it easy to extend the framework, add new functionality, and re-use others' contributions, therefore reducing the development cost.\n- **Blockchain ready**: Integration with blockchains is baked into the framework, enabling the creation of agents that take full advantage of the blockchain technology.\n- **Modern**: The framework is built from and can be integrated with the latest technologies (e.g. asynchronous programming, blockchains and smart contracts, machine-learning ready, ...).\n\n## The Ecosystem\n\nThough they can work in isolation, AEAs are truly valuable when situated in a wider ecosystem consisting of tools and infrastructure that enable them to cooperate and compete, and interact with services as well as traditional or modern systems. These include:\n\n- The <a href=\"acn\">Agent Communication Network (ACN)</a>: A peer-to-peer communication infrastructure that enables AEAs to directly communicate with one another without any intermediaries.\n- The <a href=\"simple-oef\">sOEF</a>: A search and discovery system allowing AEAs to register themselves and the services they offer, and search for agents who offer specific services.\n- The <a href=\"https://aea-registry.fetch.ai/\" target=\"_blank\">AEA Registry</a>: A space to store and share AEAs or individual agent components for anyone to find and use.\n- Blockchains: AEAs can use blockchains as a financial and commitment layer. Each <a href=\"ledger-integration\">ledger plug-in</a> provided by the framework adds the ability for AEAs to interact with a specific ledger, such as the <a href=\"https://docs.fetch.ai/ledger_v2/\" target=\"_blank\">Fetch.ai blockchain</a> or <a href=\"https://ethereum.org/en/\" target=\"_blank\">Ethereum</a>.\n- Smart Contracts: <a href=\"contract\">Contract packages</a> are wrappers around smart contracts that allow AEAs to interact with them through a common interface.\n\n## How to get involved?\n\nThere are many ways for you to get involved. You can create agents, develop new agent components, extend existing components, and contribute to the development of the framework or other related tools. Please refer to the <a href=\"https://github.com/fetchai/agents-aea/blob/main/CONTRIBUTING.md\" target=\"_blank\">Contribution</a> and <a href=\"https://github.com/fetchai/agents-aea/blob/main/DEVELOPING.md\" target=\"_blank\">Development</a> guides.\n\n## Next Steps\n\nTo get started developing your own AEA, check out the <a href=\"quickstart\">getting started</a> section.\n\nTo learn more about some of the distinctive characteristics of agent-oriented development, check out the guide on <a href=\"agent-oriented-development\">agent-oriented development</a>.\n\nIf you would like to develop an AEA in a language different to Python then check out our <a href=\"language-agnostic-definition\">language agnostic AEA definition</a>.\n\nIf you want to run a demo, check out the <a href=\"demos\">demo guides</a>.\n\n## Help us Improve\n\n!!! note\n    This developer documentation is a work in progress. If you spot any errors please open an issue on <a href=\"https://github.com/fetchai/agents-aea\" target=\"_blank\">Github</a> or contact us in the <a href=\"https://discord.com/invite/btedfjPJTj\" target=\"_blank\">developer Discord channel</a>.\n"
  },
  {
    "path": "docs/install.md",
    "content": "# Installation\n\n!!! Info \"Platforms\"\n    The AEA framework can be used on `Windows`, `Ubuntu/Debian` and `MacOS`.\n\n## System Requirements\n\n1. You need <a href=\"https://www.python.org/downloads/\" target=\"_blank\">Python 3.8, 3.9 or 3.10</a> on your system.\n2. GCC installation is also required:\n \n    === \"Ubuntu\"\n        ``` bash\n        apt-get install gcc\n        ```\n    === \"MacOS X (with <a href=\"https://brew.sh\" target=\"_blank\">Homebrew</a>)\"\n        ``` bash\n        brew install gcc\n        ```\n    === \"Windows (with <a href=\"https://chocolatey.org/\" target=\"_blank\">choco</a>)\"\n        ``` bash\n        choco install mingw\n        ```\n\n??? tip \"Tips\"\n\n    - **Ubuntu/Debian**: install Python headers, depending on the Python version you have installed on your machine. For example for Python 3.8: \n\n        ``` bash\n        sudo apt-get install python3.8-dev\n        ```\n\n    - **Windows**: install <a href=\"https://visualstudio.microsoft.com/downloads/#build-tools-for-visual-studio-2019\" target=\"_blank\">tools for Visual Studio</a>.\n\n### Alternatively: Use Docker\n\nWe also provide a Docker image with all the needed dependencies.\n\n1. Pull the image:\n\n    ``` bash\n    docker pull fetchai/aea-user:latest\n    ```\n\n2. Run the image with your current local directory mounted as a docker volume. This allows you to keep your agents local while working on them from within the docker container:\n\n    === \"Linux and MacOs\"\n        ``` bash\n        docker run -it -v $(pwd):/agents --workdir=/agents fetchai/aea-user:latest\n        ```\n    === \"Windows\"\n        ``` powershell\n        docker run -it -v %cd%:/agents --workdir=/agents fetchai/aea-user:latest\n        ```\n\nOnce successfully logged into the docker container, you can follow the rest of the guide the same way as if not using docker.\n\n## For Agent Development\n\n### Preliminaries\n\n1. Create a new working directory. Let's call it `my_aea_projects`. This is where you will create your agent projects.\n\n2. Inside `my_aea_projects`, add an empty directory called `packages`. This is a local registry for your agents' components.\n\nYou should now have the following directory structure:\n\n```bash\nmy_aea_projects\n└── packages\n```\n\n!!! tip \"Alternatively, clone a template repo:\"\n    Instead of the above, you can clone the template repo as described in `Approach 1` in the <a href=\"../development-setup#approach-1\">development setup</a> guide.\n\n#### Virtual Environment\n\nUnless you are using the docker image, we highly recommend using a virtual environment so that your setup is isolated from the rest of your system. This prevents clashes and ensures consistency across dependencies.\n\nYou can use any common virtual environment manager for Python, such as <a href=\"https://pypi.org/project/pipenv/\" target=\"_blank\">`pipenv`</a> and <a href=\"https://python-poetry.org/docs/#installation\" target=\"_blank\">`poetry`</a>. If you do not have either, install one.\n\nOnce installed, create a new virtual environment in the `my_aea_projects` directory and enter it:\n\n=== \"pipenv\"\n    Use any <a href=\"../install/#system-requirements\">Python version supported</a> in the command:\n    ``` bash\n    pipenv --python 3.9 && pipenv shell\n    ```\n=== \"poetry\"\n    ``` bash\n    poetry init -n && poetry shell\n    ```\n\n### Installation\n\nThe latest version of the Python implementation of the AEA Framework is:\n\n<a href=\"https://pypi.org/project/aea/\" target=\"_blank\"> \n    <img alt=\"PyPI\" src=\"https://img.shields.io/pypi/v/aea\"> \n</a>\n\n!!! info \"Note\"\n    If you are upgrading your AEA project from a previous version of the AEA framework, make sure you check out <a href=\"../upgrading/\">the upgrading notes</a>.\n\n#### Using pip\n\nInstall the AEA framework using pip:\n\n=== \"bash/windows\"\n    ``` bash\n    pip install aea[all]\n    ```\n=== \"zsh\"\n    ``` zsh\n    pip install 'aea[all]'\n    ```\n\n??? tip \"Troubleshooting\"\n    To ensure no cache is used, add `--force --no-cache-dir` to the installation command.\n\n#### Using pipx\n\nInstall the AEA framework using pipx:\n\n``` bash\npipx install aea[all]\n```\n\n## For Contributing to the AEA Framework\n\nTo contribute to the development of the framework or related tools (e.g. ACN), please refer to the <a href=\"https://github.com/fetchai/agents-aea/blob/main/CONTRIBUTING.md\" target=\"_blank\">Contribution</a> and <a href=\"https://github.com/fetchai/agents-aea/blob/main/DEVELOPING.md\" target=\"_blank\">Development</a> guides in our GitHub repository.\n\n## Other Tools You Might Need\n\nDepending on what you want to do, you might need extra tools on your system:\n\n- To use the Agent Communication Network (ACN) for peer-to-peer communication between agents (e.g. using the `fetchai/p2p_libp2p` connection) you will need <a href=\"https://go.dev/doc/install\" target=\"_blank\"> Golang 1.14.2 or higher</a>.\n- The framework uses <a href=\"https://protobuf.dev\" target=\"_blank\">Google Protocol Buffers</a> for message serialization. If you want to develop protocols, install the protobuf compiler on your system. The version you install must match the `protobuf` library installed with the project (see <a href=\"https://github.com/fetchai/agents-aea/blob/main/pyproject.toml\" target=\"_blank\">pyproject.toml</a>).\n- To update fingerprint hashes of packages, you will need the <a href=\"https://docs.ipfs.tech/install/\" target=\"_blank\">IPFS daemon</a>.\n"
  },
  {
    "path": "docs/interaction-protocol.md",
    "content": "# How AEAs Talk to Each Other - Interaction Protocols\n\nAlthough one can imagine scenarios where single AEAs pursue their goals in isolation without interacting with other AEAs, there is no doubt that by working together, AEAs have the potential of achieving much more, especially when taking into account agents' heterogeneity, specialisations, and differing and often complimentary local views of the environment.\n\nInteractions in the AEA world are in the form of communication. This is influenced by established practices in the field of multi-agent systems and the prominent speech-act theory which suggests that a communicative expression is not only about transferring information from the speaker to the hearer, but that there may be meanings and commitments beyond the statement's appearance. Therefore, speech may more suitably be considered as action. For example, \"I hereby appoint you as chairman\" is not just a sequence of words, but an action done by the speaker with wide-ranging consequences for the hearer and any other audience to that sentence.\n\n<a href=\"https://en.wikipedia.org/wiki/Interaction_protocol\" target=\"_blank\">Interaction protocols</a> are thus possible communication scenarios between agents or agent components (specifically, skills and connections).\n\nThere are multiple types of interactions an AEA can have:\n\n- AEA-to-AEA interactions. You can find some examples in the <a href=\"../demos\">demo section</a>.\n\n- Interactions between an AEA's internal components.\n\n<img src=\"../assets/interaction-protocols.jpg\" alt=\"Interaction protocols\" class=\"center\" style=\"display: block; margin-left: auto; margin-right: auto;width:80%;\">\n\nUsually, an interaction involves three types of framework packages: <a href=\"../skill\">skills</a>, <a href=\"../protocol\">protocols</a> and <a href=\"../connection\">connections</a>.\n\n## Examples\n\n### Example 1: Negotiation\n\nThe <a href=\"../generic-skills\">generic buyer/seller skills</a> use the `fetchai/fipa` protocol which defines the negotiation dialogue between two AEAs. The `fetchai/generic_buyer` and `fetchai/generic_seller` skills implement specific strategies for engaging in such negotiations, by providing the logic for producing negotiation messages to be sent, handling negotiation messages received. The `fetchai/p2p_libp2p` connection is then used for connecting to the <a href=\"../acn\">agent communication network</a> enabling two AEAs with these skills to deliver negotiation messages to each other.\n\n### Example 2: AEA <> Web Client\n\nIn the <a href=\"../http-connection-and-skill\">http connection guide</a> we demonstrate how an AEA with a http server connection (e.g. `fetchai/http_server`) receives http payloads from web clients, translates them to messages conforming with the `fetchai/http` protocol and passes it to a skill (e.g. `fetchai/http_echo`) to process. The `fetchai/http` protocol in this case is used for communication between the connection and the skill.\n\n### Example 3 : AEA <> 3rd Party Server\n\nThe `fetchai/http_client` connection can be used to make requests to third party servers. In this case, a skill containing the logic for the production of http requests would create messages conforming with the `fetchai/http` protocol and sends it to the `fetchai/http_client` connection which in turn translates it into http payload and sends it to the destination server.\n\nNote that in general, third party SDKs can be wrapped in a connection and shared with other developers as a package. Often this also involves creating a custom protocol to enforce the type of interactions permitted between skills and the connection wrapping the SDK.\n\n## Next Steps\n\n### Recommended\n\nWe recommend you continue with the next step in the 'Getting Started' series:\n\n- <a href=\"../generic-skills-step-by-step/\">Trade between two AEAs</a>\n\n### Relevant Deep-Dives\n\nMost AEA development focuses on developing the `Skills` and `Protocols` necessary for an AEA to deliver against its economic objectives and implement interaction protocols.\n\nUnderstanding `Protocols` is core to developing your own agent. You can learn more about the `Protocols` agents use to communicate with each other and how they are created in the following section:\n\n- <a href=\"../protocol\">Protocols</a>\n\nMost of an AEA developer's time is spent on `Skill` development. `Skills` are the core business logic components of an AEA. Check out the following guide to learn more:\n\n- <a href=\"../skill\">Skills</a>\n\nIn most cases, one of the available `Connection` packages can be used. Occasionally, you might develop your own `Connection`:\n\n- <a href=\"../connection\">Connections</a>\n"
  },
  {
    "path": "docs/known-limits.md",
    "content": "# Known Limitations\n\nThe AEA framework makes a multitude of tradeoffs.\n\nHere we present an incomplete list of known limitations:\n\n- The <a href=\"../api/aea_builder#aeabuilder-objects\">`AEABuilder`</a> checks the consistency of packages at the `add` stage. However, it does not currently check the consistency again at the `load` stage. This means, if a package is tampered with after it is added to the `AEABuilder` then these inconsistencies might not be detected by the `AEABuilder`.\n\n- The <a href=\"../api/aea_builder#aeabuilder-objects\">`AEABuilder`</a> assumes that packages with public ids of identical author and package name have a matching version. As a result, if a developer uses a package with matching author and package name but different version in the public id, then the `AEABuilder` will not detect this and simply use the last loaded package.\n\n- The order in which `setup` and `teardown` are called on the skills, and `act` is called on the behaviours, is not guaranteed. Skills should be designed to work independently. Where skills use the `shared_context` to exchange information they must do so safely.\n"
  },
  {
    "path": "docs/language-agnostic-definition.md",
    "content": "# Language Agnostic Definition\n\nCurrently, there is an implementation of the AEA framework in Python which enables the development of AEAs in Python, and allows AEAs which are built with it to run.\n\nHowever, AEAs can be developed in different programming languages. This is further backed by the idea that agent-based solutions are suited for multi-stakeholder environments where the different AEAs may be developed independently of one another, resulting in heterogeneous systems.\n\nThis means that in principle, there could be different implementations of the AEA framework, in various programming languages and for different platforms. However, to ensure that AEAs under any implementation are compatible with one another and able to interact, they must satisfy specific definitions. In this page, we compile a set of definitions which any AEA independent of its implementation must satisfy in order to be able to interact with other AEAs.\n\nAn AEA, in technical terms, must satisfy the following requirements:\n\n- It MUST be capable of receiving and sending `Envelopes` which satisfy the following <a href=\"https://developers.google.com/protocol-buffers\" target=\"_blank\">protobuf</a> schema:\n\n    ``` proto\n    syntax = \"proto3\";\n    \n    package aea.base.v0_1_0;\n    \n    message Envelope{\n      string to = 1;\n      string sender = 2;\n      string protocol_id = 3;\n      bytes message = 4;\n      string uri = 5;\n    }\n    ```\n\n    The format for the above fields are as follows:\n\n    - `to` and `sender`: an address derived from the private key of a <a href=\"https://en.bitcoin.it/wiki/Secp256k1\" target=\"_blank\">secp256k1</a>-compatible elliptic curve\n    - `protocol_id`: this must match a defined  <a href=\"https://learn.microsoft.com/en-us/dotnet/standard/base-types/regular-expression-language-quick-reference\" target=\"_blank\">regular expression</a> (see below)\n    - `message`: a bytes string representing a serialized message in the specified  <a href=\"../protocol\">protocol</a>\n    - `URI`: follows <a href=\"https://datatracker.ietf.org/doc/html/rfc3986\" target=\"_blank\">this syntax</a>\n\n- It MUST implement each protocol's `message` with the required meta-fields:\n\n    ``` proto\n    syntax = \"proto3\";\n    \n    package aea.base.v0_1_0;\n    \n    import \"google/protobuf/struct.proto\";\n    \n    \n    message DialogueMessage {\n      int32 message_id = 1;\n      string dialogue_starter_reference = 2;\n      string dialogue_responder_reference = 3;\n      int32 target = 4;\n      bytes content = 5;\n    }\n    \n    message Message {\n      oneof message {\n        google.protobuf.Struct body = 1;\n        DialogueMessage dialogue_message = 2;\n      }\n    }\n    \n    message Envelope{\n      string to = 1;\n      string sender = 2;\n      string protocol_id = 3;\n      bytes message = 4;\n      string uri = 5;\n    }\n    ```\n\n     where `content` is replaced with the protocol specific content (see <a href=\"../protocol-generator\">here</a> for details).\n\n- It MUST implement protocols according to their specification (see <a href=\"../protocol-generator/#full-mode-vs-protobuf-only-mode\">here</a> for details).\n\n- It SHOULD implement the `fetchai/default:1.1.7` protocol which satisfies the following protobuf schema:\n\n    ``` proto\n    syntax = \"proto3\";\n    \n    package aea.fetchai.default.v1_0_0;\n    \n    message DefaultMessage{\n    \n      // Custom Types\n      message ErrorCode{\n        enum ErrorCodeEnum {\n          UNSUPPORTED_PROTOCOL = 0;\n          DECODING_ERROR = 1;\n          INVALID_MESSAGE = 2;\n          UNSUPPORTED_SKILL = 3;\n          INVALID_DIALOGUE = 4;\n        }\n        ErrorCodeEnum error_code = 1;\n      }\n    \n    \n      // Performatives and contents\n      message Bytes_Performative{\n        bytes content = 1;\n      }\n    \n      message Error_Performative{\n        ErrorCode error_code = 1;\n        string error_msg = 2;\n        map<string, bytes> error_data = 3;\n      }\n    \n      message End_Performative{\n      }\n    \n    \n      oneof performative{\n        Bytes_Performative bytes = 5;\n        End_Performative end = 6;\n        Error_Performative error = 7;\n      }\n    }\n    ```\n\n- The protocol id MUST match the following regular expression: `^([a-zA-Z_][a-zA-Z0-9_]{0,127})/([a-zA-Z_][a-zA-Z0-9_]{0,127})(:((any|latest|((0|[1-9]\\d*))\\.((0|[1-9]\\d*))\\.((0|[1-9]\\d*))(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?)))?$`\n- It is recommended that it processes `Envelopes` asynchronously. Note, the specification regarding the processing of messages does not impose any particular implementation, and the AEA can be designed to process envelopes either synchronously and asynchronously. However, asynchronous message handling enables the agent to be more responsive and scalable in maintaining many concurrent dialogues with its peers.\n- It MUST have an identity in the form of, at a minimum, an address derived from a public key and its associated private key (where the elliptic curve must be of type <a href=\"https://en.bitcoin.it/wiki/Secp256k1\" target=\"_blank\">SECP256k1</a>).\n- It SHOULD implement handling of errors using the `fetchai/default:1.1.7` protocol. The protobuf schema is given above.\n- It MUST implement the following principles when handling messages:\n    - It MUST ALWAYS handle incoming envelopes/messages and NEVER raise an exception when decoding and validating the message. This ensures another AEA cannot cause the agent to fail by sending a malicious envelope/message.\n    - It MUST NEVER handle outgoing messages and ALWAYS raise an exception when validating the message. An exception implies that the handler is resolving a bug in the implementation.\n\n!!! note\n    Additional constraints will be added soon!\n"
  },
  {
    "path": "docs/ledger-integration.md",
    "content": "# Ledger & Crypto APIs\n\nIn this section, we show you how to integrate the AEA with the Fetch.ai and third-party ledgers.\n\n## Ledger Support\n\nFor a ledger to be considered _supported_ in the framework, three abstract base classes need to be implemented:\n\n- the <a href=\"../api/crypto/base#aea.crypto.base.LedgerApi\">`LedgerApi`</a> class wraps the API to talk to the ledger and its helper methods\n- the <a href=\"../api/crypto/base#aea.crypto.base.Crypto\">`Crypto`</a> class wraps the API to perform cryptographic operations for the relevant ledger\n- the <a href=\"../api/crypto/base#aea.crypto.base.FaucetApi\">`FaucetApi`</a> class wraps the API to talk to a faucet on a testnet\n\nThese three classes have their own registries, which allow the developer to import the relevant object where needed.\n\n## Ledger Plug-in Architecture\n\nThe AEA framework provides a plug-in mechanism to support ledger functionalities in\nan easily extendable way. At import time, the framework will load\nall the crypto plug-ins available in the current Python environment.\n\nA _crypto plug-in_ is a Python package which declares some specific\n<a href=\"https://setuptools.pypa.io/en/latest/pkg_resources.html#entry-points\" target=\"_blank\">\n`setuptools` \"entry points\"</a> in its `setup.py` script.\nIn particular, there are three types of entry points the framework looks up:\n\n- `aea.ledger_apis`, which points to instantiable classes implementing the `LedgerApi` interface;\n- `aea.cryptos`, which points to instantiable classes implementing the `Crypto` interface;\n- `aea.faucet_apis`, which points to instantiable classes implementing the `FaucetApi` interface.\n\nThis is an example of `setup.py` script for a ledger plug-in `aea-ledger-myledger`:\n\n``` python\n# sample ./setup.py file\nfrom setuptools import setup\n\nsetup(\n    name=\"aea-ledger-myledger\",\n    packages=[\"aea_ledger_myledger\"],\n    # plugins must depend on 'aea'  \n    install_requires=[\"aea\"], # add other dependencies...\n    # the following makes a plugin available to aea\n    entry_points={\n        \"aea.cryptos\": [\"myledger = aea_ledger_myledger:MyLedgerCrypto\"],\n        \"aea.ledger_apis\": [\"myledger = aea_ledger_myledger:MyLedgerApi\"],\n        \"aea.faucet_apis\": [\"myledger = aea_ledger_myledger:MyLedgerFaucetApi\"],\n    },\n    # PyPI classifier for AEA plugins\n    classifiers=[\"Framework :: AEA\"],\n)\n```\n\nBy convention, such plug-in packages should be named `aea-ledger-${LEDGER_ID}`,\nand the importable package name `aea_ledger_${LEDGER_ID}`.\nIn the example above, the package name is `aea-ledger-myledger`,\nand the importable package name is `aea_ledger_myledger`.\n\nYou can search for AEA ledger plug-ins on PyPI:\n<a href=\"https://pypi.org/search/?q=aea-ledger\" target=\"_blank\">https://pypi.org/search/?q=aea-ledger</a>\n\n## Maintained Plug-ins\n\nAt the moment, the framework natively supports the following three ledgers:\n\n- Fetch.ai: <a href=\"https://pypi.org/project/aea-ledger-fetchai/\" target=\"_blank\">PyPI package: `aea-ledger-fetchai`</a>, and <a href=\"https://github.com/fetchai/agents-aea/tree/main/plugins/aea-ledger-fetchai\" target=\"_blank\">source code</a>.\n- Ethereum: <a href=\"https://pypi.org/project/aea-ledger-ethereum/\" target=\"_blank\">PyPI package: `aea-ledger-ethereum`</a>, and <a href=\"https://github.com/fetchai/agents-aea/tree/main/plugins/aea-ledger-ethereum\" target=\"_blank\">source code</a>.\n- Cosmos: <a href=\"https://pypi.org/project/aea-ledger-cosmos/\" target=\"_blank\">PyPI package: `aea-ledger-cosmos`</a>, and <a href=\"https://github.com/fetchai/agents-aea/tree/main/plugins/aea-ledger-cosmos\" target=\"_blank\">source code</a>.\n\nHowever, support for additional ledgers can be added to the framework at runtime.\n\n## Examples\n\n- Examples of how to interact with the crypto registry:\n\n``` python\nfrom aea.crypto.registries import crypto_registry, make_crypto, register_crypto\n\n# by default we can use the native cryptos\nfetchai_crypto = make_crypto(\"fetchai\")\n\n# we can check what cryptos are registered\ncrypto_registry.supported_ids\n\n# we can also add a new crypto to the registry\nregister_crypto(id_=\"my_ledger_id\", entry_point=\"some.dotted.path:MyLedgerCrypto\")\n\n# and then make it anywhere\nmy_ledger_crypto = make_crypto(\"my_ledger_id\")\n```\n\n- Examples of how to interact with the ledger API registry:\n\n``` python\nfrom aea.crypto.registries import ledger_apis_registry, make_ledger_api, register_ledger_api\n\n# by default we can use the native ledger apis\nCONFIG = {\"network\": \"testnet\"}\nfetchai_ledger_api = make_ledger_api(\"fetchai\", **CONFIG)\n\n# we can check what ledger apis are registered\nledger_apis_registry.supported_ids\n\n# we can also add a new ledger api to the registry\nregister_ledger_api(id_=\"my_ledger_id\", entry_point=\"some.dotted.path:MyLedgerApi\")\n\n# and then make it anywhere\nmy_ledger_api = make_ledger_api(\"my_ledger_id\")\n```\n\n- Examples of how to interact with the faucet API registry:\n\n``` python\nfrom aea.crypto.registries import faucet_apis_registry, make_faucet_api, register_faucet_api\n\n# by default we can use the native faucet apis\nCONFIG = dict(poll_interval=1.0)\nfetchai_faucet_api = make_faucet_api(\"fetchai\", **CONFIG)\n\n# we can check what faucet apis are registered\nfaucet_apis_registry.supported_ids\n\n# we can also add a new faucet api to the registry\nregister_faucet_api(id_=\"my_ledger_id\", entry_point=\"some.dotted.path:MyLedgerFaucetApi\")\n\n# and then make it anywhere\nmy_faucet_api = make_faucet_api(\"my_ledger_id\")\n```\n\nThe framework wraps all `LedgerApi` classes and exposes them in the <a href=\"../api/crypto/ledger_apis#aea.crypto.base.LedgerApis\">`LedgerApis`</a> classes. The framework also wraps the crypto APIs to create identities on both ledgers and exposes them in the `Wallet`.\n\nThe separation between the `Crypto` and `LedgerApi` is fundamental to the framework design. In particular, the object which holds the private key is separated from the object which interacts with the ledger. This design pattern is repeated throughout the framework: the decision maker is the only entity with access to the AEA's `Wallet` whilst `LedgerApis` are accessible by all skills.\n\n## Stargate World - Fetch.ai Testnet for Agents\n\nStargate World is our stable, public testnet for the Fetch Ledger v2. As such, most developers will be interacting with this testnet. This is specifically designed and supported for AEA development.\n\n| Parameter      | Value                                                                                         |\n|----------------|-----------------------------------------------------------------------------------------------|\n| Chain ID       | dorado-1                                                                                      |\n| Denomination   | atestfet                                                                                      |\n| Decimals       | 18                                                                                            |\n| Version        | v0.8.x                                                                                        |\n| RPC Endpoint   | <https://rpc-dorado.fetch.ai:443>                                                             |\n| REST Endpoint  | <https://rest-dorado.fetch.ai:443>                                                            |\n| Block Explorer | <a href=\"https://explore-dorado.fetch.ai\" target=\"_blank\">https://explore-dorado.fetch.ai</a> |\n| Token Faucet   | Use block explorer                                                                            |\n\nYou can access more details on <a href=\"https://docs.fetch.ai/ledger_v2/networks/\" target=\"_blank\">docs section</a>.\n\nThe configurations can be specified for the `fetchai/ledger:0.21.5` connection.\n\n## CosmWasm Supporting Chains\n\nThe Fetch.ai networks use <a href=\"https://docs.cosmwasm.com\" target=\"_blank\">CosmWasm</a> for smart contract support.\n"
  },
  {
    "path": "docs/limits.md",
    "content": "# Limitations of v1\n\nThis document describes some of the limitations of `v1` of the AEA framework and tradeoffs made in its design.\n\n## Rejected Ideas\n\n### Handlers Implemented as Behaviours\n\nHandlers can be considered a special cases of a \"behaviour that listens for specific events to happen\".\n\nOne could implement `Handler` classes in terms of `Behaviours`, after having implemented the feature that behaviours can be activated after an event happens (e.g. receiving a message of a certain protocol).\n\nThis was rejected in favour of a clear separation of concerns, and to avoid purely reactive (handlers) and proactive (behaviours) components to be conflated into one concept. The proposal would also add complexity to behaviour development.\n\n### Multiple Versions of the Same Package\n\nThe framework does not allow for the usage of multiple versions of the same package in a given project.\n\nAlthough one could re-engineer the project to allow for this, it does introduce significant additional complexities. Furthermore, Python modules are by design only allowed to exist as one version in a given process. Hence, it seems sensible to maintain this approach in the AEA.\n\n## Potential Extensions, Considered yet not Decided\n\n### Alternative Skill Design\n\nFor very simple skills, the splitting of skills into `Behaviour`, `Handler`, `Model` and `Task` classes can add unnecessary complexity to the framework and a counter-intuitive responsibility split. The splitting also implies the framework needs to introduce the `SkillContext` object to allow for access to data across the skill. Furthermore, the framework requires implementing all functionality in `SkillComponent` classes `Handler`, `Behaviour` or `Model`. This approach is consistent and transparent, however it creates a lot of boilerplate code for simple skills.\n\nHence, for some use cases it would be useful to have a single `Skill` class with abstract methods `setup`, `act`, `handle` and `teardown`. Then the developer can decide how to split up their code.\n\n``` python\nclass SkillTemplate(SimpleSkill):\n\n    protocol_ids: Optional[List[PublicId]] = None\n\n    def setup():\n        # setup skill\n\n    def handle(message: Message):\n        # handle messages\n\n    def act():\n        for b in behaviours:\n            b.act()\n    \n    def teardown():\n        # teardown skill\n```\n\nAlternatively, we could use decorators to let a developer define whether a function is part of a handler or behaviour. That way, a single file with a number of functions could implement a skill. (Behind the scenes this would utilise a number of virtual `Behaviour` and `Handler` classes provided by the framework).\n\nThe downside of this approach is that it does not advocate for much modularity on the skill level. Part of the role of a framework is to propose a common way to do things. The above approach can cause for a larger degree of heterogeneity in the skill design which makes it harder for developers to understand each other's code.\n\nThe separation between all four base classes does exist both in convention *and* at the code level. Handlers deal with skill-external events (messages), behaviours deal with scheduled events (ticks), models represent data and tasks are used to manage long-running business logic.\n\nBy adopting strong convention around skill development we allow for the framework to take a more active role in providing guarantees. E.g. handlers' and behaviours' execution can be limited to avoid them being blocking, models can be persisted and recreated, tasks can be executed with different task backends. The opinionated approach is thought to allow for better scaling.\n\n### Further Modularity for Skill Level Code\n\nCurrently, we have three levels of modularity:\n\n- PyPI packages\n- framework packages: protocols, contracts, connections and skills\n- framework plugins: CLI, ledger\n\nWe could consider having a fourth level: common behaviours, handlers, models exposed as modules which can then speed up skill development.\n\n### \"promise\" Pattern\n\nGiven the asynchronous nature of the framework, it is often hard to implement reactions to specific messages, without making a \"fat\" handler. Take the example of a handler for a certain type of message `A` for a certain protocol `p`. The handler for protocol `p` would look something like this:\n\n``` python\nclass PHandler:\n...\ndef handle(msg):\n    if message type is A:\n        self._handle_a(msg)\n```\n\nHowever, it could be helpful to overwrite this handler reaction with another callback (e.g. consider <a href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise\" target=\"_blank\">this in context</a>):\n\n``` python\n# callable that handles the reply\ndef my_callback(msg):\n    # handle reply\n\nself.context.outbox.put_message(message, handler_func=my_callback, failure_func=...)\n```\n\nThis feature would introduce additional complexity for the framework to correctly wire up the callbacks and messages with the dialogues.\n\n### CLI using Standard Lib\n\nRemoving the click dependency from the CLI would further reduce the dependencies in the AEA framework which is overall desirable.\n\n### Metadata vs Configurations\n\nThe current approach uses `yaml` files to specify both metadata and component configuration. It would be desirable to introduce the following separation:\n\n- package metadata\n- package default developer configuration\n- package default user configuration\n\nA user can only configure a subset of the configuration. The developer should be able to define these constraints for the user. Similarly, a developer cannot modify all fields in a package, some of them are determined by the framework.\n\n### Configuring Agent Goal Setup\n\nBy default, the agent's goals are implicitly defined by its skills and the configurations thereof. This is because the default decision maker signs every message and transaction presented to it.\n\nIt is already possible to design a custom decision maker. However, more work needs to be done to understand how to improve the usability and configuration of the decision maker. In this context different types of decision makers can be implemented for the developer/user.\n\n### Connection Status Monitoring\n\nCurrently, connections are responsible for managing their own status after they have been \"connected\" by the `Multiplexer`. Developers writing connections must take care to properly set its connection status at all times and manage any disconnection. It would potentially be desirable to offer different policies to deal with connection problems on the multiplexer level:\n\n- disconnect one, keep others alive\n- disconnect all\n- try to reconnect indefinitely\n\n### Agent Snapshots on Teardown or Error\n\nCurrently, the developer must implement snapshots on the component level. It would be desirable if the framework offered more help to persist the agent state on teardown or error.\n\n### Dialogues Management\n\nThe current implementation of Dialogues is verbose. Developers often need to subclass `Dialogues` and `Dialogue` classes. More effort can be made to simplify and streamline dialogues management.\n\n### Instantiate Multiple Instances of the Same Class of `SkillComponent`\n\nCurrently, configuration and metadata of a package are conflated making it not straightforward to run one package component with multiple sets of configuration. It could be desirable to configure an agent to run a given package with multiple different configurations.\n\nThis feature could be problematic with respect to component-to-component messaging which currently relies on component ids, which are bound to the package and not its instance.\n\n### Containerized Agents\n\nAgent management, especially when many of them live on the same host, can be cumbersome. The framework should provide more utilities for these large-scale use cases. But a proper isolation of the agent environment is something that helps also simple use cases.\n\nA new software architecture, somehow inspired to the Docker system. The CLI only involves the initialization of the building of the agent (think of it as the specification of the `Dockerfile`: the `Agentfile`), but the actual build and run are done by the AEA engine, a daemon process analogous of the Docker Engine, which exposes APIs for these operations.\n\nUsers and developers would potentially like to run many AEAs of different versions and with differences in the versions of their dependencies. It is not possible to import different versions of the same Python (PyPI) package in the same process in a clean way. However, in different processes this is trivial with virtual environments. It would be desirable to consider this in the context of a container solution for agents.\n\n### Dependency Light Version of the AEA Framework\n\nThe `v1` of the Python AEA implementation makes every effort to minimise the amount of third-party dependencies. However, some dependencies remain to lower development time.\n\nIt would be desirable to further reduce the dependencies, and potentially have an implementation that only relies on the Python standard library.\n\nThis could be taken further, and a reduced spec version for <a href=\"https://micropython.org\" target=\"_blank\">micropython</a> could be designed.\n\n### Compiled AEA\n\nPython is not a compiled language. However, various projects attempt this, e.g. <a href=\"https://nuitka.net/doc/user-manual.html\" target=\"_blank\">Nuitka</a> and it would be desirable to explore how useful and practical this would be in the context of AEA.\n\n### DID Integration\n\nIt would be great to integrate <a href=\"https://www.w3.org/TR/did-core/\" target=\"_blank\">DID</a> in the framework design, specifically identification of packages (most urgently protocols). Other projects and standards worth reviewing in the context (in particular with respect to identity):\n\n- <a href=\"https://erc725alliance.org\" target=\"_blank\">ERC 725: Ethereum Identity Standard</a> and <a href=\"https://erc725alliance.org\" target=\"_blank\">here</a>.\n- <a href=\"https://github.com/ethereum/eips/issues/735\" target=\"_blank\">ERC 735: Claim Holder</a>\n\n### Optimise Protocol Schemas and Messages\n\nThe focus of protocol development was on extensibility and compatibility, not on optimisation. For instance, the dialogue references use inefficient string representations.\n\n### Constraints on Primitive Types in Protocols\n\nThe protocol generator currently does not support custom constraints. The framework could add support for custom constraints for the protocol generator and specification.\n\nThere are many types of constraints that could be supported in specification and generator. One could perhaps add support based on the popularity of specific constraints from users/developers.\n\nExample constraints:\n\n- strings following specific regular expression format (e.g. all lower case, any arbitrary regex format)\n- max number of elements on lists/sets\n- keys in one `dict` type be equal to keys in another `dict` type\n- other logical constraints, e.g. as supported in ontological languages\n- support for bounds (i.e. min, max) for numerical types (i.e. `int` and `float`) in protocol specification.\n\nExample syntax:\n\n- `pt:int[0, ]`\n- `pt:float[1.0, 10.0]`\n- `pt:int[-1000, 1000]`\n- `pt:float[, 0]`\n\nThis would automatically enable support for signed/unsigned `int` and `float`. This syntax would allow for unbounded positive/negative/both, or arbitrary bounds to be placed on numerical types.\n\nCurrently, the developer has to specify a custom type to implement any constraints on primitive types.\n\n### Sub-protocols & Multi-Party Interactions\n\nProtocols can be allowed to depend on each other. Similarly, protocols might have multiple parties.\n\nFurthermore, a turn-taking function that specifies who's turn it is at any given point in the dialogue could be added.\n\nThen the current `fipa` setup is a specific case of turn-taking where the turn shifts after a player sends a single move (unique-reply). But generally, it does not have to be like this. Players could be allowed to send multiple messages until the turn shifts, or until they send specific speech-acts (multiple-replies).\n\n### Timeouts in Protocols\n\nProtocols currently do not implement the concept of timeouts. We leave it to the skill developer to implement any time-specific protocol rules.\n\n### Framework Internal Messages\n\nThe activation/deactivation of skills and addition/removal of components is implemented in a \"passive\" way - the skill posts a request in its skill context queue (in the case of new behaviours), or it just sets a flag (in case of activation/deactivation of skills).\n\nOne could consider that a skill can send requests to the framework, via the internal protocol, to modify its resources or its status. The `DecisionMaker` or the `Filter` can be the components that take such actions.\n\nThis is a further small but meaningful step toward an actor-based model for agent internals.\n\n### Ledger Transaction Management\n\nCurrently, the framework does not manage any aspect of submitting multiple transactions to the ledgers. This responsibility is left to skills. Additionally, the ledger APIs/contract APIs take the ledger as a reference to determine the nonce for a transaction. If a new transaction is sent before a previous transaction has been processed then the nonce will not be incremented correctly for the second transaction. This can lead to submissions of multiple transactions with the same nonce, and therefore failure of subsequent transactions.\n\nA naive approach would involve manually incrementing the nonce and then submitting transactions into the pool with the correct nonce for eventual inclusion. The problem with this approach is that any failure of a transaction will cause none of the subsequent transactions to be processed for some ledgers (<https://ethereum.stackexchange.com/questions/2808/what-happens-when-a-transaction-nonce-is-too-high>). To recover from a transaction failure not only the failed transaction would need to be handled, but potentially also all subsequent transactions. It is easy to see that logic required to recover from a transaction failure early in a sequence can be arbitrarily complex (involving potentially new negotiations between agents, new signatures having to be generated etc.).\n\nA further problem with the naive approach is that it (imperfectly) replicates the ledger state (with respect to (subset of state of) a specific account).\n\nA simple solution looks as follows: each time a transaction is constructed (requiring a new nonce) the transaction construction is queued until all previous transactions have been included in the ledger or failed. This way, at any one time the agent has only at most one transaction pending with the ledger. Benefits: simple to understand and maintain, transaction only enter the mempool when they are ready for inclusion which has privacy benefits over submitting a whole sequence of transaction at once. Downside: at most one transaction per block.\n\nThis approach is currently used and implemented across all the reference skills.\n\nRelated, the topic of latency in transactions. State channels provide a solution. E.g. <a href=\"https://github.com/perun-network/go-perun\" target=\"_blank\">Perun</a>. There could also be an interesting overlap with our protocols here.\n\n### Unsolved Problems in `Multiplexer` - `AgentLoop` Interplay\n\nProblem 1: connection generates too many messages in a short amount of time, that are not consumed by the multiplexer\nSolution: Can be solved by slowing down connections receive method called, controlled by the inbox messages amount\nSide effects: Most of the connections should have an internal queue because there is no synchronization between internal logic and multiplexer connection `receive` calls.\n\nProblem 2: the send method can take a long time (because send retries logic in connection)\nSolution: Currently, we apply timeouts on send. Other solutions could be considered, like parallelization.\n\nProblem 3: too many messages are produced by a skill.\nSolution: Raise an exception on outbox is full or slow down agent loop?\n\n## ACN\n\n### Agent Mobility on ACN\n\nIf a peer-client or full client switches peer, then the DHT is not updated properly at the moment under certain conditions.\n\n### Mailbox Connection\n\nThe two available connections `p2p_libp2p` and `p2p_libp2p_client` imply that the agent is continuously connected and therefore must have uninterrupted network access and the resources to maintain a connection.\n\nFor more lightweight implementations, a mailbox connection is desirable, as outlined in the ACN documentation.\n"
  },
  {
    "path": "docs/logging.md",
    "content": "# Logging\n\nThe AEA framework supports flexible logging capabilities with the standard <a href=\"https://docs.python.org/3/library/logging.html\" target=\"_blank\">Python logging library</a>.\n\nIn this tutorial, we configure logging for an AEA.\n\nFirst, create your AEA.\n\n``` bash\naea create my_aea\ncd my_aea\n```\n\nThe `aea-config.yaml` file should look like this.\n\n``` yaml\nagent_name: my_aea\nauthor: fetchai\nversion: 0.1.0\ndescription: ''\nlicense: Apache-2.0\naea_version: 0.6.0\nfingerprint: {}\nfingerprint_ignore_patterns: []\nconnections:\n- fetchai/stub:0.21.3\ncontracts: []\nprotocols:\n- fetchai/default:1.1.7\nskills:\n- fetchai/error:0.18.6\ndefault_connection: fetchai/stub:0.21.3\ndefault_ledger: fetchai\nrequired_ledgers:\n- fetchai\nlogging_config:\n  disable_existing_loggers: false\n  version: 1\nprivate_key_paths: {}\n```\n\nBy updating the `logging_config` section, you can configure the loggers of your application.\n\nThe format of this section is specified in the <a href=\"https://docs.python.org/3/library/logging.config.html\" target=\"_blank\">`logging.config`</a> module.\n\nAt <a href=\"https://docs.python.org/3/library/logging.config.html#configuration-dictionary-schema\" target=\"_blank\">this section</a>\nyou'll find the definition of the configuration dictionary schema.\n\nBelow is an example of the `logging_config` value.\n\n``` yaml\nlogging_config:\n  version: 1\n  disable_existing_loggers: False\n  formatters:\n    standard:\n      format: '%(asctime)s [%(levelname)s] %(name)s: %(message)s'\n  handlers:\n    logfile:\n      class: logging.FileHandler\n      formatter: standard\n      level: DEBUG\n      filename: logconfig.log\n    console:\n      class: logging.StreamHandler\n      formatter: standard\n      level: DEBUG\n  loggers:\n    aea:\n      handlers:\n      - logfile\n      - console\n      level: DEBUG\n      propagate: False\n```\n\nThis configuration will set up a logger with name `aea`. It prints both on console and on file with a format specified by the `standard` formatter.\n\n## Streaming to Browser\n\nIt is possible to configure the AEA to stream logs to a browser.\n\nFirst, add the following configuration to your AEA:\n\n``` yaml\nlogging_config:\n  version: 1\n  disable_existing_loggers: false\n  formatters:\n    standard:\n      format: '%(asctime)s [%(levelname)s] %(name)s: %(message)s'\n  handlers:\n    http:\n      class: logging.handlers.HTTPHandler\n      formatter: standard\n      level: INFO\n      host: localhost:5000\n      url: /stream\n      method: POST\n  loggers:\n    aea:\n      handlers:\n      - http\n      level: INFO\n      propagate: false\n```\n\nSecond, create a log server:\n\n``` python\n# -*- coding: utf-8 -*-\n\"\"\"A simple flask server to serve logs.\"\"\"\n\nimport datetime\nimport itertools\nimport queue\n\nfrom flask import Flask, Response, request, stream_with_context\n\n\ndef format_log(log_dict):\n    \"\"\"Format a log record.\"\"\"\n    date = datetime.datetime.fromtimestamp(float(log_dict[\"created\"]))\n    formatted_log = f\"[{date.isoformat()}] [{log_dict['levelname']}] {log_dict['name']}: {log_dict['msg']}\"\n    return formatted_log\n\n\ndef create_app():\n    \"\"\"Create Flask app for streaming logs.\"\"\"\n    all_logs = []\n    unread_logs = queue.Queue()\n    app = Flask(__name__)\n\n    @app.route(\"/\")\n    def index():\n        \"\"\"Stream logs to client.\"\"\"\n        def generate():\n            # stream old logs\n            div = \"<div>{}</div>\"\n            for old_row in all_logs:\n                yield div.format(old_row)\n\n            # stream unread logs\n            while True:\n                row = unread_logs.get()\n                all_logs.append(row)\n                yield f\"<div>{row}</div>\"\n\n        rows = generate()\n        title = \"<p>Waiting for logs...</p>\"\n        return Response(stream_with_context(itertools.chain([title], rows)))\n\n    @app.route(\"/stream\", methods=[\"POST\"])\n    def stream():\n        \"\"\"Save log record from AEA.\"\"\"\n        log_record_formatted = format_log(dict(request.form))\n        unread_logs.put(log_record_formatted)\n        return {}, 200\n\n    app.run()\n\n\nif __name__ == \"__main__\":\n    create_app()\n```\n\nSave the script in a file called `server.py`, install flask with `pip install flask` and run the server with `python server.py`.\n\nThird, run your AEA and visit `localhost:5000` in your browser.\n"
  },
  {
    "path": "docs/message-routing.md",
    "content": "# Message Routing\n\nMessage routing can be split up into the routing of incoming and outgoing `Messages`.\n\nIt is important to keep in mind that <a href=\"../interaction-protocol\">interaction protocols</a> can be maintained between agents (agent to agent) and between components of the AEA (component to component). In the former case, the `to`/`sender` fields of the `Envelope` are agent addresses which must follow the address standard of agents, in the latter case they are component public ids. Crucially, both addresses must reference the same type: agent or component.\n\n## Incoming `Messages`\n\n- `Connections` receive or create `Envelopes` which they deposit in the `InBox`\n- for agent-to-agent communication only, the `Multiplexer` keeps track of the `connection_id` via which the `Envelope` was received.\n- the `AgentLoop` picks `Envelopes` off the `InBox`\n- the `AEA` tries to decode the message; errors are handled by the `ErrorHandler`\n- `Messages` are dispatched based on two rules:\n\n    1. checks if `to` field can be interpreted as `skill_id`, if so uses that together with the `protocol_id` to dispatch to the protocol's `Handler` in the specified `Skill`, else\n    2. uses the `protocol_id` to dispatch to the protocol's `Handler` in all skills supporting the protocol.\n\n!!! note\n    For agent-to-agent communication it is advisable to have a single skill implement a given protocol. Skills can then forward the messages via skill-to-skill communication to other skills where required. Otherwise, received agent-to-agent messages will be forwarded to all skills implementing a handler for the specified protocol and the developer needs to take care to handle them appropriately (e.g. avoid multiple replies to a single message).\n\n## Outgoing `Messages`\n\n- `Skills` deposit `Messages` in `OutBox`\n- `OutBox` constructs an `Envelope` from the `Message`\n- `Multiplexer` assigns messages to relevant `Connection` based on the following rules:\n\n    1. Component to component messages are routed by their `component_id`\n    2. Agent to agent messages are routed following four rules:\n        1. checks if `EnvelopeContext` exists and specifies a `Connection`, if so uses that else\n        2. checks which connection handled the last message from `sender`, if present uses that else\n        3. checks if default routing is specified for the `protocol_id` referenced in the `Envelope`, if so uses that else\n        4. sends to default `Connection`.\n\n- `Connections` can process `Envelopes` directly or encode them for transport to another agent.\n\n## Usage of the `EnvelopeContext`\n\nThe `EnvelopeContext` is used to maintain agent-to-agent communication only and is managed almost entirely by the framework. The developer can set the `EnvelopeContext` explicitly for the first message in a dialogue to achieve targeted routing to connections (see 2. for outgoing messages). This is relevant when the same agent can be reached via multiple connections.\n\nThe `EnvelopeContext` is not sent to another agent.\n"
  },
  {
    "path": "docs/ml-skills.md",
    "content": "# ML Skills\n\nThe AEA ML (machine learning) skills demonstrate an interaction between two AEAs, one purchasing data from the other and training a machine learning model with it.\n\nThere are two types of AEAs:\n\n- The `ml_data_provider` which sells training data.\n- The `ml_model_trainer` which purchases data and trains a model\n\n## Discussion\n\nThis demo aims to demonstrate the integration of a simple AEA with machine learning using the AEA framework. The `ml_data_provider` AEA provides some sample data and delivers to the client upon payment.\nOnce the client receives the data, it trains a model. This process can be found in `tasks.py`.\nThis demo does not utilize a smart contract. As a result, the ledger interaction is only for completing a transaction.\n\nSince the AEA framework enables using third-party libraries from PyPI, we can directly reference any external dependencies.\nThe `aea install` command installs all dependencies an AEA needs that is listed in one of its skills' YAML file.\n\n## Communication\n\nThis diagram shows the communication between the two AEAs.\n\n``` mermaid\n    sequenceDiagram\n        participant ml_model_trainer\n        participant ml_data_provider\n        participant Search\n        participant Ledger\n    \n        activate ml_model_trainer\n        activate ml_data_provider\n        activate Search\n        activate Ledger\n        \n        ml_data_provider->>Search: register_service\n        ml_model_trainer->>Search: search\n        Search-->>ml_model_trainer: list_of_agents\n        ml_model_trainer->>ml_data_provider: call_for_terms\n        ml_data_provider->>ml_model_trainer: terms\n        ml_model_trainer->>Ledger: request_transaction\n        ml_model_trainer->>ml_data_provider: accept (incl transaction_hash)\n        ml_data_provider->>Ledger: check_transaction_status\n        ml_data_provider->>ml_model_trainer: data\n        loop train\n            ml_model_trainer->>ml_model_trainer: tran_model\n        end\n        \n        deactivate ml_model_trainer\n        deactivate ml_data_provider\n        deactivate Search\n        deactivate Ledger\n```\n\n## Option 1: AEA Manager Approach\n\nFollow this approach when using the AEA Manager Desktop app. Otherwise, skip and follow the CLI approach below.\n\n### Preparation Instructions\n\n- Install the <a href=\"https://aea-manager.fetch.ai\" target=\"_blank\">AEA Manager</a>.\n- Install <a href=\"https://www.tensorflow.org/install/\" target=\"_blank\">Tensorflow</a>\n\n### Demo Instructions\n\nThe following steps assume you have launched the AEA Manager Desktop app.\n\n1. Add a new AEA called `ml_data_provider` with public id `fetchai/ml_data_provider:0.28.0`.\n\n2. Add another new AEA called `ml_model_trainer` with public id `fetchai/ml_model_trainer:0.29.0`.\n\n3. Copy the address from the `ml_model_trainer` into your clip board. Then go to the <a href=\"https://explore-dorado.fetch.ai\" target=\"_blank\">Dorado block explorer</a> and request some test tokens via `Get Funds`.\n\n4. Run the `ml_data_provider` AEA. Navigate to its logs and copy the multiaddress displayed.\n\n5. Navigate to the settings of the `ml_model_trainer` and under `components > connection >` `fetchai/p2p_libp2p:0.22.0` update as follows (make sure to replace the placeholder with the multiaddress):\n\n    ``` bash\n    {\n      \"delegate_uri\": \"127.0.0.1:11001\",\n      \"entry_peers\": [\"REPLACE_WITH_MULTI_ADDRESS_HERE\"],\n      \"local_uri\": \"127.0.0.1:9001\",\n      \"log_file\": \"libp2p_node.log\",\n      \"public_uri\": \"127.0.0.1:9001\"\n    }\n    ```\n\n6. Run the `ml_model_trainer`.\n\nIn the AEA's logs, you should see the agents trading successfully, and the training agent training its machine learning model using the data purchased.\nThe trainer keeps purchasing data and training its model until stopped.  \n\n## Option 2: CLI Approach\n\nFollow this approach when using the `aea` CLI.\n\n### Preparation Instructions\n\n#### Dependencies\n\n- Follow the <a href=\"../quickstart/#preliminaries\">Preliminaries</a> and <a href=\"../quickstart/#installation\">Installation</a> sections from the AEA quick start.\n- Install <a href=\"https://www.tensorflow.org/install/\" target=\"_blank\">Tensorflow</a>\n\n### Demo Instructions\n\n#### Create Data Provider AEA\n\nFirst, fetch the data provider AEA:\n\n``` bash\naea fetch fetchai/ml_data_provider:0.32.5\ncd ml_data_provider\naea install\naea build\n```\n\n??? note \"Alternatively, create from scratch:\"\n    The following steps create the data provider from scratch:\n\n    ``` bash\n    aea create ml_data_provider\n    cd ml_data_provider\n    aea add connection fetchai/p2p_libp2p:0.27.5\n    aea add connection fetchai/soef:0.27.6\n    aea add connection fetchai/ledger:0.21.5\n    aea add skill fetchai/ml_data_provider:0.27.6\n    aea config set --type dict agent.dependencies \\\n    '{\n      \"aea-ledger-fetchai\": {\"version\": \"<2.0.0,>=1.0.0\"}\n    }'\n    aea config set agent.default_connection fetchai/p2p_libp2p:0.27.5\n    aea config set --type dict agent.default_routing \\\n    '{\n      \"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n      \"fetchai/oef_search:1.1.7\": \"fetchai/soef:0.27.6\"\n    }'\n    aea install\n    aea build\n    ```\n\n#### Create Model Trainer AEA\n\nThen, fetch the model trainer AEA:\n\n``` bash\naea fetch fetchai/ml_model_trainer:0.33.5\ncd ml_model_trainer\naea install\naea build\n```\n\n??? note \"Alternatively, create from scratch:\"\n    The following steps create the model trainer from scratch:\n\n    ``` bash\n    aea create ml_model_trainer\n    cd ml_model_trainer\n    aea add connection fetchai/p2p_libp2p:0.27.5\n    aea add connection fetchai/soef:0.27.6\n    aea add connection fetchai/ledger:0.21.5\n    aea add skill fetchai/ml_train:0.29.6\n    aea config set --type dict agent.dependencies \\\n    '{\n      \"aea-ledger-fetchai\": {\"version\": \"<2.0.0,>=1.0.0\"}\n    }'\n    aea config set agent.default_connection fetchai/p2p_libp2p:0.27.5\n    aea config set --type dict agent.default_routing \\\n    '{\n      \"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n      \"fetchai/oef_search:1.1.7\": \"fetchai/soef:0.27.6\"\n    }'\n    aea install\n    aea build\n    ```\n\n#### Add Keys for the Data Provider AEA\n\nFirst, create the private key for the data provider AEA based on the network you want to transact. To generate and add a private-public key pair for Fetch.ai `Dorado` use:\n\n``` bash\naea generate-key fetchai\naea add-key fetchai fetchai_private_key.txt\n```\n\nNext, create a private key used to secure the AEA's communications:\n\n``` bash\naea generate-key fetchai fetchai_connection_private_key.txt\naea add-key fetchai fetchai_connection_private_key.txt --connection\n```\n\nFinally, certify the key for use by the connections that request that:\n\n``` bash\naea issue-certificates\n```\n\n#### Add Keys and Generate Wealth for the Model Trainer AEA\n\nThe model trainer needs to have some wealth to purchase the data from the data provider.\n\nFirst, create the private key for the model trainer AEA based on the network you want to transact. To generate and add a private-public key pair for Fetch.ai `Dorado` use:\n\n``` bash\naea generate-key fetchai\naea add-key fetchai fetchai_private_key.txt\n```\n\nThen, create some wealth for your model trainer based on the network you want to transact with. On the Fetch.ai `Dorado` network:\n\n``` bash\naea generate-wealth fetchai\n```\n\nNext, create a private key used to secure the AEA's communications:\n\n``` bash\naea generate-key fetchai fetchai_connection_private_key.txt\naea add-key fetchai fetchai_connection_private_key.txt --connection\n```\n\nFinally, certify the key for use by the connections that request that:\n\n``` bash\naea issue-certificates\n```\n\n#### Run both AEAs\n\nRun both AEAs from their respective terminals.\n\nFirst, run the data provider AEA:\n\n``` bash\naea run\n```\n\nOnce you see a message of the form `To join its network use multiaddr 'SOME_ADDRESS'` take note of the address. (Alternatively, use `aea get-multiaddress fetchai -c -i fetchai/p2p_libp2p:0.27.5 -u public_uri` to retrieve the address.)\nThis is the entry peer address for the local <a href=\"../acn\">agent communication network</a> created by the ML data provider.\n\nThen, in the ML model trainer, run this command (replace `SOME_ADDRESS` with the correct value as described above):\n\n``` bash\naea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \\\n'{\n  \"delegate_uri\": \"127.0.0.1:11001\",\n  \"entry_peers\": [\"SOME_ADDRESS\"],\n  \"local_uri\": \"127.0.0.1:9001\",\n  \"log_file\": \"libp2p_node.log\",\n  \"public_uri\": \"127.0.0.1:9001\"\n}'\n```\n\nThis allows the model trainer to connect to the same local agent communication network as the data provider.\n\nThen run the model trainer AEA:\n\n``` bash\naea run\n```\n\nYou can see that the AEAs find each other, negotiate and eventually trade. After the trade, the model trainer AEA trains its ML model using the data it has purchased.\nThis AEA keeps purchasing data and training its model until stopped.\n\n#### Cleaning up\n\nWhen you're finished, delete your AEAs:\n\n``` bash\ncd ..\naea delete ml_data_provider\naea delete ml_model_trainer\n```\n"
  },
  {
    "path": "docs/modes.md",
    "content": "# Modes of Running an AEA\n\nWe can run an AEA in multiple modes thanks to the configurable design of the framework.\n\nThe AEA contains two runnable parts, the `AgentLoop`, which operates the skills, and the Multiplexer, which operates the connections. The `AgentLoop` can be configured to run in `async` or `sync` mode. The `Multiplexer` by default runs in `async` mode. The AEA itself, can be configured to run in `async` mode, if both the `Multiplexer` and `AgentLoop` have the same mode, or in `threaded` mode. The latter ensures that `AgentLoop` and `Multiplexer` are run in separate threads.\n"
  },
  {
    "path": "docs/multi-agent-manager.md",
    "content": "# Multi Agent Manager\n\nThe <a href=\"../api/manager/manager\">`MultiAgentManager`</a> allows managing multiple agent projects programmatically.\n\n## Setup\n\nWe instantiate the manager by providing it with the working directory in which to operate and starting it:\n\n``` python\nimport os\nfrom pathlib import Path\nfrom aea.manager import MultiAgentManager\n\nWORKING_DIR = \"mam\"\n\nmanager = MultiAgentManager(WORKING_DIR)\nmanager.start_manager()\n```\n\n## Adding Projects\n\nWe first add a couple of finished AEA project:\n\n``` python\nfrom aea.configurations.base import PublicId\n\nweather_station_id = PublicId.from_str(\"fetchai/weather_station:0.32.5\")\nweather_client_id = PublicId.from_str(\"fetchai/weather_client:0.33.5\")\nmanager.add_project(weather_station_id)\nmanager.add_project(weather_client_id)\nweather_station_name = weather_station_id.name\nweather_client_name = weather_client_id.name\n```\n\n## Adding Agent Instances\n\nAdd the agent instances\n\n``` python\nagent_overrides = {\n    \"private_key_paths\": {\"fetchai\": \"fetchai_private_key.txt\"},\n    \"connection_private_key_paths\": {\"fetchai\": \"fetchai_connection_private_key.txt\"}\n}\n\np2p_public_id = PublicId.from_str(\"fetchai/p2p_libp2p:0.27.5\")\nsoef_public_id = PublicId.from_str(\"fetchai/soef:0.27.6\")\n\ncomponent_overrides = [{\n    **p2p_public_id.json,\n    \"type\": \"connection\",\n    \"cert_requests\": [{\n      \"identifier\": \"acn\",\n      \"ledger_id\": \"fetchai\",\n      \"not_after\": '2022-01-01',\n      \"not_before\": '2021-01-01',\n      \"public_key\": \"fetchai\",\n      \"message_format\": \"{public_key}\",\n      \"save_path\": \"conn_cert.txt\"\n    }]\n}, {\n    **soef_public_id.json,\n    \"type\": \"connection\",\n    \"config\": {\n        \"token_storage_path\": \"soef_token.txt\"\n    }\n}]\nmanager.add_agent(weather_station_id, component_overrides=component_overrides, agent_overrides=agent_overrides)\n\nagent_overrides = {\n    \"private_key_paths\": {\"fetchai\": \"fetchai_private_key.txt\"},\n    \"connection_private_key_paths\": {\"fetchai\": \"fetchai_connection_private_key.txt\"}\n}\ncomponent_overrides = [{\n    **p2p_public_id.json,\n    \"type\": \"connection\",\n    \"config\": {\n        \"delegate_uri\": \"127.0.0.1:11001\",\n        \"entry_peers\": ['/dns4/127.0.0.1/tcp/9000/p2p/16Uiu2HAkzgZYyk25XjAhmgXcdMbahrHYi18uuAzHuxPn1KkdmLRw'],\n        \"local_uri\": \"127.0.0.1:9001\",\n        \"public_uri\": \"127.0.0.1:9001\",\n    },\n    \"cert_requests\": [{\n      \"identifier\": \"acn\",\n      \"ledger_id\": \"fetchai\",\n      \"not_after\": '2022-01-01',\n      \"not_before\": '2021-01-01',\n      \"public_key\": \"fetchai\",\n      \"message_format\": \"{public_key}\",\n      \"save_path\": \"conn_cert.txt\"\n    }]\n}, {\n    **soef_public_id.json,\n    \"type\": \"connection\",\n    \"config\": {\n        \"token_storage_path\": \"soef_token.txt\"\n    }\n}]\n\nmanager.add_agent(weather_client_id, component_overrides=component_overrides, agent_overrides=agent_overrides)\n```\n\nSave the following private keys in the respective files.\n\n``` python\nFET_PRIVATE_KEY_STATION = b\"72d3149f5689f0749eaec5ebf6dba5deeb1e89b93ae1c58c71fd43dfaa231e87\"\nFET_PRIVATE_KEY_PATH_STATION = Path(manager.data_dir, weather_station_name, \"fetchai_private_key.txt\").absolute()\nFET_PRIVATE_KEY_PATH_STATION.write_bytes(FET_PRIVATE_KEY_STATION)\n\nFET_CONNECTION_PRIVATE_KEY_STATION = b\"bf529acb2546e13615ef6004c48e393f0638a5dc0c4979631a9a4bc554079f6f\"\nFET_CONNECTION_PRIVATE_KEY_PATH_STATION = Path(manager.data_dir, weather_station_name, \"fetchai_connection_private_key.txt\").absolute()\nFET_CONNECTION_PRIVATE_KEY_PATH_STATION.write_bytes(FET_CONNECTION_PRIVATE_KEY_STATION)\n\nFET_PRIVATE_KEY_CLIENT = b\"589839ae54b71b8754a7fe96b52045364077c28705a1806b74441debcae16e0a\"\nFET_PRIVATE_KEY_PATH_CLIENT = Path(manager.data_dir, weather_client_name, \"fetchai_private_key.txt\").absolute()\nFET_PRIVATE_KEY_PATH_CLIENT.write_bytes(FET_PRIVATE_KEY_CLIENT)\n\nFET_CONNECTION_PRIVATE_KEY_CLIENT = b\"c9b38eff57f678f5ab5304447997351edb08eceb883267fa4ad849074bec07e4\"\nFET_CONNECTION_PRIVATE_KEY_PATH_CLIENT = Path(manager.data_dir, weather_client_name, \"fetchai_connection_private_key.txt\").absolute()\nFET_CONNECTION_PRIVATE_KEY_PATH_CLIENT.write_bytes(FET_CONNECTION_PRIVATE_KEY_CLIENT)\n```\n\n## Running the Agents\n\n``` python\nimport time\n\nmanager.start_agent(weather_station_id.name)\n\n# wait for ~10 seconds for peer node to go live\ntime.sleep(10.0)\n\nmanager.start_agent(weather_client_id.name)\n\ntime.sleep(5.0)\n```\n\n## Stopping the Agents\n\n``` python\nmanager.stop_all_agents()\n```\n\n## Cleaning up\n\n``` python\nmanager.stop_manager()\n```\n\n## Limitations\n\nThe `MultiAgentManager` can only be used with compatible package versions, in particular the same package (with respect to author and name) cannot be used in different versions. If you want to run multiple agents with differing versions of the same package then use the `aea launch` command in the multi-processing mode, or simply launch each agent individually with `aea run`.\n"
  },
  {
    "path": "docs/multiplexer-standalone.md",
    "content": "# Use Multiplexer Stand-Alone\n\nThe `Multiplexer` can be used stand-alone. This way a developer can utilise the protocols and connections independent of the `Agent` or `AEA` classes.\n\nFirst, import the Python and application specific libraries and set the static variables. (Get the `packages` directory from the AEA repository `svn export https://github.com/fetchai/agents-aea.git/trunk/packages`.)\n\n``` python\nimport os\nimport time\nfrom copy import copy\nfrom threading import Thread\nfrom typing import Optional\n\nfrom aea.configurations.base import ConnectionConfig\nfrom aea.helpers.file_io import write_with_lock\nfrom aea.identity.base import Identity\nfrom aea.mail.base import Envelope\nfrom aea.multiplexer import Multiplexer\n\nfrom packages.fetchai.connections.stub.connection import StubConnection\nfrom packages.fetchai.protocols.default.message import DefaultMessage\n\n\nINPUT_FILE = \"input.txt\"\nOUTPUT_FILE = \"output.txt\"\n```\n\n## Instantiate a `Multiplexer`\n\nA `Multiplexer` only needs a list of connections. The `StubConnection` is a simple connection which reads from and writes to file.\n\n``` python\n    # Ensure the input and output files do not exist initially\n    if os.path.isfile(INPUT_FILE):\n        os.remove(INPUT_FILE)\n    if os.path.isfile(OUTPUT_FILE):\n        os.remove(OUTPUT_FILE)\n\n    # create the connection and multiplexer objects\n    configuration = ConnectionConfig(\n        input_file=INPUT_FILE,\n        output_file=OUTPUT_FILE,\n        connection_id=StubConnection.connection_id,\n    )\n    stub_connection = StubConnection(\n        configuration=configuration,\n        data_dir=\".\",\n        identity=Identity(\"some_agent\", \"some_address\", \"some_public_key\"),\n    )\n    multiplexer = Multiplexer([stub_connection], protocols=[DefaultMessage])\n```\n\n## Start the `Multiplexer`\n\nWe can run a multiplexer by calling, `connect()` which starts the 'receive' and 'send' loops. We run the multiplexer from a different thread so that we can still use the main thread to pass it messages.\n\n``` python\n    try:\n        # Set the multiplexer running in a different thread\n        t = Thread(target=multiplexer.connect)\n        t.start()\n\n        # Wait for everything to start up\n        for _ in range(20):\n            if multiplexer.is_connected:\n                break\n            time.sleep(1)\n        else:\n            raise Exception(\"Not connected\")\n```\n\n## Send and Receive an Envelope\n\nWe use the input and output text files to send an envelope to our agent and receive a response\n\n``` python\n        # Create a message inside an envelope and get the stub connection to pass it into the multiplexer\n        message_text = (\n            \"multiplexer,some_agent,fetchai/default:1.0.0,\\x08\\x01*\\x07\\n\\x05hello,\"\n        )\n        with open(INPUT_FILE, \"w\") as f:\n            write_with_lock(f, message_text)\n\n        # Wait for the envelope to get processed\n        for _ in range(20):\n            if not multiplexer.in_queue.empty():\n                break\n            time.sleep(1)\n        else:\n            raise Exception(\"No message!\")\n\n        # get the envelope\n        envelope = multiplexer.get()  # type: Optional[Envelope]\n        assert envelope is not None\n\n        # Inspect its contents\n        print(\n            \"Envelope received by Multiplexer: sender={}, to={}, protocol_specification_id={}, message={}\".format(\n                envelope.sender,\n                envelope.to,\n                envelope.protocol_specification_id,\n                envelope.message,\n            )\n        )\n\n        # Create a mirrored response envelope\n        response_envelope = copy(envelope)\n        response_envelope.to = envelope.sender\n        response_envelope.sender = envelope.to\n\n        # Send the envelope back\n        multiplexer.put(response_envelope)\n\n        # Read the output envelope generated by the multiplexer\n        with open(OUTPUT_FILE, \"r\") as f:\n            print(\"Envelope received from Multiplexer: \" + f.readline())\n```\n\n## Shutdown\n\nFinally, stop our multiplexer and wait for it to finish\n\n``` python\n    finally:\n        # Shut down the multiplexer\n        multiplexer.disconnect()\n        t.join()\n```\n\n## Your Turn\n\nNow it is your turn to develop a simple use case which utilises the `Multiplexer` to send and receive Envelopes.\n\n## Entire Code Listing\n\nIf you just want to copy and paste the entire script in you can find it here:\n\n??? note \"Click here to see full listing:\"\n\n    ``` python\n    import os\n    import time\n    from copy import copy\n    from threading import Thread\n    from typing import Optional\n\n    from aea.configurations.base import ConnectionConfig\n    from aea.helpers.file_io import write_with_lock\n    from aea.identity.base import Identity\n    from aea.mail.base import Envelope\n    from aea.multiplexer import Multiplexer\n    \n    from packages.fetchai.connections.stub.connection import StubConnection\n    from packages.fetchai.protocols.default.message import DefaultMessage\n    \n    \n    INPUT_FILE = \"input.txt\"\n    OUTPUT_FILE = \"output.txt\"\n    \n    \n    def run():\n        \"\"\"Run demo.\"\"\"\n    \n        # Ensure the input and output files do not exist initially\n        if os.path.isfile(INPUT_FILE):\n            os.remove(INPUT_FILE)\n        if os.path.isfile(OUTPUT_FILE):\n            os.remove(OUTPUT_FILE)\n    \n        # create the connection and multiplexer objects\n        configuration = ConnectionConfig(\n            input_file=INPUT_FILE,\n            output_file=OUTPUT_FILE,\n            connection_id=StubConnection.connection_id,\n        )\n        stub_connection = StubConnection(\n            configuration=configuration,\n            data_dir=\".\",\n            identity=Identity(\"some_agent\", \"some_address\", \"some_public_key\"),\n        )\n        multiplexer = Multiplexer([stub_connection], protocols=[DefaultMessage])\n        try:\n            # Set the multiplexer running in a different thread\n            t = Thread(target=multiplexer.connect)\n            t.start()\n    \n            # Wait for everything to start up\n            for _ in range(20):\n                if multiplexer.is_connected:\n                    break\n                time.sleep(1)\n            else:\n                raise Exception(\"Not connected\")\n    \n            # Create a message inside an envelope and get the stub connection to pass it into the multiplexer\n            message_text = (\n                \"multiplexer,some_agent,fetchai/default:1.0.0,\\x08\\x01*\\x07\\n\\x05hello,\"\n            )\n            with open(INPUT_FILE, \"w\") as f:\n                write_with_lock(f, message_text)\n    \n            # Wait for the envelope to get processed\n            for _ in range(20):\n                if not multiplexer.in_queue.empty():\n                    break\n                time.sleep(1)\n            else:\n                raise Exception(\"No message!\")\n    \n            # get the envelope\n            envelope = multiplexer.get()  # type: Optional[Envelope]\n            assert envelope is not None\n    \n            # Inspect its contents\n            print(\n                \"Envelope received by Multiplexer: sender={}, to={}, protocol_specification_id={}, message={}\".format(\n                    envelope.sender,\n                    envelope.to,\n                    envelope.protocol_specification_id,\n                    envelope.message,\n                )\n            )\n    \n            # Create a mirrored response envelope\n            response_envelope = copy(envelope)\n            response_envelope.to = envelope.sender\n            response_envelope.sender = envelope.to\n    \n            # Send the envelope back\n            multiplexer.put(response_envelope)\n    \n            # Read the output envelope generated by the multiplexer\n            with open(OUTPUT_FILE, \"r\") as f:\n                print(\"Envelope received from Multiplexer: \" + f.readline())\n        finally:\n            # Shut down the multiplexer\n            multiplexer.disconnect()\n            t.join()\n    \n    \n    if __name__ == \"__main__\":\n        run()\n    ```\n"
  },
  {
    "path": "docs/oracle-demo.md",
    "content": "# Oracle Skills\n\nThis demo shows how an AEA can be used to maintain an oracle and how another AEA can request the oracle value.\n\n## Discussion\n\n**Oracle agents** are agents that have permission to update or validate updates to state variables in a smart contract and whose goal is to accurately estimate or predict some real world quantity or quantities.\n\nThis demonstration shows how to set up a simple oracle agent who deploys an oracle contract and updates the contract with a token price fetched from a public API. It also shows how to create an oracle client agent that can request the value from the oracle contract.\n\n## Preparation Instructions\n\n### Dependencies\n\nFollow the <a href=\"../quickstart/#preliminaries\">Preliminaries</a> and <a href=\"../quickstart/#installation\">Installation</a> sections from the AEA quick start.\n\n## Demo\n\n### Create the Oracle AEA\n\nFetch the AEA that will deploy and update the oracle contract.\n\n``` bash\naea fetch fetchai/coin_price_oracle:0.17.6\ncd coin_price_oracle\naea install\n```\n\n??? note \"Alternatively, create from scratch (and customize the data source):\"\n    Create the AEA that will deploy the contract.\n\n    ``` bash\n    aea create coin_price_oracle\n    cd coin_price_oracle\n    aea add connection fetchai/http_client:0.24.6\n    aea add connection fetchai/ledger:0.21.5\n    aea add connection fetchai/prometheus:0.9.6\n    aea add skill fetchai/advanced_data_request:0.7.6\n    aea add skill fetchai/simple_oracle:0.16.5\n    aea config set --type dict agent.dependencies \\\n    '{\n      \"aea-ledger-fetchai\": {\"version\": \"<2.0.0,>=1.0.0\"},\n      \"aea-ledger-ethereum\": {\"version\": \"<2.0.0,>=1.0.0\"}\n    }'\n    aea config set agent.default_connection fetchai/ledger:0.21.5\n    aea install\n    ```\n\n    Set the URL for the data request skill:\n\n    ``` bash\n    aea config set --type str vendor.fetchai.skills.advanced_data_request.models.advanced_data_request_model.args.url \"https://api.coingecko.com/api/v3/simple/price?ids=fetch-ai&vs_currencies=usd\"\n    ```\n    \n    Specify the name and JSON path of the data to fetch from the API:\n\n    ``` bash\n    aea config set --type list vendor.fetchai.skills.advanced_data_request.models.advanced_data_request_model.args.outputs '[{\"name\": \"price\", \"json_path\": \"fetch-ai.usd\"}]'\n    ```\n\n    Set the name of the oracle value in the simple oracle skill:\n\n    ``` bash\n    aea config set vendor.fetchai.skills.simple_oracle.models.strategy.args.oracle_value_name price\n    ```\n    \n    Then update the agent configuration with the default routing:\n\n    ``` bash\n    aea config set --type dict agent.default_routing \\\n    '{\n    \"fetchai/contract_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n    \"fetchai/http:1.1.7\": \"fetchai/http_client:0.24.6\",\n    \"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\"\n    }'\n    ```\n\n    Update the default ledger.\n\n    ``` bash\n    aea config set agent.default_ledger fetchai\n    ```\n    \n    Set the following configuration for the oracle skill:\n\n    ``` bash\n    aea config set vendor.fetchai.skills.simple_oracle.models.strategy.args.ledger_id fetchai\n    aea config set vendor.fetchai.skills.simple_oracle.models.strategy.args.update_function update_oracle_value\n    ```\n\nThis demo runs on the `fetchai` ledger by default. Set the following variable for use in the configuration steps:\n\n``` bash\nLEDGER_ID=fetchai\n```\n\n??? note \"Alternatively, configure the agent to use an ethereum ledger:\"\n\n    ``` bash\n    LEDGER_ID=ethereum\n    ```\n\n    Update the default ledger.\n\n    ``` bash\n    aea config set agent.default_ledger ethereum\n    ```\n\n    Set the following configuration for the oracle skill:\n\n    ``` bash\n    aea config set vendor.fetchai.skills.simple_oracle.models.strategy.args.ledger_id ethereum\n    aea config set vendor.fetchai.skills.simple_oracle.models.strategy.args.update_function updateOracleValue\n    ```\n\nAdditionally, create the private key for the oracle AEA. Generate and add a key for use with the ledger:\n\n``` bash\naea generate-key $LEDGER_ID --add-key\n```\n\nIf running on a testnet (not including Ganache), generate some wealth for your AEA:\n\n``` bash\naea generate-wealth $LEDGER_ID\n```\n\n### Create the Oracle Client AEA\n\nFrom a new terminal (in the same top-level directory), fetch the AEA that will deploy the oracle client contract and call the function that requests the coin price from the oracle contract.\n\n``` bash\naea fetch fetchai/coin_price_oracle_client:0.12.6\ncd coin_price_oracle_client\naea install\n```\n\n??? note \"Alternatively, create from scratch:\"\n    Create the AEA that will deploy the contract.\n\n    ``` bash\n    aea create coin_price_oracle_client\n    cd coin_price_oracle_client\n    aea add connection fetchai/http_client:0.24.6\n    aea add connection fetchai/ledger:0.21.5\n    aea add skill fetchai/simple_oracle_client:0.13.5\n    aea config set --type dict agent.dependencies \\\n    '{\n      \"aea-ledger-fetchai\": {\"version\": \"<2.0.0,>=1.0.0\"},\n      \"aea-ledger-ethereum\": {\"version\": \"<2.0.0,>=1.0.0\"}\n    }'\n    aea config set agent.default_connection fetchai/ledger:0.21.5\n    aea install\n    ```\n    \n    Then update the agent configuration with the default routing:\n\n    ``` bash\n    aea config set --type dict agent.default_routing \\\n    '{\n    \"fetchai/contract_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n    \"fetchai/http:1.1.7\": \"fetchai/http_client:0.24.6\",\n    \"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\"\n    }'\n    ```\n\n    Set the default ledger:\n\n    ``` bash\n    aea config set agent.default_ledger fetchai\n    ```\n    Set the following configuration for the oracle client skill:\n\n    ``` bash\n    aea config set vendor.fetchai.skills.simple_oracle_client.models.strategy.args.ledger_id fetchai\n    aea config set vendor.fetchai.skills.simple_oracle_client.models.strategy.args.query_function query_oracle_value\n    ```\n\nSimilar to above, set a temporary variable `LEDGER_ID=fetchai` or `LEDGER_ID=ethereum`.\n\n??? note \"Follow these steps to configure for an ethereum ledger:\"\n    Set the default ledger:\n\n    ``` bash\n    aea config set agent.default_ledger ethereum\n    ```\n\n    Set the following configuration for the oracle client skill:\n\n    ``` bash\n    aea config set vendor.fetchai.skills.simple_oracle_client.models.strategy.args.ledger_id ethereum\n    aea config set vendor.fetchai.skills.simple_oracle_client.models.strategy.args.query_function queryOracleValue\n    ```\n\nCreate the private key for the oracle client AEA. Generate and add a key for use on the ledger:\n\n``` bash\naea generate-key $LEDGER_ID --add-key\n```\n\nIf running on a testnet (not including Ganache), generate some wealth for your AEA:\n\n``` bash\naea generate-wealth $LEDGER_ID\n```\n\n### Configuring a Ledger\n\nThe oracle AEAs require either a locally running ledger node or a connection to a remote ledger. By default, they are configured to use the latest `fetchai` testnet.\n\n??? note \"Follow these steps to configure local Ethereum test node:\"\n    The easiest way to test the oracle agents on an Ethereum-based ledger to set up a local test node using Ganache. This can be done by running the following docker command from the directory you started from (in a new terminal). This command will also fund the accounts of the AEAs:\n\n    ``` bash\n    docker run -p 8545:8545 trufflesuite/ganache-cli:latest --verbose --gasPrice=0 --gasLimit=0x1fffffffffffff --account=\"$(cat coin_price_oracle/ethereum_private_key.txt),1000000000000000000000\" --account=\"$(cat coin_price_oracle_client/ethereum_private_key.txt),1000000000000000000000\"\n    ```\n\n    Run the following Python script (with <code>web3</code> installed) from the top-level directory to deploy a mock Fetch ERC20 contract and give some test FET to the client agent.\n    \n    ``` python\n    import json\n    import os\n    from web3 import Web3\n    \n    FILE_DIR = os.path.dirname(os.path.realpath(__file__))\n    CONTRACT_PATH = os.path.join(FILE_DIR, \"coin_price_oracle_client/vendor/fetchai/contracts/fet_erc20/build/FetERC20Mock.json\")\n    ORACLE_PRIVATE_KEY_PATH = os.path.join(FILE_DIR, \"coin_price_oracle/ethereum_private_key.txt\")\n    CLIENT_PRIVATE_KEY_PATH = os.path.join(FILE_DIR, \"coin_price_oracle_client/ethereum_private_key.txt\")\n    \n    # Solidity source code\n    with open(CONTRACT_PATH) as file:\n        compiled_sol = json.load(file)\n    \n    # web3.py instance\n    w3 = Web3(Web3.HTTPProvider('http://127.0.0.1:8545'))\n    \n    # Import oracle account from private key and set to default account\n    with open(ORACLE_PRIVATE_KEY_PATH) as file:\n        private_key = file.read()\n    oracle_account = w3.eth.account.privateKeyToAccount(private_key)\n    w3.eth.defaultAccount = oracle_account.address\n    \n    # Import client account from private key\n    with open(CLIENT_PRIVATE_KEY_PATH) as file:\n        private_key = file.read()\n    client_account = w3.eth.account.privateKeyToAccount(private_key)\n    \n    # Deploy mock Fetch ERC20 contract\n    FetERC20Mock = w3.eth.contract(abi=compiled_sol['abi'], bytecode=compiled_sol['bytecode'])\n    \n    # Submit the transaction that deploys the contract\n    tx_hash = FetERC20Mock.constructor(\n        name=\"FetERC20Mock\",\n        symbol=\"MFET\",\n        initialSupply=int(1e23),\n        decimals_=18).transact()\n    \n    # Wait for the transaction to be mined, and get the transaction receipt\n    tx_receipt = w3.eth.waitForTransactionReceipt(tx_hash)\n    \n    # Print out the contract address\n    print(\"FetERC20Mock contract deployed at:\", tx_receipt.contractAddress)\n    \n    # Get deployed contract\n    fet_erc20_mock = w3.eth.contract(address=tx_receipt.contractAddress, abi=compiled_sol['abi'])\n    \n    # Transfer some test FET to oracle client account\n    tx_hash = fet_erc20_mock.functions.transfer(client_account.address, int(1e20)).transact()\n    tx_receipt = w3.eth.waitForTransactionReceipt(tx_hash)\n    ```\n    \n    Set the ERC20 contract address for the oracle AEA\n\n    ``` bash\n    aea config set vendor.fetchai.skills.simple_oracle.models.strategy.args.erc20_address $ERC20_ADDRESS\n    ```\n\n    as well as for the oracle client AEA\n\n    ``` bash\n    aea config set vendor.fetchai.skills.simple_oracle_client.models.strategy.args.erc20_address $ERC20_ADDRESS\n    ```\n\n    where `ERC20_ADDRESS` is in the output of the script above.\n\n### Run the Oracle AEA\n\nRun the oracle agent. This will deploy a contract to the testnet, grant oracle permissions to the AEA's wallet address, and periodically update the contract with the latest price of FET (or whichever coin was specified).\n\n``` bash\naea run\n```\n\nAfter a few moments, you should see the following notices in the logs:\n\n``` bash\ninfo: [coin_price_oracle] Oracle contract successfully deployed at address: ...\n...\ninfo: [coin_price_oracle] Oracle role successfully granted!\n...\ninfo: [coin_price_oracle] Oracle value successfully updated!\n```\n\nThe oracle contract will continue to be updated with the latest retrieved coin price at the default time interval (every 15 seconds).\n\n### Set the ERC20 and Oracle Contract Addresses for the Oracle Client AEA\n\n``` bash\naea config set vendor.fetchai.skills.simple_oracle_client.models.strategy.args.oracle_contract_address $ORACLE_ADDRESS\n```\n\nwhere `ORACLE_ADDRESS` should be set to the address shown in the oracle AEA logs:\n\n``` bash\nOracle contract successfully deployed at address: ORACLE_ADDRESS\n```\n\n### Run the Oracle Client AEA\n\nRun the oracle client agent. This will deploy an oracle client contract to the testnet, approve the contract to spend tokens on behalf of the AEA, and periodically call the contract function that requests the latest price of FET (or whichever coin was specified).\n\n``` bash\naea run\n```\n\nAfter a few moments, you should see the following notices in the logs:\n\n``` bash\ninfo: [coin_price_oracle_client] Oracle client contract successfully deployed at address: ...\n...\ninfo: [coin_price_oracle_client] Oracle value successfully requested!\n```\n\nThe AEA will continue to request the latest coin price at the default time interval (every 15 seconds).\n"
  },
  {
    "path": "docs/orm-integration.md",
    "content": "# ORM Integration\n\nThis guide demonstrates how to configure an AEA to interact with a database using `python-sql` objects.\n\n## Discussion\n\nObject-relational-mapping (ORM) is the idea of being able to write SQL queries, using the object-oriented paradigm of your preferred programming language. The scope of this guide is to demonstrate how you can create an easily configurable AEA that reads data from a database using ORMs.\n\n- We assume, that you followed the guide for the <a href=\"../thermometer-skills/\"> thermometer-skills. </a>\n- We assume, that we have a database `genericdb.db` with table name `data`. This table contains the following columns `timestamp` and `thermometer`.\n- We assume, that we have a hardware thermometer sensor that adds the readings in the `genericdb` database (although you can follow the guide without having access to a sensor).\n\nSince the AEA framework enables us to use third-party libraries hosted on PyPI we can directly reference the external dependencies. The `aea install` command will install each dependency that the specific AEA needs and which is listed in the skill's YAML file.\n\n## Communication\n\nThis diagram shows the communication between the various entities in the case where the thermometer data is successfully sold by the seller AEA to the buyer.\n\n``` mermaid\n    sequenceDiagram\n        participant Search\n        participant Buyer_AEA\n        participant Seller_AEA\n        participant Blockchain\n    \n        activate Buyer_AEA\n        activate Search\n        activate Seller_AEA\n        activate Blockchain\n        \n        Seller_AEA->>Search: register_service\n        Buyer_AEA->>Search: search\n        Search-->>Buyer_AEA: list_of_agents\n        Buyer_AEA->>Seller_AEA: call_for_proposal\n        Seller_AEA->>Buyer_AEA: propose\n        Buyer_AEA->>Seller_AEA: accept\n        Seller_AEA->>Buyer_AEA: match_accept\n        Buyer_AEA->>Blockchain: transfer_funds\n        Buyer_AEA->>Seller_AEA: send_transaction_hash\n        Seller_AEA->>Blockchain: check_transaction_status\n        Seller_AEA->>Buyer_AEA: send_data\n        \n        deactivate Buyer_AEA\n        deactivate Search\n        deactivate Seller_AEA\n        deactivate Blockchain    \n```\n\n## Preparation Instructions\n\n### Dependencies\n\nFollow the <a href=\"../quickstart/#preliminaries\">Preliminaries</a> and <a href=\"../quickstart/#installation\">Installation</a> sections from the AEA quick start.\n\n## Demo Instructions\n\nThis demo involves a true ledger transaction on Fetch.ai's `testnet` network or Ethereum's `ropsten`. This demo assumes the buyer trusts the seller AEA to send the data upon successful payment.\n\n### Create the Seller AEA\n\nFirst, fetch the seller AEA which provides thermometer data:\n\n``` bash\naea fetch fetchai/thermometer_aea:0.30.5 --alias my_thermometer_aea\ncd my_thermometer_aea\naea install\naea build\n```\n\n??? note \"Alternatively, create from scratch:\"\n    The following steps create the seller from scratch:\n\n    ``` bash\n    aea create my_thermometer_aea\n    cd my_thermometer_aea\n    aea add connection fetchai/p2p_libp2p:0.27.5\n    aea add connection fetchai/soef:0.27.6\n    aea add connection fetchai/ledger:0.21.5\n    aea add skill fetchai/thermometer:0.27.6\n    aea config set --type dict agent.dependencies \\\n    '{\n      \"aea-ledger-fetchai\": {\"version\": \"<2.0.0,>=1.0.0\"}\n    }'\n    aea config set agent.default_connection fetchai/p2p_libp2p:0.27.5\n    aea config set --type dict agent.default_routing \\\n    '{\n      \"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n      \"fetchai/oef_search:1.1.7\": \"fetchai/soef:0.27.6\"\n    }'\n    aea install\n    aea build\n    ```\n\n### Create the Buyer Client\n\nIn another terminal, fetch the buyer AEA:\n\n``` bash\naea fetch fetchai/thermometer_client:0.32.5 --alias my_thermometer_client\ncd my_thermometer_client\naea install\naea build\n```\n\n??? note \"Alternatively, create from scratch:\"\n    The following steps create the car data client from scratch:\n\n    ``` bash\n    aea create my_thermometer_client\n    cd my_thermometer_client\n    aea add connection fetchai/p2p_libp2p:0.27.5\n    aea add connection fetchai/soef:0.27.6\n    aea add connection fetchai/ledger:0.21.5\n    aea add skill fetchai/thermometer_client:0.26.6\n    aea config set --type dict agent.dependencies \\\n    '{\n      \"aea-ledger-fetchai\": {\"version\": \"<2.0.0,>=1.0.0\"}\n    }'\n    aea config set agent.default_connection fetchai/p2p_libp2p:0.27.5\n    aea config set --type dict agent.default_routing \\\n    '{\n      \"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n      \"fetchai/oef_search:1.1.7\": \"fetchai/soef:0.27.6\"\n    }'\n    aea install\n    aea build\n    ```\n\n### Add Keys for the Seller AEA\n\nFirst, create the private key for the seller AEA based on the network you want to transact. To generate and add a private-public key pair for Fetch.ai `Dorado` use:\n\n``` bash\naea generate-key fetchai\naea add-key fetchai fetchai_private_key.txt\n```\n\nNext, create a private key used to secure the AEA's communications:\n\n``` bash\naea generate-key fetchai fetchai_connection_private_key.txt\naea add-key fetchai fetchai_connection_private_key.txt --connection\n```\n\nFinally, certify the key for use by the connections that request that:\n\n``` bash\naea issue-certificates\n```\n\n### Add Keys and Generate Wealth for the Buyer AEA\n\nThe buyer needs to have some wealth to purchase the thermometer data.\n\nFirst, create the private key for the buyer AEA based on the network you want to transact. To generate and add a private-public key pair for Fetch.ai use:\n\n``` bash\naea generate-key fetchai\naea add-key fetchai fetchai_private_key.txt\n```\n\nThen, create some wealth for the buyer based on the network you want to transact with. On the Fetch.ai `Dorado` network:\n\n``` bash\naea generate-wealth fetchai\n```\n\nNext, create a private key used to secure the AEA's communications:\n\n``` bash\naea generate-key fetchai fetchai_connection_private_key.txt\naea add-key fetchai fetchai_connection_private_key.txt --connection\n```\n\nFinally, certify the key for use by the connections that request that:\n\n``` bash\naea issue-certificates\n```\n\n### Update the Seller and Buyer AEA Skill Configurations\n\nIn `my_thermometer_aea/vendor/fetchai/skills/thermometer/skill.yaml`, replace the `data_for_sale` with your data:\n\n``` yaml\nmodels:\n  ...\n  strategy:\n    args:\n      currency_id: FET\n      data_for_sale:\n        temperature: 26\n      has_data_source: false\n      is_ledger_tx: true\n      ledger_id: fetchai\n      location:\n        latitude: 51.5194\n        longitude: 0.127\n      service_data:\n        key: seller_service\n        value: thermometer_data\n      service_id: thermometer_data\n      unit_price: 10\n    class_name: Strategy\ndependencies:\n  SQLAlchemy: {}\n```\n\nThe `service_data` is used to register the service in the <a href=\"../simple-oef\">SOEF search node</a> and make your agent discoverable.\n\nIn `my_thermometer_client/vendor/fetchai/skills/thermometer_client/skill.yaml`) ensure you have matching data.\n\n``` yaml\nmodels:\n  ...\n  strategy:\n    args:\n      currency_id: FET\n      is_ledger_tx: true\n      ledger_id: fetchai\n      location:\n        latitude: 51.5194\n        longitude: 0.127\n      max_negotiations: 1\n      max_tx_fee: 3550000000000000\n      max_unit_price: 20\n      search_query:\n        constraint_type: ==\n        search_key: seller_service\n        search_value: thermometer_data\n      search_radius: 5.0\n      service_id: thermometer_data\n    class_name: Strategy\n```\n\nAfter changing the skill configuration files you should run the following command for both agents to install each dependency:\n\n``` bash\naea install\n```\n\n### Modify the Seller's Strategy\n\nBefore being able to modify a package we need to eject it from vendor:\n\n``` bash\naea eject skill fetchai/thermometer:0.27.6\n```\n\nThis will move the package to your `skills` directory and reset the version to `0.1.0` and the author to your author handle.\n\nOpen `strategy.py` (in `my_thermometer_aea/skills/thermometer/strategy.py`) and make the following modifications:\n\nImport the newly installed `sqlalchemy` library in your strategy.\n\n``` python\nimport sqlalchemy as db\n```\n\nThen modify your strategy's `__init__` function to match the following code:\n\n``` python\nclass Strategy(GenericStrategy):\n    \"\"\"This class defines a strategy for the agent.\"\"\"\n\n    def __init__(self, **kwargs) -> None:\n        \"\"\"\n        Initialize the strategy of the agent.\n\n        :param register_as: determines whether the agent registers as seller, buyer or both\n        :param search_for: determines whether the agent searches for sellers, buyers or both\n\n        :return: None\n        \"\"\"\n        self._db_engine = db.create_engine(\"sqlite:///genericdb.db\")\n        self._tbl = self.create_database_and_table()\n        self.insert_data()\n        super().__init__(**kwargs)\n```\n\nAt the end of the file modify the `collect_from_data_source` function:\n\n``` python\n    def collect_from_data_source(self) -> Dict[str, str]:\n        \"\"\"Implement the logic to collect data.\"\"\"\n        connection = self._db_engine.connect()\n        query = db.select([self._tbl])\n        result_proxy = connection.execute(query)\n        data_points = result_proxy.fetchall()\n        return {\"data\": json.dumps(list(map(tuple, data_points)))}\n```\n\nAlso, create two new functions, one that creates a connection with the database, and another that populates the database with some fake data. This is needed in the case you do not have access to an actual thermometer sensor that inserts data in the database.\n\n``` python\n    def create_database_and_table(self):\n        \"\"\"Creates a database and a table to store the data if not exists.\"\"\"\n        metadata = db.MetaData()\n\n        tbl = db.Table(\n            \"data\",\n            metadata,\n            db.Column(\"timestamp\", db.Integer()),\n            db.Column(\"temprature\", db.String(255), nullable=False),\n        )\n        metadata.create_all(self._db_engine)\n        return tbl\n\n    def insert_data(self):\n        \"\"\"Insert data in the database.\"\"\"\n        connection = self._db_engine.connect()\n        for _ in range(10):\n            query = db.insert(self._tbl).values(  # nosec\n                timestamp=time.time(), temprature=str(random.randrange(10, 25))\n            )\n            connection.execute(query)\n```\n\nAfter modifying the skill we need to fingerprint it:\n\n``` bash\naea fingerprint skill {YOUR_AUTHOR_HANDLE}/thermometer:0.1.0\n```\n\n### Run Both AEAs\n\nFirst, run the thermometer (seller) AEA:\n\n``` bash\naea run\n```\n\nOnce you see a message of the form `To join its network use multiaddr 'SOME_ADDRESS'` take note of this address. (Alternatively, use `aea get-multiaddress fetchai -c -i fetchai/p2p_libp2p:0.27.5 -u public_uri` to retrieve the address.)\nThis is the entry peer address for the local <a href=\"../acn\">agent communication network</a> created by the thermometer AEA.\n\nThen, configure the thermometer client (buyer) to connect to this same local ACN by running the following command in the buyer terminal, replacing `SOME_ADDRESS` with the value you noted above:\n\n``` bash\naea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \\\n'{\n  \"delegate_uri\": \"127.0.0.1:11001\",\n  \"entry_peers\": [\"SOME_ADDRESS\"],\n  \"local_uri\": \"127.0.0.1:9001\",\n  \"log_file\": \"libp2p_node.log\",\n  \"public_uri\": \"127.0.0.1:9001\"\n}'\n```\n\nThen run the thermometer client AEA:\n\n``` bash\naea run\n```\n\nYou will see that the AEAs negotiate and then transact using the configured testnet.\n\n## Delete the AEAs\n\nWhen you're done, stop the agents (`CTRL+C`), go up a level and delete the AEAs.\n\n``` bash\ncd ..\naea delete my_thermometer_aea\naea delete my_thermometer_client\n```\n"
  },
  {
    "path": "docs/p2p-connection.md",
    "content": "# P2P Connection\n\nThe `fetchai/p2p_libp2p:0.27.5` connection allows AEAs to create a peer-to-peer communication network. In particular, the connection creates an overlay network which maps agents' public keys to IP addresses.\n\n## Local Demo\n\nFirst, make sure you have installed the crypto plugin\nof the target test-net. E.g. for Fetch.AI:\n\n``` bash\npip install aea-ledger-fetchai\n```\n\n### Create and Run the Genesis AEA\n\nCreate one AEA as follows:\n\n``` bash\naea create my_genesis_aea\ncd my_genesis_aea\naea add connection fetchai/p2p_libp2p:0.27.5\naea config set agent.default_connection fetchai/p2p_libp2p:0.27.5\naea install\naea build\n```\n\nEstablish the <a href=\"../por\">proof of representation</a>:\n\n``` bash\naea generate-key fetchai\naea add-key fetchai fetchai_private_key.txt\naea generate-key fetchai fetchai_connection_private_key.txt\naea add-key fetchai fetchai_connection_private_key.txt --connection\naea issue-certificates\n```\n\nRun the AEA:\n\n``` bash\naea run --connections fetchai/p2p_libp2p:0.27.5\n```\n\nOnce you see a message of the form `To join its network use multiaddr 'SOME_ADDRESS'` take note of the address. (Alternatively, use `aea get-multiaddress fetchai -c -i fetchai/p2p_libp2p:0.27.5 -u public_uri` to retrieve the address.)\nThis is the entry peer address for the local <a href=\"../acn\">agent communication network</a> created by the genesis AEA.\n\n### Create and Run Another AEA\n\nCreate a second AEA:\n\n``` bash\naea create my_other_aea\ncd my_other_aea\naea add connection fetchai/p2p_libp2p:0.27.5\naea config set agent.default_connection fetchai/p2p_libp2p:0.27.5\naea install\naea build\n```\n\nEstablish the <a href=\"../por\">proof of representation</a>:\n\n``` bash\naea generate-key fetchai\naea add-key fetchai fetchai_private_key.txt\naea generate-key fetchai fetchai_connection_private_key.txt\naea add-key fetchai fetchai_connection_private_key.txt --connection\naea issue-certificates\n```\n\nProvide the AEA with the information it needs to find the genesis:\n\n``` bash\naea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \\\n'{\n  \"delegate_uri\": \"127.0.0.1:11001\",\n  \"entry_peers\": [\"SOME_ADDRESS\"],\n  \"local_uri\": \"127.0.0.1:9001\",\n  \"log_file\": \"libp2p_node.log\",\n  \"public_uri\": \"127.0.0.1:9001\"\n}'\n```\n\nHere `SOME_ADDRESS` needs to be replaced with the list of multi addresses displayed in the log output of the genesis AEA.\n\nRun the AEA:\n\n``` bash\naea run --connections fetchai/p2p_libp2p:0.27.5\n```\n\nYou can inspect the `libp2p_node.log` log files of the AEA to see how they discover each other.\n\n!!! note\n    Currently `p2p_libp2p` connection limits the total message size to 3 MB.\n\n## Local Demo with Skills\n\nExplore the <a href=\"../weather-skills\">demo section</a> for further examples.\n\n## Deployed Agent Communication Network\n\nYou can connect to the deployed public test network by adding one or multiple of the following addresses as the `p2p_libp2p` connection's `entry_peers`:\n\n``` yaml\n/dns4/acn.fetch.ai/tcp/9000/p2p/16Uiu2HAkw1ypeQYQbRFV5hKUxGRHocwU5ohmVmCnyJNg36tnPFdx\n```\n\n``` yaml\n/dns4/acn.fetch.ai/tcp/9001/p2p/16Uiu2HAmVWnopQAqq4pniYLw44VRvYxBUoRHqjz1Hh2SoCyjbyRW\n```\n\nSpecifically, in an AEA's configuration `aea-config.yaml` add the above addresses for `entry_peers` as follows:\n\n``` yaml\n---\npublic_id: fetchai/p2p_libp2p:0.27.5\ntype: connection\nconfig:\n  delegate_uri: null\n  entry_peers: [/dns4/acn.fetch.ai/tcp/9000/p2p/16Uiu2HAkw1ypeQYQbRFV5hKUxGRHocwU5ohmVmCnyJNg36tnPFdx,/dns4/acn.fetch.ai/tcp/9001/p2p/16Uiu2HAmVWnopQAqq4pniYLw44VRvYxBUoRHqjz1Hh2SoCyjbyRW]\n  public_uri: null\n  local_uri: 127.0.0.1:9001\n```\n\nNote, this configuration change must be made for all agents attempting to communicate with each other via the Agent Communication Network. For example, in demos involving two agents, both agents will need the above modifications to their respective `aea-config.yaml` file. However, remember to use different ports in `local_uri.` This will allow both agents to default to this communication network without the added overhead of opening ports and specifying hosts on the individual host machines running each agent.\n\n## Configuring the `connection.yaml` Entries\n\nTo learn more about how to configure your `fetchai/p2p_libp2p:0.27.5` connection consult the `README.md` file supplied with the connection package.\n\n## Running Go Peer Standalone\n\nYou can run a peer node in _standalone mode_; that is, as a Go process with no dependency on the AEA framework. To facilitate such a deployment, we provide a script\n <a href=\"https://github.com/fetchai/agents-aea/blob/main/scripts/acn/run_acn_node_standalone.py\" target=\"_blank\">`run_acn_node_standalone.py`</a>\n and a corresponding\n <a href=\"https://github.com/fetchai/agents-aea/blob/main/scripts/acn/Dockerfile\" target=\"_blank\">Dockerfile</a>.\n\nFirst, you need to build the node's binary (`libp2p_node`) either:\n\n- locally\n\n    ``` bash\n    svn export https://github.com/fetchai/agents-aea.git/trunk/packages/fetchai/connections/p2p_libp2p\n    cd p2p_libp2p\n    go build\n    chmod +x libp2p_node\n    ```\n\n    Make sure you satisfy the <a href=\"../quickstart\">system requirements</a>.\n\n- or within a docker image using the provided Dockerfile:\n\n    ``` bash\n    docker build -t acn_node_standalone -f scripts/acn/Dockerfile .\n    ```\n\nNext, to run the node binary in standalone mode, it requires values for the following entries:\n\n- `AEA_P2P_ID`: the node's private key, will be used as its identity\n- `AEA_P2P_URI`: the local host and port to use by node\n- `AEA_P2P_URI_PUBLIC`: the URI under which the peer is publicly reachable\n- `AEA_P2P_DELEGATE_URI`: the URI under which the peer receives delegate connections\n- `AEA_P2P_ENTRY_URIS`: an optionally supplied list of comma-separated (`,`) entry multiaddresses for the peer to bootstrap\n\nThe script allows different methods to pass these values to the node:\n\n- As environment variables exported in the format `<ENTRY_KEYWORD>=<ENTRY_VALUE>` for each entry. Then:\n\n    ``` bash\n    python3 run_acn_node_standalone.py libp2p_node --config-from-env\n    ```\n\n- Using an environment file containing the entries and their values in the format `<ENTRY_KEYWORD>=<ENTRY_VALUE>`, one entry per line. Then:\n\n    ``` bash\n    python3 run_acn_node_standalone.py libp2p_node --config-from-file <env-file-path>\n    ```\n\n    or\n\n    ``` bash\n    docker run -v <acn_config_file>:/acn/acn_config -it acn_node_standalone --config-from-file /acn/acn_config\n    ```\n\n- Using command line arguments:\n\n    ``` bash\n    python3 run_acn_node_standalone.py libp2p_node --key-file <node_private_key.txt> \\\n      --uri <AEA_P2P_URI> --uri-external <AEA_P2P_URI_PUBLIC>  \\\n      --uri-delegate <AEA_P2P_DELEGATE_URI> \\\n      --entry-peers-maddrs <AEA_P2P_ENTRY_URI_1> <AEA_P2P_ENTRY_URI_2> ...\n    ```\n\n    or\n\n    ``` bash\n    docker run -v <node_private_key.txt>:/acn/key.txt -it acn_node_standalone --key-file /acn/key.txt \\\n      --uri <AEA_P2P_URI> --uri-external <AEA_P2P_URI_PUBLIC>  \\\n      --uri-delegate <AEA_P2P_DELEGATE_URI> \\\n      --entry-peers-maddrs <AEA_P2P_ENTRY_URI_1> <AEA_P2P_ENTRY_URI_2> ...\n    ```\n\nNote that the script will always save the configuration of the running node as a file under the name `.acn_config` in the current working directory. This can be handy when you want the exact same configuration for future runs of the node.\n"
  },
  {
    "path": "docs/package-imports.md",
    "content": "# File Structure\n\nAn agent that is generated using the AEA framework is a modular system with different connections, contracts, protocols and skills.\n\n## An AEA Project's File Structure\n\nThe file structure of an AEA is fixed.\n\nThe top level directory has the AEA's name. Below is a `aea-config.yaml` configuration file, then directories containing the connections, contracts, protocols, and skills developed by the developer as part of the given project. The connections, contracts, protocols and skills used from the registry (local or remote - added via `aea fetch` or `aea add`) are located in `vendor` and sorted by author. Build artefacts are placed in the `.build/` directory and certificates are placed in the `.certs/` directory. Finally, there are files containing the private keys of the AEA.\n\nWhen we create a new agent with the command `aea create my_aea` we create the file structure that looks like the following:\n\n``` bash\naea_name/\n  aea-config.yaml       YAML configuration of the AEA\n  fetchai_private_key.txt   The private key file\n  connections/          Directory containing all the connections developed as part of the given project.\n    connection_1/       First connection\n    ...                 ...\n    connection_n/       nth connection\n  contracts/            Directory containing all the contracts developed as part of the given project.\n    connection_1/       First connection\n    ...                 ...\n    connection_n/       nth connection\n  protocols/            Directory containing all the protocols developed as part of the given project.\n    protocol_1/         First protocol\n    ...                 ...\n    protocol_m/         mth protocol\n  skills/               Directory containing all the skills developed as part of the given project.\n    skill_1/            First skill\n    ...                 ...\n    skill_k/            kth skill\n  vendor/               Directory containing all the added resources from the registry, sorted by author.\n    author_1/           Directory containing all the resources added from author_1\n      connections/      Directory containing all the added connections from author_1\n        ...             ...\n      protocols/        Directory containing all the added protocols from author_1\n        ...             ...\n      skills/           Directory containing all the added skills from author_1\n        ...             ...\n```\n\nThe developer can create new directories where necessary but the core structure must remain the same.\n\n## AEA Configuration YAML\n\nThe `aea-config.yaml` is the top level configuration file of an AEA. It defines the global configurations as well as the component/package dependencies of the AEA. In some sense, the AEA can therefore be understood as an orchestrator of components.\n\nFor the AEA to use a package, the `public_id` for the package must be listed in the `aea-config.yaml` file, e.g.\n\n``` yaml\nconnections:\n- fetchai/stub:0.21.3\n```\n\nThe above shows a part of the `aea-config.yaml`. If you see the connections, you will see that we follow a pattern of `author/name_package:version` to identify each package, also referred to as `public_id`. Here the `author` is the author of the package.\n\n## Vendor and Package Directories\n\nThe `vendor` folder contains the packages from the registry (local or remote) which have been developed by ourselves, other authors or Fetch.ai and are placed in different namespaces according to the author name.\n\nThe packages we develop as part of the given AEA project are in the respective `connections/`, `contracts/`, `protocols/`, and `skills/` folders.\n\nIn the above configuration example, the package is authored by Fetch.ai and is located inside the `vendor/fetchai/connections` folder.\n\n## Importing Modules from Packages\n\nThe way we import modules from packages inside the agent is in the form of `packages.{author}.{package_type}.{package_name}.{module_name}`. So for the above example, the import path is `packages.fetchai.connections.stub.{module_name}`.\n\nThe framework loads the modules from the local agent project and adds them to Python's `sys.modules` under the respective path.\n\nWe use a custom package management approach for the AEAs rather than the default Python one as it provides us with more flexibility, especially when it comes to extension beyond the Python ecosystem.\n\n## Python Dependencies of Packages\n\nPython dependencies of packages are specified in their respective configuration files under `dependencies`. They will be installed when `aea install` is run on an agent project.\n\n## Create a Package\n\nIf you want to create a package, you can use the <a href=\"../scaffolding/\">CLI command</a> `aea scaffold connection/contract/protocol/skill [name]` and this will create the package and put it inside the respective folder based on the command for example if we `scaffold` skill with the name `my_skill`\nit will be located inside the folder skills in the root directory of the agent (`my_aea/skills/my_skill`).\n\n## Use Published Packages from the Registry\n\nIf you want to use a finished package, you can use a package from the registry.\n\nThere or two registries. The remote registry operated by Fetch.ai and a local registry stub. The local registry stub is a directory called `packages` which contains packages in a nested structure with authors on the top level, followed by the package type, then package name. An example of such a directory is the `packages` directory located in the AEA repository. The local registry is useful for development.\n\nYou can use the CLI to interact with the registry. By default, the CLI points to the remote registry. You can point it to the local registry via the flag `--local`.\n\n## Package Versioning\n\nBy default, the AEA can only handle one version per package. That is, a project should never use both `some_author/some_package_name:0.1.0` and `some_author/some_package_name:0.2.0`.\n\nIf two AEA packages with the same author and name but different versions are used in the same Python process, then only the code from one of the packages (generally not deterministic) will be available in `sys.modules`. This can lead to inconsistencies and exceptions at runtime.\n"
  },
  {
    "path": "docs/performance-benchmark.md",
    "content": "# Performance Benchmark\n\nTest AEA framework performance.\n\n## What is it?\n\nThe benchmark module is a set of tools to measure execution time, CPU load and memory usage of the AEA Python code. It produces text reports and draws charts to present the results.\n\n## How does it Work?\n\nThe framework:\n\n- spawns a dedicated process for each test run to execute the function to test.\n- measures CPU and RAM usage periodically.\n- waits for function exits or terminates them by timeout.\n- repeats test execution multiple times to get more accurate results.\n\n## How to Use\n\nSteps to run a test:\n\n- Write a function you would like to test with all arguments you would like to parametrise, add some doc strings.\n- Split the function into two parts: 'prepare' and 'performance' part. The 'prepare' part will not be included in the measurement.\n- Add `BenchmarkControl` support, to notify framework to start measurement.\n- Import `TestCli` class,  `TestCli().run(function_to_be_tested)`\n- Call it from console to get text results.\n\n### Simple Example\n\n`cpuburn` - simple test of CPU load depends on idle sleep time. Shows how much CPU consumed during the execution.\n\n``` python\nimport time\n\nfrom benchmark.framework.benchmark import BenchmarkControl\nfrom benchmark.framework.cli import TestCli\n\n\ndef cpu_burn(benchmark: BenchmarkControl, run_time=10, sleep=0.0001) -> None:\n    \"\"\"\n    Do nothing, just burn cpu to check cpu load changed on sleep.\n\n    :param benchmark: benchmark special parameter to communicate with executor\n    :param run_time: time limit to run this function\n    :param sleep: time to sleep in loop\n\n    :return: None\n    \"\"\"\n    benchmark.start()\n    start_time = time.time()\n\n    while True:\n        time.sleep(sleep)\n        if time.time() - start_time >= run_time:\n            break\n\n\nif __name__ == \"__main__\":\n    TestCli(cpu_burn).run()\n```\n\nRun it with `python ./benchmark/cases/cpu_burn.py --help` to get help about usage.\n\n``` bash\nUsage: cpu_burn.py [OPTIONS] [ARGS]...\n\n       Do nothing, just burn cpu to check cpu load changed on sleep.\n\n  :param benchmark: benchmark special parameter to communicate with executor\n  :param run_time: time limit to run this function :param sleep: time to sleep in loop\n\n  :return: None\n\n      ARGS is function arguments in format: `run_time,sleep`\n\n      default ARGS is `10,0.0001`\n\nOptions:\n  --timeout FLOAT               Executor timeout in seconds  [default: 10.0]\n  --period FLOAT                Period for measurement  [default: 0.1]\n  -N, --num-executions INTEGER  Number of runs for each case  [default: 1]\n  -P, --plot INTEGER            X axis parameter idx\n  --help                        Show this message and exit.\n```\n\nRun it with `python ./benchmark/cases/cpu_burn.py` to start with default parameters.\n\n``` bash\nTest execution timeout: 10.0\nTest execution measure period: 0.1\nTested function name: cpu_burn\nTested function description:\n    Do nothing, just burn cpu to check cpu load changed on sleep.\n\n    :param benchmark: benchmark special parameter to communicate with executor\n    :param run_time: time limit to run this function\n    :param sleep: time to sleep in loop\n\n    :return: None\n\nTested function argument names: ['run_time', 'sleep']\nTested function argument default values: [10, 0.0001]\n\n== Report created 2020-04-27 15:14:56.076549 ==\nArguments are `[10, 0.0001]`\nNumber of runs: 1\nNumber of time terminated: 0\nTime passed (seconds): 10.031443119049072 ± 0\ncpu min (%): 0.0 ± 0\ncpu max (%): 10.0 ± 0\ncpu mean (%): 3.4 ± 0\nmem min (kb): 53.98828125 ± 0\nmem max (kb): 53.98828125 ± 0\nmem mean (kb): 53.98828125 ± 0\n```\n\nHere you can see test report for default arguments set.\n\nRun with multiple arguments set, multiple repeats and draw a chart on resources\n`python ./benchmark/cases/cpu_burn.py -N 5 -P 1 3,0.00001 3,0.001 3,0.01`\n\nReport is:\n\n``` bash\nTest execution timeout: 10.0\nTest execution measure period: 0.1\nTested function name: cpu_burn\nTested function description:\n    Do nothing, just burn cpu to check cpu load changed on sleep.\n\n    :param benchmark: benchmark special parameter to communicate with executor\n    :param run_time: time limit to run this function\n    :param sleep: time to sleep in loop\n\n    :return: None\n\nTested function argument names: ['run_time', 'sleep']\nTested function argument default values: [10, 0.0001]\n\n== Report created 2020-04-27 15:38:17.849535 ==\nArguments are `(3, 1e-05)`\nNumber of runs: 5\nNumber of time terminated: 0\nTime passed (seconds): 3.0087939262390138 ± 0.0001147521277690166\ncpu min (%): 0.0 ± 0.0\ncpu max (%): 11.0 ± 2.23606797749979\ncpu mean (%): 6.2 ± 0.18257418583505522\nmem min (kb): 54.0265625 ± 0.11180339887498948\nmem max (kb): 54.0265625 ± 0.11180339887498948\nmem mean (kb): 54.0265625 ± 0.11180339887498948\n== Report created 2020-04-27 15:38:32.947308 ==\nArguments are `(3, 0.001)`\nNumber of runs: 5\nNumber of time terminated: 0\nTime passed (seconds): 3.014109659194946 ± 0.0004416575764579524\ncpu min (%): 0.0 ± 0.0\ncpu max (%): 8.0 ± 2.7386127875258306\ncpu mean (%): 1.9986666666666666 ± 0.002981423969999689\nmem min (kb): 53.9890625 ± 0.10431954926750306\nmem max (kb): 53.9890625 ± 0.10431954926750306\nmem mean (kb): 53.9890625 ± 0.10431954926750306\n== Report created 2020-04-27 15:38:48.067511 ==\nArguments are `(3, 0.01)`\nNumber of runs: 5\nNumber of time terminated: 0\nTime passed (seconds): 3.0181806087493896 ± 0.0022409499756841883\ncpu min (%): 0.0 ± 0.0\ncpu max (%): 1.0 ± 2.23606797749979\ncpu mean (%): 0.06666666666666667 ± 0.14907119849998599\nmem min (kb): 53.9078125 ± 0.11487297672320501\nmem max (kb): 53.9078125 ± 0.11487297672320501\nmem mean (kb): 53.9078125 ± 0.11487297672320501\n```\n\nChart is drawn for argument 1: sleep:\n\n<img src=\"../assets/benchmark_chart.png\" alt=\"Char over argument 1 - sleep value\" class=\"center\">\n\nThe most interesting part is CPU usage, as you can see  CPU usage decreases with increasing value of idle sleep.\nMemory usage and execution time can slightly differ per case execution.\n\n## Requirements for Tested Function\n\n- The first function's argument has to be `benchmark: BenchmarkControl` which is passed by default by the framework.\n- All arguments except the fist one have to set default values.\n- Function doc string is required, it used for help information.\n- `benchmark.start()` has to be called once in the function body to start measurement. The timeout is counted from this point!\n- All the \"prepare part\" in the function that should not be measured has to be placed before `benchmark.start()`\n- Code to be measured has to go after `benchmark.start()`\n- Try to avoid infinitive loops and assume the test should exit after a while.\n\n## Execution Options\n\n- To pass an arguments set just provide it as a comma separated string like `10,0.1`\n- To pass several argument sets just separate them by white space `10,0.1 20,0.2`\n- `--timeout FLOAT` is test execution timeout in seconds. If the test takes more time, it will be terminated.\n- `--period FLOAT` is measurement interval in seconds, how often to make CPU and RAM usage measurements.\n- `-N, --num-executions INTEGER` - how many times to run the same argument set to make result more accurate.\n- `-P, --plot INTEGER` -  Draw a chart, using values in the argument on the X axis, argument positions started with 0, argument benchmark not counted. For example `-P 0` will use `run_time` values, `-P 1` will use `sleep` values, and so on.\n\n## Limitations\n\nCurrently, the benchmark framework does not measure resources consumed by subprocess spawned in python code. So try to keep one process solutions during tests.\n\nAsynchronous functions or coroutines are not supported directly. So you have to set up an event loop inside test function and start loop manually.\n\n## Testing AEA: Handlers Example\n\nTest react speed on specific messages amount.\n\n``` python\ndef react_speed_in_loop(benchmark: BenchmarkControl, inbox_amount=1000) -> None:\n    \"\"\"\n    Test inbox message processing in a loop.\n\n    :param benchmark: benchmark special parameter to communicate with executor\n    :param inbox_amount: num of inbox messages for every agent\n\n    :return: None\n    \"\"\"\n\n    skill_definition = {\n        \"handlers\": {\"dummy_handler\": DummyHandler}\n    }\n    aea_test_wrapper = AEATestWrapper(\n        name=\"dummy agent\",\n        skills=[skill_definition],\n    )\n\n    for _ in range(inbox_amount):\n        aea_test_wrapper.put_inbox(aea_test_wrapper.dummy_envelope())\n\n    aea_test_wrapper.set_loop_timeout(0.0)\n\n    benchmark.start()\n\n    aea_test_wrapper.start_loop()\n\n    while not aea_test_wrapper.is_inbox_empty():\n        time.sleep(0.1)\n\n    aea_test_wrapper.stop_loop()\n```\n\nCreate AEA wrapper with specified handler:\n\n``` python\nskill_definition = {\n    \"handlers\": {\"dummy_handler\": DummyHandler}\n}\naea_test_wrapper = AEATestWrapper(\n    name=\"dummy agent\",\n    skills=[skill_definition],\n)\n```\n\nPopulate inbox with dummy messages:\n\n``` python\nfor _ in range(inbox_amount):\n    aea_test_wrapper.put_inbox(aea_test_wrapper.dummy_envelope())\n```\n\nSet timeout `0`, for maximum messages processing speed: `aea_test_wrapper.set_loop_timeout(0.0)`\n\nStart benchmark: `benchmark.start()`\n\nStart/stop AEA:\n\n``` python\naea_test_wrapper.start()\n...\naea_test_wrapper.stop()\n```\n\nWait till messages present in inbox:\n\n``` python\nwhile not aea_test_wrapper.is_inbox_empty():\n    time.sleep(0.1)\n```\n"
  },
  {
    "path": "docs/por.md",
    "content": "# Proof of Representation\n\nAn AEA can use several key pairs. In particular, it can use different keys for securing its communication and for engaging in exchange. In the ACN we make use of this fact. To be able to signal to other agents that the address derived from one key pair is allowed to represent the agent controlling the other key pair, the key pair which is being represented must sign a message to prove that the other key pair is allowed to represent it. The `aea issue-certificates` command allows to create this association.\n\nThe proof of representation feature is used in the context of the `fetchai/p2p_libp2p` and `fetchai/p2p_libp2p_client` connection.\n\nIn the former connection, the configuration YAML specifies a `cert_requests` field:\n\n``` yaml\ncert_requests:\n- identifier: acn\n  ledger_id: fetchai\n  not_after: '2023-01-01'\n  not_before: '2022-01-01'\n  public_key: fetchai\n  message_format: '{public_key}'\n  save_path: .certs/conn_cert.txt\n```\n\nThe `identifier` refers to the environment for which the signature is generated, here `acn`. The `ledger_id` refers to the key pair to be used from the `private_key_paths` specified in `aea-config.yaml` for signing. The `not_after` and `not_before` fields specify constraints on the validity of the signature. The `public_key` can specify either the identifier of the key pair in `connection_private_key_paths`, of which the public key is signed, or it can contain the to be signed public key in plain text. The `save_path` specifies the path where the certificate is to be saved at.\n\nIn the above example, the connection requests a certificate which is a signature of the `fetchai` public key in `connection_private_key_paths` with the `fetchai` key pair in `private_key_paths`. The validity of the signature will be constrained to the year `2021` for the environment `acn`.\n"
  },
  {
    "path": "docs/prometheus.md",
    "content": "# Prometheus Monitoring\n\nAEAs can create and update prometheus metrics for remote monitoring by sending messages to the prometheus connection `fetchai/prometheus:0.9.6`.\n\nTo see this working in an agent, fetch and run the `coin_price_feed` agent and check `localhost:9090/metrics` to see the latest values of the metrics `num_retrievals` and `num_requests`:\n\n``` bash\naea fetch fetchai/coin_price_feed:0.15.5\ncd coin_price_feed\naea install\naea build\naea run\n```\n\nYou can then instruct a prometheus server running on the same computing cluster as a deployed agent to scrape these metrics for remote monitoring and visualisation with the Prometheus/Grafana toolset.\n\nTo use this connection, add a model `prometheus_dialogues` to your skill to handle the metrics configuration and messages to the prometheus connection.\n\n??? note \"Click here for example:\"\n    ``` python\n    class PrometheusDialogues(Model, BasePrometheusDialogues):\n        \"\"\"The dialogues class keeps track of all prometheus dialogues.\"\"\"\n\n        def __init__(self, **kwargs) -> None:\n            \"\"\"\n            Initialize dialogues.\n    \n            :return: None\n            \"\"\"\n    \n            self.enabled = kwargs.pop(\"enabled\", False)\n            self.metrics = kwargs.pop(\"metrics\", [])\n    \n            Model.__init__(self, **kwargs)\n    \n            def role_from_first_message(  # pylint: disable=unused-argument\n                message: Message, receiver_address: Address\n            ) -> BaseDialogue.Role:\n                \"\"\"Infer the role of the agent from an incoming/outgoing first message\n    \n                :param message: an incoming/outgoing first message\n                :param receiver_address: the address of the receiving agent\n                :return: The role of the agent\n                \"\"\"\n                return PrometheusDialogue.Role.AGENT\n    \n            BasePrometheusDialogues.__init__(\n                self,\n                self_address=str(self.skill_id),\n                role_from_first_message=role_from_first_message,\n            )\n    ```\n\nThen configure your metrics in the `skill.yaml` file. For example (from the `advanced_data_request` skill):\n\n``` yaml\nmodels:\n  prometheus_dialogues:\n    args:\n      enabled: true\n      metrics:\n      - name: num_retrievals\n        type: Gauge\n        description: Number of price quotes retrieved\n        labels: {}\n      - name: num_requests\n        type: Gauge\n        description: Number of price quote requests served\n        labels: {}\n    class_name: PrometheusDialogues\n```\n\nAdd a metric `metric_name` of type `metric_type` {`Gauge`, `Counter`, ...} and description `description` by sending a message with performative `ADD_METRIC` to the prometheus connection:\n\n``` python\ndef add_prometheus_metric(\n    self,\n    metric_name: str,\n    metric_type: str,\n    description: str,\n    labels: Dict[str, str],\n) -> None:\n    \"\"\"\n    Add a prometheus metric.\n\n    :param metric_name: the name of the metric to add.\n    :param type: the type of the metric.\n    :param description: a description of the metric.\n    :param labels: the metric labels.\n    :return: None\n    \"\"\"\n\n    # context\n    prom_dialogues = cast(PrometheusDialogues, self.context.prometheus_dialogues)\n\n    # prometheus update message\n    message, _ = prom_dialogues.create(\n        counterparty=str(PROM_CONNECTION_ID),\n        performative=PrometheusMessage.Performative.ADD_METRIC,\n        type=metric_type,\n        title=metric_name,\n        description=description,\n        labels=labels,\n    )\n\n    # send message\n    self.context.outbox.put_message(message=message)\n```\n\nwhere `PROM_CONNECTION_ID` should be imported to your skill as follows:\n\n``` python\nfrom packages.fetchai.connections.prometheus.connection import (\n    PUBLIC_ID as PROM_CONNECTION_ID,\n)\n```\n\nUpdate metric `metric_name` with update function `update_func` {`inc`, `set`, `observe`, ...} and value `value` by sending a message with performative `UPDATE_METRIC` to the prometheus connection:\n\n``` python\ndef update_prometheus_metric(\n    self, metric_name: str, update_func: str, value: float, labels: Dict[str, str],\n) -> None:\n    \"\"\"\n    Update a prometheus metric.\n\n    :param metric_name: the name of the metric.\n    :param update_func: the name of the update function (e.g. inc, dec, set, ...).\n    :param value: the value to provide to the update function.\n    :param labels: the metric labels.\n    :return: None\n    \"\"\"\n\n    # context\n    prom_dialogues = cast(PrometheusDialogues, self.context.prometheus_dialogues)\n\n    # prometheus update message\n    message, _ = prom_dialogues.create(\n        counterparty=str(PROM_CONNECTION_ID),\n        performative=PrometheusMessage.Performative.UPDATE_METRIC,\n        title=metric_name,\n        callable=update_func,\n        value=value,\n        labels=labels,\n    )\n\n    # send message\n    self.context.outbox.put_message(message=message)\n```\n\nInitialize the metrics from the configuration file in the behaviour setup:\n\n``` python\ndef setup(self) -> None:\n    \"\"\"Implement the setup of the behaviour\"\"\"\n    prom_dialogues = cast(PrometheusDialogues, self.context.prometheus_dialogues)\n\n    if prom_dialogues.enabled:\n        for metric in prom_dialogues.metrics:\n            self.context.logger.info(\"Adding Prometheus metric: \" + metric[\"name\"])\n            self.add_prometheus_metric(\n                metric[\"name\"], metric[\"type\"], metric[\"description\"], dict(metric[\"labels\"]),\n```\n\nThen call the `update_prometheus_metric` function from the appropriate places.\nFor example, the following code in `handlers.py` for the `advanced_data_request` skill updates the number of http requests served:\n\n``` python\nif self.context.prometheus_dialogues.enabled:\n    self.context.behaviours.advanced_data_request_behaviour.update_prometheus_metric(\n        \"num_requests\", \"inc\", 1.0, {}\n    )\n```\n\nFinally, you can add a `PrometheusHandler` to your skill to process response messages from the prometheus connection.\n\n??? note \"Click here for example:\"\n    ``` python\n    class PrometheusHandler(Handler):\n        \"\"\"This class handles responses from the prometheus server.\"\"\"\n\n        SUPPORTED_PROTOCOL = PrometheusMessage.protocol_id\n    \n        def __init__(self, **kwargs):\n            \"\"\"Initialize the handler.\"\"\"\n            super().__init__(**kwargs)\n    \n            self.handled_message = None\n    \n        def setup(self) -> None:\n            \"\"\"Set up the handler.\"\"\"\n            if self.context.prometheus_dialogues.enabled:\n                self.context.logger.info(\"setting up PrometheusHandler\")\n    \n        def handle(self, message: Message) -> None:\n            \"\"\"\n            Implement the reaction to a message.\n    \n            :param message: the message\n            :return: None\n            \"\"\"\n    \n            message = cast(PrometheusMessage, message)\n    \n            # recover dialogue\n            prometheus_dialogues = cast(\n                PrometheusDialogues, self.context.prometheus_dialogues\n            )\n            prometheus_dialogue = cast(\n                PrometheusDialogue, prometheus_dialogues.update(message)\n            )\n            if prometheus_dialogue is None:\n                self._handle_unidentified_dialogue(message)\n                return\n    \n            self.handled_message = message\n            if message.performative == PrometheusMessage.Performative.RESPONSE:\n                self.context.logger.debug(\n                    f\"Prometheus response ({message.code}): {message.message}\"\n                )\n            else:\n                self.context.logger.debug(\n                    f\"got unexpected prometheus message: Performative = {PrometheusMessage.Performative}\"\n                )\n    \n        def _handle_unidentified_dialogue(self, msg: Message) -> None:\n            \"\"\"\n            Handle an unidentified dialogue.\n    \n            :param msg: the unidentified message to be handled\n            :return: None\n            \"\"\"\n    \n            self.context.logger.info(\n                \"received invalid message={}, unidentified dialogue.\".format(msg)\n            )\n    \n        def teardown(self) -> None:\n            \"\"\"\n            Teardown the handler.\n    \n            :return: None\n            \"\"\"\n    ```\n"
  },
  {
    "path": "docs/protocol-generator.md",
    "content": "# Generating Protocols\n\n## How to Run\n\nFirst make sure you are inside your AEA's folder (see <a href=\"../quickstart\">here</a> on how to create a new agent).\n\nThen run\n\n``` bash\naea generate protocol <path-to-protocol-specification>\n```\n\nwhere `<path-to-protocol-specification>` is the path to a <a href=\"../protocol-generator/#protocol-specification\">protocol specification</a> file.\n\nIf there are no errors, this command will generate the protocol and place it in your AEA project. The name of the protocol's directory will match the protocol name given in the specification. The author will match the registered author in the CLI. The generator currently produces the following files (assuming the name of the protocol in the specification is `sample`):\n\n1. `message.py`: defines messages valid under the `sample` protocol\n2. `serialisation.py`: defines how messages are serialized/deserialized\n3. `__init__.py`: makes the directory a package\n4. `protocol.yaml`: contains package information about the `sample` protocol\n5. `sample.proto` protocol buffer schema file\n6. `sample_pb2.py`: the generated protocol buffer implementation\n7. `custom_types.py`: stub implementations for custom types (created only if the specification contains custom types)\n\n### Full Mode vs Protobuf Only Mode\n\nCurrently, the generator can operate in _full mode_ for Python, creating a complete protocol package (files 1 to 7 above) from a protocol specification. The generator also has a _protobuf only mode_ which only creates the protocol buffer schema and implementation files (files 5 and 6 above). The languages supported in the _protobuf only mode_ and their respective ids are below:\n\n- go: `go`\n- c++: `cpp`\n- java: `java`\n- c&#35;: `csharp`\n- ruby: `ruby`\n- objective-c: `objc`\n- javascript: `js`\n\nTo use the generator in protobuf only mode for any of the above languages:\n\n``` bash\naea generate protocol --l <language> <path-to-protocol-specification>\n```\n\nwhere `<language>` is a language id.\n\nThe protocol buffer compiler requires a plugin to generate Go code. Install it with:\n\n!!! note\n    Note the protocol buffer compiler `protoc` that the generator uses requires a plugin to produce `go` code. Follow <a href=\"../protocol-generator/#protocol-specification\">this instruction</a>.\n\n## Protocol Specification\n\nA protocol can be described in a YAML file. This is called a _protocol specification_. The following is an example protocol specification:\n\n``` yaml\n---\nname: two_party_negotiation\nauthor: fetchai\nversion: 0.1.0\ndescription: An example of a protocol specification that describes a protocol for bilateral negotiation.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nspeech_acts:\n  cfp:\n    query: ct:Query\n  propose:\n    price: pt:float\n    proposal: pt:dict[pt:str, pt:str]\n    conditions: pt:optional[pt:union[pt:str, pt:dict[pt:str,pt:str], pt:set[pt:str]]]\n    resources: pt:list[pt:bytes]\n  accept: {}\n  decline: {}\n...\n---\nct:Query: |\n  bytes query_bytes = 1;\n...\n---\ninitiation: [cfp]\nreply:\n  cfp: [propose, decline]\n  propose: [propose, accept, decline]\n  accept: []\n  decline: []\ntermination: [accept, decline]\nroles: {buyer, seller}\nend_states: [agreement_reached, agreement_unreached]\nkeep_terminal_state_dialogues: true\n...\n```\n\nEach protocol specification must follow the <a href=\"https://pyyaml.org/wiki/PyYAMLDocumentation\" target=\"_blank\">YAML format</a>, and have a minimum of one and a maximum of three YAML documents (each YAML document is enclosed within --- and ...).\n\n### Basic Protocol Detail and Messages Syntax\n\nThe first YAML document is mandatory in any protocol specification. It contains some basic information about the protocol and describes the syntax of communicative messages allowed under this protocol.\n\nThe allowed fields and what they represent are:\n\n- `name`: The name of the protocol (written in <a href=\"https://en.wikipedia.org/wiki/Snake_case\" target=\"_blank\">snake_case</a>)\n- `author`: The creator of the protocol\n- `version`: The current version of the protocol\n- `license`: Licensing information\n- `aea_version`: The version(s) of the framework that support this protocol. The format is described <a href=\"https://www.python.org/dev/peps/pep-0440/\" target=\"_blank\">here</a>.\n- `description`: A short description of the protocol\n- `protocol_specification_id`: The id which identifies the protocol for over-the-wire transport. This id is decoupled from the `protocol_id` (`{author}/{name}:{version}`) which is tied to the Python implementation.\n\nAll of the above fields are mandatory and each is a key/value pair, where both key and value are YAML strings.\n\nAdditionally, the first YAML document of a protocol specification must describe the syntax of valid messages according to this protocol. Therefore, it must contain another mandatory `speech-acts` field which defines the set of _performatives_ valid under this protocol, and a set of _contents_ for each performative.\n\nA _performative_ defines the _type_ of a message (e.g. propose, accept) and has a set of _contents_ (or parameters) of varying types.\n\nThe format of the `speech-act` is as follows: `speech-act` is a dictionary, where each key is a **unique** _performative_ (YAML string), and the value is a _content_ dictionary. If a performative does not have any content, then its content dictionary is empty, for instance `accept` and `decline` in the specification above.\n\nA content dictionary in turn has key/value pairs, where each key is the name of a content (YAML string) and the value is its <a href=\"../protocol-generator/#types\">type</a> (YAML string). For example, the `cfp` (short for 'call for proposal') performative has one content whose name is `query` and whose type is `ct:Query`.\n\n#### Types\n\nThe specific types which could be assigned to contents in a protocol specification are described in the table below.\n\nTypes are either user defined (i.e. custom types) or primitive:\n\n- Custom types are prepended with `ct:` and their format is described using regular expression in the table below.\n- Primitive types are prepended with `pt:`. There are different categories of primitive types. For example, `<PT>` such as integers and booleans, `<PCT>` such as sets and lists, and so on. Primitive types are compositional:\n    - For example, consider `pt:set[...]` under `<PCT>`, i.e. an unordered collection of elements without duplicates. A `pt:set[...]` describes the type of its elements (called \"sub-type\") in square brackets. The subtype of a `pt:set[...]` must be a `<PT>` (e.g. `pt:int`, `pt:bool`).\n    - In describing the format of types, `/` between two subtypes should be treated as \"or\". For example, the subtype of a `pt:optional[...]` is either a `<PT>`, `<CT>`, `<PCT>`, `<PMT>` or `<MT>`.\n\nA multi type denotes an \"or\" separated set of subtypes. For example, a content whose type is specified as `pt:union[pt:str, pt:int]` should either be `pt:int` or `pt:float`.\n\nAn optional type `pt:optional[...]` assigned to a content means the content's existence is optional, but if it is present, its type must match `pt:optional[...]`'s subtype.\n\n| Type                                | Code    | Format                                                        | Example                                  | In Python                          |\n|-------------------------------------|---------|---------------------------------------------------------------|------------------------------------------|------------------------------------|\n| Custom types<sup>1</sup>            | `<CT>`  | `ct:RegExp(^[A-Z][a-zA-Z0-9]*$)`                              | `ct:DataModel`                           | Custom Class                       |\n| Primitive types                     | `<PT>`  | `pt:bytes`                                                    | `pt:bytes`                               | `bytes`                            |\n|                                     |         | `pt:int`                                                      | `pt:int`                                 | `int`                              |\n|                                     |         | `pt:float`                                                    | `pt:float`                               | `float`                            |\n|                                     |         | `pt:bool`                                                     | `pt:bool`                                | `bool`                             |\n|                                     |         | `pt:str`                                                      | `pt:str`                                 | `str`                              |\n| Primitive collection types          | `<PCT>` | `pt:set[<PT>]`                                                | `pt:set[pt:str]`                         | `FrozenSet[str]`                   |\n|                                     |         | `pt:list[<PT>]`                                               | `pt:list[pt:int]`                        | `Tuple[int, ...]`<sup>*</sup>      |\n| Primitive mapping types<sup>2</sup> | `<PMT>` | `pt:dict[<PT>, <PT>]`                                         | `pt:dict[pt:str, pt:bool]`               | `Dict[str, bool]`                  |\n| Multi types                         | `<MT>`  | `pt:union[<PT>/<CT>/<PCT>/<PMT>, ..., <PT>/<CT>/<PCT>/<PMT>]` | `pt:union[ct:DataModel, pt:set[pt:str]]` | `Union[DataModel, FrozenSet[str]]` |\n| Optional types                      | `<O>`   | `pt:optional[<MT>/<PMT>/<PCT>/<PT>/<CT>]`                     | `pt:optional[pt:bool]`                   | `Optional[bool]`                   |\n\n&#42; This is how variable length tuples containing elements of the same type are declared in Python; see <a href=\"https://docs.python.org/3/library/typing.html#typing.Tuple\" target=\"_blank\">here</a>.\n\n### Protocol Buffer Schema\n\nCurrently, the AEA framework does not officially support describing custom types in a programming language independent format. This means that if a protocol specification includes custom types, the required serialisation logic must be provided manually.\n\nTherefore, if any of the contents declared in `speech-acts` is of a custom type, the specification must then have a second YAML document, containing the protocol buffer schema code for each custom type.\n\nYou can see an example of the second YAML document in the above protocol specification.\n\n### Dialogues\n\nYou can optionally specify the structure of dialogues conforming to your protocol in a third YAML document in the specification.\n\nThe allowed fields and what they represent are:\n\n- `initiation`: The list of initial performatives\n- `reply`: The reply structure of speech-acts\n- `termination`: The list of terminal performatives\n- `roles`: The roles of players participating in a dialogue\n- `end_states`: The possible outcomes a terminated dialogue.\n- `keep_terminal_state_dialogues`: whether to keep or drop a terminated dialogue. When a storage backend is configured, the dialogues will be persisted in storage when kept.\n\nAll of the above fields are mandatory.\n\n`initiation` is a YAML list, containing the performatives which can be used to start a dialogue.\n\n`reply` specifies for every performative, what its valid replies are. If a performative `per_1` is a valid reply to another `per_2`, this means a message with performative `per_1` can target a message whose performative is `per_2`.\n\n`reply` is a YAML dictionary, where the keys are the performatives (YAML string) defined in `speech-acts`. For each performative key, its value is a list of performatives which are defined to be a valid reply.\nFor example, valid replies to `cfp` are `propose` and `decline`.\n\n`termination` is a YAML list, containing the performatives which terminate a dialogue. Once any of these performatives are used in a dialogue, the dialogue is terminated and no other messages may be added to it.\n\n`roles` is a YAML set, containing the roles  players participating in dialogues can take. `roles` may contain one or two roles, each role being a YAML string. If there are two roles, each participant has a distinguished role in the dialogue (e.g. buyer and seller in the above specification). If there is only one role, then both participants in a dialogue have this same role.\n\n`end_states` lists the final states a terminated dialogue may have. `end_states` is a YAML list of strings.\n\n`keep_terminal_state_dialogues` has a boolean value and specifies whether the terminated dialogues of this protocol are to be kept or discarded.\n\n## Design Guidelines\n\n1. `initiation` and `termination` cannot be empty.\n\n2. Make sure that when defining `reply`, you include every speech-act you specified under `speech_acts`. If any of the speech-acts does not have a reply, indicate that with an empty list `[]` similar to `accept` and `decline` in the specification above.\n\n3. If a speech-act is listed in `termination`, it must not have any replies in `reply`. The reason is simple: a terminal speech-act terminates a dialogue and so its reply can never be used.\n\n4. If a speech-act replies to no other speech-acts, it should be listed in `initiation` otherwise it could never be used in a dialogue (neither to a start a dialogue with, nor as a reply to another speech-act).\n\n### Notes\n\n1. Currently, there is no way to describe custom types in a programming language independent format. This means that if a protocol specification includes custom types, the required implementations must be provided manually.\n    _ Before generating the protocol, the protocol buffer schema code for every custom type must be provided in the protocol specification.\n    - Once the generator is called, it produces a `custom_types` module containing stub implementations for every custom type in the specification. The user must then modify this module and add implementations for every custom type in the specification. This includes implementations of how an object of a custom type can be encoded and decoded using protocol buffer.\n    - Note, currently the way custom types are dealt with in the generator is admittedly inconvenient. The reason is, the generator does not know the structure of custom types and how they may be serialized/deserialized. Although this approach works, it is only a temporary solution until further work on a programming language-independent type description language is finished (similar to how the generator is designed to be a programming language-independent protocol description language).\n2. Currently, the first element in `pt:dict` cannot be a `<CT>`, `pt:float` or  `pt:bytes`. This is because of a constraint in protocol buffer version 3 which is the framework's underlying serialisation mechanism. In a future version, we may address this limitation, in which case we will relax this constraint.\n3. In protocol buffer version 3, which is the version used by the generator, there is no way to check whether an optional field (i.e. contents of type `pt:optional[...]`) has been set or not (see discussion <a href=\"https://github.com/protocolbuffers/protobuf/issues/1606\" target=\"_blank\">here</a>). In proto3, all optional fields are assigned a default value (e.g. `0` for integers types, `false` for boolean types, etc). Therefore, given an optional field whose value is the default value, there is no way to know from the optional field itself, whether it is not set, or in fact is set but its value happens to be the default value. Because of this, in the generated protocol schema file (the `.proto` file), for every optional content there is a second field that declares whether this field is set or not. We will maintain this temporary solution until a cleaner alternative is found.\n4. Be aware that currently, using the generated protocols in python, there might be some rounding errors when serialising and then deserializing values of `pt:float` contents.\n\n## Demo Instructions\n\nFirst, create a new AEA project:\n\n``` bash\naea create my_aea\ncd my_aea\n```\n\nSecond, run the generator on the sample specification:\n\n``` bash\naea generate protocol ../examples/protocol_specification_ex/sample.yaml\n```\n\nThis will generate the protocol and place it in your AEA project.\n\nThird, try generating other protocols by first defining a specification, then running the generator.\n"
  },
  {
    "path": "docs/protocol.md",
    "content": "# Protocols\n\n<a href=\"../api/protocols/base#protocol-objects\">`Protocols`</a> define the structure of agent-to-agent and component-to-component interactions, which in the AEA world, are in the form of communication. To learn more about interactions and interaction protocols, see <a href=\"../interaction-protocol\">here</a>.\n\nProtocols in the AEA world provide definitions for:\n\n- `messages` defining the structure and syntax of messages;\n- `serialization` defining how a message is encoded/decoded for transport; and optionally\n- `dialogues` defining the structure of dialogues formed from exchanging series of messages.\n\n<img src=\"../assets/protocol.jpg\" alt=\"Protocol simplified\" class=\"center\" style=\"display: block; margin-left: auto; margin-right: auto;width:80%;\">\n\nThe framework provides a `default` protocol. This protocol provides a bare-bones implementation for an AEA protocol which includes a <a href=\"../api/protocols/default/message#packages.fetchai.protocols.default.message\">`DefaultMessage`</a>  class and associated <a href=\"../api/protocols/default/serialization#packages.fetchai.protocols.default.serialization\">`DefaultSerializer`</a> and <a href=\"../api/protocols/default/dialogues#packages.fetchai.protocols.default.dialogues\">`DefaultDialogue`</a> classes.\n\nAdditional protocols - i.e. a new type of interaction - can be added as packages or generated with the <a href=\"../protocol-generator\">protocol generator</a>.\n\nWe highly recommend you to **not** attempt writing your protocol manually as they tend to have involved logic; always use existing packages or the protocol generator!\n\n## Components of a Protocol\n\nA protocol package contains the following files:\n\n- `__init__.py`\n- `message.py`, which defines message representation\n- `serialization.py`, which defines the encoding and decoding logic\n- two protobuf related files\n\nIt optionally also contains\n\n- `dialogues.py`, which defines the structure of dialogues formed from the exchange of a series of messages\n- `custom_types.py`, which defines custom types\n\nAll protocols are for point to point interactions between two agents or agent-like services.\n\n## Metadata\n\nEach `Message` in an interaction protocol has a set of default fields:\n\n- `dialogue_reference: Tuple[str, str]`, a reference of the dialogue the message is part of. The first part of the tuple is the reference assigned to by the agent who first initiates the dialogue (i.e. sends the first message). The second part of the tuple is the reference assigned to by the other agent. The default value is `(\"\", \"\")`.\n- `message_id: int`, the identifier of the message in a dialogue. The default value is `1`.\n- `target: int`, the id of the message this message is replying to. The default value is `0`.\n- `performative: Enum`, the purpose/intention of the message.\n- `sender: Address`, the address of the sender of this message.\n- `to: Address`, the address of the receiver of this message.\n\nThe default values for `message_id` and `target` assume the message is the first message in a dialogue. Therefore, the `message_id` is set to `1` indicating the first message in the dialogue and `target` is `0` since the first message is the only message that does not reply to any other.\n\nBy default, the values of `dialogue_reference`, `message_id`, `target` are set. However, most interactions involve more than one message being sent as part of the interaction and potentially multiple simultaneous interactions utilising the same protocol. In those cases, the `dialogue_reference` allows different interactions to be identified as such. The `message_id` and `target` are used to keep track of messages and their replies. For instance, on receiving of a message with `message_id=1` and `target=0`, the responding agent could respond with another with `message_id=2` and `target=1` replying to the first message. In particular, `target` holds the id of the message being replied to. This can be the preceding message, or an older one.\n\n## Contents\n\nEach message may optionally have any number of contents of varying types.\n\n## Dialogue Rules\n\nProtocols can optionally have a dialogue module. A _dialogue_, respectively _dialogues_ object, maintains the state of a single, respectively, all dialogues associated with a protocol.\n\nThe framework provides a number of helpful classes which implement most of the logic to maintain dialogues, namely the <a href=\"../api/protocols/dialogue/base#dialogue-objects\">`Dialogue`</a> and <a href=\"../api/protocols/dialogue/base#dialogues-objects\">`Dialogues`</a> base classes.\n\n## Custom Protocol\n\nThe developer can generate custom protocols with the <a href=\"../protocol-generator\">protocol generator</a>. This lets the developer specify the speech-acts as well as optionally the dialogue structure (e.g. roles of agents participating in a dialogue, the states a dialogue may end in, and the reply structure of the speech-acts in a dialogue).\n\nWe highly recommend you **do not** attempt to write your own protocol code; always use existing packages or the protocol generator!\n\n## `fetchai/default:1.1.7` Protocol\n\nThe `fetchai/default:1.1.7` protocol is meant to be implemented by every AEA. It serves AEA to AEA interaction and includes three message performatives:\n\n``` python\nfrom enum import Enum\n\nclass Performative(Enum):\n    \"\"\"Performatives for the default protocol.\"\"\"\n\n    BYTES = \"bytes\"\n    END = \"end\"\n    ERROR = \"error\"\n\n    def __str__(self):\n        \"\"\"Get the string representation.\"\"\"\n        return self.value\n```\n\n- The `DefaultMessage` of performative `DefaultMessage.Performative.BYTES` is used to send payloads of byte strings to other AEAs. An example is:\n\n``` python\nfrom packages.fetchai.protocols.default.message import DefaultMessage\n\nmsg = DefaultMessage(\n    performative=DefaultMessage.Performative.BYTES,\n    content=b\"This is a bytes payload\",\n)\n```\n\n- The `DefaultMessage` of performative `DefaultMessage.Performative.ERROR` is used to notify other AEAs of errors in an interaction, including errors with other protocols, by including an `error_code` in the payload:\n\n``` python\nclass ErrorCode(Enum):\n    \"\"\"This class represents an instance of ErrorCode.\"\"\"\n\n    UNSUPPORTED_PROTOCOL = 0\n    DECODING_ERROR = 1\n    INVALID_MESSAGE = 2\n    UNSUPPORTED_SKILL = 3\n    INVALID_DIALOGUE = 4\n```\n\nAn example is:\n\n``` python\nmsg = DefaultMessage(\n    performative=DefaultMessage.Performative.ERROR,\n    error_code=DefaultMessage.ErrorCode.UNSUPPORTED_PROTOCOL,\n    error_msg=\"This protocol is not supported by this AEA.\",\n    error_data={\"unsupported_msg\": b\"serialized unsupported protocol message\"},\n)\n```\n\n- The `DefaultMessage` of performative `DefaultMessage.Performative.END` is used to terminate a default protocol dialogue. An example is:\n\n``` python\nfrom packages.fetchai.protocols.default.message import DefaultMessage\n\nmsg = DefaultMessage(\n    performative=DefaultMessage.Performative.END,\n)\n```\n\nEach AEA's `fetchai/error:0.18.6` skill utilises the `fetchai/default:1.0.0` protocol for error handling.\n\n## `fetchai/oef_search:1.1.7` Protocol\n\nThe `fetchai/oef_search:1.1.7` protocol is used by AEAs to interact with an <a href=\"../simple-oef\">SOEF search node</a> to register and unregister their own services and search for services registered by other agents.\n\nThe `fetchai/oef_search:1.1.7` protocol definition includes an `OefSearchMessage` with the following message types:\n\n``` python\nclass Performative(Enum):\n\n    \"\"\"Performatives for the oef_search protocol.\"\"\"\n    REGISTER_SERVICE = \"register_service\"\n    UNREGISTER_SERVICE = \"unregister_service\"\n    SEARCH_SERVICES = \"search_services\"\n    OEF_ERROR = \"oef_error\"\n    SEARCH_RESULT = \"search_result\"\n    SUCCESS = \"success\"\n\n    def __str__(self):\n        \"\"\"Get string representation.\"\"\"\n        return self.value\n```\n\nWe show some example messages below:\n\n- To register a service, we require a reference to the dialogue in string form (used to keep different dialogues apart), for instance\n\n``` python\nmy_dialogue_reference = \"a_unique_register_service_dialogue_reference\"\n```\n\nand a description of the service we would like to register, for instance\n\n``` python\nfrom aea.helpers.search.models import Description\n\nmy_service_data = {\"country\": \"UK\", \"city\": \"Cambridge\"}\nmy_service_description = Description(\n    my_service_data,\n    data_model=my_data_model,\n)\n```\n\nwhere we use, for instance\n\n``` python\nfrom aea.helpers.search.generic import GenericDataModel\n\ndata_model_name = \"location\"\ndata_model = {\n    \"attribute_one\": {\n        \"name\": \"country\",\n        \"type\": \"str\",\n        \"is_required\": True,\n    },\n    \"attribute_two\": {\n        \"name\": \"city\",\n        \"type\": \"str\",\n        \"is_required\": True,\n    },\n}\nmy_data_model = GenericDataModel(data_model_name, data_model)\n```\n\nWe can then create the message to register this service:\n\n``` python\nmsg = OefSearchMessage(\n    performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n    dialogue_reference=(my_dialogue_reference, \"\"),\n    service_description=my_service_description,\n)\n```\n\n- To unregister a service, we require a reference to the dialogue in string form, for instance\n\n``` python\nmy_dialogue_reference = \"a_unique_unregister_service_dialogue_reference\"\n```\n\nthe description of the service we would like to unregister, say `my_service_description` from above and construct the message:\n\n``` python\nmsg = OefSearchMessage(\n    performative=OefSearchMessage.Performative.UNREGISTER_SERVICE,\n    dialogue_reference=(my_dialogue_reference, \"\"),\n    service_description=my_service_description,\n)\n```\n\n- To search a service, we similarly require a reference to the dialogue in string form, and then the query we would like the search node to evaluate, for instance\n\n``` python\nfrom aea.helpers.search.models import Constraint, ConstraintType, Query\n\nquery_data = {\n    \"search_term\": \"country\",\n    \"search_value\": \"UK\",\n    \"constraint_type\": \"==\",\n}\nquery = Query(\n    [\n        Constraint(\n            query_data[\"search_term\"],\n            ConstraintType(\n                query_data[\"constraint_type\"],\n                query_data[\"search_value\"],\n            ),\n        )\n    ],\n    model=None,\n)\n```\n\nWe can then create the message to search these services:\n\n``` python\noef_msg = OefSearchMessage(\n    performative=OefSearchMessage.Performative.SEARCH_SERVICES,\n    dialogue_reference=(my_dialogue_reference, \"\"),\n    query=query,\n)\n```\n\n- The <a href=\"../simple-oef\">SOEF search node</a> will respond with a message `msg` of type `OefSearchMessage` with performative `OefSearchMessage.Performative.SEARCH_RESULT`. To access the tuple of agents which match the query, simply use `msg.agents`. In particular, this will return the agent addresses matching the query. The <a href=\"../identity\">agent address</a> can then be used to send a message to the agent utilising the <a href=\"../acn\">P2P agent communication network</a> and any protocol other than `fetchai/oef_search:1.0.0`.\n\n- If the <a href=\"../simple-oef\">SOEF search node</a> encounters any errors with the messages you send, it will return an `OefSearchMessage` of performative `OefSearchMessage.Performative.OEF_ERROR` and indicate the error operation encountered:\n\n``` python\nclass OefErrorOperation(Enum):\n\n    \"\"\"This class represents an instance of OefErrorOperation.\"\"\"\n    REGISTER_SERVICE = 0\n    UNREGISTER_SERVICE = 1\n    SEARCH_SERVICES = 2\n    SEND_MESSAGE = 3\n\n    OTHER = 10000\n```\n\n## `fetchai/fipa:1.1.7` Protocol\n\nThis protocol provides classes and functions necessary for communication between AEAs via a variant of the <a href=\"https://en.wikipedia.org/wiki/Foundation_for_Intelligent_Physical_Agents\" target=\"_blank\">FIPA</a> Agent Communication Language.\n\nThe `fetchai/fipa:1.1.7` protocol definition includes a `FipaMessage` with the following performatives:\n\n``` python\nclass Performative(Enum):\n    \"\"\"Performatives for the fipa protocol.\"\"\"\n\n    ACCEPT = \"accept\"\n    ACCEPT_W_INFORM = \"accept_w_inform\"\n    CFP = \"cfp\"\n    DECLINE = \"decline\"\n    END = \"end\"\n    INFORM = \"inform\"\n    MATCH_ACCEPT = \"match_accept\"\n    MATCH_ACCEPT_W_INFORM = \"match_accept_w_inform\"\n    PROPOSE = \"propose\"\n\n    def __str__(self):\n        \"\"\"Get the string representation.\"\"\"\n        return self.value\n```\n\n`FipaMessages` are constructed with a `performative`, `dialogue_reference`, `message_id`, and `target` as well as the `kwargs` specific to each message performative.\n\n``` python\ndef __init__(\n    self,\n    performative: Performative,\n    dialogue_reference: Tuple[str, str] = (\"\", \"\"),\n    message_id: int = 1,\n    target: int = 0,\n    **kwargs,\n)\n```\n\nThe `fetchai/fipa:1.1.7` protocol also defines a `FipaDialogue` class which specifies the valid reply structure and provides other helper methods to maintain dialogues.\n\nFor examples of the usage of the `fetchai/fipa:1.1.7` protocol check out the <a href=\"../generic-skills-step-by-step\" target=\"_blank\"> generic skills step by step guide</a>.\n\n### Fipa Dialogue\n\nBelow, we give an example of a dialogue between two agents. In practice; both dialogues would be maintained in the respective agent.\n\nWe first create concrete implementations of `FipaDialogue` and `FipaDialogues` for the buyer and seller:\n\n``` python\nfrom aea.common import Address\nfrom aea.helpers.search.models import Constraint, ConstraintType, Description, Query\nfrom aea.mail.base import Envelope\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\nfrom aea.protocols.dialogue.base import DialogueLabel\n\nfrom packages.fetchai.protocols.fipa.dialogues import FipaDialogue, FipaDialogues\nfrom packages.fetchai.protocols.fipa.message import FipaMessage\n\n\nclass BuyerDialogue(FipaDialogue):\n    \"\"\"The dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    def __init__(\n        self,\n        dialogue_label: DialogueLabel,\n        self_address: Address,\n        role: BaseDialogue.Role,\n        message_class: Type[FipaMessage] = FipaMessage,\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n\n        :return: None\n        \"\"\"\n        FipaDialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            self_address=self_address,\n            role=role,\n            message_class=message_class,\n        )\n        self.proposal = None  # type: Optional[Description]\n\n\nclass BuyerDialogues(FipaDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, self_address: Address) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :return: None\n        \"\"\"\n        def role_from_first_message(\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return BaseFipaDialogue.Role.BUYER\n\n        FipaDialogues.__init__(\n            self,\n            self_address=self_address,\n            role_from_first_message=role_from_first_message,\n            dialogue_class=FipaDialogue,\n        )\n\n\nclass SellerDialogue(FipaDialogue):\n    \"\"\"The dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    def __init__(\n        self,\n        dialogue_label: DialogueLabel,\n        self_address: Address,\n        role: BaseDialogue.Role,\n        message_class: Type[FipaMessage] = FipaMessage,\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n\n        :return: None\n        \"\"\"\n        FipaDialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            self_address=self_address,\n            role=role,\n            message_class=message_class,\n        )\n        self.proposal = None  # type: Optional[Description]\n\n\nclass SellerDialogues(FipaDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, self_address: Address) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :return: None\n        \"\"\"\n        def role_from_first_message(\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return FipaDialogue.Role.SELLER\n\n        FipaDialogues.__init__(\n            self,\n            self_address=self_address,\n            role_from_first_message=role_from_first_message,\n            dialogue_class=FipaDialogue,\n        )\n```\n\nNext, we can imitate a dialogue between the buyer and the seller. We first instantiate the dialogues models:\n\n``` python\nbuyer_address = \"buyer_address_stub\"\nseller_address = \"seller_address_stub\"\nbuyer_dialogues = BuyerDialogues(buyer_address)\nseller_dialogues = SellerDialogues(seller_address)\n```\n\nFirst, the buyer creates a message destined for the seller and updates the dialogues:\n\n``` python\ncfp_msg = FipaMessage(\n    message_id=1,\n    dialogue_reference=buyer_dialogues.new_self_initiated_dialogue_reference(),\n    target=0,\n    performative=FipaMessage.Performative.CFP,\n    query=Query([Constraint(\"something\", ConstraintType(\">\", 1))]),\n)\ncfp_msg.counterparty = seller_addr\n\n# Extends the outgoing list of messages.\nbuyer_dialogue = buyer_dialogues.update(cfp_msg)\n```\n\nIf the message has been correctly constructed, the `buyer_dialogue` will be returned, otherwise it will be `None`.\n\nIn a skill, the message could now be sent:\n\n``` python\n# In a skill we would do:\n# self.context.outbox.put_message(message=cfp_msg)\n```\n\nHowever, here we simply continue with the seller:\n\n``` python\n# change the incoming message field & counterparty\ncfp_msg.is_incoming = True\ncfp_msg.counterparty = buyer_address\n```\n\nIn the skill, the above two lines will be done by the framework; you can simply receive the message in the handler.\n\nWe update the seller's dialogues model next to generate a new dialogue:\n\n``` python\n# Creates a new dialogue for the seller side based on the income message.\nseller_dialogue = seller_dialogues.update(cfp_msg)\n```\n\nNext, the seller can generate a proposal:\n\n``` python\n# Generate a proposal message to send to the buyer.\nproposal = Description({\"foo1\": 1, \"bar1\": 2})\nmessage_id = cfp_msg.message_id + 1\ntarget = cfp_msg.message_id\nproposal_msg = FipaMessage(\n    message_id=message_id,\n    dialogue_reference=seller_dialogue.dialogue_label.dialogue_reference,\n    target=target,\n    performative=FipaMessage.Performative.PROPOSE,\n    proposal=proposal,\n)\nproposal_msg.counterparty = cfp_msg.counterparty\n\n# Then we update the dialogue\nseller_dialogue.update(proposal_msg)\n```\n\nIn a skill, the message could now be sent:\n\n``` python\n# In a skill we would do:\n# self.context.outbox.put_message(message=proposal_msg)\n```\n\nThe dialogue can continue like this.\n\nTo retrieve a dialogue for a given message, we can do the following:\n\n``` python\nretrieved_dialogue = seller_dialogues.get_dialogue(cfp_msg)\n```\n"
  },
  {
    "path": "docs/query-language.md",
    "content": "# The Query Language\n\nWe recommend reading <a href=\"../defining-data-models\">Defining a Data Model</a> before reading this section.\n\nAlong with the Data Model language, the AEA framework offers the possibility to specify _queries_ defined over data models.\n\nThe `aea.helpers.search` module implements the API that allows you to build queries.\n\nIn one sentence, a <a href=\"../api/helpers/search/models#query-objects\">`Query`</a> is a set of _constraints_, defined over a _data model_.\nThe outcome is a set of _description_ (that is, instances of <a href=\"../api/helpers/search/models#description-objects\">`Description`</a>)\n_matching_ with the query. That is, all the description whose attributes satisfy the constraints in the query.\n\nIn the next sections, we describe how to build queries.\n\n## Constraints\n\nA <a href=\"../api/helpers/search/models#constraint-objects\">`Constraint`</a> is associated with an _attribute name_ and imposes restrictions on the domain of that attribute.\nThat is, it imposes some limitations on the values the attribute can assume.\n\nWe have different types of constraints:\n\n- _relation_ constraints:\n\n  - the author of the book must be _Stephen King_\n  - the publication year must be greater than 1990\n\n- _set_ constraints:\n\n  - the genre must fall into the following set of genres: _Horror_, _Science fiction_, _Non-fiction_.\n\n- _range_ constraints:\n\n  - the average rating must be between 3.5 and 4.5\n\n- _distance_ constraints:\n\n  - the nearest bookshop must be within a distance from a given location.\n\nThe class that implements the constraint concept is `Constraint`\nIn the following, we show how to define them.\n\n### Relation\n\nThere are several <a href=\"../api/helpers/search/models#constrainttype-objects\">`ConstraintTypes`</a> that allows you to impose specific values for the attributes.\n\nThe types of relation constraints are:\n\n- Equal: `==`\n- Not Equal: `!=`\n- Less than: `<`\n- Less than or Equal: `<=`\n- Greater than: `>`\n- Greater than or Equal: `>=`\n\n**Examples**: using the attributes we used before:\n\n``` python\nfrom aea.helpers.search.models import Constraint, ConstraintType\n\n# all the books whose author is Stephen King\nConstraint(\"author\", ConstraintType(\"==\", \"Stephen King\"))\n\n# all the books that are not of the genre Horror\nConstraint(\"genre\", ConstraintType(\"!=\", \"Horror\"))\n\n# all the books published before 1990\nConstraint(\"year\", ConstraintType(\"<\", 1990))\n\n# the same of before, but including 1990\nConstraint(\"year\", ConstraintType(\"<=\", 1990))\n\n# all the books with rating greater than 4.0\nConstraint(\"average_rating\", ConstraintType(\">\", 4.0))\n\n# all the books published after 2000, included\nConstraint(\"year\", ConstraintType(\">=\", 2000))\n```\n\n### Set\n\nThe _set_ is a constraint type that allows you to restrict the values of the attribute in a specific set.\n\nThere are two kind of _set_ constraints:\n\n- In (a set of values): `in`\n- Not in (a set of values): `not_in`\n\n**Examples**:\n\n``` python\nfrom aea.helpers.search.models import Constraint, ConstraintType\n\n# all the books whose genre is one of `Horror`, `Science fiction`, `Non-fiction`\nConstraint(\"genre\", ConstraintType(\"in\", (\"horror\", \"science fiction\", \"non-fiction\")))\n\n# all the books that have not been published neither in 1990, nor in 1995, nor in 2000\nConstraint(\"year\", ConstraintType(\"not_in\", (1990, 1995, 2000)))\n```\n\n## Range\n\nThe _range_ is a constraint type that allows you to restrict the values of the attribute in a given range.\n\n**Examples**:\n\n``` python\nfrom aea.helpers.search.models import Constraint, ConstraintType\n\n# all the books whose title is between 'A' and 'B' (alphanumeric order)\nConstraint(\"title\", ConstraintType(\"within\", (\"A\", \"B\")))\n\n# all the books that have been published between 1960 and 1970\nConstraint(\"genre\", ConstraintType(\"within\", (1960, 1970)))\n```\n\n### Distance\n\nThe _distance_ is a constraint type that allows you to put a limit on a <a href=\"../api/helpers/search/models#location-objects\">`Location`</a> attribute type. More specifically, you can set a maximum distance from a given location (the _centre_), such that will be considered only the instances whose location attribute value is within a distance from the centre.\n\n**Examples**:\n\n``` python\nfrom aea.helpers.search.models import Constraint, ConstraintType, Description, Location\n\n# define a location of interest, e.g. the Tour Eiffel\ntour_eiffel = Location(48.8581064, 2.29447)\n\n# find all the locations close to the Tour Eiffel within 1 km\nclose_to_tour_eiffel = Constraint(\"position\", ConstraintType(\"distance\", (tour_eiffel, 1.0)))\n\n# Le Jules Verne, a famous restaurant close to the Tour Eiffel, satisfies the constraint.\nle_jules_verne_restaurant = Location(48.8579675, 2.2951849)\nclose_to_tour_eiffel.check(Description({\"position\": le_jules_verne_restaurant}))  # gives `True`\n\n# The Colosseum does not satisfy the constraint (farther than 1 km from the Tour Eiffel).\ncolosseum = Location(41.8902102, 12.4922309)\nclose_to_tour_eiffel.check(Description({\"position\": colosseum}))  # gives `False`\n```\n\n## Constraint Expressions\n\nThe constraints mentioned above can be combined with the common logical operators (i.e. and, or and not), yielding more complex expression.\n\nIn particular, we can specify any conjunction/disjunction/negations of the previous constraints or composite <a href=\"../api/helpers/search/models#constraintexpression-objects\">`ConstraintExpressions`</a>, e.g.:\n\n- books that belong to _Horror_ **and** has been published after 2000, but **not** published by _Stephen King_.\n- books whose author is **either** _J. K. Rowling_ **or** _J. R. R. Tolkien_\n\nThe classes that implement these operators are `Not`, `And` and `Or`.\n\n### Not\n\nThe `Not` is a constraint expression that allows you to specify a negation of a constraint expression. The `Not` constraint is satisfied whenever its subexpression is _not_ satisfied.\n\n**Example**:\n\n``` python\nfrom aea.helpers.search.models import Constraint, ConstraintType, Not\n\n# all the books whose year of publication is not between 1990 and 2000\nNot(Constraint(\"year\", ConstraintType(\"within\", (1990, 2000))))\n```\n\n### And\n\nThe `And` is a constraint type that allows you to specify a conjunction of constraints over an attribute. That is, the `And` constraint is satisfied whenever all the subexpressions that constitute the _and_ are satisfied.\n\nNotice: the number of subexpressions must be **at least** 2.\n\n**Example**:\n\n``` python\nfrom aea.helpers.search.models import Constraint, ConstraintType, And\n\n# all the books whose title is between 'I' and 'J' (alphanumeric order) but not equal to 'It'\nAnd([Constraint(\"title\", ConstraintType(\"within\", (\"I\", \"J\"))), Constraint(\"title\", ConstraintType(\"!=\", \"It\"))])\n```\n\n### Or\n\nThe class `Or` is a constraint type that allows you to specify a disjunction of constraints. That is, the `Or` constraint is satisfied whenever at least one of the constraints that constitute the `or` is satisfied.\n\nNotice: the number of subexpressions must be **at least** 2.\n\n**Example**:\n\n``` python\nfrom aea.helpers.search.models import Constraint, ConstraintType, Or\n\n# all the books that have been published either before the year 1960 or after the year 1970\nOr([Constraint(\"year\", ConstraintType(\"<\", 1960)), Constraint(\"year\", ConstraintType(\">\", 1970))])\n```\n\n## Queries\n\nA _query_ is simply a _list of constraint expressions_, interpreted as a conjunction (that is, a matching description with the query must satisfy _every_ constraint expression.)\n\n**Examples**:\n\n``` python\nfrom aea.helpers.search.models import Query, Constraint, ConstraintType\n\n# query all the books written by Stephen King published after 1990, and available as an e-book:\nQuery([\n    Constraint(\"author\", ConstraintType(\"==\", \"Stephen King\")),\n    Constraint(\"year\", ConstraintType(\">=\", 1990)),\n    Constraint(\"ebook_available\", ConstraintType(\"==\", True))\n], book_model)\n```\n\nWhere `book_model` is the `DataModel` object. However, the data model is\nan optional parameter, but to avoid ambiguity is recommended to include it.\n\n### The ``check`` Method\n\nThe `Query` class supports a way to check whether a `Description` matches with the query. This method is called `Query.check`.\n\nExamples:\n\n``` python\nfrom aea.helpers.search.models import Query, Constraint, ConstraintType\nfrom aea.helpers.search.models import Description\n\nq = Query([\n    Constraint(\"author\", ConstraintType(\"==\", \"Stephen King\")),\n    Constraint(\"year\", ConstraintType(\">=\", 1990)),\n    Constraint(\"ebook_available\", ConstraintType(\"==\", True))\n    ])\n\n# With a query, you can check that a `Description` object satisfies the constraints.\nq.check(Description({\"author\": \"Stephen King\", \"year\": 1991, \"ebook_available\": True}))  # True\nq.check(Description({\"author\": \"George Orwell\", \"year\": 1948, \"ebook_available\": False})) # False\n```\n\n### Validity\n\nA `Query` object must satisfy some conditions in order to be instantiated.\n\n- The list of constraints expressions can't be empty; must have at least one constraint expression.\n- If the data model is specified:\n\n    - For every constraint expression that constitute the query, check if they are _valid with respect to the data model_.\n\nA `ConstraintExpr` `c` (that is, one of `And`, `Or`, `Not`, `Constraint`) is _valid with respect to a_ `DataModel` if:\n\n- If `c` is an instance of `And`, `Or` or `Not`, then\n  every subexpression of `c` must be valid (with respect to the data model);\n- If `c` is an instance of `Constraint`, then:\n    - if the constraint type is one of `<`, `<=`, `>`,\n      `>=`, the value in the constructor must be one of `str`, `int` or `float`.\n    - if the constraint type is a `within`, then the types in the range must be one of `int`, `str`, `float` or `Location`.\n    - if the constraint type is a `distance`, then the only valid type is `Location`.\n    - if the constraint type is a `in`, then the types supported are\n      `str`, `int`, `float`, `bool`, `Location`. Notice though that a set of ``bool`` is trivial, so you may find yourself more comfortable by using other alternatives.\n    - for the other constraint types, i.e. `==` and `!=`, the value can be one of the allowed types for `Attribute`, that is `str`, `int`, `float`, `bool`, `Location`.\n\n- Moreover, when `c` is a `Constraint`, the attribute must have a consistent type with respect to the data model.\n  E.g. consider a `Constraint` like:\n\n``` python\nConstraint(\"foo\", ConstraintType(\"==\", True))\n```\n\nConsider a `DataModel` where there is an `Attribute` `\"foo\"` of type `str`. Then the constraint is not compatible with the mentioned data model, because the constraint expect an equality comparison with a boolean `True`, instead of a `str`.\n"
  },
  {
    "path": "docs/questions-and-answers.md",
    "content": "# Q&A\n\n??? question \"What is an AEA?\"\n    AEA stands for \"Autonomous Economic Agent\". An AEA can represent an individual, organisation or object and looks after its owner's interests. AEAs act independently of constant user input and autonomously execute actions to achieve their prescribed goals. Their purpose is to create economic value for their owners.\n\n??? question \"How do AEAs talk to each other when they do not know each other?\"\n    For an Autonomous Economic Agent (AEA) to talk to other AEAs, it first needs to find them. Once it does, it should ensure that they both use the same protocol for communication, and if so, they then have to send messages to each other.\n\n    The AEA framework, together with some of the services it provides, address all three problems. You can read more about search and discovery <a href=\"../ecosystem/\">here</a>, protocols <a href=\"../core-components-1/\">here</a>, and the Agent Communication Network (ACN) <a href=\"../acn/\">here</a>.\n\n??? question \"How does an AEA use blockchain?\"\n    The AEA framework enables agents to interact with blockchains to settle transactions. Currently, the framework has native support for three different networks: _Fetch.ai_, _Ethereum_ and _Cosmos_.\n\n    You can read more about the framework's integration with the different blockchains <a href=\"../ledger-integration/\">here</a> and gain a high level overview <a href=\"../ecosystem/\">here</a>.\n\n??? question \"How does one install third party libraries?\"\n    The framework supports the use of third-party libraries hosted on <a href=\"https://pypi.org\" target=\"_blank\">PyPI</a>. You can directly reference the external dependencies of an AEA package (e.g. skill) in its configuration file. From inside an AEA's project directory, the `install` command can be used to install all the dependencies of the AEA which are listed in the configuration files belonging to any of its packages.\n\n??? question \"How does one connect to a database?\"\n    You have two options to connect to a database: using the built-in storage solution or using a custom ORM (object-relational mapping) library and backend.\n\n    The use of the built-in storage is explained <a href=\"../generic-storage/\">here</a>. For a detailed example of how to use an ORM, follow the <a href=\"../orm-integration/\">ORM guide</a>.\n\n??? question \"How does one connect a frontend?\"\n    There are multiple options. The most obvious is using an HTTP server connection and creating a client that communicates with this connection.\n\n    You can find a more detailed discussion <a href=\"../connect-a-frontend/\">here</a>.\n\n??? question \"Is the AEA framework ideal for agent-based modelling?\"\n    The goal of agent-based modelling (ABM) is to study the unknown (often complex) behaviour of systems comprised of agents with known (much simpler) behaviour. ABM is a popular technique for studying biological and social systems. Despite some similarities between ABM and the AEA framework, the two have fundamentally different goals. ABM's goal is not the design of agents or solving specific practical or engineering problems. Although it would be potentially possible, it would likely be inefficient to use the AEA framework for that kind of problems.\n\n    You can find more details on the application areas of the AEA framework <a href=\"../application/\">here</a>.\n\n??? question \"When a new AEA is created, is the `vendor` folder populated with some default packages?\"\n    All AEA projects by default hold the `fetchai/default:1.1.7`, `fetchai/state_update:1.1.7` and `fetchai/signing:1.1.7` protocols. These (as all other packages installed from the registry) are placed in the `vendor` folder.\n\n    You can find more details about the file structure <a href=\"../package-imports/\">here</a>.\n\n??? question \"Is there a standardization for private key files?\"\n    Currently, the private keys are stored in `.txt` files. This is temporary and will be improved soon.\n\n??? question \"How to use the same protocol in different skills?\"\n    The details of envelope/message routing by the AEA framework are discussed in <a href=\"../message-routing/\">this guide</a>.\n\n??? question \"Why does the AEA framework use its own package registry?\"\n    AEA packages could be described as personalized plugins for the AEA runtime. They are not like a library - they have no direct use outside the context of the framework - and therefore are not suitable for distribution via <a href=\"https://pypi.org/\" target=\"_blank\">PyPI</a>.\n"
  },
  {
    "path": "docs/quickstart.md",
    "content": "# AEA Quick Start\n\nIf you want to create Autonomous Economic Agents (AEAs) that can act independently of constant user input and autonomously execute actions to achieve their objective, you can use the AEA framework.\n\n<iframe width=\"560\" height=\"315\" src=\"https://www.youtube.com/embed/mwkAUh-_uxA\" frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen></iframe>\n\nThis example will take you through a simple AEA to familiarise you with the basics of the framework.\n\n## Echo Skill Demo\n\nThis is a simple demo that introduces you to the main components of an AEA.\n\nThe fastest way to have your first AEA is to fetch one that already exists!\n\n``` bash\naea fetch fetchai/my_first_aea:0.28.5\ncd my_first_aea\n```\n\nTo learn more about the folder structure of an AEA project read on <a href=\"../package-imports/\">here</a>.\n\n??? note \"Alternatively: step by step install:\"\n    **Create a new AEA**\n\n    First, create a new AEA project and enter it.\n\n    ``` bash\n    aea create my_first_aea\n    cd my_first_aea\n    ```\n\n    **Add the stub connection**\n\n    Second, add the stub connection to the project.\n\n    ``` bash\n    aea add connection fetchai/stub:0.21.3\n    ```\n\n    **Add the echo skill**\n\n    Third, add the echo skill to the project.\n\n    ``` bash\n    aea add skill fetchai/echo:0.20.6\n    ```\n\n    This copies the <code>fetchai/echo:0.20.6</code> skill code containing the \"behaviours\", and \"handlers\" into the project, ready to run. The identifier of the skill <code>fetchai/echo:0.20.6</code> consists of the name of the author of the skill, followed by the skill name and its version.\n\n### Echo Skill\n\nJust like humans, AEAs can have _skills_ to achieve their tasks. As an agent developer, you can create skills to add to your own AEAs. You can also choose to publish your skills so others add them to their AEAs. More details on skills can be found on <a href=\"../skill/\"> this page </a>.\n\nThe above agent has an <a href=\"https://aea-registry.fetch.ai/details/skill/fetchai/echo/latest\" target=\"_blank\">echo skill</a>, fetched from <a href=\"https://aea-registry.fetch.ai\" target=\"_blank\">the registry</a>, which simply echoes any messages it receives back to its sender.\n\n### Communication via Envelopes and Messages\n\nAEAs use envelopes containing messages for communication. To learn more, check out the <a href=\"../core-components-1/\">next section</a>.\n\n### Stub Connection\n\nBesides skills, AEAs may have one or more _connections_ enabling them to interface with entities in the outside world. For example, an HTTP client connection allows an AEA to communicate with HTTP servers. To read more about connections see <a href=\"../connection/\">this page</a>.\n\nIn this demo, we use the stub connection (`fetchai/stub0.15.0`) to send envelopes to and receive envelopes from the AEA.\n\nA stub connection provides an I/O reader and writer. It uses two files for communication: one for incoming envelopes and the other for outgoing envelopes.\n\nThe AEA waits for a new envelope posted to the file `my_first_aea/input_file`, and adds a response to the file `my_first_aea/output_file`.\n\nThe format of each envelope is the following:\n\n``` bash\nTO,SENDER,PROTOCOL_ID,ENCODED_MESSAGE,\n```\n\nFor example:\n\n``` bash\nrecipient_aea,sender_aea,fetchai/default:1.0.0,\\x08\\x01\\x12\\x011*\\x07\\n\\x05hello,\n```\n\n### Install AEA Dependencies\n\n``` bash\naea install\n```\n\n### Add and Create a Private Key\n\nAll AEAs need a private key to run. Add one now:\n\n``` bash\naea generate-key fetchai\naea add-key fetchai\n```\n\n### Run the AEA\n\nRun the AEA.\n\n``` bash\naea run\n```\n\nYou will see the echo skill running in the terminal window (an output similar to the one below).\n\n``` bash\n    _     _____     _\n   / \\   | ____|   / \\\n  / _ \\  |  _|    / _ \\\n / ___ \\ | |___  / ___ \\\n/_/   \\_\\|_____|/_/   \\_\\\n\nv1.1.1\n\nStarting AEA 'my_first_aea' in 'async' mode ...\ninfo: Echo Handler: setup method called.\ninfo: Echo Behaviour: setup method called.\ninfo: [my_first_aea]: Start processing messages...\ninfo: Echo Behaviour: act method called.\ninfo: Echo Behaviour: act method called.\ninfo: Echo Behaviour: act method called.\n...\n```\n\nThe framework first calls the `setup` methods in the skill's `Handler` and `Behaviour` classes in that order; after which it repeatedly calls the `act` method of `Behaviour` class. This is the main agent loop in action.\n\n#### Add a Message to the Input File\n\nYou can send the AEA a message wrapped in an envelope using the CLI's `interact` command.\n\nFrom a different terminal and same directory (ensure you are in the same virtual environment: `pipenv shell`):\n\n``` bash\ncd my_first_aea\naea interact\n```\n\nYou can now send messages to this AEA via an interactive tool by typing anything into the prompt and hitting enter twice (once to send the message and once more to check for a response).\n\nLet us send `hello` to this AEA (type `hello` and press enter twice). In the original terminal, you will see the `Echo Handler` dealing with this envelope and its contained message. You should see an output similar to the one below but with a different `dialogue_reference`.\n\n``` bash\ninfo: Echo Behaviour: act method called.\ninfo: Echo Handler: message=Message(dialogue_reference=('1', '') message_id=1 target=0 performative=bytes content=b'hello'), sender=my_first_aea_interact\ninfo: Echo Behaviour: act method called.\ninfo: Echo Behaviour: act method called.\n```\n\n??? note \"Manual approach:\"\n    Optionally, from a different terminal and same directory (i.e. the `my_first_aea` project), you can send the AEA a message wrapped in an envelope via the input file.\n\n    ``` bash\n    echo 'my_first_aea,sender_aea,fetchai/default:1.0.0,\\x12\\x10\\x08\\x01\\x12\\x011*\\t*\\x07\\n\\x05hello,' >> input_file\n    ```\n\n    You will see the <code>Echo Handler</code> dealing with the envelope and responding with the same message to the <code>output_file</code>, and also decoding the Base64 encrypted message in this case.\n\n    ``` bash\n    info: Echo Behaviour: act method called.\n    Echo Handler: message=Message(sender=sender_aea,to=my_first_aea,content=b'hello',dialogue_reference=('1', ''),message_id=1,performative=bytes,target=0), sender=sender_aea\n    info: Echo Behaviour: act method called.\n    info: Echo Behaviour: act method called.\n    ```\n    \n    Note, due to the dialogue reference having to be incremented, you can only send the above envelope once! This approach does not work in conjunction with the <code>aea interact</code> command.\n\n### Stop the AEA\n\nYou can stop an AEA by pressing `CTRL C`.\n\nOnce you do, you should see the AEA being interrupted and then calling the `teardown()` methods:\n\n``` bash\ninfo: Echo Behaviour: act method called.\ninfo: Echo Behaviour: act method called.\n^C my_first_aea interrupted!\nmy_first_aea stopping ...\ninfo: Echo Handler: teardown method called.\ninfo: Echo Behaviour: teardown method called.\n```\n\n### Write a Test for the AEA\n\nWe can write an end-to-end test for the AEA utilising helper classes provided by the framework.\n\n??? note \"Writing tests:\"\n    The following test class replicates the preceding demo and tests its correct behaviour. The `AEATestCase` classes are a tool for AEA developers to write useful end-to-end tests of their AEAs.\n\n    First, get the `packages` directory from the AEA repository (execute from the working directory which contains the <code>my_first_aea</code> folder):\n\n    ``` bash\n    svn export https://github.com/fetchai/agents-aea.git/trunk/packages\n    ```\n\n    Then write the test:\n    \n    ``` python\n    import signal\n    import time\n    \n    from aea.common import Address\n    from aea.mail.base import Envelope\n    from aea.protocols.base import Message\n    from aea.protocols.dialogue.base import Dialogue\n    \n    from packages.fetchai.protocols.default.dialogues import DefaultDialogue, DefaultDialogues\n    from packages.fetchai.protocols.default.message import DefaultMessage\n    from packages.fetchai.protocols.default.serialization import DefaultSerializer\n    from aea.test_tools.test_cases import AEATestCase\n    \n    \n    class TestEchoSkill(AEATestCase):\n        \"\"\"Test that echo skill works.\"\"\"\n    \n        def test_echo(self):\n            \"\"\"Run the echo skill sequence.\"\"\"\n            process = self.run_agent()\n            is_running = self.is_running(process)\n            assert is_running, \"AEA not running within timeout!\"\n    \n            # add sending and receiving envelope from input/output files\n            sender_aea = \"sender_aea\"\n            def role_from_first_message(\n                message: Message, receiver_address: Address\n            ) -> Dialogue.Role:\n                return DefaultDialogue.Role.AGENT\n            dialogues = DefaultDialogues(sender_aea, role_from_first_message)\n            message_content = b\"hello\"\n            message = DefaultMessage(\n                performative=DefaultMessage.Performative.BYTES,\n                dialogue_reference=dialogues.new_self_initiated_dialogue_reference(),\n                content=message_content,\n            )\n            sent_envelope = Envelope(\n                to=self.agent_name,\n                sender=sender_aea,\n                protocol_id=message.protocol_id,\n                message=DefaultSerializer().encode(message),\n            )\n    \n            self.send_envelope_to_agent(sent_envelope, self.agent_name)\n    \n            time.sleep(2.0)\n            received_envelope = self.read_envelope_from_agent(self.agent_name)\n    \n            assert sent_envelope.to == received_envelope.sender\n            assert sent_envelope.sender == received_envelope.to\n            assert sent_envelope.protocol_id == received_envelope.protocol_id\n            received_message = DefaultMessage.serializer.decode(received_envelope.message)\n            assert message.content == received_message.content\n    \n            check_strings = (\n                \"Echo Handler: setup method called.\",\n                \"Echo Behaviour: setup method called.\",\n                \"Echo Behaviour: act method called.\",\n                \"content={}\".format(message_content),\n            )\n            missing_strings = self.missing_from_output(process, check_strings)\n            assert (\n                missing_strings == []\n            ), \"Strings {} didn't appear in agent output.\".format(missing_strings)\n    \n            assert (\n                self.is_successfully_terminated()\n            ), \"Echo agent wasn't successfully terminated.\"\n    \n    ```\n    \n    Place the above code into a file <code>test.py</code> in your AEA project directory (the same level as the <code>aea-config.yaml</code> file).\n    \n    To run, execute the following:\n\n    ``` bash\n    pytest test.py\n    ```\n\n### Delete the AEA\n\nDelete the AEA from the parent directory (`cd ..` to go to the parent directory).\n\n``` bash\naea delete my_first_aea\n```\n\n## Next Steps\n\nTo gain an understanding of the core components of the framework, please continue to the next page:\n\n- <a href=\"../core-components-1/\">Core components - Part 1</a>\n\nFor more demos, use cases or step-by-step guides, please check the following:\n\n- <a href=\"../generic-skills\">Generic skill use case</a>\n- <a href='../weather-skills/'>Weather skill demo</a>\n- <a href='../generic-skills-step-by-step/'> Generic step by step guide </a>\n"
  },
  {
    "path": "docs/raspberry-set-up.md",
    "content": "# Build an AEA on a Raspberry Pi\n\nThis guide explains how to run an AEA inside a Raspberry Pi.\n\n## Prerequisites\n\n- <a href=\"https://thepihut.com/products/raspberry-pi-4-model-b?gclid=EAIaIQobChMImcuwvcfh4wIVirHtCh3szg2EEAAYASAAEgJQ_fD_BwE\" target=\"_blank\">Raspberry Pi 4</a> (You can also use Raspberry Pi3 b or Raspberry Pi3 b+)\n- Internet connection (preferably wireless to minimise the number of wires connecting into your device)\n\n## Preparing the Raspberry Pi\n\nThe easiest and recommended way to get started is to download and unzip our custom <a href=\"https://storage.googleapis.com/fetch-ai-aea-images/aea_rpi.img.tar.gz\" target=\"_blank\">AEA Raspberry Pi Image</a>, which includes the AEA installation as well as the most common dependencies.\n\nHowever, you can also do the installation manually, and if you have a new Raspberry Pi, you can boot the system using the included SD card and skip the next section.\n\n## Raspberry Pi Imager\n\nRaspberry Pi Imager is a way to write to an SD card for easy installation on a Raspberry Pi.\n\nFirst download the tool from <a href=\"https://www.raspberrypi.com/software/\" target=\"_blank\">this link</a>.\n\nThen follow <a href=\"https://projects.raspberrypi.org/en/projects/raspberry-pi-setting-up\" target=\"_blank\">this guide</a> to set up your SD card.\nWhen you get to the step of choosing an operating system, select the downloaded and unzipped AEA Raspberry Pi Image (`AEA_RPI.IMG`), or for a manual installation, select the latest Raspberry Pi OS.\n\nOnce you have set up your SD card, plug it into your Raspberry Pi, connect the power and boot up.\n\n## Booting up with the AEA Raspberry Pi Image\n\nAfter booting up, you may be prompted to log in as the `aea` user and the password is `fetch`.\nNext, navigate to settings menu to set up your internet connection.\nYour Raspberry Pi is now ready to run an AEA!\nYou can find some preloaded demos in the folder `~/aea/demos`.\nTo run these demos, navigate to one of the sub-folders and enter `aea run`.\n\n## Booting up with the Raspberry Pi OS for Manual Installation\n\nWhen you first boot your Raspberry Pi, you will be prompted to enter a password for the Raspberry Pi and your Wi-Fi password so the device can access the internet. You may also be given the option to update the operating system and software. We recommend that you let the system update. Once finished you will be prompted to restart.\n\nEven if your Raspberry Pi updated itself, we recommend that you make sure it is completely up-to-date using the terminal. Open a Terminal window (your Raspberry Pi might restart a few times during this process):\n\n``` bash\nsudo apt update -y \nsudo apt-get update\nsudo apt-get dist-upgrade \n```\n\n## Install Common Dependencies\n\n``` bash\nsudo apt install cmake golang -y\n```\n\n## Install Less Common Dependencies (optional)\n\nFor some of the more advanced AEAs that make use of SciPy, such as the Car Park Detector, you will need some additional dependencies.\n\n??? note \"Install additional dependencies with the enclosed steps:\"\n\n    Install additional dependencies\n\n    ``` bash\n    sudo apt install gfortran libatlas-base-dev libopenblas-dev -y\n    ```\n\n    Increase the swap space for the SciPy installation:\n\n    ``` bash\n    sudo /bin/dd if=/dev/zero of=/var/swap.1 bs=1M count=1024\n    sudo /sbin/mkswap /var/swap.1\n    sudo chmod 600 /var/swap.1\n    sudo /sbin/swapon /var/swap.1\n    ```\n    \n    Install NumPy and scikit-image (including SciPy)\n\n    ``` bash\n    pip install numpy --upgrade\n    pip install scikit-image\n    ```\n\n    Revert to default swap space\n\n    ``` bash\n    sudo swapoff /var/swap.1\n    sudo rm /var/swap.1\n    ```\n\n## Install the AEA Framework\n\nAdd to the local `PATH` environment variable (this will happen automatically the next time you log in):\n\n``` bash\nexport PATH=\"$HOME/.local/bin:$PATH\"\n```\n\nFinally, install the AEA framework from PyPI:\n\n``` bash\npip install aea[all]\n```\n\nCheck to make sure installation was successful:\n\n``` bash\naea --version\n```\n\nYour Raspberry Pi is now ready to run an AEA!\n"
  },
  {
    "path": "docs/runtime-cost.md",
    "content": "# Profiling\n\n## Measuring Runtime Cost\n\nIt is important to emphasise the fact that the AEA is a framework, so ultimately its running cost will highly depend on the number and type of components which are being run as part of a given AEA. The other cost factor is determined by the cost of running the core framework itself and how fast and efficient the framework is in interconnecting the components.\n\nThese observations can provide guidance on what to report as part of the cost of running an AEA.\n\nHere is a list of suggestion on how to measure the cost of running an AEA:\n\n- the cost of running the framework itself: by running a minimal agent with an idle loop (the default one) with no connections, skills or protocols and measuring memory usage and CPU consumption as a baseline.\n- the cost of interconnecting components: by running an agent with a basic skill (e.g. `fetchai/echo`) and measuring memory usage and CPU consumption relative to number of messages exchanged as well as bandwidth.\n- the cost of basic components: dialogues memory relative to number of messages, SOEF connection baseline memory usage, P2P connection baseline memory usage, smart contract baseline memory usage\n\nThe `aea run --profiling SECONDS` command can be used to report measures in all of the above scenarios.\n"
  },
  {
    "path": "docs/scaffolding.md",
    "content": "# Scaffolding Packages\n\n## Scaffold Generator\n\nThe scaffold generator builds out the directory structure required when adding new skills, protocols, contracts and connections to the AEA.\n\nFor example, create a new AEA project (add the author flag using your own author handle if this is your first project using the `aea` package).\n\n``` bash\naea create my_aea --author \"fetchai\"\ncd my_aea\n```\n\nThen, enter into your project directory and scaffold your project skill, protocol, or connection.\n\n### Scaffold a Skill\n\n``` bash\naea scaffold skill my_skill\n```\n\n### Scaffold a Protocol\n\n``` bash\naea scaffold protocol my_protocol\n```\n\n### Scaffold a Contract\n\n``` bash\naea scaffold contract my_contract\n```\n\n### Scaffold a Connection\n\n``` bash\naea scaffold connection my_connection\n```\n\nAfter running the above commands, you are able to develop your own skill, protocol, contract and connection.\n\nOnce you have made changes to your scaffolded packages, make sure you update the fingerprint of the package:\n\n``` bash\naea fingerprint [package_name] [public_id]\n```\n\nThen you are ready to run the AEA.\n"
  },
  {
    "path": "docs/security.md",
    "content": "# Security\n\nThe AEA framework takes every care to follow best practice around security.\n\nThe following advice will help you when writing your own code:\n\n- Many potential common security vulnerabilities can be caught by static code analysis. We recommend you use `safety`, `pylint` and `bandit` to analyse your code.\n\n- Don't use relative import paths, these can lead to malicious code being executed.\n\n- Try to avoid using the `subprocess` module. If needed, make sure you sanitise commands passed to `subprocess`.\n\n- Try to avoid using the `pickle` module. Pickle should never be used for agent-to-agent communication protocols.\n\n- By design, the framework prevents skill code from accessing private keys directly, as they are not reachable from the skill execution context through attribute getters. However, if the flag `-p` or the option `--password` are not used when generating private keys for an AEA project via the aea CLI tool, the private keys will be stored in plaintext. This allows the skills to access them via interaction with the OS file system. We recommend to always specify a password to encrypt private keys by using the flag argument.\n"
  },
  {
    "path": "docs/setup.md",
    "content": "# Setting up\n\nOnce you successfully <a href=\"../install\">install the AEA framework</a>, you can set it up for agent development.\n\n## Specify Author Handle\n\nYou need an author handle before being able to develop agents or agent components. This handle is used in the `author` field of any agent or component you create.\n\nAEAs and their components can be developed by anyone and pushed to the <a href=\"https://aea-registry.fetch.ai\" target=\"_blank\">AEA registry</a> for others to use. To publish packages to the registry, you also need to register your author handle.\n\n### Pick Author Handle and Register\n\nIf you are intending to use the registry:\n\n``` bash\naea init --register\n```\n\nThis will let you pick a new author handle and register it at the same time.\n\n### Pick Author Handle Only\n\nIf you are unsure whether you will need a registry account, or intending not to use it, simply pick a new author handle:\n\n``` bash\naea init\n```\n\n### Register Author Handle\n\nTo register an already created author handle with the AEA registry:\n\n``` bash\naea register\n```\n\n!!! info \"Note\"\n    The author handle is your unique author (or developer) name in the AEA ecosystem.\n"
  },
  {
    "path": "docs/simple-oef-usage.md",
    "content": "# SOEF Connection\n\nYou can use the <a href=\"../simple-oef\">SOEF</a> in the agent framework by using the SOEF connection as a package in your agent project.\n\n## Add the SOEF Package\n\nCheck out the <a href=\"../cli-commands\">CLI guide</a> on details how to add a connection. You will want to add the `fetchai/soef:0.27.6` connection package.\n\n## Register your Agent and its Services\n\n### Register Agent Location\n\nTo register your agent's location, you have to send a message in the `fetchai/oef_search:1.0.0` protocol to the SOEF connection.\n\nFirst, define a data model for location data:\n\n``` python\nfrom aea.helpers.search.models import Attribute, DataModel, Location\n\nAGENT_LOCATION_MODEL = DataModel(\n    \"location_agent\",\n    [Attribute(\"location\", Location, True, \"The location where the agent is.\")],\n    \"A data model to describe location of an agent.\",\n)\n```\n\nIt is important to use this exact data model, as the SOEF connection can only process specific data models.\n\nSecond, create a location object:\n\n``` python\nfrom aea.helpers.search.models import Location\n\nagent_location = Location(52.2057092, 2.1183431)\n```\n\nThird, construct a service description instance with location and data model:\n\n``` python\nfrom aea.helpers.search.models import Description\n\nservice_instance = {\"location\": agent_location}\nservice_description = Description(\n    service_instance, data_model=AGENT_LOCATION_MODEL\n)\n```\n\nFinally, construct a message and send it:\n\n``` python\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\n\nmessage = OefSearchMessage(\n    performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n    service_description=service_description,\n)\n```\n\nIn case everything is registered OK, you will not receive any message back.\n\nIf something goes wrong you will receive an error message with performative `OefSearchMessage.Performative.OEF_ERROR`.\n\n### Register Personality Pieces\n\nTo register personality pieces, you have to use a specific data model:\n\n``` python\nfrom aea.helpers.search.models import Attribute, DataModel, Location\n\nAGENT_PERSONALITY_MODEL = DataModel(\n    \"personality_agent\",\n    [\n        Attribute(\"piece\", str, True, \"The personality piece key.\"),\n        Attribute(\"value\", str, True, \"The personality piece value.\"),\n    ],\n    \"A data model to describe the personality of an agent.\",\n)\n```\n\nAn example follows:\n\n``` python\nservice_instance = {\"piece\": \"genus\", \"value\": \"service\"}\nservice_description = Description(\n    service_instance, data_model=AGENT_PERSONALITY_MODEL\n)\n```\n\n### Register Services\n\nTo set some service key and value you have to use a specific data model:\n\n``` python\nSET_SERVICE_KEY_MODEL = DataModel(\n    \"set_service_key\",\n    [\n        Attribute(\"key\", str, True, \"Service key name.\"),\n        Attribute(\"value\", str, True, \"Service key value.\"),\n    ],\n    \"A data model to set service key.\",\n)\n```\n\nAn example follows:\n\n``` python\nservice_instance = {\"key\": \"test\", \"value\": \"test\"}\nservice_description = Description(\n    service_instance, data_model=SET_SERVICE_KEY_MODEL\n)\n```\n\n### Remove Service Key\n\nTo remove service key have to use a specific data model:\n\n``` python\nREMOVE_SERVICE_KEY_MODEL = DataModel(\n    \"remove_service_key\",\n    [Attribute(\"key\", str, True, \"Service key name.\")],\n    \"A data model to remove service key.\",\n)\n```\n\nAn example follows:\n\n``` python\nservice_instance = {\"key\": \"test\"}\nservice_description = Description(\n    service_instance, data_model=REMOVE_SERVICE_KEY_MODEL\n)\n```\n\n!!! note\n    Currently, the soef does not allow for multiple registrations to be combined into a single command.\n\n## Perform a Search\n\nTo perform a search for services registered you have to define a search query consisting of constraints. The location constraints is required, personality pieces or services keys constraints are optional.\n\nAn example follows:\n\n``` python\nfrom aea.helpers.search.models import (\n    Constraint,\n    ConstraintType,\n    Location,\n    Query,\n)\n\nradius = 0.1\nclose_to_my_service = Constraint(\n    \"location\", ConstraintType(\"distance\", (agent_location, radius))\n)\npersonality_filters = [\n    Constraint(\"genus\", ConstraintType(\"==\", \"vehicle\")),\n    Constraint(\n        \"classification\", ConstraintType(\"==\", \"mobility.railway.train\")\n    ),\n]\n\nservice_key_filters = [\n    Constraint(\"test\", ConstraintType(\"==\", \"test\")),\n]\n\ncloseness_query = Query(\n    [close_to_my_service] + personality_filters + service_key_filters\n)\n\nmessage = OefSearchMessage(\n    performative=OefSearchMessage.Performative.SEARCH_SERVICES,\n    query=closeness_query,\n)\n```\n\nIn case of error, you will receive a message with `OefSearchMessage.Performative.OEF_ERROR`. In case of successful search you will receive a message with performative `OefSearchMessage.Performative.SEARCH_RESULT` and the list of matched agents addresses.\n\n## Generic Command\n\nTo send a generic command request to the SOEF use the following (here on the example of setting a declared name):\n\n``` python\nimport urllib\n\nAGENT_GENERIC_COMMAND_MODEL = DataModel(\n    \"generic_command\",\n    [\n        Attribute(\"command\", str, True, \"Command name to execute.\"),\n        Attribute(\"parameters\", str, False, \"Url encoded parameters string.\"),\n    ],\n    \"A data model to describe the generic soef command.\",\n)\n\ndeclared_name = \"new_declared_name\"\nservice_description = Description(\n    {\n        \"command\": \"set_declared_name\",\n        \"parameters\": urllib.parse.urlencode({\"name\": declared_name}),\n    },\n    data_model=AGENT_GENERIC_COMMAND_MODEL,\n)\nmessage = OefSearchMessage(\n    performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n    service_description=service_description,\n)\n```\n"
  },
  {
    "path": "docs/simple-oef.md",
    "content": "# Simple-OEF: Agent Search and Discovery\n\nThe full documentation is available <a href=\"https://docs.fetch.ai/soef/simple-oef/\" target=\"_blank\">here</a>.\n"
  },
  {
    "path": "docs/skill-guide.md",
    "content": "# Build your First Skill - Search & Discovery\n\nThis guide will take you through the development of your first skill. It will teach you, how to connect the AEA to the digital world, register the AEA and search for other AEAs.\n\nAlthough one can imagine scenarios where a single AEA pursues its goals in isolation without interacting with other AEAs, there is no doubt that by working together, AEAs can achieve much more. To do so, an AEA must be seen and found by other AEAs so that they can trade and do other useful things. Fetch.ai’s search-and-discovery mechanism, the <a href=\"../simple-oef\">simple OEF</a> (or SOEF, for short) lets your agents register, be discovered, and find other agents. You can then negotiate using the AEA framework’s <a href=\"../acn\">peer-to-peer network (ACN)</a> and trade. This guide covers getting your AEA connected to the SOEF, and describing your AEA to make itself visible.\n\nRegistering your AEA with the SOEF involves setting a name, a genus (a high-level description of what the agent represents, e.g. `vehicle`, `building` or `service`), a classification (for example `infrastructure.railway.train`) and other descriptors to further fine-tune the kind of service your AEA offers (for example, the agent's position, whether it buys or sells, and other descriptive items).\n\nThe more you describe your AEA, the easier it is for others to find it using specific filters.\n\n## Dependencies (Required)\n\nFollow the <a href=\"../quickstart/#preliminaries\">Preliminaries</a> and <a href=\"../quickstart/#installation\">Installation</a> sections from the AEA quick start.\n\n## Step 1: Setup\n\nWe will first create an AEA and add a scaffold skill, which we call `my_search`.\n\n``` bash\naea create my_aea && cd my_aea\naea scaffold skill my_search\n```\n\nIn the following steps, we replace the scaffolded `Behaviour` and `Handler` in `my_aea/skills/my_search` with our implementation. We will build a simple skill which lets the AEA send a search query to the <a href=\"../simple-oef\">SOEF search node</a> and process the resulting response.\n\n## Step 2: Develop a Behaviour\n\nA <a href=\"../api/skills/base#behaviour-objects\">`Behaviour`</a> class contains the business logic specific to actions initiated by the AEA rather than reactions to other events.\n\nIn this example, we implement a simple search behaviour. Each time, `act()` gets called by the main agent loop, we will send a search request to the <a href=\"../simple-oef\">SOEF search node</a> via the <a href=\"../acn\">P2P communication network</a>.\n\n``` python\nfrom typing import cast\n\nfrom aea.helpers.search.models import Constraint, ConstraintType, Location, Query\nfrom aea.skills.behaviours import TickerBehaviour\n\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.skills.my_search.dialogues import OefSearchDialogues\n\nDEFAULT_LOCATION = {\"longitude\": 0.1270, \"latitude\": 51.5194}\nDEFAULT_SEARCH_QUERY = {\n    \"search_key\": \"seller_service\",\n    \"search_value\": \"generic_service\",\n    \"constraint_type\": \"==\",\n}\nDEFAULT_SEARCH_RADIUS = 5.0\n\n\nclass MySearchBehaviour(TickerBehaviour):\n    \"\"\"This class provides a simple search behaviour.\"\"\"\n\n    def __init__(self, **kwargs):\n        \"\"\"Initialize the search behaviour.\"\"\"\n\n        search_query = kwargs.pop(\"search_query\", DEFAULT_SEARCH_QUERY)\n        location = kwargs.pop(\"location\", DEFAULT_LOCATION)\n        agent_location = Location(latitude=location[\"latitude\"], longitude=location[\"longitude\"])\n        radius = kwargs.pop(\"search_radius\", DEFAULT_SEARCH_RADIUS)\n\n        close_to_my_service = Constraint(\n            \"location\", ConstraintType(\"distance\", (agent_location, radius))\n        )\n        service_key_filter = Constraint(\n            search_query[\"search_key\"],\n            ConstraintType(\n                search_query[\"constraint_type\"], search_query[\"search_value\"],\n            ),\n        )\n        self.query = Query([close_to_my_service, service_key_filter])\n        super().__init__(**kwargs)\n        self.sent_search_count = 0\n\n    def setup(self) -> None:\n        \"\"\"\n        Implement the setup.\n\n        :return: None\n        \"\"\"\n        self.context.logger.info(\n            \"setting up MySearchBehaviour\"\n        )\n\n    def act(self) -> None:\n        \"\"\"\n        Implement the act.\n\n        :return: None\n        \"\"\"\n        self.sent_search_count += 1\n        oef_search_dialogues = cast(\n            OefSearchDialogues, self.context.oef_search_dialogues\n        )\n        self.context.logger.info(\n            \"sending search request to OEF search node, search_count={}\".format(\n                self.sent_search_count\n            )\n        )\n        search_request, _ = oef_search_dialogues.create(\n            counterparty=self.context.search_service_address,\n            performative=OefSearchMessage.Performative.SEARCH_SERVICES,\n            query=self.query,\n        )\n        self.context.outbox.put_message(message=search_request)\n\n    def teardown(self) -> None:\n        \"\"\"\n        Implement the task teardown.\n\n        :return: None\n        \"\"\"\n        self.context.logger.info(\n            \"tearing down MySearchBehaviour\"\n        )\n```\n\nSearches are proactive and, as such, well placed in a <a href=\"../api/skills/base#behaviour-objects\">`Behaviour`</a>. Specifically, we subclass the <a href=\"../api/skills/behaviours#tickerbehaviour-objects\">`TickerBehaviour`</a> as it allows us to repeatedly search at a defined tick interval.\n\nWe place this code in `my_aea/skills/my_search/behaviours.py`. Ensure you replace the `fetchai` author in this line `from packages.fetchai.skills.my_search.dialogues import OefSearchDialogues` with your author handle (run `aea init` to set or check the author name).\n\n!!! note\n    The import paths to agent packages, for example `packages.fetchai.skills.my_search.dialogues` above, are not actual paths. Package files always reside in your AEA's folder, either under a specific package directory (e.g. connection, protocol, skill) if the package is custom-built, or under `vendor` if it is pulled from the registry. These paths are virtual and created automatically when an AEA is run. See <a href=\"../package-imports\"> this page </a> for more details.\n\n## Step 3: Develop a Handler\n\nSo far, we have tasked the AEA with sending search requests to the <a href=\"../simple-oef\">SOEF search node</a>. However, we have no way of handling the responses sent to the AEA by the <a href=\"../simple-oef\">SOEF search node</a> at the moment. The AEA would simply respond to the <a href=\"../simple-oef\">SOEF search node</a> via the default `error` skill which sends all unrecognised envelopes back to the sender.\n\nLet us now implement a <a href=\"../api/skills/base#handler-objects\">`Handler`</a> to deal with the incoming search responses.\n\n``` python\nfrom typing import Optional, cast\n\nfrom aea.protocols.base import Message\nfrom aea.skills.base import Handler\n\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.skills.my_search.dialogues import (\n    OefSearchDialogue,\n    OefSearchDialogues,\n)\n\n\nclass MySearchHandler(Handler):\n    \"\"\"This class provides a simple search handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = OefSearchMessage.protocol_id\n\n    def __init__(self, **kwargs):\n        \"\"\"Initialize the handler.\"\"\"\n        super().__init__(**kwargs)\n        self.received_search_count = 0\n\n    def setup(self) -> None:\n        \"\"\"Set up the handler.\"\"\"\n        self.context.logger.info(\n            \"setting up MySearchHandler\"\n        )\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to a message.\n\n        :param message: the message\n        :return: None\n        \"\"\"\n        oef_search_msg = cast(OefSearchMessage, message)\n\n        # recover dialogue\n        oef_search_dialogues = cast(\n            OefSearchDialogues, self.context.oef_search_dialogues\n        )\n        oef_search_dialogue = cast(\n            Optional[OefSearchDialogue], oef_search_dialogues.update(oef_search_msg)\n        )\n        if oef_search_dialogue is None:\n            self._handle_unidentified_dialogue(oef_search_msg)\n            return\n\n        # handle message\n        if oef_search_msg.performative is OefSearchMessage.Performative.OEF_ERROR:\n            self._handle_error(oef_search_msg, oef_search_dialogue)\n        elif oef_search_msg.performative is OefSearchMessage.Performative.SEARCH_RESULT:\n            self._handle_search(oef_search_msg, oef_search_dialogue)\n        else:\n            self._handle_invalid(oef_search_msg, oef_search_dialogue)\n\n    def _handle_unidentified_dialogue(self, oef_search_msg: OefSearchMessage) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param msg: the message\n        \"\"\"\n        self.context.logger.info(\n            \"received invalid oef_search message={}, unidentified dialogue.\".format(\n                oef_search_msg\n            )\n        )\n\n    def _handle_error(\n        self, oef_search_msg: OefSearchMessage, oef_search_dialogue: OefSearchDialogue\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param oef_search_msg: the oef search message\n        :param oef_search_dialogue: the dialogue\n        :return: None\n        \"\"\"\n        self.context.logger.info(\n            \"received oef_search error message={} in dialogue={}.\".format(\n                oef_search_msg, oef_search_dialogue\n            )\n        )\n\n    def _handle_search(\n        self, oef_search_msg: OefSearchMessage, oef_search_dialogue: OefSearchDialogue\n    ) -> None:\n        \"\"\"\n        Handle the search response.\n\n        :param agents: the agents returned by the search\n        :return: None\n        \"\"\"\n        self.received_search_count += 1\n        nb_agents_found = len(oef_search_msg.agents)\n        self.context.logger.info(\n            \"found number of agents={}, received search count={}\".format(\n                nb_agents_found, self.received_search_count\n            )\n        )\n        self.context.logger.info(\n            \"number of search requests sent={} vs. number of search responses received={}\".format(\n                self.context.behaviours.my_search_behaviour.sent_search_count,\n                self.received_search_count,\n            )\n        )\n\n    def _handle_invalid(\n        self, oef_search_msg: OefSearchMessage, oef_search_dialogue: OefSearchDialogue\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param oef_search_msg: the oef search message\n        :param oef_search_dialogue: the dialogue\n        :return: None\n        \"\"\"\n        self.context.logger.warning(\n            \"cannot handle oef_search message of performative={} in dialogue={}.\".format(\n                oef_search_msg.performative, oef_search_dialogue,\n            )\n        )\n\n    def teardown(self) -> None:\n        \"\"\"\n        Teardown the handler.\n\n        :return: None\n        \"\"\"\n        self.context.logger.info(\n            \"tearing down MySearchHandler\"\n        )\n```\n\nWe create a handler which is registered for the `oef_search` protocol. Whenever it receives a search result, we log the number of agents returned by the search - the agents matching the search query - and update the counter of received searches.\n\nWe also implement a trivial check on the difference between the amount of search requests sent and responses received.\n\nNote, how the handler simply reacts to incoming events (i.e. messages). It could initiate further actions, however, they are still reactions to the upstream search event.\n\nAlso note, how we have access to other objects in the skill via `self.context`, the <a href=\"../api/skills/base#skillcontext-objects\">`SkillContext`</a>.\n\nWe place this code in `my_aea/skills/my_search/handlers.py`. Ensure you replace the `fetchai` author in this line `from packages.fetchai.skills.my_search.dialogues import (` with your author handle (run `aea init` to set or check the author name).\n\n## Step 4: Add Dialogues Model\n\nWe have implemented a behaviour and a handler. We now implement a <a href=\"../api/skills/base#model-objects\">`Model`</a>, in particular we implement the <a href=\"../api/protocols/dialogue/base#dialogue-objects\">`Dialogue`</a> and <a href=\"../api/protocols/dialogue/base#dialogues-objects\">`Dialogues`</a> classes. These ensure that the message flow satisfies the `fetchai/oef_search:1.0.0` protocol and keep track of the individual messages being sent and received.\n\n``` python\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\nfrom aea.skills.base import Address, Model\n\nfrom packages.fetchai.protocols.oef_search.dialogues import (\n    OefSearchDialogue as BaseOefSearchDialogue,\n)\nfrom packages.fetchai.protocols.oef_search.dialogues import (\n    OefSearchDialogues as BaseOefSearchDialogues,\n)\n\n\nOefSearchDialogue = BaseOefSearchDialogue\n\n\nclass OefSearchDialogues(Model, BaseOefSearchDialogues):\n    \"\"\"This class keeps track of all oef_search dialogues.\"\"\"\n\n    def __init__(self, **kwargs) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param agent_address: the address of the agent for whom dialogues are maintained\n        :return: None\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return BaseOefSearchDialogue.Role.AGENT\n\n        BaseOefSearchDialogues.__init__(\n            self,\n            self_address=str(self.skill_id),\n            role_from_first_message=role_from_first_message,\n        )\n```\n\nWe add this code in the file `my_aea/skills/my_search/my_model.py`, replacing its original content. We then rename `my_aea/skills/my_search/my_model.py` to `my_aea/skills/my_search/dialogues.py`.\n\n## Step 5: Create the Configuration File\n\nBased on our skill components above, we create the following configuration file.\n\n``` yaml\nname: my_search\nauthor: fetchai\nversion: 0.1.0\ntype: skill\ndescription: A simple search skill utilising the SOEF search node.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint: {}\nfingerprint_ignore_patterns: []\nconnections: []\ncontracts: []\nprotocols:\n- fetchai/oef_search:1.1.7\nskills: []\nbehaviours:\n  my_search_behaviour:\n    args:\n      location:\n        latitude: 51.5194\n        longitude: 0.127\n      search_query:\n        constraint_type: ==\n        search_key: seller_service\n        search_value: generic_service\n      search_radius: 5.0\n      tick_interval: 5\n    class_name: MySearchBehaviour\nhandlers:\n  my_search_handler:\n    args: {}\n    class_name: MySearchHandler\nmodels:\n  oef_search_dialogues:\n    args: {}\n    class_name: OefSearchDialogues\ndependencies:\n  aea-ledger-fetchai:\n    version: <2.0.0,>=1.0.0\nis_abstract: false\n```\n\nEnsure, you replace the author field with your author name! (Run `aea init` to set or check the author name.)\n\nImportantly, the keys `my_search_behaviour` and `my_search_handler` are used in the above handler to access these skill components at runtime via the context. We also set the `tick_interval` of the `TickerBehaviour` to `5` seconds.\n\nWe place this code in `my_aea/skills/my_search/skill.yaml`.\n\nSimilarly, we replace `my_aea/skills/my_search/__init__.py` as follows:\n\n``` python\n# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2019 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the implementation of the error skill.\"\"\"\n\nfrom aea.configurations.base import PublicId\n\n\nPUBLIC_ID = PublicId.from_str(\"fetchai/my_search:0.1.0\")\n\n```\n\nAgain, ensure the author field matches your own.\n\n## Step 6: Update Fingerprint\n\nTo run an AEA with new or modified code, you need to update the fingerprint of the new/modified components. In this case, we need to fingerprint our skill:\n\n``` bash\naea fingerprint skill fetchai/my_search:0.1.0\n```\n\nEnsure, you use the correct author name to reference your skill (here we use `fetchai` as the author.)\n\n## Step 7: Add the OEF Protocol and Connection\n\nOur AEA does not have the OEF protocol yet so let's add it.\n\n``` bash\naea add protocol fetchai/oef_search:1.1.7\n```\n\nThis adds the protocol to our AEA and makes it available on the path `packages.fetchai.protocols...`.\n\nAt this point we need to add the SOEF and P2P connections to allow the AEA to communicate with the SOEF node and other AEAs, install the AEA's dependencies, and configure the AEA:\n\n``` bash\naea add connection fetchai/soef:0.27.6\naea add connection fetchai/p2p_libp2p:0.27.5\naea install\naea build\naea config set agent.default_connection fetchai/p2p_libp2p:0.27.5\naea config set --type dict agent.default_routing \\\n'{\n  \"fetchai/oef_search:1.1.7\": \"fetchai/soef:0.27.6\"\n}'\n```\n\nThe last command will ensure that search requests are processed by the correct connection.\n\n## Step 8: Run a Service Provider AEA\n\nIn order for this AEA to find another AEA when searching, the second AEA (let's call it the service provider AEA) must exist and have been registered with the SOEF.\n\nFrom a different terminal window, we fetch a finished service provider AEA and install its Python dependencies:\n\n``` bash\naea fetch fetchai/simple_service_registration:0.32.5 && cd simple_service_registration && aea install && aea build\n```\n\nThis AEA will simply register a location service on the <a href=\"../simple-oef\">SOEF search node</a> so we can search for it.\n\nWe first create the private key for the service provider AEA based on the network you want to transact. To generate and add a private-public key pair for Fetch.ai `Dorado` use:\n\n``` bash\naea generate-key fetchai\naea add-key fetchai fetchai_private_key.txt\n```\n\nNext, create a private key used to secure the AEA's communications:\n\n``` bash\naea generate-key fetchai fetchai_connection_private_key.txt\naea add-key fetchai fetchai_connection_private_key.txt --connection\n```\n\nFinally, certify the key for use by the connections that request that:\n\n``` bash\naea issue-certificates\n```\n\nThen we run the AEA:\n\n``` bash\naea run\n```\n\nOnce you see a message of the form `To join its network use multiaddr: ['SOME_ADDRESS']` take note of the address. (Alternatively, use `aea get-multiaddress fetchai -c -i fetchai/p2p_libp2p:0.27.5 -u public_uri` to retrieve the address.) This is the entry peer address for the local <a href=\"../acn\">agent communication network</a> created by the `simple_service_registration` (service provider) AEA.\n\n??? note \"Click here to see full code and guide for this AEA:\"\n    We use a <a href=\"../api/skills/behaviours#tickerbehaviour-objects\">`TickerBehaviour`</a> to update the service registration at regular intervals. The following code is placed in `behaviours.py`.\n\n    ``` python\n    from typing import Any, Optional, cast\n    \n    from aea.helpers.search.models import Description\n    from aea.skills.behaviours import TickerBehaviour\n    \n    from packages.fetchai.protocols.oef_search.message import OefSearchMessage\n    from packages.fetchai.skills.simple_service_registration.dialogues import (\n        OefSearchDialogues,\n    )\n    from packages.fetchai.skills.simple_service_registration.strategy import Strategy\n    \n    \n    DEFAULT_MAX_SOEF_REGISTRATION_RETRIES = 5\n    DEFAULT_SERVICES_INTERVAL = 30.0\n    \n    \n    class ServiceRegistrationBehaviour(TickerBehaviour):\n        \"\"\"This class implements a behaviour.\"\"\"\n    \n        def __init__(self, **kwargs: Any) -> None:\n            \"\"\"Initialise the behaviour.\"\"\"\n            services_interval = kwargs.pop(\n                \"services_interval\", DEFAULT_SERVICES_INTERVAL\n            )  # type: int\n            self._max_soef_registration_retries = kwargs.pop(\n                \"max_soef_registration_retries\", DEFAULT_MAX_SOEF_REGISTRATION_RETRIES\n            )  # type: int\n            super().__init__(tick_interval=services_interval, **kwargs)\n    \n            self.failed_registration_msg = None  # type: Optional[OefSearchMessage]\n            self._nb_retries = 0\n    \n        def setup(self) -> None:\n            \"\"\"\n            Implement the setup.\n    \n            :return: None\n            \"\"\"\n            self._register_agent()\n    \n        def act(self) -> None:\n            \"\"\"\n            Implement the act.\n    \n            :return: None\n            \"\"\"\n            self._retry_failed_registration()\n    \n        def teardown(self) -> None:\n            \"\"\"\n            Implement the task teardown.\n    \n            :return: None\n            \"\"\"\n            self._unregister_service()\n            self._unregister_agent()\n    \n        def _retry_failed_registration(self) -> None:\n            \"\"\"\n            Retry a failed registration.\n    \n            :return: None\n            \"\"\"\n            if self.failed_registration_msg is not None:\n                self._nb_retries += 1\n                if self._nb_retries > self._max_soef_registration_retries:\n                    self.context.is_active = False\n                    return\n    \n                oef_search_dialogues = cast(\n                    OefSearchDialogues, self.context.oef_search_dialogues\n                )\n                oef_search_msg, _ = oef_search_dialogues.create(\n                    counterparty=self.failed_registration_msg.to,\n                    performative=self.failed_registration_msg.performative,\n                    service_description=self.failed_registration_msg.service_description,\n                )\n                self.context.outbox.put_message(message=oef_search_msg)\n                self.context.logger.info(\n                    f\"Retrying registration on SOEF. Retry {self._nb_retries} out of {self._max_soef_registration_retries}.\"\n                )\n    \n                self.failed_registration_msg = None\n    \n        def _register(self, description: Description, logger_msg: str) -> None:\n            \"\"\"\n            Register something on the SOEF.\n    \n            :param description: the description of what is being registered\n            :param logger_msg: the logger message to print after the registration\n    \n            :return: None\n            \"\"\"\n            oef_search_dialogues = cast(\n                OefSearchDialogues, self.context.oef_search_dialogues\n            )\n            oef_search_msg, _ = oef_search_dialogues.create(\n                counterparty=self.context.search_service_address,\n                performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n                service_description=description,\n            )\n            self.context.outbox.put_message(message=oef_search_msg)\n            self.context.logger.info(logger_msg)\n    \n        def _register_agent(self) -> None:\n            \"\"\"\n            Register the agent's location.\n    \n            :return: None\n            \"\"\"\n            strategy = cast(Strategy, self.context.strategy)\n            description = strategy.get_location_description()\n            self._register(description, \"registering agent on SOEF.\")\n    \n        def register_service(self) -> None:\n            \"\"\"\n            Register the agent's service.\n    \n            :return: None\n            \"\"\"\n            strategy = cast(Strategy, self.context.strategy)\n            description = strategy.get_register_service_description()\n            self._register(description, \"registering agent's service on the SOEF.\")\n    \n        def register_genus(self) -> None:\n            \"\"\"\n            Register the agent's personality genus.\n    \n            :return: None\n            \"\"\"\n            strategy = cast(Strategy, self.context.strategy)\n            description = strategy.get_register_personality_description()\n            self._register(\n                description, \"registering agent's personality genus on the SOEF.\"\n            )\n    \n        def register_classification(self) -> None:\n            \"\"\"\n            Register the agent's personality classification.\n    \n            :return: None\n            \"\"\"\n            strategy = cast(Strategy, self.context.strategy)\n            description = strategy.get_register_classification_description()\n            self._register(\n                description, \"registering agent's personality classification on the SOEF.\"\n            )\n    \n        def _unregister_service(self) -> None:\n            \"\"\"\n            Unregister service from the SOEF.\n    \n            :return: None\n            \"\"\"\n            strategy = cast(Strategy, self.context.strategy)\n            description = strategy.get_unregister_service_description()\n            oef_search_dialogues = cast(\n                OefSearchDialogues, self.context.oef_search_dialogues\n            )\n            oef_search_msg, _ = oef_search_dialogues.create(\n                counterparty=self.context.search_service_address,\n                performative=OefSearchMessage.Performative.UNREGISTER_SERVICE,\n                service_description=description,\n            )\n            self.context.outbox.put_message(message=oef_search_msg)\n            self.context.logger.info(\"unregistering service from SOEF.\")\n    \n        def _unregister_agent(self) -> None:\n            \"\"\"\n            Unregister agent from the SOEF.\n    \n            :return: None\n            \"\"\"\n            strategy = cast(Strategy, self.context.strategy)\n            description = strategy.get_location_description()\n            oef_search_dialogues = cast(\n                OefSearchDialogues, self.context.oef_search_dialogues\n            )\n            oef_search_msg, _ = oef_search_dialogues.create(\n                counterparty=self.context.search_service_address,\n                performative=OefSearchMessage.Performative.UNREGISTER_SERVICE,\n                service_description=description,\n            )\n            self.context.outbox.put_message(message=oef_search_msg)\n            self.context.logger.info(\"unregistering agent from SOEF.\")\n    ```\n\n    We create a <a href=\"../api/skills/base#model-objects\"><code>Model</code></a> type strategy class and place it in <code>strategy.py</code>. We use a generic data model to register the service. As part of the registration we register a location and a key pair describing our service.\n    \n    ``` python\n    from typing import Any\n    \n    from aea.exceptions import enforce\n    from aea.helpers.search.generic import (\n        AGENT_LOCATION_MODEL,\n        AGENT_PERSONALITY_MODEL,\n        AGENT_REMOVE_SERVICE_MODEL,\n        AGENT_SET_SERVICE_MODEL,\n    )\n    from aea.helpers.search.models import Description, Location\n    from aea.skills.base import Model\n    \n    \n    DEFAULT_LOCATION = {\"longitude\": 0.1270, \"latitude\": 51.5194}\n    DEFAULT_SERVICE_DATA = {\"key\": \"seller_service\", \"value\": \"generic_service\"}\n    DEFAULT_PERSONALITY_DATA = {\"piece\": \"genus\", \"value\": \"data\"}\n    DEFAULT_CLASSIFICATION = {\"piece\": \"classification\", \"value\": \"seller\"}\n    \n    \n    class Strategy(Model):\n        \"\"\"This class defines a strategy for the agent.\"\"\"\n    \n        def __init__(self, **kwargs: Any) -> None:\n            \"\"\"\n            Initialize the strategy of the agent.\n    \n            :return: None\n            \"\"\"\n            location = kwargs.pop(\"location\", DEFAULT_LOCATION)\n            self._agent_location = {\n                \"location\": Location(\n                    latitude=location[\"latitude\"], longitude=location[\"longitude\"]\n                )\n            }\n            self._set_personality_data = kwargs.pop(\n                \"personality_data\", DEFAULT_PERSONALITY_DATA\n            )\n            enforce(\n                len(self._set_personality_data) == 2\n                and \"piece\" in self._set_personality_data\n                and \"value\" in self._set_personality_data,\n                \"personality_data must contain keys `key` and `value`\",\n            )\n            self._set_classification = kwargs.pop(\"classification\", DEFAULT_CLASSIFICATION)\n            enforce(\n                len(self._set_classification) == 2\n                and \"piece\" in self._set_classification\n                and \"value\" in self._set_classification,\n                \"classification must contain keys `key` and `value`\",\n            )\n            self._set_service_data = kwargs.pop(\"service_data\", DEFAULT_SERVICE_DATA)\n            enforce(\n                len(self._set_service_data) == 2\n                and \"key\" in self._set_service_data\n                and \"value\" in self._set_service_data,\n                \"service_data must contain keys `key` and `value`\",\n            )\n            self._remove_service_data = {\"key\": self._set_service_data[\"key\"]}\n            super().__init__(**kwargs)\n    \n        def get_location_description(self) -> Description:\n            \"\"\"\n            Get the location description.\n    \n            :return: a description of the agent's location\n            \"\"\"\n            description = Description(\n                self._agent_location, data_model=AGENT_LOCATION_MODEL,\n            )\n            return description\n    \n        def get_register_service_description(self) -> Description:\n            \"\"\"\n            Get the register service description.\n    \n            :return: a description of the offered services\n            \"\"\"\n            description = Description(\n                self._set_service_data, data_model=AGENT_SET_SERVICE_MODEL,\n            )\n            return description\n    \n        def get_register_personality_description(self) -> Description:\n            \"\"\"\n            Get the register personality description.\n    \n            :return: a description of the personality\n            \"\"\"\n            description = Description(\n                self._set_personality_data, data_model=AGENT_PERSONALITY_MODEL,\n            )\n            return description\n    \n        def get_register_classification_description(self) -> Description:\n            \"\"\"\n            Get the register classification description.\n    \n            :return: a description of the classification\n            \"\"\"\n            description = Description(\n                self._set_classification, data_model=AGENT_PERSONALITY_MODEL,\n            )\n            return description\n    \n        def get_unregister_service_description(self) -> Description:\n            \"\"\"\n            Get the unregister service description.\n    \n            :return: a description of the to be removed service\n            \"\"\"\n            description = Description(\n                self._remove_service_data, data_model=AGENT_REMOVE_SERVICE_MODEL,\n            )\n            return description\n    ```\n    \n    We create a <a href=\"../api/skills/base#model-objects\"><code>Model</code></a> type dialogue class and place it in <code>dialogues.py</code>. These classes ensure that the message flow satisfies the <code>fetchai/oef_search:1.0.0</code> protocol and keep track of the individual messages being sent and received.\n    \n    ``` python\n    from typing import Any\n    \n    from aea.protocols.base import Address, Message\n    from aea.protocols.dialogue.base import Dialogue as BaseDialogue\n    from aea.skills.base import Model\n    \n    from packages.fetchai.protocols.oef_search.dialogues import (\n        OefSearchDialogue as BaseOefSearchDialogue,\n    )\n    from packages.fetchai.protocols.oef_search.dialogues import (\n        OefSearchDialogues as BaseOefSearchDialogues,\n    )\n    \n    \n    OefSearchDialogue = BaseOefSearchDialogue\n    \n    \n    class OefSearchDialogues(Model, BaseOefSearchDialogues):\n        \"\"\"This class keeps track of all oef_search dialogues.\"\"\"\n    \n        def __init__(self, **kwargs: Any) -> None:\n            \"\"\"\n            Initialize dialogues.\n    \n            :param agent_address: the address of the agent for whom dialogues are maintained\n            :return: None\n            \"\"\"\n            Model.__init__(self, **kwargs)\n    \n            def role_from_first_message(  # pylint: disable=unused-argument\n                message: Message, receiver_address: Address\n            ) -> BaseDialogue.Role:\n                \"\"\"Infer the role of the agent from an incoming/outgoing first message\n    \n                :param message: an incoming/outgoing first message\n                :param receiver_address: the address of the receiving agent\n                :return: The role of the agent\n                \"\"\"\n                return BaseOefSearchDialogue.Role.AGENT\n    \n            BaseOefSearchDialogues.__init__(\n                self,\n                self_address=str(self.skill_id),\n                role_from_first_message=role_from_first_message,\n            )\n    \n    ```\n\n    Finally, we have a handler, placed in <code>handlers.py</code>. The handler deals with handling any error messages which might occur during service registration:\n    \n    ``` python\n    from typing import Optional, cast\n    \n    from aea.configurations.base import PublicId\n    from aea.protocols.base import Message\n    from aea.skills.base import Handler\n    \n    from packages.fetchai.protocols.oef_search.message import OefSearchMessage\n    from packages.fetchai.skills.simple_service_registration.behaviours import (\n        ServiceRegistrationBehaviour,\n    )\n    from packages.fetchai.skills.simple_service_registration.dialogues import (\n        OefSearchDialogue,\n        OefSearchDialogues,\n    )\n    \n    \n    class OefSearchHandler(Handler):\n        \"\"\"This class implements an OEF search handler.\"\"\"\n    \n        SUPPORTED_PROTOCOL = OefSearchMessage.protocol_id  # type: Optional[PublicId]\n    \n        def setup(self) -> None:\n            \"\"\"Call to setup the handler.\"\"\"\n    \n        def handle(self, message: Message) -> None:\n            \"\"\"\n            Implement the reaction to a message.\n    \n            :param message: the message\n            :return: None\n            \"\"\"\n            oef_search_msg = cast(OefSearchMessage, message)\n    \n            # recover dialogue\n            oef_search_dialogues = cast(\n                OefSearchDialogues, self.context.oef_search_dialogues\n            )\n            oef_search_dialogue = cast(\n                Optional[OefSearchDialogue], oef_search_dialogues.update(oef_search_msg)\n            )\n            if oef_search_dialogue is None:\n                self._handle_unidentified_dialogue(oef_search_msg)\n                return\n    \n            # handle message\n            if oef_search_msg.performative == OefSearchMessage.Performative.SUCCESS:\n                self._handle_success(oef_search_msg, oef_search_dialogue)\n            elif oef_search_msg.performative == OefSearchMessage.Performative.OEF_ERROR:\n                self._handle_error(oef_search_msg, oef_search_dialogue)\n            else:\n                self._handle_invalid(oef_search_msg, oef_search_dialogue)\n    \n        def teardown(self) -> None:\n            \"\"\"\n            Implement the handler teardown.\n    \n            :return: None\n            \"\"\"\n    \n        def _handle_unidentified_dialogue(self, oef_search_msg: OefSearchMessage) -> None:\n            \"\"\"\n            Handle an unidentified dialogue.\n    \n            :param msg: the message\n            \"\"\"\n            self.context.logger.info(\n                \"received invalid oef_search message={}, unidentified dialogue.\".format(\n                    oef_search_msg\n                )\n            )\n    \n        def _handle_success(\n            self,\n            oef_search_success_msg: OefSearchMessage,\n            oef_search_dialogue: OefSearchDialogue,\n        ) -> None:\n            \"\"\"\n            Handle an oef search message.\n    \n            :param oef_search_success_msg: the oef search message\n            :param oef_search_dialogue: the dialogue\n            :return: None\n            \"\"\"\n            self.context.logger.info(\n                \"received oef_search success message={} in dialogue={}.\".format(\n                    oef_search_success_msg, oef_search_dialogue\n                )\n            )\n            target_message = cast(\n                OefSearchMessage,\n                oef_search_dialogue.get_message_by_id(oef_search_success_msg.target),\n            )\n            if (\n                target_message.performative\n                == OefSearchMessage.Performative.REGISTER_SERVICE\n            ):\n                description = target_message.service_description\n                data_model_name = description.data_model.name\n                registration_behaviour = cast(\n                    ServiceRegistrationBehaviour, self.context.behaviours.service,\n                )\n                if \"location_agent\" in data_model_name:\n                    registration_behaviour.register_service()\n                elif \"set_service_key\" in data_model_name:\n                    registration_behaviour.register_genus()\n                elif (\n                    \"personality_agent\" in data_model_name\n                    and description.values[\"piece\"] == \"genus\"\n                ):\n                    registration_behaviour.register_classification()\n                elif (\n                    \"personality_agent\" in data_model_name\n                    and description.values[\"piece\"] == \"classification\"\n                ):\n                    self.context.logger.info(\n                        \"the agent, with its genus and classification, and its service are successfully registered on the SOEF.\"\n                    )\n                else:\n                    self.context.logger.warning(\n                        f\"received soef SUCCESS message as a reply to the following unexpected message: {target_message}\"\n                    )\n    \n        def _handle_error(\n            self,\n            oef_search_error_msg: OefSearchMessage,\n            oef_search_dialogue: OefSearchDialogue,\n        ) -> None:\n            \"\"\"\n            Handle an oef search message.\n    \n            :param oef_search_error_msg: the oef search message\n            :param oef_search_dialogue: the dialogue\n            :return: None\n            \"\"\"\n            self.context.logger.info(\n                \"received oef_search error message={} in dialogue={}.\".format(\n                    oef_search_error_msg, oef_search_dialogue\n                )\n            )\n            target_message = cast(\n                OefSearchMessage,\n                oef_search_dialogue.get_message_by_id(oef_search_error_msg.target),\n            )\n            if (\n                target_message.performative\n                == OefSearchMessage.Performative.REGISTER_SERVICE\n            ):\n                registration_behaviour = cast(\n                    ServiceRegistrationBehaviour, self.context.behaviours.service,\n                )\n                registration_behaviour.failed_registration_msg = target_message\n    \n        def _handle_invalid(\n            self, oef_search_msg: OefSearchMessage, oef_search_dialogue: OefSearchDialogue\n        ) -> None:\n            \"\"\"\n            Handle an oef search message.\n    \n            :param oef_search_msg: the oef search message\n            :param oef_search_dialogue: the dialogue\n            :return: None\n            \"\"\"\n            self.context.logger.warning(\n                \"cannot handle oef_search message of performative={} in dialogue={}.\".format(\n                    oef_search_msg.performative, oef_search_dialogue,\n                )\n            )\n    ```\n    \n    The associated <code>skill.yaml</code> is:\n    \n    ``` yaml\n    name: simple_service_registration\n    author: fetchai\n    version: 0.20.0\n    type: skill\n    description: The simple service registration skills is a skill to register a service.\n    license: Apache-2.0\n    aea_version: '>=1.0.0, <2.0.0'\n    fingerprint:\n      README.md: QmUgCcR7sDBQeeCBRKwDT7tPBTi3t4zSibyEqR3xdQUKmh\n      __init__.py: QmZd48HmYDr7FMxNaVeGfWRvVtieEdEV78hd7h7roTceP2\n      behaviours.py: QmQHf6QL5aBtLJ34D2tdcbjJLbzom9gaA3HWgRn3rWyigM\n      dialogues.py: QmTT9dvFhWt6qvxjwBfMFDTrgEtgWbvgANYafyRg2BXwcR\n      handlers.py: QmZqPt8toGbJgTT6NZBLxjkusrQCZ8GmUEwcmqZ1sd7DpG\n      strategy.py: QmVXfQpk4cjDw576H2ELE12tEiN5brPkwvffvcTeMbsugA\n    fingerprint_ignore_patterns: []\n    connections: []\n    contracts: []\n    protocols:\n    - fetchai/oef_search:1.1.7\n    skills: []\n    behaviours:\n      service:\n        args:\n          max_soef_registration_retries: 5\n          services_interval: 30\n        class_name: ServiceRegistrationBehaviour\n    handlers:\n      oef_search:\n        args: {}\n        class_name: OefSearchHandler\n    models:\n      oef_search_dialogues:\n        args: {}\n        class_name: OefSearchDialogues\n      strategy:\n        args:\n          classification:\n            piece: classification\n            value: seller\n          location:\n            latitude: 51.5194\n            longitude: 0.127\n          personality_data:\n            piece: genus\n            value: data\n          service_data:\n            key: seller_service\n            value: generic_service\n        class_name: Strategy\n    dependencies: {}\n    is_abstract: false\n    ```\n\n## Step 9: Run the Search AEA\n\nFirst, create the private key for the search AEA based on the network you want to transact. To generate and add a private-public key pair for Fetch.ai `Dorado` use:\n\n``` bash\naea generate-key fetchai\naea add-key fetchai fetchai_private_key.txt\n```\n\nNext, create a private key used to secure the AEA's communications:\n\n``` bash\naea generate-key fetchai fetchai_connection_private_key.txt\naea add-key fetchai fetchai_connection_private_key.txt --connection\n```\n\nFinally, certify the key for use by the connections that request that:\n\n``` bash\naea issue-certificates\n```\n\nThen, in the search AEA, run this command (replace `SOME_ADDRESS` with the correct value as described above):\n\n``` bash\naea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \\\n'{\n  \"delegate_uri\": \"127.0.0.1:11001\",\n  \"entry_peers\": [\"/dns4/127.0.0.1/tcp/9000/p2p/16Uiu2HAm1uJpFsqSgHStJdtTBPpDme1fo8uFEvvY182D2y89jQuj\"],\n  \"local_uri\": \"127.0.0.1:9001\",\n  \"log_file\": \"libp2p_node.log\",\n  \"public_uri\": \"127.0.0.1:9001\"\n}'\n```\n\nThis allows the search AEA to connect to the same local agent communication network as the service registration AEA.\n\nWe can then launch our AEA.\n\n``` bash\naea run\n```\n\nWe can see that the AEA sends search requests to the <a href=\"../simple-oef\">SOEF search node</a> and receives search responses from the <a href=\"../simple-oef\">SOEF search node</a>. The search response returns one or more agents (the service provider and potentially other agents which match the query).\n\nWe stop the AEA with `CTRL + C`.\n\n## Next Steps\n\n### Recommended\n\nWe recommend you continue with the next step in the 'Getting Started' series:\n\n- <a href=\"../core-components-2\">Core components (Part 2)</a>\n\n### Relevant Deep-Dives\n\n<a href=\"../generic-skills-step-by-step\"> This guide </a> goes through a more elaborate scenario than the one on this page, where after finding each other, the two AEAs negotiate and trade via a ledger.\n"
  },
  {
    "path": "docs/skill-testing.md",
    "content": "# Testing Skills\n\nIn this guide, we describe some of the tools the framework offers for testing skills.\n\n## The `BaseSkillTestCase` Class\n\nThe framework offers a <a href=\"../api/test_tools/test_skill#baseskilltestcase-objects\">`BaseSkillTestCase`</a> class which you can subclass and write your test cases with.\n\nLet us assume you want to test the `my_behaviour` behaviour of a `CustomSkill` skill you have developed.\n\nYou can create a `TestMyBehaviour` class which inherits `BaseSkillTestCase` as below:\n\n``` python\nimport asyncio\n\nfrom asyncio import Queue\nfrom pathlib import Path\nfrom types import SimpleNamespace\nfrom typing import cast\n\nfrom aea.configurations.constants import DEFAULT_LEDGER\nfrom aea.context.base import AgentContext\nfrom aea.crypto.ledger_apis import DEFAULT_CURRENCY_DENOMINATIONS\nfrom aea.identity.base import Identity\nfrom aea.multiplexer import AsyncMultiplexer, OutBox, Multiplexer\nfrom aea.skills.tasks import TaskManager\nfrom aea.test_tools.test_skill import BaseSkillTestCase\n\nclass TestMyBehaviour(BaseSkillTestCase):\n    \"\"\"Test my_behaviours of the custom skill.\"\"\"\n\n    path_to_skill = Path(\"path_to_this_skill\")\n```\n\n### Specifying Skill Path\n\nYou must then specify the path to your skill directory via `path_to_skill` to allow the skill to be loaded and tested. This must be the directory in which `skill.yaml` of your skill resides.\n\n### Setting up Each Test\n\nYou can add a `setup()` class method to set the environment up for each of your tests. This code will be executed before every test method. If you do include this method, you must call the `setup()` method of the `BaseSkillTestCase` class via `super().setup()`.\n\n``` python\n@classmethod\ndef setup(cls):\n    \"\"\"Setup the test class.\"\"\"\n    super().setup()\n    cls.my_behaviour = cast(\n        MyBehaviour, cls._skill.skill_context.behaviours.my_behaviour\n    )\n```\n\nIn the above, we make the `my_behaviour` behaviour object accessible for every test.\n\n### Skill and Skill Context\n\nThe skill object itself is exposed via a property. So you can access the skill object by `self.skill` and by extension all of its attributes. This crucially includes the complete `skill_context`. This means that for example, every component of the skill (e.g. behaviours, handlers, models) can be accessed via the skill context.\n\nIn the above code snippet, `my_behavior` is accessed and exposed as a class attribute. Note accessing the skill context is slightly different in the above because it is a class method. If this was a test method, you could access the behaviour via `self.skill.skill_context.behaviours.my_behaviour`.\n\n### Dummy Agent Context\n\nThe loaded skill is also fed a dummy `agent_context` complete with an `identity`, `outbox`, `decision_maker_queue` and so on, to allow the skill to be properly loaded and have access to everything it requires to function. The `agent_context` object fed to the skill is shown below:\n\n``` python\n_multiplexer = AsyncMultiplexer()\n_multiplexer._out_queue = (asyncio.Queue())\n\nagent_context = AgentContext(\n    identity=Identity(\"test_agent_name\", \"test_agent_address\", \"test_agent_public_key\"),\n    connection_status=_multiplexer.connection_status,\n    outbox=OutBox(cast(Multiplexer, cls._multiplexer)),\n    decision_maker_message_queue=Queue(),\n    decision_maker_handler_context=SimpleNamespace(),\n    task_manager=TaskManager(),\n    default_ledger_id=DEFAULT_LEDGER,\n    currency_denominations={},\n    default_connection=None,\n    default_routing={},\n    search_service_address=\"dummy_search_service_address\",\n    decision_maker_address=\"dummy_decision_maker_address\",\n    data_dir=\".\"\n)\n```\n\n### Some Useful Skill Attributes\n\nSome of the useful objects you can access in your test class for the loaded skill are below:\n\n- `self.skill.skill_context.agent_address`: this is the agent identity the skill uses and is set to `\"test_agent_address\"`.\n- `self.skill.skill_context.search_service_address`: this is the address of the search service and is set to `\"dummy_search_service_address\"`.\n- `self.skill.skill_context.skill_id`: this is the id of the skill.\n- `self.skill.skill_context.decision_maker_address`: this is the address of the decision maker and is set to `\"dummy_decision_maker_address\"`.\n\n### Some Useful `BaseSkillTestCase` Methods\n\nThere are a number of methods that `BaseSkillTestCase` offers to make testing skills easier. Some of these are mentioned below. For the rest, consult the API for `BaseSkillTestCase`:\n\n- `self.get_quantity_in_outbox()`: gives you the number of messages which are in the outbox. After running a part of the skill which is expected to send messages, you can use this method to assert the correct number of messages are indeed sent.\n- `self.get_message_from_outbox()`: gives you the last message in the outbox. Together with the above, you can use this method to grab the last message sent by the skill code you tested and check this is indeed the expected message.\n- `self.message_has_attributes(actual_message: Message, message_type: Type[Message], **kwargs,)`: you can use this method in tandem with the above method to check that a message has the attributes you expect it to have. You have to supply it with the actual message (e.g. using `self.get_message_from_outbox()`), specify its expected type (e.g. `FipaMessage`), and any other attribute you expect the message to have (e.g. `message_id` is 1) may be provided via keyword arguments.\n- `self.build_incoming_message`: this is an especially useful method to test handlers. Since handlers handle incoming messages, you can create an incoming message using this method to feed it to the handler and test its execution.\n\n#### Checking Logger Output\n\nYou can check the output of your skill's `logger` by mocking it using `unittest.mock` before executing a part of your skill as such:\n\n``` python\nimport logging\nfrom unittest import mock\n\nwith mock.patch.object(self.my_behaviour.context.logger, \"log\") as mock_logger:\n    self.my_behaviour.act()\n\nmock_logger.assert_any_call(logging.INFO, \"some_logger_message\")\n```\n\nIn the above, we mock the logger before running `my_behaviour`'s `act()` method and check that  the string `\"some_logger_message\"` is indeed passed to the logger.\n\n## Next Steps\n\nYou can consult the `fetchai/generic_buyer` and `fetchai/generic_seller` skills and their associated tests <a href=\"https://github.com/fetchai/agents-aea/tree/main/tests/test_packages/test_skills\" target=\"_blank\">here</a> to study how `BaseSkillTestCase` can help you in testing your skills.\n\nYou can also refer to the API to study the different methods `BaseSkillTestCase` makes available to make testing your skills easier.\n"
  },
  {
    "path": "docs/skill.md",
    "content": "# Skills\n\n<a href=\"../api/skills/base#skill-objects\">`Skills`</a> are the core focus of the framework's extensibility as they implement business logic to deliver economic value for the AEA. They are self-contained capabilities that AEAs can dynamically take on board, in order to expand their effectiveness in different situations.\n\n<img src=\"../assets/skill-components.jpg\" alt=\"Skill components of an AEA\" class=\"center\" style=\"display: block; margin-left: auto; margin-right: auto;width:80%;\">\n\nA skill encapsulates implementations of the three abstract base classes `Handler`, `Behaviour`, `Model`, and is closely related with the abstract base class `Task`:\n\n- <a href=\"../api/skills/base#handler-objects\">`Handler`</a>: each skill has zero, one or more `Handler` objects, each responsible for the registered messaging protocol. Handlers implement AEAs' **reactive** behaviour. If the AEA understands the protocol referenced in a received `Envelope`, the `Handler` reacts appropriately to the corresponding message. Each `Handler` is responsible for only one protocol. A `Handler` is also capable of dealing with internal messages (see next section).\n- <a href=\"../api/skills/base#behaviour-objects\">`Behaviour`</a>: zero, one or more `Behaviours` encapsulate actions which further the AEAs goal and are initiated by internals of the AEA, rather than external events. Behaviours implement AEAs' **pro-activeness**. The framework provides a number of <a href=\"../api/skills/behaviours\">abstract base classes</a> implementing different types of behaviours (e.g. cyclic/one-shot/finite-state-machine/etc.).\n- <a href=\"../api/skills/base#model-objects\">`Model`</a>: zero, one or more `Models` that inherit from the `Model` class. `Models` encapsulate custom objects which are made accessible to any part of a skill via the `SkillContext`.\n- <a href=\"../api/skills/tasks#task-objects\">`Task`</a>: zero, one or more `Tasks` encapsulate background work internal to the AEA. `Task` differs from the other three in that it is not a part of skills, but `Task`s are declared in or from skills if a packaging approach for AEA creation is used.\n\nA skill can read (parts of) the state of the AEA (as summarised in the <a href=\"../api/context/base#agentcontext-objects\">`AgentContext`</a>), and propose actions to the AEA according to its specific logic. As such, more than one skill could exist per protocol, competing with each other in suggesting to the AEA the best course of actions to take. In technical terms this means skills are horizontally arranged.\n\nFor instance, an AEA who is trading goods, could subscribe to more than one skill, where each skill corresponds to a different trading strategy.  The skills could then read the preference and ownership state of the AEA, and independently suggest profitable transactions.\n\nThe framework places no limits on the complexity of skills. They can implement simple (e.g. `if-this-then-that`) or complex (e.g. a deep learning model or reinforcement learning agent).\n\nThe framework provides one default skill, called `error`. Additional skills can be added as packages.\n\n## Independence of Skills\n\nSkills are `horizontally layered`, that is they run independently of each other. They also cannot access each other's state.\n\nTwo skills can communicate with each other in two ways. The skill context provides access via `self.context.shared_state` to a key-value store which allows skills to share state. A skill can also define as a callback another skill in <a href=\"../decision-maker-transaction\">a message to the decision maker</a>.\n\n## Context\n\nThe skill has a <a href=\"../api/skills/base#skillcontext-objects\">`SkillContext`</a> object which is shared by all `Handler`, `Behaviour`, and `Model` objects. The skill context also has a link to the `AgentContext`. The `AgentContext` provides read access to AEA specific information like the public key and address of the AEA, its preferences and ownership state. It also provides access to the `OutBox`.\n\nThis means it is possible to, at any point, grab the `context` and have access to the code in other parts of the skill and the AEA.\n\nFor example, in the `ErrorHandler(Handler)` class, the code often grabs a reference to its context and by doing so can access initialised and running framework objects such as an `OutBox` for putting messages into.\n\n``` python\nself.context.outbox.put_message(message=reply)\n```\n\nMoreover, you can read/write to the _agent context namespace_ by accessing the attribute `SkillContext.namespace`.\n\nImportantly, however, a skill does not have access to the context of another skill or protected AEA components like the `DecisionMaker`.\n\n## What to Code\n\nEach of the skill classes has three methods that must be implemented. All of them include a `setup()` and `teardown()` method which the developer must implement.\n\nThen there is a specific method that the framework requires for each class.\n\n### `handlers.py`\n\nThere can be none, one or more `Handler` class per skill.\n\n`Handler` classes can receive `Message` objects of one protocol type only. However, `Handler` classes can send `Envelope` objects of any type of protocol they require.\n\n- `handle(self, message: Message)`: is where the skill receives a `Message` of the specified protocol and decides what to do with it.\n\nA handler can be registered in one way:\n\n- By declaring it in the skill configuration file `skill.yaml` (see <a href=\"../skill/#skill-config\">below</a>).\n\nIt is possible to register new handlers dynamically by enqueuing new\n`Handler` instances in the queue `context.new_handlers`, e.g. in a skill\ncomponent we can write:\n\n``` python\nself.context.new_handlers.put(MyHandler(name=\"my_handler\", skill_context=self.context))\n```\n\n### `behaviours.py`\n\nConceptually, a `Behaviour`  class contains the business logic specific to initial actions initiated by the AEA rather than reactions to other events.\n\nThere can be one or more `Behaviour` classes per skill. The developer must create a subclass from the abstract class `Behaviour` to create a new `Behaviour`.\n\n- `act(self)`: is how the framework calls the `Behaviour` code.\n\nA behaviour can be registered in two ways:\n\n- By declaring it in the skill configuration file `skill.yaml` (see <a href=\"../skill/#skill-config\">below</a>)\n- In any part of the code of the skill, by enqueuing new `Behaviour` instances in the queue `context.new_behaviours`. In that case, `setup`is not called by the framework, as the behaviour will be added after the AEA setup is complete.\n\nThe framework supports different types of behaviours:\n\n- <a href=\"../api/skills/behaviours#oneshotbehaviour-objects\">`OneShotBehaviour`</a>: this behaviour is executed only once.\n- <a href=\"../api/skills/behaviours#tickerbehaviour-objects\">`TickerBehaviour`</a>: the `act()` method is called every `tick_interval`. E.g. if the `TickerBehaviour` subclass is instantiated\n\nThere is another category of behaviours, called <a href=\"../api/skills/behaviours#compositebehaviour-objects\">`CompositeBehaviour`</a>:\n\n- <a href=\"../api/skills/behaviours#sequencebehaviour-objects\">`SequenceBehaviour`</a>: a sequence of `Behaviour` classes, executed\n  one after the other.\n- <a href=\"../api/skills/behaviours#fsmbehaviour-objects\">`FSMBehaviour`</a>: a state machine of `State` behaviours. A state is in charge of scheduling the next state.\n\nIf your behaviour fits one of the above, we suggest subclassing your\nbehaviour class with that behaviour class. Otherwise, you\ncan always subclass the general-purpose `Behaviour` class.\n\nFollows an example of a custom behaviour:\n\n``` python\n\nfrom aea.skills.behaviours import OneShotBehaviour\n\nclass HelloWorldBehaviour(OneShotBehaviour):\n        \n    def setup(self):\n        \"\"\"This method is called once, when the behaviour gets loaded.\"\"\"\n\n    def act(self):\n        \"\"\"This methods is called in every iteration of the agent main loop.\"\"\"\n        print(\"Hello, World!\")\n\n    def teardown(self):\n        \"\"\"This method is called once, when the behaviour is teared down.\"\"\"\n    \n\n```\n\nIf we want to register this behaviour dynamically, in any part of the skill code\n(i.e. wherever the skill context is available), we can write:\n\n``` python\nself.context.new_behaviours.put(HelloWorldBehaviour(name=\"hello_world\", skill_context=self.context))\n```\n\nOr, equivalently to the previous two code blocks:\n\n``` python\ndef hello():\n    print(\"Hello, World!\")\n\nself.context.new_behaviours.put(OneShotBehaviour(act=hello, name=\"hello_world\", skill_context=self.context))\n```\n\nThe callable passed to the `act` parameter is equivalent to the implementation\nof the `act` method described above.\n\nThe framework is then in charge of registering the behaviour and scheduling it\nfor execution.\n\n### `tasks.py`\n\nConceptually, a `Task` is where the developer codes any internal tasks the AEA requires.\n\nThere can be one or more `Task` classes per skill. The developer subclasses abstract class `Task` to create a new `Task`.\n\n- `execute(self)`: is how the framework calls a `Task`.\n\nThe `Task` class implements the <a href=\"https://en.wikipedia.org/wiki/Function_object\" target=\"_blank\">functor pattern</a>.\nAn instance of the `Task` class can be invoked as if it\nwere an ordinary function. Once completed, it will store the\nresult in the property `result`. Raises error if the task has not been executed yet,\nor an error occurred during computation.\n\nWe suggest using the `task_manager`, accessible through the skill context,\nto manage long-running tasks. The task manager uses `multiprocessing` to\nschedule tasks, so be aware that the changes on the task object will\nnot be updated.\n\nHere's an example:\n\nIn `tasks.py`:\n\n``` python\n\nfrom aea.skills.tasks import Task\n\n\ndef nth_prime_number(n: int) -> int:\n    \"\"\"A naive algorithm to find the n_th prime number.\"\"\"\n    assert n > 0\n    primes = [2]\n    num = 3\n    while len(primes) < n:\n        for p in primes:\n            if num % p == 0:\n                break\n        else:\n            primes.append(num)\n        num += 2\n    return primes[-1]\n\n\nclass LongTask(Task):\n\n    def setup(self):\n        \"\"\"Set the task up before execution.\"\"\"\n\n    def execute(self, n: int):\n        return nth_prime_number(n)\n\n    def teardown(self):\n        \"\"\"Clean the task up after execution.\"\"\"\n\n\n```\n\nIn `behaviours.py`:\n\n``` python\n\nfrom aea.skills.behaviours import TickerBehaviour\nfrom packages.my_author_name.skills.my_skill.tasks import LongTask\n\n\nclass MyBehaviour(TickerBehaviour):\n\n    def setup(self):\n        \"\"\"Setup behaviour.\"\"\"\n        my_task = LongTask()\n        task_id = self.context.task_manager.enqueue_task(my_task, args=(10000, ))\n        self.async_result = self.context.task_manager.get_task_result(task_id)  # type: multiprocessing.pool.AsyncResult\n\n    def act(self):\n        \"\"\"Act implementation.\"\"\"\n        if self.async_result.ready() is False:\n            print(\"The task is not finished yet.\")\n        else:\n            completed_task = self.async_result.get()  # type: LongTask\n            print(\"The result is:\", completed_task.result)\n            # Stop the skill\n            self.context.is_active = False\n\n    def teardown(self):\n        \"\"\"Teardown behaviour.\"\"\"\n\n\n```\n\n### Models\n\nThe developer might want to add other classes on the context level which are shared equally across the `Handler`, `Behaviour` and `Task` classes. To this end, the developer can subclass an abstract <a href=\"../api/skills/base#model-objects\">`Model`</a>. These models are made available on the context level upon initialization of the AEA.\n\nSay, the developer has a class called `SomeModel`\n\n``` python\nclass SomeModel(Model):\n    ...\n```\n\nThen, an instance of this class is available on the context level like so:\n\n``` python\nsome_model = self.context.some_model\n```\n\n### Skill Configuration\n\nEach skill has a `skill.yaml` configuration file which lists all `Behaviour`, `Handler`, and `Task` objects pertaining to the skill.\n\nIt also details the protocol types used in the skill and points to shared modules, i.e. modules of type `Model`, which allow custom classes within the skill to be accessible in the skill context.\n\n``` yaml\nname: echo\nauthors: fetchai\nversion: 0.1.0\nlicense: Apache-2.0\nbehaviours:\n  echo:\n    class_name: EchoBehaviour\n    args:\n      tick_interval: 1.0\nhandlers:\n  echo:\n    class_name: EchoHandler\n    args:\n      foo: bar\nmodels: {}\ndependencies: {}\nprotocols:\n- fetchai/default:1.1.7\n```\n\n## Error Skill\n\nAll AEAs have a default `error` skill that contains error handling code for a number of scenarios:\n\n- Received envelopes with unsupported protocols\n- Received envelopes with unsupported skills (i.e. protocols for which no handler is registered)\n- Envelopes with decoding errors\n- Invalid messages with respect to the registered protocol\n\nThe error skill relies on the `fetchai/default:1.0.0` protocol which provides error codes for the above.\n\n## Custom Error Handler\n\nThe framework implements a default <a href=\"../api/error_handler/default#errorhandler-objects\">`ErrorHandler`</a>.\nYou can implement your own and mount it. The easiest way to do this is to run the following command to scaffold a custom `ErrorHandler`:\n\n``` bash\naea scaffold error-handler\n```\n\nNow you will see a file called `error_handler.py` in the AEA project root.\nYou can then implement your own custom logic to process messages.\n"
  },
  {
    "path": "docs/standalone-transaction.md",
    "content": "# Create Stand-Alone Transaction\n\nIn this guide, we will generate some wealth for the Fetch.ai testnet and create a standalone transaction. After the completion of the transaction, we get the transaction digest. With this we can search for the transaction on the <a href='https://explore-dorado.fetch.ai/' target=\"_blank\">block explorer</a>\n\nThis guide requires the `aea-ledger-fetchai` plug-in installed in your Python environment:\n\n``` bash\npip install aea-ledger-fetchai\n```\n\nFirst, import the python and application specific libraries and set the static variables.\n\n``` python\nimport logging\n\nfrom aea_ledger_fetchai import FetchAICrypto\n\nfrom aea.crypto.helpers import create_private_key, try_generate_testnet_wealth\nfrom aea.crypto.ledger_apis import LedgerApis\nfrom aea.crypto.wallet import Wallet\n\n\nlogger = logging.getLogger(\"aea\")\nlogging.basicConfig(level=logging.INFO)\n\nFETCHAI_PRIVATE_KEY_FILE_1 = \"fetchai_private_key_1.txt\"\nFETCHAI_PRIVATE_KEY_FILE_2 = \"fetchai_private_key_2.txt\"\n```\n\n## Create the Private Keys\n\n``` python\n    # Create a private keys\n    create_private_key(\n        FetchAICrypto.identifier, private_key_file=FETCHAI_PRIVATE_KEY_FILE_1\n    )\n    create_private_key(\n        FetchAICrypto.identifier, private_key_file=FETCHAI_PRIVATE_KEY_FILE_2\n    )\n```\n\n## Create the Wallets\n\nOnce we created the private keys we need to generate the wallets.\n\n``` python\n    # Set up the wallets\n    wallet_1 = Wallet({FetchAICrypto.identifier: FETCHAI_PRIVATE_KEY_FILE_1})\n    wallet_2 = Wallet({FetchAICrypto.identifier: FETCHAI_PRIVATE_KEY_FILE_2})\n```\n\n## Generate Wealth\n\nSince we want to send funds from `wallet_1` to `wallet_2`, we need to generate some wealth for the `wallet_1`. We can\ndo this with the following code\n\n``` python\n    # Generate some wealth\n    try_generate_testnet_wealth(\n        FetchAICrypto.identifier, wallet_1.addresses[FetchAICrypto.identifier]\n    )\n```\n\n## Send Transaction\n\nFinally, we create a transaction that sends the funds to the `wallet_2`\n\n``` python\n    # Create the transaction and send it to the ledger.\n    tx_nonce = LedgerApis.generate_tx_nonce(\n        FetchAICrypto.identifier,\n        wallet_2.addresses.get(FetchAICrypto.identifier),\n        wallet_1.addresses.get(FetchAICrypto.identifier),\n    )\n    transaction = LedgerApis.get_transfer_transaction(\n        identifier=FetchAICrypto.identifier,\n        sender_address=wallet_1.addresses.get(FetchAICrypto.identifier),\n        destination_address=wallet_2.addresses.get(FetchAICrypto.identifier),\n        amount=1,\n        tx_fee=1,\n        tx_nonce=tx_nonce,\n    )\n    signed_transaction = wallet_1.sign_transaction(\n        FetchAICrypto.identifier, transaction\n    )\n    transaction_digest = LedgerApis.send_signed_transaction(\n        FetchAICrypto.identifier, signed_transaction\n    )\n\n    logger.info(\"Transaction complete.\")\n    logger.info(\"The transaction digest is {}\".format(transaction_digest))\n```\n\n??? note \"Stand-alone transaction full code:\"\n\n    ``` python\n    import logging\n\n    from aea_ledger_fetchai import FetchAICrypto\n    \n    from aea.crypto.helpers import create_private_key, try_generate_testnet_wealth\n    from aea.crypto.ledger_apis import LedgerApis\n    from aea.crypto.wallet import Wallet\n    \n    \n    logger = logging.getLogger(\"aea\")\n    logging.basicConfig(level=logging.INFO)\n    \n    FETCHAI_PRIVATE_KEY_FILE_1 = \"fetchai_private_key_1.txt\"\n    FETCHAI_PRIVATE_KEY_FILE_2 = \"fetchai_private_key_2.txt\"\n    \n    \n    def run():\n        \"\"\"Run demo.\"\"\"\n    \n        # Create a private keys\n        create_private_key(\n            FetchAICrypto.identifier, private_key_file=FETCHAI_PRIVATE_KEY_FILE_1\n        )\n        create_private_key(\n            FetchAICrypto.identifier, private_key_file=FETCHAI_PRIVATE_KEY_FILE_2\n        )\n    \n        # Set up the wallets\n        wallet_1 = Wallet({FetchAICrypto.identifier: FETCHAI_PRIVATE_KEY_FILE_1})\n        wallet_2 = Wallet({FetchAICrypto.identifier: FETCHAI_PRIVATE_KEY_FILE_2})\n    \n        # Generate some wealth\n        try_generate_testnet_wealth(\n            FetchAICrypto.identifier, wallet_1.addresses[FetchAICrypto.identifier]\n        )\n    \n        logger.info(\n            \"Sending amount to {}\".format(wallet_2.addresses.get(FetchAICrypto.identifier))\n        )\n    \n        # Create the transaction and send it to the ledger.\n        tx_nonce = LedgerApis.generate_tx_nonce(\n            FetchAICrypto.identifier,\n            wallet_2.addresses.get(FetchAICrypto.identifier),\n            wallet_1.addresses.get(FetchAICrypto.identifier),\n        )\n        transaction = LedgerApis.get_transfer_transaction(\n            identifier=FetchAICrypto.identifier,\n            sender_address=wallet_1.addresses.get(FetchAICrypto.identifier),\n            destination_address=wallet_2.addresses.get(FetchAICrypto.identifier),\n            amount=1,\n            tx_fee=1,\n            tx_nonce=tx_nonce,\n        )\n        signed_transaction = wallet_1.sign_transaction(\n            FetchAICrypto.identifier, transaction\n        )\n        transaction_digest = LedgerApis.send_signed_transaction(\n            FetchAICrypto.identifier, signed_transaction\n        )\n    \n        logger.info(\"Transaction complete.\")\n        logger.info(\"The transaction digest is {}\".format(transaction_digest))\n    \n    \n    if __name__ == \"__main__\":\n        run()\n    ```\n"
  },
  {
    "path": "docs/step-one.md",
    "content": "# Ways to Build an AEA\n\nThere are a number of ways to build an AEA:\n\n- To start with, we recommended you build an AEA project step-by-step with the CLI tool as demonstrated in the <a href=\"../quickstart/\" target=\"_blank\">quick start</a> guide and described <a href=\"../build-aea-step-by-step/\" target=\"_blank\">here</a>.\n- Using the CLI `aea fetch` command, pull in an already built project and run as is or extend it to your needs.\n- The last option is to build an AEA programmatically as described <a href=\"../build-aea-programmatically/\" target=\"_blank\">here</a>.\n\nSometimes, an AEA is more than is required for the task at hand. In particular, an AEA is much more than just an agent. In those cases, we suggest you have a look at the following two guides:\n\n- the <a href=\"../agent-vs-aea/\" target=\"_blank\">AEA vs Agents</a> guide shows the difference between an agent and an AEA in code,\n- the <a href=\"../multiplexer-standalone/\" target=\"_blank\">Use multiplexer standalone</a> guide shows how to use the multiplexer on its own to receive and send envelopes.\n"
  },
  {
    "path": "docs/tac-skills-contract.md",
    "content": "# TAC Skills Ledger-Based\n\nThe AEA TAC - trading agent competition - skills demonstrate an interaction between multiple AEAs in a game.\n\nThere are two types of AEAs:\n\n- The `tac_controller` which coordinates the game.\n- The `tac_participant` AEAs which compete in the game. The `tac_participant` AEAs trade tokens with each other to maximize their utility.\n\n## Discussion\n\nThis demo shows how agents negotiate autonomously with each other while they pursue their goals by participating in the Trading Agents Competition (TAC).\nThe demo can be run against Fetchai or Ethereum ledger.\nTransactions are validated on an ERC1155 smart contract on the Fetchai Dorado or a local Ganache Ethereum testnet.\n\nIn the following video we discuss the framework and TAC in more detail:\n\n<iframe width=\"560\" height=\"315\" src=\"https://www.youtube.com/embed/gvzYX7CYk-A\" frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen></iframe>\n\n## Communication\n\nThere are two types of interactions:\n\n- between the controller and participants (game management communication)\n- between the participants (negotiations)\n\n### Registration Communication\n\nThis diagram shows the communication between the various entities during the registration phase.\n\n``` mermaid\n    sequenceDiagram\n        participant Agent_2\n        participant Agent_1\n        participant Search\n        participant Controller\n    \n        activate Search\n        activate Controller\n        \n        Controller->>Search: register_service\n        activate Agent_1\n        Agent_1->>Search: search\n        Search-->>Agent_1: controller\n        Agent_1->>Controller: register\n        activate Agent_2\n        Agent_2->>Search: search\n        Search-->>Agent_2: controller\n        Agent_2->>Controller: register\n        Controller->>Agent_1: game_data\n        Controller->>Agent_2: game_data\n        \n        deactivate Agent_1\n        deactivate Agent_2\n        deactivate Search\n        deactivate Controller\n```\n\n### Transaction Communication\n\nThis diagram shows the communication between two AEAs and a controller. In this case, we have a `Seller_Agent` which is set up as a seller (and registers itself as such with the controller during the registration phase). We also have the `Searching_Agent` which is set up to search for sellers.\n\n``` mermaid\n    sequenceDiagram\n        participant Buyer_Agent\n        participant Seller_Agent\n        participant Search\n        participant Controller\n    \n        activate Buyer_Agent\n        activate Seller_Agent\n        activate Search\n        activate Controller\n        \n        Seller_Agent->>Search: register_service\n        Buyer_Agent->>Search: search\n        Search-->>Buyer_Agent: list_of_agents\n        Buyer_Agent->>Seller_Agent: call_for_proposal\n        Seller_Agent->>Buyer_Agent: proposal\n        Buyer_Agent->>Seller_Agent: accept\n        Seller_Agent->>Buyer_Agent: match_accept\n        Seller_Agent->>Controller: transaction\n        Controller->>Controller: transaction_execution\n        Controller->>Seller_Agent: confirm_transaction\n        Controller->>Buyer_Agent: confirm_transaction\n        \n        deactivate Buyer_Agent\n        deactivate Seller_Agent\n        deactivate Search\n        deactivate Controller\n```\n\nIn the above case, the proposal received contains a set of goods to sell and an associated price. The buyer AEA needs to determine if this is a good deal for them, and if so, it accepts.\n\nThere is an equivalent diagram for seller AEAs set up to search for buyers and their interaction with AEAs which are registered as buyers. In that scenario, the proposal will instead be a list of goods that the buyer wishes to buy and the price it is willing to pay for them.\n\n## Preparation Instructions\n\n### Dependencies\n\nFollow the <a href=\"../quickstart/#preliminaries\">Preliminaries</a> and <a href=\"../quickstart/#installation\">Installation</a> sections from the AEA quick start.\n\n## Demo Instructions (Fetchai)\n\nFollow this instruction to run TAC against the fetch.ai Dorado testnet.\n\n### Fetch TAC Controller AEA\n\nIn the root directory, fetch the controller AEA:\n\n``` bash\naea fetch fetchai/tac_controller_contract:0.32.5\ncd tac_controller_contract\naea install\naea build\n```\n\n??? note \"Alternatively, create from scratch:\"\n    The following steps create the controller from scratch:\n\n    ``` bash\n    aea create tac_controller_contract\n    cd tac_controller_contract\n    aea add connection fetchai/p2p_libp2p:0.27.5\n    aea add connection fetchai/soef:0.27.6\n    aea add connection fetchai/ledger:0.21.5\n    aea add skill fetchai/tac_control_contract:0.27.6\n    aea config set --type dict agent.dependencies \\\n    '{\n      \"aea-ledger-fetchai\": {\"version\": \"<2.0.0,>=1.0.0\"},\n      \"aea-ledger-ethereum\": {\"version\": \"<2.0.0,>=1.0.0\"}\n    }'\n    aea config set agent.default_connection fetchai/p2p_libp2p:0.27.5\n    aea config set agent.default_ledger fetchai\n    aea config set vendor.fetchai.connections.soef.config.chain_identifier fetchai_v2_misc\n    aea config set --type bool vendor.fetchai.skills.tac_control.is_abstract true\n    aea config set --type dict agent.default_routing \\\n    '{\n      \"fetchai/contract_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n      \"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n      \"fetchai/oef_search:1.1.7\": \"fetchai/soef:0.27.6\"\n    }'\n    aea config set --type list vendor.fetchai.connections.p2p_libp2p.cert_requests \\\n    '[{\"identifier\": \"acn\", \"ledger_id\": \"fetchai\", \"not_after\": \"2023-01-01\", \"not_before\": \"2022-01-01\", \"public_key\": \"fetchai\", \"save_path\": \".certs/conn_cert.txt\"}]'\n    aea install\n    aea build\n    ```\n\n### Fetch the TAC Participant AEAs\n\nIn separate terminals, in the root directory, fetch at least two participants:\n\n``` bash\naea fetch fetchai/tac_participant_contract:0.22.5 --alias tac_participant_one\ncd tac_participant_one\naea install\naea build\ncd ..\naea fetch fetchai/tac_participant_contract:0.22.5 --alias tac_participant_two\ncd tac_participant_two\naea install\naea build\n```\n\n??? note \"Alternatively, create from scratch:\"\n    In a separate terminal, in the root directory, create at least two tac participant AEAs:\n\n    ``` bash\n    aea create tac_participant_one\n    aea create tac_participant_two\n    ```\n\n    Build participant one:\n\n    ``` bash\n    cd tac_participant_one\n    aea add connection fetchai/p2p_libp2p:0.27.5\n    aea add connection fetchai/soef:0.27.6\n    aea add connection fetchai/ledger:0.21.5\n    aea add skill fetchai/tac_participation:0.25.6\n    aea add skill fetchai/tac_negotiation:0.29.6\n    aea config set --type dict agent.dependencies \\\n    '{\n      \"aea-ledger-fetchai\": {\"version\": \"<2.0.0,>=1.0.0\"},\n      \"aea-ledger-ethereum\": {\"version\": \"<2.0.0,>=1.0.0\"}\n    }'\n    aea config set agent.default_connection fetchai/p2p_libp2p:0.27.5\n    aea config set agent.default_ledger fetchai\n    aea config set vendor.fetchai.connections.soef.config.chain_identifier fetchai_v2_misc\n    aea config set vendor.fetchai.skills.tac_participation.models.game.args.is_using_contract 'True' --type bool\n    aea config set vendor.fetchai.skills.tac_negotiation.models.strategy.args.is_contract_tx 'True' --type bool\n    aea config set --type dict agent.default_routing \\\n    '{\n      \"fetchai/contract_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n      \"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n      \"fetchai/oef_search:1.1.7\": \"fetchai/soef:0.27.6\"\n    }'\n    aea config set --type dict agent.decision_maker_handler \\\n    '{\n      \"dotted_path\": \"aea.decision_maker.gop:DecisionMakerHandler\",\n      \"file_path\": null\n    }'\n    aea config set --type list vendor.fetchai.connections.p2p_libp2p.cert_requests \\\n    '''[{\"identifier\": \"acn\", \"ledger_id\": \"fetchai\", \"message_format\": \"'{public_key}'\", \"not_after\": \"2023-01-01\", \"not_before\": \"2022-01-01\", \"public_key\": \"fetchai\", \"save_path\": \".certs/conn_cert.txt\"}]'''\n    aea install\n    aea build\n    ```\n\n    Then, build participant two:\n\n    ``` bash\n    cd tac_participant_two\n    aea add connection fetchai/p2p_libp2p:0.27.5\n    aea add connection fetchai/soef:0.27.6\n    aea add connection fetchai/ledger:0.21.5\n    aea add skill fetchai/tac_participation:0.25.6\n    aea add skill fetchai/tac_negotiation:0.29.6\n    aea config set --type dict agent.dependencies \\\n    '{\n      \"aea-ledger-fetchai\": {\"version\": \"<2.0.0,>=1.0.0\"},\n      \"aea-ledger-ethereum\": {\"version\": \"<2.0.0,>=1.0.0\"}\n    }'\n    aea config set agent.default_connection fetchai/p2p_libp2p:0.27.5\n    aea config set agent.default_ledger fetchai\n    aea config set vendor.fetchai.connections.soef.config.chain_identifier fetchai_v2_misc\n    aea config set vendor.fetchai.skills.tac_participation.models.game.args.is_using_contract 'True' --type bool\n    aea config set vendor.fetchai.skills.tac_negotiation.models.strategy.args.is_contract_tx 'True' --type bool\n    aea config set --type dict agent.default_routing \\\n    '{\n      \"fetchai/contract_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n      \"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n      \"fetchai/oef_search:1.1.7\": \"fetchai/soef:0.27.6\"\n    }'\n    aea config set --type dict agent.decision_maker_handler \\\n    '{\n      \"dotted_path\": \"aea.decision_maker.gop:DecisionMakerHandler\",\n      \"file_path\": null\n    }'\n    aea config set --type list vendor.fetchai.connections.p2p_libp2p.cert_requests \\\n    '''[{\"identifier\": \"acn\", \"ledger_id\": \"fetchai\", \"message_format\": \"'{public_key}'\", \"not_after\": \"2023-01-01\", \"not_before\": \"2022-01-01\", \"public_key\": \"fetchai\", \"save_path\": \".certs/conn_cert.txt\"}]'''\n    aea install\n    aea build\n    ```\n\n### Add Keys for All AEAs\n\nFor every AEA in the competition (controller and participants):\n\nFirst generate and add a private key:\n\n``` bash\naea generate-key fetchai\naea add-key fetchai fetchai_private_key.txt\n```\n\nThen create and add a separate private key for secure communication:\n\n``` bash\naea generate-key fetchai fetchai_connection_private_key.txt\naea add-key fetchai fetchai_connection_private_key.txt --connection\n```\n\nFinally, certify the key for use by the connections that request that:\n\n``` bash\naea issue-certificates\n```\n\n### Update the Game Parameters in the Controller\n\nIn the tac controller project, get and set the registration start time (set it to at least 5 minutes in the future):\n\n``` bash\naea config get vendor.fetchai.skills.tac_control_contract.models.parameters.args.registration_start_time\naea config set vendor.fetchai.skills.tac_control_contract.models.parameters.args.registration_start_time '01 01 2020  00:01'\n```\n\nTo set the registration time, you may find handy the following command:\n\n``` bash\naea config set vendor.fetchai.skills.tac_control_contract.models.parameters.args.registration_start_time \"$(date -d \"5 minutes\" +'%d %m %Y %H:%M')\"\n```\n\n### Update the Connection Parameters\n\nUpdate the connection parameters of the TAC participants to allow them to connect to the same local agent communication network as the TAC controller.\n\nFirst, retrieve controller's local ACN address by running the following in the controller agent's project terminal:\n\n``` bash\naea get-multiaddress fetchai -c -i fetchai/p2p_libp2p:0.27.5 -u public_uri\n```\n\nThen, in participant one, run this command (replace `SOME_ADDRESS` with the value you retrieved above):\n\n``` bash\naea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \\\n'{\n  \"delegate_uri\": \"127.0.0.1:11001\",\n  \"entry_peers\": [\"SOME_ADDRESS\"],\n  \"local_uri\": \"127.0.0.1:9001\",\n  \"log_file\": \"libp2p_node.log\",\n  \"public_uri\": \"127.0.0.1:9001\"\n}'\n```\n\nDo the same in participant two (beware of the different port numbers):\n\n``` bash\naea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \\\n'{\n  \"delegate_uri\": \"127.0.0.1:11002\",\n  \"entry_peers\": [\"SOME_ADDRESS\"],\n  \"local_uri\": \"127.0.0.1:9002\",\n  \"log_file\": \"libp2p_node.log\",\n  \"public_uri\": \"127.0.0.1:9002\"\n}'\n```\n\n## Fund Agents' Accounts\n\nRetrieve the address of each agent (in each terminal):\n\n``` bash\naea get-address fetchai\n```\n\nGo to the <a href=\"https://explore-dorado.fetch.ai\" target=\"_blank\">Dorado block explorer</a> and request some test tokens via `Get Funds`.\n\nTo check the wealth of an AEA, use:\n\n``` bash\naea get-wealth fetchai\n```\n\n### Run the AEAs\n\nFirst, launch the `tac_contract_controller` then the participants by executing the following from their respective terminals:\n\n``` bash\naea run\n```\n\nThe CLI tool supports launching several agents at once.\nFor example, assuming you followed the tutorial, you\ncan launch both TAC participant agents as follows from the root directory (ensure you run the controller agent first as above):\n\n``` bash\naea launch tac_participant_one tac_participant_two\n```\n\nYou may want to try `--multithreaded`\noption in order to run the agents\nin the same process.\n\n### Cleaning up\n\nWhen you're finished, delete your AEAs:\n\n``` bash\naea delete tac_controller_contract\naea delete tac_participant_one\naea delete tac_participant_two\n```\n\n## Demo Instructions (Ethereum)\n\nFollow this instruction to run TAC against a local Ganache Ethereum test-net.\n\n### Create TAC Controller AEA\n\nIn the root directory, fetch the controller AEA:\n\n``` bash\naea fetch fetchai/tac_controller_contract:0.32.5\ncd tac_controller_contract\naea install\naea build\n```\n\n??? note \"Alternatively, create from scratch:\"\n    The following steps create the controller from scratch:\n\n    ``` bash\n    aea create tac_controller_contract\n    cd tac_controller_contract\n    aea add connection fetchai/p2p_libp2p:0.27.5\n    aea add connection fetchai/soef:0.27.6\n    aea add connection fetchai/ledger:0.21.5\n    aea add skill fetchai/tac_control_contract:0.27.6\n    aea config set --type dict agent.dependencies \\\n    '{\n      \"aea-ledger-fetchai\": {\"version\": \"<2.0.0,>=1.0.0\"},\n      \"aea-ledger-ethereum\": {\"version\": \"<2.0.0,>=1.0.0\"}\n    }'\n    aea config set agent.default_connection fetchai/p2p_libp2p:0.27.5\n    aea config set agent.default_ledger ethereum\n    aea config set vendor.fetchai.connections.soef.config.chain_identifier ethereum\n    aea config set --type bool vendor.fetchai.skills.tac_control.is_abstract true\n    aea config set --type dict agent.default_routing \\\n    '{\n      \"fetchai/contract_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n      \"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n      \"fetchai/oef_search:1.1.7\": \"fetchai/soef:0.27.6\"\n    }'\n    aea config set --type list vendor.fetchai.connections.p2p_libp2p.cert_requests \\\n    '[{\"identifier\": \"acn\", \"ledger_id\": \"ethereum\", \"not_after\": \"2023-01-01\", \"not_before\": \"2022-01-01\", \"public_key\": \"fetchai\", \"save_path\": \".certs/conn_cert.txt\"}]'\n    aea install\n    aea build\n    ```\n\n### Fetch the TAC Participant AEAs\n\nIn separate terminals, in the root directory, fetch at least two participants:\n\n``` bash\naea fetch fetchai/tac_participant_contract:0.22.5 --alias tac_participant_one\ncd tac_participant_one\naea install\naea build\ncd ..\naea fetch fetchai/tac_participant_contract:0.22.5 --alias tac_participant_two\ncd tac_participant_two\naea install\naea build\n```\n\n??? note \"Alternatively, create from scratch:\"\n    In a separate terminal, in the root directory, create at least two tac participant AEAs:\n\n    ``` bash\n    aea create tac_participant_one\n    aea create tac_participant_two\n    ```\n\n    Build participant one:\n\n    ``` bash\n    cd tac_participant_one\n    aea add connection fetchai/p2p_libp2p:0.27.5\n    aea add connection fetchai/soef:0.27.6\n    aea add connection fetchai/ledger:0.21.5\n    aea add skill fetchai/tac_participation:0.25.6\n    aea add skill fetchai/tac_negotiation:0.29.6\n    aea config set --type dict agent.dependencies \\\n    '{\n      \"aea-ledger-fetchai\": {\"version\": \"<2.0.0,>=1.0.0\"},\n      \"aea-ledger-ethereum\": {\"version\": \"<2.0.0,>=1.0.0\"}\n    }'\n    aea config set agent.default_connection fetchai/p2p_libp2p:0.27.5\n    aea config set agent.default_ledger ethereum\n    aea config set vendor.fetchai.connections.soef.config.chain_identifier ethereum\n    aea config set vendor.fetchai.skills.tac_participation.models.game.args.is_using_contract 'True' --type bool\n    aea config set vendor.fetchai.skills.tac_negotiation.models.strategy.args.is_contract_tx 'True' --type bool\n    aea config set --type dict agent.default_routing \\\n    '{\n      \"fetchai/contract_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n      \"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n      \"fetchai/oef_search:1.1.7\": \"fetchai/soef:0.27.6\"\n    }'\n    aea config set --type dict agent.decision_maker_handler \\\n    '{\n      \"dotted_path\": \"aea.decision_maker.gop:DecisionMakerHandler\",\n      \"file_path\": null\n    }'\n    aea config set --type list vendor.fetchai.connections.p2p_libp2p.cert_requests \\\n    '''[{\"identifier\": \"acn\", \"ledger_id\": \"ethereum\", \"message_format\": \"'{public_key}'\", \"not_after\": \"2023-01-01\", \"not_before\": \"2022-01-01\", \"public_key\": \"fetchai\", \"save_path\": \".certs/conn_cert.txt\"}]'''\n    aea install\n    aea build\n    ```\n    \n    Then, build participant two:\n\n    ``` bash\n    cd tac_participant_two\n    aea add connection fetchai/p2p_libp2p:0.27.5\n    aea add connection fetchai/soef:0.27.6\n    aea add connection fetchai/ledger:0.21.5\n    aea add skill fetchai/tac_participation:0.25.6\n    aea add skill fetchai/tac_negotiation:0.29.6\n    aea config set --type dict agent.dependencies \\\n    '{\n      \"aea-ledger-fetchai\": {\"version\": \"<2.0.0,>=1.0.0\"},\n      \"aea-ledger-ethereum\": {\"version\": \"<2.0.0,>=1.0.0\"}\n    }'\n    aea config set agent.default_connection fetchai/p2p_libp2p:0.27.5\n    aea config set agent.default_ledger ethereum\n    aea config set vendor.fetchai.connections.soef.config.chain_identifier ethereum\n    aea config set vendor.fetchai.skills.tac_participation.models.game.args.is_using_contract 'True' --type bool\n    aea config set vendor.fetchai.skills.tac_negotiation.models.strategy.args.is_contract_tx 'True' --type bool\n    aea config set --type dict agent.default_routing \\\n    '{\n      \"fetchai/contract_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n      \"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n      \"fetchai/oef_search:1.1.7\": \"fetchai/soef:0.27.6\"\n    }'\n    aea config set --type dict agent.decision_maker_handler \\\n    '{\n      \"dotted_path\": \"aea.decision_maker.gop:DecisionMakerHandler\",\n      \"file_path\": null\n    }'\n    aea config set --type list vendor.fetchai.connections.p2p_libp2p.cert_requests \\\n    '''[{\"identifier\": \"acn\", \"ledger_id\": \"ethereum\", \"message_format\": \"'{public_key}'\", \"not_after\": \"2023-01-01\", \"not_before\": \"2022-01-01\", \"public_key\": \"fetchai\", \"save_path\": \".certs/conn_cert.txt\"}]'''\n    aea install\n    aea build\n    ```\n\n### Configure the Agents to Use Ethereum\n\nRun the following in every AEA's terminal:\n\n``` bash\naea config set agent.default_ledger ethereum\njson=$(printf '[{\"identifier\": \"acn\", \"ledger_id\": \"ethereum\", \"not_after\": \"2023-01-01\", \"not_before\": \"2022-01-01\", \"public_key\": \"fetchai\", \"message_format\": \"{public_key}\", \"save_path\": \".certs/conn_cert.txt\"}]')\naea config set --type list vendor.fetchai.connections.p2p_libp2p.cert_requests \"$json\"\naea config set vendor.fetchai.connections.soef.config.chain_identifier ethereum\n```\n\n### Add Keys for All AEAs\n\nFor every AEA in the competition (controller and participants):\n\nFirst generate and add a private key:\n\n``` bash\naea generate-key ethereum\naea add-key ethereum ethereum_private_key.txt\n```\n\nThen create and add a separate private key for secure communication:\n\n``` bash\naea generate-key fetchai fetchai_connection_private_key.txt\naea add-key fetchai fetchai_connection_private_key.txt --connection\n```\n\nFinally, certify the key for use by the connections that request that:\n\n``` bash\naea issue-certificates\n```\n\n### Update the Game Parameters in the Controller\n\nIn the tac controller project, get and set the registration start time (set it to at least 5 minutes in the future):\n\n``` bash\naea config get vendor.fetchai.skills.tac_control_contract.models.parameters.args.registration_start_time\naea config set vendor.fetchai.skills.tac_control_contract.models.parameters.args.registration_start_time '01 01 2020  00:01'\n```\n\nTo set the registration time, you may find handy the following command:\n\n``` bash\naea config set vendor.fetchai.skills.tac_control_contract.models.parameters.args.registration_start_time \"$(date -d \"5 minutes\" +'%d %m %Y %H:%M')\"\n```\n\n### Update the Connection Parameters\n\nUpdate the connection parameters of the TAC participants to allow them to connect to the same local agent communication network as the TAC controller.\n\nFirst, retrieve controller's local ACN address by running the following in the controller agent's project terminal:\n\n``` bash\naea get-multiaddress fetchai -c -i fetchai/p2p_libp2p:0.27.5 -u public_uri\n```\n\nThen, in participant one, run this command (replace `SOME_ADDRESS` with the value you retrieved above):\n\n``` bash\naea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \\\n'{\n  \"delegate_uri\": \"127.0.0.1:11001\",\n  \"entry_peers\": [\"SOME_ADDRESS\"],\n  \"local_uri\": \"127.0.0.1:9001\",\n  \"log_file\": \"libp2p_node.log\",\n  \"public_uri\": \"127.0.0.1:9001\"\n}'\n```\n\nDo the same in participant two (beware of the different port numbers):\n\n``` bash\naea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \\\n'{\n  \"delegate_uri\": \"127.0.0.1:11002\",\n  \"entry_peers\": [\"SOME_ADDRESS\"],\n  \"local_uri\": \"127.0.0.1:9002\",\n  \"log_file\": \"libp2p_node.log\",\n  \"public_uri\": \"127.0.0.1:9002\"\n}'\n```\n\n## Fund Agents' Accounts\n\nRun a local Ganache Ethereum test-net with funds for the addresses of the three AEAs in this demo:\n\n``` bash\ndocker run -p 8545:8545 trufflesuite/ganache-cli:latest --verbose --gasPrice=0 --gasLimit=0x1fffffffffffff --account=\"$(cat tac_controller_contract/ethereum_private_key.txt),1000000000000000000000\" --account=\"$(cat tac_participant_one/ethereum_private_key.txt),1000000000000000000000\" --account=\"$(cat tac_participant_two/ethereum_private_key.txt),1000000000000000000000\"\n```\n\nTo check the wealth of an AEA, use:\n\n``` bash\naea get-wealth ethereum\n```\n\nYou should get `1000000000000000000000`.\n\n### Run the AEAs\n\nFirst, launch the `tac_contract_controller` then the participants by executing the following from their respective terminals:\n\n``` bash\naea run\n```\n\nThe CLI tool supports launching several agents at once.\nFor example, assuming you followed the tutorial, you\ncan launch both TAC participant agents as follows from the root directory (ensure you run the controller agent first as above):\n\n``` bash\naea launch tac_participant_one tac_participant_two\n```\n\nYou may want to try `--multithreaded`\noption in order to run the agents\nin the same process.\n\n### Cleaning up\n\nWhen you're finished, delete your AEAs:\n\n``` bash\naea delete tac_controller_contract\naea delete tac_participant_one\naea delete tac_participant_two\n```\n"
  },
  {
    "path": "docs/tac-skills.md",
    "content": "# TAC Skills\n\nThe AEA TAC - trading agent competition - skills demonstrate an interaction between multiple AEAs in a game.\n\nThere are two types of AEAs:\n\n- The `tac_controller` which coordinates the game.\n- The `tac_participant` AEAs which compete in the game. The `tac_participant` AEAs trade tokens with each other to maximize their utility.\n\n## Discussion\n\nThe scope of this specific demo is to demonstrate how the agents negotiate autonomously with each other while they pursue their goals by playing a game of TAC. Another AEA has the role of the controller, responsible for calculating the revenue for each participant and checking if the transaction messages are valid. Transactions are settled with the controller agent rather than against a public ledger.\n\n## Communication\n\nThere are two types of interactions:\n\n- between the participants and the controller, the game communication\n- between the participants, the negotiation\n\n### Registration Communication\n\nThis diagram shows the communication between the various entities during the registration phase.\n\n``` mermaid\n    sequenceDiagram\n        participant Agent_2\n        participant Agent_1\n        participant Search\n        participant Controller\n    \n        activate Search\n        activate Controller\n        \n        Controller->>Search: register_service\n        activate Agent_1\n        Agent_1->>Search: search\n        Search-->>Agent_1: controller\n        Agent_1->>Controller: register\n        activate Agent_2\n        Agent_2->>Search: search\n        Search-->>Agent_2: controller\n        Agent_2->>Controller: register\n        Controller->>Controller: start_game\n        Controller->>Agent_1: game_data\n        Controller->>Agent_2: game_data\n        \n        deactivate Agent_1\n        deactivate Agent_2\n        deactivate Search\n        deactivate Controller\n```\n\n### Transaction Communication\n\nThis diagram shows the communication between two AEAs and the controller. In this case, we have an AEA in the role of the seller, referred to as `Seller_Agent`. We also have an AEA in the role of the buyer, referred to as `Buyer_Agent`. During a given TAC, an AEA can be in both roles simultaneously in different bilateral interactions.\n\n``` mermaid\n    sequenceDiagram\n        participant Buyer_Agent\n        participant Seller_Agent\n        participant Search\n        participant Controller\n    \n        activate Buyer_Agent\n        activate Seller_Agent\n        activate Search\n        activate Controller\n        \n        Seller_Agent->>Search: register_service\n        Buyer_Agent->>Search: search\n        Search-->>Buyer_Agent: list_of_agents\n        Buyer_Agent->>Seller_Agent: call_for_proposal\n        Seller_Agent->>Buyer_Agent: proposal\n        Buyer_Agent->>Seller_Agent: accept\n        Seller_Agent->>Buyer_Agent: match_accept\n        Seller_Agent->>Controller: transaction\n        Controller->>Controller: transaction_execution\n        Controller->>Seller_Agent: confirm_transaction\n        Controller->>Buyer_Agent: confirm_transaction\n        \n        deactivate Buyer_Agent\n        deactivate Seller_Agent\n        deactivate Search\n        deactivate Controller\n```\n\nIn the above case, the proposal received contains a set of good which the seller wishes to sell and a cost of them. The buyer AEA needs to determine if this is a good deal for them and if so, it accepts.\n\nThere is an equivalent diagram for seller AEAs set up to search for buyers and their interaction with AEAs which are registered as buyers. In that scenario, the proposal will instead, be a list of goods that the buyer wishes to buy and the price it is willing to pay for them.\n\n## Option 1: AEA Manager Approach\n\nFollow this approach when using the AEA Manager Desktop app. Otherwise, skip and follow the CLI approach below.\n\n### Preparation Instructions\n\nInstall the <a href=\"https://aea-manager.fetch.ai\" target=\"_blank\">AEA Manager</a>.\n\n### Demo Instructions\n\nThe following steps assume you have launched the AEA Manager Desktop app.\n\n1. Add a new AEA called `controller` with public id `fetchai/tac_controller:0.26.0`.\n\n2. Add another new AEA called `participant_1` with public id `fetchai/tac_participant:0.28.0`.\n\n3. Add another new AEA called `participant_2` with public id `fetchai/tac_participant:0.28.0`.\n\n4. Navigate to the settings of `controller` and under `components > skill >` `fetchai/fetchai/tac_controller:0.22.0` `> models > parameters > args` update `registration_start_time` to the time you want TAC to begin (e.g. 2 minutes in the future)\n\n5. Run the `controller` AEA. Navigate to its logs and copy the multiaddress displayed. Stop the `controller`.\n\n6. Navigate to the settings of `participant_1` and under `components > connection >` `fetchai/p2p_libp2p:0.22.0` update as follows (make sure to replace the placeholder with the multiaddress):\n\n    ``` bash\n    {\n      \"delegate_uri\": \"127.0.0.1:11001\",\n      \"entry_peers\": [\"REPLACE_WITH_MULTI_ADDRESS_HERE\"],\n      \"local_uri\": \"127.0.0.1:9001\",\n      \"log_file\": \"libp2p_node.log\",\n      \"public_uri\": \"127.0.0.1:9001\"\n    }\n    ```\n\n7. Navigate to the settings of `participant_2` and under `components > connection >` `fetchai/p2p_libp2p:0.22.0` update as follows (make sure to replace the placeholder with the multiaddress):\n\n    ``` bash\n    {\n      \"delegate_uri\": \"127.0.0.1:11002\",\n      \"entry_peers\": [\"REPLACE_WITH_MULTI_ADDRESS_HERE\"],\n      \"local_uri\": \"127.0.0.1:9002\",\n      \"log_file\": \"libp2p_node.log\",\n      \"public_uri\": \"127.0.0.1:9002\"\n    }\n    ```\n\n8. You may add more participants by repeating steps 3 (with an updated name) and 6 (bumping the port numbers. See the difference between steps 5 and 6).\n\n9. Run the `controller`, then `participant_1` and `participant_2` (and any other participants you added).\n\nIn the `controller`'s log, you should see the details of the transactions participants submit as well as changes in their scores and holdings. In participants' logs, you should see the agents trading.\n\n## Option 2: CLI Approach\n\nFollow this approach when using the `aea` CLI.\n\n## Preparation Instructions\n\n### Dependencies\n\nFollow the <a href=\"../quickstart/#preliminaries\">Preliminaries</a> and <a href=\"../quickstart/#installation\">Installation</a> sections from the AEA quick start.\n\n## Demo Instructions\n\n### Create TAC Controller AEA\n\nIn the root directory, fetch the controller AEA:\n\n``` bash\naea fetch fetchai/tac_controller:0.30.5\ncd tac_controller\naea install\naea build\n```\n\n??? note \"Alternatively, create from scratch:\"\n\n    The following steps create the controller from scratch:\n\n    ``` bash\n    aea create tac_controller\n    cd tac_controller\n    aea add connection fetchai/p2p_libp2p:0.27.5\n    aea add connection fetchai/soef:0.27.6\n    aea add connection fetchai/ledger:0.21.5\n    aea add skill fetchai/tac_control:0.25.6\n    aea config set --type dict agent.dependencies \\\n    '{\n      \"aea-ledger-fetchai\": {\"version\": \"<2.0.0,>=1.0.0\"}\n    }'\n    aea config set agent.default_connection fetchai/p2p_libp2p:0.27.5\n    aea config set agent.default_ledger fetchai\n    aea config set --type dict agent.default_routing \\\n    '{\n      \"fetchai/oef_search:1.1.7\": \"fetchai/soef:0.27.6\"\n    }'\n    aea install\n    aea build\n    ```\n\n### Create the TAC Participant AEAs\n\nIn a separate terminal, in the root directory, fetch at least two participants:\n\n``` bash\naea fetch fetchai/tac_participant:0.32.5 --alias tac_participant_one\ncd tac_participant_one\naea install\naea build\ncd ..\naea fetch fetchai/tac_participant:0.32.5 --alias tac_participant_two\ncd tac_participant_two\naea build\n```\n\n??? note \"Alternatively, create from scratch:\"\n\n    In a separate terminal, in the root directory, create at least two tac participant AEAs:\n\n    ``` bash\n    aea create tac_participant_one\n    aea create tac_participant_two\n    ```\n\n    Build participant one:\n\n    ``` bash\n    cd tac_participant_one\n    aea add connection fetchai/p2p_libp2p:0.27.5\n    aea add connection fetchai/soef:0.27.6\n    aea add connection fetchai/ledger:0.21.5\n    aea add skill fetchai/tac_participation:0.25.6\n    aea add skill fetchai/tac_negotiation:0.29.6\n    aea config set --type dict agent.dependencies \\\n    '{\n      \"aea-ledger-fetchai\": {\"version\": \"<2.0.0,>=1.0.0\"}\n    }'\n    aea config set agent.default_connection fetchai/p2p_libp2p:0.27.5\n    aea config set agent.default_ledger fetchai\n    aea config set --type dict agent.default_routing \\\n    '{\n      \"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n      \"fetchai/oef_search:1.1.7\": \"fetchai/soef:0.27.6\"\n    }'\n    aea config set --type dict agent.decision_maker_handler \\\n    '{\n      \"dotted_path\": \"aea.decision_maker.gop:DecisionMakerHandler\",\n      \"file_path\": null\n    }'\n    aea install\n    aea build\n    ```\n    \n    Then, build participant two:\n\n    ``` bash\n    cd tac_participant_two\n    aea add connection fetchai/p2p_libp2p:0.27.5\n    aea add connection fetchai/soef:0.27.6\n    aea add connection fetchai/ledger:0.21.5\n    aea add skill fetchai/tac_participation:0.25.6\n    aea add skill fetchai/tac_negotiation:0.29.6\n    aea config set --type dict agent.dependencies \\\n    '{\n      \"aea-ledger-fetchai\": {\"version\": \"<2.0.0,>=1.0.0\"}\n    }'\n    aea config set agent.default_connection fetchai/p2p_libp2p:0.27.5\n    aea config set agent.default_ledger fetchai\n    aea config set --type dict agent.default_routing \\\n    '{\n      \"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n      \"fetchai/oef_search:1.1.7\": \"fetchai/soef:0.27.6\"\n    }'\n    aea config set --type dict agent.decision_maker_handler \\\n    '{\n      \"dotted_path\": \"aea.decision_maker.gop:DecisionMakerHandler\",\n      \"file_path\": null\n    }'\n    aea install\n    aea build\n    ```\n\n### Add Keys for All AEAs\n\nCreate the private key for the AEA for Fetch.ai `Dorado`:\n\n``` bash\naea generate-key fetchai\naea add-key fetchai fetchai_private_key.txt\n```\n\nNext, create a private key used to secure the AEA's communications:\n\n``` bash\naea generate-key fetchai fetchai_connection_private_key.txt\naea add-key fetchai fetchai_connection_private_key.txt --connection\n```\n\nFinally, certify the key for use by the connections that request that:\n\n``` bash\naea issue-certificates\n```\n\n### Update the Game Parameters in the Controller\n\nNavigate to the tac controller project, then use the command line to get and set the start time (set it to at least two minutes in the future):\n\n``` bash\naea config get vendor.fetchai.skills.tac_control.models.parameters.args.registration_start_time\naea config set vendor.fetchai.skills.tac_control.models.parameters.args.registration_start_time '01 01 2020  00:01'\n```\n\nTo set the registration time, you may find handy the following command:\n\n``` bash\naea config set vendor.fetchai.skills.tac_control.models.parameters.args.registration_start_time \"$(date -d \"2 minutes\" +'%d %m %Y %H:%M')\"\n```\n\n### Update the Connection Parameters\n\nBriefly run the controller AEA:\n\n``` bash\naea run\n```\n\nOnce you see a message of the form `To join its network use multiaddr 'SOME_ADDRESS'` take note of the address. (Alternatively, use `aea get-multiaddress fetchai -c -i fetchai/p2p_libp2p:0.27.5 -u public_uri` to retrieve the address.)\n\nThen, in the participant one, run this command (replace `SOME_ADDRESS` with the correct value as described above):\n\n``` bash\naea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \\\n'{\n  \"delegate_uri\": \"127.0.0.1:11001\",\n  \"entry_peers\": [\"SOME_ADDRESS\"],\n  \"local_uri\": \"127.0.0.1:9001\",\n  \"log_file\": \"libp2p_node.log\",\n  \"public_uri\": \"127.0.0.1:9001\"\n}'\n```\n\nDo the same in participant two (beware of the different port numbers):\n\n``` bash\naea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \\\n'{\n  \"delegate_uri\": \"127.0.0.1:11002\",\n  \"entry_peers\": [\"SOME_ADDRESS\"],\n  \"local_uri\": \"127.0.0.1:9002\",\n  \"log_file\": \"libp2p_node.log\",\n  \"public_uri\": \"127.0.0.1:9002\"\n}'\n```\n\nThis allows the TAC participants to connect to the same local agent communication network as the TAC controller.\n\n### Run the AEAs\n\nFirst, launch the `tac_controller`:\n\n``` bash\naea run\n```\n\nThe CLI tool supports the launch of several agents\nat once.\n\nFor example, assuming you followed the tutorial, you\ncan launch both the TAC agents as follows from the root directory:\n\n``` bash\naea launch tac_participant_one tac_participant_two\n```\n\nYou may want to try `--multithreaded`\noption in order to run the agents\nin the same process.\n\n### Cleaning up\n\nWhen you're finished, delete your AEAs:\n\n``` bash\naea delete tac_controller\naea delete tac_participant_one\naea delete tac_participant_two\n```\n"
  },
  {
    "path": "docs/tac.md",
    "content": "# TAC External App\n\n!!! note\n    This app is no longer maintained.\n\nThe original TAC has its own <a href=\"https://github.com/fetchai/agents-tac\" target=\"_blank\">repo</a>.\n\nFollow the instructions below to build and run the TAC demo.\n\n## Requirements\n\nMake sure you are running <a href=\"https://docs.docker.com/get-docker/\" target=\"_blank\">Docker</a> and <a href=\"https://docs.docker.com/compose/install/\" target=\"_blank\">Docker Compose</a>.\n\n## Quick Start\n\nClone the repo to include submodules.\n\n``` bash\ngit clone git@github.com:fetchai/agents-tac.git --recursive && cd agents-tac\n```\n\nCheck you have `pipenv`.\n\n``` bash\nwhich pipenv\n```\n\nIf you don't have it, install it. Instructions are <a href=\"https://pypi.org/project/pipenv/\" target=\"_blank\">here</a>.\n\nCreate and launch a virtual environment.\n\n``` bash\npipenv --python 3.7 && pipenv shell\n```\n\nInstall the dependencies.\n\n``` bash\npipenv install\n```\n\nInstall the package.\n\n``` bash\npython setup.py install\n```\n\nRun the launch script. This may take a while.\n\n``` bash\npython scripts/launch.py\n```\n\nThe <a href=\"https://github.com/fossasia/visdom\" target=\"_blank\">Visdom</a> server is now running.\n\nThe controller GUI at <a href=\"http://localhost:8097\" target=\"_blank\">http://localhost:8097</a> provides real time insights.\n\nIn the Environment tab, make sure you have the `tac_controller` environment selected.\n\n<img src=\"../assets/visdom_ui.png\" alt=\"AEA Visdom UI\" class=\"center\">\n\n## Alternative Build and Run\n\nIn a new terminal window, clone the repo, build the sandbox, and launch it.\n\n``` bash\ngit clone git@github.com:fetchai/agents-tac.git --recursive && cd agents-tac\npipenv --python 3.7 && pipenv shell\npython setup.py install\ncd sandbox && docker-compose build\ndocker-compose up\n```\n\nIn a new terminal window, enter the virtual environment, and connect a template agent to the sandbox.\n\n``` bash\npipenv shell\npython templates/v1/basic.py --name my_agent --dashboard\n```\n\nClick through to the <a href=\"http://localhost:8097\" target=\"_blank\">controller GUI</a>.\n\n## Possible Gotchas\n\nStop all running containers before restart.\n\n``` bash\ndocker stop $(docker ps -q)\n```\n\nTo remove all images, run the following command.\n\n``` bash\n# mac\ndocker ps -q | xargs docker stop ; docker system prune -a\n```\n"
  },
  {
    "path": "docs/thermometer-skills.md",
    "content": "# Thermometer Skills\n\nThe AEA thermometer skills demonstrate an interaction between two AEAs, one purchasing temperature data from the other.\n\n- The provider of thermometer data (the `thermometer`).\n- The buyer of thermometer data (the `thermometer_client`).\n\n## Discussion\n\nThis demo aims to demonstrate how to create a very simple AEA with the usage of the AEA framework and a thermometer sensor. The thermometer AEA will read data from the sensor each time a client requests the data and will deliver it to the client upon payment. To keep the demo simple, we avoided the usage of a database since this would increase the complexity. As a result, the AEA can provide only one reading from the sensor. This demo does not utilise a smart contract. As a result, the ledger interaction is only for completing a transaction.\n\n## Communication\n\nThis diagram shows the communication between the various entities as data is successfully sold by the thermometer AEA to the client AEA.\n\n``` mermaid\n    sequenceDiagram\n        participant Search\n        participant Client_AEA\n        participant Thermometer_AEA\n        participant Blockchain\n    \n        activate Client_AEA\n        activate Search\n        activate Thermometer_AEA\n        activate Blockchain\n        \n        Thermometer_AEA->>Search: register_service\n        Client_AEA->>Search: search\n        Search-->>Client_AEA: list_of_agents\n        Client_AEA->>Thermometer_AEA: call_for_proposal\n        Thermometer_AEA->>Client_AEA: propose\n        Client_AEA->>Thermometer_AEA: accept\n        Thermometer_AEA->>Client_AEA: match_accept\n        Client_AEA->>Blockchain: transfer_funds\n        Client_AEA->>Thermometer_AEA: send_transaction_hash\n        Thermometer_AEA->>Blockchain: check_transaction_status\n        Thermometer_AEA->>Client_AEA: send_data\n        \n        deactivate Client_AEA\n        deactivate Search\n        deactivate Thermometer_AEA\n        deactivate Blockchain\n```\n\n## Option 1: AEA Manager Approach\n\nFollow this approach when using the AEA Manager Desktop app. Otherwise, skip and follow the CLI approach below.\n\n### Preparation Instructions\n\nInstall the <a href=\"https://aea-manager.fetch.ai\" target=\"_blank\">AEA Manager</a>.\n\n### Demo Instructions\n\nThe following steps assume you have launched the AEA Manager Desktop app.\n\n1. Add a new AEA called `my_thermometer_aea` with public id `fetchai/thermometer_aea:0.30.5`.\n\n2. Add another new AEA called `my_thermometer_client` with public id `fetchai/thermometer_client:0.32.5`.\n\n3. Copy the address from the `my_thermometer_client` into your clip board. Then go to the <a href=\"https://explore-dorado.fetch.ai\" target=\"_blank\">Dorado block explorer</a> and request some test tokens via `Get Funds`.\n\n4. Run the `my_thermometer_aea` AEA. Navigate to its logs and copy the multiaddress displayed.\n\n5. Navigate to the settings of the `my_thermometer_client` and under `components > connection >` `fetchai/p2p_libp2p:0.22.0` update as follows (make sure to replace the placeholder with the multiaddress):\n\n    ``` bash\n    {\n      \"delegate_uri\": \"127.0.0.1:11001\",\n      \"entry_peers\": [\"REPLACE_WITH_MULTI_ADDRESS_HERE\"],\n      \"local_uri\": \"127.0.0.1:9001\",\n      \"log_file\": \"libp2p_node.log\",\n      \"public_uri\": \"127.0.0.1:9001\"\n    }\n    ```\n\n6. Run the `my_thermometer_client`.\n\nIn the AEA's logs, you should see the agent trading successfully.\n\n## Option 2: CLI Approach\n\nFollow this approach when using the `aea` CLI.\n\n### Preparation Instructions\n\n#### Dependencies\n\nFollow the <a href=\"../quickstart/#preliminaries\">Preliminaries</a> and <a href=\"../quickstart/#installation\">Installation</a> sections from the AEA quick start.\n\n### Demo Instructions\n\nA demo to run the thermometer scenario with a true ledger transaction This demo assumes the buyer trusts the seller AEA to send the data upon successful payment.\n\n#### Create Thermometer AEA\n\nFirst, fetch the thermometer AEA:\n\n``` bash\naea fetch fetchai/thermometer_aea:0.30.5 --alias my_thermometer_aea\ncd my_thermometer_aea\naea install\naea build\n```\n\n??? note \"Alternatively, create from scratch:\"\n    The following steps create the thermometer AEA from scratch:\n\n    ``` bash\n    aea create my_thermometer_aea\n    cd my_thermometer_aea\n    aea add connection fetchai/p2p_libp2p:0.27.5\n    aea add connection fetchai/soef:0.27.6\n    aea add connection fetchai/ledger:0.21.5\n    aea add skill fetchai/thermometer:0.27.6\n    aea install\n    aea build\n    aea config set agent.default_connection fetchai/p2p_libp2p:0.27.5\n    aea config set --type dict agent.default_routing \\\n    '{\n      \"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n      \"fetchai/oef_search:1.1.7\": \"fetchai/soef:0.27.6\"\n    }'\n    ```\n\n#### Create Thermometer Client\n\nThen, fetch the thermometer client AEA:\n\n``` bash\naea fetch fetchai/thermometer_client:0.32.5 --alias my_thermometer_client\ncd my_thermometer_client\naea install\naea build\n```\n\n??? note \"Alternatively, create from scratch:\"\n    The following steps create the thermometer client from scratch:\n\n    ``` bash\n    aea create my_thermometer_client\n    cd my_thermometer_client\n    aea add connection fetchai/p2p_libp2p:0.27.5\n    aea add connection fetchai/soef:0.27.6\n    aea add connection fetchai/ledger:0.21.5\n    aea add skill fetchai/thermometer_client:0.26.6\n    aea install\n    aea build\n    aea config set agent.default_connection fetchai/p2p_libp2p:0.27.5\n    aea config set --type dict agent.default_routing \\\n    '{\n      \"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n      \"fetchai/oef_search:1.1.7\": \"fetchai/soef:0.27.6\"\n    }'\n    ```\n\n#### Add Keys for the Thermometer AEA\n\nFirst, create the private key for the thermometer AEA based on the network you want to transact. To generate and add a private-public key pair for Fetch.ai `Dorado` use:\n\n``` bash\naea generate-key fetchai\naea add-key fetchai fetchai_private_key.txt\n```\n\nNext, create a private key used to secure the AEA's communications:\n\n``` bash\naea generate-key fetchai fetchai_connection_private_key.txt\naea add-key fetchai fetchai_connection_private_key.txt --connection\n```\n\nFinally, certify the key for use by the connections that request that:\n\n``` bash\naea issue-certificates\n```\n\n#### Add Keys and Generate Wealth for the Thermometer Client AEA\n\nThe thermometer client needs to have some wealth to purchase the thermometer information.\n\nFirst, create the private key for the thermometer client AEA based on the network you want to transact. To generate and add a private-public key pair for Fetch.ai use:\n\n``` bash\naea generate-key fetchai\naea add-key fetchai fetchai_private_key.txt\n```\n\nThen, create some wealth for your thermometer client based on the network you want to transact with. On the Fetch.ai `testnet` network:\n\n``` bash\naea generate-wealth fetchai\n```\n\nNext, create a private key used to secure the AEA's communications:\n\n``` bash\naea generate-key fetchai fetchai_connection_private_key.txt\naea add-key fetchai fetchai_connection_private_key.txt --connection\n```\n\nFinally, certify the key for use by the connections that request that:\n\n``` bash\naea issue-certificates\n```\n\n#### Run both AEAs\n\nRun both AEAs from their respective terminals.\n\nFirst, run the thermometer AEA:\n\n``` bash\naea run\n```\n\nOnce you see a message of the form `To join its network use multiaddr 'SOME_ADDRESS'` take note of the address. (Alternatively, use `aea get-multiaddress fetchai -c -i fetchai/p2p_libp2p:0.27.5 -u public_uri` to retrieve the address.) This is the entry peer address for the local <a href=\"../acn\">agent communication network</a> created by the thermometer AEA.\n\nThen, in the thermometer client, run this command (replace `SOME_ADDRESS` with the correct value as described above):\n\n``` bash\naea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \\\n'{\n  \"delegate_uri\": \"127.0.0.1:11001\",\n  \"entry_peers\": [\"SOME_ADDRESS\"],\n  \"local_uri\": \"127.0.0.1:9001\",\n  \"log_file\": \"libp2p_node.log\",\n  \"public_uri\": \"127.0.0.1:9001\"\n}'\n```\n\nThis allows the thermometer client to connect to the same local agent communication network as the thermometer AEA.\n\nThen run the thermometer client AEA:\n\n``` bash\naea run\n```\n\nYou can see that the AEAs find each other, negotiate and eventually trade.\n\n#### Cleaning up\n\nWhen you're done, go up a level and delete the AEAs.\n\n``` bash\ncd ..\naea delete my_thermometer_aea\naea delete my_thermometer_client\n```\n"
  },
  {
    "path": "docs/trust.md",
    "content": "# Trust Minimisation\n\nAEA applications have different requirements for _trustlessness_ or _trust minimisation_.\n\nFor example, using the AEA <a href=\"../weather-skills/\">weather skills demo</a> _without_ ledger payments means that the client has to trust the weather station to send the weather data it purchased and that this data is in fact valid. Similarly, the weather station must trust that the client somehow sends the payment amount to which they agreed.\n\nA step-up, if you run the <a href=\"../weather-skills/\">weather skills demo</a> with a ledger (e.g. Fetch.ai or Ethereum) then the client must still trust that the weather station sends valid data. However, all payment transactions are executed via the public ledger. This means the weather station no longer needs to trust the client for payment and can verify whether the transactions take place on the public ledger.\n\nWe can further minimise trust requirements by incorporating a third party as an <a href=\"https://en.wikipedia.org/wiki/Escrow\" target=\"_blank\">arbitrator or escrow</a> implemented in a <a href=\"https://en.wikipedia.org/wiki/Smart_contract\" target=\"_blank\">smart contract</a> to further reduce trust requirements. However, in the current weather skills demo, there are limits to trustlessness as the station ultimately offers unverifiable data.\n\nAnother example of minimising trust, is applications with (non-fungible) token transactions involving <a href=\"https://dl.acm.org/doi/10.1145/3212734.3212736\" target=\"_blank\">atomic swaps</a> where trustlessness is clearly satisfied (e.g. in the <a href=\"../tac-skills-contract/\">TAC demo</a>).\n"
  },
  {
    "path": "docs/upgrading.md",
    "content": "# Upgrading\n\nThis page provides some tips on how to upgrade AEA projects between different versions of the AEA framework. For full release notes check the <a href=\"https://github.com/fetchai/agents-aea/tags\" target=\"_blank\">AEA repo</a>.\n\nThe primary tool for upgrading AEA projects is the `aea upgrade` command in the <a href=\"../cli-commands/\">CLI</a>.\n\nBelow we describe the additional manual steps required to upgrade between different versions:\n\n## `v1.2.2` to `v1.2.3`\n\nEnsure you update the plugins to their latest version (all plugins are changed in this release)\n\nUpdate the packages to the latest versions (especially protocols).\n\nUpdate development environment\n\n## `v1.2.0` to `v1.2.2`\n\nEnsure you update the plugins to their latest version (all plugins are changed in this release)\n\nUpdate the packages to the latest versions (especially protocols).\n\nRegenerate your own written protocols (protocol generator was updated)\n\n## `v1.1.1` to `v1.2.0`\n\nEnsure you update the plugins to their latest version (fetchai and cosmos plugins are changed in this release)\n\nUpdate the packages to the latest versions (especially p2p_libp2p related packages are updated)\n\nCheck packages’ and agents’ configurations are correct (e.g. the fetchai test-net name is changed for the Dorado network)\n\n## `v1.1.0` to `v1.1.1`\n\nNo backwards incompatible changes.\n\nUpgrade fetchai/p2p_libp2p connection package to the latest version which fixes a slow DHT lookup problem\n\nWe advise everyone to upgrade their `fetchai` packages and plugins to get the latest fixes.\n\n## `v1.0.2` to `v1.1.0`\n\nNo backwards incompatible changes.\n\nWe advise everyone to upgrade their `fetchai` packages and plugins to get the latest fixes.\n\n## `v1.0.1` to `v1.0.2`\n\nNo backwards incompatible changes.\n\nWe advise everyone to upgrade their `fetchai` packages and plugins to get the latest fixes.\n\n## `v1.0.0` to `v1.0.1`\n\nNo backwards incompatible changes.\n\nWe advise everyone to upgrade their `fetchai` packages to get the latest fixes.\n\n## `v1.0.0rc2` to `v1.0.0`\n\nNo backwards incompatible changes to component development.\n\nWe advise everyone to upgrade to `v1` as soon as possible. When upgrading from versions below `v1.0.0rc1` first upgrade to the first release candidate, then to `v1`.\n\n## `v1.0.0rc1` to `v1.0.0rc2`\n\nNo backwards incompatible changes to component development.\n\nVarious configuration changes introduced in `v1.0.0rc1` are now enforced strictly.\n\n## `v0.11.1` to `v1.0.0rc1`\n\nNo backwards incompatible changes to component development.\n\nThe `aea-config.yaml` now requires the field `required_ledgers` which must specify all ledgers for which private keys are required to run the agent. Please add it to your project.\n\nThe `registry_path` field has been removed from the `aea-config.yaml`. Please remove it from your project.\n\nAll packages provided by author `fetchai` must be upgraded.\n\n## `v0.11.0` to `v0.11.1`\n\nNo backwards incompatible changes.\n\n## `v0.10.1` to `v0.11.0`\n\nTake special care when upgrading to `v0.11.0`. We introduced several breaking changes in preparation for `v1`!\n\n### CLI GUI\n\nWe removed the CLI GUI. It was not used by anyone as far as we know and needs to be significantly improved. Soon we will release the AEA Manager App to make up for this.\n\n### Message Routing\n\nRouting has been completely revised and simplified. The new message routing logic is described <a href=\"../message-routing/\">here</a>.\n\nWhen upgrading take the following steps:\n\n- For agent-to-agent communication: ensure the default routing and default connection are correctly defined and that the dialogues used specify the agent's address as the `self_address`. This is most likely already the case. Only in some edge cases will you need to use an `EnvelopeContext` to target a connection different from the one specified in the `default_routing` map.\n\n- For component-to-component communication: there is now only one single way to route component to component (skill to skill, skill to connection, connection to skill) messages, this is by specifying the component id in string form in the `sender`/`to` field. The `EnvelopeContext` can no longer be used, messages are routed based on their target (`to` field). Ensure that dialogues in skills set the `skill_id` as the `self_address` (in connections they need to set the `connection_id`).\n\n### Agent Configuration and Ledger Plugins\n\nAgent configuration files have a new optional field, `dependencies`,  analogous to `dependencies` field in other AEA packages. The default value is the empty object `{}`. The field will be made mandatory in the next release.\n\nCrypto modules have been extracted and released as independent plug-ins, released on PyPI. In particular:\n\n- Fetch.ai crypto classes have been released in the `aea-ledger-fetchai` package;\n- Ethereum crypto classes have been released in the `aea-ledger-ethereum` package;\n- Cosmos crypto classes have been released in the `aea-ledger-cosmos` package.\n\nIf an AEA project, or an AEA package, makes use of crypto functionalities, it will be needed to add the above packages as PyPI dependencies with version specifiers ranging from the latest minor and the latest minor + 1 (excluded). E.g. if the latest version if `0.1.0`, the version specifier should be `<0.2.0,>=0.1.0`:\n\n``` yaml\ndependencies:\n  aea-ledger-cosmos:\n    version: <2.0.0,>=1.0.0\n  aea-ledger-ethereum:\n    version: <2.0.0,>=1.0.0\n  aea-ledger-fetchai:\n    version: <2.0.0,>=1.0.0\n```\n\nThe version specifier sets are important, as these plug-ins, at version `0.1.0`, depend on a specific range of the `aea` package.\n\nThen, running `aea install` inside the AEA project should install them in the current Python environment.\n\nFor more, read the <a href=\"../ledger-integration\">guide on ledger plugins</a>.\n\n## `v0.10.0` to `v0.10.1`\n\nNo backwards incompatible changes for skill and connection development.\n\n## `v0.9.2` to `v0.10.0`\n\nSkill development sees no backward incompatible changes.\n\nConnection development requires updating the keyword arguments of the constructor: the new `data_dir` argument must be defined.\n\nProtocol specifications now need to contain a `protocol_specification_id` in addition to the public id. The `protocol_specification_id` is used for identifying Envelopes during transport. By being able to set the id independently of the protocol id, backwards compatibility in the specification (and therefore wire format) can be maintained even when the Python implementation changes.\n\nPlease update to the latest packages by running `aea upgrade` and then re-generating your own protocols.\n\n## `v0.9.1` to `v0.9.2`\n\nNo backwards incompatible changes for skill and connection development.\n\n## `v0.9.0` to `v0.9.1`\n\nNo backwards incompatible changes for skill and connection development.\n\n## `v0.8.0` to `v0.9.0`\n\nThis release introduces <a href=\"../por\">proof of representation</a> in the ACN. You will need to upgrade to the latest `fetchai/p2p_libp2p` or `fetchai/p2p_libp2p_client` connection and then use two key pairs, one for your AEA's decision maker and one for the connection.\n\nPlease update to the latest packages by running `aea upgrade`.\n\n## `v0.7.5` to `v0.8.0`\n\nMinimal backwards incompatible changes for skill and connection development:\n\n- The semantics of the `<`, `<=`, `>` and `>=` relations in `ConstraintTypes` are simplified.\n- Protocols now need to correctly define terminal states. Regenerate your protocol to identify if your protocol's dialogue rules are valid.\n\nPlease update to the latest packages by running `aea upgrade`.\n\n## `v0.7.4` to `v0.7.5`\n\nNo backwards incompatible changes for skill and connection development.\n\n## `v0.7.3` to `v0.7.4`\n\nNo backwards incompatible changes for skill and connection development.\n\n## `v0.7.2` to `v0.7.3`\n\nNo backwards incompatible changes for skill and connection development.\n\n## `v0.7.1` to `v0.7.2`\n\nNo backwards incompatible changes for skill and connection development.\n\n## `v0.7.0` to `v0.7.1`\n\nTo improve performance, in particular optimize memory usage, we refactored the `Message` and `Dialogue` classes. This means all protocols need to be bumped to the latest version or regenerated using the `aea generate protocol` command in the <a href=\"../cli-commands/\">CLI</a>.\n\n## `v0.6.3` to `v0.7.0`\n\nMultiple breaking changes require action in this order:\n\n- Custom configuration overrides in `aea-config.yaml` are now identified via `public_id` rather than `author`, `name` and `version` individually. Please replace the three fields with the equivalent `public_id`.\n\n- Run `aea upgrade` command to upgrade your project's dependencies. Note, you still do have to manually update the public ids under `default_routing` and `default_connection` in `aea-config.yaml` as well as the public ids in the non-vendor packages.\n\n- Previously, connection `fetchai/stub`, skill `fetchai/error` and protocols `fetchai/default`, `fetchai/signing` and `fetchai/state_update` where part of the AEA distribution. Now they need to be fetched from registry. If you create a new project with `aea create` then this happens automatically. For existing projects, add the dependencies explicitly if not already present. You also must update the import paths as follows:\n\n    - `aea.connections.stub` > `packages.fetchai.connections.stub`\n    - `aea.protocols.default` > `packages.fetchai.protocols.default`\n    - `aea.protocols.signing` > `packages.fetchai.protocols.signing`\n    - `aea.protocols.state_update` > `packages.fetchai.protocols.state_update`\n    - `aea.skills.error` > `packages.fetchai.skills.error`\n\n- If you use custom protocols, regenerate them.\n\n- In your own skills' `__init__.py` files add the public id (updating the string as appropriate):\n\n``` python\nfrom aea.configurations.base import PublicId\n\n\nPUBLIC_ID = PublicId.from_str(\"author/name:0.1.0\")\n```\n\n- The `fetchai/http` protocol's `bodyy` field has been renamed to `body`.\n\n- Skills can now specify `connections` as dependencies in the configuration YAML.\n\n## `v0.6.2` to `v0.6.3`\n\nA new `upgrade` command is introduced to upgrade agent projects and components to their latest versions on the registry. To use the command first upgrade the AEA PyPI package to the latest version, then enter your project and run `aea upgrade`. The project's vendor dependencies will be updated where possible.\n\n## `v0.6.1` to `v0.6.2`\n\nNo public APIs have been changed.\n\n## `v0.6.0` to `v0.6.1`\n\nThe `soef` connection and `oef_search` protocol have backward incompatible changes.\n\n## `v0.5.4` to `v0.6.0`\n\n### `Dialogue` and `Dialogues` API Updates\n\nThe dialogue and dialogues APIs have changed significantly. The constructor is different for both classes and there are now four primary methods for the developer:\n\n- `Dialogues.create`: this method is used to create a new dialogue and message:\n\n``` python\ncfp_msg, fipa_dialogue = fipa_dialogues.create(\n    counterparty=opponent_address,\n    performative=FipaMessage.Performative.CFP,\n    query=query,\n)\n```\n\nThe method will raise if the provided arguments are inconsistent.\n\n- `Dialogues.create_with_message`: this method is used to create a new dialogue from a message:\n\n``` python\nfipa_dialogue = fipa_dialogues.create_with_message(\n    counterparty=opponent_address,\n    initial_message=cfp_msg\n)\n```\n\nThe method will raise if the provided arguments are inconsistent.\n\n- `Dialogues.update`: this method is used to handle messages passed by the framework:\n\n``` python\nfipa_dialogue = fipa_dialogues.update(\n    message=cfp_msg\n)\n```\n\nThe method will return a valid dialogue if it is a valid message, otherwise it will return `None`.\n\n- `Dialogue.reply`: this method is used to reply within a dialogue:\n\n``` python\nproposal_msg = fipa_dialogue.reply(\n    performative=FipaMessage.Performative.PROPOSE,\n    target_message=cfp_msg,\n    proposal=proposal,\n)\n```\n\nThe method will raise if the provided arguments are inconsistent.\n\nThe new methods significantly reduce the lines of code needed to maintain a dialogue. They also make it easier for the developer to construct valid dialogues and messages.\n\n### `FetchAICrypto` - Default Crypto\n\nThe `FetchAICrypto` has been upgraded to the default crypto. Update your `default_ledger` to `fetchai`.\n\n### Private Key File Naming\n\nThe private key files are now consistently named with the `ledger_id` followed by `_private_key.txt` (e.g. `fetchai_private_key.txt`). Rename your existing files to match this pattern.\n\n### Type in Package YAML\n\nThe package YAML files now contain a type field. This must be added for the loading mechanism to work properly.\n\n### Moved Address Type\n\nThe address type has moved to `aea.common`. The import paths must be updated.\n\n## `v0.5.3` to `v0.5.4`\n\nThe contract base class was slightly modified. If you have implemented your own contract package you need to update it accordingly.\n\nThe dialogue reference nonce is now randomly generated. This can result in previously working but buggy implementations (which relied on the order of dialogue reference nonces) to now fail.\n\n## `v0.5.2` to `v0.5.3`\n\nConnection states and logger usage in connections where updated. If you have implemented your own connection package you need to update it accordingly.\n\nAdditional dialogue consistency checks where enabled. This can result in previously working but buggy implementations to now fail.\n\n## `v0.5.1` to `0.5.2`\n\nNo public APIs have been changed.\n\n## `v0.5.0` to `0.5.1`\n\nNo public APIs have been changed.\n\n## `v0.4.1` to `0.5.0`\n\nA number of breaking changes where introduced which make backwards compatibility of skills rare.\n\n- Ledger APIs <a href=\"../api/crypto/ledger_apis#ledger-apis-objects\">`LedgerApis`</a> have been removed from the AEA constructor and skill context. `LedgerApis` are now exposed in the `LedgerConnection` (`fetchai/ledger`). To communicate with the `LedgerApis` use the `fetchai/ledger_api` protocol. This allows for more flexibility (anyone can add another `LedgerAPI` to the registry and execute it with the connection) and removes dependencies from the core framework.\n- Skills can now depend on other skills. As a result, skills have a new required configuration field in `skill.yaml` files, by default empty: `skills: []`.\n\n## `v0.4.0` to `v0.4.1`\n\nThere are no upgrade requirements if you use the CLI based approach to AEA development.\n\nConnections are now added via <a href=\"../api/registries/resources#resources-objects\">`Resources`</a> to the AEA, not the AEA constructor directly. For programmatic usage remove the list of connections from the AEA constructor and instead add the connections to resources.\n\n## `v0.3.3` to `v0.4.0`\n\n- Message sending in the skills has been updated. In the past you had to construct messages, then serialize them and place them in an envelope:\n\n    ``` python\n    cfp_msg = FipaMessage(...)\n    self.context.outbox.put_message(\n        to=opponent_addr,\n        sender=self.context.agent_address,\n        protocol_id=FipaMessage.protocol_id,\n        message=FipaSerializer().encode(cfp_msg),\n    )\n    # or\n    cfp_msg = FipaMessage(...)\n    envelope = Envelope(\n        to=opponent_addr,\n        sender=self.context.agent_address,\n        protocol_id=FipaMessage.protocol_id,\n        message=FipaSerializer().encode(cfp_msg),\n    )\n    self.context.outbox.put(envelope)\n    ```\n\n    Now this has been simplified to:\n\n    ``` python\n    cfp_msg = FipaMessage(...)\n    cfp_msg.counterparty = opponent_addr\n    self.context.outbox.put_message(message=cfp_msg)\n    ```\n\n    You must update your skills as the old implementation is no longer supported.\n\n- Connection constructors have been simplified. In the past you had to implement both the `__init__` as well as the `from_config` methods of a Connection. Now you only have to implement the `__init__` method which by default at load time now receives the following keyword arguments: `configuration: ConnectionConfig, identity: Identity, crypto_store: CryptoStore`. See for example in the scaffold connection:\n\n    ``` python\n    class MyScaffoldConnection(Connection):\n        \"\"\"Proxy to the functionality of the SDK or API.\"\"\"\n\n        connection_id = PublicId.from_str(\"fetchai/scaffold:0.1.0\")\n\n        def __init__(\n            self,\n            configuration: ConnectionConfig,\n            identity: Identity,\n            crypto_store: CryptoStore,\n        ):\n            \"\"\"\n            Initialize a connection to an SDK or API.\n    \n            :param configuration: the connection configuration.\n            :param crypto_store: object to access the connection crypto objects.\n            :param identity: the identity object.\n            \"\"\"\n            super().__init__(\n                configuration=configuration, crypto_store=crypto_store, identity=identity\n            )\n    ```\n\n    As a result of this feature, you are now able to pass key-pairs to your connections via the `CryptoStore`.\n\n    You must update your connections as the old implementation is no longer supported.\n"
  },
  {
    "path": "docs/wealth.md",
    "content": "# Generating Wealth\n\nTo fund an AEA for testing on a test-net you need to request some test tokens from a faucet.\n\nFirst, make sure you have installed the crypto plugin\nof the target test-net. E.g. for Fetch.AI:\n\n``` bash\npip install aea-ledger-fetchai\n```\n\nAnd for Ethereum:\n\n``` bash\npip install aea-ledger-ethereum\n```\n\nAdd a private key to the agent\n\n``` bash\naea generate-key fetchai\naea add-key fetchai fetchai_private_key.txt\n```\n\nor\n\n``` bash\naea generate-key ethereum\naea add-key ethereum ethereum_private_key.txt\n```\n\n!!! note\n    If you already have keys in your project, the commands prompt you to confirm whether to replace the existing keys.\n\n## Using a Faucet Website\n\nFirst, print the address:\n\n``` bash\naea get-address fetchai\n```\n\nor\n\n``` bash\naea get-address ethereum\n```\n\nThis will print the address to the console. Copy the address into the clipboard and request test tokens from the faucet <a href=\"https://explore-dorado.fetch.ai\" target=\"_blank\">here for Fetch.ai</a> or <a href=\"https://faucet.metamask.io/\" target=\"_blank\">here for Ethereum</a>. It will take a while for the tokens to become available.\n\nSecond, after some time, check the wealth associated with the address:\n\n``` bash\naea get-wealth fetchai\n```\n\nor\n\n``` bash\naea get-wealth ethereum\n```\n\n## Using the CLI\n\nSimply generate wealth via the CLI:\n\n``` bash\naea generate-wealth fetchai\n```\n\nor\n\n``` bash\naea generate-wealth ethereum\n```\n\n!!! note\n    This approach can be unreliable for non-fetchai test nets.\n"
  },
  {
    "path": "docs/weather-skills.md",
    "content": "# Weather Skills\n\nThe AEA weather skills demonstrate an interaction between two AEAs.\n\n- The provider of weather data (the `weather_station`).\n- The buyer of weather data (the `weather_client`).\n\n## Discussion\n\nThe scope of the specific demo is to demonstrate how to create a simple AEA with the usage of the AEA framework and a database. The `weather_station` AEA\nwill read data from the database, that is populated with readings from a weather station, based on the requested dates and will deliver the data to the client upon payment.\nThis demo does not utilize a smart contract. As a result, we interact with a ledger only to complete a transaction.\n\nYou can use this AEA as an example of how to read data from a database and advertise these to possible clients.  \n\n## Communication\n\nThis diagram shows the communication between the various entities as data is successfully sold by the weather station AEA to the client.\n\n``` mermaid\n    sequenceDiagram\n        participant Search\n        participant Client_AEA\n        participant Weather_AEA\n        participant Blockchain\n    \n        activate Client_AEA\n        activate Search\n        activate Weather_AEA\n        activate Blockchain\n        \n        Weather_AEA->>Search: register_service\n        Client_AEA->>Search: search\n        Search-->>Client_AEA: list_of_agents\n        Client_AEA->>Weather_AEA: call_for_proposal\n        Weather_AEA->>Client_AEA: propose\n        Client_AEA->>Weather_AEA: accept\n        Weather_AEA->>Client_AEA: match_accept\n        Client_AEA->>Blockchain: transfer_funds\n        Client_AEA->>Weather_AEA: send_transaction_hash\n        Weather_AEA->>Blockchain: check_transaction_status\n        Weather_AEA->>Client_AEA: send_data\n        \n        deactivate Client_AEA\n        deactivate Search\n        deactivate Weather_AEA\n        deactivate Blockchain  \n```\n\n## Option 1: AEA Manager Approach\n\nFollow this approach when using the AEA Manager Desktop app. Otherwise, skip and follow the CLI approach below.\n\n### Preparation Instructions\n\nInstall the <a href=\"https://aea-manager.fetch.ai\" target=\"_blank\">AEA Manager</a>.\n\n### Demo Instructions\n\nThe following steps assume you have launched the AEA Manager Desktop app.\n\n1. Add a new AEA called `my_weather_station` with public id `fetchai/weather_station:0.32.5`.\n\n2. Add another new AEA called `my_weather_client` with public id `fetchai/weather_client:0.33.5`.\n\n3. Copy the address from the `my_weather_client` into your clip board. Then go to the <a href=\"https://explore-dorado.fetch.ai\" target=\"_blank\">Dorado block explorer</a> and request some test tokens via `Get Funds`.\n\n4. Run the `my_weather_station` AEA. Navigate to its logs and copy the multiaddress displayed.\n\n5. Navigate to the settings of the `my_weather_client` and under `components > connection >` `fetchai/p2p_libp2p:0.22.0` update as follows (make sure to replace the placeholder with the multiaddress):\n\n    ``` bash\n    {\n      \"delegate_uri\": \"127.0.0.1:11001\",\n      \"entry_peers\": [\"REPLACE_WITH_MULTI_ADDRESS_HERE\"],\n      \"local_uri\": \"127.0.0.1:9001\",\n      \"log_file\": \"libp2p_node.log\",\n      \"public_uri\": \"127.0.0.1:9001\"\n    }\n    ```\n\n6. Run the `my_weather_client`.\n\nIn the AEA's logs, you should see the agent trading successfully.\n\n## Option 2: CLI Approach\n\nFollow this approach when using the `aea` CLI.\n\n### Preparation Instructions\n\n#### Dependencies\n\nFollow the <a href=\"../quickstart/#preliminaries\">Preliminaries</a> and <a href=\"../quickstart/#installation\">Installation</a> sections from the AEA quick start.\n\n### Demo Instructions\n\nA demo to run the same scenario but with a true ledger transaction on Fetch.ai `testnet` or Ethereum `ropsten` network. This demo assumes the buyer\ntrusts the seller AEA to send the data upon successful payment.\n\n#### Create the Weather Station\n\nFirst, fetch the AEA that will provide weather measurements:\n\n``` bash\naea fetch fetchai/weather_station:0.32.5 --alias my_weather_station\ncd my_weather_station\naea install\naea build\n```\n\n??? note \"Alternatively, create from scratch:\"\n    The following steps create the weather station from scratch:\n\n    ``` bash\n    aea create my_weather_station\n    cd my_weather_station\n    aea add connection fetchai/p2p_libp2p:0.27.5\n    aea add connection fetchai/soef:0.27.6\n    aea add connection fetchai/ledger:0.21.5\n    aea add skill fetchai/weather_station:0.27.6\n    aea config set --type dict agent.dependencies \\\n    '{\n      \"aea-ledger-fetchai\": {\"version\": \"<2.0.0,>=1.0.0\"}\n    }'\n    aea config set agent.default_connection fetchai/p2p_libp2p:0.27.5\n    aea config set --type dict agent.default_routing \\\n    '{\n      \"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n      \"fetchai/oef_search:1.1.7\": \"fetchai/soef:0.27.6\"\n    }'\n    aea install\n    aea build\n    ```\n\n#### Create the Weather Client\n\nIn another terminal, fetch the AEA that will query the weather station:\n\n``` bash\naea fetch fetchai/weather_client:0.33.5 --alias my_weather_client\ncd my_weather_client\naea install\naea build\n```\n\n??? note \"Alternatively, create from scratch:\"\n    The following steps create the weather client from scratch:\n\n    ``` bash\n    aea create my_weather_client\n    cd my_weather_client\n    aea add connection fetchai/p2p_libp2p:0.27.5\n    aea add connection fetchai/soef:0.27.6\n    aea add connection fetchai/ledger:0.21.5\n    aea add skill fetchai/weather_client:0.26.6\n    aea config set --type dict agent.dependencies \\\n    '{\n      \"aea-ledger-fetchai\": {\"version\": \"<2.0.0,>=1.0.0\"}\n    }'\n    aea config set agent.default_connection fetchai/p2p_libp2p:0.27.5\n    aea config set --type dict agent.default_routing \\\n    '{\n      \"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n      \"fetchai/oef_search:1.1.7\": \"fetchai/soef:0.27.6\"\n    }'\n    aea install\n    aea build\n    ```\n\n#### Add Keys for the Weather Station AEA\n\nFirst, create the private key for the weather station AEA based on the network you want to transact. To generate and add a private-public key pair for Fetch.ai `Dorado` use:\n\n``` bash\naea generate-key fetchai\naea add-key fetchai fetchai_private_key.txt\n```\n\nNext, create a private key used to secure the AEA's communications:\n\n``` bash\naea generate-key fetchai fetchai_connection_private_key.txt\naea add-key fetchai fetchai_connection_private_key.txt --connection\n```\n\nFinally, certify the key for use by the connections that request that:\n\n``` bash\naea issue-certificates\n```\n\n#### Add Keys and Generate Wealth for the Weather Client AEA\n\nThe weather client needs to have some wealth to purchase the service from the weather station.\n\nFirst, create the private key for the weather client AEA based on the network you want to transact. To generate and add a private-public key pair for Fetch.ai `Dorado` use:\n\n``` bash\naea generate-key fetchai\naea add-key fetchai fetchai_private_key.txt\n```\n\nThen, create some wealth for your weather client based on the network you want to transact with. On the Fetch.ai `Dorado` network:\n\n``` bash\naea generate-wealth fetchai\n```\n\nNext, create a private key used to secure the AEA's communications:\n\n``` bash\naea generate-key fetchai fetchai_connection_private_key.txt\naea add-key fetchai fetchai_connection_private_key.txt --connection\n```\n\nFinally, certify the key for use by the connections that request that:\n\n``` bash\naea issue-certificates\n```\n\n#### Run the AEAs\n\nRun both AEAs from their respective terminals.\n\nFirst, run the weather station AEA:\n\n``` bash\naea run\n```\n\nOnce you see a message of the form `To join its network use multiaddr 'SOME_ADDRESS'` take note of the address. (Alternatively, use `aea get-multiaddress fetchai -c -i fetchai/p2p_libp2p:0.27.5 -u public_uri` to retrieve the address.) This is the entry peer address for the local <a href=\"../acn\">agent communication network</a> created by the weather station.\n\nThen, in the weather client, run this command (replace `SOME_ADDRESS` with the correct value as described above):\n\n``` bash\naea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \\\n'{\n  \"delegate_uri\": \"127.0.0.1:11001\",\n  \"entry_peers\": [\"SOME_ADDRESS\"],\n  \"local_uri\": \"127.0.0.1:9001\",\n  \"log_file\": \"libp2p_node.log\",\n  \"public_uri\": \"127.0.0.1:9001\"\n}'\n```\n\nThis allows the weather client to connect to the same local agent communication network as the weather station.\n\nThen run the weather client AEA:\n\n``` bash\naea run\n```\n\nYou will see that the AEAs negotiate and then transact using the selected ledger.\n\n#### Cleaning up\n\nWhen you're done, go up a level and delete the AEAs.\n\n``` bash\ncd ..\naea delete my_weather_station\naea delete my_weather_client\n```\n"
  },
  {
    "path": "examples/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Examples using the AEA framework.\"\"\"\n"
  },
  {
    "path": "examples/aealite_go/README.md",
    "content": "#  A simple example using the Golang `aealite` module\n"
  },
  {
    "path": "examples/aealite_go/default/default.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.25.0\n// \tprotoc        v3.11.4\n// source: default.proto\n\npackage aea_fetchai_default_v0_1_0\n\nimport (\n\tproto \"github.com/golang/protobuf/proto\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// This is a compile-time assertion that a sufficiently up-to-date version\n// of the legacy proto package is being used.\nconst _ = proto.ProtoPackageIsVersion4\n\ntype DefaultMessage_ErrorCode_ErrorCodeEnum int32\n\nconst (\n\tDefaultMessage_ErrorCode_UNSUPPORTED_PROTOCOL DefaultMessage_ErrorCode_ErrorCodeEnum = 0\n\tDefaultMessage_ErrorCode_DECODING_ERROR       DefaultMessage_ErrorCode_ErrorCodeEnum = 1\n\tDefaultMessage_ErrorCode_INVALID_MESSAGE      DefaultMessage_ErrorCode_ErrorCodeEnum = 2\n\tDefaultMessage_ErrorCode_UNSUPPORTED_SKILL    DefaultMessage_ErrorCode_ErrorCodeEnum = 3\n\tDefaultMessage_ErrorCode_INVALID_DIALOGUE     DefaultMessage_ErrorCode_ErrorCodeEnum = 4\n)\n\n// Enum value maps for DefaultMessage_ErrorCode_ErrorCodeEnum.\nvar (\n\tDefaultMessage_ErrorCode_ErrorCodeEnum_name = map[int32]string{\n\t\t0: \"UNSUPPORTED_PROTOCOL\",\n\t\t1: \"DECODING_ERROR\",\n\t\t2: \"INVALID_MESSAGE\",\n\t\t3: \"UNSUPPORTED_SKILL\",\n\t\t4: \"INVALID_DIALOGUE\",\n\t}\n\tDefaultMessage_ErrorCode_ErrorCodeEnum_value = map[string]int32{\n\t\t\"UNSUPPORTED_PROTOCOL\": 0,\n\t\t\"DECODING_ERROR\":       1,\n\t\t\"INVALID_MESSAGE\":      2,\n\t\t\"UNSUPPORTED_SKILL\":    3,\n\t\t\"INVALID_DIALOGUE\":     4,\n\t}\n)\n\nfunc (x DefaultMessage_ErrorCode_ErrorCodeEnum) Enum() *DefaultMessage_ErrorCode_ErrorCodeEnum {\n\tp := new(DefaultMessage_ErrorCode_ErrorCodeEnum)\n\t*p = x\n\treturn p\n}\n\nfunc (x DefaultMessage_ErrorCode_ErrorCodeEnum) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (DefaultMessage_ErrorCode_ErrorCodeEnum) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_default_proto_enumTypes[0].Descriptor()\n}\n\nfunc (DefaultMessage_ErrorCode_ErrorCodeEnum) Type() protoreflect.EnumType {\n\treturn &file_default_proto_enumTypes[0]\n}\n\nfunc (x DefaultMessage_ErrorCode_ErrorCodeEnum) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use DefaultMessage_ErrorCode_ErrorCodeEnum.Descriptor instead.\nfunc (DefaultMessage_ErrorCode_ErrorCodeEnum) EnumDescriptor() ([]byte, []int) {\n\treturn file_default_proto_rawDescGZIP(), []int{0, 0, 0}\n}\n\ntype DefaultMessage struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// Types that are assignable to Performative:\n\t//\t*DefaultMessage_Bytes\n\t//\t*DefaultMessage_End\n\t//\t*DefaultMessage_Error\n\tPerformative isDefaultMessage_Performative `protobuf_oneof:\"performative\"`\n}\n\nfunc (x *DefaultMessage) Reset() {\n\t*x = DefaultMessage{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_default_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *DefaultMessage) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*DefaultMessage) ProtoMessage() {}\n\nfunc (x *DefaultMessage) ProtoReflect() protoreflect.Message {\n\tmi := &file_default_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use DefaultMessage.ProtoReflect.Descriptor instead.\nfunc (*DefaultMessage) Descriptor() ([]byte, []int) {\n\treturn file_default_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (m *DefaultMessage) GetPerformative() isDefaultMessage_Performative {\n\tif m != nil {\n\t\treturn m.Performative\n\t}\n\treturn nil\n}\n\nfunc (x *DefaultMessage) GetBytes() *DefaultMessage_Bytes_Performative {\n\tif x, ok := x.GetPerformative().(*DefaultMessage_Bytes); ok {\n\t\treturn x.Bytes\n\t}\n\treturn nil\n}\n\nfunc (x *DefaultMessage) GetEnd() *DefaultMessage_End_Performative {\n\tif x, ok := x.GetPerformative().(*DefaultMessage_End); ok {\n\t\treturn x.End\n\t}\n\treturn nil\n}\n\nfunc (x *DefaultMessage) GetError() *DefaultMessage_Error_Performative {\n\tif x, ok := x.GetPerformative().(*DefaultMessage_Error); ok {\n\t\treturn x.Error\n\t}\n\treturn nil\n}\n\ntype isDefaultMessage_Performative interface {\n\tisDefaultMessage_Performative()\n}\n\ntype DefaultMessage_Bytes struct {\n\tBytes *DefaultMessage_Bytes_Performative `protobuf:\"bytes,5,opt,name=bytes,proto3,oneof\"`\n}\n\ntype DefaultMessage_End struct {\n\tEnd *DefaultMessage_End_Performative `protobuf:\"bytes,6,opt,name=end,proto3,oneof\"`\n}\n\ntype DefaultMessage_Error struct {\n\tError *DefaultMessage_Error_Performative `protobuf:\"bytes,7,opt,name=error,proto3,oneof\"`\n}\n\nfunc (*DefaultMessage_Bytes) isDefaultMessage_Performative() {}\n\nfunc (*DefaultMessage_End) isDefaultMessage_Performative() {}\n\nfunc (*DefaultMessage_Error) isDefaultMessage_Performative() {}\n\n// Custom Types\ntype DefaultMessage_ErrorCode struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tErrorCode DefaultMessage_ErrorCode_ErrorCodeEnum `protobuf:\"varint,1,opt,name=error_code,json=errorCode,proto3,enum=aea.fetchai.default.v0_1_0.DefaultMessage_ErrorCode_ErrorCodeEnum\" json:\"error_code,omitempty\"`\n}\n\nfunc (x *DefaultMessage_ErrorCode) Reset() {\n\t*x = DefaultMessage_ErrorCode{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_default_proto_msgTypes[1]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *DefaultMessage_ErrorCode) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*DefaultMessage_ErrorCode) ProtoMessage() {}\n\nfunc (x *DefaultMessage_ErrorCode) ProtoReflect() protoreflect.Message {\n\tmi := &file_default_proto_msgTypes[1]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use DefaultMessage_ErrorCode.ProtoReflect.Descriptor instead.\nfunc (*DefaultMessage_ErrorCode) Descriptor() ([]byte, []int) {\n\treturn file_default_proto_rawDescGZIP(), []int{0, 0}\n}\n\nfunc (x *DefaultMessage_ErrorCode) GetErrorCode() DefaultMessage_ErrorCode_ErrorCodeEnum {\n\tif x != nil {\n\t\treturn x.ErrorCode\n\t}\n\treturn DefaultMessage_ErrorCode_UNSUPPORTED_PROTOCOL\n}\n\n// Performatives and contents\ntype DefaultMessage_Bytes_Performative struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tContent []byte `protobuf:\"bytes,1,opt,name=content,proto3\" json:\"content,omitempty\"`\n}\n\nfunc (x *DefaultMessage_Bytes_Performative) Reset() {\n\t*x = DefaultMessage_Bytes_Performative{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_default_proto_msgTypes[2]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *DefaultMessage_Bytes_Performative) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*DefaultMessage_Bytes_Performative) ProtoMessage() {}\n\nfunc (x *DefaultMessage_Bytes_Performative) ProtoReflect() protoreflect.Message {\n\tmi := &file_default_proto_msgTypes[2]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use DefaultMessage_Bytes_Performative.ProtoReflect.Descriptor instead.\nfunc (*DefaultMessage_Bytes_Performative) Descriptor() ([]byte, []int) {\n\treturn file_default_proto_rawDescGZIP(), []int{0, 1}\n}\n\nfunc (x *DefaultMessage_Bytes_Performative) GetContent() []byte {\n\tif x != nil {\n\t\treturn x.Content\n\t}\n\treturn nil\n}\n\ntype DefaultMessage_Error_Performative struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tErrorCode *DefaultMessage_ErrorCode `protobuf:\"bytes,1,opt,name=error_code,json=errorCode,proto3\" json:\"error_code,omitempty\"`\n\tErrorMsg  string                    `protobuf:\"bytes,2,opt,name=error_msg,json=errorMsg,proto3\" json:\"error_msg,omitempty\"`\n\tErrorData map[string][]byte         `protobuf:\"bytes,3,rep,name=error_data,json=errorData,proto3\" json:\"error_data,omitempty\" protobuf_key:\"bytes,1,opt,name=key,proto3\" protobuf_val:\"bytes,2,opt,name=value,proto3\"`\n}\n\nfunc (x *DefaultMessage_Error_Performative) Reset() {\n\t*x = DefaultMessage_Error_Performative{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_default_proto_msgTypes[3]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *DefaultMessage_Error_Performative) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*DefaultMessage_Error_Performative) ProtoMessage() {}\n\nfunc (x *DefaultMessage_Error_Performative) ProtoReflect() protoreflect.Message {\n\tmi := &file_default_proto_msgTypes[3]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use DefaultMessage_Error_Performative.ProtoReflect.Descriptor instead.\nfunc (*DefaultMessage_Error_Performative) Descriptor() ([]byte, []int) {\n\treturn file_default_proto_rawDescGZIP(), []int{0, 2}\n}\n\nfunc (x *DefaultMessage_Error_Performative) GetErrorCode() *DefaultMessage_ErrorCode {\n\tif x != nil {\n\t\treturn x.ErrorCode\n\t}\n\treturn nil\n}\n\nfunc (x *DefaultMessage_Error_Performative) GetErrorMsg() string {\n\tif x != nil {\n\t\treturn x.ErrorMsg\n\t}\n\treturn \"\"\n}\n\nfunc (x *DefaultMessage_Error_Performative) GetErrorData() map[string][]byte {\n\tif x != nil {\n\t\treturn x.ErrorData\n\t}\n\treturn nil\n}\n\ntype DefaultMessage_End_Performative struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n}\n\nfunc (x *DefaultMessage_End_Performative) Reset() {\n\t*x = DefaultMessage_End_Performative{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_default_proto_msgTypes[4]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *DefaultMessage_End_Performative) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*DefaultMessage_End_Performative) ProtoMessage() {}\n\nfunc (x *DefaultMessage_End_Performative) ProtoReflect() protoreflect.Message {\n\tmi := &file_default_proto_msgTypes[4]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use DefaultMessage_End_Performative.ProtoReflect.Descriptor instead.\nfunc (*DefaultMessage_End_Performative) Descriptor() ([]byte, []int) {\n\treturn file_default_proto_rawDescGZIP(), []int{0, 3}\n}\n\nvar File_default_proto protoreflect.FileDescriptor\n\nvar file_default_proto_rawDesc = []byte{\n\t0x0a, 0x0d, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12,\n\t0x1a, 0x61, 0x65, 0x61, 0x2e, 0x66, 0x65, 0x74, 0x63, 0x68, 0x61, 0x69, 0x2e, 0x64, 0x65, 0x66,\n\t0x61, 0x75, 0x6c, 0x74, 0x2e, 0x76, 0x30, 0x5f, 0x31, 0x5f, 0x30, 0x22, 0x89, 0x07, 0x0a, 0x0e,\n\t0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x55,\n\t0x0a, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3d, 0x2e,\n\t0x61, 0x65, 0x61, 0x2e, 0x66, 0x65, 0x74, 0x63, 0x68, 0x61, 0x69, 0x2e, 0x64, 0x65, 0x66, 0x61,\n\t0x75, 0x6c, 0x74, 0x2e, 0x76, 0x30, 0x5f, 0x31, 0x5f, 0x30, 0x2e, 0x44, 0x65, 0x66, 0x61, 0x75,\n\t0x6c, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x42, 0x79, 0x74, 0x65, 0x73, 0x5f,\n\t0x50, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x76, 0x65, 0x48, 0x00, 0x52, 0x05,\n\t0x62, 0x79, 0x74, 0x65, 0x73, 0x12, 0x4f, 0x0a, 0x03, 0x65, 0x6e, 0x64, 0x18, 0x06, 0x20, 0x01,\n\t0x28, 0x0b, 0x32, 0x3b, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x66, 0x65, 0x74, 0x63, 0x68, 0x61, 0x69,\n\t0x2e, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x2e, 0x76, 0x30, 0x5f, 0x31, 0x5f, 0x30, 0x2e,\n\t0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x45,\n\t0x6e, 0x64, 0x5f, 0x50, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x76, 0x65, 0x48,\n\t0x00, 0x52, 0x03, 0x65, 0x6e, 0x64, 0x12, 0x55, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18,\n\t0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3d, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x66, 0x65, 0x74, 0x63,\n\t0x68, 0x61, 0x69, 0x2e, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x2e, 0x76, 0x30, 0x5f, 0x31,\n\t0x5f, 0x30, 0x2e, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67,\n\t0x65, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x50, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x61,\n\t0x74, 0x69, 0x76, 0x65, 0x48, 0x00, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x1a, 0xef, 0x01,\n\t0x0a, 0x09, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x61, 0x0a, 0x0a, 0x65,\n\t0x72, 0x72, 0x6f, 0x72, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32,\n\t0x42, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x66, 0x65, 0x74, 0x63, 0x68, 0x61, 0x69, 0x2e, 0x64, 0x65,\n\t0x66, 0x61, 0x75, 0x6c, 0x74, 0x2e, 0x76, 0x30, 0x5f, 0x31, 0x5f, 0x30, 0x2e, 0x44, 0x65, 0x66,\n\t0x61, 0x75, 0x6c, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x45, 0x72, 0x72, 0x6f,\n\t0x72, 0x43, 0x6f, 0x64, 0x65, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x45,\n\t0x6e, 0x75, 0x6d, 0x52, 0x09, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x22, 0x7f,\n\t0x0a, 0x0d, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x45, 0x6e, 0x75, 0x6d, 0x12,\n\t0x18, 0x0a, 0x14, 0x55, 0x4e, 0x53, 0x55, 0x50, 0x50, 0x4f, 0x52, 0x54, 0x45, 0x44, 0x5f, 0x50,\n\t0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0x10, 0x00, 0x12, 0x12, 0x0a, 0x0e, 0x44, 0x45, 0x43,\n\t0x4f, 0x44, 0x49, 0x4e, 0x47, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x01, 0x12, 0x13, 0x0a,\n\t0x0f, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x5f, 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, 0x45,\n\t0x10, 0x02, 0x12, 0x15, 0x0a, 0x11, 0x55, 0x4e, 0x53, 0x55, 0x50, 0x50, 0x4f, 0x52, 0x54, 0x45,\n\t0x44, 0x5f, 0x53, 0x4b, 0x49, 0x4c, 0x4c, 0x10, 0x03, 0x12, 0x14, 0x0a, 0x10, 0x49, 0x4e, 0x56,\n\t0x41, 0x4c, 0x49, 0x44, 0x5f, 0x44, 0x49, 0x41, 0x4c, 0x4f, 0x47, 0x55, 0x45, 0x10, 0x04, 0x1a,\n\t0x2e, 0x0a, 0x12, 0x42, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x50, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d,\n\t0x61, 0x74, 0x69, 0x76, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74,\n\t0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x1a,\n\t0xb1, 0x02, 0x0a, 0x12, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x50, 0x65, 0x72, 0x66, 0x6f, 0x72,\n\t0x6d, 0x61, 0x74, 0x69, 0x76, 0x65, 0x12, 0x53, 0x0a, 0x0a, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f,\n\t0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x61, 0x65, 0x61,\n\t0x2e, 0x66, 0x65, 0x74, 0x63, 0x68, 0x61, 0x69, 0x2e, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74,\n\t0x2e, 0x76, 0x30, 0x5f, 0x31, 0x5f, 0x30, 0x2e, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x4d,\n\t0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x43, 0x6f, 0x64, 0x65,\n\t0x52, 0x09, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x65,\n\t0x72, 0x72, 0x6f, 0x72, 0x5f, 0x6d, 0x73, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08,\n\t0x65, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x73, 0x67, 0x12, 0x6b, 0x0a, 0x0a, 0x65, 0x72, 0x72, 0x6f,\n\t0x72, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x4c, 0x2e, 0x61,\n\t0x65, 0x61, 0x2e, 0x66, 0x65, 0x74, 0x63, 0x68, 0x61, 0x69, 0x2e, 0x64, 0x65, 0x66, 0x61, 0x75,\n\t0x6c, 0x74, 0x2e, 0x76, 0x30, 0x5f, 0x31, 0x5f, 0x30, 0x2e, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c,\n\t0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x50,\n\t0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x76, 0x65, 0x2e, 0x45, 0x72, 0x72, 0x6f,\n\t0x72, 0x44, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x65, 0x72, 0x72, 0x6f,\n\t0x72, 0x44, 0x61, 0x74, 0x61, 0x1a, 0x3c, 0x0a, 0x0e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x44, 0x61,\n\t0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01,\n\t0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c,\n\t0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a,\n\t0x02, 0x38, 0x01, 0x1a, 0x12, 0x0a, 0x10, 0x45, 0x6e, 0x64, 0x5f, 0x50, 0x65, 0x72, 0x66, 0x6f,\n\t0x72, 0x6d, 0x61, 0x74, 0x69, 0x76, 0x65, 0x42, 0x0e, 0x0a, 0x0c, 0x70, 0x65, 0x72, 0x66, 0x6f,\n\t0x72, 0x6d, 0x61, 0x74, 0x69, 0x76, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_default_proto_rawDescOnce sync.Once\n\tfile_default_proto_rawDescData = file_default_proto_rawDesc\n)\n\nfunc file_default_proto_rawDescGZIP() []byte {\n\tfile_default_proto_rawDescOnce.Do(func() {\n\t\tfile_default_proto_rawDescData = protoimpl.X.CompressGZIP(file_default_proto_rawDescData)\n\t})\n\treturn file_default_proto_rawDescData\n}\n\nvar file_default_proto_enumTypes = make([]protoimpl.EnumInfo, 1)\nvar file_default_proto_msgTypes = make([]protoimpl.MessageInfo, 6)\nvar file_default_proto_goTypes = []interface{}{\n\t(DefaultMessage_ErrorCode_ErrorCodeEnum)(0), // 0: aea.fetchai.default.v0_1_0.DefaultMessage.ErrorCode.ErrorCodeEnum\n\t(*DefaultMessage)(nil),                      // 1: aea.fetchai.default.v0_1_0.DefaultMessage\n\t(*DefaultMessage_ErrorCode)(nil),            // 2: aea.fetchai.default.v0_1_0.DefaultMessage.ErrorCode\n\t(*DefaultMessage_Bytes_Performative)(nil),   // 3: aea.fetchai.default.v0_1_0.DefaultMessage.Bytes_Performative\n\t(*DefaultMessage_Error_Performative)(nil),   // 4: aea.fetchai.default.v0_1_0.DefaultMessage.Error_Performative\n\t(*DefaultMessage_End_Performative)(nil),     // 5: aea.fetchai.default.v0_1_0.DefaultMessage.End_Performative\n\tnil,                                         // 6: aea.fetchai.default.v0_1_0.DefaultMessage.Error_Performative.ErrorDataEntry\n}\nvar file_default_proto_depIdxs = []int32{\n\t3, // 0: aea.fetchai.default.v0_1_0.DefaultMessage.bytes:type_name -> aea.fetchai.default.v0_1_0.DefaultMessage.Bytes_Performative\n\t5, // 1: aea.fetchai.default.v0_1_0.DefaultMessage.end:type_name -> aea.fetchai.default.v0_1_0.DefaultMessage.End_Performative\n\t4, // 2: aea.fetchai.default.v0_1_0.DefaultMessage.error:type_name -> aea.fetchai.default.v0_1_0.DefaultMessage.Error_Performative\n\t0, // 3: aea.fetchai.default.v0_1_0.DefaultMessage.ErrorCode.error_code:type_name -> aea.fetchai.default.v0_1_0.DefaultMessage.ErrorCode.ErrorCodeEnum\n\t2, // 4: aea.fetchai.default.v0_1_0.DefaultMessage.Error_Performative.error_code:type_name -> aea.fetchai.default.v0_1_0.DefaultMessage.ErrorCode\n\t6, // 5: aea.fetchai.default.v0_1_0.DefaultMessage.Error_Performative.error_data:type_name -> aea.fetchai.default.v0_1_0.DefaultMessage.Error_Performative.ErrorDataEntry\n\t6, // [6:6] is the sub-list for method output_type\n\t6, // [6:6] is the sub-list for method input_type\n\t6, // [6:6] is the sub-list for extension type_name\n\t6, // [6:6] is the sub-list for extension extendee\n\t0, // [0:6] is the sub-list for field type_name\n}\n\nfunc init() { file_default_proto_init() }\nfunc file_default_proto_init() {\n\tif File_default_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_default_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*DefaultMessage); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_default_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*DefaultMessage_ErrorCode); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_default_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*DefaultMessage_Bytes_Performative); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_default_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*DefaultMessage_Error_Performative); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_default_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*DefaultMessage_End_Performative); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\tfile_default_proto_msgTypes[0].OneofWrappers = []interface{}{\n\t\t(*DefaultMessage_Bytes)(nil),\n\t\t(*DefaultMessage_End)(nil),\n\t\t(*DefaultMessage_Error)(nil),\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_default_proto_rawDesc,\n\t\t\tNumEnums:      1,\n\t\t\tNumMessages:   6,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_default_proto_goTypes,\n\t\tDependencyIndexes: file_default_proto_depIdxs,\n\t\tEnumInfos:         file_default_proto_enumTypes,\n\t\tMessageInfos:      file_default_proto_msgTypes,\n\t}.Build()\n\tFile_default_proto = out.File\n\tfile_default_proto_rawDesc = nil\n\tfile_default_proto_goTypes = nil\n\tfile_default_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "examples/aealite_go/default/default.proto",
    "content": "syntax = \"proto3\";\n\npackage aea.fetchai.default.v0_1_0;\n\nmessage DefaultMessage{\n\n  // Custom Types\n  message ErrorCode{\n    enum ErrorCodeEnum {\n      UNSUPPORTED_PROTOCOL = 0;\n      DECODING_ERROR = 1;\n      INVALID_MESSAGE = 2;\n      UNSUPPORTED_SKILL = 3;\n      INVALID_DIALOGUE = 4;\n    }\n    ErrorCodeEnum error_code = 1;\n  }\n\n\n  // Performatives and contents\n  message Bytes_Performative{\n    bytes content = 1;\n  }\n\n  message Error_Performative{\n    ErrorCode error_code = 1;\n    string error_msg = 2;\n    map<string, bytes> error_data = 3;\n  }\n\n  message End_Performative{\n  }\n\n\n  oneof performative{\n    Bytes_Performative bytes = 5;\n    End_Performative end = 6;\n    Error_Performative error = 7;\n  }\n}\n"
  },
  {
    "path": "examples/gym_ex/README.md",
    "content": "# RL agent & gym\n\n## Dependencies\n\nThis example requires `numpy` and `gym` in addition to the dependencies of the `aea` package.\n\n## Run\n\nFrom root execute:\n\n`\npython examples/gym_ex/train.py\n`\n\nwhich has the usual RL setup (that is, the `fit` method of the `RLAgent` has the typical signature and familiar implementation).\n"
  },
  {
    "path": "examples/gym_ex/gyms/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the gym environment.\"\"\"\n"
  },
  {
    "path": "examples/gym_ex/gyms/env.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Training environment for multi armed bandit.\"\"\"\n\nfrom typing import List, Tuple\n\nimport gym\nimport numpy as np\nfrom gym import spaces  # type: ignore\n\n\nBanditId = int\nPrice = int\n\nAction = Tuple[BanditId, Price]\nObservation = type(None)\nReward = float\nDone = bool\nInfo = dict\n\nFeedback = Tuple[Observation, Reward, Done, Info]\n\n\nclass BanditEnv(gym.Env):\n    \"\"\"Base environment for n-armed bandits.\"\"\"\n\n    def __init__(\n        self,\n        nb_bandits: int,\n        nb_prices_per_bandit: int,\n        reward_params: List[Tuple[float, int]],\n    ):\n        \"\"\"\n        Initialize the environment.\n\n        :param nb_bandits: number of bandits\n        :param nb_prices_per_bandit: number of prices per bandit\n        :param reward_params: single param or tuple of params for the reward distribution\n        \"\"\"\n        self.nb_bandits = nb_bandits\n        self.nb_prices_per_bandit = nb_prices_per_bandit\n        self.reward_params = reward_params\n\n        self.action_space = spaces.Tuple(\n            (\n                spaces.Discrete(self.nb_bandits),\n                spaces.Discrete(self.nb_prices_per_bandit),\n            )\n        )  # an action is specifying one of nb_bandits and specifying a price for the bandit.\n        self.observation_space = (\n            spaces.Space()\n        )  # None type space. agents only get a reward back.\n\n        self.seed()  # type: ignore  # seed environment randomness # pylint: disable=no-member  # used in aries skills\n\n    @staticmethod\n    def reset() -> Observation:  # type:ignore  # pylint: disable=arguments-differ\n        \"\"\"\n        Reset the environment.\n\n        :return: an observation\n        \"\"\"\n        observation = None  # we purposefully make this explicit here\n        return observation\n\n    def step(self, action: Action) -> Feedback:  # type: ignore\n        \"\"\"\n        Execute one time step within the environment.\n\n        :param action: the id of the bandit chosen\n        :return: a Tuple containing the Feedback of Observation, Reward, Done and Info\n        \"\"\"\n        if not self.action_space.contains(action):\n            raise ValueError(\"This is not a valid action.\")\n\n        bandit = action[0]\n        offered_price = action[1]\n\n        # defaults\n        observation = None\n        done = False\n        info = {}  # type: Info\n\n        cutoff_price = np.random.normal(\n            self.reward_params[bandit][0], self.reward_params[bandit][1]\n        )\n\n        if offered_price > cutoff_price:\n            reward = 1.0\n        else:\n            reward = 0.0\n\n        return observation, reward, done, info\n\n    def render(  # pylint: disable=arguments-differ\n        self, mode: str = \"human\", close: int = False\n    ) -> None:\n        \"\"\"\n        Render the environment to the screen.\n\n        :param mode: the rendering mode\n        :param close: a bool, true if ending\n        \"\"\"\n\n\nclass BanditNArmedRandom(BanditEnv):\n    \"\"\"N-armed bandit randomly initialized.\"\"\"\n\n    def __init__(\n        self,\n        nb_bandits: int = 10,\n        nb_prices_per_bandit: int = 100,\n        stdev: int = 1,\n        seed: int = 42,\n    ):\n        \"\"\"\n        Initialize the environment.\n\n        :param nb_bandits: number of bandits.\n        :param nb_prices_per_bandit: number of prices per bandit.\n        :param stdev: standard deviation of the normal distribution.\n        :param seed: the seed to initialize np random (not the env!)\n        \"\"\"\n        np.random.seed(seed)\n\n        reward_params = []  # type: List[Tuple[float, int]]\n        for _i in range(nb_bandits):\n            # Mean m is pulled from a uniform distribution over [0, bound). To induce a normal distribution with params\n            # (m, 1).\n            mean = np.random.uniform(0, nb_prices_per_bandit)\n            reward_params.append((mean, stdev))  # type: ignore\n\n        BanditEnv.__init__(\n            self,\n            nb_bandits=nb_bandits,\n            nb_prices_per_bandit=nb_prices_per_bandit,\n            reward_params=reward_params,\n        )\n"
  },
  {
    "path": "examples/gym_ex/proxy/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the proxies.\"\"\"\n"
  },
  {
    "path": "examples/gym_ex/proxy/agent.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This contains the proxy agent class.\"\"\"\nimport os\nimport sys\nfrom queue import Queue\n\nimport gym\n\nfrom aea.agent import Agent\nfrom aea.configurations.base import ConnectionConfig\nfrom aea.helpers.base import locate\nfrom aea.identity.base import Identity\nfrom aea.mail.base import Envelope\n\n\nsys.modules[\"packages.fetchai.connections.gym\"] = locate(  # isort:skip\n    \"packages.fetchai.connections.gym\"\n)\n\n\nfrom packages.fetchai.connections.gym.connection import (  # noqa: E402  # pylint: disable=wrong-import-position\n    GymConnection,\n)\n\n\nADDRESS = \"some_address\"\nPUBLIC_KEY = \"some_public_key\"\n\n\nclass ProxyAgent(Agent):\n    \"\"\"This class implements a proxy agent to be used by a proxy environment.\"\"\"\n\n    def __init__(self, name: str, gym_env: gym.Env, proxy_env_queue: Queue) -> None:\n        \"\"\"\n        Instantiate the agent.\n\n        :param name: the name of the agent\n        :param gym_env: gym environment\n        :param proxy_env_queue: the queue of the proxy environment\n        \"\"\"\n        identity = Identity(name, ADDRESS, PUBLIC_KEY)\n        configuration = ConnectionConfig(connection_id=GymConnection.connection_id)\n        super().__init__(\n            identity,\n            [\n                GymConnection(\n                    gym_env,\n                    identity=identity,\n                    configuration=configuration,\n                    data_dir=os.getcwd(),\n                )\n            ],\n            period=0.01,\n        )\n        self.proxy_env_queue = proxy_env_queue\n\n    def setup(self) -> None:\n        \"\"\"Set up the agent.\"\"\"\n\n    def act(self) -> None:\n        \"\"\"Perform actions.\"\"\"\n\n    def handle_envelope(self, envelope: Envelope) -> None:\n        \"\"\"\n        Handle envelope.\n\n        :param envelope: the envelope\n        \"\"\"\n        if envelope is not None:\n            self.proxy_env_queue.put(envelope)\n\n    def teardown(self) -> None:\n        \"\"\"Tear down the agent.\"\"\"\n"
  },
  {
    "path": "examples/gym_ex/proxy/env.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This contains the proxy gym environment.\"\"\"\n\nimport sys\nimport time\nfrom queue import Queue\nfrom threading import Thread\nfrom typing import Any, Optional, Tuple, cast\n\nimport gym\n\nfrom aea.common import Address\nfrom aea.helpers.base import locate\nfrom aea.mail.base import Envelope\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\n\n\nsys.modules[\"packages.fetchai.connections.gym\"] = locate(  # isort:skip\n    \"packages.fetchai.connections.gym\"\n)\nsys.modules[\"packages.fetchai.protocols.gym\"] = locate(  # isort:skip\n    \"packages.fetchai.protocols.gym\"\n)\n\n\nfrom packages.fetchai.connections.gym.connection import (  # noqa: E402  # pylint: disable=wrong-import-position\n    GymConnection,\n)\nfrom packages.fetchai.connections.gym.connection import (  # noqa: E402  # pylint: disable=wrong-import-position\n    PUBLIC_ID as GYM_CONNECTION_PUBLIC_ID,\n)\nfrom packages.fetchai.protocols.gym.dialogues import (  # noqa: E402  # pylint: disable=wrong-import-position\n    GymDialogue as BaseGymDialogue,\n)\nfrom packages.fetchai.protocols.gym.dialogues import (  # noqa: E402  # pylint: disable=wrong-import-position\n    GymDialogues as BaseGymDialogues,\n)\nfrom packages.fetchai.protocols.gym.message import (  # noqa: E402  # pylint: disable=wrong-import-position\n    GymMessage,\n)\n\nfrom .agent import ProxyAgent  # noqa: E402  # pylint: disable=wrong-import-position\n\n\nAction = Any\nObservation = Any\nReward = float\nDone = bool\nInfo = dict\nFeedback = Tuple[Observation, Reward, Done, Info]\n\nGymDialogue = BaseGymDialogue\n\nGymDialogues = BaseGymDialogues\n\n\ndef role_from_first_message(  # pylint: disable=unused-argument\n    message: Message, receiver_address: Address\n) -> BaseDialogue.Role:\n    \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n    :param message: an incoming/outgoing first message\n    :param receiver_address: the address of the receiving agent\n    :return: The role of the agent\n    \"\"\"\n    return BaseGymDialogue.Role.AGENT\n\n\nclass ProxyEnv(gym.Env):\n    \"\"\"This class implements a proxy gym environment.\"\"\"\n\n    def __init__(self, gym_env: gym.Env) -> None:\n        \"\"\"\n        Instantiate the proxy environment.\n\n        :param gym_env: gym environment\n        \"\"\"\n        super().__init__()\n        self._queue: Queue = Queue()\n        self._action_counter: int = 0\n        self.gym_address = str(GYM_CONNECTION_PUBLIC_ID)\n        self._agent = ProxyAgent(\n            name=\"proxy\", gym_env=gym_env, proxy_env_queue=self._queue\n        )\n        self._agent_thread = Thread(target=self._agent.start)\n        self._active_dialogue = None  # type: Optional[GymDialogue]\n        self.gym_skill = \"fetchai/gym:0.1.0\"\n        self.gym_dialogues = GymDialogues(self.gym_skill, role_from_first_message)\n\n    @property\n    def active_dialogue(self) -> GymDialogue:\n        \"\"\"Get the active dialogue.\"\"\"\n        if self._active_dialogue is None:\n            raise RuntimeError(\"active dialogue was not set\")\n        return self._active_dialogue\n\n    def step(self, action: Action) -> Feedback:  # type: ignore\n        \"\"\"\n        Run one time-step of the environment's dynamics.\n\n        Mirrors the standard 'step' method of a gym environment.\n\n        - The action is given to _encode_action, which does the necessary conversion to an envelope.\n        - The envelope is given to the outbox of the proxy agent.\n        - The method blocks until the _queue returns an envelope.\n        - The envelope is decoded with _decode_percept to a message.\n        - The message is converted into the standard observation, reward, done and info via _message_to_percept\n\n        :param action: the action sent to the step method (e.g. the output of an RL algorithm)\n        :return: a Tuple containing the Feedback of Observation, Reward, Done and Info\n        \"\"\"\n        self._action_counter += 1\n        step_id = self._action_counter\n\n        self._encode_and_send_action(action, step_id)\n\n        # Wait (blocking!) for the response envelope from the environment\n        in_envelope = self._queue.get(block=True, timeout=None)  # type: Envelope\n\n        msg = self._decode_percept(in_envelope, step_id)\n\n        observation, reward, done, info = self._message_to_percept(msg)\n\n        return observation, reward, done, info\n\n    def render(self, mode: str = \"human\") -> None:\n        \"\"\"\n        Render the environment.\n\n        :param mode: the run mode\n        \"\"\"\n        if self._agent.runtime.multiplexer.default_connection is None:\n            raise RuntimeError(\"Default connection was not set\")\n        cast(\n            GymConnection, self._agent.runtime.multiplexer.default_connection\n        ).channel.gym_env.render(\n            mode\n        )  # type: ignore\n\n    def reset(self) -> None:  # type: ignore # pylint: disable=arguments-differ\n        \"\"\"Reset the environment.\"\"\"\n        if not self._agent.runtime.multiplexer.is_connected:\n            self._connect()\n        gym_msg, gym_dialogue = self.gym_dialogues.create(\n            counterparty=self.gym_address,\n            performative=GymMessage.Performative.RESET,\n        )\n        gym_dialogue = cast(GymDialogue, gym_dialogue)\n        self._active_dialogue = gym_dialogue\n        self._agent.outbox.put_message(message=gym_msg)\n\n        # Wait (blocking!) for the response envelope from the environment\n        in_envelope = self._queue.get(block=True, timeout=None)  # type: Envelope\n\n        self._decode_status(in_envelope)\n\n    def close(self) -> None:\n        \"\"\"Close the environment.\"\"\"\n        last_msg = self.active_dialogue.last_message\n        if last_msg is None:\n            raise ValueError(\"Cannot retrieve last message.\")\n        gym_msg = self.active_dialogue.reply(\n            performative=GymMessage.Performative.CLOSE,\n            target_message=last_msg,\n        )\n        self._agent.outbox.put_message(message=gym_msg)\n\n        self._disconnect()\n\n    def _connect(self) -> None:\n        \"\"\"Connect to this proxy environment. It starts a proxy agent that can interact with the framework.\"\"\"\n        if self._agent_thread.is_alive():\n            raise ValueError(\"Agent already running.\")\n        self._agent_thread.start()\n\n        while not self._agent.runtime.is_running:  # check agent completely running\n            time.sleep(0.01)\n\n    def _disconnect(self) -> None:\n        \"\"\"Disconnect from this proxy environment. It stops the proxy agent and kills its thread.\"\"\"\n        self._agent.stop()\n        self._agent_thread.join()\n\n    def _encode_and_send_action(self, action: Action, step_id: int) -> None:\n        \"\"\"\n        Encode the 'action' sent to the step function and send.\n\n        :param action: the action that is the output of an RL algorithm.\n        :param step_id: the step id\n        \"\"\"\n        last_msg = self.active_dialogue.last_message\n        if last_msg is None:\n            raise ValueError(\"Cannot retrieve last message.\")\n        gym_msg = self.active_dialogue.reply(\n            performative=GymMessage.Performative.ACT,\n            target_message=last_msg,\n            action=GymMessage.AnyObject(action),\n            step_id=step_id,\n        )\n        # Send the message via the proxy agent and to the environment\n        self._agent.outbox.put_message(message=gym_msg)\n\n    def _decode_percept(self, envelope: Envelope, expected_step_id: int) -> GymMessage:\n        \"\"\"\n        Receive the response from the gym environment in the form of an envelope and decode it.\n\n        The response is a PERCEPT message containing the usual 'observation', 'reward', 'done', 'info' parameters.\n\n        :param envelope: the envelope\n        :param expected_step_id: the expected step id\n        :return: a message received as a response to the action performed in apply_action.\n        \"\"\"\n        if envelope is not None:\n            if (\n                envelope.protocol_specification_id\n                == GymMessage.protocol_specification_id\n            ):\n                gym_msg = cast(GymMessage, envelope.message)\n                gym_dialogue = self.gym_dialogues.update(gym_msg)\n                if not gym_dialogue:\n                    raise ValueError(\"Could not udpate dialogue.\")\n                if not gym_dialogue == self.active_dialogue:\n                    raise ValueError(\"Dialogue does not match.\")\n                if (\n                    gym_msg.performative == GymMessage.Performative.PERCEPT\n                    and gym_msg.step_id == expected_step_id\n                ):\n                    return gym_msg\n                raise ValueError(\n                    \"Unexpected performative or no step_id: {}\".format(\n                        gym_msg.performative\n                    )\n                )\n            raise ValueError(\n                \"Unknown protocol_specification_id: {}\".format(\n                    envelope.protocol_specification_id\n                )\n            )\n        raise ValueError(\"Missing envelope.\")\n\n    def _decode_status(self, envelope: Envelope) -> None:\n        \"\"\"\n        Receive the response from the gym environment in the form of an envelope and decode it.\n\n        The response is a STATUS message.\n\n        :param envelope: the envelope\n        :return: a message received as a response to the action performed in apply_action.\n        \"\"\"\n        if envelope is not None:\n            if (\n                envelope.protocol_specification_id\n                == GymMessage.protocol_specification_id\n            ):\n                gym_msg = cast(GymMessage, envelope.message)\n                gym_dialogue = self.gym_dialogues.update(gym_msg)\n                if not gym_dialogue:\n                    raise ValueError(\"Could not udpate dialogue.\")\n                if not gym_dialogue == self.active_dialogue:\n                    raise ValueError(\"Dialogue does not match.\")\n                if (\n                    gym_msg.performative == GymMessage.Performative.STATUS\n                    and gym_msg.content.get(\"reset\", \"failure\") == \"success\"\n                ):\n\n                    return None\n                raise ValueError(\n                    \"Unexpected performative or no step_id: {}\".format(\n                        gym_msg.performative\n                    )\n                )\n            raise ValueError(\n                \"Unknown protocol_id: {}\".format(envelope.protocol_specification_id)\n            )\n        raise ValueError(\"Missing envelope.\")\n\n    @staticmethod\n    def _message_to_percept(message: GymMessage) -> Feedback:\n        \"\"\"\n        Transform the message received from the gym environment into observation, reward, done, info.\n\n        :param message: the message received as a response to the action performed in apply_action.\n        :return: the standard feedback (observation, reward, done, info) of a gym environment.\n        \"\"\"\n        observation = cast(Any, message.observation.any)\n        reward = cast(float, message.reward)\n        done = cast(bool, message.done)\n        info = cast(dict, message.info.any)\n\n        return observation, reward, done, info\n"
  },
  {
    "path": "examples/gym_ex/rl/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the rl modules.\"\"\"\n"
  },
  {
    "path": "examples/gym_ex/rl/agent.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This contains the rl agent class.\"\"\"\n\nimport random\nfrom typing import Dict, Tuple\n\nimport gym\nimport numpy as np\n\n\nBanditId = int\nPrice = int\n\nAction = Tuple[BanditId, Price]\nObservation = type(None)\nReward = float\nDone = bool\nInfo = dict\n\nFeedback = Tuple[Observation, Reward, Done, Info]\n\n\nclass PriceBandit:\n    \"\"\"A class for a multi-armed bandit model of price.\"\"\"\n\n    def __init__(self, price: float, beta_a: float = 1.0, beta_b: float = 1.0):\n        \"\"\"\n        Instantiate a price bandit object.\n\n        :param price: the price this bandit is modelling\n        :param beta_a: the a parameter of the beta distribution\n        :param beta_b: the b parameter of the beta distribution\n        \"\"\"\n        self.price = price\n        # default params imply a uniform random prior\n        self.beta_a = beta_a\n        self.beta_b = beta_b\n\n    def sample(self) -> int:\n        \"\"\"\n        Sample from the bandit.\n\n        :return: the sampled value\n        \"\"\"\n        return round(np.random.beta(self.beta_a, self.beta_b))\n\n    def update(self, outcome: float) -> None:\n        \"\"\"\n        Update the bandit.\n\n        :param outcome: the outcome used for updating\n        \"\"\"\n        self.beta_a += outcome\n        self.beta_b += 1 - outcome\n\n\nclass GoodPriceModel:\n    \"\"\"A class for a price model of a good.\"\"\"\n\n    def __init__(self, bound: int = 100):\n        \"\"\"Instantiate a good price model.\"\"\"\n        self.price_bandits = dict(\n            (price, PriceBandit(price)) for price in range(bound + 1)\n        )\n\n    def update(self, outcome: float, price: int) -> None:\n        \"\"\"\n        Update the respective bandit.\n\n        :param price: the price to be updated\n        :param outcome: the negotiation outcome\n        \"\"\"\n        bandit = self.price_bandits[price]\n        bandit.update(outcome)\n\n    def get_price_expectation(self) -> int:\n        \"\"\"\n        Get best price.\n\n        :return: the winning price\n        \"\"\"\n        max_sample = -1\n        winning_price = 0\n        for price, bandit in self.price_bandits.items():\n            sample = bandit.sample()\n            if sample > max_sample:\n                max_sample = sample\n                winning_price = price\n        return winning_price\n\n\nclass RLAgent:\n    \"\"\"This class is a reinforcement learning agent that uses a Multi-Armed Bandit algorithm.\"\"\"\n\n    def __init__(self, nb_goods: int = 10) -> None:\n        \"\"\"\n        Instantiate the RL agent.\n\n        :param nb_goods: number of goods\n        \"\"\"\n        self.good_price_models = dict(\n            (good_id, GoodPriceModel()) for good_id in range(nb_goods)\n        )  # type: Dict[int, GoodPriceModel]\n\n    def _pick_an_action(self) -> Action:\n        \"\"\"\n        Pick an action.\n\n        :return: agent's action\n        \"\"\"\n        # Get the good\n        good_id = self._get_random_next_good()\n\n        # Pick the best price based on own model.\n        good_price_model = self.good_price_models[good_id]\n        price = good_price_model.get_price_expectation()\n\n        action = (good_id, price)\n\n        return action\n\n    def _update_model(  # pylint: disable=unused-argument\n        self,\n        observation: Observation,\n        reward: Reward,\n        done: Done,\n        info: Info,\n        action: Action,\n    ) -> None:\n        \"\"\"\n        Update the model.\n\n        :param: observation: agent's observation of the current environment\n        :param: reward: amount of reward returned after previous action\n        :param: done: whether the episode has ended\n        :param: info: auxiliary diagnostic information\n        :param: action: action the agent performed on the environment to which the response was the above 4\n        \"\"\"\n        good_id, price = action\n\n        # Update the price model:\n        good_price_model = self.good_price_models[good_id]\n        good_price_model.update(reward, price)\n\n    def _get_random_next_good(self) -> int:\n        \"\"\"\n        Get the next good for trading (randomly).\n\n        :return: a random good\n        \"\"\"\n        return random.choice(list(self.good_price_models.keys()))  # nosec\n\n    def fit(self, env: gym.Env, nb_steps: int) -> None:\n        \"\"\"\n        Train the agent on the given proxy environment.\n\n        :param env: the gym environment in which the agent is trained\n        :param nb_steps: number of training steps to be performed\n        \"\"\"\n        action_counter = 0\n        # for the BanditEnv example, the episode will always be 1.\n        # In general that's not the case, but for completeness\n        # we implemented a training loop that supports learning across many episodes.\n        episode_counter = 0\n        nb_steps_digits = len(str(nb_steps))\n\n        while action_counter < nb_steps:\n            env.reset()\n            done = False\n            episode_counter += 1\n            while not done and action_counter < nb_steps:\n                action = self._pick_an_action()\n                action_counter += 1\n                obs, reward, done, info, *_ = env.step(action)  # type: ignore\n                self._update_model(obs, reward, done, info, action)  # type: ignore\n                if action_counter % 10 == 0:\n                    print(\n                        (\n                            \"Step {:\"\n                            + str(nb_steps_digits)\n                            + \"}/{}, episode={}, action={:7}, reward={}\"\n                        ).format(\n                            action_counter,\n                            nb_steps,\n                            episode_counter,\n                            str(action),\n                            reward,  # type: ignore\n                        )\n                    )\n        env.close()\n"
  },
  {
    "path": "examples/gym_ex/train.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Training a multi armed bandit rl agent using the aea framework.\"\"\"\n\nimport argparse\n\nfrom gyms.env import BanditNArmedRandom  # noqa: I201\nfrom proxy.env import ProxyEnv  # noqa: I201\nfrom rl.agent import RLAgent  # noqa: I201\n\n\nDEFAULT_NB_GOODS = 10\nDEFAULT_NB_PRICES_PER_GOOD = 100\nDEFAULT_NB_STEPS = 4000\n\nparser = argparse.ArgumentParser(\"train\", description=\"Train an RL agent.\")\nparser.add_argument(\n    \"--nb-steps\",\n    type=int,\n    default=DEFAULT_NB_STEPS,\n    help=\"The number of training steps.\",\n)\nparser.add_argument(\n    \"--nb-goods\", type=int, default=DEFAULT_NB_GOODS, help=\"The number of goods.\"\n)\nparser.add_argument(\n    \"--nb-prices-per-good\",\n    type=int,\n    default=DEFAULT_NB_PRICES_PER_GOOD,\n    help=\"The number of prices per goods.\",\n)\n\n\nif __name__ == \"__main__\":\n    arguments = parser.parse_args()\n\n    # Use any gym.Env compatible environment:\n    gym_env = BanditNArmedRandom(\n        nb_bandits=arguments.nb_goods, nb_prices_per_bandit=arguments.nb_prices_per_good\n    )\n\n    # Pass the gym environment to a proxy environment:\n    proxy_env = ProxyEnv(gym_env)\n\n    # Use any RL agent compatible with the gym environment and call the fit method:\n    rl_agent = RLAgent(nb_goods=arguments.nb_goods)\n    rl_agent.fit(env=proxy_env, nb_steps=arguments.nb_steps)\n"
  },
  {
    "path": "examples/http_ex/petstore.yaml",
    "content": "openapi: \"3.0.0\"\ninfo:\n  version: 1.0.0\n  title: Swagger Petstore\n  license:\n    name: MIT\nservers:\n  - url: ''\npaths:\n  /pets:\n    get:\n      summary: List all pets\n      operationId: listPets\n      tags:\n        - pets\n      parameters:\n        - name: limit\n          in: query\n          description: How many items to return at one time (max 100)\n          required: false\n          schema:\n            type: integer\n            format: int32\n      responses:\n        '200':\n          description: A paged array of pets\n          headers:\n            x-next:\n              description: A link to the next page of responses\n              schema:\n                type: string\n          content:\n            application/json:\n              schema:\n                $ref: \"#/components/schemas/Pets\"\n        default:\n          description: unexpected error\n          content:\n            application/json:\n              schema:\n                $ref: \"#/components/schemas/Error\"\n    post:\n      summary: Create a pet\n      operationId: createPets\n      tags:\n        - pets\n      responses:\n        '201':\n          description: Null response\n        default:\n          description: unexpected error\n          content:\n            application/json:\n              schema:\n                $ref: \"#/components/schemas/Error\"\n  /pets/{petId}:\n    get:\n      summary: Info for a specific pet\n      operationId: showPetById\n      tags:\n        - pets\n      parameters:\n        - name: petId\n          in: path\n          required: true\n          description: The id of the pet to retrieve\n          schema:\n            type: string\n      responses:\n        '200':\n          description: Expected response to a valid request\n          content:\n            application/json:\n              schema:\n                $ref: \"#/components/schemas/Pet\"\n        default:\n          description: unexpected error\n          content:\n            application/json:\n              schema:\n                $ref: \"#/components/schemas/Error\"\ncomponents:\n  schemas:\n    Pet:\n      type: object\n      required:\n        - id\n        - name\n      properties:\n        id:\n          type: integer\n          format: int64\n        name:\n          type: string\n        tag:\n          type: string\n    Pets:\n      type: array\n      items:\n        $ref: \"#/components/schemas/Pet\"\n    Error:\n      type: object\n      required:\n        - code\n        - message\n      properties:\n        code:\n          type: integer\n          format: int32\n        message:\n          type: string\n"
  },
  {
    "path": "examples/ml_ex/model.json",
    "content": "{\"name\": \"my_model\", \"layers\": [{\"class_name\": \"InputLayer\", \"config\": {\"batch_input_shape\": [null, 28, 28], \"dtype\": \"float32\", \"sparse\": false, \"name\": \"pictures\"}, \"name\": \"pictures\", \"inbound_nodes\": []}, {\"class_name\": \"Dense\", \"config\": {\"name\": \"dense_1\", \"trainable\": true, \"dtype\": \"float32\", \"units\": 128, \"activation\": \"relu\", \"use_bias\": true, \"kernel_initializer\": {\"class_name\": \"GlorotUniform\", \"config\": {\"seed\": null}}, \"bias_initializer\": {\"class_name\": \"Zeros\", \"config\": {}}, \"kernel_regularizer\": null, \"bias_regularizer\": null, \"activity_regularizer\": null, \"kernel_constraint\": null, \"bias_constraint\": null}, \"name\": \"dense_1\", \"inbound_nodes\": [[[\"pictures\", 0, 0, {}]]]}, {\"class_name\": \"Dense\", \"config\": {\"name\": \"activations\", \"trainable\": true, \"dtype\": \"float32\", \"units\": 10, \"activation\": \"softmax\", \"use_bias\": true, \"kernel_initializer\": {\"class_name\": \"GlorotUniform\", \"config\": {\"seed\": null}}, \"bias_initializer\": {\"class_name\": \"Zeros\", \"config\": {}}, \"kernel_regularizer\": null, \"bias_regularizer\": null, \"activity_regularizer\": null, \"kernel_constraint\": null, \"bias_constraint\": null}, \"name\": \"activations\", \"inbound_nodes\": [[[\"dense_1\", 0, 0, {}]]]}], \"input_layers\": [[\"pictures\", 0, 0]], \"output_layers\": [[\"activations\", 0, 0]]}"
  },
  {
    "path": "examples/protocol_specification_ex/sample.yaml",
    "content": "---\nname: two_party_negotiation\nauthor: fetchai\nversion: 0.1.0\ndescription: An example of a protocol specification that describes a protocol for bilateral negotiation.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nprotocol_specification_id: fetchai/two_party_negotiation:0.1.0\nspeech_acts:\n  cfp:\n    query: ct:Query\n  propose:\n    price: pt:float\n    proposal: pt:dict[pt:str, pt:str]\n    conditions: pt:optional[pt:union[pt:str, pt:dict[pt:str,pt:str], pt:set[pt:str]]]\n    resources: pt:list[pt:bytes]\n  accept: {}\n  decline: {}\n...\n---\nct:Query: |\n  bytes query_bytes = 1;\n...\n---\ninitiation: [cfp]\nreply:\n  cfp: [propose, decline]\n  propose: [propose, accept, decline]\n  accept: []\n  decline: []\ntermination: [accept, decline]\nroles: {buyer, seller}\nend_states: [agreement_reached, agreement_unreached]\nkeep_terminal_state_dialogues: true\n..."
  },
  {
    "path": "examples/tac_deploy/.aea/cli_config.yaml",
    "content": "auth_token: <your-auth-token>\nauthor: <your-username>\nregistry_path: \"packages\"\n"
  },
  {
    "path": "examples/tac_deploy/Dockerfile",
    "content": "FROM python:3.8-alpine\n\nUSER root\n\nARG USE_CLIENT\nENV USE_CLIENT=$USE_CLIENT\n\nRUN apk add --no-cache make git bash\n\n# cryptography: https://cryptography.io/en/latest/installation/#alpine\nRUN apk add --no-cache gcc musl-dev python3-dev libffi-dev openssl-dev\n\n# https://stackoverflow.com/a/57485724\nRUN apk add --update --no-cache py3-numpy py3-scipy py3-pillow\nENV PYTHONPATH \"${PYTHONPATH}:/usr/lib/python3.8/site-packages\"\n\n# golang\nRUN apk add --no-cache go\n\n# aea installation\nRUN python -m pip install --upgrade pip\nRUN pip install --upgrade --force-reinstall aea[all]==1.1.1\n\n# directories and aea cli config\nCOPY /.aea /home/.aea\n\nWORKDIR /home/agents\nCOPY ./packages /home/agents/packages\n\n# aea build script\nCOPY /build.sh /build.sh\nRUN [\"chmod\", \"+x\", \"/build.sh\"]\nRUN [ \"/build.sh\" ]\n\n# optionally, specify any ports to expose here\n# EXPOSE 9000\n\n# aea entrypoint script\nCOPY /entrypoint.sh /entrypoint.sh\nRUN [\"chmod\", \"+x\", \"/entrypoint.sh\"]\nCMD [ \"/entrypoint.sh\" ]\n"
  },
  {
    "path": "examples/tac_deploy/README.md",
    "content": "# Tac Deployment image\n\nThe TAC deployment deploys one controller and `n` tac participants.\n\n## Build the image\n\nFirst, ensure the specifications in `.env` match your requirements.\n\nThen, to build the image run:\n\n``` bash\ndocker build -t tac-deploy -f Dockerfile . --no-cache\n```\n\n## Run locally\n\nSpecify preferred amount of tac participants agents in `.env` file, e.g.:\n\n``` bash\nPARTICIPANTS_AMOUNT=5\n```\n\nRun:\n\n``` bash\ndocker run --env-file .env -v \"$(pwd)/data:/data\" -ti tac-deploy\n```\n\n## Run in the cloud (here using GCloud)\n\nGCloud should be [configured](https://cloud.google.com/sdk/docs/initializing) first!\n\n### Push image\n\nTag the image first with the latest tag:\n\n``` bash\ndocker image tag tac-deploy gcr.io/fetch-ai-sandbox/tac_deploy:0.0.14\n```\n\nPush it to remote repo:\n\n``` bash\ndocker push gcr.io/fetch-ai-sandbox/tac_deploy:0.0.14\n```\n\n### Run it manually\n\nRun it\n\n``` bash\nkubectl run tac-deploy-{SOMETHING} --image=gcr.io/fetch-ai-sandbox/tac_deploy:0.0.13 --env=\"PARTICIPANTS_AMOUNT=5\" --attach\n```\n\nOr simply restart existing deployment and latest image will be used with default configurations (see below):\n\n``` bash\nkubectl delete pod tac-deploy-{SOMETHING}\n```\n\n### Manipulate container\n\nTo access the container run:\n\n``` bash\nkubectl exec tac-deploy-{SOMETHING} -ti -- /bin/sh\n```\n\nTo remove all logs and all keys:\n\n``` bash\ncd ../../data\nfind . -name \\*.log -type f -delete\nfind . -name \\*.txt -type f -delete\n```\n\n### Full deployment\n\nFirst, push the latest image, as per above.\n\nSecond, update the `tac-deployment.yaml` file with the correct image tag and configurations and then run:\n\n``` bash\nkubectl apply -f ./tac-deployment.yaml\n```\n\nCheck for pods list:\n\n``` bash\nkubectl get pods\n```\n\nTo fetch logs:\n\n``` bash\nkubectl cp tac-deploy-{SOMETHING}:/data ./output_dir\n```\n\nTo delete deployment:\n\n``` bash\nkubectl delete deployment tac-deploy\n```\n\n### Analysing Logs\n\nHandy commands to analyse logs:\n\n``` bash\ngrep -rl 'TAKE CARE! Circumventing controller identity check!' output_dir/ | sort\ngrep -rl 'TAKE CARE! Circumventing controller identity check!' output_dir/ | wc -l\ngrep -rnw 'SOEF Network Connection Error' output_dir/ |  wc -l\ngrep -rnw 'SOEF Server Bad Response Error' output_dir/ |  wc -l\ngrep -rnw ' Connection reset by peer' output_dir/ |  wc -l\ngrep -rnw 'Failure during pipe closing.' output_dir/ |  wc -l\ngrep -rnw \"Couldn't connect to libp2p process within timeout\" output_dir/ |  wc -l\ngrep -rnw 'Exception on connect:' output_dir/ |  wc -l\ngrep -rnw 'Exception' output_dir/ |  wc -l\ngrep -rnw 'connect to libp2p process within timeout' output_dir/ |  wc -l\ngrep -rnw 'handling valid transaction' output_dir/tac_controller/ | wc -l\ngrep -rnw 'received invalid tac message' output_dir/tac_controller/ | wc -l\n```\n"
  },
  {
    "path": "examples/tac_deploy/build.sh",
    "content": "#!/bin/bash\nset -e\n\nif [ -z \"$USE_CLIENT\" ];\nthen\n\tUSE_CLIENT=false\nfi\necho USE_CLIENT $USE_CLIENT\n\nif [ -z \"$PACKAGES_SOURCE\" ];\nthen\n\tPACKAGES_SOURCE=\"--remote\"\nfi\necho PACKAGES_SOURCE $PACKAGES_SOURCE\n\nmkdir /data\n\n# setup the agent\naea fetch $PACKAGES_SOURCE fetchai/tac_controller:latest\ncd tac_controller\nif [[ \"$USE_CLIENT\" == \"true\" ]]\nthen\n\taea remove connection fetchai/p2p_libp2p\n\taea add $PACKAGES_SOURCE connection fetchai/p2p_libp2p_client\n\taea config set agent.default_connection fetchai/p2p_libp2p_client:0.18.0\nfi\naea install\naea build\ncd ..\n\naea fetch $PACKAGES_SOURCE fetchai/tac_participant:latest --alias tac_participant_template\ncd tac_participant_template\nif [[ \"$USE_CLIENT\" == \"true\" ]]\nthen\n\taea remove connection fetchai/p2p_libp2p\n\taea add $PACKAGES_SOURCE connection fetchai/p2p_libp2p_client\n\taea config set agent.default_connection fetchai/p2p_libp2p_client:0.18.0\nfi\naea install\naea build\ncd ..\n\n"
  },
  {
    "path": "examples/tac_deploy/entrypoint.sh",
    "content": "#!/bin/bash\nset -e\n\nLEDGER=fetchai\nPEER=\"/dns4/acn.fetch.ai/tcp/9001/p2p/16Uiu2HAmVWnopQAqq4pniYLw44VRvYxBUoRHqjz1Hh2SoCyjbyRW\"\nTAC_NAME='v'$((10 + $RANDOM % 1000))\nTAC_SERVICE=tac_service_$TAC_NAME\nBASE_PORT=10000\nBASE_DIR=/data\nOLD_DIR=/$(date \"+%d_%m_%Y_%H%M\")\n\ncp -R \"$BASE_DIR\" \"$OLD_DIR\"\n\nif [ -z  \"$COMPETITION_TIMEOUT\" ];\nthen\n\tCOMPETITION_TIMEOUT=86400\nfi\necho COMPETITION_TIMEOUT $COMPETITION_TIMEOUT\n\nif [ -z  \"$INACTIVITY_TIMEOUT\" ];\nthen\n\tINACTIVITY_TIMEOUT=3600\nfi\necho INACTIVITY_TIMEOUT $INACTIVITY_TIMEOUT\n\nif [ -z  \"$PARTICIPANTS_AMOUNT\" ];\nthen\n\tPARTICIPANTS_AMOUNT=2\nfi\necho PARTICIPANTS_AMOUNT $PARTICIPANTS_AMOUNT\n\n\nif [ -z  \"$MINUTES_TILL_START\" ];\nthen\n\tMINUTES_TILL_START=2\nfi\necho MINUTES_TILL_START $MINUTES_TILL_START\n\nif [ -z  \"$SEARCH_INTERVAL_GAME\" ];\nthen\n\tSEARCH_INTERVAL_GAME=20\nfi\necho SEARCH_INTERVAL_GAME $SEARCH_INTERVAL_GAME\n\nif [ -z  \"$SEARCH_INTERVAL_TRADING\" ];\nthen\n\tSEARCH_INTERVAL_TRADING=600\nfi\necho SEARCH_INTERVAL_TRADING $SEARCH_INTERVAL_TRADING\n\nif [ -z  \"$CLEANUP_INTERVAL\" ];\nthen\n\tCLEANUP_INTERVAL=1800\nfi\necho CLEANUP_INTERVAL $CLEANUP_INTERVAL\n\nif [ -z  \"$NODE_CONNECTION_TIMEOUT\" ];\nthen\n\tNODE_CONNECTION_TIMEOUT=30\nfi\necho NODE_CONNECTION_TIMEOUT $NODE_CONNECTION_TIMEOUT\n\nif [ -z  \"$LOG_LEVEL\" ];\nthen\n\tLOG_LEVEL=INFO\nfi\necho LOG_LEVEL $LOG_LEVEL\n\nif [ -z  \"$CLEAR_LOG_DATA_ON_LAUNCH\" ];\nthen\n\tCLEAR_LOG_DATA_ON_LAUNCH=true\nfi\necho CLEAR_LOG_DATA_ON_LAUNCH $CLEAR_LOG_DATA_ON_LAUNCH\n\nif [ -z  \"$CLEAR_KEY_DATA_ON_LAUNCH\" ];\nthen\n\tCLEAR_KEY_DATA_ON_LAUNCH=false\nfi\necho CLEAR_KEY_DATA_ON_LAUNCH $CLEAR_KEY_DATA_ON_LAUNCH\n\nif [ \"$CLEAR_LOG_DATA_ON_LAUNCH\" == true ]; then\n\tfind \"$BASE_DIR\" -name \\*.log -type f -delete\nfi\n\nif [ \"$CLEAR_KEY_DATA_ON_LAUNCH\" == true ]; then\n\tfind \"$BASE_DIR\" -name \\*.txt -type f -delete\nfi\n\nif [ -z \"$USE_CLIENT\" ]; then\n\tUSE_CLIENT=false\nfi\n\nfunction generate_key (){\n\tledger=$1\n\tprefix=$2\n\tbase_dir=$3\n\tconnection=$4\n\tif [ $connection = '1' ];\n\tthen\n\t\tconnection='_connection'\n\telse\n\t\tconnection=''\n\tfi\n\tfilename=\"${base_dir}/${prefix}_${ledger}${connection}_private_key.txt\"\n\t\n\tif [ -e \"${filename}\" ];\n\tthen\n\t\techo > /dev/null\n\telse\n\t aea generate-key $ledger $filename $con_option\n\tfi\n\techo ${filename}\n}\n\nfunction set_agent(){\n\tname=$1\n\tport=$2\n\techo name $name port $port\n\tagent_data_dir=$BASE_DIR/$name\n\tmkdir -p $agent_data_dir\n\tkey_file_name=$(generate_key $LEDGER $name $agent_data_dir 0)\n\taea add-key fetchai $key_file_name\t\n\tkey_file_name=$(generate_key $LEDGER $name $agent_data_dir 1)\n\taea add-key fetchai $key_file_name --connection\n\tif [ \"$USE_CLIENT\" == \"false\" ];\n\tthen\n\t\tjson=$(printf '{\"log_file\": \"%s\", \"delegate_uri\": null, \"entry_peers\": [\"%s\"], \"local_uri\": \"127.0.0.1:%s\", \"public_uri\": null, \"node_connection_timeout\": '%i'}' \"$agent_data_dir/libp2p_node.log\" \"$PEER\" \"$port\" \"$(($NODE_CONNECTION_TIMEOUT))\")\n\t\taea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \"$json\"\n\tfi\n\taea issue-certificates\n\tlog_file=$agent_data_dir/$name.log\n\tjson=$(printf '{\"version\": 1, \"formatters\": {\"standard\": {\"format\": \"\"}}, \"handlers\": {\"console\": {\"class\": \"logging.StreamHandler\", \"formatter\": \"standard\", \"level\": \"%s\"}, \"file\": {\"class\": \"logging.FileHandler\", \"filename\": \"%s\", \"mode\": \"w\", \"level\": \"%s\", \"formatter\": \"standard\"}}, \"loggers\": {\"aea\": {\"level\": \"%s\", \"handlers\": [\"file\"]}}}' \"$LOG_LEVEL\" \"$log_file\" \"$LOG_LEVEL\" \"$LOG_LEVEL\")\n\taea config set --type dict agent.logging_config \"$json\"\n\taea config set agent.logging_config.formatters.standard.format '%(asctime)s [%(levelname)s]: %(message)s'\n\taea config set vendor.fetchai.connections.soef.config.token_storage_path $agent_data_dir/soef_token.txt\n\taea config set agent.skill_exception_policy just_log\n\taea config set agent.connection_exception_policy just_log\n}\n\nfunction set_tac_name (){\n\tjson=$(printf '{\"key\": \"tac\", \"value\": \"%s\"}' $TAC_NAME)\n\taea config set --type dict vendor.fetchai.skills.tac_control.models.parameters.args.service_data \"$json\"\n}\n\nfunction set_participant(){\n\tagent_id=$1\n\tagent_name=$2\n\techo \"cp -r tac_participant_template $agent_name\"\n\tcp -r tac_participant_template $agent_name\n\tcd $agent_name\n\t# cause set agent name is not allowed!\n\tsed -e \"s/tac_participant_template/$agent_name/\" -i ./aea-config.yaml\n\tset_agent $agent_name $(expr $BASE_PORT + $agent_id)\n\taea config set vendor.fetchai.skills.tac_negotiation.behaviours.clean_up.args.tick_interval $CLEANUP_INTERVAL\n\taea config set vendor.fetchai.skills.tac_negotiation.behaviours.tac_negotiation.args.search_interval $SEARCH_INTERVAL_TRADING\n\taea config set vendor.fetchai.skills.tac_negotiation.models.strategy.args.service_key $TAC_SERVICE\n\taea config set vendor.fetchai.skills.tac_participation.behaviours.tac_search.args.tick_interval $SEARCH_INTERVAL_GAME\n\taea config set vendor.fetchai.skills.tac_participation.models.game.args.search_query.search_value $TAC_NAME\n\tcd ..\n}\n\nagents_list=''\nfor i in $(seq $PARTICIPANTS_AMOUNT);\ndo\n\tagent_name=\"tac_participant_$i\"\n\tset_participant $i $agent_name\n\tagents_list=\"$agent_name $agents_list\"\ndone\n\ncd tac_controller\nset_agent tac_controller $BASE_PORT\nset_tac_name\ndatetime_start=$(date -d@\"$(( `date +%s`+$MINUTES_TILL_START*60))\" \"+%d %m %Y %H:%M\")\naea config set vendor.fetchai.skills.tac_control.models.parameters.args.registration_start_time \"$datetime_start\"\naea config set vendor.fetchai.skills.tac_control.models.parameters.args.competition_timeout $COMPETITION_TIMEOUT\naea config set vendor.fetchai.skills.tac_control.models.parameters.args.inactivity_timeout $INACTIVITY_TIMEOUT\ncd ..\n\necho \"Launching agents...\"\naea launch tac_controller $agents_list\n"
  },
  {
    "path": "examples/tac_deploy/packages/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Package registry for the AEA framework.\"\"\"\n"
  },
  {
    "path": "examples/tac_deploy/tac-deployment.yaml",
    "content": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: tac-deploy\nspec:\n  selector:\n    matchLabels:\n      app: tac-deploy\n  replicas: 1\n  template:\n    metadata:\n      labels:\n        app: tac-deploy\n      namespace: aea-research\n    spec:\n      nodeSelector:\n        # type: agent-test\n        kubernetes.io/os: linux\n      containers:\n      - name: tac-deploy-container\n        image: gcr.io/fetch-ai-sandbox/tac_deploy:0.0.14\n        resources:\n          requests:\n            memory: \"12000000Ki\"\n            cpu: \"3700m\"\n          limits:\n            memory: \"12000000Ki\"\n            cpu: \"3700m\"\n        env:\n         - name: PARTICIPANTS_AMOUNT\n           value: \"70\"\n         - name: MINUTES_TILL_START\n           value: \"10\"\n         - name: COMPETITION_TIMEOUT\n           value: \"86400\"\n         - name: INACTIVITY_TIMEOUT\n           value: \"3600\"\n         - name: SEARCH_INTERVAL_GAME\n           value: \"20\"\n         - name: SEARCH_INTERVAL_TRADING\n           value: \"600\"\n         - name: CLEANUP_INTERVAL\n           value: \"1800\"\n         - name: NODE_CONNECTION_TIMEOUT\n           value: \"30\"\n         - name: LOG_LEVEL\n           value: \"INFO\"\n         - name: CLEAR_LOG_DATA_ON_LAUNCH\n           value: \"true\"\n         - name: CLEAR_KEY_DATA_ON_LAUNCH\n           value: \"true\"\n         - name: USE_CLIENT\n           value: \"false\"\n        volumeMounts:\n         - name: tac-deploy-data-vol\n           mountPath: /data\n      volumes:\n      - name: tac-deploy-data-vol\n        persistentVolumeClaim:\n          claimName: tac-deploy-data-vol\n---\napiVersion: v1\nkind: PersistentVolumeClaim\nmetadata:\n  name: tac-deploy-data-vol\nspec:\n  accessModes:\n    - ReadWriteOnce\n  resources:\n    requests:\n      storage: 10Gi"
  },
  {
    "path": "examples/tac_deploy/tac_run.sh",
    "content": "#!/bin/bash -e\n\nminutes_to_start=$1\nparticipants=$2\nmode=$3\nregistry=$4\nacn_node=$5\nidentifier=$(python -c \"import uuid; print(uuid.uuid4().hex)\")\ntac_name=tac_$identifier\nPEER=\"\"\nagents=\"\"\nregistry_flag=\"--local\"\n\nhelp() {\necho \"\nUse tac_run.sh <minutes_to_start> <number_of_participants> [mode:noncontract,fetchai,ethereum] [registry:local,remote] [acn_node:local,public]\n\nminutes_to_start - int\nnumber_of_participants - int, min 2\nmode - which mode to run Tac in: noncontract, fetchai, ethereum. noncontract is the default\nregistry - local or remote, local is the default\nacn_node - local or public, local is the default\n\"\n exit 1;\n}\n\nfunction empty_lines {\necho \"\n\n\"\n}\n\nprint_options(){\nstart_time=$(date)\necho \"Starting Tac instance:\n\nStart time: ${start_time}\n\n* minutes_to_start - ${minutes_to_start}\n* number_of_participants - ${participants}\n* mode - ${mode}\n* registry - ${registry}\n* acn_node - ${acn_node}\n* tac_name(autogenerated) - ${tac_name}\n\n\n\"\n}\n\ncheck_options(){\n\tif [ -z \"$minutes_to_start\" ]; then\n\t\tminutes_to_start=1\n\tfi\n\t\n\tif [ -z \"$participants\" ]; then\n\t\tparticipants=2\n\tfi\n\t\n\tcase \"$registry\" in\n\t  local)\n        registry_flag=\"--local\"\n\t    ;;\n\t  remote)\n        registry_flag=\"--remote\"\n\t    ;;\n\t  \"\")\n\t  \tregistry=local\n\t  \tregistry_flag=\"--local\"\n\t    ;;\n\t  *)\n\t  \techo \"Incorrect registry!\"\n\t    help\n\t    ;;\n\tesac\n\t\n\t\n\tcase \"$acn_node\" in\n\t  local)\n\t     PEER=\"\"\n\t    ;;\n\t  public)\n\t     PEER=\"/dns4/acn.fetch.ai/tcp/9001/p2p/16Uiu2HAmVWnopQAqq4pniYLw44VRvYxBUoRHqjz1Hh2SoCyjbyRW\"\n\t    ;;\n\t  \"\")\n\t  \tacn_node=local\n\t  \tPEER=\"\"\n\t    ;;\n\t  *)\n\t    echo \"Incorrect acn node option!\"\n\t    help\n\t    ;;\n\tesac\n\t\n\tcase \"$mode\" in\n\t  fetchai|ethereum)\n\t  \tkey_type=$mode\n\t  \ttac_controller_name=\"tac_controller_contract\"\n\t  \ttac_controller_skill_name=\"tac_control_contract\"\n\t  \ttac_participant_name=\"tac_participant_contract\"\n\t    ;;\n\t  \"\"|noncontract)\n\t  \tkey_type=fetchai\n\t  \tmode=\"noncontract\"\n\t  \ttac_controller_name=\"tac_controller\"\n\t  \ttac_controller_skill_name=\"tac_control\"\n\t  \ttac_participant_name=\"tac_participant\"\n\t    ;;\n\t  *)\n\t    echo \"Incorrect mode option!\"\n\t    help\n\t    ;;\n\tesac\n}\n\ngenerate_keys(){\n\techo \"Generating ${key_type} keys...\"\n\taea generate-key $key_type\n\taea add-key $key_type ${key_type}_private_key.txt\n\taea config set agent.default_ledger ${key_type}\n\n\taea generate-key fetchai fetchai_connection_private_key.txt\n\taea add-key fetchai fetchai_connection_private_key.txt --connection\n\n\techo \"Keys are generated.\"\n}\nset_p2p_connection(){\n\tpeer=$1\n\tport=$2\n\tpublic_url=$3\n\tif [ -z \"$peer\" ]; then\n\t\t# no peer provided\n\t\tpeer=\n\telse\n\t\tpeer=\"\\\"$peer\\\"\"\n\tfi\n\n\tif [ -z \"$public_url\" ]; then\n\t\t# no peer provided\n\t\tpublic_url=null\n\telse\n\t\tpublic_url=\"\\\"$public_url\\\"\"\n\tfi\n\n\tjson=$(printf '{\"delegate_uri\": null, \"entry_peers\": [%s], \"local_uri\": \"127.0.0.1:1%0.4d\", \"public_uri\": %s}' \"$peer\" \"$port\" \"$public_url\")\n\taea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \"$json\"\n\taea config get vendor.fetchai.connections.p2p_libp2p.config\n\tjson=$(printf '[{\"identifier\": \"acn\", \"ledger_id\": \"%s\", \"not_after\": \"2030-01-01\", \"not_before\": \"2022-01-01\", \"public_key\": \"fetchai\", \"message_format\": \"{public_key}\", \"save_path\": \".certs/conn_cert.txt\"}]' \"$key_type\")\n\taea config set --type list vendor.fetchai.connections.p2p_libp2p.cert_requests \"$json\"\n}\n\nset_tac_name(){\n\techo \"Set tac name\"\n\tskill_name=$1\n\tjson=$(printf '{\"key\": \"tac\", \"value\": \"%s\"}' $tac_name)\n\taea config set --type dict vendor.fetchai.skills.$skill_name.models.parameters.args.service_data \"$json\"\n\taea config get vendor.fetchai.skills.$skill_name.models.parameters.args.service_data\n}\nset_aea(){\n\taea config set vendor.fetchai.connections.soef.config.chain_identifier ethereum\n\taea install\n\taea build\n\taea issue-certificates\n}\n\nset_PEER(){\n\tcase \"$acn_node\" in\n\t  public)\n\t  # do nothing\n\t    ;;\n\t  local)\n\t  \tPEER=`aea get-multiaddress fetchai -c -i fetchai/p2p_libp2p:0.27.5 -u public_uri`\n\t    ;;\n\tesac\n}\ncreate_controller(){\n\techo \"Creating controller...\"\n\n\trm -rf $tac_controller_name\n\taea fetch $registry_flag fetchai/$tac_controller_name:latest\n\n\tcd $tac_controller_name\n\n\tempty_lines\n\tgenerate_keys\n\n\tempty_lines\n\tset_p2p_connection \"$PEER\" \"0\" \"127.0.0.1:10000\"\n\n\tempty_lines\n\tset_tac_name \"$tac_controller_skill_name\"\n\t\n\tset_aea\t\n\tset_PEER\n\tcd ..\n}\n\ncreate_participants(){\n\tfor i in $(seq $participants);\n\tdo\n\t\tcreate_participant $i\n\tdone\n}\n\ncreate_participant(){\n\ti=$1\n\t\n\tagent=tac_participant_$i\n\tagents=$(echo $agent $agents)\n\trm -rf $agent\n\taea  fetch $registry_flag fetchai/${tac_participant_name}:latest --alias $agent\n\tcd $agent\n\t\n\tempty_lines\n\tgenerate_keys\n\n\tempty_lines\n\tset_p2p_connection \"$PEER\" \"$i\"\n\n\taea config set vendor.fetchai.skills.tac_participation.models.game.args.search_query.search_value $tac_name\n\taea config get vendor.fetchai.skills.tac_participation.models.game.args.search_query\n\t\t\n\tset_aea\t\n\tcd ..\n}\n\nset_tac_time(){\n\tempty_lines\n\ttime_diff=$(printf '+%sM' \"$minutes_to_start\")\n\tdatetime_now=$(date \"+%d %m %Y %H:%M\")\n\tdatetime_start=$([ \"$(uname)\" = Linux ] && date --date=\"$minutes_to_start minutes\" \"+%d %m %Y %H:%M\" ||date -v $time_diff \"+%d %m %Y %H:%M\")\n\techo \"Now:\" $datetime_now \"Start:\" $datetime_start\n\tcd $tac_controller_name\n\taea config set vendor.fetchai.skills.${tac_controller_skill_name}.models.parameters.args.registration_start_time \"$datetime_start\"\n\techo \"Start time set:\" $(aea config get vendor.fetchai.skills.${tac_controller_skill_name}.models.parameters.args.registration_start_time)\n\tcd ..\n}\n\ncreate_agents(){\n\tcreate_controller\n\tempty_lines\n\tcreate_participants\n\tempty_lines\n\tset_tac_time\n\techo \"agents created\"\n}\n\nrun_agents(){\n\tempty_lines\n\techo \"Use \\\"aea launch $tac_controller_name $agents\\\" to run agents\"\n}\n\n\n\ncheck_options\nprint_options\ncreate_agents\nrun_agents\n"
  },
  {
    "path": "firebase.json",
    "content": "{\n  \"hosting\": {\n    \"public\": \"site\",\n    \"ignore\": [\n      \"firebase.json\",\n      \"**/.*\",\n      \"**/node_modules/**\"\n    ]\n  }\n}\n"
  },
  {
    "path": "install_packages.py",
    "content": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"The install packages script\"\"\"\nimport re\nimport subprocess\nimport sys\nfrom pathlib import Path\nfrom typing import List\n\nfrom tomlkit import loads as loads_toml\n\n\ndef _load_groups():\n    data = loads_toml(Path(\"pyproject.toml\").read_text())\n    return list(data[\"tool\"][\"poetry\"][\"group\"].keys())\n\n\ndef _load_dependencies() -> List[str]:\n    groups = \",\".join(_load_groups())\n    text = subprocess.check_output(\n        f\"poetry export --with {groups}\", shell=True, text=True\n    )\n    text = text.replace(\"\\\\\\n\", \" \")\n    lines = text.splitlines()\n    lines = [i.split(\" \")[0] for i in lines]\n    return lines\n\n\nRE = re.compile(\"(.*)[=><]\")\n\nif __name__ == \"__main__\":\n    packages = sys.argv[1:]\n    requirements = _load_dependencies()\n\n    to_install = []\n    for package in packages:\n        for requirement in requirements:\n            if re.match(f\"^{package}([<>=].*)?$\", requirement):\n                to_install.append(requirement.strip())\n    if not to_install:\n        raise ValueError(\"No packages found to install\")\n    print(\"installing\", \", \".join(to_install))\n    subprocess.check_call([sys.executable, \"-m\", \"pip\", \"install\", *to_install])\n"
  },
  {
    "path": "libs/go/aea_end2end/Makefile",
    "content": "build:  main.go\n\tgo build\n"
  },
  {
    "path": "libs/go/aea_end2end/README.md",
    "content": "# End-to-end example Go <> Python\n\n## Run example\n\nEnsure all dependencies are installed: python, aea and Golang.\n\nTo launch the buyer agent run:\n`./run_buyer.sh`\n\nIn another terminal, to launch the seller agent run:\n`./run_seller.sh`\n\nAfter a while both agents get connected to the ACN, perform a `fetchai/fipa` message exchange and show `FIPA INTERACTION COMPLETE` in output logs.\n\nTerminate every agent with `ctrl+c`.\n\n## Generate protocol\n\nTo generate a protocol, use the following approach:\n\n``` bash\naea create temp_agent\ncd temp_agent\naea generate protocol -l PATH_TO_SPEC\n```\n"
  },
  {
    "path": "libs/go/aea_end2end/fipa_dummy_seller.env",
    "content": "export AEA_LEDGER_ID=\"fetchai\"\nexport AEA_ADDRESS=\"fetch1x9v67meyfq4pkgy2n2yf6797cfkul327kpclqr\"\nexport AEA_PUBLIC_KEY=\"02ac514ba70de60ed5c30f90e3acdfc958ecb416d9676706bf013228abfb2c2816\"\nexport AEA_PRIVATE_KEY=\"6d8d2b87d987641e2ca3f1991c1cccf08a118759e81fabdbf7e8484f27af015e\"\nexport AEA_P2P_POR_SERVICE_ID=\"acn\"\nexport AEA_P2P_POR_LEDGER_ID=\"fetchai\"\nexport AEA_P2P_POR_PEER_PUBKEY=\"0217a59bd805c310aca4febe0e99ce22ee3712ae085dc1e5630430b1e15a584bb7\"\nexport AEA_P2P_POR_SIGNATURE=\"avzHfL/fjMidvweJJKjtBUiqJ2+6aDUq8MoNRBi9nDI/lWleIX3ftRf6Sx5UWmxcS0SW03IVrf1iKTXA5zeA0g==\"\nexport AEA_P2P_DELEGATE_HOST=\"acn.fetch.ai\"\nexport AEA_P2P_DELEGATE_PORT=11000"
  },
  {
    "path": "libs/go/aea_end2end/go.mod",
    "content": "module seller_agent\n\ngo 1.14\n\nreplace aealite => ../aealite\n\nrequire (\n\taealite v0.0.0-00010101000000-000000000000\n\tgithub.com/golang/protobuf v1.4.2\n\tgithub.com/sirupsen/logrus v1.8.1\n\tgoogle.golang.org/protobuf v1.25.0\n)\n"
  },
  {
    "path": "libs/go/aea_end2end/go.sum",
    "content": "cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ngithub.com/AndreasBriese/bbloom v0.0.0-20180913140656-343706a395b7/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=\ngithub.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=\ngithub.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4=\ngithub.com/Azure/azure-pipeline-go v0.2.2/go.mod h1:4rQ/NZncSvGqNkkOsNpOU1tgoNuIlp9AfUH5G1tvCHc=\ngithub.com/Azure/azure-storage-blob-go v0.7.0/go.mod h1:f9YQKtsG1nMisotuTPpO0tjNuEjKRYAcJU8/ydDI++4=\ngithub.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI=\ngithub.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0=\ngithub.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc=\ngithub.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA=\ngithub.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g=\ngithub.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=\ngithub.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=\ngithub.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM=\ngithub.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc=\ngithub.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk=\ngithub.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=\ngithub.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=\ngithub.com/Kubuxu/go-os-helper v0.0.1/go.mod h1:N8B+I7vPCT80IcP58r50u4+gEEcsZETFUpAzWW2ep1Y=\ngithub.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=\ngithub.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=\ngithub.com/VictoriaMetrics/fastcache v1.5.7/go.mod h1:ptDBkNMQI4RtmVo8VS/XwRY6RoTu1dAWCbrk+6WsEM8=\ngithub.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=\ngithub.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=\ngithub.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=\ngithub.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM=\ngithub.com/aristanetworks/goarista v0.0.0-20170210015632-ea17b1a17847/go.mod h1:D/tb0zPVXnP7fmsLZjtdUhSsumbK/ij54UXjjVgMGxQ=\ngithub.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=\ngithub.com/aws/aws-sdk-go v1.25.48/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=\ngithub.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=\ngithub.com/btcsuite/btcd v0.0.0-20171128150713-2e60448ffcc6/go.mod h1:Dmm/EzmjnCiweXmzRIAiUWCInVmPgjkzgv5k4tVyXiQ=\ngithub.com/btcsuite/btcd v0.0.0-20190213025234-306aecffea32/go.mod h1:DrZx5ec/dmnfpw9KyYoQyYo7d0KEvTkk/5M/vbZjAr8=\ngithub.com/btcsuite/btcd v0.0.0-20190523000118-16327141da8c/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI=\ngithub.com/btcsuite/btcd v0.0.0-20190824003749-130ea5bddde3/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI=\ngithub.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=\ngithub.com/btcsuite/btcd v0.21.0-beta h1:At9hIZdJW0s9E/fAz28nrz6AmcNlSVucCH796ZteX1M=\ngithub.com/btcsuite/btcd v0.21.0-beta/go.mod h1:ZSWyehm27aAuS9bvkATT+Xte3hjHZ+MRgMY/8NJ7K94=\ngithub.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=\ngithub.com/btcsuite/btcutil v0.0.0-20190207003914-4c204d697803/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=\ngithub.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=\ngithub.com/btcsuite/btcutil v1.0.2 h1:9iZ1Terx9fMIOtq1VrwdqfsATL9MC2l8ZrUY6YZ2uts=\ngithub.com/btcsuite/btcutil v1.0.2/go.mod h1:j9HUFwoQRsZL3V4n+qG+CUnEGHOarIxfC3Le2Yhbcts=\ngithub.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg=\ngithub.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY=\ngithub.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I=\ngithub.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc=\ngithub.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc=\ngithub.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY=\ngithub.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs=\ngithub.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=\ngithub.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s=\ngithub.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=\ngithub.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=\ngithub.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=\ngithub.com/cloudflare/cloudflare-go v0.10.2-0.20190916151808-a80f83b9add9/go.mod h1:1MxXX1Ux4x6mqPmjkUgTP1CdXIBXKX7T+Jk9Gxrmx+U=\ngithub.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=\ngithub.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=\ngithub.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=\ngithub.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=\ngithub.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=\ngithub.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=\ngithub.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=\ngithub.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=\ngithub.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/davidlazar/go-crypto v0.0.0-20170701192655-dcfb0a7ac018/go.mod h1:rQYf4tfk5sSwFsnDg3qYaBxSjsD9S8+59vW0dKUgme4=\ngithub.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ=\ngithub.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218=\ngithub.com/dgraph-io/badger v1.5.5-0.20190226225317-8115aed38f8f/go.mod h1:VZxzAIRPHRVNRKRo6AXrX9BJegn6il06VMTZVJYCIjQ=\ngithub.com/dgraph-io/badger v1.6.0-rc1/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4=\ngithub.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4=\ngithub.com/dgraph-io/badger v1.6.1/go.mod h1:FRmFw3uxvcpa8zG3Rxs0th+hCLIuaQg8HlNV5bjgnuU=\ngithub.com/dgraph-io/ristretto v0.0.2/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E=\ngithub.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=\ngithub.com/dgryski/go-farm v0.0.0-20190104051053-3adb47b1fb0f/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=\ngithub.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=\ngithub.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=\ngithub.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=\ngithub.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=\ngithub.com/dop251/goja v0.0.0-20200721192441-a695b0cdd498/go.mod h1:Mw6PkjjMXWbTj+nnj4s3QPXq1jaT0s5pC0iFD4+BOAA=\ngithub.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=\ngithub.com/dvyukov/go-fuzz v0.0.0-20200318091601-be3528f3a813/go.mod h1:11Gm+ccJnvAhCNLlf5+cS9KjtbaD5I5zaZpFMsTHWTw=\ngithub.com/edsrzf/mmap-go v0.0.0-20160512033002-935e0e8a636c/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=\ngithub.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=\ngithub.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=\ngithub.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=\ngithub.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=\ngithub.com/ethereum/go-ethereum v1.9.25 h1:mMiw/zOOtCLdGLWfcekua0qPrJTe7FVIiHJ4IKNTfR0=\ngithub.com/ethereum/go-ethereum v1.9.25/go.mod h1:vMkFiYLHI4tgPw4k2j4MHKoovchFE8plZ0M9VMk4/oM=\ngithub.com/fatih/color v1.3.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=\ngithub.com/fjl/memsize v0.0.0-20180418122429-ca190fb6ffbc/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0=\ngithub.com/flynn/noise v0.0.0-20180327030543-2492fe189ae6/go.mod h1:1i71OnUq3iUe1ma7Lr6yG6/rjvM3emb6yoL7xLFzcVQ=\ngithub.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=\ngithub.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=\ngithub.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww=\ngithub.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98=\ngithub.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=\ngithub.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=\ngithub.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8=\ngithub.com/go-sourcemap/sourcemap v2.1.2+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg=\ngithub.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=\ngithub.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=\ngithub.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=\ngithub.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=\ngithub.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=\ngithub.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=\ngithub.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=\ngithub.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=\ngithub.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=\ngithub.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0=\ngithub.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=\ngithub.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=\ngithub.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=\ngithub.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=\ngithub.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=\ngithub.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=\ngithub.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=\ngithub.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=\ngithub.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=\ngithub.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=\ngithub.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=\ngithub.com/golang/snappy v0.0.3-0.20201103224600-674baa8c7fc3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=\ngithub.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=\ngithub.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=\ngithub.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=\ngithub.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=\ngithub.com/google/gopacket v1.1.17/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM=\ngithub.com/google/gopacket v1.1.18/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM=\ngithub.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=\ngithub.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/gorilla/websocket v1.4.1-0.20190629185528-ae1634f6a989/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=\ngithub.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=\ngithub.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=\ngithub.com/graph-gophers/graphql-go v0.0.0-20191115155744-f33e81362277/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc=\ngithub.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU=\ngithub.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48=\ngithub.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=\ngithub.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=\ngithub.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=\ngithub.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=\ngithub.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=\ngithub.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=\ngithub.com/holiman/uint256 v1.1.1/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw=\ngithub.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=\ngithub.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc=\ngithub.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o=\ngithub.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=\ngithub.com/influxdata/influxdb v1.2.3-0.20180221223340-01288bdb0883/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY=\ngithub.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM=\ngithub.com/ipfs/go-cid v0.0.2/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM=\ngithub.com/ipfs/go-cid v0.0.3/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM=\ngithub.com/ipfs/go-cid v0.0.4/go.mod h1:4LLaPOQwmk5z9LBgQnpkivrx8BJjUyGwTXCd5Xfj6+M=\ngithub.com/ipfs/go-cid v0.0.5/go.mod h1:plgt+Y5MnOey4vO4UlUazGqdbEXuFYitED67FexhXog=\ngithub.com/ipfs/go-cid v0.0.6/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I=\ngithub.com/ipfs/go-cid v0.0.7/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I=\ngithub.com/ipfs/go-datastore v0.0.1/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE=\ngithub.com/ipfs/go-datastore v0.1.0/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE=\ngithub.com/ipfs/go-datastore v0.1.1/go.mod h1:w38XXW9kVFNp57Zj5knbKWM2T+KOZCGDRVNdgPHtbHw=\ngithub.com/ipfs/go-datastore v0.4.0/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA=\ngithub.com/ipfs/go-datastore v0.4.1/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA=\ngithub.com/ipfs/go-datastore v0.4.4/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA=\ngithub.com/ipfs/go-datastore v0.4.5/go.mod h1:eXTcaaiN6uOlVCLS9GjJUJtlvJfM3xk23w3fyfrmmJs=\ngithub.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps=\ngithub.com/ipfs/go-ds-badger v0.0.2/go.mod h1:Y3QpeSFWQf6MopLTiZD+VT6IC1yZqaGmjvRcKeSGij8=\ngithub.com/ipfs/go-ds-badger v0.0.5/go.mod h1:g5AuuCGmr7efyzQhLL8MzwqcauPojGPUaHzfGTzuE3s=\ngithub.com/ipfs/go-ds-badger v0.0.7/go.mod h1:qt0/fWzZDoPW6jpQeqUjR5kBfhDNB65jd9YlmAvpQBk=\ngithub.com/ipfs/go-ds-badger v0.2.1/go.mod h1:Tx7l3aTph3FMFrRS838dcSJh+jjA7cX9DrGVwx/NOwE=\ngithub.com/ipfs/go-ds-badger v0.2.3/go.mod h1:pEYw0rgg3FIrywKKnL+Snr+w/LjJZVMTBRn4FS6UHUk=\ngithub.com/ipfs/go-ds-leveldb v0.0.1/go.mod h1:feO8V3kubwsEF22n0YRQCffeb79OOYIykR4L04tMOYc=\ngithub.com/ipfs/go-ds-leveldb v0.1.0/go.mod h1:hqAW8y4bwX5LWcCtku2rFNX3vjDZCy5LZCg+cSZvYb8=\ngithub.com/ipfs/go-ds-leveldb v0.4.1/go.mod h1:jpbku/YqBSsBc1qgME8BkWS4AxzF2cEu1Ii2r79Hh9s=\ngithub.com/ipfs/go-ds-leveldb v0.4.2/go.mod h1:jpbku/YqBSsBc1qgME8BkWS4AxzF2cEu1Ii2r79Hh9s=\ngithub.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw=\ngithub.com/ipfs/go-ipfs-util v0.0.1/go.mod h1:spsl5z8KUnrve+73pOhSVZND1SIxPW5RyBCNzQxlJBc=\ngithub.com/ipfs/go-ipfs-util v0.0.2/go.mod h1:CbPtkWJzjLdEcezDns2XYaehFVNXG9zrdrtMecczcsQ=\ngithub.com/ipfs/go-ipns v0.0.2/go.mod h1:WChil4e0/m9cIINWLxZe1Jtf77oz5L05rO2ei/uKJ5U=\ngithub.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM=\ngithub.com/ipfs/go-log v1.0.2/go.mod h1:1MNjMxe0u6xvJZgeqbJ8vdo2TKaGwZ1a0Bpza+sr2Sk=\ngithub.com/ipfs/go-log v1.0.3/go.mod h1:OsLySYkwIbiSUR/yBTdv1qPtcE4FW3WPWk/ewz9Ru+A=\ngithub.com/ipfs/go-log v1.0.4/go.mod h1:oDCg2FkjogeFOhqqb+N39l2RpTNPL6F/StPkB3kPgcs=\ngithub.com/ipfs/go-log/v2 v2.0.2/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBWFaa9+0=\ngithub.com/ipfs/go-log/v2 v2.0.3/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBWFaa9+0=\ngithub.com/ipfs/go-log/v2 v2.0.5/go.mod h1:eZs4Xt4ZUJQFM3DlanGhy7TkwwawCZcSByscwkWG+dw=\ngithub.com/ipfs/go-log/v2 v2.1.1/go.mod h1:2v2nsGfZsvvAJz13SyFzf9ObaqwHiHxsPLEHntrv9KM=\ngithub.com/jackpal/gateway v1.0.5/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA=\ngithub.com/jackpal/go-nat-pmp v1.0.1/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=\ngithub.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=\ngithub.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=\ngithub.com/jbenet/go-cienv v0.0.0-20150120210510-1bb1476777ec/go.mod h1:rGaEvXB4uRSZMmzKNLoXvTu1sfx+1kv/DojUlPrSZGs=\ngithub.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA=\ngithub.com/jbenet/go-temp-err-catcher v0.0.0-20150120210811-aac704a3f4f2/go.mod h1:8GXXJV31xl8whumTzdZsTt3RnUIiPqzkyf7mxToRCMs=\ngithub.com/jbenet/go-temp-err-catcher v0.1.0/go.mod h1:0kJRvmDZXNMIiJirNPEYfhpPwbGVtZVWC34vc5WLsDk=\ngithub.com/jbenet/goprocess v0.0.0-20160826012719-b497e2f366b8/go.mod h1:Ly/wlsjFq/qrU3Rar62tu1gASgGw6chQbSh/XgIIXCY=\ngithub.com/jbenet/goprocess v0.1.3/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4=\ngithub.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4=\ngithub.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e/go.mod h1:G1CVv03EnqU1wYL2dFwXxW2An0az9JTl/ZsqXQeBlkU=\ngithub.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=\ngithub.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=\ngithub.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=\ngithub.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=\ngithub.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=\ngithub.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=\ngithub.com/julienschmidt/httprouter v1.1.1-0.20170430222011-975b5c4c7c21/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=\ngithub.com/kami-zh/go-capturer v0.0.0-20171211120116-e492ea43421d/go.mod h1:P2viExyCEfeWGU259JnaQ34Inuec4R38JCyBx2edgD0=\ngithub.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU=\ngithub.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=\ngithub.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=\ngithub.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=\ngithub.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=\ngithub.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=\ngithub.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk=\ngithub.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=\ngithub.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=\ngithub.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=\ngithub.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=\ngithub.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=\ngithub.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=\ngithub.com/libp2p/go-addr-util v0.0.1/go.mod h1:4ac6O7n9rIAKB1dnd+s8IbbMXkt+oBpzX4/+RACcnlQ=\ngithub.com/libp2p/go-addr-util v0.0.2/go.mod h1:Ecd6Fb3yIuLzq4bD7VcywcVSBtefcAwnUISBM3WG15E=\ngithub.com/libp2p/go-buffer-pool v0.0.1/go.mod h1:xtyIz9PMobb13WaxR6Zo1Pd1zXJKYg0a8KiIvDp3TzQ=\ngithub.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoRZd1Vi32+RXyFM=\ngithub.com/libp2p/go-cidranger v1.1.0/go.mod h1:KWZTfSr+r9qEo9OkI9/SIEeAtw+NNoU0dXIXt15Okic=\ngithub.com/libp2p/go-conn-security-multistream v0.1.0/go.mod h1:aw6eD7LOsHEX7+2hJkDxw1MteijaVcI+/eP2/x3J1xc=\ngithub.com/libp2p/go-conn-security-multistream v0.2.0/go.mod h1:hZN4MjlNetKD3Rq5Jb/P5ohUnFLNzEAR4DLSzpn2QLU=\ngithub.com/libp2p/go-eventbus v0.1.0/go.mod h1:vROgu5cs5T7cv7POWlWxBaVLxfSegC5UGQf8A2eEmx4=\ngithub.com/libp2p/go-eventbus v0.2.1/go.mod h1:jc2S4SoEVPP48H9Wpzm5aiGwUCBMfGhVhhBjyhhCJs8=\ngithub.com/libp2p/go-flow-metrics v0.0.1/go.mod h1:Iv1GH0sG8DtYN3SVJ2eG221wMiNpZxBdp967ls1g+k8=\ngithub.com/libp2p/go-flow-metrics v0.0.2/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs=\ngithub.com/libp2p/go-flow-metrics v0.0.3/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs=\ngithub.com/libp2p/go-libp2p v0.6.1/go.mod h1:CTFnWXogryAHjXAKEbOf1OWY+VeAP3lDMZkfEI5sT54=\ngithub.com/libp2p/go-libp2p v0.7.0/go.mod h1:hZJf8txWeCduQRDC/WSqBGMxaTHCOYHt2xSU1ivxn0k=\ngithub.com/libp2p/go-libp2p v0.7.4/go.mod h1:oXsBlTLF1q7pxr+9w6lqzS1ILpyHsaBPniVO7zIHGMw=\ngithub.com/libp2p/go-libp2p v0.8.1/go.mod h1:QRNH9pwdbEBpx5DTJYg+qxcVaDMAz3Ee/qDKwXujH5o=\ngithub.com/libp2p/go-libp2p v0.12.0/go.mod h1:FpHZrfC1q7nA8jitvdjKBDF31hguaC676g/nT9PgQM0=\ngithub.com/libp2p/go-libp2p-asn-util v0.0.0-20200825225859-85005c6cf052/go.mod h1:nRMRTab+kZuk0LnKZpxhOVH/ndsdr2Nr//Zltc/vwgo=\ngithub.com/libp2p/go-libp2p-autonat v0.1.1/go.mod h1:OXqkeGOY2xJVWKAGV2inNF5aKN/djNA3fdpCWloIudE=\ngithub.com/libp2p/go-libp2p-autonat v0.2.0/go.mod h1:DX+9teU4pEEoZUqR1PiMlqliONQdNbfzE1C718tcViI=\ngithub.com/libp2p/go-libp2p-autonat v0.2.1/go.mod h1:MWtAhV5Ko1l6QBsHQNSuM6b1sRkXrpk0/LqCr+vCVxI=\ngithub.com/libp2p/go-libp2p-autonat v0.2.2/go.mod h1:HsM62HkqZmHR2k1xgX34WuWDzk/nBwNHoeyyT4IWV6A=\ngithub.com/libp2p/go-libp2p-autonat v0.4.0/go.mod h1:YxaJlpr81FhdOv3W3BTconZPfhaYivRdf53g+S2wobk=\ngithub.com/libp2p/go-libp2p-blankhost v0.1.1/go.mod h1:pf2fvdLJPsC1FsVrNP3DUUvMzUts2dsLLBEpo1vW1ro=\ngithub.com/libp2p/go-libp2p-blankhost v0.1.4/go.mod h1:oJF0saYsAXQCSfDq254GMNmLNz6ZTHTOvtF4ZydUvwU=\ngithub.com/libp2p/go-libp2p-blankhost v0.2.0/go.mod h1:eduNKXGTioTuQAUcZ5epXi9vMl+t4d8ugUBRQ4SqaNQ=\ngithub.com/libp2p/go-libp2p-circuit v0.1.4/go.mod h1:CY67BrEjKNDhdTk8UgBX1Y/H5c3xkAcs3gnksxY7osU=\ngithub.com/libp2p/go-libp2p-circuit v0.2.1/go.mod h1:BXPwYDN5A8z4OEY9sOfr2DUQMLQvKt/6oku45YUmjIo=\ngithub.com/libp2p/go-libp2p-circuit v0.4.0/go.mod h1:t/ktoFIUzM6uLQ+o1G6NuBl2ANhBKN9Bc8jRIk31MoA=\ngithub.com/libp2p/go-libp2p-core v0.0.1/go.mod h1:g/VxnTZ/1ygHxH3dKok7Vno1VfpvGcGip57wjTU4fco=\ngithub.com/libp2p/go-libp2p-core v0.0.4/go.mod h1:jyuCQP356gzfCFtRKyvAbNkyeuxb7OlyhWZ3nls5d2I=\ngithub.com/libp2p/go-libp2p-core v0.2.0/go.mod h1:X0eyB0Gy93v0DZtSYbEM7RnMChm9Uv3j7yRXjO77xSI=\ngithub.com/libp2p/go-libp2p-core v0.2.2/go.mod h1:8fcwTbsG2B+lTgRJ1ICZtiM5GWCWZVoVrLaDRvIRng0=\ngithub.com/libp2p/go-libp2p-core v0.2.4/go.mod h1:STh4fdfa5vDYr0/SzYYeqnt+E6KfEV5VxfIrm0bcI0g=\ngithub.com/libp2p/go-libp2p-core v0.2.5/go.mod h1:6+5zJmKhsf7yHn1RbmYDu08qDUpIUxGdqHuEZckmZOA=\ngithub.com/libp2p/go-libp2p-core v0.3.0/go.mod h1:ACp3DmS3/N64c2jDzcV429ukDpicbL6+TrrxANBjPGw=\ngithub.com/libp2p/go-libp2p-core v0.3.1/go.mod h1:thvWy0hvaSBhnVBaW37BvzgVV68OUhgJJLAa6almrII=\ngithub.com/libp2p/go-libp2p-core v0.4.0/go.mod h1:49XGI+kc38oGVwqSBhDEwytaAxgZasHhFfQKibzTls0=\ngithub.com/libp2p/go-libp2p-core v0.5.0/go.mod h1:49XGI+kc38oGVwqSBhDEwytaAxgZasHhFfQKibzTls0=\ngithub.com/libp2p/go-libp2p-core v0.5.1/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y=\ngithub.com/libp2p/go-libp2p-core v0.5.3/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y=\ngithub.com/libp2p/go-libp2p-core v0.5.4/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y=\ngithub.com/libp2p/go-libp2p-core v0.5.5/go.mod h1:vj3awlOr9+GMZJFH9s4mpt9RHHgGqeHCopzbYKZdRjM=\ngithub.com/libp2p/go-libp2p-core v0.5.6/go.mod h1:txwbVEhHEXikXn9gfC7/UDDw7rkxuX0bJvM49Ykaswo=\ngithub.com/libp2p/go-libp2p-core v0.5.7/go.mod h1:txwbVEhHEXikXn9gfC7/UDDw7rkxuX0bJvM49Ykaswo=\ngithub.com/libp2p/go-libp2p-core v0.6.0/go.mod h1:txwbVEhHEXikXn9gfC7/UDDw7rkxuX0bJvM49Ykaswo=\ngithub.com/libp2p/go-libp2p-core v0.6.1/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8=\ngithub.com/libp2p/go-libp2p-core v0.7.0/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8=\ngithub.com/libp2p/go-libp2p-core v0.8.5 h1:aEgbIcPGsKy6zYcC+5AJivYFedhYa4sW7mIpWpUaLKw=\ngithub.com/libp2p/go-libp2p-core v0.8.5/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8=\ngithub.com/libp2p/go-libp2p-crypto v0.1.0/go.mod h1:sPUokVISZiy+nNuTTH/TY+leRSxnFj/2GLjtOTW90hI=\ngithub.com/libp2p/go-libp2p-discovery v0.2.0/go.mod h1:s4VGaxYMbw4+4+tsoQTqh7wfxg97AEdo4GYBt6BadWg=\ngithub.com/libp2p/go-libp2p-discovery v0.3.0/go.mod h1:o03drFnz9BVAZdzC/QUQ+NeQOu38Fu7LJGEOK2gQltw=\ngithub.com/libp2p/go-libp2p-discovery v0.5.0/go.mod h1:+srtPIU9gDaBNu//UHvcdliKBIcr4SfDcm0/PfPJLug=\ngithub.com/libp2p/go-libp2p-kad-dht v0.11.1/go.mod h1:5ojtR2acDPqh/jXf5orWy8YGb8bHQDS+qeDcoscL/PI=\ngithub.com/libp2p/go-libp2p-kbucket v0.4.7/go.mod h1:XyVo99AfQH0foSf176k4jY1xUJ2+jUJIZCSDm7r2YKk=\ngithub.com/libp2p/go-libp2p-loggables v0.1.0/go.mod h1:EyumB2Y6PrYjr55Q3/tiJ/o3xoDasoRYM7nOzEpoa90=\ngithub.com/libp2p/go-libp2p-mplex v0.2.0/go.mod h1:Ejl9IyjvXJ0T9iqUTE1jpYATQ9NM3g+OtR+EMMODbKo=\ngithub.com/libp2p/go-libp2p-mplex v0.2.1/go.mod h1:SC99Rxs8Vuzrf/6WhmH41kNn13TiYdAWNYHrwImKLnE=\ngithub.com/libp2p/go-libp2p-mplex v0.2.2/go.mod h1:74S9eum0tVQdAfFiKxAyKzNdSuLqw5oadDq7+L/FELo=\ngithub.com/libp2p/go-libp2p-mplex v0.2.3/go.mod h1:CK3p2+9qH9x+7ER/gWWDYJ3QW5ZxWDkm+dVvjfuG3ek=\ngithub.com/libp2p/go-libp2p-mplex v0.3.0/go.mod h1:l9QWxRbbb5/hQMECEb908GbS9Sm2UAR2KFZKUJEynEs=\ngithub.com/libp2p/go-libp2p-nat v0.0.5/go.mod h1:1qubaE5bTZMJE+E/uu2URroMbzdubFz1ChgiN79yKPE=\ngithub.com/libp2p/go-libp2p-nat v0.0.6/go.mod h1:iV59LVhB3IkFvS6S6sauVTSOrNEANnINbI/fkaLimiw=\ngithub.com/libp2p/go-libp2p-netutil v0.1.0/go.mod h1:3Qv/aDqtMLTUyQeundkKsA+YCThNdbQD54k3TqjpbFU=\ngithub.com/libp2p/go-libp2p-noise v0.1.1/go.mod h1:QDFLdKX7nluB7DEnlVPbz7xlLHdwHFA9HiohJRr3vwM=\ngithub.com/libp2p/go-libp2p-peer v0.2.0/go.mod h1:RCffaCvUyW2CJmG2gAWVqwePwW7JMgxjsHm7+J5kjWY=\ngithub.com/libp2p/go-libp2p-peerstore v0.1.0/go.mod h1:2CeHkQsr8svp4fZ+Oi9ykN1HBb6u0MOvdJ7YIsmcwtY=\ngithub.com/libp2p/go-libp2p-peerstore v0.1.3/go.mod h1:BJ9sHlm59/80oSkpWgr1MyY1ciXAXV397W6h1GH/uKI=\ngithub.com/libp2p/go-libp2p-peerstore v0.1.4/go.mod h1:+4BDbDiiKf4PzpANZDAT+knVdLxvqh7hXOujessqdzs=\ngithub.com/libp2p/go-libp2p-peerstore v0.2.0/go.mod h1:N2l3eVIeAitSg3Pi2ipSrJYnqhVnMNQZo9nkSCuAbnQ=\ngithub.com/libp2p/go-libp2p-peerstore v0.2.1/go.mod h1:NQxhNjWxf1d4w6PihR8btWIRjwRLBr4TYKfNgrUkOPA=\ngithub.com/libp2p/go-libp2p-peerstore v0.2.2/go.mod h1:NQxhNjWxf1d4w6PihR8btWIRjwRLBr4TYKfNgrUkOPA=\ngithub.com/libp2p/go-libp2p-peerstore v0.2.6/go.mod h1:ss/TWTgHZTMpsU/oKVVPQCGuDHItOpf2W8RxAi50P2s=\ngithub.com/libp2p/go-libp2p-pnet v0.2.0/go.mod h1:Qqvq6JH/oMZGwqs3N1Fqhv8NVhrdYcO0BW4wssv21LA=\ngithub.com/libp2p/go-libp2p-record v0.1.2/go.mod h1:pal0eNcT5nqZaTV7UGhqeGqxFgGdsU/9W//C8dqjQDk=\ngithub.com/libp2p/go-libp2p-record v0.1.3/go.mod h1:yNUff/adKIfPnYQXgp6FQmNu3gLJ6EMg7+/vv2+9pY4=\ngithub.com/libp2p/go-libp2p-routing-helpers v0.2.3/go.mod h1:795bh+9YeoFl99rMASoiVgHdi5bjack0N1+AFAdbvBw=\ngithub.com/libp2p/go-libp2p-secio v0.1.0/go.mod h1:tMJo2w7h3+wN4pgU2LSYeiKPrfqBgkOsdiKK77hE7c8=\ngithub.com/libp2p/go-libp2p-secio v0.2.0/go.mod h1:2JdZepB8J5V9mBp79BmwsaPQhRPNN2NrnB2lKQcdy6g=\ngithub.com/libp2p/go-libp2p-secio v0.2.1/go.mod h1:cWtZpILJqkqrSkiYcDBh5lA3wbT2Q+hz3rJQq3iftD8=\ngithub.com/libp2p/go-libp2p-secio v0.2.2/go.mod h1:wP3bS+m5AUnFA+OFO7Er03uO1mncHG0uVwGrwvjYlNY=\ngithub.com/libp2p/go-libp2p-swarm v0.1.0/go.mod h1:wQVsCdjsuZoc730CgOvh5ox6K8evllckjebkdiY5ta4=\ngithub.com/libp2p/go-libp2p-swarm v0.2.2/go.mod h1:fvmtQ0T1nErXym1/aa1uJEyN7JzaTNyBcHImCxRpPKU=\ngithub.com/libp2p/go-libp2p-swarm v0.2.3/go.mod h1:P2VO/EpxRyDxtChXz/VPVXyTnszHvokHKRhfkEgFKNM=\ngithub.com/libp2p/go-libp2p-swarm v0.2.8/go.mod h1:JQKMGSth4SMqonruY0a8yjlPVIkb0mdNSwckW7OYziM=\ngithub.com/libp2p/go-libp2p-swarm v0.3.0/go.mod h1:hdv95GWCTmzkgeJpP+GK/9D9puJegb7H57B5hWQR5Kk=\ngithub.com/libp2p/go-libp2p-swarm v0.3.1/go.mod h1:hdv95GWCTmzkgeJpP+GK/9D9puJegb7H57B5hWQR5Kk=\ngithub.com/libp2p/go-libp2p-testing v0.0.2/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E=\ngithub.com/libp2p/go-libp2p-testing v0.0.3/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E=\ngithub.com/libp2p/go-libp2p-testing v0.0.4/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E=\ngithub.com/libp2p/go-libp2p-testing v0.1.0/go.mod h1:xaZWMJrPUM5GlDBxCeGUi7kI4eqnjVyavGroI2nxEM0=\ngithub.com/libp2p/go-libp2p-testing v0.1.1/go.mod h1:xaZWMJrPUM5GlDBxCeGUi7kI4eqnjVyavGroI2nxEM0=\ngithub.com/libp2p/go-libp2p-testing v0.1.2-0.20200422005655-8775583591d8/go.mod h1:Qy8sAncLKpwXtS2dSnDOP8ktexIAHKu+J+pnZOFZLTc=\ngithub.com/libp2p/go-libp2p-testing v0.3.0/go.mod h1:efZkql4UZ7OVsEfaxNHZPzIehtsBXMrXnCfJIgDti5g=\ngithub.com/libp2p/go-libp2p-tls v0.1.3/go.mod h1:wZfuewxOndz5RTnCAxFliGjvYSDA40sKitV4c50uI1M=\ngithub.com/libp2p/go-libp2p-transport-upgrader v0.1.1/go.mod h1:IEtA6or8JUbsV07qPW4r01GnTenLW4oi3lOPbUMGJJA=\ngithub.com/libp2p/go-libp2p-transport-upgrader v0.2.0/go.mod h1:mQcrHj4asu6ArfSoMuyojOdjx73Q47cYD7s5+gZOlns=\ngithub.com/libp2p/go-libp2p-transport-upgrader v0.3.0/go.mod h1:i+SKzbRnvXdVbU3D1dwydnTmKRPXiAR/fyvi1dXuL4o=\ngithub.com/libp2p/go-libp2p-yamux v0.2.0/go.mod h1:Db2gU+XfLpm6E4rG5uGCFX6uXA8MEXOxFcRoXUODaK8=\ngithub.com/libp2p/go-libp2p-yamux v0.2.2/go.mod h1:lIohaR0pT6mOt0AZ0L2dFze9hds9Req3OfS+B+dv4qw=\ngithub.com/libp2p/go-libp2p-yamux v0.2.5/go.mod h1:Zpgj6arbyQrmZ3wxSZxfBmbdnWtbZ48OpsfmQVTErwA=\ngithub.com/libp2p/go-libp2p-yamux v0.2.7/go.mod h1:X28ENrBMU/nm4I3Nx4sZ4dgjZ6VhLEn0XhIoZ5viCwU=\ngithub.com/libp2p/go-libp2p-yamux v0.2.8/go.mod h1:/t6tDqeuZf0INZMTgd0WxIRbtK2EzI2h7HbFm9eAKI4=\ngithub.com/libp2p/go-libp2p-yamux v0.4.0/go.mod h1:+DWDjtFMzoAwYLVkNZftoucn7PelNoy5nm3tZ3/Zw30=\ngithub.com/libp2p/go-maddr-filter v0.0.4/go.mod h1:6eT12kSQMA9x2pvFQa+xesMKUBlj9VImZbj3B9FBH/Q=\ngithub.com/libp2p/go-maddr-filter v0.0.5/go.mod h1:Jk+36PMfIqCJhAnaASRH83bdAvfDRp/w6ENFaC9bG+M=\ngithub.com/libp2p/go-maddr-filter v0.1.0/go.mod h1:VzZhTXkMucEGGEOSKddrwGiOv0tUhgnKqNEmIAz/bPU=\ngithub.com/libp2p/go-mplex v0.0.3/go.mod h1:pK5yMLmOoBR1pNCqDlA2GQrdAVTMkqFalaTWe7l4Yd0=\ngithub.com/libp2p/go-mplex v0.1.0/go.mod h1:SXgmdki2kwCUlCCbfGLEgHjC4pFqhTp0ZoV6aiKgxDU=\ngithub.com/libp2p/go-mplex v0.1.1/go.mod h1:Xgz2RDCi3co0LeZfgjm4OgUF15+sVR8SRcu3SFXI1lk=\ngithub.com/libp2p/go-mplex v0.1.2/go.mod h1:Xgz2RDCi3co0LeZfgjm4OgUF15+sVR8SRcu3SFXI1lk=\ngithub.com/libp2p/go-mplex v0.2.0/go.mod h1:0Oy/A9PQlwBytDRp4wSkFnzHYDKcpLot35JQ6msjvYQ=\ngithub.com/libp2p/go-msgio v0.0.2/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ=\ngithub.com/libp2p/go-msgio v0.0.4/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ=\ngithub.com/libp2p/go-msgio v0.0.6/go.mod h1:4ecVB6d9f4BDSL5fqvPiC4A3KivjWn+Venn/1ALLMWA=\ngithub.com/libp2p/go-nat v0.0.4/go.mod h1:Nmw50VAvKuk38jUBcmNh6p9lUJLoODbJRvYAa/+KSDo=\ngithub.com/libp2p/go-nat v0.0.5/go.mod h1:B7NxsVNPZmRLvMOwiEO1scOSyjA56zxYAGv1yQgRkEU=\ngithub.com/libp2p/go-netroute v0.1.2/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk=\ngithub.com/libp2p/go-netroute v0.1.3/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk=\ngithub.com/libp2p/go-openssl v0.0.2/go.mod h1:v8Zw2ijCSWBQi8Pq5GAixw6DbFfa9u6VIYDXnvOXkc0=\ngithub.com/libp2p/go-openssl v0.0.3/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc=\ngithub.com/libp2p/go-openssl v0.0.4/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc=\ngithub.com/libp2p/go-openssl v0.0.5/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc=\ngithub.com/libp2p/go-openssl v0.0.7/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc=\ngithub.com/libp2p/go-reuseport v0.0.1/go.mod h1:jn6RmB1ufnQwl0Q1f+YxAj8isJgDCQzaaxIFYDhcYEA=\ngithub.com/libp2p/go-reuseport v0.0.2/go.mod h1:SPD+5RwGC7rcnzngoYC86GjPzjSywuQyMVAheVBD9nQ=\ngithub.com/libp2p/go-reuseport-transport v0.0.2/go.mod h1:YkbSDrvjUVDL6b8XqriyA20obEtsW9BLkuOUyQAOCbs=\ngithub.com/libp2p/go-reuseport-transport v0.0.3/go.mod h1:Spv+MPft1exxARzP2Sruj2Wb5JSyHNncjf1Oi2dEbzM=\ngithub.com/libp2p/go-reuseport-transport v0.0.4/go.mod h1:trPa7r/7TJK/d+0hdBLOCGvpQQVOU74OXbNCIMkufGw=\ngithub.com/libp2p/go-sockaddr v0.0.2/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k=\ngithub.com/libp2p/go-stream-muxer v0.0.1/go.mod h1:bAo8x7YkSpadMTbtTaxGVHWUQsR/l5MEaHbKaliuT14=\ngithub.com/libp2p/go-stream-muxer-multistream v0.2.0/go.mod h1:j9eyPol/LLRqT+GPLSxvimPhNph4sfYfMoDPd7HkzIc=\ngithub.com/libp2p/go-stream-muxer-multistream v0.3.0/go.mod h1:yDh8abSIzmZtqtOt64gFJUXEryejzNb0lisTt+fAMJA=\ngithub.com/libp2p/go-tcp-transport v0.1.0/go.mod h1:oJ8I5VXryj493DEJ7OsBieu8fcg2nHGctwtInJVpipc=\ngithub.com/libp2p/go-tcp-transport v0.1.1/go.mod h1:3HzGvLbx6etZjnFlERyakbaYPdfjg2pWP97dFZworkY=\ngithub.com/libp2p/go-tcp-transport v0.2.0/go.mod h1:vX2U0CnWimU4h0SGSEsg++AzvBcroCGYw28kh94oLe0=\ngithub.com/libp2p/go-tcp-transport v0.2.1/go.mod h1:zskiJ70MEfWz2MKxvFB/Pv+tPIB1PpPUrHIWQ8aFw7M=\ngithub.com/libp2p/go-ws-transport v0.2.0/go.mod h1:9BHJz/4Q5A9ludYWKoGCFC5gUElzlHoKzu0yY9p/klM=\ngithub.com/libp2p/go-ws-transport v0.3.0/go.mod h1:bpgTJmRZAvVHrgHybCVyqoBmyLQ1fiZuEaBYusP5zsk=\ngithub.com/libp2p/go-ws-transport v0.3.1/go.mod h1:bpgTJmRZAvVHrgHybCVyqoBmyLQ1fiZuEaBYusP5zsk=\ngithub.com/libp2p/go-yamux v1.2.2/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow=\ngithub.com/libp2p/go-yamux v1.3.0/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow=\ngithub.com/libp2p/go-yamux v1.3.3/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow=\ngithub.com/libp2p/go-yamux v1.3.5/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow=\ngithub.com/libp2p/go-yamux v1.3.7/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/hkmpooHE=\ngithub.com/libp2p/go-yamux v1.4.0/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/hkmpooHE=\ngithub.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=\ngithub.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=\ngithub.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=\ngithub.com/mattn/go-colorable v0.1.0/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=\ngithub.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=\ngithub.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc=\ngithub.com/mattn/go-ieproxy v0.0.0-20190702010315-6dee0af9227d/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc=\ngithub.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=\ngithub.com/mattn/go-isatty v0.0.5-0.20180830101745-3fb116b82035/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=\ngithub.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=\ngithub.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=\ngithub.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=\ngithub.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=\ngithub.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=\ngithub.com/miekg/dns v1.1.12/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=\ngithub.com/miekg/dns v1.1.28/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=\ngithub.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=\ngithub.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ=\ngithub.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U=\ngithub.com/minio/sha256-simd v0.0.0-20190328051042-05b4dd3047e5/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U=\ngithub.com/minio/sha256-simd v0.1.0/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U=\ngithub.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=\ngithub.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU=\ngithub.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=\ngithub.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=\ngithub.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=\ngithub.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8=\ngithub.com/mr-tron/base58 v1.1.1/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8=\ngithub.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=\ngithub.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=\ngithub.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=\ngithub.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA=\ngithub.com/multiformats/go-base36 v0.1.0/go.mod h1:kFGE83c6s80PklsHO9sRn2NCoffoRdUUOENyW/Vv6sM=\ngithub.com/multiformats/go-multiaddr v0.0.1/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44=\ngithub.com/multiformats/go-multiaddr v0.0.2/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44=\ngithub.com/multiformats/go-multiaddr v0.0.4/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44=\ngithub.com/multiformats/go-multiaddr v0.1.0/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44=\ngithub.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo=\ngithub.com/multiformats/go-multiaddr v0.2.0/go.mod h1:0nO36NvPpyV4QzvTLi/lafl2y95ncPj0vFwVF6k6wJ4=\ngithub.com/multiformats/go-multiaddr v0.2.1/go.mod h1:s/Apk6IyxfvMjDafnhJgJ3/46z7tZ04iMk5wP4QMGGE=\ngithub.com/multiformats/go-multiaddr v0.2.2/go.mod h1:NtfXiOtHvghW9KojvtySjH5y0u0xW5UouOmQQrn6a3Y=\ngithub.com/multiformats/go-multiaddr v0.3.0/go.mod h1:dF9kph9wfJ+3VLAaeBqo9Of8x4fJxp6ggJGteB8HQTI=\ngithub.com/multiformats/go-multiaddr v0.3.1/go.mod h1:uPbspcUPd5AfaP6ql3ujFY+QWzmBD8uLLL4bXW0XfGc=\ngithub.com/multiformats/go-multiaddr-dns v0.0.1/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q=\ngithub.com/multiformats/go-multiaddr-dns v0.0.2/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q=\ngithub.com/multiformats/go-multiaddr-dns v0.2.0/go.mod h1:TJ5pr5bBO7Y1B18djPuRsVkduhQH2YqYSbxWJzYGdK0=\ngithub.com/multiformats/go-multiaddr-fmt v0.0.1/go.mod h1:aBYjqL4T/7j4Qx+R73XSv/8JsgnRFlf0w2KGLCmXl3Q=\ngithub.com/multiformats/go-multiaddr-fmt v0.1.0/go.mod h1:hGtDIW4PU4BqJ50gW2quDuPVjyWNZxToGUh/HwTZYJo=\ngithub.com/multiformats/go-multiaddr-net v0.0.1/go.mod h1:nw6HSxNmCIQH27XPGBuX+d1tnvM7ihcFwHMSstNAVUU=\ngithub.com/multiformats/go-multiaddr-net v0.1.0/go.mod h1:5JNbcfBOP4dnhoZOv10JJVkJO0pCCEf8mTnipAo2UZQ=\ngithub.com/multiformats/go-multiaddr-net v0.1.1/go.mod h1:5JNbcfBOP4dnhoZOv10JJVkJO0pCCEf8mTnipAo2UZQ=\ngithub.com/multiformats/go-multiaddr-net v0.1.2/go.mod h1:QsWt3XK/3hwvNxZJp92iMQKME1qHfpYmyIjFVsSOY6Y=\ngithub.com/multiformats/go-multiaddr-net v0.1.3/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA=\ngithub.com/multiformats/go-multiaddr-net v0.1.4/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA=\ngithub.com/multiformats/go-multiaddr-net v0.1.5/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA=\ngithub.com/multiformats/go-multiaddr-net v0.2.0/go.mod h1:gGdH3UXny6U3cKKYCvpXI5rnK7YaOIEOPVDI9tsJbEA=\ngithub.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs=\ngithub.com/multiformats/go-multibase v0.0.3/go.mod h1:5+1R4eQrT3PkYZ24C3W2Ue2tPwIdYQD509ZjSb5y9Oc=\ngithub.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U=\ngithub.com/multiformats/go-multihash v0.0.5/go.mod h1:lt/HCbqlQwlPBz7lv0sQCdtfcMtlJvakRUn/0Ual8po=\ngithub.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew=\ngithub.com/multiformats/go-multihash v0.0.9/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew=\ngithub.com/multiformats/go-multihash v0.0.10/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew=\ngithub.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc=\ngithub.com/multiformats/go-multihash v0.0.14/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc=\ngithub.com/multiformats/go-multistream v0.1.0/go.mod h1:fJTiDfXJVmItycydCnNx4+wSzZ5NwG2FEVAI30fiovg=\ngithub.com/multiformats/go-multistream v0.1.1/go.mod h1:KmHZ40hzVxiaiwlj3MEbYgK9JFk2/9UktWZAF54Du38=\ngithub.com/multiformats/go-multistream v0.2.0/go.mod h1:5GZPQZbkWOLOn3J2y4Y99vVW7vOfsAflxARk3x14o6k=\ngithub.com/multiformats/go-varint v0.0.1/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=\ngithub.com/multiformats/go-varint v0.0.2/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=\ngithub.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=\ngithub.com/multiformats/go-varint v0.0.6/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=\ngithub.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0=\ngithub.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E=\ngithub.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=\ngithub.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=\ngithub.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=\ngithub.com/olekukonko/tablewriter v0.0.2-0.20190409134802-7e037d187b0c/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=\ngithub.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=\ngithub.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=\ngithub.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=\ngithub.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg=\ngithub.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=\ngithub.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=\ngithub.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=\ngithub.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=\ngithub.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=\ngithub.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=\ngithub.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=\ngithub.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=\ngithub.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=\ngithub.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=\ngithub.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=\ngithub.com/pborman/uuid v0.0.0-20170112150404-1b00554d8222/go.mod h1:VyrYX9gd7irzKovcSS6BIIEwPRkP2Wm2m9ufcdFSJ34=\ngithub.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=\ngithub.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0=\ngithub.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=\ngithub.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=\ngithub.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=\ngithub.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=\ngithub.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=\ngithub.com/prometheus/tsdb v0.6.2-0.20190402121629-4f204dcbc150/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=\ngithub.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho=\ngithub.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=\ngithub.com/rs/cors v0.0.0-20160617231935-a62a804a8a00/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=\ngithub.com/rs/xhandler v0.0.0-20160618193221-ed27b6fd6521/go.mod h1:RvLn4FgxWubrpZHtQLnOf6EwhN2hEMusxZOhcW9H3UQ=\ngithub.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=\ngithub.com/rs/zerolog v1.20.0 h1:38k9hgtUBdxFwE34yS8rTHmHBa4eN16E4DJlv177LNs=\ngithub.com/rs/zerolog v1.20.0/go.mod h1:IzD0RJ65iWH0w97OQQebJEvTZYvsCUm9WVLWBQrJRjo=\ngithub.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=\ngithub.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=\ngithub.com/shirou/gopsutil v2.20.5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=\ngithub.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=\ngithub.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=\ngithub.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=\ngithub.com/smola/gocompat v0.2.0/go.mod h1:1B0MlxbmoZNo3h8guHp8HztB3BSYR5itql9qtVc0ypY=\ngithub.com/spacemonkeygo/openssl v0.0.0-20181017203307-c2dcc5cca94a/go.mod h1:7AyxJNCJ7SBZ1MfVQCWD6Uqo2oubI2Eq2y2eqf+A5r0=\ngithub.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w0SWMsp6j9O/dk4/ZpIhL+3CkG8ofA2vuv7k+ltqUMc=\ngithub.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=\ngithub.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=\ngithub.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=\ngithub.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=\ngithub.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=\ngithub.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=\ngithub.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=\ngithub.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=\ngithub.com/src-d/envconfig v1.0.0/go.mod h1:Q9YQZ7BKITldTBnoxsE5gOeB5y66RyPXeue/R4aaNBc=\ngithub.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q=\ngithub.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570/go.mod h1:8OR4w3TdeIHIh1g6EMY5p0gVNOovcWC+1vpc7naMuAw=\ngithub.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3/go.mod h1:hpGUWaI9xL8pRQCTXQgocU38Qw1g0Us7n5PxxTwTCYU=\ngithub.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=\ngithub.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=\ngithub.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=\ngithub.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=\ngithub.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=\ngithub.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca/go.mod h1:u2MKkTVTVJWe5D1rCvame8WqhBd88EuIwODJZ1VHCPM=\ngithub.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs=\ngithub.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=\ngithub.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=\ngithub.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1/go.mod h1:8UvriyWtv5Q5EOgjHaSseUEdkQfvwFv1I/In/O2M9gc=\ngithub.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc/go.mod h1:bopw91TMyo8J3tvftk8xmU2kPmlrt4nScJQZU2hE5EM=\ngithub.com/whyrusleeping/go-logging v0.0.1/go.mod h1:lDPYj54zutzG1XYfHAhcc7oNXEburHQBn+Iqd4yS4vE=\ngithub.com/whyrusleeping/mafmt v1.2.8/go.mod h1:faQJFPbLSxzD9xpA02ttW/tS9vZykNvXwGvqIpk20FA=\ngithub.com/whyrusleeping/mdns v0.0.0-20190826153040-b9b60ed33aa9/go.mod h1:j4l84WPFclQPj320J9gp0XwNKBb3U0zt5CBqjPp22G4=\ngithub.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7/go.mod h1:X2c0RVCI1eSUFI8eLcY3c0423ykwiUdxLJtkDvruhjI=\ngithub.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208/go.mod h1:IotVbo4F+mw0EzQ08zFqg7pK3FebNXpaMsRy2RT+Ees=\ngithub.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE=\ngithub.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=\ngo.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=\ngo.opencensus.io v0.22.1/go.mod h1:Ap50jQcDJrx6rB6VgeeFPtuPIf3wMRvRfrfYDO6+BmA=\ngo.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=\ngo.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=\ngo.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=\ngo.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=\ngo.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=\ngo.uber.org/goleak v1.0.0/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=\ngo.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=\ngo.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=\ngo.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=\ngo.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=\ngo.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc=\ngo.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc=\ngo.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ=\ngolang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=\ngolang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=\ngolang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=\ngolang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=\ngolang.org/x/crypto v0.0.0-20190225124518-7f87c0fbb88b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=\ngolang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=\ngolang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20190909091759-094676da4a83/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/crypto v0.0.0-20200423211502-4bdfaf469ed5/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=\ngolang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=\ngolang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4=\ngolang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=\ngolang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=\ngolang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=\ngolang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=\ngolang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=\ngolang.org/x/mobile v0.0.0-20200801112145-973feb4309de/go.mod h1:skQtrUTUwhdJvXM/2KKJzY8pDgNr9I/FOMqDVRPBUS4=\ngolang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=\ngolang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=\ngolang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=\ngolang.org/x/mod v0.1.1-0.20191209134235-331c550502dd/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190227160552-c95aed5357e7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=\ngolang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=\ngolang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=\ngolang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190405154228-4b34438f7a67/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190526052359-791d8a0f4d09/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200824131525-c12d262b63d8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=\ngolang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=\ngolang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20181130052023-1c3d964395ce/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=\ngolang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=\ngolang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=\ngolang.org/x/tools v0.0.0-20190828213141-aed303cbaa74/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200117012304-6edc0a871e69/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngoogle.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=\ngoogle.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=\ngoogle.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=\ngoogle.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=\ngoogle.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=\ngoogle.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=\ngoogle.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=\ngoogle.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=\ngoogle.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=\ngoogle.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=\ngoogle.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=\ngoogle.golang.org/grpc v1.28.1/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=\ngoogle.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=\ngoogle.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=\ngoogle.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=\ngoogle.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=\ngoogle.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=\ngoogle.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=\ngoogle.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=\ngoogle.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=\ngoogle.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=\ngoogle.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=\ngoogle.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=\ngopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=\ngopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=\ngopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c=\ngopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns=\ngopkg.in/src-d/go-cli.v0 v0.0.0-20181105080154-d492247bbc0d/go.mod h1:z+K8VcOYVYcSwSjGebuDL6176A1XskgbtNl64NSg+n8=\ngopkg.in/src-d/go-log.v1 v1.0.1/go.mod h1:GN34hKP0g305ysm2/hctJ0Y8nWP3zxXXJ8GFabTyABE=\ngopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=\ngopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0=\ngopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=\nhonnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=\n"
  },
  {
    "path": "libs/go/aea_end2end/main.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2021 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\n\npackage main\n\nimport (\n\taea \"aealite\"\n\tconnections \"aealite/connections\"\n\tprotocols \"aealite/protocols\"\n\t\"log\"\n\t\"os\"\n\t\"os/signal\"\n\tlocal_protocols \"seller_agent/protocols\"\n\n\tproto \"google.golang.org/protobuf/proto\"\n)\n\nfunc getRole(protocols.ProtocolMessageInterface, protocols.Address) protocols.Role {\n\treturn protocols.Role(\"some\")\n}\n\nfunc makeSellerDialogues(address string) *protocols.Dialogues {\n\tinitialPerformatives := []protocols.Performative{\"cfp\"}\n\tterminalPerformatives := []protocols.Performative{\"decline\", \"end\"}\n\tvalidReplies := map[protocols.Performative][]protocols.Performative{\n\t\t\"cfp\": []protocols.Performative{\"propose\", \"decline\"},\n\t\t\"propose\": []protocols.Performative{\n\t\t\t\"accept\",\n\t\t\t\"accept_w_inform\",\n\t\t\t\"decline\",\n\t\t\t\"propose\",\n\t\t},\n\t\t\"accept\": []protocols.Performative{\n\t\t\t\"decline\",\n\t\t\t\"match_accept\",\n\t\t\t\"match_accept_w_inform\",\n\t\t},\n\t\t\"accept_w_inform\": []protocols.Performative{\n\t\t\t\"decline\",\n\t\t\t\"match_accept\",\n\t\t\t\"match_accept_w_inform\",\n\t\t},\n\t\t\"decline\":               []protocols.Performative{},\n\t\t\"match_accept\":          []protocols.Performative{\"inform\", \"end\"},\n\t\t\"match_accept_w_inform\": []protocols.Performative{\"inform\", \"end\"},\n\t\t\"inform\":                []protocols.Performative{\"inform\", \"end\"},\n\t\t\"end\":                   []protocols.Performative{},\n\t}\n\tdialogues := protocols.NewDialogues(\n\t\tprotocols.Address(address),\n\t\tgetRole,\n\t\tfalse,\n\t\t\"my dialogues\",\n\t\tinitialPerformatives,\n\t\tterminalPerformatives,\n\t\tvalidReplies,\n\t)\n\treturn dialogues\n}\n\nfunc handleEnvelope(\n\tenvelope *protocols.Envelope,\n\tdialogues *protocols.Dialogues,\n\tagent *aea.Agent,\n) {\n\tfipaProtocolID := \"fetchai/fipa:1.0.0\"\n\n\tif envelope.GetProtocolId() != fipaProtocolID {\n\t\tlog.Printf(\"Not Fipa message!.\")\n\t\treturn\n\t}\n\n\tfipaMessage := &local_protocols.FipaMessage{}\n\tdialogueMessageWrapped, err := protocols.GetDialogueMessageWrappedAndSetContentFromEnvelope(\n\t\tenvelope,\n\t\tfipaMessage,\n\t)\n\tif err != nil {\n\t\tlog.Printf(\"Failed to get dialogue message message: %s\", err)\n\t\treturn\n\t}\n\tdialogue, err := dialogues.Update(dialogueMessageWrapped)\n\tif err != nil {\n\t\tlog.Printf(\"Failed to update dialogue:  %s\", err)\n\t\treturn\n\t}\n\tswitch dialogueMessageWrapped.Performative() {\n\tcase \"cfp\":\n\t\t{\n\t\t\tmsg, err := dialogue.Reply(\"propose\", dialogueMessageWrapped, nil)\n\t\t\tif err != nil {\n\t\t\t\tlog.Printf(\"Failed to reply dialogue:  %s\", err)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tq := &protocols.Query_Instance{\n\t\t\t\tModel: &protocols.Query_DataModel{\n\t\t\t\t\tName:        \"string\",\n\t\t\t\t\tAttributes:  []*protocols.Query_Attribute{},\n\t\t\t\t\tDescription: \"desc\",\n\t\t\t\t},\n\t\t\t\tValues: []*protocols.Query_KeyValue{},\n\t\t\t}\n\n\t\t\tout, err := proto.Marshal(q)\n\t\t\tif err != nil {\n\t\t\t\tlog.Printf(\"Failed to encode q:  %s\", err)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tproposeMsg := &local_protocols.FipaMessage{\n\t\t\t\tPerformative: &local_protocols.FipaMessage_Propose{\n\t\t\t\t\tPropose: &local_protocols.FipaMessage_Propose_Performative{\n\t\t\t\t\t\tProposal: &local_protocols.FipaMessage_Description{DescriptionBytes: out},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}\n\n\t\t\tcontent, err := proto.Marshal(proposeMsg)\n\t\t\tif err != nil {\n\t\t\t\tlog.Printf(\"Failed to encode content:  %s\", err)\n\t\t\t\treturn\n\t\t\t}\n\t\t\treplyEnvelope, err := protocols.MakeResponseEnvelope(msg, fipaProtocolID, content)\n\t\t\tif err != nil {\n\t\t\t\tlog.Printf(\"Failed to make envelope  %s\", err)\n\t\t\t\treturn\n\t\t\t}\n\t\t\terr = agent.Put(replyEnvelope)\n\t\t\tif err != nil {\n\t\t\t\tlog.Printf(\"Error on send reply: %s\", err)\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\tcase \"accept\":\n\t\t{\n\t\t\tmsg, err := dialogue.Reply(\"match_accept\", dialogueMessageWrapped, nil)\n\t\t\tif err != nil {\n\t\t\t\tlog.Printf(\"Failed to reply dialogue:  %s\", err)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tmatchMsg := &local_protocols.FipaMessage{\n\t\t\t\tPerformative: &local_protocols.FipaMessage_MatchAccept{},\n\t\t\t}\n\n\t\t\tcontent, err := proto.Marshal(matchMsg)\n\t\t\tif err != nil {\n\t\t\t\tlog.Printf(\"Failed to encode content:  %s\", err)\n\t\t\t\treturn\n\t\t\t}\n\t\t\treplyEnvelope, err := protocols.MakeResponseEnvelope(msg, fipaProtocolID, content)\n\t\t\tif err != nil {\n\t\t\t\tlog.Printf(\"Failed to make envelope  %s\", err)\n\t\t\t\treturn\n\t\t\t}\n\t\t\terr = agent.Put(replyEnvelope)\n\t\t\tif err != nil {\n\t\t\t\tlog.Printf(\"Error on send reply: %s\", err)\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\tcase \"end\":\n\t\t{\n\t\t\tlog.Print(\"It's done\")\n\t\t\tlog.Print(\"FIPA INTERACTION COMPLETE\")\n\t\t}\n\tdefault:\n\t\t{\n\t\t\tlog.Printf(\"Unsupported performative:  %s\", dialogueMessageWrapped.Performative())\n\t\t\treturn\n\t\t}\n\n\t}\n\n\tlog.Print(\"envelope handled successfully\")\n}\n\nfunc getEnvelopeAndProcess(\n\tdialogues *protocols.Dialogues,\n\tagent *aea.Agent) {\n\tfor {\n\t\tenvelope := agent.Get()\n\t\tlog.Printf(\"got incoming envelope: %s\", envelope.String())\n\t\thandleEnvelope(envelope, dialogues, agent)\n\t}\n}\n\nfunc main() {\n\n\tvar err error\n\n\t// env file\n\tif len(os.Args) != 2 {\n\t\tlog.Print(\"Usage: main ENV_FILE\")\n\t\tos.Exit(1)\n\t}\n\tenvFile := os.Args[1]\n\n\tlog.Print(\"Agent starting ...\")\n\n\t// Create agent\n\tagent := aea.Agent{}\n\n\t// Set connection\n\tagent.Connection = &connections.P2PClientApi{}\n\n\t// Initialise agent from environment file (first arg to process)\n\terr = agent.InitFromEnv(envFile)\n\tif err != nil {\n\t\tlog.Fatal(\"Failed to initialise agent\", err)\n\t}\n\tlog.Print(\"successfully initialized AEA!\")\n\n\terr = agent.Start()\n\tif err != nil {\n\t\tlog.Fatal(\"Failed to start agent\", err)\n\t}\n\tlog.Print(\"successfully started AEA!\")\n\tlog.Print(\"My Address is \", agent.Address())\n\n\tdialogues := makeSellerDialogues(agent.Address())\n\n\tgo getEnvelopeAndProcess(dialogues, &agent)\n\n\t// Wait until Ctrl+C or a termination call is done.\n\tc := make(chan os.Signal, 1)\n\tsignal.Notify(c, os.Interrupt)\n\t<-c\n\n\terr = agent.Stop()\n\tif err != nil {\n\t\tlog.Fatal(\"Failed to stop agent\", err)\n\t}\n\tlog.Print(\"Agent stopped\")\n}\n"
  },
  {
    "path": "libs/go/aea_end2end/pexpect_popen.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Wrapper for Pexpect to use in tests.\"\"\"\nimport os\nimport platform\nimport signal\nimport sys\nimport time\nfrom typing import List, Optional, Union\n\nfrom pexpect.exceptions import EOF, TIMEOUT  # type: ignore\nfrom pexpect.popen_spawn import PopenSpawn  # type: ignore\n\nfrom aea.helpers.base import send_control_c\n\n\nclass PexpectWrapper(PopenSpawn):\n    \"\"\"Utility class to make aea cli test easier.\"\"\"\n\n    def __init__(self, *args, **kwargs):\n        \"\"\"Init pexpect.spawn.\"\"\"\n        if platform.system() != \"Windows\":\n            kwargs[\"preexec_fn\"] = os.setsid\n\n        super().__init__(*args, **kwargs)\n\n    def control_c(self) -> None:\n        \"\"\"Send control c to process started.\"\"\"\n        time.sleep(0.1)  # sometimes it's better to wait a bit\n        send_control_c(self.proc, True)\n\n    @property\n    def returncode(self) -> Optional[Union[int, str]]:\n        \"\"\"Get return code of finished process.\"\"\"\n        return self.proc.poll()  # type: ignore\n\n    def wait_to_complete(self, timeout: float = 5) -> None:\n        \"\"\"Wait process to complete.\n\n        Terminate automatically after timeout.\n        Set returncode to terminated if terminated.\n\n        :param timeout: how many seconds wait process to finish before kill.\n        \"\"\"\n        if self.proc.poll() is not None:  # type: ignore\n            return\n\n        start_time = time.time()\n\n        while start_time + timeout > time.time() and self.proc.poll() is None:  # type: ignore\n            time.sleep(0.001)\n\n        if self.proc.poll() is None:  # type: ignore\n            self.terminate(force=True)\n            self.wait()\n            self.exitstatus = \"Terminated!\"  # type: ignore\n\n    def expect_all(\n        self, pattern_list: List[str], timeout: float = 10, strict: bool = True\n    ) -> None:\n        \"\"\"\n        Wait for all patterns appear in process output.\n\n        :param pattern_list: list of string to expect\n        :param timeout: timeout in seconds\n        :param strict: if non strict, it allows regular expression\n        \"\"\"\n        pattern_list = list(pattern_list)\n\n        start_time = time.time()\n        while pattern_list:\n            time_spent = time.time() - start_time\n            if time_spent > timeout:\n                raise TIMEOUT(timeout)\n            if strict:\n                idx = self.expect_exact(pattern_list, timeout - time_spent)\n            else:\n                idx = self.expect(pattern_list, timeout - time_spent)\n            pattern_list.pop(idx)\n\n    def wait_eof(self, timeout: float = 10) -> None:\n        \"\"\"\n        Wait for EOF of the process.\n\n        :param timeout: timeout in seconds\n        \"\"\"\n        self.expect(EOF, timeout=timeout)\n\n    def terminate(self, *args, **kwargs) -> None:\n        \"\"\"Terminate process.\"\"\"\n        if self.proc.poll() is None:\n            self.kill(signal.SIGKILL)\n"
  },
  {
    "path": "libs/go/aea_end2end/protocols/fipa.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.25.0\n// \tprotoc        v3.11.4\n// source: fipa.proto\n\npackage protocols\n\nimport (\n\tproto \"github.com/golang/protobuf/proto\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// This is a compile-time assertion that a sufficiently up-to-date version\n// of the legacy proto package is being used.\nconst _ = proto.ProtoPackageIsVersion4\n\ntype FipaMessage struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// Types that are assignable to Performative:\n\t//\t*FipaMessage_Accept\n\t//\t*FipaMessage_AcceptWInform\n\t//\t*FipaMessage_Cfp\n\t//\t*FipaMessage_Decline\n\t//\t*FipaMessage_End\n\t//\t*FipaMessage_Inform\n\t//\t*FipaMessage_MatchAccept\n\t//\t*FipaMessage_MatchAcceptWInform\n\t//\t*FipaMessage_Propose\n\tPerformative isFipaMessage_Performative `protobuf_oneof:\"performative\"`\n}\n\nfunc (x *FipaMessage) Reset() {\n\t*x = FipaMessage{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_fipa_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *FipaMessage) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*FipaMessage) ProtoMessage() {}\n\nfunc (x *FipaMessage) ProtoReflect() protoreflect.Message {\n\tmi := &file_fipa_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use FipaMessage.ProtoReflect.Descriptor instead.\nfunc (*FipaMessage) Descriptor() ([]byte, []int) {\n\treturn file_fipa_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (m *FipaMessage) GetPerformative() isFipaMessage_Performative {\n\tif m != nil {\n\t\treturn m.Performative\n\t}\n\treturn nil\n}\n\nfunc (x *FipaMessage) GetAccept() *FipaMessage_Accept_Performative {\n\tif x, ok := x.GetPerformative().(*FipaMessage_Accept); ok {\n\t\treturn x.Accept\n\t}\n\treturn nil\n}\n\nfunc (x *FipaMessage) GetAcceptWInform() *FipaMessage_Accept_W_Inform_Performative {\n\tif x, ok := x.GetPerformative().(*FipaMessage_AcceptWInform); ok {\n\t\treturn x.AcceptWInform\n\t}\n\treturn nil\n}\n\nfunc (x *FipaMessage) GetCfp() *FipaMessage_Cfp_Performative {\n\tif x, ok := x.GetPerformative().(*FipaMessage_Cfp); ok {\n\t\treturn x.Cfp\n\t}\n\treturn nil\n}\n\nfunc (x *FipaMessage) GetDecline() *FipaMessage_Decline_Performative {\n\tif x, ok := x.GetPerformative().(*FipaMessage_Decline); ok {\n\t\treturn x.Decline\n\t}\n\treturn nil\n}\n\nfunc (x *FipaMessage) GetEnd() *FipaMessage_End_Performative {\n\tif x, ok := x.GetPerformative().(*FipaMessage_End); ok {\n\t\treturn x.End\n\t}\n\treturn nil\n}\n\nfunc (x *FipaMessage) GetInform() *FipaMessage_Inform_Performative {\n\tif x, ok := x.GetPerformative().(*FipaMessage_Inform); ok {\n\t\treturn x.Inform\n\t}\n\treturn nil\n}\n\nfunc (x *FipaMessage) GetMatchAccept() *FipaMessage_Match_Accept_Performative {\n\tif x, ok := x.GetPerformative().(*FipaMessage_MatchAccept); ok {\n\t\treturn x.MatchAccept\n\t}\n\treturn nil\n}\n\nfunc (x *FipaMessage) GetMatchAcceptWInform() *FipaMessage_Match_Accept_W_Inform_Performative {\n\tif x, ok := x.GetPerformative().(*FipaMessage_MatchAcceptWInform); ok {\n\t\treturn x.MatchAcceptWInform\n\t}\n\treturn nil\n}\n\nfunc (x *FipaMessage) GetPropose() *FipaMessage_Propose_Performative {\n\tif x, ok := x.GetPerformative().(*FipaMessage_Propose); ok {\n\t\treturn x.Propose\n\t}\n\treturn nil\n}\n\ntype isFipaMessage_Performative interface {\n\tisFipaMessage_Performative()\n}\n\ntype FipaMessage_Accept struct {\n\tAccept *FipaMessage_Accept_Performative `protobuf:\"bytes,5,opt,name=accept,proto3,oneof\"`\n}\n\ntype FipaMessage_AcceptWInform struct {\n\tAcceptWInform *FipaMessage_Accept_W_Inform_Performative `protobuf:\"bytes,6,opt,name=accept_w_inform,json=acceptWInform,proto3,oneof\"`\n}\n\ntype FipaMessage_Cfp struct {\n\tCfp *FipaMessage_Cfp_Performative `protobuf:\"bytes,7,opt,name=cfp,proto3,oneof\"`\n}\n\ntype FipaMessage_Decline struct {\n\tDecline *FipaMessage_Decline_Performative `protobuf:\"bytes,8,opt,name=decline,proto3,oneof\"`\n}\n\ntype FipaMessage_End struct {\n\tEnd *FipaMessage_End_Performative `protobuf:\"bytes,9,opt,name=end,proto3,oneof\"`\n}\n\ntype FipaMessage_Inform struct {\n\tInform *FipaMessage_Inform_Performative `protobuf:\"bytes,10,opt,name=inform,proto3,oneof\"`\n}\n\ntype FipaMessage_MatchAccept struct {\n\tMatchAccept *FipaMessage_Match_Accept_Performative `protobuf:\"bytes,11,opt,name=match_accept,json=matchAccept,proto3,oneof\"`\n}\n\ntype FipaMessage_MatchAcceptWInform struct {\n\tMatchAcceptWInform *FipaMessage_Match_Accept_W_Inform_Performative `protobuf:\"bytes,12,opt,name=match_accept_w_inform,json=matchAcceptWInform,proto3,oneof\"`\n}\n\ntype FipaMessage_Propose struct {\n\tPropose *FipaMessage_Propose_Performative `protobuf:\"bytes,13,opt,name=propose,proto3,oneof\"`\n}\n\nfunc (*FipaMessage_Accept) isFipaMessage_Performative() {}\n\nfunc (*FipaMessage_AcceptWInform) isFipaMessage_Performative() {}\n\nfunc (*FipaMessage_Cfp) isFipaMessage_Performative() {}\n\nfunc (*FipaMessage_Decline) isFipaMessage_Performative() {}\n\nfunc (*FipaMessage_End) isFipaMessage_Performative() {}\n\nfunc (*FipaMessage_Inform) isFipaMessage_Performative() {}\n\nfunc (*FipaMessage_MatchAccept) isFipaMessage_Performative() {}\n\nfunc (*FipaMessage_MatchAcceptWInform) isFipaMessage_Performative() {}\n\nfunc (*FipaMessage_Propose) isFipaMessage_Performative() {}\n\n// Custom Types\ntype FipaMessage_Description struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tDescriptionBytes []byte `protobuf:\"bytes,1,opt,name=description_bytes,json=descriptionBytes,proto3\" json:\"description_bytes,omitempty\"`\n}\n\nfunc (x *FipaMessage_Description) Reset() {\n\t*x = FipaMessage_Description{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_fipa_proto_msgTypes[1]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *FipaMessage_Description) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*FipaMessage_Description) ProtoMessage() {}\n\nfunc (x *FipaMessage_Description) ProtoReflect() protoreflect.Message {\n\tmi := &file_fipa_proto_msgTypes[1]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use FipaMessage_Description.ProtoReflect.Descriptor instead.\nfunc (*FipaMessage_Description) Descriptor() ([]byte, []int) {\n\treturn file_fipa_proto_rawDescGZIP(), []int{0, 0}\n}\n\nfunc (x *FipaMessage_Description) GetDescriptionBytes() []byte {\n\tif x != nil {\n\t\treturn x.DescriptionBytes\n\t}\n\treturn nil\n}\n\ntype FipaMessage_Query struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tQueryBytes []byte `protobuf:\"bytes,1,opt,name=query_bytes,json=queryBytes,proto3\" json:\"query_bytes,omitempty\"`\n}\n\nfunc (x *FipaMessage_Query) Reset() {\n\t*x = FipaMessage_Query{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_fipa_proto_msgTypes[2]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *FipaMessage_Query) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*FipaMessage_Query) ProtoMessage() {}\n\nfunc (x *FipaMessage_Query) ProtoReflect() protoreflect.Message {\n\tmi := &file_fipa_proto_msgTypes[2]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use FipaMessage_Query.ProtoReflect.Descriptor instead.\nfunc (*FipaMessage_Query) Descriptor() ([]byte, []int) {\n\treturn file_fipa_proto_rawDescGZIP(), []int{0, 1}\n}\n\nfunc (x *FipaMessage_Query) GetQueryBytes() []byte {\n\tif x != nil {\n\t\treturn x.QueryBytes\n\t}\n\treturn nil\n}\n\n// Performatives and contents\ntype FipaMessage_Cfp_Performative struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tQuery *FipaMessage_Query `protobuf:\"bytes,1,opt,name=query,proto3\" json:\"query,omitempty\"`\n}\n\nfunc (x *FipaMessage_Cfp_Performative) Reset() {\n\t*x = FipaMessage_Cfp_Performative{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_fipa_proto_msgTypes[3]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *FipaMessage_Cfp_Performative) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*FipaMessage_Cfp_Performative) ProtoMessage() {}\n\nfunc (x *FipaMessage_Cfp_Performative) ProtoReflect() protoreflect.Message {\n\tmi := &file_fipa_proto_msgTypes[3]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use FipaMessage_Cfp_Performative.ProtoReflect.Descriptor instead.\nfunc (*FipaMessage_Cfp_Performative) Descriptor() ([]byte, []int) {\n\treturn file_fipa_proto_rawDescGZIP(), []int{0, 2}\n}\n\nfunc (x *FipaMessage_Cfp_Performative) GetQuery() *FipaMessage_Query {\n\tif x != nil {\n\t\treturn x.Query\n\t}\n\treturn nil\n}\n\ntype FipaMessage_Propose_Performative struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tProposal *FipaMessage_Description `protobuf:\"bytes,1,opt,name=proposal,proto3\" json:\"proposal,omitempty\"`\n}\n\nfunc (x *FipaMessage_Propose_Performative) Reset() {\n\t*x = FipaMessage_Propose_Performative{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_fipa_proto_msgTypes[4]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *FipaMessage_Propose_Performative) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*FipaMessage_Propose_Performative) ProtoMessage() {}\n\nfunc (x *FipaMessage_Propose_Performative) ProtoReflect() protoreflect.Message {\n\tmi := &file_fipa_proto_msgTypes[4]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use FipaMessage_Propose_Performative.ProtoReflect.Descriptor instead.\nfunc (*FipaMessage_Propose_Performative) Descriptor() ([]byte, []int) {\n\treturn file_fipa_proto_rawDescGZIP(), []int{0, 3}\n}\n\nfunc (x *FipaMessage_Propose_Performative) GetProposal() *FipaMessage_Description {\n\tif x != nil {\n\t\treturn x.Proposal\n\t}\n\treturn nil\n}\n\ntype FipaMessage_Accept_W_Inform_Performative struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tInfo map[string]string `protobuf:\"bytes,1,rep,name=info,proto3\" json:\"info,omitempty\" protobuf_key:\"bytes,1,opt,name=key,proto3\" protobuf_val:\"bytes,2,opt,name=value,proto3\"`\n}\n\nfunc (x *FipaMessage_Accept_W_Inform_Performative) Reset() {\n\t*x = FipaMessage_Accept_W_Inform_Performative{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_fipa_proto_msgTypes[5]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *FipaMessage_Accept_W_Inform_Performative) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*FipaMessage_Accept_W_Inform_Performative) ProtoMessage() {}\n\nfunc (x *FipaMessage_Accept_W_Inform_Performative) ProtoReflect() protoreflect.Message {\n\tmi := &file_fipa_proto_msgTypes[5]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use FipaMessage_Accept_W_Inform_Performative.ProtoReflect.Descriptor instead.\nfunc (*FipaMessage_Accept_W_Inform_Performative) Descriptor() ([]byte, []int) {\n\treturn file_fipa_proto_rawDescGZIP(), []int{0, 4}\n}\n\nfunc (x *FipaMessage_Accept_W_Inform_Performative) GetInfo() map[string]string {\n\tif x != nil {\n\t\treturn x.Info\n\t}\n\treturn nil\n}\n\ntype FipaMessage_Match_Accept_W_Inform_Performative struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tInfo map[string]string `protobuf:\"bytes,1,rep,name=info,proto3\" json:\"info,omitempty\" protobuf_key:\"bytes,1,opt,name=key,proto3\" protobuf_val:\"bytes,2,opt,name=value,proto3\"`\n}\n\nfunc (x *FipaMessage_Match_Accept_W_Inform_Performative) Reset() {\n\t*x = FipaMessage_Match_Accept_W_Inform_Performative{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_fipa_proto_msgTypes[6]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *FipaMessage_Match_Accept_W_Inform_Performative) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*FipaMessage_Match_Accept_W_Inform_Performative) ProtoMessage() {}\n\nfunc (x *FipaMessage_Match_Accept_W_Inform_Performative) ProtoReflect() protoreflect.Message {\n\tmi := &file_fipa_proto_msgTypes[6]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use FipaMessage_Match_Accept_W_Inform_Performative.ProtoReflect.Descriptor instead.\nfunc (*FipaMessage_Match_Accept_W_Inform_Performative) Descriptor() ([]byte, []int) {\n\treturn file_fipa_proto_rawDescGZIP(), []int{0, 5}\n}\n\nfunc (x *FipaMessage_Match_Accept_W_Inform_Performative) GetInfo() map[string]string {\n\tif x != nil {\n\t\treturn x.Info\n\t}\n\treturn nil\n}\n\ntype FipaMessage_Inform_Performative struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tInfo map[string]string `protobuf:\"bytes,1,rep,name=info,proto3\" json:\"info,omitempty\" protobuf_key:\"bytes,1,opt,name=key,proto3\" protobuf_val:\"bytes,2,opt,name=value,proto3\"`\n}\n\nfunc (x *FipaMessage_Inform_Performative) Reset() {\n\t*x = FipaMessage_Inform_Performative{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_fipa_proto_msgTypes[7]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *FipaMessage_Inform_Performative) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*FipaMessage_Inform_Performative) ProtoMessage() {}\n\nfunc (x *FipaMessage_Inform_Performative) ProtoReflect() protoreflect.Message {\n\tmi := &file_fipa_proto_msgTypes[7]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use FipaMessage_Inform_Performative.ProtoReflect.Descriptor instead.\nfunc (*FipaMessage_Inform_Performative) Descriptor() ([]byte, []int) {\n\treturn file_fipa_proto_rawDescGZIP(), []int{0, 6}\n}\n\nfunc (x *FipaMessage_Inform_Performative) GetInfo() map[string]string {\n\tif x != nil {\n\t\treturn x.Info\n\t}\n\treturn nil\n}\n\ntype FipaMessage_Accept_Performative struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n}\n\nfunc (x *FipaMessage_Accept_Performative) Reset() {\n\t*x = FipaMessage_Accept_Performative{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_fipa_proto_msgTypes[8]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *FipaMessage_Accept_Performative) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*FipaMessage_Accept_Performative) ProtoMessage() {}\n\nfunc (x *FipaMessage_Accept_Performative) ProtoReflect() protoreflect.Message {\n\tmi := &file_fipa_proto_msgTypes[8]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use FipaMessage_Accept_Performative.ProtoReflect.Descriptor instead.\nfunc (*FipaMessage_Accept_Performative) Descriptor() ([]byte, []int) {\n\treturn file_fipa_proto_rawDescGZIP(), []int{0, 7}\n}\n\ntype FipaMessage_Decline_Performative struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n}\n\nfunc (x *FipaMessage_Decline_Performative) Reset() {\n\t*x = FipaMessage_Decline_Performative{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_fipa_proto_msgTypes[9]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *FipaMessage_Decline_Performative) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*FipaMessage_Decline_Performative) ProtoMessage() {}\n\nfunc (x *FipaMessage_Decline_Performative) ProtoReflect() protoreflect.Message {\n\tmi := &file_fipa_proto_msgTypes[9]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use FipaMessage_Decline_Performative.ProtoReflect.Descriptor instead.\nfunc (*FipaMessage_Decline_Performative) Descriptor() ([]byte, []int) {\n\treturn file_fipa_proto_rawDescGZIP(), []int{0, 8}\n}\n\ntype FipaMessage_Match_Accept_Performative struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n}\n\nfunc (x *FipaMessage_Match_Accept_Performative) Reset() {\n\t*x = FipaMessage_Match_Accept_Performative{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_fipa_proto_msgTypes[10]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *FipaMessage_Match_Accept_Performative) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*FipaMessage_Match_Accept_Performative) ProtoMessage() {}\n\nfunc (x *FipaMessage_Match_Accept_Performative) ProtoReflect() protoreflect.Message {\n\tmi := &file_fipa_proto_msgTypes[10]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use FipaMessage_Match_Accept_Performative.ProtoReflect.Descriptor instead.\nfunc (*FipaMessage_Match_Accept_Performative) Descriptor() ([]byte, []int) {\n\treturn file_fipa_proto_rawDescGZIP(), []int{0, 9}\n}\n\ntype FipaMessage_End_Performative struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n}\n\nfunc (x *FipaMessage_End_Performative) Reset() {\n\t*x = FipaMessage_End_Performative{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_fipa_proto_msgTypes[11]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *FipaMessage_End_Performative) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*FipaMessage_End_Performative) ProtoMessage() {}\n\nfunc (x *FipaMessage_End_Performative) ProtoReflect() protoreflect.Message {\n\tmi := &file_fipa_proto_msgTypes[11]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use FipaMessage_End_Performative.ProtoReflect.Descriptor instead.\nfunc (*FipaMessage_End_Performative) Descriptor() ([]byte, []int) {\n\treturn file_fipa_proto_rawDescGZIP(), []int{0, 10}\n}\n\nvar File_fipa_proto protoreflect.FileDescriptor\n\nvar file_fipa_proto_rawDesc = []byte{\n\t0x0a, 0x0a, 0x66, 0x69, 0x70, 0x61, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x17, 0x61, 0x65,\n\t0x61, 0x2e, 0x66, 0x65, 0x74, 0x63, 0x68, 0x61, 0x69, 0x2e, 0x66, 0x69, 0x70, 0x61, 0x2e, 0x76,\n\t0x31, 0x5f, 0x30, 0x5f, 0x30, 0x22, 0x86, 0x0e, 0x0a, 0x0b, 0x46, 0x69, 0x70, 0x61, 0x4d, 0x65,\n\t0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x52, 0x0a, 0x06, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x18,\n\t0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x38, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x66, 0x65, 0x74, 0x63,\n\t0x68, 0x61, 0x69, 0x2e, 0x66, 0x69, 0x70, 0x61, 0x2e, 0x76, 0x31, 0x5f, 0x30, 0x5f, 0x30, 0x2e,\n\t0x46, 0x69, 0x70, 0x61, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x41, 0x63, 0x63, 0x65,\n\t0x70, 0x74, 0x5f, 0x50, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x76, 0x65, 0x48,\n\t0x00, 0x52, 0x06, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x12, 0x6b, 0x0a, 0x0f, 0x61, 0x63, 0x63,\n\t0x65, 0x70, 0x74, 0x5f, 0x77, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x06, 0x20, 0x01,\n\t0x28, 0x0b, 0x32, 0x41, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x66, 0x65, 0x74, 0x63, 0x68, 0x61, 0x69,\n\t0x2e, 0x66, 0x69, 0x70, 0x61, 0x2e, 0x76, 0x31, 0x5f, 0x30, 0x5f, 0x30, 0x2e, 0x46, 0x69, 0x70,\n\t0x61, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x5f,\n\t0x57, 0x5f, 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x5f, 0x50, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d,\n\t0x61, 0x74, 0x69, 0x76, 0x65, 0x48, 0x00, 0x52, 0x0d, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x57,\n\t0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x49, 0x0a, 0x03, 0x63, 0x66, 0x70, 0x18, 0x07, 0x20,\n\t0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x66, 0x65, 0x74, 0x63, 0x68, 0x61,\n\t0x69, 0x2e, 0x66, 0x69, 0x70, 0x61, 0x2e, 0x76, 0x31, 0x5f, 0x30, 0x5f, 0x30, 0x2e, 0x46, 0x69,\n\t0x70, 0x61, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x43, 0x66, 0x70, 0x5f, 0x50, 0x65,\n\t0x72, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x76, 0x65, 0x48, 0x00, 0x52, 0x03, 0x63, 0x66,\n\t0x70, 0x12, 0x55, 0x0a, 0x07, 0x64, 0x65, 0x63, 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x08, 0x20, 0x01,\n\t0x28, 0x0b, 0x32, 0x39, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x66, 0x65, 0x74, 0x63, 0x68, 0x61, 0x69,\n\t0x2e, 0x66, 0x69, 0x70, 0x61, 0x2e, 0x76, 0x31, 0x5f, 0x30, 0x5f, 0x30, 0x2e, 0x46, 0x69, 0x70,\n\t0x61, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x44, 0x65, 0x63, 0x6c, 0x69, 0x6e, 0x65,\n\t0x5f, 0x50, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x76, 0x65, 0x48, 0x00, 0x52,\n\t0x07, 0x64, 0x65, 0x63, 0x6c, 0x69, 0x6e, 0x65, 0x12, 0x49, 0x0a, 0x03, 0x65, 0x6e, 0x64, 0x18,\n\t0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x66, 0x65, 0x74, 0x63,\n\t0x68, 0x61, 0x69, 0x2e, 0x66, 0x69, 0x70, 0x61, 0x2e, 0x76, 0x31, 0x5f, 0x30, 0x5f, 0x30, 0x2e,\n\t0x46, 0x69, 0x70, 0x61, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x45, 0x6e, 0x64, 0x5f,\n\t0x50, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x76, 0x65, 0x48, 0x00, 0x52, 0x03,\n\t0x65, 0x6e, 0x64, 0x12, 0x52, 0x0a, 0x06, 0x69, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x0a, 0x20,\n\t0x01, 0x28, 0x0b, 0x32, 0x38, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x66, 0x65, 0x74, 0x63, 0x68, 0x61,\n\t0x69, 0x2e, 0x66, 0x69, 0x70, 0x61, 0x2e, 0x76, 0x31, 0x5f, 0x30, 0x5f, 0x30, 0x2e, 0x46, 0x69,\n\t0x70, 0x61, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d,\n\t0x5f, 0x50, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x76, 0x65, 0x48, 0x00, 0x52,\n\t0x06, 0x69, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x63, 0x0a, 0x0c, 0x6d, 0x61, 0x74, 0x63, 0x68,\n\t0x5f, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3e, 0x2e,\n\t0x61, 0x65, 0x61, 0x2e, 0x66, 0x65, 0x74, 0x63, 0x68, 0x61, 0x69, 0x2e, 0x66, 0x69, 0x70, 0x61,\n\t0x2e, 0x76, 0x31, 0x5f, 0x30, 0x5f, 0x30, 0x2e, 0x46, 0x69, 0x70, 0x61, 0x4d, 0x65, 0x73, 0x73,\n\t0x61, 0x67, 0x65, 0x2e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74,\n\t0x5f, 0x50, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x76, 0x65, 0x48, 0x00, 0x52,\n\t0x0b, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x12, 0x7c, 0x0a, 0x15,\n\t0x6d, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x5f, 0x77, 0x5f, 0x69,\n\t0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x47, 0x2e, 0x61, 0x65,\n\t0x61, 0x2e, 0x66, 0x65, 0x74, 0x63, 0x68, 0x61, 0x69, 0x2e, 0x66, 0x69, 0x70, 0x61, 0x2e, 0x76,\n\t0x31, 0x5f, 0x30, 0x5f, 0x30, 0x2e, 0x46, 0x69, 0x70, 0x61, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67,\n\t0x65, 0x2e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x5f, 0x57,\n\t0x5f, 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x5f, 0x50, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x61,\n\t0x74, 0x69, 0x76, 0x65, 0x48, 0x00, 0x52, 0x12, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x41, 0x63, 0x63,\n\t0x65, 0x70, 0x74, 0x57, 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x55, 0x0a, 0x07, 0x70, 0x72,\n\t0x6f, 0x70, 0x6f, 0x73, 0x65, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x39, 0x2e, 0x61, 0x65,\n\t0x61, 0x2e, 0x66, 0x65, 0x74, 0x63, 0x68, 0x61, 0x69, 0x2e, 0x66, 0x69, 0x70, 0x61, 0x2e, 0x76,\n\t0x31, 0x5f, 0x30, 0x5f, 0x30, 0x2e, 0x46, 0x69, 0x70, 0x61, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67,\n\t0x65, 0x2e, 0x50, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x65, 0x5f, 0x50, 0x65, 0x72, 0x66, 0x6f, 0x72,\n\t0x6d, 0x61, 0x74, 0x69, 0x76, 0x65, 0x48, 0x00, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x70, 0x6f, 0x73,\n\t0x65, 0x1a, 0x3a, 0x0a, 0x0b, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e,\n\t0x12, 0x2b, 0x0a, 0x11, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f,\n\t0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x10, 0x64, 0x65, 0x73,\n\t0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x79, 0x74, 0x65, 0x73, 0x1a, 0x28, 0x0a,\n\t0x05, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x1f, 0x0a, 0x0b, 0x71, 0x75, 0x65, 0x72, 0x79, 0x5f,\n\t0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x71, 0x75, 0x65,\n\t0x72, 0x79, 0x42, 0x79, 0x74, 0x65, 0x73, 0x1a, 0x54, 0x0a, 0x10, 0x43, 0x66, 0x70, 0x5f, 0x50,\n\t0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x76, 0x65, 0x12, 0x40, 0x0a, 0x05, 0x71,\n\t0x75, 0x65, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x61, 0x65, 0x61,\n\t0x2e, 0x66, 0x65, 0x74, 0x63, 0x68, 0x61, 0x69, 0x2e, 0x66, 0x69, 0x70, 0x61, 0x2e, 0x76, 0x31,\n\t0x5f, 0x30, 0x5f, 0x30, 0x2e, 0x46, 0x69, 0x70, 0x61, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,\n\t0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x1a, 0x64, 0x0a,\n\t0x14, 0x50, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x65, 0x5f, 0x50, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d,\n\t0x61, 0x74, 0x69, 0x76, 0x65, 0x12, 0x4c, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61,\n\t0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x66, 0x65,\n\t0x74, 0x63, 0x68, 0x61, 0x69, 0x2e, 0x66, 0x69, 0x70, 0x61, 0x2e, 0x76, 0x31, 0x5f, 0x30, 0x5f,\n\t0x30, 0x2e, 0x46, 0x69, 0x70, 0x61, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x44, 0x65,\n\t0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x70, 0x6f,\n\t0x73, 0x61, 0x6c, 0x1a, 0xb8, 0x01, 0x0a, 0x1c, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x5f, 0x57,\n\t0x5f, 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x5f, 0x50, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x61,\n\t0x74, 0x69, 0x76, 0x65, 0x12, 0x5f, 0x0a, 0x04, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x01, 0x20, 0x03,\n\t0x28, 0x0b, 0x32, 0x4b, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x66, 0x65, 0x74, 0x63, 0x68, 0x61, 0x69,\n\t0x2e, 0x66, 0x69, 0x70, 0x61, 0x2e, 0x76, 0x31, 0x5f, 0x30, 0x5f, 0x30, 0x2e, 0x46, 0x69, 0x70,\n\t0x61, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x5f,\n\t0x57, 0x5f, 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x5f, 0x50, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d,\n\t0x61, 0x74, 0x69, 0x76, 0x65, 0x2e, 0x49, 0x6e, 0x66, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52,\n\t0x04, 0x69, 0x6e, 0x66, 0x6f, 0x1a, 0x37, 0x0a, 0x09, 0x49, 0x6e, 0x66, 0x6f, 0x45, 0x6e, 0x74,\n\t0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,\n\t0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20,\n\t0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0xc4,\n\t0x01, 0x0a, 0x22, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x5f,\n\t0x57, 0x5f, 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x5f, 0x50, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d,\n\t0x61, 0x74, 0x69, 0x76, 0x65, 0x12, 0x65, 0x0a, 0x04, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x01, 0x20,\n\t0x03, 0x28, 0x0b, 0x32, 0x51, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x66, 0x65, 0x74, 0x63, 0x68, 0x61,\n\t0x69, 0x2e, 0x66, 0x69, 0x70, 0x61, 0x2e, 0x76, 0x31, 0x5f, 0x30, 0x5f, 0x30, 0x2e, 0x46, 0x69,\n\t0x70, 0x61, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x5f,\n\t0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x5f, 0x57, 0x5f, 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x5f,\n\t0x50, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x76, 0x65, 0x2e, 0x49, 0x6e, 0x66,\n\t0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x04, 0x69, 0x6e, 0x66, 0x6f, 0x1a, 0x37, 0x0a, 0x09,\n\t0x49, 0x6e, 0x66, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79,\n\t0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76,\n\t0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75,\n\t0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0xa6, 0x01, 0x0a, 0x13, 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d,\n\t0x5f, 0x50, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x76, 0x65, 0x12, 0x56, 0x0a,\n\t0x04, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x42, 0x2e, 0x61, 0x65,\n\t0x61, 0x2e, 0x66, 0x65, 0x74, 0x63, 0x68, 0x61, 0x69, 0x2e, 0x66, 0x69, 0x70, 0x61, 0x2e, 0x76,\n\t0x31, 0x5f, 0x30, 0x5f, 0x30, 0x2e, 0x46, 0x69, 0x70, 0x61, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67,\n\t0x65, 0x2e, 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x5f, 0x50, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d,\n\t0x61, 0x74, 0x69, 0x76, 0x65, 0x2e, 0x49, 0x6e, 0x66, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52,\n\t0x04, 0x69, 0x6e, 0x66, 0x6f, 0x1a, 0x37, 0x0a, 0x09, 0x49, 0x6e, 0x66, 0x6f, 0x45, 0x6e, 0x74,\n\t0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,\n\t0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20,\n\t0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x15,\n\t0x0a, 0x13, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x5f, 0x50, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d,\n\t0x61, 0x74, 0x69, 0x76, 0x65, 0x1a, 0x16, 0x0a, 0x14, 0x44, 0x65, 0x63, 0x6c, 0x69, 0x6e, 0x65,\n\t0x5f, 0x50, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x76, 0x65, 0x1a, 0x1b, 0x0a,\n\t0x19, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x5f, 0x50, 0x65,\n\t0x72, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x76, 0x65, 0x1a, 0x12, 0x0a, 0x10, 0x45, 0x6e,\n\t0x64, 0x5f, 0x50, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x76, 0x65, 0x42, 0x0e,\n\t0x0a, 0x0c, 0x70, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x76, 0x65, 0x62, 0x06,\n\t0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_fipa_proto_rawDescOnce sync.Once\n\tfile_fipa_proto_rawDescData = file_fipa_proto_rawDesc\n)\n\nfunc file_fipa_proto_rawDescGZIP() []byte {\n\tfile_fipa_proto_rawDescOnce.Do(func() {\n\t\tfile_fipa_proto_rawDescData = protoimpl.X.CompressGZIP(file_fipa_proto_rawDescData)\n\t})\n\treturn file_fipa_proto_rawDescData\n}\n\nvar file_fipa_proto_msgTypes = make([]protoimpl.MessageInfo, 15)\nvar file_fipa_proto_goTypes = []interface{}{\n\t(*FipaMessage)(nil),                                    // 0: aea.fetchai.fipa.v1_0_0.FipaMessage\n\t(*FipaMessage_Description)(nil),                        // 1: aea.fetchai.fipa.v1_0_0.FipaMessage.Description\n\t(*FipaMessage_Query)(nil),                              // 2: aea.fetchai.fipa.v1_0_0.FipaMessage.Query\n\t(*FipaMessage_Cfp_Performative)(nil),                   // 3: aea.fetchai.fipa.v1_0_0.FipaMessage.Cfp_Performative\n\t(*FipaMessage_Propose_Performative)(nil),               // 4: aea.fetchai.fipa.v1_0_0.FipaMessage.Propose_Performative\n\t(*FipaMessage_Accept_W_Inform_Performative)(nil),       // 5: aea.fetchai.fipa.v1_0_0.FipaMessage.Accept_W_Inform_Performative\n\t(*FipaMessage_Match_Accept_W_Inform_Performative)(nil), // 6: aea.fetchai.fipa.v1_0_0.FipaMessage.Match_Accept_W_Inform_Performative\n\t(*FipaMessage_Inform_Performative)(nil),                // 7: aea.fetchai.fipa.v1_0_0.FipaMessage.Inform_Performative\n\t(*FipaMessage_Accept_Performative)(nil),                // 8: aea.fetchai.fipa.v1_0_0.FipaMessage.Accept_Performative\n\t(*FipaMessage_Decline_Performative)(nil),               // 9: aea.fetchai.fipa.v1_0_0.FipaMessage.Decline_Performative\n\t(*FipaMessage_Match_Accept_Performative)(nil),          // 10: aea.fetchai.fipa.v1_0_0.FipaMessage.Match_Accept_Performative\n\t(*FipaMessage_End_Performative)(nil),                   // 11: aea.fetchai.fipa.v1_0_0.FipaMessage.End_Performative\n\tnil,                                                    // 12: aea.fetchai.fipa.v1_0_0.FipaMessage.Accept_W_Inform_Performative.InfoEntry\n\tnil,                                                    // 13: aea.fetchai.fipa.v1_0_0.FipaMessage.Match_Accept_W_Inform_Performative.InfoEntry\n\tnil,                                                    // 14: aea.fetchai.fipa.v1_0_0.FipaMessage.Inform_Performative.InfoEntry\n}\nvar file_fipa_proto_depIdxs = []int32{\n\t8,  // 0: aea.fetchai.fipa.v1_0_0.FipaMessage.accept:type_name -> aea.fetchai.fipa.v1_0_0.FipaMessage.Accept_Performative\n\t5,  // 1: aea.fetchai.fipa.v1_0_0.FipaMessage.accept_w_inform:type_name -> aea.fetchai.fipa.v1_0_0.FipaMessage.Accept_W_Inform_Performative\n\t3,  // 2: aea.fetchai.fipa.v1_0_0.FipaMessage.cfp:type_name -> aea.fetchai.fipa.v1_0_0.FipaMessage.Cfp_Performative\n\t9,  // 3: aea.fetchai.fipa.v1_0_0.FipaMessage.decline:type_name -> aea.fetchai.fipa.v1_0_0.FipaMessage.Decline_Performative\n\t11, // 4: aea.fetchai.fipa.v1_0_0.FipaMessage.end:type_name -> aea.fetchai.fipa.v1_0_0.FipaMessage.End_Performative\n\t7,  // 5: aea.fetchai.fipa.v1_0_0.FipaMessage.inform:type_name -> aea.fetchai.fipa.v1_0_0.FipaMessage.Inform_Performative\n\t10, // 6: aea.fetchai.fipa.v1_0_0.FipaMessage.match_accept:type_name -> aea.fetchai.fipa.v1_0_0.FipaMessage.Match_Accept_Performative\n\t6,  // 7: aea.fetchai.fipa.v1_0_0.FipaMessage.match_accept_w_inform:type_name -> aea.fetchai.fipa.v1_0_0.FipaMessage.Match_Accept_W_Inform_Performative\n\t4,  // 8: aea.fetchai.fipa.v1_0_0.FipaMessage.propose:type_name -> aea.fetchai.fipa.v1_0_0.FipaMessage.Propose_Performative\n\t2,  // 9: aea.fetchai.fipa.v1_0_0.FipaMessage.Cfp_Performative.query:type_name -> aea.fetchai.fipa.v1_0_0.FipaMessage.Query\n\t1,  // 10: aea.fetchai.fipa.v1_0_0.FipaMessage.Propose_Performative.proposal:type_name -> aea.fetchai.fipa.v1_0_0.FipaMessage.Description\n\t12, // 11: aea.fetchai.fipa.v1_0_0.FipaMessage.Accept_W_Inform_Performative.info:type_name -> aea.fetchai.fipa.v1_0_0.FipaMessage.Accept_W_Inform_Performative.InfoEntry\n\t13, // 12: aea.fetchai.fipa.v1_0_0.FipaMessage.Match_Accept_W_Inform_Performative.info:type_name -> aea.fetchai.fipa.v1_0_0.FipaMessage.Match_Accept_W_Inform_Performative.InfoEntry\n\t14, // 13: aea.fetchai.fipa.v1_0_0.FipaMessage.Inform_Performative.info:type_name -> aea.fetchai.fipa.v1_0_0.FipaMessage.Inform_Performative.InfoEntry\n\t14, // [14:14] is the sub-list for method output_type\n\t14, // [14:14] is the sub-list for method input_type\n\t14, // [14:14] is the sub-list for extension type_name\n\t14, // [14:14] is the sub-list for extension extendee\n\t0,  // [0:14] is the sub-list for field type_name\n}\n\nfunc init() { file_fipa_proto_init() }\nfunc file_fipa_proto_init() {\n\tif File_fipa_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_fipa_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*FipaMessage); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_fipa_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*FipaMessage_Description); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_fipa_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*FipaMessage_Query); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_fipa_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*FipaMessage_Cfp_Performative); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_fipa_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*FipaMessage_Propose_Performative); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_fipa_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*FipaMessage_Accept_W_Inform_Performative); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_fipa_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*FipaMessage_Match_Accept_W_Inform_Performative); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_fipa_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*FipaMessage_Inform_Performative); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_fipa_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*FipaMessage_Accept_Performative); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_fipa_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*FipaMessage_Decline_Performative); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_fipa_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*FipaMessage_Match_Accept_Performative); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_fipa_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*FipaMessage_End_Performative); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\tfile_fipa_proto_msgTypes[0].OneofWrappers = []interface{}{\n\t\t(*FipaMessage_Accept)(nil),\n\t\t(*FipaMessage_AcceptWInform)(nil),\n\t\t(*FipaMessage_Cfp)(nil),\n\t\t(*FipaMessage_Decline)(nil),\n\t\t(*FipaMessage_End)(nil),\n\t\t(*FipaMessage_Inform)(nil),\n\t\t(*FipaMessage_MatchAccept)(nil),\n\t\t(*FipaMessage_MatchAcceptWInform)(nil),\n\t\t(*FipaMessage_Propose)(nil),\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_fipa_proto_rawDesc,\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   15,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_fipa_proto_goTypes,\n\t\tDependencyIndexes: file_fipa_proto_depIdxs,\n\t\tMessageInfos:      file_fipa_proto_msgTypes,\n\t}.Build()\n\tFile_fipa_proto = out.File\n\tfile_fipa_proto_rawDesc = nil\n\tfile_fipa_proto_goTypes = nil\n\tfile_fipa_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "libs/go/aea_end2end/protocols/fipa.proto",
    "content": "syntax = \"proto3\";\n\npackage aea.fetchai.fipa.v1_0_0;\n\noption go_package = \"seller_agent/protocols\";\n\nmessage FipaMessage{\n\n  // Custom Types\n  message Description{\n    bytes description_bytes = 1;\n  }\n\n  message Query{\n    bytes query_bytes = 1;\n  }\n\n\n  // Performatives and contents\n  message Cfp_Performative{\n    Query query = 1;\n  }\n\n  message Propose_Performative{\n    Description proposal = 1;\n  }\n\n  message Accept_W_Inform_Performative{\n    map<string, string> info = 1;\n  }\n\n  message Match_Accept_W_Inform_Performative{\n    map<string, string> info = 1;\n  }\n\n  message Inform_Performative{\n    map<string, string> info = 1;\n  }\n\n  message Accept_Performative{\n  }\n\n  message Decline_Performative{\n  }\n\n  message Match_Accept_Performative{\n  }\n\n  message End_Performative{\n  }\n\n\n  oneof performative{\n    Accept_Performative accept = 5;\n    Accept_W_Inform_Performative accept_w_inform = 6;\n    Cfp_Performative cfp = 7;\n    Decline_Performative decline = 8;\n    End_Performative end = 9;\n    Inform_Performative inform = 10;\n    Match_Accept_Performative match_accept = 11;\n    Match_Accept_W_Inform_Performative match_accept_w_inform = 12;\n    Propose_Performative propose = 13;\n  }\n}\n"
  },
  {
    "path": "libs/go/aea_end2end/protocols/fipa.yaml",
    "content": "---\nname: fipa\nauthor: fetchai\nversion: 1.0.0\ndescription: A protocol for FIPA ACL.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nprotocol_specification_id: fetchai/fipa:1.0.0\nspeech_acts:\n  cfp:\n    query: ct:Query\n  propose:\n    proposal: ct:Description\n  accept_w_inform:\n    info: pt:dict[pt:str, pt:str]\n  match_accept_w_inform:\n    info: pt:dict[pt:str, pt:str]\n  inform:\n    info: pt:dict[pt:str, pt:str]\n  accept: {}\n  decline: {}\n  match_accept: {}\n  end: {}\n...\n---\nct:Query: |\n  bytes query_bytes = 1;\nct:Description: |\n  bytes description_bytes = 1;\n...\n---\ninitiation: [cfp]\nreply:\n  cfp: [propose, decline]\n  propose: [accept, accept_w_inform, decline, propose]\n  accept: [decline, match_accept, match_accept_w_inform]\n  accept_w_inform: [decline, match_accept, match_accept_w_inform]\n  decline: []\n  match_accept: [inform, end]\n  match_accept_w_inform: [inform, end]\n  inform: [inform, end]\n  end: []\ntermination: [decline, end]\nroles: {seller, buyer}\nend_states: [successful, declined_cfp, declined_propose, declined_accept]\nkeep_terminal_state_dialogues: true\n..."
  },
  {
    "path": "libs/go/aea_end2end/run_buyer.sh",
    "content": "#!/bin/bash\nsource fipa_dummy_seller.env\n\nSELLER_ADDR=${AEA_ADDRESS}\naea --registry-path ../../../packages fetch fetchai/fipa_dummy_buyer --local\ncd fipa_dummy_buyer\naea build\naea config set vendor.fetchai.skills.fipa_dummy_buyer.behaviours.initializer.args.opponent_address $SELLER_ADDR\naea generate-key fetchai\naea add-key fetchai\naea add-key fetchai --connection\naea issue-certificates\naea -v DEBUG run\ncd ../\nrm -fr ./fipa_dummy_buyer\n"
  },
  {
    "path": "libs/go/aea_end2end/run_seller.sh",
    "content": "#!/bin/bash\n\ngo build\n\n./seller_agent fipa_dummy_seller.env"
  },
  {
    "path": "libs/go/aea_end2end/test_fipa_end2end.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the end to end test for dialogues on python and golang.\"\"\"\nimport asyncio\nimport os\nimport sys\nfrom pathlib import Path\nfrom tempfile import TemporaryDirectory\nfrom threading import Thread\nfrom typing import Any, Optional, cast\n\nimport pytest\nfrom aea_ledger_fetchai import FetchAICrypto\nfrom pexpect.exceptions import EOF\n\nfrom aea.aea_builder import AEABuilder\nfrom aea.common import Address\nfrom aea.configurations.base import SkillConfig\nfrom aea.helpers.base import cd\nfrom aea.helpers.search.models import Constraint, ConstraintType, Description, Query\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\nfrom aea.skills.base import Handler, Skill, SkillContext\nfrom aea.skills.behaviours import TickerBehaviour\nfrom aea.test_tools.test_cases import AEATestCaseEmpty\nfrom libs.go.aea_end2end.pexpect_popen import PexpectWrapper\n\nfrom packages.fetchai.connections.p2p_libp2p.connection import P2PLibp2pConnection\nfrom packages.fetchai.protocols.fipa.dialogues import FipaDialogue, FipaDialogues\nfrom packages.fetchai.protocols.fipa.message import FipaMessage\n\nfrom tests.common.utils import run_in_thread, wait_for_condition\nfrom tests.conftest import _make_libp2p_connection\n\n\nclass BuyerDialogues(FipaDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, self_address: Address) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param self_address: address of the dialogues maintainer\n        \"\"\"\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return FipaDialogue.Role.BUYER\n\n        FipaDialogues.__init__(\n            self,\n            self_address=self_address,\n            role_from_first_message=role_from_first_message,\n            dialogue_class=FipaDialogue,\n        )\n\n\nclass BuyerBehaviour(TickerBehaviour):\n    \"\"\"Test buyer behaviour.\"\"\"\n\n    addr: str\n\n    def setup(self) -> None:\n        \"\"\"Set up behaviour.\"\"\"\n        self.is_started = False\n        self.was_called = False\n\n    def act(self) -> None:\n        \"\"\"Make an action.\"\"\"\n        dialogues = cast(FipaDialogues, self.context.dialogues)\n        if not self.is_started or self.was_called:\n            return\n\n        cfp_msg, _ = dialogues.create(\n            counterparty=self.addr,\n            performative=FipaMessage.Performative.CFP,\n            query=Query([Constraint(\"something\", ConstraintType(\">\", 1))]),\n        )\n        self.context.outbox.put_message(cfp_msg)\n        self.was_called = True\n        print(\"MESSAGE SENT\")\n\n    def start(self, addr: Address) -> None:\n        \"\"\"Set counterpart address and start sending CFP.\"\"\"\n        self.addr = addr\n        self.is_started = True\n\n\nclass BuyerHandler(Handler):\n    \"\"\"Test BuyerHandler.\"\"\"\n\n    SUPPORTED_PROTOCOL = FipaMessage.protocol_id\n    got_proposal: bool\n\n    def setup(self) -> None:\n        \"\"\"Set up behaviour.\"\"\"\n        self.done = False\n\n    def teardown(self) -> None:\n        \"\"\"Tear down handler.\"\"\"\n\n    def handle(self, message) -> None:\n        \"\"\"Handle an evelope.\"\"\"\n        dialogues = cast(FipaDialogues, self.context.dialogues)\n        if message.performative == FipaMessage.Performative.PROPOSE:\n            buyer_dialogue = dialogues.update(message)\n            if not buyer_dialogue:\n                print(\"error on propose message dialogue update\")\n                return\n            accept_msg = buyer_dialogue.reply(\n                performative=FipaMessage.Performative.ACCEPT, target_message=message\n            )\n            self.context.outbox.put_message(message=accept_msg)\n        elif message.performative == FipaMessage.Performative.MATCH_ACCEPT:\n            buyer_dialogue = dialogues.update(message)\n            if not buyer_dialogue:\n                print(\"error on MATCH_ACCEPT message dialogue update\", message)\n                print(dialogues._dialogues_storage.dialogues_in_active_state)\n                return\n            self.done = True\n            end_msg = buyer_dialogue.reply(\n                performative=FipaMessage.Performative.END, target_message=message\n            )\n            self.context.outbox.put_message(message=end_msg)\n        else:\n            print(\"unsupported performative\", message.performative)\n\n\nclass Base(AEATestCaseEmpty):\n    \"\"\"Base class for test case.\"\"\"\n\n    package_registry_src_rel = Path(os.path.abspath(\"../../../packages\"))\n\n    @classmethod\n    def setup_class(cls) -> None:\n        \"\"\"Setup agent.\"\"\"\n        super(Base, cls).setup_class()\n        cls.add_item(\"connection\", \"fetchai/p2p_libp2p:0.21.0\")\n        cls.add_item(\"protocol\", \"fetchai/fipa:1.0.0\")\n        cls.generate_private_key()\n        cls.add_private_key()\n        cls.add_private_key(connection=True)\n        cls.run_cli_command(\"build\", cwd=cls._get_cwd())\n        cls.run_cli_command(\"issue-certificates\", cwd=cls._get_cwd())\n\n\nROOT = Path(__file__).parent\nENV_FILE_NAME = \"1.env\"\nexec_filename: Path = ROOT / Path(\"seller_agent\")\n\nENV_TEMPLATE = \"\"\"\nexport AEA_LEDGER_ID=\"fetchai\"\nexport AEA_ADDRESS=\"fetch1x9v67meyfq4pkgy2n2yf6797cfkul327kpclqr\"\nexport AEA_PUBLIC_KEY=\"02ac514ba70de60ed5c30f90e3acdfc958ecb416d9676706bf013228abfb2c2816\"\nexport AEA_PRIVATE_KEY=\"6d8d2b87d987641e2ca3f1991c1cccf08a118759e81fabdbf7e8484f27af015e\"\nexport AEA_P2P_POR_SERVICE_ID=\"acn\"\nexport AEA_P2P_POR_LEDGER_ID=\"fetchai\"\nexport AEA_P2P_POR_PEER_PUBKEY=\"{peer_pubkey}\"\nexport AEA_P2P_POR_SIGNATURE=\"{signature}\"\nexport AEA_P2P_DELEGATE_HOST=\"localhost\"\nexport AEA_P2P_DELEGATE_PORT=11234\n\"\"\"\n\n\nclass FipaSellerAgent:\n    \"\"\"Threaded FIPA Seller agent.\"\"\"\n\n    thread: Thread\n    loop: asyncio.AbstractEventLoop\n    proc: PexpectWrapper\n    connection_node: P2PLibp2pConnection\n    temp_dir: Any\n\n    @classmethod\n    def start(cls, multi_addr: Address):\n        \"\"\"Test build example, run, terminate.\"\"\"\n        \"\"\"Run agent.\"\"\"\n        cls.loop = asyncio.new_event_loop()\n        cls.temp_dir = TemporaryDirectory()\n\n        cls.connection_node = _make_libp2p_connection(\n            data_dir=cls.temp_dir.name, delegate=True, entry_peers=[str(multi_addr)]\n        )\n\n        cls.loop.run_until_complete(cls.connection_node.node.start())\n\n        priv_key_file = Path(cls.temp_dir.name) / \"priv_key.txt\"\n        priv_key_file.write_text(\n            \"6d8d2b87d987641e2ca3f1991c1cccf08a118759e81fabdbf7e8484f27af015e\"\n        )\n        crypto = FetchAICrypto(str(priv_key_file))\n        signature = crypto.sign_message(cls.connection_node.node.pub.encode())\n\n        env_file = Path(cls.temp_dir.name) / \"test.env\"\n        env_file.write_text(\n            ENV_TEMPLATE.format(\n                peer_pubkey=cls.connection_node.node.pub, signature=signature\n            )\n        )\n\n        if exec_filename.exists():\n            exec_filename.unlink()\n        proc = PexpectWrapper(  # nosec\n            [\"go\", \"build\"],\n            cwd=str(ROOT),\n            env=os.environ,\n            maxread=10000,\n            encoding=\"utf-8\",\n            logfile=sys.stdout,\n        )\n        proc.expect(pattern=EOF, timeout=30)\n        assert proc.returncode == 0\n        assert exec_filename.exists()\n\n        cls.proc = PexpectWrapper(  # nosec\n            [str(exec_filename), str(env_file)],\n            cwd=str(ROOT),\n            env=os.environ,\n            maxread=10000,\n            encoding=\"utf-8\",\n            logfile=sys.stdout,\n        )\n\n        cls.proc.expect(\"successfully initialized AEA!\", timeout=20)\n        cls.proc.expect(\"successfully started AEA!\", timeout=20)\n\n        return \"fetch1x9v67meyfq4pkgy2n2yf6797cfkul327kpclqr\"\n\n    @classmethod\n    def wait_for_envelope(cls):\n        cls.proc.expect(\"envelope handled successfully\", timeout=20)\n\n    @classmethod\n    def stop(cls):\n        \"\"\"Stop agent and tear down.\"\"\"\n        node_log = Path(cls.temp_dir.name) / \"libp2p_node_10234.log\"\n        print(node_log.read_text())\n        cls.loop.run_until_complete(cls.connection_node.node.stop())\n        cls.proc.terminate()\n        if exec_filename.exists():\n            exec_filename.unlink()\n        cls.temp_dir.cleanup()\n\n\nclass TestFipaEnd2End(Base):\n    \"\"\"Test that echo skill works.\"\"\"\n\n    def test_run(self):\n        \"\"\"Run the echo skill sequence.\"\"\"\n        result = self.invoke(\n            \"get-multiaddress\",\n            \"fetchai\",\n            \"-c\",\n            \"-i\",\n            \"fetchai/p2p_libp2p:0.21.0\",\n            \"-u\",\n            \"public_uri\",\n        )\n        assert result.exit_code == 0\n        multi_addr = result.stdout.strip()\n        result = self.invoke(\"get-address\", \"fetchai\",)\n        assert result.exit_code == 0\n        my_addr = result.stdout.strip()\n        builder = AEABuilder.from_aea_project(self._get_cwd())\n        skill_context = SkillContext()\n        skill_context.dialogues = BuyerDialogues(my_addr)  # type: ignore\n        behaviour = BuyerBehaviour(name=\"behaviour\", skill_context=skill_context)\n        handler = BuyerHandler(name=\"handler\", skill_context=skill_context)\n        test_skill = Skill(\n            SkillConfig(name=\"test_skill\", author=\"fetchai\"),\n            skill_context=skill_context,\n            handlers={\"handler\": handler},\n            behaviours={\"behaviour\": behaviour},\n        )\n        builder.add_component_instance(test_skill)\n        with cd(self._get_cwd()):\n            agent = builder.build()\n            skill_context.set_agent_context(agent.context)\n\n        try:\n            with run_in_thread(agent.start, timeout=120, on_exit=agent.stop):\n                wait_for_condition(lambda: agent.is_running, timeout=30)\n                addr = FipaSellerAgent.start(multi_addr)\n                behaviour.start(addr)\n                wait_for_condition(lambda: behaviour.was_called, timeout=30)\n                wait_for_condition(lambda: handler.done, timeout=30)\n                FipaSellerAgent.proc.expect(\"It's done\", timeout=30)\n        finally:\n            FipaSellerAgent.stop()\n            FipaSellerAgent.proc.wait_eof()\n\n\nif __name__ == \"__main__\":\n    pytest.main([__file__, \"-s\"])\n"
  },
  {
    "path": "libs/go/aealite/Makefile",
    "content": "test:\n\tgo test -p 1 -timeout 0 -count 1 -v ./...\n"
  },
  {
    "path": "libs/go/aealite/README.md",
    "content": "# `aealite`\n\n`aealite` is a lightweight implementation of an AEA library in Golang.\n\n## Usage example\n\n``` golang\npackage main\n\nimport (\n    \"log\"\n    \"os\"\n    \"os/signal\"\n\n    aea \"aealite\"\n    connections \"aealite/connections\"\n)\n\nfunc main() {\n\n    var err error\n\n    // env file\n    if len(os.Args) != 2 {\n        log.Print(\"Usage: main ENV_FILE\")\n        os.Exit(1)\n    }\n    envFile := os.Args[1]\n\n    log.Print(\"Agent starting ...\")\n\n\n    // Create agent\n    agent := aea.Agent{}\n\n    // Set connection\n    agent.Connection = &connections.P2PClientApi{}\n\n    // Initialise agent from environment file (first arg to process)\n    err = agent.InitFromEnv(envFile)\n    if err != nil {\n        log.Fatal(\"Failed to initialise agent\", err)\n    }\n    log.Print(\"successfully initialized AEA!\")\n\n    err = agent.Start()\n    if err != nil {\n        log.Fatal(\"Failed to start agent\", err)\n    }\n    log.Print(\"successfully started AEA!\")\n\n    // // Send envelope to target\n    // agent.Put(envel)\n    // // Print out received envelopes\n    // go func() {\n    //     for envel := range agent.Queue() {\n    //         envelope := envel\n    //         logger.Info().Msgf(\"received envelope: %s\", envelope)\n    //     }\n    // }()\n\n    // Wait until Ctrl+C or a termination call is done.\n    c := make(chan os.Signal, 1)\n    signal.Notify(c, os.Interrupt)\n    <-c\n\n    err = agent.Stop()\n    if err != nil {\n        log.Fatal(\"Failed to stop agent\", err)\n    }\n    log.Print(\"Agent stopped\")\n}\n```\n\n## Development\n\nTo run all tests run:\n\n``` bash\ngo test -p 1 -timeout 0 -count 1 -v ./...\n```\n\nTo lint:\n\n``` bash\ngolines . -w\ngolangci-lint run\n```\n\nTo generate protoc files:\n\n``` bash\ncd ..\nprotoc -I=\"aealite/protocols/\" --go_out=\".\" aealite/protocols/acn.proto\nprotoc -I=\"aealite/protocols/\" --go_out=\".\" aealite/protocols/base.proto\ncd aealite\n```\n"
  },
  {
    "path": "libs/go/aealite/agent.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2019 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\n\npackage aealite\n\nimport (\n\t\"log\"\n\n\tconnections \"aealite/connections\"\n\tprotocols \"aealite/protocols\"\n\twallet \"aealite/wallet\"\n)\n\nconst (\n\tDefaultLedger = \"fetchai\"\n)\n\ntype Agent struct {\n\tWallet     *wallet.Wallet\n\tConnection connections.Connection\n}\n\nfunc (agent *Agent) InitFromEnv(envFile string) error {\n\tif agent.Connection == nil {\n\t\tlog.Fatal(\"Must set connection on agent before calling InitFromEnv().\")\n\t}\n\tagent.Wallet = &wallet.Wallet{}\n\terr := agent.Wallet.InitFromEnv(envFile)\n\tif err != nil {\n\t\tlog.Fatal(\"Error initialising identity.\")\n\t}\n\terr = agent.Connection.InitFromEnv(envFile)\n\tif err != nil {\n\t\tlog.Fatal(\"Error initialising connection.\")\n\t}\n\treturn nil\n}\n\nfunc (agent *Agent) Address() string {\n\treturn agent.Wallet.Address\n}\n\nfunc (agent *Agent) Start() error {\n\treturn agent.Connection.Connect()\n}\n\nfunc (agent *Agent) Put(envelope *protocols.Envelope) error {\n\treturn agent.Connection.Put(envelope)\n}\n\nfunc (agent *Agent) Get() *protocols.Envelope {\n\treturn agent.Connection.Get()\n}\n\nfunc (agent *Agent) Stop() error {\n\terr := agent.Connection.Disconnect()\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\treturn err\n}\n"
  },
  {
    "path": "libs/go/aealite/agent_test.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2019 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\n\npackage aealite\n\nimport (\n\t\"os\"\n\t\"testing\"\n\n\tconnections \"aealite/connections\"\n\tprotocols \"aealite/protocols\"\n)\n\nconst (\n\tEnvTestFile = \"test_env_file.env\"\n)\n\nvar (\n\tledgerId       = \"fetchai\"\n\taddress        = \"fetch1x9v67meyfq4pkgy2n2yf6797cfkul327kpclqr\"\n\tpublicKey      = \"02ac514ba70de60ed5c30f90e3acdfc958ecb416d9676706bf013228abfb2c2816\"\n\tprivateKey     = \"6d8d2b87d987641e2ca3f1991c1cccf08a118759e81fabdbf7e8484f27af015e\"\n\ttestProtocolId = \"test_protocol_id\"\n\ttestMessage    = []byte{0x00}\n)\n\n// TestAgent apis\nfunc TestAgent(t *testing.T) {\n\tos.Args = []string{\"cmd\", EnvTestFile}\n\n\tagent := Agent{}\n\tif agent.Connection != nil {\n\t\tt.Fatal(\"Agent connection not empty\")\n\t}\n\n\t// set p2p client\n\tagent.Connection = &connections.P2PClientApi{}\n\n\t// initialise\n\terr := agent.InitFromEnv(\"test_env_file.env\")\n\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialise agent\", err)\n\t}\n\n\tif agent.Wallet == nil {\n\t\tt.Fatal(\"Wallet not set on Agent\")\n\t}\n\n\tif agent.Wallet.LedgerId != ledgerId {\n\t\tt.Fatal(\"Wallet.LedgerId not set\")\n\t}\n\n\tif agent.Wallet.Address != address {\n\t\tt.Fatal(\"Wallet.Address not set\")\n\t}\n\n\tif agent.Wallet.PublicKey != publicKey {\n\t\tt.Fatal(\"Wallet.PublicKey not set\")\n\t}\n\n\tif agent.Wallet.PrivateKey != privateKey {\n\t\tt.Fatal(\"Wallet.PrivateKey not set\")\n\t}\n\n\tif !agent.Connection.Initialised() {\n\t\tt.Fatal(\"connection not initialised\")\n\t}\n\n\terr = agent.Start()\n\n\tif err != nil {\n\t\tt.Fatal(\"Failed to start agent\", err)\n\t}\n\n\toutEnvelope := &protocols.Envelope{\n\t\tTo:         agent.Address(),\n\t\tSender:     agent.Address(),\n\t\tProtocolId: testProtocolId,\n\t\tMessage:    testMessage,\n\t}\n\n\terr = agent.Put(outEnvelope)\n\n\tif err != nil {\n\t\tt.Fatal(\"Failed to send envelope\", err)\n\t}\n\n\tinEnvelope := agent.Get()\n\n\tif inEnvelope == nil {\n\t\tt.Fatal(\"Failed to get envelope\")\n\t}\n\n\tif (inEnvelope.Sender != outEnvelope.Sender) || (inEnvelope.To != outEnvelope.To) {\n\t\tt.Fatal(\"Envelopes don't match\")\n\t}\n\n\terr = agent.Stop()\n\tif err != nil {\n\t\tt.Fatal(\"Failed to stop agent\", err)\n\t}\n}\n"
  },
  {
    "path": "libs/go/aealite/connections/acn/acn.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2021 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\npackage acn\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/rs/zerolog\"\n\tproto \"google.golang.org/protobuf/proto\"\n)\n\nvar logger zerolog.Logger = zerolog.New(zerolog.ConsoleWriter{\n\tOut:        os.Stdout,\n\tNoColor:    false,\n\tTimeFormat: \"15:04:05.000\",\n}).\n\tWith().Timestamp().\n\tStr(\"package\", \"AeaApiACN\").\n\tLogger()\n\nfunc ignore(err error) {\n\tif err != nil {\n\t\tlogger.Error().Str(\"err\", err.Error()).Msgf(\"IGNORED: %s\", err.Error())\n\t}\n}\n\ntype ACNError struct {\n\tErrorCode Status_ErrCode\n\tErr       error\n}\n\nfunc (err *ACNError) Error() string {\n\treturn err.Err.Error()\n}\n\nfunc DecodeAcnMessage(buf []byte) (string, *AeaEnvelopePerformative, *StatusBody, *ACNError) {\n\tresponse := &AcnMessage{}\n\terr := proto.Unmarshal(buf, response)\n\tmsg_type := \"\"\n\n\tif err != nil {\n\t\tlogger.Error().Str(\"err\", err.Error()).Msgf(\"while decoding acn message\")\n\t\treturn msg_type, nil, nil, &ACNError{ErrorCode: ERROR_DECODE, Err: err}\n\t}\n\t// response is either a LookupResponse or Status\n\tvar aeaEnvelope *AeaEnvelopePerformative = nil\n\tvar status *StatusBody = nil\n\n\tswitch pl := response.Performative.(type) {\n\tcase *AeaEnvelope:\n\t\taeaEnvelope = pl.AeaEnvelope\n\t\tmsg_type = \"aea_envelope\"\n\tcase *Status:\n\t\tstatus = pl.Status.Body\n\t\tmsg_type = \"status\"\n\tdefault:\n\t\terr = fmt.Errorf(\"unexpected ACN Message: %s\", response)\n\t\tlogger.Error().Msg(err.Error())\n\t\treturn msg_type, nil, nil, &ACNError{ErrorCode: ERROR_UNEXPECTED_PAYLOAD, Err: err}\n\t}\n\treturn msg_type, aeaEnvelope, status, nil\n}\n\nfunc WaitForStatus(ch chan *StatusBody, timeout time.Duration) (*StatusBody, error) {\n\tselect {\n\tcase m := <-ch:\n\t\treturn m, nil\n\tcase <-time.After(timeout):\n\t\terr := errors.New(\"ACN send acknowledge timeout\")\n\t\tlogger.Error().Msg(err.Error())\n\t\treturn nil, err\n\t}\n}\n\nfunc SendAcnSuccess(pipe Pipe) error {\n\tstatus := &StatusBody{Code: SUCCESS}\n\tperformative := &StatusPerformative{Body: status}\n\tmsg := &AcnMessage{\n\t\tPerformative: &Status{Status: performative},\n\t}\n\tbuf, err := proto.Marshal(msg)\n\tif err != nil {\n\t\tlogger.Error().Str(\"err\", err.Error()).Msgf(\"error on encoding acn status message\")\n\t\treturn err\n\t}\n\terr = pipe.Write(buf)\n\tif err != nil {\n\t\tlogger.Error().Str(\"err\", err.Error()).Msgf(\"error on sending acn status message\")\n\n\t}\n\treturn err\n}\n\nfunc SendAcnError(pipe Pipe, error_msg string, err_codes ...Status_ErrCode) error {\n\tvar err_code Status_ErrCode\n\n\tif len(err_codes) == 0 {\n\t\terr_code = ERROR_GENERIC\n\t} else {\n\t\terr_code = err_codes[0]\n\t}\n\n\tstatus := &StatusBody{Code: err_code, Msgs: []string{error_msg}}\n\tmsg := &AcnMessage{\n\t\tPerformative: &Status{Status: &StatusPerformative{Body: status}},\n\t}\n\tbuf, err := proto.Marshal(msg)\n\tif err != nil {\n\t\tlogger.Error().Str(\"err\", err.Error()).Msgf(\"error on encoding acn status message\")\n\t\treturn err\n\t}\n\terr = pipe.Write(buf)\n\tif err != nil {\n\t\tlogger.Error().Str(\"err\", err.Error()).Msgf(\"error on sending acn status message\")\n\t}\n\treturn err\n}\n\nfunc EncodeAcnEnvelope(envelope_bytes []byte, record *AgentRecord) ([]byte, error) {\n\tvar performative *AeaEnvelopePerformative\n\tif record != nil {\n\t\tperformative = &AeaEnvelopePerformative{Envelope: envelope_bytes, Record: record}\n\t} else {\n\t\tperformative = &AeaEnvelopePerformative{Envelope: envelope_bytes}\n\t}\n\n\tmsg := &AcnMessage{\n\t\tPerformative: &AeaEnvelope{AeaEnvelope: performative},\n\t}\n\n\tbuf, err := proto.Marshal(msg)\n\tif err != nil {\n\t\tlogger.Error().\n\t\t\tStr(\"err\", err.Error()).\n\t\t\tMsgf(\"while serializing envelope bytes: %s\", envelope_bytes)\n\t}\n\treturn buf, err\n}\n\ntype StatusQueue interface {\n\tAddAcnStatusMessage(status *StatusBody, counterpartyID string)\n}\n\nfunc ReadAgentRegistrationMessage(pipe Pipe) (*RegisterPerformative, error) {\n\tvar register *RegisterPerformative\n\tbuf, err := pipe.Read()\n\tif err != nil {\n\t\tlogger.Error().Str(\"err\", err.Error()).Msgf(\"while receiving agent's registration request\")\n\t\treturn nil, err\n\t}\n\n\tmsg := &AcnMessage{}\n\terr = proto.Unmarshal(buf, msg)\n\tif err != nil {\n\t\tlogger.Error().Str(\"err\", err.Error()).Msgf(\"couldn't deserialize acn registration message\")\n\t\t// TOFIX(LR) setting Msgs to err.Error is potentially a security vulnerability\n\t\tacn_send_error := SendAcnError(pipe, err.Error(), ERROR_DECODE)\n\t\tignore(acn_send_error)\n\t\treturn nil, err\n\t}\n\n\tswitch pl := msg.Performative.(type) {\n\tcase *Register:\n\t\tregister = pl.Register\n\tdefault:\n\t\terr = errors.New(\"unexpected payload\")\n\t\tacn_send_error := SendAcnError(pipe, err.Error(), ERROR_UNEXPECTED_PAYLOAD)\n\t\tignore(acn_send_error)\n\t\treturn nil, err\n\t}\n\treturn register, nil\n}\n\nfunc SendEnvelopeMessageAndWaitForStatus(\n\tpipe Pipe,\n\tenvelope_bytes []byte,\n\tacn_status_chan chan *StatusBody,\n\tacnStatusTimeout time.Duration,\n) error {\n\terr := SendEnvelopeMessage(pipe, envelope_bytes, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tstatus, err := WaitForStatus(acn_status_chan, acnStatusTimeout)\n\tif err != nil {\n\t\tlogger.Error().\n\t\t\tStr(\"err\", err.Error()).\n\t\t\tMsgf(\"on envelope sent status wait\")\n\t\treturn err\n\t}\n\tif status.Code != SUCCESS {\n\t\tlogger.Error().\n\t\t\tStr(\"op\", \"send_envelope\").\n\t\t\tMsgf(\"acn confirmation status is not Status Success: %d.\", status.Code)\n\t\treturn fmt.Errorf(\n\t\t\t\"send envelope: acn confirmation status is not Status Success: %d\",\n\t\t\tstatus.Code,\n\t\t)\n\t}\n\treturn err\n\n}\n\nfunc ReadLookupRequest(pipe Pipe) (string, error) {\n\tbuf, err := pipe.Read()\n\n\tif err != nil {\n\t\tlogger.Error().Str(\"err\", err.Error()).Msgf(\"while reading message from stream\")\n\t\treturn \"\", err\n\t}\n\n\tmsg := &AcnMessage{}\n\terr = proto.Unmarshal(buf, msg)\n\tif err != nil {\n\t\tlogger.Error().\n\t\t\tStr(\"err\", err.Error()).\n\t\t\tMsgf(\"couldn't deserialize acn lookup request message\")\n\t\t// TOFIX(LR) setting Msgs to err.Error is potentially a security vulnerability\n\t\tacn_send_error := SendAcnError(pipe, err.Error(), ERROR_DECODE)\n\t\tignore(acn_send_error)\n\t\treturn \"\", err\n\t}\n\n\t// Get LookupRequest message\n\tvar lookupRequest *LookupRequestPerformative\n\tswitch pl := msg.Performative.(type) {\n\tcase *LookupRequest:\n\t\tlookupRequest = pl.LookupRequest\n\tdefault:\n\t\terr = errors.New(\"unexpected payload\")\n\t\tacn_send_error := SendAcnError(pipe, err.Error(), ERROR_UNEXPECTED_PAYLOAD)\n\t\tignore(acn_send_error)\n\t\treturn \"\", err\n\t}\n\n\treqAddress := lookupRequest.AgentAddress\n\treturn reqAddress, nil\n}\n\nfunc SendLookupRequest(pipe Pipe, address string) error {\n\tlookupRequest := &LookupRequestPerformative{AgentAddress: address}\n\tmsg := &AcnMessage{\n\t\tPerformative: &LookupRequest{LookupRequest: lookupRequest},\n\t}\n\tbuf, err := proto.Marshal(msg)\n\tif err != nil {\n\t\treturn err\n\t}\n\terr = pipe.Write([]byte(buf))\n\treturn err\n}\n\nfunc ReadLookupResponse(pipe Pipe) (*AgentRecord, error) {\n\tbuf, err := pipe.Read()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tresponse := &AcnMessage{}\n\terr = proto.Unmarshal(buf, response)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tvar lookupResponse *LookupResponsePerformative = nil\n\tvar status *StatusPerformative = nil\n\tswitch pl := response.Performative.(type) {\n\tcase *LookupResponse:\n\t\tlookupResponse = pl.LookupResponse\n\tcase *Status:\n\t\tstatus = pl.Status\n\tdefault:\n\t\terr = errors.New(\"unexpected Acn Message\")\n\t\tlogger.Error().Str(\"err\", err.Error()).Msgf(\"couldn't deserialize acn lookup response message\")\n\t\treturn nil, err\n\t}\n\n\tif status != nil {\n\t\terr = errors.New(\n\t\t\t\"Failed agent lookup response \" + status.Body.Code.String() + \" : \" + strings.Join(\n\t\t\t\tstatus.Body.Msgs,\n\t\t\t\t\":\",\n\t\t\t),\n\t\t)\n\t\treturn nil, err\n\t}\n\treturn lookupResponse.Record, nil\n}\n\nfunc SendLookupResponse(pipe Pipe, record *AgentRecord) error {\n\tlookupResponse := &LookupResponsePerformative{Record: record}\n\tresponse := &AcnMessage{\n\t\tPerformative: &LookupResponse{LookupResponse: lookupResponse},\n\t}\n\tbuf, err := proto.Marshal(response)\n\tif err != nil {\n\t\treturn err\n\t}\n\terr = pipe.Write(buf)\n\treturn err\n}\n\nfunc SendEnvelopeMessage(pipe Pipe, envelope_bytes []byte, record *AgentRecord) error {\n\tacnMsgBytes, err := EncodeAcnEnvelope(envelope_bytes, record)\n\tif err != nil {\n\t\treturn err\n\t}\n\terr = pipe.Write(acnMsgBytes)\n\tif err != nil {\n\t\tlogger.Error().\n\t\t\tStr(\"err\", err.Error()).\n\t\t\tMsgf(\"on pipe write\")\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc SendAgentRegisterMessage(pipe Pipe, agentRecord *AgentRecord) error {\n\tregistration := &RegisterPerformative{Record: agentRecord}\n\tmsg := &AcnMessage{\n\t\tPerformative: &Register{Register: registration},\n\t}\n\tbuf, err := proto.Marshal(msg)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\terr = pipe.Write(buf)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tstatus, err := ReadAcnStatus(pipe)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif status.Code != SUCCESS {\n\t\treturn errors.New(\"Registration failed: \" + strings.Join(status.Msgs, \":\"))\n\t}\n\treturn nil\n}\n\nfunc ReadAcnStatus(pipe Pipe) (*StatusBody, error) {\n\tbuf, err := pipe.Read()\n\tif err != nil {\n\t\tlogger.Error().\n\t\t\tStr(\"err\", err.Error()).\n\t\t\tMsgf(\"on pipe read\")\n\t\treturn nil, err\n\t}\n\n\tresponse := &AcnMessage{}\n\terr = proto.Unmarshal(buf, response)\n\tif err != nil {\n\t\tlogger.Error().\n\t\t\tStr(\"err\", err.Error()).\n\t\t\tMsgf(\"on acn decode\")\n\t\treturn nil, err\n\t}\n\n\t// response is expected to be a Status\n\tvar status *StatusPerformative\n\tswitch pl := response.Performative.(type) {\n\tcase *Status:\n\t\tstatus = pl.Status\n\tdefault:\n\t\terr = errors.New(\"unexpected Acn Message\")\n\t\treturn nil, err\n\t}\n\n\treturn status.Body, nil\n}\n\nfunc ReadEnvelopeMessage(pipe Pipe) (*AeaEnvelopePerformative, error) {\n\tbuf, err := pipe.Read()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tmessageType, envelope, _, acnErr := DecodeAcnMessage(buf)\n\n\tif acnErr != nil {\n\t\terr = SendAcnError(\n\t\t\tpipe,\n\t\t\tacnErr.Error(),\n\t\t\tacnErr.ErrorCode,\n\t\t)\n\t\tignore(err)\n\t\treturn nil, acnErr.Err\n\t}\n\tif messageType != \"aea_envelope\" {\n\t\treturn nil, errors.New(\"unexpected payload for acn message\")\n\t}\n\treturn envelope, nil\n}\n\nfunc PerformAddressLookup(pipe Pipe, address string) (*AgentRecord, error) {\n\terr := SendLookupRequest(pipe, address)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn ReadLookupResponse(pipe)\n}\n"
  },
  {
    "path": "libs/go/aealite/connections/acn/pipe_iface.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2021 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\npackage acn\n\ntype Pipe interface {\n\tConnect() error\n\tRead() ([]byte, error)\n\tWrite(data []byte) error\n\t//Close() error\n}\n"
  },
  {
    "path": "libs/go/aealite/connections/acn/protocol.go",
    "content": "package acn\n\nimport acn_protocol \"aealite/protocols/acn/v1_0_0\"\n\ntype StatusBody = acn_protocol.AcnMessage_StatusBody\ntype AgentRecord = acn_protocol.AcnMessage_AgentRecord\ntype AcnMessage = acn_protocol.AcnMessage\ntype LookupRequest = acn_protocol.AcnMessage_LookupRequest\ntype LookupResponse = acn_protocol.AcnMessage_LookupResponse\ntype Status = acn_protocol.AcnMessage_Status\ntype LookupRequestPerformative = acn_protocol.AcnMessage_Lookup_Request_Performative\ntype LookupResponsePerformative = acn_protocol.AcnMessage_Lookup_Response_Performative\ntype StatusPerformative = acn_protocol.AcnMessage_Status_Performative\ntype RegisterPerformative = acn_protocol.AcnMessage_Register_Performative\ntype Register = acn_protocol.AcnMessage_Register\ntype AeaEnvelope = acn_protocol.AcnMessage_AeaEnvelope\ntype AeaEnvelopePerformative = acn_protocol.AcnMessage_Aea_Envelope_Performative\n\nconst ERROR_DECODE = acn_protocol.AcnMessage_StatusBody_ERROR_DECODE\nconst SUCCESS = acn_protocol.AcnMessage_StatusBody_SUCCESS\nconst ERROR_UNEXPECTED_PAYLOAD = acn_protocol.AcnMessage_StatusBody_ERROR_UNEXPECTED_PAYLOAD\nconst ERROR_AGENT_NOT_READY = acn_protocol.AcnMessage_StatusBody_ERROR_AGENT_NOT_READY\nconst ERROR_UNKNOWN_AGENT_ADDRESS = acn_protocol.AcnMessage_StatusBody_ERROR_UNKNOWN_AGENT_ADDRESS\nconst ERROR_GENERIC = acn_protocol.AcnMessage_StatusBody_ERROR_GENERIC\nconst ERROR_WRONG_AGENT_ADDRESS = acn_protocol.AcnMessage_StatusBody_ERROR_WRONG_AGENT_ADDRESS\nconst ERROR_UNSUPPORTED_LEDGER = acn_protocol.AcnMessage_StatusBody_ERROR_UNSUPPORTED_LEDGER\nconst ERROR_WRONG_PUBLIC_KEY = acn_protocol.AcnMessage_StatusBody_ERROR_WRONG_PUBLIC_KEY\nconst ERROR_INVALID_PROOF = acn_protocol.AcnMessage_StatusBody_ERROR_INVALID_PROOF\n\ntype Status_ErrCode = acn_protocol.AcnMessage_StatusBody_StatusCodeEnum\n"
  },
  {
    "path": "libs/go/aealite/connections/connections.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2019 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\n\npackage connections\n\nimport (\n\tprotocols \"aealite/protocols\"\n)\n\ntype Socket interface {\n\tConnect() error\n\tRead() ([]byte, error)\n\tWrite(data []byte) error\n\tDisconnect() error\n}\n\ntype Connection interface {\n\tInitFromEnv(envFile string) error\n\tConnect() error\n\tGet() *protocols.Envelope\n\tPut(envelope *protocols.Envelope) error\n\tDisconnect() error\n\tInitialised() bool\n}\n"
  },
  {
    "path": "libs/go/aealite/connections/p2pclient.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2019 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\n\npackage connections\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"log\"\n\t\"math\"\n\t\"math/rand\"\n\t\"os\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\tprotocols \"aealite/protocols\"\n\twallet \"aealite/wallet\"\n\n\tacn \"aealite/connections/acn\"\n\n\t\"github.com/joho/godotenv\"\n\t\"github.com/rs/zerolog\"\n\tproto \"google.golang.org/protobuf/proto\"\n)\n\nconst retryAttempts = 5\nconst acnStatusTimeout = 5 * time.Second\n\nvar logger zerolog.Logger = zerolog.New(zerolog.ConsoleWriter{\n\tOut:        os.Stdout,\n\tNoColor:    false,\n\tTimeFormat: \"15:04:05.000\",\n}).\n\tWith().Timestamp().\n\tStr(\"package\", \"P2PClientApi\").\n\tLogger()\n\nvar (\n\tDefaultAttempts      = uint(10)\n\tDefaultOnRetry       = func(n uint, err error) {}\n\tDefaultRetryIf       = IsRecoverable\n\tDefaultDelay         = 500 * time.Millisecond\n\tDefaultMaxJitter     = 100 * time.Millisecond\n\tDefaultDelayType     = CombineDelay(BackOffDelay, RandomDelay)\n\tDefaultLastErrorOnly = false\n\tDefaultContext       = context.Background()\n\tMaxDelay             = 1000 * time.Millisecond\n)\n\ntype P2PClientConfig struct {\n\thost string\n\tport uint16\n}\n\ntype P2PClientApi struct {\n\tclientConfig *P2PClientConfig\n\tagentRecord  *acn.AgentRecord\n\n\tsocket   Socket\n\toutQueue chan *protocols.Envelope\n\n\tclosing     bool\n\tconnected   bool\n\tinitialised bool\n\n\tacn_status_chan chan *acn.StatusBody\n}\n\nfunc (client *P2PClientApi) InitFromEnv(envFile string) error {\n\tzerolog.TimeFieldFormat = time.RFC3339Nano\n\n\tif client.connected {\n\t\treturn nil\n\t}\n\tclient.connected = false\n\tclient.initialised = false\n\n\tlogger.Debug().Msgf(\"env_file: %s\", envFile)\n\terr := godotenv.Overload(envFile)\n\tif err != nil {\n\t\tlog.Fatal(\"Error loading env file\")\n\t}\n\taddress := os.Getenv(\"AEA_ADDRESS\")\n\tpublicKey := os.Getenv(\"AEA_PUBLIC_KEY\")\n\tagentRecord := &acn.AgentRecord{Address: address, PublicKey: publicKey}\n\tagentRecord.ServiceId = os.Getenv(\"AEA_P2P_POR_SERVICE_ID\")\n\tagentRecord.LedgerId = os.Getenv(\"AEA_P2P_POR_LEDGER_ID\")\n\tagentRecord.PeerPublicKey = os.Getenv(\"AEA_P2P_POR_PEER_PUBKEY\")\n\tagentRecord.Signature = os.Getenv(\"AEA_P2P_POR_SIGNATURE\")\n\tok, err := wallet.VerifyLedgerSignature(\n\t\tagentRecord.LedgerId,\n\t\t[]byte(agentRecord.PeerPublicKey),\n\t\tagentRecord.Signature,\n\t\tagentRecord.PublicKey,\n\t)\n\tif err != nil {\n\t\tlog.Fatal(\"Could not verify signature.\" + err.Error())\n\t}\n\tif !ok {\n\t\tlog.Fatal(\"Invalid signature.\")\n\t}\n\tclient.agentRecord = agentRecord\n\thost := os.Getenv(\"AEA_P2P_DELEGATE_HOST\")\n\tport := os.Getenv(\"AEA_P2P_DELEGATE_PORT\")\n\tportConv, err := strconv.ParseUint(port, 10, 16)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tclient.clientConfig = &P2PClientConfig{host: host, port: uint16(portConv)}\n\n\tclient.socket = NewSocket(client.clientConfig.host, client.clientConfig.port, client.agentRecord.PeerPublicKey)\n\tclient.initialised = true\n\treturn nil\n}\n\nfunc (client *P2PClientApi) Put(envelope *protocols.Envelope) error {\n\n\tenvelopeBytes, err := proto.Marshal(envelope)\n\tif err != nil {\n\t\tlogger.Error().Str(\"err\", err.Error()).Msgf(\"while serializing envelope: %s\", envelope)\n\t\treturn err\n\t}\n\treturn acn.SendEnvelopeMessageAndWaitForStatus(client.socket, envelopeBytes, client.acn_status_chan, acnStatusTimeout)\n\n}\n\nfunc (client *P2PClientApi) Get() *protocols.Envelope {\n\treturn <-client.outQueue\n}\n\nfunc (client *P2PClientApi) Queue() <-chan *protocols.Envelope {\n\treturn client.outQueue\n}\n\nfunc (client *P2PClientApi) Connected() bool {\n\treturn client.connected\n}\n\nfunc (client *P2PClientApi) Initialised() bool {\n\treturn client.initialised\n}\n\nfunc (client *P2PClientApi) Disconnect() error {\n\tclient.closing = true\n\terr := client.stop()\n\tif err != nil {\n\t\tlogger.Error().Str(\"err\", err.Error()).\n\t\t\tMsg(\"error while disconnecting P2PClientApi\")\n\t\treturn err\n\t}\n\tclose(client.outQueue)\n\tclose(client.acn_status_chan)\n\tclient.connected = false\n\treturn nil\n}\n\nfunc (client *P2PClientApi) Connect() error {\n\terr := client.socket.Connect()\n\tif err != nil {\n\t\tlogger.Error().Str(\"err\", err.Error()).\n\t\t\tMsg(\"while connecting to socket\")\n\t\treturn err\n\t}\n\n\terr = client.registerWithRetry()\n\tif err != nil {\n\t\tlogger.Error().Str(\"err\", err.Error()).\n\t\t\tMsg(\"while registering with retry to p2p node\")\n\t\terr_ := client.stop()\n\t\tif err_ != nil {\n\t\t\tlogger.Error().Str(\"err\", err_.Error()).\n\t\t\t\tMsg(\"while handling other error\")\n\t\t}\n\t\treturn err\n\t}\n\tlogger.Info().Msg(\"successfully registered on node\")\n\n\tclient.closing = false\n\tclient.outQueue = make(chan *protocols.Envelope, 10)\n\tclient.acn_status_chan = make(chan *acn.StatusBody, 10)\n\tgo client.listenForEnvelopes()\n\tlogger.Info().Msg(\"connected to p2p node\")\n\n\tclient.connected = true\n\n\treturn nil\n}\n\nfunc (client *P2PClientApi) registerWithRetry() error {\n\tvar n uint\n\n\t//default\n\tconfig := &Config{\n\t\tattempts:      DefaultAttempts,\n\t\tdelay:         DefaultDelay,\n\t\tmaxJitter:     DefaultMaxJitter,\n\t\tonRetry:       DefaultOnRetry,\n\t\tretryIf:       DefaultRetryIf,\n\t\tdelayType:     DefaultDelayType,\n\t\tlastErrorOnly: DefaultLastErrorOnly,\n\t\tcontext:       DefaultContext,\n\t}\n\n\tvar errorLog = make(Error, 1)\n\tcontext_ := context.Background()\n\n\tlastErrIndex := n\n\tfor n < retryAttempts {\n\t\terr := client.register()\n\n\t\tif err != nil {\n\t\t\terrorLog[lastErrIndex] = unpackUnrecoverable(err)\n\n\t\t\t// if this is last attempt - don't wait\n\t\t\tif n == retryAttempts-1 {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tdelayTime := config.delayType(n, err, config)\n\t\t\tif config.maxDelay > 0 && delayTime > config.maxDelay {\n\t\t\t\tdelayTime = config.maxDelay\n\t\t\t}\n\n\t\t\tselect {\n\t\t\tcase <-time.After(delayTime):\n\t\t\tcase <-context_.Done():\n\t\t\t\treturn context_.Err()\n\t\t\t}\n\n\t\t} else {\n\t\t\treturn nil\n\t\t}\n\n\t\tn++\n\t}\n\treturn errorLog\n}\n\nfunc (client *P2PClientApi) register() error {\n\treturn acn.SendAgentRegisterMessage(client.socket, client.agentRecord)\n}\n\nfunc (client *P2PClientApi) listenForEnvelopes() {\n\tfor {\n\t\tenvel, err := client.HandleAcnMessageFromPipe()\n\n\t\tif err != nil && !client.closing {\n\t\t\tlogger.Error().Str(\"err\", err.Error()).Msg(\"while receiving envelope\")\n\t\t\tlogger.Info().Msg(\"disconnecting\")\n\t\t\tif !client.closing {\n\t\t\t\terr_ := client.stop()\n\t\t\t\tif err_ != nil {\n\t\t\t\t\tlogger.Error().Str(\"err\", err_.Error()).Msg(\"while handling other error\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn\n\t\t}\n\t\tif envel == nil {\n\t\t\t// got acn status, not an envelope\n\t\t\tcontinue\n\t\t}\n\t\tif envel.To != client.agentRecord.Address {\n\t\t\tlogger.Error().\n\t\t\t\tStr(\"err\", \"To (\"+envel.To+\") must match registered address\").\n\t\t\t\tMsg(\"while processing envelope\")\n\t\t\tcontinue\n\t\t}\n\t\tlogger.Debug().Msgf(\"received envelope for agent\")\n\t\tclient.outQueue <- envel\n\t\tif client.closing {\n\t\t\treturn\n\t\t}\n\t}\n}\n\nfunc (client *P2PClientApi) stop() error {\n\treturn client.socket.Disconnect()\n}\n\n// Error type represents list of errors in retry\ntype Error []error\n\n// Error method return string representation of Error\n// Implements error interface\nfunc (e Error) Error() string {\n\tlogWithNumber := make([]string, lenWithoutNil(e))\n\tfor i, l := range e {\n\t\tif l != nil {\n\t\t\tlogWithNumber[i] = fmt.Sprintf(\"#%d: %s\", i+1, l.Error())\n\t\t}\n\t}\n\n\treturn fmt.Sprintf(\"All attempts fail:\\n%s\", strings.Join(logWithNumber, \"\\n\"))\n}\n\nfunc lenWithoutNil(e Error) (count int) {\n\tfor _, v := range e {\n\t\tif v != nil {\n\t\t\tcount++\n\t\t}\n\t}\n\n\treturn\n}\n\n// WrappedErrors returns the list of errors that this Error is wrapping.\nfunc (e Error) WrappedErrors() []error {\n\treturn e\n}\n\ntype unrecoverableError struct {\n\terror\n}\n\n// Unrecoverable wraps an error in `unrecoverableError` struct\nfunc Unrecoverable(err error) error {\n\treturn unrecoverableError{err}\n}\n\n// IsRecoverable checks if error is an instance of `unrecoverableError`\nfunc IsRecoverable(err error) bool {\n\t_, isUnrecoverable := err.(unrecoverableError)\n\treturn !isUnrecoverable\n}\n\nfunc unpackUnrecoverable(err error) error {\n\tif unrecoverable, isUnrecoverable := err.(unrecoverableError); isUnrecoverable {\n\t\treturn unrecoverable.error\n\t}\n\n\treturn err\n}\n\n// DelayTypeFunc is called to return the next delay to wait after the retriable function fails on `err` after `n` attempts.\ntype DelayTypeFunc func(n uint, err error, config *Config) time.Duration\n\n// Function signature of retry if function\ntype RetryIfFunc func(error) bool\n\n// Function signature of OnRetry function\n// n = count of attempts\ntype OnRetryFunc func(n uint, err error)\n\ntype Config struct {\n\tattempts      uint\n\tdelay         time.Duration\n\tmaxDelay      time.Duration\n\tmaxJitter     time.Duration\n\tonRetry       OnRetryFunc\n\tretryIf       RetryIfFunc\n\tdelayType     DelayTypeFunc\n\tlastErrorOnly bool\n\tcontext       context.Context\n\n\tmaxBackOffN uint\n}\n\n// CombineDelay is a DelayType the combines all of the specified delays into a new DelayTypeFunc\nfunc CombineDelay(delays ...DelayTypeFunc) DelayTypeFunc {\n\tconst maxInt64 = uint64(math.MaxInt64)\n\n\treturn func(n uint, err error, config *Config) time.Duration {\n\t\tvar total uint64\n\t\tfor _, delay := range delays {\n\t\t\ttotal += uint64(delay(n, err, config))\n\t\t\tif total > maxInt64 {\n\t\t\t\ttotal = maxInt64\n\t\t\t}\n\t\t}\n\n\t\treturn time.Duration(total)\n\t}\n}\n\n// BackOffDelay is a DelayType which increases delay between consecutive retries\nfunc BackOffDelay(n uint, _ error, config *Config) time.Duration {\n\t// 1 << 63 would overflow signed int64 (time.Duration), thus 62.\n\tconst max uint = 62\n\n\tif config.maxBackOffN == 0 {\n\t\tif config.delay <= 0 {\n\t\t\tconfig.delay = 1\n\t\t}\n\n\t\tconfig.maxBackOffN = max - uint(math.Floor(math.Log2(float64(config.delay))))\n\t}\n\n\tif n > config.maxBackOffN {\n\t\tn = config.maxBackOffN\n\t}\n\n\treturn config.delay << n\n}\n\n// RandomDelay is a DelayType which picks a random delay up to config.maxJitter\nfunc RandomDelay(_ uint, _ error, config *Config) time.Duration {\n\treturn time.Duration(rand.Int63n(int64(config.maxJitter)))\n}\n\nfunc (client *P2PClientApi) HandleAcnMessageFromPipe() (*protocols.Envelope, error) {\n\tpipe := client.socket\n\tenvelope := &protocols.Envelope{}\n\tvar acn_err error\n\n\tdata, err := pipe.Read()\n\n\tif err != nil {\n\n\t\treturn nil, err\n\t}\n\n\tmsg_type, acn_envelope, status, acnErr := acn.DecodeAcnMessage(data)\n\n\tif acnErr != nil {\n\t\tlogger.Error().Str(\"err\", acnErr.Error()).Msg(\"while handling acn message\")\n\t\tacn_err = acn.SendAcnError(\n\t\t\tpipe,\n\t\t\tacnErr.Error(),\n\t\t\tacnErr.ErrorCode,\n\t\t)\n\t\tif acn_err != nil {\n\t\t\tlogger.Error().Str(\"err\", acn_err.Error()).Msg(\"on acn send error\")\n\t\t}\n\t\treturn envelope, acnErr\n\t}\n\n\tswitch msg_type {\n\tcase \"aea_envelope\":\n\t\t{\n\t\t\terr = proto.Unmarshal(acn_envelope.Envelope, envelope)\n\t\t\tif err != nil {\n\t\t\t\tlogger.Error().Str(\"err\", err.Error()).Msg(\"while decoding envelope\")\n\t\t\t\tacn_err = acn.SendAcnError(\n\t\t\t\t\tpipe,\n\t\t\t\t\t\"error on decoding envelope\",\n\t\t\t\t\tacn.ERROR_DECODE,\n\t\t\t\t)\n\t\t\t\tif acn_err != nil {\n\t\t\t\t\tlogger.Error().Str(\"err\", acn_err.Error()).Msg(\"on acn send error\")\n\t\t\t\t}\n\t\t\t\treturn envelope, err\n\t\t\t}\n\t\t\terr = acn.SendAcnSuccess(pipe)\n\t\t\treturn envelope, err\n\n\t\t}\n\tcase \"status\":\n\t\t{\n\t\t\tlogger.Debug().Msgf(\"got acn status %d\", status.Code)\n\t\t\tclient.acn_status_chan <- status\n\t\t\treturn nil, nil\n\n\t\t}\n\tdefault:\n\t\t{\n\t\t\tacn_err = acn.SendAcnError(pipe, \"Unsupported ACN message\")\n\t\t\tif acn_err != nil {\n\t\t\t\tlogger.Error().Str(\"err\", acn_err.Error()).Msg(\"on acn send error\")\n\t\t\t}\n\t\t\treturn nil, errors.New(\"unsupported ACN message\")\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "libs/go/aealite/connections/p2pclient_test.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2019 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\n\npackage connections\n\nimport (\n\t\"os\"\n\t\"testing\"\n)\n\nconst (\n\tEnvTestFile = \"../test_env_file.env\"\n)\n\nvar (\n\taddress             = \"fetch1x9v67meyfq4pkgy2n2yf6797cfkul327kpclqr\"\n\tpublic_key          = \"02ac514ba70de60ed5c30f90e3acdfc958ecb416d9676706bf013228abfb2c2816\"\n\tpor_service_id      = \"acn\"\n\tpor_ledger_id       = \"fetchai\"\n\tpor_peer_public_key = \"0217a59bd805c310aca4febe0e99ce22ee3712ae085dc1e5630430b1e15a584bb7\"\n\tpor_signature       = \"avzHfL/fjMidvweJJKjtBUiqJ2+6aDUq8MoNRBi9nDI/lWleIX3ftRf6Sx5UWmxcS0SW03IVrf1iKTXA5zeA0g==\"\n\tdelegate_host       = \"acn.fetch.ai\"\n\tdelegate_port       = uint16(11000)\n)\n\n// TestP2PClientApiInit\nfunc TestP2PClientApiInit(t *testing.T) {\n\tos.Args = []string{\"cmd\", EnvTestFile}\n\n\tclient := &P2PClientApi{}\n\n\t// initialise\n\terr := client.InitFromEnv(EnvTestFile)\n\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialise client\", err)\n\t}\n\n\tif client.clientConfig == nil {\n\t\tt.Fatal(\"client_config not set\", err)\n\t}\n\n\tif client.clientConfig.host != delegate_host {\n\t\tt.Fatal(\"client_config.host not set\", err)\n\t}\n\n\tif client.clientConfig.port != delegate_port {\n\t\tt.Fatal(\"client_config.port not set\", err)\n\t}\n\n\tif client.agentRecord == nil {\n\t\tt.Fatal(\"client.agent_record not set\")\n\t}\n\n\tif client.agentRecord.ServiceId != por_service_id {\n\t\tt.Fatal(\"agent_record.ServiceId not set\")\n\t}\n\n\tif client.agentRecord.LedgerId != por_ledger_id {\n\t\tt.Fatal(\"agent_record.LedgerId not set\")\n\t}\n\n\tif client.agentRecord.Address != address {\n\t\tt.Fatal(\"agent_record.Address not set\")\n\t}\n\n\tif client.agentRecord.PublicKey != public_key {\n\t\tt.Fatal(\"agent_record.PublicKey not set\")\n\t}\n\n\tif client.agentRecord.PeerPublicKey != por_peer_public_key {\n\t\tt.Fatal(\"agent_record.PublicKey not set\")\n\t}\n\n\tif client.agentRecord.Signature != por_signature {\n\t\tt.Fatal(\"agent_record.Signature not set\")\n\t}\n\n\tif client.socket == nil {\n\t\tt.Fatal(\"client.socket not set\")\n\t}\n\n\tif !client.initialised {\n\t\tt.Fatal(\"client not initialised\")\n\t}\n\n\tif client.connected {\n\t\tt.Fatal(\"client connected\")\n\t}\n\n\terr = client.Connect()\n\n\tif err != nil {\n\t\tt.Fatal(\"client connect failed\")\n\t}\n\n\tif !client.connected {\n\t\tt.Fatal(\"client not connected\")\n\t}\n\n\terr = client.Disconnect()\n\n\tif err != nil {\n\t\tt.Fatal(\"client disconnect failed\")\n\t}\n\n\tif client.connected {\n\t\tt.Fatal(\"client connected\")\n\t}\n}\n"
  },
  {
    "path": "libs/go/aealite/connections/tcpsocket.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2019 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\n\npackage connections\n\nimport (\n\twallet \"aealite/wallet\"\n\t\"crypto/ecdsa\"\n\t\"crypto/elliptic\"\n\t\"crypto/tls\"\n\t\"crypto/x509\"\n\t\"encoding/binary\"\n\t\"errors\"\n\t\"strconv\"\n)\n\ntype TCPSocketChannel struct {\n\taddress       string\n\tport          uint16\n\tconn          *tls.Conn\n\tpeerPublicKey string\n}\n\nfunc (sock *TCPSocketChannel) Connect() error {\n\tvar err error\n\tconf := &tls.Config{\n\t\tInsecureSkipVerify: true,\n\t}\n\n\tsock.conn, err = tls.Dial(\"tcp\", sock.address+\":\"+strconv.FormatInt(int64(sock.port), 10), conf)\n\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tstate := sock.conn.ConnectionState()\n\tvar cert *x509.Certificate\n\n\tfor _, v := range state.PeerCertificates {\n\t\tcert = v\n\t}\n\n\tpub := cert.PublicKey.(*ecdsa.PublicKey)\n\tpublicKeyBytes := elliptic.Marshal(pub.Curve, pub.X, pub.Y)\n\n\tsignature, err := sock.Read()\n\tlogger.Debug().Msgf(\"got signature %d bytes\", len(signature))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tpubkey, err := wallet.PubKeyFromFetchAIPublicKey(sock.peerPublicKey)\n\tif err != nil {\n\t\treturn err\n\t}\n\tok, err := pubkey.Verify(publicKeyBytes, signature)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif !ok {\n\t\treturn errors.New(\"tls signature check failed\")\n\n\t}\n\treturn nil\n}\n\nfunc (sock *TCPSocketChannel) Read() ([]byte, error) {\n\tbuf := make([]byte, 4)\n\t_, err := sock.conn.Read(buf)\n\tif err != nil {\n\t\treturn buf, err\n\t}\n\tsize := binary.BigEndian.Uint32(buf)\n\n\tbuf = make([]byte, size)\n\t_, err = sock.conn.Read(buf)\n\treturn buf, err\n}\n\nfunc (sock *TCPSocketChannel) Write(data []byte) error {\n\tsize := uint32(len(data))\n\tbuf := make([]byte, 4, 4+size)\n\tbinary.BigEndian.PutUint32(buf, size)\n\tbuf = append(buf, data...)\n\t_, err := sock.conn.Write(buf)\n\tlogger.Debug().Msgf(\"wrote data to pipe: %d bytes\", size)\n\treturn err\n}\n\nfunc (sock *TCPSocketChannel) Disconnect() error {\n\treturn sock.conn.Close()\n}\n\nfunc NewSocket(address string, port uint16, peerPublicKey string) Socket {\n\treturn &TCPSocketChannel{address: address, port: port, peerPublicKey: peerPublicKey}\n}\n"
  },
  {
    "path": "libs/go/aealite/go.mod",
    "content": "module aealite\n\ngo 1.14\n\nrequire (\n\tgithub.com/btcsuite/btcd v0.21.0-beta\n\tgithub.com/btcsuite/btcutil v1.0.2\n\tgithub.com/ethereum/go-ethereum v1.10.17\n\tgithub.com/golang/protobuf v1.4.3\n\tgithub.com/joho/godotenv v1.3.0\n\tgithub.com/libp2p/go-libp2p-core v0.8.5\n\tgithub.com/multiformats/go-multiaddr v0.3.1 // indirect\n\tgithub.com/rs/zerolog v1.20.0\n\tgolang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2\n\tgoogle.golang.org/protobuf v1.25.0\n\tgotest.tools v2.2.0+incompatible\n)\n"
  },
  {
    "path": "libs/go/aealite/go.sum",
    "content": "cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ncloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ncloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=\ncloud.google.com/go v0.43.0/go.mod h1:BOSR3VbTLkk6FDC/TcffxP4NF/FFBGA5ku+jvKOP7pg=\ncloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=\ncloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=\ncloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=\ncloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=\ncloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=\ncloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw=\ncloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=\ncloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=\ncloud.google.com/go/bigtable v1.2.0/go.mod h1:JcVAOl45lrTmQfLj7T6TxyMzIN/3FGGcFm+2xVAli2o=\ncloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=\ncloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=\ncloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=\ncloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=\ncloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=\ncollectd.org v0.3.0/go.mod h1:A/8DzQBkF6abtvrT2j/AU/4tiBgJWYyh0y/oB/4MlWE=\ndmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=\ngithub.com/Azure/azure-sdk-for-go/sdk/azcore v0.21.1/go.mod h1:fBF9PQNqB8scdgpZ3ufzaLntG0AG7C1WjPMsiFOmfHM=\ngithub.com/Azure/azure-sdk-for-go/sdk/internal v0.8.3/go.mod h1:KLF4gFr6DcKFZwSuH8w8yEK6DpFl3LP5rhdvAb7Yz5I=\ngithub.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0/go.mod h1:tPaiy8S5bQ+S5sOiDlINkp7+Ef339+Nz5L5XO+cnOHo=\ngithub.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=\ngithub.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=\ngithub.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=\ngithub.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=\ngithub.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=\ngithub.com/VictoriaMetrics/fastcache v1.6.0/go.mod h1:0qHz5QP0GMX4pfmMA/zt5RgfNuXJrTP0zS7DqpHGGTw=\ngithub.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=\ngithub.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=\ngithub.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=\ngithub.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=\ngithub.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM=\ngithub.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=\ngithub.com/apache/arrow/go/arrow v0.0.0-20191024131854-af6fa24be0db/go.mod h1:VTxUBvSJ3s3eHAg65PNgrsn5BtqCRPdmyXh6rAfdxN0=\ngithub.com/aws/aws-sdk-go-v2 v1.2.0/go.mod h1:zEQs02YRBw1DjK0PoJv3ygDYOFTre1ejlJWl8FwAuQo=\ngithub.com/aws/aws-sdk-go-v2/config v1.1.1/go.mod h1:0XsVy9lBI/BCXm+2Tuvt39YmdHwS5unDQmxZOYe8F5Y=\ngithub.com/aws/aws-sdk-go-v2/credentials v1.1.1/go.mod h1:mM2iIjwl7LULWtS6JCACyInboHirisUUdkBPoTHMOUo=\ngithub.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.0.2/go.mod h1:3hGg3PpiEjHnrkrlasTfxFqUsZ2GCk/fMUn4CbKgSkM=\ngithub.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.0.2/go.mod h1:45MfaXZ0cNbeuT0KQ1XJylq8A6+OpVV2E5kvY/Kq+u8=\ngithub.com/aws/aws-sdk-go-v2/service/route53 v1.1.1/go.mod h1:rLiOUrPLW/Er5kRcQ7NkwbjlijluLsrIbu/iyl35RO4=\ngithub.com/aws/aws-sdk-go-v2/service/sso v1.1.1/go.mod h1:SuZJxklHxLAXgLTc1iFXbEWkXs7QRTQpCLGaKIprQW0=\ngithub.com/aws/aws-sdk-go-v2/service/sts v1.1.1/go.mod h1:Wi0EBZwiz/K44YliU0EKxqTCJGUfYTWXrrBwkq736bM=\ngithub.com/aws/smithy-go v1.1.0/go.mod h1:EzMw8dbp/YJL4A5/sbhGddag+NPT7q084agLbB9LgIw=\ngithub.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=\ngithub.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=\ngithub.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40/go.mod h1:8rLXio+WjiTceGBHIoTvn60HIbs7Hm7bcHjyrSqYB9c=\ngithub.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=\ngithub.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=\ngithub.com/btcsuite/btcd v0.21.0-beta h1:At9hIZdJW0s9E/fAz28nrz6AmcNlSVucCH796ZteX1M=\ngithub.com/btcsuite/btcd v0.21.0-beta/go.mod h1:ZSWyehm27aAuS9bvkATT+Xte3hjHZ+MRgMY/8NJ7K94=\ngithub.com/btcsuite/btcd/btcec/v2 v2.1.2 h1:YoYoC9J0jwfukodSBMzZYUVQ8PTiYg4BnOWiJVzTmLs=\ngithub.com/btcsuite/btcd/btcec/v2 v2.1.2/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE=\ngithub.com/btcsuite/btcd/chaincfg/chainhash v1.0.0 h1:MSskdM4/xJYcFzy0altH/C/xHopifpWzHUi1JeVI34Q=\ngithub.com/btcsuite/btcd/chaincfg/chainhash v1.0.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=\ngithub.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=\ngithub.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=\ngithub.com/btcsuite/btcutil v1.0.2 h1:9iZ1Terx9fMIOtq1VrwdqfsATL9MC2l8ZrUY6YZ2uts=\ngithub.com/btcsuite/btcutil v1.0.2/go.mod h1:j9HUFwoQRsZL3V4n+qG+CUnEGHOarIxfC3Le2Yhbcts=\ngithub.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg=\ngithub.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY=\ngithub.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I=\ngithub.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc=\ngithub.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc=\ngithub.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY=\ngithub.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs=\ngithub.com/c-bata/go-prompt v0.2.2/go.mod h1:VzqtzE2ksDBcdln8G7mk2RX9QyGjH+OVqOCSiVIqS34=\ngithub.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=\ngithub.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s=\ngithub.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=\ngithub.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=\ngithub.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=\ngithub.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=\ngithub.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=\ngithub.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=\ngithub.com/cloudflare/cloudflare-go v0.14.0/go.mod h1:EnwdgGMaFOruiPZRFSgn+TsQ3hQ7C/YWzIGLeu5c304=\ngithub.com/consensys/bavard v0.1.8-0.20210406032232-f3452dc9b572/go.mod h1:Bpd0/3mZuaj6Sj+PqrmIquiOKy397AKGThQPaGzNXAQ=\ngithub.com/consensys/gnark-crypto v0.4.1-0.20210426202927-39ac3d4b3f1f/go.mod h1:815PAHg3wvysy0SyIqanF8gZ0Y1wjk/hrDHD/iT88+Q=\ngithub.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=\ngithub.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=\ngithub.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=\ngithub.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=\ngithub.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4=\ngithub.com/dave/jennifer v1.2.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg=\ngithub.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/deckarep/golang-set v1.8.0/go.mod h1:5nI87KwE7wgsBU1F4GKAw2Qod7p5kyS383rP6+o6qqo=\ngithub.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0=\ngithub.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc=\ngithub.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc=\ngithub.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs=\ngithub.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218=\ngithub.com/deepmap/oapi-codegen v1.6.0/go.mod h1:ryDa9AgbELGeB+YEXE1dR53yAjHwFvE9iAUlWl9Al3M=\ngithub.com/deepmap/oapi-codegen v1.8.2/go.mod h1:YLgSKSDv/bZQB7N4ws6luhozi3cEdRktEqrX88CvjIw=\ngithub.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=\ngithub.com/dgryski/go-bitstream v0.0.0-20180413035011-3522498ce2c8/go.mod h1:VMaSuZ+SZcx/wljOQKvp5srsbCiKDEb6K2wC4+PiBmQ=\ngithub.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=\ngithub.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=\ngithub.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko=\ngithub.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=\ngithub.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=\ngithub.com/dop251/goja v0.0.0-20211011172007-d99e4b8cbf48/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk=\ngithub.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7/go.mod h1:hn7BA7c8pLvoGndExHudxTDKZ84Pyvv+90pbBjbTz0Y=\ngithub.com/eclipse/paho.mqtt.golang v1.2.0/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7joQ8SYLhZwfeOo6Ts=\ngithub.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=\ngithub.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=\ngithub.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=\ngithub.com/ethereum/go-ethereum v1.10.17 h1:XEcumY+qSr1cZQaWsQs5Kck3FHB0V2RiMHPdTBJ+oT8=\ngithub.com/ethereum/go-ethereum v1.10.17/go.mod h1:Lt5WzjM07XlXc95YzrhosmR4J9Ahd6X2wyEV2SvGhk0=\ngithub.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=\ngithub.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0=\ngithub.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=\ngithub.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=\ngithub.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=\ngithub.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww=\ngithub.com/getkin/kin-openapi v0.53.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4=\ngithub.com/getkin/kin-openapi v0.61.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4=\ngithub.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=\ngithub.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE=\ngithub.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24=\ngithub.com/go-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJpoZOs=\ngithub.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=\ngithub.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=\ngithub.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=\ngithub.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=\ngithub.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=\ngithub.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8=\ngithub.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=\ngithub.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=\ngithub.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg=\ngithub.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=\ngithub.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=\ngithub.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=\ngithub.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=\ngithub.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=\ngithub.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=\ngithub.com/golang-jwt/jwt/v4 v4.3.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=\ngithub.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=\ngithub.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=\ngithub.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=\ngithub.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=\ngithub.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=\ngithub.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=\ngithub.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=\ngithub.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=\ngithub.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=\ngithub.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=\ngithub.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=\ngithub.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=\ngithub.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=\ngithub.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=\ngithub.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=\ngithub.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM=\ngithub.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=\ngithub.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=\ngithub.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=\ngithub.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=\ngithub.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219/go.mod h1:/X8TswGSh1pIozq4ZwCfxS0WA5JGXguxk94ar/4c87Y=\ngithub.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=\ngithub.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=\ngithub.com/google/flatbuffers v1.11.0/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=\ngithub.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=\ngithub.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=\ngithub.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=\ngithub.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M=\ngithub.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=\ngithub.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=\ngithub.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=\ngithub.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=\ngithub.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=\ngithub.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=\ngithub.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=\ngithub.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=\ngithub.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=\ngithub.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=\ngithub.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=\ngithub.com/graph-gophers/graphql-go v1.3.0/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc=\ngithub.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0=\ngithub.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=\ngithub.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=\ngithub.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=\ngithub.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA=\ngithub.com/holiman/uint256 v1.2.0/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw=\ngithub.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=\ngithub.com/huin/goupnp v1.0.3-0.20220313090229-ca81a64b4204/go.mod h1:ZxNlw5WqJj6wSsRK5+YfflQGXYfccj5VgQsMNixHM7Y=\ngithub.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o=\ngithub.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=\ngithub.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=\ngithub.com/influxdata/flux v0.65.1/go.mod h1:J754/zds0vvpfwuq7Gc2wRdVwEodfpCFM7mYlOw2LqY=\ngithub.com/influxdata/influxdb v1.8.3/go.mod h1:JugdFhsvvI8gadxOI6noqNeeBHvWNTbfYGtiAn+2jhI=\ngithub.com/influxdata/influxdb-client-go/v2 v2.4.0/go.mod h1:vLNHdxTJkIf2mSLvGrpj8TCcISApPoXkaxP8g9uRlW8=\ngithub.com/influxdata/influxql v1.1.1-0.20200828144457-65d3ef77d385/go.mod h1:gHp9y86a/pxhjJ+zMjNXiQAA197Xk9wLxaz+fGG+kWk=\ngithub.com/influxdata/line-protocol v0.0.0-20180522152040-32c6aa80de5e/go.mod h1:4kt73NQhadE3daL3WhR5EJ/J2ocX0PZzwxQ0gXJ7oFE=\ngithub.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo=\ngithub.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo=\ngithub.com/influxdata/promql/v2 v2.12.0/go.mod h1:fxOPu+DY0bqCTCECchSRtWfc+0X19ybifQhZoQNF5D8=\ngithub.com/influxdata/roaring v0.4.13-0.20180809181101-fc520f41fab6/go.mod h1:bSgUQ7q5ZLSO+bKBGqJiCBGAl+9DxyW63zLTujjUlOE=\ngithub.com/influxdata/tdigest v0.0.0-20181121200506-bf2b5ad3c0a9/go.mod h1:Js0mqiSBE6Ffsg94weZZ2c+v/ciT8QRHFOap7EKDrR0=\ngithub.com/influxdata/usage-client v0.0.0-20160829180054-6d3895376368/go.mod h1:Wbbw6tYNvwa5dlB6304Sd+82Z3f7PmVZHVKU637d4po=\ngithub.com/ipfs/go-cid v0.0.7 h1:ysQJVJA3fNDF1qigJbsSQOdjhVLsOEoPdh0+R97k3jY=\ngithub.com/ipfs/go-cid v0.0.7/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I=\ngithub.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=\ngithub.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA=\ngithub.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4=\ngithub.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e/go.mod h1:G1CVv03EnqU1wYL2dFwXxW2An0az9JTl/ZsqXQeBlkU=\ngithub.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=\ngithub.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=\ngithub.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=\ngithub.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=\ngithub.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=\ngithub.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=\ngithub.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=\ngithub.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=\ngithub.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=\ngithub.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=\ngithub.com/jsternberg/zap-logfmt v1.0.0/go.mod h1:uvPs/4X51zdkcm5jXl5SYoN+4RK21K8mysFmDaM/h+o=\ngithub.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=\ngithub.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=\ngithub.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=\ngithub.com/jwilder/encoding v0.0.0-20170811194829-b4e1701a28ef/go.mod h1:Ct9fl0F6iIOGgxJ5npU/IUOhOhqlVrGjyIZc8/MagT0=\ngithub.com/karalabe/usb v0.0.2/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU=\ngithub.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=\ngithub.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=\ngithub.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=\ngithub.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=\ngithub.com/klauspost/cpuid v0.0.0-20170728055534-ae7887de9fa5/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=\ngithub.com/klauspost/crc32 v0.0.0-20161016154125-cb6bfca970f6/go.mod h1:+ZoRqAPRLkC4NPOvfYeR5KNOrY6TD+/sAC3HXPZgDYg=\ngithub.com/klauspost/pgzip v1.0.2-0.20170402124221-0bf5dcad4ada/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=\ngithub.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=\ngithub.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=\ngithub.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=\ngithub.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=\ngithub.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=\ngithub.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=\ngithub.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=\ngithub.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=\ngithub.com/labstack/echo/v4 v4.2.1/go.mod h1:AA49e0DZ8kk5jTOOCKNuPR6oTnBS0dYiM4FW1e6jwpg=\ngithub.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=\ngithub.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8=\ngithub.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=\ngithub.com/libp2p/go-buffer-pool v0.0.2 h1:QNK2iAFa8gjAe1SPz6mHSMuCcjs+X1wlHzeOSqcmlfs=\ngithub.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoRZd1Vi32+RXyFM=\ngithub.com/libp2p/go-flow-metrics v0.0.3/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs=\ngithub.com/libp2p/go-libp2p-core v0.8.5 h1:aEgbIcPGsKy6zYcC+5AJivYFedhYa4sW7mIpWpUaLKw=\ngithub.com/libp2p/go-libp2p-core v0.8.5/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8=\ngithub.com/libp2p/go-maddr-filter v0.1.0/go.mod h1:VzZhTXkMucEGGEOSKddrwGiOv0tUhgnKqNEmIAz/bPU=\ngithub.com/libp2p/go-msgio v0.0.6/go.mod h1:4ecVB6d9f4BDSL5fqvPiC4A3KivjWn+Venn/1ALLMWA=\ngithub.com/libp2p/go-openssl v0.0.7 h1:eCAzdLejcNVBzP/iZM9vqHnQm+XyCEbSSIheIPRGNsw=\ngithub.com/libp2p/go-openssl v0.0.7/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc=\ngithub.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=\ngithub.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=\ngithub.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ=\ngithub.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=\ngithub.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=\ngithub.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=\ngithub.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=\ngithub.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=\ngithub.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=\ngithub.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=\ngithub.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=\ngithub.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=\ngithub.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=\ngithub.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=\ngithub.com/mattn/go-tty v0.0.0-20180907095812-13ff1204f104/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE=\ngithub.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=\ngithub.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g=\ngithub.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ=\ngithub.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=\ngithub.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU=\ngithub.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=\ngithub.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=\ngithub.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4=\ngithub.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=\ngithub.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=\ngithub.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8=\ngithub.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8=\ngithub.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=\ngithub.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o=\ngithub.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=\ngithub.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg=\ngithub.com/multiformats/go-base32 v0.0.3 h1:tw5+NhuwaOjJCC5Pp82QuXbrmLzWg7uxlMFp8Nq/kkI=\ngithub.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA=\ngithub.com/multiformats/go-base36 v0.1.0 h1:JR6TyF7JjGd3m6FbLU2cOxhC0Li8z8dLNGQ89tUg4F4=\ngithub.com/multiformats/go-base36 v0.1.0/go.mod h1:kFGE83c6s80PklsHO9sRn2NCoffoRdUUOENyW/Vv6sM=\ngithub.com/multiformats/go-multiaddr v0.2.2/go.mod h1:NtfXiOtHvghW9KojvtySjH5y0u0xW5UouOmQQrn6a3Y=\ngithub.com/multiformats/go-multiaddr v0.3.0/go.mod h1:dF9kph9wfJ+3VLAaeBqo9Of8x4fJxp6ggJGteB8HQTI=\ngithub.com/multiformats/go-multiaddr v0.3.1 h1:1bxa+W7j9wZKTZREySx1vPMs2TqrYWjVZ7zE6/XLG1I=\ngithub.com/multiformats/go-multiaddr v0.3.1/go.mod h1:uPbspcUPd5AfaP6ql3ujFY+QWzmBD8uLLL4bXW0XfGc=\ngithub.com/multiformats/go-multiaddr-net v0.2.0/go.mod h1:gGdH3UXny6U3cKKYCvpXI5rnK7YaOIEOPVDI9tsJbEA=\ngithub.com/multiformats/go-multibase v0.0.3 h1:l/B6bJDQjvQ5G52jw4QGSYeOTZoAwIO77RblWplfIqk=\ngithub.com/multiformats/go-multibase v0.0.3/go.mod h1:5+1R4eQrT3PkYZ24C3W2Ue2tPwIdYQD509ZjSb5y9Oc=\ngithub.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc=\ngithub.com/multiformats/go-multihash v0.0.14 h1:QoBceQYQQtNUuf6s7wHxnE2c8bhbMqhfGzNI032se/I=\ngithub.com/multiformats/go-multihash v0.0.14/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc=\ngithub.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=\ngithub.com/multiformats/go-varint v0.0.6 h1:gk85QWKxh3TazbLxED/NlDVv8+q+ReFJk7Y2W/KhfNY=\ngithub.com/multiformats/go-varint v0.0.6/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=\ngithub.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=\ngithub.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0=\ngithub.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E=\ngithub.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=\ngithub.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=\ngithub.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=\ngithub.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=\ngithub.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=\ngithub.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=\ngithub.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=\ngithub.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=\ngithub.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=\ngithub.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=\ngithub.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=\ngithub.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=\ngithub.com/opentracing/opentracing-go v1.0.3-0.20180606204148-bd9c31933947/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=\ngithub.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=\ngithub.com/paulbellamy/ratecounter v0.2.0/go.mod h1:Hfx1hDpSGoqxkVVpBi/IlYD7kChlfo5C6hzIHwPqfFE=\ngithub.com/peterh/liner v1.0.1-0.20180619022028-8c1271fcf47f/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc=\ngithub.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0=\ngithub.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=\ngithub.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=\ngithub.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=\ngithub.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pkg/term v0.0.0-20180730021639-bffc007b7fd5/go.mod h1:eCbImbZ95eXtAUIbLAuAVnBnwf83mjf6QIVH8SHYwqQ=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=\ngithub.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=\ngithub.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=\ngithub.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=\ngithub.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=\ngithub.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=\ngithub.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=\ngithub.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=\ngithub.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=\ngithub.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=\ngithub.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=\ngithub.com/retailnext/hllpp v1.0.1-0.20180308014038-101a6d2f8b52/go.mod h1:RDpi1RftBQPUCDRw6SmxeaREsAaRKnOclghuzp/WRzc=\ngithub.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho=\ngithub.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=\ngithub.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=\ngithub.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=\ngithub.com/rs/zerolog v1.20.0 h1:38k9hgtUBdxFwE34yS8rTHmHBa4eN16E4DJlv177LNs=\ngithub.com/rs/zerolog v1.20.0/go.mod h1:IzD0RJ65iWH0w97OQQebJEvTZYvsCUm9WVLWBQrJRjo=\ngithub.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=\ngithub.com/segmentio/kafka-go v0.1.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo=\ngithub.com/segmentio/kafka-go v0.2.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo=\ngithub.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=\ngithub.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=\ngithub.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=\ngithub.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=\ngithub.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=\ngithub.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=\ngithub.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 h1:RC6RW7j+1+HkWaX/Yh71Ee5ZHaHYt7ZP4sQgUrm6cDU=\ngithub.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w0SWMsp6j9O/dk4/ZpIhL+3CkG8ofA2vuv7k+ltqUMc=\ngithub.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=\ngithub.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=\ngithub.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=\ngithub.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=\ngithub.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=\ngithub.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=\ngithub.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q=\ngithub.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/testify v1.2.0/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=\ngithub.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=\ngithub.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=\ngithub.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=\ngithub.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=\ngithub.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc=\ngithub.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=\ngithub.com/tklauser/go-sysconf v0.3.5/go.mod h1:MkWzOF4RMCshBAMXuhXJs64Rte09mITnppBXY/rYEFI=\ngithub.com/tklauser/numcpus v0.2.2/go.mod h1:x3qojaO3uyYt0i56EW/VUYs7uBvdl2fkfZFu0T9wgjM=\ngithub.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs=\ngithub.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=\ngithub.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=\ngithub.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=\ngithub.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=\ngithub.com/willf/bitset v1.1.3/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=\ngithub.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg=\ngithub.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngo.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=\ngo.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=\ngo.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=\ngo.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=\ngo.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=\ngo.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=\ngo.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=\ngolang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=\ngolang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=\ngolang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=\ngolang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20190909091759-094676da4a83/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=\ngolang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 h1:It14KIkyBFYkHkwZ7k45minvA9aorojkyjGk9KJ5B/w=\ngolang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=\ngolang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=\ngolang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=\ngolang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=\ngolang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=\ngolang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=\ngolang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=\ngolang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=\ngolang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=\ngolang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=\ngolang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=\ngolang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=\ngolang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=\ngolang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=\ngolang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=\ngolang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=\ngolang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=\ngolang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=\ngolang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=\ngolang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=\ngolang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=\ngolang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=\ngolang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=\ngolang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=\ngolang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=\ngolang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=\ngolang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=\ngolang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=\ngolang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=\ngolang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=\ngolang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=\ngolang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=\ngolang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=\ngolang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=\ngolang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200107162124-548cf772de50/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210316164454-77fc1eacc6aa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210420205809-ac73e9fd8988/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210816183151-1e6c022a8912 h1:uCLL3g5wH2xjxVREVuAbP9JM5PPKjRbXKRa6IBjkzmU=\ngolang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=\ngolang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=\ngolang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=\ngolang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=\ngolang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=\ngolang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=\ngolang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=\ngolang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=\ngolang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=\ngolang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=\ngolang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=\ngolang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=\ngolang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=\ngolang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=\ngolang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=\ngolang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20190828213141-aed303cbaa74/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200108203644-89082a384178/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=\ngolang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=\ngolang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo=\ngonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo=\ngonum.org/v1/gonum v0.6.0/go.mod h1:9mxDZsDKxgMAuccQkewq682L+0eCu4dCN2yonUJTCLU=\ngonum.org/v1/netlib v0.0.0-20181029234149-ec6d1f5cefe6/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw=\ngonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw=\ngonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc=\ngoogle.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=\ngoogle.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=\ngoogle.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=\ngoogle.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=\ngoogle.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=\ngoogle.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=\ngoogle.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=\ngoogle.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=\ngoogle.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=\ngoogle.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=\ngoogle.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=\ngoogle.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=\ngoogle.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=\ngoogle.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190716160619-c506a9f90610/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=\ngoogle.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=\ngoogle.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=\ngoogle.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=\ngoogle.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20200108215221-bd8f9a0ef82f/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=\ngoogle.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=\ngoogle.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=\ngoogle.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=\ngoogle.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=\ngoogle.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=\ngoogle.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=\ngoogle.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=\ngoogle.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=\ngoogle.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=\ngoogle.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=\ngoogle.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=\ngoogle.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=\ngoogle.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=\ngoogle.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=\ngoogle.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=\ngoogle.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=\ngopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=\ngopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=\ngopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=\ngopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c=\ngopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns=\ngopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=\ngopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0=\ngopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=\ngopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=\ngotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=\nhonnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=\nhonnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las=\nrsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=\nrsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=\n"
  },
  {
    "path": "libs/go/aealite/helpers/base.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2019 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\n\npackage helpers\n\n// Generic a generic type (every type implements at least zero methods).\ntype Generic interface{}\n\n/*\nSet implementation of a set of generic types.\nIt uses the built-in 'map' type, which is\nbased on hash tables:\n    https://golang.org/src/runtime/map.go\nThis guarantees (amortized) constant-time complexity\nfor addition, deletion, and lookup.\n*/\ntype Set struct {\n\tcontainer map[Generic]bool // container: a private container.\n}\n\n//AddFromArray adds elements to the set from an array\nfunc (set *Set) AddFromArray(array []Generic) {\n\tfor _, element := range array {\n\t\tset.Add(element)\n\t}\n}\n\n// ToArray gives an array of 'interface{}' built from the set.\nfunc (set *Set) ToArray() []interface{} {\n\tkeys := make([]interface{}, 0, len(set.container))\n\tfor k := range set.container {\n\t\tkeys = append(keys, k)\n\t}\n\treturn keys\n}\n\n// Add adds an element.\nfunc (set *Set) Add(element Generic) {\n\tset.container[element] = true\n}\n\n// Remove removes an element.\nfunc (set *Set) Remove(element Generic) {\n\tdelete(set.container, element)\n}\n\n// Contains checks an element is in the set.\nfunc (set *Set) Contains(element Generic) bool {\n\tval, ok := set.container[element]\n\treturn val && ok\n}\n\n// Size returns the size of the set.\nfunc (set *Set) Size() int {\n\treturn len(set.container)\n}\n\n// Copy instantiate a new copy of the set.\nfunc (set *Set) Copy() Set {\n\tnewSet := NewSet()\n\tfor element := range set.container {\n\t\tnewSet.Add(element)\n\t}\n\treturn newSet\n}\n\n// Difference computes the difference from set 1 to set 2\nfunc Difference(set1 Set, set2 Set) Set {\n\tresult := set1.Copy()\n\tfor element := range set2.container {\n\t\tresult.Remove(element)\n\t}\n\treturn result\n}\n\n// NewSet returns a new set.\nfunc NewSet() Set {\n\tresult := Set{}\n\tresult.container = make(map[Generic]bool)\n\treturn result\n}\n\n// NewSetFromArray returns a new set initialized from an array.\nfunc NewSetFromArray(array []interface{}) Set {\n\tresult := NewSet()\n\tresult.AddFromArray(fromInterfaceToGenericArray(array))\n\treturn result\n}\n\nfunc fromInterfaceToGenericArray(array []interface{}) []Generic {\n\tnewArray := make([]Generic, len(array))\n\tfor index, element := range array {\n\t\tnewArray[index] = element\n\t}\n\treturn newArray\n}\n"
  },
  {
    "path": "libs/go/aealite/helpers/base_test.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2019 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\n\npackage helpers\n\nimport (\n\t\"testing\"\n)\n\nfunc checkExpectedSize(t *testing.T, set *Set, expectedSize int) {\n\tif actualSize := set.Size(); actualSize != expectedSize {\n\t\tt.Fatalf(\"expected size %d, got %d\", expectedSize, actualSize)\n\t}\n}\n\nfunc checkIn(t *testing.T, set *Set, element Generic) {\n\tif !set.Contains(element) {\n\t\tt.Fatalf(\"expected to find element %s, but not found it\", element)\n\t}\n}\nfunc checkNotIn(t *testing.T, set *Set, element Generic) {\n\tif set.Contains(element) {\n\t\tt.Fatalf(\"expected to find element %s, but not found it\", element)\n\t}\n}\n\nfunc TestSet(t *testing.T) {\n\tset := NewSet()\n\n\telement1 := \"hello\"\n\telement2 := 42\n\telement3 := struct {\n\t\tName    string\n\t\tSurname string\n\t}{\"Alan\", \"Turing\"}\n\n\tcheckNotIn(t, &set, element1)\n\tcheckNotIn(t, &set, element2)\n\tcheckNotIn(t, &set, element3)\n\tcheckExpectedSize(t, &set, 0)\n\n\tset.Add(element1)\n\tcheckIn(t, &set, element1)\n\tcheckNotIn(t, &set, element2)\n\tcheckNotIn(t, &set, element3)\n\tcheckExpectedSize(t, &set, 1)\n\n\tset.Add(element2)\n\tset.Add(element3)\n\tcheckIn(t, &set, element1)\n\tcheckIn(t, &set, element2)\n\tcheckIn(t, &set, element3)\n\tcheckExpectedSize(t, &set, 3)\n\n\tset.Remove(element1)\n\tset.Remove(element2)\n\tset.Remove(element3)\n\tcheckNotIn(t, &set, element1)\n\tcheckNotIn(t, &set, element2)\n\tcheckNotIn(t, &set, element3)\n\tcheckExpectedSize(t, &set, 0)\n}\n\nfunc TestSetFromArray(t *testing.T) {\n\telements := []interface{}{\"hello\", 42, \"world\", \"world\"}\n\tset := NewSetFromArray(elements)\n\n\texpectedSize := 3\n\tactualSize := set.Size()\n\tif expectedSize != actualSize {\n\t\tt.Fatalf(\"expected %v, found %v\", expectedSize, actualSize)\n\t}\n}\n"
  },
  {
    "path": "libs/go/aealite/protocols/acn/v1_0_0/acn.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.25.0\n// \tprotoc        v3.11.4\n// source: acn.proto\n\npackage aea_aea_acn_v1_0_0\n\nimport (\n\tproto \"github.com/golang/protobuf/proto\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// This is a compile-time assertion that a sufficiently up-to-date version\n// of the legacy proto package is being used.\nconst _ = proto.ProtoPackageIsVersion4\n\ntype AcnMessage_StatusBody_StatusCodeEnum int32\n\nconst (\n\t// common (0x)\n\tAcnMessage_StatusBody_SUCCESS                   AcnMessage_StatusBody_StatusCodeEnum = 0\n\tAcnMessage_StatusBody_ERROR_UNSUPPORTED_VERSION AcnMessage_StatusBody_StatusCodeEnum = 1\n\tAcnMessage_StatusBody_ERROR_UNEXPECTED_PAYLOAD  AcnMessage_StatusBody_StatusCodeEnum = 2\n\tAcnMessage_StatusBody_ERROR_GENERIC             AcnMessage_StatusBody_StatusCodeEnum = 3\n\tAcnMessage_StatusBody_ERROR_DECODE              AcnMessage_StatusBody_StatusCodeEnum = 4\n\t// register (1x)\n\tAcnMessage_StatusBody_ERROR_WRONG_AGENT_ADDRESS AcnMessage_StatusBody_StatusCodeEnum = 10\n\tAcnMessage_StatusBody_ERROR_WRONG_PUBLIC_KEY    AcnMessage_StatusBody_StatusCodeEnum = 11\n\tAcnMessage_StatusBody_ERROR_INVALID_PROOF       AcnMessage_StatusBody_StatusCodeEnum = 12\n\tAcnMessage_StatusBody_ERROR_UNSUPPORTED_LEDGER  AcnMessage_StatusBody_StatusCodeEnum = 13\n\t// lookup & delivery (2x)\n\tAcnMessage_StatusBody_ERROR_UNKNOWN_AGENT_ADDRESS AcnMessage_StatusBody_StatusCodeEnum = 20\n\tAcnMessage_StatusBody_ERROR_AGENT_NOT_READY       AcnMessage_StatusBody_StatusCodeEnum = 21\n)\n\n// Enum value maps for AcnMessage_StatusBody_StatusCodeEnum.\nvar (\n\tAcnMessage_StatusBody_StatusCodeEnum_name = map[int32]string{\n\t\t0:  \"SUCCESS\",\n\t\t1:  \"ERROR_UNSUPPORTED_VERSION\",\n\t\t2:  \"ERROR_UNEXPECTED_PAYLOAD\",\n\t\t3:  \"ERROR_GENERIC\",\n\t\t4:  \"ERROR_DECODE\",\n\t\t10: \"ERROR_WRONG_AGENT_ADDRESS\",\n\t\t11: \"ERROR_WRONG_PUBLIC_KEY\",\n\t\t12: \"ERROR_INVALID_PROOF\",\n\t\t13: \"ERROR_UNSUPPORTED_LEDGER\",\n\t\t20: \"ERROR_UNKNOWN_AGENT_ADDRESS\",\n\t\t21: \"ERROR_AGENT_NOT_READY\",\n\t}\n\tAcnMessage_StatusBody_StatusCodeEnum_value = map[string]int32{\n\t\t\"SUCCESS\":                     0,\n\t\t\"ERROR_UNSUPPORTED_VERSION\":   1,\n\t\t\"ERROR_UNEXPECTED_PAYLOAD\":    2,\n\t\t\"ERROR_GENERIC\":               3,\n\t\t\"ERROR_DECODE\":                4,\n\t\t\"ERROR_WRONG_AGENT_ADDRESS\":   10,\n\t\t\"ERROR_WRONG_PUBLIC_KEY\":      11,\n\t\t\"ERROR_INVALID_PROOF\":         12,\n\t\t\"ERROR_UNSUPPORTED_LEDGER\":    13,\n\t\t\"ERROR_UNKNOWN_AGENT_ADDRESS\": 20,\n\t\t\"ERROR_AGENT_NOT_READY\":       21,\n\t}\n)\n\nfunc (x AcnMessage_StatusBody_StatusCodeEnum) Enum() *AcnMessage_StatusBody_StatusCodeEnum {\n\tp := new(AcnMessage_StatusBody_StatusCodeEnum)\n\t*p = x\n\treturn p\n}\n\nfunc (x AcnMessage_StatusBody_StatusCodeEnum) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (AcnMessage_StatusBody_StatusCodeEnum) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_acn_proto_enumTypes[0].Descriptor()\n}\n\nfunc (AcnMessage_StatusBody_StatusCodeEnum) Type() protoreflect.EnumType {\n\treturn &file_acn_proto_enumTypes[0]\n}\n\nfunc (x AcnMessage_StatusBody_StatusCodeEnum) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use AcnMessage_StatusBody_StatusCodeEnum.Descriptor instead.\nfunc (AcnMessage_StatusBody_StatusCodeEnum) EnumDescriptor() ([]byte, []int) {\n\treturn file_acn_proto_rawDescGZIP(), []int{0, 1, 0}\n}\n\ntype AcnMessage struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// Types that are assignable to Performative:\n\t//\t*AcnMessage_AeaEnvelope\n\t//\t*AcnMessage_LookupRequest\n\t//\t*AcnMessage_LookupResponse\n\t//\t*AcnMessage_Register\n\t//\t*AcnMessage_Status\n\tPerformative isAcnMessage_Performative `protobuf_oneof:\"performative\"`\n}\n\nfunc (x *AcnMessage) Reset() {\n\t*x = AcnMessage{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_acn_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *AcnMessage) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*AcnMessage) ProtoMessage() {}\n\nfunc (x *AcnMessage) ProtoReflect() protoreflect.Message {\n\tmi := &file_acn_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use AcnMessage.ProtoReflect.Descriptor instead.\nfunc (*AcnMessage) Descriptor() ([]byte, []int) {\n\treturn file_acn_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (m *AcnMessage) GetPerformative() isAcnMessage_Performative {\n\tif m != nil {\n\t\treturn m.Performative\n\t}\n\treturn nil\n}\n\nfunc (x *AcnMessage) GetAeaEnvelope() *AcnMessage_Aea_Envelope_Performative {\n\tif x, ok := x.GetPerformative().(*AcnMessage_AeaEnvelope); ok {\n\t\treturn x.AeaEnvelope\n\t}\n\treturn nil\n}\n\nfunc (x *AcnMessage) GetLookupRequest() *AcnMessage_Lookup_Request_Performative {\n\tif x, ok := x.GetPerformative().(*AcnMessage_LookupRequest); ok {\n\t\treturn x.LookupRequest\n\t}\n\treturn nil\n}\n\nfunc (x *AcnMessage) GetLookupResponse() *AcnMessage_Lookup_Response_Performative {\n\tif x, ok := x.GetPerformative().(*AcnMessage_LookupResponse); ok {\n\t\treturn x.LookupResponse\n\t}\n\treturn nil\n}\n\nfunc (x *AcnMessage) GetRegister() *AcnMessage_Register_Performative {\n\tif x, ok := x.GetPerformative().(*AcnMessage_Register); ok {\n\t\treturn x.Register\n\t}\n\treturn nil\n}\n\nfunc (x *AcnMessage) GetStatus() *AcnMessage_Status_Performative {\n\tif x, ok := x.GetPerformative().(*AcnMessage_Status); ok {\n\t\treturn x.Status\n\t}\n\treturn nil\n}\n\ntype isAcnMessage_Performative interface {\n\tisAcnMessage_Performative()\n}\n\ntype AcnMessage_AeaEnvelope struct {\n\tAeaEnvelope *AcnMessage_Aea_Envelope_Performative `protobuf:\"bytes,5,opt,name=aea_envelope,json=aeaEnvelope,proto3,oneof\"`\n}\n\ntype AcnMessage_LookupRequest struct {\n\tLookupRequest *AcnMessage_Lookup_Request_Performative `protobuf:\"bytes,6,opt,name=lookup_request,json=lookupRequest,proto3,oneof\"`\n}\n\ntype AcnMessage_LookupResponse struct {\n\tLookupResponse *AcnMessage_Lookup_Response_Performative `protobuf:\"bytes,7,opt,name=lookup_response,json=lookupResponse,proto3,oneof\"`\n}\n\ntype AcnMessage_Register struct {\n\tRegister *AcnMessage_Register_Performative `protobuf:\"bytes,8,opt,name=register,proto3,oneof\"`\n}\n\ntype AcnMessage_Status struct {\n\tStatus *AcnMessage_Status_Performative `protobuf:\"bytes,9,opt,name=status,proto3,oneof\"`\n}\n\nfunc (*AcnMessage_AeaEnvelope) isAcnMessage_Performative() {}\n\nfunc (*AcnMessage_LookupRequest) isAcnMessage_Performative() {}\n\nfunc (*AcnMessage_LookupResponse) isAcnMessage_Performative() {}\n\nfunc (*AcnMessage_Register) isAcnMessage_Performative() {}\n\nfunc (*AcnMessage_Status) isAcnMessage_Performative() {}\n\n// Custom Types\ntype AcnMessage_AgentRecord struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tServiceId     string `protobuf:\"bytes,1,opt,name=service_id,json=serviceId,proto3\" json:\"service_id,omitempty\"`\n\tLedgerId      string `protobuf:\"bytes,2,opt,name=ledger_id,json=ledgerId,proto3\" json:\"ledger_id,omitempty\"`\n\tAddress       string `protobuf:\"bytes,3,opt,name=address,proto3\" json:\"address,omitempty\"`\n\tPublicKey     string `protobuf:\"bytes,4,opt,name=public_key,json=publicKey,proto3\" json:\"public_key,omitempty\"`\n\tPeerPublicKey string `protobuf:\"bytes,5,opt,name=peer_public_key,json=peerPublicKey,proto3\" json:\"peer_public_key,omitempty\"`\n\tSignature     string `protobuf:\"bytes,6,opt,name=signature,proto3\" json:\"signature,omitempty\"`\n\tNotBefore     string `protobuf:\"bytes,7,opt,name=not_before,json=notBefore,proto3\" json:\"not_before,omitempty\"`\n\tNotAfter      string `protobuf:\"bytes,8,opt,name=not_after,json=notAfter,proto3\" json:\"not_after,omitempty\"`\n}\n\nfunc (x *AcnMessage_AgentRecord) Reset() {\n\t*x = AcnMessage_AgentRecord{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_acn_proto_msgTypes[1]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *AcnMessage_AgentRecord) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*AcnMessage_AgentRecord) ProtoMessage() {}\n\nfunc (x *AcnMessage_AgentRecord) ProtoReflect() protoreflect.Message {\n\tmi := &file_acn_proto_msgTypes[1]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use AcnMessage_AgentRecord.ProtoReflect.Descriptor instead.\nfunc (*AcnMessage_AgentRecord) Descriptor() ([]byte, []int) {\n\treturn file_acn_proto_rawDescGZIP(), []int{0, 0}\n}\n\nfunc (x *AcnMessage_AgentRecord) GetServiceId() string {\n\tif x != nil {\n\t\treturn x.ServiceId\n\t}\n\treturn \"\"\n}\n\nfunc (x *AcnMessage_AgentRecord) GetLedgerId() string {\n\tif x != nil {\n\t\treturn x.LedgerId\n\t}\n\treturn \"\"\n}\n\nfunc (x *AcnMessage_AgentRecord) GetAddress() string {\n\tif x != nil {\n\t\treturn x.Address\n\t}\n\treturn \"\"\n}\n\nfunc (x *AcnMessage_AgentRecord) GetPublicKey() string {\n\tif x != nil {\n\t\treturn x.PublicKey\n\t}\n\treturn \"\"\n}\n\nfunc (x *AcnMessage_AgentRecord) GetPeerPublicKey() string {\n\tif x != nil {\n\t\treturn x.PeerPublicKey\n\t}\n\treturn \"\"\n}\n\nfunc (x *AcnMessage_AgentRecord) GetSignature() string {\n\tif x != nil {\n\t\treturn x.Signature\n\t}\n\treturn \"\"\n}\n\nfunc (x *AcnMessage_AgentRecord) GetNotBefore() string {\n\tif x != nil {\n\t\treturn x.NotBefore\n\t}\n\treturn \"\"\n}\n\nfunc (x *AcnMessage_AgentRecord) GetNotAfter() string {\n\tif x != nil {\n\t\treturn x.NotAfter\n\t}\n\treturn \"\"\n}\n\ntype AcnMessage_StatusBody struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tCode AcnMessage_StatusBody_StatusCodeEnum `protobuf:\"varint,1,opt,name=code,proto3,enum=aea.aea.acn.v1_0_0.AcnMessage_StatusBody_StatusCodeEnum\" json:\"code,omitempty\"`\n\tMsgs []string                             `protobuf:\"bytes,2,rep,name=msgs,proto3\" json:\"msgs,omitempty\"`\n}\n\nfunc (x *AcnMessage_StatusBody) Reset() {\n\t*x = AcnMessage_StatusBody{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_acn_proto_msgTypes[2]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *AcnMessage_StatusBody) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*AcnMessage_StatusBody) ProtoMessage() {}\n\nfunc (x *AcnMessage_StatusBody) ProtoReflect() protoreflect.Message {\n\tmi := &file_acn_proto_msgTypes[2]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use AcnMessage_StatusBody.ProtoReflect.Descriptor instead.\nfunc (*AcnMessage_StatusBody) Descriptor() ([]byte, []int) {\n\treturn file_acn_proto_rawDescGZIP(), []int{0, 1}\n}\n\nfunc (x *AcnMessage_StatusBody) GetCode() AcnMessage_StatusBody_StatusCodeEnum {\n\tif x != nil {\n\t\treturn x.Code\n\t}\n\treturn AcnMessage_StatusBody_SUCCESS\n}\n\nfunc (x *AcnMessage_StatusBody) GetMsgs() []string {\n\tif x != nil {\n\t\treturn x.Msgs\n\t}\n\treturn nil\n}\n\n// Performatives and contents\ntype AcnMessage_Register_Performative struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tRecord *AcnMessage_AgentRecord `protobuf:\"bytes,1,opt,name=record,proto3\" json:\"record,omitempty\"`\n}\n\nfunc (x *AcnMessage_Register_Performative) Reset() {\n\t*x = AcnMessage_Register_Performative{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_acn_proto_msgTypes[3]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *AcnMessage_Register_Performative) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*AcnMessage_Register_Performative) ProtoMessage() {}\n\nfunc (x *AcnMessage_Register_Performative) ProtoReflect() protoreflect.Message {\n\tmi := &file_acn_proto_msgTypes[3]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use AcnMessage_Register_Performative.ProtoReflect.Descriptor instead.\nfunc (*AcnMessage_Register_Performative) Descriptor() ([]byte, []int) {\n\treturn file_acn_proto_rawDescGZIP(), []int{0, 2}\n}\n\nfunc (x *AcnMessage_Register_Performative) GetRecord() *AcnMessage_AgentRecord {\n\tif x != nil {\n\t\treturn x.Record\n\t}\n\treturn nil\n}\n\ntype AcnMessage_Lookup_Request_Performative struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tAgentAddress string `protobuf:\"bytes,1,opt,name=agent_address,json=agentAddress,proto3\" json:\"agent_address,omitempty\"`\n}\n\nfunc (x *AcnMessage_Lookup_Request_Performative) Reset() {\n\t*x = AcnMessage_Lookup_Request_Performative{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_acn_proto_msgTypes[4]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *AcnMessage_Lookup_Request_Performative) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*AcnMessage_Lookup_Request_Performative) ProtoMessage() {}\n\nfunc (x *AcnMessage_Lookup_Request_Performative) ProtoReflect() protoreflect.Message {\n\tmi := &file_acn_proto_msgTypes[4]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use AcnMessage_Lookup_Request_Performative.ProtoReflect.Descriptor instead.\nfunc (*AcnMessage_Lookup_Request_Performative) Descriptor() ([]byte, []int) {\n\treturn file_acn_proto_rawDescGZIP(), []int{0, 3}\n}\n\nfunc (x *AcnMessage_Lookup_Request_Performative) GetAgentAddress() string {\n\tif x != nil {\n\t\treturn x.AgentAddress\n\t}\n\treturn \"\"\n}\n\ntype AcnMessage_Lookup_Response_Performative struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tRecord *AcnMessage_AgentRecord `protobuf:\"bytes,1,opt,name=record,proto3\" json:\"record,omitempty\"`\n}\n\nfunc (x *AcnMessage_Lookup_Response_Performative) Reset() {\n\t*x = AcnMessage_Lookup_Response_Performative{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_acn_proto_msgTypes[5]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *AcnMessage_Lookup_Response_Performative) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*AcnMessage_Lookup_Response_Performative) ProtoMessage() {}\n\nfunc (x *AcnMessage_Lookup_Response_Performative) ProtoReflect() protoreflect.Message {\n\tmi := &file_acn_proto_msgTypes[5]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use AcnMessage_Lookup_Response_Performative.ProtoReflect.Descriptor instead.\nfunc (*AcnMessage_Lookup_Response_Performative) Descriptor() ([]byte, []int) {\n\treturn file_acn_proto_rawDescGZIP(), []int{0, 4}\n}\n\nfunc (x *AcnMessage_Lookup_Response_Performative) GetRecord() *AcnMessage_AgentRecord {\n\tif x != nil {\n\t\treturn x.Record\n\t}\n\treturn nil\n}\n\ntype AcnMessage_Aea_Envelope_Performative struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tEnvelope []byte                  `protobuf:\"bytes,1,opt,name=envelope,proto3\" json:\"envelope,omitempty\"`\n\tRecord   *AcnMessage_AgentRecord `protobuf:\"bytes,2,opt,name=record,proto3\" json:\"record,omitempty\"`\n}\n\nfunc (x *AcnMessage_Aea_Envelope_Performative) Reset() {\n\t*x = AcnMessage_Aea_Envelope_Performative{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_acn_proto_msgTypes[6]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *AcnMessage_Aea_Envelope_Performative) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*AcnMessage_Aea_Envelope_Performative) ProtoMessage() {}\n\nfunc (x *AcnMessage_Aea_Envelope_Performative) ProtoReflect() protoreflect.Message {\n\tmi := &file_acn_proto_msgTypes[6]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use AcnMessage_Aea_Envelope_Performative.ProtoReflect.Descriptor instead.\nfunc (*AcnMessage_Aea_Envelope_Performative) Descriptor() ([]byte, []int) {\n\treturn file_acn_proto_rawDescGZIP(), []int{0, 5}\n}\n\nfunc (x *AcnMessage_Aea_Envelope_Performative) GetEnvelope() []byte {\n\tif x != nil {\n\t\treturn x.Envelope\n\t}\n\treturn nil\n}\n\nfunc (x *AcnMessage_Aea_Envelope_Performative) GetRecord() *AcnMessage_AgentRecord {\n\tif x != nil {\n\t\treturn x.Record\n\t}\n\treturn nil\n}\n\ntype AcnMessage_Status_Performative struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tBody *AcnMessage_StatusBody `protobuf:\"bytes,1,opt,name=body,proto3\" json:\"body,omitempty\"`\n}\n\nfunc (x *AcnMessage_Status_Performative) Reset() {\n\t*x = AcnMessage_Status_Performative{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_acn_proto_msgTypes[7]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *AcnMessage_Status_Performative) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*AcnMessage_Status_Performative) ProtoMessage() {}\n\nfunc (x *AcnMessage_Status_Performative) ProtoReflect() protoreflect.Message {\n\tmi := &file_acn_proto_msgTypes[7]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use AcnMessage_Status_Performative.ProtoReflect.Descriptor instead.\nfunc (*AcnMessage_Status_Performative) Descriptor() ([]byte, []int) {\n\treturn file_acn_proto_rawDescGZIP(), []int{0, 6}\n}\n\nfunc (x *AcnMessage_Status_Performative) GetBody() *AcnMessage_StatusBody {\n\tif x != nil {\n\t\treturn x.Body\n\t}\n\treturn nil\n}\n\nvar File_acn_proto protoreflect.FileDescriptor\n\nvar file_acn_proto_rawDesc = []byte{\n\t0x0a, 0x09, 0x61, 0x63, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x12, 0x61, 0x65, 0x61,\n\t0x2e, 0x61, 0x65, 0x61, 0x2e, 0x61, 0x63, 0x6e, 0x2e, 0x76, 0x31, 0x5f, 0x30, 0x5f, 0x30, 0x22,\n\t0xea, 0x0c, 0x0a, 0x0a, 0x41, 0x63, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x5d,\n\t0x0a, 0x0c, 0x61, 0x65, 0x61, 0x5f, 0x65, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x18, 0x05,\n\t0x20, 0x01, 0x28, 0x0b, 0x32, 0x38, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x61,\n\t0x63, 0x6e, 0x2e, 0x76, 0x31, 0x5f, 0x30, 0x5f, 0x30, 0x2e, 0x41, 0x63, 0x6e, 0x4d, 0x65, 0x73,\n\t0x73, 0x61, 0x67, 0x65, 0x2e, 0x41, 0x65, 0x61, 0x5f, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70,\n\t0x65, 0x5f, 0x50, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x76, 0x65, 0x48, 0x00,\n\t0x52, 0x0b, 0x61, 0x65, 0x61, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x12, 0x63, 0x0a,\n\t0x0e, 0x6c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18,\n\t0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3a, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x61, 0x65, 0x61, 0x2e,\n\t0x61, 0x63, 0x6e, 0x2e, 0x76, 0x31, 0x5f, 0x30, 0x5f, 0x30, 0x2e, 0x41, 0x63, 0x6e, 0x4d, 0x65,\n\t0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x5f, 0x52, 0x65, 0x71,\n\t0x75, 0x65, 0x73, 0x74, 0x5f, 0x50, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x76,\n\t0x65, 0x48, 0x00, 0x52, 0x0d, 0x6c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65,\n\t0x73, 0x74, 0x12, 0x66, 0x0a, 0x0f, 0x6c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x5f, 0x72, 0x65, 0x73,\n\t0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3b, 0x2e, 0x61, 0x65,\n\t0x61, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x61, 0x63, 0x6e, 0x2e, 0x76, 0x31, 0x5f, 0x30, 0x5f, 0x30,\n\t0x2e, 0x41, 0x63, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4c, 0x6f, 0x6f, 0x6b,\n\t0x75, 0x70, 0x5f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x5f, 0x50, 0x65, 0x72, 0x66,\n\t0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x76, 0x65, 0x48, 0x00, 0x52, 0x0e, 0x6c, 0x6f, 0x6f, 0x6b,\n\t0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x52, 0x0a, 0x08, 0x72, 0x65,\n\t0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x61,\n\t0x65, 0x61, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x61, 0x63, 0x6e, 0x2e, 0x76, 0x31, 0x5f, 0x30, 0x5f,\n\t0x30, 0x2e, 0x41, 0x63, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x52, 0x65, 0x67,\n\t0x69, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x50, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69,\n\t0x76, 0x65, 0x48, 0x00, 0x52, 0x08, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x12, 0x4c,\n\t0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x32,\n\t0x2e, 0x61, 0x65, 0x61, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x61, 0x63, 0x6e, 0x2e, 0x76, 0x31, 0x5f,\n\t0x30, 0x5f, 0x30, 0x2e, 0x41, 0x63, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x53,\n\t0x74, 0x61, 0x74, 0x75, 0x73, 0x5f, 0x50, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69,\n\t0x76, 0x65, 0x48, 0x00, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x1a, 0x84, 0x02, 0x0a,\n\t0x0b, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x12, 0x1d, 0x0a, 0x0a,\n\t0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,\n\t0x52, 0x09, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x6c,\n\t0x65, 0x64, 0x67, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08,\n\t0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72,\n\t0x65, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65,\n\t0x73, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79,\n\t0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65,\n\t0x79, 0x12, 0x26, 0x0a, 0x0f, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63,\n\t0x5f, 0x6b, 0x65, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x70, 0x65, 0x65, 0x72,\n\t0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67,\n\t0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x69,\n\t0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x6e, 0x6f, 0x74, 0x5f, 0x62,\n\t0x65, 0x66, 0x6f, 0x72, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x6f, 0x74,\n\t0x42, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x6e, 0x6f, 0x74, 0x5f, 0x61, 0x66,\n\t0x74, 0x65, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6e, 0x6f, 0x74, 0x41, 0x66,\n\t0x74, 0x65, 0x72, 0x1a, 0x9e, 0x03, 0x0a, 0x0a, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x42, 0x6f,\n\t0x64, 0x79, 0x12, 0x4c, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e,\n\t0x32, 0x38, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x61, 0x63, 0x6e, 0x2e, 0x76,\n\t0x31, 0x5f, 0x30, 0x5f, 0x30, 0x2e, 0x41, 0x63, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,\n\t0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x42, 0x6f, 0x64, 0x79, 0x2e, 0x53, 0x74, 0x61, 0x74,\n\t0x75, 0x73, 0x43, 0x6f, 0x64, 0x65, 0x45, 0x6e, 0x75, 0x6d, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65,\n\t0x12, 0x12, 0x0a, 0x04, 0x6d, 0x73, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04,\n\t0x6d, 0x73, 0x67, 0x73, 0x22, 0xad, 0x02, 0x0a, 0x0e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x43,\n\t0x6f, 0x64, 0x65, 0x45, 0x6e, 0x75, 0x6d, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x55, 0x43, 0x43, 0x45,\n\t0x53, 0x53, 0x10, 0x00, 0x12, 0x1d, 0x0a, 0x19, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x55, 0x4e,\n\t0x53, 0x55, 0x50, 0x50, 0x4f, 0x52, 0x54, 0x45, 0x44, 0x5f, 0x56, 0x45, 0x52, 0x53, 0x49, 0x4f,\n\t0x4e, 0x10, 0x01, 0x12, 0x1c, 0x0a, 0x18, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x55, 0x4e, 0x45,\n\t0x58, 0x50, 0x45, 0x43, 0x54, 0x45, 0x44, 0x5f, 0x50, 0x41, 0x59, 0x4c, 0x4f, 0x41, 0x44, 0x10,\n\t0x02, 0x12, 0x11, 0x0a, 0x0d, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x47, 0x45, 0x4e, 0x45, 0x52,\n\t0x49, 0x43, 0x10, 0x03, 0x12, 0x10, 0x0a, 0x0c, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x44, 0x45,\n\t0x43, 0x4f, 0x44, 0x45, 0x10, 0x04, 0x12, 0x1d, 0x0a, 0x19, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f,\n\t0x57, 0x52, 0x4f, 0x4e, 0x47, 0x5f, 0x41, 0x47, 0x45, 0x4e, 0x54, 0x5f, 0x41, 0x44, 0x44, 0x52,\n\t0x45, 0x53, 0x53, 0x10, 0x0a, 0x12, 0x1a, 0x0a, 0x16, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x57,\n\t0x52, 0x4f, 0x4e, 0x47, 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x5f, 0x4b, 0x45, 0x59, 0x10,\n\t0x0b, 0x12, 0x17, 0x0a, 0x13, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x49, 0x4e, 0x56, 0x41, 0x4c,\n\t0x49, 0x44, 0x5f, 0x50, 0x52, 0x4f, 0x4f, 0x46, 0x10, 0x0c, 0x12, 0x1c, 0x0a, 0x18, 0x45, 0x52,\n\t0x52, 0x4f, 0x52, 0x5f, 0x55, 0x4e, 0x53, 0x55, 0x50, 0x50, 0x4f, 0x52, 0x54, 0x45, 0x44, 0x5f,\n\t0x4c, 0x45, 0x44, 0x47, 0x45, 0x52, 0x10, 0x0d, 0x12, 0x1f, 0x0a, 0x1b, 0x45, 0x52, 0x52, 0x4f,\n\t0x52, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x5f, 0x41, 0x47, 0x45, 0x4e, 0x54, 0x5f,\n\t0x41, 0x44, 0x44, 0x52, 0x45, 0x53, 0x53, 0x10, 0x14, 0x12, 0x19, 0x0a, 0x15, 0x45, 0x52, 0x52,\n\t0x4f, 0x52, 0x5f, 0x41, 0x47, 0x45, 0x4e, 0x54, 0x5f, 0x4e, 0x4f, 0x54, 0x5f, 0x52, 0x45, 0x41,\n\t0x44, 0x59, 0x10, 0x15, 0x1a, 0x5b, 0x0a, 0x15, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72,\n\t0x5f, 0x50, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x76, 0x65, 0x12, 0x42, 0x0a,\n\t0x06, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e,\n\t0x61, 0x65, 0x61, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x61, 0x63, 0x6e, 0x2e, 0x76, 0x31, 0x5f, 0x30,\n\t0x5f, 0x30, 0x2e, 0x41, 0x63, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x41, 0x67,\n\t0x65, 0x6e, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x52, 0x06, 0x72, 0x65, 0x63, 0x6f, 0x72,\n\t0x64, 0x1a, 0x42, 0x0a, 0x1b, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x5f, 0x52, 0x65, 0x71, 0x75,\n\t0x65, 0x73, 0x74, 0x5f, 0x50, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x76, 0x65,\n\t0x12, 0x23, 0x0a, 0x0d, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73,\n\t0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x41, 0x64,\n\t0x64, 0x72, 0x65, 0x73, 0x73, 0x1a, 0x62, 0x0a, 0x1c, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x5f,\n\t0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x5f, 0x50, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d,\n\t0x61, 0x74, 0x69, 0x76, 0x65, 0x12, 0x42, 0x0a, 0x06, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x18,\n\t0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x61, 0x65, 0x61, 0x2e,\n\t0x61, 0x63, 0x6e, 0x2e, 0x76, 0x31, 0x5f, 0x30, 0x5f, 0x30, 0x2e, 0x41, 0x63, 0x6e, 0x4d, 0x65,\n\t0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x72,\n\t0x64, 0x52, 0x06, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x1a, 0x7b, 0x0a, 0x19, 0x41, 0x65, 0x61,\n\t0x5f, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x5f, 0x50, 0x65, 0x72, 0x66, 0x6f, 0x72,\n\t0x6d, 0x61, 0x74, 0x69, 0x76, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x65, 0x6e, 0x76, 0x65, 0x6c, 0x6f,\n\t0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x65, 0x6e, 0x76, 0x65, 0x6c, 0x6f,\n\t0x70, 0x65, 0x12, 0x42, 0x0a, 0x06, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01,\n\t0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x61, 0x63, 0x6e,\n\t0x2e, 0x76, 0x31, 0x5f, 0x30, 0x5f, 0x30, 0x2e, 0x41, 0x63, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61,\n\t0x67, 0x65, 0x2e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x52, 0x06,\n\t0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x1a, 0x54, 0x0a, 0x13, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73,\n\t0x5f, 0x50, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x76, 0x65, 0x12, 0x3d, 0x0a,\n\t0x04, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x61, 0x65,\n\t0x61, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x61, 0x63, 0x6e, 0x2e, 0x76, 0x31, 0x5f, 0x30, 0x5f, 0x30,\n\t0x2e, 0x41, 0x63, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74,\n\t0x75, 0x73, 0x42, 0x6f, 0x64, 0x79, 0x52, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x42, 0x0e, 0x0a, 0x0c,\n\t0x70, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x76, 0x65, 0x62, 0x06, 0x70, 0x72,\n\t0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_acn_proto_rawDescOnce sync.Once\n\tfile_acn_proto_rawDescData = file_acn_proto_rawDesc\n)\n\nfunc file_acn_proto_rawDescGZIP() []byte {\n\tfile_acn_proto_rawDescOnce.Do(func() {\n\t\tfile_acn_proto_rawDescData = protoimpl.X.CompressGZIP(file_acn_proto_rawDescData)\n\t})\n\treturn file_acn_proto_rawDescData\n}\n\nvar file_acn_proto_enumTypes = make([]protoimpl.EnumInfo, 1)\nvar file_acn_proto_msgTypes = make([]protoimpl.MessageInfo, 8)\nvar file_acn_proto_goTypes = []interface{}{\n\t(AcnMessage_StatusBody_StatusCodeEnum)(0),       // 0: aea.aea.acn.v1_0_0.AcnMessage.StatusBody.StatusCodeEnum\n\t(*AcnMessage)(nil),                              // 1: aea.aea.acn.v1_0_0.AcnMessage\n\t(*AcnMessage_AgentRecord)(nil),                  // 2: aea.aea.acn.v1_0_0.AcnMessage.AgentRecord\n\t(*AcnMessage_StatusBody)(nil),                   // 3: aea.aea.acn.v1_0_0.AcnMessage.StatusBody\n\t(*AcnMessage_Register_Performative)(nil),        // 4: aea.aea.acn.v1_0_0.AcnMessage.Register_Performative\n\t(*AcnMessage_Lookup_Request_Performative)(nil),  // 5: aea.aea.acn.v1_0_0.AcnMessage.Lookup_Request_Performative\n\t(*AcnMessage_Lookup_Response_Performative)(nil), // 6: aea.aea.acn.v1_0_0.AcnMessage.Lookup_Response_Performative\n\t(*AcnMessage_Aea_Envelope_Performative)(nil),    // 7: aea.aea.acn.v1_0_0.AcnMessage.Aea_Envelope_Performative\n\t(*AcnMessage_Status_Performative)(nil),          // 8: aea.aea.acn.v1_0_0.AcnMessage.Status_Performative\n}\nvar file_acn_proto_depIdxs = []int32{\n\t7,  // 0: aea.aea.acn.v1_0_0.AcnMessage.aea_envelope:type_name -> aea.aea.acn.v1_0_0.AcnMessage.Aea_Envelope_Performative\n\t5,  // 1: aea.aea.acn.v1_0_0.AcnMessage.lookup_request:type_name -> aea.aea.acn.v1_0_0.AcnMessage.Lookup_Request_Performative\n\t6,  // 2: aea.aea.acn.v1_0_0.AcnMessage.lookup_response:type_name -> aea.aea.acn.v1_0_0.AcnMessage.Lookup_Response_Performative\n\t4,  // 3: aea.aea.acn.v1_0_0.AcnMessage.register:type_name -> aea.aea.acn.v1_0_0.AcnMessage.Register_Performative\n\t8,  // 4: aea.aea.acn.v1_0_0.AcnMessage.status:type_name -> aea.aea.acn.v1_0_0.AcnMessage.Status_Performative\n\t0,  // 5: aea.aea.acn.v1_0_0.AcnMessage.StatusBody.code:type_name -> aea.aea.acn.v1_0_0.AcnMessage.StatusBody.StatusCodeEnum\n\t2,  // 6: aea.aea.acn.v1_0_0.AcnMessage.Register_Performative.record:type_name -> aea.aea.acn.v1_0_0.AcnMessage.AgentRecord\n\t2,  // 7: aea.aea.acn.v1_0_0.AcnMessage.Lookup_Response_Performative.record:type_name -> aea.aea.acn.v1_0_0.AcnMessage.AgentRecord\n\t2,  // 8: aea.aea.acn.v1_0_0.AcnMessage.Aea_Envelope_Performative.record:type_name -> aea.aea.acn.v1_0_0.AcnMessage.AgentRecord\n\t3,  // 9: aea.aea.acn.v1_0_0.AcnMessage.Status_Performative.body:type_name -> aea.aea.acn.v1_0_0.AcnMessage.StatusBody\n\t10, // [10:10] is the sub-list for method output_type\n\t10, // [10:10] is the sub-list for method input_type\n\t10, // [10:10] is the sub-list for extension type_name\n\t10, // [10:10] is the sub-list for extension extendee\n\t0,  // [0:10] is the sub-list for field type_name\n}\n\nfunc init() { file_acn_proto_init() }\nfunc file_acn_proto_init() {\n\tif File_acn_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_acn_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*AcnMessage); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_acn_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*AcnMessage_AgentRecord); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_acn_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*AcnMessage_StatusBody); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_acn_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*AcnMessage_Register_Performative); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_acn_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*AcnMessage_Lookup_Request_Performative); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_acn_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*AcnMessage_Lookup_Response_Performative); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_acn_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*AcnMessage_Aea_Envelope_Performative); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_acn_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*AcnMessage_Status_Performative); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\tfile_acn_proto_msgTypes[0].OneofWrappers = []interface{}{\n\t\t(*AcnMessage_AeaEnvelope)(nil),\n\t\t(*AcnMessage_LookupRequest)(nil),\n\t\t(*AcnMessage_LookupResponse)(nil),\n\t\t(*AcnMessage_Register)(nil),\n\t\t(*AcnMessage_Status)(nil),\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_acn_proto_rawDesc,\n\t\t\tNumEnums:      1,\n\t\t\tNumMessages:   8,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_acn_proto_goTypes,\n\t\tDependencyIndexes: file_acn_proto_depIdxs,\n\t\tEnumInfos:         file_acn_proto_enumTypes,\n\t\tMessageInfos:      file_acn_proto_msgTypes,\n\t}.Build()\n\tFile_acn_proto = out.File\n\tfile_acn_proto_rawDesc = nil\n\tfile_acn_proto_goTypes = nil\n\tfile_acn_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "libs/go/aealite/protocols/acn/v1_0_0/acn.proto",
    "content": "syntax = \"proto3\";\n\npackage aea.aea.acn.v1_0_0;\n\noption go_package = \"libp2p_node/protocols/acn/v1_0_0\";\n\nmessage AcnMessage{\n\n  // Custom Types\n  message AgentRecord{\n    string service_id = 1;\n    string ledger_id = 2;\n    string address = 3;\n    string public_key = 4;\n    string peer_public_key = 5;\n    string signature = 6;\n    string not_before = 7;\n    string not_after = 8;\n  }\n\n  message StatusBody{\n    enum StatusCodeEnum {\n      // common (0x)\n      SUCCESS = 0;\n      ERROR_UNSUPPORTED_VERSION = 1;\n      ERROR_UNEXPECTED_PAYLOAD = 2;\n      ERROR_GENERIC = 3;\n      ERROR_DECODE = 4;\n      // register (1x)\n      ERROR_WRONG_AGENT_ADDRESS = 10;\n      ERROR_WRONG_PUBLIC_KEY = 11;\n      ERROR_INVALID_PROOF = 12;\n      ERROR_UNSUPPORTED_LEDGER = 13;\n      // lookup & delivery (2x) \n      ERROR_UNKNOWN_AGENT_ADDRESS = 20;\n      ERROR_AGENT_NOT_READY = 21;\n    }\n    StatusCodeEnum code = 1;\n    repeated string msgs = 2;\n  }\n\n\n  // Performatives and contents\n  message Register_Performative{\n    AgentRecord record = 1;\n  }\n\n  message Lookup_Request_Performative{\n    string agent_address = 1;\n  }\n\n  message Lookup_Response_Performative{\n    AgentRecord record = 1;\n  }\n\n  message Aea_Envelope_Performative{\n    bytes envelope = 1;\n    AgentRecord record = 2;\n  }\n\n  message Status_Performative{\n    StatusBody body = 1;\n  }\n\n\n  oneof performative{\n    Aea_Envelope_Performative aea_envelope = 5;\n    Lookup_Request_Performative lookup_request = 6;\n    Lookup_Response_Performative lookup_response = 7;\n    Register_Performative register = 8;\n    Status_Performative status = 9;\n  }\n}\n"
  },
  {
    "path": "libs/go/aealite/protocols/acn/v1_0_0/acn.yaml",
    "content": "---\nname: acn\nauthor: fetchai\nversion: 1.0.0\ndescription: The protocol used for envelope delivery on the ACN.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nprotocol_specification_id: aea/acn:1.0.0\nspeech_acts:\n  register:\n    record: ct:AgentRecord\n  lookup_request:\n    agent_address: pt:str\n  lookup_response:\n    record: ct:AgentRecord\n  aea_envelope:\n    envelope: pt:bytes\n    record: ct:AgentRecord\n  status:\n    body: ct:StatusBody\n...\n---\nct:AgentRecord:\n  string service_id = 1;\n  string ledger_id = 2;\n  string address = 3;\n  string public_key = 4;\n  string peer_public_key = 5;\n  string signature = 6;\n  string not_before = 7;\n  string not_after = 8;\nct:StatusBody: |\n  enum StatusCodeEnum {\n    // common (0x)\n    SUCCESS = 0;\n    ERROR_UNSUPPORTED_VERSION = 1;\n    ERROR_UNEXPECTED_PAYLOAD = 2;\n    ERROR_GENERIC = 3;\n    ERROR_DECODE = 4;\n    // register (1x)\n    ERROR_WRONG_AGENT_ADDRESS = 10;\n    ERROR_WRONG_PUBLIC_KEY = 11;\n    ERROR_INVALID_PROOF = 12;\n    ERROR_UNSUPPORTED_LEDGER = 13;\n    // lookup & delivery (2x) \n    ERROR_UNKNOWN_AGENT_ADDRESS = 20;\n    ERROR_AGENT_NOT_READY = 21;\n  }\n  StatusCodeEnum code = 1;\n  repeated string msgs = 2;\n...\n---\ninitiation: [register, lookup_request, aea_envelope]\nreply:\n  register: [status]\n  lookup_request: [lookup_response, status]\n  aea_envelope: [status]\n  status: []\n  lookup_response: []\ntermination: [status, lookup_response]\nroles: {node}\nend_states: [successful, failed]\nkeep_terminal_state_dialogues: false\n...\n"
  },
  {
    "path": "libs/go/aealite/protocols/base.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.25.0\n// \tprotoc        v3.11.4\n// source: base.proto\n\npackage protocols\n\nimport (\n\tproto \"github.com/golang/protobuf/proto\"\n\t_struct \"github.com/golang/protobuf/ptypes/struct\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// This is a compile-time assertion that a sufficiently up-to-date version\n// of the legacy proto package is being used.\nconst _ = proto.ProtoPackageIsVersion4\n\ntype DialogueMessage struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tMessageId                  int32  `protobuf:\"varint,1,opt,name=message_id,json=messageId,proto3\" json:\"message_id,omitempty\"`\n\tDialogueStarterReference   string `protobuf:\"bytes,2,opt,name=dialogue_starter_reference,json=dialogueStarterReference,proto3\" json:\"dialogue_starter_reference,omitempty\"`\n\tDialogueResponderReference string `protobuf:\"bytes,3,opt,name=dialogue_responder_reference,json=dialogueResponderReference,proto3\" json:\"dialogue_responder_reference,omitempty\"`\n\tTarget                     int32  `protobuf:\"varint,4,opt,name=target,proto3\" json:\"target,omitempty\"`\n\tContent                    []byte `protobuf:\"bytes,5,opt,name=content,proto3\" json:\"content,omitempty\"`\n}\n\nfunc (x *DialogueMessage) Reset() {\n\t*x = DialogueMessage{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_base_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *DialogueMessage) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*DialogueMessage) ProtoMessage() {}\n\nfunc (x *DialogueMessage) ProtoReflect() protoreflect.Message {\n\tmi := &file_base_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use DialogueMessage.ProtoReflect.Descriptor instead.\nfunc (*DialogueMessage) Descriptor() ([]byte, []int) {\n\treturn file_base_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *DialogueMessage) GetMessageId() int32 {\n\tif x != nil {\n\t\treturn x.MessageId\n\t}\n\treturn 0\n}\n\nfunc (x *DialogueMessage) GetDialogueStarterReference() string {\n\tif x != nil {\n\t\treturn x.DialogueStarterReference\n\t}\n\treturn \"\"\n}\n\nfunc (x *DialogueMessage) GetDialogueResponderReference() string {\n\tif x != nil {\n\t\treturn x.DialogueResponderReference\n\t}\n\treturn \"\"\n}\n\nfunc (x *DialogueMessage) GetTarget() int32 {\n\tif x != nil {\n\t\treturn x.Target\n\t}\n\treturn 0\n}\n\nfunc (x *DialogueMessage) GetContent() []byte {\n\tif x != nil {\n\t\treturn x.Content\n\t}\n\treturn nil\n}\n\ntype Message struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// Types that are assignable to Message:\n\t//\t*Message_Body\n\t//\t*Message_DialogueMessage\n\tMessage isMessage_Message `protobuf_oneof:\"message\"`\n}\n\nfunc (x *Message) Reset() {\n\t*x = Message{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_base_proto_msgTypes[1]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Message) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Message) ProtoMessage() {}\n\nfunc (x *Message) ProtoReflect() protoreflect.Message {\n\tmi := &file_base_proto_msgTypes[1]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Message.ProtoReflect.Descriptor instead.\nfunc (*Message) Descriptor() ([]byte, []int) {\n\treturn file_base_proto_rawDescGZIP(), []int{1}\n}\n\nfunc (m *Message) GetMessage() isMessage_Message {\n\tif m != nil {\n\t\treturn m.Message\n\t}\n\treturn nil\n}\n\nfunc (x *Message) GetBody() *_struct.Struct {\n\tif x, ok := x.GetMessage().(*Message_Body); ok {\n\t\treturn x.Body\n\t}\n\treturn nil\n}\n\nfunc (x *Message) GetDialogueMessage() *DialogueMessage {\n\tif x, ok := x.GetMessage().(*Message_DialogueMessage); ok {\n\t\treturn x.DialogueMessage\n\t}\n\treturn nil\n}\n\ntype isMessage_Message interface {\n\tisMessage_Message()\n}\n\ntype Message_Body struct {\n\tBody *_struct.Struct `protobuf:\"bytes,1,opt,name=body,proto3,oneof\"`\n}\n\ntype Message_DialogueMessage struct {\n\tDialogueMessage *DialogueMessage `protobuf:\"bytes,2,opt,name=dialogue_message,json=dialogueMessage,proto3,oneof\"`\n}\n\nfunc (*Message_Body) isMessage_Message() {}\n\nfunc (*Message_DialogueMessage) isMessage_Message() {}\n\ntype Envelope struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tTo         string `protobuf:\"bytes,1,opt,name=to,proto3\" json:\"to,omitempty\"`\n\tSender     string `protobuf:\"bytes,2,opt,name=sender,proto3\" json:\"sender,omitempty\"`\n\tProtocolId string `protobuf:\"bytes,3,opt,name=protocol_id,json=protocolId,proto3\" json:\"protocol_id,omitempty\"`\n\tMessage    []byte `protobuf:\"bytes,4,opt,name=message,proto3\" json:\"message,omitempty\"`\n\tUri        string `protobuf:\"bytes,5,opt,name=uri,proto3\" json:\"uri,omitempty\"`\n}\n\nfunc (x *Envelope) Reset() {\n\t*x = Envelope{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_base_proto_msgTypes[2]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Envelope) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Envelope) ProtoMessage() {}\n\nfunc (x *Envelope) ProtoReflect() protoreflect.Message {\n\tmi := &file_base_proto_msgTypes[2]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Envelope.ProtoReflect.Descriptor instead.\nfunc (*Envelope) Descriptor() ([]byte, []int) {\n\treturn file_base_proto_rawDescGZIP(), []int{2}\n}\n\nfunc (x *Envelope) GetTo() string {\n\tif x != nil {\n\t\treturn x.To\n\t}\n\treturn \"\"\n}\n\nfunc (x *Envelope) GetSender() string {\n\tif x != nil {\n\t\treturn x.Sender\n\t}\n\treturn \"\"\n}\n\nfunc (x *Envelope) GetProtocolId() string {\n\tif x != nil {\n\t\treturn x.ProtocolId\n\t}\n\treturn \"\"\n}\n\nfunc (x *Envelope) GetMessage() []byte {\n\tif x != nil {\n\t\treturn x.Message\n\t}\n\treturn nil\n}\n\nfunc (x *Envelope) GetUri() string {\n\tif x != nil {\n\t\treturn x.Uri\n\t}\n\treturn \"\"\n}\n\nvar File_base_proto protoreflect.FileDescriptor\n\nvar file_base_proto_rawDesc = []byte{\n\t0x0a, 0x0a, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0f, 0x61, 0x65,\n\t0x61, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x30, 0x5f, 0x31, 0x5f, 0x30, 0x1a, 0x1c, 0x67,\n\t0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x73,\n\t0x74, 0x72, 0x75, 0x63, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xe2, 0x01, 0x0a, 0x0f,\n\t0x44, 0x69, 0x61, 0x6c, 0x6f, 0x67, 0x75, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12,\n\t0x1d, 0x0a, 0x0a, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20,\n\t0x01, 0x28, 0x05, 0x52, 0x09, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x64, 0x12, 0x3c,\n\t0x0a, 0x1a, 0x64, 0x69, 0x61, 0x6c, 0x6f, 0x67, 0x75, 0x65, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74,\n\t0x65, 0x72, 0x5f, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01,\n\t0x28, 0x09, 0x52, 0x18, 0x64, 0x69, 0x61, 0x6c, 0x6f, 0x67, 0x75, 0x65, 0x53, 0x74, 0x61, 0x72,\n\t0x74, 0x65, 0x72, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x40, 0x0a, 0x1c,\n\t0x64, 0x69, 0x61, 0x6c, 0x6f, 0x67, 0x75, 0x65, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x64,\n\t0x65, 0x72, 0x5f, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01,\n\t0x28, 0x09, 0x52, 0x1a, 0x64, 0x69, 0x61, 0x6c, 0x6f, 0x67, 0x75, 0x65, 0x52, 0x65, 0x73, 0x70,\n\t0x6f, 0x6e, 0x64, 0x65, 0x72, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x16,\n\t0x0a, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06,\n\t0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e,\n\t0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74,\n\t0x22, 0x92, 0x01, 0x0a, 0x07, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2d, 0x0a, 0x04,\n\t0x62, 0x6f, 0x64, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f,\n\t0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72,\n\t0x75, 0x63, 0x74, 0x48, 0x00, 0x52, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x12, 0x4d, 0x0a, 0x10, 0x64,\n\t0x69, 0x61, 0x6c, 0x6f, 0x67, 0x75, 0x65, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18,\n\t0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x62, 0x61, 0x73, 0x65,\n\t0x2e, 0x76, 0x30, 0x5f, 0x31, 0x5f, 0x30, 0x2e, 0x44, 0x69, 0x61, 0x6c, 0x6f, 0x67, 0x75, 0x65,\n\t0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0f, 0x64, 0x69, 0x61, 0x6c, 0x6f,\n\t0x67, 0x75, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x09, 0x0a, 0x07, 0x6d, 0x65,\n\t0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x7f, 0x0a, 0x08, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70,\n\t0x65, 0x12, 0x0e, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x74,\n\t0x6f, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28,\n\t0x09, 0x52, 0x06, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x72, 0x6f,\n\t0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a,\n\t0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65,\n\t0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6d, 0x65, 0x73,\n\t0x73, 0x61, 0x67, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x69, 0x18, 0x05, 0x20, 0x01, 0x28,\n\t0x09, 0x52, 0x03, 0x75, 0x72, 0x69, 0x42, 0x13, 0x5a, 0x11, 0x61, 0x65, 0x61, 0x6c, 0x69, 0x74,\n\t0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f,\n\t0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_base_proto_rawDescOnce sync.Once\n\tfile_base_proto_rawDescData = file_base_proto_rawDesc\n)\n\nfunc file_base_proto_rawDescGZIP() []byte {\n\tfile_base_proto_rawDescOnce.Do(func() {\n\t\tfile_base_proto_rawDescData = protoimpl.X.CompressGZIP(file_base_proto_rawDescData)\n\t})\n\treturn file_base_proto_rawDescData\n}\n\nvar file_base_proto_msgTypes = make([]protoimpl.MessageInfo, 3)\nvar file_base_proto_goTypes = []interface{}{\n\t(*DialogueMessage)(nil), // 0: aea.base.v0_1_0.DialogueMessage\n\t(*Message)(nil),         // 1: aea.base.v0_1_0.Message\n\t(*Envelope)(nil),        // 2: aea.base.v0_1_0.Envelope\n\t(*_struct.Struct)(nil),  // 3: google.protobuf.Struct\n}\nvar file_base_proto_depIdxs = []int32{\n\t3, // 0: aea.base.v0_1_0.Message.body:type_name -> google.protobuf.Struct\n\t0, // 1: aea.base.v0_1_0.Message.dialogue_message:type_name -> aea.base.v0_1_0.DialogueMessage\n\t2, // [2:2] is the sub-list for method output_type\n\t2, // [2:2] is the sub-list for method input_type\n\t2, // [2:2] is the sub-list for extension type_name\n\t2, // [2:2] is the sub-list for extension extendee\n\t0, // [0:2] is the sub-list for field type_name\n}\n\nfunc init() { file_base_proto_init() }\nfunc file_base_proto_init() {\n\tif File_base_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_base_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*DialogueMessage); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_base_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Message); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_base_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Envelope); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\tfile_base_proto_msgTypes[1].OneofWrappers = []interface{}{\n\t\t(*Message_Body)(nil),\n\t\t(*Message_DialogueMessage)(nil),\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_base_proto_rawDesc,\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   3,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_base_proto_goTypes,\n\t\tDependencyIndexes: file_base_proto_depIdxs,\n\t\tMessageInfos:      file_base_proto_msgTypes,\n\t}.Build()\n\tFile_base_proto = out.File\n\tfile_base_proto_rawDesc = nil\n\tfile_base_proto_goTypes = nil\n\tfile_base_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "libs/go/aealite/protocols/base.proto",
    "content": "syntax = \"proto3\";\n\npackage aea.base.v0_1_0;\n\noption go_package = \"aealite/protocols\";\n\nimport \"google/protobuf/struct.proto\";\n\n\nmessage DialogueMessage {\n  int32 message_id = 1;\n  string dialogue_starter_reference = 2;\n  string dialogue_responder_reference = 3;\n  int32 target = 4;\n  bytes content = 5;\n}\n\nmessage Message {\n  oneof message {\n    google.protobuf.Struct body = 1;\n    DialogueMessage dialogue_message = 2;\n  }\n}\n\nmessage Envelope{\n  string to = 1;\n  string sender = 2;\n  string protocol_id = 3;\n  bytes message = 4;\n  string uri = 5;\n}\n"
  },
  {
    "path": "libs/go/aealite/protocols/dialogue.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2019 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\n\npackage protocols\n\nimport (\n\t\"aealite/helpers\"\n\t\"errors\"\n\t\"fmt\"\n)\n\ntype Role string\ntype EndStates string\n\nconst (\n\tNonceBytesNb                           = 32\n\tRole1                        Role      = \"role1\"\n\tRole2                        Role      = \"role2\"\n\tStartingMessageId            MessageId = 1\n\tStartingTarget               MessageId = 0\n\tUnassignedDialogueReference            = \"\"\n\tDialogueLabelStringSeparator           = \"_\"\n)\n\n/* Utility methods */\n\nfunc max(list []MessageId) MessageId {\n\tmax := list[0]\n\tfor i := 1; i < len(list); i++ {\n\t\tif max < list[i] {\n\t\t\tmax = list[i]\n\t\t}\n\t}\n\treturn max\n}\n\nfunc abs(id MessageId) MessageId {\n\tif id < 0 {\n\t\treturn -id\n\t}\n\treturn id\n}\n\n/* Definition of main data types */\n\ntype Rules struct {\n\tinitialPerformatives  helpers.Set\n\tterminalPerformatives helpers.Set\n\tvalidReplies          map[Performative]helpers.Set\n}\n\nfunc NewRules(initialPerformatives []Performative, terminalPerformatives []Performative,\n\tvalidReplies map[Performative][]Performative) Rules {\n\tinitialPerformativesSet := helpers.NewSet()\n\tfor _, initialPeformative := range initialPerformatives {\n\t\tinitialPerformativesSet.Add(initialPeformative)\n\t}\n\n\tterminalPerformativesSet := helpers.NewSet()\n\tfor _, terminalPerformative := range terminalPerformatives {\n\t\tterminalPerformativesSet.Add(terminalPerformative)\n\t}\n\n\tvalidRepliesMap := make(map[Performative]helpers.Set)\n\tfor performative, validPerformatives := range validReplies {\n\t\tset := helpers.NewSet()\n\t\tfor _, validPerformative := range validPerformatives {\n\t\t\tset.Add(validPerformative)\n\t\t}\n\t\tvalidRepliesMap[performative] = set\n\t}\n\trules := Rules{\n\t\tinitialPerformatives:  initialPerformativesSet,\n\t\tterminalPerformatives: terminalPerformativesSet,\n\t\tvalidReplies:          validRepliesMap,\n\t}\n\treturn rules\n}\n\ntype DialogueInterface interface {\n\t// getters\n\n\tDialogueLabel() DialogueLabel\n\tIncompleteDialogueLabel() DialogueLabel\n\tDialogueLabels() [2]DialogueLabel\n\tSelfAddress() Address\n\tRole() Role\n\tRules() Rules\n\tgetMessageClass() *ProtocolMessageInterface\n\tIsSelfInitiated() bool\n\tLastIncomingMessage() *ProtocolMessageInterface\n\tLastOutgoingMessage() *ProtocolMessageInterface\n\tLastMessage() *ProtocolMessageInterface\n\tIsEmpty() bool\n\tReply(\n\t\tPerformative,\n\t\tProtocolMessageInterface,\n\t\tMessageId,\n\t) (ProtocolMessageInterface, error)\n\tString() string\n\n\tcounterPartyFromMessage(*ProtocolMessageInterface) Address\n\tisMessageBySelf(*ProtocolMessageInterface) bool\n\tisMessageByOther(*ProtocolMessageInterface) bool\n\thasMessageId(MessageId) bool\n\tupdate(*ProtocolMessageInterface)\n\tisBelongingToDialogue(*ProtocolMessageInterface) bool\n\tvalidateNextMessage(*ProtocolMessageInterface) error\n\tbasicValidations(*ProtocolMessageInterface) error\n\tbasicValidationInitialMessage(*ProtocolMessageInterface) error\n\tbasicValidationNonInitialMessage(*ProtocolMessageInterface) error\n\tvalidateMessageTarget(*ProtocolMessageInterface) string\n\tvalidateMessageId(*ProtocolMessageInterface) string\n\tgetMessageById(MessageId) *ProtocolMessageInterface\n\tgetOutgoingNextMessageId() MessageId\n\tgetIncomingNextMessageId() MessageId\n\tupdateDialogueLabel(DialogueLabel) error\n\tcustomValidation(*ProtocolMessageInterface) error\n}\n\n/* Dialogue definition and methods */\n\ntype Dialogue struct {\n\tdialogueLabel          DialogueLabel              // dialogueLabel: the dialogue label for this dialogue\n\trole                   Role                       // role: the role of the agent this dialogue is maintained for\n\tselfAddress            Address                    // selfAddress: the address of the entity for whom this dialogue is maintained\n\toutgoingMessages       []ProtocolMessageInterface // outgoingMessages: list of outgoing messages\n\tincomingMessages       []ProtocolMessageInterface // incomingMessages: list of incoming messages\n\tlastMessageId          MessageId                  // lastMessageId: the last message id for this dialogue.\n\torderedMessageIds      []MessageId                // orderedMessageIds: the ordered message ids.\n\trules                  Rules                      // rules: the rules for this dialogue\n\tterminalStateCallbacks []func(*Dialogue)          // terminalStateCallbacks: the callbacks to be called when the dialogue reaches a terminal state.\n}\n\n// DialogueLabel return the dialogue label.\nfunc (dialogue *Dialogue) DialogueLabel() DialogueLabel {\n\treturn dialogue.dialogueLabel\n}\n\n// IncompleteDialogueLabel return the incomplete dialogue label.\nfunc (dialogue *Dialogue) IncompleteDialogueLabel() DialogueLabel {\n\treturn dialogue.dialogueLabel.IncompleteVersion()\n}\n\n// DialogueLabels get the dialogue labels (incomplete and complete, if it exists).\nfunc (dialogue *Dialogue) DialogueLabels() [2]DialogueLabel {\n\treturn [2]DialogueLabel{dialogue.dialogueLabel, dialogue.IncompleteDialogueLabel()}\n}\n\n// SelfAddress get the address of the entity for whom this dialogues is maintained.\nfunc (dialogue *Dialogue) SelfAddress() Address {\n\treturn dialogue.selfAddress\n}\n\n// Role get the agent's role in the dialogue.\nfunc (dialogue *Dialogue) Role() Role {\n\treturn dialogue.role\n}\n\n// Rules get the dialogue rules.\nfunc (dialogue *Dialogue) Rules() Rules {\n\treturn dialogue.rules\n}\n\nfunc (dialogue *Dialogue) AddTerminalStateCallback(fn func(*Dialogue)) {\n\tdialogue.terminalStateCallbacks = append(dialogue.terminalStateCallbacks, fn)\n}\n\n// IsSelfInitiated Check whether the agent initiated the dialogue.\nfunc (dialogue *Dialogue) IsSelfInitiated() bool {\n\treturn dialogue.dialogueLabel.dialogueStarterAddress != dialogue.dialogueLabel.dialogueOpponentAddress\n}\n\nfunc (dialogue *Dialogue) LastIncomingMessage() ProtocolMessageInterface {\n\tif length := len(dialogue.incomingMessages); length > 0 {\n\t\treturn dialogue.incomingMessages[length-1]\n\t}\n\treturn nil\n}\n\nfunc (dialogue *Dialogue) LastOutgoingMessage() ProtocolMessageInterface {\n\tif length := len(dialogue.outgoingMessages); length > 0 {\n\t\treturn dialogue.outgoingMessages[length-1]\n\t}\n\treturn nil\n}\n\nfunc (dialogue *Dialogue) LastMessage() ProtocolMessageInterface {\n\t// check if message id is unset\n\tif dialogue.lastMessageId == 0 {\n\t\treturn nil\n\t}\n\tlastIncomingMessage := dialogue.LastIncomingMessage()\n\tif lastIncomingMessage != nil && lastIncomingMessage.MessageId() == dialogue.lastMessageId {\n\t\treturn lastIncomingMessage\n\t}\n\treturn dialogue.LastOutgoingMessage()\n}\n\nfunc (dialogue *Dialogue) isEmpty() bool {\n\treturn len(dialogue.outgoingMessages) == 0 && len(dialogue.incomingMessages) == 0\n}\n\nfunc (dialogue *Dialogue) counterPartyFromMessage(message ProtocolMessageInterface) Address {\n\tif dialogue.isMessageBySelf(message) {\n\t\treturn message.To()\n\t}\n\treturn message.Sender()\n}\n\nfunc (dialogue *Dialogue) isMessageBySelf(message ProtocolMessageInterface) bool {\n\treturn message.Sender() == dialogue.selfAddress\n}\n\nfunc (dialogue *Dialogue) hasMessageId(messageId MessageId) bool {\n\tmsg := dialogue.getMessageById(messageId)\n\treturn msg != nil\n}\n\nfunc (dialogue *Dialogue) update(message ProtocolMessageInterface) error {\n\tif !(message).HasSender() {\n\t\t// the error is safe to ignore thanks to the above check\n\t\t_ = (message).SetSender(dialogue.selfAddress)\n\t}\n\tisBelongingToDialogue := dialogue.isBelongingToDialogue(message)\n\tif !isBelongingToDialogue {\n\t\treturn errors.New(\"message does not belong to this dialogue\")\n\t}\n\tif err := dialogue.validateNextMessage(message); err != nil {\n\t\treturn err\n\t}\n\n\tif dialogue.isMessageBySelf(message) {\n\t\tdialogue.outgoingMessages = append(dialogue.outgoingMessages, message)\n\t} else {\n\t\tdialogue.incomingMessages = append(dialogue.incomingMessages, message)\n\t}\n\t// update last message id\n\tdialogue.lastMessageId = message.MessageId()\n\t// append message ids in ordered manner\n\tdialogue.orderedMessageIds = append(dialogue.orderedMessageIds, message.MessageId())\n\n\tperformative := message.Performative()\n\tif dialogue.rules.terminalPerformatives.Contains(performative) {\n\t\tfor _, fn := range dialogue.terminalStateCallbacks {\n\t\t\tfn(dialogue)\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (dialogue *Dialogue) isBelongingToDialogue(message ProtocolMessageInterface) bool {\n\topponent := dialogue.counterPartyFromMessage(message)\n\tvar label DialogueLabel\n\tif dialogue.IsSelfInitiated() {\n\t\tlabel = DialogueLabel{\n\t\t\tdialogueReference: DialogueReference{\n\t\t\t\tmessage.DialogueReference().dialogueStarterReference,\n\t\t\t\tUnassignedDialogueReference,\n\t\t\t},\n\t\t\tdialogueOpponentAddress: opponent,\n\t\t\tdialogueStarterAddress:  dialogue.selfAddress,\n\t\t}\n\t} else {\n\t\tlabel = DialogueLabel{\n\t\t\tdialogueReference:       message.DialogueReference(),\n\t\t\tdialogueOpponentAddress: opponent,\n\t\t\tdialogueStarterAddress:  opponent,\n\t\t}\n\t}\n\tresult := dialogue.checkLabelBelongsToDialogue(label)\n\treturn result\n}\n\nfunc (dialogue *Dialogue) Reply(\n\tperformative Performative,\n\ttargetMessage ProtocolMessageInterface,\n\ttargetPtr *MessageId,\n) (ProtocolMessageInterface, error) {\n\tlastMessage := dialogue.LastMessage()\n\tif lastMessage == nil {\n\t\treturn nil, errors.New(\"cannot reply in an empty dialogue\")\n\t}\n\tvar target MessageId\n\tmsgIsNone := targetMessage == nil\n\ttargetIsNone := targetPtr == nil\n\n\tif msgIsNone && !targetIsNone {\n\t\ttarget = *targetPtr\n\t\ttargetMessage = dialogue.getMessageById(*targetPtr)\n\t} else if msgIsNone && targetIsNone {\n\t\ttargetMessage = lastMessage\n\t\ttarget = lastMessage.MessageId()\n\t} else if !msgIsNone && targetIsNone {\n\t\ttarget = targetMessage.MessageId()\n\t} else if !msgIsNone && !targetIsNone {\n\t\ttarget = *targetPtr\n\t\tif target != targetMessage.MessageId() {\n\t\t\treturn nil, errors.New(\"the provided target and target_message do not match\")\n\t\t}\n\t}\n\n\tif targetMessage == nil {\n\t\treturn nil, errors.New(\"no target message found\")\n\t}\n\n\tif !dialogue.hasMessageId(target) {\n\t\treturn nil, errors.New(\"the target message does not exist in this dialogue\")\n\t}\n\n\treply := DialogueMessageWrapper{\n\t\tdialogueReference: dialogue.dialogueLabel.dialogueReference,\n\t\tmessageId:         dialogue.getOutgoingNextMessageId(),\n\t\tsender:            dialogue.selfAddress,\n\t\tto:                dialogue.dialogueLabel.dialogueOpponentAddress,\n\t\ttarget:            target,\n\t\tperformative:      performative,\n\t}\n\n\terr := dialogue.update(&reply)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &reply, nil\n}\n\nfunc (dialogue *Dialogue) validateNextMessage(message ProtocolMessageInterface) error {\n\terr := dialogue.basicValidation(message)\n\tif err != nil {\n\t\treturn err\n\t}\n\t// check if custom validation\n\n\treturn nil\n}\n\nfunc (dialogue *Dialogue) checkLabelBelongsToDialogue(label DialogueLabel) bool {\n\treturn label == dialogue.dialogueLabel || label == dialogue.dialogueLabel.IncompleteVersion()\n}\n\nfunc (dialogue *Dialogue) basicValidation(message ProtocolMessageInterface) error {\n\tif dialogue.isEmpty() {\n\t\treturn dialogue.basicValidationInitialMessage(message)\n\t}\n\treturn dialogue.basicValidationNonInitialMessage(message)\n}\n\nfunc (dialogue *Dialogue) basicValidationInitialMessage(\n\tmessage ProtocolMessageInterface,\n) error {\n\tdialogueReference := message.DialogueReference()\n\tmessageId := message.MessageId()\n\tperformative := message.Performative()\n\texpectedReference := dialogue.dialogueLabel.dialogueReference.dialogueStarterReference\n\tactualReference := dialogueReference.dialogueStarterReference\n\tif expectedReference != actualReference {\n\t\treturn fmt.Errorf(\n\t\t\t\"invalid dialogue_reference.dialogueStarterReference: expected %s, found %s\",\n\t\t\texpectedReference,\n\t\t\tactualReference,\n\t\t)\n\t}\n\tif messageId != StartingMessageId {\n\t\treturn fmt.Errorf(\"invalid message id: expected %v, found %v\", StartingMessageId, messageId)\n\t}\n\n\terr := dialogue.validateMessageTarget(message)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t//check if performative exists in initial performatives\n\tif !dialogue.rules.initialPerformatives.Contains(performative) {\n\t\treturn errors.New(\"invalid initial performative\")\n\t}\n\t// The initial message passes basic validation -> no errors\n\treturn nil\n}\n\nfunc (dialogue *Dialogue) basicValidationNonInitialMessage(\n\tmessage ProtocolMessageInterface,\n) error {\n\tdialogueReference := message.DialogueReference()\n\texpectedReference := dialogue.dialogueLabel.dialogueReference.dialogueStarterReference\n\tactualReference := dialogueReference.dialogueStarterReference\n\tif expectedReference != actualReference {\n\t\treturn fmt.Errorf(\n\t\t\t\"invalid dialogue_reference.dialogueStarterReference: expected %s, found %s\",\n\t\t\texpectedReference,\n\t\t\tactualReference,\n\t\t)\n\t}\n\terr := dialogue.validateMessageId(message)\n\tif err != nil {\n\t\treturn err\n\t}\n\terr = dialogue.validateMessageTarget(message)\n\tif err != nil {\n\t\treturn err\n\t}\n\t// The non-initial message passes basic validation.\n\treturn nil\n}\n\nfunc (dialogue *Dialogue) validateMessageTarget(message ProtocolMessageInterface) error {\n\ttarget := message.Target()\n\tperformative := message.Performative()\n\n\tif message.MessageId() == StartingMessageId {\n\t\tif target == StartingTarget {\n\t\t\treturn nil\n\t\t}\n\t\treturn fmt.Errorf(\"invalid target: expected 0, found %v\", target)\n\t}\n\n\tif message.MessageId() != StartingMessageId && target == StartingTarget {\n\t\treturn fmt.Errorf(\"invalid target: expected a non-zero integer, found %v\", target)\n\t}\n\n\tvar latestIds []MessageId\n\tvar lastIncomingMessage = dialogue.LastIncomingMessage()\n\tif lastIncomingMessage != nil {\n\t\tlatestIds = append(latestIds, abs(lastIncomingMessage.MessageId()))\n\t}\n\tvar lastOutgoingMessage = dialogue.LastOutgoingMessage()\n\tif lastOutgoingMessage != nil {\n\t\tlatestIds = append(latestIds, abs(lastOutgoingMessage.MessageId()))\n\t}\n\n\tif absoluteTarget, maxLatestIds := abs(target), max(latestIds); absoluteTarget > maxLatestIds {\n\t\treturn fmt.Errorf(\"invalid target: expected a value less than or equal to %v. Found %v\",\n\t\t\tmaxLatestIds, absoluteTarget)\n\t}\n\n\ttargetMessage := dialogue.getMessageById(target)\n\tif targetMessage == nil {\n\t\treturn fmt.Errorf(\"invalid target %v: target message can not be found.\", target)\n\t}\n\ttargetPerformative := targetMessage.Performative()\n\n\t// check performatives\n\tsetValidReplies := dialogue.rules.validReplies[targetPerformative]\n\tif !setValidReplies.Contains(performative) {\n\t\treturn fmt.Errorf(\"invalid performative: '%s' is not a valid reply\", performative)\n\t}\n\treturn nil\n}\n\nfunc (dialogue *Dialogue) validateMessageId(message ProtocolMessageInterface) error {\n\tvar nextMessageId MessageId\n\tisOutgoing := message.To() != dialogue.selfAddress\n\tif isOutgoing {\n\t\tnextMessageId = dialogue.getOutgoingNextMessageId()\n\t} else {\n\t\tnextMessageId = dialogue.getIncomingNextMessageId()\n\t}\n\tif actual := message.MessageId(); actual != nextMessageId {\n\t\treturn fmt.Errorf(\"invalid message id: expected %v, found %v\",\n\t\t\tnextMessageId, actual)\n\t}\n\treturn nil\n}\n\nfunc (dialogue *Dialogue) getMessageById(messageId MessageId) ProtocolMessageInterface {\n\tif dialogue.isEmpty() {\n\t\treturn nil\n\t}\n\tif messageId == 0 {\n\t\t// message id == 0 is invalid\n\t\treturn nil\n\t}\n\tvar messagesList []ProtocolMessageInterface\n\tif (messageId > 0) == dialogue.IsSelfInitiated() {\n\t\tmessagesList = dialogue.outgoingMessages\n\t} else {\n\t\tmessagesList = dialogue.incomingMessages\n\t}\n\tif len(messagesList) == 0 {\n\t\treturn nil\n\t}\n\tabsoluteMessageId := abs(messageId)\n\tabsoluteLastMessageId := abs(messagesList[len(messagesList)-1].MessageId())\n\tif absoluteMessageId > absoluteLastMessageId {\n\t\treturn nil\n\t}\n\treturn messagesList[absoluteMessageId-1]\n}\n\nfunc (dialogue *Dialogue) getOutgoingNextMessageId() MessageId {\n\tnextMessageId := StartingMessageId\n\tif dialogue.LastOutgoingMessage() != nil {\n\t\tnextMessageId = abs(dialogue.LastOutgoingMessage().MessageId()) + 1\n\t}\n\tif !dialogue.IsSelfInitiated() {\n\t\tnextMessageId = 0 - nextMessageId\n\t}\n\treturn nextMessageId\n}\n\nfunc (dialogue *Dialogue) getIncomingNextMessageId() MessageId {\n\tnextMessageId := StartingMessageId\n\tif dialogue.LastIncomingMessage() != nil {\n\t\tnextMessageId = abs(dialogue.lastMessageId) + 1\n\t}\n\tif dialogue.IsSelfInitiated() {\n\t\tnextMessageId = 0 - nextMessageId\n\t}\n\treturn nextMessageId\n}\n\nfunc (dialogue *Dialogue) updateDialogueLabel(finalDialogueLabel DialogueLabel) error {\n\tif dialogue.dialogueLabel.DialogueResponderReference() == UnassignedDialogueReference &&\n\t\tfinalDialogueLabel.DialogueResponderReference() == UnassignedDialogueReference {\n\t\treturn errors.New(\"dialogue label cannot be updated\")\n\t}\n\tdialogue.dialogueLabel = finalDialogueLabel\n\treturn nil\n}\n\nfunc NewDialogue(dialogueLabel DialogueLabel,\n\tselfAddress Address,\n\trole Role,\n\tinitialPerformatives []Performative,\n\tterminalPerformatives []Performative,\n\tvalidReplies map[Performative][]Performative) Dialogue {\n\n\tdialogue := Dialogue{\n\t\tdialogueLabel: dialogueLabel,\n\t\tselfAddress:   selfAddress,\n\t\trole:          role,\n\t}\n\tdialogue.incomingMessages = make([]ProtocolMessageInterface, 0)\n\tdialogue.outgoingMessages = make([]ProtocolMessageInterface, 0)\n\tdialogue.orderedMessageIds = make([]MessageId, 0)\n\tdialogue.rules = NewRules(initialPerformatives, terminalPerformatives, validReplies)\n\tdialogue.terminalStateCallbacks = make([]func(*Dialogue), 0)\n\treturn dialogue\n}\n"
  },
  {
    "path": "libs/go/aealite/protocols/dialogue_label.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2019 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\n\npackage protocols\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"strings\"\n)\n\ntype DialogueReference struct {\n\tdialogueStarterReference   string\n\tdialogueResponderReference string\n}\n\nfunc (dialogueReference *DialogueReference) DialogueStarterReference() string {\n\treturn dialogueReference.dialogueStarterReference\n}\nfunc (dialogueReference *DialogueReference) DialogueResponderReference() string {\n\treturn dialogueReference.dialogueResponderReference\n}\n\ntype DialogueLabel struct {\n\tdialogueReference       DialogueReference\n\tdialogueOpponentAddress Address\n\tdialogueStarterAddress  Address\n}\n\n// DialogueReference Get the dialogue reference.\nfunc (dialogueLabel *DialogueLabel) DialogueReference() DialogueReference {\n\treturn dialogueLabel.dialogueReference\n}\n\n// DialogueStarterReference Get the dialogue starter reference.\nfunc (dialogueLabel *DialogueLabel) DialogueStarterReference() string {\n\treturn dialogueLabel.dialogueReference.DialogueStarterReference()\n}\n\n// DialogueResponderReference Get the dialogue responder reference.\nfunc (dialogueLabel *DialogueLabel) DialogueResponderReference() string {\n\treturn dialogueLabel.dialogueReference.DialogueResponderReference()\n}\n\n// IsSelfInitiated Check whether the agent initiated the dialogue.\nfunc (dialogueLabel *DialogueLabel) IsSelfInitiated() bool {\n\treturn dialogueLabel.dialogueStarterAddress != dialogueLabel.dialogueOpponentAddress\n}\n\n// DialogueOpponentAddress Get the dialogue opponent address.\nfunc (dialogueLabel *DialogueLabel) DialogueOpponentAddress() Address {\n\treturn dialogueLabel.dialogueOpponentAddress\n}\n\n// DialogueStarterAddress Get the dialogue starter address.\nfunc (dialogueLabel *DialogueLabel) DialogueStarterAddress() Address {\n\treturn dialogueLabel.dialogueStarterAddress\n}\n\n// IncompleteVersion Get the incomplete version of the label.\nfunc (dialogueLabel *DialogueLabel) IncompleteVersion() DialogueLabel {\n\treturn DialogueLabel{\n\t\tDialogueReference{dialogueLabel.DialogueStarterReference(), UnassignedDialogueReference},\n\t\tdialogueLabel.dialogueOpponentAddress,\n\t\tdialogueLabel.dialogueStarterAddress,\n\t}\n}\n\n// MarshalJSON custom DialogueLabel JSON serializer\nfunc (dialogueLabel DialogueLabel) MarshalJSON() ([]byte, error) {\n\tdata := map[string]string{\n\t\t\"dialogue_starter_reference\":   dialogueLabel.DialogueStarterReference(),\n\t\t\"dialogue_responder_reference\": dialogueLabel.DialogueResponderReference(),\n\t\t\"dialogue_opponent_addr\":       string(dialogueLabel.DialogueOpponentAddress()),\n\t\t\"dialogue_starter_addr\":        string(dialogueLabel.DialogueStarterAddress()),\n\t}\n\tbuffer := bytes.NewBufferString(\"{\")\n\tfor key, value := range data {\n\t\tbuffer.WriteString(fmt.Sprintf(\"\\\"%s\\\": \\\"%s\\\",\", key, value))\n\t}\n\tbuffer.Truncate(buffer.Len() - 1)\n\tbuffer.WriteString(\"}\")\n\treturn buffer.Bytes(), nil\n}\n\n// UnmarshalJSON custom DialogueLabel JSON deserializer\nfunc (dialogueLabel *DialogueLabel) UnmarshalJSON(b []byte) error {\n\tvar data map[string]string\n\terr := json.Unmarshal(b, &data)\n\tif err != nil {\n\t\treturn err\n\t}\n\tstarterReference := data[\"dialogue_starter_reference\"]\n\tresponderReference := data[\"dialogue_responder_reference\"]\n\tdialogueLabel.dialogueReference = DialogueReference{starterReference, responderReference}\n\tdialogueLabel.dialogueOpponentAddress = Address(data[\"dialogue_opponent_addr\"])\n\tdialogueLabel.dialogueStarterAddress = Address(data[\"dialogue_starter_addr\"])\n\treturn nil\n}\n\n// String transform DialogueLabel to its string representation\nfunc (dialogueLabel *DialogueLabel) String() string {\n\treturn strings.Join([]string{dialogueLabel.DialogueStarterReference(),\n\t\tdialogueLabel.DialogueResponderReference(),\n\t\tstring(dialogueLabel.dialogueOpponentAddress),\n\t\tstring(dialogueLabel.dialogueStarterAddress)}, DialogueLabelStringSeparator)\n}\n\n// FromString update a DialogueLabel from a string representation\nfunc (dialogueLabel *DialogueLabel) FromString(s string) error {\n\tresult := strings.Split(s, DialogueLabelStringSeparator)\n\tif length := len(result); length != 4 {\n\t\treturn fmt.Errorf(\"expected exactly 4 parts, got %d\", length)\n\t}\n\tdialogueLabel.dialogueReference = DialogueReference{result[0], result[1]}\n\tdialogueLabel.dialogueOpponentAddress = Address(result[2])\n\tdialogueLabel.dialogueStarterAddress = Address(result[3])\n\treturn nil\n}\n"
  },
  {
    "path": "libs/go/aealite/protocols/dialogue_label_test.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2019 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\n\npackage protocols\n\nimport (\n\t\"encoding/json\"\n\t\"testing\"\n\n\t\"gotest.tools/assert\"\n)\n\nconst (\n\tsenderAddress       Address = \"ba6b08b13043e83a962a3a5eeaad3b6c\"\n\tcounterPartyAddress Address = \"1ba5cb6f46f426a27ec53064032419f1\"\n\tstarterReference    string  = \"starterReference\"\n\tresponderReference  string  = \"responderReference\"\n)\n\n// get a default dialogue label for testing purposes\nfunc getTestDialogueLabel() DialogueLabel {\n\treturn DialogueLabel{\n\t\tDialogueReference{starterReference, responderReference},\n\t\tcounterPartyAddress,\n\t\tsenderAddress,\n\t}\n}\n\n// Test DialogueLabel initialization and getters\nfunc TestDialogueLabelGetters(t *testing.T) {\n\tstarterReference := \"starterReference\"\n\tresponderReference := \"responderReference\"\n\tdialogueReference := DialogueReference{starterReference, responderReference}\n\tlabel := DialogueLabel{\n\t\tdialogueReference,\n\t\tcounterPartyAddress,\n\t\tsenderAddress,\n\t}\n\n\tassert.Equal(t, label.DialogueOpponentAddress(), counterPartyAddress)\n\tassert.Equal(t, label.DialogueStarterAddress(), senderAddress)\n\tassert.Equal(t, label.DialogueStarterReference(), starterReference)\n\tassert.Equal(t, label.DialogueResponderReference(), responderReference)\n\tassert.Equal(t, label.DialogueReference(), dialogueReference)\n\n}\n\n// Test getIncompleteVersion function\nfunc TestGetIncompleteVersion(t *testing.T) {\n\tlabel := getTestDialogueLabel()\n\tactualIncompleteVersion := label.IncompleteVersion()\n\texpectedIncompleteVersion := DialogueLabel{\n\t\tDialogueReference{label.DialogueStarterReference(), UnassignedDialogueReference},\n\t\tlabel.DialogueOpponentAddress(),\n\t\tlabel.DialogueStarterAddress(),\n\t}\n\n\tassert.Equal(\n\t\tt,\n\t\tactualIncompleteVersion,\n\t\texpectedIncompleteVersion,\n\t\t\"getIncompleteVersion gave unexpected result.\",\n\t)\n}\n\n// Test marshalling and unmarshalling\nfunc TestMarshalAndUnmarshal(t *testing.T) {\n\tlabel := getTestDialogueLabel()\n\n\tdata, err := json.Marshal(label)\n\tif err != nil {\n\t\tt.Fatalf(\"DialogueLabel JSON marshalling failed with error: %s\", err.Error())\n\t}\n\n\tresult := DialogueLabel{}\n\terr = json.Unmarshal(data, &result)\n\tif err != nil {\n\t\tt.Fatalf(\"DialogueLabel JSON unmarshalling failed with error: %s\", err.Error())\n\t}\n\tassert.Equal(\n\t\tt,\n\t\tresult,\n\t\tlabel,\n\t\t\"the DialogueLabel parsed from JSON is not the same of the original one.\",\n\t)\n}\n\n// Test ToString and FromString methods.\nfunc TestToStringAndFromString(t *testing.T) {\n\tlabel := getTestDialogueLabel()\n\tresult := DialogueLabel{}\n\terr := result.FromString(label.String())\n\tif err != nil {\n\t\tt.Fatalf(\"Cannot parse string: %s\", err.Error())\n\t}\n\tif label != result {\n\t\tt.Fatal(\"the DialogueLabel parsed from string is not the same of the original one.\")\n\t}\n}\n"
  },
  {
    "path": "libs/go/aealite/protocols/dialogue_test.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2019 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\n\npackage protocols\n\nimport (\n\t\"reflect\"\n\t\"testing\"\n)\n\nfunc TestDialogue(t *testing.T) {\n\tlabel := getTestDialogueLabel()\n\tinitialPerformatives := []Performative{\"start\"}\n\tterminalPerformatives := []Performative{\"end\"}\n\tvalidReplies := map[Performative][]Performative{\"start\": {\"end\"}}\n\trules := NewRules(initialPerformatives, terminalPerformatives, validReplies)\n\tdialogue := NewDialogue(\n\t\tlabel,\n\t\tsenderAddress,\n\t\tRole1,\n\t\tinitialPerformatives,\n\t\tterminalPerformatives,\n\t\tvalidReplies,\n\t)\n\t// test getters\n\tif dialogue.DialogueLabel() != label {\n\t\tt.Fatalf(\"unexpected return value of DialogueLabel()\")\n\t}\n\tif dialogue.IncompleteDialogueLabel() != label.IncompleteVersion() {\n\t\tt.Fatalf(\"unexpected return value of IncompleteDialogueLabel()\")\n\t}\n\tif dialogue.DialogueLabels() != [2]DialogueLabel{label, label.IncompleteVersion()} {\n\t\tt.Fatalf(\"unexpected return value of DialogueLabels()\")\n\t}\n\tif dialogue.SelfAddress() != senderAddress {\n\t\tt.Fatalf(\"unexpected return value of SelfAddress()\")\n\t}\n\tif dialogue.Role() != Role1 {\n\t\tt.Fatalf(\"unexpected return value of Role()\")\n\t}\n\tif !reflect.DeepEqual(dialogue.Rules(), rules) {\n\t\tt.Fatalf(\"unexpected return value of Rules()\")\n\t}\n\tif dialogue.LastIncomingMessage() != nil {\n\t\tt.Fatalf(\"unexpected return value of LastIncomingMessage(): the dialogue should be empty\")\n\t}\n\tif dialogue.LastOutgoingMessage() != nil {\n\t\tt.Fatalf(\"unexpected return value of LastOutgoingMessage(): the dialogue should be empty\")\n\t}\n\tif dialogue.LastMessage() != nil {\n\t\tt.Fatalf(\"unexpected return value of LastMessage(): the dialogue should be empty\")\n\t}\n\n}\n\n////func TestDialogue(t *testing.T) {\n//\tvar performative Performative = \"sample_performative\"\n//\t// createing initital dialogue instance\n//\tmessage, dialogue := Create(\n//\t\tcounterPartyAddress,\n//\t\tsenderAddress,\n//\t\tperformative,\n//\t\t[]byte(\"initial message\"),\n//\t)\n//\t// cheking if message returned has a sender same as senderAddress\n//\tif address, err := message.HasSender(); err != nil {\n//\t\tlog.Fatal(err)\n//\t} else {\n//\t\tif address != senderAddress {\n//\t\t\tlog.Fatal(\"Error: Sender address invalid.\", address, \" \", senderAddress)\n//\t\t}\n//\t}\n//\t// cheking if message returned has a counter party same as counterPartyAddress\n//\tif address, err := message.HasCounterparty(); err != nil {\n//\t\tlog.Fatal(err)\n//\t} else {\n//\t\tif address != counterPartyAddress {\n//\t\t\tlog.Fatal(\"Error: CounterParty address invalid.\")\n//\t\t}\n//\t}\n//\t// checking if length of outgoing messages list is 1\n//\tif len(dialogue.outgoingMessages) != 1 {\n//\t\tlog.Fatal(\n//\t\t\t\"dialogue outgoing messages length is \",\n//\t\t\tlen(dialogue.outgoingMessages),\n//\t\t\t\" should be 1\",\n//\t\t)\n//\t}\n//\t// checking if length of incoming messages list is 0\n//\tif len(dialogue.incomingMessages) != 0 {\n//\t\tlog.Fatal(\n//\t\t\t\"dialogue incoming messages length is \",\n//\t\t\tlen(dialogue.incomingMessages),\n//\t\t\t\" should be 0\",\n//\t\t)\n//\t}\n//\tif dialogue.IsEmpty() == true {\n//\t\tlog.Fatal(\"dialogue should not be empty\")\n//\t}\n//\t// fetch message id for next mesaage in the dialogue\n//\tvar nextMessageId MessageId\n//\tif dialogue.selfAddress == senderAddress {\n//\t\tnextMessageId = dialogue.getOutgoingNextMessageId()\n//\t} else {\n//\t\tnextMessageId = dialogue.getIncomingNextMessageId()\n//\t}\n//\t// inititlaizing a new message and updating dialogue using it\n//\tnewMessage := InitializeMessage(\n//\t\tcounterPartyAddress,\n//\t\tsenderAddress,\n//\t\tperformative,\n//\t\t[]byte(\"second message\"),\n//\t\tdialogue.dialogueLabel.DialogueReference(),\n//\t\tnextMessageId,\n//\t\tdialogue.lastMessageId,\n//\t)\n//\tdialogue.update(newMessage)\n//\t// checking if length of outgoing messages list is 2\n//\tif len(dialogue.outgoingMessages) != 2 {\n//\t\tlog.Fatal(\n//\t\t\t\"dialogue outgoing messages length is \",\n//\t\t\tlen(dialogue.outgoingMessages),\n//\t\t\t\" should be 2\",\n//\t\t)\n//\t}\n//\t// checking if length of incoming messages list is 0\n//\tif len(dialogue.incomingMessages) != 0 {\n//\t\tlog.Fatal(\n//\t\t\t\"dialogue incoming messages length is \",\n//\t\t\tlen(dialogue.incomingMessages),\n//\t\t\t\" should be 0\",\n//\t\t)\n//\t}\n//}\n"
  },
  {
    "path": "libs/go/aealite/protocols/dialogues.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2019 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\n\npackage protocols\n\nimport (\n\t\"aealite/helpers\"\n\t\"crypto/rand\"\n\t\"encoding/hex\"\n\t\"errors\"\n\t\"fmt\"\n)\n\nconst (\n\tIncompleteDialogues     = \"incomplete_dialogues\"\n\tTerminalDialoguesSuffix = \"_terminal\"\n)\n\n/* Utility methods */\n\nfunc generateDialogueNonce() string {\n\thexValue := randomHex(NonceBytesNb)\n\treturn hexValue\n}\n\nfunc randomHex(n int) string {\n\tbytes := make([]byte, n)\n\tif _, err := rand.Read(bytes); err != nil {\n\t\treturn \"\"\n\t}\n\treturn hex.EncodeToString(bytes)\n}\n\nfunc newSelfInitiatedDialogueReference() DialogueReference {\n\treturn DialogueReference{generateDialogueNonce(), UnassignedDialogueReference}\n}\n\ntype Dialogues struct {\n\tselfAddress                Address\n\tendStates                  helpers.Set\n\troleFromFirstMessage       func(ProtocolMessageInterface, Address) Role\n\tkeepTerminalStateDialogues bool\n\n\tdialogueName    string\n\tdialogueStorage DialogueStorageInterface\n\n\tinitialPerformatives  []Performative\n\tterminalPerformatives []Performative\n\tvalidReplies          map[Performative][]Performative\n}\n\nfunc (dialogues *Dialogues) IsKeepDialoguesInTerminalStates() bool {\n\treturn dialogues.keepTerminalStateDialogues\n}\n\nfunc (dialogues *Dialogues) SelfAddress() (Address, error) {\n\tif dialogues.selfAddress == \"\" {\n\t\treturn \"\", errors.New(\"'self address' is not set\")\n\t}\n\treturn dialogues.selfAddress, nil\n}\n\nfunc (dialogues *Dialogues) GetDialoguesWithCounterparty(counterparty Address) []*Dialogue {\n\treturn dialogues.dialogueStorage.GetDialoguesWithCounterparty(counterparty)\n}\n\nfunc (dialogues *Dialogues) isMessageBySelf(message ProtocolMessageInterface) bool {\n\treturn message.Sender() == dialogues.selfAddress\n}\n\nfunc (dialogues *Dialogues) isMessageByOther(message ProtocolMessageInterface) bool {\n\treturn !dialogues.isMessageBySelf(message)\n}\n\nfunc (dialogues *Dialogues) counterpartyFromMessage(message ProtocolMessageInterface) Address {\n\tif dialogues.isMessageBySelf(message) {\n\t\treturn message.To()\n\t}\n\treturn message.Sender()\n}\n\nfunc (dialogues *Dialogues) Create(\n\tcounterparty Address,\n\tperformative Performative,\n\tbody map[string]interface{},\n) (ProtocolMessageInterface, *Dialogue, error) {\n\tdialogueReference := newSelfInitiatedDialogueReference()\n\tinitialMessage := DialogueMessageWrapper{\n\t\tdialogueReference: dialogueReference,\n\t\tmessageId:         StartingMessageId,\n\t\ttarget:            StartingTarget,\n\t\tperformative:      performative,\n\t}\n\t// safe to ignore errors as the message was just created\n\t_ = initialMessage.SetSender(dialogues.selfAddress)\n\t_ = initialMessage.SetTo(counterparty)\n\n\tdialogue, err := dialogues.createDialogue(counterparty, &initialMessage)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\treturn &initialMessage, dialogue, nil\n}\n\nfunc (dialogues *Dialogues) CreateWithMessage(\n\tcounterparty Address,\n\tinitialMessage ProtocolMessageInterface,\n) (*Dialogue, error) {\n\terr := initialMessage.SetSender(dialogues.selfAddress)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\terr = initialMessage.SetTo(counterparty)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dialogues.createDialogue(counterparty, initialMessage)\n}\n\nfunc (dialogues *Dialogues) createDialogue(\n\tcounterparty Address,\n\tinitialMessage ProtocolMessageInterface,\n) (*Dialogue, error) {\n\tdialogue, err := dialogues.createSelfInitiated(counterparty,\n\t\tinitialMessage.DialogueReference(),\n\t\tdialogues.roleFromFirstMessage(initialMessage, dialogues.selfAddress))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\terr = dialogue.update(initialMessage)\n\tif err != nil {\n\t\t// if update fails, we don't propagate the error.\n\t\treturn nil, nil\n\t}\n\treturn dialogue, nil\n}\n\nfunc (dialogues *Dialogues) Update(message ProtocolMessageInterface) (*Dialogue, error) {\n\tif !(message.HasSender() && dialogues.isMessageByOther(message)) {\n\t\treturn nil, errors.New(\n\t\t\t\"invalid update: this method must only be used with a message by another agent\",\n\t\t)\n\t}\n\tif !message.HasTo() {\n\t\treturn nil, errors.New(\"the message's 'to' field is not set\")\n\t}\n\tif message.To() != dialogues.selfAddress {\n\t\treturn nil, fmt.Errorf(\n\t\t\t\"message 'to' and dialogue 'self address' do not match: got 'to=%s' expected 'to=%s'\",\n\t\t\tmessage.To(),\n\t\t\tdialogues.selfAddress,\n\t\t)\n\t}\n\n\tdialogueReference := message.DialogueReference()\n\tstarterRefAssigned := dialogueReference.dialogueStarterReference != UnassignedDialogueReference\n\tresponderRefAssigned := dialogueReference.dialogueResponderReference != UnassignedDialogueReference\n\tisStartingMsgId := message.MessageId() == StartingMessageId\n\tisStartingTarget := message.MessageId() == StartingTarget\n\tisInvalidLabel := !starterRefAssigned && responderRefAssigned\n\tisNewDialogue := starterRefAssigned && !responderRefAssigned && isStartingMsgId\n\tisIncompleteLabelAndNotInitialMsg := starterRefAssigned && !responderRefAssigned && !isStartingMsgId &&\n\t\t!isStartingTarget\n\n\tvar dialogue *Dialogue\n\tvar err error\n\tif isInvalidLabel {\n\t\tdialogue = nil\n\t} else if isNewDialogue {\n\t\tdialogue, err = dialogues.createOpponentInitiated(message.Sender(), dialogueReference, dialogues.roleFromFirstMessage(message, dialogues.selfAddress))\n\t\tif err != nil {\n\t\t\t// propagate the error\n\t\t\treturn nil, err\n\t\t}\n\t} else if isIncompleteLabelAndNotInitialMsg {\n\t\t// we can allow a dialogue to have incomplete reference\n\t\t// as multiple messages can be sent before one is received with complete reference\n\t\tdialogue = dialogues.GetDialogue(message)\n\t} else {\n\t\terr = dialogues.completeDialogueReference(message)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tdialogue = dialogues.GetDialogue(message)\n\t}\n\n\tif dialogue != nil {\n\t\terr := dialogue.update(message)\n\n\t\tif err != nil {\n\t\t\t// invalid message for the dialogue found\n\t\t\tif isNewDialogue {\n\t\t\t\t// remove the newly created dialogue if the initial message is invalid\n\t\t\t\tdialogues.dialogueStorage.RemoveDialogue(dialogue.dialogueLabel)\n\t\t\t}\n\t\t\tdialogue = nil\n\t\t\treturn dialogue, err\n\t\t}\n\t\treturn dialogue, nil\n\t}\n\t// couldn't find the dialogue referenced by the message\n\treturn nil, nil\n\n}\n\nfunc (dialogues *Dialogues) completeDialogueReference(message ProtocolMessageInterface) error {\n\tcompleteDialogueReference := message.DialogueReference()\n\tstarterRef := completeDialogueReference.dialogueStarterReference\n\tresponderRef := completeDialogueReference.dialogueResponderReference\n\tif !(starterRef != UnassignedDialogueReference && responderRef != UnassignedDialogueReference) {\n\t\treturn errors.New(\"only complete dialogue references allowed\")\n\t}\n\tincompleteDialogueReference := DialogueReference{\n\t\tstarterRef,\n\t\tUnassignedDialogueReference,\n\t}\n\tincompleteDialogueLabel := DialogueLabel{\n\t\tincompleteDialogueReference,\n\t\tmessage.Sender(),\n\t\tdialogues.selfAddress,\n\t}\n\n\tif dialogues.dialogueStorage.IsDialoguePresent(incompleteDialogueLabel) &&\n\t\t!(dialogues.dialogueStorage.IsInIncomplete(incompleteDialogueLabel)) {\n\t\tdialogue := dialogues.dialogueStorage.GetDialogue(incompleteDialogueLabel)\n\t\tif dialogue == nil {\n\t\t\treturn errors.New(\"dialogue not found\")\n\t\t}\n\t\tdialogues.dialogueStorage.RemoveDialogue(incompleteDialogueLabel)\n\t\tfinalDialogueLabel := DialogueLabel{\n\t\t\tcompleteDialogueReference,\n\t\t\tincompleteDialogueLabel.dialogueOpponentAddress,\n\t\t\tincompleteDialogueLabel.dialogueStarterAddress,\n\t\t}\n\t\terr := dialogue.updateDialogueLabel(finalDialogueLabel)\n\t\tif err != nil {\n\t\t\t// propagate error\n\t\t\treturn err\n\t\t}\n\t\tdialogues.dialogueStorage.AddDialogue(dialogue)\n\t\tdialogues.dialogueStorage.SetIncompleteDialogue(incompleteDialogueLabel, finalDialogueLabel)\n\t}\n\n\treturn nil\n}\n\nfunc (dialogues *Dialogues) GetDialogue(message ProtocolMessageInterface) *Dialogue {\n\tcounterpartyFromMessage := dialogues.counterpartyFromMessage(message)\n\tdialogueReference := message.DialogueReference()\n\n\tselfInitiatedDialogueLabel := DialogueLabel{\n\t\tdialogueReference,\n\t\tcounterpartyFromMessage,\n\t\tdialogues.selfAddress,\n\t}\n\totherInitiatedDialogueLabel := DialogueLabel{\n\t\tdialogueReference,\n\t\tcounterpartyFromMessage,\n\t\tcounterpartyFromMessage,\n\t}\n\n\tselfInitiatedDialogueLabel = dialogues.getLatestLabel(selfInitiatedDialogueLabel)\n\totherInitiatedDialogueLabel = dialogues.getLatestLabel(otherInitiatedDialogueLabel)\n\n\tselfInitiatedDialogue := dialogues.GetDialogueFromLabel(selfInitiatedDialogueLabel)\n\totherInitiatedDialogue := dialogues.GetDialogueFromLabel(otherInitiatedDialogueLabel)\n\tif selfInitiatedDialogue != nil {\n\t\treturn selfInitiatedDialogue\n\t}\n\treturn otherInitiatedDialogue\n\n}\n\nfunc (dialogues *Dialogues) getLatestLabel(label DialogueLabel) DialogueLabel {\n\treturn dialogues.dialogueStorage.GetLatestLabel(label)\n}\n\nfunc (dialogues *Dialogues) GetDialogueFromLabel(label DialogueLabel) *Dialogue {\n\treturn dialogues.dialogueStorage.GetDialogue(label)\n}\n\nfunc (dialogues *Dialogues) createSelfInitiated(\n\tdialogueOpponentAddress Address,\n\tdialogueReference DialogueReference,\n\trole Role,\n) (*Dialogue, error) {\n\tstarterRef := dialogueReference.DialogueStarterReference()\n\tresponderRef := dialogueReference.DialogueResponderReference()\n\tif !(starterRef != UnassignedDialogueReference && responderRef == UnassignedDialogueReference) {\n\t\treturn nil, errors.New(\n\t\t\t\"cannot initiate dialogue with preassigned dialogue_responder_reference\",\n\t\t)\n\t}\n\tincompleteDialogueLabel := DialogueLabel{\n\t\tdialogueReference:       dialogueReference,\n\t\tdialogueOpponentAddress: dialogueOpponentAddress,\n\t\tdialogueStarterAddress:  dialogues.selfAddress,\n\t}\n\tdialogue, err := dialogues.create(incompleteDialogueLabel, role, nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dialogue, nil\n}\n\nfunc (dialogues *Dialogues) createOpponentInitiated(dialogueOpponentAddress Address,\n\tdialogueReference DialogueReference,\n\trole Role,\n) (*Dialogue, error) {\n\tstarterRef := dialogueReference.DialogueStarterReference()\n\tresponderRef := dialogueReference.DialogueResponderReference()\n\tif !(starterRef != UnassignedDialogueReference && responderRef == UnassignedDialogueReference) {\n\t\treturn nil, errors.New(\n\t\t\t\"cannot initiate dialogue with preassigned dialogue_responder_reference\",\n\t\t)\n\t}\n\tincompleteDialogueLabel := DialogueLabel{\n\t\tdialogueReference,\n\t\tdialogueOpponentAddress,\n\t\tdialogueOpponentAddress,\n\t}\n\tnewDialogueReference := DialogueReference{\n\t\tdialogueReference.dialogueStarterReference,\n\t\tgenerateDialogueNonce(),\n\t}\n\tcompleteDialogueLabel := DialogueLabel{\n\t\tnewDialogueReference,\n\t\tdialogueOpponentAddress,\n\t\tdialogueOpponentAddress,\n\t}\n\tdialogue, err := dialogues.create(incompleteDialogueLabel, role, &completeDialogueLabel)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dialogue, nil\n}\n\nfunc (dialogues *Dialogues) create(\n\tincompleteDialogueLabel DialogueLabel,\n\trole Role,\n\tcompleteDialogueLabel *DialogueLabel,\n) (*Dialogue, error) {\n\tvar dialogueLabel DialogueLabel\n\tif dialogues.dialogueStorage.IsInIncomplete(incompleteDialogueLabel) {\n\t\treturn nil, errors.New(\"incomplete dialogue label already present\")\n\t}\n\tif completeDialogueLabel == nil {\n\t\tdialogueLabel = incompleteDialogueLabel\n\t} else {\n\t\tcopyLabel := *completeDialogueLabel\n\t\tdialogues.dialogueStorage.SetIncompleteDialogue(incompleteDialogueLabel, copyLabel)\n\t\tdialogueLabel = *completeDialogueLabel\n\t}\n\tif dialogues.dialogueStorage.IsDialoguePresent(dialogueLabel) {\n\t\treturn nil, errors.New(\"dialogue label already present in dialogues\")\n\t}\n\tdialogue := NewDialogue(\n\t\tdialogueLabel,\n\t\tdialogues.selfAddress,\n\t\trole,\n\t\tdialogues.initialPerformatives,\n\t\tdialogues.terminalPerformatives,\n\t\tdialogues.validReplies,\n\t)\n\tdialogues.dialogueStorage.AddDialogue(&dialogue)\n\treturn &dialogue, nil\n}\n\nfunc NewDialogues(\n\tselfAddress Address,\n\troleFromFirstMessage func(ProtocolMessageInterface, Address) Role,\n\tkeepTerminalStateDialogues bool,\n\tdialogueName string,\n\n\tinitialPerformatives []Performative,\n\tterminalPerformatives []Performative,\n\tvalidReplies map[Performative][]Performative) *Dialogues {\n\n\tendStatesSet := helpers.NewSet()\n\n\tfor _, endState := range terminalPerformatives {\n\t\tendStatesSet.Add(endState)\n\t}\n\n\tdialogues := Dialogues{\n\t\tselfAddress:                selfAddress,\n\t\tendStates:                  endStatesSet,\n\t\troleFromFirstMessage:       roleFromFirstMessage,\n\t\tkeepTerminalStateDialogues: keepTerminalStateDialogues,\n\t\tdialogueName:               dialogueName,\n\t\tinitialPerformatives:       initialPerformatives,\n\t\tterminalPerformatives:      terminalPerformatives,\n\t\tvalidReplies:               validReplies,\n\t}\n\tstorage := NewSimpleDialogueStorage(&dialogues)\n\tdialogues.dialogueStorage = storage\n\n\treturn &dialogues\n}\n"
  },
  {
    "path": "libs/go/aealite/protocols/message.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2019 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\n\npackage protocols\n\nimport (\n\t\"errors\"\n\t\"log\"\n\n\tproto \"google.golang.org/protobuf/proto\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n)\n\ntype MessageId int\ntype Address string\ntype Performative string\n\ntype ProtocolMessageInterface interface {\n\tSender() Address\n\tSetSender(Address) error\n\tTo() Address\n\tSetTo(Address) error\n\tMessageId() MessageId\n\tDialogueReference() DialogueReference\n\tTarget() MessageId\n\tPerformative() Performative\n\tBody() map[string]interface{}\n\tHasSender() bool\n\tHasTo() bool\n\tGetField(name string) interface{}\n\t//ValidPerformatives() []Performative TODO temporarily removed\n}\n\ntype DialogueMessageWrapper struct {\n\tto                Address\n\tsender            Address\n\tdialogueReference DialogueReference\n\tmessageId         MessageId\n\ttarget            MessageId\n\tperformative      Performative\n\tbody              map[string]interface{}\n\t//validPerformatives helpers.Set TODO understand how to set this\n}\n\n// InitFromProtobufAndPerformative initializes a message from a DialogueMessage protobuf message and a performative.\n//  It unpacks 'message id', 'target' and 'dialogue reference'; moreover,\n//  it decodes the content as a JSON object.\n//  Returns error if:\n//  - the JSON decoding fails\n//  - the body does not contain the 'performative'\n//  It performs side-effect on the method receiver.\nfunc (message *DialogueMessageWrapper) InitFromProtobufAndPerfofrmative(\n\tdialogueMessage *DialogueMessage,\n\tperformativeStr string,\n) error {\n\tmessage.messageId = MessageId(dialogueMessage.MessageId)\n\tmessage.target = MessageId(dialogueMessage.Target)\n\tmessage.dialogueReference = DialogueReference{\n\t\tdialogueMessage.DialogueStarterReference,\n\t\tdialogueMessage.DialogueResponderReference,\n\t}\n\tmessage.target = MessageId(dialogueMessage.Target)\n\tmessage.performative = Performative(performativeStr)\n\treturn nil\n}\n\nfunc (message *DialogueMessageWrapper) Sender() Address {\n\treturn message.sender\n}\n\nfunc (message *DialogueMessageWrapper) SetSender(newAddress Address) error {\n\tif message.sender != \"\" {\n\t\treturn errors.New(\"'sender' field already set\")\n\t}\n\tmessage.sender = newAddress\n\treturn nil\n}\n\nfunc (message *DialogueMessageWrapper) To() Address {\n\treturn message.to\n}\n\nfunc (message *DialogueMessageWrapper) SetTo(newAddress Address) error {\n\tif message.to != \"\" {\n\t\treturn errors.New(\"'to' field already set\")\n\t}\n\tmessage.to = newAddress\n\treturn nil\n}\n\nfunc (message *DialogueMessageWrapper) MessageId() MessageId {\n\treturn message.messageId\n}\n\nfunc (message *DialogueMessageWrapper) DialogueReference() DialogueReference {\n\treturn message.dialogueReference\n}\n\nfunc (message *DialogueMessageWrapper) Target() MessageId {\n\treturn message.target\n}\n\nfunc (message *DialogueMessageWrapper) Performative() Performative {\n\treturn message.performative\n}\n\nfunc (message *DialogueMessageWrapper) Body() map[string]interface{} {\n\treturn message.body\n}\n\nfunc (message *DialogueMessageWrapper) HasSender() bool {\n\treturn message.sender != \"\"\n}\n\nfunc (message *DialogueMessageWrapper) HasTo() bool {\n\treturn message.sender != \"\"\n}\n\n// GetField returns the value of the field associated with the name\n//  provided in input. If not present, then nil is returned. As we\n//  don't know the type, the callre has to do a type assertion\n//  in order to process the returned value.\nfunc (message *DialogueMessageWrapper) GetField(name string) interface{} {\n\treturn message.body[name]\n}\n\nfunc GetPerformative(message MessageInterface) (string, error) {\n\tperformative := \"\"\n\tm := message.ProtoReflect()\n\tm.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {\n\t\tperformative = fd.JSONName()\n\t\treturn false\n\t})\n\n\tif performative == \"\" {\n\t\treturn performative, errors.New(\"can not determine performative\")\n\t}\n\treturn performative, nil\n}\n\ntype MessageInterface interface {\n\tProtoReflect() protoreflect.Message\n}\n\nfunc GetDialogueMessageWrappedAndSetContentFromEnvelope(\n\tenvelope *Envelope,\n\tcontent_message MessageInterface,\n) (*DialogueMessageWrapper, error) {\n\tdata := envelope.GetMessage()\n\tmessage := &Message{}\n\terr := proto.Unmarshal(data, message)\n\tif err != nil {\n\t\tlog.Printf(\"can not unmarshal message: %s\", err)\n\t\treturn nil, err\n\t}\n\tdialogue_message := message.GetDialogueMessage()\n\n\terr = proto.Unmarshal(dialogue_message.GetContent(), content_message)\n\tif err != nil {\n\t\tlog.Printf(\"err on decode message content: %s\", err)\n\t\treturn nil, err\n\t}\n\n\tperformative, err := GetPerformative(content_message)\n\tif err != nil {\n\t\tlog.Printf(\"can not get performative: %s\", err)\n\t\treturn nil, err\n\t}\n\n\tdialogue_message_wrapper := DialogueMessageWrapper{}\n\terr = dialogue_message_wrapper.InitFromProtobufAndPerfofrmative(dialogue_message, performative)\n\tif err != nil {\n\t\tlog.Printf(\"can not init dialogue wrapper: %s\", err)\n\t\treturn nil, err\n\t}\n\terr = dialogue_message_wrapper.SetSender(Address(envelope.GetSender()))\n\tif err != nil {\n\t\tlog.Printf(\"can not set Sender: %s\", err)\n\t\treturn nil, err\n\t}\n\terr = dialogue_message_wrapper.SetTo(Address(envelope.GetTo()))\n\tif err != nil {\n\t\tlog.Printf(\"can not set To: %s\", err)\n\t\treturn nil, err\n\t}\n\n\treturn &dialogue_message_wrapper, nil\n}\n\nfunc MakeResponseEnvelope(\n\twrappedMsgDialogue ProtocolMessageInterface,\n\tprotocolID string,\n\tcontent []byte,\n) (*Envelope, error) {\n\tdialogueRef := wrappedMsgDialogue.DialogueReference()\n\n\tmessage := Message{\n\t\tMessage: &Message_DialogueMessage{\n\t\t\tDialogueMessage: &DialogueMessage{\n\t\t\t\tMessageId:                  int32(wrappedMsgDialogue.MessageId()),\n\t\t\t\tDialogueStarterReference:   dialogueRef.DialogueStarterReference(),\n\t\t\t\tDialogueResponderReference: dialogueRef.DialogueResponderReference(),\n\t\t\t\tTarget:                     int32(wrappedMsgDialogue.Target()),\n\t\t\t\tContent:                    content,\n\t\t\t},\n\t\t},\n\t}\n\n\tout, err := proto.Marshal(&message)\n\tif err != nil {\n\t\tlog.Print(\"marshal dialogue messge failed\")\n\t\treturn nil, err\n\t}\n\tenv := &Envelope{\n\t\tTo:         string(wrappedMsgDialogue.To()),\n\t\tSender:     string(wrappedMsgDialogue.Sender()),\n\t\tProtocolId: protocolID,\n\t\tMessage:    out,\n\t\tUri:        \"\",\n\t}\n\treturn env, nil\n}\n"
  },
  {
    "path": "libs/go/aealite/protocols/message_test.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2019 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\n\npackage protocols\n\nimport (\n\t\"testing\"\n\n\t\"gotest.tools/assert\"\n)\n\nconst (\n\tDialogueStarterReference   = \"DialogueStarterReference\"\n\tDialogueResponderReference = \"DialogueResponderReference\"\n)\n\nfunc TestMessage(t *testing.T) {\n\tmessage := DialogueMessage{}\n\tmessage.MessageId = int32(StartingMessageId)\n\tmessage.DialogueStarterReference = DialogueStarterReference\n\tmessage.DialogueResponderReference = DialogueResponderReference\n\tmessage.Target = int32(StartingTarget)\n\tmessage.Content = []byte(`{\"performative\": \"request\", \"data\": \"hello\"}`)\n\n\tresult := DialogueMessageWrapper{}\n\terr := result.InitFromProtobufAndPerfofrmative(&message, \"request\")\n\tif err != nil {\n\t\tt.Fatalf(\"Error: %s\", err.Error())\n\t}\n\n\tassert.Equal(t, result.messageId, StartingMessageId)\n\tassert.Equal(t, result.dialogueReference.dialogueStarterReference, DialogueStarterReference)\n\tassert.Equal(t, result.dialogueReference.dialogueResponderReference, DialogueResponderReference)\n\tassert.Equal(t, result.target, StartingTarget)\n\tassert.Equal(t, result.performative, Performative(\"request\"))\n}\n"
  },
  {
    "path": "libs/go/aealite/protocols/search.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.25.0\n// \tprotoc        v3.11.4\n// source: search.proto\n\npackage protocols\n\nimport (\n\tproto \"github.com/golang/protobuf/proto\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// This is a compile-time assertion that a sufficiently up-to-date version\n// of the legacy proto package is being used.\nconst _ = proto.ProtoPackageIsVersion4\n\ntype Query_Attribute_Type int32\n\nconst (\n\tQuery_Attribute_DOUBLE   Query_Attribute_Type = 0\n\tQuery_Attribute_INT      Query_Attribute_Type = 1\n\tQuery_Attribute_BOOL     Query_Attribute_Type = 2\n\tQuery_Attribute_STRING   Query_Attribute_Type = 3\n\tQuery_Attribute_LOCATION Query_Attribute_Type = 4\n)\n\n// Enum value maps for Query_Attribute_Type.\nvar (\n\tQuery_Attribute_Type_name = map[int32]string{\n\t\t0: \"DOUBLE\",\n\t\t1: \"INT\",\n\t\t2: \"BOOL\",\n\t\t3: \"STRING\",\n\t\t4: \"LOCATION\",\n\t}\n\tQuery_Attribute_Type_value = map[string]int32{\n\t\t\"DOUBLE\":   0,\n\t\t\"INT\":      1,\n\t\t\"BOOL\":     2,\n\t\t\"STRING\":   3,\n\t\t\"LOCATION\": 4,\n\t}\n)\n\nfunc (x Query_Attribute_Type) Enum() *Query_Attribute_Type {\n\tp := new(Query_Attribute_Type)\n\t*p = x\n\treturn p\n}\n\nfunc (x Query_Attribute_Type) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (Query_Attribute_Type) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_search_proto_enumTypes[0].Descriptor()\n}\n\nfunc (Query_Attribute_Type) Type() protoreflect.EnumType {\n\treturn &file_search_proto_enumTypes[0]\n}\n\nfunc (x Query_Attribute_Type) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use Query_Attribute_Type.Descriptor instead.\nfunc (Query_Attribute_Type) EnumDescriptor() ([]byte, []int) {\n\treturn file_search_proto_rawDescGZIP(), []int{0, 0, 0}\n}\n\ntype Query_Relation_Operator int32\n\nconst (\n\tQuery_Relation_EQ    Query_Relation_Operator = 0 // =\n\tQuery_Relation_LT    Query_Relation_Operator = 1 // <\n\tQuery_Relation_LTEQ  Query_Relation_Operator = 2 // <=\n\tQuery_Relation_GT    Query_Relation_Operator = 3 // >\n\tQuery_Relation_GTEQ  Query_Relation_Operator = 4 // >=\n\tQuery_Relation_NOTEQ Query_Relation_Operator = 5 // !=, <>\n)\n\n// Enum value maps for Query_Relation_Operator.\nvar (\n\tQuery_Relation_Operator_name = map[int32]string{\n\t\t0: \"EQ\",\n\t\t1: \"LT\",\n\t\t2: \"LTEQ\",\n\t\t3: \"GT\",\n\t\t4: \"GTEQ\",\n\t\t5: \"NOTEQ\",\n\t}\n\tQuery_Relation_Operator_value = map[string]int32{\n\t\t\"EQ\":    0,\n\t\t\"LT\":    1,\n\t\t\"LTEQ\":  2,\n\t\t\"GT\":    3,\n\t\t\"GTEQ\":  4,\n\t\t\"NOTEQ\": 5,\n\t}\n)\n\nfunc (x Query_Relation_Operator) Enum() *Query_Relation_Operator {\n\tp := new(Query_Relation_Operator)\n\t*p = x\n\treturn p\n}\n\nfunc (x Query_Relation_Operator) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (Query_Relation_Operator) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_search_proto_enumTypes[1].Descriptor()\n}\n\nfunc (Query_Relation_Operator) Type() protoreflect.EnumType {\n\treturn &file_search_proto_enumTypes[1]\n}\n\nfunc (x Query_Relation_Operator) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use Query_Relation_Operator.Descriptor instead.\nfunc (Query_Relation_Operator) EnumDescriptor() ([]byte, []int) {\n\treturn file_search_proto_rawDescGZIP(), []int{0, 12, 0}\n}\n\ntype Query_Set_Operator int32\n\nconst (\n\tQuery_Set_IN    Query_Set_Operator = 0\n\tQuery_Set_NOTIN Query_Set_Operator = 1\n)\n\n// Enum value maps for Query_Set_Operator.\nvar (\n\tQuery_Set_Operator_name = map[int32]string{\n\t\t0: \"IN\",\n\t\t1: \"NOTIN\",\n\t}\n\tQuery_Set_Operator_value = map[string]int32{\n\t\t\"IN\":    0,\n\t\t\"NOTIN\": 1,\n\t}\n)\n\nfunc (x Query_Set_Operator) Enum() *Query_Set_Operator {\n\tp := new(Query_Set_Operator)\n\t*p = x\n\treturn p\n}\n\nfunc (x Query_Set_Operator) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (Query_Set_Operator) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_search_proto_enumTypes[2].Descriptor()\n}\n\nfunc (Query_Set_Operator) Type() protoreflect.EnumType {\n\treturn &file_search_proto_enumTypes[2]\n}\n\nfunc (x Query_Set_Operator) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use Query_Set_Operator.Descriptor instead.\nfunc (Query_Set_Operator) EnumDescriptor() ([]byte, []int) {\n\treturn file_search_proto_rawDescGZIP(), []int{0, 13, 0}\n}\n\ntype Query struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n}\n\nfunc (x *Query) Reset() {\n\t*x = Query{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_search_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Query) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Query) ProtoMessage() {}\n\nfunc (x *Query) ProtoReflect() protoreflect.Message {\n\tmi := &file_search_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Query.ProtoReflect.Descriptor instead.\nfunc (*Query) Descriptor() ([]byte, []int) {\n\treturn file_search_proto_rawDescGZIP(), []int{0}\n}\n\ntype Query_Attribute struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tName        string               `protobuf:\"bytes,1,opt,name=name,proto3\" json:\"name,omitempty\"`\n\tType        Query_Attribute_Type `protobuf:\"varint,2,opt,name=type,proto3,enum=aea.search.v0_1_0.Query_Attribute_Type\" json:\"type,omitempty\"`\n\tRequired    bool                 `protobuf:\"varint,3,opt,name=required,proto3\" json:\"required,omitempty\"`\n\tDescription string               `protobuf:\"bytes,4,opt,name=description,proto3\" json:\"description,omitempty\"`\n}\n\nfunc (x *Query_Attribute) Reset() {\n\t*x = Query_Attribute{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_search_proto_msgTypes[1]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Query_Attribute) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Query_Attribute) ProtoMessage() {}\n\nfunc (x *Query_Attribute) ProtoReflect() protoreflect.Message {\n\tmi := &file_search_proto_msgTypes[1]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Query_Attribute.ProtoReflect.Descriptor instead.\nfunc (*Query_Attribute) Descriptor() ([]byte, []int) {\n\treturn file_search_proto_rawDescGZIP(), []int{0, 0}\n}\n\nfunc (x *Query_Attribute) GetName() string {\n\tif x != nil {\n\t\treturn x.Name\n\t}\n\treturn \"\"\n}\n\nfunc (x *Query_Attribute) GetType() Query_Attribute_Type {\n\tif x != nil {\n\t\treturn x.Type\n\t}\n\treturn Query_Attribute_DOUBLE\n}\n\nfunc (x *Query_Attribute) GetRequired() bool {\n\tif x != nil {\n\t\treturn x.Required\n\t}\n\treturn false\n}\n\nfunc (x *Query_Attribute) GetDescription() string {\n\tif x != nil {\n\t\treturn x.Description\n\t}\n\treturn \"\"\n}\n\ntype Query_DataModel struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tName        string             `protobuf:\"bytes,1,opt,name=name,proto3\" json:\"name,omitempty\"`\n\tAttributes  []*Query_Attribute `protobuf:\"bytes,2,rep,name=attributes,proto3\" json:\"attributes,omitempty\"`\n\tDescription string             `protobuf:\"bytes,3,opt,name=description,proto3\" json:\"description,omitempty\"`\n}\n\nfunc (x *Query_DataModel) Reset() {\n\t*x = Query_DataModel{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_search_proto_msgTypes[2]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Query_DataModel) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Query_DataModel) ProtoMessage() {}\n\nfunc (x *Query_DataModel) ProtoReflect() protoreflect.Message {\n\tmi := &file_search_proto_msgTypes[2]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Query_DataModel.ProtoReflect.Descriptor instead.\nfunc (*Query_DataModel) Descriptor() ([]byte, []int) {\n\treturn file_search_proto_rawDescGZIP(), []int{0, 1}\n}\n\nfunc (x *Query_DataModel) GetName() string {\n\tif x != nil {\n\t\treturn x.Name\n\t}\n\treturn \"\"\n}\n\nfunc (x *Query_DataModel) GetAttributes() []*Query_Attribute {\n\tif x != nil {\n\t\treturn x.Attributes\n\t}\n\treturn nil\n}\n\nfunc (x *Query_DataModel) GetDescription() string {\n\tif x != nil {\n\t\treturn x.Description\n\t}\n\treturn \"\"\n}\n\ntype Query_Location struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tLon float64 `protobuf:\"fixed64,1,opt,name=lon,proto3\" json:\"lon,omitempty\"`\n\tLat float64 `protobuf:\"fixed64,2,opt,name=lat,proto3\" json:\"lat,omitempty\"`\n}\n\nfunc (x *Query_Location) Reset() {\n\t*x = Query_Location{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_search_proto_msgTypes[3]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Query_Location) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Query_Location) ProtoMessage() {}\n\nfunc (x *Query_Location) ProtoReflect() protoreflect.Message {\n\tmi := &file_search_proto_msgTypes[3]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Query_Location.ProtoReflect.Descriptor instead.\nfunc (*Query_Location) Descriptor() ([]byte, []int) {\n\treturn file_search_proto_rawDescGZIP(), []int{0, 2}\n}\n\nfunc (x *Query_Location) GetLon() float64 {\n\tif x != nil {\n\t\treturn x.Lon\n\t}\n\treturn 0\n}\n\nfunc (x *Query_Location) GetLat() float64 {\n\tif x != nil {\n\t\treturn x.Lat\n\t}\n\treturn 0\n}\n\ntype Query_Value struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// Types that are assignable to Value:\n\t//\t*Query_Value_String_\n\t//\t*Query_Value_Double\n\t//\t*Query_Value_Boolean\n\t//\t*Query_Value_Integer\n\t//\t*Query_Value_Location\n\tValue isQuery_Value_Value `protobuf_oneof:\"value\"`\n}\n\nfunc (x *Query_Value) Reset() {\n\t*x = Query_Value{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_search_proto_msgTypes[4]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Query_Value) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Query_Value) ProtoMessage() {}\n\nfunc (x *Query_Value) ProtoReflect() protoreflect.Message {\n\tmi := &file_search_proto_msgTypes[4]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Query_Value.ProtoReflect.Descriptor instead.\nfunc (*Query_Value) Descriptor() ([]byte, []int) {\n\treturn file_search_proto_rawDescGZIP(), []int{0, 3}\n}\n\nfunc (m *Query_Value) GetValue() isQuery_Value_Value {\n\tif m != nil {\n\t\treturn m.Value\n\t}\n\treturn nil\n}\n\nfunc (x *Query_Value) GetString_() string {\n\tif x, ok := x.GetValue().(*Query_Value_String_); ok {\n\t\treturn x.String_\n\t}\n\treturn \"\"\n}\n\nfunc (x *Query_Value) GetDouble() float64 {\n\tif x, ok := x.GetValue().(*Query_Value_Double); ok {\n\t\treturn x.Double\n\t}\n\treturn 0\n}\n\nfunc (x *Query_Value) GetBoolean() bool {\n\tif x, ok := x.GetValue().(*Query_Value_Boolean); ok {\n\t\treturn x.Boolean\n\t}\n\treturn false\n}\n\nfunc (x *Query_Value) GetInteger() int64 {\n\tif x, ok := x.GetValue().(*Query_Value_Integer); ok {\n\t\treturn x.Integer\n\t}\n\treturn 0\n}\n\nfunc (x *Query_Value) GetLocation() *Query_Location {\n\tif x, ok := x.GetValue().(*Query_Value_Location); ok {\n\t\treturn x.Location\n\t}\n\treturn nil\n}\n\ntype isQuery_Value_Value interface {\n\tisQuery_Value_Value()\n}\n\ntype Query_Value_String_ struct {\n\tString_ string `protobuf:\"bytes,1,opt,name=string,proto3,oneof\"`\n}\n\ntype Query_Value_Double struct {\n\tDouble float64 `protobuf:\"fixed64,2,opt,name=double,proto3,oneof\"`\n}\n\ntype Query_Value_Boolean struct {\n\tBoolean bool `protobuf:\"varint,3,opt,name=boolean,proto3,oneof\"`\n}\n\ntype Query_Value_Integer struct {\n\tInteger int64 `protobuf:\"varint,4,opt,name=integer,proto3,oneof\"`\n}\n\ntype Query_Value_Location struct {\n\tLocation *Query_Location `protobuf:\"bytes,5,opt,name=location,proto3,oneof\"`\n}\n\nfunc (*Query_Value_String_) isQuery_Value_Value() {}\n\nfunc (*Query_Value_Double) isQuery_Value_Value() {}\n\nfunc (*Query_Value_Boolean) isQuery_Value_Value() {}\n\nfunc (*Query_Value_Integer) isQuery_Value_Value() {}\n\nfunc (*Query_Value_Location) isQuery_Value_Value() {}\n\ntype Query_KeyValue struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tKey   string       `protobuf:\"bytes,1,opt,name=key,proto3\" json:\"key,omitempty\"`\n\tValue *Query_Value `protobuf:\"bytes,2,opt,name=value,proto3\" json:\"value,omitempty\"`\n}\n\nfunc (x *Query_KeyValue) Reset() {\n\t*x = Query_KeyValue{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_search_proto_msgTypes[5]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Query_KeyValue) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Query_KeyValue) ProtoMessage() {}\n\nfunc (x *Query_KeyValue) ProtoReflect() protoreflect.Message {\n\tmi := &file_search_proto_msgTypes[5]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Query_KeyValue.ProtoReflect.Descriptor instead.\nfunc (*Query_KeyValue) Descriptor() ([]byte, []int) {\n\treturn file_search_proto_rawDescGZIP(), []int{0, 4}\n}\n\nfunc (x *Query_KeyValue) GetKey() string {\n\tif x != nil {\n\t\treturn x.Key\n\t}\n\treturn \"\"\n}\n\nfunc (x *Query_KeyValue) GetValue() *Query_Value {\n\tif x != nil {\n\t\treturn x.Value\n\t}\n\treturn nil\n}\n\ntype Query_Instance struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tModel  *Query_DataModel  `protobuf:\"bytes,1,opt,name=model,proto3\" json:\"model,omitempty\"`\n\tValues []*Query_KeyValue `protobuf:\"bytes,2,rep,name=values,proto3\" json:\"values,omitempty\"`\n}\n\nfunc (x *Query_Instance) Reset() {\n\t*x = Query_Instance{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_search_proto_msgTypes[6]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Query_Instance) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Query_Instance) ProtoMessage() {}\n\nfunc (x *Query_Instance) ProtoReflect() protoreflect.Message {\n\tmi := &file_search_proto_msgTypes[6]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Query_Instance.ProtoReflect.Descriptor instead.\nfunc (*Query_Instance) Descriptor() ([]byte, []int) {\n\treturn file_search_proto_rawDescGZIP(), []int{0, 5}\n}\n\nfunc (x *Query_Instance) GetModel() *Query_DataModel {\n\tif x != nil {\n\t\treturn x.Model\n\t}\n\treturn nil\n}\n\nfunc (x *Query_Instance) GetValues() []*Query_KeyValue {\n\tif x != nil {\n\t\treturn x.Values\n\t}\n\treturn nil\n}\n\ntype Query_StringPair struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tFirst  string `protobuf:\"bytes,1,opt,name=first,proto3\" json:\"first,omitempty\"`\n\tSecond string `protobuf:\"bytes,2,opt,name=second,proto3\" json:\"second,omitempty\"`\n}\n\nfunc (x *Query_StringPair) Reset() {\n\t*x = Query_StringPair{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_search_proto_msgTypes[7]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Query_StringPair) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Query_StringPair) ProtoMessage() {}\n\nfunc (x *Query_StringPair) ProtoReflect() protoreflect.Message {\n\tmi := &file_search_proto_msgTypes[7]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Query_StringPair.ProtoReflect.Descriptor instead.\nfunc (*Query_StringPair) Descriptor() ([]byte, []int) {\n\treturn file_search_proto_rawDescGZIP(), []int{0, 6}\n}\n\nfunc (x *Query_StringPair) GetFirst() string {\n\tif x != nil {\n\t\treturn x.First\n\t}\n\treturn \"\"\n}\n\nfunc (x *Query_StringPair) GetSecond() string {\n\tif x != nil {\n\t\treturn x.Second\n\t}\n\treturn \"\"\n}\n\ntype Query_IntPair struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tFirst  int64 `protobuf:\"varint,1,opt,name=first,proto3\" json:\"first,omitempty\"`\n\tSecond int64 `protobuf:\"varint,2,opt,name=second,proto3\" json:\"second,omitempty\"`\n}\n\nfunc (x *Query_IntPair) Reset() {\n\t*x = Query_IntPair{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_search_proto_msgTypes[8]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Query_IntPair) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Query_IntPair) ProtoMessage() {}\n\nfunc (x *Query_IntPair) ProtoReflect() protoreflect.Message {\n\tmi := &file_search_proto_msgTypes[8]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Query_IntPair.ProtoReflect.Descriptor instead.\nfunc (*Query_IntPair) Descriptor() ([]byte, []int) {\n\treturn file_search_proto_rawDescGZIP(), []int{0, 7}\n}\n\nfunc (x *Query_IntPair) GetFirst() int64 {\n\tif x != nil {\n\t\treturn x.First\n\t}\n\treturn 0\n}\n\nfunc (x *Query_IntPair) GetSecond() int64 {\n\tif x != nil {\n\t\treturn x.Second\n\t}\n\treturn 0\n}\n\ntype Query_DoublePair struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tFirst  float64 `protobuf:\"fixed64,1,opt,name=first,proto3\" json:\"first,omitempty\"`\n\tSecond float64 `protobuf:\"fixed64,2,opt,name=second,proto3\" json:\"second,omitempty\"`\n}\n\nfunc (x *Query_DoublePair) Reset() {\n\t*x = Query_DoublePair{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_search_proto_msgTypes[9]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Query_DoublePair) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Query_DoublePair) ProtoMessage() {}\n\nfunc (x *Query_DoublePair) ProtoReflect() protoreflect.Message {\n\tmi := &file_search_proto_msgTypes[9]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Query_DoublePair.ProtoReflect.Descriptor instead.\nfunc (*Query_DoublePair) Descriptor() ([]byte, []int) {\n\treturn file_search_proto_rawDescGZIP(), []int{0, 8}\n}\n\nfunc (x *Query_DoublePair) GetFirst() float64 {\n\tif x != nil {\n\t\treturn x.First\n\t}\n\treturn 0\n}\n\nfunc (x *Query_DoublePair) GetSecond() float64 {\n\tif x != nil {\n\t\treturn x.Second\n\t}\n\treturn 0\n}\n\ntype Query_LocationPair struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tFirst  *Query_Location `protobuf:\"bytes,1,opt,name=first,proto3\" json:\"first,omitempty\"`\n\tSecond *Query_Location `protobuf:\"bytes,2,opt,name=second,proto3\" json:\"second,omitempty\"`\n}\n\nfunc (x *Query_LocationPair) Reset() {\n\t*x = Query_LocationPair{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_search_proto_msgTypes[10]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Query_LocationPair) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Query_LocationPair) ProtoMessage() {}\n\nfunc (x *Query_LocationPair) ProtoReflect() protoreflect.Message {\n\tmi := &file_search_proto_msgTypes[10]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Query_LocationPair.ProtoReflect.Descriptor instead.\nfunc (*Query_LocationPair) Descriptor() ([]byte, []int) {\n\treturn file_search_proto_rawDescGZIP(), []int{0, 9}\n}\n\nfunc (x *Query_LocationPair) GetFirst() *Query_Location {\n\tif x != nil {\n\t\treturn x.First\n\t}\n\treturn nil\n}\n\nfunc (x *Query_LocationPair) GetSecond() *Query_Location {\n\tif x != nil {\n\t\treturn x.Second\n\t}\n\treturn nil\n}\n\ntype Query_Range struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// Types that are assignable to Pair:\n\t//\t*Query_Range_StringPair\n\t//\t*Query_Range_IntegerPair\n\t//\t*Query_Range_DoublePair\n\t//\t*Query_Range_LocationPair\n\tPair isQuery_Range_Pair `protobuf_oneof:\"pair\"`\n}\n\nfunc (x *Query_Range) Reset() {\n\t*x = Query_Range{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_search_proto_msgTypes[11]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Query_Range) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Query_Range) ProtoMessage() {}\n\nfunc (x *Query_Range) ProtoReflect() protoreflect.Message {\n\tmi := &file_search_proto_msgTypes[11]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Query_Range.ProtoReflect.Descriptor instead.\nfunc (*Query_Range) Descriptor() ([]byte, []int) {\n\treturn file_search_proto_rawDescGZIP(), []int{0, 10}\n}\n\nfunc (m *Query_Range) GetPair() isQuery_Range_Pair {\n\tif m != nil {\n\t\treturn m.Pair\n\t}\n\treturn nil\n}\n\nfunc (x *Query_Range) GetStringPair() *Query_StringPair {\n\tif x, ok := x.GetPair().(*Query_Range_StringPair); ok {\n\t\treturn x.StringPair\n\t}\n\treturn nil\n}\n\nfunc (x *Query_Range) GetIntegerPair() *Query_IntPair {\n\tif x, ok := x.GetPair().(*Query_Range_IntegerPair); ok {\n\t\treturn x.IntegerPair\n\t}\n\treturn nil\n}\n\nfunc (x *Query_Range) GetDoublePair() *Query_DoublePair {\n\tif x, ok := x.GetPair().(*Query_Range_DoublePair); ok {\n\t\treturn x.DoublePair\n\t}\n\treturn nil\n}\n\nfunc (x *Query_Range) GetLocationPair() *Query_LocationPair {\n\tif x, ok := x.GetPair().(*Query_Range_LocationPair); ok {\n\t\treturn x.LocationPair\n\t}\n\treturn nil\n}\n\ntype isQuery_Range_Pair interface {\n\tisQuery_Range_Pair()\n}\n\ntype Query_Range_StringPair struct {\n\tStringPair *Query_StringPair `protobuf:\"bytes,1,opt,name=string_pair,json=stringPair,proto3,oneof\"`\n}\n\ntype Query_Range_IntegerPair struct {\n\tIntegerPair *Query_IntPair `protobuf:\"bytes,2,opt,name=integer_pair,json=integerPair,proto3,oneof\"`\n}\n\ntype Query_Range_DoublePair struct {\n\tDoublePair *Query_DoublePair `protobuf:\"bytes,3,opt,name=double_pair,json=doublePair,proto3,oneof\"`\n}\n\ntype Query_Range_LocationPair struct {\n\tLocationPair *Query_LocationPair `protobuf:\"bytes,4,opt,name=location_pair,json=locationPair,proto3,oneof\"`\n}\n\nfunc (*Query_Range_StringPair) isQuery_Range_Pair() {}\n\nfunc (*Query_Range_IntegerPair) isQuery_Range_Pair() {}\n\nfunc (*Query_Range_DoublePair) isQuery_Range_Pair() {}\n\nfunc (*Query_Range_LocationPair) isQuery_Range_Pair() {}\n\ntype Query_Distance struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tCenter   *Query_Location `protobuf:\"bytes,1,opt,name=center,proto3\" json:\"center,omitempty\"`\n\tDistance float64         `protobuf:\"fixed64,2,opt,name=distance,proto3\" json:\"distance,omitempty\"`\n}\n\nfunc (x *Query_Distance) Reset() {\n\t*x = Query_Distance{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_search_proto_msgTypes[12]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Query_Distance) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Query_Distance) ProtoMessage() {}\n\nfunc (x *Query_Distance) ProtoReflect() protoreflect.Message {\n\tmi := &file_search_proto_msgTypes[12]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Query_Distance.ProtoReflect.Descriptor instead.\nfunc (*Query_Distance) Descriptor() ([]byte, []int) {\n\treturn file_search_proto_rawDescGZIP(), []int{0, 11}\n}\n\nfunc (x *Query_Distance) GetCenter() *Query_Location {\n\tif x != nil {\n\t\treturn x.Center\n\t}\n\treturn nil\n}\n\nfunc (x *Query_Distance) GetDistance() float64 {\n\tif x != nil {\n\t\treturn x.Distance\n\t}\n\treturn 0\n}\n\ntype Query_Relation struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tOperator Query_Relation_Operator `protobuf:\"varint,1,opt,name=operator,proto3,enum=aea.search.v0_1_0.Query_Relation_Operator\" json:\"operator,omitempty\"`\n\tValue    *Query_Value            `protobuf:\"bytes,2,opt,name=value,proto3\" json:\"value,omitempty\"`\n}\n\nfunc (x *Query_Relation) Reset() {\n\t*x = Query_Relation{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_search_proto_msgTypes[13]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Query_Relation) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Query_Relation) ProtoMessage() {}\n\nfunc (x *Query_Relation) ProtoReflect() protoreflect.Message {\n\tmi := &file_search_proto_msgTypes[13]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Query_Relation.ProtoReflect.Descriptor instead.\nfunc (*Query_Relation) Descriptor() ([]byte, []int) {\n\treturn file_search_proto_rawDescGZIP(), []int{0, 12}\n}\n\nfunc (x *Query_Relation) GetOperator() Query_Relation_Operator {\n\tif x != nil {\n\t\treturn x.Operator\n\t}\n\treturn Query_Relation_EQ\n}\n\nfunc (x *Query_Relation) GetValue() *Query_Value {\n\tif x != nil {\n\t\treturn x.Value\n\t}\n\treturn nil\n}\n\ntype Query_Set struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tOperator Query_Set_Operator `protobuf:\"varint,1,opt,name=operator,proto3,enum=aea.search.v0_1_0.Query_Set_Operator\" json:\"operator,omitempty\"`\n\tValues   *Query_Set_Values  `protobuf:\"bytes,2,opt,name=values,proto3\" json:\"values,omitempty\"`\n}\n\nfunc (x *Query_Set) Reset() {\n\t*x = Query_Set{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_search_proto_msgTypes[14]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Query_Set) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Query_Set) ProtoMessage() {}\n\nfunc (x *Query_Set) ProtoReflect() protoreflect.Message {\n\tmi := &file_search_proto_msgTypes[14]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Query_Set.ProtoReflect.Descriptor instead.\nfunc (*Query_Set) Descriptor() ([]byte, []int) {\n\treturn file_search_proto_rawDescGZIP(), []int{0, 13}\n}\n\nfunc (x *Query_Set) GetOperator() Query_Set_Operator {\n\tif x != nil {\n\t\treturn x.Operator\n\t}\n\treturn Query_Set_IN\n}\n\nfunc (x *Query_Set) GetValues() *Query_Set_Values {\n\tif x != nil {\n\t\treturn x.Values\n\t}\n\treturn nil\n}\n\ntype Query_ConstraintExpr struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// Types that are assignable to Expression:\n\t//\t*Query_ConstraintExpr_Or_\n\t//\t*Query_ConstraintExpr_And_\n\t//\t*Query_ConstraintExpr_Not_\n\t//\t*Query_ConstraintExpr_Constraint_\n\tExpression isQuery_ConstraintExpr_Expression `protobuf_oneof:\"expression\"`\n}\n\nfunc (x *Query_ConstraintExpr) Reset() {\n\t*x = Query_ConstraintExpr{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_search_proto_msgTypes[15]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Query_ConstraintExpr) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Query_ConstraintExpr) ProtoMessage() {}\n\nfunc (x *Query_ConstraintExpr) ProtoReflect() protoreflect.Message {\n\tmi := &file_search_proto_msgTypes[15]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Query_ConstraintExpr.ProtoReflect.Descriptor instead.\nfunc (*Query_ConstraintExpr) Descriptor() ([]byte, []int) {\n\treturn file_search_proto_rawDescGZIP(), []int{0, 14}\n}\n\nfunc (m *Query_ConstraintExpr) GetExpression() isQuery_ConstraintExpr_Expression {\n\tif m != nil {\n\t\treturn m.Expression\n\t}\n\treturn nil\n}\n\nfunc (x *Query_ConstraintExpr) GetOr_() *Query_ConstraintExpr_Or {\n\tif x, ok := x.GetExpression().(*Query_ConstraintExpr_Or_); ok {\n\t\treturn x.Or_\n\t}\n\treturn nil\n}\n\nfunc (x *Query_ConstraintExpr) GetAnd_() *Query_ConstraintExpr_And {\n\tif x, ok := x.GetExpression().(*Query_ConstraintExpr_And_); ok {\n\t\treturn x.And_\n\t}\n\treturn nil\n}\n\nfunc (x *Query_ConstraintExpr) GetNot_() *Query_ConstraintExpr_Not {\n\tif x, ok := x.GetExpression().(*Query_ConstraintExpr_Not_); ok {\n\t\treturn x.Not_\n\t}\n\treturn nil\n}\n\nfunc (x *Query_ConstraintExpr) GetConstraint() *Query_ConstraintExpr_Constraint {\n\tif x, ok := x.GetExpression().(*Query_ConstraintExpr_Constraint_); ok {\n\t\treturn x.Constraint\n\t}\n\treturn nil\n}\n\ntype isQuery_ConstraintExpr_Expression interface {\n\tisQuery_ConstraintExpr_Expression()\n}\n\ntype Query_ConstraintExpr_Or_ struct {\n\tOr_ *Query_ConstraintExpr_Or `protobuf:\"bytes,1,opt,name=or_,json=or,proto3,oneof\"`\n}\n\ntype Query_ConstraintExpr_And_ struct {\n\tAnd_ *Query_ConstraintExpr_And `protobuf:\"bytes,2,opt,name=and_,json=and,proto3,oneof\"`\n}\n\ntype Query_ConstraintExpr_Not_ struct {\n\tNot_ *Query_ConstraintExpr_Not `protobuf:\"bytes,3,opt,name=not_,json=not,proto3,oneof\"`\n}\n\ntype Query_ConstraintExpr_Constraint_ struct {\n\tConstraint *Query_ConstraintExpr_Constraint `protobuf:\"bytes,4,opt,name=constraint,proto3,oneof\"`\n}\n\nfunc (*Query_ConstraintExpr_Or_) isQuery_ConstraintExpr_Expression() {}\n\nfunc (*Query_ConstraintExpr_And_) isQuery_ConstraintExpr_Expression() {}\n\nfunc (*Query_ConstraintExpr_Not_) isQuery_ConstraintExpr_Expression() {}\n\nfunc (*Query_ConstraintExpr_Constraint_) isQuery_ConstraintExpr_Expression() {}\n\ntype Query_Model struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tConstraints []*Query_ConstraintExpr `protobuf:\"bytes,1,rep,name=constraints,proto3\" json:\"constraints,omitempty\"`\n\tModel       *Query_DataModel        `protobuf:\"bytes,2,opt,name=model,proto3\" json:\"model,omitempty\"`\n}\n\nfunc (x *Query_Model) Reset() {\n\t*x = Query_Model{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_search_proto_msgTypes[16]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Query_Model) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Query_Model) ProtoMessage() {}\n\nfunc (x *Query_Model) ProtoReflect() protoreflect.Message {\n\tmi := &file_search_proto_msgTypes[16]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Query_Model.ProtoReflect.Descriptor instead.\nfunc (*Query_Model) Descriptor() ([]byte, []int) {\n\treturn file_search_proto_rawDescGZIP(), []int{0, 15}\n}\n\nfunc (x *Query_Model) GetConstraints() []*Query_ConstraintExpr {\n\tif x != nil {\n\t\treturn x.Constraints\n\t}\n\treturn nil\n}\n\nfunc (x *Query_Model) GetModel() *Query_DataModel {\n\tif x != nil {\n\t\treturn x.Model\n\t}\n\treturn nil\n}\n\ntype Query_Set_Values struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// Types that are assignable to Values:\n\t//\t*Query_Set_Values_String_\n\t//\t*Query_Set_Values_Double\n\t//\t*Query_Set_Values_Boolean\n\t//\t*Query_Set_Values_Integer\n\t//\t*Query_Set_Values_Location\n\tValues isQuery_Set_Values_Values `protobuf_oneof:\"values\"`\n}\n\nfunc (x *Query_Set_Values) Reset() {\n\t*x = Query_Set_Values{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_search_proto_msgTypes[17]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Query_Set_Values) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Query_Set_Values) ProtoMessage() {}\n\nfunc (x *Query_Set_Values) ProtoReflect() protoreflect.Message {\n\tmi := &file_search_proto_msgTypes[17]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Query_Set_Values.ProtoReflect.Descriptor instead.\nfunc (*Query_Set_Values) Descriptor() ([]byte, []int) {\n\treturn file_search_proto_rawDescGZIP(), []int{0, 13, 0}\n}\n\nfunc (m *Query_Set_Values) GetValues() isQuery_Set_Values_Values {\n\tif m != nil {\n\t\treturn m.Values\n\t}\n\treturn nil\n}\n\nfunc (x *Query_Set_Values) GetString_() *Query_Set_Values_Strings {\n\tif x, ok := x.GetValues().(*Query_Set_Values_String_); ok {\n\t\treturn x.String_\n\t}\n\treturn nil\n}\n\nfunc (x *Query_Set_Values) GetDouble() *Query_Set_Values_Doubles {\n\tif x, ok := x.GetValues().(*Query_Set_Values_Double); ok {\n\t\treturn x.Double\n\t}\n\treturn nil\n}\n\nfunc (x *Query_Set_Values) GetBoolean() *Query_Set_Values_Bools {\n\tif x, ok := x.GetValues().(*Query_Set_Values_Boolean); ok {\n\t\treturn x.Boolean\n\t}\n\treturn nil\n}\n\nfunc (x *Query_Set_Values) GetInteger() *Query_Set_Values_Ints {\n\tif x, ok := x.GetValues().(*Query_Set_Values_Integer); ok {\n\t\treturn x.Integer\n\t}\n\treturn nil\n}\n\nfunc (x *Query_Set_Values) GetLocation() *Query_Set_Values_Locations {\n\tif x, ok := x.GetValues().(*Query_Set_Values_Location); ok {\n\t\treturn x.Location\n\t}\n\treturn nil\n}\n\ntype isQuery_Set_Values_Values interface {\n\tisQuery_Set_Values_Values()\n}\n\ntype Query_Set_Values_String_ struct {\n\tString_ *Query_Set_Values_Strings `protobuf:\"bytes,1,opt,name=string,proto3,oneof\"`\n}\n\ntype Query_Set_Values_Double struct {\n\tDouble *Query_Set_Values_Doubles `protobuf:\"bytes,2,opt,name=double,proto3,oneof\"`\n}\n\ntype Query_Set_Values_Boolean struct {\n\tBoolean *Query_Set_Values_Bools `protobuf:\"bytes,3,opt,name=boolean,proto3,oneof\"`\n}\n\ntype Query_Set_Values_Integer struct {\n\tInteger *Query_Set_Values_Ints `protobuf:\"bytes,4,opt,name=integer,proto3,oneof\"`\n}\n\ntype Query_Set_Values_Location struct {\n\tLocation *Query_Set_Values_Locations `protobuf:\"bytes,5,opt,name=location,proto3,oneof\"`\n}\n\nfunc (*Query_Set_Values_String_) isQuery_Set_Values_Values() {}\n\nfunc (*Query_Set_Values_Double) isQuery_Set_Values_Values() {}\n\nfunc (*Query_Set_Values_Boolean) isQuery_Set_Values_Values() {}\n\nfunc (*Query_Set_Values_Integer) isQuery_Set_Values_Values() {}\n\nfunc (*Query_Set_Values_Location) isQuery_Set_Values_Values() {}\n\ntype Query_Set_Values_Ints struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tValues []int64 `protobuf:\"varint,1,rep,packed,name=values,proto3\" json:\"values,omitempty\"`\n}\n\nfunc (x *Query_Set_Values_Ints) Reset() {\n\t*x = Query_Set_Values_Ints{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_search_proto_msgTypes[18]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Query_Set_Values_Ints) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Query_Set_Values_Ints) ProtoMessage() {}\n\nfunc (x *Query_Set_Values_Ints) ProtoReflect() protoreflect.Message {\n\tmi := &file_search_proto_msgTypes[18]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Query_Set_Values_Ints.ProtoReflect.Descriptor instead.\nfunc (*Query_Set_Values_Ints) Descriptor() ([]byte, []int) {\n\treturn file_search_proto_rawDescGZIP(), []int{0, 13, 0, 0}\n}\n\nfunc (x *Query_Set_Values_Ints) GetValues() []int64 {\n\tif x != nil {\n\t\treturn x.Values\n\t}\n\treturn nil\n}\n\ntype Query_Set_Values_Doubles struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tValues []float64 `protobuf:\"fixed64,1,rep,packed,name=values,proto3\" json:\"values,omitempty\"`\n}\n\nfunc (x *Query_Set_Values_Doubles) Reset() {\n\t*x = Query_Set_Values_Doubles{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_search_proto_msgTypes[19]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Query_Set_Values_Doubles) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Query_Set_Values_Doubles) ProtoMessage() {}\n\nfunc (x *Query_Set_Values_Doubles) ProtoReflect() protoreflect.Message {\n\tmi := &file_search_proto_msgTypes[19]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Query_Set_Values_Doubles.ProtoReflect.Descriptor instead.\nfunc (*Query_Set_Values_Doubles) Descriptor() ([]byte, []int) {\n\treturn file_search_proto_rawDescGZIP(), []int{0, 13, 0, 1}\n}\n\nfunc (x *Query_Set_Values_Doubles) GetValues() []float64 {\n\tif x != nil {\n\t\treturn x.Values\n\t}\n\treturn nil\n}\n\ntype Query_Set_Values_Strings struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tValues []string `protobuf:\"bytes,1,rep,name=values,proto3\" json:\"values,omitempty\"`\n}\n\nfunc (x *Query_Set_Values_Strings) Reset() {\n\t*x = Query_Set_Values_Strings{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_search_proto_msgTypes[20]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Query_Set_Values_Strings) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Query_Set_Values_Strings) ProtoMessage() {}\n\nfunc (x *Query_Set_Values_Strings) ProtoReflect() protoreflect.Message {\n\tmi := &file_search_proto_msgTypes[20]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Query_Set_Values_Strings.ProtoReflect.Descriptor instead.\nfunc (*Query_Set_Values_Strings) Descriptor() ([]byte, []int) {\n\treturn file_search_proto_rawDescGZIP(), []int{0, 13, 0, 2}\n}\n\nfunc (x *Query_Set_Values_Strings) GetValues() []string {\n\tif x != nil {\n\t\treturn x.Values\n\t}\n\treturn nil\n}\n\ntype Query_Set_Values_Bools struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tValues []bool `protobuf:\"varint,1,rep,packed,name=values,proto3\" json:\"values,omitempty\"`\n}\n\nfunc (x *Query_Set_Values_Bools) Reset() {\n\t*x = Query_Set_Values_Bools{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_search_proto_msgTypes[21]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Query_Set_Values_Bools) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Query_Set_Values_Bools) ProtoMessage() {}\n\nfunc (x *Query_Set_Values_Bools) ProtoReflect() protoreflect.Message {\n\tmi := &file_search_proto_msgTypes[21]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Query_Set_Values_Bools.ProtoReflect.Descriptor instead.\nfunc (*Query_Set_Values_Bools) Descriptor() ([]byte, []int) {\n\treturn file_search_proto_rawDescGZIP(), []int{0, 13, 0, 3}\n}\n\nfunc (x *Query_Set_Values_Bools) GetValues() []bool {\n\tif x != nil {\n\t\treturn x.Values\n\t}\n\treturn nil\n}\n\ntype Query_Set_Values_Locations struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tValues []*Query_Location `protobuf:\"bytes,1,rep,name=values,proto3\" json:\"values,omitempty\"`\n}\n\nfunc (x *Query_Set_Values_Locations) Reset() {\n\t*x = Query_Set_Values_Locations{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_search_proto_msgTypes[22]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Query_Set_Values_Locations) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Query_Set_Values_Locations) ProtoMessage() {}\n\nfunc (x *Query_Set_Values_Locations) ProtoReflect() protoreflect.Message {\n\tmi := &file_search_proto_msgTypes[22]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Query_Set_Values_Locations.ProtoReflect.Descriptor instead.\nfunc (*Query_Set_Values_Locations) Descriptor() ([]byte, []int) {\n\treturn file_search_proto_rawDescGZIP(), []int{0, 13, 0, 4}\n}\n\nfunc (x *Query_Set_Values_Locations) GetValues() []*Query_Location {\n\tif x != nil {\n\t\treturn x.Values\n\t}\n\treturn nil\n}\n\ntype Query_ConstraintExpr_Or struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tExpression []*Query_ConstraintExpr `protobuf:\"bytes,1,rep,name=expression,proto3\" json:\"expression,omitempty\"`\n}\n\nfunc (x *Query_ConstraintExpr_Or) Reset() {\n\t*x = Query_ConstraintExpr_Or{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_search_proto_msgTypes[23]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Query_ConstraintExpr_Or) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Query_ConstraintExpr_Or) ProtoMessage() {}\n\nfunc (x *Query_ConstraintExpr_Or) ProtoReflect() protoreflect.Message {\n\tmi := &file_search_proto_msgTypes[23]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Query_ConstraintExpr_Or.ProtoReflect.Descriptor instead.\nfunc (*Query_ConstraintExpr_Or) Descriptor() ([]byte, []int) {\n\treturn file_search_proto_rawDescGZIP(), []int{0, 14, 0}\n}\n\nfunc (x *Query_ConstraintExpr_Or) GetExpression() []*Query_ConstraintExpr {\n\tif x != nil {\n\t\treturn x.Expression\n\t}\n\treturn nil\n}\n\ntype Query_ConstraintExpr_And struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tExpression []*Query_ConstraintExpr `protobuf:\"bytes,1,rep,name=expression,proto3\" json:\"expression,omitempty\"`\n}\n\nfunc (x *Query_ConstraintExpr_And) Reset() {\n\t*x = Query_ConstraintExpr_And{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_search_proto_msgTypes[24]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Query_ConstraintExpr_And) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Query_ConstraintExpr_And) ProtoMessage() {}\n\nfunc (x *Query_ConstraintExpr_And) ProtoReflect() protoreflect.Message {\n\tmi := &file_search_proto_msgTypes[24]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Query_ConstraintExpr_And.ProtoReflect.Descriptor instead.\nfunc (*Query_ConstraintExpr_And) Descriptor() ([]byte, []int) {\n\treturn file_search_proto_rawDescGZIP(), []int{0, 14, 1}\n}\n\nfunc (x *Query_ConstraintExpr_And) GetExpression() []*Query_ConstraintExpr {\n\tif x != nil {\n\t\treturn x.Expression\n\t}\n\treturn nil\n}\n\ntype Query_ConstraintExpr_Not struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tExpression *Query_ConstraintExpr `protobuf:\"bytes,1,opt,name=expression,proto3\" json:\"expression,omitempty\"`\n}\n\nfunc (x *Query_ConstraintExpr_Not) Reset() {\n\t*x = Query_ConstraintExpr_Not{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_search_proto_msgTypes[25]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Query_ConstraintExpr_Not) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Query_ConstraintExpr_Not) ProtoMessage() {}\n\nfunc (x *Query_ConstraintExpr_Not) ProtoReflect() protoreflect.Message {\n\tmi := &file_search_proto_msgTypes[25]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Query_ConstraintExpr_Not.ProtoReflect.Descriptor instead.\nfunc (*Query_ConstraintExpr_Not) Descriptor() ([]byte, []int) {\n\treturn file_search_proto_rawDescGZIP(), []int{0, 14, 2}\n}\n\nfunc (x *Query_ConstraintExpr_Not) GetExpression() *Query_ConstraintExpr {\n\tif x != nil {\n\t\treturn x.Expression\n\t}\n\treturn nil\n}\n\ntype Query_ConstraintExpr_Constraint struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tAttributeName string `protobuf:\"bytes,1,opt,name=attribute_name,json=attributeName,proto3\" json:\"attribute_name,omitempty\"`\n\t// Types that are assignable to Constraint:\n\t//\t*Query_ConstraintExpr_Constraint_Set_\n\t//\t*Query_ConstraintExpr_Constraint_Range_\n\t//\t*Query_ConstraintExpr_Constraint_Relation\n\t//\t*Query_ConstraintExpr_Constraint_Distance\n\tConstraint isQuery_ConstraintExpr_Constraint_Constraint `protobuf_oneof:\"constraint\"`\n}\n\nfunc (x *Query_ConstraintExpr_Constraint) Reset() {\n\t*x = Query_ConstraintExpr_Constraint{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_search_proto_msgTypes[26]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Query_ConstraintExpr_Constraint) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Query_ConstraintExpr_Constraint) ProtoMessage() {}\n\nfunc (x *Query_ConstraintExpr_Constraint) ProtoReflect() protoreflect.Message {\n\tmi := &file_search_proto_msgTypes[26]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Query_ConstraintExpr_Constraint.ProtoReflect.Descriptor instead.\nfunc (*Query_ConstraintExpr_Constraint) Descriptor() ([]byte, []int) {\n\treturn file_search_proto_rawDescGZIP(), []int{0, 14, 3}\n}\n\nfunc (x *Query_ConstraintExpr_Constraint) GetAttributeName() string {\n\tif x != nil {\n\t\treturn x.AttributeName\n\t}\n\treturn \"\"\n}\n\nfunc (m *Query_ConstraintExpr_Constraint) GetConstraint() isQuery_ConstraintExpr_Constraint_Constraint {\n\tif m != nil {\n\t\treturn m.Constraint\n\t}\n\treturn nil\n}\n\nfunc (x *Query_ConstraintExpr_Constraint) GetSet_() *Query_Set {\n\tif x, ok := x.GetConstraint().(*Query_ConstraintExpr_Constraint_Set_); ok {\n\t\treturn x.Set_\n\t}\n\treturn nil\n}\n\nfunc (x *Query_ConstraintExpr_Constraint) GetRange_() *Query_Range {\n\tif x, ok := x.GetConstraint().(*Query_ConstraintExpr_Constraint_Range_); ok {\n\t\treturn x.Range_\n\t}\n\treturn nil\n}\n\nfunc (x *Query_ConstraintExpr_Constraint) GetRelation() *Query_Relation {\n\tif x, ok := x.GetConstraint().(*Query_ConstraintExpr_Constraint_Relation); ok {\n\t\treturn x.Relation\n\t}\n\treturn nil\n}\n\nfunc (x *Query_ConstraintExpr_Constraint) GetDistance() *Query_Distance {\n\tif x, ok := x.GetConstraint().(*Query_ConstraintExpr_Constraint_Distance); ok {\n\t\treturn x.Distance\n\t}\n\treturn nil\n}\n\ntype isQuery_ConstraintExpr_Constraint_Constraint interface {\n\tisQuery_ConstraintExpr_Constraint_Constraint()\n}\n\ntype Query_ConstraintExpr_Constraint_Set_ struct {\n\tSet_ *Query_Set `protobuf:\"bytes,2,opt,name=set_,json=set,proto3,oneof\"`\n}\n\ntype Query_ConstraintExpr_Constraint_Range_ struct {\n\tRange_ *Query_Range `protobuf:\"bytes,3,opt,name=range_,json=range,proto3,oneof\"`\n}\n\ntype Query_ConstraintExpr_Constraint_Relation struct {\n\tRelation *Query_Relation `protobuf:\"bytes,4,opt,name=relation,proto3,oneof\"`\n}\n\ntype Query_ConstraintExpr_Constraint_Distance struct {\n\tDistance *Query_Distance `protobuf:\"bytes,5,opt,name=distance,proto3,oneof\"`\n}\n\nfunc (*Query_ConstraintExpr_Constraint_Set_) isQuery_ConstraintExpr_Constraint_Constraint() {}\n\nfunc (*Query_ConstraintExpr_Constraint_Range_) isQuery_ConstraintExpr_Constraint_Constraint() {}\n\nfunc (*Query_ConstraintExpr_Constraint_Relation) isQuery_ConstraintExpr_Constraint_Constraint() {}\n\nfunc (*Query_ConstraintExpr_Constraint_Distance) isQuery_ConstraintExpr_Constraint_Constraint() {}\n\nvar File_search_proto protoreflect.FileDescriptor\n\nvar file_search_proto_rawDesc = []byte{\n\t0x0a, 0x0c, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x11,\n\t0x61, 0x65, 0x61, 0x2e, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2e, 0x76, 0x30, 0x5f, 0x31, 0x5f,\n\t0x30, 0x22, 0xad, 0x1b, 0x0a, 0x05, 0x51, 0x75, 0x65, 0x72, 0x79, 0x1a, 0xdb, 0x01, 0x0a, 0x09,\n\t0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d,\n\t0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x3b, 0x0a,\n\t0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x27, 0x2e, 0x61, 0x65,\n\t0x61, 0x2e, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2e, 0x76, 0x30, 0x5f, 0x31, 0x5f, 0x30, 0x2e,\n\t0x51, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x2e,\n\t0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65,\n\t0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x72, 0x65,\n\t0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69,\n\t0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73,\n\t0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x3f, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65,\n\t0x12, 0x0a, 0x0a, 0x06, 0x44, 0x4f, 0x55, 0x42, 0x4c, 0x45, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03,\n\t0x49, 0x4e, 0x54, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x42, 0x4f, 0x4f, 0x4c, 0x10, 0x02, 0x12,\n\t0x0a, 0x0a, 0x06, 0x53, 0x54, 0x52, 0x49, 0x4e, 0x47, 0x10, 0x03, 0x12, 0x0c, 0x0a, 0x08, 0x4c,\n\t0x4f, 0x43, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x04, 0x1a, 0x85, 0x01, 0x0a, 0x09, 0x44, 0x61,\n\t0x74, 0x61, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18,\n\t0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x42, 0x0a, 0x0a, 0x61,\n\t0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32,\n\t0x22, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2e, 0x76, 0x30, 0x5f,\n\t0x31, 0x5f, 0x30, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62,\n\t0x75, 0x74, 0x65, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12,\n\t0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03,\n\t0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f,\n\t0x6e, 0x1a, 0x2e, 0x0a, 0x08, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x10, 0x0a,\n\t0x03, 0x6c, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x01, 0x52, 0x03, 0x6c, 0x6f, 0x6e, 0x12,\n\t0x10, 0x0a, 0x03, 0x6c, 0x61, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x52, 0x03, 0x6c, 0x61,\n\t0x74, 0x1a, 0xbd, 0x01, 0x0a, 0x05, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x18, 0x0a, 0x06, 0x73,\n\t0x74, 0x72, 0x69, 0x6e, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x06, 0x73,\n\t0x74, 0x72, 0x69, 0x6e, 0x67, 0x12, 0x18, 0x0a, 0x06, 0x64, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x18,\n\t0x02, 0x20, 0x01, 0x28, 0x01, 0x48, 0x00, 0x52, 0x06, 0x64, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x12,\n\t0x1a, 0x0a, 0x07, 0x62, 0x6f, 0x6f, 0x6c, 0x65, 0x61, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08,\n\t0x48, 0x00, 0x52, 0x07, 0x62, 0x6f, 0x6f, 0x6c, 0x65, 0x61, 0x6e, 0x12, 0x1a, 0x0a, 0x07, 0x69,\n\t0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, 0x07,\n\t0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x12, 0x3f, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74,\n\t0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x61, 0x65, 0x61, 0x2e,\n\t0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2e, 0x76, 0x30, 0x5f, 0x31, 0x5f, 0x30, 0x2e, 0x51, 0x75,\n\t0x65, 0x72, 0x79, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x08,\n\t0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x07, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75,\n\t0x65, 0x1a, 0x52, 0x0a, 0x08, 0x4b, 0x65, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x10, 0x0a,\n\t0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12,\n\t0x34, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e,\n\t0x2e, 0x61, 0x65, 0x61, 0x2e, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2e, 0x76, 0x30, 0x5f, 0x31,\n\t0x5f, 0x30, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05,\n\t0x76, 0x61, 0x6c, 0x75, 0x65, 0x1a, 0x7f, 0x0a, 0x08, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63,\n\t0x65, 0x12, 0x38, 0x0a, 0x05, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b,\n\t0x32, 0x22, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2e, 0x76, 0x30,\n\t0x5f, 0x31, 0x5f, 0x30, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x4d,\n\t0x6f, 0x64, 0x65, 0x6c, 0x52, 0x05, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x12, 0x39, 0x0a, 0x06, 0x76,\n\t0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x61, 0x65,\n\t0x61, 0x2e, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2e, 0x76, 0x30, 0x5f, 0x31, 0x5f, 0x30, 0x2e,\n\t0x51, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x4b, 0x65, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x06,\n\t0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x1a, 0x3a, 0x0a, 0x0a, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67,\n\t0x50, 0x61, 0x69, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x69, 0x72, 0x73, 0x74, 0x18, 0x01, 0x20,\n\t0x01, 0x28, 0x09, 0x52, 0x05, 0x66, 0x69, 0x72, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x65,\n\t0x63, 0x6f, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x65, 0x63, 0x6f,\n\t0x6e, 0x64, 0x1a, 0x37, 0x0a, 0x07, 0x49, 0x6e, 0x74, 0x50, 0x61, 0x69, 0x72, 0x12, 0x14, 0x0a,\n\t0x05, 0x66, 0x69, 0x72, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x66, 0x69,\n\t0x72, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x18, 0x02, 0x20,\n\t0x01, 0x28, 0x03, 0x52, 0x06, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x1a, 0x3a, 0x0a, 0x0a, 0x44,\n\t0x6f, 0x75, 0x62, 0x6c, 0x65, 0x50, 0x61, 0x69, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x69, 0x72,\n\t0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x01, 0x52, 0x05, 0x66, 0x69, 0x72, 0x73, 0x74, 0x12,\n\t0x16, 0x0a, 0x06, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x52,\n\t0x06, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x1a, 0x82, 0x01, 0x0a, 0x0c, 0x4c, 0x6f, 0x63, 0x61,\n\t0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x69, 0x72, 0x12, 0x37, 0x0a, 0x05, 0x66, 0x69, 0x72, 0x73,\n\t0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x73, 0x65,\n\t0x61, 0x72, 0x63, 0x68, 0x2e, 0x76, 0x30, 0x5f, 0x31, 0x5f, 0x30, 0x2e, 0x51, 0x75, 0x65, 0x72,\n\t0x79, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x05, 0x66, 0x69, 0x72, 0x73,\n\t0x74, 0x12, 0x39, 0x0a, 0x06, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28,\n\t0x0b, 0x32, 0x21, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2e, 0x76,\n\t0x30, 0x5f, 0x31, 0x5f, 0x30, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x4c, 0x6f, 0x63, 0x61,\n\t0x74, 0x69, 0x6f, 0x6e, 0x52, 0x06, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x1a, 0xb4, 0x02, 0x0a,\n\t0x05, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x46, 0x0a, 0x0b, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67,\n\t0x5f, 0x70, 0x61, 0x69, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x61, 0x65,\n\t0x61, 0x2e, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2e, 0x76, 0x30, 0x5f, 0x31, 0x5f, 0x30, 0x2e,\n\t0x51, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x50, 0x61, 0x69, 0x72,\n\t0x48, 0x00, 0x52, 0x0a, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x50, 0x61, 0x69, 0x72, 0x12, 0x45,\n\t0x0a, 0x0c, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x5f, 0x70, 0x61, 0x69, 0x72, 0x18, 0x02,\n\t0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x73, 0x65, 0x61, 0x72, 0x63,\n\t0x68, 0x2e, 0x76, 0x30, 0x5f, 0x31, 0x5f, 0x30, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x49,\n\t0x6e, 0x74, 0x50, 0x61, 0x69, 0x72, 0x48, 0x00, 0x52, 0x0b, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65,\n\t0x72, 0x50, 0x61, 0x69, 0x72, 0x12, 0x46, 0x0a, 0x0b, 0x64, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x5f,\n\t0x70, 0x61, 0x69, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x61, 0x65, 0x61,\n\t0x2e, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2e, 0x76, 0x30, 0x5f, 0x31, 0x5f, 0x30, 0x2e, 0x51,\n\t0x75, 0x65, 0x72, 0x79, 0x2e, 0x44, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x50, 0x61, 0x69, 0x72, 0x48,\n\t0x00, 0x52, 0x0a, 0x64, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x50, 0x61, 0x69, 0x72, 0x12, 0x4c, 0x0a,\n\t0x0d, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x61, 0x69, 0x72, 0x18, 0x04,\n\t0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x73, 0x65, 0x61, 0x72, 0x63,\n\t0x68, 0x2e, 0x76, 0x30, 0x5f, 0x31, 0x5f, 0x30, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x4c,\n\t0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x69, 0x72, 0x48, 0x00, 0x52, 0x0c, 0x6c,\n\t0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x69, 0x72, 0x42, 0x06, 0x0a, 0x04, 0x70,\n\t0x61, 0x69, 0x72, 0x1a, 0x61, 0x0a, 0x08, 0x44, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x12,\n\t0x39, 0x0a, 0x06, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,\n\t0x21, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2e, 0x76, 0x30, 0x5f,\n\t0x31, 0x5f, 0x30, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69,\n\t0x6f, 0x6e, 0x52, 0x06, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x69,\n\t0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x52, 0x08, 0x64, 0x69,\n\t0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x1a, 0xcb, 0x01, 0x0a, 0x08, 0x52, 0x65, 0x6c, 0x61, 0x74,\n\t0x69, 0x6f, 0x6e, 0x12, 0x46, 0x0a, 0x08, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x18,\n\t0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2a, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x73, 0x65, 0x61, 0x72,\n\t0x63, 0x68, 0x2e, 0x76, 0x30, 0x5f, 0x31, 0x5f, 0x30, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x2e,\n\t0x52, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f,\n\t0x72, 0x52, 0x08, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x34, 0x0a, 0x05, 0x76,\n\t0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x61, 0x65, 0x61,\n\t0x2e, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2e, 0x76, 0x30, 0x5f, 0x31, 0x5f, 0x30, 0x2e, 0x51,\n\t0x75, 0x65, 0x72, 0x79, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75,\n\t0x65, 0x22, 0x41, 0x0a, 0x08, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x06, 0x0a,\n\t0x02, 0x45, 0x51, 0x10, 0x00, 0x12, 0x06, 0x0a, 0x02, 0x4c, 0x54, 0x10, 0x01, 0x12, 0x08, 0x0a,\n\t0x04, 0x4c, 0x54, 0x45, 0x51, 0x10, 0x02, 0x12, 0x06, 0x0a, 0x02, 0x47, 0x54, 0x10, 0x03, 0x12,\n\t0x08, 0x0a, 0x04, 0x47, 0x54, 0x45, 0x51, 0x10, 0x04, 0x12, 0x09, 0x0a, 0x05, 0x4e, 0x4f, 0x54,\n\t0x45, 0x51, 0x10, 0x05, 0x1a, 0xf0, 0x05, 0x0a, 0x03, 0x53, 0x65, 0x74, 0x12, 0x41, 0x0a, 0x08,\n\t0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x25,\n\t0x2e, 0x61, 0x65, 0x61, 0x2e, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2e, 0x76, 0x30, 0x5f, 0x31,\n\t0x5f, 0x30, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x53, 0x65, 0x74, 0x2e, 0x4f, 0x70, 0x65,\n\t0x72, 0x61, 0x74, 0x6f, 0x72, 0x52, 0x08, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x12,\n\t0x3b, 0x0a, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32,\n\t0x23, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2e, 0x76, 0x30, 0x5f,\n\t0x31, 0x5f, 0x30, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x53, 0x65, 0x74, 0x2e, 0x56, 0x61,\n\t0x6c, 0x75, 0x65, 0x73, 0x52, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x1a, 0xc9, 0x04, 0x0a,\n\t0x06, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x45, 0x0a, 0x06, 0x73, 0x74, 0x72, 0x69, 0x6e,\n\t0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x73, 0x65,\n\t0x61, 0x72, 0x63, 0x68, 0x2e, 0x76, 0x30, 0x5f, 0x31, 0x5f, 0x30, 0x2e, 0x51, 0x75, 0x65, 0x72,\n\t0x79, 0x2e, 0x53, 0x65, 0x74, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x2e, 0x53, 0x74, 0x72,\n\t0x69, 0x6e, 0x67, 0x73, 0x48, 0x00, 0x52, 0x06, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x12, 0x45,\n\t0x0a, 0x06, 0x64, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b,\n\t0x2e, 0x61, 0x65, 0x61, 0x2e, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2e, 0x76, 0x30, 0x5f, 0x31,\n\t0x5f, 0x30, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x53, 0x65, 0x74, 0x2e, 0x56, 0x61, 0x6c,\n\t0x75, 0x65, 0x73, 0x2e, 0x44, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x73, 0x48, 0x00, 0x52, 0x06, 0x64,\n\t0x6f, 0x75, 0x62, 0x6c, 0x65, 0x12, 0x45, 0x0a, 0x07, 0x62, 0x6f, 0x6f, 0x6c, 0x65, 0x61, 0x6e,\n\t0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x73, 0x65, 0x61,\n\t0x72, 0x63, 0x68, 0x2e, 0x76, 0x30, 0x5f, 0x31, 0x5f, 0x30, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79,\n\t0x2e, 0x53, 0x65, 0x74, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x2e, 0x42, 0x6f, 0x6f, 0x6c,\n\t0x73, 0x48, 0x00, 0x52, 0x07, 0x62, 0x6f, 0x6f, 0x6c, 0x65, 0x61, 0x6e, 0x12, 0x44, 0x0a, 0x07,\n\t0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e,\n\t0x61, 0x65, 0x61, 0x2e, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2e, 0x76, 0x30, 0x5f, 0x31, 0x5f,\n\t0x30, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x53, 0x65, 0x74, 0x2e, 0x56, 0x61, 0x6c, 0x75,\n\t0x65, 0x73, 0x2e, 0x49, 0x6e, 0x74, 0x73, 0x48, 0x00, 0x52, 0x07, 0x69, 0x6e, 0x74, 0x65, 0x67,\n\t0x65, 0x72, 0x12, 0x4b, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05,\n\t0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x73, 0x65, 0x61, 0x72, 0x63,\n\t0x68, 0x2e, 0x76, 0x30, 0x5f, 0x31, 0x5f, 0x30, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x53,\n\t0x65, 0x74, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69,\n\t0x6f, 0x6e, 0x73, 0x48, 0x00, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x1a,\n\t0x1e, 0x0a, 0x04, 0x49, 0x6e, 0x74, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65,\n\t0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x03, 0x52, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x1a,\n\t0x21, 0x0a, 0x07, 0x44, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x76, 0x61,\n\t0x6c, 0x75, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x01, 0x52, 0x06, 0x76, 0x61, 0x6c, 0x75,\n\t0x65, 0x73, 0x1a, 0x21, 0x0a, 0x07, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x16, 0x0a,\n\t0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x76,\n\t0x61, 0x6c, 0x75, 0x65, 0x73, 0x1a, 0x1f, 0x0a, 0x05, 0x42, 0x6f, 0x6f, 0x6c, 0x73, 0x12, 0x16,\n\t0x0a, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x08, 0x52, 0x06,\n\t0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x1a, 0x46, 0x0a, 0x09, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69,\n\t0x6f, 0x6e, 0x73, 0x12, 0x39, 0x0a, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x01, 0x20,\n\t0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68,\n\t0x2e, 0x76, 0x30, 0x5f, 0x31, 0x5f, 0x30, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x4c, 0x6f,\n\t0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x42, 0x08,\n\t0x0a, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x22, 0x1d, 0x0a, 0x08, 0x4f, 0x70, 0x65, 0x72,\n\t0x61, 0x74, 0x6f, 0x72, 0x12, 0x06, 0x0a, 0x02, 0x49, 0x4e, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05,\n\t0x4e, 0x4f, 0x54, 0x49, 0x4e, 0x10, 0x01, 0x1a, 0xd8, 0x06, 0x0a, 0x0e, 0x43, 0x6f, 0x6e, 0x73,\n\t0x74, 0x72, 0x61, 0x69, 0x6e, 0x74, 0x45, 0x78, 0x70, 0x72, 0x12, 0x3d, 0x0a, 0x03, 0x6f, 0x72,\n\t0x5f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x73, 0x65,\n\t0x61, 0x72, 0x63, 0x68, 0x2e, 0x76, 0x30, 0x5f, 0x31, 0x5f, 0x30, 0x2e, 0x51, 0x75, 0x65, 0x72,\n\t0x79, 0x2e, 0x43, 0x6f, 0x6e, 0x73, 0x74, 0x72, 0x61, 0x69, 0x6e, 0x74, 0x45, 0x78, 0x70, 0x72,\n\t0x2e, 0x4f, 0x72, 0x48, 0x00, 0x52, 0x02, 0x6f, 0x72, 0x12, 0x40, 0x0a, 0x04, 0x61, 0x6e, 0x64,\n\t0x5f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x73, 0x65,\n\t0x61, 0x72, 0x63, 0x68, 0x2e, 0x76, 0x30, 0x5f, 0x31, 0x5f, 0x30, 0x2e, 0x51, 0x75, 0x65, 0x72,\n\t0x79, 0x2e, 0x43, 0x6f, 0x6e, 0x73, 0x74, 0x72, 0x61, 0x69, 0x6e, 0x74, 0x45, 0x78, 0x70, 0x72,\n\t0x2e, 0x41, 0x6e, 0x64, 0x48, 0x00, 0x52, 0x03, 0x61, 0x6e, 0x64, 0x12, 0x40, 0x0a, 0x04, 0x6e,\n\t0x6f, 0x74, 0x5f, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x61, 0x65, 0x61, 0x2e,\n\t0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2e, 0x76, 0x30, 0x5f, 0x31, 0x5f, 0x30, 0x2e, 0x51, 0x75,\n\t0x65, 0x72, 0x79, 0x2e, 0x43, 0x6f, 0x6e, 0x73, 0x74, 0x72, 0x61, 0x69, 0x6e, 0x74, 0x45, 0x78,\n\t0x70, 0x72, 0x2e, 0x4e, 0x6f, 0x74, 0x48, 0x00, 0x52, 0x03, 0x6e, 0x6f, 0x74, 0x12, 0x54, 0x0a,\n\t0x0a, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x72, 0x61, 0x69, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28,\n\t0x0b, 0x32, 0x32, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2e, 0x76,\n\t0x30, 0x5f, 0x31, 0x5f, 0x30, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x43, 0x6f, 0x6e, 0x73,\n\t0x74, 0x72, 0x61, 0x69, 0x6e, 0x74, 0x45, 0x78, 0x70, 0x72, 0x2e, 0x43, 0x6f, 0x6e, 0x73, 0x74,\n\t0x72, 0x61, 0x69, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x72, 0x61,\n\t0x69, 0x6e, 0x74, 0x1a, 0x4d, 0x0a, 0x02, 0x4f, 0x72, 0x12, 0x47, 0x0a, 0x0a, 0x65, 0x78, 0x70,\n\t0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e,\n\t0x61, 0x65, 0x61, 0x2e, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2e, 0x76, 0x30, 0x5f, 0x31, 0x5f,\n\t0x30, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x43, 0x6f, 0x6e, 0x73, 0x74, 0x72, 0x61, 0x69,\n\t0x6e, 0x74, 0x45, 0x78, 0x70, 0x72, 0x52, 0x0a, 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69,\n\t0x6f, 0x6e, 0x1a, 0x4e, 0x0a, 0x03, 0x41, 0x6e, 0x64, 0x12, 0x47, 0x0a, 0x0a, 0x65, 0x78, 0x70,\n\t0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e,\n\t0x61, 0x65, 0x61, 0x2e, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2e, 0x76, 0x30, 0x5f, 0x31, 0x5f,\n\t0x30, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x43, 0x6f, 0x6e, 0x73, 0x74, 0x72, 0x61, 0x69,\n\t0x6e, 0x74, 0x45, 0x78, 0x70, 0x72, 0x52, 0x0a, 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69,\n\t0x6f, 0x6e, 0x1a, 0x4e, 0x0a, 0x03, 0x4e, 0x6f, 0x74, 0x12, 0x47, 0x0a, 0x0a, 0x65, 0x78, 0x70,\n\t0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e,\n\t0x61, 0x65, 0x61, 0x2e, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2e, 0x76, 0x30, 0x5f, 0x31, 0x5f,\n\t0x30, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x43, 0x6f, 0x6e, 0x73, 0x74, 0x72, 0x61, 0x69,\n\t0x6e, 0x74, 0x45, 0x78, 0x70, 0x72, 0x52, 0x0a, 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69,\n\t0x6f, 0x6e, 0x1a, 0xaf, 0x02, 0x0a, 0x0a, 0x43, 0x6f, 0x6e, 0x73, 0x74, 0x72, 0x61, 0x69, 0x6e,\n\t0x74, 0x12, 0x25, 0x0a, 0x0e, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x5f, 0x6e,\n\t0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x61, 0x74, 0x74, 0x72, 0x69,\n\t0x62, 0x75, 0x74, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x31, 0x0a, 0x04, 0x73, 0x65, 0x74, 0x5f,\n\t0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x73, 0x65, 0x61,\n\t0x72, 0x63, 0x68, 0x2e, 0x76, 0x30, 0x5f, 0x31, 0x5f, 0x30, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79,\n\t0x2e, 0x53, 0x65, 0x74, 0x48, 0x00, 0x52, 0x03, 0x73, 0x65, 0x74, 0x12, 0x37, 0x0a, 0x06, 0x72,\n\t0x61, 0x6e, 0x67, 0x65, 0x5f, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x61, 0x65,\n\t0x61, 0x2e, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2e, 0x76, 0x30, 0x5f, 0x31, 0x5f, 0x30, 0x2e,\n\t0x51, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x48, 0x00, 0x52, 0x05, 0x72,\n\t0x61, 0x6e, 0x67, 0x65, 0x12, 0x3f, 0x0a, 0x08, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e,\n\t0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x73, 0x65, 0x61,\n\t0x72, 0x63, 0x68, 0x2e, 0x76, 0x30, 0x5f, 0x31, 0x5f, 0x30, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79,\n\t0x2e, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x08, 0x72, 0x65, 0x6c,\n\t0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3f, 0x0a, 0x08, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63,\n\t0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x73, 0x65,\n\t0x61, 0x72, 0x63, 0x68, 0x2e, 0x76, 0x30, 0x5f, 0x31, 0x5f, 0x30, 0x2e, 0x51, 0x75, 0x65, 0x72,\n\t0x79, 0x2e, 0x44, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x48, 0x00, 0x52, 0x08, 0x64, 0x69,\n\t0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x42, 0x0c, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x72,\n\t0x61, 0x69, 0x6e, 0x74, 0x42, 0x0c, 0x0a, 0x0a, 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69,\n\t0x6f, 0x6e, 0x1a, 0x8c, 0x01, 0x0a, 0x05, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x12, 0x49, 0x0a, 0x0b,\n\t0x63, 0x6f, 0x6e, 0x73, 0x74, 0x72, 0x61, 0x69, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28,\n\t0x0b, 0x32, 0x27, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2e, 0x76,\n\t0x30, 0x5f, 0x31, 0x5f, 0x30, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x43, 0x6f, 0x6e, 0x73,\n\t0x74, 0x72, 0x61, 0x69, 0x6e, 0x74, 0x45, 0x78, 0x70, 0x72, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x73,\n\t0x74, 0x72, 0x61, 0x69, 0x6e, 0x74, 0x73, 0x12, 0x38, 0x0a, 0x05, 0x6d, 0x6f, 0x64, 0x65, 0x6c,\n\t0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x73, 0x65, 0x61,\n\t0x72, 0x63, 0x68, 0x2e, 0x76, 0x30, 0x5f, 0x31, 0x5f, 0x30, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79,\n\t0x2e, 0x44, 0x61, 0x74, 0x61, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x52, 0x05, 0x6d, 0x6f, 0x64, 0x65,\n\t0x6c, 0x42, 0x15, 0x48, 0x01, 0x5a, 0x11, 0x61, 0x65, 0x61, 0x6c, 0x69, 0x74, 0x65, 0x2f, 0x70,\n\t0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_search_proto_rawDescOnce sync.Once\n\tfile_search_proto_rawDescData = file_search_proto_rawDesc\n)\n\nfunc file_search_proto_rawDescGZIP() []byte {\n\tfile_search_proto_rawDescOnce.Do(func() {\n\t\tfile_search_proto_rawDescData = protoimpl.X.CompressGZIP(file_search_proto_rawDescData)\n\t})\n\treturn file_search_proto_rawDescData\n}\n\nvar file_search_proto_enumTypes = make([]protoimpl.EnumInfo, 3)\nvar file_search_proto_msgTypes = make([]protoimpl.MessageInfo, 27)\nvar file_search_proto_goTypes = []interface{}{\n\t(Query_Attribute_Type)(0),               // 0: aea.search.v0_1_0.Query.Attribute.Type\n\t(Query_Relation_Operator)(0),            // 1: aea.search.v0_1_0.Query.Relation.Operator\n\t(Query_Set_Operator)(0),                 // 2: aea.search.v0_1_0.Query.Set.Operator\n\t(*Query)(nil),                           // 3: aea.search.v0_1_0.Query\n\t(*Query_Attribute)(nil),                 // 4: aea.search.v0_1_0.Query.Attribute\n\t(*Query_DataModel)(nil),                 // 5: aea.search.v0_1_0.Query.DataModel\n\t(*Query_Location)(nil),                  // 6: aea.search.v0_1_0.Query.Location\n\t(*Query_Value)(nil),                     // 7: aea.search.v0_1_0.Query.Value\n\t(*Query_KeyValue)(nil),                  // 8: aea.search.v0_1_0.Query.KeyValue\n\t(*Query_Instance)(nil),                  // 9: aea.search.v0_1_0.Query.Instance\n\t(*Query_StringPair)(nil),                // 10: aea.search.v0_1_0.Query.StringPair\n\t(*Query_IntPair)(nil),                   // 11: aea.search.v0_1_0.Query.IntPair\n\t(*Query_DoublePair)(nil),                // 12: aea.search.v0_1_0.Query.DoublePair\n\t(*Query_LocationPair)(nil),              // 13: aea.search.v0_1_0.Query.LocationPair\n\t(*Query_Range)(nil),                     // 14: aea.search.v0_1_0.Query.Range\n\t(*Query_Distance)(nil),                  // 15: aea.search.v0_1_0.Query.Distance\n\t(*Query_Relation)(nil),                  // 16: aea.search.v0_1_0.Query.Relation\n\t(*Query_Set)(nil),                       // 17: aea.search.v0_1_0.Query.Set\n\t(*Query_ConstraintExpr)(nil),            // 18: aea.search.v0_1_0.Query.ConstraintExpr\n\t(*Query_Model)(nil),                     // 19: aea.search.v0_1_0.Query.Model\n\t(*Query_Set_Values)(nil),                // 20: aea.search.v0_1_0.Query.Set.Values\n\t(*Query_Set_Values_Ints)(nil),           // 21: aea.search.v0_1_0.Query.Set.Values.Ints\n\t(*Query_Set_Values_Doubles)(nil),        // 22: aea.search.v0_1_0.Query.Set.Values.Doubles\n\t(*Query_Set_Values_Strings)(nil),        // 23: aea.search.v0_1_0.Query.Set.Values.Strings\n\t(*Query_Set_Values_Bools)(nil),          // 24: aea.search.v0_1_0.Query.Set.Values.Bools\n\t(*Query_Set_Values_Locations)(nil),      // 25: aea.search.v0_1_0.Query.Set.Values.Locations\n\t(*Query_ConstraintExpr_Or)(nil),         // 26: aea.search.v0_1_0.Query.ConstraintExpr.Or\n\t(*Query_ConstraintExpr_And)(nil),        // 27: aea.search.v0_1_0.Query.ConstraintExpr.And\n\t(*Query_ConstraintExpr_Not)(nil),        // 28: aea.search.v0_1_0.Query.ConstraintExpr.Not\n\t(*Query_ConstraintExpr_Constraint)(nil), // 29: aea.search.v0_1_0.Query.ConstraintExpr.Constraint\n}\nvar file_search_proto_depIdxs = []int32{\n\t0,  // 0: aea.search.v0_1_0.Query.Attribute.type:type_name -> aea.search.v0_1_0.Query.Attribute.Type\n\t4,  // 1: aea.search.v0_1_0.Query.DataModel.attributes:type_name -> aea.search.v0_1_0.Query.Attribute\n\t6,  // 2: aea.search.v0_1_0.Query.Value.location:type_name -> aea.search.v0_1_0.Query.Location\n\t7,  // 3: aea.search.v0_1_0.Query.KeyValue.value:type_name -> aea.search.v0_1_0.Query.Value\n\t5,  // 4: aea.search.v0_1_0.Query.Instance.model:type_name -> aea.search.v0_1_0.Query.DataModel\n\t8,  // 5: aea.search.v0_1_0.Query.Instance.values:type_name -> aea.search.v0_1_0.Query.KeyValue\n\t6,  // 6: aea.search.v0_1_0.Query.LocationPair.first:type_name -> aea.search.v0_1_0.Query.Location\n\t6,  // 7: aea.search.v0_1_0.Query.LocationPair.second:type_name -> aea.search.v0_1_0.Query.Location\n\t10, // 8: aea.search.v0_1_0.Query.Range.string_pair:type_name -> aea.search.v0_1_0.Query.StringPair\n\t11, // 9: aea.search.v0_1_0.Query.Range.integer_pair:type_name -> aea.search.v0_1_0.Query.IntPair\n\t12, // 10: aea.search.v0_1_0.Query.Range.double_pair:type_name -> aea.search.v0_1_0.Query.DoublePair\n\t13, // 11: aea.search.v0_1_0.Query.Range.location_pair:type_name -> aea.search.v0_1_0.Query.LocationPair\n\t6,  // 12: aea.search.v0_1_0.Query.Distance.center:type_name -> aea.search.v0_1_0.Query.Location\n\t1,  // 13: aea.search.v0_1_0.Query.Relation.operator:type_name -> aea.search.v0_1_0.Query.Relation.Operator\n\t7,  // 14: aea.search.v0_1_0.Query.Relation.value:type_name -> aea.search.v0_1_0.Query.Value\n\t2,  // 15: aea.search.v0_1_0.Query.Set.operator:type_name -> aea.search.v0_1_0.Query.Set.Operator\n\t20, // 16: aea.search.v0_1_0.Query.Set.values:type_name -> aea.search.v0_1_0.Query.Set.Values\n\t26, // 17: aea.search.v0_1_0.Query.ConstraintExpr.or_:type_name -> aea.search.v0_1_0.Query.ConstraintExpr.Or\n\t27, // 18: aea.search.v0_1_0.Query.ConstraintExpr.and_:type_name -> aea.search.v0_1_0.Query.ConstraintExpr.And\n\t28, // 19: aea.search.v0_1_0.Query.ConstraintExpr.not_:type_name -> aea.search.v0_1_0.Query.ConstraintExpr.Not\n\t29, // 20: aea.search.v0_1_0.Query.ConstraintExpr.constraint:type_name -> aea.search.v0_1_0.Query.ConstraintExpr.Constraint\n\t18, // 21: aea.search.v0_1_0.Query.Model.constraints:type_name -> aea.search.v0_1_0.Query.ConstraintExpr\n\t5,  // 22: aea.search.v0_1_0.Query.Model.model:type_name -> aea.search.v0_1_0.Query.DataModel\n\t23, // 23: aea.search.v0_1_0.Query.Set.Values.string:type_name -> aea.search.v0_1_0.Query.Set.Values.Strings\n\t22, // 24: aea.search.v0_1_0.Query.Set.Values.double:type_name -> aea.search.v0_1_0.Query.Set.Values.Doubles\n\t24, // 25: aea.search.v0_1_0.Query.Set.Values.boolean:type_name -> aea.search.v0_1_0.Query.Set.Values.Bools\n\t21, // 26: aea.search.v0_1_0.Query.Set.Values.integer:type_name -> aea.search.v0_1_0.Query.Set.Values.Ints\n\t25, // 27: aea.search.v0_1_0.Query.Set.Values.location:type_name -> aea.search.v0_1_0.Query.Set.Values.Locations\n\t6,  // 28: aea.search.v0_1_0.Query.Set.Values.Locations.values:type_name -> aea.search.v0_1_0.Query.Location\n\t18, // 29: aea.search.v0_1_0.Query.ConstraintExpr.Or.expression:type_name -> aea.search.v0_1_0.Query.ConstraintExpr\n\t18, // 30: aea.search.v0_1_0.Query.ConstraintExpr.And.expression:type_name -> aea.search.v0_1_0.Query.ConstraintExpr\n\t18, // 31: aea.search.v0_1_0.Query.ConstraintExpr.Not.expression:type_name -> aea.search.v0_1_0.Query.ConstraintExpr\n\t17, // 32: aea.search.v0_1_0.Query.ConstraintExpr.Constraint.set_:type_name -> aea.search.v0_1_0.Query.Set\n\t14, // 33: aea.search.v0_1_0.Query.ConstraintExpr.Constraint.range_:type_name -> aea.search.v0_1_0.Query.Range\n\t16, // 34: aea.search.v0_1_0.Query.ConstraintExpr.Constraint.relation:type_name -> aea.search.v0_1_0.Query.Relation\n\t15, // 35: aea.search.v0_1_0.Query.ConstraintExpr.Constraint.distance:type_name -> aea.search.v0_1_0.Query.Distance\n\t36, // [36:36] is the sub-list for method output_type\n\t36, // [36:36] is the sub-list for method input_type\n\t36, // [36:36] is the sub-list for extension type_name\n\t36, // [36:36] is the sub-list for extension extendee\n\t0,  // [0:36] is the sub-list for field type_name\n}\n\nfunc init() { file_search_proto_init() }\nfunc file_search_proto_init() {\n\tif File_search_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_search_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Query); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_search_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Query_Attribute); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_search_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Query_DataModel); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_search_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Query_Location); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_search_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Query_Value); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_search_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Query_KeyValue); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_search_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Query_Instance); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_search_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Query_StringPair); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_search_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Query_IntPair); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_search_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Query_DoublePair); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_search_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Query_LocationPair); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_search_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Query_Range); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_search_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Query_Distance); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_search_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Query_Relation); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_search_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Query_Set); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_search_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Query_ConstraintExpr); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_search_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Query_Model); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_search_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Query_Set_Values); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_search_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Query_Set_Values_Ints); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_search_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Query_Set_Values_Doubles); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_search_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Query_Set_Values_Strings); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_search_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Query_Set_Values_Bools); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_search_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Query_Set_Values_Locations); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_search_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Query_ConstraintExpr_Or); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_search_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Query_ConstraintExpr_And); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_search_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Query_ConstraintExpr_Not); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_search_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Query_ConstraintExpr_Constraint); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\tfile_search_proto_msgTypes[4].OneofWrappers = []interface{}{\n\t\t(*Query_Value_String_)(nil),\n\t\t(*Query_Value_Double)(nil),\n\t\t(*Query_Value_Boolean)(nil),\n\t\t(*Query_Value_Integer)(nil),\n\t\t(*Query_Value_Location)(nil),\n\t}\n\tfile_search_proto_msgTypes[11].OneofWrappers = []interface{}{\n\t\t(*Query_Range_StringPair)(nil),\n\t\t(*Query_Range_IntegerPair)(nil),\n\t\t(*Query_Range_DoublePair)(nil),\n\t\t(*Query_Range_LocationPair)(nil),\n\t}\n\tfile_search_proto_msgTypes[15].OneofWrappers = []interface{}{\n\t\t(*Query_ConstraintExpr_Or_)(nil),\n\t\t(*Query_ConstraintExpr_And_)(nil),\n\t\t(*Query_ConstraintExpr_Not_)(nil),\n\t\t(*Query_ConstraintExpr_Constraint_)(nil),\n\t}\n\tfile_search_proto_msgTypes[17].OneofWrappers = []interface{}{\n\t\t(*Query_Set_Values_String_)(nil),\n\t\t(*Query_Set_Values_Double)(nil),\n\t\t(*Query_Set_Values_Boolean)(nil),\n\t\t(*Query_Set_Values_Integer)(nil),\n\t\t(*Query_Set_Values_Location)(nil),\n\t}\n\tfile_search_proto_msgTypes[26].OneofWrappers = []interface{}{\n\t\t(*Query_ConstraintExpr_Constraint_Set_)(nil),\n\t\t(*Query_ConstraintExpr_Constraint_Range_)(nil),\n\t\t(*Query_ConstraintExpr_Constraint_Relation)(nil),\n\t\t(*Query_ConstraintExpr_Constraint_Distance)(nil),\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_search_proto_rawDesc,\n\t\t\tNumEnums:      3,\n\t\t\tNumMessages:   27,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_search_proto_goTypes,\n\t\tDependencyIndexes: file_search_proto_depIdxs,\n\t\tEnumInfos:         file_search_proto_enumTypes,\n\t\tMessageInfos:      file_search_proto_msgTypes,\n\t}.Build()\n\tFile_search_proto = out.File\n\tfile_search_proto_rawDesc = nil\n\tfile_search_proto_goTypes = nil\n\tfile_search_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "libs/go/aealite/protocols/search.proto",
    "content": "syntax = \"proto3\";\n\npackage aea.search.v0_1_0;\n\noption go_package = \"aealite/protocols\";\n\nmessage Query {\n    message Attribute {\n        enum Type {\n            DOUBLE  = 0;\n            INT    = 1;\n            BOOL   = 2;\n            STRING = 3;\n            LOCATION = 4;\n        }\n        string name = 1;\n        Type type = 2;\n        bool required = 3;\n        string description = 4;\n    }\n    message DataModel {\n        string name = 1;\n        repeated Attribute attributes = 2;\n        string description = 3;\n    }\n    message Location {\n         double lon = 1;\n         double lat = 2;\n    }\n    message Value {\n        oneof value {\n            string string = 1;\n            double double = 2;\n            bool boolean = 3;\n            int64 integer = 4;\n            Location location = 5;\n        }\n    }\n    message KeyValue {\n        string key = 1;\n        Value value = 2;\n    }\n    message Instance {\n        DataModel model = 1;\n        repeated KeyValue values = 2;\n    }\n    message StringPair {\n        string first = 1;\n        string second = 2;\n    }\n    message IntPair {\n        int64 first = 1;\n        int64 second = 2;\n    }\n    message DoublePair {\n        double first = 1;\n        double second = 2;\n    }\n    message LocationPair {\n        Location first = 1;\n        Location second = 2;\n    }\n    message Range {\n        oneof pair {\n            StringPair string_pair = 1;\n            IntPair integer_pair = 2;\n            DoublePair double_pair = 3;\n            LocationPair location_pair = 4;\n        }\n    }\n    message Distance {\n        Location center = 1;\n        double distance = 2;\n    }\n    message Relation {\n        enum Operator {\n            EQ    = 0; // =\n            LT    = 1; // <\n            LTEQ  = 2; // <=\n            GT    = 3; // >\n            GTEQ  = 4; // >=\n            NOTEQ = 5; // !=, <>\n        }\n        Operator operator = 1;\n        Value value = 2;\n    }\n    message Set {\n        message Values {\n            message Ints {\n                repeated int64 values = 1;\n            }\n            message Doubles {\n                repeated double values = 1;\n            }\n            message Strings {\n                repeated string values = 1;\n            }\n            message Bools {\n                repeated bool values = 1;\n            }\n            message Locations {\n                repeated Location values = 1;\n            }\n            oneof values {\n                Strings string = 1;\n                Doubles double = 2;\n                Bools boolean = 3;\n                Ints integer = 4;\n                Locations location = 5;\n            }\n        }\n        enum Operator {\n            IN    = 0;\n            NOTIN = 1;\n        }\n        Operator operator = 1;\n        Values values = 2;\n    }\n    message ConstraintExpr {\n        message Or {\n            repeated ConstraintExpr expression = 1;\n        }\n        message And {\n            repeated ConstraintExpr expression = 1;\n        }\n        message Not {\n            ConstraintExpr expression = 1;\n        }\n        message Constraint {\n            string attribute_name = 1;\n            oneof constraint {\n                Set set_ = 2;\n                Range range_ = 3;\n                Relation relation = 4;\n                Distance distance = 5;\n            }\n        }\n        oneof expression {\n            Or or_ = 1;\n            And and_ = 2;\n            Not not_ = 3;\n            Constraint constraint = 4;\n        }\n    }\n    message Model {\n        repeated ConstraintExpr constraints = 1;\n        DataModel model = 2;\n    }\n}\n\n// option optimize_for = LITE_RUNTIME;\noption optimize_for = SPEED;"
  },
  {
    "path": "libs/go/aealite/protocols/storage.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2019 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\n\npackage protocols\n\nimport \"aealite/helpers\"\n\ntype DialogueMap map[DialogueLabel]*Dialogue\n\n// Dialogue storage\ntype DialogueStorageInterface interface {\n\tGetDialoguesInTerminalState() []*Dialogue\n\tGetDialoguesInActiveState() []*Dialogue\n\tIsTerminalDialoguesKept() bool\n\tDialogueTerminalStateCallback(*Dialogue)\n\tAddDialogue(dialogue *Dialogue)\n\tRemoveDialogue(dialogueLabel DialogueLabel)\n\tGetDialogue(label DialogueLabel) *Dialogue\n\tGetDialoguesWithCounterparty(counterparty Address) []*Dialogue\n\tIsInIncomplete(dialogueLabel DialogueLabel) bool\n\tSetIncompleteDialogue(\n\t\tincompleteDialogueLabel DialogueLabel,\n\t\tcompleteDialogueLabel DialogueLabel,\n\t)\n\tIsDialoguePresent(dialogueLabel DialogueLabel) bool\n\tGetLatestLabel(dialogueLabel DialogueLabel) DialogueLabel\n}\n\ntype SimpleDialogueStorage struct {\n\tdialogues                          *Dialogues\n\tdialoguesByDialogueLabel           map[DialogueLabel]*Dialogue\n\tdialoguesByAddress                 map[Address][]*Dialogue\n\tincompleteToCompleteDialogueLabels map[DialogueLabel]DialogueLabel\n\tterminalStateDialogueLabels        helpers.Set\n}\n\n/* methods */\n\nfunc (dialogueStorage *SimpleDialogueStorage) GetDialoguesInTerminalState() []*Dialogue {\n\tresult := make([]*Dialogue, 0)\n\tfor _, labelInterface := range dialogueStorage.terminalStateDialogueLabels.ToArray() {\n\t\tlabel := labelInterface.(DialogueLabel)\n\t\tdialogue, ok := dialogueStorage.dialoguesByDialogueLabel[label]\n\t\tif ok {\n\t\t\tresult = append(result, dialogue)\n\t\t}\n\t}\n\treturn result\n}\n\nfunc (dialogueStorage *SimpleDialogueStorage) GetDialoguesInActiveState() []*Dialogue {\n\tresult := make([]*Dialogue, 0)\n\tfor label, dialogue := range dialogueStorage.dialoguesByDialogueLabel {\n\t\tif !dialogueStorage.terminalStateDialogueLabels.Contains(label) {\n\t\t\tresult = append(result, dialogue)\n\t\t}\n\t}\n\treturn result\n}\nfunc (dialogueStorage *SimpleDialogueStorage) IsTerminalDialoguesKept() bool {\n\treturn dialogueStorage.dialogues.IsKeepDialoguesInTerminalStates()\n}\nfunc (dialogueStorage *SimpleDialogueStorage) DialogueTerminalStateCallback(dialogue *Dialogue) {\n\tif dialogueStorage.dialogues.IsKeepDialoguesInTerminalStates() {\n\t\tdialogueStorage.terminalStateDialogueLabels.Add(dialogue.dialogueLabel)\n\t} else {\n\t\tdialogueStorage.RemoveDialogue(dialogue.dialogueLabel)\n\t}\n}\nfunc (dialogueStorage *SimpleDialogueStorage) AddDialogue(dialogue *Dialogue) {\n\tdialogue.AddTerminalStateCallback(dialogueStorage.DialogueTerminalStateCallback)\n\tdialogueStorage.dialoguesByDialogueLabel[dialogue.dialogueLabel] = dialogue\n\n\topponent := dialogue.dialogueLabel.dialogueOpponentAddress\n\tdialogueList, ok := dialogueStorage.dialoguesByAddress[opponent]\n\tif !ok {\n\t\tdialogueList = make([]*Dialogue, 0)\n\t\tdialogueStorage.dialoguesByAddress[opponent] = dialogueList\n\t}\n\tdialogueStorage.dialoguesByAddress[opponent] = append(dialogueList, dialogue)\n}\nfunc (dialogueStorage *SimpleDialogueStorage) RemoveDialogue(dialogueLabel DialogueLabel) {\n\t_, ok := dialogueStorage.dialoguesByDialogueLabel[dialogueLabel]\n\tdelete(dialogueStorage.dialoguesByDialogueLabel, dialogueLabel)\n\tdelete(dialogueStorage.incompleteToCompleteDialogueLabels, dialogueLabel)\n\n\tdialogueStorage.terminalStateDialogueLabels.Remove(dialogueLabel)\n\tif ok {\n\t\tarray := dialogueStorage.dialoguesByAddress[dialogueLabel.dialogueOpponentAddress]\n\t\tdialogueStorage.dialoguesByAddress[dialogueLabel.dialogueOpponentAddress] = removeDialogueFromArray(\n\t\t\tarray,\n\t\t\tdialogueLabel,\n\t\t)\n\t}\n}\nfunc (dialogueStorage *SimpleDialogueStorage) GetDialogue(label DialogueLabel) *Dialogue {\n\treturn dialogueStorage.dialoguesByDialogueLabel[label]\n}\n\nfunc (dialogueStorage *SimpleDialogueStorage) GetDialoguesWithCounterparty(\n\tcounterparty Address,\n) []*Dialogue {\n\tresult := make([]*Dialogue, 0)\n\tresult = append(result, dialogueStorage.dialoguesByAddress[counterparty]...)\n\treturn result\n}\nfunc (dialogueStorage *SimpleDialogueStorage) IsInIncomplete(dialogueLabel DialogueLabel) bool {\n\t_, ok := dialogueStorage.incompleteToCompleteDialogueLabels[dialogueLabel]\n\treturn ok\n}\n\nfunc (dialogueStorage *SimpleDialogueStorage) SetIncompleteDialogue(\n\tincompleteDialogueLabel DialogueLabel,\n\tcompleteDialogueLabel DialogueLabel,\n) {\n\tdialogueStorage.incompleteToCompleteDialogueLabels[incompleteDialogueLabel] = completeDialogueLabel\n}\nfunc (dialogueStorage *SimpleDialogueStorage) IsDialoguePresent(dialogueLabel DialogueLabel) bool {\n\t_, ok := dialogueStorage.dialoguesByDialogueLabel[dialogueLabel]\n\treturn ok\n}\n\nfunc (dialogueStorage *SimpleDialogueStorage) GetLatestLabel(\n\tdialogueLabel DialogueLabel,\n) DialogueLabel {\n\tresult, ok := dialogueStorage.incompleteToCompleteDialogueLabels[dialogueLabel]\n\tif !ok {\n\t\tresult = dialogueLabel\n\t}\n\treturn result\n}\n\n/* helper functions */\n\nfunc removeDialogueFromArray(array []*Dialogue, dialogueLabel DialogueLabel) []*Dialogue {\n\tvar index int\n\tvar dialogue *Dialogue\n\tfor index, dialogue = range array {\n\t\tif dialogue.dialogueLabel == dialogueLabel {\n\t\t\tbreak\n\t\t}\n\t}\n\tnewArray := append(array[:index], array[index+1:]...)\n\treturn newArray\n}\n\n/* global functions */\n\nfunc NewSimpleDialogueStorage(dialogues *Dialogues) *SimpleDialogueStorage {\n\tresult := SimpleDialogueStorage{\n\t\tdialogues:                          dialogues,\n\t\tdialoguesByDialogueLabel:           make(map[DialogueLabel]*Dialogue),\n\t\tdialoguesByAddress:                 make(map[Address][]*Dialogue),\n\t\tincompleteToCompleteDialogueLabels: make(map[DialogueLabel]DialogueLabel),\n\t\tterminalStateDialogueLabels:        helpers.NewSet(),\n\t}\n\treturn &result\n}\n"
  },
  {
    "path": "libs/go/aealite/protocols/storage_test.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2019 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\n\npackage protocols\n\nimport (\n\t\"testing\"\n)\n\n// getTestDialogue builds a dialogue object for testing purposes.\nfunc getTestDialogue() Dialogue {\n\treturn NewDialogue(\n\t\tgetTestDialogueLabel(),\n\t\tsenderAddress,\n\t\tRole1,\n\t\t[]Performative{\"request\", \"response\"},\n\t\t[]Performative{\"response\"},\n\t\tmap[Performative][]Performative{\n\t\t\t\"request\": {\"response\"},\n\t\t})\n}\n\nfunc TestStorage(t *testing.T) {\n\tstorage := NewSimpleDialogueStorage(nil)\n\tdialogue := getTestDialogue()\n\n\t// Test storage methods without dialogues\n\tresult := storage.GetDialogue(dialogue.dialogueLabel)\n\tif result != nil {\n\t\tt.Fatal(\"dialogue not expected\")\n\t}\n\n\t// Test storage methods after a dialogue is added\n\tstorage.AddDialogue(&dialogue)\n\tresult = storage.GetDialogue(dialogue.dialogueLabel)\n\tif result == nil {\n\t\tt.Fatal(\"dialogue expected\")\n\t}\n\n}\n"
  },
  {
    "path": "libs/go/aealite/protocols/versions.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2019 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\n\npackage protocols\n\nconst (\n\tACNProtocolVersion  = \"0.1.0\"\n\tBaseProtocolVersion = \"0.1.0\"\n)\n"
  },
  {
    "path": "libs/go/aealite/test_env_file.env",
    "content": "export AEA_LEDGER_ID=\"fetchai\"\nexport AEA_ADDRESS=\"fetch1x9v67meyfq4pkgy2n2yf6797cfkul327kpclqr\"\nexport AEA_PUBLIC_KEY=\"02ac514ba70de60ed5c30f90e3acdfc958ecb416d9676706bf013228abfb2c2816\"\nexport AEA_PRIVATE_KEY=\"6d8d2b87d987641e2ca3f1991c1cccf08a118759e81fabdbf7e8484f27af015e\"\nexport AEA_P2P_POR_SERVICE_ID=\"acn\"\nexport AEA_P2P_POR_LEDGER_ID=\"fetchai\"\nexport AEA_P2P_POR_PEER_PUBKEY=\"0217a59bd805c310aca4febe0e99ce22ee3712ae085dc1e5630430b1e15a584bb7\"\nexport AEA_P2P_POR_SIGNATURE=\"avzHfL/fjMidvweJJKjtBUiqJ2+6aDUq8MoNRBi9nDI/lWleIX3ftRf6Sx5UWmxcS0SW03IVrf1iKTXA5zeA0g==\"\nexport AEA_P2P_DELEGATE_HOST=\"acn.fetch.ai\"\nexport AEA_P2P_DELEGATE_PORT=11000"
  },
  {
    "path": "libs/go/aealite/wallet/utils.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2019 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\n\npackage wallet\n\nimport (\n\t\"crypto/sha256\"\n\t\"encoding/base64\"\n\t\"encoding/hex\"\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/libp2p/go-libp2p-core/crypto\"\n\t\"golang.org/x/crypto/ripemd160\" // nolint:staticcheck\n\t\"golang.org/x/crypto/sha3\"\n\n\tbtcec \"github.com/btcsuite/btcd/btcec\"\n\t\"github.com/btcsuite/btcutil/bech32\"\n\t\"github.com/ethereum/go-ethereum/common/hexutil\"\n\tethCrypto \"github.com/ethereum/go-ethereum/crypto\"\n)\n\nvar (\n\taddressFromPublicKeyTable = map[string]func(string) (string, error){\n\t\t\"fetchai\":  FetchAIAddressFromPublicKey,\n\t\t\"cosmos\":   CosmosAddressFromPublicKey,\n\t\t\"ethereum\": EthereumAddressFromPublicKey,\n\t}\n\tpublicKeyFromPrivateKeyTable = map[string]func(string) (string, error){\n\t\t\"fetchai\": FetchAIPublicKeyFromPrivateKey,\n\t}\n\tverifyLedgerSignatureTable = map[string]func([]byte, string, string) (bool, error){\n\t\t\"fetchai\":  VerifyFetchAISignatureBTC,\n\t\t\"cosmos\":   VerifyFetchAISignatureBTC,\n\t\t\"ethereum\": VerifyEthereumSignatureETH,\n\t}\n)\n\n// AddressFromPublicKey get wallet address from public key associated with ledgerId\nfunc AddressFromPublicKey(ledgerId string, publicKey string) (string, error) {\n\tif addressFromPublicKey, found := addressFromPublicKeyTable[ledgerId]; found {\n\t\treturn addressFromPublicKey(publicKey)\n\t}\n\treturn \"\", errors.New(\"Unsupported ledger \" + ledgerId + \"for AddressFromPublicKey\")\n}\n\n// PublicKeyFromPrivateKey get public key from private key associated with ledgerId\nfunc PublicKeyFromPrivateKey(ledgerId string, privateKey string) (string, error) {\n\tif publicKeyFromPrivateKey, found := publicKeyFromPrivateKeyTable[ledgerId]; found {\n\t\treturn publicKeyFromPrivateKey(privateKey)\n\t}\n\treturn \"\", errors.New(\"Unsupported ledger \" + ledgerId + \"for PublicKeyFromPrivateKey\")\n}\n\n// PubKeyFromFetchAIPublicKey create libp2p public key from fetchai hex encoded secp256k1 key\nfunc PubKeyFromFetchAIPublicKey(publicKey string) (crypto.PubKey, error) {\n\thexBytes, _ := hex.DecodeString(publicKey)\n\treturn crypto.UnmarshalSecp256k1PublicKey(hexBytes)\n}\n\n// FetchAIPublicKeyFromPubKey return FetchAI's format serialized public key\nfunc FetchAIPublicKeyFromPubKey(publicKey crypto.PubKey) (string, error) {\n\traw, err := publicKey.Raw()\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\treturn hex.EncodeToString(raw), nil\n}\n\n// BTCPubKeyFromFetchAIPublicKey\nfunc BTCPubKeyFromFetchAIPublicKey(publicKey string) (*btcec.PublicKey, error) {\n\tpbkBytes, err := hex.DecodeString(publicKey)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tpbk, err := btcec.ParsePubKey(pbkBytes, btcec.S256())\n\treturn pbk, err\n}\n\n// BTCPubKeyFromEthereumPublicKey create libp2p public key from ethereum uncompressed\n//  hex encoded secp256k1 key\nfunc BTCPubKeyFromEthereumPublicKey(publicKey string) (*btcec.PublicKey, error) {\n\treturn BTCPubKeyFromUncompressedHex(publicKey[2:])\n}\n\n// ConvertStrEncodedSignatureToDER\n// References:\n//  - https://github.com/fetchai/agents-aea/blob/main/aea/crypto/cosmos.py#L258\n//  - https://github.com/btcsuite/btcd/blob/master/btcec/signature.go#L47\nfunc ConvertStrEncodedSignatureToDER(signature []byte) ([]byte, error) {\n\tif signature == nil {\n\t\treturn []byte{}, errors.New(\"No signature provided.\")\n\t}\n\trb := signature[:len(signature)/2]\n\tsb := signature[len(signature)/2:]\n\tlength := 6 + len(rb) + len(sb)\n\tsigDER := make([]byte, length)\n\tsigDER[0] = 0x30\n\tsigDER[1] = byte(length - 2)\n\tsigDER[2] = 0x02\n\tsigDER[3] = byte(len(rb))\n\toffset := copy(sigDER[4:], rb) + 4\n\tsigDER[offset] = 0x02\n\tsigDER[offset+1] = byte(len(sb))\n\tcopy(sigDER[offset+2:], sb)\n\treturn sigDER, nil\n}\n\n// ConvertDEREncodedSignatureToStr\n// References:\n//  - https://github.com/fetchai/agents-aea/blob/main/aea/crypto/cosmos.py#L258\n//  - https://github.com/btcsuite/btcd/blob/master/btcec/signature.go#L47\nfunc ConvertDEREncodedSignatureToStr(signature []byte) ([]byte, error) {\n\tsig, err := btcec.ParseDERSignature(signature, btcec.S256())\n\tif err != nil {\n\t\treturn []byte{}, err\n\t}\n\treturn append(sig.R.Bytes(), sig.S.Bytes()...), nil\n}\n\n// ParseFetchAISignature create btcec Signature from base64 formated, string (not DER) encoded RFC6979 signature\nfunc ParseFetchAISignature(signature string) (*btcec.Signature, error) {\n\t// First convert the signature into a DER one\n\tsigBytes, err := base64.StdEncoding.DecodeString(signature)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tsigDER, err := ConvertStrEncodedSignatureToDER(sigBytes)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t// Parse\n\tsigBTC, err := btcec.ParseSignature(sigDER, btcec.S256())\n\treturn sigBTC, err\n}\n\n// VerifyLedgerSignature verify signature of message using public key for supported ledgers\nfunc VerifyLedgerSignature(\n\tledgerId string,\n\tmessage []byte,\n\tsignature string,\n\tpubkey string,\n) (bool, error) {\n\tverifySignature, found := verifyLedgerSignatureTable[ledgerId]\n\tif found {\n\t\treturn verifySignature(message, signature, pubkey)\n\t}\n\treturn false, errors.New(\"Unsupported ledger\")\n}\n\n// VerifyFetchAISignatureBTC verify the RFC6967 string-encoded signature of message using FetchAI public key\nfunc VerifyFetchAISignatureBTC(message []byte, signature string, pubkey string) (bool, error) {\n\t// construct verifying key\n\tverifyKey, err := BTCPubKeyFromFetchAIPublicKey(pubkey)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\t// construct signature\n\tsignatureBTC, err := ParseFetchAISignature(signature)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\t// verify signature\n\tmessageHash := sha256.New()\n\t_, err = messageHash.Write([]byte(message))\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\treturn signatureBTC.Verify(messageHash.Sum(nil), verifyKey), nil\n}\n\n// VerifyFetchAISignatureLibp2p verify RFC6967 string-encoded signature of message using FetchAI public key\nfunc VerifyFetchAISignatureLibp2p(message []byte, signature string, pubkey string) (bool, error) {\n\t// construct verifying key\n\tverifyKey, err := PubKeyFromFetchAIPublicKey(pubkey)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\t// Convert signature into DER encoding\n\tsigBytes, err := base64.StdEncoding.DecodeString(signature)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\tsigDER, err := ConvertStrEncodedSignatureToDER(sigBytes)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\t// verify signature\n\treturn verifyKey.Verify(message, sigDER)\n}\n\nfunc SignFetchAI(message []byte, privKey string) (string, error) {\n\tsigningKey, _, err := KeyPairFromFetchAIKey(privKey)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tsignature, err := signingKey.Sign(message)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tstrSignature, err := ConvertDEREncodedSignatureToStr(signature)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tencodedSignature := base64.StdEncoding.EncodeToString(strSignature)\n\treturn encodedSignature, nil\n}\n\nfunc signHashETH(data []byte) []byte {\n\tmsg := fmt.Sprintf(\"\\x19Ethereum Signed Message:\\n%d%s\", len(data), data)\n\treturn ethCrypto.Keccak256([]byte(msg))\n}\n\n// RecoverAddressFromEthereumSignature verify the signature and returns the address of the signer\n// references:\n//  - https://github.com/ethereum/go-ethereum/blob/55599ee95d4151a2502465e0afc7c47bd1acba77/internal/ethapi/api.go#L452-L459\n//  - https://github.com/ethereum/go-ethereum/blob/55599ee95d4151a2502465e0afc7c47bd1acba77/internal/ethapi/api.go#L404\nfunc RecoverAddressFromEthereumSignature(message []byte, signature string) (string, error) {\n\t// prepare signature\n\tsigBytes, err := hexutil.Decode(signature)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tif sigBytes[64] != 27 && sigBytes[64] != 28 {\n\t\treturn \"\", errors.New(\"invalid Ethereum signature (V is not 27 or 28)\")\n\t}\n\tsigBytes[64] -= 27 // Transform yellow paper V from 27/28 to 0/1\n\n\t// recover verify key\n\trecoveredPubKey, err := ethCrypto.SigToPub(signHashETH(message), sigBytes)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn ethCrypto.PubkeyToAddress(*recoveredPubKey).Hex(), nil\n}\n\n// VerifyEthereumSignatureETH verify ethereum signature using ethereum public key\nfunc VerifyEthereumSignatureETH(message []byte, signature string, pubkey string) (bool, error) {\n\t// get expected signer address\n\texpectedAddress, err := EthereumAddressFromPublicKey(pubkey)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\t// recover signer address\n\trecoveredAddress, err := RecoverAddressFromEthereumSignature(message, signature)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\tif recoveredAddress != expectedAddress {\n\t\treturn false, errors.New(\"Recovered and expected addresses don't match\")\n\t}\n\n\treturn true, nil\n}\n\n// KeyPairFromFetchAIKey  key pair from hex encoded secp256k1 private key\nfunc KeyPairFromFetchAIKey(key string) (crypto.PrivKey, crypto.PubKey, error) {\n\tpkBytes, err := hex.DecodeString(key)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tbtcPrivateKey, _ := btcec.PrivKeyFromBytes(btcec.S256(), pkBytes)\n\tprvKey, pubKey, err := crypto.KeyPairFromStdKey(btcPrivateKey)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\treturn prvKey, pubKey, nil\n}\n\n// FetchAIAddressFromPublicKey get wallet address from hex encoded secp256k1 public key\nfunc FetchAIAddressFromPublicKey(publicKey string) (string, error) {\n\treturn cosmosAddressFromPublicKeyWithPrefix(\"fetch\", publicKey)\n}\n\n// CosmosAddressFromPublicKey get wallet address from hex encoded secp256k1 public key\nfunc CosmosAddressFromPublicKey(publicKey string) (string, error) {\n\treturn cosmosAddressFromPublicKeyWithPrefix(\"cosmos\", publicKey)\n}\n\n// cosmosAddressFromPublicKeyWithPrefix get wallet address from hex encoded secp256k1 public key\n// format from: https://github.com/fetchai/agents-aea/blob/main/aea/crypto/cosmos.py#L120\nfunc cosmosAddressFromPublicKeyWithPrefix(prefix string, publicKey string) (string, error) {\n\tvar addr string\n\tvar err error\n\thexBytes, err := hex.DecodeString(publicKey)\n\tif err != nil {\n\t\treturn addr, err\n\t}\n\thash := sha256.New()\n\t_, err = hash.Write(hexBytes)\n\tif err != nil {\n\t\treturn addr, err\n\t}\n\tsha256Hash := hash.Sum(nil)\n\thash = ripemd160.New()\n\t_, err = hash.Write(sha256Hash)\n\tif err != nil {\n\t\treturn addr, err\n\t}\n\tripemd160Hash := hash.Sum(nil)\n\tfiveBitsChar, err := bech32.ConvertBits(ripemd160Hash, 8, 5, true)\n\tif err != nil {\n\t\treturn addr, err\n\t}\n\taddr, err = bech32.Encode(prefix, fiveBitsChar)\n\treturn addr, err\n}\n\n// EthereumAddressFromPublicKey get wallet address from hex encoded secp256k1 public key\n// references:\n//  - https://github.com/fetchai/agents-aea/blob/main/aea/crypto/ethereum.py#L330\n//  - https://github.com/ethereum/go-ethereum/blob/master/crypto/crypto.go#L263\nfunc EthereumAddressFromPublicKey(publicKey string) (string, error) {\n\tvar addr string\n\tvar err error\n\thexBytes, err := hex.DecodeString(publicKey[2:])\n\tif err != nil {\n\t\treturn addr, err\n\t}\n\thash := sha3.NewLegacyKeccak256()\n\t_, err = hash.Write(hexBytes)\n\tif err != nil {\n\t\treturn addr, err\n\t}\n\tsha3KeccakHash := hash.Sum(nil)\n\treturn encodeChecksumEIP55(sha3KeccakHash[12:]), nil\n}\n\n// encodeChecksumEIP55 EIP55-compliant hex string representation of the address\n// source: https://github.com/ethereum/go-ethereum/blob/master/common/types.go#L210\n// reference: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-55.md\nfunc encodeChecksumEIP55(address []byte) string {\n\tunchecksummed := hex.EncodeToString(address[:])\n\tsha := sha3.NewLegacyKeccak256()\n\t_, err := sha.Write([]byte(unchecksummed))\n\tif err != nil {\n\t\tfmt.Println(\"IGNORED:\", err)\n\t}\n\thash := sha.Sum(nil)\n\n\tresult := []byte(unchecksummed)\n\tfor i := 0; i < len(result); i++ {\n\t\thashByte := hash[i/2]\n\t\tif i%2 == 0 {\n\t\t\thashByte = hashByte >> 4\n\t\t} else {\n\t\t\thashByte &= 0xf\n\t\t}\n\t\tif result[i] > '9' && hashByte > 7 {\n\t\t\tresult[i] -= 32\n\t\t}\n\t}\n\treturn \"0x\" + string(result)\n}\n\n// BTCPubKeyFromUncompressedHex get public key from secp256k1 hex encoded  uncompressed representation\nfunc BTCPubKeyFromUncompressedHex(publicKey string) (*btcec.PublicKey, error) {\n\tb, err := hex.DecodeString(publicKey)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tpubBytes := make([]byte, 0, btcec.PubKeyBytesLenUncompressed)\n\tpubBytes = append(pubBytes, 0x4) // btcec.pubkeyUncompressed\n\tpubBytes = append(pubBytes, b...)\n\n\treturn btcec.ParsePubKey(pubBytes, btcec.S256())\n}\n\nfunc FetchAIPublicKeyFromPrivateKey(privateKey string) (string, error) {\n\tpkBytes, err := hex.DecodeString(privateKey)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\t_, btcPublicKey := btcec.PrivKeyFromBytes(btcec.S256(), pkBytes)\n\n\treturn hex.EncodeToString(btcPublicKey.SerializeCompressed()), nil\n}\n"
  },
  {
    "path": "libs/go/aealite/wallet/wallet.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2019 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\n\npackage wallet\n\nimport (\n\t\"log\"\n\t\"os\"\n\n\t\"github.com/joho/godotenv\"\n\t\"github.com/rs/zerolog\"\n)\n\nvar logger zerolog.Logger = zerolog.New(zerolog.ConsoleWriter{\n\tOut:        os.Stdout,\n\tNoColor:    false,\n\tTimeFormat: \"15:04:05.000\",\n}).\n\tWith().Timestamp().\n\tStr(\"package\", \"Wallet\").\n\tLogger()\n\ntype Wallet struct {\n\tLedgerId   string\n\tAddress    string\n\tPublicKey  string\n\tPrivateKey string\n}\n\nfunc (wallet *Wallet) InitFromEnv(envFile string) error {\n\tlogger.Debug().Msgf(\"env_file: %s\", envFile)\n\terr := godotenv.Overload(envFile)\n\tif err != nil {\n\t\tlogger.Error().Str(\"err\", err.Error()).\n\t\t\tMsg(\"Error loading env file\")\n\t\treturn err\n\t}\n\twallet.LedgerId = os.Getenv(\"AEA_LEDGER_ID\")\n\tif wallet.LedgerId == \"\" {\n\t\tlog.Fatal(\"No AEA_LEDGER_ID provided in env file.\")\n\t}\n\twallet.Address = os.Getenv(\"AEA_ADDRESS\")\n\twallet.PublicKey = os.Getenv(\"AEA_PUBLIC_KEY\")\n\twallet.PrivateKey = os.Getenv(\"AEA_PRIVATE_KEY\")\n\tif wallet.PrivateKey == \"\" {\n\t\tlog.Fatal(\"No AEA_PRIVATE_KEY provided in env file.\")\n\t}\n\tpublic_key, err := PublicKeyFromPrivateKey(wallet.LedgerId, wallet.PrivateKey)\n\tif err != nil {\n\t\tlog.Fatal(\"Could not derive public key.\")\n\t}\n\tif (wallet.PublicKey != \"\") && (public_key != wallet.PublicKey) {\n\t\tlog.Fatal(\"Derived and provided public_key don't match.\")\n\t}\n\twallet.PublicKey = public_key\n\taddress, err := AddressFromPublicKey(wallet.LedgerId, wallet.PublicKey)\n\tif err != nil {\n\t\tlog.Fatal(\"Could not derive address.\")\n\t}\n\tif (wallet.Address != \"\") && (address != wallet.Address) {\n\t\tlog.Fatal(\"Derived and provided address don't match.\")\n\t}\n\twallet.Address = address\n\treturn nil\n}\n"
  },
  {
    "path": "libs/go/aealite/wallet/wallet_test.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2019 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\n\npackage wallet\n\nimport (\n\t\"testing\"\n)\n\nconst (\n\tEnvTestFile = \"../test_env_file.env\"\n)\n\nvar (\n\tledger_id   = \"fetchai\"\n\taddress     = \"fetch1x9v67meyfq4pkgy2n2yf6797cfkul327kpclqr\"\n\tpublic_key  = \"02ac514ba70de60ed5c30f90e3acdfc958ecb416d9676706bf013228abfb2c2816\"\n\tprivate_key = \"6d8d2b87d987641e2ca3f1991c1cccf08a118759e81fabdbf7e8484f27af015e\"\n)\n\n// TestWallet\nfunc TestWallet(t *testing.T) {\n\n\twallet := Wallet{}\n\n\t// initialise\n\terr := wallet.InitFromEnv(EnvTestFile)\n\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialise wallet\", err)\n\t}\n\n\tif wallet.LedgerId != ledger_id {\n\t\tt.Fatal(\"Wallet.LedgerId not set\")\n\t}\n\n\tif wallet.Address != address {\n\t\tt.Fatal(\"Wallet.Address not set\")\n\t}\n\n\tif wallet.PublicKey != public_key {\n\t\tt.Fatal(\"Wallet.PublicKey not set\")\n\t}\n\n\tif wallet.PrivateKey != private_key {\n\t\tt.Fatal(\"Wallet.PrivateKey not set\")\n\t}\n}\n"
  },
  {
    "path": "libs/go/libp2p_node/.dockerignore",
    "content": "libp2p_node"
  },
  {
    "path": "libs/go/libp2p_node/Dockerfile",
    "content": "FROM golang:1.17.5-buster as builder\n\nUSER root\n\nWORKDIR /build\n\nCOPY ./ ./\n\nRUN go build\n\nFROM scratch AS export-stage\nCOPY --from=builder /build/libp2p_node libp2p_node"
  },
  {
    "path": "libs/go/libp2p_node/Makefile",
    "content": "test:\n\tgo test -gcflags=-l -p 1 -timeout 0 -count 1 -covermode=atomic -coverprofile=coverage.txt -v ./...\n\tgo tool cover -func=coverage.txt\nlint:\n\tgolines . -w\n\tgolangci-lint run\n\t\nbuild:\n\tgo build\ninstall:\n\tgo get -v -t -d ./...\nrace_test:\n\tgo test -gcflags=-l -p 1 -timeout 0 -count 1 -race -v ./...\nbuild_in_docker:\n\tDOCKER_BUILDKIT=1 docker build  --output . ."
  },
  {
    "path": "libs/go/libp2p_node/README.md",
    "content": "# Libp2p Node\n\nThe `libp2p_node` is an integral part of the ACN.\n\n## ACN - Agent Communication Network\n\nThe agent communication network (ACN) provides a system for agents to find each other and communicate, solely based on their wallet addresses. It addresses the message delivery problem.\n\nFor more details check out the [docs](https://github.com/fetchai/agents-aea/blob/main/docs/acn.md).\n\n## Development\n\nTo run all tests run:\n\n``` bash\ngo test -p 1 -timeout 0 -count 1 -v ./...\n```\n\nTo lint:\n\n``` bash\ngolines . -w\ngolangci-lint run\nstaticcheck ./...\n```\n\nFor mocks generation:\ncheck <https://github.com/golang/mock>\n\n## Messaging patterns\n\nInteraction protocol\n___\nACN\n___\nTCP/UDP/...\n___\n\n### Messaging patterns inwards ACN\n\nConnection (`p2p_libp2p_client`) > Delegate Client > Relay Peer > Peer (Discouraged!)\n\nConnection (`p2p_libp2p_client`)  > Delegate Client > Peer\n\nConnection (`p2p_libp2p`) > Relay Peer > Peer\n\nConnection (`p2p_libp2p`) > Peer\n\n### Messaging patterns outwards ACN\n\nPeer > Relay Peer > Delegate Client > Connection (`p2p_libp2p_client`) (Discouraged!)\n\nPeer > Relay Peer > Connection (`p2p_libp2p`)\n\nPeer > Delegate Client > Connection (`p2p_libp2p_client`)\n\nPeer > Connection (`p2p_libp2p`)\n\nIn total 4*4 = 16 patterns (practically: 3*3 = 9 patterns)\n\n## Guarantees\n\nACN should guarantee total ordering of messages for all agent pairs, independent of the type of connection and ACN messaging pattern used.\n\n## Advanced feature (post `v1`)\n\nFurthermore, there is the agent mobility. An agent can move between entry-points (Relay Peer/Peer/Delegate Client). The ACN must ensure that all messaging patterns maintain total ordering of messages for agent pairs during the move.\n\n## ACN protocols\n\nThe ACN has the following protocols:\n\n- register\n- lookup\n- unregister (dealt with by DHT defaults)\n- DHT default protocols in libp2p\n- message delivery protocol\n"
  },
  {
    "path": "libs/go/libp2p_node/acn/utils.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2021 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\npackage acn\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"strings\"\n\t\"time\"\n\n\tacn_protocol \"libp2p_node/protocols/acn/v1_0_0\"\n\n\t\"github.com/rs/zerolog\"\n\tproto \"google.golang.org/protobuf/proto\"\n)\n\ntype StatusBody = acn_protocol.AcnMessage_StatusBody\ntype AgentRecord = acn_protocol.AcnMessage_AgentRecord\ntype AcnMessage = acn_protocol.AcnMessage\ntype LookupRequest = acn_protocol.AcnMessage_LookupRequest\ntype LookupResponse = acn_protocol.AcnMessage_LookupResponse\ntype Status = acn_protocol.AcnMessage_Status\ntype LookupRequestPerformative = acn_protocol.AcnMessage_Lookup_Request_Performative\ntype LookupResponsePerformative = acn_protocol.AcnMessage_Lookup_Response_Performative\ntype StatusPerformative = acn_protocol.AcnMessage_Status_Performative\ntype RegisterPerformative = acn_protocol.AcnMessage_Register_Performative\ntype Register = acn_protocol.AcnMessage_Register\ntype AeaEnvelope = acn_protocol.AcnMessage_AeaEnvelope\ntype AeaEnvelopePerformative = acn_protocol.AcnMessage_Aea_Envelope_Performative\n\nconst ERROR_DECODE = acn_protocol.AcnMessage_StatusBody_ERROR_DECODE\nconst SUCCESS = acn_protocol.AcnMessage_StatusBody_SUCCESS\nconst ERROR_UNEXPECTED_PAYLOAD = acn_protocol.AcnMessage_StatusBody_ERROR_UNEXPECTED_PAYLOAD\nconst ERROR_AGENT_NOT_READY = acn_protocol.AcnMessage_StatusBody_ERROR_AGENT_NOT_READY\nconst ERROR_UNKNOWN_AGENT_ADDRESS = acn_protocol.AcnMessage_StatusBody_ERROR_UNKNOWN_AGENT_ADDRESS\nconst ERROR_GENERIC = acn_protocol.AcnMessage_StatusBody_ERROR_GENERIC\nconst ERROR_WRONG_AGENT_ADDRESS = acn_protocol.AcnMessage_StatusBody_ERROR_WRONG_AGENT_ADDRESS\nconst ERROR_UNSUPPORTED_LEDGER = acn_protocol.AcnMessage_StatusBody_ERROR_UNSUPPORTED_LEDGER\nconst ERROR_WRONG_PUBLIC_KEY = acn_protocol.AcnMessage_StatusBody_ERROR_WRONG_PUBLIC_KEY\nconst ERROR_INVALID_PROOF = acn_protocol.AcnMessage_StatusBody_ERROR_INVALID_PROOF\n\ntype Status_ErrCode = acn_protocol.AcnMessage_StatusBody_StatusCodeEnum\n\nvar logger zerolog.Logger = zerolog.New(zerolog.ConsoleWriter{\n\tOut:        os.Stdout,\n\tNoColor:    false,\n\tTimeFormat: \"15:04:05.000\",\n}).\n\tWith().Timestamp().\n\tStr(\"package\", \"AeaApiACN\").\n\tLogger()\n\nconst CurrentVersion = \"0.1.0\"\n\nfunc ignore(err error) {\n\tif err != nil {\n\t\tlogger.Error().Str(\"err\", err.Error()).Msgf(\"IGNORED: %s\", err.Error())\n\t}\n}\n\ntype ACNError struct {\n\tErrorCode Status_ErrCode\n\tErr       error\n}\n\nfunc (err *ACNError) Error() string {\n\treturn err.Err.Error()\n}\n\nfunc DecodeAcnMessage(buf []byte) (string, *AeaEnvelopePerformative, *StatusBody, *ACNError) {\n\tresponse := &AcnMessage{}\n\terr := proto.Unmarshal(buf, response)\n\tmsg_type := \"\"\n\n\tif err != nil {\n\t\tlogger.Error().Str(\"err\", err.Error()).Msgf(\"while decoding acn message\")\n\t\treturn msg_type, nil, nil, &ACNError{ErrorCode: ERROR_DECODE, Err: err}\n\t}\n\t// response is either a LookupResponse or Status\n\tvar aeaEnvelope *AeaEnvelopePerformative = nil\n\tvar status *StatusBody = nil\n\n\tswitch pl := response.Performative.(type) {\n\tcase *AeaEnvelope:\n\t\taeaEnvelope = pl.AeaEnvelope\n\t\tmsg_type = \"aea_envelope\"\n\tcase *Status:\n\t\tstatus = pl.Status.Body\n\t\tmsg_type = \"status\"\n\tdefault:\n\t\terr = fmt.Errorf(\"unexpected ACN Message: %s\", response)\n\t\tlogger.Error().Msg(err.Error())\n\t\treturn msg_type, nil, nil, &ACNError{ErrorCode: ERROR_UNEXPECTED_PAYLOAD, Err: err}\n\t}\n\treturn msg_type, aeaEnvelope, status, nil\n}\n\nfunc WaitForStatus(ch chan *StatusBody, timeout time.Duration) (*StatusBody, error) {\n\tselect {\n\tcase m := <-ch:\n\t\treturn m, nil\n\tcase <-time.After(timeout):\n\t\terr := errors.New(\"ACN send acknowledge timeout\")\n\t\tlogger.Error().Msg(err.Error())\n\t\treturn nil, err\n\t}\n}\n\nfunc SendAcnSuccess(pipe Pipe) error {\n\tstatus := &StatusBody{Code: SUCCESS}\n\tperformative := &StatusPerformative{Body: status}\n\tmsg := &AcnMessage{\n\t\tPerformative: &Status{Status: performative},\n\t}\n\tbuf, err := proto.Marshal(msg)\n\tif err != nil {\n\t\tlogger.Error().Str(\"err\", err.Error()).Msgf(\"error on encoding acn status message\")\n\t\treturn err\n\t}\n\terr = pipe.Write(buf)\n\tif err != nil {\n\t\tlogger.Error().Str(\"err\", err.Error()).Msgf(\"error on sending acn status message\")\n\n\t}\n\treturn err\n}\n\nfunc SendAcnError(pipe Pipe, error_msg string, err_codes ...Status_ErrCode) error {\n\tvar err_code Status_ErrCode\n\n\tif len(err_codes) == 0 {\n\t\terr_code = ERROR_GENERIC\n\t} else {\n\t\terr_code = err_codes[0]\n\t}\n\n\tstatus := &StatusBody{Code: err_code, Msgs: []string{error_msg}}\n\tmsg := &AcnMessage{\n\t\tPerformative: &Status{Status: &StatusPerformative{Body: status}},\n\t}\n\tbuf, err := proto.Marshal(msg)\n\tif err != nil {\n\t\tlogger.Error().Str(\"err\", err.Error()).Msgf(\"error on encoding acn status message\")\n\t\treturn err\n\t}\n\terr = pipe.Write(buf)\n\tif err != nil {\n\t\tlogger.Error().Str(\"err\", err.Error()).Msgf(\"error on sending acn status message\")\n\t}\n\treturn err\n}\n\nfunc EncodeAcnEnvelope(envelope_bytes []byte, record *AgentRecord) ([]byte, error) {\n\tvar performative *AeaEnvelopePerformative\n\tif record != nil {\n\t\tperformative = &AeaEnvelopePerformative{Envelope: envelope_bytes, Record: record}\n\t} else {\n\t\tperformative = &AeaEnvelopePerformative{Envelope: envelope_bytes}\n\t}\n\n\tmsg := &AcnMessage{\n\t\tPerformative: &AeaEnvelope{AeaEnvelope: performative},\n\t}\n\n\tbuf, err := proto.Marshal(msg)\n\tif err != nil {\n\t\tlogger.Error().\n\t\t\tStr(\"err\", err.Error()).\n\t\t\tMsgf(\"while serializing envelope bytes: %s\", envelope_bytes)\n\t}\n\treturn buf, err\n}\n\ntype Pipe interface {\n\tConnect() error\n\tRead() ([]byte, error)\n\tWrite(data []byte) error\n\tClose() error\n}\n\ntype StatusQueue interface {\n\tAddAcnStatusMessage(status *StatusBody, counterpartyID string)\n}\n\nfunc ReadAgentRegistrationMessage(pipe Pipe) (*RegisterPerformative, error) {\n\tvar register *RegisterPerformative\n\tbuf, err := pipe.Read()\n\tif err != nil {\n\t\tlogger.Error().Str(\"err\", err.Error()).Msgf(\"while receiving agent's registration request\")\n\t\treturn nil, err\n\t}\n\n\tmsg := &AcnMessage{}\n\terr = proto.Unmarshal(buf, msg)\n\tif err != nil {\n\t\tlogger.Error().Str(\"err\", err.Error()).Msgf(\"couldn't deserialize acn registration message\")\n\t\t// TOFIX(LR) setting Msgs to err.Error is potentially a security vulnerability\n\t\tacn_send_error := SendAcnError(pipe, err.Error(), ERROR_DECODE)\n\t\tignore(acn_send_error)\n\t\treturn nil, err\n\t}\n\n\tswitch pl := msg.Performative.(type) {\n\tcase *Register:\n\t\tregister = pl.Register\n\tdefault:\n\t\terr = errors.New(\"Unexpected payload\")\n\t\tacn_send_error := SendAcnError(pipe, err.Error(), ERROR_UNEXPECTED_PAYLOAD)\n\t\tignore(acn_send_error)\n\t\treturn nil, err\n\t}\n\treturn register, nil\n}\n\nfunc SendEnvelopeMessageAndWaitForStatus(\n\tpipe Pipe,\n\tenvelope_bytes []byte,\n\tacn_status_chan chan *StatusBody,\n\tacnStatusTimeout time.Duration,\n) error {\n\terr := SendEnvelopeMessage(pipe, envelope_bytes, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tstatus, err := WaitForStatus(acn_status_chan, acnStatusTimeout)\n\tif err != nil {\n\t\tlogger.Error().\n\t\t\tStr(\"err\", err.Error()).\n\t\t\tMsgf(\"on envelope sent status wait\")\n\t\treturn err\n\t}\n\tif status.Code != SUCCESS {\n\t\tlogger.Error().\n\t\t\tStr(\"op\", \"send_envelope\").\n\t\t\tMsgf(\"acn confirmation status is not Status Success: %d.\", status.Code)\n\t\treturn fmt.Errorf(\n\t\t\t\"send envelope: acn confirmation status is not Status Success: %d\",\n\t\t\tstatus.Code,\n\t\t)\n\t}\n\treturn err\n\n}\n\nfunc ReadLookupRequest(pipe Pipe) (string, error) {\n\tbuf, err := pipe.Read()\n\n\tif err != nil {\n\t\tlogger.Error().Str(\"err\", err.Error()).Msgf(\"while reading message from stream\")\n\t\treturn \"\", err\n\t}\n\n\tmsg := &AcnMessage{}\n\terr = proto.Unmarshal(buf, msg)\n\tif err != nil {\n\t\tlogger.Error().\n\t\t\tStr(\"err\", err.Error()).\n\t\t\tMsgf(\"couldn't deserialize acn lookup request message\")\n\t\t// TOFIX(LR) setting Msgs to err.Error is potentially a security vulnerability\n\t\tacn_send_error := SendAcnError(pipe, err.Error(), ERROR_DECODE)\n\t\tignore(acn_send_error)\n\t\treturn \"\", err\n\t}\n\n\t// Get LookupRequest message\n\tvar lookupRequest *LookupRequestPerformative\n\tswitch pl := msg.Performative.(type) {\n\tcase *LookupRequest:\n\t\tlookupRequest = pl.LookupRequest\n\tdefault:\n\t\terr = errors.New(\"Unexpected payload\")\n\t\tacn_send_error := SendAcnError(pipe, err.Error(), ERROR_UNEXPECTED_PAYLOAD)\n\t\tignore(acn_send_error)\n\t\treturn \"\", err\n\t}\n\n\treqAddress := lookupRequest.AgentAddress\n\treturn reqAddress, nil\n}\n\nfunc SendLookupRequest(pipe Pipe, address string) error {\n\tlookupRequest := &LookupRequestPerformative{AgentAddress: address}\n\tmsg := &AcnMessage{\n\t\tPerformative: &LookupRequest{LookupRequest: lookupRequest},\n\t}\n\tbuf, err := proto.Marshal(msg)\n\tif err != nil {\n\t\treturn err\n\t}\n\terr = pipe.Write([]byte(buf))\n\treturn err\n}\n\nfunc ReadLookupResponse(pipe Pipe) (*AgentRecord, error) {\n\tbuf, err := pipe.Read()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tresponse := &AcnMessage{}\n\terr = proto.Unmarshal(buf, response)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tvar lookupResponse *LookupResponsePerformative = nil\n\tvar status *StatusPerformative = nil\n\tswitch pl := response.Performative.(type) {\n\tcase *LookupResponse:\n\t\tlookupResponse = pl.LookupResponse\n\tcase *Status:\n\t\tstatus = pl.Status\n\tdefault:\n\t\terr = errors.New(\"Unexpected Acn Message\")\n\t\tlogger.Error().Str(\"err\", err.Error()).Msgf(\"couldn't deserialize acn lookup response message\")\n\t\treturn nil, err\n\t}\n\n\tif status != nil {\n\t\terr = errors.New(\n\t\t\t\"Failed agent lookup response \" + status.Body.Code.String() + \" : \" + strings.Join(\n\t\t\t\tstatus.Body.Msgs,\n\t\t\t\t\":\",\n\t\t\t),\n\t\t)\n\t\treturn nil, err\n\t}\n\treturn lookupResponse.Record, nil\n}\n\nfunc SendLookupResponse(pipe Pipe, record *AgentRecord) error {\n\tlookupResponse := &LookupResponsePerformative{Record: record}\n\tresponse := &AcnMessage{\n\t\tPerformative: &LookupResponse{LookupResponse: lookupResponse},\n\t}\n\tbuf, err := proto.Marshal(response)\n\tif err != nil {\n\t\treturn err\n\t}\n\terr = pipe.Write(buf)\n\treturn err\n}\n\nfunc SendEnvelopeMessage(pipe Pipe, envelope_bytes []byte, record *AgentRecord) error {\n\tacnMsgBytes, err := EncodeAcnEnvelope(envelope_bytes, record)\n\tif err != nil {\n\t\treturn err\n\t}\n\terr = pipe.Write(acnMsgBytes)\n\tif err != nil {\n\t\tlogger.Error().\n\t\t\tStr(\"err\", err.Error()).\n\t\t\tMsgf(\"on pipe write\")\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc SendAgentRegisterMessage(pipe Pipe, agentRecord *AgentRecord) error {\n\tregistration := &RegisterPerformative{Record: agentRecord}\n\tmsg := &AcnMessage{\n\t\tPerformative: &Register{Register: registration},\n\t}\n\tbuf, err := proto.Marshal(msg)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\terr = pipe.Write(buf)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tstatus, err := ReadAcnStatus(pipe)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif status.Code != SUCCESS {\n\t\treturn errors.New(\"Registration failed: \" + strings.Join(status.Msgs, \":\"))\n\t}\n\treturn nil\n}\n\nfunc ReadAcnStatus(pipe Pipe) (*StatusBody, error) {\n\tbuf, err := pipe.Read()\n\tif err != nil {\n\t\tlogger.Error().\n\t\t\tStr(\"err\", err.Error()).\n\t\t\tMsgf(\"on pipe read\")\n\t\treturn nil, err\n\t}\n\n\tresponse := &AcnMessage{}\n\terr = proto.Unmarshal(buf, response)\n\tif err != nil {\n\t\tlogger.Error().\n\t\t\tStr(\"err\", err.Error()).\n\t\t\tMsgf(\"on acn decode\")\n\t\treturn nil, err\n\t}\n\n\t// response is expected to be a Status\n\tvar status *StatusPerformative\n\tswitch pl := response.Performative.(type) {\n\tcase *Status:\n\t\tstatus = pl.Status\n\tdefault:\n\t\terr = errors.New(\"Unexpected Acn Message\")\n\t\treturn nil, err\n\t}\n\n\treturn status.Body, nil\n}\n\nfunc ReadEnvelopeMessage(pipe Pipe) (*AeaEnvelopePerformative, error) {\n\tbuf, err := pipe.Read()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tmessageType, envelope, _, acnErr := DecodeAcnMessage(buf)\n\n\tif acnErr != nil {\n\t\terr = SendAcnError(\n\t\t\tpipe,\n\t\t\tacnErr.Error(),\n\t\t\tacnErr.ErrorCode,\n\t\t)\n\t\tignore(err)\n\t\treturn nil, acnErr.Err\n\t}\n\tif messageType != \"aea_envelope\" {\n\t\treturn nil, errors.New(\"unexpected payload for acn message\")\n\t}\n\treturn envelope, nil\n}\n\nfunc PerformAddressLookup(pipe Pipe, address string) (*AgentRecord, error) {\n\terr := SendLookupRequest(pipe, address)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn ReadLookupResponse(pipe)\n}\n"
  },
  {
    "path": "libs/go/libp2p_node/aea/api.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2019 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\n\npackage aea\n\nimport (\n\t\"errors\"\n\t\"log\"\n\t\"net\"\n\t\"os\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/joho/godotenv\"\n\t\"github.com/rs/zerolog\"\n\tproto \"google.golang.org/protobuf/proto\"\n\n\tacn \"libp2p_node/acn\"\n\tcommon \"libp2p_node/common\"\n)\n\nconst AcnStatusTimeout = 15.0 * time.Second\nconst SendQueueSize = 100\nconst OutQueueSize = 100\n\n// code redandency to avoid import cycle\nvar logger zerolog.Logger = zerolog.New(zerolog.ConsoleWriter{\n\tOut:        os.Stdout,\n\tNoColor:    false,\n\tTimeFormat: \"15:04:05.000\",\n}).\n\tWith().Timestamp().\n\tStr(\"package\", \"AeaApi\").\n\tLogger()\n\n/*\n\n  AeaApi type\n\n*/\n\ntype AeaApi struct {\n\tmsgin_path      string\n\tmsgout_path     string\n\tagent_addr      string\n\tagent_record    *acn.AgentRecord\n\tid              string\n\tentry_peers     []string\n\thost            string\n\tport            uint16\n\thost_public     string\n\tport_public     uint16\n\thost_delegate   string\n\tport_delegate   uint16\n\thost_monitoring string\n\tport_monitoring uint16\n\n\tmailbox_uri string\n\n\tregistrationDelay  float64\n\trecordsStoragePath string\n\n\tpipe       common.Pipe\n\tout_queue  chan *Envelope\n\tsend_queue chan *Envelope\n\n\tclosing         bool\n\tconnected       bool\n\tsandbox         bool\n\tstandalone      bool\n\tacn_status_chan chan *acn.StatusBody\n}\n\nfunc (aea AeaApi) MailboxUri() string {\n\treturn aea.mailbox_uri\n}\n\nfunc (aea AeaApi) AeaAddress() string {\n\treturn aea.agent_addr\n}\n\nfunc (aea AeaApi) PrivateKey() string {\n\treturn aea.id\n}\n\nfunc (aea AeaApi) Address() (string, uint16) {\n\treturn aea.host, aea.port\n}\n\nfunc (aea AeaApi) PublicAddress() (string, uint16) {\n\treturn aea.host_public, aea.port_public\n}\n\nfunc (aea AeaApi) DelegateAddress() (string, uint16) {\n\treturn aea.host_delegate, aea.port_delegate\n}\n\nfunc (aea AeaApi) MonitoringAddress() (string, uint16) {\n\treturn aea.host_monitoring, aea.port_monitoring\n}\n\nfunc (aea AeaApi) EntryPeers() []string {\n\treturn aea.entry_peers\n}\n\nfunc (aea AeaApi) AgentRecord() *acn.AgentRecord {\n\treturn aea.agent_record\n}\n\nfunc (aea AeaApi) RegistrationDelayInSeconds() float64 {\n\treturn aea.registrationDelay\n}\n\nfunc (aea AeaApi) RecordStoragePath() string {\n\treturn aea.recordsStoragePath\n}\n\nfunc (aea AeaApi) Put(envelope *Envelope) error {\n\tif aea.standalone {\n\t\terrorMsg := \"node running in standalone mode\"\n\t\tlogger.Warn().Msgf(errorMsg)\n\t\treturn errors.New(errorMsg)\n\t}\n\taea.send_queue <- envelope\n\treturn nil\n}\n\nfunc (aea *AeaApi) Get() *Envelope {\n\tif aea.standalone {\n\t\terrorMsg := \"node running in standalone mode\"\n\t\tlogger.Warn().Msgf(errorMsg)\n\t\treturn nil\n\t}\n\treturn <-aea.out_queue\n}\n\nfunc (aea *AeaApi) Queue() <-chan *Envelope {\n\treturn aea.out_queue\n}\n\nfunc (aea *AeaApi) Connected() bool {\n\treturn aea.connected || aea.standalone\n}\n\nfunc (aea *AeaApi) Stop() {\n\taea.send_queue <- nil\n\taea.closing = true\n\taea.stop()\n\tclose(aea.out_queue)\n\tclose(aea.send_queue)\n}\n\nfunc (aea *AeaApi) Init() error {\n\tzerolog.TimeFieldFormat = time.RFC3339Nano\n\n\tif aea.sandbox {\n\t\treturn nil\n\t}\n\n\tif aea.connected {\n\t\treturn nil\n\t}\n\taea.connected = false\n\n\tenv_file := os.Args[1]\n\tlogger.Debug().Msgf(\"env_file: %s\", env_file)\n\n\t// get config\n\terr := godotenv.Overload(env_file)\n\tif err != nil {\n\t\tlog.Fatal(\"Error loading env file\")\n\t}\n\taea.msgin_path = os.Getenv(\"AEA_TO_NODE\")\n\taea.msgout_path = os.Getenv(\"NODE_TO_AEA\")\n\taea.agent_addr = os.Getenv(\"AEA_AGENT_ADDR\")\n\taea.id = os.Getenv(\"AEA_P2P_ID\")\n\tentry_peers := os.Getenv(\"AEA_P2P_ENTRY_URIS\")\n\turi := os.Getenv(\"AEA_P2P_URI\")\n\turi_public := os.Getenv(\"AEA_P2P_URI_PUBLIC\")\n\turi_delegate := os.Getenv(\"AEA_P2P_DELEGATE_URI\")\n\turi_monitoring := os.Getenv(\"AEA_P2P_URI_MONITORING\")\n\n\tpor_address := os.Getenv(\"AEA_P2P_POR_ADDRESS\")\n\tif por_address != \"\" {\n\t\trecord := &acn.AgentRecord{Address: por_address}\n\t\trecord.PublicKey = os.Getenv(\"AEA_P2P_POR_PUBKEY\")\n\t\trecord.PeerPublicKey = os.Getenv(\"AEA_P2P_POR_PEER_PUBKEY\")\n\t\trecord.Signature = os.Getenv(\"AEA_P2P_POR_SIGNATURE\")\n\t\trecord.ServiceId = os.Getenv(\"AEA_P2P_POR_SERVICE_ID\")\n\t\trecord.LedgerId = os.Getenv(\"AEA_P2P_POR_LEDGER_ID\")\n\t\taea.agent_record = record\n\t}\n\n\taea.mailbox_uri = os.Getenv(\"AEA_P2P_MAILBOX_URI\")\n\tregistrationDelay := os.Getenv(\"AEA_P2P_CFG_REGISTRATION_DELAY\")\n\taea.recordsStoragePath = os.Getenv(\"AEA_P2P_CFG_STORAGE_PATH\")\n\n\tlogger.Debug().Msgf(\"msgin_path: %s\", aea.msgin_path)\n\tlogger.Debug().Msgf(\"msgout_path: %s\", aea.msgout_path)\n\tlogger.Debug().Msgf(\"id: %s\", aea.id)\n\tlogger.Debug().Msgf(\"addr: %s\", aea.agent_addr)\n\tlogger.Debug().Msgf(\"entry_peers: %s\", entry_peers)\n\tlogger.Debug().Msgf(\"uri: %s\", uri)\n\tlogger.Debug().Msgf(\"uri public: %s\", uri_public)\n\tlogger.Debug().Msgf(\"uri delegate service: %s\", uri_delegate)\n\n\tif aea.id == \"\" || uri == \"\" {\n\t\terr := errors.New(\"couldn't get AEA configuration: key and uri are required\")\n\t\tlogger.Error().Str(\"err\", err.Error()).Msg(\"\")\n\t\treturn err\n\t}\n\tif aea.msgin_path == \"\" && aea.msgout_path == \"\" && aea.agent_addr == \"\" {\n\t\taea.standalone = true\n\t} else if aea.msgin_path == \"\" || aea.msgout_path == \"\" || aea.agent_addr == \"\" {\n\t\terr := errors.New(\"couldn't get AEA configuration: pipes paths are required when agent address is provided\")\n\t\tlogger.Error().Str(\"err\", err.Error()).Msg(\"\")\n\t\treturn err\n\t}\n\n\t// parse uri\n\tparts := strings.SplitN(uri, \":\", -1)\n\tif len(parts) < 2 {\n\t\terr := errors.New(\"malformed Uri \" + uri)\n\t\tlogger.Error().Str(\"err\", err.Error()).Msg(\"\")\n\t\treturn err\n\t}\n\taea.host = parts[0]\n\tport, _ := strconv.ParseUint(parts[1], 10, 16)\n\taea.port = uint16(port)\n\t// hack: test if port is taken\n\taddr, err := net.ResolveTCPAddr(\"tcp\", uri)\n\tif err != nil {\n\t\treturn err\n\t}\n\tlistener, err := net.ListenTCP(\"tcp\", addr)\n\tif err != nil {\n\t\tlogger.Error().Str(\"err\", err.Error()).Msgf(\"Uri already taken %s\", uri)\n\t\treturn err\n\t}\n\tlistener.Close()\n\n\t// parse public uri\n\tif uri_public != \"\" {\n\t\tparts = strings.SplitN(uri_public, \":\", -1)\n\t\tif len(parts) < 2 {\n\t\t\terr := errors.New(\"malformed Uri \" + uri_public)\n\t\t\tlogger.Error().Str(\"err\", err.Error()).Msg(\"\")\n\t\t\treturn err\n\t\t}\n\t\taea.host_public = parts[0]\n\t\tport, _ = strconv.ParseUint(parts[1], 10, 16)\n\t\taea.port_public = uint16(port)\n\t} else {\n\t\taea.host_public = \"\"\n\t\taea.port_public = 0\n\t}\n\n\t// parse delegate uri\n\tif uri_delegate != \"\" {\n\t\tparts = strings.SplitN(uri_delegate, \":\", -1)\n\t\tif len(parts) < 2 {\n\t\t\terr := errors.New(\"malformed Uri \" + uri_delegate)\n\t\t\tlogger.Error().Str(\"err\", err.Error()).Msg(\"\")\n\t\t\treturn err\n\t\t}\n\t\taea.host_delegate = parts[0]\n\t\tport, _ = strconv.ParseUint(parts[1], 10, 16)\n\t\taea.port_delegate = uint16(port)\n\t} else {\n\t\taea.host_delegate = \"\"\n\t\taea.port_delegate = 0\n\t}\n\n\t// parse monitoring uri\n\tif uri_monitoring != \"\" {\n\t\tparts = strings.SplitN(uri_monitoring, \":\", -1)\n\t\tif len(parts) < 2 {\n\t\t\terr := errors.New(\"malformed Uri \" + uri_monitoring)\n\t\t\tlogger.Error().Str(\"err\", err.Error()).Msg(\"\")\n\t\t\treturn err\n\t\t}\n\t\taea.host_monitoring = parts[0]\n\t\tport, _ = strconv.ParseUint(parts[1], 10, 16)\n\t\taea.port_monitoring = uint16(port)\n\t} else {\n\t\taea.host_monitoring = \"\"\n\t\taea.port_monitoring = 0\n\t}\n\n\t// parse entry peers multiaddress\n\tif len(entry_peers) > 0 {\n\t\taea.entry_peers = strings.SplitN(entry_peers, \",\", -1)\n\t}\n\n\t// parse registration delay\n\tif registrationDelay == \"\" {\n\t\taea.registrationDelay = 0.0\n\t} else {\n\t\tdelay, err := strconv.ParseFloat(registrationDelay, 32)\n\t\tif err != nil {\n\t\t\tlogger.Error().Str(\"err\", err.Error()).Msgf(\"malformed RegistrationDelay value\")\n\t\t\treturn err\n\t\t}\n\t\taea.registrationDelay = delay\n\t}\n\n\t// setup pipe\n\tif !aea.standalone {\n\t\taea.pipe = NewPipe(aea.msgin_path, aea.msgout_path)\n\t}\n\n\taea.acn_status_chan = make(chan *acn.StatusBody, 1000)\n\treturn nil\n}\n\nfunc (aea *AeaApi) Connect() error {\n\tif aea.standalone {\n\t\tlogger.Info().Msg(\"Successfully running in standalone mode\")\n\t\treturn nil\n\t}\n\n\t// open pipes\n\terr := aea.pipe.Connect()\n\n\tif err != nil {\n\t\tlogger.Error().Str(\"err\", err.Error()).\n\t\t\tMsg(\"while connecting to pipe\")\n\t\treturn err\n\t}\n\n\taea.closing = false\n\t//TOFIX(LR) trade-offs between bufferd vs unbuffered channel\n\taea.out_queue = make(chan *Envelope, OutQueueSize)\n\taea.send_queue = make(chan *Envelope, SendQueueSize)\n\tgo aea.listenForEnvelopes()\n\tgo aea.envelopeSendLoop()\n\tlogger.Info().Msg(\"connected to agent\")\n\n\taea.connected = true\n\n\treturn nil\n}\n\nfunc (aea *AeaApi) listenForEnvelopes() {\n\t//TOFIX(LR) add an exit strategy\n\tfor {\n\t\tenvel, err := HandleAcnMessageFromPipe(aea.pipe, aea, aea.AeaAddress())\n\n\t\tvar e *common.PipeError\n\n\t\tif errors.As(err, &e) {\n\t\t\tlogger.Error().\n\t\t\t\tStr(\"err\", err.Error()).\n\t\t\t\tMsg(\"pipe error while receiving envelope. disconnect\")\n\t\t\tlogger.Info().Msg(\"disconnecting\")\n\n\t\t\tif !aea.closing {\n\t\t\t\taea.Stop()\n\t\t\t}\n\n\t\t\treturn\n\t\t}\n\t\tif err != nil {\n\t\t\tlogger.Error().Str(\"err\", err.Error()).Msg(\"while receiving envelope. skip\")\n\t\t\tcontinue\n\t\t}\n\t\tif envel == nil {\n\t\t\t// ACN STATUS MSG\n\t\t\tcontinue\n\t\t}\n\t\tif envel.Sender != aea.agent_record.Address {\n\t\t\tlogger.Error().\n\t\t\t\tStr(\"err\", \"Sender (\"+envel.Sender+\") must match registered address\").\n\t\t\t\tMsg(\"while processing envelope\")\n\t\t\t// TODO send error back to agent\n\t\t\tcontinue\n\t\t}\n\t\tlogger.Debug().Msgf(\"received envelope from agent\")\n\t\taea.out_queue <- envel\n\t\tif aea.closing {\n\t\t\treturn\n\t\t}\n\t}\n}\n\nfunc (aea *AeaApi) envelopeSendLoop() {\n\tlogger.Debug().Msg(\"send loop started\")\n\tvar err error\n\tfor {\n\t\tenvelope := <-aea.send_queue\n\t\tif envelope == nil {\n\t\t\tlogger.Info().Msg(\"envelope is nil. exit send loop\")\n\t\t\treturn\n\t\t}\n\t\terr = aea.SendEnvelope(envelope)\n\t\tif err != nil {\n\t\t\tlogger.Error().Str(\"err\", err.Error()).Msg(\"while sending envelope\")\n\t\t} else {\n\t\t\tlogger.Debug().Msg(\"envelope sent\")\n\t\t}\n\n\t\tif aea.closing {\n\t\t\treturn\n\t\t}\n\t}\n}\nfunc (aea *AeaApi) stop() {\n\terr := aea.pipe.Close()\n\tif err != nil {\n\t\tlogger.Error().Str(\"err\", err.Error()).Msgf(\"on pipe close during aeaapi stop\")\n\t}\n}\n\n/*\n\n  Pipes helpers\n\n*/\nconst CurrentVersion = \"0.1.0\"\n\nfunc MakeAcnMessageFromEnvelope(envelope *Envelope) ([]byte, error) {\n\tenvelope_bytes, err := proto.Marshal(envelope)\n\tif err != nil {\n\t\treturn envelope_bytes, err\n\t}\n\treturn acn.EncodeAcnEnvelope(envelope_bytes, nil)\n}\n\nfunc (aea AeaApi) SendEnvelope(envelope *Envelope) error {\n\treturn SendEnvelope(aea.pipe, aea.acn_status_chan, envelope, AcnStatusTimeout)\n}\n\nfunc SendEnvelope(\n\tpipe acn.Pipe,\n\tacn_status_chan chan *acn.StatusBody,\n\tenvelope *Envelope,\n\tacnStatusTimeout time.Duration,\n) error {\n\tenvelope_bytes, err := proto.Marshal(envelope)\n\tif err != nil {\n\t\tlogger.Error().\n\t\t\tStr(\"err\", err.Error()).\n\t\t\tMsgf(\"while serializing envelope: %s\", envelope.String())\n\t\treturn err\n\t}\n\terr = acn.SendEnvelopeMessageAndWaitForStatus(\n\t\tpipe,\n\t\tenvelope_bytes,\n\t\tacn_status_chan,\n\t\tacnStatusTimeout,\n\t)\n\n\tif err != nil {\n\t\tlogger.Error().\n\t\t\tStr(\"err\", err.Error()).\n\t\t\tMsgf(\"on send envelope: %s\", envelope.String())\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc (aea AeaApi) AddAcnStatusMessage(status *acn.StatusBody, counterpartyID string) {\n\taea.acn_status_chan <- status\n\tlogger.Info().Msgf(\"chan len is %d\", len(aea.acn_status_chan))\n}\n"
  },
  {
    "path": "libs/go/libp2p_node/aea/envelope.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.25.0\n// \tprotoc        (unknown)\n// source: envelope.proto\n\npackage aea\n\nimport (\n\tproto \"github.com/golang/protobuf/proto\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// This is a compile-time assertion that a sufficiently up-to-date version\n// of the legacy proto package is being used.\nconst _ = proto.ProtoPackageIsVersion4\n\ntype Envelope struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tTo         string `protobuf:\"bytes,1,opt,name=to,proto3\" json:\"to,omitempty\"`\n\tSender     string `protobuf:\"bytes,2,opt,name=sender,proto3\" json:\"sender,omitempty\"`\n\tProtocolId string `protobuf:\"bytes,3,opt,name=protocol_id,json=protocolId,proto3\" json:\"protocol_id,omitempty\"`\n\tMessage    []byte `protobuf:\"bytes,4,opt,name=message,proto3\" json:\"message,omitempty\"`\n\tUri        string `protobuf:\"bytes,5,opt,name=uri,proto3\" json:\"uri,omitempty\"`\n}\n\nfunc (x *Envelope) Reset() {\n\t*x = Envelope{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_envelope_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Envelope) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Envelope) ProtoMessage() {}\n\nfunc (x *Envelope) ProtoReflect() protoreflect.Message {\n\tmi := &file_envelope_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Envelope.ProtoReflect.Descriptor instead.\nfunc (*Envelope) Descriptor() ([]byte, []int) {\n\treturn file_envelope_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *Envelope) GetTo() string {\n\tif x != nil {\n\t\treturn x.To\n\t}\n\treturn \"\"\n}\n\nfunc (x *Envelope) GetSender() string {\n\tif x != nil {\n\t\treturn x.Sender\n\t}\n\treturn \"\"\n}\n\nfunc (x *Envelope) GetProtocolId() string {\n\tif x != nil {\n\t\treturn x.ProtocolId\n\t}\n\treturn \"\"\n}\n\nfunc (x *Envelope) GetMessage() []byte {\n\tif x != nil {\n\t\treturn x.Message\n\t}\n\treturn nil\n}\n\nfunc (x *Envelope) GetUri() string {\n\tif x != nil {\n\t\treturn x.Uri\n\t}\n\treturn \"\"\n}\n\nvar File_envelope_proto protoreflect.FileDescriptor\n\nvar file_envelope_proto_rawDesc = []byte{\n\t0x0a, 0x0e, 0x65, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,\n\t0x12, 0x03, 0x61, 0x65, 0x61, 0x22, 0x7f, 0x0a, 0x08, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70,\n\t0x65, 0x12, 0x0e, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x74,\n\t0x6f, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28,\n\t0x09, 0x52, 0x06, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x72, 0x6f,\n\t0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a,\n\t0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65,\n\t0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6d, 0x65, 0x73,\n\t0x73, 0x61, 0x67, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x69, 0x18, 0x05, 0x20, 0x01, 0x28,\n\t0x09, 0x52, 0x03, 0x75, 0x72, 0x69, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_envelope_proto_rawDescOnce sync.Once\n\tfile_envelope_proto_rawDescData = file_envelope_proto_rawDesc\n)\n\nfunc file_envelope_proto_rawDescGZIP() []byte {\n\tfile_envelope_proto_rawDescOnce.Do(func() {\n\t\tfile_envelope_proto_rawDescData = protoimpl.X.CompressGZIP(file_envelope_proto_rawDescData)\n\t})\n\treturn file_envelope_proto_rawDescData\n}\n\nvar file_envelope_proto_msgTypes = make([]protoimpl.MessageInfo, 1)\nvar file_envelope_proto_goTypes = []interface{}{\n\t(*Envelope)(nil), // 0: aea.Envelope\n}\nvar file_envelope_proto_depIdxs = []int32{\n\t0, // [0:0] is the sub-list for method output_type\n\t0, // [0:0] is the sub-list for method input_type\n\t0, // [0:0] is the sub-list for extension type_name\n\t0, // [0:0] is the sub-list for extension extendee\n\t0, // [0:0] is the sub-list for field type_name\n}\n\nfunc init() { file_envelope_proto_init() }\nfunc file_envelope_proto_init() {\n\tif File_envelope_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_envelope_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Envelope); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_envelope_proto_rawDesc,\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   1,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_envelope_proto_goTypes,\n\t\tDependencyIndexes: file_envelope_proto_depIdxs,\n\t\tMessageInfos:      file_envelope_proto_msgTypes,\n\t}.Build()\n\tFile_envelope_proto = out.File\n\tfile_envelope_proto_rawDesc = nil\n\tfile_envelope_proto_goTypes = nil\n\tfile_envelope_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "libs/go/libp2p_node/aea/envelope.proto",
    "content": "syntax = \"proto3\";\n\n//package libp2p_node.aea;\npackage aea;\n\nmessage Envelope{\n    string to = 1;\n    string sender = 2;\n    string protocol_id = 3;\n    bytes message = 4;\n    string uri = 5;\n}"
  },
  {
    "path": "libs/go/libp2p_node/aea/pipe.go",
    "content": "// +build windows linux darwin\n\n/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2019 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\n\npackage aea\n\nimport (\n\t\"encoding/binary\"\n\t\"errors\"\n\tcommon \"libp2p_node/common\"\n\t\"math\"\n\t\"net\"\n\t\"strconv\"\n)\n\ntype TCPSocketChannel struct {\n\tport uint16\n\tconn net.Conn\n}\n\nfunc (sock *TCPSocketChannel) Connect() error {\n\t// open tcp connection\n\tvar err error\n\tsock.conn, err = net.Dial(\"tcp\", \"127.0.0.1:\"+strconv.FormatInt(int64(sock.port), 10))\n\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (sock *TCPSocketChannel) Read() ([]byte, error) {\n\t// TOFIX(LR) duplicated code to avoid circular dep\n\t//           utils.ReadBytesConn(sock.conn)\n\tbuf := make([]byte, 4)\n\t_, err := sock.conn.Read(buf)\n\tif err != nil {\n\t\treturn buf, err\n\t}\n\tsize := binary.BigEndian.Uint32(buf)\n\n\tbuf = make([]byte, size)\n\t_, err = sock.conn.Read(buf)\n\treturn buf, err\n}\n\nfunc (sock *TCPSocketChannel) Write(data []byte) error {\n\t// TOFIX(LR) duplicated code to avoid circular dep\n\t//    \t\t utils.WriteBytesConn(sock.conn, data)\n\tif len(data) > math.MaxInt32 {\n\t\treturn errors.New(\"value too large\")\n\t}\n\tsize := uint32(len(data))\n\tbuf := make([]byte, 4, 4+size)\n\tbinary.BigEndian.PutUint32(buf, size)\n\tbuf = append(buf, data...)\n\t_, err := sock.conn.Write(buf)\n\tlogger.Debug().Msgf(\"wrote data to pipe: %d bytes\", size)\n\treturn err\n}\n\nfunc (sock *TCPSocketChannel) Close() error {\n\treturn sock.conn.Close()\n}\n\nfunc NewPipe(msgin_path string, msgout_path string) common.Pipe {\n\tport, _ := strconv.ParseUint(msgin_path, 10, 16)\n\treturn &TCPSocketChannel{port: uint16(port)}\n}\n"
  },
  {
    "path": "libs/go/libp2p_node/aea/utils.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2019 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\n\npackage aea\n\nimport (\n\t\"errors\"\n\n\tacn \"libp2p_node/acn\"\n\tcommon \"libp2p_node/common\"\n\n\tproto \"google.golang.org/protobuf/proto\"\n)\n\nfunc HandleAcnMessageFromPipe(\n\tpipe common.Pipe,\n\tstatusQueue acn.StatusQueue,\n\tcounterpartyID string,\n) (*Envelope, error) {\n\tenvelope := &Envelope{}\n\tvar acn_err error\n\n\tdata, err := pipe.Read()\n\n\tif err != nil {\n\t\tlogger.Error().Str(\"err\", err.Error()).Msg(\"while receiving data\")\n\t\treturn nil, &common.PipeError{Err: err, Msg: \"Pipe error during envelope read\"}\n\t}\n\n\tmsg_type, acn_envelope, status, acnErr := acn.DecodeAcnMessage(data)\n\n\tif acnErr != nil {\n\t\tlogger.Error().Str(\"err\", acnErr.Error()).Msg(\"while handling acn message\")\n\t\tacn_err = acn.SendAcnError(\n\t\t\tpipe,\n\t\t\tacnErr.Error(),\n\t\t\tacnErr.ErrorCode,\n\t\t)\n\t\tif acn_err != nil {\n\t\t\tlogger.Error().Str(\"err\", acn_err.Error()).Msg(\"on acn send error\")\n\t\t}\n\t\treturn envelope, acnErr\n\t}\n\n\tswitch msg_type {\n\tcase \"aea_envelope\":\n\t\t{\n\t\t\terr = proto.Unmarshal(acn_envelope.Envelope, envelope)\n\t\t\tif err != nil {\n\t\t\t\tlogger.Error().Str(\"err\", err.Error()).Msg(\"while decoding envelope\")\n\t\t\t\tacn_err = acn.SendAcnError(\n\t\t\t\t\tpipe,\n\t\t\t\t\t\"error on decoding envelope\",\n\t\t\t\t\tacn.ERROR_DECODE,\n\t\t\t\t)\n\t\t\t\tif acn_err != nil {\n\t\t\t\t\tlogger.Error().Str(\"err\", acn_err.Error()).Msg(\"on acn send error\")\n\t\t\t\t}\n\t\t\t\treturn envelope, err\n\t\t\t}\n\t\t\terr = acn.SendAcnSuccess(pipe)\n\t\t\treturn envelope, err\n\n\t\t}\n\tcase \"status\":\n\t\t{\n\t\t\tlogger.Debug().Msgf(\"got acn status %d\", status.Code)\n\t\t\tstatusQueue.AddAcnStatusMessage(status, counterpartyID)\n\t\t\treturn nil, nil\n\n\t\t}\n\tdefault:\n\t\t{\n\t\t\tacn_err = acn.SendAcnError(pipe, \"Unsupported ACN message\")\n\t\t\tif acn_err != nil {\n\t\t\t\tlogger.Error().Str(\"err\", acn_err.Error()).Msg(\"on acn send error\")\n\t\t\t}\n\t\t\treturn nil, errors.New(\"unsupported ACN message\")\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "libs/go/libp2p_node/common/common.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2021 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\npackage common\n\ntype PipeError struct {\n\tErr error\n\tMsg string\n}\n\nfunc (err *PipeError) Error() string {\n\treturn err.Msg\n}\n\nfunc (err *PipeError) Unwrap() error {\n\treturn err.Err\n}\n\ntype Pipe interface {\n\tConnect() error\n\tRead() ([]byte, error)\n\tWrite(data []byte) error\n\tClose() error\n}\n"
  },
  {
    "path": "libs/go/libp2p_node/dht/common/handlers.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2019 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\n\n// Package dhtpeer provides an implementation of an Agent Communication Network node\n// using libp2p. It participates in data storage and routing for the network.\n// It offers RelayService for dhtclient and DelegateService for tcp clients.\npackage common\n\nimport (\n\t\"strings\"\n\n\t\"log\"\n\n\t\"github.com/libp2p/go-libp2p-core/network\"\n\t\"github.com/pkg/errors\"\n\t\"github.com/rs/zerolog\"\n\t\"google.golang.org/protobuf/proto\"\n\n\tacn \"libp2p_node/acn\"\n\taea \"libp2p_node/aea\"\n\t\"libp2p_node/dht/dhtnode\"\n\tutils \"libp2p_node/utils\"\n)\n\nfunc ignore(err error) {\n\tif err != nil {\n\t\tlog.Println(\"IGNORED\", err)\n\t}\n}\n\n//Abstract DHTHandler that provides logging function and handle for incoming envelopes and ACN address requests\ntype DHTHandler interface {\n\tGetLoggers() (func(error) *zerolog.Event, func() *zerolog.Event, func() *zerolog.Event, func() *zerolog.Event)\n\tHandleAeaEnvelope(envel *aea.Envelope) *acn.ACNError\n\tHandleAeaAddressRequest(reqAddress string) (*acn.AgentRecord, *acn.ACNError)\n}\n\n//read ACN message, decode envelope, check PoR\nfunc receiveEnvelopeFromPeer(dhtHandler DHTHandler, stream network.Stream) (*aea.Envelope, error) {\n\tlerror, _, _, _ := dhtHandler.GetLoggers()\n\tstreamPipe := utils.StreamPipe{Stream: stream}\n\n\taeaEnvelope, err := acn.ReadEnvelopeMessage(streamPipe)\n\tif err != nil {\n\t\tlerror(err).Msg(\"while handling acn envelope message\")\n\t\treturn nil, err\n\t}\n\n\tenvel := &aea.Envelope{}\n\terr = proto.Unmarshal(aeaEnvelope.Envelope, envel)\n\tif err != nil {\n\t\tlerror(err).Msg(\"while deserializing acn aea envelope message\")\n\t\tignore(acn.SendAcnError(\n\t\t\tstreamPipe,\n\t\t\t\"while deserializing acn aea envelope message\",\n\t\t\tacn.ERROR_DECODE,\n\t\t))\n\t\treturn nil, err\n\t}\n\n\tremotePubkey, err := utils.FetchAIPublicKeyFromPubKey(stream.Conn().RemotePublicKey())\n\tignore(err)\n\tstatus, err := dhtnode.IsValidProofOfRepresentation(\n\t\taeaEnvelope.Record,\n\t\taeaEnvelope.Record.Address,\n\t\tremotePubkey,\n\t)\n\tif err != nil || status.Code != acn.SUCCESS {\n\t\tif err == nil {\n\t\t\terr = errors.New(status.Code.String() + \":\" + strings.Join(status.Msgs, \":\"))\n\t\t}\n\t\tlerror(err).Msg(\"incoming envelope PoR is not valid\")\n\t\tignore(acn.SendAcnError(streamPipe, \"incoming envelope PoR is not valid\", status.Code))\n\t\treturn nil, err\n\t}\n\treturn envel, nil\n}\n\n// handle envelope stream, handle acn protocol and call dhtHandler.HandleAeaEnvelope for incoming envelopes\nfunc HandleAeaEnvelopeStream(dhtHandler DHTHandler, stream network.Stream) {\n\tlerror, _, _, ldebug := dhtHandler.GetLoggers()\n\n\t//ldebug().Msgf(\"Got a new aea envelope stream\")\n\n\tenvel, err := receiveEnvelopeFromPeer(dhtHandler, stream)\n\n\tif err != nil {\n\t\tlerror(err).Msgf(\"while reading envelope from peer\")\n\t\tstream.Close()\n\t\treturn\n\t}\n\n\tldebug().Msgf(\"Received envelope from peer %s\", envel.String())\n\tstreamPipe := utils.StreamPipe{Stream: stream}\n\tacnError := dhtHandler.HandleAeaEnvelope(envel)\n\n\tif acnError != nil {\n\t\terr = acn.SendAcnError(streamPipe, acnError.Err.Error(), acnError.ErrorCode)\n\t\tignore(err)\n\t\terr = stream.Close()\n\t\tignore(err)\n\t\treturn\n\t}\n\n\terr = acn.SendAcnSuccess(streamPipe)\n\tignore(err)\n\terr = stream.Close()\n\tignore(err)\n}\n\n// handle address request stream, handle acn protocol and call dhtHandler.HandleAeaAddressRequest for incoming requests\nfunc HandleAeaAddressStream(dhtHandler DHTHandler, stream network.Stream) {\n\tlerror, _, _, ldebug := dhtHandler.GetLoggers()\n\n\t//ldebug().Msg(\"Got a new aea address stream\")\n\n\t// get LookupRequest\n\tstreamPipe := utils.StreamPipe{Stream: stream}\n\treqAddress, err := acn.ReadLookupRequest(streamPipe)\n\tif err != nil {\n\t\tlerror(err).Str(\"op\", \"resolve\").\n\t\t\tMsg(\"while reading message from stream\")\n\t\terr = stream.Reset()\n\t\tignore(err)\n\t\treturn\n\t}\n\n\tldebug().\n\t\tStr(\"op\", \"resolve\").\n\t\tStr(\"target\", reqAddress).\n\t\tMsg(\"Received query for addr\")\n\n\trecord, acnError := dhtHandler.HandleAeaAddressRequest(reqAddress)\n\tif acnError != nil {\n\t\tlerror(acnError.Err).\n\t\t\tStr(\"op\", \"resolve\").\n\t\t\tStr(\"target\", reqAddress).\n\t\t\tMsgf(\"request address error\")\n\t\terr = acn.SendAcnError(streamPipe, acnError.Err.Error(), acnError.ErrorCode)\n\t\tignore(err)\n\t\terr = stream.Close()\n\t\tignore(err)\n\t\treturn\n\t}\n\tif record == nil {\n\t\tlerror(acnError.Err).\n\t\t\tStr(\"op\", \"resolve\").\n\t\t\tStr(\"target\", reqAddress).\n\t\t\tMsgf(\"unexpected error. agent record is nil!\")\n\t\treturn\n\t}\n\terr = acn.SendLookupResponse(streamPipe, record)\n\tif err != nil {\n\t\tlerror(err).Str(\"op\", \"resolve\").Str(\"addr\", reqAddress).\n\t\t\tMsg(\"while sending agent record to peer\")\n\t\terr = stream.Reset()\n\t\tignore(err)\n\t}\n}\n"
  },
  {
    "path": "libs/go/libp2p_node/dht/dhtclient/dhtclient.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2019 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\n\n// Package dhtclient provides implementation of a lightweight Agent Communication Network\n// node. It doesn't participate in network maintenance. It doesn't require a public IP\n// address either, as it relies on a DHTPeer (relay peer) to communicate with other peers.\npackage dhtclient\n\nimport (\n\t\"context\"\n\t\"log\"\n\t\"math/rand\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/pkg/errors\"\n\n\t\"github.com/rs/zerolog\"\n\t\"google.golang.org/protobuf/proto\"\n\n\tlibp2p \"github.com/libp2p/go-libp2p\"\n\t\"github.com/libp2p/go-libp2p-core/crypto\"\n\t\"github.com/libp2p/go-libp2p-core/host\"\n\t\"github.com/libp2p/go-libp2p-core/network\"\n\t\"github.com/libp2p/go-libp2p-core/peer\"\n\t\"github.com/libp2p/go-libp2p-core/protocol\"\n\t\"github.com/multiformats/go-multiaddr\"\n\n\tpeerstore \"github.com/libp2p/go-libp2p-core/peerstore\"\n\tkaddht \"github.com/libp2p/go-libp2p-kad-dht\"\n\troutedhost \"github.com/libp2p/go-libp2p/p2p/host/routed\"\n\n\tacn \"libp2p_node/acn\"\n\taea \"libp2p_node/aea\"\n\tcommon \"libp2p_node/dht/common\"\n\t\"libp2p_node/dht/dhtnode\"\n\tutils \"libp2p_node/utils\"\n)\n\nfunc ignore(err error) {\n\tif err != nil {\n\t\tlog.Println(\"IGNORED\", err)\n\t}\n}\n\nconst (\n\tnewStreamTimeoutRelayPeer = 5 * 60 * time.Second // includes peer restart\n\tnewStreamTimeout          = 1 * 60 * time.Second // doesn't include peer restart\n\tbootstrapTimeout          = 1 * 60 * time.Second // doesn't include peer restart\n\tsleepTimeDefaultDuration  = 100 * time.Millisecond\n\tsleepTimeIncreaseMFactor  = 2 // multiplicative increase\n\treconnectTimeout          = 5 * time.Second\n)\n\n// Notifee Handle DHTClient network events\ntype Notifee struct {\n\tmyRelayPeer peer.AddrInfo\n\tmyHost      host.Host\n\tlogger      zerolog.Logger\n\tclosing     chan struct{}\n}\n\n// Listen called when network starts listening on an addr\nfunc (notifee *Notifee) Listen(network.Network, multiaddr.Multiaddr) {}\n\n// ListenClose called when network stops listening on an addr\nfunc (notifee *Notifee) ListenClose(network.Network, multiaddr.Multiaddr) {}\n\n// Connected called when a connection opened\nfunc (notifee *Notifee) Connected(net network.Network, conn network.Conn) {\n\tnotifee.logger.Info().Msgf(\n\t\t\"Connected to peer %s\",\n\t\tconn.RemotePeer().Pretty(),\n\t)\n\n}\n\n// Disconnected called when a connection closed\n// Reconnects if connection is to relay peer and not currenctly closing connection.\nfunc (notifee *Notifee) Disconnected(net network.Network, conn network.Conn) {\n\n\tnotifee.logger.Info().Msgf(\n\t\t\"Disconnected from peer %s\",\n\t\tconn.RemotePeer().Pretty(),\n\t)\n\tpinfo := notifee.myRelayPeer\n\tif conn.RemotePeer().Pretty() != pinfo.ID.Pretty() {\n\t\treturn\n\t}\n\n\tnotifee.myHost.Peerstore().AddAddrs(pinfo.ID, pinfo.Addrs, peerstore.PermanentAddrTTL)\n\tfor {\n\t\tvar err error\n\t\tselect {\n\t\tcase _, open := <-notifee.closing:\n\t\t\tif !open {\n\t\t\t\treturn\n\t\t\t}\n\t\tdefault:\n\t\t\tnotifee.logger.Warn().Msgf(\n\t\t\t\t\"Lost connection to relay peer %s, reconnecting...\",\n\t\t\t\tpinfo.ID.Pretty(),\n\t\t\t)\n\t\t\tctx, cancel := context.WithTimeout(context.Background(), reconnectTimeout)\n\t\t\tdefer cancel()\n\t\t\tif err = notifee.myHost.Connect(ctx, pinfo); err == nil {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\ttime.Sleep(1 * time.Second)\n\n\t\t}\n\t\tif err == nil {\n\t\t\tbreak\n\t\t}\n\t}\n\tnotifee.logger.Info().Msgf(\"Connection to relay peer %s reestablished\", pinfo.ID.Pretty())\n}\n\n// OpenedStream called when a stream opened\nfunc (notifee *Notifee) OpenedStream(network.Network, network.Stream) {}\n\n// ClosedStream called when a stream closed\nfunc (notifee *Notifee) ClosedStream(network.Network, network.Stream) {}\n\n// DHTClient A restricted libp2p node for the Agents Communication Network\n// It use a `DHTPeer` to communicate with other peers.\ntype DHTClient struct {\n\tbootstrapPeers []peer.AddrInfo\n\trelayPeer      peer.ID\n\tkey            crypto.PrivKey\n\tpublicKey      crypto.PubKey\n\n\tdht        *kaddht.IpfsDHT\n\troutedHost *routedhost.RoutedHost\n\n\tmyAgentAddress  string\n\tmyAgentRecord   *acn.AgentRecord\n\tmyAgentReady    func() bool\n\tprocessEnvelope func(*aea.Envelope) error\n\n\tclosing chan struct{}\n\tlogger  zerolog.Logger\n}\n\n// New creates a new DHTClient\nfunc New(opts ...Option) (*DHTClient, error) {\n\tvar err error\n\tdhtClient := &DHTClient{}\n\n\tfor _, opt := range opts {\n\t\tif err := opt(dhtClient); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tdhtClient.closing = make(chan struct{})\n\n\t/* check correct configuration */\n\n\t// private key\n\tif dhtClient.key == nil {\n\t\treturn nil, errors.New(\"private key must be provided\")\n\t}\n\n\t// agent address is mandatory\n\tif dhtClient.myAgentAddress == \"\" {\n\t\treturn nil, errors.New(\"missing agent address\")\n\t}\n\n\t// agent record is mandatory\n\tif dhtClient.myAgentRecord == nil {\n\t\treturn nil, errors.New(\"missing agent record\")\n\t}\n\n\t// check if the PoR is delivered for my public key\n\tmyPublicKey, err := utils.FetchAIPublicKeyFromPubKey(dhtClient.publicKey)\n\tstatus, errPoR := dhtnode.IsValidProofOfRepresentation(\n\t\tdhtClient.myAgentRecord,\n\t\tdhtClient.myAgentRecord.Address,\n\t\tmyPublicKey,\n\t)\n\tif err != nil || errPoR != nil || status.Code != acn.SUCCESS {\n\t\tmsg := \"Invalid AgentRecord\"\n\t\tif err != nil {\n\t\t\tmsg += \" - \" + err.Error()\n\t\t}\n\t\tif errPoR != nil {\n\t\t\tmsg += \" - \" + errPoR.Error()\n\t\t}\n\t\treturn nil, errors.New(msg)\n\t}\n\n\t// bootstrap peers\n\tif len(dhtClient.bootstrapPeers) < 1 {\n\t\treturn nil, errors.New(\"at least one boostrap peer should be provided\")\n\t}\n\n\t// select a relay node randomly from entry peers\n\trand.Seed(time.Now().Unix())\n\tindex := rand.Intn(len(dhtClient.bootstrapPeers))\n\tdhtClient.relayPeer = dhtClient.bootstrapPeers[index].ID\n\n\tdhtClient.setupLogger()\n\t_, _, linfo, ldebug := dhtClient.GetLoggers()\n\tlinfo().Msg(\"INFO Using as relay\")\n\n\t/* setup libp2p node */\n\tctx := context.Background()\n\n\t// libp2p options\n\tlibp2pOpts := []libp2p.Option{\n\t\tlibp2p.ListenAddrs(),\n\t\tlibp2p.Identity(dhtClient.key),\n\t\tlibp2p.DefaultTransports,\n\t\tlibp2p.DefaultMuxers,\n\t\tlibp2p.DefaultSecurity,\n\t\tlibp2p.NATPortMap(),\n\t\tlibp2p.EnableNATService(),\n\t\tlibp2p.EnableRelay(),\n\t}\n\n\t// create a basic host\n\tbasicHost, err := libp2p.New(ctx, libp2pOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// create the dht\n\tdhtClient.dht, err = kaddht.New(ctx, basicHost, kaddht.Mode(kaddht.ModeClient))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// make the routed host\n\tdhtClient.routedHost = routedhost.Wrap(basicHost, dhtClient.dht)\n\tdhtClient.setupLogger()\n\n\t// connect to the booststrap nodes\n\terr = dhtClient.bootstrapLoopUntilTimeout()\n\tif err != nil {\n\t\tdhtClient.Close()\n\t\treturn nil, err\n\t}\n\n\t// bootstrap the host\n\terr = dhtClient.dht.Bootstrap(ctx)\n\tif err != nil {\n\t\tdhtClient.Close()\n\t\treturn nil, err\n\t}\n\n\t// register my address to relay peer\n\terr = dhtClient.registerAgentAddress()\n\tif err != nil {\n\t\tdhtClient.Close()\n\t\treturn nil, err\n\t}\n\n\tdhtClient.routedHost.Network().Notify(&Notifee{\n\t\tmyRelayPeer: dhtClient.bootstrapPeers[index],\n\t\tmyHost:      dhtClient.routedHost,\n\t\tlogger:      dhtClient.logger,\n\t\tclosing:     dhtClient.closing,\n\t})\n\n\t/* setup DHTClient message handlers */\n\n\t// aea address lookup\n\tldebug().Msg(\"DEBUG Setting /aea-address/0.1.0 stream...\")\n\tdhtClient.routedHost.SetStreamHandler(dhtnode.AeaAddressStream,\n\t\tdhtClient.handleAeaAddressStream)\n\n\t// incoming envelopes stream\n\tldebug().Msg(\"DEBUG Setting /aea/0.1.0 stream...\")\n\tdhtClient.routedHost.SetStreamHandler(dhtnode.AeaEnvelopeStream,\n\t\tdhtClient.handleAeaEnvelopeStream)\n\n\treturn dhtClient, nil\n}\n\n// bootstrapLoopUntilTimeout loops until connection to bootstrap peers established or timeout reached\nfunc (dhtClient *DHTClient) bootstrapLoopUntilTimeout() error {\n\tlerror, _, _, _ := dhtClient.GetLoggers()\n\tctx, cancel := context.WithTimeout(context.Background(), bootstrapTimeout)\n\tdefer cancel()\n\terr := utils.BootstrapConnect(\n\t\tctx,\n\t\tdhtClient.routedHost,\n\t\tdhtClient.dht,\n\t\tdhtClient.bootstrapPeers,\n\t)\n\tsleepTime := sleepTimeDefaultDuration\n\tfor err != nil {\n\t\tlerror(err).\n\t\t\tStr(\"op\", \"bootstrap\").\n\t\t\tMsgf(\"couldn't open stream to bootstrap peer, retrying in %s\", sleepTime)\n\t\tselect {\n\t\tdefault:\n\t\t\ttime.Sleep(sleepTime)\n\t\t\tsleepTime = sleepTime * sleepTimeIncreaseMFactor\n\t\t\terr = utils.BootstrapConnect(\n\t\t\t\tctx,\n\t\t\t\tdhtClient.routedHost,\n\t\t\t\tdhtClient.dht,\n\t\t\t\tdhtClient.bootstrapPeers,\n\t\t\t)\n\t\tcase <-ctx.Done():\n\t\t\terr = errors.New(\"bootstrap connect timeout reached\")\n\t\t}\n\t}\n\treturn err\n}\n\n// newStreamLoopUntilTimeout loops until stream to peer established or timeout reached\nfunc (dhtClient *DHTClient) newStreamLoopUntilTimeout(\n\tpeerID peer.ID,\n\tstreamType protocol.ID,\n\ttimeout time.Duration,\n) (network.Stream, error) {\n\tlerror, _, _, _ := dhtClient.GetLoggers()\n\tctx, cancel := context.WithTimeout(context.Background(), timeout)\n\tdefer cancel()\n\tstream, err := dhtClient.routedHost.NewStream(ctx, peerID, streamType)\n\tsleepTime := sleepTimeDefaultDuration\n\tdisconnected := false\n\tfor err != nil {\n\t\tdisconnected = true\n\t\tlerror(err).\n\t\t\tStr(\"op\", \"route\").\n\t\t\tMsgf(\"couldn't open stream to peer %s, retrying in %s\", peerID.Pretty(), sleepTime)\n\t\tselect {\n\t\tdefault:\n\t\t\ttime.Sleep(sleepTime)\n\t\t\tsleepTime = sleepTime * sleepTimeIncreaseMFactor\n\t\t\tstream, err = dhtClient.routedHost.NewStream(ctx, peerID, streamType)\n\t\tcase <-ctx.Done():\n\t\t\terr = errors.New(\"new stream loop timeout reached\")\n\t\t}\n\t}\n\tif stream == nil && err == nil {\n\t\treturn nil, errors.New(\"stream nil and err nil\")\n\t}\n\t// register again in case of disconnection\n\tif disconnected {\n\t\terr = dhtClient.registerAgentAddress()\n\t}\n\treturn stream, err\n}\n\n// setupLogger sets up a logger for the DHTClient\nfunc (dhtClient *DHTClient) setupLogger() {\n\tfields := map[string]string{\n\t\t\"package\": \"DHTClient\",\n\t\t\"relayid\": dhtClient.relayPeer.Pretty(),\n\t}\n\tif dhtClient.routedHost != nil {\n\t\tfields[\"peerid\"] = dhtClient.routedHost.ID().Pretty()\n\t}\n\tdhtClient.logger = utils.NewDefaultLoggerWithFields(fields)\n}\n\n// GetLoggers gets the various logger levels of the DHTClient\nfunc (dhtClient *DHTClient) GetLoggers() (func(error) *zerolog.Event, func() *zerolog.Event, func() *zerolog.Event, func() *zerolog.Event) {\n\tldebug := dhtClient.logger.Debug\n\tlinfo := dhtClient.logger.Info\n\tlwarn := dhtClient.logger.Warn\n\tlerror := func(err error) *zerolog.Event {\n\t\tif err == nil {\n\t\t\treturn dhtClient.logger.Error().Str(\"err\", \"nil\")\n\t\t}\n\t\treturn dhtClient.logger.Error().Str(\"err\", err.Error())\n\t}\n\n\treturn lerror, lwarn, linfo, ldebug\n}\n\n// Close stops the DHTClient\n// Closes the DHT and routedHost of the DHTClient\nfunc (dhtClient *DHTClient) Close() []error {\n\tvar err error\n\tvar status []error\n\n\t_, _, linfo, _ := dhtClient.GetLoggers()\n\n\tlinfo().Msg(\"Stopping DHTClient...\")\n\tclose(dhtClient.closing)\n\n\terrappend := func(err error) {\n\t\tif err != nil {\n\t\t\tstatus = append(status, err)\n\t\t}\n\t}\n\n\terr = dhtClient.dht.Close()\n\terrappend(err)\n\terr = dhtClient.routedHost.Close()\n\terrappend(err)\n\n\treturn status\n}\n\n// MultiAddr always return empty string\nfunc (dhtClient *DHTClient) MultiAddr() string {\n\treturn \"\"\n}\n\nfunc (dhtClient *DHTClient) PeerID() string {\n\treturn dhtClient.routedHost.ID().Pretty()\n}\n\n// RouteEnvelope routes the provided envelope to its destination contact peer\nfunc (dhtClient *DHTClient) RouteEnvelope(envel *aea.Envelope) error {\n\tlerror, lwarn, _, ldebug := dhtClient.GetLoggers()\n\n\t// only send envelopes from own agent\n\tif envel.Sender != dhtClient.myAgentAddress {\n\t\terr := errors.New(\"Sender (\" + envel.Sender + \") must match registered address\")\n\t\tlerror(err).Str(\"addr\", dhtClient.myAgentAddress).\n\t\t\tMsgf(\"while routing envelope\")\n\t\treturn err\n\t}\n\n\ttarget := envel.To\n\n\t// TODO(LR) check if the record is valid\n\tif target == dhtClient.myAgentAddress {\n\t\tldebug().\n\t\t\tStr(\"op\", \"route\").\n\t\t\tStr(\"target\", target).\n\t\t\tMsg(\"envelope destinated to my local agent...\")\n\t\tfor !dhtClient.myAgentReady() {\n\t\t\tldebug().\n\t\t\t\tStr(\"op\", \"route\").\n\t\t\t\tStr(\"target\", target).\n\t\t\t\tMsg(\"agent not ready yet, sleeping for some time ...\")\n\t\t\ttime.Sleep(time.Duration(100) * time.Millisecond)\n\t\t}\n\t\tif dhtClient.processEnvelope != nil {\n\t\t\terr := dhtClient.processEnvelope(envel)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t} else {\n\t\t\tlwarn().\n\t\t\t\tStr(\"op\", \"route\").\n\t\t\t\tStr(\"target\", target).\n\t\t\t\tMsgf(\"ProcessEnvelope not set, ignoring envelope %s\", envel.String())\n\t\t\treturn nil\n\t\t}\n\t}\n\n\t// client can get addresses only through bootstrap peer\n\tstream, err := dhtClient.newStreamLoopUntilTimeout(\n\t\tdhtClient.relayPeer,\n\t\tdhtnode.AeaAddressStream,\n\t\tnewStreamTimeoutRelayPeer,\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tldebug().\n\t\tStr(\"op\", \"route\").\n\t\tStr(\"target\", target).\n\t\tMsg(\"requesting agent record from relay...\")\n\n\tstreamPipe := utils.StreamPipe{Stream: stream}\n\n\trecord, err := acn.PerformAddressLookup(streamPipe, target)\n\tif err != nil {\n\t\tlerror(err).Str(\"op\", \"route\").Str(\"target\", target).\n\t\t\tMsgf(\"failed agent lookup\")\n\t\treturn err\n\t}\n\tvalid, err := dhtnode.IsValidProofOfRepresentation(record, target, record.PeerPublicKey)\n\tif err != nil || valid.Code != acn.SUCCESS {\n\t\terrMsg := valid.Code.String() + \" : \" + strings.Join(\n\t\t\tvalid.Msgs,\n\t\t\t\":\",\n\t\t)\n\t\tif err == nil {\n\t\t\terr = errors.New(errMsg)\n\t\t} else {\n\t\t\terr = errors.Wrap(err, valid.Code.String()+\" : \"+strings.Join(valid.Msgs, \":\"))\n\t\t}\n\t\tlerror(err).Str(\"op\", \"route\").Str(\"target\", target).\n\t\t\tMsgf(\"invalid agent record\")\n\t\treturn err\n\t}\n\n\tstream.Close()\n\n\t// retrieve peerID\n\tpeerID, err := utils.IDFromFetchAIPublicKey(record.PeerPublicKey)\n\tif err != nil {\n\t\tlerror(err).\n\t\t\tStr(\"op\", \"route\").\n\t\t\tStr(\"target\", target).\n\t\t\tMsg(\"CRITICAL couldn't get peer ID from message\")\n\t\treturn errors.New(\"CRITICAL route - couldn't get peer ID from record peerID:\" + err.Error())\n\t}\n\n\tldebug().\n\t\tStr(\"op\", \"route\").\n\t\tStr(\"target\", target).\n\t\tMsgf(\"got peer ID %s for agent Address\", peerID.Pretty())\n\n\t// TODO(LR): test if representative peer is relay peer, and skip the Connect if it is the case\n\t// TODO(DM): extract below multi-address creation for reuse and consistency\n\tmultiAddr := \"/p2p/\" + dhtClient.relayPeer.Pretty() + \"/p2p-circuit/p2p/\" + peerID.Pretty()\n\trelayMultiaddr, err := multiaddr.NewMultiaddr(multiAddr)\n\tif err != nil {\n\t\tlerror(err).\n\t\t\tStr(\"op\", \"route\").\n\t\t\tStr(\"target\", target).\n\t\t\tMsgf(\"while creating relay multiaddress %s\", multiAddr)\n\t\treturn err\n\t}\n\tpeerRelayInfo := peer.AddrInfo{\n\t\tID:    peerID,\n\t\tAddrs: []multiaddr.Multiaddr{relayMultiaddr},\n\t}\n\n\tldebug().\n\t\tStr(\"op\", \"route\").\n\t\tStr(\"target\", target).\n\t\tMsgf(\"connecting to target through relay %s\", relayMultiaddr)\n\n\tif err = dhtClient.routedHost.Connect(context.Background(), peerRelayInfo); err != nil {\n\t\tlerror(err).\n\t\t\tStr(\"op\", \"route\").\n\t\t\tStr(\"target\", target).\n\t\t\tMsgf(\"couldn't connect to target %s\", peerID)\n\t\treturn err\n\t}\n\n\tldebug().\n\t\tStr(\"op\", \"route\").\n\t\tStr(\"target\", target).\n\t\tMsgf(\"opening stream to target %s\", peerID)\n\n\tstream, err = dhtClient.newStreamLoopUntilTimeout(\n\t\tpeerID,\n\t\tdhtnode.AeaEnvelopeStream,\n\t\tnewStreamTimeout,\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\tstreamPipe = utils.StreamPipe{Stream: stream}\n\n\tenvelBytes, err := proto.Marshal(envel)\n\tif err != nil {\n\t\tlerror(err).\n\t\t\tStr(\"op\", \"route\").\n\t\t\tStr(\"target\", target).\n\t\t\tMsg(\"couldn't serialize envelope\")\n\t\terrReset := stream.Reset()\n\t\tignore(errReset)\n\t\treturn err\n\t}\n\n\terr = acn.SendEnvelopeMessage(streamPipe, envelBytes, dhtClient.myAgentRecord)\n\tif err != nil {\n\t\tlerror(err).\n\t\t\tStr(\"op\", \"route\").\n\t\t\tStr(\"target\", target).\n\t\t\tMsg(\"couldn't send envelope\")\n\t\terrReset := stream.Reset()\n\t\tlerror(errReset).\n\t\t\tMsg(\"stream.Reset error\")\n\t\tignore(errReset)\n\t\treturn err\n\t}\n\n\t// wait for response\n\tstatus, err := acn.ReadAcnStatus(streamPipe)\n\tif err != nil {\n\t\tlerror(err).\n\t\t\tStr(\"op\", \"route\").\n\t\t\tStr(\"target\", target).\n\t\t\tMsg(\"while getting confirmation\")\n\t\terrReset := stream.Reset()\n\t\tignore(errReset)\n\t\treturn err\n\t}\n\n\tstream.Close()\n\n\tif status.Code != acn.SUCCESS {\n\t\terr = errors.New(\n\t\t\tstatus.Code.String() + \" : \" + strings.Join(\n\t\t\t\tstatus.Msgs,\n\t\t\t\t\":\",\n\t\t\t),\n\t\t)\n\t\tlerror(err).\n\t\t\tStr(\"op\", \"route\").\n\t\t\tStr(\"target\", target).\n\t\t\tMsg(\"failed to deliver envelope\")\n\t\treturn err\n\t}\n\n\t// TODO(DM) check how we handle case when envelope not routable.\n\treturn err\n}\n\n// handleAeaEnvelopeStream deals with incoming envelopes on the AeaEnvelopeStream\n// envelopes arrive from other peers (full or client) and are processed\n// by HandleAeaEnvelope\nfunc (dhtClient *DHTClient) handleAeaEnvelopeStream(stream network.Stream) {\n\tcommon.HandleAeaEnvelopeStream(dhtClient, stream)\n}\n\n// Callback to handle and route  aea envelope comes from the aea envelope stream\n// return ACNError if message routing failed, otherwise nil.\nfunc (dhtClient *DHTClient) HandleAeaEnvelope(envel *aea.Envelope) *acn.ACNError {\n\tlerror, lwarn, _, _ := dhtClient.GetLoggers()\n\tvar err error\n\tif envel.To == dhtClient.myAgentAddress && dhtClient.processEnvelope != nil {\n\t\terr = dhtClient.processEnvelope(envel)\n\t\tif err != nil {\n\t\t\tlerror(err).Msgf(\"while processing envelope by agent\")\n\t\t\treturn &acn.ACNError{\n\t\t\t\tErr:       errors.New(\"agent is not ready\"),\n\t\t\t\tErrorCode: acn.ERROR_AGENT_NOT_READY,\n\t\t\t}\n\t\t}\n\t} else {\n\t\tlwarn().Msgf(\"ignored envelope from unknown agent %s\", envel.String())\n\t\treturn &acn.ACNError{Err: errors.New(\"unknown agent address\"), ErrorCode: acn.ERROR_UNKNOWN_AGENT_ADDRESS}\n\t}\n\treturn nil\n}\n\n// handleAeaAddressStream deals with incoming envelopes on the AeaAddressStream\n// agent record lookup requests arrive from other peers (full or client) and are\n// served with the agent record (if applicable)\nfunc (dhtClient *DHTClient) handleAeaAddressStream(stream network.Stream) {\n\tcommon.HandleAeaAddressStream(dhtClient, stream)\n}\n\nfunc (dhtClient *DHTClient) HandleAeaAddressRequest(\n\treqAddress string,\n) (*acn.AgentRecord, *acn.ACNError) {\n\tlerror, _, _, ldebug := dhtClient.GetLoggers()\n\tldebug().\n\t\tStr(\"op\", \"resolve\").\n\t\tStr(\"target\", reqAddress).\n\t\tMsg(\"Received query for addr\")\n\n\tif reqAddress != dhtClient.myAgentAddress {\n\t\tlerror(errors.New(\"unknown agent address\")).\n\t\t\tStr(\"op\", \"resolve\").\n\t\t\tStr(\"target\", reqAddress).\n\t\t\tMsgf(\"requested address different from advertised one %s\", dhtClient.myAgentAddress)\n\t\treturn nil, &acn.ACNError{\n\t\t\tErr:       errors.New(\"unknown agent address\"),\n\t\t\tErrorCode: acn.ERROR_UNKNOWN_AGENT_ADDRESS,\n\t\t}\n\t} else {\n\t\treturn dhtClient.myAgentRecord, nil\n\t}\n}\n\n// registerAgentAddress registers agent address to relay peer\nfunc (dhtClient *DHTClient) registerAgentAddress() error {\n\tlerror, _, _, ldebug := dhtClient.GetLoggers()\n\n\tldebug().\n\t\tStr(\"op\", \"register\").\n\t\tStr(\"addr\", dhtClient.myAgentAddress).\n\t\tMsg(\"opening stream aea-register to relay peer...\")\n\n\tctx, cancel := context.WithTimeout(context.Background(), newStreamTimeoutRelayPeer)\n\tdefer cancel()\n\tstream, err := dhtClient.routedHost.NewStream(\n\t\tctx,\n\t\tdhtClient.relayPeer,\n\t\tdhtnode.AeaRegisterRelayStream,\n\t)\n\tif err != nil {\n\t\tlerror(err).\n\t\t\tStr(\"op\", \"register\").\n\t\t\tStr(\"addr\", dhtClient.myAgentAddress).\n\t\t\tMsg(\"timeout, couldn't open stream to relay peer\")\n\t\treturn err\n\t}\n\n\tldebug().\n\t\tStr(\"op\", \"register\").\n\t\tStr(\"addr\", dhtClient.myAgentAddress).\n\t\tMsgf(\"registering addr and peerID to relay peer\")\n\n\tstreamPipe := utils.StreamPipe{Stream: stream}\n\terr = acn.SendAgentRegisterMessage(streamPipe, dhtClient.myAgentRecord)\n\n\tif err != nil {\n\t\terrReset := stream.Close()\n\t\tignore(errReset)\n\t\treturn err\n\t}\n\tstream.Close()\n\treturn nil\n\n}\n\n// ProcessEnvelope register a callback function for processing of envelopes\n// the function processes envelopes received in handleAeaEnvelopeStream\nfunc (dhtClient *DHTClient) ProcessEnvelope(fn func(*aea.Envelope) error) {\n\tdhtClient.processEnvelope = fn\n}\n"
  },
  {
    "path": "libs/go/libp2p_node/dht/dhtclient/dhtclient_test.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2019 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\n\npackage dhtclient\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"libp2p_node/acn\"\n\t\"libp2p_node/aea\"\n\t\"libp2p_node/dht/dhtnode\"\n\t\"libp2p_node/dht/dhttests\"\n\tutils \"libp2p_node/utils\"\n)\n\n//\nconst (\n\tDefaultFetchAIKey       = \"04ab8ac134ec727917cf4f9e47685e84622151bc8b12838bc54c8ffe5d44d04a\"\n\tDefaultFetchAIPublicKey = \"03b07ef4513e3f0372245b3d6d474d871ba58eacaf3a2a07c487af6d82006b86b4\"\n\tDefaultAgentKey         = \"f76137a61c1ad3ee8a0a9a185bc8e6fa51be1a2528f86042c11f9cc00880024a\"\n\tDefaultAgentPublicKey   = \"021820ce23b5f3a6ef01988149e724af854f89d37b9cabc3b1702cc5287f617b92\"\n\tDefaultAgentAddress     = \"fetch1ver6u7xdvkjy4dq8xxrkc6ualu98k7ykumv08q\"\n\n\tEnvelopeDeliveryTimeout = 10 * time.Second\n\n\tDefaultLedger = dhtnode.DefaultLedger\n)\n\n// TestNew dht client peer\nfunc TestNew(t *testing.T) {\n\n\trxEnvelopesPeer := make(chan *aea.Envelope, 2)\n\tdhtPeer, cleanup, err := dhttests.NewDHTPeerWithDefaults(rxEnvelopesPeer)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to create DHTPeer (required for DHTClient):\", err)\n\t}\n\tdefer cleanup()\n\n\tsignature, err := utils.SignFetchAI([]byte(DefaultFetchAIPublicKey), DefaultAgentKey)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTClient:\", err)\n\t}\n\n\trecord := &acn.AgentRecord{LedgerId: DefaultLedger}\n\trecord.Address = DefaultAgentAddress\n\trecord.PublicKey = DefaultAgentPublicKey\n\trecord.PeerPublicKey = DefaultFetchAIPublicKey\n\trecord.Signature = signature\n\n\topts := []Option{\n\t\tIdentityFromFetchAIKey(DefaultFetchAIKey),\n\t\tRegisterAgentAddress(record, func() bool { return true }),\n\t\tBootstrapFrom([]string{dhtPeer.MultiAddr()}),\n\t}\n\n\tt.Log(dhtPeer.MultiAddr())\n\n\tdhtClient, err := New(opts...)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTClient:\", err)\n\t}\n\tdefer dhtClient.Close()\n\n\trxEnvelopesClient := make(chan *aea.Envelope, 2)\n\tdhtClient.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxEnvelopesClient <- envel\n\t\treturn nil\n\t})\n\n}\n\n// TestRouteEnvelopeToPeerAgent send envelope from DHTClient agent to DHTPeer agent\nfunc TestRouteEnvelopeToPeerAgent(t *testing.T) {\n\n\trxEnvelopesPeer := make(chan *aea.Envelope, 2)\n\tdhtPeer, cleanup, err := dhttests.NewDHTPeerWithDefaults(rxEnvelopesPeer)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to create DHTPeer (required for DHTClient):\", err)\n\t}\n\tdefer cleanup()\n\n\tsignature, err := utils.SignFetchAI([]byte(DefaultFetchAIPublicKey), DefaultAgentKey)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTClient:\", err)\n\t}\n\n\trecord := &acn.AgentRecord{LedgerId: DefaultLedger}\n\trecord.Address = DefaultAgentAddress\n\trecord.PublicKey = DefaultAgentPublicKey\n\trecord.PeerPublicKey = DefaultFetchAIPublicKey\n\trecord.Signature = signature\n\n\topts := []Option{\n\t\tIdentityFromFetchAIKey(DefaultFetchAIKey),\n\t\tRegisterAgentAddress(record, func() bool { return true }),\n\t\tBootstrapFrom([]string{dhtPeer.MultiAddr()}),\n\t}\n\n\tt.Log(dhtPeer.MultiAddr())\n\n\tdhtClient, err := New(opts...)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTClient:\", err)\n\t}\n\tdefer dhtClient.Close()\n\n\trxEnvelopesClient := make(chan *aea.Envelope, 2)\n\tdhtClient.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxEnvelopesClient <- envel\n\t\treturn nil\n\t})\n\n\tif len(rxEnvelopesPeer) != 0 {\n\t\tt.Error(\"DHTPeer agent inbox should be empty\")\n\t}\n\n\terr = dhtClient.RouteEnvelope(&aea.Envelope{\n\t\tTo:     dhttests.DHTPeerDefaultAgentAddress,\n\t\tSender: DefaultAgentAddress,\n\t})\n\tif err != nil {\n\t\tt.Error(\"Failed to Route envelope to DHTPeer agent:\", err)\n\t}\n\n\ttimeout := time.After(EnvelopeDeliveryTimeout)\n\tselect {\n\tcase envel := <-rxEnvelopesPeer:\n\t\tt.Log(\"DHT received envelope\", envel)\n\tcase <-timeout:\n\t\tt.Error(\"Failed to Route envelope to DHTPeer agent\")\n\t}\n\n}\n"
  },
  {
    "path": "libs/go/libp2p_node/dht/dhtclient/options.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2019 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\n\npackage dhtclient\n\nimport (\n\tacn \"libp2p_node/acn\"\n\t\"libp2p_node/utils\"\n)\n\n// Option for dhtclient.New\ntype Option func(*DHTClient) error\n\n// IdentityFromFetchAIKey for dhtclient.New\nfunc IdentityFromFetchAIKey(key string) Option {\n\treturn func(dhtClient *DHTClient) error {\n\t\tvar err error\n\t\tdhtClient.key, dhtClient.publicKey, err = utils.KeyPairFromFetchAIKey(key)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t}\n}\n\n// RegisterAgentAddress for dhtclient.New\nfunc RegisterAgentAddress(record *acn.AgentRecord, isReady func() bool) Option {\n\treturn func(dhtClient *DHTClient) error {\n\t\tpbRecord := &acn.AgentRecord{}\n\t\tpbRecord.Address = record.Address\n\t\tpbRecord.PublicKey = record.PublicKey\n\t\tpbRecord.PeerPublicKey = record.PeerPublicKey\n\t\tpbRecord.Signature = record.Signature\n\t\tpbRecord.ServiceId = record.ServiceId\n\t\tpbRecord.LedgerId = record.LedgerId\n\n\t\tdhtClient.myAgentAddress = record.Address\n\t\tdhtClient.myAgentRecord = pbRecord\n\t\tdhtClient.myAgentReady = isReady\n\t\treturn nil\n\t}\n}\n\n// BootstrapFrom for dhtclient.New\nfunc BootstrapFrom(entryPeers []string) Option {\n\treturn func(dhtClient *DHTClient) error {\n\t\tvar err error\n\t\tdhtClient.bootstrapPeers, err = utils.GetPeersAddrInfo(entryPeers)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t}\n}\n"
  },
  {
    "path": "libs/go/libp2p_node/dht/dhtnode/dhtnode.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2019 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\n\n// Package dhtnode (in progress) contains the common interface between dhtpeer and dhtclient\npackage dhtnode\n\nimport \"libp2p_node/aea\"\n\n// DHTNode libp2p node interface\ntype DHTNode interface {\n\tRouteEnvelope(*aea.Envelope) error\n\tProcessEnvelope(func(*aea.Envelope) error)\n\tMultiAddr() string\n\tPeerID() string\n\tClose() []error\n}\n"
  },
  {
    "path": "libs/go/libp2p_node/dht/dhtnode/streams.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2019 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\n\npackage dhtnode\n\nconst (\n\tAeaNotifStream         = \"/aea-notif/0.1.0\"\n\tAeaAddressStream       = \"/aea-address/0.1.0\"\n\tAeaEnvelopeStream      = \"/aea/0.1.0\"\n\tAeaRegisterRelayStream = \"/aea-register/0.1.0\"\n)\n"
  },
  {
    "path": "libs/go/libp2p_node/dht/dhtnode/utils.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2019 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\n\n// Package dhtnode contains the common interface between dhtpeer and dhtclient\n// TODO: extraction of shared functionality is work in progress\npackage dhtnode\n\nimport (\n\t\"errors\"\n\t\"strings\"\n\n\tacn \"libp2p_node/acn\"\n\tutils \"libp2p_node/utils\"\n)\n\nconst (\n\tDefaultLedger  = \"fetchai\"\n\tCurrentVersion = \"0.1.0\"\n)\n\nvar supportedLedgers = []string{\"fetchai\", \"cosmos\", \"ethereum\"}\n\nfunc IsValidProofOfRepresentation(\n\trecord *acn.AgentRecord,\n\tagentAddress string,\n\trepresentativePeerPubKey string,\n) (*acn.StatusBody, error) {\n\t// check agent address matches\n\tif record.Address != agentAddress {\n\t\terr := errors.New(\"Wrong agent address, expected \" + agentAddress)\n\t\tresponse := &acn.StatusBody{\n\t\t\tCode: acn.ERROR_WRONG_AGENT_ADDRESS,\n\t\t\tMsgs: []string{err.Error()},\n\t\t}\n\t\treturn response, err\n\t}\n\n\t// check if ledger is supported\n\tvar found = false\n\tfor _, supported := range supportedLedgers {\n\t\tif record.LedgerId == supported {\n\t\t\tfound = true\n\t\t\tbreak\n\t\t}\n\t}\n\tif !found {\n\t\terr := errors.New(\n\t\t\t\"Unsupported ledger \" + record.LedgerId + \", expected \" + strings.Join(\n\t\t\t\tsupportedLedgers,\n\t\t\t\t\",\",\n\t\t\t),\n\t\t)\n\t\tresponse := &acn.StatusBody{Code: acn.ERROR_UNSUPPORTED_LEDGER, Msgs: []string{err.Error()}}\n\t\treturn response, err\n\t}\n\n\t// check public key matches\n\tif record.PeerPublicKey != representativePeerPubKey {\n\t\terr := errors.New(\"Wrong peer public key, expected \" + representativePeerPubKey)\n\t\tresponse := &acn.StatusBody{Code: acn.ERROR_WRONG_PUBLIC_KEY, Msgs: []string{err.Error()}}\n\t\treturn response, err\n\t}\n\n\t// check that agent address and public key match\n\taddrFromPubKey, err := utils.AgentAddressFromPublicKey(record.LedgerId, record.PublicKey)\n\tif err != nil || addrFromPubKey != record.Address {\n\t\tif err == nil {\n\t\t\terr = errors.New(\"agent address and public key don't match\")\n\t\t}\n\t\tresponse := &acn.StatusBody{Code: acn.ERROR_WRONG_AGENT_ADDRESS}\n\t\treturn response, err\n\t}\n\n\t// check that signature is valid\n\tok, err := utils.VerifyLedgerSignature(\n\t\trecord.LedgerId,\n\t\t[]byte(record.PeerPublicKey),\n\t\trecord.Signature,\n\t\trecord.PublicKey,\n\t)\n\tif !ok || err != nil {\n\t\tif err == nil {\n\t\t\terr = errors.New(\"signature is not valid\")\n\t\t}\n\t\tresponse := &acn.StatusBody{Code: acn.ERROR_INVALID_PROOF}\n\t\treturn response, err\n\n\t}\n\n\t// PoR is valid\n\tresponse := &acn.StatusBody{Code: acn.SUCCESS}\n\treturn response, nil\n\n}\n"
  },
  {
    "path": "libs/go/libp2p_node/dht/dhtpeer/benchmarks_test.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2019 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\n\npackage dhtpeer\n\nimport (\n\t\"bufio\"\n\t\"context\"\n\t\"flag\"\n\t\"net\"\n\t\"os\"\n\t\"testing\"\n\t\"time\"\n\n\t\"libp2p_node/acn\"\n\t\"libp2p_node/aea\"\n\t\"libp2p_node/utils\"\n\n\t\"github.com/rs/zerolog\"\n)\n\n/* **********\n* How to run\n* ***********\n\n\t$ go test -p 1 -count 20 libp2p_node/dht/dhtpeer/ -run=XXX  -bench .  -benchtime=20x -peers-keys-file=/path/to/file/benchmark_peers_keys.txt -agents-keys-file=/path/to/file/benchmark_agents_keys.txt\n\n*/\n\nvar peersKeysFilePath string\nvar agentsKeysFilePath string\nvar tcpUri = \"localhost:12345\"\n\nfunc init() {\n\tflag.StringVar(&peersKeysFilePath, \"peers-keys-file\", \"\", \"File with list of EC private keys\")\n\tflag.StringVar(\n\t\t&agentsKeysFilePath,\n\t\t\"agents-keys-file\",\n\t\t\"\",\n\t\t\"File with list of agents EC private keys\",\n\t)\n}\n\n/* **********************************\n * baseline TCP connection benchmark\n * ********************************** */\n\n// helpers\n\nfunc acceptAndEcho(server net.Listener) {\n\tfor {\n\t\tconn, err := server.Accept()\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\t\tgo func() {\n\t\t\tfor {\n\t\t\t\tbuf, err := utils.ReadBytesConn(conn)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\terr = utils.WriteBytesConn(conn, buf)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t}\n\t\t}()\n\t}\n}\n\nfunc connect(uri string, b *testing.B) net.Conn {\n\tconn, err := net.Dial(\"tcp\", uri)\n\tif err != nil {\n\t\tb.Fatal(err.Error())\n\t}\n\treturn conn\n\n}\nfunc sendAndReceive(conn net.Conn, buf []byte, b *testing.B) {\n\terr := utils.WriteBytesConn(conn, buf)\n\tif err != nil {\n\t\tb.Fatal(err.Error())\n\t}\n\t_, err = utils.ReadBytesConn(conn)\n\tif err != nil {\n\t\tb.Fatal(err.Error())\n\t}\n}\n\nfunc connectAndSend(buf []byte, b *testing.B) {\n\tconn := connect(tcpUri, b)\n\tsendAndReceive(conn, buf, b)\n\tconn.Close()\n}\n\n// benchs\n\nfunc BenchmarkBaselineTCPEcho(b *testing.B) {\n\n\ttcpServer, err := net.Listen(\"tcp\", tcpUri)\n\tif err != nil {\n\t\tb.Fatal(err.Error())\n\t}\n\tgo acceptAndEcho(tcpServer)\n\tbuf := make([]byte, 200)\n\tconn := connect(tcpUri, b)\n\n\tfor i := 0; i < b.N; i++ {\n\t\tsendAndReceive(conn, buf, b)\n\t}\n\tb.StopTimer()\n\ttcpServer.Close()\n\tb.StartTimer()\n\n}\n\nfunc BenchmarkBaselineTCPConnectAndEcho(b *testing.B) {\n\n\ttcpServer, err := net.Listen(\"tcp\", tcpUri)\n\tif err != nil {\n\t\tb.Fatal(err.Error())\n\t}\n\tgo acceptAndEcho(tcpServer)\n\tbuf := make([]byte, 200)\n\n\tfor i := 0; i < b.N; i++ {\n\t\t//var elapsed time.Duration\n\t\t//start := time.Now()\n\t\tb.ResetTimer()\n\t\tconnectAndSend(buf, b)\n\t\tb.StopTimer()\n\t\t//elapsed = time.Since(start)\n\t\t//fmt.Println(\"Elapsed \", elapsed.String())\n\t\tb.StartTimer()\n\t}\n\tb.StopTimer()\n\ttcpServer.Close()\n\tb.StartTimer()\n\n}\n\n/* **********************************\n * Peer DHT operations benchmark\n * ********************************** */\n\n// helpers\n\nfunc getKeysAndAddrs(b *testing.B) (peers []string, agents []string) {\n\tpeersKeysFile, err := os.Open(peersKeysFilePath)\n\tif err != nil {\n\t\tb.Fatal(err)\n\t}\n\tdefer peersKeysFile.Close()\n\tagentsKeysFile, err := os.Open(agentsKeysFilePath)\n\tif err != nil {\n\t\tb.Fatal(err)\n\t}\n\tdefer agentsKeysFile.Close()\n\n\tksc := bufio.NewScanner(peersKeysFile)\n\tasc := bufio.NewScanner(agentsKeysFile)\n\n\tpeers = []string{}\n\tagents = []string{}\n\tfor ksc.Scan() && asc.Scan() {\n\t\tpeers = append(peers, ksc.Text())\n\t\tagents = append(agents, asc.Text())\n\t}\n\treturn peers, agents\n}\n\nfunc setupLocalDHTPeerForBench(\n\tkey string,\n\tagentKey string,\n\tdhtPort uint16,\n\tdelegatePort uint16,\n\tentry []string,\n) (*DHTPeer, func(), error) {\n\t/*\n\t\tpeer, peerCleanup, err := SetupLocalDHTPeer(key, addr, dhtPort, delegatePort, entry)\n\t\tif err == nil {\n\t\t\tpeer.SetLogLevel(zerolog.Disabled)\n\t\t\tutils.SetLoggerLevel(zerolog.Disabled)\n\t\t}\n\t\treturn peer, peerCleanup, err\n\t*/\n\n\topts := []Option{\n\t\tLocalURI(DefaultLocalHost, dhtPort),\n\t\tPublicURI(DefaultLocalHost, dhtPort),\n\t\tIdentityFromFetchAIKey(key),\n\t\tEnableRelayService(),\n\t\tBootstrapFrom(entry),\n\t}\n\n\tif agentKey != \"\" {\n\t\tagentPubKey, err := utils.FetchAIPublicKeyFromFetchAIPrivateKey(agentKey)\n\t\tif err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\n\t\tagentAddress, err := utils.FetchAIAddressFromPublicKey(agentPubKey)\n\t\tif err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\n\t\tpeerPubKey, err := utils.FetchAIPublicKeyFromFetchAIPrivateKey(key)\n\t\tif err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\n\t\tsignature, err := utils.SignFetchAI([]byte(peerPubKey), agentKey)\n\t\tif err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\n\t\trecord := &acn.AgentRecord{}\n\t\trecord.Address = agentAddress\n\t\trecord.PublicKey = agentPubKey\n\t\trecord.PeerPublicKey = peerPubKey\n\t\trecord.Signature = signature\n\n\t\topts = append(opts, RegisterAgentAddress(record, func() bool { return true }))\n\t}\n\n\tif delegatePort != 0 {\n\t\topts = append(opts, EnableDelegateService(delegatePort))\n\t}\n\n\tdhtPeer, err := New(opts...)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tutils.SetLoggerLevel(zerolog.Disabled)\n\n\treturn dhtPeer, func() { dhtPeer.Close() }, nil\n}\n\nfunc deployPeers(number uint16, b *testing.B) ([]*DHTPeer, []string) {\n\tpeerKeys, agentsKeys := getKeysAndAddrs(b)\n\tpeers := make([]*DHTPeer, 0, number)\n\tfor i := uint16(0); i < number; i++ {\n\t\tentry := []string{}\n\t\tif i > 0 {\n\t\t\tentry = append(entry, peers[i-1].MultiAddr())\n\t\t}\n\t\tpeer, _, err := setupLocalDHTPeerForBench(\n\t\t\tpeerKeys[i], agentsKeys[i], DefaultLocalPort+i, 0,\n\t\t\tentry,\n\t\t)\n\t\tif err != nil {\n\t\t\tb.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t\t}\n\t\tpeers = append(peers, peer)\n\t}\n\treturn peers, agentsKeys\n}\n\nfunc closePeers(peers ...*DHTPeer) {\n\tfor _, peer := range peers {\n\t\tpeer.Close()\n\t}\n}\n\nfunc setupEchoServicePeers(peers ...*DHTPeer) {\n\tfor _, peer := range peers {\n\t\tpeer.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\t\terr := peer.RouteEnvelope(&aea.Envelope{\n\t\t\t\tTo:     envel.Sender,\n\t\t\t\tSender: envel.To,\n\t\t\t})\n\t\t\treturn err\n\t\t})\n\t}\n}\n\n// benchs\n\nfunc benchmarkAgentRegistration(npeers uint16, b *testing.B) {\n\tpeers, addrs := deployPeers(npeers, b)\n\tensureAddressAnnounced(peers...)\n\tdefer closePeers(peers...)\n\n\tpeer, peerCleanup, err := setupLocalDHTPeerForBench(\n\t\tFetchAITestKeys[1], \"\", DefaultLocalPort+npeers+1, 0,\n\t\t[]string{peers[0].MultiAddr()},\n\t)\n\tif err != nil {\n\t\tb.Fatal(err.Error())\n\t}\n\tdefer peerCleanup()\n\n\tfor i := 0; i < b.N; i++ {\n\t\tb.ResetTimer()\n\t\terr = peer.RegisterAgentAddress(addrs[len(addrs)-1-i%len(addrs)])\n\t\tif err != nil {\n\t\t\tb.Fail()\n\t\t}\n\t}\n}\n\nfunc benchmarkAgentLookup(npeers uint16, b *testing.B) {\n\tpeers, addrs := deployPeers(npeers, b)\n\tensureAddressAnnounced(peers...)\n\tdefer closePeers(peers...)\n\n\tpeer, peerCleanup, err := setupLocalDHTPeerForBench(\n\t\tFetchAITestKeys[1], AgentsTestKeys[1], DefaultLocalPort+npeers+1, 0,\n\t\t[]string{peers[len(peers)-1].MultiAddr()},\n\t)\n\tif err != nil {\n\t\tb.Fatal(err.Error())\n\t}\n\tdefer peerCleanup()\n\tensureAddressAnnounced(peer)\n\tctx, cancel_lookup := context.WithTimeout(context.Background(), 30*time.Second)\n\tdefer cancel_lookup()\n\n\tfor i := 0; i < b.N; i++ {\n\t\tb.ResetTimer()\n\t\t_, _, err = peer.lookupAddressDHT(ctx, addrs[len(peers)-1-i%len(peers)])\n\t\tif err != nil {\n\t\t\tb.Fail()\n\t\t}\n\t}\n}\n\nfunc benchmarkPeerJoin(npeers uint16, b *testing.B) {\n\tpeers, _ := deployPeers(npeers, b)\n\tensureAddressAnnounced(peers...)\n\tdefer closePeers(peers...)\n\n\tfor i := 0; i < b.N; i++ {\n\t\tb.ResetTimer()\n\t\tpeer, peerCleanup, err := setupLocalDHTPeerForBench(\n\t\t\tFetchAITestKeys[1], AgentsTestKeys[1], DefaultLocalPort+npeers+1, 0,\n\t\t\t[]string{peers[i%len(peers)].MultiAddr()},\n\t\t)\n\t\tif err != nil {\n\t\t\tb.Fatal(err.Error())\n\t\t}\n\t\tensureAddressAnnounced(peer)\n\t\tb.StopTimer()\n\t\tpeerCleanup()\n\t\tb.StartTimer()\n\t}\n}\n\nfunc benchmarkPeerEcho(npeers uint16, b *testing.B) {\n\tpeers, addrs := deployPeers(npeers, b)\n\tensureAddressAnnounced(peers...)\n\tdefer closePeers(peers...)\n\tsetupEchoServicePeers(peers...)\n\n\tpeer, peerCleanup, err := setupLocalDHTPeerForBench(\n\t\tFetchAITestKeys[1], AgentsTestKeys[1], DefaultLocalPort+npeers+1, 0,\n\t\t[]string{peers[len(peers)-1].MultiAddr()},\n\t)\n\tif err != nil {\n\t\tb.Fatal(err.Error())\n\t}\n\tdefer peerCleanup()\n\tensureAddressAnnounced(peer)\n\trxPeer := make(chan *aea.Envelope, 10)\n\tpeer.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxPeer <- envel\n\t\treturn nil\n\t})\n\n\tfor i := 0; i < b.N; i++ {\n\t\tenvel := &aea.Envelope{\n\t\t\tTo:      addrs[len(peers)-1-i%len(peers)],\n\t\t\tSender:  AgentsTestAddresses[1],\n\t\t\tMessage: make([]byte, 101),\n\t\t}\n\t\tb.ResetTimer()\n\t\terr = peer.RouteEnvelope(envel)\n\t\tif err != nil {\n\t\t\tb.Error(\"Failed to RouteEnvelope from peer 2 to peer 1:\", err)\n\t\t}\n\t\t<-rxPeer\n\t}\n}\n\nfunc BenchmarkAgentRegistration2(b *testing.B)   { benchmarkAgentRegistration(2, b) }\nfunc BenchmarkAgentRegistration8(b *testing.B)   { benchmarkAgentRegistration(8, b) }\nfunc BenchmarkAgentRegistration32(b *testing.B)  { benchmarkAgentRegistration(32, b) }\nfunc BenchmarkAgentRegistration128(b *testing.B) { benchmarkAgentRegistration(128, b) }\nfunc BenchmarkAgentRegistration256(b *testing.B) { benchmarkAgentRegistration(256, b) }\n\nfunc BenchmarkAgentLookup2(b *testing.B)   { benchmarkAgentLookup(2, b) }\nfunc BenchmarkAgentLookup8(b *testing.B)   { benchmarkAgentLookup(8, b) }\nfunc BenchmarkAgentLookup32(b *testing.B)  { benchmarkAgentLookup(32, b) }\nfunc BenchmarkAgentLookup128(b *testing.B) { benchmarkAgentLookup(128, b) }\nfunc BenchmarkAgentLookup256(b *testing.B) { benchmarkAgentLookup(256, b) }\n\nfunc BenchmarkPeerJoin2(b *testing.B)   { benchmarkPeerJoin(2, b) }\nfunc BenchmarkPeerJoin8(b *testing.B)   { benchmarkPeerJoin(8, b) }\nfunc BenchmarkPeerJoin32(b *testing.B)  { benchmarkPeerJoin(32, b) }\nfunc BenchmarkPeerJoin128(b *testing.B) { benchmarkPeerJoin(128, b) }\nfunc BenchmarkPeerJoin256(b *testing.B) { benchmarkPeerJoin(256, b) }\n\nfunc BenchmarkPeerEcho2(b *testing.B)   { benchmarkPeerEcho(2, b) }\nfunc BenchmarkPeerEcho8(b *testing.B)   { benchmarkPeerEcho(8, b) }\nfunc BenchmarkPeerEcho32(b *testing.B)  { benchmarkPeerEcho(32, b) }\nfunc BenchmarkPeerEcho128(b *testing.B) { benchmarkPeerEcho(128, b) }\nfunc BenchmarkPeerEcho256(b *testing.B) { benchmarkPeerEcho(256, b) }\n"
  },
  {
    "path": "libs/go/libp2p_node/dht/dhtpeer/dhtpeer.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2019 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\n\n// Package dhtpeer provides an implementation of an Agent Communication Network node\n// using libp2p. It participates in data storage and routing for the network.\n// It offers RelayService for dhtclient and DelegateService for tcp clients.\npackage dhtpeer\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"context\"\n\t\"crypto/ecdsa\"\n\t\"crypto/elliptic\"\n\t\"crypto/rand\"\n\t\"crypto/tls\"\n\t\"crypto/x509\"\n\t\"crypto/x509/pkix\"\n\t\"encoding/binary\"\n\t\"encoding/pem\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"math/big\"\n\t\"net\"\n\t\"os\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/btcsuite/btcd/btcec\"\n\t\"github.com/pkg/errors\"\n\n\t\"github.com/rs/zerolog\"\n\t\"google.golang.org/protobuf/proto\"\n\n\tlibp2p \"github.com/libp2p/go-libp2p\"\n\tcryptop2p \"github.com/libp2p/go-libp2p-core/crypto\"\n\t\"github.com/libp2p/go-libp2p-core/network\"\n\t\"github.com/libp2p/go-libp2p-core/peer\"\n\t\"github.com/libp2p/go-libp2p-core/peerstore\"\n\t\"github.com/multiformats/go-multiaddr\"\n\n\tcircuit \"github.com/libp2p/go-libp2p-circuit\"\n\tkaddht \"github.com/libp2p/go-libp2p-kad-dht\"\n\troutedhost \"github.com/libp2p/go-libp2p/p2p/host/routed\"\n\n\tacn \"libp2p_node/acn\"\n\taea \"libp2p_node/aea\"\n\tcommon \"libp2p_node/dht/common\"\n\t\"libp2p_node/dht/dhtnode\"\n\tmonitoring \"libp2p_node/dht/monitoring\"\n\tutils \"libp2p_node/utils\"\n)\n\nconst AcnStatusTimeout = 5.0 * time.Second\nconst AcnStatusesQueueSize = 1000\nconst SlowQueueSize = 100\n\n// panics if err is not nil\nfunc check(err error) {\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\nfunc ignore(err error) {\n\tif err != nil {\n\t\tlog.Println(\"IGNORED\", err)\n\t}\n}\n\nconst (\n\taddressLookupTimeout                 = 20 * time.Second\n\ttimeoutBeforeMovingToSlowQueue       = 3 * time.Second\n\troutingTableConnectionUpdateTimeout  = 5 * time.Second\n\tnewStreamTimeout                     = 10 * time.Second\n\taddressRegisterTimeout               = 3 * time.Second\n\taddressRegistrationDelay             = 0 * time.Second\n\tmonitoringNamespace                  = \"acn\"\n\tmetricDHTOpLatencyStore              = \"dht_op_latency_store\"\n\tmetricDHTOpLatencyLookup             = \"dht_op_latency_lookup\"\n\tmetricOpLatencyRegister              = \"op_latency_register\"\n\tmetricOpLatencyRoute                 = \"op_latency_route\"\n\tmetricOpRouteCount                   = \"op_route_count\"\n\tmetricOpRouteCountAll                = \"op_route_count_all\"\n\tmetricOpRouteCountSuccess            = \"op_route_count_success\"\n\tmetricServiceDelegateClientsCount    = \"service_delegate_clients_count\"\n\tmetricServiceDelegateClientsCountAll = \"service_delegate_clients_count_all\"\n\tmetricServiceRelayClientsCount       = \"service_relay_clients_count\"\n\tmetricServiceRelayClientsCountAll    = \"service_relay_clients_count_all\"\n\tdefaultPersistentStoragePath         = \"./agent_records_store\"\n)\n\nvar (\n\t//latencyBucketsMilliSeconds = []float64{1., 10., 20., 50., 100., 200., 500., 1000.}\n\tlatencyBucketsMicroSeconds = []float64{100., 500., 1e3, 1e4, 1e5, 5e5, 1e6}\n)\n\n// DHTPeer A full libp2p node for the Agents Communication Network.\n// It is required to have a local address and a public one\n// and can acts as a relay for `DHTClient`.\n// Optionally, it provides delegate service for tcp clients.\ntype DHTPeer struct {\n\thost           string\n\tport           uint16\n\tpublicHost     string\n\tpublicPort     uint16\n\tdelegatePort   uint16\n\tmonitoringPort uint16\n\tenableRelay    bool\n\n\tmailboxHostPort string\n\tmailboxServer   *MailboxServer\n\n\tregistrationDelay time.Duration\n\n\tkey             cryptop2p.PrivKey\n\tpublicKey       cryptop2p.PubKey\n\tlocalMultiaddr  multiaddr.Multiaddr\n\tpublicMultiaddr multiaddr.Multiaddr\n\tbootstrapPeers  []peer.AddrInfo\n\n\tdht          *kaddht.IpfsDHT\n\troutedHost   *routedhost.RoutedHost\n\ttcpListener  net.Listener\n\tcert         *tls.Certificate\n\tsslSignature []byte\n\n\taddressAnnouncedMap     map[string]bool\n\taddressAnnouncedMapLock sync.RWMutex\n\n\t// flag to announce addresses over network if peer connected to other peers\n\tenableAddressAnnouncement     bool\n\tenableAddressAnnouncementWg   *sync.WaitGroup\n\tenableAddressAnnouncementLock sync.RWMutex\n\n\tmyAgentAddress   string\n\tmyAgentRecord    *acn.AgentRecord\n\tmyAgentReady     func() bool\n\tdhtAddresses     map[string]string\n\tacnStatuses      map[string]chan *acn.StatusBody\n\ttcpAddresses     map[string]net.Conn\n\tagentRecords     map[string]*acn.AgentRecord\n\tacnStatusesLock  sync.RWMutex\n\tdhtAddressesLock sync.RWMutex\n\ttcpAddressesLock sync.RWMutex\n\tagentRecordsLock sync.RWMutex\n\n\t// TOFIX(LR): maps and locks need refactoring for better abstraction\n\tprocessEnvelope func(*aea.Envelope) error\n\n\tpersistentStoragePath string\n\tstorage               *os.File\n\n\tmonitor    monitoring.MonitoringService\n\tclosing    chan struct{}\n\tisClosing  bool\n\tgoroutines *sync.WaitGroup\n\tlogger     zerolog.Logger\n\n\t// syncMessages map[string]*sync.WaitGroup\n\tsyncMessagesLock sync.RWMutex\n\tsyncMessages     map[string](chan *aea.Envelope)\n\n\tslow_queue chan *aea.Envelope\n}\n\n// New creates a new DHTPeer\nfunc New(opts ...Option) (*DHTPeer, error) {\n\tvar err error\n\tdhtPeer := &DHTPeer{registrationDelay: addressRegistrationDelay, isClosing: false}\n\n\tdhtPeer.dhtAddresses = map[string]string{}\n\tdhtPeer.tcpAddresses = map[string]net.Conn{}\n\tdhtPeer.agentRecords = map[string]*acn.AgentRecord{}\n\tdhtPeer.acnStatuses = map[string]chan *acn.StatusBody{}\n\tdhtPeer.dhtAddressesLock = sync.RWMutex{}\n\tdhtPeer.tcpAddressesLock = sync.RWMutex{}\n\tdhtPeer.agentRecordsLock = sync.RWMutex{}\n\tdhtPeer.persistentStoragePath = defaultPersistentStoragePath\n\tdhtPeer.syncMessages = make(map[string](chan *aea.Envelope))\n\tdhtPeer.addressAnnouncedMap = map[string]bool{}\n\tdhtPeer.addressAnnouncedMapLock = sync.RWMutex{}\n\tdhtPeer.enableAddressAnnouncementWg = &sync.WaitGroup{}\n\tdhtPeer.enableAddressAnnouncementLock = sync.RWMutex{}\n\tdhtPeer.mailboxHostPort = \"\"\n\n\tdhtPeer.slow_queue = make(chan *aea.Envelope, SlowQueueSize)\n\n\tfor _, opt := range opts {\n\t\tif err := opt(dhtPeer); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\tdhtPeer.closing = make(chan struct{})\n\tdhtPeer.goroutines = &sync.WaitGroup{}\n\n\t/* check correct configuration */\n\n\t// private key\n\tif dhtPeer.key == nil {\n\t\treturn nil, errors.New(\"private key must be provided\")\n\t}\n\n\t// local uri\n\tif dhtPeer.localMultiaddr == nil {\n\t\treturn nil, errors.New(\"local host and port must be set\")\n\t}\n\n\t// public uri\n\tif dhtPeer.publicMultiaddr == nil {\n\t\treturn nil, errors.New(\"public host and port must be set\")\n\t}\n\n\t// check if the PoR is delivered for my public  key\n\tif dhtPeer.myAgentRecord != nil {\n\t\tmyPublicKey, err := utils.FetchAIPublicKeyFromPubKey(dhtPeer.publicKey)\n\t\tstatus, errPoR := dhtnode.IsValidProofOfRepresentation(\n\t\t\tdhtPeer.myAgentRecord, dhtPeer.myAgentRecord.Address, myPublicKey,\n\t\t)\n\t\tif err != nil || errPoR != nil || status.Code != acn.SUCCESS {\n\t\t\terrMsg := \"Invalid AgentRecord\"\n\t\t\tif err == nil {\n\t\t\t\terr = errors.New(errMsg)\n\t\t\t} else {\n\t\t\t\terr = errors.Wrap(err, errMsg)\n\t\t\t}\n\t\t\tif errPoR != nil {\n\t\t\t\terr = errors.Wrap(err, errPoR.Error())\n\t\t\t}\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\t/* setup libp2p node */\n\tctx := context.Background()\n\n\t// setup public uri as external address\n\taddressFactory := func(addrs []multiaddr.Multiaddr) []multiaddr.Multiaddr {\n\t\treturn []multiaddr.Multiaddr{dhtPeer.publicMultiaddr}\n\t}\n\n\t// libp2p options\n\tlibp2pOpts := []libp2p.Option{\n\t\tlibp2p.ListenAddrs(dhtPeer.localMultiaddr),\n\t\tlibp2p.AddrsFactory(addressFactory),\n\t\tlibp2p.Identity(dhtPeer.key),\n\t\tlibp2p.DefaultTransports,\n\t\tlibp2p.DefaultMuxers,\n\t\tlibp2p.DefaultSecurity,\n\t\tlibp2p.NATPortMap(),\n\t\tlibp2p.EnableNATService(),\n\t\tlibp2p.EnableRelay(circuit.OptHop),\n\t}\n\n\t// create a basic host\n\tbasicHost, err := libp2p.New(ctx, libp2pOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// create the dht\n\tdhtPeer.dht, err = kaddht.New(ctx, basicHost, kaddht.Mode(kaddht.ModeServer))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\terr = dhtPeer.makeSSLCertifiateAndSignature()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t// make the routed host\n\tdhtPeer.routedHost = routedhost.Wrap(basicHost, dhtPeer.dht)\n\tdhtPeer.setupLogger()\n\n\tlerror, _, linfo, ldebug := dhtPeer.GetLoggers()\n\n\tbasicHost.Network().Notify(&Notifee{\n\t\tlogger: dhtPeer.logger,\n\t})\n\n\t// connect to the booststrap nodes\n\tif len(dhtPeer.bootstrapPeers) > 0 {\n\t\tlinfo().Msgf(\"Bootstrapping from %s\", dhtPeer.bootstrapPeers)\n\t\terr = utils.BootstrapConnect(ctx, dhtPeer.routedHost, dhtPeer.dht, dhtPeer.bootstrapPeers)\n\t\tif err != nil {\n\t\t\tdhtPeer.Close()\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\t// bootstrap the dht\n\terr = dhtPeer.dht.Bootstrap(ctx)\n\tif err != nil {\n\t\tdhtPeer.Close()\n\t\treturn nil, err\n\t}\n\n\tlinfo().Msgf(\"My Peer ID is %s\", dhtPeer.PeerID())\n\n\tlinfo().Msg(\"successfully created libp2p node!\")\n\n\t/* setup DHTPeer message handlers and services */\n\n\t// setup monitoring\n\tdhtPeer.setupMonitoring()\n\n\t// relay service\n\tif dhtPeer.enableRelay {\n\t\t// Allow clients to register their agents addresses\n\t\tldebug().Msg(\"Setting /aea-register/0.1.0 stream...\")\n\t\tdhtPeer.routedHost.SetStreamHandler(dhtnode.AeaRegisterRelayStream,\n\t\t\tdhtPeer.handleAeaRegisterStream)\n\t}\n\n\t// new peers connection notification, so that this peer can register its addresses\n\tdhtPeer.routedHost.SetStreamHandler(dhtnode.AeaNotifStream,\n\t\tdhtPeer.handleAeaNotifStream)\n\n\t// Notify bootstrap peers if any\n\tfor _, bPeer := range dhtPeer.bootstrapPeers {\n\t\tctx := context.Background()\n\t\ts, err := dhtPeer.routedHost.NewStream(ctx, bPeer.ID, dhtnode.AeaNotifStream)\n\t\tif err != nil {\n\t\t\tlerror(err).Msgf(\"failed to open stream to notify bootstrap peer %s\", bPeer.ID)\n\t\t\tdhtPeer.Close()\n\t\t\treturn nil, err\n\t\t}\n\t\t_, err = s.Write([]byte(dhtnode.AeaNotifStream))\n\t\tif err != nil {\n\t\t\tlerror(err).Msgf(\"failed to notify bootstrap peer %s\", bPeer.ID)\n\t\t\tdhtPeer.Close()\n\t\t\treturn nil, err\n\t\t}\n\t\ts.Close()\n\t}\n\n\t// initialize agents records persistent storage\n\tif dhtPeer.persistentStoragePath == defaultPersistentStoragePath {\n\t\tmyPeerID, err := peer.IDFromPublicKey(dhtPeer.publicKey)\n\t\tignore(err)\n\t\tdhtPeer.persistentStoragePath += \"_\" + myPeerID.Pretty()\n\t}\n\tnbr, err := dhtPeer.initAgentRecordPersistentStorage()\n\tif err != nil {\n\t\treturn nil, errors.Wrap(err, \"while initializing agent record storage\")\n\t}\n\tif len(dhtPeer.bootstrapPeers) > 0 {\n\t\tfor addr := range dhtPeer.dhtAddresses {\n\t\t\terr := dhtPeer.RegisterAgentAddress(addr)\n\t\t\tif err != nil {\n\t\t\t\tlerror(err).Str(\"addr\", addr).\n\t\t\t\t\tMsg(\"while announcing stored client address\")\n\t\t\t}\n\t\t}\n\t}\n\tlinfo().Msgf(\"successfully loaded %d agents\", nbr)\n\n\t// if peer is joining an existing network, announce my agent address if set\n\tif len(dhtPeer.bootstrapPeers) > 0 {\n\t\t// there are some bootstrap peers so we can announce addresses to them\n\t\tdhtPeer.enableAddressAnnouncement = true\n\n\t\tif dhtPeer.myAgentAddress != \"\" && !dhtPeer.IsAddressAnnounced(dhtPeer.myAgentAddress) {\n\t\t\tldebug().Msg(\"Address was announced on bootstrap peers\")\n\t\t\topLatencyRegister, _ := dhtPeer.monitor.GetHistogram(metricOpLatencyRegister)\n\t\t\ttimer := dhtPeer.monitor.Timer()\n\t\t\tstart := timer.NewTimer()\n\t\t\terr := dhtPeer.RegisterAgentAddress(dhtPeer.myAgentAddress)\n\t\t\tif err != nil {\n\t\t\t\tdhtPeer.Close()\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tduration := timer.GetTimer(start)\n\t\t\topLatencyRegister.Observe(float64(duration.Microseconds()))\n\t\t}\n\t}\n\n\t// aea addresses lookup\n\tldebug().Msg(\"Setting /aea-address/0.1.0 stream...\")\n\tdhtPeer.routedHost.SetStreamHandler(dhtnode.AeaAddressStream, dhtPeer.handleAeaAddressStream)\n\n\t// incoming envelopes stream\n\tldebug().Msg(\"Setting /aea/0.1.0 stream...\")\n\tdhtPeer.routedHost.SetStreamHandler(dhtnode.AeaEnvelopeStream, dhtPeer.handleAeaEnvelopeStream)\n\n\t// setup delegate service\n\tif dhtPeer.delegatePort != 0 {\n\t\tdhtPeer.launchDelegateService()\n\n\t\tready := &sync.WaitGroup{}\n\t\tdhtPeer.goroutines.Add(1)\n\t\tready.Add(1)\n\t\tgo dhtPeer.handleDelegateService(ready)\n\t\tready.Wait()\n\t}\n\n\t// check mailbox uri is set\n\tif len(dhtPeer.mailboxHostPort) != 0 {\n\t\tdhtPeer.launchMailboxService()\n\t}\n\n\t// start monitoring\n\tready := &sync.WaitGroup{}\n\tready.Add(1)\n\tgo dhtPeer.startMonitoring(ready)\n\tready.Wait()\n\tgo dhtPeer.slowEnvelopeSendLoop()\n\treturn dhtPeer, nil\n}\n\n// saveAgentRecordToPersistentStorage saves the agent record to persistent storage\nfunc (dhtPeer *DHTPeer) saveAgentRecordToPersistentStorage(record *acn.AgentRecord) error {\n\tmsg := formatPersistentStorageLine(record)\n\tif len(msg) == 0 {\n\t\treturn errors.New(\"while formating record \" + record.String())\n\t}\n\n\tsize := uint32(len(msg))\n\tbuf := make([]byte, 4)\n\tbinary.BigEndian.PutUint32(buf, size)\n\n\tbuf = append(buf, msg...)\n\t_, err := dhtPeer.storage.Write(buf)\n\tif err != nil {\n\t\treturn errors.Wrap(err, \"while writing record to persistent storage\")\n\t}\n\treturn nil\n}\n\nfunc parsePersistentStorageLine(line []byte) (*acn.AgentRecord, error) {\n\trecord := &acn.AgentRecord{}\n\terr := proto.Unmarshal(line, record)\n\treturn record, err\n}\n\nfunc formatPersistentStorageLine(record *acn.AgentRecord) []byte {\n\tmsg, err := proto.Marshal(record)\n\tignore(err)\n\treturn msg\n}\n\n// initAgentRecordPersistentStorage loads agent records from persistent storage\nfunc (dhtPeer *DHTPeer) initAgentRecordPersistentStorage() (int, error) {\n\tvar err error\n\t_, _, linfo, _ := dhtPeer.GetLoggers()\n\tlinfo().Msg(\"Load records from store \" + dhtPeer.persistentStoragePath)\n\tdhtPeer.storage, err = os.OpenFile(\n\t\tdhtPeer.persistentStoragePath,\n\t\tos.O_APPEND|os.O_RDWR|os.O_CREATE,\n\t\t0600,\n\t)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\treader := bufio.NewReader(dhtPeer.storage)\n\tvar counter int = 0\n\tfor {\n\t\tbuf := make([]byte, 4)\n\t\t_, err = io.ReadFull(reader, buf)\n\t\tif err == io.EOF {\n\t\t\tbreak\n\t\t}\n\t\tif err != nil {\n\t\t\treturn 0, errors.Wrap(err, \"while loading agent records\")\n\t\t}\n\n\t\tsize := binary.BigEndian.Uint32(buf)\n\t\tline := make([]byte, size)\n\t\t_, err = io.ReadFull(reader, line)\n\t\tif err != nil {\n\t\t\treturn 0, errors.Wrap(err, \"while loading agent records\")\n\t\t}\n\n\t\trecord, err := parsePersistentStorageLine(line)\n\t\tif err != nil {\n\t\t\treturn 0, errors.Wrap(err, \"while loading agent records\")\n\t\t}\n\t\tdhtPeer.agentRecords[record.Address] = record\n\t\trelayPeerID, err := utils.IDFromFetchAIPublicKey(record.PeerPublicKey)\n\t\tif err != nil {\n\t\t\treturn 0, errors.Wrap(err, \"While loading agent records\")\n\t\t}\n\t\tdhtPeer.dhtAddresses[record.Address] = relayPeerID.Pretty()\n\t\tcounter++\n\t}\n\n\treturn counter, nil\n}\n\nfunc (dhtPeer *DHTPeer) closeAgentRecordPersistentStorage() error {\n\tdhtPeer.agentRecordsLock.Lock()\n\terr := dhtPeer.storage.Close()\n\tdhtPeer.agentRecordsLock.Unlock()\n\treturn err\n}\n\nfunc (dhtPeer *DHTPeer) setupMonitoring() {\n\tif dhtPeer.monitoringPort != 0 {\n\t\tdhtPeer.monitor = monitoring.NewPrometheusMonitoring(\n\t\t\tmonitoringNamespace,\n\t\t\tdhtPeer.monitoringPort,\n\t\t)\n\t} else {\n\t\tdhtPeer.monitor = monitoring.NewFileMonitoring(monitoringNamespace, false)\n\t}\n\n\tdhtPeer.addMonitoringMetrics()\n}\n\nfunc (dhtPeer *DHTPeer) startMonitoring(ready *sync.WaitGroup) {\n\t_, _, linfo, _ := dhtPeer.GetLoggers()\n\tlinfo().Msg(\"Starting monitoring service: \" + dhtPeer.monitor.Info())\n\tgo dhtPeer.monitor.Start()\n\tready.Done()\n}\n\nfunc (dhtPeer *DHTPeer) addMonitoringMetrics() {\n\tbuckets := latencyBucketsMicroSeconds\n\tvar err error\n\t// acn primitives\n\t_, err = dhtPeer.monitor.NewHistogram(metricDHTOpLatencyStore,\n\t\t\"Histogram for time to store a key in the DHT\", buckets)\n\tignore(err)\n\t_, err = dhtPeer.monitor.NewHistogram(metricDHTOpLatencyLookup,\n\t\t\"Histogram for time to find a key in the DHT\", buckets)\n\tignore(err)\n\t// acn main service\n\t_, err = dhtPeer.monitor.NewHistogram(metricOpLatencyRegister,\n\t\t\"Histogram for end-to-end time to register an agent in the acn\", buckets)\n\tignore(err)\n\t_, err = dhtPeer.monitor.NewHistogram(\n\t\tmetricOpLatencyRoute,\n\t\t\"Histogram for end-to-end time to route an envelope to its destination, excluding time to send envelope itself\",\n\t\tbuckets,\n\t)\n\tignore(err)\n\t_, err = dhtPeer.monitor.NewGauge(metricOpRouteCount,\n\t\t\"Number of ongoing envelope routing requests\")\n\tignore(err)\n\t_, err = dhtPeer.monitor.NewCounter(metricOpRouteCountAll,\n\t\t\"Total number envelope routing requests, successful or not\")\n\tignore(err)\n\t_, err = dhtPeer.monitor.NewCounter(metricOpRouteCountSuccess,\n\t\t\"Total number envelope routed successfully\")\n\tignore(err)\n\t// acn delegate service\n\t_, err = dhtPeer.monitor.NewGauge(metricServiceDelegateClientsCount,\n\t\t\"Number of active delagate connections\")\n\tignore(err)\n\t_, err = dhtPeer.monitor.NewCounter(metricServiceDelegateClientsCountAll,\n\t\t\"Number of all delagate clients, connected or disconnected\")\n\tignore(err)\n\t// acn relay service\n\t_, err = dhtPeer.monitor.NewGauge(metricServiceRelayClientsCount,\n\t\t\"Number of active relay clients\")\n\tignore(err)\n\t_, err = dhtPeer.monitor.NewCounter(metricServiceRelayClientsCountAll,\n\t\t\"Total number of all relayed clients, connected or disconnected\")\n\tignore(err)\n}\n\nfunc (dhtPeer *DHTPeer) setupLogger() {\n\tfields := map[string]string{\n\t\t\"package\": \"DHTPeer\",\n\t}\n\tif dhtPeer.routedHost != nil {\n\t\tfields[\"peerid\"] = dhtPeer.routedHost.ID().Pretty()\n\t}\n\tdhtPeer.logger = utils.NewDefaultLoggerWithFields(fields)\n}\n\nfunc (dhtPeer *DHTPeer) PeerID() string {\n\treturn dhtPeer.routedHost.ID().Pretty()\n}\n\nfunc (dhtPeer *DHTPeer) GetLoggers() (func(error) *zerolog.Event, func() *zerolog.Event, func() *zerolog.Event, func() *zerolog.Event) {\n\tldebug := dhtPeer.logger.Debug\n\tlinfo := dhtPeer.logger.Info\n\tlwarn := dhtPeer.logger.Warn\n\tlerror := func(err error) *zerolog.Event {\n\t\tif err == nil {\n\t\t\treturn dhtPeer.logger.Error().Str(\"err\", \"nil\")\n\t\t}\n\t\treturn dhtPeer.logger.Error().Str(\"err\", err.Error())\n\t}\n\n\treturn lerror, lwarn, linfo, ldebug\n}\n\n// SetLogLevel set utils logger level\nfunc (dhtPeer *DHTPeer) SetLogLevel(lvl zerolog.Level) {\n\tdhtPeer.logger = dhtPeer.logger.Level(lvl)\n}\n\n// Close stops the DHTPeer\nfunc (dhtPeer *DHTPeer) Close() []error {\n\tvar err error\n\tvar status []error\n\n\t_, _, linfo, _ := dhtPeer.GetLoggers()\n\n\tlinfo().Msg(\"Stopping DHTPeer...\")\n\tclose(dhtPeer.closing)\n\tdhtPeer.isClosing = true\n\n\t//return status\n\n\terrappend := func(err error) {\n\t\tif err != nil {\n\t\t\tstatus = append(status, err)\n\t\t}\n\t}\n\n\tif dhtPeer.tcpListener != nil {\n\t\terr = dhtPeer.tcpListener.Close()\n\t\terrappend(err)\n\t\tdhtPeer.tcpAddressesLock.Lock()\n\t\tfor _, conn := range dhtPeer.tcpAddresses {\n\t\t\terr = conn.Close()\n\t\t\terrappend(err)\n\t\t}\n\t\tdhtPeer.tcpAddressesLock.Unlock()\n\t}\n\n\tif dhtPeer.mailboxServer != nil {\n\t\tdhtPeer.mailboxServer.stop()\n\t}\n\n\terr = dhtPeer.dht.Close()\n\terrappend(err)\n\terr = dhtPeer.routedHost.Close()\n\terrappend(err)\n\n\terr = dhtPeer.closeAgentRecordPersistentStorage()\n\terrappend(err)\n\n\t//linfo().Msg(\"Stopping DHTPeer: waiting for goroutines to cancel...\")\n\t// dhtPeer.goroutines.Wait()\n\tdhtPeer.syncMessagesLock.Lock()\n\tfor _, channel := range dhtPeer.syncMessages {\n\t\tclose(channel)\n\t}\n\tdhtPeer.syncMessagesLock.Unlock()\n\tclose(dhtPeer.slow_queue)\n\n\treturn status\n}\n\n// Generate selfsigned c509 certificate with temprorary key to be used with TLS server\n// We can not use peer private key cause it does not supported by golang TLS implementation\n// So we generate a new one and send session public key signature made with peer private key\n// snd client can validate it with peer public key/address\nfunc generate_x509_cert() (*tls.Certificate, error) {\n\tprivBtcKey, err := btcec.NewPrivateKey(elliptic.P256())\n\tif err != nil {\n\t\treturn nil, errors.Wrap(err, \"while creating new private key\")\n\t}\n\tprivKey := privBtcKey.ToECDSA()\n\tpubKey := &privKey.PublicKey\n\n\tca := &x509.Certificate{\n\t\tSerialNumber: big.NewInt(1),\n\t\tSubject: pkix.Name{\n\t\t\tOrganization: []string{\"Acn Node\"},\n\t\t},\n\t\tNotBefore: time.Now(),\n\t\tNotAfter:  time.Now().AddDate(1, 0, 0),\n\n\t\tKeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,\n\t\tExtKeyUsage: []x509.ExtKeyUsage{\n\t\t\tx509.ExtKeyUsageClientAuth,\n\t\t\tx509.ExtKeyUsageServerAuth,\n\t\t},\n\t\tBasicConstraintsValid: true,\n\t}\n\tca.IsCA = true\n\tca.KeyUsage |= x509.KeyUsageCertSign\n\n\tcertBytes, err := x509.CreateCertificate(rand.Reader, ca, ca, pubKey, privKey)\n\tif err != nil {\n\t\treturn nil, errors.Wrap(err, \"while creating ca\")\n\t}\n\tcertPEM := new(bytes.Buffer)\n\terr = pem.Encode(certPEM, &pem.Block{\n\t\tType:  \"CERTIFICATE\",\n\t\tBytes: certBytes,\n\t})\n\tif err != nil {\n\t\treturn nil, errors.Wrap(err, \"while encoding cert pem\")\n\t}\n\n\tprivPEM := new(bytes.Buffer)\n\tb, err := x509.MarshalECPrivateKey(privKey)\n\tif err != nil {\n\t\treturn nil, errors.Wrap(err, \"while marshaling ec private key\")\n\t}\n\terr = pem.Encode(privPEM, &pem.Block{\n\t\tType:  \"EC PRIVATE KEY\",\n\t\tBytes: b,\n\t})\n\tif err != nil {\n\t\treturn nil, errors.Wrap(err, \"while encoding prive pem\")\n\t}\n\n\tcert, err := tls.X509KeyPair(certPEM.Bytes(), privPEM.Bytes())\n\treturn &cert, err\n}\n\n// launchDelegateService launches the delegate service on the configured uri\nfunc (dhtPeer *DHTPeer) launchDelegateService() {\n\tvar err error\n\n\tlerror, _, _, _ := dhtPeer.GetLoggers()\n\tconfig := &tls.Config{Certificates: []tls.Certificate{*dhtPeer.cert}}\n\turi := dhtPeer.host + \":\" + strconv.FormatInt(int64(dhtPeer.delegatePort), 10)\n\tlistener, err := tls.Listen(\"tcp\", uri, config)\n\n\tif err != nil {\n\t\tlerror(err).Msgf(\"while setting up listening tcp socket %s\", uri)\n\t\tcheck(err)\n\t}\n\n\tif err != nil {\n\t\tlerror(err).Msgf(\"while generating tls signature\")\n\t\tcheck(err)\n\t}\n\tdhtPeer.tcpListener = TLSListener{Listener: listener, Signature: dhtPeer.sslSignature}\n}\n\n// launchDelegateService launches the delegate service on the configured uri\nfunc (dhtPeer *DHTPeer) makeSSLCertifiateAndSignature() error {\n\tvar err error\n\n\tlerror, _, _, _ := dhtPeer.GetLoggers()\n\tdhtPeer.cert, err = generate_x509_cert()\n\tif err != nil {\n\t\tlerror(err).Msgf(\"while generating tls certificate\")\n\t\treturn err\n\t}\n\tdhtPeer.sslSignature, err = makeSessionKeySignature(dhtPeer.cert, dhtPeer.key)\n\tif err != nil {\n\t\tlerror(err).Msgf(\"while generating tls certificate server signature\")\n\t\treturn err\n\t}\n\treturn nil\n}\n\n// launchMailboxService launches the mailbox http service on the configured uri\nfunc (dhtPeer *DHTPeer) launchMailboxService() {\n\t_, _, linfo, _ := dhtPeer.GetLoggers()\n\tif len(dhtPeer.mailboxHostPort) == 0 {\n\t\treturn\n\t}\n\tdhtPeer.mailboxServer = &MailboxServer{\n\t\taddr:    dhtPeer.mailboxHostPort,\n\t\tdhtPeer: dhtPeer,\n\t}\n\tlinfo().Msgf(\"Starting mailbox service on %s\", dhtPeer.mailboxHostPort)\n\tgo dhtPeer.mailboxServer.start()\n}\n\n// Make signature for session public key using peer private key\nfunc makeSessionKeySignature(cert *tls.Certificate, privateKey cryptop2p.PrivKey) ([]byte, error) {\n\tcert_pub_key := cert.PrivateKey.(*ecdsa.PrivateKey).Public().(*ecdsa.PublicKey)\n\tcert_pub_key_bytes := elliptic.Marshal(cert_pub_key.Curve, cert_pub_key.X, cert_pub_key.Y)\n\tsignature, err := privateKey.Sign(cert_pub_key_bytes)\n\treturn signature, err\n}\n\n// handleDelegateService listens for new connections to delegate service and handles them\nfunc (dhtPeer *DHTPeer) handleDelegateService(ready *sync.WaitGroup) {\n\tdefer dhtPeer.goroutines.Done()\n\tdefer dhtPeer.tcpListener.Close()\n\n\tlerror, _, linfo, _ := dhtPeer.GetLoggers()\n\n\tdone := false\nL:\n\tfor {\n\t\tselect {\n\t\tdefault:\n\t\t\tlinfo().Msg(\"DelegateService listening for new connections...\")\n\t\t\tif !done {\n\t\t\t\tdone = true\n\t\t\t\tready.Done()\n\t\t\t}\n\t\t\tconn, err := dhtPeer.tcpListener.Accept()\n\t\t\tif err != nil {\n\t\t\t\tif strings.Contains(err.Error(), \"use of closed network connection\") {\n\t\t\t\t\t// About using string comparison to get the type of err,\n\t\t\t\t\t// check https://github.com/golang/go/issues/4373\n\t\t\t\t\tlinfo().Msg(\"DelegateService Stopped.\")\n\t\t\t\t} else {\n\t\t\t\t\tlerror(err).Msgf(\"while accepting a new connection\")\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tdhtPeer.goroutines.Add(1)\n\t\t\t\tgo dhtPeer.handleNewDelegationConnection(conn)\n\t\t\t}\n\t\tcase <-dhtPeer.closing:\n\t\t\tbreak L\n\t\t}\n\t}\n}\n\nfunc (dhtPeer *DHTPeer) CheckPOR(record *acn.AgentRecord) (*acn.StatusBody, error) {\n\taddr := record.Address\n\tmyPubKey, err := utils.FetchAIPublicKeyFromPubKey(dhtPeer.publicKey)\n\tignore(err)\n\tstatus, err := dhtnode.IsValidProofOfRepresentation(record, addr, myPubKey)\n\treturn status, err\n}\n\n// handleNewDelegationConnection handles a new delegate connection\n// verifies agent record and registers agent in DHT, handles incoming envelopes\n// and forwards them for processing\nfunc (dhtPeer *DHTPeer) handleNewDelegationConnection(conn net.Conn) {\n\tdefer dhtPeer.goroutines.Done()\n\tdefer conn.Close()\n\n\t// to limit spamming\n\ttime.Sleep(dhtPeer.registrationDelay)\n\n\tnbrConns, _ := dhtPeer.monitor.GetGauge(metricServiceDelegateClientsCount)\n\tnbrClients, _ := dhtPeer.monitor.GetCounter(metricServiceDelegateClientsCountAll)\n\topLatencyRegister, _ := dhtPeer.monitor.GetHistogram(metricOpLatencyRegister)\n\ttimer := dhtPeer.monitor.Timer()\n\tstart := timer.NewTimer()\n\n\tlerror, _, linfo, _ := dhtPeer.GetLoggers()\n\n\t//linfo().Msgf(\"received a new connection from %s\", conn.RemoteAddr().String())\n\n\t// read agent registration message\n\tconPipe := utils.ConnPipe{Conn: conn}\n\n\tvar register *acn.RegisterPerformative\n\tvar err error\n\n\tregister, err = acn.ReadAgentRegistrationMessage(conPipe)\n\tif err != nil {\n\t\tlerror(err).Msg(\"while receiving agent's registration request\")\n\t\tnbrConns.Dec()\n\t\treturn\n\t}\n\tlinfo().Msgf(\"Received registration request %s\", register)\n\n\t// Get Register message\n\trecord := register.Record\n\taddr := record.Address\n\n\tlinfo().Msgf(\"connection from %s established for Address %s\",\n\t\tconn.RemoteAddr().String(), addr)\n\n\t// check if the PoR is valid\n\tstatus, err := dhtPeer.CheckPOR(record)\n\tif err != nil || status.Code != acn.SUCCESS {\n\t\tlerror(err).Msg(\"PoR is not valid\")\n\t\tacn_send_error := acn.SendAcnError(conPipe, err.Error(), status.Code)\n\t\tignore(acn_send_error)\n\t\tnbrConns.Dec()\n\t\treturn\n\t}\n\n\t// TOFIX(LR) post-pone answer until address successfully registered\n\terr = acn.SendAcnSuccess(conPipe)\n\tif err != nil {\n\t\tnbrConns.Dec()\n\t\treturn\n\t}\n\n\t// Add connection to map\n\tdhtPeer.agentRecordsLock.Lock()\n\tdhtPeer.agentRecords[addr] = record\n\tdhtPeer.agentRecordsLock.Unlock()\n\n\tdhtPeer.tcpAddressesLock.Lock()\n\tdhtPeer.tcpAddresses[addr] = conn\n\tdhtPeer.tcpAddressesLock.Unlock()\n\n\tdhtPeer.acnStatusesLock.Lock()\n\tdhtPeer.acnStatuses[addr] = make(chan *acn.StatusBody, AcnStatusesQueueSize)\n\tdhtPeer.acnStatusesLock.Unlock()\n\n\t//linfo().Msgf(\"announcing tcp client address %s...\", addr)\n\t// TOFIX(LR) disconnect client?\n\tif dhtPeer.IsAddressAnnouncementEnabled() {\n\t\terr = dhtPeer.RegisterAgentAddress(addr)\n\t\tif err != nil {\n\t\t\tlerror(err).Msgf(\"while announcing tcp client address %s to the dht\", addr)\n\t\t\treturn\n\t\t}\n\t}\n\n\tduration := timer.GetTimer(start)\n\topLatencyRegister.Observe(float64(duration.Microseconds()))\n\n\tnbrConns.Inc()\n\tnbrClients.Inc()\n\n\tconnPipe := utils.ConnPipe{Conn: conn}\n\n\tfor {\n\t\t// read envelopes\n\t\tenvel, err := aea.HandleAcnMessageFromPipe(connPipe, dhtPeer, addr)\n\t\tif err != nil {\n\t\t\tif err == io.EOF {\n\t\t\t\tlinfo().Str(\n\t\t\t\t\t\"addr\",\n\t\t\t\t\taddr,\n\t\t\t\t).Msgf(\n\t\t\t\t\t\"connection closed by client: %s, stopping...\",\n\t\t\t\t\terr.Error(),\n\t\t\t\t)\n\t\t\t} else {\n\t\t\t\tlerror(err).Str(\"addr\", addr).Msg(\"while reading envelope from client connection, aborting...\")\n\t\t\t}\n\t\t\tnbrConns.Dec()\n\t\t\tbreak\n\t\t}\n\t\tif envel == nil {\n\t\t\t// ACN status\n\t\t\tcontinue\n\t\t}\n\t\tlinfo().Str(\n\t\t\t\"addr\",\n\t\t\taddr,\n\t\t).Msgf(\n\t\t\t\"got envelope from delegate connection\",\n\t\t)\n\t\tif envel.Sender != addr {\n\t\t\terr = errors.New(\"Sender (\" + envel.Sender + \") must match registered address\")\n\t\t\tlerror(err).Str(\"addr\", addr).\n\t\t\t\tMsg(\"while routing delegate client envelope\")\n\t\t\tcontinue\n\t\t}\n\n\t\t// initializing pairwise channel queues and one go routine per pair\n\t\tpair := envel.To + envel.Sender\n\t\tdhtPeer.syncMessagesLock.Lock()\n\t\t_, ok := dhtPeer.syncMessages[pair]\n\t\tdhtPeer.syncMessagesLock.Unlock()\n\t\tif !ok {\n\t\t\tdhtPeer.syncMessagesLock.Lock()\n\t\t\tdhtPeer.syncMessages[pair] = make(chan *aea.Envelope, 1000)\n\t\t\tdhtPeer.syncMessagesLock.Unlock()\n\n\t\t\t// route envelope\n\t\t\tdhtPeer.goroutines.Add(1)\n\t\t\tgo func() {\n\t\t\t\tdefer dhtPeer.goroutines.Done()\n\t\t\t\tdhtPeer.syncMessagesLock.Lock()\n\t\t\t\tpair_range := dhtPeer.syncMessages[pair]\n\t\t\t\tdhtPeer.syncMessagesLock.Unlock()\n\n\t\t\t\tfor e := range pair_range {\n\t\t\t\t\terr := dhtPeer.RouteEnvelope(e)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\tlerror(err).Str(\"addr\", addr).\n\t\t\t\t\t\t\tMsg(\"while routing delegate client envelope\")\n\t\t\t\t\t\t// TODO() send error back\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}()\n\t\t}\n\t\t// add to queue (nonblocking - buffered queue)\n\t\tdhtPeer.syncMessagesLock.Lock()\n\n\t\tselect {\n\t\tcase dhtPeer.syncMessages[pair] <- envel:\n\t\tdefault:\n\t\t\t// send back! error\n\t\t\tfmt.Println(\"CHANNEL FULL, DISCARDING <<<-------- \", string(envel.Message))\n\t\t}\n\t\tdhtPeer.syncMessagesLock.Unlock()\n\t}\n\n\tlinfo().Str(\"addr\", addr).\n\t\tMsg(\"delegate client disconnected\")\n\t// Remove connection from map\n\tdhtPeer.tcpAddressesLock.Lock()\n\tdelete(dhtPeer.tcpAddresses, addr)\n\tdhtPeer.tcpAddressesLock.Unlock()\n\t// TOFIX(LR) currently I am keeping the agent record\n\n\tdhtPeer.acnStatusesLock.Lock()\n\tdelete(dhtPeer.acnStatuses, addr)\n\tdhtPeer.acnStatusesLock.Unlock()\n\n}\n\n// ProcessEnvelope register callback function\nfunc (dhtPeer *DHTPeer) ProcessEnvelope(fn func(*aea.Envelope) error) {\n\tdhtPeer.processEnvelope = fn\n}\n\n// MultiAddr libp2p multiaddr of the peer\nfunc (dhtPeer *DHTPeer) MultiAddr() string {\n\tmultiAddr, _ := multiaddr.NewMultiaddr(\n\t\tfmt.Sprintf(\"/p2p/%s\", dhtPeer.routedHost.ID().Pretty()))\n\taddrs := dhtPeer.routedHost.Addrs()\n\tif len(addrs) == 0 {\n\t\treturn \"\"\n\t}\n\treturn addrs[0].Encapsulate(multiAddr).String()\n}\n\nfunc (dhtPeer *DHTPeer) GetCertAndSignature() (*tls.Certificate, []byte) {\n\treturn dhtPeer.cert, dhtPeer.sslSignature\n}\n\n// RouteEnvelope to its destination\n\nfunc (dhtPeer *DHTPeer) getEnvelopeAcnRecord(envel *aea.Envelope) (*acn.AgentRecord, error) {\n\tsender := envel.Sender\n\tdhtPeer.agentRecordsLock.RLock()\n\tlocalRec, existsLocal := dhtPeer.agentRecords[sender]\n\tdhtPeer.agentRecordsLock.RUnlock()\n\n\tvar envelRec *acn.AgentRecord\n\tif sender == dhtPeer.myAgentAddress {\n\t\tenvelRec = dhtPeer.myAgentRecord\n\t} else if dhtPeer.mailboxServer != nil && dhtPeer.mailboxServer.IsAddrRegistered(sender) {\n\t\tenvelRec = dhtPeer.mailboxServer.GetAgentRecord(sender)\n\t} else if existsLocal {\n\t\t// TOFIX(LR) should acquire RLock\n\t\tenvelRec = localRec\n\t} else {\n\t\terr := errors.New(\"Envelope sender is not registered locally \" + sender)\n\t\treturn nil, err\n\t}\n\treturn envelRec, nil\n}\n\nfunc (dhtPeer *DHTPeer) RouteEnvelope(envel *aea.Envelope) error {\n\tlerror, lwarn, linfo, ldebug := dhtPeer.GetLoggers()\n\n\trouteCount, _ := dhtPeer.monitor.GetGauge(metricOpRouteCount)\n\trouteCountAll, _ := dhtPeer.monitor.GetCounter(metricOpRouteCountAll)\n\trouteCountSuccess, _ := dhtPeer.monitor.GetCounter(metricOpRouteCountSuccess)\n\topLatencyRoute, _ := dhtPeer.monitor.GetHistogram(metricOpLatencyRoute)\n\ttimer := dhtPeer.monitor.Timer()\n\n\trouteCount.Inc()\n\trouteCountAll.Inc()\n\tstart := timer.NewTimer()\n\tldebug().Str(\"addr\", envel.To).Msgf(\"-> Routing envelope: %s\", envel.String())\n\n\t// get sender agent envelRec\n\t// TODO can change function signature to force the caller to provide the envelRec\n\ttarget := envel.To\n\n\tvar err error\n\n\tenvelRec, err := dhtPeer.getEnvelopeAcnRecord(envel)\n\n\tif err != nil {\n\t\tlerror(err).Str(\"op\", \"route\").Str(\"addr\", envel.To).\n\t\t\tMsg(\"\")\n\t\treturn err\n\t}\n\n\tdhtPeer.tcpAddressesLock.RLock()\n\tconnDelegate, existsDelegate := dhtPeer.tcpAddresses[target]\n\tdhtPeer.tcpAddressesLock.RUnlock()\n\n\tif dhtPeer.mailboxServer != nil {\n\t\tif dhtPeer.mailboxServer.RouteEnvelope(envel) {\n\t\t\tlinfo().Str(\"op\", \"route\").Str(\"addr\", target).\n\t\t\t\tMsg(\"route envelope destinated to mailbox registered agent...\")\n\t\t\treturn nil\n\t\t}\n\t}\n\n\tif target == dhtPeer.myAgentAddress {\n\t\tlinfo().Str(\"op\", \"route\").Str(\"addr\", target).\n\t\t\tMsg(\"route envelope destinated to my local agent...\")\n\t\t// TOFIX(LR) risk of infinite loop\n\t\tfor dhtPeer.myAgentReady != nil && !dhtPeer.myAgentReady() {\n\t\t\tlwarn().Str(\"op\", \"route\").Str(\"addr\", target).\n\t\t\t\tMsg(\"agent not ready yet, sleeping for some time ...\")\n\t\t\ttime.Sleep(time.Duration(100) * time.Millisecond)\n\t\t}\n\t\tif dhtPeer.processEnvelope != nil {\n\t\t\tduration := timer.GetTimer(start)\n\t\t\topLatencyRoute.Observe(float64(duration.Microseconds()))\n\t\t\terr := dhtPeer.processEnvelope(envel)\n\t\t\trouteCount.Dec()\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\trouteCountSuccess.Inc()\n\t\t} else {\n\t\t\tlwarn().Str(\"op\", \"route\").Str(\"addr\", target).\n\t\t\t\tMsgf(\"ProcessEnvelope not set, ignoring envelope %s\", envel.String())\n\t\t\treturn errors.New(\"Agent not ready\")\n\t\t}\n\t} else if existsDelegate {\n\t\tlinfo().Str(\"op\", \"route\").Str(\"addr\", target).\n\t\t\tMsgf(\"destination is a delegate client %s\", connDelegate.RemoteAddr().String())\n\n\t\trouteCount.Dec()\n\t\trouteCountSuccess.Inc()\n\n\t\tduration := timer.GetTimer(start)\n\t\topLatencyRoute.Observe(float64(duration.Microseconds()))\n\n\t\tdata, err := aea.MakeAcnMessageFromEnvelope(envel)\n\t\tif err != nil {\n\t\t\tlerror(err).Msgf(\"while serializing envelope: %s\", envel)\n\t\t\treturn err\n\t\t}\n\t\terr = utils.WriteBytesConn(connDelegate, data)\n\t\tif err != nil {\n\t\t\tlerror(err).Msgf(\"while writing envelope: %s\", envel)\n\t\t\treturn err\n\t\t}\n\t\tlinfo().Str(\"addr\", target).Msg(\"wait for acn ack\")\n\t\terr = dhtPeer.AwaitAcnStatus(target)\n\t\tlinfo().Str(\"addr\", target).Msg(\"got acn ack\")\n\t\tif err != nil {\n\t\t\tlerror(err).Msgf(\"while waiting acn ack for envelope: %s\", envel)\n\t\t\treturn err\n\t\t}\n\n\t} else {\n\t\tvar peerID peer.ID\n\t\tvar err error\n\t\tdhtPeer.dhtAddressesLock.RLock()\n\t\tsPeerID, exists := dhtPeer.dhtAddresses[target]\n\t\tdhtPeer.dhtAddressesLock.RUnlock()\n\t\tif exists {\n\t\t\tlinfo().Str(\"op\", \"route\").Str(\"addr\", target).\n\t\t\t\tMsgf(\"destination is a relay client %s\", sPeerID)\n\t\t\tpeerID, err = peer.Decode(sPeerID)\n\t\t\tlinfo().Str(\"op\", \"route\").Str(\"addr\", target).\n\t\t\t\tMsgf(\"relay client peer is %s\", peerID)\n\t\t\tif err != nil {\n\t\t\t\tlerror(err).Str(\"op\", \"route\").Str(\"addr\", target).\n\t\t\t\t\tMsgf(\"CRITICAL couldn't parse peer id from relay client id\")\n\t\t\t\trouteCount.Dec()\n\t\t\t\treturn err\n\t\t\t}\n\t\t\treturn dhtPeer._routeEnvelopeWithNewStream(envel, peerID, envelRec)\n\t\t}\n\t\t// not exists\n\t\terr = dhtPeer._routeEnvelopeDHTLookup(envel, timeoutBeforeMovingToSlowQueue)\n\t\tif err != nil {\n\t\t\trouteCount.Dec()\n\n\t\t\tif !dhtPeer.isClosing {\n\t\t\t\tlerror(err).Str(\"op\", \"route\").Str(\"addr\", target).\n\t\t\t\t\tMsg(\"while rooting and looking up address on the DHT. moving it to she slow queue\")\n\t\t\t\tdhtPeer.slow_queue <- envel\n\t\t\t} else {\n\t\t\t\tlerror(err).Str(\"op\", \"route\").Str(\"addr\", target).\n\t\t\t\t\tMsg(\"while rooting and looking up address on the DHT. dht peer is closing. message dropped\")\n\t\t\t}\n\n\t\t\treturn nil\n\t\t}\n\t}\n\n\treturn nil\n}\nfunc (dhtPeer *DHTPeer) slowEnvelopeSendLoop() {\n\tlerror, _, _, ldebug := dhtPeer.GetLoggers()\n\tvar err error\n\tfor {\n\t\tenvel, ok := <-dhtPeer.slow_queue\n\t\tif !ok || dhtPeer.isClosing {\n\t\t\tldebug().Msg(\"slow envelope send loop closed\")\n\t\t\treturn\n\t\t}\n\t\tif envel == nil {\n\t\t\tldebug().Msg(\"got nil envelope. exit slow envelope send loop\")\n\t\t\treturn\n\t\t}\n\t\tldebug().Str(\"addr\", envel.To).Msgf(\"-> Routing slow envelope: %s\", envel.String())\n\t\terr = dhtPeer._routeEnvelopeDHTLookup(envel, addressLookupTimeout)\n\t\tif err != nil {\n\t\t\tlerror(err).Msgf(\"while sending slow envelope: %s\", envel.String())\n\t\t} else {\n\t\t\tldebug().Str(\"addr\", envel.To).Msgf(\"sent slow envelope: %s\", envel.String())\n\t\t}\n\n\t}\n}\n\nfunc (dhtPeer *DHTPeer) _routeEnvelopeDHTLookup(\n\tenvel *aea.Envelope,\n\tlookup_timeout time.Duration,\n) error {\n\ttarget := envel.To\n\tlerror, _, linfo, _ := dhtPeer.GetLoggers()\n\tenvelRec, err := dhtPeer.getEnvelopeAcnRecord(envel)\n\tif err != nil {\n\t\treturn err\n\t}\n\tlinfo().Str(\"op\", \"route\").Str(\"addr\", target).\n\t\tMsg(\"did NOT find destination address locally, looking for it in the DHT...\")\n\tctx, cancel_lookup := context.WithTimeout(context.Background(), lookup_timeout)\n\tdefer cancel_lookup()\n\tpeerID, _, err := dhtPeer.lookupAddressDHT(ctx, target) // guarantees peerID has a valid PoR\n\tif err != nil {\n\t\tlerror(err).Str(\"op\", \"route\").Str(\"addr\", target).\n\t\t\tMsg(\"while looking up address on the DHT\")\n\t\treturn err\n\t}\n\terr = dhtPeer._routeEnvelopeWithNewStream(envel, peerID, envelRec)\n\treturn err\n\n}\n\nfunc (dhtPeer *DHTPeer) _routeEnvelopeWithNewStream(\n\tenvel *aea.Envelope,\n\tpeerID peer.ID,\n\tenvelRec *acn.AgentRecord,\n) error {\n\t//linfo().Str(\"op\", \"route\").Str(\"addr\", target).\n\t//\tMsgf(\"got peer id '%s' for agent address\", peerID.Pretty())\n\n\t//linfo().Str(\"op\", \"route\").Str(\"addr\", target).\n\t//\tMsgf(\"opening stream to target %s...\", peerID.Pretty())\n\tlerror, _, linfo, _ := dhtPeer.GetLoggers()\n\n\trouteCount, _ := dhtPeer.monitor.GetGauge(metricOpRouteCount)\n\topLatencyRoute, _ := dhtPeer.monitor.GetHistogram(metricOpLatencyRoute)\n\ttimer := dhtPeer.monitor.Timer()\n\tstart := timer.NewTimer()\n\n\tvar err error\n\ttarget := envel.To\n\tctx, cancel := context.WithTimeout(context.Background(), newStreamTimeout)\n\tdefer cancel()\n\tstream, err := dhtPeer.routedHost.NewStream(ctx, peerID, dhtnode.AeaEnvelopeStream)\n\tif err != nil {\n\t\tlerror(err).Str(\"op\", \"route\").Str(\"addr\", target).\n\t\t\tMsgf(\"timeout, couldn't open stream to target %s\", peerID.Pretty())\n\t\trouteCount.Dec()\n\t\treturn err\n\t}\n\n\tduration := timer.GetTimer(start)\n\topLatencyRoute.Observe(float64(duration.Microseconds()))\n\n\tlinfo().Str(\"op\", \"route\").Str(\"addr\", target).\n\t\tMsgf(\"sending envelope to target peer %s...\", peerID.Pretty())\n\n\tenvelBytes, err := proto.Marshal(envel)\n\tif err != nil {\n\t\tlerror(err).\n\t\t\tStr(\"op\", \"route\").\n\t\t\tStr(\"addr\", target).\n\t\t\tMsg(\"couldn't serialize envelope\")\n\t\terrReset := stream.Reset()\n\t\tignore(errReset)\n\t\trouteCount.Dec()\n\t\treturn err\n\t}\n\n\tstreamPipe := utils.StreamPipe{Stream: stream}\n\terr = acn.SendEnvelopeMessage(streamPipe, envelBytes, envelRec)\n\tif err != nil {\n\t\tlerror(err).\n\t\t\tStr(\"op\", \"route\").\n\t\t\tStr(\"addr\", target).\n\t\t\tMsg(\"couldn't send envelope\")\n\t\terrReset := stream.Reset()\n\t\tignore(errReset)\n\t\trouteCount.Dec()\n\t\treturn err\n\t}\n\n\t// wait for response\n\tlinfo().Str(\"op\", \"route\").Str(\"addr\", target).\n\t\tMsgf(\"waiting fro envelope delivery confirmation from target peer %s...\", peerID.Pretty())\n\n\tstatusBody, err := acn.ReadAcnStatus(streamPipe)\n\n\tif err != nil {\n\t\tlerror(err).\n\t\t\tStr(\"op\", \"route\").\n\t\t\tStr(\"addr\", target).\n\t\t\tMsg(\"failed to decode acn status\")\n\t\trouteCount.Dec()\n\t\treturn err\n\t}\n\tif statusBody.Code != acn.SUCCESS {\n\t\terr = errors.New(statusBody.Code.String() + \" : \" + strings.Join(statusBody.Msgs, \":\"))\n\t\tlerror(err).\n\t\t\tStr(\"op\", \"route\").\n\t\t\tStr(\"addr\", target).\n\t\t\tMsg(\"failed to deliver envelope\")\n\t\trouteCount.Dec()\n\t\treturn err\n\t}\n\n\trouteCount.Dec()\n\treturn nil\n}\n\n/// TOFIX(LR) should return (*dhtnode)\nfunc (dhtPeer *DHTPeer) lookupAddressDHT(\n\tctx context.Context,\n\taddress string,\n) (peer.ID, *acn.AgentRecord, error) {\n\tlerror, lwarn, linfo, _ := dhtPeer.GetLoggers()\n\tvar err error\n\n\tdhtLookupLatency, _ := dhtPeer.monitor.GetHistogram(metricDHTOpLatencyLookup)\n\ttimer := dhtPeer.monitor.Timer()\n\n\taddressCID, err := utils.ComputeCID(address)\n\tif err != nil {\n\t\treturn \"\", nil, err\n\t}\n\n\tlinfo().Str(\"op\", \"lookup\").Str(\"addr\", address).\n\t\tMsgf(\"Querying for providers for cid %s...\", addressCID.String())\n\tctx, cancel := context.WithTimeout(ctx, addressLookupTimeout)\n\tdefer cancel()\n\t//var elapsed time.Duration\n\tvar provider peer.AddrInfo\n\tvar stream network.Stream\n\n\tstart := timer.NewTimer()\n\n\tnoProvider := false\n\tfor {\n\t\tproviders := dhtPeer.dht.FindProvidersAsync(ctx, addressCID, 0)\n\n\t\tfor provider = range providers {\n\t\t\tduration := timer.GetTimer(start)\n\t\t\tdhtLookupLatency.Observe(float64(duration.Microseconds()))\n\n\t\t\t//linfo().Str(\"op\", \"lookup\").Str(\"addr\", address).\n\t\t\t//\tMsgf(\"found provider %s after %s\", provider, elapsed.String())\n\n\t\t\t// Add peer to host PeerStore - the provider should be the holder of the address\n\t\t\tdhtPeer.routedHost.Peerstore().AddAddrs(\n\t\t\t\tprovider.ID,\n\t\t\t\tprovider.Addrs,\n\t\t\t\tpeerstore.PermanentAddrTTL,\n\t\t\t)\n\n\t\t\t//linfo().Str(\"op\", \"lookup\").Str(\"addr\", address).\n\t\t\t//\tMsgf(\"opening stream to the address provider %s...\", provider)\n\t\t\tctxConnect := context.Background()\n\t\t\tstream, err = dhtPeer.routedHost.NewStream(\n\t\t\t\tctxConnect,\n\t\t\t\tprovider.ID,\n\t\t\t\tdhtnode.AeaAddressStream,\n\t\t\t)\n\n\t\t\tif err != nil {\n\t\t\t\tlwarn().Str(\"op\", \"lookup\").Str(\"addr\", address).\n\t\t\t\t\tMsgf(\"couldn't open stream to address provider %s: %s, looking up other providers...\", provider, err.Error())\n\t\t\t\tdhtPeer.routedHost.Peerstore().ClearAddrs(provider.ID)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tstreamPipe := utils.StreamPipe{Stream: stream}\n\n\t\t\tlinfo().Str(\"op\", \"lookup\").Str(\"addr\", address).\n\t\t\t\tMsgf(\"getting agent record from provider %s...\", provider)\n\n\t\t\t// perfrormaddress lookup\n\t\t\trecord, err := acn.PerformAddressLookup(streamPipe, address)\n\n\t\t\t// Response is either a LookupResponse or Status\n\t\t\tignore(stream.Reset())\n\t\t\tstream.Close()\n\t\t\tif err != nil {\n\t\t\t\tlwarn().Str(\"op\", \"lookup\").Str(\"addr\", address).\n\t\t\t\t\tMsgf(\"Failed agent lookup from provider %s (%s), looking up other providers...\", provider, err.Error())\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// lookupResponse must be set\n\t\t\tvalid, err := dhtnode.IsValidProofOfRepresentation(\n\t\t\t\trecord,\n\t\t\t\taddress,\n\t\t\t\trecord.PeerPublicKey,\n\t\t\t)\n\t\t\tif err != nil || valid.Code != acn.SUCCESS {\n\t\t\t\terrMsg := valid.Code.String() + \" : \" + strings.Join(valid.Msgs, \":\")\n\t\t\t\tif err == nil {\n\t\t\t\t\terr = errors.New(errMsg)\n\t\t\t\t} else {\n\t\t\t\t\terr = errors.Wrap(err, valid.Code.String()+\" : \"+strings.Join(valid.Msgs, \":\"))\n\t\t\t\t}\n\t\t\t\tlwarn().Str(\"op\", \"lookup\").Str(\"addr\", address).\n\t\t\t\t\tMsgf(\"invalid agent record from provider %s (%s), looking up other providers...\", provider, err.Error())\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tpeerid, err := utils.IDFromFetchAIPublicKey(record.PeerPublicKey)\n\t\t\tif err != nil {\n\t\t\t\treturn \"\", nil, errors.New(\n\t\t\t\t\t\"CRITICAL couldn't get peer ID from message:\" + err.Error(),\n\t\t\t\t)\n\t\t\t}\n\n\t\t\treturn peerid, record, nil\n\t\t}\n\n\t\tif provider.ID == \"\" {\n\t\t\tmsg := \"didn't find any provider for address\"\n\t\t\tif !noProvider {\n\t\t\t\tnoProvider = true\n\t\t\t\tlwarn().Str(\"op\", \"lookup\").Str(\"addr\", address).Msgf(\"%s, retrying...\", msg)\n\t\t\t}\n\t\t\tselect {\n\t\t\tdefault:\n\t\t\t\ttime.Sleep(200 * time.Millisecond)\n\t\t\tcase <-ctx.Done():\n\t\t\t\terr = errors.New(msg + \" \" + address + \" within timeout\")\n\t\t\t\tlerror(err).Str(\"op\", \"lookup\").Str(\"addr\", address).Msg(\"\")\n\t\t\t\treturn \"\", nil, err\n\t\t\t}\n\t\t} else {\n\t\t\treturn \"\", nil, err\n\t\t}\n\t}\n}\n\n// handleAeaEnvelopeStream deals with incoming envelopes on the AeaEnvelopeStream\n// envelopes arrive from other peers (full or client) and are processed\n// by HandleAeaEnvelope\nfunc (dhtPeer *DHTPeer) handleAeaEnvelopeStream(stream network.Stream) {\n\tcommon.HandleAeaEnvelopeStream(dhtPeer, stream)\n}\n\n// Callback to handle and route  aea envelope comes from the aea envelope stream\n// return ACNError if message routing failed, otherwise nil.\nfunc (dhtPeer *DHTPeer) HandleAeaEnvelope(envel *aea.Envelope) *acn.ACNError {\n\tvar err error\n\tlerror, lwarn, linfo, _ := dhtPeer.GetLoggers()\n\tdhtPeer.tcpAddressesLock.RLock()\n\tconnDelegate, existsDelegate := dhtPeer.tcpAddresses[envel.To]\n\tdhtPeer.tcpAddressesLock.RUnlock()\n\n\tif dhtPeer.mailboxServer != nil {\n\t\tif dhtPeer.mailboxServer.RouteEnvelope(envel) {\n\t\t\tlinfo().Str(\"op\", \"route\").Str(\"addr\", envel.To).\n\t\t\t\tMsg(\"route envelope destinated to mailbox registered agent...\")\n\t\t\treturn nil\n\t\t}\n\t}\n\n\tif existsDelegate {\n\t\tlinfo().Msgf(\n\t\t\t\"Sending envelope to tcp delegate client %s...\",\n\t\t\tconnDelegate.RemoteAddr().String(),\n\t\t)\n\t\tdata, err := aea.MakeAcnMessageFromEnvelope(envel)\n\t\tif err != nil {\n\t\t\tlerror(err).Msgf(\"while serializing envelope: %s\", envel)\n\t\t\treturn &acn.ACNError{\n\t\t\t\tErr:       errors.New(\"serializing envelope error\"),\n\t\t\t\tErrorCode: acn.ERROR_DECODE,\n\t\t\t}\n\t\t}\n\t\terr = utils.WriteBytesConn(connDelegate, data)\n\n\t\tif err != nil {\n\t\t\tlerror(\n\t\t\t\terr,\n\t\t\t).Msgf(\n\t\t\t\t\"while sending envelope to tcp client %s\",\n\t\t\t\tconnDelegate.RemoteAddr().String(),\n\t\t\t)\n\t\t\treturn &acn.ACNError{\n\t\t\t\tErr:       errors.New(\"agent is not ready\"),\n\t\t\t\tErrorCode: acn.ERROR_AGENT_NOT_READY,\n\t\t\t}\n\t\t}\n\t\terr = dhtPeer.AwaitAcnStatus(envel.To)\n\t\tif err != nil {\n\t\t\tlerror(\n\t\t\t\terr,\n\t\t\t).Msgf(\n\t\t\t\t\"while awating acn ack on sending  envelope to tcp client %s\",\n\t\t\t\tconnDelegate.RemoteAddr().String(),\n\t\t\t)\n\t\t\treturn &acn.ACNError{\n\t\t\t\tErr:       errors.New(\"while awating acn ack on sending  envelope to tcp clien\"),\n\t\t\t\tErrorCode: acn.ERROR_AGENT_NOT_READY,\n\t\t\t}\n\t\t}\n\t} else if envel.To == dhtPeer.myAgentAddress {\n\t\tif dhtPeer.processEnvelope == nil {\n\t\t\tlerror(err).Msgf(\"while processing envelope by agent\")\n\t\t\treturn &acn.ACNError{Err: errors.New(\"agent is not ready\"), ErrorCode: acn.ERROR_AGENT_NOT_READY}\n\t\t}\n\t\tlinfo().Msg(\"Processing envelope by local agent...\")\n\t\terr = dhtPeer.processEnvelope(envel)\n\t\tignore(err)\n\t} else {\n\t\tlwarn().Msgf(\"ignored envelope %s\", envel.String())\n\t\treturn &acn.ACNError{Err: errors.New(\"unknown agent address\"), ErrorCode: acn.ERROR_UNKNOWN_AGENT_ADDRESS}\n\t}\n\n\t// all good\n\treturn nil\n}\n\nfunc (dhtPeer *DHTPeer) handleAeaAddressStream(stream network.Stream) {\n\tcommon.HandleAeaAddressStream(dhtPeer, stream)\n\n}\n\nfunc (dhtPeer *DHTPeer) HandleAeaAddressRequest(\n\treqAddress string,\n) (*acn.AgentRecord, *acn.ACNError) {\n\tlerror, _, linfo, _ := dhtPeer.GetLoggers()\n\n\t//\tMsg(\"Received query for addr\")\n\tvar sPeerID string\n\tvar sRecord *acn.AgentRecord = nil\n\n\tdhtPeer.dhtAddressesLock.RLock()\n\tidRelay, existsRelay := dhtPeer.dhtAddresses[reqAddress]\n\tdhtPeer.dhtAddressesLock.RUnlock()\n\tdhtPeer.tcpAddressesLock.RLock()\n\t_, existsDelegate := dhtPeer.tcpAddresses[reqAddress]\n\tdhtPeer.tcpAddressesLock.RUnlock()\n\tdhtPeer.agentRecordsLock.RLock()\n\tlocalRec := dhtPeer.agentRecords[reqAddress]\n\tdhtPeer.agentRecordsLock.RUnlock()\n\n\tif reqAddress == dhtPeer.myAgentAddress {\n\t\tpeerID, err := peer.IDFromPublicKey(dhtPeer.publicKey)\n\t\tif err != nil {\n\t\t\tlerror(err).Str(\"op\", \"resolve\").Str(\"addr\", reqAddress).\n\t\t\t\tMsgf(\"CRITICAL could not get peer ID from public key %s\", dhtPeer.publicKey)\n\t\t} else {\n\t\t\tsPeerID = peerID.Pretty()\n\t\t\tsRecord = dhtPeer.myAgentRecord\n\t\t}\n\t} else if existsRelay {\n\t\tlinfo().Str(\"op\", \"resolve\").Str(\"addr\", reqAddress).\n\t\t\tMsg(\"found address in my relay clients map\")\n\t\tsPeerID = idRelay\n\t\tsRecord = localRec\n\t} else if dhtPeer.mailboxServer != nil && dhtPeer.mailboxServer.IsAddrRegistered(reqAddress) {\n\t\tsPeerID = idRelay\n\t\tsRecord = dhtPeer.mailboxServer.GetAgentRecord(reqAddress)\n\t} else if existsDelegate {\n\t\tlinfo().Str(\"op\", \"resolve\").Str(\"addr\", reqAddress).\n\t\t\tMsgf(\"found address in my delegate clients map\")\n\t\tpeerID, err := peer.IDFromPublicKey(dhtPeer.publicKey)\n\t\tif err != nil {\n\t\t\tlerror(err).Str(\"op\", \"resolve\").Str(\"addr\", reqAddress).\n\t\t\t\tMsgf(\"CRITICAL could not get peer ID from public key %s\", dhtPeer.publicKey)\n\t\t} else {\n\t\t\tsPeerID = peerID.Pretty()\n\t\t\tsRecord = localRec\n\t\t}\n\t} else {\n\t\t// needed when a relay client queries for a peer ID\n\t\t//linfo().Str(\"op\", \"resolve\").Str(\"addr\", reqAddress).\n\t\t//\tMsg(\"did NOT found the address locally, looking for it in the DHT...\")\n\t\tpeerID, peerRecord, err := dhtPeer.lookupAddressDHT(context.Background(), reqAddress)\n\t\tif err == nil {\n\t\t\tlinfo().Str(\"op\", \"resolve\").Str(\"addr\", reqAddress).\n\t\t\t\tMsg(\"found address on the DHT\")\n\t\t\tsPeerID = peerID.Pretty()\n\t\t\tsRecord = peerRecord\n\t\t} else {\n\t\t\tlerror(err).Str(\"op\", \"resolve\").Str(\"addr\", reqAddress).\n\t\t\t\tMsgf(\"did NOT find address locally or on the DHT.\")\n\n\t\t\treturn nil, &acn.ACNError{\n\t\t\t\tErr:       errors.New(\"unknown agent address\"),\n\t\t\t\tErrorCode: acn.ERROR_UNKNOWN_AGENT_ADDRESS,\n\t\t\t}\n\t\t}\n\t}\n\n\tif sRecord == nil {\n\t\treturn nil, &acn.ACNError{\n\t\t\tErr:       errors.New(\"unknown agent address\"),\n\t\t\tErrorCode: acn.ERROR_UNKNOWN_AGENT_ADDRESS,\n\t\t}\n\t}\n\n\t// record found, send\n\tlinfo().Str(\"op\", \"resolve\").Str(\"addr\", reqAddress).\n\t\tMsgf(\"sending agent record (%s) %s\", sPeerID, sRecord)\n\n\treturn sRecord, nil\n}\n\nfunc (dhtPeer *DHTPeer) handleAeaNotifStream(stream network.Stream) {\n\tlerror, _, _, ldebug := dhtPeer.GetLoggers()\n\n\tldebug().Str(\"op\", \"notif\").\n\t\tMsgf(\"Got a new notif stream. peerid: %s\", stream.Conn().RemotePeer().Pretty())\n\topLatencyRegister, _ := dhtPeer.monitor.GetHistogram(metricOpLatencyRegister)\n\ttimer := dhtPeer.monitor.Timer()\n\tstart := timer.NewTimer()\n\n\t// workaround: to avoid getting `failed to find any peer in table`\n\t//  when calling dht.Provide (happens occasionally)\n\tldebug().Msg(\"waiting for notifying peer to be added to dht routing table...\")\n\tctx, cancel := context.WithTimeout(\n\t\tcontext.Background(),\n\t\troutingTableConnectionUpdateTimeout,\n\t)\n\tdefer cancel()\n\n\tdefer dhtPeer.enableAddressAnnouncementWg.Done()\n\tdhtPeer.enableAddressAnnouncementWg.Add(1)\n\n\tfor dhtPeer.dht.RoutingTable().Find(stream.Conn().RemotePeer()) == \"\" {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\tlerror(nil).\n\t\t\t\tMsgf(\"timeout: notifying peer %s haven't been added to DHT routing table\",\n\t\t\t\t\tstream.Conn().RemotePeer().Pretty())\n\t\t\treturn\n\t\tcase <-time.After(time.Millisecond * 5):\n\t\t}\n\t}\n\n\tif dhtPeer.myAgentAddress != \"\" && !dhtPeer.IsAddressAnnounced(dhtPeer.myAgentAddress) {\n\t\terr := dhtPeer.RegisterAgentAddress(dhtPeer.myAgentAddress)\n\t\tif err != nil {\n\t\t\tlerror(err).Str(\"op\", \"notif\").\n\t\t\t\tStr(\"addr\", dhtPeer.myAgentAddress).\n\t\t\t\tMsgf(\"while announcing my agent address\")\n\t\t\treturn\n\t\t}\n\t}\n\tif dhtPeer.enableRelay {\n\t\tdhtPeer.dhtAddressesLock.RLock()\n\t\tfor addr := range dhtPeer.dhtAddresses {\n\t\t\terr := dhtPeer.RegisterAgentAddress(addr)\n\t\t\tif err != nil {\n\t\t\t\tlerror(err).Str(\"op\", \"notif\").\n\t\t\t\t\tStr(\"addr\", addr).\n\t\t\t\t\tMsg(\"while announcing relay client address\")\n\t\t\t}\n\t\t}\n\t\tdhtPeer.dhtAddressesLock.RUnlock()\n\t}\n\tif dhtPeer.delegatePort != 0 {\n\t\tdhtPeer.tcpAddressesLock.RLock()\n\t\tfor addr := range dhtPeer.tcpAddresses {\n\t\t\terr := dhtPeer.RegisterAgentAddress(addr)\n\t\t\tif err != nil {\n\t\t\t\tlerror(err).Str(\"op\", \"notif\").\n\t\t\t\t\tStr(\"addr\", addr).\n\t\t\t\t\tMsg(\"while announcing delegate client address\")\n\t\t\t}\n\t\t}\n\t\tdhtPeer.tcpAddressesLock.RUnlock()\n\n\t}\n\tduration := timer.GetTimer(start)\n\topLatencyRegister.Observe(float64(duration.Microseconds()))\n\tldebug().Msgf(\"Address was announced: peerid: %s\", stream.Conn().RemotePeer().Pretty())\n\t// got a connection to a peer, so now we can allow address announcements\n\tdhtPeer.enableAddressAnnouncementLock.Lock()\n\tdhtPeer.enableAddressAnnouncement = true\n\tdhtPeer.enableAddressAnnouncementLock.Unlock()\n\n}\n\nfunc (dhtPeer *DHTPeer) IsAddressAnnouncementEnabled() bool {\n\t// wait if new peers connection establish in process\n\tdhtPeer.enableAddressAnnouncementWg.Wait()\n\tdhtPeer.enableAddressAnnouncementLock.Lock()\n\tisEnabled := dhtPeer.enableAddressAnnouncement\n\tdhtPeer.enableAddressAnnouncementLock.Unlock()\n\treturn isEnabled\n}\n\nfunc (dhtPeer *DHTPeer) handleAeaRegisterStream(stream network.Stream) {\n\tlerror, _, linfo, _ := dhtPeer.GetLoggers()\n\n\t// to limit spamming\n\ttime.Sleep(dhtPeer.registrationDelay)\n\n\tnbrClients, _ := dhtPeer.monitor.GetCounter(metricServiceRelayClientsCountAll)\n\n\topLatencyRegister, _ := dhtPeer.monitor.GetHistogram(metricOpLatencyRegister)\n\ttimer := dhtPeer.monitor.Timer()\n\tstart := timer.NewTimer()\n\n\t//linfo().Str(\"op\", \"register\").\n\t//\tMsg(\"Got a new aea register stream\")\n\tstreamPipe := utils.StreamPipe{Stream: stream}\n\n\t// Get Register message\n\tregister, err := acn.ReadAgentRegistrationMessage(streamPipe)\n\tif err != nil {\n\t\tlerror(err).Str(\"op\", \"register\").\n\t\t\tMsg(\"while reading relay client registration request from stream\")\n\t\terr = stream.Reset()\n\t\tignore(err)\n\t\treturn\n\t}\n\trecord := register.Record\n\tclientAddr := record.Address\n\n\t//linfo().Msgf(\"connection from %s established for Address %s\",\n\t//\tstream.Conn().RemotePeer().Pretty(), clientAddr)\n\n\t// check if the PoR is valid\n\tclientPubKey, err := utils.FetchAIPublicKeyFromPubKey(stream.Conn().RemotePublicKey())\n\tignore(err)\n\tstatus, err := dhtnode.IsValidProofOfRepresentation(record, record.Address, clientPubKey)\n\n\tif err != nil || status.Code != acn.SUCCESS {\n\t\tlerror(err).Msg(\"PoR is not valid\")\n\t\tacn_send_error := acn.SendAcnError(streamPipe, err.Error(), status.Code)\n\t\tignore(acn_send_error)\n\t\treturn\n\t}\n\n\t// TOFIX(LR) post-pone answer until address successfully registered\n\terr = acn.SendAcnSuccess(streamPipe)\n\tif err != nil {\n\t\terr = stream.Reset()\n\t\tignore(err)\n\t\treturn\n\t}\n\n\tstream.Close()\n\tnbrClients.Inc()\n\n\t//linfo().Str(\"op\", \"register\").\n\t//\tStr(\"addr\", string(clientAddr)).\n\t//\tMsgf(\"Received address registration request for peer id %s\", string(clientPeerID))\n\tclientPeerID := stream.Conn().RemotePeer().Pretty()\n\n\tdhtPeer.agentRecordsLock.Lock()\n\tdhtPeer.agentRecords[clientAddr] = record\n\tdhtPeer.agentRecordsLock.Unlock()\n\n\tdhtPeer.dhtAddressesLock.Lock()\n\tdhtPeer.dhtAddresses[clientAddr] = clientPeerID\n\terr = dhtPeer.saveAgentRecordToPersistentStorage(record)\n\tif err != nil {\n\t\tlerror(err).Str(\"op\", \"register\").\n\t\t\tStr(\"addr\", clientAddr).\n\t\t\tMsg(\"while saving agent record to persistent storage\")\n\t}\n\tdhtPeer.dhtAddressesLock.Unlock()\n\n\tlinfo().Str(\"op\", \"register\").\n\t\tStr(\"addr\", clientAddr).\n\t\tMsgf(\"peer added: %s\", clientPeerID)\n\n\tif dhtPeer.IsAddressAnnouncementEnabled() && !dhtPeer.IsAddressAnnounced(string(clientAddr)) {\n\t\tlinfo().Str(\"op\", \"register\").\n\t\t\tStr(\"addr\", clientAddr).\n\t\t\tMsgf(\"Announcing client address on behalf of %s...\", clientPeerID)\n\t\terr = dhtPeer.RegisterAgentAddress(string(clientAddr))\n\t\tif err != nil {\n\t\t\t//TOFIX(LR) remove agent from map, or don't add it unless announcement done\n\t\t\tlerror(err).Str(\"op\", \"register\").\n\t\t\t\tStr(\"addr\", clientAddr).\n\t\t\t\tMsg(\"while announcing client address to the dht\")\n\t\t\treturn\n\t\t}\n\t}\n\n\tduration := timer.GetTimer(start)\n\topLatencyRegister.Observe(float64(duration.Microseconds()))\n}\n\nfunc (dhtPeer *DHTPeer) RegisterAgentAddress(addr string) error {\n\t_, _, linfo, _ := dhtPeer.GetLoggers()\n\n\tif dhtPeer.IsAddressAnnounced(addr) {\n\t\t// already announced\n\t\treturn nil\n\t}\n\n\tdhtPeer.setAddressAnnounced(addr)\n\n\tdhtStoreLatency, _ := dhtPeer.monitor.GetHistogram(metricDHTOpLatencyStore)\n\ttimer := dhtPeer.monitor.Timer()\n\n\taddressCID, err := utils.ComputeCID(addr)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// TOFIX(LR) tune timeout\n\tctx, cancel := context.WithTimeout(context.Background(), addressRegisterTimeout)\n\tdefer cancel()\n\n\tlinfo().Str(\"op\", \"register\").\n\t\tStr(\"addr\", addr).\n\t\tMsgf(\"Announcing address to the dht with cid key %s\", addressCID.String())\n\tstart := timer.NewTimer()\n\terr = dhtPeer.dht.Provide(ctx, addressCID, true)\n\tif err != context.DeadlineExceeded {\n\t\tduration := timer.GetTimer(start)\n\t\tdhtStoreLatency.Observe(float64(duration.Microseconds()))\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc (dhtPeer *DHTPeer) IsAddressAnnounced(address string) bool {\n\tdhtPeer.addressAnnouncedMapLock.Lock()\n\t_, present := dhtPeer.addressAnnouncedMap[address]\n\tdhtPeer.addressAnnouncedMapLock.Unlock()\n\treturn present\n}\n\nfunc (dhtPeer *DHTPeer) setAddressAnnounced(address string) {\n\tdhtPeer.addressAnnouncedMapLock.Lock()\n\tdhtPeer.addressAnnouncedMap[address] = true\n\tdhtPeer.addressAnnouncedMapLock.Unlock()\n}\n\nfunc (dhtPeer *DHTPeer) AddAcnStatusMessage(status *acn.StatusBody, counterpartyID string) {\n\tdhtPeer.acnStatusesLock.Lock()\n\tqueue := dhtPeer.acnStatuses[counterpartyID]\n\tdhtPeer.acnStatusesLock.Unlock()\n\n\tqueue <- status\n}\n\nfunc (dhtPeer *DHTPeer) AwaitAcnStatus(counterpartyID string) error {\n\tlerror, _, _, _ := dhtPeer.GetLoggers()\n\n\tdhtPeer.acnStatusesLock.Lock()\n\tcounterParty := dhtPeer.acnStatuses[counterpartyID]\n\tdhtPeer.acnStatusesLock.Unlock()\n\n\tstatus, err := acn.WaitForStatus(counterParty, AcnStatusTimeout)\n\n\tif err != nil {\n\t\tlerror(err).Msg(\"timeout on status wait\")\n\t\treturn err\n\t}\n\tif status.Code != acn.SUCCESS {\n\t\tlerror(err).Msgf(\"bad status: %d\", status.Code)\n\t\treturn errors.New(\"bad status!\")\n\t}\n\treturn err\n\n}\n"
  },
  {
    "path": "libs/go/libp2p_node/dht/dhtpeer/dhtpeer_test.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2019 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\n\npackage dhtpeer\n\nimport (\n\t\"context\"\n\t\"crypto/ecdsa\"\n\t\"crypto/elliptic\"\n\t\"crypto/tls\"\n\t\"log\"\n\t\"math/rand\"\n\t\"net\"\n\t\"os\"\n\t\"path\"\n\t\"strconv\"\n\t\"testing\"\n\t\"time\"\n\n\t\"libp2p_node/acn\"\n\t\"libp2p_node/aea\"\n\t\"libp2p_node/dht/dhtclient\"\n\t\"libp2p_node/dht/dhtnode\"\n\t\"libp2p_node/utils\"\n\n\t\"github.com/pkg/errors\"\n\t\"google.golang.org/protobuf/proto\"\n)\n\n/*\n  DHTPeer and DHT network routing tests\n*/\n\nconst (\n\tDefaultLocalHost    = \"127.0.0.1\"\n\tDefaultLocalPort    = 2000\n\tDefaultDelegatePort = 3000\n\n\tEnvelopeDeliveryTimeout = 1 * time.Second\n\tDHTPeerSetupTimeout     = 5 * time.Second\n\n\tDefaultLedger = dhtnode.DefaultLedger\n)\n\nvar (\n\tFetchAITestKeys = []string{\n\t\t\"3e7a1f43b2d8a4b9f63a2ffeb1d597f971a8db7ffd95453173268b453106cadc\",\n\t\t\"92c36941ae78c1b93e5f4bebcf2b40be0af37573aa263ebb70b769ea235b88b6\",\n\t\t\"b6a8ff857c49b81895f18dd6dbd309e270906b75e2c290a721da48c5de4cba70\",\n\t\t\"91a90b5be4817c46e06f0e792dd9d9ef3ceb2dbb5ff5c45125153d289d515ce1\",\n\t\t\"5ee086c5c3df6f641e36e083769d6a03f918b33e4505b1102d2be7a75bb2ae0f\",\n\t\t\"6768d7918659c1699a379691381c19e55c3c13c49d30086e74a86524123659fb\",\n\t\t\"d31485403d0cce93b0c48a2fad2acae61a68396e93a602acfcd08dadd7ba12ae\",\n\t\t\"db533c3e74963a0571e962a4022a4ebce14ab5f240299b5350c83dd18549c1fd\",\n\t\t\"95aaa63bceeb0946c877c414e1f17119b8a975417924d83db8e281abd71820b2\",\n\t\t\"9427c1472b66f6abd94a6c246eee495e3709ec45882ae0badcbc71ad2cd8f8b2\",\n\t}\n\n\tFetchAITestPublicKeys = []string{\n\t\t\"03b7e977f498dce004e2614764ff576e17cc6691135497e7bcb5d3441e816ba9e1\",\n\t\t\"02344c3f0e79f56aef8e167a6fea912745f1f770b66b4c5096040c0e8c9e3c68b3\",\n\t\t\"023d6021c001c7b562af8b6e54ace4f98b1b14170d7db4749ecab2b1f0e4252794\",\n\t\t\"02a0eb20ae23f2f78650b42dfafa6bf4e4752657905da8598b2c0806478e0bfa0d\",\n\t\t\"023db373d1fc21212f2f03fec1ddd49f193f54f71545e72f37c8a70ca20ef1622b\",\n\t\t\"03290b4e5dabcca2a994a8d63057f5c83f60d999ede181a8d9b42084e3bee256c2\",\n\t\t\"03510651fbb9d2ce5b7ae00968339055fbc552e565c54cce8c69f5a52209d3d6a7\",\n\t\t\"02c11df29b5873e0c37d1427c488ba84e5ccc57405d39299757cee06893ab8595d\",\n\t\t\"031545edc0fe81a17c77a391a343f95547745b28703bbe664e12c523e3272b637e\",\n\t\t\"02dd78522785e4175e7db9794b03adcdcfaf707153f307caa3368da5a30594d369\",\n\t}\n\n\tAgentsTestKeys = []string{\n\t\t\"730c22474709a6d17cf11599a80413a84ddb691a3c7b11a6d8d47a2c024b7b56\",\n\t\t\"a085c5eeb39636a21c85a9bc667bae18bf3e327a220ecb3998e317b62ab20ec6\",\n\t\t\"0b7af750e7e96ceb9fe5582bdf9bdafae726427d34447f7245a084b6cf0aa5e5\",\n\t\t\"dffaa5a9779931a2c1194794e6e9a89787557d6cd708d84c74de20ec5e03a7bf\",\n\t\t\"509c4019dd96a337a36149031869e6de5db014ab9ae5d8097ac997ca8f10422a\",\n\t\t\"a385fa48b4f40a2f4ea66de88c0021532299865fe6137d765788f9f856e79453\",\n\t\t\"ff212371e454f8292fd3b13020a3910fc91002a7ab5eb3f297b71df6b7ff9bc1\",\n\t\t\"04289e97041fc025c103141909d2cce649944153822f032b646214a850363618\",\n\t\t\"116294510fba759d19af7a65b915467384258d997695ed7018d8c19d38c29412\",\n\t\t\"dc2f0238e65c0291bedae58cb1c013bd03e0f41f78e1779744ac401952ec2b51\",\n\t}\n\n\tAgentsTestAddresses = []string{\n\t\t\"fetch1y39e4tec9fll66x2k7wed5qn7zhaneayjm55kk\",\n\t\t\"fetch1ufjmhth6dnhrckxrvk05lmt8s2vture23xvwjl\",\n\t\t\"fetch1dja5uazc9n7jpjm94rhmkkmcyv5nj3kt8aexgf\",\n\t\t\"fetch18v5lz9psp53akm26ztk3exytqfdvpnfdsyx232\",\n\t\t\"fetch10u6ra4qmukhf57xadv64jt9jhr9gdrg707x6l9\",\n\t\t\"fetch1hys3k2anw5mxe0y2vksccpe58jyk5gksrsjd60\",\n\t\t\"fetch1t07jnjjtlqa07mstg4gw9twjs2ddtqs3sgtx7c\",\n\t\t\"fetch18sxxgat6uaxqxvd7mgt99y7avyy3c24av36u2l\",\n\t\t\"fetch1sx2rmtndc5t97pn00x76sksrzgc9s2watpgw64\",\n\t\t\"fetch1mwd8n27t68svv4w5urztgw7e3kjh7nqkqz0j94\",\n\t}\n)\n\n/*\n  DHT Network: DHTPeer-to-DHTPeer\n*/\n\n// TestRoutingDHTPeerToSelf dht peer with agent attached\nfunc TestRoutingDHTPeerToSelf(t *testing.T) {\n\topts := []Option{\n\t\tLocalURI(DefaultLocalHost, DefaultLocalPort),\n\t\tPublicURI(DefaultLocalHost, DefaultLocalPort),\n\t\tIdentityFromFetchAIKey(FetchAITestKeys[0]),\n\t\tEnableRelayService(),\n\t\tEnableDelegateService(DefaultDelegatePort),\n\t\tStoreRecordsTo(path.Join(os.TempDir(), \"agents_records_\"+randSeq(5))),\n\t}\n\n\tagentPubKey, err := utils.FetchAIPublicKeyFromFetchAIPrivateKey(AgentsTestKeys[0])\n\tif err != nil {\n\t\tt.Fatal(\"Failed at DHTPeer initialization:\", err)\n\t}\n\n\tsignature, err := utils.SignFetchAI([]byte(FetchAITestPublicKeys[0]), AgentsTestKeys[0])\n\tif err != nil {\n\t\tt.Fatal(\"Failed at DHTPeer initialization:\", err)\n\t}\n\n\trecord := &acn.AgentRecord{LedgerId: DefaultLedger}\n\trecord.Address = AgentsTestAddresses[0]\n\trecord.PublicKey = agentPubKey\n\trecord.PeerPublicKey = FetchAITestPublicKeys[0]\n\trecord.Signature = signature\n\n\topts = append(opts, RegisterAgentAddress(record, func() bool { return true }))\n\n\tdhtPeer, err := New(opts...)\n\tif err != nil {\n\t\tt.Fatal(\"Failed at DHTPeer initialization:\", err)\n\t}\n\tdefer dhtPeer.Close()\n\n\tvar rxEnvelopes []*aea.Envelope\n\tdhtPeer.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxEnvelopes = append(rxEnvelopes, envel)\n\t\treturn nil\n\t})\n\n\terr = dhtPeer.RouteEnvelope(&aea.Envelope{\n\t\tTo:     AgentsTestAddresses[0],\n\t\tSender: AgentsTestAddresses[0],\n\t})\n\tif err != nil {\n\t\tt.Error(\"Failed to Route envelope to local Agent\")\n\t}\n\n\tif len(rxEnvelopes) == 0 {\n\t\tt.Error(\"Failed to Route & Process envelope to local Agent\")\n\t}\n\n}\n\n// TestRoutingDHTPeerToDHTPeerDirect from a dht peer to its bootstrap peer\nfunc TestRoutingDHTPeerToDHTPeerDirect(t *testing.T) {\n\tdhtPeer1, cleanup1, err := SetupLocalDHTPeer(\n\t\tFetchAITestKeys[0], AgentsTestKeys[0], DefaultLocalPort, DefaultDelegatePort,\n\t\t[]string{},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t}\n\tdefer cleanup1()\n\n\tdhtPeer2, cleanup2, err := SetupLocalDHTPeer(\n\t\tFetchAITestKeys[1], AgentsTestKeys[1], DefaultLocalPort+1, DefaultDelegatePort+1,\n\t\t[]string{dhtPeer1.MultiAddr()},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t}\n\tdefer cleanup2()\n\n\trxPeer1 := make(chan *aea.Envelope, 2)\n\tdhtPeer1.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxPeer1 <- envel\n\t\terr := dhtPeer1.RouteEnvelope(&aea.Envelope{\n\t\t\tTo:     envel.Sender,\n\t\t\tSender: envel.To,\n\t\t})\n\t\treturn err\n\t})\n\n\trxPeer2 := make(chan *aea.Envelope, 2)\n\tdhtPeer2.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxPeer2 <- envel\n\t\treturn nil\n\t})\n\n\tensureAddressAnnounced(dhtPeer1, dhtPeer2)\n\n\terr = dhtPeer2.RouteEnvelope(&aea.Envelope{\n\t\tTo:     AgentsTestAddresses[0],\n\t\tSender: AgentsTestAddresses[1],\n\t})\n\tif err != nil {\n\t\tt.Error(\"Failed to RouteEnvelope from peer 2 to peer 1:\", err)\n\t}\n\n\texpectEnvelope(t, rxPeer1)\n\texpectEnvelope(t, rxPeer2)\n}\n\n// TestRoutingDHTPeerToDHTPeerIndirect two dht peers connected to the same peer\nfunc TestRoutingDHTPeerToDHTPeerIndirect(t *testing.T) {\n\tentryPeer, cleanup, err := SetupLocalDHTPeer(\n\t\tFetchAITestKeys[0], AgentsTestKeys[0], DefaultLocalPort, DefaultDelegatePort,\n\t\t[]string{},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t}\n\tdefer cleanup()\n\n\tdhtPeer1, cleanup1, err := SetupLocalDHTPeer(\n\t\tFetchAITestKeys[1], AgentsTestKeys[1], DefaultLocalPort+1, DefaultDelegatePort+1,\n\t\t[]string{entryPeer.MultiAddr()},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t}\n\tdefer cleanup1()\n\n\tdhtPeer2, cleanup2, err := SetupLocalDHTPeer(\n\t\tFetchAITestKeys[2], AgentsTestKeys[2], DefaultLocalPort+2, DefaultDelegatePort+2,\n\t\t[]string{entryPeer.MultiAddr()},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t}\n\tdefer cleanup2()\n\n\trxPeer1 := make(chan *aea.Envelope, 2)\n\tdhtPeer1.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxPeer1 <- envel\n\t\terr := dhtPeer1.RouteEnvelope(&aea.Envelope{\n\t\t\tTo:     envel.Sender,\n\t\t\tSender: envel.To,\n\t\t})\n\t\treturn err\n\t})\n\n\trxPeer2 := make(chan *aea.Envelope, 2)\n\tdhtPeer2.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxPeer2 <- envel\n\t\treturn nil\n\t})\n\n\tensureAddressAnnounced(dhtPeer1, dhtPeer2)\n\n\terr = dhtPeer2.RouteEnvelope(&aea.Envelope{\n\t\tTo:     AgentsTestAddresses[1],\n\t\tSender: AgentsTestAddresses[2],\n\t})\n\tif err != nil {\n\t\tt.Error(\"Failed to RouteEnvelope from peer 2 to peer 1:\", err)\n\t}\n\n\texpectEnvelope(t, rxPeer1)\n\texpectEnvelope(t, rxPeer2)\n}\n\n// TestRoutingDHTPeerToDHTPeerIndirectTwoHops two dht peers connected to different peers\nfunc TestRoutingDHTPeerToDHTPeerIndirectTwoHops(t *testing.T) {\n\tentryPeer1, cleanup, err := SetupLocalDHTPeer(\n\t\tFetchAITestKeys[0], \"\", DefaultLocalPort, DefaultDelegatePort,\n\t\t[]string{},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t}\n\tdefer cleanup()\n\n\tentryPeer2, cleanup, err := SetupLocalDHTPeer(\n\t\tFetchAITestKeys[1], AgentsTestKeys[1], DefaultLocalPort+1, DefaultDelegatePort+1,\n\t\t[]string{entryPeer1.MultiAddr()},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t}\n\tdefer cleanup()\n\n\ttime.Sleep(1 * time.Second)\n\tdhtPeer1, cleanup1, err := SetupLocalDHTPeer(\n\t\tFetchAITestKeys[2], AgentsTestKeys[2], DefaultLocalPort+2, DefaultDelegatePort+2,\n\t\t[]string{entryPeer1.MultiAddr()},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t}\n\tdefer cleanup1()\n\n\tdhtPeer2, cleanup2, err := SetupLocalDHTPeer(\n\t\tFetchAITestKeys[3], AgentsTestKeys[3], DefaultLocalPort+3, DefaultDelegatePort+3,\n\t\t[]string{entryPeer2.MultiAddr()},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t}\n\tdefer cleanup2()\n\n\trxPeer1 := make(chan *aea.Envelope, 2)\n\tdhtPeer1.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxPeer1 <- envel\n\t\terr := dhtPeer1.RouteEnvelope(&aea.Envelope{\n\t\t\tTo:     envel.Sender,\n\t\t\tSender: envel.To,\n\t\t})\n\t\treturn err\n\t})\n\n\trxPeer2 := make(chan *aea.Envelope, 2)\n\tdhtPeer2.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxPeer2 <- envel\n\t\treturn nil\n\t})\n\n\tensureAddressAnnounced(dhtPeer1, dhtPeer2)\n\n\terr = dhtPeer2.RouteEnvelope(&aea.Envelope{\n\t\tTo:     AgentsTestAddresses[2],\n\t\tSender: AgentsTestAddresses[3],\n\t})\n\tif err != nil {\n\t\tt.Error(\"Failed to RouteEnvelope from peer 2 to peer 1:\", err)\n\t}\n\n\texpectEnvelope(t, rxPeer1)\n\texpectEnvelope(t, rxPeer2)\n}\n\n// TestRoutingDHTPeerToDHTPeerFullConnectivity fully connected dht peers network\nfunc TestRoutingDHTPeerToDHTPeerFullConnectivity(t *testing.T) {\n\tpeers := []*DHTPeer{}\n\trxs := []chan *aea.Envelope{}\n\n\tfor i := range FetchAITestKeys {\n\t\tpeer, cleanup, err := SetupLocalDHTPeer(\n\t\t\tFetchAITestKeys[i], AgentsTestKeys[i],\n\t\t\tDefaultLocalPort+uint16(i), DefaultDelegatePort+uint16(i),\n\t\t\tfunc() []string {\n\t\t\t\tmultiaddrs := []string{}\n\t\t\t\tfor _, entryPeer := range peers {\n\t\t\t\t\tmultiaddrs = append(multiaddrs, entryPeer.MultiAddr())\n\t\t\t\t}\n\t\t\t\treturn multiaddrs\n\t\t\t}(),\n\t\t)\n\t\tif err != nil {\n\t\t\tt.Fatal(\"Failed to initialize DHTPeer\", i, \":\", err)\n\t\t}\n\n\t\trx := make(chan *aea.Envelope, 2)\n\t\tpeer.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\t\trx <- envel\n\t\t\tif string(envel.Message) == \"ping\" {\n\t\t\t\terr := peer.RouteEnvelope(&aea.Envelope{\n\t\t\t\t\tTo:      envel.Sender,\n\t\t\t\t\tSender:  envel.To,\n\t\t\t\t\tMessage: []byte(\"ack\"),\n\t\t\t\t})\n\t\t\t\treturn err\n\t\t\t}\n\t\t\treturn nil\n\t\t})\n\n\t\tpeers = append(peers, peer)\n\t\trxs = append(rxs, rx)\n\t\tdefer cleanup()\n\t}\n\n\tensureAddressAnnounced(peers...)\n\n\tfor i := range peers {\n\t\tfor j := range peers {\n\t\t\tfrom := len(peers) - 1 - i\n\t\t\ttarget := j\n\n\t\t\t// Should be able to route to self though\n\t\t\tif from == target {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\terr := peers[from].RouteEnvelope(&aea.Envelope{\n\t\t\t\tTo:      AgentsTestAddresses[target],\n\t\t\t\tSender:  AgentsTestAddresses[from],\n\t\t\t\tMessage: []byte(\"ping\"),\n\t\t\t})\n\n\t\t\tif err != nil {\n\t\t\t\tt.Error(\"Failed to RouteEnvelope from \", from, \"to\", target)\n\t\t\t}\n\n\t\t\texpectEnvelope(t, rxs[target])\n\t\t\texpectEnvelope(t, rxs[from])\n\t\t}\n\t}\n}\n\n/*\n  DHT network: DHTClient\n*/\n\n// TestRoutingDHTClientToDHTPeer dht client to its bootstrap peer\nfunc TestRoutingDHTClientToDHTPeerX(t *testing.T) {\n\tpeer, peerCleanup, err := SetupLocalDHTPeer(\n\t\tFetchAITestKeys[0], AgentsTestKeys[0], DefaultLocalPort, DefaultDelegatePort,\n\t\t[]string{},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t}\n\tdefer peerCleanup()\n\n\tclient, clientCleanup, err := SetupDHTClient(\n\t\tFetchAITestKeys[1], AgentsTestKeys[1], []string{peer.MultiAddr()},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTClient:\", err)\n\t}\n\tdefer clientCleanup()\n\n\trxPeer := make(chan *aea.Envelope, 2)\n\tpeer.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxPeer <- envel\n\t\treturn peer.RouteEnvelope(&aea.Envelope{\n\t\t\tTo:     envel.Sender,\n\t\t\tSender: envel.To,\n\t\t})\n\t})\n\n\trxClient := make(chan *aea.Envelope, 2)\n\tclient.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxClient <- envel\n\t\treturn nil\n\t})\n\n\ttime.Sleep(1 * time.Second)\n\terr = client.RouteEnvelope(&aea.Envelope{\n\t\tTo:     AgentsTestAddresses[0],\n\t\tSender: AgentsTestAddresses[1],\n\t})\n\tif err != nil {\n\t\tt.Error(\"Failed to RouteEnvelope from DHTClient to DHTPeer:\", err)\n\t}\n\n\texpectEnvelope(t, rxPeer)\n\texpectEnvelope(t, rxClient)\n\n}\n\n// TestRoutingDHTClientToDHTPeerIndirect dht client to dht peer different than its bootstrap one\nfunc TestRoutingDHTClientToDHTPeerIndirect(t *testing.T) {\n\tentryPeer, entryPeerCleanup, err := SetupLocalDHTPeer(\n\t\tFetchAITestKeys[0], AgentsTestKeys[0], DefaultLocalPort, DefaultDelegatePort,\n\t\t[]string{},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t}\n\tdefer entryPeerCleanup()\n\n\tpeer, peerCleanup, err := SetupLocalDHTPeer(\n\t\tFetchAITestKeys[1], AgentsTestKeys[1], DefaultLocalPort+1, DefaultDelegatePort+1,\n\t\t[]string{entryPeer.MultiAddr()},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t}\n\tdefer peerCleanup()\n\n\ttime.Sleep(1 * time.Second)\n\tclient, clientCleanup, err := SetupDHTClient(\n\t\tFetchAITestKeys[2], AgentsTestKeys[2], []string{entryPeer.MultiAddr()},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTClient:\", err)\n\t}\n\tdefer clientCleanup()\n\n\trxPeer := make(chan *aea.Envelope, 2)\n\tpeer.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxPeer <- envel\n\t\treturn peer.RouteEnvelope(&aea.Envelope{\n\t\t\tTo:     envel.Sender,\n\t\t\tSender: envel.To,\n\t\t})\n\t})\n\n\trxClient := make(chan *aea.Envelope, 2)\n\tclient.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxClient <- envel\n\t\treturn nil\n\t})\n\n\tensureAddressAnnounced(entryPeer, peer)\n\n\ttime.Sleep(1 * time.Second)\n\terr = client.RouteEnvelope(&aea.Envelope{\n\t\tTo:     AgentsTestAddresses[1],\n\t\tSender: AgentsTestAddresses[2],\n\t})\n\tif err != nil {\n\t\tt.Error(\"Failed to RouteEnvelope from DHTClient to DHTPeer:\", err)\n\t}\n\n\texpectEnvelope(t, rxPeer)\n\texpectEnvelope(t, rxClient)\n}\n\n// TestRoutingDHTClientToDHTClient dht client to dht client connected to the same peer\nfunc TestRoutingDHTClientToDHTClient(t *testing.T) {\n\tpeer, peerCleanup, err := SetupLocalDHTPeer(\n\t\tFetchAITestKeys[0], AgentsTestKeys[0], DefaultLocalPort, DefaultDelegatePort,\n\t\t[]string{},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t}\n\tdefer peerCleanup()\n\n\tclient1, clientCleanup1, err := SetupDHTClient(\n\t\tFetchAITestKeys[1], AgentsTestKeys[1], []string{peer.MultiAddr()},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTClient:\", err)\n\t}\n\tdefer clientCleanup1()\n\n\tclient2, clientCleanup2, err := SetupDHTClient(\n\t\tFetchAITestKeys[2], AgentsTestKeys[2], []string{peer.MultiAddr()},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTClient:\", err)\n\t}\n\tdefer clientCleanup2()\n\n\trxClient1 := make(chan *aea.Envelope, 2)\n\tclient1.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxClient1 <- envel\n\t\treturn client1.RouteEnvelope(&aea.Envelope{\n\t\t\tTo:     envel.Sender,\n\t\t\tSender: envel.To,\n\t\t})\n\t})\n\n\trxClient2 := make(chan *aea.Envelope, 2)\n\tclient2.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxClient2 <- envel\n\t\treturn nil\n\t})\n\n\ttime.Sleep(1 * time.Second)\n\terr = client2.RouteEnvelope(&aea.Envelope{\n\t\tTo:     AgentsTestAddresses[1],\n\t\tSender: AgentsTestAddresses[2],\n\t})\n\tif err != nil {\n\t\tt.Error(\"Failed to RouteEnvelope from DHTClient to DHTClient:\", err)\n\t}\n\n\texpectEnvelope(t, rxClient1)\n\texpectEnvelope(t, rxClient2)\n\n}\n\n// TestRoutingDHTClientToDHTClientIndirect dht client to dht client connected to a different peer\nfunc TestRoutingDHTClientToDHTClientIndirect(t *testing.T) {\n\tpeer1, peerCleanup1, err := SetupLocalDHTPeer(\n\t\tFetchAITestKeys[0], \"\", DefaultLocalPort, DefaultDelegatePort,\n\t\t[]string{},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t}\n\tdefer peerCleanup1()\n\n\tpeer2, peerCleanup2, err := SetupLocalDHTPeer(\n\t\tFetchAITestKeys[1], AgentsTestKeys[1], DefaultLocalPort+1, DefaultDelegatePort+1,\n\t\t[]string{peer1.MultiAddr()},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t}\n\tdefer peerCleanup2()\n\n\tclient1, clientCleanup1, err := SetupDHTClient(\n\t\tFetchAITestKeys[2], AgentsTestKeys[2], []string{peer1.MultiAddr()},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTClient:\", err)\n\t}\n\tdefer clientCleanup1()\n\n\tclient2, clientCleanup2, err := SetupDHTClient(\n\t\tFetchAITestKeys[3], AgentsTestKeys[3], []string{peer2.MultiAddr()},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTClient:\", err)\n\t}\n\tdefer clientCleanup2()\n\n\trxClient1 := make(chan *aea.Envelope, 2)\n\tclient1.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxClient1 <- envel\n\t\treturn client1.RouteEnvelope(&aea.Envelope{\n\t\t\tTo:     envel.Sender,\n\t\t\tSender: envel.To,\n\t\t})\n\t})\n\n\trxClient2 := make(chan *aea.Envelope, 2)\n\tclient2.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxClient2 <- envel\n\t\treturn nil\n\t})\n\n\tensureAddressAnnounced(peer1, peer2)\n\n\ttime.Sleep(1 * time.Second)\n\terr = client2.RouteEnvelope(&aea.Envelope{\n\t\tTo:     AgentsTestAddresses[2],\n\t\tSender: AgentsTestAddresses[3],\n\t})\n\tif err != nil {\n\t\tt.Error(\"Failed to RouteEnvelope from DHTClient to DHTClient:\", err)\n\t}\n\n\texpectEnvelope(t, rxClient1)\n\texpectEnvelope(t, rxClient2)\n\n}\n\n/*\n  DHT network: DelegateClient\n*/\n\n// TestRoutingDelegateClientToDHTPeer\nfunc TestRoutingDelegateClientToDHTPeerX(t *testing.T) {\n\tpeer, peerCleanup, err := SetupLocalDHTPeer(\n\t\tFetchAITestKeys[0], AgentsTestKeys[0], DefaultLocalPort, DefaultDelegatePort,\n\t\t[]string{},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t}\n\tdefer peerCleanup()\n\n\tclient, clientCleanup, err := SetupDelegateClient(\n\t\tAgentsTestKeys[1],\n\t\tDefaultLocalHost,\n\t\tDefaultDelegatePort,\n\t\tFetchAITestPublicKeys[0],\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DelegateClient:\", err)\n\t}\n\tdefer clientCleanup()\n\n\trxPeer := make(chan *aea.Envelope, 2)\n\tpeer.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxPeer <- envel\n\t\treturn nil\n\t})\n\n\terr = client.Send(&aea.Envelope{\n\t\tTo:     AgentsTestAddresses[0],\n\t\tSender: AgentsTestAddresses[1],\n\t})\n\tif err != nil {\n\t\tt.Error(\"Failed to Send envelope from DelegateClient to DHTPeer:\", err)\n\t}\n\n\texpectEnvelope(t, rxPeer)\n\n\terr = peer.RouteEnvelope(&aea.Envelope{\n\t\tTo:     AgentsTestAddresses[1],\n\t\tSender: AgentsTestAddresses[0],\n\t})\n\tif err != nil {\n\t\tt.Error(\"Failed to RouteEnvelope from peer to delegate client:\", err)\n\t}\n\n\texpectEnvelope(t, client.Rx)\n}\n\n// TestRoutingDelegateClientToDHTPeerIndirect\nfunc TestRoutingDelegateClientToDHTPeerIndirect(t *testing.T) {\n\tpeer1, peerCleanup1, err := SetupLocalDHTPeer(\n\t\tFetchAITestKeys[0], AgentsTestKeys[0], DefaultLocalPort, DefaultDelegatePort,\n\t\t[]string{},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t}\n\tdefer peerCleanup1()\n\n\tpeer2, peerCleanup2, err := SetupLocalDHTPeer(\n\t\tFetchAITestKeys[1], AgentsTestKeys[1], DefaultLocalPort+1, DefaultDelegatePort+1,\n\t\t[]string{peer1.MultiAddr()},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t}\n\tdefer peerCleanup2()\n\n\ttime.Sleep(3 * time.Second)\n\tclient, clientCleanup, err := SetupDelegateClient(\n\t\tAgentsTestKeys[2],\n\t\tDefaultLocalHost,\n\t\tDefaultDelegatePort+1,\n\t\tFetchAITestPublicKeys[1],\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DelegateClient:\", err)\n\t}\n\tdefer clientCleanup()\n\n\trxPeer1 := make(chan *aea.Envelope, 20)\n\tpeer1.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxPeer1 <- envel\n\t\treturn nil\n\t})\n\n\tensureAddressAnnounced(peer1, peer2)\n\n\terr = client.Send(&aea.Envelope{\n\t\tTo:     AgentsTestAddresses[0],\n\t\tSender: AgentsTestAddresses[2],\n\t})\n\tif err != nil {\n\t\tt.Error(\"Failed to Send envelope from DelegateClient to DHTPeer:\", err)\n\t}\n\texpectEnvelope(t, rxPeer1)\n\n\terr = peer1.RouteEnvelope(&aea.Envelope{\n\t\tTo:     AgentsTestAddresses[2],\n\t\tSender: AgentsTestAddresses[0],\n\t})\n\tif err != nil {\n\t\tt.Error(\"Failed to RouteEnvelope from peer to delegate client:\", err)\n\t}\n\texpectEnvelope(t, client.Rx)\n}\n\n// TestMessageOrderingWithDelegateClient\nfunc TestMessageOrderingWithDelegateClient(t *testing.T) {\n\tpeer1, peerCleanup1, err := SetupLocalDHTPeer(\n\t\tFetchAITestKeys[0], AgentsTestKeys[0], DefaultLocalPort, DefaultDelegatePort,\n\t\t[]string{},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t}\n\tdefer peerCleanup1()\n\n\tpeer2, peerCleanup2, err := SetupLocalDHTPeer(\n\t\tFetchAITestKeys[1], AgentsTestKeys[1], DefaultLocalPort+1, DefaultDelegatePort+1,\n\t\t[]string{peer1.MultiAddr()},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t}\n\tdefer peerCleanup2()\n\n\ttime.Sleep(1 * time.Second)\n\n\tclient, clientCleanup, err := SetupDelegateClient(\n\t\tAgentsTestKeys[2],\n\t\tDefaultLocalHost,\n\t\tDefaultDelegatePort+1,\n\t\tFetchAITestPublicKeys[1],\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DelegateClient:\", err)\n\t}\n\tdefer clientCleanup()\n\n\trxPeer1 := make(chan *aea.Envelope, 20)\n\tpeer1.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxPeer1 <- envel\n\t\treturn nil\n\t})\n\trxPeer2 := make(chan *aea.Envelope, 20)\n\tpeer2.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxPeer2 <- envel\n\t\treturn nil\n\t})\n\n\tensureAddressAnnounced(peer1, peer2)\n\n\tmax := 10\n\ti := 0\n\tfor x := 0; x < max; x++ {\n\t\tenvelope := &aea.Envelope{\n\t\t\tTo:      AgentsTestAddresses[0],\n\t\t\tSender:  AgentsTestAddresses[2],\n\t\t\tMessage: []byte(strconv.Itoa(i)),\n\t\t}\n\t\terr = client.Send(envelope)\n\t\tif err != nil {\n\t\t\tt.Error(\"Failed to Send envelope from DelegateClient to DHTPeer:\", err)\n\t\t}\n\t\ti++\n\t\tt.Log(\"Sending Envelope : \", envelope)\n\t\t// time.Sleep(100 * time.Millisecond)\n\n\t\tenvelope1 := &aea.Envelope{\n\t\t\tTo:      AgentsTestAddresses[1],\n\t\t\tSender:  AgentsTestAddresses[2],\n\t\t\tMessage: []byte(strconv.Itoa(i)),\n\t\t}\n\t\terr = client.Send(envelope1)\n\t\tif err != nil {\n\t\t\tt.Error(\"Failed to Send envelope from DelegateClient to DHTPeer:\", err)\n\t\t}\n\t\ti++\n\t\tt.Log(\"Sending Envelope : \", envelope1)\n\t\t// time.Sleep(100 * time.Millisecond)\n\t}\n\n\t// go func() {\n\tii := 0\n\tfor x := 0; x < max; x++ {\n\t\texpectEnvelopeOrdered(t, rxPeer1, ii)\n\t\tii++\n\t\tii++\n\t}\n\t// }()\n\n\t// go func() {\n\tiii := 0\n\tfor x := 0; x < max; x++ {\n\t\tiii++\n\t\texpectEnvelopeOrdered(t, rxPeer2, iii)\n\t\tiii++\n\t}\n\t// }()\n\tprint(\"STOP OF THE TEST\")\n}\n\n// TestMessageOrderingWithDelegateClientTwoHops\nfunc TestMessageOrderingWithDelegateClientTwoHops(t *testing.T) {\n\tpeer1Index := 0\n\tpeer2Index := 1\n\tclient1Index := 2\n\tclient2Index := 3\n\tpeer1, peerCleanup1, err := SetupLocalDHTPeer(\n\t\tFetchAITestKeys[peer1Index],\n\t\tAgentsTestKeys[peer1Index],\n\t\tDefaultLocalPort,\n\t\tDefaultDelegatePort,\n\t\t[]string{},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t}\n\tdefer peerCleanup1()\n\n\tpeer2, peerCleanup2, err := SetupLocalDHTPeer(\n\t\tFetchAITestKeys[peer2Index],\n\t\tAgentsTestKeys[peer2Index],\n\t\tDefaultLocalPort+1,\n\t\tDefaultDelegatePort+1,\n\t\t[]string{peer1.MultiAddr()},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t}\n\tdefer peerCleanup2()\n\n\ttime.Sleep(1 * time.Second)\n\n\tclient1, clientCleanup1, err := SetupDelegateClient(\n\t\tAgentsTestKeys[client1Index],\n\t\tDefaultLocalHost,\n\t\tDefaultDelegatePort,\n\t\tFetchAITestPublicKeys[peer1Index],\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DelegateClient:\", err)\n\t}\n\tdefer clientCleanup1()\n\n\tclient2, clientCleanup2, err := SetupDelegateClient(\n\t\tAgentsTestKeys[client2Index],\n\t\tDefaultLocalHost,\n\t\tDefaultDelegatePort+1,\n\t\tFetchAITestPublicKeys[peer2Index],\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DelegateClient:\", err)\n\t}\n\tdefer clientCleanup2()\n\n\trxClient1 := make(chan *aea.Envelope, 20)\n\tclient1.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxClient1 <- envel\n\t\treturn nil\n\t})\n\trxClient2 := make(chan *aea.Envelope, 20)\n\tclient2.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxClient2 <- envel\n\t\treturn nil\n\t})\n\n\tensureAddressAnnounced(peer1, peer2)\n\n\tmax := 100\n\ti := 0\n\tfor x := 0; x < max; x++ {\n\t\tenvelope := &aea.Envelope{\n\t\t\tTo:      AgentsTestAddresses[client2Index],\n\t\t\tSender:  AgentsTestAddresses[client1Index],\n\t\t\tMessage: []byte(strconv.Itoa(i)),\n\t\t}\n\t\terr = client1.Send(envelope)\n\t\tif err != nil {\n\t\t\tt.Error(\"Failed to Send envelope from DelegateClient to DHTPeer:\", err)\n\t\t}\n\t\ti++\n\t\tt.Log(\"Sending Envelope : \", envelope)\n\t\t// time.Sleep(100 * time.Millisecond)\n\n\t\tenvelope1 := &aea.Envelope{\n\t\t\tTo:      AgentsTestAddresses[client1Index],\n\t\t\tSender:  AgentsTestAddresses[client2Index],\n\t\t\tMessage: []byte(strconv.Itoa(i)),\n\t\t}\n\t\terr = client2.Send(envelope1)\n\t\tif err != nil {\n\t\t\tt.Error(\"Failed to Send envelope from DelegateClient to DHTPeer:\", err)\n\t\t}\n\t\ti++\n\t\tt.Log(\"Sending Envelope : \", envelope1)\n\t\t// time.Sleep(100 * time.Millisecond)\n\t}\n\n\t// go func() {\n\tii := 0\n\tfor x := 0; x < max; x++ {\n\t\texpectEnvelopeOrdered(t, rxClient2, ii)\n\t\tii++\n\t\tii++\n\t}\n\t// }()\n\n\t// go func() {\n\tiii := 0\n\tfor x := 0; x < max; x++ {\n\t\tiii++\n\t\texpectEnvelopeOrdered(t, rxClient1, iii)\n\t\tiii++\n\t}\n\t// }()\n\tprint(\"STOP OF THE TEST\")\n}\n\n// TestRoutingDelegateClientToDHTPeerIndirectTwoHops\nfunc TestRoutingDelegateClientToDHTPeerIndirectTwoHops(t *testing.T) {\n\tentryPeer, entryPeerCleanup, err := SetupLocalDHTPeer(\n\t\tFetchAITestKeys[0], AgentsTestKeys[0], DefaultLocalPort, DefaultDelegatePort,\n\t\t[]string{},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t}\n\tdefer entryPeerCleanup()\n\n\tpeer1, peerCleanup1, err := SetupLocalDHTPeer(\n\t\tFetchAITestKeys[1], AgentsTestKeys[1], DefaultLocalPort+1, DefaultDelegatePort+1,\n\t\t[]string{entryPeer.MultiAddr()},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t}\n\tdefer peerCleanup1()\n\n\tpeer2, peerCleanup2, err := SetupLocalDHTPeer(\n\t\tFetchAITestKeys[2], AgentsTestKeys[2], DefaultLocalPort+2, DefaultDelegatePort+2,\n\t\t[]string{entryPeer.MultiAddr()},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t}\n\tdefer peerCleanup2()\n\n\ttime.Sleep(1 * time.Second)\n\tclient, clientCleanup, err := SetupDelegateClient(\n\t\tAgentsTestKeys[3],\n\t\tDefaultLocalHost,\n\t\tDefaultDelegatePort+2,\n\t\tFetchAITestPublicKeys[2],\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DelegateClient:\", err)\n\t}\n\tdefer clientCleanup()\n\n\trxPeer1 := make(chan *aea.Envelope, 2)\n\tpeer1.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxPeer1 <- envel\n\t\treturn nil\n\t})\n\n\tensureAddressAnnounced(entryPeer, peer1, peer2)\n\n\terr = client.Send(&aea.Envelope{\n\t\tTo:     AgentsTestAddresses[1],\n\t\tSender: AgentsTestAddresses[3],\n\t})\n\tif err != nil {\n\t\tt.Error(\"Failed to Send envelope from DelegateClient to DHTPeer:\", err)\n\t}\n\n\texpectEnvelope(t, rxPeer1)\n\n\terr = peer1.RouteEnvelope(&aea.Envelope{\n\t\tTo:     AgentsTestAddresses[3],\n\t\tSender: AgentsTestAddresses[1],\n\t})\n\tif err != nil {\n\t\tt.Error(\"Failed to RouteEnvelope from peer to delegate client:\", err)\n\t}\n\n\texpectEnvelope(t, client.Rx)\n}\n\n// TestRoutingDelegateClientToDelegateClient\nfunc TestRoutingDelegateClientToDelegateClient(t *testing.T) {\n\t_, peerCleanup, err := SetupLocalDHTPeer(\n\t\tFetchAITestKeys[0], AgentsTestKeys[0], DefaultLocalPort, DefaultDelegatePort,\n\t\t[]string{},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t}\n\tdefer peerCleanup()\n\n\tclient1, clientCleanup1, err := SetupDelegateClient(\n\t\tAgentsTestKeys[1],\n\t\tDefaultLocalHost,\n\t\tDefaultDelegatePort,\n\t\tFetchAITestPublicKeys[0],\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DelegateClient:\", err)\n\t}\n\tdefer clientCleanup1()\n\n\tclient2, clientCleanup2, err := SetupDelegateClient(\n\t\tAgentsTestKeys[2],\n\t\tDefaultLocalHost,\n\t\tDefaultDelegatePort,\n\t\tFetchAITestPublicKeys[0],\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DelegateClient:\", err)\n\t}\n\tdefer clientCleanup2()\n\n\ttime.Sleep(1 * time.Second)\n\terr = client1.Send(&aea.Envelope{\n\t\tTo:     AgentsTestAddresses[2],\n\t\tSender: AgentsTestAddresses[1],\n\t})\n\tif err != nil {\n\t\tt.Error(\"Failed to Send envelope from DelegateClient to DelegateClient:\", err)\n\t}\n\n\texpectEnvelope(t, client2.Rx)\n\n\terr = client2.Send(&aea.Envelope{\n\t\tTo:     AgentsTestAddresses[1],\n\t\tSender: AgentsTestAddresses[2],\n\t})\n\tif err != nil {\n\t\tt.Error(\"Failed to Send envelope from DelegateClient to DelegateClient:\", err)\n\t}\n\n\texpectEnvelope(t, client1.Rx)\n}\n\n// TestRoutingDelegateClientToDelegateClientIndirect\nfunc TestRoutingDelegateClientToDelegateClientIndirect(t *testing.T) {\n\tpeer1, peer1Cleanup, err := SetupLocalDHTPeer(\n\t\tFetchAITestKeys[0], \"\", DefaultLocalPort, DefaultDelegatePort,\n\t\t[]string{},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t}\n\tdefer peer1Cleanup()\n\n\tpeer2, peer2Cleanup, err := SetupLocalDHTPeer(\n\t\tFetchAITestKeys[1], AgentsTestKeys[1], DefaultLocalPort+1, DefaultDelegatePort+1,\n\t\t[]string{peer1.MultiAddr()},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t}\n\tdefer peer2Cleanup()\n\n\tclient1, clientCleanup1, err := SetupDelegateClient(\n\t\tAgentsTestKeys[2],\n\t\tDefaultLocalHost,\n\t\tDefaultDelegatePort,\n\t\tFetchAITestPublicKeys[0],\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DelegateClient:\", err)\n\t}\n\tdefer clientCleanup1()\n\n\tclient2, clientCleanup2, err := SetupDelegateClient(\n\t\tAgentsTestKeys[3],\n\t\tDefaultLocalHost,\n\t\tDefaultDelegatePort+1,\n\t\tFetchAITestPublicKeys[1],\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DelegateClient:\", err)\n\t}\n\tdefer clientCleanup2()\n\n\tensureAddressAnnounced(peer1, peer2)\n\n\terr = client1.Send(&aea.Envelope{\n\t\tTo:     AgentsTestAddresses[3],\n\t\tSender: AgentsTestAddresses[2],\n\t})\n\tif err != nil {\n\t\tt.Error(\"Failed to Send envelope from DelegateClient to DelegateClient:\", err)\n\t}\n\n\texpectEnvelope(t, client2.Rx)\n\n\terr = client2.Send(&aea.Envelope{\n\t\tTo:     AgentsTestAddresses[2],\n\t\tSender: AgentsTestAddresses[3],\n\t})\n\tif err != nil {\n\t\tt.Error(\"Failed to Send envelope from DelegateClient to DelegateClient:\", err)\n\t}\n\n\texpectEnvelope(t, client1.Rx)\n}\n\n// TestRoutingDelegateClientToDHTClientDirect\nfunc TestRoutingDelegateClientToDHTClientDirect(t *testing.T) {\n\tpeer, peerCleanup, err := SetupLocalDHTPeer(\n\t\tFetchAITestKeys[0], \"\", DefaultLocalPort, DefaultDelegatePort,\n\t\t[]string{},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t}\n\tdefer peerCleanup()\n\n\tdhtClient, dhtClientCleanup, err := SetupDHTClient(\n\t\tFetchAITestKeys[1], AgentsTestKeys[1], []string{peer.MultiAddr()},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTClient:\", err)\n\t}\n\tdefer dhtClientCleanup()\n\n\tdelegateClient, delegateClientCleanup, err := SetupDelegateClient(\n\t\tAgentsTestKeys[2],\n\t\tDefaultLocalHost,\n\t\tDefaultDelegatePort,\n\t\tFetchAITestPublicKeys[0],\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DelegateClient:\", err)\n\t}\n\tdefer delegateClientCleanup()\n\n\trxClientDHT := make(chan *aea.Envelope, 2)\n\tdhtClient.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxClientDHT <- envel\n\t\treturn dhtClient.RouteEnvelope(&aea.Envelope{\n\t\t\tTo:     envel.Sender,\n\t\t\tSender: envel.To,\n\t\t})\n\t})\n\n\ttime.Sleep(1 * time.Second)\n\terr = delegateClient.Send(&aea.Envelope{\n\t\tTo:     AgentsTestAddresses[1],\n\t\tSender: AgentsTestAddresses[2],\n\t})\n\tif err != nil {\n\t\tt.Error(\"Failed to Send envelope from DelegateClient to DHTClient:\", err)\n\t}\n\n\texpectEnvelope(t, rxClientDHT)\n\texpectEnvelope(t, delegateClient.Rx)\n}\n\n// TestRoutingDelegateClientToDHTClientIndirect\nfunc TestRoutingDelegateClientToDHTClientIndirect(t *testing.T) {\n\tpeer1, peerCleanup1, err := SetupLocalDHTPeer(\n\t\tFetchAITestKeys[0], AgentsTestKeys[0], DefaultLocalPort, DefaultDelegatePort,\n\t\t[]string{},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t}\n\tdefer peerCleanup1()\n\n\tpeer2, peerCleanup2, err := SetupLocalDHTPeer(\n\t\tFetchAITestKeys[1], AgentsTestKeys[1], DefaultLocalPort+1, DefaultDelegatePort+1,\n\t\t[]string{peer1.MultiAddr()},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t}\n\tdefer peerCleanup2()\n\n\tdhtClient, dhtClientCleanup, err := SetupDHTClient(\n\t\tFetchAITestKeys[2], AgentsTestKeys[2], []string{peer1.MultiAddr()},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTClient:\", err)\n\t}\n\tdefer dhtClientCleanup()\n\n\tdelegateClient, delegateClientCleanup, err := SetupDelegateClient(\n\t\tAgentsTestKeys[3], DefaultLocalHost, DefaultDelegatePort+1, FetchAITestPublicKeys[1],\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DelegateClient:\", err)\n\t}\n\tdefer delegateClientCleanup()\n\n\trxClientDHT := make(chan *aea.Envelope, 2)\n\tdhtClient.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxClientDHT <- envel\n\t\treturn dhtClient.RouteEnvelope(&aea.Envelope{\n\t\t\tTo:     envel.Sender,\n\t\t\tSender: envel.To,\n\t\t})\n\t})\n\n\tensureAddressAnnounced(peer1, peer2)\n\n\ttime.Sleep(3 * time.Second)\n\n\terr = delegateClient.Send(&aea.Envelope{\n\t\tTo:     AgentsTestAddresses[2],\n\t\tSender: AgentsTestAddresses[3],\n\t})\n\tif err != nil {\n\t\tt.Error(\"Failed to Send envelope from DelegateClient to DHTClient:\", err)\n\t}\n\n\texpectEnvelope(t, rxClientDHT)\n\texpectEnvelope(t, delegateClient.Rx)\n}\n\n/*\n  DHT network: all-to-all\n*/\n\n/*\n\t\t\t\t\t\t\t\t\t  Network topology\n\n\t DHTClient -------                                                 -- DelegateClient\n\t\t\t\t\t |                                                 |\n\t DHTClient -------                                                 -- DelegateClient\n\t\t\t\t\t |                                                 |\n\t\t\t\t\t |-- DHTPeer --- DHTPeeer -- DHTPeer --- DHTPeer --|\n\t\t\t\t\t |                                                 |\n\t DelegateClient --                                                 ------- DHTClient\n*/\n\n// TestRoutingAlltoAll\nfunc TestRoutingAllToAll(t *testing.T) {\n\trxs := []chan *aea.Envelope{}\n\tsend := []func(*aea.Envelope) error{}\n\n\t// setup DHTPeers\n\n\tdhtPeer1, dhtPeerCleanup1, err := SetupLocalDHTPeer(\n\t\tFetchAITestKeys[0], AgentsTestKeys[0], DefaultLocalPort, DefaultDelegatePort,\n\t\t[]string{},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t}\n\tdefer dhtPeerCleanup1()\n\n\trxPeerDHT1 := make(chan *aea.Envelope, 100)\n\tdhtPeer1.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxPeerDHT1 <- envel\n\t\tif string(envel.Message) == \"ping\" {\n\t\t\terr := dhtPeer1.RouteEnvelope(&aea.Envelope{\n\t\t\t\tTo:      envel.Sender,\n\t\t\t\tSender:  envel.To,\n\t\t\t\tMessage: []byte(\"ack\"),\n\t\t\t})\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t})\n\n\trxs = append(rxs, rxPeerDHT1)\n\tsend = append(send, func(envel *aea.Envelope) error {\n\t\treturn dhtPeer1.RouteEnvelope(envel)\n\t})\n\n\tdhtPeer2, dhtPeerCleanup2, err := SetupLocalDHTPeer(\n\t\tFetchAITestKeys[1], AgentsTestKeys[1], DefaultLocalPort+1, DefaultDelegatePort+1,\n\t\t[]string{dhtPeer1.MultiAddr()},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t}\n\tdefer dhtPeerCleanup2()\n\n\trxPeerDHT2 := make(chan *aea.Envelope, 100)\n\tdhtPeer2.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxPeerDHT2 <- envel\n\t\tif string(envel.Message) == \"ping\" {\n\t\t\terr := dhtPeer2.RouteEnvelope(&aea.Envelope{\n\t\t\t\tTo:      envel.Sender,\n\t\t\t\tSender:  envel.To,\n\t\t\t\tMessage: []byte(\"ack\"),\n\t\t\t})\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t})\n\n\trxs = append(rxs, rxPeerDHT2)\n\n\tsend = append(send, func(envel *aea.Envelope) error {\n\t\treturn dhtPeer2.RouteEnvelope(envel)\n\t})\n\n\tdhtPeer3, dhtPeerCleanup3, err := SetupLocalDHTPeer(\n\t\tFetchAITestKeys[2], AgentsTestKeys[2], DefaultLocalPort+2, DefaultDelegatePort+2,\n\t\t[]string{dhtPeer1.MultiAddr()},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t}\n\tdefer dhtPeerCleanup3()\n\n\trxPeerDHT3 := make(chan *aea.Envelope, 100)\n\tdhtPeer3.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxPeerDHT3 <- envel\n\t\tif string(envel.Message) == \"ping\" {\n\t\t\terr := dhtPeer3.RouteEnvelope(&aea.Envelope{\n\t\t\t\tTo:      envel.Sender,\n\t\t\t\tSender:  envel.To,\n\t\t\t\tMessage: []byte(\"ack\"),\n\t\t\t})\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t})\n\n\trxs = append(rxs, rxPeerDHT3)\n\tsend = append(send, func(envel *aea.Envelope) error {\n\t\treturn dhtPeer3.RouteEnvelope(envel)\n\t})\n\n\tdhtPeer4, dhtPeerCleanup4, err := SetupLocalDHTPeer(\n\t\tFetchAITestKeys[3], AgentsTestKeys[3], DefaultLocalPort+3, DefaultDelegatePort+3,\n\t\t[]string{dhtPeer2.MultiAddr()},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t}\n\tdefer dhtPeerCleanup4()\n\n\trxPeerDHT4 := make(chan *aea.Envelope, 100)\n\tdhtPeer4.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxPeerDHT4 <- envel\n\t\tif string(envel.Message) == \"ping\" {\n\t\t\terr := dhtPeer4.RouteEnvelope(&aea.Envelope{\n\t\t\t\tTo:      envel.Sender,\n\t\t\t\tSender:  envel.To,\n\t\t\t\tMessage: []byte(\"ack\"),\n\t\t\t})\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t})\n\n\trxs = append(rxs, rxPeerDHT4)\n\tsend = append(send, func(envel *aea.Envelope) error {\n\t\treturn dhtPeer4.RouteEnvelope(envel)\n\t})\n\n\t// setup DHTClients\n\n\tdhtClient1, dhtClientCleanup1, err := SetupDHTClient(\n\t\tFetchAITestKeys[4], AgentsTestKeys[4], []string{dhtPeer3.MultiAddr()},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTClient:\", err)\n\t}\n\tdefer dhtClientCleanup1()\n\n\trxClientDHT1 := make(chan *aea.Envelope, 100)\n\tdhtClient1.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxClientDHT1 <- envel\n\t\tif string(envel.Message) == \"ping\" {\n\t\t\terr := dhtClient1.RouteEnvelope(&aea.Envelope{\n\t\t\t\tTo:      envel.Sender,\n\t\t\t\tSender:  envel.To,\n\t\t\t\tMessage: []byte(\"ack\"),\n\t\t\t})\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t})\n\n\trxs = append(rxs, rxClientDHT1)\n\tsend = append(send, func(envel *aea.Envelope) error {\n\t\treturn dhtClient1.RouteEnvelope(envel)\n\t})\n\n\tdhtClient2, dhtClientCleanup2, err := SetupDHTClient(\n\t\tFetchAITestKeys[5], AgentsTestKeys[5], []string{dhtPeer3.MultiAddr()},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTClient:\", err)\n\t}\n\tdefer dhtClientCleanup2()\n\n\trxClientDHT2 := make(chan *aea.Envelope, 100)\n\tdhtClient2.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxClientDHT2 <- envel\n\t\tif string(envel.Message) == \"ping\" {\n\t\t\terr := dhtClient2.RouteEnvelope(&aea.Envelope{\n\t\t\t\tTo:      envel.Sender,\n\t\t\t\tSender:  envel.To,\n\t\t\t\tMessage: []byte(\"ack\"),\n\t\t\t})\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t})\n\n\trxs = append(rxs, rxClientDHT2)\n\tsend = append(send, func(envel *aea.Envelope) error {\n\t\treturn dhtClient2.RouteEnvelope(envel)\n\t})\n\n\tdhtClient3, dhtClientCleanup3, err := SetupDHTClient(\n\t\tFetchAITestKeys[6], AgentsTestKeys[6], []string{dhtPeer4.MultiAddr()},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTClient:\", err)\n\t}\n\tdefer dhtClientCleanup3()\n\n\trxClientDHT3 := make(chan *aea.Envelope, 100)\n\tdhtClient3.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxClientDHT3 <- envel\n\t\tif string(envel.Message) == \"ping\" {\n\t\t\terr := dhtClient3.RouteEnvelope(&aea.Envelope{\n\t\t\t\tTo:      envel.Sender,\n\t\t\t\tSender:  envel.To,\n\t\t\t\tMessage: []byte(\"ack\"),\n\t\t\t})\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t})\n\n\trxs = append(rxs, rxClientDHT3)\n\tsend = append(send, func(envel *aea.Envelope) error {\n\t\treturn dhtClient3.RouteEnvelope(envel)\n\t})\n\n\t// setup DelegateClients\n\n\tdelegateClient1, delegateClientCleanup1, err := SetupDelegateClient(\n\t\tAgentsTestKeys[7], DefaultLocalHost, DefaultDelegatePort+2, FetchAITestPublicKeys[2],\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DelegateClient:\", err)\n\t}\n\tdefer delegateClientCleanup1()\n\n\trxClientDelegate1 := make(chan *aea.Envelope, 100)\n\tdelegateClient1.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxClientDelegate1 <- envel\n\t\tif string(envel.Message) == \"ping\" {\n\t\t\terr := delegateClient1.Send(&aea.Envelope{\n\t\t\t\tTo:      envel.Sender,\n\t\t\t\tSender:  envel.To,\n\t\t\t\tMessage: []byte(\"ack\"),\n\t\t\t})\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t})\n\n\trxs = append(rxs, rxClientDelegate1)\n\tsend = append(send, func(envel *aea.Envelope) error {\n\t\treturn delegateClient1.Send(envel)\n\t})\n\n\tdelegateClient2, delegateClientCleanup2, err := SetupDelegateClient(\n\t\tAgentsTestKeys[8], DefaultLocalHost, DefaultDelegatePort+3, FetchAITestPublicKeys[3],\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DelegateClient:\", err)\n\t}\n\tdefer delegateClientCleanup2()\n\n\trxClientDelegate2 := make(chan *aea.Envelope, 100)\n\tdelegateClient2.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxClientDelegate2 <- envel\n\t\tif string(envel.Message) == \"ping\" {\n\t\t\terr := delegateClient2.Send(&aea.Envelope{\n\t\t\t\tTo:      envel.Sender,\n\t\t\t\tSender:  envel.To,\n\t\t\t\tMessage: []byte(\"ack\"),\n\t\t\t})\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t})\n\n\trxs = append(rxs, rxClientDelegate2)\n\tsend = append(send, func(envel *aea.Envelope) error {\n\t\treturn delegateClient2.Send(envel)\n\t})\n\n\tdelegateClient3, delegateClientCleanup3, err := SetupDelegateClient(\n\t\tAgentsTestKeys[9], DefaultLocalHost, DefaultDelegatePort+3, FetchAITestPublicKeys[3],\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DelegateClient:\", err)\n\t}\n\tdefer delegateClientCleanup3()\n\n\trxClientDelegate3 := make(chan *aea.Envelope, 100)\n\tdelegateClient3.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxClientDelegate3 <- envel\n\t\tif string(envel.Message) == \"ping\" {\n\t\t\terr := delegateClient3.Send(&aea.Envelope{\n\t\t\t\tTo:      envel.Sender,\n\t\t\t\tSender:  envel.To,\n\t\t\t\tMessage: []byte(\"ack\"),\n\t\t\t})\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t})\n\n\trxs = append(rxs, rxClientDelegate3)\n\tsend = append(send, func(envel *aea.Envelope) error {\n\t\treturn delegateClient3.Send(envel)\n\t})\n\n\t// Send envelope from everyone to everyone else and expect an echo back\n\n\tensureAddressAnnounced(dhtPeer1, dhtPeer2, dhtPeer3, dhtPeer4)\n\n\tfor i := range AgentsTestAddresses {\n\t\tfor j := range AgentsTestAddresses {\n\t\t\tfrom := len(AgentsTestAddresses) - 1 - i\n\t\t\ttarget := j\n\n\t\t\t// Should be able to route to self though\n\t\t\tif from == target {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\terr := send[from](&aea.Envelope{\n\t\t\t\tTo:      AgentsTestAddresses[target],\n\t\t\t\tSender:  AgentsTestAddresses[from],\n\t\t\t\tMessage: []byte(\"ping\"),\n\t\t\t})\n\n\t\t\tif err != nil {\n\t\t\t\tt.Error(\"Failed to RouteEnvelope from \", from, \"to\", target)\n\t\t\t}\n\t\t}\n\t}\n\tfor i := range AgentsTestAddresses {\n\t\tfor j := range AgentsTestAddresses {\n\t\t\tfrom := len(AgentsTestAddresses) - 1 - i\n\t\t\ttarget := j\n\t\t\tif from == target {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\texpectEnvelope(t, rxs[target])\n\t\t\texpectEnvelope(t, rxs[from])\n\t\t}\n\t}\n\n}\n\n/*\n  Helpers\n  TOFIX(LR) how to share test helpers between packages tests\n   without having circular dependencies\n*/\n\nfunc randSeq(n int) string {\n\trand.Seed(time.Now().UnixNano())\n\tvar letters = []rune(\"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\")\n\tb := make([]rune, n)\n\tfor i := range b {\n\t\tb[i] = letters[rand.Intn(len(letters))]\n\t}\n\treturn string(b)\n}\n\nfunc SetupLocalDHTPeer(\n\tkey string,\n\tagentKey string,\n\tdhtPort uint16,\n\tdelegatePort uint16,\n\tentry []string,\n) (*DHTPeer, func(), error) {\n\topts := []Option{\n\t\tLocalURI(DefaultLocalHost, dhtPort),\n\t\tPublicURI(DefaultLocalHost, dhtPort),\n\t\tIdentityFromFetchAIKey(key),\n\t\tEnableRelayService(),\n\t\tBootstrapFrom(entry),\n\t\tStoreRecordsTo(path.Join(os.TempDir(), \"agents_records_\"+randSeq(5))),\n\t}\n\n\tif agentKey != \"\" {\n\t\tagentPubKey, err := utils.FetchAIPublicKeyFromFetchAIPrivateKey(agentKey)\n\t\tif err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\n\t\tagentAddress, err := utils.FetchAIAddressFromPublicKey(agentPubKey)\n\t\tif err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\n\t\tpeerPubKey, err := utils.FetchAIPublicKeyFromFetchAIPrivateKey(key)\n\t\tif err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\n\t\tsignature, err := utils.SignFetchAI([]byte(peerPubKey), agentKey)\n\t\tif err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\n\t\trecord := &acn.AgentRecord{LedgerId: DefaultLedger}\n\t\trecord.Address = agentAddress\n\t\trecord.PublicKey = agentPubKey\n\t\trecord.PeerPublicKey = peerPubKey\n\t\trecord.Signature = signature\n\n\t\topts = append(opts, RegisterAgentAddress(record, func() bool { return true }))\n\t}\n\n\tif delegatePort != 0 {\n\t\topts = append(opts, EnableDelegateService(delegatePort))\n\t}\n\n\tdhtPeer, err := New(opts...)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\treturn dhtPeer, func() { println(\"dhtpeer going to be closed!\"); dhtPeer.Close() }, nil\n\n}\n\n// DHTClient\n\nfunc SetupDHTClient(\n\tkey string,\n\tagentKey string,\n\tentry []string,\n) (*dhtclient.DHTClient, func(), error) {\n\n\tagentPubKey, err := utils.FetchAIPublicKeyFromFetchAIPrivateKey(agentKey)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tagentAddress, err := utils.FetchAIAddressFromPublicKey(agentPubKey)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tpeerPubKey, err := utils.FetchAIPublicKeyFromFetchAIPrivateKey(key)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tsignature, err := utils.SignFetchAI([]byte(peerPubKey), agentKey)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\trecord := &acn.AgentRecord{LedgerId: DefaultLedger}\n\trecord.Address = agentAddress\n\trecord.PublicKey = agentPubKey\n\trecord.PeerPublicKey = peerPubKey\n\trecord.Signature = signature\n\n\topts := []dhtclient.Option{\n\t\tdhtclient.IdentityFromFetchAIKey(key),\n\t\tdhtclient.RegisterAgentAddress(record, func() bool { return true }),\n\t\tdhtclient.BootstrapFrom(entry),\n\t}\n\n\tdhtClient, err := dhtclient.New(opts...)\n\tif err != nil {\n\t\tprintln(\"dhtclient.New:\", err.Error())\n\t\treturn nil, nil, err\n\t}\n\n\treturn dhtClient, func() { println(\"dhtclient going to be closed!\"); dhtClient.Close() }, nil\n}\n\n// Delegate tcp client for tests only\n\ntype DelegateClient struct {\n\tAgentAddress    string\n\tAgentKey        string\n\tAgentPubKey     string\n\tPeerPubKey      string\n\tPoR             string\n\tRx              chan *aea.Envelope\n\tConn            net.Conn\n\tprocessEnvelope func(*aea.Envelope) error\n\tacn_status_chan chan *acn.StatusBody\n}\n\nfunc (client *DelegateClient) AddAcnStatusMessage(status *acn.StatusBody, counterpartyID string) {\n\t//client.acn_status_chan <- status\n}\n\nfunc (client *DelegateClient) Close() error {\n\treturn client.Conn.Close()\n}\n\nfunc (client *DelegateClient) Send(envelope *aea.Envelope) error {\n\tdata, err := aea.MakeAcnMessageFromEnvelope(envelope)\n\tif err != nil {\n\t\tprintln(\"while serializing envelope:\", err.Error())\n\t\treturn err\n\t}\n\terr = utils.WriteBytesConn(client.Conn, data)\n\tif err != nil {\n\t\tprintln(\"while sending envelope:\", err.Error())\n\t\treturn err\n\t}\n\treturn err\n}\n\nfunc (client *DelegateClient) ProcessEnvelope(fn func(*aea.Envelope) error) {\n\tclient.processEnvelope = fn\n}\n\nfunc ValidateTLSSignature(\n\ttlsSignature []byte,\n\tsessionPubKey *ecdsa.PublicKey,\n\tpeerPubKey string,\n) error {\n\tsessionPubKeyBytes := elliptic.Marshal(sessionPubKey.Curve, sessionPubKey.X, sessionPubKey.Y)\n\tverifyKey, err := utils.PubKeyFromFetchAIPublicKey(peerPubKey)\n\tif err != nil {\n\t\treturn err\n\t}\n\tok, err := verifyKey.Verify(sessionPubKeyBytes, tlsSignature)\n\n\tif err != nil {\n\t\treturn err\n\t}\n\tif !ok {\n\t\treturn errors.New(\"error on signature validation for tls start\")\n\t}\n\treturn nil\n}\n\nfunc SetupDelegateClient(\n\tkey string,\n\thost string,\n\tport uint16,\n\tpeerPubKey string,\n) (*DelegateClient, func(), error) {\n\tvar err error\n\tclient := &DelegateClient{}\n\tclient.AgentKey = key\n\n\tclient.acn_status_chan = make(chan *acn.StatusBody, 10000)\n\n\tpubKey, err := utils.FetchAIPublicKeyFromFetchAIPrivateKey(key)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\tclient.AgentPubKey = pubKey\n\n\taddress, err := utils.FetchAIAddressFromPublicKey(pubKey)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\tclient.AgentAddress = address\n\n\tsignature, err := utils.SignFetchAI([]byte(peerPubKey), key)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\tclient.PoR = signature\n\n\tclient.Rx = make(chan *aea.Envelope, 2)\n\tconf := &tls.Config{\n\t\tInsecureSkipVerify: true,\n\t}\n\tclient.Conn, err = tls.Dial(\"tcp\", host+\":\"+strconv.FormatInt(int64(port), 10), conf)\n\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tcertPubKey := client.Conn.(*tls.Conn).ConnectionState().PeerCertificates[0].PublicKey.(*ecdsa.PublicKey)\n\n\ttlsSignature, _ := utils.ReadBytesConn(client.Conn)\n\terr = ValidateTLSSignature(tlsSignature, certPubKey, peerPubKey)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\trecord := &acn.AgentRecord{LedgerId: DefaultLedger}\n\trecord.Address = address\n\trecord.PublicKey = pubKey\n\trecord.PeerPublicKey = peerPubKey\n\trecord.Signature = signature\n\tregistration := &acn.RegisterPerformative{Record: record}\n\tmsg := &acn.AcnMessage{\n\t\tPerformative: &acn.Register{Register: registration},\n\t}\n\tdata, err := proto.Marshal(msg)\n\tignore(err)\n\terr = utils.WriteBytesConn(client.Conn, data)\n\tignore(err)\n\tdata, err = utils.ReadBytesConn(client.Conn)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\tresponse := &acn.AcnMessage{}\n\terr = proto.Unmarshal(data, response)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\t// Get Status message\n\tvar status *acn.StatusPerformative\n\tswitch pl := response.Performative.(type) {\n\tcase *acn.Status:\n\t\tstatus = pl.Status\n\tdefault:\n\t\treturn nil, nil, err\n\t}\n\n\tif status.Body.Code != acn.SUCCESS {\n\t\tprintln(\"Registration error:\", status.Body.String())\n\t\treturn nil, nil, errors.New(status.Body.String())\n\t}\n\n\tpipe := utils.ConnPipe{Conn: client.Conn}\n\tgo func() {\n\t\tfor {\n\t\t\tenvel, err := aea.HandleAcnMessageFromPipe(pipe, client, \"\")\n\t\t\tif err != nil {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tif envel == nil {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\t_ = acn.SendAcnSuccess(pipe)\n\n\t\t\tif client.processEnvelope != nil {\n\t\t\t\terr = client.processEnvelope(envel)\n\t\t\t\tignore(err)\n\t\t\t} else {\n\t\t\t\tclient.Rx <- envel\n\t\t\t}\n\t\t}\n\t}()\n\n\treturn client, func() { client.Close() }, nil\n}\n\nfunc expectEnvelope(t *testing.T, rx chan *aea.Envelope) {\n\ttimeout := time.After(EnvelopeDeliveryTimeout)\n\tselect {\n\tcase envel := <-rx:\n\t\tt.Log(\"Received envelope\", envel)\n\tcase <-timeout:\n\t\tt.Error(\"Failed to receive envelope before timeout\")\n\t}\n}\n\nfunc expectEnvelopeOrdered(t *testing.T, rx chan *aea.Envelope, counter int) {\n\ttimeout := time.After(EnvelopeDeliveryTimeout)\n\tselect {\n\tcase envel := <-rx:\n\t\tt.Log(\"Received envelope\", envel)\n\t\tif envel == nil {\n\t\t\tt.Log(\"Empty envelope. exit\")\n\t\t\treturn\n\t\t}\n\t\tmessage, _ := strconv.Atoi(string(envel.Message))\n\t\tif message != counter {\n\t\t\tlog.Fatalf(\"Expected counter %d received counter %d\", counter, message)\n\t\t}\n\tcase <-timeout:\n\t\tt.Error(\"Failed to receive envelope before timeout\")\n\t}\n}\n\nfunc ensureAddressAnnounced(peers ...*DHTPeer) {\n\tfor _, peer := range peers {\n\t\tctx, cancel := context.WithTimeout(context.Background(), DHTPeerSetupTimeout)\n\t\tdefer cancel()\n\tL:\n\t\tfor !peer.IsAddressAnnounced(peer.myAgentAddress) {\n\t\t\tselect {\n\t\t\tcase <-ctx.Done():\n\t\t\t\tbreak L\n\t\t\tcase <-time.After(5 * time.Millisecond):\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc TestFetchAICrypto(t *testing.T) {\n\tpublicKey := \"02358e3e42a6ba15cf6b2ba6eb05f02b8893acf82b316d7dd9cda702b0892b8c71\"\n\taddress := \"fetch19dq2mkcpp6x0aypxt9c9gz6n4fqvax0x9a7t5r\"\n\tpeerPublicKey := \"027af21aff853b9d9589867ea142b0a60a9611fc8e1fae04c2f7144113fa4e938e\"\n\tpySigStrCanonize := \"N/GOa7/m3HU8/gpLJ88VCQ6vXsdrfiiYcqnNtF+c2N9VG9ZIiycykN4hdbpbOCGrChMYZQA3G1GpozsShrUBgg==\"\n\n\taddressFromPublicKey, _ := utils.FetchAIAddressFromPublicKey(publicKey)\n\tif address != addressFromPublicKey {\n\t\tt.Error(\"[ERR] Addresses don't match\")\n\t} else {\n\t\tt.Log(\"[OK] Agent address matches its public key\")\n\t}\n\n\tvalid, err := utils.VerifyFetchAISignatureBTC(\n\t\t[]byte(peerPublicKey),\n\t\tpySigStrCanonize,\n\t\tpublicKey,\n\t)\n\tif !valid {\n\t\tt.Errorf(\"Signature using BTC don't match %s\", err.Error())\n\t}\n\tvalid, err = utils.VerifyFetchAISignatureLibp2p(\n\t\t[]byte(peerPublicKey),\n\t\tpySigStrCanonize,\n\t\tpublicKey,\n\t)\n\tif !valid {\n\t\tt.Errorf(\"Signature using LPP don't match %s\", err.Error())\n\t}\n}\n\nfunc TestEthereumCrypto(t *testing.T) {\n\t//privateKey := \"0xb60fe8027fb82f1a1bd6b8e66d4400f858989a2c67428a4e7f589441700339b0\"\n\tpublicKey := \"0xf753e5a9e2368e97f4db869a0d956d3ffb64672d6392670572906c786b5712ada13b6bff882951b3ba3dd65bdacc915c2b532efc3f183aa44657205c6c337225\"\n\taddress := \"0xb8d8c62d4a1999b7aea0aebBD5020244a4a9bAD8\"\n\tpublicKeySignature := \"0x304c2ba4ae7fa71295bfc2920b9c1268d574d65531f1f4d2117fc1439a45310c37ab75085a9df2a4169a4d47982b330a4387b1ded0c8881b030629db30bbaf3a1c\"\n\n\taddFromPublicKey, err := utils.EthereumAddressFromPublicKey(publicKey)\n\tif err != nil || addFromPublicKey != address {\n\t\tt.Error(\n\t\t\t\"Error when computing address from public key or address and public key don't match\",\n\t\t)\n\t}\n\n\t_, err = utils.BTCPubKeyFromEthereumPublicKey(publicKey)\n\tif err != nil {\n\t\tt.Errorf(\"While building BTC public key from string: %s\", err.Error())\n\t}\n\n\t/*\n\t\t  ethSig, err := secp256k1.Sign(hashedPublicKey, hexutil.MustDecode(privateKey))\n\t\t  if err != nil {\n\t\t\t  t.Error(err.Error())\n\t\t  }\n\t\t  println(hexutil.Encode(ethSig))\n\t\t  hash := sha3.NewLegacyKeccak256()\n\t\t  _, err = hash.Write([]byte(publicKey))\n\t\t  if err != nil {\n\t\t\t  t.Error(err.Error())\n\t\t  }\n\t\t  sha3KeccakHash := hash.Sum(nil)\n\t*/\n\n\tvalid, err := utils.VerifyEthereumSignatureETH([]byte(publicKey), publicKeySignature, publicKey)\n\tif err != nil {\n\t\tt.Error(err.Error())\n\t}\n\n\tif !valid {\n\t\tt.Errorf(\"Signer address don't match %s\", addFromPublicKey)\n\t}\n}\n\n// Perform tests for tls signature generation and checking\nfunc TestTLSSignatureValidation(t *testing.T) {\n\tkey1, pubKey, _ := utils.KeyPairFromFetchAIKey(FetchAITestKeys[0])\n\tkey2, _, _ := utils.KeyPairFromFetchAIKey(FetchAITestKeys[1])\n\tpeerPubKey, _ := utils.FetchAIPublicKeyFromPubKey(pubKey)\n\n\tcert, err := generate_x509_cert()\n\tsessionPubKey := cert.PrivateKey.(*ecdsa.PrivateKey).Public().(*ecdsa.PublicKey)\n\n\tif err != nil {\n\t\tt.Fatal(\"Failed to generate certificate\")\n\t}\n\n\t// valid\n\ttlsSignature, err := makeSessionKeySignature(cert, key1)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to make signature\")\n\t}\n\terr = ValidateTLSSignature(tlsSignature, sessionPubKey, peerPubKey)\n\tif err != nil {\n\t\tt.Fatal(\"Signature is invalid, but expected to be ok\")\n\t}\n\n\t//invalid\n\ttlsSignature, err = makeSessionKeySignature(cert, key2)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to make signature\")\n\t}\n\terr = ValidateTLSSignature(tlsSignature, sessionPubKey, peerPubKey)\n\tif err == nil {\n\t\tt.Fatal(\"Signature is valid, but shoud not\")\n\t}\n}\n"
  },
  {
    "path": "libs/go/libp2p_node/dht/dhtpeer/mailbox.go",
    "content": "package dhtpeer\n\nimport (\n\t\"context\"\n\t\"crypto/tls\"\n\t\"io/ioutil\"\n\tacn \"libp2p_node/acn\"\n\taea \"libp2p_node/aea\"\n\t\"net/http\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/google/uuid\"\n\t\"google.golang.org/protobuf/proto\"\n)\n\nfunc (mailboxServer *MailboxServer) apiRegister(res http.ResponseWriter, req *http.Request) {\n\tvar data []byte\n\tvar body []byte\n\tvar err error\n\n\tif req.Method != \"POST\" {\n\t\tdata = []byte(\"invalid method\")\n\t\tres.WriteHeader(400)\n\t\t_, err = res.Write(data)\n\t\tignore(err)\n\t\treturn\n\t}\n\tbody, err = ioutil.ReadAll(req.Body)\n\tif err != nil {\n\t\tres.WriteHeader(400)\n\t\t_, err = res.Write([]byte(err.Error()))\n\t\tignore(err)\n\t\treturn\n\n\t}\n\t//get por\n\tif len(body) == 0 {\n\t\tres.WriteHeader(400)\n\t\t_, err = res.Write([]byte(\"Empty body\"))\n\t\tignore(err)\n\t\treturn\n\t}\n\trecord := &acn.AgentRecord{}\n\terr = proto.Unmarshal(body, record)\n\tif err != nil {\n\t\tres.WriteHeader(400)\n\t\t_, err = res.Write([]byte(\"Error on agent record deserialize\"))\n\t\tignore(err)\n\t\treturn\n\t}\n\taddr := record.Address\n\n\t// TODO: double register fix!!!\n\n\t//check por\n\tstatus, err := mailboxServer.dhtPeer.CheckPOR(record)\n\tif err != nil || status.Code != acn.SUCCESS {\n\t\tres.WriteHeader(400)\n\t\t_, err = res.Write([]byte(\"Invalid PoR\"))\n\t\tignore(err)\n\t\treturn\n\t}\n\tuuid := strings.ReplaceAll(uuid.NewString(), \"-\", \"\")\n\tif mailboxServer.dhtPeer.IsAddressAnnouncementEnabled() {\n\t\terr = mailboxServer.dhtPeer.RegisterAgentAddress(addr)\n\t\tif err != nil {\n\t\t\tres.WriteHeader(400)\n\t\t\t_, err = res.Write([]byte(\"failed to register address over dht\"))\n\t\t\tignore(err)\n\t\t\treturn\n\t\t}\n\t}\n\n\tmailboxServer.lock.Lock()\n\tmailboxServer.agentRecords[addr] = record\n\tmailboxServer.sessions[uuid] = addr\n\tmailboxServer.envelopes[addr] = make([]*aea.Envelope, 0)\n\tmailboxServer.lock.Unlock()\n\n\tres.WriteHeader(200)\n\t_, err = res.Write([]byte(uuid))\n\tignore(err)\n}\n\nfunc (mailboxServer *MailboxServer) apiUnregister(res http.ResponseWriter, req *http.Request) {\n\tvar data []byte\n\tvar err error\n\tvar addr string\n\tvar sessionId string\n\n\tif req.Method != \"GET\" {\n\t\tdata = []byte(\"invalid method\")\n\t\tres.WriteHeader(400)\n\t\t_, err = res.Write(data)\n\t\tignore(err)\n\t\treturn\n\t}\n\tsession_header, exists := req.Header[\"Session-Id\"]\n\n\tif exists {\n\t\tsessionId = session_header[0]\n\t\tmailboxServer.lock.Lock()\n\t\taddr, exists = mailboxServer.sessions[sessionId]\n\t\tmailboxServer.lock.Unlock()\n\t}\n\n\tif !exists {\n\t\tres.WriteHeader(400)\n\t\t_, err = res.Write([]byte(\"invalid session_id header\"))\n\t\tignore(err)\n\t\treturn\n\t}\n\n\tmailboxServer.lock.Lock()\n\tdelete(mailboxServer.agentRecords, addr)\n\tdelete(mailboxServer.sessions, sessionId)\n\tdelete(mailboxServer.envelopes, addr)\n\tmailboxServer.lock.Unlock()\n\n}\n\nfunc (mailboxServer *MailboxServer) apiGetSignature(res http.ResponseWriter, req *http.Request) {\n\tvar err error\n\tif req.Method != \"GET\" {\n\t\tres.WriteHeader(400)\n\t\t_, err = res.Write([]byte(\"invalid method\"))\n\t\tignore(err)\n\t\treturn\n\t}\n\tres.WriteHeader(200)\n\t_, err = res.Write(mailboxServer.signature)\n\tignore(err)\n}\n\nfunc (mailboxServer *MailboxServer) apiSendEnvelope(res http.ResponseWriter, req *http.Request) {\n\tvar err error\n\tif req.Method != \"POST\" {\n\t\tres.WriteHeader(400)\n\t\t_, err = res.Write([]byte(\"invalid method\"))\n\t\tignore(err)\n\t\treturn\n\t}\n\n\tsession_header, exists := req.Header[\"Session-Id\"]\n\n\tif exists {\n\t\tsessionId := session_header[0]\n\t\tmailboxServer.lock.Lock()\n\t\t_, exists = mailboxServer.sessions[sessionId]\n\t\tmailboxServer.lock.Unlock()\n\t}\n\n\tif !exists {\n\t\tres.WriteHeader(400)\n\t\t_, err = res.Write([]byte(\"invalid session_id header\"))\n\t\tignore(err)\n\t\treturn\n\t}\n\n\tbody, err := ioutil.ReadAll(req.Body)\n\tif err != nil {\n\t\tres.WriteHeader(400)\n\t\t_, err = res.Write([]byte(err.Error()))\n\t\tignore(err)\n\t\treturn\n\t}\n\t//getenvelope\n\tif len(body) == 0 {\n\t\tres.WriteHeader(400)\n\t\t_, err = res.Write([]byte(\"Empty body\"))\n\t\tignore(err)\n\t\treturn\n\t}\n\tenvelope := &aea.Envelope{}\n\terr = proto.Unmarshal(body, envelope)\n\tif err != nil {\n\t\tres.WriteHeader(400)\n\t\t_, err = res.Write([]byte(err.Error()))\n\t\tignore(err)\n\t\treturn\n\t}\n\terr = mailboxServer.dhtPeer.RouteEnvelope(envelope)\n\tif err != nil {\n\t\tres.WriteHeader(400)\n\t\t_, err = res.Write([]byte(err.Error()))\n\t\tignore(err)\n\t}\n}\n\nfunc (mailboxServer *MailboxServer) apiGetEnvelope(res http.ResponseWriter, req *http.Request) {\n\tvar buf []byte\n\tvar envelopesList []*aea.Envelope\n\tvar err error\n\tvar addr string\n\n\tif req.Method != \"GET\" {\n\t\tres.WriteHeader(400)\n\t\t_, err = res.Write([]byte(\"invalid method\"))\n\t\tignore(err)\n\t\treturn\n\t}\n\n\tsession_header, exists := req.Header[\"Session-Id\"]\n\n\tmailboxServer.lock.Lock()\n\tdefer mailboxServer.lock.Unlock()\n\tif exists {\n\t\tsessionId := session_header[0]\n\t\taddr, exists = mailboxServer.sessions[sessionId]\n\t}\n\tif !exists {\n\t\tres.WriteHeader(400)\n\t\t_, err = res.Write([]byte(\"invalid session_id header\"))\n\t\tignore(err)\n\t\treturn\n\t}\n\tenvelopesList = mailboxServer.envelopes[addr]\n\n\tif len(envelopesList) == 0 {\n\t\tres.WriteHeader(200)\n\t\treturn\n\t}\n\tenvelope := envelopesList[0]\n\tbuf, err = proto.Marshal(envelope)\n\tif err != nil {\n\t\t//log error\n\t\treturn\n\t}\n\tres.WriteHeader(200)\n\n\t_, err = res.Write(buf)\n\tif err == nil {\n\t\t// all ok, remove the first envelope from slice\n\t\tmailboxServer.envelopes[addr] = mailboxServer.envelopes[addr][1:]\n\t}\n}\n\ntype MailboxServer struct {\n\taddr           string\n\tdhtPeer        *DHTPeer\n\thttpServer     *http.Server\n\tsessions       map[string]string\n\tagentRecords   map[string]*acn.AgentRecord\n\tenvelopes      map[string]([]*aea.Envelope)\n\tlock           sync.RWMutex\n\tenvelopesLimit int\n\tcert           *tls.Certificate\n\tsignature      []byte\n}\n\nfunc (mailboxServer *MailboxServer) start() {\n\tvar err error\n\tlerror, _, _, _ := mailboxServer.dhtPeer.GetLoggers()\n\tmailboxServer.envelopes = map[string][]*aea.Envelope{}\n\tmailboxServer.agentRecords = map[string]*acn.AgentRecord{}\n\tmailboxServer.sessions = map[string]string{}\n\tmailboxServer.lock = sync.RWMutex{}\n\tmailboxServer.envelopesLimit = 1000\n\tmailboxServer.cert, mailboxServer.signature = mailboxServer.dhtPeer.GetCertAndSignature()\n\n\tmux := http.NewServeMux()\n\tmux.HandleFunc(\"/register\", mailboxServer.apiRegister)\n\tmux.HandleFunc(\"/unregister\", mailboxServer.apiUnregister)\n\tmux.HandleFunc(\"/get_envelope\", mailboxServer.apiGetEnvelope)\n\tmux.HandleFunc(\"/send_envelope\", mailboxServer.apiSendEnvelope)\n\tmux.HandleFunc(\"/ssl_signature\", mailboxServer.apiGetSignature)\n\n\ttlsConfig := &tls.Config{Certificates: []tls.Certificate{*mailboxServer.cert}}\n\n\tmailboxServer.httpServer = &http.Server{\n\t\tAddr:      mailboxServer.addr,\n\t\tHandler:   mux,\n\t\tTLSConfig: tlsConfig,\n\t}\n\tlistener, err := tls.Listen(\"tcp\", mailboxServer.addr, tlsConfig)\n\tif err != nil {\n\t\tlerror(err).Msgf(\"while setting mailbox tls\")\n\t}\n\terr = mailboxServer.httpServer.Serve(listener)\n\tif err != nil {\n\t\tlerror(err).Msgf(\"while running mailbox http server\")\n\t}\n}\n\nfunc (mailboxServer *MailboxServer) stop() {\n\tvar err error\n\tlerror, _, _, _ := mailboxServer.dhtPeer.GetLoggers()\n\n\tctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)\n\tdefer cancel()\n\terr = mailboxServer.httpServer.Shutdown(ctx)\n\tif err != nil {\n\t\tlerror(err).Msg(\"Error on mailbox http server shutdown\")\n\t}\n}\n\nfunc (mailboxServer *MailboxServer) RouteEnvelope(envelope *aea.Envelope) bool {\n\ttarget := envelope.To\n\t_, _, linfo, _ := mailboxServer.dhtPeer.GetLoggers()\n\tlinfo().Msgf(\"route to %s\", target)\n\n\tmailboxServer.lock.Lock()\n\tdefer mailboxServer.lock.Unlock()\n\tenvelopesList, listExist := mailboxServer.envelopes[target]\n\n\tif !listExist {\n\t\tlinfo().Msgf(\"route to %s. no target\", target)\n\t\treturn false\n\t}\n\t// check chan is full\n\tif mailboxServer.envelopesLimit != 0 &&\n\t\tlen(mailboxServer.envelopes[target]) >= mailboxServer.envelopesLimit {\n\t\tlinfo().Msgf(\"Envelopes queue for  %s is full. (%d envelopes)\", target, mailboxServer.envelopesLimit)\n\t\treturn false\n\t}\n\n\tmailboxServer.envelopes[target] = append(envelopesList, envelope)\n\n\tlinfo().Msgf(\"route to %s. added to queue!\", target)\n\treturn true\n}\n\nfunc (mailboxServer *MailboxServer) IsAddrRegistered(addr string) bool {\n\tmailboxServer.lock.Lock()\n\tdefer mailboxServer.lock.Unlock()\n\t_, listExist := mailboxServer.envelopes[addr]\n\treturn listExist\n}\n\nfunc (mailboxServer *MailboxServer) GetAgentRecord(addr string) *acn.AgentRecord {\n\tif !mailboxServer.IsAddrRegistered(addr) {\n\t\treturn nil\n\t}\n\tmailboxServer.lock.Lock()\n\tdefer mailboxServer.lock.Unlock()\n\treturn mailboxServer.agentRecords[addr]\n}\n"
  },
  {
    "path": "libs/go/libp2p_node/dht/dhtpeer/notifee.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2022 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\n\n// Package dhtpeer provides an implementation of an Agent Communication Network node\n// using libp2p. It participates in data storage and routing for the network.\n// It offers RelayService for dhtclient and DelegateService for tcp clients.\npackage dhtpeer\n\nimport (\n\t\"github.com/libp2p/go-libp2p-core/network\"\n\t\"github.com/multiformats/go-multiaddr\"\n\t\"github.com/rs/zerolog\"\n)\n\n// Notifee Handle DHTClient network events\ntype Notifee struct {\n\tlogger zerolog.Logger\n}\n\n// Listen called when network starts listening on an addr\nfunc (notifee *Notifee) Listen(network.Network, multiaddr.Multiaddr) {}\n\n// ListenClose called when network stops listening on an addr\nfunc (notifee *Notifee) ListenClose(network.Network, multiaddr.Multiaddr) {}\n\n// Connected called when a connection opened\nfunc (notifee *Notifee) Connected(net network.Network, conn network.Conn) {\n\tnotifee.logger.Info().Msgf(\n\t\t\"Connected to peer %s\",\n\t\tconn.RemotePeer().Pretty(),\n\t)\n\n}\n\n// Disconnected called when a connection closed\n// Reconnects if connection is to relay peer and not currenctly closing connection.\nfunc (notifee *Notifee) Disconnected(net network.Network, conn network.Conn) {\n\tnotifee.logger.Info().Msgf(\n\t\t\"Disconnected from peer %s\",\n\t\tconn.RemotePeer().Pretty(),\n\t)\n}\n\n// OpenedStream called when a stream opened\nfunc (notifee *Notifee) OpenedStream(network.Network, network.Stream) {}\n\n// ClosedStream called when a stream closed\nfunc (notifee *Notifee) ClosedStream(network.Network, network.Stream) {}\n"
  },
  {
    "path": "libs/go/libp2p_node/dht/dhtpeer/options.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2019 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\n\npackage dhtpeer\n\nimport (\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/multiformats/go-multiaddr\"\n\t\"github.com/rs/zerolog\"\n\n\tacn \"libp2p_node/acn\"\n\tutils \"libp2p_node/utils\"\n)\n\n// Option for dhtpeer.New\ntype Option func(*DHTPeer) error\n\n// IdentityFromFetchAIKey for dhtpeer.New\nfunc IdentityFromFetchAIKey(key string) Option {\n\treturn func(dhtPeer *DHTPeer) error {\n\t\tvar err error\n\t\tdhtPeer.key, dhtPeer.publicKey, err = utils.KeyPairFromFetchAIKey(key)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t}\n}\n\n// RegisterAgentAddress for dhtpeer.New\nfunc RegisterAgentAddress(record *acn.AgentRecord, isReady func() bool) Option {\n\treturn func(dhtPeer *DHTPeer) error {\n\t\tpbRecord := &acn.AgentRecord{}\n\t\tpbRecord.Address = record.Address\n\t\tpbRecord.PublicKey = record.PublicKey\n\t\tpbRecord.PeerPublicKey = record.PeerPublicKey\n\t\tpbRecord.Signature = record.Signature\n\t\tpbRecord.ServiceId = record.ServiceId\n\t\tpbRecord.LedgerId = record.LedgerId\n\n\t\tdhtPeer.myAgentAddress = record.Address\n\t\tdhtPeer.myAgentRecord = pbRecord\n\t\tdhtPeer.myAgentReady = isReady\n\t\treturn nil\n\t}\n}\n\n// BootstrapFrom for dhtpeer.New\nfunc BootstrapFrom(entryPeers []string) Option {\n\treturn func(dhtPeer *DHTPeer) error {\n\t\tvar err error\n\t\tdhtPeer.bootstrapPeers, err = utils.GetPeersAddrInfo(entryPeers)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t}\n}\n\n// LocalURI for dhtpeer.New\nfunc LocalURI(host string, port uint16) Option {\n\treturn func(dhtPeer *DHTPeer) error {\n\t\tvar err error\n\t\tdhtPeer.localMultiaddr, err =\n\t\t\tmultiaddr.NewMultiaddr(fmt.Sprintf(\"/ip4/%s/tcp/%d\", host, port))\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tdhtPeer.host = host\n\t\tdhtPeer.port = port\n\t\treturn nil\n\t}\n}\n\n// PublicURI for dhtpeer.New\nfunc PublicURI(host string, port uint16) Option {\n\treturn func(dhtPeer *DHTPeer) error {\n\t\tvar err error\n\t\tdhtPeer.publicMultiaddr, err =\n\t\t\tmultiaddr.NewMultiaddr(fmt.Sprintf(\"/dns4/%s/tcp/%d\", host, port))\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tdhtPeer.publicHost = host\n\t\tdhtPeer.publicPort = port\n\t\treturn nil\n\t}\n}\n\n// EnableDelegateService for dhtpeer.New\nfunc EnableDelegateService(port uint16) Option {\n\treturn func(dhtPeer *DHTPeer) error {\n\t\tdhtPeer.delegatePort = port\n\t\treturn nil\n\t}\n}\n\n// EnableMailboxService for dhtpeer.New\nfunc EnableMailboxService(hostport string) Option {\n\treturn func(dhtPeer *DHTPeer) error {\n\t\tdhtPeer.mailboxHostPort = hostport\n\t\treturn nil\n\t}\n}\n\n// EnableRelayService for dhtpeer.New\nfunc EnableRelayService() Option {\n\treturn func(dhtPeer *DHTPeer) error {\n\t\tdhtPeer.enableRelay = true\n\t\treturn nil\n\t}\n\n}\n\n// LoggingLevel for dhtpeer.New\nfunc LoggingLevel(lvl zerolog.Level) Option {\n\treturn func(dhtPeer *DHTPeer) error {\n\t\tdhtPeer.logger = dhtPeer.logger.Level(lvl)\n\t\treturn nil\n\t}\n}\n\n// EnablePrometheusMonitoring for dhtpeer.New\nfunc EnablePrometheusMonitoring(port uint16) Option {\n\treturn func(dhtPeer *DHTPeer) error {\n\t\tdhtPeer.monitoringPort = port\n\t\treturn nil\n\t}\n}\n\n// WithRegistrationDelay for dhtpeer.New\nfunc WithRegistrationDelay(delay time.Duration) Option {\n\treturn func(dhtPeer *DHTPeer) error {\n\t\tdhtPeer.registrationDelay = delay\n\t\treturn nil\n\t}\n}\n\n// StoreRecordsTo for dhtpeer.New\nfunc StoreRecordsTo(path string) Option {\n\treturn func(dhtPeer *DHTPeer) error {\n\t\tdhtPeer.persistentStoragePath = path\n\t\treturn nil\n\t}\n}\n"
  },
  {
    "path": "libs/go/libp2p_node/dht/dhtpeer/utils.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2021 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\n\npackage dhtpeer\n\nimport (\n\tutils \"libp2p_node/utils\"\n\t\"net\"\n)\n\ntype TLSListener struct {\n\tListener  net.Listener\n\tSignature []byte\n}\n\nfunc (listener TLSListener) Accept() (net.Conn, error) {\n\tcon, err := listener.Listener.Accept()\n\n\tif err != nil {\n\t\treturn con, err\n\t}\n\n\terr = utils.WriteBytesConn(con, listener.Signature)\n\treturn con, err\n}\n\nfunc (listener TLSListener) Close() error {\n\treturn listener.Listener.Close()\n}\n\nfunc (listener TLSListener) Addr() net.Addr {\n\treturn listener.Listener.Addr()\n}\n"
  },
  {
    "path": "libs/go/libp2p_node/dht/dhttests/dhttests.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2019 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\n\n// Package dhttests offers utilities to facilitate tests of dhtpeer, dhtclient, and dhtnetwork packages\npackage dhttests\n\nimport (\n\t\"libp2p_node/acn\"\n\t\"libp2p_node/aea\"\n\t\"libp2p_node/dht/dhtnode\"\n\t\"libp2p_node/dht/dhtpeer\"\n\t\"libp2p_node/utils\"\n\t\"log\"\n\t\"math/rand\"\n\t\"os\"\n\t\"path\"\n)\n\n//\nconst (\n\tDHTPeerDefaultLocalHost    = \"127.0.0.1\"\n\tDHTPeerDefaultLocalPort    = 2000\n\tDHTPeerDefaultDelegatePort = 3000\n\n\tDHTPeerDefaultFetchAIKey       = \"34604436e55b0eb99b5e62508433e172dd3ee133cf7a2fecb705e69611147605\"\n\tDHTPeerDefaultFetchAIPublicKey = \"039e883de988eededb9afaa4d3a6baec9ba74dd1cc237028e810569780b319940a\"\n\n\tDHTPeerDefaultAgentKey       = \"719133dc740d76ff6d1d325e193f7cd63af4c8f3491bfe3010e58b0b58c77795\"\n\tDHTPeerDefaultAgentPublicKey = \"039623e63ba1617404b2abbe7bd94d24eb788335f870fac1ae4519e9bc359b7833\"\n\tDHTPeerDefaultAgentAddress   = \"fetch134rg4n3wgmwctxsrm7gp6l65uwv6hxtxyfdwgw\"\n)\n\nfunc randSeq(n int) string {\n\tvar letters = []rune(\"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\")\n\tb := make([]rune, n)\n\tfor i := range b {\n\t\tb[i] = letters[rand.Intn(len(letters))]\n\t}\n\treturn string(b)\n}\n\n// NewDHTPeerWithDefaults for testing\nfunc NewDHTPeerWithDefaults(inbox chan<- *aea.Envelope) (*dhtpeer.DHTPeer, func(), error) {\n\topts := []dhtpeer.Option{\n\t\tdhtpeer.LocalURI(DHTPeerDefaultLocalHost, DHTPeerDefaultLocalPort),\n\t\tdhtpeer.PublicURI(DHTPeerDefaultLocalHost, DHTPeerDefaultLocalPort),\n\t\tdhtpeer.IdentityFromFetchAIKey(DHTPeerDefaultFetchAIKey),\n\t\tdhtpeer.EnableRelayService(),\n\t\tdhtpeer.EnableDelegateService(DHTPeerDefaultDelegatePort),\n\t\tdhtpeer.StoreRecordsTo(path.Join(os.TempDir(), \"agents_records_\"+randSeq(5))),\n\t}\n\n\tsignature, err := utils.SignFetchAI(\n\t\t[]byte(DHTPeerDefaultFetchAIPublicKey),\n\t\tDHTPeerDefaultAgentKey,\n\t)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\trecord := &acn.AgentRecord{LedgerId: dhtnode.DefaultLedger}\n\trecord.Address = DHTPeerDefaultAgentAddress\n\trecord.PublicKey = DHTPeerDefaultAgentPublicKey\n\trecord.PeerPublicKey = DHTPeerDefaultFetchAIPublicKey\n\trecord.Signature = signature\n\n\topts = append(opts, dhtpeer.RegisterAgentAddress(record, func() bool { return true }))\n\n\tdhtPeer, err := dhtpeer.New(opts...)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tcleanup := func() {\n\t\terrs := dhtPeer.Close()\n\t\tif len(errs) > 0 {\n\t\t\tlog.Println(\"ERROR while stopping DHTPeer:\", errs)\n\t\t}\n\t}\n\n\tdhtPeer.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\tinbox <- envel\n\t\treturn nil\n\t})\n\n\treturn dhtPeer, cleanup, nil\n}\n"
  },
  {
    "path": "libs/go/libp2p_node/dht/monitoring/file.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2019 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\n\npackage monitoring\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"sync\"\n\t\"time\"\n)\n\ntype FileGauge struct {\n\tvalue float64\n\tlock  sync.RWMutex\n}\n\nfunc (fg *FileGauge) Set(value float64) {\n\tfg.lock.Lock()\n\tfg.value = value\n\tfg.lock.Unlock()\n\n}\n\nfunc (fg *FileGauge) Get() float64 {\n\treturn fg.value\n\n}\n\nfunc (fg *FileGauge) Inc() {\n\tfg.Add(1.)\n}\n\nfunc (fg *FileGauge) Dec() {\n\tfg.Sub(1)\n}\n\nfunc (fg *FileGauge) Add(count float64) {\n\tfg.lock.Lock()\n\tfg.value += count\n\tfg.lock.Unlock()\n\n}\n\nfunc (fg *FileGauge) Sub(count float64) {\n\tfg.lock.Lock()\n\tfg.value -= count\n\tfg.lock.Unlock()\n\n}\n\ntype FileCounter struct {\n\tvalue float64\n\tlock  sync.RWMutex\n}\n\nfunc (fc *FileCounter) Inc() {\n\tfc.Add(1.)\n\n}\n\nfunc (fc *FileCounter) Add(count float64) {\n\tfc.lock.Lock()\n\tfc.value += count\n\tfc.lock.Unlock()\n}\n\nfunc (fc *FileCounter) Get() float64 {\n\treturn fc.value\n}\n\ntype FileHistogram struct {\n\tbuckets []float64\n\tcounts  []uint64\n\tlock    sync.RWMutex\n}\n\nfunc (fh *FileHistogram) Observe(value float64) {\n\tfh.lock.Lock()\n\tvar i int = 0\n\tfor i < len(fh.buckets) {\n\t\tif value <= fh.buckets[i] {\n\t\t\tfh.counts[i] += 1\n\t\t}\n\t\ti++\n\t}\n\tfh.counts[i] += 1\n\tfh.lock.Unlock()\n}\n\ntype FileMonitoring struct {\n\tNamespace   string\n\tgaugeDict   map[string]*FileGauge\n\tcounterDict map[string]*FileCounter\n\thistoDict   map[string]*FileHistogram\n\n\ttimer *Timer\n\n\tpath    string\n\twrite   bool\n\tclosing chan struct{}\n}\n\nfunc NewFileMonitoring(namespace string, write bool) *FileMonitoring {\n\tfm := &FileMonitoring{\n\t\tNamespace: namespace,\n\t}\n\n\tfm.counterDict = map[string]*FileCounter{}\n\tfm.gaugeDict = map[string]*FileGauge{}\n\tfm.histoDict = map[string]*FileHistogram{}\n\n\tfm.timer = &Timer{\n\t\tlist: map[string]time.Time{},\n\t\tlock: sync.RWMutex{},\n\t}\n\n\tcwd, _ := os.Getwd()\n\tfm.path = cwd + \"/\" + fm.Namespace + \".stats\"\n\tfm.write = write\n\n\treturn fm\n}\n\nfunc (fm *FileMonitoring) NewCounter(name string, description string) (Counter, error) {\n\tcounter := &FileCounter{}\n\tfm.counterDict[name] = counter\n\n\treturn counter, nil\n\n}\n\nfunc (fm *FileMonitoring) GetCounter(name string) (Counter, bool) {\n\tcounter, ok := fm.counterDict[name]\n\treturn counter, ok\n}\n\nfunc (fm *FileMonitoring) NewGauge(name string, description string) (Gauge, error) {\n\tgauge := &FileGauge{}\n\tfm.gaugeDict[name] = gauge\n\n\treturn gauge, nil\n}\n\nfunc (fm *FileMonitoring) GetGauge(name string) (Gauge, bool) {\n\tgauge, ok := fm.gaugeDict[name]\n\treturn gauge, ok\n}\n\nfunc (fm *FileMonitoring) NewHistogram(\n\tname string,\n\tdescription string,\n\tbuckets []float64,\n) (Histogram, error) {\n\thistogram := &FileHistogram{\n\t\tbuckets: buckets,\n\t\tcounts:  make([]uint64, len(buckets)+1),\n\t}\n\tfm.histoDict[name] = histogram\n\n\treturn histogram, nil\n}\n\nfunc (fm *FileMonitoring) GetHistogram(name string) (Histogram, bool) {\n\thisto, ok := fm.histoDict[name]\n\treturn histo, ok\n}\n\nfunc (fm *FileMonitoring) Start() {\n\tif fm.closing != nil || !fm.write {\n\t\treturn\n\t}\n\tfm.closing = make(chan struct{})\n\n\tfile, _ := os.OpenFile(fm.path, os.O_WRONLY|os.O_CREATE, 0666)\nL:\n\tfor {\n\t\tselect {\n\t\tcase <-fm.closing:\n\t\t\tfile.Close()\n\t\t\tbreak L\n\t\tdefault:\n\t\t\tignore(file.Truncate(0))\n\t\t\t_, err := file.Seek(0, 0)\n\t\t\tignore(err)\n\t\t\t_, err = file.WriteString(fm.getStats())\n\t\t\tignore(err)\n\t\t\ttime.Sleep(5 * time.Second)\n\t\t}\n\t}\n}\n\nfunc (fm *FileMonitoring) Stop() {\n\tclose(fm.closing)\n}\n\nfunc (fm FileMonitoring) getStats() string {\n\tvar stats string\n\tfor name, value := range fm.gaugeDict {\n\t\tstrValue := fmt.Sprintf(\"%e\", value.Get())\n\t\tstats += fm.Namespace + \"_\" + name + \" \" + strValue + \"\\n\"\n\t}\n\tfor name, value := range fm.counterDict {\n\t\tstrValue := fmt.Sprintf(\"%e\", value.Get())\n\t\tstats += fm.Namespace + \"_\" + name + \" \" + strValue + \"\\n\"\n\t}\n\t// TODO: report histograms\n\treturn stats\n}\n\nfunc (fm *FileMonitoring) Info() string {\n\treturn \"FileMonitoring on \" + fm.path\n}\n\nfunc (fm *FileMonitoring) Timer() *Timer {\n\treturn fm.timer\n}\n"
  },
  {
    "path": "libs/go/libp2p_node/dht/monitoring/prometheus.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2019 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\n\npackage monitoring\n\nimport (\n\t\"net/http\"\n\t\"strconv\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/prometheus/client_golang/prometheus\"\n\t\"github.com/prometheus/client_golang/prometheus/promauto\"\n\t\"github.com/prometheus/client_golang/prometheus/promhttp\"\n)\n\ntype PrometheusMonitoring struct {\n\tNamespace string\n\tPort      uint16\n\n\trunning     bool\n\thttpServer  http.Server\n\tcounterDict map[string]prometheus.Counter\n\tgaugeDict   map[string]prometheus.Gauge\n\thistoDict   map[string]prometheus.Histogram\n\n\ttimer *Timer\n}\n\nfunc NewPrometheusMonitoring(namespace string, port uint16) *PrometheusMonitoring {\n\tpmts := &PrometheusMonitoring{\n\t\tNamespace: namespace,\n\t\tPort:      port,\n\t}\n\n\tpmts.counterDict = map[string]prometheus.Counter{}\n\tpmts.gaugeDict = map[string]prometheus.Gauge{}\n\tpmts.histoDict = map[string]prometheus.Histogram{}\n\n\tpmts.timer = &Timer{\n\t\tlist: map[string]time.Time{},\n\t\tlock: sync.RWMutex{},\n\t}\n\n\treturn pmts\n}\n\nfunc (pmts *PrometheusMonitoring) NewCounter(name string, description string) (Counter, error) {\n\tcounter := promauto.NewCounter(prometheus.CounterOpts{\n\t\tNamespace: pmts.Namespace,\n\t\tName:      name,\n\t\tHelp:      description,\n\t})\n\tpmts.counterDict[name] = counter\n\n\treturn counter, nil\n}\n\nfunc (pmts *PrometheusMonitoring) GetCounter(name string) (Counter, bool) {\n\tcounter, ok := pmts.counterDict[name]\n\treturn counter, ok\n}\n\nfunc (pmts *PrometheusMonitoring) NewGauge(name string, description string) (Gauge, error) {\n\tgauge := promauto.NewGauge(prometheus.GaugeOpts{\n\t\tNamespace: pmts.Namespace,\n\t\tName:      name,\n\t\tHelp:      description,\n\t})\n\tpmts.gaugeDict[name] = gauge\n\n\treturn gauge, nil\n}\n\nfunc (pmts *PrometheusMonitoring) GetGauge(name string) (Gauge, bool) {\n\tgauge, ok := pmts.gaugeDict[name]\n\treturn gauge, ok\n}\n\nfunc (pmts *PrometheusMonitoring) NewHistogram(\n\tname string,\n\tdescription string,\n\tbuckets []float64,\n) (Histogram, error) {\n\thistogram := promauto.NewHistogram(prometheus.HistogramOpts{\n\t\tNamespace: pmts.Namespace,\n\t\tName:      name,\n\t\tHelp:      description,\n\t\tBuckets:   buckets,\n\t})\n\tpmts.histoDict[name] = histogram\n\n\treturn histogram, nil\n}\n\nfunc (pmts *PrometheusMonitoring) GetHistogram(name string) (Histogram, bool) {\n\thistogram, ok := pmts.histoDict[name]\n\treturn histogram, ok\n}\n\nfunc (pmts *PrometheusMonitoring) Start() {\n\tif pmts.running {\n\t\treturn\n\t}\n\tpmts.httpServer = http.Server{Addr: \":\" + strconv.FormatInt(int64(pmts.Port), 10)}\n\thttp.Handle(\"/metrics\", promhttp.Handler())\n\n\tpmts.running = true\n\tignore(pmts.httpServer.ListenAndServe())\n}\n\nfunc (pmts *PrometheusMonitoring) Stop() {\n\tpmts.httpServer.Close()\n}\n\nfunc (pmts *PrometheusMonitoring) Info() string {\n\treturn \"Prometheus at \" + strconv.FormatInt(int64(pmts.Port), 10)\n}\nfunc (pmts *PrometheusMonitoring) Timer() *Timer {\n\treturn pmts.timer\n}\n"
  },
  {
    "path": "libs/go/libp2p_node/dht/monitoring/service.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2019 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\n\npackage monitoring\n\nimport (\n\t\"errors\"\n\t\"log\"\n\t\"sync\"\n\t\"time\"\n)\n\ntype Gauge interface {\n\tSet(value float64)\n\tInc()\n\tDec()\n\tAdd(count float64)\n\tSub(count float64)\n}\n\ntype Counter interface {\n\tInc()\n\tAdd(count float64)\n}\n\ntype Histogram interface {\n\tObserve(value float64)\n}\n\ntype Summary interface {\n\tObserve(value float64)\n}\n\ntype Timer struct {\n\tlist map[string]time.Time\n\tlock sync.RWMutex\n}\n\nfunc (tm *Timer) NewTimer() time.Time {\n\treturn time.Now()\n}\n\nfunc (tm *Timer) GetTimer(timer time.Time) time.Duration {\n\tend := time.Now()\n\treturn end.Sub(timer)\n}\n\nfunc (tm *Timer) NewTimerNamed(name string) string {\n\ttm.lock.Lock()\n\tdefer tm.lock.Unlock()\n\ttm.list[name] = time.Now()\n\treturn name\n}\n\nfunc (tm *Timer) GetTimerNamed(timer string) (time.Duration, error) {\n\tend := time.Now()\n\ttm.lock.RLock()\n\tstart, ok := tm.list[timer]\n\ttm.lock.RUnlock()\n\tif !ok {\n\t\treturn time.Duration(0), errors.New(\"Unknown timer \" + timer)\n\t}\n\ttm.lock.Lock()\n\tdelete(tm.list, timer)\n\ttm.lock.Unlock()\n\treturn end.Sub(start), nil\n}\n\ntype MonitoringService interface {\n\tNewCounter(name string, description string) (Counter, error)\n\tGetCounter(name string) (Counter, bool)\n\tNewGauge(name string, description string) (Gauge, error)\n\tGetGauge(name string) (Gauge, bool)\n\tNewHistogram(name string, description string, buckets []float64) (Histogram, error)\n\tGetHistogram(name string) (Histogram, bool)\n\t//NewSummary(name string, description string, objectives map[float64]float64) (Summary, error)\n\t//GetSummary(name string) (Summary, bool)\n\tStart()\n\tStop()\n\tInfo() string\n\tTimer() *Timer\n}\n\nfunc ignore(err error) {\n\tif err != nil {\n\t\tlog.Println(\"IGNORED\", err)\n\t}\n}\n"
  },
  {
    "path": "libs/go/libp2p_node/go.mod",
    "content": "module libp2p_node\n\ngo 1.13\n\nrequire (\n\tbou.ke/monkey v1.0.2\n\tgithub.com/btcsuite/btcd v0.20.1-beta\n\tgithub.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d\n\tgithub.com/ethereum/go-ethereum v1.10.17\n\tgithub.com/golang/mock v1.5.0\n\tgithub.com/golang/protobuf v1.4.3\n\tgithub.com/google/uuid v1.3.0\n\tgithub.com/ipfs/go-cid v0.0.5\n\tgithub.com/joho/godotenv v1.3.0\n\tgithub.com/libp2p/go-libp2p v0.8.3\n\tgithub.com/libp2p/go-libp2p-circuit v0.2.2\n\tgithub.com/libp2p/go-libp2p-core v0.5.3\n\tgithub.com/libp2p/go-libp2p-kad-dht v0.7.11\n\tgithub.com/libp2p/go-libp2p-kbucket v0.4.1\n\tgithub.com/multiformats/go-multiaddr v0.2.1\n\tgithub.com/multiformats/go-multihash v0.0.13\n\tgithub.com/pkg/errors v0.9.1\n\tgithub.com/prometheus/client_golang v1.7.1\n\tgithub.com/rs/zerolog v1.21.0\n\tgithub.com/stretchr/testify v1.7.0\n\tgolang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2\n\tgoogle.golang.org/protobuf v1.25.0\n\thonnef.co/go/tools v0.1.4 // indirect\n\n)\n"
  },
  {
    "path": "libs/go/libp2p_node/go.sum",
    "content": "bou.ke/monkey v1.0.2 h1:kWcnsrCNUatbxncxR/ThdYqbytgOIArtYWqcQLQzKLI=\nbou.ke/monkey v1.0.2/go.mod h1:OqickVX3tNx6t33n1xvtTtu85YN5s6cKwVug+oHMaIA=\ncloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ncloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ncloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=\ncloud.google.com/go v0.43.0/go.mod h1:BOSR3VbTLkk6FDC/TcffxP4NF/FFBGA5ku+jvKOP7pg=\ncloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=\ncloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=\ncloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=\ncloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=\ncloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=\ncloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw=\ncloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=\ncloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=\ncloud.google.com/go/bigtable v1.2.0/go.mod h1:JcVAOl45lrTmQfLj7T6TxyMzIN/3FGGcFm+2xVAli2o=\ncloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=\ncloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=\ncloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=\ncloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=\ncloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=\ncollectd.org v0.3.0/go.mod h1:A/8DzQBkF6abtvrT2j/AU/4tiBgJWYyh0y/oB/4MlWE=\ndmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=\ngithub.com/AndreasBriese/bbloom v0.0.0-20180913140656-343706a395b7/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=\ngithub.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=\ngithub.com/Azure/azure-sdk-for-go/sdk/azcore v0.21.1/go.mod h1:fBF9PQNqB8scdgpZ3ufzaLntG0AG7C1WjPMsiFOmfHM=\ngithub.com/Azure/azure-sdk-for-go/sdk/internal v0.8.3/go.mod h1:KLF4gFr6DcKFZwSuH8w8yEK6DpFl3LP5rhdvAb7Yz5I=\ngithub.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0/go.mod h1:tPaiy8S5bQ+S5sOiDlINkp7+Ef339+Nz5L5XO+cnOHo=\ngithub.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=\ngithub.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=\ngithub.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=\ngithub.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=\ngithub.com/Kubuxu/go-os-helper v0.0.1/go.mod h1:N8B+I7vPCT80IcP58r50u4+gEEcsZETFUpAzWW2ep1Y=\ngithub.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=\ngithub.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=\ngithub.com/VictoriaMetrics/fastcache v1.6.0/go.mod h1:0qHz5QP0GMX4pfmMA/zt5RgfNuXJrTP0zS7DqpHGGTw=\ngithub.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=\ngithub.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=\ngithub.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=\ngithub.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=\ngithub.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=\ngithub.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=\ngithub.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM=\ngithub.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=\ngithub.com/apache/arrow/go/arrow v0.0.0-20191024131854-af6fa24be0db/go.mod h1:VTxUBvSJ3s3eHAg65PNgrsn5BtqCRPdmyXh6rAfdxN0=\ngithub.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=\ngithub.com/aws/aws-sdk-go-v2 v1.2.0/go.mod h1:zEQs02YRBw1DjK0PoJv3ygDYOFTre1ejlJWl8FwAuQo=\ngithub.com/aws/aws-sdk-go-v2/config v1.1.1/go.mod h1:0XsVy9lBI/BCXm+2Tuvt39YmdHwS5unDQmxZOYe8F5Y=\ngithub.com/aws/aws-sdk-go-v2/credentials v1.1.1/go.mod h1:mM2iIjwl7LULWtS6JCACyInboHirisUUdkBPoTHMOUo=\ngithub.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.0.2/go.mod h1:3hGg3PpiEjHnrkrlasTfxFqUsZ2GCk/fMUn4CbKgSkM=\ngithub.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.0.2/go.mod h1:45MfaXZ0cNbeuT0KQ1XJylq8A6+OpVV2E5kvY/Kq+u8=\ngithub.com/aws/aws-sdk-go-v2/service/route53 v1.1.1/go.mod h1:rLiOUrPLW/Er5kRcQ7NkwbjlijluLsrIbu/iyl35RO4=\ngithub.com/aws/aws-sdk-go-v2/service/sso v1.1.1/go.mod h1:SuZJxklHxLAXgLTc1iFXbEWkXs7QRTQpCLGaKIprQW0=\ngithub.com/aws/aws-sdk-go-v2/service/sts v1.1.1/go.mod h1:Wi0EBZwiz/K44YliU0EKxqTCJGUfYTWXrrBwkq736bM=\ngithub.com/aws/smithy-go v1.1.0/go.mod h1:EzMw8dbp/YJL4A5/sbhGddag+NPT7q084agLbB9LgIw=\ngithub.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=\ngithub.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=\ngithub.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=\ngithub.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=\ngithub.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40/go.mod h1:8rLXio+WjiTceGBHIoTvn60HIbs7Hm7bcHjyrSqYB9c=\ngithub.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=\ngithub.com/btcsuite/btcd v0.0.0-20190213025234-306aecffea32/go.mod h1:DrZx5ec/dmnfpw9KyYoQyYo7d0KEvTkk/5M/vbZjAr8=\ngithub.com/btcsuite/btcd v0.0.0-20190523000118-16327141da8c/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI=\ngithub.com/btcsuite/btcd v0.0.0-20190824003749-130ea5bddde3/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI=\ngithub.com/btcsuite/btcd v0.20.1-beta h1:Ik4hyJqN8Jfyv3S4AGBOmyouMsYE3EdYODkMbQjwPGw=\ngithub.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=\ngithub.com/btcsuite/btcd/btcec/v2 v2.1.2 h1:YoYoC9J0jwfukodSBMzZYUVQ8PTiYg4BnOWiJVzTmLs=\ngithub.com/btcsuite/btcd/btcec/v2 v2.1.2/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE=\ngithub.com/btcsuite/btcd/chaincfg/chainhash v1.0.0 h1:MSskdM4/xJYcFzy0altH/C/xHopifpWzHUi1JeVI34Q=\ngithub.com/btcsuite/btcd/chaincfg/chainhash v1.0.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=\ngithub.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=\ngithub.com/btcsuite/btcutil v0.0.0-20190207003914-4c204d697803/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=\ngithub.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d h1:yJzD/yFppdVCf6ApMkVy8cUxV0XrxdP9rVf6D87/Mng=\ngithub.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=\ngithub.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg=\ngithub.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY=\ngithub.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc=\ngithub.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY=\ngithub.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs=\ngithub.com/c-bata/go-prompt v0.2.2/go.mod h1:VzqtzE2ksDBcdln8G7mk2RX9QyGjH+OVqOCSiVIqS34=\ngithub.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=\ngithub.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s=\ngithub.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=\ngithub.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=\ngithub.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=\ngithub.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=\ngithub.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=\ngithub.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=\ngithub.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=\ngithub.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=\ngithub.com/cloudflare/cloudflare-go v0.14.0/go.mod h1:EnwdgGMaFOruiPZRFSgn+TsQ3hQ7C/YWzIGLeu5c304=\ngithub.com/consensys/bavard v0.1.8-0.20210406032232-f3452dc9b572/go.mod h1:Bpd0/3mZuaj6Sj+PqrmIquiOKy397AKGThQPaGzNXAQ=\ngithub.com/consensys/gnark-crypto v0.4.1-0.20210426202927-39ac3d4b3f1f/go.mod h1:815PAHg3wvysy0SyIqanF8gZ0Y1wjk/hrDHD/iT88+Q=\ngithub.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=\ngithub.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=\ngithub.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=\ngithub.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM=\ngithub.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=\ngithub.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=\ngithub.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=\ngithub.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=\ngithub.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=\ngithub.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4=\ngithub.com/dave/jennifer v1.2.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg=\ngithub.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/davidlazar/go-crypto v0.0.0-20170701192655-dcfb0a7ac018 h1:6xT9KW8zLC5IlbaIF5Q7JNieBoACT7iW0YTxQHR0in0=\ngithub.com/davidlazar/go-crypto v0.0.0-20170701192655-dcfb0a7ac018/go.mod h1:rQYf4tfk5sSwFsnDg3qYaBxSjsD9S8+59vW0dKUgme4=\ngithub.com/deckarep/golang-set v1.8.0/go.mod h1:5nI87KwE7wgsBU1F4GKAw2Qod7p5kyS383rP6+o6qqo=\ngithub.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0=\ngithub.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc=\ngithub.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc=\ngithub.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs=\ngithub.com/deepmap/oapi-codegen v1.6.0/go.mod h1:ryDa9AgbELGeB+YEXE1dR53yAjHwFvE9iAUlWl9Al3M=\ngithub.com/deepmap/oapi-codegen v1.8.2/go.mod h1:YLgSKSDv/bZQB7N4ws6luhozi3cEdRktEqrX88CvjIw=\ngithub.com/dgraph-io/badger v1.5.5-0.20190226225317-8115aed38f8f/go.mod h1:VZxzAIRPHRVNRKRo6AXrX9BJegn6il06VMTZVJYCIjQ=\ngithub.com/dgraph-io/badger v1.6.0-rc1/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4=\ngithub.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4=\ngithub.com/dgraph-io/badger v1.6.1/go.mod h1:FRmFw3uxvcpa8zG3Rxs0th+hCLIuaQg8HlNV5bjgnuU=\ngithub.com/dgraph-io/ristretto v0.0.2/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E=\ngithub.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=\ngithub.com/dgryski/go-bitstream v0.0.0-20180413035011-3522498ce2c8/go.mod h1:VMaSuZ+SZcx/wljOQKvp5srsbCiKDEb6K2wC4+PiBmQ=\ngithub.com/dgryski/go-farm v0.0.0-20190104051053-3adb47b1fb0f/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=\ngithub.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=\ngithub.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=\ngithub.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=\ngithub.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko=\ngithub.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=\ngithub.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=\ngithub.com/dop251/goja v0.0.0-20211011172007-d99e4b8cbf48/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk=\ngithub.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7/go.mod h1:hn7BA7c8pLvoGndExHudxTDKZ84Pyvv+90pbBjbTz0Y=\ngithub.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=\ngithub.com/eclipse/paho.mqtt.golang v1.2.0/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7joQ8SYLhZwfeOo6Ts=\ngithub.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=\ngithub.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=\ngithub.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=\ngithub.com/ethereum/go-ethereum v1.10.17 h1:XEcumY+qSr1cZQaWsQs5Kck3FHB0V2RiMHPdTBJ+oT8=\ngithub.com/ethereum/go-ethereum v1.10.17/go.mod h1:Lt5WzjM07XlXc95YzrhosmR4J9Ahd6X2wyEV2SvGhk0=\ngithub.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=\ngithub.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0=\ngithub.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=\ngithub.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=\ngithub.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=\ngithub.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=\ngithub.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww=\ngithub.com/getkin/kin-openapi v0.53.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4=\ngithub.com/getkin/kin-openapi v0.61.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4=\ngithub.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=\ngithub.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE=\ngithub.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24=\ngithub.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98=\ngithub.com/go-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJpoZOs=\ngithub.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=\ngithub.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=\ngithub.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=\ngithub.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=\ngithub.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=\ngithub.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=\ngithub.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8=\ngithub.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=\ngithub.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=\ngithub.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg=\ngithub.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=\ngithub.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=\ngithub.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=\ngithub.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=\ngithub.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=\ngithub.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=\ngithub.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=\ngithub.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=\ngithub.com/golang-jwt/jwt/v4 v4.3.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=\ngithub.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=\ngithub.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=\ngithub.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=\ngithub.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=\ngithub.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7 h1:5ZkaAPbicIKTF2I64qf5Fh8Aa83Q/dnOafMYV0OMwjA=\ngithub.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=\ngithub.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=\ngithub.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=\ngithub.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=\ngithub.com/golang/mock v1.5.0 h1:jlYHihg//f7RRwuPfptm04yp4s7O6Kw8EZiVYIGcH0g=\ngithub.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=\ngithub.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0=\ngithub.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=\ngithub.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=\ngithub.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=\ngithub.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=\ngithub.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=\ngithub.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=\ngithub.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=\ngithub.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM=\ngithub.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=\ngithub.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=\ngithub.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=\ngithub.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=\ngithub.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219/go.mod h1:/X8TswGSh1pIozq4ZwCfxS0WA5JGXguxk94ar/4c87Y=\ngithub.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=\ngithub.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=\ngithub.com/google/flatbuffers v1.11.0/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=\ngithub.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=\ngithub.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=\ngithub.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=\ngithub.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M=\ngithub.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=\ngithub.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=\ngithub.com/google/gopacket v1.1.17 h1:rMrlX2ZY2UbvT+sdz3+6J+pp2z+msCq9MxTU6ymxbBY=\ngithub.com/google/gopacket v1.1.17/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM=\ngithub.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=\ngithub.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=\ngithub.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=\ngithub.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=\ngithub.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=\ngithub.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=\ngithub.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=\ngithub.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=\ngithub.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=\ngithub.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=\ngithub.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=\ngithub.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=\ngithub.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=\ngithub.com/graph-gophers/graphql-go v1.3.0/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc=\ngithub.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU=\ngithub.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48=\ngithub.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=\ngithub.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=\ngithub.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0=\ngithub.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI=\ngithub.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=\ngithub.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=\ngithub.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=\ngithub.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=\ngithub.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d h1:dg1dEPuWpEqDnvIw251EVy4zlP8gWbsGj4BsUKCRpYs=\ngithub.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=\ngithub.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=\ngithub.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA=\ngithub.com/holiman/uint256 v1.2.0/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw=\ngithub.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=\ngithub.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc=\ngithub.com/huin/goupnp v1.0.3-0.20220313090229-ca81a64b4204 h1:+EYBkW+dbi3F/atB+LSQZSWh7+HNrV3A/N0y6DSoy9k=\ngithub.com/huin/goupnp v1.0.3-0.20220313090229-ca81a64b4204/go.mod h1:ZxNlw5WqJj6wSsRK5+YfflQGXYfccj5VgQsMNixHM7Y=\ngithub.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o=\ngithub.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=\ngithub.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=\ngithub.com/influxdata/flux v0.65.1/go.mod h1:J754/zds0vvpfwuq7Gc2wRdVwEodfpCFM7mYlOw2LqY=\ngithub.com/influxdata/influxdb v1.8.3/go.mod h1:JugdFhsvvI8gadxOI6noqNeeBHvWNTbfYGtiAn+2jhI=\ngithub.com/influxdata/influxdb-client-go/v2 v2.4.0/go.mod h1:vLNHdxTJkIf2mSLvGrpj8TCcISApPoXkaxP8g9uRlW8=\ngithub.com/influxdata/influxql v1.1.1-0.20200828144457-65d3ef77d385/go.mod h1:gHp9y86a/pxhjJ+zMjNXiQAA197Xk9wLxaz+fGG+kWk=\ngithub.com/influxdata/line-protocol v0.0.0-20180522152040-32c6aa80de5e/go.mod h1:4kt73NQhadE3daL3WhR5EJ/J2ocX0PZzwxQ0gXJ7oFE=\ngithub.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo=\ngithub.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo=\ngithub.com/influxdata/promql/v2 v2.12.0/go.mod h1:fxOPu+DY0bqCTCECchSRtWfc+0X19ybifQhZoQNF5D8=\ngithub.com/influxdata/roaring v0.4.13-0.20180809181101-fc520f41fab6/go.mod h1:bSgUQ7q5ZLSO+bKBGqJiCBGAl+9DxyW63zLTujjUlOE=\ngithub.com/influxdata/tdigest v0.0.0-20181121200506-bf2b5ad3c0a9/go.mod h1:Js0mqiSBE6Ffsg94weZZ2c+v/ciT8QRHFOap7EKDrR0=\ngithub.com/influxdata/usage-client v0.0.0-20160829180054-6d3895376368/go.mod h1:Wbbw6tYNvwa5dlB6304Sd+82Z3f7PmVZHVKU637d4po=\ngithub.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM=\ngithub.com/ipfs/go-cid v0.0.2/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM=\ngithub.com/ipfs/go-cid v0.0.3/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM=\ngithub.com/ipfs/go-cid v0.0.4/go.mod h1:4LLaPOQwmk5z9LBgQnpkivrx8BJjUyGwTXCd5Xfj6+M=\ngithub.com/ipfs/go-cid v0.0.5 h1:o0Ix8e/ql7Zb5UVUJEUfjsWCIY8t48++9lR8qi6oiJU=\ngithub.com/ipfs/go-cid v0.0.5/go.mod h1:plgt+Y5MnOey4vO4UlUazGqdbEXuFYitED67FexhXog=\ngithub.com/ipfs/go-datastore v0.0.1/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE=\ngithub.com/ipfs/go-datastore v0.1.0/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE=\ngithub.com/ipfs/go-datastore v0.1.1/go.mod h1:w38XXW9kVFNp57Zj5knbKWM2T+KOZCGDRVNdgPHtbHw=\ngithub.com/ipfs/go-datastore v0.4.0/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA=\ngithub.com/ipfs/go-datastore v0.4.1/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA=\ngithub.com/ipfs/go-datastore v0.4.4 h1:rjvQ9+muFaJ+QZ7dN5B1MSDNQ0JVZKkkES/rMZmA8X8=\ngithub.com/ipfs/go-datastore v0.4.4/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA=\ngithub.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk=\ngithub.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps=\ngithub.com/ipfs/go-ds-badger v0.0.2/go.mod h1:Y3QpeSFWQf6MopLTiZD+VT6IC1yZqaGmjvRcKeSGij8=\ngithub.com/ipfs/go-ds-badger v0.0.5/go.mod h1:g5AuuCGmr7efyzQhLL8MzwqcauPojGPUaHzfGTzuE3s=\ngithub.com/ipfs/go-ds-badger v0.0.7/go.mod h1:qt0/fWzZDoPW6jpQeqUjR5kBfhDNB65jd9YlmAvpQBk=\ngithub.com/ipfs/go-ds-badger v0.2.1/go.mod h1:Tx7l3aTph3FMFrRS838dcSJh+jjA7cX9DrGVwx/NOwE=\ngithub.com/ipfs/go-ds-badger v0.2.3/go.mod h1:pEYw0rgg3FIrywKKnL+Snr+w/LjJZVMTBRn4FS6UHUk=\ngithub.com/ipfs/go-ds-leveldb v0.0.1/go.mod h1:feO8V3kubwsEF22n0YRQCffeb79OOYIykR4L04tMOYc=\ngithub.com/ipfs/go-ds-leveldb v0.1.0/go.mod h1:hqAW8y4bwX5LWcCtku2rFNX3vjDZCy5LZCg+cSZvYb8=\ngithub.com/ipfs/go-ds-leveldb v0.4.1/go.mod h1:jpbku/YqBSsBc1qgME8BkWS4AxzF2cEu1Ii2r79Hh9s=\ngithub.com/ipfs/go-ds-leveldb v0.4.2/go.mod h1:jpbku/YqBSsBc1qgME8BkWS4AxzF2cEu1Ii2r79Hh9s=\ngithub.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw=\ngithub.com/ipfs/go-ipfs-util v0.0.1 h1:Wz9bL2wB2YBJqggkA4dD7oSmqB4cAnpNbGrlHJulv50=\ngithub.com/ipfs/go-ipfs-util v0.0.1/go.mod h1:spsl5z8KUnrve+73pOhSVZND1SIxPW5RyBCNzQxlJBc=\ngithub.com/ipfs/go-ipns v0.0.2 h1:oq4ErrV4hNQ2Eim257RTYRgfOSV/s8BDaf9iIl4NwFs=\ngithub.com/ipfs/go-ipns v0.0.2/go.mod h1:WChil4e0/m9cIINWLxZe1Jtf77oz5L05rO2ei/uKJ5U=\ngithub.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM=\ngithub.com/ipfs/go-log v1.0.2/go.mod h1:1MNjMxe0u6xvJZgeqbJ8vdo2TKaGwZ1a0Bpza+sr2Sk=\ngithub.com/ipfs/go-log v1.0.3/go.mod h1:OsLySYkwIbiSUR/yBTdv1qPtcE4FW3WPWk/ewz9Ru+A=\ngithub.com/ipfs/go-log v1.0.4 h1:6nLQdX4W8P9yZZFH7mO+X/PzjN8Laozm/lMJ6esdgzY=\ngithub.com/ipfs/go-log v1.0.4/go.mod h1:oDCg2FkjogeFOhqqb+N39l2RpTNPL6F/StPkB3kPgcs=\ngithub.com/ipfs/go-log/v2 v2.0.2/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBWFaa9+0=\ngithub.com/ipfs/go-log/v2 v2.0.3/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBWFaa9+0=\ngithub.com/ipfs/go-log/v2 v2.0.5 h1:fL4YI+1g5V/b1Yxr1qAiXTMg1H8z9vx/VmJxBuQMHvU=\ngithub.com/ipfs/go-log/v2 v2.0.5/go.mod h1:eZs4Xt4ZUJQFM3DlanGhy7TkwwawCZcSByscwkWG+dw=\ngithub.com/jackpal/gateway v1.0.5/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA=\ngithub.com/jackpal/go-nat-pmp v1.0.1/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=\ngithub.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus=\ngithub.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=\ngithub.com/jbenet/go-cienv v0.0.0-20150120210510-1bb1476777ec/go.mod h1:rGaEvXB4uRSZMmzKNLoXvTu1sfx+1kv/DojUlPrSZGs=\ngithub.com/jbenet/go-cienv v0.1.0 h1:Vc/s0QbQtoxX8MwwSLWWh+xNNZvM3Lw7NsTcHrvvhMc=\ngithub.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA=\ngithub.com/jbenet/go-temp-err-catcher v0.0.0-20150120210811-aac704a3f4f2 h1:vhC1OXXiT9R2pczegwz6moDvuRpggaroAXhPIseh57A=\ngithub.com/jbenet/go-temp-err-catcher v0.0.0-20150120210811-aac704a3f4f2/go.mod h1:8GXXJV31xl8whumTzdZsTt3RnUIiPqzkyf7mxToRCMs=\ngithub.com/jbenet/goprocess v0.0.0-20160826012719-b497e2f366b8/go.mod h1:Ly/wlsjFq/qrU3Rar62tu1gASgGw6chQbSh/XgIIXCY=\ngithub.com/jbenet/goprocess v0.1.3/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4=\ngithub.com/jbenet/goprocess v0.1.4 h1:DRGOFReOMqqDNXwW70QkacFW0YN9QnwLV0Vqk+3oU0o=\ngithub.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4=\ngithub.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e/go.mod h1:G1CVv03EnqU1wYL2dFwXxW2An0az9JTl/ZsqXQeBlkU=\ngithub.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=\ngithub.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=\ngithub.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=\ngithub.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=\ngithub.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=\ngithub.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=\ngithub.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=\ngithub.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=\ngithub.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=\ngithub.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=\ngithub.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=\ngithub.com/jsternberg/zap-logfmt v1.0.0/go.mod h1:uvPs/4X51zdkcm5jXl5SYoN+4RK21K8mysFmDaM/h+o=\ngithub.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=\ngithub.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=\ngithub.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=\ngithub.com/jwilder/encoding v0.0.0-20170811194829-b4e1701a28ef/go.mod h1:Ct9fl0F6iIOGgxJ5npU/IUOhOhqlVrGjyIZc8/MagT0=\ngithub.com/kami-zh/go-capturer v0.0.0-20171211120116-e492ea43421d/go.mod h1:P2viExyCEfeWGU259JnaQ34Inuec4R38JCyBx2edgD0=\ngithub.com/karalabe/usb v0.0.2/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU=\ngithub.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=\ngithub.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=\ngithub.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=\ngithub.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=\ngithub.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=\ngithub.com/klauspost/cpuid v0.0.0-20170728055534-ae7887de9fa5/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=\ngithub.com/klauspost/crc32 v0.0.0-20161016154125-cb6bfca970f6/go.mod h1:+ZoRqAPRLkC4NPOvfYeR5KNOrY6TD+/sAC3HXPZgDYg=\ngithub.com/klauspost/pgzip v1.0.2-0.20170402124221-0bf5dcad4ada/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=\ngithub.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=\ngithub.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d h1:68u9r4wEvL3gYg2jvAOgROwZ3H+Y3hIDk4tbbmIjcYQ=\ngithub.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk=\ngithub.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=\ngithub.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=\ngithub.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=\ngithub.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=\ngithub.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=\ngithub.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=\ngithub.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=\ngithub.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=\ngithub.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=\ngithub.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=\ngithub.com/labstack/echo/v4 v4.2.1/go.mod h1:AA49e0DZ8kk5jTOOCKNuPR6oTnBS0dYiM4FW1e6jwpg=\ngithub.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=\ngithub.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8=\ngithub.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=\ngithub.com/libp2p/go-addr-util v0.0.1 h1:TpTQm9cXVRVSKsYbgQ7GKc3KbbHVTnbostgGaDEP+88=\ngithub.com/libp2p/go-addr-util v0.0.1/go.mod h1:4ac6O7n9rIAKB1dnd+s8IbbMXkt+oBpzX4/+RACcnlQ=\ngithub.com/libp2p/go-buffer-pool v0.0.1/go.mod h1:xtyIz9PMobb13WaxR6Zo1Pd1zXJKYg0a8KiIvDp3TzQ=\ngithub.com/libp2p/go-buffer-pool v0.0.2 h1:QNK2iAFa8gjAe1SPz6mHSMuCcjs+X1wlHzeOSqcmlfs=\ngithub.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoRZd1Vi32+RXyFM=\ngithub.com/libp2p/go-conn-security-multistream v0.1.0/go.mod h1:aw6eD7LOsHEX7+2hJkDxw1MteijaVcI+/eP2/x3J1xc=\ngithub.com/libp2p/go-conn-security-multistream v0.2.0 h1:uNiDjS58vrvJTg9jO6bySd1rMKejieG7v45ekqHbZ1M=\ngithub.com/libp2p/go-conn-security-multistream v0.2.0/go.mod h1:hZN4MjlNetKD3Rq5Jb/P5ohUnFLNzEAR4DLSzpn2QLU=\ngithub.com/libp2p/go-eventbus v0.1.0 h1:mlawomSAjjkk97QnYiEmHsLu7E136+2oCWSHRUvMfzQ=\ngithub.com/libp2p/go-eventbus v0.1.0/go.mod h1:vROgu5cs5T7cv7POWlWxBaVLxfSegC5UGQf8A2eEmx4=\ngithub.com/libp2p/go-flow-metrics v0.0.1/go.mod h1:Iv1GH0sG8DtYN3SVJ2eG221wMiNpZxBdp967ls1g+k8=\ngithub.com/libp2p/go-flow-metrics v0.0.2/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs=\ngithub.com/libp2p/go-flow-metrics v0.0.3 h1:8tAs/hSdNvUiLgtlSy3mxwxWP4I9y/jlkPFT7epKdeM=\ngithub.com/libp2p/go-flow-metrics v0.0.3/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs=\ngithub.com/libp2p/go-libp2p v0.6.1/go.mod h1:CTFnWXogryAHjXAKEbOf1OWY+VeAP3lDMZkfEI5sT54=\ngithub.com/libp2p/go-libp2p v0.7.0/go.mod h1:hZJf8txWeCduQRDC/WSqBGMxaTHCOYHt2xSU1ivxn0k=\ngithub.com/libp2p/go-libp2p v0.7.4/go.mod h1:oXsBlTLF1q7pxr+9w6lqzS1ILpyHsaBPniVO7zIHGMw=\ngithub.com/libp2p/go-libp2p v0.8.2/go.mod h1:NQDA/F/qArMHGe0J7sDScaKjW8Jh4y/ozQqBbYJ+BnA=\ngithub.com/libp2p/go-libp2p v0.8.3 h1:IFWeNzxkBaNO1N8stN9ayFGdC6RmVuSsKd5bou7qpK0=\ngithub.com/libp2p/go-libp2p v0.8.3/go.mod h1:EsH1A+8yoWK+L4iKcbPYu6MPluZ+CHWI9El8cTaefiM=\ngithub.com/libp2p/go-libp2p-autonat v0.1.1/go.mod h1:OXqkeGOY2xJVWKAGV2inNF5aKN/djNA3fdpCWloIudE=\ngithub.com/libp2p/go-libp2p-autonat v0.2.0/go.mod h1:DX+9teU4pEEoZUqR1PiMlqliONQdNbfzE1C718tcViI=\ngithub.com/libp2p/go-libp2p-autonat v0.2.1/go.mod h1:MWtAhV5Ko1l6QBsHQNSuM6b1sRkXrpk0/LqCr+vCVxI=\ngithub.com/libp2p/go-libp2p-autonat v0.2.2 h1:4dlgcEEugTFWSvdG2UIFxhnOMpX76QaZSRAtXmYB8n4=\ngithub.com/libp2p/go-libp2p-autonat v0.2.2/go.mod h1:HsM62HkqZmHR2k1xgX34WuWDzk/nBwNHoeyyT4IWV6A=\ngithub.com/libp2p/go-libp2p-blankhost v0.1.1/go.mod h1:pf2fvdLJPsC1FsVrNP3DUUvMzUts2dsLLBEpo1vW1ro=\ngithub.com/libp2p/go-libp2p-blankhost v0.1.4 h1:I96SWjR4rK9irDHcHq3XHN6hawCRTPUADzkJacgZLvk=\ngithub.com/libp2p/go-libp2p-blankhost v0.1.4/go.mod h1:oJF0saYsAXQCSfDq254GMNmLNz6ZTHTOvtF4ZydUvwU=\ngithub.com/libp2p/go-libp2p-circuit v0.1.4/go.mod h1:CY67BrEjKNDhdTk8UgBX1Y/H5c3xkAcs3gnksxY7osU=\ngithub.com/libp2p/go-libp2p-circuit v0.2.1/go.mod h1:BXPwYDN5A8z4OEY9sOfr2DUQMLQvKt/6oku45YUmjIo=\ngithub.com/libp2p/go-libp2p-circuit v0.2.2 h1:87RLabJ9lrhoiSDDZyCJ80ZlI5TLJMwfyoGAaWXzWqA=\ngithub.com/libp2p/go-libp2p-circuit v0.2.2/go.mod h1:nkG3iE01tR3FoQ2nMm06IUrCpCyJp1Eo4A1xYdpjfs4=\ngithub.com/libp2p/go-libp2p-core v0.0.1/go.mod h1:g/VxnTZ/1ygHxH3dKok7Vno1VfpvGcGip57wjTU4fco=\ngithub.com/libp2p/go-libp2p-core v0.0.4/go.mod h1:jyuCQP356gzfCFtRKyvAbNkyeuxb7OlyhWZ3nls5d2I=\ngithub.com/libp2p/go-libp2p-core v0.2.0/go.mod h1:X0eyB0Gy93v0DZtSYbEM7RnMChm9Uv3j7yRXjO77xSI=\ngithub.com/libp2p/go-libp2p-core v0.2.2/go.mod h1:8fcwTbsG2B+lTgRJ1ICZtiM5GWCWZVoVrLaDRvIRng0=\ngithub.com/libp2p/go-libp2p-core v0.2.4/go.mod h1:STh4fdfa5vDYr0/SzYYeqnt+E6KfEV5VxfIrm0bcI0g=\ngithub.com/libp2p/go-libp2p-core v0.2.5/go.mod h1:6+5zJmKhsf7yHn1RbmYDu08qDUpIUxGdqHuEZckmZOA=\ngithub.com/libp2p/go-libp2p-core v0.3.0/go.mod h1:ACp3DmS3/N64c2jDzcV429ukDpicbL6+TrrxANBjPGw=\ngithub.com/libp2p/go-libp2p-core v0.3.1/go.mod h1:thvWy0hvaSBhnVBaW37BvzgVV68OUhgJJLAa6almrII=\ngithub.com/libp2p/go-libp2p-core v0.4.0/go.mod h1:49XGI+kc38oGVwqSBhDEwytaAxgZasHhFfQKibzTls0=\ngithub.com/libp2p/go-libp2p-core v0.5.0/go.mod h1:49XGI+kc38oGVwqSBhDEwytaAxgZasHhFfQKibzTls0=\ngithub.com/libp2p/go-libp2p-core v0.5.1/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y=\ngithub.com/libp2p/go-libp2p-core v0.5.2/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y=\ngithub.com/libp2p/go-libp2p-core v0.5.3 h1:b9W3w7AZR2n/YJhG8d0qPFGhGhCWKIvPuJgp4hhc4MM=\ngithub.com/libp2p/go-libp2p-core v0.5.3/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y=\ngithub.com/libp2p/go-libp2p-crypto v0.1.0/go.mod h1:sPUokVISZiy+nNuTTH/TY+leRSxnFj/2GLjtOTW90hI=\ngithub.com/libp2p/go-libp2p-discovery v0.2.0/go.mod h1:s4VGaxYMbw4+4+tsoQTqh7wfxg97AEdo4GYBt6BadWg=\ngithub.com/libp2p/go-libp2p-discovery v0.3.0/go.mod h1:o03drFnz9BVAZdzC/QUQ+NeQOu38Fu7LJGEOK2gQltw=\ngithub.com/libp2p/go-libp2p-discovery v0.4.0 h1:dK78UhopBk48mlHtRCzbdLm3q/81g77FahEBTjcqQT8=\ngithub.com/libp2p/go-libp2p-discovery v0.4.0/go.mod h1:bZ0aJSrFc/eX2llP0ryhb1kpgkPyTo23SJ5b7UQCMh4=\ngithub.com/libp2p/go-libp2p-kad-dht v0.7.11 h1:MP0DEuxO/Blg1AklIVV1P4R5xtYX+ZyXBCtEN7f60yQ=\ngithub.com/libp2p/go-libp2p-kad-dht v0.7.11/go.mod h1:1ht6+bG3Or+fNNERWPYmLacs6TN0CxBkFB5IKIWWwOI=\ngithub.com/libp2p/go-libp2p-kbucket v0.4.1 h1:6FyzbQuGLPzbMv3HiD232zqscIz5iB8ppJwb380+OGI=\ngithub.com/libp2p/go-libp2p-kbucket v0.4.1/go.mod h1:7sCeZx2GkNK1S6lQnGUW5JYZCFPnXzAZCCBBS70lytY=\ngithub.com/libp2p/go-libp2p-loggables v0.1.0 h1:h3w8QFfCt2UJl/0/NW4K829HX/0S4KD31PQ7m8UXXO8=\ngithub.com/libp2p/go-libp2p-loggables v0.1.0/go.mod h1:EyumB2Y6PrYjr55Q3/tiJ/o3xoDasoRYM7nOzEpoa90=\ngithub.com/libp2p/go-libp2p-mplex v0.2.0/go.mod h1:Ejl9IyjvXJ0T9iqUTE1jpYATQ9NM3g+OtR+EMMODbKo=\ngithub.com/libp2p/go-libp2p-mplex v0.2.1/go.mod h1:SC99Rxs8Vuzrf/6WhmH41kNn13TiYdAWNYHrwImKLnE=\ngithub.com/libp2p/go-libp2p-mplex v0.2.2/go.mod h1:74S9eum0tVQdAfFiKxAyKzNdSuLqw5oadDq7+L/FELo=\ngithub.com/libp2p/go-libp2p-mplex v0.2.3 h1:2zijwaJvpdesST2MXpI5w9wWFRgYtMcpRX7rrw0jmOo=\ngithub.com/libp2p/go-libp2p-mplex v0.2.3/go.mod h1:CK3p2+9qH9x+7ER/gWWDYJ3QW5ZxWDkm+dVvjfuG3ek=\ngithub.com/libp2p/go-libp2p-nat v0.0.5/go.mod h1:1qubaE5bTZMJE+E/uu2URroMbzdubFz1ChgiN79yKPE=\ngithub.com/libp2p/go-libp2p-nat v0.0.6 h1:wMWis3kYynCbHoyKLPBEMu4YRLltbm8Mk08HGSfvTkU=\ngithub.com/libp2p/go-libp2p-nat v0.0.6/go.mod h1:iV59LVhB3IkFvS6S6sauVTSOrNEANnINbI/fkaLimiw=\ngithub.com/libp2p/go-libp2p-netutil v0.1.0 h1:zscYDNVEcGxyUpMd0JReUZTrpMfia8PmLKcKF72EAMQ=\ngithub.com/libp2p/go-libp2p-netutil v0.1.0/go.mod h1:3Qv/aDqtMLTUyQeundkKsA+YCThNdbQD54k3TqjpbFU=\ngithub.com/libp2p/go-libp2p-peer v0.2.0/go.mod h1:RCffaCvUyW2CJmG2gAWVqwePwW7JMgxjsHm7+J5kjWY=\ngithub.com/libp2p/go-libp2p-peerstore v0.1.0/go.mod h1:2CeHkQsr8svp4fZ+Oi9ykN1HBb6u0MOvdJ7YIsmcwtY=\ngithub.com/libp2p/go-libp2p-peerstore v0.1.3/go.mod h1:BJ9sHlm59/80oSkpWgr1MyY1ciXAXV397W6h1GH/uKI=\ngithub.com/libp2p/go-libp2p-peerstore v0.1.4/go.mod h1:+4BDbDiiKf4PzpANZDAT+knVdLxvqh7hXOujessqdzs=\ngithub.com/libp2p/go-libp2p-peerstore v0.2.0/go.mod h1:N2l3eVIeAitSg3Pi2ipSrJYnqhVnMNQZo9nkSCuAbnQ=\ngithub.com/libp2p/go-libp2p-peerstore v0.2.1/go.mod h1:NQxhNjWxf1d4w6PihR8btWIRjwRLBr4TYKfNgrUkOPA=\ngithub.com/libp2p/go-libp2p-peerstore v0.2.2/go.mod h1:NQxhNjWxf1d4w6PihR8btWIRjwRLBr4TYKfNgrUkOPA=\ngithub.com/libp2p/go-libp2p-peerstore v0.2.3 h1:MofRq2l3c15vQpEygTetV+zRRrncz+ktiXW7H2EKoEQ=\ngithub.com/libp2p/go-libp2p-peerstore v0.2.3/go.mod h1:K8ljLdFn590GMttg/luh4caB/3g0vKuY01psze0upRw=\ngithub.com/libp2p/go-libp2p-pnet v0.2.0 h1:J6htxttBipJujEjz1y0a5+eYoiPcFHhSYHH6na5f0/k=\ngithub.com/libp2p/go-libp2p-pnet v0.2.0/go.mod h1:Qqvq6JH/oMZGwqs3N1Fqhv8NVhrdYcO0BW4wssv21LA=\ngithub.com/libp2p/go-libp2p-record v0.1.2 h1:M50VKzWnmUrk/M5/Dz99qO9Xh4vs8ijsK+7HkJvRP+0=\ngithub.com/libp2p/go-libp2p-record v0.1.2/go.mod h1:pal0eNcT5nqZaTV7UGhqeGqxFgGdsU/9W//C8dqjQDk=\ngithub.com/libp2p/go-libp2p-routing-helpers v0.2.3/go.mod h1:795bh+9YeoFl99rMASoiVgHdi5bjack0N1+AFAdbvBw=\ngithub.com/libp2p/go-libp2p-secio v0.1.0/go.mod h1:tMJo2w7h3+wN4pgU2LSYeiKPrfqBgkOsdiKK77hE7c8=\ngithub.com/libp2p/go-libp2p-secio v0.2.0/go.mod h1:2JdZepB8J5V9mBp79BmwsaPQhRPNN2NrnB2lKQcdy6g=\ngithub.com/libp2p/go-libp2p-secio v0.2.1/go.mod h1:cWtZpILJqkqrSkiYcDBh5lA3wbT2Q+hz3rJQq3iftD8=\ngithub.com/libp2p/go-libp2p-secio v0.2.2 h1:rLLPvShPQAcY6eNurKNZq3eZjPWfU9kXF2eI9jIYdrg=\ngithub.com/libp2p/go-libp2p-secio v0.2.2/go.mod h1:wP3bS+m5AUnFA+OFO7Er03uO1mncHG0uVwGrwvjYlNY=\ngithub.com/libp2p/go-libp2p-swarm v0.1.0/go.mod h1:wQVsCdjsuZoc730CgOvh5ox6K8evllckjebkdiY5ta4=\ngithub.com/libp2p/go-libp2p-swarm v0.2.2/go.mod h1:fvmtQ0T1nErXym1/aa1uJEyN7JzaTNyBcHImCxRpPKU=\ngithub.com/libp2p/go-libp2p-swarm v0.2.3 h1:uVkCb8Blfg7HQ/f30TyHn1g/uCwXsAET7pU0U59gx/A=\ngithub.com/libp2p/go-libp2p-swarm v0.2.3/go.mod h1:P2VO/EpxRyDxtChXz/VPVXyTnszHvokHKRhfkEgFKNM=\ngithub.com/libp2p/go-libp2p-testing v0.0.2/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E=\ngithub.com/libp2p/go-libp2p-testing v0.0.3/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E=\ngithub.com/libp2p/go-libp2p-testing v0.0.4/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E=\ngithub.com/libp2p/go-libp2p-testing v0.1.0/go.mod h1:xaZWMJrPUM5GlDBxCeGUi7kI4eqnjVyavGroI2nxEM0=\ngithub.com/libp2p/go-libp2p-testing v0.1.1 h1:U03z3HnGI7Ni8Xx6ONVZvUFOAzWYmolWf5W5jAOPNmU=\ngithub.com/libp2p/go-libp2p-testing v0.1.1/go.mod h1:xaZWMJrPUM5GlDBxCeGUi7kI4eqnjVyavGroI2nxEM0=\ngithub.com/libp2p/go-libp2p-tls v0.1.3 h1:twKMhMu44jQO+HgQK9X8NHO5HkeJu2QbhLzLJpa8oNM=\ngithub.com/libp2p/go-libp2p-tls v0.1.3/go.mod h1:wZfuewxOndz5RTnCAxFliGjvYSDA40sKitV4c50uI1M=\ngithub.com/libp2p/go-libp2p-transport-upgrader v0.1.1/go.mod h1:IEtA6or8JUbsV07qPW4r01GnTenLW4oi3lOPbUMGJJA=\ngithub.com/libp2p/go-libp2p-transport-upgrader v0.2.0 h1:5EhPgQhXZNyfL22ERZTUoVp9UVVbNowWNVtELQaKCHk=\ngithub.com/libp2p/go-libp2p-transport-upgrader v0.2.0/go.mod h1:mQcrHj4asu6ArfSoMuyojOdjx73Q47cYD7s5+gZOlns=\ngithub.com/libp2p/go-libp2p-yamux v0.2.0/go.mod h1:Db2gU+XfLpm6E4rG5uGCFX6uXA8MEXOxFcRoXUODaK8=\ngithub.com/libp2p/go-libp2p-yamux v0.2.2/go.mod h1:lIohaR0pT6mOt0AZ0L2dFze9hds9Req3OfS+B+dv4qw=\ngithub.com/libp2p/go-libp2p-yamux v0.2.5/go.mod h1:Zpgj6arbyQrmZ3wxSZxfBmbdnWtbZ48OpsfmQVTErwA=\ngithub.com/libp2p/go-libp2p-yamux v0.2.7 h1:vzKu0NVtxvEIDGCv6mjKRcK0gipSgaXmJZ6jFv0d/dk=\ngithub.com/libp2p/go-libp2p-yamux v0.2.7/go.mod h1:X28ENrBMU/nm4I3Nx4sZ4dgjZ6VhLEn0XhIoZ5viCwU=\ngithub.com/libp2p/go-maddr-filter v0.0.4/go.mod h1:6eT12kSQMA9x2pvFQa+xesMKUBlj9VImZbj3B9FBH/Q=\ngithub.com/libp2p/go-maddr-filter v0.0.5 h1:CW3AgbMO6vUvT4kf87y4N+0P8KUl2aqLYhrGyDUbLSg=\ngithub.com/libp2p/go-maddr-filter v0.0.5/go.mod h1:Jk+36PMfIqCJhAnaASRH83bdAvfDRp/w6ENFaC9bG+M=\ngithub.com/libp2p/go-mplex v0.0.3/go.mod h1:pK5yMLmOoBR1pNCqDlA2GQrdAVTMkqFalaTWe7l4Yd0=\ngithub.com/libp2p/go-mplex v0.1.0/go.mod h1:SXgmdki2kwCUlCCbfGLEgHjC4pFqhTp0ZoV6aiKgxDU=\ngithub.com/libp2p/go-mplex v0.1.1/go.mod h1:Xgz2RDCi3co0LeZfgjm4OgUF15+sVR8SRcu3SFXI1lk=\ngithub.com/libp2p/go-mplex v0.1.2 h1:qOg1s+WdGLlpkrczDqmhYzyk3vCfsQ8+RxRTQjOZWwI=\ngithub.com/libp2p/go-mplex v0.1.2/go.mod h1:Xgz2RDCi3co0LeZfgjm4OgUF15+sVR8SRcu3SFXI1lk=\ngithub.com/libp2p/go-msgio v0.0.2/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ=\ngithub.com/libp2p/go-msgio v0.0.4 h1:agEFehY3zWJFUHK6SEMR7UYmk2z6kC3oeCM7ybLhguA=\ngithub.com/libp2p/go-msgio v0.0.4/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ=\ngithub.com/libp2p/go-nat v0.0.4/go.mod h1:Nmw50VAvKuk38jUBcmNh6p9lUJLoODbJRvYAa/+KSDo=\ngithub.com/libp2p/go-nat v0.0.5 h1:qxnwkco8RLKqVh1NmjQ+tJ8p8khNLFxuElYG/TwqW4Q=\ngithub.com/libp2p/go-nat v0.0.5/go.mod h1:B7NxsVNPZmRLvMOwiEO1scOSyjA56zxYAGv1yQgRkEU=\ngithub.com/libp2p/go-netroute v0.1.2 h1:UHhB35chwgvcRI392znJA3RCBtZ3MpE3ahNCN5MR4Xg=\ngithub.com/libp2p/go-netroute v0.1.2/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk=\ngithub.com/libp2p/go-openssl v0.0.2/go.mod h1:v8Zw2ijCSWBQi8Pq5GAixw6DbFfa9u6VIYDXnvOXkc0=\ngithub.com/libp2p/go-openssl v0.0.3/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc=\ngithub.com/libp2p/go-openssl v0.0.4 h1:d27YZvLoTyMhIN4njrkr8zMDOM4lfpHIp6A+TK9fovg=\ngithub.com/libp2p/go-openssl v0.0.4/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc=\ngithub.com/libp2p/go-reuseport v0.0.1 h1:7PhkfH73VXfPJYKQ6JwS5I/eVcoyYi9IMNGc6FWpFLw=\ngithub.com/libp2p/go-reuseport v0.0.1/go.mod h1:jn6RmB1ufnQwl0Q1f+YxAj8isJgDCQzaaxIFYDhcYEA=\ngithub.com/libp2p/go-reuseport-transport v0.0.2/go.mod h1:YkbSDrvjUVDL6b8XqriyA20obEtsW9BLkuOUyQAOCbs=\ngithub.com/libp2p/go-reuseport-transport v0.0.3 h1:zzOeXnTooCkRvoH+bSXEfXhn76+LAiwoneM0gnXjF2M=\ngithub.com/libp2p/go-reuseport-transport v0.0.3/go.mod h1:Spv+MPft1exxARzP2Sruj2Wb5JSyHNncjf1Oi2dEbzM=\ngithub.com/libp2p/go-sockaddr v0.0.2 h1:tCuXfpA9rq7llM/v834RKc/Xvovy/AqM9kHvTV/jY/Q=\ngithub.com/libp2p/go-sockaddr v0.0.2/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k=\ngithub.com/libp2p/go-stream-muxer v0.0.1/go.mod h1:bAo8x7YkSpadMTbtTaxGVHWUQsR/l5MEaHbKaliuT14=\ngithub.com/libp2p/go-stream-muxer-multistream v0.2.0/go.mod h1:j9eyPol/LLRqT+GPLSxvimPhNph4sfYfMoDPd7HkzIc=\ngithub.com/libp2p/go-stream-muxer-multistream v0.3.0 h1:TqnSHPJEIqDEO7h1wZZ0p3DXdvDSiLHQidKKUGZtiOY=\ngithub.com/libp2p/go-stream-muxer-multistream v0.3.0/go.mod h1:yDh8abSIzmZtqtOt64gFJUXEryejzNb0lisTt+fAMJA=\ngithub.com/libp2p/go-tcp-transport v0.1.0/go.mod h1:oJ8I5VXryj493DEJ7OsBieu8fcg2nHGctwtInJVpipc=\ngithub.com/libp2p/go-tcp-transport v0.1.1/go.mod h1:3HzGvLbx6etZjnFlERyakbaYPdfjg2pWP97dFZworkY=\ngithub.com/libp2p/go-tcp-transport v0.2.0 h1:YoThc549fzmNJIh7XjHVtMIFaEDRtIrtWciG5LyYAPo=\ngithub.com/libp2p/go-tcp-transport v0.2.0/go.mod h1:vX2U0CnWimU4h0SGSEsg++AzvBcroCGYw28kh94oLe0=\ngithub.com/libp2p/go-ws-transport v0.2.0/go.mod h1:9BHJz/4Q5A9ludYWKoGCFC5gUElzlHoKzu0yY9p/klM=\ngithub.com/libp2p/go-ws-transport v0.3.0/go.mod h1:bpgTJmRZAvVHrgHybCVyqoBmyLQ1fiZuEaBYusP5zsk=\ngithub.com/libp2p/go-ws-transport v0.3.1 h1:ZX5rWB8nhRRJVaPO6tmkGI/Xx8XNboYX20PW5hXIscw=\ngithub.com/libp2p/go-ws-transport v0.3.1/go.mod h1:bpgTJmRZAvVHrgHybCVyqoBmyLQ1fiZuEaBYusP5zsk=\ngithub.com/libp2p/go-yamux v1.2.2/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow=\ngithub.com/libp2p/go-yamux v1.3.0/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow=\ngithub.com/libp2p/go-yamux v1.3.3/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow=\ngithub.com/libp2p/go-yamux v1.3.5 h1:ibuz4naPAully0pN6J/kmUARiqLpnDQIzI/8GCOrljg=\ngithub.com/libp2p/go-yamux v1.3.5/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow=\ngithub.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=\ngithub.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=\ngithub.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=\ngithub.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=\ngithub.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ=\ngithub.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=\ngithub.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=\ngithub.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=\ngithub.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=\ngithub.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=\ngithub.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=\ngithub.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=\ngithub.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=\ngithub.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=\ngithub.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=\ngithub.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=\ngithub.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=\ngithub.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=\ngithub.com/mattn/go-tty v0.0.0-20180907095812-13ff1204f104/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE=\ngithub.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=\ngithub.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=\ngithub.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=\ngithub.com/miekg/dns v1.1.12/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=\ngithub.com/miekg/dns v1.1.28/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=\ngithub.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g=\ngithub.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ=\ngithub.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U=\ngithub.com/minio/sha256-simd v0.0.0-20190328051042-05b4dd3047e5/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U=\ngithub.com/minio/sha256-simd v0.1.0/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U=\ngithub.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=\ngithub.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU=\ngithub.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=\ngithub.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=\ngithub.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=\ngithub.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=\ngithub.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4=\ngithub.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=\ngithub.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=\ngithub.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=\ngithub.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=\ngithub.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8=\ngithub.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8=\ngithub.com/mr-tron/base58 v1.1.1/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8=\ngithub.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=\ngithub.com/mr-tron/base58 v1.1.3 h1:v+sk57XuaCKGXpWtVBX8YJzO7hMGx4Aajh4TQbdEFdc=\ngithub.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=\ngithub.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg=\ngithub.com/multiformats/go-base32 v0.0.3 h1:tw5+NhuwaOjJCC5Pp82QuXbrmLzWg7uxlMFp8Nq/kkI=\ngithub.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA=\ngithub.com/multiformats/go-multiaddr v0.0.1/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44=\ngithub.com/multiformats/go-multiaddr v0.0.2/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44=\ngithub.com/multiformats/go-multiaddr v0.0.4/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44=\ngithub.com/multiformats/go-multiaddr v0.1.0/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44=\ngithub.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo=\ngithub.com/multiformats/go-multiaddr v0.2.0/go.mod h1:0nO36NvPpyV4QzvTLi/lafl2y95ncPj0vFwVF6k6wJ4=\ngithub.com/multiformats/go-multiaddr v0.2.1 h1:SgG/cw5vqyB5QQe5FPe2TqggU9WtrA9X4nZw7LlVqOI=\ngithub.com/multiformats/go-multiaddr v0.2.1/go.mod h1:s/Apk6IyxfvMjDafnhJgJ3/46z7tZ04iMk5wP4QMGGE=\ngithub.com/multiformats/go-multiaddr-dns v0.0.1/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q=\ngithub.com/multiformats/go-multiaddr-dns v0.0.2/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q=\ngithub.com/multiformats/go-multiaddr-dns v0.2.0 h1:YWJoIDwLePniH7OU5hBnDZV6SWuvJqJ0YtN6pLeH9zA=\ngithub.com/multiformats/go-multiaddr-dns v0.2.0/go.mod h1:TJ5pr5bBO7Y1B18djPuRsVkduhQH2YqYSbxWJzYGdK0=\ngithub.com/multiformats/go-multiaddr-fmt v0.0.1/go.mod h1:aBYjqL4T/7j4Qx+R73XSv/8JsgnRFlf0w2KGLCmXl3Q=\ngithub.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E=\ngithub.com/multiformats/go-multiaddr-fmt v0.1.0/go.mod h1:hGtDIW4PU4BqJ50gW2quDuPVjyWNZxToGUh/HwTZYJo=\ngithub.com/multiformats/go-multiaddr-net v0.0.1/go.mod h1:nw6HSxNmCIQH27XPGBuX+d1tnvM7ihcFwHMSstNAVUU=\ngithub.com/multiformats/go-multiaddr-net v0.1.0/go.mod h1:5JNbcfBOP4dnhoZOv10JJVkJO0pCCEf8mTnipAo2UZQ=\ngithub.com/multiformats/go-multiaddr-net v0.1.1/go.mod h1:5JNbcfBOP4dnhoZOv10JJVkJO0pCCEf8mTnipAo2UZQ=\ngithub.com/multiformats/go-multiaddr-net v0.1.2/go.mod h1:QsWt3XK/3hwvNxZJp92iMQKME1qHfpYmyIjFVsSOY6Y=\ngithub.com/multiformats/go-multiaddr-net v0.1.3/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA=\ngithub.com/multiformats/go-multiaddr-net v0.1.4 h1:g6gwydsfADqFvrHoMkS0n9Ok9CG6F7ytOH/bJDkhIOY=\ngithub.com/multiformats/go-multiaddr-net v0.1.4/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA=\ngithub.com/multiformats/go-multibase v0.0.1 h1:PN9/v21eLywrFWdFNsFKaU04kLJzuYzmrJR+ubhT9qA=\ngithub.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs=\ngithub.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U=\ngithub.com/multiformats/go-multihash v0.0.5/go.mod h1:lt/HCbqlQwlPBz7lv0sQCdtfcMtlJvakRUn/0Ual8po=\ngithub.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew=\ngithub.com/multiformats/go-multihash v0.0.9/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew=\ngithub.com/multiformats/go-multihash v0.0.10/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew=\ngithub.com/multiformats/go-multihash v0.0.13 h1:06x+mk/zj1FoMsgNejLpy6QTvJqlSt/BhLEy87zidlc=\ngithub.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc=\ngithub.com/multiformats/go-multistream v0.1.0/go.mod h1:fJTiDfXJVmItycydCnNx4+wSzZ5NwG2FEVAI30fiovg=\ngithub.com/multiformats/go-multistream v0.1.1 h1:JlAdpIFhBhGRLxe9W6Om0w++Gd6KMWoFPZL/dEnm9nI=\ngithub.com/multiformats/go-multistream v0.1.1/go.mod h1:KmHZ40hzVxiaiwlj3MEbYgK9JFk2/9UktWZAF54Du38=\ngithub.com/multiformats/go-varint v0.0.1/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=\ngithub.com/multiformats/go-varint v0.0.2/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=\ngithub.com/multiformats/go-varint v0.0.5 h1:XVZwSo04Cs3j/jS0uAEPpT3JY6DzMcVLLoWOSnCxOjg=\ngithub.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=\ngithub.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=\ngithub.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0=\ngithub.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E=\ngithub.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=\ngithub.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=\ngithub.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=\ngithub.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=\ngithub.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=\ngithub.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=\ngithub.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=\ngithub.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg=\ngithub.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=\ngithub.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA=\ngithub.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=\ngithub.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=\ngithub.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=\ngithub.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=\ngithub.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=\ngithub.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE=\ngithub.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=\ngithub.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=\ngithub.com/opentracing/opentracing-go v1.0.3-0.20180606204148-bd9c31933947/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=\ngithub.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU=\ngithub.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=\ngithub.com/paulbellamy/ratecounter v0.2.0/go.mod h1:Hfx1hDpSGoqxkVVpBi/IlYD7kChlfo5C6hzIHwPqfFE=\ngithub.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=\ngithub.com/peterh/liner v1.0.1-0.20180619022028-8c1271fcf47f/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc=\ngithub.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0=\ngithub.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=\ngithub.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=\ngithub.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=\ngithub.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pkg/term v0.0.0-20180730021639-bffc007b7fd5/go.mod h1:eCbImbZ95eXtAUIbLAuAVnBnwf83mjf6QIVH8SHYwqQ=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=\ngithub.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=\ngithub.com/prometheus/client_golang v1.7.1 h1:NTGy1Ja9pByO+xAeH/qiWnLrKtr3hJPNjaVUwnjpdpA=\ngithub.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=\ngithub.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=\ngithub.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=\ngithub.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=\ngithub.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=\ngithub.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=\ngithub.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=\ngithub.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=\ngithub.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=\ngithub.com/prometheus/common v0.10.0 h1:RyRA7RzGXQZiW+tGMr7sxa85G1z0yOpM1qq5c8lNawc=\ngithub.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=\ngithub.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=\ngithub.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=\ngithub.com/prometheus/procfs v0.1.3 h1:F0+tqvhOksq22sc6iCHF5WGlWjdwj92p0udFh1VFBS8=\ngithub.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=\ngithub.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=\ngithub.com/retailnext/hllpp v1.0.1-0.20180308014038-101a6d2f8b52/go.mod h1:RDpi1RftBQPUCDRw6SmxeaREsAaRKnOclghuzp/WRzc=\ngithub.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho=\ngithub.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=\ngithub.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=\ngithub.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=\ngithub.com/rs/zerolog v1.21.0 h1:Q3vdXlfLNT+OftyBHsU0Y445MD+8m8axjKgf2si0QcM=\ngithub.com/rs/zerolog v1.21.0/go.mod h1:ZPhntP/xmq1nnND05hhpAh2QMhSsA4UN3MGZ6O2J3hM=\ngithub.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=\ngithub.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=\ngithub.com/segmentio/kafka-go v0.1.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo=\ngithub.com/segmentio/kafka-go v0.2.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo=\ngithub.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=\ngithub.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=\ngithub.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=\ngithub.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=\ngithub.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=\ngithub.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=\ngithub.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=\ngithub.com/smola/gocompat v0.2.0/go.mod h1:1B0MlxbmoZNo3h8guHp8HztB3BSYR5itql9qtVc0ypY=\ngithub.com/spacemonkeygo/openssl v0.0.0-20181017203307-c2dcc5cca94a/go.mod h1:7AyxJNCJ7SBZ1MfVQCWD6Uqo2oubI2Eq2y2eqf+A5r0=\ngithub.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 h1:RC6RW7j+1+HkWaX/Yh71Ee5ZHaHYt7ZP4sQgUrm6cDU=\ngithub.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w0SWMsp6j9O/dk4/ZpIhL+3CkG8ofA2vuv7k+ltqUMc=\ngithub.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=\ngithub.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=\ngithub.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=\ngithub.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=\ngithub.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=\ngithub.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=\ngithub.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=\ngithub.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=\ngithub.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=\ngithub.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=\ngithub.com/src-d/envconfig v1.0.0/go.mod h1:Q9YQZ7BKITldTBnoxsE5gOeB5y66RyPXeue/R4aaNBc=\ngithub.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q=\ngithub.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/testify v1.2.0/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=\ngithub.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=\ngithub.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=\ngithub.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=\ngithub.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=\ngithub.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=\ngithub.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=\ngithub.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc=\ngithub.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=\ngithub.com/tklauser/go-sysconf v0.3.5/go.mod h1:MkWzOF4RMCshBAMXuhXJs64Rte09mITnppBXY/rYEFI=\ngithub.com/tklauser/numcpus v0.2.2/go.mod h1:x3qojaO3uyYt0i56EW/VUYs7uBvdl2fkfZFu0T9wgjM=\ngithub.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs=\ngithub.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=\ngithub.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=\ngithub.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=\ngithub.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=\ngithub.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=\ngithub.com/wangjia184/sortedset v0.0.0-20160527075905-f5d03557ba30/go.mod h1:YkocrP2K2tcw938x9gCOmT5G5eCD6jsTz0SZuyAqwIE=\ngithub.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 h1:EKhdznlJHPMoKr0XTrX+IlJs1LH3lyx2nfr1dOlZ79k=\ngithub.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1/go.mod h1:8UvriyWtv5Q5EOgjHaSseUEdkQfvwFv1I/In/O2M9gc=\ngithub.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc/go.mod h1:bopw91TMyo8J3tvftk8xmU2kPmlrt4nScJQZU2hE5EM=\ngithub.com/whyrusleeping/go-logging v0.0.1/go.mod h1:lDPYj54zutzG1XYfHAhcc7oNXEburHQBn+Iqd4yS4vE=\ngithub.com/whyrusleeping/mafmt v1.2.8 h1:TCghSl5kkwEE0j+sU/gudyhVMRlpBin8fMBBHg59EbA=\ngithub.com/whyrusleeping/mafmt v1.2.8/go.mod h1:faQJFPbLSxzD9xpA02ttW/tS9vZykNvXwGvqIpk20FA=\ngithub.com/whyrusleeping/mdns v0.0.0-20190826153040-b9b60ed33aa9/go.mod h1:j4l84WPFclQPj320J9gp0XwNKBb3U0zt5CBqjPp22G4=\ngithub.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 h1:E9S12nwJwEOXe2d6gT6qxdvqMnNq+VnSsKPgm2ZZNds=\ngithub.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7/go.mod h1:X2c0RVCI1eSUFI8eLcY3c0423ykwiUdxLJtkDvruhjI=\ngithub.com/willf/bitset v1.1.3/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=\ngithub.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE=\ngithub.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg=\ngithub.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=\ngithub.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngo.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=\ngo.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=\ngo.opencensus.io v0.22.1/go.mod h1:Ap50jQcDJrx6rB6VgeeFPtuPIf3wMRvRfrfYDO6+BmA=\ngo.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=\ngo.opencensus.io v0.22.3 h1:8sGtKOrtQqkN1bp2AtX+misvLIlOmsEsNd+9NIcPEm8=\ngo.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=\ngo.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=\ngo.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=\ngo.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk=\ngo.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=\ngo.uber.org/goleak v1.0.0 h1:qsup4IcBdlmsnGfqyLl4Ntn3C2XCCuKAE7DwHpScyUo=\ngo.uber.org/goleak v1.0.0/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=\ngo.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=\ngo.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A=\ngo.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=\ngo.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4=\ngo.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=\ngo.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=\ngo.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=\ngo.uber.org/zap v1.14.1 h1:nYDKopTbvAPq/NrUVZwT15y2lpROBiLLyoRTbXOYWOo=\ngo.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc=\ngolang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=\ngolang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=\ngolang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=\ngolang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=\ngolang.org/x/crypto v0.0.0-20190225124518-7f87c0fbb88b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=\ngolang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=\ngolang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20190909091759-094676da4a83/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=\ngolang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 h1:It14KIkyBFYkHkwZ7k45minvA9aorojkyjGk9KJ5B/w=\ngolang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=\ngolang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=\ngolang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=\ngolang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=\ngolang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=\ngolang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=\ngolang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=\ngolang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=\ngolang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=\ngolang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=\ngolang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=\ngolang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=\ngolang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=\ngolang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=\ngolang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=\ngolang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=\ngolang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=\ngolang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f h1:J5lckAjkw6qYlOZNj90mLYNTEKDvWeuc1yieZ8qUzUE=\ngolang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=\ngolang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=\ngolang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=\ngolang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=\ngolang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=\ngolang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=\ngolang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=\ngolang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190227160552-c95aed5357e7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=\ngolang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=\ngolang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=\ngolang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=\ngolang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=\ngolang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=\ngolang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=\ngolang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=\ngolang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=\ngolang.org/x/net v0.0.0-20210805182204-aaa1db679c0d h1:20cMwl2fHAzkJMEA+8J4JgqBQcQGzbisXo31MIeenXI=\ngolang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=\ngolang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=\ngolang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=\ngolang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190405154228-4b34438f7a67/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190526052359-791d8a0f4d09/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200107162124-548cf772de50/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210316164454-77fc1eacc6aa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210420205809-ac73e9fd8988/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210816183151-1e6c022a8912 h1:uCLL3g5wH2xjxVREVuAbP9JM5PPKjRbXKRa6IBjkzmU=\ngolang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=\ngolang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=\ngolang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=\ngolang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=\ngolang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=\ngolang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=\ngolang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=\ngolang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=\ngolang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=\ngolang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20181130052023-1c3d964395ce/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=\ngolang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=\ngolang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=\ngolang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=\ngolang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=\ngolang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=\ngolang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=\ngolang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200108203644-89082a384178/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY=\ngolang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=\ngolang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=\ngolang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo=\ngonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo=\ngonum.org/v1/gonum v0.6.0/go.mod h1:9mxDZsDKxgMAuccQkewq682L+0eCu4dCN2yonUJTCLU=\ngonum.org/v1/netlib v0.0.0-20181029234149-ec6d1f5cefe6/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw=\ngonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw=\ngonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc=\ngoogle.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=\ngoogle.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=\ngoogle.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=\ngoogle.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=\ngoogle.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=\ngoogle.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=\ngoogle.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=\ngoogle.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=\ngoogle.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=\ngoogle.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=\ngoogle.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=\ngoogle.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=\ngoogle.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=\ngoogle.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=\ngoogle.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190716160619-c506a9f90610/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=\ngoogle.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=\ngoogle.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=\ngoogle.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=\ngoogle.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20200108215221-bd8f9a0ef82f/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=\ngoogle.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=\ngoogle.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=\ngoogle.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=\ngoogle.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=\ngoogle.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=\ngoogle.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=\ngoogle.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=\ngoogle.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=\ngoogle.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=\ngoogle.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=\ngoogle.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=\ngoogle.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=\ngoogle.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=\ngoogle.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=\ngoogle.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=\ngoogle.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=\ngopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=\ngopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=\ngopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=\ngopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c=\ngopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns=\ngopkg.in/src-d/go-cli.v0 v0.0.0-20181105080154-d492247bbc0d/go.mod h1:z+K8VcOYVYcSwSjGebuDL6176A1XskgbtNl64NSg+n8=\ngopkg.in/src-d/go-log.v1 v1.0.1/go.mod h1:GN34hKP0g305ysm2/hctJ0Y8nWP3zxXXJ8GFabTyABE=\ngopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=\ngopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=\ngopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0=\ngopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=\ngopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=\ngopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=\ngopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=\nhonnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=\nhonnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las=\nhonnef.co/go/tools v0.1.4 h1:SadWOkti5uVN1FAMgxn165+Mw00fuQKyk4Gyn/inxNQ=\nhonnef.co/go/tools v0.1.4/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las=\nrsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=\nrsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=\n"
  },
  {
    "path": "libs/go/libp2p_node/libp2p_node.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2019 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\n\npackage main\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"os/signal\"\n\t\"syscall\"\n\t\"time\"\n\n\t\"github.com/rs/zerolog\"\n\n\taea \"libp2p_node/aea\"\n\t\"libp2p_node/dht/dhtclient\"\n\t\"libp2p_node/dht/dhtnode\"\n\t\"libp2p_node/dht/dhtpeer\"\n\t\"libp2p_node/utils\"\n)\n\nconst (\n\tlibp2pNodePanicError      = \"LIBP2P_NODE_PANIC_ERROR\"\n\tlibp2pMultiaddrsListStart = \"MULTIADDRS_LIST_START\"\n\tlibp2pMultiaddrsListEnd   = \"MULTIADDRS_LIST_END\"\n)\n\nvar logger zerolog.Logger = utils.NewDefaultLogger()\n\n// panics if err is not nil\nfunc check(err error) {\n\tif err != nil {\n\t\tfmt.Println(libp2pNodePanicError, \":\", err.Error())\n\t\tpanic(err)\n\t}\n}\n\nfunc main() {\n\n\tvar err error\n\n\t// Initialize connection to aea\n\tagent := aea.AeaApi{}\n\tcheck(agent.Init())\n\tlogger.Info().Msg(\"successfully initialized API to AEA!\")\n\n\t// Get node configuration\n\n\t// aea agent address\n\taeaAddr := agent.AeaAddress()\n\n\t// node address (ip and port)\n\tnodeHost, nodePort := agent.Address()\n\n\t// node public address, if set\n\tnodeHostPublic, nodePortPublic := agent.PublicAddress()\n\n\t// node delegate service address, if set\n\t_, nodePortDelegate := agent.DelegateAddress()\n\n\t// node monitoring service address, if set\n\t_, nodePortMonitoring := agent.MonitoringAddress()\n\n\t// node private key\n\tkey := agent.PrivateKey()\n\n\t// entry peers\n\tentryPeers := agent.EntryPeers()\n\n\t// agent proof of representation\n\trecord := agent.AgentRecord()\n\n\t// add artificial delay for agent registration\n\tregistrationDelay := agent.RegistrationDelayInSeconds()\n\n\t// persist agent records to file\n\tstoragePath := agent.RecordStoragePath()\n\t// libp2p node\n\tvar node dhtnode.DHTNode\n\n\t// Run as a peer or just as a client\n\tif nodePortPublic == 0 {\n\t\t// if no external address is provided, run as a client\n\t\topts := []dhtclient.Option{\n\t\t\tdhtclient.IdentityFromFetchAIKey(key),\n\t\t\tdhtclient.BootstrapFrom(entryPeers),\n\t\t}\n\t\tif record != nil {\n\t\t\topts = append(opts, dhtclient.RegisterAgentAddress(record, agent.Connected))\n\t\t}\n\t\tnode, err = dhtclient.New(opts...)\n\t} else {\n\t\topts := []dhtpeer.Option{\n\t\t\tdhtpeer.LocalURI(nodeHost, nodePort),\n\t\t\tdhtpeer.PublicURI(nodeHostPublic, nodePortPublic),\n\t\t\tdhtpeer.IdentityFromFetchAIKey(key),\n\t\t\tdhtpeer.EnableRelayService(),\n\t\t\tdhtpeer.EnableDelegateService(nodePortDelegate),\n\t\t\tdhtpeer.BootstrapFrom(entryPeers),\n\t\t}\n\t\tif record != nil {\n\t\t\topts = append(opts, dhtpeer.RegisterAgentAddress(record, agent.Connected))\n\t\t}\n\t\tif nodePortMonitoring != 0 {\n\t\t\topts = append(opts, dhtpeer.EnablePrometheusMonitoring(nodePortMonitoring))\n\t\t}\n\t\tif registrationDelay != 0 {\n\t\t\t//lint:ignore ST1011 don't use unit-specific suffix \"Seconds\"\n\t\t\tdurationSeconds := time.Duration(registrationDelay)\n\t\t\topts = append(opts, dhtpeer.WithRegistrationDelay(durationSeconds*1000000*time.Microsecond))\n\t\t}\n\t\tif storagePath != \"\" {\n\t\t\topts = append(opts, dhtpeer.StoreRecordsTo(storagePath))\n\t\t}\n\n\t\tif len(agent.MailboxUri()) > 0 {\n\t\t\topts = append(opts, dhtpeer.EnableMailboxService(agent.MailboxUri()))\n\t\t}\n\t\tnode, err = dhtpeer.New(opts...)\n\t}\n\n\tif err != nil {\n\t\tcheck(err)\n\t}\n\tdefer node.Close()\n\tlogger.Info().Msgf(\"Peer ID: %s\", node.PeerID())\n\t// Connect to the agent\n\tfmt.Println(libp2pMultiaddrsListStart) // keyword\n\tfmt.Println(node.MultiAddr())\n\tfmt.Println(libp2pMultiaddrsListEnd) // keyword\n\n\tcheck(agent.Connect())\n\tif aeaAddr != \"\" {\n\t\tlogger.Info().Msg(\"successfully connected to AEA!\")\n\t}\n\n\t// Receive envelopes from agent and forward to peer\n\tgo func() {\n\t\tfor envel := range agent.Queue() {\n\t\t\tenvelope := envel\n\t\t\tlogger.Info().Msgf(\"received envelope from agent: %s\", envelope)\n\t\t\terr := node.RouteEnvelope(envelope)\n\t\t\tif err != nil {\n\t\t\t\tlogger.Error().Msgf(\"Route envelope error: %s\", err.Error())\n\t\t\t}\n\t\t}\n\t}()\n\n\t// Deliver envelopes received fro DHT to agent\n\tnode.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\treturn agent.Put(envel)\n\t})\n\n\t// Wait until Ctrl+C or a termination call is done.\n\tc := make(chan os.Signal, 1)\n\tsignal.Notify(c, os.Interrupt)\n\n\t// SIGTERM for k8s graceful stop support\n\tsignal.Notify(c, syscall.SIGTERM)\n\n\t//wait for termination\n\t<-c\n\n\tlogger.Info().Msg(\"node stopped\")\n}\n"
  },
  {
    "path": "libs/go/libp2p_node/link",
    "content": "#!/usr/bin/python2\nimport argparse\nimport os\nimport subprocess\nimport sys\n\n\n# renamed 'link' file\noriginal_link_file = 'link_orig'\n\n# link first\noutput=None\ncode=0\ntry:\n    output = subprocess.check_output([os.path.dirname(__file__) + '/' + original_link_file] + sys.argv[1:], cwd=os.getcwd())\nexcept subprocess.CalledProcessError as e:\n    output = e.output\n    code = e.returncode\n\nif output:\n    print output.replace(original_link_file, 'link')\n\n# change max_prot value to 0x7\nparser = argparse.ArgumentParser()\nparser.add_argument('-o')\nargs, _ = parser.parse_known_args()\n\nif args.o:\n    binary_target = args.o\n    # only for testing\n    if binary_target.endswith('.test') or binary_target.endswith('_test_go'):\n        with open(os.devnull, 'wb') as DEVNULL:\n            try:\n                subprocess.check_call([\"printf '\\x07' | dd of=%s bs=1 seek=160 count=1 conv=notrunc\" % binary_target], shell=True, stdout=DEVNULL, stderr=DEVNULL)\n            except subprocess.CalledProcessError as e:\n                pass\n\nsys.exit(code)\n\n"
  },
  {
    "path": "libs/go/libp2p_node/mocks/mock_host.go",
    "content": "// Code generated by MockGen. DO NOT EDIT.\n// Source: github.com/libp2p/go-libp2p-core/host (interfaces: Host)\n\n// Package mock_host is a generated GoMock package.\npackage mocks\n\nimport (\n\tcontext \"context\"\n\treflect \"reflect\"\n\n\tgomock \"github.com/golang/mock/gomock\"\n\tconnmgr \"github.com/libp2p/go-libp2p-core/connmgr\"\n\tevent \"github.com/libp2p/go-libp2p-core/event\"\n\tnetwork \"github.com/libp2p/go-libp2p-core/network\"\n\tpeer \"github.com/libp2p/go-libp2p-core/peer\"\n\tpeerstore \"github.com/libp2p/go-libp2p-core/peerstore\"\n\tprotocol \"github.com/libp2p/go-libp2p-core/protocol\"\n\tmultiaddr \"github.com/multiformats/go-multiaddr\"\n)\n\n// MockHost is a mock of Host interface.\ntype MockHost struct {\n\tctrl     *gomock.Controller\n\trecorder *MockHostMockRecorder\n}\n\n// MockHostMockRecorder is the mock recorder for MockHost.\ntype MockHostMockRecorder struct {\n\tmock *MockHost\n}\n\n// NewMockHost creates a new mock instance.\nfunc NewMockHost(ctrl *gomock.Controller) *MockHost {\n\tmock := &MockHost{ctrl: ctrl}\n\tmock.recorder = &MockHostMockRecorder{mock}\n\treturn mock\n}\n\n// EXPECT returns an object that allows the caller to indicate expected use.\nfunc (m *MockHost) EXPECT() *MockHostMockRecorder {\n\treturn m.recorder\n}\n\n// Addrs mocks base method.\nfunc (m *MockHost) Addrs() []multiaddr.Multiaddr {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"Addrs\")\n\tret0, _ := ret[0].([]multiaddr.Multiaddr)\n\treturn ret0\n}\n\n// Addrs indicates an expected call of Addrs.\nfunc (mr *MockHostMockRecorder) Addrs() *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"Addrs\", reflect.TypeOf((*MockHost)(nil).Addrs))\n}\n\n// Close mocks base method.\nfunc (m *MockHost) Close() error {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"Close\")\n\tret0, _ := ret[0].(error)\n\treturn ret0\n}\n\n// Close indicates an expected call of Close.\nfunc (mr *MockHostMockRecorder) Close() *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"Close\", reflect.TypeOf((*MockHost)(nil).Close))\n}\n\n// ConnManager mocks base method.\nfunc (m *MockHost) ConnManager() connmgr.ConnManager {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"ConnManager\")\n\tret0, _ := ret[0].(connmgr.ConnManager)\n\treturn ret0\n}\n\n// ConnManager indicates an expected call of ConnManager.\nfunc (mr *MockHostMockRecorder) ConnManager() *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"ConnManager\", reflect.TypeOf((*MockHost)(nil).ConnManager))\n}\n\n// Connect mocks base method.\nfunc (m *MockHost) Connect(arg0 context.Context, arg1 peer.AddrInfo) error {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"Connect\", arg0, arg1)\n\tret0, _ := ret[0].(error)\n\treturn ret0\n}\n\n// Connect indicates an expected call of Connect.\nfunc (mr *MockHostMockRecorder) Connect(arg0, arg1 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"Connect\", reflect.TypeOf((*MockHost)(nil).Connect), arg0, arg1)\n}\n\n// EventBus mocks base method.\nfunc (m *MockHost) EventBus() event.Bus {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"EventBus\")\n\tret0, _ := ret[0].(event.Bus)\n\treturn ret0\n}\n\n// EventBus indicates an expected call of EventBus.\nfunc (mr *MockHostMockRecorder) EventBus() *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"EventBus\", reflect.TypeOf((*MockHost)(nil).EventBus))\n}\n\n// ID mocks base method.\nfunc (m *MockHost) ID() peer.ID {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"ID\")\n\tret0, _ := ret[0].(peer.ID)\n\treturn ret0\n}\n\n// ID indicates an expected call of ID.\nfunc (mr *MockHostMockRecorder) ID() *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"ID\", reflect.TypeOf((*MockHost)(nil).ID))\n}\n\n// Mux mocks base method.\nfunc (m *MockHost) Mux() protocol.Switch {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"Mux\")\n\tret0, _ := ret[0].(protocol.Switch)\n\treturn ret0\n}\n\n// Mux indicates an expected call of Mux.\nfunc (mr *MockHostMockRecorder) Mux() *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"Mux\", reflect.TypeOf((*MockHost)(nil).Mux))\n}\n\n// Network mocks base method.\nfunc (m *MockHost) Network() network.Network {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"Network\")\n\tret0, _ := ret[0].(network.Network)\n\treturn ret0\n}\n\n// Network indicates an expected call of Network.\nfunc (mr *MockHostMockRecorder) Network() *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"Network\", reflect.TypeOf((*MockHost)(nil).Network))\n}\n\n// NewStream mocks base method.\nfunc (m *MockHost) NewStream(arg0 context.Context, arg1 peer.ID, arg2 ...protocol.ID) (network.Stream, error) {\n\tm.ctrl.T.Helper()\n\tvarargs := []interface{}{arg0, arg1}\n\tfor _, a := range arg2 {\n\t\tvarargs = append(varargs, a)\n\t}\n\tret := m.ctrl.Call(m, \"NewStream\", varargs...)\n\tret0, _ := ret[0].(network.Stream)\n\tret1, _ := ret[1].(error)\n\treturn ret0, ret1\n}\n\n// NewStream indicates an expected call of NewStream.\nfunc (mr *MockHostMockRecorder) NewStream(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\tvarargs := append([]interface{}{arg0, arg1}, arg2...)\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"NewStream\", reflect.TypeOf((*MockHost)(nil).NewStream), varargs...)\n}\n\n// Peerstore mocks base method.\nfunc (m *MockHost) Peerstore() peerstore.Peerstore {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"Peerstore\")\n\tret0, _ := ret[0].(peerstore.Peerstore)\n\treturn ret0\n}\n\n// Peerstore indicates an expected call of Peerstore.\nfunc (mr *MockHostMockRecorder) Peerstore() *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"Peerstore\", reflect.TypeOf((*MockHost)(nil).Peerstore))\n}\n\n// RemoveStreamHandler mocks base method.\nfunc (m *MockHost) RemoveStreamHandler(arg0 protocol.ID) {\n\tm.ctrl.T.Helper()\n\tm.ctrl.Call(m, \"RemoveStreamHandler\", arg0)\n}\n\n// RemoveStreamHandler indicates an expected call of RemoveStreamHandler.\nfunc (mr *MockHostMockRecorder) RemoveStreamHandler(arg0 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"RemoveStreamHandler\", reflect.TypeOf((*MockHost)(nil).RemoveStreamHandler), arg0)\n}\n\n// SetStreamHandler mocks base method.\nfunc (m *MockHost) SetStreamHandler(arg0 protocol.ID, arg1 network.StreamHandler) {\n\tm.ctrl.T.Helper()\n\tm.ctrl.Call(m, \"SetStreamHandler\", arg0, arg1)\n}\n\n// SetStreamHandler indicates an expected call of SetStreamHandler.\nfunc (mr *MockHostMockRecorder) SetStreamHandler(arg0, arg1 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"SetStreamHandler\", reflect.TypeOf((*MockHost)(nil).SetStreamHandler), arg0, arg1)\n}\n\n// SetStreamHandlerMatch mocks base method.\nfunc (m *MockHost) SetStreamHandlerMatch(arg0 protocol.ID, arg1 func(string) bool, arg2 network.StreamHandler) {\n\tm.ctrl.T.Helper()\n\tm.ctrl.Call(m, \"SetStreamHandlerMatch\", arg0, arg1, arg2)\n}\n\n// SetStreamHandlerMatch indicates an expected call of SetStreamHandlerMatch.\nfunc (mr *MockHostMockRecorder) SetStreamHandlerMatch(arg0, arg1, arg2 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"SetStreamHandlerMatch\", reflect.TypeOf((*MockHost)(nil).SetStreamHandlerMatch), arg0, arg1, arg2)\n}\n"
  },
  {
    "path": "libs/go/libp2p_node/mocks/mock_net.go",
    "content": "// Code generated by MockGen. DO NOT EDIT.\n// Source: net (interfaces: Conn)\n\n// Package mock_net is a generated GoMock package.\npackage mocks\n\nimport (\n\tnet \"net\"\n\treflect \"reflect\"\n\ttime \"time\"\n\n\tgomock \"github.com/golang/mock/gomock\"\n)\n\n// MockConn is a mock of Conn interface.\ntype MockConn struct {\n\tctrl     *gomock.Controller\n\trecorder *MockConnMockRecorder\n}\n\n// MockConnMockRecorder is the mock recorder for MockConn.\ntype MockConnMockRecorder struct {\n\tmock *MockConn\n}\n\n// NewMockConn creates a new mock instance.\nfunc NewMockConn(ctrl *gomock.Controller) *MockConn {\n\tmock := &MockConn{ctrl: ctrl}\n\tmock.recorder = &MockConnMockRecorder{mock}\n\treturn mock\n}\n\n// EXPECT returns an object that allows the caller to indicate expected use.\nfunc (m *MockConn) EXPECT() *MockConnMockRecorder {\n\treturn m.recorder\n}\n\n// Close mocks base method.\nfunc (m *MockConn) Close() error {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"Close\")\n\tret0, _ := ret[0].(error)\n\treturn ret0\n}\n\n// Close indicates an expected call of Close.\nfunc (mr *MockConnMockRecorder) Close() *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"Close\", reflect.TypeOf((*MockConn)(nil).Close))\n}\n\n// LocalAddr mocks base method.\nfunc (m *MockConn) LocalAddr() net.Addr {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"LocalAddr\")\n\tret0, _ := ret[0].(net.Addr)\n\treturn ret0\n}\n\n// LocalAddr indicates an expected call of LocalAddr.\nfunc (mr *MockConnMockRecorder) LocalAddr() *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"LocalAddr\", reflect.TypeOf((*MockConn)(nil).LocalAddr))\n}\n\n// Read mocks base method.\nfunc (m *MockConn) Read(arg0 []byte) (int, error) {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"Read\", arg0)\n\tret0, _ := ret[0].(int)\n\tret1, _ := ret[1].(error)\n\treturn ret0, ret1\n}\n\n// Read indicates an expected call of Read.\nfunc (mr *MockConnMockRecorder) Read(arg0 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"Read\", reflect.TypeOf((*MockConn)(nil).Read), arg0)\n}\n\n// RemoteAddr mocks base method.\nfunc (m *MockConn) RemoteAddr() net.Addr {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"RemoteAddr\")\n\tret0, _ := ret[0].(net.Addr)\n\treturn ret0\n}\n\n// RemoteAddr indicates an expected call of RemoteAddr.\nfunc (mr *MockConnMockRecorder) RemoteAddr() *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"RemoteAddr\", reflect.TypeOf((*MockConn)(nil).RemoteAddr))\n}\n\n// SetDeadline mocks base method.\nfunc (m *MockConn) SetDeadline(arg0 time.Time) error {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"SetDeadline\", arg0)\n\tret0, _ := ret[0].(error)\n\treturn ret0\n}\n\n// SetDeadline indicates an expected call of SetDeadline.\nfunc (mr *MockConnMockRecorder) SetDeadline(arg0 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"SetDeadline\", reflect.TypeOf((*MockConn)(nil).SetDeadline), arg0)\n}\n\n// SetReadDeadline mocks base method.\nfunc (m *MockConn) SetReadDeadline(arg0 time.Time) error {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"SetReadDeadline\", arg0)\n\tret0, _ := ret[0].(error)\n\treturn ret0\n}\n\n// SetReadDeadline indicates an expected call of SetReadDeadline.\nfunc (mr *MockConnMockRecorder) SetReadDeadline(arg0 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"SetReadDeadline\", reflect.TypeOf((*MockConn)(nil).SetReadDeadline), arg0)\n}\n\n// SetWriteDeadline mocks base method.\nfunc (m *MockConn) SetWriteDeadline(arg0 time.Time) error {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"SetWriteDeadline\", arg0)\n\tret0, _ := ret[0].(error)\n\treturn ret0\n}\n\n// SetWriteDeadline indicates an expected call of SetWriteDeadline.\nfunc (mr *MockConnMockRecorder) SetWriteDeadline(arg0 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"SetWriteDeadline\", reflect.TypeOf((*MockConn)(nil).SetWriteDeadline), arg0)\n}\n\n// Write mocks base method.\nfunc (m *MockConn) Write(arg0 []byte) (int, error) {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"Write\", arg0)\n\tret0, _ := ret[0].(int)\n\tret1, _ := ret[1].(error)\n\treturn ret0, ret1\n}\n\n// Write indicates an expected call of Write.\nfunc (mr *MockConnMockRecorder) Write(arg0 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"Write\", reflect.TypeOf((*MockConn)(nil).Write), arg0)\n}\n"
  },
  {
    "path": "libs/go/libp2p_node/mocks/mock_network.go",
    "content": "// Code generated by MockGen. DO NOT EDIT.\n// Source: github.com/libp2p/go-libp2p-core/network (interfaces: Stream)\n\n// Package mock_network is a generated GoMock package.\npackage mocks\n\nimport (\n\treflect \"reflect\"\n\ttime \"time\"\n\n\tgomock \"github.com/golang/mock/gomock\"\n\tnetwork \"github.com/libp2p/go-libp2p-core/network\"\n\tprotocol \"github.com/libp2p/go-libp2p-core/protocol\"\n)\n\n// MockStream is a mock of Stream interface.\ntype MockStream struct {\n\tctrl     *gomock.Controller\n\trecorder *MockStreamMockRecorder\n}\n\n// MockStreamMockRecorder is the mock recorder for MockStream.\ntype MockStreamMockRecorder struct {\n\tmock *MockStream\n}\n\n// NewMockStream creates a new mock instance.\nfunc NewMockStream(ctrl *gomock.Controller) *MockStream {\n\tmock := &MockStream{ctrl: ctrl}\n\tmock.recorder = &MockStreamMockRecorder{mock}\n\treturn mock\n}\n\n// EXPECT returns an object that allows the caller to indicate expected use.\nfunc (m *MockStream) EXPECT() *MockStreamMockRecorder {\n\treturn m.recorder\n}\n\n// Close mocks base method.\nfunc (m *MockStream) Close() error {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"Close\")\n\tret0, _ := ret[0].(error)\n\treturn ret0\n}\n\n// Close indicates an expected call of Close.\nfunc (mr *MockStreamMockRecorder) Close() *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"Close\", reflect.TypeOf((*MockStream)(nil).Close))\n}\n\n// Conn mocks base method.\nfunc (m *MockStream) Conn() network.Conn {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"Conn\")\n\tret0, _ := ret[0].(network.Conn)\n\treturn ret0\n}\n\n// Conn indicates an expected call of Conn.\nfunc (mr *MockStreamMockRecorder) Conn() *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"Conn\", reflect.TypeOf((*MockStream)(nil).Conn))\n}\n\n// Protocol mocks base method.\nfunc (m *MockStream) Protocol() protocol.ID {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"Protocol\")\n\tret0, _ := ret[0].(protocol.ID)\n\treturn ret0\n}\n\n// Protocol indicates an expected call of Protocol.\nfunc (mr *MockStreamMockRecorder) Protocol() *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"Protocol\", reflect.TypeOf((*MockStream)(nil).Protocol))\n}\n\n// Read mocks base method.\nfunc (m *MockStream) Read(arg0 []byte) (int, error) {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"Read\", arg0)\n\tret0, _ := ret[0].(int)\n\tret1, _ := ret[1].(error)\n\treturn ret0, ret1\n}\n\n// Read indicates an expected call of Read.\nfunc (mr *MockStreamMockRecorder) Read(arg0 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"Read\", reflect.TypeOf((*MockStream)(nil).Read), arg0)\n}\n\n// Reset mocks base method.\nfunc (m *MockStream) Reset() error {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"Reset\")\n\tret0, _ := ret[0].(error)\n\treturn ret0\n}\n\n// Reset indicates an expected call of Reset.\nfunc (mr *MockStreamMockRecorder) Reset() *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"Reset\", reflect.TypeOf((*MockStream)(nil).Reset))\n}\n\n// SetDeadline mocks base method.\nfunc (m *MockStream) SetDeadline(arg0 time.Time) error {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"SetDeadline\", arg0)\n\tret0, _ := ret[0].(error)\n\treturn ret0\n}\n\n// SetDeadline indicates an expected call of SetDeadline.\nfunc (mr *MockStreamMockRecorder) SetDeadline(arg0 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"SetDeadline\", reflect.TypeOf((*MockStream)(nil).SetDeadline), arg0)\n}\n\n// SetProtocol mocks base method.\nfunc (m *MockStream) SetProtocol(arg0 protocol.ID) {\n\tm.ctrl.T.Helper()\n\tm.ctrl.Call(m, \"SetProtocol\", arg0)\n}\n\n// SetProtocol indicates an expected call of SetProtocol.\nfunc (mr *MockStreamMockRecorder) SetProtocol(arg0 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"SetProtocol\", reflect.TypeOf((*MockStream)(nil).SetProtocol), arg0)\n}\n\n// SetReadDeadline mocks base method.\nfunc (m *MockStream) SetReadDeadline(arg0 time.Time) error {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"SetReadDeadline\", arg0)\n\tret0, _ := ret[0].(error)\n\treturn ret0\n}\n\n// SetReadDeadline indicates an expected call of SetReadDeadline.\nfunc (mr *MockStreamMockRecorder) SetReadDeadline(arg0 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"SetReadDeadline\", reflect.TypeOf((*MockStream)(nil).SetReadDeadline), arg0)\n}\n\n// SetWriteDeadline mocks base method.\nfunc (m *MockStream) SetWriteDeadline(arg0 time.Time) error {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"SetWriteDeadline\", arg0)\n\tret0, _ := ret[0].(error)\n\treturn ret0\n}\n\n// SetWriteDeadline indicates an expected call of SetWriteDeadline.\nfunc (mr *MockStreamMockRecorder) SetWriteDeadline(arg0 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"SetWriteDeadline\", reflect.TypeOf((*MockStream)(nil).SetWriteDeadline), arg0)\n}\n\n// Stat mocks base method.\nfunc (m *MockStream) Stat() network.Stat {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"Stat\")\n\tret0, _ := ret[0].(network.Stat)\n\treturn ret0\n}\n\n// Stat indicates an expected call of Stat.\nfunc (mr *MockStreamMockRecorder) Stat() *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"Stat\", reflect.TypeOf((*MockStream)(nil).Stat))\n}\n\n// Write mocks base method.\nfunc (m *MockStream) Write(arg0 []byte) (int, error) {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"Write\", arg0)\n\tret0, _ := ret[0].(int)\n\tret1, _ := ret[1].(error)\n\treturn ret0, ret1\n}\n\n// Write indicates an expected call of Write.\nfunc (mr *MockStreamMockRecorder) Write(arg0 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"Write\", reflect.TypeOf((*MockStream)(nil).Write), arg0)\n}\n"
  },
  {
    "path": "libs/go/libp2p_node/mocks/mock_peerstore.go",
    "content": "// Code generated by MockGen. DO NOT EDIT.\n// Source: github.com/libp2p/go-libp2p-core/peerstore (interfaces: Peerstore)\n\n// Package mock_peerstore is a generated GoMock package.\npackage mocks\n\nimport (\n\tcontext \"context\"\n\treflect \"reflect\"\n\ttime \"time\"\n\n\tgomock \"github.com/golang/mock/gomock\"\n\tcrypto \"github.com/libp2p/go-libp2p-core/crypto\"\n\tpeer \"github.com/libp2p/go-libp2p-core/peer\"\n\tmultiaddr \"github.com/multiformats/go-multiaddr\"\n)\n\n// MockPeerstore is a mock of Peerstore interface.\ntype MockPeerstore struct {\n\tctrl     *gomock.Controller\n\trecorder *MockPeerstoreMockRecorder\n}\n\n// MockPeerstoreMockRecorder is the mock recorder for MockPeerstore.\ntype MockPeerstoreMockRecorder struct {\n\tmock *MockPeerstore\n}\n\n// NewMockPeerstore creates a new mock instance.\nfunc NewMockPeerstore(ctrl *gomock.Controller) *MockPeerstore {\n\tmock := &MockPeerstore{ctrl: ctrl}\n\tmock.recorder = &MockPeerstoreMockRecorder{mock}\n\treturn mock\n}\n\n// EXPECT returns an object that allows the caller to indicate expected use.\nfunc (m *MockPeerstore) EXPECT() *MockPeerstoreMockRecorder {\n\treturn m.recorder\n}\n\n// AddAddr mocks base method.\nfunc (m *MockPeerstore) AddAddr(arg0 peer.ID, arg1 multiaddr.Multiaddr, arg2 time.Duration) {\n\tm.ctrl.T.Helper()\n\tm.ctrl.Call(m, \"AddAddr\", arg0, arg1, arg2)\n}\n\n// AddAddr indicates an expected call of AddAddr.\nfunc (mr *MockPeerstoreMockRecorder) AddAddr(arg0, arg1, arg2 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"AddAddr\", reflect.TypeOf((*MockPeerstore)(nil).AddAddr), arg0, arg1, arg2)\n}\n\n// AddAddrs mocks base method.\nfunc (m *MockPeerstore) AddAddrs(arg0 peer.ID, arg1 []multiaddr.Multiaddr, arg2 time.Duration) {\n\tm.ctrl.T.Helper()\n\tm.ctrl.Call(m, \"AddAddrs\", arg0, arg1, arg2)\n}\n\n// AddAddrs indicates an expected call of AddAddrs.\nfunc (mr *MockPeerstoreMockRecorder) AddAddrs(arg0, arg1, arg2 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"AddAddrs\", reflect.TypeOf((*MockPeerstore)(nil).AddAddrs), arg0, arg1, arg2)\n}\n\n// AddPrivKey mocks base method.\nfunc (m *MockPeerstore) AddPrivKey(arg0 peer.ID, arg1 crypto.PrivKey) error {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"AddPrivKey\", arg0, arg1)\n\tret0, _ := ret[0].(error)\n\treturn ret0\n}\n\n// AddPrivKey indicates an expected call of AddPrivKey.\nfunc (mr *MockPeerstoreMockRecorder) AddPrivKey(arg0, arg1 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"AddPrivKey\", reflect.TypeOf((*MockPeerstore)(nil).AddPrivKey), arg0, arg1)\n}\n\n// AddProtocols mocks base method.\nfunc (m *MockPeerstore) AddProtocols(arg0 peer.ID, arg1 ...string) error {\n\tm.ctrl.T.Helper()\n\tvarargs := []interface{}{arg0}\n\tfor _, a := range arg1 {\n\t\tvarargs = append(varargs, a)\n\t}\n\tret := m.ctrl.Call(m, \"AddProtocols\", varargs...)\n\tret0, _ := ret[0].(error)\n\treturn ret0\n}\n\n// AddProtocols indicates an expected call of AddProtocols.\nfunc (mr *MockPeerstoreMockRecorder) AddProtocols(arg0 interface{}, arg1 ...interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\tvarargs := append([]interface{}{arg0}, arg1...)\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"AddProtocols\", reflect.TypeOf((*MockPeerstore)(nil).AddProtocols), varargs...)\n}\n\n// AddPubKey mocks base method.\nfunc (m *MockPeerstore) AddPubKey(arg0 peer.ID, arg1 crypto.PubKey) error {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"AddPubKey\", arg0, arg1)\n\tret0, _ := ret[0].(error)\n\treturn ret0\n}\n\n// AddPubKey indicates an expected call of AddPubKey.\nfunc (mr *MockPeerstoreMockRecorder) AddPubKey(arg0, arg1 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"AddPubKey\", reflect.TypeOf((*MockPeerstore)(nil).AddPubKey), arg0, arg1)\n}\n\n// AddrStream mocks base method.\nfunc (m *MockPeerstore) AddrStream(arg0 context.Context, arg1 peer.ID) <-chan multiaddr.Multiaddr {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"AddrStream\", arg0, arg1)\n\tret0, _ := ret[0].(<-chan multiaddr.Multiaddr)\n\treturn ret0\n}\n\n// AddrStream indicates an expected call of AddrStream.\nfunc (mr *MockPeerstoreMockRecorder) AddrStream(arg0, arg1 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"AddrStream\", reflect.TypeOf((*MockPeerstore)(nil).AddrStream), arg0, arg1)\n}\n\n// Addrs mocks base method.\nfunc (m *MockPeerstore) Addrs(arg0 peer.ID) []multiaddr.Multiaddr {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"Addrs\", arg0)\n\tret0, _ := ret[0].([]multiaddr.Multiaddr)\n\treturn ret0\n}\n\n// Addrs indicates an expected call of Addrs.\nfunc (mr *MockPeerstoreMockRecorder) Addrs(arg0 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"Addrs\", reflect.TypeOf((*MockPeerstore)(nil).Addrs), arg0)\n}\n\n// ClearAddrs mocks base method.\nfunc (m *MockPeerstore) ClearAddrs(arg0 peer.ID) {\n\tm.ctrl.T.Helper()\n\tm.ctrl.Call(m, \"ClearAddrs\", arg0)\n}\n\n// ClearAddrs indicates an expected call of ClearAddrs.\nfunc (mr *MockPeerstoreMockRecorder) ClearAddrs(arg0 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"ClearAddrs\", reflect.TypeOf((*MockPeerstore)(nil).ClearAddrs), arg0)\n}\n\n// Close mocks base method.\nfunc (m *MockPeerstore) Close() error {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"Close\")\n\tret0, _ := ret[0].(error)\n\treturn ret0\n}\n\n// Close indicates an expected call of Close.\nfunc (mr *MockPeerstoreMockRecorder) Close() *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"Close\", reflect.TypeOf((*MockPeerstore)(nil).Close))\n}\n\n// Get mocks base method.\nfunc (m *MockPeerstore) Get(arg0 peer.ID, arg1 string) (interface{}, error) {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"Get\", arg0, arg1)\n\tret0, _ := ret[0].(interface{})\n\tret1, _ := ret[1].(error)\n\treturn ret0, ret1\n}\n\n// Get indicates an expected call of Get.\nfunc (mr *MockPeerstoreMockRecorder) Get(arg0, arg1 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"Get\", reflect.TypeOf((*MockPeerstore)(nil).Get), arg0, arg1)\n}\n\n// GetProtocols mocks base method.\nfunc (m *MockPeerstore) GetProtocols(arg0 peer.ID) ([]string, error) {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"GetProtocols\", arg0)\n\tret0, _ := ret[0].([]string)\n\tret1, _ := ret[1].(error)\n\treturn ret0, ret1\n}\n\n// GetProtocols indicates an expected call of GetProtocols.\nfunc (mr *MockPeerstoreMockRecorder) GetProtocols(arg0 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"GetProtocols\", reflect.TypeOf((*MockPeerstore)(nil).GetProtocols), arg0)\n}\n\n// LatencyEWMA mocks base method.\nfunc (m *MockPeerstore) LatencyEWMA(arg0 peer.ID) time.Duration {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"LatencyEWMA\", arg0)\n\tret0, _ := ret[0].(time.Duration)\n\treturn ret0\n}\n\n// LatencyEWMA indicates an expected call of LatencyEWMA.\nfunc (mr *MockPeerstoreMockRecorder) LatencyEWMA(arg0 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"LatencyEWMA\", reflect.TypeOf((*MockPeerstore)(nil).LatencyEWMA), arg0)\n}\n\n// PeerInfo mocks base method.\nfunc (m *MockPeerstore) PeerInfo(arg0 peer.ID) peer.AddrInfo {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"PeerInfo\", arg0)\n\tret0, _ := ret[0].(peer.AddrInfo)\n\treturn ret0\n}\n\n// PeerInfo indicates an expected call of PeerInfo.\nfunc (mr *MockPeerstoreMockRecorder) PeerInfo(arg0 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"PeerInfo\", reflect.TypeOf((*MockPeerstore)(nil).PeerInfo), arg0)\n}\n\n// Peers mocks base method.\nfunc (m *MockPeerstore) Peers() peer.IDSlice {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"Peers\")\n\tret0, _ := ret[0].(peer.IDSlice)\n\treturn ret0\n}\n\n// Peers indicates an expected call of Peers.\nfunc (mr *MockPeerstoreMockRecorder) Peers() *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"Peers\", reflect.TypeOf((*MockPeerstore)(nil).Peers))\n}\n\n// PeersWithAddrs mocks base method.\nfunc (m *MockPeerstore) PeersWithAddrs() peer.IDSlice {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"PeersWithAddrs\")\n\tret0, _ := ret[0].(peer.IDSlice)\n\treturn ret0\n}\n\n// PeersWithAddrs indicates an expected call of PeersWithAddrs.\nfunc (mr *MockPeerstoreMockRecorder) PeersWithAddrs() *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"PeersWithAddrs\", reflect.TypeOf((*MockPeerstore)(nil).PeersWithAddrs))\n}\n\n// PeersWithKeys mocks base method.\nfunc (m *MockPeerstore) PeersWithKeys() peer.IDSlice {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"PeersWithKeys\")\n\tret0, _ := ret[0].(peer.IDSlice)\n\treturn ret0\n}\n\n// PeersWithKeys indicates an expected call of PeersWithKeys.\nfunc (mr *MockPeerstoreMockRecorder) PeersWithKeys() *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"PeersWithKeys\", reflect.TypeOf((*MockPeerstore)(nil).PeersWithKeys))\n}\n\n// PrivKey mocks base method.\nfunc (m *MockPeerstore) PrivKey(arg0 peer.ID) crypto.PrivKey {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"PrivKey\", arg0)\n\tret0, _ := ret[0].(crypto.PrivKey)\n\treturn ret0\n}\n\n// PrivKey indicates an expected call of PrivKey.\nfunc (mr *MockPeerstoreMockRecorder) PrivKey(arg0 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"PrivKey\", reflect.TypeOf((*MockPeerstore)(nil).PrivKey), arg0)\n}\n\n// PubKey mocks base method.\nfunc (m *MockPeerstore) PubKey(arg0 peer.ID) crypto.PubKey {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"PubKey\", arg0)\n\tret0, _ := ret[0].(crypto.PubKey)\n\treturn ret0\n}\n\n// PubKey indicates an expected call of PubKey.\nfunc (mr *MockPeerstoreMockRecorder) PubKey(arg0 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"PubKey\", reflect.TypeOf((*MockPeerstore)(nil).PubKey), arg0)\n}\n\n// Put mocks base method.\nfunc (m *MockPeerstore) Put(arg0 peer.ID, arg1 string, arg2 interface{}) error {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"Put\", arg0, arg1, arg2)\n\tret0, _ := ret[0].(error)\n\treturn ret0\n}\n\n// Put indicates an expected call of Put.\nfunc (mr *MockPeerstoreMockRecorder) Put(arg0, arg1, arg2 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"Put\", reflect.TypeOf((*MockPeerstore)(nil).Put), arg0, arg1, arg2)\n}\n\n// RecordLatency mocks base method.\nfunc (m *MockPeerstore) RecordLatency(arg0 peer.ID, arg1 time.Duration) {\n\tm.ctrl.T.Helper()\n\tm.ctrl.Call(m, \"RecordLatency\", arg0, arg1)\n}\n\n// RecordLatency indicates an expected call of RecordLatency.\nfunc (mr *MockPeerstoreMockRecorder) RecordLatency(arg0, arg1 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"RecordLatency\", reflect.TypeOf((*MockPeerstore)(nil).RecordLatency), arg0, arg1)\n}\n\n// RemoveProtocols mocks base method.\nfunc (m *MockPeerstore) RemoveProtocols(arg0 peer.ID, arg1 ...string) error {\n\tm.ctrl.T.Helper()\n\tvarargs := []interface{}{arg0}\n\tfor _, a := range arg1 {\n\t\tvarargs = append(varargs, a)\n\t}\n\tret := m.ctrl.Call(m, \"RemoveProtocols\", varargs...)\n\tret0, _ := ret[0].(error)\n\treturn ret0\n}\n\n// RemoveProtocols indicates an expected call of RemoveProtocols.\nfunc (mr *MockPeerstoreMockRecorder) RemoveProtocols(arg0 interface{}, arg1 ...interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\tvarargs := append([]interface{}{arg0}, arg1...)\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"RemoveProtocols\", reflect.TypeOf((*MockPeerstore)(nil).RemoveProtocols), varargs...)\n}\n\n// SetAddr mocks base method.\nfunc (m *MockPeerstore) SetAddr(arg0 peer.ID, arg1 multiaddr.Multiaddr, arg2 time.Duration) {\n\tm.ctrl.T.Helper()\n\tm.ctrl.Call(m, \"SetAddr\", arg0, arg1, arg2)\n}\n\n// SetAddr indicates an expected call of SetAddr.\nfunc (mr *MockPeerstoreMockRecorder) SetAddr(arg0, arg1, arg2 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"SetAddr\", reflect.TypeOf((*MockPeerstore)(nil).SetAddr), arg0, arg1, arg2)\n}\n\n// SetAddrs mocks base method.\nfunc (m *MockPeerstore) SetAddrs(arg0 peer.ID, arg1 []multiaddr.Multiaddr, arg2 time.Duration) {\n\tm.ctrl.T.Helper()\n\tm.ctrl.Call(m, \"SetAddrs\", arg0, arg1, arg2)\n}\n\n// SetAddrs indicates an expected call of SetAddrs.\nfunc (mr *MockPeerstoreMockRecorder) SetAddrs(arg0, arg1, arg2 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"SetAddrs\", reflect.TypeOf((*MockPeerstore)(nil).SetAddrs), arg0, arg1, arg2)\n}\n\n// SetProtocols mocks base method.\nfunc (m *MockPeerstore) SetProtocols(arg0 peer.ID, arg1 ...string) error {\n\tm.ctrl.T.Helper()\n\tvarargs := []interface{}{arg0}\n\tfor _, a := range arg1 {\n\t\tvarargs = append(varargs, a)\n\t}\n\tret := m.ctrl.Call(m, \"SetProtocols\", varargs...)\n\tret0, _ := ret[0].(error)\n\treturn ret0\n}\n\n// SetProtocols indicates an expected call of SetProtocols.\nfunc (mr *MockPeerstoreMockRecorder) SetProtocols(arg0 interface{}, arg1 ...interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\tvarargs := append([]interface{}{arg0}, arg1...)\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"SetProtocols\", reflect.TypeOf((*MockPeerstore)(nil).SetProtocols), varargs...)\n}\n\n// SupportsProtocols mocks base method.\nfunc (m *MockPeerstore) SupportsProtocols(arg0 peer.ID, arg1 ...string) ([]string, error) {\n\tm.ctrl.T.Helper()\n\tvarargs := []interface{}{arg0}\n\tfor _, a := range arg1 {\n\t\tvarargs = append(varargs, a)\n\t}\n\tret := m.ctrl.Call(m, \"SupportsProtocols\", varargs...)\n\tret0, _ := ret[0].([]string)\n\tret1, _ := ret[1].(error)\n\treturn ret0, ret1\n}\n\n// SupportsProtocols indicates an expected call of SupportsProtocols.\nfunc (mr *MockPeerstoreMockRecorder) SupportsProtocols(arg0 interface{}, arg1 ...interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\tvarargs := append([]interface{}{arg0}, arg1...)\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"SupportsProtocols\", reflect.TypeOf((*MockPeerstore)(nil).SupportsProtocols), varargs...)\n}\n\n// UpdateAddrs mocks base method.\nfunc (m *MockPeerstore) UpdateAddrs(arg0 peer.ID, arg1, arg2 time.Duration) {\n\tm.ctrl.T.Helper()\n\tm.ctrl.Call(m, \"UpdateAddrs\", arg0, arg1, arg2)\n}\n\n// UpdateAddrs indicates an expected call of UpdateAddrs.\nfunc (mr *MockPeerstoreMockRecorder) UpdateAddrs(arg0, arg1, arg2 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"UpdateAddrs\", reflect.TypeOf((*MockPeerstore)(nil).UpdateAddrs), arg0, arg1, arg2)\n}\n"
  },
  {
    "path": "libs/go/libp2p_node/protocols/acn/v1_0_0/acn.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.25.0\n// \tprotoc        v3.11.4\n// source: acn.proto\n\npackage aea_aea_acn_v1_0_0\n\nimport (\n\tproto \"github.com/golang/protobuf/proto\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// This is a compile-time assertion that a sufficiently up-to-date version\n// of the legacy proto package is being used.\nconst _ = proto.ProtoPackageIsVersion4\n\ntype AcnMessage_StatusBody_StatusCodeEnum int32\n\nconst (\n\t// common (0x)\n\tAcnMessage_StatusBody_SUCCESS                   AcnMessage_StatusBody_StatusCodeEnum = 0\n\tAcnMessage_StatusBody_ERROR_UNSUPPORTED_VERSION AcnMessage_StatusBody_StatusCodeEnum = 1\n\tAcnMessage_StatusBody_ERROR_UNEXPECTED_PAYLOAD  AcnMessage_StatusBody_StatusCodeEnum = 2\n\tAcnMessage_StatusBody_ERROR_GENERIC             AcnMessage_StatusBody_StatusCodeEnum = 3\n\tAcnMessage_StatusBody_ERROR_DECODE              AcnMessage_StatusBody_StatusCodeEnum = 4\n\t// register (1x)\n\tAcnMessage_StatusBody_ERROR_WRONG_AGENT_ADDRESS AcnMessage_StatusBody_StatusCodeEnum = 10\n\tAcnMessage_StatusBody_ERROR_WRONG_PUBLIC_KEY    AcnMessage_StatusBody_StatusCodeEnum = 11\n\tAcnMessage_StatusBody_ERROR_INVALID_PROOF       AcnMessage_StatusBody_StatusCodeEnum = 12\n\tAcnMessage_StatusBody_ERROR_UNSUPPORTED_LEDGER  AcnMessage_StatusBody_StatusCodeEnum = 13\n\t// lookup & delivery (2x)\n\tAcnMessage_StatusBody_ERROR_UNKNOWN_AGENT_ADDRESS AcnMessage_StatusBody_StatusCodeEnum = 20\n\tAcnMessage_StatusBody_ERROR_AGENT_NOT_READY       AcnMessage_StatusBody_StatusCodeEnum = 21\n)\n\n// Enum value maps for AcnMessage_StatusBody_StatusCodeEnum.\nvar (\n\tAcnMessage_StatusBody_StatusCodeEnum_name = map[int32]string{\n\t\t0:  \"SUCCESS\",\n\t\t1:  \"ERROR_UNSUPPORTED_VERSION\",\n\t\t2:  \"ERROR_UNEXPECTED_PAYLOAD\",\n\t\t3:  \"ERROR_GENERIC\",\n\t\t4:  \"ERROR_DECODE\",\n\t\t10: \"ERROR_WRONG_AGENT_ADDRESS\",\n\t\t11: \"ERROR_WRONG_PUBLIC_KEY\",\n\t\t12: \"ERROR_INVALID_PROOF\",\n\t\t13: \"ERROR_UNSUPPORTED_LEDGER\",\n\t\t20: \"ERROR_UNKNOWN_AGENT_ADDRESS\",\n\t\t21: \"ERROR_AGENT_NOT_READY\",\n\t}\n\tAcnMessage_StatusBody_StatusCodeEnum_value = map[string]int32{\n\t\t\"SUCCESS\":                     0,\n\t\t\"ERROR_UNSUPPORTED_VERSION\":   1,\n\t\t\"ERROR_UNEXPECTED_PAYLOAD\":    2,\n\t\t\"ERROR_GENERIC\":               3,\n\t\t\"ERROR_DECODE\":                4,\n\t\t\"ERROR_WRONG_AGENT_ADDRESS\":   10,\n\t\t\"ERROR_WRONG_PUBLIC_KEY\":      11,\n\t\t\"ERROR_INVALID_PROOF\":         12,\n\t\t\"ERROR_UNSUPPORTED_LEDGER\":    13,\n\t\t\"ERROR_UNKNOWN_AGENT_ADDRESS\": 20,\n\t\t\"ERROR_AGENT_NOT_READY\":       21,\n\t}\n)\n\nfunc (x AcnMessage_StatusBody_StatusCodeEnum) Enum() *AcnMessage_StatusBody_StatusCodeEnum {\n\tp := new(AcnMessage_StatusBody_StatusCodeEnum)\n\t*p = x\n\treturn p\n}\n\nfunc (x AcnMessage_StatusBody_StatusCodeEnum) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (AcnMessage_StatusBody_StatusCodeEnum) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_acn_proto_enumTypes[0].Descriptor()\n}\n\nfunc (AcnMessage_StatusBody_StatusCodeEnum) Type() protoreflect.EnumType {\n\treturn &file_acn_proto_enumTypes[0]\n}\n\nfunc (x AcnMessage_StatusBody_StatusCodeEnum) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use AcnMessage_StatusBody_StatusCodeEnum.Descriptor instead.\nfunc (AcnMessage_StatusBody_StatusCodeEnum) EnumDescriptor() ([]byte, []int) {\n\treturn file_acn_proto_rawDescGZIP(), []int{0, 1, 0}\n}\n\ntype AcnMessage struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// Types that are assignable to Performative:\n\t//\t*AcnMessage_AeaEnvelope\n\t//\t*AcnMessage_LookupRequest\n\t//\t*AcnMessage_LookupResponse\n\t//\t*AcnMessage_Register\n\t//\t*AcnMessage_Status\n\tPerformative isAcnMessage_Performative `protobuf_oneof:\"performative\"`\n}\n\nfunc (x *AcnMessage) Reset() {\n\t*x = AcnMessage{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_acn_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *AcnMessage) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*AcnMessage) ProtoMessage() {}\n\nfunc (x *AcnMessage) ProtoReflect() protoreflect.Message {\n\tmi := &file_acn_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use AcnMessage.ProtoReflect.Descriptor instead.\nfunc (*AcnMessage) Descriptor() ([]byte, []int) {\n\treturn file_acn_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (m *AcnMessage) GetPerformative() isAcnMessage_Performative {\n\tif m != nil {\n\t\treturn m.Performative\n\t}\n\treturn nil\n}\n\nfunc (x *AcnMessage) GetAeaEnvelope() *AcnMessage_Aea_Envelope_Performative {\n\tif x, ok := x.GetPerformative().(*AcnMessage_AeaEnvelope); ok {\n\t\treturn x.AeaEnvelope\n\t}\n\treturn nil\n}\n\nfunc (x *AcnMessage) GetLookupRequest() *AcnMessage_Lookup_Request_Performative {\n\tif x, ok := x.GetPerformative().(*AcnMessage_LookupRequest); ok {\n\t\treturn x.LookupRequest\n\t}\n\treturn nil\n}\n\nfunc (x *AcnMessage) GetLookupResponse() *AcnMessage_Lookup_Response_Performative {\n\tif x, ok := x.GetPerformative().(*AcnMessage_LookupResponse); ok {\n\t\treturn x.LookupResponse\n\t}\n\treturn nil\n}\n\nfunc (x *AcnMessage) GetRegister() *AcnMessage_Register_Performative {\n\tif x, ok := x.GetPerformative().(*AcnMessage_Register); ok {\n\t\treturn x.Register\n\t}\n\treturn nil\n}\n\nfunc (x *AcnMessage) GetStatus() *AcnMessage_Status_Performative {\n\tif x, ok := x.GetPerformative().(*AcnMessage_Status); ok {\n\t\treturn x.Status\n\t}\n\treturn nil\n}\n\ntype isAcnMessage_Performative interface {\n\tisAcnMessage_Performative()\n}\n\ntype AcnMessage_AeaEnvelope struct {\n\tAeaEnvelope *AcnMessage_Aea_Envelope_Performative `protobuf:\"bytes,5,opt,name=aea_envelope,json=aeaEnvelope,proto3,oneof\"`\n}\n\ntype AcnMessage_LookupRequest struct {\n\tLookupRequest *AcnMessage_Lookup_Request_Performative `protobuf:\"bytes,6,opt,name=lookup_request,json=lookupRequest,proto3,oneof\"`\n}\n\ntype AcnMessage_LookupResponse struct {\n\tLookupResponse *AcnMessage_Lookup_Response_Performative `protobuf:\"bytes,7,opt,name=lookup_response,json=lookupResponse,proto3,oneof\"`\n}\n\ntype AcnMessage_Register struct {\n\tRegister *AcnMessage_Register_Performative `protobuf:\"bytes,8,opt,name=register,proto3,oneof\"`\n}\n\ntype AcnMessage_Status struct {\n\tStatus *AcnMessage_Status_Performative `protobuf:\"bytes,9,opt,name=status,proto3,oneof\"`\n}\n\nfunc (*AcnMessage_AeaEnvelope) isAcnMessage_Performative() {}\n\nfunc (*AcnMessage_LookupRequest) isAcnMessage_Performative() {}\n\nfunc (*AcnMessage_LookupResponse) isAcnMessage_Performative() {}\n\nfunc (*AcnMessage_Register) isAcnMessage_Performative() {}\n\nfunc (*AcnMessage_Status) isAcnMessage_Performative() {}\n\n// Custom Types\ntype AcnMessage_AgentRecord struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tServiceId     string `protobuf:\"bytes,1,opt,name=service_id,json=serviceId,proto3\" json:\"service_id,omitempty\"`\n\tLedgerId      string `protobuf:\"bytes,2,opt,name=ledger_id,json=ledgerId,proto3\" json:\"ledger_id,omitempty\"`\n\tAddress       string `protobuf:\"bytes,3,opt,name=address,proto3\" json:\"address,omitempty\"`\n\tPublicKey     string `protobuf:\"bytes,4,opt,name=public_key,json=publicKey,proto3\" json:\"public_key,omitempty\"`\n\tPeerPublicKey string `protobuf:\"bytes,5,opt,name=peer_public_key,json=peerPublicKey,proto3\" json:\"peer_public_key,omitempty\"`\n\tSignature     string `protobuf:\"bytes,6,opt,name=signature,proto3\" json:\"signature,omitempty\"`\n\tNotBefore     string `protobuf:\"bytes,7,opt,name=not_before,json=notBefore,proto3\" json:\"not_before,omitempty\"`\n\tNotAfter      string `protobuf:\"bytes,8,opt,name=not_after,json=notAfter,proto3\" json:\"not_after,omitempty\"`\n}\n\nfunc (x *AcnMessage_AgentRecord) Reset() {\n\t*x = AcnMessage_AgentRecord{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_acn_proto_msgTypes[1]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *AcnMessage_AgentRecord) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*AcnMessage_AgentRecord) ProtoMessage() {}\n\nfunc (x *AcnMessage_AgentRecord) ProtoReflect() protoreflect.Message {\n\tmi := &file_acn_proto_msgTypes[1]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use AcnMessage_AgentRecord.ProtoReflect.Descriptor instead.\nfunc (*AcnMessage_AgentRecord) Descriptor() ([]byte, []int) {\n\treturn file_acn_proto_rawDescGZIP(), []int{0, 0}\n}\n\nfunc (x *AcnMessage_AgentRecord) GetServiceId() string {\n\tif x != nil {\n\t\treturn x.ServiceId\n\t}\n\treturn \"\"\n}\n\nfunc (x *AcnMessage_AgentRecord) GetLedgerId() string {\n\tif x != nil {\n\t\treturn x.LedgerId\n\t}\n\treturn \"\"\n}\n\nfunc (x *AcnMessage_AgentRecord) GetAddress() string {\n\tif x != nil {\n\t\treturn x.Address\n\t}\n\treturn \"\"\n}\n\nfunc (x *AcnMessage_AgentRecord) GetPublicKey() string {\n\tif x != nil {\n\t\treturn x.PublicKey\n\t}\n\treturn \"\"\n}\n\nfunc (x *AcnMessage_AgentRecord) GetPeerPublicKey() string {\n\tif x != nil {\n\t\treturn x.PeerPublicKey\n\t}\n\treturn \"\"\n}\n\nfunc (x *AcnMessage_AgentRecord) GetSignature() string {\n\tif x != nil {\n\t\treturn x.Signature\n\t}\n\treturn \"\"\n}\n\nfunc (x *AcnMessage_AgentRecord) GetNotBefore() string {\n\tif x != nil {\n\t\treturn x.NotBefore\n\t}\n\treturn \"\"\n}\n\nfunc (x *AcnMessage_AgentRecord) GetNotAfter() string {\n\tif x != nil {\n\t\treturn x.NotAfter\n\t}\n\treturn \"\"\n}\n\ntype AcnMessage_StatusBody struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tCode AcnMessage_StatusBody_StatusCodeEnum `protobuf:\"varint,1,opt,name=code,proto3,enum=aea.aea.acn.v1_0_0.AcnMessage_StatusBody_StatusCodeEnum\" json:\"code,omitempty\"`\n\tMsgs []string                             `protobuf:\"bytes,2,rep,name=msgs,proto3\" json:\"msgs,omitempty\"`\n}\n\nfunc (x *AcnMessage_StatusBody) Reset() {\n\t*x = AcnMessage_StatusBody{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_acn_proto_msgTypes[2]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *AcnMessage_StatusBody) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*AcnMessage_StatusBody) ProtoMessage() {}\n\nfunc (x *AcnMessage_StatusBody) ProtoReflect() protoreflect.Message {\n\tmi := &file_acn_proto_msgTypes[2]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use AcnMessage_StatusBody.ProtoReflect.Descriptor instead.\nfunc (*AcnMessage_StatusBody) Descriptor() ([]byte, []int) {\n\treturn file_acn_proto_rawDescGZIP(), []int{0, 1}\n}\n\nfunc (x *AcnMessage_StatusBody) GetCode() AcnMessage_StatusBody_StatusCodeEnum {\n\tif x != nil {\n\t\treturn x.Code\n\t}\n\treturn AcnMessage_StatusBody_SUCCESS\n}\n\nfunc (x *AcnMessage_StatusBody) GetMsgs() []string {\n\tif x != nil {\n\t\treturn x.Msgs\n\t}\n\treturn nil\n}\n\n// Performatives and contents\ntype AcnMessage_Register_Performative struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tRecord *AcnMessage_AgentRecord `protobuf:\"bytes,1,opt,name=record,proto3\" json:\"record,omitempty\"`\n}\n\nfunc (x *AcnMessage_Register_Performative) Reset() {\n\t*x = AcnMessage_Register_Performative{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_acn_proto_msgTypes[3]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *AcnMessage_Register_Performative) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*AcnMessage_Register_Performative) ProtoMessage() {}\n\nfunc (x *AcnMessage_Register_Performative) ProtoReflect() protoreflect.Message {\n\tmi := &file_acn_proto_msgTypes[3]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use AcnMessage_Register_Performative.ProtoReflect.Descriptor instead.\nfunc (*AcnMessage_Register_Performative) Descriptor() ([]byte, []int) {\n\treturn file_acn_proto_rawDescGZIP(), []int{0, 2}\n}\n\nfunc (x *AcnMessage_Register_Performative) GetRecord() *AcnMessage_AgentRecord {\n\tif x != nil {\n\t\treturn x.Record\n\t}\n\treturn nil\n}\n\ntype AcnMessage_Lookup_Request_Performative struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tAgentAddress string `protobuf:\"bytes,1,opt,name=agent_address,json=agentAddress,proto3\" json:\"agent_address,omitempty\"`\n}\n\nfunc (x *AcnMessage_Lookup_Request_Performative) Reset() {\n\t*x = AcnMessage_Lookup_Request_Performative{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_acn_proto_msgTypes[4]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *AcnMessage_Lookup_Request_Performative) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*AcnMessage_Lookup_Request_Performative) ProtoMessage() {}\n\nfunc (x *AcnMessage_Lookup_Request_Performative) ProtoReflect() protoreflect.Message {\n\tmi := &file_acn_proto_msgTypes[4]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use AcnMessage_Lookup_Request_Performative.ProtoReflect.Descriptor instead.\nfunc (*AcnMessage_Lookup_Request_Performative) Descriptor() ([]byte, []int) {\n\treturn file_acn_proto_rawDescGZIP(), []int{0, 3}\n}\n\nfunc (x *AcnMessage_Lookup_Request_Performative) GetAgentAddress() string {\n\tif x != nil {\n\t\treturn x.AgentAddress\n\t}\n\treturn \"\"\n}\n\ntype AcnMessage_Lookup_Response_Performative struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tRecord *AcnMessage_AgentRecord `protobuf:\"bytes,1,opt,name=record,proto3\" json:\"record,omitempty\"`\n}\n\nfunc (x *AcnMessage_Lookup_Response_Performative) Reset() {\n\t*x = AcnMessage_Lookup_Response_Performative{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_acn_proto_msgTypes[5]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *AcnMessage_Lookup_Response_Performative) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*AcnMessage_Lookup_Response_Performative) ProtoMessage() {}\n\nfunc (x *AcnMessage_Lookup_Response_Performative) ProtoReflect() protoreflect.Message {\n\tmi := &file_acn_proto_msgTypes[5]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use AcnMessage_Lookup_Response_Performative.ProtoReflect.Descriptor instead.\nfunc (*AcnMessage_Lookup_Response_Performative) Descriptor() ([]byte, []int) {\n\treturn file_acn_proto_rawDescGZIP(), []int{0, 4}\n}\n\nfunc (x *AcnMessage_Lookup_Response_Performative) GetRecord() *AcnMessage_AgentRecord {\n\tif x != nil {\n\t\treturn x.Record\n\t}\n\treturn nil\n}\n\ntype AcnMessage_Aea_Envelope_Performative struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tEnvelope []byte                  `protobuf:\"bytes,1,opt,name=envelope,proto3\" json:\"envelope,omitempty\"`\n\tRecord   *AcnMessage_AgentRecord `protobuf:\"bytes,2,opt,name=record,proto3\" json:\"record,omitempty\"`\n}\n\nfunc (x *AcnMessage_Aea_Envelope_Performative) Reset() {\n\t*x = AcnMessage_Aea_Envelope_Performative{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_acn_proto_msgTypes[6]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *AcnMessage_Aea_Envelope_Performative) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*AcnMessage_Aea_Envelope_Performative) ProtoMessage() {}\n\nfunc (x *AcnMessage_Aea_Envelope_Performative) ProtoReflect() protoreflect.Message {\n\tmi := &file_acn_proto_msgTypes[6]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use AcnMessage_Aea_Envelope_Performative.ProtoReflect.Descriptor instead.\nfunc (*AcnMessage_Aea_Envelope_Performative) Descriptor() ([]byte, []int) {\n\treturn file_acn_proto_rawDescGZIP(), []int{0, 5}\n}\n\nfunc (x *AcnMessage_Aea_Envelope_Performative) GetEnvelope() []byte {\n\tif x != nil {\n\t\treturn x.Envelope\n\t}\n\treturn nil\n}\n\nfunc (x *AcnMessage_Aea_Envelope_Performative) GetRecord() *AcnMessage_AgentRecord {\n\tif x != nil {\n\t\treturn x.Record\n\t}\n\treturn nil\n}\n\ntype AcnMessage_Status_Performative struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tBody *AcnMessage_StatusBody `protobuf:\"bytes,1,opt,name=body,proto3\" json:\"body,omitempty\"`\n}\n\nfunc (x *AcnMessage_Status_Performative) Reset() {\n\t*x = AcnMessage_Status_Performative{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_acn_proto_msgTypes[7]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *AcnMessage_Status_Performative) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*AcnMessage_Status_Performative) ProtoMessage() {}\n\nfunc (x *AcnMessage_Status_Performative) ProtoReflect() protoreflect.Message {\n\tmi := &file_acn_proto_msgTypes[7]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use AcnMessage_Status_Performative.ProtoReflect.Descriptor instead.\nfunc (*AcnMessage_Status_Performative) Descriptor() ([]byte, []int) {\n\treturn file_acn_proto_rawDescGZIP(), []int{0, 6}\n}\n\nfunc (x *AcnMessage_Status_Performative) GetBody() *AcnMessage_StatusBody {\n\tif x != nil {\n\t\treturn x.Body\n\t}\n\treturn nil\n}\n\nvar File_acn_proto protoreflect.FileDescriptor\n\nvar file_acn_proto_rawDesc = []byte{\n\t0x0a, 0x09, 0x61, 0x63, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x12, 0x61, 0x65, 0x61,\n\t0x2e, 0x61, 0x65, 0x61, 0x2e, 0x61, 0x63, 0x6e, 0x2e, 0x76, 0x31, 0x5f, 0x30, 0x5f, 0x30, 0x22,\n\t0xea, 0x0c, 0x0a, 0x0a, 0x41, 0x63, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x5d,\n\t0x0a, 0x0c, 0x61, 0x65, 0x61, 0x5f, 0x65, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x18, 0x05,\n\t0x20, 0x01, 0x28, 0x0b, 0x32, 0x38, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x61,\n\t0x63, 0x6e, 0x2e, 0x76, 0x31, 0x5f, 0x30, 0x5f, 0x30, 0x2e, 0x41, 0x63, 0x6e, 0x4d, 0x65, 0x73,\n\t0x73, 0x61, 0x67, 0x65, 0x2e, 0x41, 0x65, 0x61, 0x5f, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70,\n\t0x65, 0x5f, 0x50, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x76, 0x65, 0x48, 0x00,\n\t0x52, 0x0b, 0x61, 0x65, 0x61, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x12, 0x63, 0x0a,\n\t0x0e, 0x6c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18,\n\t0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3a, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x61, 0x65, 0x61, 0x2e,\n\t0x61, 0x63, 0x6e, 0x2e, 0x76, 0x31, 0x5f, 0x30, 0x5f, 0x30, 0x2e, 0x41, 0x63, 0x6e, 0x4d, 0x65,\n\t0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x5f, 0x52, 0x65, 0x71,\n\t0x75, 0x65, 0x73, 0x74, 0x5f, 0x50, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x76,\n\t0x65, 0x48, 0x00, 0x52, 0x0d, 0x6c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65,\n\t0x73, 0x74, 0x12, 0x66, 0x0a, 0x0f, 0x6c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x5f, 0x72, 0x65, 0x73,\n\t0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3b, 0x2e, 0x61, 0x65,\n\t0x61, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x61, 0x63, 0x6e, 0x2e, 0x76, 0x31, 0x5f, 0x30, 0x5f, 0x30,\n\t0x2e, 0x41, 0x63, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4c, 0x6f, 0x6f, 0x6b,\n\t0x75, 0x70, 0x5f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x5f, 0x50, 0x65, 0x72, 0x66,\n\t0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x76, 0x65, 0x48, 0x00, 0x52, 0x0e, 0x6c, 0x6f, 0x6f, 0x6b,\n\t0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x52, 0x0a, 0x08, 0x72, 0x65,\n\t0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x61,\n\t0x65, 0x61, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x61, 0x63, 0x6e, 0x2e, 0x76, 0x31, 0x5f, 0x30, 0x5f,\n\t0x30, 0x2e, 0x41, 0x63, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x52, 0x65, 0x67,\n\t0x69, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x50, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69,\n\t0x76, 0x65, 0x48, 0x00, 0x52, 0x08, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x12, 0x4c,\n\t0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x32,\n\t0x2e, 0x61, 0x65, 0x61, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x61, 0x63, 0x6e, 0x2e, 0x76, 0x31, 0x5f,\n\t0x30, 0x5f, 0x30, 0x2e, 0x41, 0x63, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x53,\n\t0x74, 0x61, 0x74, 0x75, 0x73, 0x5f, 0x50, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69,\n\t0x76, 0x65, 0x48, 0x00, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x1a, 0x84, 0x02, 0x0a,\n\t0x0b, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x12, 0x1d, 0x0a, 0x0a,\n\t0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,\n\t0x52, 0x09, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x6c,\n\t0x65, 0x64, 0x67, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08,\n\t0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72,\n\t0x65, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65,\n\t0x73, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79,\n\t0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65,\n\t0x79, 0x12, 0x26, 0x0a, 0x0f, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63,\n\t0x5f, 0x6b, 0x65, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x70, 0x65, 0x65, 0x72,\n\t0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67,\n\t0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x69,\n\t0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x6e, 0x6f, 0x74, 0x5f, 0x62,\n\t0x65, 0x66, 0x6f, 0x72, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x6f, 0x74,\n\t0x42, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x6e, 0x6f, 0x74, 0x5f, 0x61, 0x66,\n\t0x74, 0x65, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6e, 0x6f, 0x74, 0x41, 0x66,\n\t0x74, 0x65, 0x72, 0x1a, 0x9e, 0x03, 0x0a, 0x0a, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x42, 0x6f,\n\t0x64, 0x79, 0x12, 0x4c, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e,\n\t0x32, 0x38, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x61, 0x63, 0x6e, 0x2e, 0x76,\n\t0x31, 0x5f, 0x30, 0x5f, 0x30, 0x2e, 0x41, 0x63, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,\n\t0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x42, 0x6f, 0x64, 0x79, 0x2e, 0x53, 0x74, 0x61, 0x74,\n\t0x75, 0x73, 0x43, 0x6f, 0x64, 0x65, 0x45, 0x6e, 0x75, 0x6d, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65,\n\t0x12, 0x12, 0x0a, 0x04, 0x6d, 0x73, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04,\n\t0x6d, 0x73, 0x67, 0x73, 0x22, 0xad, 0x02, 0x0a, 0x0e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x43,\n\t0x6f, 0x64, 0x65, 0x45, 0x6e, 0x75, 0x6d, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x55, 0x43, 0x43, 0x45,\n\t0x53, 0x53, 0x10, 0x00, 0x12, 0x1d, 0x0a, 0x19, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x55, 0x4e,\n\t0x53, 0x55, 0x50, 0x50, 0x4f, 0x52, 0x54, 0x45, 0x44, 0x5f, 0x56, 0x45, 0x52, 0x53, 0x49, 0x4f,\n\t0x4e, 0x10, 0x01, 0x12, 0x1c, 0x0a, 0x18, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x55, 0x4e, 0x45,\n\t0x58, 0x50, 0x45, 0x43, 0x54, 0x45, 0x44, 0x5f, 0x50, 0x41, 0x59, 0x4c, 0x4f, 0x41, 0x44, 0x10,\n\t0x02, 0x12, 0x11, 0x0a, 0x0d, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x47, 0x45, 0x4e, 0x45, 0x52,\n\t0x49, 0x43, 0x10, 0x03, 0x12, 0x10, 0x0a, 0x0c, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x44, 0x45,\n\t0x43, 0x4f, 0x44, 0x45, 0x10, 0x04, 0x12, 0x1d, 0x0a, 0x19, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f,\n\t0x57, 0x52, 0x4f, 0x4e, 0x47, 0x5f, 0x41, 0x47, 0x45, 0x4e, 0x54, 0x5f, 0x41, 0x44, 0x44, 0x52,\n\t0x45, 0x53, 0x53, 0x10, 0x0a, 0x12, 0x1a, 0x0a, 0x16, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x57,\n\t0x52, 0x4f, 0x4e, 0x47, 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x5f, 0x4b, 0x45, 0x59, 0x10,\n\t0x0b, 0x12, 0x17, 0x0a, 0x13, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x49, 0x4e, 0x56, 0x41, 0x4c,\n\t0x49, 0x44, 0x5f, 0x50, 0x52, 0x4f, 0x4f, 0x46, 0x10, 0x0c, 0x12, 0x1c, 0x0a, 0x18, 0x45, 0x52,\n\t0x52, 0x4f, 0x52, 0x5f, 0x55, 0x4e, 0x53, 0x55, 0x50, 0x50, 0x4f, 0x52, 0x54, 0x45, 0x44, 0x5f,\n\t0x4c, 0x45, 0x44, 0x47, 0x45, 0x52, 0x10, 0x0d, 0x12, 0x1f, 0x0a, 0x1b, 0x45, 0x52, 0x52, 0x4f,\n\t0x52, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x5f, 0x41, 0x47, 0x45, 0x4e, 0x54, 0x5f,\n\t0x41, 0x44, 0x44, 0x52, 0x45, 0x53, 0x53, 0x10, 0x14, 0x12, 0x19, 0x0a, 0x15, 0x45, 0x52, 0x52,\n\t0x4f, 0x52, 0x5f, 0x41, 0x47, 0x45, 0x4e, 0x54, 0x5f, 0x4e, 0x4f, 0x54, 0x5f, 0x52, 0x45, 0x41,\n\t0x44, 0x59, 0x10, 0x15, 0x1a, 0x5b, 0x0a, 0x15, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72,\n\t0x5f, 0x50, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x76, 0x65, 0x12, 0x42, 0x0a,\n\t0x06, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e,\n\t0x61, 0x65, 0x61, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x61, 0x63, 0x6e, 0x2e, 0x76, 0x31, 0x5f, 0x30,\n\t0x5f, 0x30, 0x2e, 0x41, 0x63, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x41, 0x67,\n\t0x65, 0x6e, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x52, 0x06, 0x72, 0x65, 0x63, 0x6f, 0x72,\n\t0x64, 0x1a, 0x42, 0x0a, 0x1b, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x5f, 0x52, 0x65, 0x71, 0x75,\n\t0x65, 0x73, 0x74, 0x5f, 0x50, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x76, 0x65,\n\t0x12, 0x23, 0x0a, 0x0d, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73,\n\t0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x41, 0x64,\n\t0x64, 0x72, 0x65, 0x73, 0x73, 0x1a, 0x62, 0x0a, 0x1c, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x5f,\n\t0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x5f, 0x50, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d,\n\t0x61, 0x74, 0x69, 0x76, 0x65, 0x12, 0x42, 0x0a, 0x06, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x18,\n\t0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x61, 0x65, 0x61, 0x2e,\n\t0x61, 0x63, 0x6e, 0x2e, 0x76, 0x31, 0x5f, 0x30, 0x5f, 0x30, 0x2e, 0x41, 0x63, 0x6e, 0x4d, 0x65,\n\t0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x72,\n\t0x64, 0x52, 0x06, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x1a, 0x7b, 0x0a, 0x19, 0x41, 0x65, 0x61,\n\t0x5f, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x5f, 0x50, 0x65, 0x72, 0x66, 0x6f, 0x72,\n\t0x6d, 0x61, 0x74, 0x69, 0x76, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x65, 0x6e, 0x76, 0x65, 0x6c, 0x6f,\n\t0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x65, 0x6e, 0x76, 0x65, 0x6c, 0x6f,\n\t0x70, 0x65, 0x12, 0x42, 0x0a, 0x06, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01,\n\t0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x61, 0x63, 0x6e,\n\t0x2e, 0x76, 0x31, 0x5f, 0x30, 0x5f, 0x30, 0x2e, 0x41, 0x63, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61,\n\t0x67, 0x65, 0x2e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x52, 0x06,\n\t0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x1a, 0x54, 0x0a, 0x13, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73,\n\t0x5f, 0x50, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x76, 0x65, 0x12, 0x3d, 0x0a,\n\t0x04, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x61, 0x65,\n\t0x61, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x61, 0x63, 0x6e, 0x2e, 0x76, 0x31, 0x5f, 0x30, 0x5f, 0x30,\n\t0x2e, 0x41, 0x63, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74,\n\t0x75, 0x73, 0x42, 0x6f, 0x64, 0x79, 0x52, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x42, 0x0e, 0x0a, 0x0c,\n\t0x70, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x76, 0x65, 0x62, 0x06, 0x70, 0x72,\n\t0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_acn_proto_rawDescOnce sync.Once\n\tfile_acn_proto_rawDescData = file_acn_proto_rawDesc\n)\n\nfunc file_acn_proto_rawDescGZIP() []byte {\n\tfile_acn_proto_rawDescOnce.Do(func() {\n\t\tfile_acn_proto_rawDescData = protoimpl.X.CompressGZIP(file_acn_proto_rawDescData)\n\t})\n\treturn file_acn_proto_rawDescData\n}\n\nvar file_acn_proto_enumTypes = make([]protoimpl.EnumInfo, 1)\nvar file_acn_proto_msgTypes = make([]protoimpl.MessageInfo, 8)\nvar file_acn_proto_goTypes = []interface{}{\n\t(AcnMessage_StatusBody_StatusCodeEnum)(0),       // 0: aea.aea.acn.v1_0_0.AcnMessage.StatusBody.StatusCodeEnum\n\t(*AcnMessage)(nil),                              // 1: aea.aea.acn.v1_0_0.AcnMessage\n\t(*AcnMessage_AgentRecord)(nil),                  // 2: aea.aea.acn.v1_0_0.AcnMessage.AgentRecord\n\t(*AcnMessage_StatusBody)(nil),                   // 3: aea.aea.acn.v1_0_0.AcnMessage.StatusBody\n\t(*AcnMessage_Register_Performative)(nil),        // 4: aea.aea.acn.v1_0_0.AcnMessage.Register_Performative\n\t(*AcnMessage_Lookup_Request_Performative)(nil),  // 5: aea.aea.acn.v1_0_0.AcnMessage.Lookup_Request_Performative\n\t(*AcnMessage_Lookup_Response_Performative)(nil), // 6: aea.aea.acn.v1_0_0.AcnMessage.Lookup_Response_Performative\n\t(*AcnMessage_Aea_Envelope_Performative)(nil),    // 7: aea.aea.acn.v1_0_0.AcnMessage.Aea_Envelope_Performative\n\t(*AcnMessage_Status_Performative)(nil),          // 8: aea.aea.acn.v1_0_0.AcnMessage.Status_Performative\n}\nvar file_acn_proto_depIdxs = []int32{\n\t7,  // 0: aea.aea.acn.v1_0_0.AcnMessage.aea_envelope:type_name -> aea.aea.acn.v1_0_0.AcnMessage.Aea_Envelope_Performative\n\t5,  // 1: aea.aea.acn.v1_0_0.AcnMessage.lookup_request:type_name -> aea.aea.acn.v1_0_0.AcnMessage.Lookup_Request_Performative\n\t6,  // 2: aea.aea.acn.v1_0_0.AcnMessage.lookup_response:type_name -> aea.aea.acn.v1_0_0.AcnMessage.Lookup_Response_Performative\n\t4,  // 3: aea.aea.acn.v1_0_0.AcnMessage.register:type_name -> aea.aea.acn.v1_0_0.AcnMessage.Register_Performative\n\t8,  // 4: aea.aea.acn.v1_0_0.AcnMessage.status:type_name -> aea.aea.acn.v1_0_0.AcnMessage.Status_Performative\n\t0,  // 5: aea.aea.acn.v1_0_0.AcnMessage.StatusBody.code:type_name -> aea.aea.acn.v1_0_0.AcnMessage.StatusBody.StatusCodeEnum\n\t2,  // 6: aea.aea.acn.v1_0_0.AcnMessage.Register_Performative.record:type_name -> aea.aea.acn.v1_0_0.AcnMessage.AgentRecord\n\t2,  // 7: aea.aea.acn.v1_0_0.AcnMessage.Lookup_Response_Performative.record:type_name -> aea.aea.acn.v1_0_0.AcnMessage.AgentRecord\n\t2,  // 8: aea.aea.acn.v1_0_0.AcnMessage.Aea_Envelope_Performative.record:type_name -> aea.aea.acn.v1_0_0.AcnMessage.AgentRecord\n\t3,  // 9: aea.aea.acn.v1_0_0.AcnMessage.Status_Performative.body:type_name -> aea.aea.acn.v1_0_0.AcnMessage.StatusBody\n\t10, // [10:10] is the sub-list for method output_type\n\t10, // [10:10] is the sub-list for method input_type\n\t10, // [10:10] is the sub-list for extension type_name\n\t10, // [10:10] is the sub-list for extension extendee\n\t0,  // [0:10] is the sub-list for field type_name\n}\n\nfunc init() { file_acn_proto_init() }\nfunc file_acn_proto_init() {\n\tif File_acn_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_acn_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*AcnMessage); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_acn_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*AcnMessage_AgentRecord); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_acn_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*AcnMessage_StatusBody); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_acn_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*AcnMessage_Register_Performative); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_acn_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*AcnMessage_Lookup_Request_Performative); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_acn_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*AcnMessage_Lookup_Response_Performative); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_acn_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*AcnMessage_Aea_Envelope_Performative); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_acn_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*AcnMessage_Status_Performative); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\tfile_acn_proto_msgTypes[0].OneofWrappers = []interface{}{\n\t\t(*AcnMessage_AeaEnvelope)(nil),\n\t\t(*AcnMessage_LookupRequest)(nil),\n\t\t(*AcnMessage_LookupResponse)(nil),\n\t\t(*AcnMessage_Register)(nil),\n\t\t(*AcnMessage_Status)(nil),\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_acn_proto_rawDesc,\n\t\t\tNumEnums:      1,\n\t\t\tNumMessages:   8,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_acn_proto_goTypes,\n\t\tDependencyIndexes: file_acn_proto_depIdxs,\n\t\tEnumInfos:         file_acn_proto_enumTypes,\n\t\tMessageInfos:      file_acn_proto_msgTypes,\n\t}.Build()\n\tFile_acn_proto = out.File\n\tfile_acn_proto_rawDesc = nil\n\tfile_acn_proto_goTypes = nil\n\tfile_acn_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "libs/go/libp2p_node/protocols/acn/v1_0_0/acn.proto",
    "content": "syntax = \"proto3\";\n\npackage aea.aea.acn.v1_0_0;\n\noption go_package = \"libp2p_node/protocols/acn/v1_0_0\";\n\nmessage AcnMessage{\n\n  // Custom Types\n  message AgentRecord{\n    string service_id = 1;\n    string ledger_id = 2;\n    string address = 3;\n    string public_key = 4;\n    string peer_public_key = 5;\n    string signature = 6;\n    string not_before = 7;\n    string not_after = 8;\n  }\n\n  message StatusBody{\n    enum StatusCodeEnum {\n      // common (0x)\n      SUCCESS = 0;\n      ERROR_UNSUPPORTED_VERSION = 1;\n      ERROR_UNEXPECTED_PAYLOAD = 2;\n      ERROR_GENERIC = 3;\n      ERROR_DECODE = 4;\n      // register (1x)\n      ERROR_WRONG_AGENT_ADDRESS = 10;\n      ERROR_WRONG_PUBLIC_KEY = 11;\n      ERROR_INVALID_PROOF = 12;\n      ERROR_UNSUPPORTED_LEDGER = 13;\n      // lookup & delivery (2x) \n      ERROR_UNKNOWN_AGENT_ADDRESS = 20;\n      ERROR_AGENT_NOT_READY = 21;\n    }\n    StatusCodeEnum code = 1;\n    repeated string msgs = 2;\n  }\n\n\n  // Performatives and contents\n  message Register_Performative{\n    AgentRecord record = 1;\n  }\n\n  message Lookup_Request_Performative{\n    string agent_address = 1;\n  }\n\n  message Lookup_Response_Performative{\n    AgentRecord record = 1;\n  }\n\n  message Aea_Envelope_Performative{\n    bytes envelope = 1;\n    AgentRecord record = 2;\n  }\n\n  message Status_Performative{\n    StatusBody body = 1;\n  }\n\n\n  oneof performative{\n    Aea_Envelope_Performative aea_envelope = 5;\n    Lookup_Request_Performative lookup_request = 6;\n    Lookup_Response_Performative lookup_response = 7;\n    Register_Performative register = 8;\n    Status_Performative status = 9;\n  }\n}\n"
  },
  {
    "path": "libs/go/libp2p_node/protocols/acn/v1_0_0/acn.yaml",
    "content": "---\nname: acn\nauthor: fetchai\nversion: 1.0.0\ndescription: The protocol used for envelope delivery on the ACN.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nprotocol_specification_id: aea/acn:1.0.0\nspeech_acts:\n  register:\n    record: ct:AgentRecord\n  lookup_request:\n    agent_address: pt:str\n  lookup_response:\n    record: ct:AgentRecord\n  aea_envelope:\n    envelope: pt:bytes\n    record: ct:AgentRecord\n  status:\n    body: ct:StatusBody\n...\n---\nct:AgentRecord:\n  string service_id = 1;\n  string ledger_id = 2;\n  string address = 3;\n  string public_key = 4;\n  string peer_public_key = 5;\n  string signature = 6;\n  string not_before = 7;\n  string not_after = 8;\nct:StatusBody: |\n  enum StatusCodeEnum {\n    // common (0x)\n    SUCCESS = 0;\n    ERROR_UNSUPPORTED_VERSION = 1;\n    ERROR_UNEXPECTED_PAYLOAD = 2;\n    ERROR_GENERIC = 3;\n    ERROR_DECODE = 4;\n    // register (1x)\n    ERROR_WRONG_AGENT_ADDRESS = 10;\n    ERROR_WRONG_PUBLIC_KEY = 11;\n    ERROR_INVALID_PROOF = 12;\n    ERROR_UNSUPPORTED_LEDGER = 13;\n    // lookup & delivery (2x) \n    ERROR_UNKNOWN_AGENT_ADDRESS = 20;\n    ERROR_AGENT_NOT_READY = 21;\n  }\n  StatusCodeEnum code = 1;\n  repeated string msgs = 2;\n...\n---\ninitiation: [register, lookup_request, aea_envelope]\nreply:\n  register: [status]\n  lookup_request: [lookup_response, status]\n  aea_envelope: [status]\n  status: []\n  lookup_response: []\ntermination: [status, lookup_response]\nroles: {node}\nend_states: [successful, failed]\nkeep_terminal_state_dialogues: false\n...\n"
  },
  {
    "path": "libs/go/libp2p_node/utils/utils.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2019 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\n\npackage utils\n\nimport (\n\t\"bufio\"\n\t\"context\"\n\t\"crypto/sha256\"\n\t\"encoding/base64\"\n\t\"encoding/binary\"\n\t\"encoding/hex\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"math\"\n\t\"net\"\n\t\"os\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/ipfs/go-cid\"\n\t\"github.com/libp2p/go-libp2p-core/crypto\"\n\t\"github.com/libp2p/go-libp2p-core/network\"\n\t\"github.com/libp2p/go-libp2p-core/peer\"\n\tdht \"github.com/libp2p/go-libp2p-kad-dht\"\n\t\"github.com/multiformats/go-multiaddr\"\n\t\"github.com/multiformats/go-multihash\"\n\t\"github.com/rs/zerolog\"\n\t\"golang.org/x/crypto/ripemd160\" // nolint:staticcheck\n\t\"golang.org/x/crypto/sha3\"\n\n\thost \"github.com/libp2p/go-libp2p-core/host\"\n\tpeerstore \"github.com/libp2p/go-libp2p-core/peerstore\"\n\n\tbtcec \"github.com/btcsuite/btcd/btcec\"\n\t\"github.com/btcsuite/btcutil/bech32\"\n\t\"github.com/ethereum/go-ethereum/common/hexutil\"\n\tethCrypto \"github.com/ethereum/go-ethereum/crypto\"\n\tproto \"google.golang.org/protobuf/proto\"\n\n\t\"libp2p_node/aea\"\n)\n\nconst (\n\tmaxMessageSizeDelegateConnection = 1024 * 1024 * 3 // 3Mb\n)\n\nvar (\n\taddressFromPublicKeyTable = map[string]func(string) (string, error){\n\t\t\"fetchai\":  FetchAIAddressFromPublicKey,\n\t\t\"cosmos\":   CosmosAddressFromPublicKey,\n\t\t\"ethereum\": EthereumAddressFromPublicKey,\n\t}\n\tverifyLedgerSignatureTable = map[string]func([]byte, string, string) (bool, error){\n\t\t\"fetchai\":  VerifyFetchAISignatureBTC,\n\t\t\"cosmos\":   VerifyFetchAISignatureBTC,\n\t\t\"ethereum\": VerifyEthereumSignatureETH,\n\t}\n)\n\nvar loggerGlobalLevel zerolog.Level = zerolog.DebugLevel\n\nvar logger zerolog.Logger = NewDefaultLogger()\n\n// SetLoggerLevel set utils logger level\nfunc SetLoggerLevel(lvl zerolog.Level) {\n\tlogger = logger.Level(lvl)\n}\n\nfunc ignore(err error) {\n\tif err != nil {\n\t\tfmt.Println(\"IGNORED:\", err)\n\t}\n}\n\n/*\n\tLogging\n*/\n\nfunc newConsoleLogger() zerolog.Logger {\n\treturn zerolog.New(zerolog.ConsoleWriter{\n\t\tOut:        os.Stdout,\n\t\tNoColor:    false,\n\t\tTimeFormat: time.RFC3339Nano,\n\t})\n}\n\n// NewDefaultLogger basic zerolog console writer\nfunc NewDefaultLogger() zerolog.Logger {\n\treturn newConsoleLogger().\n\t\tWith().Timestamp().\n\t\tLogger().Level(loggerGlobalLevel)\n}\n\n// NewDefaultLoggerWithFields zerolog console writer\nfunc NewDefaultLoggerWithFields(fields map[string]string) zerolog.Logger {\n\tlogger := newConsoleLogger().\n\t\tWith().Timestamp()\n\tfor key, val := range fields {\n\t\tlogger = logger.Str(key, val)\n\t}\n\treturn logger.Logger().Level(loggerGlobalLevel)\n\n}\n\n/*\n\tHelpers\n*/\n\n// BootstrapConnect connect to `peers` at bootstrap\n// This code is borrowed from the go-ipfs bootstrap process\nfunc BootstrapConnect(\n\tctx context.Context,\n\tph host.Host,\n\tkaddht *dht.IpfsDHT,\n\tpeers []peer.AddrInfo,\n) error {\n\tif len(peers) < 1 {\n\t\treturn errors.New(\"not enough bootstrap peers\")\n\t}\n\n\terrs := make(chan error, len(peers))\n\tvar wg sync.WaitGroup\n\tfor _, p := range peers {\n\n\t\t// performed asynchronously because when performed synchronously, if\n\t\t// one `Connect` call hangs, subsequent calls are more likely to\n\t\t// fail/abort due to an expiring context.\n\t\t// Also, performed asynchronously for dial speed.\n\n\t\twg.Add(1)\n\t\tgo func(p peer.AddrInfo) {\n\t\t\tdefer wg.Done()\n\t\t\t//defer logger.Debug().Msgf(\"%s bootstrapDial %s %s\", ctx, ph.ID(), p.ID)\n\t\t\tlogger.Debug().Msgf(\"%s bootstrapping to %s\", ph.ID(), p.ID)\n\n\t\t\tph.Peerstore().AddAddrs(p.ID, p.Addrs, peerstore.PermanentAddrTTL)\n\t\t\tif err := ph.Connect(ctx, p); err != nil {\n\t\t\t\t//logger.Error().\n\t\t\t\t//\tStr(\"err\", err.Error()).\n\t\t\t\t//\tMsgf(\"failed to bootstrap with %v\", p.ID)\n\t\t\t\terrs <- err\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tlogger.Debug().Msgf(\"bootstrapped with %v\", p.ID)\n\t\t}(p)\n\t}\n\twg.Wait()\n\n\t// our failure condition is when no connection attempt succeeded.\n\t// So drain the errs channel, counting the results.\n\tclose(errs)\n\tcount := 0\n\tvar err error\n\tfor err = range errs {\n\t\tif err != nil {\n\t\t\tcount++\n\t\t}\n\t}\n\tif count == len(peers) {\n\t\treturn errors.New(\"failed to bootstrap: \" + err.Error())\n\t}\n\t// workaround: to avoid getting `failed to find any peer in table`\n\t//  when calling dht.Provide (happens occasionally)\n\tlogger.Debug().Msg(\"waiting for bootstrap peers to be added to dht routing table...\")\n\tfor _, peer := range peers {\n\t\tctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)\n\t\tdefer cancel()\n\t\tfor kaddht.RoutingTable().Find(peer.ID) == \"\" {\n\t\t\tselect {\n\t\t\tcase <-ctx.Done():\n\t\t\t\treturn errors.New(\n\t\t\t\t\t\"timeout: entry peer haven't been added to DHT routing table \" + peer.ID.Pretty(),\n\t\t\t\t)\n\t\t\tcase <-time.After(time.Millisecond * 5):\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// ComputeCID compute content id for ipfsDHT\nfunc ComputeCID(addr string) (cid.Cid, error) {\n\tpref := cid.Prefix{\n\t\tVersion:  0,\n\t\tCodec:    cid.Raw,\n\t\tMhType:   multihash.SHA2_256,\n\t\tMhLength: -1, // default length\n\t}\n\n\t// And then feed it some data\n\tc, err := pref.Sum([]byte(addr))\n\tif err != nil {\n\t\treturn cid.Cid{}, err\n\t}\n\n\treturn c, nil\n}\n\n// GetPeersAddrInfo Parse multiaddresses and convert them to peer.AddrInfo\nfunc GetPeersAddrInfo(peers []string) ([]peer.AddrInfo, error) {\n\tpinfos := make([]peer.AddrInfo, len(peers))\n\tfor i, addr := range peers {\n\t\tmaddr := multiaddr.StringCast(addr)\n\t\tp, err := peer.AddrInfoFromP2pAddr(maddr)\n\t\tif err != nil {\n\t\t\treturn pinfos, err\n\t\t}\n\t\tpinfos[i] = *p\n\t}\n\treturn pinfos, nil\n}\n\n/*\n\tFetchAI Crypto Helpers\n*/\n\n// PubKeyFromFetchAIPublicKey create libp2p public key from fetchai hex encoded secp256k1 key\nfunc PubKeyFromFetchAIPublicKey(publicKey string) (crypto.PubKey, error) {\n\thexBytes, _ := hex.DecodeString(publicKey)\n\treturn crypto.UnmarshalSecp256k1PublicKey(hexBytes)\n}\n\n// FetchAIPublicKeyFromPubKey return FetchAI's format serialized public key\nfunc FetchAIPublicKeyFromPubKey(publicKey crypto.PubKey) (string, error) {\n\traw, err := publicKey.Raw()\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\treturn hex.EncodeToString(raw), nil\n}\n\n// BTCPubKeyFromFetchAIPublicKey from public key string\nfunc BTCPubKeyFromFetchAIPublicKey(publicKey string) (*btcec.PublicKey, error) {\n\tpbkBytes, err := hex.DecodeString(publicKey)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tpbk, err := btcec.ParsePubKey(pbkBytes, btcec.S256())\n\treturn pbk, err\n}\n\n// BTCPubKeyFromEthereumPublicKey create libp2p public key from ethereum uncompressed\n//  hex encoded secp256k1 key\nfunc BTCPubKeyFromEthereumPublicKey(publicKey string) (*btcec.PublicKey, error) {\n\treturn BTCPubKeyFromUncompressedHex(publicKey[2:])\n}\n\n// ConvertStrEncodedSignatureToDER to convert signature to DER format\n// References:\n//  - https://github.com/fetchai/agents-aea/blob/main/aea/crypto/cosmos.py#L258\n//  - https://github.com/btcsuite/btcd/blob/master/btcec/signature.go#L47\nfunc ConvertStrEncodedSignatureToDER(signature []byte) []byte {\n\trb := signature[:len(signature)/2]\n\tsb := signature[len(signature)/2:]\n\tlength := 6 + len(rb) + len(sb)\n\tsigDER := make([]byte, length)\n\tsigDER[0] = 0x30\n\tsigDER[1] = byte(length - 2)\n\tsigDER[2] = 0x02\n\tsigDER[3] = byte(len(rb))\n\toffset := copy(sigDER[4:], rb) + 4\n\tsigDER[offset] = 0x02\n\tsigDER[offset+1] = byte(len(sb))\n\tcopy(sigDER[offset+2:], sb)\n\treturn sigDER\n}\n\n// ConvertDEREncodedSignatureToStr Convert signatue from der format to string\n// References:\n//  - https://github.com/fetchai/agents-aea/blob/main/aea/crypto/cosmos.py#L258\n//  - https://github.com/btcsuite/btcd/blob/master/btcec/signature.go#L47\nfunc ConvertDEREncodedSignatureToStr(signature []byte) ([]byte, error) {\n\tsig, err := btcec.ParseDERSignature(signature, btcec.S256())\n\tif err != nil {\n\t\treturn []byte{}, err\n\t}\n\treturn append(sig.R.Bytes(), sig.S.Bytes()...), nil\n}\n\n// ParseFetchAISignature create btcec Signature from base64 formated, string (not DER) encoded RFC6979 signature\nfunc ParseFetchAISignature(signature string) (*btcec.Signature, error) {\n\t// First convert the signature into a DER one\n\tsigBytes, err := base64.StdEncoding.DecodeString(signature)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tsigDER := ConvertStrEncodedSignatureToDER(sigBytes)\n\n\t// Parse\n\tsigBTC, err := btcec.ParseSignature(sigDER, btcec.S256())\n\treturn sigBTC, err\n}\n\n// VerifyLedgerSignature verify signature of message using public key for supported ledgers\nfunc VerifyLedgerSignature(\n\tledgerID string,\n\tmessage []byte,\n\tsignature string,\n\tpubKey string,\n) (bool, error) {\n\tverifySignature, found := verifyLedgerSignatureTable[ledgerID]\n\tif found {\n\t\treturn verifySignature(message, signature, pubKey)\n\t}\n\treturn false, errors.New(\"unsupported ledger\")\n}\n\n// VerifyFetchAISignatureBTC verify the RFC6967 string-encoded signature of message using FetchAI public key\nfunc VerifyFetchAISignatureBTC(message []byte, signature string, pubkey string) (bool, error) {\n\t// construct verifying key\n\tverifyKey, err := BTCPubKeyFromFetchAIPublicKey(pubkey)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\t// construct signature\n\tsignatureBTC, err := ParseFetchAISignature(signature)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\t// verify signature\n\tmessageHash := sha256.New()\n\t_, err = messageHash.Write([]byte(message))\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\treturn signatureBTC.Verify(messageHash.Sum(nil), verifyKey), nil\n}\n\n// VerifyFetchAISignatureLibp2p verify RFC6967 string-encoded signature of message using FetchAI public key\nfunc VerifyFetchAISignatureLibp2p(message []byte, signature string, pubkey string) (bool, error) {\n\t// construct verifying key\n\tverifyKey, err := PubKeyFromFetchAIPublicKey(pubkey)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\t// Convert signature into DER encoding\n\tsigBytes, err := base64.StdEncoding.DecodeString(signature)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\tsigDER := ConvertStrEncodedSignatureToDER(sigBytes)\n\n\t// verify signature\n\treturn verifyKey.Verify(message, sigDER)\n}\n\n// SignFetchAI signs message with private key\nfunc SignFetchAI(message []byte, privKey string) (string, error) {\n\tsigningKey, _, err := KeyPairFromFetchAIKey(privKey)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tsignature, err := signingKey.Sign(message)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tstrSignature, err := ConvertDEREncodedSignatureToStr(signature)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tencodedSignature := base64.StdEncoding.EncodeToString(strSignature)\n\treturn encodedSignature, nil\n}\n\nfunc signHashETH(data []byte) []byte {\n\tmsg := fmt.Sprintf(\"\\x19Ethereum Signed Message:\\n%d%s\", len(data), data)\n\treturn ethCrypto.Keccak256([]byte(msg))\n}\n\n// RecoverAddressFromEthereumSignature verify the signature and returns the address of the signer\n// references:\n//  - https://github.com/ethereum/go-ethereum/blob/55599ee95d4151a2502465e0afc7c47bd1acba77/internal/ethapi/api.go#L452-L459\n//  - https://github.com/ethereum/go-ethereum/blob/55599ee95d4151a2502465e0afc7c47bd1acba77/internal/ethapi/api.go#L404\nfunc RecoverAddressFromEthereumSignature(message []byte, signature string) (string, error) {\n\t// prepare signature\n\tsigBytes, err := hexutil.Decode(signature)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tif sigBytes[64] != 27 && sigBytes[64] != 28 {\n\t\treturn \"\", errors.New(\"invalid Ethereum signature (V is not 27 or 28)\")\n\t}\n\tsigBytes[64] -= 27 // Transform yellow paper V from 27/28 to 0/1\n\n\t// recover verify key\n\trecoveredPubKey, err := ethCrypto.SigToPub(signHashETH(message), sigBytes)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn ethCrypto.PubkeyToAddress(*recoveredPubKey).Hex(), nil\n}\n\n// VerifyEthereumSignatureETH verify ethereum signature using ethereum public key\nfunc VerifyEthereumSignatureETH(message []byte, signature string, pubkey string) (bool, error) {\n\t// get expected signer address\n\texpectedAddress, err := EthereumAddressFromPublicKey(pubkey)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\t// recover signer address\n\trecoveredAddress, err := RecoverAddressFromEthereumSignature(message, signature)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\tif recoveredAddress != expectedAddress {\n\t\treturn false, errors.New(\"recovered and expected addresses don't match\")\n\t}\n\n\treturn true, nil\n}\n\n// KeyPairFromFetchAIKey  key pair from hex encoded secp256k1 private key\nfunc KeyPairFromFetchAIKey(key string) (crypto.PrivKey, crypto.PubKey, error) {\n\tpkBytes, err := hex.DecodeString(key)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tbtcPrivateKey, _ := btcec.PrivKeyFromBytes(btcec.S256(), pkBytes)\n\tprvKey, pubKey, err := crypto.KeyPairFromStdKey(btcPrivateKey)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\treturn prvKey, pubKey, nil\n}\n\n// AgentAddressFromPublicKey get wallet address from public key associated with ledgerId\n// format from: https://github.com/fetchai/agents-aea/blob/main/aea/crypto/cosmos.py#L120\nfunc AgentAddressFromPublicKey(ledgerID string, publicKey string) (string, error) {\n\tif addressFromPublicKey, found := addressFromPublicKeyTable[ledgerID]; found {\n\t\treturn addressFromPublicKey(publicKey)\n\t}\n\treturn \"\", errors.New(\"Unsupported ledger \" + ledgerID)\n}\n\n// FetchAIAddressFromPublicKey get wallet address from hex encoded secp256k1 public key\nfunc FetchAIAddressFromPublicKey(publicKey string) (string, error) {\n\treturn cosmosAddressFromPublicKeyWithPrefix(\"fetch\", publicKey)\n}\n\n// CosmosAddressFromPublicKey get wallet address from hex encoded secp256k1 public key\nfunc CosmosAddressFromPublicKey(publicKey string) (string, error) {\n\treturn cosmosAddressFromPublicKeyWithPrefix(\"cosmos\", publicKey)\n}\n\n// cosmosAddressFromPublicKeyWithPrefix get wallet address from hex encoded secp256k1 public key\n// format from: https://github.com/fetchai/agents-aea/blob/main/aea/crypto/cosmos.py#L120\nfunc cosmosAddressFromPublicKeyWithPrefix(prefix string, publicKey string) (string, error) {\n\tvar addr string\n\tvar err error\n\thexBytes, err := hex.DecodeString(publicKey)\n\tif err != nil {\n\t\treturn addr, err\n\t}\n\thash := sha256.New()\n\t_, err = hash.Write(hexBytes)\n\tif err != nil {\n\t\treturn addr, err\n\t}\n\tsha256Hash := hash.Sum(nil)\n\thash = ripemd160.New()\n\t_, err = hash.Write(sha256Hash)\n\tif err != nil {\n\t\treturn addr, err\n\t}\n\tripemd160Hash := hash.Sum(nil)\n\tfiveBitsChar, err := bech32.ConvertBits(ripemd160Hash, 8, 5, true)\n\tif err != nil {\n\t\treturn addr, err\n\t}\n\taddr, err = bech32.Encode(prefix, fiveBitsChar)\n\treturn addr, err\n}\n\n// EthereumAddressFromPublicKey get wallet address from hex encoded secp256k1 public key\n// references:\n//  - https://github.com/fetchai/agents-aea/blob/main/aea/crypto/ethereum.py#L330\n//  - https://github.com/ethereum/go-ethereum/blob/master/crypto/crypto.go#L263\nfunc EthereumAddressFromPublicKey(publicKey string) (string, error) {\n\tvar addr string\n\tvar err error\n\thexBytes, err := hex.DecodeString(publicKey[2:])\n\tif err != nil {\n\t\treturn addr, err\n\t}\n\thash := sha3.NewLegacyKeccak256()\n\t_, err = hash.Write(hexBytes)\n\tif err != nil {\n\t\treturn addr, err\n\t}\n\tsha3KeccakHash := hash.Sum(nil)\n\treturn encodeChecksumEIP55(sha3KeccakHash[12:]), nil\n}\n\n// encodeChecksumEIP55 EIP55-compliant hex string representation of the address\n// source: https://github.com/ethereum/go-ethereum/blob/master/common/types.go#L210\n// reference: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-55.md\nfunc encodeChecksumEIP55(address []byte) string {\n\tunchecksummed := hex.EncodeToString(address[:])\n\tsha := sha3.NewLegacyKeccak256()\n\t_, err := sha.Write([]byte(unchecksummed))\n\tignore(err)\n\thash := sha.Sum(nil)\n\n\tresult := []byte(unchecksummed)\n\tfor i := 0; i < len(result); i++ {\n\t\thashByte := hash[i/2]\n\t\tif i%2 == 0 {\n\t\t\thashByte = hashByte >> 4\n\t\t} else {\n\t\t\thashByte &= 0xf\n\t\t}\n\t\tif result[i] > '9' && hashByte > 7 {\n\t\t\tresult[i] -= 32\n\t\t}\n\t}\n\treturn \"0x\" + string(result)\n}\n\n// IDFromFetchAIPublicKey Get PeeID (multihash) from fetchai public key\nfunc IDFromFetchAIPublicKey(publicKey string) (peer.ID, error) {\n\tb, err := hex.DecodeString(publicKey)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tpubKey, err := btcec.ParsePubKey(b, btcec.S256())\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tmultihash, err := peer.IDFromPublicKey((*crypto.Secp256k1PublicKey)(pubKey))\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn multihash, nil\n}\n\n// BTCPubKeyFromUncompressedHex get public key from secp256k1 hex encoded  uncompressed representation\nfunc BTCPubKeyFromUncompressedHex(publicKey string) (*btcec.PublicKey, error) {\n\tb, err := hex.DecodeString(publicKey)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tpubBytes := make([]byte, 0, btcec.PubKeyBytesLenUncompressed)\n\tpubBytes = append(pubBytes, 0x4) // btcec.pubkeyUncompressed\n\tpubBytes = append(pubBytes, b...)\n\n\treturn btcec.ParsePubKey(pubBytes, btcec.S256())\n}\n\n// IDFromFetchAIPublicKeyUncompressed Get PeeID (multihash) from fetchai public key\nfunc IDFromFetchAIPublicKeyUncompressed(publicKey string) (peer.ID, error) {\n\tpubKey, err := BTCPubKeyFromUncompressedHex(publicKey)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tmultihash, err := peer.IDFromPublicKey((*crypto.Secp256k1PublicKey)(pubKey))\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn multihash, nil\n}\n\n// FetchAIPublicKeyFromFetchAIPrivateKey get fetchai public key from fetchai private key\nfunc FetchAIPublicKeyFromFetchAIPrivateKey(privateKey string) (string, error) {\n\tpkBytes, err := hex.DecodeString(privateKey)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\t_, btcPublicKey := btcec.PrivKeyFromBytes(btcec.S256(), pkBytes)\n\n\treturn hex.EncodeToString(btcPublicKey.SerializeCompressed()), nil\n}\n\n/*\n   Utils\n*/\n\n// WriteBytesConn send bytes to `conn`\nfunc WriteBytesConn(conn net.Conn, data []byte) error {\n\n\tif len(data) > math.MaxInt32 {\n\t\tlogger.Error().Msg(\"data size too large\")\n\t\treturn errors.New(\"data size too large\")\n\t}\n\tif len(data) == 0 {\n\t\tlogger.Error().Msg(\"No data to write\")\n\t\treturn nil\n\t}\n\n\tsize := uint32(len(data))\n\tbuf := make([]byte, 4, 4+size)\n\tbinary.BigEndian.PutUint32(buf, size)\n\tbuf = append(buf, data...)\n\t_, err := conn.Write(buf)\n\treturn err\n}\n\n// ReadBytesConn receive bytes from `conn`\nfunc ReadBytesConn(conn net.Conn) ([]byte, error) {\n\tbuf := make([]byte, 4)\n\t_, err := conn.Read(buf)\n\tif err != nil {\n\t\treturn buf, err\n\t}\n\n\tsize := binary.BigEndian.Uint32(buf)\n\tif size > maxMessageSizeDelegateConnection {\n\t\treturn nil, errors.New(\"expected message size larger than maximum allowed\")\n\t}\n\n\tbuf = make([]byte, size)\n\t_, err = conn.Read(buf)\n\treturn buf, err\n}\n\n// WriteEnvelopeConn send envelope to `conn`\nfunc WriteEnvelopeConn(conn net.Conn, envelope *aea.Envelope) error {\n\tdata, err := proto.Marshal(envelope)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn WriteBytesConn(conn, data)\n}\n\n// ReadEnvelopeConn receive envelope from `conn`\nfunc ReadEnvelopeConn(conn net.Conn) (*aea.Envelope, error) {\n\tenvelope := &aea.Envelope{}\n\tdata, err := ReadBytesConn(conn)\n\tif err != nil {\n\t\treturn envelope, err\n\t}\n\terr = proto.Unmarshal(data, envelope)\n\treturn envelope, err\n}\n\n// ReadBytes from a network stream\nfunc ReadBytes(s network.Stream) ([]byte, error) {\n\tif s == nil {\n\t\tpanic(\"CRITICAL can not write to nil stream\")\n\t}\n\n\trstream := bufio.NewReader(s)\n\n\tbuf := make([]byte, 4)\n\t_, err := io.ReadFull(rstream, buf)\n\tif err != nil {\n\t\tlogger.Error().\n\t\t\tStr(\"err\", err.Error()).\n\t\t\tMsg(\"while receiving size\")\n\t\treturn buf, err\n\t}\n\n\tsize := binary.BigEndian.Uint32(buf)\n\tif size > maxMessageSizeDelegateConnection {\n\t\treturn nil, errors.New(\"expected message size larger than maximum allowed\")\n\t}\n\n\t//logger.Debug().Msgf(\"expecting %d\", size)\n\n\tbuf = make([]byte, size)\n\t_, err = io.ReadFull(rstream, buf)\n\n\treturn buf, err\n}\n\n// WriteBytes to a network stream\nfunc WriteBytes(s network.Stream, data []byte) error {\n\tif len(data) > math.MaxInt32 {\n\t\tlogger.Error().Msg(\"data size too large\")\n\t\treturn errors.New(\"data size too large\")\n\t}\n\tif len(data) == 0 {\n\t\tlogger.Error().Msg(\"No data to write\")\n\t\treturn nil\n\t}\n\n\tif s == nil {\n\t\tpanic(\"CRITICAL, can not write to nil stream\")\n\t}\n\n\twstream := bufio.NewWriter(s)\n\n\tsize := uint32(len(data))\n\tbuf := make([]byte, 4)\n\tbinary.BigEndian.PutUint32(buf, size)\n\n\t_, err := wstream.Write(buf)\n\tif err != nil {\n\t\tlogger.Error().\n\t\t\tStr(\"err\", err.Error()).\n\t\t\tMsg(\"while sending size\")\n\t\treturn err\n\t}\n\n\t//logger.Debug().Msgf(\"writing %d\", len(data))\n\t_, err = wstream.Write(data)\n\tif err != nil {\n\t\tlogger.Error().\n\t\t\tStr(\"err\", err.Error()).\n\t\t\tMsg(\"Error on data write\")\n\t\treturn err\n\t}\n\tif s == nil {\n\t\tpanic(\"CRITICAL, can not flush nil stream\")\n\t}\n\n\terr = wstream.Flush()\n\treturn err\n}\n\ntype ConnPipe struct {\n\tConn net.Conn\n}\n\nfunc (conPipe ConnPipe) Connect() error {\n\treturn nil\n}\nfunc (conPipe ConnPipe) Read() ([]byte, error) {\n\treturn ReadBytesConn(conPipe.Conn)\n}\nfunc (conPipe ConnPipe) Write(data []byte) error {\n\treturn WriteBytesConn(conPipe.Conn, data)\n}\nfunc (conPipe ConnPipe) Close() error {\n\treturn nil\n}\n\ntype StreamPipe struct {\n\tStream network.Stream\n}\n\nfunc (streamPipe StreamPipe) Connect() error {\n\treturn nil\n}\nfunc (streamPipe StreamPipe) Read() ([]byte, error) {\n\treturn ReadBytes(streamPipe.Stream)\n}\nfunc (streamPipe StreamPipe) Write(data []byte) error {\n\treturn WriteBytes(streamPipe.Stream, data)\n}\nfunc (streamPipe StreamPipe) Close() error {\n\treturn nil\n}\n"
  },
  {
    "path": "libs/go/libp2p_node/utils/utils_test.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2021 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\n\npackage utils\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"libp2p_node/aea\"\n\tmocks \"libp2p_node/mocks\"\n\t\"net\"\n\t\"reflect\"\n\t\"testing\"\n\n\t\"bou.ke/monkey\"\n\tgomock \"github.com/golang/mock/gomock\"\n\t\"github.com/libp2p/go-libp2p-core/peer\"\n\tdht \"github.com/libp2p/go-libp2p-kad-dht\"\n\tkb \"github.com/libp2p/go-libp2p-kbucket\"\n\tma \"github.com/multiformats/go-multiaddr\"\n\t\"github.com/rs/zerolog\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\n// Crypto operations\n\nfunc TestEthereumCrypto(t *testing.T) {\n\t//privateKey := \"0xb60fe8027fb82f1a1bd6b8e66d4400f858989a2c67428a4e7f589441700339b0\"\n\tpublicKey := \"0xf753e5a9e2368e97f4db869a0d956d3ffb64672d6392670572906c786b5712ada13b6bff882951b3ba3dd65bdacc915c2b532efc3f183aa44657205c6c337225\"\n\taddress := \"0xb8d8c62d4a1999b7aea0aebBD5020244a4a9bAD8\"\n\tpublicKeySignature := \"0x304c2ba4ae7fa71295bfc2920b9c1268d574d65531f1f4d2117fc1439a45310c37ab75085a9df2a4169a4d47982b330a4387b1ded0c8881b030629db30bbaf3a1c\"\n\n\taddFromPublicKey, err := EthereumAddressFromPublicKey(publicKey)\n\tif err != nil || addFromPublicKey != address {\n\t\tt.Error(\n\t\t\t\"Error when computing address from public key or address and public key don't match\",\n\t\t)\n\t}\n\n\t_, err = BTCPubKeyFromEthereumPublicKey(publicKey)\n\tif err != nil {\n\t\tt.Errorf(\"While building BTC public key from string: %s\", err.Error())\n\t}\n\n\t/*\n\t\tethSig, err := secp256k1.Sign(hashedPublicKey, hexutil.MustDecode(privateKey))\n\t\tif err != nil {\n\t\t\tt.Error(err.Error())\n\t\t}\n\t\tprintln(hexutil.Encode(ethSig))\n\t\thash := sha3.NewLegacyKeccak256()\n\t\t_, err = hash.Write([]byte(publicKey))\n\t\tif err != nil {\n\t\t\tt.Error(err.Error())\n\t\t}\n\t\tsha3KeccakHash := hash.Sum(nil)\n\t*/\n\n\tvalid, err := VerifyEthereumSignatureETH([]byte(publicKey), publicKeySignature, publicKey)\n\tif err != nil {\n\t\tt.Error(err.Error())\n\t}\n\n\tif !valid {\n\t\tt.Errorf(\"Signer address don't match %s\", addFromPublicKey)\n\t}\n}\n\nfunc TestFetchAICrypto(t *testing.T) {\n\tpublicKey := \"02358e3e42a6ba15cf6b2ba6eb05f02b8893acf82b316d7dd9cda702b0892b8c71\"\n\taddress := \"fetch19dq2mkcpp6x0aypxt9c9gz6n4fqvax0x9a7t5r\"\n\tpeerPublicKey := \"027af21aff853b9d9589867ea142b0a60a9611fc8e1fae04c2f7144113fa4e938e\"\n\tpySigStrCanonize := \"N/GOa7/m3HU8/gpLJ88VCQ6vXsdrfiiYcqnNtF+c2N9VG9ZIiycykN4hdbpbOCGrChMYZQA3G1GpozsShrUBgg==\"\n\n\taddressFromPublicKey, _ := FetchAIAddressFromPublicKey(publicKey)\n\tif address != addressFromPublicKey {\n\t\tt.Error(\"[ERR] Addresses don't match\")\n\t} else {\n\t\tt.Log(\"[OK] Agent address matches its public key\")\n\t}\n\n\tvalid, err := VerifyFetchAISignatureBTC(\n\t\t[]byte(peerPublicKey),\n\t\tpySigStrCanonize,\n\t\tpublicKey,\n\t)\n\tif !valid {\n\t\tt.Errorf(\"Signature using BTC don't match %s\", err.Error())\n\t}\n\tvalid, err = VerifyFetchAISignatureLibp2p(\n\t\t[]byte(peerPublicKey),\n\t\tpySigStrCanonize,\n\t\tpublicKey,\n\t)\n\tif !valid {\n\t\tt.Errorf(\"Signature using LPP don't match %s\", err.Error())\n\t}\n}\n\nfunc TestSetLoggerLevel(t *testing.T) {\n\tassert.Equal(t, logger.GetLevel(), zerolog.Level(0), \"Initial log level is not 0\")\n\n\tlvl := zerolog.InfoLevel\n\tSetLoggerLevel(lvl)\n\n\tassert.Equal(\n\t\tt,\n\t\tlogger.GetLevel(),\n\t\tlvl,\n\t\t\"Waited for logger level %d but got %d\",\n\t\tlvl,\n\t\tlogger.GetLevel(),\n\t)\n}\n\nfunc Example_ignore() {\n\tignore(errors.New(\"Test\"))\n\t// Output: IGNORED: Test\n}\n\nfunc TestNewDefaultLoggerWithFields(t *testing.T) {\n\tfields := map[string]string{\n\t\t\"test_field\": \"test_value\",\n\t}\n\tvar logBuffer bytes.Buffer\n\tlogger := NewDefaultLoggerWithFields(fields).Output(&logBuffer)\n\tlogger.Info().Msg(\"test\")\n\tvar jsonResult map[string]interface{}\n\terr := json.Unmarshal(logBuffer.Bytes(), &jsonResult)\n\tassert.Equal(t, nil, err)\n\tassert.Equal(t, jsonResult[\"test_field\"], \"test_value\")\n}\n\nfunc TestComputeCID(t *testing.T) {\n\taddress := \"fetch19dq2mkcpp6x0aypxt9c9gz6n4fqvax0x9a7t5r\"\n\tcid, err := ComputeCID(address)\n\tassert.Equal(t, nil, err)\n\tassert.Equal(t, \"QmZ6ryKyS9rSnesX8YnFLAmFwFuRMdHpE7pQ2V6SjXTbqM\", cid.String())\n}\n\nfunc TestWriteBytes(t *testing.T) {\n\tmockCtrl := gomock.NewController(t)\n\tdefer mockCtrl.Finish()\n\tmockStream := mocks.NewMockStream(mockCtrl)\n\tmockStream.EXPECT().Write([]byte{0, 0, 0, 5, 104, 101, 108, 108, 111}).Return(9, nil).Times(1)\n\terr := WriteBytes(mockStream, []byte(\"hello\"))\n\tassert.Equal(t, nil, err)\n\n\tmockStream.EXPECT().\n\t\tWrite([]byte{0, 0, 0, 4, 104, 101, 108, 108}).\n\t\tReturn(8, errors.New(\"oops\")).\n\t\tTimes(1)\n\terr = WriteBytes(mockStream, []byte(\"hell\"))\n\tassert.NotEqual(t, err, nil)\n}\n\nfunc TestReadBytesConn(t *testing.T) {\n\tmockCtrl := gomock.NewController(t)\n\tdefer mockCtrl.Finish()\n\tmockConn := mocks.NewMockConn(mockCtrl)\n\tmockConn.EXPECT().Read(gomock.Any()).Return(4, nil).Times(2)\n\tbuf, err := ReadBytesConn(mockConn)\n\tassert.Equal(t, nil, err)\n\tassert.Equal(t, \"\", string(buf))\n}\n\nfunc TestWriteBytesConn(t *testing.T) {\n\tmockCtrl := gomock.NewController(t)\n\tdefer mockCtrl.Finish()\n\tmockConn := mocks.NewMockConn(mockCtrl)\n\tmockConn.EXPECT().Write(gomock.Any()).Return(0, nil).Times(1)\n\terr := WriteBytesConn(mockConn, []byte(\"ABC\"))\n\tassert.Equal(t, nil, err)\n}\n\nfunc TestReadWriteEnvelopeFromConnection(t *testing.T) {\n\tmockCtrl := gomock.NewController(t)\n\tdefer mockCtrl.Finish()\n\tdefer monkey.UnpatchAll()\n\taddress := \"0xb8d8c62d4a1999b7aea0aebBD5020244a4a9bAD8\"\n\tbuffer := bytes.NewBuffer([]byte{})\n\tmockConn := mocks.NewMockConn(mockCtrl)\n\n\tt.Run(\"TestWriteEnvelope\", func(t *testing.T) {\n\t\tmonkey.PatchInstanceMethod(\n\t\t\treflect.TypeOf(mockConn),\n\t\t\t\"Write\",\n\t\t\tfunc(_ *mocks.MockConn, b []byte) (int, error) {\n\t\t\t\tbuffer.Write(b)\n\t\t\t\treturn 0, nil\n\t\t\t},\n\t\t)\n\n\t\terr := WriteEnvelopeConn(mockConn, &aea.Envelope{\n\t\t\tTo:     address,\n\t\t\tSender: address,\n\t\t})\n\t\tassert.Equal(t, nil, err)\n\t\tassert.NotEqual(t, 0, buffer)\n\t})\n\n\tt.Run(\"TestReadEnvelope\", func(t *testing.T) {\n\t\tmonkey.Patch(ReadBytesConn, func(conn net.Conn) ([]byte, error) {\n\t\t\treturn buffer.Bytes()[4:], nil\n\t\t})\n\t\tenv, err := ReadEnvelopeConn(mockConn)\n\t\tassert.Equal(t, nil, err)\n\t\tassert.Equal(t, address, env.To)\n\t})\n}\n\nfunc TestGetPeersAddrInfo(t *testing.T) {\n\taddrs, err := GetPeersAddrInfo(\n\t\t[]string{\n\t\t\t\"/dns4/acn.fetch.ai/tcp/9001/p2p/16Uiu2HAmVWnopQAqq4pniYLw44VRvYxBUoRHqjz1Hh2SoCyjbyRW\",\n\t\t},\n\t)\n\tassert.Equal(t, nil, err)\n\tassert.Equal(t, 1, len(addrs))\n}\n\nfunc TestFetchAIPublicKeyFromPubKey(t *testing.T) {\n\t//(publicKey crypto.PubKey) (string, error) {\n\t_, pubKey, err := KeyPairFromFetchAIKey(\n\t\t\"3e7a1f43b2d8a4b9f63a2ffeb1d597f971a8db7ffd95453173268b453106cadc\",\n\t)\n\tassert.Equal(t, nil, err)\n\tkey, err := FetchAIPublicKeyFromPubKey(pubKey)\n\tassert.Equal(t, nil, err)\n\tassert.Equal(t, \"03b7e977f498dce004e2614764ff576e17cc6691135497e7bcb5d3441e816ba9e1\", key)\n}\n\nfunc TestIDFromFetchAIPublicKey(t *testing.T) {\n\t_, pubKey, err := KeyPairFromFetchAIKey(\n\t\t\"3e7a1f43b2d8a4b9f63a2ffeb1d597f971a8db7ffd95453173268b453106cadc\",\n\t)\n\tassert.Equal(t, nil, err)\n\tkey, err := FetchAIPublicKeyFromPubKey(pubKey)\n\tassert.Equal(t, nil, err)\n\tpeerID, err := IDFromFetchAIPublicKey(key)\n\tassert.Equal(t, nil, err)\n\tassert.NotEqual(t, 0, len(peerID))\n}\n\nfunc TestAgentAddressFromPublicKey(t *testing.T) {\n\taddress, err := AgentAddressFromPublicKey(\n\t\t\"fetchai\",\n\t\t\"3e7a1f43b2d8a4b9f63a2ffeb1d597f971a8db7ffd95453173268b453106cadc\",\n\t)\n\tassert.Equal(t, nil, err)\n\tassert.NotEqual(t, 0, len(address))\n}\n\nfunc TestCosmosAddressFromPublicKey(t *testing.T) {\n\taddress, err := CosmosAddressFromPublicKey(\n\t\t\"3e7a1f43b2d8a4b9f63a2ffeb1d597f971a8db7ffd95453173268b453106cadc\",\n\t)\n\tassert.Equal(t, nil, err)\n\tassert.NotEqual(t, 0, len(address))\n}\n\nfunc TestFetchAIPublicKeyFromFetchAIPrivateKey(t *testing.T) {\n\tkey, err := FetchAIPublicKeyFromFetchAIPrivateKey(\n\t\t\"3e7a1f43b2d8a4b9f63a2ffeb1d597f971a8db7ffd95453173268b453106cadc\",\n\t)\n\tassert.Equal(t, nil, err)\n\tassert.Equal(t, \"03b7e977f498dce004e2614764ff576e17cc6691135497e7bcb5d3441e816ba9e1\", key)\n}\n\nfunc TestIDFromFetchAIPublicKeyUncompressed(t *testing.T) {\n\t//bad pub key\n\t_, err := IDFromFetchAIPublicKeyUncompressed(\"some\")\n\tassert.NotEqual(t, nil, err)\n\t// good pub key\n\tid, err := IDFromFetchAIPublicKeyUncompressed(\n\t\t\"50863AD64A87AE8A2FE83C1AF1A8403CB53F53E486D8511DAD8A04887E5B23522CD470243453A299FA9E77237716103ABC11A1DF38855ED6F2EE187E9C582BA6\",\n\t)\n\tassert.Equal(t, nil, err)\n\tassert.Equal(\n\t\tt,\n\t\tpeer.ID(\n\t\t\t\"\\x00%\\b\\x02\\x12!\\x02P\\x86:\\xd6J\\x87\\xae\\x8a/\\xe8<\\x1a\\xf1\\xa8@<\\xb5?S\\xe4\\x86\\xd8Q\\x1d\\xad\\x8a\\x04\\x88~[#R\",\n\t\t),\n\t\tid,\n\t)\n}\n\nfunc TestSignFetchAI(t *testing.T) {\n\tprivKey := \"3e7a1f43b2d8a4b9f63a2ffeb1d597f971a8db7ffd95453173268b453106cadc\"\n\tmessage := []byte(\"somebytes\")\n\n\t_, pubKey, err := KeyPairFromFetchAIKey(privKey)\n\tassert.Equal(t, nil, err)\n\tfetchPubKey, err := FetchAIPublicKeyFromPubKey(pubKey)\n\tassert.Equal(t, nil, err)\n\n\tsignature, err := SignFetchAI(message, privKey)\n\tassert.Equal(t, nil, err)\n\tassert.NotEqual(t, 0, len(signature))\n\n\tisValid, err := VerifyLedgerSignature(\"fetchai\", message, signature, fetchPubKey)\n\tassert.Equal(t, nil, err)\n\tassert.Equal(t, true, isValid)\n\n}\n\nfunc TestBootstrapConnect(t *testing.T) {\n\tctx := context.Background()\n\tmockCtrl := gomock.NewController(t)\n\tdefer mockCtrl.Finish()\n\tdefer monkey.UnpatchAll()\n\tvar ipfsdht *dht.IpfsDHT\n\tvar routingTable *kb.RoutingTable\n\n\tmockPeerstore := mocks.NewMockPeerstore(mockCtrl)\n\tpeers := make([]peer.AddrInfo, 2)\n\tvar addrs []ma.Multiaddr\n\tpeers[0] = peer.AddrInfo{ID: peer.ID(\"peer1\"), Addrs: addrs}\n\tpeers[1] = peer.AddrInfo{ID: peer.ID(\"peer2\"), Addrs: addrs}\n\n\tmockHost := mocks.NewMockHost(mockCtrl)\n\n\tmockHost.EXPECT().ID().Return(peer.ID(\"host_id\")).Times(2)\n\tmockHost.EXPECT().Peerstore().Return(mockPeerstore).Times(2)\n\tmockHost.EXPECT().Connect(gomock.Any(), gomock.Any()).Return(nil).Times(2)\n\tmockPeerstore.EXPECT().AddAddrs(gomock.Any(), gomock.Any(), gomock.Any()).Return().Times(2)\n\n\tt.Run(\"TestOk\", func(t *testing.T) {\n\t\tmonkey.PatchInstanceMethod(\n\t\t\treflect.TypeOf(routingTable),\n\t\t\t\"Find\",\n\t\t\tfunc(_ *kb.RoutingTable, _ peer.ID) peer.ID {\n\t\t\t\treturn peer.ID(\"som peer\")\n\t\t\t},\n\t\t)\n\t\tmonkey.PatchInstanceMethod(\n\t\t\treflect.TypeOf(ipfsdht),\n\t\t\t\"RoutingTable\",\n\t\t\tfunc(_ *dht.IpfsDHT) *kb.RoutingTable {\n\t\t\t\treturn routingTable\n\t\t\t},\n\t\t)\n\n\t\terr := BootstrapConnect(ctx, mockHost, ipfsdht, peers)\n\t\tassert.Equal(t, nil, err)\n\t})\n\n\tmockHost = mocks.NewMockHost(mockCtrl)\n\n\tmockHost.EXPECT().ID().Return(peer.ID(\"host_id\")).Times(2)\n\tmockHost.EXPECT().Peerstore().Return(mockPeerstore).Times(2)\n\tmockHost.EXPECT().Connect(gomock.Any(), gomock.Any()).Return(nil).Times(2)\n\tmockPeerstore.EXPECT().AddAddrs(gomock.Any(), gomock.Any(), gomock.Any()).Return().Times(2)\n\n\tt.Run(\"Test_PeersNotAdded\", func(t *testing.T) {\n\t\tmonkey.PatchInstanceMethod(\n\t\t\treflect.TypeOf(routingTable),\n\t\t\t\"Find\",\n\t\t\tfunc(_ *kb.RoutingTable, _ peer.ID) peer.ID {\n\t\t\t\treturn peer.ID(\"\")\n\t\t\t},\n\t\t)\n\t\tmonkey.PatchInstanceMethod(\n\t\t\treflect.TypeOf(ipfsdht),\n\t\t\t\"RoutingTable\",\n\t\t\tfunc(_ *dht.IpfsDHT) *kb.RoutingTable {\n\t\t\t\treturn routingTable\n\t\t\t},\n\t\t)\n\n\t\terr := BootstrapConnect(ctx, mockHost, ipfsdht, peers)\n\t\tassert.NotEqual(t, nil, err)\n\t\tassert.Contains(t, err.Error(), \"timeout: entry peer haven't been added to DHT\")\n\t})\n\n\tmockHost = mocks.NewMockHost(mockCtrl)\n\n\tmockHost.EXPECT().ID().Return(peer.ID(\"host_id\")).Times(2)\n\tmockHost.EXPECT().Peerstore().Return(mockPeerstore).Times(2)\n\tmockHost.EXPECT().Connect(gomock.Any(), gomock.Any()).Return(errors.New(\"some error\")).Times(2)\n\tmockPeerstore.EXPECT().AddAddrs(gomock.Any(), gomock.Any(), gomock.Any()).Return().Times(2)\n\n\tt.Run(\"Test_PeersNotConnected\", func(t *testing.T) {\n\t\tmonkey.PatchInstanceMethod(\n\t\t\treflect.TypeOf(routingTable),\n\t\t\t\"Find\",\n\t\t\tfunc(_ *kb.RoutingTable, _ peer.ID) peer.ID {\n\t\t\t\treturn peer.ID(\"\")\n\t\t\t},\n\t\t)\n\t\tmonkey.PatchInstanceMethod(\n\t\t\treflect.TypeOf(ipfsdht),\n\t\t\t\"RoutingTable\",\n\t\t\tfunc(_ *dht.IpfsDHT) *kb.RoutingTable {\n\t\t\t\treturn routingTable\n\t\t\t},\n\t\t)\n\n\t\terr := BootstrapConnect(ctx, mockHost, ipfsdht, peers)\n\t\tassert.NotEqual(t, nil, err)\n\t\tassert.Equal(t, \"failed to bootstrap: some error\", err.Error())\n\t})\n\n}\n"
  },
  {
    "path": "mkdocs.yml",
    "content": "site_name: AEA Framework Documentation\nsite_url: https://docs.fetch.ai/aea\nsite_description: Everything you need to know about the Autonomous Economic Agents.\nrepo_url: https://github.com/fetchai/agents-aea\nrepo_name: fetchai/agents-aea\nedit_uri: \"\"\nsite_author: developer@fetch.ai\ncopyright: Copyright &copy; 2018 - 2023 Fetch.ai # Copyright notice in footer\n\nstrict: true\n\nnav:\n  - AEA Overview:\n    - Overview: 'index.md'\n    - Autonomous Economic Agents: 'aeas.md'\n    - Application areas: 'application.md'\n    - Agent ecosystem: 'ecosystem.md'\n  - Installation and setup:\n    - Installation: 'install.md'\n    - Setting up: 'setup.md'\n    - Development setup: 'development-setup.md'\n    - Upgrading: 'upgrading.md'\n    - Build an AEA on a Raspberry Pi: 'raspberry-set-up.md'\n  - Getting started:\n    - Core components: 'core-components.md'\n    - Ways to build an AEA: 'step-one.md'\n    - Build an AEA with the CLI: 'build-aea-step-by-step.md'\n  - Architecture deep dives:\n    - Language Agnostic Definition: 'language-agnostic-definition.md'\n    - Architectural diagram: 'diagram.md'\n    - Core components - Part 1: 'core-components-1.md'\n    - Core components - Part 2: 'core-components-2.md'\n    - Comparisons:\n      - AEA and web frameworks: 'aea-vs-mvc.md'\n      - 12-Factor app and AEAs: '12-factor.md'\n      - Design principles: 'design-principles.md'\n  - Developing Agents:\n    - Modes of running an AEA: 'modes.md'\n    - Multi agent manager: 'multi-agent-manager.md'\n    - Logging: 'logging.md'\n    - Deployment: 'deployment.md'\n    - Debugging: 'debug.md'\n    - Profiling: 'runtime-cost.md'\n    - Performance benchmark: 'performance-benchmark.md'\n    - Security Considerations: 'security.md'\n  - Developing Packages:\n    - File structure: 'package-imports.md'\n    - Scaffolding packages: 'scaffolding.md'\n    - Configurations: 'config.md'\n    - Skills:\n      - Skills: 'skill.md'\n      - AEA quick start: 'quickstart.md'\n      - Build your first skill - search & discovery: 'skill-guide.md'\n      - Trade between two AEAs: 'generic-skills-step-by-step.md'\n      - Testing Skills: 'skill-testing.md'\n    - Protocols:\n      - Protocols: 'protocol.md'\n      - Message routing: 'message-routing.md'\n      - Generating protocols: 'protocol-generator.md'\n    - Connections:\n      - Connections: 'connection.md'\n    - Contracts:\n      - Contracts: 'contract.md'\n      - Contract deploy and interact: 'erc1155-skills.md'\n    - Decision Maker:\n      - Decision Maker: 'decision-maker.md'\n    - Ledger & Crypto APIs:\n      - Ledger & Crypto APIs: 'ledger-integration.md'\n  - Ecosystem:\n    - Agent Communication:\n      - Agent Communication Network: 'acn.md'\n      - ACN Internals: 'acn-internals.md'\n      - Proof of Representation: 'por.md'\n      - P2P Connection: 'p2p-connection.md'\n    - Search & Discovery:\n      - Simple OEF: 'simple-oef.md'\n      - Defining Data Models: 'defining-data-models.md'\n      - The Query Language: 'query-language.md'\n      - SOEF Connection: 'simple-oef-usage.md'\n    - Integrations:\n      - Front-end integration: 'connect-a-frontend.md'\n      - ORM integration: 'orm-integration.md'\n      - Generic Storage: 'generic-storage.md'\n      - Prometheus monitoring: 'prometheus.md'\n      - Generating wealth: 'wealth.md'\n  - Guides:\n    - Agent-oriented development: 'agent-oriented-development.md'\n    - Interaction protocols: 'interaction-protocol.md'\n    - Concepts:\n      - Identity: 'identity.md'\n      - Trust minimisation: 'trust.md'\n  - Development - Advanced:\n    - Build an AEA programmatically: 'build-aea-programmatically.md'\n    - CLI vs programmatic AEAs: 'cli-vs-programmatic-aeas.md'\n    - AEAs vs agents: 'agent-vs-aea.md'\n    - Use multiplexer stand-alone: 'multiplexer-standalone.md'\n    - Create stand-alone transaction: 'standalone-transaction.md'\n    - Create decision-maker transaction: 'decision-maker-transaction.md'\n  - Demos:\n    - Demos: 'demos.md'\n    - Generic skills: 'generic-skills.md'\n    - HTTP Connection: 'http-connection-and-skill.md'\n    - Aries Cloud Agents Demo: 'aries-cloud-agent-demo.md'\n    - Car park skills: 'car-park-skills.md'\n    - Gym example: 'gym-example.md'\n    - Gym skill: 'gym-skill.md'\n    - ML skills: 'ml-skills.md'\n    - Oracle skills: 'oracle-demo.md'\n    - Aggregation skill: 'aggregation-demo.md'\n    - TAC skills: 'tac-skills.md'\n    - TAC skills ledger-based: 'tac-skills-contract.md'\n    - Thermometer skills: 'thermometer-skills.md'\n    - Weather skills: 'weather-skills.md'\n  - Reference:\n    - Command Line Interface: 'cli-commands.md'\n    - API:\n      - AbstractAgent: 'api/abstract_agent.md'\n      - AEA: 'api/aea.md'\n      - AEA Builder: 'api/aea_builder.md'\n      - Agent: 'api/agent.md'\n      - Agent Loop: 'api/agent_loop.md'\n      - Common: 'api/common.md'\n      - Exceptions: 'api/exceptions.md'\n      - Launcher: 'api/launcher.md'\n      - Multiplexer: 'api/multiplexer.md'\n      - Runner: 'api/runner.md'\n      - Runtime: 'api/runtime.md'\n      - Components:\n          - Base: 'api/components/base.md'\n          - Loader: 'api/components/loader.md'\n          - Utils: 'api/components/utils.md'\n      - Configurations:\n          - Base: 'api/configurations/base.md'\n          - Constants: 'api/configurations/constants.md'\n          - Data Types: 'api/configurations/data_types.md'\n          - Loader: 'api/configurations/loader.md'\n          - Manager: 'api/configurations/manager.md'\n          - Pypi: 'api/configurations/pypi.md'\n          - Utils: 'api/configurations/utils.md'\n          - Validation: 'api/configurations/validation.md'\n      - Connections:\n          - Base: 'api/connections/base.md'\n      - Context: 'api/context/base.md'\n      - Contracts:\n          - Base: 'api/contracts/base.md'\n      - Crypto:\n          - Base: 'api/crypto/base.md'\n          - Helpers: 'api/crypto/helpers.md'\n          - LedgerApis: 'api/crypto/ledger_apis.md'\n          - Plugin: 'api/crypto/plugin.md'\n          - Wallet: 'api/crypto/wallet.md'\n          - Registries:\n              - Base: 'api/crypto/registries/base.md'\n      - Decision Maker:\n          - Base: 'api/decision_maker/base.md'\n          - Default: 'api/decision_maker/default.md'\n          - GOP: 'api/decision_maker/gop.md'\n      - Error Handler:\n          - Base: 'api/error_handler/base.md'\n          - Default: 'api/error_handler/default.md'\n      - Helpers:\n          - ACN:\n              - Agent Record: 'api/helpers/acn/agent_record.md'\n              - URI: 'api/helpers/acn/uri.md'\n          - Async Friendly Queue: 'api/helpers/async_friendly_queue.md'\n          - Async Utils: 'api/helpers/async_utils.md'\n          - Base: 'api/helpers/base.md'\n          - Constants: 'api/helpers/constants.md'\n          - Env Vars: 'api/helpers/env_vars.md'\n          - Exception Policy: 'api/helpers/exception_policy.md'\n          - Exec Timeout: 'api/helpers/exec_timeout.md'\n          - File IO: 'api/helpers/file_io.md'\n          - File Lock: 'api/helpers/file_lock.md'\n          - HttpRequests: 'api/helpers/http_requests.md'\n          - Install Dependency: 'api/helpers/install_dependency.md'\n          - IO: 'api/helpers/io.md'\n          - IPFS:\n              - Base: 'api/helpers/ipfs/base.md'\n              - Utils: 'api/helpers/ipfs/utils.md'\n          - Logging: 'api/helpers/logging.md'\n          - MultiAddress:\n              - Base: 'api/helpers/multiaddr/base.md'\n          - MultipleExecutor: 'api/helpers/multiple_executor.md'\n          - Pipe: 'api/helpers/pipe.md'\n          - Preferences:\n              - Base: 'api/helpers/preference_representations/base.md'\n          - Profiling: 'api/helpers/profiling.md'\n          - Search:\n              - Generic: 'api/helpers/search/generic.md'\n              - Models: 'api/helpers/search/models.md'\n          - Serializers: 'api/helpers/serializers.md'\n          - Storage:\n              - GenericStorage: 'api/helpers/storage/generic_storage.md'\n              - Backends:\n                  - Base: 'api/helpers/storage/backends/base.md'\n                  - Sqlite: 'api/helpers/storage/backends/sqlite.md'\n          - Sym Link: 'api/helpers/sym_link.md'\n          - Transaction:\n              - Base: 'api/helpers/transaction/base.md'\n          - Win32: 'api/helpers/win32.md'\n          - YamlUtils: 'api/helpers/yaml_utils.md'\n      - Identity: 'api/identity/base.md'\n      - Mail: 'api/mail/base.md'\n      - Manager:\n          - Manager: 'api/manager/manager.md'\n          - Project: 'api/manager/project.md'\n          - Utils: 'api/manager/utils.md'\n      - Protocols:\n          - Base: 'api/protocols/base.md'\n          - Dialogue:\n              - Base: 'api/protocols/dialogue/base.md'\n          - Generator:\n              - Base: 'api/protocols/generator/base.md'\n              - Common: 'api/protocols/generator/common.md'\n              - Extract Specification: 'api/protocols/generator/extract_specification.md'\n              - Validate: 'api/protocols/generator/validate.md'\n          - Default Protocol:\n              - Custom Types: 'api/protocols/default/custom_types.md'\n              - Dialogues: 'api/protocols/default/dialogues.md'\n              - Message: 'api/protocols/default/message.md'\n              - Serialization: 'api/protocols/default/serialization.md'\n          - Signing Protocol:\n              - Custom Types: 'api/protocols/signing/custom_types.md'\n              - Dialogues: 'api/protocols/signing/dialogues.md'\n              - Message: 'api/protocols/signing/message.md'\n              - Serialization: 'api/protocols/signing/serialization.md'\n          - State Update Protocol:\n              - Dialogues: 'api/protocols/state_update/dialogues.md'\n              - Message: 'api/protocols/state_update/message.md'\n              - Serialization: 'api/protocols/state_update/serialization.md'\n      - Registries:\n          - Base: 'api/registries/base.md'\n          - Filter: 'api/registries/filter.md'\n          - Resources: 'api/registries/resources.md'\n      - Skills:\n          - Base: 'api/skills/base.md'\n          - Behaviors: 'api/skills/behaviours.md'\n          - Task: 'api/skills/tasks.md'\n      - Test Tools:\n          - Constants: 'api/test_tools/constants.md'\n          - Exceptions: 'api/test_tools/exceptions.md'\n          - Generic: 'api/test_tools/generic.md'\n          - Test Cases: 'api/test_tools/test_cases.md'\n          - Test Contract: 'api/test_tools/test_contract.md'\n          - Test Skill: 'api/test_tools/test_skill.md'\n      - Plugins:\n          - CLI:\n              - IPFS:\n                  - API: 'api/plugins/aea_cli_ipfs/core.md'\n                  - Utils: 'api/plugins/aea_cli_ipfs/ipfs_utils.md'\n          - Ledger:\n              - Cosmos:\n                  - API: 'api/plugins/aea_ledger_cosmos/cosmos.md'\n              - Ethereum:\n                  - API: 'api/plugins/aea_ledger_ethereum/ethereum.md'\n              - Fetchai:\n                  - API: 'api/plugins/aea_ledger_fetchai/fetchai.md'\n                  - Helper: 'api/plugins/aea_ledger_fetchai/_cosmos.md'\n  - Limitations of v1: 'limits.md'\n  - Known limitations: 'known-limits.md'\n  - Glossary: 'glossary.md'\n  - Q&A: 'questions-and-answers.md'\n  - Archives:\n      - TAC external app: 'tac.md'\n\ntheme:\n  name: material\n  language: en\n  palette: # Set light/dark theme button next to the search bar\n    - media: \"(prefers-color-scheme: light)\"\n      scheme: default\n      toggle:\n        icon: material/weather-night\n        name: Switch to dark mode\n    - media: \"(prefers-color-scheme: dark)\"\n      scheme: slate\n      toggle:\n        icon: material/weather-sunny\n        name: Switch to light mode\n  logo: assets/images/logo.png  # Set Fetch Logo top left\n  favicon: assets/images/favicon.ico  # Set Fetch favicon\n  icon:\n    repo: fontawesome/brands/github\n  features:\n    - navigation.instant # Fast page loading\n    - navigation.tracking # URL automatically updated with the currently active anchor\n#    - navigation.tabs\n#    - navigation.tabs.sticky\n#    - navigation.sections\n#    - navigation.expand\n#    - navigation.indexes\n    - navigation.top # Back-to-top button\n    - navigation.footer # Add links to the previous and next page of the current page\n    - search.suggest # Completion for the searched word (can be accepted with ->).\n    - search.highlight # Highlight all occurrences after following a search result link\n    - search.share # Show share button for copying deep link to the current search query and result\n    - toc.follow # Follow the table of content\n    - content.action.view # Shows button to \"view the source of this page\"\n    - content.code.copy # Shows a button next to code blocks to copy the code into clipboard\n#  custom_dir: docs/overrides # Uncomment to enable announcements bar at the top\n\nextra_css:\n    - css/my-styles.css\n    - css/admonitions.css\n\nmarkdown_extensions:\n  - admonition # Required by admonitions\n  - pymdownx.superfences: # Required by admonitions, annotations, tabs. Enables arbitrary nesting of code and content blocks\n      custom_fences:\n        - name: mermaid\n          class: mermaid\n          format: !!python/name:pymdownx.superfences.fence_code_format\n  - pymdownx.highlight: # Required by code blocks\n      anchor_linenums: true\n  - pymdownx.inlinehilite # Required by code blocks\n  - pymdownx.snippets # Required by code blocks\n  - pymdownx.superfences # Required by admonitions, code blocks\n  - pymdownx.details # Required by admonitions, code blocks\n  - attr_list # Required by annotations\n  - md_in_html # Required by annotations\n  - pymdownx.tabbed: # Required by tabs\n      alternate_style: true\n  - tables # # Required by tables\n  - toc:\n        permalink: true\n  - def_list\n\nplugins:\n  - search # Enables search\n\nextra:\n  social:\n    - icon: fontawesome/brands/twitter\n      link: https://bit.ly/3oDuI3f\n      name: fetch.ai on twitter\n    - icon: fontawesome/brands/telegram\n      link: https://t.me/fetch_ai\n      name: fetch.ai on telegram\n    - icon: fontawesome/brands/discord\n      link: https://bit.ly/3ra5uMI\n      name: fetch.ai on discord\n    - icon: fontawesome/brands/github\n      link: https://bit.ly/3AFCWxl\n      name: fetch.ai on github\n    - icon: fontawesome/brands/reddit\n      link: https://bit.ly/30zS1Tg\n      name: fetch.ai on reddit\n    - icon: fontawesome/brands/youtube\n      link: https://bit.ly/3DxFazs\n      name: fetch.ai on youtube\n    - icon: fontawesome/brands/linkedin\n      link: https://bit.ly/3kNO70p\n      name: fetch.ai on linkedin"
  },
  {
    "path": "packages/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Package registry for the AEA framework.\"\"\"\n"
  },
  {
    "path": "packages/fetchai/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Packages authored by 'fetchai'.\"\"\"\n"
  },
  {
    "path": "packages/fetchai/agents/aries_alice/README.md",
    "content": "# Aries Alice\n\nThis agent represents the Alice actor in <a href=\"https://github.com/hyperledger/aries-cloudagent-python/blob/master/demo/README.md\" target=\"_blank\">this demo</a>.\n\n## Description\n\nThis agent is part of the Fetch.ai Aries demo. It simulates the Alice actor of the demo linked above. It uses its primary skill, the `fetchai/aries_alice` skill, to do the following:\n\n- Registers Alice on the `SOEF` service.\n- On receiving an invitation details from Faber AEA (see `fetchai/aries_faber` agent), it connects with an underlying Aries Cloud Agent (ACA) instance and executes an `accept-invitation` command.\n\n## Links\n\n- <a href=\"https://docs.fetch.ai/aea/aries-cloud-agent-demo/\" target=\"_blank\">AEA Aries Demo</a>\n- <a href=\"https://github.com/hyperledger/aries-cloudagent-python/blob/master/demo/README.md\" target=\"_blank\">Hyperledger Demo</a>\n"
  },
  {
    "path": "packages/fetchai/agents/aries_alice/aea-config.yaml",
    "content": "agent_name: aries_alice\nauthor: fetchai\nversion: 0.32.5\ndescription: An AEA representing Alice in the Aries demo.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint: {}\nfingerprint_ignore_patterns: []\nconnections:\n- fetchai/http_client:0.24.6\n- fetchai/p2p_libp2p:0.27.5\n- fetchai/soef:0.27.6\n- fetchai/webhook:0.20.6\ncontracts: []\nprotocols:\n- fetchai/default:1.1.7\n- fetchai/http:1.1.7\n- fetchai/oef_search:1.1.7\n- fetchai/signing:1.1.7\n- fetchai/state_update:1.1.7\nskills:\n- fetchai/aries_alice:0.26.6\ndefault_connection: fetchai/p2p_libp2p:0.27.5\ndefault_ledger: fetchai\nrequired_ledgers:\n- fetchai\nlogging_config:\n  disable_existing_loggers: false\n  version: 1\nprivate_key_paths: {}\ndefault_routing:\n  fetchai/http:1.1.7: fetchai/http_client:0.24.6\n  fetchai/oef_search:1.1.7: fetchai/soef:0.27.6\nconnection_private_key_paths: {}\ndependencies:\n  aea-ledger-fetchai:\n    version: <2.0.0,>=1.0.0\n"
  },
  {
    "path": "packages/fetchai/agents/aries_faber/README.md",
    "content": "# Aries Faber\n\nThis agent represents the Faber actor in <a href=\"https://github.com/hyperledger/aries-cloudagent-python/blob/master/demo/README.md\" target=\"_blank\">this demo</a>.\n\n## Description\n\nThis agent is part of the Fetch.ai Aries demo. It simulates the Faber actor of the demo linked above. It uses its primary skill, the `fetchai/aries_faber` skill, to do the following:\n\n- Register a decentralised ID on a ledger.\n- Connects with an underlying Aries Cloud Agent (ACA) instance, and forwards the following instructions:\n  - Register schema definition\n  - Register credential definition\n  - Create an invitation\n\nIt then sends the invitation detail to the Alice agent (see `fetchai/aries_alice` agent) it finds via the `SOEF` service.\n\n## Links\n\n- <a href=\"https://docs.fetch.ai/aea/aries-cloud-agent-demo/\" target=\"_blank\">AEA Aries Demo</a>\n- <a href=\"https://github.com/hyperledger/aries-cloudagent-python/blob/master/demo/README.md\" target=\"_blank\">Hyperledger Demo</a>\n"
  },
  {
    "path": "packages/fetchai/agents/aries_faber/aea-config.yaml",
    "content": "agent_name: aries_faber\nauthor: fetchai\nversion: 0.32.5\ndescription: An AEA representing Faber in the Aries demo.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint: {}\nfingerprint_ignore_patterns: []\nconnections:\n- fetchai/http_client:0.24.6\n- fetchai/p2p_libp2p:0.27.5\n- fetchai/soef:0.27.6\n- fetchai/webhook:0.20.6\ncontracts: []\nprotocols:\n- fetchai/default:1.1.7\n- fetchai/http:1.1.7\n- fetchai/oef_search:1.1.7\n- fetchai/signing:1.1.7\n- fetchai/state_update:1.1.7\nskills:\n- fetchai/aries_faber:0.24.5\ndefault_connection: fetchai/p2p_libp2p:0.27.5\ndefault_ledger: fetchai\nrequired_ledgers:\n- fetchai\nlogging_config:\n  disable_existing_loggers: false\n  version: 1\nprivate_key_paths: {}\ndefault_routing:\n  fetchai/http:1.1.7: fetchai/http_client:0.24.6\n  fetchai/oef_search:1.1.7: fetchai/soef:0.27.6\nconnection_private_key_paths: {}\ndependencies:\n  aea-ledger-fetchai:\n    version: <2.0.0,>=1.0.0\n"
  },
  {
    "path": "packages/fetchai/agents/car_data_buyer/README.md",
    "content": "# Car Park Client\n\nThis agent purchases information on available car parking spaces in a vicinity.\n\n## Description\n\nThis agent is part of the Fetch.ai car park demo. It uses its primary skill, the `fetchai/carpark_client` skill, to find an agent on the `SOEF` service that sells car park availability data in a vicinity.\n\nOnce found, it requests this data, negotiates the price using the `fetchai/fipa` protocol, and if an agreement is reached, pays the proposed amount and receives the data.\n\n## Links\n\n- <a href=\"https://docs.fetch.ai/aea/car-park-skills/\" target=\"_blank\">Car Park Demo</a>\n"
  },
  {
    "path": "packages/fetchai/agents/car_data_buyer/aea-config.yaml",
    "content": "agent_name: car_data_buyer\nauthor: fetchai\nversion: 0.33.5\ndescription: An agent which searches for an instance of a `car_detector` agent and\n  attempts to purchase car park data from it.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint: {}\nfingerprint_ignore_patterns: []\nconnections:\n- fetchai/ledger:0.21.5\n- fetchai/p2p_libp2p:0.27.5\n- fetchai/soef:0.27.6\ncontracts: []\nprotocols:\n- fetchai/default:1.1.7\n- fetchai/fipa:1.1.7\n- fetchai/ledger_api:1.1.7\n- fetchai/oef_search:1.1.7\n- fetchai/signing:1.1.7\n- fetchai/state_update:1.1.7\nskills:\n- fetchai/carpark_client:0.27.6\n- fetchai/generic_buyer:0.27.6\ndefault_connection: fetchai/p2p_libp2p:0.27.5\ndefault_ledger: fetchai\nrequired_ledgers:\n- fetchai\nlogging_config:\n  disable_existing_loggers: false\n  version: 1\nprivate_key_paths: {}\ndefault_routing:\n  fetchai/ledger_api:1.1.7: fetchai/ledger:0.21.5\n  fetchai/oef_search:1.1.7: fetchai/soef:0.27.6\nconnection_private_key_paths: {}\ndependencies:\n  aea-ledger-fetchai:\n    version: <2.0.0,>=1.0.0\n"
  },
  {
    "path": "packages/fetchai/agents/car_detector/README.md",
    "content": "# Car Park Detector\n\nThis agent sells information on the number of car parking spaces available in a given vicinity.\n\n## Description\n\nThis agent is part of the Fetch.ai car park demo. It uses its primary skill, the `fetchai/carpark_detection` skill, to register its car park availability data selling service on the `SOEF`. It can then be contacted by another agent (for example the `fetchai/carpark_client` agent) to provide its data.\n\nOnce such a request is made, this agent negotiates the terms of trade using the `fetchai/fipa` protocol, and if an agreement is reached, it delivers the data after receiving payment.\n\n## Links\n\n- <a href=\"https://docs.fetch.ai/aea/car-park-skills/\" target=\"_blank\">Car Park Demo</a>\n"
  },
  {
    "path": "packages/fetchai/agents/car_detector/aea-config.yaml",
    "content": "agent_name: car_detector\nauthor: fetchai\nversion: 0.32.5\ndescription: An agent which sells car park data to instances of `car_data_buyer` agents.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint: {}\nfingerprint_ignore_patterns: []\nconnections:\n- fetchai/ledger:0.21.5\n- fetchai/p2p_libp2p:0.27.5\n- fetchai/soef:0.27.6\ncontracts: []\nprotocols:\n- fetchai/default:1.1.7\n- fetchai/fipa:1.1.7\n- fetchai/ledger_api:1.1.7\n- fetchai/oef_search:1.1.7\n- fetchai/signing:1.1.7\n- fetchai/state_update:1.1.7\nskills:\n- fetchai/carpark_detection:0.27.6\n- fetchai/generic_seller:0.28.6\ndefault_connection: fetchai/p2p_libp2p:0.27.5\ndefault_ledger: fetchai\nrequired_ledgers:\n- fetchai\nlogging_config:\n  disable_existing_loggers: false\n  version: 1\nprivate_key_paths: {}\ndefault_routing:\n  fetchai/ledger_api:1.1.7: fetchai/ledger:0.21.5\n  fetchai/oef_search:1.1.7: fetchai/soef:0.27.6\nconnection_private_key_paths: {}\ndependencies:\n  aea-ledger-fetchai:\n    version: <2.0.0,>=1.0.0\n"
  },
  {
    "path": "packages/fetchai/agents/coin_price_feed/README.md",
    "content": "# Coin Price Feed AEA\n\nAn agent that fetches a coin price from an API and makes it available by http request.\n\n## Description\n\nThis agent uses the `fetchai/advanced_data_request` skill to fetch a coin price from an API, which is then logged and then made available by http request using the `fetchai/http_server` connection. The agent also exposes the number of price quote retrievals and incoming http requests to a local prometheus server.\n"
  },
  {
    "path": "packages/fetchai/agents/coin_price_feed/aea-config.yaml",
    "content": "agent_name: coin_price_feed\nauthor: fetchai\nversion: 0.15.5\nlicense: Apache-2.0\ndescription: An AEA providing a coin price feed.\naea_version: '>=1.0.0, <2.0.0'\nfingerprint: {}\nfingerprint_ignore_patterns: []\nconnections:\n- fetchai/http_client:0.24.6\n- fetchai/http_server:0.23.6\n- fetchai/prometheus:0.9.6\ncontracts: []\nprotocols:\n- fetchai/default:1.1.7\n- fetchai/http:1.1.7\n- fetchai/prometheus:1.1.7\n- fetchai/signing:1.1.7\n- fetchai/state_update:1.1.7\nskills:\n- fetchai/advanced_data_request:0.7.6\ndefault_connection: fetchai/http_server:0.23.6\ndefault_ledger: fetchai\nrequired_ledgers:\n- fetchai\ndefault_routing:\n  fetchai/http:1.1.7: fetchai/http_client:0.24.6\n  fetchai/prometheus:1.1.7: fetchai/prometheus:0.9.6\nconnection_private_key_paths: {}\nprivate_key_paths: {}\nlogging_config:\n  disable_existing_loggers: false\n  version: 1\ndependencies:\n  aea-ledger-fetchai:\n    version: <2.0.0,>=1.0.0\n---\npublic_id: fetchai/http_server:0.23.6\ntype: connection\nconfig:\n  api_spec_path: vendor/fetchai/skills/advanced_data_request/api_spec.yaml\n  target_skill_id: fetchai/advanced_data_request:0.7.6\n---\npublic_id: fetchai/advanced_data_request:0.7.6\ntype: skill\nmodels:\n  advanced_data_request_model:\n    args:\n      url: https://api.coingecko.com/api/v3/simple/price?ids=fetch-ai&vs_currencies=usd\n      outputs:\n      - name: price\n        json_path: fetch-ai.usd\n      use_http_server: true\n"
  },
  {
    "path": "packages/fetchai/agents/coin_price_oracle/README.md",
    "content": "# Coin Price Oracle AEA\n\nAn agent that fetches a coin price from an API and makes it available by request to an oracle smart contract.\n\n## Description\n\nThis agent uses the `fetchai/simple_oracle` skill to deploy an oracle smart contract to a ledger and updates this contract with the latest value of a coin price fetched using the `fetchai/advanced_data_request` skill.\n"
  },
  {
    "path": "packages/fetchai/agents/coin_price_oracle/aea-config.yaml",
    "content": "agent_name: coin_price_oracle\nauthor: fetchai\nversion: 0.17.6\nlicense: Apache-2.0\ndescription: An AEA providing a coin price oracle service.\naea_version: '>=1.0.0, <2.0.0'\nfingerprint: {}\nfingerprint_ignore_patterns: []\nconnections:\n- fetchai/http_client:0.24.6\n- fetchai/ledger:0.21.5\n- fetchai/prometheus:0.9.6\ncontracts:\n- fetchai/oracle:0.12.3\nprotocols:\n- fetchai/contract_api:1.1.7\n- fetchai/default:1.1.7\n- fetchai/http:1.1.7\n- fetchai/ledger_api:1.1.7\n- fetchai/prometheus:1.1.7\n- fetchai/signing:1.1.7\n- fetchai/state_update:1.1.7\nskills:\n- fetchai/advanced_data_request:0.7.6\n- fetchai/simple_oracle:0.16.5\ndefault_connection: fetchai/ledger:0.21.5\ndefault_ledger: fetchai\nrequired_ledgers:\n- fetchai\ndefault_routing:\n  fetchai/contract_api:1.1.7: fetchai/ledger:0.21.5\n  fetchai/http:1.1.7: fetchai/http_client:0.24.6\n  fetchai/ledger_api:1.1.7: fetchai/ledger:0.21.5\n  fetchai/prometheus:1.1.7: fetchai/prometheus:0.9.6\nconnection_private_key_paths: {}\nprivate_key_paths: {}\nlogging_config:\n  disable_existing_loggers: false\n  version: 1\ndependencies:\n  aea-ledger-fetchai:\n    version: <2.0.0,>=1.0.0\n---\npublic_id: fetchai/advanced_data_request:0.7.6\ntype: skill\nmodels:\n  advanced_data_request_model:\n    args:\n      url: https://api.coingecko.com/api/v3/simple/price?ids=fetch-ai&vs_currencies=usd\n      outputs:\n      - name: price\n        json_path: fetch-ai.usd\n---\npublic_id: fetchai/simple_oracle:0.16.5\ntype: skill\nmodels:\n  strategy:\n    args:\n      ledger_id: fetchai\n      oracle_value_name: price\n      update_function: update_oracle_value\n"
  },
  {
    "path": "packages/fetchai/agents/coin_price_oracle_client/README.md",
    "content": "# Coin Price Oracle Client AEA\n\nAn agent that deploys an oracle client contract that can request a coin price from an oracle contract.\n\n## Description\n\nThis agent uses the `fetchai/simple_oracle_client` skill to deploy an oracle client smart contract to a ledger and periodically calls the contract function that requests the latest value of a coin price from a deployed oracle smart contract.\n"
  },
  {
    "path": "packages/fetchai/agents/coin_price_oracle_client/aea-config.yaml",
    "content": "agent_name: coin_price_oracle_client\nauthor: fetchai\nversion: 0.12.6\nlicense: Apache-2.0\ndescription: An AEA providing a coin price oracle client service.\naea_version: '>=1.0.0, <2.0.0'\nfingerprint: {}\nfingerprint_ignore_patterns: []\nconnections:\n- fetchai/http_client:0.24.6\n- fetchai/ledger:0.21.5\ncontracts:\n- fetchai/fet_erc20:0.9.2\n- fetchai/oracle_client:0.11.3\nprotocols:\n- fetchai/contract_api:1.1.7\n- fetchai/default:1.1.7\n- fetchai/http:1.1.7\n- fetchai/ledger_api:1.1.7\n- fetchai/signing:1.1.7\n- fetchai/state_update:1.1.7\nskills:\n- fetchai/simple_oracle_client:0.13.5\ndefault_connection: fetchai/ledger:0.21.5\ndefault_ledger: fetchai\nrequired_ledgers:\n- fetchai\n- ethereum\ndefault_routing:\n  fetchai/contract_api:1.1.7: fetchai/ledger:0.21.5\n  fetchai/http:1.1.7: fetchai/http_client:0.24.6\n  fetchai/ledger_api:1.1.7: fetchai/ledger:0.21.5\nconnection_private_key_paths: {}\nprivate_key_paths: {}\nlogging_config:\n  disable_existing_loggers: false\n  version: 1\ndependencies:\n  aea-ledger-ethereum:\n    version: <2.0.0,>=1.0.0\n  aea-ledger-fetchai:\n    version: <2.0.0,>=1.0.0\n---\npublic_id: fetchai/simple_oracle_client:0.13.5\ntype: skill\nmodels:\n  strategy:\n    args:\n      ledger_id: fetchai\n      query_function: query_oracle_value\n"
  },
  {
    "path": "packages/fetchai/agents/confirmation_aea_aw1/README.md",
    "content": "# Confirmation AEA AW1\n\nAn agent that manages confirmation of registration for Agent World 1.\n\n## Description\n\nThis agent uses the `fetchai/simple_service_registration` skill to register itself on the sOEF. The `fetchai/confirmation_aw1` skill, is used to handle incoming registration requests, verifying the data contained in them and responding with an outcome (success/error). For successful registrations it transfers test-net wealth to the sender of the request.\n\n## Links\n"
  },
  {
    "path": "packages/fetchai/agents/confirmation_aea_aw1/aea-config.yaml",
    "content": "agent_name: confirmation_aea_aw1\nauthor: fetchai\nversion: 0.20.5\ndescription: This agent manages confirmation of registration for Agent World 1\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint: {}\nfingerprint_ignore_patterns: []\nconnections:\n- fetchai/ledger:0.21.5\n- fetchai/p2p_libp2p:0.27.5\n- fetchai/soef:0.27.6\ncontracts:\n- fetchai/staking_erc20:0.10.3\nprotocols:\n- fetchai/contract_api:1.1.7\n- fetchai/default:1.1.7\n- fetchai/ledger_api:1.1.7\n- fetchai/oef_search:1.1.7\n- fetchai/register:1.1.7\n- fetchai/signing:1.1.7\n- fetchai/state_update:1.1.7\nskills:\n- fetchai/confirmation_aw1:0.15.6\n- fetchai/simple_service_registration:0.23.6\ndefault_connection: fetchai/p2p_libp2p:0.27.5\ndefault_ledger: fetchai\nrequired_ledgers:\n- fetchai\ndefault_routing:\n  fetchai/contract_api:1.1.7: fetchai/ledger:0.21.5\n  fetchai/ledger_api:1.1.7: fetchai/ledger:0.21.5\n  fetchai/oef_search:1.1.7: fetchai/soef:0.27.6\nconnection_private_key_paths: {}\nprivate_key_paths: {}\nlogging_config:\n  disable_existing_loggers: false\n  version: 1\n  formatters:\n    standard:\n      format: '[%(levelname)s]: %(message)s'\n    extra:\n      format: '%(asctime)s [%(levelname)s] %(name)s: %(message)s'\n  handlers:\n    logfile:\n      class: logging.FileHandler\n      formatter: extra\n      level: NOTSET\n      filename: all.log\n    logfile_error:\n      class: logging.FileHandler\n      formatter: extra\n      level: ERROR\n      filename: error.log\n    console:\n      class: logging.StreamHandler\n      formatter: standard\n      level: INFO\n  loggers:\n    aea:\n      handlers:\n      - logfile\n      - logfile_error\n      - console\n      level: DEBUG\n      propagate: false\ndependencies:\n  aea-ledger-ethereum:\n    version: <2.0.0,>=1.0.0\n  aea-ledger-fetchai:\n    version: <2.0.0,>=1.0.0\n---\npublic_id: fetchai/p2p_libp2p:0.27.5\ntype: connection\nconfig:\n  delegate_uri: null\n  public_uri: null\n  entry_peers:\n  - /dns4/acn.fetch.ai/tcp/9001/p2p/16Uiu2HAmVWnopQAqq4pniYLw44VRvYxBUoRHqjz1Hh2SoCyjbyRW\n---\npublic_id: fetchai/soef:0.27.6\ntype: connection\nconfig:\n  chain_identifier: fetchai_v2_testnet_incentivised\n  token_storage_path: /data/soef_key.txt\n---\npublic_id: fetchai/ledger:0.21.5\ntype: connection\nconfig:\n  ledger_apis:\n    ethereum:\n      address: null\n    fetchai:\n      address: https://rest-dorado.fetch.ai:443\n      chain_id: dorado-1\n---\npublic_id: fetchai/simple_service_registration:0.23.6\ntype: skill\nmodels:\n  strategy:\n    args:\n      location:\n        latitude: 51.5194\n        longitude: 0.127\n      service_data:\n        key: registration_service\n        value: aw1-registration\n---\npublic_id: fetchai/confirmation_aw1:0.15.6\ntype: skill\nmodels:\n  registration_db:\n    args:\n      custom_path: /data/registration.db\n  strategy:\n    args:\n      token_dispense_amount: 100000000000000000000\n      awx_aeas: []\n"
  },
  {
    "path": "packages/fetchai/agents/confirmation_aea_aw2/README.md",
    "content": "# Confirmation AEA AW2\n\nAn agent that purchases information from other agents as specified in its configuration. It acts as the confirmation AEA in Agent World 2.\n\n## Description\n\nThis agent uses the `fetchai/confirmation_aw2` skill to purchase data from valid Agent World 2 participants.\n\n## Links\n"
  },
  {
    "path": "packages/fetchai/agents/confirmation_aea_aw2/aea-config.yaml",
    "content": "agent_name: confirmation_aea_aw2\nauthor: fetchai\nversion: 0.18.5\ndescription: This agent purchases information from other agents as specified in its\n  configuration. It acts as the confirmation AEA in Agent World 2.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint: {}\nfingerprint_ignore_patterns: []\nconnections:\n- fetchai/ledger:0.21.5\n- fetchai/p2p_libp2p:0.27.5\n- fetchai/soef:0.27.6\ncontracts: []\nprotocols:\n- fetchai/default:1.1.7\n- fetchai/ledger_api:1.1.7\n- fetchai/oef_search:1.1.7\n- fetchai/signing:1.1.7\n- fetchai/state_update:1.1.7\nskills:\n- fetchai/confirmation_aw2:0.13.6\n- fetchai/generic_buyer:0.27.6\ndefault_connection: fetchai/p2p_libp2p:0.27.5\ndefault_ledger: fetchai\nrequired_ledgers:\n- fetchai\ndefault_routing:\n  fetchai/ledger_api:1.1.7: fetchai/ledger:0.21.5\n  fetchai/oef_search:1.1.7: fetchai/soef:0.27.6\nconnection_private_key_paths: {}\nprivate_key_paths: {}\nlogging_config:\n  disable_existing_loggers: false\n  version: 1\n  formatters:\n    standard:\n      format: '[%(levelname)s]: %(message)s'\n    extra:\n      format: '%(asctime)s [%(levelname)s] %(name)s: %(message)s'\n  handlers:\n    logfile:\n      class: logging.FileHandler\n      formatter: extra\n      level: NOTSET\n      filename: all.log\n    logfile_error:\n      class: logging.FileHandler\n      formatter: extra\n      level: ERROR\n      filename: error.log\n    console:\n      class: logging.StreamHandler\n      formatter: standard\n      level: INFO\n  loggers:\n    aea:\n      handlers:\n      - logfile\n      - logfile_error\n      - console\n      level: DEBUG\n      propagate: false\ndependencies:\n  aea-ledger-ethereum:\n    version: <2.0.0,>=1.0.0\n  aea-ledger-fetchai:\n    version: <2.0.0,>=1.0.0\n---\npublic_id: fetchai/p2p_libp2p:0.27.5\ntype: connection\nconfig:\n  delegate_uri: null\n  public_uri: null\n  entry_peers:\n  - /dns4/acn.fetch.ai/tcp/9001/p2p/16Uiu2HAmVWnopQAqq4pniYLw44VRvYxBUoRHqjz1Hh2SoCyjbyRW\n---\npublic_id: fetchai/soef:0.27.6\ntype: connection\nconfig:\n  chain_identifier: fetchai_v2_testnet_incentivised\n  token_storage_path: /data/soef_key.txt\n---\npublic_id: fetchai/ledger:0.21.5\ntype: connection\nconfig:\n  ledger_apis:\n    ethereum:\n      address: null\n    fetchai:\n      address: https://rest-dorado.fetch.ai:443\n      chain_id: dorado-1\n---\npublic_id: fetchai/confirmation_aw2:0.13.6\ntype: skill\nbehaviours:\n  search:\n    args:\n      search_interval: 30\nmodels:\n  registration_db:\n    args:\n      custom_path: /data/registration.db\n  strategy:\n    args:\n      aw1_aea: null\n      location:\n        latitude: 51.5194\n        longitude: 0.127\n      max_tx_fee: 3550000000000000\n      max_unit_price: 20\n      mininum_hours_between_txs: 4\n      search_query:\n        constraint_type: ==\n        search_key: seller_service\n        search_value: weather_data\n      search_radius: 50.0\n      service_id: weather_data\n"
  },
  {
    "path": "packages/fetchai/agents/confirmation_aea_aw3/README.md",
    "content": "# Confirmation AEA AW3\n\nAn agent that purchases information from other agents as specified in its configuration. It acts as the confirmation AEA in Agent World 3.\n\n## Description\n\nThis agent uses the `fetchai/confirmation_aw3` skill to purchase data from valid Agent World 3 participants.\n\n## Links\n"
  },
  {
    "path": "packages/fetchai/agents/confirmation_aea_aw3/aea-config.yaml",
    "content": "agent_name: confirmation_aea_aw3\nauthor: fetchai\nversion: 0.16.5\ndescription: This agent purchases information from other agents as specified in its\n  configuration. It acts as the confirmation AEA in Agent World 3.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint: {}\nfingerprint_ignore_patterns: []\nconnections:\n- fetchai/http_client:0.24.6\n- fetchai/ledger:0.21.5\n- fetchai/p2p_libp2p:0.27.5\n- fetchai/soef:0.27.6\ncontracts: []\nprotocols:\n- fetchai/contract_api:1.1.7\n- fetchai/default:1.1.7\n- fetchai/fipa:1.1.7\n- fetchai/http:1.1.7\n- fetchai/ledger_api:1.1.7\n- fetchai/oef_search:1.1.7\n- fetchai/signing:1.1.7\n- fetchai/state_update:1.1.7\nskills:\n- fetchai/confirmation_aw3:0.12.6\n- fetchai/generic_buyer:0.27.6\ndefault_connection: fetchai/p2p_libp2p:0.27.5\ndefault_ledger: fetchai\nrequired_ledgers:\n- fetchai\ndefault_routing:\n  fetchai/http:1.1.7: fetchai/http_client:0.24.6\n  fetchai/ledger_api:1.1.7: fetchai/ledger:0.21.5\n  fetchai/oef_search:1.1.7: fetchai/soef:0.27.6\nconnection_private_key_paths: {}\nprivate_key_paths: {}\nlogging_config:\n  disable_existing_loggers: false\n  version: 1\n  formatters:\n    standard:\n      format: '[%(levelname)s]: %(message)s'\n    extra:\n      format: '%(asctime)s [%(levelname)s] %(name)s: %(message)s'\n  handlers:\n    logfile:\n      class: logging.FileHandler\n      formatter: extra\n      level: NOTSET\n      filename: all.log\n    logfile_error:\n      class: logging.FileHandler\n      formatter: extra\n      level: ERROR\n      filename: error.log\n    console:\n      class: logging.StreamHandler\n      formatter: standard\n      level: INFO\n  loggers:\n    aea:\n      handlers:\n      - logfile\n      - logfile_error\n      - console\n      level: DEBUG\n      propagate: false\ndependencies:\n  aea-ledger-ethereum:\n    version: <2.0.0,>=1.0.0\n  aea-ledger-fetchai:\n    version: <2.0.0,>=1.0.0\n---\npublic_id: fetchai/p2p_libp2p:0.27.5\ntype: connection\nconfig:\n  delegate_uri: null\n  public_uri: null\n  entry_peers:\n  - /dns4/acn.fetch.ai/tcp/9001/p2p/16Uiu2HAmVWnopQAqq4pniYLw44VRvYxBUoRHqjz1Hh2SoCyjbyRW\n---\npublic_id: fetchai/soef:0.27.6\ntype: connection\nconfig:\n  chain_identifier: fetchai_v2_testnet_incentivised\n  token_storage_path: /data/soef_key.txt\n---\npublic_id: fetchai/ledger:0.21.5\ntype: connection\nconfig:\n  ledger_apis:\n    ethereum:\n      address: null\n    fetchai:\n      address: https://rest-dorado.fetch.ai:443\n      chain_id: dorado-1\n---\npublic_id: fetchai/confirmation_aw3:0.12.6\ntype: skill\nbehaviours:\n  search:\n    args:\n      search_interval: 900\nmodels:\n  registration_db:\n    args:\n      custom_path: /data/registration.db\n  strategy:\n    args:\n      aw1_aea: null\n      leaderboard_token: null\n      leaderboard_url: null\n      locations:\n        berlin:\n          latitude: 52.52\n          longitude: 13.405\n        london:\n          latitude: 51.5074\n          longitude: -0.1278\n        san_francisco:\n          latitude: 37.7749\n          longitude: -122.4194\n        shanghai:\n          latitude: 31.2304\n          longitude: 121.4737\n        rome:\n          latitude: 41.9028\n          longitude: 12.4964\n        rio_de_janeiro:\n          latitude: -22.9068\n          longitude: -43.1729\n        sydney:\n          latitude: -33.8688\n          longitude: 151.2093\n        delhi:\n          latitude: 28.7041\n          longitude: 77.1025\n        tokyo:\n          latitude: 35.6762\n          longitude: 139.6503\n        mexico_city:\n          latitude: 19.4326\n          longitude: -99.1332\n        cairo:\n          latitude: 30.0444\n          longitude: 31.2357\n        kinshasa:\n          latitude: -4.4419\n          longitude: 15.2663\n      search_queries:\n        weather:\n          constraint_type: ==\n          search_key: seller_service\n          search_value: weather_data\n        mobility:\n          constraint_type: ==\n          search_key: seller_service\n          search_value: mobility_data\n      search_radius: 50.0\n"
  },
  {
    "path": "packages/fetchai/agents/confirmation_aea_aw5/aea-config.yaml",
    "content": "agent_name: confirmation_aea_aw5\nauthor: fetchai\nversion: 0.5.5\nlicense: Apache-2.0\ndescription: This agent manages confirmation of registration for Agent World 5\naea_version: '>=1.0.0, <2.0.0'\nfingerprint: {}\nfingerprint_ignore_patterns: []\nconnections:\n- fetchai/ledger:0.21.5\n- fetchai/p2p_libp2p:0.27.5\n- fetchai/soef:0.27.6\ncontracts:\n- fetchai/staking_erc20:0.10.3\nprotocols:\n- fetchai/contract_api:1.1.7\n- fetchai/default:1.1.7\n- fetchai/ledger_api:1.1.7\n- fetchai/oef_search:1.1.7\n- fetchai/register:1.1.7\n- fetchai/signing:1.1.7\n- fetchai/state_update:1.1.7\nskills:\n- fetchai/confirmation_aw1:0.15.6\n- fetchai/simple_service_registration:0.23.6\ndefault_ledger: fetchai\nrequired_ledgers:\n- fetchai\ndefault_routing:\n  fetchai/contract_api:1.1.7: fetchai/ledger:0.21.5\n  fetchai/ledger_api:1.1.7: fetchai/ledger:0.21.5\n  fetchai/oef_search:1.1.7: fetchai/soef:0.27.6\nconnection_private_key_paths: {}\nprivate_key_paths: {}\nlogging_config:\n  disable_existing_loggers: false\n  version: 1\n  formatters:\n    standard:\n      format: '[%(levelname)s]: %(message)s'\n    extra:\n      format: '%(asctime)s [%(levelname)s] %(name)s: %(message)s'\n  handlers:\n    logfile:\n      class: logging.FileHandler\n      formatter: extra\n      level: NOTSET\n      filename: all.log\n    logfile_error:\n      class: logging.FileHandler\n      formatter: extra\n      level: ERROR\n      filename: error.log\n    console:\n      class: logging.StreamHandler\n      formatter: standard\n      level: INFO\n  loggers:\n    aea:\n      handlers:\n      - logfile\n      - logfile_error\n      - console\n      level: DEBUG\n      propagate: false\ndependencies:\n  aea-ledger-fetchai:\n    version: <2.0.0,>=1.0.0\ndefault_connection: fetchai/p2p_libp2p:0.27.5\n---\npublic_id: fetchai/p2p_libp2p:0.27.5\ntype: connection\nconfig:\n  delegate_uri: null\n  public_uri: null\n  entry_peers:\n  - /dns4/acn.fetch.ai/tcp/9001/p2p/16Uiu2HAmVWnopQAqq4pniYLw44VRvYxBUoRHqjz1Hh2SoCyjbyRW\n---\npublic_id: fetchai/soef:0.27.6\ntype: connection\nconfig:\n  chain_identifier: fetchai_v2_testnet_incentivised\n  token_storage_path: soef_key.txt\n---\npublic_id: fetchai/ledger:0.21.5\ntype: connection\nconfig:\n  ledger_apis:\n    ethereum:\n      address: null\n    fetchai:\n      address: https://rest-dorado.fetch.ai:443\n      chain_id: dorado-1\n---\npublic_id: fetchai/simple_service_registration:0.23.6\ntype: skill\nmodels:\n  strategy:\n    args:\n      location:\n        latitude: 51.5074\n        longitude: -0.1278\n      service_data:\n        key: registration_service\n        value: aw5-registration\n---\npublic_id: fetchai/confirmation_aw1:0.15.6\ntype: skill\nmodels:\n  registration_db:\n    args:\n      custom_path: registration.db\n  strategy:\n    args:\n      developer_handle_only: true\n      token_dispense_amount: 100000000000000000000\n      awx_aeas: []\n"
  },
  {
    "path": "packages/fetchai/agents/erc1155_client/README.md",
    "content": "# ERC1155 Client\n\nAn agent that purchases data via a smart contract.\n\n## Description\n\nThis agent uses its primary skill, the `fetchai/erc1155_client` skill, to find an agent selling data on the `SOEF` service.\n\n Once found, it requests specific data, negotiates the price using the `fetchai/fipa` protocol, and if an agreement is reached, pays the proposed amount via a deployed smart contract and receives the data.\n\n## Links\n\n- <a href=\"https://docs.fetch.ai/aea/erc1155-skills/\" target=\"_blank\">Contract Deployment Guide</a>\n"
  },
  {
    "path": "packages/fetchai/agents/erc1155_client/aea-config.yaml",
    "content": "agent_name: erc1155_client\nauthor: fetchai\nversion: 0.34.5\ndescription: An AEA to interact with the ERC1155 deployer AEA\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint: {}\nfingerprint_ignore_patterns: []\nconnections:\n- fetchai/ledger:0.21.5\n- fetchai/p2p_libp2p:0.27.5\n- fetchai/soef:0.27.6\ncontracts:\n- fetchai/erc1155:0.23.3\nprotocols:\n- fetchai/contract_api:1.1.7\n- fetchai/default:1.1.7\n- fetchai/fipa:1.1.7\n- fetchai/ledger_api:1.1.7\n- fetchai/oef_search:1.1.7\n- fetchai/signing:1.1.7\n- fetchai/state_update:1.1.7\nskills:\n- fetchai/erc1155_client:0.29.6\ndefault_connection: fetchai/p2p_libp2p:0.27.5\ndefault_ledger: ethereum\nrequired_ledgers:\n- fetchai\n- ethereum\nlogging_config:\n  disable_existing_loggers: false\n  version: 1\nprivate_key_paths: {}\ndefault_routing:\n  fetchai/contract_api:1.1.7: fetchai/ledger:0.21.5\n  fetchai/ledger_api:1.1.7: fetchai/ledger:0.21.5\n  fetchai/oef_search:1.1.7: fetchai/soef:0.27.6\nconnection_private_key_paths: {}\ndependencies:\n  aea-ledger-cosmos:\n    version: <2.0.0,>=1.0.0\n  aea-ledger-ethereum:\n    version: <2.0.0,>=1.0.0\n  aea-ledger-fetchai:\n    version: <2.0.0,>=1.0.0\n---\npublic_id: fetchai/soef:0.27.6\ntype: connection\nconfig:\n  chain_identifier: ethereum\n---\npublic_id: fetchai/p2p_libp2p:0.27.5\ntype: connection\ncert_requests:\n- identifier: acn\n  ledger_id: ethereum\n  not_after: '2023-01-01'\n  not_before: '2022-01-01'\n  public_key: fetchai\n  message_format: '{public_key}'\n  save_path: .certs/conn_cert.txt\n"
  },
  {
    "path": "packages/fetchai/agents/erc1155_deployer/README.md",
    "content": "# ERC1155 Deployer\n\nAn agent that deploys a smart contract sells data using it.\n\n## Description\n\nThis agent uses its primary skill, the `fetchai/erc1155_deploy` skill, to deploy a smart contract, create and mint tokens, and register its 'data-selling' service on the `SOEF`. It can then be contacted by another agent (for example the `fetchai/erc1155_client` agent) to provide specific data.\n\nOnce such a request is made, this agent negotiates the terms of trade using the `fetchai/fipa` protocol, and if an agreement is reached, it delivers the data after receiving payment via the deployed smart contract.\n\n## Links\n\n- <a href=\"https://docs.fetch.ai/aea/erc1155-skills/\" target=\"_blank\">Contract Deployment Guide</a>\n"
  },
  {
    "path": "packages/fetchai/agents/erc1155_deployer/aea-config.yaml",
    "content": "agent_name: erc1155_deployer\nauthor: fetchai\nversion: 0.34.5\ndescription: An AEA to deploy and interact with an ERC1155\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint: {}\nfingerprint_ignore_patterns: []\nconnections:\n- fetchai/ledger:0.21.5\n- fetchai/p2p_libp2p:0.27.5\n- fetchai/soef:0.27.6\ncontracts:\n- fetchai/erc1155:0.23.3\nprotocols:\n- fetchai/contract_api:1.1.7\n- fetchai/default:1.1.7\n- fetchai/fipa:1.1.7\n- fetchai/ledger_api:1.1.7\n- fetchai/oef_search:1.1.7\n- fetchai/signing:1.1.7\n- fetchai/state_update:1.1.7\nskills:\n- fetchai/erc1155_deploy:0.31.6\ndefault_connection: fetchai/p2p_libp2p:0.27.5\ndefault_ledger: ethereum\nrequired_ledgers:\n- fetchai\n- ethereum\nlogging_config:\n  disable_existing_loggers: false\n  version: 1\nprivate_key_paths: {}\ndefault_routing:\n  fetchai/contract_api:1.1.7: fetchai/ledger:0.21.5\n  fetchai/ledger_api:1.1.7: fetchai/ledger:0.21.5\n  fetchai/oef_search:1.1.7: fetchai/soef:0.27.6\nconnection_private_key_paths: {}\ndependencies:\n  aea-ledger-cosmos:\n    version: <2.0.0,>=1.0.0\n  aea-ledger-ethereum:\n    version: <2.0.0,>=1.0.0\n  aea-ledger-fetchai:\n    version: <2.0.0,>=1.0.0\n---\npublic_id: fetchai/soef:0.27.6\ntype: connection\nconfig:\n  chain_identifier: ethereum\n---\npublic_id: fetchai/p2p_libp2p:0.27.5\ntype: connection\ncert_requests:\n- identifier: acn\n  ledger_id: ethereum\n  not_after: '2023-01-01'\n  not_before: '2022-01-01'\n  public_key: fetchai\n  message_format: '{public_key}'\n  save_path: .certs/conn_cert.txt\n"
  },
  {
    "path": "packages/fetchai/agents/error_test/README.md",
    "content": "# Error Test\n\nAgent to raise an error in special skill.\n\n## Description\n\nFor tests purposes only!\n\n## Links\n"
  },
  {
    "path": "packages/fetchai/agents/error_test/aea-config.yaml",
    "content": "agent_name: error_test\nauthor: fetchai\nversion: 0.1.1\ndescription: A simple agent to test error raised in skill.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint: {}\nfingerprint_ignore_patterns: []\nconnections:\n- fetchai/stub:0.21.3\ncontracts: []\nprotocols: []\nskills:\n- fetchai/error_test_skill:0.1.2\ndefault_connection: fetchai/stub:0.21.3\ndefault_ledger: fetchai\nrequired_ledgers:\n- fetchai\nlogging_config:\n  disable_existing_loggers: false\n  version: 1\nprivate_key_paths: {}\ndefault_routing: {}\nconnection_private_key_paths: {}\ndependencies:\n  aea-ledger-fetchai:\n    version: <2.0.0,>=1.0.0\n"
  },
  {
    "path": "packages/fetchai/agents/fipa_dummy_buyer/README.md",
    "content": "# FIPA Dummy buyer\n\nA sample agent for FIPA protocol interaction.\n\n## Description\n\nDummy agent that tries to communicate  with FIPA seller agent over libp2p connection.\n"
  },
  {
    "path": "packages/fetchai/agents/fipa_dummy_buyer/aea-config.yaml",
    "content": "agent_name: fipa_dummy_buyer\nauthor: fetchai\nversion: 0.5.5\ndescription: Sample agent for FIPA interaction\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint: {}\nfingerprint_ignore_patterns: []\nconnections:\n- fetchai/p2p_libp2p:0.27.5\nprotocols:\n- fetchai/fipa:1.1.7\n- fetchai/signing:1.1.7\nskills:\n- fetchai/fipa_dummy_buyer:0.3.6\ndefault_connection: fetchai/p2p_libp2p:0.27.5\ndefault_ledger: fetchai\ncontracts: []\nrequired_ledgers:\n- fetchai\nlogging_config:\n  disable_existing_loggers: false\n  version: 1\nprivate_key_paths: {}\ndefault_routing: {}\nconnection_private_key_paths: {}\ndependencies:\n  aea-ledger-fetchai:\n    version: <2.0.0,>=1.0.0\n---\npublic_id: fetchai/p2p_libp2p:0.27.5\ntype: connection\nconfig:\n  delegate_uri: null\n  entry_peers:\n  - /dns4/acn.fetch.ai/tcp/9000/p2p/16Uiu2HAkw1ypeQYQbRFV5hKUxGRHocwU5ohmVmCnyJNg36tnPFdx\n  - /dns4/acn.fetch.ai/tcp/9001/p2p/16Uiu2HAmVWnopQAqq4pniYLw44VRvYxBUoRHqjz1Hh2SoCyjbyRW\n  public_uri: null\n  local_uri: 127.0.0.1:9000\n"
  },
  {
    "path": "packages/fetchai/agents/generic_buyer/README.md",
    "content": "# Generic Buyer\n\nA generic agent for buying data.\n\n## Description\n\nThis agent uses its primary skill, the `fetchai/generic_buyer` skill, to find an agent selling data on the `SOEF` service.\n\nOnce found, it requests specific data, negotiates the price using the `fetchai/fipa` protocol, and if an agreement is reached, pays the proposed amount and receives the data.\n\n## Links\n\n- <a href=\"https://docs.fetch.ai/aea/generic-skills/\" target=\"_blank\">Generic Skills</a>\n- <a href=\"https://docs.fetch.ai/aea/generic-skills-step-by-step/\" target=\"_blank\">Generic Skill Step by Step Guide</a>\n"
  },
  {
    "path": "packages/fetchai/agents/generic_buyer/aea-config.yaml",
    "content": "agent_name: generic_buyer\nauthor: fetchai\nversion: 0.30.5\ndescription: The buyer AEA purchases the services offered by the seller AEA.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint: {}\nfingerprint_ignore_patterns: []\nconnections:\n- fetchai/ledger:0.21.5\n- fetchai/p2p_libp2p:0.27.5\n- fetchai/soef:0.27.6\ncontracts: []\nprotocols:\n- fetchai/default:1.1.7\n- fetchai/fipa:1.1.7\n- fetchai/ledger_api:1.1.7\n- fetchai/oef_search:1.1.7\n- fetchai/signing:1.1.7\n- fetchai/state_update:1.1.7\nskills:\n- fetchai/generic_buyer:0.27.6\ndefault_connection: fetchai/p2p_libp2p:0.27.5\ndefault_ledger: fetchai\nrequired_ledgers:\n- fetchai\nlogging_config:\n  disable_existing_loggers: false\n  version: 1\nprivate_key_paths: {}\ndefault_routing:\n  fetchai/ledger_api:1.1.7: fetchai/ledger:0.21.5\n  fetchai/oef_search:1.1.7: fetchai/soef:0.27.6\nconnection_private_key_paths: {}\ndependencies:\n  aea-ledger-fetchai:\n    version: <2.0.0,>=1.0.0\n"
  },
  {
    "path": "packages/fetchai/agents/generic_seller/README.md",
    "content": "# Generic Seller\n\nA generic agent for selling data.\n\n## Description\n\nThis agent uses its primary skill, the `fetchai/generic_seller` skill, to register its 'data-selling' service on the `SOEF`. It can then be contacted by another agent (for example the `fetchai/generic_buyer` agent) to provide specific data.\n\nOnce such a request is made, this agent negotiates the terms of trade using the `fetchai/fipa` protocol, and if an agreement is reached, it delivers the data after receiving payment.\n\n## Links\n\n- <a href=\"https://docs.fetch.ai/aea/generic-skills/\" target=\"_blank\">Generic Skills</a>\n- <a href=\"https://docs.fetch.ai/aea/generic-skills-step-by-step/\" target=\"_blank\">Generic Skill Step by Step Guide</a>\n"
  },
  {
    "path": "packages/fetchai/agents/generic_seller/aea-config.yaml",
    "content": "agent_name: generic_seller\nauthor: fetchai\nversion: 0.29.5\ndescription: The seller AEA sells the services specified in the `skill.yaml` file\n  and delivers them upon payment to the buyer.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint: {}\nfingerprint_ignore_patterns: []\nconnections:\n- fetchai/ledger:0.21.5\n- fetchai/p2p_libp2p:0.27.5\n- fetchai/soef:0.27.6\ncontracts: []\nprotocols:\n- fetchai/default:1.1.7\n- fetchai/fipa:1.1.7\n- fetchai/ledger_api:1.1.7\n- fetchai/oef_search:1.1.7\n- fetchai/signing:1.1.7\n- fetchai/state_update:1.1.7\nskills:\n- fetchai/generic_seller:0.28.6\ndefault_connection: fetchai/p2p_libp2p:0.27.5\ndefault_ledger: fetchai\nrequired_ledgers:\n- fetchai\nlogging_config:\n  disable_existing_loggers: false\n  version: 1\nprivate_key_paths: {}\ndefault_routing:\n  fetchai/ledger_api:1.1.7: fetchai/ledger:0.21.5\n  fetchai/oef_search:1.1.7: fetchai/soef:0.27.6\nconnection_private_key_paths: {}\ndependencies:\n  aea-ledger-fetchai:\n    version: <2.0.0,>=1.0.0\n"
  },
  {
    "path": "packages/fetchai/agents/gym_aea/README.md",
    "content": "# Gym\n\nThis agent trains an RL algorithm using OpenAI Gym.\n\n## Description\n\nThis agent is part of the Fetch.ai Gym demo. It uses its primary skill, the `fetchai/gym` skill, to train a reinforcement learning (RL) algorithm using OpenAI Gym.\n\nIt demonstrate how an RL agent can be wrapped inside a skill by decoupling the RL agent from the gym environment, allowing them to run in separate execution environments.\n\n## Links\n\n- <a href=\"https://docs.fetch.ai/aea/gym-skill/\" target=\"_blank\">Gym Demo</a>\n- <a href=\"https://docs.fetch.ai/aea/gym-example/\" target=\"_blank\">Gym Example</a>\n- <a href=\"https://gym.openai.com\" target=\"_blank\">OpenAI Gym</a>\n"
  },
  {
    "path": "packages/fetchai/agents/gym_aea/aea-config.yaml",
    "content": "agent_name: gym_aea\nauthor: fetchai\nversion: 0.26.5\ndescription: The gym aea demos the interaction between a skill containing a RL agent\n  and a gym connection.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint: {}\nfingerprint_ignore_patterns: []\nconnections:\n- fetchai/gym:0.20.6\ncontracts: []\nprotocols:\n- fetchai/default:1.1.7\n- fetchai/gym:1.1.7\n- fetchai/signing:1.1.7\n- fetchai/state_update:1.1.7\nskills:\n- fetchai/gym:0.21.6\ndefault_connection: fetchai/gym:0.20.6\ndefault_ledger: fetchai\nrequired_ledgers:\n- fetchai\nlogging_config:\n  disable_existing_loggers: false\n  version: 1\nprivate_key_paths: {}\ndefault_routing: {}\nconnection_private_key_paths: {}\ndependencies:\n  aea-ledger-fetchai:\n    version: <2.0.0,>=1.0.0\n"
  },
  {
    "path": "packages/fetchai/agents/hello_world/README.md",
    "content": "# Hello World Agent\n\nThis is a \"Hello World\" agent!\n\n## Description\n\nThis agent uses its primary `fetchai/hello_world` skill to print `Hello World!` on the screen.\nThe message to be printed can be configured to be any string.\n"
  },
  {
    "path": "packages/fetchai/agents/hello_world/aea-config.yaml",
    "content": "agent_name: hello_world\nauthor: fetchai\nversion: 0.1.7\nlicense: Apache-2.0\ndescription: A hello world agent. An agent that prints a message on the screen.\naea_version: '>=1.2.0, <2.0.0'\nfingerprint: {}\nfingerprint_ignore_patterns: []\nconnections: []\ncontracts: []\nprotocols:\n- fetchai/signing:1.1.7\nskills:\n- fetchai/hello_world:0.1.5\ndefault_ledger: fetchai\nrequired_ledgers:\n- fetchai\ndefault_routing: {}\nconnection_private_key_paths: {}\nprivate_key_paths: {}\nlogging_config:\n  disable_existing_loggers: false\n  version: 1\ndependencies:\n  aea-ledger-fetchai: {}\ndefault_connection: null\n---\npublic_id: fetchai/hello_world:0.1.5\ntype: skill\nbehaviours:\n  hello_world:\n    args:\n      message: Hello World!\n"
  },
  {
    "path": "packages/fetchai/agents/latest_block_feed/README.md",
    "content": "# Random Beacon Feed AEA\n\nAn agent that fetches the latest block from the Fetch ledger.\n\n## Description\n\nThis agent uses the `fetchai/fetch_block` skill to get the latest block data from the fetch ledger.\n"
  },
  {
    "path": "packages/fetchai/agents/latest_block_feed/aea-config.yaml",
    "content": "agent_name: latest_block_feed\nauthor: fetchai\nversion: 0.11.5\nlicense: Apache-2.0\ndescription: An agent that retrieves the latest block data from the Fetch ledger.\naea_version: '>=1.0.0, <2.0.0'\nfingerprint: {}\nfingerprint_ignore_patterns: []\nconnections:\n- fetchai/ledger:0.21.5\ncontracts: []\nprotocols:\n- fetchai/default:1.1.7\n- fetchai/ledger_api:1.1.7\n- fetchai/signing:1.1.7\n- fetchai/state_update:1.1.7\nskills:\n- fetchai/fetch_block:0.12.6\ndefault_connection: fetchai/ledger:0.21.5\ndefault_ledger: fetchai\nrequired_ledgers:\n- fetchai\ndefault_routing: {}\nconnection_private_key_paths: {}\nprivate_key_paths: {}\nlogging_config:\n  disable_existing_loggers: false\n  version: 1\ndependencies:\n  aea-ledger-fetchai:\n    version: <2.0.0,>=1.0.0\n---\npublic_id: fetchai/ledger:0.21.5\ntype: connection\nconfig:\n  ledger_apis:\n    fetchai:\n      address: https://rest-dorado.fetch.ai:443\n      denom: atestfet\n      chain_id: dorado-1\n"
  },
  {
    "path": "packages/fetchai/agents/ml_data_provider/README.md",
    "content": "# ML Data Provider\n\nThis agent sells ML data for training.\n\n## Description\n\nThis agent is part of the Fetch.ai ML skill demo. It uses its primary skill, the `fetchai/ml_data_provider` skill, to register its 'ML-data-selling' service on the `SOEF`.\n\nIt can be contacted by another agent (for example the `fetchai/ml_train` agent) to provide specific data samples.\n\nOnce such a request is made and the terms of trade are agreed by both agents, it delivers the data after receiving payment.\n\n## Links\n\n- <a href=\"https://docs.fetch.ai/aea/ml-skills/\" target=\"_blank\">ML Demo</a>\n"
  },
  {
    "path": "packages/fetchai/agents/ml_data_provider/aea-config.yaml",
    "content": "agent_name: ml_data_provider\nauthor: fetchai\nversion: 0.32.5\ndescription: An agent that sells data.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint: {}\nfingerprint_ignore_patterns: []\nconnections:\n- fetchai/ledger:0.21.5\n- fetchai/p2p_libp2p:0.27.5\n- fetchai/soef:0.27.6\ncontracts: []\nprotocols:\n- fetchai/default:1.1.7\n- fetchai/ledger_api:1.1.7\n- fetchai/ml_trade:1.1.7\n- fetchai/oef_search:1.1.7\n- fetchai/signing:1.1.7\n- fetchai/state_update:1.1.7\nskills:\n- fetchai/generic_seller:0.28.6\n- fetchai/ml_data_provider:0.27.6\ndefault_connection: fetchai/p2p_libp2p:0.27.5\ndefault_ledger: fetchai\nrequired_ledgers:\n- fetchai\nlogging_config:\n  disable_existing_loggers: false\n  version: 1\nprivate_key_paths: {}\ndefault_routing:\n  fetchai/ledger_api:1.1.7: fetchai/ledger:0.21.5\n  fetchai/oef_search:1.1.7: fetchai/soef:0.27.6\nconnection_private_key_paths: {}\ndependencies:\n  aea-ledger-fetchai:\n    version: <2.0.0,>=1.0.0\n"
  },
  {
    "path": "packages/fetchai/agents/ml_model_trainer/README.md",
    "content": "# ML Train\n\nThis agent buys ML data for training.\n\n## Description\n\nThis skill is part of the Fetch.ai ML skill demo. It uses its primary skill, the `fetchai/ml_train` skill, to find an agent selling ML data on the `SOEF` service (for example a `fetchai/ml_data_provider` agent).\n\nOnce found, it requests specific data samples. If both parties agree with the terms of trade, it pays the proposed amount and trains an ML model using the data bought.\n\n## Links\n\n- <a href=\"https://docs.fetch.ai/aea/ml-skills/\" target=\"_blank\">ML Demo</a>\n"
  },
  {
    "path": "packages/fetchai/agents/ml_model_trainer/aea-config.yaml",
    "content": "agent_name: ml_model_trainer\nauthor: fetchai\nversion: 0.33.5\ndescription: An agent buying data and training a model from it.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint: {}\nfingerprint_ignore_patterns: []\nconnections:\n- fetchai/ledger:0.21.5\n- fetchai/p2p_libp2p:0.27.5\n- fetchai/soef:0.27.6\ncontracts: []\nprotocols:\n- fetchai/default:1.1.7\n- fetchai/ledger_api:1.1.7\n- fetchai/ml_trade:1.1.7\n- fetchai/oef_search:1.1.7\n- fetchai/signing:1.1.7\n- fetchai/state_update:1.1.7\nskills:\n- fetchai/generic_buyer:0.27.6\n- fetchai/ml_train:0.29.6\ndefault_connection: fetchai/p2p_libp2p:0.27.5\ndefault_ledger: fetchai\nrequired_ledgers:\n- fetchai\nlogging_config:\n  disable_existing_loggers: false\n  version: 1\nprivate_key_paths: {}\ndefault_routing:\n  fetchai/ledger_api:1.1.7: fetchai/ledger:0.21.5\n  fetchai/oef_search:1.1.7: fetchai/soef:0.27.6\nconnection_private_key_paths: {}\ndependencies:\n  aea-ledger-fetchai:\n    version: <2.0.0,>=1.0.0\n"
  },
  {
    "path": "packages/fetchai/agents/my_first_aea/README.md",
    "content": "# My First Agent\n\nThis is the \"Hello World\" agent!\n\n## Description\n\nThis agent uses its primary skill, the `fetchai/echo` skill, to sends back the contents of any message it receives.\n\n## Links\n\n- <a href=\"https://docs.fetch.ai/aea/quickstart/\" target=\"_blank\">Quick Start</a>\n- <a href=\"https://docs.fetch.ai/aea/build-aea-programmatically/\" target=\"_blank\">Programmatically Build an AEA</a>\n"
  },
  {
    "path": "packages/fetchai/agents/my_first_aea/aea-config.yaml",
    "content": "agent_name: my_first_aea\nauthor: fetchai\nversion: 0.28.5\ndescription: A simple agent to demo the echo skill.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint: {}\nfingerprint_ignore_patterns: []\nconnections:\n- fetchai/stub:0.21.3\ncontracts: []\nprotocols:\n- fetchai/default:1.1.7\n- fetchai/signing:1.1.7\n- fetchai/state_update:1.1.7\nskills:\n- fetchai/echo:0.20.6\ndefault_connection: fetchai/stub:0.21.3\ndefault_ledger: fetchai\nrequired_ledgers:\n- fetchai\nlogging_config:\n  disable_existing_loggers: false\n  version: 1\nprivate_key_paths: {}\ndefault_routing: {}\nconnection_private_key_paths: {}\ndependencies:\n  aea-ledger-fetchai:\n    version: <2.0.0,>=1.0.0\n"
  },
  {
    "path": "packages/fetchai/agents/registration_aea_aw1/README.md",
    "content": "# Registration AEA AW1\n\nThis is an agent to register for Agent World 1.\n\n## Description\n\nThis agent uses the `fetchai/simple_service_registration` skill to register information about itself on the sOEF. It uses the `fetchai/simple_service_search` skill to find the agent handling confirmation of registration in AW1. It uses the `fetchai/registration_aw1` skill to deal with the registration flow, including signing of messages.\n\n## Links\n"
  },
  {
    "path": "packages/fetchai/agents/registration_aea_aw1/aea-config.yaml",
    "content": "agent_name: registration_aea_aw1\nauthor: fetchai\nversion: 0.18.5\ndescription: This is an agent to register for Agent World 1.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint: {}\nfingerprint_ignore_patterns: []\nconnections:\n- fetchai/ledger:0.21.5\n- fetchai/p2p_libp2p:0.27.5\n- fetchai/soef:0.27.6\ncontracts: []\nprotocols:\n- fetchai/default:1.1.7\n- fetchai/oef_search:1.1.7\n- fetchai/register:1.1.7\n- fetchai/signing:1.1.7\n- fetchai/state_update:1.1.7\nskills:\n- fetchai/registration_aw1:0.13.6\n- fetchai/simple_service_registration:0.23.6\n- fetchai/simple_service_search:0.11.6\ndefault_connection: fetchai/p2p_libp2p:0.27.5\ndefault_ledger: fetchai\nrequired_ledgers:\n- fetchai\ndefault_routing:\n  fetchai/oef_search:1.1.7: fetchai/soef:0.27.6\nconnection_private_key_paths: {}\nprivate_key_paths: {}\nlogging_config:\n  disable_existing_loggers: false\n  version: 1\n  formatters:\n    standard:\n      format: '[%(levelname)s]: %(message)s'\n    extra:\n      format: '%(asctime)s [%(levelname)s] %(name)s: %(message)s'\n  handlers:\n    logfile:\n      class: logging.FileHandler\n      formatter: extra\n      level: DEBUG\n      filename: all.log\n    console:\n      class: logging.StreamHandler\n      formatter: standard\n      level: INFO\n  loggers:\n    aea:\n      handlers:\n      - logfile\n      - console\n      level: DEBUG\n      propagate: false\ndependencies:\n  aea-ledger-ethereum:\n    version: <2.0.0,>=1.0.0\n  aea-ledger-fetchai:\n    version: <2.0.0,>=1.0.0\n---\npublic_id: fetchai/registration_aw1:0.13.6\ntype: skill\nmodels:\n  strategy:\n    args:\n      ethereum_address: PUT_YOUR_ETHEREUM_ADDRESS_HERE\n      developer_handle: PUT_YOUR_DEVELOPER_HANDLE_HERE\n      signature_of_fetchai_address: PUT_YOUR_SIGNATURE_HERE\n      tweet: PUT_THE_LINK_TO_YOUR_TWEET_HERE\n      whitelist:\n      - PUT_WHITELIST_ADDRESSES_HERE\n---\npublic_id: fetchai/p2p_libp2p:0.27.5\ntype: connection\nconfig:\n  delegate_uri: null\n  public_uri: null\n  entry_peers:\n  - /dns4/acn.fetch.ai/tcp/9001/p2p/16Uiu2HAmVWnopQAqq4pniYLw44VRvYxBUoRHqjz1Hh2SoCyjbyRW\n---\npublic_id: fetchai/soef:0.27.6\ntype: connection\nconfig:\n  chain_identifier: fetchai_v2_testnet_incentivised\n---\npublic_id: fetchai/ledger:0.21.5\ntype: connection\nconfig:\n  ledger_apis:\n    fetchai:\n      address: https://rest-dorado.fetch.ai:443\n      chain_id: dorado-1\n---\npublic_id: fetchai/simple_service_registration:0.23.6\ntype: skill\nmodels:\n  strategy:\n    args:\n      location:\n        latitude: 51.5194\n        longitude: 0.127\n      service_data:\n        key: agentworld-1\n        value: PUT_YOUR_DEVELOPER_HANDLE_HERE\n---\npublic_id: fetchai/simple_service_search:0.11.6\ntype: skill\nmodels:\n  strategy:\n    args:\n      search_location:\n        latitude: 51.5194\n        longitude: 0.127\n      search_query:\n        constraint_type: ==\n        search_key: registration_service\n        search_value: aw1-registration\n"
  },
  {
    "path": "packages/fetchai/agents/simple_aggregator/README.md",
    "content": "# Oracle Aggregator AEA\n\nAn agent that aggregates individual observations for an oracle network\n\n## Description\n\nThis agent uses the `fetchai/oracle_aggregation` skill to find peers and aggregate values.\n"
  },
  {
    "path": "packages/fetchai/agents/simple_aggregator/aea-config.yaml",
    "content": "agent_name: simple_aggregator\nauthor: fetchai\nversion: 0.5.5\nlicense: Apache-2.0\ndescription: AEA that aggregates observations\naea_version: '>=1.0.0, <2.0.0'\nfingerprint: {}\nfingerprint_ignore_patterns: []\nconnections:\n- fetchai/http_client:0.24.6\n- fetchai/http_server:0.23.6\n- fetchai/p2p_libp2p:0.27.5\n- fetchai/prometheus:0.9.6\n- fetchai/soef:0.27.6\ncontracts: []\nprotocols:\n- fetchai/aggregation:0.2.7\n- fetchai/default:1.1.7\n- fetchai/http:1.1.7\n- fetchai/oef_search:1.1.7\n- fetchai/prometheus:1.1.7\n- fetchai/signing:1.1.7\n- fetchai/state_update:1.1.7\nskills:\n- fetchai/advanced_data_request:0.7.6\n- fetchai/simple_aggregation:0.3.6\ndefault_connection: fetchai/p2p_libp2p:0.27.5\ndefault_ledger: fetchai\nrequired_ledgers:\n- fetchai\nlogging_config:\n  disable_existing_loggers: false\n  version: 1\ndefault_routing: {}\nconnection_private_key_paths: {}\nprivate_key_paths: {}\ndependencies:\n  aea-ledger-fetchai:\n    version: <2.0.0,>=1.0.0\n---\npublic_id: fetchai/advanced_data_request:0.7.6\ntype: skill\nmodels:\n  advanced_data_request_model:\n    args:\n      decimals: 0\n      use_http_server: false\n---\npublic_id: fetchai/http_server:0.23.6\ntype: connection\nconfig:\n  target_skill_id: fetchai/advanced_data_request:0.7.6\n---\npublic_id: fetchai/simple_aggregation:0.3.6\ntype: skill\nmodels:\n  strategy:\n    args:\n      aggregation_function: mean\n      quantity_name: price\n      search_query:\n        search_value: generic_aggregation_service\n      service_id: generic_aggregation_service\n"
  },
  {
    "path": "packages/fetchai/agents/simple_buyer_aw2/README.md",
    "content": "# Simple Buyer AW2\n\nThis is an agent that buys data in Agent World 2.\n\n## Description\n\nThis agent uses the `fetchai/buyer_aw2` skill to purchase data from other agents in Agent World 2.\n"
  },
  {
    "path": "packages/fetchai/agents/simple_buyer_aw2/aea-config.yaml",
    "content": "agent_name: simple_buyer_aw2\nauthor: fetchai\nversion: 0.18.5\nlicense: Apache-2.0\ndescription: This AEA buys data from a simple seller in Agent World 2.\naea_version: '>=1.0.0, <2.0.0'\nfingerprint: {}\nfingerprint_ignore_patterns: []\nconnections:\n- fetchai/ledger:0.21.5\n- fetchai/p2p_libp2p:0.27.5\n- fetchai/soef:0.27.6\ncontracts: []\nprotocols:\n- fetchai/contract_api:1.1.7\n- fetchai/default:1.1.7\n- fetchai/fipa:1.1.7\n- fetchai/ledger_api:1.1.7\n- fetchai/oef_search:1.1.7\n- fetchai/signing:1.1.7\n- fetchai/state_update:1.1.7\nskills:\n- fetchai/generic_buyer:0.27.6\n- fetchai/simple_buyer:0.13.6\ndefault_connection: fetchai/p2p_libp2p:0.27.5\ndefault_ledger: fetchai\nrequired_ledgers:\n- fetchai\ndefault_routing:\n  fetchai/ledger_api:1.1.7: fetchai/ledger:0.21.5\n  fetchai/oef_search:1.1.7: fetchai/soef:0.27.6\nconnection_private_key_paths: {}\nprivate_key_paths: {}\nlogging_config:\n  disable_existing_loggers: false\n  version: 1\n  formatters:\n    standard:\n      format: '[%(levelname)s]: %(message)s'\n    extra:\n      format: '%(asctime)s [%(levelname)s] %(name)s: %(message)s'\n  handlers:\n    logfile:\n      class: logging.FileHandler\n      formatter: extra\n      level: DEBUG\n      filename: all.log\n    console:\n      class: logging.StreamHandler\n      formatter: standard\n      level: INFO\n  loggers:\n    aea:\n      handlers:\n      - logfile\n      - console\n      level: DEBUG\n      propagate: false\ndependencies:\n  aea-ledger-fetchai:\n    version: <2.0.0,>=1.0.0\n---\npublic_id: fetchai/simple_buyer:0.13.6\ntype: skill\nmodels:\n  strategy:\n    args:\n      location:\n        latitude: 51.5194\n        longitude: 0.127\n      max_negotiations: 2\n      max_unit_price: 20\n      search_query:\n        constraint_type: ==\n        search_key: seller_service\n        search_value: weather_data\n      search_radius: 50.0\n      service_id: weather_data\n---\npublic_id: fetchai/p2p_libp2p:0.27.5\ntype: connection\nconfig:\n  delegate_uri: null\n  public_uri: null\n  entry_peers:\n  - /dns4/acn.fetch.ai/tcp/9001/p2p/16Uiu2HAmVWnopQAqq4pniYLw44VRvYxBUoRHqjz1Hh2SoCyjbyRW\n---\npublic_id: fetchai/soef:0.27.6\ntype: connection\nconfig:\n  chain_identifier: fetchai_v2_testnet_incentivised\n---\npublic_id: fetchai/ledger:0.21.5\ntype: connection\nconfig:\n  ledger_apis:\n    fetchai:\n      address: https://rest-dorado.fetch.ai:443\n      chain_id: dorado-1\n"
  },
  {
    "path": "packages/fetchai/agents/simple_buyer_aw5/aea-config.yaml",
    "content": "agent_name: simple_buyer_aw5\nauthor: fetchai\nversion: 0.5.5\nlicense: Apache-2.0\ndescription: This agent purchases information from other agents as specified in its\n  configuration. It acts as the confirmation AEA in Agent World 5.\naea_version: '>=1.0.0, <2.0.0'\nfingerprint: {}\nfingerprint_ignore_patterns: []\nconnections:\n- fetchai/http_client:0.24.6\n- fetchai/ledger:0.21.5\n- fetchai/p2p_libp2p:0.27.5\n- fetchai/soef:0.27.6\ncontracts: []\nprotocols:\n- fetchai/contract_api:1.1.7\n- fetchai/default:1.1.7\n- fetchai/fipa:1.1.7\n- fetchai/http:1.1.7\n- fetchai/ledger_api:1.1.7\n- fetchai/oef_search:1.1.7\n- fetchai/signing:1.1.7\n- fetchai/state_update:1.1.7\nskills:\n- fetchai/confirmation_aw3:0.12.6\n- fetchai/generic_buyer:0.27.6\ndefault_ledger: fetchai\nrequired_ledgers:\n- fetchai\ndefault_routing:\n  fetchai/http:1.1.7: fetchai/http_client:0.24.6\n  fetchai/ledger_api:1.1.7: fetchai/ledger:0.21.5\n  fetchai/oef_search:1.1.7: fetchai/soef:0.27.6\nconnection_private_key_paths: {}\nprivate_key_paths: {}\nlogging_config:\n  disable_existing_loggers: false\n  version: 1\n  formatters:\n    standard:\n      format: '[%(levelname)s]: %(message)s'\n    extra:\n      format: '%(asctime)s [%(levelname)s] %(name)s: %(message)s'\n  handlers:\n    logfile:\n      class: logging.FileHandler\n      formatter: extra\n      level: NOTSET\n      filename: all.log\n    logfile_error:\n      class: logging.FileHandler\n      formatter: extra\n      level: ERROR\n      filename: error.log\n    console:\n      class: logging.StreamHandler\n      formatter: standard\n      level: INFO\n  loggers:\n    aea:\n      handlers:\n      - logfile\n      - logfile_error\n      - console\n      level: DEBUG\n      propagate: false\ndependencies:\n  aea-ledger-fetchai:\n    version: <2.0.0,>=1.0.0\ndefault_connection: fetchai/p2p_libp2p:0.27.5\n---\npublic_id: fetchai/p2p_libp2p:0.27.5\ntype: connection\nconfig:\n  delegate_uri: null\n  public_uri: null\n  entry_peers:\n  - /dns4/acn.fetch.ai/tcp/9001/p2p/16Uiu2HAmVWnopQAqq4pniYLw44VRvYxBUoRHqjz1Hh2SoCyjbyRW\n---\npublic_id: fetchai/soef:0.27.6\ntype: connection\nconfig:\n  chain_identifier: fetchai_v2_testnet_incentivised\n  token_storage_path: soef_key.txt\n---\npublic_id: fetchai/ledger:0.21.5\ntype: connection\nconfig:\n  ledger_apis:\n    ethereum:\n      address: null\n    fetchai:\n      address: https://rest-dorado.fetch.ai:443\n      chain_id: dorado-1\n---\npublic_id: fetchai/confirmation_aw3:0.12.6\ntype: skill\nbehaviours:\n  search:\n    args:\n      search_interval: 900\nmodels:\n  registration_db:\n    args:\n      custom_path: registration.db\n  strategy:\n    args:\n      aw1_aea: null\n      leaderboard_token: null\n      leaderboard_url: null\n      locations:\n        berlin:\n          latitude: 52.52\n          longitude: 13.405\n        london:\n          latitude: 51.5074\n          longitude: -0.1278\n        san_francisco:\n          latitude: 37.7749\n          longitude: -122.4194\n        shanghai:\n          latitude: 31.2304\n          longitude: 121.4737\n        rome:\n          latitude: 41.9028\n          longitude: 12.4964\n        rio_de_janeiro:\n          latitude: -22.9068\n          longitude: -43.1729\n        sydney:\n          latitude: -33.8688\n          longitude: 151.2093\n        delhi:\n          latitude: 28.7041\n          longitude: 77.1025\n        tokyo:\n          latitude: 35.6762\n          longitude: 139.6503\n        mexico_city:\n          latitude: 19.4326\n          longitude: -99.1332\n        cairo:\n          latitude: 30.0444\n          longitude: 31.2357\n        kinshasa:\n          latitude: -4.4419\n          longitude: 15.2663\n      search_queries:\n        weather:\n          constraint_type: ==\n          search_key: seller_service\n          search_value: weather_data\n        mobility:\n          constraint_type: ==\n          search_key: seller_service\n          search_value: mobility_data\n      search_radius: 50.0\n"
  },
  {
    "path": "packages/fetchai/agents/simple_seller_aw2/README.md",
    "content": "# Simple Seller AW2\n\nThis is an agent that sells data in Agent World 2.\n\n## Description\n\nThis agent uses the `fetchai/simple_seller` skill to sell data to other agents in Agent World 2.\n"
  },
  {
    "path": "packages/fetchai/agents/simple_seller_aw2/aea-config.yaml",
    "content": "agent_name: simple_seller_aw2\nauthor: fetchai\nversion: 0.20.5\ndescription: This AEA sells data to a simple buyer in Agent World 2.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint: {}\nfingerprint_ignore_patterns: []\nconnections:\n- fetchai/http_client:0.24.6\n- fetchai/ledger:0.21.5\n- fetchai/p2p_libp2p:0.27.5\n- fetchai/soef:0.27.6\ncontracts: []\nprotocols:\n- fetchai/contract_api:1.1.7\n- fetchai/default:1.1.7\n- fetchai/fipa:1.1.7\n- fetchai/http:1.1.7\n- fetchai/ledger_api:1.1.7\n- fetchai/oef_search:1.1.7\n- fetchai/signing:1.1.7\n- fetchai/state_update:1.1.7\nskills:\n- fetchai/generic_seller:0.28.6\n- fetchai/simple_data_request:0.14.6\n- fetchai/simple_seller:0.14.6\ndefault_connection: fetchai/p2p_libp2p:0.27.5\ndefault_ledger: fetchai\nrequired_ledgers:\n- fetchai\nlogging_config:\n  disable_existing_loggers: false\n  version: 1\n  formatters:\n    standard:\n      format: '[%(levelname)s]: %(message)s'\n    extra:\n      format: '%(asctime)s [%(levelname)s] %(name)s: %(message)s'\n  handlers:\n    logfile:\n      class: logging.FileHandler\n      formatter: extra\n      level: DEBUG\n      filename: all.log\n    console:\n      class: logging.StreamHandler\n      formatter: standard\n      level: INFO\n  loggers:\n    aea:\n      handlers:\n      - logfile\n      - console\n      level: DEBUG\n      propagate: false\nprivate_key_paths: {}\ndefault_routing:\n  fetchai/http:1.1.7: fetchai/http_client:0.24.6\n  fetchai/ledger_api:1.1.7: fetchai/ledger:0.21.5\n  fetchai/oef_search:1.1.7: fetchai/soef:0.27.6\nconnection_private_key_paths: {}\ndependencies:\n  aea-ledger-fetchai:\n    version: <2.0.0,>=1.0.0\n---\npublic_id: fetchai/simple_seller:0.14.6\ntype: skill\nmodels:\n  strategy:\n    args:\n      location:\n        latitude: 51.5194\n        longitude: 0.127\n      service_data:\n        key: seller_service\n        value: weather_data\n      service_id: weather_data\n      shared_state_key: my_data\n      unit_price: 10\n---\npublic_id: fetchai/simple_data_request:0.14.6\ntype: skill\nbehaviours:\n  http_request:\n    args:\n      request_interval: 20\n      body: ''\n      method: null\n      url: null\nhandlers:\n  http:\n    args:\n      shared_state_key: my_data\n---\npublic_id: fetchai/p2p_libp2p:0.27.5\ntype: connection\nconfig:\n  delegate_uri: null\n  public_uri: null\n  entry_peers:\n  - /dns4/acn.fetch.ai/tcp/9001/p2p/16Uiu2HAmVWnopQAqq4pniYLw44VRvYxBUoRHqjz1Hh2SoCyjbyRW\n---\npublic_id: fetchai/soef:0.27.6\ntype: connection\nconfig:\n  chain_identifier: fetchai_v2_testnet_incentivised\n---\npublic_id: fetchai/ledger:0.21.5\ntype: connection\nconfig:\n  ledger_apis:\n    fetchai:\n      address: https://rest-dorado.fetch.ai:443\n      chain_id: dorado-1\n"
  },
  {
    "path": "packages/fetchai/agents/simple_seller_aw5/aea-config.yaml",
    "content": "agent_name: simple_seller_aw5\nauthor: fetchai\nversion: 0.5.5\nlicense: Apache-2.0\ndescription: An agent that participates in Agent World 5 as a simple seller.\naea_version: '>=1.0.0, <2.0.0'\nfingerprint: {}\nfingerprint_ignore_patterns: []\nconnections:\n- fetchai/http_client:0.24.6\n- fetchai/ledger:0.21.5\n- fetchai/p2p_libp2p:0.27.5\n- fetchai/soef:0.27.6\ncontracts: []\nprotocols:\n- fetchai/contract_api:1.1.7\n- fetchai/default:1.1.7\n- fetchai/fipa:1.1.7\n- fetchai/http:1.1.7\n- fetchai/ledger_api:1.1.7\n- fetchai/oef_search:1.1.7\n- fetchai/register:1.1.7\n- fetchai/signing:1.1.7\n- fetchai/state_update:1.1.7\nskills:\n- fetchai/generic_seller:0.28.6\n- fetchai/registration_aw1:0.13.6\n- fetchai/simple_data_request:0.14.6\n- fetchai/simple_seller:0.14.6\n- fetchai/simple_service_registration:0.23.6\n- fetchai/simple_service_search:0.11.6\ndefault_connection: fetchai/p2p_libp2p:0.27.5\ndefault_ledger: fetchai\nrequired_ledgers:\n- fetchai\ndefault_routing:\n  fetchai/http:1.1.7: fetchai/http_client:0.24.6\n  fetchai/ledger_api:1.1.7: fetchai/ledger:0.21.5\n  fetchai/oef_search:1.1.7: fetchai/soef:0.27.6\nconnection_private_key_paths: {}\nprivate_key_paths: {}\nlogging_config:\n  disable_existing_loggers: false\n  version: 1\n  formatters:\n    standard:\n      format: '[%(levelname)s]: %(message)s'\n    extra:\n      format: '%(asctime)s [%(levelname)s] %(name)s: %(message)s'\n  handlers:\n    logfile:\n      class: logging.FileHandler\n      formatter: extra\n      level: DEBUG\n      filename: all.log\n    console:\n      class: logging.StreamHandler\n      formatter: standard\n      level: INFO\n  loggers:\n    aea:\n      handlers:\n      - logfile\n      - console\n      level: DEBUG\n      propagate: false\ndependencies:\n  aea-ledger-ethereum:\n    version: <2.0.0,>=1.0.0\n  aea-ledger-fetchai:\n    version: <2.0.0,>=1.0.0\n---\npublic_id: fetchai/registration_aw1:0.13.6\ntype: skill\nmodels:\n  strategy:\n    args:\n      announce_termination_key: aw-registration\n      developer_handle: PUT_YOUR_DEVELOPER_HANDLE_HERE\n      developer_handle_only: true\n      whitelist:\n      - PUT_WHITELIST_ADDRESSES_HERE\n---\npublic_id: fetchai/simple_service_registration:0.23.6\ntype: skill\nmodels:\n  strategy:\n    args:\n      location:\n        latitude: 51.5194\n        longitude: 0.127\n      service_data:\n        key: agentworld-5\n        value: PUT_YOUR_DEVELOPER_HANDLE_HERE\n---\npublic_id: fetchai/simple_service_search:0.11.6\ntype: skill\nmodels:\n  strategy:\n    args:\n      search_location:\n        latitude: 51.5074\n        longitude: -0.1278\n      search_query:\n        constraint_type: ==\n        search_key: registration_service\n        search_value: aw5-registration\n---\npublic_id: fetchai/p2p_libp2p:0.27.5\ntype: connection\nconfig:\n  delegate_uri: null\n  public_uri: null\n  entry_peers:\n  - /dns4/acn.fetch.ai/tcp/9001/p2p/16Uiu2HAmVWnopQAqq4pniYLw44VRvYxBUoRHqjz1Hh2SoCyjbyRW\n---\npublic_id: fetchai/soef:0.27.6\ntype: connection\nconfig:\n  chain_identifier: fetchai_v2_testnet_incentivised\n---\npublic_id: fetchai/ledger:0.21.5\ntype: connection\nconfig:\n  ledger_apis:\n    fetchai:\n      address: https://rest-dorado.fetch.ai:443\n      chain_id: dorado-1\n---\npublic_id: fetchai/simple_seller:0.14.6\ntype: skill\nmodels:\n  strategy:\n    args:\n      location:\n        latitude: 51.5074\n        longitude: -0.1278\n      service_data:\n        key: seller_service\n        value: weather_data\n      service_id: weather_data\n      shared_state_key: my_data\n      unit_price: 10\n---\npublic_id: fetchai/simple_data_request:0.14.6\ntype: skill\nbehaviours:\n  http_request:\n    args:\n      request_interval: 20\n      body: ''\n      method: null\n      url: null\n      lookup_termination_key: aw-registration\nhandlers:\n  http:\n    args:\n      shared_state_key: my_data\n"
  },
  {
    "path": "packages/fetchai/agents/simple_service_registration/README.md",
    "content": "# Simple Service Registration\n\nThis agent registers and unregisters its service on the SOEF.\n\n## Description\n\nThis agent is used in the \"Guide on Writing a Skill\" section of the documentation. On start, it registers its service on the `SOEF`, and on termination it unregisters it.\n\n## Links\n\n- <a href=\"https://docs.fetch.ai/aea/skill-guide/\" target=\"_blank\">Guide on Building a Skill</a>\n"
  },
  {
    "path": "packages/fetchai/agents/simple_service_registration/aea-config.yaml",
    "content": "agent_name: simple_service_registration\nauthor: fetchai\nversion: 0.32.5\ndescription: A simple example of service registration.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint: {}\nfingerprint_ignore_patterns: []\nconnections:\n- fetchai/p2p_libp2p:0.27.5\n- fetchai/soef:0.27.6\ncontracts: []\nprotocols:\n- fetchai/default:1.1.7\n- fetchai/fipa:1.1.7\n- fetchai/oef_search:1.1.7\n- fetchai/signing:1.1.7\n- fetchai/state_update:1.1.7\nskills:\n- fetchai/simple_service_registration:0.23.6\ndefault_connection: fetchai/p2p_libp2p:0.27.5\ndefault_ledger: fetchai\nrequired_ledgers:\n- fetchai\nlogging_config:\n  disable_existing_loggers: false\n  version: 1\nprivate_key_paths: {}\ndefault_routing:\n  fetchai/oef_search:1.1.7: fetchai/soef:0.27.6\nconnection_private_key_paths: {}\ndependencies:\n  aea-ledger-fetchai:\n    version: <2.0.0,>=1.0.0\n"
  },
  {
    "path": "packages/fetchai/agents/simple_service_search/README.md",
    "content": "# Simple Service Search\n\nThis agent searches for a service on the SOEF.\n\n## Description\n\nThis agent is used in the \"Guide on Writing a Skill\" section of the documentation. On start, it starts repeatedly searching on the `SOEF`.\n\n## Links\n\n- <a href=\"https://docs.fetch.ai/aea/skill-guide/\" target=\"_blank\">Guide on Building a Skill</a>\n"
  },
  {
    "path": "packages/fetchai/agents/simple_service_search/aea-config.yaml",
    "content": "agent_name: simple_service_search\nauthor: fetchai\nversion: 0.16.5\ndescription: A simple example of service search.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint: {}\nfingerprint_ignore_patterns: []\nconnections:\n- fetchai/p2p_libp2p:0.27.5\n- fetchai/soef:0.27.6\ncontracts: []\nprotocols:\n- fetchai/default:1.1.7\n- fetchai/fipa:1.1.7\n- fetchai/oef_search:1.1.7\n- fetchai/signing:1.1.7\n- fetchai/state_update:1.1.7\nskills:\n- fetchai/simple_service_search:0.11.6\ndefault_connection: fetchai/p2p_libp2p:0.27.5\ndefault_ledger: fetchai\nrequired_ledgers:\n- fetchai\nlogging_config:\n  disable_existing_loggers: false\n  version: 1\nprivate_key_paths: {}\ndefault_routing:\n  fetchai/oef_search:1.1.7: fetchai/soef:0.27.6\nconnection_private_key_paths: {}\ndependencies:\n  aea-ledger-fetchai:\n    version: <2.0.0,>=1.0.0\n"
  },
  {
    "path": "packages/fetchai/agents/tac_controller/README.md",
    "content": "# TAC Controller\n\nThis is a controller agent for a Trading Agent Competition (TAC).\n\n## Description\n\nThis agent is part of the Fetch.ai TAC demo.\n\nIt uses its `fetchai/tac_control` skill to manage the progression of a competition across various stages.\n\n## Links\n\n- <a href=\"https://docs.fetch.ai/aea/tac-skills-contract/\" target=\"_blank\">TAC Demo</a>\n"
  },
  {
    "path": "packages/fetchai/agents/tac_controller/aea-config.yaml",
    "content": "agent_name: tac_controller\nauthor: fetchai\nversion: 0.30.5\ndescription: An AEA to manage an instance of the TAC (trading agent competition)\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint: {}\nfingerprint_ignore_patterns: []\nconnections:\n- fetchai/p2p_libp2p:0.27.5\n- fetchai/soef:0.27.6\ncontracts: []\nprotocols:\n- fetchai/default:1.1.7\n- fetchai/oef_search:1.1.7\n- fetchai/signing:1.1.7\n- fetchai/state_update:1.1.7\n- fetchai/tac:1.1.7\nskills:\n- fetchai/tac_control:0.25.6\ndefault_connection: fetchai/p2p_libp2p:0.27.5\ndefault_ledger: fetchai\nrequired_ledgers:\n- fetchai\nlogging_config:\n  disable_existing_loggers: false\n  version: 1\nprivate_key_paths: {}\ndefault_routing:\n  fetchai/oef_search:1.1.7: fetchai/soef:0.27.6\nconnection_private_key_paths: {}\ndependencies:\n  aea-ledger-fetchai:\n    version: <2.0.0,>=1.0.0\n"
  },
  {
    "path": "packages/fetchai/agents/tac_controller_contract/README.md",
    "content": "# TAC Controller Contract\n\nThis is a controller agent for a Trading Agent Competition (TAC) using smart contracts.\n\n## Description\n\nThis agent is part of the Fetch.ai TAC demo.\n\nIt uses its `fetchai/tac_control` skill to manage the progression of a competition across various stages, and uses its `fetchai/tac_control_contract` skill to create and maintain a smart contract (for example, deploying the contract, creating and minting tokens, etc).\n\n## Links\n\n- <a href=\"https://docs.fetch.ai/aea/tac-skills-contract/\" target=\"_blank\">TAC Demo</a>\n"
  },
  {
    "path": "packages/fetchai/agents/tac_controller_contract/aea-config.yaml",
    "content": "agent_name: tac_controller_contract\nauthor: fetchai\nversion: 0.32.5\ndescription: An AEA to manage an instance of the TAC (trading agent competition) using\n  an ERC1155 smart contract.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint: {}\nfingerprint_ignore_patterns: []\nconnections:\n- fetchai/ledger:0.21.5\n- fetchai/p2p_libp2p:0.27.5\n- fetchai/soef:0.27.6\ncontracts:\n- fetchai/erc1155:0.23.3\nprotocols:\n- fetchai/contract_api:1.1.7\n- fetchai/default:1.1.7\n- fetchai/ledger_api:1.1.7\n- fetchai/oef_search:1.1.7\n- fetchai/signing:1.1.7\n- fetchai/state_update:1.1.7\n- fetchai/tac:1.1.7\nskills:\n- fetchai/tac_control:0.25.6\n- fetchai/tac_control_contract:0.27.6\ndefault_connection: fetchai/p2p_libp2p:0.27.5\ndefault_ledger: fetchai\nrequired_ledgers:\n- fetchai\n- ethereum\nlogging_config:\n  disable_existing_loggers: false\n  version: 1\nprivate_key_paths: {}\ndefault_routing:\n  fetchai/contract_api:1.1.7: fetchai/ledger:0.21.5\n  fetchai/ledger_api:1.1.7: fetchai/ledger:0.21.5\n  fetchai/oef_search:1.1.7: fetchai/soef:0.27.6\nconnection_private_key_paths: {}\ndependencies:\n  aea-ledger-ethereum:\n    version: <2.0.0,>=1.0.0\n  aea-ledger-fetchai:\n    version: <2.0.0,>=1.0.0\n---\npublic_id: fetchai/p2p_libp2p:0.27.5\ntype: connection\ncert_requests:\n- identifier: acn\n  ledger_id: fetchai\n  not_after: '2023-01-01'\n  not_before: '2022-01-01'\n  public_key: fetchai\n  message_format: '{public_key}'\n  save_path: .certs/conn_cert.txt\n---\npublic_id: fetchai/soef:0.27.6\ntype: connection\nconfig:\n  chain_identifier: fetchai_v2_misc\n---\npublic_id: fetchai/tac_control:0.25.6\ntype: skill\nis_abstract: true\n"
  },
  {
    "path": "packages/fetchai/agents/tac_participant/README.md",
    "content": "# TAC Participant\n\nThis is an agent that participates in a Trading Agent Competition (TAC).\n\n## Description\n\nThis agent is part of the Fetch.ai TAC demo.\n\nIt uses its `fetchai/tac_participation` skill to find and register with a TAC by communicating with a controller agent.\n\nIt then uses its `fetchai/tac_negotiation` skill to find trading partners, negotiate deals and exchange goods with them.\n\n## Links\n\n- <a href=\"https://docs.fetch.ai/aea/tac-skills-contract/\" target=\"_blank\">TAC Demo</a>\n"
  },
  {
    "path": "packages/fetchai/agents/tac_participant/aea-config.yaml",
    "content": "agent_name: tac_participant\nauthor: fetchai\nversion: 0.32.5\ndescription: An AEA to participate in the TAC (trading agent competition)\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint: {}\nfingerprint_ignore_patterns: []\nconnections:\n- fetchai/ledger:0.21.5\n- fetchai/p2p_libp2p:0.27.5\n- fetchai/soef:0.27.6\ncontracts:\n- fetchai/erc1155:0.23.3\nprotocols:\n- fetchai/default:1.1.7\n- fetchai/fipa:1.1.7\n- fetchai/oef_search:1.1.7\n- fetchai/signing:1.1.7\n- fetchai/state_update:1.1.7\n- fetchai/tac:1.1.7\nskills:\n- fetchai/tac_negotiation:0.29.6\n- fetchai/tac_participation:0.25.6\ndefault_connection: fetchai/p2p_libp2p:0.27.5\ndefault_ledger: fetchai\nrequired_ledgers:\n- fetchai\nlogging_config:\n  disable_existing_loggers: false\n  version: 1\nprivate_key_paths: {}\ndefault_routing:\n  fetchai/ledger_api:1.1.7: fetchai/ledger:0.21.5\n  fetchai/oef_search:1.1.7: fetchai/soef:0.27.6\nconnection_private_key_paths: {}\ndecision_maker_handler:\n  dotted_path: aea.decision_maker.gop:DecisionMakerHandler\n  file_path: null\n  config: {}\ndependencies:\n  aea-ledger-fetchai:\n    version: <2.0.0,>=1.0.0\n"
  },
  {
    "path": "packages/fetchai/agents/tac_participant_contract/README.md",
    "content": "# TAC Participant Contract\n\nThis is an agent that participates in a Trading Agent Competition (TAC) using a smart contract.\n\n## Description\n\nThis agent is part of the Fetch.ai TAC demo.\n\nIt uses its `fetchai/tac_participation` skill to find and register with a TAC by communicating with a controller agent.\n\nIt then uses its `fetchai/tac_negotiation` skill to find trading partners, negotiate deals and exchange goods with them using a smart contract.\n\n## Links\n\n- <a href=\"https://docs.fetch.ai/aea/tac-skills-contract/\" target=\"_blank\">TAC Demo</a>\n"
  },
  {
    "path": "packages/fetchai/agents/tac_participant_contract/aea-config.yaml",
    "content": "agent_name: tac_participant_contract\nauthor: fetchai\nversion: 0.22.5\ndescription: An AEA to participate in the TAC (trading agent competition) using an\n  ERC1155 smart contract.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint: {}\nfingerprint_ignore_patterns: []\nconnections:\n- fetchai/ledger:0.21.5\n- fetchai/p2p_libp2p:0.27.5\n- fetchai/soef:0.27.6\ncontracts:\n- fetchai/erc1155:0.23.3\nprotocols:\n- fetchai/default:1.1.7\n- fetchai/fipa:1.1.7\n- fetchai/oef_search:1.1.7\n- fetchai/signing:1.1.7\n- fetchai/state_update:1.1.7\n- fetchai/tac:1.1.7\nskills:\n- fetchai/tac_negotiation:0.29.6\n- fetchai/tac_participation:0.25.6\ndefault_connection: fetchai/p2p_libp2p:0.27.5\ndefault_ledger: fetchai\nrequired_ledgers:\n- fetchai\n- ethereum\nlogging_config:\n  disable_existing_loggers: false\n  version: 1\nprivate_key_paths: {}\ndefault_routing:\n  fetchai/contract_api:1.1.7: fetchai/ledger:0.21.5\n  fetchai/ledger_api:1.1.7: fetchai/ledger:0.21.5\n  fetchai/oef_search:1.1.7: fetchai/soef:0.27.6\nconnection_private_key_paths: {}\ndecision_maker_handler:\n  dotted_path: aea.decision_maker.gop:DecisionMakerHandler\n  file_path: null\n  config: {}\ndependencies:\n  aea-ledger-ethereum:\n    version: <2.0.0,>=1.0.0\n  aea-ledger-fetchai:\n    version: <2.0.0,>=1.0.0\n---\npublic_id: fetchai/p2p_libp2p:0.27.5\ntype: connection\ncert_requests:\n- identifier: acn\n  ledger_id: fetchai\n  not_after: '2023-01-01'\n  not_before: '2022-01-01'\n  public_key: fetchai\n  message_format: '{public_key}'\n  save_path: .certs/conn_cert.txt\n---\npublic_id: fetchai/soef:0.27.6\ntype: connection\nconfig:\n  chain_identifier: fetchai_v2_misc\n---\npublic_id: fetchai/tac_participation:0.25.6\ntype: skill\nmodels:\n  game:\n    args:\n      is_using_contract: true\n---\npublic_id: fetchai/tac_negotiation:0.29.6\ntype: skill\nmodels:\n  strategy:\n    args:\n      is_contract_tx: true\n"
  },
  {
    "path": "packages/fetchai/agents/thermometer_aea/README.md",
    "content": "# Thermometer\n\nThis agent sells thermometer data.\n\n## Description\n\nThis agent is part of the Fetch.ai thermometer demo. It uses its primary skill, the `fetchai/thermometer` skill, to register its 'thermometer-data-selling' service on the `SOEF`.\n\nIt can be contacted by another agent (for example the `fetchai/thermometer_client` agent) to provide data from a thermometer reading.\n\nOnce such a request is made, this agent negotiates the terms of trade using the `fetchai/fipa` protocol, and if an agreement is reached, it reads data from a (real or fake) thermometer, and delivers it after receiving payment.\n\n## Links\n\n- <a href=\"https://docs.fetch.ai/aea/thermometer-skills/\" target=\"_blank\">Thermometer Demo</a>\n"
  },
  {
    "path": "packages/fetchai/agents/thermometer_aea/aea-config.yaml",
    "content": "agent_name: thermometer_aea\nauthor: fetchai\nversion: 0.30.5\ndescription: An AEA to represent a thermometer and sell temperature data.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint: {}\nfingerprint_ignore_patterns: []\nconnections:\n- fetchai/ledger:0.21.5\n- fetchai/p2p_libp2p:0.27.5\n- fetchai/soef:0.27.6\ncontracts: []\nprotocols:\n- fetchai/default:1.1.7\n- fetchai/fipa:1.1.7\n- fetchai/ledger_api:1.1.7\n- fetchai/oef_search:1.1.7\n- fetchai/signing:1.1.7\n- fetchai/state_update:1.1.7\nskills:\n- fetchai/generic_seller:0.28.6\n- fetchai/thermometer:0.27.6\ndefault_connection: fetchai/p2p_libp2p:0.27.5\ndefault_ledger: fetchai\nrequired_ledgers:\n- fetchai\nlogging_config:\n  disable_existing_loggers: false\n  version: 1\nprivate_key_paths: {}\ndefault_routing:\n  fetchai/ledger_api:1.1.7: fetchai/ledger:0.21.5\n  fetchai/oef_search:1.1.7: fetchai/soef:0.27.6\nconnection_private_key_paths: {}\ndependencies:\n  aea-ledger-fetchai:\n    version: <2.0.0,>=1.0.0\n"
  },
  {
    "path": "packages/fetchai/agents/thermometer_client/README.md",
    "content": "# Thermometer Client\n\nThis agent buys thermometer data.\n\n## Description\n\nThis agent is part of the Fetch.ai thermometer demo. It uses its primary skill, the `fetchai/thermometer_client` skill, to find an agent selling thermometer data on the `SOEF` service.\n\nOnce found, it requests data from a thermometer reading, negotiates the price using the `fetchai/fipa` protocol, and if an agreement is reached, pays the proposed amount and receives the data.\n\n## Links\n\n- <a href=\"https://docs.fetch.ai/aea/thermometer-skills/\" target=\"_blank\">Thermometer Demo</a>\n"
  },
  {
    "path": "packages/fetchai/agents/thermometer_client/aea-config.yaml",
    "content": "agent_name: thermometer_client\nauthor: fetchai\nversion: 0.32.5\ndescription: An AEA that purchases thermometer data.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint: {}\nfingerprint_ignore_patterns: []\nconnections:\n- fetchai/ledger:0.21.5\n- fetchai/p2p_libp2p:0.27.5\n- fetchai/soef:0.27.6\ncontracts: []\nprotocols:\n- fetchai/default:1.1.7\n- fetchai/fipa:1.1.7\n- fetchai/ledger_api:1.1.7\n- fetchai/oef_search:1.1.7\n- fetchai/signing:1.1.7\n- fetchai/state_update:1.1.7\nskills:\n- fetchai/generic_buyer:0.27.6\n- fetchai/thermometer_client:0.26.6\ndefault_connection: fetchai/p2p_libp2p:0.27.5\ndefault_ledger: fetchai\nrequired_ledgers:\n- fetchai\nlogging_config:\n  disable_existing_loggers: false\n  version: 1\nprivate_key_paths: {}\ndefault_routing:\n  fetchai/ledger_api:1.1.7: fetchai/ledger:0.21.5\n  fetchai/oef_search:1.1.7: fetchai/soef:0.27.6\nconnection_private_key_paths: {}\ndependencies:\n  aea-ledger-fetchai:\n    version: <2.0.0,>=1.0.0\n"
  },
  {
    "path": "packages/fetchai/agents/weather_client/README.md",
    "content": "# Weather Client\n\nThis agent buys dummy weather data.\n\n## Description\n\nThis agent is part of the Fetch.ai weather demo. It uses its primary skill, the `fetchai/weather_client` skill, to find an agent selling weather data on the `SOEF` service.\n\nOnce found, it requests weather data for specific dates, negotiates the price using the `fetchai/fipa` protocol, and if an agreement is reached, pays the proposed amount and receives the data.\n\n## Links\n\n- <a href=\"https://docs.fetch.ai/aea/weather-skills/\" target=\"_blank\">Weather Demo</a>\n"
  },
  {
    "path": "packages/fetchai/agents/weather_client/aea-config.yaml",
    "content": "agent_name: weather_client\nauthor: fetchai\nversion: 0.33.5\ndescription: This AEA purchases weather data from the weather station.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint: {}\nfingerprint_ignore_patterns: []\nconnections:\n- fetchai/ledger:0.21.5\n- fetchai/p2p_libp2p:0.27.5\n- fetchai/soef:0.27.6\ncontracts: []\nprotocols:\n- fetchai/default:1.1.7\n- fetchai/fipa:1.1.7\n- fetchai/ledger_api:1.1.7\n- fetchai/oef_search:1.1.7\n- fetchai/signing:1.1.7\n- fetchai/state_update:1.1.7\nskills:\n- fetchai/generic_buyer:0.27.6\n- fetchai/weather_client:0.26.6\ndefault_connection: fetchai/p2p_libp2p:0.27.5\ndefault_ledger: fetchai\nrequired_ledgers:\n- fetchai\nlogging_config:\n  disable_existing_loggers: false\n  version: 1\nprivate_key_paths: {}\ndefault_routing:\n  fetchai/ledger_api:1.1.7: fetchai/ledger:0.21.5\n  fetchai/oef_search:1.1.7: fetchai/soef:0.27.6\nconnection_private_key_paths: {}\ndependencies:\n  aea-ledger-fetchai:\n    version: <2.0.0,>=1.0.0\n"
  },
  {
    "path": "packages/fetchai/agents/weather_station/README.md",
    "content": "# Weather Station\n\nThis agent sells dummy weather data.\n\n## Description\n\nThis agent is part of the Fetch.ai weather demo. It uses its primary skill, the `fetchai/weather_station` skill, to registers its 'weather-data-selling' service on the `SOEF`. This data comes from a database that is populated with dummy data from a weather station.\n\nIt can be contacted by another agent (for example the `fetchai/weather_client` agent) to provide weather data for specific dates..\n\nOnce such a request is made, this agent negotiates the terms of trade using the `fetchai/fipa` protocol, and if an agreement is reached, it delivers the weather data after receiving payment.\n\n## Links\n\n- <a href=\"https://docs.fetch.ai/aea/weather-skills/\" target=\"_blank\">Weather Demo</a>\n"
  },
  {
    "path": "packages/fetchai/agents/weather_station/aea-config.yaml",
    "content": "agent_name: weather_station\nauthor: fetchai\nversion: 0.32.5\ndescription: This AEA represents a weather station selling weather data.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint: {}\nfingerprint_ignore_patterns: []\nconnections:\n- fetchai/ledger:0.21.5\n- fetchai/p2p_libp2p:0.27.5\n- fetchai/soef:0.27.6\ncontracts: []\nprotocols:\n- fetchai/default:1.1.7\n- fetchai/fipa:1.1.7\n- fetchai/ledger_api:1.1.7\n- fetchai/oef_search:1.1.7\n- fetchai/signing:1.1.7\n- fetchai/state_update:1.1.7\nskills:\n- fetchai/generic_seller:0.28.6\n- fetchai/weather_station:0.27.6\ndefault_connection: fetchai/p2p_libp2p:0.27.5\ndefault_ledger: fetchai\nrequired_ledgers:\n- fetchai\nlogging_config:\n  disable_existing_loggers: false\n  version: 1\nprivate_key_paths: {}\ndefault_routing:\n  fetchai/ledger_api:1.1.7: fetchai/ledger:0.21.5\n  fetchai/oef_search:1.1.7: fetchai/soef:0.27.6\nconnection_private_key_paths: {}\ndependencies:\n  aea-ledger-fetchai:\n    version: <2.0.0,>=1.0.0\n"
  },
  {
    "path": "packages/fetchai/connections/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the connection packages authored by Fetch.ai\"\"\"\n"
  },
  {
    "path": "packages/fetchai/connections/gym/README.md",
    "content": "# Gym connection\n\nConnection providing access to the gym interface (<https://github.com/openai/gym>) for training reinforcement learning systems.\n\nThe connection wraps a gym and allows the AEA to interact with the gym interface via the `gym` protocol.\n\n## Usage\n\nFirst, add the connection to your AEA project (`aea add connection fetchai/gym:0.20.6`). Then, update the `config` in `connection.yaml` by providing a dotted path to the gym module in the `env` field.\n"
  },
  {
    "path": "packages/fetchai/connections/gym/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Implementation of the Gym connection.\"\"\"\n"
  },
  {
    "path": "packages/fetchai/connections/gym/connection.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Gym connector and gym channel.\"\"\"\n\nimport asyncio\nimport logging\nfrom asyncio import CancelledError\nfrom asyncio.events import AbstractEventLoop\nfrom concurrent.futures.thread import ThreadPoolExecutor\nfrom typing import Any, Callable, Dict, Optional, Tuple, Union, cast\n\nimport gym\n\nfrom aea.common import Address\nfrom aea.configurations.base import PublicId\nfrom aea.connections.base import Connection, ConnectionStates\nfrom aea.exceptions import enforce\nfrom aea.helpers.base import locate\nfrom aea.mail.base import Envelope, Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\n\nfrom packages.fetchai.protocols.gym.dialogues import GymDialogue\nfrom packages.fetchai.protocols.gym.dialogues import GymDialogues as BaseGymDialogues\nfrom packages.fetchai.protocols.gym.message import GymMessage\n\n\n_default_logger = logging.getLogger(\"aea.packages.fetchai.connections.gym\")\n\nPUBLIC_ID = PublicId.from_str(\"fetchai/gym:0.20.6\")\n\n\nclass GymDialogues(BaseGymDialogues):\n    \"\"\"The dialogues class keeps track of all gym dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            # The gym connection maintains the dialogue on behalf of the environment\n            return GymDialogue.Role.ENVIRONMENT\n\n        BaseGymDialogues.__init__(\n            self,\n            self_address=str(PUBLIC_ID),\n            role_from_first_message=role_from_first_message,\n            **kwargs,\n        )\n\n\nclass GymChannel:\n    \"\"\"A wrapper of the gym environment.\"\"\"\n\n    THREAD_POOL_SIZE = 3\n\n    def __init__(self, address: Address, gym_env: gym.Env):\n        \"\"\"Initialize a gym channel.\"\"\"\n        self.address = address\n        self.gym_env = gym_env\n        self._loop: Optional[AbstractEventLoop] = None\n        self._queue: Optional[asyncio.Queue] = None\n        self._threaded_pool: ThreadPoolExecutor = ThreadPoolExecutor(\n            self.THREAD_POOL_SIZE\n        )\n        self.logger: Union[logging.Logger, logging.LoggerAdapter] = _default_logger\n        self._dialogues = GymDialogues()\n\n    def _get_message_and_dialogue(\n        self, envelope: Envelope\n    ) -> Tuple[GymMessage, Optional[GymDialogue]]:\n        \"\"\"\n        Get a message copy and dialogue related to this message.\n\n        :param envelope: incoming envelope\n\n        :return: Tuple[Message, Optional[Dialogue]]\n        \"\"\"\n        message = cast(GymMessage, envelope.message)\n        dialogue = cast(GymDialogue, self._dialogues.update(message))\n        return message, dialogue\n\n    @property\n    def queue(self) -> asyncio.Queue:\n        \"\"\"Check queue is set and return queue.\"\"\"\n        if self._queue is None:  # pragma: nocover\n            raise ValueError(\"Channel is not connected\")\n        return self._queue\n\n    async def connect(self) -> None:\n        \"\"\"\n        Connect an address to the gym.\n\n        :return: an asynchronous queue, that constitutes the communication channel.\n        \"\"\"\n        if self._queue:  # pragma: nocover\n            return None\n        self._loop = asyncio.get_event_loop()\n        self._queue = asyncio.Queue()\n\n    async def send(self, envelope: Envelope) -> None:\n        \"\"\"\n        Process the envelopes to the gym.\n\n        :param envelope: the envelope\n        \"\"\"\n        sender = envelope.sender\n        self.logger.debug(\"Processing message from {}: {}\".format(sender, envelope))\n        if envelope.protocol_specification_id != GymMessage.protocol_specification_id:\n            raise ValueError(\"This protocol is not valid for gym.\")\n        await self.handle_gym_message(envelope)\n\n    async def _run_in_executor(\n        self, fn: Callable, *args: Any\n    ) -> Tuple[Any, float, bool, Dict]:\n        if self._loop is None:  # pragma: nocover\n            raise ValueError(\"Loop not set!\")\n        return await self._loop.run_in_executor(self._threaded_pool, fn, *args)\n\n    async def handle_gym_message(self, envelope: Envelope) -> None:\n        \"\"\"\n        Forward a message to gym.\n\n        :param envelope: the envelope\n        \"\"\"\n        enforce(\n            isinstance(envelope.message, GymMessage), \"Message not of type GymMessage\"\n        )\n        gym_message, dialogue = self._get_message_and_dialogue(envelope)\n\n        if dialogue is None:\n            self.logger.warning(\n                \"Could not create dialogue from message={}\".format(gym_message)\n            )\n            return\n\n        if gym_message.performative == GymMessage.Performative.ACT:\n            action = gym_message.action.any\n            step_id = gym_message.step_id\n\n            observation, reward, done, info = await self._run_in_executor(\n                self.gym_env.step, action\n            )\n\n            msg = dialogue.reply(\n                performative=GymMessage.Performative.PERCEPT,\n                target_message=gym_message,\n                observation=GymMessage.AnyObject(observation),\n                reward=reward,\n                done=done,\n                info=GymMessage.AnyObject(info),\n                step_id=step_id,\n            )\n        elif gym_message.performative == GymMessage.Performative.RESET:\n            await self._run_in_executor(self.gym_env.reset)\n            msg = dialogue.reply(\n                performative=GymMessage.Performative.STATUS,\n                target_message=gym_message,\n                content={\"reset\": \"success\"},\n            )\n        elif gym_message.performative == GymMessage.Performative.CLOSE:\n            await self._run_in_executor(self.gym_env.close)\n            return\n        envelope = Envelope(\n            to=msg.to,\n            sender=msg.sender,\n            message=msg,\n        )\n        await self._send(envelope)\n\n    async def _send(self, envelope: Envelope) -> None:\n        \"\"\"Send a message.\n\n        :param envelope: the envelope\n        \"\"\"\n        await self.queue.put(envelope)\n\n    async def disconnect(self) -> None:\n        \"\"\"Disconnect.\"\"\"\n        if self._queue is not None:\n            await self._queue.put(None)\n            self._queue = None\n\n    async def get(self) -> Optional[Envelope]:\n        \"\"\"Get incoming envelope.\"\"\"\n        return await self.queue.get()\n\n\nclass GymConnection(Connection):\n    \"\"\"Proxy to the functionality of the gym.\"\"\"\n\n    connection_id = PUBLIC_ID\n\n    def __init__(self, gym_env: Optional[gym.Env] = None, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize a connection to a local gym environment.\n\n        :param gym_env: the gym environment (this cannot be loaded by AEA loader).\n        :param kwargs: the keyword arguments of the parent class.\n        \"\"\"\n        super().__init__(**kwargs)\n        if gym_env is None:\n            gym_env_package = cast(str, self.configuration.config.get(\"env\"))\n            if gym_env_package is None:  # pragma: nocover\n                raise ValueError(\"`env` must be set in configuration!\")\n            gym_env_class = locate(gym_env_package)\n            gym_env = gym_env_class()\n        self.channel = GymChannel(self.address, gym_env)\n        self._connection = None  # type: Optional[asyncio.Queue]\n\n    async def connect(self) -> None:\n        \"\"\"Connect to the gym.\"\"\"\n        if self.is_connected:  # pragma: nocover\n            return\n\n        with self._connect_context():\n            self.channel.logger = self.logger\n            await self.channel.connect()\n\n    async def disconnect(self) -> None:\n        \"\"\"Disconnect from the gym.\"\"\"\n        if self.is_disconnected:  # pragma: nocover\n            return\n\n        self.state = ConnectionStates.disconnecting\n        await self.channel.disconnect()\n        self.state = ConnectionStates.disconnected\n\n    async def send(self, envelope: Envelope) -> None:\n        \"\"\"\n        Send an envelope.\n\n        :param envelope: the envelop\n        \"\"\"\n        self._ensure_connected()\n        await self.channel.send(envelope)\n\n    async def receive(self, *args: Any, **kwargs: Any) -> Optional[\"Envelope\"]:\n        \"\"\"Receive an envelope.\"\"\"\n        self._ensure_connected()\n        try:\n            envelope = await self.channel.get()\n            return envelope\n        except CancelledError:  # pragma: no cover\n            return None\n"
  },
  {
    "path": "packages/fetchai/connections/gym/connection.yaml",
    "content": "name: gym\nauthor: fetchai\nversion: 0.20.6\ntype: connection\ndescription: The gym connection wraps an OpenAI gym.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: QmbQw2EjS2WJYrmf1H7AJkdJfewXAWyYkfGqL1k9DBe1hs\n  __init__.py: QmaxS1pbCJtyT7zjAamvEnwLyR1LdrHK6VDcfN45jFgwQH\n  connection.py: QmP316GNMBHiuFuPhcgLHdwYsoH7ejwxCtGJSNodnDhyWa\nfingerprint_ignore_patterns: []\nconnections: []\nprotocols:\n- fetchai/gym:1.1.7\nclass_name: GymConnection\nconfig:\n  env: ''\nexcluded_protocols: []\nrestricted_to_protocols:\n- fetchai/gym:1.1.7\ndependencies:\n  gym: {}\nis_abstract: false\n"
  },
  {
    "path": "packages/fetchai/connections/http_client/README.md",
    "content": "# HTTP client connection\n\nThis connection wraps an HTTP client. It consumes messages from the AEA, translates them into HTTP requests, then sends the HTTP response as a message back to the AEA.\n\n## Usage\n\nFirst, add the connection to your AEA project (`aea add connection fetchai/http_client:0.24.6`). Then, update the `config` in `connection.yaml` by providing a `host` and `port` of the server.\n"
  },
  {
    "path": "packages/fetchai/connections/http_client/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Implementation of the HTTP_client connection and channel.\"\"\"\n"
  },
  {
    "path": "packages/fetchai/connections/http_client/connection.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"HTTP client connection and channel.\"\"\"\nimport asyncio\nimport email\nimport logging\nimport ssl\nfrom asyncio import CancelledError\nfrom asyncio.events import AbstractEventLoop\nfrom asyncio.tasks import Task\nfrom traceback import format_exc\nfrom typing import Any, Optional, Set, Tuple, cast\n\nimport aiohttp\nimport certifi  # pylint: disable=wrong-import-order\nfrom aiohttp.client_reqrep import ClientResponse\nfrom multidict import CIMultiDict, CIMultiDictProxy\n\nfrom aea.common import Address\nfrom aea.configurations.base import PublicId\nfrom aea.connections.base import Connection, ConnectionStates\nfrom aea.exceptions import enforce\nfrom aea.mail.base import Envelope, Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\n\nfrom packages.fetchai.protocols.http.dialogues import HttpDialogue as BaseHttpDialogue\nfrom packages.fetchai.protocols.http.dialogues import HttpDialogues as BaseHttpDialogues\nfrom packages.fetchai.protocols.http.message import HttpMessage\n\n\nSUCCESS = 200\nNOT_FOUND = 404\nREQUEST_TIMEOUT = 408\nSERVER_ERROR = 500\nPUBLIC_ID = PublicId.from_str(\"fetchai/http_client:0.24.6\")\n\n_default_logger = logging.getLogger(\"aea.packages.fetchai.connections.http_client\")\n\nRequestId = str\n\nssl_context = ssl.create_default_context(cafile=certifi.where())\n\n\ndef headers_to_string(headers: CIMultiDictProxy) -> str:\n    \"\"\"\n    Convert headers to string.\n\n    :param headers: dict\n\n    :return: str\n    \"\"\"\n    msg = email.message.Message()\n    for name, value in headers.items():\n        msg.add_header(name, value)\n    return msg.as_string()\n\n\nHttpDialogue = BaseHttpDialogue\n\n\nclass HttpDialogues(BaseHttpDialogues):\n    \"\"\"The dialogues class keeps track of all http dialogues.\"\"\"\n\n    def __init__(self) -> None:\n        \"\"\"Initialize dialogues.\"\"\"\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            # The client connection maintains the dialogue on behalf of the server\n            return HttpDialogue.Role.SERVER\n\n        BaseHttpDialogues.__init__(\n            self,\n            self_address=str(HTTPClientConnection.connection_id),\n            role_from_first_message=role_from_first_message,\n            dialogue_class=HttpDialogue,\n        )\n\n\nclass HTTPClientAsyncChannel:\n    \"\"\"A wrapper for a HTTPClient.\"\"\"\n\n    DEFAULT_TIMEOUT = 300  # default timeout in seconds\n    DEFAULT_EXCEPTION_CODE = (\n        600  # custom code to indicate there was exception during request\n    )\n\n    def __init__(\n        self,\n        agent_address: Address,\n        address: str,\n        port: int,\n        connection_id: PublicId,\n    ):\n        \"\"\"\n        Initialize an http client channel.\n\n        :param agent_address: the address of the agent.\n        :param address: server hostname / IP address\n        :param port: server port number\n        :param connection_id: the id of the connection\n        \"\"\"\n        self.agent_address = agent_address\n        self.address = address\n        self.port = port\n        self.connection_id = connection_id\n        self._dialogues = HttpDialogues()\n\n        self._in_queue = None  # type: Optional[asyncio.Queue]  # pragma: no cover\n        self._loop = (\n            None\n        )  # type: Optional[asyncio.AbstractEventLoop]  # pragma: no cover\n        self.is_stopped = True\n        self._tasks: Set[Task] = set()\n\n        self.logger = _default_logger\n        self.logger.debug(\"Initialised the HTTP client channel\")\n\n    async def connect(self, loop: AbstractEventLoop) -> None:\n        \"\"\"\n        Connect channel using loop.\n\n        :param loop: asyncio event loop to use\n        \"\"\"\n        self._loop = loop\n        self._in_queue = asyncio.Queue()\n        self.is_stopped = False\n\n    def _get_message_and_dialogue(\n        self, envelope: Envelope\n    ) -> Tuple[HttpMessage, Optional[HttpDialogue]]:\n        \"\"\"\n        Get a message copy and dialogue related to this message.\n\n        :param envelope: incoming envelope\n\n        :return: Tuple[MEssage, Optional[Dialogue]]\n        \"\"\"\n        message = cast(HttpMessage, envelope.message)\n        dialogue = cast(Optional[HttpDialogue], self._dialogues.update(message))\n        return message, dialogue\n\n    async def _http_request_task(self, request_envelope: Envelope) -> None:\n        \"\"\"\n        Perform http request and send back response.\n\n        :param request_envelope: request envelope.\n        \"\"\"\n        if not self._loop:  # pragma: nocover\n            raise ValueError(\"Channel is not connected\")\n\n        request_http_message, dialogue = self._get_message_and_dialogue(\n            request_envelope\n        )\n\n        if not dialogue:\n            self.logger.warning(\n                \"Could not create dialogue for message={}\".format(request_http_message)\n            )\n            return\n\n        try:\n            resp = await asyncio.wait_for(\n                self._perform_http_request(request_http_message),\n                timeout=self.DEFAULT_TIMEOUT,\n            )\n            envelope = self.to_envelope(\n                request_http_message,\n                status_code=resp.status,\n                headers=resp.headers,\n                status_text=resp.reason,\n                body=resp._body  # pylint: disable=protected-access\n                if resp._body is not None  # pylint: disable=protected-access\n                else b\"\",\n                dialogue=dialogue,\n            )\n        except Exception:  # pylint: disable=broad-except\n            envelope = self.to_envelope(\n                request_http_message,\n                status_code=self.DEFAULT_EXCEPTION_CODE,\n                headers=CIMultiDictProxy(CIMultiDict()),\n                status_text=\"HTTPConnection request error.\",\n                body=format_exc().encode(\"utf-8\"),\n                dialogue=dialogue,\n            )\n\n        if self._in_queue is not None:\n            await self._in_queue.put(envelope)\n\n    async def _perform_http_request(\n        self, request_http_message: HttpMessage\n    ) -> ClientResponse:\n        \"\"\"\n        Perform http request and return response.\n\n        :param request_http_message: HttpMessage with http request constructed.\n\n        :return: aiohttp.ClientResponse\n        \"\"\"\n        try:\n            if request_http_message.is_set(\"headers\") and request_http_message.headers:\n                headers: Optional[dict] = dict(\n                    email.message_from_string(request_http_message.headers).items()\n                )\n            else:\n                headers = None\n            async with aiohttp.ClientSession() as session:\n                async with session.request(\n                    method=request_http_message.method,\n                    url=request_http_message.url,\n                    headers=headers,\n                    data=request_http_message.body,\n                    ssl=ssl_context,\n                ) as resp:\n                    await resp.read()\n                return resp\n        except Exception:  # pragma: nocover # pylint: disable=broad-except\n            self.logger.exception(\n                f\"Exception raised during http call: {request_http_message.method} {request_http_message.url}\"\n            )\n            raise\n\n    def send(self, request_envelope: Envelope) -> None:\n        \"\"\"\n        Send an envelope with http request data to request.\n\n        Convert an http envelope into an http request.\n        Send the http request\n        Wait for and receive its response\n        Translate the response into a response envelop.\n        Send the response envelope to the in-queue.\n\n        :param request_envelope: the envelope containing an http request\n        \"\"\"\n        if self._loop is None or self.is_stopped:\n            raise ValueError(\"Can not send a message! Channel is not started!\")\n\n        if request_envelope is None:\n            return\n\n        enforce(\n            isinstance(request_envelope.message, HttpMessage),\n            \"Message not of type HttpMessage\",\n        )\n\n        request_http_message = cast(HttpMessage, request_envelope.message)\n\n        if (\n            request_http_message.performative != HttpMessage.Performative.REQUEST\n        ):  # pragma: nocover\n            self.logger.warning(\n                \"The HTTPMessage performative must be a REQUEST. Envelop dropped.\"\n            )\n            return\n\n        task = self._loop.create_task(self._http_request_task(request_envelope))\n        task.add_done_callback(self._task_done_callback)\n        self._tasks.add(task)\n\n    def _task_done_callback(self, task: Task) -> None:\n        \"\"\"\n        Handle http request task completed.\n\n        Removes tasks from _tasks.\n\n        :param task: Task completed.\n        \"\"\"\n        self._tasks.remove(task)\n        self.logger.debug(f\"Task completed: {task}\")\n\n    async def get_message(self) -> Optional[\"Envelope\"]:\n        \"\"\"\n        Get http response from in-queue.\n\n        :return: None or envelope with http response.\n        \"\"\"\n        if self._in_queue is None:\n            raise ValueError(\"Looks like channel is not connected!\")\n\n        try:\n            return await self._in_queue.get()\n        except CancelledError:  # pragma: nocover\n            return None\n\n    @staticmethod\n    def to_envelope(\n        http_request_message: HttpMessage,\n        status_code: int,\n        headers: CIMultiDictProxy,\n        status_text: Optional[Any],\n        body: bytes,\n        dialogue: HttpDialogue,\n    ) -> Envelope:\n        \"\"\"\n        Convert an HTTP response object (from the 'requests' library) into an Envelope containing an HttpMessage (from the 'http' Protocol).\n\n        :param http_request_message: the message of the http request envelop\n        :param status_code: the http status code, int\n        :param headers: dict of http response headers\n        :param status_text: the http status_text, str\n        :param body: bytes of http response content\n        :param dialogue: the http dialogue\n\n        :return: Envelope with http response data.\n        \"\"\"\n        http_message = dialogue.reply(\n            performative=HttpMessage.Performative.RESPONSE,\n            target_message=http_request_message,\n            status_code=status_code,\n            headers=headers_to_string(headers),\n            status_text=status_text,\n            body=body,\n            version=\"\",\n        )\n        envelope = Envelope(\n            to=http_message.to,\n            sender=http_message.sender,\n            message=http_message,\n        )\n        return envelope\n\n    async def _cancel_tasks(self) -> None:\n        \"\"\"Cancel all requests tasks pending.\"\"\"\n        for task in list(self._tasks):\n            if task.done():  # pragma: nocover\n                continue\n            task.cancel()\n\n        for task in list(self._tasks):\n            try:\n                await task\n            except KeyboardInterrupt:  # pragma: nocover\n                raise\n            except BaseException:  # pragma: nocover # pylint: disable=broad-except\n                pass  # nosec\n\n    async def disconnect(self) -> None:\n        \"\"\"Disconnect.\"\"\"\n        if not self.is_stopped:\n            self.logger.info(\"HTTP Client has shutdown on port: {}.\".format(self.port))\n            self.is_stopped = True\n\n            await self._cancel_tasks()\n\n\nclass HTTPClientConnection(Connection):\n    \"\"\"Proxy to the functionality of the web client.\"\"\"\n\n    connection_id = PUBLIC_ID\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize a HTTP client connection.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        super().__init__(**kwargs)\n        host = cast(str, self.configuration.config.get(\"host\"))\n        port = cast(int, self.configuration.config.get(\"port\"))\n        if host is None or port is None:  # pragma: nocover\n            raise ValueError(\"host and port must be set!\")\n        self.channel = HTTPClientAsyncChannel(\n            self.address,\n            host,\n            port,\n            connection_id=self.connection_id,\n        )\n\n    async def connect(self) -> None:\n        \"\"\"Connect to a HTTP server.\"\"\"\n        if self.is_connected:  # pragma: nocover\n            return\n\n        with self._connect_context():\n            self.channel.logger = self.logger\n            await self.channel.connect(self.loop)\n\n    async def disconnect(self) -> None:\n        \"\"\"Disconnect from a HTTP server.\"\"\"\n        if self.is_disconnected:\n            return  # pragma: nocover\n        self.state = ConnectionStates.disconnecting\n        await self.channel.disconnect()\n        self.state = ConnectionStates.disconnected\n\n    async def send(self, envelope: \"Envelope\") -> None:\n        \"\"\"\n        Send an envelope.\n\n        :param envelope: the envelop\n        \"\"\"\n        self._ensure_connected()\n        self.channel.send(envelope)\n\n    async def receive(self, *args: Any, **kwargs: Any) -> Optional[\"Envelope\"]:\n        \"\"\"\n        Receive an envelope.\n\n        :param args: positional arguments\n        :param kwargs: keyword arguments\n        :return: the envelope received, or None.\n        \"\"\"\n        self._ensure_connected()\n        try:\n            return await self.channel.get_message()\n        except Exception:  # pragma: nocover # pylint: disable=broad-except\n            self.logger.exception(\"Exception on receive\")\n            return None\n"
  },
  {
    "path": "packages/fetchai/connections/http_client/connection.yaml",
    "content": "name: http_client\nauthor: fetchai\nversion: 0.24.6\ntype: connection\ndescription: The HTTP_client connection that wraps a web-based client connecting to\n  a RESTful API specification.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: QmaAq5Ed75yQRZaSPWMksAC6JWTzvWfo1ustNjuMQBJ1WX\n  __init__.py: QmNsJsfE93PYUGgj7GqndT4aRoZ39ruL9zF3MMrbFcuE9a\n  connection.py: QmRPbv2Rhw7akb9BsNsZWFDfk9wChkEi1xxnWfqhFoTfsP\nfingerprint_ignore_patterns: []\nconnections: []\nprotocols:\n- fetchai/http:1.1.7\nclass_name: HTTPClientConnection\nconfig:\n  host: 127.0.0.1\n  port: 8000\nexcluded_protocols: []\nrestricted_to_protocols:\n- fetchai/http:1.1.7\ndependencies:\n  aiohttp:\n    version: <3.8,>=3.7.4\nis_abstract: false\n"
  },
  {
    "path": "packages/fetchai/connections/http_server/README.md",
    "content": "# HTTP server connection\n\nThis connection wraps an HTTP server. It consumes requests from clients, translates them into messages for the AEA, waits for a response message from the AEA, then serves the response to the client.\n\n## Usage\n\nFirst, add the connection to your AEA project (`aea add connection fetchai/http_server:0.23.6`). Then, update the `config` in `connection.yaml` by providing a `host` and `port` of the server. Optionally, provide a path to an [OpenAPI specification](https://swagger.io/docs/specification/about/) for request validation.\n"
  },
  {
    "path": "packages/fetchai/connections/http_server/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Implementation of the HTTP connection and channel.\"\"\"\n"
  },
  {
    "path": "packages/fetchai/connections/http_server/connection.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"HTTP server connection, channel, server, and handler.\"\"\"\nimport asyncio\nimport email\nimport logging\nimport ssl\nfrom abc import ABC, abstractmethod\nfrom asyncio import CancelledError\nfrom asyncio.events import AbstractEventLoop\nfrom asyncio.futures import Future\nfrom concurrent.futures._base import CancelledError as FuturesCancelledError\nfrom traceback import format_exc\nfrom typing import Any, Dict, Optional, cast\nfrom urllib.parse import parse_qs, urlparse\n\nfrom aiohttp import web\nfrom aiohttp.web_request import BaseRequest\nfrom openapi_core import create_spec\nfrom openapi_core.validation.request.datatypes import OpenAPIRequest, RequestParameters\nfrom openapi_core.validation.request.shortcuts import validate_request\nfrom openapi_core.validation.request.validators import RequestValidator\nfrom openapi_spec_validator.exceptions import (  # pylint: disable=wrong-import-order\n    OpenAPIValidationError,\n)\nfrom openapi_spec_validator.schemas import (  # pylint: disable=wrong-import-order\n    read_yaml_file,\n)\nfrom werkzeug.datastructures import (  # pylint: disable=wrong-import-order\n    ImmutableMultiDict,\n)\n\nfrom aea.common import Address\nfrom aea.configurations.base import PublicId\nfrom aea.connections.base import Connection, ConnectionStates\nfrom aea.mail.base import Envelope, Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\nfrom aea.protocols.dialogue.base import DialogueLabel\n\nfrom packages.fetchai.protocols.http.dialogues import HttpDialogue\nfrom packages.fetchai.protocols.http.dialogues import HttpDialogues as BaseHttpDialogues\nfrom packages.fetchai.protocols.http.message import HttpMessage\n\n\nSUCCESS = 200\nNOT_FOUND = 404\nREQUEST_TIMEOUT = 408\nSERVER_ERROR = 500\n\n_default_logger = logging.getLogger(\"aea.packages.fetchai.connections.http_server\")\n\nRequestId = DialogueLabel\nPUBLIC_ID = PublicId.from_str(\"fetchai/http_server:0.23.6\")\n\n\nclass HttpDialogues(BaseHttpDialogues):\n    \"\"\"The dialogues class keeps track of all http dialogues.\"\"\"\n\n    def __init__(self, self_address: Address, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param self_address: address of the dialogues maintainer.\n        :param kwargs: keyword arguments.\n        \"\"\"\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            # The server connection maintains the dialogue on behalf of the client\n            return HttpDialogue.Role.CLIENT\n\n        BaseHttpDialogues.__init__(\n            self,\n            self_address=self_address,\n            role_from_first_message=role_from_first_message,\n            **kwargs,\n        )\n\n\ndef headers_to_string(headers: Dict) -> str:\n    \"\"\"\n    Convert headers to string.\n\n    :param headers: dict\n\n    :return: str\n    \"\"\"\n    msg = email.message.Message()\n    for name, value in headers.items():\n        msg.add_header(name, value)\n    return msg.as_string()\n\n\nclass Request(OpenAPIRequest):\n    \"\"\"Generic request object.\"\"\"\n\n    @property\n    def is_id_set(self) -> bool:\n        \"\"\"Check if id is set.\"\"\"\n        return self._id is not None\n\n    @property\n    def id(self) -> RequestId:\n        \"\"\"Get the request id.\"\"\"\n        return self._id\n\n    @id.setter\n    def id(self, request_id: RequestId) -> None:\n        \"\"\"Set the request id.\"\"\"\n        self._id = request_id\n\n    @classmethod\n    async def create(cls, http_request: BaseRequest) -> \"Request\":\n        \"\"\"\n        Create a request.\n\n        :param http_request: http_request\n        :return: a request\n        \"\"\"\n        method = http_request.method.lower()\n\n        parsed_path = urlparse(http_request.path_qs)\n\n        url = http_request.url\n\n        body = await http_request.read()\n\n        mimetype = http_request.content_type\n\n        query_params = parse_qs(parsed_path.query, keep_blank_values=True)\n\n        parameters = RequestParameters(\n            query=ImmutableMultiDict(query_params),  # type: ignore\n            header=headers_to_string(dict(http_request.headers)),\n            path={},\n        )\n\n        request = Request(\n            full_url_pattern=str(url),\n            method=method,\n            parameters=parameters,\n            body=body,\n            mimetype=mimetype,\n        )\n        return request\n\n    def to_envelope_and_set_id(\n        self,\n        dialogues: HttpDialogues,\n        target_skill_id: PublicId,\n    ) -> Envelope:\n        \"\"\"\n        Process incoming API request by packaging into Envelope and sending it in-queue.\n\n        :param dialogues: the http dialogues\n        :param target_skill_id: the target skill id\n\n        :return: envelope\n        \"\"\"\n        url = self.full_url_pattern\n        http_message, http_dialogue = dialogues.create(\n            counterparty=str(target_skill_id),\n            performative=HttpMessage.Performative.REQUEST,\n            method=self.method,\n            url=url,\n            headers=self.parameters.header,\n            body=self.body if self.body is not None else b\"\",\n            version=\"\",\n        )\n        dialogue = cast(HttpDialogue, http_dialogue)\n        self.id = dialogue.incomplete_dialogue_label\n        envelope = Envelope(\n            to=http_message.to,\n            sender=http_message.sender,\n            message=http_message,\n        )\n        return envelope\n\n\nclass Response(web.Response):\n    \"\"\"Generic response object.\"\"\"\n\n    @classmethod\n    def from_message(cls, http_message: HttpMessage) -> \"Response\":\n        \"\"\"\n        Turn an envelope into a response.\n\n        :param http_message: the http_message\n        :return: the response\n        \"\"\"\n        if http_message.performative == HttpMessage.Performative.RESPONSE:\n\n            if http_message.is_set(\"headers\") and http_message.headers:\n                headers: Optional[dict] = dict(\n                    email.message_from_string(http_message.headers).items()\n                )\n            else:\n                headers = None\n\n            # if content length header provided, it should correspond to actuyal body length\n            if headers and \"Content-Length\" in headers:\n                headers[\"Content-Length\"] = str(len(http_message.body or \"\"))\n\n            response = cls(\n                status=http_message.status_code,\n                reason=http_message.status_text,\n                body=http_message.body,\n                headers=headers,\n            )\n        else:  # pragma: nocover\n            response = cls(status=SERVER_ERROR, text=\"Server error\")\n        return response\n\n\nclass APISpec:\n    \"\"\"API Spec class to verify a request against an OpenAPI/Swagger spec.\"\"\"\n\n    def __init__(\n        self,\n        api_spec_path: Optional[str] = None,\n        server: Optional[str] = None,\n        logger: logging.Logger = _default_logger,\n    ):\n        \"\"\"\n        Initialize the API spec.\n\n        :param api_spec_path: Directory API path and filename of the API spec YAML source file.\n        :param server: the server url\n        :param logger: the logger\n        \"\"\"\n        self._validator = None  # type: Optional[RequestValidator]\n        self.logger = logger\n        if api_spec_path is not None:\n            try:\n                api_spec_dict = read_yaml_file(api_spec_path)\n                if server is not None:\n                    api_spec_dict[\"servers\"] = [{\"url\": server}]\n                api_spec = create_spec(api_spec_dict)\n                self._validator = RequestValidator(api_spec)\n            except OpenAPIValidationError as e:  # pragma: nocover\n                self.logger.error(\n                    f\"API specification YAML source file not correctly formatted: {str(e)}\"\n                )\n            except Exception:\n                self.logger.exception(\n                    \"API specification YAML source file not correctly formatted.\"\n                )\n                raise\n\n    def verify(self, request: Request) -> bool:\n        \"\"\"\n        Verify a http_method, url and param against the provided API spec.\n\n        :param request: the request object\n        :return: whether or not the request conforms with the API spec\n        \"\"\"\n        if self._validator is None:\n            self.logger.debug(\"Skipping API verification!\")\n            return True\n\n        try:\n            validate_request(self._validator, request)\n        except Exception:  # pragma: nocover # pylint: disable=broad-except\n            self.logger.exception(\"APISpec verify error\")\n            return False\n        return True\n\n\nclass BaseAsyncChannel(ABC):\n    \"\"\"Base asynchronous channel class.\"\"\"\n\n    def __init__(self, address: Address, connection_id: PublicId) -> None:\n        \"\"\"\n        Initialize a channel.\n\n        :param address: the address of the agent.\n        :param connection_id: public id of connection using this channel.\n        \"\"\"\n        self._in_queue = None  # type: Optional[asyncio.Queue]\n        self._loop = None  # type: Optional[asyncio.AbstractEventLoop]\n        self.is_stopped = True\n        self.address = address\n        self.connection_id = connection_id\n\n    @abstractmethod\n    async def connect(self, loop: AbstractEventLoop) -> None:\n        \"\"\"\n        Connect.\n\n        Upon HTTP Channel connection, start the HTTP Server in its own thread.\n\n        :param loop: asyncio event loop\n        \"\"\"\n        self._loop = loop\n        self._in_queue = asyncio.Queue()\n        self.is_stopped = False\n\n    async def get_message(self) -> Optional[\"Envelope\"]:\n        \"\"\"\n        Get http response from in-queue.\n\n        :return: None or envelope with http response.\n        \"\"\"\n        if self._in_queue is None:\n            raise ValueError(\"Looks like channel is not connected!\")\n\n        try:\n            return await self._in_queue.get()\n        except CancelledError:  # pragma: nocover\n            return None\n\n    @abstractmethod\n    def send(self, envelope: Envelope) -> None:\n        \"\"\"\n        Send the envelope in_queue.\n\n        :param envelope: the envelope\n        \"\"\"\n\n    @abstractmethod\n    async def disconnect(self) -> None:\n        \"\"\"\n        Disconnect.\n\n        Shut-off the HTTP Server.\n        \"\"\"\n\n\nclass HTTPChannel(BaseAsyncChannel):\n    \"\"\"A wrapper for an RESTful API with an internal HTTPServer.\"\"\"\n\n    RESPONSE_TIMEOUT = 5.0\n\n    def __init__(\n        self,\n        address: Address,\n        host: str,\n        port: int,\n        target_skill_id: PublicId,\n        api_spec_path: Optional[str],\n        connection_id: PublicId,\n        timeout_window: float = RESPONSE_TIMEOUT,\n        logger: logging.Logger = _default_logger,\n        ssl_cert_path: Optional[str] = None,\n        ssl_key_path: Optional[str] = None,\n    ):\n        \"\"\"\n        Initialize a channel and process the initial API specification from the file path (if given).\n\n        :param address: the address of the agent.\n        :param host: RESTful API hostname / IP address\n        :param port: RESTful API port number\n        :param target_skill_id: the skill id which handles the requests\n        :param api_spec_path: Directory API path and filename of the API spec YAML source file.\n        :param connection_id: public id of connection using this channel.\n        :param timeout_window: the timeout (in seconds) for a request to be handled.\n        :param logger: the logger\n        :param ssl_cert_path:  optional path to ssl certificate\n        :param ssl_key_path: optional path to ssl key\n        \"\"\"\n        super().__init__(address=address, connection_id=connection_id)\n        self.host = host\n        self.port = port\n        self.ssl_cert_path = ssl_cert_path\n        self.ssl_key_path = ssl_key_path\n        self.target_skill_id = target_skill_id\n        if self.ssl_cert_path and self.ssl_key_path:\n            self.server_address = \"https://{}:{}\".format(self.host, self.port)\n        else:\n            self.server_address = \"http://{}:{}\".format(self.host, self.port)\n\n        self._api_spec = APISpec(api_spec_path, self.server_address, logger)\n        self.timeout_window = timeout_window\n        self.http_server: Optional[web.TCPSite] = None\n        self.pending_requests: Dict[RequestId, Future] = {}\n        self._dialogues = HttpDialogues(str(HTTPServerConnection.connection_id))\n        self.logger = logger\n\n    @property\n    def api_spec(self) -> APISpec:\n        \"\"\"Get the api spec.\"\"\"\n        return self._api_spec\n\n    async def connect(self, loop: AbstractEventLoop) -> None:\n        \"\"\"\n        Connect.\n\n        Upon HTTP Channel connection, start the HTTP Server in its own thread.\n\n        :param loop: asyncio event loop\n        \"\"\"\n        if self.is_stopped:\n            await super().connect(loop)\n\n            try:\n                await self._start_http_server()\n                self.logger.info(\n                    \"HTTP Server has connected to port: {}.\".format(self.port)\n                )\n            except Exception:  # pragma: nocover # pylint: disable=broad-except\n                self.is_stopped = True\n                self._in_queue = None\n                self.logger.exception(\n                    \"Failed to start server on {}:{}.\".format(self.host, self.port)\n                )\n\n    async def _http_handler(self, http_request: BaseRequest) -> Response:\n        \"\"\"\n        Verify the request then send the request to Agent as an envelope.\n\n        :param http_request: the request object\n\n        :return: a tuple of response code and response description\n        \"\"\"\n        request = await Request.create(http_request)\n        if self._in_queue is None:  # pragma: nocover\n            raise ValueError(\"Channel not connected!\")\n\n        is_valid_request = self.api_spec.verify(request)\n\n        if not is_valid_request:\n            self.logger.warning(f\"request is not valid: {request}\")\n            return Response(status=NOT_FOUND, reason=\"Request Not Found\")\n\n        try:\n            # turn request into envelope\n            envelope = request.to_envelope_and_set_id(\n                self._dialogues, self.target_skill_id\n            )\n\n            self.pending_requests[request.id] = Future()\n\n            # send the envelope to the agent's inbox (via self.in_queue)\n            await self._in_queue.put(envelope)\n            # wait for response envelope within given timeout window (self.timeout_window) to appear in dispatch_ready_envelopes\n\n            response_message = await asyncio.wait_for(\n                self.pending_requests[request.id],\n                timeout=self.timeout_window,\n            )\n            return Response.from_message(response_message)\n\n        except asyncio.TimeoutError:\n            self.logger.warning(\n                f\"Request timed out! Request={request} not handled as a result. Ensure requests (protocol_id={HttpMessage.protocol_id}) are handled by a skill!\"\n            )\n            return Response(status=REQUEST_TIMEOUT, reason=\"Request Timeout\")\n        except FuturesCancelledError:\n            return Response(  # pragma: nocover\n                status=SERVER_ERROR, reason=\"Server terminated unexpectedly.\"\n            )\n        except BaseException:  # pragma: nocover # pylint: disable=broad-except\n            self.logger.exception(\"Error during handling incoming request\")\n            return Response(\n                status=SERVER_ERROR, reason=\"Server Error\", text=format_exc()\n            )\n        finally:\n            if request.is_id_set:\n                self.pending_requests.pop(request.id, None)\n\n    async def _start_http_server(self) -> None:\n        \"\"\"Start http server.\"\"\"\n        server = web.Server(self._http_handler)\n        runner = web.ServerRunner(server)\n        await runner.setup()\n        ssl_context = None\n        if self.ssl_cert_path and self.ssl_key_path:\n            ssl_context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)\n            ssl_context.load_cert_chain(self.ssl_cert_path, self.ssl_key_path)\n        self.http_server = web.TCPSite(\n            runner, self.host, self.port, ssl_context=ssl_context\n        )\n        await self.http_server.start()\n\n    def send(self, envelope: Envelope) -> None:\n        \"\"\"\n        Send the envelope in_queue.\n\n        :param envelope: the envelope\n        \"\"\"\n        if self.http_server is None:  # pragma: nocover\n            raise ValueError(\"Server not connected, call connect first!\")\n\n        message = cast(HttpMessage, envelope.message)\n        dialogue = self._dialogues.update(message)\n\n        if dialogue is None:\n            self.logger.warning(\n                \"Could not create dialogue for message={}\".format(message)\n            )\n            return\n\n        future = self.pending_requests.pop(dialogue.incomplete_dialogue_label, None)\n\n        if not future:\n            self.logger.warning(\n                \"Dropping message={} for incomplete_dialogue_label={} which has timed out.\".format(\n                    message, dialogue.incomplete_dialogue_label\n                )\n            )\n            return\n        if not future.done():\n            future.set_result(message)\n\n    async def disconnect(self) -> None:\n        \"\"\"\n        Disconnect.\n\n        Shut-off the HTTP Server.\n        \"\"\"\n        if self.http_server is None:  # pragma: nocover\n            raise ValueError(\"Server not connected, call connect first!\")\n\n        if not self.is_stopped:\n            await self.http_server.stop()\n            self.logger.info(\"HTTP Server has shutdown on port: {}.\".format(self.port))\n            self.is_stopped = True\n            self._in_queue = None\n\n\nclass HTTPServerConnection(Connection):\n    \"\"\"Proxy to the functionality of the http server implementing a RESTful API specification.\"\"\"\n\n    connection_id = PUBLIC_ID\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"Initialize a HTTP server connection.\"\"\"\n        super().__init__(**kwargs)\n        host = cast(Optional[str], self.configuration.config.get(\"host\"))\n        port = cast(Optional[int], self.configuration.config.get(\"port\"))\n        target_skill_id_ = cast(\n            Optional[str], self.configuration.config.get(\"target_skill_id\")\n        )\n        if host is None or port is None or target_skill_id_ is None:  # pragma: nocover\n            raise ValueError(\"host and port and target_skill_id must be set!\")\n        target_skill_id = PublicId.try_from_str(target_skill_id_)\n        if target_skill_id is None:  # pragma: nocover\n            raise ValueError(\"Provided target_skill_id is not a valid public id.\")\n        api_spec_path = cast(\n            Optional[str], self.configuration.config.get(\"api_spec_path\")\n        )\n        ssl_cert_path = cast(Optional[str], self.configuration.config.get(\"ssl_cert\"))\n        ssl_key_path = cast(Optional[str], self.configuration.config.get(\"ssl_key\"))\n\n        if bool(ssl_cert_path) != bool(ssl_key_path):  # pragma: nocover\n            raise ValueError(\"Please specify both ssl_cert and ssl_key or neither.\")\n\n        self.channel = HTTPChannel(\n            self.address,\n            host,\n            port,\n            target_skill_id,\n            api_spec_path,\n            connection_id=self.connection_id,\n            logger=self.logger,\n            ssl_cert_path=ssl_cert_path,\n            ssl_key_path=ssl_key_path,\n        )\n\n    async def connect(self) -> None:\n        \"\"\"Connect to the http channel.\"\"\"\n        if self.is_connected:\n            return\n\n        self.state = ConnectionStates.connecting\n        self.channel.logger = self.logger\n        await self.channel.connect(loop=self.loop)\n        if self.channel.is_stopped:\n            self.state = ConnectionStates.disconnected\n        else:\n            self.state = ConnectionStates.connected\n\n    async def disconnect(self) -> None:\n        \"\"\"Disconnect from HTTP channel.\"\"\"\n        if self.is_disconnected:\n            return\n\n        self.state = ConnectionStates.disconnecting\n        await self.channel.disconnect()\n        self.state = ConnectionStates.disconnected\n\n    async def send(self, envelope: \"Envelope\") -> None:\n        \"\"\"\n        Send an envelope.\n\n        :param envelope: the envelop\n        \"\"\"\n        self._ensure_connected()\n        self.channel.send(envelope)\n\n    async def receive(self, *args: Any, **kwargs: Any) -> Optional[\"Envelope\"]:\n        \"\"\"\n        Receive an envelope.\n\n        :param args: positional arguments\n        :param kwargs: keyword arguments\n        :return: the envelope received, or None.\n        \"\"\"\n        self._ensure_connected()\n        try:\n            return await self.channel.get_message()\n        except CancelledError:  # pragma: no cover\n            return None\n"
  },
  {
    "path": "packages/fetchai/connections/http_server/connection.yaml",
    "content": "name: http_server\nauthor: fetchai\nversion: 0.23.6\ntype: connection\ndescription: The HTTP server connection that wraps http server implementing a RESTful\n  API specification.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: QmQKVp9nw9xvQa36AbBQzwrwvvLeuSEE1poy1GNw5egBXG\n  __init__.py: QmPQbWNzuoYoaWQ35b4XUzGUZqwm2YYNg9XpngS4xqCdiZ\n  connection.py: QmaQj91PXE5X9BZBBtei7JAKRWuxjHo8X8oewX5rFKU7VR\nfingerprint_ignore_patterns: []\nconnections: []\nprotocols:\n- fetchai/http:1.1.7\nclass_name: HTTPServerConnection\nconfig:\n  api_spec_path: null\n  host: 127.0.0.1\n  port: 8000\n  ssl_cert: null\n  ssl_key: null\n  target_skill_id: null\nexcluded_protocols: []\nrestricted_to_protocols:\n- fetchai/http:1.1.7\ndependencies:\n  aiohttp:\n    version: <3.8,>=3.7.4\n  openapi-core:\n    version: ==0.13.2\n  openapi-spec-validator:\n    version: ==0.2.8\nis_abstract: false\n"
  },
  {
    "path": "packages/fetchai/connections/ledger/README.md",
    "content": "# Ledger connection\n\nThe ledger connection wraps the APIs needed to interact with multiple ledgers, including smart contracts deployed on those ledgers.\n\nThe AEA communicates with the ledger connection via the `fetchai/ledger_api:1.0.0` and `fetchai/contract_api:1.0.0` protocols.\n\nThe connection uses the ledger APIs registered in the ledger API registry.\n\n## Usage\n\nFirst, add the connection to your AEA project (`aea add connection fetchai/ledger:0.21.5`). Optionally, update the `ledger_apis` in `config` of `connection.yaml`.\n"
  },
  {
    "path": "packages/fetchai/connections/ledger/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Scaffold of a connection.\"\"\"\n"
  },
  {
    "path": "packages/fetchai/connections/ledger/base.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains base classes for the ledger API connection.\"\"\"\nimport asyncio\nfrom abc import ABC, abstractmethod\nfrom asyncio import Task\nfrom concurrent.futures._base import Executor\nfrom logging import Logger\nfrom typing import Any, Callable, Dict, Optional, Union\n\nfrom aea.configurations.base import PublicId\nfrom aea.crypto.base import LedgerApi\nfrom aea.crypto.registries import Registry, ledger_apis_registry\nfrom aea.helpers.async_utils import AsyncState\nfrom aea.mail.base import Envelope\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue, Dialogues\n\n\nCONNECTION_ID = PublicId.from_str(\"fetchai/ledger:0.21.5\")\n\n\nclass RequestDispatcher(ABC):\n    \"\"\"Base class for a request dispatcher.\"\"\"\n\n    TIMEOUT = 3\n    MAX_ATTEMPTS = 120\n\n    def __init__(\n        self,\n        logger: Logger,\n        connection_state: AsyncState,\n        loop: Optional[asyncio.AbstractEventLoop] = None,\n        executor: Optional[Executor] = None,\n        api_configs: Optional[Dict[str, Dict[str, str]]] = None,\n    ):\n        \"\"\"\n        Initialize the request dispatcher.\n\n        :param logger: the logger.\n        :param connection_state: the connection state.\n        :param loop: the asyncio loop.\n        :param executor: an executor.\n        :param api_configs: the configurations of the api.\n        \"\"\"\n        self.connection_state = connection_state\n        self.loop = loop if loop is not None else asyncio.get_event_loop()\n        self.executor = executor\n        self._api_configs = api_configs\n        self.logger = logger\n\n    def api_config(self, ledger_id: str) -> Dict[str, str]:\n        \"\"\"Get api config.\"\"\"\n        config = {}  # type: Dict[str, str]\n        if self._api_configs is not None and ledger_id in self._api_configs:\n            config = self._api_configs[ledger_id]\n        return config\n\n    async def run_async(\n        self,\n        func: Callable[[Any], Task],\n        api: LedgerApi,\n        message: Message,\n        dialogue: Dialogue,\n    ) -> Union[Message, Task]:\n        \"\"\"\n        Run a function in executor.\n\n        :param func: the function to execute.\n        :param api: the ledger api.\n        :param message: the message.\n        :param dialogue: the dialogue.\n        :return: the return value of the function.\n        \"\"\"\n        try:\n            response = await self.loop.run_in_executor(\n                self.executor, func, api, message, dialogue\n            )\n            return response\n        except Exception as e:  # pylint: disable=broad-except\n            return self.get_error_message(e, api, message, dialogue)\n\n    def dispatch(self, envelope: Envelope) -> Task:\n        \"\"\"\n        Dispatch the request to the right sender handler.\n\n        :param envelope: the envelope.\n        :return: an awaitable.\n        \"\"\"\n        if not isinstance(envelope.message, Message):  # pragma: nocover\n            raise ValueError(\"Ledger connection expects non-serialized messages.\")\n        message = envelope.message\n        ledger_id = self.get_ledger_id(message)\n        api = self.ledger_api_registry.make(ledger_id, **self.api_config(ledger_id))\n        dialogue = self.dialogues.update(message)\n        if dialogue is None:\n            raise ValueError(  # pragma: nocover\n                \"No dialogue created. Message={} not valid.\".format(message)\n            )\n        performative = message.performative\n        handler = self.get_handler(performative)\n        return self.loop.create_task(self.run_async(handler, api, message, dialogue))\n\n    def get_handler(self, performative: Any) -> Callable[[Any], Task]:\n        \"\"\"\n        Get the handler method, given the message performative.\n\n        :param performative: the message performative.\n        :return: the method that will send the request.\n        \"\"\"\n        handler = getattr(self, performative.value, None)\n        if handler is None:\n            raise Exception(\"Performative not recognized.\")\n        return handler\n\n    @abstractmethod\n    def get_error_message(\n        self,\n        e: Exception,\n        api: LedgerApi,\n        message: Message,\n        dialogue: Dialogue,\n    ) -> Message:\n        \"\"\"\n        Build an error message.\n\n        :param e: the exception\n        :param api: the ledger api\n        :param message: the received message.\n        :param dialogue: the dialogue.\n        :return: an error message response.\n        \"\"\"\n\n    @property\n    @abstractmethod\n    def dialogues(self) -> Dialogues:\n        \"\"\"Get the dialogues.\"\"\"\n\n    @property\n    def ledger_api_registry(self) -> Registry:\n        \"\"\"Get the registry.\"\"\"\n        return ledger_apis_registry\n\n    @abstractmethod\n    def get_ledger_id(self, message: Message) -> str:\n        \"\"\"Extract the ledger id from the message.\"\"\"\n"
  },
  {
    "path": "packages/fetchai/connections/ledger/connection.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Scaffold connection and channel.\"\"\"\nimport asyncio\nfrom asyncio import Task\nfrom collections import deque\nfrom typing import Any, Deque, Dict, List, Optional, cast\n\nfrom aea.connections.base import Connection, ConnectionStates\nfrom aea.mail.base import Envelope\nfrom aea.protocols.base import Message\n\nfrom packages.fetchai.connections.ledger.base import CONNECTION_ID, RequestDispatcher\nfrom packages.fetchai.connections.ledger.contract_dispatcher import (\n    ContractApiRequestDispatcher,\n)\nfrom packages.fetchai.connections.ledger.ledger_dispatcher import (\n    LedgerApiRequestDispatcher,\n)\nfrom packages.fetchai.protocols.contract_api import ContractApiMessage\nfrom packages.fetchai.protocols.ledger_api import LedgerApiMessage\n\n\nclass LedgerConnection(Connection):\n    \"\"\"Proxy to the functionality of the SDK or API.\"\"\"\n\n    connection_id = CONNECTION_ID\n\n    def __init__(self, **kwargs: Any):\n        \"\"\"Initialize a connection to interact with a ledger APIs.\"\"\"\n        super().__init__(**kwargs)\n\n        self._ledger_dispatcher: Optional[LedgerApiRequestDispatcher] = None\n        self._contract_dispatcher: Optional[ContractApiRequestDispatcher] = None\n        self._event_new_receiving_task: Optional[asyncio.Event] = None\n\n        self.receiving_tasks: List[asyncio.Future] = []\n        self.task_to_request: Dict[asyncio.Future, Envelope] = {}\n        self.done_tasks: Deque[asyncio.Future] = deque()\n        self.api_configs = self.configuration.config.get(\n            \"ledger_apis\", {}\n        )  # type: Dict[str, Dict[str, str]]\n\n    @property\n    def event_new_receiving_task(self) -> asyncio.Event:\n        \"\"\"Get the event to notify the 'receive' method of new receiving tasks.\"\"\"\n        return cast(asyncio.Event, self._event_new_receiving_task)\n\n    async def connect(self) -> None:\n        \"\"\"Set up the connection.\"\"\"\n\n        if self.is_connected:  # pragma: nocover\n            return\n\n        self.state = ConnectionStates.connecting\n\n        self._ledger_dispatcher = LedgerApiRequestDispatcher(\n            self._state,\n            loop=self.loop,\n            api_configs=self.api_configs,\n            logger=self.logger,\n        )\n        self._contract_dispatcher = ContractApiRequestDispatcher(\n            self._state,\n            loop=self.loop,\n            api_configs=self.api_configs,\n            logger=self.logger,\n        )\n        self._event_new_receiving_task = asyncio.Event()\n\n        self.state = ConnectionStates.connected\n\n    async def disconnect(self) -> None:\n        \"\"\"Tear down the connection.\"\"\"\n        if self.is_disconnected:  # pragma: nocover\n            return\n\n        self.state = ConnectionStates.disconnecting\n\n        for task in self.receiving_tasks:\n            if not task.cancelled():  # pragma: nocover\n                task.cancel()\n        self._ledger_dispatcher = None\n        self._contract_dispatcher = None\n        self._event_new_receiving_task = None\n\n        self.state = ConnectionStates.disconnected\n\n    async def send(self, envelope: \"Envelope\") -> None:\n        \"\"\"\n        Send an envelope.\n\n        :param envelope: the envelope to send.\n        \"\"\"\n        task = self._schedule_request(envelope)\n        self.receiving_tasks.append(task)\n        self.task_to_request[task] = envelope\n        self.event_new_receiving_task.set()\n\n    def _schedule_request(self, envelope: Envelope) -> Task:\n        \"\"\"\n        Schedule a ledger API request.\n\n        :param envelope: the message.\n        :return: task\n        \"\"\"\n        dispatcher: RequestDispatcher\n        if (\n            envelope.protocol_specification_id\n            == LedgerApiMessage.protocol_specification_id\n        ):\n            if self._ledger_dispatcher is None:  # pragma: nocover\n                raise ValueError(\"No ledger dispatcher set.\")\n            dispatcher = self._ledger_dispatcher\n        elif (\n            envelope.protocol_specification_id\n            == ContractApiMessage.protocol_specification_id\n        ):\n            if self._contract_dispatcher is None:  # pragma: nocover\n                raise ValueError(\"No contract dispatcher set.\")\n            dispatcher = self._contract_dispatcher\n        else:\n            raise ValueError(\"Protocol not supported\")\n\n        task = dispatcher.dispatch(envelope)\n        return task\n\n    async def receive(self, *args: Any, **kwargs: Any) -> Optional[\"Envelope\"]:\n        \"\"\"\n        Receive an envelope. Blocking.\n\n        :param args: positional arguments\n        :param kwargs: keyword arguments\n        :return: the envelope received, or None.\n        \"\"\"\n        # if there are done tasks, return the result\n        if len(self.done_tasks) > 0:  # pragma: nocover\n            done_task = self.done_tasks.pop()\n            return self._handle_done_task(done_task)\n\n        if len(self.receiving_tasks) == 0:\n            self.event_new_receiving_task.clear()\n            await self.event_new_receiving_task.wait()\n\n        # wait for completion of at least one receiving task\n        done, _ = await asyncio.wait(\n            self.receiving_tasks, return_when=asyncio.FIRST_COMPLETED\n        )\n\n        # pick one done task\n        done_task = done.pop()\n\n        # update done tasks\n        self.done_tasks.extend([*done])\n\n        return self._handle_done_task(done_task)\n\n    def _handle_done_task(self, task: asyncio.Future) -> Optional[Envelope]:\n        \"\"\"\n        Process a done receiving task.\n\n        :param task: the done task.\n        :return: the response envelope.\n        \"\"\"\n        request = self.task_to_request.pop(task)\n        self.receiving_tasks.remove(task)\n        response_message: Optional[Message] = task.result()\n\n        response_envelope = None\n        if response_message is not None:\n            response_envelope = Envelope(\n                to=request.sender,\n                sender=request.to,\n                message=response_message,\n                context=request.context,\n            )\n        return response_envelope\n"
  },
  {
    "path": "packages/fetchai/connections/ledger/connection.yaml",
    "content": "name: ledger\nauthor: fetchai\nversion: 0.21.5\ntype: connection\ndescription: A connection to interact with any ledger API and contract API.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: QmSFv3KfHuN5dhUU5bo6Eem5Df6Ph77GgSP8ZPgKQrRQHN\n  __init__.py: QmaA7o9G1hT3fHtPDq6UYUyS5KY51uDkwMUGUc96odzSCX\n  base.py: QmexgSRbx7AbPP1dfRuqLiU5BYwanYzmLMkQ9ebxHctGqG\n  connection.py: Qmcu2SPDRdoT6jPAfuTAeEfugBppyEM4Ge5FM9hRNKNgzB\n  contract_dispatcher.py: QmaQjpMMUNZXGXUavhofVnaXCQAte7hj4zCmvhWzPPkc5V\n  ledger_dispatcher.py: QmQXRSCdQiYqdb7vX7S95Bhpr5V6sX15fb4f2gzQzvW148\nfingerprint_ignore_patterns: []\nconnections: []\nprotocols:\n- fetchai/contract_api:1.1.7\n- fetchai/ledger_api:1.1.7\nclass_name: LedgerConnection\nconfig:\n  ledger_apis:\n    ethereum:\n      address: http://127.0.0.1:8545\n      gas_price_api_key: null\n    fetchai:\n      address: https://rest-dorado.fetch.ai:443\n      denom: atestfet\n      chain_id: dorado-1\nexcluded_protocols: []\nrestricted_to_protocols:\n- fetchai/contract_api:1.1.7\n- fetchai/ledger_api:1.1.7\ndependencies: {}\nis_abstract: false\n"
  },
  {
    "path": "packages/fetchai/connections/ledger/contract_dispatcher.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the implementation of the contract API request dispatcher.\"\"\"\nimport inspect\nimport logging\nfrom collections.abc import Mapping\nfrom typing import Any, Callable, Optional, Union, cast\n\nfrom aea.common import JSONLike\nfrom aea.contracts import Contract, contract_registry\nfrom aea.crypto.base import LedgerApi\nfrom aea.crypto.registries import Registry\nfrom aea.exceptions import AEAException\nfrom aea.helpers.transaction.base import RawMessage, RawTransaction, State\nfrom aea.protocols.base import Address, Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\nfrom aea.protocols.dialogue.base import Dialogues as BaseDialogues\n\nfrom packages.fetchai.connections.ledger.base import CONNECTION_ID, RequestDispatcher\nfrom packages.fetchai.protocols.contract_api import ContractApiMessage\nfrom packages.fetchai.protocols.contract_api.dialogues import ContractApiDialogue\nfrom packages.fetchai.protocols.contract_api.dialogues import (\n    ContractApiDialogues as BaseContractApiDialogues,\n)\n\n\n_default_logger = logging.getLogger(\n    \"aea.packages.fetchai.connections.ledger.contract_dispatcher\"\n)\n\n\nclass ContractApiDialogues(BaseContractApiDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            # The ledger connection maintains the dialogue on behalf of the ledger\n            return ContractApiDialogue.Role.LEDGER\n\n        BaseContractApiDialogues.__init__(\n            self,\n            self_address=str(CONNECTION_ID),\n            role_from_first_message=role_from_first_message,\n            **kwargs,\n        )\n\n\nclass ContractApiRequestDispatcher(RequestDispatcher):\n    \"\"\"Implement the contract API request dispatcher.\"\"\"\n\n    def __init__(self, *args: Any, **kwargs: Any) -> None:\n        \"\"\"Initialize the dispatcher.\"\"\"\n        logger = kwargs.pop(\"logger\", None)\n        logger = logger if logger is not None else _default_logger\n\n        super().__init__(logger, *args, **kwargs)\n        self._contract_api_dialogues = ContractApiDialogues()\n\n    @property\n    def dialogues(self) -> BaseDialogues:\n        \"\"\"Get the dialogues.\"\"\"\n        return self._contract_api_dialogues\n\n    @property\n    def contract_registry(self) -> Registry[Contract]:\n        \"\"\"Get the contract registry.\"\"\"\n        return contract_registry\n\n    def get_ledger_id(self, message: Message) -> str:\n        \"\"\"Get the ledger id.\"\"\"\n        if not isinstance(message, ContractApiMessage):  # pragma: nocover\n            raise ValueError(\"argument is not a ContractApiMessage instance.\")\n        message = cast(ContractApiMessage, message)\n        return message.ledger_id\n\n    def get_error_message(\n        self,\n        e: Exception,\n        api: LedgerApi,\n        message: Message,\n        dialogue: BaseDialogue,\n    ) -> ContractApiMessage:\n        \"\"\"\n        Build an error message.\n\n        :param e: the exception.\n        :param api: the Ledger API.\n        :param message: the request message.\n        :param dialogue: the dialogue\n        :return: an error message response.\n        \"\"\"\n        response = cast(\n            ContractApiMessage,\n            dialogue.reply(\n                performative=ContractApiMessage.Performative.ERROR,\n                target_message=message,\n                code=500,\n                message=str(e),\n                data=b\"\",\n            ),\n        )\n        return response\n\n    def dispatch_request(\n        self,\n        ledger_api: LedgerApi,\n        message: ContractApiMessage,\n        dialogue: ContractApiDialogue,\n        response_builder: Callable[\n            [Union[bytes, JSONLike], ContractApiDialogue], ContractApiMessage\n        ],\n    ) -> ContractApiMessage:\n        \"\"\"\n        Dispatch a request to a user-defined contract method.\n\n        :param ledger_api: the ledger apis.\n        :param message: the contract API request message.\n        :param dialogue: the contract API dialogue.\n        :param response_builder: callable that from bytes builds a contract API message.\n        :return: the response message.\n        \"\"\"\n        contract = self.contract_registry.make(message.contract_id)\n        try:\n            data = self._get_data(ledger_api, message, contract)\n            response = response_builder(data, dialogue)\n        except AEAException as e:\n            self.logger.error(f\"Exception during contract request: {str(e)}\")\n            response = self.get_error_message(e, ledger_api, message, dialogue)\n        except Exception as e:  # pylint: disable=broad-except  # pragma: nocover\n            self.logger.error(\n                f\"An error occurred while processing the contract api request: '{str(e)}'.\"\n            )\n            response = self.get_error_message(e, ledger_api, message, dialogue)\n        return response\n\n    def get_state(\n        self,\n        ledger_api: LedgerApi,\n        message: ContractApiMessage,\n        dialogue: ContractApiDialogue,\n    ) -> ContractApiMessage:\n        \"\"\"\n        Send the request 'get_state'.\n\n        :param ledger_api: the API object.\n        :param message: the Ledger API message\n        :param dialogue: the contract API dialogue\n        :return: the contract api message\n        \"\"\"\n\n        def build_response(\n            data: Union[bytes, JSONLike], dialogue: ContractApiDialogue\n        ) -> ContractApiMessage:\n            if not isinstance(data, Mapping):\n                raise ValueError(\n                    f\"Invalid state type, got={type(data)}, expected={JSONLike}.\"\n                )\n            return cast(\n                ContractApiMessage,\n                dialogue.reply(\n                    performative=ContractApiMessage.Performative.STATE,\n                    state=State(message.ledger_id, data),\n                ),\n            )\n\n        return self.dispatch_request(ledger_api, message, dialogue, build_response)\n\n    def get_deploy_transaction(\n        self,\n        ledger_api: LedgerApi,\n        message: ContractApiMessage,\n        dialogue: ContractApiDialogue,\n    ) -> ContractApiMessage:\n        \"\"\"\n        Send the request 'get_raw_transaction'.\n\n        :param ledger_api: the API object.\n        :param message: the Ledger API message\n        :param dialogue: the contract API dialogue\n        :return: the contract api message\n        \"\"\"\n\n        def build_response(\n            tx: Union[bytes, JSONLike], dialogue: ContractApiDialogue\n        ) -> ContractApiMessage:\n            if not isinstance(tx, Mapping):\n                raise ValueError(\n                    f\"Invalid transaction type, got={type(tx)}, expected={JSONLike}.\"\n                )\n            return cast(\n                ContractApiMessage,\n                dialogue.reply(\n                    performative=ContractApiMessage.Performative.RAW_TRANSACTION,\n                    raw_transaction=RawTransaction(message.ledger_id, tx),\n                ),\n            )\n\n        return self.dispatch_request(ledger_api, message, dialogue, build_response)\n\n    def get_raw_transaction(\n        self,\n        ledger_api: LedgerApi,\n        message: ContractApiMessage,\n        dialogue: ContractApiDialogue,\n    ) -> ContractApiMessage:\n        \"\"\"\n        Send the request 'get_raw_transaction'.\n\n        :param ledger_api: the API object.\n        :param message: the Ledger API message\n        :param dialogue: the contract API dialogue\n        :return: the contract api message\n        \"\"\"\n\n        def build_response(\n            tx: Union[bytes, JSONLike], dialogue: ContractApiDialogue\n        ) -> ContractApiMessage:\n            if isinstance(tx, bytes):\n                raise ValueError(\n                    f\"Invalid transaction type, got={type(tx)}, expected={JSONLike}.\"\n                )\n            return cast(\n                ContractApiMessage,\n                dialogue.reply(\n                    performative=ContractApiMessage.Performative.RAW_TRANSACTION,\n                    raw_transaction=RawTransaction(message.ledger_id, tx),\n                ),\n            )\n\n        return self.dispatch_request(ledger_api, message, dialogue, build_response)\n\n    def get_raw_message(\n        self,\n        ledger_api: LedgerApi,\n        message: ContractApiMessage,\n        dialogue: ContractApiDialogue,\n    ) -> ContractApiMessage:\n        \"\"\"\n        Send the request 'get_raw_message'.\n\n        :param ledger_api: the ledger API object.\n        :param message: the Ledger API message\n        :param dialogue: the contract API dialogue\n        :return: the contract api message\n        \"\"\"\n\n        def build_response(\n            rm: Union[bytes, JSONLike], dialogue: ContractApiDialogue\n        ) -> ContractApiMessage:\n            if not isinstance(rm, bytes):\n                raise ValueError(\n                    f\"Invalid message type, got={type(rm)}, expected=bytes.\"\n                )\n            return cast(\n                ContractApiMessage,\n                dialogue.reply(\n                    performative=ContractApiMessage.Performative.RAW_MESSAGE,\n                    raw_message=RawMessage(message.ledger_id, rm),\n                ),\n            )\n\n        return self.dispatch_request(ledger_api, message, dialogue, build_response)\n\n    def _get_data(\n        self,\n        api: LedgerApi,\n        message: ContractApiMessage,\n        contract: Contract,\n    ) -> Union[bytes, JSONLike]:\n        \"\"\"Get the data from the contract method, either from the stub or from the callable specified by the message.\"\"\"\n        # first, check if the custom handler for this type of request has been implemented.\n        data = self._call_stub(api, message, contract)\n        if data is not None:\n            return data\n\n        # then, check if there is the handler for the provided callable.\n        data = self._validate_and_call_callable(api, message, contract)\n        return data\n\n    @staticmethod\n    def _call_stub(\n        ledger_api: LedgerApi, message: ContractApiMessage, contract: Contract\n    ) -> Optional[Union[bytes, JSONLike]]:\n        \"\"\"Try to call stub methods associated to the contract API request performative.\"\"\"\n        try:\n            method: Callable = getattr(contract, message.performative.value)\n            if message.performative in [\n                ContractApiMessage.Performative.GET_STATE,\n                ContractApiMessage.Performative.GET_RAW_MESSAGE,\n                ContractApiMessage.Performative.GET_RAW_TRANSACTION,\n            ]:\n                args, kwargs = (\n                    [ledger_api, message.contract_address],\n                    message.kwargs.body,\n                )\n            elif message.performative in [  # pragma: nocover\n                ContractApiMessage.Performative.GET_DEPLOY_TRANSACTION,\n            ]:\n                args, kwargs = [ledger_api], message.kwargs.body\n            else:  # pragma: nocover\n                raise AEAException(f\"Unexpected performative: {message.performative}\")\n            data = method(*args, **kwargs)\n            return data\n        except (AttributeError, NotImplementedError):\n            return None\n\n    @staticmethod\n    def _validate_and_call_callable(\n        api: LedgerApi, message: ContractApiMessage, contract: Contract\n    ) -> Union[bytes, JSONLike]:\n        \"\"\"\n        Validate a Contract callable, given the performative.\n\n        In particular:\n        - if the performative is either 'get_state' or 'get_raw_transaction', the signature\n          must accept ledger api as first argument and contract address as second argument,\n          plus keyword arguments.\n        - if the performative is either 'get_deploy_transaction' or 'get_raw_message', the signature\n          must accept ledger api as first argument, plus keyword arguments.\n\n        :param api: the ledger api object.\n        :param message: the contract api request.\n        :param contract: the contract instance.\n        :return: the data generated by the method.\n        \"\"\"\n        try:\n            method_to_call = getattr(contract, message.callable)\n        except AttributeError:\n            raise AEAException(\n                f\"Cannot find {message.callable} in contract {type(contract)}\"\n            )\n        full_args_spec = inspect.getfullargspec(method_to_call)\n        if message.performative in [\n            ContractApiMessage.Performative.GET_STATE,\n            ContractApiMessage.Performative.GET_RAW_MESSAGE,\n            ContractApiMessage.Performative.GET_RAW_TRANSACTION,\n        ]:\n            if len(full_args_spec.args) < 2:\n                raise AEAException(\n                    f\"Expected two or more positional arguments, got {len(full_args_spec.args)}\"\n                )\n            return method_to_call(api, message.contract_address, **message.kwargs.body)\n        if message.performative in [\n            ContractApiMessage.Performative.GET_DEPLOY_TRANSACTION,\n        ]:\n            if len(full_args_spec.args) < 1:\n                raise AEAException(\n                    f\"Expected one or more positional arguments, got {len(full_args_spec.args)}\"\n                )\n            return method_to_call(api, **message.kwargs.body)\n        raise AEAException(  # pragma: nocover\n            f\"Unexpected performative: {message.performative}\"\n        )\n"
  },
  {
    "path": "packages/fetchai/connections/ledger/ledger_dispatcher.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the implementation of the ledger API request dispatcher.\"\"\"\nimport logging\nimport time\nfrom typing import Any, cast\n\nfrom aea.connections.base import ConnectionStates\nfrom aea.crypto.base import LedgerApi\nfrom aea.helpers.transaction.base import RawTransaction, State, TransactionDigest\nfrom aea.protocols.base import Address, Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\nfrom aea.protocols.dialogue.base import Dialogues as BaseDialogues\n\nfrom packages.fetchai.connections.ledger.base import CONNECTION_ID, RequestDispatcher\nfrom packages.fetchai.protocols.ledger_api.custom_types import TransactionReceipt\nfrom packages.fetchai.protocols.ledger_api.dialogues import LedgerApiDialogue\nfrom packages.fetchai.protocols.ledger_api.dialogues import (\n    LedgerApiDialogues as BaseLedgerApiDialogues,\n)\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\n\n\n_default_logger = logging.getLogger(\n    \"aea.packages.fetchai.connections.ledger.ledger_dispatcher\"\n)\n\n\nclass LedgerApiDialogues(BaseLedgerApiDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            # The ledger connection maintains the dialogue on behalf of the ledger\n            return LedgerApiDialogue.Role.LEDGER\n\n        BaseLedgerApiDialogues.__init__(\n            self,\n            self_address=str(CONNECTION_ID),\n            role_from_first_message=role_from_first_message,\n            **kwargs,\n        )\n\n\nclass LedgerApiRequestDispatcher(RequestDispatcher):\n    \"\"\"Implement ledger API request dispatcher.\"\"\"\n\n    def __init__(self, *args: Any, **kwargs: Any) -> None:\n        \"\"\"Initialize the dispatcher.\"\"\"\n        logger = kwargs.pop(\"logger\", None)\n        logger = logger if logger is not None else _default_logger\n        super().__init__(logger, *args, **kwargs)\n        self._ledger_api_dialogues = LedgerApiDialogues()\n\n    def get_ledger_id(self, message: Message) -> str:\n        \"\"\"Get the ledger id from message.\"\"\"\n        if not isinstance(message, LedgerApiMessage):  # pragma: nocover\n            raise ValueError(\"argument is not a LedgerApiMessage instance.\")\n        message = cast(LedgerApiMessage, message)\n        if message.performative is LedgerApiMessage.Performative.GET_RAW_TRANSACTION:\n            ledger_id = message.terms.ledger_id\n        elif (\n            message.performative\n            is LedgerApiMessage.Performative.SEND_SIGNED_TRANSACTION\n        ):\n            ledger_id = message.signed_transaction.ledger_id\n        elif (\n            message.performative\n            is LedgerApiMessage.Performative.GET_TRANSACTION_RECEIPT\n        ):\n            ledger_id = message.transaction_digest.ledger_id\n        else:\n            ledger_id = message.ledger_id\n        return ledger_id\n\n    @property\n    def dialogues(self) -> BaseDialogues:\n        \"\"\"Get the dialogues.\"\"\"\n        return self._ledger_api_dialogues\n\n    def get_balance(\n        self,\n        api: LedgerApi,\n        message: LedgerApiMessage,\n        dialogue: LedgerApiDialogue,\n    ) -> LedgerApiMessage:\n        \"\"\"\n        Send the request 'get_balance'.\n\n        :param api: the API object.\n        :param message: the Ledger API message\n        :param dialogue: the dialogue\n        :return: the ledger api message\n        \"\"\"\n        balance = api.get_balance(message.address)\n        if balance is None:\n            response = self.get_error_message(\n                ValueError(\"No balance returned\"), api, message, dialogue\n            )\n        else:\n            response = cast(\n                LedgerApiMessage,\n                dialogue.reply(\n                    performative=LedgerApiMessage.Performative.BALANCE,\n                    target_message=message,\n                    balance=balance,\n                    ledger_id=message.ledger_id,\n                ),\n            )\n        return response\n\n    def get_state(\n        self,\n        api: LedgerApi,\n        message: LedgerApiMessage,\n        dialogue: LedgerApiDialogue,\n    ) -> LedgerApiMessage:\n        \"\"\"\n        Send the request 'get_state'.\n\n        :param api: the API object.\n        :param message: the Ledger API message\n        :param dialogue: the dialogue\n        :return: the ledger api message\n        \"\"\"\n        result = api.get_state(message.callable, *message.args, **message.kwargs.body)\n        if result is None:  # pragma: nocover\n            response = self.get_error_message(\n                ValueError(\"Failed to get state\"), api, message, dialogue\n            )\n        else:\n            response = cast(\n                LedgerApiMessage,\n                dialogue.reply(\n                    performative=LedgerApiMessage.Performative.STATE,\n                    target_message=message,\n                    state=State(message.ledger_id, result),\n                    ledger_id=message.ledger_id,\n                ),\n            )\n        return response\n\n    def get_raw_transaction(\n        self,\n        api: LedgerApi,\n        message: LedgerApiMessage,\n        dialogue: LedgerApiDialogue,\n    ) -> LedgerApiMessage:\n        \"\"\"\n        Send the request 'get_raw_transaction'.\n\n        :param api: the API object.\n        :param message: the Ledger API message\n        :param dialogue: the dialogue\n        :return: the ledger api message\n        \"\"\"\n        raw_transaction = api.get_transfer_transaction(\n            sender_address=message.terms.sender_address,\n            destination_address=message.terms.counterparty_address,\n            amount=message.terms.sender_payable_amount,\n            tx_fee=message.terms.fee,\n            tx_nonce=message.terms.nonce,\n            **message.terms.kwargs,\n        )\n        if raw_transaction is None:\n            response = self.get_error_message(\n                ValueError(\"No raw transaction returned\"), api, message, dialogue\n            )\n        else:\n            response = cast(\n                LedgerApiMessage,\n                dialogue.reply(\n                    performative=LedgerApiMessage.Performative.RAW_TRANSACTION,\n                    target_message=message,\n                    raw_transaction=RawTransaction(\n                        message.terms.ledger_id, raw_transaction\n                    ),\n                ),\n            )\n        return response\n\n    def get_transaction_receipt(\n        self,\n        api: LedgerApi,\n        message: LedgerApiMessage,\n        dialogue: LedgerApiDialogue,\n    ) -> LedgerApiMessage:\n        \"\"\"\n        Send the request 'get_transaction_receipt'.\n\n        :param api: the API object.\n        :param message: the Ledger API message\n        :param dialogue: the dialogue\n        :return: the ledger api message\n        \"\"\"\n        is_settled = False\n        attempts = 0\n        while (\n            not is_settled\n            and attempts < self.MAX_ATTEMPTS\n            and self.connection_state.get() == ConnectionStates.connected\n        ):\n            time.sleep(self.TIMEOUT)\n            transaction_receipt = api.get_transaction_receipt(\n                message.transaction_digest.body\n            )\n            if transaction_receipt is not None:\n                is_settled = api.is_transaction_settled(transaction_receipt)\n            attempts += 1\n        attempts = 0\n        transaction = api.get_transaction(message.transaction_digest.body)\n        while (\n            transaction is None\n            and attempts < self.MAX_ATTEMPTS\n            and self.connection_state.get() == ConnectionStates.connected\n        ):\n            time.sleep(self.TIMEOUT)\n            transaction = api.get_transaction(message.transaction_digest.body)\n            attempts += 1\n        if not is_settled:  # pragma: nocover\n            response = self.get_error_message(\n                ValueError(\"Transaction not settled within timeout\"),\n                api,\n                message,\n                dialogue,\n            )\n        elif transaction_receipt is None:  # pragma: nocover\n            response = self.get_error_message(\n                ValueError(\"No transaction_receipt returned\"), api, message, dialogue\n            )\n        elif transaction is None:  # pragma: nocover\n            response = self.get_error_message(\n                ValueError(\"No transaction returned\"), api, message, dialogue\n            )\n        else:\n            response = cast(\n                LedgerApiMessage,\n                dialogue.reply(\n                    performative=LedgerApiMessage.Performative.TRANSACTION_RECEIPT,\n                    target_message=message,\n                    transaction_receipt=TransactionReceipt(\n                        message.transaction_digest.ledger_id,\n                        transaction_receipt,\n                        transaction,\n                    ),\n                ),\n            )\n        return response\n\n    def send_signed_transaction(\n        self,\n        api: LedgerApi,\n        message: LedgerApiMessage,\n        dialogue: LedgerApiDialogue,\n    ) -> LedgerApiMessage:\n        \"\"\"\n        Send the request 'send_signed_tx'.\n\n        :param api: the API object.\n        :param message: the Ledger API message\n        :param dialogue: the dialogue\n        :return: the ledger api message\n        \"\"\"\n        transaction_digest = api.send_signed_transaction(\n            message.signed_transaction.body\n        )\n        if transaction_digest is None:  # pragma: nocover\n            response = self.get_error_message(\n                ValueError(\"No transaction_digest returned\"), api, message, dialogue\n            )\n        else:\n            response = cast(\n                LedgerApiMessage,\n                dialogue.reply(\n                    performative=LedgerApiMessage.Performative.TRANSACTION_DIGEST,\n                    target_message=message,\n                    transaction_digest=TransactionDigest(\n                        message.signed_transaction.ledger_id, transaction_digest\n                    ),\n                ),\n            )\n        return response\n\n    def get_error_message(\n        self,\n        e: Exception,\n        api: LedgerApi,\n        message: Message,\n        dialogue: BaseDialogue,\n    ) -> LedgerApiMessage:\n        \"\"\"\n        Build an error message.\n\n        :param e: the exception.\n        :param api: the Ledger API.\n        :param message: the request message.\n        :param dialogue: the dialogue\n        :return: an error message response.\n        \"\"\"\n        message = cast(LedgerApiMessage, message)\n        dialogue = cast(LedgerApiDialogue, dialogue)\n        response = cast(\n            LedgerApiMessage,\n            dialogue.reply(\n                performative=LedgerApiMessage.Performative.ERROR,\n                target_message=message,\n                code=500,\n                message=str(e),\n                data=b\"\",\n            ),\n        )\n        return response\n"
  },
  {
    "path": "packages/fetchai/connections/local/README.md",
    "content": "# Local connection\n\nOEF compatible local connection for testing purposes only.\n\n## Usage\n\nOEF compatible connection to be used for testing, does not interact with external nodes. Does not preserve state on restart.\n"
  },
  {
    "path": "packages/fetchai/connections/local/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Implementation of the Local OEF connection.\"\"\"\n"
  },
  {
    "path": "packages/fetchai/connections/local/connection.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Extension to the Local Node.\"\"\"\nimport asyncio\nimport logging\nimport threading\nfrom asyncio import AbstractEventLoop, Queue\nfrom collections import defaultdict\nfrom concurrent.futures import Future\nfrom threading import Thread\nfrom typing import Any, Dict, List, Optional, Tuple, cast\n\nfrom aea.common import Address\nfrom aea.configurations.base import PublicId\nfrom aea.connections.base import Connection, ConnectionStates\nfrom aea.helpers.search.models import Description\nfrom aea.mail.base import Envelope\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\n\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.protocols.oef_search.dialogues import (\n    OefSearchDialogue as BaseOefSearchDialogue,\n)\nfrom packages.fetchai.protocols.oef_search.dialogues import (\n    OefSearchDialogues as BaseOefSearchDialogues,\n)\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\n\n\n_default_logger = logging.getLogger(\"aea.packages.fetchai.connections.local\")\n\nTARGET = 0\nMESSAGE_ID = 1\nRESPONSE_TARGET = MESSAGE_ID\nRESPONSE_MESSAGE_ID = MESSAGE_ID + 1\nSTUB_DIALOGUE_ID = 0\n\nPUBLIC_ID = PublicId.from_str(\"fetchai/local:0.21.6\")\n\n\nOefSearchDialogue = BaseOefSearchDialogue\nOEF_LOCAL_NODE_SEARCH_ADDRESS = \"oef_local_node_search\"\nOEF_LOCAL_NODE_ADDRESS = \"oef_local_node\"\n\n\nclass OefSearchDialogues(BaseOefSearchDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self) -> None:\n        \"\"\"Initialize dialogues.\"\"\"\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            # The local connection maintains the dialogue on behalf of the node\n            return OefSearchDialogue.Role.OEF_NODE\n\n        BaseOefSearchDialogues.__init__(\n            self,\n            self_address=OEF_LOCAL_NODE_SEARCH_ADDRESS,\n            role_from_first_message=role_from_first_message,\n            dialogue_class=OefSearchDialogue,\n        )\n\n\nclass LocalNode:\n    \"\"\"A light-weight local implementation of a OEF Node.\"\"\"\n\n    def __init__(\n        self, loop: AbstractEventLoop = None, logger: logging.Logger = _default_logger\n    ):\n        \"\"\"\n        Initialize a local (i.e. non-networked) implementation of an OEF Node.\n\n        :param loop: the event loop. If None, a new event loop is instantiated.\n        :param logger: the logger.\n        \"\"\"\n        self._lock = threading.Lock()\n        self.services = defaultdict(lambda: [])  # type: Dict[str, List[Description]]\n        self._loop = loop if loop is not None else asyncio.new_event_loop()\n        self._thread = Thread(target=self._run_loop, daemon=True)\n\n        self._in_queue = None  # type: Optional[asyncio.Queue]\n        self._out_queues = {}  # type: Dict[str, asyncio.Queue]\n\n        self._receiving_loop_task = None  # type: Optional[Future]\n        self.address: Optional[Address] = None\n        self._dialogues: Optional[OefSearchDialogues] = None\n        self.logger = logger\n        self.started_event = threading.Event()\n\n    def __enter__(self) -> \"LocalNode\":\n        \"\"\"Start the local node.\"\"\"\n        self.start()\n        return self\n\n    def __exit__(self, exc_type: str, exc_val: str, exc_tb: str) -> None:\n        \"\"\"Stop the local node.\"\"\"\n        self.stop()\n\n    def _run_loop(self) -> None:\n        \"\"\"\n        Run the asyncio loop.\n\n        This method is supposed to be run only in the Multiplexer thread.\n        \"\"\"\n        self.logger.debug(\"Starting threaded asyncio loop...\")\n        asyncio.set_event_loop(self._loop)\n        self._loop.run_forever()\n        self.logger.debug(\"Asyncio loop has been stopped.\")\n\n    async def connect(\n        self, address: Address, writer: asyncio.Queue\n    ) -> Optional[asyncio.Queue]:\n        \"\"\"\n        Connect an address to the node.\n\n        :param address: the address of the agent.\n        :param writer: the queue where the client is listening.\n        :return: an asynchronous queue, that constitutes the communication channel.\n        \"\"\"\n        if address in self._out_queues.keys():\n            return None\n\n        if self._in_queue is None:  # pragma: nocover\n            raise ValueError(\"In queue not set.\")\n        q = self._in_queue  # type: asyncio.Queue\n        self._out_queues[address] = writer\n\n        self.address = address\n        self._dialogues = OefSearchDialogues()\n        return q\n\n    def start(self) -> None:\n        \"\"\"Start the node.\"\"\"\n        if not self._loop.is_running() and not self._thread.is_alive():\n            self._thread.start()\n        self._receiving_loop_task = asyncio.run_coroutine_threadsafe(\n            self.receiving_loop(), loop=self._loop\n        )\n        self.started_event.wait()\n        self.logger.debug(\"Local node has been started.\")\n\n    def stop(self) -> None:\n        \"\"\"Stop the node.\"\"\"\n\n        if self._receiving_loop_task is None or self._in_queue is None:\n            raise ValueError(\"Connection not started!\")\n        asyncio.run_coroutine_threadsafe(self._in_queue.put(None), self._loop).result()\n        self._receiving_loop_task.result()\n\n        if self._loop.is_running():\n            self._loop.call_soon_threadsafe(self._loop.stop)\n        if self._thread.is_alive():\n            self._thread.join()\n\n    async def receiving_loop(self) -> None:\n        \"\"\"Process incoming messages.\"\"\"\n        self._in_queue = asyncio.Queue()\n        self.started_event.set()\n        while True:\n            envelope = await self._in_queue.get()\n            if envelope is None:\n                self.logger.debug(\"Receiving loop terminated.\")\n                return\n            self.logger.debug(\"Handling envelope: {}\".format(envelope))\n            await self._handle_envelope(envelope)\n\n    async def _handle_envelope(self, envelope: Envelope) -> None:\n        \"\"\"Handle an envelope.\n\n        :param envelope: the envelope\n        \"\"\"\n        if (\n            envelope.protocol_specification_id\n            == OefSearchMessage.protocol_specification_id\n        ):\n            await self._handle_oef_message(envelope)\n        else:\n            OEFLocalConnection._ensure_valid_envelope_for_external_comms(  # pylint: disable=protected-access\n                envelope\n            )\n            await self._handle_agent_message(envelope)\n\n    async def _handle_oef_message(self, envelope: Envelope) -> None:\n        \"\"\"Handle oef messages.\n\n        :param envelope: the envelope\n        \"\"\"\n        if not isinstance(envelope.message, OefSearchMessage):  # pragma: nocover\n            raise ValueError(\"Message not of type OefSearchMessage.\")\n        oef_message, dialogue = self._get_message_and_dialogue(envelope)\n\n        if dialogue is None:\n            self.logger.warning(\n                \"Could not create dialogue for message={}\".format(oef_message)\n            )\n            return\n\n        if oef_message.performative == OefSearchMessage.Performative.REGISTER_SERVICE:\n            await self._register_service(\n                envelope.sender, oef_message.service_description\n            )\n        elif (\n            oef_message.performative == OefSearchMessage.Performative.UNREGISTER_SERVICE\n        ):\n            await self._unregister_service(oef_message, dialogue)\n        elif oef_message.performative == OefSearchMessage.Performative.SEARCH_SERVICES:\n            await self._search_services(oef_message, dialogue)\n        else:\n            # request not recognized\n            pass\n\n    async def _handle_agent_message(self, envelope: Envelope) -> None:\n        \"\"\"\n        Forward an envelope to the right agent.\n\n        :param envelope: the envelope\n        \"\"\"\n        destination = envelope.to\n\n        if destination not in self._out_queues.keys():\n            msg = DefaultMessage(\n                performative=DefaultMessage.Performative.ERROR,\n                dialogue_reference=(\"\", \"\"),\n                target=TARGET,\n                message_id=MESSAGE_ID,\n                error_code=DefaultMessage.ErrorCode.INVALID_DIALOGUE,\n                error_msg=\"Destination not available\",\n                error_data={},\n            )\n            error_envelope = Envelope(\n                to=envelope.sender,\n                sender=OEF_LOCAL_NODE_ADDRESS,\n                message=msg,\n            )\n            await self._send(error_envelope)\n            return\n        await self._send(envelope)\n\n    async def _register_service(\n        self, address: Address, service_description: Description\n    ) -> None:\n        \"\"\"\n        Register a service agent in the service directory of the node.\n\n        :param address: the address of the service agent to be registered.\n        :param service_description: the description of the service agent to be registered.\n        \"\"\"\n        with self._lock:\n            self.services[address].append(service_description)\n\n    async def _unregister_service(\n        self,\n        oef_search_msg: OefSearchMessage,\n        dialogue: OefSearchDialogue,\n    ) -> None:\n        \"\"\"\n        Unregister a service agent.\n\n        :param oef_search_msg: the incoming message.\n        :param dialogue: the dialogue.\n        \"\"\"\n        service_description = oef_search_msg.service_description\n        address = oef_search_msg.sender\n        with self._lock:\n            if address not in self.services:\n                msg = dialogue.reply(\n                    performative=OefSearchMessage.Performative.OEF_ERROR,\n                    target_message=oef_search_msg,\n                    oef_error_operation=OefSearchMessage.OefErrorOperation.UNREGISTER_SERVICE,\n                )\n                envelope = Envelope(\n                    to=msg.to,\n                    sender=msg.sender,\n                    message=msg,\n                )\n                await self._send(envelope)\n            else:\n                self.services[address].remove(service_description)\n                if len(self.services[address]) == 0:\n                    self.services.pop(address)\n\n    async def _search_services(\n        self,\n        oef_search_msg: OefSearchMessage,\n        dialogue: OefSearchDialogue,\n    ) -> None:\n        \"\"\"\n        Search the agents in the local Service Directory, and send back the result.\n\n        This is actually a dummy search, it will return all the registered agents with the specified data model.\n        If the data model is not specified, it will return all the agents.\n\n        :param oef_search_msg: the message.\n        :param dialogue: the dialogue.\n        \"\"\"\n        with self._lock:\n            query = oef_search_msg.query\n            result = []  # type: List[str]\n            if query.model is None:\n                result = list(set(self.services.keys()))\n            else:\n                for agent_address, descriptions in self.services.items():\n                    for description in descriptions:\n                        if description.data_model == query.model:\n                            result.append(agent_address)\n\n            msg = dialogue.reply(\n                performative=OefSearchMessage.Performative.SEARCH_RESULT,\n                target_message=oef_search_msg,\n                agents=tuple(sorted(set(result))),\n            )\n\n            envelope = Envelope(\n                to=msg.to,\n                sender=msg.sender,\n                message=msg,\n            )\n            await self._send(envelope)\n\n    def _get_message_and_dialogue(\n        self, envelope: Envelope\n    ) -> Tuple[OefSearchMessage, Optional[OefSearchDialogue]]:\n        \"\"\"\n        Get a message copy and dialogue related to this message.\n\n        :param envelope: incoming envelope\n\n        :return: Tuple[Message, Optional[Dialogue]]\n        \"\"\"\n        if self._dialogues is None:  # pragma: nocover\n            raise ValueError(\"Call connect before!\")\n        message = cast(OefSearchMessage, envelope.message)\n        dialogue = cast(Optional[OefSearchDialogue], self._dialogues.update(message))\n        return message, dialogue\n\n    async def _send(self, envelope: Envelope) -> None:\n        \"\"\"Send a message.\"\"\"\n        destination = envelope.to\n        destination_queue = self._out_queues[destination]\n        destination_queue._loop.call_soon_threadsafe(destination_queue.put_nowait, envelope)  # type: ignore  # pylint: disable=protected-access\n        self.logger.debug(\"Send envelope {}\".format(envelope))\n\n    async def disconnect(self, address: Address) -> None:\n        \"\"\"\n        Disconnect.\n\n        :param address: the address of the agent\n        \"\"\"\n        with self._lock:\n            self._out_queues.pop(address, None)\n            self.services.pop(address, None)\n\n\nclass OEFLocalConnection(Connection):\n    \"\"\"\n    Proxy to the functionality of the OEF.\n\n    It allows the interaction between agents, but not the search functionality.\n    It is useful for local testing.\n    \"\"\"\n\n    connection_id = PUBLIC_ID\n\n    def __init__(self, local_node: Optional[LocalNode] = None, **kwargs: Any) -> None:\n        \"\"\"\n        Load the connection configuration.\n\n        Initialize a OEF proxy for a local OEF Node\n\n        :param local_node: the Local OEF Node object. This reference must be the same across the agents of interest. (Note, AEA loader will not accept this argument.)\n        :param kwargs: keyword arguments.\n        \"\"\"\n        super().__init__(**kwargs)\n        self._local_node = local_node\n        self._reader = None  # type: Optional[Queue]\n        self._writer = None  # type: Optional[Queue]\n\n    async def connect(self) -> None:\n        \"\"\"Connect to the local OEF Node.\"\"\"\n        if self._local_node is None:  # pragma: nocover\n            raise ValueError(\"No local node set!\")\n\n        if self.is_connected:  # pragma: nocover\n            return\n\n        with self._connect_context():\n            self._reader = Queue()\n            self._writer = await self._local_node.connect(self.address, self._reader)\n\n    async def disconnect(self) -> None:\n        \"\"\"Disconnect from the local OEF Node.\"\"\"\n        if self._local_node is None:\n            raise ValueError(\"No local node set!\")  # pragma: nocover\n        if self.is_disconnected:\n            return  # pragma: nocover\n        self.state = ConnectionStates.disconnecting\n        if self._reader is None:\n            raise ValueError(\"No reader set!\")  # pragma: nocover\n        await self._local_node.disconnect(self.address)\n        await self._reader.put(None)\n        self._reader, self._writer = None, None\n        self.state = ConnectionStates.disconnected\n\n    async def send(self, envelope: Envelope) -> None:\n        \"\"\"\n        Send a message.\n\n        :param envelope: the envelope.\n        \"\"\"\n        self._ensure_connected()\n        self._writer._loop.call_soon_threadsafe(self._writer.put_nowait, envelope)  # type: ignore  # pylint: disable=protected-access\n\n    async def receive(self, *args: Any, **kwargs: Any) -> Optional[\"Envelope\"]:\n        \"\"\"\n        Receive an envelope. Blocking.\n\n        :param args: positional arguments.\n        :param kwargs: keyword arguments.\n        :return: the envelope received, or None.\n        \"\"\"\n        self._ensure_connected()\n        try:\n            if self._reader is None:\n                raise ValueError(\"No reader set!\")  # pragma: nocover\n            envelope = await self._reader.get()\n            if envelope is None:  # pragma: no cover\n                self.logger.debug(\"Receiving task terminated.\")\n                return None\n            self.logger.debug(\"Received envelope {}\".format(envelope))\n            return envelope\n        except Exception:  # pragma: nocover # pylint: disable=broad-except\n            return None\n"
  },
  {
    "path": "packages/fetchai/connections/local/connection.yaml",
    "content": "name: local\nauthor: fetchai\nversion: 0.21.6\ntype: connection\ndescription: The local connection provides a stub for an OEF node.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: QmbK7MtyAVqh2LmSh9TY6yBZqfWaAXURP4rQGATyP2hTKC\n  __init__.py: QmUZgacY7XBWHCum6DrUkoy4r3xM3hkzKpqC49XFmKuYRQ\n  connection.py: QmWiVqkzLKTJNgXNKRKJSiR3CLZkJWvU9QYN691gTuCTZG\nfingerprint_ignore_patterns: []\nconnections: []\nprotocols:\n- fetchai/oef_search:1.1.7\nclass_name: OEFLocalConnection\nconfig: {}\nexcluded_protocols: []\nrestricted_to_protocols: []\ndependencies: {}\nis_abstract: false\n"
  },
  {
    "path": "packages/fetchai/connections/oef/README.md",
    "content": "# OEF connection\n\nConnection to interact with an OEF node (<https://fetchai.github.io/oef-sdk-python/user/introduction.html>).\n\n## Usage\n\nRegister/unregister services, perform searches using `fetchai/oef_search:1.1.7` protocol and send messages of any protocol to other agents connected to the same node.\n"
  },
  {
    "path": "packages/fetchai/connections/oef/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Implementation of the OEF connection.\"\"\"\n"
  },
  {
    "path": "packages/fetchai/connections/oef/connection.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Extension to the OEF Python SDK.\"\"\"\n\nimport asyncio\nimport logging\nfrom asyncio import AbstractEventLoop, CancelledError\nfrom concurrent.futures.thread import ThreadPoolExecutor\nfrom itertools import cycle\nfrom logging import Logger\nfrom typing import Any, Callable, Dict, List, Optional, cast\n\nimport oef\nfrom oef.agents import OEFAgent\nfrom oef.core import AsyncioCore\nfrom oef.messages import CFP_TYPES, PROPOSE_TYPES\n\nfrom aea.common import Address\nfrom aea.configurations.base import PublicId\nfrom aea.connections.base import Connection, ConnectionStates\nfrom aea.exceptions import enforce\nfrom aea.mail.base import Envelope\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\n\nfrom packages.fetchai.connections.oef.object_translator import OEFObjectTranslator\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.protocols.oef_search.dialogues import (\n    OefSearchDialogue as BaseOefSearchDialogue,\n)\nfrom packages.fetchai.protocols.oef_search.dialogues import (\n    OefSearchDialogues as BaseOefSearchDialogues,\n)\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\n\n\n_default_logger = logging.getLogger(\"aea.packages.fetchai.connections.oef\")\n\nTARGET = 0\nMESSAGE_ID = 1\nRESPONSE_TARGET = MESSAGE_ID\nRESPONSE_MESSAGE_ID = MESSAGE_ID + 1\nSTUB_MESSAGE_ID = 0\nSTUB_DIALOGUE_ID = 0\nDEFAULT_OEF = \"oef\"\nPUBLIC_ID = PublicId.from_str(\"fetchai/oef:0.22.6\")\n\nOefSearchDialogue = BaseOefSearchDialogue\n\n\nclass OefSearchDialogues(BaseOefSearchDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self) -> None:\n        \"\"\"Initialize dialogues.\"\"\"\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            # The oef connection maintains the dialogue on behalf of the node\n            return OefSearchDialogue.Role.OEF_NODE\n\n        BaseOefSearchDialogues.__init__(\n            self,\n            self_address=str(OEFConnection.connection_id),\n            role_from_first_message=role_from_first_message,\n            dialogue_class=OefSearchDialogue,\n        )\n\n\nclass OEFChannel(OEFAgent):\n    \"\"\"The OEFChannel connects the OEF Agent with the connection.\"\"\"\n\n    THREAD_POOL_SIZE = 3\n    CONNECT_RETRY_DELAY = 5.0\n    CONNECT_TIMEOUT = 2\n    CONNECT_ATTEMPTS_LIMIT = 0\n\n    def __init__(\n        self,\n        address: Address,\n        oef_addr: str,\n        oef_port: int,\n        logger: Logger = _default_logger,\n    ):\n        \"\"\"\n        Initialize.\n\n        :param address: the address of the agent.\n        :param oef_addr: the OEF IP address.\n        :param oef_port: the OEF port.\n        :param logger: the logger.\n        \"\"\"\n        super().__init__(\n            address,\n            oef_addr=oef_addr,\n            oef_port=oef_port,\n            core=AsyncioCore(logger=logger),\n            logger=lambda *x: None,\n            logger_debug=lambda *x: None,\n        )\n        self.address = address\n        self._in_queue = None  # type: Optional[asyncio.Queue]\n        self._loop = None  # type: Optional[AbstractEventLoop]\n\n        self.oef_search_dialogues = OefSearchDialogues()\n        self.oef_msg_id = 0\n        self.oef_msg_id_to_dialogue = {}  # type: Dict[int, OefSearchDialogue]\n\n        self._threaded_pool = ThreadPoolExecutor(self.THREAD_POOL_SIZE)\n\n        self.aea_logger = logger\n\n    async def _run_in_executor(self, fn: Callable, *args: Any) -> Any:\n        if not self._loop:  # pragma: nocover\n            raise ValueError(\"Channel not connected!\")\n        return await self._loop.run_in_executor(self._threaded_pool, fn, *args)\n\n    @property\n    def in_queue(self) -> asyncio.Queue:\n        \"\"\"Get input messages queue.\"\"\"\n        if not self._in_queue:  # pragma: nocover\n            raise ValueError(\"Channel not connected!\")\n        return self._in_queue\n\n    @property\n    def loop(self) -> AbstractEventLoop:\n        \"\"\"Get event loop.\"\"\"\n        if not self._loop:  # pragma: nocover\n            raise ValueError(\"Channel not connected!\")\n        return self._loop\n\n    def on_message(  # pylint: disable=unused-argument\n        self, msg_id: int, dialogue_id: int, origin: Address, content: bytes\n    ) -> None:\n        \"\"\"\n        On message event handler.\n\n        :param msg_id: the message id.\n        :param dialogue_id: the dialogue id.\n        :param origin: the address of the sender.\n        :param content: the bytes content.\n        \"\"\"\n        # We are not using the 'msg_id', 'dialogue_id' and 'origin' parameters because 'content' contains a\n        # serialized instance of 'Envelope', hence it already contains this information.\n        self._check_loop_and_queue()\n        envelope = Envelope.decode(content)\n        asyncio.run_coroutine_threadsafe(self.in_queue.put(envelope), self.loop)\n\n    def on_cfp(\n        self,\n        msg_id: int,\n        dialogue_id: int,\n        origin: Address,\n        target: int,\n        query: CFP_TYPES,\n    ) -> None:\n        \"\"\"\n        On cfp event handler.\n\n        :param msg_id: the message id.\n        :param dialogue_id: the dialogue id.\n        :param origin: the address of the sender.\n        :param target: the message target.\n        :param query: the query.\n        \"\"\"\n        self._check_loop_and_queue()\n        self.aea_logger.warning(\n            \"Dropping incompatible on_cfp: msg_id={}, dialogue_id={}, origin={}, target={}, query={}\".format(\n                msg_id, dialogue_id, origin, target, query\n            )\n        )\n\n    def on_propose(  # pylint: disable=unused-argument\n        self,\n        msg_id: int,\n        dialogue_id: int,\n        origin: Address,\n        target: int,\n        proposals: PROPOSE_TYPES,\n    ) -> None:\n        \"\"\"\n        On propose event handler.\n\n        :param msg_id: the message id.\n        :param dialogue_id: the dialogue id.\n        :param origin: the address of the sender.\n        :param target: the message target.\n        :param proposals: the proposals.\n        \"\"\"\n        self._check_loop_and_queue()\n        self.aea_logger.warning(\n            \"Dropping incompatible on_propose: msg_id={}, dialogue_id={}, origin={}, target={}\".format(\n                msg_id, dialogue_id, origin, target\n            )\n        )\n\n    def on_accept(\n        self, msg_id: int, dialogue_id: int, origin: Address, target: int\n    ) -> None:\n        \"\"\"\n        On accept event handler.\n\n        :param msg_id: the message id.\n        :param dialogue_id: the dialogue id.\n        :param origin: the address of the sender.\n        :param target: the message target.\n        \"\"\"\n        self._check_loop_and_queue()\n        self.aea_logger.warning(\n            \"Dropping incompatible on_accept: msg_id={}, dialogue_id={}, origin={}, target={}\".format(\n                msg_id, dialogue_id, origin, target\n            )\n        )\n\n    def on_decline(\n        self, msg_id: int, dialogue_id: int, origin: Address, target: int\n    ) -> None:\n        \"\"\"\n        On decline event handler.\n\n        :param msg_id: the message id.\n        :param dialogue_id: the dialogue id.\n        :param origin: the address of the sender.\n        :param target: the message target.\n        \"\"\"\n        self._check_loop_and_queue()\n        self.aea_logger.warning(\n            \"Dropping incompatible on_decline: msg_id={}, dialogue_id={}, origin={}, target={}\".format(\n                msg_id, dialogue_id, origin, target\n            )\n        )\n\n    def on_search_result(self, search_id: int, agents: List[Address]) -> None:\n        \"\"\"\n        On accept event handler.\n\n        :param search_id: the search id.\n        :param agents: the list of agents.\n        \"\"\"\n        self._check_loop_and_queue()\n        oef_search_dialogue = self.oef_msg_id_to_dialogue.pop(search_id, None)\n        if oef_search_dialogue is None:\n            self.aea_logger.warning(\n                \"Could not find dialogue for search_id={}\".format(search_id)\n            )  # pragma: nocover\n            return  # pragma: nocover\n        last_msg = oef_search_dialogue.last_incoming_message\n        if last_msg is None:\n            self.aea_logger.warning(\"Could not find last message.\")  # pragma: nocover\n            return  # pragma: nocover\n        msg = oef_search_dialogue.reply(\n            performative=OefSearchMessage.Performative.SEARCH_RESULT,\n            target_message=last_msg,\n            agents=tuple(agents),\n        )\n        envelope = Envelope(\n            to=msg.to,\n            sender=msg.sender,\n            message=msg,\n        )\n        asyncio.run_coroutine_threadsafe(self.in_queue.put(envelope), self.loop)\n\n    def on_oef_error(\n        self, answer_id: int, operation: oef.messages.OEFErrorOperation\n    ) -> None:\n        \"\"\"\n        On oef error event handler.\n\n        :param answer_id: the answer id.\n        :param operation: the error operation.\n        \"\"\"\n        self._check_loop_and_queue()\n        try:\n            operation = OefSearchMessage.OefErrorOperation(operation)\n        except ValueError:\n            operation = OefSearchMessage.OefErrorOperation.OTHER\n        oef_search_dialogue = self.oef_msg_id_to_dialogue.pop(answer_id, None)\n        if oef_search_dialogue is None:\n            self.aea_logger.warning(\n                \"Could not find dialogue for answer_id={}\".format(answer_id)\n            )  # pragma: nocover\n            return  # pragma: nocover\n        last_msg = oef_search_dialogue.last_incoming_message\n        if last_msg is None:\n            self.aea_logger.warning(\"Could not find last message.\")  # pragma: nocover\n            return  # pragma: nocover\n        msg = oef_search_dialogue.reply(\n            performative=OefSearchMessage.Performative.OEF_ERROR,\n            target_message=last_msg,\n            oef_error_operation=operation,\n        )\n        envelope = Envelope(\n            to=msg.to,\n            sender=msg.sender,\n            message=msg,\n        )\n        asyncio.run_coroutine_threadsafe(self.in_queue.put(envelope), self.loop)\n\n    def on_dialogue_error(  # pylint: disable=unused-argument\n        self, answer_id: int, dialogue_id: int, origin: Address\n    ) -> None:\n        \"\"\"\n        On dialogue error event handler.\n\n        :param answer_id: the answer id.\n        :param dialogue_id: the dialogue id.\n        :param origin: the message sender.\n        \"\"\"\n        self._check_loop_and_queue()\n        msg = DefaultMessage(\n            performative=DefaultMessage.Performative.ERROR,\n            dialogue_reference=(str(answer_id), \"\"),\n            target=TARGET,\n            message_id=MESSAGE_ID,\n            error_code=DefaultMessage.ErrorCode.INVALID_DIALOGUE,\n            error_msg=\"Destination not available\",\n            error_data={},\n        )\n        envelope = Envelope(\n            to=self.address,\n            sender=DEFAULT_OEF,\n            message=msg,\n        )\n        asyncio.run_coroutine_threadsafe(self.in_queue.put(envelope), self.loop)\n\n    def send(self, envelope: Envelope) -> None:\n        \"\"\"\n        Send message handler.\n\n        :param envelope: the message.\n        \"\"\"\n        if (\n            envelope.protocol_specification_id\n            == OefSearchMessage.protocol_specification_id\n        ):\n            self.send_oef_message(envelope)\n        else:\n            self.send_default_message(envelope)\n\n    def send_default_message(self, envelope: Envelope) -> None:\n        \"\"\"Send a 'default' message.\"\"\"\n        self.send_message(\n            STUB_MESSAGE_ID, STUB_DIALOGUE_ID, envelope.to, envelope.encode()\n        )\n\n    def send_oef_message(self, envelope: Envelope) -> None:\n        \"\"\"\n        Send oef message handler.\n\n        :param envelope: the message.\n        \"\"\"\n        enforce(\n            isinstance(envelope.message, OefSearchMessage),\n            \"Message not of type OefSearchMessage\",\n        )\n        oef_message = cast(OefSearchMessage, envelope.message)\n        oef_search_dialogue = cast(\n            OefSearchDialogue, self.oef_search_dialogues.update(oef_message)\n        )\n        if oef_search_dialogue is None:\n            self.aea_logger.warning(\n                \"Could not create dialogue for message={}\".format(oef_message)\n            )  # pragma: nocover\n            return  # pragma: nocover\n        self.oef_msg_id += 1\n        self.oef_msg_id_to_dialogue[self.oef_msg_id] = oef_search_dialogue\n        if oef_message.performative == OefSearchMessage.Performative.REGISTER_SERVICE:\n            service_description = oef_message.service_description\n            oef_service_description = OEFObjectTranslator.to_oef_description(\n                service_description\n            )\n            self.register_service(self.oef_msg_id, oef_service_description)\n        elif (\n            oef_message.performative == OefSearchMessage.Performative.UNREGISTER_SERVICE\n        ):\n            service_description = oef_message.service_description\n            oef_service_description = OEFObjectTranslator.to_oef_description(\n                service_description\n            )\n            self.unregister_service(self.oef_msg_id, oef_service_description)\n        elif oef_message.performative == OefSearchMessage.Performative.SEARCH_SERVICES:\n            query = oef_message.query\n            oef_query = OEFObjectTranslator.to_oef_query(query)\n            self.search_services(self.oef_msg_id, oef_query)\n        else:\n            raise ValueError(\"OEF request not recognized.\")  # pragma: nocover\n\n    def handle_failure(  # pylint: disable=unused-argument\n        self, exception: Exception, conn: Any\n    ) -> None:\n        \"\"\"Handle failure.\"\"\"\n        self.aea_logger.exception(exception)  # pragma: nocover\n\n    async def _set_loop_and_queue(self) -> None:\n        self._loop = asyncio.get_event_loop()\n        self._in_queue = asyncio.Queue()\n\n    async def _unset_loop_and_queue(self) -> None:\n        self._loop = None\n        self._in_queue = None\n\n    def _check_loop_and_queue(self) -> None:\n        enforce(self.in_queue is not None, \"In queue is not set!\")\n        enforce(self.loop is not None, \"Loop is not set!\")\n\n    async def connect(  # pylint: disable=invalid-overridden-method,arguments-differ\n        self,\n    ) -> None:\n        \"\"\"Connect channel.\"\"\"\n        await self._set_loop_and_queue()\n        self.core = AsyncioCore(  # pylint: disable=attribute-defined-outside-init\n            loop=self._loop, logger=_default_logger\n        )\n\n        if self.CONNECT_ATTEMPTS_LIMIT != 0:  # pragma: nocover\n            gen = range(self.CONNECT_ATTEMPTS_LIMIT)\n        else:\n            gen = cycle(range(1))  # type: ignore\n\n        try:\n            for _ in gen:\n                is_connected = await self._run_in_executor(\n                    self._oef_agent_connect, self.CONNECT_TIMEOUT\n                )\n                if is_connected:\n                    return\n                self.aea_logger.warning(\n                    \"Cannot connect to OEFChannel. Retrying in 5 seconds...\"\n                )\n                await asyncio.sleep(self.CONNECT_RETRY_DELAY)\n\n            raise ValueError(\"Connect attempts limit!\")  # pragma: nocover\n        except Exception:  # pragma: nocover\n            await self._unset_loop_and_queue()\n            raise\n\n    def _oef_agent_connect(self, timeout: float = 2) -> bool:\n        \"\"\"\n        Connect OEF agent.\n\n        :param timeout: timeout to wait on connection\n        :return: bool, connected or not\n        \"\"\"\n        return super().connect(timeout)\n\n    async def disconnect(self) -> None:  # pylint: disable=invalid-overridden-method\n        \"\"\"Disconnect channel.\"\"\"\n        if self._in_queue is None and self._loop is None:  # pragma: nocover\n            return  # not connected so nothing to do\n\n        await self.in_queue.put(None)\n        await self._run_in_executor(super().disconnect)\n        await self._unset_loop_and_queue()\n\n    async def get(self) -> Optional[Envelope]:\n        \"\"\"Get incoming envelope.\"\"\"\n        return await self.in_queue.get()\n\n\nclass OEFConnection(Connection):\n    \"\"\"The OEFConnection connects the to the mailbox.\"\"\"\n\n    connection_id = PUBLIC_ID\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize.\n\n        :param kwargs: the keyword arguments (check the parent constructor)\n        \"\"\"\n        super().__init__(**kwargs)\n        addr = cast(str, self.configuration.config.get(\"addr\"))\n        port = cast(int, self.configuration.config.get(\"port\"))\n        if addr is None or port is None:\n            raise ValueError(\"addr and port must be set!\")  # pragma: nocover\n        self.oef_addr = addr\n        self.oef_port = port\n        self.channel = OEFChannel(self.address, self.oef_addr, self.oef_port, logger=self.logger)  # type: ignore\n        self._connection_check_task = None  # type: Optional[asyncio.Future]\n\n    async def connect(self) -> None:\n        \"\"\"\n        Connect to the channel.\n\n        :raises Exception if the connection to the OEF fails.\n        \"\"\"\n        if self.is_connected:\n            return\n\n        with self._connect_context():\n            self.channel.aea_logger = self.logger\n            await self.channel.connect()\n            self._connection_check_task = self.loop.create_task(\n                self._connection_check()\n            )\n\n    async def _connection_check(self) -> None:\n        \"\"\"\n        Check for connection to the channel.\n\n        Try to reconnect if connection is dropped.\n        \"\"\"\n        while self.is_connected:\n            await asyncio.sleep(2.0)\n            if not self.channel.get_state() == \"connected\":  # pragma: no cover\n                self.state = ConnectionStates.connecting\n                self.logger.warning(\n                    \"Lost connection to OEFChannel. Retrying to connect soon ...\"\n                )\n                await self.channel.connect()\n                self.state = ConnectionStates.connected\n                self.logger.warning(\n                    \"Successfully re-established connection to OEFChannel.\"\n                )\n\n    async def disconnect(self) -> None:\n        \"\"\"Disconnect from the channel.\"\"\"\n        if self.is_disconnected:\n            return\n        self.state = ConnectionStates.disconnecting\n        if self._connection_check_task is not None:\n            self._connection_check_task.cancel()\n            self._connection_check_task = None\n        await self.channel.disconnect()\n\n        self.state = ConnectionStates.disconnected\n\n    async def receive(self, *args: Any, **kwargs: Any) -> Optional[\"Envelope\"]:\n        \"\"\"\n        Receive an envelope. Blocking.\n\n        :param args: the positional arguments\n        :param kwargs: the keyword arguments\n        :return: the envelope received, or None.\n        \"\"\"\n        try:\n            envelope = await self.channel.get()\n            if envelope is None:  # pragma: no cover\n                self.logger.debug(\"Received None.\")\n                return None\n            self.logger.debug(\"Received envelope: {}\".format(envelope))\n            return envelope\n        except CancelledError:\n            self.logger.debug(\"Receive cancelled.\")\n            return None\n        except Exception as e:  # pragma: nocover # pylint: disable=broad-except\n            self.logger.exception(e)\n            return None\n\n    async def send(self, envelope: \"Envelope\") -> None:\n        \"\"\"\n        Send an envelope.\n\n        :param envelope: the envelope to send.\n        \"\"\"\n        if self.is_connected:\n            self.channel.send(envelope)\n"
  },
  {
    "path": "packages/fetchai/connections/oef/connection.yaml",
    "content": "name: oef\nauthor: fetchai\nversion: 0.22.6\ntype: connection\ndescription: The oef connection provides a wrapper around the OEF SDK for connection\n  with the OEF search and communication node.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: QmWXtFDtByTYoLy5UKYbYQ9hfDUnDhLJzSy1svoAnHyKUp\n  __init__.py: QmPyDUmHgQdAtuq46GSQ75kpkeH3jg5LQoZm2xQi9j9PMk\n  connection.py: QmTKTZvUxTfL9qZ9on9h6WmiempZBbPsQ6yMiCvwt2jm3v\n  object_translator.py: QmTcyE7yVMzx72zr7JJoZDftL42aP5s3jQQBgMCGqgY6PW\nfingerprint_ignore_patterns: []\nconnections: []\nprotocols:\n- fetchai/default:1.1.7\n- fetchai/oef_search:1.1.7\nclass_name: OEFConnection\nconfig:\n  addr: 127.0.0.1\n  port: '10000'\nexcluded_protocols: []\nrestricted_to_protocols: []\ndependencies:\n  colorlog: {}\n  oef:\n    version: ==0.8.1\nis_abstract: false\n"
  },
  {
    "path": "packages/fetchai/connections/oef/object_translator.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Extension to the OEF Python SDK.\"\"\"\n\nimport logging\nfrom typing import Tuple\n\nfrom oef.query import And as OEFAnd\nfrom oef.query import Constraint as OEFConstraint\nfrom oef.query import ConstraintExpr as OEFConstraintExpr\nfrom oef.query import ConstraintType as OEFConstraintType\nfrom oef.query import Distance, Eq, Gt, GtEq, In\nfrom oef.query import Location as OEFLocation\nfrom oef.query import Lt, LtEq\nfrom oef.query import Not as OEFNot\nfrom oef.query import NotEq, NotIn\nfrom oef.query import Or as OEFOr\nfrom oef.query import Query as OEFQuery\nfrom oef.query import Range\nfrom oef.schema import AttributeSchema as OEFAttribute\nfrom oef.schema import DataModel as OEFDataModel\nfrom oef.schema import Description as OEFDescription\n\nfrom aea.helpers.search.models import (\n    And,\n    Attribute,\n    Constraint,\n    ConstraintExpr,\n    ConstraintType,\n    ConstraintTypes,\n    DataModel,\n    Description,\n    Location,\n    Not,\n    Or,\n    Query,\n)\n\n\n_default_logger = logging.getLogger(\"aea.packages.fetchai.connections.oef\")\n\n\nclass OEFObjectTranslator:\n    \"\"\"Translate our OEF object to object of OEF SDK classes.\"\"\"\n\n    @classmethod\n    def to_oef_description(cls, desc: Description) -> OEFDescription:\n        \"\"\"From our description to OEF description.\"\"\"\n        oef_data_model = (\n            cls.to_oef_data_model(desc.data_model)\n            if desc.data_model is not None\n            else None\n        )\n\n        new_values = {}\n        location_keys = set()\n        loggers_by_key = {}\n        for key, value in desc.values.items():\n            if isinstance(value, Location):\n                oef_location = OEFLocation(\n                    latitude=value.latitude, longitude=value.longitude\n                )\n                location_keys.add(key)\n                new_values[key] = oef_location\n            else:\n                new_values[key] = value\n\n        # this is a workaround to make OEFLocation objects deep-copyable.\n        # Indeed, there is a problem in deep-copying such objects\n        # because of the logger object they have attached.\n        # Steps:\n        # 1) we remove the loggers attached to each Location obj,\n        # 2) then we instantiate the description (it runs deepcopy on the values),\n        # 3) and then we reattach the loggers.\n        for key in location_keys:\n            loggers_by_key[key] = new_values[key].log\n            # in this way we remove the logger\n            new_values[key].log = None\n\n        description = OEFDescription(new_values, oef_data_model)\n\n        for key in location_keys:\n            new_values[key].log = loggers_by_key[key]\n\n        return description\n\n    @classmethod\n    def to_oef_data_model(cls, data_model: DataModel) -> OEFDataModel:\n        \"\"\"From our data model to OEF data model.\"\"\"\n        oef_attributes = [\n            cls.to_oef_attribute(attribute) for attribute in data_model.attributes\n        ]\n        return OEFDataModel(data_model.name, oef_attributes, data_model.description)\n\n    @classmethod\n    def to_oef_attribute(cls, attribute: Attribute) -> OEFAttribute:\n        \"\"\"From our attribute to OEF attribute.\"\"\"\n        # in case the attribute type is Location, replace with the `oef` class.\n        attribute_type = OEFLocation if attribute.type == Location else attribute.type\n        return OEFAttribute(\n            attribute.name, attribute_type, attribute.is_required, attribute.description\n        )\n\n    @classmethod\n    def to_oef_query(cls, query: Query) -> OEFQuery:\n        \"\"\"From our query to OEF query.\"\"\"\n        oef_data_model = (\n            cls.to_oef_data_model(query.model) if query.model is not None else None\n        )\n        constraints = [cls.to_oef_constraint_expr(c) for c in query.constraints]\n        return OEFQuery(constraints, oef_data_model)\n\n    @classmethod\n    def to_oef_location(cls, location: Location) -> OEFLocation:\n        \"\"\"From our location to OEF location.\"\"\"\n        return OEFLocation(latitude=location.latitude, longitude=location.longitude)  # type: ignore\n\n    @classmethod\n    def to_oef_constraint_expr(\n        cls, constraint_expr: ConstraintExpr\n    ) -> OEFConstraintExpr:\n        \"\"\"From our constraint expression to the OEF constraint expression.\"\"\"\n        if isinstance(constraint_expr, And):\n            return OEFAnd(\n                [cls.to_oef_constraint_expr(c) for c in constraint_expr.constraints]\n            )\n        if isinstance(constraint_expr, Or):\n            return OEFOr(\n                [cls.to_oef_constraint_expr(c) for c in constraint_expr.constraints]\n            )\n        if isinstance(constraint_expr, Not):\n            return OEFNot(cls.to_oef_constraint_expr(constraint_expr.constraint))\n        if isinstance(constraint_expr, Constraint):\n            oef_constraint_type = cls.to_oef_constraint_type(\n                constraint_expr.constraint_type\n            )\n            return OEFConstraint(constraint_expr.attribute_name, oef_constraint_type)\n        raise ValueError(\"Constraint expression not supported.\")\n\n    @classmethod\n    def to_oef_constraint_type(\n        cls, constraint_type: ConstraintType\n    ) -> OEFConstraintType:\n        \"\"\"From our constraint type to OEF constraint type.\"\"\"\n        value = constraint_type.value\n\n        def distance(value: Tuple) -> Distance:\n            location = cls.to_oef_location(location=value[0])\n            return Distance(center=location, distance=value[1])\n\n        CONSTRAINT_MAP = {\n            ConstraintTypes.EQUAL: Eq,\n            ConstraintTypes.NOT_EQUAL: NotEq,\n            ConstraintTypes.LESS_THAN: Lt,\n            ConstraintTypes.LESS_THAN_EQ: LtEq,\n            ConstraintTypes.GREATER_THAN: Gt,\n            ConstraintTypes.GREATER_THAN_EQ: GtEq,\n            ConstraintTypes.WITHIN: Range,\n            ConstraintTypes.IN: In,\n            ConstraintTypes.NOT_IN: NotIn,\n            ConstraintTypes.DISTANCE: distance,\n        }\n\n        if constraint_type.type not in CONSTRAINT_MAP:\n            raise ValueError(\"Constraint type not recognized.\")\n\n        return CONSTRAINT_MAP[constraint_type.type](value)\n\n    @classmethod\n    def from_oef_description(cls, oef_desc: OEFDescription) -> Description:\n        \"\"\"From an OEF description to our description.\"\"\"\n        data_model = (\n            cls.from_oef_data_model(oef_desc.data_model)\n            if oef_desc.data_model is not None\n            else None\n        )\n\n        new_values = {}\n        for key, value in oef_desc.values.items():\n            if isinstance(value, OEFLocation):\n                new_values[key] = Location(\n                    latitude=value.latitude, longitude=value.longitude\n                )\n            else:\n                new_values[key] = value\n\n        return Description(new_values, data_model=data_model)\n\n    @classmethod\n    def from_oef_data_model(cls, oef_data_model: OEFDataModel) -> DataModel:\n        \"\"\"From an OEF data model to our data model.\"\"\"\n        attributes = [\n            cls.from_oef_attribute(oef_attribute)\n            for oef_attribute in oef_data_model.attribute_schemas\n        ]\n        return DataModel(oef_data_model.name, attributes, oef_data_model.description)\n\n    @classmethod\n    def from_oef_attribute(cls, oef_attribute: OEFAttribute) -> Attribute:\n        \"\"\"From an OEF attribute to our attribute.\"\"\"\n        oef_attribute_type = (\n            Location if oef_attribute.type == OEFLocation else oef_attribute.type\n        )\n        return Attribute(\n            oef_attribute.name,\n            oef_attribute_type,\n            oef_attribute.required,\n            oef_attribute.description,\n        )\n\n    @classmethod\n    def from_oef_query(cls, oef_query: OEFQuery) -> Query:\n        \"\"\"From our query to OrOEF query.\"\"\"\n        data_model = (\n            cls.from_oef_data_model(oef_query.model)\n            if oef_query.model is not None\n            else None\n        )\n        constraints = [cls.from_oef_constraint_expr(c) for c in oef_query.constraints]\n        return Query(constraints, data_model)\n\n    @classmethod\n    def from_oef_location(cls, oef_location: OEFLocation) -> Location:\n        \"\"\"From oef location to our location.\"\"\"\n        return Location(\n            latitude=oef_location.latitude, longitude=oef_location.longitude\n        )\n\n    @classmethod\n    def from_oef_constraint_expr(\n        cls, oef_constraint_expr: OEFConstraintExpr\n    ) -> ConstraintExpr:\n        \"\"\"From our query to OEF query.\"\"\"\n        if isinstance(oef_constraint_expr, OEFAnd):\n            return And(\n                [\n                    cls.from_oef_constraint_expr(c)\n                    for c in oef_constraint_expr.constraints\n                ]\n            )\n        if isinstance(oef_constraint_expr, OEFOr):\n            return Or(\n                [\n                    cls.from_oef_constraint_expr(c)\n                    for c in oef_constraint_expr.constraints\n                ]\n            )\n        if isinstance(oef_constraint_expr, OEFNot):\n            return Not(cls.from_oef_constraint_expr(oef_constraint_expr.constraint))\n        if isinstance(oef_constraint_expr, OEFConstraint):\n            constraint_type = cls.from_oef_constraint_type(\n                oef_constraint_expr.constraint\n            )\n            return Constraint(oef_constraint_expr.attribute_name, constraint_type)\n        raise ValueError(\"OEF Constraint not supported.\")\n\n    @classmethod\n    def from_oef_constraint_type(\n        cls, constraint_type: OEFConstraintType\n    ) -> ConstraintType:\n        \"\"\"From OEF constraint type to our constraint type.\"\"\"\n        if isinstance(constraint_type, Eq):\n            return ConstraintType(ConstraintTypes.EQUAL, constraint_type.value)\n        if isinstance(constraint_type, NotEq):\n            return ConstraintType(ConstraintTypes.NOT_EQUAL, constraint_type.value)\n        if isinstance(constraint_type, Lt):\n            return ConstraintType(ConstraintTypes.LESS_THAN, constraint_type.value)\n        if isinstance(constraint_type, LtEq):\n            return ConstraintType(ConstraintTypes.LESS_THAN_EQ, constraint_type.value)\n        if isinstance(constraint_type, Gt):\n            return ConstraintType(ConstraintTypes.GREATER_THAN, constraint_type.value)\n        if isinstance(constraint_type, GtEq):\n            return ConstraintType(\n                ConstraintTypes.GREATER_THAN_EQ, constraint_type.value\n            )\n        if isinstance(constraint_type, Range):\n            return ConstraintType(ConstraintTypes.WITHIN, constraint_type.values)\n        if isinstance(constraint_type, In):\n            return ConstraintType(ConstraintTypes.IN, constraint_type.values)\n        if isinstance(constraint_type, NotIn):\n            return ConstraintType(ConstraintTypes.NOT_IN, constraint_type.values)\n        if isinstance(constraint_type, Distance):\n            location = cls.from_oef_location(constraint_type.center)\n            return ConstraintType(\n                ConstraintTypes.DISTANCE, (location, constraint_type.distance)\n            )\n        raise ValueError(\"Constraint type not recognized.\")\n"
  },
  {
    "path": "packages/fetchai/connections/p2p_libp2p/README.md",
    "content": "# P2P Libp2p Connection\n\nThis connection enables point-to-point secure end-to-end encrypted communication between agents in a fully decentralized way.\nThe connection deploys a node that collectively maintains a distributed hash table (DHT) along with other nodes in the same network.\nThe DHT provides proper messages delivery by mapping agents addresses to their locations.\n\n## Usage\n\nFirst, add the connection to your AEA project: `aea add connection fetchai/p2p_libp2p:0.27.5`.\n\nNext, ensure that the connection is properly configured by setting:\n\n- `local_uri` to the local IP address and port number that the node should use, in format `${ip}:${port}`\n- `public_uri` to the external IP address and port number allocated for the node, can be the same as `local_uri` if running locally\n- `entry_peers` to a list of multiaddresses of already deployed nodes to join their network, should be empty for genesis node\n- `delegate_uri` to the IP address and port number for the delegate service, leave empty to disable the service\n\nIf the delegate service is enabled, then other AEAs can connect to the peer node using the `fetchai/p2p_libp2p_client:0.20.6` connection.\n"
  },
  {
    "path": "packages/fetchai/connections/p2p_libp2p/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Implementation of the p2p libp2p connection.\"\"\"\n"
  },
  {
    "path": "packages/fetchai/connections/p2p_libp2p/check_dependencies.py",
    "content": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Check that the dependencies 'gcc' and 'go' are installed in the system.\"\"\"\nimport asyncio\nimport os\nimport platform\nimport re\nimport shutil\nimport subprocess  # nosec\nimport sys\nimport tempfile\nfrom itertools import islice\nfrom shutil import copytree as copy_tree\nfrom subprocess import Popen, TimeoutExpired  # nosec\nfrom typing import Iterable, List, Optional, Pattern, Tuple\n\nfrom aea.exceptions import AEAException\nfrom aea.helpers.base import ensure_dir\n\n\ntry:\n    # flake8: noqa\n    # pylint: disable=unused-import,ungrouped-imports\n    from .consts import (  # type: ignore\n        LIBP2P_NODE_DEPS_DOWNLOAD_TIMEOUT,\n        LIBP2P_NODE_MODULE,\n        LIBP2P_NODE_MODULE_NAME,\n    )\nexcept ImportError:  # pragma: nocover\n    # flake8: noqa\n    # pylint: disable=unused-import,ungrouped-imports\n    from consts import (  # type: ignore\n        LIBP2P_NODE_DEPS_DOWNLOAD_TIMEOUT,\n        LIBP2P_NODE_MODULE,\n        LIBP2P_NODE_MODULE_NAME,\n    )\n\n\nERROR_MESSAGE_TEMPLATE_BINARY_NOT_FOUND = \"'{command}' is required by the libp2p connection, but it is not installed, or it is not accessible from the system path.\"\nERROR_MESSAGE_TEMPLATE_VERSION_TOO_LOW = \"The installed version of '{command}' is too low: expected at least {lower_bound}; found {actual_version}.\"\n\n# for the purposes of this script,\n# a version is a tuple of integers: (major, minor, patch)\nVERSION = Tuple[int, int, int]\nMINIMUM_GO_VERSION: VERSION = (1, 13, 0)\nMINIMUM_GCC_VERSION: VERSION = (7, 5, 0)\n\n\ndef nth(iterable: Iterable, n: int, default: int = 0) -> int:\n    \"\"\"Returns the nth item or a default value\"\"\"\n    return next(islice(iterable, n, None), default)\n\n\ndef get_version(*args: int) -> VERSION:\n    \"\"\"\n    Get the version from a list of arguments.\n\n    Set to '0' if there are not enough arguments.\n\n    :param args: positional arguments\n    :return: the version\n    \"\"\"\n    major = nth(args, 0, 0)\n    minor = nth(args, 1, 0)\n    patch = nth(args, 2, 0)\n    return major, minor, patch\n\n\ndef version_to_string(version: VERSION) -> str:\n    \"\"\"\n    Transform version to string.\n\n    :param version: the version.\n    :return: the string representation.\n    \"\"\"\n    return \".\".join(map(str, version))\n\n\ndef print_ok_message(\n    binary_name: str, actual_version: VERSION, version_lower_bound: VERSION\n) -> None:\n    \"\"\"\n    Print OK message.\n\n    :param binary_name: the binary binary_name.\n    :param actual_version: the actual version.\n    :param version_lower_bound: the version lower bound.\n    \"\"\"\n    print(\n        f\"check '{binary_name}'>={version_to_string(version_lower_bound)}, found {version_to_string(actual_version)}\"\n    )\n\n\ndef check_binary(\n    binary_name: str,\n    args: List[str],\n    version_regex: Pattern,\n    version_lower_bound: VERSION,\n) -> None:\n    \"\"\"\n    Check a binary is accessible from the terminal.\n\n    It breaks down in:\n    1) check if the binary is reachable from the system path;\n    2) check that the version number is higher or equal than the minimum required version.\n\n    :param binary_name: the name of the binary.\n    :param args: the arguments to provide to the binary to retrieve the version.\n    :param version_regex: the regex used to extract the version from the output.\n    :param version_lower_bound: the minimum required version.\n    \"\"\"\n    path = shutil.which(binary_name)\n    if not path:\n        raise AEAException(\n            ERROR_MESSAGE_TEMPLATE_BINARY_NOT_FOUND.format(command=binary_name)\n        )\n\n    version_getter_command = [binary_name, *args]\n    stdout = subprocess.check_output(version_getter_command).decode(\"utf-8\")  # nosec\n    version_match = version_regex.search(stdout)\n    if version_match is None:\n        print(\n            f\"Warning: cannot parse '{binary_name}' version from command: {version_getter_command}. stdout: {stdout}\"\n        )\n        return\n    actual_version: VERSION = get_version(*map(int, version_match.groups(default=\"0\")))\n    if actual_version < version_lower_bound:\n        raise AEAException(\n            ERROR_MESSAGE_TEMPLATE_VERSION_TOO_LOW.format(\n                command=binary_name,\n                lower_bound=version_to_string(version_lower_bound),\n                actual_version=version_to_string(actual_version),\n            )\n        )\n\n    print_ok_message(binary_name, actual_version, version_lower_bound)\n\n\ndef check_versions() -> None:\n    \"\"\"Check versions.\"\"\"\n    check_binary(\n        \"go\",\n        [\"version\"],\n        re.compile(r\"go version go([0-9]+)\\.([0-9]+)\"),\n        MINIMUM_GO_VERSION,\n    )\n    if platform.system() == \"Darwin\":\n        check_binary(  # pragma: nocover\n            \"gcc\",\n            [\"--version\"],\n            re.compile(r\"clang version.* ([0-9]+)\\.([0-9]+)\\.([0-9]+) \"),\n            MINIMUM_GCC_VERSION,\n        )\n    else:\n        check_binary(\n            \"gcc\",\n            [\"--version\"],\n            re.compile(r\"gcc.* ([0-9]+)\\.([0-9]+)\\.([0-9]+)\"),\n            MINIMUM_GCC_VERSION,\n        )\n\n\ndef main() -> None:  # pragma: nocover\n    \"\"\"The main entrypoint of the script.\"\"\"\n    if len(sys.argv) < 2:\n        raise ValueError(\"Please provide build directory path as an argument!\")\n    build_dir = sys.argv[1]\n    check_versions()\n    build_node(build_dir)\n\n\ndef _golang_module_build(\n    path: str,\n    timeout: float = LIBP2P_NODE_DEPS_DOWNLOAD_TIMEOUT,\n) -> Optional[str]:\n    \"\"\"\n    Builds go module located at `path`, downloads necessary dependencies\n\n    :param path: the path to the node code\n    :param timeout: the build timeout\n    :return: str with logs or error description if happens\n    \"\"\"\n    with Popen(  # nosec\n        [\"go\", \"build\"],\n        stdout=asyncio.subprocess.PIPE,\n        stderr=asyncio.subprocess.STDOUT,\n        cwd=path,\n        env=os.environ,\n    ) as proc:\n        try:\n            stdout, _ = proc.communicate(timeout=timeout)  # type: ignore\n        except TimeoutExpired:  # pragma: nocover\n            proc.terminate()\n            proc.wait(timeout=timeout)\n            return \"terminated by timeout\"\n\n        if proc.returncode != 0:  # pragma: nocover\n            return stdout.decode()  # type: ignore\n    return None\n\n\ndef build_node(build_dir: str) -> None:\n    \"\"\"Build node placed inside build_dir.\"\"\"\n    with tempfile.TemporaryDirectory() as dirname:\n        copy_tree(LIBP2P_NODE_MODULE, dirname, dirs_exist_ok=True)  # type: ignore\n        err_str = _golang_module_build(dirname)\n        if err_str:  # pragma: nocover\n            raise Exception(f\"Node build failed: {err_str}\")\n        ensure_dir(build_dir)\n        shutil.copy(\n            os.path.join(dirname, LIBP2P_NODE_MODULE_NAME),\n            os.path.join(build_dir, LIBP2P_NODE_MODULE_NAME),\n        )\n    print(f\"{LIBP2P_NODE_MODULE_NAME} built successfully!\")\n\n\nif __name__ == \"__main__\":\n    main()  # pragma: nocover\n"
  },
  {
    "path": "packages/fetchai/connections/p2p_libp2p/connection.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the p2p libp2p connection.\"\"\"\nimport asyncio\nimport logging\nimport os\nimport platform\nimport subprocess  # nosec\nimport sys\nfrom asyncio import AbstractEventLoop, CancelledError, events\nfrom ipaddress import ip_address\nfrom pathlib import Path\nfrom socket import gethostbyname\nfrom typing import Any, IO, List, Optional, Sequence, cast\n\nfrom aea.configurations.base import PublicId\nfrom aea.configurations.constants import DEFAULT_LEDGER\nfrom aea.connections.base import Connection, ConnectionStates\nfrom aea.crypto.base import Crypto\nfrom aea.exceptions import enforce\nfrom aea.helpers.acn.agent_record import AgentRecord\nfrom aea.helpers.acn.uri import Uri\nfrom aea.helpers.multiaddr.base import MultiAddr\nfrom aea.helpers.pipe import IPCChannel, TCPSocketChannel\nfrom aea.mail.base import Envelope\n\nfrom packages.fetchai.connections.p2p_libp2p.consts import LIBP2P_NODE_MODULE_NAME\nfrom packages.fetchai.protocols.acn import acn_pb2\nfrom packages.fetchai.protocols.acn.message import AcnMessage\n\n\n_default_logger = logging.getLogger(\"aea.packages.fetchai.connections.p2p_libp2p\")\n\nACN_CURRENT_VERSION = \"0.1.0\"\n\nLIBP2P_NODE_LOG_FILE = \"libp2p_node.log\"\n\nLIBP2P_NODE_ENV_FILE = \".env.libp2p\"\n\nLIBP2P_NODE_CLARGS = []  # type: List[str]\n\n\nPIPE_CONN_TIMEOUT = 10.0\n\nPUBLIC_ID = PublicId.from_str(\"fetchai/p2p_libp2p:0.27.5\")\n\nSUPPORTED_LEDGER_IDS = [\"fetchai\", \"cosmos\", \"ethereum\"]\n\nLIBP2P_SUCCESS_MESSAGE = \"Peer running in \"\n\nPOR_DEFAULT_SERVICE_ID = \"acn\"\n\n\ndef _ip_all_private_or_all_public(addrs: List[str]) -> bool:\n    if len(addrs) == 0:\n        return True\n\n    is_private = ip_address(gethostbyname(addrs[0])).is_private\n    is_loopback = ip_address(gethostbyname(addrs[0])).is_loopback\n\n    for addr in addrs:\n        if ip_address(gethostbyname(addr)).is_private != is_private:\n            return False  # pragma: nocover\n        if ip_address(gethostbyname(addr)).is_loopback != is_loopback:\n            return False\n    return True\n\n\ndef _golang_module_run(\n    path: str,\n    name: str,\n    args: Sequence[str],\n    log_file_desc: IO[str],\n    logger: logging.Logger = _default_logger,\n) -> subprocess.Popen:\n    \"\"\"\n    Runs a built module located at `path`.\n\n    :param path: the path to the go module.\n    :param name: the name of the module.\n    :param args: the args\n    :param log_file_desc: the file descriptor of the log file.\n    :param logger: the logger\n    :return: subprocess\n    \"\"\"\n    cmd = [os.path.join(path, name)]\n\n    cmd.extend(args)\n\n    env = os.environ\n    try:\n        logger.debug(cmd)\n        proc = subprocess.Popen(  # nosec  # pylint: disable=consider-using-with\n            cmd,\n            cwd=path,\n            env=env,\n            stdout=log_file_desc,\n            stderr=log_file_desc,\n            shell=False,\n        )\n    except Exception as e:\n        logger.error(\n            \"While executing go run . {} at {} : {}\".format(path, args, str(e))\n        )\n        raise e\n\n    return proc\n\n\nclass NodeClient:\n    \"\"\"Client to communicate with node using ipc channel(pipe).\"\"\"\n\n    ACN_ACK_TIMEOUT = 5\n\n    def __init__(self, pipe: IPCChannel, agent_record: AgentRecord) -> None:\n        \"\"\"Set node client with pipe.\"\"\"\n        self.pipe = pipe\n        self.agent_record = agent_record\n        self._wait_status: Optional[asyncio.Future] = None\n\n    async def connect(self) -> bool:\n        \"\"\"Connect to node with pipe.\"\"\"\n        return await self.pipe.connect()\n\n    async def send_envelope(self, envelope: Envelope) -> None:\n        \"\"\"Send envelope to node.\"\"\"\n        self._wait_status = asyncio.Future()\n        buf = self.make_acn_envelope_message(envelope)\n        await self._write(buf)\n\n        status = await self.wait_for_status()\n\n        if status.code != int(AcnMessage.StatusBody.StatusCode.SUCCESS):  # type: ignore  # pylint: disable=no-member\n            raise ValueError(  # pragma: nocover\n                f\"failed to send envelope. got error confirmation: {status.code}\"\n            )\n\n    async def wait_for_status(self) -> Any:\n        \"\"\"Get status.\"\"\"\n        if self._wait_status is None:  # pragma: nocover\n            raise ValueError(\"value failed!\")\n        try:\n            status = await asyncio.wait_for(\n                self._wait_status, timeout=self.ACN_ACK_TIMEOUT\n            )\n            return status\n        except asyncio.TimeoutError:  # pragma: nocover\n            if not self._wait_status.done():  # pragma: nocover\n                self._wait_status.set_exception(Exception(\"Timeout\"))\n            await asyncio.sleep(0)\n            raise ValueError(\"acn status await timeout!\")\n        finally:\n            self._wait_status = None\n\n    @staticmethod\n    def make_acn_envelope_message(envelope: Envelope) -> bytes:\n        \"\"\"Make acn message with envelope in.\"\"\"\n        acn_msg = acn_pb2.AcnMessage()\n        performative = acn_pb2.AcnMessage.Aea_Envelope_Performative()  # type: ignore\n        performative.envelope = envelope.encode()\n        acn_msg.aea_envelope.CopyFrom(performative)  # pylint: disable=no-member\n        buf = acn_msg.SerializeToString()\n        return buf\n\n    async def read_envelope(self) -> Optional[Envelope]:\n        \"\"\"Read envelope from the node.\"\"\"\n        while True:\n            buf = await self._read()\n\n            if not buf:\n                return None\n\n            try:\n                acn_msg = acn_pb2.AcnMessage()\n                acn_msg.ParseFromString(buf)\n\n            except Exception as e:\n                await self.write_acn_status_error(\n                    f\"Failed to parse acn message {e}\",\n                    status_code=AcnMessage.StatusBody.StatusCode.ERROR_DECODE,\n                )\n                raise ValueError(f\"Error parsing acn message: {e}\") from e\n\n            performative = acn_msg.WhichOneof(\"performative\")\n            if performative == \"aea_envelope\":  # pragma: nocover\n                aea_envelope = acn_msg.aea_envelope  # pylint: disable=no-member\n                try:\n                    envelope = Envelope.decode(aea_envelope.envelope)\n                    await self.write_acn_status_ok()\n                    return envelope\n                except Exception as e:\n                    await self.write_acn_status_error(\n                        f\"Failed to decode envelope: {e}\",\n                        status_code=AcnMessage.StatusBody.StatusCode.ERROR_DECODE,\n                    )\n                    raise\n\n            elif performative == \"status\":\n                if self._wait_status is not None:\n                    self._wait_status.set_result(\n                        acn_msg.status.body  # pylint: disable=no-member\n                    )\n            else:  # pragma: nocover\n                await self.write_acn_status_error(\n                    f\"Bad acn message {performative}\",\n                    status_code=AcnMessage.StatusBody.StatusCode.ERROR_UNEXPECTED_PAYLOAD,\n                )\n\n    async def write_acn_status_ok(self) -> None:\n        \"\"\"Send acn status ok.\"\"\"\n        acn_msg = acn_pb2.AcnMessage()\n        performative = acn_pb2.AcnMessage.Status_Performative()  # type: ignore\n        status = AcnMessage.StatusBody(\n            status_code=AcnMessage.StatusBody.StatusCode.SUCCESS, msgs=[]\n        )\n        AcnMessage.StatusBody.encode(\n            performative.body, status  # pylint: disable=no-member\n        )\n        acn_msg.status.CopyFrom(performative)  # pylint: disable=no-member\n        buf = acn_msg.SerializeToString()\n        await self._write(buf)\n\n    async def write_acn_status_error(\n        self,\n        msg: str,\n        status_code: AcnMessage.StatusBody.StatusCode = AcnMessage.StatusBody.StatusCode.ERROR_GENERIC,  # type: ignore\n    ) -> None:\n        \"\"\"Send acn status error generic.\"\"\"\n        acn_msg = acn_pb2.AcnMessage()\n        performative = acn_pb2.AcnMessage.Status_Performative()  # type: ignore\n        status = AcnMessage.StatusBody(status_code=status_code, msgs=[msg])\n        AcnMessage.StatusBody.encode(\n            performative.body, status  # pylint: disable=no-member\n        )\n        acn_msg.status.CopyFrom(performative)  # pylint: disable=no-member\n\n        buf = acn_msg.SerializeToString()\n\n        await self._write(buf)\n\n    async def _write(self, data: bytes) -> None:\n        \"\"\"\n        Write to the writer stream.\n\n        :param data: data to write to stream\n        \"\"\"\n        await self.pipe.write(data)\n\n    async def _read(self) -> Optional[bytes]:\n        \"\"\"\n        Read from the reader stream.\n\n        :return: bytes\n        \"\"\"\n        return await self.pipe.read()\n\n\nclass Libp2pNode:\n    \"\"\"Libp2p p2p node as a subprocess with named pipes interface.\"\"\"\n\n    def __init__(\n        self,\n        agent_record: AgentRecord,\n        key: Crypto,\n        module_path: str,\n        data_dir: str,\n        clargs: Optional[List[str]] = None,\n        uri: Optional[Uri] = None,\n        public_uri: Optional[Uri] = None,\n        delegate_uri: Optional[Uri] = None,\n        monitoring_uri: Optional[Uri] = None,\n        entry_peers: Optional[Sequence[MultiAddr]] = None,\n        log_file: Optional[str] = None,\n        env_file: Optional[str] = None,\n        logger: logging.Logger = _default_logger,\n        peer_registration_delay: Optional[float] = None,\n        records_storage_path: Optional[str] = None,\n        connection_timeout: Optional[float] = None,\n        max_restarts: int = 5,\n        mailbox_uri: str = \"127.0.0.1:8888\",\n    ):\n        \"\"\"\n        Initialize a p2p libp2p node.\n\n        :param agent_record: the agent proof-of-representation for peer.\n        :param key: secp256k1 curve private key.\n        :param module_path: the module path.\n        :param data_dir: the data directory.\n        :param clargs: the command line arguments for the libp2p node\n        :param uri: libp2p node ip address and port number in format ipaddress:port.\n        :param public_uri: libp2p node public ip address and port number in format ipaddress:port.\n        :param delegate_uri: libp2p node delegate service ip address and port number in format ipaddress:port.\n        :param monitoring_uri: libp2 node monitoring ip address and port in format ipaddress:port\n        :param entry_peers: libp2p entry peers multiaddresses.\n        :param log_file: the logfile path for the libp2p node\n        :param env_file: the env file path for the exchange of environment variables\n        :param logger: the logger.\n        :param peer_registration_delay: add artificial delay to agent registration in seconds\n        :param records_storage_path: the path where to store the agent records.\n        :param connection_timeout: the connection timeout of the node.\n        :param max_restarts: amount of node restarts during operation.\n        :param mailbox_uri: libp2p mailbox_uri ip address and port number in format ipaddress:port.\n        \"\"\"\n\n        self.record = agent_record\n        self.address = self.record.address\n\n        # node id in the p2p network\n        self.key = key.private_key\n        self.pub = key.public_key\n\n        # node uri\n        self.uri = uri if uri is not None else Uri()\n\n        # node public uri, optional\n        self.public_uri = public_uri\n\n        # node delegate uri, optional\n        self.delegate_uri = delegate_uri\n\n        # node monitoring uri, optional\n        self.monitoring_uri = monitoring_uri\n\n        # entry peer\n        self.entry_peers = entry_peers if entry_peers is not None else []\n\n        self.mailbox_uri = mailbox_uri\n\n        # peer configuration\n        self.peer_registration_delay = peer_registration_delay\n        self.records_storage_path = records_storage_path\n        if (\n            self.records_storage_path is not None\n            and not Path(self.records_storage_path).is_absolute()\n        ):\n            self.records_storage_path = os.path.join(  # pragma: nocover\n                data_dir, self.records_storage_path\n            )\n\n        # node startup\n        self.source = os.path.abspath(module_path)\n        self.clargs = clargs if clargs is not None else []\n\n        # node libp2p multiaddress\n        self.multiaddrs = []  # type: Sequence[MultiAddr]\n\n        # log file\n        self.log_file = log_file if log_file is not None else LIBP2P_NODE_LOG_FILE\n        if not Path(self.log_file).is_absolute():\n            self.log_file = os.path.join(data_dir, self.log_file)  # pragma: nocover\n        # env file\n        self.env_file = env_file if env_file is not None else LIBP2P_NODE_ENV_FILE\n        if not Path(self.env_file).is_absolute():\n            self.env_file = os.path.join(data_dir, self.env_file)\n\n        # named pipes (fifos)\n        self.pipe = None  # type: Optional[IPCChannel]\n\n        self._loop = None  # type: Optional[AbstractEventLoop]\n        self.proc = None  # type: Optional[subprocess.Popen]\n        self._log_file_desc = None  # type: Optional[IO[str]]\n\n        self.logger = logger\n        self._connection_timeout = (\n            connection_timeout if connection_timeout is not None else PIPE_CONN_TIMEOUT\n        )\n        self._max_restarts = max_restarts\n        self._restart_counter: int = 0\n        self._is_on_stop: bool = False\n\n    def _make_env_file(self, pipe_in_path: str, pipe_out_path: str) -> str:\n        # setup config\n        if os.path.exists(self.env_file):\n            os.remove(self.env_file)  # pragma: nocover\n\n        config = \"\"\n        config += \"AEA_AGENT_ADDR={}\\n\".format(self.address)\n        config += \"AEA_P2P_ID={}\\n\".format(self.key)\n        config += \"AEA_P2P_URI={}\\n\".format(str(self.uri))\n        config += \"AEA_P2P_ENTRY_URIS={}\\n\".format(\n            \",\".join(\n                [\n                    str(maddr)\n                    for maddr in self.entry_peers\n                    if str(maddr) != str(self.uri)  # TOFIX(LR) won't exclude self\n                ]\n            )\n        )\n        config += \"NODE_TO_AEA={}\\n\".format(pipe_in_path)\n        config += \"AEA_TO_NODE={}\\n\".format(pipe_out_path)\n        config += \"AEA_P2P_URI_PUBLIC={}\\n\".format(\n            str(self.public_uri) if self.public_uri is not None else \"\"\n        )\n        config += \"AEA_P2P_DELEGATE_URI={}\\n\".format(\n            str(self.delegate_uri) if self.delegate_uri is not None else \"\"\n        )\n        config += \"AEA_P2P_URI_MONITORING={}\\n\".format(\n            str(self.monitoring_uri) if self.monitoring_uri is not None else \"\"\n        )\n        config += \"AEA_P2P_POR_ADDRESS={}\\n\".format(self.record.address)\n        config += \"AEA_P2P_POR_PUBKEY={}\\n\".format(self.record.public_key)\n        config += \"AEA_P2P_POR_PEER_PUBKEY={}\\n\".format(\n            self.record.representative_public_key\n        )\n        config += \"AEA_P2P_POR_SIGNATURE={}\\n\".format(self.record.signature)\n        config += \"AEA_P2P_POR_SERVICE_ID={}\\n\".format(POR_DEFAULT_SERVICE_ID)\n        config += \"AEA_P2P_POR_LEDGER_ID={}\\n\".format(self.record.ledger_id)\n        config += \"AEA_P2P_CFG_REGISTRATION_DELAY={}\\n\".format(\n            str(self.peer_registration_delay)\n            if self.peer_registration_delay is not None\n            else str(0.0)\n        )\n        config += \"AEA_P2P_CFG_STORAGE_PATH={}\\n\".format(\n            self.records_storage_path if self.records_storage_path is not None else \"\"\n        )\n\n        config += \"AEA_P2P_MAILBOX_URI={}\\n\".format(self.mailbox_uri)\n\n        with open(\n            self.env_file, \"w\", encoding=\"utf-8\"\n        ) as env_file:  # overwrite if exists\n            env_file.write(config)\n\n        return config\n\n    async def _set_connection_to_node(self) -> bool:\n        if self.pipe is None:\n            raise Exception(\"pipe was not set\")  # pragma: nocover\n\n        return await self.pipe.connect(timeout=self._connection_timeout)\n\n    def get_client(self) -> NodeClient:\n        \"\"\"Get client instance to communicate to node.\"\"\"\n        if self.pipe is None:\n            raise Exception(\"pipe was not set\")  # pragma: nocover\n\n        return NodeClient(self.pipe, self.record)\n\n    def _child_watcher_callback(self, *_) -> None:  # type: ignore # pragma: nocover\n        \"\"\"Log if process was terminated before stop was called.\"\"\"\n        if self._is_on_stop:\n            return\n        if self.proc is None:\n            return\n        self.proc.poll()\n        returncode = self.proc.returncode\n        self.logger.error(\n            f\"Node process with pid {self.proc.pid} was terminated with returncode {returncode}\"\n        )\n\n    def is_proccess_running(self) -> bool:\n        \"\"\"Check process is running.\"\"\"\n        if not self.proc:\n            return False\n\n        self.proc.poll()\n        return self.proc.returncode is None\n\n    async def start(self) -> None:\n        \"\"\"Start the node.\"\"\"\n        self._is_on_stop = False\n        if self._loop is None:\n            self._loop = asyncio.get_event_loop()\n\n        self._log_file_desc = open(  # pylint: disable=consider-using-with\n            self.log_file, \"a\", 1, encoding=\"utf-8\"\n        )\n        self._log_file_desc.write(\"test\")\n        self._log_file_desc.flush()\n\n        # tcp socket on every platform\n        self.pipe = TCPSocketChannel(logger=self.logger)\n\n        env_file_data = self._make_env_file(\n            pipe_in_path=self.pipe.in_path, pipe_out_path=self.pipe.out_path\n        )\n        # run node\n        self.logger.info(\"Starting libp2p node...\")\n        self.proc = _golang_module_run(\n            self.source, LIBP2P_NODE_MODULE_NAME, [self.env_file], self._log_file_desc\n        )\n\n        if (\n            platform.system() != \"Windows\"\n            and sys.version_info.major == 3\n            and sys.version_info.minor >= 8\n        ):  # pragma: nocover\n            with events.get_child_watcher() as watcher:\n                if watcher:\n                    watcher.add_child_handler(\n                        self.proc.pid, self._child_watcher_callback\n                    )\n\n        self.logger.info(\"Connecting to libp2p node...\")\n\n        try:\n            connected = await self._set_connection_to_node()\n\n            if not connected:\n                raise Exception(\"Couldn't connect to libp2p process within timeout\")\n        except Exception as e:\n            err_msg = self.get_libp2p_node_error()\n            self.logger.error(\"Couldn't connect to libp2p process: {}\".format(err_msg))\n            self.logger.error(\n                \"Libp2p process configuration:\\n{}\".format(env_file_data.strip())\n            )\n            if err_msg == \"\":\n                with open(self.log_file, \"r\", encoding=\"utf-8\") as f:\n                    self.logger.error(\n                        \"Libp2p process log file {}:\\n{}\".format(\n                            self.log_file, f.read()\n                        )\n                    )\n            else:  # pragma: nocover\n                self.logger.error(\n                    \"Please check log file {} for more details.\".format(self.log_file)\n                )\n\n            await self.stop()\n            raise e\n\n        self.logger.info(\"Successfully connected to libp2p node!\")\n        self.multiaddrs = self.get_libp2p_node_multiaddrs()\n        self.describe_configuration()\n\n    async def restart(self) -> None:\n        \"\"\"Perform node restart.\"\"\"\n        if self._restart_counter >= self._max_restarts:\n            raise ValueError(f\"Max restarts attempts reached: {self._max_restarts}\")\n        await self.stop()\n        await self.start()\n        self._restart_counter += 1\n\n    def describe_configuration(self) -> None:\n        \"\"\"Print a message describing the libp2p node configuration\"\"\"\n        msg = LIBP2P_SUCCESS_MESSAGE\n\n        if self.public_uri is not None:\n            msg += \"full DHT mode with \"\n            if self.delegate_uri is not None:  # pragma: nocover\n                msg += \"delegate service reachable at '{}:{}' and relay service enabled. \".format(\n                    self.public_uri.host, self.delegate_uri.port\n                )\n            else:\n                msg += \"relay service enabled. \"\n\n            msg += \"To join its network use multiaddr '{}'.\".format(self.multiaddrs[0])\n        else:\n            msg += \"relayed mode and cannot be used as entry peer.\"\n\n        self.logger.info(msg)\n\n    def get_libp2p_node_multiaddrs(self) -> Sequence[MultiAddr]:\n        \"\"\"\n        Get the node's multiaddresses.\n\n        :return: a list of multiaddresses\n        \"\"\"\n        LIST_START = \"MULTIADDRS_LIST_START\"\n        LIST_END = \"MULTIADDRS_LIST_END\"\n\n        multiaddrs = []  # type: List[MultiAddr]\n\n        with open(self.log_file, \"r\", encoding=\"utf-8\") as f:\n            lines = f.readlines()\n\n        found = False\n        for line in lines:\n            if LIST_START in line:\n                found = True\n                multiaddrs = []\n                continue\n            if found:\n                elem = line.strip()\n                if elem != LIST_END and len(elem) != 0:\n                    multiaddrs.append(MultiAddr.from_string(elem))\n                else:\n                    found = False\n        return multiaddrs\n\n    def get_libp2p_node_error(self) -> str:\n        \"\"\"\n        Parses libp2p node logs for critical errors\n\n        :return: error message if any, empty string otherwise\n        \"\"\"\n\n        CRITICAL_ERROR = \"LIBP2P_NODE_PANIC_ERROR\"\n        PANIC_ERROR = \"panic:\"\n\n        error_msg = \"\"\n        panic_msg = \"\"\n\n        with open(self.log_file, \"r\", encoding=\"utf-8\") as f:\n            lines = f.readlines()\n\n        for line in lines:  # pragma: nocover\n            if CRITICAL_ERROR in line:\n                parts = line.split(\":\", 1)\n                error_msg = parts[1].strip()\n            if PANIC_ERROR in line:\n                parts = line.split(\":\", 1)\n                panic_msg = parts[1].strip()\n\n        return error_msg if error_msg != \"\" else panic_msg\n\n    async def stop(self) -> None:\n        \"\"\"Stop the node.\"\"\"\n        if self.proc is not None:\n            self.logger.debug(\"Terminating node process {}...\".format(self.proc.pid))\n            self._is_on_stop = True\n            self.proc.poll()\n            self.proc.terminate()\n            self.logger.debug(\n                \"Waiting for node process {} to terminate...\".format(self.proc.pid)\n            )\n            self.proc.wait()\n            if self._log_file_desc is None:\n                raise ValueError(\"log file descriptor is not set.\")  # pragma: nocover\n            self._log_file_desc.close()\n        else:\n            self.logger.debug(\"Called stop when process not set!\")  # pragma: no cover\n\n        if self.pipe is not None:\n            try:\n                await self.pipe.close()\n            except Exception as e:  # pragma: nocover pylint: disable=broad-except\n                self.logger.exception((f\"Failure during pipe closing. Exception: {e}\"))\n            self.pipe = None\n        else:\n            self.logger.debug(\"Called stop when pipe not set!\")  # pragma: no cover\n\n        if os.path.exists(self.env_file):\n            os.remove(self.env_file)\n\n\nclass P2PLibp2pConnection(Connection):\n    \"\"\"A libp2p p2p node connection.\"\"\"\n\n    connection_id = PUBLIC_ID\n    DEFAULT_MAX_RESTARTS = 5\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"Initialize a p2p libp2p connection.\"\"\"\n        super().__init__(**kwargs)\n        ledger_id = self.configuration.config.get(\"ledger_id\", DEFAULT_LEDGER)\n        if ledger_id not in SUPPORTED_LEDGER_IDS:\n            raise ValueError(  # pragma: nocover\n                \"Ledger id '{}' is not supported. Supported ids: '{}'\".format(\n                    ledger_id, SUPPORTED_LEDGER_IDS\n                )\n            )\n        libp2p_local_uri: Optional[str] = self.configuration.config.get(\"local_uri\")\n        libp2p_public_uri: Optional[str] = self.configuration.config.get(\"public_uri\")\n        libp2p_delegate_uri: Optional[str] = self.configuration.config.get(\n            \"delegate_uri\"\n        )\n        libp2p_monitoring_uri: Optional[str] = self.configuration.config.get(\n            \"monitoring_uri\"\n        )\n        libp2p_entry_peers = self.configuration.config.get(\"entry_peers\")\n        if libp2p_entry_peers is None:\n            libp2p_entry_peers = []\n        libp2p_entry_peers = list(cast(List, libp2p_entry_peers))\n        log_file: Optional[str] = self.configuration.config.get(\"log_file\")\n        env_file: Optional[str] = self.configuration.config.get(\"env_file\")\n        peer_registration_delay: Optional[str] = self.configuration.config.get(\n            \"peer_registration_delay\"\n        )\n        records_storage_path: Optional[str] = self.configuration.config.get(\n            \"storage_path\"\n        )\n        node_connection_timeout: Optional[float] = self.configuration.config.get(\n            \"node_connection_timeout\", PIPE_CONN_TIMEOUT\n        )\n        if (\n            self.has_crypto_store\n            and self.crypto_store.crypto_objects.get(ledger_id, None) is not None\n        ):  # pragma: no cover\n            key = self.crypto_store.crypto_objects[ledger_id]\n        else:\n            raise ValueError(\n                f\"Couldn't find connection key for {str(ledger_id)} in connections keys. \"\n                \"Please ensure agent private key is added with `aea add-key`.\"\n            )\n\n        uri = None\n        if libp2p_local_uri is not None:\n            uri = Uri(libp2p_local_uri)\n\n        public_uri = None\n        if libp2p_public_uri is not None:\n            public_uri = Uri(libp2p_public_uri)\n\n        delegate_uri = None\n        if libp2p_delegate_uri is not None:  # pragma: nocover\n            delegate_uri = Uri(libp2p_delegate_uri)\n\n        monitoring_uri = None\n        if libp2p_monitoring_uri is not None:\n            monitoring_uri = Uri(libp2p_monitoring_uri)  # pragma: nocover\n\n        entry_peers = [\n            MultiAddr.from_string(str(maddr)) for maddr in libp2p_entry_peers\n        ]\n\n        delay = None\n        if peer_registration_delay is not None:\n            try:\n                delay = float(peer_registration_delay)\n            except ValueError:\n                raise ValueError(\n                    f\"peer_registration_delay {peer_registration_delay} must be a float number in seconds\"\n                )\n\n        if public_uri is None:\n            # node will be run as a ClientDHT\n            # requires entry peers to use as relay\n            if entry_peers is None or len(entry_peers) == 0:\n                raise ValueError(  # pragma: no cover\n                    \"At least one Entry Peer should be provided when node is run in relayed mode\"\n                )\n            if delegate_uri is not None:  # pragma: no cover\n                self.logger.warning(\n                    \"Ignoring Delegate Uri configuration as node is run in relayed mode\"\n                )\n        else:\n            # node will be run as a full NodeDHT\n            if uri is None:\n                raise ValueError(  # pragma: no cover\n                    \"Local Uri must be set when Public Uri is provided. \"\n                    \"Hint: they are the same for local host/network deployment\"\n                )\n            # check if node's public host and entry peers hosts are either\n            #  both private or both public\n            if not _ip_all_private_or_all_public(\n                [public_uri.host] + [maddr.host for maddr in entry_peers]\n            ):\n                raise ValueError(  # pragma: nocover\n                    \"Node's public ip and entry peers ip addresses are not in the same ip address space (private/public)\"\n                )\n\n        cert_requests = self.configuration.cert_requests\n        if cert_requests is None or len(cert_requests) != 1:\n            raise ValueError(  # pragma: no cover\n                \"cert_requests field must be set and contain exactly one entry!\"\n            )\n        cert_request = cert_requests[0]\n\n        agent_record = AgentRecord.from_cert_request(\n            cert_request, self.address, key.public_key, Path(self.data_dir)\n        )\n\n        # libp2p local node\n        self.logger.debug(\"Public key used by libp2p node: {}\".format(key.public_key))\n\n        if self.configuration.config.get(\"mailbox_uri\"):\n            mailbox_uri = str(self.configuration.config.get(\"mailbox_uri\"))\n        else:\n            mailbox_uri = \"\"\n\n        module_dir = self._check_node_built()\n        self.node = Libp2pNode(\n            agent_record,\n            key,\n            module_dir,\n            self.data_dir,\n            LIBP2P_NODE_CLARGS,\n            uri,\n            public_uri,\n            delegate_uri,\n            monitoring_uri,\n            entry_peers,\n            log_file,\n            env_file,\n            self.logger,\n            delay,\n            records_storage_path,\n            node_connection_timeout,\n            max_restarts=self.configuration.config.get(\n                \"max_node_restarts\", self.DEFAULT_MAX_RESTARTS\n            ),\n            mailbox_uri=mailbox_uri,\n        )\n\n        self._in_queue = None  # type: Optional[asyncio.Queue]\n        self._receive_from_node_task = None  # type: Optional[asyncio.Future]\n        self._node_client: Optional[NodeClient] = None\n\n        self._send_queue: Optional[asyncio.Queue] = None\n        self._send_task: Optional[asyncio.Task] = None\n\n    def _check_node_built(self) -> str:\n        \"\"\"Check node built.\"\"\"\n        if self.configuration.build_directory is None:\n            raise ValueError(\"Connection Configuration build directory is not set!\")\n\n        libp2p_node_module_path = os.path.join(\n            self.configuration.build_directory, LIBP2P_NODE_MODULE_NAME\n        )\n        enforce(\n            os.path.exists(libp2p_node_module_path),\n            f\"Module {LIBP2P_NODE_MODULE_NAME} is not present in {self.configuration.build_directory}, please call the `aea build` command first!\",\n        )\n        return self.configuration.build_directory\n\n    async def connect(self) -> None:\n        \"\"\"Set up the connection.\"\"\"\n        if self.is_connected:\n            return  # pragma: nocover\n            # start libp2p node\n        with self._connect_context():\n            self.node.logger = self.logger\n            await self._start_node()\n            # starting receiving msgs\n            self._in_queue = asyncio.Queue()\n            self._send_queue = asyncio.Queue()\n            self._receive_from_node_task = asyncio.ensure_future(\n                self._receive_from_node(), loop=self.loop\n            )\n            self._send_task = self.loop.create_task(self._send_loop())\n\n    async def _start_node(self) -> None:\n        \"\"\"Start node and set node client instance.\"\"\"\n        await self.node.start()\n        self._node_client = self.node.get_client()\n\n    async def _restart_node(self) -> None:\n        \"\"\"Stop and start node again.\"\"\"\n        await self.node.stop()\n        await self._start_node()\n\n    async def disconnect(self) -> None:\n        \"\"\"Disconnect from the channel.\"\"\"\n        if self.is_disconnected:\n            return  # pragma: nocover\n\n        self.state = ConnectionStates.disconnecting\n        try:\n\n            if self._receive_from_node_task is not None:\n                self._receive_from_node_task.cancel()\n                self._receive_from_node_task = None\n\n            if self._send_task is not None:\n                self._send_task.cancel()\n                self._send_task = None\n\n            await self.node.stop()\n            if self._in_queue is not None:\n                self._in_queue.put_nowait(None)\n            else:\n                self.logger.debug(  # pragma: nocover\n                    \"Called disconnect when input queue not initialized.\"\n                )\n        finally:\n            self.state = ConnectionStates.disconnected\n\n    async def receive(self, *args: Any, **kwargs: Any) -> Optional[\"Envelope\"]:\n        \"\"\"\n        Receive an envelope. Blocking.\n\n        :param args: positional arguments\n        :param kwargs: keyword arguments\n        :return: the envelope received, or None.\n        \"\"\"\n        try:\n            if self._in_queue is None:\n                raise ValueError(\"Input queue not initialized.\")  # pragma: nocover\n            envelope = await self._in_queue.get()\n            if envelope is None:  # pragma: nocover\n                self.logger.debug(\"Received None.\")\n                return None\n            return envelope\n        except CancelledError:  # pragma: no cover\n            self.logger.debug(\"Receive cancelled.\")\n            return None\n        except Exception as e:  # pragma: nocover # pylint: disable=broad-except\n            self.logger.exception(e)\n            return None\n\n    async def _send_envelope_with_node_client(self, envelope: Envelope) -> None:\n        if not self._node_client:  # pragma: nocover\n            raise ValueError(f\"Node client not set! Can not send envelope: {envelope}\")\n\n        if not self.node.pipe:  # pragma: nocover\n            raise ValueError(\"Node is not connected\")\n\n        try:\n            await self._node_client.send_envelope(envelope)\n            return\n        except asyncio.CancelledError:  # pylint: disable=try-except-raise\n            raise  # pragma: nocover\n        except Exception as e:  # pylint: disable=broad-except\n            self.logger.exception(\n                f\"Failed to send. Exception: {e}. Try recover connection to node and send again.\"\n            )\n\n        try:\n            if self.node.is_proccess_running():\n                await self.node.pipe.connect()\n                await self._node_client.send_envelope(envelope)\n                self.logger.debug(\"Envelope sent after reconnect to node\")\n                return\n        except asyncio.CancelledError:  # pylint: disable=try-except-raise\n            raise  # pragma: nocover\n        except Exception as e:  # pylint: disable=broad-except\n            self.logger.exception(\n                f\"Failed to send after pipe reconnect. Exception: {e}. Try recover connection to node and send again.\"\n            )\n\n        try:\n            await self._restart_node()\n            await self._node_client.send_envelope(envelope)\n        except asyncio.CancelledError:  # pylint: disable=try-except-raise\n            raise  # pragma: nocover\n        except Exception as e:  # pylint: disable=broad-except\n            self.logger.exception(\n                f\"Failed to send after node restart. Exception: {e}. Try recover connection to node and send again.\"\n            )\n            raise\n\n    async def _send_loop(self) -> None:\n        \"\"\"Handle message in  the send queue.\"\"\"\n\n        if not self._send_queue or not self._node_client:  # pragma: nocover\n            self.logger.error(\"Send loop not started cause not connected properly.\")\n            return\n        try:\n            while self.is_connected:\n                envelope = await self._send_queue.get()\n                await self._send_envelope_with_node_client(envelope)\n        except asyncio.CancelledError:  # pylint: disable=try-except-raise\n            raise  # pragma: nocover\n        except Exception:  # pylint: disable=broad-except # pragma: nocover\n            self.logger.exception(\n                f\"Failed to send an envelope {envelope}. Stop connection.\"\n            )\n            await asyncio.shield(self.disconnect())\n\n    async def send(self, envelope: Envelope) -> None:\n        \"\"\"\n        Send messages.\n\n        :param envelope: the envelope\n        \"\"\"\n        if not self._node_client or not self._send_queue:\n            raise ValueError(\"Node is not connected!\")  # pragma: nocover\n\n        self._ensure_valid_envelope_for_external_comms(envelope)\n        await self._send_queue.put(envelope)\n\n    async def _read_envelope_from_node(self) -> Optional[Envelope]:\n        if not self._node_client:\n            raise ValueError(\"Node is not connected!\")  # pragma: nocover\n        try:\n            return await self._node_client.read_envelope()\n        except asyncio.CancelledError:  # pylint: disable=try-except-raise\n            raise  # pragma: nocover\n        except Exception as e:  # pylint: disable=broad-except\n            self.logger.exception(\n                f\"Failed to read. Exception: {e}. Try reconnect to node and read again.\"\n            )\n\n            await self._restart_node()\n            return await self._node_client.read_envelope()\n\n    async def _receive_from_node(self) -> None:\n        \"\"\"Receive data from node.\"\"\"\n        while True:\n            if self._in_queue is None:\n                raise ValueError(\"Input queue not initialized.\")  # pragma: nocover\n\n            if not self._node_client:\n                raise ValueError(\"Node is not connected!\")  # pragma: nocover\n\n            envelope = await self._read_envelope_from_node()\n            if envelope is None:\n                break\n            self._in_queue.put_nowait(envelope)\n"
  },
  {
    "path": "packages/fetchai/connections/p2p_libp2p/connection.yaml",
    "content": "name: p2p_libp2p\nauthor: fetchai\nversion: 0.27.5\ntype: connection\ndescription: The p2p libp2p connection implements an interface to standalone golang\n  go-libp2p node that can exchange aea envelopes with other agents connected to the\n  same DHT.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: Qmf8Gh38S4rtZVh2yPUTdHrAEpovt1ULg4bccaFNZfYxCt\n  __init__.py: Qmcwvb5isp1zoF57phgDHEPTNLuPa5zCkEC4JSsDUUHE78\n  check_dependencies.py: QmXCg3mGhHzGxxbaTtHKY1HfumubPKryiaBeBMbJEZLQTE\n  connection.py: QmZxZagVYj9NVzAYtM9UyMPsiXjz6uPuF8Ywb2WnJnTDiZ\n  consts.py: QmXi6edKonz6SuAnRnMURRRU62GNZa9TRhqiDxmnwLB4Sp\n  libp2p_node/.dockerignore: QmVwyNjya468nRTxSjFP73dSzQdSffp74osz5dGEAHHweA\n  libp2p_node/Dockerfile: QmeZ6KJf4cpgL7DY6qdWetVfTPPijUvHxoCUbYgSS3SsWM\n  libp2p_node/Makefile: Qmezxsp96mW85mJhjGAarLmwWJG9JvGJowcY5h56oPB9bt\n  libp2p_node/README.md: QmR1Lk6utZWxN1rEBmTodenwfyjTucv5akx9GGcFzxmPjb\n  libp2p_node/acn/utils.go: Qmb39aDGu7N5a8JPdHeRsjSzJ9fyKp2jT3EkULocvGGYKV\n  libp2p_node/aea/api.go: QmW7mHHShumfDHg9Ds1nxHZJN4EAHGLrr15jLX7kKYkcV9\n  libp2p_node/aea/envelope.pb.go: QmRfUNGpCeVJfsW3H1MzCN4pwDWgumfyWufVFp6xvUjjug\n  libp2p_node/aea/envelope.proto: QmVuvesmfgzj5aKnbFoCocoGEv3T9MR7u6KWn7CT5yfjGi\n  libp2p_node/aea/pipe.go: QmdY77nQhJt5ojfcpJn2quaxdseGxS8GymQbzNvizkXNoz\n  libp2p_node/aea/utils.go: QmbPhDuPZzzA8hrf7U5uLxsVQqY31BHJbv9fiGYEPDg1Go\n  libp2p_node/common/common.go: QmeGr6xMzqkBVJMnWzCTcXJVQj2A8RK64mhTSewZJKpiJa\n  libp2p_node/dht/common/handlers.go: Qmb5bvheRaddLXmcjwLNPyKq3SX5dqWUwc6aop5YjE9WMx\n  libp2p_node/dht/dhtclient/dhtclient.go: QmP9Jzr7s38iJPuWUuMuFJ8TiepHT2AwaYzzKZ7hgWAUWg\n  libp2p_node/dht/dhtclient/dhtclient_test.go: QmY5YQVYPHYdHc3GXPgbMQBtMstEpYiik1KtZH9ZchJVNh\n  libp2p_node/dht/dhtclient/options.go: QmbjHT3ZXFo5GaMDTFbpZVRNiq3KPeoQWuGQuDaz7QJfaU\n  libp2p_node/dht/dhtnode/dhtnode.go: QmfYx33eCLKLz7cVGrj3wTRF9oLjeS8yXR7kSKmQSfHPP8\n  libp2p_node/dht/dhtnode/streams.go: Qmc2JcyiU4wHsgDj6aUunMAp4c5yMzo2ixeqRZHSW5PVwo\n  libp2p_node/dht/dhtnode/utils.go: QmUabTTyRXixEEfksTzSNiHsqF9GcQ9qXpfwVY3VNsXBYK\n  libp2p_node/dht/dhtpeer/benchmarks_test.go: QmeXZbWBxwGY33oRRogFPv61qJu28ufmoprGkmZVrQ9kEV\n  libp2p_node/dht/dhtpeer/dhtpeer.go: Qme7jvbR5JLnxvnRxaPxZ76Pq2Pece1C95ZkJxoY9a4YwE\n  libp2p_node/dht/dhtpeer/dhtpeer_test.go: QmegkzZpi9vpFHTDxrSUKFDWQhBviL63AYMRNgcHpe5wcu\n  libp2p_node/dht/dhtpeer/mailbox.go: QmSgWxkVVQQSrMux8WNvvLbWRfZCb7ZChr6PjumyoW5vdT\n  libp2p_node/dht/dhtpeer/notifee.go: Qmes2KPbWecKZu6Bh3mThEsPs74W3LwD6y3Mzrai1fV7zi\n  libp2p_node/dht/dhtpeer/options.go: QmXiQ1iKHWCGZLKu2YTRkkLkJ7opR7LzsWxiwktKYHc3Va\n  libp2p_node/dht/dhtpeer/utils.go: QmPWx5716sBX43gkCqHHXMmQ8hcg5KBbXqCsRGAnqJcSZw\n  libp2p_node/dht/dhttests/dhttests.go: QmSe8XsEhMJAWuokeWtPLXP4m9G5rDEAXrrQWBcma8t71c\n  libp2p_node/dht/monitoring/file.go: QmZwH59RcraRfgYjugVafVojakv1oEcgBUKuMdFAoeZBhS\n  libp2p_node/dht/monitoring/prometheus.go: QmQvXjEozVPMvRjda5WGRAU5b7cfUcRZUACQkTESG7Aewu\n  libp2p_node/dht/monitoring/service.go: QmT47y2LHZECYcoE2uJ9QCGh3Kq8ePhYedo8dQE7X7v6YV\n  libp2p_node/go.mod: QmWJwSZP3BzuyZjSUUADTuKD7Y3LhJE8NSd8CVke7noFeD\n  libp2p_node/go.sum: QmSPKTBqNZJaTSacn5cPN2sC3MqwzeAN7L2RnCwRhpGR1Q\n  libp2p_node/libp2p_node.go: Qmcp82gLaEpyJU7Q8NnsB6Wp7wF5FMV5ZRv9Y3XdNgPJ2L\n  libp2p_node/link: QmXoSqhnHAFDZiZYT3F1txkjrsjtxDAkPVg9oG9Kvpv2dx\n  libp2p_node/mocks/mock_host.go: QmSJ7g6S2PGhC5j8xBQyrjs56hXJGEewkgFgiivyZDthbW\n  libp2p_node/mocks/mock_net.go: QmVKnkDdH8XCJ9jriEkZui4NoB36GBYF2DtfX8uCqAthMw\n  libp2p_node/mocks/mock_network.go: QmbVVvd3wrY6PnVs1rn9T9m6FD5kbmSVJLwhSxUgSLAiM5\n  libp2p_node/mocks/mock_peerstore.go: QmaPCBrwsTeWCHZoAKDzaxN6uhY3bez1karzeGeovWYwkB\n  libp2p_node/protocols/acn/v1_0_0/acn.pb.go: QmWDoniHr3wa5freLHDESv7SgC9ggYenrLyibw4jFkTc4r\n  libp2p_node/protocols/acn/v1_0_0/acn.proto: QmcguMcKttJfsuPYrUVWFJ1Trr1VxrSSfan94Z3yNAxNEW\n  libp2p_node/protocols/acn/v1_0_0/acn.yaml: QmeqaYRWL5bVRE8FKgbiAspgFkoi5HKtkSncT7fCf1JAex\n  libp2p_node/utils/utils.go: QmRYpCrW8fia1qtmraGcGRhFz5KgAJ8zwGBFP2DJkpFnm8\n  libp2p_node/utils/utils_test.go: QmaUTrtqhPYcCLTHnJic4EN7R1pZY8ra7QbeRrPuedgAuc\nfingerprint_ignore_patterns: []\nbuild_entrypoint: check_dependencies.py\nconnections: []\nprotocols:\n- fetchai/acn:1.1.7\nclass_name: P2PLibp2pConnection\nconfig:\n  delegate_uri: 127.0.0.1:11000\n  entry_peers: []\n  ledger_id: fetchai\n  local_uri: 127.0.0.1:9000\n  log_file: libp2p_node.log\n  max_node_restarts: 5\n  monitoring_uri: null\n  node_connection_timeout: 10\n  public_uri: 127.0.0.1:9000\n  storage_path: null\ncert_requests:\n- identifier: acn\n  ledger_id: fetchai\n  message_format: '{public_key}'\n  not_after: '2023-01-01'\n  not_before: '2022-01-01'\n  public_key: fetchai\n  save_path: .certs/conn_cert.txt\nexcluded_protocols: []\nrestricted_to_protocols: []\ndependencies: {}\nis_abstract: false\n"
  },
  {
    "path": "packages/fetchai/connections/p2p_libp2p/consts.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains some constants for the p2p libp2p connection.\"\"\"\nimport os\nimport platform\n\n\nLIBP2P_NODE_MODULE_NAME = \"libp2p_node\"\n\nLIBP2P_NODE_MODULE = str(\n    os.path.join(os.path.abspath(os.path.dirname(__file__)), LIBP2P_NODE_MODULE_NAME)\n)\n\nif platform.system() == \"Windows\":  # pragma: nocover\n    LIBP2P_NODE_MODULE_NAME += \".exe\"\n\nLIBP2P_NODE_DEPS_DOWNLOAD_TIMEOUT = 660  # time to download ~66Mb\n"
  },
  {
    "path": "packages/fetchai/connections/p2p_libp2p/libp2p_node/.dockerignore",
    "content": "libp2p_node"
  },
  {
    "path": "packages/fetchai/connections/p2p_libp2p/libp2p_node/Dockerfile",
    "content": "FROM golang:1.17.5-buster as builder\n\nUSER root\n\nWORKDIR /build\n\nCOPY ./ ./\n\nRUN go build\n\nFROM scratch AS export-stage\nCOPY --from=builder /build/libp2p_node libp2p_node"
  },
  {
    "path": "packages/fetchai/connections/p2p_libp2p/libp2p_node/Makefile",
    "content": "test:\n\tgo test -gcflags=-l -p 1 -timeout 0 -count 1 -covermode=atomic -coverprofile=coverage.txt -v ./...\n\tgo tool cover -func=coverage.txt\nlint:\n\tgolines . -w\n\tgolangci-lint run\n\t\nbuild:\n\tgo build\ninstall:\n\tgo get -v -t -d ./...\nrace_test:\n\tgo test -gcflags=-l -p 1 -timeout 0 -count 1 -race -v ./...\nbuild_in_docker:\n\tDOCKER_BUILDKIT=1 docker build  --output . ."
  },
  {
    "path": "packages/fetchai/connections/p2p_libp2p/libp2p_node/README.md",
    "content": "# Libp2p Node\n\nThe `libp2p_node` is an integral part of the ACN.\n\n## ACN - Agent Communication Network\n\nThe agent communication network (ACN) provides a system for agents to find each other and communicate, solely based on their wallet addresses. It addresses the message delivery problem.\n\nFor more details check out the [docs](https://github.com/fetchai/agents-aea/blob/main/docs/acn.md).\n\n## Development\n\nTo run all tests run:\n\n``` bash\ngo test -p 1 -timeout 0 -count 1 -v ./...\n```\n\nTo lint:\n\n``` bash\ngolines . -w\ngolangci-lint run\nstaticcheck ./...\n```\n\nFor mocks generation:\ncheck <https://github.com/golang/mock>\n\n## Messaging patterns\n\nInteraction protocol\n___\nACN\n___\nTCP/UDP/...\n___\n\n### Messaging patterns inwards ACN\n\nConnection (`p2p_libp2p_client`) > Delegate Client > Relay Peer > Peer (Discouraged!)\n\nConnection (`p2p_libp2p_client`)  > Delegate Client > Peer\n\nConnection (`p2p_libp2p`) > Relay Peer > Peer\n\nConnection (`p2p_libp2p`) > Peer\n\n### Messaging patterns outwards ACN\n\nPeer > Relay Peer > Delegate Client > Connection (`p2p_libp2p_client`) (Discouraged!)\n\nPeer > Relay Peer > Connection (`p2p_libp2p`)\n\nPeer > Delegate Client > Connection (`p2p_libp2p_client`)\n\nPeer > Connection (`p2p_libp2p`)\n\nIn total 4*4 = 16 patterns (practically: 3*3 = 9 patterns)\n\n## Guarantees\n\nACN should guarantee total ordering of messages for all agent pairs, independent of the type of connection and ACN messaging pattern used.\n\n## Advanced feature (post `v1`)\n\nFurthermore, there is the agent mobility. An agent can move between entry-points (Relay Peer/Peer/Delegate Client). The ACN must ensure that all messaging patterns maintain total ordering of messages for agent pairs during the move.\n\n## ACN protocols\n\nThe ACN has the following protocols:\n\n- register\n- lookup\n- unregister (dealt with by DHT defaults)\n- DHT default protocols in libp2p\n- message delivery protocol\n"
  },
  {
    "path": "packages/fetchai/connections/p2p_libp2p/libp2p_node/acn/utils.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2021 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\npackage acn\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"strings\"\n\t\"time\"\n\n\tacn_protocol \"libp2p_node/protocols/acn/v1_0_0\"\n\n\t\"github.com/rs/zerolog\"\n\tproto \"google.golang.org/protobuf/proto\"\n)\n\ntype StatusBody = acn_protocol.AcnMessage_StatusBody\ntype AgentRecord = acn_protocol.AcnMessage_AgentRecord\ntype AcnMessage = acn_protocol.AcnMessage\ntype LookupRequest = acn_protocol.AcnMessage_LookupRequest\ntype LookupResponse = acn_protocol.AcnMessage_LookupResponse\ntype Status = acn_protocol.AcnMessage_Status\ntype LookupRequestPerformative = acn_protocol.AcnMessage_Lookup_Request_Performative\ntype LookupResponsePerformative = acn_protocol.AcnMessage_Lookup_Response_Performative\ntype StatusPerformative = acn_protocol.AcnMessage_Status_Performative\ntype RegisterPerformative = acn_protocol.AcnMessage_Register_Performative\ntype Register = acn_protocol.AcnMessage_Register\ntype AeaEnvelope = acn_protocol.AcnMessage_AeaEnvelope\ntype AeaEnvelopePerformative = acn_protocol.AcnMessage_Aea_Envelope_Performative\n\nconst ERROR_DECODE = acn_protocol.AcnMessage_StatusBody_ERROR_DECODE\nconst SUCCESS = acn_protocol.AcnMessage_StatusBody_SUCCESS\nconst ERROR_UNEXPECTED_PAYLOAD = acn_protocol.AcnMessage_StatusBody_ERROR_UNEXPECTED_PAYLOAD\nconst ERROR_AGENT_NOT_READY = acn_protocol.AcnMessage_StatusBody_ERROR_AGENT_NOT_READY\nconst ERROR_UNKNOWN_AGENT_ADDRESS = acn_protocol.AcnMessage_StatusBody_ERROR_UNKNOWN_AGENT_ADDRESS\nconst ERROR_GENERIC = acn_protocol.AcnMessage_StatusBody_ERROR_GENERIC\nconst ERROR_WRONG_AGENT_ADDRESS = acn_protocol.AcnMessage_StatusBody_ERROR_WRONG_AGENT_ADDRESS\nconst ERROR_UNSUPPORTED_LEDGER = acn_protocol.AcnMessage_StatusBody_ERROR_UNSUPPORTED_LEDGER\nconst ERROR_WRONG_PUBLIC_KEY = acn_protocol.AcnMessage_StatusBody_ERROR_WRONG_PUBLIC_KEY\nconst ERROR_INVALID_PROOF = acn_protocol.AcnMessage_StatusBody_ERROR_INVALID_PROOF\n\ntype Status_ErrCode = acn_protocol.AcnMessage_StatusBody_StatusCodeEnum\n\nvar logger zerolog.Logger = zerolog.New(zerolog.ConsoleWriter{\n\tOut:        os.Stdout,\n\tNoColor:    false,\n\tTimeFormat: \"15:04:05.000\",\n}).\n\tWith().Timestamp().\n\tStr(\"package\", \"AeaApiACN\").\n\tLogger()\n\nconst CurrentVersion = \"0.1.0\"\n\nfunc ignore(err error) {\n\tif err != nil {\n\t\tlogger.Error().Str(\"err\", err.Error()).Msgf(\"IGNORED: %s\", err.Error())\n\t}\n}\n\ntype ACNError struct {\n\tErrorCode Status_ErrCode\n\tErr       error\n}\n\nfunc (err *ACNError) Error() string {\n\treturn err.Err.Error()\n}\n\nfunc DecodeAcnMessage(buf []byte) (string, *AeaEnvelopePerformative, *StatusBody, *ACNError) {\n\tresponse := &AcnMessage{}\n\terr := proto.Unmarshal(buf, response)\n\tmsg_type := \"\"\n\n\tif err != nil {\n\t\tlogger.Error().Str(\"err\", err.Error()).Msgf(\"while decoding acn message\")\n\t\treturn msg_type, nil, nil, &ACNError{ErrorCode: ERROR_DECODE, Err: err}\n\t}\n\t// response is either a LookupResponse or Status\n\tvar aeaEnvelope *AeaEnvelopePerformative = nil\n\tvar status *StatusBody = nil\n\n\tswitch pl := response.Performative.(type) {\n\tcase *AeaEnvelope:\n\t\taeaEnvelope = pl.AeaEnvelope\n\t\tmsg_type = \"aea_envelope\"\n\tcase *Status:\n\t\tstatus = pl.Status.Body\n\t\tmsg_type = \"status\"\n\tdefault:\n\t\terr = fmt.Errorf(\"unexpected ACN Message: %s\", response)\n\t\tlogger.Error().Msg(err.Error())\n\t\treturn msg_type, nil, nil, &ACNError{ErrorCode: ERROR_UNEXPECTED_PAYLOAD, Err: err}\n\t}\n\treturn msg_type, aeaEnvelope, status, nil\n}\n\nfunc WaitForStatus(ch chan *StatusBody, timeout time.Duration) (*StatusBody, error) {\n\tselect {\n\tcase m := <-ch:\n\t\treturn m, nil\n\tcase <-time.After(timeout):\n\t\terr := errors.New(\"ACN send acknowledge timeout\")\n\t\tlogger.Error().Msg(err.Error())\n\t\treturn nil, err\n\t}\n}\n\nfunc SendAcnSuccess(pipe Pipe) error {\n\tstatus := &StatusBody{Code: SUCCESS}\n\tperformative := &StatusPerformative{Body: status}\n\tmsg := &AcnMessage{\n\t\tPerformative: &Status{Status: performative},\n\t}\n\tbuf, err := proto.Marshal(msg)\n\tif err != nil {\n\t\tlogger.Error().Str(\"err\", err.Error()).Msgf(\"error on encoding acn status message\")\n\t\treturn err\n\t}\n\terr = pipe.Write(buf)\n\tif err != nil {\n\t\tlogger.Error().Str(\"err\", err.Error()).Msgf(\"error on sending acn status message\")\n\n\t}\n\treturn err\n}\n\nfunc SendAcnError(pipe Pipe, error_msg string, err_codes ...Status_ErrCode) error {\n\tvar err_code Status_ErrCode\n\n\tif len(err_codes) == 0 {\n\t\terr_code = ERROR_GENERIC\n\t} else {\n\t\terr_code = err_codes[0]\n\t}\n\n\tstatus := &StatusBody{Code: err_code, Msgs: []string{error_msg}}\n\tmsg := &AcnMessage{\n\t\tPerformative: &Status{Status: &StatusPerformative{Body: status}},\n\t}\n\tbuf, err := proto.Marshal(msg)\n\tif err != nil {\n\t\tlogger.Error().Str(\"err\", err.Error()).Msgf(\"error on encoding acn status message\")\n\t\treturn err\n\t}\n\terr = pipe.Write(buf)\n\tif err != nil {\n\t\tlogger.Error().Str(\"err\", err.Error()).Msgf(\"error on sending acn status message\")\n\t}\n\treturn err\n}\n\nfunc EncodeAcnEnvelope(envelope_bytes []byte, record *AgentRecord) ([]byte, error) {\n\tvar performative *AeaEnvelopePerformative\n\tif record != nil {\n\t\tperformative = &AeaEnvelopePerformative{Envelope: envelope_bytes, Record: record}\n\t} else {\n\t\tperformative = &AeaEnvelopePerformative{Envelope: envelope_bytes}\n\t}\n\n\tmsg := &AcnMessage{\n\t\tPerformative: &AeaEnvelope{AeaEnvelope: performative},\n\t}\n\n\tbuf, err := proto.Marshal(msg)\n\tif err != nil {\n\t\tlogger.Error().\n\t\t\tStr(\"err\", err.Error()).\n\t\t\tMsgf(\"while serializing envelope bytes: %s\", envelope_bytes)\n\t}\n\treturn buf, err\n}\n\ntype Pipe interface {\n\tConnect() error\n\tRead() ([]byte, error)\n\tWrite(data []byte) error\n\tClose() error\n}\n\ntype StatusQueue interface {\n\tAddAcnStatusMessage(status *StatusBody, counterpartyID string)\n}\n\nfunc ReadAgentRegistrationMessage(pipe Pipe) (*RegisterPerformative, error) {\n\tvar register *RegisterPerformative\n\tbuf, err := pipe.Read()\n\tif err != nil {\n\t\tlogger.Error().Str(\"err\", err.Error()).Msgf(\"while receiving agent's registration request\")\n\t\treturn nil, err\n\t}\n\n\tmsg := &AcnMessage{}\n\terr = proto.Unmarshal(buf, msg)\n\tif err != nil {\n\t\tlogger.Error().Str(\"err\", err.Error()).Msgf(\"couldn't deserialize acn registration message\")\n\t\t// TOFIX(LR) setting Msgs to err.Error is potentially a security vulnerability\n\t\tacn_send_error := SendAcnError(pipe, err.Error(), ERROR_DECODE)\n\t\tignore(acn_send_error)\n\t\treturn nil, err\n\t}\n\n\tswitch pl := msg.Performative.(type) {\n\tcase *Register:\n\t\tregister = pl.Register\n\tdefault:\n\t\terr = errors.New(\"Unexpected payload\")\n\t\tacn_send_error := SendAcnError(pipe, err.Error(), ERROR_UNEXPECTED_PAYLOAD)\n\t\tignore(acn_send_error)\n\t\treturn nil, err\n\t}\n\treturn register, nil\n}\n\nfunc SendEnvelopeMessageAndWaitForStatus(\n\tpipe Pipe,\n\tenvelope_bytes []byte,\n\tacn_status_chan chan *StatusBody,\n\tacnStatusTimeout time.Duration,\n) error {\n\terr := SendEnvelopeMessage(pipe, envelope_bytes, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tstatus, err := WaitForStatus(acn_status_chan, acnStatusTimeout)\n\tif err != nil {\n\t\tlogger.Error().\n\t\t\tStr(\"err\", err.Error()).\n\t\t\tMsgf(\"on envelope sent status wait\")\n\t\treturn err\n\t}\n\tif status.Code != SUCCESS {\n\t\tlogger.Error().\n\t\t\tStr(\"op\", \"send_envelope\").\n\t\t\tMsgf(\"acn confirmation status is not Status Success: %d.\", status.Code)\n\t\treturn fmt.Errorf(\n\t\t\t\"send envelope: acn confirmation status is not Status Success: %d\",\n\t\t\tstatus.Code,\n\t\t)\n\t}\n\treturn err\n\n}\n\nfunc ReadLookupRequest(pipe Pipe) (string, error) {\n\tbuf, err := pipe.Read()\n\n\tif err != nil {\n\t\tlogger.Error().Str(\"err\", err.Error()).Msgf(\"while reading message from stream\")\n\t\treturn \"\", err\n\t}\n\n\tmsg := &AcnMessage{}\n\terr = proto.Unmarshal(buf, msg)\n\tif err != nil {\n\t\tlogger.Error().\n\t\t\tStr(\"err\", err.Error()).\n\t\t\tMsgf(\"couldn't deserialize acn lookup request message\")\n\t\t// TOFIX(LR) setting Msgs to err.Error is potentially a security vulnerability\n\t\tacn_send_error := SendAcnError(pipe, err.Error(), ERROR_DECODE)\n\t\tignore(acn_send_error)\n\t\treturn \"\", err\n\t}\n\n\t// Get LookupRequest message\n\tvar lookupRequest *LookupRequestPerformative\n\tswitch pl := msg.Performative.(type) {\n\tcase *LookupRequest:\n\t\tlookupRequest = pl.LookupRequest\n\tdefault:\n\t\terr = errors.New(\"Unexpected payload\")\n\t\tacn_send_error := SendAcnError(pipe, err.Error(), ERROR_UNEXPECTED_PAYLOAD)\n\t\tignore(acn_send_error)\n\t\treturn \"\", err\n\t}\n\n\treqAddress := lookupRequest.AgentAddress\n\treturn reqAddress, nil\n}\n\nfunc SendLookupRequest(pipe Pipe, address string) error {\n\tlookupRequest := &LookupRequestPerformative{AgentAddress: address}\n\tmsg := &AcnMessage{\n\t\tPerformative: &LookupRequest{LookupRequest: lookupRequest},\n\t}\n\tbuf, err := proto.Marshal(msg)\n\tif err != nil {\n\t\treturn err\n\t}\n\terr = pipe.Write([]byte(buf))\n\treturn err\n}\n\nfunc ReadLookupResponse(pipe Pipe) (*AgentRecord, error) {\n\tbuf, err := pipe.Read()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tresponse := &AcnMessage{}\n\terr = proto.Unmarshal(buf, response)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tvar lookupResponse *LookupResponsePerformative = nil\n\tvar status *StatusPerformative = nil\n\tswitch pl := response.Performative.(type) {\n\tcase *LookupResponse:\n\t\tlookupResponse = pl.LookupResponse\n\tcase *Status:\n\t\tstatus = pl.Status\n\tdefault:\n\t\terr = errors.New(\"Unexpected Acn Message\")\n\t\tlogger.Error().Str(\"err\", err.Error()).Msgf(\"couldn't deserialize acn lookup response message\")\n\t\treturn nil, err\n\t}\n\n\tif status != nil {\n\t\terr = errors.New(\n\t\t\t\"Failed agent lookup response \" + status.Body.Code.String() + \" : \" + strings.Join(\n\t\t\t\tstatus.Body.Msgs,\n\t\t\t\t\":\",\n\t\t\t),\n\t\t)\n\t\treturn nil, err\n\t}\n\treturn lookupResponse.Record, nil\n}\n\nfunc SendLookupResponse(pipe Pipe, record *AgentRecord) error {\n\tlookupResponse := &LookupResponsePerformative{Record: record}\n\tresponse := &AcnMessage{\n\t\tPerformative: &LookupResponse{LookupResponse: lookupResponse},\n\t}\n\tbuf, err := proto.Marshal(response)\n\tif err != nil {\n\t\treturn err\n\t}\n\terr = pipe.Write(buf)\n\treturn err\n}\n\nfunc SendEnvelopeMessage(pipe Pipe, envelope_bytes []byte, record *AgentRecord) error {\n\tacnMsgBytes, err := EncodeAcnEnvelope(envelope_bytes, record)\n\tif err != nil {\n\t\treturn err\n\t}\n\terr = pipe.Write(acnMsgBytes)\n\tif err != nil {\n\t\tlogger.Error().\n\t\t\tStr(\"err\", err.Error()).\n\t\t\tMsgf(\"on pipe write\")\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc SendAgentRegisterMessage(pipe Pipe, agentRecord *AgentRecord) error {\n\tregistration := &RegisterPerformative{Record: agentRecord}\n\tmsg := &AcnMessage{\n\t\tPerformative: &Register{Register: registration},\n\t}\n\tbuf, err := proto.Marshal(msg)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\terr = pipe.Write(buf)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tstatus, err := ReadAcnStatus(pipe)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif status.Code != SUCCESS {\n\t\treturn errors.New(\"Registration failed: \" + strings.Join(status.Msgs, \":\"))\n\t}\n\treturn nil\n}\n\nfunc ReadAcnStatus(pipe Pipe) (*StatusBody, error) {\n\tbuf, err := pipe.Read()\n\tif err != nil {\n\t\tlogger.Error().\n\t\t\tStr(\"err\", err.Error()).\n\t\t\tMsgf(\"on pipe read\")\n\t\treturn nil, err\n\t}\n\n\tresponse := &AcnMessage{}\n\terr = proto.Unmarshal(buf, response)\n\tif err != nil {\n\t\tlogger.Error().\n\t\t\tStr(\"err\", err.Error()).\n\t\t\tMsgf(\"on acn decode\")\n\t\treturn nil, err\n\t}\n\n\t// response is expected to be a Status\n\tvar status *StatusPerformative\n\tswitch pl := response.Performative.(type) {\n\tcase *Status:\n\t\tstatus = pl.Status\n\tdefault:\n\t\terr = errors.New(\"Unexpected Acn Message\")\n\t\treturn nil, err\n\t}\n\n\treturn status.Body, nil\n}\n\nfunc ReadEnvelopeMessage(pipe Pipe) (*AeaEnvelopePerformative, error) {\n\tbuf, err := pipe.Read()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tmessageType, envelope, _, acnErr := DecodeAcnMessage(buf)\n\n\tif acnErr != nil {\n\t\terr = SendAcnError(\n\t\t\tpipe,\n\t\t\tacnErr.Error(),\n\t\t\tacnErr.ErrorCode,\n\t\t)\n\t\tignore(err)\n\t\treturn nil, acnErr.Err\n\t}\n\tif messageType != \"aea_envelope\" {\n\t\treturn nil, errors.New(\"unexpected payload for acn message\")\n\t}\n\treturn envelope, nil\n}\n\nfunc PerformAddressLookup(pipe Pipe, address string) (*AgentRecord, error) {\n\terr := SendLookupRequest(pipe, address)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn ReadLookupResponse(pipe)\n}\n"
  },
  {
    "path": "packages/fetchai/connections/p2p_libp2p/libp2p_node/aea/api.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2019 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\n\npackage aea\n\nimport (\n\t\"errors\"\n\t\"log\"\n\t\"net\"\n\t\"os\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/joho/godotenv\"\n\t\"github.com/rs/zerolog\"\n\tproto \"google.golang.org/protobuf/proto\"\n\n\tacn \"libp2p_node/acn\"\n\tcommon \"libp2p_node/common\"\n)\n\nconst AcnStatusTimeout = 15.0 * time.Second\nconst SendQueueSize = 100\nconst OutQueueSize = 100\n\n// code redandency to avoid import cycle\nvar logger zerolog.Logger = zerolog.New(zerolog.ConsoleWriter{\n\tOut:        os.Stdout,\n\tNoColor:    false,\n\tTimeFormat: \"15:04:05.000\",\n}).\n\tWith().Timestamp().\n\tStr(\"package\", \"AeaApi\").\n\tLogger()\n\n/*\n\n  AeaApi type\n\n*/\n\ntype AeaApi struct {\n\tmsgin_path      string\n\tmsgout_path     string\n\tagent_addr      string\n\tagent_record    *acn.AgentRecord\n\tid              string\n\tentry_peers     []string\n\thost            string\n\tport            uint16\n\thost_public     string\n\tport_public     uint16\n\thost_delegate   string\n\tport_delegate   uint16\n\thost_monitoring string\n\tport_monitoring uint16\n\n\tmailbox_uri string\n\n\tregistrationDelay  float64\n\trecordsStoragePath string\n\n\tpipe       common.Pipe\n\tout_queue  chan *Envelope\n\tsend_queue chan *Envelope\n\n\tclosing         bool\n\tconnected       bool\n\tsandbox         bool\n\tstandalone      bool\n\tacn_status_chan chan *acn.StatusBody\n}\n\nfunc (aea AeaApi) MailboxUri() string {\n\treturn aea.mailbox_uri\n}\n\nfunc (aea AeaApi) AeaAddress() string {\n\treturn aea.agent_addr\n}\n\nfunc (aea AeaApi) PrivateKey() string {\n\treturn aea.id\n}\n\nfunc (aea AeaApi) Address() (string, uint16) {\n\treturn aea.host, aea.port\n}\n\nfunc (aea AeaApi) PublicAddress() (string, uint16) {\n\treturn aea.host_public, aea.port_public\n}\n\nfunc (aea AeaApi) DelegateAddress() (string, uint16) {\n\treturn aea.host_delegate, aea.port_delegate\n}\n\nfunc (aea AeaApi) MonitoringAddress() (string, uint16) {\n\treturn aea.host_monitoring, aea.port_monitoring\n}\n\nfunc (aea AeaApi) EntryPeers() []string {\n\treturn aea.entry_peers\n}\n\nfunc (aea AeaApi) AgentRecord() *acn.AgentRecord {\n\treturn aea.agent_record\n}\n\nfunc (aea AeaApi) RegistrationDelayInSeconds() float64 {\n\treturn aea.registrationDelay\n}\n\nfunc (aea AeaApi) RecordStoragePath() string {\n\treturn aea.recordsStoragePath\n}\n\nfunc (aea AeaApi) Put(envelope *Envelope) error {\n\tif aea.standalone {\n\t\terrorMsg := \"node running in standalone mode\"\n\t\tlogger.Warn().Msgf(errorMsg)\n\t\treturn errors.New(errorMsg)\n\t}\n\taea.send_queue <- envelope\n\treturn nil\n}\n\nfunc (aea *AeaApi) Get() *Envelope {\n\tif aea.standalone {\n\t\terrorMsg := \"node running in standalone mode\"\n\t\tlogger.Warn().Msgf(errorMsg)\n\t\treturn nil\n\t}\n\treturn <-aea.out_queue\n}\n\nfunc (aea *AeaApi) Queue() <-chan *Envelope {\n\treturn aea.out_queue\n}\n\nfunc (aea *AeaApi) Connected() bool {\n\treturn aea.connected || aea.standalone\n}\n\nfunc (aea *AeaApi) Stop() {\n\taea.send_queue <- nil\n\taea.closing = true\n\taea.stop()\n\tclose(aea.out_queue)\n\tclose(aea.send_queue)\n}\n\nfunc (aea *AeaApi) Init() error {\n\tzerolog.TimeFieldFormat = time.RFC3339Nano\n\n\tif aea.sandbox {\n\t\treturn nil\n\t}\n\n\tif aea.connected {\n\t\treturn nil\n\t}\n\taea.connected = false\n\n\tenv_file := os.Args[1]\n\tlogger.Debug().Msgf(\"env_file: %s\", env_file)\n\n\t// get config\n\terr := godotenv.Overload(env_file)\n\tif err != nil {\n\t\tlog.Fatal(\"Error loading env file\")\n\t}\n\taea.msgin_path = os.Getenv(\"AEA_TO_NODE\")\n\taea.msgout_path = os.Getenv(\"NODE_TO_AEA\")\n\taea.agent_addr = os.Getenv(\"AEA_AGENT_ADDR\")\n\taea.id = os.Getenv(\"AEA_P2P_ID\")\n\tentry_peers := os.Getenv(\"AEA_P2P_ENTRY_URIS\")\n\turi := os.Getenv(\"AEA_P2P_URI\")\n\turi_public := os.Getenv(\"AEA_P2P_URI_PUBLIC\")\n\turi_delegate := os.Getenv(\"AEA_P2P_DELEGATE_URI\")\n\turi_monitoring := os.Getenv(\"AEA_P2P_URI_MONITORING\")\n\n\tpor_address := os.Getenv(\"AEA_P2P_POR_ADDRESS\")\n\tif por_address != \"\" {\n\t\trecord := &acn.AgentRecord{Address: por_address}\n\t\trecord.PublicKey = os.Getenv(\"AEA_P2P_POR_PUBKEY\")\n\t\trecord.PeerPublicKey = os.Getenv(\"AEA_P2P_POR_PEER_PUBKEY\")\n\t\trecord.Signature = os.Getenv(\"AEA_P2P_POR_SIGNATURE\")\n\t\trecord.ServiceId = os.Getenv(\"AEA_P2P_POR_SERVICE_ID\")\n\t\trecord.LedgerId = os.Getenv(\"AEA_P2P_POR_LEDGER_ID\")\n\t\taea.agent_record = record\n\t}\n\n\taea.mailbox_uri = os.Getenv(\"AEA_P2P_MAILBOX_URI\")\n\tregistrationDelay := os.Getenv(\"AEA_P2P_CFG_REGISTRATION_DELAY\")\n\taea.recordsStoragePath = os.Getenv(\"AEA_P2P_CFG_STORAGE_PATH\")\n\n\tlogger.Debug().Msgf(\"msgin_path: %s\", aea.msgin_path)\n\tlogger.Debug().Msgf(\"msgout_path: %s\", aea.msgout_path)\n\tlogger.Debug().Msgf(\"id: %s\", aea.id)\n\tlogger.Debug().Msgf(\"addr: %s\", aea.agent_addr)\n\tlogger.Debug().Msgf(\"entry_peers: %s\", entry_peers)\n\tlogger.Debug().Msgf(\"uri: %s\", uri)\n\tlogger.Debug().Msgf(\"uri public: %s\", uri_public)\n\tlogger.Debug().Msgf(\"uri delegate service: %s\", uri_delegate)\n\n\tif aea.id == \"\" || uri == \"\" {\n\t\terr := errors.New(\"couldn't get AEA configuration: key and uri are required\")\n\t\tlogger.Error().Str(\"err\", err.Error()).Msg(\"\")\n\t\treturn err\n\t}\n\tif aea.msgin_path == \"\" && aea.msgout_path == \"\" && aea.agent_addr == \"\" {\n\t\taea.standalone = true\n\t} else if aea.msgin_path == \"\" || aea.msgout_path == \"\" || aea.agent_addr == \"\" {\n\t\terr := errors.New(\"couldn't get AEA configuration: pipes paths are required when agent address is provided\")\n\t\tlogger.Error().Str(\"err\", err.Error()).Msg(\"\")\n\t\treturn err\n\t}\n\n\t// parse uri\n\tparts := strings.SplitN(uri, \":\", -1)\n\tif len(parts) < 2 {\n\t\terr := errors.New(\"malformed Uri \" + uri)\n\t\tlogger.Error().Str(\"err\", err.Error()).Msg(\"\")\n\t\treturn err\n\t}\n\taea.host = parts[0]\n\tport, _ := strconv.ParseUint(parts[1], 10, 16)\n\taea.port = uint16(port)\n\t// hack: test if port is taken\n\taddr, err := net.ResolveTCPAddr(\"tcp\", uri)\n\tif err != nil {\n\t\treturn err\n\t}\n\tlistener, err := net.ListenTCP(\"tcp\", addr)\n\tif err != nil {\n\t\tlogger.Error().Str(\"err\", err.Error()).Msgf(\"Uri already taken %s\", uri)\n\t\treturn err\n\t}\n\tlistener.Close()\n\n\t// parse public uri\n\tif uri_public != \"\" {\n\t\tparts = strings.SplitN(uri_public, \":\", -1)\n\t\tif len(parts) < 2 {\n\t\t\terr := errors.New(\"malformed Uri \" + uri_public)\n\t\t\tlogger.Error().Str(\"err\", err.Error()).Msg(\"\")\n\t\t\treturn err\n\t\t}\n\t\taea.host_public = parts[0]\n\t\tport, _ = strconv.ParseUint(parts[1], 10, 16)\n\t\taea.port_public = uint16(port)\n\t} else {\n\t\taea.host_public = \"\"\n\t\taea.port_public = 0\n\t}\n\n\t// parse delegate uri\n\tif uri_delegate != \"\" {\n\t\tparts = strings.SplitN(uri_delegate, \":\", -1)\n\t\tif len(parts) < 2 {\n\t\t\terr := errors.New(\"malformed Uri \" + uri_delegate)\n\t\t\tlogger.Error().Str(\"err\", err.Error()).Msg(\"\")\n\t\t\treturn err\n\t\t}\n\t\taea.host_delegate = parts[0]\n\t\tport, _ = strconv.ParseUint(parts[1], 10, 16)\n\t\taea.port_delegate = uint16(port)\n\t} else {\n\t\taea.host_delegate = \"\"\n\t\taea.port_delegate = 0\n\t}\n\n\t// parse monitoring uri\n\tif uri_monitoring != \"\" {\n\t\tparts = strings.SplitN(uri_monitoring, \":\", -1)\n\t\tif len(parts) < 2 {\n\t\t\terr := errors.New(\"malformed Uri \" + uri_monitoring)\n\t\t\tlogger.Error().Str(\"err\", err.Error()).Msg(\"\")\n\t\t\treturn err\n\t\t}\n\t\taea.host_monitoring = parts[0]\n\t\tport, _ = strconv.ParseUint(parts[1], 10, 16)\n\t\taea.port_monitoring = uint16(port)\n\t} else {\n\t\taea.host_monitoring = \"\"\n\t\taea.port_monitoring = 0\n\t}\n\n\t// parse entry peers multiaddress\n\tif len(entry_peers) > 0 {\n\t\taea.entry_peers = strings.SplitN(entry_peers, \",\", -1)\n\t}\n\n\t// parse registration delay\n\tif registrationDelay == \"\" {\n\t\taea.registrationDelay = 0.0\n\t} else {\n\t\tdelay, err := strconv.ParseFloat(registrationDelay, 32)\n\t\tif err != nil {\n\t\t\tlogger.Error().Str(\"err\", err.Error()).Msgf(\"malformed RegistrationDelay value\")\n\t\t\treturn err\n\t\t}\n\t\taea.registrationDelay = delay\n\t}\n\n\t// setup pipe\n\tif !aea.standalone {\n\t\taea.pipe = NewPipe(aea.msgin_path, aea.msgout_path)\n\t}\n\n\taea.acn_status_chan = make(chan *acn.StatusBody, 1000)\n\treturn nil\n}\n\nfunc (aea *AeaApi) Connect() error {\n\tif aea.standalone {\n\t\tlogger.Info().Msg(\"Successfully running in standalone mode\")\n\t\treturn nil\n\t}\n\n\t// open pipes\n\terr := aea.pipe.Connect()\n\n\tif err != nil {\n\t\tlogger.Error().Str(\"err\", err.Error()).\n\t\t\tMsg(\"while connecting to pipe\")\n\t\treturn err\n\t}\n\n\taea.closing = false\n\t//TOFIX(LR) trade-offs between bufferd vs unbuffered channel\n\taea.out_queue = make(chan *Envelope, OutQueueSize)\n\taea.send_queue = make(chan *Envelope, SendQueueSize)\n\tgo aea.listenForEnvelopes()\n\tgo aea.envelopeSendLoop()\n\tlogger.Info().Msg(\"connected to agent\")\n\n\taea.connected = true\n\n\treturn nil\n}\n\nfunc (aea *AeaApi) listenForEnvelopes() {\n\t//TOFIX(LR) add an exit strategy\n\tfor {\n\t\tenvel, err := HandleAcnMessageFromPipe(aea.pipe, aea, aea.AeaAddress())\n\n\t\tvar e *common.PipeError\n\n\t\tif errors.As(err, &e) {\n\t\t\tlogger.Error().\n\t\t\t\tStr(\"err\", err.Error()).\n\t\t\t\tMsg(\"pipe error while receiving envelope. disconnect\")\n\t\t\tlogger.Info().Msg(\"disconnecting\")\n\n\t\t\tif !aea.closing {\n\t\t\t\taea.Stop()\n\t\t\t}\n\n\t\t\treturn\n\t\t}\n\t\tif err != nil {\n\t\t\tlogger.Error().Str(\"err\", err.Error()).Msg(\"while receiving envelope. skip\")\n\t\t\tcontinue\n\t\t}\n\t\tif envel == nil {\n\t\t\t// ACN STATUS MSG\n\t\t\tcontinue\n\t\t}\n\t\tif envel.Sender != aea.agent_record.Address {\n\t\t\tlogger.Error().\n\t\t\t\tStr(\"err\", \"Sender (\"+envel.Sender+\") must match registered address\").\n\t\t\t\tMsg(\"while processing envelope\")\n\t\t\t// TODO send error back to agent\n\t\t\tcontinue\n\t\t}\n\t\tlogger.Debug().Msgf(\"received envelope from agent\")\n\t\taea.out_queue <- envel\n\t\tif aea.closing {\n\t\t\treturn\n\t\t}\n\t}\n}\n\nfunc (aea *AeaApi) envelopeSendLoop() {\n\tlogger.Debug().Msg(\"send loop started\")\n\tvar err error\n\tfor {\n\t\tenvelope := <-aea.send_queue\n\t\tif envelope == nil {\n\t\t\tlogger.Info().Msg(\"envelope is nil. exit send loop\")\n\t\t\treturn\n\t\t}\n\t\terr = aea.SendEnvelope(envelope)\n\t\tif err != nil {\n\t\t\tlogger.Error().Str(\"err\", err.Error()).Msg(\"while sending envelope\")\n\t\t} else {\n\t\t\tlogger.Debug().Msg(\"envelope sent\")\n\t\t}\n\n\t\tif aea.closing {\n\t\t\treturn\n\t\t}\n\t}\n}\nfunc (aea *AeaApi) stop() {\n\terr := aea.pipe.Close()\n\tif err != nil {\n\t\tlogger.Error().Str(\"err\", err.Error()).Msgf(\"on pipe close during aeaapi stop\")\n\t}\n}\n\n/*\n\n  Pipes helpers\n\n*/\nconst CurrentVersion = \"0.1.0\"\n\nfunc MakeAcnMessageFromEnvelope(envelope *Envelope) ([]byte, error) {\n\tenvelope_bytes, err := proto.Marshal(envelope)\n\tif err != nil {\n\t\treturn envelope_bytes, err\n\t}\n\treturn acn.EncodeAcnEnvelope(envelope_bytes, nil)\n}\n\nfunc (aea AeaApi) SendEnvelope(envelope *Envelope) error {\n\treturn SendEnvelope(aea.pipe, aea.acn_status_chan, envelope, AcnStatusTimeout)\n}\n\nfunc SendEnvelope(\n\tpipe acn.Pipe,\n\tacn_status_chan chan *acn.StatusBody,\n\tenvelope *Envelope,\n\tacnStatusTimeout time.Duration,\n) error {\n\tenvelope_bytes, err := proto.Marshal(envelope)\n\tif err != nil {\n\t\tlogger.Error().\n\t\t\tStr(\"err\", err.Error()).\n\t\t\tMsgf(\"while serializing envelope: %s\", envelope.String())\n\t\treturn err\n\t}\n\terr = acn.SendEnvelopeMessageAndWaitForStatus(\n\t\tpipe,\n\t\tenvelope_bytes,\n\t\tacn_status_chan,\n\t\tacnStatusTimeout,\n\t)\n\n\tif err != nil {\n\t\tlogger.Error().\n\t\t\tStr(\"err\", err.Error()).\n\t\t\tMsgf(\"on send envelope: %s\", envelope.String())\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc (aea AeaApi) AddAcnStatusMessage(status *acn.StatusBody, counterpartyID string) {\n\taea.acn_status_chan <- status\n\tlogger.Info().Msgf(\"chan len is %d\", len(aea.acn_status_chan))\n}\n"
  },
  {
    "path": "packages/fetchai/connections/p2p_libp2p/libp2p_node/aea/envelope.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.25.0\n// \tprotoc        (unknown)\n// source: envelope.proto\n\npackage aea\n\nimport (\n\tproto \"github.com/golang/protobuf/proto\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// This is a compile-time assertion that a sufficiently up-to-date version\n// of the legacy proto package is being used.\nconst _ = proto.ProtoPackageIsVersion4\n\ntype Envelope struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tTo         string `protobuf:\"bytes,1,opt,name=to,proto3\" json:\"to,omitempty\"`\n\tSender     string `protobuf:\"bytes,2,opt,name=sender,proto3\" json:\"sender,omitempty\"`\n\tProtocolId string `protobuf:\"bytes,3,opt,name=protocol_id,json=protocolId,proto3\" json:\"protocol_id,omitempty\"`\n\tMessage    []byte `protobuf:\"bytes,4,opt,name=message,proto3\" json:\"message,omitempty\"`\n\tUri        string `protobuf:\"bytes,5,opt,name=uri,proto3\" json:\"uri,omitempty\"`\n}\n\nfunc (x *Envelope) Reset() {\n\t*x = Envelope{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_envelope_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Envelope) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Envelope) ProtoMessage() {}\n\nfunc (x *Envelope) ProtoReflect() protoreflect.Message {\n\tmi := &file_envelope_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Envelope.ProtoReflect.Descriptor instead.\nfunc (*Envelope) Descriptor() ([]byte, []int) {\n\treturn file_envelope_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *Envelope) GetTo() string {\n\tif x != nil {\n\t\treturn x.To\n\t}\n\treturn \"\"\n}\n\nfunc (x *Envelope) GetSender() string {\n\tif x != nil {\n\t\treturn x.Sender\n\t}\n\treturn \"\"\n}\n\nfunc (x *Envelope) GetProtocolId() string {\n\tif x != nil {\n\t\treturn x.ProtocolId\n\t}\n\treturn \"\"\n}\n\nfunc (x *Envelope) GetMessage() []byte {\n\tif x != nil {\n\t\treturn x.Message\n\t}\n\treturn nil\n}\n\nfunc (x *Envelope) GetUri() string {\n\tif x != nil {\n\t\treturn x.Uri\n\t}\n\treturn \"\"\n}\n\nvar File_envelope_proto protoreflect.FileDescriptor\n\nvar file_envelope_proto_rawDesc = []byte{\n\t0x0a, 0x0e, 0x65, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,\n\t0x12, 0x03, 0x61, 0x65, 0x61, 0x22, 0x7f, 0x0a, 0x08, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70,\n\t0x65, 0x12, 0x0e, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x74,\n\t0x6f, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28,\n\t0x09, 0x52, 0x06, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x72, 0x6f,\n\t0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a,\n\t0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65,\n\t0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6d, 0x65, 0x73,\n\t0x73, 0x61, 0x67, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x69, 0x18, 0x05, 0x20, 0x01, 0x28,\n\t0x09, 0x52, 0x03, 0x75, 0x72, 0x69, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_envelope_proto_rawDescOnce sync.Once\n\tfile_envelope_proto_rawDescData = file_envelope_proto_rawDesc\n)\n\nfunc file_envelope_proto_rawDescGZIP() []byte {\n\tfile_envelope_proto_rawDescOnce.Do(func() {\n\t\tfile_envelope_proto_rawDescData = protoimpl.X.CompressGZIP(file_envelope_proto_rawDescData)\n\t})\n\treturn file_envelope_proto_rawDescData\n}\n\nvar file_envelope_proto_msgTypes = make([]protoimpl.MessageInfo, 1)\nvar file_envelope_proto_goTypes = []interface{}{\n\t(*Envelope)(nil), // 0: aea.Envelope\n}\nvar file_envelope_proto_depIdxs = []int32{\n\t0, // [0:0] is the sub-list for method output_type\n\t0, // [0:0] is the sub-list for method input_type\n\t0, // [0:0] is the sub-list for extension type_name\n\t0, // [0:0] is the sub-list for extension extendee\n\t0, // [0:0] is the sub-list for field type_name\n}\n\nfunc init() { file_envelope_proto_init() }\nfunc file_envelope_proto_init() {\n\tif File_envelope_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_envelope_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Envelope); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_envelope_proto_rawDesc,\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   1,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_envelope_proto_goTypes,\n\t\tDependencyIndexes: file_envelope_proto_depIdxs,\n\t\tMessageInfos:      file_envelope_proto_msgTypes,\n\t}.Build()\n\tFile_envelope_proto = out.File\n\tfile_envelope_proto_rawDesc = nil\n\tfile_envelope_proto_goTypes = nil\n\tfile_envelope_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "packages/fetchai/connections/p2p_libp2p/libp2p_node/aea/envelope.proto",
    "content": "syntax = \"proto3\";\n\n//package libp2p_node.aea;\npackage aea;\n\nmessage Envelope{\n    string to = 1;\n    string sender = 2;\n    string protocol_id = 3;\n    bytes message = 4;\n    string uri = 5;\n}"
  },
  {
    "path": "packages/fetchai/connections/p2p_libp2p/libp2p_node/aea/pipe.go",
    "content": "// +build windows linux darwin\n\n/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2019 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\n\npackage aea\n\nimport (\n\t\"encoding/binary\"\n\t\"errors\"\n\tcommon \"libp2p_node/common\"\n\t\"math\"\n\t\"net\"\n\t\"strconv\"\n)\n\ntype TCPSocketChannel struct {\n\tport uint16\n\tconn net.Conn\n}\n\nfunc (sock *TCPSocketChannel) Connect() error {\n\t// open tcp connection\n\tvar err error\n\tsock.conn, err = net.Dial(\"tcp\", \"127.0.0.1:\"+strconv.FormatInt(int64(sock.port), 10))\n\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (sock *TCPSocketChannel) Read() ([]byte, error) {\n\t// TOFIX(LR) duplicated code to avoid circular dep\n\t//           utils.ReadBytesConn(sock.conn)\n\tbuf := make([]byte, 4)\n\t_, err := sock.conn.Read(buf)\n\tif err != nil {\n\t\treturn buf, err\n\t}\n\tsize := binary.BigEndian.Uint32(buf)\n\n\tbuf = make([]byte, size)\n\t_, err = sock.conn.Read(buf)\n\treturn buf, err\n}\n\nfunc (sock *TCPSocketChannel) Write(data []byte) error {\n\t// TOFIX(LR) duplicated code to avoid circular dep\n\t//    \t\t utils.WriteBytesConn(sock.conn, data)\n\tif len(data) > math.MaxInt32 {\n\t\treturn errors.New(\"value too large\")\n\t}\n\tsize := uint32(len(data))\n\tbuf := make([]byte, 4, 4+size)\n\tbinary.BigEndian.PutUint32(buf, size)\n\tbuf = append(buf, data...)\n\t_, err := sock.conn.Write(buf)\n\tlogger.Debug().Msgf(\"wrote data to pipe: %d bytes\", size)\n\treturn err\n}\n\nfunc (sock *TCPSocketChannel) Close() error {\n\treturn sock.conn.Close()\n}\n\nfunc NewPipe(msgin_path string, msgout_path string) common.Pipe {\n\tport, _ := strconv.ParseUint(msgin_path, 10, 16)\n\treturn &TCPSocketChannel{port: uint16(port)}\n}\n"
  },
  {
    "path": "packages/fetchai/connections/p2p_libp2p/libp2p_node/aea/utils.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2019 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\n\npackage aea\n\nimport (\n\t\"errors\"\n\n\tacn \"libp2p_node/acn\"\n\tcommon \"libp2p_node/common\"\n\n\tproto \"google.golang.org/protobuf/proto\"\n)\n\nfunc HandleAcnMessageFromPipe(\n\tpipe common.Pipe,\n\tstatusQueue acn.StatusQueue,\n\tcounterpartyID string,\n) (*Envelope, error) {\n\tenvelope := &Envelope{}\n\tvar acn_err error\n\n\tdata, err := pipe.Read()\n\n\tif err != nil {\n\t\tlogger.Error().Str(\"err\", err.Error()).Msg(\"while receiving data\")\n\t\treturn nil, &common.PipeError{Err: err, Msg: \"Pipe error during envelope read\"}\n\t}\n\n\tmsg_type, acn_envelope, status, acnErr := acn.DecodeAcnMessage(data)\n\n\tif acnErr != nil {\n\t\tlogger.Error().Str(\"err\", acnErr.Error()).Msg(\"while handling acn message\")\n\t\tacn_err = acn.SendAcnError(\n\t\t\tpipe,\n\t\t\tacnErr.Error(),\n\t\t\tacnErr.ErrorCode,\n\t\t)\n\t\tif acn_err != nil {\n\t\t\tlogger.Error().Str(\"err\", acn_err.Error()).Msg(\"on acn send error\")\n\t\t}\n\t\treturn envelope, acnErr\n\t}\n\n\tswitch msg_type {\n\tcase \"aea_envelope\":\n\t\t{\n\t\t\terr = proto.Unmarshal(acn_envelope.Envelope, envelope)\n\t\t\tif err != nil {\n\t\t\t\tlogger.Error().Str(\"err\", err.Error()).Msg(\"while decoding envelope\")\n\t\t\t\tacn_err = acn.SendAcnError(\n\t\t\t\t\tpipe,\n\t\t\t\t\t\"error on decoding envelope\",\n\t\t\t\t\tacn.ERROR_DECODE,\n\t\t\t\t)\n\t\t\t\tif acn_err != nil {\n\t\t\t\t\tlogger.Error().Str(\"err\", acn_err.Error()).Msg(\"on acn send error\")\n\t\t\t\t}\n\t\t\t\treturn envelope, err\n\t\t\t}\n\t\t\terr = acn.SendAcnSuccess(pipe)\n\t\t\treturn envelope, err\n\n\t\t}\n\tcase \"status\":\n\t\t{\n\t\t\tlogger.Debug().Msgf(\"got acn status %d\", status.Code)\n\t\t\tstatusQueue.AddAcnStatusMessage(status, counterpartyID)\n\t\t\treturn nil, nil\n\n\t\t}\n\tdefault:\n\t\t{\n\t\t\tacn_err = acn.SendAcnError(pipe, \"Unsupported ACN message\")\n\t\t\tif acn_err != nil {\n\t\t\t\tlogger.Error().Str(\"err\", acn_err.Error()).Msg(\"on acn send error\")\n\t\t\t}\n\t\t\treturn nil, errors.New(\"unsupported ACN message\")\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "packages/fetchai/connections/p2p_libp2p/libp2p_node/common/common.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2021 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\npackage common\n\ntype PipeError struct {\n\tErr error\n\tMsg string\n}\n\nfunc (err *PipeError) Error() string {\n\treturn err.Msg\n}\n\nfunc (err *PipeError) Unwrap() error {\n\treturn err.Err\n}\n\ntype Pipe interface {\n\tConnect() error\n\tRead() ([]byte, error)\n\tWrite(data []byte) error\n\tClose() error\n}\n"
  },
  {
    "path": "packages/fetchai/connections/p2p_libp2p/libp2p_node/dht/common/handlers.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2019 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\n\n// Package dhtpeer provides an implementation of an Agent Communication Network node\n// using libp2p. It participates in data storage and routing for the network.\n// It offers RelayService for dhtclient and DelegateService for tcp clients.\npackage common\n\nimport (\n\t\"strings\"\n\n\t\"log\"\n\n\t\"github.com/libp2p/go-libp2p-core/network\"\n\t\"github.com/pkg/errors\"\n\t\"github.com/rs/zerolog\"\n\t\"google.golang.org/protobuf/proto\"\n\n\tacn \"libp2p_node/acn\"\n\taea \"libp2p_node/aea\"\n\t\"libp2p_node/dht/dhtnode\"\n\tutils \"libp2p_node/utils\"\n)\n\nfunc ignore(err error) {\n\tif err != nil {\n\t\tlog.Println(\"IGNORED\", err)\n\t}\n}\n\n//Abstract DHTHandler that provides logging function and handle for incoming envelopes and ACN address requests\ntype DHTHandler interface {\n\tGetLoggers() (func(error) *zerolog.Event, func() *zerolog.Event, func() *zerolog.Event, func() *zerolog.Event)\n\tHandleAeaEnvelope(envel *aea.Envelope) *acn.ACNError\n\tHandleAeaAddressRequest(reqAddress string) (*acn.AgentRecord, *acn.ACNError)\n}\n\n//read ACN message, decode envelope, check PoR\nfunc receiveEnvelopeFromPeer(dhtHandler DHTHandler, stream network.Stream) (*aea.Envelope, error) {\n\tlerror, _, _, _ := dhtHandler.GetLoggers()\n\tstreamPipe := utils.StreamPipe{Stream: stream}\n\n\taeaEnvelope, err := acn.ReadEnvelopeMessage(streamPipe)\n\tif err != nil {\n\t\tlerror(err).Msg(\"while handling acn envelope message\")\n\t\treturn nil, err\n\t}\n\n\tenvel := &aea.Envelope{}\n\terr = proto.Unmarshal(aeaEnvelope.Envelope, envel)\n\tif err != nil {\n\t\tlerror(err).Msg(\"while deserializing acn aea envelope message\")\n\t\tignore(acn.SendAcnError(\n\t\t\tstreamPipe,\n\t\t\t\"while deserializing acn aea envelope message\",\n\t\t\tacn.ERROR_DECODE,\n\t\t))\n\t\treturn nil, err\n\t}\n\n\tremotePubkey, err := utils.FetchAIPublicKeyFromPubKey(stream.Conn().RemotePublicKey())\n\tignore(err)\n\tstatus, err := dhtnode.IsValidProofOfRepresentation(\n\t\taeaEnvelope.Record,\n\t\taeaEnvelope.Record.Address,\n\t\tremotePubkey,\n\t)\n\tif err != nil || status.Code != acn.SUCCESS {\n\t\tif err == nil {\n\t\t\terr = errors.New(status.Code.String() + \":\" + strings.Join(status.Msgs, \":\"))\n\t\t}\n\t\tlerror(err).Msg(\"incoming envelope PoR is not valid\")\n\t\tignore(acn.SendAcnError(streamPipe, \"incoming envelope PoR is not valid\", status.Code))\n\t\treturn nil, err\n\t}\n\treturn envel, nil\n}\n\n// handle envelope stream, handle acn protocol and call dhtHandler.HandleAeaEnvelope for incoming envelopes\nfunc HandleAeaEnvelopeStream(dhtHandler DHTHandler, stream network.Stream) {\n\tlerror, _, _, ldebug := dhtHandler.GetLoggers()\n\n\t//ldebug().Msgf(\"Got a new aea envelope stream\")\n\n\tenvel, err := receiveEnvelopeFromPeer(dhtHandler, stream)\n\n\tif err != nil {\n\t\tlerror(err).Msgf(\"while reading envelope from peer\")\n\t\tstream.Close()\n\t\treturn\n\t}\n\n\tldebug().Msgf(\"Received envelope from peer %s\", envel.String())\n\tstreamPipe := utils.StreamPipe{Stream: stream}\n\tacnError := dhtHandler.HandleAeaEnvelope(envel)\n\n\tif acnError != nil {\n\t\terr = acn.SendAcnError(streamPipe, acnError.Err.Error(), acnError.ErrorCode)\n\t\tignore(err)\n\t\terr = stream.Close()\n\t\tignore(err)\n\t\treturn\n\t}\n\n\terr = acn.SendAcnSuccess(streamPipe)\n\tignore(err)\n\terr = stream.Close()\n\tignore(err)\n}\n\n// handle address request stream, handle acn protocol and call dhtHandler.HandleAeaAddressRequest for incoming requests\nfunc HandleAeaAddressStream(dhtHandler DHTHandler, stream network.Stream) {\n\tlerror, _, _, ldebug := dhtHandler.GetLoggers()\n\n\t//ldebug().Msg(\"Got a new aea address stream\")\n\n\t// get LookupRequest\n\tstreamPipe := utils.StreamPipe{Stream: stream}\n\treqAddress, err := acn.ReadLookupRequest(streamPipe)\n\tif err != nil {\n\t\tlerror(err).Str(\"op\", \"resolve\").\n\t\t\tMsg(\"while reading message from stream\")\n\t\terr = stream.Reset()\n\t\tignore(err)\n\t\treturn\n\t}\n\n\tldebug().\n\t\tStr(\"op\", \"resolve\").\n\t\tStr(\"target\", reqAddress).\n\t\tMsg(\"Received query for addr\")\n\n\trecord, acnError := dhtHandler.HandleAeaAddressRequest(reqAddress)\n\tif acnError != nil {\n\t\tlerror(acnError.Err).\n\t\t\tStr(\"op\", \"resolve\").\n\t\t\tStr(\"target\", reqAddress).\n\t\t\tMsgf(\"request address error\")\n\t\terr = acn.SendAcnError(streamPipe, acnError.Err.Error(), acnError.ErrorCode)\n\t\tignore(err)\n\t\terr = stream.Close()\n\t\tignore(err)\n\t\treturn\n\t}\n\tif record == nil {\n\t\tlerror(acnError.Err).\n\t\t\tStr(\"op\", \"resolve\").\n\t\t\tStr(\"target\", reqAddress).\n\t\t\tMsgf(\"unexpected error. agent record is nil!\")\n\t\treturn\n\t}\n\terr = acn.SendLookupResponse(streamPipe, record)\n\tif err != nil {\n\t\tlerror(err).Str(\"op\", \"resolve\").Str(\"addr\", reqAddress).\n\t\t\tMsg(\"while sending agent record to peer\")\n\t\terr = stream.Reset()\n\t\tignore(err)\n\t}\n}\n"
  },
  {
    "path": "packages/fetchai/connections/p2p_libp2p/libp2p_node/dht/dhtclient/dhtclient.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2019 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\n\n// Package dhtclient provides implementation of a lightweight Agent Communication Network\n// node. It doesn't participate in network maintenance. It doesn't require a public IP\n// address either, as it relies on a DHTPeer (relay peer) to communicate with other peers.\npackage dhtclient\n\nimport (\n\t\"context\"\n\t\"log\"\n\t\"math/rand\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/pkg/errors\"\n\n\t\"github.com/rs/zerolog\"\n\t\"google.golang.org/protobuf/proto\"\n\n\tlibp2p \"github.com/libp2p/go-libp2p\"\n\t\"github.com/libp2p/go-libp2p-core/crypto\"\n\t\"github.com/libp2p/go-libp2p-core/host\"\n\t\"github.com/libp2p/go-libp2p-core/network\"\n\t\"github.com/libp2p/go-libp2p-core/peer\"\n\t\"github.com/libp2p/go-libp2p-core/protocol\"\n\t\"github.com/multiformats/go-multiaddr\"\n\n\tpeerstore \"github.com/libp2p/go-libp2p-core/peerstore\"\n\tkaddht \"github.com/libp2p/go-libp2p-kad-dht\"\n\troutedhost \"github.com/libp2p/go-libp2p/p2p/host/routed\"\n\n\tacn \"libp2p_node/acn\"\n\taea \"libp2p_node/aea\"\n\tcommon \"libp2p_node/dht/common\"\n\t\"libp2p_node/dht/dhtnode\"\n\tutils \"libp2p_node/utils\"\n)\n\nfunc ignore(err error) {\n\tif err != nil {\n\t\tlog.Println(\"IGNORED\", err)\n\t}\n}\n\nconst (\n\tnewStreamTimeoutRelayPeer = 5 * 60 * time.Second // includes peer restart\n\tnewStreamTimeout          = 1 * 60 * time.Second // doesn't include peer restart\n\tbootstrapTimeout          = 1 * 60 * time.Second // doesn't include peer restart\n\tsleepTimeDefaultDuration  = 100 * time.Millisecond\n\tsleepTimeIncreaseMFactor  = 2 // multiplicative increase\n\treconnectTimeout          = 5 * time.Second\n)\n\n// Notifee Handle DHTClient network events\ntype Notifee struct {\n\tmyRelayPeer peer.AddrInfo\n\tmyHost      host.Host\n\tlogger      zerolog.Logger\n\tclosing     chan struct{}\n}\n\n// Listen called when network starts listening on an addr\nfunc (notifee *Notifee) Listen(network.Network, multiaddr.Multiaddr) {}\n\n// ListenClose called when network stops listening on an addr\nfunc (notifee *Notifee) ListenClose(network.Network, multiaddr.Multiaddr) {}\n\n// Connected called when a connection opened\nfunc (notifee *Notifee) Connected(net network.Network, conn network.Conn) {\n\tnotifee.logger.Info().Msgf(\n\t\t\"Connected to peer %s\",\n\t\tconn.RemotePeer().Pretty(),\n\t)\n\n}\n\n// Disconnected called when a connection closed\n// Reconnects if connection is to relay peer and not currenctly closing connection.\nfunc (notifee *Notifee) Disconnected(net network.Network, conn network.Conn) {\n\n\tnotifee.logger.Info().Msgf(\n\t\t\"Disconnected from peer %s\",\n\t\tconn.RemotePeer().Pretty(),\n\t)\n\tpinfo := notifee.myRelayPeer\n\tif conn.RemotePeer().Pretty() != pinfo.ID.Pretty() {\n\t\treturn\n\t}\n\n\tnotifee.myHost.Peerstore().AddAddrs(pinfo.ID, pinfo.Addrs, peerstore.PermanentAddrTTL)\n\tfor {\n\t\tvar err error\n\t\tselect {\n\t\tcase _, open := <-notifee.closing:\n\t\t\tif !open {\n\t\t\t\treturn\n\t\t\t}\n\t\tdefault:\n\t\t\tnotifee.logger.Warn().Msgf(\n\t\t\t\t\"Lost connection to relay peer %s, reconnecting...\",\n\t\t\t\tpinfo.ID.Pretty(),\n\t\t\t)\n\t\t\tctx, cancel := context.WithTimeout(context.Background(), reconnectTimeout)\n\t\t\tdefer cancel()\n\t\t\tif err = notifee.myHost.Connect(ctx, pinfo); err == nil {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\ttime.Sleep(1 * time.Second)\n\n\t\t}\n\t\tif err == nil {\n\t\t\tbreak\n\t\t}\n\t}\n\tnotifee.logger.Info().Msgf(\"Connection to relay peer %s reestablished\", pinfo.ID.Pretty())\n}\n\n// OpenedStream called when a stream opened\nfunc (notifee *Notifee) OpenedStream(network.Network, network.Stream) {}\n\n// ClosedStream called when a stream closed\nfunc (notifee *Notifee) ClosedStream(network.Network, network.Stream) {}\n\n// DHTClient A restricted libp2p node for the Agents Communication Network\n// It use a `DHTPeer` to communicate with other peers.\ntype DHTClient struct {\n\tbootstrapPeers []peer.AddrInfo\n\trelayPeer      peer.ID\n\tkey            crypto.PrivKey\n\tpublicKey      crypto.PubKey\n\n\tdht        *kaddht.IpfsDHT\n\troutedHost *routedhost.RoutedHost\n\n\tmyAgentAddress  string\n\tmyAgentRecord   *acn.AgentRecord\n\tmyAgentReady    func() bool\n\tprocessEnvelope func(*aea.Envelope) error\n\n\tclosing chan struct{}\n\tlogger  zerolog.Logger\n}\n\n// New creates a new DHTClient\nfunc New(opts ...Option) (*DHTClient, error) {\n\tvar err error\n\tdhtClient := &DHTClient{}\n\n\tfor _, opt := range opts {\n\t\tif err := opt(dhtClient); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tdhtClient.closing = make(chan struct{})\n\n\t/* check correct configuration */\n\n\t// private key\n\tif dhtClient.key == nil {\n\t\treturn nil, errors.New(\"private key must be provided\")\n\t}\n\n\t// agent address is mandatory\n\tif dhtClient.myAgentAddress == \"\" {\n\t\treturn nil, errors.New(\"missing agent address\")\n\t}\n\n\t// agent record is mandatory\n\tif dhtClient.myAgentRecord == nil {\n\t\treturn nil, errors.New(\"missing agent record\")\n\t}\n\n\t// check if the PoR is delivered for my public key\n\tmyPublicKey, err := utils.FetchAIPublicKeyFromPubKey(dhtClient.publicKey)\n\tstatus, errPoR := dhtnode.IsValidProofOfRepresentation(\n\t\tdhtClient.myAgentRecord,\n\t\tdhtClient.myAgentRecord.Address,\n\t\tmyPublicKey,\n\t)\n\tif err != nil || errPoR != nil || status.Code != acn.SUCCESS {\n\t\tmsg := \"Invalid AgentRecord\"\n\t\tif err != nil {\n\t\t\tmsg += \" - \" + err.Error()\n\t\t}\n\t\tif errPoR != nil {\n\t\t\tmsg += \" - \" + errPoR.Error()\n\t\t}\n\t\treturn nil, errors.New(msg)\n\t}\n\n\t// bootstrap peers\n\tif len(dhtClient.bootstrapPeers) < 1 {\n\t\treturn nil, errors.New(\"at least one boostrap peer should be provided\")\n\t}\n\n\t// select a relay node randomly from entry peers\n\trand.Seed(time.Now().Unix())\n\tindex := rand.Intn(len(dhtClient.bootstrapPeers))\n\tdhtClient.relayPeer = dhtClient.bootstrapPeers[index].ID\n\n\tdhtClient.setupLogger()\n\t_, _, linfo, ldebug := dhtClient.GetLoggers()\n\tlinfo().Msg(\"INFO Using as relay\")\n\n\t/* setup libp2p node */\n\tctx := context.Background()\n\n\t// libp2p options\n\tlibp2pOpts := []libp2p.Option{\n\t\tlibp2p.ListenAddrs(),\n\t\tlibp2p.Identity(dhtClient.key),\n\t\tlibp2p.DefaultTransports,\n\t\tlibp2p.DefaultMuxers,\n\t\tlibp2p.DefaultSecurity,\n\t\tlibp2p.NATPortMap(),\n\t\tlibp2p.EnableNATService(),\n\t\tlibp2p.EnableRelay(),\n\t}\n\n\t// create a basic host\n\tbasicHost, err := libp2p.New(ctx, libp2pOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// create the dht\n\tdhtClient.dht, err = kaddht.New(ctx, basicHost, kaddht.Mode(kaddht.ModeClient))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// make the routed host\n\tdhtClient.routedHost = routedhost.Wrap(basicHost, dhtClient.dht)\n\tdhtClient.setupLogger()\n\n\t// connect to the booststrap nodes\n\terr = dhtClient.bootstrapLoopUntilTimeout()\n\tif err != nil {\n\t\tdhtClient.Close()\n\t\treturn nil, err\n\t}\n\n\t// bootstrap the host\n\terr = dhtClient.dht.Bootstrap(ctx)\n\tif err != nil {\n\t\tdhtClient.Close()\n\t\treturn nil, err\n\t}\n\n\t// register my address to relay peer\n\terr = dhtClient.registerAgentAddress()\n\tif err != nil {\n\t\tdhtClient.Close()\n\t\treturn nil, err\n\t}\n\n\tdhtClient.routedHost.Network().Notify(&Notifee{\n\t\tmyRelayPeer: dhtClient.bootstrapPeers[index],\n\t\tmyHost:      dhtClient.routedHost,\n\t\tlogger:      dhtClient.logger,\n\t\tclosing:     dhtClient.closing,\n\t})\n\n\t/* setup DHTClient message handlers */\n\n\t// aea address lookup\n\tldebug().Msg(\"DEBUG Setting /aea-address/0.1.0 stream...\")\n\tdhtClient.routedHost.SetStreamHandler(dhtnode.AeaAddressStream,\n\t\tdhtClient.handleAeaAddressStream)\n\n\t// incoming envelopes stream\n\tldebug().Msg(\"DEBUG Setting /aea/0.1.0 stream...\")\n\tdhtClient.routedHost.SetStreamHandler(dhtnode.AeaEnvelopeStream,\n\t\tdhtClient.handleAeaEnvelopeStream)\n\n\treturn dhtClient, nil\n}\n\n// bootstrapLoopUntilTimeout loops until connection to bootstrap peers established or timeout reached\nfunc (dhtClient *DHTClient) bootstrapLoopUntilTimeout() error {\n\tlerror, _, _, _ := dhtClient.GetLoggers()\n\tctx, cancel := context.WithTimeout(context.Background(), bootstrapTimeout)\n\tdefer cancel()\n\terr := utils.BootstrapConnect(\n\t\tctx,\n\t\tdhtClient.routedHost,\n\t\tdhtClient.dht,\n\t\tdhtClient.bootstrapPeers,\n\t)\n\tsleepTime := sleepTimeDefaultDuration\n\tfor err != nil {\n\t\tlerror(err).\n\t\t\tStr(\"op\", \"bootstrap\").\n\t\t\tMsgf(\"couldn't open stream to bootstrap peer, retrying in %s\", sleepTime)\n\t\tselect {\n\t\tdefault:\n\t\t\ttime.Sleep(sleepTime)\n\t\t\tsleepTime = sleepTime * sleepTimeIncreaseMFactor\n\t\t\terr = utils.BootstrapConnect(\n\t\t\t\tctx,\n\t\t\t\tdhtClient.routedHost,\n\t\t\t\tdhtClient.dht,\n\t\t\t\tdhtClient.bootstrapPeers,\n\t\t\t)\n\t\tcase <-ctx.Done():\n\t\t\terr = errors.New(\"bootstrap connect timeout reached\")\n\t\t}\n\t}\n\treturn err\n}\n\n// newStreamLoopUntilTimeout loops until stream to peer established or timeout reached\nfunc (dhtClient *DHTClient) newStreamLoopUntilTimeout(\n\tpeerID peer.ID,\n\tstreamType protocol.ID,\n\ttimeout time.Duration,\n) (network.Stream, error) {\n\tlerror, _, _, _ := dhtClient.GetLoggers()\n\tctx, cancel := context.WithTimeout(context.Background(), timeout)\n\tdefer cancel()\n\tstream, err := dhtClient.routedHost.NewStream(ctx, peerID, streamType)\n\tsleepTime := sleepTimeDefaultDuration\n\tdisconnected := false\n\tfor err != nil {\n\t\tdisconnected = true\n\t\tlerror(err).\n\t\t\tStr(\"op\", \"route\").\n\t\t\tMsgf(\"couldn't open stream to peer %s, retrying in %s\", peerID.Pretty(), sleepTime)\n\t\tselect {\n\t\tdefault:\n\t\t\ttime.Sleep(sleepTime)\n\t\t\tsleepTime = sleepTime * sleepTimeIncreaseMFactor\n\t\t\tstream, err = dhtClient.routedHost.NewStream(ctx, peerID, streamType)\n\t\tcase <-ctx.Done():\n\t\t\terr = errors.New(\"new stream loop timeout reached\")\n\t\t}\n\t}\n\tif stream == nil && err == nil {\n\t\treturn nil, errors.New(\"stream nil and err nil\")\n\t}\n\t// register again in case of disconnection\n\tif disconnected {\n\t\terr = dhtClient.registerAgentAddress()\n\t}\n\treturn stream, err\n}\n\n// setupLogger sets up a logger for the DHTClient\nfunc (dhtClient *DHTClient) setupLogger() {\n\tfields := map[string]string{\n\t\t\"package\": \"DHTClient\",\n\t\t\"relayid\": dhtClient.relayPeer.Pretty(),\n\t}\n\tif dhtClient.routedHost != nil {\n\t\tfields[\"peerid\"] = dhtClient.routedHost.ID().Pretty()\n\t}\n\tdhtClient.logger = utils.NewDefaultLoggerWithFields(fields)\n}\n\n// GetLoggers gets the various logger levels of the DHTClient\nfunc (dhtClient *DHTClient) GetLoggers() (func(error) *zerolog.Event, func() *zerolog.Event, func() *zerolog.Event, func() *zerolog.Event) {\n\tldebug := dhtClient.logger.Debug\n\tlinfo := dhtClient.logger.Info\n\tlwarn := dhtClient.logger.Warn\n\tlerror := func(err error) *zerolog.Event {\n\t\tif err == nil {\n\t\t\treturn dhtClient.logger.Error().Str(\"err\", \"nil\")\n\t\t}\n\t\treturn dhtClient.logger.Error().Str(\"err\", err.Error())\n\t}\n\n\treturn lerror, lwarn, linfo, ldebug\n}\n\n// Close stops the DHTClient\n// Closes the DHT and routedHost of the DHTClient\nfunc (dhtClient *DHTClient) Close() []error {\n\tvar err error\n\tvar status []error\n\n\t_, _, linfo, _ := dhtClient.GetLoggers()\n\n\tlinfo().Msg(\"Stopping DHTClient...\")\n\tclose(dhtClient.closing)\n\n\terrappend := func(err error) {\n\t\tif err != nil {\n\t\t\tstatus = append(status, err)\n\t\t}\n\t}\n\n\terr = dhtClient.dht.Close()\n\terrappend(err)\n\terr = dhtClient.routedHost.Close()\n\terrappend(err)\n\n\treturn status\n}\n\n// MultiAddr always return empty string\nfunc (dhtClient *DHTClient) MultiAddr() string {\n\treturn \"\"\n}\n\nfunc (dhtClient *DHTClient) PeerID() string {\n\treturn dhtClient.routedHost.ID().Pretty()\n}\n\n// RouteEnvelope routes the provided envelope to its destination contact peer\nfunc (dhtClient *DHTClient) RouteEnvelope(envel *aea.Envelope) error {\n\tlerror, lwarn, _, ldebug := dhtClient.GetLoggers()\n\n\t// only send envelopes from own agent\n\tif envel.Sender != dhtClient.myAgentAddress {\n\t\terr := errors.New(\"Sender (\" + envel.Sender + \") must match registered address\")\n\t\tlerror(err).Str(\"addr\", dhtClient.myAgentAddress).\n\t\t\tMsgf(\"while routing envelope\")\n\t\treturn err\n\t}\n\n\ttarget := envel.To\n\n\t// TODO(LR) check if the record is valid\n\tif target == dhtClient.myAgentAddress {\n\t\tldebug().\n\t\t\tStr(\"op\", \"route\").\n\t\t\tStr(\"target\", target).\n\t\t\tMsg(\"envelope destinated to my local agent...\")\n\t\tfor !dhtClient.myAgentReady() {\n\t\t\tldebug().\n\t\t\t\tStr(\"op\", \"route\").\n\t\t\t\tStr(\"target\", target).\n\t\t\t\tMsg(\"agent not ready yet, sleeping for some time ...\")\n\t\t\ttime.Sleep(time.Duration(100) * time.Millisecond)\n\t\t}\n\t\tif dhtClient.processEnvelope != nil {\n\t\t\terr := dhtClient.processEnvelope(envel)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t} else {\n\t\t\tlwarn().\n\t\t\t\tStr(\"op\", \"route\").\n\t\t\t\tStr(\"target\", target).\n\t\t\t\tMsgf(\"ProcessEnvelope not set, ignoring envelope %s\", envel.String())\n\t\t\treturn nil\n\t\t}\n\t}\n\n\t// client can get addresses only through bootstrap peer\n\tstream, err := dhtClient.newStreamLoopUntilTimeout(\n\t\tdhtClient.relayPeer,\n\t\tdhtnode.AeaAddressStream,\n\t\tnewStreamTimeoutRelayPeer,\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tldebug().\n\t\tStr(\"op\", \"route\").\n\t\tStr(\"target\", target).\n\t\tMsg(\"requesting agent record from relay...\")\n\n\tstreamPipe := utils.StreamPipe{Stream: stream}\n\n\trecord, err := acn.PerformAddressLookup(streamPipe, target)\n\tif err != nil {\n\t\tlerror(err).Str(\"op\", \"route\").Str(\"target\", target).\n\t\t\tMsgf(\"failed agent lookup\")\n\t\treturn err\n\t}\n\tvalid, err := dhtnode.IsValidProofOfRepresentation(record, target, record.PeerPublicKey)\n\tif err != nil || valid.Code != acn.SUCCESS {\n\t\terrMsg := valid.Code.String() + \" : \" + strings.Join(\n\t\t\tvalid.Msgs,\n\t\t\t\":\",\n\t\t)\n\t\tif err == nil {\n\t\t\terr = errors.New(errMsg)\n\t\t} else {\n\t\t\terr = errors.Wrap(err, valid.Code.String()+\" : \"+strings.Join(valid.Msgs, \":\"))\n\t\t}\n\t\tlerror(err).Str(\"op\", \"route\").Str(\"target\", target).\n\t\t\tMsgf(\"invalid agent record\")\n\t\treturn err\n\t}\n\n\tstream.Close()\n\n\t// retrieve peerID\n\tpeerID, err := utils.IDFromFetchAIPublicKey(record.PeerPublicKey)\n\tif err != nil {\n\t\tlerror(err).\n\t\t\tStr(\"op\", \"route\").\n\t\t\tStr(\"target\", target).\n\t\t\tMsg(\"CRITICAL couldn't get peer ID from message\")\n\t\treturn errors.New(\"CRITICAL route - couldn't get peer ID from record peerID:\" + err.Error())\n\t}\n\n\tldebug().\n\t\tStr(\"op\", \"route\").\n\t\tStr(\"target\", target).\n\t\tMsgf(\"got peer ID %s for agent Address\", peerID.Pretty())\n\n\t// TODO(LR): test if representative peer is relay peer, and skip the Connect if it is the case\n\t// TODO(DM): extract below multi-address creation for reuse and consistency\n\tmultiAddr := \"/p2p/\" + dhtClient.relayPeer.Pretty() + \"/p2p-circuit/p2p/\" + peerID.Pretty()\n\trelayMultiaddr, err := multiaddr.NewMultiaddr(multiAddr)\n\tif err != nil {\n\t\tlerror(err).\n\t\t\tStr(\"op\", \"route\").\n\t\t\tStr(\"target\", target).\n\t\t\tMsgf(\"while creating relay multiaddress %s\", multiAddr)\n\t\treturn err\n\t}\n\tpeerRelayInfo := peer.AddrInfo{\n\t\tID:    peerID,\n\t\tAddrs: []multiaddr.Multiaddr{relayMultiaddr},\n\t}\n\n\tldebug().\n\t\tStr(\"op\", \"route\").\n\t\tStr(\"target\", target).\n\t\tMsgf(\"connecting to target through relay %s\", relayMultiaddr)\n\n\tif err = dhtClient.routedHost.Connect(context.Background(), peerRelayInfo); err != nil {\n\t\tlerror(err).\n\t\t\tStr(\"op\", \"route\").\n\t\t\tStr(\"target\", target).\n\t\t\tMsgf(\"couldn't connect to target %s\", peerID)\n\t\treturn err\n\t}\n\n\tldebug().\n\t\tStr(\"op\", \"route\").\n\t\tStr(\"target\", target).\n\t\tMsgf(\"opening stream to target %s\", peerID)\n\n\tstream, err = dhtClient.newStreamLoopUntilTimeout(\n\t\tpeerID,\n\t\tdhtnode.AeaEnvelopeStream,\n\t\tnewStreamTimeout,\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\tstreamPipe = utils.StreamPipe{Stream: stream}\n\n\tenvelBytes, err := proto.Marshal(envel)\n\tif err != nil {\n\t\tlerror(err).\n\t\t\tStr(\"op\", \"route\").\n\t\t\tStr(\"target\", target).\n\t\t\tMsg(\"couldn't serialize envelope\")\n\t\terrReset := stream.Reset()\n\t\tignore(errReset)\n\t\treturn err\n\t}\n\n\terr = acn.SendEnvelopeMessage(streamPipe, envelBytes, dhtClient.myAgentRecord)\n\tif err != nil {\n\t\tlerror(err).\n\t\t\tStr(\"op\", \"route\").\n\t\t\tStr(\"target\", target).\n\t\t\tMsg(\"couldn't send envelope\")\n\t\terrReset := stream.Reset()\n\t\tlerror(errReset).\n\t\t\tMsg(\"stream.Reset error\")\n\t\tignore(errReset)\n\t\treturn err\n\t}\n\n\t// wait for response\n\tstatus, err := acn.ReadAcnStatus(streamPipe)\n\tif err != nil {\n\t\tlerror(err).\n\t\t\tStr(\"op\", \"route\").\n\t\t\tStr(\"target\", target).\n\t\t\tMsg(\"while getting confirmation\")\n\t\terrReset := stream.Reset()\n\t\tignore(errReset)\n\t\treturn err\n\t}\n\n\tstream.Close()\n\n\tif status.Code != acn.SUCCESS {\n\t\terr = errors.New(\n\t\t\tstatus.Code.String() + \" : \" + strings.Join(\n\t\t\t\tstatus.Msgs,\n\t\t\t\t\":\",\n\t\t\t),\n\t\t)\n\t\tlerror(err).\n\t\t\tStr(\"op\", \"route\").\n\t\t\tStr(\"target\", target).\n\t\t\tMsg(\"failed to deliver envelope\")\n\t\treturn err\n\t}\n\n\t// TODO(DM) check how we handle case when envelope not routable.\n\treturn err\n}\n\n// handleAeaEnvelopeStream deals with incoming envelopes on the AeaEnvelopeStream\n// envelopes arrive from other peers (full or client) and are processed\n// by HandleAeaEnvelope\nfunc (dhtClient *DHTClient) handleAeaEnvelopeStream(stream network.Stream) {\n\tcommon.HandleAeaEnvelopeStream(dhtClient, stream)\n}\n\n// Callback to handle and route  aea envelope comes from the aea envelope stream\n// return ACNError if message routing failed, otherwise nil.\nfunc (dhtClient *DHTClient) HandleAeaEnvelope(envel *aea.Envelope) *acn.ACNError {\n\tlerror, lwarn, _, _ := dhtClient.GetLoggers()\n\tvar err error\n\tif envel.To == dhtClient.myAgentAddress && dhtClient.processEnvelope != nil {\n\t\terr = dhtClient.processEnvelope(envel)\n\t\tif err != nil {\n\t\t\tlerror(err).Msgf(\"while processing envelope by agent\")\n\t\t\treturn &acn.ACNError{\n\t\t\t\tErr:       errors.New(\"agent is not ready\"),\n\t\t\t\tErrorCode: acn.ERROR_AGENT_NOT_READY,\n\t\t\t}\n\t\t}\n\t} else {\n\t\tlwarn().Msgf(\"ignored envelope from unknown agent %s\", envel.String())\n\t\treturn &acn.ACNError{Err: errors.New(\"unknown agent address\"), ErrorCode: acn.ERROR_UNKNOWN_AGENT_ADDRESS}\n\t}\n\treturn nil\n}\n\n// handleAeaAddressStream deals with incoming envelopes on the AeaAddressStream\n// agent record lookup requests arrive from other peers (full or client) and are\n// served with the agent record (if applicable)\nfunc (dhtClient *DHTClient) handleAeaAddressStream(stream network.Stream) {\n\tcommon.HandleAeaAddressStream(dhtClient, stream)\n}\n\nfunc (dhtClient *DHTClient) HandleAeaAddressRequest(\n\treqAddress string,\n) (*acn.AgentRecord, *acn.ACNError) {\n\tlerror, _, _, ldebug := dhtClient.GetLoggers()\n\tldebug().\n\t\tStr(\"op\", \"resolve\").\n\t\tStr(\"target\", reqAddress).\n\t\tMsg(\"Received query for addr\")\n\n\tif reqAddress != dhtClient.myAgentAddress {\n\t\tlerror(errors.New(\"unknown agent address\")).\n\t\t\tStr(\"op\", \"resolve\").\n\t\t\tStr(\"target\", reqAddress).\n\t\t\tMsgf(\"requested address different from advertised one %s\", dhtClient.myAgentAddress)\n\t\treturn nil, &acn.ACNError{\n\t\t\tErr:       errors.New(\"unknown agent address\"),\n\t\t\tErrorCode: acn.ERROR_UNKNOWN_AGENT_ADDRESS,\n\t\t}\n\t} else {\n\t\treturn dhtClient.myAgentRecord, nil\n\t}\n}\n\n// registerAgentAddress registers agent address to relay peer\nfunc (dhtClient *DHTClient) registerAgentAddress() error {\n\tlerror, _, _, ldebug := dhtClient.GetLoggers()\n\n\tldebug().\n\t\tStr(\"op\", \"register\").\n\t\tStr(\"addr\", dhtClient.myAgentAddress).\n\t\tMsg(\"opening stream aea-register to relay peer...\")\n\n\tctx, cancel := context.WithTimeout(context.Background(), newStreamTimeoutRelayPeer)\n\tdefer cancel()\n\tstream, err := dhtClient.routedHost.NewStream(\n\t\tctx,\n\t\tdhtClient.relayPeer,\n\t\tdhtnode.AeaRegisterRelayStream,\n\t)\n\tif err != nil {\n\t\tlerror(err).\n\t\t\tStr(\"op\", \"register\").\n\t\t\tStr(\"addr\", dhtClient.myAgentAddress).\n\t\t\tMsg(\"timeout, couldn't open stream to relay peer\")\n\t\treturn err\n\t}\n\n\tldebug().\n\t\tStr(\"op\", \"register\").\n\t\tStr(\"addr\", dhtClient.myAgentAddress).\n\t\tMsgf(\"registering addr and peerID to relay peer\")\n\n\tstreamPipe := utils.StreamPipe{Stream: stream}\n\terr = acn.SendAgentRegisterMessage(streamPipe, dhtClient.myAgentRecord)\n\n\tif err != nil {\n\t\terrReset := stream.Close()\n\t\tignore(errReset)\n\t\treturn err\n\t}\n\tstream.Close()\n\treturn nil\n\n}\n\n// ProcessEnvelope register a callback function for processing of envelopes\n// the function processes envelopes received in handleAeaEnvelopeStream\nfunc (dhtClient *DHTClient) ProcessEnvelope(fn func(*aea.Envelope) error) {\n\tdhtClient.processEnvelope = fn\n}\n"
  },
  {
    "path": "packages/fetchai/connections/p2p_libp2p/libp2p_node/dht/dhtclient/dhtclient_test.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2019 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\n\npackage dhtclient\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"libp2p_node/acn\"\n\t\"libp2p_node/aea\"\n\t\"libp2p_node/dht/dhtnode\"\n\t\"libp2p_node/dht/dhttests\"\n\tutils \"libp2p_node/utils\"\n)\n\n//\nconst (\n\tDefaultFetchAIKey       = \"04ab8ac134ec727917cf4f9e47685e84622151bc8b12838bc54c8ffe5d44d04a\"\n\tDefaultFetchAIPublicKey = \"03b07ef4513e3f0372245b3d6d474d871ba58eacaf3a2a07c487af6d82006b86b4\"\n\tDefaultAgentKey         = \"f76137a61c1ad3ee8a0a9a185bc8e6fa51be1a2528f86042c11f9cc00880024a\"\n\tDefaultAgentPublicKey   = \"021820ce23b5f3a6ef01988149e724af854f89d37b9cabc3b1702cc5287f617b92\"\n\tDefaultAgentAddress     = \"fetch1ver6u7xdvkjy4dq8xxrkc6ualu98k7ykumv08q\"\n\n\tEnvelopeDeliveryTimeout = 10 * time.Second\n\n\tDefaultLedger = dhtnode.DefaultLedger\n)\n\n// TestNew dht client peer\nfunc TestNew(t *testing.T) {\n\n\trxEnvelopesPeer := make(chan *aea.Envelope, 2)\n\tdhtPeer, cleanup, err := dhttests.NewDHTPeerWithDefaults(rxEnvelopesPeer)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to create DHTPeer (required for DHTClient):\", err)\n\t}\n\tdefer cleanup()\n\n\tsignature, err := utils.SignFetchAI([]byte(DefaultFetchAIPublicKey), DefaultAgentKey)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTClient:\", err)\n\t}\n\n\trecord := &acn.AgentRecord{LedgerId: DefaultLedger}\n\trecord.Address = DefaultAgentAddress\n\trecord.PublicKey = DefaultAgentPublicKey\n\trecord.PeerPublicKey = DefaultFetchAIPublicKey\n\trecord.Signature = signature\n\n\topts := []Option{\n\t\tIdentityFromFetchAIKey(DefaultFetchAIKey),\n\t\tRegisterAgentAddress(record, func() bool { return true }),\n\t\tBootstrapFrom([]string{dhtPeer.MultiAddr()}),\n\t}\n\n\tt.Log(dhtPeer.MultiAddr())\n\n\tdhtClient, err := New(opts...)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTClient:\", err)\n\t}\n\tdefer dhtClient.Close()\n\n\trxEnvelopesClient := make(chan *aea.Envelope, 2)\n\tdhtClient.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxEnvelopesClient <- envel\n\t\treturn nil\n\t})\n\n}\n\n// TestRouteEnvelopeToPeerAgent send envelope from DHTClient agent to DHTPeer agent\nfunc TestRouteEnvelopeToPeerAgent(t *testing.T) {\n\n\trxEnvelopesPeer := make(chan *aea.Envelope, 2)\n\tdhtPeer, cleanup, err := dhttests.NewDHTPeerWithDefaults(rxEnvelopesPeer)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to create DHTPeer (required for DHTClient):\", err)\n\t}\n\tdefer cleanup()\n\n\tsignature, err := utils.SignFetchAI([]byte(DefaultFetchAIPublicKey), DefaultAgentKey)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTClient:\", err)\n\t}\n\n\trecord := &acn.AgentRecord{LedgerId: DefaultLedger}\n\trecord.Address = DefaultAgentAddress\n\trecord.PublicKey = DefaultAgentPublicKey\n\trecord.PeerPublicKey = DefaultFetchAIPublicKey\n\trecord.Signature = signature\n\n\topts := []Option{\n\t\tIdentityFromFetchAIKey(DefaultFetchAIKey),\n\t\tRegisterAgentAddress(record, func() bool { return true }),\n\t\tBootstrapFrom([]string{dhtPeer.MultiAddr()}),\n\t}\n\n\tt.Log(dhtPeer.MultiAddr())\n\n\tdhtClient, err := New(opts...)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTClient:\", err)\n\t}\n\tdefer dhtClient.Close()\n\n\trxEnvelopesClient := make(chan *aea.Envelope, 2)\n\tdhtClient.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxEnvelopesClient <- envel\n\t\treturn nil\n\t})\n\n\tif len(rxEnvelopesPeer) != 0 {\n\t\tt.Error(\"DHTPeer agent inbox should be empty\")\n\t}\n\n\terr = dhtClient.RouteEnvelope(&aea.Envelope{\n\t\tTo:     dhttests.DHTPeerDefaultAgentAddress,\n\t\tSender: DefaultAgentAddress,\n\t})\n\tif err != nil {\n\t\tt.Error(\"Failed to Route envelope to DHTPeer agent:\", err)\n\t}\n\n\ttimeout := time.After(EnvelopeDeliveryTimeout)\n\tselect {\n\tcase envel := <-rxEnvelopesPeer:\n\t\tt.Log(\"DHT received envelope\", envel)\n\tcase <-timeout:\n\t\tt.Error(\"Failed to Route envelope to DHTPeer agent\")\n\t}\n\n}\n"
  },
  {
    "path": "packages/fetchai/connections/p2p_libp2p/libp2p_node/dht/dhtclient/options.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2019 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\n\npackage dhtclient\n\nimport (\n\tacn \"libp2p_node/acn\"\n\t\"libp2p_node/utils\"\n)\n\n// Option for dhtclient.New\ntype Option func(*DHTClient) error\n\n// IdentityFromFetchAIKey for dhtclient.New\nfunc IdentityFromFetchAIKey(key string) Option {\n\treturn func(dhtClient *DHTClient) error {\n\t\tvar err error\n\t\tdhtClient.key, dhtClient.publicKey, err = utils.KeyPairFromFetchAIKey(key)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t}\n}\n\n// RegisterAgentAddress for dhtclient.New\nfunc RegisterAgentAddress(record *acn.AgentRecord, isReady func() bool) Option {\n\treturn func(dhtClient *DHTClient) error {\n\t\tpbRecord := &acn.AgentRecord{}\n\t\tpbRecord.Address = record.Address\n\t\tpbRecord.PublicKey = record.PublicKey\n\t\tpbRecord.PeerPublicKey = record.PeerPublicKey\n\t\tpbRecord.Signature = record.Signature\n\t\tpbRecord.ServiceId = record.ServiceId\n\t\tpbRecord.LedgerId = record.LedgerId\n\n\t\tdhtClient.myAgentAddress = record.Address\n\t\tdhtClient.myAgentRecord = pbRecord\n\t\tdhtClient.myAgentReady = isReady\n\t\treturn nil\n\t}\n}\n\n// BootstrapFrom for dhtclient.New\nfunc BootstrapFrom(entryPeers []string) Option {\n\treturn func(dhtClient *DHTClient) error {\n\t\tvar err error\n\t\tdhtClient.bootstrapPeers, err = utils.GetPeersAddrInfo(entryPeers)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t}\n}\n"
  },
  {
    "path": "packages/fetchai/connections/p2p_libp2p/libp2p_node/dht/dhtnode/dhtnode.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2019 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\n\n// Package dhtnode (in progress) contains the common interface between dhtpeer and dhtclient\npackage dhtnode\n\nimport \"libp2p_node/aea\"\n\n// DHTNode libp2p node interface\ntype DHTNode interface {\n\tRouteEnvelope(*aea.Envelope) error\n\tProcessEnvelope(func(*aea.Envelope) error)\n\tMultiAddr() string\n\tPeerID() string\n\tClose() []error\n}\n"
  },
  {
    "path": "packages/fetchai/connections/p2p_libp2p/libp2p_node/dht/dhtnode/streams.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2019 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\n\npackage dhtnode\n\nconst (\n\tAeaNotifStream         = \"/aea-notif/0.1.0\"\n\tAeaAddressStream       = \"/aea-address/0.1.0\"\n\tAeaEnvelopeStream      = \"/aea/0.1.0\"\n\tAeaRegisterRelayStream = \"/aea-register/0.1.0\"\n)\n"
  },
  {
    "path": "packages/fetchai/connections/p2p_libp2p/libp2p_node/dht/dhtnode/utils.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2019 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\n\n// Package dhtnode contains the common interface between dhtpeer and dhtclient\n// TODO: extraction of shared functionality is work in progress\npackage dhtnode\n\nimport (\n\t\"errors\"\n\t\"strings\"\n\n\tacn \"libp2p_node/acn\"\n\tutils \"libp2p_node/utils\"\n)\n\nconst (\n\tDefaultLedger  = \"fetchai\"\n\tCurrentVersion = \"0.1.0\"\n)\n\nvar supportedLedgers = []string{\"fetchai\", \"cosmos\", \"ethereum\"}\n\nfunc IsValidProofOfRepresentation(\n\trecord *acn.AgentRecord,\n\tagentAddress string,\n\trepresentativePeerPubKey string,\n) (*acn.StatusBody, error) {\n\t// check agent address matches\n\tif record.Address != agentAddress {\n\t\terr := errors.New(\"Wrong agent address, expected \" + agentAddress)\n\t\tresponse := &acn.StatusBody{\n\t\t\tCode: acn.ERROR_WRONG_AGENT_ADDRESS,\n\t\t\tMsgs: []string{err.Error()},\n\t\t}\n\t\treturn response, err\n\t}\n\n\t// check if ledger is supported\n\tvar found = false\n\tfor _, supported := range supportedLedgers {\n\t\tif record.LedgerId == supported {\n\t\t\tfound = true\n\t\t\tbreak\n\t\t}\n\t}\n\tif !found {\n\t\terr := errors.New(\n\t\t\t\"Unsupported ledger \" + record.LedgerId + \", expected \" + strings.Join(\n\t\t\t\tsupportedLedgers,\n\t\t\t\t\",\",\n\t\t\t),\n\t\t)\n\t\tresponse := &acn.StatusBody{Code: acn.ERROR_UNSUPPORTED_LEDGER, Msgs: []string{err.Error()}}\n\t\treturn response, err\n\t}\n\n\t// check public key matches\n\tif record.PeerPublicKey != representativePeerPubKey {\n\t\terr := errors.New(\"Wrong peer public key, expected \" + representativePeerPubKey)\n\t\tresponse := &acn.StatusBody{Code: acn.ERROR_WRONG_PUBLIC_KEY, Msgs: []string{err.Error()}}\n\t\treturn response, err\n\t}\n\n\t// check that agent address and public key match\n\taddrFromPubKey, err := utils.AgentAddressFromPublicKey(record.LedgerId, record.PublicKey)\n\tif err != nil || addrFromPubKey != record.Address {\n\t\tif err == nil {\n\t\t\terr = errors.New(\"agent address and public key don't match\")\n\t\t}\n\t\tresponse := &acn.StatusBody{Code: acn.ERROR_WRONG_AGENT_ADDRESS}\n\t\treturn response, err\n\t}\n\n\t// check that signature is valid\n\tok, err := utils.VerifyLedgerSignature(\n\t\trecord.LedgerId,\n\t\t[]byte(record.PeerPublicKey),\n\t\trecord.Signature,\n\t\trecord.PublicKey,\n\t)\n\tif !ok || err != nil {\n\t\tif err == nil {\n\t\t\terr = errors.New(\"signature is not valid\")\n\t\t}\n\t\tresponse := &acn.StatusBody{Code: acn.ERROR_INVALID_PROOF}\n\t\treturn response, err\n\n\t}\n\n\t// PoR is valid\n\tresponse := &acn.StatusBody{Code: acn.SUCCESS}\n\treturn response, nil\n\n}\n"
  },
  {
    "path": "packages/fetchai/connections/p2p_libp2p/libp2p_node/dht/dhtpeer/benchmarks_test.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2019 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\n\npackage dhtpeer\n\nimport (\n\t\"bufio\"\n\t\"context\"\n\t\"flag\"\n\t\"net\"\n\t\"os\"\n\t\"testing\"\n\t\"time\"\n\n\t\"libp2p_node/acn\"\n\t\"libp2p_node/aea\"\n\t\"libp2p_node/utils\"\n\n\t\"github.com/rs/zerolog\"\n)\n\n/* **********\n* How to run\n* ***********\n\n\t$ go test -p 1 -count 20 libp2p_node/dht/dhtpeer/ -run=XXX  -bench .  -benchtime=20x -peers-keys-file=/path/to/file/benchmark_peers_keys.txt -agents-keys-file=/path/to/file/benchmark_agents_keys.txt\n\n*/\n\nvar peersKeysFilePath string\nvar agentsKeysFilePath string\nvar tcpUri = \"localhost:12345\"\n\nfunc init() {\n\tflag.StringVar(&peersKeysFilePath, \"peers-keys-file\", \"\", \"File with list of EC private keys\")\n\tflag.StringVar(\n\t\t&agentsKeysFilePath,\n\t\t\"agents-keys-file\",\n\t\t\"\",\n\t\t\"File with list of agents EC private keys\",\n\t)\n}\n\n/* **********************************\n * baseline TCP connection benchmark\n * ********************************** */\n\n// helpers\n\nfunc acceptAndEcho(server net.Listener) {\n\tfor {\n\t\tconn, err := server.Accept()\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\t\tgo func() {\n\t\t\tfor {\n\t\t\t\tbuf, err := utils.ReadBytesConn(conn)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\terr = utils.WriteBytesConn(conn, buf)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t}\n\t\t}()\n\t}\n}\n\nfunc connect(uri string, b *testing.B) net.Conn {\n\tconn, err := net.Dial(\"tcp\", uri)\n\tif err != nil {\n\t\tb.Fatal(err.Error())\n\t}\n\treturn conn\n\n}\nfunc sendAndReceive(conn net.Conn, buf []byte, b *testing.B) {\n\terr := utils.WriteBytesConn(conn, buf)\n\tif err != nil {\n\t\tb.Fatal(err.Error())\n\t}\n\t_, err = utils.ReadBytesConn(conn)\n\tif err != nil {\n\t\tb.Fatal(err.Error())\n\t}\n}\n\nfunc connectAndSend(buf []byte, b *testing.B) {\n\tconn := connect(tcpUri, b)\n\tsendAndReceive(conn, buf, b)\n\tconn.Close()\n}\n\n// benchs\n\nfunc BenchmarkBaselineTCPEcho(b *testing.B) {\n\n\ttcpServer, err := net.Listen(\"tcp\", tcpUri)\n\tif err != nil {\n\t\tb.Fatal(err.Error())\n\t}\n\tgo acceptAndEcho(tcpServer)\n\tbuf := make([]byte, 200)\n\tconn := connect(tcpUri, b)\n\n\tfor i := 0; i < b.N; i++ {\n\t\tsendAndReceive(conn, buf, b)\n\t}\n\tb.StopTimer()\n\ttcpServer.Close()\n\tb.StartTimer()\n\n}\n\nfunc BenchmarkBaselineTCPConnectAndEcho(b *testing.B) {\n\n\ttcpServer, err := net.Listen(\"tcp\", tcpUri)\n\tif err != nil {\n\t\tb.Fatal(err.Error())\n\t}\n\tgo acceptAndEcho(tcpServer)\n\tbuf := make([]byte, 200)\n\n\tfor i := 0; i < b.N; i++ {\n\t\t//var elapsed time.Duration\n\t\t//start := time.Now()\n\t\tb.ResetTimer()\n\t\tconnectAndSend(buf, b)\n\t\tb.StopTimer()\n\t\t//elapsed = time.Since(start)\n\t\t//fmt.Println(\"Elapsed \", elapsed.String())\n\t\tb.StartTimer()\n\t}\n\tb.StopTimer()\n\ttcpServer.Close()\n\tb.StartTimer()\n\n}\n\n/* **********************************\n * Peer DHT operations benchmark\n * ********************************** */\n\n// helpers\n\nfunc getKeysAndAddrs(b *testing.B) (peers []string, agents []string) {\n\tpeersKeysFile, err := os.Open(peersKeysFilePath)\n\tif err != nil {\n\t\tb.Fatal(err)\n\t}\n\tdefer peersKeysFile.Close()\n\tagentsKeysFile, err := os.Open(agentsKeysFilePath)\n\tif err != nil {\n\t\tb.Fatal(err)\n\t}\n\tdefer agentsKeysFile.Close()\n\n\tksc := bufio.NewScanner(peersKeysFile)\n\tasc := bufio.NewScanner(agentsKeysFile)\n\n\tpeers = []string{}\n\tagents = []string{}\n\tfor ksc.Scan() && asc.Scan() {\n\t\tpeers = append(peers, ksc.Text())\n\t\tagents = append(agents, asc.Text())\n\t}\n\treturn peers, agents\n}\n\nfunc setupLocalDHTPeerForBench(\n\tkey string,\n\tagentKey string,\n\tdhtPort uint16,\n\tdelegatePort uint16,\n\tentry []string,\n) (*DHTPeer, func(), error) {\n\t/*\n\t\tpeer, peerCleanup, err := SetupLocalDHTPeer(key, addr, dhtPort, delegatePort, entry)\n\t\tif err == nil {\n\t\t\tpeer.SetLogLevel(zerolog.Disabled)\n\t\t\tutils.SetLoggerLevel(zerolog.Disabled)\n\t\t}\n\t\treturn peer, peerCleanup, err\n\t*/\n\n\topts := []Option{\n\t\tLocalURI(DefaultLocalHost, dhtPort),\n\t\tPublicURI(DefaultLocalHost, dhtPort),\n\t\tIdentityFromFetchAIKey(key),\n\t\tEnableRelayService(),\n\t\tBootstrapFrom(entry),\n\t}\n\n\tif agentKey != \"\" {\n\t\tagentPubKey, err := utils.FetchAIPublicKeyFromFetchAIPrivateKey(agentKey)\n\t\tif err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\n\t\tagentAddress, err := utils.FetchAIAddressFromPublicKey(agentPubKey)\n\t\tif err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\n\t\tpeerPubKey, err := utils.FetchAIPublicKeyFromFetchAIPrivateKey(key)\n\t\tif err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\n\t\tsignature, err := utils.SignFetchAI([]byte(peerPubKey), agentKey)\n\t\tif err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\n\t\trecord := &acn.AgentRecord{}\n\t\trecord.Address = agentAddress\n\t\trecord.PublicKey = agentPubKey\n\t\trecord.PeerPublicKey = peerPubKey\n\t\trecord.Signature = signature\n\n\t\topts = append(opts, RegisterAgentAddress(record, func() bool { return true }))\n\t}\n\n\tif delegatePort != 0 {\n\t\topts = append(opts, EnableDelegateService(delegatePort))\n\t}\n\n\tdhtPeer, err := New(opts...)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tutils.SetLoggerLevel(zerolog.Disabled)\n\n\treturn dhtPeer, func() { dhtPeer.Close() }, nil\n}\n\nfunc deployPeers(number uint16, b *testing.B) ([]*DHTPeer, []string) {\n\tpeerKeys, agentsKeys := getKeysAndAddrs(b)\n\tpeers := make([]*DHTPeer, 0, number)\n\tfor i := uint16(0); i < number; i++ {\n\t\tentry := []string{}\n\t\tif i > 0 {\n\t\t\tentry = append(entry, peers[i-1].MultiAddr())\n\t\t}\n\t\tpeer, _, err := setupLocalDHTPeerForBench(\n\t\t\tpeerKeys[i], agentsKeys[i], DefaultLocalPort+i, 0,\n\t\t\tentry,\n\t\t)\n\t\tif err != nil {\n\t\t\tb.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t\t}\n\t\tpeers = append(peers, peer)\n\t}\n\treturn peers, agentsKeys\n}\n\nfunc closePeers(peers ...*DHTPeer) {\n\tfor _, peer := range peers {\n\t\tpeer.Close()\n\t}\n}\n\nfunc setupEchoServicePeers(peers ...*DHTPeer) {\n\tfor _, peer := range peers {\n\t\tpeer.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\t\terr := peer.RouteEnvelope(&aea.Envelope{\n\t\t\t\tTo:     envel.Sender,\n\t\t\t\tSender: envel.To,\n\t\t\t})\n\t\t\treturn err\n\t\t})\n\t}\n}\n\n// benchs\n\nfunc benchmarkAgentRegistration(npeers uint16, b *testing.B) {\n\tpeers, addrs := deployPeers(npeers, b)\n\tensureAddressAnnounced(peers...)\n\tdefer closePeers(peers...)\n\n\tpeer, peerCleanup, err := setupLocalDHTPeerForBench(\n\t\tFetchAITestKeys[1], \"\", DefaultLocalPort+npeers+1, 0,\n\t\t[]string{peers[0].MultiAddr()},\n\t)\n\tif err != nil {\n\t\tb.Fatal(err.Error())\n\t}\n\tdefer peerCleanup()\n\n\tfor i := 0; i < b.N; i++ {\n\t\tb.ResetTimer()\n\t\terr = peer.RegisterAgentAddress(addrs[len(addrs)-1-i%len(addrs)])\n\t\tif err != nil {\n\t\t\tb.Fail()\n\t\t}\n\t}\n}\n\nfunc benchmarkAgentLookup(npeers uint16, b *testing.B) {\n\tpeers, addrs := deployPeers(npeers, b)\n\tensureAddressAnnounced(peers...)\n\tdefer closePeers(peers...)\n\n\tpeer, peerCleanup, err := setupLocalDHTPeerForBench(\n\t\tFetchAITestKeys[1], AgentsTestKeys[1], DefaultLocalPort+npeers+1, 0,\n\t\t[]string{peers[len(peers)-1].MultiAddr()},\n\t)\n\tif err != nil {\n\t\tb.Fatal(err.Error())\n\t}\n\tdefer peerCleanup()\n\tensureAddressAnnounced(peer)\n\tctx, cancel_lookup := context.WithTimeout(context.Background(), 30*time.Second)\n\tdefer cancel_lookup()\n\n\tfor i := 0; i < b.N; i++ {\n\t\tb.ResetTimer()\n\t\t_, _, err = peer.lookupAddressDHT(ctx, addrs[len(peers)-1-i%len(peers)])\n\t\tif err != nil {\n\t\t\tb.Fail()\n\t\t}\n\t}\n}\n\nfunc benchmarkPeerJoin(npeers uint16, b *testing.B) {\n\tpeers, _ := deployPeers(npeers, b)\n\tensureAddressAnnounced(peers...)\n\tdefer closePeers(peers...)\n\n\tfor i := 0; i < b.N; i++ {\n\t\tb.ResetTimer()\n\t\tpeer, peerCleanup, err := setupLocalDHTPeerForBench(\n\t\t\tFetchAITestKeys[1], AgentsTestKeys[1], DefaultLocalPort+npeers+1, 0,\n\t\t\t[]string{peers[i%len(peers)].MultiAddr()},\n\t\t)\n\t\tif err != nil {\n\t\t\tb.Fatal(err.Error())\n\t\t}\n\t\tensureAddressAnnounced(peer)\n\t\tb.StopTimer()\n\t\tpeerCleanup()\n\t\tb.StartTimer()\n\t}\n}\n\nfunc benchmarkPeerEcho(npeers uint16, b *testing.B) {\n\tpeers, addrs := deployPeers(npeers, b)\n\tensureAddressAnnounced(peers...)\n\tdefer closePeers(peers...)\n\tsetupEchoServicePeers(peers...)\n\n\tpeer, peerCleanup, err := setupLocalDHTPeerForBench(\n\t\tFetchAITestKeys[1], AgentsTestKeys[1], DefaultLocalPort+npeers+1, 0,\n\t\t[]string{peers[len(peers)-1].MultiAddr()},\n\t)\n\tif err != nil {\n\t\tb.Fatal(err.Error())\n\t}\n\tdefer peerCleanup()\n\tensureAddressAnnounced(peer)\n\trxPeer := make(chan *aea.Envelope, 10)\n\tpeer.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxPeer <- envel\n\t\treturn nil\n\t})\n\n\tfor i := 0; i < b.N; i++ {\n\t\tenvel := &aea.Envelope{\n\t\t\tTo:      addrs[len(peers)-1-i%len(peers)],\n\t\t\tSender:  AgentsTestAddresses[1],\n\t\t\tMessage: make([]byte, 101),\n\t\t}\n\t\tb.ResetTimer()\n\t\terr = peer.RouteEnvelope(envel)\n\t\tif err != nil {\n\t\t\tb.Error(\"Failed to RouteEnvelope from peer 2 to peer 1:\", err)\n\t\t}\n\t\t<-rxPeer\n\t}\n}\n\nfunc BenchmarkAgentRegistration2(b *testing.B)   { benchmarkAgentRegistration(2, b) }\nfunc BenchmarkAgentRegistration8(b *testing.B)   { benchmarkAgentRegistration(8, b) }\nfunc BenchmarkAgentRegistration32(b *testing.B)  { benchmarkAgentRegistration(32, b) }\nfunc BenchmarkAgentRegistration128(b *testing.B) { benchmarkAgentRegistration(128, b) }\nfunc BenchmarkAgentRegistration256(b *testing.B) { benchmarkAgentRegistration(256, b) }\n\nfunc BenchmarkAgentLookup2(b *testing.B)   { benchmarkAgentLookup(2, b) }\nfunc BenchmarkAgentLookup8(b *testing.B)   { benchmarkAgentLookup(8, b) }\nfunc BenchmarkAgentLookup32(b *testing.B)  { benchmarkAgentLookup(32, b) }\nfunc BenchmarkAgentLookup128(b *testing.B) { benchmarkAgentLookup(128, b) }\nfunc BenchmarkAgentLookup256(b *testing.B) { benchmarkAgentLookup(256, b) }\n\nfunc BenchmarkPeerJoin2(b *testing.B)   { benchmarkPeerJoin(2, b) }\nfunc BenchmarkPeerJoin8(b *testing.B)   { benchmarkPeerJoin(8, b) }\nfunc BenchmarkPeerJoin32(b *testing.B)  { benchmarkPeerJoin(32, b) }\nfunc BenchmarkPeerJoin128(b *testing.B) { benchmarkPeerJoin(128, b) }\nfunc BenchmarkPeerJoin256(b *testing.B) { benchmarkPeerJoin(256, b) }\n\nfunc BenchmarkPeerEcho2(b *testing.B)   { benchmarkPeerEcho(2, b) }\nfunc BenchmarkPeerEcho8(b *testing.B)   { benchmarkPeerEcho(8, b) }\nfunc BenchmarkPeerEcho32(b *testing.B)  { benchmarkPeerEcho(32, b) }\nfunc BenchmarkPeerEcho128(b *testing.B) { benchmarkPeerEcho(128, b) }\nfunc BenchmarkPeerEcho256(b *testing.B) { benchmarkPeerEcho(256, b) }\n"
  },
  {
    "path": "packages/fetchai/connections/p2p_libp2p/libp2p_node/dht/dhtpeer/dhtpeer.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2019 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\n\n// Package dhtpeer provides an implementation of an Agent Communication Network node\n// using libp2p. It participates in data storage and routing for the network.\n// It offers RelayService for dhtclient and DelegateService for tcp clients.\npackage dhtpeer\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"context\"\n\t\"crypto/ecdsa\"\n\t\"crypto/elliptic\"\n\t\"crypto/rand\"\n\t\"crypto/tls\"\n\t\"crypto/x509\"\n\t\"crypto/x509/pkix\"\n\t\"encoding/binary\"\n\t\"encoding/pem\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"math/big\"\n\t\"net\"\n\t\"os\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/btcsuite/btcd/btcec\"\n\t\"github.com/pkg/errors\"\n\n\t\"github.com/rs/zerolog\"\n\t\"google.golang.org/protobuf/proto\"\n\n\tlibp2p \"github.com/libp2p/go-libp2p\"\n\tcryptop2p \"github.com/libp2p/go-libp2p-core/crypto\"\n\t\"github.com/libp2p/go-libp2p-core/network\"\n\t\"github.com/libp2p/go-libp2p-core/peer\"\n\t\"github.com/libp2p/go-libp2p-core/peerstore\"\n\t\"github.com/multiformats/go-multiaddr\"\n\n\tcircuit \"github.com/libp2p/go-libp2p-circuit\"\n\tkaddht \"github.com/libp2p/go-libp2p-kad-dht\"\n\troutedhost \"github.com/libp2p/go-libp2p/p2p/host/routed\"\n\n\tacn \"libp2p_node/acn\"\n\taea \"libp2p_node/aea\"\n\tcommon \"libp2p_node/dht/common\"\n\t\"libp2p_node/dht/dhtnode\"\n\tmonitoring \"libp2p_node/dht/monitoring\"\n\tutils \"libp2p_node/utils\"\n)\n\nconst AcnStatusTimeout = 5.0 * time.Second\nconst AcnStatusesQueueSize = 1000\nconst SlowQueueSize = 100\n\n// panics if err is not nil\nfunc check(err error) {\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\nfunc ignore(err error) {\n\tif err != nil {\n\t\tlog.Println(\"IGNORED\", err)\n\t}\n}\n\nconst (\n\taddressLookupTimeout                 = 20 * time.Second\n\ttimeoutBeforeMovingToSlowQueue       = 3 * time.Second\n\troutingTableConnectionUpdateTimeout  = 5 * time.Second\n\tnewStreamTimeout                     = 10 * time.Second\n\taddressRegisterTimeout               = 3 * time.Second\n\taddressRegistrationDelay             = 0 * time.Second\n\tmonitoringNamespace                  = \"acn\"\n\tmetricDHTOpLatencyStore              = \"dht_op_latency_store\"\n\tmetricDHTOpLatencyLookup             = \"dht_op_latency_lookup\"\n\tmetricOpLatencyRegister              = \"op_latency_register\"\n\tmetricOpLatencyRoute                 = \"op_latency_route\"\n\tmetricOpRouteCount                   = \"op_route_count\"\n\tmetricOpRouteCountAll                = \"op_route_count_all\"\n\tmetricOpRouteCountSuccess            = \"op_route_count_success\"\n\tmetricServiceDelegateClientsCount    = \"service_delegate_clients_count\"\n\tmetricServiceDelegateClientsCountAll = \"service_delegate_clients_count_all\"\n\tmetricServiceRelayClientsCount       = \"service_relay_clients_count\"\n\tmetricServiceRelayClientsCountAll    = \"service_relay_clients_count_all\"\n\tdefaultPersistentStoragePath         = \"./agent_records_store\"\n)\n\nvar (\n\t//latencyBucketsMilliSeconds = []float64{1., 10., 20., 50., 100., 200., 500., 1000.}\n\tlatencyBucketsMicroSeconds = []float64{100., 500., 1e3, 1e4, 1e5, 5e5, 1e6}\n)\n\n// DHTPeer A full libp2p node for the Agents Communication Network.\n// It is required to have a local address and a public one\n// and can acts as a relay for `DHTClient`.\n// Optionally, it provides delegate service for tcp clients.\ntype DHTPeer struct {\n\thost           string\n\tport           uint16\n\tpublicHost     string\n\tpublicPort     uint16\n\tdelegatePort   uint16\n\tmonitoringPort uint16\n\tenableRelay    bool\n\n\tmailboxHostPort string\n\tmailboxServer   *MailboxServer\n\n\tregistrationDelay time.Duration\n\n\tkey             cryptop2p.PrivKey\n\tpublicKey       cryptop2p.PubKey\n\tlocalMultiaddr  multiaddr.Multiaddr\n\tpublicMultiaddr multiaddr.Multiaddr\n\tbootstrapPeers  []peer.AddrInfo\n\n\tdht          *kaddht.IpfsDHT\n\troutedHost   *routedhost.RoutedHost\n\ttcpListener  net.Listener\n\tcert         *tls.Certificate\n\tsslSignature []byte\n\n\taddressAnnouncedMap     map[string]bool\n\taddressAnnouncedMapLock sync.RWMutex\n\n\t// flag to announce addresses over network if peer connected to other peers\n\tenableAddressAnnouncement     bool\n\tenableAddressAnnouncementWg   *sync.WaitGroup\n\tenableAddressAnnouncementLock sync.RWMutex\n\n\tmyAgentAddress   string\n\tmyAgentRecord    *acn.AgentRecord\n\tmyAgentReady     func() bool\n\tdhtAddresses     map[string]string\n\tacnStatuses      map[string]chan *acn.StatusBody\n\ttcpAddresses     map[string]net.Conn\n\tagentRecords     map[string]*acn.AgentRecord\n\tacnStatusesLock  sync.RWMutex\n\tdhtAddressesLock sync.RWMutex\n\ttcpAddressesLock sync.RWMutex\n\tagentRecordsLock sync.RWMutex\n\n\t// TOFIX(LR): maps and locks need refactoring for better abstraction\n\tprocessEnvelope func(*aea.Envelope) error\n\n\tpersistentStoragePath string\n\tstorage               *os.File\n\n\tmonitor    monitoring.MonitoringService\n\tclosing    chan struct{}\n\tisClosing  bool\n\tgoroutines *sync.WaitGroup\n\tlogger     zerolog.Logger\n\n\t// syncMessages map[string]*sync.WaitGroup\n\tsyncMessagesLock sync.RWMutex\n\tsyncMessages     map[string](chan *aea.Envelope)\n\n\tslow_queue chan *aea.Envelope\n}\n\n// New creates a new DHTPeer\nfunc New(opts ...Option) (*DHTPeer, error) {\n\tvar err error\n\tdhtPeer := &DHTPeer{registrationDelay: addressRegistrationDelay, isClosing: false}\n\n\tdhtPeer.dhtAddresses = map[string]string{}\n\tdhtPeer.tcpAddresses = map[string]net.Conn{}\n\tdhtPeer.agentRecords = map[string]*acn.AgentRecord{}\n\tdhtPeer.acnStatuses = map[string]chan *acn.StatusBody{}\n\tdhtPeer.dhtAddressesLock = sync.RWMutex{}\n\tdhtPeer.tcpAddressesLock = sync.RWMutex{}\n\tdhtPeer.agentRecordsLock = sync.RWMutex{}\n\tdhtPeer.persistentStoragePath = defaultPersistentStoragePath\n\tdhtPeer.syncMessages = make(map[string](chan *aea.Envelope))\n\tdhtPeer.addressAnnouncedMap = map[string]bool{}\n\tdhtPeer.addressAnnouncedMapLock = sync.RWMutex{}\n\tdhtPeer.enableAddressAnnouncementWg = &sync.WaitGroup{}\n\tdhtPeer.enableAddressAnnouncementLock = sync.RWMutex{}\n\tdhtPeer.mailboxHostPort = \"\"\n\n\tdhtPeer.slow_queue = make(chan *aea.Envelope, SlowQueueSize)\n\n\tfor _, opt := range opts {\n\t\tif err := opt(dhtPeer); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\tdhtPeer.closing = make(chan struct{})\n\tdhtPeer.goroutines = &sync.WaitGroup{}\n\n\t/* check correct configuration */\n\n\t// private key\n\tif dhtPeer.key == nil {\n\t\treturn nil, errors.New(\"private key must be provided\")\n\t}\n\n\t// local uri\n\tif dhtPeer.localMultiaddr == nil {\n\t\treturn nil, errors.New(\"local host and port must be set\")\n\t}\n\n\t// public uri\n\tif dhtPeer.publicMultiaddr == nil {\n\t\treturn nil, errors.New(\"public host and port must be set\")\n\t}\n\n\t// check if the PoR is delivered for my public  key\n\tif dhtPeer.myAgentRecord != nil {\n\t\tmyPublicKey, err := utils.FetchAIPublicKeyFromPubKey(dhtPeer.publicKey)\n\t\tstatus, errPoR := dhtnode.IsValidProofOfRepresentation(\n\t\t\tdhtPeer.myAgentRecord, dhtPeer.myAgentRecord.Address, myPublicKey,\n\t\t)\n\t\tif err != nil || errPoR != nil || status.Code != acn.SUCCESS {\n\t\t\terrMsg := \"Invalid AgentRecord\"\n\t\t\tif err == nil {\n\t\t\t\terr = errors.New(errMsg)\n\t\t\t} else {\n\t\t\t\terr = errors.Wrap(err, errMsg)\n\t\t\t}\n\t\t\tif errPoR != nil {\n\t\t\t\terr = errors.Wrap(err, errPoR.Error())\n\t\t\t}\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\t/* setup libp2p node */\n\tctx := context.Background()\n\n\t// setup public uri as external address\n\taddressFactory := func(addrs []multiaddr.Multiaddr) []multiaddr.Multiaddr {\n\t\treturn []multiaddr.Multiaddr{dhtPeer.publicMultiaddr}\n\t}\n\n\t// libp2p options\n\tlibp2pOpts := []libp2p.Option{\n\t\tlibp2p.ListenAddrs(dhtPeer.localMultiaddr),\n\t\tlibp2p.AddrsFactory(addressFactory),\n\t\tlibp2p.Identity(dhtPeer.key),\n\t\tlibp2p.DefaultTransports,\n\t\tlibp2p.DefaultMuxers,\n\t\tlibp2p.DefaultSecurity,\n\t\tlibp2p.NATPortMap(),\n\t\tlibp2p.EnableNATService(),\n\t\tlibp2p.EnableRelay(circuit.OptHop),\n\t}\n\n\t// create a basic host\n\tbasicHost, err := libp2p.New(ctx, libp2pOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// create the dht\n\tdhtPeer.dht, err = kaddht.New(ctx, basicHost, kaddht.Mode(kaddht.ModeServer))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\terr = dhtPeer.makeSSLCertifiateAndSignature()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t// make the routed host\n\tdhtPeer.routedHost = routedhost.Wrap(basicHost, dhtPeer.dht)\n\tdhtPeer.setupLogger()\n\n\tlerror, _, linfo, ldebug := dhtPeer.GetLoggers()\n\n\tbasicHost.Network().Notify(&Notifee{\n\t\tlogger: dhtPeer.logger,\n\t})\n\n\t// connect to the booststrap nodes\n\tif len(dhtPeer.bootstrapPeers) > 0 {\n\t\tlinfo().Msgf(\"Bootstrapping from %s\", dhtPeer.bootstrapPeers)\n\t\terr = utils.BootstrapConnect(ctx, dhtPeer.routedHost, dhtPeer.dht, dhtPeer.bootstrapPeers)\n\t\tif err != nil {\n\t\t\tdhtPeer.Close()\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\t// bootstrap the dht\n\terr = dhtPeer.dht.Bootstrap(ctx)\n\tif err != nil {\n\t\tdhtPeer.Close()\n\t\treturn nil, err\n\t}\n\n\tlinfo().Msgf(\"My Peer ID is %s\", dhtPeer.PeerID())\n\n\tlinfo().Msg(\"successfully created libp2p node!\")\n\n\t/* setup DHTPeer message handlers and services */\n\n\t// setup monitoring\n\tdhtPeer.setupMonitoring()\n\n\t// relay service\n\tif dhtPeer.enableRelay {\n\t\t// Allow clients to register their agents addresses\n\t\tldebug().Msg(\"Setting /aea-register/0.1.0 stream...\")\n\t\tdhtPeer.routedHost.SetStreamHandler(dhtnode.AeaRegisterRelayStream,\n\t\t\tdhtPeer.handleAeaRegisterStream)\n\t}\n\n\t// new peers connection notification, so that this peer can register its addresses\n\tdhtPeer.routedHost.SetStreamHandler(dhtnode.AeaNotifStream,\n\t\tdhtPeer.handleAeaNotifStream)\n\n\t// Notify bootstrap peers if any\n\tfor _, bPeer := range dhtPeer.bootstrapPeers {\n\t\tctx := context.Background()\n\t\ts, err := dhtPeer.routedHost.NewStream(ctx, bPeer.ID, dhtnode.AeaNotifStream)\n\t\tif err != nil {\n\t\t\tlerror(err).Msgf(\"failed to open stream to notify bootstrap peer %s\", bPeer.ID)\n\t\t\tdhtPeer.Close()\n\t\t\treturn nil, err\n\t\t}\n\t\t_, err = s.Write([]byte(dhtnode.AeaNotifStream))\n\t\tif err != nil {\n\t\t\tlerror(err).Msgf(\"failed to notify bootstrap peer %s\", bPeer.ID)\n\t\t\tdhtPeer.Close()\n\t\t\treturn nil, err\n\t\t}\n\t\ts.Close()\n\t}\n\n\t// initialize agents records persistent storage\n\tif dhtPeer.persistentStoragePath == defaultPersistentStoragePath {\n\t\tmyPeerID, err := peer.IDFromPublicKey(dhtPeer.publicKey)\n\t\tignore(err)\n\t\tdhtPeer.persistentStoragePath += \"_\" + myPeerID.Pretty()\n\t}\n\tnbr, err := dhtPeer.initAgentRecordPersistentStorage()\n\tif err != nil {\n\t\treturn nil, errors.Wrap(err, \"while initializing agent record storage\")\n\t}\n\tif len(dhtPeer.bootstrapPeers) > 0 {\n\t\tfor addr := range dhtPeer.dhtAddresses {\n\t\t\terr := dhtPeer.RegisterAgentAddress(addr)\n\t\t\tif err != nil {\n\t\t\t\tlerror(err).Str(\"addr\", addr).\n\t\t\t\t\tMsg(\"while announcing stored client address\")\n\t\t\t}\n\t\t}\n\t}\n\tlinfo().Msgf(\"successfully loaded %d agents\", nbr)\n\n\t// if peer is joining an existing network, announce my agent address if set\n\tif len(dhtPeer.bootstrapPeers) > 0 {\n\t\t// there are some bootstrap peers so we can announce addresses to them\n\t\tdhtPeer.enableAddressAnnouncement = true\n\n\t\tif dhtPeer.myAgentAddress != \"\" && !dhtPeer.IsAddressAnnounced(dhtPeer.myAgentAddress) {\n\t\t\tldebug().Msg(\"Address was announced on bootstrap peers\")\n\t\t\topLatencyRegister, _ := dhtPeer.monitor.GetHistogram(metricOpLatencyRegister)\n\t\t\ttimer := dhtPeer.monitor.Timer()\n\t\t\tstart := timer.NewTimer()\n\t\t\terr := dhtPeer.RegisterAgentAddress(dhtPeer.myAgentAddress)\n\t\t\tif err != nil {\n\t\t\t\tdhtPeer.Close()\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tduration := timer.GetTimer(start)\n\t\t\topLatencyRegister.Observe(float64(duration.Microseconds()))\n\t\t}\n\t}\n\n\t// aea addresses lookup\n\tldebug().Msg(\"Setting /aea-address/0.1.0 stream...\")\n\tdhtPeer.routedHost.SetStreamHandler(dhtnode.AeaAddressStream, dhtPeer.handleAeaAddressStream)\n\n\t// incoming envelopes stream\n\tldebug().Msg(\"Setting /aea/0.1.0 stream...\")\n\tdhtPeer.routedHost.SetStreamHandler(dhtnode.AeaEnvelopeStream, dhtPeer.handleAeaEnvelopeStream)\n\n\t// setup delegate service\n\tif dhtPeer.delegatePort != 0 {\n\t\tdhtPeer.launchDelegateService()\n\n\t\tready := &sync.WaitGroup{}\n\t\tdhtPeer.goroutines.Add(1)\n\t\tready.Add(1)\n\t\tgo dhtPeer.handleDelegateService(ready)\n\t\tready.Wait()\n\t}\n\n\t// check mailbox uri is set\n\tif len(dhtPeer.mailboxHostPort) != 0 {\n\t\tdhtPeer.launchMailboxService()\n\t}\n\n\t// start monitoring\n\tready := &sync.WaitGroup{}\n\tready.Add(1)\n\tgo dhtPeer.startMonitoring(ready)\n\tready.Wait()\n\tgo dhtPeer.slowEnvelopeSendLoop()\n\treturn dhtPeer, nil\n}\n\n// saveAgentRecordToPersistentStorage saves the agent record to persistent storage\nfunc (dhtPeer *DHTPeer) saveAgentRecordToPersistentStorage(record *acn.AgentRecord) error {\n\tmsg := formatPersistentStorageLine(record)\n\tif len(msg) == 0 {\n\t\treturn errors.New(\"while formating record \" + record.String())\n\t}\n\n\tsize := uint32(len(msg))\n\tbuf := make([]byte, 4)\n\tbinary.BigEndian.PutUint32(buf, size)\n\n\tbuf = append(buf, msg...)\n\t_, err := dhtPeer.storage.Write(buf)\n\tif err != nil {\n\t\treturn errors.Wrap(err, \"while writing record to persistent storage\")\n\t}\n\treturn nil\n}\n\nfunc parsePersistentStorageLine(line []byte) (*acn.AgentRecord, error) {\n\trecord := &acn.AgentRecord{}\n\terr := proto.Unmarshal(line, record)\n\treturn record, err\n}\n\nfunc formatPersistentStorageLine(record *acn.AgentRecord) []byte {\n\tmsg, err := proto.Marshal(record)\n\tignore(err)\n\treturn msg\n}\n\n// initAgentRecordPersistentStorage loads agent records from persistent storage\nfunc (dhtPeer *DHTPeer) initAgentRecordPersistentStorage() (int, error) {\n\tvar err error\n\t_, _, linfo, _ := dhtPeer.GetLoggers()\n\tlinfo().Msg(\"Load records from store \" + dhtPeer.persistentStoragePath)\n\tdhtPeer.storage, err = os.OpenFile(\n\t\tdhtPeer.persistentStoragePath,\n\t\tos.O_APPEND|os.O_RDWR|os.O_CREATE,\n\t\t0600,\n\t)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\treader := bufio.NewReader(dhtPeer.storage)\n\tvar counter int = 0\n\tfor {\n\t\tbuf := make([]byte, 4)\n\t\t_, err = io.ReadFull(reader, buf)\n\t\tif err == io.EOF {\n\t\t\tbreak\n\t\t}\n\t\tif err != nil {\n\t\t\treturn 0, errors.Wrap(err, \"while loading agent records\")\n\t\t}\n\n\t\tsize := binary.BigEndian.Uint32(buf)\n\t\tline := make([]byte, size)\n\t\t_, err = io.ReadFull(reader, line)\n\t\tif err != nil {\n\t\t\treturn 0, errors.Wrap(err, \"while loading agent records\")\n\t\t}\n\n\t\trecord, err := parsePersistentStorageLine(line)\n\t\tif err != nil {\n\t\t\treturn 0, errors.Wrap(err, \"while loading agent records\")\n\t\t}\n\t\tdhtPeer.agentRecords[record.Address] = record\n\t\trelayPeerID, err := utils.IDFromFetchAIPublicKey(record.PeerPublicKey)\n\t\tif err != nil {\n\t\t\treturn 0, errors.Wrap(err, \"While loading agent records\")\n\t\t}\n\t\tdhtPeer.dhtAddresses[record.Address] = relayPeerID.Pretty()\n\t\tcounter++\n\t}\n\n\treturn counter, nil\n}\n\nfunc (dhtPeer *DHTPeer) closeAgentRecordPersistentStorage() error {\n\tdhtPeer.agentRecordsLock.Lock()\n\terr := dhtPeer.storage.Close()\n\tdhtPeer.agentRecordsLock.Unlock()\n\treturn err\n}\n\nfunc (dhtPeer *DHTPeer) setupMonitoring() {\n\tif dhtPeer.monitoringPort != 0 {\n\t\tdhtPeer.monitor = monitoring.NewPrometheusMonitoring(\n\t\t\tmonitoringNamespace,\n\t\t\tdhtPeer.monitoringPort,\n\t\t)\n\t} else {\n\t\tdhtPeer.monitor = monitoring.NewFileMonitoring(monitoringNamespace, false)\n\t}\n\n\tdhtPeer.addMonitoringMetrics()\n}\n\nfunc (dhtPeer *DHTPeer) startMonitoring(ready *sync.WaitGroup) {\n\t_, _, linfo, _ := dhtPeer.GetLoggers()\n\tlinfo().Msg(\"Starting monitoring service: \" + dhtPeer.monitor.Info())\n\tgo dhtPeer.monitor.Start()\n\tready.Done()\n}\n\nfunc (dhtPeer *DHTPeer) addMonitoringMetrics() {\n\tbuckets := latencyBucketsMicroSeconds\n\tvar err error\n\t// acn primitives\n\t_, err = dhtPeer.monitor.NewHistogram(metricDHTOpLatencyStore,\n\t\t\"Histogram for time to store a key in the DHT\", buckets)\n\tignore(err)\n\t_, err = dhtPeer.monitor.NewHistogram(metricDHTOpLatencyLookup,\n\t\t\"Histogram for time to find a key in the DHT\", buckets)\n\tignore(err)\n\t// acn main service\n\t_, err = dhtPeer.monitor.NewHistogram(metricOpLatencyRegister,\n\t\t\"Histogram for end-to-end time to register an agent in the acn\", buckets)\n\tignore(err)\n\t_, err = dhtPeer.monitor.NewHistogram(\n\t\tmetricOpLatencyRoute,\n\t\t\"Histogram for end-to-end time to route an envelope to its destination, excluding time to send envelope itself\",\n\t\tbuckets,\n\t)\n\tignore(err)\n\t_, err = dhtPeer.monitor.NewGauge(metricOpRouteCount,\n\t\t\"Number of ongoing envelope routing requests\")\n\tignore(err)\n\t_, err = dhtPeer.monitor.NewCounter(metricOpRouteCountAll,\n\t\t\"Total number envelope routing requests, successful or not\")\n\tignore(err)\n\t_, err = dhtPeer.monitor.NewCounter(metricOpRouteCountSuccess,\n\t\t\"Total number envelope routed successfully\")\n\tignore(err)\n\t// acn delegate service\n\t_, err = dhtPeer.monitor.NewGauge(metricServiceDelegateClientsCount,\n\t\t\"Number of active delagate connections\")\n\tignore(err)\n\t_, err = dhtPeer.monitor.NewCounter(metricServiceDelegateClientsCountAll,\n\t\t\"Number of all delagate clients, connected or disconnected\")\n\tignore(err)\n\t// acn relay service\n\t_, err = dhtPeer.monitor.NewGauge(metricServiceRelayClientsCount,\n\t\t\"Number of active relay clients\")\n\tignore(err)\n\t_, err = dhtPeer.monitor.NewCounter(metricServiceRelayClientsCountAll,\n\t\t\"Total number of all relayed clients, connected or disconnected\")\n\tignore(err)\n}\n\nfunc (dhtPeer *DHTPeer) setupLogger() {\n\tfields := map[string]string{\n\t\t\"package\": \"DHTPeer\",\n\t}\n\tif dhtPeer.routedHost != nil {\n\t\tfields[\"peerid\"] = dhtPeer.routedHost.ID().Pretty()\n\t}\n\tdhtPeer.logger = utils.NewDefaultLoggerWithFields(fields)\n}\n\nfunc (dhtPeer *DHTPeer) PeerID() string {\n\treturn dhtPeer.routedHost.ID().Pretty()\n}\n\nfunc (dhtPeer *DHTPeer) GetLoggers() (func(error) *zerolog.Event, func() *zerolog.Event, func() *zerolog.Event, func() *zerolog.Event) {\n\tldebug := dhtPeer.logger.Debug\n\tlinfo := dhtPeer.logger.Info\n\tlwarn := dhtPeer.logger.Warn\n\tlerror := func(err error) *zerolog.Event {\n\t\tif err == nil {\n\t\t\treturn dhtPeer.logger.Error().Str(\"err\", \"nil\")\n\t\t}\n\t\treturn dhtPeer.logger.Error().Str(\"err\", err.Error())\n\t}\n\n\treturn lerror, lwarn, linfo, ldebug\n}\n\n// SetLogLevel set utils logger level\nfunc (dhtPeer *DHTPeer) SetLogLevel(lvl zerolog.Level) {\n\tdhtPeer.logger = dhtPeer.logger.Level(lvl)\n}\n\n// Close stops the DHTPeer\nfunc (dhtPeer *DHTPeer) Close() []error {\n\tvar err error\n\tvar status []error\n\n\t_, _, linfo, _ := dhtPeer.GetLoggers()\n\n\tlinfo().Msg(\"Stopping DHTPeer...\")\n\tclose(dhtPeer.closing)\n\tdhtPeer.isClosing = true\n\n\t//return status\n\n\terrappend := func(err error) {\n\t\tif err != nil {\n\t\t\tstatus = append(status, err)\n\t\t}\n\t}\n\n\tif dhtPeer.tcpListener != nil {\n\t\terr = dhtPeer.tcpListener.Close()\n\t\terrappend(err)\n\t\tdhtPeer.tcpAddressesLock.Lock()\n\t\tfor _, conn := range dhtPeer.tcpAddresses {\n\t\t\terr = conn.Close()\n\t\t\terrappend(err)\n\t\t}\n\t\tdhtPeer.tcpAddressesLock.Unlock()\n\t}\n\n\tif dhtPeer.mailboxServer != nil {\n\t\tdhtPeer.mailboxServer.stop()\n\t}\n\n\terr = dhtPeer.dht.Close()\n\terrappend(err)\n\terr = dhtPeer.routedHost.Close()\n\terrappend(err)\n\n\terr = dhtPeer.closeAgentRecordPersistentStorage()\n\terrappend(err)\n\n\t//linfo().Msg(\"Stopping DHTPeer: waiting for goroutines to cancel...\")\n\t// dhtPeer.goroutines.Wait()\n\tdhtPeer.syncMessagesLock.Lock()\n\tfor _, channel := range dhtPeer.syncMessages {\n\t\tclose(channel)\n\t}\n\tdhtPeer.syncMessagesLock.Unlock()\n\tclose(dhtPeer.slow_queue)\n\n\treturn status\n}\n\n// Generate selfsigned c509 certificate with temprorary key to be used with TLS server\n// We can not use peer private key cause it does not supported by golang TLS implementation\n// So we generate a new one and send session public key signature made with peer private key\n// snd client can validate it with peer public key/address\nfunc generate_x509_cert() (*tls.Certificate, error) {\n\tprivBtcKey, err := btcec.NewPrivateKey(elliptic.P256())\n\tif err != nil {\n\t\treturn nil, errors.Wrap(err, \"while creating new private key\")\n\t}\n\tprivKey := privBtcKey.ToECDSA()\n\tpubKey := &privKey.PublicKey\n\n\tca := &x509.Certificate{\n\t\tSerialNumber: big.NewInt(1),\n\t\tSubject: pkix.Name{\n\t\t\tOrganization: []string{\"Acn Node\"},\n\t\t},\n\t\tNotBefore: time.Now(),\n\t\tNotAfter:  time.Now().AddDate(1, 0, 0),\n\n\t\tKeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,\n\t\tExtKeyUsage: []x509.ExtKeyUsage{\n\t\t\tx509.ExtKeyUsageClientAuth,\n\t\t\tx509.ExtKeyUsageServerAuth,\n\t\t},\n\t\tBasicConstraintsValid: true,\n\t}\n\tca.IsCA = true\n\tca.KeyUsage |= x509.KeyUsageCertSign\n\n\tcertBytes, err := x509.CreateCertificate(rand.Reader, ca, ca, pubKey, privKey)\n\tif err != nil {\n\t\treturn nil, errors.Wrap(err, \"while creating ca\")\n\t}\n\tcertPEM := new(bytes.Buffer)\n\terr = pem.Encode(certPEM, &pem.Block{\n\t\tType:  \"CERTIFICATE\",\n\t\tBytes: certBytes,\n\t})\n\tif err != nil {\n\t\treturn nil, errors.Wrap(err, \"while encoding cert pem\")\n\t}\n\n\tprivPEM := new(bytes.Buffer)\n\tb, err := x509.MarshalECPrivateKey(privKey)\n\tif err != nil {\n\t\treturn nil, errors.Wrap(err, \"while marshaling ec private key\")\n\t}\n\terr = pem.Encode(privPEM, &pem.Block{\n\t\tType:  \"EC PRIVATE KEY\",\n\t\tBytes: b,\n\t})\n\tif err != nil {\n\t\treturn nil, errors.Wrap(err, \"while encoding prive pem\")\n\t}\n\n\tcert, err := tls.X509KeyPair(certPEM.Bytes(), privPEM.Bytes())\n\treturn &cert, err\n}\n\n// launchDelegateService launches the delegate service on the configured uri\nfunc (dhtPeer *DHTPeer) launchDelegateService() {\n\tvar err error\n\n\tlerror, _, _, _ := dhtPeer.GetLoggers()\n\tconfig := &tls.Config{Certificates: []tls.Certificate{*dhtPeer.cert}}\n\turi := dhtPeer.host + \":\" + strconv.FormatInt(int64(dhtPeer.delegatePort), 10)\n\tlistener, err := tls.Listen(\"tcp\", uri, config)\n\n\tif err != nil {\n\t\tlerror(err).Msgf(\"while setting up listening tcp socket %s\", uri)\n\t\tcheck(err)\n\t}\n\n\tif err != nil {\n\t\tlerror(err).Msgf(\"while generating tls signature\")\n\t\tcheck(err)\n\t}\n\tdhtPeer.tcpListener = TLSListener{Listener: listener, Signature: dhtPeer.sslSignature}\n}\n\n// launchDelegateService launches the delegate service on the configured uri\nfunc (dhtPeer *DHTPeer) makeSSLCertifiateAndSignature() error {\n\tvar err error\n\n\tlerror, _, _, _ := dhtPeer.GetLoggers()\n\tdhtPeer.cert, err = generate_x509_cert()\n\tif err != nil {\n\t\tlerror(err).Msgf(\"while generating tls certificate\")\n\t\treturn err\n\t}\n\tdhtPeer.sslSignature, err = makeSessionKeySignature(dhtPeer.cert, dhtPeer.key)\n\tif err != nil {\n\t\tlerror(err).Msgf(\"while generating tls certificate server signature\")\n\t\treturn err\n\t}\n\treturn nil\n}\n\n// launchMailboxService launches the mailbox http service on the configured uri\nfunc (dhtPeer *DHTPeer) launchMailboxService() {\n\t_, _, linfo, _ := dhtPeer.GetLoggers()\n\tif len(dhtPeer.mailboxHostPort) == 0 {\n\t\treturn\n\t}\n\tdhtPeer.mailboxServer = &MailboxServer{\n\t\taddr:    dhtPeer.mailboxHostPort,\n\t\tdhtPeer: dhtPeer,\n\t}\n\tlinfo().Msgf(\"Starting mailbox service on %s\", dhtPeer.mailboxHostPort)\n\tgo dhtPeer.mailboxServer.start()\n}\n\n// Make signature for session public key using peer private key\nfunc makeSessionKeySignature(cert *tls.Certificate, privateKey cryptop2p.PrivKey) ([]byte, error) {\n\tcert_pub_key := cert.PrivateKey.(*ecdsa.PrivateKey).Public().(*ecdsa.PublicKey)\n\tcert_pub_key_bytes := elliptic.Marshal(cert_pub_key.Curve, cert_pub_key.X, cert_pub_key.Y)\n\tsignature, err := privateKey.Sign(cert_pub_key_bytes)\n\treturn signature, err\n}\n\n// handleDelegateService listens for new connections to delegate service and handles them\nfunc (dhtPeer *DHTPeer) handleDelegateService(ready *sync.WaitGroup) {\n\tdefer dhtPeer.goroutines.Done()\n\tdefer dhtPeer.tcpListener.Close()\n\n\tlerror, _, linfo, _ := dhtPeer.GetLoggers()\n\n\tdone := false\nL:\n\tfor {\n\t\tselect {\n\t\tdefault:\n\t\t\tlinfo().Msg(\"DelegateService listening for new connections...\")\n\t\t\tif !done {\n\t\t\t\tdone = true\n\t\t\t\tready.Done()\n\t\t\t}\n\t\t\tconn, err := dhtPeer.tcpListener.Accept()\n\t\t\tif err != nil {\n\t\t\t\tif strings.Contains(err.Error(), \"use of closed network connection\") {\n\t\t\t\t\t// About using string comparison to get the type of err,\n\t\t\t\t\t// check https://github.com/golang/go/issues/4373\n\t\t\t\t\tlinfo().Msg(\"DelegateService Stopped.\")\n\t\t\t\t} else {\n\t\t\t\t\tlerror(err).Msgf(\"while accepting a new connection\")\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tdhtPeer.goroutines.Add(1)\n\t\t\t\tgo dhtPeer.handleNewDelegationConnection(conn)\n\t\t\t}\n\t\tcase <-dhtPeer.closing:\n\t\t\tbreak L\n\t\t}\n\t}\n}\n\nfunc (dhtPeer *DHTPeer) CheckPOR(record *acn.AgentRecord) (*acn.StatusBody, error) {\n\taddr := record.Address\n\tmyPubKey, err := utils.FetchAIPublicKeyFromPubKey(dhtPeer.publicKey)\n\tignore(err)\n\tstatus, err := dhtnode.IsValidProofOfRepresentation(record, addr, myPubKey)\n\treturn status, err\n}\n\n// handleNewDelegationConnection handles a new delegate connection\n// verifies agent record and registers agent in DHT, handles incoming envelopes\n// and forwards them for processing\nfunc (dhtPeer *DHTPeer) handleNewDelegationConnection(conn net.Conn) {\n\tdefer dhtPeer.goroutines.Done()\n\tdefer conn.Close()\n\n\t// to limit spamming\n\ttime.Sleep(dhtPeer.registrationDelay)\n\n\tnbrConns, _ := dhtPeer.monitor.GetGauge(metricServiceDelegateClientsCount)\n\tnbrClients, _ := dhtPeer.monitor.GetCounter(metricServiceDelegateClientsCountAll)\n\topLatencyRegister, _ := dhtPeer.monitor.GetHistogram(metricOpLatencyRegister)\n\ttimer := dhtPeer.monitor.Timer()\n\tstart := timer.NewTimer()\n\n\tlerror, _, linfo, _ := dhtPeer.GetLoggers()\n\n\t//linfo().Msgf(\"received a new connection from %s\", conn.RemoteAddr().String())\n\n\t// read agent registration message\n\tconPipe := utils.ConnPipe{Conn: conn}\n\n\tvar register *acn.RegisterPerformative\n\tvar err error\n\n\tregister, err = acn.ReadAgentRegistrationMessage(conPipe)\n\tif err != nil {\n\t\tlerror(err).Msg(\"while receiving agent's registration request\")\n\t\tnbrConns.Dec()\n\t\treturn\n\t}\n\tlinfo().Msgf(\"Received registration request %s\", register)\n\n\t// Get Register message\n\trecord := register.Record\n\taddr := record.Address\n\n\tlinfo().Msgf(\"connection from %s established for Address %s\",\n\t\tconn.RemoteAddr().String(), addr)\n\n\t// check if the PoR is valid\n\tstatus, err := dhtPeer.CheckPOR(record)\n\tif err != nil || status.Code != acn.SUCCESS {\n\t\tlerror(err).Msg(\"PoR is not valid\")\n\t\tacn_send_error := acn.SendAcnError(conPipe, err.Error(), status.Code)\n\t\tignore(acn_send_error)\n\t\tnbrConns.Dec()\n\t\treturn\n\t}\n\n\t// TOFIX(LR) post-pone answer until address successfully registered\n\terr = acn.SendAcnSuccess(conPipe)\n\tif err != nil {\n\t\tnbrConns.Dec()\n\t\treturn\n\t}\n\n\t// Add connection to map\n\tdhtPeer.agentRecordsLock.Lock()\n\tdhtPeer.agentRecords[addr] = record\n\tdhtPeer.agentRecordsLock.Unlock()\n\n\tdhtPeer.tcpAddressesLock.Lock()\n\tdhtPeer.tcpAddresses[addr] = conn\n\tdhtPeer.tcpAddressesLock.Unlock()\n\n\tdhtPeer.acnStatusesLock.Lock()\n\tdhtPeer.acnStatuses[addr] = make(chan *acn.StatusBody, AcnStatusesQueueSize)\n\tdhtPeer.acnStatusesLock.Unlock()\n\n\t//linfo().Msgf(\"announcing tcp client address %s...\", addr)\n\t// TOFIX(LR) disconnect client?\n\tif dhtPeer.IsAddressAnnouncementEnabled() {\n\t\terr = dhtPeer.RegisterAgentAddress(addr)\n\t\tif err != nil {\n\t\t\tlerror(err).Msgf(\"while announcing tcp client address %s to the dht\", addr)\n\t\t\treturn\n\t\t}\n\t}\n\n\tduration := timer.GetTimer(start)\n\topLatencyRegister.Observe(float64(duration.Microseconds()))\n\n\tnbrConns.Inc()\n\tnbrClients.Inc()\n\n\tconnPipe := utils.ConnPipe{Conn: conn}\n\n\tfor {\n\t\t// read envelopes\n\t\tenvel, err := aea.HandleAcnMessageFromPipe(connPipe, dhtPeer, addr)\n\t\tif err != nil {\n\t\t\tif err == io.EOF {\n\t\t\t\tlinfo().Str(\n\t\t\t\t\t\"addr\",\n\t\t\t\t\taddr,\n\t\t\t\t).Msgf(\n\t\t\t\t\t\"connection closed by client: %s, stopping...\",\n\t\t\t\t\terr.Error(),\n\t\t\t\t)\n\t\t\t} else {\n\t\t\t\tlerror(err).Str(\"addr\", addr).Msg(\"while reading envelope from client connection, aborting...\")\n\t\t\t}\n\t\t\tnbrConns.Dec()\n\t\t\tbreak\n\t\t}\n\t\tif envel == nil {\n\t\t\t// ACN status\n\t\t\tcontinue\n\t\t}\n\t\tlinfo().Str(\n\t\t\t\"addr\",\n\t\t\taddr,\n\t\t).Msgf(\n\t\t\t\"got envelope from delegate connection\",\n\t\t)\n\t\tif envel.Sender != addr {\n\t\t\terr = errors.New(\"Sender (\" + envel.Sender + \") must match registered address\")\n\t\t\tlerror(err).Str(\"addr\", addr).\n\t\t\t\tMsg(\"while routing delegate client envelope\")\n\t\t\tcontinue\n\t\t}\n\n\t\t// initializing pairwise channel queues and one go routine per pair\n\t\tpair := envel.To + envel.Sender\n\t\tdhtPeer.syncMessagesLock.Lock()\n\t\t_, ok := dhtPeer.syncMessages[pair]\n\t\tdhtPeer.syncMessagesLock.Unlock()\n\t\tif !ok {\n\t\t\tdhtPeer.syncMessagesLock.Lock()\n\t\t\tdhtPeer.syncMessages[pair] = make(chan *aea.Envelope, 1000)\n\t\t\tdhtPeer.syncMessagesLock.Unlock()\n\n\t\t\t// route envelope\n\t\t\tdhtPeer.goroutines.Add(1)\n\t\t\tgo func() {\n\t\t\t\tdefer dhtPeer.goroutines.Done()\n\t\t\t\tdhtPeer.syncMessagesLock.Lock()\n\t\t\t\tpair_range := dhtPeer.syncMessages[pair]\n\t\t\t\tdhtPeer.syncMessagesLock.Unlock()\n\n\t\t\t\tfor e := range pair_range {\n\t\t\t\t\terr := dhtPeer.RouteEnvelope(e)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\tlerror(err).Str(\"addr\", addr).\n\t\t\t\t\t\t\tMsg(\"while routing delegate client envelope\")\n\t\t\t\t\t\t// TODO() send error back\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}()\n\t\t}\n\t\t// add to queue (nonblocking - buffered queue)\n\t\tdhtPeer.syncMessagesLock.Lock()\n\n\t\tselect {\n\t\tcase dhtPeer.syncMessages[pair] <- envel:\n\t\tdefault:\n\t\t\t// send back! error\n\t\t\tfmt.Println(\"CHANNEL FULL, DISCARDING <<<-------- \", string(envel.Message))\n\t\t}\n\t\tdhtPeer.syncMessagesLock.Unlock()\n\t}\n\n\tlinfo().Str(\"addr\", addr).\n\t\tMsg(\"delegate client disconnected\")\n\t// Remove connection from map\n\tdhtPeer.tcpAddressesLock.Lock()\n\tdelete(dhtPeer.tcpAddresses, addr)\n\tdhtPeer.tcpAddressesLock.Unlock()\n\t// TOFIX(LR) currently I am keeping the agent record\n\n\tdhtPeer.acnStatusesLock.Lock()\n\tdelete(dhtPeer.acnStatuses, addr)\n\tdhtPeer.acnStatusesLock.Unlock()\n\n}\n\n// ProcessEnvelope register callback function\nfunc (dhtPeer *DHTPeer) ProcessEnvelope(fn func(*aea.Envelope) error) {\n\tdhtPeer.processEnvelope = fn\n}\n\n// MultiAddr libp2p multiaddr of the peer\nfunc (dhtPeer *DHTPeer) MultiAddr() string {\n\tmultiAddr, _ := multiaddr.NewMultiaddr(\n\t\tfmt.Sprintf(\"/p2p/%s\", dhtPeer.routedHost.ID().Pretty()))\n\taddrs := dhtPeer.routedHost.Addrs()\n\tif len(addrs) == 0 {\n\t\treturn \"\"\n\t}\n\treturn addrs[0].Encapsulate(multiAddr).String()\n}\n\nfunc (dhtPeer *DHTPeer) GetCertAndSignature() (*tls.Certificate, []byte) {\n\treturn dhtPeer.cert, dhtPeer.sslSignature\n}\n\n// RouteEnvelope to its destination\n\nfunc (dhtPeer *DHTPeer) getEnvelopeAcnRecord(envel *aea.Envelope) (*acn.AgentRecord, error) {\n\tsender := envel.Sender\n\tdhtPeer.agentRecordsLock.RLock()\n\tlocalRec, existsLocal := dhtPeer.agentRecords[sender]\n\tdhtPeer.agentRecordsLock.RUnlock()\n\n\tvar envelRec *acn.AgentRecord\n\tif sender == dhtPeer.myAgentAddress {\n\t\tenvelRec = dhtPeer.myAgentRecord\n\t} else if dhtPeer.mailboxServer != nil && dhtPeer.mailboxServer.IsAddrRegistered(sender) {\n\t\tenvelRec = dhtPeer.mailboxServer.GetAgentRecord(sender)\n\t} else if existsLocal {\n\t\t// TOFIX(LR) should acquire RLock\n\t\tenvelRec = localRec\n\t} else {\n\t\terr := errors.New(\"Envelope sender is not registered locally \" + sender)\n\t\treturn nil, err\n\t}\n\treturn envelRec, nil\n}\n\nfunc (dhtPeer *DHTPeer) RouteEnvelope(envel *aea.Envelope) error {\n\tlerror, lwarn, linfo, ldebug := dhtPeer.GetLoggers()\n\n\trouteCount, _ := dhtPeer.monitor.GetGauge(metricOpRouteCount)\n\trouteCountAll, _ := dhtPeer.monitor.GetCounter(metricOpRouteCountAll)\n\trouteCountSuccess, _ := dhtPeer.monitor.GetCounter(metricOpRouteCountSuccess)\n\topLatencyRoute, _ := dhtPeer.monitor.GetHistogram(metricOpLatencyRoute)\n\ttimer := dhtPeer.monitor.Timer()\n\n\trouteCount.Inc()\n\trouteCountAll.Inc()\n\tstart := timer.NewTimer()\n\tldebug().Str(\"addr\", envel.To).Msgf(\"-> Routing envelope: %s\", envel.String())\n\n\t// get sender agent envelRec\n\t// TODO can change function signature to force the caller to provide the envelRec\n\ttarget := envel.To\n\n\tvar err error\n\n\tenvelRec, err := dhtPeer.getEnvelopeAcnRecord(envel)\n\n\tif err != nil {\n\t\tlerror(err).Str(\"op\", \"route\").Str(\"addr\", envel.To).\n\t\t\tMsg(\"\")\n\t\treturn err\n\t}\n\n\tdhtPeer.tcpAddressesLock.RLock()\n\tconnDelegate, existsDelegate := dhtPeer.tcpAddresses[target]\n\tdhtPeer.tcpAddressesLock.RUnlock()\n\n\tif dhtPeer.mailboxServer != nil {\n\t\tif dhtPeer.mailboxServer.RouteEnvelope(envel) {\n\t\t\tlinfo().Str(\"op\", \"route\").Str(\"addr\", target).\n\t\t\t\tMsg(\"route envelope destinated to mailbox registered agent...\")\n\t\t\treturn nil\n\t\t}\n\t}\n\n\tif target == dhtPeer.myAgentAddress {\n\t\tlinfo().Str(\"op\", \"route\").Str(\"addr\", target).\n\t\t\tMsg(\"route envelope destinated to my local agent...\")\n\t\t// TOFIX(LR) risk of infinite loop\n\t\tfor dhtPeer.myAgentReady != nil && !dhtPeer.myAgentReady() {\n\t\t\tlwarn().Str(\"op\", \"route\").Str(\"addr\", target).\n\t\t\t\tMsg(\"agent not ready yet, sleeping for some time ...\")\n\t\t\ttime.Sleep(time.Duration(100) * time.Millisecond)\n\t\t}\n\t\tif dhtPeer.processEnvelope != nil {\n\t\t\tduration := timer.GetTimer(start)\n\t\t\topLatencyRoute.Observe(float64(duration.Microseconds()))\n\t\t\terr := dhtPeer.processEnvelope(envel)\n\t\t\trouteCount.Dec()\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\trouteCountSuccess.Inc()\n\t\t} else {\n\t\t\tlwarn().Str(\"op\", \"route\").Str(\"addr\", target).\n\t\t\t\tMsgf(\"ProcessEnvelope not set, ignoring envelope %s\", envel.String())\n\t\t\treturn errors.New(\"Agent not ready\")\n\t\t}\n\t} else if existsDelegate {\n\t\tlinfo().Str(\"op\", \"route\").Str(\"addr\", target).\n\t\t\tMsgf(\"destination is a delegate client %s\", connDelegate.RemoteAddr().String())\n\n\t\trouteCount.Dec()\n\t\trouteCountSuccess.Inc()\n\n\t\tduration := timer.GetTimer(start)\n\t\topLatencyRoute.Observe(float64(duration.Microseconds()))\n\n\t\tdata, err := aea.MakeAcnMessageFromEnvelope(envel)\n\t\tif err != nil {\n\t\t\tlerror(err).Msgf(\"while serializing envelope: %s\", envel)\n\t\t\treturn err\n\t\t}\n\t\terr = utils.WriteBytesConn(connDelegate, data)\n\t\tif err != nil {\n\t\t\tlerror(err).Msgf(\"while writing envelope: %s\", envel)\n\t\t\treturn err\n\t\t}\n\t\tlinfo().Str(\"addr\", target).Msg(\"wait for acn ack\")\n\t\terr = dhtPeer.AwaitAcnStatus(target)\n\t\tlinfo().Str(\"addr\", target).Msg(\"got acn ack\")\n\t\tif err != nil {\n\t\t\tlerror(err).Msgf(\"while waiting acn ack for envelope: %s\", envel)\n\t\t\treturn err\n\t\t}\n\n\t} else {\n\t\tvar peerID peer.ID\n\t\tvar err error\n\t\tdhtPeer.dhtAddressesLock.RLock()\n\t\tsPeerID, exists := dhtPeer.dhtAddresses[target]\n\t\tdhtPeer.dhtAddressesLock.RUnlock()\n\t\tif exists {\n\t\t\tlinfo().Str(\"op\", \"route\").Str(\"addr\", target).\n\t\t\t\tMsgf(\"destination is a relay client %s\", sPeerID)\n\t\t\tpeerID, err = peer.Decode(sPeerID)\n\t\t\tlinfo().Str(\"op\", \"route\").Str(\"addr\", target).\n\t\t\t\tMsgf(\"relay client peer is %s\", peerID)\n\t\t\tif err != nil {\n\t\t\t\tlerror(err).Str(\"op\", \"route\").Str(\"addr\", target).\n\t\t\t\t\tMsgf(\"CRITICAL couldn't parse peer id from relay client id\")\n\t\t\t\trouteCount.Dec()\n\t\t\t\treturn err\n\t\t\t}\n\t\t\treturn dhtPeer._routeEnvelopeWithNewStream(envel, peerID, envelRec)\n\t\t}\n\t\t// not exists\n\t\terr = dhtPeer._routeEnvelopeDHTLookup(envel, timeoutBeforeMovingToSlowQueue)\n\t\tif err != nil {\n\t\t\trouteCount.Dec()\n\n\t\t\tif !dhtPeer.isClosing {\n\t\t\t\tlerror(err).Str(\"op\", \"route\").Str(\"addr\", target).\n\t\t\t\t\tMsg(\"while rooting and looking up address on the DHT. moving it to she slow queue\")\n\t\t\t\tdhtPeer.slow_queue <- envel\n\t\t\t} else {\n\t\t\t\tlerror(err).Str(\"op\", \"route\").Str(\"addr\", target).\n\t\t\t\t\tMsg(\"while rooting and looking up address on the DHT. dht peer is closing. message dropped\")\n\t\t\t}\n\n\t\t\treturn nil\n\t\t}\n\t}\n\n\treturn nil\n}\nfunc (dhtPeer *DHTPeer) slowEnvelopeSendLoop() {\n\tlerror, _, _, ldebug := dhtPeer.GetLoggers()\n\tvar err error\n\tfor {\n\t\tenvel, ok := <-dhtPeer.slow_queue\n\t\tif !ok || dhtPeer.isClosing {\n\t\t\tldebug().Msg(\"slow envelope send loop closed\")\n\t\t\treturn\n\t\t}\n\t\tif envel == nil {\n\t\t\tldebug().Msg(\"got nil envelope. exit slow envelope send loop\")\n\t\t\treturn\n\t\t}\n\t\tldebug().Str(\"addr\", envel.To).Msgf(\"-> Routing slow envelope: %s\", envel.String())\n\t\terr = dhtPeer._routeEnvelopeDHTLookup(envel, addressLookupTimeout)\n\t\tif err != nil {\n\t\t\tlerror(err).Msgf(\"while sending slow envelope: %s\", envel.String())\n\t\t} else {\n\t\t\tldebug().Str(\"addr\", envel.To).Msgf(\"sent slow envelope: %s\", envel.String())\n\t\t}\n\n\t}\n}\n\nfunc (dhtPeer *DHTPeer) _routeEnvelopeDHTLookup(\n\tenvel *aea.Envelope,\n\tlookup_timeout time.Duration,\n) error {\n\ttarget := envel.To\n\tlerror, _, linfo, _ := dhtPeer.GetLoggers()\n\tenvelRec, err := dhtPeer.getEnvelopeAcnRecord(envel)\n\tif err != nil {\n\t\treturn err\n\t}\n\tlinfo().Str(\"op\", \"route\").Str(\"addr\", target).\n\t\tMsg(\"did NOT find destination address locally, looking for it in the DHT...\")\n\tctx, cancel_lookup := context.WithTimeout(context.Background(), lookup_timeout)\n\tdefer cancel_lookup()\n\tpeerID, _, err := dhtPeer.lookupAddressDHT(ctx, target) // guarantees peerID has a valid PoR\n\tif err != nil {\n\t\tlerror(err).Str(\"op\", \"route\").Str(\"addr\", target).\n\t\t\tMsg(\"while looking up address on the DHT\")\n\t\treturn err\n\t}\n\terr = dhtPeer._routeEnvelopeWithNewStream(envel, peerID, envelRec)\n\treturn err\n\n}\n\nfunc (dhtPeer *DHTPeer) _routeEnvelopeWithNewStream(\n\tenvel *aea.Envelope,\n\tpeerID peer.ID,\n\tenvelRec *acn.AgentRecord,\n) error {\n\t//linfo().Str(\"op\", \"route\").Str(\"addr\", target).\n\t//\tMsgf(\"got peer id '%s' for agent address\", peerID.Pretty())\n\n\t//linfo().Str(\"op\", \"route\").Str(\"addr\", target).\n\t//\tMsgf(\"opening stream to target %s...\", peerID.Pretty())\n\tlerror, _, linfo, _ := dhtPeer.GetLoggers()\n\n\trouteCount, _ := dhtPeer.monitor.GetGauge(metricOpRouteCount)\n\topLatencyRoute, _ := dhtPeer.monitor.GetHistogram(metricOpLatencyRoute)\n\ttimer := dhtPeer.monitor.Timer()\n\tstart := timer.NewTimer()\n\n\tvar err error\n\ttarget := envel.To\n\tctx, cancel := context.WithTimeout(context.Background(), newStreamTimeout)\n\tdefer cancel()\n\tstream, err := dhtPeer.routedHost.NewStream(ctx, peerID, dhtnode.AeaEnvelopeStream)\n\tif err != nil {\n\t\tlerror(err).Str(\"op\", \"route\").Str(\"addr\", target).\n\t\t\tMsgf(\"timeout, couldn't open stream to target %s\", peerID.Pretty())\n\t\trouteCount.Dec()\n\t\treturn err\n\t}\n\n\tduration := timer.GetTimer(start)\n\topLatencyRoute.Observe(float64(duration.Microseconds()))\n\n\tlinfo().Str(\"op\", \"route\").Str(\"addr\", target).\n\t\tMsgf(\"sending envelope to target peer %s...\", peerID.Pretty())\n\n\tenvelBytes, err := proto.Marshal(envel)\n\tif err != nil {\n\t\tlerror(err).\n\t\t\tStr(\"op\", \"route\").\n\t\t\tStr(\"addr\", target).\n\t\t\tMsg(\"couldn't serialize envelope\")\n\t\terrReset := stream.Reset()\n\t\tignore(errReset)\n\t\trouteCount.Dec()\n\t\treturn err\n\t}\n\n\tstreamPipe := utils.StreamPipe{Stream: stream}\n\terr = acn.SendEnvelopeMessage(streamPipe, envelBytes, envelRec)\n\tif err != nil {\n\t\tlerror(err).\n\t\t\tStr(\"op\", \"route\").\n\t\t\tStr(\"addr\", target).\n\t\t\tMsg(\"couldn't send envelope\")\n\t\terrReset := stream.Reset()\n\t\tignore(errReset)\n\t\trouteCount.Dec()\n\t\treturn err\n\t}\n\n\t// wait for response\n\tlinfo().Str(\"op\", \"route\").Str(\"addr\", target).\n\t\tMsgf(\"waiting fro envelope delivery confirmation from target peer %s...\", peerID.Pretty())\n\n\tstatusBody, err := acn.ReadAcnStatus(streamPipe)\n\n\tif err != nil {\n\t\tlerror(err).\n\t\t\tStr(\"op\", \"route\").\n\t\t\tStr(\"addr\", target).\n\t\t\tMsg(\"failed to decode acn status\")\n\t\trouteCount.Dec()\n\t\treturn err\n\t}\n\tif statusBody.Code != acn.SUCCESS {\n\t\terr = errors.New(statusBody.Code.String() + \" : \" + strings.Join(statusBody.Msgs, \":\"))\n\t\tlerror(err).\n\t\t\tStr(\"op\", \"route\").\n\t\t\tStr(\"addr\", target).\n\t\t\tMsg(\"failed to deliver envelope\")\n\t\trouteCount.Dec()\n\t\treturn err\n\t}\n\n\trouteCount.Dec()\n\treturn nil\n}\n\n/// TOFIX(LR) should return (*dhtnode)\nfunc (dhtPeer *DHTPeer) lookupAddressDHT(\n\tctx context.Context,\n\taddress string,\n) (peer.ID, *acn.AgentRecord, error) {\n\tlerror, lwarn, linfo, _ := dhtPeer.GetLoggers()\n\tvar err error\n\n\tdhtLookupLatency, _ := dhtPeer.monitor.GetHistogram(metricDHTOpLatencyLookup)\n\ttimer := dhtPeer.monitor.Timer()\n\n\taddressCID, err := utils.ComputeCID(address)\n\tif err != nil {\n\t\treturn \"\", nil, err\n\t}\n\n\tlinfo().Str(\"op\", \"lookup\").Str(\"addr\", address).\n\t\tMsgf(\"Querying for providers for cid %s...\", addressCID.String())\n\tctx, cancel := context.WithTimeout(ctx, addressLookupTimeout)\n\tdefer cancel()\n\t//var elapsed time.Duration\n\tvar provider peer.AddrInfo\n\tvar stream network.Stream\n\n\tstart := timer.NewTimer()\n\n\tnoProvider := false\n\tfor {\n\t\tproviders := dhtPeer.dht.FindProvidersAsync(ctx, addressCID, 0)\n\n\t\tfor provider = range providers {\n\t\t\tduration := timer.GetTimer(start)\n\t\t\tdhtLookupLatency.Observe(float64(duration.Microseconds()))\n\n\t\t\t//linfo().Str(\"op\", \"lookup\").Str(\"addr\", address).\n\t\t\t//\tMsgf(\"found provider %s after %s\", provider, elapsed.String())\n\n\t\t\t// Add peer to host PeerStore - the provider should be the holder of the address\n\t\t\tdhtPeer.routedHost.Peerstore().AddAddrs(\n\t\t\t\tprovider.ID,\n\t\t\t\tprovider.Addrs,\n\t\t\t\tpeerstore.PermanentAddrTTL,\n\t\t\t)\n\n\t\t\t//linfo().Str(\"op\", \"lookup\").Str(\"addr\", address).\n\t\t\t//\tMsgf(\"opening stream to the address provider %s...\", provider)\n\t\t\tctxConnect := context.Background()\n\t\t\tstream, err = dhtPeer.routedHost.NewStream(\n\t\t\t\tctxConnect,\n\t\t\t\tprovider.ID,\n\t\t\t\tdhtnode.AeaAddressStream,\n\t\t\t)\n\n\t\t\tif err != nil {\n\t\t\t\tlwarn().Str(\"op\", \"lookup\").Str(\"addr\", address).\n\t\t\t\t\tMsgf(\"couldn't open stream to address provider %s: %s, looking up other providers...\", provider, err.Error())\n\t\t\t\tdhtPeer.routedHost.Peerstore().ClearAddrs(provider.ID)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tstreamPipe := utils.StreamPipe{Stream: stream}\n\n\t\t\tlinfo().Str(\"op\", \"lookup\").Str(\"addr\", address).\n\t\t\t\tMsgf(\"getting agent record from provider %s...\", provider)\n\n\t\t\t// perfrormaddress lookup\n\t\t\trecord, err := acn.PerformAddressLookup(streamPipe, address)\n\n\t\t\t// Response is either a LookupResponse or Status\n\t\t\tignore(stream.Reset())\n\t\t\tstream.Close()\n\t\t\tif err != nil {\n\t\t\t\tlwarn().Str(\"op\", \"lookup\").Str(\"addr\", address).\n\t\t\t\t\tMsgf(\"Failed agent lookup from provider %s (%s), looking up other providers...\", provider, err.Error())\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// lookupResponse must be set\n\t\t\tvalid, err := dhtnode.IsValidProofOfRepresentation(\n\t\t\t\trecord,\n\t\t\t\taddress,\n\t\t\t\trecord.PeerPublicKey,\n\t\t\t)\n\t\t\tif err != nil || valid.Code != acn.SUCCESS {\n\t\t\t\terrMsg := valid.Code.String() + \" : \" + strings.Join(valid.Msgs, \":\")\n\t\t\t\tif err == nil {\n\t\t\t\t\terr = errors.New(errMsg)\n\t\t\t\t} else {\n\t\t\t\t\terr = errors.Wrap(err, valid.Code.String()+\" : \"+strings.Join(valid.Msgs, \":\"))\n\t\t\t\t}\n\t\t\t\tlwarn().Str(\"op\", \"lookup\").Str(\"addr\", address).\n\t\t\t\t\tMsgf(\"invalid agent record from provider %s (%s), looking up other providers...\", provider, err.Error())\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tpeerid, err := utils.IDFromFetchAIPublicKey(record.PeerPublicKey)\n\t\t\tif err != nil {\n\t\t\t\treturn \"\", nil, errors.New(\n\t\t\t\t\t\"CRITICAL couldn't get peer ID from message:\" + err.Error(),\n\t\t\t\t)\n\t\t\t}\n\n\t\t\treturn peerid, record, nil\n\t\t}\n\n\t\tif provider.ID == \"\" {\n\t\t\tmsg := \"didn't find any provider for address\"\n\t\t\tif !noProvider {\n\t\t\t\tnoProvider = true\n\t\t\t\tlwarn().Str(\"op\", \"lookup\").Str(\"addr\", address).Msgf(\"%s, retrying...\", msg)\n\t\t\t}\n\t\t\tselect {\n\t\t\tdefault:\n\t\t\t\ttime.Sleep(200 * time.Millisecond)\n\t\t\tcase <-ctx.Done():\n\t\t\t\terr = errors.New(msg + \" \" + address + \" within timeout\")\n\t\t\t\tlerror(err).Str(\"op\", \"lookup\").Str(\"addr\", address).Msg(\"\")\n\t\t\t\treturn \"\", nil, err\n\t\t\t}\n\t\t} else {\n\t\t\treturn \"\", nil, err\n\t\t}\n\t}\n}\n\n// handleAeaEnvelopeStream deals with incoming envelopes on the AeaEnvelopeStream\n// envelopes arrive from other peers (full or client) and are processed\n// by HandleAeaEnvelope\nfunc (dhtPeer *DHTPeer) handleAeaEnvelopeStream(stream network.Stream) {\n\tcommon.HandleAeaEnvelopeStream(dhtPeer, stream)\n}\n\n// Callback to handle and route  aea envelope comes from the aea envelope stream\n// return ACNError if message routing failed, otherwise nil.\nfunc (dhtPeer *DHTPeer) HandleAeaEnvelope(envel *aea.Envelope) *acn.ACNError {\n\tvar err error\n\tlerror, lwarn, linfo, _ := dhtPeer.GetLoggers()\n\tdhtPeer.tcpAddressesLock.RLock()\n\tconnDelegate, existsDelegate := dhtPeer.tcpAddresses[envel.To]\n\tdhtPeer.tcpAddressesLock.RUnlock()\n\n\tif dhtPeer.mailboxServer != nil {\n\t\tif dhtPeer.mailboxServer.RouteEnvelope(envel) {\n\t\t\tlinfo().Str(\"op\", \"route\").Str(\"addr\", envel.To).\n\t\t\t\tMsg(\"route envelope destinated to mailbox registered agent...\")\n\t\t\treturn nil\n\t\t}\n\t}\n\n\tif existsDelegate {\n\t\tlinfo().Msgf(\n\t\t\t\"Sending envelope to tcp delegate client %s...\",\n\t\t\tconnDelegate.RemoteAddr().String(),\n\t\t)\n\t\tdata, err := aea.MakeAcnMessageFromEnvelope(envel)\n\t\tif err != nil {\n\t\t\tlerror(err).Msgf(\"while serializing envelope: %s\", envel)\n\t\t\treturn &acn.ACNError{\n\t\t\t\tErr:       errors.New(\"serializing envelope error\"),\n\t\t\t\tErrorCode: acn.ERROR_DECODE,\n\t\t\t}\n\t\t}\n\t\terr = utils.WriteBytesConn(connDelegate, data)\n\n\t\tif err != nil {\n\t\t\tlerror(\n\t\t\t\terr,\n\t\t\t).Msgf(\n\t\t\t\t\"while sending envelope to tcp client %s\",\n\t\t\t\tconnDelegate.RemoteAddr().String(),\n\t\t\t)\n\t\t\treturn &acn.ACNError{\n\t\t\t\tErr:       errors.New(\"agent is not ready\"),\n\t\t\t\tErrorCode: acn.ERROR_AGENT_NOT_READY,\n\t\t\t}\n\t\t}\n\t\terr = dhtPeer.AwaitAcnStatus(envel.To)\n\t\tif err != nil {\n\t\t\tlerror(\n\t\t\t\terr,\n\t\t\t).Msgf(\n\t\t\t\t\"while awating acn ack on sending  envelope to tcp client %s\",\n\t\t\t\tconnDelegate.RemoteAddr().String(),\n\t\t\t)\n\t\t\treturn &acn.ACNError{\n\t\t\t\tErr:       errors.New(\"while awating acn ack on sending  envelope to tcp clien\"),\n\t\t\t\tErrorCode: acn.ERROR_AGENT_NOT_READY,\n\t\t\t}\n\t\t}\n\t} else if envel.To == dhtPeer.myAgentAddress {\n\t\tif dhtPeer.processEnvelope == nil {\n\t\t\tlerror(err).Msgf(\"while processing envelope by agent\")\n\t\t\treturn &acn.ACNError{Err: errors.New(\"agent is not ready\"), ErrorCode: acn.ERROR_AGENT_NOT_READY}\n\t\t}\n\t\tlinfo().Msg(\"Processing envelope by local agent...\")\n\t\terr = dhtPeer.processEnvelope(envel)\n\t\tignore(err)\n\t} else {\n\t\tlwarn().Msgf(\"ignored envelope %s\", envel.String())\n\t\treturn &acn.ACNError{Err: errors.New(\"unknown agent address\"), ErrorCode: acn.ERROR_UNKNOWN_AGENT_ADDRESS}\n\t}\n\n\t// all good\n\treturn nil\n}\n\nfunc (dhtPeer *DHTPeer) handleAeaAddressStream(stream network.Stream) {\n\tcommon.HandleAeaAddressStream(dhtPeer, stream)\n\n}\n\nfunc (dhtPeer *DHTPeer) HandleAeaAddressRequest(\n\treqAddress string,\n) (*acn.AgentRecord, *acn.ACNError) {\n\tlerror, _, linfo, _ := dhtPeer.GetLoggers()\n\n\t//\tMsg(\"Received query for addr\")\n\tvar sPeerID string\n\tvar sRecord *acn.AgentRecord = nil\n\n\tdhtPeer.dhtAddressesLock.RLock()\n\tidRelay, existsRelay := dhtPeer.dhtAddresses[reqAddress]\n\tdhtPeer.dhtAddressesLock.RUnlock()\n\tdhtPeer.tcpAddressesLock.RLock()\n\t_, existsDelegate := dhtPeer.tcpAddresses[reqAddress]\n\tdhtPeer.tcpAddressesLock.RUnlock()\n\tdhtPeer.agentRecordsLock.RLock()\n\tlocalRec := dhtPeer.agentRecords[reqAddress]\n\tdhtPeer.agentRecordsLock.RUnlock()\n\n\tif reqAddress == dhtPeer.myAgentAddress {\n\t\tpeerID, err := peer.IDFromPublicKey(dhtPeer.publicKey)\n\t\tif err != nil {\n\t\t\tlerror(err).Str(\"op\", \"resolve\").Str(\"addr\", reqAddress).\n\t\t\t\tMsgf(\"CRITICAL could not get peer ID from public key %s\", dhtPeer.publicKey)\n\t\t} else {\n\t\t\tsPeerID = peerID.Pretty()\n\t\t\tsRecord = dhtPeer.myAgentRecord\n\t\t}\n\t} else if existsRelay {\n\t\tlinfo().Str(\"op\", \"resolve\").Str(\"addr\", reqAddress).\n\t\t\tMsg(\"found address in my relay clients map\")\n\t\tsPeerID = idRelay\n\t\tsRecord = localRec\n\t} else if dhtPeer.mailboxServer != nil && dhtPeer.mailboxServer.IsAddrRegistered(reqAddress) {\n\t\tsPeerID = idRelay\n\t\tsRecord = dhtPeer.mailboxServer.GetAgentRecord(reqAddress)\n\t} else if existsDelegate {\n\t\tlinfo().Str(\"op\", \"resolve\").Str(\"addr\", reqAddress).\n\t\t\tMsgf(\"found address in my delegate clients map\")\n\t\tpeerID, err := peer.IDFromPublicKey(dhtPeer.publicKey)\n\t\tif err != nil {\n\t\t\tlerror(err).Str(\"op\", \"resolve\").Str(\"addr\", reqAddress).\n\t\t\t\tMsgf(\"CRITICAL could not get peer ID from public key %s\", dhtPeer.publicKey)\n\t\t} else {\n\t\t\tsPeerID = peerID.Pretty()\n\t\t\tsRecord = localRec\n\t\t}\n\t} else {\n\t\t// needed when a relay client queries for a peer ID\n\t\t//linfo().Str(\"op\", \"resolve\").Str(\"addr\", reqAddress).\n\t\t//\tMsg(\"did NOT found the address locally, looking for it in the DHT...\")\n\t\tpeerID, peerRecord, err := dhtPeer.lookupAddressDHT(context.Background(), reqAddress)\n\t\tif err == nil {\n\t\t\tlinfo().Str(\"op\", \"resolve\").Str(\"addr\", reqAddress).\n\t\t\t\tMsg(\"found address on the DHT\")\n\t\t\tsPeerID = peerID.Pretty()\n\t\t\tsRecord = peerRecord\n\t\t} else {\n\t\t\tlerror(err).Str(\"op\", \"resolve\").Str(\"addr\", reqAddress).\n\t\t\t\tMsgf(\"did NOT find address locally or on the DHT.\")\n\n\t\t\treturn nil, &acn.ACNError{\n\t\t\t\tErr:       errors.New(\"unknown agent address\"),\n\t\t\t\tErrorCode: acn.ERROR_UNKNOWN_AGENT_ADDRESS,\n\t\t\t}\n\t\t}\n\t}\n\n\tif sRecord == nil {\n\t\treturn nil, &acn.ACNError{\n\t\t\tErr:       errors.New(\"unknown agent address\"),\n\t\t\tErrorCode: acn.ERROR_UNKNOWN_AGENT_ADDRESS,\n\t\t}\n\t}\n\n\t// record found, send\n\tlinfo().Str(\"op\", \"resolve\").Str(\"addr\", reqAddress).\n\t\tMsgf(\"sending agent record (%s) %s\", sPeerID, sRecord)\n\n\treturn sRecord, nil\n}\n\nfunc (dhtPeer *DHTPeer) handleAeaNotifStream(stream network.Stream) {\n\tlerror, _, _, ldebug := dhtPeer.GetLoggers()\n\n\tldebug().Str(\"op\", \"notif\").\n\t\tMsgf(\"Got a new notif stream. peerid: %s\", stream.Conn().RemotePeer().Pretty())\n\topLatencyRegister, _ := dhtPeer.monitor.GetHistogram(metricOpLatencyRegister)\n\ttimer := dhtPeer.monitor.Timer()\n\tstart := timer.NewTimer()\n\n\t// workaround: to avoid getting `failed to find any peer in table`\n\t//  when calling dht.Provide (happens occasionally)\n\tldebug().Msg(\"waiting for notifying peer to be added to dht routing table...\")\n\tctx, cancel := context.WithTimeout(\n\t\tcontext.Background(),\n\t\troutingTableConnectionUpdateTimeout,\n\t)\n\tdefer cancel()\n\n\tdefer dhtPeer.enableAddressAnnouncementWg.Done()\n\tdhtPeer.enableAddressAnnouncementWg.Add(1)\n\n\tfor dhtPeer.dht.RoutingTable().Find(stream.Conn().RemotePeer()) == \"\" {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\tlerror(nil).\n\t\t\t\tMsgf(\"timeout: notifying peer %s haven't been added to DHT routing table\",\n\t\t\t\t\tstream.Conn().RemotePeer().Pretty())\n\t\t\treturn\n\t\tcase <-time.After(time.Millisecond * 5):\n\t\t}\n\t}\n\n\tif dhtPeer.myAgentAddress != \"\" && !dhtPeer.IsAddressAnnounced(dhtPeer.myAgentAddress) {\n\t\terr := dhtPeer.RegisterAgentAddress(dhtPeer.myAgentAddress)\n\t\tif err != nil {\n\t\t\tlerror(err).Str(\"op\", \"notif\").\n\t\t\t\tStr(\"addr\", dhtPeer.myAgentAddress).\n\t\t\t\tMsgf(\"while announcing my agent address\")\n\t\t\treturn\n\t\t}\n\t}\n\tif dhtPeer.enableRelay {\n\t\tdhtPeer.dhtAddressesLock.RLock()\n\t\tfor addr := range dhtPeer.dhtAddresses {\n\t\t\terr := dhtPeer.RegisterAgentAddress(addr)\n\t\t\tif err != nil {\n\t\t\t\tlerror(err).Str(\"op\", \"notif\").\n\t\t\t\t\tStr(\"addr\", addr).\n\t\t\t\t\tMsg(\"while announcing relay client address\")\n\t\t\t}\n\t\t}\n\t\tdhtPeer.dhtAddressesLock.RUnlock()\n\t}\n\tif dhtPeer.delegatePort != 0 {\n\t\tdhtPeer.tcpAddressesLock.RLock()\n\t\tfor addr := range dhtPeer.tcpAddresses {\n\t\t\terr := dhtPeer.RegisterAgentAddress(addr)\n\t\t\tif err != nil {\n\t\t\t\tlerror(err).Str(\"op\", \"notif\").\n\t\t\t\t\tStr(\"addr\", addr).\n\t\t\t\t\tMsg(\"while announcing delegate client address\")\n\t\t\t}\n\t\t}\n\t\tdhtPeer.tcpAddressesLock.RUnlock()\n\n\t}\n\tduration := timer.GetTimer(start)\n\topLatencyRegister.Observe(float64(duration.Microseconds()))\n\tldebug().Msgf(\"Address was announced: peerid: %s\", stream.Conn().RemotePeer().Pretty())\n\t// got a connection to a peer, so now we can allow address announcements\n\tdhtPeer.enableAddressAnnouncementLock.Lock()\n\tdhtPeer.enableAddressAnnouncement = true\n\tdhtPeer.enableAddressAnnouncementLock.Unlock()\n\n}\n\nfunc (dhtPeer *DHTPeer) IsAddressAnnouncementEnabled() bool {\n\t// wait if new peers connection establish in process\n\tdhtPeer.enableAddressAnnouncementWg.Wait()\n\tdhtPeer.enableAddressAnnouncementLock.Lock()\n\tisEnabled := dhtPeer.enableAddressAnnouncement\n\tdhtPeer.enableAddressAnnouncementLock.Unlock()\n\treturn isEnabled\n}\n\nfunc (dhtPeer *DHTPeer) handleAeaRegisterStream(stream network.Stream) {\n\tlerror, _, linfo, _ := dhtPeer.GetLoggers()\n\n\t// to limit spamming\n\ttime.Sleep(dhtPeer.registrationDelay)\n\n\tnbrClients, _ := dhtPeer.monitor.GetCounter(metricServiceRelayClientsCountAll)\n\n\topLatencyRegister, _ := dhtPeer.monitor.GetHistogram(metricOpLatencyRegister)\n\ttimer := dhtPeer.monitor.Timer()\n\tstart := timer.NewTimer()\n\n\t//linfo().Str(\"op\", \"register\").\n\t//\tMsg(\"Got a new aea register stream\")\n\tstreamPipe := utils.StreamPipe{Stream: stream}\n\n\t// Get Register message\n\tregister, err := acn.ReadAgentRegistrationMessage(streamPipe)\n\tif err != nil {\n\t\tlerror(err).Str(\"op\", \"register\").\n\t\t\tMsg(\"while reading relay client registration request from stream\")\n\t\terr = stream.Reset()\n\t\tignore(err)\n\t\treturn\n\t}\n\trecord := register.Record\n\tclientAddr := record.Address\n\n\t//linfo().Msgf(\"connection from %s established for Address %s\",\n\t//\tstream.Conn().RemotePeer().Pretty(), clientAddr)\n\n\t// check if the PoR is valid\n\tclientPubKey, err := utils.FetchAIPublicKeyFromPubKey(stream.Conn().RemotePublicKey())\n\tignore(err)\n\tstatus, err := dhtnode.IsValidProofOfRepresentation(record, record.Address, clientPubKey)\n\n\tif err != nil || status.Code != acn.SUCCESS {\n\t\tlerror(err).Msg(\"PoR is not valid\")\n\t\tacn_send_error := acn.SendAcnError(streamPipe, err.Error(), status.Code)\n\t\tignore(acn_send_error)\n\t\treturn\n\t}\n\n\t// TOFIX(LR) post-pone answer until address successfully registered\n\terr = acn.SendAcnSuccess(streamPipe)\n\tif err != nil {\n\t\terr = stream.Reset()\n\t\tignore(err)\n\t\treturn\n\t}\n\n\tstream.Close()\n\tnbrClients.Inc()\n\n\t//linfo().Str(\"op\", \"register\").\n\t//\tStr(\"addr\", string(clientAddr)).\n\t//\tMsgf(\"Received address registration request for peer id %s\", string(clientPeerID))\n\tclientPeerID := stream.Conn().RemotePeer().Pretty()\n\n\tdhtPeer.agentRecordsLock.Lock()\n\tdhtPeer.agentRecords[clientAddr] = record\n\tdhtPeer.agentRecordsLock.Unlock()\n\n\tdhtPeer.dhtAddressesLock.Lock()\n\tdhtPeer.dhtAddresses[clientAddr] = clientPeerID\n\terr = dhtPeer.saveAgentRecordToPersistentStorage(record)\n\tif err != nil {\n\t\tlerror(err).Str(\"op\", \"register\").\n\t\t\tStr(\"addr\", clientAddr).\n\t\t\tMsg(\"while saving agent record to persistent storage\")\n\t}\n\tdhtPeer.dhtAddressesLock.Unlock()\n\n\tlinfo().Str(\"op\", \"register\").\n\t\tStr(\"addr\", clientAddr).\n\t\tMsgf(\"peer added: %s\", clientPeerID)\n\n\tif dhtPeer.IsAddressAnnouncementEnabled() && !dhtPeer.IsAddressAnnounced(string(clientAddr)) {\n\t\tlinfo().Str(\"op\", \"register\").\n\t\t\tStr(\"addr\", clientAddr).\n\t\t\tMsgf(\"Announcing client address on behalf of %s...\", clientPeerID)\n\t\terr = dhtPeer.RegisterAgentAddress(string(clientAddr))\n\t\tif err != nil {\n\t\t\t//TOFIX(LR) remove agent from map, or don't add it unless announcement done\n\t\t\tlerror(err).Str(\"op\", \"register\").\n\t\t\t\tStr(\"addr\", clientAddr).\n\t\t\t\tMsg(\"while announcing client address to the dht\")\n\t\t\treturn\n\t\t}\n\t}\n\n\tduration := timer.GetTimer(start)\n\topLatencyRegister.Observe(float64(duration.Microseconds()))\n}\n\nfunc (dhtPeer *DHTPeer) RegisterAgentAddress(addr string) error {\n\t_, _, linfo, _ := dhtPeer.GetLoggers()\n\n\tif dhtPeer.IsAddressAnnounced(addr) {\n\t\t// already announced\n\t\treturn nil\n\t}\n\n\tdhtPeer.setAddressAnnounced(addr)\n\n\tdhtStoreLatency, _ := dhtPeer.monitor.GetHistogram(metricDHTOpLatencyStore)\n\ttimer := dhtPeer.monitor.Timer()\n\n\taddressCID, err := utils.ComputeCID(addr)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// TOFIX(LR) tune timeout\n\tctx, cancel := context.WithTimeout(context.Background(), addressRegisterTimeout)\n\tdefer cancel()\n\n\tlinfo().Str(\"op\", \"register\").\n\t\tStr(\"addr\", addr).\n\t\tMsgf(\"Announcing address to the dht with cid key %s\", addressCID.String())\n\tstart := timer.NewTimer()\n\terr = dhtPeer.dht.Provide(ctx, addressCID, true)\n\tif err != context.DeadlineExceeded {\n\t\tduration := timer.GetTimer(start)\n\t\tdhtStoreLatency.Observe(float64(duration.Microseconds()))\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc (dhtPeer *DHTPeer) IsAddressAnnounced(address string) bool {\n\tdhtPeer.addressAnnouncedMapLock.Lock()\n\t_, present := dhtPeer.addressAnnouncedMap[address]\n\tdhtPeer.addressAnnouncedMapLock.Unlock()\n\treturn present\n}\n\nfunc (dhtPeer *DHTPeer) setAddressAnnounced(address string) {\n\tdhtPeer.addressAnnouncedMapLock.Lock()\n\tdhtPeer.addressAnnouncedMap[address] = true\n\tdhtPeer.addressAnnouncedMapLock.Unlock()\n}\n\nfunc (dhtPeer *DHTPeer) AddAcnStatusMessage(status *acn.StatusBody, counterpartyID string) {\n\tdhtPeer.acnStatusesLock.Lock()\n\tqueue := dhtPeer.acnStatuses[counterpartyID]\n\tdhtPeer.acnStatusesLock.Unlock()\n\n\tqueue <- status\n}\n\nfunc (dhtPeer *DHTPeer) AwaitAcnStatus(counterpartyID string) error {\n\tlerror, _, _, _ := dhtPeer.GetLoggers()\n\n\tdhtPeer.acnStatusesLock.Lock()\n\tcounterParty := dhtPeer.acnStatuses[counterpartyID]\n\tdhtPeer.acnStatusesLock.Unlock()\n\n\tstatus, err := acn.WaitForStatus(counterParty, AcnStatusTimeout)\n\n\tif err != nil {\n\t\tlerror(err).Msg(\"timeout on status wait\")\n\t\treturn err\n\t}\n\tif status.Code != acn.SUCCESS {\n\t\tlerror(err).Msgf(\"bad status: %d\", status.Code)\n\t\treturn errors.New(\"bad status!\")\n\t}\n\treturn err\n\n}\n"
  },
  {
    "path": "packages/fetchai/connections/p2p_libp2p/libp2p_node/dht/dhtpeer/dhtpeer_test.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2019 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\n\npackage dhtpeer\n\nimport (\n\t\"context\"\n\t\"crypto/ecdsa\"\n\t\"crypto/elliptic\"\n\t\"crypto/tls\"\n\t\"log\"\n\t\"math/rand\"\n\t\"net\"\n\t\"os\"\n\t\"path\"\n\t\"strconv\"\n\t\"testing\"\n\t\"time\"\n\n\t\"libp2p_node/acn\"\n\t\"libp2p_node/aea\"\n\t\"libp2p_node/dht/dhtclient\"\n\t\"libp2p_node/dht/dhtnode\"\n\t\"libp2p_node/utils\"\n\n\t\"github.com/pkg/errors\"\n\t\"google.golang.org/protobuf/proto\"\n)\n\n/*\n  DHTPeer and DHT network routing tests\n*/\n\nconst (\n\tDefaultLocalHost    = \"127.0.0.1\"\n\tDefaultLocalPort    = 2000\n\tDefaultDelegatePort = 3000\n\n\tEnvelopeDeliveryTimeout = 1 * time.Second\n\tDHTPeerSetupTimeout     = 5 * time.Second\n\n\tDefaultLedger = dhtnode.DefaultLedger\n)\n\nvar (\n\tFetchAITestKeys = []string{\n\t\t\"3e7a1f43b2d8a4b9f63a2ffeb1d597f971a8db7ffd95453173268b453106cadc\",\n\t\t\"92c36941ae78c1b93e5f4bebcf2b40be0af37573aa263ebb70b769ea235b88b6\",\n\t\t\"b6a8ff857c49b81895f18dd6dbd309e270906b75e2c290a721da48c5de4cba70\",\n\t\t\"91a90b5be4817c46e06f0e792dd9d9ef3ceb2dbb5ff5c45125153d289d515ce1\",\n\t\t\"5ee086c5c3df6f641e36e083769d6a03f918b33e4505b1102d2be7a75bb2ae0f\",\n\t\t\"6768d7918659c1699a379691381c19e55c3c13c49d30086e74a86524123659fb\",\n\t\t\"d31485403d0cce93b0c48a2fad2acae61a68396e93a602acfcd08dadd7ba12ae\",\n\t\t\"db533c3e74963a0571e962a4022a4ebce14ab5f240299b5350c83dd18549c1fd\",\n\t\t\"95aaa63bceeb0946c877c414e1f17119b8a975417924d83db8e281abd71820b2\",\n\t\t\"9427c1472b66f6abd94a6c246eee495e3709ec45882ae0badcbc71ad2cd8f8b2\",\n\t}\n\n\tFetchAITestPublicKeys = []string{\n\t\t\"03b7e977f498dce004e2614764ff576e17cc6691135497e7bcb5d3441e816ba9e1\",\n\t\t\"02344c3f0e79f56aef8e167a6fea912745f1f770b66b4c5096040c0e8c9e3c68b3\",\n\t\t\"023d6021c001c7b562af8b6e54ace4f98b1b14170d7db4749ecab2b1f0e4252794\",\n\t\t\"02a0eb20ae23f2f78650b42dfafa6bf4e4752657905da8598b2c0806478e0bfa0d\",\n\t\t\"023db373d1fc21212f2f03fec1ddd49f193f54f71545e72f37c8a70ca20ef1622b\",\n\t\t\"03290b4e5dabcca2a994a8d63057f5c83f60d999ede181a8d9b42084e3bee256c2\",\n\t\t\"03510651fbb9d2ce5b7ae00968339055fbc552e565c54cce8c69f5a52209d3d6a7\",\n\t\t\"02c11df29b5873e0c37d1427c488ba84e5ccc57405d39299757cee06893ab8595d\",\n\t\t\"031545edc0fe81a17c77a391a343f95547745b28703bbe664e12c523e3272b637e\",\n\t\t\"02dd78522785e4175e7db9794b03adcdcfaf707153f307caa3368da5a30594d369\",\n\t}\n\n\tAgentsTestKeys = []string{\n\t\t\"730c22474709a6d17cf11599a80413a84ddb691a3c7b11a6d8d47a2c024b7b56\",\n\t\t\"a085c5eeb39636a21c85a9bc667bae18bf3e327a220ecb3998e317b62ab20ec6\",\n\t\t\"0b7af750e7e96ceb9fe5582bdf9bdafae726427d34447f7245a084b6cf0aa5e5\",\n\t\t\"dffaa5a9779931a2c1194794e6e9a89787557d6cd708d84c74de20ec5e03a7bf\",\n\t\t\"509c4019dd96a337a36149031869e6de5db014ab9ae5d8097ac997ca8f10422a\",\n\t\t\"a385fa48b4f40a2f4ea66de88c0021532299865fe6137d765788f9f856e79453\",\n\t\t\"ff212371e454f8292fd3b13020a3910fc91002a7ab5eb3f297b71df6b7ff9bc1\",\n\t\t\"04289e97041fc025c103141909d2cce649944153822f032b646214a850363618\",\n\t\t\"116294510fba759d19af7a65b915467384258d997695ed7018d8c19d38c29412\",\n\t\t\"dc2f0238e65c0291bedae58cb1c013bd03e0f41f78e1779744ac401952ec2b51\",\n\t}\n\n\tAgentsTestAddresses = []string{\n\t\t\"fetch1y39e4tec9fll66x2k7wed5qn7zhaneayjm55kk\",\n\t\t\"fetch1ufjmhth6dnhrckxrvk05lmt8s2vture23xvwjl\",\n\t\t\"fetch1dja5uazc9n7jpjm94rhmkkmcyv5nj3kt8aexgf\",\n\t\t\"fetch18v5lz9psp53akm26ztk3exytqfdvpnfdsyx232\",\n\t\t\"fetch10u6ra4qmukhf57xadv64jt9jhr9gdrg707x6l9\",\n\t\t\"fetch1hys3k2anw5mxe0y2vksccpe58jyk5gksrsjd60\",\n\t\t\"fetch1t07jnjjtlqa07mstg4gw9twjs2ddtqs3sgtx7c\",\n\t\t\"fetch18sxxgat6uaxqxvd7mgt99y7avyy3c24av36u2l\",\n\t\t\"fetch1sx2rmtndc5t97pn00x76sksrzgc9s2watpgw64\",\n\t\t\"fetch1mwd8n27t68svv4w5urztgw7e3kjh7nqkqz0j94\",\n\t}\n)\n\n/*\n  DHT Network: DHTPeer-to-DHTPeer\n*/\n\n// TestRoutingDHTPeerToSelf dht peer with agent attached\nfunc TestRoutingDHTPeerToSelf(t *testing.T) {\n\topts := []Option{\n\t\tLocalURI(DefaultLocalHost, DefaultLocalPort),\n\t\tPublicURI(DefaultLocalHost, DefaultLocalPort),\n\t\tIdentityFromFetchAIKey(FetchAITestKeys[0]),\n\t\tEnableRelayService(),\n\t\tEnableDelegateService(DefaultDelegatePort),\n\t\tStoreRecordsTo(path.Join(os.TempDir(), \"agents_records_\"+randSeq(5))),\n\t}\n\n\tagentPubKey, err := utils.FetchAIPublicKeyFromFetchAIPrivateKey(AgentsTestKeys[0])\n\tif err != nil {\n\t\tt.Fatal(\"Failed at DHTPeer initialization:\", err)\n\t}\n\n\tsignature, err := utils.SignFetchAI([]byte(FetchAITestPublicKeys[0]), AgentsTestKeys[0])\n\tif err != nil {\n\t\tt.Fatal(\"Failed at DHTPeer initialization:\", err)\n\t}\n\n\trecord := &acn.AgentRecord{LedgerId: DefaultLedger}\n\trecord.Address = AgentsTestAddresses[0]\n\trecord.PublicKey = agentPubKey\n\trecord.PeerPublicKey = FetchAITestPublicKeys[0]\n\trecord.Signature = signature\n\n\topts = append(opts, RegisterAgentAddress(record, func() bool { return true }))\n\n\tdhtPeer, err := New(opts...)\n\tif err != nil {\n\t\tt.Fatal(\"Failed at DHTPeer initialization:\", err)\n\t}\n\tdefer dhtPeer.Close()\n\n\tvar rxEnvelopes []*aea.Envelope\n\tdhtPeer.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxEnvelopes = append(rxEnvelopes, envel)\n\t\treturn nil\n\t})\n\n\terr = dhtPeer.RouteEnvelope(&aea.Envelope{\n\t\tTo:     AgentsTestAddresses[0],\n\t\tSender: AgentsTestAddresses[0],\n\t})\n\tif err != nil {\n\t\tt.Error(\"Failed to Route envelope to local Agent\")\n\t}\n\n\tif len(rxEnvelopes) == 0 {\n\t\tt.Error(\"Failed to Route & Process envelope to local Agent\")\n\t}\n\n}\n\n// TestRoutingDHTPeerToDHTPeerDirect from a dht peer to its bootstrap peer\nfunc TestRoutingDHTPeerToDHTPeerDirect(t *testing.T) {\n\tdhtPeer1, cleanup1, err := SetupLocalDHTPeer(\n\t\tFetchAITestKeys[0], AgentsTestKeys[0], DefaultLocalPort, DefaultDelegatePort,\n\t\t[]string{},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t}\n\tdefer cleanup1()\n\n\tdhtPeer2, cleanup2, err := SetupLocalDHTPeer(\n\t\tFetchAITestKeys[1], AgentsTestKeys[1], DefaultLocalPort+1, DefaultDelegatePort+1,\n\t\t[]string{dhtPeer1.MultiAddr()},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t}\n\tdefer cleanup2()\n\n\trxPeer1 := make(chan *aea.Envelope, 2)\n\tdhtPeer1.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxPeer1 <- envel\n\t\terr := dhtPeer1.RouteEnvelope(&aea.Envelope{\n\t\t\tTo:     envel.Sender,\n\t\t\tSender: envel.To,\n\t\t})\n\t\treturn err\n\t})\n\n\trxPeer2 := make(chan *aea.Envelope, 2)\n\tdhtPeer2.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxPeer2 <- envel\n\t\treturn nil\n\t})\n\n\tensureAddressAnnounced(dhtPeer1, dhtPeer2)\n\n\terr = dhtPeer2.RouteEnvelope(&aea.Envelope{\n\t\tTo:     AgentsTestAddresses[0],\n\t\tSender: AgentsTestAddresses[1],\n\t})\n\tif err != nil {\n\t\tt.Error(\"Failed to RouteEnvelope from peer 2 to peer 1:\", err)\n\t}\n\n\texpectEnvelope(t, rxPeer1)\n\texpectEnvelope(t, rxPeer2)\n}\n\n// TestRoutingDHTPeerToDHTPeerIndirect two dht peers connected to the same peer\nfunc TestRoutingDHTPeerToDHTPeerIndirect(t *testing.T) {\n\tentryPeer, cleanup, err := SetupLocalDHTPeer(\n\t\tFetchAITestKeys[0], AgentsTestKeys[0], DefaultLocalPort, DefaultDelegatePort,\n\t\t[]string{},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t}\n\tdefer cleanup()\n\n\tdhtPeer1, cleanup1, err := SetupLocalDHTPeer(\n\t\tFetchAITestKeys[1], AgentsTestKeys[1], DefaultLocalPort+1, DefaultDelegatePort+1,\n\t\t[]string{entryPeer.MultiAddr()},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t}\n\tdefer cleanup1()\n\n\tdhtPeer2, cleanup2, err := SetupLocalDHTPeer(\n\t\tFetchAITestKeys[2], AgentsTestKeys[2], DefaultLocalPort+2, DefaultDelegatePort+2,\n\t\t[]string{entryPeer.MultiAddr()},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t}\n\tdefer cleanup2()\n\n\trxPeer1 := make(chan *aea.Envelope, 2)\n\tdhtPeer1.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxPeer1 <- envel\n\t\terr := dhtPeer1.RouteEnvelope(&aea.Envelope{\n\t\t\tTo:     envel.Sender,\n\t\t\tSender: envel.To,\n\t\t})\n\t\treturn err\n\t})\n\n\trxPeer2 := make(chan *aea.Envelope, 2)\n\tdhtPeer2.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxPeer2 <- envel\n\t\treturn nil\n\t})\n\n\tensureAddressAnnounced(dhtPeer1, dhtPeer2)\n\n\terr = dhtPeer2.RouteEnvelope(&aea.Envelope{\n\t\tTo:     AgentsTestAddresses[1],\n\t\tSender: AgentsTestAddresses[2],\n\t})\n\tif err != nil {\n\t\tt.Error(\"Failed to RouteEnvelope from peer 2 to peer 1:\", err)\n\t}\n\n\texpectEnvelope(t, rxPeer1)\n\texpectEnvelope(t, rxPeer2)\n}\n\n// TestRoutingDHTPeerToDHTPeerIndirectTwoHops two dht peers connected to different peers\nfunc TestRoutingDHTPeerToDHTPeerIndirectTwoHops(t *testing.T) {\n\tentryPeer1, cleanup, err := SetupLocalDHTPeer(\n\t\tFetchAITestKeys[0], \"\", DefaultLocalPort, DefaultDelegatePort,\n\t\t[]string{},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t}\n\tdefer cleanup()\n\n\tentryPeer2, cleanup, err := SetupLocalDHTPeer(\n\t\tFetchAITestKeys[1], AgentsTestKeys[1], DefaultLocalPort+1, DefaultDelegatePort+1,\n\t\t[]string{entryPeer1.MultiAddr()},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t}\n\tdefer cleanup()\n\n\ttime.Sleep(1 * time.Second)\n\tdhtPeer1, cleanup1, err := SetupLocalDHTPeer(\n\t\tFetchAITestKeys[2], AgentsTestKeys[2], DefaultLocalPort+2, DefaultDelegatePort+2,\n\t\t[]string{entryPeer1.MultiAddr()},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t}\n\tdefer cleanup1()\n\n\tdhtPeer2, cleanup2, err := SetupLocalDHTPeer(\n\t\tFetchAITestKeys[3], AgentsTestKeys[3], DefaultLocalPort+3, DefaultDelegatePort+3,\n\t\t[]string{entryPeer2.MultiAddr()},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t}\n\tdefer cleanup2()\n\n\trxPeer1 := make(chan *aea.Envelope, 2)\n\tdhtPeer1.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxPeer1 <- envel\n\t\terr := dhtPeer1.RouteEnvelope(&aea.Envelope{\n\t\t\tTo:     envel.Sender,\n\t\t\tSender: envel.To,\n\t\t})\n\t\treturn err\n\t})\n\n\trxPeer2 := make(chan *aea.Envelope, 2)\n\tdhtPeer2.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxPeer2 <- envel\n\t\treturn nil\n\t})\n\n\tensureAddressAnnounced(dhtPeer1, dhtPeer2)\n\n\terr = dhtPeer2.RouteEnvelope(&aea.Envelope{\n\t\tTo:     AgentsTestAddresses[2],\n\t\tSender: AgentsTestAddresses[3],\n\t})\n\tif err != nil {\n\t\tt.Error(\"Failed to RouteEnvelope from peer 2 to peer 1:\", err)\n\t}\n\n\texpectEnvelope(t, rxPeer1)\n\texpectEnvelope(t, rxPeer2)\n}\n\n// TestRoutingDHTPeerToDHTPeerFullConnectivity fully connected dht peers network\nfunc TestRoutingDHTPeerToDHTPeerFullConnectivity(t *testing.T) {\n\tpeers := []*DHTPeer{}\n\trxs := []chan *aea.Envelope{}\n\n\tfor i := range FetchAITestKeys {\n\t\tpeer, cleanup, err := SetupLocalDHTPeer(\n\t\t\tFetchAITestKeys[i], AgentsTestKeys[i],\n\t\t\tDefaultLocalPort+uint16(i), DefaultDelegatePort+uint16(i),\n\t\t\tfunc() []string {\n\t\t\t\tmultiaddrs := []string{}\n\t\t\t\tfor _, entryPeer := range peers {\n\t\t\t\t\tmultiaddrs = append(multiaddrs, entryPeer.MultiAddr())\n\t\t\t\t}\n\t\t\t\treturn multiaddrs\n\t\t\t}(),\n\t\t)\n\t\tif err != nil {\n\t\t\tt.Fatal(\"Failed to initialize DHTPeer\", i, \":\", err)\n\t\t}\n\n\t\trx := make(chan *aea.Envelope, 2)\n\t\tpeer.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\t\trx <- envel\n\t\t\tif string(envel.Message) == \"ping\" {\n\t\t\t\terr := peer.RouteEnvelope(&aea.Envelope{\n\t\t\t\t\tTo:      envel.Sender,\n\t\t\t\t\tSender:  envel.To,\n\t\t\t\t\tMessage: []byte(\"ack\"),\n\t\t\t\t})\n\t\t\t\treturn err\n\t\t\t}\n\t\t\treturn nil\n\t\t})\n\n\t\tpeers = append(peers, peer)\n\t\trxs = append(rxs, rx)\n\t\tdefer cleanup()\n\t}\n\n\tensureAddressAnnounced(peers...)\n\n\tfor i := range peers {\n\t\tfor j := range peers {\n\t\t\tfrom := len(peers) - 1 - i\n\t\t\ttarget := j\n\n\t\t\t// Should be able to route to self though\n\t\t\tif from == target {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\terr := peers[from].RouteEnvelope(&aea.Envelope{\n\t\t\t\tTo:      AgentsTestAddresses[target],\n\t\t\t\tSender:  AgentsTestAddresses[from],\n\t\t\t\tMessage: []byte(\"ping\"),\n\t\t\t})\n\n\t\t\tif err != nil {\n\t\t\t\tt.Error(\"Failed to RouteEnvelope from \", from, \"to\", target)\n\t\t\t}\n\n\t\t\texpectEnvelope(t, rxs[target])\n\t\t\texpectEnvelope(t, rxs[from])\n\t\t}\n\t}\n}\n\n/*\n  DHT network: DHTClient\n*/\n\n// TestRoutingDHTClientToDHTPeer dht client to its bootstrap peer\nfunc TestRoutingDHTClientToDHTPeerX(t *testing.T) {\n\tpeer, peerCleanup, err := SetupLocalDHTPeer(\n\t\tFetchAITestKeys[0], AgentsTestKeys[0], DefaultLocalPort, DefaultDelegatePort,\n\t\t[]string{},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t}\n\tdefer peerCleanup()\n\n\tclient, clientCleanup, err := SetupDHTClient(\n\t\tFetchAITestKeys[1], AgentsTestKeys[1], []string{peer.MultiAddr()},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTClient:\", err)\n\t}\n\tdefer clientCleanup()\n\n\trxPeer := make(chan *aea.Envelope, 2)\n\tpeer.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxPeer <- envel\n\t\treturn peer.RouteEnvelope(&aea.Envelope{\n\t\t\tTo:     envel.Sender,\n\t\t\tSender: envel.To,\n\t\t})\n\t})\n\n\trxClient := make(chan *aea.Envelope, 2)\n\tclient.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxClient <- envel\n\t\treturn nil\n\t})\n\n\ttime.Sleep(1 * time.Second)\n\terr = client.RouteEnvelope(&aea.Envelope{\n\t\tTo:     AgentsTestAddresses[0],\n\t\tSender: AgentsTestAddresses[1],\n\t})\n\tif err != nil {\n\t\tt.Error(\"Failed to RouteEnvelope from DHTClient to DHTPeer:\", err)\n\t}\n\n\texpectEnvelope(t, rxPeer)\n\texpectEnvelope(t, rxClient)\n\n}\n\n// TestRoutingDHTClientToDHTPeerIndirect dht client to dht peer different than its bootstrap one\nfunc TestRoutingDHTClientToDHTPeerIndirect(t *testing.T) {\n\tentryPeer, entryPeerCleanup, err := SetupLocalDHTPeer(\n\t\tFetchAITestKeys[0], AgentsTestKeys[0], DefaultLocalPort, DefaultDelegatePort,\n\t\t[]string{},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t}\n\tdefer entryPeerCleanup()\n\n\tpeer, peerCleanup, err := SetupLocalDHTPeer(\n\t\tFetchAITestKeys[1], AgentsTestKeys[1], DefaultLocalPort+1, DefaultDelegatePort+1,\n\t\t[]string{entryPeer.MultiAddr()},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t}\n\tdefer peerCleanup()\n\n\ttime.Sleep(1 * time.Second)\n\tclient, clientCleanup, err := SetupDHTClient(\n\t\tFetchAITestKeys[2], AgentsTestKeys[2], []string{entryPeer.MultiAddr()},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTClient:\", err)\n\t}\n\tdefer clientCleanup()\n\n\trxPeer := make(chan *aea.Envelope, 2)\n\tpeer.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxPeer <- envel\n\t\treturn peer.RouteEnvelope(&aea.Envelope{\n\t\t\tTo:     envel.Sender,\n\t\t\tSender: envel.To,\n\t\t})\n\t})\n\n\trxClient := make(chan *aea.Envelope, 2)\n\tclient.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxClient <- envel\n\t\treturn nil\n\t})\n\n\tensureAddressAnnounced(entryPeer, peer)\n\n\ttime.Sleep(1 * time.Second)\n\terr = client.RouteEnvelope(&aea.Envelope{\n\t\tTo:     AgentsTestAddresses[1],\n\t\tSender: AgentsTestAddresses[2],\n\t})\n\tif err != nil {\n\t\tt.Error(\"Failed to RouteEnvelope from DHTClient to DHTPeer:\", err)\n\t}\n\n\texpectEnvelope(t, rxPeer)\n\texpectEnvelope(t, rxClient)\n}\n\n// TestRoutingDHTClientToDHTClient dht client to dht client connected to the same peer\nfunc TestRoutingDHTClientToDHTClient(t *testing.T) {\n\tpeer, peerCleanup, err := SetupLocalDHTPeer(\n\t\tFetchAITestKeys[0], AgentsTestKeys[0], DefaultLocalPort, DefaultDelegatePort,\n\t\t[]string{},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t}\n\tdefer peerCleanup()\n\n\tclient1, clientCleanup1, err := SetupDHTClient(\n\t\tFetchAITestKeys[1], AgentsTestKeys[1], []string{peer.MultiAddr()},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTClient:\", err)\n\t}\n\tdefer clientCleanup1()\n\n\tclient2, clientCleanup2, err := SetupDHTClient(\n\t\tFetchAITestKeys[2], AgentsTestKeys[2], []string{peer.MultiAddr()},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTClient:\", err)\n\t}\n\tdefer clientCleanup2()\n\n\trxClient1 := make(chan *aea.Envelope, 2)\n\tclient1.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxClient1 <- envel\n\t\treturn client1.RouteEnvelope(&aea.Envelope{\n\t\t\tTo:     envel.Sender,\n\t\t\tSender: envel.To,\n\t\t})\n\t})\n\n\trxClient2 := make(chan *aea.Envelope, 2)\n\tclient2.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxClient2 <- envel\n\t\treturn nil\n\t})\n\n\ttime.Sleep(1 * time.Second)\n\terr = client2.RouteEnvelope(&aea.Envelope{\n\t\tTo:     AgentsTestAddresses[1],\n\t\tSender: AgentsTestAddresses[2],\n\t})\n\tif err != nil {\n\t\tt.Error(\"Failed to RouteEnvelope from DHTClient to DHTClient:\", err)\n\t}\n\n\texpectEnvelope(t, rxClient1)\n\texpectEnvelope(t, rxClient2)\n\n}\n\n// TestRoutingDHTClientToDHTClientIndirect dht client to dht client connected to a different peer\nfunc TestRoutingDHTClientToDHTClientIndirect(t *testing.T) {\n\tpeer1, peerCleanup1, err := SetupLocalDHTPeer(\n\t\tFetchAITestKeys[0], \"\", DefaultLocalPort, DefaultDelegatePort,\n\t\t[]string{},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t}\n\tdefer peerCleanup1()\n\n\tpeer2, peerCleanup2, err := SetupLocalDHTPeer(\n\t\tFetchAITestKeys[1], AgentsTestKeys[1], DefaultLocalPort+1, DefaultDelegatePort+1,\n\t\t[]string{peer1.MultiAddr()},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t}\n\tdefer peerCleanup2()\n\n\tclient1, clientCleanup1, err := SetupDHTClient(\n\t\tFetchAITestKeys[2], AgentsTestKeys[2], []string{peer1.MultiAddr()},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTClient:\", err)\n\t}\n\tdefer clientCleanup1()\n\n\tclient2, clientCleanup2, err := SetupDHTClient(\n\t\tFetchAITestKeys[3], AgentsTestKeys[3], []string{peer2.MultiAddr()},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTClient:\", err)\n\t}\n\tdefer clientCleanup2()\n\n\trxClient1 := make(chan *aea.Envelope, 2)\n\tclient1.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxClient1 <- envel\n\t\treturn client1.RouteEnvelope(&aea.Envelope{\n\t\t\tTo:     envel.Sender,\n\t\t\tSender: envel.To,\n\t\t})\n\t})\n\n\trxClient2 := make(chan *aea.Envelope, 2)\n\tclient2.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxClient2 <- envel\n\t\treturn nil\n\t})\n\n\tensureAddressAnnounced(peer1, peer2)\n\n\ttime.Sleep(1 * time.Second)\n\terr = client2.RouteEnvelope(&aea.Envelope{\n\t\tTo:     AgentsTestAddresses[2],\n\t\tSender: AgentsTestAddresses[3],\n\t})\n\tif err != nil {\n\t\tt.Error(\"Failed to RouteEnvelope from DHTClient to DHTClient:\", err)\n\t}\n\n\texpectEnvelope(t, rxClient1)\n\texpectEnvelope(t, rxClient2)\n\n}\n\n/*\n  DHT network: DelegateClient\n*/\n\n// TestRoutingDelegateClientToDHTPeer\nfunc TestRoutingDelegateClientToDHTPeerX(t *testing.T) {\n\tpeer, peerCleanup, err := SetupLocalDHTPeer(\n\t\tFetchAITestKeys[0], AgentsTestKeys[0], DefaultLocalPort, DefaultDelegatePort,\n\t\t[]string{},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t}\n\tdefer peerCleanup()\n\n\tclient, clientCleanup, err := SetupDelegateClient(\n\t\tAgentsTestKeys[1],\n\t\tDefaultLocalHost,\n\t\tDefaultDelegatePort,\n\t\tFetchAITestPublicKeys[0],\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DelegateClient:\", err)\n\t}\n\tdefer clientCleanup()\n\n\trxPeer := make(chan *aea.Envelope, 2)\n\tpeer.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxPeer <- envel\n\t\treturn nil\n\t})\n\n\terr = client.Send(&aea.Envelope{\n\t\tTo:     AgentsTestAddresses[0],\n\t\tSender: AgentsTestAddresses[1],\n\t})\n\tif err != nil {\n\t\tt.Error(\"Failed to Send envelope from DelegateClient to DHTPeer:\", err)\n\t}\n\n\texpectEnvelope(t, rxPeer)\n\n\terr = peer.RouteEnvelope(&aea.Envelope{\n\t\tTo:     AgentsTestAddresses[1],\n\t\tSender: AgentsTestAddresses[0],\n\t})\n\tif err != nil {\n\t\tt.Error(\"Failed to RouteEnvelope from peer to delegate client:\", err)\n\t}\n\n\texpectEnvelope(t, client.Rx)\n}\n\n// TestRoutingDelegateClientToDHTPeerIndirect\nfunc TestRoutingDelegateClientToDHTPeerIndirect(t *testing.T) {\n\tpeer1, peerCleanup1, err := SetupLocalDHTPeer(\n\t\tFetchAITestKeys[0], AgentsTestKeys[0], DefaultLocalPort, DefaultDelegatePort,\n\t\t[]string{},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t}\n\tdefer peerCleanup1()\n\n\tpeer2, peerCleanup2, err := SetupLocalDHTPeer(\n\t\tFetchAITestKeys[1], AgentsTestKeys[1], DefaultLocalPort+1, DefaultDelegatePort+1,\n\t\t[]string{peer1.MultiAddr()},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t}\n\tdefer peerCleanup2()\n\n\ttime.Sleep(3 * time.Second)\n\tclient, clientCleanup, err := SetupDelegateClient(\n\t\tAgentsTestKeys[2],\n\t\tDefaultLocalHost,\n\t\tDefaultDelegatePort+1,\n\t\tFetchAITestPublicKeys[1],\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DelegateClient:\", err)\n\t}\n\tdefer clientCleanup()\n\n\trxPeer1 := make(chan *aea.Envelope, 20)\n\tpeer1.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxPeer1 <- envel\n\t\treturn nil\n\t})\n\n\tensureAddressAnnounced(peer1, peer2)\n\n\terr = client.Send(&aea.Envelope{\n\t\tTo:     AgentsTestAddresses[0],\n\t\tSender: AgentsTestAddresses[2],\n\t})\n\tif err != nil {\n\t\tt.Error(\"Failed to Send envelope from DelegateClient to DHTPeer:\", err)\n\t}\n\texpectEnvelope(t, rxPeer1)\n\n\terr = peer1.RouteEnvelope(&aea.Envelope{\n\t\tTo:     AgentsTestAddresses[2],\n\t\tSender: AgentsTestAddresses[0],\n\t})\n\tif err != nil {\n\t\tt.Error(\"Failed to RouteEnvelope from peer to delegate client:\", err)\n\t}\n\texpectEnvelope(t, client.Rx)\n}\n\n// TestMessageOrderingWithDelegateClient\nfunc TestMessageOrderingWithDelegateClient(t *testing.T) {\n\tpeer1, peerCleanup1, err := SetupLocalDHTPeer(\n\t\tFetchAITestKeys[0], AgentsTestKeys[0], DefaultLocalPort, DefaultDelegatePort,\n\t\t[]string{},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t}\n\tdefer peerCleanup1()\n\n\tpeer2, peerCleanup2, err := SetupLocalDHTPeer(\n\t\tFetchAITestKeys[1], AgentsTestKeys[1], DefaultLocalPort+1, DefaultDelegatePort+1,\n\t\t[]string{peer1.MultiAddr()},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t}\n\tdefer peerCleanup2()\n\n\ttime.Sleep(1 * time.Second)\n\n\tclient, clientCleanup, err := SetupDelegateClient(\n\t\tAgentsTestKeys[2],\n\t\tDefaultLocalHost,\n\t\tDefaultDelegatePort+1,\n\t\tFetchAITestPublicKeys[1],\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DelegateClient:\", err)\n\t}\n\tdefer clientCleanup()\n\n\trxPeer1 := make(chan *aea.Envelope, 20)\n\tpeer1.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxPeer1 <- envel\n\t\treturn nil\n\t})\n\trxPeer2 := make(chan *aea.Envelope, 20)\n\tpeer2.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxPeer2 <- envel\n\t\treturn nil\n\t})\n\n\tensureAddressAnnounced(peer1, peer2)\n\n\tmax := 10\n\ti := 0\n\tfor x := 0; x < max; x++ {\n\t\tenvelope := &aea.Envelope{\n\t\t\tTo:      AgentsTestAddresses[0],\n\t\t\tSender:  AgentsTestAddresses[2],\n\t\t\tMessage: []byte(strconv.Itoa(i)),\n\t\t}\n\t\terr = client.Send(envelope)\n\t\tif err != nil {\n\t\t\tt.Error(\"Failed to Send envelope from DelegateClient to DHTPeer:\", err)\n\t\t}\n\t\ti++\n\t\tt.Log(\"Sending Envelope : \", envelope)\n\t\t// time.Sleep(100 * time.Millisecond)\n\n\t\tenvelope1 := &aea.Envelope{\n\t\t\tTo:      AgentsTestAddresses[1],\n\t\t\tSender:  AgentsTestAddresses[2],\n\t\t\tMessage: []byte(strconv.Itoa(i)),\n\t\t}\n\t\terr = client.Send(envelope1)\n\t\tif err != nil {\n\t\t\tt.Error(\"Failed to Send envelope from DelegateClient to DHTPeer:\", err)\n\t\t}\n\t\ti++\n\t\tt.Log(\"Sending Envelope : \", envelope1)\n\t\t// time.Sleep(100 * time.Millisecond)\n\t}\n\n\t// go func() {\n\tii := 0\n\tfor x := 0; x < max; x++ {\n\t\texpectEnvelopeOrdered(t, rxPeer1, ii)\n\t\tii++\n\t\tii++\n\t}\n\t// }()\n\n\t// go func() {\n\tiii := 0\n\tfor x := 0; x < max; x++ {\n\t\tiii++\n\t\texpectEnvelopeOrdered(t, rxPeer2, iii)\n\t\tiii++\n\t}\n\t// }()\n\tprint(\"STOP OF THE TEST\")\n}\n\n// TestMessageOrderingWithDelegateClientTwoHops\nfunc TestMessageOrderingWithDelegateClientTwoHops(t *testing.T) {\n\tpeer1Index := 0\n\tpeer2Index := 1\n\tclient1Index := 2\n\tclient2Index := 3\n\tpeer1, peerCleanup1, err := SetupLocalDHTPeer(\n\t\tFetchAITestKeys[peer1Index],\n\t\tAgentsTestKeys[peer1Index],\n\t\tDefaultLocalPort,\n\t\tDefaultDelegatePort,\n\t\t[]string{},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t}\n\tdefer peerCleanup1()\n\n\tpeer2, peerCleanup2, err := SetupLocalDHTPeer(\n\t\tFetchAITestKeys[peer2Index],\n\t\tAgentsTestKeys[peer2Index],\n\t\tDefaultLocalPort+1,\n\t\tDefaultDelegatePort+1,\n\t\t[]string{peer1.MultiAddr()},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t}\n\tdefer peerCleanup2()\n\n\ttime.Sleep(1 * time.Second)\n\n\tclient1, clientCleanup1, err := SetupDelegateClient(\n\t\tAgentsTestKeys[client1Index],\n\t\tDefaultLocalHost,\n\t\tDefaultDelegatePort,\n\t\tFetchAITestPublicKeys[peer1Index],\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DelegateClient:\", err)\n\t}\n\tdefer clientCleanup1()\n\n\tclient2, clientCleanup2, err := SetupDelegateClient(\n\t\tAgentsTestKeys[client2Index],\n\t\tDefaultLocalHost,\n\t\tDefaultDelegatePort+1,\n\t\tFetchAITestPublicKeys[peer2Index],\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DelegateClient:\", err)\n\t}\n\tdefer clientCleanup2()\n\n\trxClient1 := make(chan *aea.Envelope, 20)\n\tclient1.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxClient1 <- envel\n\t\treturn nil\n\t})\n\trxClient2 := make(chan *aea.Envelope, 20)\n\tclient2.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxClient2 <- envel\n\t\treturn nil\n\t})\n\n\tensureAddressAnnounced(peer1, peer2)\n\n\tmax := 100\n\ti := 0\n\tfor x := 0; x < max; x++ {\n\t\tenvelope := &aea.Envelope{\n\t\t\tTo:      AgentsTestAddresses[client2Index],\n\t\t\tSender:  AgentsTestAddresses[client1Index],\n\t\t\tMessage: []byte(strconv.Itoa(i)),\n\t\t}\n\t\terr = client1.Send(envelope)\n\t\tif err != nil {\n\t\t\tt.Error(\"Failed to Send envelope from DelegateClient to DHTPeer:\", err)\n\t\t}\n\t\ti++\n\t\tt.Log(\"Sending Envelope : \", envelope)\n\t\t// time.Sleep(100 * time.Millisecond)\n\n\t\tenvelope1 := &aea.Envelope{\n\t\t\tTo:      AgentsTestAddresses[client1Index],\n\t\t\tSender:  AgentsTestAddresses[client2Index],\n\t\t\tMessage: []byte(strconv.Itoa(i)),\n\t\t}\n\t\terr = client2.Send(envelope1)\n\t\tif err != nil {\n\t\t\tt.Error(\"Failed to Send envelope from DelegateClient to DHTPeer:\", err)\n\t\t}\n\t\ti++\n\t\tt.Log(\"Sending Envelope : \", envelope1)\n\t\t// time.Sleep(100 * time.Millisecond)\n\t}\n\n\t// go func() {\n\tii := 0\n\tfor x := 0; x < max; x++ {\n\t\texpectEnvelopeOrdered(t, rxClient2, ii)\n\t\tii++\n\t\tii++\n\t}\n\t// }()\n\n\t// go func() {\n\tiii := 0\n\tfor x := 0; x < max; x++ {\n\t\tiii++\n\t\texpectEnvelopeOrdered(t, rxClient1, iii)\n\t\tiii++\n\t}\n\t// }()\n\tprint(\"STOP OF THE TEST\")\n}\n\n// TestRoutingDelegateClientToDHTPeerIndirectTwoHops\nfunc TestRoutingDelegateClientToDHTPeerIndirectTwoHops(t *testing.T) {\n\tentryPeer, entryPeerCleanup, err := SetupLocalDHTPeer(\n\t\tFetchAITestKeys[0], AgentsTestKeys[0], DefaultLocalPort, DefaultDelegatePort,\n\t\t[]string{},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t}\n\tdefer entryPeerCleanup()\n\n\tpeer1, peerCleanup1, err := SetupLocalDHTPeer(\n\t\tFetchAITestKeys[1], AgentsTestKeys[1], DefaultLocalPort+1, DefaultDelegatePort+1,\n\t\t[]string{entryPeer.MultiAddr()},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t}\n\tdefer peerCleanup1()\n\n\tpeer2, peerCleanup2, err := SetupLocalDHTPeer(\n\t\tFetchAITestKeys[2], AgentsTestKeys[2], DefaultLocalPort+2, DefaultDelegatePort+2,\n\t\t[]string{entryPeer.MultiAddr()},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t}\n\tdefer peerCleanup2()\n\n\ttime.Sleep(1 * time.Second)\n\tclient, clientCleanup, err := SetupDelegateClient(\n\t\tAgentsTestKeys[3],\n\t\tDefaultLocalHost,\n\t\tDefaultDelegatePort+2,\n\t\tFetchAITestPublicKeys[2],\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DelegateClient:\", err)\n\t}\n\tdefer clientCleanup()\n\n\trxPeer1 := make(chan *aea.Envelope, 2)\n\tpeer1.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxPeer1 <- envel\n\t\treturn nil\n\t})\n\n\tensureAddressAnnounced(entryPeer, peer1, peer2)\n\n\terr = client.Send(&aea.Envelope{\n\t\tTo:     AgentsTestAddresses[1],\n\t\tSender: AgentsTestAddresses[3],\n\t})\n\tif err != nil {\n\t\tt.Error(\"Failed to Send envelope from DelegateClient to DHTPeer:\", err)\n\t}\n\n\texpectEnvelope(t, rxPeer1)\n\n\terr = peer1.RouteEnvelope(&aea.Envelope{\n\t\tTo:     AgentsTestAddresses[3],\n\t\tSender: AgentsTestAddresses[1],\n\t})\n\tif err != nil {\n\t\tt.Error(\"Failed to RouteEnvelope from peer to delegate client:\", err)\n\t}\n\n\texpectEnvelope(t, client.Rx)\n}\n\n// TestRoutingDelegateClientToDelegateClient\nfunc TestRoutingDelegateClientToDelegateClient(t *testing.T) {\n\t_, peerCleanup, err := SetupLocalDHTPeer(\n\t\tFetchAITestKeys[0], AgentsTestKeys[0], DefaultLocalPort, DefaultDelegatePort,\n\t\t[]string{},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t}\n\tdefer peerCleanup()\n\n\tclient1, clientCleanup1, err := SetupDelegateClient(\n\t\tAgentsTestKeys[1],\n\t\tDefaultLocalHost,\n\t\tDefaultDelegatePort,\n\t\tFetchAITestPublicKeys[0],\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DelegateClient:\", err)\n\t}\n\tdefer clientCleanup1()\n\n\tclient2, clientCleanup2, err := SetupDelegateClient(\n\t\tAgentsTestKeys[2],\n\t\tDefaultLocalHost,\n\t\tDefaultDelegatePort,\n\t\tFetchAITestPublicKeys[0],\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DelegateClient:\", err)\n\t}\n\tdefer clientCleanup2()\n\n\ttime.Sleep(1 * time.Second)\n\terr = client1.Send(&aea.Envelope{\n\t\tTo:     AgentsTestAddresses[2],\n\t\tSender: AgentsTestAddresses[1],\n\t})\n\tif err != nil {\n\t\tt.Error(\"Failed to Send envelope from DelegateClient to DelegateClient:\", err)\n\t}\n\n\texpectEnvelope(t, client2.Rx)\n\n\terr = client2.Send(&aea.Envelope{\n\t\tTo:     AgentsTestAddresses[1],\n\t\tSender: AgentsTestAddresses[2],\n\t})\n\tif err != nil {\n\t\tt.Error(\"Failed to Send envelope from DelegateClient to DelegateClient:\", err)\n\t}\n\n\texpectEnvelope(t, client1.Rx)\n}\n\n// TestRoutingDelegateClientToDelegateClientIndirect\nfunc TestRoutingDelegateClientToDelegateClientIndirect(t *testing.T) {\n\tpeer1, peer1Cleanup, err := SetupLocalDHTPeer(\n\t\tFetchAITestKeys[0], \"\", DefaultLocalPort, DefaultDelegatePort,\n\t\t[]string{},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t}\n\tdefer peer1Cleanup()\n\n\tpeer2, peer2Cleanup, err := SetupLocalDHTPeer(\n\t\tFetchAITestKeys[1], AgentsTestKeys[1], DefaultLocalPort+1, DefaultDelegatePort+1,\n\t\t[]string{peer1.MultiAddr()},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t}\n\tdefer peer2Cleanup()\n\n\tclient1, clientCleanup1, err := SetupDelegateClient(\n\t\tAgentsTestKeys[2],\n\t\tDefaultLocalHost,\n\t\tDefaultDelegatePort,\n\t\tFetchAITestPublicKeys[0],\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DelegateClient:\", err)\n\t}\n\tdefer clientCleanup1()\n\n\tclient2, clientCleanup2, err := SetupDelegateClient(\n\t\tAgentsTestKeys[3],\n\t\tDefaultLocalHost,\n\t\tDefaultDelegatePort+1,\n\t\tFetchAITestPublicKeys[1],\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DelegateClient:\", err)\n\t}\n\tdefer clientCleanup2()\n\n\tensureAddressAnnounced(peer1, peer2)\n\n\terr = client1.Send(&aea.Envelope{\n\t\tTo:     AgentsTestAddresses[3],\n\t\tSender: AgentsTestAddresses[2],\n\t})\n\tif err != nil {\n\t\tt.Error(\"Failed to Send envelope from DelegateClient to DelegateClient:\", err)\n\t}\n\n\texpectEnvelope(t, client2.Rx)\n\n\terr = client2.Send(&aea.Envelope{\n\t\tTo:     AgentsTestAddresses[2],\n\t\tSender: AgentsTestAddresses[3],\n\t})\n\tif err != nil {\n\t\tt.Error(\"Failed to Send envelope from DelegateClient to DelegateClient:\", err)\n\t}\n\n\texpectEnvelope(t, client1.Rx)\n}\n\n// TestRoutingDelegateClientToDHTClientDirect\nfunc TestRoutingDelegateClientToDHTClientDirect(t *testing.T) {\n\tpeer, peerCleanup, err := SetupLocalDHTPeer(\n\t\tFetchAITestKeys[0], \"\", DefaultLocalPort, DefaultDelegatePort,\n\t\t[]string{},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t}\n\tdefer peerCleanup()\n\n\tdhtClient, dhtClientCleanup, err := SetupDHTClient(\n\t\tFetchAITestKeys[1], AgentsTestKeys[1], []string{peer.MultiAddr()},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTClient:\", err)\n\t}\n\tdefer dhtClientCleanup()\n\n\tdelegateClient, delegateClientCleanup, err := SetupDelegateClient(\n\t\tAgentsTestKeys[2],\n\t\tDefaultLocalHost,\n\t\tDefaultDelegatePort,\n\t\tFetchAITestPublicKeys[0],\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DelegateClient:\", err)\n\t}\n\tdefer delegateClientCleanup()\n\n\trxClientDHT := make(chan *aea.Envelope, 2)\n\tdhtClient.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxClientDHT <- envel\n\t\treturn dhtClient.RouteEnvelope(&aea.Envelope{\n\t\t\tTo:     envel.Sender,\n\t\t\tSender: envel.To,\n\t\t})\n\t})\n\n\ttime.Sleep(1 * time.Second)\n\terr = delegateClient.Send(&aea.Envelope{\n\t\tTo:     AgentsTestAddresses[1],\n\t\tSender: AgentsTestAddresses[2],\n\t})\n\tif err != nil {\n\t\tt.Error(\"Failed to Send envelope from DelegateClient to DHTClient:\", err)\n\t}\n\n\texpectEnvelope(t, rxClientDHT)\n\texpectEnvelope(t, delegateClient.Rx)\n}\n\n// TestRoutingDelegateClientToDHTClientIndirect\nfunc TestRoutingDelegateClientToDHTClientIndirect(t *testing.T) {\n\tpeer1, peerCleanup1, err := SetupLocalDHTPeer(\n\t\tFetchAITestKeys[0], AgentsTestKeys[0], DefaultLocalPort, DefaultDelegatePort,\n\t\t[]string{},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t}\n\tdefer peerCleanup1()\n\n\tpeer2, peerCleanup2, err := SetupLocalDHTPeer(\n\t\tFetchAITestKeys[1], AgentsTestKeys[1], DefaultLocalPort+1, DefaultDelegatePort+1,\n\t\t[]string{peer1.MultiAddr()},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t}\n\tdefer peerCleanup2()\n\n\tdhtClient, dhtClientCleanup, err := SetupDHTClient(\n\t\tFetchAITestKeys[2], AgentsTestKeys[2], []string{peer1.MultiAddr()},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTClient:\", err)\n\t}\n\tdefer dhtClientCleanup()\n\n\tdelegateClient, delegateClientCleanup, err := SetupDelegateClient(\n\t\tAgentsTestKeys[3], DefaultLocalHost, DefaultDelegatePort+1, FetchAITestPublicKeys[1],\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DelegateClient:\", err)\n\t}\n\tdefer delegateClientCleanup()\n\n\trxClientDHT := make(chan *aea.Envelope, 2)\n\tdhtClient.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxClientDHT <- envel\n\t\treturn dhtClient.RouteEnvelope(&aea.Envelope{\n\t\t\tTo:     envel.Sender,\n\t\t\tSender: envel.To,\n\t\t})\n\t})\n\n\tensureAddressAnnounced(peer1, peer2)\n\n\ttime.Sleep(3 * time.Second)\n\n\terr = delegateClient.Send(&aea.Envelope{\n\t\tTo:     AgentsTestAddresses[2],\n\t\tSender: AgentsTestAddresses[3],\n\t})\n\tif err != nil {\n\t\tt.Error(\"Failed to Send envelope from DelegateClient to DHTClient:\", err)\n\t}\n\n\texpectEnvelope(t, rxClientDHT)\n\texpectEnvelope(t, delegateClient.Rx)\n}\n\n/*\n  DHT network: all-to-all\n*/\n\n/*\n\t\t\t\t\t\t\t\t\t  Network topology\n\n\t DHTClient -------                                                 -- DelegateClient\n\t\t\t\t\t |                                                 |\n\t DHTClient -------                                                 -- DelegateClient\n\t\t\t\t\t |                                                 |\n\t\t\t\t\t |-- DHTPeer --- DHTPeeer -- DHTPeer --- DHTPeer --|\n\t\t\t\t\t |                                                 |\n\t DelegateClient --                                                 ------- DHTClient\n*/\n\n// TestRoutingAlltoAll\nfunc TestRoutingAllToAll(t *testing.T) {\n\trxs := []chan *aea.Envelope{}\n\tsend := []func(*aea.Envelope) error{}\n\n\t// setup DHTPeers\n\n\tdhtPeer1, dhtPeerCleanup1, err := SetupLocalDHTPeer(\n\t\tFetchAITestKeys[0], AgentsTestKeys[0], DefaultLocalPort, DefaultDelegatePort,\n\t\t[]string{},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t}\n\tdefer dhtPeerCleanup1()\n\n\trxPeerDHT1 := make(chan *aea.Envelope, 100)\n\tdhtPeer1.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxPeerDHT1 <- envel\n\t\tif string(envel.Message) == \"ping\" {\n\t\t\terr := dhtPeer1.RouteEnvelope(&aea.Envelope{\n\t\t\t\tTo:      envel.Sender,\n\t\t\t\tSender:  envel.To,\n\t\t\t\tMessage: []byte(\"ack\"),\n\t\t\t})\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t})\n\n\trxs = append(rxs, rxPeerDHT1)\n\tsend = append(send, func(envel *aea.Envelope) error {\n\t\treturn dhtPeer1.RouteEnvelope(envel)\n\t})\n\n\tdhtPeer2, dhtPeerCleanup2, err := SetupLocalDHTPeer(\n\t\tFetchAITestKeys[1], AgentsTestKeys[1], DefaultLocalPort+1, DefaultDelegatePort+1,\n\t\t[]string{dhtPeer1.MultiAddr()},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t}\n\tdefer dhtPeerCleanup2()\n\n\trxPeerDHT2 := make(chan *aea.Envelope, 100)\n\tdhtPeer2.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxPeerDHT2 <- envel\n\t\tif string(envel.Message) == \"ping\" {\n\t\t\terr := dhtPeer2.RouteEnvelope(&aea.Envelope{\n\t\t\t\tTo:      envel.Sender,\n\t\t\t\tSender:  envel.To,\n\t\t\t\tMessage: []byte(\"ack\"),\n\t\t\t})\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t})\n\n\trxs = append(rxs, rxPeerDHT2)\n\n\tsend = append(send, func(envel *aea.Envelope) error {\n\t\treturn dhtPeer2.RouteEnvelope(envel)\n\t})\n\n\tdhtPeer3, dhtPeerCleanup3, err := SetupLocalDHTPeer(\n\t\tFetchAITestKeys[2], AgentsTestKeys[2], DefaultLocalPort+2, DefaultDelegatePort+2,\n\t\t[]string{dhtPeer1.MultiAddr()},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t}\n\tdefer dhtPeerCleanup3()\n\n\trxPeerDHT3 := make(chan *aea.Envelope, 100)\n\tdhtPeer3.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxPeerDHT3 <- envel\n\t\tif string(envel.Message) == \"ping\" {\n\t\t\terr := dhtPeer3.RouteEnvelope(&aea.Envelope{\n\t\t\t\tTo:      envel.Sender,\n\t\t\t\tSender:  envel.To,\n\t\t\t\tMessage: []byte(\"ack\"),\n\t\t\t})\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t})\n\n\trxs = append(rxs, rxPeerDHT3)\n\tsend = append(send, func(envel *aea.Envelope) error {\n\t\treturn dhtPeer3.RouteEnvelope(envel)\n\t})\n\n\tdhtPeer4, dhtPeerCleanup4, err := SetupLocalDHTPeer(\n\t\tFetchAITestKeys[3], AgentsTestKeys[3], DefaultLocalPort+3, DefaultDelegatePort+3,\n\t\t[]string{dhtPeer2.MultiAddr()},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTPeer:\", err)\n\t}\n\tdefer dhtPeerCleanup4()\n\n\trxPeerDHT4 := make(chan *aea.Envelope, 100)\n\tdhtPeer4.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxPeerDHT4 <- envel\n\t\tif string(envel.Message) == \"ping\" {\n\t\t\terr := dhtPeer4.RouteEnvelope(&aea.Envelope{\n\t\t\t\tTo:      envel.Sender,\n\t\t\t\tSender:  envel.To,\n\t\t\t\tMessage: []byte(\"ack\"),\n\t\t\t})\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t})\n\n\trxs = append(rxs, rxPeerDHT4)\n\tsend = append(send, func(envel *aea.Envelope) error {\n\t\treturn dhtPeer4.RouteEnvelope(envel)\n\t})\n\n\t// setup DHTClients\n\n\tdhtClient1, dhtClientCleanup1, err := SetupDHTClient(\n\t\tFetchAITestKeys[4], AgentsTestKeys[4], []string{dhtPeer3.MultiAddr()},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTClient:\", err)\n\t}\n\tdefer dhtClientCleanup1()\n\n\trxClientDHT1 := make(chan *aea.Envelope, 100)\n\tdhtClient1.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxClientDHT1 <- envel\n\t\tif string(envel.Message) == \"ping\" {\n\t\t\terr := dhtClient1.RouteEnvelope(&aea.Envelope{\n\t\t\t\tTo:      envel.Sender,\n\t\t\t\tSender:  envel.To,\n\t\t\t\tMessage: []byte(\"ack\"),\n\t\t\t})\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t})\n\n\trxs = append(rxs, rxClientDHT1)\n\tsend = append(send, func(envel *aea.Envelope) error {\n\t\treturn dhtClient1.RouteEnvelope(envel)\n\t})\n\n\tdhtClient2, dhtClientCleanup2, err := SetupDHTClient(\n\t\tFetchAITestKeys[5], AgentsTestKeys[5], []string{dhtPeer3.MultiAddr()},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTClient:\", err)\n\t}\n\tdefer dhtClientCleanup2()\n\n\trxClientDHT2 := make(chan *aea.Envelope, 100)\n\tdhtClient2.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxClientDHT2 <- envel\n\t\tif string(envel.Message) == \"ping\" {\n\t\t\terr := dhtClient2.RouteEnvelope(&aea.Envelope{\n\t\t\t\tTo:      envel.Sender,\n\t\t\t\tSender:  envel.To,\n\t\t\t\tMessage: []byte(\"ack\"),\n\t\t\t})\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t})\n\n\trxs = append(rxs, rxClientDHT2)\n\tsend = append(send, func(envel *aea.Envelope) error {\n\t\treturn dhtClient2.RouteEnvelope(envel)\n\t})\n\n\tdhtClient3, dhtClientCleanup3, err := SetupDHTClient(\n\t\tFetchAITestKeys[6], AgentsTestKeys[6], []string{dhtPeer4.MultiAddr()},\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DHTClient:\", err)\n\t}\n\tdefer dhtClientCleanup3()\n\n\trxClientDHT3 := make(chan *aea.Envelope, 100)\n\tdhtClient3.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxClientDHT3 <- envel\n\t\tif string(envel.Message) == \"ping\" {\n\t\t\terr := dhtClient3.RouteEnvelope(&aea.Envelope{\n\t\t\t\tTo:      envel.Sender,\n\t\t\t\tSender:  envel.To,\n\t\t\t\tMessage: []byte(\"ack\"),\n\t\t\t})\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t})\n\n\trxs = append(rxs, rxClientDHT3)\n\tsend = append(send, func(envel *aea.Envelope) error {\n\t\treturn dhtClient3.RouteEnvelope(envel)\n\t})\n\n\t// setup DelegateClients\n\n\tdelegateClient1, delegateClientCleanup1, err := SetupDelegateClient(\n\t\tAgentsTestKeys[7], DefaultLocalHost, DefaultDelegatePort+2, FetchAITestPublicKeys[2],\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DelegateClient:\", err)\n\t}\n\tdefer delegateClientCleanup1()\n\n\trxClientDelegate1 := make(chan *aea.Envelope, 100)\n\tdelegateClient1.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxClientDelegate1 <- envel\n\t\tif string(envel.Message) == \"ping\" {\n\t\t\terr := delegateClient1.Send(&aea.Envelope{\n\t\t\t\tTo:      envel.Sender,\n\t\t\t\tSender:  envel.To,\n\t\t\t\tMessage: []byte(\"ack\"),\n\t\t\t})\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t})\n\n\trxs = append(rxs, rxClientDelegate1)\n\tsend = append(send, func(envel *aea.Envelope) error {\n\t\treturn delegateClient1.Send(envel)\n\t})\n\n\tdelegateClient2, delegateClientCleanup2, err := SetupDelegateClient(\n\t\tAgentsTestKeys[8], DefaultLocalHost, DefaultDelegatePort+3, FetchAITestPublicKeys[3],\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DelegateClient:\", err)\n\t}\n\tdefer delegateClientCleanup2()\n\n\trxClientDelegate2 := make(chan *aea.Envelope, 100)\n\tdelegateClient2.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxClientDelegate2 <- envel\n\t\tif string(envel.Message) == \"ping\" {\n\t\t\terr := delegateClient2.Send(&aea.Envelope{\n\t\t\t\tTo:      envel.Sender,\n\t\t\t\tSender:  envel.To,\n\t\t\t\tMessage: []byte(\"ack\"),\n\t\t\t})\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t})\n\n\trxs = append(rxs, rxClientDelegate2)\n\tsend = append(send, func(envel *aea.Envelope) error {\n\t\treturn delegateClient2.Send(envel)\n\t})\n\n\tdelegateClient3, delegateClientCleanup3, err := SetupDelegateClient(\n\t\tAgentsTestKeys[9], DefaultLocalHost, DefaultDelegatePort+3, FetchAITestPublicKeys[3],\n\t)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to initialize DelegateClient:\", err)\n\t}\n\tdefer delegateClientCleanup3()\n\n\trxClientDelegate3 := make(chan *aea.Envelope, 100)\n\tdelegateClient3.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\trxClientDelegate3 <- envel\n\t\tif string(envel.Message) == \"ping\" {\n\t\t\terr := delegateClient3.Send(&aea.Envelope{\n\t\t\t\tTo:      envel.Sender,\n\t\t\t\tSender:  envel.To,\n\t\t\t\tMessage: []byte(\"ack\"),\n\t\t\t})\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t})\n\n\trxs = append(rxs, rxClientDelegate3)\n\tsend = append(send, func(envel *aea.Envelope) error {\n\t\treturn delegateClient3.Send(envel)\n\t})\n\n\t// Send envelope from everyone to everyone else and expect an echo back\n\n\tensureAddressAnnounced(dhtPeer1, dhtPeer2, dhtPeer3, dhtPeer4)\n\n\tfor i := range AgentsTestAddresses {\n\t\tfor j := range AgentsTestAddresses {\n\t\t\tfrom := len(AgentsTestAddresses) - 1 - i\n\t\t\ttarget := j\n\n\t\t\t// Should be able to route to self though\n\t\t\tif from == target {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\terr := send[from](&aea.Envelope{\n\t\t\t\tTo:      AgentsTestAddresses[target],\n\t\t\t\tSender:  AgentsTestAddresses[from],\n\t\t\t\tMessage: []byte(\"ping\"),\n\t\t\t})\n\n\t\t\tif err != nil {\n\t\t\t\tt.Error(\"Failed to RouteEnvelope from \", from, \"to\", target)\n\t\t\t}\n\t\t}\n\t}\n\tfor i := range AgentsTestAddresses {\n\t\tfor j := range AgentsTestAddresses {\n\t\t\tfrom := len(AgentsTestAddresses) - 1 - i\n\t\t\ttarget := j\n\t\t\tif from == target {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\texpectEnvelope(t, rxs[target])\n\t\t\texpectEnvelope(t, rxs[from])\n\t\t}\n\t}\n\n}\n\n/*\n  Helpers\n  TOFIX(LR) how to share test helpers between packages tests\n   without having circular dependencies\n*/\n\nfunc randSeq(n int) string {\n\trand.Seed(time.Now().UnixNano())\n\tvar letters = []rune(\"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\")\n\tb := make([]rune, n)\n\tfor i := range b {\n\t\tb[i] = letters[rand.Intn(len(letters))]\n\t}\n\treturn string(b)\n}\n\nfunc SetupLocalDHTPeer(\n\tkey string,\n\tagentKey string,\n\tdhtPort uint16,\n\tdelegatePort uint16,\n\tentry []string,\n) (*DHTPeer, func(), error) {\n\topts := []Option{\n\t\tLocalURI(DefaultLocalHost, dhtPort),\n\t\tPublicURI(DefaultLocalHost, dhtPort),\n\t\tIdentityFromFetchAIKey(key),\n\t\tEnableRelayService(),\n\t\tBootstrapFrom(entry),\n\t\tStoreRecordsTo(path.Join(os.TempDir(), \"agents_records_\"+randSeq(5))),\n\t}\n\n\tif agentKey != \"\" {\n\t\tagentPubKey, err := utils.FetchAIPublicKeyFromFetchAIPrivateKey(agentKey)\n\t\tif err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\n\t\tagentAddress, err := utils.FetchAIAddressFromPublicKey(agentPubKey)\n\t\tif err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\n\t\tpeerPubKey, err := utils.FetchAIPublicKeyFromFetchAIPrivateKey(key)\n\t\tif err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\n\t\tsignature, err := utils.SignFetchAI([]byte(peerPubKey), agentKey)\n\t\tif err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\n\t\trecord := &acn.AgentRecord{LedgerId: DefaultLedger}\n\t\trecord.Address = agentAddress\n\t\trecord.PublicKey = agentPubKey\n\t\trecord.PeerPublicKey = peerPubKey\n\t\trecord.Signature = signature\n\n\t\topts = append(opts, RegisterAgentAddress(record, func() bool { return true }))\n\t}\n\n\tif delegatePort != 0 {\n\t\topts = append(opts, EnableDelegateService(delegatePort))\n\t}\n\n\tdhtPeer, err := New(opts...)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\treturn dhtPeer, func() { println(\"dhtpeer going to be closed!\"); dhtPeer.Close() }, nil\n\n}\n\n// DHTClient\n\nfunc SetupDHTClient(\n\tkey string,\n\tagentKey string,\n\tentry []string,\n) (*dhtclient.DHTClient, func(), error) {\n\n\tagentPubKey, err := utils.FetchAIPublicKeyFromFetchAIPrivateKey(agentKey)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tagentAddress, err := utils.FetchAIAddressFromPublicKey(agentPubKey)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tpeerPubKey, err := utils.FetchAIPublicKeyFromFetchAIPrivateKey(key)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tsignature, err := utils.SignFetchAI([]byte(peerPubKey), agentKey)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\trecord := &acn.AgentRecord{LedgerId: DefaultLedger}\n\trecord.Address = agentAddress\n\trecord.PublicKey = agentPubKey\n\trecord.PeerPublicKey = peerPubKey\n\trecord.Signature = signature\n\n\topts := []dhtclient.Option{\n\t\tdhtclient.IdentityFromFetchAIKey(key),\n\t\tdhtclient.RegisterAgentAddress(record, func() bool { return true }),\n\t\tdhtclient.BootstrapFrom(entry),\n\t}\n\n\tdhtClient, err := dhtclient.New(opts...)\n\tif err != nil {\n\t\tprintln(\"dhtclient.New:\", err.Error())\n\t\treturn nil, nil, err\n\t}\n\n\treturn dhtClient, func() { println(\"dhtclient going to be closed!\"); dhtClient.Close() }, nil\n}\n\n// Delegate tcp client for tests only\n\ntype DelegateClient struct {\n\tAgentAddress    string\n\tAgentKey        string\n\tAgentPubKey     string\n\tPeerPubKey      string\n\tPoR             string\n\tRx              chan *aea.Envelope\n\tConn            net.Conn\n\tprocessEnvelope func(*aea.Envelope) error\n\tacn_status_chan chan *acn.StatusBody\n}\n\nfunc (client *DelegateClient) AddAcnStatusMessage(status *acn.StatusBody, counterpartyID string) {\n\t//client.acn_status_chan <- status\n}\n\nfunc (client *DelegateClient) Close() error {\n\treturn client.Conn.Close()\n}\n\nfunc (client *DelegateClient) Send(envelope *aea.Envelope) error {\n\tdata, err := aea.MakeAcnMessageFromEnvelope(envelope)\n\tif err != nil {\n\t\tprintln(\"while serializing envelope:\", err.Error())\n\t\treturn err\n\t}\n\terr = utils.WriteBytesConn(client.Conn, data)\n\tif err != nil {\n\t\tprintln(\"while sending envelope:\", err.Error())\n\t\treturn err\n\t}\n\treturn err\n}\n\nfunc (client *DelegateClient) ProcessEnvelope(fn func(*aea.Envelope) error) {\n\tclient.processEnvelope = fn\n}\n\nfunc ValidateTLSSignature(\n\ttlsSignature []byte,\n\tsessionPubKey *ecdsa.PublicKey,\n\tpeerPubKey string,\n) error {\n\tsessionPubKeyBytes := elliptic.Marshal(sessionPubKey.Curve, sessionPubKey.X, sessionPubKey.Y)\n\tverifyKey, err := utils.PubKeyFromFetchAIPublicKey(peerPubKey)\n\tif err != nil {\n\t\treturn err\n\t}\n\tok, err := verifyKey.Verify(sessionPubKeyBytes, tlsSignature)\n\n\tif err != nil {\n\t\treturn err\n\t}\n\tif !ok {\n\t\treturn errors.New(\"error on signature validation for tls start\")\n\t}\n\treturn nil\n}\n\nfunc SetupDelegateClient(\n\tkey string,\n\thost string,\n\tport uint16,\n\tpeerPubKey string,\n) (*DelegateClient, func(), error) {\n\tvar err error\n\tclient := &DelegateClient{}\n\tclient.AgentKey = key\n\n\tclient.acn_status_chan = make(chan *acn.StatusBody, 10000)\n\n\tpubKey, err := utils.FetchAIPublicKeyFromFetchAIPrivateKey(key)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\tclient.AgentPubKey = pubKey\n\n\taddress, err := utils.FetchAIAddressFromPublicKey(pubKey)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\tclient.AgentAddress = address\n\n\tsignature, err := utils.SignFetchAI([]byte(peerPubKey), key)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\tclient.PoR = signature\n\n\tclient.Rx = make(chan *aea.Envelope, 2)\n\tconf := &tls.Config{\n\t\tInsecureSkipVerify: true,\n\t}\n\tclient.Conn, err = tls.Dial(\"tcp\", host+\":\"+strconv.FormatInt(int64(port), 10), conf)\n\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tcertPubKey := client.Conn.(*tls.Conn).ConnectionState().PeerCertificates[0].PublicKey.(*ecdsa.PublicKey)\n\n\ttlsSignature, _ := utils.ReadBytesConn(client.Conn)\n\terr = ValidateTLSSignature(tlsSignature, certPubKey, peerPubKey)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\trecord := &acn.AgentRecord{LedgerId: DefaultLedger}\n\trecord.Address = address\n\trecord.PublicKey = pubKey\n\trecord.PeerPublicKey = peerPubKey\n\trecord.Signature = signature\n\tregistration := &acn.RegisterPerformative{Record: record}\n\tmsg := &acn.AcnMessage{\n\t\tPerformative: &acn.Register{Register: registration},\n\t}\n\tdata, err := proto.Marshal(msg)\n\tignore(err)\n\terr = utils.WriteBytesConn(client.Conn, data)\n\tignore(err)\n\tdata, err = utils.ReadBytesConn(client.Conn)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\tresponse := &acn.AcnMessage{}\n\terr = proto.Unmarshal(data, response)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\t// Get Status message\n\tvar status *acn.StatusPerformative\n\tswitch pl := response.Performative.(type) {\n\tcase *acn.Status:\n\t\tstatus = pl.Status\n\tdefault:\n\t\treturn nil, nil, err\n\t}\n\n\tif status.Body.Code != acn.SUCCESS {\n\t\tprintln(\"Registration error:\", status.Body.String())\n\t\treturn nil, nil, errors.New(status.Body.String())\n\t}\n\n\tpipe := utils.ConnPipe{Conn: client.Conn}\n\tgo func() {\n\t\tfor {\n\t\t\tenvel, err := aea.HandleAcnMessageFromPipe(pipe, client, \"\")\n\t\t\tif err != nil {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tif envel == nil {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\t_ = acn.SendAcnSuccess(pipe)\n\n\t\t\tif client.processEnvelope != nil {\n\t\t\t\terr = client.processEnvelope(envel)\n\t\t\t\tignore(err)\n\t\t\t} else {\n\t\t\t\tclient.Rx <- envel\n\t\t\t}\n\t\t}\n\t}()\n\n\treturn client, func() { client.Close() }, nil\n}\n\nfunc expectEnvelope(t *testing.T, rx chan *aea.Envelope) {\n\ttimeout := time.After(EnvelopeDeliveryTimeout)\n\tselect {\n\tcase envel := <-rx:\n\t\tt.Log(\"Received envelope\", envel)\n\tcase <-timeout:\n\t\tt.Error(\"Failed to receive envelope before timeout\")\n\t}\n}\n\nfunc expectEnvelopeOrdered(t *testing.T, rx chan *aea.Envelope, counter int) {\n\ttimeout := time.After(EnvelopeDeliveryTimeout)\n\tselect {\n\tcase envel := <-rx:\n\t\tt.Log(\"Received envelope\", envel)\n\t\tif envel == nil {\n\t\t\tt.Log(\"Empty envelope. exit\")\n\t\t\treturn\n\t\t}\n\t\tmessage, _ := strconv.Atoi(string(envel.Message))\n\t\tif message != counter {\n\t\t\tlog.Fatalf(\"Expected counter %d received counter %d\", counter, message)\n\t\t}\n\tcase <-timeout:\n\t\tt.Error(\"Failed to receive envelope before timeout\")\n\t}\n}\n\nfunc ensureAddressAnnounced(peers ...*DHTPeer) {\n\tfor _, peer := range peers {\n\t\tctx, cancel := context.WithTimeout(context.Background(), DHTPeerSetupTimeout)\n\t\tdefer cancel()\n\tL:\n\t\tfor !peer.IsAddressAnnounced(peer.myAgentAddress) {\n\t\t\tselect {\n\t\t\tcase <-ctx.Done():\n\t\t\t\tbreak L\n\t\t\tcase <-time.After(5 * time.Millisecond):\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc TestFetchAICrypto(t *testing.T) {\n\tpublicKey := \"02358e3e42a6ba15cf6b2ba6eb05f02b8893acf82b316d7dd9cda702b0892b8c71\"\n\taddress := \"fetch19dq2mkcpp6x0aypxt9c9gz6n4fqvax0x9a7t5r\"\n\tpeerPublicKey := \"027af21aff853b9d9589867ea142b0a60a9611fc8e1fae04c2f7144113fa4e938e\"\n\tpySigStrCanonize := \"N/GOa7/m3HU8/gpLJ88VCQ6vXsdrfiiYcqnNtF+c2N9VG9ZIiycykN4hdbpbOCGrChMYZQA3G1GpozsShrUBgg==\"\n\n\taddressFromPublicKey, _ := utils.FetchAIAddressFromPublicKey(publicKey)\n\tif address != addressFromPublicKey {\n\t\tt.Error(\"[ERR] Addresses don't match\")\n\t} else {\n\t\tt.Log(\"[OK] Agent address matches its public key\")\n\t}\n\n\tvalid, err := utils.VerifyFetchAISignatureBTC(\n\t\t[]byte(peerPublicKey),\n\t\tpySigStrCanonize,\n\t\tpublicKey,\n\t)\n\tif !valid {\n\t\tt.Errorf(\"Signature using BTC don't match %s\", err.Error())\n\t}\n\tvalid, err = utils.VerifyFetchAISignatureLibp2p(\n\t\t[]byte(peerPublicKey),\n\t\tpySigStrCanonize,\n\t\tpublicKey,\n\t)\n\tif !valid {\n\t\tt.Errorf(\"Signature using LPP don't match %s\", err.Error())\n\t}\n}\n\nfunc TestEthereumCrypto(t *testing.T) {\n\t//privateKey := \"0xb60fe8027fb82f1a1bd6b8e66d4400f858989a2c67428a4e7f589441700339b0\"\n\tpublicKey := \"0xf753e5a9e2368e97f4db869a0d956d3ffb64672d6392670572906c786b5712ada13b6bff882951b3ba3dd65bdacc915c2b532efc3f183aa44657205c6c337225\"\n\taddress := \"0xb8d8c62d4a1999b7aea0aebBD5020244a4a9bAD8\"\n\tpublicKeySignature := \"0x304c2ba4ae7fa71295bfc2920b9c1268d574d65531f1f4d2117fc1439a45310c37ab75085a9df2a4169a4d47982b330a4387b1ded0c8881b030629db30bbaf3a1c\"\n\n\taddFromPublicKey, err := utils.EthereumAddressFromPublicKey(publicKey)\n\tif err != nil || addFromPublicKey != address {\n\t\tt.Error(\n\t\t\t\"Error when computing address from public key or address and public key don't match\",\n\t\t)\n\t}\n\n\t_, err = utils.BTCPubKeyFromEthereumPublicKey(publicKey)\n\tif err != nil {\n\t\tt.Errorf(\"While building BTC public key from string: %s\", err.Error())\n\t}\n\n\t/*\n\t\t  ethSig, err := secp256k1.Sign(hashedPublicKey, hexutil.MustDecode(privateKey))\n\t\t  if err != nil {\n\t\t\t  t.Error(err.Error())\n\t\t  }\n\t\t  println(hexutil.Encode(ethSig))\n\t\t  hash := sha3.NewLegacyKeccak256()\n\t\t  _, err = hash.Write([]byte(publicKey))\n\t\t  if err != nil {\n\t\t\t  t.Error(err.Error())\n\t\t  }\n\t\t  sha3KeccakHash := hash.Sum(nil)\n\t*/\n\n\tvalid, err := utils.VerifyEthereumSignatureETH([]byte(publicKey), publicKeySignature, publicKey)\n\tif err != nil {\n\t\tt.Error(err.Error())\n\t}\n\n\tif !valid {\n\t\tt.Errorf(\"Signer address don't match %s\", addFromPublicKey)\n\t}\n}\n\n// Perform tests for tls signature generation and checking\nfunc TestTLSSignatureValidation(t *testing.T) {\n\tkey1, pubKey, _ := utils.KeyPairFromFetchAIKey(FetchAITestKeys[0])\n\tkey2, _, _ := utils.KeyPairFromFetchAIKey(FetchAITestKeys[1])\n\tpeerPubKey, _ := utils.FetchAIPublicKeyFromPubKey(pubKey)\n\n\tcert, err := generate_x509_cert()\n\tsessionPubKey := cert.PrivateKey.(*ecdsa.PrivateKey).Public().(*ecdsa.PublicKey)\n\n\tif err != nil {\n\t\tt.Fatal(\"Failed to generate certificate\")\n\t}\n\n\t// valid\n\ttlsSignature, err := makeSessionKeySignature(cert, key1)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to make signature\")\n\t}\n\terr = ValidateTLSSignature(tlsSignature, sessionPubKey, peerPubKey)\n\tif err != nil {\n\t\tt.Fatal(\"Signature is invalid, but expected to be ok\")\n\t}\n\n\t//invalid\n\ttlsSignature, err = makeSessionKeySignature(cert, key2)\n\tif err != nil {\n\t\tt.Fatal(\"Failed to make signature\")\n\t}\n\terr = ValidateTLSSignature(tlsSignature, sessionPubKey, peerPubKey)\n\tif err == nil {\n\t\tt.Fatal(\"Signature is valid, but shoud not\")\n\t}\n}\n"
  },
  {
    "path": "packages/fetchai/connections/p2p_libp2p/libp2p_node/dht/dhtpeer/mailbox.go",
    "content": "package dhtpeer\n\nimport (\n\t\"context\"\n\t\"crypto/tls\"\n\t\"io/ioutil\"\n\tacn \"libp2p_node/acn\"\n\taea \"libp2p_node/aea\"\n\t\"net/http\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/google/uuid\"\n\t\"google.golang.org/protobuf/proto\"\n)\n\nfunc (mailboxServer *MailboxServer) apiRegister(res http.ResponseWriter, req *http.Request) {\n\tvar data []byte\n\tvar body []byte\n\tvar err error\n\n\tif req.Method != \"POST\" {\n\t\tdata = []byte(\"invalid method\")\n\t\tres.WriteHeader(400)\n\t\t_, err = res.Write(data)\n\t\tignore(err)\n\t\treturn\n\t}\n\tbody, err = ioutil.ReadAll(req.Body)\n\tif err != nil {\n\t\tres.WriteHeader(400)\n\t\t_, err = res.Write([]byte(err.Error()))\n\t\tignore(err)\n\t\treturn\n\n\t}\n\t//get por\n\tif len(body) == 0 {\n\t\tres.WriteHeader(400)\n\t\t_, err = res.Write([]byte(\"Empty body\"))\n\t\tignore(err)\n\t\treturn\n\t}\n\trecord := &acn.AgentRecord{}\n\terr = proto.Unmarshal(body, record)\n\tif err != nil {\n\t\tres.WriteHeader(400)\n\t\t_, err = res.Write([]byte(\"Error on agent record deserialize\"))\n\t\tignore(err)\n\t\treturn\n\t}\n\taddr := record.Address\n\n\t// TODO: double register fix!!!\n\n\t//check por\n\tstatus, err := mailboxServer.dhtPeer.CheckPOR(record)\n\tif err != nil || status.Code != acn.SUCCESS {\n\t\tres.WriteHeader(400)\n\t\t_, err = res.Write([]byte(\"Invalid PoR\"))\n\t\tignore(err)\n\t\treturn\n\t}\n\tuuid := strings.ReplaceAll(uuid.NewString(), \"-\", \"\")\n\tif mailboxServer.dhtPeer.IsAddressAnnouncementEnabled() {\n\t\terr = mailboxServer.dhtPeer.RegisterAgentAddress(addr)\n\t\tif err != nil {\n\t\t\tres.WriteHeader(400)\n\t\t\t_, err = res.Write([]byte(\"failed to register address over dht\"))\n\t\t\tignore(err)\n\t\t\treturn\n\t\t}\n\t}\n\n\tmailboxServer.lock.Lock()\n\tmailboxServer.agentRecords[addr] = record\n\tmailboxServer.sessions[uuid] = addr\n\tmailboxServer.envelopes[addr] = make([]*aea.Envelope, 0)\n\tmailboxServer.lock.Unlock()\n\n\tres.WriteHeader(200)\n\t_, err = res.Write([]byte(uuid))\n\tignore(err)\n}\n\nfunc (mailboxServer *MailboxServer) apiUnregister(res http.ResponseWriter, req *http.Request) {\n\tvar data []byte\n\tvar err error\n\tvar addr string\n\tvar sessionId string\n\n\tif req.Method != \"GET\" {\n\t\tdata = []byte(\"invalid method\")\n\t\tres.WriteHeader(400)\n\t\t_, err = res.Write(data)\n\t\tignore(err)\n\t\treturn\n\t}\n\tsession_header, exists := req.Header[\"Session-Id\"]\n\n\tif exists {\n\t\tsessionId = session_header[0]\n\t\tmailboxServer.lock.Lock()\n\t\taddr, exists = mailboxServer.sessions[sessionId]\n\t\tmailboxServer.lock.Unlock()\n\t}\n\n\tif !exists {\n\t\tres.WriteHeader(400)\n\t\t_, err = res.Write([]byte(\"invalid session_id header\"))\n\t\tignore(err)\n\t\treturn\n\t}\n\n\tmailboxServer.lock.Lock()\n\tdelete(mailboxServer.agentRecords, addr)\n\tdelete(mailboxServer.sessions, sessionId)\n\tdelete(mailboxServer.envelopes, addr)\n\tmailboxServer.lock.Unlock()\n\n}\n\nfunc (mailboxServer *MailboxServer) apiGetSignature(res http.ResponseWriter, req *http.Request) {\n\tvar err error\n\tif req.Method != \"GET\" {\n\t\tres.WriteHeader(400)\n\t\t_, err = res.Write([]byte(\"invalid method\"))\n\t\tignore(err)\n\t\treturn\n\t}\n\tres.WriteHeader(200)\n\t_, err = res.Write(mailboxServer.signature)\n\tignore(err)\n}\n\nfunc (mailboxServer *MailboxServer) apiSendEnvelope(res http.ResponseWriter, req *http.Request) {\n\tvar err error\n\tif req.Method != \"POST\" {\n\t\tres.WriteHeader(400)\n\t\t_, err = res.Write([]byte(\"invalid method\"))\n\t\tignore(err)\n\t\treturn\n\t}\n\n\tsession_header, exists := req.Header[\"Session-Id\"]\n\n\tif exists {\n\t\tsessionId := session_header[0]\n\t\tmailboxServer.lock.Lock()\n\t\t_, exists = mailboxServer.sessions[sessionId]\n\t\tmailboxServer.lock.Unlock()\n\t}\n\n\tif !exists {\n\t\tres.WriteHeader(400)\n\t\t_, err = res.Write([]byte(\"invalid session_id header\"))\n\t\tignore(err)\n\t\treturn\n\t}\n\n\tbody, err := ioutil.ReadAll(req.Body)\n\tif err != nil {\n\t\tres.WriteHeader(400)\n\t\t_, err = res.Write([]byte(err.Error()))\n\t\tignore(err)\n\t\treturn\n\t}\n\t//getenvelope\n\tif len(body) == 0 {\n\t\tres.WriteHeader(400)\n\t\t_, err = res.Write([]byte(\"Empty body\"))\n\t\tignore(err)\n\t\treturn\n\t}\n\tenvelope := &aea.Envelope{}\n\terr = proto.Unmarshal(body, envelope)\n\tif err != nil {\n\t\tres.WriteHeader(400)\n\t\t_, err = res.Write([]byte(err.Error()))\n\t\tignore(err)\n\t\treturn\n\t}\n\terr = mailboxServer.dhtPeer.RouteEnvelope(envelope)\n\tif err != nil {\n\t\tres.WriteHeader(400)\n\t\t_, err = res.Write([]byte(err.Error()))\n\t\tignore(err)\n\t}\n}\n\nfunc (mailboxServer *MailboxServer) apiGetEnvelope(res http.ResponseWriter, req *http.Request) {\n\tvar buf []byte\n\tvar envelopesList []*aea.Envelope\n\tvar err error\n\tvar addr string\n\n\tif req.Method != \"GET\" {\n\t\tres.WriteHeader(400)\n\t\t_, err = res.Write([]byte(\"invalid method\"))\n\t\tignore(err)\n\t\treturn\n\t}\n\n\tsession_header, exists := req.Header[\"Session-Id\"]\n\n\tmailboxServer.lock.Lock()\n\tdefer mailboxServer.lock.Unlock()\n\tif exists {\n\t\tsessionId := session_header[0]\n\t\taddr, exists = mailboxServer.sessions[sessionId]\n\t}\n\tif !exists {\n\t\tres.WriteHeader(400)\n\t\t_, err = res.Write([]byte(\"invalid session_id header\"))\n\t\tignore(err)\n\t\treturn\n\t}\n\tenvelopesList = mailboxServer.envelopes[addr]\n\n\tif len(envelopesList) == 0 {\n\t\tres.WriteHeader(200)\n\t\treturn\n\t}\n\tenvelope := envelopesList[0]\n\tbuf, err = proto.Marshal(envelope)\n\tif err != nil {\n\t\t//log error\n\t\treturn\n\t}\n\tres.WriteHeader(200)\n\n\t_, err = res.Write(buf)\n\tif err == nil {\n\t\t// all ok, remove the first envelope from slice\n\t\tmailboxServer.envelopes[addr] = mailboxServer.envelopes[addr][1:]\n\t}\n}\n\ntype MailboxServer struct {\n\taddr           string\n\tdhtPeer        *DHTPeer\n\thttpServer     *http.Server\n\tsessions       map[string]string\n\tagentRecords   map[string]*acn.AgentRecord\n\tenvelopes      map[string]([]*aea.Envelope)\n\tlock           sync.RWMutex\n\tenvelopesLimit int\n\tcert           *tls.Certificate\n\tsignature      []byte\n}\n\nfunc (mailboxServer *MailboxServer) start() {\n\tvar err error\n\tlerror, _, _, _ := mailboxServer.dhtPeer.GetLoggers()\n\tmailboxServer.envelopes = map[string][]*aea.Envelope{}\n\tmailboxServer.agentRecords = map[string]*acn.AgentRecord{}\n\tmailboxServer.sessions = map[string]string{}\n\tmailboxServer.lock = sync.RWMutex{}\n\tmailboxServer.envelopesLimit = 1000\n\tmailboxServer.cert, mailboxServer.signature = mailboxServer.dhtPeer.GetCertAndSignature()\n\n\tmux := http.NewServeMux()\n\tmux.HandleFunc(\"/register\", mailboxServer.apiRegister)\n\tmux.HandleFunc(\"/unregister\", mailboxServer.apiUnregister)\n\tmux.HandleFunc(\"/get_envelope\", mailboxServer.apiGetEnvelope)\n\tmux.HandleFunc(\"/send_envelope\", mailboxServer.apiSendEnvelope)\n\tmux.HandleFunc(\"/ssl_signature\", mailboxServer.apiGetSignature)\n\n\ttlsConfig := &tls.Config{Certificates: []tls.Certificate{*mailboxServer.cert}}\n\n\tmailboxServer.httpServer = &http.Server{\n\t\tAddr:      mailboxServer.addr,\n\t\tHandler:   mux,\n\t\tTLSConfig: tlsConfig,\n\t}\n\tlistener, err := tls.Listen(\"tcp\", mailboxServer.addr, tlsConfig)\n\tif err != nil {\n\t\tlerror(err).Msgf(\"while setting mailbox tls\")\n\t}\n\terr = mailboxServer.httpServer.Serve(listener)\n\tif err != nil {\n\t\tlerror(err).Msgf(\"while running mailbox http server\")\n\t}\n}\n\nfunc (mailboxServer *MailboxServer) stop() {\n\tvar err error\n\tlerror, _, _, _ := mailboxServer.dhtPeer.GetLoggers()\n\n\tctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)\n\tdefer cancel()\n\terr = mailboxServer.httpServer.Shutdown(ctx)\n\tif err != nil {\n\t\tlerror(err).Msg(\"Error on mailbox http server shutdown\")\n\t}\n}\n\nfunc (mailboxServer *MailboxServer) RouteEnvelope(envelope *aea.Envelope) bool {\n\ttarget := envelope.To\n\t_, _, linfo, _ := mailboxServer.dhtPeer.GetLoggers()\n\tlinfo().Msgf(\"route to %s\", target)\n\n\tmailboxServer.lock.Lock()\n\tdefer mailboxServer.lock.Unlock()\n\tenvelopesList, listExist := mailboxServer.envelopes[target]\n\n\tif !listExist {\n\t\tlinfo().Msgf(\"route to %s. no target\", target)\n\t\treturn false\n\t}\n\t// check chan is full\n\tif mailboxServer.envelopesLimit != 0 &&\n\t\tlen(mailboxServer.envelopes[target]) >= mailboxServer.envelopesLimit {\n\t\tlinfo().Msgf(\"Envelopes queue for  %s is full. (%d envelopes)\", target, mailboxServer.envelopesLimit)\n\t\treturn false\n\t}\n\n\tmailboxServer.envelopes[target] = append(envelopesList, envelope)\n\n\tlinfo().Msgf(\"route to %s. added to queue!\", target)\n\treturn true\n}\n\nfunc (mailboxServer *MailboxServer) IsAddrRegistered(addr string) bool {\n\tmailboxServer.lock.Lock()\n\tdefer mailboxServer.lock.Unlock()\n\t_, listExist := mailboxServer.envelopes[addr]\n\treturn listExist\n}\n\nfunc (mailboxServer *MailboxServer) GetAgentRecord(addr string) *acn.AgentRecord {\n\tif !mailboxServer.IsAddrRegistered(addr) {\n\t\treturn nil\n\t}\n\tmailboxServer.lock.Lock()\n\tdefer mailboxServer.lock.Unlock()\n\treturn mailboxServer.agentRecords[addr]\n}\n"
  },
  {
    "path": "packages/fetchai/connections/p2p_libp2p/libp2p_node/dht/dhtpeer/notifee.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2022 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\n\n// Package dhtpeer provides an implementation of an Agent Communication Network node\n// using libp2p. It participates in data storage and routing for the network.\n// It offers RelayService for dhtclient and DelegateService for tcp clients.\npackage dhtpeer\n\nimport (\n\t\"github.com/libp2p/go-libp2p-core/network\"\n\t\"github.com/multiformats/go-multiaddr\"\n\t\"github.com/rs/zerolog\"\n)\n\n// Notifee Handle DHTClient network events\ntype Notifee struct {\n\tlogger zerolog.Logger\n}\n\n// Listen called when network starts listening on an addr\nfunc (notifee *Notifee) Listen(network.Network, multiaddr.Multiaddr) {}\n\n// ListenClose called when network stops listening on an addr\nfunc (notifee *Notifee) ListenClose(network.Network, multiaddr.Multiaddr) {}\n\n// Connected called when a connection opened\nfunc (notifee *Notifee) Connected(net network.Network, conn network.Conn) {\n\tnotifee.logger.Info().Msgf(\n\t\t\"Connected to peer %s\",\n\t\tconn.RemotePeer().Pretty(),\n\t)\n\n}\n\n// Disconnected called when a connection closed\n// Reconnects if connection is to relay peer and not currenctly closing connection.\nfunc (notifee *Notifee) Disconnected(net network.Network, conn network.Conn) {\n\tnotifee.logger.Info().Msgf(\n\t\t\"Disconnected from peer %s\",\n\t\tconn.RemotePeer().Pretty(),\n\t)\n}\n\n// OpenedStream called when a stream opened\nfunc (notifee *Notifee) OpenedStream(network.Network, network.Stream) {}\n\n// ClosedStream called when a stream closed\nfunc (notifee *Notifee) ClosedStream(network.Network, network.Stream) {}\n"
  },
  {
    "path": "packages/fetchai/connections/p2p_libp2p/libp2p_node/dht/dhtpeer/options.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2019 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\n\npackage dhtpeer\n\nimport (\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/multiformats/go-multiaddr\"\n\t\"github.com/rs/zerolog\"\n\n\tacn \"libp2p_node/acn\"\n\tutils \"libp2p_node/utils\"\n)\n\n// Option for dhtpeer.New\ntype Option func(*DHTPeer) error\n\n// IdentityFromFetchAIKey for dhtpeer.New\nfunc IdentityFromFetchAIKey(key string) Option {\n\treturn func(dhtPeer *DHTPeer) error {\n\t\tvar err error\n\t\tdhtPeer.key, dhtPeer.publicKey, err = utils.KeyPairFromFetchAIKey(key)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t}\n}\n\n// RegisterAgentAddress for dhtpeer.New\nfunc RegisterAgentAddress(record *acn.AgentRecord, isReady func() bool) Option {\n\treturn func(dhtPeer *DHTPeer) error {\n\t\tpbRecord := &acn.AgentRecord{}\n\t\tpbRecord.Address = record.Address\n\t\tpbRecord.PublicKey = record.PublicKey\n\t\tpbRecord.PeerPublicKey = record.PeerPublicKey\n\t\tpbRecord.Signature = record.Signature\n\t\tpbRecord.ServiceId = record.ServiceId\n\t\tpbRecord.LedgerId = record.LedgerId\n\n\t\tdhtPeer.myAgentAddress = record.Address\n\t\tdhtPeer.myAgentRecord = pbRecord\n\t\tdhtPeer.myAgentReady = isReady\n\t\treturn nil\n\t}\n}\n\n// BootstrapFrom for dhtpeer.New\nfunc BootstrapFrom(entryPeers []string) Option {\n\treturn func(dhtPeer *DHTPeer) error {\n\t\tvar err error\n\t\tdhtPeer.bootstrapPeers, err = utils.GetPeersAddrInfo(entryPeers)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t}\n}\n\n// LocalURI for dhtpeer.New\nfunc LocalURI(host string, port uint16) Option {\n\treturn func(dhtPeer *DHTPeer) error {\n\t\tvar err error\n\t\tdhtPeer.localMultiaddr, err =\n\t\t\tmultiaddr.NewMultiaddr(fmt.Sprintf(\"/ip4/%s/tcp/%d\", host, port))\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tdhtPeer.host = host\n\t\tdhtPeer.port = port\n\t\treturn nil\n\t}\n}\n\n// PublicURI for dhtpeer.New\nfunc PublicURI(host string, port uint16) Option {\n\treturn func(dhtPeer *DHTPeer) error {\n\t\tvar err error\n\t\tdhtPeer.publicMultiaddr, err =\n\t\t\tmultiaddr.NewMultiaddr(fmt.Sprintf(\"/dns4/%s/tcp/%d\", host, port))\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tdhtPeer.publicHost = host\n\t\tdhtPeer.publicPort = port\n\t\treturn nil\n\t}\n}\n\n// EnableDelegateService for dhtpeer.New\nfunc EnableDelegateService(port uint16) Option {\n\treturn func(dhtPeer *DHTPeer) error {\n\t\tdhtPeer.delegatePort = port\n\t\treturn nil\n\t}\n}\n\n// EnableMailboxService for dhtpeer.New\nfunc EnableMailboxService(hostport string) Option {\n\treturn func(dhtPeer *DHTPeer) error {\n\t\tdhtPeer.mailboxHostPort = hostport\n\t\treturn nil\n\t}\n}\n\n// EnableRelayService for dhtpeer.New\nfunc EnableRelayService() Option {\n\treturn func(dhtPeer *DHTPeer) error {\n\t\tdhtPeer.enableRelay = true\n\t\treturn nil\n\t}\n\n}\n\n// LoggingLevel for dhtpeer.New\nfunc LoggingLevel(lvl zerolog.Level) Option {\n\treturn func(dhtPeer *DHTPeer) error {\n\t\tdhtPeer.logger = dhtPeer.logger.Level(lvl)\n\t\treturn nil\n\t}\n}\n\n// EnablePrometheusMonitoring for dhtpeer.New\nfunc EnablePrometheusMonitoring(port uint16) Option {\n\treturn func(dhtPeer *DHTPeer) error {\n\t\tdhtPeer.monitoringPort = port\n\t\treturn nil\n\t}\n}\n\n// WithRegistrationDelay for dhtpeer.New\nfunc WithRegistrationDelay(delay time.Duration) Option {\n\treturn func(dhtPeer *DHTPeer) error {\n\t\tdhtPeer.registrationDelay = delay\n\t\treturn nil\n\t}\n}\n\n// StoreRecordsTo for dhtpeer.New\nfunc StoreRecordsTo(path string) Option {\n\treturn func(dhtPeer *DHTPeer) error {\n\t\tdhtPeer.persistentStoragePath = path\n\t\treturn nil\n\t}\n}\n"
  },
  {
    "path": "packages/fetchai/connections/p2p_libp2p/libp2p_node/dht/dhtpeer/utils.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2021 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\n\npackage dhtpeer\n\nimport (\n\tutils \"libp2p_node/utils\"\n\t\"net\"\n)\n\ntype TLSListener struct {\n\tListener  net.Listener\n\tSignature []byte\n}\n\nfunc (listener TLSListener) Accept() (net.Conn, error) {\n\tcon, err := listener.Listener.Accept()\n\n\tif err != nil {\n\t\treturn con, err\n\t}\n\n\terr = utils.WriteBytesConn(con, listener.Signature)\n\treturn con, err\n}\n\nfunc (listener TLSListener) Close() error {\n\treturn listener.Listener.Close()\n}\n\nfunc (listener TLSListener) Addr() net.Addr {\n\treturn listener.Listener.Addr()\n}\n"
  },
  {
    "path": "packages/fetchai/connections/p2p_libp2p/libp2p_node/dht/dhttests/dhttests.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2019 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\n\n// Package dhttests offers utilities to facilitate tests of dhtpeer, dhtclient, and dhtnetwork packages\npackage dhttests\n\nimport (\n\t\"libp2p_node/acn\"\n\t\"libp2p_node/aea\"\n\t\"libp2p_node/dht/dhtnode\"\n\t\"libp2p_node/dht/dhtpeer\"\n\t\"libp2p_node/utils\"\n\t\"log\"\n\t\"math/rand\"\n\t\"os\"\n\t\"path\"\n)\n\n//\nconst (\n\tDHTPeerDefaultLocalHost    = \"127.0.0.1\"\n\tDHTPeerDefaultLocalPort    = 2000\n\tDHTPeerDefaultDelegatePort = 3000\n\n\tDHTPeerDefaultFetchAIKey       = \"34604436e55b0eb99b5e62508433e172dd3ee133cf7a2fecb705e69611147605\"\n\tDHTPeerDefaultFetchAIPublicKey = \"039e883de988eededb9afaa4d3a6baec9ba74dd1cc237028e810569780b319940a\"\n\n\tDHTPeerDefaultAgentKey       = \"719133dc740d76ff6d1d325e193f7cd63af4c8f3491bfe3010e58b0b58c77795\"\n\tDHTPeerDefaultAgentPublicKey = \"039623e63ba1617404b2abbe7bd94d24eb788335f870fac1ae4519e9bc359b7833\"\n\tDHTPeerDefaultAgentAddress   = \"fetch134rg4n3wgmwctxsrm7gp6l65uwv6hxtxyfdwgw\"\n)\n\nfunc randSeq(n int) string {\n\tvar letters = []rune(\"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\")\n\tb := make([]rune, n)\n\tfor i := range b {\n\t\tb[i] = letters[rand.Intn(len(letters))]\n\t}\n\treturn string(b)\n}\n\n// NewDHTPeerWithDefaults for testing\nfunc NewDHTPeerWithDefaults(inbox chan<- *aea.Envelope) (*dhtpeer.DHTPeer, func(), error) {\n\topts := []dhtpeer.Option{\n\t\tdhtpeer.LocalURI(DHTPeerDefaultLocalHost, DHTPeerDefaultLocalPort),\n\t\tdhtpeer.PublicURI(DHTPeerDefaultLocalHost, DHTPeerDefaultLocalPort),\n\t\tdhtpeer.IdentityFromFetchAIKey(DHTPeerDefaultFetchAIKey),\n\t\tdhtpeer.EnableRelayService(),\n\t\tdhtpeer.EnableDelegateService(DHTPeerDefaultDelegatePort),\n\t\tdhtpeer.StoreRecordsTo(path.Join(os.TempDir(), \"agents_records_\"+randSeq(5))),\n\t}\n\n\tsignature, err := utils.SignFetchAI(\n\t\t[]byte(DHTPeerDefaultFetchAIPublicKey),\n\t\tDHTPeerDefaultAgentKey,\n\t)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\trecord := &acn.AgentRecord{LedgerId: dhtnode.DefaultLedger}\n\trecord.Address = DHTPeerDefaultAgentAddress\n\trecord.PublicKey = DHTPeerDefaultAgentPublicKey\n\trecord.PeerPublicKey = DHTPeerDefaultFetchAIPublicKey\n\trecord.Signature = signature\n\n\topts = append(opts, dhtpeer.RegisterAgentAddress(record, func() bool { return true }))\n\n\tdhtPeer, err := dhtpeer.New(opts...)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tcleanup := func() {\n\t\terrs := dhtPeer.Close()\n\t\tif len(errs) > 0 {\n\t\t\tlog.Println(\"ERROR while stopping DHTPeer:\", errs)\n\t\t}\n\t}\n\n\tdhtPeer.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\tinbox <- envel\n\t\treturn nil\n\t})\n\n\treturn dhtPeer, cleanup, nil\n}\n"
  },
  {
    "path": "packages/fetchai/connections/p2p_libp2p/libp2p_node/dht/monitoring/file.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2019 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\n\npackage monitoring\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"sync\"\n\t\"time\"\n)\n\ntype FileGauge struct {\n\tvalue float64\n\tlock  sync.RWMutex\n}\n\nfunc (fg *FileGauge) Set(value float64) {\n\tfg.lock.Lock()\n\tfg.value = value\n\tfg.lock.Unlock()\n\n}\n\nfunc (fg *FileGauge) Get() float64 {\n\treturn fg.value\n\n}\n\nfunc (fg *FileGauge) Inc() {\n\tfg.Add(1.)\n}\n\nfunc (fg *FileGauge) Dec() {\n\tfg.Sub(1)\n}\n\nfunc (fg *FileGauge) Add(count float64) {\n\tfg.lock.Lock()\n\tfg.value += count\n\tfg.lock.Unlock()\n\n}\n\nfunc (fg *FileGauge) Sub(count float64) {\n\tfg.lock.Lock()\n\tfg.value -= count\n\tfg.lock.Unlock()\n\n}\n\ntype FileCounter struct {\n\tvalue float64\n\tlock  sync.RWMutex\n}\n\nfunc (fc *FileCounter) Inc() {\n\tfc.Add(1.)\n\n}\n\nfunc (fc *FileCounter) Add(count float64) {\n\tfc.lock.Lock()\n\tfc.value += count\n\tfc.lock.Unlock()\n}\n\nfunc (fc *FileCounter) Get() float64 {\n\treturn fc.value\n}\n\ntype FileHistogram struct {\n\tbuckets []float64\n\tcounts  []uint64\n\tlock    sync.RWMutex\n}\n\nfunc (fh *FileHistogram) Observe(value float64) {\n\tfh.lock.Lock()\n\tvar i int = 0\n\tfor i < len(fh.buckets) {\n\t\tif value <= fh.buckets[i] {\n\t\t\tfh.counts[i] += 1\n\t\t}\n\t\ti++\n\t}\n\tfh.counts[i] += 1\n\tfh.lock.Unlock()\n}\n\ntype FileMonitoring struct {\n\tNamespace   string\n\tgaugeDict   map[string]*FileGauge\n\tcounterDict map[string]*FileCounter\n\thistoDict   map[string]*FileHistogram\n\n\ttimer *Timer\n\n\tpath    string\n\twrite   bool\n\tclosing chan struct{}\n}\n\nfunc NewFileMonitoring(namespace string, write bool) *FileMonitoring {\n\tfm := &FileMonitoring{\n\t\tNamespace: namespace,\n\t}\n\n\tfm.counterDict = map[string]*FileCounter{}\n\tfm.gaugeDict = map[string]*FileGauge{}\n\tfm.histoDict = map[string]*FileHistogram{}\n\n\tfm.timer = &Timer{\n\t\tlist: map[string]time.Time{},\n\t\tlock: sync.RWMutex{},\n\t}\n\n\tcwd, _ := os.Getwd()\n\tfm.path = cwd + \"/\" + fm.Namespace + \".stats\"\n\tfm.write = write\n\n\treturn fm\n}\n\nfunc (fm *FileMonitoring) NewCounter(name string, description string) (Counter, error) {\n\tcounter := &FileCounter{}\n\tfm.counterDict[name] = counter\n\n\treturn counter, nil\n\n}\n\nfunc (fm *FileMonitoring) GetCounter(name string) (Counter, bool) {\n\tcounter, ok := fm.counterDict[name]\n\treturn counter, ok\n}\n\nfunc (fm *FileMonitoring) NewGauge(name string, description string) (Gauge, error) {\n\tgauge := &FileGauge{}\n\tfm.gaugeDict[name] = gauge\n\n\treturn gauge, nil\n}\n\nfunc (fm *FileMonitoring) GetGauge(name string) (Gauge, bool) {\n\tgauge, ok := fm.gaugeDict[name]\n\treturn gauge, ok\n}\n\nfunc (fm *FileMonitoring) NewHistogram(\n\tname string,\n\tdescription string,\n\tbuckets []float64,\n) (Histogram, error) {\n\thistogram := &FileHistogram{\n\t\tbuckets: buckets,\n\t\tcounts:  make([]uint64, len(buckets)+1),\n\t}\n\tfm.histoDict[name] = histogram\n\n\treturn histogram, nil\n}\n\nfunc (fm *FileMonitoring) GetHistogram(name string) (Histogram, bool) {\n\thisto, ok := fm.histoDict[name]\n\treturn histo, ok\n}\n\nfunc (fm *FileMonitoring) Start() {\n\tif fm.closing != nil || !fm.write {\n\t\treturn\n\t}\n\tfm.closing = make(chan struct{})\n\n\tfile, _ := os.OpenFile(fm.path, os.O_WRONLY|os.O_CREATE, 0666)\nL:\n\tfor {\n\t\tselect {\n\t\tcase <-fm.closing:\n\t\t\tfile.Close()\n\t\t\tbreak L\n\t\tdefault:\n\t\t\tignore(file.Truncate(0))\n\t\t\t_, err := file.Seek(0, 0)\n\t\t\tignore(err)\n\t\t\t_, err = file.WriteString(fm.getStats())\n\t\t\tignore(err)\n\t\t\ttime.Sleep(5 * time.Second)\n\t\t}\n\t}\n}\n\nfunc (fm *FileMonitoring) Stop() {\n\tclose(fm.closing)\n}\n\nfunc (fm FileMonitoring) getStats() string {\n\tvar stats string\n\tfor name, value := range fm.gaugeDict {\n\t\tstrValue := fmt.Sprintf(\"%e\", value.Get())\n\t\tstats += fm.Namespace + \"_\" + name + \" \" + strValue + \"\\n\"\n\t}\n\tfor name, value := range fm.counterDict {\n\t\tstrValue := fmt.Sprintf(\"%e\", value.Get())\n\t\tstats += fm.Namespace + \"_\" + name + \" \" + strValue + \"\\n\"\n\t}\n\t// TODO: report histograms\n\treturn stats\n}\n\nfunc (fm *FileMonitoring) Info() string {\n\treturn \"FileMonitoring on \" + fm.path\n}\n\nfunc (fm *FileMonitoring) Timer() *Timer {\n\treturn fm.timer\n}\n"
  },
  {
    "path": "packages/fetchai/connections/p2p_libp2p/libp2p_node/dht/monitoring/prometheus.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2019 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\n\npackage monitoring\n\nimport (\n\t\"net/http\"\n\t\"strconv\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/prometheus/client_golang/prometheus\"\n\t\"github.com/prometheus/client_golang/prometheus/promauto\"\n\t\"github.com/prometheus/client_golang/prometheus/promhttp\"\n)\n\ntype PrometheusMonitoring struct {\n\tNamespace string\n\tPort      uint16\n\n\trunning     bool\n\thttpServer  http.Server\n\tcounterDict map[string]prometheus.Counter\n\tgaugeDict   map[string]prometheus.Gauge\n\thistoDict   map[string]prometheus.Histogram\n\n\ttimer *Timer\n}\n\nfunc NewPrometheusMonitoring(namespace string, port uint16) *PrometheusMonitoring {\n\tpmts := &PrometheusMonitoring{\n\t\tNamespace: namespace,\n\t\tPort:      port,\n\t}\n\n\tpmts.counterDict = map[string]prometheus.Counter{}\n\tpmts.gaugeDict = map[string]prometheus.Gauge{}\n\tpmts.histoDict = map[string]prometheus.Histogram{}\n\n\tpmts.timer = &Timer{\n\t\tlist: map[string]time.Time{},\n\t\tlock: sync.RWMutex{},\n\t}\n\n\treturn pmts\n}\n\nfunc (pmts *PrometheusMonitoring) NewCounter(name string, description string) (Counter, error) {\n\tcounter := promauto.NewCounter(prometheus.CounterOpts{\n\t\tNamespace: pmts.Namespace,\n\t\tName:      name,\n\t\tHelp:      description,\n\t})\n\tpmts.counterDict[name] = counter\n\n\treturn counter, nil\n}\n\nfunc (pmts *PrometheusMonitoring) GetCounter(name string) (Counter, bool) {\n\tcounter, ok := pmts.counterDict[name]\n\treturn counter, ok\n}\n\nfunc (pmts *PrometheusMonitoring) NewGauge(name string, description string) (Gauge, error) {\n\tgauge := promauto.NewGauge(prometheus.GaugeOpts{\n\t\tNamespace: pmts.Namespace,\n\t\tName:      name,\n\t\tHelp:      description,\n\t})\n\tpmts.gaugeDict[name] = gauge\n\n\treturn gauge, nil\n}\n\nfunc (pmts *PrometheusMonitoring) GetGauge(name string) (Gauge, bool) {\n\tgauge, ok := pmts.gaugeDict[name]\n\treturn gauge, ok\n}\n\nfunc (pmts *PrometheusMonitoring) NewHistogram(\n\tname string,\n\tdescription string,\n\tbuckets []float64,\n) (Histogram, error) {\n\thistogram := promauto.NewHistogram(prometheus.HistogramOpts{\n\t\tNamespace: pmts.Namespace,\n\t\tName:      name,\n\t\tHelp:      description,\n\t\tBuckets:   buckets,\n\t})\n\tpmts.histoDict[name] = histogram\n\n\treturn histogram, nil\n}\n\nfunc (pmts *PrometheusMonitoring) GetHistogram(name string) (Histogram, bool) {\n\thistogram, ok := pmts.histoDict[name]\n\treturn histogram, ok\n}\n\nfunc (pmts *PrometheusMonitoring) Start() {\n\tif pmts.running {\n\t\treturn\n\t}\n\tpmts.httpServer = http.Server{Addr: \":\" + strconv.FormatInt(int64(pmts.Port), 10)}\n\thttp.Handle(\"/metrics\", promhttp.Handler())\n\n\tpmts.running = true\n\tignore(pmts.httpServer.ListenAndServe())\n}\n\nfunc (pmts *PrometheusMonitoring) Stop() {\n\tpmts.httpServer.Close()\n}\n\nfunc (pmts *PrometheusMonitoring) Info() string {\n\treturn \"Prometheus at \" + strconv.FormatInt(int64(pmts.Port), 10)\n}\nfunc (pmts *PrometheusMonitoring) Timer() *Timer {\n\treturn pmts.timer\n}\n"
  },
  {
    "path": "packages/fetchai/connections/p2p_libp2p/libp2p_node/dht/monitoring/service.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2019 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\n\npackage monitoring\n\nimport (\n\t\"errors\"\n\t\"log\"\n\t\"sync\"\n\t\"time\"\n)\n\ntype Gauge interface {\n\tSet(value float64)\n\tInc()\n\tDec()\n\tAdd(count float64)\n\tSub(count float64)\n}\n\ntype Counter interface {\n\tInc()\n\tAdd(count float64)\n}\n\ntype Histogram interface {\n\tObserve(value float64)\n}\n\ntype Summary interface {\n\tObserve(value float64)\n}\n\ntype Timer struct {\n\tlist map[string]time.Time\n\tlock sync.RWMutex\n}\n\nfunc (tm *Timer) NewTimer() time.Time {\n\treturn time.Now()\n}\n\nfunc (tm *Timer) GetTimer(timer time.Time) time.Duration {\n\tend := time.Now()\n\treturn end.Sub(timer)\n}\n\nfunc (tm *Timer) NewTimerNamed(name string) string {\n\ttm.lock.Lock()\n\tdefer tm.lock.Unlock()\n\ttm.list[name] = time.Now()\n\treturn name\n}\n\nfunc (tm *Timer) GetTimerNamed(timer string) (time.Duration, error) {\n\tend := time.Now()\n\ttm.lock.RLock()\n\tstart, ok := tm.list[timer]\n\ttm.lock.RUnlock()\n\tif !ok {\n\t\treturn time.Duration(0), errors.New(\"Unknown timer \" + timer)\n\t}\n\ttm.lock.Lock()\n\tdelete(tm.list, timer)\n\ttm.lock.Unlock()\n\treturn end.Sub(start), nil\n}\n\ntype MonitoringService interface {\n\tNewCounter(name string, description string) (Counter, error)\n\tGetCounter(name string) (Counter, bool)\n\tNewGauge(name string, description string) (Gauge, error)\n\tGetGauge(name string) (Gauge, bool)\n\tNewHistogram(name string, description string, buckets []float64) (Histogram, error)\n\tGetHistogram(name string) (Histogram, bool)\n\t//NewSummary(name string, description string, objectives map[float64]float64) (Summary, error)\n\t//GetSummary(name string) (Summary, bool)\n\tStart()\n\tStop()\n\tInfo() string\n\tTimer() *Timer\n}\n\nfunc ignore(err error) {\n\tif err != nil {\n\t\tlog.Println(\"IGNORED\", err)\n\t}\n}\n"
  },
  {
    "path": "packages/fetchai/connections/p2p_libp2p/libp2p_node/go.mod",
    "content": "module libp2p_node\n\ngo 1.13\n\nrequire (\n\tbou.ke/monkey v1.0.2\n\tgithub.com/btcsuite/btcd v0.20.1-beta\n\tgithub.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d\n\tgithub.com/ethereum/go-ethereum v1.10.17\n\tgithub.com/golang/mock v1.5.0\n\tgithub.com/golang/protobuf v1.4.3\n\tgithub.com/google/uuid v1.3.0\n\tgithub.com/ipfs/go-cid v0.0.5\n\tgithub.com/joho/godotenv v1.3.0\n\tgithub.com/libp2p/go-libp2p v0.8.3\n\tgithub.com/libp2p/go-libp2p-circuit v0.2.2\n\tgithub.com/libp2p/go-libp2p-core v0.5.3\n\tgithub.com/libp2p/go-libp2p-kad-dht v0.7.11\n\tgithub.com/libp2p/go-libp2p-kbucket v0.4.1\n\tgithub.com/multiformats/go-multiaddr v0.2.1\n\tgithub.com/multiformats/go-multihash v0.0.13\n\tgithub.com/pkg/errors v0.9.1\n\tgithub.com/prometheus/client_golang v1.7.1\n\tgithub.com/rs/zerolog v1.21.0\n\tgithub.com/stretchr/testify v1.7.0\n\tgolang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2\n\tgoogle.golang.org/protobuf v1.25.0\n\thonnef.co/go/tools v0.1.4 // indirect\n\n)\n"
  },
  {
    "path": "packages/fetchai/connections/p2p_libp2p/libp2p_node/go.sum",
    "content": "bou.ke/monkey v1.0.2 h1:kWcnsrCNUatbxncxR/ThdYqbytgOIArtYWqcQLQzKLI=\nbou.ke/monkey v1.0.2/go.mod h1:OqickVX3tNx6t33n1xvtTtu85YN5s6cKwVug+oHMaIA=\ncloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ncloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ncloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=\ncloud.google.com/go v0.43.0/go.mod h1:BOSR3VbTLkk6FDC/TcffxP4NF/FFBGA5ku+jvKOP7pg=\ncloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=\ncloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=\ncloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=\ncloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=\ncloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=\ncloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw=\ncloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=\ncloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=\ncloud.google.com/go/bigtable v1.2.0/go.mod h1:JcVAOl45lrTmQfLj7T6TxyMzIN/3FGGcFm+2xVAli2o=\ncloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=\ncloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=\ncloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=\ncloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=\ncloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=\ncollectd.org v0.3.0/go.mod h1:A/8DzQBkF6abtvrT2j/AU/4tiBgJWYyh0y/oB/4MlWE=\ndmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=\ngithub.com/AndreasBriese/bbloom v0.0.0-20180913140656-343706a395b7/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=\ngithub.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=\ngithub.com/Azure/azure-sdk-for-go/sdk/azcore v0.21.1/go.mod h1:fBF9PQNqB8scdgpZ3ufzaLntG0AG7C1WjPMsiFOmfHM=\ngithub.com/Azure/azure-sdk-for-go/sdk/internal v0.8.3/go.mod h1:KLF4gFr6DcKFZwSuH8w8yEK6DpFl3LP5rhdvAb7Yz5I=\ngithub.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0/go.mod h1:tPaiy8S5bQ+S5sOiDlINkp7+Ef339+Nz5L5XO+cnOHo=\ngithub.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=\ngithub.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=\ngithub.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=\ngithub.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=\ngithub.com/Kubuxu/go-os-helper v0.0.1/go.mod h1:N8B+I7vPCT80IcP58r50u4+gEEcsZETFUpAzWW2ep1Y=\ngithub.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=\ngithub.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=\ngithub.com/VictoriaMetrics/fastcache v1.6.0/go.mod h1:0qHz5QP0GMX4pfmMA/zt5RgfNuXJrTP0zS7DqpHGGTw=\ngithub.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=\ngithub.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=\ngithub.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=\ngithub.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=\ngithub.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=\ngithub.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=\ngithub.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM=\ngithub.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=\ngithub.com/apache/arrow/go/arrow v0.0.0-20191024131854-af6fa24be0db/go.mod h1:VTxUBvSJ3s3eHAg65PNgrsn5BtqCRPdmyXh6rAfdxN0=\ngithub.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=\ngithub.com/aws/aws-sdk-go-v2 v1.2.0/go.mod h1:zEQs02YRBw1DjK0PoJv3ygDYOFTre1ejlJWl8FwAuQo=\ngithub.com/aws/aws-sdk-go-v2/config v1.1.1/go.mod h1:0XsVy9lBI/BCXm+2Tuvt39YmdHwS5unDQmxZOYe8F5Y=\ngithub.com/aws/aws-sdk-go-v2/credentials v1.1.1/go.mod h1:mM2iIjwl7LULWtS6JCACyInboHirisUUdkBPoTHMOUo=\ngithub.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.0.2/go.mod h1:3hGg3PpiEjHnrkrlasTfxFqUsZ2GCk/fMUn4CbKgSkM=\ngithub.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.0.2/go.mod h1:45MfaXZ0cNbeuT0KQ1XJylq8A6+OpVV2E5kvY/Kq+u8=\ngithub.com/aws/aws-sdk-go-v2/service/route53 v1.1.1/go.mod h1:rLiOUrPLW/Er5kRcQ7NkwbjlijluLsrIbu/iyl35RO4=\ngithub.com/aws/aws-sdk-go-v2/service/sso v1.1.1/go.mod h1:SuZJxklHxLAXgLTc1iFXbEWkXs7QRTQpCLGaKIprQW0=\ngithub.com/aws/aws-sdk-go-v2/service/sts v1.1.1/go.mod h1:Wi0EBZwiz/K44YliU0EKxqTCJGUfYTWXrrBwkq736bM=\ngithub.com/aws/smithy-go v1.1.0/go.mod h1:EzMw8dbp/YJL4A5/sbhGddag+NPT7q084agLbB9LgIw=\ngithub.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=\ngithub.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=\ngithub.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=\ngithub.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=\ngithub.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40/go.mod h1:8rLXio+WjiTceGBHIoTvn60HIbs7Hm7bcHjyrSqYB9c=\ngithub.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=\ngithub.com/btcsuite/btcd v0.0.0-20190213025234-306aecffea32/go.mod h1:DrZx5ec/dmnfpw9KyYoQyYo7d0KEvTkk/5M/vbZjAr8=\ngithub.com/btcsuite/btcd v0.0.0-20190523000118-16327141da8c/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI=\ngithub.com/btcsuite/btcd v0.0.0-20190824003749-130ea5bddde3/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI=\ngithub.com/btcsuite/btcd v0.20.1-beta h1:Ik4hyJqN8Jfyv3S4AGBOmyouMsYE3EdYODkMbQjwPGw=\ngithub.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=\ngithub.com/btcsuite/btcd/btcec/v2 v2.1.2 h1:YoYoC9J0jwfukodSBMzZYUVQ8PTiYg4BnOWiJVzTmLs=\ngithub.com/btcsuite/btcd/btcec/v2 v2.1.2/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE=\ngithub.com/btcsuite/btcd/chaincfg/chainhash v1.0.0 h1:MSskdM4/xJYcFzy0altH/C/xHopifpWzHUi1JeVI34Q=\ngithub.com/btcsuite/btcd/chaincfg/chainhash v1.0.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=\ngithub.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=\ngithub.com/btcsuite/btcutil v0.0.0-20190207003914-4c204d697803/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=\ngithub.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d h1:yJzD/yFppdVCf6ApMkVy8cUxV0XrxdP9rVf6D87/Mng=\ngithub.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=\ngithub.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg=\ngithub.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY=\ngithub.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc=\ngithub.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY=\ngithub.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs=\ngithub.com/c-bata/go-prompt v0.2.2/go.mod h1:VzqtzE2ksDBcdln8G7mk2RX9QyGjH+OVqOCSiVIqS34=\ngithub.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=\ngithub.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s=\ngithub.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=\ngithub.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=\ngithub.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=\ngithub.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=\ngithub.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=\ngithub.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=\ngithub.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=\ngithub.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=\ngithub.com/cloudflare/cloudflare-go v0.14.0/go.mod h1:EnwdgGMaFOruiPZRFSgn+TsQ3hQ7C/YWzIGLeu5c304=\ngithub.com/consensys/bavard v0.1.8-0.20210406032232-f3452dc9b572/go.mod h1:Bpd0/3mZuaj6Sj+PqrmIquiOKy397AKGThQPaGzNXAQ=\ngithub.com/consensys/gnark-crypto v0.4.1-0.20210426202927-39ac3d4b3f1f/go.mod h1:815PAHg3wvysy0SyIqanF8gZ0Y1wjk/hrDHD/iT88+Q=\ngithub.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=\ngithub.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=\ngithub.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=\ngithub.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM=\ngithub.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=\ngithub.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=\ngithub.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=\ngithub.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=\ngithub.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=\ngithub.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4=\ngithub.com/dave/jennifer v1.2.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg=\ngithub.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/davidlazar/go-crypto v0.0.0-20170701192655-dcfb0a7ac018 h1:6xT9KW8zLC5IlbaIF5Q7JNieBoACT7iW0YTxQHR0in0=\ngithub.com/davidlazar/go-crypto v0.0.0-20170701192655-dcfb0a7ac018/go.mod h1:rQYf4tfk5sSwFsnDg3qYaBxSjsD9S8+59vW0dKUgme4=\ngithub.com/deckarep/golang-set v1.8.0/go.mod h1:5nI87KwE7wgsBU1F4GKAw2Qod7p5kyS383rP6+o6qqo=\ngithub.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0=\ngithub.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc=\ngithub.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc=\ngithub.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs=\ngithub.com/deepmap/oapi-codegen v1.6.0/go.mod h1:ryDa9AgbELGeB+YEXE1dR53yAjHwFvE9iAUlWl9Al3M=\ngithub.com/deepmap/oapi-codegen v1.8.2/go.mod h1:YLgSKSDv/bZQB7N4ws6luhozi3cEdRktEqrX88CvjIw=\ngithub.com/dgraph-io/badger v1.5.5-0.20190226225317-8115aed38f8f/go.mod h1:VZxzAIRPHRVNRKRo6AXrX9BJegn6il06VMTZVJYCIjQ=\ngithub.com/dgraph-io/badger v1.6.0-rc1/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4=\ngithub.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4=\ngithub.com/dgraph-io/badger v1.6.1/go.mod h1:FRmFw3uxvcpa8zG3Rxs0th+hCLIuaQg8HlNV5bjgnuU=\ngithub.com/dgraph-io/ristretto v0.0.2/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E=\ngithub.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=\ngithub.com/dgryski/go-bitstream v0.0.0-20180413035011-3522498ce2c8/go.mod h1:VMaSuZ+SZcx/wljOQKvp5srsbCiKDEb6K2wC4+PiBmQ=\ngithub.com/dgryski/go-farm v0.0.0-20190104051053-3adb47b1fb0f/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=\ngithub.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=\ngithub.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=\ngithub.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=\ngithub.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko=\ngithub.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=\ngithub.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=\ngithub.com/dop251/goja v0.0.0-20211011172007-d99e4b8cbf48/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk=\ngithub.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7/go.mod h1:hn7BA7c8pLvoGndExHudxTDKZ84Pyvv+90pbBjbTz0Y=\ngithub.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=\ngithub.com/eclipse/paho.mqtt.golang v1.2.0/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7joQ8SYLhZwfeOo6Ts=\ngithub.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=\ngithub.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=\ngithub.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=\ngithub.com/ethereum/go-ethereum v1.10.17 h1:XEcumY+qSr1cZQaWsQs5Kck3FHB0V2RiMHPdTBJ+oT8=\ngithub.com/ethereum/go-ethereum v1.10.17/go.mod h1:Lt5WzjM07XlXc95YzrhosmR4J9Ahd6X2wyEV2SvGhk0=\ngithub.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=\ngithub.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0=\ngithub.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=\ngithub.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=\ngithub.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=\ngithub.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=\ngithub.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww=\ngithub.com/getkin/kin-openapi v0.53.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4=\ngithub.com/getkin/kin-openapi v0.61.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4=\ngithub.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=\ngithub.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE=\ngithub.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24=\ngithub.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98=\ngithub.com/go-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJpoZOs=\ngithub.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=\ngithub.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=\ngithub.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=\ngithub.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=\ngithub.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=\ngithub.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=\ngithub.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8=\ngithub.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=\ngithub.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=\ngithub.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg=\ngithub.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=\ngithub.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=\ngithub.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=\ngithub.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=\ngithub.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=\ngithub.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=\ngithub.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=\ngithub.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=\ngithub.com/golang-jwt/jwt/v4 v4.3.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=\ngithub.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=\ngithub.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=\ngithub.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=\ngithub.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=\ngithub.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7 h1:5ZkaAPbicIKTF2I64qf5Fh8Aa83Q/dnOafMYV0OMwjA=\ngithub.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=\ngithub.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=\ngithub.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=\ngithub.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=\ngithub.com/golang/mock v1.5.0 h1:jlYHihg//f7RRwuPfptm04yp4s7O6Kw8EZiVYIGcH0g=\ngithub.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=\ngithub.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0=\ngithub.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=\ngithub.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=\ngithub.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=\ngithub.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=\ngithub.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=\ngithub.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=\ngithub.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=\ngithub.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM=\ngithub.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=\ngithub.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=\ngithub.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=\ngithub.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=\ngithub.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219/go.mod h1:/X8TswGSh1pIozq4ZwCfxS0WA5JGXguxk94ar/4c87Y=\ngithub.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=\ngithub.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=\ngithub.com/google/flatbuffers v1.11.0/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=\ngithub.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=\ngithub.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=\ngithub.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=\ngithub.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M=\ngithub.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=\ngithub.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=\ngithub.com/google/gopacket v1.1.17 h1:rMrlX2ZY2UbvT+sdz3+6J+pp2z+msCq9MxTU6ymxbBY=\ngithub.com/google/gopacket v1.1.17/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM=\ngithub.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=\ngithub.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=\ngithub.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=\ngithub.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=\ngithub.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=\ngithub.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=\ngithub.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=\ngithub.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=\ngithub.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=\ngithub.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=\ngithub.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=\ngithub.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=\ngithub.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=\ngithub.com/graph-gophers/graphql-go v1.3.0/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc=\ngithub.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU=\ngithub.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48=\ngithub.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=\ngithub.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=\ngithub.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0=\ngithub.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI=\ngithub.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=\ngithub.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=\ngithub.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=\ngithub.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=\ngithub.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d h1:dg1dEPuWpEqDnvIw251EVy4zlP8gWbsGj4BsUKCRpYs=\ngithub.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=\ngithub.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=\ngithub.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA=\ngithub.com/holiman/uint256 v1.2.0/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw=\ngithub.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=\ngithub.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc=\ngithub.com/huin/goupnp v1.0.3-0.20220313090229-ca81a64b4204 h1:+EYBkW+dbi3F/atB+LSQZSWh7+HNrV3A/N0y6DSoy9k=\ngithub.com/huin/goupnp v1.0.3-0.20220313090229-ca81a64b4204/go.mod h1:ZxNlw5WqJj6wSsRK5+YfflQGXYfccj5VgQsMNixHM7Y=\ngithub.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o=\ngithub.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=\ngithub.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=\ngithub.com/influxdata/flux v0.65.1/go.mod h1:J754/zds0vvpfwuq7Gc2wRdVwEodfpCFM7mYlOw2LqY=\ngithub.com/influxdata/influxdb v1.8.3/go.mod h1:JugdFhsvvI8gadxOI6noqNeeBHvWNTbfYGtiAn+2jhI=\ngithub.com/influxdata/influxdb-client-go/v2 v2.4.0/go.mod h1:vLNHdxTJkIf2mSLvGrpj8TCcISApPoXkaxP8g9uRlW8=\ngithub.com/influxdata/influxql v1.1.1-0.20200828144457-65d3ef77d385/go.mod h1:gHp9y86a/pxhjJ+zMjNXiQAA197Xk9wLxaz+fGG+kWk=\ngithub.com/influxdata/line-protocol v0.0.0-20180522152040-32c6aa80de5e/go.mod h1:4kt73NQhadE3daL3WhR5EJ/J2ocX0PZzwxQ0gXJ7oFE=\ngithub.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo=\ngithub.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo=\ngithub.com/influxdata/promql/v2 v2.12.0/go.mod h1:fxOPu+DY0bqCTCECchSRtWfc+0X19ybifQhZoQNF5D8=\ngithub.com/influxdata/roaring v0.4.13-0.20180809181101-fc520f41fab6/go.mod h1:bSgUQ7q5ZLSO+bKBGqJiCBGAl+9DxyW63zLTujjUlOE=\ngithub.com/influxdata/tdigest v0.0.0-20181121200506-bf2b5ad3c0a9/go.mod h1:Js0mqiSBE6Ffsg94weZZ2c+v/ciT8QRHFOap7EKDrR0=\ngithub.com/influxdata/usage-client v0.0.0-20160829180054-6d3895376368/go.mod h1:Wbbw6tYNvwa5dlB6304Sd+82Z3f7PmVZHVKU637d4po=\ngithub.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM=\ngithub.com/ipfs/go-cid v0.0.2/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM=\ngithub.com/ipfs/go-cid v0.0.3/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM=\ngithub.com/ipfs/go-cid v0.0.4/go.mod h1:4LLaPOQwmk5z9LBgQnpkivrx8BJjUyGwTXCd5Xfj6+M=\ngithub.com/ipfs/go-cid v0.0.5 h1:o0Ix8e/ql7Zb5UVUJEUfjsWCIY8t48++9lR8qi6oiJU=\ngithub.com/ipfs/go-cid v0.0.5/go.mod h1:plgt+Y5MnOey4vO4UlUazGqdbEXuFYitED67FexhXog=\ngithub.com/ipfs/go-datastore v0.0.1/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE=\ngithub.com/ipfs/go-datastore v0.1.0/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE=\ngithub.com/ipfs/go-datastore v0.1.1/go.mod h1:w38XXW9kVFNp57Zj5knbKWM2T+KOZCGDRVNdgPHtbHw=\ngithub.com/ipfs/go-datastore v0.4.0/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA=\ngithub.com/ipfs/go-datastore v0.4.1/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA=\ngithub.com/ipfs/go-datastore v0.4.4 h1:rjvQ9+muFaJ+QZ7dN5B1MSDNQ0JVZKkkES/rMZmA8X8=\ngithub.com/ipfs/go-datastore v0.4.4/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA=\ngithub.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk=\ngithub.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps=\ngithub.com/ipfs/go-ds-badger v0.0.2/go.mod h1:Y3QpeSFWQf6MopLTiZD+VT6IC1yZqaGmjvRcKeSGij8=\ngithub.com/ipfs/go-ds-badger v0.0.5/go.mod h1:g5AuuCGmr7efyzQhLL8MzwqcauPojGPUaHzfGTzuE3s=\ngithub.com/ipfs/go-ds-badger v0.0.7/go.mod h1:qt0/fWzZDoPW6jpQeqUjR5kBfhDNB65jd9YlmAvpQBk=\ngithub.com/ipfs/go-ds-badger v0.2.1/go.mod h1:Tx7l3aTph3FMFrRS838dcSJh+jjA7cX9DrGVwx/NOwE=\ngithub.com/ipfs/go-ds-badger v0.2.3/go.mod h1:pEYw0rgg3FIrywKKnL+Snr+w/LjJZVMTBRn4FS6UHUk=\ngithub.com/ipfs/go-ds-leveldb v0.0.1/go.mod h1:feO8V3kubwsEF22n0YRQCffeb79OOYIykR4L04tMOYc=\ngithub.com/ipfs/go-ds-leveldb v0.1.0/go.mod h1:hqAW8y4bwX5LWcCtku2rFNX3vjDZCy5LZCg+cSZvYb8=\ngithub.com/ipfs/go-ds-leveldb v0.4.1/go.mod h1:jpbku/YqBSsBc1qgME8BkWS4AxzF2cEu1Ii2r79Hh9s=\ngithub.com/ipfs/go-ds-leveldb v0.4.2/go.mod h1:jpbku/YqBSsBc1qgME8BkWS4AxzF2cEu1Ii2r79Hh9s=\ngithub.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw=\ngithub.com/ipfs/go-ipfs-util v0.0.1 h1:Wz9bL2wB2YBJqggkA4dD7oSmqB4cAnpNbGrlHJulv50=\ngithub.com/ipfs/go-ipfs-util v0.0.1/go.mod h1:spsl5z8KUnrve+73pOhSVZND1SIxPW5RyBCNzQxlJBc=\ngithub.com/ipfs/go-ipns v0.0.2 h1:oq4ErrV4hNQ2Eim257RTYRgfOSV/s8BDaf9iIl4NwFs=\ngithub.com/ipfs/go-ipns v0.0.2/go.mod h1:WChil4e0/m9cIINWLxZe1Jtf77oz5L05rO2ei/uKJ5U=\ngithub.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM=\ngithub.com/ipfs/go-log v1.0.2/go.mod h1:1MNjMxe0u6xvJZgeqbJ8vdo2TKaGwZ1a0Bpza+sr2Sk=\ngithub.com/ipfs/go-log v1.0.3/go.mod h1:OsLySYkwIbiSUR/yBTdv1qPtcE4FW3WPWk/ewz9Ru+A=\ngithub.com/ipfs/go-log v1.0.4 h1:6nLQdX4W8P9yZZFH7mO+X/PzjN8Laozm/lMJ6esdgzY=\ngithub.com/ipfs/go-log v1.0.4/go.mod h1:oDCg2FkjogeFOhqqb+N39l2RpTNPL6F/StPkB3kPgcs=\ngithub.com/ipfs/go-log/v2 v2.0.2/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBWFaa9+0=\ngithub.com/ipfs/go-log/v2 v2.0.3/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBWFaa9+0=\ngithub.com/ipfs/go-log/v2 v2.0.5 h1:fL4YI+1g5V/b1Yxr1qAiXTMg1H8z9vx/VmJxBuQMHvU=\ngithub.com/ipfs/go-log/v2 v2.0.5/go.mod h1:eZs4Xt4ZUJQFM3DlanGhy7TkwwawCZcSByscwkWG+dw=\ngithub.com/jackpal/gateway v1.0.5/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA=\ngithub.com/jackpal/go-nat-pmp v1.0.1/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=\ngithub.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus=\ngithub.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=\ngithub.com/jbenet/go-cienv v0.0.0-20150120210510-1bb1476777ec/go.mod h1:rGaEvXB4uRSZMmzKNLoXvTu1sfx+1kv/DojUlPrSZGs=\ngithub.com/jbenet/go-cienv v0.1.0 h1:Vc/s0QbQtoxX8MwwSLWWh+xNNZvM3Lw7NsTcHrvvhMc=\ngithub.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA=\ngithub.com/jbenet/go-temp-err-catcher v0.0.0-20150120210811-aac704a3f4f2 h1:vhC1OXXiT9R2pczegwz6moDvuRpggaroAXhPIseh57A=\ngithub.com/jbenet/go-temp-err-catcher v0.0.0-20150120210811-aac704a3f4f2/go.mod h1:8GXXJV31xl8whumTzdZsTt3RnUIiPqzkyf7mxToRCMs=\ngithub.com/jbenet/goprocess v0.0.0-20160826012719-b497e2f366b8/go.mod h1:Ly/wlsjFq/qrU3Rar62tu1gASgGw6chQbSh/XgIIXCY=\ngithub.com/jbenet/goprocess v0.1.3/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4=\ngithub.com/jbenet/goprocess v0.1.4 h1:DRGOFReOMqqDNXwW70QkacFW0YN9QnwLV0Vqk+3oU0o=\ngithub.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4=\ngithub.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e/go.mod h1:G1CVv03EnqU1wYL2dFwXxW2An0az9JTl/ZsqXQeBlkU=\ngithub.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=\ngithub.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=\ngithub.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=\ngithub.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=\ngithub.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=\ngithub.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=\ngithub.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=\ngithub.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=\ngithub.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=\ngithub.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=\ngithub.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=\ngithub.com/jsternberg/zap-logfmt v1.0.0/go.mod h1:uvPs/4X51zdkcm5jXl5SYoN+4RK21K8mysFmDaM/h+o=\ngithub.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=\ngithub.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=\ngithub.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=\ngithub.com/jwilder/encoding v0.0.0-20170811194829-b4e1701a28ef/go.mod h1:Ct9fl0F6iIOGgxJ5npU/IUOhOhqlVrGjyIZc8/MagT0=\ngithub.com/kami-zh/go-capturer v0.0.0-20171211120116-e492ea43421d/go.mod h1:P2viExyCEfeWGU259JnaQ34Inuec4R38JCyBx2edgD0=\ngithub.com/karalabe/usb v0.0.2/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU=\ngithub.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=\ngithub.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=\ngithub.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=\ngithub.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=\ngithub.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=\ngithub.com/klauspost/cpuid v0.0.0-20170728055534-ae7887de9fa5/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=\ngithub.com/klauspost/crc32 v0.0.0-20161016154125-cb6bfca970f6/go.mod h1:+ZoRqAPRLkC4NPOvfYeR5KNOrY6TD+/sAC3HXPZgDYg=\ngithub.com/klauspost/pgzip v1.0.2-0.20170402124221-0bf5dcad4ada/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=\ngithub.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=\ngithub.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d h1:68u9r4wEvL3gYg2jvAOgROwZ3H+Y3hIDk4tbbmIjcYQ=\ngithub.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk=\ngithub.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=\ngithub.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=\ngithub.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=\ngithub.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=\ngithub.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=\ngithub.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=\ngithub.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=\ngithub.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=\ngithub.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=\ngithub.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=\ngithub.com/labstack/echo/v4 v4.2.1/go.mod h1:AA49e0DZ8kk5jTOOCKNuPR6oTnBS0dYiM4FW1e6jwpg=\ngithub.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=\ngithub.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8=\ngithub.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=\ngithub.com/libp2p/go-addr-util v0.0.1 h1:TpTQm9cXVRVSKsYbgQ7GKc3KbbHVTnbostgGaDEP+88=\ngithub.com/libp2p/go-addr-util v0.0.1/go.mod h1:4ac6O7n9rIAKB1dnd+s8IbbMXkt+oBpzX4/+RACcnlQ=\ngithub.com/libp2p/go-buffer-pool v0.0.1/go.mod h1:xtyIz9PMobb13WaxR6Zo1Pd1zXJKYg0a8KiIvDp3TzQ=\ngithub.com/libp2p/go-buffer-pool v0.0.2 h1:QNK2iAFa8gjAe1SPz6mHSMuCcjs+X1wlHzeOSqcmlfs=\ngithub.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoRZd1Vi32+RXyFM=\ngithub.com/libp2p/go-conn-security-multistream v0.1.0/go.mod h1:aw6eD7LOsHEX7+2hJkDxw1MteijaVcI+/eP2/x3J1xc=\ngithub.com/libp2p/go-conn-security-multistream v0.2.0 h1:uNiDjS58vrvJTg9jO6bySd1rMKejieG7v45ekqHbZ1M=\ngithub.com/libp2p/go-conn-security-multistream v0.2.0/go.mod h1:hZN4MjlNetKD3Rq5Jb/P5ohUnFLNzEAR4DLSzpn2QLU=\ngithub.com/libp2p/go-eventbus v0.1.0 h1:mlawomSAjjkk97QnYiEmHsLu7E136+2oCWSHRUvMfzQ=\ngithub.com/libp2p/go-eventbus v0.1.0/go.mod h1:vROgu5cs5T7cv7POWlWxBaVLxfSegC5UGQf8A2eEmx4=\ngithub.com/libp2p/go-flow-metrics v0.0.1/go.mod h1:Iv1GH0sG8DtYN3SVJ2eG221wMiNpZxBdp967ls1g+k8=\ngithub.com/libp2p/go-flow-metrics v0.0.2/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs=\ngithub.com/libp2p/go-flow-metrics v0.0.3 h1:8tAs/hSdNvUiLgtlSy3mxwxWP4I9y/jlkPFT7epKdeM=\ngithub.com/libp2p/go-flow-metrics v0.0.3/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs=\ngithub.com/libp2p/go-libp2p v0.6.1/go.mod h1:CTFnWXogryAHjXAKEbOf1OWY+VeAP3lDMZkfEI5sT54=\ngithub.com/libp2p/go-libp2p v0.7.0/go.mod h1:hZJf8txWeCduQRDC/WSqBGMxaTHCOYHt2xSU1ivxn0k=\ngithub.com/libp2p/go-libp2p v0.7.4/go.mod h1:oXsBlTLF1q7pxr+9w6lqzS1ILpyHsaBPniVO7zIHGMw=\ngithub.com/libp2p/go-libp2p v0.8.2/go.mod h1:NQDA/F/qArMHGe0J7sDScaKjW8Jh4y/ozQqBbYJ+BnA=\ngithub.com/libp2p/go-libp2p v0.8.3 h1:IFWeNzxkBaNO1N8stN9ayFGdC6RmVuSsKd5bou7qpK0=\ngithub.com/libp2p/go-libp2p v0.8.3/go.mod h1:EsH1A+8yoWK+L4iKcbPYu6MPluZ+CHWI9El8cTaefiM=\ngithub.com/libp2p/go-libp2p-autonat v0.1.1/go.mod h1:OXqkeGOY2xJVWKAGV2inNF5aKN/djNA3fdpCWloIudE=\ngithub.com/libp2p/go-libp2p-autonat v0.2.0/go.mod h1:DX+9teU4pEEoZUqR1PiMlqliONQdNbfzE1C718tcViI=\ngithub.com/libp2p/go-libp2p-autonat v0.2.1/go.mod h1:MWtAhV5Ko1l6QBsHQNSuM6b1sRkXrpk0/LqCr+vCVxI=\ngithub.com/libp2p/go-libp2p-autonat v0.2.2 h1:4dlgcEEugTFWSvdG2UIFxhnOMpX76QaZSRAtXmYB8n4=\ngithub.com/libp2p/go-libp2p-autonat v0.2.2/go.mod h1:HsM62HkqZmHR2k1xgX34WuWDzk/nBwNHoeyyT4IWV6A=\ngithub.com/libp2p/go-libp2p-blankhost v0.1.1/go.mod h1:pf2fvdLJPsC1FsVrNP3DUUvMzUts2dsLLBEpo1vW1ro=\ngithub.com/libp2p/go-libp2p-blankhost v0.1.4 h1:I96SWjR4rK9irDHcHq3XHN6hawCRTPUADzkJacgZLvk=\ngithub.com/libp2p/go-libp2p-blankhost v0.1.4/go.mod h1:oJF0saYsAXQCSfDq254GMNmLNz6ZTHTOvtF4ZydUvwU=\ngithub.com/libp2p/go-libp2p-circuit v0.1.4/go.mod h1:CY67BrEjKNDhdTk8UgBX1Y/H5c3xkAcs3gnksxY7osU=\ngithub.com/libp2p/go-libp2p-circuit v0.2.1/go.mod h1:BXPwYDN5A8z4OEY9sOfr2DUQMLQvKt/6oku45YUmjIo=\ngithub.com/libp2p/go-libp2p-circuit v0.2.2 h1:87RLabJ9lrhoiSDDZyCJ80ZlI5TLJMwfyoGAaWXzWqA=\ngithub.com/libp2p/go-libp2p-circuit v0.2.2/go.mod h1:nkG3iE01tR3FoQ2nMm06IUrCpCyJp1Eo4A1xYdpjfs4=\ngithub.com/libp2p/go-libp2p-core v0.0.1/go.mod h1:g/VxnTZ/1ygHxH3dKok7Vno1VfpvGcGip57wjTU4fco=\ngithub.com/libp2p/go-libp2p-core v0.0.4/go.mod h1:jyuCQP356gzfCFtRKyvAbNkyeuxb7OlyhWZ3nls5d2I=\ngithub.com/libp2p/go-libp2p-core v0.2.0/go.mod h1:X0eyB0Gy93v0DZtSYbEM7RnMChm9Uv3j7yRXjO77xSI=\ngithub.com/libp2p/go-libp2p-core v0.2.2/go.mod h1:8fcwTbsG2B+lTgRJ1ICZtiM5GWCWZVoVrLaDRvIRng0=\ngithub.com/libp2p/go-libp2p-core v0.2.4/go.mod h1:STh4fdfa5vDYr0/SzYYeqnt+E6KfEV5VxfIrm0bcI0g=\ngithub.com/libp2p/go-libp2p-core v0.2.5/go.mod h1:6+5zJmKhsf7yHn1RbmYDu08qDUpIUxGdqHuEZckmZOA=\ngithub.com/libp2p/go-libp2p-core v0.3.0/go.mod h1:ACp3DmS3/N64c2jDzcV429ukDpicbL6+TrrxANBjPGw=\ngithub.com/libp2p/go-libp2p-core v0.3.1/go.mod h1:thvWy0hvaSBhnVBaW37BvzgVV68OUhgJJLAa6almrII=\ngithub.com/libp2p/go-libp2p-core v0.4.0/go.mod h1:49XGI+kc38oGVwqSBhDEwytaAxgZasHhFfQKibzTls0=\ngithub.com/libp2p/go-libp2p-core v0.5.0/go.mod h1:49XGI+kc38oGVwqSBhDEwytaAxgZasHhFfQKibzTls0=\ngithub.com/libp2p/go-libp2p-core v0.5.1/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y=\ngithub.com/libp2p/go-libp2p-core v0.5.2/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y=\ngithub.com/libp2p/go-libp2p-core v0.5.3 h1:b9W3w7AZR2n/YJhG8d0qPFGhGhCWKIvPuJgp4hhc4MM=\ngithub.com/libp2p/go-libp2p-core v0.5.3/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y=\ngithub.com/libp2p/go-libp2p-crypto v0.1.0/go.mod h1:sPUokVISZiy+nNuTTH/TY+leRSxnFj/2GLjtOTW90hI=\ngithub.com/libp2p/go-libp2p-discovery v0.2.0/go.mod h1:s4VGaxYMbw4+4+tsoQTqh7wfxg97AEdo4GYBt6BadWg=\ngithub.com/libp2p/go-libp2p-discovery v0.3.0/go.mod h1:o03drFnz9BVAZdzC/QUQ+NeQOu38Fu7LJGEOK2gQltw=\ngithub.com/libp2p/go-libp2p-discovery v0.4.0 h1:dK78UhopBk48mlHtRCzbdLm3q/81g77FahEBTjcqQT8=\ngithub.com/libp2p/go-libp2p-discovery v0.4.0/go.mod h1:bZ0aJSrFc/eX2llP0ryhb1kpgkPyTo23SJ5b7UQCMh4=\ngithub.com/libp2p/go-libp2p-kad-dht v0.7.11 h1:MP0DEuxO/Blg1AklIVV1P4R5xtYX+ZyXBCtEN7f60yQ=\ngithub.com/libp2p/go-libp2p-kad-dht v0.7.11/go.mod h1:1ht6+bG3Or+fNNERWPYmLacs6TN0CxBkFB5IKIWWwOI=\ngithub.com/libp2p/go-libp2p-kbucket v0.4.1 h1:6FyzbQuGLPzbMv3HiD232zqscIz5iB8ppJwb380+OGI=\ngithub.com/libp2p/go-libp2p-kbucket v0.4.1/go.mod h1:7sCeZx2GkNK1S6lQnGUW5JYZCFPnXzAZCCBBS70lytY=\ngithub.com/libp2p/go-libp2p-loggables v0.1.0 h1:h3w8QFfCt2UJl/0/NW4K829HX/0S4KD31PQ7m8UXXO8=\ngithub.com/libp2p/go-libp2p-loggables v0.1.0/go.mod h1:EyumB2Y6PrYjr55Q3/tiJ/o3xoDasoRYM7nOzEpoa90=\ngithub.com/libp2p/go-libp2p-mplex v0.2.0/go.mod h1:Ejl9IyjvXJ0T9iqUTE1jpYATQ9NM3g+OtR+EMMODbKo=\ngithub.com/libp2p/go-libp2p-mplex v0.2.1/go.mod h1:SC99Rxs8Vuzrf/6WhmH41kNn13TiYdAWNYHrwImKLnE=\ngithub.com/libp2p/go-libp2p-mplex v0.2.2/go.mod h1:74S9eum0tVQdAfFiKxAyKzNdSuLqw5oadDq7+L/FELo=\ngithub.com/libp2p/go-libp2p-mplex v0.2.3 h1:2zijwaJvpdesST2MXpI5w9wWFRgYtMcpRX7rrw0jmOo=\ngithub.com/libp2p/go-libp2p-mplex v0.2.3/go.mod h1:CK3p2+9qH9x+7ER/gWWDYJ3QW5ZxWDkm+dVvjfuG3ek=\ngithub.com/libp2p/go-libp2p-nat v0.0.5/go.mod h1:1qubaE5bTZMJE+E/uu2URroMbzdubFz1ChgiN79yKPE=\ngithub.com/libp2p/go-libp2p-nat v0.0.6 h1:wMWis3kYynCbHoyKLPBEMu4YRLltbm8Mk08HGSfvTkU=\ngithub.com/libp2p/go-libp2p-nat v0.0.6/go.mod h1:iV59LVhB3IkFvS6S6sauVTSOrNEANnINbI/fkaLimiw=\ngithub.com/libp2p/go-libp2p-netutil v0.1.0 h1:zscYDNVEcGxyUpMd0JReUZTrpMfia8PmLKcKF72EAMQ=\ngithub.com/libp2p/go-libp2p-netutil v0.1.0/go.mod h1:3Qv/aDqtMLTUyQeundkKsA+YCThNdbQD54k3TqjpbFU=\ngithub.com/libp2p/go-libp2p-peer v0.2.0/go.mod h1:RCffaCvUyW2CJmG2gAWVqwePwW7JMgxjsHm7+J5kjWY=\ngithub.com/libp2p/go-libp2p-peerstore v0.1.0/go.mod h1:2CeHkQsr8svp4fZ+Oi9ykN1HBb6u0MOvdJ7YIsmcwtY=\ngithub.com/libp2p/go-libp2p-peerstore v0.1.3/go.mod h1:BJ9sHlm59/80oSkpWgr1MyY1ciXAXV397W6h1GH/uKI=\ngithub.com/libp2p/go-libp2p-peerstore v0.1.4/go.mod h1:+4BDbDiiKf4PzpANZDAT+knVdLxvqh7hXOujessqdzs=\ngithub.com/libp2p/go-libp2p-peerstore v0.2.0/go.mod h1:N2l3eVIeAitSg3Pi2ipSrJYnqhVnMNQZo9nkSCuAbnQ=\ngithub.com/libp2p/go-libp2p-peerstore v0.2.1/go.mod h1:NQxhNjWxf1d4w6PihR8btWIRjwRLBr4TYKfNgrUkOPA=\ngithub.com/libp2p/go-libp2p-peerstore v0.2.2/go.mod h1:NQxhNjWxf1d4w6PihR8btWIRjwRLBr4TYKfNgrUkOPA=\ngithub.com/libp2p/go-libp2p-peerstore v0.2.3 h1:MofRq2l3c15vQpEygTetV+zRRrncz+ktiXW7H2EKoEQ=\ngithub.com/libp2p/go-libp2p-peerstore v0.2.3/go.mod h1:K8ljLdFn590GMttg/luh4caB/3g0vKuY01psze0upRw=\ngithub.com/libp2p/go-libp2p-pnet v0.2.0 h1:J6htxttBipJujEjz1y0a5+eYoiPcFHhSYHH6na5f0/k=\ngithub.com/libp2p/go-libp2p-pnet v0.2.0/go.mod h1:Qqvq6JH/oMZGwqs3N1Fqhv8NVhrdYcO0BW4wssv21LA=\ngithub.com/libp2p/go-libp2p-record v0.1.2 h1:M50VKzWnmUrk/M5/Dz99qO9Xh4vs8ijsK+7HkJvRP+0=\ngithub.com/libp2p/go-libp2p-record v0.1.2/go.mod h1:pal0eNcT5nqZaTV7UGhqeGqxFgGdsU/9W//C8dqjQDk=\ngithub.com/libp2p/go-libp2p-routing-helpers v0.2.3/go.mod h1:795bh+9YeoFl99rMASoiVgHdi5bjack0N1+AFAdbvBw=\ngithub.com/libp2p/go-libp2p-secio v0.1.0/go.mod h1:tMJo2w7h3+wN4pgU2LSYeiKPrfqBgkOsdiKK77hE7c8=\ngithub.com/libp2p/go-libp2p-secio v0.2.0/go.mod h1:2JdZepB8J5V9mBp79BmwsaPQhRPNN2NrnB2lKQcdy6g=\ngithub.com/libp2p/go-libp2p-secio v0.2.1/go.mod h1:cWtZpILJqkqrSkiYcDBh5lA3wbT2Q+hz3rJQq3iftD8=\ngithub.com/libp2p/go-libp2p-secio v0.2.2 h1:rLLPvShPQAcY6eNurKNZq3eZjPWfU9kXF2eI9jIYdrg=\ngithub.com/libp2p/go-libp2p-secio v0.2.2/go.mod h1:wP3bS+m5AUnFA+OFO7Er03uO1mncHG0uVwGrwvjYlNY=\ngithub.com/libp2p/go-libp2p-swarm v0.1.0/go.mod h1:wQVsCdjsuZoc730CgOvh5ox6K8evllckjebkdiY5ta4=\ngithub.com/libp2p/go-libp2p-swarm v0.2.2/go.mod h1:fvmtQ0T1nErXym1/aa1uJEyN7JzaTNyBcHImCxRpPKU=\ngithub.com/libp2p/go-libp2p-swarm v0.2.3 h1:uVkCb8Blfg7HQ/f30TyHn1g/uCwXsAET7pU0U59gx/A=\ngithub.com/libp2p/go-libp2p-swarm v0.2.3/go.mod h1:P2VO/EpxRyDxtChXz/VPVXyTnszHvokHKRhfkEgFKNM=\ngithub.com/libp2p/go-libp2p-testing v0.0.2/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E=\ngithub.com/libp2p/go-libp2p-testing v0.0.3/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E=\ngithub.com/libp2p/go-libp2p-testing v0.0.4/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E=\ngithub.com/libp2p/go-libp2p-testing v0.1.0/go.mod h1:xaZWMJrPUM5GlDBxCeGUi7kI4eqnjVyavGroI2nxEM0=\ngithub.com/libp2p/go-libp2p-testing v0.1.1 h1:U03z3HnGI7Ni8Xx6ONVZvUFOAzWYmolWf5W5jAOPNmU=\ngithub.com/libp2p/go-libp2p-testing v0.1.1/go.mod h1:xaZWMJrPUM5GlDBxCeGUi7kI4eqnjVyavGroI2nxEM0=\ngithub.com/libp2p/go-libp2p-tls v0.1.3 h1:twKMhMu44jQO+HgQK9X8NHO5HkeJu2QbhLzLJpa8oNM=\ngithub.com/libp2p/go-libp2p-tls v0.1.3/go.mod h1:wZfuewxOndz5RTnCAxFliGjvYSDA40sKitV4c50uI1M=\ngithub.com/libp2p/go-libp2p-transport-upgrader v0.1.1/go.mod h1:IEtA6or8JUbsV07qPW4r01GnTenLW4oi3lOPbUMGJJA=\ngithub.com/libp2p/go-libp2p-transport-upgrader v0.2.0 h1:5EhPgQhXZNyfL22ERZTUoVp9UVVbNowWNVtELQaKCHk=\ngithub.com/libp2p/go-libp2p-transport-upgrader v0.2.0/go.mod h1:mQcrHj4asu6ArfSoMuyojOdjx73Q47cYD7s5+gZOlns=\ngithub.com/libp2p/go-libp2p-yamux v0.2.0/go.mod h1:Db2gU+XfLpm6E4rG5uGCFX6uXA8MEXOxFcRoXUODaK8=\ngithub.com/libp2p/go-libp2p-yamux v0.2.2/go.mod h1:lIohaR0pT6mOt0AZ0L2dFze9hds9Req3OfS+B+dv4qw=\ngithub.com/libp2p/go-libp2p-yamux v0.2.5/go.mod h1:Zpgj6arbyQrmZ3wxSZxfBmbdnWtbZ48OpsfmQVTErwA=\ngithub.com/libp2p/go-libp2p-yamux v0.2.7 h1:vzKu0NVtxvEIDGCv6mjKRcK0gipSgaXmJZ6jFv0d/dk=\ngithub.com/libp2p/go-libp2p-yamux v0.2.7/go.mod h1:X28ENrBMU/nm4I3Nx4sZ4dgjZ6VhLEn0XhIoZ5viCwU=\ngithub.com/libp2p/go-maddr-filter v0.0.4/go.mod h1:6eT12kSQMA9x2pvFQa+xesMKUBlj9VImZbj3B9FBH/Q=\ngithub.com/libp2p/go-maddr-filter v0.0.5 h1:CW3AgbMO6vUvT4kf87y4N+0P8KUl2aqLYhrGyDUbLSg=\ngithub.com/libp2p/go-maddr-filter v0.0.5/go.mod h1:Jk+36PMfIqCJhAnaASRH83bdAvfDRp/w6ENFaC9bG+M=\ngithub.com/libp2p/go-mplex v0.0.3/go.mod h1:pK5yMLmOoBR1pNCqDlA2GQrdAVTMkqFalaTWe7l4Yd0=\ngithub.com/libp2p/go-mplex v0.1.0/go.mod h1:SXgmdki2kwCUlCCbfGLEgHjC4pFqhTp0ZoV6aiKgxDU=\ngithub.com/libp2p/go-mplex v0.1.1/go.mod h1:Xgz2RDCi3co0LeZfgjm4OgUF15+sVR8SRcu3SFXI1lk=\ngithub.com/libp2p/go-mplex v0.1.2 h1:qOg1s+WdGLlpkrczDqmhYzyk3vCfsQ8+RxRTQjOZWwI=\ngithub.com/libp2p/go-mplex v0.1.2/go.mod h1:Xgz2RDCi3co0LeZfgjm4OgUF15+sVR8SRcu3SFXI1lk=\ngithub.com/libp2p/go-msgio v0.0.2/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ=\ngithub.com/libp2p/go-msgio v0.0.4 h1:agEFehY3zWJFUHK6SEMR7UYmk2z6kC3oeCM7ybLhguA=\ngithub.com/libp2p/go-msgio v0.0.4/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ=\ngithub.com/libp2p/go-nat v0.0.4/go.mod h1:Nmw50VAvKuk38jUBcmNh6p9lUJLoODbJRvYAa/+KSDo=\ngithub.com/libp2p/go-nat v0.0.5 h1:qxnwkco8RLKqVh1NmjQ+tJ8p8khNLFxuElYG/TwqW4Q=\ngithub.com/libp2p/go-nat v0.0.5/go.mod h1:B7NxsVNPZmRLvMOwiEO1scOSyjA56zxYAGv1yQgRkEU=\ngithub.com/libp2p/go-netroute v0.1.2 h1:UHhB35chwgvcRI392znJA3RCBtZ3MpE3ahNCN5MR4Xg=\ngithub.com/libp2p/go-netroute v0.1.2/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk=\ngithub.com/libp2p/go-openssl v0.0.2/go.mod h1:v8Zw2ijCSWBQi8Pq5GAixw6DbFfa9u6VIYDXnvOXkc0=\ngithub.com/libp2p/go-openssl v0.0.3/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc=\ngithub.com/libp2p/go-openssl v0.0.4 h1:d27YZvLoTyMhIN4njrkr8zMDOM4lfpHIp6A+TK9fovg=\ngithub.com/libp2p/go-openssl v0.0.4/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc=\ngithub.com/libp2p/go-reuseport v0.0.1 h1:7PhkfH73VXfPJYKQ6JwS5I/eVcoyYi9IMNGc6FWpFLw=\ngithub.com/libp2p/go-reuseport v0.0.1/go.mod h1:jn6RmB1ufnQwl0Q1f+YxAj8isJgDCQzaaxIFYDhcYEA=\ngithub.com/libp2p/go-reuseport-transport v0.0.2/go.mod h1:YkbSDrvjUVDL6b8XqriyA20obEtsW9BLkuOUyQAOCbs=\ngithub.com/libp2p/go-reuseport-transport v0.0.3 h1:zzOeXnTooCkRvoH+bSXEfXhn76+LAiwoneM0gnXjF2M=\ngithub.com/libp2p/go-reuseport-transport v0.0.3/go.mod h1:Spv+MPft1exxARzP2Sruj2Wb5JSyHNncjf1Oi2dEbzM=\ngithub.com/libp2p/go-sockaddr v0.0.2 h1:tCuXfpA9rq7llM/v834RKc/Xvovy/AqM9kHvTV/jY/Q=\ngithub.com/libp2p/go-sockaddr v0.0.2/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k=\ngithub.com/libp2p/go-stream-muxer v0.0.1/go.mod h1:bAo8x7YkSpadMTbtTaxGVHWUQsR/l5MEaHbKaliuT14=\ngithub.com/libp2p/go-stream-muxer-multistream v0.2.0/go.mod h1:j9eyPol/LLRqT+GPLSxvimPhNph4sfYfMoDPd7HkzIc=\ngithub.com/libp2p/go-stream-muxer-multistream v0.3.0 h1:TqnSHPJEIqDEO7h1wZZ0p3DXdvDSiLHQidKKUGZtiOY=\ngithub.com/libp2p/go-stream-muxer-multistream v0.3.0/go.mod h1:yDh8abSIzmZtqtOt64gFJUXEryejzNb0lisTt+fAMJA=\ngithub.com/libp2p/go-tcp-transport v0.1.0/go.mod h1:oJ8I5VXryj493DEJ7OsBieu8fcg2nHGctwtInJVpipc=\ngithub.com/libp2p/go-tcp-transport v0.1.1/go.mod h1:3HzGvLbx6etZjnFlERyakbaYPdfjg2pWP97dFZworkY=\ngithub.com/libp2p/go-tcp-transport v0.2.0 h1:YoThc549fzmNJIh7XjHVtMIFaEDRtIrtWciG5LyYAPo=\ngithub.com/libp2p/go-tcp-transport v0.2.0/go.mod h1:vX2U0CnWimU4h0SGSEsg++AzvBcroCGYw28kh94oLe0=\ngithub.com/libp2p/go-ws-transport v0.2.0/go.mod h1:9BHJz/4Q5A9ludYWKoGCFC5gUElzlHoKzu0yY9p/klM=\ngithub.com/libp2p/go-ws-transport v0.3.0/go.mod h1:bpgTJmRZAvVHrgHybCVyqoBmyLQ1fiZuEaBYusP5zsk=\ngithub.com/libp2p/go-ws-transport v0.3.1 h1:ZX5rWB8nhRRJVaPO6tmkGI/Xx8XNboYX20PW5hXIscw=\ngithub.com/libp2p/go-ws-transport v0.3.1/go.mod h1:bpgTJmRZAvVHrgHybCVyqoBmyLQ1fiZuEaBYusP5zsk=\ngithub.com/libp2p/go-yamux v1.2.2/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow=\ngithub.com/libp2p/go-yamux v1.3.0/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow=\ngithub.com/libp2p/go-yamux v1.3.3/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow=\ngithub.com/libp2p/go-yamux v1.3.5 h1:ibuz4naPAully0pN6J/kmUARiqLpnDQIzI/8GCOrljg=\ngithub.com/libp2p/go-yamux v1.3.5/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow=\ngithub.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=\ngithub.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=\ngithub.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=\ngithub.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=\ngithub.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ=\ngithub.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=\ngithub.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=\ngithub.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=\ngithub.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=\ngithub.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=\ngithub.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=\ngithub.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=\ngithub.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=\ngithub.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=\ngithub.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=\ngithub.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=\ngithub.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=\ngithub.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=\ngithub.com/mattn/go-tty v0.0.0-20180907095812-13ff1204f104/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE=\ngithub.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=\ngithub.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=\ngithub.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=\ngithub.com/miekg/dns v1.1.12/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=\ngithub.com/miekg/dns v1.1.28/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=\ngithub.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g=\ngithub.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ=\ngithub.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U=\ngithub.com/minio/sha256-simd v0.0.0-20190328051042-05b4dd3047e5/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U=\ngithub.com/minio/sha256-simd v0.1.0/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U=\ngithub.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=\ngithub.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU=\ngithub.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=\ngithub.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=\ngithub.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=\ngithub.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=\ngithub.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4=\ngithub.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=\ngithub.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=\ngithub.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=\ngithub.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=\ngithub.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8=\ngithub.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8=\ngithub.com/mr-tron/base58 v1.1.1/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8=\ngithub.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=\ngithub.com/mr-tron/base58 v1.1.3 h1:v+sk57XuaCKGXpWtVBX8YJzO7hMGx4Aajh4TQbdEFdc=\ngithub.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=\ngithub.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg=\ngithub.com/multiformats/go-base32 v0.0.3 h1:tw5+NhuwaOjJCC5Pp82QuXbrmLzWg7uxlMFp8Nq/kkI=\ngithub.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA=\ngithub.com/multiformats/go-multiaddr v0.0.1/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44=\ngithub.com/multiformats/go-multiaddr v0.0.2/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44=\ngithub.com/multiformats/go-multiaddr v0.0.4/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44=\ngithub.com/multiformats/go-multiaddr v0.1.0/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44=\ngithub.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo=\ngithub.com/multiformats/go-multiaddr v0.2.0/go.mod h1:0nO36NvPpyV4QzvTLi/lafl2y95ncPj0vFwVF6k6wJ4=\ngithub.com/multiformats/go-multiaddr v0.2.1 h1:SgG/cw5vqyB5QQe5FPe2TqggU9WtrA9X4nZw7LlVqOI=\ngithub.com/multiformats/go-multiaddr v0.2.1/go.mod h1:s/Apk6IyxfvMjDafnhJgJ3/46z7tZ04iMk5wP4QMGGE=\ngithub.com/multiformats/go-multiaddr-dns v0.0.1/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q=\ngithub.com/multiformats/go-multiaddr-dns v0.0.2/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q=\ngithub.com/multiformats/go-multiaddr-dns v0.2.0 h1:YWJoIDwLePniH7OU5hBnDZV6SWuvJqJ0YtN6pLeH9zA=\ngithub.com/multiformats/go-multiaddr-dns v0.2.0/go.mod h1:TJ5pr5bBO7Y1B18djPuRsVkduhQH2YqYSbxWJzYGdK0=\ngithub.com/multiformats/go-multiaddr-fmt v0.0.1/go.mod h1:aBYjqL4T/7j4Qx+R73XSv/8JsgnRFlf0w2KGLCmXl3Q=\ngithub.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E=\ngithub.com/multiformats/go-multiaddr-fmt v0.1.0/go.mod h1:hGtDIW4PU4BqJ50gW2quDuPVjyWNZxToGUh/HwTZYJo=\ngithub.com/multiformats/go-multiaddr-net v0.0.1/go.mod h1:nw6HSxNmCIQH27XPGBuX+d1tnvM7ihcFwHMSstNAVUU=\ngithub.com/multiformats/go-multiaddr-net v0.1.0/go.mod h1:5JNbcfBOP4dnhoZOv10JJVkJO0pCCEf8mTnipAo2UZQ=\ngithub.com/multiformats/go-multiaddr-net v0.1.1/go.mod h1:5JNbcfBOP4dnhoZOv10JJVkJO0pCCEf8mTnipAo2UZQ=\ngithub.com/multiformats/go-multiaddr-net v0.1.2/go.mod h1:QsWt3XK/3hwvNxZJp92iMQKME1qHfpYmyIjFVsSOY6Y=\ngithub.com/multiformats/go-multiaddr-net v0.1.3/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA=\ngithub.com/multiformats/go-multiaddr-net v0.1.4 h1:g6gwydsfADqFvrHoMkS0n9Ok9CG6F7ytOH/bJDkhIOY=\ngithub.com/multiformats/go-multiaddr-net v0.1.4/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA=\ngithub.com/multiformats/go-multibase v0.0.1 h1:PN9/v21eLywrFWdFNsFKaU04kLJzuYzmrJR+ubhT9qA=\ngithub.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs=\ngithub.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U=\ngithub.com/multiformats/go-multihash v0.0.5/go.mod h1:lt/HCbqlQwlPBz7lv0sQCdtfcMtlJvakRUn/0Ual8po=\ngithub.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew=\ngithub.com/multiformats/go-multihash v0.0.9/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew=\ngithub.com/multiformats/go-multihash v0.0.10/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew=\ngithub.com/multiformats/go-multihash v0.0.13 h1:06x+mk/zj1FoMsgNejLpy6QTvJqlSt/BhLEy87zidlc=\ngithub.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc=\ngithub.com/multiformats/go-multistream v0.1.0/go.mod h1:fJTiDfXJVmItycydCnNx4+wSzZ5NwG2FEVAI30fiovg=\ngithub.com/multiformats/go-multistream v0.1.1 h1:JlAdpIFhBhGRLxe9W6Om0w++Gd6KMWoFPZL/dEnm9nI=\ngithub.com/multiformats/go-multistream v0.1.1/go.mod h1:KmHZ40hzVxiaiwlj3MEbYgK9JFk2/9UktWZAF54Du38=\ngithub.com/multiformats/go-varint v0.0.1/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=\ngithub.com/multiformats/go-varint v0.0.2/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=\ngithub.com/multiformats/go-varint v0.0.5 h1:XVZwSo04Cs3j/jS0uAEPpT3JY6DzMcVLLoWOSnCxOjg=\ngithub.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=\ngithub.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=\ngithub.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0=\ngithub.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E=\ngithub.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=\ngithub.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=\ngithub.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=\ngithub.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=\ngithub.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=\ngithub.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=\ngithub.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=\ngithub.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg=\ngithub.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=\ngithub.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA=\ngithub.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=\ngithub.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=\ngithub.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=\ngithub.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=\ngithub.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=\ngithub.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE=\ngithub.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=\ngithub.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=\ngithub.com/opentracing/opentracing-go v1.0.3-0.20180606204148-bd9c31933947/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=\ngithub.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU=\ngithub.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=\ngithub.com/paulbellamy/ratecounter v0.2.0/go.mod h1:Hfx1hDpSGoqxkVVpBi/IlYD7kChlfo5C6hzIHwPqfFE=\ngithub.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=\ngithub.com/peterh/liner v1.0.1-0.20180619022028-8c1271fcf47f/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc=\ngithub.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0=\ngithub.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=\ngithub.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=\ngithub.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=\ngithub.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pkg/term v0.0.0-20180730021639-bffc007b7fd5/go.mod h1:eCbImbZ95eXtAUIbLAuAVnBnwf83mjf6QIVH8SHYwqQ=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=\ngithub.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=\ngithub.com/prometheus/client_golang v1.7.1 h1:NTGy1Ja9pByO+xAeH/qiWnLrKtr3hJPNjaVUwnjpdpA=\ngithub.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=\ngithub.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=\ngithub.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=\ngithub.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=\ngithub.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=\ngithub.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=\ngithub.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=\ngithub.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=\ngithub.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=\ngithub.com/prometheus/common v0.10.0 h1:RyRA7RzGXQZiW+tGMr7sxa85G1z0yOpM1qq5c8lNawc=\ngithub.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=\ngithub.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=\ngithub.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=\ngithub.com/prometheus/procfs v0.1.3 h1:F0+tqvhOksq22sc6iCHF5WGlWjdwj92p0udFh1VFBS8=\ngithub.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=\ngithub.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=\ngithub.com/retailnext/hllpp v1.0.1-0.20180308014038-101a6d2f8b52/go.mod h1:RDpi1RftBQPUCDRw6SmxeaREsAaRKnOclghuzp/WRzc=\ngithub.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho=\ngithub.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=\ngithub.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=\ngithub.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=\ngithub.com/rs/zerolog v1.21.0 h1:Q3vdXlfLNT+OftyBHsU0Y445MD+8m8axjKgf2si0QcM=\ngithub.com/rs/zerolog v1.21.0/go.mod h1:ZPhntP/xmq1nnND05hhpAh2QMhSsA4UN3MGZ6O2J3hM=\ngithub.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=\ngithub.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=\ngithub.com/segmentio/kafka-go v0.1.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo=\ngithub.com/segmentio/kafka-go v0.2.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo=\ngithub.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=\ngithub.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=\ngithub.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=\ngithub.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=\ngithub.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=\ngithub.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=\ngithub.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=\ngithub.com/smola/gocompat v0.2.0/go.mod h1:1B0MlxbmoZNo3h8guHp8HztB3BSYR5itql9qtVc0ypY=\ngithub.com/spacemonkeygo/openssl v0.0.0-20181017203307-c2dcc5cca94a/go.mod h1:7AyxJNCJ7SBZ1MfVQCWD6Uqo2oubI2Eq2y2eqf+A5r0=\ngithub.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 h1:RC6RW7j+1+HkWaX/Yh71Ee5ZHaHYt7ZP4sQgUrm6cDU=\ngithub.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w0SWMsp6j9O/dk4/ZpIhL+3CkG8ofA2vuv7k+ltqUMc=\ngithub.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=\ngithub.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=\ngithub.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=\ngithub.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=\ngithub.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=\ngithub.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=\ngithub.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=\ngithub.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=\ngithub.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=\ngithub.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=\ngithub.com/src-d/envconfig v1.0.0/go.mod h1:Q9YQZ7BKITldTBnoxsE5gOeB5y66RyPXeue/R4aaNBc=\ngithub.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q=\ngithub.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/testify v1.2.0/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=\ngithub.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=\ngithub.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=\ngithub.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=\ngithub.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=\ngithub.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=\ngithub.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=\ngithub.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc=\ngithub.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=\ngithub.com/tklauser/go-sysconf v0.3.5/go.mod h1:MkWzOF4RMCshBAMXuhXJs64Rte09mITnppBXY/rYEFI=\ngithub.com/tklauser/numcpus v0.2.2/go.mod h1:x3qojaO3uyYt0i56EW/VUYs7uBvdl2fkfZFu0T9wgjM=\ngithub.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs=\ngithub.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=\ngithub.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=\ngithub.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=\ngithub.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=\ngithub.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=\ngithub.com/wangjia184/sortedset v0.0.0-20160527075905-f5d03557ba30/go.mod h1:YkocrP2K2tcw938x9gCOmT5G5eCD6jsTz0SZuyAqwIE=\ngithub.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 h1:EKhdznlJHPMoKr0XTrX+IlJs1LH3lyx2nfr1dOlZ79k=\ngithub.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1/go.mod h1:8UvriyWtv5Q5EOgjHaSseUEdkQfvwFv1I/In/O2M9gc=\ngithub.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc/go.mod h1:bopw91TMyo8J3tvftk8xmU2kPmlrt4nScJQZU2hE5EM=\ngithub.com/whyrusleeping/go-logging v0.0.1/go.mod h1:lDPYj54zutzG1XYfHAhcc7oNXEburHQBn+Iqd4yS4vE=\ngithub.com/whyrusleeping/mafmt v1.2.8 h1:TCghSl5kkwEE0j+sU/gudyhVMRlpBin8fMBBHg59EbA=\ngithub.com/whyrusleeping/mafmt v1.2.8/go.mod h1:faQJFPbLSxzD9xpA02ttW/tS9vZykNvXwGvqIpk20FA=\ngithub.com/whyrusleeping/mdns v0.0.0-20190826153040-b9b60ed33aa9/go.mod h1:j4l84WPFclQPj320J9gp0XwNKBb3U0zt5CBqjPp22G4=\ngithub.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 h1:E9S12nwJwEOXe2d6gT6qxdvqMnNq+VnSsKPgm2ZZNds=\ngithub.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7/go.mod h1:X2c0RVCI1eSUFI8eLcY3c0423ykwiUdxLJtkDvruhjI=\ngithub.com/willf/bitset v1.1.3/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=\ngithub.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE=\ngithub.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg=\ngithub.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=\ngithub.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngo.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=\ngo.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=\ngo.opencensus.io v0.22.1/go.mod h1:Ap50jQcDJrx6rB6VgeeFPtuPIf3wMRvRfrfYDO6+BmA=\ngo.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=\ngo.opencensus.io v0.22.3 h1:8sGtKOrtQqkN1bp2AtX+misvLIlOmsEsNd+9NIcPEm8=\ngo.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=\ngo.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=\ngo.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=\ngo.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk=\ngo.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=\ngo.uber.org/goleak v1.0.0 h1:qsup4IcBdlmsnGfqyLl4Ntn3C2XCCuKAE7DwHpScyUo=\ngo.uber.org/goleak v1.0.0/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=\ngo.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=\ngo.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A=\ngo.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=\ngo.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4=\ngo.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=\ngo.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=\ngo.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=\ngo.uber.org/zap v1.14.1 h1:nYDKopTbvAPq/NrUVZwT15y2lpROBiLLyoRTbXOYWOo=\ngo.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc=\ngolang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=\ngolang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=\ngolang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=\ngolang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=\ngolang.org/x/crypto v0.0.0-20190225124518-7f87c0fbb88b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=\ngolang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=\ngolang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20190909091759-094676da4a83/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=\ngolang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 h1:It14KIkyBFYkHkwZ7k45minvA9aorojkyjGk9KJ5B/w=\ngolang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=\ngolang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=\ngolang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=\ngolang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=\ngolang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=\ngolang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=\ngolang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=\ngolang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=\ngolang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=\ngolang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=\ngolang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=\ngolang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=\ngolang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=\ngolang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=\ngolang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=\ngolang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=\ngolang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=\ngolang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f h1:J5lckAjkw6qYlOZNj90mLYNTEKDvWeuc1yieZ8qUzUE=\ngolang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=\ngolang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=\ngolang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=\ngolang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=\ngolang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=\ngolang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=\ngolang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=\ngolang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190227160552-c95aed5357e7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=\ngolang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=\ngolang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=\ngolang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=\ngolang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=\ngolang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=\ngolang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=\ngolang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=\ngolang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=\ngolang.org/x/net v0.0.0-20210805182204-aaa1db679c0d h1:20cMwl2fHAzkJMEA+8J4JgqBQcQGzbisXo31MIeenXI=\ngolang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=\ngolang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=\ngolang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=\ngolang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190405154228-4b34438f7a67/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190526052359-791d8a0f4d09/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200107162124-548cf772de50/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210316164454-77fc1eacc6aa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210420205809-ac73e9fd8988/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210816183151-1e6c022a8912 h1:uCLL3g5wH2xjxVREVuAbP9JM5PPKjRbXKRa6IBjkzmU=\ngolang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=\ngolang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=\ngolang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=\ngolang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=\ngolang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=\ngolang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=\ngolang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=\ngolang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=\ngolang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=\ngolang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20181130052023-1c3d964395ce/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=\ngolang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=\ngolang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=\ngolang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=\ngolang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=\ngolang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=\ngolang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=\ngolang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200108203644-89082a384178/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY=\ngolang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=\ngolang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=\ngolang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo=\ngonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo=\ngonum.org/v1/gonum v0.6.0/go.mod h1:9mxDZsDKxgMAuccQkewq682L+0eCu4dCN2yonUJTCLU=\ngonum.org/v1/netlib v0.0.0-20181029234149-ec6d1f5cefe6/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw=\ngonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw=\ngonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc=\ngoogle.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=\ngoogle.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=\ngoogle.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=\ngoogle.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=\ngoogle.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=\ngoogle.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=\ngoogle.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=\ngoogle.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=\ngoogle.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=\ngoogle.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=\ngoogle.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=\ngoogle.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=\ngoogle.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=\ngoogle.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=\ngoogle.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190716160619-c506a9f90610/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=\ngoogle.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=\ngoogle.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=\ngoogle.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=\ngoogle.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20200108215221-bd8f9a0ef82f/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=\ngoogle.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=\ngoogle.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=\ngoogle.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=\ngoogle.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=\ngoogle.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=\ngoogle.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=\ngoogle.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=\ngoogle.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=\ngoogle.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=\ngoogle.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=\ngoogle.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=\ngoogle.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=\ngoogle.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=\ngoogle.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=\ngoogle.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=\ngoogle.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=\ngopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=\ngopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=\ngopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=\ngopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c=\ngopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns=\ngopkg.in/src-d/go-cli.v0 v0.0.0-20181105080154-d492247bbc0d/go.mod h1:z+K8VcOYVYcSwSjGebuDL6176A1XskgbtNl64NSg+n8=\ngopkg.in/src-d/go-log.v1 v1.0.1/go.mod h1:GN34hKP0g305ysm2/hctJ0Y8nWP3zxXXJ8GFabTyABE=\ngopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=\ngopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=\ngopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0=\ngopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=\ngopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=\ngopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=\ngopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=\nhonnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=\nhonnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las=\nhonnef.co/go/tools v0.1.4 h1:SadWOkti5uVN1FAMgxn165+Mw00fuQKyk4Gyn/inxNQ=\nhonnef.co/go/tools v0.1.4/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las=\nrsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=\nrsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=\n"
  },
  {
    "path": "packages/fetchai/connections/p2p_libp2p/libp2p_node/libp2p_node.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2019 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\n\npackage main\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"os/signal\"\n\t\"syscall\"\n\t\"time\"\n\n\t\"github.com/rs/zerolog\"\n\n\taea \"libp2p_node/aea\"\n\t\"libp2p_node/dht/dhtclient\"\n\t\"libp2p_node/dht/dhtnode\"\n\t\"libp2p_node/dht/dhtpeer\"\n\t\"libp2p_node/utils\"\n)\n\nconst (\n\tlibp2pNodePanicError      = \"LIBP2P_NODE_PANIC_ERROR\"\n\tlibp2pMultiaddrsListStart = \"MULTIADDRS_LIST_START\"\n\tlibp2pMultiaddrsListEnd   = \"MULTIADDRS_LIST_END\"\n)\n\nvar logger zerolog.Logger = utils.NewDefaultLogger()\n\n// panics if err is not nil\nfunc check(err error) {\n\tif err != nil {\n\t\tfmt.Println(libp2pNodePanicError, \":\", err.Error())\n\t\tpanic(err)\n\t}\n}\n\nfunc main() {\n\n\tvar err error\n\n\t// Initialize connection to aea\n\tagent := aea.AeaApi{}\n\tcheck(agent.Init())\n\tlogger.Info().Msg(\"successfully initialized API to AEA!\")\n\n\t// Get node configuration\n\n\t// aea agent address\n\taeaAddr := agent.AeaAddress()\n\n\t// node address (ip and port)\n\tnodeHost, nodePort := agent.Address()\n\n\t// node public address, if set\n\tnodeHostPublic, nodePortPublic := agent.PublicAddress()\n\n\t// node delegate service address, if set\n\t_, nodePortDelegate := agent.DelegateAddress()\n\n\t// node monitoring service address, if set\n\t_, nodePortMonitoring := agent.MonitoringAddress()\n\n\t// node private key\n\tkey := agent.PrivateKey()\n\n\t// entry peers\n\tentryPeers := agent.EntryPeers()\n\n\t// agent proof of representation\n\trecord := agent.AgentRecord()\n\n\t// add artificial delay for agent registration\n\tregistrationDelay := agent.RegistrationDelayInSeconds()\n\n\t// persist agent records to file\n\tstoragePath := agent.RecordStoragePath()\n\t// libp2p node\n\tvar node dhtnode.DHTNode\n\n\t// Run as a peer or just as a client\n\tif nodePortPublic == 0 {\n\t\t// if no external address is provided, run as a client\n\t\topts := []dhtclient.Option{\n\t\t\tdhtclient.IdentityFromFetchAIKey(key),\n\t\t\tdhtclient.BootstrapFrom(entryPeers),\n\t\t}\n\t\tif record != nil {\n\t\t\topts = append(opts, dhtclient.RegisterAgentAddress(record, agent.Connected))\n\t\t}\n\t\tnode, err = dhtclient.New(opts...)\n\t} else {\n\t\topts := []dhtpeer.Option{\n\t\t\tdhtpeer.LocalURI(nodeHost, nodePort),\n\t\t\tdhtpeer.PublicURI(nodeHostPublic, nodePortPublic),\n\t\t\tdhtpeer.IdentityFromFetchAIKey(key),\n\t\t\tdhtpeer.EnableRelayService(),\n\t\t\tdhtpeer.EnableDelegateService(nodePortDelegate),\n\t\t\tdhtpeer.BootstrapFrom(entryPeers),\n\t\t}\n\t\tif record != nil {\n\t\t\topts = append(opts, dhtpeer.RegisterAgentAddress(record, agent.Connected))\n\t\t}\n\t\tif nodePortMonitoring != 0 {\n\t\t\topts = append(opts, dhtpeer.EnablePrometheusMonitoring(nodePortMonitoring))\n\t\t}\n\t\tif registrationDelay != 0 {\n\t\t\t//lint:ignore ST1011 don't use unit-specific suffix \"Seconds\"\n\t\t\tdurationSeconds := time.Duration(registrationDelay)\n\t\t\topts = append(opts, dhtpeer.WithRegistrationDelay(durationSeconds*1000000*time.Microsecond))\n\t\t}\n\t\tif storagePath != \"\" {\n\t\t\topts = append(opts, dhtpeer.StoreRecordsTo(storagePath))\n\t\t}\n\n\t\tif len(agent.MailboxUri()) > 0 {\n\t\t\topts = append(opts, dhtpeer.EnableMailboxService(agent.MailboxUri()))\n\t\t}\n\t\tnode, err = dhtpeer.New(opts...)\n\t}\n\n\tif err != nil {\n\t\tcheck(err)\n\t}\n\tdefer node.Close()\n\tlogger.Info().Msgf(\"Peer ID: %s\", node.PeerID())\n\t// Connect to the agent\n\tfmt.Println(libp2pMultiaddrsListStart) // keyword\n\tfmt.Println(node.MultiAddr())\n\tfmt.Println(libp2pMultiaddrsListEnd) // keyword\n\n\tcheck(agent.Connect())\n\tif aeaAddr != \"\" {\n\t\tlogger.Info().Msg(\"successfully connected to AEA!\")\n\t}\n\n\t// Receive envelopes from agent and forward to peer\n\tgo func() {\n\t\tfor envel := range agent.Queue() {\n\t\t\tenvelope := envel\n\t\t\tlogger.Info().Msgf(\"received envelope from agent: %s\", envelope)\n\t\t\terr := node.RouteEnvelope(envelope)\n\t\t\tif err != nil {\n\t\t\t\tlogger.Error().Msgf(\"Route envelope error: %s\", err.Error())\n\t\t\t}\n\t\t}\n\t}()\n\n\t// Deliver envelopes received fro DHT to agent\n\tnode.ProcessEnvelope(func(envel *aea.Envelope) error {\n\t\treturn agent.Put(envel)\n\t})\n\n\t// Wait until Ctrl+C or a termination call is done.\n\tc := make(chan os.Signal, 1)\n\tsignal.Notify(c, os.Interrupt)\n\n\t// SIGTERM for k8s graceful stop support\n\tsignal.Notify(c, syscall.SIGTERM)\n\n\t//wait for termination\n\t<-c\n\n\tlogger.Info().Msg(\"node stopped\")\n}\n"
  },
  {
    "path": "packages/fetchai/connections/p2p_libp2p/libp2p_node/link",
    "content": "#!/usr/bin/python2\nimport argparse\nimport os\nimport subprocess\nimport sys\n\n\n# renamed 'link' file\noriginal_link_file = 'link_orig'\n\n# link first\noutput=None\ncode=0\ntry:\n    output = subprocess.check_output([os.path.dirname(__file__) + '/' + original_link_file] + sys.argv[1:], cwd=os.getcwd())\nexcept subprocess.CalledProcessError as e:\n    output = e.output\n    code = e.returncode\n\nif output:\n    print output.replace(original_link_file, 'link')\n\n# change max_prot value to 0x7\nparser = argparse.ArgumentParser()\nparser.add_argument('-o')\nargs, _ = parser.parse_known_args()\n\nif args.o:\n    binary_target = args.o\n    # only for testing\n    if binary_target.endswith('.test') or binary_target.endswith('_test_go'):\n        with open(os.devnull, 'wb') as DEVNULL:\n            try:\n                subprocess.check_call([\"printf '\\x07' | dd of=%s bs=1 seek=160 count=1 conv=notrunc\" % binary_target], shell=True, stdout=DEVNULL, stderr=DEVNULL)\n            except subprocess.CalledProcessError as e:\n                pass\n\nsys.exit(code)\n\n"
  },
  {
    "path": "packages/fetchai/connections/p2p_libp2p/libp2p_node/mocks/mock_host.go",
    "content": "// Code generated by MockGen. DO NOT EDIT.\n// Source: github.com/libp2p/go-libp2p-core/host (interfaces: Host)\n\n// Package mock_host is a generated GoMock package.\npackage mocks\n\nimport (\n\tcontext \"context\"\n\treflect \"reflect\"\n\n\tgomock \"github.com/golang/mock/gomock\"\n\tconnmgr \"github.com/libp2p/go-libp2p-core/connmgr\"\n\tevent \"github.com/libp2p/go-libp2p-core/event\"\n\tnetwork \"github.com/libp2p/go-libp2p-core/network\"\n\tpeer \"github.com/libp2p/go-libp2p-core/peer\"\n\tpeerstore \"github.com/libp2p/go-libp2p-core/peerstore\"\n\tprotocol \"github.com/libp2p/go-libp2p-core/protocol\"\n\tmultiaddr \"github.com/multiformats/go-multiaddr\"\n)\n\n// MockHost is a mock of Host interface.\ntype MockHost struct {\n\tctrl     *gomock.Controller\n\trecorder *MockHostMockRecorder\n}\n\n// MockHostMockRecorder is the mock recorder for MockHost.\ntype MockHostMockRecorder struct {\n\tmock *MockHost\n}\n\n// NewMockHost creates a new mock instance.\nfunc NewMockHost(ctrl *gomock.Controller) *MockHost {\n\tmock := &MockHost{ctrl: ctrl}\n\tmock.recorder = &MockHostMockRecorder{mock}\n\treturn mock\n}\n\n// EXPECT returns an object that allows the caller to indicate expected use.\nfunc (m *MockHost) EXPECT() *MockHostMockRecorder {\n\treturn m.recorder\n}\n\n// Addrs mocks base method.\nfunc (m *MockHost) Addrs() []multiaddr.Multiaddr {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"Addrs\")\n\tret0, _ := ret[0].([]multiaddr.Multiaddr)\n\treturn ret0\n}\n\n// Addrs indicates an expected call of Addrs.\nfunc (mr *MockHostMockRecorder) Addrs() *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"Addrs\", reflect.TypeOf((*MockHost)(nil).Addrs))\n}\n\n// Close mocks base method.\nfunc (m *MockHost) Close() error {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"Close\")\n\tret0, _ := ret[0].(error)\n\treturn ret0\n}\n\n// Close indicates an expected call of Close.\nfunc (mr *MockHostMockRecorder) Close() *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"Close\", reflect.TypeOf((*MockHost)(nil).Close))\n}\n\n// ConnManager mocks base method.\nfunc (m *MockHost) ConnManager() connmgr.ConnManager {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"ConnManager\")\n\tret0, _ := ret[0].(connmgr.ConnManager)\n\treturn ret0\n}\n\n// ConnManager indicates an expected call of ConnManager.\nfunc (mr *MockHostMockRecorder) ConnManager() *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"ConnManager\", reflect.TypeOf((*MockHost)(nil).ConnManager))\n}\n\n// Connect mocks base method.\nfunc (m *MockHost) Connect(arg0 context.Context, arg1 peer.AddrInfo) error {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"Connect\", arg0, arg1)\n\tret0, _ := ret[0].(error)\n\treturn ret0\n}\n\n// Connect indicates an expected call of Connect.\nfunc (mr *MockHostMockRecorder) Connect(arg0, arg1 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"Connect\", reflect.TypeOf((*MockHost)(nil).Connect), arg0, arg1)\n}\n\n// EventBus mocks base method.\nfunc (m *MockHost) EventBus() event.Bus {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"EventBus\")\n\tret0, _ := ret[0].(event.Bus)\n\treturn ret0\n}\n\n// EventBus indicates an expected call of EventBus.\nfunc (mr *MockHostMockRecorder) EventBus() *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"EventBus\", reflect.TypeOf((*MockHost)(nil).EventBus))\n}\n\n// ID mocks base method.\nfunc (m *MockHost) ID() peer.ID {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"ID\")\n\tret0, _ := ret[0].(peer.ID)\n\treturn ret0\n}\n\n// ID indicates an expected call of ID.\nfunc (mr *MockHostMockRecorder) ID() *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"ID\", reflect.TypeOf((*MockHost)(nil).ID))\n}\n\n// Mux mocks base method.\nfunc (m *MockHost) Mux() protocol.Switch {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"Mux\")\n\tret0, _ := ret[0].(protocol.Switch)\n\treturn ret0\n}\n\n// Mux indicates an expected call of Mux.\nfunc (mr *MockHostMockRecorder) Mux() *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"Mux\", reflect.TypeOf((*MockHost)(nil).Mux))\n}\n\n// Network mocks base method.\nfunc (m *MockHost) Network() network.Network {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"Network\")\n\tret0, _ := ret[0].(network.Network)\n\treturn ret0\n}\n\n// Network indicates an expected call of Network.\nfunc (mr *MockHostMockRecorder) Network() *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"Network\", reflect.TypeOf((*MockHost)(nil).Network))\n}\n\n// NewStream mocks base method.\nfunc (m *MockHost) NewStream(arg0 context.Context, arg1 peer.ID, arg2 ...protocol.ID) (network.Stream, error) {\n\tm.ctrl.T.Helper()\n\tvarargs := []interface{}{arg0, arg1}\n\tfor _, a := range arg2 {\n\t\tvarargs = append(varargs, a)\n\t}\n\tret := m.ctrl.Call(m, \"NewStream\", varargs...)\n\tret0, _ := ret[0].(network.Stream)\n\tret1, _ := ret[1].(error)\n\treturn ret0, ret1\n}\n\n// NewStream indicates an expected call of NewStream.\nfunc (mr *MockHostMockRecorder) NewStream(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\tvarargs := append([]interface{}{arg0, arg1}, arg2...)\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"NewStream\", reflect.TypeOf((*MockHost)(nil).NewStream), varargs...)\n}\n\n// Peerstore mocks base method.\nfunc (m *MockHost) Peerstore() peerstore.Peerstore {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"Peerstore\")\n\tret0, _ := ret[0].(peerstore.Peerstore)\n\treturn ret0\n}\n\n// Peerstore indicates an expected call of Peerstore.\nfunc (mr *MockHostMockRecorder) Peerstore() *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"Peerstore\", reflect.TypeOf((*MockHost)(nil).Peerstore))\n}\n\n// RemoveStreamHandler mocks base method.\nfunc (m *MockHost) RemoveStreamHandler(arg0 protocol.ID) {\n\tm.ctrl.T.Helper()\n\tm.ctrl.Call(m, \"RemoveStreamHandler\", arg0)\n}\n\n// RemoveStreamHandler indicates an expected call of RemoveStreamHandler.\nfunc (mr *MockHostMockRecorder) RemoveStreamHandler(arg0 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"RemoveStreamHandler\", reflect.TypeOf((*MockHost)(nil).RemoveStreamHandler), arg0)\n}\n\n// SetStreamHandler mocks base method.\nfunc (m *MockHost) SetStreamHandler(arg0 protocol.ID, arg1 network.StreamHandler) {\n\tm.ctrl.T.Helper()\n\tm.ctrl.Call(m, \"SetStreamHandler\", arg0, arg1)\n}\n\n// SetStreamHandler indicates an expected call of SetStreamHandler.\nfunc (mr *MockHostMockRecorder) SetStreamHandler(arg0, arg1 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"SetStreamHandler\", reflect.TypeOf((*MockHost)(nil).SetStreamHandler), arg0, arg1)\n}\n\n// SetStreamHandlerMatch mocks base method.\nfunc (m *MockHost) SetStreamHandlerMatch(arg0 protocol.ID, arg1 func(string) bool, arg2 network.StreamHandler) {\n\tm.ctrl.T.Helper()\n\tm.ctrl.Call(m, \"SetStreamHandlerMatch\", arg0, arg1, arg2)\n}\n\n// SetStreamHandlerMatch indicates an expected call of SetStreamHandlerMatch.\nfunc (mr *MockHostMockRecorder) SetStreamHandlerMatch(arg0, arg1, arg2 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"SetStreamHandlerMatch\", reflect.TypeOf((*MockHost)(nil).SetStreamHandlerMatch), arg0, arg1, arg2)\n}\n"
  },
  {
    "path": "packages/fetchai/connections/p2p_libp2p/libp2p_node/mocks/mock_net.go",
    "content": "// Code generated by MockGen. DO NOT EDIT.\n// Source: net (interfaces: Conn)\n\n// Package mock_net is a generated GoMock package.\npackage mocks\n\nimport (\n\tnet \"net\"\n\treflect \"reflect\"\n\ttime \"time\"\n\n\tgomock \"github.com/golang/mock/gomock\"\n)\n\n// MockConn is a mock of Conn interface.\ntype MockConn struct {\n\tctrl     *gomock.Controller\n\trecorder *MockConnMockRecorder\n}\n\n// MockConnMockRecorder is the mock recorder for MockConn.\ntype MockConnMockRecorder struct {\n\tmock *MockConn\n}\n\n// NewMockConn creates a new mock instance.\nfunc NewMockConn(ctrl *gomock.Controller) *MockConn {\n\tmock := &MockConn{ctrl: ctrl}\n\tmock.recorder = &MockConnMockRecorder{mock}\n\treturn mock\n}\n\n// EXPECT returns an object that allows the caller to indicate expected use.\nfunc (m *MockConn) EXPECT() *MockConnMockRecorder {\n\treturn m.recorder\n}\n\n// Close mocks base method.\nfunc (m *MockConn) Close() error {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"Close\")\n\tret0, _ := ret[0].(error)\n\treturn ret0\n}\n\n// Close indicates an expected call of Close.\nfunc (mr *MockConnMockRecorder) Close() *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"Close\", reflect.TypeOf((*MockConn)(nil).Close))\n}\n\n// LocalAddr mocks base method.\nfunc (m *MockConn) LocalAddr() net.Addr {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"LocalAddr\")\n\tret0, _ := ret[0].(net.Addr)\n\treturn ret0\n}\n\n// LocalAddr indicates an expected call of LocalAddr.\nfunc (mr *MockConnMockRecorder) LocalAddr() *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"LocalAddr\", reflect.TypeOf((*MockConn)(nil).LocalAddr))\n}\n\n// Read mocks base method.\nfunc (m *MockConn) Read(arg0 []byte) (int, error) {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"Read\", arg0)\n\tret0, _ := ret[0].(int)\n\tret1, _ := ret[1].(error)\n\treturn ret0, ret1\n}\n\n// Read indicates an expected call of Read.\nfunc (mr *MockConnMockRecorder) Read(arg0 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"Read\", reflect.TypeOf((*MockConn)(nil).Read), arg0)\n}\n\n// RemoteAddr mocks base method.\nfunc (m *MockConn) RemoteAddr() net.Addr {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"RemoteAddr\")\n\tret0, _ := ret[0].(net.Addr)\n\treturn ret0\n}\n\n// RemoteAddr indicates an expected call of RemoteAddr.\nfunc (mr *MockConnMockRecorder) RemoteAddr() *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"RemoteAddr\", reflect.TypeOf((*MockConn)(nil).RemoteAddr))\n}\n\n// SetDeadline mocks base method.\nfunc (m *MockConn) SetDeadline(arg0 time.Time) error {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"SetDeadline\", arg0)\n\tret0, _ := ret[0].(error)\n\treturn ret0\n}\n\n// SetDeadline indicates an expected call of SetDeadline.\nfunc (mr *MockConnMockRecorder) SetDeadline(arg0 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"SetDeadline\", reflect.TypeOf((*MockConn)(nil).SetDeadline), arg0)\n}\n\n// SetReadDeadline mocks base method.\nfunc (m *MockConn) SetReadDeadline(arg0 time.Time) error {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"SetReadDeadline\", arg0)\n\tret0, _ := ret[0].(error)\n\treturn ret0\n}\n\n// SetReadDeadline indicates an expected call of SetReadDeadline.\nfunc (mr *MockConnMockRecorder) SetReadDeadline(arg0 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"SetReadDeadline\", reflect.TypeOf((*MockConn)(nil).SetReadDeadline), arg0)\n}\n\n// SetWriteDeadline mocks base method.\nfunc (m *MockConn) SetWriteDeadline(arg0 time.Time) error {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"SetWriteDeadline\", arg0)\n\tret0, _ := ret[0].(error)\n\treturn ret0\n}\n\n// SetWriteDeadline indicates an expected call of SetWriteDeadline.\nfunc (mr *MockConnMockRecorder) SetWriteDeadline(arg0 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"SetWriteDeadline\", reflect.TypeOf((*MockConn)(nil).SetWriteDeadline), arg0)\n}\n\n// Write mocks base method.\nfunc (m *MockConn) Write(arg0 []byte) (int, error) {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"Write\", arg0)\n\tret0, _ := ret[0].(int)\n\tret1, _ := ret[1].(error)\n\treturn ret0, ret1\n}\n\n// Write indicates an expected call of Write.\nfunc (mr *MockConnMockRecorder) Write(arg0 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"Write\", reflect.TypeOf((*MockConn)(nil).Write), arg0)\n}\n"
  },
  {
    "path": "packages/fetchai/connections/p2p_libp2p/libp2p_node/mocks/mock_network.go",
    "content": "// Code generated by MockGen. DO NOT EDIT.\n// Source: github.com/libp2p/go-libp2p-core/network (interfaces: Stream)\n\n// Package mock_network is a generated GoMock package.\npackage mocks\n\nimport (\n\treflect \"reflect\"\n\ttime \"time\"\n\n\tgomock \"github.com/golang/mock/gomock\"\n\tnetwork \"github.com/libp2p/go-libp2p-core/network\"\n\tprotocol \"github.com/libp2p/go-libp2p-core/protocol\"\n)\n\n// MockStream is a mock of Stream interface.\ntype MockStream struct {\n\tctrl     *gomock.Controller\n\trecorder *MockStreamMockRecorder\n}\n\n// MockStreamMockRecorder is the mock recorder for MockStream.\ntype MockStreamMockRecorder struct {\n\tmock *MockStream\n}\n\n// NewMockStream creates a new mock instance.\nfunc NewMockStream(ctrl *gomock.Controller) *MockStream {\n\tmock := &MockStream{ctrl: ctrl}\n\tmock.recorder = &MockStreamMockRecorder{mock}\n\treturn mock\n}\n\n// EXPECT returns an object that allows the caller to indicate expected use.\nfunc (m *MockStream) EXPECT() *MockStreamMockRecorder {\n\treturn m.recorder\n}\n\n// Close mocks base method.\nfunc (m *MockStream) Close() error {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"Close\")\n\tret0, _ := ret[0].(error)\n\treturn ret0\n}\n\n// Close indicates an expected call of Close.\nfunc (mr *MockStreamMockRecorder) Close() *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"Close\", reflect.TypeOf((*MockStream)(nil).Close))\n}\n\n// Conn mocks base method.\nfunc (m *MockStream) Conn() network.Conn {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"Conn\")\n\tret0, _ := ret[0].(network.Conn)\n\treturn ret0\n}\n\n// Conn indicates an expected call of Conn.\nfunc (mr *MockStreamMockRecorder) Conn() *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"Conn\", reflect.TypeOf((*MockStream)(nil).Conn))\n}\n\n// Protocol mocks base method.\nfunc (m *MockStream) Protocol() protocol.ID {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"Protocol\")\n\tret0, _ := ret[0].(protocol.ID)\n\treturn ret0\n}\n\n// Protocol indicates an expected call of Protocol.\nfunc (mr *MockStreamMockRecorder) Protocol() *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"Protocol\", reflect.TypeOf((*MockStream)(nil).Protocol))\n}\n\n// Read mocks base method.\nfunc (m *MockStream) Read(arg0 []byte) (int, error) {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"Read\", arg0)\n\tret0, _ := ret[0].(int)\n\tret1, _ := ret[1].(error)\n\treturn ret0, ret1\n}\n\n// Read indicates an expected call of Read.\nfunc (mr *MockStreamMockRecorder) Read(arg0 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"Read\", reflect.TypeOf((*MockStream)(nil).Read), arg0)\n}\n\n// Reset mocks base method.\nfunc (m *MockStream) Reset() error {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"Reset\")\n\tret0, _ := ret[0].(error)\n\treturn ret0\n}\n\n// Reset indicates an expected call of Reset.\nfunc (mr *MockStreamMockRecorder) Reset() *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"Reset\", reflect.TypeOf((*MockStream)(nil).Reset))\n}\n\n// SetDeadline mocks base method.\nfunc (m *MockStream) SetDeadline(arg0 time.Time) error {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"SetDeadline\", arg0)\n\tret0, _ := ret[0].(error)\n\treturn ret0\n}\n\n// SetDeadline indicates an expected call of SetDeadline.\nfunc (mr *MockStreamMockRecorder) SetDeadline(arg0 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"SetDeadline\", reflect.TypeOf((*MockStream)(nil).SetDeadline), arg0)\n}\n\n// SetProtocol mocks base method.\nfunc (m *MockStream) SetProtocol(arg0 protocol.ID) {\n\tm.ctrl.T.Helper()\n\tm.ctrl.Call(m, \"SetProtocol\", arg0)\n}\n\n// SetProtocol indicates an expected call of SetProtocol.\nfunc (mr *MockStreamMockRecorder) SetProtocol(arg0 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"SetProtocol\", reflect.TypeOf((*MockStream)(nil).SetProtocol), arg0)\n}\n\n// SetReadDeadline mocks base method.\nfunc (m *MockStream) SetReadDeadline(arg0 time.Time) error {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"SetReadDeadline\", arg0)\n\tret0, _ := ret[0].(error)\n\treturn ret0\n}\n\n// SetReadDeadline indicates an expected call of SetReadDeadline.\nfunc (mr *MockStreamMockRecorder) SetReadDeadline(arg0 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"SetReadDeadline\", reflect.TypeOf((*MockStream)(nil).SetReadDeadline), arg0)\n}\n\n// SetWriteDeadline mocks base method.\nfunc (m *MockStream) SetWriteDeadline(arg0 time.Time) error {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"SetWriteDeadline\", arg0)\n\tret0, _ := ret[0].(error)\n\treturn ret0\n}\n\n// SetWriteDeadline indicates an expected call of SetWriteDeadline.\nfunc (mr *MockStreamMockRecorder) SetWriteDeadline(arg0 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"SetWriteDeadline\", reflect.TypeOf((*MockStream)(nil).SetWriteDeadline), arg0)\n}\n\n// Stat mocks base method.\nfunc (m *MockStream) Stat() network.Stat {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"Stat\")\n\tret0, _ := ret[0].(network.Stat)\n\treturn ret0\n}\n\n// Stat indicates an expected call of Stat.\nfunc (mr *MockStreamMockRecorder) Stat() *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"Stat\", reflect.TypeOf((*MockStream)(nil).Stat))\n}\n\n// Write mocks base method.\nfunc (m *MockStream) Write(arg0 []byte) (int, error) {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"Write\", arg0)\n\tret0, _ := ret[0].(int)\n\tret1, _ := ret[1].(error)\n\treturn ret0, ret1\n}\n\n// Write indicates an expected call of Write.\nfunc (mr *MockStreamMockRecorder) Write(arg0 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"Write\", reflect.TypeOf((*MockStream)(nil).Write), arg0)\n}\n"
  },
  {
    "path": "packages/fetchai/connections/p2p_libp2p/libp2p_node/mocks/mock_peerstore.go",
    "content": "// Code generated by MockGen. DO NOT EDIT.\n// Source: github.com/libp2p/go-libp2p-core/peerstore (interfaces: Peerstore)\n\n// Package mock_peerstore is a generated GoMock package.\npackage mocks\n\nimport (\n\tcontext \"context\"\n\treflect \"reflect\"\n\ttime \"time\"\n\n\tgomock \"github.com/golang/mock/gomock\"\n\tcrypto \"github.com/libp2p/go-libp2p-core/crypto\"\n\tpeer \"github.com/libp2p/go-libp2p-core/peer\"\n\tmultiaddr \"github.com/multiformats/go-multiaddr\"\n)\n\n// MockPeerstore is a mock of Peerstore interface.\ntype MockPeerstore struct {\n\tctrl     *gomock.Controller\n\trecorder *MockPeerstoreMockRecorder\n}\n\n// MockPeerstoreMockRecorder is the mock recorder for MockPeerstore.\ntype MockPeerstoreMockRecorder struct {\n\tmock *MockPeerstore\n}\n\n// NewMockPeerstore creates a new mock instance.\nfunc NewMockPeerstore(ctrl *gomock.Controller) *MockPeerstore {\n\tmock := &MockPeerstore{ctrl: ctrl}\n\tmock.recorder = &MockPeerstoreMockRecorder{mock}\n\treturn mock\n}\n\n// EXPECT returns an object that allows the caller to indicate expected use.\nfunc (m *MockPeerstore) EXPECT() *MockPeerstoreMockRecorder {\n\treturn m.recorder\n}\n\n// AddAddr mocks base method.\nfunc (m *MockPeerstore) AddAddr(arg0 peer.ID, arg1 multiaddr.Multiaddr, arg2 time.Duration) {\n\tm.ctrl.T.Helper()\n\tm.ctrl.Call(m, \"AddAddr\", arg0, arg1, arg2)\n}\n\n// AddAddr indicates an expected call of AddAddr.\nfunc (mr *MockPeerstoreMockRecorder) AddAddr(arg0, arg1, arg2 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"AddAddr\", reflect.TypeOf((*MockPeerstore)(nil).AddAddr), arg0, arg1, arg2)\n}\n\n// AddAddrs mocks base method.\nfunc (m *MockPeerstore) AddAddrs(arg0 peer.ID, arg1 []multiaddr.Multiaddr, arg2 time.Duration) {\n\tm.ctrl.T.Helper()\n\tm.ctrl.Call(m, \"AddAddrs\", arg0, arg1, arg2)\n}\n\n// AddAddrs indicates an expected call of AddAddrs.\nfunc (mr *MockPeerstoreMockRecorder) AddAddrs(arg0, arg1, arg2 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"AddAddrs\", reflect.TypeOf((*MockPeerstore)(nil).AddAddrs), arg0, arg1, arg2)\n}\n\n// AddPrivKey mocks base method.\nfunc (m *MockPeerstore) AddPrivKey(arg0 peer.ID, arg1 crypto.PrivKey) error {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"AddPrivKey\", arg0, arg1)\n\tret0, _ := ret[0].(error)\n\treturn ret0\n}\n\n// AddPrivKey indicates an expected call of AddPrivKey.\nfunc (mr *MockPeerstoreMockRecorder) AddPrivKey(arg0, arg1 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"AddPrivKey\", reflect.TypeOf((*MockPeerstore)(nil).AddPrivKey), arg0, arg1)\n}\n\n// AddProtocols mocks base method.\nfunc (m *MockPeerstore) AddProtocols(arg0 peer.ID, arg1 ...string) error {\n\tm.ctrl.T.Helper()\n\tvarargs := []interface{}{arg0}\n\tfor _, a := range arg1 {\n\t\tvarargs = append(varargs, a)\n\t}\n\tret := m.ctrl.Call(m, \"AddProtocols\", varargs...)\n\tret0, _ := ret[0].(error)\n\treturn ret0\n}\n\n// AddProtocols indicates an expected call of AddProtocols.\nfunc (mr *MockPeerstoreMockRecorder) AddProtocols(arg0 interface{}, arg1 ...interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\tvarargs := append([]interface{}{arg0}, arg1...)\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"AddProtocols\", reflect.TypeOf((*MockPeerstore)(nil).AddProtocols), varargs...)\n}\n\n// AddPubKey mocks base method.\nfunc (m *MockPeerstore) AddPubKey(arg0 peer.ID, arg1 crypto.PubKey) error {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"AddPubKey\", arg0, arg1)\n\tret0, _ := ret[0].(error)\n\treturn ret0\n}\n\n// AddPubKey indicates an expected call of AddPubKey.\nfunc (mr *MockPeerstoreMockRecorder) AddPubKey(arg0, arg1 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"AddPubKey\", reflect.TypeOf((*MockPeerstore)(nil).AddPubKey), arg0, arg1)\n}\n\n// AddrStream mocks base method.\nfunc (m *MockPeerstore) AddrStream(arg0 context.Context, arg1 peer.ID) <-chan multiaddr.Multiaddr {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"AddrStream\", arg0, arg1)\n\tret0, _ := ret[0].(<-chan multiaddr.Multiaddr)\n\treturn ret0\n}\n\n// AddrStream indicates an expected call of AddrStream.\nfunc (mr *MockPeerstoreMockRecorder) AddrStream(arg0, arg1 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"AddrStream\", reflect.TypeOf((*MockPeerstore)(nil).AddrStream), arg0, arg1)\n}\n\n// Addrs mocks base method.\nfunc (m *MockPeerstore) Addrs(arg0 peer.ID) []multiaddr.Multiaddr {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"Addrs\", arg0)\n\tret0, _ := ret[0].([]multiaddr.Multiaddr)\n\treturn ret0\n}\n\n// Addrs indicates an expected call of Addrs.\nfunc (mr *MockPeerstoreMockRecorder) Addrs(arg0 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"Addrs\", reflect.TypeOf((*MockPeerstore)(nil).Addrs), arg0)\n}\n\n// ClearAddrs mocks base method.\nfunc (m *MockPeerstore) ClearAddrs(arg0 peer.ID) {\n\tm.ctrl.T.Helper()\n\tm.ctrl.Call(m, \"ClearAddrs\", arg0)\n}\n\n// ClearAddrs indicates an expected call of ClearAddrs.\nfunc (mr *MockPeerstoreMockRecorder) ClearAddrs(arg0 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"ClearAddrs\", reflect.TypeOf((*MockPeerstore)(nil).ClearAddrs), arg0)\n}\n\n// Close mocks base method.\nfunc (m *MockPeerstore) Close() error {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"Close\")\n\tret0, _ := ret[0].(error)\n\treturn ret0\n}\n\n// Close indicates an expected call of Close.\nfunc (mr *MockPeerstoreMockRecorder) Close() *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"Close\", reflect.TypeOf((*MockPeerstore)(nil).Close))\n}\n\n// Get mocks base method.\nfunc (m *MockPeerstore) Get(arg0 peer.ID, arg1 string) (interface{}, error) {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"Get\", arg0, arg1)\n\tret0, _ := ret[0].(interface{})\n\tret1, _ := ret[1].(error)\n\treturn ret0, ret1\n}\n\n// Get indicates an expected call of Get.\nfunc (mr *MockPeerstoreMockRecorder) Get(arg0, arg1 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"Get\", reflect.TypeOf((*MockPeerstore)(nil).Get), arg0, arg1)\n}\n\n// GetProtocols mocks base method.\nfunc (m *MockPeerstore) GetProtocols(arg0 peer.ID) ([]string, error) {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"GetProtocols\", arg0)\n\tret0, _ := ret[0].([]string)\n\tret1, _ := ret[1].(error)\n\treturn ret0, ret1\n}\n\n// GetProtocols indicates an expected call of GetProtocols.\nfunc (mr *MockPeerstoreMockRecorder) GetProtocols(arg0 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"GetProtocols\", reflect.TypeOf((*MockPeerstore)(nil).GetProtocols), arg0)\n}\n\n// LatencyEWMA mocks base method.\nfunc (m *MockPeerstore) LatencyEWMA(arg0 peer.ID) time.Duration {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"LatencyEWMA\", arg0)\n\tret0, _ := ret[0].(time.Duration)\n\treturn ret0\n}\n\n// LatencyEWMA indicates an expected call of LatencyEWMA.\nfunc (mr *MockPeerstoreMockRecorder) LatencyEWMA(arg0 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"LatencyEWMA\", reflect.TypeOf((*MockPeerstore)(nil).LatencyEWMA), arg0)\n}\n\n// PeerInfo mocks base method.\nfunc (m *MockPeerstore) PeerInfo(arg0 peer.ID) peer.AddrInfo {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"PeerInfo\", arg0)\n\tret0, _ := ret[0].(peer.AddrInfo)\n\treturn ret0\n}\n\n// PeerInfo indicates an expected call of PeerInfo.\nfunc (mr *MockPeerstoreMockRecorder) PeerInfo(arg0 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"PeerInfo\", reflect.TypeOf((*MockPeerstore)(nil).PeerInfo), arg0)\n}\n\n// Peers mocks base method.\nfunc (m *MockPeerstore) Peers() peer.IDSlice {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"Peers\")\n\tret0, _ := ret[0].(peer.IDSlice)\n\treturn ret0\n}\n\n// Peers indicates an expected call of Peers.\nfunc (mr *MockPeerstoreMockRecorder) Peers() *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"Peers\", reflect.TypeOf((*MockPeerstore)(nil).Peers))\n}\n\n// PeersWithAddrs mocks base method.\nfunc (m *MockPeerstore) PeersWithAddrs() peer.IDSlice {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"PeersWithAddrs\")\n\tret0, _ := ret[0].(peer.IDSlice)\n\treturn ret0\n}\n\n// PeersWithAddrs indicates an expected call of PeersWithAddrs.\nfunc (mr *MockPeerstoreMockRecorder) PeersWithAddrs() *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"PeersWithAddrs\", reflect.TypeOf((*MockPeerstore)(nil).PeersWithAddrs))\n}\n\n// PeersWithKeys mocks base method.\nfunc (m *MockPeerstore) PeersWithKeys() peer.IDSlice {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"PeersWithKeys\")\n\tret0, _ := ret[0].(peer.IDSlice)\n\treturn ret0\n}\n\n// PeersWithKeys indicates an expected call of PeersWithKeys.\nfunc (mr *MockPeerstoreMockRecorder) PeersWithKeys() *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"PeersWithKeys\", reflect.TypeOf((*MockPeerstore)(nil).PeersWithKeys))\n}\n\n// PrivKey mocks base method.\nfunc (m *MockPeerstore) PrivKey(arg0 peer.ID) crypto.PrivKey {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"PrivKey\", arg0)\n\tret0, _ := ret[0].(crypto.PrivKey)\n\treturn ret0\n}\n\n// PrivKey indicates an expected call of PrivKey.\nfunc (mr *MockPeerstoreMockRecorder) PrivKey(arg0 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"PrivKey\", reflect.TypeOf((*MockPeerstore)(nil).PrivKey), arg0)\n}\n\n// PubKey mocks base method.\nfunc (m *MockPeerstore) PubKey(arg0 peer.ID) crypto.PubKey {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"PubKey\", arg0)\n\tret0, _ := ret[0].(crypto.PubKey)\n\treturn ret0\n}\n\n// PubKey indicates an expected call of PubKey.\nfunc (mr *MockPeerstoreMockRecorder) PubKey(arg0 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"PubKey\", reflect.TypeOf((*MockPeerstore)(nil).PubKey), arg0)\n}\n\n// Put mocks base method.\nfunc (m *MockPeerstore) Put(arg0 peer.ID, arg1 string, arg2 interface{}) error {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"Put\", arg0, arg1, arg2)\n\tret0, _ := ret[0].(error)\n\treturn ret0\n}\n\n// Put indicates an expected call of Put.\nfunc (mr *MockPeerstoreMockRecorder) Put(arg0, arg1, arg2 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"Put\", reflect.TypeOf((*MockPeerstore)(nil).Put), arg0, arg1, arg2)\n}\n\n// RecordLatency mocks base method.\nfunc (m *MockPeerstore) RecordLatency(arg0 peer.ID, arg1 time.Duration) {\n\tm.ctrl.T.Helper()\n\tm.ctrl.Call(m, \"RecordLatency\", arg0, arg1)\n}\n\n// RecordLatency indicates an expected call of RecordLatency.\nfunc (mr *MockPeerstoreMockRecorder) RecordLatency(arg0, arg1 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"RecordLatency\", reflect.TypeOf((*MockPeerstore)(nil).RecordLatency), arg0, arg1)\n}\n\n// RemoveProtocols mocks base method.\nfunc (m *MockPeerstore) RemoveProtocols(arg0 peer.ID, arg1 ...string) error {\n\tm.ctrl.T.Helper()\n\tvarargs := []interface{}{arg0}\n\tfor _, a := range arg1 {\n\t\tvarargs = append(varargs, a)\n\t}\n\tret := m.ctrl.Call(m, \"RemoveProtocols\", varargs...)\n\tret0, _ := ret[0].(error)\n\treturn ret0\n}\n\n// RemoveProtocols indicates an expected call of RemoveProtocols.\nfunc (mr *MockPeerstoreMockRecorder) RemoveProtocols(arg0 interface{}, arg1 ...interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\tvarargs := append([]interface{}{arg0}, arg1...)\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"RemoveProtocols\", reflect.TypeOf((*MockPeerstore)(nil).RemoveProtocols), varargs...)\n}\n\n// SetAddr mocks base method.\nfunc (m *MockPeerstore) SetAddr(arg0 peer.ID, arg1 multiaddr.Multiaddr, arg2 time.Duration) {\n\tm.ctrl.T.Helper()\n\tm.ctrl.Call(m, \"SetAddr\", arg0, arg1, arg2)\n}\n\n// SetAddr indicates an expected call of SetAddr.\nfunc (mr *MockPeerstoreMockRecorder) SetAddr(arg0, arg1, arg2 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"SetAddr\", reflect.TypeOf((*MockPeerstore)(nil).SetAddr), arg0, arg1, arg2)\n}\n\n// SetAddrs mocks base method.\nfunc (m *MockPeerstore) SetAddrs(arg0 peer.ID, arg1 []multiaddr.Multiaddr, arg2 time.Duration) {\n\tm.ctrl.T.Helper()\n\tm.ctrl.Call(m, \"SetAddrs\", arg0, arg1, arg2)\n}\n\n// SetAddrs indicates an expected call of SetAddrs.\nfunc (mr *MockPeerstoreMockRecorder) SetAddrs(arg0, arg1, arg2 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"SetAddrs\", reflect.TypeOf((*MockPeerstore)(nil).SetAddrs), arg0, arg1, arg2)\n}\n\n// SetProtocols mocks base method.\nfunc (m *MockPeerstore) SetProtocols(arg0 peer.ID, arg1 ...string) error {\n\tm.ctrl.T.Helper()\n\tvarargs := []interface{}{arg0}\n\tfor _, a := range arg1 {\n\t\tvarargs = append(varargs, a)\n\t}\n\tret := m.ctrl.Call(m, \"SetProtocols\", varargs...)\n\tret0, _ := ret[0].(error)\n\treturn ret0\n}\n\n// SetProtocols indicates an expected call of SetProtocols.\nfunc (mr *MockPeerstoreMockRecorder) SetProtocols(arg0 interface{}, arg1 ...interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\tvarargs := append([]interface{}{arg0}, arg1...)\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"SetProtocols\", reflect.TypeOf((*MockPeerstore)(nil).SetProtocols), varargs...)\n}\n\n// SupportsProtocols mocks base method.\nfunc (m *MockPeerstore) SupportsProtocols(arg0 peer.ID, arg1 ...string) ([]string, error) {\n\tm.ctrl.T.Helper()\n\tvarargs := []interface{}{arg0}\n\tfor _, a := range arg1 {\n\t\tvarargs = append(varargs, a)\n\t}\n\tret := m.ctrl.Call(m, \"SupportsProtocols\", varargs...)\n\tret0, _ := ret[0].([]string)\n\tret1, _ := ret[1].(error)\n\treturn ret0, ret1\n}\n\n// SupportsProtocols indicates an expected call of SupportsProtocols.\nfunc (mr *MockPeerstoreMockRecorder) SupportsProtocols(arg0 interface{}, arg1 ...interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\tvarargs := append([]interface{}{arg0}, arg1...)\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"SupportsProtocols\", reflect.TypeOf((*MockPeerstore)(nil).SupportsProtocols), varargs...)\n}\n\n// UpdateAddrs mocks base method.\nfunc (m *MockPeerstore) UpdateAddrs(arg0 peer.ID, arg1, arg2 time.Duration) {\n\tm.ctrl.T.Helper()\n\tm.ctrl.Call(m, \"UpdateAddrs\", arg0, arg1, arg2)\n}\n\n// UpdateAddrs indicates an expected call of UpdateAddrs.\nfunc (mr *MockPeerstoreMockRecorder) UpdateAddrs(arg0, arg1, arg2 interface{}) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"UpdateAddrs\", reflect.TypeOf((*MockPeerstore)(nil).UpdateAddrs), arg0, arg1, arg2)\n}\n"
  },
  {
    "path": "packages/fetchai/connections/p2p_libp2p/libp2p_node/protocols/acn/v1_0_0/acn.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.25.0\n// \tprotoc        v3.11.4\n// source: acn.proto\n\npackage aea_aea_acn_v1_0_0\n\nimport (\n\tproto \"github.com/golang/protobuf/proto\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// This is a compile-time assertion that a sufficiently up-to-date version\n// of the legacy proto package is being used.\nconst _ = proto.ProtoPackageIsVersion4\n\ntype AcnMessage_StatusBody_StatusCodeEnum int32\n\nconst (\n\t// common (0x)\n\tAcnMessage_StatusBody_SUCCESS                   AcnMessage_StatusBody_StatusCodeEnum = 0\n\tAcnMessage_StatusBody_ERROR_UNSUPPORTED_VERSION AcnMessage_StatusBody_StatusCodeEnum = 1\n\tAcnMessage_StatusBody_ERROR_UNEXPECTED_PAYLOAD  AcnMessage_StatusBody_StatusCodeEnum = 2\n\tAcnMessage_StatusBody_ERROR_GENERIC             AcnMessage_StatusBody_StatusCodeEnum = 3\n\tAcnMessage_StatusBody_ERROR_DECODE              AcnMessage_StatusBody_StatusCodeEnum = 4\n\t// register (1x)\n\tAcnMessage_StatusBody_ERROR_WRONG_AGENT_ADDRESS AcnMessage_StatusBody_StatusCodeEnum = 10\n\tAcnMessage_StatusBody_ERROR_WRONG_PUBLIC_KEY    AcnMessage_StatusBody_StatusCodeEnum = 11\n\tAcnMessage_StatusBody_ERROR_INVALID_PROOF       AcnMessage_StatusBody_StatusCodeEnum = 12\n\tAcnMessage_StatusBody_ERROR_UNSUPPORTED_LEDGER  AcnMessage_StatusBody_StatusCodeEnum = 13\n\t// lookup & delivery (2x)\n\tAcnMessage_StatusBody_ERROR_UNKNOWN_AGENT_ADDRESS AcnMessage_StatusBody_StatusCodeEnum = 20\n\tAcnMessage_StatusBody_ERROR_AGENT_NOT_READY       AcnMessage_StatusBody_StatusCodeEnum = 21\n)\n\n// Enum value maps for AcnMessage_StatusBody_StatusCodeEnum.\nvar (\n\tAcnMessage_StatusBody_StatusCodeEnum_name = map[int32]string{\n\t\t0:  \"SUCCESS\",\n\t\t1:  \"ERROR_UNSUPPORTED_VERSION\",\n\t\t2:  \"ERROR_UNEXPECTED_PAYLOAD\",\n\t\t3:  \"ERROR_GENERIC\",\n\t\t4:  \"ERROR_DECODE\",\n\t\t10: \"ERROR_WRONG_AGENT_ADDRESS\",\n\t\t11: \"ERROR_WRONG_PUBLIC_KEY\",\n\t\t12: \"ERROR_INVALID_PROOF\",\n\t\t13: \"ERROR_UNSUPPORTED_LEDGER\",\n\t\t20: \"ERROR_UNKNOWN_AGENT_ADDRESS\",\n\t\t21: \"ERROR_AGENT_NOT_READY\",\n\t}\n\tAcnMessage_StatusBody_StatusCodeEnum_value = map[string]int32{\n\t\t\"SUCCESS\":                     0,\n\t\t\"ERROR_UNSUPPORTED_VERSION\":   1,\n\t\t\"ERROR_UNEXPECTED_PAYLOAD\":    2,\n\t\t\"ERROR_GENERIC\":               3,\n\t\t\"ERROR_DECODE\":                4,\n\t\t\"ERROR_WRONG_AGENT_ADDRESS\":   10,\n\t\t\"ERROR_WRONG_PUBLIC_KEY\":      11,\n\t\t\"ERROR_INVALID_PROOF\":         12,\n\t\t\"ERROR_UNSUPPORTED_LEDGER\":    13,\n\t\t\"ERROR_UNKNOWN_AGENT_ADDRESS\": 20,\n\t\t\"ERROR_AGENT_NOT_READY\":       21,\n\t}\n)\n\nfunc (x AcnMessage_StatusBody_StatusCodeEnum) Enum() *AcnMessage_StatusBody_StatusCodeEnum {\n\tp := new(AcnMessage_StatusBody_StatusCodeEnum)\n\t*p = x\n\treturn p\n}\n\nfunc (x AcnMessage_StatusBody_StatusCodeEnum) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (AcnMessage_StatusBody_StatusCodeEnum) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_acn_proto_enumTypes[0].Descriptor()\n}\n\nfunc (AcnMessage_StatusBody_StatusCodeEnum) Type() protoreflect.EnumType {\n\treturn &file_acn_proto_enumTypes[0]\n}\n\nfunc (x AcnMessage_StatusBody_StatusCodeEnum) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use AcnMessage_StatusBody_StatusCodeEnum.Descriptor instead.\nfunc (AcnMessage_StatusBody_StatusCodeEnum) EnumDescriptor() ([]byte, []int) {\n\treturn file_acn_proto_rawDescGZIP(), []int{0, 1, 0}\n}\n\ntype AcnMessage struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// Types that are assignable to Performative:\n\t//\t*AcnMessage_AeaEnvelope\n\t//\t*AcnMessage_LookupRequest\n\t//\t*AcnMessage_LookupResponse\n\t//\t*AcnMessage_Register\n\t//\t*AcnMessage_Status\n\tPerformative isAcnMessage_Performative `protobuf_oneof:\"performative\"`\n}\n\nfunc (x *AcnMessage) Reset() {\n\t*x = AcnMessage{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_acn_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *AcnMessage) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*AcnMessage) ProtoMessage() {}\n\nfunc (x *AcnMessage) ProtoReflect() protoreflect.Message {\n\tmi := &file_acn_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use AcnMessage.ProtoReflect.Descriptor instead.\nfunc (*AcnMessage) Descriptor() ([]byte, []int) {\n\treturn file_acn_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (m *AcnMessage) GetPerformative() isAcnMessage_Performative {\n\tif m != nil {\n\t\treturn m.Performative\n\t}\n\treturn nil\n}\n\nfunc (x *AcnMessage) GetAeaEnvelope() *AcnMessage_Aea_Envelope_Performative {\n\tif x, ok := x.GetPerformative().(*AcnMessage_AeaEnvelope); ok {\n\t\treturn x.AeaEnvelope\n\t}\n\treturn nil\n}\n\nfunc (x *AcnMessage) GetLookupRequest() *AcnMessage_Lookup_Request_Performative {\n\tif x, ok := x.GetPerformative().(*AcnMessage_LookupRequest); ok {\n\t\treturn x.LookupRequest\n\t}\n\treturn nil\n}\n\nfunc (x *AcnMessage) GetLookupResponse() *AcnMessage_Lookup_Response_Performative {\n\tif x, ok := x.GetPerformative().(*AcnMessage_LookupResponse); ok {\n\t\treturn x.LookupResponse\n\t}\n\treturn nil\n}\n\nfunc (x *AcnMessage) GetRegister() *AcnMessage_Register_Performative {\n\tif x, ok := x.GetPerformative().(*AcnMessage_Register); ok {\n\t\treturn x.Register\n\t}\n\treturn nil\n}\n\nfunc (x *AcnMessage) GetStatus() *AcnMessage_Status_Performative {\n\tif x, ok := x.GetPerformative().(*AcnMessage_Status); ok {\n\t\treturn x.Status\n\t}\n\treturn nil\n}\n\ntype isAcnMessage_Performative interface {\n\tisAcnMessage_Performative()\n}\n\ntype AcnMessage_AeaEnvelope struct {\n\tAeaEnvelope *AcnMessage_Aea_Envelope_Performative `protobuf:\"bytes,5,opt,name=aea_envelope,json=aeaEnvelope,proto3,oneof\"`\n}\n\ntype AcnMessage_LookupRequest struct {\n\tLookupRequest *AcnMessage_Lookup_Request_Performative `protobuf:\"bytes,6,opt,name=lookup_request,json=lookupRequest,proto3,oneof\"`\n}\n\ntype AcnMessage_LookupResponse struct {\n\tLookupResponse *AcnMessage_Lookup_Response_Performative `protobuf:\"bytes,7,opt,name=lookup_response,json=lookupResponse,proto3,oneof\"`\n}\n\ntype AcnMessage_Register struct {\n\tRegister *AcnMessage_Register_Performative `protobuf:\"bytes,8,opt,name=register,proto3,oneof\"`\n}\n\ntype AcnMessage_Status struct {\n\tStatus *AcnMessage_Status_Performative `protobuf:\"bytes,9,opt,name=status,proto3,oneof\"`\n}\n\nfunc (*AcnMessage_AeaEnvelope) isAcnMessage_Performative() {}\n\nfunc (*AcnMessage_LookupRequest) isAcnMessage_Performative() {}\n\nfunc (*AcnMessage_LookupResponse) isAcnMessage_Performative() {}\n\nfunc (*AcnMessage_Register) isAcnMessage_Performative() {}\n\nfunc (*AcnMessage_Status) isAcnMessage_Performative() {}\n\n// Custom Types\ntype AcnMessage_AgentRecord struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tServiceId     string `protobuf:\"bytes,1,opt,name=service_id,json=serviceId,proto3\" json:\"service_id,omitempty\"`\n\tLedgerId      string `protobuf:\"bytes,2,opt,name=ledger_id,json=ledgerId,proto3\" json:\"ledger_id,omitempty\"`\n\tAddress       string `protobuf:\"bytes,3,opt,name=address,proto3\" json:\"address,omitempty\"`\n\tPublicKey     string `protobuf:\"bytes,4,opt,name=public_key,json=publicKey,proto3\" json:\"public_key,omitempty\"`\n\tPeerPublicKey string `protobuf:\"bytes,5,opt,name=peer_public_key,json=peerPublicKey,proto3\" json:\"peer_public_key,omitempty\"`\n\tSignature     string `protobuf:\"bytes,6,opt,name=signature,proto3\" json:\"signature,omitempty\"`\n\tNotBefore     string `protobuf:\"bytes,7,opt,name=not_before,json=notBefore,proto3\" json:\"not_before,omitempty\"`\n\tNotAfter      string `protobuf:\"bytes,8,opt,name=not_after,json=notAfter,proto3\" json:\"not_after,omitempty\"`\n}\n\nfunc (x *AcnMessage_AgentRecord) Reset() {\n\t*x = AcnMessage_AgentRecord{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_acn_proto_msgTypes[1]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *AcnMessage_AgentRecord) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*AcnMessage_AgentRecord) ProtoMessage() {}\n\nfunc (x *AcnMessage_AgentRecord) ProtoReflect() protoreflect.Message {\n\tmi := &file_acn_proto_msgTypes[1]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use AcnMessage_AgentRecord.ProtoReflect.Descriptor instead.\nfunc (*AcnMessage_AgentRecord) Descriptor() ([]byte, []int) {\n\treturn file_acn_proto_rawDescGZIP(), []int{0, 0}\n}\n\nfunc (x *AcnMessage_AgentRecord) GetServiceId() string {\n\tif x != nil {\n\t\treturn x.ServiceId\n\t}\n\treturn \"\"\n}\n\nfunc (x *AcnMessage_AgentRecord) GetLedgerId() string {\n\tif x != nil {\n\t\treturn x.LedgerId\n\t}\n\treturn \"\"\n}\n\nfunc (x *AcnMessage_AgentRecord) GetAddress() string {\n\tif x != nil {\n\t\treturn x.Address\n\t}\n\treturn \"\"\n}\n\nfunc (x *AcnMessage_AgentRecord) GetPublicKey() string {\n\tif x != nil {\n\t\treturn x.PublicKey\n\t}\n\treturn \"\"\n}\n\nfunc (x *AcnMessage_AgentRecord) GetPeerPublicKey() string {\n\tif x != nil {\n\t\treturn x.PeerPublicKey\n\t}\n\treturn \"\"\n}\n\nfunc (x *AcnMessage_AgentRecord) GetSignature() string {\n\tif x != nil {\n\t\treturn x.Signature\n\t}\n\treturn \"\"\n}\n\nfunc (x *AcnMessage_AgentRecord) GetNotBefore() string {\n\tif x != nil {\n\t\treturn x.NotBefore\n\t}\n\treturn \"\"\n}\n\nfunc (x *AcnMessage_AgentRecord) GetNotAfter() string {\n\tif x != nil {\n\t\treturn x.NotAfter\n\t}\n\treturn \"\"\n}\n\ntype AcnMessage_StatusBody struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tCode AcnMessage_StatusBody_StatusCodeEnum `protobuf:\"varint,1,opt,name=code,proto3,enum=aea.aea.acn.v1_0_0.AcnMessage_StatusBody_StatusCodeEnum\" json:\"code,omitempty\"`\n\tMsgs []string                             `protobuf:\"bytes,2,rep,name=msgs,proto3\" json:\"msgs,omitempty\"`\n}\n\nfunc (x *AcnMessage_StatusBody) Reset() {\n\t*x = AcnMessage_StatusBody{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_acn_proto_msgTypes[2]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *AcnMessage_StatusBody) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*AcnMessage_StatusBody) ProtoMessage() {}\n\nfunc (x *AcnMessage_StatusBody) ProtoReflect() protoreflect.Message {\n\tmi := &file_acn_proto_msgTypes[2]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use AcnMessage_StatusBody.ProtoReflect.Descriptor instead.\nfunc (*AcnMessage_StatusBody) Descriptor() ([]byte, []int) {\n\treturn file_acn_proto_rawDescGZIP(), []int{0, 1}\n}\n\nfunc (x *AcnMessage_StatusBody) GetCode() AcnMessage_StatusBody_StatusCodeEnum {\n\tif x != nil {\n\t\treturn x.Code\n\t}\n\treturn AcnMessage_StatusBody_SUCCESS\n}\n\nfunc (x *AcnMessage_StatusBody) GetMsgs() []string {\n\tif x != nil {\n\t\treturn x.Msgs\n\t}\n\treturn nil\n}\n\n// Performatives and contents\ntype AcnMessage_Register_Performative struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tRecord *AcnMessage_AgentRecord `protobuf:\"bytes,1,opt,name=record,proto3\" json:\"record,omitempty\"`\n}\n\nfunc (x *AcnMessage_Register_Performative) Reset() {\n\t*x = AcnMessage_Register_Performative{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_acn_proto_msgTypes[3]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *AcnMessage_Register_Performative) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*AcnMessage_Register_Performative) ProtoMessage() {}\n\nfunc (x *AcnMessage_Register_Performative) ProtoReflect() protoreflect.Message {\n\tmi := &file_acn_proto_msgTypes[3]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use AcnMessage_Register_Performative.ProtoReflect.Descriptor instead.\nfunc (*AcnMessage_Register_Performative) Descriptor() ([]byte, []int) {\n\treturn file_acn_proto_rawDescGZIP(), []int{0, 2}\n}\n\nfunc (x *AcnMessage_Register_Performative) GetRecord() *AcnMessage_AgentRecord {\n\tif x != nil {\n\t\treturn x.Record\n\t}\n\treturn nil\n}\n\ntype AcnMessage_Lookup_Request_Performative struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tAgentAddress string `protobuf:\"bytes,1,opt,name=agent_address,json=agentAddress,proto3\" json:\"agent_address,omitempty\"`\n}\n\nfunc (x *AcnMessage_Lookup_Request_Performative) Reset() {\n\t*x = AcnMessage_Lookup_Request_Performative{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_acn_proto_msgTypes[4]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *AcnMessage_Lookup_Request_Performative) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*AcnMessage_Lookup_Request_Performative) ProtoMessage() {}\n\nfunc (x *AcnMessage_Lookup_Request_Performative) ProtoReflect() protoreflect.Message {\n\tmi := &file_acn_proto_msgTypes[4]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use AcnMessage_Lookup_Request_Performative.ProtoReflect.Descriptor instead.\nfunc (*AcnMessage_Lookup_Request_Performative) Descriptor() ([]byte, []int) {\n\treturn file_acn_proto_rawDescGZIP(), []int{0, 3}\n}\n\nfunc (x *AcnMessage_Lookup_Request_Performative) GetAgentAddress() string {\n\tif x != nil {\n\t\treturn x.AgentAddress\n\t}\n\treturn \"\"\n}\n\ntype AcnMessage_Lookup_Response_Performative struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tRecord *AcnMessage_AgentRecord `protobuf:\"bytes,1,opt,name=record,proto3\" json:\"record,omitempty\"`\n}\n\nfunc (x *AcnMessage_Lookup_Response_Performative) Reset() {\n\t*x = AcnMessage_Lookup_Response_Performative{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_acn_proto_msgTypes[5]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *AcnMessage_Lookup_Response_Performative) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*AcnMessage_Lookup_Response_Performative) ProtoMessage() {}\n\nfunc (x *AcnMessage_Lookup_Response_Performative) ProtoReflect() protoreflect.Message {\n\tmi := &file_acn_proto_msgTypes[5]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use AcnMessage_Lookup_Response_Performative.ProtoReflect.Descriptor instead.\nfunc (*AcnMessage_Lookup_Response_Performative) Descriptor() ([]byte, []int) {\n\treturn file_acn_proto_rawDescGZIP(), []int{0, 4}\n}\n\nfunc (x *AcnMessage_Lookup_Response_Performative) GetRecord() *AcnMessage_AgentRecord {\n\tif x != nil {\n\t\treturn x.Record\n\t}\n\treturn nil\n}\n\ntype AcnMessage_Aea_Envelope_Performative struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tEnvelope []byte                  `protobuf:\"bytes,1,opt,name=envelope,proto3\" json:\"envelope,omitempty\"`\n\tRecord   *AcnMessage_AgentRecord `protobuf:\"bytes,2,opt,name=record,proto3\" json:\"record,omitempty\"`\n}\n\nfunc (x *AcnMessage_Aea_Envelope_Performative) Reset() {\n\t*x = AcnMessage_Aea_Envelope_Performative{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_acn_proto_msgTypes[6]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *AcnMessage_Aea_Envelope_Performative) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*AcnMessage_Aea_Envelope_Performative) ProtoMessage() {}\n\nfunc (x *AcnMessage_Aea_Envelope_Performative) ProtoReflect() protoreflect.Message {\n\tmi := &file_acn_proto_msgTypes[6]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use AcnMessage_Aea_Envelope_Performative.ProtoReflect.Descriptor instead.\nfunc (*AcnMessage_Aea_Envelope_Performative) Descriptor() ([]byte, []int) {\n\treturn file_acn_proto_rawDescGZIP(), []int{0, 5}\n}\n\nfunc (x *AcnMessage_Aea_Envelope_Performative) GetEnvelope() []byte {\n\tif x != nil {\n\t\treturn x.Envelope\n\t}\n\treturn nil\n}\n\nfunc (x *AcnMessage_Aea_Envelope_Performative) GetRecord() *AcnMessage_AgentRecord {\n\tif x != nil {\n\t\treturn x.Record\n\t}\n\treturn nil\n}\n\ntype AcnMessage_Status_Performative struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tBody *AcnMessage_StatusBody `protobuf:\"bytes,1,opt,name=body,proto3\" json:\"body,omitempty\"`\n}\n\nfunc (x *AcnMessage_Status_Performative) Reset() {\n\t*x = AcnMessage_Status_Performative{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_acn_proto_msgTypes[7]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *AcnMessage_Status_Performative) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*AcnMessage_Status_Performative) ProtoMessage() {}\n\nfunc (x *AcnMessage_Status_Performative) ProtoReflect() protoreflect.Message {\n\tmi := &file_acn_proto_msgTypes[7]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use AcnMessage_Status_Performative.ProtoReflect.Descriptor instead.\nfunc (*AcnMessage_Status_Performative) Descriptor() ([]byte, []int) {\n\treturn file_acn_proto_rawDescGZIP(), []int{0, 6}\n}\n\nfunc (x *AcnMessage_Status_Performative) GetBody() *AcnMessage_StatusBody {\n\tif x != nil {\n\t\treturn x.Body\n\t}\n\treturn nil\n}\n\nvar File_acn_proto protoreflect.FileDescriptor\n\nvar file_acn_proto_rawDesc = []byte{\n\t0x0a, 0x09, 0x61, 0x63, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x12, 0x61, 0x65, 0x61,\n\t0x2e, 0x61, 0x65, 0x61, 0x2e, 0x61, 0x63, 0x6e, 0x2e, 0x76, 0x31, 0x5f, 0x30, 0x5f, 0x30, 0x22,\n\t0xea, 0x0c, 0x0a, 0x0a, 0x41, 0x63, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x5d,\n\t0x0a, 0x0c, 0x61, 0x65, 0x61, 0x5f, 0x65, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x18, 0x05,\n\t0x20, 0x01, 0x28, 0x0b, 0x32, 0x38, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x61,\n\t0x63, 0x6e, 0x2e, 0x76, 0x31, 0x5f, 0x30, 0x5f, 0x30, 0x2e, 0x41, 0x63, 0x6e, 0x4d, 0x65, 0x73,\n\t0x73, 0x61, 0x67, 0x65, 0x2e, 0x41, 0x65, 0x61, 0x5f, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70,\n\t0x65, 0x5f, 0x50, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x76, 0x65, 0x48, 0x00,\n\t0x52, 0x0b, 0x61, 0x65, 0x61, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x12, 0x63, 0x0a,\n\t0x0e, 0x6c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18,\n\t0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3a, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x61, 0x65, 0x61, 0x2e,\n\t0x61, 0x63, 0x6e, 0x2e, 0x76, 0x31, 0x5f, 0x30, 0x5f, 0x30, 0x2e, 0x41, 0x63, 0x6e, 0x4d, 0x65,\n\t0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x5f, 0x52, 0x65, 0x71,\n\t0x75, 0x65, 0x73, 0x74, 0x5f, 0x50, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x76,\n\t0x65, 0x48, 0x00, 0x52, 0x0d, 0x6c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65,\n\t0x73, 0x74, 0x12, 0x66, 0x0a, 0x0f, 0x6c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x5f, 0x72, 0x65, 0x73,\n\t0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3b, 0x2e, 0x61, 0x65,\n\t0x61, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x61, 0x63, 0x6e, 0x2e, 0x76, 0x31, 0x5f, 0x30, 0x5f, 0x30,\n\t0x2e, 0x41, 0x63, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4c, 0x6f, 0x6f, 0x6b,\n\t0x75, 0x70, 0x5f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x5f, 0x50, 0x65, 0x72, 0x66,\n\t0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x76, 0x65, 0x48, 0x00, 0x52, 0x0e, 0x6c, 0x6f, 0x6f, 0x6b,\n\t0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x52, 0x0a, 0x08, 0x72, 0x65,\n\t0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x61,\n\t0x65, 0x61, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x61, 0x63, 0x6e, 0x2e, 0x76, 0x31, 0x5f, 0x30, 0x5f,\n\t0x30, 0x2e, 0x41, 0x63, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x52, 0x65, 0x67,\n\t0x69, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x50, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69,\n\t0x76, 0x65, 0x48, 0x00, 0x52, 0x08, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x12, 0x4c,\n\t0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x32,\n\t0x2e, 0x61, 0x65, 0x61, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x61, 0x63, 0x6e, 0x2e, 0x76, 0x31, 0x5f,\n\t0x30, 0x5f, 0x30, 0x2e, 0x41, 0x63, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x53,\n\t0x74, 0x61, 0x74, 0x75, 0x73, 0x5f, 0x50, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69,\n\t0x76, 0x65, 0x48, 0x00, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x1a, 0x84, 0x02, 0x0a,\n\t0x0b, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x12, 0x1d, 0x0a, 0x0a,\n\t0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,\n\t0x52, 0x09, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x6c,\n\t0x65, 0x64, 0x67, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08,\n\t0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72,\n\t0x65, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65,\n\t0x73, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79,\n\t0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65,\n\t0x79, 0x12, 0x26, 0x0a, 0x0f, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63,\n\t0x5f, 0x6b, 0x65, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x70, 0x65, 0x65, 0x72,\n\t0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67,\n\t0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x69,\n\t0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x6e, 0x6f, 0x74, 0x5f, 0x62,\n\t0x65, 0x66, 0x6f, 0x72, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x6f, 0x74,\n\t0x42, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x6e, 0x6f, 0x74, 0x5f, 0x61, 0x66,\n\t0x74, 0x65, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6e, 0x6f, 0x74, 0x41, 0x66,\n\t0x74, 0x65, 0x72, 0x1a, 0x9e, 0x03, 0x0a, 0x0a, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x42, 0x6f,\n\t0x64, 0x79, 0x12, 0x4c, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e,\n\t0x32, 0x38, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x61, 0x63, 0x6e, 0x2e, 0x76,\n\t0x31, 0x5f, 0x30, 0x5f, 0x30, 0x2e, 0x41, 0x63, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,\n\t0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x42, 0x6f, 0x64, 0x79, 0x2e, 0x53, 0x74, 0x61, 0x74,\n\t0x75, 0x73, 0x43, 0x6f, 0x64, 0x65, 0x45, 0x6e, 0x75, 0x6d, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65,\n\t0x12, 0x12, 0x0a, 0x04, 0x6d, 0x73, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04,\n\t0x6d, 0x73, 0x67, 0x73, 0x22, 0xad, 0x02, 0x0a, 0x0e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x43,\n\t0x6f, 0x64, 0x65, 0x45, 0x6e, 0x75, 0x6d, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x55, 0x43, 0x43, 0x45,\n\t0x53, 0x53, 0x10, 0x00, 0x12, 0x1d, 0x0a, 0x19, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x55, 0x4e,\n\t0x53, 0x55, 0x50, 0x50, 0x4f, 0x52, 0x54, 0x45, 0x44, 0x5f, 0x56, 0x45, 0x52, 0x53, 0x49, 0x4f,\n\t0x4e, 0x10, 0x01, 0x12, 0x1c, 0x0a, 0x18, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x55, 0x4e, 0x45,\n\t0x58, 0x50, 0x45, 0x43, 0x54, 0x45, 0x44, 0x5f, 0x50, 0x41, 0x59, 0x4c, 0x4f, 0x41, 0x44, 0x10,\n\t0x02, 0x12, 0x11, 0x0a, 0x0d, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x47, 0x45, 0x4e, 0x45, 0x52,\n\t0x49, 0x43, 0x10, 0x03, 0x12, 0x10, 0x0a, 0x0c, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x44, 0x45,\n\t0x43, 0x4f, 0x44, 0x45, 0x10, 0x04, 0x12, 0x1d, 0x0a, 0x19, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f,\n\t0x57, 0x52, 0x4f, 0x4e, 0x47, 0x5f, 0x41, 0x47, 0x45, 0x4e, 0x54, 0x5f, 0x41, 0x44, 0x44, 0x52,\n\t0x45, 0x53, 0x53, 0x10, 0x0a, 0x12, 0x1a, 0x0a, 0x16, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x57,\n\t0x52, 0x4f, 0x4e, 0x47, 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x5f, 0x4b, 0x45, 0x59, 0x10,\n\t0x0b, 0x12, 0x17, 0x0a, 0x13, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x49, 0x4e, 0x56, 0x41, 0x4c,\n\t0x49, 0x44, 0x5f, 0x50, 0x52, 0x4f, 0x4f, 0x46, 0x10, 0x0c, 0x12, 0x1c, 0x0a, 0x18, 0x45, 0x52,\n\t0x52, 0x4f, 0x52, 0x5f, 0x55, 0x4e, 0x53, 0x55, 0x50, 0x50, 0x4f, 0x52, 0x54, 0x45, 0x44, 0x5f,\n\t0x4c, 0x45, 0x44, 0x47, 0x45, 0x52, 0x10, 0x0d, 0x12, 0x1f, 0x0a, 0x1b, 0x45, 0x52, 0x52, 0x4f,\n\t0x52, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x5f, 0x41, 0x47, 0x45, 0x4e, 0x54, 0x5f,\n\t0x41, 0x44, 0x44, 0x52, 0x45, 0x53, 0x53, 0x10, 0x14, 0x12, 0x19, 0x0a, 0x15, 0x45, 0x52, 0x52,\n\t0x4f, 0x52, 0x5f, 0x41, 0x47, 0x45, 0x4e, 0x54, 0x5f, 0x4e, 0x4f, 0x54, 0x5f, 0x52, 0x45, 0x41,\n\t0x44, 0x59, 0x10, 0x15, 0x1a, 0x5b, 0x0a, 0x15, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72,\n\t0x5f, 0x50, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x76, 0x65, 0x12, 0x42, 0x0a,\n\t0x06, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e,\n\t0x61, 0x65, 0x61, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x61, 0x63, 0x6e, 0x2e, 0x76, 0x31, 0x5f, 0x30,\n\t0x5f, 0x30, 0x2e, 0x41, 0x63, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x41, 0x67,\n\t0x65, 0x6e, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x52, 0x06, 0x72, 0x65, 0x63, 0x6f, 0x72,\n\t0x64, 0x1a, 0x42, 0x0a, 0x1b, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x5f, 0x52, 0x65, 0x71, 0x75,\n\t0x65, 0x73, 0x74, 0x5f, 0x50, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x76, 0x65,\n\t0x12, 0x23, 0x0a, 0x0d, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73,\n\t0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x41, 0x64,\n\t0x64, 0x72, 0x65, 0x73, 0x73, 0x1a, 0x62, 0x0a, 0x1c, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x5f,\n\t0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x5f, 0x50, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d,\n\t0x61, 0x74, 0x69, 0x76, 0x65, 0x12, 0x42, 0x0a, 0x06, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x18,\n\t0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x61, 0x65, 0x61, 0x2e,\n\t0x61, 0x63, 0x6e, 0x2e, 0x76, 0x31, 0x5f, 0x30, 0x5f, 0x30, 0x2e, 0x41, 0x63, 0x6e, 0x4d, 0x65,\n\t0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x72,\n\t0x64, 0x52, 0x06, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x1a, 0x7b, 0x0a, 0x19, 0x41, 0x65, 0x61,\n\t0x5f, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x5f, 0x50, 0x65, 0x72, 0x66, 0x6f, 0x72,\n\t0x6d, 0x61, 0x74, 0x69, 0x76, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x65, 0x6e, 0x76, 0x65, 0x6c, 0x6f,\n\t0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x65, 0x6e, 0x76, 0x65, 0x6c, 0x6f,\n\t0x70, 0x65, 0x12, 0x42, 0x0a, 0x06, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01,\n\t0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x61, 0x63, 0x6e,\n\t0x2e, 0x76, 0x31, 0x5f, 0x30, 0x5f, 0x30, 0x2e, 0x41, 0x63, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61,\n\t0x67, 0x65, 0x2e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x52, 0x06,\n\t0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x1a, 0x54, 0x0a, 0x13, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73,\n\t0x5f, 0x50, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x76, 0x65, 0x12, 0x3d, 0x0a,\n\t0x04, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x61, 0x65,\n\t0x61, 0x2e, 0x61, 0x65, 0x61, 0x2e, 0x61, 0x63, 0x6e, 0x2e, 0x76, 0x31, 0x5f, 0x30, 0x5f, 0x30,\n\t0x2e, 0x41, 0x63, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74,\n\t0x75, 0x73, 0x42, 0x6f, 0x64, 0x79, 0x52, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x42, 0x0e, 0x0a, 0x0c,\n\t0x70, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x76, 0x65, 0x62, 0x06, 0x70, 0x72,\n\t0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_acn_proto_rawDescOnce sync.Once\n\tfile_acn_proto_rawDescData = file_acn_proto_rawDesc\n)\n\nfunc file_acn_proto_rawDescGZIP() []byte {\n\tfile_acn_proto_rawDescOnce.Do(func() {\n\t\tfile_acn_proto_rawDescData = protoimpl.X.CompressGZIP(file_acn_proto_rawDescData)\n\t})\n\treturn file_acn_proto_rawDescData\n}\n\nvar file_acn_proto_enumTypes = make([]protoimpl.EnumInfo, 1)\nvar file_acn_proto_msgTypes = make([]protoimpl.MessageInfo, 8)\nvar file_acn_proto_goTypes = []interface{}{\n\t(AcnMessage_StatusBody_StatusCodeEnum)(0),       // 0: aea.aea.acn.v1_0_0.AcnMessage.StatusBody.StatusCodeEnum\n\t(*AcnMessage)(nil),                              // 1: aea.aea.acn.v1_0_0.AcnMessage\n\t(*AcnMessage_AgentRecord)(nil),                  // 2: aea.aea.acn.v1_0_0.AcnMessage.AgentRecord\n\t(*AcnMessage_StatusBody)(nil),                   // 3: aea.aea.acn.v1_0_0.AcnMessage.StatusBody\n\t(*AcnMessage_Register_Performative)(nil),        // 4: aea.aea.acn.v1_0_0.AcnMessage.Register_Performative\n\t(*AcnMessage_Lookup_Request_Performative)(nil),  // 5: aea.aea.acn.v1_0_0.AcnMessage.Lookup_Request_Performative\n\t(*AcnMessage_Lookup_Response_Performative)(nil), // 6: aea.aea.acn.v1_0_0.AcnMessage.Lookup_Response_Performative\n\t(*AcnMessage_Aea_Envelope_Performative)(nil),    // 7: aea.aea.acn.v1_0_0.AcnMessage.Aea_Envelope_Performative\n\t(*AcnMessage_Status_Performative)(nil),          // 8: aea.aea.acn.v1_0_0.AcnMessage.Status_Performative\n}\nvar file_acn_proto_depIdxs = []int32{\n\t7,  // 0: aea.aea.acn.v1_0_0.AcnMessage.aea_envelope:type_name -> aea.aea.acn.v1_0_0.AcnMessage.Aea_Envelope_Performative\n\t5,  // 1: aea.aea.acn.v1_0_0.AcnMessage.lookup_request:type_name -> aea.aea.acn.v1_0_0.AcnMessage.Lookup_Request_Performative\n\t6,  // 2: aea.aea.acn.v1_0_0.AcnMessage.lookup_response:type_name -> aea.aea.acn.v1_0_0.AcnMessage.Lookup_Response_Performative\n\t4,  // 3: aea.aea.acn.v1_0_0.AcnMessage.register:type_name -> aea.aea.acn.v1_0_0.AcnMessage.Register_Performative\n\t8,  // 4: aea.aea.acn.v1_0_0.AcnMessage.status:type_name -> aea.aea.acn.v1_0_0.AcnMessage.Status_Performative\n\t0,  // 5: aea.aea.acn.v1_0_0.AcnMessage.StatusBody.code:type_name -> aea.aea.acn.v1_0_0.AcnMessage.StatusBody.StatusCodeEnum\n\t2,  // 6: aea.aea.acn.v1_0_0.AcnMessage.Register_Performative.record:type_name -> aea.aea.acn.v1_0_0.AcnMessage.AgentRecord\n\t2,  // 7: aea.aea.acn.v1_0_0.AcnMessage.Lookup_Response_Performative.record:type_name -> aea.aea.acn.v1_0_0.AcnMessage.AgentRecord\n\t2,  // 8: aea.aea.acn.v1_0_0.AcnMessage.Aea_Envelope_Performative.record:type_name -> aea.aea.acn.v1_0_0.AcnMessage.AgentRecord\n\t3,  // 9: aea.aea.acn.v1_0_0.AcnMessage.Status_Performative.body:type_name -> aea.aea.acn.v1_0_0.AcnMessage.StatusBody\n\t10, // [10:10] is the sub-list for method output_type\n\t10, // [10:10] is the sub-list for method input_type\n\t10, // [10:10] is the sub-list for extension type_name\n\t10, // [10:10] is the sub-list for extension extendee\n\t0,  // [0:10] is the sub-list for field type_name\n}\n\nfunc init() { file_acn_proto_init() }\nfunc file_acn_proto_init() {\n\tif File_acn_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_acn_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*AcnMessage); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_acn_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*AcnMessage_AgentRecord); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_acn_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*AcnMessage_StatusBody); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_acn_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*AcnMessage_Register_Performative); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_acn_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*AcnMessage_Lookup_Request_Performative); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_acn_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*AcnMessage_Lookup_Response_Performative); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_acn_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*AcnMessage_Aea_Envelope_Performative); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_acn_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*AcnMessage_Status_Performative); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\tfile_acn_proto_msgTypes[0].OneofWrappers = []interface{}{\n\t\t(*AcnMessage_AeaEnvelope)(nil),\n\t\t(*AcnMessage_LookupRequest)(nil),\n\t\t(*AcnMessage_LookupResponse)(nil),\n\t\t(*AcnMessage_Register)(nil),\n\t\t(*AcnMessage_Status)(nil),\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_acn_proto_rawDesc,\n\t\t\tNumEnums:      1,\n\t\t\tNumMessages:   8,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_acn_proto_goTypes,\n\t\tDependencyIndexes: file_acn_proto_depIdxs,\n\t\tEnumInfos:         file_acn_proto_enumTypes,\n\t\tMessageInfos:      file_acn_proto_msgTypes,\n\t}.Build()\n\tFile_acn_proto = out.File\n\tfile_acn_proto_rawDesc = nil\n\tfile_acn_proto_goTypes = nil\n\tfile_acn_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "packages/fetchai/connections/p2p_libp2p/libp2p_node/protocols/acn/v1_0_0/acn.proto",
    "content": "syntax = \"proto3\";\n\npackage aea.aea.acn.v1_0_0;\n\noption go_package = \"libp2p_node/protocols/acn/v1_0_0\";\n\nmessage AcnMessage{\n\n  // Custom Types\n  message AgentRecord{\n    string service_id = 1;\n    string ledger_id = 2;\n    string address = 3;\n    string public_key = 4;\n    string peer_public_key = 5;\n    string signature = 6;\n    string not_before = 7;\n    string not_after = 8;\n  }\n\n  message StatusBody{\n    enum StatusCodeEnum {\n      // common (0x)\n      SUCCESS = 0;\n      ERROR_UNSUPPORTED_VERSION = 1;\n      ERROR_UNEXPECTED_PAYLOAD = 2;\n      ERROR_GENERIC = 3;\n      ERROR_DECODE = 4;\n      // register (1x)\n      ERROR_WRONG_AGENT_ADDRESS = 10;\n      ERROR_WRONG_PUBLIC_KEY = 11;\n      ERROR_INVALID_PROOF = 12;\n      ERROR_UNSUPPORTED_LEDGER = 13;\n      // lookup & delivery (2x) \n      ERROR_UNKNOWN_AGENT_ADDRESS = 20;\n      ERROR_AGENT_NOT_READY = 21;\n    }\n    StatusCodeEnum code = 1;\n    repeated string msgs = 2;\n  }\n\n\n  // Performatives and contents\n  message Register_Performative{\n    AgentRecord record = 1;\n  }\n\n  message Lookup_Request_Performative{\n    string agent_address = 1;\n  }\n\n  message Lookup_Response_Performative{\n    AgentRecord record = 1;\n  }\n\n  message Aea_Envelope_Performative{\n    bytes envelope = 1;\n    AgentRecord record = 2;\n  }\n\n  message Status_Performative{\n    StatusBody body = 1;\n  }\n\n\n  oneof performative{\n    Aea_Envelope_Performative aea_envelope = 5;\n    Lookup_Request_Performative lookup_request = 6;\n    Lookup_Response_Performative lookup_response = 7;\n    Register_Performative register = 8;\n    Status_Performative status = 9;\n  }\n}\n"
  },
  {
    "path": "packages/fetchai/connections/p2p_libp2p/libp2p_node/protocols/acn/v1_0_0/acn.yaml",
    "content": "---\nname: acn\nauthor: fetchai\nversion: 1.0.0\ndescription: The protocol used for envelope delivery on the ACN.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nprotocol_specification_id: aea/acn:1.0.0\nspeech_acts:\n  register:\n    record: ct:AgentRecord\n  lookup_request:\n    agent_address: pt:str\n  lookup_response:\n    record: ct:AgentRecord\n  aea_envelope:\n    envelope: pt:bytes\n    record: ct:AgentRecord\n  status:\n    body: ct:StatusBody\n...\n---\nct:AgentRecord:\n  string service_id = 1;\n  string ledger_id = 2;\n  string address = 3;\n  string public_key = 4;\n  string peer_public_key = 5;\n  string signature = 6;\n  string not_before = 7;\n  string not_after = 8;\nct:StatusBody: |\n  enum StatusCodeEnum {\n    // common (0x)\n    SUCCESS = 0;\n    ERROR_UNSUPPORTED_VERSION = 1;\n    ERROR_UNEXPECTED_PAYLOAD = 2;\n    ERROR_GENERIC = 3;\n    ERROR_DECODE = 4;\n    // register (1x)\n    ERROR_WRONG_AGENT_ADDRESS = 10;\n    ERROR_WRONG_PUBLIC_KEY = 11;\n    ERROR_INVALID_PROOF = 12;\n    ERROR_UNSUPPORTED_LEDGER = 13;\n    // lookup & delivery (2x) \n    ERROR_UNKNOWN_AGENT_ADDRESS = 20;\n    ERROR_AGENT_NOT_READY = 21;\n  }\n  StatusCodeEnum code = 1;\n  repeated string msgs = 2;\n...\n---\ninitiation: [register, lookup_request, aea_envelope]\nreply:\n  register: [status]\n  lookup_request: [lookup_response, status]\n  aea_envelope: [status]\n  status: []\n  lookup_response: []\ntermination: [status, lookup_response]\nroles: {node}\nend_states: [successful, failed]\nkeep_terminal_state_dialogues: false\n...\n"
  },
  {
    "path": "packages/fetchai/connections/p2p_libp2p/libp2p_node/utils/utils.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2019 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\n\npackage utils\n\nimport (\n\t\"bufio\"\n\t\"context\"\n\t\"crypto/sha256\"\n\t\"encoding/base64\"\n\t\"encoding/binary\"\n\t\"encoding/hex\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"math\"\n\t\"net\"\n\t\"os\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/ipfs/go-cid\"\n\t\"github.com/libp2p/go-libp2p-core/crypto\"\n\t\"github.com/libp2p/go-libp2p-core/network\"\n\t\"github.com/libp2p/go-libp2p-core/peer\"\n\tdht \"github.com/libp2p/go-libp2p-kad-dht\"\n\t\"github.com/multiformats/go-multiaddr\"\n\t\"github.com/multiformats/go-multihash\"\n\t\"github.com/rs/zerolog\"\n\t\"golang.org/x/crypto/ripemd160\" // nolint:staticcheck\n\t\"golang.org/x/crypto/sha3\"\n\n\thost \"github.com/libp2p/go-libp2p-core/host\"\n\tpeerstore \"github.com/libp2p/go-libp2p-core/peerstore\"\n\n\tbtcec \"github.com/btcsuite/btcd/btcec\"\n\t\"github.com/btcsuite/btcutil/bech32\"\n\t\"github.com/ethereum/go-ethereum/common/hexutil\"\n\tethCrypto \"github.com/ethereum/go-ethereum/crypto\"\n\tproto \"google.golang.org/protobuf/proto\"\n\n\t\"libp2p_node/aea\"\n)\n\nconst (\n\tmaxMessageSizeDelegateConnection = 1024 * 1024 * 3 // 3Mb\n)\n\nvar (\n\taddressFromPublicKeyTable = map[string]func(string) (string, error){\n\t\t\"fetchai\":  FetchAIAddressFromPublicKey,\n\t\t\"cosmos\":   CosmosAddressFromPublicKey,\n\t\t\"ethereum\": EthereumAddressFromPublicKey,\n\t}\n\tverifyLedgerSignatureTable = map[string]func([]byte, string, string) (bool, error){\n\t\t\"fetchai\":  VerifyFetchAISignatureBTC,\n\t\t\"cosmos\":   VerifyFetchAISignatureBTC,\n\t\t\"ethereum\": VerifyEthereumSignatureETH,\n\t}\n)\n\nvar loggerGlobalLevel zerolog.Level = zerolog.DebugLevel\n\nvar logger zerolog.Logger = NewDefaultLogger()\n\n// SetLoggerLevel set utils logger level\nfunc SetLoggerLevel(lvl zerolog.Level) {\n\tlogger = logger.Level(lvl)\n}\n\nfunc ignore(err error) {\n\tif err != nil {\n\t\tfmt.Println(\"IGNORED:\", err)\n\t}\n}\n\n/*\n\tLogging\n*/\n\nfunc newConsoleLogger() zerolog.Logger {\n\treturn zerolog.New(zerolog.ConsoleWriter{\n\t\tOut:        os.Stdout,\n\t\tNoColor:    false,\n\t\tTimeFormat: time.RFC3339Nano,\n\t})\n}\n\n// NewDefaultLogger basic zerolog console writer\nfunc NewDefaultLogger() zerolog.Logger {\n\treturn newConsoleLogger().\n\t\tWith().Timestamp().\n\t\tLogger().Level(loggerGlobalLevel)\n}\n\n// NewDefaultLoggerWithFields zerolog console writer\nfunc NewDefaultLoggerWithFields(fields map[string]string) zerolog.Logger {\n\tlogger := newConsoleLogger().\n\t\tWith().Timestamp()\n\tfor key, val := range fields {\n\t\tlogger = logger.Str(key, val)\n\t}\n\treturn logger.Logger().Level(loggerGlobalLevel)\n\n}\n\n/*\n\tHelpers\n*/\n\n// BootstrapConnect connect to `peers` at bootstrap\n// This code is borrowed from the go-ipfs bootstrap process\nfunc BootstrapConnect(\n\tctx context.Context,\n\tph host.Host,\n\tkaddht *dht.IpfsDHT,\n\tpeers []peer.AddrInfo,\n) error {\n\tif len(peers) < 1 {\n\t\treturn errors.New(\"not enough bootstrap peers\")\n\t}\n\n\terrs := make(chan error, len(peers))\n\tvar wg sync.WaitGroup\n\tfor _, p := range peers {\n\n\t\t// performed asynchronously because when performed synchronously, if\n\t\t// one `Connect` call hangs, subsequent calls are more likely to\n\t\t// fail/abort due to an expiring context.\n\t\t// Also, performed asynchronously for dial speed.\n\n\t\twg.Add(1)\n\t\tgo func(p peer.AddrInfo) {\n\t\t\tdefer wg.Done()\n\t\t\t//defer logger.Debug().Msgf(\"%s bootstrapDial %s %s\", ctx, ph.ID(), p.ID)\n\t\t\tlogger.Debug().Msgf(\"%s bootstrapping to %s\", ph.ID(), p.ID)\n\n\t\t\tph.Peerstore().AddAddrs(p.ID, p.Addrs, peerstore.PermanentAddrTTL)\n\t\t\tif err := ph.Connect(ctx, p); err != nil {\n\t\t\t\t//logger.Error().\n\t\t\t\t//\tStr(\"err\", err.Error()).\n\t\t\t\t//\tMsgf(\"failed to bootstrap with %v\", p.ID)\n\t\t\t\terrs <- err\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tlogger.Debug().Msgf(\"bootstrapped with %v\", p.ID)\n\t\t}(p)\n\t}\n\twg.Wait()\n\n\t// our failure condition is when no connection attempt succeeded.\n\t// So drain the errs channel, counting the results.\n\tclose(errs)\n\tcount := 0\n\tvar err error\n\tfor err = range errs {\n\t\tif err != nil {\n\t\t\tcount++\n\t\t}\n\t}\n\tif count == len(peers) {\n\t\treturn errors.New(\"failed to bootstrap: \" + err.Error())\n\t}\n\t// workaround: to avoid getting `failed to find any peer in table`\n\t//  when calling dht.Provide (happens occasionally)\n\tlogger.Debug().Msg(\"waiting for bootstrap peers to be added to dht routing table...\")\n\tfor _, peer := range peers {\n\t\tctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)\n\t\tdefer cancel()\n\t\tfor kaddht.RoutingTable().Find(peer.ID) == \"\" {\n\t\t\tselect {\n\t\t\tcase <-ctx.Done():\n\t\t\t\treturn errors.New(\n\t\t\t\t\t\"timeout: entry peer haven't been added to DHT routing table \" + peer.ID.Pretty(),\n\t\t\t\t)\n\t\t\tcase <-time.After(time.Millisecond * 5):\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// ComputeCID compute content id for ipfsDHT\nfunc ComputeCID(addr string) (cid.Cid, error) {\n\tpref := cid.Prefix{\n\t\tVersion:  0,\n\t\tCodec:    cid.Raw,\n\t\tMhType:   multihash.SHA2_256,\n\t\tMhLength: -1, // default length\n\t}\n\n\t// And then feed it some data\n\tc, err := pref.Sum([]byte(addr))\n\tif err != nil {\n\t\treturn cid.Cid{}, err\n\t}\n\n\treturn c, nil\n}\n\n// GetPeersAddrInfo Parse multiaddresses and convert them to peer.AddrInfo\nfunc GetPeersAddrInfo(peers []string) ([]peer.AddrInfo, error) {\n\tpinfos := make([]peer.AddrInfo, len(peers))\n\tfor i, addr := range peers {\n\t\tmaddr := multiaddr.StringCast(addr)\n\t\tp, err := peer.AddrInfoFromP2pAddr(maddr)\n\t\tif err != nil {\n\t\t\treturn pinfos, err\n\t\t}\n\t\tpinfos[i] = *p\n\t}\n\treturn pinfos, nil\n}\n\n/*\n\tFetchAI Crypto Helpers\n*/\n\n// PubKeyFromFetchAIPublicKey create libp2p public key from fetchai hex encoded secp256k1 key\nfunc PubKeyFromFetchAIPublicKey(publicKey string) (crypto.PubKey, error) {\n\thexBytes, _ := hex.DecodeString(publicKey)\n\treturn crypto.UnmarshalSecp256k1PublicKey(hexBytes)\n}\n\n// FetchAIPublicKeyFromPubKey return FetchAI's format serialized public key\nfunc FetchAIPublicKeyFromPubKey(publicKey crypto.PubKey) (string, error) {\n\traw, err := publicKey.Raw()\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\treturn hex.EncodeToString(raw), nil\n}\n\n// BTCPubKeyFromFetchAIPublicKey from public key string\nfunc BTCPubKeyFromFetchAIPublicKey(publicKey string) (*btcec.PublicKey, error) {\n\tpbkBytes, err := hex.DecodeString(publicKey)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tpbk, err := btcec.ParsePubKey(pbkBytes, btcec.S256())\n\treturn pbk, err\n}\n\n// BTCPubKeyFromEthereumPublicKey create libp2p public key from ethereum uncompressed\n//  hex encoded secp256k1 key\nfunc BTCPubKeyFromEthereumPublicKey(publicKey string) (*btcec.PublicKey, error) {\n\treturn BTCPubKeyFromUncompressedHex(publicKey[2:])\n}\n\n// ConvertStrEncodedSignatureToDER to convert signature to DER format\n// References:\n//  - https://github.com/fetchai/agents-aea/blob/main/aea/crypto/cosmos.py#L258\n//  - https://github.com/btcsuite/btcd/blob/master/btcec/signature.go#L47\nfunc ConvertStrEncodedSignatureToDER(signature []byte) []byte {\n\trb := signature[:len(signature)/2]\n\tsb := signature[len(signature)/2:]\n\tlength := 6 + len(rb) + len(sb)\n\tsigDER := make([]byte, length)\n\tsigDER[0] = 0x30\n\tsigDER[1] = byte(length - 2)\n\tsigDER[2] = 0x02\n\tsigDER[3] = byte(len(rb))\n\toffset := copy(sigDER[4:], rb) + 4\n\tsigDER[offset] = 0x02\n\tsigDER[offset+1] = byte(len(sb))\n\tcopy(sigDER[offset+2:], sb)\n\treturn sigDER\n}\n\n// ConvertDEREncodedSignatureToStr Convert signatue from der format to string\n// References:\n//  - https://github.com/fetchai/agents-aea/blob/main/aea/crypto/cosmos.py#L258\n//  - https://github.com/btcsuite/btcd/blob/master/btcec/signature.go#L47\nfunc ConvertDEREncodedSignatureToStr(signature []byte) ([]byte, error) {\n\tsig, err := btcec.ParseDERSignature(signature, btcec.S256())\n\tif err != nil {\n\t\treturn []byte{}, err\n\t}\n\treturn append(sig.R.Bytes(), sig.S.Bytes()...), nil\n}\n\n// ParseFetchAISignature create btcec Signature from base64 formated, string (not DER) encoded RFC6979 signature\nfunc ParseFetchAISignature(signature string) (*btcec.Signature, error) {\n\t// First convert the signature into a DER one\n\tsigBytes, err := base64.StdEncoding.DecodeString(signature)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tsigDER := ConvertStrEncodedSignatureToDER(sigBytes)\n\n\t// Parse\n\tsigBTC, err := btcec.ParseSignature(sigDER, btcec.S256())\n\treturn sigBTC, err\n}\n\n// VerifyLedgerSignature verify signature of message using public key for supported ledgers\nfunc VerifyLedgerSignature(\n\tledgerID string,\n\tmessage []byte,\n\tsignature string,\n\tpubKey string,\n) (bool, error) {\n\tverifySignature, found := verifyLedgerSignatureTable[ledgerID]\n\tif found {\n\t\treturn verifySignature(message, signature, pubKey)\n\t}\n\treturn false, errors.New(\"unsupported ledger\")\n}\n\n// VerifyFetchAISignatureBTC verify the RFC6967 string-encoded signature of message using FetchAI public key\nfunc VerifyFetchAISignatureBTC(message []byte, signature string, pubkey string) (bool, error) {\n\t// construct verifying key\n\tverifyKey, err := BTCPubKeyFromFetchAIPublicKey(pubkey)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\t// construct signature\n\tsignatureBTC, err := ParseFetchAISignature(signature)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\t// verify signature\n\tmessageHash := sha256.New()\n\t_, err = messageHash.Write([]byte(message))\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\treturn signatureBTC.Verify(messageHash.Sum(nil), verifyKey), nil\n}\n\n// VerifyFetchAISignatureLibp2p verify RFC6967 string-encoded signature of message using FetchAI public key\nfunc VerifyFetchAISignatureLibp2p(message []byte, signature string, pubkey string) (bool, error) {\n\t// construct verifying key\n\tverifyKey, err := PubKeyFromFetchAIPublicKey(pubkey)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\t// Convert signature into DER encoding\n\tsigBytes, err := base64.StdEncoding.DecodeString(signature)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\tsigDER := ConvertStrEncodedSignatureToDER(sigBytes)\n\n\t// verify signature\n\treturn verifyKey.Verify(message, sigDER)\n}\n\n// SignFetchAI signs message with private key\nfunc SignFetchAI(message []byte, privKey string) (string, error) {\n\tsigningKey, _, err := KeyPairFromFetchAIKey(privKey)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tsignature, err := signingKey.Sign(message)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tstrSignature, err := ConvertDEREncodedSignatureToStr(signature)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tencodedSignature := base64.StdEncoding.EncodeToString(strSignature)\n\treturn encodedSignature, nil\n}\n\nfunc signHashETH(data []byte) []byte {\n\tmsg := fmt.Sprintf(\"\\x19Ethereum Signed Message:\\n%d%s\", len(data), data)\n\treturn ethCrypto.Keccak256([]byte(msg))\n}\n\n// RecoverAddressFromEthereumSignature verify the signature and returns the address of the signer\n// references:\n//  - https://github.com/ethereum/go-ethereum/blob/55599ee95d4151a2502465e0afc7c47bd1acba77/internal/ethapi/api.go#L452-L459\n//  - https://github.com/ethereum/go-ethereum/blob/55599ee95d4151a2502465e0afc7c47bd1acba77/internal/ethapi/api.go#L404\nfunc RecoverAddressFromEthereumSignature(message []byte, signature string) (string, error) {\n\t// prepare signature\n\tsigBytes, err := hexutil.Decode(signature)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tif sigBytes[64] != 27 && sigBytes[64] != 28 {\n\t\treturn \"\", errors.New(\"invalid Ethereum signature (V is not 27 or 28)\")\n\t}\n\tsigBytes[64] -= 27 // Transform yellow paper V from 27/28 to 0/1\n\n\t// recover verify key\n\trecoveredPubKey, err := ethCrypto.SigToPub(signHashETH(message), sigBytes)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn ethCrypto.PubkeyToAddress(*recoveredPubKey).Hex(), nil\n}\n\n// VerifyEthereumSignatureETH verify ethereum signature using ethereum public key\nfunc VerifyEthereumSignatureETH(message []byte, signature string, pubkey string) (bool, error) {\n\t// get expected signer address\n\texpectedAddress, err := EthereumAddressFromPublicKey(pubkey)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\t// recover signer address\n\trecoveredAddress, err := RecoverAddressFromEthereumSignature(message, signature)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\tif recoveredAddress != expectedAddress {\n\t\treturn false, errors.New(\"recovered and expected addresses don't match\")\n\t}\n\n\treturn true, nil\n}\n\n// KeyPairFromFetchAIKey  key pair from hex encoded secp256k1 private key\nfunc KeyPairFromFetchAIKey(key string) (crypto.PrivKey, crypto.PubKey, error) {\n\tpkBytes, err := hex.DecodeString(key)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tbtcPrivateKey, _ := btcec.PrivKeyFromBytes(btcec.S256(), pkBytes)\n\tprvKey, pubKey, err := crypto.KeyPairFromStdKey(btcPrivateKey)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\treturn prvKey, pubKey, nil\n}\n\n// AgentAddressFromPublicKey get wallet address from public key associated with ledgerId\n// format from: https://github.com/fetchai/agents-aea/blob/main/aea/crypto/cosmos.py#L120\nfunc AgentAddressFromPublicKey(ledgerID string, publicKey string) (string, error) {\n\tif addressFromPublicKey, found := addressFromPublicKeyTable[ledgerID]; found {\n\t\treturn addressFromPublicKey(publicKey)\n\t}\n\treturn \"\", errors.New(\"Unsupported ledger \" + ledgerID)\n}\n\n// FetchAIAddressFromPublicKey get wallet address from hex encoded secp256k1 public key\nfunc FetchAIAddressFromPublicKey(publicKey string) (string, error) {\n\treturn cosmosAddressFromPublicKeyWithPrefix(\"fetch\", publicKey)\n}\n\n// CosmosAddressFromPublicKey get wallet address from hex encoded secp256k1 public key\nfunc CosmosAddressFromPublicKey(publicKey string) (string, error) {\n\treturn cosmosAddressFromPublicKeyWithPrefix(\"cosmos\", publicKey)\n}\n\n// cosmosAddressFromPublicKeyWithPrefix get wallet address from hex encoded secp256k1 public key\n// format from: https://github.com/fetchai/agents-aea/blob/main/aea/crypto/cosmos.py#L120\nfunc cosmosAddressFromPublicKeyWithPrefix(prefix string, publicKey string) (string, error) {\n\tvar addr string\n\tvar err error\n\thexBytes, err := hex.DecodeString(publicKey)\n\tif err != nil {\n\t\treturn addr, err\n\t}\n\thash := sha256.New()\n\t_, err = hash.Write(hexBytes)\n\tif err != nil {\n\t\treturn addr, err\n\t}\n\tsha256Hash := hash.Sum(nil)\n\thash = ripemd160.New()\n\t_, err = hash.Write(sha256Hash)\n\tif err != nil {\n\t\treturn addr, err\n\t}\n\tripemd160Hash := hash.Sum(nil)\n\tfiveBitsChar, err := bech32.ConvertBits(ripemd160Hash, 8, 5, true)\n\tif err != nil {\n\t\treturn addr, err\n\t}\n\taddr, err = bech32.Encode(prefix, fiveBitsChar)\n\treturn addr, err\n}\n\n// EthereumAddressFromPublicKey get wallet address from hex encoded secp256k1 public key\n// references:\n//  - https://github.com/fetchai/agents-aea/blob/main/aea/crypto/ethereum.py#L330\n//  - https://github.com/ethereum/go-ethereum/blob/master/crypto/crypto.go#L263\nfunc EthereumAddressFromPublicKey(publicKey string) (string, error) {\n\tvar addr string\n\tvar err error\n\thexBytes, err := hex.DecodeString(publicKey[2:])\n\tif err != nil {\n\t\treturn addr, err\n\t}\n\thash := sha3.NewLegacyKeccak256()\n\t_, err = hash.Write(hexBytes)\n\tif err != nil {\n\t\treturn addr, err\n\t}\n\tsha3KeccakHash := hash.Sum(nil)\n\treturn encodeChecksumEIP55(sha3KeccakHash[12:]), nil\n}\n\n// encodeChecksumEIP55 EIP55-compliant hex string representation of the address\n// source: https://github.com/ethereum/go-ethereum/blob/master/common/types.go#L210\n// reference: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-55.md\nfunc encodeChecksumEIP55(address []byte) string {\n\tunchecksummed := hex.EncodeToString(address[:])\n\tsha := sha3.NewLegacyKeccak256()\n\t_, err := sha.Write([]byte(unchecksummed))\n\tignore(err)\n\thash := sha.Sum(nil)\n\n\tresult := []byte(unchecksummed)\n\tfor i := 0; i < len(result); i++ {\n\t\thashByte := hash[i/2]\n\t\tif i%2 == 0 {\n\t\t\thashByte = hashByte >> 4\n\t\t} else {\n\t\t\thashByte &= 0xf\n\t\t}\n\t\tif result[i] > '9' && hashByte > 7 {\n\t\t\tresult[i] -= 32\n\t\t}\n\t}\n\treturn \"0x\" + string(result)\n}\n\n// IDFromFetchAIPublicKey Get PeeID (multihash) from fetchai public key\nfunc IDFromFetchAIPublicKey(publicKey string) (peer.ID, error) {\n\tb, err := hex.DecodeString(publicKey)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tpubKey, err := btcec.ParsePubKey(b, btcec.S256())\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tmultihash, err := peer.IDFromPublicKey((*crypto.Secp256k1PublicKey)(pubKey))\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn multihash, nil\n}\n\n// BTCPubKeyFromUncompressedHex get public key from secp256k1 hex encoded  uncompressed representation\nfunc BTCPubKeyFromUncompressedHex(publicKey string) (*btcec.PublicKey, error) {\n\tb, err := hex.DecodeString(publicKey)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tpubBytes := make([]byte, 0, btcec.PubKeyBytesLenUncompressed)\n\tpubBytes = append(pubBytes, 0x4) // btcec.pubkeyUncompressed\n\tpubBytes = append(pubBytes, b...)\n\n\treturn btcec.ParsePubKey(pubBytes, btcec.S256())\n}\n\n// IDFromFetchAIPublicKeyUncompressed Get PeeID (multihash) from fetchai public key\nfunc IDFromFetchAIPublicKeyUncompressed(publicKey string) (peer.ID, error) {\n\tpubKey, err := BTCPubKeyFromUncompressedHex(publicKey)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tmultihash, err := peer.IDFromPublicKey((*crypto.Secp256k1PublicKey)(pubKey))\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn multihash, nil\n}\n\n// FetchAIPublicKeyFromFetchAIPrivateKey get fetchai public key from fetchai private key\nfunc FetchAIPublicKeyFromFetchAIPrivateKey(privateKey string) (string, error) {\n\tpkBytes, err := hex.DecodeString(privateKey)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\t_, btcPublicKey := btcec.PrivKeyFromBytes(btcec.S256(), pkBytes)\n\n\treturn hex.EncodeToString(btcPublicKey.SerializeCompressed()), nil\n}\n\n/*\n   Utils\n*/\n\n// WriteBytesConn send bytes to `conn`\nfunc WriteBytesConn(conn net.Conn, data []byte) error {\n\n\tif len(data) > math.MaxInt32 {\n\t\tlogger.Error().Msg(\"data size too large\")\n\t\treturn errors.New(\"data size too large\")\n\t}\n\tif len(data) == 0 {\n\t\tlogger.Error().Msg(\"No data to write\")\n\t\treturn nil\n\t}\n\n\tsize := uint32(len(data))\n\tbuf := make([]byte, 4, 4+size)\n\tbinary.BigEndian.PutUint32(buf, size)\n\tbuf = append(buf, data...)\n\t_, err := conn.Write(buf)\n\treturn err\n}\n\n// ReadBytesConn receive bytes from `conn`\nfunc ReadBytesConn(conn net.Conn) ([]byte, error) {\n\tbuf := make([]byte, 4)\n\t_, err := conn.Read(buf)\n\tif err != nil {\n\t\treturn buf, err\n\t}\n\n\tsize := binary.BigEndian.Uint32(buf)\n\tif size > maxMessageSizeDelegateConnection {\n\t\treturn nil, errors.New(\"expected message size larger than maximum allowed\")\n\t}\n\n\tbuf = make([]byte, size)\n\t_, err = conn.Read(buf)\n\treturn buf, err\n}\n\n// WriteEnvelopeConn send envelope to `conn`\nfunc WriteEnvelopeConn(conn net.Conn, envelope *aea.Envelope) error {\n\tdata, err := proto.Marshal(envelope)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn WriteBytesConn(conn, data)\n}\n\n// ReadEnvelopeConn receive envelope from `conn`\nfunc ReadEnvelopeConn(conn net.Conn) (*aea.Envelope, error) {\n\tenvelope := &aea.Envelope{}\n\tdata, err := ReadBytesConn(conn)\n\tif err != nil {\n\t\treturn envelope, err\n\t}\n\terr = proto.Unmarshal(data, envelope)\n\treturn envelope, err\n}\n\n// ReadBytes from a network stream\nfunc ReadBytes(s network.Stream) ([]byte, error) {\n\tif s == nil {\n\t\tpanic(\"CRITICAL can not write to nil stream\")\n\t}\n\n\trstream := bufio.NewReader(s)\n\n\tbuf := make([]byte, 4)\n\t_, err := io.ReadFull(rstream, buf)\n\tif err != nil {\n\t\tlogger.Error().\n\t\t\tStr(\"err\", err.Error()).\n\t\t\tMsg(\"while receiving size\")\n\t\treturn buf, err\n\t}\n\n\tsize := binary.BigEndian.Uint32(buf)\n\tif size > maxMessageSizeDelegateConnection {\n\t\treturn nil, errors.New(\"expected message size larger than maximum allowed\")\n\t}\n\n\t//logger.Debug().Msgf(\"expecting %d\", size)\n\n\tbuf = make([]byte, size)\n\t_, err = io.ReadFull(rstream, buf)\n\n\treturn buf, err\n}\n\n// WriteBytes to a network stream\nfunc WriteBytes(s network.Stream, data []byte) error {\n\tif len(data) > math.MaxInt32 {\n\t\tlogger.Error().Msg(\"data size too large\")\n\t\treturn errors.New(\"data size too large\")\n\t}\n\tif len(data) == 0 {\n\t\tlogger.Error().Msg(\"No data to write\")\n\t\treturn nil\n\t}\n\n\tif s == nil {\n\t\tpanic(\"CRITICAL, can not write to nil stream\")\n\t}\n\n\twstream := bufio.NewWriter(s)\n\n\tsize := uint32(len(data))\n\tbuf := make([]byte, 4)\n\tbinary.BigEndian.PutUint32(buf, size)\n\n\t_, err := wstream.Write(buf)\n\tif err != nil {\n\t\tlogger.Error().\n\t\t\tStr(\"err\", err.Error()).\n\t\t\tMsg(\"while sending size\")\n\t\treturn err\n\t}\n\n\t//logger.Debug().Msgf(\"writing %d\", len(data))\n\t_, err = wstream.Write(data)\n\tif err != nil {\n\t\tlogger.Error().\n\t\t\tStr(\"err\", err.Error()).\n\t\t\tMsg(\"Error on data write\")\n\t\treturn err\n\t}\n\tif s == nil {\n\t\tpanic(\"CRITICAL, can not flush nil stream\")\n\t}\n\n\terr = wstream.Flush()\n\treturn err\n}\n\ntype ConnPipe struct {\n\tConn net.Conn\n}\n\nfunc (conPipe ConnPipe) Connect() error {\n\treturn nil\n}\nfunc (conPipe ConnPipe) Read() ([]byte, error) {\n\treturn ReadBytesConn(conPipe.Conn)\n}\nfunc (conPipe ConnPipe) Write(data []byte) error {\n\treturn WriteBytesConn(conPipe.Conn, data)\n}\nfunc (conPipe ConnPipe) Close() error {\n\treturn nil\n}\n\ntype StreamPipe struct {\n\tStream network.Stream\n}\n\nfunc (streamPipe StreamPipe) Connect() error {\n\treturn nil\n}\nfunc (streamPipe StreamPipe) Read() ([]byte, error) {\n\treturn ReadBytes(streamPipe.Stream)\n}\nfunc (streamPipe StreamPipe) Write(data []byte) error {\n\treturn WriteBytes(streamPipe.Stream, data)\n}\nfunc (streamPipe StreamPipe) Close() error {\n\treturn nil\n}\n"
  },
  {
    "path": "packages/fetchai/connections/p2p_libp2p/libp2p_node/utils/utils_test.go",
    "content": "/* -*- coding: utf-8 -*-\n* ------------------------------------------------------------------------------\n*\n*   Copyright 2018-2021 Fetch.AI Limited\n*\n*   Licensed under the Apache License, Version 2.0 (the \"License\");\n*   you may not use this file except in compliance with the License.\n*   You may obtain a copy of the License at\n*\n*       http://www.apache.org/licenses/LICENSE-2.0\n*\n*   Unless required by applicable law or agreed to in writing, software\n*   distributed under the License is distributed on an \"AS IS\" BASIS,\n*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*   See the License for the specific language governing permissions and\n*   limitations under the License.\n*\n* ------------------------------------------------------------------------------\n */\n\npackage utils\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"libp2p_node/aea\"\n\tmocks \"libp2p_node/mocks\"\n\t\"net\"\n\t\"reflect\"\n\t\"testing\"\n\n\t\"bou.ke/monkey\"\n\tgomock \"github.com/golang/mock/gomock\"\n\t\"github.com/libp2p/go-libp2p-core/peer\"\n\tdht \"github.com/libp2p/go-libp2p-kad-dht\"\n\tkb \"github.com/libp2p/go-libp2p-kbucket\"\n\tma \"github.com/multiformats/go-multiaddr\"\n\t\"github.com/rs/zerolog\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\n// Crypto operations\n\nfunc TestEthereumCrypto(t *testing.T) {\n\t//privateKey := \"0xb60fe8027fb82f1a1bd6b8e66d4400f858989a2c67428a4e7f589441700339b0\"\n\tpublicKey := \"0xf753e5a9e2368e97f4db869a0d956d3ffb64672d6392670572906c786b5712ada13b6bff882951b3ba3dd65bdacc915c2b532efc3f183aa44657205c6c337225\"\n\taddress := \"0xb8d8c62d4a1999b7aea0aebBD5020244a4a9bAD8\"\n\tpublicKeySignature := \"0x304c2ba4ae7fa71295bfc2920b9c1268d574d65531f1f4d2117fc1439a45310c37ab75085a9df2a4169a4d47982b330a4387b1ded0c8881b030629db30bbaf3a1c\"\n\n\taddFromPublicKey, err := EthereumAddressFromPublicKey(publicKey)\n\tif err != nil || addFromPublicKey != address {\n\t\tt.Error(\n\t\t\t\"Error when computing address from public key or address and public key don't match\",\n\t\t)\n\t}\n\n\t_, err = BTCPubKeyFromEthereumPublicKey(publicKey)\n\tif err != nil {\n\t\tt.Errorf(\"While building BTC public key from string: %s\", err.Error())\n\t}\n\n\t/*\n\t\tethSig, err := secp256k1.Sign(hashedPublicKey, hexutil.MustDecode(privateKey))\n\t\tif err != nil {\n\t\t\tt.Error(err.Error())\n\t\t}\n\t\tprintln(hexutil.Encode(ethSig))\n\t\thash := sha3.NewLegacyKeccak256()\n\t\t_, err = hash.Write([]byte(publicKey))\n\t\tif err != nil {\n\t\t\tt.Error(err.Error())\n\t\t}\n\t\tsha3KeccakHash := hash.Sum(nil)\n\t*/\n\n\tvalid, err := VerifyEthereumSignatureETH([]byte(publicKey), publicKeySignature, publicKey)\n\tif err != nil {\n\t\tt.Error(err.Error())\n\t}\n\n\tif !valid {\n\t\tt.Errorf(\"Signer address don't match %s\", addFromPublicKey)\n\t}\n}\n\nfunc TestFetchAICrypto(t *testing.T) {\n\tpublicKey := \"02358e3e42a6ba15cf6b2ba6eb05f02b8893acf82b316d7dd9cda702b0892b8c71\"\n\taddress := \"fetch19dq2mkcpp6x0aypxt9c9gz6n4fqvax0x9a7t5r\"\n\tpeerPublicKey := \"027af21aff853b9d9589867ea142b0a60a9611fc8e1fae04c2f7144113fa4e938e\"\n\tpySigStrCanonize := \"N/GOa7/m3HU8/gpLJ88VCQ6vXsdrfiiYcqnNtF+c2N9VG9ZIiycykN4hdbpbOCGrChMYZQA3G1GpozsShrUBgg==\"\n\n\taddressFromPublicKey, _ := FetchAIAddressFromPublicKey(publicKey)\n\tif address != addressFromPublicKey {\n\t\tt.Error(\"[ERR] Addresses don't match\")\n\t} else {\n\t\tt.Log(\"[OK] Agent address matches its public key\")\n\t}\n\n\tvalid, err := VerifyFetchAISignatureBTC(\n\t\t[]byte(peerPublicKey),\n\t\tpySigStrCanonize,\n\t\tpublicKey,\n\t)\n\tif !valid {\n\t\tt.Errorf(\"Signature using BTC don't match %s\", err.Error())\n\t}\n\tvalid, err = VerifyFetchAISignatureLibp2p(\n\t\t[]byte(peerPublicKey),\n\t\tpySigStrCanonize,\n\t\tpublicKey,\n\t)\n\tif !valid {\n\t\tt.Errorf(\"Signature using LPP don't match %s\", err.Error())\n\t}\n}\n\nfunc TestSetLoggerLevel(t *testing.T) {\n\tassert.Equal(t, logger.GetLevel(), zerolog.Level(0), \"Initial log level is not 0\")\n\n\tlvl := zerolog.InfoLevel\n\tSetLoggerLevel(lvl)\n\n\tassert.Equal(\n\t\tt,\n\t\tlogger.GetLevel(),\n\t\tlvl,\n\t\t\"Waited for logger level %d but got %d\",\n\t\tlvl,\n\t\tlogger.GetLevel(),\n\t)\n}\n\nfunc Example_ignore() {\n\tignore(errors.New(\"Test\"))\n\t// Output: IGNORED: Test\n}\n\nfunc TestNewDefaultLoggerWithFields(t *testing.T) {\n\tfields := map[string]string{\n\t\t\"test_field\": \"test_value\",\n\t}\n\tvar logBuffer bytes.Buffer\n\tlogger := NewDefaultLoggerWithFields(fields).Output(&logBuffer)\n\tlogger.Info().Msg(\"test\")\n\tvar jsonResult map[string]interface{}\n\terr := json.Unmarshal(logBuffer.Bytes(), &jsonResult)\n\tassert.Equal(t, nil, err)\n\tassert.Equal(t, jsonResult[\"test_field\"], \"test_value\")\n}\n\nfunc TestComputeCID(t *testing.T) {\n\taddress := \"fetch19dq2mkcpp6x0aypxt9c9gz6n4fqvax0x9a7t5r\"\n\tcid, err := ComputeCID(address)\n\tassert.Equal(t, nil, err)\n\tassert.Equal(t, \"QmZ6ryKyS9rSnesX8YnFLAmFwFuRMdHpE7pQ2V6SjXTbqM\", cid.String())\n}\n\nfunc TestWriteBytes(t *testing.T) {\n\tmockCtrl := gomock.NewController(t)\n\tdefer mockCtrl.Finish()\n\tmockStream := mocks.NewMockStream(mockCtrl)\n\tmockStream.EXPECT().Write([]byte{0, 0, 0, 5, 104, 101, 108, 108, 111}).Return(9, nil).Times(1)\n\terr := WriteBytes(mockStream, []byte(\"hello\"))\n\tassert.Equal(t, nil, err)\n\n\tmockStream.EXPECT().\n\t\tWrite([]byte{0, 0, 0, 4, 104, 101, 108, 108}).\n\t\tReturn(8, errors.New(\"oops\")).\n\t\tTimes(1)\n\terr = WriteBytes(mockStream, []byte(\"hell\"))\n\tassert.NotEqual(t, err, nil)\n}\n\nfunc TestReadBytesConn(t *testing.T) {\n\tmockCtrl := gomock.NewController(t)\n\tdefer mockCtrl.Finish()\n\tmockConn := mocks.NewMockConn(mockCtrl)\n\tmockConn.EXPECT().Read(gomock.Any()).Return(4, nil).Times(2)\n\tbuf, err := ReadBytesConn(mockConn)\n\tassert.Equal(t, nil, err)\n\tassert.Equal(t, \"\", string(buf))\n}\n\nfunc TestWriteBytesConn(t *testing.T) {\n\tmockCtrl := gomock.NewController(t)\n\tdefer mockCtrl.Finish()\n\tmockConn := mocks.NewMockConn(mockCtrl)\n\tmockConn.EXPECT().Write(gomock.Any()).Return(0, nil).Times(1)\n\terr := WriteBytesConn(mockConn, []byte(\"ABC\"))\n\tassert.Equal(t, nil, err)\n}\n\nfunc TestReadWriteEnvelopeFromConnection(t *testing.T) {\n\tmockCtrl := gomock.NewController(t)\n\tdefer mockCtrl.Finish()\n\tdefer monkey.UnpatchAll()\n\taddress := \"0xb8d8c62d4a1999b7aea0aebBD5020244a4a9bAD8\"\n\tbuffer := bytes.NewBuffer([]byte{})\n\tmockConn := mocks.NewMockConn(mockCtrl)\n\n\tt.Run(\"TestWriteEnvelope\", func(t *testing.T) {\n\t\tmonkey.PatchInstanceMethod(\n\t\t\treflect.TypeOf(mockConn),\n\t\t\t\"Write\",\n\t\t\tfunc(_ *mocks.MockConn, b []byte) (int, error) {\n\t\t\t\tbuffer.Write(b)\n\t\t\t\treturn 0, nil\n\t\t\t},\n\t\t)\n\n\t\terr := WriteEnvelopeConn(mockConn, &aea.Envelope{\n\t\t\tTo:     address,\n\t\t\tSender: address,\n\t\t})\n\t\tassert.Equal(t, nil, err)\n\t\tassert.NotEqual(t, 0, buffer)\n\t})\n\n\tt.Run(\"TestReadEnvelope\", func(t *testing.T) {\n\t\tmonkey.Patch(ReadBytesConn, func(conn net.Conn) ([]byte, error) {\n\t\t\treturn buffer.Bytes()[4:], nil\n\t\t})\n\t\tenv, err := ReadEnvelopeConn(mockConn)\n\t\tassert.Equal(t, nil, err)\n\t\tassert.Equal(t, address, env.To)\n\t})\n}\n\nfunc TestGetPeersAddrInfo(t *testing.T) {\n\taddrs, err := GetPeersAddrInfo(\n\t\t[]string{\n\t\t\t\"/dns4/acn.fetch.ai/tcp/9001/p2p/16Uiu2HAmVWnopQAqq4pniYLw44VRvYxBUoRHqjz1Hh2SoCyjbyRW\",\n\t\t},\n\t)\n\tassert.Equal(t, nil, err)\n\tassert.Equal(t, 1, len(addrs))\n}\n\nfunc TestFetchAIPublicKeyFromPubKey(t *testing.T) {\n\t//(publicKey crypto.PubKey) (string, error) {\n\t_, pubKey, err := KeyPairFromFetchAIKey(\n\t\t\"3e7a1f43b2d8a4b9f63a2ffeb1d597f971a8db7ffd95453173268b453106cadc\",\n\t)\n\tassert.Equal(t, nil, err)\n\tkey, err := FetchAIPublicKeyFromPubKey(pubKey)\n\tassert.Equal(t, nil, err)\n\tassert.Equal(t, \"03b7e977f498dce004e2614764ff576e17cc6691135497e7bcb5d3441e816ba9e1\", key)\n}\n\nfunc TestIDFromFetchAIPublicKey(t *testing.T) {\n\t_, pubKey, err := KeyPairFromFetchAIKey(\n\t\t\"3e7a1f43b2d8a4b9f63a2ffeb1d597f971a8db7ffd95453173268b453106cadc\",\n\t)\n\tassert.Equal(t, nil, err)\n\tkey, err := FetchAIPublicKeyFromPubKey(pubKey)\n\tassert.Equal(t, nil, err)\n\tpeerID, err := IDFromFetchAIPublicKey(key)\n\tassert.Equal(t, nil, err)\n\tassert.NotEqual(t, 0, len(peerID))\n}\n\nfunc TestAgentAddressFromPublicKey(t *testing.T) {\n\taddress, err := AgentAddressFromPublicKey(\n\t\t\"fetchai\",\n\t\t\"3e7a1f43b2d8a4b9f63a2ffeb1d597f971a8db7ffd95453173268b453106cadc\",\n\t)\n\tassert.Equal(t, nil, err)\n\tassert.NotEqual(t, 0, len(address))\n}\n\nfunc TestCosmosAddressFromPublicKey(t *testing.T) {\n\taddress, err := CosmosAddressFromPublicKey(\n\t\t\"3e7a1f43b2d8a4b9f63a2ffeb1d597f971a8db7ffd95453173268b453106cadc\",\n\t)\n\tassert.Equal(t, nil, err)\n\tassert.NotEqual(t, 0, len(address))\n}\n\nfunc TestFetchAIPublicKeyFromFetchAIPrivateKey(t *testing.T) {\n\tkey, err := FetchAIPublicKeyFromFetchAIPrivateKey(\n\t\t\"3e7a1f43b2d8a4b9f63a2ffeb1d597f971a8db7ffd95453173268b453106cadc\",\n\t)\n\tassert.Equal(t, nil, err)\n\tassert.Equal(t, \"03b7e977f498dce004e2614764ff576e17cc6691135497e7bcb5d3441e816ba9e1\", key)\n}\n\nfunc TestIDFromFetchAIPublicKeyUncompressed(t *testing.T) {\n\t//bad pub key\n\t_, err := IDFromFetchAIPublicKeyUncompressed(\"some\")\n\tassert.NotEqual(t, nil, err)\n\t// good pub key\n\tid, err := IDFromFetchAIPublicKeyUncompressed(\n\t\t\"50863AD64A87AE8A2FE83C1AF1A8403CB53F53E486D8511DAD8A04887E5B23522CD470243453A299FA9E77237716103ABC11A1DF38855ED6F2EE187E9C582BA6\",\n\t)\n\tassert.Equal(t, nil, err)\n\tassert.Equal(\n\t\tt,\n\t\tpeer.ID(\n\t\t\t\"\\x00%\\b\\x02\\x12!\\x02P\\x86:\\xd6J\\x87\\xae\\x8a/\\xe8<\\x1a\\xf1\\xa8@<\\xb5?S\\xe4\\x86\\xd8Q\\x1d\\xad\\x8a\\x04\\x88~[#R\",\n\t\t),\n\t\tid,\n\t)\n}\n\nfunc TestSignFetchAI(t *testing.T) {\n\tprivKey := \"3e7a1f43b2d8a4b9f63a2ffeb1d597f971a8db7ffd95453173268b453106cadc\"\n\tmessage := []byte(\"somebytes\")\n\n\t_, pubKey, err := KeyPairFromFetchAIKey(privKey)\n\tassert.Equal(t, nil, err)\n\tfetchPubKey, err := FetchAIPublicKeyFromPubKey(pubKey)\n\tassert.Equal(t, nil, err)\n\n\tsignature, err := SignFetchAI(message, privKey)\n\tassert.Equal(t, nil, err)\n\tassert.NotEqual(t, 0, len(signature))\n\n\tisValid, err := VerifyLedgerSignature(\"fetchai\", message, signature, fetchPubKey)\n\tassert.Equal(t, nil, err)\n\tassert.Equal(t, true, isValid)\n\n}\n\nfunc TestBootstrapConnect(t *testing.T) {\n\tctx := context.Background()\n\tmockCtrl := gomock.NewController(t)\n\tdefer mockCtrl.Finish()\n\tdefer monkey.UnpatchAll()\n\tvar ipfsdht *dht.IpfsDHT\n\tvar routingTable *kb.RoutingTable\n\n\tmockPeerstore := mocks.NewMockPeerstore(mockCtrl)\n\tpeers := make([]peer.AddrInfo, 2)\n\tvar addrs []ma.Multiaddr\n\tpeers[0] = peer.AddrInfo{ID: peer.ID(\"peer1\"), Addrs: addrs}\n\tpeers[1] = peer.AddrInfo{ID: peer.ID(\"peer2\"), Addrs: addrs}\n\n\tmockHost := mocks.NewMockHost(mockCtrl)\n\n\tmockHost.EXPECT().ID().Return(peer.ID(\"host_id\")).Times(2)\n\tmockHost.EXPECT().Peerstore().Return(mockPeerstore).Times(2)\n\tmockHost.EXPECT().Connect(gomock.Any(), gomock.Any()).Return(nil).Times(2)\n\tmockPeerstore.EXPECT().AddAddrs(gomock.Any(), gomock.Any(), gomock.Any()).Return().Times(2)\n\n\tt.Run(\"TestOk\", func(t *testing.T) {\n\t\tmonkey.PatchInstanceMethod(\n\t\t\treflect.TypeOf(routingTable),\n\t\t\t\"Find\",\n\t\t\tfunc(_ *kb.RoutingTable, _ peer.ID) peer.ID {\n\t\t\t\treturn peer.ID(\"som peer\")\n\t\t\t},\n\t\t)\n\t\tmonkey.PatchInstanceMethod(\n\t\t\treflect.TypeOf(ipfsdht),\n\t\t\t\"RoutingTable\",\n\t\t\tfunc(_ *dht.IpfsDHT) *kb.RoutingTable {\n\t\t\t\treturn routingTable\n\t\t\t},\n\t\t)\n\n\t\terr := BootstrapConnect(ctx, mockHost, ipfsdht, peers)\n\t\tassert.Equal(t, nil, err)\n\t})\n\n\tmockHost = mocks.NewMockHost(mockCtrl)\n\n\tmockHost.EXPECT().ID().Return(peer.ID(\"host_id\")).Times(2)\n\tmockHost.EXPECT().Peerstore().Return(mockPeerstore).Times(2)\n\tmockHost.EXPECT().Connect(gomock.Any(), gomock.Any()).Return(nil).Times(2)\n\tmockPeerstore.EXPECT().AddAddrs(gomock.Any(), gomock.Any(), gomock.Any()).Return().Times(2)\n\n\tt.Run(\"Test_PeersNotAdded\", func(t *testing.T) {\n\t\tmonkey.PatchInstanceMethod(\n\t\t\treflect.TypeOf(routingTable),\n\t\t\t\"Find\",\n\t\t\tfunc(_ *kb.RoutingTable, _ peer.ID) peer.ID {\n\t\t\t\treturn peer.ID(\"\")\n\t\t\t},\n\t\t)\n\t\tmonkey.PatchInstanceMethod(\n\t\t\treflect.TypeOf(ipfsdht),\n\t\t\t\"RoutingTable\",\n\t\t\tfunc(_ *dht.IpfsDHT) *kb.RoutingTable {\n\t\t\t\treturn routingTable\n\t\t\t},\n\t\t)\n\n\t\terr := BootstrapConnect(ctx, mockHost, ipfsdht, peers)\n\t\tassert.NotEqual(t, nil, err)\n\t\tassert.Contains(t, err.Error(), \"timeout: entry peer haven't been added to DHT\")\n\t})\n\n\tmockHost = mocks.NewMockHost(mockCtrl)\n\n\tmockHost.EXPECT().ID().Return(peer.ID(\"host_id\")).Times(2)\n\tmockHost.EXPECT().Peerstore().Return(mockPeerstore).Times(2)\n\tmockHost.EXPECT().Connect(gomock.Any(), gomock.Any()).Return(errors.New(\"some error\")).Times(2)\n\tmockPeerstore.EXPECT().AddAddrs(gomock.Any(), gomock.Any(), gomock.Any()).Return().Times(2)\n\n\tt.Run(\"Test_PeersNotConnected\", func(t *testing.T) {\n\t\tmonkey.PatchInstanceMethod(\n\t\t\treflect.TypeOf(routingTable),\n\t\t\t\"Find\",\n\t\t\tfunc(_ *kb.RoutingTable, _ peer.ID) peer.ID {\n\t\t\t\treturn peer.ID(\"\")\n\t\t\t},\n\t\t)\n\t\tmonkey.PatchInstanceMethod(\n\t\t\treflect.TypeOf(ipfsdht),\n\t\t\t\"RoutingTable\",\n\t\t\tfunc(_ *dht.IpfsDHT) *kb.RoutingTable {\n\t\t\t\treturn routingTable\n\t\t\t},\n\t\t)\n\n\t\terr := BootstrapConnect(ctx, mockHost, ipfsdht, peers)\n\t\tassert.NotEqual(t, nil, err)\n\t\tassert.Equal(t, \"failed to bootstrap: some error\", err.Error())\n\t})\n\n}\n"
  },
  {
    "path": "packages/fetchai/connections/p2p_libp2p_client/README.md",
    "content": "# P2P Libp2p Client Connection\n\nA lightweight TCP connection to a libp2p DHT node.\n\nIt allows for using the DHT without having to deploy a node by delegating its communication traffic to an already running DHT node with delegate service enabled.\n\n## Usage\n\nFirst, add the connection to your AEA project: `aea add connection fetchai/p2p_libp2p_client:0.20.6`.\n\nNext, ensure that the connection is properly configured by setting:\n\n- `nodes` to a list of `uri`s, connection will choose the delegate randomly\n- `uri` to the public IP address and port number of the delegate service of a running DHT node, in format `${ip|dns}:${port}`\n"
  },
  {
    "path": "packages/fetchai/connections/p2p_libp2p_client/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Implementation of the libp2p client connection.\"\"\"\n"
  },
  {
    "path": "packages/fetchai/connections/p2p_libp2p_client/connection.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the libp2p client connection.\"\"\"\nimport asyncio\nimport contextlib\nimport hashlib\nimport logging\nimport random\nimport ssl\nfrom asyncio import CancelledError\nfrom asyncio.events import AbstractEventLoop\nfrom asyncio.streams import StreamWriter\nfrom pathlib import Path\nfrom typing import Any, Dict, List, Optional\n\nfrom asn1crypto import x509  # type: ignore\nfrom ecdsa.curves import SECP256k1\nfrom ecdsa.keys import BadSignatureError, VerifyingKey\nfrom ecdsa.util import sigdecode_der\n\nfrom aea.configurations.base import PublicId\nfrom aea.configurations.constants import DEFAULT_LEDGER\nfrom aea.connections.base import Connection, ConnectionStates\nfrom aea.crypto.registries import make_crypto\nfrom aea.exceptions import enforce\nfrom aea.helpers.acn.agent_record import AgentRecord\nfrom aea.helpers.acn.uri import Uri\nfrom aea.helpers.pipe import IPCChannelClient, TCPSocketChannelClient, TCPSocketProtocol\nfrom aea.mail.base import Envelope\n\nfrom packages.fetchai.protocols.acn import acn_pb2\nfrom packages.fetchai.protocols.acn.message import AcnMessage\n\n\ntry:\n    from asyncio.streams import IncompleteReadError  # pylint: disable=ungrouped-imports\nexcept ImportError:  # pragma: nocover\n    from asyncio import IncompleteReadError  # pylint: disable=ungrouped-imports\n\n\n_default_logger = logging.getLogger(\n    \"aea.packages.fetchai.connections.p2p_libp2p_client\"\n)\n\nPUBLIC_ID = PublicId.from_str(\"fetchai/p2p_libp2p_client:0.20.6\")\n\nSUPPORTED_LEDGER_IDS = [\"fetchai\", \"cosmos\", \"ethereum\"]\n\nPOR_DEFAULT_SERVICE_ID = \"acn\"\n\nACN_CURRENT_VERSION = \"0.1.0\"\n\n\nclass NodeClient:\n    \"\"\"Client to communicate with node using ipc channel(pipe).\"\"\"\n\n    ACN_ACK_TIMEOUT = 5.0\n\n    def __init__(self, pipe: IPCChannelClient, node_por: AgentRecord) -> None:\n        \"\"\"Set node client with pipe.\"\"\"\n        self.pipe = pipe\n        self._wait_status: Optional[asyncio.Future] = None\n        self.agent_record = node_por\n\n    async def wait_for_status(self) -> Any:\n        \"\"\"Get status.\"\"\"\n        if self._wait_status is None:  # pragma: nocover\n            raise ValueError(\"waiter for status not set!\")\n        return await asyncio.wait_for(self._wait_status, timeout=self.ACN_ACK_TIMEOUT)\n\n    @staticmethod\n    def make_acn_envelope_message(envelope: Envelope) -> bytes:\n        \"\"\"Make acn message with envelope in.\"\"\"\n        acn_msg = acn_pb2.AcnMessage()\n        performative = acn_pb2.AcnMessage.Aea_Envelope_Performative()  # type: ignore\n        performative.envelope = envelope.encode()\n        acn_msg.aea_envelope.CopyFrom(performative)  # pylint: disable=no-member\n        buf = acn_msg.SerializeToString()\n        return buf\n\n    async def write_acn_status_ok(self) -> None:\n        \"\"\"Send acn status ok.\"\"\"\n        acn_msg = acn_pb2.AcnMessage()\n        performative = acn_pb2.AcnMessage.Status_Performative()  # type: ignore\n        status = AcnMessage.StatusBody(\n            status_code=AcnMessage.StatusBody.StatusCode.SUCCESS, msgs=[]\n        )\n        AcnMessage.StatusBody.encode(\n            performative.body, status  # pylint: disable=no-member\n        )\n        acn_msg.status.CopyFrom(performative)  # pylint: disable=no-member\n        buf = acn_msg.SerializeToString()\n        await self._write(buf)\n\n    async def write_acn_status_error(\n        self,\n        msg: str,\n        status_code: AcnMessage.StatusBody.StatusCode = AcnMessage.StatusBody.StatusCode.ERROR_GENERIC,  # type: ignore\n    ) -> None:\n        \"\"\"Send acn status error generic.\"\"\"\n        acn_msg = acn_pb2.AcnMessage()\n        performative = acn_pb2.AcnMessage.Status_Performative()  # type: ignore\n        status = AcnMessage.StatusBody(status_code=status_code, msgs=[msg])\n        AcnMessage.StatusBody.encode(\n            performative.body, status  # pylint: disable=no-member\n        )\n        acn_msg.status.CopyFrom(performative)  # pylint: disable=no-member\n\n        buf = acn_msg.SerializeToString()\n\n        await self._write(buf)\n\n    async def connect(self) -> bool:\n        \"\"\"Connect to node with pipe.\"\"\"\n        return await self.pipe.connect()\n\n    async def send_envelope(self, envelope: Envelope) -> None:\n        \"\"\"Send envelope to node.\"\"\"\n        self._wait_status = asyncio.Future()\n        buf = self.make_acn_envelope_message(envelope)\n        await self._write(buf)\n        try:\n            status = await self.wait_for_status()\n            if status.code != int(AcnMessage.StatusBody.StatusCode.SUCCESS):  # type: ignore  # pylint: disable=no-member\n                raise ValueError(  # pragma: nocover\n                    f\"failed to send envelope. got error confirmation: {status}\"\n                )\n        except asyncio.TimeoutError:  # pragma: nocover\n            if not self._wait_status.done():  # pragma: nocover\n                self._wait_status.set_exception(Exception(\"Timeout\"))\n            await asyncio.sleep(0)\n            raise ValueError(\"acn status await timeout!\")\n        finally:\n            self._wait_status = None\n\n    def make_agent_record(self) -> AcnMessage.AgentRecord:  # type: ignore\n        \"\"\"Make acn agent record.\"\"\"\n        agent_record = AcnMessage.AgentRecord(\n            address=self.agent_record.address,\n            public_key=self.agent_record.public_key,\n            peer_public_key=self.agent_record.representative_public_key,\n            signature=self.agent_record.signature,\n            service_id=POR_DEFAULT_SERVICE_ID,\n            ledger_id=self.agent_record.ledger_id,\n        )\n        return agent_record\n\n    async def read_envelope(self) -> Optional[Envelope]:\n        \"\"\"Read envelope from the node.\"\"\"\n        while True:\n            buf = await self._read()\n\n            if not buf:\n                return None\n\n            try:\n                acn_msg = acn_pb2.AcnMessage()\n                acn_msg.ParseFromString(buf)\n\n            except Exception as e:  # pragma: nocover\n                await self.write_acn_status_error(\n                    f\"Failed to parse acn message {e}\",\n                    status_code=AcnMessage.StatusBody.StatusCode.ERROR_DECODE,\n                )\n                raise ValueError(f\"Error parsing acn message: {e}\") from e\n\n            performative = acn_msg.WhichOneof(\"performative\")\n            if performative == \"aea_envelope\":  # pragma: nocover\n                aea_envelope = acn_msg.aea_envelope  # pylint: disable=no-member\n                try:\n                    envelope = Envelope.decode(aea_envelope.envelope)\n                    await self.write_acn_status_ok()\n                    return envelope\n                except Exception as e:\n                    await self.write_acn_status_error(\n                        f\"Failed to decode envelope: {e}\",\n                        status_code=AcnMessage.StatusBody.StatusCode.ERROR_DECODE,\n                    )\n                    raise\n\n            elif performative == \"status\":\n                if self._wait_status is not None:\n                    self._wait_status.set_result(\n                        acn_msg.status.body  # pylint: disable=no-member\n                    )\n            else:  # pragma: nocover\n                await self.write_acn_status_error(\n                    f\"Bad acn message {performative}\",\n                    status_code=AcnMessage.StatusBody.StatusCode.ERROR_UNEXPECTED_PAYLOAD,\n                )\n\n    async def _write(self, data: bytes) -> None:\n        \"\"\"\n        Write to the writer stream.\n\n        :param data: data to write to stream\n        \"\"\"\n        await self.pipe.write(data)\n\n    async def _read(self) -> Optional[bytes]:\n        \"\"\"\n        Read from the reader stream.\n\n        :return: bytes\n        \"\"\"\n        return await self.pipe.read()\n\n    async def register(\n        self,\n    ) -> None:\n        \"\"\"Register agent on the remote node.\"\"\"\n        agent_record = self.make_agent_record()\n        acn_msg = acn_pb2.AcnMessage()\n        performative = acn_pb2.AcnMessage.Register_Performative()  # type: ignore\n        AcnMessage.AgentRecord.encode(\n            performative.record, agent_record  # pylint: disable=no-member\n        )\n        acn_msg.register.CopyFrom(performative)  # pylint: disable=no-member\n\n        buf = acn_msg.SerializeToString()\n        await self._write(buf)\n\n        try:\n            buf = await asyncio.wait_for(self._read(), timeout=self.ACN_ACK_TIMEOUT)\n        except ConnectionError as e:  # pragma: nocover\n            raise e\n        except IncompleteReadError as e:  # pragma: no cover\n            raise e\n\n        if buf is None:  # pragma: nocover\n            raise ConnectionError(\n                \"Error on connection setup. Incoming buffer is empty!\"\n            )\n        acn_msg = acn_pb2.AcnMessage()\n        acn_msg.ParseFromString(buf)\n        performative = acn_msg.WhichOneof(\"performative\")\n        if performative != \"status\":  # pragma: nocover\n            raise Exception(f\"Wrong response message from peer: {performative}\")\n        response = acn_msg.status  # pylint: disable=no-member\n\n        if response.body.code != int(AcnMessage.StatusBody.StatusCode.SUCCESS):  # type: ignore # pylint: disable=no-member\n            raise Exception(  # pragma: nocover\n                \"Registration to peer failed: {}\".format(\n                    AcnMessage.StatusBody.StatusCode(response.body.code)  # type: ignore # pylint: disable=no-member\n                )\n            )\n\n    async def close(self) -> None:\n        \"\"\"Close client and pipe.\"\"\"\n        await self.pipe.close()\n\n\nclass P2PLibp2pClientConnection(Connection):\n    \"\"\"\n    A libp2p client connection.\n\n    Send and receive envelopes to and from agents on the p2p network without deploying a libp2p node.\n    Connect to the libp2p node using traffic delegation service.\n    \"\"\"\n\n    connection_id = PUBLIC_ID\n\n    DEFAULT_CONNECT_RETRIES = 3\n    DEFAULT_TLS_CONNECTION_SIGNATURE_TIMEOUT = 5.0\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"Initialize a libp2p client connection.\"\"\"\n        super().__init__(**kwargs)\n\n        self.tls_connection_signature_timeout = self.configuration.config.get(\n            \"tls_connection_signature_timeout\",\n            self.DEFAULT_TLS_CONNECTION_SIGNATURE_TIMEOUT,\n        )\n        self.connect_retries = self.configuration.config.get(\n            \"connect_retries\", self.DEFAULT_CONNECT_RETRIES\n        )\n        ledger_id = self.configuration.config.get(\"ledger_id\", DEFAULT_LEDGER)\n        if ledger_id not in SUPPORTED_LEDGER_IDS:\n            raise ValueError(  # pragma: nocover\n                \"Ledger id '{}' is not supported. Supported ids: '{}'\".format(\n                    ledger_id, SUPPORTED_LEDGER_IDS\n                )\n            )\n\n        key_file: Optional[str] = self.configuration.config.get(\"tcp_key_file\")\n        nodes: Optional[List[Dict[str, Any]]] = self.configuration.config.get(\"nodes\")\n\n        if nodes is None:\n            raise ValueError(\"At least one node should be provided\")\n        nodes = list(nodes)\n\n        nodes_uris = [node.get(\"uri\", None) for node in nodes]\n        enforce(\n            len(nodes_uris) == len(nodes) and None not in nodes_uris,\n            \"Delegate 'uri' should be provided for each node\",\n        )\n\n        nodes_public_keys = [node.get(\"public_key\", None) for node in nodes]\n        enforce(\n            len(nodes_public_keys) == len(nodes) and None not in nodes_public_keys,\n            \"Delegate 'public_key' should be provided for each node\",\n        )\n\n        cert_requests = self.configuration.cert_requests\n        if cert_requests is None or len(cert_requests) != len(nodes):\n            raise ValueError(  # pragma: nocover\n                \"cert_requests field must be set and contain exactly as many entries as 'nodes'!\"\n            )\n        for cert_request in cert_requests:\n            save_path = cert_request.get_absolute_save_path(Path(self.data_dir))\n            if not save_path.is_file():\n                raise Exception(  # pragma: nocover\n                    \"cert_request 'save_path' field is not a file. \"\n                    \"Please ensure that 'issue-certificates' command is called beforehand\"\n                )\n\n        # we cannot use the key from the connection's crypto store as\n        # the key will be used for TLS tcp connection, whereas the\n        # connection's crypto store key is used for PoR\n        if key_file is not None:\n            key = make_crypto(ledger_id, private_key_path=key_file)\n        else:\n            key = make_crypto(ledger_id)\n\n        # client connection id\n        self.key = key\n        self.logger.debug(\"Public key used for TCP: {}\".format(key.public_key))\n\n        # delegate uris\n        self.delegate_uris = [Uri(node_uri) for node_uri in nodes_uris]\n\n        # delegates PoRs\n        self.delegate_pors: List[AgentRecord] = []\n        for i, cert_request in enumerate(cert_requests):\n            agent_record = AgentRecord.from_cert_request(\n                cert_request, self.address, nodes_public_keys[i], self.data_dir\n            )\n            self.delegate_pors.append(agent_record)\n\n        # select a delegate\n        index = random.randint(0, len(self.delegate_uris) - 1)  # nosec\n        self.node_uri = self.delegate_uris[index]\n        self.node_por = self.delegate_pors[index]\n        self.logger.debug(\"Node to use as delegate: {}\".format(self.node_uri))\n\n        self._in_queue = None  # type: Optional[asyncio.Queue]\n        self._process_messages_task = None  # type: Optional[asyncio.Future]\n        self._node_client: Optional[NodeClient] = None\n\n        self._send_queue: Optional[asyncio.Queue] = None\n        self._send_task: Optional[asyncio.Task] = None\n\n    async def _send_loop(self) -> None:\n        \"\"\"Handle message in  the send queue.\"\"\"\n\n        if not self._send_queue or not self._node_client:  # pragma: nocover\n            self.logger.error(\"Send loop not started cause not connected properly.\")\n            return\n        try:\n            while self.is_connected:\n                envelope = await self._send_queue.get()\n                await self._send_envelope_with_node_client(envelope)\n        except asyncio.CancelledError:  # pylint: disable=try-except-raise\n            raise  # pragma: nocover\n        except Exception:  # pylint: disable=broad-except # pragma: nocover\n            self.logger.exception(\n                f\"Failed to send an envelope {envelope}. Stop connection.\"\n            )\n            await asyncio.shield(self.disconnect())\n\n    async def _send_envelope_with_node_client(self, envelope: Envelope) -> None:\n        \"\"\"Send envelope with node client, reconnect and retry on fail.\"\"\"\n        if not self._node_client:  # pragma: nocover\n            raise ValueError(\"Connection not connected to node!\")\n\n        self._ensure_valid_envelope_for_external_comms(envelope)\n        try:\n            await self._node_client.send_envelope(envelope)\n        except Exception:  # pylint: disable=broad-except\n            self.logger.exception(\n                \"Exception raised on message send. Try reconnect and send again.\"\n            )\n            await self._perform_connection_to_node()\n            await self._node_client.send_envelope(envelope)\n\n    async def connect(self) -> None:\n        \"\"\"Set up the connection.\"\"\"\n        if self.is_connected:  # pragma: nocover\n            return\n\n        with self._connect_context():\n            # connect libp2p client\n\n            await self._perform_connection_to_node()\n            # start receiving msgs\n            self._in_queue = asyncio.Queue()\n            self._process_messages_task = asyncio.ensure_future(\n                self._process_messages(), loop=self.loop\n            )\n            self._send_queue = asyncio.Queue()\n            self._send_task = self.loop.create_task(self._send_loop())\n\n    async def _perform_connection_to_node(self) -> None:\n        \"\"\"Connect to node with retries.\"\"\"\n        for attempt in range(self.connect_retries):\n            if self.state not in [\n                ConnectionStates.connecting,\n                ConnectionStates.connected,\n            ]:\n                # do nothing if disconnected, or disconnecting\n                return  # pragma: nocover\n            try:\n                self.logger.info(\n                    \"Connecting to libp2p node {}. Attempt {}\".format(\n                        str(self.node_uri), attempt + 1\n                    )\n                )\n                pipe = TCPSocketChannelClientTLS(\n                    f\"{self.node_uri.host}:{self.node_uri._port}\",  # pylint: disable=protected-access\n                    \"\",\n                    server_pub_key=self.node_por.representative_public_key,\n                    verification_signature_wait_timeout=self.tls_connection_signature_timeout,\n                )\n                if not await pipe.connect():\n                    raise ValueError(\n                        f\"Pipe connection error: {pipe.last_exception or ''}\"\n                    )\n\n                self._node_client = NodeClient(pipe, self.node_por)\n                await self._setup_connection()\n\n                self.logger.info(\n                    \"Successfully connected to libp2p node {}\".format(\n                        str(self.node_uri)\n                    )\n                )\n                return\n            except Exception as e:  # pylint: disable=broad-except\n                if attempt == self.connect_retries - 1:\n                    self.logger.error(\n                        \"Connection to  libp2p node {} failed: error: {}. It was the last attempt, exception will be raised\".format(\n                            str(self.node_uri), str(e)\n                        )\n                    )\n                    self.state = ConnectionStates.disconnected\n                    raise\n                sleep_time = attempt * 2 + 1\n                self.logger.error(\n                    \"Connection to  libp2p node {} failed: error: {}. Another attempt will be performed in {} seconds\".format(\n                        str(self.node_uri), str(e), sleep_time\n                    )\n                )\n                await asyncio.sleep(sleep_time)\n\n    async def _setup_connection(self) -> None:\n        \"\"\"Set up connection to node over tcp connection.\"\"\"\n        if not self._node_client:  # pragma: nocover\n            raise ValueError(\"Connection was not connected!\")\n\n        await self._node_client.register()\n\n    async def disconnect(self) -> None:\n        \"\"\"Disconnect from the channel.\"\"\"\n        if self.is_disconnected:  # pragma: nocover\n            return\n\n        self.state = ConnectionStates.disconnecting\n        self.logger.debug(\"disconnecting libp2p client connection...\")\n\n        if self._process_messages_task is not None:\n            if not self._process_messages_task.done():\n                self._process_messages_task.cancel()\n            self._process_messages_task = None\n\n        if self._send_task is not None:\n            if not self._send_task.done():\n                self._send_task.cancel()\n            self._send_task = None\n\n        try:\n            self.logger.debug(\"disconnecting libp2p node client connection...\")\n            if self._node_client is not None:\n                await self._node_client.close()\n        except Exception:  # pragma: nocover  # pylint:disable=broad-except\n            self.logger.exception(\"exception on node client close\")\n            raise\n        finally:\n            # set disconnected state anyway\n            if self._in_queue is not None:\n                self._in_queue.put_nowait(None)\n\n            self.state = ConnectionStates.disconnected\n            self.logger.debug(\"libp2p client connection disconnected.\")\n\n    async def receive(self, *args: Any, **kwargs: Any) -> Optional[\"Envelope\"]:\n        \"\"\"\n        Receive an envelope. Blocking.\n\n        :param args: positional arguments\n        :param kwargs: keyword arguments\n        :return: the envelope received, or None.\n        \"\"\"\n        try:\n            if self._in_queue is None:\n                raise ValueError(\"Input queue not initialized.\")  # pragma: nocover\n            envelope = await self._in_queue.get()\n            if envelope is None:  # pragma: no cover\n                self.logger.debug(\"Received None.\")\n                return None\n            self.logger.debug(\"Received envelope: {}\".format(envelope))\n            return envelope\n        except CancelledError:  # pragma: no cover\n            self.logger.debug(\"Receive cancelled.\")\n            return None\n        except Exception as e:  # pragma: no cover # pylint: disable=broad-except\n            self.logger.exception(e)\n            return None\n\n    async def send(self, envelope: Envelope) -> None:\n        \"\"\"\n        Send messages.\n\n        :param envelope: the envelope\n        \"\"\"\n        if not self._node_client or not self._send_queue:\n            raise ValueError(\"Node is not connected!\")  # pragma: nocover\n\n        self._ensure_valid_envelope_for_external_comms(envelope)\n        await self._send_queue.put(envelope)\n\n    async def _read_envelope_from_node(self) -> Optional[Envelope]:\n        \"\"\"Read envelope from node, reconnec on error.\"\"\"\n        if not self._node_client:  # pragma: nocover\n            raise ValueError(\"Connection not connected to node!\")\n\n        try:\n            self.logger.debug(\"Waiting for messages...\")\n            envelope = await self._node_client.read_envelope()\n            return envelope\n        except ConnectionError as e:  # pragma: nocover\n            self.logger.error(f\"Connection error: {e}. Try to reconnect and read again\")\n        except IncompleteReadError as e:  # pragma: no cover\n            self.logger.error(\n                \"Connection disconnected while reading from node ({}/{})\".format(\n                    len(e.partial), e.expected\n                )\n            )\n        except Exception as e:  # pylint: disable=broad-except  # pragma: nocover\n            self.logger.exception(f\"On envelope read: {e}\")\n\n        try:\n            self.logger.debug(\"Read envelope retry! Reconnect first!\")\n            await self._perform_connection_to_node()\n            envelope = await self._node_client.read_envelope()\n            return envelope\n        except Exception:  # pragma: no cover  # pylint: disable=broad-except\n            self.logger.exception(\"Failed to read with reconnect!\")\n            return None\n\n    async def _process_messages(self) -> None:\n        \"\"\"Receive data from node.\"\"\"\n        if not self._node_client:  # pragma: nocover\n            raise ValueError(\"Connection not connected to node!\")\n\n        while True:\n            envelope = await self._read_envelope_from_node()\n            if self._in_queue is None:\n                raise ValueError(\"Input queue not initialized.\")  # pragma: nocover\n            self._in_queue.put_nowait(envelope)\n            if envelope is None:\n                break  # pragma: no cover\n\n\nclass TCPSocketChannelClientTLS(TCPSocketChannelClient):\n    \"\"\"Interprocess communication channel client using tcp sockets with TLS.\"\"\"\n\n    DEFAULT_VERIFICATION_SIGNATURE_WAIT_TIMEOUT = 5.0\n\n    def __init__(\n        self,\n        in_path: str,\n        out_path: str,\n        server_pub_key: str,\n        logger: logging.Logger = _default_logger,\n        loop: Optional[AbstractEventLoop] = None,\n        verification_signature_wait_timeout: Optional[float] = None,\n    ) -> None:\n        \"\"\"\n        Initialize a tcp socket communication channel client.\n\n        :param in_path: rendezvous point for incoming data\n        :param out_path: rendezvous point for outgoing data\n        :param server_pub_key: str, server public key to verify identity\n        :param logger: the logger\n        :param loop: the event loop\n        :param verification_signature_wait_timeout: optional float, if not provided, default value will be used\n        \"\"\"\n        super().__init__(in_path, out_path, logger, loop)\n        self.verification_signature_wait_timeout = (\n            self.DEFAULT_VERIFICATION_SIGNATURE_WAIT_TIMEOUT\n            if verification_signature_wait_timeout is None\n            else verification_signature_wait_timeout\n        )\n        self.server_pub_key = server_pub_key\n\n    @staticmethod\n    def _get_session_pub_key(writer: StreamWriter) -> bytes:  # pragma: nocover\n        \"\"\"Get session public key from tls stream writer.\"\"\"\n        cert_data = writer.get_extra_info(\"ssl_object\").getpeercert(binary_form=True)\n\n        cert = x509.Certificate.load(cert_data)\n        session_pub_key = VerifyingKey.from_der(cert.public_key.dump()).to_string(\n            \"uncompressed\"\n        )\n        return session_pub_key\n\n    async def _open_connection(self) -> TCPSocketProtocol:\n        \"\"\"Open a connection with TLS support and verify peer.\"\"\"\n        sock = await self._open_tls_connection()\n        session_pub_key = self._get_session_pub_key(sock.writer)\n\n        try:\n            signature = await asyncio.wait_for(\n                sock.read(), timeout=self.verification_signature_wait_timeout\n            )\n        except asyncio.TimeoutError:  # pragma: nocover\n            raise ValueError(\n                f\"Failed to get peer verification record in timeout: {self.verification_signature_wait_timeout}\"\n            )\n\n        if not signature:  # pragma: nocover\n            raise ValueError(\"Unexpected socket read data!\")\n\n        try:\n            self._verify_session_key_signature(signature, session_pub_key)\n        except BadSignatureError as e:  # pragma: nocover\n            with contextlib.suppress(Exception):\n                await sock.close()\n            raise ValueError(f\"Invalid TLS session key signature: {e}\")\n        return sock\n\n    async def _open_tls_connection(self) -> TCPSocketProtocol:\n        \"\"\"Open a connection with TLS support.\"\"\"\n        cadata = await asyncio.get_event_loop().run_in_executor(\n            None, lambda: ssl.get_server_certificate((self._host, self._port))\n        )\n\n        ssl_ctx = ssl.create_default_context(cadata=cadata)\n        ssl_ctx.check_hostname = False\n        ssl_ctx.verify_mode = ssl.CERT_REQUIRED\n        reader, writer = await asyncio.open_connection(\n            self._host,\n            self._port,\n            ssl=ssl_ctx,\n        )\n        return TCPSocketProtocol(reader, writer, logger=self.logger, loop=self._loop)\n\n    def _verify_session_key_signature(\n        self, signature: bytes, session_pub_key: bytes\n    ) -> None:\n        \"\"\"\n        Validate signature of session public key.\n\n        :param signature: bytes, signature of session public key made with server private key\n        :param session_pub_key: session public key to check signature for.\n        \"\"\"\n        vk = VerifyingKey.from_string(bytes.fromhex(self.server_pub_key), SECP256k1)\n        vk.verify(\n            signature, session_pub_key, hashfunc=hashlib.sha256, sigdecode=sigdecode_der\n        )\n"
  },
  {
    "path": "packages/fetchai/connections/p2p_libp2p_client/connection.yaml",
    "content": "name: p2p_libp2p_client\nauthor: fetchai\nversion: 0.20.6\ntype: connection\ndescription: The libp2p client connection implements a tcp connection to a running\n  libp2p node as a traffic delegate to send/receive envelopes to/from agents in the\n  DHT.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: QmSbRjhLF6vhoVugcGKJtT3CD59sSgCPG3NF3rBrS3CG8t\n  __init__.py: QmXwtBAZxhrLXVTU5FYytTxnoh7vScRQBRjtMvFerXH31e\n  connection.py: Qmb2RBaDjdEpM1i8YHYcZQpuPfFcZGPiZ4SdSunejxvfho\nfingerprint_ignore_patterns: []\nconnections: []\nprotocols:\n- fetchai/acn:1.1.7\nclass_name: P2PLibp2pClientConnection\nconfig:\n  connect_retries: 3\n  ledger_id: fetchai\n  nodes:\n  - uri: acn.fetch.ai:11000\n    public_key: 0217a59bd805c310aca4febe0e99ce22ee3712ae085dc1e5630430b1e15a584bb7\n  - uri: acn.fetch.ai:11001\n    public_key: 03fa7cfae1037cba5218f0f5743802eced8de3247c55ecebaae46c7d3679e3f91d\n  tls_connection_signature_timeout: 5.0\ncert_requests:\n- identifier: acn\n  ledger_id: fetchai\n  message_format: '{public_key}'\n  not_after: '2023-01-01'\n  not_before: '2022-01-01'\n  public_key: 0217a59bd805c310aca4febe0e99ce22ee3712ae085dc1e5630430b1e15a584bb7\n  save_path: .certs/acn_fetch_ai_11000.txt\n- identifier: acn\n  ledger_id: fetchai\n  message_format: '{public_key}'\n  not_after: '2023-01-01'\n  not_before: '2022-01-01'\n  public_key: 03fa7cfae1037cba5218f0f5743802eced8de3247c55ecebaae46c7d3679e3f91d\n  save_path: .certs/acn_fetch_ai_11001.txt\nexcluded_protocols: []\nrestricted_to_protocols: []\ndependencies:\n  asn1crypto:\n    version: <1.5.0,>=1.4.0\nis_abstract: false\n"
  },
  {
    "path": "packages/fetchai/connections/p2p_libp2p_mailbox/README.md",
    "content": "# P2P Libp2p Client Connection\n\nA lightweight TCP connection to a libp2p DHT node.\n\nIt allows for using the DHT without having to deploy a node by delegating its communication traffic to an already running DHT node with delegate service enabled.\n\n## Usage\n\nFirst, add the connection to your AEA project: `aea add connection fetchai/p2p_libp2p_client:0.20.6`.\n\nNext, ensure that the connection is properly configured by setting:\n\n- `nodes` to a list of `uri`s, connection will choose the delegate randomly\n- `uri` to the public IP address and port number of the delegate service of a running DHT node, in format `${ip|dns}:${port}`\n"
  },
  {
    "path": "packages/fetchai/connections/p2p_libp2p_mailbox/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Implementation of the libp2p client connection.\"\"\"\n"
  },
  {
    "path": "packages/fetchai/connections/p2p_libp2p_mailbox/connection.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the libp2p client connection.\"\"\"\nimport asyncio\nimport hashlib\nimport logging\nimport random\nimport re\nimport ssl\nfrom asyncio import CancelledError\nfrom asyncio.streams import StreamWriter\nfrom pathlib import Path\nfrom typing import Any, Dict, List, Optional, Tuple, cast\nfrom urllib.parse import urlparse\n\nimport aiohttp\nfrom aiohttp.client_reqrep import ClientResponse\nfrom asn1crypto import x509  # type: ignore\nfrom ecdsa.curves import SECP256k1\nfrom ecdsa.keys import VerifyingKey\nfrom ecdsa.util import sigdecode_der\n\nfrom aea.configurations.base import PublicId\nfrom aea.configurations.constants import DEFAULT_LEDGER\nfrom aea.connections.base import Connection, ConnectionStates\nfrom aea.crypto.registries import make_crypto\nfrom aea.exceptions import enforce\nfrom aea.helpers.acn.agent_record import AgentRecord\nfrom aea.helpers.acn.uri import Uri\nfrom aea.mail.base import Envelope\n\nfrom packages.fetchai.protocols.acn import acn_pb2\nfrom packages.fetchai.protocols.acn.message import AcnMessage\n\n\ntry:\n    from asyncio.streams import IncompleteReadError  # pylint: disable=ungrouped-imports\nexcept ImportError:  # pragma: nocover\n    from asyncio import IncompleteReadError  # pylint: disable=ungrouped-imports\n\n\n_default_logger = logging.getLogger(\n    \"aea.packages.fetchai.connections.p2p_libp2p_client\"\n)\n\nPUBLIC_ID = PublicId.from_str(\"fetchai/p2p_libp2p_mailbox:0.2.6\")\n\nSUPPORTED_LEDGER_IDS = [\"fetchai\", \"cosmos\", \"ethereum\"]\n\nPOR_DEFAULT_SERVICE_ID = \"acn\"\n\nACN_CURRENT_VERSION = \"0.1.0\"\n\n\nclass NodeClient:\n    \"\"\"Client to communicate with node using ipc channel(pipe).\"\"\"\n\n    NO_ENVELOPES_SLEEP_TIME: float = 2.0\n\n    def __init__(self, node_uri: Uri, node_por: AgentRecord) -> None:\n        \"\"\"Set node client with pipe.\"\"\"\n        self.node_uri = node_uri\n        self.agent_record = node_por\n        self._session_token: Optional[str] = None\n        self.ssl_ctx = Optional[ssl.SSLContext]\n\n    async def connect(self) -> bool:\n        \"\"\"Connect to node with pipe.\"\"\"\n        url = f\"https://{self.node_uri}/ssl_signature\"\n        self.ssl_ctx = await SSLValidator(\n            url, self.agent_record.representative_public_key\n        ).check()\n        await self.register()\n        return True\n\n    async def send_envelope(self, envelope: Envelope) -> None:\n        \"\"\"Send envelope to node.\"\"\"\n        if not self._session_token:  # pragma: nocover\n            raise ValueError(\"not connected!\")\n\n        envelope_data = envelope.encode()\n        # send here\n        response, _ = await self._perform_http_request(\n            method=\"POST\",\n            url=\"/send_envelope\",\n            data=envelope_data,\n            headers={\"Session-Id\": self._session_token},\n        )\n\n        if response.status != 200:  # pragma: nocover\n            text = await response.text()\n            raise ValueError(f\"Bad response code: {response.status} {text}\")\n\n    async def _perform_http_request(\n        self, method: str, url: str, **kwargs: Any\n    ) -> Tuple[ClientResponse, bytes]:\n        async with aiohttp.ClientSession() as session:\n            async with session.request(\n                method, url=f\"https://{self.node_uri}{url}\", ssl=self.ssl_ctx, **kwargs\n            ) as response:\n                data = await response.read()\n                return response, data\n\n    def make_agent_record(self) -> AcnMessage.AgentRecord:  # type: ignore\n        \"\"\"Make acn agent record.\"\"\"\n        agent_record = AcnMessage.AgentRecord(\n            address=self.agent_record.address,\n            public_key=self.agent_record.public_key,\n            peer_public_key=self.agent_record.representative_public_key,\n            signature=self.agent_record.signature,\n            service_id=POR_DEFAULT_SERVICE_ID,\n            ledger_id=self.agent_record.ledger_id,\n        )\n        return agent_record\n\n    async def read_envelope(self) -> Optional[Envelope]:\n        \"\"\"Read envelope from the mailbox node.\"\"\"\n        while True:\n            if not self._session_token:  # pragma: nocover\n                raise ValueError(\"Client not registered!\")\n            response, data = await self._perform_http_request(\n                \"GET\", \"/get_envelope\", headers={\"Session-Id\": self._session_token}\n            )\n            if response.status != 200:  # pragma: nocover\n                raise ValueError(f\"Bad response code: {response.status}\")\n\n            if not data:\n                await asyncio.sleep(self.NO_ENVELOPES_SLEEP_TIME)\n                continue\n\n            envelope = Envelope.decode(data)\n            return envelope\n\n    async def register(self) -> None:\n        \"\"\"Register agent on the remote node.\"\"\"\n        agent_record = self.make_agent_record()\n        performative = acn_pb2.AcnMessage.Register_Performative()  # type: ignore\n        AcnMessage.AgentRecord.encode(\n            performative.record, agent_record  # pylint: disable=no-member\n        )\n        data = performative.record.SerializeToString()  # pylint: disable=no-member\n        response, _ = await self._perform_http_request(\n            \"POST\", url=\"/register\", data=data\n        )\n\n        if response.status != 200:  # pragma: nocover\n            raise ValueError(f\"Bad response code: {response.status}\")\n\n        token = await response.text()\n        if not re.match(\"[0-9a-f]{32}\", token, re.I):  # pragma: nocover\n            raise ValueError(f\"invalid response: {token}\")\n\n        self._session_token = token\n\n    async def close(self) -> None:\n        \"\"\"Close node connection.\"\"\"\n        if not self._session_token:  # pragma: nocover\n            raise ValueError(\"not connected!\")\n\n        response, _ = await self._perform_http_request(\n            \"GET\", \"/unregister\", headers={\"Session-Id\": self._session_token}\n        )\n        if response.status != 200:  # pragma: nocover\n            raise ValueError(f\"Bad response code: {response.status}\")\n\n        self._session_token = None\n\n\nclass P2PLibp2pMailboxConnection(Connection):\n    \"\"\"\n    A libp2p client connection.\n\n    Send and receive envelopes to and from agents on the p2p network without deploying a libp2p node.\n    Connect to the libp2p node using traffic delegation service.\n    \"\"\"\n\n    connection_id = PUBLIC_ID\n\n    DEFAULT_CONNECT_RETRIES = 3\n    DEFAULT_TLS_CONNECTION_SIGNATURE_TIMEOUT = 5.0\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"Initialize a libp2p client connection.\"\"\"\n        super().__init__(**kwargs)\n\n        self.tls_connection_signature_timeout = self.configuration.config.get(\n            \"tls_connection_signature_timeout\",\n            self.DEFAULT_TLS_CONNECTION_SIGNATURE_TIMEOUT,\n        )\n        self.connect_retries = self.configuration.config.get(\n            \"connect_retries\", self.DEFAULT_CONNECT_RETRIES\n        )\n        ledger_id = self.configuration.config.get(\"ledger_id\", DEFAULT_LEDGER)\n        if ledger_id not in SUPPORTED_LEDGER_IDS:\n            raise ValueError(  # pragma: nocover\n                \"Ledger id '{}' is not supported. Supported ids: '{}'\".format(\n                    ledger_id, SUPPORTED_LEDGER_IDS\n                )\n            )\n\n        key_file: Optional[str] = self.configuration.config.get(\"tcp_key_file\")\n        nodes: Optional[List[Dict[str, Any]]] = self.configuration.config.get(\"nodes\")\n\n        if nodes is None:\n            raise ValueError(\"At least one node should be provided\")\n        nodes = list(nodes)\n\n        nodes_uris = [node.get(\"uri\", None) for node in nodes]\n        enforce(\n            len(nodes_uris) == len(nodes) and None not in nodes_uris,\n            \"Delegate 'uri' should be provided for each node\",\n        )\n\n        nodes_public_keys = [node.get(\"public_key\", None) for node in nodes]\n        enforce(\n            len(nodes_public_keys) == len(nodes) and None not in nodes_public_keys,\n            \"Delegate 'public_key' should be provided for each node\",\n        )\n\n        cert_requests = self.configuration.cert_requests\n        if cert_requests is None or len(cert_requests) != len(nodes):\n            raise ValueError(  # pragma: nocover\n                \"cert_requests field must be set and contain exactly as many entries as 'nodes'!\"\n            )\n        for cert_request in cert_requests:\n            save_path = cert_request.get_absolute_save_path(Path(self.data_dir))\n            if not save_path.is_file():\n                raise Exception(  # pragma: nocover\n                    \"cert_request 'save_path' field is not a file. \"\n                    \"Please ensure that 'issue-certificates' command is called beforehand\"\n                )\n\n        # we cannot use the key from the connection's crypto store as\n        # the key will be used for TLS tcp connection, whereas the\n        # connection's crypto store key is used for PoR\n        if key_file is not None:\n            key = make_crypto(ledger_id, private_key_path=key_file)\n        else:\n            key = make_crypto(ledger_id)\n\n        # client connection id\n        self.key = key\n        self.logger.debug(\"Public key used for TCP: {}\".format(key.public_key))\n\n        # delegate uris\n        self.delegate_uris = [Uri(node_uri) for node_uri in nodes_uris]\n\n        # delegates PoRs\n        self.delegate_pors: List[AgentRecord] = []\n        for i, cert_request in enumerate(cert_requests):\n            agent_record = AgentRecord.from_cert_request(\n                cert_request, self.address, nodes_public_keys[i], self.data_dir\n            )\n            self.delegate_pors.append(agent_record)\n\n        # select a delegate\n        index = random.randint(0, len(self.delegate_uris) - 1)  # nosec\n        self.node_uri = self.delegate_uris[index]\n        self.node_por = self.delegate_pors[index]\n        self.logger.debug(\"Node to use as delegate: {}\".format(self.node_uri))\n\n        self._in_queue = None  # type: Optional[asyncio.Queue]\n        self._process_messages_task = None  # type: Optional[asyncio.Future]\n        self._node_client: Optional[NodeClient] = None\n\n        self._send_queue: Optional[asyncio.Queue] = None\n        self._send_task: Optional[asyncio.Task] = None\n\n    async def _send_loop(self) -> None:\n        \"\"\"Handle message in  the send queue.\"\"\"\n\n        if not self._send_queue or not self._node_client:  # pragma: nocover\n            self.logger.error(\"Send loop not started cause not connected properly.\")\n            return\n        try:\n            while self.is_connected:\n                envelope = await self._send_queue.get()\n                await self._send_envelope_with_node_client(envelope)\n        except asyncio.CancelledError:  # pylint: disable=try-except-raise\n            raise  # pragma: nocover\n        except Exception:  # pylint: disable=broad-except # pragma: nocover\n            self.logger.exception(\n                f\"Failed to send an envelope {envelope}. Stop connection.\"\n            )\n            await asyncio.shield(self.disconnect())\n\n    async def _send_envelope_with_node_client(self, envelope: Envelope) -> None:\n        \"\"\"Send envelope with node client, reconnect and retry on fail.\"\"\"\n        if not self._node_client:  # pragma: nocover\n            raise ValueError(\"Connection not connected to node!\")\n\n        self._ensure_valid_envelope_for_external_comms(envelope)\n        try:\n            await self._node_client.send_envelope(envelope)\n        except Exception:  # pylint: disable=broad-except\n            self.logger.exception(\n                \"Exception raised on message send. Try reconnect and send again.\"\n            )\n            await self._perform_connection_to_node()\n            await self._node_client.send_envelope(envelope)\n\n    async def connect(self) -> None:\n        \"\"\"Set up the connection.\"\"\"\n        if self.is_connected:  # pragma: nocover\n            return\n\n        with self._connect_context():\n            # connect libp2p client\n\n            await self._perform_connection_to_node()\n            # start receiving msgs\n            self._in_queue = asyncio.Queue()\n            self._process_messages_task = asyncio.ensure_future(\n                self._process_messages(), loop=self.loop\n            )\n            self._send_queue = asyncio.Queue()\n            self._send_task = self.loop.create_task(self._send_loop())\n\n    async def _perform_connection_to_node(self) -> None:\n        \"\"\"Connect to node with retries.\"\"\"\n        for attempt in range(self.connect_retries):\n            if self.state not in [\n                ConnectionStates.connecting,\n                ConnectionStates.connected,\n            ]:\n                # do nothing if disconnected, or disconnecting\n                return  # pragma: nocover\n            try:\n                self.logger.info(\n                    \"Connecting to libp2p node {}. Attempt {}\".format(\n                        str(self.node_uri), attempt + 1\n                    )\n                )\n                self._node_client = NodeClient(self.node_uri, self.node_por)\n                await self._setup_connection()\n\n                self.logger.info(\n                    \"Successfully connected to libp2p node {}\".format(\n                        str(self.node_uri)\n                    )\n                )\n                return\n            except Exception as e:  # pylint: disable=broad-except\n                if attempt == self.connect_retries - 1:\n                    self.logger.error(\n                        \"Connection to  libp2p node {} failed: error: {}. It was the last attempt, exception will be raised\".format(\n                            str(self.node_uri), str(e)\n                        )\n                    )\n                    self.state = ConnectionStates.disconnected\n                    raise\n                sleep_time = attempt * 2 + 1\n                self.logger.error(\n                    \"Connection to  libp2p node {} failed: error: {}. Another attempt will be performed in {} seconds\".format(\n                        str(self.node_uri), str(e), sleep_time\n                    )\n                )\n                await asyncio.sleep(sleep_time)\n\n    async def _setup_connection(self) -> None:\n        \"\"\"Set up connection to node over tcp connection.\"\"\"\n        if not self._node_client:  # pragma: nocover\n            raise ValueError(\"Connection was not connected!\")\n\n        await self._node_client.connect()\n\n    async def disconnect(self) -> None:\n        \"\"\"Disconnect from the channel.\"\"\"\n        if self.is_disconnected:  # pragma: nocover\n            return\n\n        self.state = ConnectionStates.disconnecting\n        self.logger.debug(\"disconnecting libp2p client connection...\")\n\n        if self._process_messages_task is not None:\n            if not self._process_messages_task.done():\n                self._process_messages_task.cancel()\n            self._process_messages_task = None\n\n        if self._send_task is not None:\n            if not self._send_task.done():\n                self._send_task.cancel()\n            self._send_task = None\n\n        try:\n            self.logger.debug(\"disconnecting libp2p node client connection...\")\n            if self._node_client is not None:\n                await self._node_client.close()\n        except Exception:  # pragma: nocover  # pylint:disable=broad-except\n            self.logger.exception(\"exception on node client close\")\n            raise\n        finally:\n            # set disconnected state anyway\n            if self._in_queue is not None:\n                self._in_queue.put_nowait(None)\n\n            self.state = ConnectionStates.disconnected\n            self.logger.debug(\"libp2p client connection disconnected.\")\n\n    async def receive(self, *args: Any, **kwargs: Any) -> Optional[\"Envelope\"]:\n        \"\"\"\n        Receive an envelope. Blocking.\n\n        :param args: positional arguments\n        :param kwargs: keyword arguments\n        :return: the envelope received, or None.\n        \"\"\"\n        try:\n            if self._in_queue is None:\n                raise ValueError(\"Input queue not initialized.\")  # pragma: nocover\n            envelope = await self._in_queue.get()\n            if envelope is None:  # pragma: no cover\n                self.logger.debug(\"Received None.\")\n                return None\n            self.logger.debug(\"Received envelope: {}\".format(envelope))\n            return envelope\n        except CancelledError:  # pragma: no cover\n            self.logger.debug(\"Receive cancelled.\")\n            return None\n        except Exception as e:  # pragma: no cover # pylint: disable=broad-except\n            self.logger.exception(e)\n            return None\n\n    async def send(self, envelope: Envelope) -> None:\n        \"\"\"\n        Send messages.\n\n        :param envelope: the envelope\n        \"\"\"\n        if not self._node_client or not self._send_queue:\n            raise ValueError(\"Node is not connected!\")  # pragma: nocover\n\n        self._ensure_valid_envelope_for_external_comms(envelope)\n        await self._send_queue.put(envelope)\n\n    async def _read_envelope_from_node(self) -> Optional[Envelope]:\n        \"\"\"Read envelope from node, reconnec on error.\"\"\"\n        if not self._node_client:  # pragma: nocover\n            raise ValueError(\"Connection not connected to node!\")\n\n        try:\n            self.logger.debug(\"Waiting for messages...\")\n            envelope = await self._node_client.read_envelope()\n            return envelope\n        except ConnectionError as e:  # pragma: nocover\n            self.logger.error(f\"Connection error: {e}. Try to reconnect and read again\")\n        except IncompleteReadError as e:  # pragma: no cover\n            self.logger.error(\n                \"Connection disconnected while reading from node ({}/{})\".format(\n                    len(e.partial), e.expected\n                )\n            )\n        except Exception as e:  # pylint: disable=broad-except  # pragma: nocover\n            self.logger.exception(f\"On envelope read: {e}\")\n\n        try:\n            self.logger.debug(\"Read envelope retry! Reconnect first!\")\n            await self._perform_connection_to_node()\n            envelope = await self._node_client.read_envelope()\n            return envelope  # pragma: no cover\n        except Exception:  # pragma: no cover  # pylint: disable=broad-except\n            self.logger.exception(\"Failed to read with reconnect!\")\n            return None\n\n    async def _process_messages(self) -> None:\n        \"\"\"Receive data from node.\"\"\"\n        if not self._node_client:  # pragma: nocover\n            raise ValueError(\"Connection not connected to node!\")\n\n        while True:\n            envelope = await self._read_envelope_from_node()\n            if self._in_queue is None:\n                raise ValueError(\"Input queue not initialized.\")  # pragma: nocover\n            self._in_queue.put_nowait(envelope)\n            if envelope is None:\n                break  # pragma: no cover\n\n\nclass SSLValidator:\n    \"\"\"Interprocess communication channel client using tcp sockets with TLS.\"\"\"\n\n    def __init__(\n        self,\n        url: str,\n        server_pub_key: str,\n        logger: logging.Logger = _default_logger,\n    ) -> None:\n        \"\"\"\n        Check ssl certificate with server pub key.\n\n        :param url: url to get signature\n        :param server_pub_key: str, server public key to verify identity\n        :param logger: the logger\n        \"\"\"\n        self.server_pub_key = server_pub_key\n        o = urlparse(url)\n        self.url = url\n        self.logger = logger\n        self.host: str = cast(str, o.hostname)\n        self.port: int = cast(int, o.port)\n\n    async def check(self) -> ssl.SSLContext:\n        \"\"\"Check ssl/pubkey for mailbox service and return ssl context.\"\"\"\n        ssl_ctx, session_pub_key = await self.get_ssl_ctx_and_session_pub_key(\n            self.host, self.port\n        )\n        signature = await self.get_signature(ssl_ctx)\n        self._verify_session_key_signature(\n            self.server_pub_key, signature, session_pub_key\n        )\n        return ssl_ctx\n\n    async def get_signature(self, ssl_ctx: ssl.SSLContext) -> bytes:\n        \"\"\"\n        Get signature for mailbox service (ssl pubkey signed with node private key).\n\n        :param ssl_ctx: ssl context.\n\n        :return: signature in bytes\n        \"\"\"\n        async with aiohttp.ClientSession() as client:\n            async with client.get(self.url, ssl=ssl_ctx) as resp:\n                if resp.status != 200:  # pragma: nocover\n                    raise ValueError(\"Bad server response\")\n                signature = await resp.read()\n        return signature\n\n    @staticmethod\n    def _get_session_pub_key(writer: StreamWriter) -> bytes:  # pragma: nocover\n        \"\"\"Get session public key from tls stream writer.\"\"\"\n        cert_data = writer.get_extra_info(\"ssl_object\").getpeercert(binary_form=True)\n\n        cert = x509.Certificate.load(cert_data)\n        session_pub_key = VerifyingKey.from_der(cert.public_key.dump()).to_string(\n            \"uncompressed\"\n        )\n        return session_pub_key\n\n    async def get_ssl_ctx_and_session_pub_key(\n        self, host: str, port: int\n    ) -> Tuple[ssl.SSLContext, bytes]:\n        \"\"\"Open a connection with TLS support.\"\"\"\n        cadata = await asyncio.get_event_loop().run_in_executor(\n            None, lambda: ssl.get_server_certificate((host, port))\n        )\n\n        ssl_ctx = ssl.create_default_context(cadata=cadata)\n        ssl_ctx.check_hostname = False\n        ssl_ctx.verify_mode = ssl.CERT_REQUIRED\n        _, writer = await asyncio.open_connection(\n            self.host,\n            self.port,\n            ssl=ssl_ctx,\n        )\n        session_pub_key = self._get_session_pub_key(writer)\n        writer.close()\n        return ssl_ctx, session_pub_key\n\n    @staticmethod\n    def _verify_session_key_signature(\n        server_pub_key: str, signature: bytes, session_pub_key: bytes\n    ) -> None:\n        \"\"\"\n        Validate signature of session public key.\n\n        :param server_pub_key: node pub key/addr.\n        :param signature: bytes, signature of session public key made with server private key\n        :param session_pub_key: session public key to check signature for.\n        \"\"\"\n        vk = VerifyingKey.from_string(bytes.fromhex(server_pub_key), SECP256k1)\n        vk.verify(\n            signature, session_pub_key, hashfunc=hashlib.sha256, sigdecode=sigdecode_der\n        )\n"
  },
  {
    "path": "packages/fetchai/connections/p2p_libp2p_mailbox/connection.yaml",
    "content": "name: p2p_libp2p_mailbox\nauthor: fetchai\nversion: 0.2.6\ntype: connection\ndescription: The libp2p client connection implements a tcp connection to a running\n  libp2p node as a traffic delegate to send/receive envelopes to/from agents in the\n  DHT.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: QmSbRjhLF6vhoVugcGKJtT3CD59sSgCPG3NF3rBrS3CG8t\n  __init__.py: QmXwtBAZxhrLXVTU5FYytTxnoh7vScRQBRjtMvFerXH31e\n  connection.py: QmStAHydBBs2De2oAnjspoNi56cDuKMAdyFCsjsK6PBHfa\nfingerprint_ignore_patterns: []\nconnections: []\nprotocols:\n- fetchai/acn:1.1.7\nclass_name: P2PLibp2pMailboxConnection\nconfig:\n  connect_retries: 3\n  ledger_id: fetchai\n  nodes:\n  - uri: acn.fetch.ai:8888\n    public_key: 0217a59bd805c310aca4febe0e99ce22ee3712ae085dc1e5630430b1e15a584bb7\n  tls_connection_signature_timeout: 5.0\ncert_requests:\n- identifier: acn\n  ledger_id: fetchai\n  message_format: '{public_key}'\n  not_after: '2023-01-01'\n  not_before: '2022-01-01'\n  public_key: 0217a59bd805c310aca4febe0e99ce22ee3712ae085dc1e5630430b1e15a584bb7\n  save_path: .certs/acn_fetch_ai_11000.txt\n- identifier: acn\n  ledger_id: fetchai\n  message_format: '{public_key}'\n  not_after: '2023-01-01'\n  not_before: '2022-01-01'\n  public_key: 03fa7cfae1037cba5218f0f5743802eced8de3247c55ecebaae46c7d3679e3f91d\n  save_path: .certs/acn_fetch_ai_11001.txt\nexcluded_protocols: []\nrestricted_to_protocols: []\ndependencies:\n  aiohttp:\n    version: <3.8,>=3.7.4\n  asn1crypto:\n    version: <1.5.0,>=1.4.0\nis_abstract: false\n"
  },
  {
    "path": "packages/fetchai/connections/p2p_stub/README.md",
    "content": "# P2P stub connection\n\nSimple file based connection to perform interaction between multiple local agents.\n\n## Usage\n\nFirst, add the connection to your AEA project: `aea add connection fetchai/p2p_stub:0.18.3`.\n\nOptionally, in the `connection.yaml` file under `config` set the `namespace_dir` to the desired file path. The `p2p_stub` connection reads encoded envelopes from its input file and writes encoded envelopes to its output file. Multiple agents can be pointed to the same `namespace_dir` and are then able to exchange envelopes via the file system.\n"
  },
  {
    "path": "packages/fetchai/connections/p2p_stub/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Implementation of the P2P stub connection.\"\"\"\n"
  },
  {
    "path": "packages/fetchai/connections/p2p_stub/connection.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the p2p stub connection.\"\"\"\n\nimport os\nimport tempfile\nfrom pathlib import Path\nfrom typing import Any, Union, cast\n\nfrom aea.configurations.base import ConnectionConfig, PublicId\nfrom aea.identity.base import Identity\nfrom aea.mail.base import Envelope\n\nfrom packages.fetchai.connections.stub.connection import StubConnection, write_envelope\n\n\nPUBLIC_ID = PublicId.from_str(\"fetchai/p2p_stub:0.18.3\")\n\n\nclass P2PStubConnection(StubConnection):\n    r\"\"\"A p2p stub connection.\n\n    This connection uses an existing directory as a Rendez-Vous point for agents to communicate locally.\n    Each connected agent will create a file named after its address/identity where it can receive messages.\n\n    The connection detects new messages by watchdogging the input file looking for new lines.\n    \"\"\"\n\n    connection_id = PUBLIC_ID\n\n    def __init__(\n        self, configuration: ConnectionConfig, identity: Identity, **kwargs: Any\n    ) -> None:\n        \"\"\"\n        Initialize a p2p stub connection.\n\n        :param configuration: the connection configuration\n        :param identity: the identity\n        :param kwargs: positional arguments\n        \"\"\"\n        namespace_dir_path = cast(\n            Union[str, Path],\n            configuration.config.get(\"namespace_dir\", tempfile.mkdtemp()),\n        )\n        if namespace_dir_path is None:\n            raise ValueError(\"namespace_dir_path must be set!\")  # pragma: nocover\n        self.namespace = os.path.abspath(namespace_dir_path)\n\n        input_file_path = os.path.join(self.namespace, \"{}.in\".format(identity.address))\n        output_file_path = os.path.join(\n            self.namespace, \"{}.out\".format(identity.address)\n        )\n        configuration.config[\"input_file\"] = input_file_path\n        configuration.config[\"output_file\"] = output_file_path\n        super().__init__(configuration=configuration, identity=identity, **kwargs)\n\n    async def send(self, envelope: Envelope) -> None:\n        \"\"\"\n        Send messages.\n\n        :param envelope: the envelope\n        \"\"\"\n        if self.loop is None:\n            raise ValueError(\"Loop not initialized.\")  # pragma: nocover\n        self._ensure_valid_envelope_for_external_comms(envelope)\n        target_file = Path(os.path.join(self.namespace, \"{}.in\".format(envelope.to)))\n\n        with open(target_file, \"ab\") as file:\n            await self.loop.run_in_executor(\n                self._write_pool, write_envelope, envelope, file\n            )\n\n    async def disconnect(self) -> None:\n        \"\"\"Disconnect the connection.\"\"\"\n        if self.loop is None:\n            raise ValueError(\"Loop not initialized.\")  # pragma: nocover\n        await self.loop.run_in_executor(self._write_pool, self._cleanup)\n        await super().disconnect()\n\n    def _cleanup(self) -> None:\n        try:\n            os.unlink(self.configuration.config[\"input_file\"])\n        except OSError:\n            pass\n        try:\n            os.unlink(self.configuration.config[\"output_file\"])\n        except OSError:\n            pass\n        try:\n            os.rmdir(self.namespace)\n        except OSError:\n            pass\n"
  },
  {
    "path": "packages/fetchai/connections/p2p_stub/connection.yaml",
    "content": "name: p2p_stub\nauthor: fetchai\nversion: 0.18.3\ntype: connection\ndescription: The stub p2p connection implements a local p2p connection allowing agents\n  to communicate with each other through files created in the namespace directory.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: QmRsMvDbqtD1Hwdjr6H6ypRLuWmyUwT7ZJxj6Taq7VYM28\n  __init__.py: QmTEHNj5MHXKyboUYrPr2FEpFH2rDgFPasLGViZJg6GuS3\n  connection.py: QmfHu2JX3ksGkFvcwQiXfASvrp7RZ8bzoKDdYNYU11XfuV\nfingerprint_ignore_patterns: []\nconnections:\n- fetchai/stub:0.21.3\nprotocols: []\nclass_name: P2PStubConnection\nconfig:\n  namespace_dir: /tmp/\nexcluded_protocols: []\nrestricted_to_protocols: []\ndependencies:\n  watchdog: {}\nis_abstract: false\n"
  },
  {
    "path": "packages/fetchai/connections/prometheus/README.md",
    "content": "# Prometheus connection\n\nAEAs can create and update prometheus metrics for remote monitoring by sending messages to the prometheus connection.\n\n## Usage\n\nFirst, add the connection to your AEA project (`aea add connection fetchai/prometheus:0.9.6`). Then, add the protocol (`aea add protocol fetchai/prometheus:1.1.7`) to your project. The default port (`9090`) to expose metrics can be changed to `PORT` by updating the `config` at the agent level (`aea config set --type=int vendor.fetchai.connections.prometheus.config.port PORT`).\n"
  },
  {
    "path": "packages/fetchai/connections/prometheus/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Implementation of the Prometheus connection.\"\"\"\n"
  },
  {
    "path": "packages/fetchai/connections/prometheus/connection.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Prometheus connection and channel.\"\"\"\n\nimport asyncio\nimport logging\nfrom typing import Any, Dict, Optional, Tuple, Union, cast\n\nimport aioprometheus  # type: ignore\n\nfrom aea.common import Address\nfrom aea.configurations.base import PublicId\nfrom aea.connections.base import Connection, ConnectionStates\nfrom aea.exceptions import enforce\nfrom aea.mail.base import Envelope, Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\n\nfrom packages.fetchai.protocols.prometheus.dialogues import PrometheusDialogue\nfrom packages.fetchai.protocols.prometheus.dialogues import (\n    PrometheusDialogues as BasePrometheusDialogues,\n)\nfrom packages.fetchai.protocols.prometheus.message import PrometheusMessage\n\n\nPUBLIC_ID = PublicId.from_str(\"fetchai/prometheus:0.9.6\")\n\nDEFAULT_HOST = \"127.0.0.1\"\nDEFAULT_PORT = 9090\nVALID_UPDATE_FUNCS = {\"inc\", \"dec\", \"add\", \"sub\", \"set\", \"observe\"}\nVALID_METRIC_TYPES = {\"Counter\", \"Gauge\", \"Histogram\", \"Summary\"}\n\n\nclass PrometheusDialogues(BasePrometheusDialogues):\n    \"\"\"The dialogues class keeps track of all prometheus dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            # The server connection maintains the dialogue on behalf of the agent\n            return PrometheusDialogue.Role.SERVER\n\n        BasePrometheusDialogues.__init__(\n            self,\n            self_address=str(PUBLIC_ID),\n            role_from_first_message=role_from_first_message,\n            **kwargs,\n        )\n\n\nclass PrometheusChannel:\n    \"\"\"A wrapper for interacting with a prometheus server.\"\"\"\n\n    def __init__(\n        self,\n        address: Address,\n        host: str,\n        port: int,\n        logger: Union[logging.Logger, logging.LoggerAdapter],\n    ):\n        \"\"\"\n        Initialize a prometheus channel.\n\n        :param address: The address of the connection.\n        :param host: The host at which to expose the metrics.\n        :param port: The port at which to expose the metrics.\n        :param logger: The logger.\n        \"\"\"\n        self.address = address\n        self.metrics = {}  # type: Dict[str, aioprometheus.Collector]\n        self.logger = logger\n        self._loop: Optional[asyncio.AbstractEventLoop] = None\n        self._queue: Optional[asyncio.Queue] = None\n        self._dialogues = PrometheusDialogues()\n        self._host = host\n        self._port = port\n        self._service = aioprometheus.Service()\n\n    def _get_message_and_dialogue(\n        self, envelope: Envelope\n    ) -> Tuple[PrometheusMessage, Optional[PrometheusDialogue]]:\n        \"\"\"\n        Get a message copy and dialogue related to this message.\n\n        :param envelope: incoming envelope\n\n        :return: Tuple[Message, Optional[Dialogue]]\n        \"\"\"\n        message = cast(PrometheusMessage, envelope.message)\n        dialogue = cast(Optional[PrometheusDialogue], self._dialogues.update(message))\n        return message, dialogue\n\n    @property\n    def queue(self) -> asyncio.Queue:\n        \"\"\"Check queue is set and return queue.\"\"\"\n        if self._queue is None:  # pragma: nocover\n            raise ValueError(\"Channel is not connected\")\n        return self._queue\n\n    async def connect(self) -> None:\n        \"\"\"Start prometheus http server.\"\"\"\n        if self._queue:  # pragma: nocover\n            return None\n        self._loop = asyncio.get_event_loop()\n        self._queue = asyncio.Queue()\n        await self._service.start(addr=self._host, port=self._port)\n\n    async def send(self, envelope: Envelope) -> None:\n        \"\"\"\n        Process the envelopes to prometheus.\n\n        :param envelope: envelope\n        \"\"\"\n        sender = envelope.sender\n        self.logger.debug(\"Processing message from {}: {}\".format(sender, envelope))\n        if (\n            envelope.protocol_specification_id\n            != PrometheusMessage.protocol_specification_id\n        ):\n            raise ValueError(\n                f\"Protocol {envelope.protocol_specification_id} is not valid for prometheus.\"\n            )\n        await self._handle_prometheus_message(envelope)\n\n    async def _handle_prometheus_message(self, envelope: Envelope) -> None:\n        \"\"\"\n        Handle messages to prometheus.\n\n        :param envelope: the envelope\n        \"\"\"\n        enforce(\n            isinstance(envelope.message, PrometheusMessage),\n            \"Message not of type PrometheusMessage\",\n        )\n        message, dialogue = self._get_message_and_dialogue(envelope)\n\n        if dialogue is None:\n            self.logger.warning(\n                \"Could not create dialogue from message={}\".format(message)\n            )\n            return\n\n        if message.performative == PrometheusMessage.Performative.ADD_METRIC:\n            response = await self._handle_add_metric(message)\n        elif message.performative == PrometheusMessage.Performative.UPDATE_METRIC:\n            response = await self._handle_update_metric(message)\n        else:  # pragma: nocover\n            self.logger.warning(\"Unrecognized performative for PrometheusMessage\")\n            return\n\n        response_code, response_msg = cast(Tuple[int, str], response)\n\n        msg = dialogue.reply(\n            performative=PrometheusMessage.Performative.RESPONSE,\n            target_message=message,\n            code=response_code,\n            message=response_msg,\n        )\n        envelope = Envelope(to=msg.to, sender=msg.sender, message=msg)\n        await self._send(envelope)\n\n    async def _handle_add_metric(self, message: PrometheusMessage) -> Tuple[int, str]:\n        \"\"\"Handle add metric message.\n\n        :param message: the message to handle.\n        :return: the response code and response message.\n        \"\"\"\n        if message.title in self.metrics:\n            response_code = 409\n            response_msg = \"Metric already exists.\"\n        else:\n            metric_type = getattr(aioprometheus, message.type, None)\n            if metric_type is None or message.type not in VALID_METRIC_TYPES:\n                response_code = 404\n                response_msg = f\"{message.type} is not a recognized prometheus metric.\"\n            else:\n                self.metrics[message.title] = metric_type(\n                    message.title, message.description, message.labels\n                )\n                self._service.register(self.metrics[message.title])\n                response_code = 200\n                response_msg = (\n                    f\"New {message.type} successfully added: {message.title}.\"\n                )\n\n        return response_code, response_msg\n\n    async def _handle_update_metric(\n        self, message: PrometheusMessage\n    ) -> Tuple[int, str]:\n        \"\"\"Handle update metric message.\n\n        :param message: the message to handle.\n        :return: the response code and response message.\n        \"\"\"\n        metric = message.title\n        if metric not in self.metrics:\n            response_code = 404\n            response_msg = f\"Metric {metric} not found.\"\n        else:\n            update_func = getattr(self.metrics[metric], message.callable, None)\n            if update_func is None:\n                response_code = 400\n                response_msg = (\n                    f\"Update function {message.callable} not found for metric {metric}.\"\n                )\n            else:\n                if message.callable in VALID_UPDATE_FUNCS:\n                    # Update the metric (\"inc\" and \"dec\" do not take \"value\" argument)\n                    if message.callable in {\"inc\", \"dec\"}:\n                        update_func(message.labels)\n                    else:\n                        update_func(message.labels, message.value)\n                    response_code = 200\n                    response_msg = f\"Metric {metric} successfully updated.\"\n                else:\n                    response_code = 400\n                    response_msg = f\"Failed to update metric {metric}: {message.callable} is not a valid update function.\"\n\n        return response_code, response_msg\n\n    async def _send(self, envelope: Envelope) -> None:\n        \"\"\"Send a message.\n\n        :param envelope: the envelope\n        \"\"\"\n        await self.queue.put(envelope)\n\n    async def disconnect(self) -> None:\n        \"\"\"Disconnect.\"\"\"\n        if self._queue is not None:\n            await self._queue.put(None)\n            self._queue = None\n        await self._service.stop()\n\n    async def get(self) -> Optional[Envelope]:\n        \"\"\"Get incoming envelope.\"\"\"\n        return await self.queue.get()\n\n\nclass PrometheusConnection(Connection):\n    \"\"\"Proxy to the functionality of prometheus.\"\"\"\n\n    connection_id = PUBLIC_ID\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize a connection to a local prometheus server.\n\n        :param kwargs: the keyword arguments of the parent class.\n        \"\"\"\n        super().__init__(**kwargs)\n\n        self.host = cast(str, self.configuration.config.get(\"host\", DEFAULT_HOST))\n        self.port = cast(int, self.configuration.config.get(\"port\", DEFAULT_PORT))\n        self.channel = PrometheusChannel(\n            self.address, self.host, self.port, self.logger\n        )\n\n    async def connect(self) -> None:\n        \"\"\"Connect to prometheus server via prometheus channel.\"\"\"\n        if self.is_connected:  # pragma: nocover\n            return\n\n        with self._connect_context():\n            self.channel.logger = self.logger\n            self.state = ConnectionStates.connecting\n            await self.channel.connect()\n            self.state = ConnectionStates.connected\n\n    async def disconnect(self) -> None:\n        \"\"\"Disconnect from prometheus server.\"\"\"\n        if self.is_disconnected:  # pragma: nocover\n            return\n\n        self.state = ConnectionStates.disconnecting\n        await self.channel.disconnect()\n        self.state = ConnectionStates.disconnected\n\n    async def send(self, envelope: Envelope) -> None:\n        \"\"\"\n        Send an envelope.\n\n        :param envelope: the envelop\n        \"\"\"\n        self._ensure_connected()\n        await self.channel.send(envelope)\n\n    async def receive(self, *args: Any, **kwargs: Any) -> Optional[\"Envelope\"]:\n        \"\"\"\n        Receive an envelope.\n\n        :param args: positional arguments\n        :param kwargs: keyword arguments\n        :return: The received envelope or None\n        \"\"\"\n        self._ensure_connected()\n        try:\n            envelope = await self.channel.get()\n            return envelope\n        except asyncio.CancelledError:  # pragma: no cover\n            return None\n"
  },
  {
    "path": "packages/fetchai/connections/prometheus/connection.yaml",
    "content": "name: prometheus\nauthor: fetchai\nversion: 0.9.6\ntype: connection\ndescription: Connection for exposing agent metrics to prometheus server\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: QmRRMZobBhviy9KjqzJR5NqaL4YaKtE9atwK6Y5mdgZYSM\n  __init__.py: QmW4f9cnBi7hiCqyiNk7Xx4bS1y6yt5B1b64FErHCm8BSA\n  connection.py: QmSXqP7kK42HCoavWUaZHgk7ke3ioaTKQgVFLtCcNpFsPL\nfingerprint_ignore_patterns: []\nconnections: []\nprotocols:\n- fetchai/prometheus:1.1.7\nclass_name: PrometheusConnection\nconfig:\n  host: 127.0.0.1\n  port: 9090\nexcluded_protocols: []\nrestricted_to_protocols:\n- fetchai/prometheus:1.1.7\ndependencies:\n  aioprometheus:\n    version: <21.0.0,>=20.0.0\nis_abstract: false\n"
  },
  {
    "path": "packages/fetchai/connections/soef/README.md",
    "content": "# SOEF connection\n\nThe SOEF connection is used to connect to an SOEF node. The SOEF provides OEF services of register/unregister and search.\n\n## Usage\n\nFirst, add the connection to your AEA project: `aea add connection fetchai/soef:0.27.6`. Then ensure the `config` in `connection.yaml` matches your need. In particular, make sure `chain_identifier` matches your `default_ledger`.\n\nTo register/unregister services and perform searches use the `fetchai/oef_search:1.1.7` protocol\n"
  },
  {
    "path": "packages/fetchai/connections/soef/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Implementation of the Simple OEF connection.\"\"\"\n"
  },
  {
    "path": "packages/fetchai/connections/soef/connection.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Extension to the Simple OEF and OEF Python SDK.\"\"\"\nimport asyncio\nimport copy\nimport logging\nimport os\nimport re\nimport urllib\nfrom asyncio import CancelledError\nfrom concurrent.futures._base import CancelledError as ConcurrentCancelledError\nfrom concurrent.futures.thread import ThreadPoolExecutor\nfrom contextlib import suppress\nfrom enum import Enum\nfrom pathlib import Path\nfrom typing import Any, Callable, Dict, List, Optional, Union, cast\nfrom urllib import parse\nfrom uuid import uuid4\n\nfrom defusedxml import ElementTree  # pylint: disable=wrong-import-order\n\nfrom aea.common import Address, JSONLike\nfrom aea.configurations.base import PublicId\nfrom aea.connections.base import Connection, ConnectionStates\nfrom aea.exceptions import enforce\nfrom aea.helpers import http_requests as requests\nfrom aea.helpers.search.models import (\n    Constraint,\n    ConstraintTypes,\n    Description,\n    Location,\n    Query,\n)\nfrom aea.mail.base import Envelope\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\n\nfrom packages.fetchai.protocols.oef_search.custom_types import (\n    AgentsInfo,\n    OefErrorOperation,\n)\nfrom packages.fetchai.protocols.oef_search.dialogues import (\n    OefSearchDialogue as BaseOefSearchDialogue,\n)\nfrom packages.fetchai.protocols.oef_search.dialogues import (\n    OefSearchDialogues as BaseOefSearchDialogues,\n)\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\n\n\n_default_logger = logging.getLogger(\"aea.packages.fetchai.connections.soef\")\n\nPUBLIC_ID = PublicId.from_str(\"fetchai/soef:0.27.6\")\n\nNOT_SPECIFIED = object()\n\nPERSONALITY_PIECES_KEYS = [\n    \"genus\",\n    \"classification\",\n    \"architecture\",\n    \"dynamics.moving\",\n    \"dynamics.heading\",\n    \"dynamics.position\",\n    \"action.buyer\",\n    \"action.seller\",\n]\n\n\nclass ModelNames(Enum):\n    \"\"\"Enum of supported data models.\"\"\"\n\n    LOCATION_AGENT = \"location_agent\"\n    SET_SERVICE_KEY = \"set_service_key\"\n    REMOVE_SERVICE_KEY = \"remove_service_key\"\n    PERSONALITY_AGENT = \"personality_agent\"\n    SEARCH_MODEL = \"search_model\"\n    PING = \"ping\"\n    GENERIC_COMMAND = \"generic_command\"\n\n\nclass SOEFException(Exception):\n    \"\"\"SOEF channel expected exception.\"\"\"\n\n    @classmethod\n    def warning(\n        cls, msg: str, logger: logging.Logger = _default_logger\n    ) -> \"SOEFException\":  # pragma: no cover\n        \"\"\"Construct exception and write log.\"\"\"\n        logger.warning(msg)\n        return cls(msg)\n\n    @classmethod\n    def debug(\n        cls, msg: str, logger: logging.Logger = _default_logger\n    ) -> \"SOEFException\":  # pragma: no cover\n        \"\"\"Construct exception and write log.\"\"\"\n        logger.debug(msg)\n        return cls(msg)\n\n    @classmethod\n    def error(\n        cls, msg: str, logger: logging.Logger = _default_logger\n    ) -> \"SOEFException\":  # pragma: no cover\n        \"\"\"Construct exception and write log.\"\"\"\n        logger.error(msg)\n        return cls(msg)\n\n    @classmethod\n    def exception(\n        cls, msg: str, logger: logging.Logger = _default_logger\n    ) -> \"SOEFException\":  # pragma: no cover\n        \"\"\"Construct exception and write log.\"\"\"\n        logger.exception(msg)\n        return cls(msg)\n\n\nOefSearchDialogue = BaseOefSearchDialogue\n\n\nclass BaseHandledException(Exception):\n    \"\"\"Base Exception class.\"\"\"\n\n    MSG: str\n\n    def __init__(self, exc: Union[Exception, str]) -> None:\n        \"\"\"Init exception with message or exception instance.\"\"\"\n        super().__init__()\n        self.exc = exc\n\n    def __repr__(self) -> str:\n        \"\"\"Get exception representation.\"\"\"\n        return self.MSG.format(str(self.exc))\n\n    def __str__(self) -> str:\n        \"\"\"Get exception str representation.\"\"\"\n        return self.__repr__()\n\n\nclass SOEFNetworkConnectionError(BaseHandledException):\n    \"\"\"Exception class for network connection errors.\"\"\"\n\n    MSG = \"<SOEF Network Connection Error: {}. Check internet connection!>\"\n\n\nclass SOEFServerBadResponseError(BaseHandledException):\n    \"\"\"Exception class for bad server responses.\"\"\"\n\n    MSG = \"<SOEF Server Bad Response Error: {}.>\"\n\n\nclass OefSearchDialogues(BaseOefSearchDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self) -> None:\n        \"\"\"Initialize dialogues.\"\"\"\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            # The soef connection maintains the dialogue on behalf of the node\n            return OefSearchDialogue.Role.OEF_NODE\n\n        BaseOefSearchDialogues.__init__(\n            self,\n            self_address=str(SOEFConnection.connection_id.to_any()),\n            role_from_first_message=role_from_first_message,\n            dialogue_class=OefSearchDialogue,\n        )\n\n\nclass SOEFChannel:\n    \"\"\"The OEFChannel connects the OEF Agent with the connection.\"\"\"\n\n    DEFAULT_CHAIN_IDENTIFIER = \"fetchai_v2_testnet_stable\"\n\n    SUPPORTED_CHAIN_IDENTIFIERS = [\n        re.compile(\"ethereum\"),\n        re.compile(\"^fetchai(_[a-z0-9_]*)?$\"),\n    ]\n\n    DEFAULT_PERSONALITY_PIECES = [\"architecture,agentframework\"]\n    NONE_UNIQUE_PAGE_ADDRESS = \"\"\n\n    PING_PERIOD = 30 * 60  # 30 minutes\n    FIND_AROUND_ME_REQUEST_DELAY = 2  # seconds\n\n    def __init__(\n        self,\n        address: Address,\n        api_key: str,\n        is_https: bool,\n        soef_addr: str,\n        soef_port: int,\n        data_dir: str,\n        chain_identifier: Optional[str] = None,\n        token_storage_path: Optional[str] = None,\n        logger: logging.Logger = _default_logger,\n        connection_check_timeout: float = 15.0,\n        connection_check_max_retries: int = 3,\n    ):\n        \"\"\"\n        Initialize.\n\n        :param address: the address of the agent.\n        :param api_key: the SOEF API key.\n        :param is_https: whether htts or http is used.\n        :param soef_addr: the SOEF IP address.\n        :param soef_port: the SOEF port.\n        :param data_dir: the data directory.\n        :param chain_identifier: supported chain id.\n        :param token_storage_path: storage path for the SOEF token.\n        :param logger: the logger.\n        :param connection_check_timeout: timeout to check network connection on connect.\n        :param connection_check_max_retries: maximum retries when performing connection check.\n        \"\"\"\n        if chain_identifier is not None and not any(\n            regex.match(chain_identifier) for regex in self.SUPPORTED_CHAIN_IDENTIFIERS\n        ):\n            raise ValueError(\n                f\"Unsupported chain_identifier. Valid identifier regular expressions are {', '.join([reg.pattern for reg in self.SUPPORTED_CHAIN_IDENTIFIERS])}\"\n            )\n\n        self.address = address\n        self.api_key = api_key\n        self.is_https = is_https\n        self.soef_addr = soef_addr\n        self.soef_port = soef_port\n        self.base_url = (\n            f\"https://{soef_addr}:{soef_port}\"\n            if self.is_https\n            else f\"http://{soef_addr}:{soef_port}\"\n        )\n        self.oef_search_dialogues = OefSearchDialogues()\n        self.connection_check_timeout = connection_check_timeout\n        self.connection_check_max_retries = connection_check_max_retries\n\n        self._token_storage_path = token_storage_path\n        if self._token_storage_path is not None:\n            if not Path(self._token_storage_path).is_absolute():\n                self._token_storage_path = os.path.join(\n                    data_dir, self._token_storage_path\n                )\n            Path(self._token_storage_path).touch()\n        self.declared_name = uuid4().hex\n        self._unique_page_address = None  # type: Optional[str]\n        self.agent_location = None  # type: Optional[Location]\n        self.in_queue = None  # type: Optional[asyncio.Queue]\n        self._executor_pool: Optional[ThreadPoolExecutor] = None\n        self.chain_identifier: str = chain_identifier or self.DEFAULT_CHAIN_IDENTIFIER\n        self._loop = None  # type: Optional[asyncio.AbstractEventLoop]\n        self._ping_periodic_task: Optional[asyncio.Task] = None\n        self._find_around_me_queue: Optional[asyncio.Queue] = None\n        self._find_around_me_processor_task: Optional[asyncio.Task] = None\n        self.logger = logger\n        self._unregister_lock: Optional[asyncio.Lock] = None\n\n    @property\n    def unique_page_address(self) -> Optional[str]:\n        \"\"\"Get unique page address.\"\"\"\n        if self._unique_page_address is None:\n            # check if we have it in storage\n            self._unique_page_address = self._get_unique_page_address_from_storage()\n        return self._unique_page_address\n\n    @unique_page_address.setter\n    def unique_page_address(self, unique_page_address: Optional[str]) -> None:\n        \"\"\"Set the unique page address.\"\"\"\n        self._unique_page_address = unique_page_address\n        self._set_unique_page_address_to_storage(unique_page_address)\n\n    def _get_unique_page_address_from_storage(self) -> Optional[str]:\n        \"\"\"Get the unique page address from storage.\"\"\"\n        if self._token_storage_path is None:\n            return None\n        with open(self._token_storage_path, \"r\", encoding=\"utf-8\") as f:\n            result = f.read().strip()\n        unique_page_address = (\n            result if result != self.NONE_UNIQUE_PAGE_ADDRESS else None\n        )\n        return unique_page_address\n\n    def _set_unique_page_address_to_storage(\n        self, unique_page_address: Optional[str]\n    ) -> None:\n        \"\"\"Set the unique page address to storage.\"\"\"\n        if self._token_storage_path is None:\n            return\n        if unique_page_address is None:\n            unique_page_address = self.NONE_UNIQUE_PAGE_ADDRESS\n        with open(self._token_storage_path, \"w\", encoding=\"utf-8\") as f:\n            f.write(unique_page_address)\n\n    async def _find_around_me_processor(self) -> None:\n        \"\"\"Process find me around requests in background task.\"\"\"\n        while self._find_around_me_queue is not None:\n            try:\n                task = await self._find_around_me_queue.get()\n                oef_message, oef_search_dialogue, radius, params = task\n            except (\n                asyncio.CancelledError,\n                CancelledError,\n                GeneratorExit,\n            ):  # pylint: disable=try-except-raise  # pragma: nocover\n                return\n            except Exception:  # pragma: nocover\n                self.logger.exception(\n                    \"Error on reading messages queue for find around me!\"\n                )\n                raise\n\n            try:\n                await self._find_around_me_handle_request(\n                    oef_message, oef_search_dialogue, radius, params\n                )\n                await asyncio.sleep(self.FIND_AROUND_ME_REQUEST_DELAY)\n            except (\n                asyncio.CancelledError,\n                CancelledError,\n                GeneratorExit,\n            ):  # pylint: disable=try-except-raise\n                return\n            except SOEFException:  # pragma: nocover\n                await self._send_error_response(\n                    oef_message,\n                    oef_search_dialogue,\n                    oef_error_operation=OefSearchMessage.OefErrorOperation.OTHER,\n                )\n            except Exception as e:  # pylint: disable=broad-except  # pragma: nocover\n                self.logger.exception(\n                    f\"Exception occurred in  _find_around_me_processor: {e}\"\n                )\n                await self._send_error_response(\n                    oef_message,\n                    oef_search_dialogue,\n                    oef_error_operation=OefSearchMessage.OefErrorOperation.OTHER,\n                )\n            finally:\n                self.logger.debug(\"_find_around_me_processor exited\")\n\n    @property\n    def loop(self) -> asyncio.AbstractEventLoop:\n        \"\"\"Get event loop.\"\"\"\n        if self._loop is None:\n            raise ValueError(\"Loop not set!\")  # pragma: nocover\n        return self._loop\n\n    @staticmethod\n    def _is_compatible_query(query: Query) -> bool:\n        \"\"\"\n        Check if a query is compatible with the soef.\n\n        Each query must contain a distance constraint type.\n\n        :param query: search query to check\n        :return: bool\n        \"\"\"\n        constraints = [c for c in query.constraints if isinstance(c, Constraint)]\n        if len(constraints) == 0:  # pragma: nocover\n            return False\n\n        if ConstraintTypes.DISTANCE not in [\n            c.constraint_type.type for c in constraints\n        ]:  # pragma: nocover\n            return False\n\n        return True\n\n    def _construct_personality_filter_params(\n        self,\n        equality_constraints: List[Constraint],\n    ) -> Dict[str, List[str]]:\n        \"\"\"\n        Construct a dictionary of personality filters.\n\n        :param equality_constraints: list of equality constraints\n        :return: bool\n        \"\"\"\n        filters = copy.copy(self.DEFAULT_PERSONALITY_PIECES)\n\n        for constraint in equality_constraints:\n            if constraint.attribute_name not in PERSONALITY_PIECES_KEYS:\n                continue\n            filters.append(\n                constraint.attribute_name + \",\" + constraint.constraint_type.value\n            )\n        if not filters:  # pragma: nocover\n            return {}\n        return {\"ppfilter\": filters}\n\n    @staticmethod\n    def _construct_service_key_filter_params(\n        equality_constraints: List[Constraint],\n    ) -> Dict[str, List[str]]:\n        \"\"\"\n        Construct a dictionary of service keys filters.\n\n        We assume each equality constraint which is not a personality piece relates to a service key!\n\n        :param equality_constraints: list of equality constraints\n\n        :return: bool\n        \"\"\"\n        filters = []\n\n        for constraint in equality_constraints:\n            if constraint.attribute_name in PERSONALITY_PIECES_KEYS:\n                continue\n            filters.append(\n                constraint.attribute_name + \",\" + constraint.constraint_type.value\n            )\n        if not filters:  # pragma: nocover\n            return {}\n        return {\"skfilter\": filters}\n\n    async def send(self, envelope: Envelope) -> None:\n        \"\"\"\n        Send message handler.\n\n        :param envelope: the envelope.\n        \"\"\"\n        await self.process_envelope(envelope)\n\n    async def _request_text(self, *args: Any, **kwargs: Any) -> str:\n        \"\"\"Perform and http request and return text of response.\"\"\"\n\n        def _do_request() -> requests.Response:\n            return requests.request(*args, **kwargs)\n\n        try:\n            response = await self.loop.run_in_executor(self._executor_pool, _do_request)\n        except requests.ConnectionError as e:\n            raise SOEFNetworkConnectionError(e) from e\n\n        if response.status_code < 200 or response.status_code >= 300:\n            raise SOEFServerBadResponseError(\n                f\"Bad server response: code {response.status_code} when 2XX expected. Request data: ({args}, {kwargs}) Response content: `{response.text}`\"\n            )\n        if not response.text:\n            raise SOEFServerBadResponseError(\n                f\"Bad server response: empty response. Request data: ({args}, {kwargs})\"\n            )\n\n        return response.text\n\n    async def process_envelope(self, envelope: Envelope) -> None:\n        \"\"\"\n        Process envelope.\n\n        :param envelope: the envelope.\n        \"\"\"\n        enforce(\n            isinstance(envelope.message, OefSearchMessage),\n            \"Message not of type OefSearchMessage\",\n        )\n        oef_message = cast(OefSearchMessage, envelope.message)\n        oef_search_dialogue = cast(\n            OefSearchDialogue, self.oef_search_dialogues.update(oef_message)\n        )\n        if oef_search_dialogue is None:  # pragma: nocover\n            raise ValueError(\n                \"Could not create dialogue for message={}\".format(oef_message)\n            )\n\n        err_ops = OefSearchMessage.OefErrorOperation\n        oef_error_operation = err_ops.OTHER\n\n        try:\n            if self.unique_page_address is None:  # pragma: nocover\n                # first time registration or we previously unregistered\n                await self._register_agent()\n\n            handlers_and_errors = {\n                OefSearchMessage.Performative.REGISTER_SERVICE: (\n                    self.register_service,\n                    err_ops.REGISTER_SERVICE,\n                ),\n                OefSearchMessage.Performative.UNREGISTER_SERVICE: (\n                    self.unregister_service,\n                    err_ops.UNREGISTER_SERVICE,\n                ),\n                OefSearchMessage.Performative.SEARCH_SERVICES: (\n                    self.search_services,\n                    err_ops.SEARCH_SERVICES,\n                ),\n            }\n\n            if oef_message.performative not in handlers_and_errors:\n                raise ValueError(\"OEF request not recognized.\")  # pragma: nocover\n\n            handler, oef_error_operation = handlers_and_errors[oef_message.performative]\n            await handler(oef_message, oef_search_dialogue)\n\n        except SOEFException:\n            await self._send_error_response(\n                oef_message,\n                oef_search_dialogue,\n                oef_error_operation=oef_error_operation,\n            )\n        except (asyncio.CancelledError, ConcurrentCancelledError):  # pragma: nocover\n            pass\n        except Exception as e:  # pylint: disable=broad-except # pragma: nocover\n            if \"<reason>Forbidden</reason><detail>already in lobby\" in str(e):\n                raise ValueError(\n                    \"Could not register with SOEF. Agent address already registered from elsewhere.\"\n                )\n            self.logger.exception(f\"Exception during envelope processing: {e}\")\n            await self._send_error_response(\n                oef_message,\n                oef_search_dialogue,\n                oef_error_operation=oef_error_operation,\n            )\n\n    async def register_service(\n        self, oef_message: OefSearchMessage, oef_search_dialogue: OefSearchDialogue\n    ) -> None:\n        \"\"\"\n        Register a service on the SOEF.\n\n        :param oef_message: OefSearchMessage\n        :param oef_search_dialogue: OefSearchDialogue\n        \"\"\"\n        service_description = oef_message.service_description\n\n        data_model_handlers = {\n            \"location_agent\": self._register_location_handler,\n            \"personality_agent\": self._set_personality_piece_handler,\n            \"set_service_key\": self._set_service_key_handler,\n            \"ping\": self._ping_handler,\n            \"generic_command\": self._generic_command_handler,\n        }  # type: Dict[str, Callable]\n        data_model_name = service_description.data_model.name\n\n        if data_model_name not in data_model_handlers:\n            raise SOEFException.error(\n                f'Data model name: {data_model_name} is not supported for `register`. Valid models for performative {oef_message.performative} are: {\", \".join(data_model_handlers.keys())}'\n            )\n\n        handler = data_model_handlers[data_model_name]\n        await handler(service_description, oef_message, oef_search_dialogue)\n\n    async def _ping_handler(\n        self,\n        service_description: Description,\n        oef_message: OefSearchMessage,\n        oef_search_dialogue: OefSearchDialogue,\n    ) -> None:\n        \"\"\"\n        Perform ping command.\n\n        :param service_description: Service description\n        :param oef_message: the oef message.\n        :param oef_search_dialogue: the oef search dialogue\n        \"\"\"\n        self._check_data_model(service_description, ModelNames.PING.value)\n        await self._ping_command()\n        await self._send_success_response(oef_message, oef_search_dialogue)\n\n    async def _generic_command_handler(\n        self,\n        service_description: Description,\n        oef_message: OefSearchMessage,\n        oef_search_dialogue: OefSearchDialogue,\n    ) -> None:\n        \"\"\"\n        Perform ping command.\n\n        :param service_description: Service description\n        :param oef_message: the oef message.\n        :param oef_search_dialogue: the oef search dialogue\n        \"\"\"\n        if not self.in_queue:  # pragma: no cover\n            \"\"\"not connected.\"\"\"\n            return\n\n        self._check_data_model(service_description, ModelNames.GENERIC_COMMAND.value)\n        command = service_description.values.get(\"command\", None)\n        params = service_description.values.get(\"parameters\", {})\n\n        if params:\n            params = urllib.parse.parse_qs(params)\n\n        parsed_text = await self._generic_oef_command(command, params)\n        content = ElementTree.tostring(parsed_text)\n        agents_info: JSONLike = {\n            \"response\": {\"content\": content},\n            \"command\": service_description.values,\n        }\n        await self._send_success_response(oef_message, oef_search_dialogue, agents_info)\n\n    async def _ping_command(self) -> None:\n        \"\"\"Perform ping on registered agent.\"\"\"\n        await self._generic_oef_command(\"ping\", {}, check_success=False)\n\n    async def _ping_periodic(self, period: float = 30 * 60) -> None:\n        \"\"\"\n        Send ping command every `period`.\n\n        :param period: period of ping in seconds\n        \"\"\"\n        with suppress(asyncio.CancelledError):\n            while self.unique_page_address:\n                try:\n                    await self._ping_command()\n                except (\n                    asyncio.CancelledError,\n                    ConcurrentCancelledError,\n                ):  # pragma: nocover  # pylint: disable=try-except-raise\n                    raise\n                except Exception:  # pylint: disable=broad-except  # pragma: nocover\n                    self.logger.exception(\"Error on periodic ping command!\")\n                await asyncio.sleep(period)\n\n    async def _set_service_key_handler(\n        self,\n        service_description: Description,\n        oef_message: OefSearchMessage,\n        oef_search_dialogue: OefSearchDialogue,\n    ) -> None:\n        \"\"\"\n        Set service key from service description.\n\n        :param service_description: Service description\n        :param oef_message: the oef message.\n        :param oef_search_dialogue: the oef search dialogue\n        \"\"\"\n        self._check_data_model(service_description, ModelNames.SET_SERVICE_KEY.value)\n\n        key = service_description.values.get(\"key\", None)\n        value = service_description.values.get(\"value\", NOT_SPECIFIED)\n\n        if key is None or value is NOT_SPECIFIED:  # pragma: nocover\n            raise SOEFException.error(\"Bad values provided!\")\n\n        await self._set_service_key(key, value)\n        await self._send_success_response(oef_message, oef_search_dialogue)\n\n    @staticmethod\n    def _parse_soef_response(\n        response_text: str, check_success: bool = True\n    ) -> ElementTree:\n        try:\n            root = ElementTree.fromstring(response_text)\n        except ElementTree.ParseError as e:  # pragma: nocover\n            raise SOEFServerBadResponseError(\n                f\"Failed to parse xml from the response: Error {e}. Text: {response_text}\"\n            ) from e\n\n        if root.tag != \"response\":\n            raise SOEFServerBadResponseError(\n                \"Not a valid response. Expected `root.tag = response`, received `root.tag = {root.tag}`\"\n            )\n        if check_success:\n            el = root.find(\"./success\")\n            if el is None:\n                raise SOEFServerBadResponseError(\n                    \"Bad response, no success value present. Found = {response_text}.\"\n                )\n            if str(el.text).strip() != \"1\":\n                raise SOEFServerBadResponseError(  # pragma: nocover\n                    \"Request was not successful. Found = {response_text}\"\n                )\n        return root\n\n    async def _generic_oef_command(\n        self,\n        command: str,\n        params: Optional[Dict[str, Union[str, List[str]]]] = None,\n        unique_page_address: Optional[str] = None,\n        check_success: bool = True,\n    ) -> ElementTree:\n        \"\"\"\n        Set service key from service description.\n\n        :param command: the command\n        :param params: the parameters of the command\n        :param unique_page_address: the unique page address\n        :param check_success: whether or not to check for success\n\n        :return: parsed xml ElementTree\n        \"\"\"\n        params = params or {}\n        self.logger.debug(f\"Perform `{command}` with {params}\")\n        url = parse.urljoin(\n            self.base_url, unique_page_address or self.unique_page_address\n        )\n\n        response_text = \"\"\n        try:\n            response_text = await self._request_text(\n                \"get\", url=url, params={\"command\": command, **params}\n            )\n            parsed_text = self._parse_soef_response(response_text, check_success)\n            self.logger.debug(f\"`{command}` SUCCESS!\")\n            return parsed_text\n        except (\n            asyncio.CancelledError,\n            ConcurrentCancelledError,\n        ):  # pragma: nocover  # pylint: disable=try-except-raise\n            raise\n        except Exception as e:\n            raise SOEFException.error(\n                f\"Command: `{command}` Params: `{params}` Response: `{response_text}` Exception: {[e]}\"\n            ) from e\n\n    async def _set_service_key(self, key: str, value: Union[str, int, float]) -> None:\n        \"\"\"\n        Perform set service key command.\n\n        :param key: key to set\n        :param value: value to set\n        \"\"\"\n        await self._generic_oef_command(\n            \"set_service_key\", {\"key\": key, \"value\": str(value)}\n        )\n\n    async def _remove_service_key_handler(\n        self,\n        service_description: Description,\n        oef_message: OefSearchMessage,\n        oef_search_dialogue: OefSearchDialogue,\n    ) -> None:\n        \"\"\"\n        Remove service key from service description.\n\n        :param service_description: Service description\n        :param oef_message: the oef message.\n        :param oef_search_dialogue: the oef search dialogue\n        \"\"\"\n        self._check_data_model(service_description, ModelNames.REMOVE_SERVICE_KEY.value)\n        key = service_description.values.get(\"key\", None)\n\n        if key is None:  # pragma: nocover\n            raise SOEFException.error(\"Bad values provided!\")\n\n        await self._remove_service_key(key)\n        await self._send_success_response(oef_message, oef_search_dialogue)\n\n    async def _remove_service_key(self, key: str) -> None:\n        \"\"\"\n        Perform remove service key command.\n\n        :param key: key to remove\n        \"\"\"\n        await self._generic_oef_command(\"remove_service_key\", {\"key\": key})\n\n    async def _register_location_handler(\n        self,\n        service_description: Description,\n        oef_message: OefSearchMessage,\n        oef_search_dialogue: OefSearchDialogue,\n    ) -> None:\n        \"\"\"\n        Register service with location.\n\n        :param service_description: Service description\n        :param oef_message: the oef message.\n        :param oef_search_dialogue: the oef search dialogue\n        \"\"\"\n        self._check_data_model(service_description, ModelNames.LOCATION_AGENT.value)\n\n        agent_location = service_description.values.get(\"location\", None)\n\n        if agent_location is None or not isinstance(\n            agent_location, Location\n        ):  # pragma: nocover\n            raise SOEFException.debug(\"Bad location provided.\")\n\n        disclosure_accuracy = service_description.values.get(\n            \"disclosure_accuracy\", None\n        )\n\n        if disclosure_accuracy not in [\n            None,\n            \"none\",\n            \"low\",\n            \"medium\",\n            \"high\",\n            \"maximum\",\n        ]:\n            raise SOEFException.debug(\"Bad disclosure_accuracy.\")  # pragma: nocover\n\n        await self._set_location(agent_location, disclosure_accuracy)\n        await self._send_success_response(oef_message, oef_search_dialogue)\n\n    async def _send_success_response(\n        self,\n        oef_message: OefSearchMessage,\n        oef_search_dialogue: OefSearchDialogue,\n        agents_info: Optional[JSONLike] = None,\n    ) -> None:\n        \"\"\"\n        Send success message in response to the given dialogue and message.\n\n        :param oef_search_dialogue: the oef search dialogue\n        :param oef_message: the oef message\n        :param agents_info: the agents info json\n        \"\"\"\n        if self.in_queue is None:\n            raise ValueError(\"Inqueue not set!\")  # pragma: nocover\n        if agents_info is None:\n            agents_info = {}\n        message = oef_search_dialogue.reply(\n            performative=OefSearchMessage.Performative.SUCCESS,\n            target_message=oef_message,\n            agents_info=AgentsInfo(cast(Dict[str, Any], agents_info)),\n        )\n        envelope = Envelope(to=message.to, sender=message.sender, message=message)\n        await self.in_queue.put(envelope)\n\n    @staticmethod\n    def _check_data_model(\n        service_description: Description, data_model_name: str\n    ) -> None:\n        \"\"\"\n        Check data model corresponds.\n\n        Raise exception if not.\n\n        :param service_description: Service description\n        :param data_model_name: data model name expected.\n        \"\"\"\n        if service_description.data_model.name != data_model_name:  # pragma: nocover\n            raise SOEFException.error(\n                f\"Bad service description! expected {data_model_name} but go {service_description.data_model.name}\"\n            )\n\n    async def _set_location(\n        self, agent_location: Location, disclosure_accuracy: Optional[str] = None\n    ) -> None:\n        \"\"\"\n        Set the location.\n\n        :param agent_location: the agent location\n        :param disclosure_accuracy: the accuracy of the agent location disclosure\n        \"\"\"\n        latitude = agent_location.latitude\n        longitude = agent_location.longitude\n        params: Dict[str, Union[str, List[str]]] = {\n            \"longitude\": str(longitude),\n            \"latitude\": str(latitude),\n        }\n        await self._generic_oef_command(\"set_position\", params)\n        if disclosure_accuracy:\n            params = {\"accuracy\": disclosure_accuracy}\n            await self._generic_oef_command(\n                \"set_find_position_disclosure_accuracy\",\n                params,\n            )\n\n        self.agent_location = agent_location\n\n    async def _set_personality_piece_handler(\n        self,\n        service_description: Description,\n        oef_message: OefSearchMessage,\n        oef_search_dialogue: OefSearchDialogue,\n    ) -> None:\n        \"\"\"\n        Set the personality piece.\n\n        :param service_description: the service description.\n        :param oef_message: the oef message.\n        :param oef_search_dialogue: the oef search dialogue\n        \"\"\"\n        self._check_data_model(service_description, ModelNames.PERSONALITY_AGENT.value)\n        piece = service_description.values.get(\"piece\", None)\n        value = service_description.values.get(\"value\", None)\n\n        if not (isinstance(piece, str) and isinstance(value, str)):  # pragma: nocover\n            raise SOEFException.debug(\"Personality piece bad values provided.\")\n\n        await self._set_personality_piece(piece, value)\n        await self._send_success_response(oef_message, oef_search_dialogue)\n\n    async def _set_personality_piece(self, piece: str, value: str) -> None:\n        \"\"\"\n        Set the personality piece.\n\n        :param piece: the piece to be set\n        :param value: the value to be set\n        \"\"\"\n        params: Dict[str, Union[str, List[str]]] = {\n            \"piece\": piece,\n            \"value\": value,\n        }\n        await self._generic_oef_command(\"set_personality_piece\", params)\n\n    async def _register_agent(self) -> None:\n        \"\"\"\n        Register an agent on the SOEF.\n\n        Includes the following steps:\n        - apply to lobby to receive unique page address and token\n        - acknowledge registration\n        - set default personality piece for agent framework\n        - initiate ping task\n        \"\"\"\n        self.logger.debug(\"Applying to SOEF lobby with address={}\".format(self.address))\n        url = parse.urljoin(self.base_url, \"register\")\n        params: Dict[str, Union[str, List[str]]] = {\n            \"api_key\": self.api_key,\n            \"chain_identifier\": self.chain_identifier,\n            \"address\": self.address,\n            \"declared_name\": self.declared_name,\n        }\n        response_text = await self._request_text(\"get\", url=url, params=params)\n        root = self._parse_soef_response(response_text, check_success=False)\n\n        self.logger.debug(\"Root tag: {}\".format(root.tag))\n        unique_page_address = \"\"\n        unique_token = \"\"  # nosec\n        for child in root:\n            self.logger.debug(\n                \"Child tag={}, child attrib={}, child text={}\".format(\n                    child.tag, child.attrib, child.text\n                )\n            )\n            if child.tag == \"page_address\" and child.text is not None:\n                unique_page_address = child.text\n            if child.tag == \"token\" and child.text is not None:\n                unique_token = child.text\n        if not (len(unique_page_address) > 0 and len(unique_token) > 0):\n            raise SOEFException.error(\n                f\"Agent registration error - page address or token not received. Response text: {response_text}\"\n            )\n        self.logger.debug(\"Registering agent\")\n        params = {\"token\": unique_token}\n        await self._generic_oef_command(\n            \"acknowledge\", params, unique_page_address=unique_page_address\n        )\n        self.unique_page_address = unique_page_address\n\n        await self._set_personality_piece(\"architecture\", \"agentframework\")\n\n        self.start_periodic_ping_task()\n\n    def start_periodic_ping_task(self) -> None:\n        \"\"\"Start the periodic ping task.\"\"\"\n        if self._loop and not self._ping_periodic_task:\n            self._ping_periodic_task = self._loop.create_task(\n                self._ping_periodic(self.PING_PERIOD)\n            )\n\n    async def _send_error_response(\n        self,\n        oef_search_message: OefSearchMessage,\n        oef_search_dialogue: OefSearchDialogue,\n        oef_error_operation: OefErrorOperation = OefSearchMessage.OefErrorOperation.OTHER,\n    ) -> None:\n        \"\"\"\n        Send an error response back.\n\n        :param oef_search_message: the oef search message\n        :param oef_search_dialogue: the oef search dialogue\n        :param oef_error_operation: the error code to send back\n        \"\"\"\n        if self.in_queue is None:\n            raise ValueError(\"Inqueue not set!\")  # pragma: nocover\n        message = oef_search_dialogue.reply(\n            performative=OefSearchMessage.Performative.OEF_ERROR,\n            target_message=oef_search_message,\n            oef_error_operation=oef_error_operation,\n        )\n        envelope = Envelope(\n            to=message.to,\n            sender=message.sender,\n            message=message,\n        )\n        await self.in_queue.put(envelope)\n\n    async def unregister_service(\n        self, oef_message: OefSearchMessage, oef_search_dialogue: OefSearchDialogue\n    ) -> None:\n        \"\"\"\n        Unregister a service on the SOEF.\n\n        :param oef_message: OefSearchMessage\n        :param oef_search_dialogue: OefSearchDialogue\n        \"\"\"\n        service_description = oef_message.service_description\n\n        data_model_handlers = {\n            \"location_agent\": self._unregister_agent,\n            \"remove_service_key\": self._remove_service_key_handler,\n        }  # type: Dict[str, Callable]\n        data_model_name = service_description.data_model.name\n\n        if data_model_name not in data_model_handlers:  # pragma: nocover\n            raise SOEFException.error(\n                f'Data model name: {data_model_name} is not supported for `unregister`. Valid models for performative {oef_message.performative} are: {\", \".join(data_model_handlers.keys())}'\n            )\n\n        handler = data_model_handlers[data_model_name]\n        if data_model_name == \"location_agent\":\n            await handler(oef_message, oef_search_dialogue)\n        else:\n            await handler(service_description, oef_message, oef_search_dialogue)\n\n    async def _unregister_agent(\n        self,\n        oef_message: Optional[OefSearchMessage] = None,\n        oef_search_dialogue: Optional[OefSearchDialogue] = None,\n    ) -> None:\n        \"\"\"\n        Unregister a location agent from the SOEF.\n\n        :param oef_message: OefSearchMessage\n        :param oef_search_dialogue: OefSearchDialogue\n        \"\"\"\n        if not self._unregister_lock:\n            raise ValueError(  # pragma: nocover\n                \"unregistered lock is not set, please call connect!\"\n            )\n\n        async with self._unregister_lock:\n            if self.unique_page_address is None:  # pragma: nocover\n                self.logger.debug(\n                    \"The service is not registered to the simple OEF. Cannot unregister.\"\n                )\n                return\n\n            task = asyncio.ensure_future(\n                self._generic_oef_command(\"unregister\", check_success=False)\n            )\n\n            try:\n                response = await asyncio.shield(task)\n            finally:\n                response = await task\n                if (\n                    \"<response><message>Goodbye!</message></response>\" not in response\n                ):  # pragma: nocover\n                    self.logger.debug(f\"No Goodbye response. Response={response}\")\n                self.unique_page_address = None\n                await self._stop_periodic_ping_task()\n        if oef_message is not None and oef_search_dialogue is not None:\n            await self._send_success_response(oef_message, oef_search_dialogue)\n\n    async def _stop_periodic_ping_task(self) -> None:\n        \"\"\"Cancel periodic ping task.\"\"\"\n        if self._ping_periodic_task and not self._ping_periodic_task.done():\n            self._ping_periodic_task.cancel()\n            self._ping_periodic_task.cancel()\n            with suppress(asyncio.CancelledError):\n                await self._ping_periodic_task\n            self._ping_periodic_task = None\n\n    async def _check_server_reachable(self) -> None:\n        \"\"\"Check network connection is ok.\"\"\"\n        try:\n            await asyncio.wait_for(\n                self._request_text(\n                    \"get\", self.base_url, timeout=self.connection_check_timeout\n                ),\n                timeout=self.connection_check_timeout,\n            )\n        except asyncio.TimeoutError:\n            raise SOEFNetworkConnectionError(\n                f\"Server can not be reached within timeout={self.connection_check_timeout}!\"\n            )\n\n    async def connect(self) -> None:\n        \"\"\"Connect channel set queues and executor pool.\"\"\"\n        self._loop = asyncio.get_event_loop()\n\n        reachable_check_count = 0\n        while reachable_check_count < self.connection_check_max_retries:\n            reachable_check_count += 1\n            try:\n                await self._check_server_reachable()\n                reachable_check_count = self.connection_check_max_retries\n            except Exception as e:  # pylint: disable=broad-except # pragma: nocover\n                if reachable_check_count == self.connection_check_max_retries:\n                    raise e\n                self.logger.debug(f\"Exception during SOEF reachability check: {e}.\")\n\n        self.in_queue = asyncio.Queue()\n        self._find_around_me_queue = asyncio.Queue()\n        self._unregister_lock = asyncio.Lock()\n        self._executor_pool = ThreadPoolExecutor(max_workers=10)\n        self._find_around_me_processor_task = self._loop.create_task(\n            self._find_around_me_processor()\n        )\n        # make sure we first unregister, in case of improper previous termination\n        try:\n            await self._unregister_agent()\n        except Exception as e:  # pylint: disable=broad-except # pragma: nocover\n            if \"<reason>Bad Request</reason><detail>agent lookup failed\" not in str(e):\n                # i.e. we're not trying to unregister and already unregistered agent\n                raise e\n            self.logger.debug(\"Unregister on SOEF failed. Agent not registered.\")\n            self.unique_page_address = None\n\n    async def disconnect(self) -> None:\n        \"\"\"Disconnect unregisters any potential services still registered.\"\"\"\n        await self._stop_periodic_ping_task()\n\n        if self.in_queue is None:\n            raise ValueError(\"Queue is not set, use connect first!\")  # pragma: nocover\n\n        if self._find_around_me_processor_task:\n            if not self._find_around_me_processor_task.done():\n                self._find_around_me_processor_task.cancel()\n            await self._find_around_me_processor_task\n\n        try:\n            await self._unregister_agent()\n        except Exception as e:  # pylint: disable=broad-except # pragma: nocover\n            self.logger.exception(str(e))\n\n        await self.in_queue.put(None)\n        self._find_around_me_queue = None\n\n    async def search_services(\n        self, oef_message: OefSearchMessage, oef_search_dialogue: OefSearchDialogue\n    ) -> None:\n        \"\"\"\n        Search services on the SOEF.\n\n        :param oef_message: OefSearchMessage\n        :param oef_search_dialogue: OefSearchDialogue\n        \"\"\"\n        query = oef_message.query\n\n        if not self._is_compatible_query(query):\n            raise SOEFException.warning(\n                \"Service query incompatible with SOEF: constraints={}\".format(\n                    query.constraints\n                )\n            )\n\n        constraints = [cast(Constraint, c) for c in query.constraints]\n        constraint_distance = [\n            c for c in constraints if c.constraint_type.type == ConstraintTypes.DISTANCE\n        ][0]\n        service_location, radius = constraint_distance.constraint_type.value\n\n        equality_constraints = [\n            c for c in constraints if c.constraint_type.type == ConstraintTypes.EQUAL\n        ]\n\n        params = {}\n\n        params.update(self._construct_personality_filter_params(equality_constraints))\n\n        params.update(self._construct_service_key_filter_params(equality_constraints))\n\n        if self.agent_location is None or self.agent_location != service_location:\n            # we update the location to match the query.\n            await self._set_location(service_location)  # pragma: nocover\n\n        await self._find_around_me(oef_message, oef_search_dialogue, radius, params)\n\n    async def _find_around_me(\n        self,\n        oef_message: OefSearchMessage,\n        oef_search_dialogue: OefSearchDialogue,\n        radius: float,\n        params: Dict[str, List[str]],\n    ) -> None:\n        \"\"\"\n        Add find agent task to queue to process in dedicated loop respectful to timeouts.\n\n        :param oef_message: OefSearchMessage\n        :param oef_search_dialogue: OefSearchDialogue\n        :param radius: the radius in which to search\n        :param params: the parameters for the query\n        \"\"\"\n        if not self._find_around_me_queue:\n            raise ValueError(\"SOEFChannel not started.\")  # pragma: nocover\n        await self._find_around_me_queue.put(\n            (oef_message, oef_search_dialogue, radius, params)\n        )\n\n    async def _find_around_me_handle_request(\n        self,\n        oef_message: OefSearchMessage,\n        oef_search_dialogue: OefSearchDialogue,\n        radius: float,\n        params: Dict[str, List[str]],\n    ) -> None:\n        \"\"\"\n        Find agents around me.\n\n        :param oef_message: OefSearchMessage\n        :param oef_search_dialogue: OefSearchDialogue\n        :param radius: the radius in which to search\n        :param params: the parameters for the query\n        \"\"\"\n        if self.in_queue is None:\n            raise ValueError(\"Inqueue not set!\")  # pragma: nocover\n        self.logger.debug(\"Searching in radius={} of myself\".format(radius))\n\n        root = await self._generic_oef_command(\n            \"find_around_me\", {\"range_in_km\": [str(radius)], **params}\n        )\n        agents = {}  # type: Dict[str, Dict[str, Union[str, Dict[str, str]]]]\n        for agent in root.findall(path=\".//agent\"):\n            chain_identifier = \"\"\n            for identities in agent.findall(\"identities\"):\n                for identity in identities.findall(\"identity\"):\n                    for (\n                        chain_identifier_key,\n                        chain_identifier_name,\n                    ) in identity.items():\n                        if chain_identifier_key == \"chain_identifier\":\n                            chain_identifier = chain_identifier_name\n                            agent_address = identity.text\n\n                            range_in_km = agent.find(\"range_in_km\").text\n                            agents[agent_address] = {\n                                \"chain_identifier\": chain_identifier,\n                                \"address\": agent_address,\n                                \"range_in_km\": range_in_km,\n                                **agent.attrib,\n                            }\n                            location = agent.find(\"./location\")\n                            if location:\n                                agents[agent_address][\"location\"] = {\n                                    **location.attrib,\n                                    \"longitude\": location.find(\"longitude\").text,\n                                    \"latitude\": location.find(\"latitude\").text,\n                                }\n\n        message = oef_search_dialogue.reply(\n            performative=OefSearchMessage.Performative.SEARCH_RESULT,\n            target_message=oef_message,\n            agents=tuple(agents.keys()),\n            agents_info=AgentsInfo(agents),\n        )\n        envelope = Envelope(\n            to=message.to,\n            sender=message.sender,\n            message=message,\n        )\n        await self.in_queue.put(envelope)\n\n\nclass SOEFConnection(Connection):\n    \"\"\"The SOEFConnection connects the Simple OEF to the mailbox.\"\"\"\n\n    connection_id = PUBLIC_ID\n    DEFAULT_CONNECTION_CHECK_TIMEOUT: float = 15.0\n    DEFAULT_CONNECTION_CHECK_MAX_RETRIES: int = 3\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"Initialize.\"\"\"\n        if kwargs.get(\"configuration\") is None:  # pragma: nocover\n            kwargs[\"excluded_protocols\"] = kwargs.get(\"excluded_protocols\") or []\n            kwargs[\"restricted_to_protocols\"] = kwargs.get(\"excluded_protocols\") or [\n                OefSearchMessage.protocol_id\n            ]\n\n        super().__init__(**kwargs)\n        api_key = cast(str, self.configuration.config.get(\"api_key\"))\n        connection_check_timeout = cast(\n            float,\n            self.configuration.config.get(\n                \"connection_check_timeout\", self.DEFAULT_CONNECTION_CHECK_TIMEOUT\n            ),\n        )\n        connection_check_max_retries = cast(\n            int,\n            self.configuration.config.get(\n                \"connection_check_max_retries\",\n                self.DEFAULT_CONNECTION_CHECK_MAX_RETRIES,\n            ),\n        )\n        is_https = cast(bool, self.configuration.config.get(\"is_https\", True))\n        soef_addr = cast(str, self.configuration.config.get(\"soef_addr\"))\n        soef_port = cast(int, self.configuration.config.get(\"soef_port\"))\n        chain_identifier = cast(str, self.configuration.config.get(\"chain_identifier\"))\n        token_storage_path = cast(\n            Optional[str], self.configuration.config.get(\"token_storage_path\")\n        )\n        not_none_params = {\n            \"api_key\": api_key,\n            \"soef_addr\": soef_addr,\n            \"soef_port\": soef_port,\n        }\n        for param_name, param_value in not_none_params.items():  # pragma: nocover\n            if param_value is None:\n                raise ValueError(f\"{param_name} must be set!\")\n        self.api_key = api_key\n        self.is_https = is_https\n        self.soef_addr = soef_addr\n        self.soef_port = soef_port\n        self.channel = SOEFChannel(\n            self.address,\n            self.api_key,\n            self.is_https,\n            self.soef_addr,\n            self.soef_port,\n            data_dir=self.data_dir,\n            chain_identifier=chain_identifier,\n            token_storage_path=token_storage_path,\n            connection_check_timeout=connection_check_timeout,\n            connection_check_max_retries=connection_check_max_retries,\n        )\n\n    async def connect(self) -> None:\n        \"\"\"\n        Connect to the channel.\n\n        :raises Exception if the connection to the OEF fails.\n        \"\"\"\n        if self.is_connected:  # pragma: nocover\n            return\n\n        with self._connect_context():\n            await self.channel.connect()\n\n    @property\n    def in_queue(self) -> Optional[asyncio.Queue]:\n        \"\"\"Return in_queue of the channel.\"\"\"\n        return self.channel.in_queue\n\n    async def disconnect(self) -> None:\n        \"\"\"Disconnect from the channel.\"\"\"\n        if self.is_disconnected:  # pragma: nocover\n            return\n        if self.in_queue is None:\n            raise ValueError(\"In queue not set.\")  # pragma: nocover\n        self.state = ConnectionStates.disconnecting\n        await self.channel.disconnect()\n        self.state = ConnectionStates.disconnected\n\n    async def receive(self, *args: Any, **kwargs: Any) -> Optional[\"Envelope\"]:\n        \"\"\"\n        Receive an envelope. Blocking.\n\n        :param args: positional arguments\n        :param kwargs: keyword arguments\n        :return: the envelope received, or None.\n        \"\"\"\n        try:\n            if self.in_queue is None:\n                raise ValueError(\"In queue not set.\")  # pragma: nocover\n            envelope = await self.in_queue.get()\n            if envelope is None:  # pragma: nocover\n                self.logger.debug(\"Received None.\")\n                return None\n            self.logger.debug(\"Received envelope: {}\".format(envelope))\n            return envelope\n        except CancelledError:\n            self.logger.debug(\"Receive cancelled.\")\n            return None\n        except Exception as e:  # pragma: nocover # pylint: disable=broad-except\n            self.logger.exception(e)\n            return None\n\n    async def send(self, envelope: \"Envelope\") -> None:\n        \"\"\"\n        Send an envelope.\n\n        :param envelope: the envelope to send.\n        \"\"\"\n        if self.is_connected:\n            await self.channel.send(envelope)\n"
  },
  {
    "path": "packages/fetchai/connections/soef/connection.yaml",
    "content": "name: soef\nauthor: fetchai\nversion: 0.27.6\ntype: connection\ndescription: The soef connection provides a connection api to the simple OEF.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: Qma5vKjAp6cPoDKM7fxTDhTbzKbemEWQecfk7kosHymptF\n  __init__.py: QmTCY2JASjfXJdt9ywBE5pejcXKvbrtSNCzJ9uiiEoHKFm\n  connection.py: QmZjpVuG4x9m9nFtAitdZ5MbJdBXFgrYHtkVrxUq7QL8c5\nfingerprint_ignore_patterns: []\nconnections: []\nprotocols:\n- fetchai/oef_search:1.1.7\nclass_name: SOEFConnection\nconfig:\n  api_key: TwiCIriSl0mLahw17pyqoA\n  chain_identifier: fetchai_v2_testnet_stable\n  connection_check_max_retries: 3\n  connection_check_timeout: 15.0\n  is_https: true\n  soef_addr: s-oef.fetch.ai\n  soef_port: 443\n  token_storage_path: soef_token.txt\nexcluded_protocols: []\nrestricted_to_protocols:\n- fetchai/oef_search:1.1.7\ndependencies:\n  defusedxml: {}\nis_abstract: false\n"
  },
  {
    "path": "packages/fetchai/connections/stub/README.md",
    "content": "# Stub connection\n\nA simple connection for communication with an AEA, using the file system as a point of data exchange.\n\n## Usage\n\nFirst, add the connection to your AEA project: `aea add connection fetchai/stub:0.21.3`. (If you have created your AEA project with `aea create` then the connection will already be available by default.)\n\nOptionally, in the `connection.yaml` file under `config` set the `input_file` and `output_file` to the desired file path. The `stub` connection reads encoded envelopes from the `input_file` and writes encoded envelopes to the `output_file`.\n"
  },
  {
    "path": "packages/fetchai/connections/stub/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Implementation of the stub connection.\"\"\"\n"
  },
  {
    "path": "packages/fetchai/connections/stub/connection.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the stub connection.\"\"\"\nimport asyncio\nimport logging\nimport os\nimport re\nimport typing\nfrom asyncio import CancelledError\nfrom asyncio.tasks import Task\nfrom concurrent.futures.thread import ThreadPoolExecutor\nfrom pathlib import Path\nfrom typing import Any, AsyncIterable, List, Optional\n\nfrom aea.configurations.base import PublicId\nfrom aea.configurations.constants import (\n    DEFAULT_INPUT_FILE_NAME,\n    DEFAULT_OUTPUT_FILE_NAME,\n)\nfrom aea.connections.base import Connection, ConnectionStates\nfrom aea.helpers.file_io import envelope_from_bytes, lock_file, write_envelope\nfrom aea.mail.base import Envelope\n\n\n_default_logger = logging.getLogger(\"aea.packages.fetchai.connections.stub\")\n\nINPUT_FILE_KEY = \"input_file\"\nOUTPUT_FILE_KEY = \"output_file\"\nSEPARATOR = b\",\"\n\nPUBLIC_ID = PublicId.from_str(\"fetchai/stub:0.21.3\")\n\n\nclass StubConnection(Connection):\n    r\"\"\"A stub connection.\n\n    This connection uses two files to communicate: one for the incoming messages and\n    the other for the outgoing messages. Each line contains an encoded envelope.\n\n    The format of each line is the following:\n\n        TO,SENDER,PROTOCOL_ID,ENCODED_MESSAGE\n\n    e.g.:\n\n        recipient_agent,sender_agent,default,{\"type\": \"bytes\", \"content\": \"aGVsbG8=\"}\n\n    The connection detects new messages by watchdogging the input file looking for new lines.\n\n    To post a message on the input file, you can use e.g.\n\n        echo \"...\" >> input_file\n\n    or:\n\n        #>>> fp = open(DEFAULT_INPUT_FILE_NAME, \"ab+\")\n        #>>> fp.write(b\"...\\n\")\n\n    It is discouraged adding a message with a text editor since the outcome depends on the actual text editor used.\n    \"\"\"\n\n    connection_id = PUBLIC_ID\n\n    message_regex = re.compile(\n        (b\"[^\" + SEPARATOR + b\"]*\" + SEPARATOR) * 3 + b\".*,[\\n]?\", re.DOTALL\n    )\n\n    read_delay = 0.001\n\n    def __init__(self, **kwargs: Any):\n        \"\"\"Initialize a stub connection.\"\"\"\n        super().__init__(**kwargs)\n        input_file: str = self.configuration.config.get(\n            INPUT_FILE_KEY, DEFAULT_INPUT_FILE_NAME\n        )\n        output_file: str = self.configuration.config.get(\n            OUTPUT_FILE_KEY, DEFAULT_OUTPUT_FILE_NAME\n        )\n        if not Path(input_file).is_absolute():\n            input_file = os.path.join(self.data_dir, input_file)\n        if not Path(output_file).is_absolute():\n            output_file = os.path.join(self.data_dir, output_file)\n        input_file_path = Path(input_file)\n        output_file_path = Path(output_file)\n        if not input_file_path.exists():\n            input_file_path.touch()\n\n        self.input_file_path = input_file_path\n        self.output_file_path = output_file_path\n\n        self.input_file: Optional[typing.IO] = None\n        self.output_file: Optional[typing.IO] = None\n\n        self.in_queue = None  # type: Optional[asyncio.Queue]\n\n        self._read_envelopes_task: Optional[Task] = None\n        self._write_pool = ThreadPoolExecutor(\n            max_workers=1, thread_name_prefix=\"stub_connection_writer_\"\n        )  # sequential write only! but threaded!\n\n    def _open_files(self) -> None:\n        \"\"\"Open file to read and write.\"\"\"\n        self.input_file = open(  # pylint: disable=consider-using-with\n            self.input_file_path, \"rb+\"\n        )\n        self.output_file = open(  # pylint: disable=consider-using-with\n            self.output_file_path, \"wb+\"\n        )\n\n    def _close_files(self) -> None:\n        \"\"\"Close opened files.\"\"\"\n        if self.input_file:\n            self.input_file.close()\n\n        if self.output_file:\n            self.output_file.close()\n\n    async def _file_read_and_trunc(self, delay: float = 0.001) -> AsyncIterable[bytes]:\n        \"\"\"\n        Generate input file read chunks and truncate data already read.\n\n        :param delay: float, delay on empty read.\n        :yield: async generator return file read bytes.\n        \"\"\"\n        if not self.input_file:  # pragma: nocover\n            raise ValueError(\"Input file not opened! Call Connection.connect first.\")\n\n        while True:\n            if self.input_file.closed:  # pragma: nocover\n                return\n            with lock_file(self.input_file):\n                data = self.input_file.read()\n                if data:\n                    self.input_file.truncate(0)\n                    self.input_file.seek(0)\n\n            if data:\n                yield data\n            else:\n                await asyncio.sleep(delay)\n\n    async def read_envelopes(self) -> None:\n        \"\"\"Read envelopes from input file, decode and put into in_queue.\"\"\"\n        self._ensure_connected()\n        if self.in_queue is None:  # pragma: nocover\n            raise ValueError(\"Input queue not initialized.\")\n\n        self.logger.debug(\"Read messages!\")\n        async for data in self._file_read_and_trunc(delay=self.read_delay):\n            lines = self._split_messages(data)\n            for line in lines:\n                envelope = envelope_from_bytes(line, SEPARATOR, self.logger)\n\n                if envelope is None:\n                    continue\n\n                self.logger.debug(f\"Add envelope {envelope}\")\n                await self.in_queue.put(envelope)\n\n    @classmethod\n    def _split_messages(cls, data: bytes) -> List[bytes]:\n        \"\"\"\n        Split binary data on messages.\n\n        :param data: bytes\n\n        :return: list of bytes\n        \"\"\"\n        return [m.group(0) for m in cls.message_regex.finditer(data)]\n\n    async def receive(self, *args: Any, **kwargs: Any) -> Optional[\"Envelope\"]:\n        \"\"\"Receive an envelope.\"\"\"\n        self._ensure_connected()\n        if self.in_queue is None:  # pragma: nocover\n            self.logger.error(\"Input queue not initialized.\")\n            return None\n\n        try:\n            envelope = await self.in_queue.get()\n            return envelope\n        except (CancelledError, asyncio.TimeoutError):  # pragma: no cover\n            self.logger.debug(\"Receive cancelled.\")\n            raise\n        except Exception:  # pylint: disable=broad-except\n            self.logger.exception(\"Stub connection receive error:\")\n            return None\n\n    async def connect(self) -> None:\n        \"\"\"Set up the connection.\"\"\"\n        if self.is_connected:\n            return\n\n        with self._connect_context():\n            self.in_queue = asyncio.Queue()\n            self._open_files()\n            self._read_envelopes_task = self.loop.create_task(self.read_envelopes())\n\n    async def _stop_read_envelopes(self) -> None:\n        \"\"\"\n        Stop read envelopes task.\n\n        Cancel task and wait for completed.\n        \"\"\"\n        if not self._read_envelopes_task:\n            return  # pragma: nocover\n\n        if not self._read_envelopes_task.done():\n            self._read_envelopes_task.cancel()\n\n        try:\n            await self._read_envelopes_task\n        except CancelledError:\n            pass  # task was cancelled, that was expected\n        except BaseException:  # pragma: nocover  # pylint: disable=broad-except\n            self.logger.exception(\n                \"during envelop read\"\n            )  # do not raise exception cause it's on task stop\n\n    async def disconnect(self) -> None:\n        \"\"\"\n        Disconnect from the channel.\n\n        In this type of connection there's no channel to disconnect.\n        \"\"\"\n        if self.is_disconnected:\n            return\n\n        if self.in_queue is None:  # pragma: nocover\n            raise ValueError(\"Input queue not initialized.\")\n\n        self.state = ConnectionStates.disconnecting\n        await self._stop_read_envelopes()\n        self._write_pool.shutdown(wait=True)  # wait write operation to complete\n        self.in_queue.put_nowait(None)\n        self._close_files()\n        self.state = ConnectionStates.disconnected\n\n    async def send(self, envelope: Envelope) -> None:\n        \"\"\"\n        Send messages.\n\n        :param envelope: the envelope\n        \"\"\"\n        self._ensure_connected()\n        self._ensure_valid_envelope_for_external_comms(envelope)\n        if not self.output_file:  # pragma: nocover\n            raise ValueError(\n                \"output_file file not opened! Call Connection.connect first.\"\n            )\n\n        await self.loop.run_in_executor(\n            self._write_pool,\n            write_envelope,\n            envelope,\n            self.output_file,\n            SEPARATOR,\n            self.logger,\n        )\n"
  },
  {
    "path": "packages/fetchai/connections/stub/connection.yaml",
    "content": "name: stub\nauthor: fetchai\nversion: 0.21.3\ntype: connection\ndescription: The stub connection implements a connection stub which reads/writes messages\n  from/to file.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: QmVtTqPDAvnMjj2W97E1u84NDLREZZ1Qcp8csVGRi8TjHL\n  __init__.py: QmU3CUkFsuMuBuFtcrCkUpt7ydGXRfM5PtBmamTk3yP2uP\n  connection.py: Qmb379EQWBCrqXw9PiTpsbeRtzPyYXiwDVXKJLWwYR2wXN\nfingerprint_ignore_patterns: []\nconnections: []\nprotocols: []\nclass_name: StubConnection\nconfig:\n  input_file: ./input_file\n  output_file: ./output_file\nexcluded_protocols: []\nrestricted_to_protocols: []\ndependencies: {}\nis_abstract: false\n"
  },
  {
    "path": "packages/fetchai/connections/tcp/README.md",
    "content": "# TCP client connection\n\nA simple TCP client/server connection to use the TCP protocol for sending and receiving envelopes.\n\n## Usage\n\nAdd the connection to your AEA project: `aea add connection fetchai/tcp:0.17.3`.\n"
  },
  {
    "path": "packages/fetchai/connections/tcp/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Implementation of a TCP connection.\"\"\"\n"
  },
  {
    "path": "packages/fetchai/connections/tcp/base.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Base classes for TCP communication.\"\"\"\nimport logging\nimport struct\nfrom abc import ABC, abstractmethod\nfrom asyncio import CancelledError, StreamReader, StreamWriter\nfrom typing import Any, Optional\n\nfrom aea.configurations.base import PublicId\nfrom aea.connections.base import Connection, ConnectionStates\nfrom aea.mail.base import Envelope\n\n\n_default_logger = logging.getLogger(\"aea.packages.fetchai.connections.tcp\")\n\nPUBLIC_ID = PublicId.from_str(\"fetchai/tcp:0.17.3\")\n\n\nclass TCPConnection(Connection, ABC):\n    \"\"\"Abstract TCP connection.\"\"\"\n\n    connection_id = PUBLIC_ID\n\n    def __init__(self, host: str, port: int, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize a TCP connection.\n\n        :param host: the socket bind address.\n        :param port: the socket bind port.\n        :param kwargs: keyword arguments.\n        \"\"\"\n        super().__init__(**kwargs)\n        # for the server, the listening address/port\n        # for the client, the server address/port\n        self.host = host\n        self.port = port\n\n    @abstractmethod\n    async def setup(self) -> None:\n        \"\"\"Set the TCP connection up.\"\"\"\n\n    @abstractmethod\n    async def teardown(self) -> None:\n        \"\"\"Tear the TCP connection down.\"\"\"\n\n    @abstractmethod\n    def select_writer_from_envelope(self, envelope: Envelope) -> Optional[StreamWriter]:\n        \"\"\"\n        Select the destination, given the envelope.\n\n        :param envelope: the envelope to be sent.\n        :return: the stream writer to communicate with the recipient. None if it cannot be determined.\n        \"\"\"\n\n    async def connect(self) -> None:\n        \"\"\"Set up the connection.\"\"\"\n        if self.is_connected:  # pragma: nocover\n            self.logger.warning(\"Connection already set up.\")\n            return\n\n        self.state = ConnectionStates.connecting\n        try:\n            await self.setup()\n            self.state = ConnectionStates.connected\n        except Exception as e:  # pragma: nocover # pylint: disable=broad-except\n            self.logger.error(str(e))\n            self.state = ConnectionStates.disconnected\n\n    async def disconnect(self) -> None:\n        \"\"\"Tear down the connection.\"\"\"\n        if self.is_disconnected:  # pragma: nocover\n            self.logger.warning(\"Connection already disconnected.\")\n            return\n\n        self.state = ConnectionStates.disconnecting\n        await self.teardown()\n        self.state = ConnectionStates.disconnected\n\n    async def _recv(self, reader: StreamReader) -> Optional[bytes]:\n        \"\"\"Receive bytes.\"\"\"\n        data = await reader.read(len(struct.pack(\"I\", 0)))\n        if not self.is_connected:\n            return None\n        nbytes = struct.unpack(\"I\", data)[0]\n        nbytes_read = 0\n        data = b\"\"\n        while nbytes_read < nbytes:\n            data += await reader.read(nbytes - nbytes_read)\n            nbytes_read = len(data)\n        return data\n\n    async def _send(self, writer: StreamWriter, data: bytes) -> None:\n        self.logger.debug(\"[{}] Send a message\".format(self.address))\n        nbytes = struct.pack(\"I\", len(data))\n        self.logger.debug(\"#bytes: {!r}\".format(nbytes))\n        try:\n            writer.write(nbytes)\n            writer.write(data)\n            await writer.drain()\n        except CancelledError:\n            return None\n\n    async def send(self, envelope: Envelope) -> None:\n        \"\"\"\n        Send an envelope.\n\n        :param envelope: the envelope to send.\n        \"\"\"\n        self._ensure_valid_envelope_for_external_comms(envelope)\n        writer = self.select_writer_from_envelope(envelope)\n        if writer is not None:\n            data = envelope.encode()\n            await self._send(writer, data)\n        else:\n            self.logger.error(\n                \"[{}]: Cannot send envelope {}\".format(self.address, envelope)\n            )\n"
  },
  {
    "path": "packages/fetchai/connections/tcp/connection.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n# pragma: nocover # noqa: E800\n\"\"\"Base classes for TCP communication.\"\"\"\n\nfrom .tcp_client import (  # noqa: F401 # pylint: disable=unused-import\n    TCPClientConnection,\n)\nfrom .tcp_server import (  # noqa: F401 # pylint: disable=unused-import\n    TCPServerConnection,\n)\n"
  },
  {
    "path": "packages/fetchai/connections/tcp/connection.yaml",
    "content": "name: tcp\nauthor: fetchai\nversion: 0.17.3\ntype: connection\ndescription: The tcp connection implements a tcp server and client.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: Qmc2px6Bbjnf44wPB56Y2gYroNE1gfjEszTntnTWkwsUzX\n  __init__.py: Qmb3vSwEJwhNEaV899VUrwEkUatVJrxXqbegc1oiXEmAtJ\n  base.py: QmYLota5rE8UjaJmEY1eUmjakEsv2uUcYLGYGToAwCtX5F\n  connection.py: QmNcPrHd1Qoe59eTLWLH4Xbg31AZZ6SdCpekJnmhhxG1o8\n  tcp_client.py: QmauAiCbvMtp8e5V2s1qZWpeXqPRfXxSEfo11jLhPMFxBc\n  tcp_server.py: QmSJDqUHCFA9erUjyQVcUUTnHr7FP2CEPQbYijdcUARjdv\nfingerprint_ignore_patterns: []\nconnections: []\nprotocols: []\nclass_name: TCPClientConnection\nconfig:\n  address: 127.0.0.1\n  port: 8082\nexcluded_protocols: []\nrestricted_to_protocols: []\ndependencies: {}\nis_abstract: false\n"
  },
  {
    "path": "packages/fetchai/connections/tcp/tcp_client.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Implementation of the TCP client.\"\"\"\n\nimport asyncio\nimport logging\nimport struct\nfrom asyncio import (  # pylint: disable=unused-import\n    CancelledError,\n    StreamReader,\n    StreamWriter,\n)\nfrom typing import Any, Optional, cast\n\nfrom aea.configurations.base import ConnectionConfig\nfrom aea.mail.base import Envelope\n\nfrom packages.fetchai.connections.tcp.base import TCPConnection\n\n\n_default_logger = logging.getLogger(\"aea.packages.fetchai.connections.tcp.tcp_client\")\n\nSTUB_DIALOGUE_ID = 0\n\n\nclass TCPClientConnection(TCPConnection):\n    \"\"\"This class implements a TCP client.\"\"\"\n\n    def __init__(self, configuration: ConnectionConfig, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize a TCP client connection.\n\n        :param configuration: the configuration object.\n        :param kwargs: keyword arguments.\n        \"\"\"\n        address = cast(str, configuration.config.get(\"address\"))\n        port = cast(int, configuration.config.get(\"port\"))\n        if address is None or port is None:\n            raise ValueError(\"address and port must be set!\")  # pragma: nocover\n        super().__init__(address, port, configuration=configuration, **kwargs)\n        self._reader, self._writer = (\n            None,\n            None,\n        )  # type: Optional[StreamReader], Optional[StreamWriter]\n\n    async def setup(self) -> None:\n        \"\"\"Set the connection up.\"\"\"\n        self._reader, self._writer = await asyncio.open_connection(self.host, self.port)\n        address_bytes = self.address.encode(\"utf-8\")\n        await self._send(self._writer, address_bytes)\n\n    async def teardown(self) -> None:\n        \"\"\"Tear the connection down.\"\"\"\n        if self._reader is not None:\n            self._reader.feed_eof()\n        if self._writer is None:  # pragma: nocover\n            return\n        if self._writer.can_write_eof():\n            self._writer.write_eof()\n        await self._writer.drain()\n        self._writer.close()\n        # it should be 'await self._writer.wait_closed()'\n        # however, it is not backward compatible with Python 3.6.\n        # this turned out to work in the tests\n        await asyncio.sleep(0.0)\n\n    async def receive(self, *args: Any, **kwargs: Any) -> Optional[\"Envelope\"]:\n        \"\"\"\n        Receive an envelope.\n\n        :param args: positional arguments\n        :param kwargs: keyword arguments\n        :return: the received envelope, or None if an error occurred.\n        \"\"\"\n        try:\n            if self._reader is None:\n                raise ValueError(\"Reader not set.\")  # pragma: nocover\n            data = await self._recv(self._reader)\n            if data is None:  # pragma: nocover\n                self.logger.debug(\"[{}] No data received.\".format(self.address))\n                return None\n            self.logger.debug(\"[{}] Message received: {!r}\".format(self.address, data))\n            envelope = Envelope.decode(data)\n            self.logger.debug(\n                \"[{}] Decoded envelope: {}\".format(self.address, envelope)\n            )\n            return envelope\n        except CancelledError:\n            self.logger.debug(\"[{}] Read cancelled.\".format(self.address))\n            return None\n        except struct.error as e:\n            self.logger.debug(\"Struct error: {}\".format(str(e)))\n            return None\n        except Exception as e:\n            self.logger.exception(e)\n            raise\n\n    def select_writer_from_envelope(self, envelope: Envelope) -> Optional[StreamWriter]:\n        \"\"\"Select the destination, given the envelope.\"\"\"\n        return self._writer\n"
  },
  {
    "path": "packages/fetchai/connections/tcp/tcp_server.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Implementation of the TCP server.\"\"\"\n\nimport asyncio\nimport logging\nfrom asyncio import AbstractServer, Future, StreamReader, StreamWriter\nfrom typing import Any, Dict, Optional, Tuple, cast\n\nfrom aea.common import Address\nfrom aea.configurations.base import ConnectionConfig\nfrom aea.mail.base import Envelope\n\nfrom packages.fetchai.connections.tcp.base import TCPConnection\n\n\n_default_logger = logging.getLogger(\"aea.packages.fetchai.connections.tcp.tcp_server\")\n\nSTUB_DIALOGUE_ID = 0\n\n\nclass TCPServerConnection(TCPConnection):\n    \"\"\"This class implements a TCP server.\"\"\"\n\n    def __init__(self, configuration: ConnectionConfig, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize a TCP server connection.\n\n        :param configuration: the configuration object.\n        :param kwargs: keyword arguments.\n        \"\"\"\n        address = cast(str, configuration.config.get(\"address\"))\n        port = cast(int, configuration.config.get(\"port\"))\n        if address is None or port is None:\n            raise ValueError(\"address and port must be set!\")  # pragma: nocover\n        super().__init__(address, port, configuration=configuration, **kwargs)\n        self._server = None  # type: Optional[AbstractServer]\n        self.connections = {}  # type: Dict[str, Tuple[StreamReader, StreamWriter]]\n\n        self._read_tasks_to_address = {}  # type: Dict[Future, Address]\n\n    async def handle(self, reader: StreamReader, writer: StreamWriter) -> None:\n        \"\"\"\n        Handle new connections.\n\n        :param reader: the stream reader.\n        :param writer: the stream writer.\n        \"\"\"\n        self.logger.debug(\"Waiting for client address...\")\n        address_bytes = await self._recv(reader)\n        if address_bytes is not None:\n            address_bytes = cast(bytes, address_bytes)\n            address = address_bytes.decode(\"utf-8\")\n            self.logger.debug(\"Public key of the client: {}\".format(address))\n            self.connections[address] = (reader, writer)\n            read_task = asyncio.ensure_future(self._recv(reader), loop=self.loop)\n            self._read_tasks_to_address[read_task] = address\n\n    async def receive(self, *args: Any, **kwargs: Any) -> Optional[\"Envelope\"]:\n        \"\"\"\n        Receive an envelope.\n\n        :param args: positional arguments\n        :param kwargs: keyword arguments\n        :return: the received envelope, or None if an error occurred.\n        \"\"\"\n        if len(self._read_tasks_to_address) == 0:\n            self.logger.warning(\n                \"Tried to read from the TCP server. However, there is no open connection to read from.\"\n            )\n            return None\n\n        try:\n            self.logger.debug(\"Waiting for incoming messages...\")\n            done, _ = await asyncio.wait(self._read_tasks_to_address.keys(), return_when=asyncio.FIRST_COMPLETED)  # type: ignore\n\n            # take the first\n            task = next(iter(done))\n            envelope_bytes = task.result()\n            if envelope_bytes is None:  # pragma: no cover\n                self.logger.debug(\"[{}]: No data received.\")\n                return None\n            envelope = Envelope.decode(envelope_bytes)\n            address = self._read_tasks_to_address.pop(task)\n            reader = self.connections[address][0]\n            new_task = asyncio.ensure_future(self._recv(reader), loop=self.loop)\n            self._read_tasks_to_address[new_task] = address\n            return envelope\n        except asyncio.CancelledError:\n            self.logger.debug(\"Receiving loop cancelled.\")\n            return None\n        except Exception as e:  # pragma: nocover # pylint: disable=broad-except\n            self.logger.error(\"Error in the receiving loop: {}\".format(str(e)))\n            return None\n\n    async def setup(self) -> None:\n        \"\"\"Set the connection up.\"\"\"\n        self._server = await asyncio.start_server(\n            self.handle, host=self.host, port=self.port\n        )\n        self.logger.debug(\"Start listening on {}:{}\".format(self.host, self.port))\n\n    async def teardown(self) -> None:\n        \"\"\"Tear the connection down.\"\"\"\n        for (reader, _) in self.connections.values():\n            reader.feed_eof()\n\n        for t in self._read_tasks_to_address:\n            t.cancel()\n\n        if self._server is None:  # pragma: nocover\n            raise ValueError(\"Server not set!\")\n\n        self._server.close()\n        await self._server.wait_closed()\n\n    def select_writer_from_envelope(self, envelope: Envelope) -> Optional[StreamWriter]:\n        \"\"\"Select the destination, given the envelope.\"\"\"\n        to = envelope.to\n        if to not in self.connections:\n            return None\n        _, writer = self.connections[to]\n        return writer\n"
  },
  {
    "path": "packages/fetchai/connections/webhook/README.md",
    "content": "# Webhook connection\n\nAn HTTP webhook connection which registers a webhook and waits for incoming requests. It generates messages based on webhook requests received and forwards them to the agent.\n\n## Usage\n\nFirst, add the connection to your AEA project: `aea add connection fetchai/webhook:0.20.6`. Then ensure the `config` in `connection.yaml` matches your need. In particular, set `webhook_address`, `webhook_port` and `webhook_url_path` appropriately.\n"
  },
  {
    "path": "packages/fetchai/connections/webhook/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Implementation of the webhook connection and channel.\"\"\"\n"
  },
  {
    "path": "packages/fetchai/connections/webhook/connection.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Webhook connection and channel.\"\"\"\n\nimport asyncio\nimport json\nimport logging\nfrom asyncio import CancelledError\nfrom typing import Any, Optional, cast\n\nfrom aiohttp import web  # type: ignore\n\nfrom aea.common import Address\nfrom aea.configurations.base import PublicId\nfrom aea.connections.base import Connection, ConnectionStates\nfrom aea.mail.base import Envelope\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\n\nfrom packages.fetchai.protocols.http.dialogues import HttpDialogue\nfrom packages.fetchai.protocols.http.dialogues import HttpDialogues as BaseHttpDialogues\nfrom packages.fetchai.protocols.http.message import HttpMessage\n\n\nSUCCESS = 200\nNOT_FOUND = 404\nREQUEST_TIMEOUT = 408\nSERVER_ERROR = 500\nPUBLIC_ID = PublicId.from_str(\"fetchai/webhook:0.20.6\")\n\n_default_logger = logging.getLogger(\"aea.packages.fetchai.connections.webhook\")\n\nRequestId = str\n\n\nclass HttpDialogues(BaseHttpDialogues):\n    \"\"\"The dialogues class keeps track of all http dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            # The webhook connection maintains the dialogue on behalf of the server\n            return HttpDialogue.Role.SERVER\n\n        BaseHttpDialogues.__init__(\n            self,\n            self_address=str(WebhookConnection.connection_id),\n            role_from_first_message=role_from_first_message,\n            **kwargs,\n        )\n\n\nclass WebhookChannel:\n    \"\"\"A wrapper for a Webhook.\"\"\"\n\n    def __init__(\n        self,\n        agent_address: Address,\n        webhook_address: Address,\n        webhook_port: int,\n        webhook_url_path: str,\n        connection_id: PublicId,\n        target_skill_id: PublicId,\n        logger: logging.Logger = _default_logger,\n    ):\n        \"\"\"\n        Initialize a webhook channel.\n\n        :param agent_address: the address of the agent\n        :param webhook_address: webhook hostname / IP address\n        :param webhook_port: webhook port number\n        :param webhook_url_path: the url path to receive webhooks from\n        :param connection_id: the connection id\n        :param target_skill_id: the skill id which should receive the http messages\n        :param logger: the logger\n        \"\"\"\n        self.agent_address = agent_address\n\n        self.webhook_address = webhook_address\n        self.webhook_port = webhook_port\n        self.webhook_url_path = webhook_url_path\n        self.target_skill_id = target_skill_id\n\n        self.webhook_site = None  # type: Optional[web.TCPSite]\n        self.runner = None  # type: Optional[web.AppRunner]\n        self.app = None  # type: Optional[web.Application]\n\n        self.is_stopped = True\n\n        self.connection_id = connection_id\n        self.in_queue = None  # type: Optional[asyncio.Queue]  # pragma: no cover\n        self.logger = logger\n        self.logger.info(\"Initialised a webhook channel\")\n        self._dialogues = HttpDialogues()\n\n    async def connect(self) -> None:\n        \"\"\"\n        Connect the webhook.\n\n        Connects the webhook via the webhook_address and webhook_port parameters\n        \"\"\"\n        if self.is_stopped:\n            self.app = web.Application()\n            self.app.add_routes(\n                [web.post(self.webhook_url_path, self._receive_webhook)]\n            )\n            self.runner = web.AppRunner(self.app)\n            await self.runner.setup()\n            self.webhook_site = web.TCPSite(\n                self.runner, self.webhook_address, self.webhook_port\n            )\n            await self.webhook_site.start()\n            self.is_stopped = False\n\n    async def disconnect(self) -> None:\n        \"\"\"\n        Disconnect.\n\n        Shut-off and cleanup the webhook site, the runner and the web app, then stop the channel.\n        \"\"\"\n        if self.webhook_site is None or self.runner is None or self.app is None:\n            raise ValueError(\n                \"Application not connected, call connect first!\"\n            )  # pragma: nocover\n\n        if not self.is_stopped:\n            await self.webhook_site.stop()\n            await self.runner.shutdown()\n            await self.runner.cleanup()\n            await self.app.shutdown()\n            await self.app.cleanup()\n            self.logger.info(\"Webhook app is shutdown.\")\n            self.is_stopped = True\n\n    async def _receive_webhook(self, request: web.Request) -> web.Response:\n        \"\"\"\n        Receive a webhook request.\n\n        Get webhook request, turn it to envelop and send it to the agent to be picked up.\n\n        :param request: the webhook request\n        :return: Http response with a 200 code\n        \"\"\"\n        webhook_envelop = await self.to_envelope(request)\n        self.in_queue.put_nowait(webhook_envelop)  # type: ignore\n        return web.Response(status=200)\n\n    async def send(self, envelope: Envelope) -> None:\n        \"\"\"\n        Send an envelope.\n\n        Sending envelopes via the webhook is not possible!\n\n        :param envelope: the envelope\n        \"\"\"\n        self.logger.warning(\n            \"Dropping envelope={} as sending via the webhook is not possible!\".format(\n                envelope\n            )\n        )\n\n    async def to_envelope(self, request: web.Request) -> Envelope:\n        \"\"\"\n        Convert a webhook request object into an Envelope containing an HttpMessage `from the 'http' Protocol`.\n\n        :param request: the webhook request\n        :return: The envelop representing the webhook request\n        \"\"\"\n        payload_bytes = await request.read()\n        version = str(request.version[0]) + \".\" + str(request.version[1])\n\n        http_message, _ = self._dialogues.create(\n            counterparty=str(self.target_skill_id),\n            performative=HttpMessage.Performative.REQUEST,\n            method=request.method,\n            url=str(request.url),\n            version=version,\n            headers=json.dumps(dict(request.headers)),\n            body=payload_bytes if payload_bytes is not None else b\"\",\n        )\n        envelope = Envelope(\n            to=http_message.to,\n            sender=http_message.sender,\n            message=http_message,\n        )\n        return envelope\n\n\nclass WebhookConnection(Connection):\n    \"\"\"Proxy to the functionality of a webhook.\"\"\"\n\n    connection_id = PUBLIC_ID\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"Initialize a web hook connection.\"\"\"\n        super().__init__(**kwargs)\n        webhook_address = cast(str, self.configuration.config.get(\"webhook_address\"))\n        webhook_port = cast(int, self.configuration.config.get(\"webhook_port\"))\n        webhook_url_path = cast(str, self.configuration.config.get(\"webhook_url_path\"))\n        target_skill_id_ = cast(\n            Optional[str], self.configuration.config.get(\"target_skill_id\")\n        )\n        if (\n            webhook_address is None\n            or webhook_port is None\n            or webhook_url_path is None\n            or target_skill_id_ is None\n        ):\n            raise ValueError(  # pragma: nocover\n                \"webhook_address, webhook_port, webhook_url_path and target_skill_id must be set!\"\n            )\n        target_skill_id = PublicId.try_from_str(target_skill_id_)\n        if target_skill_id is None:  # pragma: nocover\n            raise ValueError(\"Provided target_skill_id is not a valid public id.\")\n        self.channel = WebhookChannel(\n            agent_address=self.address,\n            webhook_address=webhook_address,\n            webhook_port=webhook_port,\n            webhook_url_path=webhook_url_path,\n            connection_id=self.connection_id,\n            target_skill_id=target_skill_id,\n            logger=self.logger,\n        )\n\n    async def connect(self) -> None:\n        \"\"\"Connect to a HTTP server.\"\"\"\n        if self.is_connected:  # pragma: nocover\n            return\n\n        with self._connect_context():\n            self.channel.logger = self.logger\n            self.channel.in_queue = asyncio.Queue()\n            await self.channel.connect()\n\n    async def disconnect(self) -> None:\n        \"\"\"Disconnect from a HTTP server.\"\"\"\n        if self.is_disconnected:  # pragma: nocover\n            return\n\n        self.state = ConnectionStates.disconnecting\n        await self.channel.disconnect()\n        self.state = ConnectionStates.disconnected\n\n    async def send(self, envelope: \"Envelope\") -> None:\n        \"\"\"\n        Send does nothing. Webhooks only receive.\n\n        :param envelope: the envelop\n        \"\"\"\n        self._ensure_connected()\n        if self.channel.in_queue is None:\n            raise ValueError(\"Channel in queue not set.\")  # pragma: nocover\n        await self.channel.send(envelope)\n\n    async def receive(self, *args: Any, **kwargs: Any) -> Optional[\"Envelope\"]:\n        \"\"\"\n        Receive an envelope.\n\n        :param args: positional arguments\n        :param kwargs: keyword arguments\n        :return: the envelope received, or None.\n        \"\"\"\n        self._ensure_connected()\n        if self.channel.in_queue is None:\n            raise ValueError(\"Channel in queue not set.\")  # pragma: nocover\n        try:\n            envelope = await self.channel.in_queue.get()\n            if envelope is None:\n                return None  # pragma: no cover\n            return envelope\n        except CancelledError:  # pragma: no cover\n            return None\n"
  },
  {
    "path": "packages/fetchai/connections/webhook/connection.yaml",
    "content": "name: webhook\nauthor: fetchai\nversion: 0.20.6\ntype: connection\ndescription: The webhook connection that wraps a webhook functionality.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: QmdSsHTfZkHbdjFTM9mJRiNEobjVzDy4YfMxGUQdSPiBtF\n  __init__.py: QmesEv4nZwUWcqYRFs1BkHp7RW9uuHG8did8FF9Axc7mD8\n  connection.py: QmRFthb8nkh9RPA39o9tWUQNDB7YVjKrCd7Z1q3sMQfwMY\nfingerprint_ignore_patterns: []\nconnections: []\nprotocols:\n- fetchai/http:1.1.7\nclass_name: WebhookConnection\nconfig:\n  target_skill_id: null\n  webhook_address: 127.0.0.1\n  webhook_port: 8000\n  webhook_url_path: /some/url/path\nexcluded_protocols: []\nrestricted_to_protocols:\n- fetchai/http:1.1.7\ndependencies:\n  aiohttp:\n    version: <3.8,>=3.7.4\nis_abstract: false\n"
  },
  {
    "path": "packages/fetchai/contracts/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the contract packages authored by Fetch.ai\"\"\"\n"
  },
  {
    "path": "packages/fetchai/contracts/erc1155/README.md",
    "content": "# Fetch ERC1155 Contract\n\n## Description\n\nThis contract package is used to interface with an ERC1155 smart contract.\n\n## Functions\n\n- `generate_token_ids(token_type, nb_tokens, starting_index)`: Generate token ids.\n- `get_create_batch_transaction(token_ids)`: Get the transaction to create a batch of `token_ids` tokens.\n- `get_create_single_transaction()`: Get the transaction to create a single `token_id` token.\n- `get_mint_batch_transaction(token_ids, mint_quantities)`: Get the transaction to mint `mint_quantities` number of `token_ids` tokens.\n- `validate_mint_quantities(token_ids, mint_quantities)`: Validate the mint quantities\n- `get_mint_single_transaction(token_id, mint_quantity)`: Get the transaction to mint `mint_quantity` number of a single `token_id` token.\n- `get_balance(token_id)`: Get the balance for a specific `token_id`.\n- `get_atomic_swap_single_transaction(token_id)`: Get the transaction for a trustless trade between two agents for a single `token_id` token.\n- `get_balances(token_ids)`: Get the balances for a batch of specific `token_ids`.\n- `get_atomic_swap_batch_transaction(token_ids)`: Get the transaction for a trustless trade between two agents for a batch of `token_ids` tokens.\n- `get_hash_single(token_id)`: Get the hash for a trustless trade between two agents for a single `token_id` token.\n- `get_hash_batch(token_ids)`: Get the hash for a trustless trade between two agents for a batch of `token_ids` token.\n- `generate_trade_nonce()`: Generate a valid trade nonce.\n\n## Links\n\n- <a href=\"https://eips.ethereum.org/EIPS/eip-1155\" target=\"_blank\">ERC1155 Standard</a>\n"
  },
  {
    "path": "packages/fetchai/contracts/erc1155/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the support resources for the erc1155 contract.\"\"\"\n"
  },
  {
    "path": "packages/fetchai/contracts/erc1155/build/Migrations.json",
    "content": "{\n  \"contractName\": \"Migrations\",\n  \"abi\": [\n    {\n      \"constant\": true,\n      \"inputs\": [],\n      \"name\": \"last_completed_migration\",\n      \"outputs\": [\n        {\n          \"name\": \"\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"payable\": false,\n      \"stateMutability\": \"view\",\n      \"type\": \"function\"\n    },\n    {\n      \"constant\": true,\n      \"inputs\": [],\n      \"name\": \"owner\",\n      \"outputs\": [\n        {\n          \"name\": \"\",\n          \"type\": \"address\"\n        }\n      ],\n      \"payable\": false,\n      \"stateMutability\": \"view\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [],\n      \"payable\": false,\n      \"stateMutability\": \"nonpayable\",\n      \"type\": \"constructor\"\n    },\n    {\n      \"constant\": false,\n      \"inputs\": [\n        {\n          \"name\": \"completed\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"name\": \"setCompleted\",\n      \"outputs\": [],\n      \"payable\": false,\n      \"stateMutability\": \"nonpayable\",\n      \"type\": \"function\"\n    },\n    {\n      \"constant\": false,\n      \"inputs\": [\n        {\n          \"name\": \"new_address\",\n          \"type\": \"address\"\n        }\n      ],\n      \"name\": \"upgrade\",\n      \"outputs\": [],\n      \"payable\": false,\n      \"stateMutability\": \"nonpayable\",\n      \"type\": \"function\"\n    }\n  ],\n  \"metadata\": \"{\\\"compiler\\\":{\\\"version\\\":\\\"0.5.2+commit.1df8f40c\\\"},\\\"language\\\":\\\"Solidity\\\",\\\"output\\\":{\\\"abi\\\":[{\\\"constant\\\":false,\\\"inputs\\\":[{\\\"name\\\":\\\"new_address\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"upgrade\\\",\\\"outputs\\\":[],\\\"payable\\\":false,\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"constant\\\":true,\\\"inputs\\\":[],\\\"name\\\":\\\"last_completed_migration\\\",\\\"outputs\\\":[{\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"payable\\\":false,\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"constant\\\":true,\\\"inputs\\\":[],\\\"name\\\":\\\"owner\\\",\\\"outputs\\\":[{\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"address\\\"}],\\\"payable\\\":false,\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"constant\\\":false,\\\"inputs\\\":[{\\\"name\\\":\\\"completed\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"setCompleted\\\",\\\"outputs\\\":[],\\\"payable\\\":false,\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"payable\\\":false,\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"constructor\\\"}],\\\"devdoc\\\":{\\\"methods\\\":{}},\\\"userdoc\\\":{\\\"methods\\\":{}}},\\\"settings\\\":{\\\"compilationTarget\\\":{\\\"/Users/aristotelistriantafyllidis/Documents/agents-research/erc1155/contracts/Migrations.sol\\\":\\\"Migrations\\\"},\\\"evmVersion\\\":\\\"byzantium\\\",\\\"libraries\\\":{},\\\"optimizer\\\":{\\\"enabled\\\":true,\\\"runs\\\":200},\\\"remappings\\\":[]},\\\"sources\\\":{\\\"/Users/aristotelistriantafyllidis/Documents/agents-research/erc1155/contracts/Migrations.sol\\\":{\\\"keccak256\\\":\\\"0xfdb731592344e2a2890faf03baec7b4bee7057ffba18ba6dbb6eec8db85f8f4c\\\",\\\"urls\\\":[\\\"bzzr://ddc8801d0a2a7220c2c9bf3881b4921817e72fdd96827ec8be4428fa009ace07\\\"]}},\\\"version\\\":1}\",\n  \"bytecode\": \"0x608060405234801561001057600080fd5b5060008054600160a060020a03191633179055610230806100326000396000f3fe608060405234801561001057600080fd5b5060043610610068577c010000000000000000000000000000000000000000000000000000000060003504630900f010811461006d578063445df0ac146100a25780638da5cb5b146100bc578063fdacd576146100ed575b600080fd5b6100a06004803603602081101561008357600080fd5b503573ffffffffffffffffffffffffffffffffffffffff1661010a565b005b6100aa6101bd565b60408051918252519081900360200190f35b6100c46101c3565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b6100a06004803603602081101561010357600080fd5b50356101df565b60005473ffffffffffffffffffffffffffffffffffffffff163314156101ba5760008190508073ffffffffffffffffffffffffffffffffffffffff1663fdacd5766001546040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180828152602001915050600060405180830381600087803b1580156101a057600080fd5b505af11580156101b4573d6000803e3d6000fd5b50505050505b50565b60015481565b60005473ffffffffffffffffffffffffffffffffffffffff1681565b60005473ffffffffffffffffffffffffffffffffffffffff163314156101ba5760015556fea165627a7a7230582065546060ae2694c0faa5ae3a86876c1f4f60c32218234b846e28adec7370506c0029\",\n  \"deployedBytecode\": \"0x608060405234801561001057600080fd5b5060043610610068577c010000000000000000000000000000000000000000000000000000000060003504630900f010811461006d578063445df0ac146100a25780638da5cb5b146100bc578063fdacd576146100ed575b600080fd5b6100a06004803603602081101561008357600080fd5b503573ffffffffffffffffffffffffffffffffffffffff1661010a565b005b6100aa6101bd565b60408051918252519081900360200190f35b6100c46101c3565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b6100a06004803603602081101561010357600080fd5b50356101df565b60005473ffffffffffffffffffffffffffffffffffffffff163314156101ba5760008190508073ffffffffffffffffffffffffffffffffffffffff1663fdacd5766001546040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180828152602001915050600060405180830381600087803b1580156101a057600080fd5b505af11580156101b4573d6000803e3d6000fd5b50505050505b50565b60015481565b60005473ffffffffffffffffffffffffffffffffffffffff1681565b60005473ffffffffffffffffffffffffffffffffffffffff163314156101ba5760015556fea165627a7a7230582065546060ae2694c0faa5ae3a86876c1f4f60c32218234b846e28adec7370506c0029\",\n  \"sourceMap\": \"34:480:0:-;;;123:50;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;150:5:0;:18;;-1:-1:-1;;;;;;150:18:0;158:10;150:18;;;34:480;;;;;;\",\n  \"deployedSourceMap\": \"34:480:0:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;34:480:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;347:165;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;347:165:0;;;;:::i;:::-;;82:36;;;:::i;:::-;;;;;;;;;;;;;;;;58:20;;;:::i;:::-;;;;;;;;;;;;;;;;;;;240:103;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;240:103:0;;:::i;347:165::-;223:5;;;;209:10;:19;205:26;;;409:19;442:11;409:45;;460:8;:21;;;482:24;;460:47;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;460:47:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;460:47:0;;;;230:1;205:26;347:165;:::o;82:36::-;;;;:::o;58:20::-;;;;;;:::o;240:103::-;223:5;;;;209:10;:19;205:26;;;302:24;:36;240:103::o\",\n  \"source\": \"pragma solidity >=0.4.21 <0.6.0;\\n\\ncontract Migrations {\\n  address public owner;\\n  uint public last_completed_migration;\\n\\n  constructor() public {\\n    owner = msg.sender;\\n  }\\n\\n  modifier restricted() {\\n    if (msg.sender == owner) _;\\n  }\\n\\n  function setCompleted(uint completed) public restricted {\\n    last_completed_migration = completed;\\n  }\\n\\n  function upgrade(address new_address) public restricted {\\n    Migrations upgraded = Migrations(new_address);\\n    upgraded.setCompleted(last_completed_migration);\\n  }\\n}\\n\",\n  \"sourcePath\": \"/Users/aristotelistriantafyllidis/Documents/agents-research/erc1155/contracts/Migrations.sol\",\n  \"ast\": {\n    \"absolutePath\": \"/Users/aristotelistriantafyllidis/Documents/agents-research/erc1155/contracts/Migrations.sol\",\n    \"exportedSymbols\": {\n      \"Migrations\": [\n        56\n      ]\n    },\n    \"id\": 57,\n    \"nodeType\": \"SourceUnit\",\n    \"nodes\": [\n      {\n        \"id\": 1,\n        \"literals\": [\n          \"solidity\",\n          \">=\",\n          \"0.4\",\n          \".21\",\n          \"<\",\n          \"0.6\",\n          \".0\"\n        ],\n        \"nodeType\": \"PragmaDirective\",\n        \"src\": \"0:32:0\"\n      },\n      {\n        \"baseContracts\": [],\n        \"contractDependencies\": [],\n        \"contractKind\": \"contract\",\n        \"documentation\": null,\n        \"fullyImplemented\": true,\n        \"id\": 56,\n        \"linearizedBaseContracts\": [\n          56\n        ],\n        \"name\": \"Migrations\",\n        \"nodeType\": \"ContractDefinition\",\n        \"nodes\": [\n          {\n            \"constant\": false,\n            \"id\": 3,\n            \"name\": \"owner\",\n            \"nodeType\": \"VariableDeclaration\",\n            \"scope\": 56,\n            \"src\": \"58:20:0\",\n            \"stateVariable\": true,\n            \"storageLocation\": \"default\",\n            \"typeDescriptions\": {\n              \"typeIdentifier\": \"t_address\",\n              \"typeString\": \"address\"\n            },\n            \"typeName\": {\n              \"id\": 2,\n              \"name\": \"address\",\n              \"nodeType\": \"ElementaryTypeName\",\n              \"src\": \"58:7:0\",\n              \"stateMutability\": \"nonpayable\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_address\",\n                \"typeString\": \"address\"\n              }\n            },\n            \"value\": null,\n            \"visibility\": \"public\"\n          },\n          {\n            \"constant\": false,\n            \"id\": 5,\n            \"name\": \"last_completed_migration\",\n            \"nodeType\": \"VariableDeclaration\",\n            \"scope\": 56,\n            \"src\": \"82:36:0\",\n            \"stateVariable\": true,\n            \"storageLocation\": \"default\",\n            \"typeDescriptions\": {\n              \"typeIdentifier\": \"t_uint256\",\n              \"typeString\": \"uint256\"\n            },\n            \"typeName\": {\n              \"id\": 4,\n              \"name\": \"uint\",\n              \"nodeType\": \"ElementaryTypeName\",\n              \"src\": \"82:4:0\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_uint256\",\n                \"typeString\": \"uint256\"\n              }\n            },\n            \"value\": null,\n            \"visibility\": \"public\"\n          },\n          {\n            \"body\": {\n              \"id\": 13,\n              \"nodeType\": \"Block\",\n              \"src\": \"144:29:0\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 11,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 8,\n                      \"name\": \"owner\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 3,\n                      \"src\": \"150:5:0\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_address\",\n                        \"typeString\": \"address\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 9,\n                        \"name\": \"msg\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 71,\n                        \"src\": \"158:3:0\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_magic_message\",\n                          \"typeString\": \"msg\"\n                        }\n                      },\n                      \"id\": 10,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"memberName\": \"sender\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": null,\n                      \"src\": \"158:10:0\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_address_payable\",\n                        \"typeString\": \"address payable\"\n                      }\n                    },\n                    \"src\": \"150:18:0\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address\",\n                      \"typeString\": \"address\"\n                    }\n                  },\n                  \"id\": 12,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"150:18:0\"\n                }\n              ]\n            },\n            \"documentation\": null,\n            \"id\": 14,\n            \"implemented\": true,\n            \"kind\": \"constructor\",\n            \"modifiers\": [],\n            \"name\": \"\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"parameters\": {\n              \"id\": 6,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"134:2:0\"\n            },\n            \"returnParameters\": {\n              \"id\": 7,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"144:0:0\"\n            },\n            \"scope\": 56,\n            \"src\": \"123:50:0\",\n            \"stateMutability\": \"nonpayable\",\n            \"superFunction\": null,\n            \"visibility\": \"public\"\n          },\n          {\n            \"body\": {\n              \"id\": 22,\n              \"nodeType\": \"Block\",\n              \"src\": \"199:37:0\",\n              \"statements\": [\n                {\n                  \"condition\": {\n                    \"argumentTypes\": null,\n                    \"commonType\": {\n                      \"typeIdentifier\": \"t_address\",\n                      \"typeString\": \"address\"\n                    },\n                    \"id\": 19,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftExpression\": {\n                      \"argumentTypes\": null,\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 16,\n                        \"name\": \"msg\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 71,\n                        \"src\": \"209:3:0\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_magic_message\",\n                          \"typeString\": \"msg\"\n                        }\n                      },\n                      \"id\": 17,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"memberName\": \"sender\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": null,\n                      \"src\": \"209:10:0\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_address_payable\",\n                        \"typeString\": \"address payable\"\n                      }\n                    },\n                    \"nodeType\": \"BinaryOperation\",\n                    \"operator\": \"==\",\n                    \"rightExpression\": {\n                      \"argumentTypes\": null,\n                      \"id\": 18,\n                      \"name\": \"owner\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 3,\n                      \"src\": \"223:5:0\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_address\",\n                        \"typeString\": \"address\"\n                      }\n                    },\n                    \"src\": \"209:19:0\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_bool\",\n                      \"typeString\": \"bool\"\n                    }\n                  },\n                  \"falseBody\": null,\n                  \"id\": 21,\n                  \"nodeType\": \"IfStatement\",\n                  \"src\": \"205:26:0\",\n                  \"trueBody\": {\n                    \"id\": 20,\n                    \"nodeType\": \"PlaceholderStatement\",\n                    \"src\": \"230:1:0\"\n                  }\n                }\n              ]\n            },\n            \"documentation\": null,\n            \"id\": 23,\n            \"name\": \"restricted\",\n            \"nodeType\": \"ModifierDefinition\",\n            \"parameters\": {\n              \"id\": 15,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"196:2:0\"\n            },\n            \"src\": \"177:59:0\",\n            \"visibility\": \"internal\"\n          },\n          {\n            \"body\": {\n              \"id\": 34,\n              \"nodeType\": \"Block\",\n              \"src\": \"296:47:0\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 32,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 30,\n                      \"name\": \"last_completed_migration\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5,\n                      \"src\": \"302:24:0\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 31,\n                      \"name\": \"completed\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 25,\n                      \"src\": \"329:9:0\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"src\": \"302:36:0\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"id\": 33,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"302:36:0\"\n                }\n              ]\n            },\n            \"documentation\": null,\n            \"id\": 35,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [\n              {\n                \"arguments\": null,\n                \"id\": 28,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 27,\n                  \"name\": \"restricted\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 23,\n                  \"src\": \"285:10:0\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$__$\",\n                    \"typeString\": \"modifier ()\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"285:10:0\"\n              }\n            ],\n            \"name\": \"setCompleted\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"parameters\": {\n              \"id\": 26,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 25,\n                  \"name\": \"completed\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"scope\": 35,\n                  \"src\": \"262:14:0\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 24,\n                    \"name\": \"uint\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"262:4:0\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"261:16:0\"\n            },\n            \"returnParameters\": {\n              \"id\": 29,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"296:0:0\"\n            },\n            \"scope\": 56,\n            \"src\": \"240:103:0\",\n            \"stateMutability\": \"nonpayable\",\n            \"superFunction\": null,\n            \"visibility\": \"public\"\n          },\n          {\n            \"body\": {\n              \"id\": 54,\n              \"nodeType\": \"Block\",\n              \"src\": \"403:109:0\",\n              \"statements\": [\n                {\n                  \"assignments\": [\n                    43\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 43,\n                      \"name\": \"upgraded\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"scope\": 54,\n                      \"src\": \"409:19:0\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"default\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_contract$_Migrations_$56\",\n                        \"typeString\": \"contract Migrations\"\n                      },\n                      \"typeName\": {\n                        \"contractScope\": null,\n                        \"id\": 42,\n                        \"name\": \"Migrations\",\n                        \"nodeType\": \"UserDefinedTypeName\",\n                        \"referencedDeclaration\": 56,\n                        \"src\": \"409:10:0\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_contract$_Migrations_$56\",\n                          \"typeString\": \"contract Migrations\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 47,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 45,\n                        \"name\": \"new_address\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 37,\n                        \"src\": \"442:11:0\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        }\n                      ],\n                      \"id\": 44,\n                      \"name\": \"Migrations\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 56,\n                      \"src\": \"431:10:0\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_type$_t_contract$_Migrations_$56_$\",\n                        \"typeString\": \"type(contract Migrations)\"\n                      }\n                    },\n                    \"id\": 46,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"typeConversion\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"431:23:0\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_contract$_Migrations_$56\",\n                      \"typeString\": \"contract Migrations\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"409:45:0\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 51,\n                        \"name\": \"last_completed_migration\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 5,\n                        \"src\": \"482:24:0\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 48,\n                        \"name\": \"upgraded\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 43,\n                        \"src\": \"460:8:0\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_contract$_Migrations_$56\",\n                          \"typeString\": \"contract Migrations\"\n                        }\n                      },\n                      \"id\": 50,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"memberName\": \"setCompleted\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": 35,\n                      \"src\": \"460:21:0\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_external_nonpayable$_t_uint256_$returns$__$\",\n                        \"typeString\": \"function (uint256) external\"\n                      }\n                    },\n                    \"id\": 52,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"460:47:0\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 53,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"460:47:0\"\n                }\n              ]\n            },\n            \"documentation\": null,\n            \"id\": 55,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [\n              {\n                \"arguments\": null,\n                \"id\": 40,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 39,\n                  \"name\": \"restricted\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 23,\n                  \"src\": \"392:10:0\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$__$\",\n                    \"typeString\": \"modifier ()\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"392:10:0\"\n              }\n            ],\n            \"name\": \"upgrade\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"parameters\": {\n              \"id\": 38,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 37,\n                  \"name\": \"new_address\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"scope\": 55,\n                  \"src\": \"364:19:0\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_address\",\n                    \"typeString\": \"address\"\n                  },\n                  \"typeName\": {\n                    \"id\": 36,\n                    \"name\": \"address\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"364:7:0\",\n                    \"stateMutability\": \"nonpayable\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address\",\n                      \"typeString\": \"address\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"363:21:0\"\n            },\n            \"returnParameters\": {\n              \"id\": 41,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"403:0:0\"\n            },\n            \"scope\": 56,\n            \"src\": \"347:165:0\",\n            \"stateMutability\": \"nonpayable\",\n            \"superFunction\": null,\n            \"visibility\": \"public\"\n          }\n        ],\n        \"scope\": 57,\n        \"src\": \"34:480:0\"\n      }\n    ],\n    \"src\": \"0:515:0\"\n  },\n  \"legacyAST\": {\n    \"absolutePath\": \"/Users/aristotelistriantafyllidis/Documents/agents-research/erc1155/contracts/Migrations.sol\",\n    \"exportedSymbols\": {\n      \"Migrations\": [\n        56\n      ]\n    },\n    \"id\": 57,\n    \"nodeType\": \"SourceUnit\",\n    \"nodes\": [\n      {\n        \"id\": 1,\n        \"literals\": [\n          \"solidity\",\n          \">=\",\n          \"0.4\",\n          \".21\",\n          \"<\",\n          \"0.6\",\n          \".0\"\n        ],\n        \"nodeType\": \"PragmaDirective\",\n        \"src\": \"0:32:0\"\n      },\n      {\n        \"baseContracts\": [],\n        \"contractDependencies\": [],\n        \"contractKind\": \"contract\",\n        \"documentation\": null,\n        \"fullyImplemented\": true,\n        \"id\": 56,\n        \"linearizedBaseContracts\": [\n          56\n        ],\n        \"name\": \"Migrations\",\n        \"nodeType\": \"ContractDefinition\",\n        \"nodes\": [\n          {\n            \"constant\": false,\n            \"id\": 3,\n            \"name\": \"owner\",\n            \"nodeType\": \"VariableDeclaration\",\n            \"scope\": 56,\n            \"src\": \"58:20:0\",\n            \"stateVariable\": true,\n            \"storageLocation\": \"default\",\n            \"typeDescriptions\": {\n              \"typeIdentifier\": \"t_address\",\n              \"typeString\": \"address\"\n            },\n            \"typeName\": {\n              \"id\": 2,\n              \"name\": \"address\",\n              \"nodeType\": \"ElementaryTypeName\",\n              \"src\": \"58:7:0\",\n              \"stateMutability\": \"nonpayable\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_address\",\n                \"typeString\": \"address\"\n              }\n            },\n            \"value\": null,\n            \"visibility\": \"public\"\n          },\n          {\n            \"constant\": false,\n            \"id\": 5,\n            \"name\": \"last_completed_migration\",\n            \"nodeType\": \"VariableDeclaration\",\n            \"scope\": 56,\n            \"src\": \"82:36:0\",\n            \"stateVariable\": true,\n            \"storageLocation\": \"default\",\n            \"typeDescriptions\": {\n              \"typeIdentifier\": \"t_uint256\",\n              \"typeString\": \"uint256\"\n            },\n            \"typeName\": {\n              \"id\": 4,\n              \"name\": \"uint\",\n              \"nodeType\": \"ElementaryTypeName\",\n              \"src\": \"82:4:0\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_uint256\",\n                \"typeString\": \"uint256\"\n              }\n            },\n            \"value\": null,\n            \"visibility\": \"public\"\n          },\n          {\n            \"body\": {\n              \"id\": 13,\n              \"nodeType\": \"Block\",\n              \"src\": \"144:29:0\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 11,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 8,\n                      \"name\": \"owner\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 3,\n                      \"src\": \"150:5:0\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_address\",\n                        \"typeString\": \"address\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 9,\n                        \"name\": \"msg\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 71,\n                        \"src\": \"158:3:0\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_magic_message\",\n                          \"typeString\": \"msg\"\n                        }\n                      },\n                      \"id\": 10,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"memberName\": \"sender\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": null,\n                      \"src\": \"158:10:0\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_address_payable\",\n                        \"typeString\": \"address payable\"\n                      }\n                    },\n                    \"src\": \"150:18:0\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address\",\n                      \"typeString\": \"address\"\n                    }\n                  },\n                  \"id\": 12,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"150:18:0\"\n                }\n              ]\n            },\n            \"documentation\": null,\n            \"id\": 14,\n            \"implemented\": true,\n            \"kind\": \"constructor\",\n            \"modifiers\": [],\n            \"name\": \"\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"parameters\": {\n              \"id\": 6,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"134:2:0\"\n            },\n            \"returnParameters\": {\n              \"id\": 7,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"144:0:0\"\n            },\n            \"scope\": 56,\n            \"src\": \"123:50:0\",\n            \"stateMutability\": \"nonpayable\",\n            \"superFunction\": null,\n            \"visibility\": \"public\"\n          },\n          {\n            \"body\": {\n              \"id\": 22,\n              \"nodeType\": \"Block\",\n              \"src\": \"199:37:0\",\n              \"statements\": [\n                {\n                  \"condition\": {\n                    \"argumentTypes\": null,\n                    \"commonType\": {\n                      \"typeIdentifier\": \"t_address\",\n                      \"typeString\": \"address\"\n                    },\n                    \"id\": 19,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftExpression\": {\n                      \"argumentTypes\": null,\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 16,\n                        \"name\": \"msg\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 71,\n                        \"src\": \"209:3:0\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_magic_message\",\n                          \"typeString\": \"msg\"\n                        }\n                      },\n                      \"id\": 17,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"memberName\": \"sender\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": null,\n                      \"src\": \"209:10:0\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_address_payable\",\n                        \"typeString\": \"address payable\"\n                      }\n                    },\n                    \"nodeType\": \"BinaryOperation\",\n                    \"operator\": \"==\",\n                    \"rightExpression\": {\n                      \"argumentTypes\": null,\n                      \"id\": 18,\n                      \"name\": \"owner\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 3,\n                      \"src\": \"223:5:0\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_address\",\n                        \"typeString\": \"address\"\n                      }\n                    },\n                    \"src\": \"209:19:0\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_bool\",\n                      \"typeString\": \"bool\"\n                    }\n                  },\n                  \"falseBody\": null,\n                  \"id\": 21,\n                  \"nodeType\": \"IfStatement\",\n                  \"src\": \"205:26:0\",\n                  \"trueBody\": {\n                    \"id\": 20,\n                    \"nodeType\": \"PlaceholderStatement\",\n                    \"src\": \"230:1:0\"\n                  }\n                }\n              ]\n            },\n            \"documentation\": null,\n            \"id\": 23,\n            \"name\": \"restricted\",\n            \"nodeType\": \"ModifierDefinition\",\n            \"parameters\": {\n              \"id\": 15,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"196:2:0\"\n            },\n            \"src\": \"177:59:0\",\n            \"visibility\": \"internal\"\n          },\n          {\n            \"body\": {\n              \"id\": 34,\n              \"nodeType\": \"Block\",\n              \"src\": \"296:47:0\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 32,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 30,\n                      \"name\": \"last_completed_migration\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5,\n                      \"src\": \"302:24:0\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 31,\n                      \"name\": \"completed\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 25,\n                      \"src\": \"329:9:0\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"src\": \"302:36:0\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"id\": 33,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"302:36:0\"\n                }\n              ]\n            },\n            \"documentation\": null,\n            \"id\": 35,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [\n              {\n                \"arguments\": null,\n                \"id\": 28,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 27,\n                  \"name\": \"restricted\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 23,\n                  \"src\": \"285:10:0\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$__$\",\n                    \"typeString\": \"modifier ()\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"285:10:0\"\n              }\n            ],\n            \"name\": \"setCompleted\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"parameters\": {\n              \"id\": 26,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 25,\n                  \"name\": \"completed\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"scope\": 35,\n                  \"src\": \"262:14:0\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 24,\n                    \"name\": \"uint\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"262:4:0\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"261:16:0\"\n            },\n            \"returnParameters\": {\n              \"id\": 29,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"296:0:0\"\n            },\n            \"scope\": 56,\n            \"src\": \"240:103:0\",\n            \"stateMutability\": \"nonpayable\",\n            \"superFunction\": null,\n            \"visibility\": \"public\"\n          },\n          {\n            \"body\": {\n              \"id\": 54,\n              \"nodeType\": \"Block\",\n              \"src\": \"403:109:0\",\n              \"statements\": [\n                {\n                  \"assignments\": [\n                    43\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 43,\n                      \"name\": \"upgraded\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"scope\": 54,\n                      \"src\": \"409:19:0\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"default\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_contract$_Migrations_$56\",\n                        \"typeString\": \"contract Migrations\"\n                      },\n                      \"typeName\": {\n                        \"contractScope\": null,\n                        \"id\": 42,\n                        \"name\": \"Migrations\",\n                        \"nodeType\": \"UserDefinedTypeName\",\n                        \"referencedDeclaration\": 56,\n                        \"src\": \"409:10:0\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_contract$_Migrations_$56\",\n                          \"typeString\": \"contract Migrations\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 47,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 45,\n                        \"name\": \"new_address\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 37,\n                        \"src\": \"442:11:0\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        }\n                      ],\n                      \"id\": 44,\n                      \"name\": \"Migrations\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 56,\n                      \"src\": \"431:10:0\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_type$_t_contract$_Migrations_$56_$\",\n                        \"typeString\": \"type(contract Migrations)\"\n                      }\n                    },\n                    \"id\": 46,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"typeConversion\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"431:23:0\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_contract$_Migrations_$56\",\n                      \"typeString\": \"contract Migrations\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"409:45:0\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 51,\n                        \"name\": \"last_completed_migration\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 5,\n                        \"src\": \"482:24:0\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 48,\n                        \"name\": \"upgraded\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 43,\n                        \"src\": \"460:8:0\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_contract$_Migrations_$56\",\n                          \"typeString\": \"contract Migrations\"\n                        }\n                      },\n                      \"id\": 50,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"memberName\": \"setCompleted\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": 35,\n                      \"src\": \"460:21:0\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_external_nonpayable$_t_uint256_$returns$__$\",\n                        \"typeString\": \"function (uint256) external\"\n                      }\n                    },\n                    \"id\": 52,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"460:47:0\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 53,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"460:47:0\"\n                }\n              ]\n            },\n            \"documentation\": null,\n            \"id\": 55,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [\n              {\n                \"arguments\": null,\n                \"id\": 40,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 39,\n                  \"name\": \"restricted\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 23,\n                  \"src\": \"392:10:0\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$__$\",\n                    \"typeString\": \"modifier ()\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"392:10:0\"\n              }\n            ],\n            \"name\": \"upgrade\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"parameters\": {\n              \"id\": 38,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 37,\n                  \"name\": \"new_address\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"scope\": 55,\n                  \"src\": \"364:19:0\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_address\",\n                    \"typeString\": \"address\"\n                  },\n                  \"typeName\": {\n                    \"id\": 36,\n                    \"name\": \"address\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"364:7:0\",\n                    \"stateMutability\": \"nonpayable\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address\",\n                      \"typeString\": \"address\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"363:21:0\"\n            },\n            \"returnParameters\": {\n              \"id\": 41,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"403:0:0\"\n            },\n            \"scope\": 56,\n            \"src\": \"347:165:0\",\n            \"stateMutability\": \"nonpayable\",\n            \"superFunction\": null,\n            \"visibility\": \"public\"\n          }\n        ],\n        \"scope\": 57,\n        \"src\": \"34:480:0\"\n      }\n    ],\n    \"src\": \"0:515:0\"\n  },\n  \"compiler\": {\n    \"name\": \"solc\",\n    \"version\": \"0.5.2+commit.1df8f40c.Emscripten.clang\"\n  },\n  \"networks\": {\n    \"1583918911727\": {\n      \"events\": {},\n      \"links\": {},\n      \"address\": \"0xC89Ce4735882C9F0f0FE26686c53074E09B0D550\",\n      \"transactionHash\": \"0xc59b0daeb6b17beb9ea57bb0586fd626fb7b6f092d20bf22406168f7381ac949\"\n    }\n  },\n  \"schemaVersion\": \"3.0.19\",\n  \"updatedAt\": \"2020-03-11T13:47:51.887Z\",\n  \"networkType\": \"ethereum\",\n  \"devdoc\": {\n    \"methods\": {}\n  },\n  \"userdoc\": {\n    \"methods\": {}\n  }\n}"
  },
  {
    "path": "packages/fetchai/contracts/erc1155/build/erc1155.json",
    "content": "{\n  \"contractName\": \"erc1155\",\n  \"abi\": [\n    {\n      \"name\": \"TransferSingle\",\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_operator\",\n          \"indexed\": true\n        },\n        {\n          \"type\": \"address\",\n          \"name\": \"_from\",\n          \"indexed\": true\n        },\n        {\n          \"type\": \"address\",\n          \"name\": \"_to\",\n          \"indexed\": true\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_id\",\n          \"indexed\": false\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_value\",\n          \"indexed\": false\n        }\n      ],\n      \"anonymous\": false,\n      \"type\": \"event\"\n    },\n    {\n      \"name\": \"TransferBatch\",\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_operator\",\n          \"indexed\": true\n        },\n        {\n          \"type\": \"address\",\n          \"name\": \"_from\",\n          \"indexed\": true\n        },\n        {\n          \"type\": \"address\",\n          \"name\": \"_to\",\n          \"indexed\": true\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_ids\",\n          \"indexed\": false\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_values\",\n          \"indexed\": false\n        }\n      ],\n      \"anonymous\": false,\n      \"type\": \"event\"\n    },\n    {\n      \"name\": \"ApprovalForAll\",\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_owner\",\n          \"indexed\": true\n        },\n        {\n          \"type\": \"address\",\n          \"name\": \"_operator\",\n          \"indexed\": true\n        },\n        {\n          \"type\": \"bool\",\n          \"name\": \"_approved\",\n          \"indexed\": false\n        }\n      ],\n      \"anonymous\": false,\n      \"type\": \"event\"\n    },\n    {\n      \"name\": \"URI\",\n      \"inputs\": [\n        {\n          \"type\": \"string\",\n          \"name\": \"_value\",\n          \"indexed\": false\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_id\",\n          \"indexed\": true\n        }\n      ],\n      \"anonymous\": false,\n      \"type\": \"event\"\n    },\n    {\n      \"outputs\": [],\n      \"inputs\": [],\n      \"constant\": false,\n      \"payable\": false,\n      \"type\": \"constructor\"\n    },\n    {\n      \"name\": \"getAddress\",\n      \"outputs\": [\n        {\n          \"type\": \"bytes32\",\n          \"name\": \"out\"\n        }\n      ],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_addr\"\n        }\n      ],\n      \"constant\": true,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 370\n    },\n    {\n      \"name\": \"getHash\",\n      \"outputs\": [\n        {\n          \"type\": \"bytes32\",\n          \"name\": \"out\"\n        }\n      ],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_from\"\n        },\n        {\n          \"type\": \"address\",\n          \"name\": \"_to\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_ids\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_from_supplies\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_to_supplies\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_value_eth\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_nonce\"\n        }\n      ],\n      \"constant\": true,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 11446\n    },\n    {\n      \"name\": \"getSingleHash\",\n      \"outputs\": [\n        {\n          \"type\": \"bytes32\",\n          \"name\": \"out\"\n        }\n      ],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_from\"\n        },\n        {\n          \"type\": \"address\",\n          \"name\": \"_to\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_id\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_from_supply\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_to_supply\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_value_eth\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_nonce\"\n        }\n      ],\n      \"constant\": true,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 2041\n    },\n    {\n      \"name\": \"supportsInterface\",\n      \"outputs\": [\n        {\n          \"type\": \"bool\",\n          \"name\": \"out\"\n        }\n      ],\n      \"inputs\": [\n        {\n          \"type\": \"bytes32\",\n          \"name\": \"_interfaceID\"\n        }\n      ],\n      \"constant\": true,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 868\n    },\n    {\n      \"name\": \"is_nonce_used\",\n      \"outputs\": [\n        {\n          \"type\": \"bool\",\n          \"name\": \"out\"\n        }\n      ],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"addr\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"nonce\"\n        }\n      ],\n      \"constant\": true,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 1052\n    },\n    {\n      \"name\": \"is_token_id_exists\",\n      \"outputs\": [\n        {\n          \"type\": \"bool\",\n          \"name\": \"out\"\n        }\n      ],\n      \"inputs\": [\n        {\n          \"type\": \"uint256\",\n          \"name\": \"token_id\"\n        }\n      ],\n      \"constant\": true,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 928\n    },\n    {\n      \"name\": \"safeTransferFrom\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_from\"\n        },\n        {\n          \"type\": \"address\",\n          \"name\": \"_to\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_id\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_value\"\n        },\n        {\n          \"type\": \"bytes\",\n          \"name\": \"_data\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 80803\n    },\n    {\n      \"name\": \"safeBatchTransferFrom\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_from\"\n        },\n        {\n          \"type\": \"address\",\n          \"name\": \"_to\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_ids\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_values\"\n        },\n        {\n          \"type\": \"bytes\",\n          \"name\": \"_data\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 748184\n    },\n    {\n      \"name\": \"balanceOf\",\n      \"outputs\": [\n        {\n          \"type\": \"uint256\",\n          \"name\": \"out\"\n        }\n      ],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_owner\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_id\"\n        }\n      ],\n      \"constant\": true,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 1172\n    },\n    {\n      \"name\": \"balanceOfBatch\",\n      \"outputs\": [\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"out\"\n        }\n      ],\n      \"inputs\": [\n        {\n          \"type\": \"address[10]\",\n          \"name\": \"_owner\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_ids\"\n        }\n      ],\n      \"constant\": true,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 7524\n    },\n    {\n      \"name\": \"setApprovalForAll\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_operator\"\n        },\n        {\n          \"type\": \"bool\",\n          \"name\": \"_approved\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 38136\n    },\n    {\n      \"name\": \"isApprovedForAll\",\n      \"outputs\": [\n        {\n          \"type\": \"bool\",\n          \"name\": \"out\"\n        }\n      ],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_owner\"\n        },\n        {\n          \"type\": \"address\",\n          \"name\": \"_operator\"\n        }\n      ],\n      \"constant\": true,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 1301\n    },\n    {\n      \"name\": \"createSingle\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_item_owner\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_id\"\n        },\n        {\n          \"type\": \"string\",\n          \"name\": \"_path\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 597461\n    },\n    {\n      \"name\": \"createBatch\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_items_owner\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_ids\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 927926\n    },\n    {\n      \"name\": \"mint\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_to\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_id\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_supply\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": false,\n      \"type\": \"function\"\n    },\n    {\n      \"name\": \"mint\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_to\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_id\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_supply\"\n        },\n        {\n          \"type\": \"bytes\",\n          \"name\": \"_data\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": false,\n      \"type\": \"function\"\n    },\n    {\n      \"name\": \"mintBatch\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_to\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_ids\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_supplies\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": false,\n      \"type\": \"function\"\n    },\n    {\n      \"name\": \"mintBatch\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_to\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_ids\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_supplies\"\n        },\n        {\n          \"type\": \"bytes\",\n          \"name\": \"_data\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": false,\n      \"type\": \"function\"\n    },\n    {\n      \"name\": \"burn\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_id\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_supply\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 40353\n    },\n    {\n      \"name\": \"burnBatch\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_ids\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_supplies\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 382149\n    },\n    {\n      \"name\": \"tradeBatch\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_from\"\n        },\n        {\n          \"type\": \"address\",\n          \"name\": \"_to\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_ids\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_from_supplies\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_to_supplies\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_value_eth\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_nonce\"\n        },\n        {\n          \"type\": \"bytes\",\n          \"name\": \"_signature\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": true,\n      \"type\": \"function\"\n    },\n    {\n      \"name\": \"tradeBatch\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_from\"\n        },\n        {\n          \"type\": \"address\",\n          \"name\": \"_to\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_ids\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_from_supplies\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_to_supplies\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_value_eth\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_nonce\"\n        },\n        {\n          \"type\": \"bytes\",\n          \"name\": \"_signature\"\n        },\n        {\n          \"type\": \"bytes\",\n          \"name\": \"_data\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": true,\n      \"type\": \"function\"\n    },\n    {\n      \"name\": \"trade\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_from\"\n        },\n        {\n          \"type\": \"address\",\n          \"name\": \"_to\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_id\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_from_supply\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_to_supply\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_value_eth\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_nonce\"\n        },\n        {\n          \"type\": \"bytes\",\n          \"name\": \"_signature\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": true,\n      \"type\": \"function\"\n    },\n    {\n      \"name\": \"trade\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_from\"\n        },\n        {\n          \"type\": \"address\",\n          \"name\": \"_to\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_id\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_from_supply\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_to_supply\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_value_eth\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_nonce\"\n        },\n        {\n          \"type\": \"bytes\",\n          \"name\": \"_signature\"\n        },\n        {\n          \"type\": \"bytes\",\n          \"name\": \"_data\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": true,\n      \"type\": \"function\"\n    },\n    {\n      \"name\": \"owner\",\n      \"outputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"out\"\n        }\n      ],\n      \"inputs\": [],\n      \"constant\": true,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 1263\n    }\n  ],\n  \"bytecode\": \"0x740100000000000000000000000000000000000000006020526f7fffffffffffffffffffffffffffffff6040527fffffffffffffffffffffffffffffffff8000000000000000000000000000000060605274012a05f1fffffffffffffffffffffffffdabf41c006080527ffffffffffffffffffffffffed5fa0e000000000000000000000000000000000060a052341561009857600080fd5b6000600155600160006301ffc9a760e05260c052604060c020556001600063d9b67a2660e05260c052604060c020553360025561405a56600035601c52740100000000000000000000000000000000000000006020526f7fffffffffffffffffffffffffffffff6040527fffffffffffffffffffffffffffffffff8000000000000000000000000000000060605274012a05f1fffffffffffffffffffffffffdabf41c006080527ffffffffffffffffffffffffed5fa0e000000000000000000000000000000000060a05263ae22c57d60005114156100d45734156100ac57600080fd5b60043560205181106100bd57600080fd5b50600435610140526101405160005260206000f350005b600015610313575b610580526101405261016052610180526101a0526101c0526101e05261020052610220526102405261026052610280526102a0526102c0526102e05261030052610320526103405261036052610380526103a0526103c0526103e05261040052610420526104405261046052610480526104a0526104c0526104e052610500526105205261054052610560526000610180516020826105c00101526020810190506102c0516020826105c0010152602081019050610400516020826105c0010152602081019050806105c0526105c090508051602082012090506105a0526106606000600a818352015b610660511515156102765760006105a05160208261068001015260208101905061018061066051600a81106101fa57600080fd5b60200201516020826106800101526020810190506102c061066051600a811061022257600080fd5b602002015160208261068001015260208101905061040061066051600a811061024a57600080fd5b6020020151602082610680010152602081019050806106805261068090508051602082012090506105a0525b5b81516001018083528114156101c6575b5050600061014051602082610760010152602081019050610160516020826107600101526020810190506105a0516020826107600101526020810190506105405160208261076001015260208101905061056051602082610760010152602081019050806107605261076090508051602082012090506107405261074051600052600051610580515650005b634a6f823360005114156105c457341561032c57600080fd5b600435602051811061033d57600080fd5b50602435602051811061034f57600080fd5b506000610120525b602061012051016101205261012061012051101561037457610357565b6000610120525b60206101205101610120526101206101205110156103985761037b565b6000610120525b60206101205101610120526101206101205110156103bc5761039f565b6373ad25716101405260043561016052602435610180526101a0604480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250506102e061018480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250506104206102c480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250506104043561056052610424356105805261058051610560516105405161052051610500516104e0516104c0516104a05161048051610460516104405161042051610400516103e0516103c0516103a05161038051610360516103405161032051610300516102e0516102c0516102a05161028051610260516102405161022051610200516101e0516101c0516101a0516101805161016051600658016100dc565b6105e0526105e05160005260206000f350005b600015610909575b610580526101405261016052610180526101a0526101c0526101e05261020052610220526102405261026052610280526102a0526102c0526102e05261030052610320526103405261036052610380526103a0526103c0526103e05261040052610420526104405261046052610480526104a0526104c0526104e052610500526105205261054052610560526000610140516020826105c0010152602081019050610160516020826105c0010152602081019050610180516020826105c00101526020810190506101a0516020826105c00101526020810190506101c0516020826105c00101526020810190506101e0516020826105c0010152602081019050610200516020826105c0010152602081019050610220516020826105c0010152602081019050610240516020826105c0010152602081019050610260516020826105c0010152602081019050610280516020826105c00101526020810190506102a0516020826105c00101526020810190506102c0516020826105c00101526020810190506102e0516020826105c0010152602081019050610300516020826105c0010152602081019050610320516020826105c0010152602081019050610340516020826105c0010152602081019050610360516020826105c0010152602081019050610380516020826105c00101526020810190506103a0516020826105c00101526020810190506103c0516020826105c00101526020810190506103e0516020826105c0010152602081019050610400516020826105c0010152602081019050610420516020826105c0010152602081019050610440516020826105c0010152602081019050610460516020826105c0010152602081019050610480516020826105c00101526020810190506104a0516020826105c00101526020810190506104c0516020826105c00101526020810190506104e0516020826105c0010152602081019050610500516020826105c0010152602081019050610520516020826105c0010152602081019050610540516020826105c0010152602081019050610560516020826105c0010152602081019050806105c0526105c090508051602082012090506105a0526105a051600052600051610580515650005b6000156109e1575b610220526101405261016052610180526101a0526101c0526101e0526102005260006101405160208261026001015260208101905061016051602082610260010152602081019050610180516020826102600101526020810190506101a0516020826102600101526020810190506101c0516020826102600101526020810190506101e05160208261026001015260208101905061020051602082610260010152602081019050806102605261026090508051602082012090506102405261024051600052600051610220515650005b6310660e866000511415610a905734156109fa57600080fd5b6004356020518110610a0b57600080fd5b506024356020518110610a1d57600080fd5b5063155960636101405260043561016052602435610180526044356101a0526064356101c0526084356101e05260a4356102005260c4356102205261022051610200516101e0516101c0516101a051610180516101605160065801610911565b610280526102805160005260206000f350005b600015610cf2575b6101805261014052610160526101a0526000610240525b6101a05160206001820306601f820103905061024051101515610ad157610aea565b610240516101c001526102405160200161024052610aaf565b60005060416101a0511815610b0757600060005260005161018051565b6101a0602060006020835103811315610b1f57600080fd5b046020026020018101519050610280526101a0602060206020835103811315610b4757600080fd5b0460200260200181015190506102a05260406001602082066103a0016101a0518284011115610b7557600080fd5b6041806103c0826020602088068803016101a001600060046018f1505081815280905090509050806020015160008251806020901315610bb457600080fd5b8091901215610bc257600080fd5b606051816020036101000a830480604051901315610bdf57600080fd5b8091901215610bed57600080fd5b9050905090506102c052601b6102c0511215610c30576102c0606051601b82510180604051901315610c1e57600080fd5b8091901215610c2c57600080fd5b8152505b610480601b8152601c81602001525060006104605261046061012060006002818352015b6101205160200261048001516102c0511415610c735760018352610c84565b5b8151600101808352811415610c54575b5050506104605160011415610ce257610140516104c0526102c0516000811215610cad57600080fd5b6104e05261028051610500526102a05161052052602060c060806104c060006001610bb8f15060c05160005260005161018051565b6000600052600051610180515650005b600015610db3575b6101605261014052610140517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff806000811215610d3e578060000360020a8204610d45565b8060020a82025b90509050604051811115610d5857600080fd5b61018052700100000000000000000000000000000000610d7757600080fd5b7001000000000000000000000000000000006101405106604051811115610d9d57600080fd5b6101a05261018051600052600051610160515650005b63f17535506000511415610de8573415610dcc57600080fd5b600060043560e05260c052604060c0205460005260206000f350005b63ac2a2e216000511415610e3d573415610e0157600080fd5b6004356020518110610e1257600080fd5b50600460043560e05260c052604060c02060243560e05260c052604060c0205460005260206000f350005b634026b7556000511415610e72573415610e5657600080fd5b600760043560e05260c052604060c0205460005260206000f350005b63f242432a6000511415611135573415610e8b57600080fd5b6004356020518110610e9c57600080fd5b506024356020518110610eae57600080fd5b5061012060843560040161014037610100608435600401351115610ed157600080fd5b600660043560e05260c052604060c0203360e05260c052604060c02054336004351417610efd57600080fd5b6308c379a06102805260206102a05260206102c0527f43616e6e6f74207472616e7366657220746f207a65726f20616464726573732e6102e0526102c050600060243518610f4c57608461029cfd5b6308c379a0610320526020610340526012610360527f4e6f7420656e6f75676820746f6b656e732e00000000000000000000000000006103805261036050606435600360043560e05260c052604060c02060443560e05260c052604060c020541015610fb957608461033cfd5b600360043560e05260c052604060c02060443560e05260c052604060c02060643581541015610fe757600080fd5b606435815403815550600360243560e05260c052604060c02060443560e05260c052604060c0208054606435825401101561102157600080fd5b6064358154018155506044356103c0526064356103e052602435600435337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6260406103c0a460006024353b1115611133576024353b61107f57600080fd5b602435301861108d57600080fd5b60206106406101c460a063f23a6e6161042052336104405260043561046052604435610480526064356104a052806104c052610140808051602001808461044001828460006004600a8704601201f16110e557600080fd5b50508051820160206001820306601f820103905060200191505061043c905060006024355af161111457600080fd5b600050610640516104005263f23a6e61610400511461113257600080fd5b5b005b63cf36e535600051141561163c57341561114e57600080fd5b600435602051811061115f57600080fd5b50602435602051811061117157600080fd5b506000610120525b602061012051016101205261012061012051101561119657611179565b6000610120525b60206101205101610120526101206101205110156111ba5761119d565b6101206102c435600401610140376101006102c4356004013511156111de57600080fd5b600660043560e05260c052604060c0203360e05260c052604060c0205433600435141761120a57600080fd5b6308c379a06102805260206102a05260206102c0527f43616e6e6f74207472616e7366657220746f207a65726f20616464726573732e6102e0526102c05060006024351861125957608461029cfd5b6103206000600a818352015b604461032051600a811061127857600080fd5b60200201356103405261018461032051600a811061129557600080fd5b6020020135600360043560e05260c052604060c0206103405160e05260c052604060c0205410156112c557600080fd5b5b8151600101808352811415611265575b505060443561036052606435610380526084356103a05260a4356103c05260c4356103e05260e435610400526101043561042052610124356104405261014435610460526101643561048052610184356104a0526101a4356104c0526101c4356104e0526101e435610500526102043561052052610224356105405261024435610560526102643561058052610284356105a0526102a4356105c052602435600435337f514c24e4790d7c31a095a1688a73a01f28d936a9a85d806ba95970d8ee88efa8610280610360a46105e06000600a818352015b60446105e051600a81106113c057600080fd5b602002013561060052600360043560e05260c052604060c0206106005160e05260c052604060c0206101846105e051600a81106113fc57600080fd5b60200201358154101561140e57600080fd5b6101846105e051600a811061142257600080fd5b6020020135815403815550600360243560e05260c052604060c0206106005160e05260c052604060c02080546101846105e051600a811061146257600080fd5b6020020135825401101561147557600080fd5b6101846105e051600a811061148957600080fd5b60200201358154018155505b81516001018083528114156113ad575b505060006024353b111561163a576024353b6114c057600080fd5b60243530186114ce57600080fd5b6020610aa06104046102e063a3bfc206610640523361066052600435610680526106a0604480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250506107e061018480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250508061092052610140808051602001808461066001828460006004600a8704601201f16115ec57600080fd5b50508051820160206001820306601f820103905060200191505061065c905060006024355af161161b57600080fd5b600050610aa0516106205263e324a00d610620511461163957600080fd5b5b005b62fdd58e600051141561169057341561165457600080fd5b600435602051811061166557600080fd5b50600360043560e05260c052604060c02060243560e05260c052604060c0205460005260206000f350005b63fbe31aea60005114156117935734156116a957600080fd5b6000610120525b610120516004013560205181106116c657600080fd5b5060206101205101610120526101206101205110156116e4576116b0565b6000610120525b6020610120510161012052610120610120511015611708576116eb565b6102806000600a818352015b6003600461028051600a811061172957600080fd5b602002013560e05260c052604060c02061014461028051600a811061174d57600080fd5b602002013560e05260c052604060c0205461014061028051600a811061177257600080fd5b60200201525b8151600101808352811415611714575b5050610140610140f3005b63a22cb46560005114156118235734156117ac57600080fd5b60043560205181106117bd57600080fd5b50602435600281106117ce57600080fd5b5060243560063360e05260c052604060c02060043560e05260c052604060c0205560243561014052600435337f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c316020610140a3005b63e985e9c5600051141561188a57341561183c57600080fd5b600435602051811061184d57600080fd5b50602435602051811061185f57600080fd5b50600660043560e05260c052604060c02060243560e05260c052604060c0205460005260206000f350005b63a70b070f6000511415611af85734156118a357600080fd5b60043560205181106118b457600080fd5b50610120604435600401610140376101006044356004013511156118d757600080fd5b6000600435186118e657600080fd5b6308c379a06102805260206102a052601b6102c0527f4f776e6572206f6e6c792063616e20637265617465206974656d2e00000000006102e0526102c050336002541461193457608461029cfd5b6000600360043560e05260c052604060c02060243560e05260c052604060c02055600180546001825401101561196957600080fd5b60018154018155506001600760243560e05260c052604060c0205561014080600560243560e05260c052604060c02060c052602060c020602082510161012060006009818352015b826101205160200211156119c4576119e6565b61012051602002850151610120518501555b81516001018083528114156119b1575b50505050505060206103405261034051610380526101408051602001806103405161038001828460006004600a8704601201f1611a2257600080fd5b5050610320610340516103800151610440818352015b610440610320511115611a4a57611a6b565b600061032051610340516103a00101535b8151600101808352811415611a38575b5050602061034051610380015160206001820306601f8201039050610340510101610340526024357f6bb7ff708619ba0610cba295a58592e0451dee2622938c8755667688daf3529b61034051610380a26024356103a05260006103c0526004356000337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6260406103a0a4005b6319a35d7c6000511415611d43573415611b1157600080fd5b6004356020518110611b2257600080fd5b506000610120525b6020610120510161012052610120610120511015611b4757611b2a565b600060043518611b5657600080fd5b6308c379a061014052602061016052601c610180527f4f776e6572206f6e6c792063616e20637265617465206974656d732e000000006101a052610180503360025414611ba457608461015cfd5b6101e06000600a818352015b60246101e051600a8110611bc357600080fd5b6020020135610200526000600360043560e05260c052604060c0206102005160e05260c052604060c020556001805460018254011015611c0257600080fd5b6001815401815550600160076102005160e05260c052604060c020555b8151600101808352811415611bb0575b5050610220600081526000816020015260008160400152600081606001526000816080015260008160a0015260008160c0015260008160e00152600081610100015260008161012001525060243561036052604435610380526064356103a0526084356103c05260a4356103e05260c4356104005260e43561042052610104356104405261012435610460526101443561048052610220516104a052610240516104c052610260516104e05261028051610500526102a051610520526102c051610540526102e051610560526103005161058052610320516105a052610340516105c0526004356000337f514c24e4790d7c31a095a1688a73a01f28d936a9a85d806ba95970d8ee88efa8610280610360a4005b63156e29f66000511415611d8157600061028052610280805160200180610140828460006004600a8704601201f1611d7a57600080fd5b5050611dce565b63731133e96000511415611dc65761012060643560040161014037610100606435600401351115611db157600080fd5b61014060643560040161014037600050611dce565b60001561208a575b3415611dd957600080fd5b6004356020518110611dea57600080fd5b50600060043518611dfa57600080fd5b6308c379a06102c05260206102e052601a610300527f4f776e6572206f6e6c792063616e206d696e74206974656d732e00000000000061032052610300503360025414611e485760846102dcfd5b610140610380525b61038051516020610380510161038052610380610380511015611e7257611e50565b6320171bef6103a0526024356103c0526103c05160065801610cfa565b61042052610360610380525b6103805152602061038051036103805261014061038051101515611ebe57611e9b565b6104205161036052600261036051146001610360511417611ede57600080fd5b6001610360511415611f5f576308c379a0610440526020610460526028610480527f43616e6e6f74206d696e74204e46542077697468205f737570706c79206d6f726104a0527f65207468616e20310000000000000000000000000000000000000000000000006104c05261048050600160443514611f5e5760a461045cfd5b5b604435600360043560e05260c052604060c02060243560e05260c052604060c0205560243561050052604435610520526004356000337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f626040610500a460006004353b1115612088576004353b611fd557600080fd5b6004353018611fe357600080fd5b60206107806101c460a063f23a6e6161056052336105805260006105a0526024356105c0526044356105e0528061060052610140808051602001808461058001828460006004600a8704601201f161203a57600080fd5b50508051820160206001820306601f820103905060200191505061057c905060006004355af161206957600080fd5b600050610780516105405263f23a6e61610540511461208757600080fd5b5b005b63c671854d60005114156120c857600061028052610280805160200180610140828460006004600a8704601201f16120c157600080fd5b5050612118565b63b07e58756000511415612110576101206102a435600401610140376101006102a4356004013511156120fa57600080fd5b6101406102a43560040161014037600050612118565b6000156124f6575b341561212357600080fd5b600435602051811061213457600080fd5b506000610120525b60206101205101610120526101206101205110156121595761213c565b6000610120525b602061012051016101205261012061012051101561217d57612160565b60006004351861218c57600080fd5b6308c379a06102c05260206102e052601a610300527f4f776e6572206f6e6c792063616e206d696e74206974656d732e000000000000610320526103005033600254146121da5760846102dcfd5b6103606000600a818352015b602461036051600a81106121f957600080fd5b6020020135610380526101406103c0525b6103c0515160206103c051016103c0526103c06103c051101561222c5761220a565b6320171bef6103e05261038051610400526104005160065801610cfa565b610460526103a06103c0525b6103c0515260206103c051036103c0526101406103c05110151561227957612256565b610460516103a05260026103a0511460016103a051141761229957600080fd5b60016103a05114156122cb57600161016461036051600a81106122bb57600080fd5b6020020135146122ca57600080fd5b5b61016461036051600a81106122df57600080fd5b6020020135600360043560e05260c052604060c0206103805160e05260c052604060c020555b81516001018083528114156121e6575b5050602435610480526044356104a0526064356104c0526084356104e05260a4356105005260c4356105205260e4356105405261010435610560526101243561058052610144356105a052610164356105c052610184356105e0526101a435610600526101c435610620526101e4356106405261020435610660526102243561068052610244356106a052610264356106c052610284356106e0526004356000337f514c24e4790d7c31a095a1688a73a01f28d936a9a85d806ba95970d8ee88efa8610280610480a46107006000600a818352015b60006004353b11156124e1576004353b61240357600080fd5b600435301861241157600080fd5b60206109606101c460a063f23a6e61610740523361076052600061078052602461070051600a811061244257600080fd5b60200201356107a05261016461070051600a811061245f57600080fd5b60200201356107c052806107e052610140808051602001808461076001828460006004600a8704601201f161249357600080fd5b50508051820160206001820306601f820103905060200191505061075c905060006004355af16124c257600080fd5b600050610960516107205263f23a6e6161072051146124e057600080fd5b5b5b81516001018083528114156123ea575b5050005b63b390c0ab60005114156125ea57341561250f57600080fd5b6308c379a061014052602061016052601a610180527f4e6f7420656e6f75676820746f6b656e7320746f206275726e2e0000000000006101a0526101805060243560033360e05260c052604060c02060043560e05260c052604060c02054101561257a57608461015cfd5b60033360e05260c052604060c02060043560e05260c052604060c020602435815410156125a657600080fd5b6024358154038155506004356101e05260243561020052600033337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6260406101e0a4005b63b59afe52600051141561282b57341561260357600080fd5b6000610120525b60206101205101610120526101206101205110156126275761260a565b6000610120525b602061012051016101205261012061012051101561264b5761262e565b6101406000600a818352015b600461014051600a811061266a57600080fd5b60200201356101605261014461014051600a811061268757600080fd5b602002013560033360e05260c052604060c0206101605160e05260c052604060c0205410156126b557600080fd5b5b8151600101808352811415612657575b50506101806000600a818352015b600461018051600a81106126e757600080fd5b60200201356101a05260033360e05260c052604060c0206101a05160e05260c052604060c02061014461018051600a811061272157600080fd5b60200201358154101561273357600080fd5b61014461018051600a811061274757600080fd5b60200201358154038155505b81516001018083528114156126d4575b50506004356101c0526024356101e05260443561020052606435610220526084356102405260a4356102605260c4356102805260e4356102a052610104356102c052610124356102e0526101443561030052610164356103205261018435610340526101a435610360526101c435610380526101e4356103a052610204356103c052610224356103e05261024435610400526102643561042052600033337f514c24e4790d7c31a095a1688a73a01f28d936a9a85d806ba95970d8ee88efa86102806101c0a4005b63f2526ada6000511415612869576000610320526103208051602001806101e0828460006004600a8704601201f161286257600080fd5b50506128b9565b63a835c36960005114156128b157610120610464356004016101e0376101006104643560040135111561289b57600080fd5b610140610464356004016101e0376000506128b9565b600015613725575b60043560205181106128ca57600080fd5b5060243560205181106128dc57600080fd5b506000610120525b6020610120510161012052610120610120511015612901576128e4565b6000610120525b602061012051016101205261012061012051101561292557612908565b6000610120525b60206101205101610120526101206101205110156129495761292c565b6061610444356004016101403760416104443560040135111561296b57600080fd5b6308c379a061036052602061038052602c6103a0527f5f66726f6d206d757374206265207468652073656e646572206f7220617070726103c0527f6f766564206164647265737300000000000000000000000000000000000000006103e0526103a050600660043560e05260c052604060c0203360e05260c052604060c020543360043514176129fc5760a461037cfd5b6308c379a0610420526020610440526025610460527f44657374696e6174696f6e2061646472657373206d757374206265206e6f6e2d610480527f7a65726f2e0000000000000000000000000000000000000000000000000000006104a05261046050600060243518612a705760a461043cfd5b6308c379a06104e0526020610500526015610520527f4e6f6e6365206d75737420626520756e757365642e00000000000000000000006105405261052050600460043560e05260c052604060c0206104243560e05260c052604060c0205415612ada5760846104fcfd5b6308c379a06105805260206105a05260256105c0527f53656e64657220686173206e6f742070726f766964656420656e6f75676820656105e0527f746865722e000000000000000000000000000000000000000000000000000000610600526105c050346104043514612b4e5760a461059cfd5b6106406000600a818352015b604461064051600a8110612b6d57600080fd5b602002013561066052600061018461064051600a8110612b8c57600080fd5b60200201351115612c03576102c461064051600a8110612bab57600080fd5b602002013515612bba57600080fd5b61018461064051600a8110612bce57600080fd5b6020020135600360043560e05260c052604060c0206106605160e05260c052604060c020541015612bfe57600080fd5b612c6b565b61018461064051600a8110612c1757600080fd5b602002013515612c2657600080fd5b6102c461064051600a8110612c3a57600080fd5b6020020135600360243560e05260c052604060c0206106605160e05260c052604060c020541015612c6a57600080fd5b5b5b8151600101808352811415612b5a575b50506101406106a0525b6106a0515160206106a051016106a0526106a06106a0511015612ca857612c86565b6373ad25716106c0526004356106e05260243561070052610720604480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e00152806101000135826101000152806101200135826101200152505061086061018480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250506109a06102c480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e00152806101000135826101000152806101200135826101200152505061040435610ae05261042435610b0052610b0051610ae051610ac051610aa051610a8051610a6051610a4051610a2051610a00516109e0516109c0516109a05161098051610960516109405161092051610900516108e0516108c0516108a05161088051610860516108405161082051610800516107e0516107c0516107a05161078051610760516107405161072051610700516106e051600658016100dc565b610b60526106806106a0525b6106a0515260206106a051036106a0526101406106a051101515612ecc57612ea9565b610b605161068052610140610ba0525b610ba051516020610ba05101610ba052610ba0610ba0511015612efe57612edc565b6040636f868168610bc05261068051610be05280610c00526101408080516020018084610be001828460006004600a8704601201f1612f3c57600080fd5b50508051820160206001820306601f820103905060200191505050610c005180610be00180518060206001820306601f82010390508201610ce0525050505b610c20610ce0511015612f8d57612fa2565b610ce051516020610ce05103610ce052612f7b565b610c0051610be05160065801610a98565b610d0052610b80610ba0525b610ba051526020610ba05103610ba052610140610ba051101515612fe257612fbf565b610d0051610b80526308c379a0610d20526020610d40526020610d60527f5369676e657220646f6573206e6f74206d61746368207369676e61747572652e610d8052610d6050602435610b80511461303b576084610d3cfd5b600160043360e05260c052604060c0206104243560e05260c052604060c02055610dc06000600a818352015b6044610dc051600a811061307a57600080fd5b6020020135610de0526000610184610dc051600a811061309957600080fd5b6020020135111561317457600360043560e05260c052604060c020610de05160e05260c052604060c020610184610dc051600a81106130d757600080fd5b6020020135815410156130e957600080fd5b610184610dc051600a81106130fd57600080fd5b6020020135815403815550600360243560e05260c052604060c020610de05160e05260c052604060c0208054610184610dc051600a811061313d57600080fd5b6020020135825401101561315057600080fd5b610184610dc051600a811061316457600080fd5b6020020135815401815550613240565b600360043560e05260c052604060c020610de05160e05260c052604060c02080546102c4610dc051600a81106131a957600080fd5b602002013582540110156131bc57600080fd5b6102c4610dc051600a81106131d057600080fd5b6020020135815401815550600360243560e05260c052604060c020610de05160e05260c052604060c0206102c4610dc051600a811061320e57600080fd5b60200201358154101561322057600080fd5b6102c4610dc051600a811061323457600080fd5b60200201358154038155505b5b8151600101808352811415613067575b50506000600060006000346024356000f161326b57600080fd5b604435610e0052606435610e2052608435610e405260a435610e605260c435610e805260e435610ea05261010435610ec05261012435610ee05261014435610f005261016435610f205261018435610f40526101a435610f60526101c435610f80526101e435610fa05261020435610fc05261022435610fe0526102443561100052610264356110205261028435611040526102a43561106052602435600435337f514c24e4790d7c31a095a1688a73a01f28d936a9a85d806ba95970d8ee88efa8610280610e00a4604435611080526064356110a0526084356110c05260a4356110e05260c4356111005260e43561112052610104356111405261012435611160526101443561118052610164356111a0526102c4356111c0526102e4356111e052610304356112005261032435611220526103443561124052610364356112605261038435611280526103a4356112a0526103c4356112c0526103e4356112e052600435602435337f514c24e4790d7c31a095a1688a73a01f28d936a9a85d806ba95970d8ee88efa8610280611080a460006024353b1115613590576024353b61341657600080fd5b602435301861342457600080fd5b60206117806104046102e063a3bfc20661132052336113405260243561136052611380604480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250506114c061018480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e00152806101000135826101000152806101200135826101200152505080611600526101e0808051602001808461134001828460006004600a8704601201f161354257600080fd5b50508051820160206001820306601f820103905060200191505061133c905060006024355af161357157600080fd5b6000506117805161130052630c97e564611300511461358f57600080fd5b5b60006004353b1115613723576004353b6135a957600080fd5b60043530186135b757600080fd5b6020611c206104046102e063a3bfc2066117c052336117e05260043561180052611820604480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250506119606102c480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e00152806101000135826101000152806101200135826101200152505080611aa0526101e080805160200180846117e001828460006004600a8704601201f16136d557600080fd5b50508051820160206001820306601f82010390506020019150506117dc905060006004355af161370457600080fd5b600050611c20516117a052630c97e5646117a0511461372257600080fd5b5b005b636e8205b26000511415613763576000610320526103208051602001806101e0828460006004600a8704601201f161375c57600080fd5b50506137b3565b63183f5ec560005114156137ab57610120610104356004016101e0376101006101043560040135111561379557600080fd5b610140610104356004016101e0376000506137b3565b600015613f5d575b60043560205181106137c457600080fd5b5060243560205181106137d657600080fd5b50606160e43560040161014037604160e4356004013511156137f757600080fd5b600660043560e05260c052604060c0203360e05260c052604060c0205433600435141761382357600080fd5b6308c379a06103605260206103805260256103a0527f44657374696e6174696f6e2061646472657373206d757374206265206e6f6e2d6103c0527f7a65726f2e0000000000000000000000000000000000000000000000000000006103e0526103a0506000602435186138975760a461037cfd5b6308c379a0610420526020610440526015610460527f4e6f6e6365206d75737420626520756e757365642e00000000000000000000006104805261046050600460043560e05260c052604060c02060c43560e05260c052604060c020541561390057608461043cfd5b6308c379a06104c05260206104e0526025610500527f53656e64657220686173206e6f742070726f766964656420656e6f7567682065610520527f746865722e00000000000000000000000000000000000000000000000000000061054052610500503460a435146139735760a46104dcfd5b600060643511156139bd576084351561398b57600080fd5b606435600360043560e05260c052604060c02060443560e05260c052604060c0205410156139b857600080fd5b6139f8565b606435156139ca57600080fd5b608435600360243560e05260c052604060c02060443560e05260c052604060c0205410156139f757600080fd5b5b6101406105a0525b6105a0515160206105a051016105a0526105a06105a0511015613a2257613a00565b63155960636105c0526004356105e0526024356106005260443561062052606435610640526084356106605260a4356106805260c4356106a0526106a05161068051610660516106405161062051610600516105e05160065801610911565b610700526105806105a0525b6105a0515260206105a051036105a0526101406105a051101515613ab057613a8d565b6107005161058052610140610740525b61074051516020610740510161074052610740610740511015613ae257613ac0565b6040636f868168610760526105805161078052806107a052610140808051602001808461078001828460006004600a8704601201f1613b2057600080fd5b50508051820160206001820306601f8201039050602001915050506107a051806107800180518060206001820306601f82010390508201610880525050505b6107c0610880511015613b7157613b86565b61088051516020610880510361088052613b5f565b6107a0516107805160065801610a98565b6108a052610720610740525b6107405152602061074051036107405261014061074051101515613bc657613ba3565b6108a051610720526308c379a06108c05260206108e0526020610900527f5369676e657220646f6573206e6f74206d61746368207369676e61747572652e61092052610900506024356107205114613c1f5760846108dcfd5b600160043360e05260c052604060c02060c43560e05260c052604060c0205560006064351115613cbf57600360043560e05260c052604060c02060443560e05260c052604060c02060643581541015613c7757600080fd5b606435815403815550600360243560e05260c052604060c02060443560e05260c052604060c02080546064358254011015613cb157600080fd5b606435815401815550613d31565b600360043560e05260c052604060c02060443560e05260c052604060c02080546084358254011015613cf057600080fd5b608435815401815550600360243560e05260c052604060c02060443560e05260c052604060c02060843581541015613d2757600080fd5b6084358154038155505b6000600060006000346024356000f1613d4957600080fd5b6044356109605260643561098052602435600435337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f626040610960a46044356109a0526084356109c052600435602435337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6260406109a0a460006024353b1115613e8e576024353b613dda57600080fd5b6024353018613de857600080fd5b6020610c206101c460a063f23a6e61610a005233610a2052602435610a4052604435610a6052606435610a805280610aa0526101e08080516020018084610a2001828460006004600a8704601201f1613e4057600080fd5b50508051820160206001820306601f8201039050602001915050610a1c905060006024355af1613e6f57600080fd5b600050610c20516109e052630c97e5646109e05114613e8d57600080fd5b5b60006004353b1115613f5b576004353b613ea757600080fd5b6004353018613eb557600080fd5b6020610e806101c460a063f23a6e61610c605233610c8052600435610ca052604435610cc052608435610ce05280610d00526101e08080516020018084610c8001828460006004600a8704601201f1613f0d57600080fd5b50508051820160206001820306601f8201039050602001915050610c7c905060006004355af1613f3c57600080fd5b600050610e8051610c4052630c97e564610c405114613f5a57600080fd5b5b005b638da5cb5b6000511415613f84573415613f7657600080fd5b60025460005260206000f350005b60006000fd5b6100d061405a036100d06000396100d061405a036000f3\",\n  \"deployedBytecode\": \"0x600035601c52740100000000000000000000000000000000000000006020526f7fffffffffffffffffffffffffffffff6040527fffffffffffffffffffffffffffffffff8000000000000000000000000000000060605274012a05f1fffffffffffffffffffffffffdabf41c006080527ffffffffffffffffffffffffed5fa0e000000000000000000000000000000000060a05263ae22c57d60005114156100d45734156100ac57600080fd5b60043560205181106100bd57600080fd5b50600435610140526101405160005260206000f350005b600015610313575b610580526101405261016052610180526101a0526101c0526101e05261020052610220526102405261026052610280526102a0526102c0526102e05261030052610320526103405261036052610380526103a0526103c0526103e05261040052610420526104405261046052610480526104a0526104c0526104e052610500526105205261054052610560526000610180516020826105c00101526020810190506102c0516020826105c0010152602081019050610400516020826105c0010152602081019050806105c0526105c090508051602082012090506105a0526106606000600a818352015b610660511515156102765760006105a05160208261068001015260208101905061018061066051600a81106101fa57600080fd5b60200201516020826106800101526020810190506102c061066051600a811061022257600080fd5b602002015160208261068001015260208101905061040061066051600a811061024a57600080fd5b6020020151602082610680010152602081019050806106805261068090508051602082012090506105a0525b5b81516001018083528114156101c6575b5050600061014051602082610760010152602081019050610160516020826107600101526020810190506105a0516020826107600101526020810190506105405160208261076001015260208101905061056051602082610760010152602081019050806107605261076090508051602082012090506107405261074051600052600051610580515650005b634a6f823360005114156105c457341561032c57600080fd5b600435602051811061033d57600080fd5b50602435602051811061034f57600080fd5b506000610120525b602061012051016101205261012061012051101561037457610357565b6000610120525b60206101205101610120526101206101205110156103985761037b565b6000610120525b60206101205101610120526101206101205110156103bc5761039f565b6373ad25716101405260043561016052602435610180526101a0604480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250506102e061018480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250506104206102c480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250506104043561056052610424356105805261058051610560516105405161052051610500516104e0516104c0516104a05161048051610460516104405161042051610400516103e0516103c0516103a05161038051610360516103405161032051610300516102e0516102c0516102a05161028051610260516102405161022051610200516101e0516101c0516101a0516101805161016051600658016100dc565b6105e0526105e05160005260206000f350005b600015610909575b610580526101405261016052610180526101a0526101c0526101e05261020052610220526102405261026052610280526102a0526102c0526102e05261030052610320526103405261036052610380526103a0526103c0526103e05261040052610420526104405261046052610480526104a0526104c0526104e052610500526105205261054052610560526000610140516020826105c0010152602081019050610160516020826105c0010152602081019050610180516020826105c00101526020810190506101a0516020826105c00101526020810190506101c0516020826105c00101526020810190506101e0516020826105c0010152602081019050610200516020826105c0010152602081019050610220516020826105c0010152602081019050610240516020826105c0010152602081019050610260516020826105c0010152602081019050610280516020826105c00101526020810190506102a0516020826105c00101526020810190506102c0516020826105c00101526020810190506102e0516020826105c0010152602081019050610300516020826105c0010152602081019050610320516020826105c0010152602081019050610340516020826105c0010152602081019050610360516020826105c0010152602081019050610380516020826105c00101526020810190506103a0516020826105c00101526020810190506103c0516020826105c00101526020810190506103e0516020826105c0010152602081019050610400516020826105c0010152602081019050610420516020826105c0010152602081019050610440516020826105c0010152602081019050610460516020826105c0010152602081019050610480516020826105c00101526020810190506104a0516020826105c00101526020810190506104c0516020826105c00101526020810190506104e0516020826105c0010152602081019050610500516020826105c0010152602081019050610520516020826105c0010152602081019050610540516020826105c0010152602081019050610560516020826105c0010152602081019050806105c0526105c090508051602082012090506105a0526105a051600052600051610580515650005b6000156109e1575b610220526101405261016052610180526101a0526101c0526101e0526102005260006101405160208261026001015260208101905061016051602082610260010152602081019050610180516020826102600101526020810190506101a0516020826102600101526020810190506101c0516020826102600101526020810190506101e05160208261026001015260208101905061020051602082610260010152602081019050806102605261026090508051602082012090506102405261024051600052600051610220515650005b6310660e866000511415610a905734156109fa57600080fd5b6004356020518110610a0b57600080fd5b506024356020518110610a1d57600080fd5b5063155960636101405260043561016052602435610180526044356101a0526064356101c0526084356101e05260a4356102005260c4356102205261022051610200516101e0516101c0516101a051610180516101605160065801610911565b610280526102805160005260206000f350005b600015610cf2575b6101805261014052610160526101a0526000610240525b6101a05160206001820306601f820103905061024051101515610ad157610aea565b610240516101c001526102405160200161024052610aaf565b60005060416101a0511815610b0757600060005260005161018051565b6101a0602060006020835103811315610b1f57600080fd5b046020026020018101519050610280526101a0602060206020835103811315610b4757600080fd5b0460200260200181015190506102a05260406001602082066103a0016101a0518284011115610b7557600080fd5b6041806103c0826020602088068803016101a001600060046018f1505081815280905090509050806020015160008251806020901315610bb457600080fd5b8091901215610bc257600080fd5b606051816020036101000a830480604051901315610bdf57600080fd5b8091901215610bed57600080fd5b9050905090506102c052601b6102c0511215610c30576102c0606051601b82510180604051901315610c1e57600080fd5b8091901215610c2c57600080fd5b8152505b610480601b8152601c81602001525060006104605261046061012060006002818352015b6101205160200261048001516102c0511415610c735760018352610c84565b5b8151600101808352811415610c54575b5050506104605160011415610ce257610140516104c0526102c0516000811215610cad57600080fd5b6104e05261028051610500526102a05161052052602060c060806104c060006001610bb8f15060c05160005260005161018051565b6000600052600051610180515650005b600015610db3575b6101605261014052610140517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff806000811215610d3e578060000360020a8204610d45565b8060020a82025b90509050604051811115610d5857600080fd5b61018052700100000000000000000000000000000000610d7757600080fd5b7001000000000000000000000000000000006101405106604051811115610d9d57600080fd5b6101a05261018051600052600051610160515650005b63f17535506000511415610de8573415610dcc57600080fd5b600060043560e05260c052604060c0205460005260206000f350005b63ac2a2e216000511415610e3d573415610e0157600080fd5b6004356020518110610e1257600080fd5b50600460043560e05260c052604060c02060243560e05260c052604060c0205460005260206000f350005b634026b7556000511415610e72573415610e5657600080fd5b600760043560e05260c052604060c0205460005260206000f350005b63f242432a6000511415611135573415610e8b57600080fd5b6004356020518110610e9c57600080fd5b506024356020518110610eae57600080fd5b5061012060843560040161014037610100608435600401351115610ed157600080fd5b600660043560e05260c052604060c0203360e05260c052604060c02054336004351417610efd57600080fd5b6308c379a06102805260206102a05260206102c0527f43616e6e6f74207472616e7366657220746f207a65726f20616464726573732e6102e0526102c050600060243518610f4c57608461029cfd5b6308c379a0610320526020610340526012610360527f4e6f7420656e6f75676820746f6b656e732e00000000000000000000000000006103805261036050606435600360043560e05260c052604060c02060443560e05260c052604060c020541015610fb957608461033cfd5b600360043560e05260c052604060c02060443560e05260c052604060c02060643581541015610fe757600080fd5b606435815403815550600360243560e05260c052604060c02060443560e05260c052604060c0208054606435825401101561102157600080fd5b6064358154018155506044356103c0526064356103e052602435600435337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6260406103c0a460006024353b1115611133576024353b61107f57600080fd5b602435301861108d57600080fd5b60206106406101c460a063f23a6e6161042052336104405260043561046052604435610480526064356104a052806104c052610140808051602001808461044001828460006004600a8704601201f16110e557600080fd5b50508051820160206001820306601f820103905060200191505061043c905060006024355af161111457600080fd5b600050610640516104005263f23a6e61610400511461113257600080fd5b5b005b63cf36e535600051141561163c57341561114e57600080fd5b600435602051811061115f57600080fd5b50602435602051811061117157600080fd5b506000610120525b602061012051016101205261012061012051101561119657611179565b6000610120525b60206101205101610120526101206101205110156111ba5761119d565b6101206102c435600401610140376101006102c4356004013511156111de57600080fd5b600660043560e05260c052604060c0203360e05260c052604060c0205433600435141761120a57600080fd5b6308c379a06102805260206102a05260206102c0527f43616e6e6f74207472616e7366657220746f207a65726f20616464726573732e6102e0526102c05060006024351861125957608461029cfd5b6103206000600a818352015b604461032051600a811061127857600080fd5b60200201356103405261018461032051600a811061129557600080fd5b6020020135600360043560e05260c052604060c0206103405160e05260c052604060c0205410156112c557600080fd5b5b8151600101808352811415611265575b505060443561036052606435610380526084356103a05260a4356103c05260c4356103e05260e435610400526101043561042052610124356104405261014435610460526101643561048052610184356104a0526101a4356104c0526101c4356104e0526101e435610500526102043561052052610224356105405261024435610560526102643561058052610284356105a0526102a4356105c052602435600435337f514c24e4790d7c31a095a1688a73a01f28d936a9a85d806ba95970d8ee88efa8610280610360a46105e06000600a818352015b60446105e051600a81106113c057600080fd5b602002013561060052600360043560e05260c052604060c0206106005160e05260c052604060c0206101846105e051600a81106113fc57600080fd5b60200201358154101561140e57600080fd5b6101846105e051600a811061142257600080fd5b6020020135815403815550600360243560e05260c052604060c0206106005160e05260c052604060c02080546101846105e051600a811061146257600080fd5b6020020135825401101561147557600080fd5b6101846105e051600a811061148957600080fd5b60200201358154018155505b81516001018083528114156113ad575b505060006024353b111561163a576024353b6114c057600080fd5b60243530186114ce57600080fd5b6020610aa06104046102e063a3bfc206610640523361066052600435610680526106a0604480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250506107e061018480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250508061092052610140808051602001808461066001828460006004600a8704601201f16115ec57600080fd5b50508051820160206001820306601f820103905060200191505061065c905060006024355af161161b57600080fd5b600050610aa0516106205263e324a00d610620511461163957600080fd5b5b005b62fdd58e600051141561169057341561165457600080fd5b600435602051811061166557600080fd5b50600360043560e05260c052604060c02060243560e05260c052604060c0205460005260206000f350005b63fbe31aea60005114156117935734156116a957600080fd5b6000610120525b610120516004013560205181106116c657600080fd5b5060206101205101610120526101206101205110156116e4576116b0565b6000610120525b6020610120510161012052610120610120511015611708576116eb565b6102806000600a818352015b6003600461028051600a811061172957600080fd5b602002013560e05260c052604060c02061014461028051600a811061174d57600080fd5b602002013560e05260c052604060c0205461014061028051600a811061177257600080fd5b60200201525b8151600101808352811415611714575b5050610140610140f3005b63a22cb46560005114156118235734156117ac57600080fd5b60043560205181106117bd57600080fd5b50602435600281106117ce57600080fd5b5060243560063360e05260c052604060c02060043560e05260c052604060c0205560243561014052600435337f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c316020610140a3005b63e985e9c5600051141561188a57341561183c57600080fd5b600435602051811061184d57600080fd5b50602435602051811061185f57600080fd5b50600660043560e05260c052604060c02060243560e05260c052604060c0205460005260206000f350005b63a70b070f6000511415611af85734156118a357600080fd5b60043560205181106118b457600080fd5b50610120604435600401610140376101006044356004013511156118d757600080fd5b6000600435186118e657600080fd5b6308c379a06102805260206102a052601b6102c0527f4f776e6572206f6e6c792063616e20637265617465206974656d2e00000000006102e0526102c050336002541461193457608461029cfd5b6000600360043560e05260c052604060c02060243560e05260c052604060c02055600180546001825401101561196957600080fd5b60018154018155506001600760243560e05260c052604060c0205561014080600560243560e05260c052604060c02060c052602060c020602082510161012060006009818352015b826101205160200211156119c4576119e6565b61012051602002850151610120518501555b81516001018083528114156119b1575b50505050505060206103405261034051610380526101408051602001806103405161038001828460006004600a8704601201f1611a2257600080fd5b5050610320610340516103800151610440818352015b610440610320511115611a4a57611a6b565b600061032051610340516103a00101535b8151600101808352811415611a38575b5050602061034051610380015160206001820306601f8201039050610340510101610340526024357f6bb7ff708619ba0610cba295a58592e0451dee2622938c8755667688daf3529b61034051610380a26024356103a05260006103c0526004356000337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6260406103a0a4005b6319a35d7c6000511415611d43573415611b1157600080fd5b6004356020518110611b2257600080fd5b506000610120525b6020610120510161012052610120610120511015611b4757611b2a565b600060043518611b5657600080fd5b6308c379a061014052602061016052601c610180527f4f776e6572206f6e6c792063616e20637265617465206974656d732e000000006101a052610180503360025414611ba457608461015cfd5b6101e06000600a818352015b60246101e051600a8110611bc357600080fd5b6020020135610200526000600360043560e05260c052604060c0206102005160e05260c052604060c020556001805460018254011015611c0257600080fd5b6001815401815550600160076102005160e05260c052604060c020555b8151600101808352811415611bb0575b5050610220600081526000816020015260008160400152600081606001526000816080015260008160a0015260008160c0015260008160e00152600081610100015260008161012001525060243561036052604435610380526064356103a0526084356103c05260a4356103e05260c4356104005260e43561042052610104356104405261012435610460526101443561048052610220516104a052610240516104c052610260516104e05261028051610500526102a051610520526102c051610540526102e051610560526103005161058052610320516105a052610340516105c0526004356000337f514c24e4790d7c31a095a1688a73a01f28d936a9a85d806ba95970d8ee88efa8610280610360a4005b63156e29f66000511415611d8157600061028052610280805160200180610140828460006004600a8704601201f1611d7a57600080fd5b5050611dce565b63731133e96000511415611dc65761012060643560040161014037610100606435600401351115611db157600080fd5b61014060643560040161014037600050611dce565b60001561208a575b3415611dd957600080fd5b6004356020518110611dea57600080fd5b50600060043518611dfa57600080fd5b6308c379a06102c05260206102e052601a610300527f4f776e6572206f6e6c792063616e206d696e74206974656d732e00000000000061032052610300503360025414611e485760846102dcfd5b610140610380525b61038051516020610380510161038052610380610380511015611e7257611e50565b6320171bef6103a0526024356103c0526103c05160065801610cfa565b61042052610360610380525b6103805152602061038051036103805261014061038051101515611ebe57611e9b565b6104205161036052600261036051146001610360511417611ede57600080fd5b6001610360511415611f5f576308c379a0610440526020610460526028610480527f43616e6e6f74206d696e74204e46542077697468205f737570706c79206d6f726104a0527f65207468616e20310000000000000000000000000000000000000000000000006104c05261048050600160443514611f5e5760a461045cfd5b5b604435600360043560e05260c052604060c02060243560e05260c052604060c0205560243561050052604435610520526004356000337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f626040610500a460006004353b1115612088576004353b611fd557600080fd5b6004353018611fe357600080fd5b60206107806101c460a063f23a6e6161056052336105805260006105a0526024356105c0526044356105e0528061060052610140808051602001808461058001828460006004600a8704601201f161203a57600080fd5b50508051820160206001820306601f820103905060200191505061057c905060006004355af161206957600080fd5b600050610780516105405263f23a6e61610540511461208757600080fd5b5b005b63c671854d60005114156120c857600061028052610280805160200180610140828460006004600a8704601201f16120c157600080fd5b5050612118565b63b07e58756000511415612110576101206102a435600401610140376101006102a4356004013511156120fa57600080fd5b6101406102a43560040161014037600050612118565b6000156124f6575b341561212357600080fd5b600435602051811061213457600080fd5b506000610120525b60206101205101610120526101206101205110156121595761213c565b6000610120525b602061012051016101205261012061012051101561217d57612160565b60006004351861218c57600080fd5b6308c379a06102c05260206102e052601a610300527f4f776e6572206f6e6c792063616e206d696e74206974656d732e000000000000610320526103005033600254146121da5760846102dcfd5b6103606000600a818352015b602461036051600a81106121f957600080fd5b6020020135610380526101406103c0525b6103c0515160206103c051016103c0526103c06103c051101561222c5761220a565b6320171bef6103e05261038051610400526104005160065801610cfa565b610460526103a06103c0525b6103c0515260206103c051036103c0526101406103c05110151561227957612256565b610460516103a05260026103a0511460016103a051141761229957600080fd5b60016103a05114156122cb57600161016461036051600a81106122bb57600080fd5b6020020135146122ca57600080fd5b5b61016461036051600a81106122df57600080fd5b6020020135600360043560e05260c052604060c0206103805160e05260c052604060c020555b81516001018083528114156121e6575b5050602435610480526044356104a0526064356104c0526084356104e05260a4356105005260c4356105205260e4356105405261010435610560526101243561058052610144356105a052610164356105c052610184356105e0526101a435610600526101c435610620526101e4356106405261020435610660526102243561068052610244356106a052610264356106c052610284356106e0526004356000337f514c24e4790d7c31a095a1688a73a01f28d936a9a85d806ba95970d8ee88efa8610280610480a46107006000600a818352015b60006004353b11156124e1576004353b61240357600080fd5b600435301861241157600080fd5b60206109606101c460a063f23a6e61610740523361076052600061078052602461070051600a811061244257600080fd5b60200201356107a05261016461070051600a811061245f57600080fd5b60200201356107c052806107e052610140808051602001808461076001828460006004600a8704601201f161249357600080fd5b50508051820160206001820306601f820103905060200191505061075c905060006004355af16124c257600080fd5b600050610960516107205263f23a6e6161072051146124e057600080fd5b5b5b81516001018083528114156123ea575b5050005b63b390c0ab60005114156125ea57341561250f57600080fd5b6308c379a061014052602061016052601a610180527f4e6f7420656e6f75676820746f6b656e7320746f206275726e2e0000000000006101a0526101805060243560033360e05260c052604060c02060043560e05260c052604060c02054101561257a57608461015cfd5b60033360e05260c052604060c02060043560e05260c052604060c020602435815410156125a657600080fd5b6024358154038155506004356101e05260243561020052600033337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6260406101e0a4005b63b59afe52600051141561282b57341561260357600080fd5b6000610120525b60206101205101610120526101206101205110156126275761260a565b6000610120525b602061012051016101205261012061012051101561264b5761262e565b6101406000600a818352015b600461014051600a811061266a57600080fd5b60200201356101605261014461014051600a811061268757600080fd5b602002013560033360e05260c052604060c0206101605160e05260c052604060c0205410156126b557600080fd5b5b8151600101808352811415612657575b50506101806000600a818352015b600461018051600a81106126e757600080fd5b60200201356101a05260033360e05260c052604060c0206101a05160e05260c052604060c02061014461018051600a811061272157600080fd5b60200201358154101561273357600080fd5b61014461018051600a811061274757600080fd5b60200201358154038155505b81516001018083528114156126d4575b50506004356101c0526024356101e05260443561020052606435610220526084356102405260a4356102605260c4356102805260e4356102a052610104356102c052610124356102e0526101443561030052610164356103205261018435610340526101a435610360526101c435610380526101e4356103a052610204356103c052610224356103e05261024435610400526102643561042052600033337f514c24e4790d7c31a095a1688a73a01f28d936a9a85d806ba95970d8ee88efa86102806101c0a4005b63f2526ada6000511415612869576000610320526103208051602001806101e0828460006004600a8704601201f161286257600080fd5b50506128b9565b63a835c36960005114156128b157610120610464356004016101e0376101006104643560040135111561289b57600080fd5b610140610464356004016101e0376000506128b9565b600015613725575b60043560205181106128ca57600080fd5b5060243560205181106128dc57600080fd5b506000610120525b6020610120510161012052610120610120511015612901576128e4565b6000610120525b602061012051016101205261012061012051101561292557612908565b6000610120525b60206101205101610120526101206101205110156129495761292c565b6061610444356004016101403760416104443560040135111561296b57600080fd5b6308c379a061036052602061038052602c6103a0527f5f66726f6d206d757374206265207468652073656e646572206f7220617070726103c0527f6f766564206164647265737300000000000000000000000000000000000000006103e0526103a050600660043560e05260c052604060c0203360e05260c052604060c020543360043514176129fc5760a461037cfd5b6308c379a0610420526020610440526025610460527f44657374696e6174696f6e2061646472657373206d757374206265206e6f6e2d610480527f7a65726f2e0000000000000000000000000000000000000000000000000000006104a05261046050600060243518612a705760a461043cfd5b6308c379a06104e0526020610500526015610520527f4e6f6e6365206d75737420626520756e757365642e00000000000000000000006105405261052050600460043560e05260c052604060c0206104243560e05260c052604060c0205415612ada5760846104fcfd5b6308c379a06105805260206105a05260256105c0527f53656e64657220686173206e6f742070726f766964656420656e6f75676820656105e0527f746865722e000000000000000000000000000000000000000000000000000000610600526105c050346104043514612b4e5760a461059cfd5b6106406000600a818352015b604461064051600a8110612b6d57600080fd5b602002013561066052600061018461064051600a8110612b8c57600080fd5b60200201351115612c03576102c461064051600a8110612bab57600080fd5b602002013515612bba57600080fd5b61018461064051600a8110612bce57600080fd5b6020020135600360043560e05260c052604060c0206106605160e05260c052604060c020541015612bfe57600080fd5b612c6b565b61018461064051600a8110612c1757600080fd5b602002013515612c2657600080fd5b6102c461064051600a8110612c3a57600080fd5b6020020135600360243560e05260c052604060c0206106605160e05260c052604060c020541015612c6a57600080fd5b5b5b8151600101808352811415612b5a575b50506101406106a0525b6106a0515160206106a051016106a0526106a06106a0511015612ca857612c86565b6373ad25716106c0526004356106e05260243561070052610720604480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e00152806101000135826101000152806101200135826101200152505061086061018480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250506109a06102c480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e00152806101000135826101000152806101200135826101200152505061040435610ae05261042435610b0052610b0051610ae051610ac051610aa051610a8051610a6051610a4051610a2051610a00516109e0516109c0516109a05161098051610960516109405161092051610900516108e0516108c0516108a05161088051610860516108405161082051610800516107e0516107c0516107a05161078051610760516107405161072051610700516106e051600658016100dc565b610b60526106806106a0525b6106a0515260206106a051036106a0526101406106a051101515612ecc57612ea9565b610b605161068052610140610ba0525b610ba051516020610ba05101610ba052610ba0610ba0511015612efe57612edc565b6040636f868168610bc05261068051610be05280610c00526101408080516020018084610be001828460006004600a8704601201f1612f3c57600080fd5b50508051820160206001820306601f820103905060200191505050610c005180610be00180518060206001820306601f82010390508201610ce0525050505b610c20610ce0511015612f8d57612fa2565b610ce051516020610ce05103610ce052612f7b565b610c0051610be05160065801610a98565b610d0052610b80610ba0525b610ba051526020610ba05103610ba052610140610ba051101515612fe257612fbf565b610d0051610b80526308c379a0610d20526020610d40526020610d60527f5369676e657220646f6573206e6f74206d61746368207369676e61747572652e610d8052610d6050602435610b80511461303b576084610d3cfd5b600160043360e05260c052604060c0206104243560e05260c052604060c02055610dc06000600a818352015b6044610dc051600a811061307a57600080fd5b6020020135610de0526000610184610dc051600a811061309957600080fd5b6020020135111561317457600360043560e05260c052604060c020610de05160e05260c052604060c020610184610dc051600a81106130d757600080fd5b6020020135815410156130e957600080fd5b610184610dc051600a81106130fd57600080fd5b6020020135815403815550600360243560e05260c052604060c020610de05160e05260c052604060c0208054610184610dc051600a811061313d57600080fd5b6020020135825401101561315057600080fd5b610184610dc051600a811061316457600080fd5b6020020135815401815550613240565b600360043560e05260c052604060c020610de05160e05260c052604060c02080546102c4610dc051600a81106131a957600080fd5b602002013582540110156131bc57600080fd5b6102c4610dc051600a81106131d057600080fd5b6020020135815401815550600360243560e05260c052604060c020610de05160e05260c052604060c0206102c4610dc051600a811061320e57600080fd5b60200201358154101561322057600080fd5b6102c4610dc051600a811061323457600080fd5b60200201358154038155505b5b8151600101808352811415613067575b50506000600060006000346024356000f161326b57600080fd5b604435610e0052606435610e2052608435610e405260a435610e605260c435610e805260e435610ea05261010435610ec05261012435610ee05261014435610f005261016435610f205261018435610f40526101a435610f60526101c435610f80526101e435610fa05261020435610fc05261022435610fe0526102443561100052610264356110205261028435611040526102a43561106052602435600435337f514c24e4790d7c31a095a1688a73a01f28d936a9a85d806ba95970d8ee88efa8610280610e00a4604435611080526064356110a0526084356110c05260a4356110e05260c4356111005260e43561112052610104356111405261012435611160526101443561118052610164356111a0526102c4356111c0526102e4356111e052610304356112005261032435611220526103443561124052610364356112605261038435611280526103a4356112a0526103c4356112c0526103e4356112e052600435602435337f514c24e4790d7c31a095a1688a73a01f28d936a9a85d806ba95970d8ee88efa8610280611080a460006024353b1115613590576024353b61341657600080fd5b602435301861342457600080fd5b60206117806104046102e063a3bfc20661132052336113405260243561136052611380604480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250506114c061018480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e00152806101000135826101000152806101200135826101200152505080611600526101e0808051602001808461134001828460006004600a8704601201f161354257600080fd5b50508051820160206001820306601f820103905060200191505061133c905060006024355af161357157600080fd5b6000506117805161130052630c97e564611300511461358f57600080fd5b5b60006004353b1115613723576004353b6135a957600080fd5b60043530186135b757600080fd5b6020611c206104046102e063a3bfc2066117c052336117e05260043561180052611820604480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250506119606102c480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e00152806101000135826101000152806101200135826101200152505080611aa0526101e080805160200180846117e001828460006004600a8704601201f16136d557600080fd5b50508051820160206001820306601f82010390506020019150506117dc905060006004355af161370457600080fd5b600050611c20516117a052630c97e5646117a0511461372257600080fd5b5b005b636e8205b26000511415613763576000610320526103208051602001806101e0828460006004600a8704601201f161375c57600080fd5b50506137b3565b63183f5ec560005114156137ab57610120610104356004016101e0376101006101043560040135111561379557600080fd5b610140610104356004016101e0376000506137b3565b600015613f5d575b60043560205181106137c457600080fd5b5060243560205181106137d657600080fd5b50606160e43560040161014037604160e4356004013511156137f757600080fd5b600660043560e05260c052604060c0203360e05260c052604060c0205433600435141761382357600080fd5b6308c379a06103605260206103805260256103a0527f44657374696e6174696f6e2061646472657373206d757374206265206e6f6e2d6103c0527f7a65726f2e0000000000000000000000000000000000000000000000000000006103e0526103a0506000602435186138975760a461037cfd5b6308c379a0610420526020610440526015610460527f4e6f6e6365206d75737420626520756e757365642e00000000000000000000006104805261046050600460043560e05260c052604060c02060c43560e05260c052604060c020541561390057608461043cfd5b6308c379a06104c05260206104e0526025610500527f53656e64657220686173206e6f742070726f766964656420656e6f7567682065610520527f746865722e00000000000000000000000000000000000000000000000000000061054052610500503460a435146139735760a46104dcfd5b600060643511156139bd576084351561398b57600080fd5b606435600360043560e05260c052604060c02060443560e05260c052604060c0205410156139b857600080fd5b6139f8565b606435156139ca57600080fd5b608435600360243560e05260c052604060c02060443560e05260c052604060c0205410156139f757600080fd5b5b6101406105a0525b6105a0515160206105a051016105a0526105a06105a0511015613a2257613a00565b63155960636105c0526004356105e0526024356106005260443561062052606435610640526084356106605260a4356106805260c4356106a0526106a05161068051610660516106405161062051610600516105e05160065801610911565b610700526105806105a0525b6105a0515260206105a051036105a0526101406105a051101515613ab057613a8d565b6107005161058052610140610740525b61074051516020610740510161074052610740610740511015613ae257613ac0565b6040636f868168610760526105805161078052806107a052610140808051602001808461078001828460006004600a8704601201f1613b2057600080fd5b50508051820160206001820306601f8201039050602001915050506107a051806107800180518060206001820306601f82010390508201610880525050505b6107c0610880511015613b7157613b86565b61088051516020610880510361088052613b5f565b6107a0516107805160065801610a98565b6108a052610720610740525b6107405152602061074051036107405261014061074051101515613bc657613ba3565b6108a051610720526308c379a06108c05260206108e0526020610900527f5369676e657220646f6573206e6f74206d61746368207369676e61747572652e61092052610900506024356107205114613c1f5760846108dcfd5b600160043360e05260c052604060c02060c43560e05260c052604060c0205560006064351115613cbf57600360043560e05260c052604060c02060443560e05260c052604060c02060643581541015613c7757600080fd5b606435815403815550600360243560e05260c052604060c02060443560e05260c052604060c02080546064358254011015613cb157600080fd5b606435815401815550613d31565b600360043560e05260c052604060c02060443560e05260c052604060c02080546084358254011015613cf057600080fd5b608435815401815550600360243560e05260c052604060c02060443560e05260c052604060c02060843581541015613d2757600080fd5b6084358154038155505b6000600060006000346024356000f1613d4957600080fd5b6044356109605260643561098052602435600435337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f626040610960a46044356109a0526084356109c052600435602435337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6260406109a0a460006024353b1115613e8e576024353b613dda57600080fd5b6024353018613de857600080fd5b6020610c206101c460a063f23a6e61610a005233610a2052602435610a4052604435610a6052606435610a805280610aa0526101e08080516020018084610a2001828460006004600a8704601201f1613e4057600080fd5b50508051820160206001820306601f8201039050602001915050610a1c905060006024355af1613e6f57600080fd5b600050610c20516109e052630c97e5646109e05114613e8d57600080fd5b5b60006004353b1115613f5b576004353b613ea757600080fd5b6004353018613eb557600080fd5b6020610e806101c460a063f23a6e61610c605233610c8052600435610ca052604435610cc052608435610ce05280610d00526101e08080516020018084610c8001828460006004600a8704601201f1613f0d57600080fd5b50508051820160206001820306601f8201039050602001915050610c7c905060006004355af1613f3c57600080fd5b600050610e8051610c4052630c97e564610c405114613f5a57600080fd5b5b005b638da5cb5b6000511415613f84573415613f7657600080fd5b60025460005260206000f350005b60006000fd\",\n  \"source\": \"# Author: Sören Steiger, github.com/ssteiger\\n# Author: Fetch.ai, github.com/fetchai\\n# License: MIT\\n\\n# ERC1155 Token Standard\\n# https://eips.ethereum.org/EIPS/eip-1155\\n\\n########################EXTERNAL-CONTRACTS####################################\\n\\ncontract ERC1155TokenReceiver:\\n    # Note: The ERC-165 identifier for this interface is 0x4e2312e0.\\n\\n    def onERC1155Received(_operator: address, _from: address, _id: uint256, _value: uint256,\\n                          _data: bytes[256]) -> bytes32: modifying  # TODO: should return bytes4\\n    #        \\\"\\\"\\\"\\n    #       @notice Handle the receipt of a single ERC1155 token type.\\n    #       @dev An ERC1155-compliant smart contract MUST call this function on the token recipient contract, at the end of a `safeTransferFrom` after the balance has been updated.        \\n    #       This function MUST return `bytes4(keccak256(\\\"onERC1155Received(address,address,uint256,uint256,bytes)\\\"))` (i.e. 0xf23a6e61) if it accepts the transfer.\\n    #       This function MUST revert if it rejects the transfer.\\n    #       Return of any other value than the prescribed keccak256 generated value MUST result in the transaction being reverted by the caller.\\n    #       @param _operator  The address which initiated the transfer (i.e. msg.sender)\\n    #       @param _from      The address which previously owned the token\\n    #       @param _id        The ID of the token being transferred\\n    #       @param _value     The amount of tokens being transferred\\n    #       @param _data      Additional data with no specified format\\n    #       @return           `bytes4(keccak256(\\\"onERC1155Received(address,address,uint256,uint256,bytes)\\\"))`\\n    #       \\\"\\\"\\\"\\n\\n    def onERC1155BatchReceived(_operator: address, _from: address, _ids: uint256[BATCH_SIZE], _values: uint256[BATCH_SIZE],\\n                               _data: bytes[256]) -> bytes32: modifying  # TODO: should return bytes4\\n    #       \\\"\\\"\\\"\\n    #       @notice Handle the receipt of multiple ERC1155 token types.\\n    #       @dev An ERC1155-compliant smart contract MUST call this function on the token recipient contract, at the end of a `safeBatchTransferFrom` after the balances have been updated.        \\n    #       This function MUST return `bytes4(keccak256(\\\"onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)\\\"))` (i.e. 0xbc197c81) if it accepts the transfer(s).\\n    #       This function MUST revert if it rejects the transfer(s).\\n    #       Return of any other value than the prescribed keccak256 generated value MUST result in the transaction being reverted by the caller.\\n    #       @param _operator  The address which initiated the batch transfer (i.e. msg.sender)\\n    #       @param _from      The address which previously owned the token\\n    #       @param _ids       An array containing ids of each token being transferred (order and length must match _values array)\\n    #       @param _values    An array containing amounts of each token being transferred (order and length must match _ids array)\\n    #       @param _data      Additional data with no specified format\\n    #       @return           `bytes4(keccak256(\\\"onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)\\\"))`\\n    #       \\\"\\\"\\\"\\n\\n########################END-EXTERNAL-CONTRACTS####################################\\n########################EVENTS####################################\\n\\nMAX_URI_SIZE: constant(uint256) = 1024\\n\\nTransferSingle: event({_operator: indexed(address), _from: indexed(address), _to: indexed(address), _id: uint256,\\n                       _value: uint256})\\n#   @dev Either `TransferSingle` or `TransferBatch` MUST emit when tokens are transferred, including zero value transfers as well as minting or burning (see \\\"Safe Transfer Rules\\\" section of the standard).\\n#        The `_operator` argument MUST be the address of an account/contract that is approved to make the transfer (SHOULD be msg.sender).\\n#        The `_from` argument MUST be the address of the holder whose balance is decreased.\\n#        The `_to` argument MUST be the address of the recipient whose balance is increased.\\n#        The `_id` argument MUST be the token type being transferred.\\n#        The `_value` argument MUST be the number of tokens the holder balance is decreased by and match what the recipient balance is increased by.\\n#        When minting/creating tokens, the `_from` argument MUST be set to `0x0` (i.e. zero address).\\n#        When burning/destroying tokens, the `_to` argument MUST be set to `0x0` (i.e. zero address).\\n\\n\\nTransferBatch: event({_operator: indexed(address), _from: indexed(address), _to: indexed(address),\\n                      _ids: uint256[BATCH_SIZE], _values: uint256[BATCH_SIZE]})\\n#   @dev Either `TransferSingle` or `TransferBatch` MUST emit when tokens are transferred, including zero value transfers as well as minting or burning (see \\\"Safe Transfer Rules\\\" section of the standard).\\n#        The `_operator` argument MUST be the address of an account/contract that is approved to make the transfer (SHOULD be msg.sender).\\n#        The `_from` argument MUST be the address of the holder whose balance is decreased.\\n#        The `_to` argument MUST be the address of the recipient whose balance is increased.\\n#        The `_ids` argument MUST be the list of tokens being transferred.\\n#        The `_values` argument MUST be the list of number of tokens (matching the list and order of tokens specified in _ids) the holder balance is decreased by and match what the recipient balance is increased by.\\n#        When minting/creating tokens, the `_from` argument MUST be set to `0x0` (i.e. zero address).\\n#        When burning/destroying tokens, the `_to` argument MUST be set to `0x0` (i.e. zero address).\\n\\n\\nApprovalForAll: event({_owner: indexed(address), _operator: indexed(address), _approved: bool})\\n#   @dev MUST emit when approval for a second party/operator address to manage all tokens for an owner address is enabled or disabled (absence of an event assumes disabled).\\n\\n\\nURI: event({_value: string[MAX_URI_SIZE], _id: indexed(uint256)})\\n#   @dev MUST emit when the URI is updated for a token ID.\\n#        URIs are defined in RFC 3986.\\n#        The URI MUST point to a JSON file that conforms to the \\\"ERC-1155 Metadata URI JSON Schema\\\".\\n\\n########################END-EVENTS####################################\\n########################INITIALIZATION####################################\\n\\nsupportedInterfaces: map(bytes32, bool)\\n# https://eips.ethereum.org/EIPS/eip-165\\nERC165_INTERFACE_ID: constant(bytes32)  = 0x0000000000000000000000000000000000000000000000000000000001ffc9a7\\nERC1155_INTERFACE_ID: constant(bytes32) = 0x00000000000000000000000000000000000000000000000000000000d9b67a26\\ntokensIdCount: uint256\\nowner: public(address)\\n\\nbalancesOf: map(address, map(uint256, uint256))\\nnoncesOf: map(address, map(uint256, bool))\\nuri: map(uint256, string[256])\\noperators: map(address, map(address, bool))\\ntoken_ids: map(uint256, bool)\\n\\n# This is to be set before contract migration!\\nBATCH_SIZE: constant(uint256) = 10\\n\\n\\n@public\\ndef __init__():\\n    \\\"\\\"\\\"\\n    @notice Called once and only upon contract deployment.\\n    \\\"\\\"\\\"\\n    self.tokensIdCount = convert(0, uint256)\\n    self.supportedInterfaces[ERC165_INTERFACE_ID] = True\\n    self.supportedInterfaces[ERC1155_INTERFACE_ID] = True\\n    self.owner = msg.sender\\n\\n########################END-INITIALIZATION####################################\\n########################PRIVATE-FUNCTIONS####################################\\n\\n\\n######### THIS IS A TEMPORARY SOLUTION #################\\n@public\\n@constant\\ndef getAddress(_addr: address) -> bytes32:\\n    hash: bytes32 = convert(_addr, bytes32)\\n    return hash\\n##################### END ##############################\\n\\n@private\\n@constant\\ndef _getHash(_from: address, _to: address, _ids: uint256[BATCH_SIZE], _from_supplies: uint256[BATCH_SIZE], _to_supplies: uint256[BATCH_SIZE], _value_eth: uint256, _nonce: uint256) -> bytes32:\\n    \\\"\\\"\\\"\\n    @notice Get the hash from the tx values.\\n    @param _from          The address of the sender.\\n    @param _to            The address of the receiver.\\n    @param _ids           The ids of the tokens.\\n    @param _from_supplies The supply of token values that will send the _from.\\n    @param _to_supplies   The supply of token values that will send the _from.\\n    @param _value_eth     The value of the ether.\\n    @param _nonce         The nonce.\\n    @return the hash\\n    \\\"\\\"\\\"\\n    aggregate_hash: bytes32 = keccak256(concat(convert(_ids[0], bytes32), convert(_from_supplies[0], bytes32), convert(_to_supplies[0], bytes32)))\\n    for i in range(BATCH_SIZE):\\n      if not i == 0:\\n        aggregate_hash = keccak256(concat(aggregate_hash, convert(_ids[i], bytes32), convert(_from_supplies[i], bytes32), convert(_to_supplies[i], bytes32)))\\n    hash: bytes32 = keccak256(concat(convert(_from, bytes32),\\n                              convert(_to, bytes32),\\n                              aggregate_hash,\\n                              convert(_value_eth, bytes32),\\n                              convert(_nonce, bytes32)))\\n    return hash\\n\\n\\n@public\\n@constant\\ndef getHash(_from: address, _to: address, _ids: uint256[BATCH_SIZE], _from_supplies: uint256[BATCH_SIZE], _to_supplies: uint256[BATCH_SIZE], _value_eth: uint256, _nonce: uint256) -> bytes32:\\n    \\\"\\\"\\\"\\n    @notice Get the hash from the tx values.\\n    @param _from          The address of the sender.\\n    @param _to            The address of the receiver.\\n    @param _ids           The ids of the tokens.\\n    @param _from_supplies The supply of token values that will send the _from.\\n    @param _to_supplies   The supply of token values that will send the _from.\\n    @param _value_eth     The value of the ether.\\n    @param _nonce         The nonce.\\n    @return the hash\\n    \\\"\\\"\\\"\\n    return self._getHash(_from, _to, _ids, _from_supplies, _to_supplies, _value_eth, _nonce)\\n\\n\\n@private\\n@constant\\ndef getHashOld(_from: address, _to: address, _ids: uint256[BATCH_SIZE], _from_supplies: uint256[BATCH_SIZE], _to_supplies: uint256[BATCH_SIZE], _value_eth: uint256, _nonce: uint256) -> bytes32:\\n    \\\"\\\"\\\"\\n    @notice Get the hash from the tx values.\\n    @param _from          The address of the sender.\\n    @param _to            The address of the receiver.\\n    @param _ids           The ids of the tokens.\\n    @param _from_supplies The supply of token values that will send the _from.\\n    @param _to_supplies   The supply of token values that will send the _from.\\n    @param _value_eth     The value of the ether.\\n    @param _nonce         The nonce.\\n    @return the hash\\n    \\\"\\\"\\\"\\n    hash: bytes32 = keccak256(concat(convert(_from, bytes32),\\n                              convert(_to, bytes32),\\n                              convert(_ids[0], bytes32),\\n                              convert(_ids[1], bytes32),\\n                              convert(_ids[2], bytes32),\\n                              convert(_ids[3], bytes32),\\n                              convert(_ids[4], bytes32),\\n                              convert(_ids[5], bytes32),\\n                              convert(_ids[6], bytes32),\\n                              convert(_ids[7], bytes32),\\n                              convert(_ids[8], bytes32),\\n                              convert(_ids[9], bytes32),\\n                              convert(_from_supplies[0], bytes32),\\n                              convert(_from_supplies[1], bytes32),\\n                              convert(_from_supplies[2], bytes32),\\n                              convert(_from_supplies[3], bytes32),\\n                              convert(_from_supplies[4], bytes32),\\n                              convert(_from_supplies[5], bytes32),\\n                              convert(_from_supplies[6], bytes32),\\n                              convert(_from_supplies[7], bytes32),\\n                              convert(_from_supplies[8], bytes32),\\n                              convert(_from_supplies[9], bytes32),\\n                              convert(_to_supplies[0], bytes32),\\n                              convert(_to_supplies[1], bytes32),\\n                              convert(_to_supplies[2], bytes32),\\n                              convert(_to_supplies[3], bytes32),\\n                              convert(_to_supplies[4], bytes32),\\n                              convert(_to_supplies[5], bytes32),\\n                              convert(_to_supplies[6], bytes32),\\n                              convert(_to_supplies[7], bytes32),\\n                              convert(_to_supplies[8], bytes32),\\n                              convert(_to_supplies[9], bytes32),\\n                              convert(_value_eth, bytes32),\\n                              convert(_nonce, bytes32)))\\n    return hash\\n\\n\\n@private\\n@constant\\ndef _getSingleHash(_from: address, _to: address, _id: uint256, _from_supply: uint256, _to_supply: uint256, _value_eth: uint256, _nonce: uint256) -> bytes32:\\n    \\\"\\\"\\\"\\n    @notice Get the hash from the tx values.\\n    @param _from            The address of the sender.\\n    @param _to              The address of the receiver.\\n    @param _id              The id of the tokens.\\n    @param _from_supply     The from token value. (_from sends)\\n    @param _to_supply       The to token value (_to sends).\\n    @param _value_eth       The value of the ether.\\n    @param _nonce           The nonce.\\n    @return the hash\\n    \\\"\\\"\\\"\\n    hash: bytes32 = keccak256(concat(convert(_from, bytes32),\\n                              convert(_to, bytes32),\\n                              convert(_id, bytes32),\\n                              convert(_from_supply, bytes32),\\n                              convert(_to_supply, bytes32),\\n                              convert(_value_eth, bytes32),\\n                              convert(_nonce, bytes32)))\\n    return hash\\n\\n\\n@public\\n@constant\\ndef getSingleHash(_from: address, _to: address, _id: uint256, _from_supply: uint256, _to_supply: uint256, _value_eth: uint256, _nonce: uint256) -> bytes32:\\n    \\\"\\\"\\\"\\n    @notice Get the hash from the tx values.\\n    @param _from            The address of the sender.\\n    @param _to              The address of the receiver.\\n    @param _id              The id of the tokens.\\n    @param _from_supply     The from token value. (_from sends)\\n    @param _to_supply       The to token value (_to sends).\\n    @param _value_eth       The value of the ether.\\n    @param _nonce           The nonce.\\n    @return the hash\\n    \\\"\\\"\\\"\\n    return self._getSingleHash(_from, _to, _id, _from_supply, _to_supply, _value_eth, _nonce)\\n\\n\\n@private\\n@constant\\ndef ecrecoverSig(_hash: bytes32, _sig: bytes[65]) -> address:\\n    \\\"\\\"\\\"\\n    @notice Check whether the the signature matches the hash.\\n    @param _hash The hash to be checked.\\n    @param _sig  The signature which is meant to match the hash.\\n    @return the address which signed the signature or the zero address\\n    \\\"\\\"\\\"\\n    if len(_sig) != 65:\\n        return ZERO_ADDRESS\\n    # ref. https://gist.github.com/axic/5b33912c6f61ae6fd96d6c4a47afde6d\\n    # The signature format is a compact form of:\\n    # {bytes32 r}{bytes32 s}{uint8 v}\\n    r: bytes32 = extract32(_sig, 0, type=bytes32)\\n    s: bytes32 = extract32(_sig, 32, type=bytes32)\\n    v: int128 = convert(slice(_sig, start=64, len=1), int128)\\n    # Version of signature should be 27 or 28, but 0 and 1 are also possible versions.\\n    # geth uses [0, 1] and some clients have followed. This might change, see:\\n    # https://github.com/ethereum/go-ethereum/issues/2053\\n    if v < 27:\\n        v += 27\\n    if v in [27, 28]:\\n        return ecrecover(_hash, convert(v, uint256), convert(r, uint256), convert(s, uint256))\\n    return ZERO_ADDRESS\\n\\n\\n@private\\n@constant\\ndef decode_id(id: uint256) -> int128:\\n    \\\"\\\"\\\"\\n    @notice Decodes the id of the token inorder to find out if it NFT or FT.\\n    @param id: uint256\\n    @return token_id : int128 (Specified id for FT and NFT.)\\n    @dev shift(x, -y): returns x with the bits shifted to the right by y places, which is equivalent to dividing x by 2**y.\\n    \\\"\\\"\\\"\\n    decoded_token_id: int128 = convert(shift(id, -128), int128)\\n    decoded_index: int128 = convert(id % 2 ** 128, int128)\\n    return decoded_token_id\\n\\n########################END-PRIVATE-FUNCTIONS################################\\n########################PUBLIC-FUNCTIONS#####################################\\n\\n@public\\n@constant\\ndef supportsInterface(_interfaceID: bytes32) -> bool:\\n    \\\"\\\"\\\"\\n    @notice Check whether the interface id is supported.\\n    @param _interfaceID The interface id\\n    @return True if the interface id is supported.\\n    \\\"\\\"\\\"\\n    return self.supportedInterfaces[_interfaceID]\\n\\n@public\\n@constant\\ndef is_nonce_used(addr: address, nonce: uint256) -> bool:\\n    \\\"\\\"\\\"\\n    @notice Checks if the given nonce for the give address is unused.\\n    @param nonce: uint256 the counter of the transaction\\n    @param address: the address that want to transact.\\n    \\\"\\\"\\\"\\n    return self.noncesOf[addr][nonce]\\n\\n@public\\n@constant\\ndef is_token_id_exists(token_id: uint256) -> bool:\\n    \\\"\\\"\\\"\\n    @notice Checks if the given token_id is already created.\\n    @param token_id: uint256 the id of the token.\\n    \\\"\\\"\\\"\\n    return self.token_ids[token_id]\\n\\n@public\\ndef safeTransferFrom(_from: address, _to: address, _id: uint256, _value: uint256, _data: bytes[256]):\\n    \\\"\\\"\\\"\\n    @notice Transfers `_value` amount of an `_id` from the `_from` address to the `_to` address specified (with safety call).\\n    @dev Caller must be approved to manage the tokens being transferred out of the `_from` account (see \\\"Approval\\\" section of the standard).\\n         MUST revert if `_to` is the zero address.\\n         MUST revert if balance of holder for token `_id` is lower than the `_value` sent.\\n         MUST revert on any other error.\\n         MUST emit the `TransferSingle` event to reflect the balance change (see \\\"Safe Transfer Rules\\\" section of the standard).\\n         After the above conditions are met, this function MUST check if `_to` is a smart contract (e.g. code size > 0). If so, it MUST call `onERC1155Received` on `_to` and act appropriately (see \\\"Safe Transfer Rules\\\" section of the standard).\\n    @param _from    Source address\\n    @param _to      Target address\\n    @param _id      ID of the token type\\n    @param _value   Transfer amount\\n    @param _data    Additional data with no specified format, MUST be sent unaltered in call to `onERC1155Received` on `_to`\\n    @return None\\n    \\\"\\\"\\\"\\n    assert _from == msg.sender or (self.operators[_from])[msg.sender]\\n    assert _to != ZERO_ADDRESS, \\\"Cannot transfer to zero address.\\\"\\n    assert self.balancesOf[_from][_id] >= _value, \\\"Not enough tokens.\\\"\\n\\n    self.balancesOf[_from][_id] -= _value\\n    self.balancesOf[_to][_id] += _value\\n\\n    log.TransferSingle(msg.sender, _from, _to, _id, _value)\\n\\n    if _to.is_contract:\\n        returnValue: bytes32 = ERC1155TokenReceiver(_to).onERC1155Received(msg.sender, _from, _id, _value, _data)\\n        assert returnValue == method_id(\\\"onERC1155Received(address,address,uint256,uint256,bytes)\\\", bytes32)\\n\\n\\n@public\\ndef safeBatchTransferFrom(_from: address, _to: address, _ids: uint256[BATCH_SIZE], _values: uint256[BATCH_SIZE], _data: bytes[256]):\\n    \\\"\\\"\\\"\\n    @notice Transfers `_values` amount(s) of `_ids` from the `_from` address to the `_to` address specified (with safety call).\\n    @dev Caller must be approved to manage the tokens being transferred out of the `_from` account (see \\\"Approval\\\" section of the standard).\\n        MUST revert if `_to` is the zero address.\\n        MUST revert if length of `_ids` is not the same as length of `_values`.\\n        MUST revert if any of the balance(s) of the holder(s) for token(s) in `_ids` is lower than the respective amount(s) in `_values` sent to the recipient.\\n        MUST revert on any other error.\\n        MUST emit `TransferSingle` or `TransferBatch` event(s) such that all the balance changes are reflected (see \\\"Safe Transfer Rules\\\" section of the standard).\\n        Balance changes and events MUST follow the ordering of the arrays (_ids[0]/_values[0] before _ids[1]/_values[1], etc).\\n        After the above conditions for the transfer(s) in the batch are met, this function MUST check if `_to` is a smart contract (e.g. code size > 0). If so, it MUST call the relevant `ERC1155TokenReceiver` hook(s) on `_to` and act appropriately (see \\\"Safe Transfer Rules\\\" section of the standard).\\n    @param _from    Source address\\n    @param _to      Target address\\n    @param _ids     IDs of each token type (order and length must match _values array)\\n    @param _values  Transfer amounts per token type (order and length must match _ids array)\\n    @param _data    Additional data with no specified format, MUST be sent unaltered in call to the `ERC1155TokenReceiver` hook(s) on `_to`\\n    @return None\\n    \\\"\\\"\\\"\\n    assert _from == msg.sender or (self.operators[_from])[msg.sender]\\n    assert _to != ZERO_ADDRESS, \\\"Cannot transfer to zero address.\\\"\\n    for i in range(BATCH_SIZE):\\n        id: uint256 = _ids[i]\\n        assert self.balancesOf[_from][id] >= _values[i]\\n\\n    log.TransferBatch(msg.sender, _from, _to, _ids, _values)\\n\\n    for i in range(BATCH_SIZE):\\n        id: uint256 = _ids[i]\\n        self.balancesOf[_from][id] -= _values[i]\\n        self.balancesOf[_to][id] += _values[i]\\n\\n    if _to.is_contract:\\n        returnValue: bytes32 = ERC1155TokenReceiver(_to).onERC1155BatchReceived(msg.sender, _from, _ids, _values, _data)\\n        assert returnValue == method_id(\\\"onERC1155BatchReceived(address,address,uint256[BATCH_SIZE],uint256[BATCH_SIZE],bytes)\\\", bytes32)\\n\\n\\n@public\\n@constant\\ndef balanceOf(_owner: address, _id: uint256) -> uint256:\\n    \\\"\\\"\\\"\\n    @notice Get the balance of an account's tokens.\\n    @param  _owner The address of the token holder\\n    @param  _id    ID of the token\\n    @return The _owner's balance of the token type requested\\n    \\\"\\\"\\\"\\n    return self.balancesOf[_owner][_id]\\n\\n\\n@public\\n@constant\\ndef balanceOfBatch( _owner: address[BATCH_SIZE], _ids: uint256[BATCH_SIZE]) -> uint256[BATCH_SIZE]:\\n    \\\"\\\"\\\"\\n    @notice Get the balance of multiple account/token pairs\\n    @param _owners The addresses of the token holders\\n    @param _ids    ID of the tokens\\n    @return The _owner's balance of the token types requested (i.e. balance for each (owner, id) pair)\\n    \\\"\\\"\\\"\\n    returnBalances: uint256[BATCH_SIZE]\\n    for i in range(BATCH_SIZE):\\n        returnBalances[i] = self.balancesOf[_owner[i]][_ids[i]]\\n    return returnBalances\\n\\n\\n@public\\ndef setApprovalForAll(_operator: address, _approved: bool):\\n    \\\"\\\"\\\"\\n    @notice Enable or disable approval for a third party (\\\"operator\\\") to manage all of the caller's tokens.\\n    @dev MUST emit the ApprovalForAll event on success.\\n    @param _operator  Address to add to the set of authorized operators\\n    @param _approved  True if the operator is approved, false to revoke approval\\n    @return None\\n    \\\"\\\"\\\"\\n    (self.operators[msg.sender])[_operator] = _approved\\n    log.ApprovalForAll(msg.sender, _operator, _approved)\\n\\n\\n@public\\n@constant\\ndef isApprovedForAll(_owner: address, _operator: address) -> bool:\\n    \\\"\\\"\\\"\\n    @notice Queries the approval status of an operator for a given owner.\\n    @param _owner     The owner of the tokens.\\n    @param _operator  Address of authorized operator.\\n    @return True if the operator is approved, false if not\\n    \\\"\\\"\\\"\\n    return (self.operators[_owner])[_operator]\\n\\n\\n@public\\ndef createSingle(_item_owner: address, _id: uint256, _path: string[256]):\\n    \\\"\\\"\\\"\\n    @notice Create a new token type that we can mint later.\\n    @param _item_owner The owner of the item.\\n    @param _id         The id of the token.\\n    @param _path       The path to the token data.\\n    @return None\\n    \\\"\\\"\\\"\\n    assert _item_owner != ZERO_ADDRESS\\n    assert self.owner == msg.sender, \\\"Owner only can create item.\\\"\\n    self.balancesOf[_item_owner][_id] = 0\\n    self.tokensIdCount += 1\\n    self.token_ids[_id] = True\\n    self.uri[_id] = _path\\n    log.URI(_path, _id)\\n    log.TransferSingle(msg.sender, ZERO_ADDRESS, _item_owner, _id, 0)\\n\\n\\n@public\\ndef createBatch(_items_owner: address, _ids: uint256[BATCH_SIZE]):\\n    \\\"\\\"\\\"\\n    @notice Create new token types that we can mint later.\\n    @param _items_owner The owner of the items.\\n    @param _ids         The ids of the tokens.\\n    @return None\\n    \\\"\\\"\\\"\\n    assert _items_owner != ZERO_ADDRESS\\n    assert self.owner == msg.sender, \\\"Owner only can create items.\\\"\\n    for i in range(BATCH_SIZE):\\n        id: uint256 = _ids[i]\\n        self.balancesOf[_items_owner][id] = 0\\n        self.tokensIdCount += 1\\n        self.token_ids[id] = True\\n    zero_supply: uint256[BATCH_SIZE] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]\\n    log.TransferBatch(msg.sender, ZERO_ADDRESS, _items_owner, _ids, zero_supply)\\n\\n\\n@public\\ndef mint(_to: address, _id: uint256, _supply: uint256, _data: bytes[256]=\\\"\\\"):\\n    \\\"\\\"\\\"\\n    @notice Mint a token.\\n    @dev This is not part of the standard.\\n    @param _to      The address of the receiver.\\n    @param _id      The id of the token.\\n    @param _supply  The supply to be minted for the token.\\n    @param _data    The data.\\n    @return None\\n    \\\"\\\"\\\"\\n    assert _to != ZERO_ADDRESS\\n    assert self.owner == msg.sender, \\\"Owner only can mint items.\\\"\\n    decoded_id: int128 = self.decode_id(_id)\\n    assert decoded_id == 1 or decoded_id == 2\\n    if decoded_id == 1 :\\n        assert _supply == 1, \\\"Cannot mint NFT with _supply more than 1\\\"\\n    self.balancesOf[_to][_id] = _supply\\n\\n    log.TransferSingle(msg.sender, ZERO_ADDRESS, _to, _id, _supply)\\n\\n    if _to.is_contract:\\n        returnValue: bytes32 = ERC1155TokenReceiver(_to).onERC1155Received(msg.sender, ZERO_ADDRESS, _id, _supply, _data)\\n        assert returnValue == method_id(\\\"onERC1155Received(address,address,uint256,uint256,bytes)\\\", bytes32)\\n\\n\\n@public\\ndef mintBatch(_to: address, _ids: uint256[BATCH_SIZE], _supplies: uint256[BATCH_SIZE], _data: bytes[256]=\\\"\\\"):\\n    \\\"\\\"\\\"\\n    @notice Mint a batch of tokens.\\n    @dev This is not part of the standard.\\n    @param _to      The address of the receiver.\\n    @param _ids     The ids of the tokens.\\n    @param _supplies The supply to be minted for each token.\\n    @param _data    The data.\\n    @return None\\n    \\\"\\\"\\\"\\n    assert _to != ZERO_ADDRESS\\n    assert self.owner == msg.sender, \\\"Owner only can mint items.\\\"\\n\\n    for i in range(BATCH_SIZE):\\n        id: uint256 = _ids[i]\\n        decoded_id: int128 = self.decode_id(id)\\n        assert decoded_id == 1 or decoded_id == 2\\n\\n        if decoded_id == 1 :\\n            assert _supplies[i] == 1\\n\\n        self.balancesOf[_to][id] = _supplies[i]\\n\\n    log.TransferBatch(msg.sender, ZERO_ADDRESS, _to, _ids, _supplies)\\n\\n    for i in range(BATCH_SIZE):\\n        if _to.is_contract:\\n            returnValue: bytes32 = ERC1155TokenReceiver(_to).onERC1155Received(msg.sender, ZERO_ADDRESS, _ids[i], _supplies[i], _data)\\n            assert returnValue == method_id(\\\"onERC1155Received(address,address,uint256,uint256,bytes)\\\", bytes32)\\n\\n\\n@public\\ndef burn(_id: uint256, _supply: uint256):\\n    \\\"\\\"\\\"\\n    @notice Burns the supply of the specified token.\\n    @param _id        The id of the token\\n    @param _supply    Supply to be burned\\n    @return None\\n    \\\"\\\"\\\"\\n    assert self.balancesOf[msg.sender][_id] >= _supply, \\\"Not enough tokens to burn.\\\"\\n    self.balancesOf[msg.sender][_id] -= _supply\\n    log.TransferSingle(msg.sender, msg.sender, ZERO_ADDRESS, _id, _supply)\\n\\n\\n@public\\ndef burnBatch(_ids: uint256[BATCH_SIZE], _supplies: uint256[BATCH_SIZE]):\\n    \\\"\\\"\\\"\\n    @notice Burns the supply of the specified tokens.\\n    @dev At this point anyone can burn items if they own it.\\n    @param _ids        The ids of the token\\n    @param _supplies   Supplies to be burned\\n    @return None\\n    \\\"\\\"\\\"\\n    for i in range(BATCH_SIZE):\\n        id: uint256 = _ids[i]\\n        assert self.balancesOf[msg.sender][id] >= _supplies[i]\\n\\n    for i in range(BATCH_SIZE):\\n        id: uint256 = _ids[i]\\n        self.balancesOf[msg.sender][id] -= _supplies[i]\\n    log.TransferBatch(msg.sender, msg.sender, ZERO_ADDRESS, _ids, _supplies)\\n\\n\\n@public\\n@payable\\ndef tradeBatch(_from: address, _to: address, _ids: uint256[BATCH_SIZE], _from_supplies: uint256[BATCH_SIZE], _to_supplies: uint256[BATCH_SIZE], _value_eth: uint256, _nonce: uint256, _signature: bytes[65], _data: bytes[256]=\\\"\\\"):\\n    \\\"\\\"\\\"\\n    @notice Trade (atomically swap) tokens with tokens or eth.\\n    @dev Caller must be approved to manage the tokens being transferred out of the `_from` account (see \\\"Approval\\\" section of the standard).\\n        MUST revert if `_to` is the zero address.\\n        MUST revert if _from_supplies[i] > 0 and _to_supplies[i] > 0\\n        MUST revert if len(_ids) != len(_from_supplies) != len(_to_supplies)\\n        MUST revert if _value_eth != msg.value\\n        MUST revert if any of the balance(s) of the holder(s) for token(s) in `_ids` is lower than the respective amount(s) in `positive and negative values` sent to the recipient.\\n        MUST revert on any other error.\\n        MUST emit `TransferSingle` or `TransferBatch` event(s) such that all the balance changes are reflected (see \\\"Safe Transfer Rules\\\" section of the standard).\\n        Balance changes and events MUST follow the ordering of the arrays (_ids[0]/_values[0] before _ids[1]/_values[1], etc).\\n        After the above conditions for the transfer(s) in the batch are met, this function MUST check if `_to` is a smart contract (e.g. code size > 0). If so, it MUST call the relevant `ERC1155TokenReceiver` hook(s) on `_to` and act appropriately (see \\\"Safe Transfer Rules\\\" section of the standard).\\n    @param _from          The address of the sender.\\n    @param _to            The address of the receiver.\\n    @param _ids           The ids of the tokens.\\n    @param _from_supplies The supply of token values that will send the _from.\\n    @param _to_supplies   The supply of token values that will send the _from.\\n    @param _value_eth     The value of the ether.\\n    @param _nonce         The nonce.\\n    @param _signature    The signature of the _to address.\\n    @param _data    The data.\\n    @return None\\n    \\\"\\\"\\\"\\n    # Assert the value of the transaction is less than the balance of A.\\n\\n    assert _from == msg.sender or (self.operators[_from])[msg.sender], \\\"_from must be the sender or approved address\\\"\\n    assert _to != ZERO_ADDRESS, \\\"Destination address must be non-zero.\\\"\\n    assert self.noncesOf[_from][_nonce] == False, \\\"Nonce must be unused.\\\"\\n    assert _value_eth == msg.value, \\\"Sender has not provided enough ether.\\\"\\n\\n    for i in range(BATCH_SIZE):\\n       id: uint256 = _ids[i]\\n       if _from_supplies[i] > 0:\\n           assert _to_supplies[i] == 0\\n           assert self.balancesOf[_from][id] >= _from_supplies[i]\\n       else:\\n           assert _from_supplies[i] == 0\\n           assert self.balancesOf[_to][id] >= _to_supplies[i]\\n\\n    # Create hash from variables.\\n    hash: bytes32 = self._getHash(_from, _to, _ids, _from_supplies, _to_supplies, _value_eth, _nonce)\\n\\n    # Assert that the ecrecover(address,signature) returns true.\\n    recovered_to: address = self.ecrecoverSig(hash, _signature)\\n    assert recovered_to == _to, \\\"Signer does not match signature.\\\"\\n\\n    # Store the nonce\\n    self.noncesOf[msg.sender][_nonce] = True\\n\\n    # Update the balances\\n    for i in range(BATCH_SIZE):\\n        id: uint256 = _ids[i]\\n        if _from_supplies[i] > 0:\\n            self.balancesOf[_from][id] -= _from_supplies[i]\\n            self.balancesOf[_to][id] += _from_supplies[i]\\n        else:\\n            self.balancesOf[_from][id] += _to_supplies[i]\\n            self.balancesOf[_to][id] -= _to_supplies[i]\\n\\n    send(_to, msg.value)\\n\\n    log.TransferBatch(msg.sender, _from, _to, _ids, _from_supplies)\\n    log.TransferBatch(msg.sender, _to, _from, _ids, _to_supplies)\\n\\n\\n    if _to.is_contract:\\n        returnValue: bytes32 = ERC1155TokenReceiver(_to).onERC1155BatchReceived(msg.sender, _to, _ids, _from_supplies, _data)\\n        assert returnValue == method_id(\\\"onERC1155BatchReceived(address,address,uint256,uint256,bytes)\\\", bytes32)\\n    if _from.is_contract:\\n        returnValue: bytes32 = ERC1155TokenReceiver(_from).onERC1155BatchReceived(msg.sender, _from, _ids, _to_supplies, _data)\\n        assert returnValue == method_id(\\\"onERC1155BatchReceived(address,address,uint256,uint256,bytes)\\\", bytes32)\\n\\n\\n\\n@public\\n@payable\\ndef trade(_from: address, _to: address, _id: uint256, _from_supply: uint256, _to_supply: uint256, _value_eth: uint256, _nonce: uint256, _signature: bytes[65], _data: bytes[256]=\\\"\\\"):\\n    \\\"\\\"\\\"\\n    @notice Trade (atomically swap) tokens with tokens or eth.\\n    @dev Caller must be approved to manage the tokens being transferred out of the `_from` account (see \\\"Approval\\\" section of the standard).\\n        MUST revert if `_to` is the zero address.\\n        MUST revert if _from_supply > 0 and _to_supply > 0\\n        MUST revert if _value_eth != msg.value\\n        MUST revert if any of the balance(s) of the holder(s) for token(s) in `_id` is lower than the respective amount in `positive or negative value` sent to the recipient.\\n        MUST revert on any other error.\\n        MUST emit `TransferSingle` or `TransferBatch` event(s) such that all the balance changes are reflected (see \\\"Safe Transfer Rules\\\" section of the standard).\\n        Balance changes and events MUST follow the ordering of the arrays (_ids[0]/_values[0] before _ids[1]/_values[1], etc).\\n        After the above conditions for the transfer(s) in the batch are met, this function MUST check if `_to` is a smart contract (e.g. code size > 0). If so, it MUST call the relevant `ERC1155TokenReceiver` hook(s) on `_to` and act appropriately (see \\\"Safe Transfer Rules\\\" section of the standard).\\n    @param _from            The from address (seller of eth, potential receiver of tokens).\\n    @param _to              The receiver address (receiver of tokens).\\n    @param _id              The id of the token\\n    @param _from_supply     The change in value of token (for _from)\\n    @param _to_supply       The change in value of token (for _to)\\n    @param _value_eth       The value of the ETH sent to the _from address.\\n    @param _nonce           The nonce.\\n    @param _signature       The signature of the _to address.\\n    @param _data    The data.\\n    @return None\\n    \\\"\\\"\\\"\\n    # Assert the value of the transaction is less than the balance of A.\\n    assert _from == msg.sender or (self.operators[_from])[msg.sender]\\n    assert _to != ZERO_ADDRESS, \\\"Destination address must be non-zero.\\\"\\n    assert self.noncesOf[_from][_nonce] == False, \\\"Nonce must be unused.\\\"\\n    assert _value_eth == msg.value, \\\"Sender has not provided enough ether.\\\"\\n    if _from_supply > 0:\\n        assert _to_supply == 0\\n        assert self.balancesOf[_from][_id] >= _from_supply\\n    else:\\n        assert _from_supply == 0\\n        assert self.balancesOf[_to][_id] >= _to_supply\\n\\n    # Create hash from variables.\\n    hash: bytes32 = self._getSingleHash(_from, _to, _id, _from_supply, _to_supply, _value_eth, _nonce)\\n\\n    # Assert that the ecrecover(address,signature) returns true.\\n    recovered_to: address = self.ecrecoverSig(hash, _signature)\\n    assert recovered_to == _to, \\\"Signer does not match signature.\\\"\\n\\n    # Store the nonce\\n    self.noncesOf[msg.sender][_nonce] = True\\n\\n    # Update the balances\\n    if _from_supply > 0:\\n        self.balancesOf[_from][_id] -= _from_supply\\n        self.balancesOf[_to][_id] += _from_supply\\n    else:\\n        self.balancesOf[_from][_id] += _to_supply\\n        self.balancesOf[_to][_id] -= _to_supply\\n\\n    send(_to, msg.value)\\n\\n    log.TransferSingle(msg.sender, _from, _to, _id, _from_supply)\\n    log.TransferSingle(msg.sender, _to, _from, _id, _to_supply)\\n\\n    if _to.is_contract:\\n        returnValue: bytes32 = ERC1155TokenReceiver(_to).onERC1155Received(msg.sender, _to, _id, _from_supply, _data)\\n        assert returnValue == method_id(\\\"onERC1155BatchReceived(address,address,uint256,uint256,bytes)\\\", bytes32)\\n    if _from.is_contract:\\n        returnValue: bytes32 = ERC1155TokenReceiver(_from).onERC1155Received(msg.sender, _from, _id, _to_supply, _data)\\n        assert returnValue == method_id(\\\"onERC1155BatchReceived(address,address,uint256,uint256,bytes)\\\", bytes32)\\n\",\n  \"sourcePath\": \"/Users/aristotelistriantafyllidis/Documents/agents-research/erc1155/contracts/erc1155.vy\",\n  \"compiler\": {\n    \"name\": \"vyper\",\n    \"version\": \"0.1.0b12+commit.a01cdc8\"\n  },\n  \"networks\": {\n    \"1583918911727\": {\n      \"events\": {\n        \"0xc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62\": {\n          \"name\": \"TransferSingle\",\n          \"inputs\": [\n            {\n              \"type\": \"address\",\n              \"name\": \"_operator\",\n              \"indexed\": true\n            },\n            {\n              \"type\": \"address\",\n              \"name\": \"_from\",\n              \"indexed\": true\n            },\n            {\n              \"type\": \"address\",\n              \"name\": \"_to\",\n              \"indexed\": true\n            },\n            {\n              \"type\": \"uint256\",\n              \"name\": \"_id\",\n              \"indexed\": false\n            },\n            {\n              \"type\": \"uint256\",\n              \"name\": \"_value\",\n              \"indexed\": false\n            }\n          ],\n          \"anonymous\": false,\n          \"type\": \"event\",\n          \"signature\": \"0xc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62\"\n        },\n        \"0x514c24e4790d7c31a095a1688a73a01f28d936a9a85d806ba95970d8ee88efa8\": {\n          \"name\": \"TransferBatch\",\n          \"inputs\": [\n            {\n              \"type\": \"address\",\n              \"name\": \"_operator\",\n              \"indexed\": true\n            },\n            {\n              \"type\": \"address\",\n              \"name\": \"_from\",\n              \"indexed\": true\n            },\n            {\n              \"type\": \"address\",\n              \"name\": \"_to\",\n              \"indexed\": true\n            },\n            {\n              \"type\": \"uint256[10]\",\n              \"name\": \"_ids\",\n              \"indexed\": false\n            },\n            {\n              \"type\": \"uint256[10]\",\n              \"name\": \"_values\",\n              \"indexed\": false\n            }\n          ],\n          \"anonymous\": false,\n          \"type\": \"event\",\n          \"signature\": \"0x514c24e4790d7c31a095a1688a73a01f28d936a9a85d806ba95970d8ee88efa8\"\n        },\n        \"0x17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31\": {\n          \"name\": \"ApprovalForAll\",\n          \"inputs\": [\n            {\n              \"type\": \"address\",\n              \"name\": \"_owner\",\n              \"indexed\": true\n            },\n            {\n              \"type\": \"address\",\n              \"name\": \"_operator\",\n              \"indexed\": true\n            },\n            {\n              \"type\": \"bool\",\n              \"name\": \"_approved\",\n              \"indexed\": false\n            }\n          ],\n          \"anonymous\": false,\n          \"type\": \"event\",\n          \"signature\": \"0x17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31\"\n        },\n        \"0x6bb7ff708619ba0610cba295a58592e0451dee2622938c8755667688daf3529b\": {\n          \"name\": \"URI\",\n          \"inputs\": [\n            {\n              \"type\": \"string\",\n              \"name\": \"_value\",\n              \"indexed\": false\n            },\n            {\n              \"type\": \"uint256\",\n              \"name\": \"_id\",\n              \"indexed\": true\n            }\n          ],\n          \"anonymous\": false,\n          \"type\": \"event\",\n          \"signature\": \"0x6bb7ff708619ba0610cba295a58592e0451dee2622938c8755667688daf3529b\"\n        }\n      },\n      \"links\": {},\n      \"address\": \"0x9561C133DD8580860B6b7E504bC5Aa500f0f06a7\",\n      \"transactionHash\": \"0x816b272ebd644b189a3addfbd429b0ea0fa7b2403cca3aa038bcd59f09d9c116\"\n    }\n  },\n  \"schemaVersion\": \"3.0.19\",\n  \"updatedAt\": \"2020-03-11T13:47:51.885Z\",\n  \"networkType\": \"ethereum\"\n}"
  },
  {
    "path": "packages/fetchai/contracts/erc1155/contract.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the erc1155 contract definition.\"\"\"\n\nimport logging\nimport random\nfrom typing import Dict, List, Optional, cast\n\nfrom aea_ledger_cosmos import CosmosApi\nfrom aea_ledger_ethereum import EthereumApi\nfrom aea_ledger_fetchai import FetchAIApi\nfrom google.protobuf.any_pb2 import Any as ProtoAny\n\nfrom aea.common import Address, JSONLike\nfrom aea.configurations.base import PublicId\nfrom aea.contracts.base import Contract\nfrom aea.crypto.base import LedgerApi\n\n\n_default_logger = logging.getLogger(\"aea.packages.fetchai.contracts.erc1155.contract\")\nMAX_UINT_256 = 2 ^ 256 - 1\n\nPUBLIC_ID = PublicId.from_str(\"fetchai/erc1155:0.23.3\")\nDEFAUT_ETH_ATOMIC_SWAP_GAS_LIMIT = 2818111\nDEFAUT_COSMOS_ATOMIC_SWAP_GAS_LIMIT = 1500000\nDEFAUT_ETH_SINGLE_TASK_GAS_LIMIT = 300000\nDEFAUT_COSMOS_SINGLE_TASK_GAS_LIMIT = 300000\nDEFAUT_ETH_BATCH_TASK_GAS_LIMIT = 500000\nDEFAUT_COSMOS_BATCH_TASK_GAS_LIMIT = 500000\n\n\ndef keccak256(input_: bytes) -> bytes:\n    \"\"\"Compute hash.\"\"\"\n    return bytes(bytearray.fromhex(EthereumApi.get_hash(input_)[2:]))\n\n\nclass ERC1155Contract(Contract):\n    \"\"\"The ERC1155 contract class which acts as a bridge between AEA framework and ERC1155 ABI.\"\"\"\n\n    contract_id = PUBLIC_ID\n\n    @classmethod\n    def generate_token_ids(\n        cls, token_type: int, nb_tokens: int, starting_index: int = 0\n    ) -> List[int]:\n        \"\"\"\n        Generate token_ids.\n\n        :param token_type: the token type (nft or ft)\n        :param nb_tokens: the number of tokens\n        :param starting_index: the index at which to start constructing ids\n        :return: the list of token ids generated\n        \"\"\"\n        token_ids = []\n        for i in range(nb_tokens):\n            index = starting_index + i\n            token_id = cls._generate_id(index, token_type)\n            token_ids.append(token_id)\n        return token_ids\n\n    @staticmethod\n    def _generate_id(index: int, token_type: int) -> int:\n        \"\"\"\n        Generate a token_id.\n\n        :param index: the index to byte-shift\n        :param token_type: the token type\n        :return: the token id\n        \"\"\"\n        token_id = (token_type << 128) + index\n        return token_id\n\n    @classmethod\n    def get_create_batch_transaction(  # pylint: disable=unused-argument\n        cls,\n        ledger_api: LedgerApi,\n        contract_address: Address,\n        deployer_address: Address,\n        token_ids: List[int],\n        data: Optional[bytes] = b\"\",\n        gas: Optional[int] = None,\n        tx_fee: int = 0,\n    ) -> JSONLike:\n        \"\"\"\n        Get the transaction to create a batch of tokens.\n\n        :param ledger_api: the ledger API\n        :param contract_address: the address of the contract\n        :param deployer_address: the address of the deployer\n        :param token_ids: the list of token ids for creation\n        :param data: the data to include in the transaction\n        :param gas: the gas to be used\n        :param tx_fee: the tx_fee to be used\n        :return: the transaction object\n        \"\"\"\n        if ledger_api.identifier == EthereumApi.identifier:\n            gas = gas if gas is not None else DEFAUT_ETH_BATCH_TASK_GAS_LIMIT\n            nonce = ledger_api.api.eth.getTransactionCount(deployer_address)\n            instance = cls.get_instance(ledger_api, contract_address)\n            tx = instance.functions.createBatch(\n                deployer_address, token_ids\n            ).buildTransaction(\n                {\n                    \"gas\": gas,\n                    \"gasPrice\": ledger_api.api.toWei(\"50\", \"gwei\"),\n                    \"nonce\": nonce,\n                }\n            )\n            tx = ledger_api.update_with_gas_estimate(tx)\n            return tx\n        if ledger_api.identifier in [CosmosApi.identifier, FetchAIApi.identifier]:\n            gas = gas if gas is not None else DEFAUT_COSMOS_BATCH_TASK_GAS_LIMIT\n            tokens = []\n            for token_id in token_ids:\n                tokens.append({\"id\": str(token_id), \"path\": str(token_id)})\n\n            msg = {\n                \"create_batch\": {\"item_owner\": str(deployer_address), \"tokens\": tokens}\n            }\n            cosmos_api = cast(CosmosApi, ledger_api)\n            tx = cosmos_api.get_handle_transaction(\n                deployer_address,\n                contract_address,\n                msg,\n                amount=0,\n                tx_fee=tx_fee,\n                gas=gas,\n            )\n            return tx\n        raise NotImplementedError\n\n    @classmethod\n    def get_create_single_transaction(\n        cls,\n        ledger_api: LedgerApi,\n        contract_address: Address,\n        deployer_address: Address,\n        token_id: int,\n        data: Optional[bytes] = b\"\",\n        gas: Optional[int] = None,\n        tx_fee: int = 0,\n    ) -> JSONLike:\n        \"\"\"\n        Get the transaction to create a single token.\n\n        :param ledger_api: the ledger API\n        :param contract_address: the address of the contract\n        :param deployer_address: the address of the deployer\n        :param token_id: the token id for creation\n        :param data: the data to include in the transaction\n        :param gas: the gas to be used\n        :param tx_fee: the tx_fee to be used\n        :return: the transaction object\n        \"\"\"\n        if ledger_api.identifier == EthereumApi.identifier:\n            gas = gas if gas is not None else DEFAUT_COSMOS_SINGLE_TASK_GAS_LIMIT\n            nonce = ledger_api.api.eth.getTransactionCount(deployer_address)\n            instance = cls.get_instance(ledger_api, contract_address)\n            tx = instance.functions.createSingle(\n                deployer_address, token_id, data\n            ).buildTransaction(\n                {\n                    \"gas\": gas,\n                    \"gasPrice\": ledger_api.api.toWei(\"50\", \"gwei\"),\n                    \"nonce\": nonce,\n                }\n            )\n            tx = ledger_api.update_with_gas_estimate(tx)\n            return tx\n        if ledger_api.identifier in [CosmosApi.identifier, FetchAIApi.identifier]:\n            gas = gas if gas is not None else DEFAUT_ETH_SINGLE_TASK_GAS_LIMIT\n            msg = {\n                \"create_single\": {\n                    \"item_owner\": deployer_address,\n                    \"id\": str(token_id),\n                    \"path\": str(data),\n                }\n            }\n            cosmos_api = cast(CosmosApi, ledger_api)\n            tx = cosmos_api.get_handle_transaction(\n                deployer_address,\n                contract_address,\n                msg,\n                amount=0,\n                tx_fee=tx_fee,\n                gas=gas,\n            )\n            return tx\n        raise NotImplementedError\n\n    @classmethod\n    def get_mint_batch_transaction(\n        cls,\n        ledger_api: LedgerApi,\n        contract_address: Address,\n        deployer_address: Address,\n        recipient_address: Address,\n        token_ids: List[int],\n        mint_quantities: List[int],\n        data: Optional[bytes] = b\"\",\n        gas: Optional[int] = None,\n        tx_fee: int = 0,\n    ) -> JSONLike:\n        \"\"\"\n        Get the transaction to mint a batch of tokens.\n\n        :param ledger_api: the ledger API\n        :param contract_address: the address of the contract\n        :param deployer_address: the address of the deployer\n        :param recipient_address: the address of the recipient\n        :param token_ids: the token ids\n        :param mint_quantities: the quantity to mint for each token\n        :param data: the data to include in the transaction\n        :param gas: the gas to be used\n        :param tx_fee: the tx_fee to be used\n        :return: the transaction object\n        \"\"\"\n        cls.validate_mint_quantities(token_ids, mint_quantities)\n        if ledger_api.identifier == EthereumApi.identifier:\n            gas = gas if gas is not None else DEFAUT_ETH_BATCH_TASK_GAS_LIMIT\n            nonce = ledger_api.api.eth.getTransactionCount(deployer_address)\n            instance = cls.get_instance(ledger_api, contract_address)\n            tx = instance.functions.mintBatch(\n                recipient_address, token_ids, mint_quantities, data\n            ).buildTransaction(\n                {\n                    \"gas\": gas,\n                    \"gasPrice\": ledger_api.api.toWei(\"50\", \"gwei\"),\n                    \"nonce\": nonce,\n                }\n            )\n            tx = ledger_api.update_with_gas_estimate(tx)\n            return tx\n        if ledger_api.identifier in [CosmosApi.identifier, FetchAIApi.identifier]:\n            gas = gas if gas is not None else DEFAUT_COSMOS_BATCH_TASK_GAS_LIMIT\n            tokens = []\n            for token_id, quantity in zip(token_ids, mint_quantities):\n                tokens.append({\"id\": str(token_id), \"value\": str(quantity)})\n\n            msg = {\n                \"mint_batch\": {\n                    \"to_address\": recipient_address,\n                    \"data\": str(data),\n                    \"tokens\": tokens,\n                }\n            }\n            cosmos_api = cast(CosmosApi, ledger_api)\n            tx = cosmos_api.get_handle_transaction(\n                deployer_address,\n                contract_address,\n                msg,\n                amount=0,\n                tx_fee=tx_fee,\n                gas=gas,\n            )\n            return tx\n        raise NotImplementedError\n\n    @classmethod\n    def validate_mint_quantities(\n        cls, token_ids: List[int], mint_quantities: List[int]\n    ) -> None:\n        \"\"\"Validate the mint quantities.\"\"\"\n        for token_id, mint_quantity in zip(token_ids, mint_quantities):\n            decoded_type = cls.decode_id(token_id)\n            if decoded_type not in [\n                1,\n                2,\n            ]:\n                raise ValueError(\n                    \"The token type must be 1 or 2. Found type={} for token_id={}\".format(\n                        decoded_type, token_id\n                    )\n                )\n            if decoded_type == 1:\n                if mint_quantity != 1:\n                    raise ValueError(\n                        \"Cannot mint NFT (token_id={}) with mint_quantity more than 1 (found={})\".format(\n                            token_id, mint_quantity\n                        )\n                    )\n\n    @staticmethod\n    def decode_id(token_id: int) -> int:\n        \"\"\"\n        Decode a give token id.\n\n        :param token_id: the byte shifted token id\n        :return: the non-shifted id\n        \"\"\"\n        decoded_type = token_id >> 128\n        return decoded_type\n\n    @classmethod\n    def get_mint_single_transaction(\n        cls,\n        ledger_api: LedgerApi,\n        contract_address: Address,\n        deployer_address: Address,\n        recipient_address: Address,\n        token_id: int,\n        mint_quantity: int,\n        data: Optional[bytes] = b\"\",\n        gas: Optional[int] = None,\n        tx_fee: int = 0,\n    ) -> JSONLike:\n        \"\"\"\n        Get the transaction to mint a single token.\n\n        :param ledger_api: the ledger API\n        :param contract_address: the address of the contract\n        :param deployer_address: the address of the deployer\n        :param recipient_address: the address of the recipient\n        :param token_id: the token id\n        :param mint_quantity: the quantity to mint\n        :param data: the data to include in the transaction\n        :param gas: the gas to be used\n        :param tx_fee: the tx_fee to be used\n        :return: the transaction object\n        \"\"\"\n        if ledger_api.identifier == EthereumApi.identifier:\n            gas = gas if gas is not None else DEFAUT_ETH_SINGLE_TASK_GAS_LIMIT\n            nonce = ledger_api.api.eth.getTransactionCount(deployer_address)\n            instance = cls.get_instance(ledger_api, contract_address)\n            tx = instance.functions.mint(\n                recipient_address, token_id, mint_quantity, data\n            ).buildTransaction(\n                {\n                    \"gas\": gas,\n                    \"gasPrice\": ledger_api.api.toWei(\"50\", \"gwei\"),\n                    \"nonce\": nonce,\n                }\n            )\n            tx = ledger_api.update_with_gas_estimate(tx)\n            return tx\n        if ledger_api.identifier in [CosmosApi.identifier, FetchAIApi.identifier]:\n            gas = gas if gas is not None else DEFAUT_COSMOS_SINGLE_TASK_GAS_LIMIT\n            msg = {\n                \"mint_single\": {\n                    \"to_address\": recipient_address,\n                    \"id\": str(token_id),\n                    \"supply\": str(mint_quantity),\n                    \"data\": str(data),\n                }\n            }\n            cosmos_api = cast(CosmosApi, ledger_api)\n            tx = cosmos_api.get_handle_transaction(\n                deployer_address,\n                contract_address,\n                msg,\n                amount=0,\n                tx_fee=tx_fee,\n                gas=gas,\n            )\n            return tx\n        raise NotImplementedError\n\n    @classmethod\n    def get_balance(\n        cls,\n        ledger_api: LedgerApi,\n        contract_address: Address,\n        agent_address: Address,\n        token_id: int,\n    ) -> JSONLike:\n        \"\"\"\n        Get the balance for a specific token id.\n\n        :param ledger_api: the ledger API\n        :param contract_address: the address of the contract\n        :param agent_address: the address\n        :param token_id: the token id\n        :return: the balance in a dictionary - {\"balance\": {token_id: int, balance: int}}\n        \"\"\"\n        if ledger_api.identifier == EthereumApi.identifier:\n            instance = cls.get_instance(ledger_api, contract_address)\n            balance = instance.functions.balanceOf(agent_address, token_id).call()\n            result = {token_id: balance}\n            return {\"balance\": result}\n        if ledger_api.identifier in [CosmosApi.identifier, FetchAIApi.identifier]:\n            cosmos_api = cast(CosmosApi, ledger_api)\n            msg: JSONLike = {\n                \"balance\": {\"address\": str(agent_address), \"id\": str(token_id)}\n            }\n            query_res = cosmos_api.execute_contract_query(contract_address, msg)\n            if query_res is None:\n                raise ValueError(\"call to contract returned None\")\n            # Convert {\"balance\": balance: str} balances to Dict[token_id: int, balance: int]\n            result = {token_id: int(cast(str, query_res[\"balance\"]))}\n            return {\"balance\": result}\n        raise NotImplementedError\n\n    @classmethod\n    def get_atomic_swap_single_transaction(\n        cls,\n        ledger_api: LedgerApi,\n        contract_address: Address,\n        from_address: Address,\n        to_address: Address,\n        token_id: int,\n        from_supply: int,\n        to_supply: int,\n        value: int,\n        trade_nonce: int,\n        signature: Optional[str] = None,\n        data: Optional[bytes] = b\"\",\n        gas: Optional[int] = None,\n        from_pubkey: Optional[str] = None,\n        to_pubkey: Optional[str] = None,\n        tx_fee: int = 0,\n    ) -> JSONLike:\n        \"\"\"\n        Get the transaction for a trustless trade between two agents for a single token.\n\n        :param ledger_api: the ledger API\n        :param contract_address: the address of the contract\n        :param from_address: the address of the agent sending tokens, receiving ether\n        :param to_address: the address of the agent receiving tokens, sending ether\n        :param token_id: the token id\n        :param from_supply: the supply of tokens by the sender\n        :param to_supply: the supply of tokens by the receiver\n        :param value: the amount of ether sent from the to_address to the from_address\n        :param trade_nonce: the nonce of the trade, this is separate from the nonce of the transaction\n        :param signature: the signature of the trade - used on Ethereum\n        :param data: the data to include in the transaction\n        :param gas: the gas to be used\n        :param from_pubkey: Public key associated with from_address - Used on Cosmos/Fetch\n        :param to_pubkey: Public key associated with to_address - Used on Cosmos/Fetch\n        :param tx_fee: the tx_fee to be used\n        :return: a ledger transaction object\n        \"\"\"\n        if from_supply > 0 and to_supply > 0:\n            raise RuntimeError(\n                \"Can't determine direction of swap because from_supply and to_supply are both non-zero.\"\n            )\n\n        if from_supply == 0 and to_supply == 0 and value == 0:\n            raise RuntimeError(\"Invalid atomic swap with all supplies to be zero.\")\n\n        if ledger_api.identifier == EthereumApi.identifier:\n            if signature is None:\n                raise RuntimeError(\"Signature expected for Eth based contract.\")\n            if from_pubkey is not None or to_pubkey is not None:\n                raise RuntimeError(\"Pubkeys not expected for Eth based contract.\")\n\n            gas = gas if gas is not None else DEFAUT_ETH_ATOMIC_SWAP_GAS_LIMIT\n            nonce = ledger_api.api.eth.getTransactionCount(from_address)\n            instance = cls.get_instance(ledger_api, contract_address)\n            value_eth_wei = ledger_api.api.toWei(value, \"ether\")\n            tx = instance.functions.trade(\n                from_address,\n                to_address,\n                token_id,\n                from_supply,\n                to_supply,\n                value_eth_wei,\n                trade_nonce,\n                signature,\n                data,\n            ).buildTransaction(\n                {\n                    \"gas\": gas,\n                    \"from\": from_address,\n                    \"value\": value_eth_wei,\n                    \"gasPrice\": ledger_api.api.toWei(\"50\", \"gwei\"),\n                    \"nonce\": nonce,\n                }\n            )\n            tx = ledger_api.update_with_gas_estimate(tx)\n            return tx\n        if ledger_api.identifier in [CosmosApi.identifier, FetchAIApi.identifier]:\n            if signature is not None:\n                raise RuntimeError(\n                    \"Signature not expected for Cosmos/Fetch based contract.\"\n                )\n\n            cosmos_api = cast(CosmosApi, ledger_api)\n            msgs: List[ProtoAny] = []\n            from_pubkey_required: bool = False\n            to_pubkey_required: bool = False\n            gas = gas if gas is not None else DEFAUT_COSMOS_ATOMIC_SWAP_GAS_LIMIT\n\n            # from_address sends tokens\n            if from_supply > 0:\n                contract_msg: JSONLike = {\n                    \"transfer_single\": {\n                        \"operator\": str(from_address),\n                        \"from_address\": str(from_address),\n                        \"to_address\": str(to_address),\n                        \"id\": str(token_id),\n                        \"value\": str(from_supply),\n                    }\n                }\n                msgs.append(\n                    cosmos_api.get_packed_exec_msg(\n                        sender_address=from_address,\n                        contract_address=contract_address,\n                        msg=contract_msg,\n                    )\n                )\n                from_pubkey_required = True\n\n            # to_address sends tokens\n            if to_supply > 0:\n                contract_msg = {\n                    \"transfer_single\": {\n                        \"operator\": str(to_address),\n                        \"from_address\": str(to_address),\n                        \"to_address\": str(from_address),\n                        \"id\": str(token_id),\n                        \"value\": str(to_supply),\n                    }\n                }\n                msgs.append(\n                    cosmos_api.get_packed_exec_msg(\n                        sender_address=to_address,\n                        contract_address=contract_address,\n                        msg=contract_msg,\n                    )\n                )\n                to_pubkey_required = True\n\n            # Sending native tokens from to_address to from_address\n            if value > 0:\n                msgs.append(\n                    cosmos_api.get_packed_send_msg(to_address, from_address, value)\n                )\n                to_pubkey_required = True\n\n            # Determine required signers and generate tx\n            if to_pubkey_required and not from_pubkey_required:\n                if to_pubkey is None:\n                    raise RuntimeError(\n                        \"to_pubkey is missing and required for Cosmos/Fetch based contract.\"\n                    )\n                tx = cosmos_api.get_multi_transaction(\n                    from_addresses=[to_address],\n                    pub_keys=[bytes.fromhex(to_pubkey)],\n                    msgs=msgs,\n                    gas=gas,\n                    tx_fee=tx_fee,\n                )\n            elif to_pubkey_required and from_pubkey_required:\n                if from_pubkey is None:\n                    raise RuntimeError(\n                        \"from_pubkey is missing and required for Cosmos/Fetch based contract.\"\n                    )\n                if to_pubkey is None:\n                    raise RuntimeError(\n                        \"to_pubkey is missing and required for Cosmos/Fetch based contract.\"\n                    )\n                tx = cosmos_api.get_multi_transaction(\n                    from_addresses=[from_address, to_address],\n                    pub_keys=[bytes.fromhex(from_pubkey), bytes.fromhex(to_pubkey)],\n                    msgs=msgs,\n                    gas=gas,\n                    tx_fee=tx_fee,\n                )\n            else:\n                if from_pubkey is None:\n                    raise RuntimeError(\n                        \"from_pubkey is missing and required for Cosmos/Fetch based contract.\"\n                    )\n                tx = cosmos_api.get_multi_transaction(\n                    from_addresses=[from_address],\n                    pub_keys=[bytes.fromhex(from_pubkey)],\n                    msgs=msgs,\n                    gas=gas,\n                    tx_fee=tx_fee,\n                )\n\n            return tx\n\n        raise NotImplementedError  # pragma: nocover\n\n    @classmethod\n    def get_balances(\n        cls,\n        ledger_api: LedgerApi,\n        contract_address: Address,\n        agent_address: Address,\n        token_ids: List[int],\n    ) -> JSONLike:\n        \"\"\"\n        Get the balances for a batch of specific token ids.\n\n        :param ledger_api: the ledger API\n        :param contract_address: the address of the contract\n        :param agent_address: the address\n        :param token_ids: the token id\n        :return: the balances in dictionary - {\"balances\": {id: int, balance: int}}\n        \"\"\"\n        if ledger_api.identifier == EthereumApi.identifier:\n            instance = cls.get_instance(ledger_api, contract_address)\n            balances = instance.functions.balanceOfBatch(\n                [agent_address] * 10, token_ids\n            ).call()\n            result = dict(zip(token_ids, balances))\n            return {\"balances\": result}\n        if ledger_api.identifier in [CosmosApi.identifier, FetchAIApi.identifier]:\n            tokens = []\n            for token_id in token_ids:\n                tokens.append({\"address\": agent_address, \"id\": str(token_id)})\n\n            msg: JSONLike = {\"balance_batch\": {\"addresses\": tokens}}\n\n            cosmos_api = cast(CosmosApi, ledger_api)\n            query_res = cosmos_api.execute_contract_query(contract_address, msg)\n            # Convert List[balances: str] balances to Dict[token_id: int, balance: int]\n            if query_res is None:\n                raise ValueError(\"call to contract returned None\")\n            result = {\n                token_id: int(balance)\n                for token_id, balance in zip(\n                    token_ids, cast(List[str], query_res[\"balances\"])\n                )\n            }\n            return {\"balances\": result}\n        raise NotImplementedError  # pragma: nocover\n\n    @classmethod\n    def get_atomic_swap_batch_transaction(\n        cls,\n        ledger_api: LedgerApi,\n        contract_address: Address,\n        from_address: Address,\n        to_address: Address,\n        token_ids: List[int],\n        from_supplies: List[int],\n        to_supplies: List[int],\n        value: int,\n        trade_nonce: int,\n        signature: Optional[str] = None,\n        data: Optional[bytes] = b\"\",\n        gas: Optional[int] = None,\n        from_pubkey: Optional[str] = None,\n        to_pubkey: Optional[str] = None,\n        tx_fee: int = 0,\n    ) -> JSONLike:\n        \"\"\"\n        Get the transaction for a trustless trade between two agents for a batch of tokens.\n\n        :param ledger_api: the ledger API\n        :param contract_address: the address of the contract\n        :param from_address: the address of the agent sending tokens, receiving ether\n        :param to_address: the address of the agent receiving tokens, sending ether\n        :param token_ids: the token ids\n        :param from_supplies: the supply of tokens by the sender\n        :param to_supplies: the supply of tokens by the receiver\n        :param value: the amount of ether sent from the to_address to the from_address\n        :param trade_nonce: the nonce of the trade, this is separate from the nonce of the transaction\n        :param signature: the signature of the trade - used on Ethereum\n        :param data: the data to include in the transaction\n        :param gas: the gas to be used\n        :param from_pubkey: Public key associated with from_address - Used on Cosmos/Fetch\n        :param to_pubkey: Public key associated with to_address - Used on Cosmos/Fetch\n        :param tx_fee: the tx_fee to be used\n        :return: a ledger transaction object\n        \"\"\"\n        if ledger_api.identifier == EthereumApi.identifier:\n            if signature is None:\n                raise RuntimeError(\"Signature expected for Eth based contract.\")\n            if from_pubkey is not None or to_pubkey is not None:\n                raise RuntimeError(\"Pubkeys not expected for Eth based contract.\")\n\n            gas = gas if gas is not None else DEFAUT_ETH_ATOMIC_SWAP_GAS_LIMIT\n            nonce = ledger_api.api.eth.getTransactionCount(from_address)\n            instance = cls.get_instance(ledger_api, contract_address)\n            value_eth_wei = ledger_api.api.toWei(value, \"ether\")\n            tx = instance.functions.tradeBatch(\n                from_address,\n                to_address,\n                token_ids,\n                from_supplies,\n                to_supplies,\n                value_eth_wei,\n                trade_nonce,\n                signature,\n                data,\n            ).buildTransaction(\n                {\n                    \"gas\": gas,\n                    \"from\": from_address,\n                    \"value\": value_eth_wei,\n                    \"gasPrice\": ledger_api.api.toWei(\"50\", \"gwei\"),\n                    \"nonce\": nonce,\n                }\n            )\n            tx = ledger_api.update_with_gas_estimate(tx)\n            return tx\n        if ledger_api.identifier in [CosmosApi.identifier, FetchAIApi.identifier]:\n            if signature is not None:\n                raise RuntimeError(\n                    \"Signature not expected for Cosmos/Fetch based contract.\"\n                )\n\n            gas = gas if gas is not None else DEFAUT_COSMOS_ATOMIC_SWAP_GAS_LIMIT\n            cosmos_api = cast(CosmosApi, ledger_api)\n            msgs: List[ProtoAny] = []\n            from_pubkey_required: bool = False\n            to_pubkey_required: bool = False\n\n            # Split token transfers to two batch transfers for each side\n            from_tokens: List[Dict[str, str]] = []\n            to_tokens: List[Dict[str, str]] = []\n            for token_id, from_supply, to_supply in zip(\n                token_ids, from_supplies, to_supplies\n            ):\n                if from_supply > 0:\n                    from_tokens.append({\"id\": str(token_id), \"value\": str(from_supply)})\n                if to_supply > 0:\n                    to_tokens.append({\"id\": str(token_id), \"value\": str(to_supply)})\n\n            # First direction of swap\n            if len(from_tokens) != 0:\n                contract_msg: JSONLike = {\n                    \"transfer_batch\": {\n                        \"operator\": str(from_address),\n                        \"from_address\": str(from_address),\n                        \"to_address\": str(to_address),\n                        \"tokens\": from_tokens,\n                    }\n                }\n                msgs.append(\n                    cosmos_api.get_packed_exec_msg(\n                        sender_address=from_address,\n                        contract_address=contract_address,\n                        msg=contract_msg,\n                    )\n                )\n                from_pubkey_required = True\n\n            # Second direction of swap\n            if len(to_tokens) != 0:\n                contract_msg = {\n                    \"transfer_batch\": {\n                        \"operator\": str(to_address),\n                        \"from_address\": str(to_address),\n                        \"to_address\": str(from_address),\n                        \"tokens\": to_tokens,\n                    }\n                }\n                msgs.append(\n                    cosmos_api.get_packed_exec_msg(\n                        sender_address=to_address,\n                        contract_address=contract_address,\n                        msg=contract_msg,\n                    )\n                )\n                to_pubkey_required = True\n\n            # Sending native tokens from to_address to from_address\n            if value > 0:\n                msgs.append(\n                    cosmos_api.get_packed_send_msg(to_address, from_address, value)\n                )\n                to_pubkey_required = True\n\n            if len(from_tokens) == 0 and len(to_tokens) == 0 and value == 0:\n                raise RuntimeError(\"Invalid atomic swap with all supplies to be zero.\")\n\n            # Determine required signers and generate tx\n            if to_pubkey_required and not from_pubkey_required:\n                if to_pubkey is None:\n                    raise RuntimeError(\n                        \"to_pubkey is missing and required for Cosmos/Fetch based contract.\"\n                    )\n                tx = cosmos_api.get_multi_transaction(\n                    from_addresses=[to_address],\n                    pub_keys=[bytes.fromhex(to_pubkey)],\n                    msgs=msgs,\n                    gas=gas,\n                    tx_fee=tx_fee,\n                )\n            elif to_pubkey_required and from_pubkey_required:\n                if from_pubkey is None:\n                    raise RuntimeError(\n                        \"to_pubkey is missing and required for Cosmos/Fetch based contract.\"\n                    )\n                if to_pubkey is None:\n                    raise RuntimeError(\n                        \"to_pubkey is missing and required for Cosmos/Fetch based contract.\"\n                    )\n                tx = cosmos_api.get_multi_transaction(\n                    from_addresses=[from_address, to_address],\n                    pub_keys=[bytes.fromhex(from_pubkey), bytes.fromhex(to_pubkey)],\n                    msgs=msgs,\n                    gas=gas,\n                    tx_fee=tx_fee,\n                )\n            else:\n                if from_pubkey is None:\n                    raise RuntimeError(\n                        \"to_pubkey is missing and required for Cosmos/Fetch based contract.\"\n                    )\n                tx = cosmos_api.get_multi_transaction(\n                    from_addresses=[from_address],\n                    pub_keys=[bytes.fromhex(from_pubkey)],\n                    msgs=msgs,\n                    gas=gas,\n                    tx_fee=tx_fee,\n                )\n\n            return tx\n\n        raise NotImplementedError  # pragma: nocover\n\n    @classmethod\n    def get_hash_single(\n        cls,\n        ledger_api: LedgerApi,\n        contract_address: Address,\n        from_address: Address,\n        to_address: Address,\n        token_id: int,\n        from_supply: int,\n        to_supply: int,\n        value: int,\n        trade_nonce: int,\n    ) -> bytes:\n        \"\"\"\n        Get the hash for a trustless trade between two agents for a single token.\n\n        :param ledger_api: the ledger API\n        :param contract_address: the address of the contract\n        :param from_address: the address of the agent sending tokens, receiving ether\n        :param to_address: the address of the agent receiving tokens, sending ether\n        :param token_id: the token id\n        :param from_supply: the supply of tokens by the sender\n        :param to_supply: the supply of tokens by the receiver\n        :param value: the amount of ether sent from the to_address to the from_address\n        :param trade_nonce: the nonce used in the trade\n        :return: the transaction hash in a dict\n        \"\"\"\n        if ledger_api.identifier == EthereumApi.identifier:\n            instance = cls.get_instance(ledger_api, contract_address)\n            from_address_hash = instance.functions.getAddress(from_address).call()\n            to_address_hash = instance.functions.getAddress(to_address).call()\n            value_eth_wei = ledger_api.api.toWei(value, \"ether\")\n            tx_hash = cls._get_hash_single(\n                _from=from_address_hash,\n                _to=to_address_hash,\n                _id=token_id,\n                _from_value=from_supply,\n                _to_value=to_supply,\n                _value_eth_wei=value_eth_wei,\n                _nonce=trade_nonce,\n            )\n            if (\n                tx_hash\n                != instance.functions.getSingleHash(\n                    from_address,\n                    to_address,\n                    token_id,\n                    from_supply,\n                    to_supply,\n                    value_eth_wei,\n                    trade_nonce,\n                ).call()\n            ):\n                raise ValueError(  # pragma: nocover\n                    \"On-chain and off-chain hash computation do not agree!\"\n                )\n            return tx_hash\n        raise NotImplementedError  # pragma: nocover\n\n    @staticmethod\n    def _get_hash_single(\n        _from: bytes,\n        _to: bytes,\n        _id: int,\n        _from_value: int,\n        _to_value: int,\n        _value_eth_wei: int,\n        _nonce: int,\n    ) -> bytes:\n        \"\"\"\n        Generate a hash mirroring the way we are creating this in the contract.\n\n        :param _from: the from address hashed\n        :param _to: the to address hashed\n        :param _id: the token id\n        :param _from_value: the from value\n        :param _to_value: the to value\n        :param _value_eth_wei: the value eth (in wei)\n        :param _nonce: the trade nonce\n        :return: the hash in bytes string representation\n        \"\"\"\n        return keccak256(\n            b\"\".join(\n                [\n                    _from,\n                    _to,\n                    _id.to_bytes(32, \"big\"),\n                    _from_value.to_bytes(32, \"big\"),\n                    _to_value.to_bytes(32, \"big\"),\n                    _value_eth_wei.to_bytes(32, \"big\"),\n                    _nonce.to_bytes(32, \"big\"),\n                ]\n            )\n        )\n\n    @classmethod\n    def get_hash_batch(\n        cls,\n        ledger_api: LedgerApi,\n        contract_address: Address,\n        from_address: Address,\n        to_address: Address,\n        token_ids: List[int],\n        from_supplies: List[int],\n        to_supplies: List[int],\n        value: int,\n        trade_nonce: int,\n    ) -> bytes:\n        \"\"\"\n        Get the hash for a trustless trade between two agents for a batch of tokens.\n\n        :param ledger_api: the ledger API\n        :param contract_address: the address of the contract\n        :param from_address: the address of the agent sending tokens, receiving ether\n        :param to_address: the address of the agent receiving tokens, sending ether\n        :param token_ids: the list of token ids for the bash transaction\n        :param from_supplies: the quantities of tokens sent from the from_address to the to_address\n        :param to_supplies: the quantities of tokens sent from the to_address to the from_address\n        :param value: the value of ether sent from the from_address to the to_address\n        :param trade_nonce: the trade nonce\n        :return: the transaction hash in a dict\n        \"\"\"\n        if ledger_api.identifier == EthereumApi.identifier:\n            instance = cls.get_instance(ledger_api, contract_address)\n            from_address_hash = instance.functions.getAddress(from_address).call()\n            to_address_hash = instance.functions.getAddress(to_address).call()\n            value_eth_wei = ledger_api.api.toWei(value, \"ether\")\n            tx_hash = cls._get_hash_batch(\n                _from=from_address_hash,\n                _to=to_address_hash,\n                _ids=token_ids,\n                _from_values=from_supplies,\n                _to_values=to_supplies,\n                _value_eth_wei=value_eth_wei,\n                _nonce=trade_nonce,\n            )\n            if (\n                tx_hash\n                != instance.functions.getHash(\n                    from_address,\n                    to_address,\n                    token_ids,\n                    from_supplies,\n                    to_supplies,\n                    value_eth_wei,\n                    trade_nonce,\n                ).call()\n            ):\n                raise ValueError(\n                    \"On-chain and off-chain hash computation do not agree!\"\n                )\n            return tx_hash\n        raise NotImplementedError  # pragma: nocover\n\n    @staticmethod\n    def _get_hash_batch(\n        _from: bytes,\n        _to: bytes,\n        _ids: List[int],\n        _from_values: List[int],\n        _to_values: List[int],\n        _value_eth_wei: int,\n        _nonce: int,\n    ) -> bytes:\n        \"\"\"\n        Generate a hash mirroring the way we are creating this in the contract.\n\n        :param _from: the from address hashed\n        :param _to: the to address hashed\n        :param _ids: the token ids\n        :param _from_values: the from values\n        :param _to_values: the to values\n        :param _value_eth_wei: the value of eth (in wei)\n        :param _nonce: the trade nonce\n        :return: the hash in bytes string representation\n        \"\"\"\n        aggregate_hash = keccak256(\n            b\"\".join(\n                [\n                    _ids[0].to_bytes(32, \"big\"),\n                    _from_values[0].to_bytes(32, \"big\"),\n                    _to_values[0].to_bytes(32, \"big\"),\n                ]\n            )\n        )\n        for idx, _id in enumerate(_ids):\n            if not idx == 0:\n                aggregate_hash = keccak256(\n                    b\"\".join(\n                        [\n                            aggregate_hash,\n                            _id.to_bytes(32, \"big\"),\n                            _from_values[idx].to_bytes(32, \"big\"),\n                            _to_values[idx].to_bytes(32, \"big\"),\n                        ]\n                    )\n                )\n\n        m_list = []\n        m_list.append(_from)\n        m_list.append(_to)\n        m_list.append(aggregate_hash)\n        m_list.append(_value_eth_wei.to_bytes(32, \"big\"))\n        m_list.append(_nonce.to_bytes(32, \"big\"))\n        return keccak256(b\"\".join(m_list))\n\n    @classmethod\n    def generate_trade_nonce(\n        cls, ledger_api: LedgerApi, contract_address: Address, agent_address: Address\n    ) -> Dict[str, int]:\n        \"\"\"\n        Generate a valid trade nonce.\n\n        :param ledger_api: the ledger API\n        :param contract_address: the address of the contract\n        :param agent_address: the address to use\n        :return: the generated trade nonce\n        \"\"\"\n        if ledger_api.identifier == EthereumApi.identifier:\n            instance = cls.get_instance(ledger_api, contract_address)\n            trade_nonce = random.randrange(0, MAX_UINT_256)  # nosec\n            while instance.functions.is_nonce_used(agent_address, trade_nonce).call():\n                trade_nonce = random.randrange(0, MAX_UINT_256)  # nosec\n            return {\"trade_nonce\": trade_nonce}\n        raise NotImplementedError  # pragma: nocover\n"
  },
  {
    "path": "packages/fetchai/contracts/erc1155/contract.yaml",
    "content": "name: erc1155\nauthor: fetchai\nversion: 0.23.3\ntype: contract\ndescription: The erc1155 contract implements an ERC1155 contract package.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: QmVKKf8Uyub6iUQytLSKVJBrFW9h6ALtHY4c8XF7pihuhg\n  __init__.py: QmTDUtfiUxkNFz3yemKkghfwsC7wYcyVJ9zzs99PXrrrVf\n  build/Migrations.json: QmfFYYWoq1L1Ni6YPBWWoRPvCZKBLZ7qzN3UDX537mCeuE\n  build/erc1155.json: Qma5n7au2NDCg1nLwYfYnmFNwWChFuXtu65w5DV7wAZRvw\n  build/erc1155.wasm: QmVWAjvDT1qQFyZ8GxVkCm4gzR4KgE93BM5KrqfbDtwp2v\n  contract.py: QmR4Etcu8w7KkyTmSrj6udFCWpFYarDKNRc9jR6NxG7TEc\n  contracts/Migrations.sol: QmbW34mYrj3uLteyHf3S46pnp9bnwovtCXHbdBHfzMkSZx\n  contracts/erc1155.vy: QmXwob8G1uX7fDvtuuKW139LALWtQmGw2vvaTRBVAWRxTx\n  migrations/1_initial_migration.js: QmcxaWKQ2yPkQBmnpXmcuxPZQUMuUudmPmX3We8Z9vtAf7\n  migrations/2_deploy_contracts.js: QmeLraUZBgtJK5KAhsf4Bb5S9amcYugfMJsjbhZgfmEfuP\nfingerprint_ignore_patterns: []\nclass_name: ERC1155Contract\ncontract_interface_paths:\n  cosmos: build/erc1155.wasm\n  ethereum: build/erc1155.json\n  fetchai: build/erc1155.wasm\ndependencies:\n  aea-ledger-cosmos:\n    version: <2.0.0,>=1.0.0\n  aea-ledger-ethereum:\n    version: <2.0.0,>=1.0.0\n  aea-ledger-fetchai:\n    version: <2.0.0,>=1.0.0\n"
  },
  {
    "path": "packages/fetchai/contracts/erc1155/contracts/Migrations.sol",
    "content": "pragma solidity >=0.4.21 <0.6.0;\n\ncontract Migrations {\n  address public owner;\n  uint public last_completed_migration;\n\n  constructor() public {\n    owner = msg.sender;\n  }\n\n  modifier restricted() {\n    if (msg.sender == owner) _;\n  }\n\n  function setCompleted(uint completed) public restricted {\n    last_completed_migration = completed;\n  }\n\n  function upgrade(address new_address) public restricted {\n    Migrations upgraded = Migrations(new_address);\n    upgraded.setCompleted(last_completed_migration);\n  }\n}\n"
  },
  {
    "path": "packages/fetchai/contracts/erc1155/contracts/erc1155.vy",
    "content": "# Author: Sören Steiger, github.com/ssteiger\n# Author: Fetch.ai, github.com/fetchai\n# License: MIT\n\n# ERC1155 Token Standard\n# https://eips.ethereum.org/EIPS/eip-1155\n\n########################EXTERNAL-CONTRACTS####################################\n\ncontract ERC1155TokenReceiver:\n    # Note: The ERC-165 identifier for this interface is 0x4e2312e0.\n\n    def onERC1155Received(_operator: address, _from: address, _id: uint256, _value: uint256,\n                          _data: bytes[256]) -> bytes32: modifying  # TODO: should return bytes4\n    #        \"\"\"\n    #       @notice Handle the receipt of a single ERC1155 token type.\n    #       @dev An ERC1155-compliant smart contract MUST call this function on the token recipient contract, at the end of a `safeTransferFrom` after the balance has been updated.        \n    #       This function MUST return `bytes4(keccak256(\"onERC1155Received(address,address,uint256,uint256,bytes)\"))` (i.e. 0xf23a6e61) if it accepts the transfer.\n    #       This function MUST revert if it rejects the transfer.\n    #       Return of any other value than the prescribed keccak256 generated value MUST result in the transaction being reverted by the caller.\n    #       @param _operator  The address which initiated the transfer (i.e. msg.sender)\n    #       @param _from      The address which previously owned the token\n    #       @param _id        The ID of the token being transferred\n    #       @param _value     The amount of tokens being transferred\n    #       @param _data      Additional data with no specified format\n    #       @return           `bytes4(keccak256(\"onERC1155Received(address,address,uint256,uint256,bytes)\"))`\n    #       \"\"\"\n\n    def onERC1155BatchReceived(_operator: address, _from: address, _ids: uint256[BATCH_SIZE], _values: uint256[BATCH_SIZE],\n                               _data: bytes[256]) -> bytes32: modifying  # TODO: should return bytes4\n    #       \"\"\"\n    #       @notice Handle the receipt of multiple ERC1155 token types.\n    #       @dev An ERC1155-compliant smart contract MUST call this function on the token recipient contract, at the end of a `safeBatchTransferFrom` after the balances have been updated.        \n    #       This function MUST return `bytes4(keccak256(\"onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)\"))` (i.e. 0xbc197c81) if it accepts the transfer(s).\n    #       This function MUST revert if it rejects the transfer(s).\n    #       Return of any other value than the prescribed keccak256 generated value MUST result in the transaction being reverted by the caller.\n    #       @param _operator  The address which initiated the batch transfer (i.e. msg.sender)\n    #       @param _from      The address which previously owned the token\n    #       @param _ids       An array containing ids of each token being transferred (order and length must match _values array)\n    #       @param _values    An array containing amounts of each token being transferred (order and length must match _ids array)\n    #       @param _data      Additional data with no specified format\n    #       @return           `bytes4(keccak256(\"onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)\"))`\n    #       \"\"\"\n\n########################END-EXTERNAL-CONTRACTS####################################\n########################EVENTS####################################\n\nMAX_URI_SIZE: constant(uint256) = 1024\n\nTransferSingle: event({_operator: indexed(address), _from: indexed(address), _to: indexed(address), _id: uint256,\n                       _value: uint256})\n#   @dev Either `TransferSingle` or `TransferBatch` MUST emit when tokens are transferred, including zero value transfers as well as minting or burning (see \"Safe Transfer Rules\" section of the standard).\n#        The `_operator` argument MUST be the address of an account/contract that is approved to make the transfer (SHOULD be msg.sender).\n#        The `_from` argument MUST be the address of the holder whose balance is decreased.\n#        The `_to` argument MUST be the address of the recipient whose balance is increased.\n#        The `_id` argument MUST be the token type being transferred.\n#        The `_value` argument MUST be the number of tokens the holder balance is decreased by and match what the recipient balance is increased by.\n#        When minting/creating tokens, the `_from` argument MUST be set to `0x0` (i.e. zero address).\n#        When burning/destroying tokens, the `_to` argument MUST be set to `0x0` (i.e. zero address).\n\n\nTransferBatch: event({_operator: indexed(address), _from: indexed(address), _to: indexed(address),\n                      _ids: uint256[BATCH_SIZE], _values: uint256[BATCH_SIZE]})\n#   @dev Either `TransferSingle` or `TransferBatch` MUST emit when tokens are transferred, including zero value transfers as well as minting or burning (see \"Safe Transfer Rules\" section of the standard).\n#        The `_operator` argument MUST be the address of an account/contract that is approved to make the transfer (SHOULD be msg.sender).\n#        The `_from` argument MUST be the address of the holder whose balance is decreased.\n#        The `_to` argument MUST be the address of the recipient whose balance is increased.\n#        The `_ids` argument MUST be the list of tokens being transferred.\n#        The `_values` argument MUST be the list of number of tokens (matching the list and order of tokens specified in _ids) the holder balance is decreased by and match what the recipient balance is increased by.\n#        When minting/creating tokens, the `_from` argument MUST be set to `0x0` (i.e. zero address).\n#        When burning/destroying tokens, the `_to` argument MUST be set to `0x0` (i.e. zero address).\n\n\nApprovalForAll: event({_owner: indexed(address), _operator: indexed(address), _approved: bool})\n#   @dev MUST emit when approval for a second party/operator address to manage all tokens for an owner address is enabled or disabled (absence of an event assumes disabled).\n\n\nURI: event({_value: string[MAX_URI_SIZE], _id: indexed(uint256)})\n#   @dev MUST emit when the URI is updated for a token ID.\n#        URIs are defined in RFC 3986.\n#        The URI MUST point to a JSON file that conforms to the \"ERC-1155 Metadata URI JSON Schema\".\n\n########################END-EVENTS####################################\n########################INITIALIZATION####################################\n\nsupportedInterfaces: map(bytes32, bool)\n# https://eips.ethereum.org/EIPS/eip-165\nERC165_INTERFACE_ID: constant(bytes32)  = 0x0000000000000000000000000000000000000000000000000000000001ffc9a7\nERC1155_INTERFACE_ID: constant(bytes32) = 0x00000000000000000000000000000000000000000000000000000000d9b67a26\ntokensIdCount: uint256\nowner: public(address)\n\nbalancesOf: map(address, map(uint256, uint256))\nnoncesOf: map(address, map(uint256, bool))\nuri: map(uint256, string[256])\noperators: map(address, map(address, bool))\ntoken_ids: map(uint256, bool)\n\n# This is to be set before contract migration!\nBATCH_SIZE: constant(uint256) = 10\n\n\n@public\ndef __init__():\n    \"\"\"\n    @notice Called once and only upon contract deployment.\n    \"\"\"\n    self.tokensIdCount = convert(0, uint256)\n    self.supportedInterfaces[ERC165_INTERFACE_ID] = True\n    self.supportedInterfaces[ERC1155_INTERFACE_ID] = True\n    self.owner = msg.sender\n\n########################END-INITIALIZATION####################################\n########################PRIVATE-FUNCTIONS####################################\n\n\n######### THIS IS A TEMPORARY SOLUTION #################\n@public\n@constant\ndef getAddress(_addr: address) -> bytes32:\n    hash: bytes32 = convert(_addr, bytes32)\n    return hash\n##################### END ##############################\n\n@private\n@constant\ndef _getHash(_from: address, _to: address, _ids: uint256[BATCH_SIZE], _from_supplies: uint256[BATCH_SIZE], _to_supplies: uint256[BATCH_SIZE], _value_eth: uint256, _nonce: uint256) -> bytes32:\n    \"\"\"\n    @notice Get the hash from the tx values.\n    @param _from          The address of the sender.\n    @param _to            The address of the receiver.\n    @param _ids           The ids of the tokens.\n    @param _from_supplies The supply of token values that will send the _from.\n    @param _to_supplies   The supply of token values that will send the _from.\n    @param _value_eth     The value of the ether.\n    @param _nonce         The nonce.\n    @return the hash\n    \"\"\"\n    aggregate_hash: bytes32 = keccak256(concat(convert(_ids[0], bytes32), convert(_from_supplies[0], bytes32), convert(_to_supplies[0], bytes32)))\n    for i in range(BATCH_SIZE):\n      if not i == 0:\n        aggregate_hash = keccak256(concat(aggregate_hash, convert(_ids[i], bytes32), convert(_from_supplies[i], bytes32), convert(_to_supplies[i], bytes32)))\n    hash: bytes32 = keccak256(concat(convert(_from, bytes32),\n                              convert(_to, bytes32),\n                              aggregate_hash,\n                              convert(_value_eth, bytes32),\n                              convert(_nonce, bytes32)))\n    return hash\n\n\n@public\n@constant\ndef getHash(_from: address, _to: address, _ids: uint256[BATCH_SIZE], _from_supplies: uint256[BATCH_SIZE], _to_supplies: uint256[BATCH_SIZE], _value_eth: uint256, _nonce: uint256) -> bytes32:\n    \"\"\"\n    @notice Get the hash from the tx values.\n    @param _from          The address of the sender.\n    @param _to            The address of the receiver.\n    @param _ids           The ids of the tokens.\n    @param _from_supplies The supply of token values that will send the _from.\n    @param _to_supplies   The supply of token values that will send the _from.\n    @param _value_eth     The value of the ether.\n    @param _nonce         The nonce.\n    @return the hash\n    \"\"\"\n    return self._getHash(_from, _to, _ids, _from_supplies, _to_supplies, _value_eth, _nonce)\n\n\n@private\n@constant\ndef getHashOld(_from: address, _to: address, _ids: uint256[BATCH_SIZE], _from_supplies: uint256[BATCH_SIZE], _to_supplies: uint256[BATCH_SIZE], _value_eth: uint256, _nonce: uint256) -> bytes32:\n    \"\"\"\n    @notice Get the hash from the tx values.\n    @param _from          The address of the sender.\n    @param _to            The address of the receiver.\n    @param _ids           The ids of the tokens.\n    @param _from_supplies The supply of token values that will send the _from.\n    @param _to_supplies   The supply of token values that will send the _from.\n    @param _value_eth     The value of the ether.\n    @param _nonce         The nonce.\n    @return the hash\n    \"\"\"\n    hash: bytes32 = keccak256(concat(convert(_from, bytes32),\n                              convert(_to, bytes32),\n                              convert(_ids[0], bytes32),\n                              convert(_ids[1], bytes32),\n                              convert(_ids[2], bytes32),\n                              convert(_ids[3], bytes32),\n                              convert(_ids[4], bytes32),\n                              convert(_ids[5], bytes32),\n                              convert(_ids[6], bytes32),\n                              convert(_ids[7], bytes32),\n                              convert(_ids[8], bytes32),\n                              convert(_ids[9], bytes32),\n                              convert(_from_supplies[0], bytes32),\n                              convert(_from_supplies[1], bytes32),\n                              convert(_from_supplies[2], bytes32),\n                              convert(_from_supplies[3], bytes32),\n                              convert(_from_supplies[4], bytes32),\n                              convert(_from_supplies[5], bytes32),\n                              convert(_from_supplies[6], bytes32),\n                              convert(_from_supplies[7], bytes32),\n                              convert(_from_supplies[8], bytes32),\n                              convert(_from_supplies[9], bytes32),\n                              convert(_to_supplies[0], bytes32),\n                              convert(_to_supplies[1], bytes32),\n                              convert(_to_supplies[2], bytes32),\n                              convert(_to_supplies[3], bytes32),\n                              convert(_to_supplies[4], bytes32),\n                              convert(_to_supplies[5], bytes32),\n                              convert(_to_supplies[6], bytes32),\n                              convert(_to_supplies[7], bytes32),\n                              convert(_to_supplies[8], bytes32),\n                              convert(_to_supplies[9], bytes32),\n                              convert(_value_eth, bytes32),\n                              convert(_nonce, bytes32)))\n    return hash\n\n\n@private\n@constant\ndef _getSingleHash(_from: address, _to: address, _id: uint256, _from_supply: uint256, _to_supply: uint256, _value_eth: uint256, _nonce: uint256) -> bytes32:\n    \"\"\"\n    @notice Get the hash from the tx values.\n    @param _from            The address of the sender.\n    @param _to              The address of the receiver.\n    @param _id              The id of the tokens.\n    @param _from_supply     The from token value. (_from sends)\n    @param _to_supply       The to token value (_to sends).\n    @param _value_eth       The value of the ether.\n    @param _nonce           The nonce.\n    @return the hash\n    \"\"\"\n    hash: bytes32 = keccak256(concat(convert(_from, bytes32),\n                              convert(_to, bytes32),\n                              convert(_id, bytes32),\n                              convert(_from_supply, bytes32),\n                              convert(_to_supply, bytes32),\n                              convert(_value_eth, bytes32),\n                              convert(_nonce, bytes32)))\n    return hash\n\n\n@public\n@constant\ndef getSingleHash(_from: address, _to: address, _id: uint256, _from_supply: uint256, _to_supply: uint256, _value_eth: uint256, _nonce: uint256) -> bytes32:\n    \"\"\"\n    @notice Get the hash from the tx values.\n    @param _from            The address of the sender.\n    @param _to              The address of the receiver.\n    @param _id              The id of the tokens.\n    @param _from_supply     The from token value. (_from sends)\n    @param _to_supply       The to token value (_to sends).\n    @param _value_eth       The value of the ether.\n    @param _nonce           The nonce.\n    @return the hash\n    \"\"\"\n    return self._getSingleHash(_from, _to, _id, _from_supply, _to_supply, _value_eth, _nonce)\n\n\n@private\n@constant\ndef ecrecoverSig(_hash: bytes32, _sig: bytes[65]) -> address:\n    \"\"\"\n    @notice Check whether the the signature matches the hash.\n    @param _hash The hash to be checked.\n    @param _sig  The signature which is meant to match the hash.\n    @return the address which signed the signature or the zero address\n    \"\"\"\n    if len(_sig) != 65:\n        return ZERO_ADDRESS\n    # ref. https://gist.github.com/axic/5b33912c6f61ae6fd96d6c4a47afde6d\n    # The signature format is a compact form of:\n    # {bytes32 r}{bytes32 s}{uint8 v}\n    r: bytes32 = extract32(_sig, 0, type=bytes32)\n    s: bytes32 = extract32(_sig, 32, type=bytes32)\n    v: int128 = convert(slice(_sig, start=64, len=1), int128)\n    # Version of signature should be 27 or 28, but 0 and 1 are also possible versions.\n    # geth uses [0, 1] and some clients have followed. This might change, see:\n    # https://github.com/ethereum/go-ethereum/issues/2053\n    if v < 27:\n        v += 27\n    if v in [27, 28]:\n        return ecrecover(_hash, convert(v, uint256), convert(r, uint256), convert(s, uint256))\n    return ZERO_ADDRESS\n\n\n@private\n@constant\ndef decode_id(id: uint256) -> int128:\n    \"\"\"\n    @notice Decodes the id of the token inorder to find out if it NFT or FT.\n    @param id: uint256\n    @return token_id : int128 (Specified id for FT and NFT.)\n    @dev shift(x, -y): returns x with the bits shifted to the right by y places, which is equivalent to dividing x by 2**y.\n    \"\"\"\n    decoded_token_id: int128 = convert(shift(id, -128), int128)\n    decoded_index: int128 = convert(id % 2 ** 128, int128)\n    return decoded_token_id\n\n########################END-PRIVATE-FUNCTIONS################################\n########################PUBLIC-FUNCTIONS#####################################\n\n@public\n@constant\ndef supportsInterface(_interfaceID: bytes32) -> bool:\n    \"\"\"\n    @notice Check whether the interface id is supported.\n    @param _interfaceID The interface id\n    @return True if the interface id is supported.\n    \"\"\"\n    return self.supportedInterfaces[_interfaceID]\n\n@public\n@constant\ndef is_nonce_used(addr: address, nonce: uint256) -> bool:\n    \"\"\"\n    @notice Checks if the given nonce for the give address is unused.\n    @param nonce: uint256 the counter of the transaction\n    @param address: the address that want to transact.\n    \"\"\"\n    return self.noncesOf[addr][nonce]\n\n@public\n@constant\ndef is_token_id_exists(token_id: uint256) -> bool:\n    \"\"\"\n    @notice Checks if the given token_id is already created.\n    @param token_id: uint256 the id of the token.\n    \"\"\"\n    return self.token_ids[token_id]\n\n@public\ndef safeTransferFrom(_from: address, _to: address, _id: uint256, _value: uint256, _data: bytes[256]):\n    \"\"\"\n    @notice Transfers `_value` amount of an `_id` from the `_from` address to the `_to` address specified (with safety call).\n    @dev Caller must be approved to manage the tokens being transferred out of the `_from` account (see \"Approval\" section of the standard).\n         MUST revert if `_to` is the zero address.\n         MUST revert if balance of holder for token `_id` is lower than the `_value` sent.\n         MUST revert on any other error.\n         MUST emit the `TransferSingle` event to reflect the balance change (see \"Safe Transfer Rules\" section of the standard).\n         After the above conditions are met, this function MUST check if `_to` is a smart contract (e.g. code size > 0). If so, it MUST call `onERC1155Received` on `_to` and act appropriately (see \"Safe Transfer Rules\" section of the standard).\n    @param _from    Source address\n    @param _to      Target address\n    @param _id      ID of the token type\n    @param _value   Transfer amount\n    @param _data    Additional data with no specified format, MUST be sent unaltered in call to `onERC1155Received` on `_to`\n    @return None\n    \"\"\"\n    assert _from == msg.sender or (self.operators[_from])[msg.sender]\n    assert _to != ZERO_ADDRESS, \"Cannot transfer to zero address.\"\n    assert self.balancesOf[_from][_id] >= _value, \"Not enough tokens.\"\n\n    self.balancesOf[_from][_id] -= _value\n    self.balancesOf[_to][_id] += _value\n\n    log.TransferSingle(msg.sender, _from, _to, _id, _value)\n\n    if _to.is_contract:\n        returnValue: bytes32 = ERC1155TokenReceiver(_to).onERC1155Received(msg.sender, _from, _id, _value, _data)\n        assert returnValue == method_id(\"onERC1155Received(address,address,uint256,uint256,bytes)\", bytes32)\n\n\n@public\ndef safeBatchTransferFrom(_from: address, _to: address, _ids: uint256[BATCH_SIZE], _values: uint256[BATCH_SIZE], _data: bytes[256]):\n    \"\"\"\n    @notice Transfers `_values` amount(s) of `_ids` from the `_from` address to the `_to` address specified (with safety call).\n    @dev Caller must be approved to manage the tokens being transferred out of the `_from` account (see \"Approval\" section of the standard).\n        MUST revert if `_to` is the zero address.\n        MUST revert if length of `_ids` is not the same as length of `_values`.\n        MUST revert if any of the balance(s) of the holder(s) for token(s) in `_ids` is lower than the respective amount(s) in `_values` sent to the recipient.\n        MUST revert on any other error.\n        MUST emit `TransferSingle` or `TransferBatch` event(s) such that all the balance changes are reflected (see \"Safe Transfer Rules\" section of the standard).\n        Balance changes and events MUST follow the ordering of the arrays (_ids[0]/_values[0] before _ids[1]/_values[1], etc).\n        After the above conditions for the transfer(s) in the batch are met, this function MUST check if `_to` is a smart contract (e.g. code size > 0). If so, it MUST call the relevant `ERC1155TokenReceiver` hook(s) on `_to` and act appropriately (see \"Safe Transfer Rules\" section of the standard).\n    @param _from    Source address\n    @param _to      Target address\n    @param _ids     IDs of each token type (order and length must match _values array)\n    @param _values  Transfer amounts per token type (order and length must match _ids array)\n    @param _data    Additional data with no specified format, MUST be sent unaltered in call to the `ERC1155TokenReceiver` hook(s) on `_to`\n    @return None\n    \"\"\"\n    assert _from == msg.sender or (self.operators[_from])[msg.sender]\n    assert _to != ZERO_ADDRESS, \"Cannot transfer to zero address.\"\n    for i in range(BATCH_SIZE):\n        id: uint256 = _ids[i]\n        assert self.balancesOf[_from][id] >= _values[i]\n\n    log.TransferBatch(msg.sender, _from, _to, _ids, _values)\n\n    for i in range(BATCH_SIZE):\n        id: uint256 = _ids[i]\n        self.balancesOf[_from][id] -= _values[i]\n        self.balancesOf[_to][id] += _values[i]\n\n    if _to.is_contract:\n        returnValue: bytes32 = ERC1155TokenReceiver(_to).onERC1155BatchReceived(msg.sender, _from, _ids, _values, _data)\n        assert returnValue == method_id(\"onERC1155BatchReceived(address,address,uint256[BATCH_SIZE],uint256[BATCH_SIZE],bytes)\", bytes32)\n\n\n@public\n@constant\ndef balanceOf(_owner: address, _id: uint256) -> uint256:\n    \"\"\"\n    @notice Get the balance of an account's tokens.\n    @param  _owner The address of the token holder\n    @param  _id    ID of the token\n    @return The _owner's balance of the token type requested\n    \"\"\"\n    return self.balancesOf[_owner][_id]\n\n\n@public\n@constant\ndef balanceOfBatch( _owner: address[BATCH_SIZE], _ids: uint256[BATCH_SIZE]) -> uint256[BATCH_SIZE]:\n    \"\"\"\n    @notice Get the balance of multiple account/token pairs\n    @param _owners The addresses of the token holders\n    @param _ids    ID of the tokens\n    @return The _owner's balance of the token types requested (i.e. balance for each (owner, id) pair)\n    \"\"\"\n    returnBalances: uint256[BATCH_SIZE]\n    for i in range(BATCH_SIZE):\n        returnBalances[i] = self.balancesOf[_owner[i]][_ids[i]]\n    return returnBalances\n\n\n@public\ndef setApprovalForAll(_operator: address, _approved: bool):\n    \"\"\"\n    @notice Enable or disable approval for a third party (\"operator\") to manage all of the caller's tokens.\n    @dev MUST emit the ApprovalForAll event on success.\n    @param _operator  Address to add to the set of authorized operators\n    @param _approved  True if the operator is approved, false to revoke approval\n    @return None\n    \"\"\"\n    (self.operators[msg.sender])[_operator] = _approved\n    log.ApprovalForAll(msg.sender, _operator, _approved)\n\n\n@public\n@constant\ndef isApprovedForAll(_owner: address, _operator: address) -> bool:\n    \"\"\"\n    @notice Queries the approval status of an operator for a given owner.\n    @param _owner     The owner of the tokens.\n    @param _operator  Address of authorized operator.\n    @return True if the operator is approved, false if not\n    \"\"\"\n    return (self.operators[_owner])[_operator]\n\n\n@public\ndef createSingle(_item_owner: address, _id: uint256, _path: string[256]):\n    \"\"\"\n    @notice Create a new token type that we can mint later.\n    @param _item_owner The owner of the item.\n    @param _id         The id of the token.\n    @param _path       The path to the token data.\n    @return None\n    \"\"\"\n    assert _item_owner != ZERO_ADDRESS\n    assert self.owner == msg.sender, \"Owner only can create item.\"\n    self.balancesOf[_item_owner][_id] = 0\n    self.tokensIdCount += 1\n    self.token_ids[_id] = True\n    self.uri[_id] = _path\n    log.URI(_path, _id)\n    log.TransferSingle(msg.sender, ZERO_ADDRESS, _item_owner, _id, 0)\n\n\n@public\ndef createBatch(_items_owner: address, _ids: uint256[BATCH_SIZE]):\n    \"\"\"\n    @notice Create new token types that we can mint later.\n    @param _items_owner The owner of the items.\n    @param _ids         The ids of the tokens.\n    @return None\n    \"\"\"\n    assert _items_owner != ZERO_ADDRESS\n    assert self.owner == msg.sender, \"Owner only can create items.\"\n    for i in range(BATCH_SIZE):\n        id: uint256 = _ids[i]\n        self.balancesOf[_items_owner][id] = 0\n        self.tokensIdCount += 1\n        self.token_ids[id] = True\n    zero_supply: uint256[BATCH_SIZE] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]\n    log.TransferBatch(msg.sender, ZERO_ADDRESS, _items_owner, _ids, zero_supply)\n\n\n@public\ndef mint(_to: address, _id: uint256, _supply: uint256, _data: bytes[256]=\"\"):\n    \"\"\"\n    @notice Mint a token.\n    @dev This is not part of the standard.\n    @param _to      The address of the receiver.\n    @param _id      The id of the token.\n    @param _supply  The supply to be minted for the token.\n    @param _data    The data.\n    @return None\n    \"\"\"\n    assert _to != ZERO_ADDRESS\n    assert self.owner == msg.sender, \"Owner only can mint items.\"\n    decoded_id: int128 = self.decode_id(_id)\n    assert decoded_id == 1 or decoded_id == 2\n    if decoded_id == 1 :\n        assert _supply == 1, \"Cannot mint NFT with _supply more than 1\"\n    self.balancesOf[_to][_id] = _supply\n\n    log.TransferSingle(msg.sender, ZERO_ADDRESS, _to, _id, _supply)\n\n    if _to.is_contract:\n        returnValue: bytes32 = ERC1155TokenReceiver(_to).onERC1155Received(msg.sender, ZERO_ADDRESS, _id, _supply, _data)\n        assert returnValue == method_id(\"onERC1155Received(address,address,uint256,uint256,bytes)\", bytes32)\n\n\n@public\ndef mintBatch(_to: address, _ids: uint256[BATCH_SIZE], _supplies: uint256[BATCH_SIZE], _data: bytes[256]=\"\"):\n    \"\"\"\n    @notice Mint a batch of tokens.\n    @dev This is not part of the standard.\n    @param _to      The address of the receiver.\n    @param _ids     The ids of the tokens.\n    @param _supplies The supply to be minted for each token.\n    @param _data    The data.\n    @return None\n    \"\"\"\n    assert _to != ZERO_ADDRESS\n    assert self.owner == msg.sender, \"Owner only can mint items.\"\n\n    for i in range(BATCH_SIZE):\n        id: uint256 = _ids[i]\n        decoded_id: int128 = self.decode_id(id)\n        assert decoded_id == 1 or decoded_id == 2\n\n        if decoded_id == 1 :\n            assert _supplies[i] == 1\n\n        self.balancesOf[_to][id] = _supplies[i]\n\n    log.TransferBatch(msg.sender, ZERO_ADDRESS, _to, _ids, _supplies)\n\n    for i in range(BATCH_SIZE):\n        if _to.is_contract:\n            returnValue: bytes32 = ERC1155TokenReceiver(_to).onERC1155Received(msg.sender, ZERO_ADDRESS, _ids[i], _supplies[i], _data)\n            assert returnValue == method_id(\"onERC1155Received(address,address,uint256,uint256,bytes)\", bytes32)\n\n\n@public\ndef burn(_id: uint256, _supply: uint256):\n    \"\"\"\n    @notice Burns the supply of the specified token.\n    @param _id        The id of the token\n    @param _supply    Supply to be burned\n    @return None\n    \"\"\"\n    assert self.balancesOf[msg.sender][_id] >= _supply, \"Not enough tokens to burn.\"\n    self.balancesOf[msg.sender][_id] -= _supply\n    log.TransferSingle(msg.sender, msg.sender, ZERO_ADDRESS, _id, _supply)\n\n\n@public\ndef burnBatch(_ids: uint256[BATCH_SIZE], _supplies: uint256[BATCH_SIZE]):\n    \"\"\"\n    @notice Burns the supply of the specified tokens.\n    @dev At this point anyone can burn items if they own it.\n    @param _ids        The ids of the token\n    @param _supplies   Supplies to be burned\n    @return None\n    \"\"\"\n    for i in range(BATCH_SIZE):\n        id: uint256 = _ids[i]\n        assert self.balancesOf[msg.sender][id] >= _supplies[i]\n\n    for i in range(BATCH_SIZE):\n        id: uint256 = _ids[i]\n        self.balancesOf[msg.sender][id] -= _supplies[i]\n    log.TransferBatch(msg.sender, msg.sender, ZERO_ADDRESS, _ids, _supplies)\n\n\n@public\n@payable\ndef tradeBatch(_from: address, _to: address, _ids: uint256[BATCH_SIZE], _from_supplies: uint256[BATCH_SIZE], _to_supplies: uint256[BATCH_SIZE], _value_eth: uint256, _nonce: uint256, _signature: bytes[65], _data: bytes[256]=\"\"):\n    \"\"\"\n    @notice Trade (atomically swap) tokens with tokens or eth.\n    @dev Caller must be approved to manage the tokens being transferred out of the `_from` account (see \"Approval\" section of the standard).\n        MUST revert if `_to` is the zero address.\n        MUST revert if _from_supplies[i] > 0 and _to_supplies[i] > 0\n        MUST revert if len(_ids) != len(_from_supplies) != len(_to_supplies)\n        MUST revert if _value_eth != msg.value\n        MUST revert if any of the balance(s) of the holder(s) for token(s) in `_ids` is lower than the respective amount(s) in `positive and negative values` sent to the recipient.\n        MUST revert on any other error.\n        MUST emit `TransferSingle` or `TransferBatch` event(s) such that all the balance changes are reflected (see \"Safe Transfer Rules\" section of the standard).\n        Balance changes and events MUST follow the ordering of the arrays (_ids[0]/_values[0] before _ids[1]/_values[1], etc).\n        After the above conditions for the transfer(s) in the batch are met, this function MUST check if `_to` is a smart contract (e.g. code size > 0). If so, it MUST call the relevant `ERC1155TokenReceiver` hook(s) on `_to` and act appropriately (see \"Safe Transfer Rules\" section of the standard).\n    @param _from          The address of the sender.\n    @param _to            The address of the receiver.\n    @param _ids           The ids of the tokens.\n    @param _from_supplies The supply of token values that will send the _from.\n    @param _to_supplies   The supply of token values that will send the _from.\n    @param _value_eth     The value of the ether.\n    @param _nonce         The nonce.\n    @param _signature    The signature of the _to address.\n    @param _data    The data.\n    @return None\n    \"\"\"\n    # Assert the value of the transaction is less than the balance of A.\n\n    assert _from == msg.sender or (self.operators[_from])[msg.sender], \"_from must be the sender or approved address\"\n    assert _to != ZERO_ADDRESS, \"Destination address must be non-zero.\"\n    assert self.noncesOf[_from][_nonce] == False, \"Nonce must be unused.\"\n    assert _value_eth == msg.value, \"Sender has not provided enough ether.\"\n\n    for i in range(BATCH_SIZE):\n       id: uint256 = _ids[i]\n       if _from_supplies[i] > 0:\n           assert _to_supplies[i] == 0\n           assert self.balancesOf[_from][id] >= _from_supplies[i]\n       else:\n           assert _from_supplies[i] == 0\n           assert self.balancesOf[_to][id] >= _to_supplies[i]\n\n    # Create hash from variables.\n    hash: bytes32 = self._getHash(_from, _to, _ids, _from_supplies, _to_supplies, _value_eth, _nonce)\n\n    # Assert that the ecrecover(address,signature) returns true.\n    recovered_to: address = self.ecrecoverSig(hash, _signature)\n    assert recovered_to == _to, \"Signer does not match signature.\"\n\n    # Store the nonce\n    self.noncesOf[msg.sender][_nonce] = True\n\n    # Update the balances\n    for i in range(BATCH_SIZE):\n        id: uint256 = _ids[i]\n        if _from_supplies[i] > 0:\n            self.balancesOf[_from][id] -= _from_supplies[i]\n            self.balancesOf[_to][id] += _from_supplies[i]\n        else:\n            self.balancesOf[_from][id] += _to_supplies[i]\n            self.balancesOf[_to][id] -= _to_supplies[i]\n\n    send(_to, msg.value)\n\n    log.TransferBatch(msg.sender, _from, _to, _ids, _from_supplies)\n    log.TransferBatch(msg.sender, _to, _from, _ids, _to_supplies)\n\n\n    if _to.is_contract:\n        returnValue: bytes32 = ERC1155TokenReceiver(_to).onERC1155BatchReceived(msg.sender, _to, _ids, _from_supplies, _data)\n        assert returnValue == method_id(\"onERC1155BatchReceived(address,address,uint256,uint256,bytes)\", bytes32)\n    if _from.is_contract:\n        returnValue: bytes32 = ERC1155TokenReceiver(_from).onERC1155BatchReceived(msg.sender, _from, _ids, _to_supplies, _data)\n        assert returnValue == method_id(\"onERC1155BatchReceived(address,address,uint256,uint256,bytes)\", bytes32)\n\n\n\n@public\n@payable\ndef trade(_from: address, _to: address, _id: uint256, _from_supply: uint256, _to_supply: uint256, _value_eth: uint256, _nonce: uint256, _signature: bytes[65], _data: bytes[256]=\"\"):\n    \"\"\"\n    @notice Trade (atomically swap) tokens with tokens or eth.\n    @dev Caller must be approved to manage the tokens being transferred out of the `_from` account (see \"Approval\" section of the standard).\n        MUST revert if `_to` is the zero address.\n        MUST revert if _from_supply > 0 and _to_supply > 0\n        MUST revert if _value_eth != msg.value\n        MUST revert if any of the balance(s) of the holder(s) for token(s) in `_id` is lower than the respective amount in `positive or negative value` sent to the recipient.\n        MUST revert on any other error.\n        MUST emit `TransferSingle` or `TransferBatch` event(s) such that all the balance changes are reflected (see \"Safe Transfer Rules\" section of the standard).\n        Balance changes and events MUST follow the ordering of the arrays (_ids[0]/_values[0] before _ids[1]/_values[1], etc).\n        After the above conditions for the transfer(s) in the batch are met, this function MUST check if `_to` is a smart contract (e.g. code size > 0). If so, it MUST call the relevant `ERC1155TokenReceiver` hook(s) on `_to` and act appropriately (see \"Safe Transfer Rules\" section of the standard).\n    @param _from            The from address (seller of eth, potential receiver of tokens).\n    @param _to              The receiver address (receiver of tokens).\n    @param _id              The id of the token\n    @param _from_supply     The change in value of token (for _from)\n    @param _to_supply       The change in value of token (for _to)\n    @param _value_eth       The value of the ETH sent to the _from address.\n    @param _nonce           The nonce.\n    @param _signature       The signature of the _to address.\n    @param _data    The data.\n    @return None\n    \"\"\"\n    # Assert the value of the transaction is less than the balance of A.\n    assert _from == msg.sender or (self.operators[_from])[msg.sender]\n    assert _to != ZERO_ADDRESS, \"Destination address must be non-zero.\"\n    assert self.noncesOf[_from][_nonce] == False, \"Nonce must be unused.\"\n    assert _value_eth == msg.value, \"Sender has not provided enough ether.\"\n    if _from_supply > 0:\n        assert _to_supply == 0\n        assert self.balancesOf[_from][_id] >= _from_supply\n    else:\n        assert _from_supply == 0\n        assert self.balancesOf[_to][_id] >= _to_supply\n\n    # Create hash from variables.\n    hash: bytes32 = self._getSingleHash(_from, _to, _id, _from_supply, _to_supply, _value_eth, _nonce)\n\n    # Assert that the ecrecover(address,signature) returns true.\n    recovered_to: address = self.ecrecoverSig(hash, _signature)\n    assert recovered_to == _to, \"Signer does not match signature.\"\n\n    # Store the nonce\n    self.noncesOf[msg.sender][_nonce] = True\n\n    # Update the balances\n    if _from_supply > 0:\n        self.balancesOf[_from][_id] -= _from_supply\n        self.balancesOf[_to][_id] += _from_supply\n    else:\n        self.balancesOf[_from][_id] += _to_supply\n        self.balancesOf[_to][_id] -= _to_supply\n\n    send(_to, msg.value)\n\n    log.TransferSingle(msg.sender, _from, _to, _id, _from_supply)\n    log.TransferSingle(msg.sender, _to, _from, _id, _to_supply)\n\n    if _to.is_contract:\n        returnValue: bytes32 = ERC1155TokenReceiver(_to).onERC1155Received(msg.sender, _to, _id, _from_supply, _data)\n        assert returnValue == method_id(\"onERC1155BatchReceived(address,address,uint256,uint256,bytes)\", bytes32)\n    if _from.is_contract:\n        returnValue: bytes32 = ERC1155TokenReceiver(_from).onERC1155Received(msg.sender, _from, _id, _to_supply, _data)\n        assert returnValue == method_id(\"onERC1155BatchReceived(address,address,uint256,uint256,bytes)\", bytes32)\n"
  },
  {
    "path": "packages/fetchai/contracts/erc1155/migrations/1_initial_migration.js",
    "content": "var Migrations = artifacts.require(\"./Migrations.sol\");\n\nmodule.exports = function(deployer) {\n  deployer.deploy(Migrations);\n};\n"
  },
  {
    "path": "packages/fetchai/contracts/erc1155/migrations/2_deploy_contracts.js",
    "content": "var ERC1155 = artifacts.require(\"erc1155\");\n\nmodule.exports = function(deployer) {\n  deployer.deploy(ERC1155);\n};\n"
  },
  {
    "path": "packages/fetchai/contracts/fet_erc20/README.md",
    "content": "# Fetch ERC20 Contract\n\n## Description\n\nThis contract package is used to interface with a Fetch ERC20 contract.\n\n## Functions\n\n- approve(spender, amount): approve address `spender` to transfer up to `amount` tokens on behalf of sender\n- transfer(receiver, amount): transfer `amount` tokens from sender to receiver\n"
  },
  {
    "path": "packages/fetchai/contracts/fet_erc20/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the support resources for the fet_erc20 contract.\"\"\"\n"
  },
  {
    "path": "packages/fetchai/contracts/fet_erc20/build/FetERC20Mock.json",
    "content": "{\n  \"abi\": [\n    {\n      \"inputs\": [\n        {\n          \"internalType\": \"string\",\n          \"name\": \"name\",\n          \"type\": \"string\"\n        },\n        {\n          \"internalType\": \"string\",\n          \"name\": \"symbol\",\n          \"type\": \"string\"\n        },\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"initialSupply\",\n          \"type\": \"uint256\"\n        },\n        {\n          \"internalType\": \"uint8\",\n          \"name\": \"decimals_\",\n          \"type\": \"uint8\"\n        }\n      ],\n      \"stateMutability\": \"payable\",\n      \"type\": \"constructor\"\n    },\n    {\n      \"anonymous\": false,\n      \"inputs\": [\n        {\n          \"indexed\": true,\n          \"internalType\": \"address\",\n          \"name\": \"owner\",\n          \"type\": \"address\"\n        },\n        {\n          \"indexed\": true,\n          \"internalType\": \"address\",\n          \"name\": \"spender\",\n          \"type\": \"address\"\n        },\n        {\n          \"indexed\": false,\n          \"internalType\": \"uint256\",\n          \"name\": \"value\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"name\": \"Approval\",\n      \"type\": \"event\"\n    },\n    {\n      \"anonymous\": false,\n      \"inputs\": [\n        {\n          \"indexed\": true,\n          \"internalType\": \"address\",\n          \"name\": \"from\",\n          \"type\": \"address\"\n        },\n        {\n          \"indexed\": true,\n          \"internalType\": \"address\",\n          \"name\": \"to\",\n          \"type\": \"address\"\n        },\n        {\n          \"indexed\": false,\n          \"internalType\": \"uint256\",\n          \"name\": \"value\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"name\": \"Transfer\",\n      \"type\": \"event\"\n    },\n    {\n      \"inputs\": [\n        {\n          \"internalType\": \"address\",\n          \"name\": \"owner\",\n          \"type\": \"address\"\n        },\n        {\n          \"internalType\": \"address\",\n          \"name\": \"spender\",\n          \"type\": \"address\"\n        }\n      ],\n      \"name\": \"allowance\",\n      \"outputs\": [\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"stateMutability\": \"view\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [\n        {\n          \"internalType\": \"address\",\n          \"name\": \"spender\",\n          \"type\": \"address\"\n        },\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"amount\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"name\": \"approve\",\n      \"outputs\": [\n        {\n          \"internalType\": \"bool\",\n          \"name\": \"\",\n          \"type\": \"bool\"\n        }\n      ],\n      \"stateMutability\": \"nonpayable\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [\n        {\n          \"internalType\": \"address\",\n          \"name\": \"owner\",\n          \"type\": \"address\"\n        },\n        {\n          \"internalType\": \"address\",\n          \"name\": \"spender\",\n          \"type\": \"address\"\n        },\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"value\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"name\": \"approveInternal\",\n      \"outputs\": [],\n      \"stateMutability\": \"nonpayable\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [\n        {\n          \"internalType\": \"address\",\n          \"name\": \"account\",\n          \"type\": \"address\"\n        }\n      ],\n      \"name\": \"balanceOf\",\n      \"outputs\": [\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"stateMutability\": \"view\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [\n        {\n          \"internalType\": \"address\",\n          \"name\": \"account\",\n          \"type\": \"address\"\n        },\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"amount\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"name\": \"burn\",\n      \"outputs\": [],\n      \"stateMutability\": \"nonpayable\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [],\n      \"name\": \"decimals\",\n      \"outputs\": [\n        {\n          \"internalType\": \"uint8\",\n          \"name\": \"\",\n          \"type\": \"uint8\"\n        }\n      ],\n      \"stateMutability\": \"view\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [\n        {\n          \"internalType\": \"address\",\n          \"name\": \"spender\",\n          \"type\": \"address\"\n        },\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"subtractedValue\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"name\": \"decreaseAllowance\",\n      \"outputs\": [\n        {\n          \"internalType\": \"bool\",\n          \"name\": \"\",\n          \"type\": \"bool\"\n        }\n      ],\n      \"stateMutability\": \"nonpayable\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [\n        {\n          \"internalType\": \"address\",\n          \"name\": \"spender\",\n          \"type\": \"address\"\n        },\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"addedValue\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"name\": \"increaseAllowance\",\n      \"outputs\": [\n        {\n          \"internalType\": \"bool\",\n          \"name\": \"\",\n          \"type\": \"bool\"\n        }\n      ],\n      \"stateMutability\": \"nonpayable\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [\n        {\n          \"internalType\": \"address\",\n          \"name\": \"account\",\n          \"type\": \"address\"\n        },\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"amount\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"name\": \"mint\",\n      \"outputs\": [],\n      \"stateMutability\": \"nonpayable\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [],\n      \"name\": \"name\",\n      \"outputs\": [\n        {\n          \"internalType\": \"string\",\n          \"name\": \"\",\n          \"type\": \"string\"\n        }\n      ],\n      \"stateMutability\": \"view\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [],\n      \"name\": \"symbol\",\n      \"outputs\": [\n        {\n          \"internalType\": \"string\",\n          \"name\": \"\",\n          \"type\": \"string\"\n        }\n      ],\n      \"stateMutability\": \"view\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [],\n      \"name\": \"totalSupply\",\n      \"outputs\": [\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"stateMutability\": \"view\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [\n        {\n          \"internalType\": \"address\",\n          \"name\": \"recipient\",\n          \"type\": \"address\"\n        },\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"amount\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"name\": \"transfer\",\n      \"outputs\": [\n        {\n          \"internalType\": \"bool\",\n          \"name\": \"\",\n          \"type\": \"bool\"\n        }\n      ],\n      \"stateMutability\": \"nonpayable\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [\n        {\n          \"internalType\": \"address\",\n          \"name\": \"sender\",\n          \"type\": \"address\"\n        },\n        {\n          \"internalType\": \"address\",\n          \"name\": \"recipient\",\n          \"type\": \"address\"\n        },\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"amount\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"name\": \"transferFrom\",\n      \"outputs\": [\n        {\n          \"internalType\": \"bool\",\n          \"name\": \"\",\n          \"type\": \"bool\"\n        }\n      ],\n      \"stateMutability\": \"nonpayable\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [\n        {\n          \"internalType\": \"address\",\n          \"name\": \"from\",\n          \"type\": \"address\"\n        },\n        {\n          \"internalType\": \"address\",\n          \"name\": \"to\",\n          \"type\": \"address\"\n        },\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"value\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"name\": \"transferInternal\",\n      \"outputs\": [],\n      \"stateMutability\": \"nonpayable\",\n      \"type\": \"function\"\n    }\n  ],\n  \"allSourcePaths\": {\n    \"1\": \"contracts/Address.sol\",\n    \"12\": \"contracts/SafeMath.sol\",\n    \"13\": \"interfaces/IERC20.sol\",\n    \"2\": \"contracts/Context.sol\",\n    \"3\": \"contracts/ERC20.sol\",\n    \"4\": \"contracts/ERC20Mock.sol\",\n    \"6\": \"contracts/FetERC20Mock.sol\"\n  },\n  \"ast\": {\n    \"absolutePath\": \"contracts/FetERC20Mock.sol\",\n    \"exportedSymbols\": {\n      \"FetERC20Mock\": [\n        1516\n      ]\n    },\n    \"id\": 1517,\n    \"license\": \"Apache-2.0\",\n    \"nodeType\": \"SourceUnit\",\n    \"nodes\": [\n      {\n        \"id\": 1489,\n        \"literals\": [\n          \"solidity\",\n          \"^\",\n          \"0.6\",\n          \".0\"\n        ],\n        \"nodeType\": \"PragmaDirective\",\n        \"src\": \"820:23:6\"\n      },\n      {\n        \"absolutePath\": \"contracts/ERC20Mock.sol\",\n        \"file\": \"./ERC20Mock.sol\",\n        \"id\": 1490,\n        \"nodeType\": \"ImportDirective\",\n        \"scope\": 1517,\n        \"sourceUnit\": 1093,\n        \"src\": \"845:25:6\",\n        \"symbolAliases\": [],\n        \"unitAlias\": \"\"\n      },\n      {\n        \"abstract\": false,\n        \"baseContracts\": [\n          {\n            \"arguments\": null,\n            \"baseName\": {\n              \"contractScope\": null,\n              \"id\": 1491,\n              \"name\": \"ERC20Mock\",\n              \"nodeType\": \"UserDefinedTypeName\",\n              \"referencedDeclaration\": 1092,\n              \"src\": \"897:9:6\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_contract$_ERC20Mock_$1092\",\n                \"typeString\": \"contract ERC20Mock\"\n              }\n            },\n            \"id\": 1492,\n            \"nodeType\": \"InheritanceSpecifier\",\n            \"src\": \"897:9:6\"\n          }\n        ],\n        \"contractDependencies\": [\n          500,\n          1007,\n          1092,\n          2713\n        ],\n        \"contractKind\": \"contract\",\n        \"documentation\": null,\n        \"fullyImplemented\": true,\n        \"id\": 1516,\n        \"linearizedBaseContracts\": [\n          1516,\n          1092,\n          1007,\n          2713,\n          500\n        ],\n        \"name\": \"FetERC20Mock\",\n        \"nodeType\": \"ContractDefinition\",\n        \"nodes\": [\n          {\n            \"body\": {\n              \"id\": 1514,\n              \"nodeType\": \"Block\",\n              \"src\": \"1136:42:6\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 1511,\n                        \"name\": \"decimals_\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 1500,\n                        \"src\": \"1161:9:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint8\",\n                          \"typeString\": \"uint8\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_uint8\",\n                          \"typeString\": \"uint8\"\n                        }\n                      ],\n                      \"id\": 1510,\n                      \"name\": \"_setupDecimals\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 995,\n                      \"src\": \"1146:14:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_nonpayable$_t_uint8_$returns$__$\",\n                        \"typeString\": \"function (uint8)\"\n                      }\n                    },\n                    \"id\": 1512,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"1146:25:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 1513,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"1146:25:6\"\n                }\n              ]\n            },\n            \"documentation\": null,\n            \"id\": 1515,\n            \"implemented\": true,\n            \"kind\": \"constructor\",\n            \"modifiers\": [\n              {\n                \"arguments\": [\n                  {\n                    \"argumentTypes\": null,\n                    \"id\": 1503,\n                    \"name\": \"name\",\n                    \"nodeType\": \"Identifier\",\n                    \"overloadedDeclarations\": [],\n                    \"referencedDeclaration\": 1494,\n                    \"src\": \"1091:4:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_string_memory_ptr\",\n                      \"typeString\": \"string memory\"\n                    }\n                  },\n                  {\n                    \"argumentTypes\": null,\n                    \"id\": 1504,\n                    \"name\": \"symbol\",\n                    \"nodeType\": \"Identifier\",\n                    \"overloadedDeclarations\": [],\n                    \"referencedDeclaration\": 1496,\n                    \"src\": \"1097:6:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_string_memory_ptr\",\n                      \"typeString\": \"string memory\"\n                    }\n                  },\n                  {\n                    \"argumentTypes\": null,\n                    \"expression\": {\n                      \"argumentTypes\": null,\n                      \"id\": 1505,\n                      \"name\": \"msg\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": -15,\n                      \"src\": \"1105:3:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_magic_message\",\n                        \"typeString\": \"msg\"\n                      }\n                    },\n                    \"id\": 1506,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"memberName\": \"sender\",\n                    \"nodeType\": \"MemberAccess\",\n                    \"referencedDeclaration\": null,\n                    \"src\": \"1105:10:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address_payable\",\n                      \"typeString\": \"address payable\"\n                    }\n                  },\n                  {\n                    \"argumentTypes\": null,\n                    \"id\": 1507,\n                    \"name\": \"initialSupply\",\n                    \"nodeType\": \"Identifier\",\n                    \"overloadedDeclarations\": [],\n                    \"referencedDeclaration\": 1498,\n                    \"src\": \"1117:13:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  }\n                ],\n                \"id\": 1508,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 1502,\n                  \"name\": \"ERC20Mock\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 1092,\n                  \"src\": \"1081:9:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_type$_t_contract$_ERC20Mock_$1092_$\",\n                    \"typeString\": \"type(contract ERC20Mock)\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"1081:50:6\"\n              }\n            ],\n            \"name\": \"\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 1501,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 1494,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"name\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 1515,\n                  \"src\": \"935:18:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"memory\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_string_memory_ptr\",\n                    \"typeString\": \"string\"\n                  },\n                  \"typeName\": {\n                    \"id\": 1493,\n                    \"name\": \"string\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"935:6:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_string_storage_ptr\",\n                      \"typeString\": \"string\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 1496,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"symbol\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 1515,\n                  \"src\": \"963:20:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"memory\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_string_memory_ptr\",\n                    \"typeString\": \"string\"\n                  },\n                  \"typeName\": {\n                    \"id\": 1495,\n                    \"name\": \"string\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"963:6:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_string_storage_ptr\",\n                      \"typeString\": \"string\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 1498,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"initialSupply\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 1515,\n                  \"src\": \"993:21:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 1497,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"993:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 1500,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"decimals_\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 1515,\n                  \"src\": \"1024:15:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint8\",\n                    \"typeString\": \"uint8\"\n                  },\n                  \"typeName\": {\n                    \"id\": 1499,\n                    \"name\": \"uint8\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"1024:5:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint8\",\n                      \"typeString\": \"uint8\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"925:124:6\"\n            },\n            \"returnParameters\": {\n              \"id\": 1509,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"1136:0:6\"\n            },\n            \"scope\": 1516,\n            \"src\": \"913:265:6\",\n            \"stateMutability\": \"payable\",\n            \"virtual\": false,\n            \"visibility\": \"public\"\n          }\n        ],\n        \"scope\": 1517,\n        \"src\": \"872:308:6\"\n      }\n    ],\n    \"src\": \"820:361:6\"\n  },\n  \"bytecode\": \"6080604052604051620011eb380380620011eb833981810160405260808110156200002957600080fd5b81019080805160405193929190846401000000008211156200004a57600080fd5b9083019060208201858111156200006057600080fd5b82516401000000008111828201881017156200007b57600080fd5b82525081516020918201929091019080838360005b83811015620000aa57818101518382015260200162000090565b50505050905090810190601f168015620000d85780820380516001836020036101000a031916815260200191505b5060405260200180516040519392919084640100000000821115620000fc57600080fd5b9083019060208201858111156200011257600080fd5b82516401000000008111828201881017156200012d57600080fd5b82525081516020918201929091019080838360005b838110156200015c57818101518382015260200162000142565b50505050905090810190601f1680156200018a5780820380516001836020036101000a031916815260200191505b506040908152602082810151929091015186519294509250859185913391869185918591620001bf916003918501906200039c565b508051620001d59060049060208401906200039c565b50506005805460ff1916601217905550620001f1828262000210565b5050505062000206816200031f60201b60201c565b5050505062000438565b6001600160a01b0382166200026c576040805162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015290519081900360640190fd5b6200027a6000838362000335565b62000296816002546200033a60201b620006b81790919060201c565b6002556001600160a01b03821660009081526020818152604090912054620002c9918390620006b86200033a821b17901c565b6001600160a01b0383166000818152602081815260408083209490945583518581529351929391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a35050565b6005805460ff191660ff92909216919091179055565b505050565b60008282018381101562000395576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b9392505050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10620003df57805160ff19168380011785556200040f565b828001600101855582156200040f579182015b828111156200040f578251825591602001919060010190620003f2565b506200041d92915062000421565b5090565b5b808211156200041d576000815560010162000422565b610da380620004486000396000f3fe608060405234801561001057600080fd5b50600436106100f55760003560e01c806340c10f19116100975780639dc29fac116100665780639dc29fac14610319578063a457c2d714610345578063a9059cbb14610371578063dd62ed3e1461039d576100f5565b806340c10f191461028957806356189cb4146102b557806370a08231146102eb57806395d89b4114610311576100f5565b8063222f5be0116100d3578063222f5be0146101d157806323b872dd14610209578063313ce5671461023f578063395093511461025d576100f5565b806306fdde03146100fa578063095ea7b31461017757806318160ddd146101b7575b600080fd5b6101026103cb565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561013c578181015183820152602001610124565b50505050905090810190601f1680156101695780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6101a36004803603604081101561018d57600080fd5b506001600160a01b038135169060200135610461565b604080519115158252519081900360200190f35b6101bf61047e565b60408051918252519081900360200190f35b610207600480360360608110156101e757600080fd5b506001600160a01b03813581169160208101359091169060400135610484565b005b6101a36004803603606081101561021f57600080fd5b506001600160a01b03813581169160208101359091169060400135610494565b61024761051b565b6040805160ff9092168252519081900360200190f35b6101a36004803603604081101561027357600080fd5b506001600160a01b038135169060200135610524565b6102076004803603604081101561029f57600080fd5b506001600160a01b038135169060200135610572565b610207600480360360608110156102cb57600080fd5b506001600160a01b03813581169160208101359091169060400135610580565b6101bf6004803603602081101561030157600080fd5b50356001600160a01b031661058b565b6101026105a6565b6102076004803603604081101561032f57600080fd5b506001600160a01b038135169060200135610607565b6101a36004803603604081101561035b57600080fd5b506001600160a01b038135169060200135610611565b6101a36004803603604081101561038757600080fd5b506001600160a01b038135169060200135610679565b6101bf600480360360408110156103b357600080fd5b506001600160a01b038135811691602001351661068d565b60038054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156104575780601f1061042c57610100808354040283529160200191610457565b820191906000526020600020905b81548152906001019060200180831161043a57829003601f168201915b5050505050905090565b600061047561046e610719565b848461071d565b50600192915050565b60025490565b61048f838383610809565b505050565b60006104a1848484610809565b610511846104ad610719565b61050c85604051806060016040528060288152602001610cb7602891396001600160a01b038a166000908152600160205260408120906104eb610719565b6001600160a01b031681526020810191909152604001600020549190610964565b61071d565b5060019392505050565b60055460ff1690565b6000610475610531610719565b8461050c8560016000610542610719565b6001600160a01b03908116825260208083019390935260409182016000908120918c1681529252902054906106b8565b61057c82826109fb565b5050565b61048f83838361071d565b6001600160a01b031660009081526020819052604090205490565b60048054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156104575780601f1061042c57610100808354040283529160200191610457565b61057c8282610aeb565b600061047561061e610719565b8461050c85604051806060016040528060258152602001610d496025913960016000610648610719565b6001600160a01b03908116825260208083019390935260409182016000908120918d16815292529020549190610964565b6000610475610686610719565b8484610809565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b600082820183811015610712576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b9392505050565b3390565b6001600160a01b0383166107625760405162461bcd60e51b8152600401808060200182810382526024815260200180610d256024913960400191505060405180910390fd5b6001600160a01b0382166107a75760405162461bcd60e51b8152600401808060200182810382526022815260200180610c6f6022913960400191505060405180910390fd5b6001600160a01b03808416600081815260016020908152604080832094871680845294825291829020859055815185815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3505050565b6001600160a01b03831661084e5760405162461bcd60e51b8152600401808060200182810382526025815260200180610d006025913960400191505060405180910390fd5b6001600160a01b0382166108935760405162461bcd60e51b8152600401808060200182810382526023815260200180610c2a6023913960400191505060405180910390fd5b61089e83838361048f565b6108db81604051806060016040528060268152602001610c91602691396001600160a01b0386166000908152602081905260409020549190610964565b6001600160a01b03808516600090815260208190526040808220939093559084168152205461090a90826106b8565b6001600160a01b038084166000818152602081815260409182902094909455805185815290519193928716927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a3505050565b600081848411156109f35760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b838110156109b85781810151838201526020016109a0565b50505050905090810190601f1680156109e55780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b6001600160a01b038216610a56576040805162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015290519081900360640190fd5b610a626000838361048f565b600254610a6f90826106b8565b6002556001600160a01b038216600090815260208190526040902054610a9590826106b8565b6001600160a01b0383166000818152602081815260408083209490945583518581529351929391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a35050565b6001600160a01b038216610b305760405162461bcd60e51b8152600401808060200182810382526021815260200180610cdf6021913960400191505060405180910390fd5b610b3c8260008361048f565b610b7981604051806060016040528060228152602001610c4d602291396001600160a01b0385166000908152602081905260409020549190610964565b6001600160a01b038316600090815260208190526040902055600254610b9f9082610be7565b6002556040805182815290516000916001600160a01b038516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9181900360200190a35050565b600061071283836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f77000081525061096456fe45524332303a207472616e7366657220746f20746865207a65726f206164647265737345524332303a206275726e20616d6f756e7420657863656564732062616c616e636545524332303a20617070726f766520746f20746865207a65726f206164647265737345524332303a207472616e7366657220616d6f756e7420657863656564732062616c616e636545524332303a207472616e7366657220616d6f756e74206578636565647320616c6c6f77616e636545524332303a206275726e2066726f6d20746865207a65726f206164647265737345524332303a207472616e736665722066726f6d20746865207a65726f206164647265737345524332303a20617070726f76652066726f6d20746865207a65726f206164647265737345524332303a2064656372656173656420616c6c6f77616e63652062656c6f77207a65726fa264697066735822122025eb021c0ed77f150fa57486a8a5859aa0bd55f4a7e710b5e08119b2c079293964736f6c634300060c0033\",\n  \"bytecodeSha1\": \"ea60ac335378f826c77f1866c8f5cdddd74e1e95\",\n  \"compiler\": {\n    \"evm_version\": \"istanbul\",\n    \"optimizer\": {\n      \"enabled\": true,\n      \"runs\": 200\n    },\n    \"version\": \"0.6.12\"\n  },\n  \"contractName\": \"FetERC20Mock\",\n  \"coverageMap\": {\n    \"branches\": {\n      \"1\": {},\n      \"12\": {\n        \"SafeMath.add\": {\n          \"49\": [\n            986,\n            992,\n            true\n          ]\n        },\n        \"SafeMath.sub\": {\n          \"50\": [\n            1859,\n            1865,\n            true\n          ]\n        }\n      },\n      \"13\": {},\n      \"2\": {},\n      \"3\": {\n        \"ERC20._approve\": {\n          \"43\": [\n            9445,\n            9464,\n            true\n          ],\n          \"44\": [\n            9523,\n            9544,\n            true\n          ]\n        },\n        \"ERC20._burn\": {\n          \"48\": [\n            8592,\n            8613,\n            true\n          ]\n        },\n        \"ERC20._mint\": {\n          \"47\": [\n            7903,\n            7924,\n            true\n          ]\n        },\n        \"ERC20._transfer\": {\n          \"45\": [\n            7125,\n            7145,\n            true\n          ],\n          \"46\": [\n            7205,\n            7228,\n            true\n          ]\n        }\n      },\n      \"4\": {},\n      \"6\": {}\n    },\n    \"statements\": {\n      \"1\": {},\n      \"12\": {\n        \"SafeMath.add\": {\n          \"18\": [\n            978,\n            1024\n          ],\n          \"19\": [\n            1035,\n            1043\n          ]\n        },\n        \"SafeMath.sub\": {\n          \"31\": [\n            1851,\n            1880\n          ],\n          \"42\": [\n            1398,\n            1448\n          ]\n        }\n      },\n      \"13\": {},\n      \"2\": {\n        \"Context._msgSender\": {\n          \"20\": [\n            670,\n            687\n          ]\n        }\n      },\n      \"3\": {\n        \"ERC20._approve\": {\n          \"21\": [\n            9437,\n            9505\n          ],\n          \"22\": [\n            9515,\n            9583\n          ],\n          \"23\": [\n            9594,\n            9630\n          ],\n          \"24\": [\n            9640,\n            9677\n          ]\n        },\n        \"ERC20._burn\": {\n          \"37\": [\n            8584,\n            8651\n          ],\n          \"38\": [\n            8662,\n            8711\n          ],\n          \"39\": [\n            8722,\n            8811\n          ],\n          \"40\": [\n            8821,\n            8860\n          ],\n          \"41\": [\n            8870,\n            8912\n          ]\n        },\n        \"ERC20._mint\": {\n          \"32\": [\n            7895,\n            7960\n          ],\n          \"33\": [\n            7971,\n            8020\n          ],\n          \"34\": [\n            8031,\n            8070\n          ],\n          \"35\": [\n            8080,\n            8131\n          ],\n          \"36\": [\n            8141,\n            8183\n          ]\n        },\n        \"ERC20._transfer\": {\n          \"25\": [\n            7117,\n            7187\n          ],\n          \"26\": [\n            7197,\n            7268\n          ],\n          \"27\": [\n            7279,\n            7326\n          ],\n          \"28\": [\n            7337,\n            7428\n          ],\n          \"29\": [\n            7438,\n            7493\n          ],\n          \"30\": [\n            7503,\n            7543\n          ]\n        },\n        \"ERC20.allowance\": {\n          \"17\": [\n            4061,\n            4095\n          ]\n        },\n        \"ERC20.approve\": {\n          \"1\": [\n            4339,\n            4378\n          ],\n          \"2\": [\n            4388,\n            4399\n          ]\n        },\n        \"ERC20.balanceOf\": {\n          \"12\": [\n            3488,\n            3513\n          ]\n        },\n        \"ERC20.decimals\": {\n          \"8\": [\n            3164,\n            3180\n          ]\n        },\n        \"ERC20.decreaseAllowance\": {\n          \"15\": [\n            6389,\n            6518\n          ]\n        },\n        \"ERC20.increaseAllowance\": {\n          \"9\": [\n            5682,\n            5765\n          ]\n        },\n        \"ERC20.name\": {\n          \"0\": [\n            2266,\n            2278\n          ]\n        },\n        \"ERC20.symbol\": {\n          \"13\": [\n            2462,\n            2476\n          ]\n        },\n        \"ERC20.totalSupply\": {\n          \"3\": [\n            3319,\n            3338\n          ]\n        },\n        \"ERC20.transfer\": {\n          \"16\": [\n            3825,\n            3867\n          ]\n        },\n        \"ERC20.transferFrom\": {\n          \"5\": [\n            4988,\n            5024\n          ],\n          \"6\": [\n            5034,\n            5155\n          ],\n          \"7\": [\n            5165,\n            5176\n          ]\n        }\n      },\n      \"4\": {\n        \"ERC20Mock.approveInternal\": {\n          \"11\": [\n            787,\n            818\n          ]\n        },\n        \"ERC20Mock.burn\": {\n          \"14\": [\n            540,\n            562\n          ]\n        },\n        \"ERC20Mock.mint\": {\n          \"10\": [\n            441,\n            463\n          ]\n        },\n        \"ERC20Mock.transferInternal\": {\n          \"4\": [\n            659,\n            685\n          ]\n        }\n      },\n      \"6\": {}\n    }\n  },\n  \"dependencies\": [\n    \"Address\",\n    \"Context\",\n    \"ERC20\",\n    \"ERC20Mock\",\n    \"IERC20\",\n    \"SafeMath\"\n  ],\n  \"deployedBytecode\": \"608060405234801561001057600080fd5b50600436106100f55760003560e01c806340c10f19116100975780639dc29fac116100665780639dc29fac14610319578063a457c2d714610345578063a9059cbb14610371578063dd62ed3e1461039d576100f5565b806340c10f191461028957806356189cb4146102b557806370a08231146102eb57806395d89b4114610311576100f5565b8063222f5be0116100d3578063222f5be0146101d157806323b872dd14610209578063313ce5671461023f578063395093511461025d576100f5565b806306fdde03146100fa578063095ea7b31461017757806318160ddd146101b7575b600080fd5b6101026103cb565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561013c578181015183820152602001610124565b50505050905090810190601f1680156101695780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6101a36004803603604081101561018d57600080fd5b506001600160a01b038135169060200135610461565b604080519115158252519081900360200190f35b6101bf61047e565b60408051918252519081900360200190f35b610207600480360360608110156101e757600080fd5b506001600160a01b03813581169160208101359091169060400135610484565b005b6101a36004803603606081101561021f57600080fd5b506001600160a01b03813581169160208101359091169060400135610494565b61024761051b565b6040805160ff9092168252519081900360200190f35b6101a36004803603604081101561027357600080fd5b506001600160a01b038135169060200135610524565b6102076004803603604081101561029f57600080fd5b506001600160a01b038135169060200135610572565b610207600480360360608110156102cb57600080fd5b506001600160a01b03813581169160208101359091169060400135610580565b6101bf6004803603602081101561030157600080fd5b50356001600160a01b031661058b565b6101026105a6565b6102076004803603604081101561032f57600080fd5b506001600160a01b038135169060200135610607565b6101a36004803603604081101561035b57600080fd5b506001600160a01b038135169060200135610611565b6101a36004803603604081101561038757600080fd5b506001600160a01b038135169060200135610679565b6101bf600480360360408110156103b357600080fd5b506001600160a01b038135811691602001351661068d565b60038054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156104575780601f1061042c57610100808354040283529160200191610457565b820191906000526020600020905b81548152906001019060200180831161043a57829003601f168201915b5050505050905090565b600061047561046e610719565b848461071d565b50600192915050565b60025490565b61048f838383610809565b505050565b60006104a1848484610809565b610511846104ad610719565b61050c85604051806060016040528060288152602001610cb7602891396001600160a01b038a166000908152600160205260408120906104eb610719565b6001600160a01b031681526020810191909152604001600020549190610964565b61071d565b5060019392505050565b60055460ff1690565b6000610475610531610719565b8461050c8560016000610542610719565b6001600160a01b03908116825260208083019390935260409182016000908120918c1681529252902054906106b8565b61057c82826109fb565b5050565b61048f83838361071d565b6001600160a01b031660009081526020819052604090205490565b60048054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156104575780601f1061042c57610100808354040283529160200191610457565b61057c8282610aeb565b600061047561061e610719565b8461050c85604051806060016040528060258152602001610d496025913960016000610648610719565b6001600160a01b03908116825260208083019390935260409182016000908120918d16815292529020549190610964565b6000610475610686610719565b8484610809565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b600082820183811015610712576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b9392505050565b3390565b6001600160a01b0383166107625760405162461bcd60e51b8152600401808060200182810382526024815260200180610d256024913960400191505060405180910390fd5b6001600160a01b0382166107a75760405162461bcd60e51b8152600401808060200182810382526022815260200180610c6f6022913960400191505060405180910390fd5b6001600160a01b03808416600081815260016020908152604080832094871680845294825291829020859055815185815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3505050565b6001600160a01b03831661084e5760405162461bcd60e51b8152600401808060200182810382526025815260200180610d006025913960400191505060405180910390fd5b6001600160a01b0382166108935760405162461bcd60e51b8152600401808060200182810382526023815260200180610c2a6023913960400191505060405180910390fd5b61089e83838361048f565b6108db81604051806060016040528060268152602001610c91602691396001600160a01b0386166000908152602081905260409020549190610964565b6001600160a01b03808516600090815260208190526040808220939093559084168152205461090a90826106b8565b6001600160a01b038084166000818152602081815260409182902094909455805185815290519193928716927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a3505050565b600081848411156109f35760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b838110156109b85781810151838201526020016109a0565b50505050905090810190601f1680156109e55780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b6001600160a01b038216610a56576040805162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015290519081900360640190fd5b610a626000838361048f565b600254610a6f90826106b8565b6002556001600160a01b038216600090815260208190526040902054610a9590826106b8565b6001600160a01b0383166000818152602081815260408083209490945583518581529351929391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a35050565b6001600160a01b038216610b305760405162461bcd60e51b8152600401808060200182810382526021815260200180610cdf6021913960400191505060405180910390fd5b610b3c8260008361048f565b610b7981604051806060016040528060228152602001610c4d602291396001600160a01b0385166000908152602081905260409020549190610964565b6001600160a01b038316600090815260208190526040902055600254610b9f9082610be7565b6002556040805182815290516000916001600160a01b038516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9181900360200190a35050565b600061071283836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f77000081525061096456fe45524332303a207472616e7366657220746f20746865207a65726f206164647265737345524332303a206275726e20616d6f756e7420657863656564732062616c616e636545524332303a20617070726f766520746f20746865207a65726f206164647265737345524332303a207472616e7366657220616d6f756e7420657863656564732062616c616e636545524332303a207472616e7366657220616d6f756e74206578636565647320616c6c6f77616e636545524332303a206275726e2066726f6d20746865207a65726f206164647265737345524332303a207472616e736665722066726f6d20746865207a65726f206164647265737345524332303a20617070726f76652066726f6d20746865207a65726f206164647265737345524332303a2064656372656173656420616c6c6f77616e63652062656c6f77207a65726fa264697066735822122025eb021c0ed77f150fa57486a8a5859aa0bd55f4a7e710b5e08119b2c079293964736f6c634300060c0033\",\n  \"deployedSourceMap\": \"872:308:6:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2204:81:3;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4240:166;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;4240:166:3;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;3247:98;;;:::i;:::-;;;;;;;;;;;;;;;;575:117:4;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;575:117:4;;;;;;;;;;;;;;;;;:::i;:::-;;4866:317:3;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;4866:317:3;;;;;;;;;;;;;;;;;:::i;3106:81::-;;;:::i;:::-;;;;;;;;;;;;;;;;;;;5578:215;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;5578:215:3;;;;;;;;:::i;377:93:4:-;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;377:93:4;;;;;;;;:::i;698:127::-;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;698:127:4;;;;;;;;;;;;;;;;;:::i;3403:117:3:-;;;;;;;;;;;;;;;;-1:-1:-1;3403:117:3;-1:-1:-1;;;;;3403:117:3;;:::i;2398:85::-;;;:::i;476:93:4:-;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;476:93:4;;;;;;;;:::i;6280:266:3:-;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;6280:266:3;;;;;;;;:::i;3723:172::-;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;3723:172:3;;;;;;;;:::i;3953:149::-;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;3953:149:3;;;;;;;;;;:::i;2204:81::-;2273:5;2266:12;;;;;;;;-1:-1:-1;;2266:12:3;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2241:13;;2266:12;;2273:5;;2266:12;;2273:5;2266:12;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2204:81;:::o;4240:166::-;4323:4;4339:39;4348:12;:10;:12::i;:::-;4362:7;4371:6;4339:8;:39::i;:::-;-1:-1:-1;4395:4:3;4240:166;;;;:::o;3247:98::-;3326:12;;3247:98;:::o;575:117:4:-;659:26;669:4;675:2;679:5;659:9;:26::i;:::-;575:117;;;:::o;4866:317:3:-;4972:4;4988:36;4998:6;5006:9;5017:6;4988:9;:36::i;:::-;5034:121;5043:6;5051:12;:10;:12::i;:::-;5065:89;5103:6;5065:89;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;5065:19:3;;;;;;:11;:19;;;;;;5085:12;:10;:12::i;:::-;-1:-1:-1;;;;;5065:33:3;;;;;;;;;;;;-1:-1:-1;5065:33:3;;;:89;:37;:89::i;:::-;5034:8;:121::i;:::-;-1:-1:-1;5172:4:3;4866:317;;;;;:::o;3106:81::-;3171:9;;;;3106:81;:::o;5578:215::-;5666:4;5682:83;5691:12;:10;:12::i;:::-;5705:7;5714:50;5753:10;5714:11;:25;5726:12;:10;:12::i;:::-;-1:-1:-1;;;;;5714:25:3;;;;;;;;;;;;;;;;;-1:-1:-1;5714:25:3;;;:34;;;;;;;;;;;:38;:50::i;377:93:4:-;441:22;447:7;456:6;441:5;:22::i;:::-;377:93;;:::o;698:127::-;787:31;796:5;803:7;812:5;787:8;:31::i;3403:117:3:-;-1:-1:-1;;;;;3495:18:3;3469:7;3495:18;;;;;;;;;;;;3403:117::o;2398:85::-;2469:7;2462:14;;;;;;;;-1:-1:-1;;2462:14:3;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2437:13;;2462:14;;2469:7;;2462:14;;2469:7;2462:14;;;;;;;;;;;;;;;;;;;;;;;;476:93:4;540:22;546:7;555:6;540:5;:22::i;6280:266:3:-;6373:4;6389:129;6398:12;:10;:12::i;:::-;6412:7;6421:96;6460:15;6421:96;;;;;;;;;;;;;;;;;:11;:25;6433:12;:10;:12::i;:::-;-1:-1:-1;;;;;6421:25:3;;;;;;;;;;;;;;;;;-1:-1:-1;6421:25:3;;;:34;;;;;;;;;;;:96;:38;:96::i;3723:172::-;3809:4;3825:42;3835:12;:10;:12::i;:::-;3849:9;3860:6;3825:9;:42::i;3953:149::-;-1:-1:-1;;;;;4068:18:3;;;4042:7;4068:18;;;:11;:18;;;;;;;;:27;;;;;;;;;;;;;3953:149::o;874:176:12:-;932:7;963:5;;;986:6;;;;978:46;;;;;-1:-1:-1;;;978:46:12;;;;;;;;;;;;;;;;;;;;;;;;;;;;1042:1;874:176;-1:-1:-1;;;874:176:12:o;590:104:2:-;677:10;590:104;:::o;9344:340:3:-;-1:-1:-1;;;;;9445:19:3;;9437:68;;;;-1:-1:-1;;;9437:68:3;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;9523:21:3;;9515:68;;;;-1:-1:-1;;;9515:68:3;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;9594:18:3;;;;;;;:11;:18;;;;;;;;:27;;;;;;;;;;;;;:36;;;9645:32;;;;;;;;;;;;;;;;;9344:340;;;:::o;7020:530::-;-1:-1:-1;;;;;7125:20:3;;7117:70;;;;-1:-1:-1;;;7117:70:3;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;7205:23:3;;7197:71;;;;-1:-1:-1;;;7197:71:3;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;7279:47;7300:6;7308:9;7319:6;7279:20;:47::i;:::-;7357:71;7379:6;7357:71;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;7357:17:3;;:9;:17;;;;;;;;;;;;:71;:21;:71::i;:::-;-1:-1:-1;;;;;7337:17:3;;;:9;:17;;;;;;;;;;;:91;;;;7461:20;;;;;;;:32;;7486:6;7461:24;:32::i;:::-;-1:-1:-1;;;;;7438:20:3;;;:9;:20;;;;;;;;;;;;:55;;;;7508:35;;;;;;;7438:20;;7508:35;;;;;;;;;;;;;7020:530;;;:::o;1746:187:12:-;1832:7;1867:12;1859:6;;;;1851:29;;;;-1:-1:-1;;;1851:29:12;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;1902:5:12;;;1746:187::o;7820:370:3:-;-1:-1:-1;;;;;7903:21:3;;7895:65;;;;;-1:-1:-1;;;7895:65:3;;;;;;;;;;;;;;;;;;;;;;;;;;;;7971:49;8000:1;8004:7;8013:6;7971:20;:49::i;:::-;8046:12;;:24;;8063:6;8046:16;:24::i;:::-;8031:12;:39;-1:-1:-1;;;;;8101:18:3;;:9;:18;;;;;;;;;;;:30;;8124:6;8101:22;:30::i;:::-;-1:-1:-1;;;;;8080:18:3;;:9;:18;;;;;;;;;;;:51;;;;8146:37;;;;;;;8080:18;;:9;;8146:37;;;;;;;;;;7820:370;;:::o;8509:410::-;-1:-1:-1;;;;;8592:21:3;;8584:67;;;;-1:-1:-1;;;8584:67:3;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8662:49;8683:7;8700:1;8704:6;8662:20;:49::i;:::-;8743:68;8766:6;8743:68;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;8743:18:3;;:9;:18;;;;;;;;;;;;:68;:22;:68::i;:::-;-1:-1:-1;;;;;8722:18:3;;:9;:18;;;;;;;;;;:89;8836:12;;:24;;8853:6;8836:16;:24::i;:::-;8821:12;:39;8875:37;;;;;;;;8901:1;;-1:-1:-1;;;;;8875:37:3;;;;;;;;;;;;8509:410;;:::o;1321:134:12:-;1379:7;1405:43;1409:1;1412;1405:43;;;;;;;;;;;;;;;;;:3;:43::i\",\n  \"language\": \"Solidity\",\n  \"natspec\": {\n    \"kind\": \"dev\",\n    \"methods\": {\n      \"allowance(address,address)\": {\n        \"details\": \"See {IERC20-allowance}.\"\n      },\n      \"approve(address,uint256)\": {\n        \"details\": \"See {IERC20-approve}. Requirements: - `spender` cannot be the zero address.\"\n      },\n      \"balanceOf(address)\": {\n        \"details\": \"See {IERC20-balanceOf}.\"\n      },\n      \"decimals()\": {\n        \"details\": \"Returns the number of decimals used to get its user representation. For example, if `decimals` equals `2`, a balance of `505` tokens should be displayed to a user as `5,05` (`505 / 10 ** 2`). Tokens usually opt for a value of 18, imitating the relationship between Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is called. NOTE: This information is only used for _display_ purposes: it in no way affects any of the arithmetic of the contract, including {IERC20-balanceOf} and {IERC20-transfer}.\"\n      },\n      \"decreaseAllowance(address,uint256)\": {\n        \"details\": \"Atomically decreases the allowance granted to `spender` by the caller. This is an alternative to {approve} that can be used as a mitigation for problems described in {IERC20-approve}. Emits an {Approval} event indicating the updated allowance. Requirements: - `spender` cannot be the zero address. - `spender` must have allowance for the caller of at least `subtractedValue`.\"\n      },\n      \"increaseAllowance(address,uint256)\": {\n        \"details\": \"Atomically increases the allowance granted to `spender` by the caller. This is an alternative to {approve} that can be used as a mitigation for problems described in {IERC20-approve}. Emits an {Approval} event indicating the updated allowance. Requirements: - `spender` cannot be the zero address.\"\n      },\n      \"name()\": {\n        \"details\": \"Returns the name of the token.\"\n      },\n      \"symbol()\": {\n        \"details\": \"Returns the symbol of the token, usually a shorter version of the name.\"\n      },\n      \"totalSupply()\": {\n        \"details\": \"See {IERC20-totalSupply}.\"\n      },\n      \"transfer(address,uint256)\": {\n        \"details\": \"See {IERC20-transfer}. Requirements: - `recipient` cannot be the zero address. - the caller must have a balance of at least `amount`.\"\n      },\n      \"transferFrom(address,address,uint256)\": {\n        \"details\": \"See {IERC20-transferFrom}. Emits an {Approval} event indicating the updated allowance. This is not required by the EIP. See the note at the beginning of {ERC20}; Requirements: - `sender` and `recipient` cannot be the zero address. - `sender` must have a balance of at least `amount`. - the caller must have allowance for ``sender``'s tokens of at least `amount`.\"\n      }\n    },\n    \"version\": 1\n  },\n  \"offset\": [\n    872,\n    1180\n  ],\n  \"opcodes\": \"PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x4 CALLDATASIZE LT PUSH2 0xF5 JUMPI PUSH1 0x0 CALLDATALOAD PUSH1 0xE0 SHR DUP1 PUSH4 0x40C10F19 GT PUSH2 0x97 JUMPI DUP1 PUSH4 0x9DC29FAC GT PUSH2 0x66 JUMPI DUP1 PUSH4 0x9DC29FAC EQ PUSH2 0x319 JUMPI DUP1 PUSH4 0xA457C2D7 EQ PUSH2 0x345 JUMPI DUP1 PUSH4 0xA9059CBB EQ PUSH2 0x371 JUMPI DUP1 PUSH4 0xDD62ED3E EQ PUSH2 0x39D JUMPI PUSH2 0xF5 JUMP JUMPDEST DUP1 PUSH4 0x40C10F19 EQ PUSH2 0x289 JUMPI DUP1 PUSH4 0x56189CB4 EQ PUSH2 0x2B5 JUMPI DUP1 PUSH4 0x70A08231 EQ PUSH2 0x2EB JUMPI DUP1 PUSH4 0x95D89B41 EQ PUSH2 0x311 JUMPI PUSH2 0xF5 JUMP JUMPDEST DUP1 PUSH4 0x222F5BE0 GT PUSH2 0xD3 JUMPI DUP1 PUSH4 0x222F5BE0 EQ PUSH2 0x1D1 JUMPI DUP1 PUSH4 0x23B872DD EQ PUSH2 0x209 JUMPI DUP1 PUSH4 0x313CE567 EQ PUSH2 0x23F JUMPI DUP1 PUSH4 0x39509351 EQ PUSH2 0x25D JUMPI PUSH2 0xF5 JUMP JUMPDEST DUP1 PUSH4 0x6FDDE03 EQ PUSH2 0xFA JUMPI DUP1 PUSH4 0x95EA7B3 EQ PUSH2 0x177 JUMPI DUP1 PUSH4 0x18160DDD EQ PUSH2 0x1B7 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x102 PUSH2 0x3CB JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0x20 DUP1 DUP3 MSTORE DUP4 MLOAD DUP2 DUP4 ADD MSTORE DUP4 MLOAD SWAP2 SWAP3 DUP4 SWAP3 SWAP1 DUP4 ADD SWAP2 DUP6 ADD SWAP1 DUP1 DUP4 DUP4 PUSH1 0x0 JUMPDEST DUP4 DUP2 LT ISZERO PUSH2 0x13C JUMPI DUP2 DUP2 ADD MLOAD DUP4 DUP3 ADD MSTORE PUSH1 0x20 ADD PUSH2 0x124 JUMP JUMPDEST POP POP POP POP SWAP1 POP SWAP1 DUP2 ADD SWAP1 PUSH1 0x1F AND DUP1 ISZERO PUSH2 0x169 JUMPI DUP1 DUP3 SUB DUP1 MLOAD PUSH1 0x1 DUP4 PUSH1 0x20 SUB PUSH2 0x100 EXP SUB NOT AND DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP JUMPDEST POP SWAP3 POP POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH2 0x1A3 PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x40 DUP2 LT ISZERO PUSH2 0x18D JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB DUP2 CALLDATALOAD AND SWAP1 PUSH1 0x20 ADD CALLDATALOAD PUSH2 0x461 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD SWAP2 ISZERO ISZERO DUP3 MSTORE MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x20 ADD SWAP1 RETURN JUMPDEST PUSH2 0x1BF PUSH2 0x47E JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD SWAP2 DUP3 MSTORE MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x20 ADD SWAP1 RETURN JUMPDEST PUSH2 0x207 PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x60 DUP2 LT ISZERO PUSH2 0x1E7 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB DUP2 CALLDATALOAD DUP2 AND SWAP2 PUSH1 0x20 DUP2 ADD CALLDATALOAD SWAP1 SWAP2 AND SWAP1 PUSH1 0x40 ADD CALLDATALOAD PUSH2 0x484 JUMP JUMPDEST STOP JUMPDEST PUSH2 0x1A3 PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x60 DUP2 LT ISZERO PUSH2 0x21F JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB DUP2 CALLDATALOAD DUP2 AND SWAP2 PUSH1 0x20 DUP2 ADD CALLDATALOAD SWAP1 SWAP2 AND SWAP1 PUSH1 0x40 ADD CALLDATALOAD PUSH2 0x494 JUMP JUMPDEST PUSH2 0x247 PUSH2 0x51B JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0xFF SWAP1 SWAP3 AND DUP3 MSTORE MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x20 ADD SWAP1 RETURN JUMPDEST PUSH2 0x1A3 PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x40 DUP2 LT ISZERO PUSH2 0x273 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB DUP2 CALLDATALOAD AND SWAP1 PUSH1 0x20 ADD CALLDATALOAD PUSH2 0x524 JUMP JUMPDEST PUSH2 0x207 PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x40 DUP2 LT ISZERO PUSH2 0x29F JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB DUP2 CALLDATALOAD AND SWAP1 PUSH1 0x20 ADD CALLDATALOAD PUSH2 0x572 JUMP JUMPDEST PUSH2 0x207 PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x60 DUP2 LT ISZERO PUSH2 0x2CB JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB DUP2 CALLDATALOAD DUP2 AND SWAP2 PUSH1 0x20 DUP2 ADD CALLDATALOAD SWAP1 SWAP2 AND SWAP1 PUSH1 0x40 ADD CALLDATALOAD PUSH2 0x580 JUMP JUMPDEST PUSH2 0x1BF PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x301 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP CALLDATALOAD PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB AND PUSH2 0x58B JUMP JUMPDEST PUSH2 0x102 PUSH2 0x5A6 JUMP JUMPDEST PUSH2 0x207 PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x40 DUP2 LT ISZERO PUSH2 0x32F JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB DUP2 CALLDATALOAD AND SWAP1 PUSH1 0x20 ADD CALLDATALOAD PUSH2 0x607 JUMP JUMPDEST PUSH2 0x1A3 PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x40 DUP2 LT ISZERO PUSH2 0x35B JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB DUP2 CALLDATALOAD AND SWAP1 PUSH1 0x20 ADD CALLDATALOAD PUSH2 0x611 JUMP JUMPDEST PUSH2 0x1A3 PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x40 DUP2 LT ISZERO PUSH2 0x387 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB DUP2 CALLDATALOAD AND SWAP1 PUSH1 0x20 ADD CALLDATALOAD PUSH2 0x679 JUMP JUMPDEST PUSH2 0x1BF PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x40 DUP2 LT ISZERO PUSH2 0x3B3 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB DUP2 CALLDATALOAD DUP2 AND SWAP2 PUSH1 0x20 ADD CALLDATALOAD AND PUSH2 0x68D JUMP JUMPDEST PUSH1 0x3 DUP1 SLOAD PUSH1 0x40 DUP1 MLOAD PUSH1 0x20 PUSH1 0x1F PUSH1 0x2 PUSH1 0x0 NOT PUSH2 0x100 PUSH1 0x1 DUP9 AND ISZERO MUL ADD SWAP1 SWAP6 AND SWAP5 SWAP1 SWAP5 DIV SWAP4 DUP5 ADD DUP2 SWAP1 DIV DUP2 MUL DUP3 ADD DUP2 ADD SWAP1 SWAP3 MSTORE DUP3 DUP2 MSTORE PUSH1 0x60 SWAP4 SWAP1 SWAP3 SWAP1 SWAP2 DUP4 ADD DUP3 DUP3 DUP1 ISZERO PUSH2 0x457 JUMPI DUP1 PUSH1 0x1F LT PUSH2 0x42C JUMPI PUSH2 0x100 DUP1 DUP4 SLOAD DIV MUL DUP4 MSTORE SWAP2 PUSH1 0x20 ADD SWAP2 PUSH2 0x457 JUMP JUMPDEST DUP3 ADD SWAP2 SWAP1 PUSH1 0x0 MSTORE PUSH1 0x20 PUSH1 0x0 KECCAK256 SWAP1 JUMPDEST DUP2 SLOAD DUP2 MSTORE SWAP1 PUSH1 0x1 ADD SWAP1 PUSH1 0x20 ADD DUP1 DUP4 GT PUSH2 0x43A JUMPI DUP3 SWAP1 SUB PUSH1 0x1F AND DUP3 ADD SWAP2 JUMPDEST POP POP POP POP POP SWAP1 POP SWAP1 JUMP JUMPDEST PUSH1 0x0 PUSH2 0x475 PUSH2 0x46E PUSH2 0x719 JUMP JUMPDEST DUP5 DUP5 PUSH2 0x71D JUMP JUMPDEST POP PUSH1 0x1 SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x2 SLOAD SWAP1 JUMP JUMPDEST PUSH2 0x48F DUP4 DUP4 DUP4 PUSH2 0x809 JUMP JUMPDEST POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH2 0x4A1 DUP5 DUP5 DUP5 PUSH2 0x809 JUMP JUMPDEST PUSH2 0x511 DUP5 PUSH2 0x4AD PUSH2 0x719 JUMP JUMPDEST PUSH2 0x50C DUP6 PUSH1 0x40 MLOAD DUP1 PUSH1 0x60 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x28 DUP2 MSTORE PUSH1 0x20 ADD PUSH2 0xCB7 PUSH1 0x28 SWAP2 CODECOPY PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB DUP11 AND PUSH1 0x0 SWAP1 DUP2 MSTORE PUSH1 0x1 PUSH1 0x20 MSTORE PUSH1 0x40 DUP2 KECCAK256 SWAP1 PUSH2 0x4EB PUSH2 0x719 JUMP JUMPDEST PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB AND DUP2 MSTORE PUSH1 0x20 DUP2 ADD SWAP2 SWAP1 SWAP2 MSTORE PUSH1 0x40 ADD PUSH1 0x0 KECCAK256 SLOAD SWAP2 SWAP1 PUSH2 0x964 JUMP JUMPDEST PUSH2 0x71D JUMP JUMPDEST POP PUSH1 0x1 SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH1 0x5 SLOAD PUSH1 0xFF AND SWAP1 JUMP JUMPDEST PUSH1 0x0 PUSH2 0x475 PUSH2 0x531 PUSH2 0x719 JUMP JUMPDEST DUP5 PUSH2 0x50C DUP6 PUSH1 0x1 PUSH1 0x0 PUSH2 0x542 PUSH2 0x719 JUMP JUMPDEST PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB SWAP1 DUP2 AND DUP3 MSTORE PUSH1 0x20 DUP1 DUP4 ADD SWAP4 SWAP1 SWAP4 MSTORE PUSH1 0x40 SWAP2 DUP3 ADD PUSH1 0x0 SWAP1 DUP2 KECCAK256 SWAP2 DUP13 AND DUP2 MSTORE SWAP3 MSTORE SWAP1 KECCAK256 SLOAD SWAP1 PUSH2 0x6B8 JUMP JUMPDEST PUSH2 0x57C DUP3 DUP3 PUSH2 0x9FB JUMP JUMPDEST POP POP JUMP JUMPDEST PUSH2 0x48F DUP4 DUP4 DUP4 PUSH2 0x71D JUMP JUMPDEST PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB AND PUSH1 0x0 SWAP1 DUP2 MSTORE PUSH1 0x20 DUP2 SWAP1 MSTORE PUSH1 0x40 SWAP1 KECCAK256 SLOAD SWAP1 JUMP JUMPDEST PUSH1 0x4 DUP1 SLOAD PUSH1 0x40 DUP1 MLOAD PUSH1 0x20 PUSH1 0x1F PUSH1 0x2 PUSH1 0x0 NOT PUSH2 0x100 PUSH1 0x1 DUP9 AND ISZERO MUL ADD SWAP1 SWAP6 AND SWAP5 SWAP1 SWAP5 DIV SWAP4 DUP5 ADD DUP2 SWAP1 DIV DUP2 MUL DUP3 ADD DUP2 ADD SWAP1 SWAP3 MSTORE DUP3 DUP2 MSTORE PUSH1 0x60 SWAP4 SWAP1 SWAP3 SWAP1 SWAP2 DUP4 ADD DUP3 DUP3 DUP1 ISZERO PUSH2 0x457 JUMPI DUP1 PUSH1 0x1F LT PUSH2 0x42C JUMPI PUSH2 0x100 DUP1 DUP4 SLOAD DIV MUL DUP4 MSTORE SWAP2 PUSH1 0x20 ADD SWAP2 PUSH2 0x457 JUMP JUMPDEST PUSH2 0x57C DUP3 DUP3 PUSH2 0xAEB JUMP JUMPDEST PUSH1 0x0 PUSH2 0x475 PUSH2 0x61E PUSH2 0x719 JUMP JUMPDEST DUP5 PUSH2 0x50C DUP6 PUSH1 0x40 MLOAD DUP1 PUSH1 0x60 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x25 DUP2 MSTORE PUSH1 0x20 ADD PUSH2 0xD49 PUSH1 0x25 SWAP2 CODECOPY PUSH1 0x1 PUSH1 0x0 PUSH2 0x648 PUSH2 0x719 JUMP JUMPDEST PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB SWAP1 DUP2 AND DUP3 MSTORE PUSH1 0x20 DUP1 DUP4 ADD SWAP4 SWAP1 SWAP4 MSTORE PUSH1 0x40 SWAP2 DUP3 ADD PUSH1 0x0 SWAP1 DUP2 KECCAK256 SWAP2 DUP14 AND DUP2 MSTORE SWAP3 MSTORE SWAP1 KECCAK256 SLOAD SWAP2 SWAP1 PUSH2 0x964 JUMP JUMPDEST PUSH1 0x0 PUSH2 0x475 PUSH2 0x686 PUSH2 0x719 JUMP JUMPDEST DUP5 DUP5 PUSH2 0x809 JUMP JUMPDEST PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB SWAP2 DUP3 AND PUSH1 0x0 SWAP1 DUP2 MSTORE PUSH1 0x1 PUSH1 0x20 SWAP1 DUP2 MSTORE PUSH1 0x40 DUP1 DUP4 KECCAK256 SWAP4 SWAP1 SWAP5 AND DUP3 MSTORE SWAP2 SWAP1 SWAP2 MSTORE KECCAK256 SLOAD SWAP1 JUMP JUMPDEST PUSH1 0x0 DUP3 DUP3 ADD DUP4 DUP2 LT ISZERO PUSH2 0x712 JUMPI PUSH1 0x40 DUP1 MLOAD PUSH3 0x461BCD PUSH1 0xE5 SHL DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD MSTORE PUSH1 0x1B PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x536166654D6174683A206164646974696F6E206F766572666C6F770000000000 PUSH1 0x44 DUP3 ADD MSTORE SWAP1 MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x64 ADD SWAP1 REVERT JUMPDEST SWAP4 SWAP3 POP POP POP JUMP JUMPDEST CALLER SWAP1 JUMP JUMPDEST PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB DUP4 AND PUSH2 0x762 JUMPI PUSH1 0x40 MLOAD PUSH3 0x461BCD PUSH1 0xE5 SHL DUP2 MSTORE PUSH1 0x4 ADD DUP1 DUP1 PUSH1 0x20 ADD DUP3 DUP2 SUB DUP3 MSTORE PUSH1 0x24 DUP2 MSTORE PUSH1 0x20 ADD DUP1 PUSH2 0xD25 PUSH1 0x24 SWAP2 CODECOPY PUSH1 0x40 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 REVERT JUMPDEST PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB DUP3 AND PUSH2 0x7A7 JUMPI PUSH1 0x40 MLOAD PUSH3 0x461BCD PUSH1 0xE5 SHL DUP2 MSTORE PUSH1 0x4 ADD DUP1 DUP1 PUSH1 0x20 ADD DUP3 DUP2 SUB DUP3 MSTORE PUSH1 0x22 DUP2 MSTORE PUSH1 0x20 ADD DUP1 PUSH2 0xC6F PUSH1 0x22 SWAP2 CODECOPY PUSH1 0x40 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 REVERT JUMPDEST PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB DUP1 DUP5 AND PUSH1 0x0 DUP2 DUP2 MSTORE PUSH1 0x1 PUSH1 0x20 SWAP1 DUP2 MSTORE PUSH1 0x40 DUP1 DUP4 KECCAK256 SWAP5 DUP8 AND DUP1 DUP5 MSTORE SWAP5 DUP3 MSTORE SWAP2 DUP3 SWAP1 KECCAK256 DUP6 SWAP1 SSTORE DUP2 MLOAD DUP6 DUP2 MSTORE SWAP2 MLOAD PUSH32 0x8C5BE1E5EBEC7D5BD14F71427D1E84F3DD0314C0F7B2291E5B200AC8C7C3B925 SWAP3 DUP2 SWAP1 SUB SWAP1 SWAP2 ADD SWAP1 LOG3 POP POP POP JUMP JUMPDEST PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB DUP4 AND PUSH2 0x84E JUMPI PUSH1 0x40 MLOAD PUSH3 0x461BCD PUSH1 0xE5 SHL DUP2 MSTORE PUSH1 0x4 ADD DUP1 DUP1 PUSH1 0x20 ADD DUP3 DUP2 SUB DUP3 MSTORE PUSH1 0x25 DUP2 MSTORE PUSH1 0x20 ADD DUP1 PUSH2 0xD00 PUSH1 0x25 SWAP2 CODECOPY PUSH1 0x40 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 REVERT JUMPDEST PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB DUP3 AND PUSH2 0x893 JUMPI PUSH1 0x40 MLOAD PUSH3 0x461BCD PUSH1 0xE5 SHL DUP2 MSTORE PUSH1 0x4 ADD DUP1 DUP1 PUSH1 0x20 ADD DUP3 DUP2 SUB DUP3 MSTORE PUSH1 0x23 DUP2 MSTORE PUSH1 0x20 ADD DUP1 PUSH2 0xC2A PUSH1 0x23 SWAP2 CODECOPY PUSH1 0x40 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 REVERT JUMPDEST PUSH2 0x89E DUP4 DUP4 DUP4 PUSH2 0x48F JUMP JUMPDEST PUSH2 0x8DB DUP2 PUSH1 0x40 MLOAD DUP1 PUSH1 0x60 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x26 DUP2 MSTORE PUSH1 0x20 ADD PUSH2 0xC91 PUSH1 0x26 SWAP2 CODECOPY PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB DUP7 AND PUSH1 0x0 SWAP1 DUP2 MSTORE PUSH1 0x20 DUP2 SWAP1 MSTORE PUSH1 0x40 SWAP1 KECCAK256 SLOAD SWAP2 SWAP1 PUSH2 0x964 JUMP JUMPDEST PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB DUP1 DUP6 AND PUSH1 0x0 SWAP1 DUP2 MSTORE PUSH1 0x20 DUP2 SWAP1 MSTORE PUSH1 0x40 DUP1 DUP3 KECCAK256 SWAP4 SWAP1 SWAP4 SSTORE SWAP1 DUP5 AND DUP2 MSTORE KECCAK256 SLOAD PUSH2 0x90A SWAP1 DUP3 PUSH2 0x6B8 JUMP JUMPDEST PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB DUP1 DUP5 AND PUSH1 0x0 DUP2 DUP2 MSTORE PUSH1 0x20 DUP2 DUP2 MSTORE PUSH1 0x40 SWAP2 DUP3 SWAP1 KECCAK256 SWAP5 SWAP1 SWAP5 SSTORE DUP1 MLOAD DUP6 DUP2 MSTORE SWAP1 MLOAD SWAP2 SWAP4 SWAP3 DUP8 AND SWAP3 PUSH32 0xDDF252AD1BE2C89B69C2B068FC378DAA952BA7F163C4A11628F55A4DF523B3EF SWAP3 SWAP2 DUP3 SWAP1 SUB ADD SWAP1 LOG3 POP POP POP JUMP JUMPDEST PUSH1 0x0 DUP2 DUP5 DUP5 GT ISZERO PUSH2 0x9F3 JUMPI PUSH1 0x40 MLOAD PUSH3 0x461BCD PUSH1 0xE5 SHL DUP2 MSTORE PUSH1 0x4 ADD DUP1 DUP1 PUSH1 0x20 ADD DUP3 DUP2 SUB DUP3 MSTORE DUP4 DUP2 DUP2 MLOAD DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 PUSH1 0x0 JUMPDEST DUP4 DUP2 LT ISZERO PUSH2 0x9B8 JUMPI DUP2 DUP2 ADD MLOAD DUP4 DUP3 ADD MSTORE PUSH1 0x20 ADD PUSH2 0x9A0 JUMP JUMPDEST POP POP POP POP SWAP1 POP SWAP1 DUP2 ADD SWAP1 PUSH1 0x1F AND DUP1 ISZERO PUSH2 0x9E5 JUMPI DUP1 DUP3 SUB DUP1 MLOAD PUSH1 0x1 DUP4 PUSH1 0x20 SUB PUSH2 0x100 EXP SUB NOT AND DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP JUMPDEST POP SWAP3 POP POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 REVERT JUMPDEST POP POP POP SWAP1 SUB SWAP1 JUMP JUMPDEST PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB DUP3 AND PUSH2 0xA56 JUMPI PUSH1 0x40 DUP1 MLOAD PUSH3 0x461BCD PUSH1 0xE5 SHL DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD MSTORE PUSH1 0x1F PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x45524332303A206D696E7420746F20746865207A65726F206164647265737300 PUSH1 0x44 DUP3 ADD MSTORE SWAP1 MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x64 ADD SWAP1 REVERT JUMPDEST PUSH2 0xA62 PUSH1 0x0 DUP4 DUP4 PUSH2 0x48F JUMP JUMPDEST PUSH1 0x2 SLOAD PUSH2 0xA6F SWAP1 DUP3 PUSH2 0x6B8 JUMP JUMPDEST PUSH1 0x2 SSTORE PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB DUP3 AND PUSH1 0x0 SWAP1 DUP2 MSTORE PUSH1 0x20 DUP2 SWAP1 MSTORE PUSH1 0x40 SWAP1 KECCAK256 SLOAD PUSH2 0xA95 SWAP1 DUP3 PUSH2 0x6B8 JUMP JUMPDEST PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB DUP4 AND PUSH1 0x0 DUP2 DUP2 MSTORE PUSH1 0x20 DUP2 DUP2 MSTORE PUSH1 0x40 DUP1 DUP4 KECCAK256 SWAP5 SWAP1 SWAP5 SSTORE DUP4 MLOAD DUP6 DUP2 MSTORE SWAP4 MLOAD SWAP3 SWAP4 SWAP2 SWAP3 PUSH32 0xDDF252AD1BE2C89B69C2B068FC378DAA952BA7F163C4A11628F55A4DF523B3EF SWAP3 DUP2 SWAP1 SUB SWAP1 SWAP2 ADD SWAP1 LOG3 POP POP JUMP JUMPDEST PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB DUP3 AND PUSH2 0xB30 JUMPI PUSH1 0x40 MLOAD PUSH3 0x461BCD PUSH1 0xE5 SHL DUP2 MSTORE PUSH1 0x4 ADD DUP1 DUP1 PUSH1 0x20 ADD DUP3 DUP2 SUB DUP3 MSTORE PUSH1 0x21 DUP2 MSTORE PUSH1 0x20 ADD DUP1 PUSH2 0xCDF PUSH1 0x21 SWAP2 CODECOPY PUSH1 0x40 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 REVERT JUMPDEST PUSH2 0xB3C DUP3 PUSH1 0x0 DUP4 PUSH2 0x48F JUMP JUMPDEST PUSH2 0xB79 DUP2 PUSH1 0x40 MLOAD DUP1 PUSH1 0x60 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x22 DUP2 MSTORE PUSH1 0x20 ADD PUSH2 0xC4D PUSH1 0x22 SWAP2 CODECOPY PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB DUP6 AND PUSH1 0x0 SWAP1 DUP2 MSTORE PUSH1 0x20 DUP2 SWAP1 MSTORE PUSH1 0x40 SWAP1 KECCAK256 SLOAD SWAP2 SWAP1 PUSH2 0x964 JUMP JUMPDEST PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB DUP4 AND PUSH1 0x0 SWAP1 DUP2 MSTORE PUSH1 0x20 DUP2 SWAP1 MSTORE PUSH1 0x40 SWAP1 KECCAK256 SSTORE PUSH1 0x2 SLOAD PUSH2 0xB9F SWAP1 DUP3 PUSH2 0xBE7 JUMP JUMPDEST PUSH1 0x2 SSTORE PUSH1 0x40 DUP1 MLOAD DUP3 DUP2 MSTORE SWAP1 MLOAD PUSH1 0x0 SWAP2 PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB DUP6 AND SWAP2 PUSH32 0xDDF252AD1BE2C89B69C2B068FC378DAA952BA7F163C4A11628F55A4DF523B3EF SWAP2 DUP2 SWAP1 SUB PUSH1 0x20 ADD SWAP1 LOG3 POP POP JUMP JUMPDEST PUSH1 0x0 PUSH2 0x712 DUP4 DUP4 PUSH1 0x40 MLOAD DUP1 PUSH1 0x40 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x1E DUP2 MSTORE PUSH1 0x20 ADD PUSH32 0x536166654D6174683A207375627472616374696F6E206F766572666C6F770000 DUP2 MSTORE POP PUSH2 0x964 JUMP INVALID GASLIMIT MSTORE NUMBER ORIGIN ADDRESS GASPRICE KECCAK256 PUSH21 0x72616E7366657220746F20746865207A65726F2061 PUSH5 0x6472657373 GASLIMIT MSTORE NUMBER ORIGIN ADDRESS GASPRICE KECCAK256 PUSH3 0x75726E KECCAK256 PUSH2 0x6D6F PUSH22 0x6E7420657863656564732062616C616E636545524332 ADDRESS GASPRICE KECCAK256 PUSH2 0x7070 PUSH19 0x6F766520746F20746865207A65726F20616464 PUSH19 0x65737345524332303A207472616E7366657220 PUSH2 0x6D6F PUSH22 0x6E7420657863656564732062616C616E636545524332 ADDRESS GASPRICE KECCAK256 PUSH21 0x72616E7366657220616D6F756E7420657863656564 PUSH20 0x20616C6C6F77616E636545524332303A20627572 PUSH15 0x2066726F6D20746865207A65726F20 PUSH2 0x6464 PUSH19 0x65737345524332303A207472616E7366657220 PUSH7 0x726F6D20746865 KECCAK256 PUSH27 0x65726F206164647265737345524332303A20617070726F76652066 PUSH19 0x6F6D20746865207A65726F2061646472657373 GASLIMIT MSTORE NUMBER ORIGIN ADDRESS GASPRICE KECCAK256 PUSH5 0x6563726561 PUSH20 0x656420616C6C6F77616E63652062656C6F77207A PUSH6 0x726FA2646970 PUSH7 0x735822122025EB MUL SHR 0xE 0xD7 PUSH32 0x150FA57486A8A5859AA0BD55F4A7E710B5E08119B2C079293964736F6C634300 MOD 0xC STOP CALLER \",\n  \"pcMap\": {\n    \"0\": {\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"6\",\n      \"value\": \"0x80\"\n    },\n    \"2\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"6\",\n      \"value\": \"0x40\"\n    },\n    \"4\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"6\"\n    },\n    \"5\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"CALLVALUE\",\n      \"path\": \"6\"\n    },\n    \"6\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"6\"\n    },\n    \"7\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"ISZERO\",\n      \"path\": \"6\"\n    },\n    \"8\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"6\",\n      \"value\": \"0x10\"\n    },\n    \"11\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"6\"\n    },\n    \"12\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"6\",\n      \"value\": \"0x0\"\n    },\n    \"14\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"6\"\n    },\n    \"15\": {\n      \"dev\": \"Cannot send ether to nonpayable function\",\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"REVERT\",\n      \"path\": \"6\"\n    },\n    \"16\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"6\"\n    },\n    \"17\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"POP\",\n      \"path\": \"6\"\n    },\n    \"18\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"6\",\n      \"value\": \"0x4\"\n    },\n    \"20\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"CALLDATASIZE\",\n      \"path\": \"6\"\n    },\n    \"21\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"LT\",\n      \"path\": \"6\"\n    },\n    \"22\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"6\",\n      \"value\": \"0xF5\"\n    },\n    \"25\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"6\"\n    },\n    \"26\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"6\",\n      \"value\": \"0x0\"\n    },\n    \"28\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"CALLDATALOAD\",\n      \"path\": \"6\"\n    },\n    \"29\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"6\",\n      \"value\": \"0xE0\"\n    },\n    \"31\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"SHR\",\n      \"path\": \"6\"\n    },\n    \"32\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"6\"\n    },\n    \"33\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"PUSH4\",\n      \"path\": \"6\",\n      \"value\": \"0x40C10F19\"\n    },\n    \"38\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"GT\",\n      \"path\": \"6\"\n    },\n    \"39\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"6\",\n      \"value\": \"0x97\"\n    },\n    \"42\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"6\"\n    },\n    \"43\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"6\"\n    },\n    \"44\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"PUSH4\",\n      \"path\": \"6\",\n      \"value\": \"0x9DC29FAC\"\n    },\n    \"49\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"GT\",\n      \"path\": \"6\"\n    },\n    \"50\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"6\",\n      \"value\": \"0x66\"\n    },\n    \"53\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"6\"\n    },\n    \"54\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"6\"\n    },\n    \"55\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"PUSH4\",\n      \"path\": \"6\",\n      \"value\": \"0x9DC29FAC\"\n    },\n    \"60\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"EQ\",\n      \"path\": \"6\"\n    },\n    \"61\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"6\",\n      \"value\": \"0x319\"\n    },\n    \"64\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"6\"\n    },\n    \"65\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"6\"\n    },\n    \"66\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"PUSH4\",\n      \"path\": \"6\",\n      \"value\": \"0xA457C2D7\"\n    },\n    \"71\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"EQ\",\n      \"path\": \"6\"\n    },\n    \"72\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"6\",\n      \"value\": \"0x345\"\n    },\n    \"75\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"6\"\n    },\n    \"76\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"6\"\n    },\n    \"77\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"PUSH4\",\n      \"path\": \"6\",\n      \"value\": \"0xA9059CBB\"\n    },\n    \"82\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"EQ\",\n      \"path\": \"6\"\n    },\n    \"83\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"6\",\n      \"value\": \"0x371\"\n    },\n    \"86\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"6\"\n    },\n    \"87\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"6\"\n    },\n    \"88\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"PUSH4\",\n      \"path\": \"6\",\n      \"value\": \"0xDD62ED3E\"\n    },\n    \"93\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"EQ\",\n      \"path\": \"6\"\n    },\n    \"94\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"6\",\n      \"value\": \"0x39D\"\n    },\n    \"97\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"6\"\n    },\n    \"98\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"6\",\n      \"value\": \"0xF5\"\n    },\n    \"101\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"6\"\n    },\n    \"102\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"6\"\n    },\n    \"103\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"6\"\n    },\n    \"104\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"PUSH4\",\n      \"path\": \"6\",\n      \"value\": \"0x40C10F19\"\n    },\n    \"109\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"EQ\",\n      \"path\": \"6\"\n    },\n    \"110\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"6\",\n      \"value\": \"0x289\"\n    },\n    \"113\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"6\"\n    },\n    \"114\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"6\"\n    },\n    \"115\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"PUSH4\",\n      \"path\": \"6\",\n      \"value\": \"0x56189CB4\"\n    },\n    \"120\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"EQ\",\n      \"path\": \"6\"\n    },\n    \"121\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"6\",\n      \"value\": \"0x2B5\"\n    },\n    \"124\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"6\"\n    },\n    \"125\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"6\"\n    },\n    \"126\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"PUSH4\",\n      \"path\": \"6\",\n      \"value\": \"0x70A08231\"\n    },\n    \"131\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"EQ\",\n      \"path\": \"6\"\n    },\n    \"132\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"6\",\n      \"value\": \"0x2EB\"\n    },\n    \"135\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"6\"\n    },\n    \"136\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"6\"\n    },\n    \"137\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"PUSH4\",\n      \"path\": \"6\",\n      \"value\": \"0x95D89B41\"\n    },\n    \"142\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"EQ\",\n      \"path\": \"6\"\n    },\n    \"143\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"6\",\n      \"value\": \"0x311\"\n    },\n    \"146\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"6\"\n    },\n    \"147\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"6\",\n      \"value\": \"0xF5\"\n    },\n    \"150\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"6\"\n    },\n    \"151\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"6\"\n    },\n    \"152\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"6\"\n    },\n    \"153\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"PUSH4\",\n      \"path\": \"6\",\n      \"value\": \"0x222F5BE0\"\n    },\n    \"158\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"GT\",\n      \"path\": \"6\"\n    },\n    \"159\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"6\",\n      \"value\": \"0xD3\"\n    },\n    \"162\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"6\"\n    },\n    \"163\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"6\"\n    },\n    \"164\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"PUSH4\",\n      \"path\": \"6\",\n      \"value\": \"0x222F5BE0\"\n    },\n    \"169\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"EQ\",\n      \"path\": \"6\"\n    },\n    \"170\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"6\",\n      \"value\": \"0x1D1\"\n    },\n    \"173\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"6\"\n    },\n    \"174\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"6\"\n    },\n    \"175\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"PUSH4\",\n      \"path\": \"6\",\n      \"value\": \"0x23B872DD\"\n    },\n    \"180\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"EQ\",\n      \"path\": \"6\"\n    },\n    \"181\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"6\",\n      \"value\": \"0x209\"\n    },\n    \"184\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"6\"\n    },\n    \"185\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"6\"\n    },\n    \"186\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"PUSH4\",\n      \"path\": \"6\",\n      \"value\": \"0x313CE567\"\n    },\n    \"191\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"EQ\",\n      \"path\": \"6\"\n    },\n    \"192\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"6\",\n      \"value\": \"0x23F\"\n    },\n    \"195\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"6\"\n    },\n    \"196\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"6\"\n    },\n    \"197\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"PUSH4\",\n      \"path\": \"6\",\n      \"value\": \"0x39509351\"\n    },\n    \"202\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"EQ\",\n      \"path\": \"6\"\n    },\n    \"203\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"6\",\n      \"value\": \"0x25D\"\n    },\n    \"206\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"6\"\n    },\n    \"207\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"6\",\n      \"value\": \"0xF5\"\n    },\n    \"210\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"6\"\n    },\n    \"211\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"6\"\n    },\n    \"212\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"6\"\n    },\n    \"213\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"PUSH4\",\n      \"path\": \"6\",\n      \"value\": \"0x6FDDE03\"\n    },\n    \"218\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"EQ\",\n      \"path\": \"6\"\n    },\n    \"219\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"6\",\n      \"value\": \"0xFA\"\n    },\n    \"222\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"6\"\n    },\n    \"223\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"6\"\n    },\n    \"224\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"PUSH4\",\n      \"path\": \"6\",\n      \"value\": \"0x95EA7B3\"\n    },\n    \"229\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"EQ\",\n      \"path\": \"6\"\n    },\n    \"230\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"6\",\n      \"value\": \"0x177\"\n    },\n    \"233\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"6\"\n    },\n    \"234\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"6\"\n    },\n    \"235\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"PUSH4\",\n      \"path\": \"6\",\n      \"value\": \"0x18160DDD\"\n    },\n    \"240\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"EQ\",\n      \"path\": \"6\"\n    },\n    \"241\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"6\",\n      \"value\": \"0x1B7\"\n    },\n    \"244\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"6\"\n    },\n    \"245\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"6\"\n    },\n    \"246\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"6\",\n      \"value\": \"0x0\"\n    },\n    \"248\": {\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"6\"\n    },\n    \"249\": {\n      \"first_revert\": true,\n      \"fn\": null,\n      \"offset\": [\n        872,\n        1180\n      ],\n      \"op\": \"REVERT\",\n      \"path\": \"6\"\n    },\n    \"250\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"3\"\n    },\n    \"251\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x102\"\n    },\n    \"254\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x3CB\"\n    },\n    \"257\": {\n      \"fn\": \"ERC20.name\",\n      \"jump\": \"i\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"3\"\n    },\n    \"258\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"3\"\n    },\n    \"259\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x40\"\n    },\n    \"261\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"262\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"3\"\n    },\n    \"263\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x20\"\n    },\n    \"265\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"266\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"3\"\n    },\n    \"267\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"268\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"DUP4\",\n      \"path\": \"3\"\n    },\n    \"269\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"3\"\n    },\n    \"270\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"271\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"DUP4\",\n      \"path\": \"3\"\n    },\n    \"272\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"273\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"274\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"DUP4\",\n      \"path\": \"3\"\n    },\n    \"275\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"3\"\n    },\n    \"276\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"3\"\n    },\n    \"277\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"SWAP3\",\n      \"path\": \"3\"\n    },\n    \"278\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"DUP4\",\n      \"path\": \"3\"\n    },\n    \"279\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"SWAP3\",\n      \"path\": \"3\"\n    },\n    \"280\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"281\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"DUP4\",\n      \"path\": \"3\"\n    },\n    \"282\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"283\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"3\"\n    },\n    \"284\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"DUP6\",\n      \"path\": \"3\"\n    },\n    \"285\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"286\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"287\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"288\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"DUP4\",\n      \"path\": \"3\"\n    },\n    \"289\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"DUP4\",\n      \"path\": \"3\"\n    },\n    \"290\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x0\"\n    },\n    \"292\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"3\"\n    },\n    \"293\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"DUP4\",\n      \"path\": \"3\"\n    },\n    \"294\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"295\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"LT\",\n      \"path\": \"3\"\n    },\n    \"296\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"ISZERO\",\n      \"path\": \"3\"\n    },\n    \"297\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x13C\"\n    },\n    \"300\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"3\"\n    },\n    \"301\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"302\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"303\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"304\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"3\"\n    },\n    \"305\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"DUP4\",\n      \"path\": \"3\"\n    },\n    \"306\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"3\"\n    },\n    \"307\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"308\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"309\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x20\"\n    },\n    \"311\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"312\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x124\"\n    },\n    \"315\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"3\"\n    },\n    \"316\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"3\"\n    },\n    \"317\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"POP\",\n      \"path\": \"3\"\n    },\n    \"318\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"POP\",\n      \"path\": \"3\"\n    },\n    \"319\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"POP\",\n      \"path\": \"3\"\n    },\n    \"320\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"POP\",\n      \"path\": \"3\"\n    },\n    \"321\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"322\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"POP\",\n      \"path\": \"3\"\n    },\n    \"323\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"324\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"325\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"326\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"327\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x1F\"\n    },\n    \"329\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"AND\",\n      \"path\": \"3\"\n    },\n    \"330\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"331\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"ISZERO\",\n      \"path\": \"3\"\n    },\n    \"332\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x169\"\n    },\n    \"335\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"3\"\n    },\n    \"336\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"337\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"3\"\n    },\n    \"338\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"SUB\",\n      \"path\": \"3\"\n    },\n    \"339\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"340\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"3\"\n    },\n    \"341\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x1\"\n    },\n    \"343\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"DUP4\",\n      \"path\": \"3\"\n    },\n    \"344\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x20\"\n    },\n    \"346\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"SUB\",\n      \"path\": \"3\"\n    },\n    \"347\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x100\"\n    },\n    \"350\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"EXP\",\n      \"path\": \"3\"\n    },\n    \"351\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"SUB\",\n      \"path\": \"3\"\n    },\n    \"352\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"NOT\",\n      \"path\": \"3\"\n    },\n    \"353\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"AND\",\n      \"path\": \"3\"\n    },\n    \"354\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"355\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"356\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x20\"\n    },\n    \"358\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"359\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"3\"\n    },\n    \"360\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"POP\",\n      \"path\": \"3\"\n    },\n    \"361\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"3\"\n    },\n    \"362\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"POP\",\n      \"path\": \"3\"\n    },\n    \"363\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"SWAP3\",\n      \"path\": \"3\"\n    },\n    \"364\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"POP\",\n      \"path\": \"3\"\n    },\n    \"365\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"POP\",\n      \"path\": \"3\"\n    },\n    \"366\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"POP\",\n      \"path\": \"3\"\n    },\n    \"367\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x40\"\n    },\n    \"369\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"3\"\n    },\n    \"370\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"371\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"3\"\n    },\n    \"372\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"SUB\",\n      \"path\": \"3\"\n    },\n    \"373\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"374\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"RETURN\",\n      \"path\": \"3\"\n    },\n    \"375\": {\n      \"fn\": \"ERC20.approve\",\n      \"offset\": [\n        4240,\n        4406\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"3\"\n    },\n    \"376\": {\n      \"fn\": \"ERC20.approve\",\n      \"offset\": [\n        4240,\n        4406\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x1A3\"\n    },\n    \"379\": {\n      \"fn\": \"ERC20.approve\",\n      \"offset\": [\n        4240,\n        4406\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x4\"\n    },\n    \"381\": {\n      \"fn\": \"ERC20.approve\",\n      \"offset\": [\n        4240,\n        4406\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"382\": {\n      \"fn\": \"ERC20.approve\",\n      \"offset\": [\n        4240,\n        4406\n      ],\n      \"op\": \"CALLDATASIZE\",\n      \"path\": \"3\"\n    },\n    \"383\": {\n      \"fn\": \"ERC20.approve\",\n      \"offset\": [\n        4240,\n        4406\n      ],\n      \"op\": \"SUB\",\n      \"path\": \"3\"\n    },\n    \"384\": {\n      \"fn\": \"ERC20.approve\",\n      \"offset\": [\n        4240,\n        4406\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x40\"\n    },\n    \"386\": {\n      \"fn\": \"ERC20.approve\",\n      \"offset\": [\n        4240,\n        4406\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"387\": {\n      \"fn\": \"ERC20.approve\",\n      \"offset\": [\n        4240,\n        4406\n      ],\n      \"op\": \"LT\",\n      \"path\": \"3\"\n    },\n    \"388\": {\n      \"fn\": \"ERC20.approve\",\n      \"offset\": [\n        4240,\n        4406\n      ],\n      \"op\": \"ISZERO\",\n      \"path\": \"3\"\n    },\n    \"389\": {\n      \"fn\": \"ERC20.approve\",\n      \"offset\": [\n        4240,\n        4406\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x18D\"\n    },\n    \"392\": {\n      \"fn\": \"ERC20.approve\",\n      \"offset\": [\n        4240,\n        4406\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"3\"\n    },\n    \"393\": {\n      \"fn\": \"ERC20.approve\",\n      \"offset\": [\n        4240,\n        4406\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x0\"\n    },\n    \"395\": {\n      \"fn\": \"ERC20.approve\",\n      \"offset\": [\n        4240,\n        4406\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"396\": {\n      \"fn\": \"ERC20.approve\",\n      \"offset\": [\n        4240,\n        4406\n      ],\n      \"op\": \"REVERT\",\n      \"path\": \"3\"\n    },\n    \"397\": {\n      \"fn\": \"ERC20.approve\",\n      \"offset\": [\n        4240,\n        4406\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"3\"\n    },\n    \"398\": {\n      \"op\": \"POP\"\n    },\n    \"399\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"401\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"403\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0xA0\"\n    },\n    \"405\": {\n      \"op\": \"SHL\"\n    },\n    \"406\": {\n      \"op\": \"SUB\"\n    },\n    \"407\": {\n      \"fn\": \"ERC20.approve\",\n      \"offset\": [\n        4240,\n        4406\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"408\": {\n      \"fn\": \"ERC20.approve\",\n      \"offset\": [\n        4240,\n        4406\n      ],\n      \"op\": \"CALLDATALOAD\",\n      \"path\": \"3\"\n    },\n    \"409\": {\n      \"fn\": \"ERC20.approve\",\n      \"offset\": [\n        4240,\n        4406\n      ],\n      \"op\": \"AND\",\n      \"path\": \"3\"\n    },\n    \"410\": {\n      \"fn\": \"ERC20.approve\",\n      \"offset\": [\n        4240,\n        4406\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"411\": {\n      \"fn\": \"ERC20.approve\",\n      \"offset\": [\n        4240,\n        4406\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x20\"\n    },\n    \"413\": {\n      \"fn\": \"ERC20.approve\",\n      \"offset\": [\n        4240,\n        4406\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"414\": {\n      \"fn\": \"ERC20.approve\",\n      \"offset\": [\n        4240,\n        4406\n      ],\n      \"op\": \"CALLDATALOAD\",\n      \"path\": \"3\"\n    },\n    \"415\": {\n      \"fn\": \"ERC20.approve\",\n      \"offset\": [\n        4240,\n        4406\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x461\"\n    },\n    \"418\": {\n      \"fn\": \"ERC20.approve\",\n      \"jump\": \"i\",\n      \"offset\": [\n        4240,\n        4406\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"3\"\n    },\n    \"419\": {\n      \"fn\": \"ERC20.approve\",\n      \"offset\": [\n        4240,\n        4406\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"3\"\n    },\n    \"420\": {\n      \"fn\": \"ERC20.approve\",\n      \"offset\": [\n        4240,\n        4406\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x40\"\n    },\n    \"422\": {\n      \"fn\": \"ERC20.approve\",\n      \"offset\": [\n        4240,\n        4406\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"423\": {\n      \"fn\": \"ERC20.approve\",\n      \"offset\": [\n        4240,\n        4406\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"3\"\n    },\n    \"424\": {\n      \"fn\": \"ERC20.approve\",\n      \"offset\": [\n        4240,\n        4406\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"3\"\n    },\n    \"425\": {\n      \"fn\": \"ERC20.approve\",\n      \"offset\": [\n        4240,\n        4406\n      ],\n      \"op\": \"ISZERO\",\n      \"path\": \"3\"\n    },\n    \"426\": {\n      \"fn\": \"ERC20.approve\",\n      \"offset\": [\n        4240,\n        4406\n      ],\n      \"op\": \"ISZERO\",\n      \"path\": \"3\"\n    },\n    \"427\": {\n      \"fn\": \"ERC20.approve\",\n      \"offset\": [\n        4240,\n        4406\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"3\"\n    },\n    \"428\": {\n      \"fn\": \"ERC20.approve\",\n      \"offset\": [\n        4240,\n        4406\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"429\": {\n      \"fn\": \"ERC20.approve\",\n      \"offset\": [\n        4240,\n        4406\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"3\"\n    },\n    \"430\": {\n      \"fn\": \"ERC20.approve\",\n      \"offset\": [\n        4240,\n        4406\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"431\": {\n      \"fn\": \"ERC20.approve\",\n      \"offset\": [\n        4240,\n        4406\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"432\": {\n      \"fn\": \"ERC20.approve\",\n      \"offset\": [\n        4240,\n        4406\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"433\": {\n      \"fn\": \"ERC20.approve\",\n      \"offset\": [\n        4240,\n        4406\n      ],\n      \"op\": \"SUB\",\n      \"path\": \"3\"\n    },\n    \"434\": {\n      \"fn\": \"ERC20.approve\",\n      \"offset\": [\n        4240,\n        4406\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x20\"\n    },\n    \"436\": {\n      \"fn\": \"ERC20.approve\",\n      \"offset\": [\n        4240,\n        4406\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"437\": {\n      \"fn\": \"ERC20.approve\",\n      \"offset\": [\n        4240,\n        4406\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"438\": {\n      \"fn\": \"ERC20.approve\",\n      \"offset\": [\n        4240,\n        4406\n      ],\n      \"op\": \"RETURN\",\n      \"path\": \"3\"\n    },\n    \"439\": {\n      \"fn\": \"ERC20.totalSupply\",\n      \"offset\": [\n        3247,\n        3345\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"3\"\n    },\n    \"440\": {\n      \"fn\": \"ERC20.totalSupply\",\n      \"offset\": [\n        3247,\n        3345\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x1BF\"\n    },\n    \"443\": {\n      \"fn\": \"ERC20.totalSupply\",\n      \"offset\": [\n        3247,\n        3345\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x47E\"\n    },\n    \"446\": {\n      \"fn\": \"ERC20.totalSupply\",\n      \"jump\": \"i\",\n      \"offset\": [\n        3247,\n        3345\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"3\"\n    },\n    \"447\": {\n      \"fn\": \"ERC20.totalSupply\",\n      \"offset\": [\n        3247,\n        3345\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"3\"\n    },\n    \"448\": {\n      \"fn\": \"ERC20.totalSupply\",\n      \"offset\": [\n        3247,\n        3345\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x40\"\n    },\n    \"450\": {\n      \"fn\": \"ERC20.totalSupply\",\n      \"offset\": [\n        3247,\n        3345\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"451\": {\n      \"fn\": \"ERC20.totalSupply\",\n      \"offset\": [\n        3247,\n        3345\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"3\"\n    },\n    \"452\": {\n      \"fn\": \"ERC20.totalSupply\",\n      \"offset\": [\n        3247,\n        3345\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"3\"\n    },\n    \"453\": {\n      \"fn\": \"ERC20.totalSupply\",\n      \"offset\": [\n        3247,\n        3345\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"3\"\n    },\n    \"454\": {\n      \"fn\": \"ERC20.totalSupply\",\n      \"offset\": [\n        3247,\n        3345\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"455\": {\n      \"fn\": \"ERC20.totalSupply\",\n      \"offset\": [\n        3247,\n        3345\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"3\"\n    },\n    \"456\": {\n      \"fn\": \"ERC20.totalSupply\",\n      \"offset\": [\n        3247,\n        3345\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"457\": {\n      \"fn\": \"ERC20.totalSupply\",\n      \"offset\": [\n        3247,\n        3345\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"458\": {\n      \"fn\": \"ERC20.totalSupply\",\n      \"offset\": [\n        3247,\n        3345\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"459\": {\n      \"fn\": \"ERC20.totalSupply\",\n      \"offset\": [\n        3247,\n        3345\n      ],\n      \"op\": \"SUB\",\n      \"path\": \"3\"\n    },\n    \"460\": {\n      \"fn\": \"ERC20.totalSupply\",\n      \"offset\": [\n        3247,\n        3345\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x20\"\n    },\n    \"462\": {\n      \"fn\": \"ERC20.totalSupply\",\n      \"offset\": [\n        3247,\n        3345\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"463\": {\n      \"fn\": \"ERC20.totalSupply\",\n      \"offset\": [\n        3247,\n        3345\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"464\": {\n      \"fn\": \"ERC20.totalSupply\",\n      \"offset\": [\n        3247,\n        3345\n      ],\n      \"op\": \"RETURN\",\n      \"path\": \"3\"\n    },\n    \"465\": {\n      \"fn\": \"ERC20Mock.transferInternal\",\n      \"offset\": [\n        575,\n        692\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"4\"\n    },\n    \"466\": {\n      \"fn\": \"ERC20Mock.transferInternal\",\n      \"offset\": [\n        575,\n        692\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"4\",\n      \"value\": \"0x207\"\n    },\n    \"469\": {\n      \"fn\": \"ERC20Mock.transferInternal\",\n      \"offset\": [\n        575,\n        692\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"4\",\n      \"value\": \"0x4\"\n    },\n    \"471\": {\n      \"fn\": \"ERC20Mock.transferInternal\",\n      \"offset\": [\n        575,\n        692\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"4\"\n    },\n    \"472\": {\n      \"fn\": \"ERC20Mock.transferInternal\",\n      \"offset\": [\n        575,\n        692\n      ],\n      \"op\": \"CALLDATASIZE\",\n      \"path\": \"4\"\n    },\n    \"473\": {\n      \"fn\": \"ERC20Mock.transferInternal\",\n      \"offset\": [\n        575,\n        692\n      ],\n      \"op\": \"SUB\",\n      \"path\": \"4\"\n    },\n    \"474\": {\n      \"fn\": \"ERC20Mock.transferInternal\",\n      \"offset\": [\n        575,\n        692\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"4\",\n      \"value\": \"0x60\"\n    },\n    \"476\": {\n      \"fn\": \"ERC20Mock.transferInternal\",\n      \"offset\": [\n        575,\n        692\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"4\"\n    },\n    \"477\": {\n      \"fn\": \"ERC20Mock.transferInternal\",\n      \"offset\": [\n        575,\n        692\n      ],\n      \"op\": \"LT\",\n      \"path\": \"4\"\n    },\n    \"478\": {\n      \"fn\": \"ERC20Mock.transferInternal\",\n      \"offset\": [\n        575,\n        692\n      ],\n      \"op\": \"ISZERO\",\n      \"path\": \"4\"\n    },\n    \"479\": {\n      \"fn\": \"ERC20Mock.transferInternal\",\n      \"offset\": [\n        575,\n        692\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"4\",\n      \"value\": \"0x1E7\"\n    },\n    \"482\": {\n      \"fn\": \"ERC20Mock.transferInternal\",\n      \"offset\": [\n        575,\n        692\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"4\"\n    },\n    \"483\": {\n      \"fn\": \"ERC20Mock.transferInternal\",\n      \"offset\": [\n        575,\n        692\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"4\",\n      \"value\": \"0x0\"\n    },\n    \"485\": {\n      \"fn\": \"ERC20Mock.transferInternal\",\n      \"offset\": [\n        575,\n        692\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"4\"\n    },\n    \"486\": {\n      \"fn\": \"ERC20Mock.transferInternal\",\n      \"offset\": [\n        575,\n        692\n      ],\n      \"op\": \"REVERT\",\n      \"path\": \"4\"\n    },\n    \"487\": {\n      \"fn\": \"ERC20Mock.transferInternal\",\n      \"offset\": [\n        575,\n        692\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"4\"\n    },\n    \"488\": {\n      \"op\": \"POP\"\n    },\n    \"489\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"491\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"493\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0xA0\"\n    },\n    \"495\": {\n      \"op\": \"SHL\"\n    },\n    \"496\": {\n      \"op\": \"SUB\"\n    },\n    \"497\": {\n      \"fn\": \"ERC20Mock.transferInternal\",\n      \"offset\": [\n        575,\n        692\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"4\"\n    },\n    \"498\": {\n      \"fn\": \"ERC20Mock.transferInternal\",\n      \"offset\": [\n        575,\n        692\n      ],\n      \"op\": \"CALLDATALOAD\",\n      \"path\": \"4\"\n    },\n    \"499\": {\n      \"fn\": \"ERC20Mock.transferInternal\",\n      \"offset\": [\n        575,\n        692\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"4\"\n    },\n    \"500\": {\n      \"fn\": \"ERC20Mock.transferInternal\",\n      \"offset\": [\n        575,\n        692\n      ],\n      \"op\": \"AND\",\n      \"path\": \"4\"\n    },\n    \"501\": {\n      \"fn\": \"ERC20Mock.transferInternal\",\n      \"offset\": [\n        575,\n        692\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"4\"\n    },\n    \"502\": {\n      \"fn\": \"ERC20Mock.transferInternal\",\n      \"offset\": [\n        575,\n        692\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"4\",\n      \"value\": \"0x20\"\n    },\n    \"504\": {\n      \"fn\": \"ERC20Mock.transferInternal\",\n      \"offset\": [\n        575,\n        692\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"4\"\n    },\n    \"505\": {\n      \"fn\": \"ERC20Mock.transferInternal\",\n      \"offset\": [\n        575,\n        692\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"4\"\n    },\n    \"506\": {\n      \"fn\": \"ERC20Mock.transferInternal\",\n      \"offset\": [\n        575,\n        692\n      ],\n      \"op\": \"CALLDATALOAD\",\n      \"path\": \"4\"\n    },\n    \"507\": {\n      \"fn\": \"ERC20Mock.transferInternal\",\n      \"offset\": [\n        575,\n        692\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"4\"\n    },\n    \"508\": {\n      \"fn\": \"ERC20Mock.transferInternal\",\n      \"offset\": [\n        575,\n        692\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"4\"\n    },\n    \"509\": {\n      \"fn\": \"ERC20Mock.transferInternal\",\n      \"offset\": [\n        575,\n        692\n      ],\n      \"op\": \"AND\",\n      \"path\": \"4\"\n    },\n    \"510\": {\n      \"fn\": \"ERC20Mock.transferInternal\",\n      \"offset\": [\n        575,\n        692\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"4\"\n    },\n    \"511\": {\n      \"fn\": \"ERC20Mock.transferInternal\",\n      \"offset\": [\n        575,\n        692\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"4\",\n      \"value\": \"0x40\"\n    },\n    \"513\": {\n      \"fn\": \"ERC20Mock.transferInternal\",\n      \"offset\": [\n        575,\n        692\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"4\"\n    },\n    \"514\": {\n      \"fn\": \"ERC20Mock.transferInternal\",\n      \"offset\": [\n        575,\n        692\n      ],\n      \"op\": \"CALLDATALOAD\",\n      \"path\": \"4\"\n    },\n    \"515\": {\n      \"fn\": \"ERC20Mock.transferInternal\",\n      \"offset\": [\n        575,\n        692\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"4\",\n      \"value\": \"0x484\"\n    },\n    \"518\": {\n      \"fn\": \"ERC20Mock.transferInternal\",\n      \"jump\": \"i\",\n      \"offset\": [\n        575,\n        692\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"4\"\n    },\n    \"519\": {\n      \"fn\": \"ERC20Mock.transferInternal\",\n      \"offset\": [\n        575,\n        692\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"4\"\n    },\n    \"520\": {\n      \"fn\": \"ERC20Mock.transferInternal\",\n      \"offset\": [\n        575,\n        692\n      ],\n      \"op\": \"STOP\",\n      \"path\": \"4\"\n    },\n    \"521\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        4866,\n        5183\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"3\"\n    },\n    \"522\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        4866,\n        5183\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x1A3\"\n    },\n    \"525\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        4866,\n        5183\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x4\"\n    },\n    \"527\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        4866,\n        5183\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"528\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        4866,\n        5183\n      ],\n      \"op\": \"CALLDATASIZE\",\n      \"path\": \"3\"\n    },\n    \"529\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        4866,\n        5183\n      ],\n      \"op\": \"SUB\",\n      \"path\": \"3\"\n    },\n    \"530\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        4866,\n        5183\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x60\"\n    },\n    \"532\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        4866,\n        5183\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"533\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        4866,\n        5183\n      ],\n      \"op\": \"LT\",\n      \"path\": \"3\"\n    },\n    \"534\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        4866,\n        5183\n      ],\n      \"op\": \"ISZERO\",\n      \"path\": \"3\"\n    },\n    \"535\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        4866,\n        5183\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x21F\"\n    },\n    \"538\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        4866,\n        5183\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"3\"\n    },\n    \"539\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        4866,\n        5183\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x0\"\n    },\n    \"541\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        4866,\n        5183\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"542\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        4866,\n        5183\n      ],\n      \"op\": \"REVERT\",\n      \"path\": \"3\"\n    },\n    \"543\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        4866,\n        5183\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"3\"\n    },\n    \"544\": {\n      \"op\": \"POP\"\n    },\n    \"545\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"547\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"549\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0xA0\"\n    },\n    \"551\": {\n      \"op\": \"SHL\"\n    },\n    \"552\": {\n      \"op\": \"SUB\"\n    },\n    \"553\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        4866,\n        5183\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"554\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        4866,\n        5183\n      ],\n      \"op\": \"CALLDATALOAD\",\n      \"path\": \"3\"\n    },\n    \"555\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        4866,\n        5183\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"556\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        4866,\n        5183\n      ],\n      \"op\": \"AND\",\n      \"path\": \"3\"\n    },\n    \"557\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        4866,\n        5183\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"3\"\n    },\n    \"558\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        4866,\n        5183\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x20\"\n    },\n    \"560\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        4866,\n        5183\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"561\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        4866,\n        5183\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"562\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        4866,\n        5183\n      ],\n      \"op\": \"CALLDATALOAD\",\n      \"path\": \"3\"\n    },\n    \"563\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        4866,\n        5183\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"564\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        4866,\n        5183\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"3\"\n    },\n    \"565\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        4866,\n        5183\n      ],\n      \"op\": \"AND\",\n      \"path\": \"3\"\n    },\n    \"566\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        4866,\n        5183\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"567\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        4866,\n        5183\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x40\"\n    },\n    \"569\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        4866,\n        5183\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"570\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        4866,\n        5183\n      ],\n      \"op\": \"CALLDATALOAD\",\n      \"path\": \"3\"\n    },\n    \"571\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        4866,\n        5183\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x494\"\n    },\n    \"574\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"jump\": \"i\",\n      \"offset\": [\n        4866,\n        5183\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"3\"\n    },\n    \"575\": {\n      \"fn\": \"ERC20.decimals\",\n      \"offset\": [\n        3106,\n        3187\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"3\"\n    },\n    \"576\": {\n      \"fn\": \"ERC20.decimals\",\n      \"offset\": [\n        3106,\n        3187\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x247\"\n    },\n    \"579\": {\n      \"fn\": \"ERC20.decimals\",\n      \"offset\": [\n        3106,\n        3187\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x51B\"\n    },\n    \"582\": {\n      \"fn\": \"ERC20.decimals\",\n      \"jump\": \"i\",\n      \"offset\": [\n        3106,\n        3187\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"3\"\n    },\n    \"583\": {\n      \"fn\": \"ERC20.decimals\",\n      \"offset\": [\n        3106,\n        3187\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"3\"\n    },\n    \"584\": {\n      \"fn\": \"ERC20.decimals\",\n      \"offset\": [\n        3106,\n        3187\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x40\"\n    },\n    \"586\": {\n      \"fn\": \"ERC20.decimals\",\n      \"offset\": [\n        3106,\n        3187\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"587\": {\n      \"fn\": \"ERC20.decimals\",\n      \"offset\": [\n        3106,\n        3187\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"3\"\n    },\n    \"588\": {\n      \"fn\": \"ERC20.decimals\",\n      \"offset\": [\n        3106,\n        3187\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0xFF\"\n    },\n    \"590\": {\n      \"fn\": \"ERC20.decimals\",\n      \"offset\": [\n        3106,\n        3187\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"591\": {\n      \"fn\": \"ERC20.decimals\",\n      \"offset\": [\n        3106,\n        3187\n      ],\n      \"op\": \"SWAP3\",\n      \"path\": \"3\"\n    },\n    \"592\": {\n      \"fn\": \"ERC20.decimals\",\n      \"offset\": [\n        3106,\n        3187\n      ],\n      \"op\": \"AND\",\n      \"path\": \"3\"\n    },\n    \"593\": {\n      \"fn\": \"ERC20.decimals\",\n      \"offset\": [\n        3106,\n        3187\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"3\"\n    },\n    \"594\": {\n      \"fn\": \"ERC20.decimals\",\n      \"offset\": [\n        3106,\n        3187\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"595\": {\n      \"fn\": \"ERC20.decimals\",\n      \"offset\": [\n        3106,\n        3187\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"3\"\n    },\n    \"596\": {\n      \"fn\": \"ERC20.decimals\",\n      \"offset\": [\n        3106,\n        3187\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"597\": {\n      \"fn\": \"ERC20.decimals\",\n      \"offset\": [\n        3106,\n        3187\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"598\": {\n      \"fn\": \"ERC20.decimals\",\n      \"offset\": [\n        3106,\n        3187\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"599\": {\n      \"fn\": \"ERC20.decimals\",\n      \"offset\": [\n        3106,\n        3187\n      ],\n      \"op\": \"SUB\",\n      \"path\": \"3\"\n    },\n    \"600\": {\n      \"fn\": \"ERC20.decimals\",\n      \"offset\": [\n        3106,\n        3187\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x20\"\n    },\n    \"602\": {\n      \"fn\": \"ERC20.decimals\",\n      \"offset\": [\n        3106,\n        3187\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"603\": {\n      \"fn\": \"ERC20.decimals\",\n      \"offset\": [\n        3106,\n        3187\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"604\": {\n      \"fn\": \"ERC20.decimals\",\n      \"offset\": [\n        3106,\n        3187\n      ],\n      \"op\": \"RETURN\",\n      \"path\": \"3\"\n    },\n    \"605\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"offset\": [\n        5578,\n        5793\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"3\"\n    },\n    \"606\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"offset\": [\n        5578,\n        5793\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x1A3\"\n    },\n    \"609\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"offset\": [\n        5578,\n        5793\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x4\"\n    },\n    \"611\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"offset\": [\n        5578,\n        5793\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"612\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"offset\": [\n        5578,\n        5793\n      ],\n      \"op\": \"CALLDATASIZE\",\n      \"path\": \"3\"\n    },\n    \"613\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"offset\": [\n        5578,\n        5793\n      ],\n      \"op\": \"SUB\",\n      \"path\": \"3\"\n    },\n    \"614\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"offset\": [\n        5578,\n        5793\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x40\"\n    },\n    \"616\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"offset\": [\n        5578,\n        5793\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"617\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"offset\": [\n        5578,\n        5793\n      ],\n      \"op\": \"LT\",\n      \"path\": \"3\"\n    },\n    \"618\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"offset\": [\n        5578,\n        5793\n      ],\n      \"op\": \"ISZERO\",\n      \"path\": \"3\"\n    },\n    \"619\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"offset\": [\n        5578,\n        5793\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x273\"\n    },\n    \"622\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"offset\": [\n        5578,\n        5793\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"3\"\n    },\n    \"623\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"offset\": [\n        5578,\n        5793\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x0\"\n    },\n    \"625\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"offset\": [\n        5578,\n        5793\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"626\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"offset\": [\n        5578,\n        5793\n      ],\n      \"op\": \"REVERT\",\n      \"path\": \"3\"\n    },\n    \"627\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"offset\": [\n        5578,\n        5793\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"3\"\n    },\n    \"628\": {\n      \"op\": \"POP\"\n    },\n    \"629\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"631\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"633\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0xA0\"\n    },\n    \"635\": {\n      \"op\": \"SHL\"\n    },\n    \"636\": {\n      \"op\": \"SUB\"\n    },\n    \"637\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"offset\": [\n        5578,\n        5793\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"638\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"offset\": [\n        5578,\n        5793\n      ],\n      \"op\": \"CALLDATALOAD\",\n      \"path\": \"3\"\n    },\n    \"639\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"offset\": [\n        5578,\n        5793\n      ],\n      \"op\": \"AND\",\n      \"path\": \"3\"\n    },\n    \"640\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"offset\": [\n        5578,\n        5793\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"641\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"offset\": [\n        5578,\n        5793\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x20\"\n    },\n    \"643\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"offset\": [\n        5578,\n        5793\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"644\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"offset\": [\n        5578,\n        5793\n      ],\n      \"op\": \"CALLDATALOAD\",\n      \"path\": \"3\"\n    },\n    \"645\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"offset\": [\n        5578,\n        5793\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x524\"\n    },\n    \"648\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"jump\": \"i\",\n      \"offset\": [\n        5578,\n        5793\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"3\"\n    },\n    \"649\": {\n      \"fn\": \"ERC20Mock.mint\",\n      \"offset\": [\n        377,\n        470\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"4\"\n    },\n    \"650\": {\n      \"fn\": \"ERC20Mock.mint\",\n      \"offset\": [\n        377,\n        470\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"4\",\n      \"value\": \"0x207\"\n    },\n    \"653\": {\n      \"fn\": \"ERC20Mock.mint\",\n      \"offset\": [\n        377,\n        470\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"4\",\n      \"value\": \"0x4\"\n    },\n    \"655\": {\n      \"fn\": \"ERC20Mock.mint\",\n      \"offset\": [\n        377,\n        470\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"4\"\n    },\n    \"656\": {\n      \"fn\": \"ERC20Mock.mint\",\n      \"offset\": [\n        377,\n        470\n      ],\n      \"op\": \"CALLDATASIZE\",\n      \"path\": \"4\"\n    },\n    \"657\": {\n      \"fn\": \"ERC20Mock.mint\",\n      \"offset\": [\n        377,\n        470\n      ],\n      \"op\": \"SUB\",\n      \"path\": \"4\"\n    },\n    \"658\": {\n      \"fn\": \"ERC20Mock.mint\",\n      \"offset\": [\n        377,\n        470\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"4\",\n      \"value\": \"0x40\"\n    },\n    \"660\": {\n      \"fn\": \"ERC20Mock.mint\",\n      \"offset\": [\n        377,\n        470\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"4\"\n    },\n    \"661\": {\n      \"fn\": \"ERC20Mock.mint\",\n      \"offset\": [\n        377,\n        470\n      ],\n      \"op\": \"LT\",\n      \"path\": \"4\"\n    },\n    \"662\": {\n      \"fn\": \"ERC20Mock.mint\",\n      \"offset\": [\n        377,\n        470\n      ],\n      \"op\": \"ISZERO\",\n      \"path\": \"4\"\n    },\n    \"663\": {\n      \"fn\": \"ERC20Mock.mint\",\n      \"offset\": [\n        377,\n        470\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"4\",\n      \"value\": \"0x29F\"\n    },\n    \"666\": {\n      \"fn\": \"ERC20Mock.mint\",\n      \"offset\": [\n        377,\n        470\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"4\"\n    },\n    \"667\": {\n      \"fn\": \"ERC20Mock.mint\",\n      \"offset\": [\n        377,\n        470\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"4\",\n      \"value\": \"0x0\"\n    },\n    \"669\": {\n      \"fn\": \"ERC20Mock.mint\",\n      \"offset\": [\n        377,\n        470\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"4\"\n    },\n    \"670\": {\n      \"fn\": \"ERC20Mock.mint\",\n      \"offset\": [\n        377,\n        470\n      ],\n      \"op\": \"REVERT\",\n      \"path\": \"4\"\n    },\n    \"671\": {\n      \"fn\": \"ERC20Mock.mint\",\n      \"offset\": [\n        377,\n        470\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"4\"\n    },\n    \"672\": {\n      \"op\": \"POP\"\n    },\n    \"673\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"675\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"677\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0xA0\"\n    },\n    \"679\": {\n      \"op\": \"SHL\"\n    },\n    \"680\": {\n      \"op\": \"SUB\"\n    },\n    \"681\": {\n      \"fn\": \"ERC20Mock.mint\",\n      \"offset\": [\n        377,\n        470\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"4\"\n    },\n    \"682\": {\n      \"fn\": \"ERC20Mock.mint\",\n      \"offset\": [\n        377,\n        470\n      ],\n      \"op\": \"CALLDATALOAD\",\n      \"path\": \"4\"\n    },\n    \"683\": {\n      \"fn\": \"ERC20Mock.mint\",\n      \"offset\": [\n        377,\n        470\n      ],\n      \"op\": \"AND\",\n      \"path\": \"4\"\n    },\n    \"684\": {\n      \"fn\": \"ERC20Mock.mint\",\n      \"offset\": [\n        377,\n        470\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"4\"\n    },\n    \"685\": {\n      \"fn\": \"ERC20Mock.mint\",\n      \"offset\": [\n        377,\n        470\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"4\",\n      \"value\": \"0x20\"\n    },\n    \"687\": {\n      \"fn\": \"ERC20Mock.mint\",\n      \"offset\": [\n        377,\n        470\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"4\"\n    },\n    \"688\": {\n      \"fn\": \"ERC20Mock.mint\",\n      \"offset\": [\n        377,\n        470\n      ],\n      \"op\": \"CALLDATALOAD\",\n      \"path\": \"4\"\n    },\n    \"689\": {\n      \"fn\": \"ERC20Mock.mint\",\n      \"offset\": [\n        377,\n        470\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"4\",\n      \"value\": \"0x572\"\n    },\n    \"692\": {\n      \"fn\": \"ERC20Mock.mint\",\n      \"jump\": \"i\",\n      \"offset\": [\n        377,\n        470\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"4\"\n    },\n    \"693\": {\n      \"fn\": \"ERC20Mock.approveInternal\",\n      \"offset\": [\n        698,\n        825\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"4\"\n    },\n    \"694\": {\n      \"fn\": \"ERC20Mock.approveInternal\",\n      \"offset\": [\n        698,\n        825\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"4\",\n      \"value\": \"0x207\"\n    },\n    \"697\": {\n      \"fn\": \"ERC20Mock.approveInternal\",\n      \"offset\": [\n        698,\n        825\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"4\",\n      \"value\": \"0x4\"\n    },\n    \"699\": {\n      \"fn\": \"ERC20Mock.approveInternal\",\n      \"offset\": [\n        698,\n        825\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"4\"\n    },\n    \"700\": {\n      \"fn\": \"ERC20Mock.approveInternal\",\n      \"offset\": [\n        698,\n        825\n      ],\n      \"op\": \"CALLDATASIZE\",\n      \"path\": \"4\"\n    },\n    \"701\": {\n      \"fn\": \"ERC20Mock.approveInternal\",\n      \"offset\": [\n        698,\n        825\n      ],\n      \"op\": \"SUB\",\n      \"path\": \"4\"\n    },\n    \"702\": {\n      \"fn\": \"ERC20Mock.approveInternal\",\n      \"offset\": [\n        698,\n        825\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"4\",\n      \"value\": \"0x60\"\n    },\n    \"704\": {\n      \"fn\": \"ERC20Mock.approveInternal\",\n      \"offset\": [\n        698,\n        825\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"4\"\n    },\n    \"705\": {\n      \"fn\": \"ERC20Mock.approveInternal\",\n      \"offset\": [\n        698,\n        825\n      ],\n      \"op\": \"LT\",\n      \"path\": \"4\"\n    },\n    \"706\": {\n      \"fn\": \"ERC20Mock.approveInternal\",\n      \"offset\": [\n        698,\n        825\n      ],\n      \"op\": \"ISZERO\",\n      \"path\": \"4\"\n    },\n    \"707\": {\n      \"fn\": \"ERC20Mock.approveInternal\",\n      \"offset\": [\n        698,\n        825\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"4\",\n      \"value\": \"0x2CB\"\n    },\n    \"710\": {\n      \"fn\": \"ERC20Mock.approveInternal\",\n      \"offset\": [\n        698,\n        825\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"4\"\n    },\n    \"711\": {\n      \"fn\": \"ERC20Mock.approveInternal\",\n      \"offset\": [\n        698,\n        825\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"4\",\n      \"value\": \"0x0\"\n    },\n    \"713\": {\n      \"fn\": \"ERC20Mock.approveInternal\",\n      \"offset\": [\n        698,\n        825\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"4\"\n    },\n    \"714\": {\n      \"fn\": \"ERC20Mock.approveInternal\",\n      \"offset\": [\n        698,\n        825\n      ],\n      \"op\": \"REVERT\",\n      \"path\": \"4\"\n    },\n    \"715\": {\n      \"fn\": \"ERC20Mock.approveInternal\",\n      \"offset\": [\n        698,\n        825\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"4\"\n    },\n    \"716\": {\n      \"op\": \"POP\"\n    },\n    \"717\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"719\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"721\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0xA0\"\n    },\n    \"723\": {\n      \"op\": \"SHL\"\n    },\n    \"724\": {\n      \"op\": \"SUB\"\n    },\n    \"725\": {\n      \"fn\": \"ERC20Mock.approveInternal\",\n      \"offset\": [\n        698,\n        825\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"4\"\n    },\n    \"726\": {\n      \"fn\": \"ERC20Mock.approveInternal\",\n      \"offset\": [\n        698,\n        825\n      ],\n      \"op\": \"CALLDATALOAD\",\n      \"path\": \"4\"\n    },\n    \"727\": {\n      \"fn\": \"ERC20Mock.approveInternal\",\n      \"offset\": [\n        698,\n        825\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"4\"\n    },\n    \"728\": {\n      \"fn\": \"ERC20Mock.approveInternal\",\n      \"offset\": [\n        698,\n        825\n      ],\n      \"op\": \"AND\",\n      \"path\": \"4\"\n    },\n    \"729\": {\n      \"fn\": \"ERC20Mock.approveInternal\",\n      \"offset\": [\n        698,\n        825\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"4\"\n    },\n    \"730\": {\n      \"fn\": \"ERC20Mock.approveInternal\",\n      \"offset\": [\n        698,\n        825\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"4\",\n      \"value\": \"0x20\"\n    },\n    \"732\": {\n      \"fn\": \"ERC20Mock.approveInternal\",\n      \"offset\": [\n        698,\n        825\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"4\"\n    },\n    \"733\": {\n      \"fn\": \"ERC20Mock.approveInternal\",\n      \"offset\": [\n        698,\n        825\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"4\"\n    },\n    \"734\": {\n      \"fn\": \"ERC20Mock.approveInternal\",\n      \"offset\": [\n        698,\n        825\n      ],\n      \"op\": \"CALLDATALOAD\",\n      \"path\": \"4\"\n    },\n    \"735\": {\n      \"fn\": \"ERC20Mock.approveInternal\",\n      \"offset\": [\n        698,\n        825\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"4\"\n    },\n    \"736\": {\n      \"fn\": \"ERC20Mock.approveInternal\",\n      \"offset\": [\n        698,\n        825\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"4\"\n    },\n    \"737\": {\n      \"fn\": \"ERC20Mock.approveInternal\",\n      \"offset\": [\n        698,\n        825\n      ],\n      \"op\": \"AND\",\n      \"path\": \"4\"\n    },\n    \"738\": {\n      \"fn\": \"ERC20Mock.approveInternal\",\n      \"offset\": [\n        698,\n        825\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"4\"\n    },\n    \"739\": {\n      \"fn\": \"ERC20Mock.approveInternal\",\n      \"offset\": [\n        698,\n        825\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"4\",\n      \"value\": \"0x40\"\n    },\n    \"741\": {\n      \"fn\": \"ERC20Mock.approveInternal\",\n      \"offset\": [\n        698,\n        825\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"4\"\n    },\n    \"742\": {\n      \"fn\": \"ERC20Mock.approveInternal\",\n      \"offset\": [\n        698,\n        825\n      ],\n      \"op\": \"CALLDATALOAD\",\n      \"path\": \"4\"\n    },\n    \"743\": {\n      \"fn\": \"ERC20Mock.approveInternal\",\n      \"offset\": [\n        698,\n        825\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"4\",\n      \"value\": \"0x580\"\n    },\n    \"746\": {\n      \"fn\": \"ERC20Mock.approveInternal\",\n      \"jump\": \"i\",\n      \"offset\": [\n        698,\n        825\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"4\"\n    },\n    \"747\": {\n      \"fn\": \"ERC20.balanceOf\",\n      \"offset\": [\n        3403,\n        3520\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"3\"\n    },\n    \"748\": {\n      \"fn\": \"ERC20.balanceOf\",\n      \"offset\": [\n        3403,\n        3520\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x1BF\"\n    },\n    \"751\": {\n      \"fn\": \"ERC20.balanceOf\",\n      \"offset\": [\n        3403,\n        3520\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x4\"\n    },\n    \"753\": {\n      \"fn\": \"ERC20.balanceOf\",\n      \"offset\": [\n        3403,\n        3520\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"754\": {\n      \"fn\": \"ERC20.balanceOf\",\n      \"offset\": [\n        3403,\n        3520\n      ],\n      \"op\": \"CALLDATASIZE\",\n      \"path\": \"3\"\n    },\n    \"755\": {\n      \"fn\": \"ERC20.balanceOf\",\n      \"offset\": [\n        3403,\n        3520\n      ],\n      \"op\": \"SUB\",\n      \"path\": \"3\"\n    },\n    \"756\": {\n      \"fn\": \"ERC20.balanceOf\",\n      \"offset\": [\n        3403,\n        3520\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x20\"\n    },\n    \"758\": {\n      \"fn\": \"ERC20.balanceOf\",\n      \"offset\": [\n        3403,\n        3520\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"759\": {\n      \"fn\": \"ERC20.balanceOf\",\n      \"offset\": [\n        3403,\n        3520\n      ],\n      \"op\": \"LT\",\n      \"path\": \"3\"\n    },\n    \"760\": {\n      \"fn\": \"ERC20.balanceOf\",\n      \"offset\": [\n        3403,\n        3520\n      ],\n      \"op\": \"ISZERO\",\n      \"path\": \"3\"\n    },\n    \"761\": {\n      \"fn\": \"ERC20.balanceOf\",\n      \"offset\": [\n        3403,\n        3520\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x301\"\n    },\n    \"764\": {\n      \"fn\": \"ERC20.balanceOf\",\n      \"offset\": [\n        3403,\n        3520\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"3\"\n    },\n    \"765\": {\n      \"fn\": \"ERC20.balanceOf\",\n      \"offset\": [\n        3403,\n        3520\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x0\"\n    },\n    \"767\": {\n      \"fn\": \"ERC20.balanceOf\",\n      \"offset\": [\n        3403,\n        3520\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"768\": {\n      \"fn\": \"ERC20.balanceOf\",\n      \"offset\": [\n        3403,\n        3520\n      ],\n      \"op\": \"REVERT\",\n      \"path\": \"3\"\n    },\n    \"769\": {\n      \"fn\": \"ERC20.balanceOf\",\n      \"offset\": [\n        3403,\n        3520\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"3\"\n    },\n    \"770\": {\n      \"op\": \"POP\"\n    },\n    \"771\": {\n      \"fn\": \"ERC20.balanceOf\",\n      \"offset\": [\n        3403,\n        3520\n      ],\n      \"op\": \"CALLDATALOAD\",\n      \"path\": \"3\"\n    },\n    \"772\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"774\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"776\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0xA0\"\n    },\n    \"778\": {\n      \"op\": \"SHL\"\n    },\n    \"779\": {\n      \"op\": \"SUB\"\n    },\n    \"780\": {\n      \"fn\": \"ERC20.balanceOf\",\n      \"offset\": [\n        3403,\n        3520\n      ],\n      \"op\": \"AND\",\n      \"path\": \"3\"\n    },\n    \"781\": {\n      \"fn\": \"ERC20.balanceOf\",\n      \"offset\": [\n        3403,\n        3520\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x58B\"\n    },\n    \"784\": {\n      \"fn\": \"ERC20.balanceOf\",\n      \"jump\": \"i\",\n      \"offset\": [\n        3403,\n        3520\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"3\"\n    },\n    \"785\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2398,\n        2483\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"3\"\n    },\n    \"786\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2398,\n        2483\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x102\"\n    },\n    \"789\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2398,\n        2483\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x5A6\"\n    },\n    \"792\": {\n      \"fn\": \"ERC20.symbol\",\n      \"jump\": \"i\",\n      \"offset\": [\n        2398,\n        2483\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"3\"\n    },\n    \"793\": {\n      \"fn\": \"ERC20Mock.burn\",\n      \"offset\": [\n        476,\n        569\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"4\"\n    },\n    \"794\": {\n      \"fn\": \"ERC20Mock.burn\",\n      \"offset\": [\n        476,\n        569\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"4\",\n      \"value\": \"0x207\"\n    },\n    \"797\": {\n      \"fn\": \"ERC20Mock.burn\",\n      \"offset\": [\n        476,\n        569\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"4\",\n      \"value\": \"0x4\"\n    },\n    \"799\": {\n      \"fn\": \"ERC20Mock.burn\",\n      \"offset\": [\n        476,\n        569\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"4\"\n    },\n    \"800\": {\n      \"fn\": \"ERC20Mock.burn\",\n      \"offset\": [\n        476,\n        569\n      ],\n      \"op\": \"CALLDATASIZE\",\n      \"path\": \"4\"\n    },\n    \"801\": {\n      \"fn\": \"ERC20Mock.burn\",\n      \"offset\": [\n        476,\n        569\n      ],\n      \"op\": \"SUB\",\n      \"path\": \"4\"\n    },\n    \"802\": {\n      \"fn\": \"ERC20Mock.burn\",\n      \"offset\": [\n        476,\n        569\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"4\",\n      \"value\": \"0x40\"\n    },\n    \"804\": {\n      \"fn\": \"ERC20Mock.burn\",\n      \"offset\": [\n        476,\n        569\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"4\"\n    },\n    \"805\": {\n      \"fn\": \"ERC20Mock.burn\",\n      \"offset\": [\n        476,\n        569\n      ],\n      \"op\": \"LT\",\n      \"path\": \"4\"\n    },\n    \"806\": {\n      \"fn\": \"ERC20Mock.burn\",\n      \"offset\": [\n        476,\n        569\n      ],\n      \"op\": \"ISZERO\",\n      \"path\": \"4\"\n    },\n    \"807\": {\n      \"fn\": \"ERC20Mock.burn\",\n      \"offset\": [\n        476,\n        569\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"4\",\n      \"value\": \"0x32F\"\n    },\n    \"810\": {\n      \"fn\": \"ERC20Mock.burn\",\n      \"offset\": [\n        476,\n        569\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"4\"\n    },\n    \"811\": {\n      \"fn\": \"ERC20Mock.burn\",\n      \"offset\": [\n        476,\n        569\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"4\",\n      \"value\": \"0x0\"\n    },\n    \"813\": {\n      \"fn\": \"ERC20Mock.burn\",\n      \"offset\": [\n        476,\n        569\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"4\"\n    },\n    \"814\": {\n      \"fn\": \"ERC20Mock.burn\",\n      \"offset\": [\n        476,\n        569\n      ],\n      \"op\": \"REVERT\",\n      \"path\": \"4\"\n    },\n    \"815\": {\n      \"fn\": \"ERC20Mock.burn\",\n      \"offset\": [\n        476,\n        569\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"4\"\n    },\n    \"816\": {\n      \"op\": \"POP\"\n    },\n    \"817\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"819\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"821\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0xA0\"\n    },\n    \"823\": {\n      \"op\": \"SHL\"\n    },\n    \"824\": {\n      \"op\": \"SUB\"\n    },\n    \"825\": {\n      \"fn\": \"ERC20Mock.burn\",\n      \"offset\": [\n        476,\n        569\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"4\"\n    },\n    \"826\": {\n      \"fn\": \"ERC20Mock.burn\",\n      \"offset\": [\n        476,\n        569\n      ],\n      \"op\": \"CALLDATALOAD\",\n      \"path\": \"4\"\n    },\n    \"827\": {\n      \"fn\": \"ERC20Mock.burn\",\n      \"offset\": [\n        476,\n        569\n      ],\n      \"op\": \"AND\",\n      \"path\": \"4\"\n    },\n    \"828\": {\n      \"fn\": \"ERC20Mock.burn\",\n      \"offset\": [\n        476,\n        569\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"4\"\n    },\n    \"829\": {\n      \"fn\": \"ERC20Mock.burn\",\n      \"offset\": [\n        476,\n        569\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"4\",\n      \"value\": \"0x20\"\n    },\n    \"831\": {\n      \"fn\": \"ERC20Mock.burn\",\n      \"offset\": [\n        476,\n        569\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"4\"\n    },\n    \"832\": {\n      \"fn\": \"ERC20Mock.burn\",\n      \"offset\": [\n        476,\n        569\n      ],\n      \"op\": \"CALLDATALOAD\",\n      \"path\": \"4\"\n    },\n    \"833\": {\n      \"fn\": \"ERC20Mock.burn\",\n      \"offset\": [\n        476,\n        569\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"4\",\n      \"value\": \"0x607\"\n    },\n    \"836\": {\n      \"fn\": \"ERC20Mock.burn\",\n      \"jump\": \"i\",\n      \"offset\": [\n        476,\n        569\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"4\"\n    },\n    \"837\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6280,\n        6546\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"3\"\n    },\n    \"838\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6280,\n        6546\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x1A3\"\n    },\n    \"841\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6280,\n        6546\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x4\"\n    },\n    \"843\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6280,\n        6546\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"844\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6280,\n        6546\n      ],\n      \"op\": \"CALLDATASIZE\",\n      \"path\": \"3\"\n    },\n    \"845\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6280,\n        6546\n      ],\n      \"op\": \"SUB\",\n      \"path\": \"3\"\n    },\n    \"846\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6280,\n        6546\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x40\"\n    },\n    \"848\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6280,\n        6546\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"849\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6280,\n        6546\n      ],\n      \"op\": \"LT\",\n      \"path\": \"3\"\n    },\n    \"850\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6280,\n        6546\n      ],\n      \"op\": \"ISZERO\",\n      \"path\": \"3\"\n    },\n    \"851\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6280,\n        6546\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x35B\"\n    },\n    \"854\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6280,\n        6546\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"3\"\n    },\n    \"855\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6280,\n        6546\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x0\"\n    },\n    \"857\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6280,\n        6546\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"858\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6280,\n        6546\n      ],\n      \"op\": \"REVERT\",\n      \"path\": \"3\"\n    },\n    \"859\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6280,\n        6546\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"3\"\n    },\n    \"860\": {\n      \"op\": \"POP\"\n    },\n    \"861\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"863\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"865\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0xA0\"\n    },\n    \"867\": {\n      \"op\": \"SHL\"\n    },\n    \"868\": {\n      \"op\": \"SUB\"\n    },\n    \"869\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6280,\n        6546\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"870\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6280,\n        6546\n      ],\n      \"op\": \"CALLDATALOAD\",\n      \"path\": \"3\"\n    },\n    \"871\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6280,\n        6546\n      ],\n      \"op\": \"AND\",\n      \"path\": \"3\"\n    },\n    \"872\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6280,\n        6546\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"873\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6280,\n        6546\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x20\"\n    },\n    \"875\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6280,\n        6546\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"876\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6280,\n        6546\n      ],\n      \"op\": \"CALLDATALOAD\",\n      \"path\": \"3\"\n    },\n    \"877\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6280,\n        6546\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x611\"\n    },\n    \"880\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"jump\": \"i\",\n      \"offset\": [\n        6280,\n        6546\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"3\"\n    },\n    \"881\": {\n      \"fn\": \"ERC20.transfer\",\n      \"offset\": [\n        3723,\n        3895\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"3\"\n    },\n    \"882\": {\n      \"fn\": \"ERC20.transfer\",\n      \"offset\": [\n        3723,\n        3895\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x1A3\"\n    },\n    \"885\": {\n      \"fn\": \"ERC20.transfer\",\n      \"offset\": [\n        3723,\n        3895\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x4\"\n    },\n    \"887\": {\n      \"fn\": \"ERC20.transfer\",\n      \"offset\": [\n        3723,\n        3895\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"888\": {\n      \"fn\": \"ERC20.transfer\",\n      \"offset\": [\n        3723,\n        3895\n      ],\n      \"op\": \"CALLDATASIZE\",\n      \"path\": \"3\"\n    },\n    \"889\": {\n      \"fn\": \"ERC20.transfer\",\n      \"offset\": [\n        3723,\n        3895\n      ],\n      \"op\": \"SUB\",\n      \"path\": \"3\"\n    },\n    \"890\": {\n      \"fn\": \"ERC20.transfer\",\n      \"offset\": [\n        3723,\n        3895\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x40\"\n    },\n    \"892\": {\n      \"fn\": \"ERC20.transfer\",\n      \"offset\": [\n        3723,\n        3895\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"893\": {\n      \"fn\": \"ERC20.transfer\",\n      \"offset\": [\n        3723,\n        3895\n      ],\n      \"op\": \"LT\",\n      \"path\": \"3\"\n    },\n    \"894\": {\n      \"fn\": \"ERC20.transfer\",\n      \"offset\": [\n        3723,\n        3895\n      ],\n      \"op\": \"ISZERO\",\n      \"path\": \"3\"\n    },\n    \"895\": {\n      \"fn\": \"ERC20.transfer\",\n      \"offset\": [\n        3723,\n        3895\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x387\"\n    },\n    \"898\": {\n      \"fn\": \"ERC20.transfer\",\n      \"offset\": [\n        3723,\n        3895\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"3\"\n    },\n    \"899\": {\n      \"fn\": \"ERC20.transfer\",\n      \"offset\": [\n        3723,\n        3895\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x0\"\n    },\n    \"901\": {\n      \"fn\": \"ERC20.transfer\",\n      \"offset\": [\n        3723,\n        3895\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"902\": {\n      \"fn\": \"ERC20.transfer\",\n      \"offset\": [\n        3723,\n        3895\n      ],\n      \"op\": \"REVERT\",\n      \"path\": \"3\"\n    },\n    \"903\": {\n      \"fn\": \"ERC20.transfer\",\n      \"offset\": [\n        3723,\n        3895\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"3\"\n    },\n    \"904\": {\n      \"op\": \"POP\"\n    },\n    \"905\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"907\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"909\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0xA0\"\n    },\n    \"911\": {\n      \"op\": \"SHL\"\n    },\n    \"912\": {\n      \"op\": \"SUB\"\n    },\n    \"913\": {\n      \"fn\": \"ERC20.transfer\",\n      \"offset\": [\n        3723,\n        3895\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"914\": {\n      \"fn\": \"ERC20.transfer\",\n      \"offset\": [\n        3723,\n        3895\n      ],\n      \"op\": \"CALLDATALOAD\",\n      \"path\": \"3\"\n    },\n    \"915\": {\n      \"fn\": \"ERC20.transfer\",\n      \"offset\": [\n        3723,\n        3895\n      ],\n      \"op\": \"AND\",\n      \"path\": \"3\"\n    },\n    \"916\": {\n      \"fn\": \"ERC20.transfer\",\n      \"offset\": [\n        3723,\n        3895\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"917\": {\n      \"fn\": \"ERC20.transfer\",\n      \"offset\": [\n        3723,\n        3895\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x20\"\n    },\n    \"919\": {\n      \"fn\": \"ERC20.transfer\",\n      \"offset\": [\n        3723,\n        3895\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"920\": {\n      \"fn\": \"ERC20.transfer\",\n      \"offset\": [\n        3723,\n        3895\n      ],\n      \"op\": \"CALLDATALOAD\",\n      \"path\": \"3\"\n    },\n    \"921\": {\n      \"fn\": \"ERC20.transfer\",\n      \"offset\": [\n        3723,\n        3895\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x679\"\n    },\n    \"924\": {\n      \"fn\": \"ERC20.transfer\",\n      \"jump\": \"i\",\n      \"offset\": [\n        3723,\n        3895\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"3\"\n    },\n    \"925\": {\n      \"fn\": \"ERC20.allowance\",\n      \"offset\": [\n        3953,\n        4102\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"3\"\n    },\n    \"926\": {\n      \"fn\": \"ERC20.allowance\",\n      \"offset\": [\n        3953,\n        4102\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x1BF\"\n    },\n    \"929\": {\n      \"fn\": \"ERC20.allowance\",\n      \"offset\": [\n        3953,\n        4102\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x4\"\n    },\n    \"931\": {\n      \"fn\": \"ERC20.allowance\",\n      \"offset\": [\n        3953,\n        4102\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"932\": {\n      \"fn\": \"ERC20.allowance\",\n      \"offset\": [\n        3953,\n        4102\n      ],\n      \"op\": \"CALLDATASIZE\",\n      \"path\": \"3\"\n    },\n    \"933\": {\n      \"fn\": \"ERC20.allowance\",\n      \"offset\": [\n        3953,\n        4102\n      ],\n      \"op\": \"SUB\",\n      \"path\": \"3\"\n    },\n    \"934\": {\n      \"fn\": \"ERC20.allowance\",\n      \"offset\": [\n        3953,\n        4102\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x40\"\n    },\n    \"936\": {\n      \"fn\": \"ERC20.allowance\",\n      \"offset\": [\n        3953,\n        4102\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"937\": {\n      \"fn\": \"ERC20.allowance\",\n      \"offset\": [\n        3953,\n        4102\n      ],\n      \"op\": \"LT\",\n      \"path\": \"3\"\n    },\n    \"938\": {\n      \"fn\": \"ERC20.allowance\",\n      \"offset\": [\n        3953,\n        4102\n      ],\n      \"op\": \"ISZERO\",\n      \"path\": \"3\"\n    },\n    \"939\": {\n      \"fn\": \"ERC20.allowance\",\n      \"offset\": [\n        3953,\n        4102\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x3B3\"\n    },\n    \"942\": {\n      \"fn\": \"ERC20.allowance\",\n      \"offset\": [\n        3953,\n        4102\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"3\"\n    },\n    \"943\": {\n      \"fn\": \"ERC20.allowance\",\n      \"offset\": [\n        3953,\n        4102\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x0\"\n    },\n    \"945\": {\n      \"fn\": \"ERC20.allowance\",\n      \"offset\": [\n        3953,\n        4102\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"946\": {\n      \"fn\": \"ERC20.allowance\",\n      \"offset\": [\n        3953,\n        4102\n      ],\n      \"op\": \"REVERT\",\n      \"path\": \"3\"\n    },\n    \"947\": {\n      \"fn\": \"ERC20.allowance\",\n      \"offset\": [\n        3953,\n        4102\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"3\"\n    },\n    \"948\": {\n      \"op\": \"POP\"\n    },\n    \"949\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"951\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"953\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0xA0\"\n    },\n    \"955\": {\n      \"op\": \"SHL\"\n    },\n    \"956\": {\n      \"op\": \"SUB\"\n    },\n    \"957\": {\n      \"fn\": \"ERC20.allowance\",\n      \"offset\": [\n        3953,\n        4102\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"958\": {\n      \"fn\": \"ERC20.allowance\",\n      \"offset\": [\n        3953,\n        4102\n      ],\n      \"op\": \"CALLDATALOAD\",\n      \"path\": \"3\"\n    },\n    \"959\": {\n      \"fn\": \"ERC20.allowance\",\n      \"offset\": [\n        3953,\n        4102\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"960\": {\n      \"fn\": \"ERC20.allowance\",\n      \"offset\": [\n        3953,\n        4102\n      ],\n      \"op\": \"AND\",\n      \"path\": \"3\"\n    },\n    \"961\": {\n      \"fn\": \"ERC20.allowance\",\n      \"offset\": [\n        3953,\n        4102\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"3\"\n    },\n    \"962\": {\n      \"fn\": \"ERC20.allowance\",\n      \"offset\": [\n        3953,\n        4102\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x20\"\n    },\n    \"964\": {\n      \"fn\": \"ERC20.allowance\",\n      \"offset\": [\n        3953,\n        4102\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"965\": {\n      \"fn\": \"ERC20.allowance\",\n      \"offset\": [\n        3953,\n        4102\n      ],\n      \"op\": \"CALLDATALOAD\",\n      \"path\": \"3\"\n    },\n    \"966\": {\n      \"fn\": \"ERC20.allowance\",\n      \"offset\": [\n        3953,\n        4102\n      ],\n      \"op\": \"AND\",\n      \"path\": \"3\"\n    },\n    \"967\": {\n      \"fn\": \"ERC20.allowance\",\n      \"offset\": [\n        3953,\n        4102\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x68D\"\n    },\n    \"970\": {\n      \"fn\": \"ERC20.allowance\",\n      \"jump\": \"i\",\n      \"offset\": [\n        3953,\n        4102\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"3\"\n    },\n    \"971\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"3\"\n    },\n    \"972\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2273,\n        2278\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"statement\": 0,\n      \"value\": \"0x3\"\n    },\n    \"974\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"975\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"SLOAD\",\n      \"path\": \"3\"\n    },\n    \"976\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x40\"\n    },\n    \"978\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"979\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"3\"\n    },\n    \"980\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x20\"\n    },\n    \"982\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x1F\"\n    },\n    \"984\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x2\"\n    },\n    \"986\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x0\"\n    },\n    \"988\": {\n      \"op\": \"NOT\"\n    },\n    \"989\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x100\"\n    },\n    \"992\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x1\"\n    },\n    \"994\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"DUP9\",\n      \"path\": \"3\"\n    },\n    \"995\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"AND\",\n      \"path\": \"3\"\n    },\n    \"996\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"ISZERO\",\n      \"path\": \"3\"\n    },\n    \"997\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"MUL\",\n      \"path\": \"3\"\n    },\n    \"998\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"999\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"1000\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"SWAP6\",\n      \"path\": \"3\"\n    },\n    \"1001\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"AND\",\n      \"path\": \"3\"\n    },\n    \"1002\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"SWAP5\",\n      \"path\": \"3\"\n    },\n    \"1003\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"1004\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"SWAP5\",\n      \"path\": \"3\"\n    },\n    \"1005\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"DIV\",\n      \"path\": \"3\"\n    },\n    \"1006\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"SWAP4\",\n      \"path\": \"3\"\n    },\n    \"1007\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"DUP5\",\n      \"path\": \"3\"\n    },\n    \"1008\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"1009\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"1010\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"1011\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"DIV\",\n      \"path\": \"3\"\n    },\n    \"1012\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"1013\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"MUL\",\n      \"path\": \"3\"\n    },\n    \"1014\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"3\"\n    },\n    \"1015\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"1016\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"1017\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"1018\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"1019\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"SWAP3\",\n      \"path\": \"3\"\n    },\n    \"1020\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"1021\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"3\"\n    },\n    \"1022\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"1023\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"1024\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2241,\n        2254\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x60\"\n    },\n    \"1026\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2241,\n        2254\n      ],\n      \"op\": \"SWAP4\",\n      \"path\": \"3\"\n    },\n    \"1027\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"1028\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"SWAP3\",\n      \"path\": \"3\"\n    },\n    \"1029\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2273,\n        2278\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"1030\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2273,\n        2278\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"3\"\n    },\n    \"1031\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"DUP4\",\n      \"path\": \"3\"\n    },\n    \"1032\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"1033\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2273,\n        2278\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"3\"\n    },\n    \"1034\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"3\"\n    },\n    \"1035\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"1036\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"ISZERO\",\n      \"path\": \"3\"\n    },\n    \"1037\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x457\"\n    },\n    \"1040\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"3\"\n    },\n    \"1041\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"1042\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x1F\"\n    },\n    \"1044\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"LT\",\n      \"path\": \"3\"\n    },\n    \"1045\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x42C\"\n    },\n    \"1048\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"3\"\n    },\n    \"1049\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x100\"\n    },\n    \"1052\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"1053\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"DUP4\",\n      \"path\": \"3\"\n    },\n    \"1054\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"SLOAD\",\n      \"path\": \"3\"\n    },\n    \"1055\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"DIV\",\n      \"path\": \"3\"\n    },\n    \"1056\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"MUL\",\n      \"path\": \"3\"\n    },\n    \"1057\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"DUP4\",\n      \"path\": \"3\"\n    },\n    \"1058\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"1059\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"3\"\n    },\n    \"1060\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x20\"\n    },\n    \"1062\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"1063\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"3\"\n    },\n    \"1064\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x457\"\n    },\n    \"1067\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"3\"\n    },\n    \"1068\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"3\"\n    },\n    \"1069\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"3\"\n    },\n    \"1070\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"1071\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"3\"\n    },\n    \"1072\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"1073\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x0\"\n    },\n    \"1075\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"1076\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x20\"\n    },\n    \"1078\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x0\"\n    },\n    \"1080\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"KECCAK256\",\n      \"path\": \"3\"\n    },\n    \"1081\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"1082\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"3\"\n    },\n    \"1083\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"1084\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"SLOAD\",\n      \"path\": \"3\"\n    },\n    \"1085\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"1086\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"1087\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"1088\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x1\"\n    },\n    \"1090\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"1091\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"1092\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x20\"\n    },\n    \"1094\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"1095\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"1096\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"DUP4\",\n      \"path\": \"3\"\n    },\n    \"1097\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"GT\",\n      \"path\": \"3\"\n    },\n    \"1098\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x43A\"\n    },\n    \"1101\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"3\"\n    },\n    \"1102\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"3\"\n    },\n    \"1103\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"1104\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"SUB\",\n      \"path\": \"3\"\n    },\n    \"1105\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x1F\"\n    },\n    \"1107\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"AND\",\n      \"path\": \"3\"\n    },\n    \"1108\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"3\"\n    },\n    \"1109\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"1110\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"3\"\n    },\n    \"1111\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"3\"\n    },\n    \"1112\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"POP\",\n      \"path\": \"3\"\n    },\n    \"1113\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"POP\",\n      \"path\": \"3\"\n    },\n    \"1114\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"POP\",\n      \"path\": \"3\"\n    },\n    \"1115\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"POP\",\n      \"path\": \"3\"\n    },\n    \"1116\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"POP\",\n      \"path\": \"3\"\n    },\n    \"1117\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"1118\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2266,\n        2278\n      ],\n      \"op\": \"POP\",\n      \"path\": \"3\"\n    },\n    \"1119\": {\n      \"fn\": \"ERC20.name\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"1120\": {\n      \"fn\": \"ERC20.name\",\n      \"jump\": \"o\",\n      \"offset\": [\n        2204,\n        2285\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"3\"\n    },\n    \"1121\": {\n      \"fn\": \"ERC20.approve\",\n      \"offset\": [\n        4240,\n        4406\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"3\"\n    },\n    \"1122\": {\n      \"fn\": \"ERC20.approve\",\n      \"offset\": [\n        4323,\n        4327\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x0\"\n    },\n    \"1124\": {\n      \"fn\": \"ERC20.approve\",\n      \"offset\": [\n        4339,\n        4378\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"statement\": 1,\n      \"value\": \"0x475\"\n    },\n    \"1127\": {\n      \"fn\": \"ERC20.approve\",\n      \"offset\": [\n        4348,\n        4360\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x46E\"\n    },\n    \"1130\": {\n      \"fn\": \"ERC20.approve\",\n      \"offset\": [\n        4348,\n        4358\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x719\"\n    },\n    \"1133\": {\n      \"fn\": \"ERC20.approve\",\n      \"jump\": \"i\",\n      \"offset\": [\n        4348,\n        4360\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"3\"\n    },\n    \"1134\": {\n      \"fn\": \"ERC20.approve\",\n      \"offset\": [\n        4348,\n        4360\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"3\"\n    },\n    \"1135\": {\n      \"fn\": \"ERC20.approve\",\n      \"offset\": [\n        4362,\n        4369\n      ],\n      \"op\": \"DUP5\",\n      \"path\": \"3\"\n    },\n    \"1136\": {\n      \"fn\": \"ERC20.approve\",\n      \"offset\": [\n        4371,\n        4377\n      ],\n      \"op\": \"DUP5\",\n      \"path\": \"3\"\n    },\n    \"1137\": {\n      \"fn\": \"ERC20.approve\",\n      \"offset\": [\n        4339,\n        4347\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x71D\"\n    },\n    \"1140\": {\n      \"fn\": \"ERC20.approve\",\n      \"jump\": \"i\",\n      \"offset\": [\n        4339,\n        4378\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"3\"\n    },\n    \"1141\": {\n      \"fn\": \"ERC20.approve\",\n      \"offset\": [\n        4339,\n        4378\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"3\"\n    },\n    \"1142\": {\n      \"op\": \"POP\"\n    },\n    \"1143\": {\n      \"fn\": \"ERC20.approve\",\n      \"offset\": [\n        4395,\n        4399\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"statement\": 2,\n      \"value\": \"0x1\"\n    },\n    \"1145\": {\n      \"fn\": \"ERC20.approve\",\n      \"offset\": [\n        4240,\n        4406\n      ],\n      \"op\": \"SWAP3\",\n      \"path\": \"3\"\n    },\n    \"1146\": {\n      \"fn\": \"ERC20.approve\",\n      \"offset\": [\n        4240,\n        4406\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"3\"\n    },\n    \"1147\": {\n      \"fn\": \"ERC20.approve\",\n      \"offset\": [\n        4240,\n        4406\n      ],\n      \"op\": \"POP\",\n      \"path\": \"3\"\n    },\n    \"1148\": {\n      \"fn\": \"ERC20.approve\",\n      \"offset\": [\n        4240,\n        4406\n      ],\n      \"op\": \"POP\",\n      \"path\": \"3\"\n    },\n    \"1149\": {\n      \"fn\": \"ERC20.approve\",\n      \"jump\": \"o\",\n      \"offset\": [\n        4240,\n        4406\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"3\"\n    },\n    \"1150\": {\n      \"fn\": \"ERC20.totalSupply\",\n      \"offset\": [\n        3247,\n        3345\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"3\"\n    },\n    \"1151\": {\n      \"fn\": \"ERC20.totalSupply\",\n      \"offset\": [\n        3326,\n        3338\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"statement\": 3,\n      \"value\": \"0x2\"\n    },\n    \"1153\": {\n      \"fn\": \"ERC20.totalSupply\",\n      \"offset\": [\n        3326,\n        3338\n      ],\n      \"op\": \"SLOAD\",\n      \"path\": \"3\"\n    },\n    \"1154\": {\n      \"fn\": \"ERC20.totalSupply\",\n      \"offset\": [\n        3247,\n        3345\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"1155\": {\n      \"fn\": \"ERC20.totalSupply\",\n      \"jump\": \"o\",\n      \"offset\": [\n        3247,\n        3345\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"3\"\n    },\n    \"1156\": {\n      \"fn\": \"ERC20Mock.transferInternal\",\n      \"offset\": [\n        575,\n        692\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"4\"\n    },\n    \"1157\": {\n      \"fn\": \"ERC20Mock.transferInternal\",\n      \"offset\": [\n        659,\n        685\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"4\",\n      \"statement\": 4,\n      \"value\": \"0x48F\"\n    },\n    \"1160\": {\n      \"fn\": \"ERC20Mock.transferInternal\",\n      \"offset\": [\n        669,\n        673\n      ],\n      \"op\": \"DUP4\",\n      \"path\": \"4\"\n    },\n    \"1161\": {\n      \"fn\": \"ERC20Mock.transferInternal\",\n      \"offset\": [\n        675,\n        677\n      ],\n      \"op\": \"DUP4\",\n      \"path\": \"4\"\n    },\n    \"1162\": {\n      \"fn\": \"ERC20Mock.transferInternal\",\n      \"offset\": [\n        679,\n        684\n      ],\n      \"op\": \"DUP4\",\n      \"path\": \"4\"\n    },\n    \"1163\": {\n      \"fn\": \"ERC20Mock.transferInternal\",\n      \"offset\": [\n        659,\n        668\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"4\",\n      \"value\": \"0x809\"\n    },\n    \"1166\": {\n      \"fn\": \"ERC20Mock.transferInternal\",\n      \"jump\": \"i\",\n      \"offset\": [\n        659,\n        685\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"4\"\n    },\n    \"1167\": {\n      \"fn\": \"ERC20Mock.transferInternal\",\n      \"offset\": [\n        659,\n        685\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"4\"\n    },\n    \"1168\": {\n      \"fn\": \"ERC20Mock.transferInternal\",\n      \"offset\": [\n        575,\n        692\n      ],\n      \"op\": \"POP\",\n      \"path\": \"4\"\n    },\n    \"1169\": {\n      \"fn\": \"ERC20Mock.transferInternal\",\n      \"offset\": [\n        575,\n        692\n      ],\n      \"op\": \"POP\",\n      \"path\": \"4\"\n    },\n    \"1170\": {\n      \"fn\": \"ERC20Mock.transferInternal\",\n      \"offset\": [\n        575,\n        692\n      ],\n      \"op\": \"POP\",\n      \"path\": \"4\"\n    },\n    \"1171\": {\n      \"fn\": \"ERC20Mock.transferInternal\",\n      \"jump\": \"o\",\n      \"offset\": [\n        575,\n        692\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"4\"\n    },\n    \"1172\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        4866,\n        5183\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"3\"\n    },\n    \"1173\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        4972,\n        4976\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x0\"\n    },\n    \"1175\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        4988,\n        5024\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"statement\": 5,\n      \"value\": \"0x4A1\"\n    },\n    \"1178\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        4998,\n        5004\n      ],\n      \"op\": \"DUP5\",\n      \"path\": \"3\"\n    },\n    \"1179\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        5006,\n        5015\n      ],\n      \"op\": \"DUP5\",\n      \"path\": \"3\"\n    },\n    \"1180\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        5017,\n        5023\n      ],\n      \"op\": \"DUP5\",\n      \"path\": \"3\"\n    },\n    \"1181\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        4988,\n        4997\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x809\"\n    },\n    \"1184\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"jump\": \"i\",\n      \"offset\": [\n        4988,\n        5024\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"3\"\n    },\n    \"1185\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        4988,\n        5024\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"3\"\n    },\n    \"1186\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        5034,\n        5155\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"statement\": 6,\n      \"value\": \"0x511\"\n    },\n    \"1189\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        5043,\n        5049\n      ],\n      \"op\": \"DUP5\",\n      \"path\": \"3\"\n    },\n    \"1190\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        5051,\n        5063\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x4AD\"\n    },\n    \"1193\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        5051,\n        5061\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x719\"\n    },\n    \"1196\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"jump\": \"i\",\n      \"offset\": [\n        5051,\n        5063\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"3\"\n    },\n    \"1197\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        5051,\n        5063\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"3\"\n    },\n    \"1198\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        5065,\n        5154\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x50C\"\n    },\n    \"1201\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        5103,\n        5109\n      ],\n      \"op\": \"DUP6\",\n      \"path\": \"3\"\n    },\n    \"1202\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        5065,\n        5154\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x40\"\n    },\n    \"1204\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        5065,\n        5154\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"3\"\n    },\n    \"1205\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        5065,\n        5154\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"1206\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        5065,\n        5154\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x60\"\n    },\n    \"1208\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        5065,\n        5154\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"1209\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        5065,\n        5154\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x40\"\n    },\n    \"1211\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        5065,\n        5154\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"1212\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        5065,\n        5154\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"1213\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        5065,\n        5154\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x28\"\n    },\n    \"1215\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        5065,\n        5154\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"1216\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        5065,\n        5154\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"1217\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        5065,\n        5154\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x20\"\n    },\n    \"1219\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        5065,\n        5154\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"1220\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        5065,\n        5154\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0xCB7\"\n    },\n    \"1223\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        5065,\n        5154\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x28\"\n    },\n    \"1225\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        5065,\n        5154\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"3\"\n    },\n    \"1226\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        5065,\n        5154\n      ],\n      \"op\": \"CODECOPY\",\n      \"path\": \"3\"\n    },\n    \"1227\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"1229\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"1231\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0xA0\"\n    },\n    \"1233\": {\n      \"op\": \"SHL\"\n    },\n    \"1234\": {\n      \"op\": \"SUB\"\n    },\n    \"1235\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        5065,\n        5084\n      ],\n      \"op\": \"DUP11\",\n      \"path\": \"3\"\n    },\n    \"1236\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        5065,\n        5084\n      ],\n      \"op\": \"AND\",\n      \"path\": \"3\"\n    },\n    \"1237\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        5065,\n        5084\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x0\"\n    },\n    \"1239\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        5065,\n        5084\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"1240\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        5065,\n        5084\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"1241\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        5065,\n        5084\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"1242\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        5065,\n        5076\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x1\"\n    },\n    \"1244\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        5065,\n        5084\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x20\"\n    },\n    \"1246\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        5065,\n        5084\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"1247\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        5065,\n        5084\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x40\"\n    },\n    \"1249\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        5065,\n        5084\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"1250\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        5065,\n        5084\n      ],\n      \"op\": \"KECCAK256\",\n      \"path\": \"3\"\n    },\n    \"1251\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        5065,\n        5084\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"1252\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        5085,\n        5097\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x4EB\"\n    },\n    \"1255\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        5085,\n        5095\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x719\"\n    },\n    \"1258\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"jump\": \"i\",\n      \"offset\": [\n        5085,\n        5097\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"3\"\n    },\n    \"1259\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        5085,\n        5097\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"3\"\n    },\n    \"1260\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"1262\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"1264\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0xA0\"\n    },\n    \"1266\": {\n      \"op\": \"SHL\"\n    },\n    \"1267\": {\n      \"op\": \"SUB\"\n    },\n    \"1268\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        5065,\n        5098\n      ],\n      \"op\": \"AND\",\n      \"path\": \"3\"\n    },\n    \"1269\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        5065,\n        5098\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"1270\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        5065,\n        5098\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"1271\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        5065,\n        5098\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x20\"\n    },\n    \"1273\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        5065,\n        5098\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"1274\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        5065,\n        5098\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"1275\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        5065,\n        5098\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"3\"\n    },\n    \"1276\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        5065,\n        5098\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"1277\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        5065,\n        5098\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"3\"\n    },\n    \"1278\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        5065,\n        5098\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"1279\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        5065,\n        5098\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x40\"\n    },\n    \"1281\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        5065,\n        5098\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"1282\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x0\"\n    },\n    \"1284\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        5065,\n        5098\n      ],\n      \"op\": \"KECCAK256\",\n      \"path\": \"3\"\n    },\n    \"1285\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        5065,\n        5098\n      ],\n      \"op\": \"SLOAD\",\n      \"path\": \"3\"\n    },\n    \"1286\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        5065,\n        5098\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"3\"\n    },\n    \"1287\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        5065,\n        5154\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"1288\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        5065,\n        5102\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x964\"\n    },\n    \"1291\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"jump\": \"i\",\n      \"offset\": [\n        5065,\n        5154\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"3\"\n    },\n    \"1292\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        5065,\n        5154\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"3\"\n    },\n    \"1293\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        5034,\n        5042\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x71D\"\n    },\n    \"1296\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"jump\": \"i\",\n      \"offset\": [\n        5034,\n        5155\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"3\"\n    },\n    \"1297\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        5034,\n        5155\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"3\"\n    },\n    \"1298\": {\n      \"op\": \"POP\"\n    },\n    \"1299\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        5172,\n        5176\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"statement\": 7,\n      \"value\": \"0x1\"\n    },\n    \"1301\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        4866,\n        5183\n      ],\n      \"op\": \"SWAP4\",\n      \"path\": \"3\"\n    },\n    \"1302\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        4866,\n        5183\n      ],\n      \"op\": \"SWAP3\",\n      \"path\": \"3\"\n    },\n    \"1303\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        4866,\n        5183\n      ],\n      \"op\": \"POP\",\n      \"path\": \"3\"\n    },\n    \"1304\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        4866,\n        5183\n      ],\n      \"op\": \"POP\",\n      \"path\": \"3\"\n    },\n    \"1305\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"offset\": [\n        4866,\n        5183\n      ],\n      \"op\": \"POP\",\n      \"path\": \"3\"\n    },\n    \"1306\": {\n      \"fn\": \"ERC20.transferFrom\",\n      \"jump\": \"o\",\n      \"offset\": [\n        4866,\n        5183\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"3\"\n    },\n    \"1307\": {\n      \"fn\": \"ERC20.decimals\",\n      \"offset\": [\n        3106,\n        3187\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"3\"\n    },\n    \"1308\": {\n      \"fn\": \"ERC20.decimals\",\n      \"offset\": [\n        3171,\n        3180\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"statement\": 8,\n      \"value\": \"0x5\"\n    },\n    \"1310\": {\n      \"fn\": \"ERC20.decimals\",\n      \"offset\": [\n        3171,\n        3180\n      ],\n      \"op\": \"SLOAD\",\n      \"path\": \"3\"\n    },\n    \"1311\": {\n      \"fn\": \"ERC20.decimals\",\n      \"offset\": [\n        3171,\n        3180\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0xFF\"\n    },\n    \"1313\": {\n      \"fn\": \"ERC20.decimals\",\n      \"offset\": [\n        3171,\n        3180\n      ],\n      \"op\": \"AND\",\n      \"path\": \"3\"\n    },\n    \"1314\": {\n      \"fn\": \"ERC20.decimals\",\n      \"offset\": [\n        3106,\n        3187\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"1315\": {\n      \"fn\": \"ERC20.decimals\",\n      \"jump\": \"o\",\n      \"offset\": [\n        3106,\n        3187\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"3\"\n    },\n    \"1316\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"offset\": [\n        5578,\n        5793\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"3\"\n    },\n    \"1317\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"offset\": [\n        5666,\n        5670\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x0\"\n    },\n    \"1319\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"offset\": [\n        5682,\n        5765\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"statement\": 9,\n      \"value\": \"0x475\"\n    },\n    \"1322\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"offset\": [\n        5691,\n        5703\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x531\"\n    },\n    \"1325\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"offset\": [\n        5691,\n        5701\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x719\"\n    },\n    \"1328\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"jump\": \"i\",\n      \"offset\": [\n        5691,\n        5703\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"3\"\n    },\n    \"1329\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"offset\": [\n        5691,\n        5703\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"3\"\n    },\n    \"1330\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"offset\": [\n        5705,\n        5712\n      ],\n      \"op\": \"DUP5\",\n      \"path\": \"3\"\n    },\n    \"1331\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"offset\": [\n        5714,\n        5764\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x50C\"\n    },\n    \"1334\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"offset\": [\n        5753,\n        5763\n      ],\n      \"op\": \"DUP6\",\n      \"path\": \"3\"\n    },\n    \"1335\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"offset\": [\n        5714,\n        5725\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x1\"\n    },\n    \"1337\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"offset\": [\n        5714,\n        5739\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x0\"\n    },\n    \"1339\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"offset\": [\n        5726,\n        5738\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x542\"\n    },\n    \"1342\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"offset\": [\n        5726,\n        5736\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x719\"\n    },\n    \"1345\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"jump\": \"i\",\n      \"offset\": [\n        5726,\n        5738\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"3\"\n    },\n    \"1346\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"offset\": [\n        5726,\n        5738\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"3\"\n    },\n    \"1347\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"1349\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"1351\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0xA0\"\n    },\n    \"1353\": {\n      \"op\": \"SHL\"\n    },\n    \"1354\": {\n      \"op\": \"SUB\"\n    },\n    \"1355\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"offset\": [\n        5714,\n        5739\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"1356\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"offset\": [\n        5714,\n        5739\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"1357\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"offset\": [\n        5714,\n        5739\n      ],\n      \"op\": \"AND\",\n      \"path\": \"3\"\n    },\n    \"1358\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"offset\": [\n        5714,\n        5739\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"3\"\n    },\n    \"1359\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"offset\": [\n        5714,\n        5739\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"1360\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"offset\": [\n        5714,\n        5739\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x20\"\n    },\n    \"1362\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"offset\": [\n        5714,\n        5739\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"1363\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"offset\": [\n        5714,\n        5739\n      ],\n      \"op\": \"DUP4\",\n      \"path\": \"3\"\n    },\n    \"1364\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"offset\": [\n        5714,\n        5739\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"1365\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"offset\": [\n        5714,\n        5739\n      ],\n      \"op\": \"SWAP4\",\n      \"path\": \"3\"\n    },\n    \"1366\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"offset\": [\n        5714,\n        5739\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"1367\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"offset\": [\n        5714,\n        5739\n      ],\n      \"op\": \"SWAP4\",\n      \"path\": \"3\"\n    },\n    \"1368\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"offset\": [\n        5714,\n        5739\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"1369\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"offset\": [\n        5714,\n        5739\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x40\"\n    },\n    \"1371\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"offset\": [\n        5714,\n        5739\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"3\"\n    },\n    \"1372\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"offset\": [\n        5714,\n        5739\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"3\"\n    },\n    \"1373\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"offset\": [\n        5714,\n        5739\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"1374\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x0\"\n    },\n    \"1376\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"offset\": [\n        5714,\n        5739\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"1377\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"offset\": [\n        5714,\n        5739\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"1378\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"offset\": [\n        5714,\n        5739\n      ],\n      \"op\": \"KECCAK256\",\n      \"path\": \"3\"\n    },\n    \"1379\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"offset\": [\n        5714,\n        5748\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"3\"\n    },\n    \"1380\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"offset\": [\n        5714,\n        5748\n      ],\n      \"op\": \"DUP13\",\n      \"path\": \"3\"\n    },\n    \"1381\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"offset\": [\n        5714,\n        5748\n      ],\n      \"op\": \"AND\",\n      \"path\": \"3\"\n    },\n    \"1382\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"offset\": [\n        5714,\n        5748\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"1383\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"offset\": [\n        5714,\n        5748\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"1384\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"offset\": [\n        5714,\n        5748\n      ],\n      \"op\": \"SWAP3\",\n      \"path\": \"3\"\n    },\n    \"1385\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"offset\": [\n        5714,\n        5748\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"1386\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"offset\": [\n        5714,\n        5748\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"1387\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"offset\": [\n        5714,\n        5748\n      ],\n      \"op\": \"KECCAK256\",\n      \"path\": \"3\"\n    },\n    \"1388\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"offset\": [\n        5714,\n        5748\n      ],\n      \"op\": \"SLOAD\",\n      \"path\": \"3\"\n    },\n    \"1389\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"offset\": [\n        5714,\n        5748\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"1390\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"offset\": [\n        5714,\n        5752\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x6B8\"\n    },\n    \"1393\": {\n      \"fn\": \"ERC20.increaseAllowance\",\n      \"jump\": \"i\",\n      \"offset\": [\n        5714,\n        5764\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"3\"\n    },\n    \"1394\": {\n      \"fn\": \"ERC20Mock.mint\",\n      \"offset\": [\n        377,\n        470\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"4\"\n    },\n    \"1395\": {\n      \"fn\": \"ERC20Mock.mint\",\n      \"offset\": [\n        441,\n        463\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"4\",\n      \"statement\": 10,\n      \"value\": \"0x57C\"\n    },\n    \"1398\": {\n      \"fn\": \"ERC20Mock.mint\",\n      \"offset\": [\n        447,\n        454\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"4\"\n    },\n    \"1399\": {\n      \"fn\": \"ERC20Mock.mint\",\n      \"offset\": [\n        456,\n        462\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"4\"\n    },\n    \"1400\": {\n      \"fn\": \"ERC20Mock.mint\",\n      \"offset\": [\n        441,\n        446\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"4\",\n      \"value\": \"0x9FB\"\n    },\n    \"1403\": {\n      \"fn\": \"ERC20Mock.mint\",\n      \"jump\": \"i\",\n      \"offset\": [\n        441,\n        463\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"4\"\n    },\n    \"1404\": {\n      \"fn\": \"ERC20Mock.mint\",\n      \"offset\": [\n        441,\n        463\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"4\"\n    },\n    \"1405\": {\n      \"fn\": \"ERC20Mock.mint\",\n      \"offset\": [\n        377,\n        470\n      ],\n      \"op\": \"POP\",\n      \"path\": \"4\"\n    },\n    \"1406\": {\n      \"fn\": \"ERC20Mock.mint\",\n      \"offset\": [\n        377,\n        470\n      ],\n      \"op\": \"POP\",\n      \"path\": \"4\"\n    },\n    \"1407\": {\n      \"fn\": \"ERC20Mock.mint\",\n      \"jump\": \"o\",\n      \"offset\": [\n        377,\n        470\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"4\"\n    },\n    \"1408\": {\n      \"fn\": \"ERC20Mock.approveInternal\",\n      \"offset\": [\n        698,\n        825\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"4\"\n    },\n    \"1409\": {\n      \"fn\": \"ERC20Mock.approveInternal\",\n      \"offset\": [\n        787,\n        818\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"4\",\n      \"statement\": 11,\n      \"value\": \"0x48F\"\n    },\n    \"1412\": {\n      \"fn\": \"ERC20Mock.approveInternal\",\n      \"offset\": [\n        796,\n        801\n      ],\n      \"op\": \"DUP4\",\n      \"path\": \"4\"\n    },\n    \"1413\": {\n      \"fn\": \"ERC20Mock.approveInternal\",\n      \"offset\": [\n        803,\n        810\n      ],\n      \"op\": \"DUP4\",\n      \"path\": \"4\"\n    },\n    \"1414\": {\n      \"fn\": \"ERC20Mock.approveInternal\",\n      \"offset\": [\n        812,\n        817\n      ],\n      \"op\": \"DUP4\",\n      \"path\": \"4\"\n    },\n    \"1415\": {\n      \"fn\": \"ERC20Mock.approveInternal\",\n      \"offset\": [\n        787,\n        795\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"4\",\n      \"value\": \"0x71D\"\n    },\n    \"1418\": {\n      \"fn\": \"ERC20Mock.approveInternal\",\n      \"jump\": \"i\",\n      \"offset\": [\n        787,\n        818\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"4\"\n    },\n    \"1419\": {\n      \"fn\": \"ERC20.balanceOf\",\n      \"offset\": [\n        3403,\n        3520\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"3\"\n    },\n    \"1420\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"1422\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"1424\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0xA0\"\n    },\n    \"1426\": {\n      \"op\": \"SHL\"\n    },\n    \"1427\": {\n      \"op\": \"SUB\"\n    },\n    \"1428\": {\n      \"fn\": \"ERC20.balanceOf\",\n      \"offset\": [\n        3495,\n        3513\n      ],\n      \"op\": \"AND\",\n      \"path\": \"3\",\n      \"statement\": 12\n    },\n    \"1429\": {\n      \"fn\": \"ERC20.balanceOf\",\n      \"offset\": [\n        3469,\n        3476\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x0\"\n    },\n    \"1431\": {\n      \"fn\": \"ERC20.balanceOf\",\n      \"offset\": [\n        3495,\n        3513\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"1432\": {\n      \"fn\": \"ERC20.balanceOf\",\n      \"offset\": [\n        3495,\n        3513\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"1433\": {\n      \"fn\": \"ERC20.balanceOf\",\n      \"offset\": [\n        3495,\n        3513\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"1434\": {\n      \"fn\": \"ERC20.balanceOf\",\n      \"offset\": [\n        3495,\n        3513\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x20\"\n    },\n    \"1436\": {\n      \"fn\": \"ERC20.balanceOf\",\n      \"offset\": [\n        3495,\n        3513\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"1437\": {\n      \"fn\": \"ERC20.balanceOf\",\n      \"offset\": [\n        3495,\n        3513\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"1438\": {\n      \"fn\": \"ERC20.balanceOf\",\n      \"offset\": [\n        3495,\n        3513\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"1439\": {\n      \"fn\": \"ERC20.balanceOf\",\n      \"offset\": [\n        3495,\n        3513\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x40\"\n    },\n    \"1441\": {\n      \"fn\": \"ERC20.balanceOf\",\n      \"offset\": [\n        3495,\n        3513\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"1442\": {\n      \"fn\": \"ERC20.balanceOf\",\n      \"offset\": [\n        3495,\n        3513\n      ],\n      \"op\": \"KECCAK256\",\n      \"path\": \"3\"\n    },\n    \"1443\": {\n      \"fn\": \"ERC20.balanceOf\",\n      \"offset\": [\n        3495,\n        3513\n      ],\n      \"op\": \"SLOAD\",\n      \"path\": \"3\"\n    },\n    \"1444\": {\n      \"fn\": \"ERC20.balanceOf\",\n      \"offset\": [\n        3495,\n        3513\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"1445\": {\n      \"fn\": \"ERC20.balanceOf\",\n      \"jump\": \"o\",\n      \"offset\": [\n        3403,\n        3520\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"3\"\n    },\n    \"1446\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2398,\n        2483\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"3\"\n    },\n    \"1447\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2469,\n        2476\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"statement\": 13,\n      \"value\": \"0x4\"\n    },\n    \"1449\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2462,\n        2476\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"1450\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2462,\n        2476\n      ],\n      \"op\": \"SLOAD\",\n      \"path\": \"3\"\n    },\n    \"1451\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2462,\n        2476\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x40\"\n    },\n    \"1453\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2462,\n        2476\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"1454\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2462,\n        2476\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"3\"\n    },\n    \"1455\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2462,\n        2476\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x20\"\n    },\n    \"1457\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2462,\n        2476\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x1F\"\n    },\n    \"1459\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2462,\n        2476\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x2\"\n    },\n    \"1461\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x0\"\n    },\n    \"1463\": {\n      \"op\": \"NOT\"\n    },\n    \"1464\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2462,\n        2476\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x100\"\n    },\n    \"1467\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2462,\n        2476\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x1\"\n    },\n    \"1469\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2462,\n        2476\n      ],\n      \"op\": \"DUP9\",\n      \"path\": \"3\"\n    },\n    \"1470\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2462,\n        2476\n      ],\n      \"op\": \"AND\",\n      \"path\": \"3\"\n    },\n    \"1471\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2462,\n        2476\n      ],\n      \"op\": \"ISZERO\",\n      \"path\": \"3\"\n    },\n    \"1472\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2462,\n        2476\n      ],\n      \"op\": \"MUL\",\n      \"path\": \"3\"\n    },\n    \"1473\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2462,\n        2476\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"1474\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2462,\n        2476\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"1475\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2462,\n        2476\n      ],\n      \"op\": \"SWAP6\",\n      \"path\": \"3\"\n    },\n    \"1476\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2462,\n        2476\n      ],\n      \"op\": \"AND\",\n      \"path\": \"3\"\n    },\n    \"1477\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2462,\n        2476\n      ],\n      \"op\": \"SWAP5\",\n      \"path\": \"3\"\n    },\n    \"1478\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2462,\n        2476\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"1479\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2462,\n        2476\n      ],\n      \"op\": \"SWAP5\",\n      \"path\": \"3\"\n    },\n    \"1480\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2462,\n        2476\n      ],\n      \"op\": \"DIV\",\n      \"path\": \"3\"\n    },\n    \"1481\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2462,\n        2476\n      ],\n      \"op\": \"SWAP4\",\n      \"path\": \"3\"\n    },\n    \"1482\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2462,\n        2476\n      ],\n      \"op\": \"DUP5\",\n      \"path\": \"3\"\n    },\n    \"1483\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2462,\n        2476\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"1484\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2462,\n        2476\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"1485\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2462,\n        2476\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"1486\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2462,\n        2476\n      ],\n      \"op\": \"DIV\",\n      \"path\": \"3\"\n    },\n    \"1487\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2462,\n        2476\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"1488\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2462,\n        2476\n      ],\n      \"op\": \"MUL\",\n      \"path\": \"3\"\n    },\n    \"1489\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2462,\n        2476\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"3\"\n    },\n    \"1490\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2462,\n        2476\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"1491\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2462,\n        2476\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"1492\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2462,\n        2476\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"1493\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2462,\n        2476\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"1494\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2462,\n        2476\n      ],\n      \"op\": \"SWAP3\",\n      \"path\": \"3\"\n    },\n    \"1495\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2462,\n        2476\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"1496\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2462,\n        2476\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"3\"\n    },\n    \"1497\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2462,\n        2476\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"1498\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2462,\n        2476\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"1499\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2437,\n        2450\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x60\"\n    },\n    \"1501\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2437,\n        2450\n      ],\n      \"op\": \"SWAP4\",\n      \"path\": \"3\"\n    },\n    \"1502\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2462,\n        2476\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"1503\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2462,\n        2476\n      ],\n      \"op\": \"SWAP3\",\n      \"path\": \"3\"\n    },\n    \"1504\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2469,\n        2476\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"1505\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2469,\n        2476\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"3\"\n    },\n    \"1506\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2462,\n        2476\n      ],\n      \"op\": \"DUP4\",\n      \"path\": \"3\"\n    },\n    \"1507\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2462,\n        2476\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"1508\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2469,\n        2476\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"3\"\n    },\n    \"1509\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2462,\n        2476\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"3\"\n    },\n    \"1510\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2462,\n        2476\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"1511\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2462,\n        2476\n      ],\n      \"op\": \"ISZERO\",\n      \"path\": \"3\"\n    },\n    \"1512\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2462,\n        2476\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x457\"\n    },\n    \"1515\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2462,\n        2476\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"3\"\n    },\n    \"1516\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2462,\n        2476\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"1517\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2462,\n        2476\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x1F\"\n    },\n    \"1519\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2462,\n        2476\n      ],\n      \"op\": \"LT\",\n      \"path\": \"3\"\n    },\n    \"1520\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2462,\n        2476\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x42C\"\n    },\n    \"1523\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2462,\n        2476\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"3\"\n    },\n    \"1524\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2462,\n        2476\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x100\"\n    },\n    \"1527\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2462,\n        2476\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"1528\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2462,\n        2476\n      ],\n      \"op\": \"DUP4\",\n      \"path\": \"3\"\n    },\n    \"1529\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2462,\n        2476\n      ],\n      \"op\": \"SLOAD\",\n      \"path\": \"3\"\n    },\n    \"1530\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2462,\n        2476\n      ],\n      \"op\": \"DIV\",\n      \"path\": \"3\"\n    },\n    \"1531\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2462,\n        2476\n      ],\n      \"op\": \"MUL\",\n      \"path\": \"3\"\n    },\n    \"1532\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2462,\n        2476\n      ],\n      \"op\": \"DUP4\",\n      \"path\": \"3\"\n    },\n    \"1533\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2462,\n        2476\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"1534\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2462,\n        2476\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"3\"\n    },\n    \"1535\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2462,\n        2476\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x20\"\n    },\n    \"1537\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2462,\n        2476\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"1538\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2462,\n        2476\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"3\"\n    },\n    \"1539\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2462,\n        2476\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x457\"\n    },\n    \"1542\": {\n      \"fn\": \"ERC20.symbol\",\n      \"offset\": [\n        2462,\n        2476\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"3\"\n    },\n    \"1543\": {\n      \"fn\": \"ERC20Mock.burn\",\n      \"offset\": [\n        476,\n        569\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"4\"\n    },\n    \"1544\": {\n      \"fn\": \"ERC20Mock.burn\",\n      \"offset\": [\n        540,\n        562\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"4\",\n      \"statement\": 14,\n      \"value\": \"0x57C\"\n    },\n    \"1547\": {\n      \"fn\": \"ERC20Mock.burn\",\n      \"offset\": [\n        546,\n        553\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"4\"\n    },\n    \"1548\": {\n      \"fn\": \"ERC20Mock.burn\",\n      \"offset\": [\n        555,\n        561\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"4\"\n    },\n    \"1549\": {\n      \"fn\": \"ERC20Mock.burn\",\n      \"offset\": [\n        540,\n        545\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"4\",\n      \"value\": \"0xAEB\"\n    },\n    \"1552\": {\n      \"fn\": \"ERC20Mock.burn\",\n      \"jump\": \"i\",\n      \"offset\": [\n        540,\n        562\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"4\"\n    },\n    \"1553\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6280,\n        6546\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"3\"\n    },\n    \"1554\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6373,\n        6377\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x0\"\n    },\n    \"1556\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6389,\n        6518\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"statement\": 15,\n      \"value\": \"0x475\"\n    },\n    \"1559\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6398,\n        6410\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x61E\"\n    },\n    \"1562\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6398,\n        6408\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x719\"\n    },\n    \"1565\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"jump\": \"i\",\n      \"offset\": [\n        6398,\n        6410\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"3\"\n    },\n    \"1566\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6398,\n        6410\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"3\"\n    },\n    \"1567\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6412,\n        6419\n      ],\n      \"op\": \"DUP5\",\n      \"path\": \"3\"\n    },\n    \"1568\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6421,\n        6517\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x50C\"\n    },\n    \"1571\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6460,\n        6475\n      ],\n      \"op\": \"DUP6\",\n      \"path\": \"3\"\n    },\n    \"1572\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6421,\n        6517\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x40\"\n    },\n    \"1574\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6421,\n        6517\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"3\"\n    },\n    \"1575\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6421,\n        6517\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"1576\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6421,\n        6517\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x60\"\n    },\n    \"1578\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6421,\n        6517\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"1579\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6421,\n        6517\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x40\"\n    },\n    \"1581\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6421,\n        6517\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"1582\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6421,\n        6517\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"1583\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6421,\n        6517\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x25\"\n    },\n    \"1585\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6421,\n        6517\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"1586\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6421,\n        6517\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"1587\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6421,\n        6517\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x20\"\n    },\n    \"1589\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6421,\n        6517\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"1590\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6421,\n        6517\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0xD49\"\n    },\n    \"1593\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6421,\n        6517\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x25\"\n    },\n    \"1595\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6421,\n        6517\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"3\"\n    },\n    \"1596\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6421,\n        6517\n      ],\n      \"op\": \"CODECOPY\",\n      \"path\": \"3\"\n    },\n    \"1597\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6421,\n        6432\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x1\"\n    },\n    \"1599\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6421,\n        6446\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x0\"\n    },\n    \"1601\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6433,\n        6445\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x648\"\n    },\n    \"1604\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6433,\n        6443\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x719\"\n    },\n    \"1607\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"jump\": \"i\",\n      \"offset\": [\n        6433,\n        6445\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"3\"\n    },\n    \"1608\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6433,\n        6445\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"3\"\n    },\n    \"1609\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"1611\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"1613\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0xA0\"\n    },\n    \"1615\": {\n      \"op\": \"SHL\"\n    },\n    \"1616\": {\n      \"op\": \"SUB\"\n    },\n    \"1617\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6421,\n        6446\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"1618\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6421,\n        6446\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"1619\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6421,\n        6446\n      ],\n      \"op\": \"AND\",\n      \"path\": \"3\"\n    },\n    \"1620\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6421,\n        6446\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"3\"\n    },\n    \"1621\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6421,\n        6446\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"1622\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6421,\n        6446\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x20\"\n    },\n    \"1624\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6421,\n        6446\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"1625\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6421,\n        6446\n      ],\n      \"op\": \"DUP4\",\n      \"path\": \"3\"\n    },\n    \"1626\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6421,\n        6446\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"1627\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6421,\n        6446\n      ],\n      \"op\": \"SWAP4\",\n      \"path\": \"3\"\n    },\n    \"1628\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6421,\n        6446\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"1629\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6421,\n        6446\n      ],\n      \"op\": \"SWAP4\",\n      \"path\": \"3\"\n    },\n    \"1630\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6421,\n        6446\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"1631\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6421,\n        6446\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x40\"\n    },\n    \"1633\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6421,\n        6446\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"3\"\n    },\n    \"1634\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6421,\n        6446\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"3\"\n    },\n    \"1635\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6421,\n        6446\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"1636\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x0\"\n    },\n    \"1638\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6421,\n        6446\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"1639\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6421,\n        6446\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"1640\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6421,\n        6446\n      ],\n      \"op\": \"KECCAK256\",\n      \"path\": \"3\"\n    },\n    \"1641\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6421,\n        6455\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"3\"\n    },\n    \"1642\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6421,\n        6455\n      ],\n      \"op\": \"DUP14\",\n      \"path\": \"3\"\n    },\n    \"1643\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6421,\n        6455\n      ],\n      \"op\": \"AND\",\n      \"path\": \"3\"\n    },\n    \"1644\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6421,\n        6455\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"1645\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6421,\n        6455\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"1646\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6421,\n        6455\n      ],\n      \"op\": \"SWAP3\",\n      \"path\": \"3\"\n    },\n    \"1647\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6421,\n        6455\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"1648\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6421,\n        6455\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"1649\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6421,\n        6455\n      ],\n      \"op\": \"KECCAK256\",\n      \"path\": \"3\"\n    },\n    \"1650\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6421,\n        6455\n      ],\n      \"op\": \"SLOAD\",\n      \"path\": \"3\"\n    },\n    \"1651\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6421,\n        6455\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"3\"\n    },\n    \"1652\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6421,\n        6517\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"1653\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"offset\": [\n        6421,\n        6459\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x964\"\n    },\n    \"1656\": {\n      \"fn\": \"ERC20.decreaseAllowance\",\n      \"jump\": \"i\",\n      \"offset\": [\n        6421,\n        6517\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"3\"\n    },\n    \"1657\": {\n      \"fn\": \"ERC20.transfer\",\n      \"offset\": [\n        3723,\n        3895\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"3\"\n    },\n    \"1658\": {\n      \"fn\": \"ERC20.transfer\",\n      \"offset\": [\n        3809,\n        3813\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x0\"\n    },\n    \"1660\": {\n      \"fn\": \"ERC20.transfer\",\n      \"offset\": [\n        3825,\n        3867\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"statement\": 16,\n      \"value\": \"0x475\"\n    },\n    \"1663\": {\n      \"fn\": \"ERC20.transfer\",\n      \"offset\": [\n        3835,\n        3847\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x686\"\n    },\n    \"1666\": {\n      \"fn\": \"ERC20.transfer\",\n      \"offset\": [\n        3835,\n        3845\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x719\"\n    },\n    \"1669\": {\n      \"fn\": \"ERC20.transfer\",\n      \"jump\": \"i\",\n      \"offset\": [\n        3835,\n        3847\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"3\"\n    },\n    \"1670\": {\n      \"fn\": \"ERC20.transfer\",\n      \"offset\": [\n        3835,\n        3847\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"3\"\n    },\n    \"1671\": {\n      \"fn\": \"ERC20.transfer\",\n      \"offset\": [\n        3849,\n        3858\n      ],\n      \"op\": \"DUP5\",\n      \"path\": \"3\"\n    },\n    \"1672\": {\n      \"fn\": \"ERC20.transfer\",\n      \"offset\": [\n        3860,\n        3866\n      ],\n      \"op\": \"DUP5\",\n      \"path\": \"3\"\n    },\n    \"1673\": {\n      \"fn\": \"ERC20.transfer\",\n      \"offset\": [\n        3825,\n        3834\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x809\"\n    },\n    \"1676\": {\n      \"fn\": \"ERC20.transfer\",\n      \"jump\": \"i\",\n      \"offset\": [\n        3825,\n        3867\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"3\"\n    },\n    \"1677\": {\n      \"fn\": \"ERC20.allowance\",\n      \"offset\": [\n        3953,\n        4102\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"3\"\n    },\n    \"1678\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"1680\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"1682\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0xA0\"\n    },\n    \"1684\": {\n      \"op\": \"SHL\"\n    },\n    \"1685\": {\n      \"op\": \"SUB\"\n    },\n    \"1686\": {\n      \"fn\": \"ERC20.allowance\",\n      \"offset\": [\n        4068,\n        4086\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"3\",\n      \"statement\": 17\n    },\n    \"1687\": {\n      \"fn\": \"ERC20.allowance\",\n      \"offset\": [\n        4068,\n        4086\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"3\"\n    },\n    \"1688\": {\n      \"fn\": \"ERC20.allowance\",\n      \"offset\": [\n        4068,\n        4086\n      ],\n      \"op\": \"AND\",\n      \"path\": \"3\"\n    },\n    \"1689\": {\n      \"fn\": \"ERC20.allowance\",\n      \"offset\": [\n        4042,\n        4049\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x0\"\n    },\n    \"1691\": {\n      \"fn\": \"ERC20.allowance\",\n      \"offset\": [\n        4068,\n        4086\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"1692\": {\n      \"fn\": \"ERC20.allowance\",\n      \"offset\": [\n        4068,\n        4086\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"1693\": {\n      \"fn\": \"ERC20.allowance\",\n      \"offset\": [\n        4068,\n        4086\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"1694\": {\n      \"fn\": \"ERC20.allowance\",\n      \"offset\": [\n        4068,\n        4079\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x1\"\n    },\n    \"1696\": {\n      \"fn\": \"ERC20.allowance\",\n      \"offset\": [\n        4068,\n        4086\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x20\"\n    },\n    \"1698\": {\n      \"fn\": \"ERC20.allowance\",\n      \"offset\": [\n        4068,\n        4086\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"1699\": {\n      \"fn\": \"ERC20.allowance\",\n      \"offset\": [\n        4068,\n        4086\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"1700\": {\n      \"fn\": \"ERC20.allowance\",\n      \"offset\": [\n        4068,\n        4086\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"1701\": {\n      \"fn\": \"ERC20.allowance\",\n      \"offset\": [\n        4068,\n        4086\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x40\"\n    },\n    \"1703\": {\n      \"fn\": \"ERC20.allowance\",\n      \"offset\": [\n        4068,\n        4086\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"1704\": {\n      \"fn\": \"ERC20.allowance\",\n      \"offset\": [\n        4068,\n        4086\n      ],\n      \"op\": \"DUP4\",\n      \"path\": \"3\"\n    },\n    \"1705\": {\n      \"fn\": \"ERC20.allowance\",\n      \"offset\": [\n        4068,\n        4086\n      ],\n      \"op\": \"KECCAK256\",\n      \"path\": \"3\"\n    },\n    \"1706\": {\n      \"fn\": \"ERC20.allowance\",\n      \"offset\": [\n        4068,\n        4095\n      ],\n      \"op\": \"SWAP4\",\n      \"path\": \"3\"\n    },\n    \"1707\": {\n      \"fn\": \"ERC20.allowance\",\n      \"offset\": [\n        4068,\n        4095\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"1708\": {\n      \"fn\": \"ERC20.allowance\",\n      \"offset\": [\n        4068,\n        4095\n      ],\n      \"op\": \"SWAP5\",\n      \"path\": \"3\"\n    },\n    \"1709\": {\n      \"fn\": \"ERC20.allowance\",\n      \"offset\": [\n        4068,\n        4095\n      ],\n      \"op\": \"AND\",\n      \"path\": \"3\"\n    },\n    \"1710\": {\n      \"fn\": \"ERC20.allowance\",\n      \"offset\": [\n        4068,\n        4095\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"3\"\n    },\n    \"1711\": {\n      \"fn\": \"ERC20.allowance\",\n      \"offset\": [\n        4068,\n        4095\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"1712\": {\n      \"fn\": \"ERC20.allowance\",\n      \"offset\": [\n        4068,\n        4095\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"3\"\n    },\n    \"1713\": {\n      \"fn\": \"ERC20.allowance\",\n      \"offset\": [\n        4068,\n        4095\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"1714\": {\n      \"fn\": \"ERC20.allowance\",\n      \"offset\": [\n        4068,\n        4095\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"3\"\n    },\n    \"1715\": {\n      \"fn\": \"ERC20.allowance\",\n      \"offset\": [\n        4068,\n        4095\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"1716\": {\n      \"fn\": \"ERC20.allowance\",\n      \"offset\": [\n        4068,\n        4095\n      ],\n      \"op\": \"KECCAK256\",\n      \"path\": \"3\"\n    },\n    \"1717\": {\n      \"fn\": \"ERC20.allowance\",\n      \"offset\": [\n        4068,\n        4095\n      ],\n      \"op\": \"SLOAD\",\n      \"path\": \"3\"\n    },\n    \"1718\": {\n      \"fn\": \"ERC20.allowance\",\n      \"offset\": [\n        4068,\n        4095\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"1719\": {\n      \"fn\": \"ERC20.allowance\",\n      \"jump\": \"o\",\n      \"offset\": [\n        3953,\n        4102\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"3\"\n    },\n    \"1720\": {\n      \"fn\": \"SafeMath.add\",\n      \"offset\": [\n        874,\n        1050\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"12\"\n    },\n    \"1721\": {\n      \"fn\": \"SafeMath.add\",\n      \"offset\": [\n        932,\n        939\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"12\",\n      \"value\": \"0x0\"\n    },\n    \"1723\": {\n      \"fn\": \"SafeMath.add\",\n      \"offset\": [\n        963,\n        968\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"12\"\n    },\n    \"1724\": {\n      \"fn\": \"SafeMath.add\",\n      \"offset\": [\n        963,\n        968\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"12\"\n    },\n    \"1725\": {\n      \"fn\": \"SafeMath.add\",\n      \"offset\": [\n        963,\n        968\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"12\"\n    },\n    \"1726\": {\n      \"fn\": \"SafeMath.add\",\n      \"offset\": [\n        986,\n        992\n      ],\n      \"op\": \"DUP4\",\n      \"path\": \"12\",\n      \"statement\": 18\n    },\n    \"1727\": {\n      \"fn\": \"SafeMath.add\",\n      \"offset\": [\n        986,\n        992\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"12\"\n    },\n    \"1728\": {\n      \"fn\": \"SafeMath.add\",\n      \"offset\": [\n        986,\n        992\n      ],\n      \"op\": \"LT\",\n      \"path\": \"12\"\n    },\n    \"1729\": {\n      \"branch\": 49,\n      \"fn\": \"SafeMath.add\",\n      \"offset\": [\n        986,\n        992\n      ],\n      \"op\": \"ISZERO\",\n      \"path\": \"12\"\n    },\n    \"1730\": {\n      \"fn\": \"SafeMath.add\",\n      \"offset\": [\n        978,\n        1024\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"12\",\n      \"value\": \"0x712\"\n    },\n    \"1733\": {\n      \"branch\": 49,\n      \"fn\": \"SafeMath.add\",\n      \"offset\": [\n        978,\n        1024\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"12\"\n    },\n    \"1734\": {\n      \"fn\": \"SafeMath.add\",\n      \"offset\": [\n        978,\n        1024\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"12\",\n      \"value\": \"0x40\"\n    },\n    \"1736\": {\n      \"fn\": \"SafeMath.add\",\n      \"offset\": [\n        978,\n        1024\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"12\"\n    },\n    \"1737\": {\n      \"fn\": \"SafeMath.add\",\n      \"offset\": [\n        978,\n        1024\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"12\"\n    },\n    \"1738\": {\n      \"op\": \"PUSH3\",\n      \"value\": \"0x461BCD\"\n    },\n    \"1742\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0xE5\"\n    },\n    \"1744\": {\n      \"op\": \"SHL\"\n    },\n    \"1745\": {\n      \"fn\": \"SafeMath.add\",\n      \"offset\": [\n        978,\n        1024\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"12\"\n    },\n    \"1746\": {\n      \"fn\": \"SafeMath.add\",\n      \"offset\": [\n        978,\n        1024\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"12\"\n    },\n    \"1747\": {\n      \"fn\": \"SafeMath.add\",\n      \"offset\": [\n        978,\n        1024\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"12\",\n      \"value\": \"0x20\"\n    },\n    \"1749\": {\n      \"fn\": \"SafeMath.add\",\n      \"offset\": [\n        978,\n        1024\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"12\",\n      \"value\": \"0x4\"\n    },\n    \"1751\": {\n      \"fn\": \"SafeMath.add\",\n      \"offset\": [\n        978,\n        1024\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"12\"\n    },\n    \"1752\": {\n      \"fn\": \"SafeMath.add\",\n      \"offset\": [\n        978,\n        1024\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"12\"\n    },\n    \"1753\": {\n      \"fn\": \"SafeMath.add\",\n      \"offset\": [\n        978,\n        1024\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"12\"\n    },\n    \"1754\": {\n      \"fn\": \"SafeMath.add\",\n      \"offset\": [\n        978,\n        1024\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"12\",\n      \"value\": \"0x1B\"\n    },\n    \"1756\": {\n      \"fn\": \"SafeMath.add\",\n      \"offset\": [\n        978,\n        1024\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"12\",\n      \"value\": \"0x24\"\n    },\n    \"1758\": {\n      \"fn\": \"SafeMath.add\",\n      \"offset\": [\n        978,\n        1024\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"12\"\n    },\n    \"1759\": {\n      \"fn\": \"SafeMath.add\",\n      \"offset\": [\n        978,\n        1024\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"12\"\n    },\n    \"1760\": {\n      \"fn\": \"SafeMath.add\",\n      \"offset\": [\n        978,\n        1024\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"12\"\n    },\n    \"1761\": {\n      \"fn\": \"SafeMath.add\",\n      \"offset\": [\n        978,\n        1024\n      ],\n      \"op\": \"PUSH32\",\n      \"path\": \"12\",\n      \"value\": \"0x536166654D6174683A206164646974696F6E206F766572666C6F770000000000\"\n    },\n    \"1794\": {\n      \"fn\": \"SafeMath.add\",\n      \"offset\": [\n        978,\n        1024\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"12\",\n      \"value\": \"0x44\"\n    },\n    \"1796\": {\n      \"fn\": \"SafeMath.add\",\n      \"offset\": [\n        978,\n        1024\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"12\"\n    },\n    \"1797\": {\n      \"fn\": \"SafeMath.add\",\n      \"offset\": [\n        978,\n        1024\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"12\"\n    },\n    \"1798\": {\n      \"fn\": \"SafeMath.add\",\n      \"offset\": [\n        978,\n        1024\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"12\"\n    },\n    \"1799\": {\n      \"fn\": \"SafeMath.add\",\n      \"offset\": [\n        978,\n        1024\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"12\"\n    },\n    \"1800\": {\n      \"fn\": \"SafeMath.add\",\n      \"offset\": [\n        978,\n        1024\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"12\"\n    },\n    \"1801\": {\n      \"fn\": \"SafeMath.add\",\n      \"offset\": [\n        978,\n        1024\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"12\"\n    },\n    \"1802\": {\n      \"fn\": \"SafeMath.add\",\n      \"offset\": [\n        978,\n        1024\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"12\"\n    },\n    \"1803\": {\n      \"fn\": \"SafeMath.add\",\n      \"offset\": [\n        978,\n        1024\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"12\"\n    },\n    \"1804\": {\n      \"fn\": \"SafeMath.add\",\n      \"offset\": [\n        978,\n        1024\n      ],\n      \"op\": \"SUB\",\n      \"path\": \"12\"\n    },\n    \"1805\": {\n      \"fn\": \"SafeMath.add\",\n      \"offset\": [\n        978,\n        1024\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"12\",\n      \"value\": \"0x64\"\n    },\n    \"1807\": {\n      \"fn\": \"SafeMath.add\",\n      \"offset\": [\n        978,\n        1024\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"12\"\n    },\n    \"1808\": {\n      \"fn\": \"SafeMath.add\",\n      \"offset\": [\n        978,\n        1024\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"12\"\n    },\n    \"1809\": {\n      \"fn\": \"SafeMath.add\",\n      \"offset\": [\n        978,\n        1024\n      ],\n      \"op\": \"REVERT\",\n      \"path\": \"12\"\n    },\n    \"1810\": {\n      \"fn\": \"SafeMath.add\",\n      \"offset\": [\n        978,\n        1024\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"12\"\n    },\n    \"1811\": {\n      \"fn\": \"SafeMath.add\",\n      \"offset\": [\n        1042,\n        1043\n      ],\n      \"op\": \"SWAP4\",\n      \"path\": \"12\",\n      \"statement\": 19\n    },\n    \"1812\": {\n      \"fn\": \"SafeMath.add\",\n      \"offset\": [\n        874,\n        1050\n      ],\n      \"op\": \"SWAP3\",\n      \"path\": \"12\"\n    },\n    \"1813\": {\n      \"op\": \"POP\"\n    },\n    \"1814\": {\n      \"op\": \"POP\"\n    },\n    \"1815\": {\n      \"op\": \"POP\"\n    },\n    \"1816\": {\n      \"fn\": \"SafeMath.add\",\n      \"jump\": \"o\",\n      \"offset\": [\n        874,\n        1050\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"12\"\n    },\n    \"1817\": {\n      \"fn\": \"Context._msgSender\",\n      \"offset\": [\n        590,\n        694\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"2\"\n    },\n    \"1818\": {\n      \"fn\": \"Context._msgSender\",\n      \"offset\": [\n        677,\n        687\n      ],\n      \"op\": \"CALLER\",\n      \"path\": \"2\",\n      \"statement\": 20\n    },\n    \"1819\": {\n      \"fn\": \"Context._msgSender\",\n      \"offset\": [\n        590,\n        694\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"2\"\n    },\n    \"1820\": {\n      \"fn\": \"Context._msgSender\",\n      \"jump\": \"o\",\n      \"offset\": [\n        590,\n        694\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"2\"\n    },\n    \"1821\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9344,\n        9684\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"3\"\n    },\n    \"1822\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"1824\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"1826\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0xA0\"\n    },\n    \"1828\": {\n      \"op\": \"SHL\"\n    },\n    \"1829\": {\n      \"op\": \"SUB\"\n    },\n    \"1830\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9445,\n        9464\n      ],\n      \"op\": \"DUP4\",\n      \"path\": \"3\",\n      \"statement\": 21\n    },\n    \"1831\": {\n      \"branch\": 43,\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9445,\n        9464\n      ],\n      \"op\": \"AND\",\n      \"path\": \"3\"\n    },\n    \"1832\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9437,\n        9505\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x762\"\n    },\n    \"1835\": {\n      \"branch\": 43,\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9437,\n        9505\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"3\"\n    },\n    \"1836\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9437,\n        9505\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x40\"\n    },\n    \"1838\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9437,\n        9505\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"3\"\n    },\n    \"1839\": {\n      \"op\": \"PUSH3\",\n      \"value\": \"0x461BCD\"\n    },\n    \"1843\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0xE5\"\n    },\n    \"1845\": {\n      \"op\": \"SHL\"\n    },\n    \"1846\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9437,\n        9505\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"1847\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9437,\n        9505\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"1848\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9437,\n        9505\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x4\"\n    },\n    \"1850\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9437,\n        9505\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"1851\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9437,\n        9505\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"1852\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9437,\n        9505\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"1853\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9437,\n        9505\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x20\"\n    },\n    \"1855\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9437,\n        9505\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"1856\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9437,\n        9505\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"3\"\n    },\n    \"1857\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9437,\n        9505\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"1858\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9437,\n        9505\n      ],\n      \"op\": \"SUB\",\n      \"path\": \"3\"\n    },\n    \"1859\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9437,\n        9505\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"3\"\n    },\n    \"1860\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9437,\n        9505\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"1861\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9437,\n        9505\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x24\"\n    },\n    \"1863\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9437,\n        9505\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"1864\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9437,\n        9505\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"1865\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9437,\n        9505\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x20\"\n    },\n    \"1867\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9437,\n        9505\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"1868\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9437,\n        9505\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"1869\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9437,\n        9505\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0xD25\"\n    },\n    \"1872\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9437,\n        9505\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x24\"\n    },\n    \"1874\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9437,\n        9505\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"3\"\n    },\n    \"1875\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9437,\n        9505\n      ],\n      \"op\": \"CODECOPY\",\n      \"path\": \"3\"\n    },\n    \"1876\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9437,\n        9505\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x40\"\n    },\n    \"1878\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9437,\n        9505\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"1879\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9437,\n        9505\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"3\"\n    },\n    \"1880\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9437,\n        9505\n      ],\n      \"op\": \"POP\",\n      \"path\": \"3\"\n    },\n    \"1881\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9437,\n        9505\n      ],\n      \"op\": \"POP\",\n      \"path\": \"3\"\n    },\n    \"1882\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9437,\n        9505\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x40\"\n    },\n    \"1884\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9437,\n        9505\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"3\"\n    },\n    \"1885\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9437,\n        9505\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"1886\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9437,\n        9505\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"3\"\n    },\n    \"1887\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9437,\n        9505\n      ],\n      \"op\": \"SUB\",\n      \"path\": \"3\"\n    },\n    \"1888\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9437,\n        9505\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"1889\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9437,\n        9505\n      ],\n      \"op\": \"REVERT\",\n      \"path\": \"3\"\n    },\n    \"1890\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9437,\n        9505\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"3\"\n    },\n    \"1891\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"1893\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"1895\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0xA0\"\n    },\n    \"1897\": {\n      \"op\": \"SHL\"\n    },\n    \"1898\": {\n      \"op\": \"SUB\"\n    },\n    \"1899\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9523,\n        9544\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"3\",\n      \"statement\": 22\n    },\n    \"1900\": {\n      \"branch\": 44,\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9523,\n        9544\n      ],\n      \"op\": \"AND\",\n      \"path\": \"3\"\n    },\n    \"1901\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9515,\n        9583\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x7A7\"\n    },\n    \"1904\": {\n      \"branch\": 44,\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9515,\n        9583\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"3\"\n    },\n    \"1905\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9515,\n        9583\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x40\"\n    },\n    \"1907\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9515,\n        9583\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"3\"\n    },\n    \"1908\": {\n      \"op\": \"PUSH3\",\n      \"value\": \"0x461BCD\"\n    },\n    \"1912\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0xE5\"\n    },\n    \"1914\": {\n      \"op\": \"SHL\"\n    },\n    \"1915\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9515,\n        9583\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"1916\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9515,\n        9583\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"1917\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9515,\n        9583\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x4\"\n    },\n    \"1919\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9515,\n        9583\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"1920\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9515,\n        9583\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"1921\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9515,\n        9583\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"1922\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9515,\n        9583\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x20\"\n    },\n    \"1924\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9515,\n        9583\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"1925\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9515,\n        9583\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"3\"\n    },\n    \"1926\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9515,\n        9583\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"1927\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9515,\n        9583\n      ],\n      \"op\": \"SUB\",\n      \"path\": \"3\"\n    },\n    \"1928\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9515,\n        9583\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"3\"\n    },\n    \"1929\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9515,\n        9583\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"1930\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9515,\n        9583\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x22\"\n    },\n    \"1932\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9515,\n        9583\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"1933\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9515,\n        9583\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"1934\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9515,\n        9583\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x20\"\n    },\n    \"1936\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9515,\n        9583\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"1937\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9515,\n        9583\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"1938\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9515,\n        9583\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0xC6F\"\n    },\n    \"1941\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9515,\n        9583\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x22\"\n    },\n    \"1943\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9515,\n        9583\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"3\"\n    },\n    \"1944\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9515,\n        9583\n      ],\n      \"op\": \"CODECOPY\",\n      \"path\": \"3\"\n    },\n    \"1945\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9515,\n        9583\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x40\"\n    },\n    \"1947\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9515,\n        9583\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"1948\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9515,\n        9583\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"3\"\n    },\n    \"1949\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9515,\n        9583\n      ],\n      \"op\": \"POP\",\n      \"path\": \"3\"\n    },\n    \"1950\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9515,\n        9583\n      ],\n      \"op\": \"POP\",\n      \"path\": \"3\"\n    },\n    \"1951\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9515,\n        9583\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x40\"\n    },\n    \"1953\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9515,\n        9583\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"3\"\n    },\n    \"1954\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9515,\n        9583\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"1955\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9515,\n        9583\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"3\"\n    },\n    \"1956\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9515,\n        9583\n      ],\n      \"op\": \"SUB\",\n      \"path\": \"3\"\n    },\n    \"1957\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9515,\n        9583\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"1958\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9515,\n        9583\n      ],\n      \"op\": \"REVERT\",\n      \"path\": \"3\"\n    },\n    \"1959\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9515,\n        9583\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"3\"\n    },\n    \"1960\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"1962\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"1964\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0xA0\"\n    },\n    \"1966\": {\n      \"op\": \"SHL\"\n    },\n    \"1967\": {\n      \"op\": \"SUB\"\n    },\n    \"1968\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9594,\n        9612\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\",\n      \"statement\": 23\n    },\n    \"1969\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9594,\n        9612\n      ],\n      \"op\": \"DUP5\",\n      \"path\": \"3\"\n    },\n    \"1970\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9594,\n        9612\n      ],\n      \"op\": \"AND\",\n      \"path\": \"3\"\n    },\n    \"1971\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9594,\n        9612\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x0\"\n    },\n    \"1973\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9594,\n        9612\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"1974\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9594,\n        9612\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"1975\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9594,\n        9612\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"1976\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9594,\n        9605\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x1\"\n    },\n    \"1978\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9594,\n        9612\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x20\"\n    },\n    \"1980\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9594,\n        9612\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"1981\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9594,\n        9612\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"1982\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9594,\n        9612\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"1983\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9594,\n        9612\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x40\"\n    },\n    \"1985\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9594,\n        9612\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"1986\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9594,\n        9612\n      ],\n      \"op\": \"DUP4\",\n      \"path\": \"3\"\n    },\n    \"1987\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9594,\n        9612\n      ],\n      \"op\": \"KECCAK256\",\n      \"path\": \"3\"\n    },\n    \"1988\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9594,\n        9621\n      ],\n      \"op\": \"SWAP5\",\n      \"path\": \"3\"\n    },\n    \"1989\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9594,\n        9621\n      ],\n      \"op\": \"DUP8\",\n      \"path\": \"3\"\n    },\n    \"1990\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9594,\n        9621\n      ],\n      \"op\": \"AND\",\n      \"path\": \"3\"\n    },\n    \"1991\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9594,\n        9621\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"1992\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9594,\n        9621\n      ],\n      \"op\": \"DUP5\",\n      \"path\": \"3\"\n    },\n    \"1993\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9594,\n        9621\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"1994\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9594,\n        9621\n      ],\n      \"op\": \"SWAP5\",\n      \"path\": \"3\"\n    },\n    \"1995\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9594,\n        9621\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"3\"\n    },\n    \"1996\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9594,\n        9621\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"1997\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9594,\n        9621\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"3\"\n    },\n    \"1998\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9594,\n        9621\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"3\"\n    },\n    \"1999\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9594,\n        9621\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"2000\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9594,\n        9621\n      ],\n      \"op\": \"KECCAK256\",\n      \"path\": \"3\"\n    },\n    \"2001\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9594,\n        9630\n      ],\n      \"op\": \"DUP6\",\n      \"path\": \"3\"\n    },\n    \"2002\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9594,\n        9630\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"2003\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9594,\n        9630\n      ],\n      \"op\": \"SSTORE\",\n      \"path\": \"3\"\n    },\n    \"2004\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9645,\n        9677\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\",\n      \"statement\": 24\n    },\n    \"2005\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9645,\n        9677\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"3\"\n    },\n    \"2006\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9645,\n        9677\n      ],\n      \"op\": \"DUP6\",\n      \"path\": \"3\"\n    },\n    \"2007\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9645,\n        9677\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"2008\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9645,\n        9677\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"2009\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9645,\n        9677\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"3\"\n    },\n    \"2010\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9645,\n        9677\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"3\"\n    },\n    \"2011\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9645,\n        9677\n      ],\n      \"op\": \"PUSH32\",\n      \"path\": \"3\",\n      \"value\": \"0x8C5BE1E5EBEC7D5BD14F71427D1E84F3DD0314C0F7B2291E5B200AC8C7C3B925\"\n    },\n    \"2044\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9645,\n        9677\n      ],\n      \"op\": \"SWAP3\",\n      \"path\": \"3\"\n    },\n    \"2045\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9645,\n        9677\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"2046\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9645,\n        9677\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"2047\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9645,\n        9677\n      ],\n      \"op\": \"SUB\",\n      \"path\": \"3\"\n    },\n    \"2048\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9645,\n        9677\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"2049\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9645,\n        9677\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"3\"\n    },\n    \"2050\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9645,\n        9677\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"2051\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9645,\n        9677\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"2052\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9645,\n        9677\n      ],\n      \"op\": \"LOG3\",\n      \"path\": \"3\"\n    },\n    \"2053\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9344,\n        9684\n      ],\n      \"op\": \"POP\",\n      \"path\": \"3\"\n    },\n    \"2054\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9344,\n        9684\n      ],\n      \"op\": \"POP\",\n      \"path\": \"3\"\n    },\n    \"2055\": {\n      \"fn\": \"ERC20._approve\",\n      \"offset\": [\n        9344,\n        9684\n      ],\n      \"op\": \"POP\",\n      \"path\": \"3\"\n    },\n    \"2056\": {\n      \"fn\": \"ERC20._approve\",\n      \"jump\": \"o\",\n      \"offset\": [\n        9344,\n        9684\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"3\"\n    },\n    \"2057\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7020,\n        7550\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"3\"\n    },\n    \"2058\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"2060\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"2062\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0xA0\"\n    },\n    \"2064\": {\n      \"op\": \"SHL\"\n    },\n    \"2065\": {\n      \"op\": \"SUB\"\n    },\n    \"2066\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7125,\n        7145\n      ],\n      \"op\": \"DUP4\",\n      \"path\": \"3\",\n      \"statement\": 25\n    },\n    \"2067\": {\n      \"branch\": 45,\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7125,\n        7145\n      ],\n      \"op\": \"AND\",\n      \"path\": \"3\"\n    },\n    \"2068\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7117,\n        7187\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x84E\"\n    },\n    \"2071\": {\n      \"branch\": 45,\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7117,\n        7187\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"3\"\n    },\n    \"2072\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7117,\n        7187\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x40\"\n    },\n    \"2074\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7117,\n        7187\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"3\"\n    },\n    \"2075\": {\n      \"op\": \"PUSH3\",\n      \"value\": \"0x461BCD\"\n    },\n    \"2079\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0xE5\"\n    },\n    \"2081\": {\n      \"op\": \"SHL\"\n    },\n    \"2082\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7117,\n        7187\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"2083\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7117,\n        7187\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"2084\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7117,\n        7187\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x4\"\n    },\n    \"2086\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7117,\n        7187\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"2087\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7117,\n        7187\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"2088\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7117,\n        7187\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"2089\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7117,\n        7187\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x20\"\n    },\n    \"2091\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7117,\n        7187\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"2092\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7117,\n        7187\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"3\"\n    },\n    \"2093\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7117,\n        7187\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"2094\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7117,\n        7187\n      ],\n      \"op\": \"SUB\",\n      \"path\": \"3\"\n    },\n    \"2095\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7117,\n        7187\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"3\"\n    },\n    \"2096\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7117,\n        7187\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"2097\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7117,\n        7187\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x25\"\n    },\n    \"2099\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7117,\n        7187\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"2100\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7117,\n        7187\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"2101\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7117,\n        7187\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x20\"\n    },\n    \"2103\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7117,\n        7187\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"2104\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7117,\n        7187\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"2105\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7117,\n        7187\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0xD00\"\n    },\n    \"2108\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7117,\n        7187\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x25\"\n    },\n    \"2110\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7117,\n        7187\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"3\"\n    },\n    \"2111\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7117,\n        7187\n      ],\n      \"op\": \"CODECOPY\",\n      \"path\": \"3\"\n    },\n    \"2112\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7117,\n        7187\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x40\"\n    },\n    \"2114\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7117,\n        7187\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"2115\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7117,\n        7187\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"3\"\n    },\n    \"2116\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7117,\n        7187\n      ],\n      \"op\": \"POP\",\n      \"path\": \"3\"\n    },\n    \"2117\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7117,\n        7187\n      ],\n      \"op\": \"POP\",\n      \"path\": \"3\"\n    },\n    \"2118\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7117,\n        7187\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x40\"\n    },\n    \"2120\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7117,\n        7187\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"3\"\n    },\n    \"2121\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7117,\n        7187\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"2122\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7117,\n        7187\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"3\"\n    },\n    \"2123\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7117,\n        7187\n      ],\n      \"op\": \"SUB\",\n      \"path\": \"3\"\n    },\n    \"2124\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7117,\n        7187\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"2125\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7117,\n        7187\n      ],\n      \"op\": \"REVERT\",\n      \"path\": \"3\"\n    },\n    \"2126\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7117,\n        7187\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"3\"\n    },\n    \"2127\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"2129\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"2131\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0xA0\"\n    },\n    \"2133\": {\n      \"op\": \"SHL\"\n    },\n    \"2134\": {\n      \"op\": \"SUB\"\n    },\n    \"2135\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7205,\n        7228\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"3\",\n      \"statement\": 26\n    },\n    \"2136\": {\n      \"branch\": 46,\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7205,\n        7228\n      ],\n      \"op\": \"AND\",\n      \"path\": \"3\"\n    },\n    \"2137\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7197,\n        7268\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x893\"\n    },\n    \"2140\": {\n      \"branch\": 46,\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7197,\n        7268\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"3\"\n    },\n    \"2141\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7197,\n        7268\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x40\"\n    },\n    \"2143\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7197,\n        7268\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"3\"\n    },\n    \"2144\": {\n      \"op\": \"PUSH3\",\n      \"value\": \"0x461BCD\"\n    },\n    \"2148\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0xE5\"\n    },\n    \"2150\": {\n      \"op\": \"SHL\"\n    },\n    \"2151\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7197,\n        7268\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"2152\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7197,\n        7268\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"2153\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7197,\n        7268\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x4\"\n    },\n    \"2155\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7197,\n        7268\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"2156\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7197,\n        7268\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"2157\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7197,\n        7268\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"2158\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7197,\n        7268\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x20\"\n    },\n    \"2160\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7197,\n        7268\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"2161\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7197,\n        7268\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"3\"\n    },\n    \"2162\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7197,\n        7268\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"2163\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7197,\n        7268\n      ],\n      \"op\": \"SUB\",\n      \"path\": \"3\"\n    },\n    \"2164\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7197,\n        7268\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"3\"\n    },\n    \"2165\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7197,\n        7268\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"2166\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7197,\n        7268\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x23\"\n    },\n    \"2168\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7197,\n        7268\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"2169\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7197,\n        7268\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"2170\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7197,\n        7268\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x20\"\n    },\n    \"2172\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7197,\n        7268\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"2173\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7197,\n        7268\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"2174\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7197,\n        7268\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0xC2A\"\n    },\n    \"2177\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7197,\n        7268\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x23\"\n    },\n    \"2179\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7197,\n        7268\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"3\"\n    },\n    \"2180\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7197,\n        7268\n      ],\n      \"op\": \"CODECOPY\",\n      \"path\": \"3\"\n    },\n    \"2181\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7197,\n        7268\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x40\"\n    },\n    \"2183\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7197,\n        7268\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"2184\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7197,\n        7268\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"3\"\n    },\n    \"2185\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7197,\n        7268\n      ],\n      \"op\": \"POP\",\n      \"path\": \"3\"\n    },\n    \"2186\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7197,\n        7268\n      ],\n      \"op\": \"POP\",\n      \"path\": \"3\"\n    },\n    \"2187\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7197,\n        7268\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x40\"\n    },\n    \"2189\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7197,\n        7268\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"3\"\n    },\n    \"2190\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7197,\n        7268\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"2191\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7197,\n        7268\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"3\"\n    },\n    \"2192\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7197,\n        7268\n      ],\n      \"op\": \"SUB\",\n      \"path\": \"3\"\n    },\n    \"2193\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7197,\n        7268\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"2194\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7197,\n        7268\n      ],\n      \"op\": \"REVERT\",\n      \"path\": \"3\"\n    },\n    \"2195\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7197,\n        7268\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"3\"\n    },\n    \"2196\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7279,\n        7326\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"statement\": 27,\n      \"value\": \"0x89E\"\n    },\n    \"2199\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7300,\n        7306\n      ],\n      \"op\": \"DUP4\",\n      \"path\": \"3\"\n    },\n    \"2200\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7308,\n        7317\n      ],\n      \"op\": \"DUP4\",\n      \"path\": \"3\"\n    },\n    \"2201\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7319,\n        7325\n      ],\n      \"op\": \"DUP4\",\n      \"path\": \"3\"\n    },\n    \"2202\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7279,\n        7299\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x48F\"\n    },\n    \"2205\": {\n      \"fn\": \"ERC20._transfer\",\n      \"jump\": \"i\",\n      \"offset\": [\n        7279,\n        7326\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"3\"\n    },\n    \"2206\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7279,\n        7326\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"3\"\n    },\n    \"2207\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7357,\n        7428\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"statement\": 28,\n      \"value\": \"0x8DB\"\n    },\n    \"2210\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7379,\n        7385\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"2211\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7357,\n        7428\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x40\"\n    },\n    \"2213\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7357,\n        7428\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"3\"\n    },\n    \"2214\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7357,\n        7428\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"2215\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7357,\n        7428\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x60\"\n    },\n    \"2217\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7357,\n        7428\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"2218\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7357,\n        7428\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x40\"\n    },\n    \"2220\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7357,\n        7428\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"2221\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7357,\n        7428\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"2222\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7357,\n        7428\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x26\"\n    },\n    \"2224\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7357,\n        7428\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"2225\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7357,\n        7428\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"2226\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7357,\n        7428\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x20\"\n    },\n    \"2228\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7357,\n        7428\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"2229\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7357,\n        7428\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0xC91\"\n    },\n    \"2232\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7357,\n        7428\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x26\"\n    },\n    \"2234\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7357,\n        7428\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"3\"\n    },\n    \"2235\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7357,\n        7428\n      ],\n      \"op\": \"CODECOPY\",\n      \"path\": \"3\"\n    },\n    \"2236\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"2238\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"2240\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0xA0\"\n    },\n    \"2242\": {\n      \"op\": \"SHL\"\n    },\n    \"2243\": {\n      \"op\": \"SUB\"\n    },\n    \"2244\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7357,\n        7374\n      ],\n      \"op\": \"DUP7\",\n      \"path\": \"3\"\n    },\n    \"2245\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7357,\n        7374\n      ],\n      \"op\": \"AND\",\n      \"path\": \"3\"\n    },\n    \"2246\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7357,\n        7366\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x0\"\n    },\n    \"2248\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7357,\n        7374\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"2249\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7357,\n        7374\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"2250\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7357,\n        7374\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"2251\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7357,\n        7374\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x20\"\n    },\n    \"2253\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7357,\n        7374\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"2254\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7357,\n        7374\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"2255\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7357,\n        7374\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"2256\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7357,\n        7374\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x40\"\n    },\n    \"2258\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7357,\n        7374\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"2259\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7357,\n        7374\n      ],\n      \"op\": \"KECCAK256\",\n      \"path\": \"3\"\n    },\n    \"2260\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7357,\n        7374\n      ],\n      \"op\": \"SLOAD\",\n      \"path\": \"3\"\n    },\n    \"2261\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7357,\n        7374\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"3\"\n    },\n    \"2262\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7357,\n        7428\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"2263\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7357,\n        7378\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x964\"\n    },\n    \"2266\": {\n      \"fn\": \"ERC20._transfer\",\n      \"jump\": \"i\",\n      \"offset\": [\n        7357,\n        7428\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"3\"\n    },\n    \"2267\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7357,\n        7428\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"3\"\n    },\n    \"2268\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"2270\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"2272\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0xA0\"\n    },\n    \"2274\": {\n      \"op\": \"SHL\"\n    },\n    \"2275\": {\n      \"op\": \"SUB\"\n    },\n    \"2276\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7337,\n        7354\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"2277\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7337,\n        7354\n      ],\n      \"op\": \"DUP6\",\n      \"path\": \"3\"\n    },\n    \"2278\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7337,\n        7354\n      ],\n      \"op\": \"AND\",\n      \"path\": \"3\"\n    },\n    \"2279\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7337,\n        7346\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x0\"\n    },\n    \"2281\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7337,\n        7354\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"2282\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7337,\n        7354\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"2283\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7337,\n        7354\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"2284\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7337,\n        7354\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x20\"\n    },\n    \"2286\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7337,\n        7354\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"2287\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7337,\n        7354\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"2288\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7337,\n        7354\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"2289\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7337,\n        7354\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x40\"\n    },\n    \"2291\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7337,\n        7354\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"2292\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7337,\n        7354\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"3\"\n    },\n    \"2293\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7337,\n        7354\n      ],\n      \"op\": \"KECCAK256\",\n      \"path\": \"3\"\n    },\n    \"2294\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7337,\n        7428\n      ],\n      \"op\": \"SWAP4\",\n      \"path\": \"3\"\n    },\n    \"2295\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7337,\n        7428\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"2296\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7337,\n        7428\n      ],\n      \"op\": \"SWAP4\",\n      \"path\": \"3\"\n    },\n    \"2297\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7337,\n        7428\n      ],\n      \"op\": \"SSTORE\",\n      \"path\": \"3\"\n    },\n    \"2298\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7461,\n        7481\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\",\n      \"statement\": 29\n    },\n    \"2299\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7461,\n        7481\n      ],\n      \"op\": \"DUP5\",\n      \"path\": \"3\"\n    },\n    \"2300\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7461,\n        7481\n      ],\n      \"op\": \"AND\",\n      \"path\": \"3\"\n    },\n    \"2301\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7461,\n        7481\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"2302\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7461,\n        7481\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"2303\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7461,\n        7481\n      ],\n      \"op\": \"KECCAK256\",\n      \"path\": \"3\"\n    },\n    \"2304\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7461,\n        7481\n      ],\n      \"op\": \"SLOAD\",\n      \"path\": \"3\"\n    },\n    \"2305\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7461,\n        7493\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x90A\"\n    },\n    \"2308\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7461,\n        7493\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"2309\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7486,\n        7492\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"3\"\n    },\n    \"2310\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7461,\n        7485\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x6B8\"\n    },\n    \"2313\": {\n      \"fn\": \"ERC20._transfer\",\n      \"jump\": \"i\",\n      \"offset\": [\n        7461,\n        7493\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"3\"\n    },\n    \"2314\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7461,\n        7493\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"3\"\n    },\n    \"2315\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"2317\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"2319\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0xA0\"\n    },\n    \"2321\": {\n      \"op\": \"SHL\"\n    },\n    \"2322\": {\n      \"op\": \"SUB\"\n    },\n    \"2323\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7438,\n        7458\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"2324\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7438,\n        7458\n      ],\n      \"op\": \"DUP5\",\n      \"path\": \"3\"\n    },\n    \"2325\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7438,\n        7458\n      ],\n      \"op\": \"AND\",\n      \"path\": \"3\"\n    },\n    \"2326\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7438,\n        7447\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x0\"\n    },\n    \"2328\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7438,\n        7458\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"2329\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7438,\n        7458\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"2330\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7438,\n        7458\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"2331\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7438,\n        7458\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x20\"\n    },\n    \"2333\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7438,\n        7458\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"2334\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7438,\n        7458\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"2335\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7438,\n        7458\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"2336\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7438,\n        7458\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x40\"\n    },\n    \"2338\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7438,\n        7458\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"3\"\n    },\n    \"2339\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7438,\n        7458\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"3\"\n    },\n    \"2340\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7438,\n        7458\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"2341\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7438,\n        7458\n      ],\n      \"op\": \"KECCAK256\",\n      \"path\": \"3\"\n    },\n    \"2342\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7438,\n        7493\n      ],\n      \"op\": \"SWAP5\",\n      \"path\": \"3\"\n    },\n    \"2343\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7438,\n        7493\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"2344\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7438,\n        7493\n      ],\n      \"op\": \"SWAP5\",\n      \"path\": \"3\"\n    },\n    \"2345\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7438,\n        7493\n      ],\n      \"op\": \"SSTORE\",\n      \"path\": \"3\"\n    },\n    \"2346\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7508,\n        7543\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\",\n      \"statement\": 30\n    },\n    \"2347\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7508,\n        7543\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"3\"\n    },\n    \"2348\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7508,\n        7543\n      ],\n      \"op\": \"DUP6\",\n      \"path\": \"3\"\n    },\n    \"2349\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7508,\n        7543\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"2350\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7508,\n        7543\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"2351\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7508,\n        7543\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"2352\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7508,\n        7543\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"3\"\n    },\n    \"2353\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7438,\n        7458\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"3\"\n    },\n    \"2354\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7438,\n        7458\n      ],\n      \"op\": \"SWAP4\",\n      \"path\": \"3\"\n    },\n    \"2355\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7508,\n        7543\n      ],\n      \"op\": \"SWAP3\",\n      \"path\": \"3\"\n    },\n    \"2356\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7508,\n        7543\n      ],\n      \"op\": \"DUP8\",\n      \"path\": \"3\"\n    },\n    \"2357\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7508,\n        7543\n      ],\n      \"op\": \"AND\",\n      \"path\": \"3\"\n    },\n    \"2358\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7508,\n        7543\n      ],\n      \"op\": \"SWAP3\",\n      \"path\": \"3\"\n    },\n    \"2359\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7508,\n        7543\n      ],\n      \"op\": \"PUSH32\",\n      \"path\": \"3\",\n      \"value\": \"0xDDF252AD1BE2C89B69C2B068FC378DAA952BA7F163C4A11628F55A4DF523B3EF\"\n    },\n    \"2392\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7508,\n        7543\n      ],\n      \"op\": \"SWAP3\",\n      \"path\": \"3\"\n    },\n    \"2393\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7508,\n        7543\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"3\"\n    },\n    \"2394\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7508,\n        7543\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"3\"\n    },\n    \"2395\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7508,\n        7543\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"2396\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7508,\n        7543\n      ],\n      \"op\": \"SUB\",\n      \"path\": \"3\"\n    },\n    \"2397\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7508,\n        7543\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"2398\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7508,\n        7543\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"2399\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7508,\n        7543\n      ],\n      \"op\": \"LOG3\",\n      \"path\": \"3\"\n    },\n    \"2400\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7020,\n        7550\n      ],\n      \"op\": \"POP\",\n      \"path\": \"3\"\n    },\n    \"2401\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7020,\n        7550\n      ],\n      \"op\": \"POP\",\n      \"path\": \"3\"\n    },\n    \"2402\": {\n      \"fn\": \"ERC20._transfer\",\n      \"offset\": [\n        7020,\n        7550\n      ],\n      \"op\": \"POP\",\n      \"path\": \"3\"\n    },\n    \"2403\": {\n      \"fn\": \"ERC20._transfer\",\n      \"jump\": \"o\",\n      \"offset\": [\n        7020,\n        7550\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"3\"\n    },\n    \"2404\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1746,\n        1933\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"12\"\n    },\n    \"2405\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1832,\n        1839\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"12\",\n      \"value\": \"0x0\"\n    },\n    \"2407\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1867,\n        1879\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"12\",\n      \"statement\": 31\n    },\n    \"2408\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1859,\n        1865\n      ],\n      \"op\": \"DUP5\",\n      \"path\": \"12\"\n    },\n    \"2409\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1859,\n        1865\n      ],\n      \"op\": \"DUP5\",\n      \"path\": \"12\"\n    },\n    \"2410\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1859,\n        1865\n      ],\n      \"op\": \"GT\",\n      \"path\": \"12\"\n    },\n    \"2411\": {\n      \"branch\": 50,\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1859,\n        1865\n      ],\n      \"op\": \"ISZERO\",\n      \"path\": \"12\"\n    },\n    \"2412\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"12\",\n      \"value\": \"0x9F3\"\n    },\n    \"2415\": {\n      \"branch\": 50,\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"12\"\n    },\n    \"2416\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"12\",\n      \"value\": \"0x40\"\n    },\n    \"2418\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"12\"\n    },\n    \"2419\": {\n      \"op\": \"PUSH3\",\n      \"value\": \"0x461BCD\"\n    },\n    \"2423\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0xE5\"\n    },\n    \"2425\": {\n      \"op\": \"SHL\"\n    },\n    \"2426\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"12\"\n    },\n    \"2427\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"12\"\n    },\n    \"2428\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"12\",\n      \"value\": \"0x4\"\n    },\n    \"2430\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"12\"\n    },\n    \"2431\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"12\"\n    },\n    \"2432\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"12\"\n    },\n    \"2433\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"12\",\n      \"value\": \"0x20\"\n    },\n    \"2435\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"12\"\n    },\n    \"2436\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"12\"\n    },\n    \"2437\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"12\"\n    },\n    \"2438\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"SUB\",\n      \"path\": \"12\"\n    },\n    \"2439\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"12\"\n    },\n    \"2440\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"12\"\n    },\n    \"2441\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"DUP4\",\n      \"path\": \"12\"\n    },\n    \"2442\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"12\"\n    },\n    \"2443\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"12\"\n    },\n    \"2444\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"12\"\n    },\n    \"2445\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"12\"\n    },\n    \"2446\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"12\"\n    },\n    \"2447\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"12\",\n      \"value\": \"0x20\"\n    },\n    \"2449\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"12\"\n    },\n    \"2450\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"12\"\n    },\n    \"2451\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"POP\",\n      \"path\": \"12\"\n    },\n    \"2452\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"12\"\n    },\n    \"2453\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"12\"\n    },\n    \"2454\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"12\"\n    },\n    \"2455\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"12\",\n      \"value\": \"0x20\"\n    },\n    \"2457\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"12\"\n    },\n    \"2458\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"12\"\n    },\n    \"2459\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"12\"\n    },\n    \"2460\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"DUP4\",\n      \"path\": \"12\"\n    },\n    \"2461\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"DUP4\",\n      \"path\": \"12\"\n    },\n    \"2462\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"12\",\n      \"value\": \"0x0\"\n    },\n    \"2464\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"12\"\n    },\n    \"2465\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"DUP4\",\n      \"path\": \"12\"\n    },\n    \"2466\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"12\"\n    },\n    \"2467\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"LT\",\n      \"path\": \"12\"\n    },\n    \"2468\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"ISZERO\",\n      \"path\": \"12\"\n    },\n    \"2469\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"12\",\n      \"value\": \"0x9B8\"\n    },\n    \"2472\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"12\"\n    },\n    \"2473\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"12\"\n    },\n    \"2474\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"12\"\n    },\n    \"2475\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"12\"\n    },\n    \"2476\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"12\"\n    },\n    \"2477\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"DUP4\",\n      \"path\": \"12\"\n    },\n    \"2478\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"12\"\n    },\n    \"2479\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"12\"\n    },\n    \"2480\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"12\"\n    },\n    \"2481\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"12\",\n      \"value\": \"0x20\"\n    },\n    \"2483\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"12\"\n    },\n    \"2484\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"12\",\n      \"value\": \"0x9A0\"\n    },\n    \"2487\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"12\"\n    },\n    \"2488\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"12\"\n    },\n    \"2489\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"POP\",\n      \"path\": \"12\"\n    },\n    \"2490\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"POP\",\n      \"path\": \"12\"\n    },\n    \"2491\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"POP\",\n      \"path\": \"12\"\n    },\n    \"2492\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"POP\",\n      \"path\": \"12\"\n    },\n    \"2493\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"12\"\n    },\n    \"2494\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"POP\",\n      \"path\": \"12\"\n    },\n    \"2495\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"12\"\n    },\n    \"2496\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"12\"\n    },\n    \"2497\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"12\"\n    },\n    \"2498\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"12\"\n    },\n    \"2499\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"12\",\n      \"value\": \"0x1F\"\n    },\n    \"2501\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"AND\",\n      \"path\": \"12\"\n    },\n    \"2502\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"12\"\n    },\n    \"2503\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"ISZERO\",\n      \"path\": \"12\"\n    },\n    \"2504\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"12\",\n      \"value\": \"0x9E5\"\n    },\n    \"2507\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"12\"\n    },\n    \"2508\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"12\"\n    },\n    \"2509\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"12\"\n    },\n    \"2510\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"SUB\",\n      \"path\": \"12\"\n    },\n    \"2511\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"12\"\n    },\n    \"2512\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"12\"\n    },\n    \"2513\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"12\",\n      \"value\": \"0x1\"\n    },\n    \"2515\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"DUP4\",\n      \"path\": \"12\"\n    },\n    \"2516\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"12\",\n      \"value\": \"0x20\"\n    },\n    \"2518\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"SUB\",\n      \"path\": \"12\"\n    },\n    \"2519\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"12\",\n      \"value\": \"0x100\"\n    },\n    \"2522\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"EXP\",\n      \"path\": \"12\"\n    },\n    \"2523\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"SUB\",\n      \"path\": \"12\"\n    },\n    \"2524\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"NOT\",\n      \"path\": \"12\"\n    },\n    \"2525\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"AND\",\n      \"path\": \"12\"\n    },\n    \"2526\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"12\"\n    },\n    \"2527\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"12\"\n    },\n    \"2528\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"12\",\n      \"value\": \"0x20\"\n    },\n    \"2530\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"12\"\n    },\n    \"2531\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"12\"\n    },\n    \"2532\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"POP\",\n      \"path\": \"12\"\n    },\n    \"2533\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"12\"\n    },\n    \"2534\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"POP\",\n      \"path\": \"12\"\n    },\n    \"2535\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"SWAP3\",\n      \"path\": \"12\"\n    },\n    \"2536\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"POP\",\n      \"path\": \"12\"\n    },\n    \"2537\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"POP\",\n      \"path\": \"12\"\n    },\n    \"2538\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"POP\",\n      \"path\": \"12\"\n    },\n    \"2539\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"12\",\n      \"value\": \"0x40\"\n    },\n    \"2541\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"12\"\n    },\n    \"2542\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"12\"\n    },\n    \"2543\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"12\"\n    },\n    \"2544\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"SUB\",\n      \"path\": \"12\"\n    },\n    \"2545\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"12\"\n    },\n    \"2546\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"REVERT\",\n      \"path\": \"12\"\n    },\n    \"2547\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1851,\n        1880\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"12\"\n    },\n    \"2548\": {\n      \"op\": \"POP\"\n    },\n    \"2549\": {\n      \"op\": \"POP\"\n    },\n    \"2550\": {\n      \"op\": \"POP\"\n    },\n    \"2551\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1902,\n        1907\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"12\"\n    },\n    \"2552\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1902,\n        1907\n      ],\n      \"op\": \"SUB\",\n      \"path\": \"12\"\n    },\n    \"2553\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1902,\n        1907\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"12\"\n    },\n    \"2554\": {\n      \"fn\": \"SafeMath.sub\",\n      \"jump\": \"o\",\n      \"offset\": [\n        1746,\n        1933\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"12\"\n    },\n    \"2555\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        7820,\n        8190\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"3\"\n    },\n    \"2556\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"2558\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"2560\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0xA0\"\n    },\n    \"2562\": {\n      \"op\": \"SHL\"\n    },\n    \"2563\": {\n      \"op\": \"SUB\"\n    },\n    \"2564\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        7903,\n        7924\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"3\",\n      \"statement\": 32\n    },\n    \"2565\": {\n      \"branch\": 47,\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        7903,\n        7924\n      ],\n      \"op\": \"AND\",\n      \"path\": \"3\"\n    },\n    \"2566\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        7895,\n        7960\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0xA56\"\n    },\n    \"2569\": {\n      \"branch\": 47,\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        7895,\n        7960\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"3\"\n    },\n    \"2570\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        7895,\n        7960\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x40\"\n    },\n    \"2572\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        7895,\n        7960\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"2573\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        7895,\n        7960\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"3\"\n    },\n    \"2574\": {\n      \"op\": \"PUSH3\",\n      \"value\": \"0x461BCD\"\n    },\n    \"2578\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0xE5\"\n    },\n    \"2580\": {\n      \"op\": \"SHL\"\n    },\n    \"2581\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        7895,\n        7960\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"2582\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        7895,\n        7960\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"2583\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        7895,\n        7960\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x20\"\n    },\n    \"2585\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        7895,\n        7960\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x4\"\n    },\n    \"2587\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        7895,\n        7960\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"3\"\n    },\n    \"2588\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        7895,\n        7960\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"2589\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        7895,\n        7960\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"2590\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        7895,\n        7960\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x1F\"\n    },\n    \"2592\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        7895,\n        7960\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x24\"\n    },\n    \"2594\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        7895,\n        7960\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"3\"\n    },\n    \"2595\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        7895,\n        7960\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"2596\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        7895,\n        7960\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"2597\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        7895,\n        7960\n      ],\n      \"op\": \"PUSH32\",\n      \"path\": \"3\",\n      \"value\": \"0x45524332303A206D696E7420746F20746865207A65726F206164647265737300\"\n    },\n    \"2630\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        7895,\n        7960\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x44\"\n    },\n    \"2632\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        7895,\n        7960\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"3\"\n    },\n    \"2633\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        7895,\n        7960\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"2634\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        7895,\n        7960\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"2635\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        7895,\n        7960\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"2636\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        7895,\n        7960\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"3\"\n    },\n    \"2637\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        7895,\n        7960\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"2638\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        7895,\n        7960\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"2639\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        7895,\n        7960\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"2640\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        7895,\n        7960\n      ],\n      \"op\": \"SUB\",\n      \"path\": \"3\"\n    },\n    \"2641\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        7895,\n        7960\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x64\"\n    },\n    \"2643\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        7895,\n        7960\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"2644\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        7895,\n        7960\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"2645\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        7895,\n        7960\n      ],\n      \"op\": \"REVERT\",\n      \"path\": \"3\"\n    },\n    \"2646\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        7895,\n        7960\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"3\"\n    },\n    \"2647\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        7971,\n        8020\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"statement\": 33,\n      \"value\": \"0xA62\"\n    },\n    \"2650\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        8000,\n        8001\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x0\"\n    },\n    \"2652\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        8004,\n        8011\n      ],\n      \"op\": \"DUP4\",\n      \"path\": \"3\"\n    },\n    \"2653\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        8013,\n        8019\n      ],\n      \"op\": \"DUP4\",\n      \"path\": \"3\"\n    },\n    \"2654\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        7971,\n        7991\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x48F\"\n    },\n    \"2657\": {\n      \"fn\": \"ERC20._mint\",\n      \"jump\": \"i\",\n      \"offset\": [\n        7971,\n        8020\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"3\"\n    },\n    \"2658\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        7971,\n        8020\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"3\"\n    },\n    \"2659\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        8046,\n        8058\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"statement\": 34,\n      \"value\": \"0x2\"\n    },\n    \"2661\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        8046,\n        8058\n      ],\n      \"op\": \"SLOAD\",\n      \"path\": \"3\"\n    },\n    \"2662\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        8046,\n        8070\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0xA6F\"\n    },\n    \"2665\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        8046,\n        8070\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"2666\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        8063,\n        8069\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"3\"\n    },\n    \"2667\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        8046,\n        8062\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x6B8\"\n    },\n    \"2670\": {\n      \"fn\": \"ERC20._mint\",\n      \"jump\": \"i\",\n      \"offset\": [\n        8046,\n        8070\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"3\"\n    },\n    \"2671\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        8046,\n        8070\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"3\"\n    },\n    \"2672\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        8031,\n        8043\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x2\"\n    },\n    \"2674\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        8031,\n        8070\n      ],\n      \"op\": \"SSTORE\",\n      \"path\": \"3\"\n    },\n    \"2675\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"2677\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"2679\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0xA0\"\n    },\n    \"2681\": {\n      \"op\": \"SHL\"\n    },\n    \"2682\": {\n      \"op\": \"SUB\"\n    },\n    \"2683\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        8101,\n        8119\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"3\",\n      \"statement\": 35\n    },\n    \"2684\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        8101,\n        8119\n      ],\n      \"op\": \"AND\",\n      \"path\": \"3\"\n    },\n    \"2685\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        8101,\n        8110\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x0\"\n    },\n    \"2687\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        8101,\n        8119\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"2688\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        8101,\n        8119\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"2689\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        8101,\n        8119\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"2690\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        8101,\n        8119\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x20\"\n    },\n    \"2692\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        8101,\n        8119\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"2693\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        8101,\n        8119\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"2694\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        8101,\n        8119\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"2695\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        8101,\n        8119\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x40\"\n    },\n    \"2697\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        8101,\n        8119\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"2698\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        8101,\n        8119\n      ],\n      \"op\": \"KECCAK256\",\n      \"path\": \"3\"\n    },\n    \"2699\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        8101,\n        8119\n      ],\n      \"op\": \"SLOAD\",\n      \"path\": \"3\"\n    },\n    \"2700\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        8101,\n        8131\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0xA95\"\n    },\n    \"2703\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        8101,\n        8131\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"2704\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        8124,\n        8130\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"3\"\n    },\n    \"2705\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        8101,\n        8123\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x6B8\"\n    },\n    \"2708\": {\n      \"fn\": \"ERC20._mint\",\n      \"jump\": \"i\",\n      \"offset\": [\n        8101,\n        8131\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"3\"\n    },\n    \"2709\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        8101,\n        8131\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"3\"\n    },\n    \"2710\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"2712\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"2714\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0xA0\"\n    },\n    \"2716\": {\n      \"op\": \"SHL\"\n    },\n    \"2717\": {\n      \"op\": \"SUB\"\n    },\n    \"2718\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        8080,\n        8098\n      ],\n      \"op\": \"DUP4\",\n      \"path\": \"3\"\n    },\n    \"2719\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        8080,\n        8098\n      ],\n      \"op\": \"AND\",\n      \"path\": \"3\"\n    },\n    \"2720\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        8080,\n        8089\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x0\"\n    },\n    \"2722\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        8080,\n        8098\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"2723\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        8080,\n        8098\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"2724\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        8080,\n        8098\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"2725\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        8080,\n        8098\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x20\"\n    },\n    \"2727\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        8080,\n        8098\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"2728\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        8080,\n        8098\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"2729\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        8080,\n        8098\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"2730\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        8080,\n        8098\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x40\"\n    },\n    \"2732\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        8080,\n        8098\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"2733\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        8080,\n        8098\n      ],\n      \"op\": \"DUP4\",\n      \"path\": \"3\"\n    },\n    \"2734\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        8080,\n        8098\n      ],\n      \"op\": \"KECCAK256\",\n      \"path\": \"3\"\n    },\n    \"2735\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        8080,\n        8131\n      ],\n      \"op\": \"SWAP5\",\n      \"path\": \"3\"\n    },\n    \"2736\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        8080,\n        8131\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"2737\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        8080,\n        8131\n      ],\n      \"op\": \"SWAP5\",\n      \"path\": \"3\"\n    },\n    \"2738\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        8080,\n        8131\n      ],\n      \"op\": \"SSTORE\",\n      \"path\": \"3\"\n    },\n    \"2739\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        8146,\n        8183\n      ],\n      \"op\": \"DUP4\",\n      \"path\": \"3\",\n      \"statement\": 36\n    },\n    \"2740\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        8146,\n        8183\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"3\"\n    },\n    \"2741\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        8146,\n        8183\n      ],\n      \"op\": \"DUP6\",\n      \"path\": \"3\"\n    },\n    \"2742\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        8146,\n        8183\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"2743\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        8146,\n        8183\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"2744\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        8146,\n        8183\n      ],\n      \"op\": \"SWAP4\",\n      \"path\": \"3\"\n    },\n    \"2745\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        8146,\n        8183\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"3\"\n    },\n    \"2746\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        8080,\n        8098\n      ],\n      \"op\": \"SWAP3\",\n      \"path\": \"3\"\n    },\n    \"2747\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        8080,\n        8098\n      ],\n      \"op\": \"SWAP4\",\n      \"path\": \"3\"\n    },\n    \"2748\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        8080,\n        8089\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"3\"\n    },\n    \"2749\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        8080,\n        8089\n      ],\n      \"op\": \"SWAP3\",\n      \"path\": \"3\"\n    },\n    \"2750\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        8146,\n        8183\n      ],\n      \"op\": \"PUSH32\",\n      \"path\": \"3\",\n      \"value\": \"0xDDF252AD1BE2C89B69C2B068FC378DAA952BA7F163C4A11628F55A4DF523B3EF\"\n    },\n    \"2783\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        8146,\n        8183\n      ],\n      \"op\": \"SWAP3\",\n      \"path\": \"3\"\n    },\n    \"2784\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        8146,\n        8183\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"2785\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        8146,\n        8183\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"2786\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        8146,\n        8183\n      ],\n      \"op\": \"SUB\",\n      \"path\": \"3\"\n    },\n    \"2787\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        8146,\n        8183\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"2788\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        8146,\n        8183\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"3\"\n    },\n    \"2789\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        8146,\n        8183\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"2790\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        8146,\n        8183\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"2791\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        8146,\n        8183\n      ],\n      \"op\": \"LOG3\",\n      \"path\": \"3\"\n    },\n    \"2792\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        7820,\n        8190\n      ],\n      \"op\": \"POP\",\n      \"path\": \"3\"\n    },\n    \"2793\": {\n      \"fn\": \"ERC20._mint\",\n      \"offset\": [\n        7820,\n        8190\n      ],\n      \"op\": \"POP\",\n      \"path\": \"3\"\n    },\n    \"2794\": {\n      \"fn\": \"ERC20._mint\",\n      \"jump\": \"o\",\n      \"offset\": [\n        7820,\n        8190\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"3\"\n    },\n    \"2795\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8509,\n        8919\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"3\"\n    },\n    \"2796\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"2798\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"2800\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0xA0\"\n    },\n    \"2802\": {\n      \"op\": \"SHL\"\n    },\n    \"2803\": {\n      \"op\": \"SUB\"\n    },\n    \"2804\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8592,\n        8613\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"3\",\n      \"statement\": 37\n    },\n    \"2805\": {\n      \"branch\": 48,\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8592,\n        8613\n      ],\n      \"op\": \"AND\",\n      \"path\": \"3\"\n    },\n    \"2806\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8584,\n        8651\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0xB30\"\n    },\n    \"2809\": {\n      \"branch\": 48,\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8584,\n        8651\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"3\"\n    },\n    \"2810\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8584,\n        8651\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x40\"\n    },\n    \"2812\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8584,\n        8651\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"3\"\n    },\n    \"2813\": {\n      \"op\": \"PUSH3\",\n      \"value\": \"0x461BCD\"\n    },\n    \"2817\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0xE5\"\n    },\n    \"2819\": {\n      \"op\": \"SHL\"\n    },\n    \"2820\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8584,\n        8651\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"2821\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8584,\n        8651\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"2822\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8584,\n        8651\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x4\"\n    },\n    \"2824\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8584,\n        8651\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"2825\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8584,\n        8651\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"2826\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8584,\n        8651\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"2827\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8584,\n        8651\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x20\"\n    },\n    \"2829\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8584,\n        8651\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"2830\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8584,\n        8651\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"3\"\n    },\n    \"2831\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8584,\n        8651\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"2832\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8584,\n        8651\n      ],\n      \"op\": \"SUB\",\n      \"path\": \"3\"\n    },\n    \"2833\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8584,\n        8651\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"3\"\n    },\n    \"2834\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8584,\n        8651\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"2835\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8584,\n        8651\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x21\"\n    },\n    \"2837\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8584,\n        8651\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"2838\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8584,\n        8651\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"2839\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8584,\n        8651\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x20\"\n    },\n    \"2841\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8584,\n        8651\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"2842\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8584,\n        8651\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"2843\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8584,\n        8651\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0xCDF\"\n    },\n    \"2846\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8584,\n        8651\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x21\"\n    },\n    \"2848\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8584,\n        8651\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"3\"\n    },\n    \"2849\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8584,\n        8651\n      ],\n      \"op\": \"CODECOPY\",\n      \"path\": \"3\"\n    },\n    \"2850\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8584,\n        8651\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x40\"\n    },\n    \"2852\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8584,\n        8651\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"2853\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8584,\n        8651\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"3\"\n    },\n    \"2854\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8584,\n        8651\n      ],\n      \"op\": \"POP\",\n      \"path\": \"3\"\n    },\n    \"2855\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8584,\n        8651\n      ],\n      \"op\": \"POP\",\n      \"path\": \"3\"\n    },\n    \"2856\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8584,\n        8651\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x40\"\n    },\n    \"2858\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8584,\n        8651\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"3\"\n    },\n    \"2859\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8584,\n        8651\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"2860\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8584,\n        8651\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"3\"\n    },\n    \"2861\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8584,\n        8651\n      ],\n      \"op\": \"SUB\",\n      \"path\": \"3\"\n    },\n    \"2862\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8584,\n        8651\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"2863\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8584,\n        8651\n      ],\n      \"op\": \"REVERT\",\n      \"path\": \"3\"\n    },\n    \"2864\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8584,\n        8651\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"3\"\n    },\n    \"2865\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8662,\n        8711\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"statement\": 38,\n      \"value\": \"0xB3C\"\n    },\n    \"2868\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8683,\n        8690\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"3\"\n    },\n    \"2869\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8700,\n        8701\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x0\"\n    },\n    \"2871\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8704,\n        8710\n      ],\n      \"op\": \"DUP4\",\n      \"path\": \"3\"\n    },\n    \"2872\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8662,\n        8682\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x48F\"\n    },\n    \"2875\": {\n      \"fn\": \"ERC20._burn\",\n      \"jump\": \"i\",\n      \"offset\": [\n        8662,\n        8711\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"3\"\n    },\n    \"2876\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8662,\n        8711\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"3\"\n    },\n    \"2877\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8743,\n        8811\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"statement\": 39,\n      \"value\": \"0xB79\"\n    },\n    \"2880\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8766,\n        8772\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"2881\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8743,\n        8811\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x40\"\n    },\n    \"2883\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8743,\n        8811\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"3\"\n    },\n    \"2884\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8743,\n        8811\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"2885\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8743,\n        8811\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x60\"\n    },\n    \"2887\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8743,\n        8811\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"2888\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8743,\n        8811\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x40\"\n    },\n    \"2890\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8743,\n        8811\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"2891\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8743,\n        8811\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"2892\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8743,\n        8811\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x22\"\n    },\n    \"2894\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8743,\n        8811\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"2895\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8743,\n        8811\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"2896\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8743,\n        8811\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x20\"\n    },\n    \"2898\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8743,\n        8811\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"2899\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8743,\n        8811\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0xC4D\"\n    },\n    \"2902\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8743,\n        8811\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x22\"\n    },\n    \"2904\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8743,\n        8811\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"3\"\n    },\n    \"2905\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8743,\n        8811\n      ],\n      \"op\": \"CODECOPY\",\n      \"path\": \"3\"\n    },\n    \"2906\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"2908\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"2910\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0xA0\"\n    },\n    \"2912\": {\n      \"op\": \"SHL\"\n    },\n    \"2913\": {\n      \"op\": \"SUB\"\n    },\n    \"2914\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8743,\n        8761\n      ],\n      \"op\": \"DUP6\",\n      \"path\": \"3\"\n    },\n    \"2915\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8743,\n        8761\n      ],\n      \"op\": \"AND\",\n      \"path\": \"3\"\n    },\n    \"2916\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8743,\n        8752\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x0\"\n    },\n    \"2918\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8743,\n        8761\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"2919\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8743,\n        8761\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"2920\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8743,\n        8761\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"2921\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8743,\n        8761\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x20\"\n    },\n    \"2923\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8743,\n        8761\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"2924\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8743,\n        8761\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"2925\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8743,\n        8761\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"2926\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8743,\n        8761\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x40\"\n    },\n    \"2928\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8743,\n        8761\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"2929\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8743,\n        8761\n      ],\n      \"op\": \"KECCAK256\",\n      \"path\": \"3\"\n    },\n    \"2930\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8743,\n        8761\n      ],\n      \"op\": \"SLOAD\",\n      \"path\": \"3\"\n    },\n    \"2931\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8743,\n        8761\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"3\"\n    },\n    \"2932\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8743,\n        8811\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"2933\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8743,\n        8765\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0x964\"\n    },\n    \"2936\": {\n      \"fn\": \"ERC20._burn\",\n      \"jump\": \"i\",\n      \"offset\": [\n        8743,\n        8811\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"3\"\n    },\n    \"2937\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8743,\n        8811\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"3\"\n    },\n    \"2938\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"2940\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"2942\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0xA0\"\n    },\n    \"2944\": {\n      \"op\": \"SHL\"\n    },\n    \"2945\": {\n      \"op\": \"SUB\"\n    },\n    \"2946\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8722,\n        8740\n      ],\n      \"op\": \"DUP4\",\n      \"path\": \"3\"\n    },\n    \"2947\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8722,\n        8740\n      ],\n      \"op\": \"AND\",\n      \"path\": \"3\"\n    },\n    \"2948\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8722,\n        8731\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x0\"\n    },\n    \"2950\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8722,\n        8740\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"2951\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8722,\n        8740\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"2952\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8722,\n        8740\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"2953\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8722,\n        8740\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x20\"\n    },\n    \"2955\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8722,\n        8740\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"2956\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8722,\n        8740\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"2957\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8722,\n        8740\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"2958\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8722,\n        8740\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x40\"\n    },\n    \"2960\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8722,\n        8740\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"2961\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8722,\n        8740\n      ],\n      \"op\": \"KECCAK256\",\n      \"path\": \"3\"\n    },\n    \"2962\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8722,\n        8811\n      ],\n      \"op\": \"SSTORE\",\n      \"path\": \"3\"\n    },\n    \"2963\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8836,\n        8848\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"statement\": 40,\n      \"value\": \"0x2\"\n    },\n    \"2965\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8836,\n        8848\n      ],\n      \"op\": \"SLOAD\",\n      \"path\": \"3\"\n    },\n    \"2966\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8836,\n        8860\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0xB9F\"\n    },\n    \"2969\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8836,\n        8860\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"2970\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8853,\n        8859\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"3\"\n    },\n    \"2971\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8836,\n        8852\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"3\",\n      \"value\": \"0xBE7\"\n    },\n    \"2974\": {\n      \"fn\": \"ERC20._burn\",\n      \"jump\": \"i\",\n      \"offset\": [\n        8836,\n        8860\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"3\"\n    },\n    \"2975\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8836,\n        8860\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"3\"\n    },\n    \"2976\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8821,\n        8833\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x2\"\n    },\n    \"2978\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8821,\n        8860\n      ],\n      \"op\": \"SSTORE\",\n      \"path\": \"3\"\n    },\n    \"2979\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8875,\n        8912\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"statement\": 41,\n      \"value\": \"0x40\"\n    },\n    \"2981\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8875,\n        8912\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"3\"\n    },\n    \"2982\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8875,\n        8912\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"3\"\n    },\n    \"2983\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8875,\n        8912\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"3\"\n    },\n    \"2984\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8875,\n        8912\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"2985\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8875,\n        8912\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"3\"\n    },\n    \"2986\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8875,\n        8912\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"2987\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8875,\n        8912\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"3\"\n    },\n    \"2988\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8901,\n        8902\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x0\"\n    },\n    \"2990\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8901,\n        8902\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"3\"\n    },\n    \"2991\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"2993\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"2995\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0xA0\"\n    },\n    \"2997\": {\n      \"op\": \"SHL\"\n    },\n    \"2998\": {\n      \"op\": \"SUB\"\n    },\n    \"2999\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8875,\n        8912\n      ],\n      \"op\": \"DUP6\",\n      \"path\": \"3\"\n    },\n    \"3000\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8875,\n        8912\n      ],\n      \"op\": \"AND\",\n      \"path\": \"3\"\n    },\n    \"3001\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8875,\n        8912\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"3\"\n    },\n    \"3002\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8875,\n        8912\n      ],\n      \"op\": \"PUSH32\",\n      \"path\": \"3\",\n      \"value\": \"0xDDF252AD1BE2C89B69C2B068FC378DAA952BA7F163C4A11628F55A4DF523B3EF\"\n    },\n    \"3035\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8875,\n        8912\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"3\"\n    },\n    \"3036\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8875,\n        8912\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"3\"\n    },\n    \"3037\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8875,\n        8912\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"3038\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8875,\n        8912\n      ],\n      \"op\": \"SUB\",\n      \"path\": \"3\"\n    },\n    \"3039\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8875,\n        8912\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"3\",\n      \"value\": \"0x20\"\n    },\n    \"3041\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8875,\n        8912\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"3\"\n    },\n    \"3042\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8875,\n        8912\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"3\"\n    },\n    \"3043\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8875,\n        8912\n      ],\n      \"op\": \"LOG3\",\n      \"path\": \"3\"\n    },\n    \"3044\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8509,\n        8919\n      ],\n      \"op\": \"POP\",\n      \"path\": \"3\"\n    },\n    \"3045\": {\n      \"fn\": \"ERC20._burn\",\n      \"offset\": [\n        8509,\n        8919\n      ],\n      \"op\": \"POP\",\n      \"path\": \"3\"\n    },\n    \"3046\": {\n      \"fn\": \"ERC20._burn\",\n      \"jump\": \"o\",\n      \"offset\": [\n        8509,\n        8919\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"3\"\n    },\n    \"3047\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1321,\n        1455\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"12\"\n    },\n    \"3048\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1379,\n        1386\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"12\",\n      \"value\": \"0x0\"\n    },\n    \"3050\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1405,\n        1448\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"12\",\n      \"statement\": 42,\n      \"value\": \"0x712\"\n    },\n    \"3053\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1409,\n        1410\n      ],\n      \"op\": \"DUP4\",\n      \"path\": \"12\"\n    },\n    \"3054\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1412,\n        1413\n      ],\n      \"op\": \"DUP4\",\n      \"path\": \"12\"\n    },\n    \"3055\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1405,\n        1448\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"12\",\n      \"value\": \"0x40\"\n    },\n    \"3057\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1405,\n        1448\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"12\"\n    },\n    \"3058\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1405,\n        1448\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"12\"\n    },\n    \"3059\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1405,\n        1448\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"12\",\n      \"value\": \"0x40\"\n    },\n    \"3061\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1405,\n        1448\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"12\"\n    },\n    \"3062\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1405,\n        1448\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"12\",\n      \"value\": \"0x40\"\n    },\n    \"3064\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1405,\n        1448\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"12\"\n    },\n    \"3065\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1405,\n        1448\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"12\"\n    },\n    \"3066\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1405,\n        1448\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"12\",\n      \"value\": \"0x1E\"\n    },\n    \"3068\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1405,\n        1448\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"12\"\n    },\n    \"3069\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1405,\n        1448\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"12\"\n    },\n    \"3070\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1405,\n        1448\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"12\",\n      \"value\": \"0x20\"\n    },\n    \"3072\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1405,\n        1448\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"12\"\n    },\n    \"3073\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1405,\n        1448\n      ],\n      \"op\": \"PUSH32\",\n      \"path\": \"12\",\n      \"value\": \"0x536166654D6174683A207375627472616374696F6E206F766572666C6F770000\"\n    },\n    \"3106\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1405,\n        1448\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"12\"\n    },\n    \"3107\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1405,\n        1448\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"12\"\n    },\n    \"3108\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1405,\n        1448\n      ],\n      \"op\": \"POP\",\n      \"path\": \"12\"\n    },\n    \"3109\": {\n      \"fn\": \"SafeMath.sub\",\n      \"offset\": [\n        1405,\n        1408\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"12\",\n      \"value\": \"0x964\"\n    },\n    \"3112\": {\n      \"fn\": \"SafeMath.sub\",\n      \"jump\": \"i\",\n      \"offset\": [\n        1405,\n        1448\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"12\"\n    }\n  },\n  \"sha1\": \"0da0cdb26e7a68b3659b1cec22c9c49a42259a3e\",\n  \"source\": \"// SPDX-License-Identifier:Apache-2.0\\n//------------------------------------------------------------------------------\\n//\\n//   Copyright 2020 Fetch.AI Limited\\n//\\n//   Licensed under the Apache License, Version 2.0 (the \\\"License\\\");\\n//   you may not use this file except in compliance with the License.\\n//   You may obtain a copy of the License at\\n//\\n//       http://www.apache.org/licenses/LICENSE-2.0\\n//\\n//   Unless required by applicable law or agreed to in writing, software\\n//   distributed under the License is distributed on an \\\"AS IS\\\" BASIS,\\n//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\\n//   See the License for the specific language governing permissions and\\n//   limitations under the License.\\n//\\n//------------------------------------------------------------------------------\\n\\npragma solidity ^0.6.0;\\n\\nimport \\\"./ERC20Mock.sol\\\";\\n\\ncontract FetERC20Mock is ERC20Mock\\n{\\n    constructor (\\n        string memory name,\\n        string memory symbol,\\n        uint256 initialSupply,\\n        uint8 decimals_\\n        )\\n        public payable\\n        ERC20Mock(name, symbol, msg.sender, initialSupply)\\n    {\\n        _setupDecimals(decimals_);\\n    }\\n}\\n\",\n  \"sourceMap\": \"872:308:6:-:0;;;913:265;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;913:265:6;;;;;;;;;;-1:-1:-1;913:265:6;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;913:265:6;;;;;;;;;;-1:-1:-1;913:265:6;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;913:265:6;;;;;;;;;;;;;;2070:12:3;;913:265:6;;-1:-1:-1;913:265:6;-1:-1:-1;1091:4:6;;1097:6;;1105:10;;913:265;;1091:4;;1097:6;;2070:12:3;;:5;;:12;;;;:::i;:::-;-1:-1:-1;2092:16:3;;;;:7;;:16;;;;;:::i;:::-;-1:-1:-1;;2118:9:3;:14;;-1:-1:-1;;2118:14:3;2130:2;2118:14;;;-1:-1:-1;327:37:4::1;333:14:::0;349;327:5:::1;:37::i;:::-;141:230:::0;;;;1146:25:6::1;1161:9;1146:14;;;:25;;:::i;:::-;913:265:::0;;;;872:308;;7820:370:3;-1:-1:-1;;;;;7903:21:3;;7895:65;;;;;-1:-1:-1;;;7895:65:3;;;;;;;;;;;;;;;;;;;;;;;;;;;;7971:49;8000:1;8004:7;8013:6;7971:20;:49::i;:::-;8046:24;8063:6;8046:12;;:16;;;;;;:24;;;;:::i;:::-;8031:12;:39;-1:-1:-1;;;;;8101:18:3;;:9;:18;;;;;;;;;;;;:30;;8124:6;;8101:22;;;;;:30;;:::i;:::-;-1:-1:-1;;;;;8080:18:3;;:9;:18;;;;;;;;;;;:51;;;;8146:37;;;;;;;8080:18;;:9;;8146:37;;;;;;;;;;7820:370;;:::o;10007:88::-;10067:9;:21;;-1:-1:-1;;10067:21:3;;;;;;;;;;;;10007:88::o;10682:92::-;;;;:::o;874:176:12:-;932:7;963:5;;;986:6;;;;978:46;;;;;-1:-1:-1;;;978:46:12;;;;;;;;;;;;;;;;;;;;;;;;;;;;1042:1;874:176;-1:-1:-1;;;874:176:12:o;872:308:6:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;872:308:6;;;-1:-1:-1;872:308:6;:::i;:::-;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;\",\n  \"sourcePath\": \"contracts/FetERC20Mock.sol\",\n  \"type\": \"contract\"\n}"
  },
  {
    "path": "packages/fetchai/contracts/fet_erc20/contract.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the FET ERC20 contract definition.\"\"\"\n\nimport logging\n\nfrom aea_ledger_ethereum import EthereumApi\n\nfrom aea.common import Address, JSONLike\nfrom aea.configurations.base import PublicId\nfrom aea.contracts.base import Contract\nfrom aea.crypto.base import LedgerApi\n\n\n_default_logger = logging.getLogger(\"aea.packages.fetchai.contracts.fet_erc20.contract\")\n\nPUBLIC_ID = PublicId.from_str(\"fetchai/fet_erc20:0.9.2\")\n\n\nclass FetERC20(Contract):\n    \"\"\"The FetERC20 contract class which acts as a bridge between AEA framework and ERC20 ABI.\"\"\"\n\n    contract_id = PUBLIC_ID\n\n    @classmethod\n    def get_approve_transaction(\n        cls,\n        ledger_api: LedgerApi,\n        contract_address: Address,\n        from_address: Address,\n        spender: Address,\n        amount: int,\n        gas: int = 0,\n    ) -> JSONLike:\n        \"\"\"\n        Get transaction to approve oracle client contract transactions on behalf of sender.\n\n        :param ledger_api: the ledger apis.\n        :param contract_address: the contract address.\n        :param from_address: the address of the approver.\n        :param spender: the address approved to spend on behalf of sender.\n        :param amount: the amount approved to be spent.\n        :param gas: the gas limit for the transaction.\n        :return: the approve transaction\n        \"\"\"\n        if ledger_api.identifier == EthereumApi.identifier:\n            nonce = ledger_api.api.eth.getTransactionCount(from_address)\n            instance = cls.get_instance(ledger_api, contract_address)\n            function = instance.functions.approve\n            intermediate = function(spender, amount)\n            tx = intermediate.buildTransaction(\n                {\n                    \"gas\": gas,\n                    \"gasPrice\": ledger_api.api.toWei(\"50\", \"gwei\"),\n                    \"nonce\": nonce,\n                }\n            )\n            tx = ledger_api.update_with_gas_estimate(tx)\n            return tx\n        raise NotImplementedError\n\n    @classmethod\n    def get_transfer_transaction(\n        cls,\n        ledger_api: LedgerApi,\n        contract_address: Address,\n        from_address: Address,\n        receiver: Address,\n        amount: int,\n        gas: int = 0,\n    ) -> JSONLike:\n        \"\"\"\n        Get transaction to transfer tokens to an account\n\n        :param ledger_api: the ledger apis.\n        :param contract_address: the contract address.\n        :param from_address: the address of the sender.\n        :param receiver: the address to which to transfer tokens.\n        :param amount: the amount of tokens to transfer.\n        :param gas: the gas limit for the transaction.\n        :return: the transfer transaction\n        \"\"\"\n        if ledger_api.identifier == EthereumApi.identifier:\n            nonce = ledger_api.api.eth.getTransactionCount(from_address)\n            instance = cls.get_instance(ledger_api, contract_address)\n            function = instance.functions.transfer\n            intermediate = function(receiver, amount)\n            tx = intermediate.buildTransaction(\n                {\n                    \"gas\": gas,\n                    \"gasPrice\": ledger_api.api.toWei(\"50\", \"gwei\"),\n                    \"nonce\": nonce,\n                }\n            )\n            tx = ledger_api.update_with_gas_estimate(tx)\n            return tx\n        raise NotImplementedError\n"
  },
  {
    "path": "packages/fetchai/contracts/fet_erc20/contract.yaml",
    "content": "name: fet_erc20\nauthor: fetchai\nversion: 0.9.2\ntype: contract\ndescription: The fet_erc20 contract contains a mock Fetch ERC20 contract\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: QmWVwuKSyna278svBZ18tdxHtVfhHuTV6pZ79UH5gmaNes\n  __init__.py: QmRCPaWpwzAgESvZPpgyNQwSHAfDcU9rnEH2PauuLgfVor\n  build/FetERC20Mock.json: QmPKt6BUTUotWS7mtdHLxfg7dEw3cATzNojNBiJ1nifwF9\n  contract.py: QmZBS2cDYWHQVdBogFRpCPUjqQjXCDbkz5mzP1XprLrYAv\nfingerprint_ignore_patterns: []\nclass_name: FetERC20\ncontract_interface_paths:\n  ethereum: build/FetERC20Mock.json\ndependencies:\n  aea-ledger-ethereum:\n    version: <2.0.0,>=1.0.0\n"
  },
  {
    "path": "packages/fetchai/contracts/oracle/README.md",
    "content": "# Fetch Oracle Contract\n\n## Description\n\nThis contract package is used to interface with a Fetch Oracle contract, which makes real-world data available to a smart-contract-capable blockchain.\n\n## Functions\n\n- `grantRole(oracle_role, oracle_address)`: grant oracle role to address `oracle_address`\n- `updateOracleValue(value, decimals, txExpirationBlock)`: update oracle contract value to `value` with `decimals` decimal places, to expire at block `txExpirationBlock`\n"
  },
  {
    "path": "packages/fetchai/contracts/oracle/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the support resources for the Fetch oracle contract.\"\"\"\n"
  },
  {
    "path": "packages/fetchai/contracts/oracle/build/FetchOracle.json",
    "content": "{\n  \"contractName\": \"FetchOracle\",\n  \"abi\": [\n    {\n      \"inputs\": [\n        {\n          \"internalType\": \"address\",\n          \"name\": \"ERC20Address\",\n          \"type\": \"address\"\n        },\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"initialFee\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"stateMutability\": \"nonpayable\",\n      \"type\": \"constructor\"\n    },\n    {\n      \"anonymous\": false,\n      \"inputs\": [\n        {\n          \"indexed\": false,\n          \"internalType\": \"address\",\n          \"name\": \"targetAddress\",\n          \"type\": \"address\"\n        },\n        {\n          \"indexed\": false,\n          \"internalType\": \"uint256\",\n          \"name\": \"amount\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"name\": \"AccruedFeesWithdrawal\",\n      \"type\": \"event\"\n    },\n    {\n      \"anonymous\": false,\n      \"inputs\": [],\n      \"name\": \"ContractDeleted\",\n      \"type\": \"event\"\n    },\n    {\n      \"anonymous\": false,\n      \"inputs\": [\n        {\n          \"indexed\": false,\n          \"internalType\": \"address\",\n          \"name\": \"targetAddress\",\n          \"type\": \"address\"\n        },\n        {\n          \"indexed\": false,\n          \"internalType\": \"uint256\",\n          \"name\": \"amount\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"name\": \"ExcessTokenWithdrawal\",\n      \"type\": \"event\"\n    },\n    {\n      \"anonymous\": false,\n      \"inputs\": [\n        {\n          \"indexed\": false,\n          \"internalType\": \"uint256\",\n          \"name\": \"fee\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"name\": \"FeeUpdated\",\n      \"type\": \"event\"\n    },\n    {\n      \"anonymous\": false,\n      \"inputs\": [\n        {\n          \"indexed\": false,\n          \"internalType\": \"uint256\",\n          \"name\": \"atBlock\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"name\": \"OracleValueUpdated\",\n      \"type\": \"event\"\n    },\n    {\n      \"anonymous\": false,\n      \"inputs\": [\n        {\n          \"indexed\": false,\n          \"internalType\": \"uint256\",\n          \"name\": \"sinceBlock\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"name\": \"Pause\",\n      \"type\": \"event\"\n    },\n    {\n      \"anonymous\": false,\n      \"inputs\": [\n        {\n          \"indexed\": true,\n          \"internalType\": \"bytes32\",\n          \"name\": \"role\",\n          \"type\": \"bytes32\"\n        },\n        {\n          \"indexed\": true,\n          \"internalType\": \"bytes32\",\n          \"name\": \"previousAdminRole\",\n          \"type\": \"bytes32\"\n        },\n        {\n          \"indexed\": true,\n          \"internalType\": \"bytes32\",\n          \"name\": \"newAdminRole\",\n          \"type\": \"bytes32\"\n        }\n      ],\n      \"name\": \"RoleAdminChanged\",\n      \"type\": \"event\"\n    },\n    {\n      \"anonymous\": false,\n      \"inputs\": [\n        {\n          \"indexed\": true,\n          \"internalType\": \"bytes32\",\n          \"name\": \"role\",\n          \"type\": \"bytes32\"\n        },\n        {\n          \"indexed\": true,\n          \"internalType\": \"address\",\n          \"name\": \"account\",\n          \"type\": \"address\"\n        },\n        {\n          \"indexed\": true,\n          \"internalType\": \"address\",\n          \"name\": \"sender\",\n          \"type\": \"address\"\n        }\n      ],\n      \"name\": \"RoleGranted\",\n      \"type\": \"event\"\n    },\n    {\n      \"anonymous\": false,\n      \"inputs\": [\n        {\n          \"indexed\": true,\n          \"internalType\": \"bytes32\",\n          \"name\": \"role\",\n          \"type\": \"bytes32\"\n        },\n        {\n          \"indexed\": true,\n          \"internalType\": \"address\",\n          \"name\": \"account\",\n          \"type\": \"address\"\n        },\n        {\n          \"indexed\": true,\n          \"internalType\": \"address\",\n          \"name\": \"sender\",\n          \"type\": \"address\"\n        }\n      ],\n      \"name\": \"RoleRevoked\",\n      \"type\": \"event\"\n    },\n    {\n      \"inputs\": [],\n      \"name\": \"DEFAULT_ADMIN_ROLE\",\n      \"outputs\": [\n        {\n          \"internalType\": \"bytes32\",\n          \"name\": \"\",\n          \"type\": \"bytes32\"\n        }\n      ],\n      \"stateMutability\": \"view\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [],\n      \"name\": \"DELEGATE_ROLE\",\n      \"outputs\": [\n        {\n          \"internalType\": \"bytes32\",\n          \"name\": \"\",\n          \"type\": \"bytes32\"\n        }\n      ],\n      \"stateMutability\": \"view\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [],\n      \"name\": \"DELETE_PROTECTION_PERIOD\",\n      \"outputs\": [\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"stateMutability\": \"view\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [],\n      \"name\": \"ORACLE_ROLE\",\n      \"outputs\": [\n        {\n          \"internalType\": \"bytes32\",\n          \"name\": \"\",\n          \"type\": \"bytes32\"\n        }\n      ],\n      \"stateMutability\": \"view\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [],\n      \"name\": \"_accruedFeesAmount\",\n      \"outputs\": [\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"stateMutability\": \"view\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [],\n      \"name\": \"_earliestDelete\",\n      \"outputs\": [\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"stateMutability\": \"view\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [],\n      \"name\": \"_fee\",\n      \"outputs\": [\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"stateMutability\": \"view\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [],\n      \"name\": \"_feeCurrency\",\n      \"outputs\": [\n        {\n          \"internalType\": \"enum FetchOracle.FeeCurrency\",\n          \"name\": \"\",\n          \"type\": \"uint8\"\n        }\n      ],\n      \"stateMutability\": \"view\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [],\n      \"name\": \"_pausedSinceBlock\",\n      \"outputs\": [\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"stateMutability\": \"view\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [],\n      \"name\": \"_token\",\n      \"outputs\": [\n        {\n          \"internalType\": \"contract IERC20\",\n          \"name\": \"\",\n          \"type\": \"address\"\n        }\n      ],\n      \"stateMutability\": \"view\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [\n        {\n          \"internalType\": \"bytes32\",\n          \"name\": \"role\",\n          \"type\": \"bytes32\"\n        }\n      ],\n      \"name\": \"getRoleAdmin\",\n      \"outputs\": [\n        {\n          \"internalType\": \"bytes32\",\n          \"name\": \"\",\n          \"type\": \"bytes32\"\n        }\n      ],\n      \"stateMutability\": \"view\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [\n        {\n          \"internalType\": \"bytes32\",\n          \"name\": \"role\",\n          \"type\": \"bytes32\"\n        },\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"index\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"name\": \"getRoleMember\",\n      \"outputs\": [\n        {\n          \"internalType\": \"address\",\n          \"name\": \"\",\n          \"type\": \"address\"\n        }\n      ],\n      \"stateMutability\": \"view\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [\n        {\n          \"internalType\": \"bytes32\",\n          \"name\": \"role\",\n          \"type\": \"bytes32\"\n        }\n      ],\n      \"name\": \"getRoleMemberCount\",\n      \"outputs\": [\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"stateMutability\": \"view\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [\n        {\n          \"internalType\": \"bytes32\",\n          \"name\": \"role\",\n          \"type\": \"bytes32\"\n        },\n        {\n          \"internalType\": \"address\",\n          \"name\": \"account\",\n          \"type\": \"address\"\n        }\n      ],\n      \"name\": \"grantRole\",\n      \"outputs\": [],\n      \"stateMutability\": \"nonpayable\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [\n        {\n          \"internalType\": \"bytes32\",\n          \"name\": \"role\",\n          \"type\": \"bytes32\"\n        },\n        {\n          \"internalType\": \"address\",\n          \"name\": \"account\",\n          \"type\": \"address\"\n        }\n      ],\n      \"name\": \"hasRole\",\n      \"outputs\": [\n        {\n          \"internalType\": \"bool\",\n          \"name\": \"\",\n          \"type\": \"bool\"\n        }\n      ],\n      \"stateMutability\": \"view\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [\n        {\n          \"internalType\": \"bytes32\",\n          \"name\": \"role\",\n          \"type\": \"bytes32\"\n        },\n        {\n          \"internalType\": \"address\",\n          \"name\": \"account\",\n          \"type\": \"address\"\n        }\n      ],\n      \"name\": \"renounceRole\",\n      \"outputs\": [],\n      \"stateMutability\": \"nonpayable\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [\n        {\n          \"internalType\": \"bytes32\",\n          \"name\": \"role\",\n          \"type\": \"bytes32\"\n        },\n        {\n          \"internalType\": \"address\",\n          \"name\": \"account\",\n          \"type\": \"address\"\n        }\n      ],\n      \"name\": \"revokeRole\",\n      \"outputs\": [],\n      \"stateMutability\": \"nonpayable\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"value\",\n          \"type\": \"uint256\"\n        },\n        {\n          \"internalType\": \"uint8\",\n          \"name\": \"decimals\",\n          \"type\": \"uint8\"\n        },\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"txExpirationBlock\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"name\": \"updateOracleValue\",\n      \"outputs\": [],\n      \"stateMutability\": \"nonpayable\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [],\n      \"name\": \"queryOracleValue\",\n      \"outputs\": [\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"value\",\n          \"type\": \"uint256\"\n        },\n        {\n          \"internalType\": \"uint8\",\n          \"name\": \"decimals\",\n          \"type\": \"uint8\"\n        },\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"updatedAtEthBlockNumber\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"stateMutability\": \"payable\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"fee\",\n          \"type\": \"uint256\"\n        },\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"txExpirationBlock\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"name\": \"setFee\",\n      \"outputs\": [],\n      \"stateMutability\": \"nonpayable\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"block_number\",\n          \"type\": \"uint256\"\n        },\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"txExpirationBlock\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"name\": \"pauseSince\",\n      \"outputs\": [],\n      \"stateMutability\": \"nonpayable\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [\n        {\n          \"internalType\": \"address payable\",\n          \"name\": \"targetAddress\",\n          \"type\": \"address\"\n        },\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"txExpirationBlock\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"name\": \"withdrawAccruedFees\",\n      \"outputs\": [],\n      \"stateMutability\": \"nonpayable\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [\n        {\n          \"internalType\": \"address payable\",\n          \"name\": \"targetAddress\",\n          \"type\": \"address\"\n        },\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"txExpirationBlock\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"name\": \"withdrawExcessTokens\",\n      \"outputs\": [],\n      \"stateMutability\": \"nonpayable\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [\n        {\n          \"internalType\": \"address payable\",\n          \"name\": \"payoutAddress\",\n          \"type\": \"address\"\n        },\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"txExpirationBlock\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"name\": \"deleteContract\",\n      \"outputs\": [],\n      \"stateMutability\": \"nonpayable\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [],\n      \"name\": \"oracleValueLastUpdated\",\n      \"outputs\": [\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"stateMutability\": \"view\",\n      \"type\": \"function\"\n    }\n  ],\n  \"metadata\": \"{\\\"compiler\\\":{\\\"version\\\":\\\"0.6.8+commit.0bbfe453\\\"},\\\"language\\\":\\\"Solidity\\\",\\\"output\\\":{\\\"abi\\\":[{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"ERC20Address\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"initialFee\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"constructor\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":false,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"targetAddress\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"amount\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"AccruedFeesWithdrawal\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[],\\\"name\\\":\\\"ContractDeleted\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":false,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"targetAddress\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"amount\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"ExcessTokenWithdrawal\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"fee\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"FeeUpdated\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"atBlock\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"OracleValueUpdated\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"sinceBlock\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"Pause\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":true,\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"role\\\",\\\"type\\\":\\\"bytes32\\\"},{\\\"indexed\\\":true,\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"previousAdminRole\\\",\\\"type\\\":\\\"bytes32\\\"},{\\\"indexed\\\":true,\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"newAdminRole\\\",\\\"type\\\":\\\"bytes32\\\"}],\\\"name\\\":\\\"RoleAdminChanged\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":true,\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"role\\\",\\\"type\\\":\\\"bytes32\\\"},{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"account\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"sender\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"RoleGranted\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":true,\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"role\\\",\\\"type\\\":\\\"bytes32\\\"},{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"account\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"sender\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"RoleRevoked\\\",\\\"type\\\":\\\"event\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"DEFAULT_ADMIN_ROLE\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"bytes32\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"DELEGATE_ROLE\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"bytes32\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"DELETE_PROTECTION_PERIOD\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"ORACLE_ROLE\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"bytes32\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"_accruedFeesAmount\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"_earliestDelete\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"_fee\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"_feeCurrency\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"enum FetchOracle.FeeCurrency\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint8\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"_pausedSinceBlock\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"_token\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"contract IERC20\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"address\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address payable\\\",\\\"name\\\":\\\"payoutAddress\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"txExpirationBlock\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"deleteContract\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"role\\\",\\\"type\\\":\\\"bytes32\\\"}],\\\"name\\\":\\\"getRoleAdmin\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"bytes32\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"role\\\",\\\"type\\\":\\\"bytes32\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"index\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"getRoleMember\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"address\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"role\\\",\\\"type\\\":\\\"bytes32\\\"}],\\\"name\\\":\\\"getRoleMemberCount\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"role\\\",\\\"type\\\":\\\"bytes32\\\"},{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"account\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"grantRole\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"role\\\",\\\"type\\\":\\\"bytes32\\\"},{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"account\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"hasRole\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"bool\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"bool\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"oracleValueLastUpdated\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"block_number\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"txExpirationBlock\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"pauseSince\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"queryOracleValue\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"value\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"uint8\\\",\\\"name\\\":\\\"decimals\\\",\\\"type\\\":\\\"uint8\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"updatedAtEthBlockNumber\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"payable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"role\\\",\\\"type\\\":\\\"bytes32\\\"},{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"account\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"renounceRole\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"role\\\",\\\"type\\\":\\\"bytes32\\\"},{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"account\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"revokeRole\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"fee\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"txExpirationBlock\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"setFee\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"value\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"uint8\\\",\\\"name\\\":\\\"decimals\\\",\\\"type\\\":\\\"uint8\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"txExpirationBlock\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"updateOracleValue\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address payable\\\",\\\"name\\\":\\\"targetAddress\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"txExpirationBlock\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"withdrawAccruedFees\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address payable\\\",\\\"name\\\":\\\"targetAddress\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"txExpirationBlock\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"withdrawExcessTokens\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"}],\\\"devdoc\\\":{\\\"details\\\":\\\"The contract *INTENTIONALLY* does not contain the `receive()` or fallback functions in order to ensure that all unsolicited direct ETH transfers in to this contract (in direct Transaction) will fail. Only way how to make successful fee transfer in ETH currency (*IF* contract is initialised for ETH as fee currency), is to make transfer ETH to caller(client) contract and client contract then is responsible for further rogrammatic* (= *not* via Tx) transfer of fee to this this contract.\\\",\\\"methods\\\":{\\\"constructor\\\":{\\\"params\\\":{\\\"ERC20Address\\\":\\\"address of the ERC20 contract\\\"}},\\\"deleteContract(address,uint256)\\\":{\\\"details\\\":\\\"Delete the contract, transfers the remaining token and ether balance to the specified payoutAddressowner only + only on or after `_earliestDelete` block\\\",\\\"params\\\":{\\\"payoutAddress\\\":\\\"address to transfer the balances to. Ensure that this is able to handle ERC20 tokens\\\"}},\\\"getRoleAdmin(bytes32)\\\":{\\\"details\\\":\\\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}.     * To change a role's admin, use {_setRoleAdmin}.\\\"},\\\"getRoleMember(bytes32,uint256)\\\":{\\\"details\\\":\\\"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive.     * Role bearers are not sorted in any particular way, and their ordering may change at any point.     * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information.\\\"},\\\"getRoleMemberCount(bytes32)\\\":{\\\"details\\\":\\\"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role.\\\"},\\\"grantRole(bytes32,address)\\\":{\\\"details\\\":\\\"Grants `role` to `account`.     * If `account` had not been already granted `role`, emits a {RoleGranted} event.     * Requirements:     * - the caller must have ``role``'s admin role.\\\"},\\\"hasRole(bytes32,address)\\\":{\\\"details\\\":\\\"Returns `true` if `account` has been granted `role`.\\\"},\\\"pauseSince(uint256,uint256)\\\":{\\\"details\\\":\\\"Pause the non-administrative interaction with the contractOwners only\\\",\\\"params\\\":{\\\"block_number\\\":\\\"disallow non-admin. interactions with contract for a _getBlockNumber() >= block_number\\\"}},\\\"renounceRole(bytes32,address)\\\":{\\\"details\\\":\\\"Revokes `role` from the calling account.     * Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced).     * If the calling account had been granted `role`, emits a {RoleRevoked} event.     * Requirements:     * - the caller must be `account`.\\\"},\\\"revokeRole(bytes32,address)\\\":{\\\"details\\\":\\\"Revokes `role` from `account`.     * If `account` had been granted `role`, emits a {RoleRevoked} event.     * Requirements:     * - the caller must have ``role``'s admin role.\\\"},\\\"setFee(uint256,uint256)\\\":{\\\"details\\\":\\\"Pause the non-administrative interaction with the contractOwners only\\\",\\\"params\\\":{\\\"fee\\\":\\\"- value of fee\\\",\\\"txExpirationBlock\\\":\\\"- block number defined by Tx sender beyond which transaction becomes invalid\\\"}},\\\"withdrawAccruedFees(address,uint256)\\\":{\\\"details\\\":\\\"Withdraw whole balance of all fees accrued in the contract so far.Owners only\\\",\\\"params\\\":{\\\"targetAddress\\\":\\\": address to send tokens to\\\",\\\"txExpirationBlock\\\":\\\": block number until which is the transaction valid (inclusive).                           When transaction is processed after this block, it fails.\\\"}},\\\"withdrawExcessTokens(address,uint256)\\\":{\\\"details\\\":\\\"Withdraw \\\\\\\"excess\\\\\\\" tokens, which were sent to contract address directly via direct ERC20 transfer(...) or transferFrom(...),     without interacting with API of this (FetchOracle) contract, what could be done only by mistake.     Thus this method is meant to be used primarily for rescue purposes, enabling withdrawal of such     \\\\\\\"excess\\\\\\\" tokens out of contract.\\\",\\\"params\\\":{\\\"targetAddress\\\":\\\": address to send tokens to\\\",\\\"txExpirationBlock\\\":\\\": block number until which is the transaction valid (inclusive).                           When transaction is processed after this block, it fails.\\\"}}}},\\\"userdoc\\\":{\\\"methods\\\":{}}},\\\"settings\\\":{\\\"compilationTarget\\\":{\\\"/home/james/Code/cosmos-drb-oracle/ethereum/contracts/FetchOracle.sol\\\":\\\"FetchOracle\\\"},\\\"evmVersion\\\":\\\"istanbul\\\",\\\"libraries\\\":{},\\\"metadata\\\":{\\\"bytecodeHash\\\":\\\"ipfs\\\"},\\\"optimizer\\\":{\\\"enabled\\\":true,\\\"runs\\\":200},\\\"remappings\\\":[]},\\\"sources\\\":{\\\"/home/james/Code/cosmos-drb-oracle/ethereum/contracts/FetchOracle.sol\\\":{\\\"keccak256\\\":\\\"0x9692300de48590be183d31bc7b918e25b1defc6a685a6da9483cac3ba69c0a76\\\",\\\"license\\\":\\\"Apache-2.0\\\",\\\"urls\\\":[\\\"bzz-raw://72d7f74f5784f94c735e2e47c822fa5d24a6dc47d40bef17d22f115f41cc8940\\\",\\\"dweb:/ipfs/QmeuyFTWyzcx8rULNoHMYJmqJXPauHMnBgLckyh2XaPNEV\\\"]},\\\"/home/james/Code/cosmos-drb-oracle/ethereum/openzeppelin/contracts/GSN/Context.sol\\\":{\\\"keccak256\\\":\\\"0xdb26cbf4d028490f49831a7865c2fe1b28db44b535ca8d343785a3b768aae183\\\",\\\"license\\\":\\\"MIT\\\",\\\"urls\\\":[\\\"bzz-raw://840b14ce0315c47d49ba328f1f9fa7654ded1c9e1559e6c5e777a7b2dc28bf0a\\\",\\\"dweb:/ipfs/QmTLLabn4wcfGro9LEmUXUN2nwKqZSotXMvjDCLXEnLtZP\\\"]},\\\"/home/james/Code/cosmos-drb-oracle/ethereum/openzeppelin/contracts/access/AccessControl.sol\\\":{\\\"keccak256\\\":\\\"0x92f7900d382761c7faefeaced81c6b4f1aae909ed0551803bfe8f27101956360\\\",\\\"license\\\":\\\"MIT\\\",\\\"urls\\\":[\\\"bzz-raw://407c0864143968542e5cf5aa7556916d2cf292b201e3dadb65662e9a3aa24187\\\",\\\"dweb:/ipfs/QmSnXzYAUaGLGr7uofRbgQraTJvatbjQLBPhyYiMd18oUJ\\\"]},\\\"/home/james/Code/cosmos-drb-oracle/ethereum/openzeppelin/contracts/math/SafeMath.sol\\\":{\\\"keccak256\\\":\\\"0x9a9cf02622cd7a64261b10534fc3260449da25c98c9e96d1b4ae8110a20e5806\\\",\\\"license\\\":\\\"MIT\\\",\\\"urls\\\":[\\\"bzz-raw://2df142592d1dc267d9549049ee3317fa190d2f87eaa565f86ab05ec83f7ab8f5\\\",\\\"dweb:/ipfs/QmSkJtcfWo7c42KnL5hho6GFxK6HRNV91XABx1P7xDtfLV\\\"]},\\\"/home/james/Code/cosmos-drb-oracle/ethereum/openzeppelin/contracts/token/ERC20/IERC20.sol\\\":{\\\"keccak256\\\":\\\"0x5c26b39d26f7ed489e555d955dcd3e01872972e71fdd1528e93ec164e4f23385\\\",\\\"license\\\":\\\"MIT\\\",\\\"urls\\\":[\\\"bzz-raw://efdc632af6960cf865dbc113665ea1f5b90eab75cc40ec062b2f6ae6da582017\\\",\\\"dweb:/ipfs/QmfAZFDuG62vxmAN9DnXApv7e7PMzPqi4RkqqZHLMSQiY5\\\"]},\\\"/home/james/Code/cosmos-drb-oracle/ethereum/openzeppelin/contracts/utils/Address.sol\\\":{\\\"keccak256\\\":\\\"0xf5fa8cbdffa5ef8be49b246b5628facc30b71707e78a45d80d93b64eff3fe390\\\",\\\"license\\\":\\\"MIT\\\",\\\"urls\\\":[\\\"bzz-raw://774e78a9ff32792cc95db4d2ceaf3a7965bb7f0bea5e6cb7cff182b450d44b37\\\",\\\"dweb:/ipfs/QmRRMC4uj7eAcLW7chynA3sNEYULMFazdLwQHKHQPyzAbA\\\"]},\\\"/home/james/Code/cosmos-drb-oracle/ethereum/openzeppelin/contracts/utils/EnumerableSet.sol\\\":{\\\"keccak256\\\":\\\"0xb2a11b236f073662f5a196995863f51c11d006bf7c3de158b316dfa1506c4b79\\\",\\\"license\\\":\\\"MIT\\\",\\\"urls\\\":[\\\"bzz-raw://8651649cf0b9efa18c3b01c030276fa320d41adbdc286833417e7f36e357b2f3\\\",\\\"dweb:/ipfs/QmafhM2Nd1aP43QVB1eRRZaqRXQKswNfQcWi8U8xjrxCfN\\\"]}},\\\"version\\\":1}\",\n  \"bytecode\": \"0x60806040523480156200001157600080fd5b5060405162001bc538038062001bc5833981810160405260408110156200003757600080fd5b508051602090910151620000566000336001600160e01b03620000e016565b6001600160a01b03821662000078576009805460ff191660011790556200009e565b6009805460ff19169055600180546001600160a01b0319166001600160a01b0384161790555b620000cd6205a66d620000b96001600160e01b03620000f916565b620000fd60201b620010611790919060201c565b6002556000196003556004555062000277565b620000f582826001600160e01b036200016116565b5050565b4390565b60008282018381101562000158576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b90505b92915050565b60008281526020818152604090912062000186918390620010bb620001e3821b17901c565b15620000f5576200019f6001600160e01b036200020316565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b600062000158836001600160a01b0384166001600160e01b036200020716565b3390565b60006200021e83836001600160e01b036200025f16565b62000256575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556200015b565b5060006200015b565b60009081526001919091016020526040902054151590565b61193e80620002876000396000f3fe6080604052600436106101665760003560e01c806391d14854116100d1578063c5b37c221161008a578063d83222ec11610064578063d83222ec14610527578063ecd0c0c31461053c578063f1209ef714610551578063f7e1c7481461056657610166565b8063c5b37c22146104af578063ca15c873146104c4578063d547741f146104ee57610166565b806391d14854146103b15780639608df4b146103fe578063993240a3146104375780639bc1890914610470578063a217fddf14610485578063c0ba241b1461049a57610166565b806336568abe1161012357806336568abe14610275578063372646bb146102ae57806352f7c988146102c357806353e052ac146102f357806359f9f7cc1461032c5780639010d07c1461036557610166565b806307e2cea51461016b578063248a9ca3146101925780632f2ff15d146101bc578063323f4501146101f757806332a1bd7014610230578063347908df14610245575b600080fd5b34801561017757600080fd5b5061018061058e565b60408051918252519081900360200190f35b34801561019e57600080fd5b50610180600480360360208110156101b557600080fd5b50356105b1565b3480156101c857600080fd5b506101f5600480360360408110156101df57600080fd5b50803590602001356001600160a01b03166105c6565b005b34801561020357600080fd5b506101f56004803603604081101561021a57600080fd5b506001600160a01b038135169060200135610632565b34801561023c57600080fd5b50610180610748565b34801561025157600080fd5b506101f56004803603604081101561026857600080fd5b508035906020013561074e565b34801561028157600080fd5b506101f56004803603604081101561029857600080fd5b50803590602001356001600160a01b031661086e565b3480156102ba57600080fd5b506101806108cf565b3480156102cf57600080fd5b506101f5600480360360408110156102e657600080fd5b50803590602001356108d6565b3480156102ff57600080fd5b506101f56004803603604081101561031657600080fd5b506001600160a01b0381351690602001356109db565b34801561033857600080fd5b506101f56004803603606081101561034f57600080fd5b5080359060ff6020820135169060400135610baa565b34801561037157600080fd5b506103956004803603604081101561038857600080fd5b5080359060200135610cd1565b604080516001600160a01b039092168252519081900360200190f35b3480156103bd57600080fd5b506103ea600480360360408110156103d457600080fd5b50803590602001356001600160a01b0316610cf8565b604080519115158252519081900360200190f35b34801561040a57600080fd5b506101f56004803603604081101561042157600080fd5b506001600160a01b038135169060200135610d16565b34801561044357600080fd5b5061044c610f74565b6040518082600181111561045c57fe5b60ff16815260200191505060405180910390f35b34801561047c57600080fd5b50610180610f7d565b34801561049157600080fd5b50610180610f83565b3480156104a657600080fd5b50610180610f88565b3480156104bb57600080fd5b50610180610fad565b3480156104d057600080fd5b50610180600480360360208110156104e757600080fd5b5035610fb3565b3480156104fa57600080fd5b506101f56004803603604081101561051157600080fd5b50803590602001356001600160a01b0316610fca565b34801561053357600080fd5b50610180611023565b34801561054857600080fd5b50610395611029565b34801561055d57600080fd5b50610180611038565b61056e61103e565b6040805193845260ff909216602084015282820152519081900360600190f35b604080516a4f5241434c455f524f4c4560a81b8152905190819003600b01902081565b60009081526020819052604090206002015490565b6000828152602081905260409020600201546105e9906105e46110d0565b610cf8565b6106245760405162461bcd60e51b815260040180806020018281038252602f815260200180611857602f913960400191505060405180910390fd5b61062e82826110d4565b5050565b808061063c611143565b1115610685576040805162461bcd60e51b8152602060048201526013602482015272151c985b9cd858dd1a5bdb88195e1c1a5c9959606a1b604482015290519081900360640190fd5b61068d611147565b6106de576040805162461bcd60e51b815260206004820152601e60248201527f43616c6c6572206973206e6f7420616e2061646d696e6973747261746f720000604482015290519081900360640190fd5b6005546106ea57610743565b6106f683600554611158565b600554604080516001600160a01b0386168152602081019290925280517fe6646aed3b0543182f7396de55e4a49dfbddb4e684eece060fbaa5b03ff275149281900390910190a160006005555b505050565b60025481565b8080610758611143565b11156107a1576040805162461bcd60e51b8152602060048201526013602482015272151c985b9cd858dd1a5bdb88195e1c1a5c9959606a1b604482015290519081900360640190fd5b6107a9611147565b806107db5750604080516c44454c45474154455f524f4c4560981b8152905190819003600d0190206107db9033610cf8565b6108165760405162461bcd60e51b81526004018080602001828103825260248152602001806118866024913960400191505060405180910390fd5b6000610820611143565b905080841061082f5783610831565b805b600381905560408051918252517f68b095021b1f40fe513109f513c66692f0b3219aee674a69f4efc57badb8201d9181900360200190a150505050565b6108766110d0565b6001600160a01b0316816001600160a01b0316146108c55760405162461bcd60e51b815260040180806020018281038252602f8152602001806118da602f913960400191505060405180910390fd5b61062e828261133f565b6205a66d81565b80806108e0611143565b1115610929576040805162461bcd60e51b8152602060048201526013602482015272151c985b9cd858dd1a5bdb88195e1c1a5c9959606a1b604482015290519081900360640190fd5b610931611147565b806109635750604080516c44454c45474154455f524f4c4560981b8152905190819003600d0190206109639033610cf8565b61099e5760405162461bcd60e51b81526004018080602001828103825260248152602001806118866024913960400191505060405180910390fd5b60048390556040805184815290517f8c4d35e54a3f2ef1134138fd8ea3daee6a3c89e10d2665996babdf70261e2c769181900360200190a1505050565b80806109e5611143565b1115610a2e576040805162461bcd60e51b8152602060048201526013602482015272151c985b9cd858dd1a5bdb88195e1c1a5c9959606a1b604482015290519081900360640190fd5b610a36611147565b610a87576040805162461bcd60e51b815260206004820152601e60248201527f43616c6c6572206973206e6f7420616e2061646d696e6973747261746f720000604482015290519081900360640190fd5b6000600160095460ff166001811115610a9c57fe5b1415610aa9575047610b3c565b600060095460ff166001811115610abc57fe5b1415610b3c57600154604080516370a0823160e01b815230600482015290516001600160a01b03909216916370a0823191602480820192602092909190829003018186803b158015610b0d57600080fd5b505afa158015610b21573d6000803e3d6000fd5b505050506040513d6020811015610b3757600080fd5b505190505b6000610b53600554836113ae90919063ffffffff16565b9050610b5f8582611158565b604080516001600160a01b03871681526020810183905281517f7f66376a5ef2f39ab4ee2ee6e400606624e66929dba5d82df5b14dd0070a8a87929181900390910190a15050505050565b8080610bb4611143565b1115610bfd576040805162461bcd60e51b8152602060048201526013602482015272151c985b9cd858dd1a5bdb88195e1c1a5c9959606a1b604482015290519081900360640190fd5b604080516a4f5241434c455f524f4c4560a81b8152905190819003600b019020610c279033610cf8565b610c78576040805162461bcd60e51b815260206004820152601760248201527f43616c6c6572206973206e6f7420616e206f7261636c65000000000000000000604482015290519081900360640190fd5b60068490556007805460ff191660ff8516179055610c94611143565b600881905560408051918252517f47d1a578550704475fb893bcd176030186929dfaf9c7a4cac4ddc882bd000d429181900360200190a150505050565b6000828152602081905260408120610cef908363ffffffff6113f016565b90505b92915050565b6000828152602081905260408120610cef908363ffffffff6113fc16565b8080610d20611143565b1115610d69576040805162461bcd60e51b8152602060048201526013602482015272151c985b9cd858dd1a5bdb88195e1c1a5c9959606a1b604482015290519081900360640190fd5b610d71611147565b610dc2576040805162461bcd60e51b815260206004820152601e60248201527f43616c6c6572206973206e6f7420616e2061646d696e6973747261746f720000604482015290519081900360640190fd5b610dca611143565b6002541015610e20576040805162461bcd60e51b815260206004820152601b60248201527f4561726c696573742064656c657465206e6f7420726561636865640000000000604482015290519081900360640190fd5b600060095460ff166001811115610e3357fe5b1415610f3f57600154604080516370a0823160e01b815230600482015290516000926001600160a01b0316916370a08231916024808301926020929190829003018186803b158015610e8457600080fd5b505afa158015610e98573d6000803e3d6000fd5b505050506040513d6020811015610eae57600080fd5b50516001546040805163a9059cbb60e01b81526001600160a01b03888116600483015260248201859052915193945091169163a9059cbb916044808201926020929091908290030181600087803b158015610f0857600080fd5b505af1158015610f1c573d6000803e3d6000fd5b505050506040513d6020811015610f3257600080fd5b5051610f3d57600080fd5b505b6040517f41dbff2a3f1765d729d9e0651e4a45e813fb9a45fc4dd4f99ac3aa35bbab579290600090a1826001600160a01b0316ff5b60095460ff1681565b60085490565b600081565b604080516c44454c45474154455f524f4c4560981b8152905190819003600d01902081565b60045481565b6000818152602081905260408120610cf290611411565b600082815260208190526040902060020154610fe8906105e46110d0565b6108c55760405162461bcd60e51b81526004018080602001828103825260308152602001806118aa6030913960400191505060405180910390fd5b60055481565b6001546001600160a01b031681565b60035481565b600080600061104b61141c565b5050600654600754600854919360ff9091169250565b600082820183811015610cef576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b6000610cef836001600160a01b0384166115f8565b3390565b60008281526020819052604090206110f2908263ffffffff6110bb16565b1561062e576110ff6110d0565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b4390565b60006111538133610cf8565b905090565b6001600160a01b0382166111ac576040805162461bcd60e51b8152602060048201526016602482015275546172676574206973207a65726f206164647265737360501b604482015290519081900360640190fd5b600160095460ff1660018111156111bf57fe5b1415611201576040516001600160a01b0383169082156108fc029083906000818181858888f193505050501580156111fb573d6000803e3d6000fd5b5061062e565b600060095460ff16600181111561121457fe5b14156112f2576001546040805163a9059cbb60e01b81526001600160a01b038581166004830152602482018590529151919092169163a9059cbb9160448083019260209291908290030181600087803b15801561127057600080fd5b505af1158015611284573d6000803e3d6000fd5b505050506040513d602081101561129a57600080fd5b50516112ed576040805162461bcd60e51b815260206004820181905260248201527f496e737566662e204645542066756e6473206f6e20636f6e74722e2061646472604482015290519081900360640190fd5b61062e565b6040805162461bcd60e51b815260206004820181905260248201527f556e657870656374656420636f6e7472616374206665652063757272656e6379604482015290519081900360640190fd5b600082815260208190526040902061135d908263ffffffff61164216565b1561062e5761136a6110d0565b6001600160a01b0316816001600160a01b0316837ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b60405160405180910390a45050565b6000610cef83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250611657565b6000610cef83836116ee565b6000610cef836001600160a01b038416611752565b6000610cf28261176a565b600160095460ff16600181111561142f57fe5b14156114e857600454341415611444576114e3565b6004543411156114965760045433906108fc9061146890349063ffffffff6113ae16565b6040518115909202916000818181858888f19350505050158015611490573d6000803e3d6000fd5b506114e3565b6040805162461bcd60e51b815260206004820181905260248201527f496e7375662e2045544820616d6f756e742073656e742062792063616c6c6572604482015290519081900360640190fd5b6115de565b600060095460ff1660018111156114fb57fe5b14156112f25760015460048054604080516323b872dd60e01b815233938101939093523060248401526044830191909152516001600160a01b03909216916323b872dd916064808201926020929091908290030181600087803b15801561156157600080fd5b505af1158015611575573d6000803e3d6000fd5b505050506040513d602081101561158b57600080fd5b50516114e3576040805162461bcd60e51b815260206004820181905260248201527f496e7375662e2046455420616c6c6f772e206f6e2063616c6c65722061646472604482015290519081900360640190fd5b6004546005546115f39163ffffffff61106116565b600555565b60006116048383611752565b61163a57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610cf2565b506000610cf2565b6000610cef836001600160a01b03841661176e565b600081848411156116e65760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b838110156116ab578181015183820152602001611693565b50505050905090810190601f1680156116d85780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b815460009082106117305760405162461bcd60e51b81526004018080602001828103825260228152602001806118356022913960400191505060405180910390fd5b82600001828154811061173f57fe5b9060005260206000200154905092915050565b60009081526001919091016020526040902054151590565b5490565b6000818152600183016020526040812054801561182a57835460001980830191908101906000908790839081106117a157fe5b90600052602060002001549050808760000184815481106117be57fe5b6000918252602080832090910192909255828152600189810190925260409020908401905586548790806117ee57fe5b60019003818190600052602060002001600090559055866001016000878152602001908152602001600020600090556001945050505050610cf2565b6000915050610cf256fe456e756d657261626c655365743a20696e646578206f7574206f6620626f756e6473416363657373436f6e74726f6c3a2073656e646572206d75737420626520616e2061646d696e20746f206772616e7443616c6c6572206973206e656974686572206f776e6572206e6f722064656c6567617465416363657373436f6e74726f6c3a2073656e646572206d75737420626520616e2061646d696e20746f207265766f6b65416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636520726f6c657320666f722073656c66a2646970667358221220cc47090461aca71dac0f4022e5d6bb4238845310292224f2b873ef1d2a226c1464736f6c63430006080033\",\n  \"deployedBytecode\": \"0x6080604052600436106101665760003560e01c806391d14854116100d1578063c5b37c221161008a578063d83222ec11610064578063d83222ec14610527578063ecd0c0c31461053c578063f1209ef714610551578063f7e1c7481461056657610166565b8063c5b37c22146104af578063ca15c873146104c4578063d547741f146104ee57610166565b806391d14854146103b15780639608df4b146103fe578063993240a3146104375780639bc1890914610470578063a217fddf14610485578063c0ba241b1461049a57610166565b806336568abe1161012357806336568abe14610275578063372646bb146102ae57806352f7c988146102c357806353e052ac146102f357806359f9f7cc1461032c5780639010d07c1461036557610166565b806307e2cea51461016b578063248a9ca3146101925780632f2ff15d146101bc578063323f4501146101f757806332a1bd7014610230578063347908df14610245575b600080fd5b34801561017757600080fd5b5061018061058e565b60408051918252519081900360200190f35b34801561019e57600080fd5b50610180600480360360208110156101b557600080fd5b50356105b1565b3480156101c857600080fd5b506101f5600480360360408110156101df57600080fd5b50803590602001356001600160a01b03166105c6565b005b34801561020357600080fd5b506101f56004803603604081101561021a57600080fd5b506001600160a01b038135169060200135610632565b34801561023c57600080fd5b50610180610748565b34801561025157600080fd5b506101f56004803603604081101561026857600080fd5b508035906020013561074e565b34801561028157600080fd5b506101f56004803603604081101561029857600080fd5b50803590602001356001600160a01b031661086e565b3480156102ba57600080fd5b506101806108cf565b3480156102cf57600080fd5b506101f5600480360360408110156102e657600080fd5b50803590602001356108d6565b3480156102ff57600080fd5b506101f56004803603604081101561031657600080fd5b506001600160a01b0381351690602001356109db565b34801561033857600080fd5b506101f56004803603606081101561034f57600080fd5b5080359060ff6020820135169060400135610baa565b34801561037157600080fd5b506103956004803603604081101561038857600080fd5b5080359060200135610cd1565b604080516001600160a01b039092168252519081900360200190f35b3480156103bd57600080fd5b506103ea600480360360408110156103d457600080fd5b50803590602001356001600160a01b0316610cf8565b604080519115158252519081900360200190f35b34801561040a57600080fd5b506101f56004803603604081101561042157600080fd5b506001600160a01b038135169060200135610d16565b34801561044357600080fd5b5061044c610f74565b6040518082600181111561045c57fe5b60ff16815260200191505060405180910390f35b34801561047c57600080fd5b50610180610f7d565b34801561049157600080fd5b50610180610f83565b3480156104a657600080fd5b50610180610f88565b3480156104bb57600080fd5b50610180610fad565b3480156104d057600080fd5b50610180600480360360208110156104e757600080fd5b5035610fb3565b3480156104fa57600080fd5b506101f56004803603604081101561051157600080fd5b50803590602001356001600160a01b0316610fca565b34801561053357600080fd5b50610180611023565b34801561054857600080fd5b50610395611029565b34801561055d57600080fd5b50610180611038565b61056e61103e565b6040805193845260ff909216602084015282820152519081900360600190f35b604080516a4f5241434c455f524f4c4560a81b8152905190819003600b01902081565b60009081526020819052604090206002015490565b6000828152602081905260409020600201546105e9906105e46110d0565b610cf8565b6106245760405162461bcd60e51b815260040180806020018281038252602f815260200180611857602f913960400191505060405180910390fd5b61062e82826110d4565b5050565b808061063c611143565b1115610685576040805162461bcd60e51b8152602060048201526013602482015272151c985b9cd858dd1a5bdb88195e1c1a5c9959606a1b604482015290519081900360640190fd5b61068d611147565b6106de576040805162461bcd60e51b815260206004820152601e60248201527f43616c6c6572206973206e6f7420616e2061646d696e6973747261746f720000604482015290519081900360640190fd5b6005546106ea57610743565b6106f683600554611158565b600554604080516001600160a01b0386168152602081019290925280517fe6646aed3b0543182f7396de55e4a49dfbddb4e684eece060fbaa5b03ff275149281900390910190a160006005555b505050565b60025481565b8080610758611143565b11156107a1576040805162461bcd60e51b8152602060048201526013602482015272151c985b9cd858dd1a5bdb88195e1c1a5c9959606a1b604482015290519081900360640190fd5b6107a9611147565b806107db5750604080516c44454c45474154455f524f4c4560981b8152905190819003600d0190206107db9033610cf8565b6108165760405162461bcd60e51b81526004018080602001828103825260248152602001806118866024913960400191505060405180910390fd5b6000610820611143565b905080841061082f5783610831565b805b600381905560408051918252517f68b095021b1f40fe513109f513c66692f0b3219aee674a69f4efc57badb8201d9181900360200190a150505050565b6108766110d0565b6001600160a01b0316816001600160a01b0316146108c55760405162461bcd60e51b815260040180806020018281038252602f8152602001806118da602f913960400191505060405180910390fd5b61062e828261133f565b6205a66d81565b80806108e0611143565b1115610929576040805162461bcd60e51b8152602060048201526013602482015272151c985b9cd858dd1a5bdb88195e1c1a5c9959606a1b604482015290519081900360640190fd5b610931611147565b806109635750604080516c44454c45474154455f524f4c4560981b8152905190819003600d0190206109639033610cf8565b61099e5760405162461bcd60e51b81526004018080602001828103825260248152602001806118866024913960400191505060405180910390fd5b60048390556040805184815290517f8c4d35e54a3f2ef1134138fd8ea3daee6a3c89e10d2665996babdf70261e2c769181900360200190a1505050565b80806109e5611143565b1115610a2e576040805162461bcd60e51b8152602060048201526013602482015272151c985b9cd858dd1a5bdb88195e1c1a5c9959606a1b604482015290519081900360640190fd5b610a36611147565b610a87576040805162461bcd60e51b815260206004820152601e60248201527f43616c6c6572206973206e6f7420616e2061646d696e6973747261746f720000604482015290519081900360640190fd5b6000600160095460ff166001811115610a9c57fe5b1415610aa9575047610b3c565b600060095460ff166001811115610abc57fe5b1415610b3c57600154604080516370a0823160e01b815230600482015290516001600160a01b03909216916370a0823191602480820192602092909190829003018186803b158015610b0d57600080fd5b505afa158015610b21573d6000803e3d6000fd5b505050506040513d6020811015610b3757600080fd5b505190505b6000610b53600554836113ae90919063ffffffff16565b9050610b5f8582611158565b604080516001600160a01b03871681526020810183905281517f7f66376a5ef2f39ab4ee2ee6e400606624e66929dba5d82df5b14dd0070a8a87929181900390910190a15050505050565b8080610bb4611143565b1115610bfd576040805162461bcd60e51b8152602060048201526013602482015272151c985b9cd858dd1a5bdb88195e1c1a5c9959606a1b604482015290519081900360640190fd5b604080516a4f5241434c455f524f4c4560a81b8152905190819003600b019020610c279033610cf8565b610c78576040805162461bcd60e51b815260206004820152601760248201527f43616c6c6572206973206e6f7420616e206f7261636c65000000000000000000604482015290519081900360640190fd5b60068490556007805460ff191660ff8516179055610c94611143565b600881905560408051918252517f47d1a578550704475fb893bcd176030186929dfaf9c7a4cac4ddc882bd000d429181900360200190a150505050565b6000828152602081905260408120610cef908363ffffffff6113f016565b90505b92915050565b6000828152602081905260408120610cef908363ffffffff6113fc16565b8080610d20611143565b1115610d69576040805162461bcd60e51b8152602060048201526013602482015272151c985b9cd858dd1a5bdb88195e1c1a5c9959606a1b604482015290519081900360640190fd5b610d71611147565b610dc2576040805162461bcd60e51b815260206004820152601e60248201527f43616c6c6572206973206e6f7420616e2061646d696e6973747261746f720000604482015290519081900360640190fd5b610dca611143565b6002541015610e20576040805162461bcd60e51b815260206004820152601b60248201527f4561726c696573742064656c657465206e6f7420726561636865640000000000604482015290519081900360640190fd5b600060095460ff166001811115610e3357fe5b1415610f3f57600154604080516370a0823160e01b815230600482015290516000926001600160a01b0316916370a08231916024808301926020929190829003018186803b158015610e8457600080fd5b505afa158015610e98573d6000803e3d6000fd5b505050506040513d6020811015610eae57600080fd5b50516001546040805163a9059cbb60e01b81526001600160a01b03888116600483015260248201859052915193945091169163a9059cbb916044808201926020929091908290030181600087803b158015610f0857600080fd5b505af1158015610f1c573d6000803e3d6000fd5b505050506040513d6020811015610f3257600080fd5b5051610f3d57600080fd5b505b6040517f41dbff2a3f1765d729d9e0651e4a45e813fb9a45fc4dd4f99ac3aa35bbab579290600090a1826001600160a01b0316ff5b60095460ff1681565b60085490565b600081565b604080516c44454c45474154455f524f4c4560981b8152905190819003600d01902081565b60045481565b6000818152602081905260408120610cf290611411565b600082815260208190526040902060020154610fe8906105e46110d0565b6108c55760405162461bcd60e51b81526004018080602001828103825260308152602001806118aa6030913960400191505060405180910390fd5b60055481565b6001546001600160a01b031681565b60035481565b600080600061104b61141c565b5050600654600754600854919360ff9091169250565b600082820183811015610cef576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b6000610cef836001600160a01b0384166115f8565b3390565b60008281526020819052604090206110f2908263ffffffff6110bb16565b1561062e576110ff6110d0565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b4390565b60006111538133610cf8565b905090565b6001600160a01b0382166111ac576040805162461bcd60e51b8152602060048201526016602482015275546172676574206973207a65726f206164647265737360501b604482015290519081900360640190fd5b600160095460ff1660018111156111bf57fe5b1415611201576040516001600160a01b0383169082156108fc029083906000818181858888f193505050501580156111fb573d6000803e3d6000fd5b5061062e565b600060095460ff16600181111561121457fe5b14156112f2576001546040805163a9059cbb60e01b81526001600160a01b038581166004830152602482018590529151919092169163a9059cbb9160448083019260209291908290030181600087803b15801561127057600080fd5b505af1158015611284573d6000803e3d6000fd5b505050506040513d602081101561129a57600080fd5b50516112ed576040805162461bcd60e51b815260206004820181905260248201527f496e737566662e204645542066756e6473206f6e20636f6e74722e2061646472604482015290519081900360640190fd5b61062e565b6040805162461bcd60e51b815260206004820181905260248201527f556e657870656374656420636f6e7472616374206665652063757272656e6379604482015290519081900360640190fd5b600082815260208190526040902061135d908263ffffffff61164216565b1561062e5761136a6110d0565b6001600160a01b0316816001600160a01b0316837ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b60405160405180910390a45050565b6000610cef83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250611657565b6000610cef83836116ee565b6000610cef836001600160a01b038416611752565b6000610cf28261176a565b600160095460ff16600181111561142f57fe5b14156114e857600454341415611444576114e3565b6004543411156114965760045433906108fc9061146890349063ffffffff6113ae16565b6040518115909202916000818181858888f19350505050158015611490573d6000803e3d6000fd5b506114e3565b6040805162461bcd60e51b815260206004820181905260248201527f496e7375662e2045544820616d6f756e742073656e742062792063616c6c6572604482015290519081900360640190fd5b6115de565b600060095460ff1660018111156114fb57fe5b14156112f25760015460048054604080516323b872dd60e01b815233938101939093523060248401526044830191909152516001600160a01b03909216916323b872dd916064808201926020929091908290030181600087803b15801561156157600080fd5b505af1158015611575573d6000803e3d6000fd5b505050506040513d602081101561158b57600080fd5b50516114e3576040805162461bcd60e51b815260206004820181905260248201527f496e7375662e2046455420616c6c6f772e206f6e2063616c6c65722061646472604482015290519081900360640190fd5b6004546005546115f39163ffffffff61106116565b600555565b60006116048383611752565b61163a57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610cf2565b506000610cf2565b6000610cef836001600160a01b03841661176e565b600081848411156116e65760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b838110156116ab578181015183820152602001611693565b50505050905090810190601f1680156116d85780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b815460009082106117305760405162461bcd60e51b81526004018080602001828103825260228152602001806118356022913960400191505060405180910390fd5b82600001828154811061173f57fe5b9060005260206000200154905092915050565b60009081526001919091016020526040902054151590565b5490565b6000818152600183016020526040812054801561182a57835460001980830191908101906000908790839081106117a157fe5b90600052602060002001549050808760000184815481106117be57fe5b6000918252602080832090910192909255828152600189810190925260409020908401905586548790806117ee57fe5b60019003818190600052602060002001600090559055866001016000878152602001908152602001600020600090556001945050505050610cf2565b6000915050610cf256fe456e756d657261626c655365743a20696e646578206f7574206f6620626f756e6473416363657373436f6e74726f6c3a2073656e646572206d75737420626520616e2061646d696e20746f206772616e7443616c6c6572206973206e656974686572206f776e6572206e6f722064656c6567617465416363657373436f6e74726f6c3a2073656e646572206d75737420626520616e2061646d696e20746f207265766f6b65416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636520726f6c657320666f722073656c66a2646970667358221220cc47090461aca71dac0f4022e5d6bb4238845310292224f2b873ef1d2a226c1464736f6c63430006080033\",\n  \"sourceMap\": \"1550:9995:4:-:0;;;3624:467;5:9:-1;2:2;;;27:1;24;17:12;2:2;3624:467:4;;;;;;;;;;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;3624:467:4;;;;;;;3695:42;1762:4:7;3726:10:4;-1:-1:-1;;;;;3695:10:4;:42;:::i;:::-;-1:-1:-1;;;;;3752:26:4;;3748:193;;3794:12;:30;;-1:-1:-1;;3794:30:4;3809:15;3794:30;;;3748:193;;;3855:12;:32;;-1:-1:-1;;3855:32:4;;;-1:-1:-1;3901:29:4;;-1:-1:-1;;;;;;3901:29:4;-1:-1:-1;;;;;3901:29:4;;;;;3748:193;3969:47;2272:6;3969:17;-1:-1:-1;;;;;3969:15:4;:17;:::i;:::-;:21;;;;;;:47;;;;:::i;:::-;3951:15;:65;-1:-1:-1;;4026:17:4;:31;4067:4;:17;-1:-1:-1;1550:9995:4;;6578:110:7;6656:25;6667:4;6673:7;-1:-1:-1;;;;;6656:10:7;:25;:::i;:::-;6578:110;;:::o;9537:106:4:-;9624:12;9537:106;:::o;874:176:8:-;932:7;963:5;;;986:6;;;;978:46;;;;;-1:-1:-1;;;978:46:8;;;;;;;;;;;;;;;;;;;;;;;;;;;;1042:1;-1:-1:-1;874:176:8;;;;;:::o;7015:184:7:-;7088:6;:12;;;;;;;;;;;:33;;7113:7;;7088:24;;;;;:33;;:::i;:::-;7084:109;;;7169:12;-1:-1:-1;;;;;7169:10:7;:12;:::i;:::-;-1:-1:-1;;;;;7142:40:7;7160:7;-1:-1:-1;;;;;7142:40:7;7154:4;7142:40;;;;;;;;;;7015:184;;:::o;4864:141:13:-;4934:4;4957:41;4962:3;-1:-1:-1;;;;;4982:14:13;;-1:-1:-1;;;;;4957:4:13;:41;:::i;590:104:6:-;677:10;590:104;:::o;1611:404:13:-;1674:4;1695:21;1705:3;1710:5;-1:-1:-1;;;;;1695:9:13;:21;:::i;:::-;1690:319;;-1:-1:-1;27:10;;39:1;23:18;;;45:23;;1732:11:13;:23;;;;;;;;;;;;;1912:18;;1890:19;;;:12;;;:19;;;;;;:40;;;;1944:11;;1690:319;-1:-1:-1;1993:5:13;1986:12;;3776:127;3849:4;3872:19;;;:12;;;;;:19;;;;;;:24;;;3776:127::o;1550:9995:4:-;;;;;;;\",\n  \"deployedSourceMap\": \"1550:9995:4:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;12:1:-1;9;2:12;2081:62:4;;5:9:-1;2:2;;;27:1;24;17:12;2:2;2081:62:4;;;:::i;:::-;;;;;;;;;;;;;;;;4272:112:7;;5:9:-1;2:2;;;27:1;24;17:12;2:2;4272:112:7;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;4272:112:7;;:::i;4634:223::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;4634:223:7;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;4634:223:7;;;;;;-1:-1:-1;;;;;4634:223:7;;:::i;:::-;;6270:538:4;;5:9:-1;2:2;;;27:1;24;17:12;2:2;6270:538:4;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;;;;;;6270:538:4;;;;;;;;:::i;2361:30::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;2361:30:4;;;:::i;5544:355::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;5544:355:4;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;5544:355:4;;;;;;;:::i;5808:205:7:-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;5808:205:7;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;5808:205:7;;;;;;-1:-1:-1;;;;;5808:205:7;;:::i;2221:57:4:-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;2221:57:4;;;:::i;5110:202::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;5110:202:4;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;5110:202:4;;;;;;;:::i;7471:967::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;7471:967:4;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;;;;;;7471:967:4;;;;;;;;:::i;4098:428::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;4098:428:4;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;4098:428:4;;;;;;;;;;;;;;:::i;3955:136:7:-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;3955:136:7;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;3955:136:7;;;;;;;:::i;:::-;;;;-1:-1:-1;;;;;3955:136:7;;;;;;;;;;;;;;2940:137;;5:9:-1;2:2;;;27:1;24;17:12;2:2;2940:137:7;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;2940:137:7;;;;;;-1:-1:-1;;;;;2940:137:7;;:::i;:::-;;;;;;;;;;;;;;;;;;8759:636:4;;5:9:-1;2:2;;;27:1;24;17:12;2:2;8759:636:4;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;;;;;;8759:636:4;;;;;;;;:::i;2537:31::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;2537:31:4;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;9402:129;;5:9:-1;2:2;;;27:1;24;17:12;2:2;9402:129:4;;;:::i;1717:49:7:-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;1717:49:7;;;:::i;2149:66:4:-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;2149:66:4;;;:::i;2435:19::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;2435:19:4;;;:::i;3245:125:7:-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;3245:125:7;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;3245:125:7;;:::i;5091:226::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;5091:226:7;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;5091:226:7;;;;;;-1:-1:-1;;;;;5091:226:7;;:::i;2460:33:4:-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;2460:33:4;;;:::i;2335:20::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;2335:20:4;;;:::i;2397:32::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;2397:32:4;;;:::i;4533:317::-;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;2081:62;2119:24;;;-1:-1:-1;;;2119:24:4;;;;;;;;;;;;2081:62;:::o;4272:112:7:-;4329:7;4355:12;;;;;;;;;;:22;;;;4272:112::o;4634:223::-;4725:6;:12;;;;;;;;;;:22;;;4717:45;;4749:12;:10;:12::i;:::-;4717:7;:45::i;:::-;4709:105;;;;-1:-1:-1;;;4709:105:7;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4825:25;4836:4;4842:7;4825:10;:25::i;:::-;4634:223;;:::o;6270:538:4:-;6401:17;3283:15;3262:17;:15;:17::i;:::-;:36;;3254:68;;;;;-1:-1:-1;;;3254:68:4;;;;;;;;;;;;-1:-1:-1;;;3254:68:4;;;;;;;;;;;;;;;2764:10:::1;:8;:10::i;:::-;2756:53;;;::::0;;-1:-1:-1;;;2756:53:4;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;::::1;::::0;;;;;;;;;;;;;::::1;;6456:18:::2;::::0;6452:60:::2;;6495:7;;6452:60;6641:56;6663:13;6678:18;;6641:21;:56::i;:::-;6750:18;::::0;6713:56:::2;::::0;;-1:-1:-1;;;;;6713:56:4;::::2;::::0;;::::2;::::0;::::2;::::0;;;;;;::::2;::::0;;;;;;;;::::2;6800:1;6779:18;:22:::0;2819:1:::2;6270:538:::0;;;:::o;2361:30::-;;;;:::o;5544:355::-;5657:17;3283:15;3262:17;:15;:17::i;:::-;:36;;3254:68;;;;;-1:-1:-1;;;3254:68:4;;;;;;;;;;;;-1:-1:-1;;;3254:68:4;;;;;;;;;;;;;;;2920:10:::1;:8;:10::i;:::-;:48;;;-1:-1:-1::0;2189:26:4::1;::::0;;-1:-1:-1;;;2189:26:4;;;;;;;;::::1;::::0;;;2934:34:::1;::::0;2957:10:::1;2934:7;:34::i;:::-;2912:97;;;;-1:-1:-1::0;;;2912:97:4::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5711:25:::2;5739:17;:15;:17::i;:::-;5711:45;;5801:17;5786:12;:32;:67;;5841:12;5786:67;;;5821:17;5786:67;5766:17;:87:::0;;;5868:24:::2;::::0;;;;;;::::2;::::0;;;;::::2;::::0;;::::2;3019:1;5544:355:::0;;;:::o;5808:205:7:-;5905:12;:10;:12::i;:::-;-1:-1:-1;;;;;5894:23:7;:7;-1:-1:-1;;;;;5894:23:7;;5886:83;;;;-1:-1:-1;;;5886:83:7;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5980:26;5992:4;5998:7;5980:11;:26::i;2221:57:4:-;2272:6;2221:57;:::o;5110:202::-;5210:17;3283:15;3262:17;:15;:17::i;:::-;:36;;3254:68;;;;;-1:-1:-1;;;3254:68:4;;;;;;;;;;;;-1:-1:-1;;;3254:68:4;;;;;;;;;;;;;;;2920:10:::1;:8;:10::i;:::-;:48;;;-1:-1:-1::0;2189:26:4::1;::::0;;-1:-1:-1;;;2189:26:4;;;;;;;;::::1;::::0;;;2934:34:::1;::::0;2957:10:::1;2934:7;:34::i;:::-;2912:97;;;;-1:-1:-1::0;;;2912:97:4::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5264:4:::2;:10:::0;;;5289:16:::2;::::0;;;;;;;::::2;::::0;;;;::::2;::::0;;::::2;5110:202:::0;;;:::o;7471:967::-;7603:17;3283:15;3262:17;:15;:17::i;:::-;:36;;3254:68;;;;;-1:-1:-1;;;3254:68:4;;;;;;;;;;;;-1:-1:-1;;;3254:68:4;;;;;;;;;;;;;;;2764:10:::1;:8;:10::i;:::-;2756:53;;;::::0;;-1:-1:-1;;;2756:53:4;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;::::1;::::0;;;;;;;;;;;;;::::1;;7654:23:::2;7708:15;7692:12;::::0;::::2;;::::0;:31;::::2;;;;;;;7688:236;;;-1:-1:-1::0;7765:21:4::2;7688:236;;;7831:17;7815:12;::::0;::::2;;::::0;:33;::::2;;;;;;;7811:113;;;7882:6;::::0;:31:::2;::::0;;-1:-1:-1;;;7882:31:4;;7907:4:::2;7882:31;::::0;::::2;::::0;;;-1:-1:-1;;;;;7882:6:4;;::::2;::::0;:16:::2;::::0;:31;;;;;::::2;::::0;;;;;;;;;:6;:31;::::2;;2:2:-1::0;::::2;;;27:1;24::::0;17:12:::2;2:2;7882:31:4;;;;8:9:-1;5:2;;;45:16;42:1;39::::0;24:38:::2;77:16;74:1;67:27;5:2;7882:31:4;;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28::::0;21:12:::2;4:2;-1:-1:::0;7882:31:4;;-1:-1:-1;7811:113:4::2;8244:20;8267:39;8287:18;;8267:15;:19;;:39;;;;:::i;:::-;8244:62;;8316:50;8338:13;8353:12;8316:21;:50::i;:::-;8381;::::0;;-1:-1:-1;;;;;8381:50:4;::::2;::::0;;::::2;::::0;::::2;::::0;;;;;::::2;::::0;;;;;;;;;::::2;2819:1;;7471:967:::0;;;:::o;4098:428::-;4261:17;3283:15;3262:17;:15;:17::i;:::-;:36;;3254:68;;;;;-1:-1:-1;;;3254:68:4;;;;;;;;;;;;-1:-1:-1;;;3254:68:4;;;;;;;;;;;;;;;2119:24:::1;::::0;;-1:-1:-1;;;2119:24:4;;;;;;;;::::1;::::0;;;3107:32:::1;::::0;3128:10:::1;3107:7;:32::i;:::-;3099:68;;;::::0;;-1:-1:-1;;;3099:68:4;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;::::1;::::0;;;;;;;;;;;;;::::1;;4313:12:::2;:26:::0;;;4349:21;:32;;-1:-1:-1;;4349:32:4::2;;::::0;::::2;;::::0;;4430:17:::2;:15;:17::i;:::-;4391:36:::0;:56;;;4462::::2;::::0;;;;;;::::2;::::0;;;;::::2;::::0;;::::2;4098:428:::0;;;;:::o;3955:136:7:-;4028:7;4054:12;;;;;;;;;;:30;;4078:5;4054:30;:23;:30;:::i;:::-;4047:37;;3955:136;;;;;:::o;2940:137::-;3009:4;3032:12;;;;;;;;;;:38;;3062:7;3032:38;:29;:38;:::i;8759:636:4:-;8885:17;3283:15;3262:17;:15;:17::i;:::-;:36;;3254:68;;;;;-1:-1:-1;;;3254:68:4;;;;;;;;;;;;-1:-1:-1;;;3254:68:4;;;;;;;;;;;;;;;2764:10:::1;:8;:10::i;:::-;2756:53;;;::::0;;-1:-1:-1;;;2756:53:4;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;::::1;::::0;;;;;;;;;;;;;::::1;;8963:17:::2;:15;:17::i;:::-;8944:15;;:36;;8936:76;;;::::0;;-1:-1:-1;;;8936:76:4;;::::2;;::::0;::::2;::::0;::::2;::::0;;;;::::2;::::0;;;;;;;;;;;;;::::2;;9042:17;9026:12;::::0;::::2;;::::0;:33;::::2;;;;;;;9022:191;;;9101:6;::::0;:31:::2;::::0;;-1:-1:-1;;;9101:31:4;;9126:4:::2;9101:31;::::0;::::2;::::0;;;9075:23:::2;::::0;-1:-1:-1;;;;;9101:6:4::2;::::0;:16:::2;::::0;:31;;;;;::::2;::::0;;;;;;;;:6;:31;::::2;;2:2:-1::0;::::2;;;27:1;24::::0;17:12:::2;2:2;9101:31:4;;;;8:9:-1;5:2;;;45:16;42:1;39::::0;24:38:::2;77:16;74:1;67:27;5:2;9101:31:4;;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28::::0;21:12:::2;4:2;-1:-1:::0;9101:31:4;9154:6:::2;::::0;:47:::2;::::0;;-1:-1:-1;;;9154:47:4;;-1:-1:-1;;;;;9154:47:4;;::::2;;::::0;::::2;::::0;;;;;;;;;9101:31;;-1:-1:-1;9154:6:4;::::2;::::0;:15:::2;::::0;:47;;;;;9101:31:::2;::::0;9154:47;;;;;;;;:6:::2;::::0;:47;::::2;;2:2:-1::0;::::2;;;27:1;24::::0;17:12:::2;2:2;9154:47:4;;;;8:9:-1;5:2;;;45:16;42:1;39::::0;24:38:::2;77:16;74:1;67:27;5:2;9154:47:4;;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28::::0;21:12:::2;4:2;-1:-1:::0;9154:47:4;9146:56:::2;;12:1:-1;9::::0;2:12:::2;9146:56:4;9022:191;;9227:17;::::0;::::2;::::0;;;::::2;9374:13;-1:-1:-1::0;;;;;9361:27:4::2;;2537:31:::0;;;;;;:::o;9402:129::-;9488:36;;9402:129;:::o;1717:49:7:-;1762:4;1717:49;:::o;2149:66:4:-;2189:26;;;-1:-1:-1;;;2189:26:4;;;;;;;;;;;;2149:66;:::o;2435:19::-;;;;:::o;3245:125:7:-;3308:7;3334:12;;;;;;;;;;:29;;:27;:29::i;5091:226::-;5183:6;:12;;;;;;;;;;:22;;;5175:45;;5207:12;:10;:12::i;5175:45::-;5167:106;;;;-1:-1:-1;;;5167:106:7;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2460:33:4;;;;:::o;2335:20::-;;;-1:-1:-1;;;;;2335:20:4;;:::o;2397:32::-;;;;:::o;4533:317::-;4601:13;4616:14;4632:31;4679:14;:12;:14::i;:::-;-1:-1:-1;;4711:12:4;:18;4750:21;;4807:36;;4711:18;;4750:21;;;;;-1:-1:-1;4533:317:4:o;874:176:8:-;932:7;963:5;;;986:6;;;;978:46;;;;;-1:-1:-1;;;978:46:8;;;;;;;;;;;;;;;;;;;;;;;;;;;4864:141:13;4934:4;4957:41;4962:3;-1:-1:-1;;;;;4982:14:13;;4957:4;:41::i;590:104:6:-;677:10;590:104;:::o;7015:184:7:-;7088:6;:12;;;;;;;;;;:33;;7113:7;7088:33;:24;:33;:::i;:::-;7084:109;;;7169:12;:10;:12::i;:::-;-1:-1:-1;;;;;7142:40:7;7160:7;-1:-1:-1;;;;;7142:40:7;7154:4;7142:40;;;;;;;;;;7015:184;;:::o;9537:106:4:-;9624:12;9537:106;:::o;2575:111::-;2617:4;2640:39;2617:4;2668:10;2640:7;:39::i;:::-;2633:46;;2575:111;:::o;10753:790::-;-1:-1:-1;;;;;10862:27:4;;10854:62;;;;;-1:-1:-1;;;10854:62:4;;;;;;;;;;;;-1:-1:-1;;;10854:62:4;;;;;;;;;;;;;;;10947:15;10931:12;;;;;:31;;;;;;;;10927:610;;;11108:30;;-1:-1:-1;;;;;11108:22:4;;;:30;;;;;11131:6;;11108:30;;;;11131:6;11108:22;:30;;;;;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;11108:30:4;10927:610;;;11183:17;11167:12;;;;;:33;;;;;;;;11163:374;;;11354:6;;:38;;;-1:-1:-1;;;11354:38:4;;-1:-1:-1;;;;;11354:38:4;;;;;;;;;;;;;;;:6;;;;;:15;;:38;;;;;;;;;;;;;;:6;;:38;;;2:2:-1;;;;27:1;24;17:12;2:2;11354:38:4;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;11354:38:4;;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;11354:38:4;11346:83;;;;;-1:-1:-1;;;11346:83:4;;;;;;;;;;;;;;;;;;;;;;;;;;;;;11163:374;;;11476:50;;;-1:-1:-1;;;11476:50:4;;;;;;;;;;;;;;;;;;;;;;;;;;;;7205:188:7;7279:6;:12;;;;;;;;;;:36;;7307:7;7279:36;:27;:36;:::i;:::-;7275:112;;;7363:12;:10;:12::i;:::-;-1:-1:-1;;;;;7336:40:7;7354:7;-1:-1:-1;;;;;7336:40:7;7348:4;7336:40;;;;;;;;;;7205:188;;:::o;1321:134:8:-;1379:7;1405:43;1409:1;1412;1405:43;;;;;;;;;;;;;;;;;:3;:43::i;6085:147:13:-;6159:7;6201:22;6205:3;6217:5;6201:3;:22::i;5401:156::-;5481:4;5504:46;5514:3;-1:-1:-1;;;;;5534:14:13;;5504:9;:46::i;5638:115::-;5701:7;5727:19;5735:3;5727:7;:19::i;9708:1038:4:-;9775:15;9759:12;;;;;:31;;;;;;;;9755:925;;;9830:4;;9817:9;:17;9813:577;;;;;;10093:4;;10081:9;:16;10077:313;;;10261:4;;10227:10;;:40;;10247:19;;:9;;:19;:13;:19;:::i;:::-;10227:40;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;10227:40:4;10077:313;;;10326:50;;;-1:-1:-1;;;10326:50:4;;;;;;;;;;;;;;;;;;;;;;;;;;;;;9755:925;;;10434:17;10418:12;;;;;:33;;;;;;;;10414:266;;;10483:6;;10530:4;;;10483:52;;;-1:-1:-1;;;10483:52:4;;10503:10;10483:52;;;;;;;10523:4;10483:52;;;;;;;;;;;;-1:-1:-1;;;;;10483:6:4;;;;:19;;:52;;;;;;;;;;;;;;;:6;;:52;;;2:2:-1;;;;27:1;24;17:12;2:2;10483:52:4;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;10483:52:4;;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;10483:52:4;10475:97;;;;;-1:-1:-1;;;10475:97:4;;;;;;;;;;;;;;;;;;;;;;;;;;;;10619:50;10734:4;;10711:18;;:28;;;:22;:28;:::i;:::-;10690:18;:49;9708:1038::o;1611:404:13:-;1674:4;1695:21;1705:3;1710:5;1695:9;:21::i;:::-;1690:319;;-1:-1:-1;27:10;;39:1;23:18;;;45:23;;1732:11:13;:23;;;;;;;;;;;;;1912:18;;1890:19;;;:12;;;:19;;;;;;:40;;;;1944:11;;1690:319;-1:-1:-1;1993:5:13;1986:12;;5173:147;5246:4;5269:44;5277:3;-1:-1:-1;;;;;5297:14:13;;5269:7;:44::i;1746:187:8:-;1832:7;1867:12;1859:6;;;;1851:29;;;;-1:-1:-1;;;1851:29:8;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;1851:29:8;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;1902:5:8;;;1746:187::o;4423:201:13:-;4517:18;;4490:7;;4517:26;-1:-1:-1;4509:73:13;;;;-1:-1:-1;;;4509:73:13;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4599:3;:11;;4611:5;4599:18;;;;;;;;;;;;;;;;4592:25;;4423:201;;;;:::o;3776:127::-;3849:4;3872:19;;;:12;;;;;:19;;;;;;:24;;;3776:127::o;3984:107::-;4066:18;;3984:107::o;2183:1512::-;2249:4;2386:19;;;:12;;;:19;;;;;;2420:15;;2416:1273;;2849:18;;-1:-1:-1;;2801:14:13;;;;2849:22;;;;2777:21;;2849:3;;:22;;3131;;;;;;;;;;;;;;3111:42;;3274:9;3245:3;:11;;3257:13;3245:26;;;;;;;;;;;;;;;;;;;:38;;;;3349:23;;;3391:1;3349:12;;;:23;;;;;;3375:17;;;3349:43;;3498:17;;3349:3;;3498:17;;;;;;;;;;;;;;;;;;;;;;3590:3;:12;;:19;3603:5;3590:19;;;;;;;;;;;3583:26;;;3631:4;3624:11;;;;;;;;2416:1273;3673:5;3666:12;;;;\",\n  \"source\": \"// SPDX-License-Identifier:Apache-2.0\\n//------------------------------------------------------------------------------\\n//\\n//   Copyright 2020 Fetch.AI Limited\\n//\\n//   Licensed under the Apache License, Version 2.0 (the \\\"License\\\");\\n//   you may not use this file except in compliance with the License.\\n//   You may obtain a copy of the License at\\n//\\n//       http://www.apache.org/licenses/LICENSE-2.0\\n//\\n//   Unless required by applicable law or agreed to in writing, software\\n//   distributed under the License is distributed on an \\\"AS IS\\\" BASIS,\\n//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\\n//   See the License for the specific language governing permissions and\\n//   limitations under the License.\\n//\\n//------------------------------------------------------------------------------\\n\\npragma solidity ^0.6.0;\\n\\nimport \\\"../openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"../openzeppelin/contracts/access/AccessControl.sol\\\";\\nimport \\\"../openzeppelin/contracts/math/SafeMath.sol\\\";\\n\\n\\n/**\\n @dev The contract *INTENTIONALLY* does not contain the `receive()` or fallback functions in order to ensure that all\\n      unsolicited direct ETH transfers in to this contract (in direct Transaction) will fail.\\n      Only way how to make successful fee transfer in ETH currency (*IF* contract is initialised for ETH as fee currency),\\n      is to make transfer ETH to caller(client) contract and client contract then is responsible for further\\n      *programmatic* (= *not* via Tx) transfer of fee to this this contract.\\n */\\ncontract FetchOracle is AccessControl {\\n    using SafeMath for uint256;\\n\\n\\n    enum  FeeCurrency { ERC20, ETH }\\n\\n    struct OracleValue {\\n        uint256 value;\\n        uint8 decimals;\\n        uint256 updatedAtEthBlockNumber;\\n    }\\n\\n    event FeeUpdated(uint256 fee);\\n    event Pause(uint256 sinceBlock);\\n    event ExcessTokenWithdrawal(address targetAddress, uint256 amount);\\n    event AccruedFeesWithdrawal(address targetAddress, uint256 amount);\\n    event ContractDeleted();\\n    event OracleValueUpdated(uint256 atBlock); \\n\\n\\n    bytes32 public constant ORACLE_ROLE = keccak256(\\\"ORACLE_ROLE\\\");\\n    bytes32 public constant DELEGATE_ROLE = keccak256(\\\"DELEGATE_ROLE\\\");\\n    uint256 public constant DELETE_PROTECTION_PERIOD = 370285;// 60*24*60*60[s] / (14[s/block]) = 370285[block];\\n\\n    IERC20 public _token;\\n    uint256 public _earliestDelete;\\n    uint256 public _pausedSinceBlock;\\n    uint256 public _fee;\\n    uint256 public _accruedFeesAmount;\\n    OracleValue private _oracleValue;\\n    FeeCurrency public _feeCurrency;\\n\\n    function _isOwner() internal view returns(bool) {\\n        return hasRole(DEFAULT_ADMIN_ROLE, msg.sender);\\n    }\\n\\n    /* Only callable by owner */\\n    modifier onlyOwner() {\\n        require(_isOwner(), \\\"Caller is not an administrator\\\");\\n        _;\\n    }\\n\\n    /* Only callable by owner or delegate */\\n    modifier onlyDelegate() {\\n        require(_isOwner() || hasRole(DELEGATE_ROLE, msg.sender), \\\"Caller is neither owner nor delegate\\\");\\n        _;\\n    }\\n\\n    /* Only callable by oracle */\\n    modifier onlyOracle() {\\n        require(hasRole(ORACLE_ROLE, msg.sender), \\\"Caller is not an oracle\\\");\\n        _;\\n    }\\n\\n    modifier verifyTxExpiration(uint256 expirationBlock) {\\n        require(_getBlockNumber() <= expirationBlock, \\\"Transaction expired\\\");\\n        _;\\n    }\\n\\n    modifier verifyNotPaused() {\\n        require(_pausedSinceBlock > _getBlockNumber(), \\\"Contract has been paused\\\");\\n        _;\\n    }\\n\\n\\n    /*******************\\n    Contract start\\n    *******************/\\n    /**\\n     * @param ERC20Address address of the ERC20 contract\\n     */\\n    constructor(address ERC20Address, uint256 initialFee) public {\\n        _setupRole(DEFAULT_ADMIN_ROLE, msg.sender);\\n\\n        if (ERC20Address == address(0)) {\\n            _feeCurrency = FeeCurrency.ETH;\\n        } else {\\n            _feeCurrency = FeeCurrency.ERC20;\\n            _token = IERC20(ERC20Address);\\n        }\\n\\n        _earliestDelete = _getBlockNumber().add(DELETE_PROTECTION_PERIOD);\\n        _pausedSinceBlock = ~uint256(0);\\n        _fee = initialFee;\\n    }\\n\\n\\n    function updateOracleValue(\\n        uint256 value,\\n        uint8 decimals,\\n        uint256 txExpirationBlock\\n        )\\n        external\\n        verifyTxExpiration(txExpirationBlock)\\n        onlyOracle\\n    {\\n        _oracleValue.value = value;\\n        _oracleValue.decimals = decimals;\\n        _oracleValue.updatedAtEthBlockNumber = _getBlockNumber();\\n        emit OracleValueUpdated(_oracleValue.updatedAtEthBlockNumber); \\n    }\\n\\n\\n    function queryOracleValue()\\n        public payable\\n        returns (uint256 value, uint8 decimals, uint256 updatedAtEthBlockNumber)\\n    {\\n        _withdrawFee();\\n        value = _oracleValue.value;\\n        decimals = _oracleValue.decimals;\\n        updatedAtEthBlockNumber = _oracleValue.updatedAtEthBlockNumber;\\n    }\\n\\n\\n    /**\\n     * @dev Pause the non-administrative interaction with the contract\\n     * @param fee - value of fee\\n     * @param txExpirationBlock - block number defined by Tx sender beyond which transaction becomes invalid\\n     * @dev Owners only\\n     */\\n    function setFee(uint256 fee, uint256 txExpirationBlock)\\n        external\\n        verifyTxExpiration(txExpirationBlock)\\n        onlyDelegate\\n    {\\n        _fee = fee;\\n        emit FeeUpdated(_fee);\\n    }\\n\\n\\n    /**\\n     * @dev Pause the non-administrative interaction with the contract\\n     * @param block_number disallow non-admin. interactions with contract for a _getBlockNumber() >= block_number\\n     * @dev Owners only\\n     */\\n    function pauseSince(uint256 block_number, uint256 txExpirationBlock)\\n        external\\n        verifyTxExpiration(txExpirationBlock)\\n        onlyDelegate\\n    {\\n        uint256 curr_block_number = _getBlockNumber();\\n        _pausedSinceBlock = block_number < curr_block_number ? curr_block_number : block_number;\\n        emit Pause(_pausedSinceBlock);\\n    }\\n\\n\\n    /**\\n     * @dev Withdraw whole balance of all fees accrued in the contract so far.\\n     * @param targetAddress : address to send tokens to\\n     * @param txExpirationBlock : block number until which is the transaction valid (inclusive).\\n     *                            When transaction is processed after this block, it fails.\\n     * @dev Owners only\\n     */\\n    function withdrawAccruedFees(address payable targetAddress, uint256 txExpirationBlock)\\n        external\\n        verifyTxExpiration(txExpirationBlock)\\n        onlyOwner\\n    {\\n        if (_accruedFeesAmount == 0) {\\n            return;\\n        }\\n\\n        // The following method will revert in the case of issue (e.g. not enough balance for transfer, zero address):\\n        _withdrawFromContract(targetAddress, _accruedFeesAmount);\\n\\n        emit AccruedFeesWithdrawal(targetAddress, _accruedFeesAmount);\\n        _accruedFeesAmount = 0;\\n    }\\n\\n\\n    /**\\n     * @dev Withdraw \\\"excess\\\" tokens, which were sent to contract address directly via direct ERC20 transfer(...) or transferFrom(...),\\n     *      without interacting with API of this (FetchOracle) contract, what could be done only by mistake.\\n     *      Thus this method is meant to be used primarily for rescue purposes, enabling withdrawal of such\\n     *      \\\"excess\\\" tokens out of contract.\\n     * @param targetAddress : address to send tokens to\\n     * @param txExpirationBlock : block number until which is the transaction valid (inclusive).\\n     *                            When transaction is processed after this block, it fails.\\n     */\\n    function withdrawExcessTokens(address payable targetAddress, uint256 txExpirationBlock)\\n        external\\n        verifyTxExpiration(txExpirationBlock)\\n        onlyOwner\\n    {\\n        uint256 contractBalance;\\n\\n        if (_feeCurrency == FeeCurrency.ETH)\\n        {\\n            contractBalance = address(this).balance;\\n        }\\n        else if (_feeCurrency == FeeCurrency.ERC20) {\\n            contractBalance = _token.balanceOf(address(this));\\n        } // NOTE(pb): Final else{...} is not necessary since it is checked in the `_withdrawFromContract(...)` call bellow\\n\\n        // NOTE(pb): The following subtraction shall *fail* (revert) IF the contract is in *INCONSISTENT* state,\\n        //           = when contract balance is less than minial expected balance:\\n        uint256 excessAmount = contractBalance.sub(_accruedFeesAmount);\\n        _withdrawFromContract(targetAddress, excessAmount);\\n        emit ExcessTokenWithdrawal(targetAddress, excessAmount);\\n    }\\n\\n\\n    /**\\n     * @dev Delete the contract, transfers the remaining token and ether balance to the specified\\n       payoutAddress\\n     * @param payoutAddress address to transfer the balances to. Ensure that this is able to handle ERC20 tokens\\n     * @dev owner only + only on or after `_earliestDelete` block\\n     */\\n    function deleteContract(address payable payoutAddress, uint256 txExpirationBlock)\\n        external\\n        verifyTxExpiration(txExpirationBlock)\\n        onlyOwner\\n    {\\n        require(_earliestDelete >= _getBlockNumber(), \\\"Earliest delete not reached\\\");\\n        if (_feeCurrency == FeeCurrency.ERC20) {\\n            uint256 contractBalance = _token.balanceOf(address(this));\\n            require(_token.transfer(payoutAddress, contractBalance));\\n        }\\n        emit ContractDeleted();\\n        // The selfdestruct, by design, transfers *whole* ETH balance from this contract to targetAddress:\\n        selfdestruct(payoutAddress);\\n    }\\n\\n\\n    function oracleValueLastUpdated() external view returns(uint256)\\n    {\\n        return _oracleValue.updatedAtEthBlockNumber;\\n    }\\n\\n    function _getBlockNumber() internal view virtual returns(uint256)\\n    {\\n        return block.number;\\n    }\\n\\n\\n    /**\\n     * @dev Withdraw fee from the caller.\\n     */\\n    function _withdrawFee() internal\\n    {\\n        if (_feeCurrency == FeeCurrency.ETH)\\n        {\\n           if (msg.value == _fee)\\n           {\\n               // No action necessary, since exact expected fee amount has been already transferred by caller,\\n               // this this is just placeholder block to capture the logical condition.\\n           }\\n           else if (msg.value > _fee)\\n           {\\n               // Refund (back to caller) the excess caller paid on top of the expected _fee value:\\n               msg.sender.transfer(msg.value.sub(_fee));\\n           }\\n           else\\n           {\\n               require(false, \\\"Insuf. ETH amount sent by caller\\\");\\n           }\\n        }\\n        else if (_feeCurrency == FeeCurrency.ERC20)\\n        {\\n            require(_token.transferFrom(msg.sender, address(this), _fee), \\\"Insuf. FET allow. on caller addr\\\");\\n        }\\n        else\\n        {\\n            require(false, \\\"Unexpected contract fee currency\\\");\\n        }\\n\\n        _accruedFeesAmount = _accruedFeesAmount.add(_fee);\\n    }\\n\\n\\n    function _withdrawFromContract(address payable targetAddress, uint256 amount) internal\\n    {\\n        require(targetAddress != address(0), \\\"Target is zero address\\\");\\n\\n        if (_feeCurrency == FeeCurrency.ETH)\\n        {\\n            // NOTE(pb): The following transfer shall *fail* with revert IF contract balance is insufficient for transfer\\n            targetAddress.transfer(amount);\\n        }\\n        else if (_feeCurrency == FeeCurrency.ERC20)\\n        {\\n            // NOTE(pb): The following transfer shall *fail* with revert IF contract balance is insufficient for transfer\\n            require(_token.transfer(targetAddress, amount), \\\"Insuff. FET funds on contr. addr\\\");\\n        }\\n        else\\n        {\\n            require(false, \\\"Unexpected contract fee currency\\\");\\n        }\\n    }\\n}\\n\",\n  \"sourcePath\": \"/home/james/Code/cosmos-drb-oracle/ethereum/contracts/FetchOracle.sol\",\n  \"ast\": {\n    \"absolutePath\": \"/home/james/Code/cosmos-drb-oracle/ethereum/contracts/FetchOracle.sol\",\n    \"exportedSymbols\": {\n      \"FetchOracle\": [\n        1440\n      ]\n    },\n    \"id\": 1441,\n    \"license\": \"Apache-2.0\",\n    \"nodeType\": \"SourceUnit\",\n    \"nodes\": [\n      {\n        \"id\": 815,\n        \"literals\": [\n          \"solidity\",\n          \"^\",\n          \"0.6\",\n          \".0\"\n        ],\n        \"nodeType\": \"PragmaDirective\",\n        \"src\": \"820:23:4\"\n      },\n      {\n        \"absolutePath\": \"/home/james/Code/cosmos-drb-oracle/ethereum/openzeppelin/contracts/token/ERC20/IERC20.sol\",\n        \"file\": \"../openzeppelin/contracts/token/ERC20/IERC20.sol\",\n        \"id\": 816,\n        \"nodeType\": \"ImportDirective\",\n        \"scope\": 1441,\n        \"sourceUnit\": 2650,\n        \"src\": \"845:58:4\",\n        \"symbolAliases\": [],\n        \"unitAlias\": \"\"\n      },\n      {\n        \"absolutePath\": \"/home/james/Code/cosmos-drb-oracle/ethereum/openzeppelin/contracts/access/AccessControl.sol\",\n        \"file\": \"../openzeppelin/contracts/access/AccessControl.sol\",\n        \"id\": 817,\n        \"nodeType\": \"ImportDirective\",\n        \"scope\": 1441,\n        \"sourceUnit\": 1784,\n        \"src\": \"904:60:4\",\n        \"symbolAliases\": [],\n        \"unitAlias\": \"\"\n      },\n      {\n        \"absolutePath\": \"/home/james/Code/cosmos-drb-oracle/ethereum/openzeppelin/contracts/math/SafeMath.sol\",\n        \"file\": \"../openzeppelin/contracts/math/SafeMath.sol\",\n        \"id\": 818,\n        \"nodeType\": \"ImportDirective\",\n        \"scope\": 1441,\n        \"sourceUnit\": 1980,\n        \"src\": \"965:53:4\",\n        \"symbolAliases\": [],\n        \"unitAlias\": \"\"\n      },\n      {\n        \"abstract\": false,\n        \"baseContracts\": [\n          {\n            \"arguments\": null,\n            \"baseName\": {\n              \"contractScope\": null,\n              \"id\": 820,\n              \"name\": \"AccessControl\",\n              \"nodeType\": \"UserDefinedTypeName\",\n              \"referencedDeclaration\": 1783,\n              \"src\": \"1574:13:4\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_contract$_AccessControl_$1783\",\n                \"typeString\": \"contract AccessControl\"\n              }\n            },\n            \"id\": 821,\n            \"nodeType\": \"InheritanceSpecifier\",\n            \"src\": \"1574:13:4\"\n          }\n        ],\n        \"contractDependencies\": [\n          1500,\n          1783\n        ],\n        \"contractKind\": \"contract\",\n        \"documentation\": {\n          \"id\": 819,\n          \"nodeType\": \"StructuredDocumentation\",\n          \"src\": \"1021:528:4\",\n          \"text\": \"@dev The contract *INTENTIONALLY* does not contain the `receive()` or fallback functions in order to ensure that all\\nunsolicited direct ETH transfers in to this contract (in direct Transaction) will fail.\\nOnly way how to make successful fee transfer in ETH currency (*IF* contract is initialised for ETH as fee currency),\\nis to make transfer ETH to caller(client) contract and client contract then is responsible for further\\nrogrammatic* (= *not* via Tx) transfer of fee to this this contract.\"\n        },\n        \"fullyImplemented\": true,\n        \"id\": 1440,\n        \"linearizedBaseContracts\": [\n          1440,\n          1783,\n          1500\n        ],\n        \"name\": \"FetchOracle\",\n        \"nodeType\": \"ContractDefinition\",\n        \"nodes\": [\n          {\n            \"id\": 824,\n            \"libraryName\": {\n              \"contractScope\": null,\n              \"id\": 822,\n              \"name\": \"SafeMath\",\n              \"nodeType\": \"UserDefinedTypeName\",\n              \"referencedDeclaration\": 1979,\n              \"src\": \"1600:8:4\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_contract$_SafeMath_$1979\",\n                \"typeString\": \"library SafeMath\"\n              }\n            },\n            \"nodeType\": \"UsingForDirective\",\n            \"src\": \"1594:27:4\",\n            \"typeName\": {\n              \"id\": 823,\n              \"name\": \"uint256\",\n              \"nodeType\": \"ElementaryTypeName\",\n              \"src\": \"1613:7:4\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_uint256\",\n                \"typeString\": \"uint256\"\n              }\n            }\n          },\n          {\n            \"canonicalName\": \"FetchOracle.FeeCurrency\",\n            \"id\": 827,\n            \"members\": [\n              {\n                \"id\": 825,\n                \"name\": \"ERC20\",\n                \"nodeType\": \"EnumValue\",\n                \"src\": \"1648:5:4\"\n              },\n              {\n                \"id\": 826,\n                \"name\": \"ETH\",\n                \"nodeType\": \"EnumValue\",\n                \"src\": \"1655:3:4\"\n              }\n            ],\n            \"name\": \"FeeCurrency\",\n            \"nodeType\": \"EnumDefinition\",\n            \"src\": \"1628:32:4\"\n          },\n          {\n            \"canonicalName\": \"FetchOracle.OracleValue\",\n            \"id\": 834,\n            \"members\": [\n              {\n                \"constant\": false,\n                \"id\": 829,\n                \"mutability\": \"mutable\",\n                \"name\": \"value\",\n                \"nodeType\": \"VariableDeclaration\",\n                \"overrides\": null,\n                \"scope\": 834,\n                \"src\": \"1695:13:4\",\n                \"stateVariable\": false,\n                \"storageLocation\": \"default\",\n                \"typeDescriptions\": {\n                  \"typeIdentifier\": \"t_uint256\",\n                  \"typeString\": \"uint256\"\n                },\n                \"typeName\": {\n                  \"id\": 828,\n                  \"name\": \"uint256\",\n                  \"nodeType\": \"ElementaryTypeName\",\n                  \"src\": \"1695:7:4\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  }\n                },\n                \"value\": null,\n                \"visibility\": \"internal\"\n              },\n              {\n                \"constant\": false,\n                \"id\": 831,\n                \"mutability\": \"mutable\",\n                \"name\": \"decimals\",\n                \"nodeType\": \"VariableDeclaration\",\n                \"overrides\": null,\n                \"scope\": 834,\n                \"src\": \"1718:14:4\",\n                \"stateVariable\": false,\n                \"storageLocation\": \"default\",\n                \"typeDescriptions\": {\n                  \"typeIdentifier\": \"t_uint8\",\n                  \"typeString\": \"uint8\"\n                },\n                \"typeName\": {\n                  \"id\": 830,\n                  \"name\": \"uint8\",\n                  \"nodeType\": \"ElementaryTypeName\",\n                  \"src\": \"1718:5:4\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint8\",\n                    \"typeString\": \"uint8\"\n                  }\n                },\n                \"value\": null,\n                \"visibility\": \"internal\"\n              },\n              {\n                \"constant\": false,\n                \"id\": 833,\n                \"mutability\": \"mutable\",\n                \"name\": \"updatedAtEthBlockNumber\",\n                \"nodeType\": \"VariableDeclaration\",\n                \"overrides\": null,\n                \"scope\": 834,\n                \"src\": \"1742:31:4\",\n                \"stateVariable\": false,\n                \"storageLocation\": \"default\",\n                \"typeDescriptions\": {\n                  \"typeIdentifier\": \"t_uint256\",\n                  \"typeString\": \"uint256\"\n                },\n                \"typeName\": {\n                  \"id\": 832,\n                  \"name\": \"uint256\",\n                  \"nodeType\": \"ElementaryTypeName\",\n                  \"src\": \"1742:7:4\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  }\n                },\n                \"value\": null,\n                \"visibility\": \"internal\"\n              }\n            ],\n            \"name\": \"OracleValue\",\n            \"nodeType\": \"StructDefinition\",\n            \"scope\": 1440,\n            \"src\": \"1666:114:4\",\n            \"visibility\": \"public\"\n          },\n          {\n            \"anonymous\": false,\n            \"documentation\": null,\n            \"id\": 838,\n            \"name\": \"FeeUpdated\",\n            \"nodeType\": \"EventDefinition\",\n            \"parameters\": {\n              \"id\": 837,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 836,\n                  \"indexed\": false,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"fee\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 838,\n                  \"src\": \"1803:11:4\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 835,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"1803:7:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"1802:13:4\"\n            },\n            \"src\": \"1786:30:4\"\n          },\n          {\n            \"anonymous\": false,\n            \"documentation\": null,\n            \"id\": 842,\n            \"name\": \"Pause\",\n            \"nodeType\": \"EventDefinition\",\n            \"parameters\": {\n              \"id\": 841,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 840,\n                  \"indexed\": false,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"sinceBlock\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 842,\n                  \"src\": \"1833:18:4\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 839,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"1833:7:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"1832:20:4\"\n            },\n            \"src\": \"1821:32:4\"\n          },\n          {\n            \"anonymous\": false,\n            \"documentation\": null,\n            \"id\": 848,\n            \"name\": \"ExcessTokenWithdrawal\",\n            \"nodeType\": \"EventDefinition\",\n            \"parameters\": {\n              \"id\": 847,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 844,\n                  \"indexed\": false,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"targetAddress\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 848,\n                  \"src\": \"1886:21:4\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_address\",\n                    \"typeString\": \"address\"\n                  },\n                  \"typeName\": {\n                    \"id\": 843,\n                    \"name\": \"address\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"1886:7:4\",\n                    \"stateMutability\": \"nonpayable\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address\",\n                      \"typeString\": \"address\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 846,\n                  \"indexed\": false,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"amount\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 848,\n                  \"src\": \"1909:14:4\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 845,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"1909:7:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"1885:39:4\"\n            },\n            \"src\": \"1858:67:4\"\n          },\n          {\n            \"anonymous\": false,\n            \"documentation\": null,\n            \"id\": 854,\n            \"name\": \"AccruedFeesWithdrawal\",\n            \"nodeType\": \"EventDefinition\",\n            \"parameters\": {\n              \"id\": 853,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 850,\n                  \"indexed\": false,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"targetAddress\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 854,\n                  \"src\": \"1958:21:4\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_address\",\n                    \"typeString\": \"address\"\n                  },\n                  \"typeName\": {\n                    \"id\": 849,\n                    \"name\": \"address\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"1958:7:4\",\n                    \"stateMutability\": \"nonpayable\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address\",\n                      \"typeString\": \"address\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 852,\n                  \"indexed\": false,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"amount\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 854,\n                  \"src\": \"1981:14:4\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 851,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"1981:7:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"1957:39:4\"\n            },\n            \"src\": \"1930:67:4\"\n          },\n          {\n            \"anonymous\": false,\n            \"documentation\": null,\n            \"id\": 856,\n            \"name\": \"ContractDeleted\",\n            \"nodeType\": \"EventDefinition\",\n            \"parameters\": {\n              \"id\": 855,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"2023:2:4\"\n            },\n            \"src\": \"2002:24:4\"\n          },\n          {\n            \"anonymous\": false,\n            \"documentation\": null,\n            \"id\": 860,\n            \"name\": \"OracleValueUpdated\",\n            \"nodeType\": \"EventDefinition\",\n            \"parameters\": {\n              \"id\": 859,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 858,\n                  \"indexed\": false,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"atBlock\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 860,\n                  \"src\": \"2056:15:4\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 857,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"2056:7:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"2055:17:4\"\n            },\n            \"src\": \"2031:42:4\"\n          },\n          {\n            \"constant\": true,\n            \"functionSelector\": \"07e2cea5\",\n            \"id\": 865,\n            \"mutability\": \"constant\",\n            \"name\": \"ORACLE_ROLE\",\n            \"nodeType\": \"VariableDeclaration\",\n            \"overrides\": null,\n            \"scope\": 1440,\n            \"src\": \"2081:62:4\",\n            \"stateVariable\": true,\n            \"storageLocation\": \"default\",\n            \"typeDescriptions\": {\n              \"typeIdentifier\": \"t_bytes32\",\n              \"typeString\": \"bytes32\"\n            },\n            \"typeName\": {\n              \"id\": 861,\n              \"name\": \"bytes32\",\n              \"nodeType\": \"ElementaryTypeName\",\n              \"src\": \"2081:7:4\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_bytes32\",\n                \"typeString\": \"bytes32\"\n              }\n            },\n            \"value\": {\n              \"argumentTypes\": null,\n              \"arguments\": [\n                {\n                  \"argumentTypes\": null,\n                  \"hexValue\": \"4f5241434c455f524f4c45\",\n                  \"id\": 863,\n                  \"isConstant\": false,\n                  \"isLValue\": false,\n                  \"isPure\": true,\n                  \"kind\": \"string\",\n                  \"lValueRequested\": false,\n                  \"nodeType\": \"Literal\",\n                  \"src\": \"2129:13:4\",\n                  \"subdenomination\": null,\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_stringliteral_68e79a7bf1e0bc45d0a330c573bc367f9cf464fd326078812f301165fbda4ef1\",\n                    \"typeString\": \"literal_string \\\"ORACLE_ROLE\\\"\"\n                  },\n                  \"value\": \"ORACLE_ROLE\"\n                }\n              ],\n              \"expression\": {\n                \"argumentTypes\": [\n                  {\n                    \"typeIdentifier\": \"t_stringliteral_68e79a7bf1e0bc45d0a330c573bc367f9cf464fd326078812f301165fbda4ef1\",\n                    \"typeString\": \"literal_string \\\"ORACLE_ROLE\\\"\"\n                  }\n                ],\n                \"id\": 862,\n                \"name\": \"keccak256\",\n                \"nodeType\": \"Identifier\",\n                \"overloadedDeclarations\": [],\n                \"referencedDeclaration\": -8,\n                \"src\": \"2119:9:4\",\n                \"typeDescriptions\": {\n                  \"typeIdentifier\": \"t_function_keccak256_pure$_t_bytes_memory_ptr_$returns$_t_bytes32_$\",\n                  \"typeString\": \"function (bytes memory) pure returns (bytes32)\"\n                }\n              },\n              \"id\": 864,\n              \"isConstant\": false,\n              \"isLValue\": false,\n              \"isPure\": true,\n              \"kind\": \"functionCall\",\n              \"lValueRequested\": false,\n              \"names\": [],\n              \"nodeType\": \"FunctionCall\",\n              \"src\": \"2119:24:4\",\n              \"tryCall\": false,\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_bytes32\",\n                \"typeString\": \"bytes32\"\n              }\n            },\n            \"visibility\": \"public\"\n          },\n          {\n            \"constant\": true,\n            \"functionSelector\": \"c0ba241b\",\n            \"id\": 870,\n            \"mutability\": \"constant\",\n            \"name\": \"DELEGATE_ROLE\",\n            \"nodeType\": \"VariableDeclaration\",\n            \"overrides\": null,\n            \"scope\": 1440,\n            \"src\": \"2149:66:4\",\n            \"stateVariable\": true,\n            \"storageLocation\": \"default\",\n            \"typeDescriptions\": {\n              \"typeIdentifier\": \"t_bytes32\",\n              \"typeString\": \"bytes32\"\n            },\n            \"typeName\": {\n              \"id\": 866,\n              \"name\": \"bytes32\",\n              \"nodeType\": \"ElementaryTypeName\",\n              \"src\": \"2149:7:4\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_bytes32\",\n                \"typeString\": \"bytes32\"\n              }\n            },\n            \"value\": {\n              \"argumentTypes\": null,\n              \"arguments\": [\n                {\n                  \"argumentTypes\": null,\n                  \"hexValue\": \"44454c45474154455f524f4c45\",\n                  \"id\": 868,\n                  \"isConstant\": false,\n                  \"isLValue\": false,\n                  \"isPure\": true,\n                  \"kind\": \"string\",\n                  \"lValueRequested\": false,\n                  \"nodeType\": \"Literal\",\n                  \"src\": \"2199:15:4\",\n                  \"subdenomination\": null,\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_stringliteral_1a82baf2b928242f69f7147fb92490c6288d044f7257b88817e6284f1eec0f15\",\n                    \"typeString\": \"literal_string \\\"DELEGATE_ROLE\\\"\"\n                  },\n                  \"value\": \"DELEGATE_ROLE\"\n                }\n              ],\n              \"expression\": {\n                \"argumentTypes\": [\n                  {\n                    \"typeIdentifier\": \"t_stringliteral_1a82baf2b928242f69f7147fb92490c6288d044f7257b88817e6284f1eec0f15\",\n                    \"typeString\": \"literal_string \\\"DELEGATE_ROLE\\\"\"\n                  }\n                ],\n                \"id\": 867,\n                \"name\": \"keccak256\",\n                \"nodeType\": \"Identifier\",\n                \"overloadedDeclarations\": [],\n                \"referencedDeclaration\": -8,\n                \"src\": \"2189:9:4\",\n                \"typeDescriptions\": {\n                  \"typeIdentifier\": \"t_function_keccak256_pure$_t_bytes_memory_ptr_$returns$_t_bytes32_$\",\n                  \"typeString\": \"function (bytes memory) pure returns (bytes32)\"\n                }\n              },\n              \"id\": 869,\n              \"isConstant\": false,\n              \"isLValue\": false,\n              \"isPure\": true,\n              \"kind\": \"functionCall\",\n              \"lValueRequested\": false,\n              \"names\": [],\n              \"nodeType\": \"FunctionCall\",\n              \"src\": \"2189:26:4\",\n              \"tryCall\": false,\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_bytes32\",\n                \"typeString\": \"bytes32\"\n              }\n            },\n            \"visibility\": \"public\"\n          },\n          {\n            \"constant\": true,\n            \"functionSelector\": \"372646bb\",\n            \"id\": 873,\n            \"mutability\": \"constant\",\n            \"name\": \"DELETE_PROTECTION_PERIOD\",\n            \"nodeType\": \"VariableDeclaration\",\n            \"overrides\": null,\n            \"scope\": 1440,\n            \"src\": \"2221:57:4\",\n            \"stateVariable\": true,\n            \"storageLocation\": \"default\",\n            \"typeDescriptions\": {\n              \"typeIdentifier\": \"t_uint256\",\n              \"typeString\": \"uint256\"\n            },\n            \"typeName\": {\n              \"id\": 871,\n              \"name\": \"uint256\",\n              \"nodeType\": \"ElementaryTypeName\",\n              \"src\": \"2221:7:4\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_uint256\",\n                \"typeString\": \"uint256\"\n              }\n            },\n            \"value\": {\n              \"argumentTypes\": null,\n              \"hexValue\": \"333730323835\",\n              \"id\": 872,\n              \"isConstant\": false,\n              \"isLValue\": false,\n              \"isPure\": true,\n              \"kind\": \"number\",\n              \"lValueRequested\": false,\n              \"nodeType\": \"Literal\",\n              \"src\": \"2272:6:4\",\n              \"subdenomination\": null,\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_rational_370285_by_1\",\n                \"typeString\": \"int_const 370285\"\n              },\n              \"value\": \"370285\"\n            },\n            \"visibility\": \"public\"\n          },\n          {\n            \"constant\": false,\n            \"functionSelector\": \"ecd0c0c3\",\n            \"id\": 875,\n            \"mutability\": \"mutable\",\n            \"name\": \"_token\",\n            \"nodeType\": \"VariableDeclaration\",\n            \"overrides\": null,\n            \"scope\": 1440,\n            \"src\": \"2335:20:4\",\n            \"stateVariable\": true,\n            \"storageLocation\": \"default\",\n            \"typeDescriptions\": {\n              \"typeIdentifier\": \"t_contract$_IERC20_$2649\",\n              \"typeString\": \"contract IERC20\"\n            },\n            \"typeName\": {\n              \"contractScope\": null,\n              \"id\": 874,\n              \"name\": \"IERC20\",\n              \"nodeType\": \"UserDefinedTypeName\",\n              \"referencedDeclaration\": 2649,\n              \"src\": \"2335:6:4\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_contract$_IERC20_$2649\",\n                \"typeString\": \"contract IERC20\"\n              }\n            },\n            \"value\": null,\n            \"visibility\": \"public\"\n          },\n          {\n            \"constant\": false,\n            \"functionSelector\": \"32a1bd70\",\n            \"id\": 877,\n            \"mutability\": \"mutable\",\n            \"name\": \"_earliestDelete\",\n            \"nodeType\": \"VariableDeclaration\",\n            \"overrides\": null,\n            \"scope\": 1440,\n            \"src\": \"2361:30:4\",\n            \"stateVariable\": true,\n            \"storageLocation\": \"default\",\n            \"typeDescriptions\": {\n              \"typeIdentifier\": \"t_uint256\",\n              \"typeString\": \"uint256\"\n            },\n            \"typeName\": {\n              \"id\": 876,\n              \"name\": \"uint256\",\n              \"nodeType\": \"ElementaryTypeName\",\n              \"src\": \"2361:7:4\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_uint256\",\n                \"typeString\": \"uint256\"\n              }\n            },\n            \"value\": null,\n            \"visibility\": \"public\"\n          },\n          {\n            \"constant\": false,\n            \"functionSelector\": \"f1209ef7\",\n            \"id\": 879,\n            \"mutability\": \"mutable\",\n            \"name\": \"_pausedSinceBlock\",\n            \"nodeType\": \"VariableDeclaration\",\n            \"overrides\": null,\n            \"scope\": 1440,\n            \"src\": \"2397:32:4\",\n            \"stateVariable\": true,\n            \"storageLocation\": \"default\",\n            \"typeDescriptions\": {\n              \"typeIdentifier\": \"t_uint256\",\n              \"typeString\": \"uint256\"\n            },\n            \"typeName\": {\n              \"id\": 878,\n              \"name\": \"uint256\",\n              \"nodeType\": \"ElementaryTypeName\",\n              \"src\": \"2397:7:4\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_uint256\",\n                \"typeString\": \"uint256\"\n              }\n            },\n            \"value\": null,\n            \"visibility\": \"public\"\n          },\n          {\n            \"constant\": false,\n            \"functionSelector\": \"c5b37c22\",\n            \"id\": 881,\n            \"mutability\": \"mutable\",\n            \"name\": \"_fee\",\n            \"nodeType\": \"VariableDeclaration\",\n            \"overrides\": null,\n            \"scope\": 1440,\n            \"src\": \"2435:19:4\",\n            \"stateVariable\": true,\n            \"storageLocation\": \"default\",\n            \"typeDescriptions\": {\n              \"typeIdentifier\": \"t_uint256\",\n              \"typeString\": \"uint256\"\n            },\n            \"typeName\": {\n              \"id\": 880,\n              \"name\": \"uint256\",\n              \"nodeType\": \"ElementaryTypeName\",\n              \"src\": \"2435:7:4\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_uint256\",\n                \"typeString\": \"uint256\"\n              }\n            },\n            \"value\": null,\n            \"visibility\": \"public\"\n          },\n          {\n            \"constant\": false,\n            \"functionSelector\": \"d83222ec\",\n            \"id\": 883,\n            \"mutability\": \"mutable\",\n            \"name\": \"_accruedFeesAmount\",\n            \"nodeType\": \"VariableDeclaration\",\n            \"overrides\": null,\n            \"scope\": 1440,\n            \"src\": \"2460:33:4\",\n            \"stateVariable\": true,\n            \"storageLocation\": \"default\",\n            \"typeDescriptions\": {\n              \"typeIdentifier\": \"t_uint256\",\n              \"typeString\": \"uint256\"\n            },\n            \"typeName\": {\n              \"id\": 882,\n              \"name\": \"uint256\",\n              \"nodeType\": \"ElementaryTypeName\",\n              \"src\": \"2460:7:4\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_uint256\",\n                \"typeString\": \"uint256\"\n              }\n            },\n            \"value\": null,\n            \"visibility\": \"public\"\n          },\n          {\n            \"constant\": false,\n            \"id\": 885,\n            \"mutability\": \"mutable\",\n            \"name\": \"_oracleValue\",\n            \"nodeType\": \"VariableDeclaration\",\n            \"overrides\": null,\n            \"scope\": 1440,\n            \"src\": \"2499:32:4\",\n            \"stateVariable\": true,\n            \"storageLocation\": \"default\",\n            \"typeDescriptions\": {\n              \"typeIdentifier\": \"t_struct$_OracleValue_$834_storage\",\n              \"typeString\": \"struct FetchOracle.OracleValue\"\n            },\n            \"typeName\": {\n              \"contractScope\": null,\n              \"id\": 884,\n              \"name\": \"OracleValue\",\n              \"nodeType\": \"UserDefinedTypeName\",\n              \"referencedDeclaration\": 834,\n              \"src\": \"2499:11:4\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_struct$_OracleValue_$834_storage_ptr\",\n                \"typeString\": \"struct FetchOracle.OracleValue\"\n              }\n            },\n            \"value\": null,\n            \"visibility\": \"private\"\n          },\n          {\n            \"constant\": false,\n            \"functionSelector\": \"993240a3\",\n            \"id\": 887,\n            \"mutability\": \"mutable\",\n            \"name\": \"_feeCurrency\",\n            \"nodeType\": \"VariableDeclaration\",\n            \"overrides\": null,\n            \"scope\": 1440,\n            \"src\": \"2537:31:4\",\n            \"stateVariable\": true,\n            \"storageLocation\": \"default\",\n            \"typeDescriptions\": {\n              \"typeIdentifier\": \"t_enum$_FeeCurrency_$827\",\n              \"typeString\": \"enum FetchOracle.FeeCurrency\"\n            },\n            \"typeName\": {\n              \"contractScope\": null,\n              \"id\": 886,\n              \"name\": \"FeeCurrency\",\n              \"nodeType\": \"UserDefinedTypeName\",\n              \"referencedDeclaration\": 827,\n              \"src\": \"2537:11:4\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_enum$_FeeCurrency_$827\",\n                \"typeString\": \"enum FetchOracle.FeeCurrency\"\n              }\n            },\n            \"value\": null,\n            \"visibility\": \"public\"\n          },\n          {\n            \"body\": {\n              \"id\": 898,\n              \"nodeType\": \"Block\",\n              \"src\": \"2623:63:4\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 893,\n                        \"name\": \"DEFAULT_ADMIN_ROLE\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 1526,\n                        \"src\": \"2648:18:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_bytes32\",\n                          \"typeString\": \"bytes32\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 894,\n                          \"name\": \"msg\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": -15,\n                          \"src\": \"2668:3:4\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_magic_message\",\n                            \"typeString\": \"msg\"\n                          }\n                        },\n                        \"id\": 895,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"memberName\": \"sender\",\n                        \"nodeType\": \"MemberAccess\",\n                        \"referencedDeclaration\": null,\n                        \"src\": \"2668:10:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_bytes32\",\n                          \"typeString\": \"bytes32\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        }\n                      ],\n                      \"id\": 892,\n                      \"name\": \"hasRole\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 1572,\n                      \"src\": \"2640:7:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_view$_t_bytes32_$_t_address_$returns$_t_bool_$\",\n                        \"typeString\": \"function (bytes32,address) view returns (bool)\"\n                      }\n                    },\n                    \"id\": 896,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"2640:39:4\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_bool\",\n                      \"typeString\": \"bool\"\n                    }\n                  },\n                  \"functionReturnParameters\": 891,\n                  \"id\": 897,\n                  \"nodeType\": \"Return\",\n                  \"src\": \"2633:46:4\"\n                }\n              ]\n            },\n            \"documentation\": null,\n            \"id\": 899,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [],\n            \"name\": \"_isOwner\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 888,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"2592:2:4\"\n            },\n            \"returnParameters\": {\n              \"id\": 891,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 890,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 899,\n                  \"src\": \"2617:4:4\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_bool\",\n                    \"typeString\": \"bool\"\n                  },\n                  \"typeName\": {\n                    \"id\": 889,\n                    \"name\": \"bool\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"2617:4:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_bool\",\n                      \"typeString\": \"bool\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"2616:6:4\"\n            },\n            \"scope\": 1440,\n            \"src\": \"2575:111:4\",\n            \"stateMutability\": \"view\",\n            \"virtual\": false,\n            \"visibility\": \"internal\"\n          },\n          {\n            \"body\": {\n              \"id\": 908,\n              \"nodeType\": \"Block\",\n              \"src\": \"2746:81:4\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"arguments\": [],\n                        \"expression\": {\n                          \"argumentTypes\": [],\n                          \"id\": 902,\n                          \"name\": \"_isOwner\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 899,\n                          \"src\": \"2764:8:4\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_function_internal_view$__$returns$_t_bool_$\",\n                            \"typeString\": \"function () view returns (bool)\"\n                          }\n                        },\n                        \"id\": 903,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"kind\": \"functionCall\",\n                        \"lValueRequested\": false,\n                        \"names\": [],\n                        \"nodeType\": \"FunctionCall\",\n                        \"src\": \"2764:10:4\",\n                        \"tryCall\": false,\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"hexValue\": \"43616c6c6572206973206e6f7420616e2061646d696e6973747261746f72\",\n                        \"id\": 904,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": true,\n                        \"kind\": \"string\",\n                        \"lValueRequested\": false,\n                        \"nodeType\": \"Literal\",\n                        \"src\": \"2776:32:4\",\n                        \"subdenomination\": null,\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_stringliteral_fff29d4bd770cdc17b9f156c578c5f49981008f3769f218da7df946262b27392\",\n                          \"typeString\": \"literal_string \\\"Caller is not an administrator\\\"\"\n                        },\n                        \"value\": \"Caller is not an administrator\"\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_stringliteral_fff29d4bd770cdc17b9f156c578c5f49981008f3769f218da7df946262b27392\",\n                          \"typeString\": \"literal_string \\\"Caller is not an administrator\\\"\"\n                        }\n                      ],\n                      \"id\": 901,\n                      \"name\": \"require\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [\n                        -18,\n                        -18\n                      ],\n                      \"referencedDeclaration\": -18,\n                      \"src\": \"2756:7:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$\",\n                        \"typeString\": \"function (bool,string memory) pure\"\n                      }\n                    },\n                    \"id\": 905,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"2756:53:4\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 906,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"2756:53:4\"\n                },\n                {\n                  \"id\": 907,\n                  \"nodeType\": \"PlaceholderStatement\",\n                  \"src\": \"2819:1:4\"\n                }\n              ]\n            },\n            \"documentation\": null,\n            \"id\": 909,\n            \"name\": \"onlyOwner\",\n            \"nodeType\": \"ModifierDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 900,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"2743:2:4\"\n            },\n            \"src\": \"2725:102:4\",\n            \"virtual\": false,\n            \"visibility\": \"internal\"\n          },\n          {\n            \"body\": {\n              \"id\": 924,\n              \"nodeType\": \"Block\",\n              \"src\": \"2902:125:4\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"commonType\": {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        },\n                        \"id\": 919,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"leftExpression\": {\n                          \"argumentTypes\": null,\n                          \"arguments\": [],\n                          \"expression\": {\n                            \"argumentTypes\": [],\n                            \"id\": 912,\n                            \"name\": \"_isOwner\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 899,\n                            \"src\": \"2920:8:4\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_function_internal_view$__$returns$_t_bool_$\",\n                              \"typeString\": \"function () view returns (bool)\"\n                            }\n                          },\n                          \"id\": 913,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"kind\": \"functionCall\",\n                          \"lValueRequested\": false,\n                          \"names\": [],\n                          \"nodeType\": \"FunctionCall\",\n                          \"src\": \"2920:10:4\",\n                          \"tryCall\": false,\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_bool\",\n                            \"typeString\": \"bool\"\n                          }\n                        },\n                        \"nodeType\": \"BinaryOperation\",\n                        \"operator\": \"||\",\n                        \"rightExpression\": {\n                          \"argumentTypes\": null,\n                          \"arguments\": [\n                            {\n                              \"argumentTypes\": null,\n                              \"id\": 915,\n                              \"name\": \"DELEGATE_ROLE\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 870,\n                              \"src\": \"2942:13:4\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_bytes32\",\n                                \"typeString\": \"bytes32\"\n                              }\n                            },\n                            {\n                              \"argumentTypes\": null,\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"id\": 916,\n                                \"name\": \"msg\",\n                                \"nodeType\": \"Identifier\",\n                                \"overloadedDeclarations\": [],\n                                \"referencedDeclaration\": -15,\n                                \"src\": \"2957:3:4\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_magic_message\",\n                                  \"typeString\": \"msg\"\n                                }\n                              },\n                              \"id\": 917,\n                              \"isConstant\": false,\n                              \"isLValue\": false,\n                              \"isPure\": false,\n                              \"lValueRequested\": false,\n                              \"memberName\": \"sender\",\n                              \"nodeType\": \"MemberAccess\",\n                              \"referencedDeclaration\": null,\n                              \"src\": \"2957:10:4\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_address_payable\",\n                                \"typeString\": \"address payable\"\n                              }\n                            }\n                          ],\n                          \"expression\": {\n                            \"argumentTypes\": [\n                              {\n                                \"typeIdentifier\": \"t_bytes32\",\n                                \"typeString\": \"bytes32\"\n                              },\n                              {\n                                \"typeIdentifier\": \"t_address_payable\",\n                                \"typeString\": \"address payable\"\n                              }\n                            ],\n                            \"id\": 914,\n                            \"name\": \"hasRole\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 1572,\n                            \"src\": \"2934:7:4\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_function_internal_view$_t_bytes32_$_t_address_$returns$_t_bool_$\",\n                              \"typeString\": \"function (bytes32,address) view returns (bool)\"\n                            }\n                          },\n                          \"id\": 918,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"kind\": \"functionCall\",\n                          \"lValueRequested\": false,\n                          \"names\": [],\n                          \"nodeType\": \"FunctionCall\",\n                          \"src\": \"2934:34:4\",\n                          \"tryCall\": false,\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_bool\",\n                            \"typeString\": \"bool\"\n                          }\n                        },\n                        \"src\": \"2920:48:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"hexValue\": \"43616c6c6572206973206e656974686572206f776e6572206e6f722064656c6567617465\",\n                        \"id\": 920,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": true,\n                        \"kind\": \"string\",\n                        \"lValueRequested\": false,\n                        \"nodeType\": \"Literal\",\n                        \"src\": \"2970:38:4\",\n                        \"subdenomination\": null,\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_stringliteral_3c2cbf62f56025e2baf3b46dabe4ee1ab0f4be1432d0bef94b4d166423814999\",\n                          \"typeString\": \"literal_string \\\"Caller is neither owner nor delegate\\\"\"\n                        },\n                        \"value\": \"Caller is neither owner nor delegate\"\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_stringliteral_3c2cbf62f56025e2baf3b46dabe4ee1ab0f4be1432d0bef94b4d166423814999\",\n                          \"typeString\": \"literal_string \\\"Caller is neither owner nor delegate\\\"\"\n                        }\n                      ],\n                      \"id\": 911,\n                      \"name\": \"require\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [\n                        -18,\n                        -18\n                      ],\n                      \"referencedDeclaration\": -18,\n                      \"src\": \"2912:7:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$\",\n                        \"typeString\": \"function (bool,string memory) pure\"\n                      }\n                    },\n                    \"id\": 921,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"2912:97:4\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 922,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"2912:97:4\"\n                },\n                {\n                  \"id\": 923,\n                  \"nodeType\": \"PlaceholderStatement\",\n                  \"src\": \"3019:1:4\"\n                }\n              ]\n            },\n            \"documentation\": null,\n            \"id\": 925,\n            \"name\": \"onlyDelegate\",\n            \"nodeType\": \"ModifierDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 910,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"2899:2:4\"\n            },\n            \"src\": \"2878:149:4\",\n            \"virtual\": false,\n            \"visibility\": \"internal\"\n          },\n          {\n            \"body\": {\n              \"id\": 937,\n              \"nodeType\": \"Block\",\n              \"src\": \"3089:96:4\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"arguments\": [\n                          {\n                            \"argumentTypes\": null,\n                            \"id\": 929,\n                            \"name\": \"ORACLE_ROLE\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 865,\n                            \"src\": \"3115:11:4\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_bytes32\",\n                              \"typeString\": \"bytes32\"\n                            }\n                          },\n                          {\n                            \"argumentTypes\": null,\n                            \"expression\": {\n                              \"argumentTypes\": null,\n                              \"id\": 930,\n                              \"name\": \"msg\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": -15,\n                              \"src\": \"3128:3:4\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_magic_message\",\n                                \"typeString\": \"msg\"\n                              }\n                            },\n                            \"id\": 931,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": false,\n                            \"lValueRequested\": false,\n                            \"memberName\": \"sender\",\n                            \"nodeType\": \"MemberAccess\",\n                            \"referencedDeclaration\": null,\n                            \"src\": \"3128:10:4\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_address_payable\",\n                              \"typeString\": \"address payable\"\n                            }\n                          }\n                        ],\n                        \"expression\": {\n                          \"argumentTypes\": [\n                            {\n                              \"typeIdentifier\": \"t_bytes32\",\n                              \"typeString\": \"bytes32\"\n                            },\n                            {\n                              \"typeIdentifier\": \"t_address_payable\",\n                              \"typeString\": \"address payable\"\n                            }\n                          ],\n                          \"id\": 928,\n                          \"name\": \"hasRole\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 1572,\n                          \"src\": \"3107:7:4\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_function_internal_view$_t_bytes32_$_t_address_$returns$_t_bool_$\",\n                            \"typeString\": \"function (bytes32,address) view returns (bool)\"\n                          }\n                        },\n                        \"id\": 932,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"kind\": \"functionCall\",\n                        \"lValueRequested\": false,\n                        \"names\": [],\n                        \"nodeType\": \"FunctionCall\",\n                        \"src\": \"3107:32:4\",\n                        \"tryCall\": false,\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"hexValue\": \"43616c6c6572206973206e6f7420616e206f7261636c65\",\n                        \"id\": 933,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": true,\n                        \"kind\": \"string\",\n                        \"lValueRequested\": false,\n                        \"nodeType\": \"Literal\",\n                        \"src\": \"3141:25:4\",\n                        \"subdenomination\": null,\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_stringliteral_8c1dc436c657406c837ef43aefe277157f6f9572ac3e706ad659a5d014391325\",\n                          \"typeString\": \"literal_string \\\"Caller is not an oracle\\\"\"\n                        },\n                        \"value\": \"Caller is not an oracle\"\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_stringliteral_8c1dc436c657406c837ef43aefe277157f6f9572ac3e706ad659a5d014391325\",\n                          \"typeString\": \"literal_string \\\"Caller is not an oracle\\\"\"\n                        }\n                      ],\n                      \"id\": 927,\n                      \"name\": \"require\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [\n                        -18,\n                        -18\n                      ],\n                      \"referencedDeclaration\": -18,\n                      \"src\": \"3099:7:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$\",\n                        \"typeString\": \"function (bool,string memory) pure\"\n                      }\n                    },\n                    \"id\": 934,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"3099:68:4\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 935,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"3099:68:4\"\n                },\n                {\n                  \"id\": 936,\n                  \"nodeType\": \"PlaceholderStatement\",\n                  \"src\": \"3177:1:4\"\n                }\n              ]\n            },\n            \"documentation\": null,\n            \"id\": 938,\n            \"name\": \"onlyOracle\",\n            \"nodeType\": \"ModifierDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 926,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"3086:2:4\"\n            },\n            \"src\": \"3067:118:4\",\n            \"virtual\": false,\n            \"visibility\": \"internal\"\n          },\n          {\n            \"body\": {\n              \"id\": 951,\n              \"nodeType\": \"Block\",\n              \"src\": \"3244:96:4\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"commonType\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        },\n                        \"id\": 946,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"leftExpression\": {\n                          \"argumentTypes\": null,\n                          \"arguments\": [],\n                          \"expression\": {\n                            \"argumentTypes\": [],\n                            \"id\": 943,\n                            \"name\": \"_getBlockNumber\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 1314,\n                            \"src\": \"3262:15:4\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_function_internal_view$__$returns$_t_uint256_$\",\n                              \"typeString\": \"function () view returns (uint256)\"\n                            }\n                          },\n                          \"id\": 944,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"kind\": \"functionCall\",\n                          \"lValueRequested\": false,\n                          \"names\": [],\n                          \"nodeType\": \"FunctionCall\",\n                          \"src\": \"3262:17:4\",\n                          \"tryCall\": false,\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"nodeType\": \"BinaryOperation\",\n                        \"operator\": \"<=\",\n                        \"rightExpression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 945,\n                          \"name\": \"expirationBlock\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 940,\n                          \"src\": \"3283:15:4\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"src\": \"3262:36:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"hexValue\": \"5472616e73616374696f6e2065787069726564\",\n                        \"id\": 947,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": true,\n                        \"kind\": \"string\",\n                        \"lValueRequested\": false,\n                        \"nodeType\": \"Literal\",\n                        \"src\": \"3300:21:4\",\n                        \"subdenomination\": null,\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_stringliteral_38b57334da13daffb65e2d9cfe97bc3051af86f72807115eae867384ed846551\",\n                          \"typeString\": \"literal_string \\\"Transaction expired\\\"\"\n                        },\n                        \"value\": \"Transaction expired\"\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_stringliteral_38b57334da13daffb65e2d9cfe97bc3051af86f72807115eae867384ed846551\",\n                          \"typeString\": \"literal_string \\\"Transaction expired\\\"\"\n                        }\n                      ],\n                      \"id\": 942,\n                      \"name\": \"require\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [\n                        -18,\n                        -18\n                      ],\n                      \"referencedDeclaration\": -18,\n                      \"src\": \"3254:7:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$\",\n                        \"typeString\": \"function (bool,string memory) pure\"\n                      }\n                    },\n                    \"id\": 948,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"3254:68:4\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 949,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"3254:68:4\"\n                },\n                {\n                  \"id\": 950,\n                  \"nodeType\": \"PlaceholderStatement\",\n                  \"src\": \"3332:1:4\"\n                }\n              ]\n            },\n            \"documentation\": null,\n            \"id\": 952,\n            \"name\": \"verifyTxExpiration\",\n            \"nodeType\": \"ModifierDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 941,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 940,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"expirationBlock\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 952,\n                  \"src\": \"3219:23:4\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 939,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"3219:7:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"3218:25:4\"\n            },\n            \"src\": \"3191:149:4\",\n            \"virtual\": false,\n            \"visibility\": \"internal\"\n          },\n          {\n            \"body\": {\n              \"id\": 963,\n              \"nodeType\": \"Block\",\n              \"src\": \"3373:102:4\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"commonType\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        },\n                        \"id\": 958,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"leftExpression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 955,\n                          \"name\": \"_pausedSinceBlock\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 879,\n                          \"src\": \"3391:17:4\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"nodeType\": \"BinaryOperation\",\n                        \"operator\": \">\",\n                        \"rightExpression\": {\n                          \"argumentTypes\": null,\n                          \"arguments\": [],\n                          \"expression\": {\n                            \"argumentTypes\": [],\n                            \"id\": 956,\n                            \"name\": \"_getBlockNumber\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 1314,\n                            \"src\": \"3411:15:4\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_function_internal_view$__$returns$_t_uint256_$\",\n                              \"typeString\": \"function () view returns (uint256)\"\n                            }\n                          },\n                          \"id\": 957,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"kind\": \"functionCall\",\n                          \"lValueRequested\": false,\n                          \"names\": [],\n                          \"nodeType\": \"FunctionCall\",\n                          \"src\": \"3411:17:4\",\n                          \"tryCall\": false,\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"src\": \"3391:37:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"hexValue\": \"436f6e747261637420686173206265656e20706175736564\",\n                        \"id\": 959,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": true,\n                        \"kind\": \"string\",\n                        \"lValueRequested\": false,\n                        \"nodeType\": \"Literal\",\n                        \"src\": \"3430:26:4\",\n                        \"subdenomination\": null,\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_stringliteral_6993ab713d4a8a857f0654d36ec91738ef7ba3b8999d96006199fec5b907c586\",\n                          \"typeString\": \"literal_string \\\"Contract has been paused\\\"\"\n                        },\n                        \"value\": \"Contract has been paused\"\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_stringliteral_6993ab713d4a8a857f0654d36ec91738ef7ba3b8999d96006199fec5b907c586\",\n                          \"typeString\": \"literal_string \\\"Contract has been paused\\\"\"\n                        }\n                      ],\n                      \"id\": 954,\n                      \"name\": \"require\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [\n                        -18,\n                        -18\n                      ],\n                      \"referencedDeclaration\": -18,\n                      \"src\": \"3383:7:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$\",\n                        \"typeString\": \"function (bool,string memory) pure\"\n                      }\n                    },\n                    \"id\": 960,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"3383:74:4\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 961,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"3383:74:4\"\n                },\n                {\n                  \"id\": 962,\n                  \"nodeType\": \"PlaceholderStatement\",\n                  \"src\": \"3467:1:4\"\n                }\n              ]\n            },\n            \"documentation\": null,\n            \"id\": 964,\n            \"name\": \"verifyNotPaused\",\n            \"nodeType\": \"ModifierDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 953,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"3370:2:4\"\n            },\n            \"src\": \"3346:129:4\",\n            \"virtual\": false,\n            \"visibility\": \"internal\"\n          },\n          {\n            \"body\": {\n              \"id\": 1023,\n              \"nodeType\": \"Block\",\n              \"src\": \"3685:406:4\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 973,\n                        \"name\": \"DEFAULT_ADMIN_ROLE\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 1526,\n                        \"src\": \"3706:18:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_bytes32\",\n                          \"typeString\": \"bytes32\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 974,\n                          \"name\": \"msg\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": -15,\n                          \"src\": \"3726:3:4\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_magic_message\",\n                            \"typeString\": \"msg\"\n                          }\n                        },\n                        \"id\": 975,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"memberName\": \"sender\",\n                        \"nodeType\": \"MemberAccess\",\n                        \"referencedDeclaration\": null,\n                        \"src\": \"3726:10:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_bytes32\",\n                          \"typeString\": \"bytes32\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        }\n                      ],\n                      \"id\": 972,\n                      \"name\": \"_setupRole\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 1709,\n                      \"src\": \"3695:10:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_nonpayable$_t_bytes32_$_t_address_$returns$__$\",\n                        \"typeString\": \"function (bytes32,address)\"\n                      }\n                    },\n                    \"id\": 976,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"3695:42:4\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 977,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"3695:42:4\"\n                },\n                {\n                  \"condition\": {\n                    \"argumentTypes\": null,\n                    \"commonType\": {\n                      \"typeIdentifier\": \"t_address\",\n                      \"typeString\": \"address\"\n                    },\n                    \"id\": 983,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftExpression\": {\n                      \"argumentTypes\": null,\n                      \"id\": 978,\n                      \"name\": \"ERC20Address\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 967,\n                      \"src\": \"3752:12:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_address\",\n                        \"typeString\": \"address\"\n                      }\n                    },\n                    \"nodeType\": \"BinaryOperation\",\n                    \"operator\": \"==\",\n                    \"rightExpression\": {\n                      \"argumentTypes\": null,\n                      \"arguments\": [\n                        {\n                          \"argumentTypes\": null,\n                          \"hexValue\": \"30\",\n                          \"id\": 981,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": true,\n                          \"kind\": \"number\",\n                          \"lValueRequested\": false,\n                          \"nodeType\": \"Literal\",\n                          \"src\": \"3776:1:4\",\n                          \"subdenomination\": null,\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_rational_0_by_1\",\n                            \"typeString\": \"int_const 0\"\n                          },\n                          \"value\": \"0\"\n                        }\n                      ],\n                      \"expression\": {\n                        \"argumentTypes\": [\n                          {\n                            \"typeIdentifier\": \"t_rational_0_by_1\",\n                            \"typeString\": \"int_const 0\"\n                          }\n                        ],\n                        \"id\": 980,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": true,\n                        \"lValueRequested\": false,\n                        \"nodeType\": \"ElementaryTypeNameExpression\",\n                        \"src\": \"3768:7:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_type$_t_address_$\",\n                          \"typeString\": \"type(address)\"\n                        },\n                        \"typeName\": {\n                          \"id\": 979,\n                          \"name\": \"address\",\n                          \"nodeType\": \"ElementaryTypeName\",\n                          \"src\": \"3768:7:4\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": null,\n                            \"typeString\": null\n                          }\n                        }\n                      },\n                      \"id\": 982,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": true,\n                      \"kind\": \"typeConversion\",\n                      \"lValueRequested\": false,\n                      \"names\": [],\n                      \"nodeType\": \"FunctionCall\",\n                      \"src\": \"3768:10:4\",\n                      \"tryCall\": false,\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_address_payable\",\n                        \"typeString\": \"address payable\"\n                      }\n                    },\n                    \"src\": \"3752:26:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_bool\",\n                      \"typeString\": \"bool\"\n                    }\n                  },\n                  \"falseBody\": {\n                    \"id\": 1001,\n                    \"nodeType\": \"Block\",\n                    \"src\": \"3841:100:4\",\n                    \"statements\": [\n                      {\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 993,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"leftHandSide\": {\n                            \"argumentTypes\": null,\n                            \"id\": 990,\n                            \"name\": \"_feeCurrency\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 887,\n                            \"src\": \"3855:12:4\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_enum$_FeeCurrency_$827\",\n                              \"typeString\": \"enum FetchOracle.FeeCurrency\"\n                            }\n                          },\n                          \"nodeType\": \"Assignment\",\n                          \"operator\": \"=\",\n                          \"rightHandSide\": {\n                            \"argumentTypes\": null,\n                            \"expression\": {\n                              \"argumentTypes\": null,\n                              \"id\": 991,\n                              \"name\": \"FeeCurrency\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 827,\n                              \"src\": \"3870:11:4\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_type$_t_enum$_FeeCurrency_$827_$\",\n                                \"typeString\": \"type(enum FetchOracle.FeeCurrency)\"\n                              }\n                            },\n                            \"id\": 992,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": true,\n                            \"lValueRequested\": false,\n                            \"memberName\": \"ERC20\",\n                            \"nodeType\": \"MemberAccess\",\n                            \"referencedDeclaration\": null,\n                            \"src\": \"3870:17:4\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_enum$_FeeCurrency_$827\",\n                              \"typeString\": \"enum FetchOracle.FeeCurrency\"\n                            }\n                          },\n                          \"src\": \"3855:32:4\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_enum$_FeeCurrency_$827\",\n                            \"typeString\": \"enum FetchOracle.FeeCurrency\"\n                          }\n                        },\n                        \"id\": 994,\n                        \"nodeType\": \"ExpressionStatement\",\n                        \"src\": \"3855:32:4\"\n                      },\n                      {\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 999,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"leftHandSide\": {\n                            \"argumentTypes\": null,\n                            \"id\": 995,\n                            \"name\": \"_token\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 875,\n                            \"src\": \"3901:6:4\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_contract$_IERC20_$2649\",\n                              \"typeString\": \"contract IERC20\"\n                            }\n                          },\n                          \"nodeType\": \"Assignment\",\n                          \"operator\": \"=\",\n                          \"rightHandSide\": {\n                            \"argumentTypes\": null,\n                            \"arguments\": [\n                              {\n                                \"argumentTypes\": null,\n                                \"id\": 997,\n                                \"name\": \"ERC20Address\",\n                                \"nodeType\": \"Identifier\",\n                                \"overloadedDeclarations\": [],\n                                \"referencedDeclaration\": 967,\n                                \"src\": \"3917:12:4\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_address\",\n                                  \"typeString\": \"address\"\n                                }\n                              }\n                            ],\n                            \"expression\": {\n                              \"argumentTypes\": [\n                                {\n                                  \"typeIdentifier\": \"t_address\",\n                                  \"typeString\": \"address\"\n                                }\n                              ],\n                              \"id\": 996,\n                              \"name\": \"IERC20\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 2649,\n                              \"src\": \"3910:6:4\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_type$_t_contract$_IERC20_$2649_$\",\n                                \"typeString\": \"type(contract IERC20)\"\n                              }\n                            },\n                            \"id\": 998,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": false,\n                            \"kind\": \"typeConversion\",\n                            \"lValueRequested\": false,\n                            \"names\": [],\n                            \"nodeType\": \"FunctionCall\",\n                            \"src\": \"3910:20:4\",\n                            \"tryCall\": false,\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_contract$_IERC20_$2649\",\n                              \"typeString\": \"contract IERC20\"\n                            }\n                          },\n                          \"src\": \"3901:29:4\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_contract$_IERC20_$2649\",\n                            \"typeString\": \"contract IERC20\"\n                          }\n                        },\n                        \"id\": 1000,\n                        \"nodeType\": \"ExpressionStatement\",\n                        \"src\": \"3901:29:4\"\n                      }\n                    ]\n                  },\n                  \"id\": 1002,\n                  \"nodeType\": \"IfStatement\",\n                  \"src\": \"3748:193:4\",\n                  \"trueBody\": {\n                    \"id\": 989,\n                    \"nodeType\": \"Block\",\n                    \"src\": \"3780:55:4\",\n                    \"statements\": [\n                      {\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 987,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"leftHandSide\": {\n                            \"argumentTypes\": null,\n                            \"id\": 984,\n                            \"name\": \"_feeCurrency\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 887,\n                            \"src\": \"3794:12:4\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_enum$_FeeCurrency_$827\",\n                              \"typeString\": \"enum FetchOracle.FeeCurrency\"\n                            }\n                          },\n                          \"nodeType\": \"Assignment\",\n                          \"operator\": \"=\",\n                          \"rightHandSide\": {\n                            \"argumentTypes\": null,\n                            \"expression\": {\n                              \"argumentTypes\": null,\n                              \"id\": 985,\n                              \"name\": \"FeeCurrency\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 827,\n                              \"src\": \"3809:11:4\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_type$_t_enum$_FeeCurrency_$827_$\",\n                                \"typeString\": \"type(enum FetchOracle.FeeCurrency)\"\n                              }\n                            },\n                            \"id\": 986,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": true,\n                            \"lValueRequested\": false,\n                            \"memberName\": \"ETH\",\n                            \"nodeType\": \"MemberAccess\",\n                            \"referencedDeclaration\": null,\n                            \"src\": \"3809:15:4\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_enum$_FeeCurrency_$827\",\n                              \"typeString\": \"enum FetchOracle.FeeCurrency\"\n                            }\n                          },\n                          \"src\": \"3794:30:4\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_enum$_FeeCurrency_$827\",\n                            \"typeString\": \"enum FetchOracle.FeeCurrency\"\n                          }\n                        },\n                        \"id\": 988,\n                        \"nodeType\": \"ExpressionStatement\",\n                        \"src\": \"3794:30:4\"\n                      }\n                    ]\n                  }\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 1009,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 1003,\n                      \"name\": \"_earliestDelete\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 877,\n                      \"src\": \"3951:15:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"arguments\": [\n                        {\n                          \"argumentTypes\": null,\n                          \"id\": 1007,\n                          \"name\": \"DELETE_PROTECTION_PERIOD\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 873,\n                          \"src\": \"3991:24:4\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        }\n                      ],\n                      \"expression\": {\n                        \"argumentTypes\": [\n                          {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        ],\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"arguments\": [],\n                          \"expression\": {\n                            \"argumentTypes\": [],\n                            \"id\": 1004,\n                            \"name\": \"_getBlockNumber\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 1314,\n                            \"src\": \"3969:15:4\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_function_internal_view$__$returns$_t_uint256_$\",\n                              \"typeString\": \"function () view returns (uint256)\"\n                            }\n                          },\n                          \"id\": 1005,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"kind\": \"functionCall\",\n                          \"lValueRequested\": false,\n                          \"names\": [],\n                          \"nodeType\": \"FunctionCall\",\n                          \"src\": \"3969:17:4\",\n                          \"tryCall\": false,\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"id\": 1006,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"memberName\": \"add\",\n                        \"nodeType\": \"MemberAccess\",\n                        \"referencedDeclaration\": 1812,\n                        \"src\": \"3969:21:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_function_internal_pure$_t_uint256_$_t_uint256_$returns$_t_uint256_$bound_to$_t_uint256_$\",\n                          \"typeString\": \"function (uint256,uint256) pure returns (uint256)\"\n                        }\n                      },\n                      \"id\": 1008,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": false,\n                      \"kind\": \"functionCall\",\n                      \"lValueRequested\": false,\n                      \"names\": [],\n                      \"nodeType\": \"FunctionCall\",\n                      \"src\": \"3969:47:4\",\n                      \"tryCall\": false,\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"src\": \"3951:65:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"id\": 1010,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"3951:65:4\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 1017,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 1011,\n                      \"name\": \"_pausedSinceBlock\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 879,\n                      \"src\": \"4026:17:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 1016,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": true,\n                      \"lValueRequested\": false,\n                      \"nodeType\": \"UnaryOperation\",\n                      \"operator\": \"~\",\n                      \"prefix\": true,\n                      \"src\": \"4046:11:4\",\n                      \"subExpression\": {\n                        \"argumentTypes\": null,\n                        \"arguments\": [\n                          {\n                            \"argumentTypes\": null,\n                            \"hexValue\": \"30\",\n                            \"id\": 1014,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": true,\n                            \"kind\": \"number\",\n                            \"lValueRequested\": false,\n                            \"nodeType\": \"Literal\",\n                            \"src\": \"4055:1:4\",\n                            \"subdenomination\": null,\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_rational_0_by_1\",\n                              \"typeString\": \"int_const 0\"\n                            },\n                            \"value\": \"0\"\n                          }\n                        ],\n                        \"expression\": {\n                          \"argumentTypes\": [\n                            {\n                              \"typeIdentifier\": \"t_rational_0_by_1\",\n                              \"typeString\": \"int_const 0\"\n                            }\n                          ],\n                          \"id\": 1013,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": true,\n                          \"lValueRequested\": false,\n                          \"nodeType\": \"ElementaryTypeNameExpression\",\n                          \"src\": \"4047:7:4\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_type$_t_uint256_$\",\n                            \"typeString\": \"type(uint256)\"\n                          },\n                          \"typeName\": {\n                            \"id\": 1012,\n                            \"name\": \"uint256\",\n                            \"nodeType\": \"ElementaryTypeName\",\n                            \"src\": \"4047:7:4\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": null,\n                              \"typeString\": null\n                            }\n                          }\n                        },\n                        \"id\": 1015,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": true,\n                        \"kind\": \"typeConversion\",\n                        \"lValueRequested\": false,\n                        \"names\": [],\n                        \"nodeType\": \"FunctionCall\",\n                        \"src\": \"4047:10:4\",\n                        \"tryCall\": false,\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"src\": \"4026:31:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"id\": 1018,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"4026:31:4\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 1021,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 1019,\n                      \"name\": \"_fee\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 881,\n                      \"src\": \"4067:4:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 1020,\n                      \"name\": \"initialFee\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 969,\n                      \"src\": \"4074:10:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"src\": \"4067:17:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"id\": 1022,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"4067:17:4\"\n                }\n              ]\n            },\n            \"documentation\": {\n              \"id\": 965,\n              \"nodeType\": \"StructuredDocumentation\",\n              \"src\": \"3551:68:4\",\n              \"text\": \"@param ERC20Address address of the ERC20 contract\"\n            },\n            \"id\": 1024,\n            \"implemented\": true,\n            \"kind\": \"constructor\",\n            \"modifiers\": [],\n            \"name\": \"\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 970,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 967,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"ERC20Address\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 1024,\n                  \"src\": \"3636:20:4\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_address\",\n                    \"typeString\": \"address\"\n                  },\n                  \"typeName\": {\n                    \"id\": 966,\n                    \"name\": \"address\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"3636:7:4\",\n                    \"stateMutability\": \"nonpayable\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address\",\n                      \"typeString\": \"address\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 969,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"initialFee\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 1024,\n                  \"src\": \"3658:18:4\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 968,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"3658:7:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"3635:42:4\"\n            },\n            \"returnParameters\": {\n              \"id\": 971,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"3685:0:4\"\n            },\n            \"scope\": 1440,\n            \"src\": \"3624:467:4\",\n            \"stateMutability\": \"nonpayable\",\n            \"virtual\": false,\n            \"visibility\": \"public\"\n          },\n          {\n            \"body\": {\n              \"id\": 1062,\n              \"nodeType\": \"Block\",\n              \"src\": \"4303:223:4\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 1042,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 1038,\n                        \"name\": \"_oracleValue\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 885,\n                        \"src\": \"4313:12:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_OracleValue_$834_storage\",\n                          \"typeString\": \"struct FetchOracle.OracleValue storage ref\"\n                        }\n                      },\n                      \"id\": 1040,\n                      \"isConstant\": false,\n                      \"isLValue\": true,\n                      \"isPure\": false,\n                      \"lValueRequested\": true,\n                      \"memberName\": \"value\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": 829,\n                      \"src\": \"4313:18:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 1041,\n                      \"name\": \"value\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 1026,\n                      \"src\": \"4334:5:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"src\": \"4313:26:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"id\": 1043,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"4313:26:4\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 1048,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 1044,\n                        \"name\": \"_oracleValue\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 885,\n                        \"src\": \"4349:12:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_OracleValue_$834_storage\",\n                          \"typeString\": \"struct FetchOracle.OracleValue storage ref\"\n                        }\n                      },\n                      \"id\": 1046,\n                      \"isConstant\": false,\n                      \"isLValue\": true,\n                      \"isPure\": false,\n                      \"lValueRequested\": true,\n                      \"memberName\": \"decimals\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": 831,\n                      \"src\": \"4349:21:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint8\",\n                        \"typeString\": \"uint8\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 1047,\n                      \"name\": \"decimals\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 1028,\n                      \"src\": \"4373:8:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint8\",\n                        \"typeString\": \"uint8\"\n                      }\n                    },\n                    \"src\": \"4349:32:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint8\",\n                      \"typeString\": \"uint8\"\n                    }\n                  },\n                  \"id\": 1049,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"4349:32:4\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 1055,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 1050,\n                        \"name\": \"_oracleValue\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 885,\n                        \"src\": \"4391:12:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_OracleValue_$834_storage\",\n                          \"typeString\": \"struct FetchOracle.OracleValue storage ref\"\n                        }\n                      },\n                      \"id\": 1052,\n                      \"isConstant\": false,\n                      \"isLValue\": true,\n                      \"isPure\": false,\n                      \"lValueRequested\": true,\n                      \"memberName\": \"updatedAtEthBlockNumber\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": 833,\n                      \"src\": \"4391:36:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"arguments\": [],\n                      \"expression\": {\n                        \"argumentTypes\": [],\n                        \"id\": 1053,\n                        \"name\": \"_getBlockNumber\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 1314,\n                        \"src\": \"4430:15:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_function_internal_view$__$returns$_t_uint256_$\",\n                          \"typeString\": \"function () view returns (uint256)\"\n                        }\n                      },\n                      \"id\": 1054,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": false,\n                      \"kind\": \"functionCall\",\n                      \"lValueRequested\": false,\n                      \"names\": [],\n                      \"nodeType\": \"FunctionCall\",\n                      \"src\": \"4430:17:4\",\n                      \"tryCall\": false,\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"src\": \"4391:56:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"id\": 1056,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"4391:56:4\"\n                },\n                {\n                  \"eventCall\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 1058,\n                          \"name\": \"_oracleValue\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 885,\n                          \"src\": \"4481:12:4\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_struct$_OracleValue_$834_storage\",\n                            \"typeString\": \"struct FetchOracle.OracleValue storage ref\"\n                          }\n                        },\n                        \"id\": 1059,\n                        \"isConstant\": false,\n                        \"isLValue\": true,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"memberName\": \"updatedAtEthBlockNumber\",\n                        \"nodeType\": \"MemberAccess\",\n                        \"referencedDeclaration\": 833,\n                        \"src\": \"4481:36:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"id\": 1057,\n                      \"name\": \"OracleValueUpdated\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 860,\n                      \"src\": \"4462:18:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_event_nonpayable$_t_uint256_$returns$__$\",\n                        \"typeString\": \"function (uint256)\"\n                      }\n                    },\n                    \"id\": 1060,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"4462:56:4\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 1061,\n                  \"nodeType\": \"EmitStatement\",\n                  \"src\": \"4457:61:4\"\n                }\n              ]\n            },\n            \"documentation\": null,\n            \"functionSelector\": \"59f9f7cc\",\n            \"id\": 1063,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [\n              {\n                \"arguments\": [\n                  {\n                    \"argumentTypes\": null,\n                    \"id\": 1033,\n                    \"name\": \"txExpirationBlock\",\n                    \"nodeType\": \"Identifier\",\n                    \"overloadedDeclarations\": [],\n                    \"referencedDeclaration\": 1030,\n                    \"src\": \"4261:17:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  }\n                ],\n                \"id\": 1034,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 1032,\n                  \"name\": \"verifyTxExpiration\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 952,\n                  \"src\": \"4242:18:4\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$_t_uint256_$\",\n                    \"typeString\": \"modifier (uint256)\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"4242:37:4\"\n              },\n              {\n                \"arguments\": null,\n                \"id\": 1036,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 1035,\n                  \"name\": \"onlyOracle\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 938,\n                  \"src\": \"4288:10:4\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$__$\",\n                    \"typeString\": \"modifier ()\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"4288:10:4\"\n              }\n            ],\n            \"name\": \"updateOracleValue\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 1031,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 1026,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"value\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 1063,\n                  \"src\": \"4134:13:4\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 1025,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"4134:7:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 1028,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"decimals\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 1063,\n                  \"src\": \"4157:14:4\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint8\",\n                    \"typeString\": \"uint8\"\n                  },\n                  \"typeName\": {\n                    \"id\": 1027,\n                    \"name\": \"uint8\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"4157:5:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint8\",\n                      \"typeString\": \"uint8\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 1030,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"txExpirationBlock\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 1063,\n                  \"src\": \"4181:25:4\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 1029,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"4181:7:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"4124:92:4\"\n            },\n            \"returnParameters\": {\n              \"id\": 1037,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"4303:0:4\"\n            },\n            \"scope\": 1440,\n            \"src\": \"4098:428:4\",\n            \"stateMutability\": \"nonpayable\",\n            \"virtual\": false,\n            \"visibility\": \"external\"\n          },\n          {\n            \"body\": {\n              \"id\": 1090,\n              \"nodeType\": \"Block\",\n              \"src\": \"4669:181:4\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [],\n                    \"expression\": {\n                      \"argumentTypes\": [],\n                      \"id\": 1072,\n                      \"name\": \"_withdrawFee\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 1388,\n                      \"src\": \"4679:12:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_nonpayable$__$returns$__$\",\n                        \"typeString\": \"function ()\"\n                      }\n                    },\n                    \"id\": 1073,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"4679:14:4\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 1074,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"4679:14:4\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 1078,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 1075,\n                      \"name\": \"value\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 1066,\n                      \"src\": \"4703:5:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 1076,\n                        \"name\": \"_oracleValue\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 885,\n                        \"src\": \"4711:12:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_OracleValue_$834_storage\",\n                          \"typeString\": \"struct FetchOracle.OracleValue storage ref\"\n                        }\n                      },\n                      \"id\": 1077,\n                      \"isConstant\": false,\n                      \"isLValue\": true,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"memberName\": \"value\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": 829,\n                      \"src\": \"4711:18:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"src\": \"4703:26:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"id\": 1079,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"4703:26:4\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 1083,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 1080,\n                      \"name\": \"decimals\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 1068,\n                      \"src\": \"4739:8:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint8\",\n                        \"typeString\": \"uint8\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 1081,\n                        \"name\": \"_oracleValue\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 885,\n                        \"src\": \"4750:12:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_OracleValue_$834_storage\",\n                          \"typeString\": \"struct FetchOracle.OracleValue storage ref\"\n                        }\n                      },\n                      \"id\": 1082,\n                      \"isConstant\": false,\n                      \"isLValue\": true,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"memberName\": \"decimals\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": 831,\n                      \"src\": \"4750:21:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint8\",\n                        \"typeString\": \"uint8\"\n                      }\n                    },\n                    \"src\": \"4739:32:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint8\",\n                      \"typeString\": \"uint8\"\n                    }\n                  },\n                  \"id\": 1084,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"4739:32:4\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 1088,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 1085,\n                      \"name\": \"updatedAtEthBlockNumber\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 1070,\n                      \"src\": \"4781:23:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 1086,\n                        \"name\": \"_oracleValue\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 885,\n                        \"src\": \"4807:12:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_OracleValue_$834_storage\",\n                          \"typeString\": \"struct FetchOracle.OracleValue storage ref\"\n                        }\n                      },\n                      \"id\": 1087,\n                      \"isConstant\": false,\n                      \"isLValue\": true,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"memberName\": \"updatedAtEthBlockNumber\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": 833,\n                      \"src\": \"4807:36:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"src\": \"4781:62:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"id\": 1089,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"4781:62:4\"\n                }\n              ]\n            },\n            \"documentation\": null,\n            \"functionSelector\": \"f7e1c748\",\n            \"id\": 1091,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [],\n            \"name\": \"queryOracleValue\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 1064,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"4558:2:4\"\n            },\n            \"returnParameters\": {\n              \"id\": 1071,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 1066,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"value\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 1091,\n                  \"src\": \"4601:13:4\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 1065,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"4601:7:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 1068,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"decimals\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 1091,\n                  \"src\": \"4616:14:4\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint8\",\n                    \"typeString\": \"uint8\"\n                  },\n                  \"typeName\": {\n                    \"id\": 1067,\n                    \"name\": \"uint8\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"4616:5:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint8\",\n                      \"typeString\": \"uint8\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 1070,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"updatedAtEthBlockNumber\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 1091,\n                  \"src\": \"4632:31:4\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 1069,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"4632:7:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"4600:64:4\"\n            },\n            \"scope\": 1440,\n            \"src\": \"4533:317:4\",\n            \"stateMutability\": \"payable\",\n            \"virtual\": false,\n            \"visibility\": \"public\"\n          },\n          {\n            \"body\": {\n              \"id\": 1112,\n              \"nodeType\": \"Block\",\n              \"src\": \"5254:58:4\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 1106,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 1104,\n                      \"name\": \"_fee\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 881,\n                      \"src\": \"5264:4:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 1105,\n                      \"name\": \"fee\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 1094,\n                      \"src\": \"5271:3:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"src\": \"5264:10:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"id\": 1107,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"5264:10:4\"\n                },\n                {\n                  \"eventCall\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 1109,\n                        \"name\": \"_fee\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 881,\n                        \"src\": \"5300:4:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"id\": 1108,\n                      \"name\": \"FeeUpdated\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 838,\n                      \"src\": \"5289:10:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_event_nonpayable$_t_uint256_$returns$__$\",\n                        \"typeString\": \"function (uint256)\"\n                      }\n                    },\n                    \"id\": 1110,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"5289:16:4\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 1111,\n                  \"nodeType\": \"EmitStatement\",\n                  \"src\": \"5284:21:4\"\n                }\n              ]\n            },\n            \"documentation\": {\n              \"id\": 1092,\n              \"nodeType\": \"StructuredDocumentation\",\n              \"src\": \"4857:248:4\",\n              \"text\": \"@dev Pause the non-administrative interaction with the contract\\n@param fee - value of fee\\n@param txExpirationBlock - block number defined by Tx sender beyond which transaction becomes invalid\\n@dev Owners only\"\n            },\n            \"functionSelector\": \"52f7c988\",\n            \"id\": 1113,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [\n              {\n                \"arguments\": [\n                  {\n                    \"argumentTypes\": null,\n                    \"id\": 1099,\n                    \"name\": \"txExpirationBlock\",\n                    \"nodeType\": \"Identifier\",\n                    \"overloadedDeclarations\": [],\n                    \"referencedDeclaration\": 1096,\n                    \"src\": \"5210:17:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  }\n                ],\n                \"id\": 1100,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 1098,\n                  \"name\": \"verifyTxExpiration\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 952,\n                  \"src\": \"5191:18:4\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$_t_uint256_$\",\n                    \"typeString\": \"modifier (uint256)\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"5191:37:4\"\n              },\n              {\n                \"arguments\": null,\n                \"id\": 1102,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 1101,\n                  \"name\": \"onlyDelegate\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 925,\n                  \"src\": \"5237:12:4\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$__$\",\n                    \"typeString\": \"modifier ()\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"5237:12:4\"\n              }\n            ],\n            \"name\": \"setFee\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 1097,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 1094,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"fee\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 1113,\n                  \"src\": \"5126:11:4\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 1093,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"5126:7:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 1096,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"txExpirationBlock\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 1113,\n                  \"src\": \"5139:25:4\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 1095,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"5139:7:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"5125:40:4\"\n            },\n            \"returnParameters\": {\n              \"id\": 1103,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"5254:0:4\"\n            },\n            \"scope\": 1440,\n            \"src\": \"5110:202:4\",\n            \"stateMutability\": \"nonpayable\",\n            \"virtual\": false,\n            \"visibility\": \"external\"\n          },\n          {\n            \"body\": {\n              \"id\": 1144,\n              \"nodeType\": \"Block\",\n              \"src\": \"5701:198:4\",\n              \"statements\": [\n                {\n                  \"assignments\": [\n                    1127\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 1127,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"curr_block_number\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 1144,\n                      \"src\": \"5711:25:4\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"default\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      },\n                      \"typeName\": {\n                        \"id\": 1126,\n                        \"name\": \"uint256\",\n                        \"nodeType\": \"ElementaryTypeName\",\n                        \"src\": \"5711:7:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 1130,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [],\n                    \"expression\": {\n                      \"argumentTypes\": [],\n                      \"id\": 1128,\n                      \"name\": \"_getBlockNumber\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 1314,\n                      \"src\": \"5739:15:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_view$__$returns$_t_uint256_$\",\n                        \"typeString\": \"function () view returns (uint256)\"\n                      }\n                    },\n                    \"id\": 1129,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"5739:17:4\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"5711:45:4\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 1138,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 1131,\n                      \"name\": \"_pausedSinceBlock\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 879,\n                      \"src\": \"5766:17:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"condition\": {\n                        \"argumentTypes\": null,\n                        \"commonType\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        },\n                        \"id\": 1134,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"leftExpression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 1132,\n                          \"name\": \"block_number\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 1116,\n                          \"src\": \"5786:12:4\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"nodeType\": \"BinaryOperation\",\n                        \"operator\": \"<\",\n                        \"rightExpression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 1133,\n                          \"name\": \"curr_block_number\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 1127,\n                          \"src\": \"5801:17:4\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"src\": \"5786:32:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        }\n                      },\n                      \"falseExpression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 1136,\n                        \"name\": \"block_number\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 1116,\n                        \"src\": \"5841:12:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      \"id\": 1137,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"nodeType\": \"Conditional\",\n                      \"src\": \"5786:67:4\",\n                      \"trueExpression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 1135,\n                        \"name\": \"curr_block_number\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 1127,\n                        \"src\": \"5821:17:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"src\": \"5766:87:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"id\": 1139,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"5766:87:4\"\n                },\n                {\n                  \"eventCall\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 1141,\n                        \"name\": \"_pausedSinceBlock\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 879,\n                        \"src\": \"5874:17:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"id\": 1140,\n                      \"name\": \"Pause\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 842,\n                      \"src\": \"5868:5:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_event_nonpayable$_t_uint256_$returns$__$\",\n                        \"typeString\": \"function (uint256)\"\n                      }\n                    },\n                    \"id\": 1142,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"5868:24:4\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 1143,\n                  \"nodeType\": \"EmitStatement\",\n                  \"src\": \"5863:29:4\"\n                }\n              ]\n            },\n            \"documentation\": {\n              \"id\": 1114,\n              \"nodeType\": \"StructuredDocumentation\",\n              \"src\": \"5319:220:4\",\n              \"text\": \"@dev Pause the non-administrative interaction with the contract\\n@param block_number disallow non-admin. interactions with contract for a _getBlockNumber() >= block_number\\n@dev Owners only\"\n            },\n            \"functionSelector\": \"347908df\",\n            \"id\": 1145,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [\n              {\n                \"arguments\": [\n                  {\n                    \"argumentTypes\": null,\n                    \"id\": 1121,\n                    \"name\": \"txExpirationBlock\",\n                    \"nodeType\": \"Identifier\",\n                    \"overloadedDeclarations\": [],\n                    \"referencedDeclaration\": 1118,\n                    \"src\": \"5657:17:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  }\n                ],\n                \"id\": 1122,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 1120,\n                  \"name\": \"verifyTxExpiration\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 952,\n                  \"src\": \"5638:18:4\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$_t_uint256_$\",\n                    \"typeString\": \"modifier (uint256)\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"5638:37:4\"\n              },\n              {\n                \"arguments\": null,\n                \"id\": 1124,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 1123,\n                  \"name\": \"onlyDelegate\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 925,\n                  \"src\": \"5684:12:4\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$__$\",\n                    \"typeString\": \"modifier ()\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"5684:12:4\"\n              }\n            ],\n            \"name\": \"pauseSince\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 1119,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 1116,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"block_number\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 1145,\n                  \"src\": \"5564:20:4\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 1115,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"5564:7:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 1118,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"txExpirationBlock\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 1145,\n                  \"src\": \"5586:25:4\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 1117,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"5586:7:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"5563:49:4\"\n            },\n            \"returnParameters\": {\n              \"id\": 1125,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"5701:0:4\"\n            },\n            \"scope\": 1440,\n            \"src\": \"5544:355:4\",\n            \"stateMutability\": \"nonpayable\",\n            \"virtual\": false,\n            \"visibility\": \"external\"\n          },\n          {\n            \"body\": {\n              \"id\": 1178,\n              \"nodeType\": \"Block\",\n              \"src\": \"6442:366:4\",\n              \"statements\": [\n                {\n                  \"condition\": {\n                    \"argumentTypes\": null,\n                    \"commonType\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    },\n                    \"id\": 1160,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftExpression\": {\n                      \"argumentTypes\": null,\n                      \"id\": 1158,\n                      \"name\": \"_accruedFeesAmount\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 883,\n                      \"src\": \"6456:18:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"BinaryOperation\",\n                    \"operator\": \"==\",\n                    \"rightExpression\": {\n                      \"argumentTypes\": null,\n                      \"hexValue\": \"30\",\n                      \"id\": 1159,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": true,\n                      \"kind\": \"number\",\n                      \"lValueRequested\": false,\n                      \"nodeType\": \"Literal\",\n                      \"src\": \"6478:1:4\",\n                      \"subdenomination\": null,\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_rational_0_by_1\",\n                        \"typeString\": \"int_const 0\"\n                      },\n                      \"value\": \"0\"\n                    },\n                    \"src\": \"6456:23:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_bool\",\n                      \"typeString\": \"bool\"\n                    }\n                  },\n                  \"falseBody\": null,\n                  \"id\": 1163,\n                  \"nodeType\": \"IfStatement\",\n                  \"src\": \"6452:60:4\",\n                  \"trueBody\": {\n                    \"id\": 1162,\n                    \"nodeType\": \"Block\",\n                    \"src\": \"6481:31:4\",\n                    \"statements\": [\n                      {\n                        \"expression\": null,\n                        \"functionReturnParameters\": 1157,\n                        \"id\": 1161,\n                        \"nodeType\": \"Return\",\n                        \"src\": \"6495:7:4\"\n                      }\n                    ]\n                  }\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 1165,\n                        \"name\": \"targetAddress\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 1148,\n                        \"src\": \"6663:13:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 1166,\n                        \"name\": \"_accruedFeesAmount\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 883,\n                        \"src\": \"6678:18:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"id\": 1164,\n                      \"name\": \"_withdrawFromContract\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 1439,\n                      \"src\": \"6641:21:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_nonpayable$_t_address_payable_$_t_uint256_$returns$__$\",\n                        \"typeString\": \"function (address payable,uint256)\"\n                      }\n                    },\n                    \"id\": 1167,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"6641:56:4\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 1168,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"6641:56:4\"\n                },\n                {\n                  \"eventCall\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 1170,\n                        \"name\": \"targetAddress\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 1148,\n                        \"src\": \"6735:13:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 1171,\n                        \"name\": \"_accruedFeesAmount\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 883,\n                        \"src\": \"6750:18:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"id\": 1169,\n                      \"name\": \"AccruedFeesWithdrawal\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 854,\n                      \"src\": \"6713:21:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_event_nonpayable$_t_address_$_t_uint256_$returns$__$\",\n                        \"typeString\": \"function (address,uint256)\"\n                      }\n                    },\n                    \"id\": 1172,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"6713:56:4\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 1173,\n                  \"nodeType\": \"EmitStatement\",\n                  \"src\": \"6708:61:4\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 1176,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 1174,\n                      \"name\": \"_accruedFeesAmount\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 883,\n                      \"src\": \"6779:18:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"hexValue\": \"30\",\n                      \"id\": 1175,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": true,\n                      \"kind\": \"number\",\n                      \"lValueRequested\": false,\n                      \"nodeType\": \"Literal\",\n                      \"src\": \"6800:1:4\",\n                      \"subdenomination\": null,\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_rational_0_by_1\",\n                        \"typeString\": \"int_const 0\"\n                      },\n                      \"value\": \"0\"\n                    },\n                    \"src\": \"6779:22:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"id\": 1177,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"6779:22:4\"\n                }\n              ]\n            },\n            \"documentation\": {\n              \"id\": 1146,\n              \"nodeType\": \"StructuredDocumentation\",\n              \"src\": \"5906:359:4\",\n              \"text\": \"@dev Withdraw whole balance of all fees accrued in the contract so far.\\n@param targetAddress : address to send tokens to\\n@param txExpirationBlock : block number until which is the transaction valid (inclusive).\\n                           When transaction is processed after this block, it fails.\\n@dev Owners only\"\n            },\n            \"functionSelector\": \"323f4501\",\n            \"id\": 1179,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [\n              {\n                \"arguments\": [\n                  {\n                    \"argumentTypes\": null,\n                    \"id\": 1153,\n                    \"name\": \"txExpirationBlock\",\n                    \"nodeType\": \"Identifier\",\n                    \"overloadedDeclarations\": [],\n                    \"referencedDeclaration\": 1150,\n                    \"src\": \"6401:17:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  }\n                ],\n                \"id\": 1154,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 1152,\n                  \"name\": \"verifyTxExpiration\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 952,\n                  \"src\": \"6382:18:4\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$_t_uint256_$\",\n                    \"typeString\": \"modifier (uint256)\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"6382:37:4\"\n              },\n              {\n                \"arguments\": null,\n                \"id\": 1156,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 1155,\n                  \"name\": \"onlyOwner\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 909,\n                  \"src\": \"6428:9:4\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$__$\",\n                    \"typeString\": \"modifier ()\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"6428:9:4\"\n              }\n            ],\n            \"name\": \"withdrawAccruedFees\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 1151,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 1148,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"targetAddress\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 1179,\n                  \"src\": \"6299:29:4\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_address_payable\",\n                    \"typeString\": \"address payable\"\n                  },\n                  \"typeName\": {\n                    \"id\": 1147,\n                    \"name\": \"address\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"6299:15:4\",\n                    \"stateMutability\": \"payable\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address_payable\",\n                      \"typeString\": \"address payable\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 1150,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"txExpirationBlock\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 1179,\n                  \"src\": \"6330:25:4\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 1149,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"6330:7:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"6298:58:4\"\n            },\n            \"returnParameters\": {\n              \"id\": 1157,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"6442:0:4\"\n            },\n            \"scope\": 1440,\n            \"src\": \"6270:538:4\",\n            \"stateMutability\": \"nonpayable\",\n            \"virtual\": false,\n            \"visibility\": \"external\"\n          },\n          {\n            \"body\": {\n              \"id\": 1242,\n              \"nodeType\": \"Block\",\n              \"src\": \"7644:794:4\",\n              \"statements\": [\n                {\n                  \"assignments\": [\n                    1193\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 1193,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"contractBalance\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 1242,\n                      \"src\": \"7654:23:4\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"default\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      },\n                      \"typeName\": {\n                        \"id\": 1192,\n                        \"name\": \"uint256\",\n                        \"nodeType\": \"ElementaryTypeName\",\n                        \"src\": \"7654:7:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 1194,\n                  \"initialValue\": null,\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"7654:23:4\"\n                },\n                {\n                  \"condition\": {\n                    \"argumentTypes\": null,\n                    \"commonType\": {\n                      \"typeIdentifier\": \"t_enum$_FeeCurrency_$827\",\n                      \"typeString\": \"enum FetchOracle.FeeCurrency\"\n                    },\n                    \"id\": 1198,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftExpression\": {\n                      \"argumentTypes\": null,\n                      \"id\": 1195,\n                      \"name\": \"_feeCurrency\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 887,\n                      \"src\": \"7692:12:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_enum$_FeeCurrency_$827\",\n                        \"typeString\": \"enum FetchOracle.FeeCurrency\"\n                      }\n                    },\n                    \"nodeType\": \"BinaryOperation\",\n                    \"operator\": \"==\",\n                    \"rightExpression\": {\n                      \"argumentTypes\": null,\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 1196,\n                        \"name\": \"FeeCurrency\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 827,\n                        \"src\": \"7708:11:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_type$_t_enum$_FeeCurrency_$827_$\",\n                          \"typeString\": \"type(enum FetchOracle.FeeCurrency)\"\n                        }\n                      },\n                      \"id\": 1197,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": true,\n                      \"lValueRequested\": false,\n                      \"memberName\": \"ETH\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": null,\n                      \"src\": \"7708:15:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_enum$_FeeCurrency_$827\",\n                        \"typeString\": \"enum FetchOracle.FeeCurrency\"\n                      }\n                    },\n                    \"src\": \"7692:31:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_bool\",\n                      \"typeString\": \"bool\"\n                    }\n                  },\n                  \"falseBody\": {\n                    \"condition\": {\n                      \"argumentTypes\": null,\n                      \"commonType\": {\n                        \"typeIdentifier\": \"t_enum$_FeeCurrency_$827\",\n                        \"typeString\": \"enum FetchOracle.FeeCurrency\"\n                      },\n                      \"id\": 1211,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"leftExpression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 1208,\n                        \"name\": \"_feeCurrency\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 887,\n                        \"src\": \"7815:12:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_enum$_FeeCurrency_$827\",\n                          \"typeString\": \"enum FetchOracle.FeeCurrency\"\n                        }\n                      },\n                      \"nodeType\": \"BinaryOperation\",\n                      \"operator\": \"==\",\n                      \"rightExpression\": {\n                        \"argumentTypes\": null,\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 1209,\n                          \"name\": \"FeeCurrency\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 827,\n                          \"src\": \"7831:11:4\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_type$_t_enum$_FeeCurrency_$827_$\",\n                            \"typeString\": \"type(enum FetchOracle.FeeCurrency)\"\n                          }\n                        },\n                        \"id\": 1210,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": true,\n                        \"lValueRequested\": false,\n                        \"memberName\": \"ERC20\",\n                        \"nodeType\": \"MemberAccess\",\n                        \"referencedDeclaration\": null,\n                        \"src\": \"7831:17:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_enum$_FeeCurrency_$827\",\n                          \"typeString\": \"enum FetchOracle.FeeCurrency\"\n                        }\n                      },\n                      \"src\": \"7815:33:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_bool\",\n                        \"typeString\": \"bool\"\n                      }\n                    },\n                    \"falseBody\": null,\n                    \"id\": 1223,\n                    \"nodeType\": \"IfStatement\",\n                    \"src\": \"7811:113:4\",\n                    \"trueBody\": {\n                      \"id\": 1222,\n                      \"nodeType\": \"Block\",\n                      \"src\": \"7850:74:4\",\n                      \"statements\": [\n                        {\n                          \"expression\": {\n                            \"argumentTypes\": null,\n                            \"id\": 1220,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": false,\n                            \"lValueRequested\": false,\n                            \"leftHandSide\": {\n                              \"argumentTypes\": null,\n                              \"id\": 1212,\n                              \"name\": \"contractBalance\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 1193,\n                              \"src\": \"7864:15:4\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_uint256\",\n                                \"typeString\": \"uint256\"\n                              }\n                            },\n                            \"nodeType\": \"Assignment\",\n                            \"operator\": \"=\",\n                            \"rightHandSide\": {\n                              \"argumentTypes\": null,\n                              \"arguments\": [\n                                {\n                                  \"argumentTypes\": null,\n                                  \"arguments\": [\n                                    {\n                                      \"argumentTypes\": null,\n                                      \"id\": 1217,\n                                      \"name\": \"this\",\n                                      \"nodeType\": \"Identifier\",\n                                      \"overloadedDeclarations\": [],\n                                      \"referencedDeclaration\": -28,\n                                      \"src\": \"7907:4:4\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_contract$_FetchOracle_$1440\",\n                                        \"typeString\": \"contract FetchOracle\"\n                                      }\n                                    }\n                                  ],\n                                  \"expression\": {\n                                    \"argumentTypes\": [\n                                      {\n                                        \"typeIdentifier\": \"t_contract$_FetchOracle_$1440\",\n                                        \"typeString\": \"contract FetchOracle\"\n                                      }\n                                    ],\n                                    \"id\": 1216,\n                                    \"isConstant\": false,\n                                    \"isLValue\": false,\n                                    \"isPure\": true,\n                                    \"lValueRequested\": false,\n                                    \"nodeType\": \"ElementaryTypeNameExpression\",\n                                    \"src\": \"7899:7:4\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_type$_t_address_$\",\n                                      \"typeString\": \"type(address)\"\n                                    },\n                                    \"typeName\": {\n                                      \"id\": 1215,\n                                      \"name\": \"address\",\n                                      \"nodeType\": \"ElementaryTypeName\",\n                                      \"src\": \"7899:7:4\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": null,\n                                        \"typeString\": null\n                                      }\n                                    }\n                                  },\n                                  \"id\": 1218,\n                                  \"isConstant\": false,\n                                  \"isLValue\": false,\n                                  \"isPure\": false,\n                                  \"kind\": \"typeConversion\",\n                                  \"lValueRequested\": false,\n                                  \"names\": [],\n                                  \"nodeType\": \"FunctionCall\",\n                                  \"src\": \"7899:13:4\",\n                                  \"tryCall\": false,\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_address\",\n                                    \"typeString\": \"address\"\n                                  }\n                                }\n                              ],\n                              \"expression\": {\n                                \"argumentTypes\": [\n                                  {\n                                    \"typeIdentifier\": \"t_address\",\n                                    \"typeString\": \"address\"\n                                  }\n                                ],\n                                \"expression\": {\n                                  \"argumentTypes\": null,\n                                  \"id\": 1213,\n                                  \"name\": \"_token\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 875,\n                                  \"src\": \"7882:6:4\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_contract$_IERC20_$2649\",\n                                    \"typeString\": \"contract IERC20\"\n                                  }\n                                },\n                                \"id\": 1214,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": false,\n                                \"lValueRequested\": false,\n                                \"memberName\": \"balanceOf\",\n                                \"nodeType\": \"MemberAccess\",\n                                \"referencedDeclaration\": 2588,\n                                \"src\": \"7882:16:4\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_function_external_view$_t_address_$returns$_t_uint256_$\",\n                                  \"typeString\": \"function (address) view external returns (uint256)\"\n                                }\n                              },\n                              \"id\": 1219,\n                              \"isConstant\": false,\n                              \"isLValue\": false,\n                              \"isPure\": false,\n                              \"kind\": \"functionCall\",\n                              \"lValueRequested\": false,\n                              \"names\": [],\n                              \"nodeType\": \"FunctionCall\",\n                              \"src\": \"7882:31:4\",\n                              \"tryCall\": false,\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_uint256\",\n                                \"typeString\": \"uint256\"\n                              }\n                            },\n                            \"src\": \"7864:49:4\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"id\": 1221,\n                          \"nodeType\": \"ExpressionStatement\",\n                          \"src\": \"7864:49:4\"\n                        }\n                      ]\n                    }\n                  },\n                  \"id\": 1224,\n                  \"nodeType\": \"IfStatement\",\n                  \"src\": \"7688:236:4\",\n                  \"trueBody\": {\n                    \"id\": 1207,\n                    \"nodeType\": \"Block\",\n                    \"src\": \"7733:64:4\",\n                    \"statements\": [\n                      {\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 1205,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"leftHandSide\": {\n                            \"argumentTypes\": null,\n                            \"id\": 1199,\n                            \"name\": \"contractBalance\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 1193,\n                            \"src\": \"7747:15:4\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"nodeType\": \"Assignment\",\n                          \"operator\": \"=\",\n                          \"rightHandSide\": {\n                            \"argumentTypes\": null,\n                            \"expression\": {\n                              \"argumentTypes\": null,\n                              \"arguments\": [\n                                {\n                                  \"argumentTypes\": null,\n                                  \"id\": 1202,\n                                  \"name\": \"this\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": -28,\n                                  \"src\": \"7773:4:4\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_contract$_FetchOracle_$1440\",\n                                    \"typeString\": \"contract FetchOracle\"\n                                  }\n                                }\n                              ],\n                              \"expression\": {\n                                \"argumentTypes\": [\n                                  {\n                                    \"typeIdentifier\": \"t_contract$_FetchOracle_$1440\",\n                                    \"typeString\": \"contract FetchOracle\"\n                                  }\n                                ],\n                                \"id\": 1201,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": true,\n                                \"lValueRequested\": false,\n                                \"nodeType\": \"ElementaryTypeNameExpression\",\n                                \"src\": \"7765:7:4\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_type$_t_address_$\",\n                                  \"typeString\": \"type(address)\"\n                                },\n                                \"typeName\": {\n                                  \"id\": 1200,\n                                  \"name\": \"address\",\n                                  \"nodeType\": \"ElementaryTypeName\",\n                                  \"src\": \"7765:7:4\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": null,\n                                    \"typeString\": null\n                                  }\n                                }\n                              },\n                              \"id\": 1203,\n                              \"isConstant\": false,\n                              \"isLValue\": false,\n                              \"isPure\": false,\n                              \"kind\": \"typeConversion\",\n                              \"lValueRequested\": false,\n                              \"names\": [],\n                              \"nodeType\": \"FunctionCall\",\n                              \"src\": \"7765:13:4\",\n                              \"tryCall\": false,\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_address\",\n                                \"typeString\": \"address\"\n                              }\n                            },\n                            \"id\": 1204,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": false,\n                            \"lValueRequested\": false,\n                            \"memberName\": \"balance\",\n                            \"nodeType\": \"MemberAccess\",\n                            \"referencedDeclaration\": null,\n                            \"src\": \"7765:21:4\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"src\": \"7747:39:4\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"id\": 1206,\n                        \"nodeType\": \"ExpressionStatement\",\n                        \"src\": \"7747:39:4\"\n                      }\n                    ]\n                  }\n                },\n                {\n                  \"assignments\": [\n                    1226\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 1226,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"excessAmount\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 1242,\n                      \"src\": \"8244:20:4\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"default\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      },\n                      \"typeName\": {\n                        \"id\": 1225,\n                        \"name\": \"uint256\",\n                        \"nodeType\": \"ElementaryTypeName\",\n                        \"src\": \"8244:7:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 1231,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 1229,\n                        \"name\": \"_accruedFeesAmount\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 883,\n                        \"src\": \"8287:18:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 1227,\n                        \"name\": \"contractBalance\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 1193,\n                        \"src\": \"8267:15:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      \"id\": 1228,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"memberName\": \"sub\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": 1829,\n                      \"src\": \"8267:19:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_pure$_t_uint256_$_t_uint256_$returns$_t_uint256_$bound_to$_t_uint256_$\",\n                        \"typeString\": \"function (uint256,uint256) pure returns (uint256)\"\n                      }\n                    },\n                    \"id\": 1230,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"8267:39:4\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"8244:62:4\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 1233,\n                        \"name\": \"targetAddress\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 1182,\n                        \"src\": \"8338:13:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 1234,\n                        \"name\": \"excessAmount\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 1226,\n                        \"src\": \"8353:12:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"id\": 1232,\n                      \"name\": \"_withdrawFromContract\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 1439,\n                      \"src\": \"8316:21:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_nonpayable$_t_address_payable_$_t_uint256_$returns$__$\",\n                        \"typeString\": \"function (address payable,uint256)\"\n                      }\n                    },\n                    \"id\": 1235,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"8316:50:4\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 1236,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"8316:50:4\"\n                },\n                {\n                  \"eventCall\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 1238,\n                        \"name\": \"targetAddress\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 1182,\n                        \"src\": \"8403:13:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 1239,\n                        \"name\": \"excessAmount\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 1226,\n                        \"src\": \"8418:12:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"id\": 1237,\n                      \"name\": \"ExcessTokenWithdrawal\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 848,\n                      \"src\": \"8381:21:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_event_nonpayable$_t_address_$_t_uint256_$returns$__$\",\n                        \"typeString\": \"function (address,uint256)\"\n                      }\n                    },\n                    \"id\": 1240,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"8381:50:4\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 1241,\n                  \"nodeType\": \"EmitStatement\",\n                  \"src\": \"8376:55:4\"\n                }\n              ]\n            },\n            \"documentation\": {\n              \"id\": 1180,\n              \"nodeType\": \"StructuredDocumentation\",\n              \"src\": \"6815:651:4\",\n              \"text\": \"@dev Withdraw \\\"excess\\\" tokens, which were sent to contract address directly via direct ERC20 transfer(...) or transferFrom(...),\\n     without interacting with API of this (FetchOracle) contract, what could be done only by mistake.\\n     Thus this method is meant to be used primarily for rescue purposes, enabling withdrawal of such\\n     \\\"excess\\\" tokens out of contract.\\n@param targetAddress : address to send tokens to\\n@param txExpirationBlock : block number until which is the transaction valid (inclusive).\\n                           When transaction is processed after this block, it fails.\"\n            },\n            \"functionSelector\": \"53e052ac\",\n            \"id\": 1243,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [\n              {\n                \"arguments\": [\n                  {\n                    \"argumentTypes\": null,\n                    \"id\": 1187,\n                    \"name\": \"txExpirationBlock\",\n                    \"nodeType\": \"Identifier\",\n                    \"overloadedDeclarations\": [],\n                    \"referencedDeclaration\": 1184,\n                    \"src\": \"7603:17:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  }\n                ],\n                \"id\": 1188,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 1186,\n                  \"name\": \"verifyTxExpiration\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 952,\n                  \"src\": \"7584:18:4\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$_t_uint256_$\",\n                    \"typeString\": \"modifier (uint256)\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"7584:37:4\"\n              },\n              {\n                \"arguments\": null,\n                \"id\": 1190,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 1189,\n                  \"name\": \"onlyOwner\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 909,\n                  \"src\": \"7630:9:4\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$__$\",\n                    \"typeString\": \"modifier ()\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"7630:9:4\"\n              }\n            ],\n            \"name\": \"withdrawExcessTokens\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 1185,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 1182,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"targetAddress\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 1243,\n                  \"src\": \"7501:29:4\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_address_payable\",\n                    \"typeString\": \"address payable\"\n                  },\n                  \"typeName\": {\n                    \"id\": 1181,\n                    \"name\": \"address\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"7501:15:4\",\n                    \"stateMutability\": \"payable\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address_payable\",\n                      \"typeString\": \"address payable\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 1184,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"txExpirationBlock\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 1243,\n                  \"src\": \"7532:25:4\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 1183,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"7532:7:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"7500:58:4\"\n            },\n            \"returnParameters\": {\n              \"id\": 1191,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"7644:0:4\"\n            },\n            \"scope\": 1440,\n            \"src\": \"7471:967:4\",\n            \"stateMutability\": \"nonpayable\",\n            \"virtual\": false,\n            \"visibility\": \"external\"\n          },\n          {\n            \"body\": {\n              \"id\": 1295,\n              \"nodeType\": \"Block\",\n              \"src\": \"8926:469:4\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"commonType\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        },\n                        \"id\": 1260,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"leftExpression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 1257,\n                          \"name\": \"_earliestDelete\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 877,\n                          \"src\": \"8944:15:4\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"nodeType\": \"BinaryOperation\",\n                        \"operator\": \">=\",\n                        \"rightExpression\": {\n                          \"argumentTypes\": null,\n                          \"arguments\": [],\n                          \"expression\": {\n                            \"argumentTypes\": [],\n                            \"id\": 1258,\n                            \"name\": \"_getBlockNumber\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 1314,\n                            \"src\": \"8963:15:4\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_function_internal_view$__$returns$_t_uint256_$\",\n                              \"typeString\": \"function () view returns (uint256)\"\n                            }\n                          },\n                          \"id\": 1259,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"kind\": \"functionCall\",\n                          \"lValueRequested\": false,\n                          \"names\": [],\n                          \"nodeType\": \"FunctionCall\",\n                          \"src\": \"8963:17:4\",\n                          \"tryCall\": false,\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"src\": \"8944:36:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"hexValue\": \"4561726c696573742064656c657465206e6f742072656163686564\",\n                        \"id\": 1261,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": true,\n                        \"kind\": \"string\",\n                        \"lValueRequested\": false,\n                        \"nodeType\": \"Literal\",\n                        \"src\": \"8982:29:4\",\n                        \"subdenomination\": null,\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_stringliteral_5f181249ab5034a5754d3db6b5f7492a28b118cbf69c6f93d3cfe542886db22a\",\n                          \"typeString\": \"literal_string \\\"Earliest delete not reached\\\"\"\n                        },\n                        \"value\": \"Earliest delete not reached\"\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_stringliteral_5f181249ab5034a5754d3db6b5f7492a28b118cbf69c6f93d3cfe542886db22a\",\n                          \"typeString\": \"literal_string \\\"Earliest delete not reached\\\"\"\n                        }\n                      ],\n                      \"id\": 1256,\n                      \"name\": \"require\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [\n                        -18,\n                        -18\n                      ],\n                      \"referencedDeclaration\": -18,\n                      \"src\": \"8936:7:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$\",\n                        \"typeString\": \"function (bool,string memory) pure\"\n                      }\n                    },\n                    \"id\": 1262,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"8936:76:4\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 1263,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"8936:76:4\"\n                },\n                {\n                  \"condition\": {\n                    \"argumentTypes\": null,\n                    \"commonType\": {\n                      \"typeIdentifier\": \"t_enum$_FeeCurrency_$827\",\n                      \"typeString\": \"enum FetchOracle.FeeCurrency\"\n                    },\n                    \"id\": 1267,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftExpression\": {\n                      \"argumentTypes\": null,\n                      \"id\": 1264,\n                      \"name\": \"_feeCurrency\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 887,\n                      \"src\": \"9026:12:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_enum$_FeeCurrency_$827\",\n                        \"typeString\": \"enum FetchOracle.FeeCurrency\"\n                      }\n                    },\n                    \"nodeType\": \"BinaryOperation\",\n                    \"operator\": \"==\",\n                    \"rightExpression\": {\n                      \"argumentTypes\": null,\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 1265,\n                        \"name\": \"FeeCurrency\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 827,\n                        \"src\": \"9042:11:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_type$_t_enum$_FeeCurrency_$827_$\",\n                          \"typeString\": \"type(enum FetchOracle.FeeCurrency)\"\n                        }\n                      },\n                      \"id\": 1266,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": true,\n                      \"lValueRequested\": false,\n                      \"memberName\": \"ERC20\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": null,\n                      \"src\": \"9042:17:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_enum$_FeeCurrency_$827\",\n                        \"typeString\": \"enum FetchOracle.FeeCurrency\"\n                      }\n                    },\n                    \"src\": \"9026:33:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_bool\",\n                      \"typeString\": \"bool\"\n                    }\n                  },\n                  \"falseBody\": null,\n                  \"id\": 1287,\n                  \"nodeType\": \"IfStatement\",\n                  \"src\": \"9022:191:4\",\n                  \"trueBody\": {\n                    \"id\": 1286,\n                    \"nodeType\": \"Block\",\n                    \"src\": \"9061:152:4\",\n                    \"statements\": [\n                      {\n                        \"assignments\": [\n                          1269\n                        ],\n                        \"declarations\": [\n                          {\n                            \"constant\": false,\n                            \"id\": 1269,\n                            \"mutability\": \"mutable\",\n                            \"name\": \"contractBalance\",\n                            \"nodeType\": \"VariableDeclaration\",\n                            \"overrides\": null,\n                            \"scope\": 1286,\n                            \"src\": \"9075:23:4\",\n                            \"stateVariable\": false,\n                            \"storageLocation\": \"default\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            },\n                            \"typeName\": {\n                              \"id\": 1268,\n                              \"name\": \"uint256\",\n                              \"nodeType\": \"ElementaryTypeName\",\n                              \"src\": \"9075:7:4\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_uint256\",\n                                \"typeString\": \"uint256\"\n                              }\n                            },\n                            \"value\": null,\n                            \"visibility\": \"internal\"\n                          }\n                        ],\n                        \"id\": 1277,\n                        \"initialValue\": {\n                          \"argumentTypes\": null,\n                          \"arguments\": [\n                            {\n                              \"argumentTypes\": null,\n                              \"arguments\": [\n                                {\n                                  \"argumentTypes\": null,\n                                  \"id\": 1274,\n                                  \"name\": \"this\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": -28,\n                                  \"src\": \"9126:4:4\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_contract$_FetchOracle_$1440\",\n                                    \"typeString\": \"contract FetchOracle\"\n                                  }\n                                }\n                              ],\n                              \"expression\": {\n                                \"argumentTypes\": [\n                                  {\n                                    \"typeIdentifier\": \"t_contract$_FetchOracle_$1440\",\n                                    \"typeString\": \"contract FetchOracle\"\n                                  }\n                                ],\n                                \"id\": 1273,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": true,\n                                \"lValueRequested\": false,\n                                \"nodeType\": \"ElementaryTypeNameExpression\",\n                                \"src\": \"9118:7:4\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_type$_t_address_$\",\n                                  \"typeString\": \"type(address)\"\n                                },\n                                \"typeName\": {\n                                  \"id\": 1272,\n                                  \"name\": \"address\",\n                                  \"nodeType\": \"ElementaryTypeName\",\n                                  \"src\": \"9118:7:4\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": null,\n                                    \"typeString\": null\n                                  }\n                                }\n                              },\n                              \"id\": 1275,\n                              \"isConstant\": false,\n                              \"isLValue\": false,\n                              \"isPure\": false,\n                              \"kind\": \"typeConversion\",\n                              \"lValueRequested\": false,\n                              \"names\": [],\n                              \"nodeType\": \"FunctionCall\",\n                              \"src\": \"9118:13:4\",\n                              \"tryCall\": false,\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_address\",\n                                \"typeString\": \"address\"\n                              }\n                            }\n                          ],\n                          \"expression\": {\n                            \"argumentTypes\": [\n                              {\n                                \"typeIdentifier\": \"t_address\",\n                                \"typeString\": \"address\"\n                              }\n                            ],\n                            \"expression\": {\n                              \"argumentTypes\": null,\n                              \"id\": 1270,\n                              \"name\": \"_token\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 875,\n                              \"src\": \"9101:6:4\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_contract$_IERC20_$2649\",\n                                \"typeString\": \"contract IERC20\"\n                              }\n                            },\n                            \"id\": 1271,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": false,\n                            \"lValueRequested\": false,\n                            \"memberName\": \"balanceOf\",\n                            \"nodeType\": \"MemberAccess\",\n                            \"referencedDeclaration\": 2588,\n                            \"src\": \"9101:16:4\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_function_external_view$_t_address_$returns$_t_uint256_$\",\n                              \"typeString\": \"function (address) view external returns (uint256)\"\n                            }\n                          },\n                          \"id\": 1276,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"kind\": \"functionCall\",\n                          \"lValueRequested\": false,\n                          \"names\": [],\n                          \"nodeType\": \"FunctionCall\",\n                          \"src\": \"9101:31:4\",\n                          \"tryCall\": false,\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"nodeType\": \"VariableDeclarationStatement\",\n                        \"src\": \"9075:57:4\"\n                      },\n                      {\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"arguments\": [\n                            {\n                              \"argumentTypes\": null,\n                              \"arguments\": [\n                                {\n                                  \"argumentTypes\": null,\n                                  \"id\": 1281,\n                                  \"name\": \"payoutAddress\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 1246,\n                                  \"src\": \"9170:13:4\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_address_payable\",\n                                    \"typeString\": \"address payable\"\n                                  }\n                                },\n                                {\n                                  \"argumentTypes\": null,\n                                  \"id\": 1282,\n                                  \"name\": \"contractBalance\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 1269,\n                                  \"src\": \"9185:15:4\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_uint256\",\n                                    \"typeString\": \"uint256\"\n                                  }\n                                }\n                              ],\n                              \"expression\": {\n                                \"argumentTypes\": [\n                                  {\n                                    \"typeIdentifier\": \"t_address_payable\",\n                                    \"typeString\": \"address payable\"\n                                  },\n                                  {\n                                    \"typeIdentifier\": \"t_uint256\",\n                                    \"typeString\": \"uint256\"\n                                  }\n                                ],\n                                \"expression\": {\n                                  \"argumentTypes\": null,\n                                  \"id\": 1279,\n                                  \"name\": \"_token\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 875,\n                                  \"src\": \"9154:6:4\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_contract$_IERC20_$2649\",\n                                    \"typeString\": \"contract IERC20\"\n                                  }\n                                },\n                                \"id\": 1280,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": false,\n                                \"lValueRequested\": false,\n                                \"memberName\": \"transfer\",\n                                \"nodeType\": \"MemberAccess\",\n                                \"referencedDeclaration\": 2598,\n                                \"src\": \"9154:15:4\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_function_external_nonpayable$_t_address_$_t_uint256_$returns$_t_bool_$\",\n                                  \"typeString\": \"function (address,uint256) external returns (bool)\"\n                                }\n                              },\n                              \"id\": 1283,\n                              \"isConstant\": false,\n                              \"isLValue\": false,\n                              \"isPure\": false,\n                              \"kind\": \"functionCall\",\n                              \"lValueRequested\": false,\n                              \"names\": [],\n                              \"nodeType\": \"FunctionCall\",\n                              \"src\": \"9154:47:4\",\n                              \"tryCall\": false,\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_bool\",\n                                \"typeString\": \"bool\"\n                              }\n                            }\n                          ],\n                          \"expression\": {\n                            \"argumentTypes\": [\n                              {\n                                \"typeIdentifier\": \"t_bool\",\n                                \"typeString\": \"bool\"\n                              }\n                            ],\n                            \"id\": 1278,\n                            \"name\": \"require\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [\n                              -18,\n                              -18\n                            ],\n                            \"referencedDeclaration\": -18,\n                            \"src\": \"9146:7:4\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_function_require_pure$_t_bool_$returns$__$\",\n                              \"typeString\": \"function (bool) pure\"\n                            }\n                          },\n                          \"id\": 1284,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"kind\": \"functionCall\",\n                          \"lValueRequested\": false,\n                          \"names\": [],\n                          \"nodeType\": \"FunctionCall\",\n                          \"src\": \"9146:56:4\",\n                          \"tryCall\": false,\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_tuple$__$\",\n                            \"typeString\": \"tuple()\"\n                          }\n                        },\n                        \"id\": 1285,\n                        \"nodeType\": \"ExpressionStatement\",\n                        \"src\": \"9146:56:4\"\n                      }\n                    ]\n                  }\n                },\n                {\n                  \"eventCall\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [],\n                    \"expression\": {\n                      \"argumentTypes\": [],\n                      \"id\": 1288,\n                      \"name\": \"ContractDeleted\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 856,\n                      \"src\": \"9227:15:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_event_nonpayable$__$returns$__$\",\n                        \"typeString\": \"function ()\"\n                      }\n                    },\n                    \"id\": 1289,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"9227:17:4\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 1290,\n                  \"nodeType\": \"EmitStatement\",\n                  \"src\": \"9222:22:4\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 1292,\n                        \"name\": \"payoutAddress\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 1246,\n                        \"src\": \"9374:13:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        }\n                      ],\n                      \"id\": 1291,\n                      \"name\": \"selfdestruct\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": -21,\n                      \"src\": \"9361:12:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_selfdestruct_nonpayable$_t_address_payable_$returns$__$\",\n                        \"typeString\": \"function (address payable)\"\n                      }\n                    },\n                    \"id\": 1293,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"9361:27:4\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 1294,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"9361:27:4\"\n                }\n              ]\n            },\n            \"documentation\": {\n              \"id\": 1244,\n              \"nodeType\": \"StructuredDocumentation\",\n              \"src\": \"8445:309:4\",\n              \"text\": \"@dev Delete the contract, transfers the remaining token and ether balance to the specified\\npayoutAddress\\n@param payoutAddress address to transfer the balances to. Ensure that this is able to handle ERC20 tokens\\n@dev owner only + only on or after `_earliestDelete` block\"\n            },\n            \"functionSelector\": \"9608df4b\",\n            \"id\": 1296,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [\n              {\n                \"arguments\": [\n                  {\n                    \"argumentTypes\": null,\n                    \"id\": 1251,\n                    \"name\": \"txExpirationBlock\",\n                    \"nodeType\": \"Identifier\",\n                    \"overloadedDeclarations\": [],\n                    \"referencedDeclaration\": 1248,\n                    \"src\": \"8885:17:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  }\n                ],\n                \"id\": 1252,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 1250,\n                  \"name\": \"verifyTxExpiration\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 952,\n                  \"src\": \"8866:18:4\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$_t_uint256_$\",\n                    \"typeString\": \"modifier (uint256)\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"8866:37:4\"\n              },\n              {\n                \"arguments\": null,\n                \"id\": 1254,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 1253,\n                  \"name\": \"onlyOwner\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 909,\n                  \"src\": \"8912:9:4\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$__$\",\n                    \"typeString\": \"modifier ()\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"8912:9:4\"\n              }\n            ],\n            \"name\": \"deleteContract\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 1249,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 1246,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"payoutAddress\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 1296,\n                  \"src\": \"8783:29:4\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_address_payable\",\n                    \"typeString\": \"address payable\"\n                  },\n                  \"typeName\": {\n                    \"id\": 1245,\n                    \"name\": \"address\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"8783:15:4\",\n                    \"stateMutability\": \"payable\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address_payable\",\n                      \"typeString\": \"address payable\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 1248,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"txExpirationBlock\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 1296,\n                  \"src\": \"8814:25:4\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 1247,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"8814:7:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"8782:58:4\"\n            },\n            \"returnParameters\": {\n              \"id\": 1255,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"8926:0:4\"\n            },\n            \"scope\": 1440,\n            \"src\": \"8759:636:4\",\n            \"stateMutability\": \"nonpayable\",\n            \"virtual\": false,\n            \"visibility\": \"external\"\n          },\n          {\n            \"body\": {\n              \"id\": 1304,\n              \"nodeType\": \"Block\",\n              \"src\": \"9471:60:4\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"expression\": {\n                      \"argumentTypes\": null,\n                      \"id\": 1301,\n                      \"name\": \"_oracleValue\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 885,\n                      \"src\": \"9488:12:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_struct$_OracleValue_$834_storage\",\n                        \"typeString\": \"struct FetchOracle.OracleValue storage ref\"\n                      }\n                    },\n                    \"id\": 1302,\n                    \"isConstant\": false,\n                    \"isLValue\": true,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"memberName\": \"updatedAtEthBlockNumber\",\n                    \"nodeType\": \"MemberAccess\",\n                    \"referencedDeclaration\": 833,\n                    \"src\": \"9488:36:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"functionReturnParameters\": 1300,\n                  \"id\": 1303,\n                  \"nodeType\": \"Return\",\n                  \"src\": \"9481:43:4\"\n                }\n              ]\n            },\n            \"documentation\": null,\n            \"functionSelector\": \"9bc18909\",\n            \"id\": 1305,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [],\n            \"name\": \"oracleValueLastUpdated\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 1297,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"9433:2:4\"\n            },\n            \"returnParameters\": {\n              \"id\": 1300,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 1299,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 1305,\n                  \"src\": \"9458:7:4\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 1298,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"9458:7:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"9457:9:4\"\n            },\n            \"scope\": 1440,\n            \"src\": \"9402:129:4\",\n            \"stateMutability\": \"view\",\n            \"virtual\": false,\n            \"visibility\": \"external\"\n          },\n          {\n            \"body\": {\n              \"id\": 1313,\n              \"nodeType\": \"Block\",\n              \"src\": \"9607:36:4\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"expression\": {\n                      \"argumentTypes\": null,\n                      \"id\": 1310,\n                      \"name\": \"block\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": -4,\n                      \"src\": \"9624:5:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_magic_block\",\n                        \"typeString\": \"block\"\n                      }\n                    },\n                    \"id\": 1311,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"memberName\": \"number\",\n                    \"nodeType\": \"MemberAccess\",\n                    \"referencedDeclaration\": null,\n                    \"src\": \"9624:12:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"functionReturnParameters\": 1309,\n                  \"id\": 1312,\n                  \"nodeType\": \"Return\",\n                  \"src\": \"9617:19:4\"\n                }\n              ]\n            },\n            \"documentation\": null,\n            \"id\": 1314,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [],\n            \"name\": \"_getBlockNumber\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 1306,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"9561:2:4\"\n            },\n            \"returnParameters\": {\n              \"id\": 1309,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 1308,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 1314,\n                  \"src\": \"9594:7:4\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 1307,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"9594:7:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"9593:9:4\"\n            },\n            \"scope\": 1440,\n            \"src\": \"9537:106:4\",\n            \"stateMutability\": \"view\",\n            \"virtual\": true,\n            \"visibility\": \"internal\"\n          },\n          {\n            \"body\": {\n              \"id\": 1387,\n              \"nodeType\": \"Block\",\n              \"src\": \"9745:1001:4\",\n              \"statements\": [\n                {\n                  \"condition\": {\n                    \"argumentTypes\": null,\n                    \"commonType\": {\n                      \"typeIdentifier\": \"t_enum$_FeeCurrency_$827\",\n                      \"typeString\": \"enum FetchOracle.FeeCurrency\"\n                    },\n                    \"id\": 1321,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftExpression\": {\n                      \"argumentTypes\": null,\n                      \"id\": 1318,\n                      \"name\": \"_feeCurrency\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 887,\n                      \"src\": \"9759:12:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_enum$_FeeCurrency_$827\",\n                        \"typeString\": \"enum FetchOracle.FeeCurrency\"\n                      }\n                    },\n                    \"nodeType\": \"BinaryOperation\",\n                    \"operator\": \"==\",\n                    \"rightExpression\": {\n                      \"argumentTypes\": null,\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 1319,\n                        \"name\": \"FeeCurrency\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 827,\n                        \"src\": \"9775:11:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_type$_t_enum$_FeeCurrency_$827_$\",\n                          \"typeString\": \"type(enum FetchOracle.FeeCurrency)\"\n                        }\n                      },\n                      \"id\": 1320,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": true,\n                      \"lValueRequested\": false,\n                      \"memberName\": \"ETH\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": null,\n                      \"src\": \"9775:15:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_enum$_FeeCurrency_$827\",\n                        \"typeString\": \"enum FetchOracle.FeeCurrency\"\n                      }\n                    },\n                    \"src\": \"9759:31:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_bool\",\n                      \"typeString\": \"bool\"\n                    }\n                  },\n                  \"falseBody\": {\n                    \"condition\": {\n                      \"argumentTypes\": null,\n                      \"commonType\": {\n                        \"typeIdentifier\": \"t_enum$_FeeCurrency_$827\",\n                        \"typeString\": \"enum FetchOracle.FeeCurrency\"\n                      },\n                      \"id\": 1356,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"leftExpression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 1353,\n                        \"name\": \"_feeCurrency\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 887,\n                        \"src\": \"10418:12:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_enum$_FeeCurrency_$827\",\n                          \"typeString\": \"enum FetchOracle.FeeCurrency\"\n                        }\n                      },\n                      \"nodeType\": \"BinaryOperation\",\n                      \"operator\": \"==\",\n                      \"rightExpression\": {\n                        \"argumentTypes\": null,\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 1354,\n                          \"name\": \"FeeCurrency\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 827,\n                          \"src\": \"10434:11:4\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_type$_t_enum$_FeeCurrency_$827_$\",\n                            \"typeString\": \"type(enum FetchOracle.FeeCurrency)\"\n                          }\n                        },\n                        \"id\": 1355,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": true,\n                        \"lValueRequested\": false,\n                        \"memberName\": \"ERC20\",\n                        \"nodeType\": \"MemberAccess\",\n                        \"referencedDeclaration\": null,\n                        \"src\": \"10434:17:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_enum$_FeeCurrency_$827\",\n                          \"typeString\": \"enum FetchOracle.FeeCurrency\"\n                        }\n                      },\n                      \"src\": \"10418:33:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_bool\",\n                        \"typeString\": \"bool\"\n                      }\n                    },\n                    \"falseBody\": {\n                      \"id\": 1377,\n                      \"nodeType\": \"Block\",\n                      \"src\": \"10605:75:4\",\n                      \"statements\": [\n                        {\n                          \"expression\": {\n                            \"argumentTypes\": null,\n                            \"arguments\": [\n                              {\n                                \"argumentTypes\": null,\n                                \"hexValue\": \"66616c7365\",\n                                \"id\": 1373,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": true,\n                                \"kind\": \"bool\",\n                                \"lValueRequested\": false,\n                                \"nodeType\": \"Literal\",\n                                \"src\": \"10627:5:4\",\n                                \"subdenomination\": null,\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_bool\",\n                                  \"typeString\": \"bool\"\n                                },\n                                \"value\": \"false\"\n                              },\n                              {\n                                \"argumentTypes\": null,\n                                \"hexValue\": \"556e657870656374656420636f6e7472616374206665652063757272656e6379\",\n                                \"id\": 1374,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": true,\n                                \"kind\": \"string\",\n                                \"lValueRequested\": false,\n                                \"nodeType\": \"Literal\",\n                                \"src\": \"10634:34:4\",\n                                \"subdenomination\": null,\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_stringliteral_f131716b743e5ec47535766db932d6974cfad176c58ab32b82f54addc42de82c\",\n                                  \"typeString\": \"literal_string \\\"Unexpected contract fee currency\\\"\"\n                                },\n                                \"value\": \"Unexpected contract fee currency\"\n                              }\n                            ],\n                            \"expression\": {\n                              \"argumentTypes\": [\n                                {\n                                  \"typeIdentifier\": \"t_bool\",\n                                  \"typeString\": \"bool\"\n                                },\n                                {\n                                  \"typeIdentifier\": \"t_stringliteral_f131716b743e5ec47535766db932d6974cfad176c58ab32b82f54addc42de82c\",\n                                  \"typeString\": \"literal_string \\\"Unexpected contract fee currency\\\"\"\n                                }\n                              ],\n                              \"id\": 1372,\n                              \"name\": \"require\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [\n                                -18,\n                                -18\n                              ],\n                              \"referencedDeclaration\": -18,\n                              \"src\": \"10619:7:4\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$\",\n                                \"typeString\": \"function (bool,string memory) pure\"\n                              }\n                            },\n                            \"id\": 1375,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": false,\n                            \"kind\": \"functionCall\",\n                            \"lValueRequested\": false,\n                            \"names\": [],\n                            \"nodeType\": \"FunctionCall\",\n                            \"src\": \"10619:50:4\",\n                            \"tryCall\": false,\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_tuple$__$\",\n                              \"typeString\": \"tuple()\"\n                            }\n                          },\n                          \"id\": 1376,\n                          \"nodeType\": \"ExpressionStatement\",\n                          \"src\": \"10619:50:4\"\n                        }\n                      ]\n                    },\n                    \"id\": 1378,\n                    \"nodeType\": \"IfStatement\",\n                    \"src\": \"10414:266:4\",\n                    \"trueBody\": {\n                      \"id\": 1371,\n                      \"nodeType\": \"Block\",\n                      \"src\": \"10461:122:4\",\n                      \"statements\": [\n                        {\n                          \"expression\": {\n                            \"argumentTypes\": null,\n                            \"arguments\": [\n                              {\n                                \"argumentTypes\": null,\n                                \"arguments\": [\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"expression\": {\n                                      \"argumentTypes\": null,\n                                      \"id\": 1360,\n                                      \"name\": \"msg\",\n                                      \"nodeType\": \"Identifier\",\n                                      \"overloadedDeclarations\": [],\n                                      \"referencedDeclaration\": -15,\n                                      \"src\": \"10503:3:4\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_magic_message\",\n                                        \"typeString\": \"msg\"\n                                      }\n                                    },\n                                    \"id\": 1361,\n                                    \"isConstant\": false,\n                                    \"isLValue\": false,\n                                    \"isPure\": false,\n                                    \"lValueRequested\": false,\n                                    \"memberName\": \"sender\",\n                                    \"nodeType\": \"MemberAccess\",\n                                    \"referencedDeclaration\": null,\n                                    \"src\": \"10503:10:4\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_address_payable\",\n                                      \"typeString\": \"address payable\"\n                                    }\n                                  },\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"arguments\": [\n                                      {\n                                        \"argumentTypes\": null,\n                                        \"id\": 1364,\n                                        \"name\": \"this\",\n                                        \"nodeType\": \"Identifier\",\n                                        \"overloadedDeclarations\": [],\n                                        \"referencedDeclaration\": -28,\n                                        \"src\": \"10523:4:4\",\n                                        \"typeDescriptions\": {\n                                          \"typeIdentifier\": \"t_contract$_FetchOracle_$1440\",\n                                          \"typeString\": \"contract FetchOracle\"\n                                        }\n                                      }\n                                    ],\n                                    \"expression\": {\n                                      \"argumentTypes\": [\n                                        {\n                                          \"typeIdentifier\": \"t_contract$_FetchOracle_$1440\",\n                                          \"typeString\": \"contract FetchOracle\"\n                                        }\n                                      ],\n                                      \"id\": 1363,\n                                      \"isConstant\": false,\n                                      \"isLValue\": false,\n                                      \"isPure\": true,\n                                      \"lValueRequested\": false,\n                                      \"nodeType\": \"ElementaryTypeNameExpression\",\n                                      \"src\": \"10515:7:4\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_type$_t_address_$\",\n                                        \"typeString\": \"type(address)\"\n                                      },\n                                      \"typeName\": {\n                                        \"id\": 1362,\n                                        \"name\": \"address\",\n                                        \"nodeType\": \"ElementaryTypeName\",\n                                        \"src\": \"10515:7:4\",\n                                        \"typeDescriptions\": {\n                                          \"typeIdentifier\": null,\n                                          \"typeString\": null\n                                        }\n                                      }\n                                    },\n                                    \"id\": 1365,\n                                    \"isConstant\": false,\n                                    \"isLValue\": false,\n                                    \"isPure\": false,\n                                    \"kind\": \"typeConversion\",\n                                    \"lValueRequested\": false,\n                                    \"names\": [],\n                                    \"nodeType\": \"FunctionCall\",\n                                    \"src\": \"10515:13:4\",\n                                    \"tryCall\": false,\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_address\",\n                                      \"typeString\": \"address\"\n                                    }\n                                  },\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"id\": 1366,\n                                    \"name\": \"_fee\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 881,\n                                    \"src\": \"10530:4:4\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    }\n                                  }\n                                ],\n                                \"expression\": {\n                                  \"argumentTypes\": [\n                                    {\n                                      \"typeIdentifier\": \"t_address_payable\",\n                                      \"typeString\": \"address payable\"\n                                    },\n                                    {\n                                      \"typeIdentifier\": \"t_address\",\n                                      \"typeString\": \"address\"\n                                    },\n                                    {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    }\n                                  ],\n                                  \"expression\": {\n                                    \"argumentTypes\": null,\n                                    \"id\": 1358,\n                                    \"name\": \"_token\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 875,\n                                    \"src\": \"10483:6:4\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_contract$_IERC20_$2649\",\n                                      \"typeString\": \"contract IERC20\"\n                                    }\n                                  },\n                                  \"id\": 1359,\n                                  \"isConstant\": false,\n                                  \"isLValue\": false,\n                                  \"isPure\": false,\n                                  \"lValueRequested\": false,\n                                  \"memberName\": \"transferFrom\",\n                                  \"nodeType\": \"MemberAccess\",\n                                  \"referencedDeclaration\": 2630,\n                                  \"src\": \"10483:19:4\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_function_external_nonpayable$_t_address_$_t_address_$_t_uint256_$returns$_t_bool_$\",\n                                    \"typeString\": \"function (address,address,uint256) external returns (bool)\"\n                                  }\n                                },\n                                \"id\": 1367,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": false,\n                                \"kind\": \"functionCall\",\n                                \"lValueRequested\": false,\n                                \"names\": [],\n                                \"nodeType\": \"FunctionCall\",\n                                \"src\": \"10483:52:4\",\n                                \"tryCall\": false,\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_bool\",\n                                  \"typeString\": \"bool\"\n                                }\n                              },\n                              {\n                                \"argumentTypes\": null,\n                                \"hexValue\": \"496e7375662e2046455420616c6c6f772e206f6e2063616c6c65722061646472\",\n                                \"id\": 1368,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": true,\n                                \"kind\": \"string\",\n                                \"lValueRequested\": false,\n                                \"nodeType\": \"Literal\",\n                                \"src\": \"10537:34:4\",\n                                \"subdenomination\": null,\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_stringliteral_a65cdee615e67dbd2cf8397ad58720c2c52ee993f0d8f62cb315ac2d7f1f9f3f\",\n                                  \"typeString\": \"literal_string \\\"Insuf. FET allow. on caller addr\\\"\"\n                                },\n                                \"value\": \"Insuf. FET allow. on caller addr\"\n                              }\n                            ],\n                            \"expression\": {\n                              \"argumentTypes\": [\n                                {\n                                  \"typeIdentifier\": \"t_bool\",\n                                  \"typeString\": \"bool\"\n                                },\n                                {\n                                  \"typeIdentifier\": \"t_stringliteral_a65cdee615e67dbd2cf8397ad58720c2c52ee993f0d8f62cb315ac2d7f1f9f3f\",\n                                  \"typeString\": \"literal_string \\\"Insuf. FET allow. on caller addr\\\"\"\n                                }\n                              ],\n                              \"id\": 1357,\n                              \"name\": \"require\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [\n                                -18,\n                                -18\n                              ],\n                              \"referencedDeclaration\": -18,\n                              \"src\": \"10475:7:4\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$\",\n                                \"typeString\": \"function (bool,string memory) pure\"\n                              }\n                            },\n                            \"id\": 1369,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": false,\n                            \"kind\": \"functionCall\",\n                            \"lValueRequested\": false,\n                            \"names\": [],\n                            \"nodeType\": \"FunctionCall\",\n                            \"src\": \"10475:97:4\",\n                            \"tryCall\": false,\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_tuple$__$\",\n                              \"typeString\": \"tuple()\"\n                            }\n                          },\n                          \"id\": 1370,\n                          \"nodeType\": \"ExpressionStatement\",\n                          \"src\": \"10475:97:4\"\n                        }\n                      ]\n                    }\n                  },\n                  \"id\": 1379,\n                  \"nodeType\": \"IfStatement\",\n                  \"src\": \"9755:925:4\",\n                  \"trueBody\": {\n                    \"id\": 1352,\n                    \"nodeType\": \"Block\",\n                    \"src\": \"9800:600:4\",\n                    \"statements\": [\n                      {\n                        \"condition\": {\n                          \"argumentTypes\": null,\n                          \"commonType\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          },\n                          \"id\": 1325,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"leftExpression\": {\n                            \"argumentTypes\": null,\n                            \"expression\": {\n                              \"argumentTypes\": null,\n                              \"id\": 1322,\n                              \"name\": \"msg\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": -15,\n                              \"src\": \"9817:3:4\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_magic_message\",\n                                \"typeString\": \"msg\"\n                              }\n                            },\n                            \"id\": 1323,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": false,\n                            \"lValueRequested\": false,\n                            \"memberName\": \"value\",\n                            \"nodeType\": \"MemberAccess\",\n                            \"referencedDeclaration\": null,\n                            \"src\": \"9817:9:4\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"nodeType\": \"BinaryOperation\",\n                          \"operator\": \"==\",\n                          \"rightExpression\": {\n                            \"argumentTypes\": null,\n                            \"id\": 1324,\n                            \"name\": \"_fee\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 881,\n                            \"src\": \"9830:4:4\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"src\": \"9817:17:4\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_bool\",\n                            \"typeString\": \"bool\"\n                          }\n                        },\n                        \"falseBody\": {\n                          \"condition\": {\n                            \"argumentTypes\": null,\n                            \"commonType\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            },\n                            \"id\": 1330,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": false,\n                            \"lValueRequested\": false,\n                            \"leftExpression\": {\n                              \"argumentTypes\": null,\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"id\": 1327,\n                                \"name\": \"msg\",\n                                \"nodeType\": \"Identifier\",\n                                \"overloadedDeclarations\": [],\n                                \"referencedDeclaration\": -15,\n                                \"src\": \"10081:3:4\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_magic_message\",\n                                  \"typeString\": \"msg\"\n                                }\n                              },\n                              \"id\": 1328,\n                              \"isConstant\": false,\n                              \"isLValue\": false,\n                              \"isPure\": false,\n                              \"lValueRequested\": false,\n                              \"memberName\": \"value\",\n                              \"nodeType\": \"MemberAccess\",\n                              \"referencedDeclaration\": null,\n                              \"src\": \"10081:9:4\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_uint256\",\n                                \"typeString\": \"uint256\"\n                              }\n                            },\n                            \"nodeType\": \"BinaryOperation\",\n                            \"operator\": \">\",\n                            \"rightExpression\": {\n                              \"argumentTypes\": null,\n                              \"id\": 1329,\n                              \"name\": \"_fee\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 881,\n                              \"src\": \"10093:4:4\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_uint256\",\n                                \"typeString\": \"uint256\"\n                              }\n                            },\n                            \"src\": \"10081:16:4\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_bool\",\n                              \"typeString\": \"bool\"\n                            }\n                          },\n                          \"falseBody\": {\n                            \"id\": 1349,\n                            \"nodeType\": \"Block\",\n                            \"src\": \"10309:81:4\",\n                            \"statements\": [\n                              {\n                                \"expression\": {\n                                  \"argumentTypes\": null,\n                                  \"arguments\": [\n                                    {\n                                      \"argumentTypes\": null,\n                                      \"hexValue\": \"66616c7365\",\n                                      \"id\": 1345,\n                                      \"isConstant\": false,\n                                      \"isLValue\": false,\n                                      \"isPure\": true,\n                                      \"kind\": \"bool\",\n                                      \"lValueRequested\": false,\n                                      \"nodeType\": \"Literal\",\n                                      \"src\": \"10334:5:4\",\n                                      \"subdenomination\": null,\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_bool\",\n                                        \"typeString\": \"bool\"\n                                      },\n                                      \"value\": \"false\"\n                                    },\n                                    {\n                                      \"argumentTypes\": null,\n                                      \"hexValue\": \"496e7375662e2045544820616d6f756e742073656e742062792063616c6c6572\",\n                                      \"id\": 1346,\n                                      \"isConstant\": false,\n                                      \"isLValue\": false,\n                                      \"isPure\": true,\n                                      \"kind\": \"string\",\n                                      \"lValueRequested\": false,\n                                      \"nodeType\": \"Literal\",\n                                      \"src\": \"10341:34:4\",\n                                      \"subdenomination\": null,\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_stringliteral_cb0058c10826e687d07067bad869c8c10a79c4914786ac0532f9d46b4ce50fc7\",\n                                        \"typeString\": \"literal_string \\\"Insuf. ETH amount sent by caller\\\"\"\n                                      },\n                                      \"value\": \"Insuf. ETH amount sent by caller\"\n                                    }\n                                  ],\n                                  \"expression\": {\n                                    \"argumentTypes\": [\n                                      {\n                                        \"typeIdentifier\": \"t_bool\",\n                                        \"typeString\": \"bool\"\n                                      },\n                                      {\n                                        \"typeIdentifier\": \"t_stringliteral_cb0058c10826e687d07067bad869c8c10a79c4914786ac0532f9d46b4ce50fc7\",\n                                        \"typeString\": \"literal_string \\\"Insuf. ETH amount sent by caller\\\"\"\n                                      }\n                                    ],\n                                    \"id\": 1344,\n                                    \"name\": \"require\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [\n                                      -18,\n                                      -18\n                                    ],\n                                    \"referencedDeclaration\": -18,\n                                    \"src\": \"10326:7:4\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$\",\n                                      \"typeString\": \"function (bool,string memory) pure\"\n                                    }\n                                  },\n                                  \"id\": 1347,\n                                  \"isConstant\": false,\n                                  \"isLValue\": false,\n                                  \"isPure\": false,\n                                  \"kind\": \"functionCall\",\n                                  \"lValueRequested\": false,\n                                  \"names\": [],\n                                  \"nodeType\": \"FunctionCall\",\n                                  \"src\": \"10326:50:4\",\n                                  \"tryCall\": false,\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_tuple$__$\",\n                                    \"typeString\": \"tuple()\"\n                                  }\n                                },\n                                \"id\": 1348,\n                                \"nodeType\": \"ExpressionStatement\",\n                                \"src\": \"10326:50:4\"\n                              }\n                            ]\n                          },\n                          \"id\": 1350,\n                          \"nodeType\": \"IfStatement\",\n                          \"src\": \"10077:313:4\",\n                          \"trueBody\": {\n                            \"id\": 1343,\n                            \"nodeType\": \"Block\",\n                            \"src\": \"10110:171:4\",\n                            \"statements\": [\n                              {\n                                \"expression\": {\n                                  \"argumentTypes\": null,\n                                  \"arguments\": [\n                                    {\n                                      \"argumentTypes\": null,\n                                      \"arguments\": [\n                                        {\n                                          \"argumentTypes\": null,\n                                          \"id\": 1339,\n                                          \"name\": \"_fee\",\n                                          \"nodeType\": \"Identifier\",\n                                          \"overloadedDeclarations\": [],\n                                          \"referencedDeclaration\": 881,\n                                          \"src\": \"10261:4:4\",\n                                          \"typeDescriptions\": {\n                                            \"typeIdentifier\": \"t_uint256\",\n                                            \"typeString\": \"uint256\"\n                                          }\n                                        }\n                                      ],\n                                      \"expression\": {\n                                        \"argumentTypes\": [\n                                          {\n                                            \"typeIdentifier\": \"t_uint256\",\n                                            \"typeString\": \"uint256\"\n                                          }\n                                        ],\n                                        \"expression\": {\n                                          \"argumentTypes\": null,\n                                          \"expression\": {\n                                            \"argumentTypes\": null,\n                                            \"id\": 1336,\n                                            \"name\": \"msg\",\n                                            \"nodeType\": \"Identifier\",\n                                            \"overloadedDeclarations\": [],\n                                            \"referencedDeclaration\": -15,\n                                            \"src\": \"10247:3:4\",\n                                            \"typeDescriptions\": {\n                                              \"typeIdentifier\": \"t_magic_message\",\n                                              \"typeString\": \"msg\"\n                                            }\n                                          },\n                                          \"id\": 1337,\n                                          \"isConstant\": false,\n                                          \"isLValue\": false,\n                                          \"isPure\": false,\n                                          \"lValueRequested\": false,\n                                          \"memberName\": \"value\",\n                                          \"nodeType\": \"MemberAccess\",\n                                          \"referencedDeclaration\": null,\n                                          \"src\": \"10247:9:4\",\n                                          \"typeDescriptions\": {\n                                            \"typeIdentifier\": \"t_uint256\",\n                                            \"typeString\": \"uint256\"\n                                          }\n                                        },\n                                        \"id\": 1338,\n                                        \"isConstant\": false,\n                                        \"isLValue\": false,\n                                        \"isPure\": false,\n                                        \"lValueRequested\": false,\n                                        \"memberName\": \"sub\",\n                                        \"nodeType\": \"MemberAccess\",\n                                        \"referencedDeclaration\": 1829,\n                                        \"src\": \"10247:13:4\",\n                                        \"typeDescriptions\": {\n                                          \"typeIdentifier\": \"t_function_internal_pure$_t_uint256_$_t_uint256_$returns$_t_uint256_$bound_to$_t_uint256_$\",\n                                          \"typeString\": \"function (uint256,uint256) pure returns (uint256)\"\n                                        }\n                                      },\n                                      \"id\": 1340,\n                                      \"isConstant\": false,\n                                      \"isLValue\": false,\n                                      \"isPure\": false,\n                                      \"kind\": \"functionCall\",\n                                      \"lValueRequested\": false,\n                                      \"names\": [],\n                                      \"nodeType\": \"FunctionCall\",\n                                      \"src\": \"10247:19:4\",\n                                      \"tryCall\": false,\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_uint256\",\n                                        \"typeString\": \"uint256\"\n                                      }\n                                    }\n                                  ],\n                                  \"expression\": {\n                                    \"argumentTypes\": [\n                                      {\n                                        \"typeIdentifier\": \"t_uint256\",\n                                        \"typeString\": \"uint256\"\n                                      }\n                                    ],\n                                    \"expression\": {\n                                      \"argumentTypes\": null,\n                                      \"expression\": {\n                                        \"argumentTypes\": null,\n                                        \"id\": 1331,\n                                        \"name\": \"msg\",\n                                        \"nodeType\": \"Identifier\",\n                                        \"overloadedDeclarations\": [],\n                                        \"referencedDeclaration\": -15,\n                                        \"src\": \"10227:3:4\",\n                                        \"typeDescriptions\": {\n                                          \"typeIdentifier\": \"t_magic_message\",\n                                          \"typeString\": \"msg\"\n                                        }\n                                      },\n                                      \"id\": 1334,\n                                      \"isConstant\": false,\n                                      \"isLValue\": false,\n                                      \"isPure\": false,\n                                      \"lValueRequested\": false,\n                                      \"memberName\": \"sender\",\n                                      \"nodeType\": \"MemberAccess\",\n                                      \"referencedDeclaration\": null,\n                                      \"src\": \"10227:10:4\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_address_payable\",\n                                        \"typeString\": \"address payable\"\n                                      }\n                                    },\n                                    \"id\": 1335,\n                                    \"isConstant\": false,\n                                    \"isLValue\": false,\n                                    \"isPure\": false,\n                                    \"lValueRequested\": false,\n                                    \"memberName\": \"transfer\",\n                                    \"nodeType\": \"MemberAccess\",\n                                    \"referencedDeclaration\": null,\n                                    \"src\": \"10227:19:4\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_function_transfer_nonpayable$_t_uint256_$returns$__$\",\n                                      \"typeString\": \"function (uint256)\"\n                                    }\n                                  },\n                                  \"id\": 1341,\n                                  \"isConstant\": false,\n                                  \"isLValue\": false,\n                                  \"isPure\": false,\n                                  \"kind\": \"functionCall\",\n                                  \"lValueRequested\": false,\n                                  \"names\": [],\n                                  \"nodeType\": \"FunctionCall\",\n                                  \"src\": \"10227:40:4\",\n                                  \"tryCall\": false,\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_tuple$__$\",\n                                    \"typeString\": \"tuple()\"\n                                  }\n                                },\n                                \"id\": 1342,\n                                \"nodeType\": \"ExpressionStatement\",\n                                \"src\": \"10227:40:4\"\n                              }\n                            ]\n                          }\n                        },\n                        \"id\": 1351,\n                        \"nodeType\": \"IfStatement\",\n                        \"src\": \"9813:577:4\",\n                        \"trueBody\": {\n                          \"id\": 1326,\n                          \"nodeType\": \"Block\",\n                          \"src\": \"9847:213:4\",\n                          \"statements\": []\n                        }\n                      }\n                    ]\n                  }\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 1385,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 1380,\n                      \"name\": \"_accruedFeesAmount\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 883,\n                      \"src\": \"10690:18:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"arguments\": [\n                        {\n                          \"argumentTypes\": null,\n                          \"id\": 1383,\n                          \"name\": \"_fee\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 881,\n                          \"src\": \"10734:4:4\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        }\n                      ],\n                      \"expression\": {\n                        \"argumentTypes\": [\n                          {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        ],\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 1381,\n                          \"name\": \"_accruedFeesAmount\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 883,\n                          \"src\": \"10711:18:4\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"id\": 1382,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"memberName\": \"add\",\n                        \"nodeType\": \"MemberAccess\",\n                        \"referencedDeclaration\": 1812,\n                        \"src\": \"10711:22:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_function_internal_pure$_t_uint256_$_t_uint256_$returns$_t_uint256_$bound_to$_t_uint256_$\",\n                          \"typeString\": \"function (uint256,uint256) pure returns (uint256)\"\n                        }\n                      },\n                      \"id\": 1384,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": false,\n                      \"kind\": \"functionCall\",\n                      \"lValueRequested\": false,\n                      \"names\": [],\n                      \"nodeType\": \"FunctionCall\",\n                      \"src\": \"10711:28:4\",\n                      \"tryCall\": false,\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"src\": \"10690:49:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"id\": 1386,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"10690:49:4\"\n                }\n              ]\n            },\n            \"documentation\": {\n              \"id\": 1315,\n              \"nodeType\": \"StructuredDocumentation\",\n              \"src\": \"9650:53:4\",\n              \"text\": \"@dev Withdraw fee from the caller.\"\n            },\n            \"id\": 1388,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [],\n            \"name\": \"_withdrawFee\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 1316,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"9729:2:4\"\n            },\n            \"returnParameters\": {\n              \"id\": 1317,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"9745:0:4\"\n            },\n            \"scope\": 1440,\n            \"src\": \"9708:1038:4\",\n            \"stateMutability\": \"nonpayable\",\n            \"virtual\": false,\n            \"visibility\": \"internal\"\n          },\n          {\n            \"body\": {\n              \"id\": 1438,\n              \"nodeType\": \"Block\",\n              \"src\": \"10844:699:4\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"commonType\": {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        },\n                        \"id\": 1401,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"leftExpression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 1396,\n                          \"name\": \"targetAddress\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 1390,\n                          \"src\": \"10862:13:4\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_address_payable\",\n                            \"typeString\": \"address payable\"\n                          }\n                        },\n                        \"nodeType\": \"BinaryOperation\",\n                        \"operator\": \"!=\",\n                        \"rightExpression\": {\n                          \"argumentTypes\": null,\n                          \"arguments\": [\n                            {\n                              \"argumentTypes\": null,\n                              \"hexValue\": \"30\",\n                              \"id\": 1399,\n                              \"isConstant\": false,\n                              \"isLValue\": false,\n                              \"isPure\": true,\n                              \"kind\": \"number\",\n                              \"lValueRequested\": false,\n                              \"nodeType\": \"Literal\",\n                              \"src\": \"10887:1:4\",\n                              \"subdenomination\": null,\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_rational_0_by_1\",\n                                \"typeString\": \"int_const 0\"\n                              },\n                              \"value\": \"0\"\n                            }\n                          ],\n                          \"expression\": {\n                            \"argumentTypes\": [\n                              {\n                                \"typeIdentifier\": \"t_rational_0_by_1\",\n                                \"typeString\": \"int_const 0\"\n                              }\n                            ],\n                            \"id\": 1398,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": true,\n                            \"lValueRequested\": false,\n                            \"nodeType\": \"ElementaryTypeNameExpression\",\n                            \"src\": \"10879:7:4\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_type$_t_address_$\",\n                              \"typeString\": \"type(address)\"\n                            },\n                            \"typeName\": {\n                              \"id\": 1397,\n                              \"name\": \"address\",\n                              \"nodeType\": \"ElementaryTypeName\",\n                              \"src\": \"10879:7:4\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": null,\n                                \"typeString\": null\n                              }\n                            }\n                          },\n                          \"id\": 1400,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": true,\n                          \"kind\": \"typeConversion\",\n                          \"lValueRequested\": false,\n                          \"names\": [],\n                          \"nodeType\": \"FunctionCall\",\n                          \"src\": \"10879:10:4\",\n                          \"tryCall\": false,\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_address_payable\",\n                            \"typeString\": \"address payable\"\n                          }\n                        },\n                        \"src\": \"10862:27:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"hexValue\": \"546172676574206973207a65726f2061646472657373\",\n                        \"id\": 1402,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": true,\n                        \"kind\": \"string\",\n                        \"lValueRequested\": false,\n                        \"nodeType\": \"Literal\",\n                        \"src\": \"10891:24:4\",\n                        \"subdenomination\": null,\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_stringliteral_cccbd8782d968807cd85c549e83adb6604b8463e9d07bb08e05c43c68c493c61\",\n                          \"typeString\": \"literal_string \\\"Target is zero address\\\"\"\n                        },\n                        \"value\": \"Target is zero address\"\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_stringliteral_cccbd8782d968807cd85c549e83adb6604b8463e9d07bb08e05c43c68c493c61\",\n                          \"typeString\": \"literal_string \\\"Target is zero address\\\"\"\n                        }\n                      ],\n                      \"id\": 1395,\n                      \"name\": \"require\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [\n                        -18,\n                        -18\n                      ],\n                      \"referencedDeclaration\": -18,\n                      \"src\": \"10854:7:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$\",\n                        \"typeString\": \"function (bool,string memory) pure\"\n                      }\n                    },\n                    \"id\": 1403,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"10854:62:4\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 1404,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"10854:62:4\"\n                },\n                {\n                  \"condition\": {\n                    \"argumentTypes\": null,\n                    \"commonType\": {\n                      \"typeIdentifier\": \"t_enum$_FeeCurrency_$827\",\n                      \"typeString\": \"enum FetchOracle.FeeCurrency\"\n                    },\n                    \"id\": 1408,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftExpression\": {\n                      \"argumentTypes\": null,\n                      \"id\": 1405,\n                      \"name\": \"_feeCurrency\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 887,\n                      \"src\": \"10931:12:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_enum$_FeeCurrency_$827\",\n                        \"typeString\": \"enum FetchOracle.FeeCurrency\"\n                      }\n                    },\n                    \"nodeType\": \"BinaryOperation\",\n                    \"operator\": \"==\",\n                    \"rightExpression\": {\n                      \"argumentTypes\": null,\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 1406,\n                        \"name\": \"FeeCurrency\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 827,\n                        \"src\": \"10947:11:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_type$_t_enum$_FeeCurrency_$827_$\",\n                          \"typeString\": \"type(enum FetchOracle.FeeCurrency)\"\n                        }\n                      },\n                      \"id\": 1407,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": true,\n                      \"lValueRequested\": false,\n                      \"memberName\": \"ETH\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": null,\n                      \"src\": \"10947:15:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_enum$_FeeCurrency_$827\",\n                        \"typeString\": \"enum FetchOracle.FeeCurrency\"\n                      }\n                    },\n                    \"src\": \"10931:31:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_bool\",\n                      \"typeString\": \"bool\"\n                    }\n                  },\n                  \"falseBody\": {\n                    \"condition\": {\n                      \"argumentTypes\": null,\n                      \"commonType\": {\n                        \"typeIdentifier\": \"t_enum$_FeeCurrency_$827\",\n                        \"typeString\": \"enum FetchOracle.FeeCurrency\"\n                      },\n                      \"id\": 1419,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"leftExpression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 1416,\n                        \"name\": \"_feeCurrency\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 887,\n                        \"src\": \"11167:12:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_enum$_FeeCurrency_$827\",\n                          \"typeString\": \"enum FetchOracle.FeeCurrency\"\n                        }\n                      },\n                      \"nodeType\": \"BinaryOperation\",\n                      \"operator\": \"==\",\n                      \"rightExpression\": {\n                        \"argumentTypes\": null,\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 1417,\n                          \"name\": \"FeeCurrency\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 827,\n                          \"src\": \"11183:11:4\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_type$_t_enum$_FeeCurrency_$827_$\",\n                            \"typeString\": \"type(enum FetchOracle.FeeCurrency)\"\n                          }\n                        },\n                        \"id\": 1418,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": true,\n                        \"lValueRequested\": false,\n                        \"memberName\": \"ERC20\",\n                        \"nodeType\": \"MemberAccess\",\n                        \"referencedDeclaration\": null,\n                        \"src\": \"11183:17:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_enum$_FeeCurrency_$827\",\n                          \"typeString\": \"enum FetchOracle.FeeCurrency\"\n                        }\n                      },\n                      \"src\": \"11167:33:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_bool\",\n                        \"typeString\": \"bool\"\n                      }\n                    },\n                    \"falseBody\": {\n                      \"id\": 1435,\n                      \"nodeType\": \"Block\",\n                      \"src\": \"11462:75:4\",\n                      \"statements\": [\n                        {\n                          \"expression\": {\n                            \"argumentTypes\": null,\n                            \"arguments\": [\n                              {\n                                \"argumentTypes\": null,\n                                \"hexValue\": \"66616c7365\",\n                                \"id\": 1431,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": true,\n                                \"kind\": \"bool\",\n                                \"lValueRequested\": false,\n                                \"nodeType\": \"Literal\",\n                                \"src\": \"11484:5:4\",\n                                \"subdenomination\": null,\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_bool\",\n                                  \"typeString\": \"bool\"\n                                },\n                                \"value\": \"false\"\n                              },\n                              {\n                                \"argumentTypes\": null,\n                                \"hexValue\": \"556e657870656374656420636f6e7472616374206665652063757272656e6379\",\n                                \"id\": 1432,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": true,\n                                \"kind\": \"string\",\n                                \"lValueRequested\": false,\n                                \"nodeType\": \"Literal\",\n                                \"src\": \"11491:34:4\",\n                                \"subdenomination\": null,\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_stringliteral_f131716b743e5ec47535766db932d6974cfad176c58ab32b82f54addc42de82c\",\n                                  \"typeString\": \"literal_string \\\"Unexpected contract fee currency\\\"\"\n                                },\n                                \"value\": \"Unexpected contract fee currency\"\n                              }\n                            ],\n                            \"expression\": {\n                              \"argumentTypes\": [\n                                {\n                                  \"typeIdentifier\": \"t_bool\",\n                                  \"typeString\": \"bool\"\n                                },\n                                {\n                                  \"typeIdentifier\": \"t_stringliteral_f131716b743e5ec47535766db932d6974cfad176c58ab32b82f54addc42de82c\",\n                                  \"typeString\": \"literal_string \\\"Unexpected contract fee currency\\\"\"\n                                }\n                              ],\n                              \"id\": 1430,\n                              \"name\": \"require\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [\n                                -18,\n                                -18\n                              ],\n                              \"referencedDeclaration\": -18,\n                              \"src\": \"11476:7:4\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$\",\n                                \"typeString\": \"function (bool,string memory) pure\"\n                              }\n                            },\n                            \"id\": 1433,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": false,\n                            \"kind\": \"functionCall\",\n                            \"lValueRequested\": false,\n                            \"names\": [],\n                            \"nodeType\": \"FunctionCall\",\n                            \"src\": \"11476:50:4\",\n                            \"tryCall\": false,\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_tuple$__$\",\n                              \"typeString\": \"tuple()\"\n                            }\n                          },\n                          \"id\": 1434,\n                          \"nodeType\": \"ExpressionStatement\",\n                          \"src\": \"11476:50:4\"\n                        }\n                      ]\n                    },\n                    \"id\": 1436,\n                    \"nodeType\": \"IfStatement\",\n                    \"src\": \"11163:374:4\",\n                    \"trueBody\": {\n                      \"id\": 1429,\n                      \"nodeType\": \"Block\",\n                      \"src\": \"11210:230:4\",\n                      \"statements\": [\n                        {\n                          \"expression\": {\n                            \"argumentTypes\": null,\n                            \"arguments\": [\n                              {\n                                \"argumentTypes\": null,\n                                \"arguments\": [\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"id\": 1423,\n                                    \"name\": \"targetAddress\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 1390,\n                                    \"src\": \"11370:13:4\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_address_payable\",\n                                      \"typeString\": \"address payable\"\n                                    }\n                                  },\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"id\": 1424,\n                                    \"name\": \"amount\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 1392,\n                                    \"src\": \"11385:6:4\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    }\n                                  }\n                                ],\n                                \"expression\": {\n                                  \"argumentTypes\": [\n                                    {\n                                      \"typeIdentifier\": \"t_address_payable\",\n                                      \"typeString\": \"address payable\"\n                                    },\n                                    {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    }\n                                  ],\n                                  \"expression\": {\n                                    \"argumentTypes\": null,\n                                    \"id\": 1421,\n                                    \"name\": \"_token\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 875,\n                                    \"src\": \"11354:6:4\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_contract$_IERC20_$2649\",\n                                      \"typeString\": \"contract IERC20\"\n                                    }\n                                  },\n                                  \"id\": 1422,\n                                  \"isConstant\": false,\n                                  \"isLValue\": false,\n                                  \"isPure\": false,\n                                  \"lValueRequested\": false,\n                                  \"memberName\": \"transfer\",\n                                  \"nodeType\": \"MemberAccess\",\n                                  \"referencedDeclaration\": 2598,\n                                  \"src\": \"11354:15:4\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_function_external_nonpayable$_t_address_$_t_uint256_$returns$_t_bool_$\",\n                                    \"typeString\": \"function (address,uint256) external returns (bool)\"\n                                  }\n                                },\n                                \"id\": 1425,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": false,\n                                \"kind\": \"functionCall\",\n                                \"lValueRequested\": false,\n                                \"names\": [],\n                                \"nodeType\": \"FunctionCall\",\n                                \"src\": \"11354:38:4\",\n                                \"tryCall\": false,\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_bool\",\n                                  \"typeString\": \"bool\"\n                                }\n                              },\n                              {\n                                \"argumentTypes\": null,\n                                \"hexValue\": \"496e737566662e204645542066756e6473206f6e20636f6e74722e2061646472\",\n                                \"id\": 1426,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": true,\n                                \"kind\": \"string\",\n                                \"lValueRequested\": false,\n                                \"nodeType\": \"Literal\",\n                                \"src\": \"11394:34:4\",\n                                \"subdenomination\": null,\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_stringliteral_ac4273e35d12186f8e3dd3c3e48a2a5436d20bacdfa1045742d7a790fa7c7376\",\n                                  \"typeString\": \"literal_string \\\"Insuff. FET funds on contr. addr\\\"\"\n                                },\n                                \"value\": \"Insuff. FET funds on contr. addr\"\n                              }\n                            ],\n                            \"expression\": {\n                              \"argumentTypes\": [\n                                {\n                                  \"typeIdentifier\": \"t_bool\",\n                                  \"typeString\": \"bool\"\n                                },\n                                {\n                                  \"typeIdentifier\": \"t_stringliteral_ac4273e35d12186f8e3dd3c3e48a2a5436d20bacdfa1045742d7a790fa7c7376\",\n                                  \"typeString\": \"literal_string \\\"Insuff. FET funds on contr. addr\\\"\"\n                                }\n                              ],\n                              \"id\": 1420,\n                              \"name\": \"require\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [\n                                -18,\n                                -18\n                              ],\n                              \"referencedDeclaration\": -18,\n                              \"src\": \"11346:7:4\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$\",\n                                \"typeString\": \"function (bool,string memory) pure\"\n                              }\n                            },\n                            \"id\": 1427,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": false,\n                            \"kind\": \"functionCall\",\n                            \"lValueRequested\": false,\n                            \"names\": [],\n                            \"nodeType\": \"FunctionCall\",\n                            \"src\": \"11346:83:4\",\n                            \"tryCall\": false,\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_tuple$__$\",\n                              \"typeString\": \"tuple()\"\n                            }\n                          },\n                          \"id\": 1428,\n                          \"nodeType\": \"ExpressionStatement\",\n                          \"src\": \"11346:83:4\"\n                        }\n                      ]\n                    }\n                  },\n                  \"id\": 1437,\n                  \"nodeType\": \"IfStatement\",\n                  \"src\": \"10927:610:4\",\n                  \"trueBody\": {\n                    \"id\": 1415,\n                    \"nodeType\": \"Block\",\n                    \"src\": \"10972:177:4\",\n                    \"statements\": [\n                      {\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"arguments\": [\n                            {\n                              \"argumentTypes\": null,\n                              \"id\": 1412,\n                              \"name\": \"amount\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 1392,\n                              \"src\": \"11131:6:4\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_uint256\",\n                                \"typeString\": \"uint256\"\n                              }\n                            }\n                          ],\n                          \"expression\": {\n                            \"argumentTypes\": [\n                              {\n                                \"typeIdentifier\": \"t_uint256\",\n                                \"typeString\": \"uint256\"\n                              }\n                            ],\n                            \"expression\": {\n                              \"argumentTypes\": null,\n                              \"id\": 1409,\n                              \"name\": \"targetAddress\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 1390,\n                              \"src\": \"11108:13:4\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_address_payable\",\n                                \"typeString\": \"address payable\"\n                              }\n                            },\n                            \"id\": 1411,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": false,\n                            \"lValueRequested\": false,\n                            \"memberName\": \"transfer\",\n                            \"nodeType\": \"MemberAccess\",\n                            \"referencedDeclaration\": null,\n                            \"src\": \"11108:22:4\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_function_transfer_nonpayable$_t_uint256_$returns$__$\",\n                              \"typeString\": \"function (uint256)\"\n                            }\n                          },\n                          \"id\": 1413,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"kind\": \"functionCall\",\n                          \"lValueRequested\": false,\n                          \"names\": [],\n                          \"nodeType\": \"FunctionCall\",\n                          \"src\": \"11108:30:4\",\n                          \"tryCall\": false,\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_tuple$__$\",\n                            \"typeString\": \"tuple()\"\n                          }\n                        },\n                        \"id\": 1414,\n                        \"nodeType\": \"ExpressionStatement\",\n                        \"src\": \"11108:30:4\"\n                      }\n                    ]\n                  }\n                }\n              ]\n            },\n            \"documentation\": null,\n            \"id\": 1439,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [],\n            \"name\": \"_withdrawFromContract\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 1393,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 1390,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"targetAddress\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 1439,\n                  \"src\": \"10784:29:4\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_address_payable\",\n                    \"typeString\": \"address payable\"\n                  },\n                  \"typeName\": {\n                    \"id\": 1389,\n                    \"name\": \"address\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"10784:15:4\",\n                    \"stateMutability\": \"payable\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address_payable\",\n                      \"typeString\": \"address payable\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 1392,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"amount\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 1439,\n                  \"src\": \"10815:14:4\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 1391,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"10815:7:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"10783:47:4\"\n            },\n            \"returnParameters\": {\n              \"id\": 1394,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"10844:0:4\"\n            },\n            \"scope\": 1440,\n            \"src\": \"10753:790:4\",\n            \"stateMutability\": \"nonpayable\",\n            \"virtual\": false,\n            \"visibility\": \"internal\"\n          }\n        ],\n        \"scope\": 1441,\n        \"src\": \"1550:9995:4\"\n      }\n    ],\n    \"src\": \"820:10726:4\"\n  },\n  \"legacyAST\": {\n    \"absolutePath\": \"/home/james/Code/cosmos-drb-oracle/ethereum/contracts/FetchOracle.sol\",\n    \"exportedSymbols\": {\n      \"FetchOracle\": [\n        1440\n      ]\n    },\n    \"id\": 1441,\n    \"license\": \"Apache-2.0\",\n    \"nodeType\": \"SourceUnit\",\n    \"nodes\": [\n      {\n        \"id\": 815,\n        \"literals\": [\n          \"solidity\",\n          \"^\",\n          \"0.6\",\n          \".0\"\n        ],\n        \"nodeType\": \"PragmaDirective\",\n        \"src\": \"820:23:4\"\n      },\n      {\n        \"absolutePath\": \"/home/james/Code/cosmos-drb-oracle/ethereum/openzeppelin/contracts/token/ERC20/IERC20.sol\",\n        \"file\": \"../openzeppelin/contracts/token/ERC20/IERC20.sol\",\n        \"id\": 816,\n        \"nodeType\": \"ImportDirective\",\n        \"scope\": 1441,\n        \"sourceUnit\": 2650,\n        \"src\": \"845:58:4\",\n        \"symbolAliases\": [],\n        \"unitAlias\": \"\"\n      },\n      {\n        \"absolutePath\": \"/home/james/Code/cosmos-drb-oracle/ethereum/openzeppelin/contracts/access/AccessControl.sol\",\n        \"file\": \"../openzeppelin/contracts/access/AccessControl.sol\",\n        \"id\": 817,\n        \"nodeType\": \"ImportDirective\",\n        \"scope\": 1441,\n        \"sourceUnit\": 1784,\n        \"src\": \"904:60:4\",\n        \"symbolAliases\": [],\n        \"unitAlias\": \"\"\n      },\n      {\n        \"absolutePath\": \"/home/james/Code/cosmos-drb-oracle/ethereum/openzeppelin/contracts/math/SafeMath.sol\",\n        \"file\": \"../openzeppelin/contracts/math/SafeMath.sol\",\n        \"id\": 818,\n        \"nodeType\": \"ImportDirective\",\n        \"scope\": 1441,\n        \"sourceUnit\": 1980,\n        \"src\": \"965:53:4\",\n        \"symbolAliases\": [],\n        \"unitAlias\": \"\"\n      },\n      {\n        \"abstract\": false,\n        \"baseContracts\": [\n          {\n            \"arguments\": null,\n            \"baseName\": {\n              \"contractScope\": null,\n              \"id\": 820,\n              \"name\": \"AccessControl\",\n              \"nodeType\": \"UserDefinedTypeName\",\n              \"referencedDeclaration\": 1783,\n              \"src\": \"1574:13:4\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_contract$_AccessControl_$1783\",\n                \"typeString\": \"contract AccessControl\"\n              }\n            },\n            \"id\": 821,\n            \"nodeType\": \"InheritanceSpecifier\",\n            \"src\": \"1574:13:4\"\n          }\n        ],\n        \"contractDependencies\": [\n          1500,\n          1783\n        ],\n        \"contractKind\": \"contract\",\n        \"documentation\": {\n          \"id\": 819,\n          \"nodeType\": \"StructuredDocumentation\",\n          \"src\": \"1021:528:4\",\n          \"text\": \"@dev The contract *INTENTIONALLY* does not contain the `receive()` or fallback functions in order to ensure that all\\nunsolicited direct ETH transfers in to this contract (in direct Transaction) will fail.\\nOnly way how to make successful fee transfer in ETH currency (*IF* contract is initialised for ETH as fee currency),\\nis to make transfer ETH to caller(client) contract and client contract then is responsible for further\\nrogrammatic* (= *not* via Tx) transfer of fee to this this contract.\"\n        },\n        \"fullyImplemented\": true,\n        \"id\": 1440,\n        \"linearizedBaseContracts\": [\n          1440,\n          1783,\n          1500\n        ],\n        \"name\": \"FetchOracle\",\n        \"nodeType\": \"ContractDefinition\",\n        \"nodes\": [\n          {\n            \"id\": 824,\n            \"libraryName\": {\n              \"contractScope\": null,\n              \"id\": 822,\n              \"name\": \"SafeMath\",\n              \"nodeType\": \"UserDefinedTypeName\",\n              \"referencedDeclaration\": 1979,\n              \"src\": \"1600:8:4\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_contract$_SafeMath_$1979\",\n                \"typeString\": \"library SafeMath\"\n              }\n            },\n            \"nodeType\": \"UsingForDirective\",\n            \"src\": \"1594:27:4\",\n            \"typeName\": {\n              \"id\": 823,\n              \"name\": \"uint256\",\n              \"nodeType\": \"ElementaryTypeName\",\n              \"src\": \"1613:7:4\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_uint256\",\n                \"typeString\": \"uint256\"\n              }\n            }\n          },\n          {\n            \"canonicalName\": \"FetchOracle.FeeCurrency\",\n            \"id\": 827,\n            \"members\": [\n              {\n                \"id\": 825,\n                \"name\": \"ERC20\",\n                \"nodeType\": \"EnumValue\",\n                \"src\": \"1648:5:4\"\n              },\n              {\n                \"id\": 826,\n                \"name\": \"ETH\",\n                \"nodeType\": \"EnumValue\",\n                \"src\": \"1655:3:4\"\n              }\n            ],\n            \"name\": \"FeeCurrency\",\n            \"nodeType\": \"EnumDefinition\",\n            \"src\": \"1628:32:4\"\n          },\n          {\n            \"canonicalName\": \"FetchOracle.OracleValue\",\n            \"id\": 834,\n            \"members\": [\n              {\n                \"constant\": false,\n                \"id\": 829,\n                \"mutability\": \"mutable\",\n                \"name\": \"value\",\n                \"nodeType\": \"VariableDeclaration\",\n                \"overrides\": null,\n                \"scope\": 834,\n                \"src\": \"1695:13:4\",\n                \"stateVariable\": false,\n                \"storageLocation\": \"default\",\n                \"typeDescriptions\": {\n                  \"typeIdentifier\": \"t_uint256\",\n                  \"typeString\": \"uint256\"\n                },\n                \"typeName\": {\n                  \"id\": 828,\n                  \"name\": \"uint256\",\n                  \"nodeType\": \"ElementaryTypeName\",\n                  \"src\": \"1695:7:4\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  }\n                },\n                \"value\": null,\n                \"visibility\": \"internal\"\n              },\n              {\n                \"constant\": false,\n                \"id\": 831,\n                \"mutability\": \"mutable\",\n                \"name\": \"decimals\",\n                \"nodeType\": \"VariableDeclaration\",\n                \"overrides\": null,\n                \"scope\": 834,\n                \"src\": \"1718:14:4\",\n                \"stateVariable\": false,\n                \"storageLocation\": \"default\",\n                \"typeDescriptions\": {\n                  \"typeIdentifier\": \"t_uint8\",\n                  \"typeString\": \"uint8\"\n                },\n                \"typeName\": {\n                  \"id\": 830,\n                  \"name\": \"uint8\",\n                  \"nodeType\": \"ElementaryTypeName\",\n                  \"src\": \"1718:5:4\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint8\",\n                    \"typeString\": \"uint8\"\n                  }\n                },\n                \"value\": null,\n                \"visibility\": \"internal\"\n              },\n              {\n                \"constant\": false,\n                \"id\": 833,\n                \"mutability\": \"mutable\",\n                \"name\": \"updatedAtEthBlockNumber\",\n                \"nodeType\": \"VariableDeclaration\",\n                \"overrides\": null,\n                \"scope\": 834,\n                \"src\": \"1742:31:4\",\n                \"stateVariable\": false,\n                \"storageLocation\": \"default\",\n                \"typeDescriptions\": {\n                  \"typeIdentifier\": \"t_uint256\",\n                  \"typeString\": \"uint256\"\n                },\n                \"typeName\": {\n                  \"id\": 832,\n                  \"name\": \"uint256\",\n                  \"nodeType\": \"ElementaryTypeName\",\n                  \"src\": \"1742:7:4\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  }\n                },\n                \"value\": null,\n                \"visibility\": \"internal\"\n              }\n            ],\n            \"name\": \"OracleValue\",\n            \"nodeType\": \"StructDefinition\",\n            \"scope\": 1440,\n            \"src\": \"1666:114:4\",\n            \"visibility\": \"public\"\n          },\n          {\n            \"anonymous\": false,\n            \"documentation\": null,\n            \"id\": 838,\n            \"name\": \"FeeUpdated\",\n            \"nodeType\": \"EventDefinition\",\n            \"parameters\": {\n              \"id\": 837,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 836,\n                  \"indexed\": false,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"fee\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 838,\n                  \"src\": \"1803:11:4\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 835,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"1803:7:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"1802:13:4\"\n            },\n            \"src\": \"1786:30:4\"\n          },\n          {\n            \"anonymous\": false,\n            \"documentation\": null,\n            \"id\": 842,\n            \"name\": \"Pause\",\n            \"nodeType\": \"EventDefinition\",\n            \"parameters\": {\n              \"id\": 841,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 840,\n                  \"indexed\": false,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"sinceBlock\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 842,\n                  \"src\": \"1833:18:4\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 839,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"1833:7:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"1832:20:4\"\n            },\n            \"src\": \"1821:32:4\"\n          },\n          {\n            \"anonymous\": false,\n            \"documentation\": null,\n            \"id\": 848,\n            \"name\": \"ExcessTokenWithdrawal\",\n            \"nodeType\": \"EventDefinition\",\n            \"parameters\": {\n              \"id\": 847,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 844,\n                  \"indexed\": false,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"targetAddress\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 848,\n                  \"src\": \"1886:21:4\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_address\",\n                    \"typeString\": \"address\"\n                  },\n                  \"typeName\": {\n                    \"id\": 843,\n                    \"name\": \"address\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"1886:7:4\",\n                    \"stateMutability\": \"nonpayable\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address\",\n                      \"typeString\": \"address\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 846,\n                  \"indexed\": false,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"amount\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 848,\n                  \"src\": \"1909:14:4\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 845,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"1909:7:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"1885:39:4\"\n            },\n            \"src\": \"1858:67:4\"\n          },\n          {\n            \"anonymous\": false,\n            \"documentation\": null,\n            \"id\": 854,\n            \"name\": \"AccruedFeesWithdrawal\",\n            \"nodeType\": \"EventDefinition\",\n            \"parameters\": {\n              \"id\": 853,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 850,\n                  \"indexed\": false,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"targetAddress\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 854,\n                  \"src\": \"1958:21:4\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_address\",\n                    \"typeString\": \"address\"\n                  },\n                  \"typeName\": {\n                    \"id\": 849,\n                    \"name\": \"address\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"1958:7:4\",\n                    \"stateMutability\": \"nonpayable\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address\",\n                      \"typeString\": \"address\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 852,\n                  \"indexed\": false,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"amount\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 854,\n                  \"src\": \"1981:14:4\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 851,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"1981:7:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"1957:39:4\"\n            },\n            \"src\": \"1930:67:4\"\n          },\n          {\n            \"anonymous\": false,\n            \"documentation\": null,\n            \"id\": 856,\n            \"name\": \"ContractDeleted\",\n            \"nodeType\": \"EventDefinition\",\n            \"parameters\": {\n              \"id\": 855,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"2023:2:4\"\n            },\n            \"src\": \"2002:24:4\"\n          },\n          {\n            \"anonymous\": false,\n            \"documentation\": null,\n            \"id\": 860,\n            \"name\": \"OracleValueUpdated\",\n            \"nodeType\": \"EventDefinition\",\n            \"parameters\": {\n              \"id\": 859,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 858,\n                  \"indexed\": false,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"atBlock\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 860,\n                  \"src\": \"2056:15:4\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 857,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"2056:7:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"2055:17:4\"\n            },\n            \"src\": \"2031:42:4\"\n          },\n          {\n            \"constant\": true,\n            \"functionSelector\": \"07e2cea5\",\n            \"id\": 865,\n            \"mutability\": \"constant\",\n            \"name\": \"ORACLE_ROLE\",\n            \"nodeType\": \"VariableDeclaration\",\n            \"overrides\": null,\n            \"scope\": 1440,\n            \"src\": \"2081:62:4\",\n            \"stateVariable\": true,\n            \"storageLocation\": \"default\",\n            \"typeDescriptions\": {\n              \"typeIdentifier\": \"t_bytes32\",\n              \"typeString\": \"bytes32\"\n            },\n            \"typeName\": {\n              \"id\": 861,\n              \"name\": \"bytes32\",\n              \"nodeType\": \"ElementaryTypeName\",\n              \"src\": \"2081:7:4\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_bytes32\",\n                \"typeString\": \"bytes32\"\n              }\n            },\n            \"value\": {\n              \"argumentTypes\": null,\n              \"arguments\": [\n                {\n                  \"argumentTypes\": null,\n                  \"hexValue\": \"4f5241434c455f524f4c45\",\n                  \"id\": 863,\n                  \"isConstant\": false,\n                  \"isLValue\": false,\n                  \"isPure\": true,\n                  \"kind\": \"string\",\n                  \"lValueRequested\": false,\n                  \"nodeType\": \"Literal\",\n                  \"src\": \"2129:13:4\",\n                  \"subdenomination\": null,\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_stringliteral_68e79a7bf1e0bc45d0a330c573bc367f9cf464fd326078812f301165fbda4ef1\",\n                    \"typeString\": \"literal_string \\\"ORACLE_ROLE\\\"\"\n                  },\n                  \"value\": \"ORACLE_ROLE\"\n                }\n              ],\n              \"expression\": {\n                \"argumentTypes\": [\n                  {\n                    \"typeIdentifier\": \"t_stringliteral_68e79a7bf1e0bc45d0a330c573bc367f9cf464fd326078812f301165fbda4ef1\",\n                    \"typeString\": \"literal_string \\\"ORACLE_ROLE\\\"\"\n                  }\n                ],\n                \"id\": 862,\n                \"name\": \"keccak256\",\n                \"nodeType\": \"Identifier\",\n                \"overloadedDeclarations\": [],\n                \"referencedDeclaration\": -8,\n                \"src\": \"2119:9:4\",\n                \"typeDescriptions\": {\n                  \"typeIdentifier\": \"t_function_keccak256_pure$_t_bytes_memory_ptr_$returns$_t_bytes32_$\",\n                  \"typeString\": \"function (bytes memory) pure returns (bytes32)\"\n                }\n              },\n              \"id\": 864,\n              \"isConstant\": false,\n              \"isLValue\": false,\n              \"isPure\": true,\n              \"kind\": \"functionCall\",\n              \"lValueRequested\": false,\n              \"names\": [],\n              \"nodeType\": \"FunctionCall\",\n              \"src\": \"2119:24:4\",\n              \"tryCall\": false,\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_bytes32\",\n                \"typeString\": \"bytes32\"\n              }\n            },\n            \"visibility\": \"public\"\n          },\n          {\n            \"constant\": true,\n            \"functionSelector\": \"c0ba241b\",\n            \"id\": 870,\n            \"mutability\": \"constant\",\n            \"name\": \"DELEGATE_ROLE\",\n            \"nodeType\": \"VariableDeclaration\",\n            \"overrides\": null,\n            \"scope\": 1440,\n            \"src\": \"2149:66:4\",\n            \"stateVariable\": true,\n            \"storageLocation\": \"default\",\n            \"typeDescriptions\": {\n              \"typeIdentifier\": \"t_bytes32\",\n              \"typeString\": \"bytes32\"\n            },\n            \"typeName\": {\n              \"id\": 866,\n              \"name\": \"bytes32\",\n              \"nodeType\": \"ElementaryTypeName\",\n              \"src\": \"2149:7:4\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_bytes32\",\n                \"typeString\": \"bytes32\"\n              }\n            },\n            \"value\": {\n              \"argumentTypes\": null,\n              \"arguments\": [\n                {\n                  \"argumentTypes\": null,\n                  \"hexValue\": \"44454c45474154455f524f4c45\",\n                  \"id\": 868,\n                  \"isConstant\": false,\n                  \"isLValue\": false,\n                  \"isPure\": true,\n                  \"kind\": \"string\",\n                  \"lValueRequested\": false,\n                  \"nodeType\": \"Literal\",\n                  \"src\": \"2199:15:4\",\n                  \"subdenomination\": null,\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_stringliteral_1a82baf2b928242f69f7147fb92490c6288d044f7257b88817e6284f1eec0f15\",\n                    \"typeString\": \"literal_string \\\"DELEGATE_ROLE\\\"\"\n                  },\n                  \"value\": \"DELEGATE_ROLE\"\n                }\n              ],\n              \"expression\": {\n                \"argumentTypes\": [\n                  {\n                    \"typeIdentifier\": \"t_stringliteral_1a82baf2b928242f69f7147fb92490c6288d044f7257b88817e6284f1eec0f15\",\n                    \"typeString\": \"literal_string \\\"DELEGATE_ROLE\\\"\"\n                  }\n                ],\n                \"id\": 867,\n                \"name\": \"keccak256\",\n                \"nodeType\": \"Identifier\",\n                \"overloadedDeclarations\": [],\n                \"referencedDeclaration\": -8,\n                \"src\": \"2189:9:4\",\n                \"typeDescriptions\": {\n                  \"typeIdentifier\": \"t_function_keccak256_pure$_t_bytes_memory_ptr_$returns$_t_bytes32_$\",\n                  \"typeString\": \"function (bytes memory) pure returns (bytes32)\"\n                }\n              },\n              \"id\": 869,\n              \"isConstant\": false,\n              \"isLValue\": false,\n              \"isPure\": true,\n              \"kind\": \"functionCall\",\n              \"lValueRequested\": false,\n              \"names\": [],\n              \"nodeType\": \"FunctionCall\",\n              \"src\": \"2189:26:4\",\n              \"tryCall\": false,\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_bytes32\",\n                \"typeString\": \"bytes32\"\n              }\n            },\n            \"visibility\": \"public\"\n          },\n          {\n            \"constant\": true,\n            \"functionSelector\": \"372646bb\",\n            \"id\": 873,\n            \"mutability\": \"constant\",\n            \"name\": \"DELETE_PROTECTION_PERIOD\",\n            \"nodeType\": \"VariableDeclaration\",\n            \"overrides\": null,\n            \"scope\": 1440,\n            \"src\": \"2221:57:4\",\n            \"stateVariable\": true,\n            \"storageLocation\": \"default\",\n            \"typeDescriptions\": {\n              \"typeIdentifier\": \"t_uint256\",\n              \"typeString\": \"uint256\"\n            },\n            \"typeName\": {\n              \"id\": 871,\n              \"name\": \"uint256\",\n              \"nodeType\": \"ElementaryTypeName\",\n              \"src\": \"2221:7:4\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_uint256\",\n                \"typeString\": \"uint256\"\n              }\n            },\n            \"value\": {\n              \"argumentTypes\": null,\n              \"hexValue\": \"333730323835\",\n              \"id\": 872,\n              \"isConstant\": false,\n              \"isLValue\": false,\n              \"isPure\": true,\n              \"kind\": \"number\",\n              \"lValueRequested\": false,\n              \"nodeType\": \"Literal\",\n              \"src\": \"2272:6:4\",\n              \"subdenomination\": null,\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_rational_370285_by_1\",\n                \"typeString\": \"int_const 370285\"\n              },\n              \"value\": \"370285\"\n            },\n            \"visibility\": \"public\"\n          },\n          {\n            \"constant\": false,\n            \"functionSelector\": \"ecd0c0c3\",\n            \"id\": 875,\n            \"mutability\": \"mutable\",\n            \"name\": \"_token\",\n            \"nodeType\": \"VariableDeclaration\",\n            \"overrides\": null,\n            \"scope\": 1440,\n            \"src\": \"2335:20:4\",\n            \"stateVariable\": true,\n            \"storageLocation\": \"default\",\n            \"typeDescriptions\": {\n              \"typeIdentifier\": \"t_contract$_IERC20_$2649\",\n              \"typeString\": \"contract IERC20\"\n            },\n            \"typeName\": {\n              \"contractScope\": null,\n              \"id\": 874,\n              \"name\": \"IERC20\",\n              \"nodeType\": \"UserDefinedTypeName\",\n              \"referencedDeclaration\": 2649,\n              \"src\": \"2335:6:4\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_contract$_IERC20_$2649\",\n                \"typeString\": \"contract IERC20\"\n              }\n            },\n            \"value\": null,\n            \"visibility\": \"public\"\n          },\n          {\n            \"constant\": false,\n            \"functionSelector\": \"32a1bd70\",\n            \"id\": 877,\n            \"mutability\": \"mutable\",\n            \"name\": \"_earliestDelete\",\n            \"nodeType\": \"VariableDeclaration\",\n            \"overrides\": null,\n            \"scope\": 1440,\n            \"src\": \"2361:30:4\",\n            \"stateVariable\": true,\n            \"storageLocation\": \"default\",\n            \"typeDescriptions\": {\n              \"typeIdentifier\": \"t_uint256\",\n              \"typeString\": \"uint256\"\n            },\n            \"typeName\": {\n              \"id\": 876,\n              \"name\": \"uint256\",\n              \"nodeType\": \"ElementaryTypeName\",\n              \"src\": \"2361:7:4\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_uint256\",\n                \"typeString\": \"uint256\"\n              }\n            },\n            \"value\": null,\n            \"visibility\": \"public\"\n          },\n          {\n            \"constant\": false,\n            \"functionSelector\": \"f1209ef7\",\n            \"id\": 879,\n            \"mutability\": \"mutable\",\n            \"name\": \"_pausedSinceBlock\",\n            \"nodeType\": \"VariableDeclaration\",\n            \"overrides\": null,\n            \"scope\": 1440,\n            \"src\": \"2397:32:4\",\n            \"stateVariable\": true,\n            \"storageLocation\": \"default\",\n            \"typeDescriptions\": {\n              \"typeIdentifier\": \"t_uint256\",\n              \"typeString\": \"uint256\"\n            },\n            \"typeName\": {\n              \"id\": 878,\n              \"name\": \"uint256\",\n              \"nodeType\": \"ElementaryTypeName\",\n              \"src\": \"2397:7:4\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_uint256\",\n                \"typeString\": \"uint256\"\n              }\n            },\n            \"value\": null,\n            \"visibility\": \"public\"\n          },\n          {\n            \"constant\": false,\n            \"functionSelector\": \"c5b37c22\",\n            \"id\": 881,\n            \"mutability\": \"mutable\",\n            \"name\": \"_fee\",\n            \"nodeType\": \"VariableDeclaration\",\n            \"overrides\": null,\n            \"scope\": 1440,\n            \"src\": \"2435:19:4\",\n            \"stateVariable\": true,\n            \"storageLocation\": \"default\",\n            \"typeDescriptions\": {\n              \"typeIdentifier\": \"t_uint256\",\n              \"typeString\": \"uint256\"\n            },\n            \"typeName\": {\n              \"id\": 880,\n              \"name\": \"uint256\",\n              \"nodeType\": \"ElementaryTypeName\",\n              \"src\": \"2435:7:4\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_uint256\",\n                \"typeString\": \"uint256\"\n              }\n            },\n            \"value\": null,\n            \"visibility\": \"public\"\n          },\n          {\n            \"constant\": false,\n            \"functionSelector\": \"d83222ec\",\n            \"id\": 883,\n            \"mutability\": \"mutable\",\n            \"name\": \"_accruedFeesAmount\",\n            \"nodeType\": \"VariableDeclaration\",\n            \"overrides\": null,\n            \"scope\": 1440,\n            \"src\": \"2460:33:4\",\n            \"stateVariable\": true,\n            \"storageLocation\": \"default\",\n            \"typeDescriptions\": {\n              \"typeIdentifier\": \"t_uint256\",\n              \"typeString\": \"uint256\"\n            },\n            \"typeName\": {\n              \"id\": 882,\n              \"name\": \"uint256\",\n              \"nodeType\": \"ElementaryTypeName\",\n              \"src\": \"2460:7:4\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_uint256\",\n                \"typeString\": \"uint256\"\n              }\n            },\n            \"value\": null,\n            \"visibility\": \"public\"\n          },\n          {\n            \"constant\": false,\n            \"id\": 885,\n            \"mutability\": \"mutable\",\n            \"name\": \"_oracleValue\",\n            \"nodeType\": \"VariableDeclaration\",\n            \"overrides\": null,\n            \"scope\": 1440,\n            \"src\": \"2499:32:4\",\n            \"stateVariable\": true,\n            \"storageLocation\": \"default\",\n            \"typeDescriptions\": {\n              \"typeIdentifier\": \"t_struct$_OracleValue_$834_storage\",\n              \"typeString\": \"struct FetchOracle.OracleValue\"\n            },\n            \"typeName\": {\n              \"contractScope\": null,\n              \"id\": 884,\n              \"name\": \"OracleValue\",\n              \"nodeType\": \"UserDefinedTypeName\",\n              \"referencedDeclaration\": 834,\n              \"src\": \"2499:11:4\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_struct$_OracleValue_$834_storage_ptr\",\n                \"typeString\": \"struct FetchOracle.OracleValue\"\n              }\n            },\n            \"value\": null,\n            \"visibility\": \"private\"\n          },\n          {\n            \"constant\": false,\n            \"functionSelector\": \"993240a3\",\n            \"id\": 887,\n            \"mutability\": \"mutable\",\n            \"name\": \"_feeCurrency\",\n            \"nodeType\": \"VariableDeclaration\",\n            \"overrides\": null,\n            \"scope\": 1440,\n            \"src\": \"2537:31:4\",\n            \"stateVariable\": true,\n            \"storageLocation\": \"default\",\n            \"typeDescriptions\": {\n              \"typeIdentifier\": \"t_enum$_FeeCurrency_$827\",\n              \"typeString\": \"enum FetchOracle.FeeCurrency\"\n            },\n            \"typeName\": {\n              \"contractScope\": null,\n              \"id\": 886,\n              \"name\": \"FeeCurrency\",\n              \"nodeType\": \"UserDefinedTypeName\",\n              \"referencedDeclaration\": 827,\n              \"src\": \"2537:11:4\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_enum$_FeeCurrency_$827\",\n                \"typeString\": \"enum FetchOracle.FeeCurrency\"\n              }\n            },\n            \"value\": null,\n            \"visibility\": \"public\"\n          },\n          {\n            \"body\": {\n              \"id\": 898,\n              \"nodeType\": \"Block\",\n              \"src\": \"2623:63:4\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 893,\n                        \"name\": \"DEFAULT_ADMIN_ROLE\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 1526,\n                        \"src\": \"2648:18:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_bytes32\",\n                          \"typeString\": \"bytes32\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 894,\n                          \"name\": \"msg\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": -15,\n                          \"src\": \"2668:3:4\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_magic_message\",\n                            \"typeString\": \"msg\"\n                          }\n                        },\n                        \"id\": 895,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"memberName\": \"sender\",\n                        \"nodeType\": \"MemberAccess\",\n                        \"referencedDeclaration\": null,\n                        \"src\": \"2668:10:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_bytes32\",\n                          \"typeString\": \"bytes32\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        }\n                      ],\n                      \"id\": 892,\n                      \"name\": \"hasRole\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 1572,\n                      \"src\": \"2640:7:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_view$_t_bytes32_$_t_address_$returns$_t_bool_$\",\n                        \"typeString\": \"function (bytes32,address) view returns (bool)\"\n                      }\n                    },\n                    \"id\": 896,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"2640:39:4\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_bool\",\n                      \"typeString\": \"bool\"\n                    }\n                  },\n                  \"functionReturnParameters\": 891,\n                  \"id\": 897,\n                  \"nodeType\": \"Return\",\n                  \"src\": \"2633:46:4\"\n                }\n              ]\n            },\n            \"documentation\": null,\n            \"id\": 899,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [],\n            \"name\": \"_isOwner\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 888,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"2592:2:4\"\n            },\n            \"returnParameters\": {\n              \"id\": 891,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 890,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 899,\n                  \"src\": \"2617:4:4\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_bool\",\n                    \"typeString\": \"bool\"\n                  },\n                  \"typeName\": {\n                    \"id\": 889,\n                    \"name\": \"bool\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"2617:4:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_bool\",\n                      \"typeString\": \"bool\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"2616:6:4\"\n            },\n            \"scope\": 1440,\n            \"src\": \"2575:111:4\",\n            \"stateMutability\": \"view\",\n            \"virtual\": false,\n            \"visibility\": \"internal\"\n          },\n          {\n            \"body\": {\n              \"id\": 908,\n              \"nodeType\": \"Block\",\n              \"src\": \"2746:81:4\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"arguments\": [],\n                        \"expression\": {\n                          \"argumentTypes\": [],\n                          \"id\": 902,\n                          \"name\": \"_isOwner\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 899,\n                          \"src\": \"2764:8:4\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_function_internal_view$__$returns$_t_bool_$\",\n                            \"typeString\": \"function () view returns (bool)\"\n                          }\n                        },\n                        \"id\": 903,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"kind\": \"functionCall\",\n                        \"lValueRequested\": false,\n                        \"names\": [],\n                        \"nodeType\": \"FunctionCall\",\n                        \"src\": \"2764:10:4\",\n                        \"tryCall\": false,\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"hexValue\": \"43616c6c6572206973206e6f7420616e2061646d696e6973747261746f72\",\n                        \"id\": 904,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": true,\n                        \"kind\": \"string\",\n                        \"lValueRequested\": false,\n                        \"nodeType\": \"Literal\",\n                        \"src\": \"2776:32:4\",\n                        \"subdenomination\": null,\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_stringliteral_fff29d4bd770cdc17b9f156c578c5f49981008f3769f218da7df946262b27392\",\n                          \"typeString\": \"literal_string \\\"Caller is not an administrator\\\"\"\n                        },\n                        \"value\": \"Caller is not an administrator\"\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_stringliteral_fff29d4bd770cdc17b9f156c578c5f49981008f3769f218da7df946262b27392\",\n                          \"typeString\": \"literal_string \\\"Caller is not an administrator\\\"\"\n                        }\n                      ],\n                      \"id\": 901,\n                      \"name\": \"require\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [\n                        -18,\n                        -18\n                      ],\n                      \"referencedDeclaration\": -18,\n                      \"src\": \"2756:7:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$\",\n                        \"typeString\": \"function (bool,string memory) pure\"\n                      }\n                    },\n                    \"id\": 905,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"2756:53:4\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 906,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"2756:53:4\"\n                },\n                {\n                  \"id\": 907,\n                  \"nodeType\": \"PlaceholderStatement\",\n                  \"src\": \"2819:1:4\"\n                }\n              ]\n            },\n            \"documentation\": null,\n            \"id\": 909,\n            \"name\": \"onlyOwner\",\n            \"nodeType\": \"ModifierDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 900,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"2743:2:4\"\n            },\n            \"src\": \"2725:102:4\",\n            \"virtual\": false,\n            \"visibility\": \"internal\"\n          },\n          {\n            \"body\": {\n              \"id\": 924,\n              \"nodeType\": \"Block\",\n              \"src\": \"2902:125:4\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"commonType\": {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        },\n                        \"id\": 919,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"leftExpression\": {\n                          \"argumentTypes\": null,\n                          \"arguments\": [],\n                          \"expression\": {\n                            \"argumentTypes\": [],\n                            \"id\": 912,\n                            \"name\": \"_isOwner\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 899,\n                            \"src\": \"2920:8:4\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_function_internal_view$__$returns$_t_bool_$\",\n                              \"typeString\": \"function () view returns (bool)\"\n                            }\n                          },\n                          \"id\": 913,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"kind\": \"functionCall\",\n                          \"lValueRequested\": false,\n                          \"names\": [],\n                          \"nodeType\": \"FunctionCall\",\n                          \"src\": \"2920:10:4\",\n                          \"tryCall\": false,\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_bool\",\n                            \"typeString\": \"bool\"\n                          }\n                        },\n                        \"nodeType\": \"BinaryOperation\",\n                        \"operator\": \"||\",\n                        \"rightExpression\": {\n                          \"argumentTypes\": null,\n                          \"arguments\": [\n                            {\n                              \"argumentTypes\": null,\n                              \"id\": 915,\n                              \"name\": \"DELEGATE_ROLE\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 870,\n                              \"src\": \"2942:13:4\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_bytes32\",\n                                \"typeString\": \"bytes32\"\n                              }\n                            },\n                            {\n                              \"argumentTypes\": null,\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"id\": 916,\n                                \"name\": \"msg\",\n                                \"nodeType\": \"Identifier\",\n                                \"overloadedDeclarations\": [],\n                                \"referencedDeclaration\": -15,\n                                \"src\": \"2957:3:4\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_magic_message\",\n                                  \"typeString\": \"msg\"\n                                }\n                              },\n                              \"id\": 917,\n                              \"isConstant\": false,\n                              \"isLValue\": false,\n                              \"isPure\": false,\n                              \"lValueRequested\": false,\n                              \"memberName\": \"sender\",\n                              \"nodeType\": \"MemberAccess\",\n                              \"referencedDeclaration\": null,\n                              \"src\": \"2957:10:4\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_address_payable\",\n                                \"typeString\": \"address payable\"\n                              }\n                            }\n                          ],\n                          \"expression\": {\n                            \"argumentTypes\": [\n                              {\n                                \"typeIdentifier\": \"t_bytes32\",\n                                \"typeString\": \"bytes32\"\n                              },\n                              {\n                                \"typeIdentifier\": \"t_address_payable\",\n                                \"typeString\": \"address payable\"\n                              }\n                            ],\n                            \"id\": 914,\n                            \"name\": \"hasRole\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 1572,\n                            \"src\": \"2934:7:4\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_function_internal_view$_t_bytes32_$_t_address_$returns$_t_bool_$\",\n                              \"typeString\": \"function (bytes32,address) view returns (bool)\"\n                            }\n                          },\n                          \"id\": 918,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"kind\": \"functionCall\",\n                          \"lValueRequested\": false,\n                          \"names\": [],\n                          \"nodeType\": \"FunctionCall\",\n                          \"src\": \"2934:34:4\",\n                          \"tryCall\": false,\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_bool\",\n                            \"typeString\": \"bool\"\n                          }\n                        },\n                        \"src\": \"2920:48:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"hexValue\": \"43616c6c6572206973206e656974686572206f776e6572206e6f722064656c6567617465\",\n                        \"id\": 920,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": true,\n                        \"kind\": \"string\",\n                        \"lValueRequested\": false,\n                        \"nodeType\": \"Literal\",\n                        \"src\": \"2970:38:4\",\n                        \"subdenomination\": null,\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_stringliteral_3c2cbf62f56025e2baf3b46dabe4ee1ab0f4be1432d0bef94b4d166423814999\",\n                          \"typeString\": \"literal_string \\\"Caller is neither owner nor delegate\\\"\"\n                        },\n                        \"value\": \"Caller is neither owner nor delegate\"\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_stringliteral_3c2cbf62f56025e2baf3b46dabe4ee1ab0f4be1432d0bef94b4d166423814999\",\n                          \"typeString\": \"literal_string \\\"Caller is neither owner nor delegate\\\"\"\n                        }\n                      ],\n                      \"id\": 911,\n                      \"name\": \"require\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [\n                        -18,\n                        -18\n                      ],\n                      \"referencedDeclaration\": -18,\n                      \"src\": \"2912:7:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$\",\n                        \"typeString\": \"function (bool,string memory) pure\"\n                      }\n                    },\n                    \"id\": 921,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"2912:97:4\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 922,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"2912:97:4\"\n                },\n                {\n                  \"id\": 923,\n                  \"nodeType\": \"PlaceholderStatement\",\n                  \"src\": \"3019:1:4\"\n                }\n              ]\n            },\n            \"documentation\": null,\n            \"id\": 925,\n            \"name\": \"onlyDelegate\",\n            \"nodeType\": \"ModifierDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 910,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"2899:2:4\"\n            },\n            \"src\": \"2878:149:4\",\n            \"virtual\": false,\n            \"visibility\": \"internal\"\n          },\n          {\n            \"body\": {\n              \"id\": 937,\n              \"nodeType\": \"Block\",\n              \"src\": \"3089:96:4\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"arguments\": [\n                          {\n                            \"argumentTypes\": null,\n                            \"id\": 929,\n                            \"name\": \"ORACLE_ROLE\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 865,\n                            \"src\": \"3115:11:4\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_bytes32\",\n                              \"typeString\": \"bytes32\"\n                            }\n                          },\n                          {\n                            \"argumentTypes\": null,\n                            \"expression\": {\n                              \"argumentTypes\": null,\n                              \"id\": 930,\n                              \"name\": \"msg\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": -15,\n                              \"src\": \"3128:3:4\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_magic_message\",\n                                \"typeString\": \"msg\"\n                              }\n                            },\n                            \"id\": 931,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": false,\n                            \"lValueRequested\": false,\n                            \"memberName\": \"sender\",\n                            \"nodeType\": \"MemberAccess\",\n                            \"referencedDeclaration\": null,\n                            \"src\": \"3128:10:4\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_address_payable\",\n                              \"typeString\": \"address payable\"\n                            }\n                          }\n                        ],\n                        \"expression\": {\n                          \"argumentTypes\": [\n                            {\n                              \"typeIdentifier\": \"t_bytes32\",\n                              \"typeString\": \"bytes32\"\n                            },\n                            {\n                              \"typeIdentifier\": \"t_address_payable\",\n                              \"typeString\": \"address payable\"\n                            }\n                          ],\n                          \"id\": 928,\n                          \"name\": \"hasRole\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 1572,\n                          \"src\": \"3107:7:4\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_function_internal_view$_t_bytes32_$_t_address_$returns$_t_bool_$\",\n                            \"typeString\": \"function (bytes32,address) view returns (bool)\"\n                          }\n                        },\n                        \"id\": 932,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"kind\": \"functionCall\",\n                        \"lValueRequested\": false,\n                        \"names\": [],\n                        \"nodeType\": \"FunctionCall\",\n                        \"src\": \"3107:32:4\",\n                        \"tryCall\": false,\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"hexValue\": \"43616c6c6572206973206e6f7420616e206f7261636c65\",\n                        \"id\": 933,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": true,\n                        \"kind\": \"string\",\n                        \"lValueRequested\": false,\n                        \"nodeType\": \"Literal\",\n                        \"src\": \"3141:25:4\",\n                        \"subdenomination\": null,\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_stringliteral_8c1dc436c657406c837ef43aefe277157f6f9572ac3e706ad659a5d014391325\",\n                          \"typeString\": \"literal_string \\\"Caller is not an oracle\\\"\"\n                        },\n                        \"value\": \"Caller is not an oracle\"\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_stringliteral_8c1dc436c657406c837ef43aefe277157f6f9572ac3e706ad659a5d014391325\",\n                          \"typeString\": \"literal_string \\\"Caller is not an oracle\\\"\"\n                        }\n                      ],\n                      \"id\": 927,\n                      \"name\": \"require\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [\n                        -18,\n                        -18\n                      ],\n                      \"referencedDeclaration\": -18,\n                      \"src\": \"3099:7:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$\",\n                        \"typeString\": \"function (bool,string memory) pure\"\n                      }\n                    },\n                    \"id\": 934,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"3099:68:4\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 935,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"3099:68:4\"\n                },\n                {\n                  \"id\": 936,\n                  \"nodeType\": \"PlaceholderStatement\",\n                  \"src\": \"3177:1:4\"\n                }\n              ]\n            },\n            \"documentation\": null,\n            \"id\": 938,\n            \"name\": \"onlyOracle\",\n            \"nodeType\": \"ModifierDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 926,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"3086:2:4\"\n            },\n            \"src\": \"3067:118:4\",\n            \"virtual\": false,\n            \"visibility\": \"internal\"\n          },\n          {\n            \"body\": {\n              \"id\": 951,\n              \"nodeType\": \"Block\",\n              \"src\": \"3244:96:4\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"commonType\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        },\n                        \"id\": 946,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"leftExpression\": {\n                          \"argumentTypes\": null,\n                          \"arguments\": [],\n                          \"expression\": {\n                            \"argumentTypes\": [],\n                            \"id\": 943,\n                            \"name\": \"_getBlockNumber\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 1314,\n                            \"src\": \"3262:15:4\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_function_internal_view$__$returns$_t_uint256_$\",\n                              \"typeString\": \"function () view returns (uint256)\"\n                            }\n                          },\n                          \"id\": 944,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"kind\": \"functionCall\",\n                          \"lValueRequested\": false,\n                          \"names\": [],\n                          \"nodeType\": \"FunctionCall\",\n                          \"src\": \"3262:17:4\",\n                          \"tryCall\": false,\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"nodeType\": \"BinaryOperation\",\n                        \"operator\": \"<=\",\n                        \"rightExpression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 945,\n                          \"name\": \"expirationBlock\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 940,\n                          \"src\": \"3283:15:4\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"src\": \"3262:36:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"hexValue\": \"5472616e73616374696f6e2065787069726564\",\n                        \"id\": 947,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": true,\n                        \"kind\": \"string\",\n                        \"lValueRequested\": false,\n                        \"nodeType\": \"Literal\",\n                        \"src\": \"3300:21:4\",\n                        \"subdenomination\": null,\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_stringliteral_38b57334da13daffb65e2d9cfe97bc3051af86f72807115eae867384ed846551\",\n                          \"typeString\": \"literal_string \\\"Transaction expired\\\"\"\n                        },\n                        \"value\": \"Transaction expired\"\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_stringliteral_38b57334da13daffb65e2d9cfe97bc3051af86f72807115eae867384ed846551\",\n                          \"typeString\": \"literal_string \\\"Transaction expired\\\"\"\n                        }\n                      ],\n                      \"id\": 942,\n                      \"name\": \"require\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [\n                        -18,\n                        -18\n                      ],\n                      \"referencedDeclaration\": -18,\n                      \"src\": \"3254:7:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$\",\n                        \"typeString\": \"function (bool,string memory) pure\"\n                      }\n                    },\n                    \"id\": 948,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"3254:68:4\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 949,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"3254:68:4\"\n                },\n                {\n                  \"id\": 950,\n                  \"nodeType\": \"PlaceholderStatement\",\n                  \"src\": \"3332:1:4\"\n                }\n              ]\n            },\n            \"documentation\": null,\n            \"id\": 952,\n            \"name\": \"verifyTxExpiration\",\n            \"nodeType\": \"ModifierDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 941,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 940,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"expirationBlock\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 952,\n                  \"src\": \"3219:23:4\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 939,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"3219:7:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"3218:25:4\"\n            },\n            \"src\": \"3191:149:4\",\n            \"virtual\": false,\n            \"visibility\": \"internal\"\n          },\n          {\n            \"body\": {\n              \"id\": 963,\n              \"nodeType\": \"Block\",\n              \"src\": \"3373:102:4\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"commonType\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        },\n                        \"id\": 958,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"leftExpression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 955,\n                          \"name\": \"_pausedSinceBlock\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 879,\n                          \"src\": \"3391:17:4\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"nodeType\": \"BinaryOperation\",\n                        \"operator\": \">\",\n                        \"rightExpression\": {\n                          \"argumentTypes\": null,\n                          \"arguments\": [],\n                          \"expression\": {\n                            \"argumentTypes\": [],\n                            \"id\": 956,\n                            \"name\": \"_getBlockNumber\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 1314,\n                            \"src\": \"3411:15:4\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_function_internal_view$__$returns$_t_uint256_$\",\n                              \"typeString\": \"function () view returns (uint256)\"\n                            }\n                          },\n                          \"id\": 957,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"kind\": \"functionCall\",\n                          \"lValueRequested\": false,\n                          \"names\": [],\n                          \"nodeType\": \"FunctionCall\",\n                          \"src\": \"3411:17:4\",\n                          \"tryCall\": false,\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"src\": \"3391:37:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"hexValue\": \"436f6e747261637420686173206265656e20706175736564\",\n                        \"id\": 959,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": true,\n                        \"kind\": \"string\",\n                        \"lValueRequested\": false,\n                        \"nodeType\": \"Literal\",\n                        \"src\": \"3430:26:4\",\n                        \"subdenomination\": null,\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_stringliteral_6993ab713d4a8a857f0654d36ec91738ef7ba3b8999d96006199fec5b907c586\",\n                          \"typeString\": \"literal_string \\\"Contract has been paused\\\"\"\n                        },\n                        \"value\": \"Contract has been paused\"\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_stringliteral_6993ab713d4a8a857f0654d36ec91738ef7ba3b8999d96006199fec5b907c586\",\n                          \"typeString\": \"literal_string \\\"Contract has been paused\\\"\"\n                        }\n                      ],\n                      \"id\": 954,\n                      \"name\": \"require\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [\n                        -18,\n                        -18\n                      ],\n                      \"referencedDeclaration\": -18,\n                      \"src\": \"3383:7:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$\",\n                        \"typeString\": \"function (bool,string memory) pure\"\n                      }\n                    },\n                    \"id\": 960,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"3383:74:4\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 961,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"3383:74:4\"\n                },\n                {\n                  \"id\": 962,\n                  \"nodeType\": \"PlaceholderStatement\",\n                  \"src\": \"3467:1:4\"\n                }\n              ]\n            },\n            \"documentation\": null,\n            \"id\": 964,\n            \"name\": \"verifyNotPaused\",\n            \"nodeType\": \"ModifierDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 953,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"3370:2:4\"\n            },\n            \"src\": \"3346:129:4\",\n            \"virtual\": false,\n            \"visibility\": \"internal\"\n          },\n          {\n            \"body\": {\n              \"id\": 1023,\n              \"nodeType\": \"Block\",\n              \"src\": \"3685:406:4\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 973,\n                        \"name\": \"DEFAULT_ADMIN_ROLE\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 1526,\n                        \"src\": \"3706:18:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_bytes32\",\n                          \"typeString\": \"bytes32\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 974,\n                          \"name\": \"msg\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": -15,\n                          \"src\": \"3726:3:4\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_magic_message\",\n                            \"typeString\": \"msg\"\n                          }\n                        },\n                        \"id\": 975,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"memberName\": \"sender\",\n                        \"nodeType\": \"MemberAccess\",\n                        \"referencedDeclaration\": null,\n                        \"src\": \"3726:10:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_bytes32\",\n                          \"typeString\": \"bytes32\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        }\n                      ],\n                      \"id\": 972,\n                      \"name\": \"_setupRole\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 1709,\n                      \"src\": \"3695:10:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_nonpayable$_t_bytes32_$_t_address_$returns$__$\",\n                        \"typeString\": \"function (bytes32,address)\"\n                      }\n                    },\n                    \"id\": 976,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"3695:42:4\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 977,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"3695:42:4\"\n                },\n                {\n                  \"condition\": {\n                    \"argumentTypes\": null,\n                    \"commonType\": {\n                      \"typeIdentifier\": \"t_address\",\n                      \"typeString\": \"address\"\n                    },\n                    \"id\": 983,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftExpression\": {\n                      \"argumentTypes\": null,\n                      \"id\": 978,\n                      \"name\": \"ERC20Address\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 967,\n                      \"src\": \"3752:12:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_address\",\n                        \"typeString\": \"address\"\n                      }\n                    },\n                    \"nodeType\": \"BinaryOperation\",\n                    \"operator\": \"==\",\n                    \"rightExpression\": {\n                      \"argumentTypes\": null,\n                      \"arguments\": [\n                        {\n                          \"argumentTypes\": null,\n                          \"hexValue\": \"30\",\n                          \"id\": 981,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": true,\n                          \"kind\": \"number\",\n                          \"lValueRequested\": false,\n                          \"nodeType\": \"Literal\",\n                          \"src\": \"3776:1:4\",\n                          \"subdenomination\": null,\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_rational_0_by_1\",\n                            \"typeString\": \"int_const 0\"\n                          },\n                          \"value\": \"0\"\n                        }\n                      ],\n                      \"expression\": {\n                        \"argumentTypes\": [\n                          {\n                            \"typeIdentifier\": \"t_rational_0_by_1\",\n                            \"typeString\": \"int_const 0\"\n                          }\n                        ],\n                        \"id\": 980,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": true,\n                        \"lValueRequested\": false,\n                        \"nodeType\": \"ElementaryTypeNameExpression\",\n                        \"src\": \"3768:7:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_type$_t_address_$\",\n                          \"typeString\": \"type(address)\"\n                        },\n                        \"typeName\": {\n                          \"id\": 979,\n                          \"name\": \"address\",\n                          \"nodeType\": \"ElementaryTypeName\",\n                          \"src\": \"3768:7:4\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": null,\n                            \"typeString\": null\n                          }\n                        }\n                      },\n                      \"id\": 982,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": true,\n                      \"kind\": \"typeConversion\",\n                      \"lValueRequested\": false,\n                      \"names\": [],\n                      \"nodeType\": \"FunctionCall\",\n                      \"src\": \"3768:10:4\",\n                      \"tryCall\": false,\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_address_payable\",\n                        \"typeString\": \"address payable\"\n                      }\n                    },\n                    \"src\": \"3752:26:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_bool\",\n                      \"typeString\": \"bool\"\n                    }\n                  },\n                  \"falseBody\": {\n                    \"id\": 1001,\n                    \"nodeType\": \"Block\",\n                    \"src\": \"3841:100:4\",\n                    \"statements\": [\n                      {\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 993,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"leftHandSide\": {\n                            \"argumentTypes\": null,\n                            \"id\": 990,\n                            \"name\": \"_feeCurrency\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 887,\n                            \"src\": \"3855:12:4\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_enum$_FeeCurrency_$827\",\n                              \"typeString\": \"enum FetchOracle.FeeCurrency\"\n                            }\n                          },\n                          \"nodeType\": \"Assignment\",\n                          \"operator\": \"=\",\n                          \"rightHandSide\": {\n                            \"argumentTypes\": null,\n                            \"expression\": {\n                              \"argumentTypes\": null,\n                              \"id\": 991,\n                              \"name\": \"FeeCurrency\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 827,\n                              \"src\": \"3870:11:4\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_type$_t_enum$_FeeCurrency_$827_$\",\n                                \"typeString\": \"type(enum FetchOracle.FeeCurrency)\"\n                              }\n                            },\n                            \"id\": 992,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": true,\n                            \"lValueRequested\": false,\n                            \"memberName\": \"ERC20\",\n                            \"nodeType\": \"MemberAccess\",\n                            \"referencedDeclaration\": null,\n                            \"src\": \"3870:17:4\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_enum$_FeeCurrency_$827\",\n                              \"typeString\": \"enum FetchOracle.FeeCurrency\"\n                            }\n                          },\n                          \"src\": \"3855:32:4\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_enum$_FeeCurrency_$827\",\n                            \"typeString\": \"enum FetchOracle.FeeCurrency\"\n                          }\n                        },\n                        \"id\": 994,\n                        \"nodeType\": \"ExpressionStatement\",\n                        \"src\": \"3855:32:4\"\n                      },\n                      {\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 999,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"leftHandSide\": {\n                            \"argumentTypes\": null,\n                            \"id\": 995,\n                            \"name\": \"_token\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 875,\n                            \"src\": \"3901:6:4\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_contract$_IERC20_$2649\",\n                              \"typeString\": \"contract IERC20\"\n                            }\n                          },\n                          \"nodeType\": \"Assignment\",\n                          \"operator\": \"=\",\n                          \"rightHandSide\": {\n                            \"argumentTypes\": null,\n                            \"arguments\": [\n                              {\n                                \"argumentTypes\": null,\n                                \"id\": 997,\n                                \"name\": \"ERC20Address\",\n                                \"nodeType\": \"Identifier\",\n                                \"overloadedDeclarations\": [],\n                                \"referencedDeclaration\": 967,\n                                \"src\": \"3917:12:4\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_address\",\n                                  \"typeString\": \"address\"\n                                }\n                              }\n                            ],\n                            \"expression\": {\n                              \"argumentTypes\": [\n                                {\n                                  \"typeIdentifier\": \"t_address\",\n                                  \"typeString\": \"address\"\n                                }\n                              ],\n                              \"id\": 996,\n                              \"name\": \"IERC20\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 2649,\n                              \"src\": \"3910:6:4\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_type$_t_contract$_IERC20_$2649_$\",\n                                \"typeString\": \"type(contract IERC20)\"\n                              }\n                            },\n                            \"id\": 998,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": false,\n                            \"kind\": \"typeConversion\",\n                            \"lValueRequested\": false,\n                            \"names\": [],\n                            \"nodeType\": \"FunctionCall\",\n                            \"src\": \"3910:20:4\",\n                            \"tryCall\": false,\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_contract$_IERC20_$2649\",\n                              \"typeString\": \"contract IERC20\"\n                            }\n                          },\n                          \"src\": \"3901:29:4\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_contract$_IERC20_$2649\",\n                            \"typeString\": \"contract IERC20\"\n                          }\n                        },\n                        \"id\": 1000,\n                        \"nodeType\": \"ExpressionStatement\",\n                        \"src\": \"3901:29:4\"\n                      }\n                    ]\n                  },\n                  \"id\": 1002,\n                  \"nodeType\": \"IfStatement\",\n                  \"src\": \"3748:193:4\",\n                  \"trueBody\": {\n                    \"id\": 989,\n                    \"nodeType\": \"Block\",\n                    \"src\": \"3780:55:4\",\n                    \"statements\": [\n                      {\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 987,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"leftHandSide\": {\n                            \"argumentTypes\": null,\n                            \"id\": 984,\n                            \"name\": \"_feeCurrency\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 887,\n                            \"src\": \"3794:12:4\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_enum$_FeeCurrency_$827\",\n                              \"typeString\": \"enum FetchOracle.FeeCurrency\"\n                            }\n                          },\n                          \"nodeType\": \"Assignment\",\n                          \"operator\": \"=\",\n                          \"rightHandSide\": {\n                            \"argumentTypes\": null,\n                            \"expression\": {\n                              \"argumentTypes\": null,\n                              \"id\": 985,\n                              \"name\": \"FeeCurrency\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 827,\n                              \"src\": \"3809:11:4\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_type$_t_enum$_FeeCurrency_$827_$\",\n                                \"typeString\": \"type(enum FetchOracle.FeeCurrency)\"\n                              }\n                            },\n                            \"id\": 986,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": true,\n                            \"lValueRequested\": false,\n                            \"memberName\": \"ETH\",\n                            \"nodeType\": \"MemberAccess\",\n                            \"referencedDeclaration\": null,\n                            \"src\": \"3809:15:4\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_enum$_FeeCurrency_$827\",\n                              \"typeString\": \"enum FetchOracle.FeeCurrency\"\n                            }\n                          },\n                          \"src\": \"3794:30:4\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_enum$_FeeCurrency_$827\",\n                            \"typeString\": \"enum FetchOracle.FeeCurrency\"\n                          }\n                        },\n                        \"id\": 988,\n                        \"nodeType\": \"ExpressionStatement\",\n                        \"src\": \"3794:30:4\"\n                      }\n                    ]\n                  }\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 1009,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 1003,\n                      \"name\": \"_earliestDelete\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 877,\n                      \"src\": \"3951:15:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"arguments\": [\n                        {\n                          \"argumentTypes\": null,\n                          \"id\": 1007,\n                          \"name\": \"DELETE_PROTECTION_PERIOD\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 873,\n                          \"src\": \"3991:24:4\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        }\n                      ],\n                      \"expression\": {\n                        \"argumentTypes\": [\n                          {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        ],\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"arguments\": [],\n                          \"expression\": {\n                            \"argumentTypes\": [],\n                            \"id\": 1004,\n                            \"name\": \"_getBlockNumber\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 1314,\n                            \"src\": \"3969:15:4\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_function_internal_view$__$returns$_t_uint256_$\",\n                              \"typeString\": \"function () view returns (uint256)\"\n                            }\n                          },\n                          \"id\": 1005,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"kind\": \"functionCall\",\n                          \"lValueRequested\": false,\n                          \"names\": [],\n                          \"nodeType\": \"FunctionCall\",\n                          \"src\": \"3969:17:4\",\n                          \"tryCall\": false,\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"id\": 1006,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"memberName\": \"add\",\n                        \"nodeType\": \"MemberAccess\",\n                        \"referencedDeclaration\": 1812,\n                        \"src\": \"3969:21:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_function_internal_pure$_t_uint256_$_t_uint256_$returns$_t_uint256_$bound_to$_t_uint256_$\",\n                          \"typeString\": \"function (uint256,uint256) pure returns (uint256)\"\n                        }\n                      },\n                      \"id\": 1008,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": false,\n                      \"kind\": \"functionCall\",\n                      \"lValueRequested\": false,\n                      \"names\": [],\n                      \"nodeType\": \"FunctionCall\",\n                      \"src\": \"3969:47:4\",\n                      \"tryCall\": false,\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"src\": \"3951:65:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"id\": 1010,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"3951:65:4\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 1017,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 1011,\n                      \"name\": \"_pausedSinceBlock\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 879,\n                      \"src\": \"4026:17:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 1016,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": true,\n                      \"lValueRequested\": false,\n                      \"nodeType\": \"UnaryOperation\",\n                      \"operator\": \"~\",\n                      \"prefix\": true,\n                      \"src\": \"4046:11:4\",\n                      \"subExpression\": {\n                        \"argumentTypes\": null,\n                        \"arguments\": [\n                          {\n                            \"argumentTypes\": null,\n                            \"hexValue\": \"30\",\n                            \"id\": 1014,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": true,\n                            \"kind\": \"number\",\n                            \"lValueRequested\": false,\n                            \"nodeType\": \"Literal\",\n                            \"src\": \"4055:1:4\",\n                            \"subdenomination\": null,\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_rational_0_by_1\",\n                              \"typeString\": \"int_const 0\"\n                            },\n                            \"value\": \"0\"\n                          }\n                        ],\n                        \"expression\": {\n                          \"argumentTypes\": [\n                            {\n                              \"typeIdentifier\": \"t_rational_0_by_1\",\n                              \"typeString\": \"int_const 0\"\n                            }\n                          ],\n                          \"id\": 1013,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": true,\n                          \"lValueRequested\": false,\n                          \"nodeType\": \"ElementaryTypeNameExpression\",\n                          \"src\": \"4047:7:4\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_type$_t_uint256_$\",\n                            \"typeString\": \"type(uint256)\"\n                          },\n                          \"typeName\": {\n                            \"id\": 1012,\n                            \"name\": \"uint256\",\n                            \"nodeType\": \"ElementaryTypeName\",\n                            \"src\": \"4047:7:4\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": null,\n                              \"typeString\": null\n                            }\n                          }\n                        },\n                        \"id\": 1015,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": true,\n                        \"kind\": \"typeConversion\",\n                        \"lValueRequested\": false,\n                        \"names\": [],\n                        \"nodeType\": \"FunctionCall\",\n                        \"src\": \"4047:10:4\",\n                        \"tryCall\": false,\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"src\": \"4026:31:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"id\": 1018,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"4026:31:4\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 1021,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 1019,\n                      \"name\": \"_fee\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 881,\n                      \"src\": \"4067:4:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 1020,\n                      \"name\": \"initialFee\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 969,\n                      \"src\": \"4074:10:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"src\": \"4067:17:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"id\": 1022,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"4067:17:4\"\n                }\n              ]\n            },\n            \"documentation\": {\n              \"id\": 965,\n              \"nodeType\": \"StructuredDocumentation\",\n              \"src\": \"3551:68:4\",\n              \"text\": \"@param ERC20Address address of the ERC20 contract\"\n            },\n            \"id\": 1024,\n            \"implemented\": true,\n            \"kind\": \"constructor\",\n            \"modifiers\": [],\n            \"name\": \"\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 970,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 967,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"ERC20Address\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 1024,\n                  \"src\": \"3636:20:4\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_address\",\n                    \"typeString\": \"address\"\n                  },\n                  \"typeName\": {\n                    \"id\": 966,\n                    \"name\": \"address\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"3636:7:4\",\n                    \"stateMutability\": \"nonpayable\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address\",\n                      \"typeString\": \"address\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 969,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"initialFee\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 1024,\n                  \"src\": \"3658:18:4\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 968,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"3658:7:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"3635:42:4\"\n            },\n            \"returnParameters\": {\n              \"id\": 971,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"3685:0:4\"\n            },\n            \"scope\": 1440,\n            \"src\": \"3624:467:4\",\n            \"stateMutability\": \"nonpayable\",\n            \"virtual\": false,\n            \"visibility\": \"public\"\n          },\n          {\n            \"body\": {\n              \"id\": 1062,\n              \"nodeType\": \"Block\",\n              \"src\": \"4303:223:4\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 1042,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 1038,\n                        \"name\": \"_oracleValue\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 885,\n                        \"src\": \"4313:12:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_OracleValue_$834_storage\",\n                          \"typeString\": \"struct FetchOracle.OracleValue storage ref\"\n                        }\n                      },\n                      \"id\": 1040,\n                      \"isConstant\": false,\n                      \"isLValue\": true,\n                      \"isPure\": false,\n                      \"lValueRequested\": true,\n                      \"memberName\": \"value\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": 829,\n                      \"src\": \"4313:18:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 1041,\n                      \"name\": \"value\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 1026,\n                      \"src\": \"4334:5:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"src\": \"4313:26:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"id\": 1043,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"4313:26:4\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 1048,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 1044,\n                        \"name\": \"_oracleValue\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 885,\n                        \"src\": \"4349:12:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_OracleValue_$834_storage\",\n                          \"typeString\": \"struct FetchOracle.OracleValue storage ref\"\n                        }\n                      },\n                      \"id\": 1046,\n                      \"isConstant\": false,\n                      \"isLValue\": true,\n                      \"isPure\": false,\n                      \"lValueRequested\": true,\n                      \"memberName\": \"decimals\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": 831,\n                      \"src\": \"4349:21:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint8\",\n                        \"typeString\": \"uint8\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 1047,\n                      \"name\": \"decimals\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 1028,\n                      \"src\": \"4373:8:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint8\",\n                        \"typeString\": \"uint8\"\n                      }\n                    },\n                    \"src\": \"4349:32:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint8\",\n                      \"typeString\": \"uint8\"\n                    }\n                  },\n                  \"id\": 1049,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"4349:32:4\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 1055,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 1050,\n                        \"name\": \"_oracleValue\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 885,\n                        \"src\": \"4391:12:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_OracleValue_$834_storage\",\n                          \"typeString\": \"struct FetchOracle.OracleValue storage ref\"\n                        }\n                      },\n                      \"id\": 1052,\n                      \"isConstant\": false,\n                      \"isLValue\": true,\n                      \"isPure\": false,\n                      \"lValueRequested\": true,\n                      \"memberName\": \"updatedAtEthBlockNumber\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": 833,\n                      \"src\": \"4391:36:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"arguments\": [],\n                      \"expression\": {\n                        \"argumentTypes\": [],\n                        \"id\": 1053,\n                        \"name\": \"_getBlockNumber\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 1314,\n                        \"src\": \"4430:15:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_function_internal_view$__$returns$_t_uint256_$\",\n                          \"typeString\": \"function () view returns (uint256)\"\n                        }\n                      },\n                      \"id\": 1054,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": false,\n                      \"kind\": \"functionCall\",\n                      \"lValueRequested\": false,\n                      \"names\": [],\n                      \"nodeType\": \"FunctionCall\",\n                      \"src\": \"4430:17:4\",\n                      \"tryCall\": false,\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"src\": \"4391:56:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"id\": 1056,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"4391:56:4\"\n                },\n                {\n                  \"eventCall\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 1058,\n                          \"name\": \"_oracleValue\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 885,\n                          \"src\": \"4481:12:4\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_struct$_OracleValue_$834_storage\",\n                            \"typeString\": \"struct FetchOracle.OracleValue storage ref\"\n                          }\n                        },\n                        \"id\": 1059,\n                        \"isConstant\": false,\n                        \"isLValue\": true,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"memberName\": \"updatedAtEthBlockNumber\",\n                        \"nodeType\": \"MemberAccess\",\n                        \"referencedDeclaration\": 833,\n                        \"src\": \"4481:36:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"id\": 1057,\n                      \"name\": \"OracleValueUpdated\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 860,\n                      \"src\": \"4462:18:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_event_nonpayable$_t_uint256_$returns$__$\",\n                        \"typeString\": \"function (uint256)\"\n                      }\n                    },\n                    \"id\": 1060,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"4462:56:4\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 1061,\n                  \"nodeType\": \"EmitStatement\",\n                  \"src\": \"4457:61:4\"\n                }\n              ]\n            },\n            \"documentation\": null,\n            \"functionSelector\": \"59f9f7cc\",\n            \"id\": 1063,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [\n              {\n                \"arguments\": [\n                  {\n                    \"argumentTypes\": null,\n                    \"id\": 1033,\n                    \"name\": \"txExpirationBlock\",\n                    \"nodeType\": \"Identifier\",\n                    \"overloadedDeclarations\": [],\n                    \"referencedDeclaration\": 1030,\n                    \"src\": \"4261:17:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  }\n                ],\n                \"id\": 1034,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 1032,\n                  \"name\": \"verifyTxExpiration\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 952,\n                  \"src\": \"4242:18:4\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$_t_uint256_$\",\n                    \"typeString\": \"modifier (uint256)\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"4242:37:4\"\n              },\n              {\n                \"arguments\": null,\n                \"id\": 1036,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 1035,\n                  \"name\": \"onlyOracle\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 938,\n                  \"src\": \"4288:10:4\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$__$\",\n                    \"typeString\": \"modifier ()\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"4288:10:4\"\n              }\n            ],\n            \"name\": \"updateOracleValue\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 1031,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 1026,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"value\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 1063,\n                  \"src\": \"4134:13:4\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 1025,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"4134:7:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 1028,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"decimals\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 1063,\n                  \"src\": \"4157:14:4\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint8\",\n                    \"typeString\": \"uint8\"\n                  },\n                  \"typeName\": {\n                    \"id\": 1027,\n                    \"name\": \"uint8\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"4157:5:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint8\",\n                      \"typeString\": \"uint8\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 1030,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"txExpirationBlock\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 1063,\n                  \"src\": \"4181:25:4\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 1029,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"4181:7:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"4124:92:4\"\n            },\n            \"returnParameters\": {\n              \"id\": 1037,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"4303:0:4\"\n            },\n            \"scope\": 1440,\n            \"src\": \"4098:428:4\",\n            \"stateMutability\": \"nonpayable\",\n            \"virtual\": false,\n            \"visibility\": \"external\"\n          },\n          {\n            \"body\": {\n              \"id\": 1090,\n              \"nodeType\": \"Block\",\n              \"src\": \"4669:181:4\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [],\n                    \"expression\": {\n                      \"argumentTypes\": [],\n                      \"id\": 1072,\n                      \"name\": \"_withdrawFee\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 1388,\n                      \"src\": \"4679:12:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_nonpayable$__$returns$__$\",\n                        \"typeString\": \"function ()\"\n                      }\n                    },\n                    \"id\": 1073,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"4679:14:4\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 1074,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"4679:14:4\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 1078,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 1075,\n                      \"name\": \"value\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 1066,\n                      \"src\": \"4703:5:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 1076,\n                        \"name\": \"_oracleValue\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 885,\n                        \"src\": \"4711:12:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_OracleValue_$834_storage\",\n                          \"typeString\": \"struct FetchOracle.OracleValue storage ref\"\n                        }\n                      },\n                      \"id\": 1077,\n                      \"isConstant\": false,\n                      \"isLValue\": true,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"memberName\": \"value\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": 829,\n                      \"src\": \"4711:18:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"src\": \"4703:26:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"id\": 1079,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"4703:26:4\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 1083,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 1080,\n                      \"name\": \"decimals\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 1068,\n                      \"src\": \"4739:8:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint8\",\n                        \"typeString\": \"uint8\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 1081,\n                        \"name\": \"_oracleValue\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 885,\n                        \"src\": \"4750:12:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_OracleValue_$834_storage\",\n                          \"typeString\": \"struct FetchOracle.OracleValue storage ref\"\n                        }\n                      },\n                      \"id\": 1082,\n                      \"isConstant\": false,\n                      \"isLValue\": true,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"memberName\": \"decimals\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": 831,\n                      \"src\": \"4750:21:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint8\",\n                        \"typeString\": \"uint8\"\n                      }\n                    },\n                    \"src\": \"4739:32:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint8\",\n                      \"typeString\": \"uint8\"\n                    }\n                  },\n                  \"id\": 1084,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"4739:32:4\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 1088,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 1085,\n                      \"name\": \"updatedAtEthBlockNumber\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 1070,\n                      \"src\": \"4781:23:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 1086,\n                        \"name\": \"_oracleValue\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 885,\n                        \"src\": \"4807:12:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_OracleValue_$834_storage\",\n                          \"typeString\": \"struct FetchOracle.OracleValue storage ref\"\n                        }\n                      },\n                      \"id\": 1087,\n                      \"isConstant\": false,\n                      \"isLValue\": true,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"memberName\": \"updatedAtEthBlockNumber\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": 833,\n                      \"src\": \"4807:36:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"src\": \"4781:62:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"id\": 1089,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"4781:62:4\"\n                }\n              ]\n            },\n            \"documentation\": null,\n            \"functionSelector\": \"f7e1c748\",\n            \"id\": 1091,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [],\n            \"name\": \"queryOracleValue\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 1064,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"4558:2:4\"\n            },\n            \"returnParameters\": {\n              \"id\": 1071,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 1066,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"value\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 1091,\n                  \"src\": \"4601:13:4\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 1065,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"4601:7:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 1068,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"decimals\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 1091,\n                  \"src\": \"4616:14:4\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint8\",\n                    \"typeString\": \"uint8\"\n                  },\n                  \"typeName\": {\n                    \"id\": 1067,\n                    \"name\": \"uint8\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"4616:5:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint8\",\n                      \"typeString\": \"uint8\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 1070,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"updatedAtEthBlockNumber\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 1091,\n                  \"src\": \"4632:31:4\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 1069,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"4632:7:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"4600:64:4\"\n            },\n            \"scope\": 1440,\n            \"src\": \"4533:317:4\",\n            \"stateMutability\": \"payable\",\n            \"virtual\": false,\n            \"visibility\": \"public\"\n          },\n          {\n            \"body\": {\n              \"id\": 1112,\n              \"nodeType\": \"Block\",\n              \"src\": \"5254:58:4\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 1106,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 1104,\n                      \"name\": \"_fee\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 881,\n                      \"src\": \"5264:4:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 1105,\n                      \"name\": \"fee\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 1094,\n                      \"src\": \"5271:3:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"src\": \"5264:10:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"id\": 1107,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"5264:10:4\"\n                },\n                {\n                  \"eventCall\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 1109,\n                        \"name\": \"_fee\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 881,\n                        \"src\": \"5300:4:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"id\": 1108,\n                      \"name\": \"FeeUpdated\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 838,\n                      \"src\": \"5289:10:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_event_nonpayable$_t_uint256_$returns$__$\",\n                        \"typeString\": \"function (uint256)\"\n                      }\n                    },\n                    \"id\": 1110,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"5289:16:4\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 1111,\n                  \"nodeType\": \"EmitStatement\",\n                  \"src\": \"5284:21:4\"\n                }\n              ]\n            },\n            \"documentation\": {\n              \"id\": 1092,\n              \"nodeType\": \"StructuredDocumentation\",\n              \"src\": \"4857:248:4\",\n              \"text\": \"@dev Pause the non-administrative interaction with the contract\\n@param fee - value of fee\\n@param txExpirationBlock - block number defined by Tx sender beyond which transaction becomes invalid\\n@dev Owners only\"\n            },\n            \"functionSelector\": \"52f7c988\",\n            \"id\": 1113,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [\n              {\n                \"arguments\": [\n                  {\n                    \"argumentTypes\": null,\n                    \"id\": 1099,\n                    \"name\": \"txExpirationBlock\",\n                    \"nodeType\": \"Identifier\",\n                    \"overloadedDeclarations\": [],\n                    \"referencedDeclaration\": 1096,\n                    \"src\": \"5210:17:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  }\n                ],\n                \"id\": 1100,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 1098,\n                  \"name\": \"verifyTxExpiration\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 952,\n                  \"src\": \"5191:18:4\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$_t_uint256_$\",\n                    \"typeString\": \"modifier (uint256)\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"5191:37:4\"\n              },\n              {\n                \"arguments\": null,\n                \"id\": 1102,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 1101,\n                  \"name\": \"onlyDelegate\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 925,\n                  \"src\": \"5237:12:4\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$__$\",\n                    \"typeString\": \"modifier ()\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"5237:12:4\"\n              }\n            ],\n            \"name\": \"setFee\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 1097,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 1094,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"fee\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 1113,\n                  \"src\": \"5126:11:4\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 1093,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"5126:7:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 1096,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"txExpirationBlock\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 1113,\n                  \"src\": \"5139:25:4\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 1095,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"5139:7:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"5125:40:4\"\n            },\n            \"returnParameters\": {\n              \"id\": 1103,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"5254:0:4\"\n            },\n            \"scope\": 1440,\n            \"src\": \"5110:202:4\",\n            \"stateMutability\": \"nonpayable\",\n            \"virtual\": false,\n            \"visibility\": \"external\"\n          },\n          {\n            \"body\": {\n              \"id\": 1144,\n              \"nodeType\": \"Block\",\n              \"src\": \"5701:198:4\",\n              \"statements\": [\n                {\n                  \"assignments\": [\n                    1127\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 1127,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"curr_block_number\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 1144,\n                      \"src\": \"5711:25:4\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"default\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      },\n                      \"typeName\": {\n                        \"id\": 1126,\n                        \"name\": \"uint256\",\n                        \"nodeType\": \"ElementaryTypeName\",\n                        \"src\": \"5711:7:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 1130,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [],\n                    \"expression\": {\n                      \"argumentTypes\": [],\n                      \"id\": 1128,\n                      \"name\": \"_getBlockNumber\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 1314,\n                      \"src\": \"5739:15:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_view$__$returns$_t_uint256_$\",\n                        \"typeString\": \"function () view returns (uint256)\"\n                      }\n                    },\n                    \"id\": 1129,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"5739:17:4\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"5711:45:4\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 1138,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 1131,\n                      \"name\": \"_pausedSinceBlock\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 879,\n                      \"src\": \"5766:17:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"condition\": {\n                        \"argumentTypes\": null,\n                        \"commonType\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        },\n                        \"id\": 1134,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"leftExpression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 1132,\n                          \"name\": \"block_number\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 1116,\n                          \"src\": \"5786:12:4\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"nodeType\": \"BinaryOperation\",\n                        \"operator\": \"<\",\n                        \"rightExpression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 1133,\n                          \"name\": \"curr_block_number\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 1127,\n                          \"src\": \"5801:17:4\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"src\": \"5786:32:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        }\n                      },\n                      \"falseExpression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 1136,\n                        \"name\": \"block_number\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 1116,\n                        \"src\": \"5841:12:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      \"id\": 1137,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"nodeType\": \"Conditional\",\n                      \"src\": \"5786:67:4\",\n                      \"trueExpression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 1135,\n                        \"name\": \"curr_block_number\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 1127,\n                        \"src\": \"5821:17:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"src\": \"5766:87:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"id\": 1139,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"5766:87:4\"\n                },\n                {\n                  \"eventCall\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 1141,\n                        \"name\": \"_pausedSinceBlock\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 879,\n                        \"src\": \"5874:17:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"id\": 1140,\n                      \"name\": \"Pause\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 842,\n                      \"src\": \"5868:5:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_event_nonpayable$_t_uint256_$returns$__$\",\n                        \"typeString\": \"function (uint256)\"\n                      }\n                    },\n                    \"id\": 1142,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"5868:24:4\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 1143,\n                  \"nodeType\": \"EmitStatement\",\n                  \"src\": \"5863:29:4\"\n                }\n              ]\n            },\n            \"documentation\": {\n              \"id\": 1114,\n              \"nodeType\": \"StructuredDocumentation\",\n              \"src\": \"5319:220:4\",\n              \"text\": \"@dev Pause the non-administrative interaction with the contract\\n@param block_number disallow non-admin. interactions with contract for a _getBlockNumber() >= block_number\\n@dev Owners only\"\n            },\n            \"functionSelector\": \"347908df\",\n            \"id\": 1145,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [\n              {\n                \"arguments\": [\n                  {\n                    \"argumentTypes\": null,\n                    \"id\": 1121,\n                    \"name\": \"txExpirationBlock\",\n                    \"nodeType\": \"Identifier\",\n                    \"overloadedDeclarations\": [],\n                    \"referencedDeclaration\": 1118,\n                    \"src\": \"5657:17:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  }\n                ],\n                \"id\": 1122,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 1120,\n                  \"name\": \"verifyTxExpiration\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 952,\n                  \"src\": \"5638:18:4\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$_t_uint256_$\",\n                    \"typeString\": \"modifier (uint256)\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"5638:37:4\"\n              },\n              {\n                \"arguments\": null,\n                \"id\": 1124,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 1123,\n                  \"name\": \"onlyDelegate\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 925,\n                  \"src\": \"5684:12:4\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$__$\",\n                    \"typeString\": \"modifier ()\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"5684:12:4\"\n              }\n            ],\n            \"name\": \"pauseSince\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 1119,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 1116,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"block_number\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 1145,\n                  \"src\": \"5564:20:4\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 1115,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"5564:7:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 1118,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"txExpirationBlock\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 1145,\n                  \"src\": \"5586:25:4\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 1117,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"5586:7:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"5563:49:4\"\n            },\n            \"returnParameters\": {\n              \"id\": 1125,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"5701:0:4\"\n            },\n            \"scope\": 1440,\n            \"src\": \"5544:355:4\",\n            \"stateMutability\": \"nonpayable\",\n            \"virtual\": false,\n            \"visibility\": \"external\"\n          },\n          {\n            \"body\": {\n              \"id\": 1178,\n              \"nodeType\": \"Block\",\n              \"src\": \"6442:366:4\",\n              \"statements\": [\n                {\n                  \"condition\": {\n                    \"argumentTypes\": null,\n                    \"commonType\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    },\n                    \"id\": 1160,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftExpression\": {\n                      \"argumentTypes\": null,\n                      \"id\": 1158,\n                      \"name\": \"_accruedFeesAmount\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 883,\n                      \"src\": \"6456:18:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"BinaryOperation\",\n                    \"operator\": \"==\",\n                    \"rightExpression\": {\n                      \"argumentTypes\": null,\n                      \"hexValue\": \"30\",\n                      \"id\": 1159,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": true,\n                      \"kind\": \"number\",\n                      \"lValueRequested\": false,\n                      \"nodeType\": \"Literal\",\n                      \"src\": \"6478:1:4\",\n                      \"subdenomination\": null,\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_rational_0_by_1\",\n                        \"typeString\": \"int_const 0\"\n                      },\n                      \"value\": \"0\"\n                    },\n                    \"src\": \"6456:23:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_bool\",\n                      \"typeString\": \"bool\"\n                    }\n                  },\n                  \"falseBody\": null,\n                  \"id\": 1163,\n                  \"nodeType\": \"IfStatement\",\n                  \"src\": \"6452:60:4\",\n                  \"trueBody\": {\n                    \"id\": 1162,\n                    \"nodeType\": \"Block\",\n                    \"src\": \"6481:31:4\",\n                    \"statements\": [\n                      {\n                        \"expression\": null,\n                        \"functionReturnParameters\": 1157,\n                        \"id\": 1161,\n                        \"nodeType\": \"Return\",\n                        \"src\": \"6495:7:4\"\n                      }\n                    ]\n                  }\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 1165,\n                        \"name\": \"targetAddress\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 1148,\n                        \"src\": \"6663:13:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 1166,\n                        \"name\": \"_accruedFeesAmount\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 883,\n                        \"src\": \"6678:18:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"id\": 1164,\n                      \"name\": \"_withdrawFromContract\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 1439,\n                      \"src\": \"6641:21:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_nonpayable$_t_address_payable_$_t_uint256_$returns$__$\",\n                        \"typeString\": \"function (address payable,uint256)\"\n                      }\n                    },\n                    \"id\": 1167,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"6641:56:4\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 1168,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"6641:56:4\"\n                },\n                {\n                  \"eventCall\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 1170,\n                        \"name\": \"targetAddress\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 1148,\n                        \"src\": \"6735:13:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 1171,\n                        \"name\": \"_accruedFeesAmount\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 883,\n                        \"src\": \"6750:18:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"id\": 1169,\n                      \"name\": \"AccruedFeesWithdrawal\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 854,\n                      \"src\": \"6713:21:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_event_nonpayable$_t_address_$_t_uint256_$returns$__$\",\n                        \"typeString\": \"function (address,uint256)\"\n                      }\n                    },\n                    \"id\": 1172,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"6713:56:4\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 1173,\n                  \"nodeType\": \"EmitStatement\",\n                  \"src\": \"6708:61:4\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 1176,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 1174,\n                      \"name\": \"_accruedFeesAmount\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 883,\n                      \"src\": \"6779:18:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"hexValue\": \"30\",\n                      \"id\": 1175,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": true,\n                      \"kind\": \"number\",\n                      \"lValueRequested\": false,\n                      \"nodeType\": \"Literal\",\n                      \"src\": \"6800:1:4\",\n                      \"subdenomination\": null,\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_rational_0_by_1\",\n                        \"typeString\": \"int_const 0\"\n                      },\n                      \"value\": \"0\"\n                    },\n                    \"src\": \"6779:22:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"id\": 1177,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"6779:22:4\"\n                }\n              ]\n            },\n            \"documentation\": {\n              \"id\": 1146,\n              \"nodeType\": \"StructuredDocumentation\",\n              \"src\": \"5906:359:4\",\n              \"text\": \"@dev Withdraw whole balance of all fees accrued in the contract so far.\\n@param targetAddress : address to send tokens to\\n@param txExpirationBlock : block number until which is the transaction valid (inclusive).\\n                           When transaction is processed after this block, it fails.\\n@dev Owners only\"\n            },\n            \"functionSelector\": \"323f4501\",\n            \"id\": 1179,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [\n              {\n                \"arguments\": [\n                  {\n                    \"argumentTypes\": null,\n                    \"id\": 1153,\n                    \"name\": \"txExpirationBlock\",\n                    \"nodeType\": \"Identifier\",\n                    \"overloadedDeclarations\": [],\n                    \"referencedDeclaration\": 1150,\n                    \"src\": \"6401:17:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  }\n                ],\n                \"id\": 1154,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 1152,\n                  \"name\": \"verifyTxExpiration\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 952,\n                  \"src\": \"6382:18:4\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$_t_uint256_$\",\n                    \"typeString\": \"modifier (uint256)\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"6382:37:4\"\n              },\n              {\n                \"arguments\": null,\n                \"id\": 1156,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 1155,\n                  \"name\": \"onlyOwner\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 909,\n                  \"src\": \"6428:9:4\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$__$\",\n                    \"typeString\": \"modifier ()\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"6428:9:4\"\n              }\n            ],\n            \"name\": \"withdrawAccruedFees\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 1151,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 1148,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"targetAddress\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 1179,\n                  \"src\": \"6299:29:4\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_address_payable\",\n                    \"typeString\": \"address payable\"\n                  },\n                  \"typeName\": {\n                    \"id\": 1147,\n                    \"name\": \"address\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"6299:15:4\",\n                    \"stateMutability\": \"payable\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address_payable\",\n                      \"typeString\": \"address payable\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 1150,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"txExpirationBlock\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 1179,\n                  \"src\": \"6330:25:4\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 1149,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"6330:7:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"6298:58:4\"\n            },\n            \"returnParameters\": {\n              \"id\": 1157,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"6442:0:4\"\n            },\n            \"scope\": 1440,\n            \"src\": \"6270:538:4\",\n            \"stateMutability\": \"nonpayable\",\n            \"virtual\": false,\n            \"visibility\": \"external\"\n          },\n          {\n            \"body\": {\n              \"id\": 1242,\n              \"nodeType\": \"Block\",\n              \"src\": \"7644:794:4\",\n              \"statements\": [\n                {\n                  \"assignments\": [\n                    1193\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 1193,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"contractBalance\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 1242,\n                      \"src\": \"7654:23:4\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"default\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      },\n                      \"typeName\": {\n                        \"id\": 1192,\n                        \"name\": \"uint256\",\n                        \"nodeType\": \"ElementaryTypeName\",\n                        \"src\": \"7654:7:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 1194,\n                  \"initialValue\": null,\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"7654:23:4\"\n                },\n                {\n                  \"condition\": {\n                    \"argumentTypes\": null,\n                    \"commonType\": {\n                      \"typeIdentifier\": \"t_enum$_FeeCurrency_$827\",\n                      \"typeString\": \"enum FetchOracle.FeeCurrency\"\n                    },\n                    \"id\": 1198,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftExpression\": {\n                      \"argumentTypes\": null,\n                      \"id\": 1195,\n                      \"name\": \"_feeCurrency\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 887,\n                      \"src\": \"7692:12:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_enum$_FeeCurrency_$827\",\n                        \"typeString\": \"enum FetchOracle.FeeCurrency\"\n                      }\n                    },\n                    \"nodeType\": \"BinaryOperation\",\n                    \"operator\": \"==\",\n                    \"rightExpression\": {\n                      \"argumentTypes\": null,\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 1196,\n                        \"name\": \"FeeCurrency\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 827,\n                        \"src\": \"7708:11:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_type$_t_enum$_FeeCurrency_$827_$\",\n                          \"typeString\": \"type(enum FetchOracle.FeeCurrency)\"\n                        }\n                      },\n                      \"id\": 1197,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": true,\n                      \"lValueRequested\": false,\n                      \"memberName\": \"ETH\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": null,\n                      \"src\": \"7708:15:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_enum$_FeeCurrency_$827\",\n                        \"typeString\": \"enum FetchOracle.FeeCurrency\"\n                      }\n                    },\n                    \"src\": \"7692:31:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_bool\",\n                      \"typeString\": \"bool\"\n                    }\n                  },\n                  \"falseBody\": {\n                    \"condition\": {\n                      \"argumentTypes\": null,\n                      \"commonType\": {\n                        \"typeIdentifier\": \"t_enum$_FeeCurrency_$827\",\n                        \"typeString\": \"enum FetchOracle.FeeCurrency\"\n                      },\n                      \"id\": 1211,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"leftExpression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 1208,\n                        \"name\": \"_feeCurrency\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 887,\n                        \"src\": \"7815:12:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_enum$_FeeCurrency_$827\",\n                          \"typeString\": \"enum FetchOracle.FeeCurrency\"\n                        }\n                      },\n                      \"nodeType\": \"BinaryOperation\",\n                      \"operator\": \"==\",\n                      \"rightExpression\": {\n                        \"argumentTypes\": null,\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 1209,\n                          \"name\": \"FeeCurrency\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 827,\n                          \"src\": \"7831:11:4\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_type$_t_enum$_FeeCurrency_$827_$\",\n                            \"typeString\": \"type(enum FetchOracle.FeeCurrency)\"\n                          }\n                        },\n                        \"id\": 1210,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": true,\n                        \"lValueRequested\": false,\n                        \"memberName\": \"ERC20\",\n                        \"nodeType\": \"MemberAccess\",\n                        \"referencedDeclaration\": null,\n                        \"src\": \"7831:17:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_enum$_FeeCurrency_$827\",\n                          \"typeString\": \"enum FetchOracle.FeeCurrency\"\n                        }\n                      },\n                      \"src\": \"7815:33:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_bool\",\n                        \"typeString\": \"bool\"\n                      }\n                    },\n                    \"falseBody\": null,\n                    \"id\": 1223,\n                    \"nodeType\": \"IfStatement\",\n                    \"src\": \"7811:113:4\",\n                    \"trueBody\": {\n                      \"id\": 1222,\n                      \"nodeType\": \"Block\",\n                      \"src\": \"7850:74:4\",\n                      \"statements\": [\n                        {\n                          \"expression\": {\n                            \"argumentTypes\": null,\n                            \"id\": 1220,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": false,\n                            \"lValueRequested\": false,\n                            \"leftHandSide\": {\n                              \"argumentTypes\": null,\n                              \"id\": 1212,\n                              \"name\": \"contractBalance\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 1193,\n                              \"src\": \"7864:15:4\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_uint256\",\n                                \"typeString\": \"uint256\"\n                              }\n                            },\n                            \"nodeType\": \"Assignment\",\n                            \"operator\": \"=\",\n                            \"rightHandSide\": {\n                              \"argumentTypes\": null,\n                              \"arguments\": [\n                                {\n                                  \"argumentTypes\": null,\n                                  \"arguments\": [\n                                    {\n                                      \"argumentTypes\": null,\n                                      \"id\": 1217,\n                                      \"name\": \"this\",\n                                      \"nodeType\": \"Identifier\",\n                                      \"overloadedDeclarations\": [],\n                                      \"referencedDeclaration\": -28,\n                                      \"src\": \"7907:4:4\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_contract$_FetchOracle_$1440\",\n                                        \"typeString\": \"contract FetchOracle\"\n                                      }\n                                    }\n                                  ],\n                                  \"expression\": {\n                                    \"argumentTypes\": [\n                                      {\n                                        \"typeIdentifier\": \"t_contract$_FetchOracle_$1440\",\n                                        \"typeString\": \"contract FetchOracle\"\n                                      }\n                                    ],\n                                    \"id\": 1216,\n                                    \"isConstant\": false,\n                                    \"isLValue\": false,\n                                    \"isPure\": true,\n                                    \"lValueRequested\": false,\n                                    \"nodeType\": \"ElementaryTypeNameExpression\",\n                                    \"src\": \"7899:7:4\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_type$_t_address_$\",\n                                      \"typeString\": \"type(address)\"\n                                    },\n                                    \"typeName\": {\n                                      \"id\": 1215,\n                                      \"name\": \"address\",\n                                      \"nodeType\": \"ElementaryTypeName\",\n                                      \"src\": \"7899:7:4\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": null,\n                                        \"typeString\": null\n                                      }\n                                    }\n                                  },\n                                  \"id\": 1218,\n                                  \"isConstant\": false,\n                                  \"isLValue\": false,\n                                  \"isPure\": false,\n                                  \"kind\": \"typeConversion\",\n                                  \"lValueRequested\": false,\n                                  \"names\": [],\n                                  \"nodeType\": \"FunctionCall\",\n                                  \"src\": \"7899:13:4\",\n                                  \"tryCall\": false,\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_address\",\n                                    \"typeString\": \"address\"\n                                  }\n                                }\n                              ],\n                              \"expression\": {\n                                \"argumentTypes\": [\n                                  {\n                                    \"typeIdentifier\": \"t_address\",\n                                    \"typeString\": \"address\"\n                                  }\n                                ],\n                                \"expression\": {\n                                  \"argumentTypes\": null,\n                                  \"id\": 1213,\n                                  \"name\": \"_token\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 875,\n                                  \"src\": \"7882:6:4\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_contract$_IERC20_$2649\",\n                                    \"typeString\": \"contract IERC20\"\n                                  }\n                                },\n                                \"id\": 1214,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": false,\n                                \"lValueRequested\": false,\n                                \"memberName\": \"balanceOf\",\n                                \"nodeType\": \"MemberAccess\",\n                                \"referencedDeclaration\": 2588,\n                                \"src\": \"7882:16:4\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_function_external_view$_t_address_$returns$_t_uint256_$\",\n                                  \"typeString\": \"function (address) view external returns (uint256)\"\n                                }\n                              },\n                              \"id\": 1219,\n                              \"isConstant\": false,\n                              \"isLValue\": false,\n                              \"isPure\": false,\n                              \"kind\": \"functionCall\",\n                              \"lValueRequested\": false,\n                              \"names\": [],\n                              \"nodeType\": \"FunctionCall\",\n                              \"src\": \"7882:31:4\",\n                              \"tryCall\": false,\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_uint256\",\n                                \"typeString\": \"uint256\"\n                              }\n                            },\n                            \"src\": \"7864:49:4\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"id\": 1221,\n                          \"nodeType\": \"ExpressionStatement\",\n                          \"src\": \"7864:49:4\"\n                        }\n                      ]\n                    }\n                  },\n                  \"id\": 1224,\n                  \"nodeType\": \"IfStatement\",\n                  \"src\": \"7688:236:4\",\n                  \"trueBody\": {\n                    \"id\": 1207,\n                    \"nodeType\": \"Block\",\n                    \"src\": \"7733:64:4\",\n                    \"statements\": [\n                      {\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 1205,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"leftHandSide\": {\n                            \"argumentTypes\": null,\n                            \"id\": 1199,\n                            \"name\": \"contractBalance\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 1193,\n                            \"src\": \"7747:15:4\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"nodeType\": \"Assignment\",\n                          \"operator\": \"=\",\n                          \"rightHandSide\": {\n                            \"argumentTypes\": null,\n                            \"expression\": {\n                              \"argumentTypes\": null,\n                              \"arguments\": [\n                                {\n                                  \"argumentTypes\": null,\n                                  \"id\": 1202,\n                                  \"name\": \"this\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": -28,\n                                  \"src\": \"7773:4:4\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_contract$_FetchOracle_$1440\",\n                                    \"typeString\": \"contract FetchOracle\"\n                                  }\n                                }\n                              ],\n                              \"expression\": {\n                                \"argumentTypes\": [\n                                  {\n                                    \"typeIdentifier\": \"t_contract$_FetchOracle_$1440\",\n                                    \"typeString\": \"contract FetchOracle\"\n                                  }\n                                ],\n                                \"id\": 1201,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": true,\n                                \"lValueRequested\": false,\n                                \"nodeType\": \"ElementaryTypeNameExpression\",\n                                \"src\": \"7765:7:4\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_type$_t_address_$\",\n                                  \"typeString\": \"type(address)\"\n                                },\n                                \"typeName\": {\n                                  \"id\": 1200,\n                                  \"name\": \"address\",\n                                  \"nodeType\": \"ElementaryTypeName\",\n                                  \"src\": \"7765:7:4\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": null,\n                                    \"typeString\": null\n                                  }\n                                }\n                              },\n                              \"id\": 1203,\n                              \"isConstant\": false,\n                              \"isLValue\": false,\n                              \"isPure\": false,\n                              \"kind\": \"typeConversion\",\n                              \"lValueRequested\": false,\n                              \"names\": [],\n                              \"nodeType\": \"FunctionCall\",\n                              \"src\": \"7765:13:4\",\n                              \"tryCall\": false,\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_address\",\n                                \"typeString\": \"address\"\n                              }\n                            },\n                            \"id\": 1204,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": false,\n                            \"lValueRequested\": false,\n                            \"memberName\": \"balance\",\n                            \"nodeType\": \"MemberAccess\",\n                            \"referencedDeclaration\": null,\n                            \"src\": \"7765:21:4\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"src\": \"7747:39:4\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"id\": 1206,\n                        \"nodeType\": \"ExpressionStatement\",\n                        \"src\": \"7747:39:4\"\n                      }\n                    ]\n                  }\n                },\n                {\n                  \"assignments\": [\n                    1226\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 1226,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"excessAmount\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 1242,\n                      \"src\": \"8244:20:4\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"default\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      },\n                      \"typeName\": {\n                        \"id\": 1225,\n                        \"name\": \"uint256\",\n                        \"nodeType\": \"ElementaryTypeName\",\n                        \"src\": \"8244:7:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 1231,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 1229,\n                        \"name\": \"_accruedFeesAmount\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 883,\n                        \"src\": \"8287:18:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 1227,\n                        \"name\": \"contractBalance\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 1193,\n                        \"src\": \"8267:15:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      \"id\": 1228,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"memberName\": \"sub\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": 1829,\n                      \"src\": \"8267:19:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_pure$_t_uint256_$_t_uint256_$returns$_t_uint256_$bound_to$_t_uint256_$\",\n                        \"typeString\": \"function (uint256,uint256) pure returns (uint256)\"\n                      }\n                    },\n                    \"id\": 1230,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"8267:39:4\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"8244:62:4\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 1233,\n                        \"name\": \"targetAddress\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 1182,\n                        \"src\": \"8338:13:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 1234,\n                        \"name\": \"excessAmount\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 1226,\n                        \"src\": \"8353:12:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"id\": 1232,\n                      \"name\": \"_withdrawFromContract\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 1439,\n                      \"src\": \"8316:21:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_nonpayable$_t_address_payable_$_t_uint256_$returns$__$\",\n                        \"typeString\": \"function (address payable,uint256)\"\n                      }\n                    },\n                    \"id\": 1235,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"8316:50:4\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 1236,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"8316:50:4\"\n                },\n                {\n                  \"eventCall\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 1238,\n                        \"name\": \"targetAddress\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 1182,\n                        \"src\": \"8403:13:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 1239,\n                        \"name\": \"excessAmount\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 1226,\n                        \"src\": \"8418:12:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"id\": 1237,\n                      \"name\": \"ExcessTokenWithdrawal\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 848,\n                      \"src\": \"8381:21:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_event_nonpayable$_t_address_$_t_uint256_$returns$__$\",\n                        \"typeString\": \"function (address,uint256)\"\n                      }\n                    },\n                    \"id\": 1240,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"8381:50:4\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 1241,\n                  \"nodeType\": \"EmitStatement\",\n                  \"src\": \"8376:55:4\"\n                }\n              ]\n            },\n            \"documentation\": {\n              \"id\": 1180,\n              \"nodeType\": \"StructuredDocumentation\",\n              \"src\": \"6815:651:4\",\n              \"text\": \"@dev Withdraw \\\"excess\\\" tokens, which were sent to contract address directly via direct ERC20 transfer(...) or transferFrom(...),\\n     without interacting with API of this (FetchOracle) contract, what could be done only by mistake.\\n     Thus this method is meant to be used primarily for rescue purposes, enabling withdrawal of such\\n     \\\"excess\\\" tokens out of contract.\\n@param targetAddress : address to send tokens to\\n@param txExpirationBlock : block number until which is the transaction valid (inclusive).\\n                           When transaction is processed after this block, it fails.\"\n            },\n            \"functionSelector\": \"53e052ac\",\n            \"id\": 1243,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [\n              {\n                \"arguments\": [\n                  {\n                    \"argumentTypes\": null,\n                    \"id\": 1187,\n                    \"name\": \"txExpirationBlock\",\n                    \"nodeType\": \"Identifier\",\n                    \"overloadedDeclarations\": [],\n                    \"referencedDeclaration\": 1184,\n                    \"src\": \"7603:17:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  }\n                ],\n                \"id\": 1188,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 1186,\n                  \"name\": \"verifyTxExpiration\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 952,\n                  \"src\": \"7584:18:4\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$_t_uint256_$\",\n                    \"typeString\": \"modifier (uint256)\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"7584:37:4\"\n              },\n              {\n                \"arguments\": null,\n                \"id\": 1190,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 1189,\n                  \"name\": \"onlyOwner\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 909,\n                  \"src\": \"7630:9:4\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$__$\",\n                    \"typeString\": \"modifier ()\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"7630:9:4\"\n              }\n            ],\n            \"name\": \"withdrawExcessTokens\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 1185,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 1182,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"targetAddress\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 1243,\n                  \"src\": \"7501:29:4\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_address_payable\",\n                    \"typeString\": \"address payable\"\n                  },\n                  \"typeName\": {\n                    \"id\": 1181,\n                    \"name\": \"address\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"7501:15:4\",\n                    \"stateMutability\": \"payable\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address_payable\",\n                      \"typeString\": \"address payable\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 1184,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"txExpirationBlock\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 1243,\n                  \"src\": \"7532:25:4\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 1183,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"7532:7:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"7500:58:4\"\n            },\n            \"returnParameters\": {\n              \"id\": 1191,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"7644:0:4\"\n            },\n            \"scope\": 1440,\n            \"src\": \"7471:967:4\",\n            \"stateMutability\": \"nonpayable\",\n            \"virtual\": false,\n            \"visibility\": \"external\"\n          },\n          {\n            \"body\": {\n              \"id\": 1295,\n              \"nodeType\": \"Block\",\n              \"src\": \"8926:469:4\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"commonType\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        },\n                        \"id\": 1260,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"leftExpression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 1257,\n                          \"name\": \"_earliestDelete\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 877,\n                          \"src\": \"8944:15:4\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"nodeType\": \"BinaryOperation\",\n                        \"operator\": \">=\",\n                        \"rightExpression\": {\n                          \"argumentTypes\": null,\n                          \"arguments\": [],\n                          \"expression\": {\n                            \"argumentTypes\": [],\n                            \"id\": 1258,\n                            \"name\": \"_getBlockNumber\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 1314,\n                            \"src\": \"8963:15:4\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_function_internal_view$__$returns$_t_uint256_$\",\n                              \"typeString\": \"function () view returns (uint256)\"\n                            }\n                          },\n                          \"id\": 1259,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"kind\": \"functionCall\",\n                          \"lValueRequested\": false,\n                          \"names\": [],\n                          \"nodeType\": \"FunctionCall\",\n                          \"src\": \"8963:17:4\",\n                          \"tryCall\": false,\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"src\": \"8944:36:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"hexValue\": \"4561726c696573742064656c657465206e6f742072656163686564\",\n                        \"id\": 1261,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": true,\n                        \"kind\": \"string\",\n                        \"lValueRequested\": false,\n                        \"nodeType\": \"Literal\",\n                        \"src\": \"8982:29:4\",\n                        \"subdenomination\": null,\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_stringliteral_5f181249ab5034a5754d3db6b5f7492a28b118cbf69c6f93d3cfe542886db22a\",\n                          \"typeString\": \"literal_string \\\"Earliest delete not reached\\\"\"\n                        },\n                        \"value\": \"Earliest delete not reached\"\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_stringliteral_5f181249ab5034a5754d3db6b5f7492a28b118cbf69c6f93d3cfe542886db22a\",\n                          \"typeString\": \"literal_string \\\"Earliest delete not reached\\\"\"\n                        }\n                      ],\n                      \"id\": 1256,\n                      \"name\": \"require\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [\n                        -18,\n                        -18\n                      ],\n                      \"referencedDeclaration\": -18,\n                      \"src\": \"8936:7:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$\",\n                        \"typeString\": \"function (bool,string memory) pure\"\n                      }\n                    },\n                    \"id\": 1262,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"8936:76:4\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 1263,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"8936:76:4\"\n                },\n                {\n                  \"condition\": {\n                    \"argumentTypes\": null,\n                    \"commonType\": {\n                      \"typeIdentifier\": \"t_enum$_FeeCurrency_$827\",\n                      \"typeString\": \"enum FetchOracle.FeeCurrency\"\n                    },\n                    \"id\": 1267,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftExpression\": {\n                      \"argumentTypes\": null,\n                      \"id\": 1264,\n                      \"name\": \"_feeCurrency\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 887,\n                      \"src\": \"9026:12:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_enum$_FeeCurrency_$827\",\n                        \"typeString\": \"enum FetchOracle.FeeCurrency\"\n                      }\n                    },\n                    \"nodeType\": \"BinaryOperation\",\n                    \"operator\": \"==\",\n                    \"rightExpression\": {\n                      \"argumentTypes\": null,\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 1265,\n                        \"name\": \"FeeCurrency\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 827,\n                        \"src\": \"9042:11:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_type$_t_enum$_FeeCurrency_$827_$\",\n                          \"typeString\": \"type(enum FetchOracle.FeeCurrency)\"\n                        }\n                      },\n                      \"id\": 1266,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": true,\n                      \"lValueRequested\": false,\n                      \"memberName\": \"ERC20\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": null,\n                      \"src\": \"9042:17:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_enum$_FeeCurrency_$827\",\n                        \"typeString\": \"enum FetchOracle.FeeCurrency\"\n                      }\n                    },\n                    \"src\": \"9026:33:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_bool\",\n                      \"typeString\": \"bool\"\n                    }\n                  },\n                  \"falseBody\": null,\n                  \"id\": 1287,\n                  \"nodeType\": \"IfStatement\",\n                  \"src\": \"9022:191:4\",\n                  \"trueBody\": {\n                    \"id\": 1286,\n                    \"nodeType\": \"Block\",\n                    \"src\": \"9061:152:4\",\n                    \"statements\": [\n                      {\n                        \"assignments\": [\n                          1269\n                        ],\n                        \"declarations\": [\n                          {\n                            \"constant\": false,\n                            \"id\": 1269,\n                            \"mutability\": \"mutable\",\n                            \"name\": \"contractBalance\",\n                            \"nodeType\": \"VariableDeclaration\",\n                            \"overrides\": null,\n                            \"scope\": 1286,\n                            \"src\": \"9075:23:4\",\n                            \"stateVariable\": false,\n                            \"storageLocation\": \"default\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            },\n                            \"typeName\": {\n                              \"id\": 1268,\n                              \"name\": \"uint256\",\n                              \"nodeType\": \"ElementaryTypeName\",\n                              \"src\": \"9075:7:4\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_uint256\",\n                                \"typeString\": \"uint256\"\n                              }\n                            },\n                            \"value\": null,\n                            \"visibility\": \"internal\"\n                          }\n                        ],\n                        \"id\": 1277,\n                        \"initialValue\": {\n                          \"argumentTypes\": null,\n                          \"arguments\": [\n                            {\n                              \"argumentTypes\": null,\n                              \"arguments\": [\n                                {\n                                  \"argumentTypes\": null,\n                                  \"id\": 1274,\n                                  \"name\": \"this\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": -28,\n                                  \"src\": \"9126:4:4\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_contract$_FetchOracle_$1440\",\n                                    \"typeString\": \"contract FetchOracle\"\n                                  }\n                                }\n                              ],\n                              \"expression\": {\n                                \"argumentTypes\": [\n                                  {\n                                    \"typeIdentifier\": \"t_contract$_FetchOracle_$1440\",\n                                    \"typeString\": \"contract FetchOracle\"\n                                  }\n                                ],\n                                \"id\": 1273,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": true,\n                                \"lValueRequested\": false,\n                                \"nodeType\": \"ElementaryTypeNameExpression\",\n                                \"src\": \"9118:7:4\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_type$_t_address_$\",\n                                  \"typeString\": \"type(address)\"\n                                },\n                                \"typeName\": {\n                                  \"id\": 1272,\n                                  \"name\": \"address\",\n                                  \"nodeType\": \"ElementaryTypeName\",\n                                  \"src\": \"9118:7:4\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": null,\n                                    \"typeString\": null\n                                  }\n                                }\n                              },\n                              \"id\": 1275,\n                              \"isConstant\": false,\n                              \"isLValue\": false,\n                              \"isPure\": false,\n                              \"kind\": \"typeConversion\",\n                              \"lValueRequested\": false,\n                              \"names\": [],\n                              \"nodeType\": \"FunctionCall\",\n                              \"src\": \"9118:13:4\",\n                              \"tryCall\": false,\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_address\",\n                                \"typeString\": \"address\"\n                              }\n                            }\n                          ],\n                          \"expression\": {\n                            \"argumentTypes\": [\n                              {\n                                \"typeIdentifier\": \"t_address\",\n                                \"typeString\": \"address\"\n                              }\n                            ],\n                            \"expression\": {\n                              \"argumentTypes\": null,\n                              \"id\": 1270,\n                              \"name\": \"_token\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 875,\n                              \"src\": \"9101:6:4\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_contract$_IERC20_$2649\",\n                                \"typeString\": \"contract IERC20\"\n                              }\n                            },\n                            \"id\": 1271,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": false,\n                            \"lValueRequested\": false,\n                            \"memberName\": \"balanceOf\",\n                            \"nodeType\": \"MemberAccess\",\n                            \"referencedDeclaration\": 2588,\n                            \"src\": \"9101:16:4\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_function_external_view$_t_address_$returns$_t_uint256_$\",\n                              \"typeString\": \"function (address) view external returns (uint256)\"\n                            }\n                          },\n                          \"id\": 1276,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"kind\": \"functionCall\",\n                          \"lValueRequested\": false,\n                          \"names\": [],\n                          \"nodeType\": \"FunctionCall\",\n                          \"src\": \"9101:31:4\",\n                          \"tryCall\": false,\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"nodeType\": \"VariableDeclarationStatement\",\n                        \"src\": \"9075:57:4\"\n                      },\n                      {\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"arguments\": [\n                            {\n                              \"argumentTypes\": null,\n                              \"arguments\": [\n                                {\n                                  \"argumentTypes\": null,\n                                  \"id\": 1281,\n                                  \"name\": \"payoutAddress\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 1246,\n                                  \"src\": \"9170:13:4\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_address_payable\",\n                                    \"typeString\": \"address payable\"\n                                  }\n                                },\n                                {\n                                  \"argumentTypes\": null,\n                                  \"id\": 1282,\n                                  \"name\": \"contractBalance\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 1269,\n                                  \"src\": \"9185:15:4\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_uint256\",\n                                    \"typeString\": \"uint256\"\n                                  }\n                                }\n                              ],\n                              \"expression\": {\n                                \"argumentTypes\": [\n                                  {\n                                    \"typeIdentifier\": \"t_address_payable\",\n                                    \"typeString\": \"address payable\"\n                                  },\n                                  {\n                                    \"typeIdentifier\": \"t_uint256\",\n                                    \"typeString\": \"uint256\"\n                                  }\n                                ],\n                                \"expression\": {\n                                  \"argumentTypes\": null,\n                                  \"id\": 1279,\n                                  \"name\": \"_token\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 875,\n                                  \"src\": \"9154:6:4\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_contract$_IERC20_$2649\",\n                                    \"typeString\": \"contract IERC20\"\n                                  }\n                                },\n                                \"id\": 1280,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": false,\n                                \"lValueRequested\": false,\n                                \"memberName\": \"transfer\",\n                                \"nodeType\": \"MemberAccess\",\n                                \"referencedDeclaration\": 2598,\n                                \"src\": \"9154:15:4\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_function_external_nonpayable$_t_address_$_t_uint256_$returns$_t_bool_$\",\n                                  \"typeString\": \"function (address,uint256) external returns (bool)\"\n                                }\n                              },\n                              \"id\": 1283,\n                              \"isConstant\": false,\n                              \"isLValue\": false,\n                              \"isPure\": false,\n                              \"kind\": \"functionCall\",\n                              \"lValueRequested\": false,\n                              \"names\": [],\n                              \"nodeType\": \"FunctionCall\",\n                              \"src\": \"9154:47:4\",\n                              \"tryCall\": false,\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_bool\",\n                                \"typeString\": \"bool\"\n                              }\n                            }\n                          ],\n                          \"expression\": {\n                            \"argumentTypes\": [\n                              {\n                                \"typeIdentifier\": \"t_bool\",\n                                \"typeString\": \"bool\"\n                              }\n                            ],\n                            \"id\": 1278,\n                            \"name\": \"require\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [\n                              -18,\n                              -18\n                            ],\n                            \"referencedDeclaration\": -18,\n                            \"src\": \"9146:7:4\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_function_require_pure$_t_bool_$returns$__$\",\n                              \"typeString\": \"function (bool) pure\"\n                            }\n                          },\n                          \"id\": 1284,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"kind\": \"functionCall\",\n                          \"lValueRequested\": false,\n                          \"names\": [],\n                          \"nodeType\": \"FunctionCall\",\n                          \"src\": \"9146:56:4\",\n                          \"tryCall\": false,\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_tuple$__$\",\n                            \"typeString\": \"tuple()\"\n                          }\n                        },\n                        \"id\": 1285,\n                        \"nodeType\": \"ExpressionStatement\",\n                        \"src\": \"9146:56:4\"\n                      }\n                    ]\n                  }\n                },\n                {\n                  \"eventCall\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [],\n                    \"expression\": {\n                      \"argumentTypes\": [],\n                      \"id\": 1288,\n                      \"name\": \"ContractDeleted\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 856,\n                      \"src\": \"9227:15:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_event_nonpayable$__$returns$__$\",\n                        \"typeString\": \"function ()\"\n                      }\n                    },\n                    \"id\": 1289,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"9227:17:4\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 1290,\n                  \"nodeType\": \"EmitStatement\",\n                  \"src\": \"9222:22:4\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 1292,\n                        \"name\": \"payoutAddress\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 1246,\n                        \"src\": \"9374:13:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        }\n                      ],\n                      \"id\": 1291,\n                      \"name\": \"selfdestruct\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": -21,\n                      \"src\": \"9361:12:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_selfdestruct_nonpayable$_t_address_payable_$returns$__$\",\n                        \"typeString\": \"function (address payable)\"\n                      }\n                    },\n                    \"id\": 1293,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"9361:27:4\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 1294,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"9361:27:4\"\n                }\n              ]\n            },\n            \"documentation\": {\n              \"id\": 1244,\n              \"nodeType\": \"StructuredDocumentation\",\n              \"src\": \"8445:309:4\",\n              \"text\": \"@dev Delete the contract, transfers the remaining token and ether balance to the specified\\npayoutAddress\\n@param payoutAddress address to transfer the balances to. Ensure that this is able to handle ERC20 tokens\\n@dev owner only + only on or after `_earliestDelete` block\"\n            },\n            \"functionSelector\": \"9608df4b\",\n            \"id\": 1296,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [\n              {\n                \"arguments\": [\n                  {\n                    \"argumentTypes\": null,\n                    \"id\": 1251,\n                    \"name\": \"txExpirationBlock\",\n                    \"nodeType\": \"Identifier\",\n                    \"overloadedDeclarations\": [],\n                    \"referencedDeclaration\": 1248,\n                    \"src\": \"8885:17:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  }\n                ],\n                \"id\": 1252,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 1250,\n                  \"name\": \"verifyTxExpiration\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 952,\n                  \"src\": \"8866:18:4\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$_t_uint256_$\",\n                    \"typeString\": \"modifier (uint256)\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"8866:37:4\"\n              },\n              {\n                \"arguments\": null,\n                \"id\": 1254,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 1253,\n                  \"name\": \"onlyOwner\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 909,\n                  \"src\": \"8912:9:4\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$__$\",\n                    \"typeString\": \"modifier ()\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"8912:9:4\"\n              }\n            ],\n            \"name\": \"deleteContract\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 1249,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 1246,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"payoutAddress\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 1296,\n                  \"src\": \"8783:29:4\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_address_payable\",\n                    \"typeString\": \"address payable\"\n                  },\n                  \"typeName\": {\n                    \"id\": 1245,\n                    \"name\": \"address\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"8783:15:4\",\n                    \"stateMutability\": \"payable\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address_payable\",\n                      \"typeString\": \"address payable\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 1248,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"txExpirationBlock\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 1296,\n                  \"src\": \"8814:25:4\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 1247,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"8814:7:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"8782:58:4\"\n            },\n            \"returnParameters\": {\n              \"id\": 1255,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"8926:0:4\"\n            },\n            \"scope\": 1440,\n            \"src\": \"8759:636:4\",\n            \"stateMutability\": \"nonpayable\",\n            \"virtual\": false,\n            \"visibility\": \"external\"\n          },\n          {\n            \"body\": {\n              \"id\": 1304,\n              \"nodeType\": \"Block\",\n              \"src\": \"9471:60:4\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"expression\": {\n                      \"argumentTypes\": null,\n                      \"id\": 1301,\n                      \"name\": \"_oracleValue\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 885,\n                      \"src\": \"9488:12:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_struct$_OracleValue_$834_storage\",\n                        \"typeString\": \"struct FetchOracle.OracleValue storage ref\"\n                      }\n                    },\n                    \"id\": 1302,\n                    \"isConstant\": false,\n                    \"isLValue\": true,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"memberName\": \"updatedAtEthBlockNumber\",\n                    \"nodeType\": \"MemberAccess\",\n                    \"referencedDeclaration\": 833,\n                    \"src\": \"9488:36:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"functionReturnParameters\": 1300,\n                  \"id\": 1303,\n                  \"nodeType\": \"Return\",\n                  \"src\": \"9481:43:4\"\n                }\n              ]\n            },\n            \"documentation\": null,\n            \"functionSelector\": \"9bc18909\",\n            \"id\": 1305,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [],\n            \"name\": \"oracleValueLastUpdated\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 1297,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"9433:2:4\"\n            },\n            \"returnParameters\": {\n              \"id\": 1300,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 1299,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 1305,\n                  \"src\": \"9458:7:4\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 1298,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"9458:7:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"9457:9:4\"\n            },\n            \"scope\": 1440,\n            \"src\": \"9402:129:4\",\n            \"stateMutability\": \"view\",\n            \"virtual\": false,\n            \"visibility\": \"external\"\n          },\n          {\n            \"body\": {\n              \"id\": 1313,\n              \"nodeType\": \"Block\",\n              \"src\": \"9607:36:4\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"expression\": {\n                      \"argumentTypes\": null,\n                      \"id\": 1310,\n                      \"name\": \"block\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": -4,\n                      \"src\": \"9624:5:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_magic_block\",\n                        \"typeString\": \"block\"\n                      }\n                    },\n                    \"id\": 1311,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"memberName\": \"number\",\n                    \"nodeType\": \"MemberAccess\",\n                    \"referencedDeclaration\": null,\n                    \"src\": \"9624:12:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"functionReturnParameters\": 1309,\n                  \"id\": 1312,\n                  \"nodeType\": \"Return\",\n                  \"src\": \"9617:19:4\"\n                }\n              ]\n            },\n            \"documentation\": null,\n            \"id\": 1314,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [],\n            \"name\": \"_getBlockNumber\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 1306,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"9561:2:4\"\n            },\n            \"returnParameters\": {\n              \"id\": 1309,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 1308,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 1314,\n                  \"src\": \"9594:7:4\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 1307,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"9594:7:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"9593:9:4\"\n            },\n            \"scope\": 1440,\n            \"src\": \"9537:106:4\",\n            \"stateMutability\": \"view\",\n            \"virtual\": true,\n            \"visibility\": \"internal\"\n          },\n          {\n            \"body\": {\n              \"id\": 1387,\n              \"nodeType\": \"Block\",\n              \"src\": \"9745:1001:4\",\n              \"statements\": [\n                {\n                  \"condition\": {\n                    \"argumentTypes\": null,\n                    \"commonType\": {\n                      \"typeIdentifier\": \"t_enum$_FeeCurrency_$827\",\n                      \"typeString\": \"enum FetchOracle.FeeCurrency\"\n                    },\n                    \"id\": 1321,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftExpression\": {\n                      \"argumentTypes\": null,\n                      \"id\": 1318,\n                      \"name\": \"_feeCurrency\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 887,\n                      \"src\": \"9759:12:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_enum$_FeeCurrency_$827\",\n                        \"typeString\": \"enum FetchOracle.FeeCurrency\"\n                      }\n                    },\n                    \"nodeType\": \"BinaryOperation\",\n                    \"operator\": \"==\",\n                    \"rightExpression\": {\n                      \"argumentTypes\": null,\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 1319,\n                        \"name\": \"FeeCurrency\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 827,\n                        \"src\": \"9775:11:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_type$_t_enum$_FeeCurrency_$827_$\",\n                          \"typeString\": \"type(enum FetchOracle.FeeCurrency)\"\n                        }\n                      },\n                      \"id\": 1320,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": true,\n                      \"lValueRequested\": false,\n                      \"memberName\": \"ETH\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": null,\n                      \"src\": \"9775:15:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_enum$_FeeCurrency_$827\",\n                        \"typeString\": \"enum FetchOracle.FeeCurrency\"\n                      }\n                    },\n                    \"src\": \"9759:31:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_bool\",\n                      \"typeString\": \"bool\"\n                    }\n                  },\n                  \"falseBody\": {\n                    \"condition\": {\n                      \"argumentTypes\": null,\n                      \"commonType\": {\n                        \"typeIdentifier\": \"t_enum$_FeeCurrency_$827\",\n                        \"typeString\": \"enum FetchOracle.FeeCurrency\"\n                      },\n                      \"id\": 1356,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"leftExpression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 1353,\n                        \"name\": \"_feeCurrency\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 887,\n                        \"src\": \"10418:12:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_enum$_FeeCurrency_$827\",\n                          \"typeString\": \"enum FetchOracle.FeeCurrency\"\n                        }\n                      },\n                      \"nodeType\": \"BinaryOperation\",\n                      \"operator\": \"==\",\n                      \"rightExpression\": {\n                        \"argumentTypes\": null,\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 1354,\n                          \"name\": \"FeeCurrency\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 827,\n                          \"src\": \"10434:11:4\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_type$_t_enum$_FeeCurrency_$827_$\",\n                            \"typeString\": \"type(enum FetchOracle.FeeCurrency)\"\n                          }\n                        },\n                        \"id\": 1355,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": true,\n                        \"lValueRequested\": false,\n                        \"memberName\": \"ERC20\",\n                        \"nodeType\": \"MemberAccess\",\n                        \"referencedDeclaration\": null,\n                        \"src\": \"10434:17:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_enum$_FeeCurrency_$827\",\n                          \"typeString\": \"enum FetchOracle.FeeCurrency\"\n                        }\n                      },\n                      \"src\": \"10418:33:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_bool\",\n                        \"typeString\": \"bool\"\n                      }\n                    },\n                    \"falseBody\": {\n                      \"id\": 1377,\n                      \"nodeType\": \"Block\",\n                      \"src\": \"10605:75:4\",\n                      \"statements\": [\n                        {\n                          \"expression\": {\n                            \"argumentTypes\": null,\n                            \"arguments\": [\n                              {\n                                \"argumentTypes\": null,\n                                \"hexValue\": \"66616c7365\",\n                                \"id\": 1373,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": true,\n                                \"kind\": \"bool\",\n                                \"lValueRequested\": false,\n                                \"nodeType\": \"Literal\",\n                                \"src\": \"10627:5:4\",\n                                \"subdenomination\": null,\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_bool\",\n                                  \"typeString\": \"bool\"\n                                },\n                                \"value\": \"false\"\n                              },\n                              {\n                                \"argumentTypes\": null,\n                                \"hexValue\": \"556e657870656374656420636f6e7472616374206665652063757272656e6379\",\n                                \"id\": 1374,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": true,\n                                \"kind\": \"string\",\n                                \"lValueRequested\": false,\n                                \"nodeType\": \"Literal\",\n                                \"src\": \"10634:34:4\",\n                                \"subdenomination\": null,\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_stringliteral_f131716b743e5ec47535766db932d6974cfad176c58ab32b82f54addc42de82c\",\n                                  \"typeString\": \"literal_string \\\"Unexpected contract fee currency\\\"\"\n                                },\n                                \"value\": \"Unexpected contract fee currency\"\n                              }\n                            ],\n                            \"expression\": {\n                              \"argumentTypes\": [\n                                {\n                                  \"typeIdentifier\": \"t_bool\",\n                                  \"typeString\": \"bool\"\n                                },\n                                {\n                                  \"typeIdentifier\": \"t_stringliteral_f131716b743e5ec47535766db932d6974cfad176c58ab32b82f54addc42de82c\",\n                                  \"typeString\": \"literal_string \\\"Unexpected contract fee currency\\\"\"\n                                }\n                              ],\n                              \"id\": 1372,\n                              \"name\": \"require\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [\n                                -18,\n                                -18\n                              ],\n                              \"referencedDeclaration\": -18,\n                              \"src\": \"10619:7:4\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$\",\n                                \"typeString\": \"function (bool,string memory) pure\"\n                              }\n                            },\n                            \"id\": 1375,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": false,\n                            \"kind\": \"functionCall\",\n                            \"lValueRequested\": false,\n                            \"names\": [],\n                            \"nodeType\": \"FunctionCall\",\n                            \"src\": \"10619:50:4\",\n                            \"tryCall\": false,\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_tuple$__$\",\n                              \"typeString\": \"tuple()\"\n                            }\n                          },\n                          \"id\": 1376,\n                          \"nodeType\": \"ExpressionStatement\",\n                          \"src\": \"10619:50:4\"\n                        }\n                      ]\n                    },\n                    \"id\": 1378,\n                    \"nodeType\": \"IfStatement\",\n                    \"src\": \"10414:266:4\",\n                    \"trueBody\": {\n                      \"id\": 1371,\n                      \"nodeType\": \"Block\",\n                      \"src\": \"10461:122:4\",\n                      \"statements\": [\n                        {\n                          \"expression\": {\n                            \"argumentTypes\": null,\n                            \"arguments\": [\n                              {\n                                \"argumentTypes\": null,\n                                \"arguments\": [\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"expression\": {\n                                      \"argumentTypes\": null,\n                                      \"id\": 1360,\n                                      \"name\": \"msg\",\n                                      \"nodeType\": \"Identifier\",\n                                      \"overloadedDeclarations\": [],\n                                      \"referencedDeclaration\": -15,\n                                      \"src\": \"10503:3:4\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_magic_message\",\n                                        \"typeString\": \"msg\"\n                                      }\n                                    },\n                                    \"id\": 1361,\n                                    \"isConstant\": false,\n                                    \"isLValue\": false,\n                                    \"isPure\": false,\n                                    \"lValueRequested\": false,\n                                    \"memberName\": \"sender\",\n                                    \"nodeType\": \"MemberAccess\",\n                                    \"referencedDeclaration\": null,\n                                    \"src\": \"10503:10:4\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_address_payable\",\n                                      \"typeString\": \"address payable\"\n                                    }\n                                  },\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"arguments\": [\n                                      {\n                                        \"argumentTypes\": null,\n                                        \"id\": 1364,\n                                        \"name\": \"this\",\n                                        \"nodeType\": \"Identifier\",\n                                        \"overloadedDeclarations\": [],\n                                        \"referencedDeclaration\": -28,\n                                        \"src\": \"10523:4:4\",\n                                        \"typeDescriptions\": {\n                                          \"typeIdentifier\": \"t_contract$_FetchOracle_$1440\",\n                                          \"typeString\": \"contract FetchOracle\"\n                                        }\n                                      }\n                                    ],\n                                    \"expression\": {\n                                      \"argumentTypes\": [\n                                        {\n                                          \"typeIdentifier\": \"t_contract$_FetchOracle_$1440\",\n                                          \"typeString\": \"contract FetchOracle\"\n                                        }\n                                      ],\n                                      \"id\": 1363,\n                                      \"isConstant\": false,\n                                      \"isLValue\": false,\n                                      \"isPure\": true,\n                                      \"lValueRequested\": false,\n                                      \"nodeType\": \"ElementaryTypeNameExpression\",\n                                      \"src\": \"10515:7:4\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_type$_t_address_$\",\n                                        \"typeString\": \"type(address)\"\n                                      },\n                                      \"typeName\": {\n                                        \"id\": 1362,\n                                        \"name\": \"address\",\n                                        \"nodeType\": \"ElementaryTypeName\",\n                                        \"src\": \"10515:7:4\",\n                                        \"typeDescriptions\": {\n                                          \"typeIdentifier\": null,\n                                          \"typeString\": null\n                                        }\n                                      }\n                                    },\n                                    \"id\": 1365,\n                                    \"isConstant\": false,\n                                    \"isLValue\": false,\n                                    \"isPure\": false,\n                                    \"kind\": \"typeConversion\",\n                                    \"lValueRequested\": false,\n                                    \"names\": [],\n                                    \"nodeType\": \"FunctionCall\",\n                                    \"src\": \"10515:13:4\",\n                                    \"tryCall\": false,\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_address\",\n                                      \"typeString\": \"address\"\n                                    }\n                                  },\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"id\": 1366,\n                                    \"name\": \"_fee\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 881,\n                                    \"src\": \"10530:4:4\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    }\n                                  }\n                                ],\n                                \"expression\": {\n                                  \"argumentTypes\": [\n                                    {\n                                      \"typeIdentifier\": \"t_address_payable\",\n                                      \"typeString\": \"address payable\"\n                                    },\n                                    {\n                                      \"typeIdentifier\": \"t_address\",\n                                      \"typeString\": \"address\"\n                                    },\n                                    {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    }\n                                  ],\n                                  \"expression\": {\n                                    \"argumentTypes\": null,\n                                    \"id\": 1358,\n                                    \"name\": \"_token\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 875,\n                                    \"src\": \"10483:6:4\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_contract$_IERC20_$2649\",\n                                      \"typeString\": \"contract IERC20\"\n                                    }\n                                  },\n                                  \"id\": 1359,\n                                  \"isConstant\": false,\n                                  \"isLValue\": false,\n                                  \"isPure\": false,\n                                  \"lValueRequested\": false,\n                                  \"memberName\": \"transferFrom\",\n                                  \"nodeType\": \"MemberAccess\",\n                                  \"referencedDeclaration\": 2630,\n                                  \"src\": \"10483:19:4\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_function_external_nonpayable$_t_address_$_t_address_$_t_uint256_$returns$_t_bool_$\",\n                                    \"typeString\": \"function (address,address,uint256) external returns (bool)\"\n                                  }\n                                },\n                                \"id\": 1367,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": false,\n                                \"kind\": \"functionCall\",\n                                \"lValueRequested\": false,\n                                \"names\": [],\n                                \"nodeType\": \"FunctionCall\",\n                                \"src\": \"10483:52:4\",\n                                \"tryCall\": false,\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_bool\",\n                                  \"typeString\": \"bool\"\n                                }\n                              },\n                              {\n                                \"argumentTypes\": null,\n                                \"hexValue\": \"496e7375662e2046455420616c6c6f772e206f6e2063616c6c65722061646472\",\n                                \"id\": 1368,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": true,\n                                \"kind\": \"string\",\n                                \"lValueRequested\": false,\n                                \"nodeType\": \"Literal\",\n                                \"src\": \"10537:34:4\",\n                                \"subdenomination\": null,\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_stringliteral_a65cdee615e67dbd2cf8397ad58720c2c52ee993f0d8f62cb315ac2d7f1f9f3f\",\n                                  \"typeString\": \"literal_string \\\"Insuf. FET allow. on caller addr\\\"\"\n                                },\n                                \"value\": \"Insuf. FET allow. on caller addr\"\n                              }\n                            ],\n                            \"expression\": {\n                              \"argumentTypes\": [\n                                {\n                                  \"typeIdentifier\": \"t_bool\",\n                                  \"typeString\": \"bool\"\n                                },\n                                {\n                                  \"typeIdentifier\": \"t_stringliteral_a65cdee615e67dbd2cf8397ad58720c2c52ee993f0d8f62cb315ac2d7f1f9f3f\",\n                                  \"typeString\": \"literal_string \\\"Insuf. FET allow. on caller addr\\\"\"\n                                }\n                              ],\n                              \"id\": 1357,\n                              \"name\": \"require\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [\n                                -18,\n                                -18\n                              ],\n                              \"referencedDeclaration\": -18,\n                              \"src\": \"10475:7:4\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$\",\n                                \"typeString\": \"function (bool,string memory) pure\"\n                              }\n                            },\n                            \"id\": 1369,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": false,\n                            \"kind\": \"functionCall\",\n                            \"lValueRequested\": false,\n                            \"names\": [],\n                            \"nodeType\": \"FunctionCall\",\n                            \"src\": \"10475:97:4\",\n                            \"tryCall\": false,\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_tuple$__$\",\n                              \"typeString\": \"tuple()\"\n                            }\n                          },\n                          \"id\": 1370,\n                          \"nodeType\": \"ExpressionStatement\",\n                          \"src\": \"10475:97:4\"\n                        }\n                      ]\n                    }\n                  },\n                  \"id\": 1379,\n                  \"nodeType\": \"IfStatement\",\n                  \"src\": \"9755:925:4\",\n                  \"trueBody\": {\n                    \"id\": 1352,\n                    \"nodeType\": \"Block\",\n                    \"src\": \"9800:600:4\",\n                    \"statements\": [\n                      {\n                        \"condition\": {\n                          \"argumentTypes\": null,\n                          \"commonType\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          },\n                          \"id\": 1325,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"leftExpression\": {\n                            \"argumentTypes\": null,\n                            \"expression\": {\n                              \"argumentTypes\": null,\n                              \"id\": 1322,\n                              \"name\": \"msg\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": -15,\n                              \"src\": \"9817:3:4\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_magic_message\",\n                                \"typeString\": \"msg\"\n                              }\n                            },\n                            \"id\": 1323,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": false,\n                            \"lValueRequested\": false,\n                            \"memberName\": \"value\",\n                            \"nodeType\": \"MemberAccess\",\n                            \"referencedDeclaration\": null,\n                            \"src\": \"9817:9:4\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"nodeType\": \"BinaryOperation\",\n                          \"operator\": \"==\",\n                          \"rightExpression\": {\n                            \"argumentTypes\": null,\n                            \"id\": 1324,\n                            \"name\": \"_fee\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 881,\n                            \"src\": \"9830:4:4\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"src\": \"9817:17:4\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_bool\",\n                            \"typeString\": \"bool\"\n                          }\n                        },\n                        \"falseBody\": {\n                          \"condition\": {\n                            \"argumentTypes\": null,\n                            \"commonType\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            },\n                            \"id\": 1330,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": false,\n                            \"lValueRequested\": false,\n                            \"leftExpression\": {\n                              \"argumentTypes\": null,\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"id\": 1327,\n                                \"name\": \"msg\",\n                                \"nodeType\": \"Identifier\",\n                                \"overloadedDeclarations\": [],\n                                \"referencedDeclaration\": -15,\n                                \"src\": \"10081:3:4\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_magic_message\",\n                                  \"typeString\": \"msg\"\n                                }\n                              },\n                              \"id\": 1328,\n                              \"isConstant\": false,\n                              \"isLValue\": false,\n                              \"isPure\": false,\n                              \"lValueRequested\": false,\n                              \"memberName\": \"value\",\n                              \"nodeType\": \"MemberAccess\",\n                              \"referencedDeclaration\": null,\n                              \"src\": \"10081:9:4\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_uint256\",\n                                \"typeString\": \"uint256\"\n                              }\n                            },\n                            \"nodeType\": \"BinaryOperation\",\n                            \"operator\": \">\",\n                            \"rightExpression\": {\n                              \"argumentTypes\": null,\n                              \"id\": 1329,\n                              \"name\": \"_fee\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 881,\n                              \"src\": \"10093:4:4\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_uint256\",\n                                \"typeString\": \"uint256\"\n                              }\n                            },\n                            \"src\": \"10081:16:4\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_bool\",\n                              \"typeString\": \"bool\"\n                            }\n                          },\n                          \"falseBody\": {\n                            \"id\": 1349,\n                            \"nodeType\": \"Block\",\n                            \"src\": \"10309:81:4\",\n                            \"statements\": [\n                              {\n                                \"expression\": {\n                                  \"argumentTypes\": null,\n                                  \"arguments\": [\n                                    {\n                                      \"argumentTypes\": null,\n                                      \"hexValue\": \"66616c7365\",\n                                      \"id\": 1345,\n                                      \"isConstant\": false,\n                                      \"isLValue\": false,\n                                      \"isPure\": true,\n                                      \"kind\": \"bool\",\n                                      \"lValueRequested\": false,\n                                      \"nodeType\": \"Literal\",\n                                      \"src\": \"10334:5:4\",\n                                      \"subdenomination\": null,\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_bool\",\n                                        \"typeString\": \"bool\"\n                                      },\n                                      \"value\": \"false\"\n                                    },\n                                    {\n                                      \"argumentTypes\": null,\n                                      \"hexValue\": \"496e7375662e2045544820616d6f756e742073656e742062792063616c6c6572\",\n                                      \"id\": 1346,\n                                      \"isConstant\": false,\n                                      \"isLValue\": false,\n                                      \"isPure\": true,\n                                      \"kind\": \"string\",\n                                      \"lValueRequested\": false,\n                                      \"nodeType\": \"Literal\",\n                                      \"src\": \"10341:34:4\",\n                                      \"subdenomination\": null,\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_stringliteral_cb0058c10826e687d07067bad869c8c10a79c4914786ac0532f9d46b4ce50fc7\",\n                                        \"typeString\": \"literal_string \\\"Insuf. ETH amount sent by caller\\\"\"\n                                      },\n                                      \"value\": \"Insuf. ETH amount sent by caller\"\n                                    }\n                                  ],\n                                  \"expression\": {\n                                    \"argumentTypes\": [\n                                      {\n                                        \"typeIdentifier\": \"t_bool\",\n                                        \"typeString\": \"bool\"\n                                      },\n                                      {\n                                        \"typeIdentifier\": \"t_stringliteral_cb0058c10826e687d07067bad869c8c10a79c4914786ac0532f9d46b4ce50fc7\",\n                                        \"typeString\": \"literal_string \\\"Insuf. ETH amount sent by caller\\\"\"\n                                      }\n                                    ],\n                                    \"id\": 1344,\n                                    \"name\": \"require\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [\n                                      -18,\n                                      -18\n                                    ],\n                                    \"referencedDeclaration\": -18,\n                                    \"src\": \"10326:7:4\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$\",\n                                      \"typeString\": \"function (bool,string memory) pure\"\n                                    }\n                                  },\n                                  \"id\": 1347,\n                                  \"isConstant\": false,\n                                  \"isLValue\": false,\n                                  \"isPure\": false,\n                                  \"kind\": \"functionCall\",\n                                  \"lValueRequested\": false,\n                                  \"names\": [],\n                                  \"nodeType\": \"FunctionCall\",\n                                  \"src\": \"10326:50:4\",\n                                  \"tryCall\": false,\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_tuple$__$\",\n                                    \"typeString\": \"tuple()\"\n                                  }\n                                },\n                                \"id\": 1348,\n                                \"nodeType\": \"ExpressionStatement\",\n                                \"src\": \"10326:50:4\"\n                              }\n                            ]\n                          },\n                          \"id\": 1350,\n                          \"nodeType\": \"IfStatement\",\n                          \"src\": \"10077:313:4\",\n                          \"trueBody\": {\n                            \"id\": 1343,\n                            \"nodeType\": \"Block\",\n                            \"src\": \"10110:171:4\",\n                            \"statements\": [\n                              {\n                                \"expression\": {\n                                  \"argumentTypes\": null,\n                                  \"arguments\": [\n                                    {\n                                      \"argumentTypes\": null,\n                                      \"arguments\": [\n                                        {\n                                          \"argumentTypes\": null,\n                                          \"id\": 1339,\n                                          \"name\": \"_fee\",\n                                          \"nodeType\": \"Identifier\",\n                                          \"overloadedDeclarations\": [],\n                                          \"referencedDeclaration\": 881,\n                                          \"src\": \"10261:4:4\",\n                                          \"typeDescriptions\": {\n                                            \"typeIdentifier\": \"t_uint256\",\n                                            \"typeString\": \"uint256\"\n                                          }\n                                        }\n                                      ],\n                                      \"expression\": {\n                                        \"argumentTypes\": [\n                                          {\n                                            \"typeIdentifier\": \"t_uint256\",\n                                            \"typeString\": \"uint256\"\n                                          }\n                                        ],\n                                        \"expression\": {\n                                          \"argumentTypes\": null,\n                                          \"expression\": {\n                                            \"argumentTypes\": null,\n                                            \"id\": 1336,\n                                            \"name\": \"msg\",\n                                            \"nodeType\": \"Identifier\",\n                                            \"overloadedDeclarations\": [],\n                                            \"referencedDeclaration\": -15,\n                                            \"src\": \"10247:3:4\",\n                                            \"typeDescriptions\": {\n                                              \"typeIdentifier\": \"t_magic_message\",\n                                              \"typeString\": \"msg\"\n                                            }\n                                          },\n                                          \"id\": 1337,\n                                          \"isConstant\": false,\n                                          \"isLValue\": false,\n                                          \"isPure\": false,\n                                          \"lValueRequested\": false,\n                                          \"memberName\": \"value\",\n                                          \"nodeType\": \"MemberAccess\",\n                                          \"referencedDeclaration\": null,\n                                          \"src\": \"10247:9:4\",\n                                          \"typeDescriptions\": {\n                                            \"typeIdentifier\": \"t_uint256\",\n                                            \"typeString\": \"uint256\"\n                                          }\n                                        },\n                                        \"id\": 1338,\n                                        \"isConstant\": false,\n                                        \"isLValue\": false,\n                                        \"isPure\": false,\n                                        \"lValueRequested\": false,\n                                        \"memberName\": \"sub\",\n                                        \"nodeType\": \"MemberAccess\",\n                                        \"referencedDeclaration\": 1829,\n                                        \"src\": \"10247:13:4\",\n                                        \"typeDescriptions\": {\n                                          \"typeIdentifier\": \"t_function_internal_pure$_t_uint256_$_t_uint256_$returns$_t_uint256_$bound_to$_t_uint256_$\",\n                                          \"typeString\": \"function (uint256,uint256) pure returns (uint256)\"\n                                        }\n                                      },\n                                      \"id\": 1340,\n                                      \"isConstant\": false,\n                                      \"isLValue\": false,\n                                      \"isPure\": false,\n                                      \"kind\": \"functionCall\",\n                                      \"lValueRequested\": false,\n                                      \"names\": [],\n                                      \"nodeType\": \"FunctionCall\",\n                                      \"src\": \"10247:19:4\",\n                                      \"tryCall\": false,\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_uint256\",\n                                        \"typeString\": \"uint256\"\n                                      }\n                                    }\n                                  ],\n                                  \"expression\": {\n                                    \"argumentTypes\": [\n                                      {\n                                        \"typeIdentifier\": \"t_uint256\",\n                                        \"typeString\": \"uint256\"\n                                      }\n                                    ],\n                                    \"expression\": {\n                                      \"argumentTypes\": null,\n                                      \"expression\": {\n                                        \"argumentTypes\": null,\n                                        \"id\": 1331,\n                                        \"name\": \"msg\",\n                                        \"nodeType\": \"Identifier\",\n                                        \"overloadedDeclarations\": [],\n                                        \"referencedDeclaration\": -15,\n                                        \"src\": \"10227:3:4\",\n                                        \"typeDescriptions\": {\n                                          \"typeIdentifier\": \"t_magic_message\",\n                                          \"typeString\": \"msg\"\n                                        }\n                                      },\n                                      \"id\": 1334,\n                                      \"isConstant\": false,\n                                      \"isLValue\": false,\n                                      \"isPure\": false,\n                                      \"lValueRequested\": false,\n                                      \"memberName\": \"sender\",\n                                      \"nodeType\": \"MemberAccess\",\n                                      \"referencedDeclaration\": null,\n                                      \"src\": \"10227:10:4\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_address_payable\",\n                                        \"typeString\": \"address payable\"\n                                      }\n                                    },\n                                    \"id\": 1335,\n                                    \"isConstant\": false,\n                                    \"isLValue\": false,\n                                    \"isPure\": false,\n                                    \"lValueRequested\": false,\n                                    \"memberName\": \"transfer\",\n                                    \"nodeType\": \"MemberAccess\",\n                                    \"referencedDeclaration\": null,\n                                    \"src\": \"10227:19:4\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_function_transfer_nonpayable$_t_uint256_$returns$__$\",\n                                      \"typeString\": \"function (uint256)\"\n                                    }\n                                  },\n                                  \"id\": 1341,\n                                  \"isConstant\": false,\n                                  \"isLValue\": false,\n                                  \"isPure\": false,\n                                  \"kind\": \"functionCall\",\n                                  \"lValueRequested\": false,\n                                  \"names\": [],\n                                  \"nodeType\": \"FunctionCall\",\n                                  \"src\": \"10227:40:4\",\n                                  \"tryCall\": false,\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_tuple$__$\",\n                                    \"typeString\": \"tuple()\"\n                                  }\n                                },\n                                \"id\": 1342,\n                                \"nodeType\": \"ExpressionStatement\",\n                                \"src\": \"10227:40:4\"\n                              }\n                            ]\n                          }\n                        },\n                        \"id\": 1351,\n                        \"nodeType\": \"IfStatement\",\n                        \"src\": \"9813:577:4\",\n                        \"trueBody\": {\n                          \"id\": 1326,\n                          \"nodeType\": \"Block\",\n                          \"src\": \"9847:213:4\",\n                          \"statements\": []\n                        }\n                      }\n                    ]\n                  }\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 1385,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 1380,\n                      \"name\": \"_accruedFeesAmount\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 883,\n                      \"src\": \"10690:18:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"arguments\": [\n                        {\n                          \"argumentTypes\": null,\n                          \"id\": 1383,\n                          \"name\": \"_fee\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 881,\n                          \"src\": \"10734:4:4\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        }\n                      ],\n                      \"expression\": {\n                        \"argumentTypes\": [\n                          {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        ],\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 1381,\n                          \"name\": \"_accruedFeesAmount\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 883,\n                          \"src\": \"10711:18:4\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"id\": 1382,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"memberName\": \"add\",\n                        \"nodeType\": \"MemberAccess\",\n                        \"referencedDeclaration\": 1812,\n                        \"src\": \"10711:22:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_function_internal_pure$_t_uint256_$_t_uint256_$returns$_t_uint256_$bound_to$_t_uint256_$\",\n                          \"typeString\": \"function (uint256,uint256) pure returns (uint256)\"\n                        }\n                      },\n                      \"id\": 1384,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": false,\n                      \"kind\": \"functionCall\",\n                      \"lValueRequested\": false,\n                      \"names\": [],\n                      \"nodeType\": \"FunctionCall\",\n                      \"src\": \"10711:28:4\",\n                      \"tryCall\": false,\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"src\": \"10690:49:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"id\": 1386,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"10690:49:4\"\n                }\n              ]\n            },\n            \"documentation\": {\n              \"id\": 1315,\n              \"nodeType\": \"StructuredDocumentation\",\n              \"src\": \"9650:53:4\",\n              \"text\": \"@dev Withdraw fee from the caller.\"\n            },\n            \"id\": 1388,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [],\n            \"name\": \"_withdrawFee\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 1316,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"9729:2:4\"\n            },\n            \"returnParameters\": {\n              \"id\": 1317,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"9745:0:4\"\n            },\n            \"scope\": 1440,\n            \"src\": \"9708:1038:4\",\n            \"stateMutability\": \"nonpayable\",\n            \"virtual\": false,\n            \"visibility\": \"internal\"\n          },\n          {\n            \"body\": {\n              \"id\": 1438,\n              \"nodeType\": \"Block\",\n              \"src\": \"10844:699:4\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"commonType\": {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        },\n                        \"id\": 1401,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"leftExpression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 1396,\n                          \"name\": \"targetAddress\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 1390,\n                          \"src\": \"10862:13:4\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_address_payable\",\n                            \"typeString\": \"address payable\"\n                          }\n                        },\n                        \"nodeType\": \"BinaryOperation\",\n                        \"operator\": \"!=\",\n                        \"rightExpression\": {\n                          \"argumentTypes\": null,\n                          \"arguments\": [\n                            {\n                              \"argumentTypes\": null,\n                              \"hexValue\": \"30\",\n                              \"id\": 1399,\n                              \"isConstant\": false,\n                              \"isLValue\": false,\n                              \"isPure\": true,\n                              \"kind\": \"number\",\n                              \"lValueRequested\": false,\n                              \"nodeType\": \"Literal\",\n                              \"src\": \"10887:1:4\",\n                              \"subdenomination\": null,\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_rational_0_by_1\",\n                                \"typeString\": \"int_const 0\"\n                              },\n                              \"value\": \"0\"\n                            }\n                          ],\n                          \"expression\": {\n                            \"argumentTypes\": [\n                              {\n                                \"typeIdentifier\": \"t_rational_0_by_1\",\n                                \"typeString\": \"int_const 0\"\n                              }\n                            ],\n                            \"id\": 1398,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": true,\n                            \"lValueRequested\": false,\n                            \"nodeType\": \"ElementaryTypeNameExpression\",\n                            \"src\": \"10879:7:4\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_type$_t_address_$\",\n                              \"typeString\": \"type(address)\"\n                            },\n                            \"typeName\": {\n                              \"id\": 1397,\n                              \"name\": \"address\",\n                              \"nodeType\": \"ElementaryTypeName\",\n                              \"src\": \"10879:7:4\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": null,\n                                \"typeString\": null\n                              }\n                            }\n                          },\n                          \"id\": 1400,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": true,\n                          \"kind\": \"typeConversion\",\n                          \"lValueRequested\": false,\n                          \"names\": [],\n                          \"nodeType\": \"FunctionCall\",\n                          \"src\": \"10879:10:4\",\n                          \"tryCall\": false,\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_address_payable\",\n                            \"typeString\": \"address payable\"\n                          }\n                        },\n                        \"src\": \"10862:27:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"hexValue\": \"546172676574206973207a65726f2061646472657373\",\n                        \"id\": 1402,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": true,\n                        \"kind\": \"string\",\n                        \"lValueRequested\": false,\n                        \"nodeType\": \"Literal\",\n                        \"src\": \"10891:24:4\",\n                        \"subdenomination\": null,\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_stringliteral_cccbd8782d968807cd85c549e83adb6604b8463e9d07bb08e05c43c68c493c61\",\n                          \"typeString\": \"literal_string \\\"Target is zero address\\\"\"\n                        },\n                        \"value\": \"Target is zero address\"\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_stringliteral_cccbd8782d968807cd85c549e83adb6604b8463e9d07bb08e05c43c68c493c61\",\n                          \"typeString\": \"literal_string \\\"Target is zero address\\\"\"\n                        }\n                      ],\n                      \"id\": 1395,\n                      \"name\": \"require\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [\n                        -18,\n                        -18\n                      ],\n                      \"referencedDeclaration\": -18,\n                      \"src\": \"10854:7:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$\",\n                        \"typeString\": \"function (bool,string memory) pure\"\n                      }\n                    },\n                    \"id\": 1403,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"10854:62:4\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 1404,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"10854:62:4\"\n                },\n                {\n                  \"condition\": {\n                    \"argumentTypes\": null,\n                    \"commonType\": {\n                      \"typeIdentifier\": \"t_enum$_FeeCurrency_$827\",\n                      \"typeString\": \"enum FetchOracle.FeeCurrency\"\n                    },\n                    \"id\": 1408,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftExpression\": {\n                      \"argumentTypes\": null,\n                      \"id\": 1405,\n                      \"name\": \"_feeCurrency\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 887,\n                      \"src\": \"10931:12:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_enum$_FeeCurrency_$827\",\n                        \"typeString\": \"enum FetchOracle.FeeCurrency\"\n                      }\n                    },\n                    \"nodeType\": \"BinaryOperation\",\n                    \"operator\": \"==\",\n                    \"rightExpression\": {\n                      \"argumentTypes\": null,\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 1406,\n                        \"name\": \"FeeCurrency\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 827,\n                        \"src\": \"10947:11:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_type$_t_enum$_FeeCurrency_$827_$\",\n                          \"typeString\": \"type(enum FetchOracle.FeeCurrency)\"\n                        }\n                      },\n                      \"id\": 1407,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": true,\n                      \"lValueRequested\": false,\n                      \"memberName\": \"ETH\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": null,\n                      \"src\": \"10947:15:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_enum$_FeeCurrency_$827\",\n                        \"typeString\": \"enum FetchOracle.FeeCurrency\"\n                      }\n                    },\n                    \"src\": \"10931:31:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_bool\",\n                      \"typeString\": \"bool\"\n                    }\n                  },\n                  \"falseBody\": {\n                    \"condition\": {\n                      \"argumentTypes\": null,\n                      \"commonType\": {\n                        \"typeIdentifier\": \"t_enum$_FeeCurrency_$827\",\n                        \"typeString\": \"enum FetchOracle.FeeCurrency\"\n                      },\n                      \"id\": 1419,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"leftExpression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 1416,\n                        \"name\": \"_feeCurrency\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 887,\n                        \"src\": \"11167:12:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_enum$_FeeCurrency_$827\",\n                          \"typeString\": \"enum FetchOracle.FeeCurrency\"\n                        }\n                      },\n                      \"nodeType\": \"BinaryOperation\",\n                      \"operator\": \"==\",\n                      \"rightExpression\": {\n                        \"argumentTypes\": null,\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 1417,\n                          \"name\": \"FeeCurrency\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 827,\n                          \"src\": \"11183:11:4\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_type$_t_enum$_FeeCurrency_$827_$\",\n                            \"typeString\": \"type(enum FetchOracle.FeeCurrency)\"\n                          }\n                        },\n                        \"id\": 1418,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": true,\n                        \"lValueRequested\": false,\n                        \"memberName\": \"ERC20\",\n                        \"nodeType\": \"MemberAccess\",\n                        \"referencedDeclaration\": null,\n                        \"src\": \"11183:17:4\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_enum$_FeeCurrency_$827\",\n                          \"typeString\": \"enum FetchOracle.FeeCurrency\"\n                        }\n                      },\n                      \"src\": \"11167:33:4\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_bool\",\n                        \"typeString\": \"bool\"\n                      }\n                    },\n                    \"falseBody\": {\n                      \"id\": 1435,\n                      \"nodeType\": \"Block\",\n                      \"src\": \"11462:75:4\",\n                      \"statements\": [\n                        {\n                          \"expression\": {\n                            \"argumentTypes\": null,\n                            \"arguments\": [\n                              {\n                                \"argumentTypes\": null,\n                                \"hexValue\": \"66616c7365\",\n                                \"id\": 1431,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": true,\n                                \"kind\": \"bool\",\n                                \"lValueRequested\": false,\n                                \"nodeType\": \"Literal\",\n                                \"src\": \"11484:5:4\",\n                                \"subdenomination\": null,\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_bool\",\n                                  \"typeString\": \"bool\"\n                                },\n                                \"value\": \"false\"\n                              },\n                              {\n                                \"argumentTypes\": null,\n                                \"hexValue\": \"556e657870656374656420636f6e7472616374206665652063757272656e6379\",\n                                \"id\": 1432,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": true,\n                                \"kind\": \"string\",\n                                \"lValueRequested\": false,\n                                \"nodeType\": \"Literal\",\n                                \"src\": \"11491:34:4\",\n                                \"subdenomination\": null,\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_stringliteral_f131716b743e5ec47535766db932d6974cfad176c58ab32b82f54addc42de82c\",\n                                  \"typeString\": \"literal_string \\\"Unexpected contract fee currency\\\"\"\n                                },\n                                \"value\": \"Unexpected contract fee currency\"\n                              }\n                            ],\n                            \"expression\": {\n                              \"argumentTypes\": [\n                                {\n                                  \"typeIdentifier\": \"t_bool\",\n                                  \"typeString\": \"bool\"\n                                },\n                                {\n                                  \"typeIdentifier\": \"t_stringliteral_f131716b743e5ec47535766db932d6974cfad176c58ab32b82f54addc42de82c\",\n                                  \"typeString\": \"literal_string \\\"Unexpected contract fee currency\\\"\"\n                                }\n                              ],\n                              \"id\": 1430,\n                              \"name\": \"require\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [\n                                -18,\n                                -18\n                              ],\n                              \"referencedDeclaration\": -18,\n                              \"src\": \"11476:7:4\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$\",\n                                \"typeString\": \"function (bool,string memory) pure\"\n                              }\n                            },\n                            \"id\": 1433,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": false,\n                            \"kind\": \"functionCall\",\n                            \"lValueRequested\": false,\n                            \"names\": [],\n                            \"nodeType\": \"FunctionCall\",\n                            \"src\": \"11476:50:4\",\n                            \"tryCall\": false,\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_tuple$__$\",\n                              \"typeString\": \"tuple()\"\n                            }\n                          },\n                          \"id\": 1434,\n                          \"nodeType\": \"ExpressionStatement\",\n                          \"src\": \"11476:50:4\"\n                        }\n                      ]\n                    },\n                    \"id\": 1436,\n                    \"nodeType\": \"IfStatement\",\n                    \"src\": \"11163:374:4\",\n                    \"trueBody\": {\n                      \"id\": 1429,\n                      \"nodeType\": \"Block\",\n                      \"src\": \"11210:230:4\",\n                      \"statements\": [\n                        {\n                          \"expression\": {\n                            \"argumentTypes\": null,\n                            \"arguments\": [\n                              {\n                                \"argumentTypes\": null,\n                                \"arguments\": [\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"id\": 1423,\n                                    \"name\": \"targetAddress\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 1390,\n                                    \"src\": \"11370:13:4\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_address_payable\",\n                                      \"typeString\": \"address payable\"\n                                    }\n                                  },\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"id\": 1424,\n                                    \"name\": \"amount\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 1392,\n                                    \"src\": \"11385:6:4\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    }\n                                  }\n                                ],\n                                \"expression\": {\n                                  \"argumentTypes\": [\n                                    {\n                                      \"typeIdentifier\": \"t_address_payable\",\n                                      \"typeString\": \"address payable\"\n                                    },\n                                    {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    }\n                                  ],\n                                  \"expression\": {\n                                    \"argumentTypes\": null,\n                                    \"id\": 1421,\n                                    \"name\": \"_token\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 875,\n                                    \"src\": \"11354:6:4\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_contract$_IERC20_$2649\",\n                                      \"typeString\": \"contract IERC20\"\n                                    }\n                                  },\n                                  \"id\": 1422,\n                                  \"isConstant\": false,\n                                  \"isLValue\": false,\n                                  \"isPure\": false,\n                                  \"lValueRequested\": false,\n                                  \"memberName\": \"transfer\",\n                                  \"nodeType\": \"MemberAccess\",\n                                  \"referencedDeclaration\": 2598,\n                                  \"src\": \"11354:15:4\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_function_external_nonpayable$_t_address_$_t_uint256_$returns$_t_bool_$\",\n                                    \"typeString\": \"function (address,uint256) external returns (bool)\"\n                                  }\n                                },\n                                \"id\": 1425,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": false,\n                                \"kind\": \"functionCall\",\n                                \"lValueRequested\": false,\n                                \"names\": [],\n                                \"nodeType\": \"FunctionCall\",\n                                \"src\": \"11354:38:4\",\n                                \"tryCall\": false,\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_bool\",\n                                  \"typeString\": \"bool\"\n                                }\n                              },\n                              {\n                                \"argumentTypes\": null,\n                                \"hexValue\": \"496e737566662e204645542066756e6473206f6e20636f6e74722e2061646472\",\n                                \"id\": 1426,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": true,\n                                \"kind\": \"string\",\n                                \"lValueRequested\": false,\n                                \"nodeType\": \"Literal\",\n                                \"src\": \"11394:34:4\",\n                                \"subdenomination\": null,\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_stringliteral_ac4273e35d12186f8e3dd3c3e48a2a5436d20bacdfa1045742d7a790fa7c7376\",\n                                  \"typeString\": \"literal_string \\\"Insuff. FET funds on contr. addr\\\"\"\n                                },\n                                \"value\": \"Insuff. FET funds on contr. addr\"\n                              }\n                            ],\n                            \"expression\": {\n                              \"argumentTypes\": [\n                                {\n                                  \"typeIdentifier\": \"t_bool\",\n                                  \"typeString\": \"bool\"\n                                },\n                                {\n                                  \"typeIdentifier\": \"t_stringliteral_ac4273e35d12186f8e3dd3c3e48a2a5436d20bacdfa1045742d7a790fa7c7376\",\n                                  \"typeString\": \"literal_string \\\"Insuff. FET funds on contr. addr\\\"\"\n                                }\n                              ],\n                              \"id\": 1420,\n                              \"name\": \"require\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [\n                                -18,\n                                -18\n                              ],\n                              \"referencedDeclaration\": -18,\n                              \"src\": \"11346:7:4\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$\",\n                                \"typeString\": \"function (bool,string memory) pure\"\n                              }\n                            },\n                            \"id\": 1427,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": false,\n                            \"kind\": \"functionCall\",\n                            \"lValueRequested\": false,\n                            \"names\": [],\n                            \"nodeType\": \"FunctionCall\",\n                            \"src\": \"11346:83:4\",\n                            \"tryCall\": false,\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_tuple$__$\",\n                              \"typeString\": \"tuple()\"\n                            }\n                          },\n                          \"id\": 1428,\n                          \"nodeType\": \"ExpressionStatement\",\n                          \"src\": \"11346:83:4\"\n                        }\n                      ]\n                    }\n                  },\n                  \"id\": 1437,\n                  \"nodeType\": \"IfStatement\",\n                  \"src\": \"10927:610:4\",\n                  \"trueBody\": {\n                    \"id\": 1415,\n                    \"nodeType\": \"Block\",\n                    \"src\": \"10972:177:4\",\n                    \"statements\": [\n                      {\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"arguments\": [\n                            {\n                              \"argumentTypes\": null,\n                              \"id\": 1412,\n                              \"name\": \"amount\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 1392,\n                              \"src\": \"11131:6:4\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_uint256\",\n                                \"typeString\": \"uint256\"\n                              }\n                            }\n                          ],\n                          \"expression\": {\n                            \"argumentTypes\": [\n                              {\n                                \"typeIdentifier\": \"t_uint256\",\n                                \"typeString\": \"uint256\"\n                              }\n                            ],\n                            \"expression\": {\n                              \"argumentTypes\": null,\n                              \"id\": 1409,\n                              \"name\": \"targetAddress\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 1390,\n                              \"src\": \"11108:13:4\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_address_payable\",\n                                \"typeString\": \"address payable\"\n                              }\n                            },\n                            \"id\": 1411,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": false,\n                            \"lValueRequested\": false,\n                            \"memberName\": \"transfer\",\n                            \"nodeType\": \"MemberAccess\",\n                            \"referencedDeclaration\": null,\n                            \"src\": \"11108:22:4\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_function_transfer_nonpayable$_t_uint256_$returns$__$\",\n                              \"typeString\": \"function (uint256)\"\n                            }\n                          },\n                          \"id\": 1413,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"kind\": \"functionCall\",\n                          \"lValueRequested\": false,\n                          \"names\": [],\n                          \"nodeType\": \"FunctionCall\",\n                          \"src\": \"11108:30:4\",\n                          \"tryCall\": false,\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_tuple$__$\",\n                            \"typeString\": \"tuple()\"\n                          }\n                        },\n                        \"id\": 1414,\n                        \"nodeType\": \"ExpressionStatement\",\n                        \"src\": \"11108:30:4\"\n                      }\n                    ]\n                  }\n                }\n              ]\n            },\n            \"documentation\": null,\n            \"id\": 1439,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [],\n            \"name\": \"_withdrawFromContract\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 1393,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 1390,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"targetAddress\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 1439,\n                  \"src\": \"10784:29:4\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_address_payable\",\n                    \"typeString\": \"address payable\"\n                  },\n                  \"typeName\": {\n                    \"id\": 1389,\n                    \"name\": \"address\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"10784:15:4\",\n                    \"stateMutability\": \"payable\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address_payable\",\n                      \"typeString\": \"address payable\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 1392,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"amount\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 1439,\n                  \"src\": \"10815:14:4\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 1391,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"10815:7:4\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"10783:47:4\"\n            },\n            \"returnParameters\": {\n              \"id\": 1394,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"10844:0:4\"\n            },\n            \"scope\": 1440,\n            \"src\": \"10753:790:4\",\n            \"stateMutability\": \"nonpayable\",\n            \"virtual\": false,\n            \"visibility\": \"internal\"\n          }\n        ],\n        \"scope\": 1441,\n        \"src\": \"1550:9995:4\"\n      }\n    ],\n    \"src\": \"820:10726:4\"\n  },\n  \"compiler\": {\n    \"name\": \"solc\",\n    \"version\": \"0.6.8+commit.0bbfe453.Emscripten.clang\"\n  },\n  \"networks\": {},\n  \"schemaVersion\": \"3.0.23\",\n  \"updatedAt\": \"2020-11-17T14:40:20.557Z\",\n  \"devdoc\": {\n    \"details\": \"The contract *INTENTIONALLY* does not contain the `receive()` or fallback functions in order to ensure that all unsolicited direct ETH transfers in to this contract (in direct Transaction) will fail. Only way how to make successful fee transfer in ETH currency (*IF* contract is initialised for ETH as fee currency), is to make transfer ETH to caller(client) contract and client contract then is responsible for further rogrammatic* (= *not* via Tx) transfer of fee to this this contract.\",\n    \"methods\": {\n      \"constructor\": {\n        \"params\": {\n          \"ERC20Address\": \"address of the ERC20 contract\"\n        }\n      },\n      \"deleteContract(address,uint256)\": {\n        \"details\": \"Delete the contract, transfers the remaining token and ether balance to the specified payoutAddressowner only + only on or after `_earliestDelete` block\",\n        \"params\": {\n          \"payoutAddress\": \"address to transfer the balances to. Ensure that this is able to handle ERC20 tokens\"\n        }\n      },\n      \"getRoleAdmin(bytes32)\": {\n        \"details\": \"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}.     * To change a role's admin, use {_setRoleAdmin}.\"\n      },\n      \"getRoleMember(bytes32,uint256)\": {\n        \"details\": \"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive.     * Role bearers are not sorted in any particular way, and their ordering may change at any point.     * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information.\"\n      },\n      \"getRoleMemberCount(bytes32)\": {\n        \"details\": \"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role.\"\n      },\n      \"grantRole(bytes32,address)\": {\n        \"details\": \"Grants `role` to `account`.     * If `account` had not been already granted `role`, emits a {RoleGranted} event.     * Requirements:     * - the caller must have ``role``'s admin role.\"\n      },\n      \"hasRole(bytes32,address)\": {\n        \"details\": \"Returns `true` if `account` has been granted `role`.\"\n      },\n      \"pauseSince(uint256,uint256)\": {\n        \"details\": \"Pause the non-administrative interaction with the contractOwners only\",\n        \"params\": {\n          \"block_number\": \"disallow non-admin. interactions with contract for a _getBlockNumber() >= block_number\"\n        }\n      },\n      \"renounceRole(bytes32,address)\": {\n        \"details\": \"Revokes `role` from the calling account.     * Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced).     * If the calling account had been granted `role`, emits a {RoleRevoked} event.     * Requirements:     * - the caller must be `account`.\"\n      },\n      \"revokeRole(bytes32,address)\": {\n        \"details\": \"Revokes `role` from `account`.     * If `account` had been granted `role`, emits a {RoleRevoked} event.     * Requirements:     * - the caller must have ``role``'s admin role.\"\n      },\n      \"setFee(uint256,uint256)\": {\n        \"details\": \"Pause the non-administrative interaction with the contractOwners only\",\n        \"params\": {\n          \"fee\": \"- value of fee\",\n          \"txExpirationBlock\": \"- block number defined by Tx sender beyond which transaction becomes invalid\"\n        }\n      },\n      \"withdrawAccruedFees(address,uint256)\": {\n        \"details\": \"Withdraw whole balance of all fees accrued in the contract so far.Owners only\",\n        \"params\": {\n          \"targetAddress\": \": address to send tokens to\",\n          \"txExpirationBlock\": \": block number until which is the transaction valid (inclusive).                           When transaction is processed after this block, it fails.\"\n        }\n      },\n      \"withdrawExcessTokens(address,uint256)\": {\n        \"details\": \"Withdraw \\\"excess\\\" tokens, which were sent to contract address directly via direct ERC20 transfer(...) or transferFrom(...),     without interacting with API of this (FetchOracle) contract, what could be done only by mistake.     Thus this method is meant to be used primarily for rescue purposes, enabling withdrawal of such     \\\"excess\\\" tokens out of contract.\",\n        \"params\": {\n          \"targetAddress\": \": address to send tokens to\",\n          \"txExpirationBlock\": \": block number until which is the transaction valid (inclusive).                           When transaction is processed after this block, it fails.\"\n        }\n      }\n    }\n  },\n  \"userdoc\": {\n    \"methods\": {}\n  }\n}"
  },
  {
    "path": "packages/fetchai/contracts/oracle/contract.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the class to connect to an Oracle contract.\"\"\"\n\nimport logging\nfrom typing import Any, Dict, cast\n\nfrom aea_ledger_ethereum import EthereumApi\nfrom aea_ledger_fetchai import FetchAIApi\n\nfrom aea.common import Address, JSONLike\nfrom aea.configurations.base import PublicId\nfrom aea.contracts.base import Contract\nfrom aea.crypto.base import LedgerApi\n\n\nPUBLIC_ID = PublicId.from_str(\"fetchai/oracle:0.12.3\")\n\n\ndef keccak256(input_: bytes) -> bytes:\n    \"\"\"Compute hash.\"\"\"\n    return bytes(bytearray.fromhex(EthereumApi.get_hash(input_)[2:]))\n\n\nORACLE_ROLE = \"ORACLE_ROLE\"\n\n_default_logger = logging.getLogger(\"aea.packages.fetchai.contracts.oracle.contract\")\n\n\nclass FetchOracleContract(Contract):\n    \"\"\"The Fetch oracle contract.\"\"\"\n\n    @classmethod\n    def get_grant_role_transaction(\n        cls,\n        ledger_api: LedgerApi,\n        contract_address: Address,\n        oracle_address: Address,\n        gas: int = 0,\n        tx_fee: int = 0,\n    ) -> JSONLike:\n        \"\"\"\n        Get transaction to grant oracle role to recipient_address\n\n        :param ledger_api: the ledger API\n        :param contract_address: the contract address\n        :param oracle_address: the address of the oracle\n        :param gas: the gas limit\n        :param tx_fee: the transaction fee\n        :return: the transaction object\n        \"\"\"\n        if ledger_api.identifier == EthereumApi.identifier:\n            nonce = ledger_api.api.eth.getTransactionCount(oracle_address)\n            instance = cls.get_instance(ledger_api, contract_address)\n            oracle_role = keccak256(ORACLE_ROLE.encode(\"utf-8\"))\n            tx = instance.functions.grantRole(\n                oracle_role, oracle_address\n            ).buildTransaction(\n                {\n                    \"gas\": gas,\n                    \"gasPrice\": ledger_api.api.toWei(\"50\", \"gwei\"),\n                    \"nonce\": nonce,\n                }\n            )\n            tx = ledger_api.update_with_gas_estimate(tx)\n            return tx\n        if ledger_api.identifier == FetchAIApi.identifier:\n            msg = {\"grant_oracle_role\": {\"address\": oracle_address}}\n            fetchai_api = cast(FetchAIApi, ledger_api)\n            tx = fetchai_api.get_handle_transaction(\n                oracle_address, contract_address, msg, amount=0, tx_fee=tx_fee, gas=gas\n            )\n            return tx\n        raise NotImplementedError\n\n    @classmethod\n    def get_update_transaction(\n        cls,\n        ledger_api: LedgerApi,\n        contract_address: Address,\n        oracle_address: Address,\n        update_function: str,\n        update_kwargs: Dict[str, Any],\n        gas: int = 0,\n        tx_fee: int = 0,\n    ) -> JSONLike:\n        \"\"\"\n        Update oracle value in contract\n\n        :param ledger_api: the ledger apis.\n        :param contract_address: the contract address.\n        :param oracle_address: the oracle address.\n        :param update_function: the oracle value update function.\n        :param update_kwargs: the arguments to the contract's update function.\n        :param gas: the gas limit\n        :param tx_fee: the transaction fee\n        :return: transaction json\n        \"\"\"\n        if ledger_api.identifier == EthereumApi.identifier:\n            nonce = ledger_api.api.eth.getTransactionCount(oracle_address)\n            instance = cls.get_instance(ledger_api, contract_address)\n            function = getattr(instance.functions, update_function)\n            update_args = list(update_kwargs.values())\n            intermediate = function(*update_args)\n            tx = intermediate.buildTransaction(\n                {\n                    \"gas\": gas,\n                    \"gasPrice\": ledger_api.api.toWei(\"50\", \"gwei\"),\n                    \"nonce\": nonce,\n                }\n            )\n            tx = ledger_api.update_with_gas_estimate(tx)\n            return tx\n        if ledger_api.identifier in FetchAIApi.identifier:\n\n            # Convert all values to strings for CosmWasm message\n            update_kwargs_str = {\n                key: str(value) for (key, value) in update_kwargs.items()\n            }\n\n            msg = {update_function: update_kwargs_str}\n            fetchai_api = cast(FetchAIApi, ledger_api)\n            tx = fetchai_api.get_handle_transaction(\n                oracle_address, contract_address, msg, amount=0, tx_fee=tx_fee, gas=gas\n            )\n            return tx\n        raise NotImplementedError\n"
  },
  {
    "path": "packages/fetchai/contracts/oracle/contract.yaml",
    "content": "name: oracle\nauthor: fetchai\nversion: 0.12.3\ntype: contract\ndescription: Fetch oracle contract\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: QmQvXSNH6CN9uNqF8bjuCiv7ThQ5D7SCEZvNgKw88uYTdT\n  __init__.py: QmYWrZY2q18XGiS8EDki97v3Gi9KHLi1YhC7e7cpbkEXU2\n  build/FetchOracle.json: QmfEMai1yxPtWoshFahBk2EyVHd9Mo8pSp1SAE83rRvQgH\n  build/oracle.wasm: QmPkM6EDcizaV39AhqynLSu7bFpy27Kda27r1bJ61W73AA\n  contract.py: QmUdjMGUHvbvQBXEC4zTzg5525pt89VATTQuq1hunJJjE3\n  contracts/FetchOracle.sol: QmadnUCtsVobBGMxiWAkqMptC9acSMBGj5x4Z4V2UhnFx8\nfingerprint_ignore_patterns: []\nclass_name: FetchOracleContract\ncontract_interface_paths:\n  ethereum: build/FetchOracle.json\n  fetchai: build/oracle.wasm\ndependencies:\n  aea-ledger-ethereum:\n    version: <2.0.0,>=1.0.0\n  aea-ledger-fetchai:\n    version: <2.0.0,>=1.0.0\n"
  },
  {
    "path": "packages/fetchai/contracts/oracle/contracts/FetchOracle.sol",
    "content": "// SPDX-License-Identifier:Apache-2.0\n//------------------------------------------------------------------------------\n//\n//   Copyright 2020 Fetch.AI Limited\n//\n//   Licensed under the Apache License, Version 2.0 (the \"License\");\n//   you may not use this file except in compliance with the License.\n//   You may obtain a copy of the License at\n//\n//       http://www.apache.org/licenses/LICENSE-2.0\n//\n//   Unless required by applicable law or agreed to in writing, software\n//   distributed under the License is distributed on an \"AS IS\" BASIS,\n//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//   See the License for the specific language governing permissions and\n//   limitations under the License.\n//\n//------------------------------------------------------------------------------\n\npragma solidity ^0.6.0;\n\nimport \"../openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../openzeppelin/contracts/access/AccessControl.sol\";\nimport \"../openzeppelin/contracts/math/SafeMath.sol\";\n\n\n/**\n @dev The contract *INTENTIONALLY* does not contain the `receive()` or fallback functions in order to ensure that all\n      unsolicited direct ETH transfers in to this contract (in direct Transaction) will fail.\n      Only way how to make successful fee transfer in ETH currency (*IF* contract is initialised for ETH as fee currency),\n      is to make transfer ETH to caller(client) contract and client contract then is responsible for further\n      *programmatic* (= *not* via Tx) transfer of fee to this this contract.\n */\ncontract FetchOracle is AccessControl {\n    using SafeMath for uint256;\n\n\n    enum  FeeCurrency { ERC20, ETH }\n\n    struct OracleValue {\n        uint256 value;\n        uint8 decimals;\n        uint256 updatedAtEthBlockNumber;\n    }\n\n    event FeeUpdated(uint256 fee);\n    event Pause(uint256 sinceBlock);\n    event ExcessTokenWithdrawal(address targetAddress, uint256 amount);\n    event AccruedFeesWithdrawal(address targetAddress, uint256 amount);\n    event ContractDeleted();\n    event OracleValueUpdated(uint256 atBlock); \n\n\n    bytes32 public constant ORACLE_ROLE = keccak256(\"ORACLE_ROLE\");\n    bytes32 public constant DELEGATE_ROLE = keccak256(\"DELEGATE_ROLE\");\n    uint256 public constant DELETE_PROTECTION_PERIOD = 370285;// 60*24*60*60[s] / (14[s/block]) = 370285[block];\n\n    IERC20 public _token;\n    uint256 public _earliestDelete;\n    uint256 public _pausedSinceBlock;\n    uint256 public _fee;\n    uint256 public _accruedFeesAmount;\n    OracleValue private _oracleValue;\n    FeeCurrency public _feeCurrency;\n\n    function _isOwner() internal view returns(bool) {\n        return hasRole(DEFAULT_ADMIN_ROLE, msg.sender);\n    }\n\n    /* Only callable by owner */\n    modifier onlyOwner() {\n        require(_isOwner(), \"Caller is not an administrator\");\n        _;\n    }\n\n    /* Only callable by owner or delegate */\n    modifier onlyDelegate() {\n        require(_isOwner() || hasRole(DELEGATE_ROLE, msg.sender), \"Caller is neither owner nor delegate\");\n        _;\n    }\n\n    /* Only callable by oracle */\n    modifier onlyOracle() {\n        require(hasRole(ORACLE_ROLE, msg.sender), \"Caller is not an oracle\");\n        _;\n    }\n\n    modifier verifyTxExpiration(uint256 expirationBlock) {\n        require(_getBlockNumber() <= expirationBlock, \"Transaction expired\");\n        _;\n    }\n\n    modifier verifyNotPaused() {\n        require(_pausedSinceBlock > _getBlockNumber(), \"Contract has been paused\");\n        _;\n    }\n\n\n    /*******************\n    Contract start\n    *******************/\n    /**\n     * @param ERC20Address address of the ERC20 contract\n     */\n    constructor(address ERC20Address, uint256 initialFee) public {\n        _setupRole(DEFAULT_ADMIN_ROLE, msg.sender);\n\n        if (ERC20Address == address(0)) {\n            _feeCurrency = FeeCurrency.ETH;\n        } else {\n            _feeCurrency = FeeCurrency.ERC20;\n            _token = IERC20(ERC20Address);\n        }\n\n        _earliestDelete = _getBlockNumber().add(DELETE_PROTECTION_PERIOD);\n        _pausedSinceBlock = ~uint256(0);\n        _fee = initialFee;\n    }\n\n\n    function updateOracleValue(\n        uint256 value,\n        uint8 decimals,\n        uint256 txExpirationBlock\n        )\n        external\n        verifyTxExpiration(txExpirationBlock)\n        onlyOracle\n    {\n        _oracleValue.value = value;\n        _oracleValue.decimals = decimals;\n        _oracleValue.updatedAtEthBlockNumber = _getBlockNumber();\n        emit OracleValueUpdated(_oracleValue.updatedAtEthBlockNumber); \n    }\n\n\n    function queryOracleValue()\n        public payable\n        returns (uint256 value, uint8 decimals, uint256 updatedAtEthBlockNumber)\n    {\n        _withdrawFee();\n        value = _oracleValue.value;\n        decimals = _oracleValue.decimals;\n        updatedAtEthBlockNumber = _oracleValue.updatedAtEthBlockNumber;\n    }\n\n\n    /**\n     * @dev Pause the non-administrative interaction with the contract\n     * @param fee - value of fee\n     * @param txExpirationBlock - block number defined by Tx sender beyond which transaction becomes invalid\n     * @dev Owners only\n     */\n    function setFee(uint256 fee, uint256 txExpirationBlock)\n        external\n        verifyTxExpiration(txExpirationBlock)\n        onlyDelegate\n    {\n        _fee = fee;\n        emit FeeUpdated(_fee);\n    }\n\n\n    /**\n     * @dev Pause the non-administrative interaction with the contract\n     * @param block_number disallow non-admin. interactions with contract for a _getBlockNumber() >= block_number\n     * @dev Owners only\n     */\n    function pauseSince(uint256 block_number, uint256 txExpirationBlock)\n        external\n        verifyTxExpiration(txExpirationBlock)\n        onlyDelegate\n    {\n        uint256 curr_block_number = _getBlockNumber();\n        _pausedSinceBlock = block_number < curr_block_number ? curr_block_number : block_number;\n        emit Pause(_pausedSinceBlock);\n    }\n\n\n    /**\n     * @dev Withdraw whole balance of all fees accrued in the contract so far.\n     * @param targetAddress : address to send tokens to\n     * @param txExpirationBlock : block number until which is the transaction valid (inclusive).\n     *                            When transaction is processed after this block, it fails.\n     * @dev Owners only\n     */\n    function withdrawAccruedFees(address payable targetAddress, uint256 txExpirationBlock)\n        external\n        verifyTxExpiration(txExpirationBlock)\n        onlyOwner\n    {\n        if (_accruedFeesAmount == 0) {\n            return;\n        }\n\n        // The following method will revert in the case of issue (e.g. not enough balance for transfer, zero address):\n        _withdrawFromContract(targetAddress, _accruedFeesAmount);\n\n        emit AccruedFeesWithdrawal(targetAddress, _accruedFeesAmount);\n        _accruedFeesAmount = 0;\n    }\n\n\n    /**\n     * @dev Withdraw \"excess\" tokens, which were sent to contract address directly via direct ERC20 transfer(...) or transferFrom(...),\n     *      without interacting with API of this (FetchOracle) contract, what could be done only by mistake.\n     *      Thus this method is meant to be used primarily for rescue purposes, enabling withdrawal of such\n     *      \"excess\" tokens out of contract.\n     * @param targetAddress : address to send tokens to\n     * @param txExpirationBlock : block number until which is the transaction valid (inclusive).\n     *                            When transaction is processed after this block, it fails.\n     */\n    function withdrawExcessTokens(address payable targetAddress, uint256 txExpirationBlock)\n        external\n        verifyTxExpiration(txExpirationBlock)\n        onlyOwner\n    {\n        uint256 contractBalance;\n\n        if (_feeCurrency == FeeCurrency.ETH)\n        {\n            contractBalance = address(this).balance;\n        }\n        else if (_feeCurrency == FeeCurrency.ERC20) {\n            contractBalance = _token.balanceOf(address(this));\n        } // NOTE(pb): Final else{...} is not necessary since it is checked in the `_withdrawFromContract(...)` call bellow\n\n        // NOTE(pb): The following subtraction shall *fail* (revert) IF the contract is in *INCONSISTENT* state,\n        //           = when contract balance is less than minial expected balance:\n        uint256 excessAmount = contractBalance.sub(_accruedFeesAmount);\n        _withdrawFromContract(targetAddress, excessAmount);\n        emit ExcessTokenWithdrawal(targetAddress, excessAmount);\n    }\n\n\n    /**\n     * @dev Delete the contract, transfers the remaining token and ether balance to the specified\n       payoutAddress\n     * @param payoutAddress address to transfer the balances to. Ensure that this is able to handle ERC20 tokens\n     * @dev owner only + only on or after `_earliestDelete` block\n     */\n    function deleteContract(address payable payoutAddress, uint256 txExpirationBlock)\n        external\n        verifyTxExpiration(txExpirationBlock)\n        onlyOwner\n    {\n        require(_earliestDelete >= _getBlockNumber(), \"Earliest delete not reached\");\n        if (_feeCurrency == FeeCurrency.ERC20) {\n            uint256 contractBalance = _token.balanceOf(address(this));\n            require(_token.transfer(payoutAddress, contractBalance));\n        }\n        emit ContractDeleted();\n        // The selfdestruct, by design, transfers *whole* ETH balance from this contract to targetAddress:\n        selfdestruct(payoutAddress);\n    }\n\n\n    function oracleValueLastUpdated() external view returns(uint256)\n    {\n        return _oracleValue.updatedAtEthBlockNumber;\n    }\n\n    function _getBlockNumber() internal view virtual returns(uint256)\n    {\n        return block.number;\n    }\n\n\n    /**\n     * @dev Withdraw fee from the caller.\n     */\n    function _withdrawFee() internal\n    {\n        if (_feeCurrency == FeeCurrency.ETH)\n        {\n           if (msg.value == _fee)\n           {\n               // No action necessary, since exact expected fee amount has been already transferred by caller,\n               // this this is just placeholder block to capture the logical condition.\n           }\n           else if (msg.value > _fee)\n           {\n               // Refund (back to caller) the excess caller paid on top of the expected _fee value:\n               msg.sender.transfer(msg.value.sub(_fee));\n           }\n           else\n           {\n               require(false, \"Insuf. ETH amount sent by caller\");\n           }\n        }\n        else if (_feeCurrency == FeeCurrency.ERC20)\n        {\n            require(_token.transferFrom(msg.sender, address(this), _fee), \"Insuf. FET allow. on caller addr\");\n        }\n        else\n        {\n            require(false, \"Unexpected contract fee currency\");\n        }\n\n        _accruedFeesAmount = _accruedFeesAmount.add(_fee);\n    }\n\n\n    function _withdrawFromContract(address payable targetAddress, uint256 amount) internal\n    {\n        require(targetAddress != address(0), \"Target is zero address\");\n\n        if (_feeCurrency == FeeCurrency.ETH)\n        {\n            // NOTE(pb): The following transfer shall *fail* with revert IF contract balance is insufficient for transfer\n            targetAddress.transfer(amount);\n        }\n        else if (_feeCurrency == FeeCurrency.ERC20)\n        {\n            // NOTE(pb): The following transfer shall *fail* with revert IF contract balance is insufficient for transfer\n            require(_token.transfer(targetAddress, amount), \"Insuff. FET funds on contr. addr\");\n        }\n        else\n        {\n            require(false, \"Unexpected contract fee currency\");\n        }\n    }\n}\n"
  },
  {
    "path": "packages/fetchai/contracts/oracle_client/README.md",
    "content": "# Fetch Oracle Client Contract\n\n## Description\n\nThis contract package is used to interface with a Fetch Oracle Client contract, which requests a real-world value from a Fetch Oracle contract.\n\n## Functions\n\n- `queryOracleValue()`: call contract method that requests oracle value from associated oracle contract\n"
  },
  {
    "path": "packages/fetchai/contracts/oracle_client/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the support resources for the Fetch oracle contract.\"\"\"\n"
  },
  {
    "path": "packages/fetchai/contracts/oracle_client/build/FetchOracleTestClient.json",
    "content": "{\n  \"abi\": [\n    {\n      \"inputs\": [\n        {\n          \"internalType\": \"address\",\n          \"name\": \"fetchOracleContractAddress\",\n          \"type\": \"address\"\n        }\n      ],\n      \"stateMutability\": \"nonpayable\",\n      \"type\": \"constructor\"\n    },\n    {\n      \"inputs\": [],\n      \"name\": \"_decimals\",\n      \"outputs\": [\n        {\n          \"internalType\": \"uint8\",\n          \"name\": \"\",\n          \"type\": \"uint8\"\n        }\n      ],\n      \"stateMutability\": \"view\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [],\n      \"name\": \"_fetch_oracle\",\n      \"outputs\": [\n        {\n          \"internalType\": \"contract FetchOracle\",\n          \"name\": \"\",\n          \"type\": \"address\"\n        }\n      ],\n      \"stateMutability\": \"view\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [],\n      \"name\": \"_updatedAtEthBlockNumber\",\n      \"outputs\": [\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"stateMutability\": \"view\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [],\n      \"name\": \"_value\",\n      \"outputs\": [\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"stateMutability\": \"view\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [],\n      \"name\": \"queryOracleValue\",\n      \"outputs\": [],\n      \"stateMutability\": \"nonpayable\",\n      \"type\": \"function\"\n    }\n  ],\n  \"allSourcePaths\": {\n    \"12\": \"interfaces/IFetchOracleClient.sol\",\n    \"9\": \"contracts/FetchOracleTestClient.sol\"\n  },\n  \"ast\": {\n    \"absolutePath\": \"contracts/FetchOracleTestClient.sol\",\n    \"exportedSymbols\": {\n      \"FetchOracleTestClient\": [\n        188\n      ],\n      \"FetchOracleTestClientETH\": [\n        200\n      ]\n    },\n    \"id\": 201,\n    \"license\": \"Apache-2.0\",\n    \"nodeType\": \"SourceUnit\",\n    \"nodes\": [\n      {\n        \"id\": 119,\n        \"literals\": [\n          \"solidity\",\n          \"^\",\n          \"0.6\",\n          \".0\"\n        ],\n        \"nodeType\": \"PragmaDirective\",\n        \"src\": \"820:23:9\"\n      },\n      {\n        \"absolutePath\": \"contracts/FetchOracleMock.sol\",\n        \"file\": \"./FetchOracleMock.sol\",\n        \"id\": 120,\n        \"nodeType\": \"ImportDirective\",\n        \"scope\": 201,\n        \"sourceUnit\": 118,\n        \"src\": \"845:31:9\",\n        \"symbolAliases\": [],\n        \"unitAlias\": \"\"\n      },\n      {\n        \"absolutePath\": \"interfaces/IFetchOracleClient.sol\",\n        \"file\": \"../interfaces/IFetchOracleClient.sol\",\n        \"id\": 121,\n        \"nodeType\": \"ImportDirective\",\n        \"scope\": 201,\n        \"sourceUnit\": 448,\n        \"src\": \"877:46:9\",\n        \"symbolAliases\": [],\n        \"unitAlias\": \"\"\n      },\n      {\n        \"abstract\": false,\n        \"baseContracts\": [\n          {\n            \"arguments\": null,\n            \"baseName\": {\n              \"contractScope\": null,\n              \"id\": 122,\n              \"name\": \"IFetchOracleClient\",\n              \"nodeType\": \"UserDefinedTypeName\",\n              \"referencedDeclaration\": 447,\n              \"src\": \"959:18:9\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_contract$_IFetchOracleClient_$447\",\n                \"typeString\": \"contract IFetchOracleClient\"\n              }\n            },\n            \"id\": 123,\n            \"nodeType\": \"InheritanceSpecifier\",\n            \"src\": \"959:18:9\"\n          }\n        ],\n        \"contractDependencies\": [\n          447\n        ],\n        \"contractKind\": \"contract\",\n        \"documentation\": null,\n        \"fullyImplemented\": true,\n        \"id\": 188,\n        \"linearizedBaseContracts\": [\n          188,\n          447\n        ],\n        \"name\": \"FetchOracleTestClient\",\n        \"nodeType\": \"ContractDefinition\",\n        \"nodes\": [\n          {\n            \"constant\": false,\n            \"functionSelector\": \"19cc4b5a\",\n            \"id\": 125,\n            \"mutability\": \"mutable\",\n            \"name\": \"_fetch_oracle\",\n            \"nodeType\": \"VariableDeclaration\",\n            \"overrides\": null,\n            \"scope\": 188,\n            \"src\": \"983:32:9\",\n            \"stateVariable\": true,\n            \"storageLocation\": \"default\",\n            \"typeDescriptions\": {\n              \"typeIdentifier\": \"t_contract$_FetchOracle_$441\",\n              \"typeString\": \"contract FetchOracle\"\n            },\n            \"typeName\": {\n              \"contractScope\": null,\n              \"id\": 124,\n              \"name\": \"FetchOracle\",\n              \"nodeType\": \"UserDefinedTypeName\",\n              \"referencedDeclaration\": 441,\n              \"src\": \"983:11:9\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_contract$_FetchOracle_$441\",\n                \"typeString\": \"contract FetchOracle\"\n              }\n            },\n            \"value\": null,\n            \"visibility\": \"public\"\n          },\n          {\n            \"constant\": false,\n            \"functionSelector\": \"b895c74a\",\n            \"id\": 127,\n            \"mutability\": \"mutable\",\n            \"name\": \"_value\",\n            \"nodeType\": \"VariableDeclaration\",\n            \"overrides\": null,\n            \"scope\": 188,\n            \"src\": \"1022:21:9\",\n            \"stateVariable\": true,\n            \"storageLocation\": \"default\",\n            \"typeDescriptions\": {\n              \"typeIdentifier\": \"t_uint256\",\n              \"typeString\": \"uint256\"\n            },\n            \"typeName\": {\n              \"id\": 126,\n              \"name\": \"uint256\",\n              \"nodeType\": \"ElementaryTypeName\",\n              \"src\": \"1022:7:9\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_uint256\",\n                \"typeString\": \"uint256\"\n              }\n            },\n            \"value\": null,\n            \"visibility\": \"public\"\n          },\n          {\n            \"constant\": false,\n            \"functionSelector\": \"32424aa3\",\n            \"id\": 129,\n            \"mutability\": \"mutable\",\n            \"name\": \"_decimals\",\n            \"nodeType\": \"VariableDeclaration\",\n            \"overrides\": null,\n            \"scope\": 188,\n            \"src\": \"1049:22:9\",\n            \"stateVariable\": true,\n            \"storageLocation\": \"default\",\n            \"typeDescriptions\": {\n              \"typeIdentifier\": \"t_uint8\",\n              \"typeString\": \"uint8\"\n            },\n            \"typeName\": {\n              \"id\": 128,\n              \"name\": \"uint8\",\n              \"nodeType\": \"ElementaryTypeName\",\n              \"src\": \"1049:5:9\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_uint8\",\n                \"typeString\": \"uint8\"\n              }\n            },\n            \"value\": null,\n            \"visibility\": \"public\"\n          },\n          {\n            \"constant\": false,\n            \"functionSelector\": \"4e5551ce\",\n            \"id\": 131,\n            \"mutability\": \"mutable\",\n            \"name\": \"_updatedAtEthBlockNumber\",\n            \"nodeType\": \"VariableDeclaration\",\n            \"overrides\": null,\n            \"scope\": 188,\n            \"src\": \"1077:39:9\",\n            \"stateVariable\": true,\n            \"storageLocation\": \"default\",\n            \"typeDescriptions\": {\n              \"typeIdentifier\": \"t_uint256\",\n              \"typeString\": \"uint256\"\n            },\n            \"typeName\": {\n              \"id\": 130,\n              \"name\": \"uint256\",\n              \"nodeType\": \"ElementaryTypeName\",\n              \"src\": \"1077:7:9\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_uint256\",\n                \"typeString\": \"uint256\"\n              }\n            },\n            \"value\": null,\n            \"visibility\": \"public\"\n          },\n          {\n            \"body\": {\n              \"id\": 142,\n              \"nodeType\": \"Block\",\n              \"src\": \"1179:144:9\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 140,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 136,\n                      \"name\": \"_fetch_oracle\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 125,\n                      \"src\": \"1257:13:9\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_contract$_FetchOracle_$441\",\n                        \"typeString\": \"contract FetchOracle\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"arguments\": [\n                        {\n                          \"argumentTypes\": null,\n                          \"id\": 138,\n                          \"name\": \"fetchOracleContractAddress\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 133,\n                          \"src\": \"1289:26:9\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_address\",\n                            \"typeString\": \"address\"\n                          }\n                        }\n                      ],\n                      \"expression\": {\n                        \"argumentTypes\": [\n                          {\n                            \"typeIdentifier\": \"t_address\",\n                            \"typeString\": \"address\"\n                          }\n                        ],\n                        \"id\": 137,\n                        \"name\": \"FetchOracleMock\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 101,\n                        \"src\": \"1273:15:9\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_type$_t_contract$_FetchOracleMock_$101_$\",\n                          \"typeString\": \"type(contract FetchOracleMock)\"\n                        }\n                      },\n                      \"id\": 139,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": false,\n                      \"kind\": \"typeConversion\",\n                      \"lValueRequested\": false,\n                      \"names\": [],\n                      \"nodeType\": \"FunctionCall\",\n                      \"src\": \"1273:43:9\",\n                      \"tryCall\": false,\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_contract$_FetchOracleMock_$101\",\n                        \"typeString\": \"contract FetchOracleMock\"\n                      }\n                    },\n                    \"src\": \"1257:59:9\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_contract$_FetchOracle_$441\",\n                      \"typeString\": \"contract FetchOracle\"\n                    }\n                  },\n                  \"id\": 141,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"1257:59:9\"\n                }\n              ]\n            },\n            \"documentation\": null,\n            \"id\": 143,\n            \"implemented\": true,\n            \"kind\": \"constructor\",\n            \"modifiers\": [],\n            \"name\": \"\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 134,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 133,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"fetchOracleContractAddress\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 143,\n                  \"src\": \"1136:34:9\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_address\",\n                    \"typeString\": \"address\"\n                  },\n                  \"typeName\": {\n                    \"id\": 132,\n                    \"name\": \"address\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"1136:7:9\",\n                    \"stateMutability\": \"nonpayable\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address\",\n                      \"typeString\": \"address\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"1135:36:9\"\n            },\n            \"returnParameters\": {\n              \"id\": 135,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"1179:0:9\"\n            },\n            \"scope\": 188,\n            \"src\": \"1124:199:9\",\n            \"stateMutability\": \"nonpayable\",\n            \"virtual\": false,\n            \"visibility\": \"public\"\n          },\n          {\n            \"baseFunctions\": [\n              446\n            ],\n            \"body\": {\n              \"id\": 186,\n              \"nodeType\": \"Block\",\n              \"src\": \"1380:277:9\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 152,\n                          \"name\": \"msg\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": -15,\n                          \"src\": \"1426:3:9\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_magic_message\",\n                            \"typeString\": \"msg\"\n                          }\n                        },\n                        \"id\": 153,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"memberName\": \"sender\",\n                        \"nodeType\": \"MemberAccess\",\n                        \"referencedDeclaration\": null,\n                        \"src\": \"1426:10:9\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"arguments\": [\n                          {\n                            \"argumentTypes\": null,\n                            \"id\": 156,\n                            \"name\": \"this\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": -28,\n                            \"src\": \"1446:4:9\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_contract$_FetchOracleTestClient_$188\",\n                              \"typeString\": \"contract FetchOracleTestClient\"\n                            }\n                          }\n                        ],\n                        \"expression\": {\n                          \"argumentTypes\": [\n                            {\n                              \"typeIdentifier\": \"t_contract$_FetchOracleTestClient_$188\",\n                              \"typeString\": \"contract FetchOracleTestClient\"\n                            }\n                          ],\n                          \"id\": 155,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": true,\n                          \"lValueRequested\": false,\n                          \"nodeType\": \"ElementaryTypeNameExpression\",\n                          \"src\": \"1438:7:9\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_type$_t_address_$\",\n                            \"typeString\": \"type(address)\"\n                          },\n                          \"typeName\": {\n                            \"id\": 154,\n                            \"name\": \"address\",\n                            \"nodeType\": \"ElementaryTypeName\",\n                            \"src\": \"1438:7:9\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": null,\n                              \"typeString\": null\n                            }\n                          }\n                        },\n                        \"id\": 157,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"kind\": \"typeConversion\",\n                        \"lValueRequested\": false,\n                        \"names\": [],\n                        \"nodeType\": \"FunctionCall\",\n                        \"src\": \"1438:13:9\",\n                        \"tryCall\": false,\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"arguments\": [],\n                        \"expression\": {\n                          \"argumentTypes\": [],\n                          \"expression\": {\n                            \"argumentTypes\": null,\n                            \"id\": 158,\n                            \"name\": \"_fetch_oracle\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 125,\n                            \"src\": \"1453:13:9\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_contract$_FetchOracle_$441\",\n                              \"typeString\": \"contract FetchOracle\"\n                            }\n                          },\n                          \"id\": 159,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"memberName\": \"_fee\",\n                          \"nodeType\": \"MemberAccess\",\n                          \"referencedDeclaration\": 491,\n                          \"src\": \"1453:18:9\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_function_external_view$__$returns$_t_uint256_$\",\n                            \"typeString\": \"function () view external returns (uint256)\"\n                          }\n                        },\n                        \"id\": 160,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"kind\": \"functionCall\",\n                        \"lValueRequested\": false,\n                        \"names\": [],\n                        \"nodeType\": \"FunctionCall\",\n                        \"src\": \"1453:20:9\",\n                        \"tryCall\": false,\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"arguments\": [],\n                        \"expression\": {\n                          \"argumentTypes\": [],\n                          \"expression\": {\n                            \"argumentTypes\": null,\n                            \"id\": 147,\n                            \"name\": \"_fetch_oracle\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 125,\n                            \"src\": \"1390:13:9\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_contract$_FetchOracle_$441\",\n                              \"typeString\": \"contract FetchOracle\"\n                            }\n                          },\n                          \"id\": 149,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"memberName\": \"_token\",\n                          \"nodeType\": \"MemberAccess\",\n                          \"referencedDeclaration\": 485,\n                          \"src\": \"1390:20:9\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_function_external_view$__$returns$_t_contract$_IERC20_$1542_$\",\n                            \"typeString\": \"function () view external returns (contract IERC20)\"\n                          }\n                        },\n                        \"id\": 150,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"kind\": \"functionCall\",\n                        \"lValueRequested\": false,\n                        \"names\": [],\n                        \"nodeType\": \"FunctionCall\",\n                        \"src\": \"1390:22:9\",\n                        \"tryCall\": false,\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_contract$_IERC20_$1542\",\n                          \"typeString\": \"contract IERC20\"\n                        }\n                      },\n                      \"id\": 151,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"memberName\": \"transferFrom\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": 1523,\n                      \"src\": \"1390:35:9\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_external_nonpayable$_t_address_$_t_address_$_t_uint256_$returns$_t_bool_$\",\n                        \"typeString\": \"function (address,address,uint256) external returns (bool)\"\n                      }\n                    },\n                    \"id\": 161,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"1390:84:9\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_bool\",\n                      \"typeString\": \"bool\"\n                    }\n                  },\n                  \"id\": 162,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"1390:84:9\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"arguments\": [\n                          {\n                            \"argumentTypes\": null,\n                            \"id\": 170,\n                            \"name\": \"_fetch_oracle\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 125,\n                            \"src\": \"1523:13:9\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_contract$_FetchOracle_$441\",\n                              \"typeString\": \"contract FetchOracle\"\n                            }\n                          }\n                        ],\n                        \"expression\": {\n                          \"argumentTypes\": [\n                            {\n                              \"typeIdentifier\": \"t_contract$_FetchOracle_$441\",\n                              \"typeString\": \"contract FetchOracle\"\n                            }\n                          ],\n                          \"id\": 169,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": true,\n                          \"lValueRequested\": false,\n                          \"nodeType\": \"ElementaryTypeNameExpression\",\n                          \"src\": \"1515:7:9\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_type$_t_address_$\",\n                            \"typeString\": \"type(address)\"\n                          },\n                          \"typeName\": {\n                            \"id\": 168,\n                            \"name\": \"address\",\n                            \"nodeType\": \"ElementaryTypeName\",\n                            \"src\": \"1515:7:9\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": null,\n                              \"typeString\": null\n                            }\n                          }\n                        },\n                        \"id\": 171,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"kind\": \"typeConversion\",\n                        \"lValueRequested\": false,\n                        \"names\": [],\n                        \"nodeType\": \"FunctionCall\",\n                        \"src\": \"1515:22:9\",\n                        \"tryCall\": false,\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"arguments\": [],\n                        \"expression\": {\n                          \"argumentTypes\": [],\n                          \"expression\": {\n                            \"argumentTypes\": null,\n                            \"id\": 172,\n                            \"name\": \"_fetch_oracle\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 125,\n                            \"src\": \"1539:13:9\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_contract$_FetchOracle_$441\",\n                              \"typeString\": \"contract FetchOracle\"\n                            }\n                          },\n                          \"id\": 173,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"memberName\": \"_fee\",\n                          \"nodeType\": \"MemberAccess\",\n                          \"referencedDeclaration\": 491,\n                          \"src\": \"1539:18:9\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_function_external_view$__$returns$_t_uint256_$\",\n                            \"typeString\": \"function () view external returns (uint256)\"\n                          }\n                        },\n                        \"id\": 174,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"kind\": \"functionCall\",\n                        \"lValueRequested\": false,\n                        \"names\": [],\n                        \"nodeType\": \"FunctionCall\",\n                        \"src\": \"1539:20:9\",\n                        \"tryCall\": false,\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"arguments\": [],\n                        \"expression\": {\n                          \"argumentTypes\": [],\n                          \"expression\": {\n                            \"argumentTypes\": null,\n                            \"id\": 163,\n                            \"name\": \"_fetch_oracle\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 125,\n                            \"src\": \"1484:13:9\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_contract$_FetchOracle_$441\",\n                              \"typeString\": \"contract FetchOracle\"\n                            }\n                          },\n                          \"id\": 165,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"memberName\": \"_token\",\n                          \"nodeType\": \"MemberAccess\",\n                          \"referencedDeclaration\": 485,\n                          \"src\": \"1484:20:9\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_function_external_view$__$returns$_t_contract$_IERC20_$1542_$\",\n                            \"typeString\": \"function () view external returns (contract IERC20)\"\n                          }\n                        },\n                        \"id\": 166,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"kind\": \"functionCall\",\n                        \"lValueRequested\": false,\n                        \"names\": [],\n                        \"nodeType\": \"FunctionCall\",\n                        \"src\": \"1484:22:9\",\n                        \"tryCall\": false,\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_contract$_IERC20_$1542\",\n                          \"typeString\": \"contract IERC20\"\n                        }\n                      },\n                      \"id\": 167,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"memberName\": \"approve\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": 1511,\n                      \"src\": \"1484:30:9\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_external_nonpayable$_t_address_$_t_uint256_$returns$_t_bool_$\",\n                        \"typeString\": \"function (address,uint256) external returns (bool)\"\n                      }\n                    },\n                    \"id\": 175,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"1484:76:9\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_bool\",\n                      \"typeString\": \"bool\"\n                    }\n                  },\n                  \"id\": 176,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"1484:76:9\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 184,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"components\": [\n                        {\n                          \"argumentTypes\": null,\n                          \"id\": 177,\n                          \"name\": \"_value\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 127,\n                          \"src\": \"1571:6:9\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        {\n                          \"argumentTypes\": null,\n                          \"id\": 178,\n                          \"name\": \"_decimals\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 129,\n                          \"src\": \"1579:9:9\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint8\",\n                            \"typeString\": \"uint8\"\n                          }\n                        },\n                        {\n                          \"argumentTypes\": null,\n                          \"id\": 179,\n                          \"name\": \"_updatedAtEthBlockNumber\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 131,\n                          \"src\": \"1590:24:9\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        }\n                      ],\n                      \"id\": 180,\n                      \"isConstant\": false,\n                      \"isInlineArray\": false,\n                      \"isLValue\": true,\n                      \"isPure\": false,\n                      \"lValueRequested\": true,\n                      \"nodeType\": \"TupleExpression\",\n                      \"src\": \"1570:45:9\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_tuple$_t_uint256_$_t_uint8_$_t_uint256_$\",\n                        \"typeString\": \"tuple(uint256,uint8,uint256)\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"arguments\": [],\n                      \"expression\": {\n                        \"argumentTypes\": [],\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 181,\n                          \"name\": \"_fetch_oracle\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 125,\n                          \"src\": \"1618:13:9\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_contract$_FetchOracle_$441\",\n                            \"typeString\": \"contract FetchOracle\"\n                          }\n                        },\n                        \"id\": 182,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"memberName\": \"queryOracleValue\",\n                        \"nodeType\": \"MemberAccess\",\n                        \"referencedDeclaration\": 431,\n                        \"src\": \"1618:30:9\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_function_external_payable$__$returns$_t_uint256_$_t_uint8_$_t_uint256_$\",\n                          \"typeString\": \"function () payable external returns (uint256,uint8,uint256)\"\n                        }\n                      },\n                      \"id\": 183,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": false,\n                      \"kind\": \"functionCall\",\n                      \"lValueRequested\": false,\n                      \"names\": [],\n                      \"nodeType\": \"FunctionCall\",\n                      \"src\": \"1618:32:9\",\n                      \"tryCall\": false,\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_tuple$_t_uint256_$_t_uint8_$_t_uint256_$\",\n                        \"typeString\": \"tuple(uint256,uint8,uint256)\"\n                      }\n                    },\n                    \"src\": \"1570:80:9\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 185,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"1570:80:9\"\n                }\n              ]\n            },\n            \"documentation\": null,\n            \"functionSelector\": \"f7e1c748\",\n            \"id\": 187,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [],\n            \"name\": \"queryOracleValue\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": {\n              \"id\": 145,\n              \"nodeType\": \"OverrideSpecifier\",\n              \"overrides\": [],\n              \"src\": \"1367:8:9\"\n            },\n            \"parameters\": {\n              \"id\": 144,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"1355:2:9\"\n            },\n            \"returnParameters\": {\n              \"id\": 146,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"1380:0:9\"\n            },\n            \"scope\": 188,\n            \"src\": \"1330:327:9\",\n            \"stateMutability\": \"nonpayable\",\n            \"virtual\": false,\n            \"visibility\": \"external\"\n          }\n        ],\n        \"scope\": 201,\n        \"src\": \"925:734:9\"\n      },\n      {\n        \"abstract\": false,\n        \"baseContracts\": [\n          {\n            \"arguments\": null,\n            \"baseName\": {\n              \"contractScope\": null,\n              \"id\": 189,\n              \"name\": \"FetchOracleTestClient\",\n              \"nodeType\": \"UserDefinedTypeName\",\n              \"referencedDeclaration\": 188,\n              \"src\": \"1769:21:9\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_contract$_FetchOracleTestClient_$188\",\n                \"typeString\": \"contract FetchOracleTestClient\"\n              }\n            },\n            \"id\": 190,\n            \"nodeType\": \"InheritanceSpecifier\",\n            \"src\": \"1769:21:9\"\n          }\n        ],\n        \"contractDependencies\": [\n          188,\n          447\n        ],\n        \"contractKind\": \"contract\",\n        \"documentation\": null,\n        \"fullyImplemented\": true,\n        \"id\": 200,\n        \"linearizedBaseContracts\": [\n          200,\n          188,\n          447\n        ],\n        \"name\": \"FetchOracleTestClientETH\",\n        \"nodeType\": \"ContractDefinition\",\n        \"nodes\": [\n          {\n            \"body\": {\n              \"id\": 198,\n              \"nodeType\": \"Block\",\n              \"src\": \"1902:7:9\",\n              \"statements\": []\n            },\n            \"documentation\": null,\n            \"id\": 199,\n            \"implemented\": true,\n            \"kind\": \"constructor\",\n            \"modifiers\": [\n              {\n                \"arguments\": [\n                  {\n                    \"argumentTypes\": null,\n                    \"id\": 195,\n                    \"name\": \"fetchOracleContractAddress\",\n                    \"nodeType\": \"Identifier\",\n                    \"overloadedDeclarations\": [],\n                    \"referencedDeclaration\": 192,\n                    \"src\": \"1874:26:9\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address\",\n                      \"typeString\": \"address\"\n                    }\n                  }\n                ],\n                \"id\": 196,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 194,\n                  \"name\": \"FetchOracleTestClient\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 188,\n                  \"src\": \"1852:21:9\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_type$_t_contract$_FetchOracleTestClient_$188_$\",\n                    \"typeString\": \"type(contract FetchOracleTestClient)\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"1852:49:9\"\n              }\n            ],\n            \"name\": \"\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 193,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 192,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"fetchOracleContractAddress\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 199,\n                  \"src\": \"1809:34:9\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_address\",\n                    \"typeString\": \"address\"\n                  },\n                  \"typeName\": {\n                    \"id\": 191,\n                    \"name\": \"address\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"1809:7:9\",\n                    \"stateMutability\": \"nonpayable\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address\",\n                      \"typeString\": \"address\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"1808:36:9\"\n            },\n            \"returnParameters\": {\n              \"id\": 197,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"1902:0:9\"\n            },\n            \"scope\": 200,\n            \"src\": \"1797:112:9\",\n            \"stateMutability\": \"nonpayable\",\n            \"virtual\": false,\n            \"visibility\": \"public\"\n          }\n        ],\n        \"scope\": 201,\n        \"src\": \"1732:179:9\"\n      }\n    ],\n    \"src\": \"820:1092:9\"\n  },\n  \"bytecode\": \"608060405234801561001057600080fd5b506040516105053803806105058339818101604052602081101561003357600080fd5b5051600080546001600160a01b039092166001600160a01b03199092169190911790556104a0806100656000396000f3fe608060405234801561001057600080fd5b50600436106100575760003560e01c806319cc4b5a1461005c57806332424aa3146100805780634e5551ce1461009e578063b895c74a146100b8578063f7e1c748146100c0575b600080fd5b6100646100ca565b604080516001600160a01b039092168252519081900360200190f35b6100886100d9565b6040805160ff9092168252519081900360200190f35b6100a66100e2565b60408051918252519081900360200190f35b6100a66100e8565b6100c86100ee565b005b6000546001600160a01b031681565b60025460ff1681565b60035481565b60015481565b60008054906101000a90046001600160a01b03166001600160a01b031663ecd0c0c36040518163ffffffff1660e01b815260040160206040518083038186803b15801561013a57600080fd5b505afa15801561014e573d6000803e3d6000fd5b505050506040513d602081101561016457600080fd5b5051600054604080516362d9be1160e11b815290516001600160a01b03938416936323b872dd9333933093919092169163c5b37c22916004808301926020929190829003018186803b1580156101b957600080fd5b505afa1580156101cd573d6000803e3d6000fd5b505050506040513d60208110156101e357600080fd5b5051604080516001600160e01b031960e087901b1681526001600160a01b0394851660048201529290931660248301526044820152905160648083019260209291908290030181600087803b15801561023b57600080fd5b505af115801561024f573d6000803e3d6000fd5b505050506040513d602081101561026557600080fd5b50506000546040805163ecd0c0c360e01b815290516001600160a01b039092169163ecd0c0c391600480820192602092909190829003018186803b1580156102ac57600080fd5b505afa1580156102c0573d6000803e3d6000fd5b505050506040513d60208110156102d657600080fd5b5051600054604080516362d9be1160e11b815290516001600160a01b039384169363095ea7b3931691829163c5b37c2291600480820192602092909190829003018186803b15801561032757600080fd5b505afa15801561033b573d6000803e3d6000fd5b505050506040513d602081101561035157600080fd5b5051604080516001600160e01b031960e086901b1681526001600160a01b03909316600484015260248301919091525160448083019260209291908290030181600087803b1580156103a257600080fd5b505af11580156103b6573d6000803e3d6000fd5b505050506040513d60208110156103cc57600080fd5b50506000805460408051631efc38e960e31b815290516001600160a01b039092169263f7e1c748926004808401936060939083900390910190829087803b15801561041657600080fd5b505af115801561042a573d6000803e3d6000fd5b505050506040513d606081101561044057600080fd5b50805160208201516040909201516003556002805460ff191660ff9093169290921790915560015556fea26469706673582212203ed415b0bf9e63200b9658ae26b80a450e549e9a0e9ad3934c5c1496ec57aa0e64736f6c634300060c0033\",\n  \"bytecodeSha1\": \"796e98fdfc59410c81344db30cddb2856d6dfd13\",\n  \"compiler\": {\n    \"evm_version\": \"istanbul\",\n    \"optimizer\": {\n      \"enabled\": true,\n      \"runs\": 200\n    },\n    \"version\": \"0.6.12\"\n  },\n  \"contractName\": \"FetchOracleTestClient\",\n  \"coverageMap\": {\n    \"branches\": {\n      \"12\": {},\n      \"9\": {}\n    },\n    \"statements\": {\n      \"12\": {},\n      \"9\": {\n        \"FetchOracleTestClient.queryOracleValue\": {\n          \"0\": [\n            1390,\n            1474\n          ],\n          \"1\": [\n            1484,\n            1560\n          ],\n          \"2\": [\n            1570,\n            1650\n          ]\n        }\n      }\n    }\n  },\n  \"dependencies\": [\n    \"IFetchOracleClient\"\n  ],\n  \"deployedBytecode\": \"608060405234801561001057600080fd5b50600436106100575760003560e01c806319cc4b5a1461005c57806332424aa3146100805780634e5551ce1461009e578063b895c74a146100b8578063f7e1c748146100c0575b600080fd5b6100646100ca565b604080516001600160a01b039092168252519081900360200190f35b6100886100d9565b6040805160ff9092168252519081900360200190f35b6100a66100e2565b60408051918252519081900360200190f35b6100a66100e8565b6100c86100ee565b005b6000546001600160a01b031681565b60025460ff1681565b60035481565b60015481565b60008054906101000a90046001600160a01b03166001600160a01b031663ecd0c0c36040518163ffffffff1660e01b815260040160206040518083038186803b15801561013a57600080fd5b505afa15801561014e573d6000803e3d6000fd5b505050506040513d602081101561016457600080fd5b5051600054604080516362d9be1160e11b815290516001600160a01b03938416936323b872dd9333933093919092169163c5b37c22916004808301926020929190829003018186803b1580156101b957600080fd5b505afa1580156101cd573d6000803e3d6000fd5b505050506040513d60208110156101e357600080fd5b5051604080516001600160e01b031960e087901b1681526001600160a01b0394851660048201529290931660248301526044820152905160648083019260209291908290030181600087803b15801561023b57600080fd5b505af115801561024f573d6000803e3d6000fd5b505050506040513d602081101561026557600080fd5b50506000546040805163ecd0c0c360e01b815290516001600160a01b039092169163ecd0c0c391600480820192602092909190829003018186803b1580156102ac57600080fd5b505afa1580156102c0573d6000803e3d6000fd5b505050506040513d60208110156102d657600080fd5b5051600054604080516362d9be1160e11b815290516001600160a01b039384169363095ea7b3931691829163c5b37c2291600480820192602092909190829003018186803b15801561032757600080fd5b505afa15801561033b573d6000803e3d6000fd5b505050506040513d602081101561035157600080fd5b5051604080516001600160e01b031960e086901b1681526001600160a01b03909316600484015260248301919091525160448083019260209291908290030181600087803b1580156103a257600080fd5b505af11580156103b6573d6000803e3d6000fd5b505050506040513d60208110156103cc57600080fd5b50506000805460408051631efc38e960e31b815290516001600160a01b039092169263f7e1c748926004808401936060939083900390910190829087803b15801561041657600080fd5b505af115801561042a573d6000803e3d6000fd5b505050506040513d606081101561044057600080fd5b50805160208201516040909201516003556002805460ff191660ff9093169290921790915560015556fea26469706673582212203ed415b0bf9e63200b9658ae26b80a450e549e9a0e9ad3934c5c1496ec57aa0e64736f6c634300060c0033\",\n  \"deployedSourceMap\": \"925:734:9:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;983:32;;;:::i;:::-;;;;-1:-1:-1;;;;;983:32:9;;;;;;;;;;;;;;1049:22;;;:::i;:::-;;;;;;;;;;;;;;;;;;;1077:39;;;:::i;:::-;;;;;;;;;;;;;;;;1022:21;;;:::i;1330:327::-;;;:::i;:::-;;983:32;;;-1:-1:-1;;;;;983:32:9;;:::o;1049:22::-;;;;;;:::o;1077:39::-;;;;:::o;1022:21::-;;;;:::o;1330:327::-;1390:13;;;;;;;;-1:-1:-1;;;;;1390:13:9;-1:-1:-1;;;;;1390:20:9;;:22;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;1390:22:9;1453:13;;:20;;;-1:-1:-1;;;1453:20:9;;;;-1:-1:-1;;;;;1390:35:9;;;;;;1426:10;;1446:4;;1453:13;;;;;:18;;:20;;;;;1390:22;;1453:20;;;;;;;:13;:20;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;1453:20:9;1390:84;;;-1:-1:-1;;;;;;1390:84:9;;;;;;;-1:-1:-1;;;;;1390:84:9;;;;;;;;;;;;;;;;;;;;;;;;;;1453:20;;1390:84;;;;;;;-1:-1:-1;1390:84:9;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1484:13:9;;:22;;;-1:-1:-1;;;1484:22:9;;;;-1:-1:-1;;;;;1484:13:9;;;;:20;;:22;;;;;1390:84;;1484:22;;;;;;;;:13;:22;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;1484:22:9;1523:13;;1539:20;;;-1:-1:-1;;;1539:20:9;;;;-1:-1:-1;;;;;1484:30:9;;;;;;1523:13;;;;1539:18;;:20;;;;;1484:22;;1539:20;;;;;;;;1523:13;1539:20;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;1539:20:9;1484:76;;;-1:-1:-1;;;;;;1484:76:9;;;;;;;-1:-1:-1;;;;;1484:76:9;;;;;;;;;;;;;;;;;;;;1539:20;;1484:76;;;;;;;-1:-1:-1;1484:76:9;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1618:13:9;;;:32;;;-1:-1:-1;;;1618:32:9;;;;-1:-1:-1;;;;;1618:13:9;;;;:30;;:32;;;;;;;;;;;;;;;;;:13;:32;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;1618:32:9;;;;;;;;;;;1590:24;1570:80;1579:9;1570:80;;-1:-1:-1;;1570:80:9;;;;;;;;;;;;-1:-1:-1;1570:80:9;1330:327::o\",\n  \"language\": \"Solidity\",\n  \"natspec\": {\n    \"kind\": \"dev\",\n    \"methods\": {},\n    \"version\": 1\n  },\n  \"offset\": [\n    925,\n    1659\n  ],\n  \"opcodes\": \"PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x4 CALLDATASIZE LT PUSH2 0x57 JUMPI PUSH1 0x0 CALLDATALOAD PUSH1 0xE0 SHR DUP1 PUSH4 0x19CC4B5A EQ PUSH2 0x5C JUMPI DUP1 PUSH4 0x32424AA3 EQ PUSH2 0x80 JUMPI DUP1 PUSH4 0x4E5551CE EQ PUSH2 0x9E JUMPI DUP1 PUSH4 0xB895C74A EQ PUSH2 0xB8 JUMPI DUP1 PUSH4 0xF7E1C748 EQ PUSH2 0xC0 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x64 PUSH2 0xCA JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB SWAP1 SWAP3 AND DUP3 MSTORE MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x20 ADD SWAP1 RETURN JUMPDEST PUSH2 0x88 PUSH2 0xD9 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0xFF SWAP1 SWAP3 AND DUP3 MSTORE MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x20 ADD SWAP1 RETURN JUMPDEST PUSH2 0xA6 PUSH2 0xE2 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD SWAP2 DUP3 MSTORE MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x20 ADD SWAP1 RETURN JUMPDEST PUSH2 0xA6 PUSH2 0xE8 JUMP JUMPDEST PUSH2 0xC8 PUSH2 0xEE JUMP JUMPDEST STOP JUMPDEST PUSH1 0x0 SLOAD PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB AND DUP2 JUMP JUMPDEST PUSH1 0x2 SLOAD PUSH1 0xFF AND DUP2 JUMP JUMPDEST PUSH1 0x3 SLOAD DUP2 JUMP JUMPDEST PUSH1 0x1 SLOAD DUP2 JUMP JUMPDEST PUSH1 0x0 DUP1 SLOAD SWAP1 PUSH2 0x100 EXP SWAP1 DIV PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB AND PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB AND PUSH4 0xECD0C0C3 PUSH1 0x40 MLOAD DUP2 PUSH4 0xFFFFFFFF AND PUSH1 0xE0 SHL DUP2 MSTORE PUSH1 0x4 ADD PUSH1 0x20 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 DUP7 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x13A JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS STATICCALL ISZERO DUP1 ISZERO PUSH2 0x14E JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x164 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP MLOAD PUSH1 0x0 SLOAD PUSH1 0x40 DUP1 MLOAD PUSH4 0x62D9BE11 PUSH1 0xE1 SHL DUP2 MSTORE SWAP1 MLOAD PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB SWAP4 DUP5 AND SWAP4 PUSH4 0x23B872DD SWAP4 CALLER SWAP4 ADDRESS SWAP4 SWAP2 SWAP1 SWAP3 AND SWAP2 PUSH4 0xC5B37C22 SWAP2 PUSH1 0x4 DUP1 DUP4 ADD SWAP3 PUSH1 0x20 SWAP3 SWAP2 SWAP1 DUP3 SWAP1 SUB ADD DUP2 DUP7 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x1B9 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS STATICCALL ISZERO DUP1 ISZERO PUSH2 0x1CD JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x1E3 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP MLOAD PUSH1 0x40 DUP1 MLOAD PUSH1 0x1 PUSH1 0x1 PUSH1 0xE0 SHL SUB NOT PUSH1 0xE0 DUP8 SWAP1 SHL AND DUP2 MSTORE PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB SWAP5 DUP6 AND PUSH1 0x4 DUP3 ADD MSTORE SWAP3 SWAP1 SWAP4 AND PUSH1 0x24 DUP4 ADD MSTORE PUSH1 0x44 DUP3 ADD MSTORE SWAP1 MLOAD PUSH1 0x64 DUP1 DUP4 ADD SWAP3 PUSH1 0x20 SWAP3 SWAP2 SWAP1 DUP3 SWAP1 SUB ADD DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x23B JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x24F JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x265 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP POP PUSH1 0x0 SLOAD PUSH1 0x40 DUP1 MLOAD PUSH4 0xECD0C0C3 PUSH1 0xE0 SHL DUP2 MSTORE SWAP1 MLOAD PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB SWAP1 SWAP3 AND SWAP2 PUSH4 0xECD0C0C3 SWAP2 PUSH1 0x4 DUP1 DUP3 ADD SWAP3 PUSH1 0x20 SWAP3 SWAP1 SWAP2 SWAP1 DUP3 SWAP1 SUB ADD DUP2 DUP7 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x2AC JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS STATICCALL ISZERO DUP1 ISZERO PUSH2 0x2C0 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x2D6 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP MLOAD PUSH1 0x0 SLOAD PUSH1 0x40 DUP1 MLOAD PUSH4 0x62D9BE11 PUSH1 0xE1 SHL DUP2 MSTORE SWAP1 MLOAD PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB SWAP4 DUP5 AND SWAP4 PUSH4 0x95EA7B3 SWAP4 AND SWAP2 DUP3 SWAP2 PUSH4 0xC5B37C22 SWAP2 PUSH1 0x4 DUP1 DUP3 ADD SWAP3 PUSH1 0x20 SWAP3 SWAP1 SWAP2 SWAP1 DUP3 SWAP1 SUB ADD DUP2 DUP7 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x327 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS STATICCALL ISZERO DUP1 ISZERO PUSH2 0x33B JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x351 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP MLOAD PUSH1 0x40 DUP1 MLOAD PUSH1 0x1 PUSH1 0x1 PUSH1 0xE0 SHL SUB NOT PUSH1 0xE0 DUP7 SWAP1 SHL AND DUP2 MSTORE PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB SWAP1 SWAP4 AND PUSH1 0x4 DUP5 ADD MSTORE PUSH1 0x24 DUP4 ADD SWAP2 SWAP1 SWAP2 MSTORE MLOAD PUSH1 0x44 DUP1 DUP4 ADD SWAP3 PUSH1 0x20 SWAP3 SWAP2 SWAP1 DUP3 SWAP1 SUB ADD DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x3A2 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x3B6 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x3CC JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP POP PUSH1 0x0 DUP1 SLOAD PUSH1 0x40 DUP1 MLOAD PUSH4 0x1EFC38E9 PUSH1 0xE3 SHL DUP2 MSTORE SWAP1 MLOAD PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB SWAP1 SWAP3 AND SWAP3 PUSH4 0xF7E1C748 SWAP3 PUSH1 0x4 DUP1 DUP5 ADD SWAP4 PUSH1 0x60 SWAP4 SWAP1 DUP4 SWAP1 SUB SWAP1 SWAP2 ADD SWAP1 DUP3 SWAP1 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x416 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x42A JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x60 DUP2 LT ISZERO PUSH2 0x440 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP DUP1 MLOAD PUSH1 0x20 DUP3 ADD MLOAD PUSH1 0x40 SWAP1 SWAP3 ADD MLOAD PUSH1 0x3 SSTORE PUSH1 0x2 DUP1 SLOAD PUSH1 0xFF NOT AND PUSH1 0xFF SWAP1 SWAP4 AND SWAP3 SWAP1 SWAP3 OR SWAP1 SWAP2 SSTORE PUSH1 0x1 SSTORE JUMP INVALID LOG2 PUSH5 0x6970667358 0x22 SLT KECCAK256 RETURNDATACOPY 0xD4 ISZERO 0xB0 0xBF SWAP15 PUSH4 0x200B9658 0xAE 0x26 0xB8 EXP GASLIMIT 0xE SLOAD SWAP15 SWAP11 0xE SWAP11 0xD3 SWAP4 0x4C 0x5C EQ SWAP7 0xEC JUMPI 0xAA 0xE PUSH5 0x736F6C6343 STOP MOD 0xC STOP CALLER \",\n  \"pcMap\": {\n    \"0\": {\n      \"offset\": [\n        925,\n        1659\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x80\"\n    },\n    \"2\": {\n      \"fn\": null,\n      \"offset\": [\n        925,\n        1659\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x40\"\n    },\n    \"4\": {\n      \"fn\": null,\n      \"offset\": [\n        925,\n        1659\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"9\"\n    },\n    \"5\": {\n      \"fn\": null,\n      \"offset\": [\n        925,\n        1659\n      ],\n      \"op\": \"CALLVALUE\",\n      \"path\": \"9\"\n    },\n    \"6\": {\n      \"fn\": null,\n      \"offset\": [\n        925,\n        1659\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"9\"\n    },\n    \"7\": {\n      \"fn\": null,\n      \"offset\": [\n        925,\n        1659\n      ],\n      \"op\": \"ISZERO\",\n      \"path\": \"9\"\n    },\n    \"8\": {\n      \"fn\": null,\n      \"offset\": [\n        925,\n        1659\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"9\",\n      \"value\": \"0x10\"\n    },\n    \"11\": {\n      \"fn\": null,\n      \"offset\": [\n        925,\n        1659\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"9\"\n    },\n    \"12\": {\n      \"fn\": null,\n      \"offset\": [\n        925,\n        1659\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x0\"\n    },\n    \"14\": {\n      \"fn\": null,\n      \"offset\": [\n        925,\n        1659\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"9\"\n    },\n    \"15\": {\n      \"dev\": \"Cannot send ether to nonpayable function\",\n      \"fn\": null,\n      \"offset\": [\n        925,\n        1659\n      ],\n      \"op\": \"REVERT\",\n      \"path\": \"9\"\n    },\n    \"16\": {\n      \"fn\": null,\n      \"offset\": [\n        925,\n        1659\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"9\"\n    },\n    \"17\": {\n      \"fn\": null,\n      \"offset\": [\n        925,\n        1659\n      ],\n      \"op\": \"POP\",\n      \"path\": \"9\"\n    },\n    \"18\": {\n      \"fn\": null,\n      \"offset\": [\n        925,\n        1659\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x4\"\n    },\n    \"20\": {\n      \"fn\": null,\n      \"offset\": [\n        925,\n        1659\n      ],\n      \"op\": \"CALLDATASIZE\",\n      \"path\": \"9\"\n    },\n    \"21\": {\n      \"fn\": null,\n      \"offset\": [\n        925,\n        1659\n      ],\n      \"op\": \"LT\",\n      \"path\": \"9\"\n    },\n    \"22\": {\n      \"fn\": null,\n      \"offset\": [\n        925,\n        1659\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"9\",\n      \"value\": \"0x57\"\n    },\n    \"25\": {\n      \"fn\": null,\n      \"offset\": [\n        925,\n        1659\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"9\"\n    },\n    \"26\": {\n      \"fn\": null,\n      \"offset\": [\n        925,\n        1659\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x0\"\n    },\n    \"28\": {\n      \"fn\": null,\n      \"offset\": [\n        925,\n        1659\n      ],\n      \"op\": \"CALLDATALOAD\",\n      \"path\": \"9\"\n    },\n    \"29\": {\n      \"fn\": null,\n      \"offset\": [\n        925,\n        1659\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0xE0\"\n    },\n    \"31\": {\n      \"fn\": null,\n      \"offset\": [\n        925,\n        1659\n      ],\n      \"op\": \"SHR\",\n      \"path\": \"9\"\n    },\n    \"32\": {\n      \"fn\": null,\n      \"offset\": [\n        925,\n        1659\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"9\"\n    },\n    \"33\": {\n      \"fn\": null,\n      \"offset\": [\n        925,\n        1659\n      ],\n      \"op\": \"PUSH4\",\n      \"path\": \"9\",\n      \"value\": \"0x19CC4B5A\"\n    },\n    \"38\": {\n      \"fn\": null,\n      \"offset\": [\n        925,\n        1659\n      ],\n      \"op\": \"EQ\",\n      \"path\": \"9\"\n    },\n    \"39\": {\n      \"fn\": null,\n      \"offset\": [\n        925,\n        1659\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"9\",\n      \"value\": \"0x5C\"\n    },\n    \"42\": {\n      \"fn\": null,\n      \"offset\": [\n        925,\n        1659\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"9\"\n    },\n    \"43\": {\n      \"fn\": null,\n      \"offset\": [\n        925,\n        1659\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"9\"\n    },\n    \"44\": {\n      \"fn\": null,\n      \"offset\": [\n        925,\n        1659\n      ],\n      \"op\": \"PUSH4\",\n      \"path\": \"9\",\n      \"value\": \"0x32424AA3\"\n    },\n    \"49\": {\n      \"fn\": null,\n      \"offset\": [\n        925,\n        1659\n      ],\n      \"op\": \"EQ\",\n      \"path\": \"9\"\n    },\n    \"50\": {\n      \"fn\": null,\n      \"offset\": [\n        925,\n        1659\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"9\",\n      \"value\": \"0x80\"\n    },\n    \"53\": {\n      \"fn\": null,\n      \"offset\": [\n        925,\n        1659\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"9\"\n    },\n    \"54\": {\n      \"fn\": null,\n      \"offset\": [\n        925,\n        1659\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"9\"\n    },\n    \"55\": {\n      \"fn\": null,\n      \"offset\": [\n        925,\n        1659\n      ],\n      \"op\": \"PUSH4\",\n      \"path\": \"9\",\n      \"value\": \"0x4E5551CE\"\n    },\n    \"60\": {\n      \"fn\": null,\n      \"offset\": [\n        925,\n        1659\n      ],\n      \"op\": \"EQ\",\n      \"path\": \"9\"\n    },\n    \"61\": {\n      \"fn\": null,\n      \"offset\": [\n        925,\n        1659\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"9\",\n      \"value\": \"0x9E\"\n    },\n    \"64\": {\n      \"fn\": null,\n      \"offset\": [\n        925,\n        1659\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"9\"\n    },\n    \"65\": {\n      \"fn\": null,\n      \"offset\": [\n        925,\n        1659\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"9\"\n    },\n    \"66\": {\n      \"fn\": null,\n      \"offset\": [\n        925,\n        1659\n      ],\n      \"op\": \"PUSH4\",\n      \"path\": \"9\",\n      \"value\": \"0xB895C74A\"\n    },\n    \"71\": {\n      \"fn\": null,\n      \"offset\": [\n        925,\n        1659\n      ],\n      \"op\": \"EQ\",\n      \"path\": \"9\"\n    },\n    \"72\": {\n      \"fn\": null,\n      \"offset\": [\n        925,\n        1659\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"9\",\n      \"value\": \"0xB8\"\n    },\n    \"75\": {\n      \"fn\": null,\n      \"offset\": [\n        925,\n        1659\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"9\"\n    },\n    \"76\": {\n      \"fn\": null,\n      \"offset\": [\n        925,\n        1659\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"9\"\n    },\n    \"77\": {\n      \"fn\": null,\n      \"offset\": [\n        925,\n        1659\n      ],\n      \"op\": \"PUSH4\",\n      \"path\": \"9\",\n      \"value\": \"0xF7E1C748\"\n    },\n    \"82\": {\n      \"fn\": null,\n      \"offset\": [\n        925,\n        1659\n      ],\n      \"op\": \"EQ\",\n      \"path\": \"9\"\n    },\n    \"83\": {\n      \"fn\": null,\n      \"offset\": [\n        925,\n        1659\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"9\",\n      \"value\": \"0xC0\"\n    },\n    \"86\": {\n      \"fn\": null,\n      \"offset\": [\n        925,\n        1659\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"9\"\n    },\n    \"87\": {\n      \"fn\": null,\n      \"offset\": [\n        925,\n        1659\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"9\"\n    },\n    \"88\": {\n      \"fn\": null,\n      \"offset\": [\n        925,\n        1659\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x0\"\n    },\n    \"90\": {\n      \"fn\": null,\n      \"offset\": [\n        925,\n        1659\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"9\"\n    },\n    \"91\": {\n      \"first_revert\": true,\n      \"fn\": null,\n      \"offset\": [\n        925,\n        1659\n      ],\n      \"op\": \"REVERT\",\n      \"path\": \"9\"\n    },\n    \"92\": {\n      \"offset\": [\n        983,\n        1015\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"9\"\n    },\n    \"93\": {\n      \"fn\": null,\n      \"offset\": [\n        983,\n        1015\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"9\",\n      \"value\": \"0x64\"\n    },\n    \"96\": {\n      \"fn\": null,\n      \"offset\": [\n        983,\n        1015\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"9\",\n      \"value\": \"0xCA\"\n    },\n    \"99\": {\n      \"fn\": null,\n      \"jump\": \"i\",\n      \"offset\": [\n        983,\n        1015\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"9\"\n    },\n    \"100\": {\n      \"fn\": null,\n      \"offset\": [\n        983,\n        1015\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"9\"\n    },\n    \"101\": {\n      \"fn\": null,\n      \"offset\": [\n        983,\n        1015\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x40\"\n    },\n    \"103\": {\n      \"fn\": null,\n      \"offset\": [\n        983,\n        1015\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"9\"\n    },\n    \"104\": {\n      \"fn\": null,\n      \"offset\": [\n        983,\n        1015\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"9\"\n    },\n    \"105\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"107\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"109\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0xA0\"\n    },\n    \"111\": {\n      \"op\": \"SHL\"\n    },\n    \"112\": {\n      \"op\": \"SUB\"\n    },\n    \"113\": {\n      \"offset\": [\n        983,\n        1015\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"9\"\n    },\n    \"114\": {\n      \"fn\": null,\n      \"offset\": [\n        983,\n        1015\n      ],\n      \"op\": \"SWAP3\",\n      \"path\": \"9\"\n    },\n    \"115\": {\n      \"fn\": null,\n      \"offset\": [\n        983,\n        1015\n      ],\n      \"op\": \"AND\",\n      \"path\": \"9\"\n    },\n    \"116\": {\n      \"fn\": null,\n      \"offset\": [\n        983,\n        1015\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"9\"\n    },\n    \"117\": {\n      \"fn\": null,\n      \"offset\": [\n        983,\n        1015\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"9\"\n    },\n    \"118\": {\n      \"fn\": null,\n      \"offset\": [\n        983,\n        1015\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"9\"\n    },\n    \"119\": {\n      \"fn\": null,\n      \"offset\": [\n        983,\n        1015\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"9\"\n    },\n    \"120\": {\n      \"fn\": null,\n      \"offset\": [\n        983,\n        1015\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"9\"\n    },\n    \"121\": {\n      \"fn\": null,\n      \"offset\": [\n        983,\n        1015\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"9\"\n    },\n    \"122\": {\n      \"fn\": null,\n      \"offset\": [\n        983,\n        1015\n      ],\n      \"op\": \"SUB\",\n      \"path\": \"9\"\n    },\n    \"123\": {\n      \"fn\": null,\n      \"offset\": [\n        983,\n        1015\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x20\"\n    },\n    \"125\": {\n      \"fn\": null,\n      \"offset\": [\n        983,\n        1015\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"9\"\n    },\n    \"126\": {\n      \"fn\": null,\n      \"offset\": [\n        983,\n        1015\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"9\"\n    },\n    \"127\": {\n      \"fn\": null,\n      \"offset\": [\n        983,\n        1015\n      ],\n      \"op\": \"RETURN\",\n      \"path\": \"9\"\n    },\n    \"128\": {\n      \"offset\": [\n        1049,\n        1071\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"9\"\n    },\n    \"129\": {\n      \"fn\": null,\n      \"offset\": [\n        1049,\n        1071\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"9\",\n      \"value\": \"0x88\"\n    },\n    \"132\": {\n      \"fn\": null,\n      \"offset\": [\n        1049,\n        1071\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"9\",\n      \"value\": \"0xD9\"\n    },\n    \"135\": {\n      \"fn\": null,\n      \"jump\": \"i\",\n      \"offset\": [\n        1049,\n        1071\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"9\"\n    },\n    \"136\": {\n      \"fn\": null,\n      \"offset\": [\n        1049,\n        1071\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"9\"\n    },\n    \"137\": {\n      \"fn\": null,\n      \"offset\": [\n        1049,\n        1071\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x40\"\n    },\n    \"139\": {\n      \"fn\": null,\n      \"offset\": [\n        1049,\n        1071\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"9\"\n    },\n    \"140\": {\n      \"fn\": null,\n      \"offset\": [\n        1049,\n        1071\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"9\"\n    },\n    \"141\": {\n      \"fn\": null,\n      \"offset\": [\n        1049,\n        1071\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0xFF\"\n    },\n    \"143\": {\n      \"fn\": null,\n      \"offset\": [\n        1049,\n        1071\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"9\"\n    },\n    \"144\": {\n      \"fn\": null,\n      \"offset\": [\n        1049,\n        1071\n      ],\n      \"op\": \"SWAP3\",\n      \"path\": \"9\"\n    },\n    \"145\": {\n      \"fn\": null,\n      \"offset\": [\n        1049,\n        1071\n      ],\n      \"op\": \"AND\",\n      \"path\": \"9\"\n    },\n    \"146\": {\n      \"fn\": null,\n      \"offset\": [\n        1049,\n        1071\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"9\"\n    },\n    \"147\": {\n      \"fn\": null,\n      \"offset\": [\n        1049,\n        1071\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"9\"\n    },\n    \"148\": {\n      \"fn\": null,\n      \"offset\": [\n        1049,\n        1071\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"9\"\n    },\n    \"149\": {\n      \"fn\": null,\n      \"offset\": [\n        1049,\n        1071\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"9\"\n    },\n    \"150\": {\n      \"fn\": null,\n      \"offset\": [\n        1049,\n        1071\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"9\"\n    },\n    \"151\": {\n      \"fn\": null,\n      \"offset\": [\n        1049,\n        1071\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"9\"\n    },\n    \"152\": {\n      \"fn\": null,\n      \"offset\": [\n        1049,\n        1071\n      ],\n      \"op\": \"SUB\",\n      \"path\": \"9\"\n    },\n    \"153\": {\n      \"fn\": null,\n      \"offset\": [\n        1049,\n        1071\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x20\"\n    },\n    \"155\": {\n      \"fn\": null,\n      \"offset\": [\n        1049,\n        1071\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"9\"\n    },\n    \"156\": {\n      \"fn\": null,\n      \"offset\": [\n        1049,\n        1071\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"9\"\n    },\n    \"157\": {\n      \"fn\": null,\n      \"offset\": [\n        1049,\n        1071\n      ],\n      \"op\": \"RETURN\",\n      \"path\": \"9\"\n    },\n    \"158\": {\n      \"offset\": [\n        1077,\n        1116\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"9\"\n    },\n    \"159\": {\n      \"fn\": null,\n      \"offset\": [\n        1077,\n        1116\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"9\",\n      \"value\": \"0xA6\"\n    },\n    \"162\": {\n      \"fn\": null,\n      \"offset\": [\n        1077,\n        1116\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"9\",\n      \"value\": \"0xE2\"\n    },\n    \"165\": {\n      \"fn\": null,\n      \"jump\": \"i\",\n      \"offset\": [\n        1077,\n        1116\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"9\"\n    },\n    \"166\": {\n      \"fn\": null,\n      \"offset\": [\n        1077,\n        1116\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"9\"\n    },\n    \"167\": {\n      \"fn\": null,\n      \"offset\": [\n        1077,\n        1116\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x40\"\n    },\n    \"169\": {\n      \"fn\": null,\n      \"offset\": [\n        1077,\n        1116\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"9\"\n    },\n    \"170\": {\n      \"fn\": null,\n      \"offset\": [\n        1077,\n        1116\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"9\"\n    },\n    \"171\": {\n      \"fn\": null,\n      \"offset\": [\n        1077,\n        1116\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"9\"\n    },\n    \"172\": {\n      \"fn\": null,\n      \"offset\": [\n        1077,\n        1116\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"9\"\n    },\n    \"173\": {\n      \"fn\": null,\n      \"offset\": [\n        1077,\n        1116\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"9\"\n    },\n    \"174\": {\n      \"fn\": null,\n      \"offset\": [\n        1077,\n        1116\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"9\"\n    },\n    \"175\": {\n      \"fn\": null,\n      \"offset\": [\n        1077,\n        1116\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"9\"\n    },\n    \"176\": {\n      \"fn\": null,\n      \"offset\": [\n        1077,\n        1116\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"9\"\n    },\n    \"177\": {\n      \"fn\": null,\n      \"offset\": [\n        1077,\n        1116\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"9\"\n    },\n    \"178\": {\n      \"fn\": null,\n      \"offset\": [\n        1077,\n        1116\n      ],\n      \"op\": \"SUB\",\n      \"path\": \"9\"\n    },\n    \"179\": {\n      \"fn\": null,\n      \"offset\": [\n        1077,\n        1116\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x20\"\n    },\n    \"181\": {\n      \"fn\": null,\n      \"offset\": [\n        1077,\n        1116\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"9\"\n    },\n    \"182\": {\n      \"fn\": null,\n      \"offset\": [\n        1077,\n        1116\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"9\"\n    },\n    \"183\": {\n      \"fn\": null,\n      \"offset\": [\n        1077,\n        1116\n      ],\n      \"op\": \"RETURN\",\n      \"path\": \"9\"\n    },\n    \"184\": {\n      \"offset\": [\n        1022,\n        1043\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"9\"\n    },\n    \"185\": {\n      \"fn\": null,\n      \"offset\": [\n        1022,\n        1043\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"9\",\n      \"value\": \"0xA6\"\n    },\n    \"188\": {\n      \"fn\": null,\n      \"offset\": [\n        1022,\n        1043\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"9\",\n      \"value\": \"0xE8\"\n    },\n    \"191\": {\n      \"fn\": null,\n      \"jump\": \"i\",\n      \"offset\": [\n        1022,\n        1043\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"9\"\n    },\n    \"192\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1330,\n        1657\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"9\"\n    },\n    \"193\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1330,\n        1657\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"9\",\n      \"value\": \"0xC8\"\n    },\n    \"196\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1330,\n        1657\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"9\",\n      \"value\": \"0xEE\"\n    },\n    \"199\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"jump\": \"i\",\n      \"offset\": [\n        1330,\n        1657\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"9\"\n    },\n    \"200\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1330,\n        1657\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"9\"\n    },\n    \"201\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1330,\n        1657\n      ],\n      \"op\": \"STOP\",\n      \"path\": \"9\"\n    },\n    \"202\": {\n      \"offset\": [\n        983,\n        1015\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"9\"\n    },\n    \"203\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        983,\n        1015\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x0\"\n    },\n    \"205\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        983,\n        1015\n      ],\n      \"op\": \"SLOAD\",\n      \"path\": \"9\"\n    },\n    \"206\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"208\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"210\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0xA0\"\n    },\n    \"212\": {\n      \"op\": \"SHL\"\n    },\n    \"213\": {\n      \"op\": \"SUB\"\n    },\n    \"214\": {\n      \"offset\": [\n        983,\n        1015\n      ],\n      \"op\": \"AND\",\n      \"path\": \"9\"\n    },\n    \"215\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        983,\n        1015\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"9\"\n    },\n    \"216\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"jump\": \"o\",\n      \"offset\": [\n        983,\n        1015\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"9\"\n    },\n    \"217\": {\n      \"offset\": [\n        1049,\n        1071\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"9\"\n    },\n    \"218\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1049,\n        1071\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x2\"\n    },\n    \"220\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1049,\n        1071\n      ],\n      \"op\": \"SLOAD\",\n      \"path\": \"9\"\n    },\n    \"221\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1049,\n        1071\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0xFF\"\n    },\n    \"223\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1049,\n        1071\n      ],\n      \"op\": \"AND\",\n      \"path\": \"9\"\n    },\n    \"224\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1049,\n        1071\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"9\"\n    },\n    \"225\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"jump\": \"o\",\n      \"offset\": [\n        1049,\n        1071\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"9\"\n    },\n    \"226\": {\n      \"offset\": [\n        1077,\n        1116\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"9\"\n    },\n    \"227\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1077,\n        1116\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x3\"\n    },\n    \"229\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1077,\n        1116\n      ],\n      \"op\": \"SLOAD\",\n      \"path\": \"9\"\n    },\n    \"230\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1077,\n        1116\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"9\"\n    },\n    \"231\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"jump\": \"o\",\n      \"offset\": [\n        1077,\n        1116\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"9\"\n    },\n    \"232\": {\n      \"offset\": [\n        1022,\n        1043\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"9\"\n    },\n    \"233\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1022,\n        1043\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x1\"\n    },\n    \"235\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1022,\n        1043\n      ],\n      \"op\": \"SLOAD\",\n      \"path\": \"9\"\n    },\n    \"236\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1022,\n        1043\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"9\"\n    },\n    \"237\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"jump\": \"o\",\n      \"offset\": [\n        1022,\n        1043\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"9\"\n    },\n    \"238\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1330,\n        1657\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"9\"\n    },\n    \"239\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1403\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"statement\": 0,\n      \"value\": \"0x0\"\n    },\n    \"241\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1403\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"9\"\n    },\n    \"242\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1403\n      ],\n      \"op\": \"SLOAD\",\n      \"path\": \"9\"\n    },\n    \"243\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1403\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"9\"\n    },\n    \"244\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1403\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"9\",\n      \"value\": \"0x100\"\n    },\n    \"247\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1403\n      ],\n      \"op\": \"EXP\",\n      \"path\": \"9\"\n    },\n    \"248\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1403\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"9\"\n    },\n    \"249\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1403\n      ],\n      \"op\": \"DIV\",\n      \"path\": \"9\"\n    },\n    \"250\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"252\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"254\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0xA0\"\n    },\n    \"256\": {\n      \"op\": \"SHL\"\n    },\n    \"257\": {\n      \"op\": \"SUB\"\n    },\n    \"258\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1403\n      ],\n      \"op\": \"AND\",\n      \"path\": \"9\"\n    },\n    \"259\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"261\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"263\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0xA0\"\n    },\n    \"265\": {\n      \"op\": \"SHL\"\n    },\n    \"266\": {\n      \"op\": \"SUB\"\n    },\n    \"267\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1410\n      ],\n      \"op\": \"AND\",\n      \"path\": \"9\"\n    },\n    \"268\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1410\n      ],\n      \"op\": \"PUSH4\",\n      \"path\": \"9\",\n      \"value\": \"0xECD0C0C3\"\n    },\n    \"273\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1412\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x40\"\n    },\n    \"275\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1412\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"9\"\n    },\n    \"276\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1412\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"9\"\n    },\n    \"277\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1412\n      ],\n      \"op\": \"PUSH4\",\n      \"path\": \"9\",\n      \"value\": \"0xFFFFFFFF\"\n    },\n    \"282\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1412\n      ],\n      \"op\": \"AND\",\n      \"path\": \"9\"\n    },\n    \"283\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1412\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0xE0\"\n    },\n    \"285\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1412\n      ],\n      \"op\": \"SHL\",\n      \"path\": \"9\"\n    },\n    \"286\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1412\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"9\"\n    },\n    \"287\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1412\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"9\"\n    },\n    \"288\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1412\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x4\"\n    },\n    \"290\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1412\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"9\"\n    },\n    \"291\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1412\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x20\"\n    },\n    \"293\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1412\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x40\"\n    },\n    \"295\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1412\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"9\"\n    },\n    \"296\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1412\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"9\"\n    },\n    \"297\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1412\n      ],\n      \"op\": \"DUP4\",\n      \"path\": \"9\"\n    },\n    \"298\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1412\n      ],\n      \"op\": \"SUB\",\n      \"path\": \"9\"\n    },\n    \"299\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1412\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"9\"\n    },\n    \"300\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1412\n      ],\n      \"op\": \"DUP7\",\n      \"path\": \"9\"\n    },\n    \"301\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1412\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"9\"\n    },\n    \"302\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1412\n      ],\n      \"op\": \"EXTCODESIZE\",\n      \"path\": \"9\"\n    },\n    \"303\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1412\n      ],\n      \"op\": \"ISZERO\",\n      \"path\": \"9\"\n    },\n    \"304\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1412\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"9\"\n    },\n    \"305\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1412\n      ],\n      \"op\": \"ISZERO\",\n      \"path\": \"9\"\n    },\n    \"306\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1412\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"9\",\n      \"value\": \"0x13A\"\n    },\n    \"309\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1412\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"9\"\n    },\n    \"310\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1412\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x0\"\n    },\n    \"312\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1412\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"9\"\n    },\n    \"313\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1412\n      ],\n      \"op\": \"REVERT\",\n      \"path\": \"9\"\n    },\n    \"314\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1412\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"9\"\n    },\n    \"315\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1412\n      ],\n      \"op\": \"POP\",\n      \"path\": \"9\"\n    },\n    \"316\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1412\n      ],\n      \"op\": \"GAS\",\n      \"path\": \"9\"\n    },\n    \"317\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1412\n      ],\n      \"op\": \"STATICCALL\",\n      \"path\": \"9\"\n    },\n    \"318\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1412\n      ],\n      \"op\": \"ISZERO\",\n      \"path\": \"9\"\n    },\n    \"319\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1412\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"9\"\n    },\n    \"320\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1412\n      ],\n      \"op\": \"ISZERO\",\n      \"path\": \"9\"\n    },\n    \"321\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1412\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"9\",\n      \"value\": \"0x14E\"\n    },\n    \"324\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1412\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"9\"\n    },\n    \"325\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1412\n      ],\n      \"op\": \"RETURNDATASIZE\",\n      \"path\": \"9\"\n    },\n    \"326\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1412\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x0\"\n    },\n    \"328\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1412\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"9\"\n    },\n    \"329\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1412\n      ],\n      \"op\": \"RETURNDATACOPY\",\n      \"path\": \"9\"\n    },\n    \"330\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1412\n      ],\n      \"op\": \"RETURNDATASIZE\",\n      \"path\": \"9\"\n    },\n    \"331\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1412\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x0\"\n    },\n    \"333\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1412\n      ],\n      \"op\": \"REVERT\",\n      \"path\": \"9\"\n    },\n    \"334\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1412\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"9\"\n    },\n    \"335\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1412\n      ],\n      \"op\": \"POP\",\n      \"path\": \"9\"\n    },\n    \"336\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1412\n      ],\n      \"op\": \"POP\",\n      \"path\": \"9\"\n    },\n    \"337\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1412\n      ],\n      \"op\": \"POP\",\n      \"path\": \"9\"\n    },\n    \"338\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1412\n      ],\n      \"op\": \"POP\",\n      \"path\": \"9\"\n    },\n    \"339\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1412\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x40\"\n    },\n    \"341\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1412\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"9\"\n    },\n    \"342\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1412\n      ],\n      \"op\": \"RETURNDATASIZE\",\n      \"path\": \"9\"\n    },\n    \"343\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1412\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x20\"\n    },\n    \"345\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1412\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"9\"\n    },\n    \"346\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1412\n      ],\n      \"op\": \"LT\",\n      \"path\": \"9\"\n    },\n    \"347\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1412\n      ],\n      \"op\": \"ISZERO\",\n      \"path\": \"9\"\n    },\n    \"348\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1412\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"9\",\n      \"value\": \"0x164\"\n    },\n    \"351\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1412\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"9\"\n    },\n    \"352\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1412\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x0\"\n    },\n    \"354\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1412\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"9\"\n    },\n    \"355\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1412\n      ],\n      \"op\": \"REVERT\",\n      \"path\": \"9\"\n    },\n    \"356\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1412\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"9\"\n    },\n    \"357\": {\n      \"op\": \"POP\"\n    },\n    \"358\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1412\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"9\"\n    },\n    \"359\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1466\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x0\"\n    },\n    \"361\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1466\n      ],\n      \"op\": \"SLOAD\",\n      \"path\": \"9\"\n    },\n    \"362\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1473\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x40\"\n    },\n    \"364\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1473\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"9\"\n    },\n    \"365\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1473\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"9\"\n    },\n    \"366\": {\n      \"op\": \"PUSH4\",\n      \"value\": \"0x62D9BE11\"\n    },\n    \"371\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0xE1\"\n    },\n    \"373\": {\n      \"op\": \"SHL\"\n    },\n    \"374\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1473\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"9\"\n    },\n    \"375\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1473\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"9\"\n    },\n    \"376\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1473\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"9\"\n    },\n    \"377\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1473\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"9\"\n    },\n    \"378\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"380\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"382\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0xA0\"\n    },\n    \"384\": {\n      \"op\": \"SHL\"\n    },\n    \"385\": {\n      \"op\": \"SUB\"\n    },\n    \"386\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1425\n      ],\n      \"op\": \"SWAP4\",\n      \"path\": \"9\"\n    },\n    \"387\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1425\n      ],\n      \"op\": \"DUP5\",\n      \"path\": \"9\"\n    },\n    \"388\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1425\n      ],\n      \"op\": \"AND\",\n      \"path\": \"9\"\n    },\n    \"389\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1425\n      ],\n      \"op\": \"SWAP4\",\n      \"path\": \"9\"\n    },\n    \"390\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1425\n      ],\n      \"op\": \"PUSH4\",\n      \"path\": \"9\",\n      \"value\": \"0x23B872DD\"\n    },\n    \"395\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1425\n      ],\n      \"op\": \"SWAP4\",\n      \"path\": \"9\"\n    },\n    \"396\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1426,\n        1436\n      ],\n      \"op\": \"CALLER\",\n      \"path\": \"9\"\n    },\n    \"397\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1426,\n        1436\n      ],\n      \"op\": \"SWAP4\",\n      \"path\": \"9\"\n    },\n    \"398\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1446,\n        1450\n      ],\n      \"op\": \"ADDRESS\",\n      \"path\": \"9\"\n    },\n    \"399\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1446,\n        1450\n      ],\n      \"op\": \"SWAP4\",\n      \"path\": \"9\"\n    },\n    \"400\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1466\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"9\"\n    },\n    \"401\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1466\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"9\"\n    },\n    \"402\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1466\n      ],\n      \"op\": \"SWAP3\",\n      \"path\": \"9\"\n    },\n    \"403\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1466\n      ],\n      \"op\": \"AND\",\n      \"path\": \"9\"\n    },\n    \"404\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1466\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"9\"\n    },\n    \"405\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1471\n      ],\n      \"op\": \"PUSH4\",\n      \"path\": \"9\",\n      \"value\": \"0xC5B37C22\"\n    },\n    \"410\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1471\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"9\"\n    },\n    \"411\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1473\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x4\"\n    },\n    \"413\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1473\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"9\"\n    },\n    \"414\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1473\n      ],\n      \"op\": \"DUP4\",\n      \"path\": \"9\"\n    },\n    \"415\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1473\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"9\"\n    },\n    \"416\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1473\n      ],\n      \"op\": \"SWAP3\",\n      \"path\": \"9\"\n    },\n    \"417\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1412\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x20\"\n    },\n    \"419\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1412\n      ],\n      \"op\": \"SWAP3\",\n      \"path\": \"9\"\n    },\n    \"420\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1473\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"9\"\n    },\n    \"421\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1473\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"9\"\n    },\n    \"422\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1473\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"9\"\n    },\n    \"423\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1473\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"9\"\n    },\n    \"424\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1473\n      ],\n      \"op\": \"SUB\",\n      \"path\": \"9\"\n    },\n    \"425\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1473\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"9\"\n    },\n    \"426\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1473\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"9\"\n    },\n    \"427\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1466\n      ],\n      \"op\": \"DUP7\",\n      \"path\": \"9\"\n    },\n    \"428\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1473\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"9\"\n    },\n    \"429\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1473\n      ],\n      \"op\": \"EXTCODESIZE\",\n      \"path\": \"9\"\n    },\n    \"430\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1473\n      ],\n      \"op\": \"ISZERO\",\n      \"path\": \"9\"\n    },\n    \"431\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1473\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"9\"\n    },\n    \"432\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1473\n      ],\n      \"op\": \"ISZERO\",\n      \"path\": \"9\"\n    },\n    \"433\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1473\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"9\",\n      \"value\": \"0x1B9\"\n    },\n    \"436\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1473\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"9\"\n    },\n    \"437\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1473\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x0\"\n    },\n    \"439\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1473\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"9\"\n    },\n    \"440\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1473\n      ],\n      \"op\": \"REVERT\",\n      \"path\": \"9\"\n    },\n    \"441\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1473\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"9\"\n    },\n    \"442\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1473\n      ],\n      \"op\": \"POP\",\n      \"path\": \"9\"\n    },\n    \"443\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1473\n      ],\n      \"op\": \"GAS\",\n      \"path\": \"9\"\n    },\n    \"444\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1473\n      ],\n      \"op\": \"STATICCALL\",\n      \"path\": \"9\"\n    },\n    \"445\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1473\n      ],\n      \"op\": \"ISZERO\",\n      \"path\": \"9\"\n    },\n    \"446\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1473\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"9\"\n    },\n    \"447\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1473\n      ],\n      \"op\": \"ISZERO\",\n      \"path\": \"9\"\n    },\n    \"448\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1473\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"9\",\n      \"value\": \"0x1CD\"\n    },\n    \"451\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1473\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"9\"\n    },\n    \"452\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1473\n      ],\n      \"op\": \"RETURNDATASIZE\",\n      \"path\": \"9\"\n    },\n    \"453\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1473\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x0\"\n    },\n    \"455\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1473\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"9\"\n    },\n    \"456\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1473\n      ],\n      \"op\": \"RETURNDATACOPY\",\n      \"path\": \"9\"\n    },\n    \"457\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1473\n      ],\n      \"op\": \"RETURNDATASIZE\",\n      \"path\": \"9\"\n    },\n    \"458\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1473\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x0\"\n    },\n    \"460\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1473\n      ],\n      \"op\": \"REVERT\",\n      \"path\": \"9\"\n    },\n    \"461\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1473\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"9\"\n    },\n    \"462\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1473\n      ],\n      \"op\": \"POP\",\n      \"path\": \"9\"\n    },\n    \"463\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1473\n      ],\n      \"op\": \"POP\",\n      \"path\": \"9\"\n    },\n    \"464\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1473\n      ],\n      \"op\": \"POP\",\n      \"path\": \"9\"\n    },\n    \"465\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1473\n      ],\n      \"op\": \"POP\",\n      \"path\": \"9\"\n    },\n    \"466\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1473\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x40\"\n    },\n    \"468\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1473\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"9\"\n    },\n    \"469\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1473\n      ],\n      \"op\": \"RETURNDATASIZE\",\n      \"path\": \"9\"\n    },\n    \"470\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1473\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x20\"\n    },\n    \"472\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1473\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"9\"\n    },\n    \"473\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1473\n      ],\n      \"op\": \"LT\",\n      \"path\": \"9\"\n    },\n    \"474\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1473\n      ],\n      \"op\": \"ISZERO\",\n      \"path\": \"9\"\n    },\n    \"475\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1473\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"9\",\n      \"value\": \"0x1E3\"\n    },\n    \"478\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1473\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"9\"\n    },\n    \"479\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1473\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x0\"\n    },\n    \"481\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1473\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"9\"\n    },\n    \"482\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1473\n      ],\n      \"op\": \"REVERT\",\n      \"path\": \"9\"\n    },\n    \"483\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1473\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"9\"\n    },\n    \"484\": {\n      \"op\": \"POP\"\n    },\n    \"485\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1473\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"9\"\n    },\n    \"486\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x40\"\n    },\n    \"488\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"9\"\n    },\n    \"489\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"9\"\n    },\n    \"490\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"492\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"494\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0xE0\"\n    },\n    \"496\": {\n      \"op\": \"SHL\"\n    },\n    \"497\": {\n      \"op\": \"SUB\"\n    },\n    \"498\": {\n      \"op\": \"NOT\"\n    },\n    \"499\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0xE0\"\n    },\n    \"501\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"DUP8\",\n      \"path\": \"9\"\n    },\n    \"502\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"9\"\n    },\n    \"503\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"SHL\",\n      \"path\": \"9\"\n    },\n    \"504\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"AND\",\n      \"path\": \"9\"\n    },\n    \"505\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"9\"\n    },\n    \"506\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"9\"\n    },\n    \"507\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"509\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"511\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0xA0\"\n    },\n    \"513\": {\n      \"op\": \"SHL\"\n    },\n    \"514\": {\n      \"op\": \"SUB\"\n    },\n    \"515\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"SWAP5\",\n      \"path\": \"9\"\n    },\n    \"516\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"DUP6\",\n      \"path\": \"9\"\n    },\n    \"517\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"AND\",\n      \"path\": \"9\"\n    },\n    \"518\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x4\"\n    },\n    \"520\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"9\"\n    },\n    \"521\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"9\"\n    },\n    \"522\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"9\"\n    },\n    \"523\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"SWAP3\",\n      \"path\": \"9\"\n    },\n    \"524\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"9\"\n    },\n    \"525\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"SWAP4\",\n      \"path\": \"9\"\n    },\n    \"526\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"AND\",\n      \"path\": \"9\"\n    },\n    \"527\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x24\"\n    },\n    \"529\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"DUP4\",\n      \"path\": \"9\"\n    },\n    \"530\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"9\"\n    },\n    \"531\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"9\"\n    },\n    \"532\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x44\"\n    },\n    \"534\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"9\"\n    },\n    \"535\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"9\"\n    },\n    \"536\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"9\"\n    },\n    \"537\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"9\"\n    },\n    \"538\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"9\"\n    },\n    \"539\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x64\"\n    },\n    \"541\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"9\"\n    },\n    \"542\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"DUP4\",\n      \"path\": \"9\"\n    },\n    \"543\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"9\"\n    },\n    \"544\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"SWAP3\",\n      \"path\": \"9\"\n    },\n    \"545\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1473\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x20\"\n    },\n    \"547\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1453,\n        1473\n      ],\n      \"op\": \"SWAP3\",\n      \"path\": \"9\"\n    },\n    \"548\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"9\"\n    },\n    \"549\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"9\"\n    },\n    \"550\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"9\"\n    },\n    \"551\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"9\"\n    },\n    \"552\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"SUB\",\n      \"path\": \"9\"\n    },\n    \"553\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"9\"\n    },\n    \"554\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"9\"\n    },\n    \"555\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x0\"\n    },\n    \"557\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"DUP8\",\n      \"path\": \"9\"\n    },\n    \"558\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"9\"\n    },\n    \"559\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"EXTCODESIZE\",\n      \"path\": \"9\"\n    },\n    \"560\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"ISZERO\",\n      \"path\": \"9\"\n    },\n    \"561\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"9\"\n    },\n    \"562\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"ISZERO\",\n      \"path\": \"9\"\n    },\n    \"563\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"9\",\n      \"value\": \"0x23B\"\n    },\n    \"566\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"9\"\n    },\n    \"567\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x0\"\n    },\n    \"569\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"9\"\n    },\n    \"570\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"REVERT\",\n      \"path\": \"9\"\n    },\n    \"571\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"9\"\n    },\n    \"572\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"POP\",\n      \"path\": \"9\"\n    },\n    \"573\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"GAS\",\n      \"path\": \"9\"\n    },\n    \"574\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"CALL\",\n      \"path\": \"9\"\n    },\n    \"575\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"ISZERO\",\n      \"path\": \"9\"\n    },\n    \"576\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"9\"\n    },\n    \"577\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"ISZERO\",\n      \"path\": \"9\"\n    },\n    \"578\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"9\",\n      \"value\": \"0x24F\"\n    },\n    \"581\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"9\"\n    },\n    \"582\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"RETURNDATASIZE\",\n      \"path\": \"9\"\n    },\n    \"583\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x0\"\n    },\n    \"585\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"9\"\n    },\n    \"586\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"RETURNDATACOPY\",\n      \"path\": \"9\"\n    },\n    \"587\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"RETURNDATASIZE\",\n      \"path\": \"9\"\n    },\n    \"588\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x0\"\n    },\n    \"590\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"REVERT\",\n      \"path\": \"9\"\n    },\n    \"591\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"9\"\n    },\n    \"592\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"POP\",\n      \"path\": \"9\"\n    },\n    \"593\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"POP\",\n      \"path\": \"9\"\n    },\n    \"594\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"POP\",\n      \"path\": \"9\"\n    },\n    \"595\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"POP\",\n      \"path\": \"9\"\n    },\n    \"596\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x40\"\n    },\n    \"598\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"9\"\n    },\n    \"599\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"RETURNDATASIZE\",\n      \"path\": \"9\"\n    },\n    \"600\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x20\"\n    },\n    \"602\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"9\"\n    },\n    \"603\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"LT\",\n      \"path\": \"9\"\n    },\n    \"604\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"ISZERO\",\n      \"path\": \"9\"\n    },\n    \"605\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"9\",\n      \"value\": \"0x265\"\n    },\n    \"608\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"9\"\n    },\n    \"609\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x0\"\n    },\n    \"611\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"9\"\n    },\n    \"612\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"REVERT\",\n      \"path\": \"9\"\n    },\n    \"613\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"9\"\n    },\n    \"614\": {\n      \"op\": \"POP\"\n    },\n    \"615\": {\n      \"op\": \"POP\"\n    },\n    \"616\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1497\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"statement\": 1,\n      \"value\": \"0x0\"\n    },\n    \"618\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1497\n      ],\n      \"op\": \"SLOAD\",\n      \"path\": \"9\"\n    },\n    \"619\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1506\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x40\"\n    },\n    \"621\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1506\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"9\"\n    },\n    \"622\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1506\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"9\"\n    },\n    \"623\": {\n      \"op\": \"PUSH4\",\n      \"value\": \"0xECD0C0C3\"\n    },\n    \"628\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0xE0\"\n    },\n    \"630\": {\n      \"op\": \"SHL\"\n    },\n    \"631\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1506\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"9\"\n    },\n    \"632\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1506\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"9\"\n    },\n    \"633\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1506\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"9\"\n    },\n    \"634\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1506\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"9\"\n    },\n    \"635\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"637\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"639\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0xA0\"\n    },\n    \"641\": {\n      \"op\": \"SHL\"\n    },\n    \"642\": {\n      \"op\": \"SUB\"\n    },\n    \"643\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1497\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"9\"\n    },\n    \"644\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1497\n      ],\n      \"op\": \"SWAP3\",\n      \"path\": \"9\"\n    },\n    \"645\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1497\n      ],\n      \"op\": \"AND\",\n      \"path\": \"9\"\n    },\n    \"646\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1497\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"9\"\n    },\n    \"647\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1504\n      ],\n      \"op\": \"PUSH4\",\n      \"path\": \"9\",\n      \"value\": \"0xECD0C0C3\"\n    },\n    \"652\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1504\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"9\"\n    },\n    \"653\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1506\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x4\"\n    },\n    \"655\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1506\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"9\"\n    },\n    \"656\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1506\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"9\"\n    },\n    \"657\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1506\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"9\"\n    },\n    \"658\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1506\n      ],\n      \"op\": \"SWAP3\",\n      \"path\": \"9\"\n    },\n    \"659\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x20\"\n    },\n    \"661\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1390,\n        1474\n      ],\n      \"op\": \"SWAP3\",\n      \"path\": \"9\"\n    },\n    \"662\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1506\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"9\"\n    },\n    \"663\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1506\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"9\"\n    },\n    \"664\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1506\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"9\"\n    },\n    \"665\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1506\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"9\"\n    },\n    \"666\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1506\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"9\"\n    },\n    \"667\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1506\n      ],\n      \"op\": \"SUB\",\n      \"path\": \"9\"\n    },\n    \"668\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1506\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"9\"\n    },\n    \"669\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1506\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"9\"\n    },\n    \"670\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1497\n      ],\n      \"op\": \"DUP7\",\n      \"path\": \"9\"\n    },\n    \"671\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1506\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"9\"\n    },\n    \"672\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1506\n      ],\n      \"op\": \"EXTCODESIZE\",\n      \"path\": \"9\"\n    },\n    \"673\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1506\n      ],\n      \"op\": \"ISZERO\",\n      \"path\": \"9\"\n    },\n    \"674\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1506\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"9\"\n    },\n    \"675\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1506\n      ],\n      \"op\": \"ISZERO\",\n      \"path\": \"9\"\n    },\n    \"676\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1506\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"9\",\n      \"value\": \"0x2AC\"\n    },\n    \"679\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1506\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"9\"\n    },\n    \"680\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1506\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x0\"\n    },\n    \"682\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1506\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"9\"\n    },\n    \"683\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1506\n      ],\n      \"op\": \"REVERT\",\n      \"path\": \"9\"\n    },\n    \"684\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1506\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"9\"\n    },\n    \"685\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1506\n      ],\n      \"op\": \"POP\",\n      \"path\": \"9\"\n    },\n    \"686\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1506\n      ],\n      \"op\": \"GAS\",\n      \"path\": \"9\"\n    },\n    \"687\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1506\n      ],\n      \"op\": \"STATICCALL\",\n      \"path\": \"9\"\n    },\n    \"688\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1506\n      ],\n      \"op\": \"ISZERO\",\n      \"path\": \"9\"\n    },\n    \"689\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1506\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"9\"\n    },\n    \"690\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1506\n      ],\n      \"op\": \"ISZERO\",\n      \"path\": \"9\"\n    },\n    \"691\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1506\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"9\",\n      \"value\": \"0x2C0\"\n    },\n    \"694\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1506\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"9\"\n    },\n    \"695\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1506\n      ],\n      \"op\": \"RETURNDATASIZE\",\n      \"path\": \"9\"\n    },\n    \"696\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1506\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x0\"\n    },\n    \"698\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1506\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"9\"\n    },\n    \"699\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1506\n      ],\n      \"op\": \"RETURNDATACOPY\",\n      \"path\": \"9\"\n    },\n    \"700\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1506\n      ],\n      \"op\": \"RETURNDATASIZE\",\n      \"path\": \"9\"\n    },\n    \"701\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1506\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x0\"\n    },\n    \"703\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1506\n      ],\n      \"op\": \"REVERT\",\n      \"path\": \"9\"\n    },\n    \"704\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1506\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"9\"\n    },\n    \"705\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1506\n      ],\n      \"op\": \"POP\",\n      \"path\": \"9\"\n    },\n    \"706\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1506\n      ],\n      \"op\": \"POP\",\n      \"path\": \"9\"\n    },\n    \"707\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1506\n      ],\n      \"op\": \"POP\",\n      \"path\": \"9\"\n    },\n    \"708\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1506\n      ],\n      \"op\": \"POP\",\n      \"path\": \"9\"\n    },\n    \"709\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1506\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x40\"\n    },\n    \"711\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1506\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"9\"\n    },\n    \"712\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1506\n      ],\n      \"op\": \"RETURNDATASIZE\",\n      \"path\": \"9\"\n    },\n    \"713\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1506\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x20\"\n    },\n    \"715\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1506\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"9\"\n    },\n    \"716\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1506\n      ],\n      \"op\": \"LT\",\n      \"path\": \"9\"\n    },\n    \"717\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1506\n      ],\n      \"op\": \"ISZERO\",\n      \"path\": \"9\"\n    },\n    \"718\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1506\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"9\",\n      \"value\": \"0x2D6\"\n    },\n    \"721\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1506\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"9\"\n    },\n    \"722\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1506\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x0\"\n    },\n    \"724\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1506\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"9\"\n    },\n    \"725\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1506\n      ],\n      \"op\": \"REVERT\",\n      \"path\": \"9\"\n    },\n    \"726\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1506\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"9\"\n    },\n    \"727\": {\n      \"op\": \"POP\"\n    },\n    \"728\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1506\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"9\"\n    },\n    \"729\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1523,\n        1536\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x0\"\n    },\n    \"731\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1523,\n        1536\n      ],\n      \"op\": \"SLOAD\",\n      \"path\": \"9\"\n    },\n    \"732\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1539,\n        1559\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x40\"\n    },\n    \"734\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1539,\n        1559\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"9\"\n    },\n    \"735\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1539,\n        1559\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"9\"\n    },\n    \"736\": {\n      \"op\": \"PUSH4\",\n      \"value\": \"0x62D9BE11\"\n    },\n    \"741\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0xE1\"\n    },\n    \"743\": {\n      \"op\": \"SHL\"\n    },\n    \"744\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1539,\n        1559\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"9\"\n    },\n    \"745\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1539,\n        1559\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"9\"\n    },\n    \"746\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1539,\n        1559\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"9\"\n    },\n    \"747\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1539,\n        1559\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"9\"\n    },\n    \"748\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"750\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"752\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0xA0\"\n    },\n    \"754\": {\n      \"op\": \"SHL\"\n    },\n    \"755\": {\n      \"op\": \"SUB\"\n    },\n    \"756\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1514\n      ],\n      \"op\": \"SWAP4\",\n      \"path\": \"9\"\n    },\n    \"757\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1514\n      ],\n      \"op\": \"DUP5\",\n      \"path\": \"9\"\n    },\n    \"758\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1514\n      ],\n      \"op\": \"AND\",\n      \"path\": \"9\"\n    },\n    \"759\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1514\n      ],\n      \"op\": \"SWAP4\",\n      \"path\": \"9\"\n    },\n    \"760\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1514\n      ],\n      \"op\": \"PUSH4\",\n      \"path\": \"9\",\n      \"value\": \"0x95EA7B3\"\n    },\n    \"765\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1514\n      ],\n      \"op\": \"SWAP4\",\n      \"path\": \"9\"\n    },\n    \"766\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1523,\n        1536\n      ],\n      \"op\": \"AND\",\n      \"path\": \"9\"\n    },\n    \"767\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1523,\n        1536\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"9\"\n    },\n    \"768\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1523,\n        1536\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"9\"\n    },\n    \"769\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1523,\n        1536\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"9\"\n    },\n    \"770\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1539,\n        1557\n      ],\n      \"op\": \"PUSH4\",\n      \"path\": \"9\",\n      \"value\": \"0xC5B37C22\"\n    },\n    \"775\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1539,\n        1557\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"9\"\n    },\n    \"776\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1539,\n        1559\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x4\"\n    },\n    \"778\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1539,\n        1559\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"9\"\n    },\n    \"779\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1539,\n        1559\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"9\"\n    },\n    \"780\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1539,\n        1559\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"9\"\n    },\n    \"781\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1539,\n        1559\n      ],\n      \"op\": \"SWAP3\",\n      \"path\": \"9\"\n    },\n    \"782\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1506\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x20\"\n    },\n    \"784\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1506\n      ],\n      \"op\": \"SWAP3\",\n      \"path\": \"9\"\n    },\n    \"785\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1539,\n        1559\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"9\"\n    },\n    \"786\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1539,\n        1559\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"9\"\n    },\n    \"787\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1539,\n        1559\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"9\"\n    },\n    \"788\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1539,\n        1559\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"9\"\n    },\n    \"789\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1539,\n        1559\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"9\"\n    },\n    \"790\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1539,\n        1559\n      ],\n      \"op\": \"SUB\",\n      \"path\": \"9\"\n    },\n    \"791\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1539,\n        1559\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"9\"\n    },\n    \"792\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1539,\n        1559\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"9\"\n    },\n    \"793\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1523,\n        1536\n      ],\n      \"op\": \"DUP7\",\n      \"path\": \"9\"\n    },\n    \"794\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1539,\n        1559\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"9\"\n    },\n    \"795\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1539,\n        1559\n      ],\n      \"op\": \"EXTCODESIZE\",\n      \"path\": \"9\"\n    },\n    \"796\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1539,\n        1559\n      ],\n      \"op\": \"ISZERO\",\n      \"path\": \"9\"\n    },\n    \"797\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1539,\n        1559\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"9\"\n    },\n    \"798\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1539,\n        1559\n      ],\n      \"op\": \"ISZERO\",\n      \"path\": \"9\"\n    },\n    \"799\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1539,\n        1559\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"9\",\n      \"value\": \"0x327\"\n    },\n    \"802\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1539,\n        1559\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"9\"\n    },\n    \"803\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1539,\n        1559\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x0\"\n    },\n    \"805\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1539,\n        1559\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"9\"\n    },\n    \"806\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1539,\n        1559\n      ],\n      \"op\": \"REVERT\",\n      \"path\": \"9\"\n    },\n    \"807\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1539,\n        1559\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"9\"\n    },\n    \"808\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1539,\n        1559\n      ],\n      \"op\": \"POP\",\n      \"path\": \"9\"\n    },\n    \"809\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1539,\n        1559\n      ],\n      \"op\": \"GAS\",\n      \"path\": \"9\"\n    },\n    \"810\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1539,\n        1559\n      ],\n      \"op\": \"STATICCALL\",\n      \"path\": \"9\"\n    },\n    \"811\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1539,\n        1559\n      ],\n      \"op\": \"ISZERO\",\n      \"path\": \"9\"\n    },\n    \"812\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1539,\n        1559\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"9\"\n    },\n    \"813\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1539,\n        1559\n      ],\n      \"op\": \"ISZERO\",\n      \"path\": \"9\"\n    },\n    \"814\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1539,\n        1559\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"9\",\n      \"value\": \"0x33B\"\n    },\n    \"817\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1539,\n        1559\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"9\"\n    },\n    \"818\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1539,\n        1559\n      ],\n      \"op\": \"RETURNDATASIZE\",\n      \"path\": \"9\"\n    },\n    \"819\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1539,\n        1559\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x0\"\n    },\n    \"821\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1539,\n        1559\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"9\"\n    },\n    \"822\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1539,\n        1559\n      ],\n      \"op\": \"RETURNDATACOPY\",\n      \"path\": \"9\"\n    },\n    \"823\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1539,\n        1559\n      ],\n      \"op\": \"RETURNDATASIZE\",\n      \"path\": \"9\"\n    },\n    \"824\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1539,\n        1559\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x0\"\n    },\n    \"826\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1539,\n        1559\n      ],\n      \"op\": \"REVERT\",\n      \"path\": \"9\"\n    },\n    \"827\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1539,\n        1559\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"9\"\n    },\n    \"828\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1539,\n        1559\n      ],\n      \"op\": \"POP\",\n      \"path\": \"9\"\n    },\n    \"829\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1539,\n        1559\n      ],\n      \"op\": \"POP\",\n      \"path\": \"9\"\n    },\n    \"830\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1539,\n        1559\n      ],\n      \"op\": \"POP\",\n      \"path\": \"9\"\n    },\n    \"831\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1539,\n        1559\n      ],\n      \"op\": \"POP\",\n      \"path\": \"9\"\n    },\n    \"832\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1539,\n        1559\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x40\"\n    },\n    \"834\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1539,\n        1559\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"9\"\n    },\n    \"835\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1539,\n        1559\n      ],\n      \"op\": \"RETURNDATASIZE\",\n      \"path\": \"9\"\n    },\n    \"836\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1539,\n        1559\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x20\"\n    },\n    \"838\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1539,\n        1559\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"9\"\n    },\n    \"839\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1539,\n        1559\n      ],\n      \"op\": \"LT\",\n      \"path\": \"9\"\n    },\n    \"840\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1539,\n        1559\n      ],\n      \"op\": \"ISZERO\",\n      \"path\": \"9\"\n    },\n    \"841\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1539,\n        1559\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"9\",\n      \"value\": \"0x351\"\n    },\n    \"844\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1539,\n        1559\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"9\"\n    },\n    \"845\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1539,\n        1559\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x0\"\n    },\n    \"847\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1539,\n        1559\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"9\"\n    },\n    \"848\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1539,\n        1559\n      ],\n      \"op\": \"REVERT\",\n      \"path\": \"9\"\n    },\n    \"849\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1539,\n        1559\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"9\"\n    },\n    \"850\": {\n      \"op\": \"POP\"\n    },\n    \"851\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1539,\n        1559\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"9\"\n    },\n    \"852\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x40\"\n    },\n    \"854\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"9\"\n    },\n    \"855\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"9\"\n    },\n    \"856\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"858\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"860\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0xE0\"\n    },\n    \"862\": {\n      \"op\": \"SHL\"\n    },\n    \"863\": {\n      \"op\": \"SUB\"\n    },\n    \"864\": {\n      \"op\": \"NOT\"\n    },\n    \"865\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0xE0\"\n    },\n    \"867\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"DUP7\",\n      \"path\": \"9\"\n    },\n    \"868\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"9\"\n    },\n    \"869\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"SHL\",\n      \"path\": \"9\"\n    },\n    \"870\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"AND\",\n      \"path\": \"9\"\n    },\n    \"871\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"9\"\n    },\n    \"872\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"9\"\n    },\n    \"873\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"875\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"877\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0xA0\"\n    },\n    \"879\": {\n      \"op\": \"SHL\"\n    },\n    \"880\": {\n      \"op\": \"SUB\"\n    },\n    \"881\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"9\"\n    },\n    \"882\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"SWAP4\",\n      \"path\": \"9\"\n    },\n    \"883\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"AND\",\n      \"path\": \"9\"\n    },\n    \"884\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x4\"\n    },\n    \"886\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"DUP5\",\n      \"path\": \"9\"\n    },\n    \"887\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"9\"\n    },\n    \"888\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"9\"\n    },\n    \"889\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x24\"\n    },\n    \"891\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"DUP4\",\n      \"path\": \"9\"\n    },\n    \"892\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"9\"\n    },\n    \"893\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"9\"\n    },\n    \"894\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"9\"\n    },\n    \"895\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"9\"\n    },\n    \"896\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"9\"\n    },\n    \"897\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"9\"\n    },\n    \"898\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x44\"\n    },\n    \"900\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"9\"\n    },\n    \"901\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"DUP4\",\n      \"path\": \"9\"\n    },\n    \"902\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"9\"\n    },\n    \"903\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"SWAP3\",\n      \"path\": \"9\"\n    },\n    \"904\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1539,\n        1559\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x20\"\n    },\n    \"906\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1539,\n        1559\n      ],\n      \"op\": \"SWAP3\",\n      \"path\": \"9\"\n    },\n    \"907\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"9\"\n    },\n    \"908\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"9\"\n    },\n    \"909\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"9\"\n    },\n    \"910\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"9\"\n    },\n    \"911\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"SUB\",\n      \"path\": \"9\"\n    },\n    \"912\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"9\"\n    },\n    \"913\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"9\"\n    },\n    \"914\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x0\"\n    },\n    \"916\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"DUP8\",\n      \"path\": \"9\"\n    },\n    \"917\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"9\"\n    },\n    \"918\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"EXTCODESIZE\",\n      \"path\": \"9\"\n    },\n    \"919\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"ISZERO\",\n      \"path\": \"9\"\n    },\n    \"920\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"9\"\n    },\n    \"921\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"ISZERO\",\n      \"path\": \"9\"\n    },\n    \"922\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"9\",\n      \"value\": \"0x3A2\"\n    },\n    \"925\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"9\"\n    },\n    \"926\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x0\"\n    },\n    \"928\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"9\"\n    },\n    \"929\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"REVERT\",\n      \"path\": \"9\"\n    },\n    \"930\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"9\"\n    },\n    \"931\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"POP\",\n      \"path\": \"9\"\n    },\n    \"932\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"GAS\",\n      \"path\": \"9\"\n    },\n    \"933\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"CALL\",\n      \"path\": \"9\"\n    },\n    \"934\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"ISZERO\",\n      \"path\": \"9\"\n    },\n    \"935\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"9\"\n    },\n    \"936\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"ISZERO\",\n      \"path\": \"9\"\n    },\n    \"937\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"9\",\n      \"value\": \"0x3B6\"\n    },\n    \"940\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"9\"\n    },\n    \"941\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"RETURNDATASIZE\",\n      \"path\": \"9\"\n    },\n    \"942\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x0\"\n    },\n    \"944\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"9\"\n    },\n    \"945\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"RETURNDATACOPY\",\n      \"path\": \"9\"\n    },\n    \"946\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"RETURNDATASIZE\",\n      \"path\": \"9\"\n    },\n    \"947\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x0\"\n    },\n    \"949\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"REVERT\",\n      \"path\": \"9\"\n    },\n    \"950\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"9\"\n    },\n    \"951\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"POP\",\n      \"path\": \"9\"\n    },\n    \"952\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"POP\",\n      \"path\": \"9\"\n    },\n    \"953\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"POP\",\n      \"path\": \"9\"\n    },\n    \"954\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"POP\",\n      \"path\": \"9\"\n    },\n    \"955\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x40\"\n    },\n    \"957\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"9\"\n    },\n    \"958\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"RETURNDATASIZE\",\n      \"path\": \"9\"\n    },\n    \"959\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x20\"\n    },\n    \"961\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"9\"\n    },\n    \"962\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"LT\",\n      \"path\": \"9\"\n    },\n    \"963\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"ISZERO\",\n      \"path\": \"9\"\n    },\n    \"964\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"9\",\n      \"value\": \"0x3CC\"\n    },\n    \"967\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"9\"\n    },\n    \"968\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x0\"\n    },\n    \"970\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"9\"\n    },\n    \"971\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"REVERT\",\n      \"path\": \"9\"\n    },\n    \"972\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1484,\n        1560\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"9\"\n    },\n    \"973\": {\n      \"op\": \"POP\"\n    },\n    \"974\": {\n      \"op\": \"POP\"\n    },\n    \"975\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1631\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"statement\": 2,\n      \"value\": \"0x0\"\n    },\n    \"977\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1631\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"9\"\n    },\n    \"978\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1631\n      ],\n      \"op\": \"SLOAD\",\n      \"path\": \"9\"\n    },\n    \"979\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x40\"\n    },\n    \"981\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"9\"\n    },\n    \"982\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"9\"\n    },\n    \"983\": {\n      \"op\": \"PUSH4\",\n      \"value\": \"0x1EFC38E9\"\n    },\n    \"988\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0xE3\"\n    },\n    \"990\": {\n      \"op\": \"SHL\"\n    },\n    \"991\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"9\"\n    },\n    \"992\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"MSTORE\",\n      \"path\": \"9\"\n    },\n    \"993\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"9\"\n    },\n    \"994\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"9\"\n    },\n    \"995\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"997\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"999\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0xA0\"\n    },\n    \"1001\": {\n      \"op\": \"SHL\"\n    },\n    \"1002\": {\n      \"op\": \"SUB\"\n    },\n    \"1003\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1631\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"9\"\n    },\n    \"1004\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1631\n      ],\n      \"op\": \"SWAP3\",\n      \"path\": \"9\"\n    },\n    \"1005\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1631\n      ],\n      \"op\": \"AND\",\n      \"path\": \"9\"\n    },\n    \"1006\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1631\n      ],\n      \"op\": \"SWAP3\",\n      \"path\": \"9\"\n    },\n    \"1007\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1648\n      ],\n      \"op\": \"PUSH4\",\n      \"path\": \"9\",\n      \"value\": \"0xF7E1C748\"\n    },\n    \"1012\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1648\n      ],\n      \"op\": \"SWAP3\",\n      \"path\": \"9\"\n    },\n    \"1013\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x4\"\n    },\n    \"1015\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"9\"\n    },\n    \"1016\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"DUP5\",\n      \"path\": \"9\"\n    },\n    \"1017\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"9\"\n    },\n    \"1018\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"SWAP4\",\n      \"path\": \"9\"\n    },\n    \"1019\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x60\"\n    },\n    \"1021\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"SWAP4\",\n      \"path\": \"9\"\n    },\n    \"1022\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"9\"\n    },\n    \"1023\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"DUP4\",\n      \"path\": \"9\"\n    },\n    \"1024\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"9\"\n    },\n    \"1025\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"SUB\",\n      \"path\": \"9\"\n    },\n    \"1026\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"9\"\n    },\n    \"1027\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"9\"\n    },\n    \"1028\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"9\"\n    },\n    \"1029\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"9\"\n    },\n    \"1030\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"9\"\n    },\n    \"1031\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"9\"\n    },\n    \"1032\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1631\n      ],\n      \"op\": \"DUP8\",\n      \"path\": \"9\"\n    },\n    \"1033\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"9\"\n    },\n    \"1034\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"EXTCODESIZE\",\n      \"path\": \"9\"\n    },\n    \"1035\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"ISZERO\",\n      \"path\": \"9\"\n    },\n    \"1036\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"9\"\n    },\n    \"1037\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"ISZERO\",\n      \"path\": \"9\"\n    },\n    \"1038\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"9\",\n      \"value\": \"0x416\"\n    },\n    \"1041\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"9\"\n    },\n    \"1042\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x0\"\n    },\n    \"1044\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"9\"\n    },\n    \"1045\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"REVERT\",\n      \"path\": \"9\"\n    },\n    \"1046\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"9\"\n    },\n    \"1047\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"POP\",\n      \"path\": \"9\"\n    },\n    \"1048\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"GAS\",\n      \"path\": \"9\"\n    },\n    \"1049\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"CALL\",\n      \"path\": \"9\"\n    },\n    \"1050\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"ISZERO\",\n      \"path\": \"9\"\n    },\n    \"1051\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"9\"\n    },\n    \"1052\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"ISZERO\",\n      \"path\": \"9\"\n    },\n    \"1053\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"9\",\n      \"value\": \"0x42A\"\n    },\n    \"1056\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"9\"\n    },\n    \"1057\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"RETURNDATASIZE\",\n      \"path\": \"9\"\n    },\n    \"1058\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x0\"\n    },\n    \"1060\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"9\"\n    },\n    \"1061\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"RETURNDATACOPY\",\n      \"path\": \"9\"\n    },\n    \"1062\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"RETURNDATASIZE\",\n      \"path\": \"9\"\n    },\n    \"1063\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x0\"\n    },\n    \"1065\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"REVERT\",\n      \"path\": \"9\"\n    },\n    \"1066\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"9\"\n    },\n    \"1067\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"POP\",\n      \"path\": \"9\"\n    },\n    \"1068\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"POP\",\n      \"path\": \"9\"\n    },\n    \"1069\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"POP\",\n      \"path\": \"9\"\n    },\n    \"1070\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"POP\",\n      \"path\": \"9\"\n    },\n    \"1071\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x40\"\n    },\n    \"1073\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"9\"\n    },\n    \"1074\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"RETURNDATASIZE\",\n      \"path\": \"9\"\n    },\n    \"1075\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x60\"\n    },\n    \"1077\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"DUP2\",\n      \"path\": \"9\"\n    },\n    \"1078\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"LT\",\n      \"path\": \"9\"\n    },\n    \"1079\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"ISZERO\",\n      \"path\": \"9\"\n    },\n    \"1080\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"PUSH2\",\n      \"path\": \"9\",\n      \"value\": \"0x440\"\n    },\n    \"1083\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"JUMPI\",\n      \"path\": \"9\"\n    },\n    \"1084\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x0\"\n    },\n    \"1086\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"9\"\n    },\n    \"1087\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"REVERT\",\n      \"path\": \"9\"\n    },\n    \"1088\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"JUMPDEST\",\n      \"path\": \"9\"\n    },\n    \"1089\": {\n      \"op\": \"POP\"\n    },\n    \"1090\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"9\"\n    },\n    \"1091\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"9\"\n    },\n    \"1092\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x20\"\n    },\n    \"1094\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"DUP3\",\n      \"path\": \"9\"\n    },\n    \"1095\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"9\"\n    },\n    \"1096\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"9\"\n    },\n    \"1097\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x40\"\n    },\n    \"1099\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"9\"\n    },\n    \"1100\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"SWAP3\",\n      \"path\": \"9\"\n    },\n    \"1101\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"ADD\",\n      \"path\": \"9\"\n    },\n    \"1102\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1618,\n        1650\n      ],\n      \"op\": \"MLOAD\",\n      \"path\": \"9\"\n    },\n    \"1103\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1590,\n        1614\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x3\"\n    },\n    \"1105\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1570,\n        1650\n      ],\n      \"op\": \"SSTORE\",\n      \"path\": \"9\"\n    },\n    \"1106\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1579,\n        1588\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0x2\"\n    },\n    \"1108\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1570,\n        1650\n      ],\n      \"op\": \"DUP1\",\n      \"path\": \"9\"\n    },\n    \"1109\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1570,\n        1650\n      ],\n      \"op\": \"SLOAD\",\n      \"path\": \"9\"\n    },\n    \"1110\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0xFF\"\n    },\n    \"1112\": {\n      \"op\": \"NOT\"\n    },\n    \"1113\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1570,\n        1650\n      ],\n      \"op\": \"AND\",\n      \"path\": \"9\"\n    },\n    \"1114\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1570,\n        1650\n      ],\n      \"op\": \"PUSH1\",\n      \"path\": \"9\",\n      \"value\": \"0xFF\"\n    },\n    \"1116\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1570,\n        1650\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"9\"\n    },\n    \"1117\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1570,\n        1650\n      ],\n      \"op\": \"SWAP4\",\n      \"path\": \"9\"\n    },\n    \"1118\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1570,\n        1650\n      ],\n      \"op\": \"AND\",\n      \"path\": \"9\"\n    },\n    \"1119\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1570,\n        1650\n      ],\n      \"op\": \"SWAP3\",\n      \"path\": \"9\"\n    },\n    \"1120\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1570,\n        1650\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"9\"\n    },\n    \"1121\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1570,\n        1650\n      ],\n      \"op\": \"SWAP3\",\n      \"path\": \"9\"\n    },\n    \"1122\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1570,\n        1650\n      ],\n      \"op\": \"OR\",\n      \"path\": \"9\"\n    },\n    \"1123\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1570,\n        1650\n      ],\n      \"op\": \"SWAP1\",\n      \"path\": \"9\"\n    },\n    \"1124\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1570,\n        1650\n      ],\n      \"op\": \"SWAP2\",\n      \"path\": \"9\"\n    },\n    \"1125\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1570,\n        1650\n      ],\n      \"op\": \"SSTORE\",\n      \"path\": \"9\"\n    },\n    \"1126\": {\n      \"op\": \"PUSH1\",\n      \"value\": \"0x1\"\n    },\n    \"1128\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"offset\": [\n        1570,\n        1650\n      ],\n      \"op\": \"SSTORE\",\n      \"path\": \"9\"\n    },\n    \"1129\": {\n      \"fn\": \"FetchOracleTestClient.queryOracleValue\",\n      \"jump\": \"o\",\n      \"offset\": [\n        1330,\n        1657\n      ],\n      \"op\": \"JUMP\",\n      \"path\": \"9\"\n    }\n  },\n  \"sha1\": \"1e1432f308d186ca35fb73d8f7bc376195fdd503\",\n  \"source\": \"// SPDX-License-Identifier:Apache-2.0\\n//------------------------------------------------------------------------------\\n//\\n//   Copyright 2020 Fetch.AI Limited\\n//\\n//   Licensed under the Apache License, Version 2.0 (the \\\"License\\\");\\n//   you may not use this file except in compliance with the License.\\n//   You may obtain a copy of the License at\\n//\\n//       http://www.apache.org/licenses/LICENSE-2.0\\n//\\n//   Unless required by applicable law or agreed to in writing, software\\n//   distributed under the License is distributed on an \\\"AS IS\\\" BASIS,\\n//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\\n//   See the License for the specific language governing permissions and\\n//   limitations under the License.\\n//\\n//------------------------------------------------------------------------------\\n\\npragma solidity ^0.6.0;\\n\\nimport \\\"./FetchOracleMock.sol\\\";\\nimport \\\"../interfaces/IFetchOracleClient.sol\\\";\\n\\ncontract FetchOracleTestClient is IFetchOracleClient{\\n    FetchOracle public _fetch_oracle;\\n\\n    uint256 public _value;\\n    uint8 public _decimals;\\n    uint256 public _updatedAtEthBlockNumber;\\n\\n\\n    constructor(address fetchOracleContractAddress) public {\\n        // NOTE(pb): We expect this to de deployed on testnet only:\\n        _fetch_oracle = FetchOracleMock(fetchOracleContractAddress);\\n    }\\n\\n\\n    function queryOracleValue() external override\\n    {\\n        _fetch_oracle._token().transferFrom(msg.sender, address(this), _fetch_oracle._fee());\\n        _fetch_oracle._token().approve(address(_fetch_oracle), _fetch_oracle._fee());\\n        (_value, _decimals, _updatedAtEthBlockNumber) = _fetch_oracle.queryOracleValue();\\n    }\\n}\\n\\n// Contract created exclusively for more comfortable usage in truffle:\\ncontract FetchOracleTestClientETH is FetchOracleTestClient {\\n    constructor(address fetchOracleContractAddress) public FetchOracleTestClient(fetchOracleContractAddress) {\\n    }\\n}\\n\",\n  \"sourceMap\": \"925:734:9:-:0;;;1124:199;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;1124:199:9;1257:13;:59;;-1:-1:-1;;;;;1257:59:9;;;-1:-1:-1;;;;;;1257:59:9;;;;;;;;;925:734;;;;;;\",\n  \"sourcePath\": \"contracts/FetchOracleTestClient.sol\",\n  \"type\": \"contract\"\n}"
  },
  {
    "path": "packages/fetchai/contracts/oracle_client/contract.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the class to connect to an oracle client contract.\"\"\"\n\nimport logging\nfrom typing import cast\n\nfrom aea_ledger_ethereum import EthereumApi\nfrom aea_ledger_fetchai import FetchAIApi\n\nfrom aea.common import Address, JSONLike\nfrom aea.configurations.base import PublicId\nfrom aea.contracts.base import Contract\nfrom aea.crypto.base import LedgerApi\n\n\nPUBLIC_ID = PublicId.from_str(\"fetchai/oracle_client:0.11.3\")\n\n_default_logger = logging.getLogger(\n    \"aea.packages.fetchai.contracts.oracle_client.contract\"\n)\n\n\nclass FetchOracleClientContract(Contract):\n    \"\"\"The Fetch oracle client contract.\"\"\"\n\n    @classmethod\n    def get_query_transaction(\n        cls,\n        ledger_api: LedgerApi,\n        contract_address: Address,\n        from_address: Address,\n        query_function: str,\n        amount: int = 0,\n        gas: int = 0,\n        tx_fee: int = 0,\n    ) -> JSONLike:\n        \"\"\"\n        Get transaction to query oracle value in contract\n\n        :param ledger_api: the ledger apis.\n        :param contract_address: the contract address.\n        :param from_address: the address of the transaction sender.\n        :param query_function: the query oracle value function.\n        :param amount: the amount to transfer as part of the transaction.\n        :param gas: the gas limit for the transaction.\n        :param tx_fee: the transaction fee.\n        :return: the query transaction\n        \"\"\"\n        if ledger_api.identifier == EthereumApi.identifier:\n            nonce = ledger_api.api.eth.getTransactionCount(from_address)\n            instance = cls.get_instance(ledger_api, contract_address)\n            function = getattr(instance.functions, query_function)\n            query_args = ()\n            intermediate = function(*query_args)\n            tx = intermediate.buildTransaction(\n                {\n                    \"gas\": gas,\n                    \"gasPrice\": ledger_api.api.toWei(\"50\", \"gwei\"),\n                    \"from\": from_address,\n                    \"nonce\": nonce,\n                }\n            )\n            tx = ledger_api.update_with_gas_estimate(tx)\n            return tx\n        if ledger_api.identifier == FetchAIApi.identifier:\n            msg = {\"query_oracle_value\": {}}  # type: JSONLike\n            fetchai_api = cast(FetchAIApi, ledger_api)\n            tx = fetchai_api.get_handle_transaction(\n                from_address,\n                contract_address,\n                msg,\n                amount=amount,\n                tx_fee=tx_fee,\n                gas=gas,\n            )\n            return tx\n        raise NotImplementedError\n"
  },
  {
    "path": "packages/fetchai/contracts/oracle_client/contract.yaml",
    "content": "name: oracle_client\nauthor: fetchai\nversion: 0.11.3\ntype: contract\ndescription: Fetch oracle client contract\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: Qmasz3mr6zrBNWULfiMeeMC9py561evkcwsCbkjEZnwto5\n  __init__.py: QmYWrZY2q18XGiS8EDki97v3Gi9KHLi1YhC7e7cpbkEXU2\n  build/FetchOracleTestClient.json: QmbqwQiYs8Tb2DKB1BDiigqmXxVt1BmfM5RVXHwkvysdqf\n  build/oracle_client.wasm: QmXE7H9JqjJFNEzjUiMv5Sv6NyaMqB4eYDwSVym66L52xU\n  contract.py: QmfHnZjmgtAmzJCVVWbePYy6D2brchHt2iCQX3E2rPsG86\n  contracts/FetchOracleTestClient.sol: QmWpUJ4aBrNreiyuXe6EgfSfE7T7hWz3xHDdT7fFye3WCG\nfingerprint_ignore_patterns: []\nclass_name: FetchOracleClientContract\ncontract_interface_paths:\n  ethereum: build/FetchOracleTestClient.json\n  fetchai: build/oracle_client.wasm\ndependencies:\n  aea-ledger-ethereum:\n    version: <2.0.0,>=1.0.0\n  aea-ledger-fetchai:\n    version: <2.0.0,>=1.0.0\n"
  },
  {
    "path": "packages/fetchai/contracts/oracle_client/contracts/FetchOracleTestClient.sol",
    "content": "// SPDX-License-Identifier:Apache-2.0\n//------------------------------------------------------------------------------\n//\n//   Copyright 2020 Fetch.AI Limited\n//\n//   Licensed under the Apache License, Version 2.0 (the \"License\");\n//   you may not use this file except in compliance with the License.\n//   You may obtain a copy of the License at\n//\n//       http://www.apache.org/licenses/LICENSE-2.0\n//\n//   Unless required by applicable law or agreed to in writing, software\n//   distributed under the License is distributed on an \"AS IS\" BASIS,\n//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//   See the License for the specific language governing permissions and\n//   limitations under the License.\n//\n//------------------------------------------------------------------------------\n\npragma solidity ^0.6.0;\n\nimport \"./FetchOracleMock.sol\";\nimport \"../interfaces/IFetchOracleClient.sol\";\n\ncontract FetchOracleTestClient is IFetchOracleClient{\n    FetchOracle public _fetch_oracle;\n\n    uint256 public _value;\n    uint8 public _decimals;\n    uint256 public _updatedAtEthBlockNumber;\n\n\n    constructor(address fetchOracleContractAddress) public {\n        // NOTE(pb): We expect this to de deployed on testnet only:\n        _fetch_oracle = FetchOracleMock(fetchOracleContractAddress);\n    }\n\n\n    function queryOracleValue() external override\n    {\n        _fetch_oracle._token().transferFrom(msg.sender, address(this), _fetch_oracle._fee());\n        _fetch_oracle._token().approve(address(_fetch_oracle), _fetch_oracle._fee());\n        (_value, _decimals, _updatedAtEthBlockNumber) = _fetch_oracle.queryOracleValue();\n    }\n}\n\n// Contract created exclusively for more comfortable usage in truffle:\ncontract FetchOracleTestClientETH is FetchOracleTestClient {\n    constructor(address fetchOracleContractAddress) public FetchOracleTestClient(fetchOracleContractAddress) {\n    }\n}\n"
  },
  {
    "path": "packages/fetchai/contracts/staking_erc20/README.md",
    "content": "# Fetch Staking ERC20 Contract\n\n## Description\n\nThis contract package is used to interface with a Fetch staking ERC20 contract.\n\n## Functions\n\n- `get_stake(address)`: Get the balance for a specific `address`\n"
  },
  {
    "path": "packages/fetchai/contracts/staking_erc20/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the support resources for the staking_erc20 contract.\"\"\"\n"
  },
  {
    "path": "packages/fetchai/contracts/staking_erc20/build/Migrations.json",
    "content": "{\n  \"contractName\": \"Migrations\",\n  \"abi\": [\n    {\n      \"constant\": true,\n      \"inputs\": [],\n      \"name\": \"last_completed_migration\",\n      \"outputs\": [\n        {\n          \"name\": \"\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"payable\": false,\n      \"stateMutability\": \"view\",\n      \"type\": \"function\"\n    },\n    {\n      \"constant\": true,\n      \"inputs\": [],\n      \"name\": \"owner\",\n      \"outputs\": [\n        {\n          \"name\": \"\",\n          \"type\": \"address\"\n        }\n      ],\n      \"payable\": false,\n      \"stateMutability\": \"view\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [],\n      \"payable\": false,\n      \"stateMutability\": \"nonpayable\",\n      \"type\": \"constructor\"\n    },\n    {\n      \"constant\": false,\n      \"inputs\": [\n        {\n          \"name\": \"completed\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"name\": \"setCompleted\",\n      \"outputs\": [],\n      \"payable\": false,\n      \"stateMutability\": \"nonpayable\",\n      \"type\": \"function\"\n    },\n    {\n      \"constant\": false,\n      \"inputs\": [\n        {\n          \"name\": \"new_address\",\n          \"type\": \"address\"\n        }\n      ],\n      \"name\": \"upgrade\",\n      \"outputs\": [],\n      \"payable\": false,\n      \"stateMutability\": \"nonpayable\",\n      \"type\": \"function\"\n    }\n  ],\n  \"metadata\": \"{\\\"compiler\\\":{\\\"version\\\":\\\"0.5.2+commit.1df8f40c\\\"},\\\"language\\\":\\\"Solidity\\\",\\\"output\\\":{\\\"abi\\\":[{\\\"constant\\\":false,\\\"inputs\\\":[{\\\"name\\\":\\\"new_address\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"upgrade\\\",\\\"outputs\\\":[],\\\"payable\\\":false,\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"constant\\\":true,\\\"inputs\\\":[],\\\"name\\\":\\\"last_completed_migration\\\",\\\"outputs\\\":[{\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"payable\\\":false,\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"constant\\\":true,\\\"inputs\\\":[],\\\"name\\\":\\\"owner\\\",\\\"outputs\\\":[{\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"address\\\"}],\\\"payable\\\":false,\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"constant\\\":false,\\\"inputs\\\":[{\\\"name\\\":\\\"completed\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"setCompleted\\\",\\\"outputs\\\":[],\\\"payable\\\":false,\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"payable\\\":false,\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"constructor\\\"}],\\\"devdoc\\\":{\\\"methods\\\":{}},\\\"userdoc\\\":{\\\"methods\\\":{}}},\\\"settings\\\":{\\\"compilationTarget\\\":{\\\"/Users/aristotelistriantafyllidis/Documents/agents-research/erc1155/contracts/Migrations.sol\\\":\\\"Migrations\\\"},\\\"evmVersion\\\":\\\"byzantium\\\",\\\"libraries\\\":{},\\\"optimizer\\\":{\\\"enabled\\\":true,\\\"runs\\\":200},\\\"remappings\\\":[]},\\\"sources\\\":{\\\"/Users/aristotelistriantafyllidis/Documents/agents-research/erc1155/contracts/Migrations.sol\\\":{\\\"keccak256\\\":\\\"0xfdb731592344e2a2890faf03baec7b4bee7057ffba18ba6dbb6eec8db85f8f4c\\\",\\\"urls\\\":[\\\"bzzr://ddc8801d0a2a7220c2c9bf3881b4921817e72fdd96827ec8be4428fa009ace07\\\"]}},\\\"version\\\":1}\",\n  \"bytecode\": \"0x608060405234801561001057600080fd5b5060008054600160a060020a03191633179055610230806100326000396000f3fe608060405234801561001057600080fd5b5060043610610068577c010000000000000000000000000000000000000000000000000000000060003504630900f010811461006d578063445df0ac146100a25780638da5cb5b146100bc578063fdacd576146100ed575b600080fd5b6100a06004803603602081101561008357600080fd5b503573ffffffffffffffffffffffffffffffffffffffff1661010a565b005b6100aa6101bd565b60408051918252519081900360200190f35b6100c46101c3565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b6100a06004803603602081101561010357600080fd5b50356101df565b60005473ffffffffffffffffffffffffffffffffffffffff163314156101ba5760008190508073ffffffffffffffffffffffffffffffffffffffff1663fdacd5766001546040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180828152602001915050600060405180830381600087803b1580156101a057600080fd5b505af11580156101b4573d6000803e3d6000fd5b50505050505b50565b60015481565b60005473ffffffffffffffffffffffffffffffffffffffff1681565b60005473ffffffffffffffffffffffffffffffffffffffff163314156101ba5760015556fea165627a7a7230582065546060ae2694c0faa5ae3a86876c1f4f60c32218234b846e28adec7370506c0029\",\n  \"deployedBytecode\": \"0x608060405234801561001057600080fd5b5060043610610068577c010000000000000000000000000000000000000000000000000000000060003504630900f010811461006d578063445df0ac146100a25780638da5cb5b146100bc578063fdacd576146100ed575b600080fd5b6100a06004803603602081101561008357600080fd5b503573ffffffffffffffffffffffffffffffffffffffff1661010a565b005b6100aa6101bd565b60408051918252519081900360200190f35b6100c46101c3565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b6100a06004803603602081101561010357600080fd5b50356101df565b60005473ffffffffffffffffffffffffffffffffffffffff163314156101ba5760008190508073ffffffffffffffffffffffffffffffffffffffff1663fdacd5766001546040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180828152602001915050600060405180830381600087803b1580156101a057600080fd5b505af11580156101b4573d6000803e3d6000fd5b50505050505b50565b60015481565b60005473ffffffffffffffffffffffffffffffffffffffff1681565b60005473ffffffffffffffffffffffffffffffffffffffff163314156101ba5760015556fea165627a7a7230582065546060ae2694c0faa5ae3a86876c1f4f60c32218234b846e28adec7370506c0029\",\n  \"sourceMap\": \"34:480:0:-;;;123:50;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;150:5:0;:18;;-1:-1:-1;;;;;;150:18:0;158:10;150:18;;;34:480;;;;;;\",\n  \"deployedSourceMap\": \"34:480:0:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;34:480:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;347:165;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;347:165:0;;;;:::i;:::-;;82:36;;;:::i;:::-;;;;;;;;;;;;;;;;58:20;;;:::i;:::-;;;;;;;;;;;;;;;;;;;240:103;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;240:103:0;;:::i;347:165::-;223:5;;;;209:10;:19;205:26;;;409:19;442:11;409:45;;460:8;:21;;;482:24;;460:47;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;460:47:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;460:47:0;;;;230:1;205:26;347:165;:::o;82:36::-;;;;:::o;58:20::-;;;;;;:::o;240:103::-;223:5;;;;209:10;:19;205:26;;;302:24;:36;240:103::o\",\n  \"source\": \"pragma solidity >=0.4.21 <0.6.0;\\n\\ncontract Migrations {\\n  address public owner;\\n  uint public last_completed_migration;\\n\\n  constructor() public {\\n    owner = msg.sender;\\n  }\\n\\n  modifier restricted() {\\n    if (msg.sender == owner) _;\\n  }\\n\\n  function setCompleted(uint completed) public restricted {\\n    last_completed_migration = completed;\\n  }\\n\\n  function upgrade(address new_address) public restricted {\\n    Migrations upgraded = Migrations(new_address);\\n    upgraded.setCompleted(last_completed_migration);\\n  }\\n}\\n\",\n  \"sourcePath\": \"/Users/aristotelistriantafyllidis/Documents/agents-research/erc1155/contracts/Migrations.sol\",\n  \"ast\": {\n    \"absolutePath\": \"/Users/aristotelistriantafyllidis/Documents/agents-research/erc1155/contracts/Migrations.sol\",\n    \"exportedSymbols\": {\n      \"Migrations\": [\n        56\n      ]\n    },\n    \"id\": 57,\n    \"nodeType\": \"SourceUnit\",\n    \"nodes\": [\n      {\n        \"id\": 1,\n        \"literals\": [\n          \"solidity\",\n          \">=\",\n          \"0.4\",\n          \".21\",\n          \"<\",\n          \"0.6\",\n          \".0\"\n        ],\n        \"nodeType\": \"PragmaDirective\",\n        \"src\": \"0:32:0\"\n      },\n      {\n        \"baseContracts\": [],\n        \"contractDependencies\": [],\n        \"contractKind\": \"contract\",\n        \"documentation\": null,\n        \"fullyImplemented\": true,\n        \"id\": 56,\n        \"linearizedBaseContracts\": [\n          56\n        ],\n        \"name\": \"Migrations\",\n        \"nodeType\": \"ContractDefinition\",\n        \"nodes\": [\n          {\n            \"constant\": false,\n            \"id\": 3,\n            \"name\": \"owner\",\n            \"nodeType\": \"VariableDeclaration\",\n            \"scope\": 56,\n            \"src\": \"58:20:0\",\n            \"stateVariable\": true,\n            \"storageLocation\": \"default\",\n            \"typeDescriptions\": {\n              \"typeIdentifier\": \"t_address\",\n              \"typeString\": \"address\"\n            },\n            \"typeName\": {\n              \"id\": 2,\n              \"name\": \"address\",\n              \"nodeType\": \"ElementaryTypeName\",\n              \"src\": \"58:7:0\",\n              \"stateMutability\": \"nonpayable\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_address\",\n                \"typeString\": \"address\"\n              }\n            },\n            \"value\": null,\n            \"visibility\": \"public\"\n          },\n          {\n            \"constant\": false,\n            \"id\": 5,\n            \"name\": \"last_completed_migration\",\n            \"nodeType\": \"VariableDeclaration\",\n            \"scope\": 56,\n            \"src\": \"82:36:0\",\n            \"stateVariable\": true,\n            \"storageLocation\": \"default\",\n            \"typeDescriptions\": {\n              \"typeIdentifier\": \"t_uint256\",\n              \"typeString\": \"uint256\"\n            },\n            \"typeName\": {\n              \"id\": 4,\n              \"name\": \"uint\",\n              \"nodeType\": \"ElementaryTypeName\",\n              \"src\": \"82:4:0\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_uint256\",\n                \"typeString\": \"uint256\"\n              }\n            },\n            \"value\": null,\n            \"visibility\": \"public\"\n          },\n          {\n            \"body\": {\n              \"id\": 13,\n              \"nodeType\": \"Block\",\n              \"src\": \"144:29:0\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 11,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 8,\n                      \"name\": \"owner\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 3,\n                      \"src\": \"150:5:0\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_address\",\n                        \"typeString\": \"address\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 9,\n                        \"name\": \"msg\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 71,\n                        \"src\": \"158:3:0\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_magic_message\",\n                          \"typeString\": \"msg\"\n                        }\n                      },\n                      \"id\": 10,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"memberName\": \"sender\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": null,\n                      \"src\": \"158:10:0\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_address_payable\",\n                        \"typeString\": \"address payable\"\n                      }\n                    },\n                    \"src\": \"150:18:0\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address\",\n                      \"typeString\": \"address\"\n                    }\n                  },\n                  \"id\": 12,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"150:18:0\"\n                }\n              ]\n            },\n            \"documentation\": null,\n            \"id\": 14,\n            \"implemented\": true,\n            \"kind\": \"constructor\",\n            \"modifiers\": [],\n            \"name\": \"\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"parameters\": {\n              \"id\": 6,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"134:2:0\"\n            },\n            \"returnParameters\": {\n              \"id\": 7,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"144:0:0\"\n            },\n            \"scope\": 56,\n            \"src\": \"123:50:0\",\n            \"stateMutability\": \"nonpayable\",\n            \"superFunction\": null,\n            \"visibility\": \"public\"\n          },\n          {\n            \"body\": {\n              \"id\": 22,\n              \"nodeType\": \"Block\",\n              \"src\": \"199:37:0\",\n              \"statements\": [\n                {\n                  \"condition\": {\n                    \"argumentTypes\": null,\n                    \"commonType\": {\n                      \"typeIdentifier\": \"t_address\",\n                      \"typeString\": \"address\"\n                    },\n                    \"id\": 19,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftExpression\": {\n                      \"argumentTypes\": null,\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 16,\n                        \"name\": \"msg\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 71,\n                        \"src\": \"209:3:0\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_magic_message\",\n                          \"typeString\": \"msg\"\n                        }\n                      },\n                      \"id\": 17,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"memberName\": \"sender\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": null,\n                      \"src\": \"209:10:0\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_address_payable\",\n                        \"typeString\": \"address payable\"\n                      }\n                    },\n                    \"nodeType\": \"BinaryOperation\",\n                    \"operator\": \"==\",\n                    \"rightExpression\": {\n                      \"argumentTypes\": null,\n                      \"id\": 18,\n                      \"name\": \"owner\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 3,\n                      \"src\": \"223:5:0\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_address\",\n                        \"typeString\": \"address\"\n                      }\n                    },\n                    \"src\": \"209:19:0\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_bool\",\n                      \"typeString\": \"bool\"\n                    }\n                  },\n                  \"falseBody\": null,\n                  \"id\": 21,\n                  \"nodeType\": \"IfStatement\",\n                  \"src\": \"205:26:0\",\n                  \"trueBody\": {\n                    \"id\": 20,\n                    \"nodeType\": \"PlaceholderStatement\",\n                    \"src\": \"230:1:0\"\n                  }\n                }\n              ]\n            },\n            \"documentation\": null,\n            \"id\": 23,\n            \"name\": \"restricted\",\n            \"nodeType\": \"ModifierDefinition\",\n            \"parameters\": {\n              \"id\": 15,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"196:2:0\"\n            },\n            \"src\": \"177:59:0\",\n            \"visibility\": \"internal\"\n          },\n          {\n            \"body\": {\n              \"id\": 34,\n              \"nodeType\": \"Block\",\n              \"src\": \"296:47:0\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 32,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 30,\n                      \"name\": \"last_completed_migration\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5,\n                      \"src\": \"302:24:0\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 31,\n                      \"name\": \"completed\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 25,\n                      \"src\": \"329:9:0\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"src\": \"302:36:0\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"id\": 33,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"302:36:0\"\n                }\n              ]\n            },\n            \"documentation\": null,\n            \"id\": 35,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [\n              {\n                \"arguments\": null,\n                \"id\": 28,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 27,\n                  \"name\": \"restricted\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 23,\n                  \"src\": \"285:10:0\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$__$\",\n                    \"typeString\": \"modifier ()\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"285:10:0\"\n              }\n            ],\n            \"name\": \"setCompleted\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"parameters\": {\n              \"id\": 26,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 25,\n                  \"name\": \"completed\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"scope\": 35,\n                  \"src\": \"262:14:0\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 24,\n                    \"name\": \"uint\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"262:4:0\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"261:16:0\"\n            },\n            \"returnParameters\": {\n              \"id\": 29,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"296:0:0\"\n            },\n            \"scope\": 56,\n            \"src\": \"240:103:0\",\n            \"stateMutability\": \"nonpayable\",\n            \"superFunction\": null,\n            \"visibility\": \"public\"\n          },\n          {\n            \"body\": {\n              \"id\": 54,\n              \"nodeType\": \"Block\",\n              \"src\": \"403:109:0\",\n              \"statements\": [\n                {\n                  \"assignments\": [\n                    43\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 43,\n                      \"name\": \"upgraded\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"scope\": 54,\n                      \"src\": \"409:19:0\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"default\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_contract$_Migrations_$56\",\n                        \"typeString\": \"contract Migrations\"\n                      },\n                      \"typeName\": {\n                        \"contractScope\": null,\n                        \"id\": 42,\n                        \"name\": \"Migrations\",\n                        \"nodeType\": \"UserDefinedTypeName\",\n                        \"referencedDeclaration\": 56,\n                        \"src\": \"409:10:0\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_contract$_Migrations_$56\",\n                          \"typeString\": \"contract Migrations\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 47,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 45,\n                        \"name\": \"new_address\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 37,\n                        \"src\": \"442:11:0\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        }\n                      ],\n                      \"id\": 44,\n                      \"name\": \"Migrations\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 56,\n                      \"src\": \"431:10:0\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_type$_t_contract$_Migrations_$56_$\",\n                        \"typeString\": \"type(contract Migrations)\"\n                      }\n                    },\n                    \"id\": 46,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"typeConversion\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"431:23:0\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_contract$_Migrations_$56\",\n                      \"typeString\": \"contract Migrations\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"409:45:0\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 51,\n                        \"name\": \"last_completed_migration\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 5,\n                        \"src\": \"482:24:0\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 48,\n                        \"name\": \"upgraded\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 43,\n                        \"src\": \"460:8:0\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_contract$_Migrations_$56\",\n                          \"typeString\": \"contract Migrations\"\n                        }\n                      },\n                      \"id\": 50,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"memberName\": \"setCompleted\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": 35,\n                      \"src\": \"460:21:0\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_external_nonpayable$_t_uint256_$returns$__$\",\n                        \"typeString\": \"function (uint256) external\"\n                      }\n                    },\n                    \"id\": 52,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"460:47:0\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 53,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"460:47:0\"\n                }\n              ]\n            },\n            \"documentation\": null,\n            \"id\": 55,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [\n              {\n                \"arguments\": null,\n                \"id\": 40,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 39,\n                  \"name\": \"restricted\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 23,\n                  \"src\": \"392:10:0\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$__$\",\n                    \"typeString\": \"modifier ()\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"392:10:0\"\n              }\n            ],\n            \"name\": \"upgrade\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"parameters\": {\n              \"id\": 38,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 37,\n                  \"name\": \"new_address\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"scope\": 55,\n                  \"src\": \"364:19:0\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_address\",\n                    \"typeString\": \"address\"\n                  },\n                  \"typeName\": {\n                    \"id\": 36,\n                    \"name\": \"address\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"364:7:0\",\n                    \"stateMutability\": \"nonpayable\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address\",\n                      \"typeString\": \"address\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"363:21:0\"\n            },\n            \"returnParameters\": {\n              \"id\": 41,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"403:0:0\"\n            },\n            \"scope\": 56,\n            \"src\": \"347:165:0\",\n            \"stateMutability\": \"nonpayable\",\n            \"superFunction\": null,\n            \"visibility\": \"public\"\n          }\n        ],\n        \"scope\": 57,\n        \"src\": \"34:480:0\"\n      }\n    ],\n    \"src\": \"0:515:0\"\n  },\n  \"legacyAST\": {\n    \"absolutePath\": \"/Users/aristotelistriantafyllidis/Documents/agents-research/erc1155/contracts/Migrations.sol\",\n    \"exportedSymbols\": {\n      \"Migrations\": [\n        56\n      ]\n    },\n    \"id\": 57,\n    \"nodeType\": \"SourceUnit\",\n    \"nodes\": [\n      {\n        \"id\": 1,\n        \"literals\": [\n          \"solidity\",\n          \">=\",\n          \"0.4\",\n          \".21\",\n          \"<\",\n          \"0.6\",\n          \".0\"\n        ],\n        \"nodeType\": \"PragmaDirective\",\n        \"src\": \"0:32:0\"\n      },\n      {\n        \"baseContracts\": [],\n        \"contractDependencies\": [],\n        \"contractKind\": \"contract\",\n        \"documentation\": null,\n        \"fullyImplemented\": true,\n        \"id\": 56,\n        \"linearizedBaseContracts\": [\n          56\n        ],\n        \"name\": \"Migrations\",\n        \"nodeType\": \"ContractDefinition\",\n        \"nodes\": [\n          {\n            \"constant\": false,\n            \"id\": 3,\n            \"name\": \"owner\",\n            \"nodeType\": \"VariableDeclaration\",\n            \"scope\": 56,\n            \"src\": \"58:20:0\",\n            \"stateVariable\": true,\n            \"storageLocation\": \"default\",\n            \"typeDescriptions\": {\n              \"typeIdentifier\": \"t_address\",\n              \"typeString\": \"address\"\n            },\n            \"typeName\": {\n              \"id\": 2,\n              \"name\": \"address\",\n              \"nodeType\": \"ElementaryTypeName\",\n              \"src\": \"58:7:0\",\n              \"stateMutability\": \"nonpayable\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_address\",\n                \"typeString\": \"address\"\n              }\n            },\n            \"value\": null,\n            \"visibility\": \"public\"\n          },\n          {\n            \"constant\": false,\n            \"id\": 5,\n            \"name\": \"last_completed_migration\",\n            \"nodeType\": \"VariableDeclaration\",\n            \"scope\": 56,\n            \"src\": \"82:36:0\",\n            \"stateVariable\": true,\n            \"storageLocation\": \"default\",\n            \"typeDescriptions\": {\n              \"typeIdentifier\": \"t_uint256\",\n              \"typeString\": \"uint256\"\n            },\n            \"typeName\": {\n              \"id\": 4,\n              \"name\": \"uint\",\n              \"nodeType\": \"ElementaryTypeName\",\n              \"src\": \"82:4:0\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_uint256\",\n                \"typeString\": \"uint256\"\n              }\n            },\n            \"value\": null,\n            \"visibility\": \"public\"\n          },\n          {\n            \"body\": {\n              \"id\": 13,\n              \"nodeType\": \"Block\",\n              \"src\": \"144:29:0\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 11,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 8,\n                      \"name\": \"owner\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 3,\n                      \"src\": \"150:5:0\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_address\",\n                        \"typeString\": \"address\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 9,\n                        \"name\": \"msg\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 71,\n                        \"src\": \"158:3:0\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_magic_message\",\n                          \"typeString\": \"msg\"\n                        }\n                      },\n                      \"id\": 10,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"memberName\": \"sender\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": null,\n                      \"src\": \"158:10:0\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_address_payable\",\n                        \"typeString\": \"address payable\"\n                      }\n                    },\n                    \"src\": \"150:18:0\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address\",\n                      \"typeString\": \"address\"\n                    }\n                  },\n                  \"id\": 12,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"150:18:0\"\n                }\n              ]\n            },\n            \"documentation\": null,\n            \"id\": 14,\n            \"implemented\": true,\n            \"kind\": \"constructor\",\n            \"modifiers\": [],\n            \"name\": \"\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"parameters\": {\n              \"id\": 6,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"134:2:0\"\n            },\n            \"returnParameters\": {\n              \"id\": 7,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"144:0:0\"\n            },\n            \"scope\": 56,\n            \"src\": \"123:50:0\",\n            \"stateMutability\": \"nonpayable\",\n            \"superFunction\": null,\n            \"visibility\": \"public\"\n          },\n          {\n            \"body\": {\n              \"id\": 22,\n              \"nodeType\": \"Block\",\n              \"src\": \"199:37:0\",\n              \"statements\": [\n                {\n                  \"condition\": {\n                    \"argumentTypes\": null,\n                    \"commonType\": {\n                      \"typeIdentifier\": \"t_address\",\n                      \"typeString\": \"address\"\n                    },\n                    \"id\": 19,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftExpression\": {\n                      \"argumentTypes\": null,\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 16,\n                        \"name\": \"msg\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 71,\n                        \"src\": \"209:3:0\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_magic_message\",\n                          \"typeString\": \"msg\"\n                        }\n                      },\n                      \"id\": 17,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"memberName\": \"sender\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": null,\n                      \"src\": \"209:10:0\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_address_payable\",\n                        \"typeString\": \"address payable\"\n                      }\n                    },\n                    \"nodeType\": \"BinaryOperation\",\n                    \"operator\": \"==\",\n                    \"rightExpression\": {\n                      \"argumentTypes\": null,\n                      \"id\": 18,\n                      \"name\": \"owner\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 3,\n                      \"src\": \"223:5:0\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_address\",\n                        \"typeString\": \"address\"\n                      }\n                    },\n                    \"src\": \"209:19:0\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_bool\",\n                      \"typeString\": \"bool\"\n                    }\n                  },\n                  \"falseBody\": null,\n                  \"id\": 21,\n                  \"nodeType\": \"IfStatement\",\n                  \"src\": \"205:26:0\",\n                  \"trueBody\": {\n                    \"id\": 20,\n                    \"nodeType\": \"PlaceholderStatement\",\n                    \"src\": \"230:1:0\"\n                  }\n                }\n              ]\n            },\n            \"documentation\": null,\n            \"id\": 23,\n            \"name\": \"restricted\",\n            \"nodeType\": \"ModifierDefinition\",\n            \"parameters\": {\n              \"id\": 15,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"196:2:0\"\n            },\n            \"src\": \"177:59:0\",\n            \"visibility\": \"internal\"\n          },\n          {\n            \"body\": {\n              \"id\": 34,\n              \"nodeType\": \"Block\",\n              \"src\": \"296:47:0\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 32,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 30,\n                      \"name\": \"last_completed_migration\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5,\n                      \"src\": \"302:24:0\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 31,\n                      \"name\": \"completed\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 25,\n                      \"src\": \"329:9:0\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"src\": \"302:36:0\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"id\": 33,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"302:36:0\"\n                }\n              ]\n            },\n            \"documentation\": null,\n            \"id\": 35,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [\n              {\n                \"arguments\": null,\n                \"id\": 28,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 27,\n                  \"name\": \"restricted\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 23,\n                  \"src\": \"285:10:0\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$__$\",\n                    \"typeString\": \"modifier ()\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"285:10:0\"\n              }\n            ],\n            \"name\": \"setCompleted\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"parameters\": {\n              \"id\": 26,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 25,\n                  \"name\": \"completed\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"scope\": 35,\n                  \"src\": \"262:14:0\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 24,\n                    \"name\": \"uint\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"262:4:0\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"261:16:0\"\n            },\n            \"returnParameters\": {\n              \"id\": 29,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"296:0:0\"\n            },\n            \"scope\": 56,\n            \"src\": \"240:103:0\",\n            \"stateMutability\": \"nonpayable\",\n            \"superFunction\": null,\n            \"visibility\": \"public\"\n          },\n          {\n            \"body\": {\n              \"id\": 54,\n              \"nodeType\": \"Block\",\n              \"src\": \"403:109:0\",\n              \"statements\": [\n                {\n                  \"assignments\": [\n                    43\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 43,\n                      \"name\": \"upgraded\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"scope\": 54,\n                      \"src\": \"409:19:0\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"default\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_contract$_Migrations_$56\",\n                        \"typeString\": \"contract Migrations\"\n                      },\n                      \"typeName\": {\n                        \"contractScope\": null,\n                        \"id\": 42,\n                        \"name\": \"Migrations\",\n                        \"nodeType\": \"UserDefinedTypeName\",\n                        \"referencedDeclaration\": 56,\n                        \"src\": \"409:10:0\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_contract$_Migrations_$56\",\n                          \"typeString\": \"contract Migrations\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 47,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 45,\n                        \"name\": \"new_address\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 37,\n                        \"src\": \"442:11:0\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        }\n                      ],\n                      \"id\": 44,\n                      \"name\": \"Migrations\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 56,\n                      \"src\": \"431:10:0\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_type$_t_contract$_Migrations_$56_$\",\n                        \"typeString\": \"type(contract Migrations)\"\n                      }\n                    },\n                    \"id\": 46,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"typeConversion\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"431:23:0\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_contract$_Migrations_$56\",\n                      \"typeString\": \"contract Migrations\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"409:45:0\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 51,\n                        \"name\": \"last_completed_migration\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 5,\n                        \"src\": \"482:24:0\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 48,\n                        \"name\": \"upgraded\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 43,\n                        \"src\": \"460:8:0\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_contract$_Migrations_$56\",\n                          \"typeString\": \"contract Migrations\"\n                        }\n                      },\n                      \"id\": 50,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"memberName\": \"setCompleted\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": 35,\n                      \"src\": \"460:21:0\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_external_nonpayable$_t_uint256_$returns$__$\",\n                        \"typeString\": \"function (uint256) external\"\n                      }\n                    },\n                    \"id\": 52,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"460:47:0\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 53,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"460:47:0\"\n                }\n              ]\n            },\n            \"documentation\": null,\n            \"id\": 55,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [\n              {\n                \"arguments\": null,\n                \"id\": 40,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 39,\n                  \"name\": \"restricted\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 23,\n                  \"src\": \"392:10:0\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$__$\",\n                    \"typeString\": \"modifier ()\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"392:10:0\"\n              }\n            ],\n            \"name\": \"upgrade\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"parameters\": {\n              \"id\": 38,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 37,\n                  \"name\": \"new_address\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"scope\": 55,\n                  \"src\": \"364:19:0\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_address\",\n                    \"typeString\": \"address\"\n                  },\n                  \"typeName\": {\n                    \"id\": 36,\n                    \"name\": \"address\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"364:7:0\",\n                    \"stateMutability\": \"nonpayable\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address\",\n                      \"typeString\": \"address\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"363:21:0\"\n            },\n            \"returnParameters\": {\n              \"id\": 41,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"403:0:0\"\n            },\n            \"scope\": 56,\n            \"src\": \"347:165:0\",\n            \"stateMutability\": \"nonpayable\",\n            \"superFunction\": null,\n            \"visibility\": \"public\"\n          }\n        ],\n        \"scope\": 57,\n        \"src\": \"34:480:0\"\n      }\n    ],\n    \"src\": \"0:515:0\"\n  },\n  \"compiler\": {\n    \"name\": \"solc\",\n    \"version\": \"0.5.2+commit.1df8f40c.Emscripten.clang\"\n  },\n  \"networks\": {\n    \"1583918911727\": {\n      \"events\": {},\n      \"links\": {},\n      \"address\": \"0xC89Ce4735882C9F0f0FE26686c53074E09B0D550\",\n      \"transactionHash\": \"0xc59b0daeb6b17beb9ea57bb0586fd626fb7b6f092d20bf22406168f7381ac949\"\n    }\n  },\n  \"schemaVersion\": \"3.0.19\",\n  \"updatedAt\": \"2020-03-11T13:47:51.887Z\",\n  \"networkType\": \"ethereum\",\n  \"devdoc\": {\n    \"methods\": {}\n  },\n  \"userdoc\": {\n    \"methods\": {}\n  }\n}"
  },
  {
    "path": "packages/fetchai/contracts/staking_erc20/build/staking_erc20.json",
    "content": "{\n  \"contractName\": \"Staking\",\n  \"abi\": [\n    {\n      \"inputs\": [\n        {\n          \"internalType\": \"address\",\n          \"name\": \"ERC20Address\",\n          \"type\": \"address\"\n        },\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"interestRatePerBlock\",\n          \"type\": \"uint256\"\n        },\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"pausedSinceBlock\",\n          \"type\": \"uint256\"\n        },\n        {\n          \"internalType\": \"uint64\",\n          \"name\": \"lockPeriodInBlocks\",\n          \"type\": \"uint64\"\n        }\n      ],\n      \"stateMutability\": \"nonpayable\",\n      \"type\": \"constructor\"\n    },\n    {\n      \"anonymous\": false,\n      \"inputs\": [\n        {\n          \"indexed\": true,\n          \"internalType\": \"address\",\n          \"name\": \"stakerAddress\",\n          \"type\": \"address\"\n        },\n        {\n          \"indexed\": true,\n          \"internalType\": \"uint256\",\n          \"name\": \"sinceInterestRateIndex\",\n          \"type\": \"uint256\"\n        },\n        {\n          \"indexed\": false,\n          \"internalType\": \"uint256\",\n          \"name\": \"principal\",\n          \"type\": \"uint256\"\n        },\n        {\n          \"indexed\": false,\n          \"internalType\": \"uint256\",\n          \"name\": \"compoundInterest\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"name\": \"BindStake\",\n      \"type\": \"event\"\n    },\n    {\n      \"anonymous\": false,\n      \"inputs\": [],\n      \"name\": \"DeleteContract\",\n      \"type\": \"event\"\n    },\n    {\n      \"anonymous\": false,\n      \"inputs\": [\n        {\n          \"indexed\": false,\n          \"internalType\": \"address\",\n          \"name\": \"targetAddress\",\n          \"type\": \"address\"\n        },\n        {\n          \"indexed\": false,\n          \"internalType\": \"uint256\",\n          \"name\": \"amount\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"name\": \"ExcessTokenWithdrawal\",\n      \"type\": \"event\"\n    },\n    {\n      \"anonymous\": false,\n      \"inputs\": [\n        {\n          \"indexed\": true,\n          \"internalType\": \"address\",\n          \"name\": \"stakerAddress\",\n          \"type\": \"address\"\n        },\n        {\n          \"indexed\": false,\n          \"internalType\": \"uint256\",\n          \"name\": \"amount\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"name\": \"LiquidityDeposited\",\n      \"type\": \"event\"\n    },\n    {\n      \"anonymous\": false,\n      \"inputs\": [\n        {\n          \"indexed\": true,\n          \"internalType\": \"address\",\n          \"name\": \"stakerAddress\",\n          \"type\": \"address\"\n        },\n        {\n          \"indexed\": false,\n          \"internalType\": \"uint256\",\n          \"name\": \"principal\",\n          \"type\": \"uint256\"\n        },\n        {\n          \"indexed\": false,\n          \"internalType\": \"uint256\",\n          \"name\": \"compoundInterest\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"name\": \"LiquidityUnlocked\",\n      \"type\": \"event\"\n    },\n    {\n      \"anonymous\": false,\n      \"inputs\": [\n        {\n          \"indexed\": false,\n          \"internalType\": \"uint64\",\n          \"name\": \"numOfBlocks\",\n          \"type\": \"uint64\"\n        }\n      ],\n      \"name\": \"LockPeriod\",\n      \"type\": \"event\"\n    },\n    {\n      \"anonymous\": false,\n      \"inputs\": [\n        {\n          \"indexed\": true,\n          \"internalType\": \"uint256\",\n          \"name\": \"index\",\n          \"type\": \"uint256\"\n        },\n        {\n          \"indexed\": false,\n          \"internalType\": \"uint256\",\n          \"name\": \"rate\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"name\": \"NewInterestRate\",\n      \"type\": \"event\"\n    },\n    {\n      \"anonymous\": false,\n      \"inputs\": [\n        {\n          \"indexed\": false,\n          \"internalType\": \"uint256\",\n          \"name\": \"sinceBlock\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"name\": \"Pause\",\n      \"type\": \"event\"\n    },\n    {\n      \"anonymous\": false,\n      \"inputs\": [\n        {\n          \"indexed\": false,\n          \"internalType\": \"address\",\n          \"name\": \"sender\",\n          \"type\": \"address\"\n        },\n        {\n          \"indexed\": false,\n          \"internalType\": \"uint256\",\n          \"name\": \"amount\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"name\": \"RewardsPoolTokenTopUp\",\n      \"type\": \"event\"\n    },\n    {\n      \"anonymous\": false,\n      \"inputs\": [\n        {\n          \"indexed\": false,\n          \"internalType\": \"address\",\n          \"name\": \"targetAddress\",\n          \"type\": \"address\"\n        },\n        {\n          \"indexed\": false,\n          \"internalType\": \"uint256\",\n          \"name\": \"amount\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"name\": \"RewardsPoolTokenWithdrawal\",\n      \"type\": \"event\"\n    },\n    {\n      \"anonymous\": false,\n      \"inputs\": [\n        {\n          \"indexed\": true,\n          \"internalType\": \"bytes32\",\n          \"name\": \"role\",\n          \"type\": \"bytes32\"\n        },\n        {\n          \"indexed\": true,\n          \"internalType\": \"bytes32\",\n          \"name\": \"previousAdminRole\",\n          \"type\": \"bytes32\"\n        },\n        {\n          \"indexed\": true,\n          \"internalType\": \"bytes32\",\n          \"name\": \"newAdminRole\",\n          \"type\": \"bytes32\"\n        }\n      ],\n      \"name\": \"RoleAdminChanged\",\n      \"type\": \"event\"\n    },\n    {\n      \"anonymous\": false,\n      \"inputs\": [\n        {\n          \"indexed\": true,\n          \"internalType\": \"bytes32\",\n          \"name\": \"role\",\n          \"type\": \"bytes32\"\n        },\n        {\n          \"indexed\": true,\n          \"internalType\": \"address\",\n          \"name\": \"account\",\n          \"type\": \"address\"\n        },\n        {\n          \"indexed\": true,\n          \"internalType\": \"address\",\n          \"name\": \"sender\",\n          \"type\": \"address\"\n        }\n      ],\n      \"name\": \"RoleGranted\",\n      \"type\": \"event\"\n    },\n    {\n      \"anonymous\": false,\n      \"inputs\": [\n        {\n          \"indexed\": true,\n          \"internalType\": \"bytes32\",\n          \"name\": \"role\",\n          \"type\": \"bytes32\"\n        },\n        {\n          \"indexed\": true,\n          \"internalType\": \"address\",\n          \"name\": \"account\",\n          \"type\": \"address\"\n        },\n        {\n          \"indexed\": true,\n          \"internalType\": \"address\",\n          \"name\": \"sender\",\n          \"type\": \"address\"\n        }\n      ],\n      \"name\": \"RoleRevoked\",\n      \"type\": \"event\"\n    },\n    {\n      \"anonymous\": false,\n      \"inputs\": [\n        {\n          \"indexed\": true,\n          \"internalType\": \"address\",\n          \"name\": \"stakerAddress\",\n          \"type\": \"address\"\n        },\n        {\n          \"indexed\": true,\n          \"internalType\": \"uint256\",\n          \"name\": \"sinceInterestRateIndex\",\n          \"type\": \"uint256\"\n        },\n        {\n          \"indexed\": false,\n          \"internalType\": \"uint256\",\n          \"name\": \"principal\",\n          \"type\": \"uint256\"\n        },\n        {\n          \"indexed\": false,\n          \"internalType\": \"uint256\",\n          \"name\": \"compoundInterest\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"name\": \"StakeCompoundInterest\",\n      \"type\": \"event\"\n    },\n    {\n      \"anonymous\": false,\n      \"inputs\": [\n        {\n          \"indexed\": false,\n          \"internalType\": \"address\",\n          \"name\": \"targetAddress\",\n          \"type\": \"address\"\n        },\n        {\n          \"indexed\": false,\n          \"internalType\": \"uint256\",\n          \"name\": \"amount\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"name\": \"TokenWithdrawal\",\n      \"type\": \"event\"\n    },\n    {\n      \"anonymous\": false,\n      \"inputs\": [\n        {\n          \"indexed\": true,\n          \"internalType\": \"address\",\n          \"name\": \"stakerAddress\",\n          \"type\": \"address\"\n        },\n        {\n          \"indexed\": true,\n          \"internalType\": \"uint256\",\n          \"name\": \"liquidSinceBlock\",\n          \"type\": \"uint256\"\n        },\n        {\n          \"indexed\": false,\n          \"internalType\": \"uint256\",\n          \"name\": \"principal\",\n          \"type\": \"uint256\"\n        },\n        {\n          \"indexed\": false,\n          \"internalType\": \"uint256\",\n          \"name\": \"compoundInterest\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"name\": \"UnbindStake\",\n      \"type\": \"event\"\n    },\n    {\n      \"anonymous\": false,\n      \"inputs\": [\n        {\n          \"indexed\": true,\n          \"internalType\": \"address\",\n          \"name\": \"stakerAddress\",\n          \"type\": \"address\"\n        },\n        {\n          \"indexed\": false,\n          \"internalType\": \"uint256\",\n          \"name\": \"principal\",\n          \"type\": \"uint256\"\n        },\n        {\n          \"indexed\": false,\n          \"internalType\": \"uint256\",\n          \"name\": \"compoundInterest\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"name\": \"Withdraw\",\n      \"type\": \"event\"\n    },\n    {\n      \"inputs\": [],\n      \"name\": \"DEFAULT_ADMIN_ROLE\",\n      \"outputs\": [\n        {\n          \"internalType\": \"bytes32\",\n          \"name\": \"\",\n          \"type\": \"bytes32\"\n        }\n      ],\n      \"stateMutability\": \"view\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [],\n      \"name\": \"DELEGATE_ROLE\",\n      \"outputs\": [\n        {\n          \"internalType\": \"bytes32\",\n          \"name\": \"\",\n          \"type\": \"bytes32\"\n        }\n      ],\n      \"stateMutability\": \"view\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [],\n      \"name\": \"DELETE_PROTECTION_PERIOD\",\n      \"outputs\": [\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"stateMutability\": \"view\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [],\n      \"name\": \"_accruedGlobalLiquidity\",\n      \"outputs\": [\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"principal\",\n          \"type\": \"uint256\"\n        },\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"compoundInterest\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"stateMutability\": \"view\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [],\n      \"name\": \"_accruedGlobalLocked\",\n      \"outputs\": [\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"principal\",\n          \"type\": \"uint256\"\n        },\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"compoundInterest\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"stateMutability\": \"view\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [],\n      \"name\": \"_accruedGlobalPrincipal\",\n      \"outputs\": [\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"stateMutability\": \"view\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [],\n      \"name\": \"_earliestDelete\",\n      \"outputs\": [\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"stateMutability\": \"view\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"name\": \"_interestRates\",\n      \"outputs\": [\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"sinceBlock\",\n          \"type\": \"uint256\"\n        },\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"rate\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"stateMutability\": \"view\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [],\n      \"name\": \"_interestRatesNextIdx\",\n      \"outputs\": [\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"stateMutability\": \"view\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [],\n      \"name\": \"_interestRatesStartIdx\",\n      \"outputs\": [\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"stateMutability\": \"view\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [\n        {\n          \"internalType\": \"address\",\n          \"name\": \"\",\n          \"type\": \"address\"\n        }\n      ],\n      \"name\": \"_liquidity\",\n      \"outputs\": [\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"principal\",\n          \"type\": \"uint256\"\n        },\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"compoundInterest\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"stateMutability\": \"view\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [],\n      \"name\": \"_lockPeriodInBlocks\",\n      \"outputs\": [\n        {\n          \"internalType\": \"uint64\",\n          \"name\": \"\",\n          \"type\": \"uint64\"\n        }\n      ],\n      \"stateMutability\": \"view\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [],\n      \"name\": \"_pausedSinceBlock\",\n      \"outputs\": [\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"stateMutability\": \"view\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [],\n      \"name\": \"_rewardsPoolBalance\",\n      \"outputs\": [\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"stateMutability\": \"view\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [],\n      \"name\": \"_token\",\n      \"outputs\": [\n        {\n          \"internalType\": \"contract IERC20\",\n          \"name\": \"\",\n          \"type\": \"address\"\n        }\n      ],\n      \"stateMutability\": \"view\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [\n        {\n          \"internalType\": \"bytes32\",\n          \"name\": \"role\",\n          \"type\": \"bytes32\"\n        }\n      ],\n      \"name\": \"getRoleAdmin\",\n      \"outputs\": [\n        {\n          \"internalType\": \"bytes32\",\n          \"name\": \"\",\n          \"type\": \"bytes32\"\n        }\n      ],\n      \"stateMutability\": \"view\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [\n        {\n          \"internalType\": \"bytes32\",\n          \"name\": \"role\",\n          \"type\": \"bytes32\"\n        },\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"index\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"name\": \"getRoleMember\",\n      \"outputs\": [\n        {\n          \"internalType\": \"address\",\n          \"name\": \"\",\n          \"type\": \"address\"\n        }\n      ],\n      \"stateMutability\": \"view\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [\n        {\n          \"internalType\": \"bytes32\",\n          \"name\": \"role\",\n          \"type\": \"bytes32\"\n        }\n      ],\n      \"name\": \"getRoleMemberCount\",\n      \"outputs\": [\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"stateMutability\": \"view\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [\n        {\n          \"internalType\": \"bytes32\",\n          \"name\": \"role\",\n          \"type\": \"bytes32\"\n        },\n        {\n          \"internalType\": \"address\",\n          \"name\": \"account\",\n          \"type\": \"address\"\n        }\n      ],\n      \"name\": \"grantRole\",\n      \"outputs\": [],\n      \"stateMutability\": \"nonpayable\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [\n        {\n          \"internalType\": \"bytes32\",\n          \"name\": \"role\",\n          \"type\": \"bytes32\"\n        },\n        {\n          \"internalType\": \"address\",\n          \"name\": \"account\",\n          \"type\": \"address\"\n        }\n      ],\n      \"name\": \"hasRole\",\n      \"outputs\": [\n        {\n          \"internalType\": \"bool\",\n          \"name\": \"\",\n          \"type\": \"bool\"\n        }\n      ],\n      \"stateMutability\": \"view\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [\n        {\n          \"internalType\": \"bytes32\",\n          \"name\": \"role\",\n          \"type\": \"bytes32\"\n        },\n        {\n          \"internalType\": \"address\",\n          \"name\": \"account\",\n          \"type\": \"address\"\n        }\n      ],\n      \"name\": \"renounceRole\",\n      \"outputs\": [],\n      \"stateMutability\": \"nonpayable\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [\n        {\n          \"internalType\": \"bytes32\",\n          \"name\": \"role\",\n          \"type\": \"bytes32\"\n        },\n        {\n          \"internalType\": \"address\",\n          \"name\": \"account\",\n          \"type\": \"address\"\n        }\n      ],\n      \"name\": \"revokeRole\",\n      \"outputs\": [],\n      \"stateMutability\": \"nonpayable\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"rate\",\n          \"type\": \"uint256\"\n        },\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"expirationBlock\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"name\": \"addInterestRate\",\n      \"outputs\": [],\n      \"stateMutability\": \"nonpayable\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"amount\",\n          \"type\": \"uint256\"\n        },\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"txExpirationBlock\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"name\": \"deposit\",\n      \"outputs\": [],\n      \"stateMutability\": \"nonpayable\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"amount\",\n          \"type\": \"uint256\"\n        },\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"txExpirationBlock\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"name\": \"withdraw\",\n      \"outputs\": [],\n      \"stateMutability\": \"nonpayable\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"txExpirationBlock\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"name\": \"withdrawPrincipal\",\n      \"outputs\": [],\n      \"stateMutability\": \"nonpayable\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"txExpirationBlock\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"name\": \"withdrawCompoundInterest\",\n      \"outputs\": [],\n      \"stateMutability\": \"nonpayable\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"txExpirationBlock\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"name\": \"withdrawWholeLiquidity\",\n      \"outputs\": [],\n      \"stateMutability\": \"nonpayable\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"amount\",\n          \"type\": \"uint256\"\n        },\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"txExpirationBlock\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"name\": \"bindStake\",\n      \"outputs\": [],\n      \"stateMutability\": \"nonpayable\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"amount\",\n          \"type\": \"uint256\"\n        },\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"txExpirationBlock\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"name\": \"unbindStake\",\n      \"outputs\": [],\n      \"stateMutability\": \"nonpayable\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [],\n      \"name\": \"getRewardsPoolBalance\",\n      \"outputs\": [\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"stateMutability\": \"view\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [],\n      \"name\": \"getEarliestDeleteBlock\",\n      \"outputs\": [\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"stateMutability\": \"view\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [\n        {\n          \"internalType\": \"address\",\n          \"name\": \"forAddress\",\n          \"type\": \"address\"\n        }\n      ],\n      \"name\": \"getNumberOfLockedAssetsForUser\",\n      \"outputs\": [\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"length\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"stateMutability\": \"view\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [\n        {\n          \"internalType\": \"address\",\n          \"name\": \"forAddress\",\n          \"type\": \"address\"\n        }\n      ],\n      \"name\": \"getLockedAssetsAggregateForUser\",\n      \"outputs\": [\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"principal\",\n          \"type\": \"uint256\"\n        },\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"compoundInterest\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"stateMutability\": \"view\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [\n        {\n          \"internalType\": \"address\",\n          \"name\": \"forAddress\",\n          \"type\": \"address\"\n        }\n      ],\n      \"name\": \"getLockedAssetsForUser\",\n      \"outputs\": [\n        {\n          \"internalType\": \"uint256[]\",\n          \"name\": \"principal\",\n          \"type\": \"uint256[]\"\n        },\n        {\n          \"internalType\": \"uint256[]\",\n          \"name\": \"compoundInterest\",\n          \"type\": \"uint256[]\"\n        },\n        {\n          \"internalType\": \"uint256[]\",\n          \"name\": \"liquidSinceBlock\",\n          \"type\": \"uint256[]\"\n        }\n      ],\n      \"stateMutability\": \"view\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [\n        {\n          \"internalType\": \"address\",\n          \"name\": \"forAddress\",\n          \"type\": \"address\"\n        }\n      ],\n      \"name\": \"getStakeForUser\",\n      \"outputs\": [\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"principal\",\n          \"type\": \"uint256\"\n        },\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"compoundInterest\",\n          \"type\": \"uint256\"\n        },\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"sinceBlock\",\n          \"type\": \"uint256\"\n        },\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"sinceInterestRateIndex\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"stateMutability\": \"view\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"amount\",\n          \"type\": \"uint256\"\n        },\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"txExpirationBlock\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"name\": \"topUpRewardsPool\",\n      \"outputs\": [],\n      \"stateMutability\": \"nonpayable\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [\n        {\n          \"internalType\": \"uint64\",\n          \"name\": \"numOfBlocks\",\n          \"type\": \"uint64\"\n        },\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"txExpirationBlock\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"name\": \"updateLockPeriod\",\n      \"outputs\": [],\n      \"stateMutability\": \"nonpayable\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"blockNumber\",\n          \"type\": \"uint256\"\n        },\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"txExpirationBlock\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"name\": \"pauseSince\",\n      \"outputs\": [],\n      \"stateMutability\": \"nonpayable\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"amount\",\n          \"type\": \"uint256\"\n        },\n        {\n          \"internalType\": \"address payable\",\n          \"name\": \"targetAddress\",\n          \"type\": \"address\"\n        },\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"txExpirationBlock\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"name\": \"withdrawFromRewardsPool\",\n      \"outputs\": [],\n      \"stateMutability\": \"nonpayable\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [\n        {\n          \"internalType\": \"address payable\",\n          \"name\": \"targetAddress\",\n          \"type\": \"address\"\n        },\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"txExpirationBlock\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"name\": \"withdrawExcessTokens\",\n      \"outputs\": [],\n      \"stateMutability\": \"nonpayable\",\n      \"type\": \"function\"\n    },\n    {\n      \"inputs\": [\n        {\n          \"internalType\": \"address payable\",\n          \"name\": \"payoutAddress\",\n          \"type\": \"address\"\n        },\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"txExpirationBlock\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"name\": \"deleteContract\",\n      \"outputs\": [],\n      \"stateMutability\": \"nonpayable\",\n      \"type\": \"function\"\n    }\n  ],\n  \"metadata\": \"{\\\"compiler\\\":{\\\"version\\\":\\\"0.6.8+commit.0bbfe453\\\"},\\\"language\\\":\\\"Solidity\\\",\\\"output\\\":{\\\"abi\\\":[{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"ERC20Address\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"interestRatePerBlock\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"pausedSinceBlock\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"uint64\\\",\\\"name\\\":\\\"lockPeriodInBlocks\\\",\\\"type\\\":\\\"uint64\\\"}],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"constructor\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"stakerAddress\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":true,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"sinceInterestRateIndex\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"principal\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"compoundInterest\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"BindStake\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[],\\\"name\\\":\\\"DeleteContract\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":false,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"targetAddress\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"amount\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"ExcessTokenWithdrawal\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"stakerAddress\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"amount\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"LiquidityDeposited\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"stakerAddress\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"principal\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"compoundInterest\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"LiquidityUnlocked\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint64\\\",\\\"name\\\":\\\"numOfBlocks\\\",\\\"type\\\":\\\"uint64\\\"}],\\\"name\\\":\\\"LockPeriod\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":true,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"index\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"rate\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"NewInterestRate\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"sinceBlock\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"Pause\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":false,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"sender\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"amount\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"RewardsPoolTokenTopUp\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":false,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"targetAddress\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"amount\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"RewardsPoolTokenWithdrawal\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":true,\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"role\\\",\\\"type\\\":\\\"bytes32\\\"},{\\\"indexed\\\":true,\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"previousAdminRole\\\",\\\"type\\\":\\\"bytes32\\\"},{\\\"indexed\\\":true,\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"newAdminRole\\\",\\\"type\\\":\\\"bytes32\\\"}],\\\"name\\\":\\\"RoleAdminChanged\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":true,\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"role\\\",\\\"type\\\":\\\"bytes32\\\"},{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"account\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"sender\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"RoleGranted\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":true,\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"role\\\",\\\"type\\\":\\\"bytes32\\\"},{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"account\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"sender\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"RoleRevoked\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"stakerAddress\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":true,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"sinceInterestRateIndex\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"principal\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"compoundInterest\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"StakeCompoundInterest\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":false,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"targetAddress\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"amount\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"TokenWithdrawal\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"stakerAddress\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":true,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"liquidSinceBlock\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"principal\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"compoundInterest\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"UnbindStake\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"stakerAddress\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"principal\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"compoundInterest\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"Withdraw\\\",\\\"type\\\":\\\"event\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"DEFAULT_ADMIN_ROLE\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"bytes32\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"DELEGATE_ROLE\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"bytes32\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"DELETE_PROTECTION_PERIOD\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"_accruedGlobalLiquidity\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"principal\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"compoundInterest\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"_accruedGlobalLocked\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"principal\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"compoundInterest\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"_accruedGlobalPrincipal\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"_earliestDelete\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"_interestRates\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"sinceBlock\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"rate\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"_interestRatesNextIdx\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"_interestRatesStartIdx\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"_liquidity\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"principal\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"compoundInterest\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"_lockPeriodInBlocks\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint64\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint64\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"_pausedSinceBlock\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"_rewardsPoolBalance\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"_token\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"contract IERC20\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"address\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"rate\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"expirationBlock\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"addInterestRate\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"amount\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"txExpirationBlock\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"bindStake\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address payable\\\",\\\"name\\\":\\\"payoutAddress\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"txExpirationBlock\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"deleteContract\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"amount\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"txExpirationBlock\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"deposit\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"getEarliestDeleteBlock\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"forAddress\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"getLockedAssetsAggregateForUser\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"principal\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"compoundInterest\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"forAddress\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"getLockedAssetsForUser\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256[]\\\",\\\"name\\\":\\\"principal\\\",\\\"type\\\":\\\"uint256[]\\\"},{\\\"internalType\\\":\\\"uint256[]\\\",\\\"name\\\":\\\"compoundInterest\\\",\\\"type\\\":\\\"uint256[]\\\"},{\\\"internalType\\\":\\\"uint256[]\\\",\\\"name\\\":\\\"liquidSinceBlock\\\",\\\"type\\\":\\\"uint256[]\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"forAddress\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"getNumberOfLockedAssetsForUser\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"length\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"getRewardsPoolBalance\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"role\\\",\\\"type\\\":\\\"bytes32\\\"}],\\\"name\\\":\\\"getRoleAdmin\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"bytes32\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"role\\\",\\\"type\\\":\\\"bytes32\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"index\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"getRoleMember\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"address\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"role\\\",\\\"type\\\":\\\"bytes32\\\"}],\\\"name\\\":\\\"getRoleMemberCount\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"forAddress\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"getStakeForUser\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"principal\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"compoundInterest\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"sinceBlock\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"sinceInterestRateIndex\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"role\\\",\\\"type\\\":\\\"bytes32\\\"},{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"account\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"grantRole\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"role\\\",\\\"type\\\":\\\"bytes32\\\"},{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"account\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"hasRole\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"bool\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"bool\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"blockNumber\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"txExpirationBlock\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"pauseSince\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"role\\\",\\\"type\\\":\\\"bytes32\\\"},{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"account\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"renounceRole\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"role\\\",\\\"type\\\":\\\"bytes32\\\"},{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"account\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"revokeRole\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"amount\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"txExpirationBlock\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"topUpRewardsPool\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"amount\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"txExpirationBlock\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"unbindStake\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"uint64\\\",\\\"name\\\":\\\"numOfBlocks\\\",\\\"type\\\":\\\"uint64\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"txExpirationBlock\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"updateLockPeriod\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"amount\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"txExpirationBlock\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"withdraw\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"txExpirationBlock\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"withdrawCompoundInterest\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address payable\\\",\\\"name\\\":\\\"targetAddress\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"txExpirationBlock\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"withdrawExcessTokens\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"amount\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"address payable\\\",\\\"name\\\":\\\"targetAddress\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"txExpirationBlock\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"withdrawFromRewardsPool\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"txExpirationBlock\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"withdrawPrincipal\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"txExpirationBlock\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"withdrawWholeLiquidity\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"}],\\\"devdoc\\\":{\\\"methods\\\":{\\\"addInterestRate(uint256,uint256)\\\":{\\\"details\\\":\\\"expiration period\\\",\\\"params\\\":{\\\"expirationBlock\\\":\\\"- block number beyond which is the carrier Tx considered expired, and so rejected.                    This is for protection of Tx sender to exactly define lifecycle length of the Tx,                    and so avoiding uncertainty of how long Tx sender needs to wait for Tx processing.                    Tx can be withheld\\\",\\\"rate\\\":\\\"- signed interest rate value in [10**18] units => real_rate [1] = rate [10**18] / 10**18\\\"}},\\\"constructor\\\":{\\\"params\\\":{\\\"ERC20Address\\\":\\\"address of the ERC20 contract\\\"}},\\\"deleteContract(address,uint256)\\\":{\\\"details\\\":\\\"owner only + only on or after `_earliestDelete` block\\\",\\\"params\\\":{\\\"payoutAddress\\\":\\\"address to transfer the balances to. Ensure that this is able to handle ERC20 tokens\\\"}},\\\"getLockedAssetsForUser(address)\\\":{\\\"details\\\":\\\"Returns locked assets decomposed in to 3 separate arrays (principal, compound interest, liquid since block)     NOTE(pb): This method might be quite expensive, depending on size of locked assets\\\"},\\\"getRoleAdmin(bytes32)\\\":{\\\"details\\\":\\\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}.     * To change a role's admin, use {_setRoleAdmin}.\\\"},\\\"getRoleMember(bytes32,uint256)\\\":{\\\"details\\\":\\\"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive.     * Role bearers are not sorted in any particular way, and their ordering may change at any point.     * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information.\\\"},\\\"getRoleMemberCount(bytes32)\\\":{\\\"details\\\":\\\"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role.\\\"},\\\"grantRole(bytes32,address)\\\":{\\\"details\\\":\\\"Grants `role` to `account`.     * If `account` had not been already granted `role`, emits a {RoleGranted} event.     * Requirements:     * - the caller must have ``role``'s admin role.\\\"},\\\"hasRole(bytes32,address)\\\":{\\\"details\\\":\\\"Returns `true` if `account` has been granted `role`.\\\"},\\\"pauseSince(uint256,uint256)\\\":{\\\"details\\\":\\\"Delegate only\\\",\\\"params\\\":{\\\"blockNumber\\\":\\\"block number since which non-admin interaction will be paused (for all _getBlockNumber() >= blockNumber)\\\"}},\\\"renounceRole(bytes32,address)\\\":{\\\"details\\\":\\\"Revokes `role` from the calling account.     * Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced).     * If the calling account had been granted `role`, emits a {RoleRevoked} event.     * Requirements:     * - the caller must be `account`.\\\"},\\\"revokeRole(bytes32,address)\\\":{\\\"details\\\":\\\"Revokes `role` from `account`.     * If `account` had been granted `role`, emits a {RoleRevoked} event.     * Requirements:     * - the caller must have ``role``'s admin role.\\\"},\\\"topUpRewardsPool(uint256,uint256)\\\":{\\\"details\\\":\\\"Even though this is considered as administrative action (is not affected by by contract paused state, it can be executed by anyone who wishes to top-up the rewards pool (funds are sent in to contract, *not* the other way around). The Rewards Pool is exclusively dedicated to cover withdrawals of user' compound interest, which is effectively the reward.\\\"},\\\"unbindStake(uint256,uint256)\\\":{\\\"details\\\":\\\"public access\\\",\\\"params\\\":{\\\"amount\\\":\\\"- value to un-bind from the stake                If `amount=0` then the **WHOLE** stake (including                compound interest) will be unbound.\\\"}},\\\"updateLockPeriod(uint64,uint256)\\\":{\\\"details\\\":\\\"Delegate only\\\",\\\"params\\\":{\\\"numOfBlocks\\\":\\\"length of the lock period\\\"}},\\\"withdraw(uint256,uint256)\\\":{\\\"details\\\":\\\"public access\\\",\\\"params\\\":{\\\"amount\\\":\\\"- value to withdraw\\\"}},\\\"withdrawCompoundInterest(uint256)\\\":{\\\"details\\\":\\\"public access\\\"},\\\"withdrawExcessTokens(address,uint256)\\\":{\\\"details\\\":\\\"Withdraw \\\\\\\"excess\\\\\\\" tokens, which were sent to contract directly via direct ERC20.transfer(...),     without interacting with API of this (Staking) contract, what could be done only by mistake.     Thus this method is meant to be used primarily for rescue purposes, enabling withdrawal of such     \\\\\\\"excess\\\\\\\" tokens out of contract.\\\",\\\"params\\\":{\\\"targetAddress\\\":\\\": address to send tokens to\\\",\\\"txExpirationBlock\\\":\\\": block number until which is the transaction valid (inclusive).                           When transaction is processed after this block, it fails.\\\"}},\\\"withdrawFromRewardsPool(uint256,address,uint256)\\\":{\\\"details\\\":\\\"Withdraw tokens from rewards pool.\\\",\\\"params\\\":{\\\"amount\\\":\\\": amount to withdraw.                If `amount == 0` then whole amount in rewards pool will be withdrawn.\\\",\\\"targetAddress\\\":\\\": address to send tokens to\\\"}},\\\"withdrawPrincipal(uint256)\\\":{\\\"details\\\":\\\"public access\\\"},\\\"withdrawWholeLiquidity(uint256)\\\":{\\\"details\\\":\\\"public access\\\"}}},\\\"userdoc\\\":{\\\"methods\\\":{\\\"addInterestRate(uint256,uint256)\\\":{\\\"notice\\\":\\\"Add new interest rate in to the ordered container of previously added interest rates\\\"},\\\"deleteContract(address,uint256)\\\":{\\\"notice\\\":\\\"Delete the contract, transfers the remaining token and ether balance to the specified payoutAddress\\\"},\\\"pauseSince(uint256,uint256)\\\":{\\\"notice\\\":\\\"Pauses all NON-administrative interaction with the contract since the specidfed block number \\\"},\\\"unbindStake(uint256,uint256)\\\":{\\\"notice\\\":\\\"Unbinds amount from the stake of sender of the transaction,        and *LOCKS* it for number of blocks defined by value of the        `_lockPeriodInBlocks` state of this contract at the point        of this call.        The locked amount can *NOT* be withdrawn from the contract        *BEFORE* the lock period ends.     *         Unbinding (=calling this method) also means, that compound        interest will be calculated for period since la.\\\"},\\\"updateLockPeriod(uint64,uint256)\\\":{\\\"notice\\\":\\\"Updates Lock Period value\\\"},\\\"withdraw(uint256,uint256)\\\":{\\\"notice\\\":\\\"Withdraws amount from sender' available liquidity pool back to sender address,        preferring withdrawal from compound interest dimension of liquidity.\\\"},\\\"withdrawCompoundInterest(uint256)\\\":{\\\"notice\\\":\\\"Withdraws *WHOLE* compound interest amount available to sender.\\\"},\\\"withdrawPrincipal(uint256)\\\":{\\\"notice\\\":\\\"Withdraws *WHOLE* compound interest amount available to sender.\\\"},\\\"withdrawWholeLiquidity(uint256)\\\":{\\\"notice\\\":\\\"Withdraws whole liquidity available to sender back to sender' address,\\\"}}}},\\\"settings\\\":{\\\"compilationTarget\\\":{\\\"/Users/pb/code/fetch/cosmos/ledger-staking-contract/contracts/Staking.sol\\\":\\\"Staking\\\"},\\\"evmVersion\\\":\\\"istanbul\\\",\\\"libraries\\\":{},\\\"metadata\\\":{\\\"bytecodeHash\\\":\\\"ipfs\\\"},\\\"optimizer\\\":{\\\"enabled\\\":true,\\\"runs\\\":200},\\\"remappings\\\":[]},\\\"sources\\\":{\\\"/Users/pb/code/fetch/cosmos/ledger-staking-contract/abdk-libraries/ABDKMath64x64.sol\\\":{\\\"keccak256\\\":\\\"0x67609bc0923563d05d3a8a7c681056f9702a92120777cb0bcbb40d0afbb4a015\\\",\\\"license\\\":\\\"BSD-4-Clause\\\",\\\"urls\\\":[\\\"bzz-raw://55e817969394d4e0201a8cd3763ad6776bc9fddc986febe9b4acf120e8b7ad0d\\\",\\\"dweb:/ipfs/QmNMve5ZjUfA8DJYic4sYTrDEAN6VyxcC7jWUTX25Wmnnp\\\"]},\\\"/Users/pb/code/fetch/cosmos/ledger-staking-contract/contracts/AssetLib.sol\\\":{\\\"keccak256\\\":\\\"0x627891fef396f63fae2a38078dd28861689cac7e2d50286eaddf6b9a1109376a\\\",\\\"license\\\":\\\"Apache-2.0\\\",\\\"urls\\\":[\\\"bzz-raw://e187942e72c2ed510626977753274ead2201b9a6655bbebac608964837d91d49\\\",\\\"dweb:/ipfs/QmTiUziuoAVEo2twWu9qydMKuwKUHW4WojQxweJGnUTDgM\\\"]},\\\"/Users/pb/code/fetch/cosmos/ledger-staking-contract/contracts/Finance.sol\\\":{\\\"keccak256\\\":\\\"0x1295bbe45c79971d2f7228e9ab5ce2b6563aec12cff2539704a2a5f69433225f\\\",\\\"license\\\":\\\"Apache-2.0\\\",\\\"urls\\\":[\\\"bzz-raw://85de9e0ddb40020077f653f294cf9cbcffeb276fa82702e210805396c08c2698\\\",\\\"dweb:/ipfs/QmeqoWfLk21PN5ebnLbp58GifGsrheksRPYqKFmLyd1P97\\\"]},\\\"/Users/pb/code/fetch/cosmos/ledger-staking-contract/contracts/Staking.sol\\\":{\\\"keccak256\\\":\\\"0x53912db09c77d22c3a3880515ac7e9effb7d820598f27bddb970a10a8c95c92c\\\",\\\"license\\\":\\\"Apache-2.0\\\",\\\"urls\\\":[\\\"bzz-raw://ddf0503ac09a8af192e946efb3248600e3cf71e6cd0c5ad68842380c332eaf60\\\",\\\"dweb:/ipfs/QmbbJ18e8MRoU1C3L59YnVHCoKfd1mgeCoYjQArmF25JQA\\\"]},\\\"/Users/pb/code/fetch/cosmos/ledger-staking-contract/openzeppelin/contracts/GSN/Context.sol\\\":{\\\"keccak256\\\":\\\"0xdb26cbf4d028490f49831a7865c2fe1b28db44b535ca8d343785a3b768aae183\\\",\\\"license\\\":\\\"MIT\\\",\\\"urls\\\":[\\\"bzz-raw://840b14ce0315c47d49ba328f1f9fa7654ded1c9e1559e6c5e777a7b2dc28bf0a\\\",\\\"dweb:/ipfs/QmTLLabn4wcfGro9LEmUXUN2nwKqZSotXMvjDCLXEnLtZP\\\"]},\\\"/Users/pb/code/fetch/cosmos/ledger-staking-contract/openzeppelin/contracts/access/AccessControl.sol\\\":{\\\"keccak256\\\":\\\"0x92f7900d382761c7faefeaced81c6b4f1aae909ed0551803bfe8f27101956360\\\",\\\"license\\\":\\\"MIT\\\",\\\"urls\\\":[\\\"bzz-raw://407c0864143968542e5cf5aa7556916d2cf292b201e3dadb65662e9a3aa24187\\\",\\\"dweb:/ipfs/QmSnXzYAUaGLGr7uofRbgQraTJvatbjQLBPhyYiMd18oUJ\\\"]},\\\"/Users/pb/code/fetch/cosmos/ledger-staking-contract/openzeppelin/contracts/math/SafeMath.sol\\\":{\\\"keccak256\\\":\\\"0x9a9cf02622cd7a64261b10534fc3260449da25c98c9e96d1b4ae8110a20e5806\\\",\\\"license\\\":\\\"MIT\\\",\\\"urls\\\":[\\\"bzz-raw://2df142592d1dc267d9549049ee3317fa190d2f87eaa565f86ab05ec83f7ab8f5\\\",\\\"dweb:/ipfs/QmSkJtcfWo7c42KnL5hho6GFxK6HRNV91XABx1P7xDtfLV\\\"]},\\\"/Users/pb/code/fetch/cosmos/ledger-staking-contract/openzeppelin/contracts/token/ERC20/IERC20.sol\\\":{\\\"keccak256\\\":\\\"0x5c26b39d26f7ed489e555d955dcd3e01872972e71fdd1528e93ec164e4f23385\\\",\\\"license\\\":\\\"MIT\\\",\\\"urls\\\":[\\\"bzz-raw://efdc632af6960cf865dbc113665ea1f5b90eab75cc40ec062b2f6ae6da582017\\\",\\\"dweb:/ipfs/QmfAZFDuG62vxmAN9DnXApv7e7PMzPqi4RkqqZHLMSQiY5\\\"]},\\\"/Users/pb/code/fetch/cosmos/ledger-staking-contract/openzeppelin/contracts/utils/Address.sol\\\":{\\\"keccak256\\\":\\\"0xdfb4f812600ba4ce6738c35584ceb8c9433472583051b48ba5b1f66cb758a498\\\",\\\"license\\\":\\\"MIT\\\",\\\"urls\\\":[\\\"bzz-raw://df02dffe1c1de089d9b4f6192f0dcf464526f2230f420b3deec4645e0cdd2bff\\\",\\\"dweb:/ipfs/QmcqXGAU3KJqwrgUVoGJ2W8osomhSJ4R5kdsRpbuW3fELS\\\"]},\\\"/Users/pb/code/fetch/cosmos/ledger-staking-contract/openzeppelin/contracts/utils/EnumerableSet.sol\\\":{\\\"keccak256\\\":\\\"0xb2a11b236f073662f5a196995863f51c11d006bf7c3de158b316dfa1506c4b79\\\",\\\"license\\\":\\\"MIT\\\",\\\"urls\\\":[\\\"bzz-raw://8651649cf0b9efa18c3b01c030276fa320d41adbdc286833417e7f36e357b2f3\\\",\\\"dweb:/ipfs/QmafhM2Nd1aP43QVB1eRRZaqRXQKswNfQcWi8U8xjrxCfN\\\"]}},\\\"version\\\":1}\",\n  \"bytecode\": \"0x60806040523480156200001157600080fd5b506040516200391838038062003918833981810160405260808110156200003757600080fd5b5080516020820151604083015160609093015191929091620000646000336001600160e01b03620000ee16565b600180546001600160a01b0319166001600160a01b038616179055620000a56205a66d6200009162000107565b6200010b60201b620023d81790919060201c565b600255620000bc816001600160e01b036200016f16565b620000d0836001600160e01b03620001c316565b620000e4826001600160e01b036200025f16565b50505050620003d8565b6200010382826001600160e01b03620002c216565b5050565b4390565b60008282018381101562000166576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b90505b92915050565b600480546001600160401b0383166001600160401b0319909116811790915560408051918252517f6b24ea7c7a8ce7fd2e6a6cb675dbabcd38a90f83ddd581c4435610ce90456e8f9181900360200190a150565b600c546040805180820190915280620001e46001600160e01b036200010716565b815260209081018490526000838152600d8252604090208251815591810151600192830155600c5462000222929091620023d86200010b821b17901c565b600c5560408051838152905182917fbcd200f406c53d9438c6cdc2966a1e99c35f336588c95bc3639e539df21c2f53919081900360200190a25050565b6000620002746001600160e01b036200010716565b905080821062000285578162000287565b805b600381905560408051918252517f68b095021b1f40fe513109f513c66692f0b3219aee674a69f4efc57badb8201d9181900360200190a15050565b600082815260208181526040909120620002e79183906200243262000344821b17901c565b156200010357620003006001600160e01b036200036416565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b600062000166836001600160a01b0384166001600160e01b036200036816565b3390565b60006200037f83836001600160e01b03620003c016565b620003b75750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562000169565b50600062000169565b60009081526001919091016020526040902054151590565b61353080620003e86000396000f3fe608060405234801561001057600080fd5b506004361061025e5760003560e01c80639010d07c11610146578063c8984ab2116100c3578063d9d8e78311610087578063d9d8e783146107bf578063dca2aa5c146107c7578063e2bbb158146107e4578063ecd0c0c314610807578063f0895e521461080f578063f1209ef71461083c5761025e565b8063c8984ab214610749578063ca15c87314610751578063d547741f1461076e578063d8cd39991461079a578063d9b202c9146107b75761025e565b8063aa700ff21161010a578063aa700ff2146106ad578063adf55101146106ca578063ba92a4c5146106d2578063c0ba241b146106f5578063c30f75cf146106fd5761025e565b80639010d07c146105d457806391d14854146106135780639608df4b14610653578063a217fddf1461067f578063a8f1b4c4146106875761025e565b8063372646bb116101df57806353e052ac116101a357806353e052ac146103f35780635f208f341461041f578063658e28a41461052357806367ce50c01461054057806368bccfcf1461057f57806388cedd5e146105b15761025e565b8063372646bb1461037757806340e979031461037f5780634164b001146103a5578063441a3e70146103ad57806352885d8d146103d05761025e565b8063292911fb11610226578063292911fb146102ec5780632f2ff15d146102f457806332a1bd7014610320578063347908df1461032857806336568abe1461034b5761025e565b8063085313ec146102635780630c450f9d1461027d5780631338403914610285578063248a9ca3146102aa5780632514c50a146102c7575b600080fd5b61026b610844565b60408051918252519081900360200190f35b61026b61084b565b6102a86004803603604081101561029b57600080fd5b5080359060200135610851565b005b61026b600480360360208110156102c057600080fd5b503561091f565b6102cf610934565b6040805167ffffffffffffffff9092168252519081900360200190f35b61026b610944565b6102a86004803603604081101561030a57600080fd5b50803590602001356001600160a01b031661094a565b61026b6109b6565b6102a86004803603604081101561033e57600080fd5b50803590602001356109bc565b6102a86004803603604081101561036157600080fd5b50803590602001356001600160a01b0316610a85565b61026b610ae6565b61026b6004803603602081101561039557600080fd5b50356001600160a01b0316610aed565b61026b610b0b565b6102a8600480360360408110156103c357600080fd5b5080359060200135610b11565b6102a8600480360360408110156103e657600080fd5b5080359060200135610bf2565b6102a86004803603604081101561040957600080fd5b506001600160a01b03813516906020013561108b565b6104456004803603602081101561043557600080fd5b50356001600160a01b03166112ef565b60405180806020018060200180602001848103845287818151815260200191508051906020019060200280838360005b8381101561048d578181015183820152602001610475565b50505050905001848103835286818151815260200191508051906020019060200280838360005b838110156104cc5781810151838201526020016104b4565b50505050905001848103825285818151815260200191508051906020019060200280838360005b8381101561050b5781810151838201526020016104f3565b50505050905001965050505050505060405180910390f35b6102a86004803603602081101561053957600080fd5b5035611482565b6105666004803603602081101561055657600080fd5b50356001600160a01b031661155b565b6040805192835260208301919091528051918290030190f35b6102a86004803603606081101561059557600080fd5b508035906001600160a01b036020820135169060400135611574565b6102a8600480360360408110156105c757600080fd5b5080359060200135611886565b6105f7600480360360408110156105ea57600080fd5b5080359060200135611a15565b604080516001600160a01b039092168252519081900360200190f35b61063f6004803603604081101561062957600080fd5b50803590602001356001600160a01b0316611a3c565b604080519115158252519081900360200190f35b6102a86004803603604081101561066957600080fd5b506001600160a01b038135169060200135611a5a565b61026b611c8e565b6105666004803603602081101561069d57600080fd5b50356001600160a01b0316611c93565b610566600480360360208110156106c357600080fd5b5035611cb6565b61026b611ccf565b6102a8600480360360408110156106e857600080fd5b5080359060200135611cd5565b61026b611e49565b6107236004803603602081101561071357600080fd5b50356001600160a01b0316611e6e565b604080519485526020850193909352838301919091526060830152519081900360800190f35b610566611e9f565b61026b6004803603602081101561076757600080fd5b5035611ea8565b6102a86004803603604081101561078457600080fd5b50803590602001356001600160a01b0316611ebf565b6102a8600480360360208110156107b057600080fd5b5035611f18565b610566611ff2565b61026b611ffb565b6102a8600480360360208110156107dd57600080fd5b5035612001565b6102a8600480360360408110156107fa57600080fd5b50803590602001356120f2565b6105f76122fa565b6102a86004803603604081101561082557600080fd5b5067ffffffffffffffff8135169060200135612309565b61026b6123d2565b6002545b90565b60055481565b610859612447565b8061088b5750604080516c44454c45474154455f524f4c4560981b8152905190819003600d01902061088b9033611a3c565b6108c65760405162461bcd60e51b81526004018080602001828103825260248152602001806134186024913960400191505060405180910390fd5b80806108d0612458565b1115610911576040805162461bcd60e51b8152602060048201526013602482015260008051602061346c833981519152604482015290519081900360640190fd5b61091a8361245c565b505050565b60009081526020819052604090206002015490565b60045467ffffffffffffffff1681565b60065481565b60008281526020819052604090206002015461096d906109686124e5565b611a3c565b6109a85760405162461bcd60e51b815260040180806020018281038252602f8152602001806133e9602f913960400191505060405180910390fd5b6109b282826124e9565b5050565b60025481565b80806109c6612458565b1115610a07576040805162461bcd60e51b8152602060048201526013602482015260008051602061346c833981519152604482015290519081900360640190fd5b610a0f612447565b80610a415750604080516c44454c45474154455f524f4c4560981b8152905190819003600d019020610a419033611a3c565b610a7c5760405162461bcd60e51b81526004018080602001828103825260248152602001806134186024913960400191505060405180910390fd5b61091a83612558565b610a8d6124e5565b6001600160a01b0316816001600160a01b031614610adc5760405162461bcd60e51b815260040180806020018281038252602f8152602001806134cc602f913960400191505060405180910390fd5b6109b282826125ae565b6205a66d81565b6001600160a01b03166000908152600f602052604090206002015490565b600c5481565b8080610b1b612458565b1115610b5c576040805162461bcd60e51b8152602060048201526013602482015260008051602061346c833981519152604482015290519081900360640190fd5b610b64612458565b60035411610ba7576040805162461bcd60e51b815260206004820152601860248201526000805160206134ac833981519152604482015290519081900360640190fd5b336000610bb2612458565b90506000610bc0838361261d565b50915050610bcc61333e565b610bdc828863ffffffff61287b16565b9050610be98482896128f4565b50505050505050565b8080610bfc612458565b1115610c3d576040805162461bcd60e51b8152602060048201526013602482015260008051602061346c833981519152604482015290519081900360640190fd5b610c45612458565b60035411610c88576040805162461bcd60e51b815260206004820152601860248201526000805160206134ac833981519152604482015290519081900360640190fd5b6000610c92612458565b9050336000610ca18284612aa1565b90506000610cb182600201612c1a565b9050610cbb61333e565b8715610ebd5781881115610d16576040805162461bcd60e51b815260206004820152601b60248201527f416d6f756e7420697320686967686572207468616e207374616b650000000000604482015290519081900360640190fd5b60045467ffffffffffffffff16610dee576001600160a01b0384166000908152601060205260409020610d549060028501908a63ffffffff612c3416565b9050610d6760078263ffffffff612c5916565b80516020808301516040805193845291830152805187926001600160a01b0388169260008051602061348c83398151915292918290030190a38051602080830151604080519384529183015280516001600160a01b038716927fa219ed960eef85ed4cd072d3a9f240ea94727c0d6fb15e9a91a8cd4bf18ee3a692908290030190a2610eb8565b6001600160a01b0384166000908152600f6020908152604082206002810180546001810182559084529190922060045460039092020190610e4090889067ffffffffffffffff1663ffffffff6123d816565b8155610e5960028601600183018c63ffffffff612c3416565b9250610e6c60098463ffffffff612c5916565b610e7c828463ffffffff612c5916565b80548351602080860151604080519384529183015280516001600160a01b038a169260008051602061348c83398151915292908290030190a350505b611081565b81610ecc57505050505061091a565b5060408051808201909152600283018054825260038401805460208401526000918290555560045467ffffffffffffffff16610fc2576001600160a01b0384166000908152601060205260409020610f2a908263ffffffff612c5916565b610f3b60078263ffffffff612c5916565b80516020808301516040805193845291830152805187926001600160a01b0388169260008051602061348c83398151915292918290030190a38051602080830151604080519384529183015280516001600160a01b038716927fa219ed960eef85ed4cd072d3a9f240ea94727c0d6fb15e9a91a8cd4bf18ee3a692908290030190a2611081565b6001600160a01b0384166000908152600f602090815260408220600281018054600181018255908452919092206004546003909202019061101490889067ffffffffffffffff1663ffffffff6123d816565b8155825160018201556020830151600282015561103860098463ffffffff612c5916565b611048828463ffffffff612c5916565b8054600182015460028301546040805192835260208301919091528051339260008051602061348c83398151915292908290030190a350505b5050505050505050565b8080611095612458565b11156110d6576040805162461bcd60e51b8152602060048201526013602482015260008051602061346c833981519152604482015290519081900360640190fd5b6110de612447565b611128576040805162461bcd60e51b815260206004820152601660248201527521b0b63632b91034b9903737ba1030b71037bbb732b960511b604482015290519081900360640190fd5b600154604080516370a0823160e01b815230600482015290516000926001600160a01b0316916370a08231916024808301926020929190829003018186803b15801561117357600080fd5b505afa158015611187573d6000803e3d6000fd5b505050506040513d602081101561119d57600080fd5b50516005546006549192506000916111ba9163ffffffff6123d816565b905060006111ce838363ffffffff612c9316565b6001546040805163a9059cbb60e01b81526001600160a01b038a8116600483015260248201859052915193945091169163a9059cbb916044808201926020929091908290030181600087803b15801561122657600080fd5b505af115801561123a573d6000803e3d6000fd5b505050506040513d602081101561125057600080fd5b50516112a3576040805162461bcd60e51b815260206004820181905260248201527f4e6f7420656e6f7567682066756e6473206f6e20636f6e74722e20616464722e604482015290519081900360640190fd5b604080516001600160a01b03881681526020810183905281517f7f66376a5ef2f39ab4ee2ee6e400606624e66929dba5d82df5b14dd0070a8a87929181900390910190a1505050505050565b6001600160a01b0381166000908152600f60205260409020600201805460609182918291908015611479578067ffffffffffffffff8111801561133157600080fd5b5060405190808252806020026020018201604052801561135b578160200160208202803683370190505b5094508067ffffffffffffffff8111801561137557600080fd5b5060405190808252806020026020018201604052801561139f578160200160208202803683370190505b5093508067ffffffffffffffff811180156113b957600080fd5b506040519080825280602002602001820160405280156113e3578160200160208202803683370190505b50925060005b818110156114775760008382815481106113ff57fe5b906000526020600020906003020190506000816001019050806000015488848151811061142857fe5b602002602001018181525050806001015487848151811061144557fe5b602002602001018181525050816000015486848151811061146257fe5b602090810291909101015250506001016113e9565b505b50509193909250565b808061148c612458565b11156114cd576040805162461bcd60e51b8152602060048201526013602482015260008051602061346c833981519152604482015290519081900360640190fd5b6114d5612458565b60035411611518576040805162461bcd60e51b815260206004820152601860248201526000805160206134ac833981519152604482015290519081900360640190fd5b336000611523612458565b90506000611531838361261d565b5091505061153d61333e565b81548082526000835561155390859083906128f4565b505050505050565b6010602052600090815260409020805460019091015482565b808061157e612458565b11156115bf576040805162461bcd60e51b8152602060048201526013602482015260008051602061346c833981519152604482015290519081900360640190fd5b6115c7612447565b611611576040805162461bcd60e51b815260206004820152601660248201527521b0b63632b91034b9903737ba1030b71037bbb732b960511b604482015290519081900360640190fd5b83611620576005549350611677565b600554841115611677576040805162461bcd60e51b815260206004820152601f60248201527f416d6f756e7420686967686572207468616e207265776172647320706f6f6c00604482015290519081900360640190fd5b600154604080516370a0823160e01b815230600482015290516000926001600160a01b0316916370a08231916024808301926020929190829003018186803b1580156116c257600080fd5b505afa1580156116d6573d6000803e3d6000fd5b505050506040513d60208110156116ec57600080fd5b5051600654909150600090611707908763ffffffff6123d816565b90508181111561175e576040805162461bcd60e51b815260206004820152601760248201527f436f6e747261637420696e636f6e73697374656e63792e000000000000000000604482015290519081900360640190fd5b6001546040805163a9059cbb60e01b81526001600160a01b038881166004830152602482018a90529151919092169163a9059cbb9160448083019260209291908290030181600087803b1580156117b457600080fd5b505af11580156117c8573d6000803e3d6000fd5b505050506040513d60208110156117de57600080fd5b5051611831576040805162461bcd60e51b815260206004820181905260248201527f4e6f7420656e6f7567682066756e6473206f6e20636f6e74722e20616464722e604482015290519081900360640190fd5b600580548790039055604080516001600160a01b03871681526020810188905281517f8a652d32cc9efc0a4f0fc3708c9fb81d5a924a7b9af2a37c46e9e4910d0dc325929181900390910190a1505050505050565b8080611890612458565b11156118d1576040805162461bcd60e51b8152602060048201526013602482015260008051602061346c833981519152604482015290519081900360640190fd5b6118d9612458565b6003541161191c576040805162461bcd60e51b815260206004820152601860248201526000805160206134ac833981519152604482015290519081900360640190fd5b8261196e576040805162461bcd60e51b815260206004820152601f60248201527f416d6f756e74206d75737420626520686967686572207468616e207a65726f00604482015290519081900360640190fd5b6000611978612458565b90506000611986338361261d565b5091505060006119963384612aa1565b90506119a061333e565b6119b483600284018963ffffffff612cd516565b90506119c760078263ffffffff612ce716565b600182015481516020808401516040805193845291830152805133927f0fb741c5ad2cad8215be7b4cab4e3f202f907d4540668ebf954f8e742efd89cf92908290030190a350505050505050565b6000828152602081905260408120611a33908363ffffffff612d1516565b90505b92915050565b6000828152602081905260408120611a33908363ffffffff612d2116565b8080611a64612458565b1115611aa5576040805162461bcd60e51b8152602060048201526013602482015260008051602061346c833981519152604482015290519081900360640190fd5b611aad612447565b611af7576040805162461bcd60e51b815260206004820152601660248201527521b0b63632b91034b9903737ba1030b71037bbb732b960511b604482015290519081900360640190fd5b611aff612458565b6002541015611b55576040805162461bcd60e51b815260206004820152601b60248201527f4561726c696573742064656c657465206e6f7420726561636865640000000000604482015290519081900360640190fd5b600154604080516370a0823160e01b815230600482015290516000926001600160a01b0316916370a08231916024808301926020929190829003018186803b158015611ba057600080fd5b505afa158015611bb4573d6000803e3d6000fd5b505050506040513d6020811015611bca57600080fd5b50516001546040805163a9059cbb60e01b81526001600160a01b03888116600483015260248201859052915193945091169163a9059cbb916044808201926020929091908290030181600087803b158015611c2457600080fd5b505af1158015611c38573d6000803e3d6000fd5b505050506040513d6020811015611c4e57600080fd5b5051611c5957600080fd5b6040517fe4dedc7f698868c432fb679313d1381b06601dfb7174d9b18b2e35378b67633390600090a1836001600160a01b0316ff5b600081565b6001600160a01b03166000908152600f6020526040902080546001909101549091565b600d602052600090815260409020805460019091015482565b60055490565b8080611cdf612458565b1115611d20576040805162461bcd60e51b8152602060048201526013602482015260008051602061346c833981519152604482015290519081900360640190fd5b82611d2a5761091a565b600154604080516323b872dd60e01b81523360048201523060248201526044810186905290516001600160a01b03909216916323b872dd916064808201926020929091908290030181600087803b158015611d8457600080fd5b505af1158015611d98573d6000803e3d6000fd5b505050506040513d6020811015611dae57600080fd5b5051611df3576040805162461bcd60e51b815260206004820152600f60248201526e151c985b9cd9995c8819985a5b1959608a1b604482015290519081900360640190fd5b600554611e06908463ffffffff6123d816565b600555604080513381526020810185905281517fb562e06b275d420e5848bb9083041a1c68466a478df92491b473ce99a4c68f68929181900390910190a1505050565b604080516c44454c45474154455f524f4c4560981b8152905190819003600d01902081565b6001600160a01b03166000908152600e60205260409020600281015460038201548254600190930154919390929190565b60075460085482565b6000818152602081905260408120611a3690612d36565b600082815260208190526040902060020154611edd906109686124e5565b610adc5760405162461bcd60e51b815260040180806020018281038252603081526020018061343c6030913960400191505060405180910390fd5b8080611f22612458565b1115611f63576040805162461bcd60e51b8152602060048201526013602482015260008051602061346c833981519152604482015290519081900360640190fd5b611f6b612458565b60035411611fae576040805162461bcd60e51b815260206004820152601860248201526000805160206134ac833981519152604482015290519081900360640190fd5b336000611fb9612458565b90506000611fc7838361261d565b50915050611fd361333e565b60018201805460208301819052600090915561155390859083906128f4565b600954600a5482565b600b5481565b808061200b612458565b111561204c576040805162461bcd60e51b8152602060048201526013602482015260008051602061346c833981519152604482015290519081900360640190fd5b612054612458565b60035411612097576040805162461bcd60e51b815260206004820152601860248201526000805160206134ac833981519152604482015290519081900360640190fd5b3360006120a2612458565b905060006120b0838361261d565b506040805180820190915281548152600182015460208201529092506120e1915084906120dc84612c1a565b6128f4565b600060018201819055905550505050565b80806120fc612458565b111561213d576040805162461bcd60e51b8152602060048201526013602482015260008051602061346c833981519152604482015290519081900360640190fd5b612145612458565b60035411612188576040805162461bcd60e51b815260206004820152601860248201526000805160206134ac833981519152604482015290519081900360640190fd5b82158015906122bd57600154604080516323b872dd60e01b81523360048201523060248201526044810187905290516001600160a01b03909216916323b872dd916064808201926020929091908290030181600087803b1580156121eb57600080fd5b505af11580156121ff573d6000803e3d6000fd5b505050506040513d602081101561221557600080fd5b505161225a576040805162461bcd60e51b815260206004820152600f60248201526e151c985b9cd9995c8819985a5b1959608a1b604482015290519081900360640190fd5b60065461226d908563ffffffff6123d816565b600655600754612283908563ffffffff6123d816565b60075560408051858152905133917f7ff07ce9a287649537e4b012e45cf012d90228b12e2b56bb03515a6b5436fcdf919081900360200190a25b60006122c7612458565b905060006122d5338361261d565b5091505082156115535780546122f1908763ffffffff6123d816565b90555050505050565b6001546001600160a01b031681565b8080612313612458565b1115612354576040805162461bcd60e51b8152602060048201526013602482015260008051602061346c833981519152604482015290519081900360640190fd5b61235c612447565b8061238e5750604080516c44454c45474154455f524f4c4560981b8152905190819003600d01902061238e9033611a3c565b6123c95760405162461bcd60e51b81526004018080602001828103825260248152602001806134186024913960400191505060405180910390fd5b61091a83612d41565b60035481565b600082820183811015611a33576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b6000611a33836001600160a01b038416612d97565b60006124538133611a3c565b905090565b4390565b600c546040805180820190915280612472612458565b815260209081018490526000838152600d82526040902082518155910151600191820155600c546124a89163ffffffff6123d816565b600c5560408051838152905182917fbcd200f406c53d9438c6cdc2966a1e99c35f336588c95bc3639e539df21c2f53919081900360200190a25050565b3390565b6000828152602081905260409020612507908263ffffffff61243216565b156109b2576125146124e5565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6000612562612458565b90508082106125715781612573565b805b600381905560408051918252517f68b095021b1f40fe513109f513c66692f0b3219aee674a69f4efc57badb8201d9181900360200190a15050565b60008281526020819052604090206125cc908263ffffffff612de116565b156109b2576125d96124e5565b6001600160a01b0316816001600160a01b0316837ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b60405160405180910390a45050565b61262561333e565b6001600160a01b0383166000908152600f6020908152604080832060109092528220919060028101825b815481101561278c57612660613358565b82828154811061266c57fe5b600091825260209182902060408051808201825260039093029091018054835281518083019092526001810154825260020154818401529181019190915280519091508810156126bf5750600101612787565b60208101515187516126d69163ffffffff6123d816565b8752602080820151810151908801516126f49163ffffffff6123d816565b60208801528254600019018281146127555783818154811061271257fe5b906000526020600020906003020184848154811061272c57fe5b600091825260209091208254600390920201908155600180830154908201556002918201549101555b8380548061275f57fe5b6000828152602081206003600019909301928302018181556001810182905560020155905550505b61264f565b5080546127c6576001600160a01b0387166000908152600f6020526040812081815560018101829055906127c36002830182613377565b50505b84511515806127d85750602085015115155b92508215612872578451602080870151604080519384529183015280516001600160a01b038a16927fa219ed960eef85ed4cd072d3a9f240ea94727c0d6fb15e9a91a8cd4bf18ee3a692908290030190a261283a60098663ffffffff612ce716565b80541561285157612851828663ffffffff612ce716565b61286260078663ffffffff612c5916565b612872848663ffffffff612c5916565b50509250925092565b61288361333e565b818360010154106128b45760018301546128a3908363ffffffff612c9316565b600184015560208101829052611a36565b60018301546128ca90839063ffffffff612c9316565b80825283546128de9163ffffffff612c9316565b8355600190920180546020840152600090555090565b801561091a5781602001516005541015612955576040805162461bcd60e51b815260206004820181905260248201527f4e6f7420656e6f7567682066756e647320696e207265776172647320706f6f6c604482015290519081900360640190fd5b6001546040805163a9059cbb60e01b81526001600160a01b038681166004830152602482018590529151919092169163a9059cbb9160448083019260209291908290030181600087803b1580156129ab57600080fd5b505af11580156129bf573d6000803e3d6000fd5b505050506040513d60208110156129d557600080fd5b5051612a1a576040805162461bcd60e51b815260206004820152600f60248201526e151c985b9cd9995c8819985a5b1959608a1b604482015290519081900360640190fd5b6020820151600554612a319163ffffffff612c9316565b6005558151600654612a489163ffffffff612c9316565b600655612a5c60078363ffffffff612ce716565b81516020808401516040805193845291830152805133927ff279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b56892908290030190a2505050565b6001600160a01b0382166000908152600e6020526040812090612ac660028301612c1a565b90508015612ba557815460018301545b600c54811015612b87576000818152600d602052604090208054831015612b44576040805162461bcd60e51b815260206004820152601860248201527f73696e6365426c6f636b20696e636f6e73697374656e63790000000000000000604482015290519081900360640190fd5b600c5486906001840190811015612b67576000818152600d602052604090205491505b612b78868460010154878503612df6565b95509093505050600101612ad6565b506002830154612b9e90839063ffffffff612c9316565b6003840155505b828255600c54612bb6576000612bbd565b6001600c54035b600183018190556002830154600384015460408051928352602083019190915280516001600160a01b038816927f6b6b43cdaf8f2ae06bdc6f6be433bb374b703ce8c88db4adce9dd8aefe44fe6d92908290030190a35092915050565b60018101548154600091611a36919063ffffffff6123d816565b612c3c61333e565b612c46848361287b565b9050612c528382612c59565b9392505050565b80518254612c6c9163ffffffff6123d816565b825560208101516001830154612c879163ffffffff6123d816565b82600101819055505050565b6000611a3383836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250612e36565b612cdd61333e565b612c468483612ecd565b80518254612cfa9163ffffffff612c9316565b825560208101516001830154612c879163ffffffff612c9316565b6000611a338383612f39565b6000611a33836001600160a01b038416612f9d565b6000611a3682612fb5565b6004805467ffffffffffffffff831667ffffffffffffffff19909116811790915560408051918252517f6b24ea7c7a8ce7fd2e6a6cb675dbabcd38a90f83ddd581c4435610ce90456e8f9181900360200190a150565b6000612da38383612f9d565b612dd957508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155611a36565b506000611a36565b6000611a33836001600160a01b038416612fb9565b6000612e2e612e28612e22612e0b600161307f565b612e1d87670de0b6b3a764000061309d565b6130d4565b84613108565b85613156565b949350505050565b60008184841115612ec55760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015612e8a578181015183820152602001612e72565b50505050905090810190601f168015612eb75780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b612ed561333e565b82548211612ef9578254612eef908363ffffffff612c9316565b8355818152611a36565b8254612f0c90839063ffffffff612c9316565b602082018190526001840154612f279163ffffffff612c9316565b60018401558254815260009092555090565b81546000908210612f7b5760405162461bcd60e51b81526004018080602001828103825260228152602001806133c76022913960400191505060405180910390fd5b826000018281548110612f8a57fe5b9060005260206000200154905092915050565b60009081526001919091016020526040902054151590565b5490565b600081815260018301602052604081205480156130755783546000198083019190810190600090879083908110612fec57fe5b906000526020600020015490508087600001848154811061300957fe5b60009182526020808320909101929092558281526001898101909252604090209084019055865487908061303957fe5b60019003818190600052602060002001600090559055866001016000878152602001908152602001600020600090556001945050505050611a36565b6000915050611a36565b6000677fffffffffffffff82111561309657600080fd5b5060401b90565b6000816130a957600080fd5b60006130b584846131be565b905060016001607f1b036001600160801b0382161115611a3357600080fd5b6000600f83810b9083900b0160016001607f1b031981128015906130ff575060016001607f1b038113155b611a3357600080fd5b6000613114600161307f565b90505b8115611a3657600182161561313d576131308184613308565b9050600182039150613151565b6131478384613308565b9250600182901c91505b613117565b60008161316557506000611a36565b600083600f0b121561317657600080fd5b600f83900b6001600160801b038316810260401c90608084901c026001600160c01b038111156131a557600080fd5b60401b81198111156131b657600080fd5b019392505050565b6000816131ca57600080fd5b60006001600160c01b0384116131ef5782604085901b816131e757fe5b0490506132f4565b60c084811c6401000000008110613208576020918201911c5b62010000811061321a576010918201911c5b610100811061322b576008918201911c5b6010811061323b576004918201911c5b6004811061324b576002918201911c5b6002811061325a576001820191505b60bf820360018603901c6001018260ff0387901b8161327557fe5b0492506001600160801b0383111561328c57600080fd5b608085901c83026001600160801b038616840260c088901c604089901b828110156132b8576001820391505b608084901b929003828110156132cf576001820391505b829003608084901c82146132df57fe5b8881816132e857fe5b04870196505050505050505b6001600160801b03811115611a3357600080fd5b6000600f83810b9083900b0260401d60016001607f1b031981128015906130ff575060016001607f1b03811315611a3357600080fd5b604051806040016040528060008152602001600081525090565b60405180604001604052806000815260200161337261333e565b905290565b5080546000825560030290600052602060002090810190613398919061339b565b50565b61084891905b808211156133c25760008082556001820181905560028201556003016133a1565b509056fe456e756d657261626c655365743a20696e646578206f7574206f6620626f756e6473416363657373436f6e74726f6c3a2073656e646572206d75737420626520616e2061646d696e20746f206772616e7443616c6c6572206973206e656974686572206f776e6572206e6f722064656c6567617465416363657373436f6e74726f6c3a2073656e646572206d75737420626520616e2061646d696e20746f207265766f6b655472616e73616374696f6e2065787069726564000000000000000000000000005bfe1e16d75ca1fa001989652cd88c5b8ee8a59b5df6df99836337def4d1c82d436f6e747261637420686173206265656e207061757365640000000000000000416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636520726f6c657320666f722073656c66a26469706673582212205436678265352631f897e2cef39869cf23c267c4a2f500784a8480a5ff10f77664736f6c63430006080033\",\n  \"deployedBytecode\": \"0x608060405234801561001057600080fd5b506004361061025e5760003560e01c80639010d07c11610146578063c8984ab2116100c3578063d9d8e78311610087578063d9d8e783146107bf578063dca2aa5c146107c7578063e2bbb158146107e4578063ecd0c0c314610807578063f0895e521461080f578063f1209ef71461083c5761025e565b8063c8984ab214610749578063ca15c87314610751578063d547741f1461076e578063d8cd39991461079a578063d9b202c9146107b75761025e565b8063aa700ff21161010a578063aa700ff2146106ad578063adf55101146106ca578063ba92a4c5146106d2578063c0ba241b146106f5578063c30f75cf146106fd5761025e565b80639010d07c146105d457806391d14854146106135780639608df4b14610653578063a217fddf1461067f578063a8f1b4c4146106875761025e565b8063372646bb116101df57806353e052ac116101a357806353e052ac146103f35780635f208f341461041f578063658e28a41461052357806367ce50c01461054057806368bccfcf1461057f57806388cedd5e146105b15761025e565b8063372646bb1461037757806340e979031461037f5780634164b001146103a5578063441a3e70146103ad57806352885d8d146103d05761025e565b8063292911fb11610226578063292911fb146102ec5780632f2ff15d146102f457806332a1bd7014610320578063347908df1461032857806336568abe1461034b5761025e565b8063085313ec146102635780630c450f9d1461027d5780631338403914610285578063248a9ca3146102aa5780632514c50a146102c7575b600080fd5b61026b610844565b60408051918252519081900360200190f35b61026b61084b565b6102a86004803603604081101561029b57600080fd5b5080359060200135610851565b005b61026b600480360360208110156102c057600080fd5b503561091f565b6102cf610934565b6040805167ffffffffffffffff9092168252519081900360200190f35b61026b610944565b6102a86004803603604081101561030a57600080fd5b50803590602001356001600160a01b031661094a565b61026b6109b6565b6102a86004803603604081101561033e57600080fd5b50803590602001356109bc565b6102a86004803603604081101561036157600080fd5b50803590602001356001600160a01b0316610a85565b61026b610ae6565b61026b6004803603602081101561039557600080fd5b50356001600160a01b0316610aed565b61026b610b0b565b6102a8600480360360408110156103c357600080fd5b5080359060200135610b11565b6102a8600480360360408110156103e657600080fd5b5080359060200135610bf2565b6102a86004803603604081101561040957600080fd5b506001600160a01b03813516906020013561108b565b6104456004803603602081101561043557600080fd5b50356001600160a01b03166112ef565b60405180806020018060200180602001848103845287818151815260200191508051906020019060200280838360005b8381101561048d578181015183820152602001610475565b50505050905001848103835286818151815260200191508051906020019060200280838360005b838110156104cc5781810151838201526020016104b4565b50505050905001848103825285818151815260200191508051906020019060200280838360005b8381101561050b5781810151838201526020016104f3565b50505050905001965050505050505060405180910390f35b6102a86004803603602081101561053957600080fd5b5035611482565b6105666004803603602081101561055657600080fd5b50356001600160a01b031661155b565b6040805192835260208301919091528051918290030190f35b6102a86004803603606081101561059557600080fd5b508035906001600160a01b036020820135169060400135611574565b6102a8600480360360408110156105c757600080fd5b5080359060200135611886565b6105f7600480360360408110156105ea57600080fd5b5080359060200135611a15565b604080516001600160a01b039092168252519081900360200190f35b61063f6004803603604081101561062957600080fd5b50803590602001356001600160a01b0316611a3c565b604080519115158252519081900360200190f35b6102a86004803603604081101561066957600080fd5b506001600160a01b038135169060200135611a5a565b61026b611c8e565b6105666004803603602081101561069d57600080fd5b50356001600160a01b0316611c93565b610566600480360360208110156106c357600080fd5b5035611cb6565b61026b611ccf565b6102a8600480360360408110156106e857600080fd5b5080359060200135611cd5565b61026b611e49565b6107236004803603602081101561071357600080fd5b50356001600160a01b0316611e6e565b604080519485526020850193909352838301919091526060830152519081900360800190f35b610566611e9f565b61026b6004803603602081101561076757600080fd5b5035611ea8565b6102a86004803603604081101561078457600080fd5b50803590602001356001600160a01b0316611ebf565b6102a8600480360360208110156107b057600080fd5b5035611f18565b610566611ff2565b61026b611ffb565b6102a8600480360360208110156107dd57600080fd5b5035612001565b6102a8600480360360408110156107fa57600080fd5b50803590602001356120f2565b6105f76122fa565b6102a86004803603604081101561082557600080fd5b5067ffffffffffffffff8135169060200135612309565b61026b6123d2565b6002545b90565b60055481565b610859612447565b8061088b5750604080516c44454c45474154455f524f4c4560981b8152905190819003600d01902061088b9033611a3c565b6108c65760405162461bcd60e51b81526004018080602001828103825260248152602001806134186024913960400191505060405180910390fd5b80806108d0612458565b1115610911576040805162461bcd60e51b8152602060048201526013602482015260008051602061346c833981519152604482015290519081900360640190fd5b61091a8361245c565b505050565b60009081526020819052604090206002015490565b60045467ffffffffffffffff1681565b60065481565b60008281526020819052604090206002015461096d906109686124e5565b611a3c565b6109a85760405162461bcd60e51b815260040180806020018281038252602f8152602001806133e9602f913960400191505060405180910390fd5b6109b282826124e9565b5050565b60025481565b80806109c6612458565b1115610a07576040805162461bcd60e51b8152602060048201526013602482015260008051602061346c833981519152604482015290519081900360640190fd5b610a0f612447565b80610a415750604080516c44454c45474154455f524f4c4560981b8152905190819003600d019020610a419033611a3c565b610a7c5760405162461bcd60e51b81526004018080602001828103825260248152602001806134186024913960400191505060405180910390fd5b61091a83612558565b610a8d6124e5565b6001600160a01b0316816001600160a01b031614610adc5760405162461bcd60e51b815260040180806020018281038252602f8152602001806134cc602f913960400191505060405180910390fd5b6109b282826125ae565b6205a66d81565b6001600160a01b03166000908152600f602052604090206002015490565b600c5481565b8080610b1b612458565b1115610b5c576040805162461bcd60e51b8152602060048201526013602482015260008051602061346c833981519152604482015290519081900360640190fd5b610b64612458565b60035411610ba7576040805162461bcd60e51b815260206004820152601860248201526000805160206134ac833981519152604482015290519081900360640190fd5b336000610bb2612458565b90506000610bc0838361261d565b50915050610bcc61333e565b610bdc828863ffffffff61287b16565b9050610be98482896128f4565b50505050505050565b8080610bfc612458565b1115610c3d576040805162461bcd60e51b8152602060048201526013602482015260008051602061346c833981519152604482015290519081900360640190fd5b610c45612458565b60035411610c88576040805162461bcd60e51b815260206004820152601860248201526000805160206134ac833981519152604482015290519081900360640190fd5b6000610c92612458565b9050336000610ca18284612aa1565b90506000610cb182600201612c1a565b9050610cbb61333e565b8715610ebd5781881115610d16576040805162461bcd60e51b815260206004820152601b60248201527f416d6f756e7420697320686967686572207468616e207374616b650000000000604482015290519081900360640190fd5b60045467ffffffffffffffff16610dee576001600160a01b0384166000908152601060205260409020610d549060028501908a63ffffffff612c3416565b9050610d6760078263ffffffff612c5916565b80516020808301516040805193845291830152805187926001600160a01b0388169260008051602061348c83398151915292918290030190a38051602080830151604080519384529183015280516001600160a01b038716927fa219ed960eef85ed4cd072d3a9f240ea94727c0d6fb15e9a91a8cd4bf18ee3a692908290030190a2610eb8565b6001600160a01b0384166000908152600f6020908152604082206002810180546001810182559084529190922060045460039092020190610e4090889067ffffffffffffffff1663ffffffff6123d816565b8155610e5960028601600183018c63ffffffff612c3416565b9250610e6c60098463ffffffff612c5916565b610e7c828463ffffffff612c5916565b80548351602080860151604080519384529183015280516001600160a01b038a169260008051602061348c83398151915292908290030190a350505b611081565b81610ecc57505050505061091a565b5060408051808201909152600283018054825260038401805460208401526000918290555560045467ffffffffffffffff16610fc2576001600160a01b0384166000908152601060205260409020610f2a908263ffffffff612c5916565b610f3b60078263ffffffff612c5916565b80516020808301516040805193845291830152805187926001600160a01b0388169260008051602061348c83398151915292918290030190a38051602080830151604080519384529183015280516001600160a01b038716927fa219ed960eef85ed4cd072d3a9f240ea94727c0d6fb15e9a91a8cd4bf18ee3a692908290030190a2611081565b6001600160a01b0384166000908152600f602090815260408220600281018054600181018255908452919092206004546003909202019061101490889067ffffffffffffffff1663ffffffff6123d816565b8155825160018201556020830151600282015561103860098463ffffffff612c5916565b611048828463ffffffff612c5916565b8054600182015460028301546040805192835260208301919091528051339260008051602061348c83398151915292908290030190a350505b5050505050505050565b8080611095612458565b11156110d6576040805162461bcd60e51b8152602060048201526013602482015260008051602061346c833981519152604482015290519081900360640190fd5b6110de612447565b611128576040805162461bcd60e51b815260206004820152601660248201527521b0b63632b91034b9903737ba1030b71037bbb732b960511b604482015290519081900360640190fd5b600154604080516370a0823160e01b815230600482015290516000926001600160a01b0316916370a08231916024808301926020929190829003018186803b15801561117357600080fd5b505afa158015611187573d6000803e3d6000fd5b505050506040513d602081101561119d57600080fd5b50516005546006549192506000916111ba9163ffffffff6123d816565b905060006111ce838363ffffffff612c9316565b6001546040805163a9059cbb60e01b81526001600160a01b038a8116600483015260248201859052915193945091169163a9059cbb916044808201926020929091908290030181600087803b15801561122657600080fd5b505af115801561123a573d6000803e3d6000fd5b505050506040513d602081101561125057600080fd5b50516112a3576040805162461bcd60e51b815260206004820181905260248201527f4e6f7420656e6f7567682066756e6473206f6e20636f6e74722e20616464722e604482015290519081900360640190fd5b604080516001600160a01b03881681526020810183905281517f7f66376a5ef2f39ab4ee2ee6e400606624e66929dba5d82df5b14dd0070a8a87929181900390910190a1505050505050565b6001600160a01b0381166000908152600f60205260409020600201805460609182918291908015611479578067ffffffffffffffff8111801561133157600080fd5b5060405190808252806020026020018201604052801561135b578160200160208202803683370190505b5094508067ffffffffffffffff8111801561137557600080fd5b5060405190808252806020026020018201604052801561139f578160200160208202803683370190505b5093508067ffffffffffffffff811180156113b957600080fd5b506040519080825280602002602001820160405280156113e3578160200160208202803683370190505b50925060005b818110156114775760008382815481106113ff57fe5b906000526020600020906003020190506000816001019050806000015488848151811061142857fe5b602002602001018181525050806001015487848151811061144557fe5b602002602001018181525050816000015486848151811061146257fe5b602090810291909101015250506001016113e9565b505b50509193909250565b808061148c612458565b11156114cd576040805162461bcd60e51b8152602060048201526013602482015260008051602061346c833981519152604482015290519081900360640190fd5b6114d5612458565b60035411611518576040805162461bcd60e51b815260206004820152601860248201526000805160206134ac833981519152604482015290519081900360640190fd5b336000611523612458565b90506000611531838361261d565b5091505061153d61333e565b81548082526000835561155390859083906128f4565b505050505050565b6010602052600090815260409020805460019091015482565b808061157e612458565b11156115bf576040805162461bcd60e51b8152602060048201526013602482015260008051602061346c833981519152604482015290519081900360640190fd5b6115c7612447565b611611576040805162461bcd60e51b815260206004820152601660248201527521b0b63632b91034b9903737ba1030b71037bbb732b960511b604482015290519081900360640190fd5b83611620576005549350611677565b600554841115611677576040805162461bcd60e51b815260206004820152601f60248201527f416d6f756e7420686967686572207468616e207265776172647320706f6f6c00604482015290519081900360640190fd5b600154604080516370a0823160e01b815230600482015290516000926001600160a01b0316916370a08231916024808301926020929190829003018186803b1580156116c257600080fd5b505afa1580156116d6573d6000803e3d6000fd5b505050506040513d60208110156116ec57600080fd5b5051600654909150600090611707908763ffffffff6123d816565b90508181111561175e576040805162461bcd60e51b815260206004820152601760248201527f436f6e747261637420696e636f6e73697374656e63792e000000000000000000604482015290519081900360640190fd5b6001546040805163a9059cbb60e01b81526001600160a01b038881166004830152602482018a90529151919092169163a9059cbb9160448083019260209291908290030181600087803b1580156117b457600080fd5b505af11580156117c8573d6000803e3d6000fd5b505050506040513d60208110156117de57600080fd5b5051611831576040805162461bcd60e51b815260206004820181905260248201527f4e6f7420656e6f7567682066756e6473206f6e20636f6e74722e20616464722e604482015290519081900360640190fd5b600580548790039055604080516001600160a01b03871681526020810188905281517f8a652d32cc9efc0a4f0fc3708c9fb81d5a924a7b9af2a37c46e9e4910d0dc325929181900390910190a1505050505050565b8080611890612458565b11156118d1576040805162461bcd60e51b8152602060048201526013602482015260008051602061346c833981519152604482015290519081900360640190fd5b6118d9612458565b6003541161191c576040805162461bcd60e51b815260206004820152601860248201526000805160206134ac833981519152604482015290519081900360640190fd5b8261196e576040805162461bcd60e51b815260206004820152601f60248201527f416d6f756e74206d75737420626520686967686572207468616e207a65726f00604482015290519081900360640190fd5b6000611978612458565b90506000611986338361261d565b5091505060006119963384612aa1565b90506119a061333e565b6119b483600284018963ffffffff612cd516565b90506119c760078263ffffffff612ce716565b600182015481516020808401516040805193845291830152805133927f0fb741c5ad2cad8215be7b4cab4e3f202f907d4540668ebf954f8e742efd89cf92908290030190a350505050505050565b6000828152602081905260408120611a33908363ffffffff612d1516565b90505b92915050565b6000828152602081905260408120611a33908363ffffffff612d2116565b8080611a64612458565b1115611aa5576040805162461bcd60e51b8152602060048201526013602482015260008051602061346c833981519152604482015290519081900360640190fd5b611aad612447565b611af7576040805162461bcd60e51b815260206004820152601660248201527521b0b63632b91034b9903737ba1030b71037bbb732b960511b604482015290519081900360640190fd5b611aff612458565b6002541015611b55576040805162461bcd60e51b815260206004820152601b60248201527f4561726c696573742064656c657465206e6f7420726561636865640000000000604482015290519081900360640190fd5b600154604080516370a0823160e01b815230600482015290516000926001600160a01b0316916370a08231916024808301926020929190829003018186803b158015611ba057600080fd5b505afa158015611bb4573d6000803e3d6000fd5b505050506040513d6020811015611bca57600080fd5b50516001546040805163a9059cbb60e01b81526001600160a01b03888116600483015260248201859052915193945091169163a9059cbb916044808201926020929091908290030181600087803b158015611c2457600080fd5b505af1158015611c38573d6000803e3d6000fd5b505050506040513d6020811015611c4e57600080fd5b5051611c5957600080fd5b6040517fe4dedc7f698868c432fb679313d1381b06601dfb7174d9b18b2e35378b67633390600090a1836001600160a01b0316ff5b600081565b6001600160a01b03166000908152600f6020526040902080546001909101549091565b600d602052600090815260409020805460019091015482565b60055490565b8080611cdf612458565b1115611d20576040805162461bcd60e51b8152602060048201526013602482015260008051602061346c833981519152604482015290519081900360640190fd5b82611d2a5761091a565b600154604080516323b872dd60e01b81523360048201523060248201526044810186905290516001600160a01b03909216916323b872dd916064808201926020929091908290030181600087803b158015611d8457600080fd5b505af1158015611d98573d6000803e3d6000fd5b505050506040513d6020811015611dae57600080fd5b5051611df3576040805162461bcd60e51b815260206004820152600f60248201526e151c985b9cd9995c8819985a5b1959608a1b604482015290519081900360640190fd5b600554611e06908463ffffffff6123d816565b600555604080513381526020810185905281517fb562e06b275d420e5848bb9083041a1c68466a478df92491b473ce99a4c68f68929181900390910190a1505050565b604080516c44454c45474154455f524f4c4560981b8152905190819003600d01902081565b6001600160a01b03166000908152600e60205260409020600281015460038201548254600190930154919390929190565b60075460085482565b6000818152602081905260408120611a3690612d36565b600082815260208190526040902060020154611edd906109686124e5565b610adc5760405162461bcd60e51b815260040180806020018281038252603081526020018061343c6030913960400191505060405180910390fd5b8080611f22612458565b1115611f63576040805162461bcd60e51b8152602060048201526013602482015260008051602061346c833981519152604482015290519081900360640190fd5b611f6b612458565b60035411611fae576040805162461bcd60e51b815260206004820152601860248201526000805160206134ac833981519152604482015290519081900360640190fd5b336000611fb9612458565b90506000611fc7838361261d565b50915050611fd361333e565b60018201805460208301819052600090915561155390859083906128f4565b600954600a5482565b600b5481565b808061200b612458565b111561204c576040805162461bcd60e51b8152602060048201526013602482015260008051602061346c833981519152604482015290519081900360640190fd5b612054612458565b60035411612097576040805162461bcd60e51b815260206004820152601860248201526000805160206134ac833981519152604482015290519081900360640190fd5b3360006120a2612458565b905060006120b0838361261d565b506040805180820190915281548152600182015460208201529092506120e1915084906120dc84612c1a565b6128f4565b600060018201819055905550505050565b80806120fc612458565b111561213d576040805162461bcd60e51b8152602060048201526013602482015260008051602061346c833981519152604482015290519081900360640190fd5b612145612458565b60035411612188576040805162461bcd60e51b815260206004820152601860248201526000805160206134ac833981519152604482015290519081900360640190fd5b82158015906122bd57600154604080516323b872dd60e01b81523360048201523060248201526044810187905290516001600160a01b03909216916323b872dd916064808201926020929091908290030181600087803b1580156121eb57600080fd5b505af11580156121ff573d6000803e3d6000fd5b505050506040513d602081101561221557600080fd5b505161225a576040805162461bcd60e51b815260206004820152600f60248201526e151c985b9cd9995c8819985a5b1959608a1b604482015290519081900360640190fd5b60065461226d908563ffffffff6123d816565b600655600754612283908563ffffffff6123d816565b60075560408051858152905133917f7ff07ce9a287649537e4b012e45cf012d90228b12e2b56bb03515a6b5436fcdf919081900360200190a25b60006122c7612458565b905060006122d5338361261d565b5091505082156115535780546122f1908763ffffffff6123d816565b90555050505050565b6001546001600160a01b031681565b8080612313612458565b1115612354576040805162461bcd60e51b8152602060048201526013602482015260008051602061346c833981519152604482015290519081900360640190fd5b61235c612447565b8061238e5750604080516c44454c45474154455f524f4c4560981b8152905190819003600d01902061238e9033611a3c565b6123c95760405162461bcd60e51b81526004018080602001828103825260248152602001806134186024913960400191505060405180910390fd5b61091a83612d41565b60035481565b600082820183811015611a33576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b6000611a33836001600160a01b038416612d97565b60006124538133611a3c565b905090565b4390565b600c546040805180820190915280612472612458565b815260209081018490526000838152600d82526040902082518155910151600191820155600c546124a89163ffffffff6123d816565b600c5560408051838152905182917fbcd200f406c53d9438c6cdc2966a1e99c35f336588c95bc3639e539df21c2f53919081900360200190a25050565b3390565b6000828152602081905260409020612507908263ffffffff61243216565b156109b2576125146124e5565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6000612562612458565b90508082106125715781612573565b805b600381905560408051918252517f68b095021b1f40fe513109f513c66692f0b3219aee674a69f4efc57badb8201d9181900360200190a15050565b60008281526020819052604090206125cc908263ffffffff612de116565b156109b2576125d96124e5565b6001600160a01b0316816001600160a01b0316837ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b60405160405180910390a45050565b61262561333e565b6001600160a01b0383166000908152600f6020908152604080832060109092528220919060028101825b815481101561278c57612660613358565b82828154811061266c57fe5b600091825260209182902060408051808201825260039093029091018054835281518083019092526001810154825260020154818401529181019190915280519091508810156126bf5750600101612787565b60208101515187516126d69163ffffffff6123d816565b8752602080820151810151908801516126f49163ffffffff6123d816565b60208801528254600019018281146127555783818154811061271257fe5b906000526020600020906003020184848154811061272c57fe5b600091825260209091208254600390920201908155600180830154908201556002918201549101555b8380548061275f57fe5b6000828152602081206003600019909301928302018181556001810182905560020155905550505b61264f565b5080546127c6576001600160a01b0387166000908152600f6020526040812081815560018101829055906127c36002830182613377565b50505b84511515806127d85750602085015115155b92508215612872578451602080870151604080519384529183015280516001600160a01b038a16927fa219ed960eef85ed4cd072d3a9f240ea94727c0d6fb15e9a91a8cd4bf18ee3a692908290030190a261283a60098663ffffffff612ce716565b80541561285157612851828663ffffffff612ce716565b61286260078663ffffffff612c5916565b612872848663ffffffff612c5916565b50509250925092565b61288361333e565b818360010154106128b45760018301546128a3908363ffffffff612c9316565b600184015560208101829052611a36565b60018301546128ca90839063ffffffff612c9316565b80825283546128de9163ffffffff612c9316565b8355600190920180546020840152600090555090565b801561091a5781602001516005541015612955576040805162461bcd60e51b815260206004820181905260248201527f4e6f7420656e6f7567682066756e647320696e207265776172647320706f6f6c604482015290519081900360640190fd5b6001546040805163a9059cbb60e01b81526001600160a01b038681166004830152602482018590529151919092169163a9059cbb9160448083019260209291908290030181600087803b1580156129ab57600080fd5b505af11580156129bf573d6000803e3d6000fd5b505050506040513d60208110156129d557600080fd5b5051612a1a576040805162461bcd60e51b815260206004820152600f60248201526e151c985b9cd9995c8819985a5b1959608a1b604482015290519081900360640190fd5b6020820151600554612a319163ffffffff612c9316565b6005558151600654612a489163ffffffff612c9316565b600655612a5c60078363ffffffff612ce716565b81516020808401516040805193845291830152805133927ff279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b56892908290030190a2505050565b6001600160a01b0382166000908152600e6020526040812090612ac660028301612c1a565b90508015612ba557815460018301545b600c54811015612b87576000818152600d602052604090208054831015612b44576040805162461bcd60e51b815260206004820152601860248201527f73696e6365426c6f636b20696e636f6e73697374656e63790000000000000000604482015290519081900360640190fd5b600c5486906001840190811015612b67576000818152600d602052604090205491505b612b78868460010154878503612df6565b95509093505050600101612ad6565b506002830154612b9e90839063ffffffff612c9316565b6003840155505b828255600c54612bb6576000612bbd565b6001600c54035b600183018190556002830154600384015460408051928352602083019190915280516001600160a01b038816927f6b6b43cdaf8f2ae06bdc6f6be433bb374b703ce8c88db4adce9dd8aefe44fe6d92908290030190a35092915050565b60018101548154600091611a36919063ffffffff6123d816565b612c3c61333e565b612c46848361287b565b9050612c528382612c59565b9392505050565b80518254612c6c9163ffffffff6123d816565b825560208101516001830154612c879163ffffffff6123d816565b82600101819055505050565b6000611a3383836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250612e36565b612cdd61333e565b612c468483612ecd565b80518254612cfa9163ffffffff612c9316565b825560208101516001830154612c879163ffffffff612c9316565b6000611a338383612f39565b6000611a33836001600160a01b038416612f9d565b6000611a3682612fb5565b6004805467ffffffffffffffff831667ffffffffffffffff19909116811790915560408051918252517f6b24ea7c7a8ce7fd2e6a6cb675dbabcd38a90f83ddd581c4435610ce90456e8f9181900360200190a150565b6000612da38383612f9d565b612dd957508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155611a36565b506000611a36565b6000611a33836001600160a01b038416612fb9565b6000612e2e612e28612e22612e0b600161307f565b612e1d87670de0b6b3a764000061309d565b6130d4565b84613108565b85613156565b949350505050565b60008184841115612ec55760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015612e8a578181015183820152602001612e72565b50505050905090810190601f168015612eb75780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b612ed561333e565b82548211612ef9578254612eef908363ffffffff612c9316565b8355818152611a36565b8254612f0c90839063ffffffff612c9316565b602082018190526001840154612f279163ffffffff612c9316565b60018401558254815260009092555090565b81546000908210612f7b5760405162461bcd60e51b81526004018080602001828103825260228152602001806133c76022913960400191505060405180910390fd5b826000018281548110612f8a57fe5b9060005260206000200154905092915050565b60009081526001919091016020526040902054151590565b5490565b600081815260018301602052604081205480156130755783546000198083019190810190600090879083908110612fec57fe5b906000526020600020015490508087600001848154811061300957fe5b60009182526020808320909101929092558281526001898101909252604090209084019055865487908061303957fe5b60019003818190600052602060002001600090559055866001016000878152602001908152602001600020600090556001945050505050611a36565b6000915050611a36565b6000677fffffffffffffff82111561309657600080fd5b5060401b90565b6000816130a957600080fd5b60006130b584846131be565b905060016001607f1b036001600160801b0382161115611a3357600080fd5b6000600f83810b9083900b0160016001607f1b031981128015906130ff575060016001607f1b038113155b611a3357600080fd5b6000613114600161307f565b90505b8115611a3657600182161561313d576131308184613308565b9050600182039150613151565b6131478384613308565b9250600182901c91505b613117565b60008161316557506000611a36565b600083600f0b121561317657600080fd5b600f83900b6001600160801b038316810260401c90608084901c026001600160c01b038111156131a557600080fd5b60401b81198111156131b657600080fd5b019392505050565b6000816131ca57600080fd5b60006001600160c01b0384116131ef5782604085901b816131e757fe5b0490506132f4565b60c084811c6401000000008110613208576020918201911c5b62010000811061321a576010918201911c5b610100811061322b576008918201911c5b6010811061323b576004918201911c5b6004811061324b576002918201911c5b6002811061325a576001820191505b60bf820360018603901c6001018260ff0387901b8161327557fe5b0492506001600160801b0383111561328c57600080fd5b608085901c83026001600160801b038616840260c088901c604089901b828110156132b8576001820391505b608084901b929003828110156132cf576001820391505b829003608084901c82146132df57fe5b8881816132e857fe5b04870196505050505050505b6001600160801b03811115611a3357600080fd5b6000600f83810b9083900b0260401d60016001607f1b031981128015906130ff575060016001607f1b03811315611a3357600080fd5b604051806040016040528060008152602001600081525090565b60405180604001604052806000815260200161337261333e565b905290565b5080546000825560030290600052602060002090810190613398919061339b565b50565b61084891905b808211156133c25760008082556001820181905560028201556003016133a1565b509056fe456e756d657261626c655365743a20696e646578206f7574206f6620626f756e6473416363657373436f6e74726f6c3a2073656e646572206d75737420626520616e2061646d696e20746f206772616e7443616c6c6572206973206e656974686572206f776e6572206e6f722064656c6567617465416363657373436f6e74726f6c3a2073656e646572206d75737420626520616e2061646d696e20746f207265766f6b655472616e73616374696f6e2065787069726564000000000000000000000000005bfe1e16d75ca1fa001989652cd88c5b8ee8a59b5df6df99836337def4d1c82d436f6e747261637420686173206265656e207061757365640000000000000000416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636520726f6c657320666f722073656c66a26469706673582212205436678265352631f897e2cef39869cf23c267c4a2f500784a8480a5ff10f77664736f6c63430006080033\",\n  \"immutableReferences\": {},\n  \"sourceMap\": \"1040:33269:6:-:0;;;6829:813;5:9:-1;2:2;;;27:1;24;17:12;2:2;6829:813:6;;;;;;;;;;;;;;;15:3:-1;10;7:12;4:2;;;32:1;29;22:12;4:2;-1:-1;6829:813:6;;;;;;;;;;;;;;;;;;;7012:42;1762:4:9;7043:10:6;-1:-1:-1;;;;;7012:10:6;:42;:::i;:::-;7065:6;:29;;-1:-1:-1;;;;;;7065:29:6;-1:-1:-1;;;;;7065:29:6;;;;;7122:47;4364:6;7122:17;:15;:17::i;:::-;:21;;;;;;:47;;;;:::i;:::-;7104:15;:65;7494:37;7512:18;-1:-1:-1;;;;;7494:17:6;:37;:::i;:::-;7541:38;7558:20;-1:-1:-1;;;;;7541:16:6;:38;:::i;:::-;7589:46;7601:16;-1:-1:-1;;;;;7589:11:6;:46;:::i;:::-;6829:813;;;;1040:33269;;6578:110:9;6656:25;6667:4;6673:7;-1:-1:-1;;;;;6656:10:9;:25;:::i;:::-;6578:110;;:::o;25560:106:6:-;25647:12;25560:106;:::o;874:176:10:-;932:7;963:5;;;986:6;;;;978:46;;;;;-1:-1:-1;;;978:46:10;;;;;;;;;;;;;;;;;;;;;;;;;;;;1042:1;-1:-1:-1;874:176:10;;;;;:::o;26522:148:6:-;26592:19;:33;;-1:-1:-1;;;;;26592:33:6;;-1:-1:-1;;;;;;26592:33:6;;;;;;;;26640:23;;;;;;;;;;;;;;;;26522:148;:::o;26015:390::-;26093:21;;26146:148;;;;;;;;;;26195:17;-1:-1:-1;;;;;26195:15:6;:17;:::i;:::-;26146:148;;;;;;;;;-1:-1:-1;26124:19:6;;;:14;:19;;;;;:170;;;;;;;;;;;;;26328:21;;:28;;:21;;:25;;;;;:28;;:::i;:::-;26304:21;:52;26372:26;;;;;;;;26388:3;;26372:26;;;;;;;;;;26015:390;;:::o;26933:255::-;26999:26;27028:17;-1:-1:-1;;;;;27028:15:6;:17;:::i;:::-;26999:46;;27089:18;27075:11;:32;:67;;27131:11;27075:67;;;27110:18;27075:67;27055:17;:87;;;27157:24;;;;;;;;;;;;;;;;26933:255;;:::o;7015:184:9:-;7088:6;:12;;;;;;;;;;;:33;;7113:7;;7088:24;;;;;:33;;:::i;:::-;7084:109;;;7169:12;-1:-1:-1;;;;;7169:10:9;:12;:::i;:::-;-1:-1:-1;;;;;7142:40:9;7160:7;-1:-1:-1;;;;;7142:40:9;7154:4;7142:40;;;;;;;;;;7015:184;;:::o;4864:141:15:-;4934:4;4957:41;4962:3;-1:-1:-1;;;;;4982:14:15;;-1:-1:-1;;;;;4957:4:15;:41;:::i;590:104:8:-;677:10;590:104;:::o;1611:404:15:-;1674:4;1695:21;1705:3;1710:5;-1:-1:-1;;;;;1695:9:15;:21;:::i;:::-;1690:319;;-1:-1:-1;27:10;;39:1;23:18;;;45:23;;1732:11:15;:23;;;;;;;;;;;;;1912:18;;1890:19;;;:12;;;:19;;;;;;:40;;;;1944:11;;1690:319;-1:-1:-1;1993:5:15;1986:12;;3776:127;3849:4;3872:19;;;:12;;;;;:19;;;;;;:24;;;3776:127::o;1040:33269:6:-;;;;;;;\",\n  \"deployedSourceMap\": \"1040:33269:6:-:0;;;;5:9:-1;2:2;;;27:1;24;17:12;2:2;1040:33269:6;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;12:1:-1;9;2:12;17935:104:6;;;:::i;:::-;;;;;;;;;;;;;;;;5441:34;;;:::i;8281:217::-;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;8281:217:6;;;;;;;:::i;:::-;;4272:112:9;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;4272:112:9;;:::i;5280:33:6:-;;;:::i;:::-;;;;;;;;;;;;;;;;;;;5608:38;;;:::i;4634:223:9:-;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;4634:223:9;;;;;;-1:-1:-1;;;;;4634:223:9;;:::i;5201:30:6:-;;;:::i;21515:197::-;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;21515:197:6;;;;;;;:::i;5808:205:9:-;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;5808:205:9;;;;;;-1:-1:-1;;;;;5808:205:9;;:::i;4313:57:6:-;;;:::i;18046:157::-;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;18046:157:6;-1:-1:-1;;;;;18046:157:6;;:::i;5813:36::-;;;:::i;9618:495::-;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;9618:495:6;;;;;;;:::i;14174:3640::-;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;14174:3640:6;;;;;;;:::i;23734:782::-;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;;;;;;23734:782:6;;;;;;;;:::i;18723:846::-;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;18723:846:6;-1:-1:-1;;;;;18723:846:6;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;18723:846:6;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;18723:846:6;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;18723:846:6;;;;;;;;;;;;;;;;;;;;;10248:529;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;10248:529:6;;:::i;6003:52::-;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;6003:52:6;-1:-1:-1;;;;;6003:52:6;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;21981:1120;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;21981:1120:6;;;-1:-1:-1;;;;;21981:1120:6;;;;;;;;;;:::i;12116:1291::-;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;12116:1291:6;;;;;;;:::i;3955:136:9:-;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;3955:136:9;;;;;;;:::i;:::-;;;;-1:-1:-1;;;;;3955:136:9;;;;;;;;;;;;;;2940:137;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;2940:137:9;;;;;;-1:-1:-1;;;;;2940:137:9;;:::i;:::-;;;;;;;;;;;;;;;;;;24840:449:6;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;;;;;;24840:449:6;;;;;;;;:::i;1717:49:9:-;;;:::i;18210:275:6:-;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;18210:275:6;-1:-1:-1;;;;;18210:275:6;;:::i;5855:62::-;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;5855:62:6;;:::i;17821:107::-;;;:::i;20437:438::-;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;20437:438:6;;;;;;;:::i;4241:66::-;;;:::i;19576:424::-;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;19576:424:6;-1:-1:-1;;;;;19576:424:6;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5652:45;;;:::i;3245:125:9:-;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;3245:125:9;;:::i;5091:226::-;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;5091:226:9;;;;;;-1:-1:-1;;;;;5091:226:9;;:::i;10912:564:6:-;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;10912:564:6;;:::i;5712:42::-;;;:::i;5770:37::-;;;:::i;11618:491::-;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;11618:491:6;;:::i;8505:831::-;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;8505:831:6;;;;;;;:::i;4427:20::-;;;:::i;21018:208::-;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;21018:208:6;;;;;;;;;:::i;5242:32::-;;;:::i;17935:104::-;18017:15;;17935:104;;:::o;5441:34::-;;;;:::o;8281:217::-;6283:10;:8;:10::i;:::-;:48;;;-1:-1:-1;4281:26:6;;;-1:-1:-1;;;4281:26:6;;;;;;;;;;;;6297:34;;6320:10;6297:7;:34::i;:::-;6275:97;;;;-1:-1:-1;;;6275:97:6;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8438:15:::1;6488;6467:17;:15;:17::i;:::-;:36;;6459:68;;;::::0;;-1:-1:-1;;;6459:68:6;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;-1:-1:-1;;;;;;;;;;;6459:68:6;;;;;;;;;;;;;::::1;;8469:22:::2;8486:4;8469:16;:22::i;:::-;6382:1:::1;8281:217:::0;;:::o;4272:112:9:-;4329:7;4355:12;;;;;;;;;;:22;;;;4272:112::o;5280:33:6:-;;;;;;:::o;5608:38::-;;;;:::o;4634:223:9:-;4725:6;:12;;;;;;;;;;:22;;;4717:45;;4749:12;:10;:12::i;:::-;4717:7;:45::i;:::-;4709:105;;;;-1:-1:-1;;;4709:105:9;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4825:25;4836:4;4842:7;4825:10;:25::i;:::-;4634:223;;:::o;5201:30:6:-;;;;:::o;21515:197::-;21627:17;6488:15;6467:17;:15;:17::i;:::-;:36;;6459:68;;;;;-1:-1:-1;;;6459:68:6;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;6459:68:6;;;;;;;;;;;;;;;6283:10:::1;:8;:10::i;:::-;:48;;;-1:-1:-1::0;4281:26:6::1;::::0;;-1:-1:-1;;;4281:26:6;;;;;;;;::::1;::::0;;;6297:34:::1;::::0;6320:10:::1;6297:7;:34::i;:::-;6275:97;;;;-1:-1:-1::0;;;6275:97:6::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;21681:24:::2;21693:11;21681;:24::i;5808:205:9:-:0;5905:12;:10;:12::i;:::-;-1:-1:-1;;;;;5894:23:9;:7;-1:-1:-1;;;;;5894:23:9;;5886:83;;;;-1:-1:-1;;;5886:83:9;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5980:26;5992:4;5998:7;5980:11;:26::i;4313:57:6:-;4364:6;4313:57;:::o;18046:157::-;-1:-1:-1;;;;;18163:19:6;18128:14;18163:19;;;:7;:19;;;;;:26;;:33;;18046:157::o;5813:36::-;;;;:::o;9618:495::-;9749:17;6488:15;6467:17;:15;:17::i;:::-;:36;;6459:68;;;;;-1:-1:-1;;;6459:68:6;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;6459:68:6;;;;;;;;;;;;;;;6616:17:::1;:15;:17::i;:::-;6596;;:37;6588:74;;;::::0;;-1:-1:-1;;;6588:74:6;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;-1:-1:-1;;;;;;;;;;;6588:74:6;;;;;;;;;;;;;::::1;;9823:10:::2;9806:14;9864:17;:15;:17::i;:::-;9843:38;;9894:32;9931:37;9949:6;9957:10;9931:17;:37::i;:::-;9891:77;;;;9979:29;;:::i;:::-;10011:43;:9:::0;10047:6;10011:43:::2;:35;:43;:::i;:::-;9979:75;;10064:42;10082:6;10090:7;10099:6;10064:17;:42::i;:::-;6672:1;;;;9618:495:::0;;;:::o;14174:3640::-;14353:17;6488:15;6467:17;:15;:17::i;:::-;:36;;6459:68;;;;;-1:-1:-1;;;6459:68:6;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;6459:68:6;;;;;;;;;;;;;;;6616:17:::1;:15;:17::i;:::-;6596;;:37;6588:74;;;::::0;;-1:-1:-1;;;6588:74:6;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;-1:-1:-1;;;;;;;;;;;6588:74:6;;;;;;;;;;;;;::::1;;14410:18:::2;14431:17;:15;:17::i;:::-;14410:38:::0;-1:-1:-1;14475:10:6::2;14458:14;14517:48;14475:10:::0;14410:38;14517:28:::2;:48::i;:::-;14495:70;;14576:23;14602;:5;:11;;:21;:23::i;:::-;14576:49;;14635:29;;:::i;:::-;14679:10:::0;;14675:3133:::2;;15435:15;15425:6;:25;;15417:65;;;::::0;;-1:-1:-1;;;15417:65:6;;::::2;;::::0;::::2;::::0;::::2;::::0;;;;::::2;::::0;;;;;;;;;;;;;::::2;;15501:19;::::0;::::2;;15497:1049;;-1:-1:-1::0;;;;;15598:18:6;::::2;;::::0;;;:10:::2;:18;::::0;;;;15555:70:::2;::::0;:11:::2;::::0;::::2;::::0;15618:6;15555:70:::2;:42;:70;:::i;:::-;15545:80:::0;-1:-1:-1;15643:37:6::2;:23;15545:80:::0;15643:37:::2;:28;:37;:::i;:::-;15735:17:::0;;15754:24:::2;::::0;;::::2;::::0;15703:76:::2;::::0;;;;;;;::::2;::::0;;;15723:10;;-1:-1:-1;;;;;15703:76:6;::::2;::::0;-1:-1:-1;;;;;;;;;;;15703:76:6;;;;;;;::::2;15828:17:::0;;15847:24:::2;::::0;;::::2;::::0;15802:70:::2;::::0;;;;;;;::::2;::::0;;;-1:-1:-1;;;;;15802:70:6;::::2;::::0;::::2;::::0;;;;;;;::::2;15497:1049;;;-1:-1:-1::0;;;;;15935:15:6;::::2;15911:21;15935:15:::0;;;:7:::2;:15;::::0;;;;;;16005:13:::2;::::0;::::2;27:10:-1::0;;16005:20:6::2;23:18:-1::0;::::2;45:23:::0;;16005:20:6;;;;;;;16092:19:::2;::::0;16005:20:::2;::::0;;::::2;;::::0;16077:35:::2;::::0;:10;;16092:19:::2;;16077:35;:14;:35;:::i;:::-;16043:69:::0;;16140:72:::2;:11;::::0;::::2;16183:20;::::0;::::2;16205:6:::0;16140:72:::2;:42;:72;:::i;:::-;16130:82:::0;-1:-1:-1;16231:34:6::2;:20;16130:82:::0;16231:34:::2;:25;:34;:::i;:::-;16283:30;:6:::0;16305:7;16283:30:::2;:21;:30;:::i;:::-;16454:31:::0;;16487:17;;16506:24:::2;::::0;;::::2;::::0;16434:97:::2;::::0;;;;;;;::::2;::::0;;;-1:-1:-1;;;;;16434:97:6;::::2;::::0;-1:-1:-1;;;;;;;;;;;16434:97:6;;;;;;;::::2;15497:1049;;;14675:3133;;;16580:20:::0;16576:108:::2;;16663:7;;;;;;;16576:108;-1:-1:-1::0;16698:21:6::2;::::0;;;;::::2;::::0;;;16708:11:::2;::::0;::::2;16698:21:::0;;;;;;;;;::::2;::::0;::::2;::::0;-1:-1:-1;16733:25:6;;;;16772:32;16823:19:::2;::::0;::::2;;16819:979;;-1:-1:-1::0;;;;;16867:18:6;::::2;;::::0;;;:10:::2;:18;::::0;;;;:32:::2;::::0;16891:7;16867:32:::2;:23;:32;:::i;:::-;16917:37;:23;16946:7:::0;16917:37:::2;:28;:37;:::i;:::-;17009:17:::0;;17028:24:::2;::::0;;::::2;::::0;16977:76:::2;::::0;;;;;;;::::2;::::0;;;16997:10;;-1:-1:-1;;;;;16977:76:6;::::2;::::0;-1:-1:-1;;;;;;;;;;;16977:76:6;;;;;;;::::2;17102:17:::0;;17121:24:::2;::::0;;::::2;::::0;17076:70:::2;::::0;;;;;;;::::2;::::0;;;-1:-1:-1;;;;;17076:70:6;::::2;::::0;::::2;::::0;;;;;;;::::2;16819:979;;;-1:-1:-1::0;;;;;17209:15:6;::::2;17185:21;17209:15:::0;;;:7:::2;:15;::::0;;;;;;17279:13:::2;::::0;::::2;27:10:-1::0;;17279:20:6::2;23:18:-1::0;::::2;45:23:::0;;17279:20:6;;;;;;;17366:19:::2;::::0;17279:20:::2;::::0;;::::2;;::::0;17351:35:::2;::::0;:10;;17366:19:::2;;17351:35;:14;:35;:::i;:::-;17317:69:::0;;17404:30;;:20:::2;::::0;::::2;:30:::0;::::2;::::0;::::2;::::0;;;;;17453:34:::2;:20;17427:7:::0;17453:34:::2;:25;:34;:::i;:::-;17505:30;:6:::0;17527:7;17505:30:::2;:21;:30;:::i;:::-;17680:31:::0;;17713:20:::2;::::0;::::2;:30:::0;17745:37;;;;17656:127:::2;::::0;;;;;::::2;::::0;::::2;::::0;;;;;;17668:10:::2;::::0;-1:-1:-1;;;;;;;;;;;17656:127:6;;;;;;;::::2;16819:979;;;6672:1;;;;;14174:3640:::0;;;:::o;23734:782::-;23866:17;6488:15;6467:17;:15;:17::i;:::-;:36;;6459:68;;;;;-1:-1:-1;;;6459:68:6;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;6459:68:6;;;;;;;;;;;;;;;6135:10:::1;:8;:10::i;:::-;6127:45;;;::::0;;-1:-1:-1;;;6127:45:6;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;-1:-1:-1;;;6127:45:6;;;;;;;;;;;;;::::1;;23943:6:::2;::::0;:31:::2;::::0;;-1:-1:-1;;;23943:31:6;;23968:4:::2;23943:31;::::0;::::2;::::0;;;23917:23:::2;::::0;-1:-1:-1;;;;;23943:6:6::2;::::0;:16:::2;::::0;:31;;;;;::::2;::::0;;;;;;;;:6;:31;::::2;;2:2:-1::0;::::2;;;27:1;24::::0;17:12:::2;2:2;23943:31:6;;;;8:9:-1;5:2;;;45:16;42:1;39::::0;24:38:::2;77:16;74:1;67:27;5:2;23943:31:6;;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28::::0;21:12:::2;4:2;-1:-1:::0;23943:31:6;24049:19:::2;::::0;24021:23:::2;::::0;23943:31;;-1:-1:-1;23984:34:6::2;::::0;24021:48:::2;::::0;::::2;:27;:48;:::i;:::-;23984:85:::0;-1:-1:-1;24275:20:6::2;24298:47;:15:::0;23984:85;24298:47:::2;:19;:47;:::i;:::-;24363:6;::::0;:44:::2;::::0;;-1:-1:-1;;;24363:44:6;;-1:-1:-1;;;;;24363:44:6;;::::2;;::::0;::::2;::::0;;;;;;;;;24275:70;;-1:-1:-1;24363:6:6;::::2;::::0;:15:::2;::::0;:44;;;;;::::2;::::0;;;;;;;;;:6:::2;::::0;:44;::::2;;2:2:-1::0;::::2;;;27:1;24::::0;17:12:::2;2:2;24363:44:6;;;;8:9:-1;5:2;;;45:16;42:1;39::::0;24:38:::2;77:16;74:1;67:27;5:2;24363:44:6;;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28::::0;21:12:::2;4:2;-1:-1:::0;24363:44:6;24355:89:::2;;;::::0;;-1:-1:-1;;;24355:89:6;;::::2;;::::0;::::2;::::0;;;;;;;::::2;::::0;;;;;;;;;;;;;::::2;;24459:50;::::0;;-1:-1:-1;;;;;24459:50:6;::::2;::::0;;::::2;::::0;::::2;::::0;;;;;::::2;::::0;;;;;;;;;::::2;6182:1;;;23734:782:::0;;;:::o;18723:846::-;-1:-1:-1;;;;;18962:19:6;;18925:34;18962:19;;;:7;:19;;;;;:26;;19015:19;;18813:26;;;;;;18962;19048:11;;19044:519;;19101:6;19087:21;;;5:9:-1;2:2;;;27:1;24;17:12;2:2;19087:21:6;;;;;;;;;;;;;;;;;;;;;;;29:2:-1;21:6;17:15;125:4;109:14;101:6;88:42;144:17;;-1:-1;19087:21:6;;19075:33;;19155:6;19141:21;;;5:9:-1;2:2;;;27:1;24;17:12;2:2;19141:21:6;;;;;;;;;;;;;;;;;;;;;;;29:2:-1;21:6;17:15;125:4;109:14;101:6;88:42;144:17;;-1:-1;19141:21:6;;19122:40;;19209:6;19195:21;;;5:9:-1;2:2;;;27:1;24;17:12;2:2;19195:21:6;;;;;;;;;;;;;;;;;;;;;;;29:2:-1;21:6;17:15;125:4;109:14;101:6;88:42;144:17;;-1:-1;19195:21:6;-1:-1:-1;19176:40:6;-1:-1:-1;19236:9:6;19231:322;19253:6;19249:1;:10;19231:322;;;19284:22;19309:12;19322:1;19309:15;;;;;;;;;;;;;;;;;;19284:40;;19342:24;19369:2;:8;;19342:35;;19410:1;:11;;;19395:9;19405:1;19395:12;;;;;;;;;;;;;:26;;;;;19461:1;:18;;;19439:16;19456:1;19439:19;;;;;;;;;;;;;:40;;;;;19519:2;:19;;;19497:16;19514:1;19497:19;;;;;;;;;;;;;;;;;:41;-1:-1:-1;;19261:3:6;;19231:322;;;;19044:519;18723:846;;;;;;;:::o;10248:529::-;10364:17;6488:15;6467:17;:15;:17::i;:::-;:36;;6459:68;;;;;-1:-1:-1;;;6459:68:6;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;6459:68:6;;;;;;;;;;;;;;;6616:17:::1;:15;:17::i;:::-;6596;;:37;6588:74;;;::::0;;-1:-1:-1;;;6588:74:6;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;-1:-1:-1;;;;;;;;;;;6588:74:6;;;;;;;;;;;;;::::1;;10438:10:::2;10421:14;10479:17;:15;:17::i;:::-;10458:38;;10509:32;10547:37;10565:6;10573:10;10547:17;:37::i;:::-;10506:78;;;;10595:29;;:::i;:::-;10654:19:::0;;10634:39;;;10654:19:::2;10683:23:::0;;10717:53:::2;::::0;10735:6;;10634:7;;10717:17:::2;:53::i;:::-;6672:1;;;;10248:529:::0;;:::o;6003:52::-;;;;;;;;;;;;;;;;;;;:::o;21981:1120::-;22149:17;6488:15;6467:17;:15;:17::i;:::-;:36;;6459:68;;;;;-1:-1:-1;;;6459:68:6;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;6459:68:6;;;;;;;;;;;;;;;6135:10:::1;:8;:10::i;:::-;6127:45;;;::::0;;-1:-1:-1;;;6127:45:6;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;-1:-1:-1;;;6127:45:6;;;;;;;;;;;;;::::1;;22204:11:::0;22200:174:::2;;22240:19;;22231:28;;22200:174;;;22308:19;;22298:6;:29;;22290:73;;;::::0;;-1:-1:-1;;;22290:73:6;;::::2;;::::0;::::2;::::0;::::2;::::0;;;;::::2;::::0;;;;;;;;;;;;;::::2;;22588:6;::::0;:31:::2;::::0;;-1:-1:-1;;;22588:31:6;;22613:4:::2;22588:31;::::0;::::2;::::0;;;22562:23:::2;::::0;-1:-1:-1;;;;;22588:6:6::2;::::0;:16:::2;::::0;:31;;;;;::::2;::::0;;;;;;;;:6;:31;::::2;;2:2:-1::0;::::2;;;27:1;24::::0;17:12:::2;2:2;22588:31:6;;;;8:9:-1;5:2;;;45:16;42:1;39::::0;24:38:::2;77:16;74:1;67:27;5:2;22588:31:6;;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28::::0;21:12:::2;4:2;-1:-1:::0;22588:31:6;22666:23:::2;::::0;22588:31;;-1:-1:-1;22629:34:6::2;::::0;22666:35:::2;::::0;22694:6;22666:35:::2;:27;:35;:::i;:::-;22629:72;;22749:15;22719:26;:45;;22711:81;;;::::0;;-1:-1:-1;;;22711:81:6;;::::2;;::::0;::::2;::::0;::::2;::::0;;;;::::2;::::0;;;;;;;;;;;;;::::2;;22811:6;::::0;:38:::2;::::0;;-1:-1:-1;;;22811:38:6;;-1:-1:-1;;;;;22811:38:6;;::::2;;::::0;::::2;::::0;;;;;;;;;:6;;;::::2;::::0;:15:::2;::::0;:38;;;;;::::2;::::0;;;;;;;;:6:::2;::::0;:38;::::2;;2:2:-1::0;::::2;;;27:1;24::::0;17:12:::2;2:2;22811:38:6;;;;8:9:-1;5:2;;;45:16;42:1;39::::0;24:38:::2;77:16;74:1;67:27;5:2;22811:38:6;;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28::::0;21:12:::2;4:2;-1:-1:::0;22811:38:6;22803:83:::2;;;::::0;;-1:-1:-1;;;22803:83:6;;::::2;;::::0;::::2;::::0;;;;;;;::::2;::::0;;;;;;;;;;;;;::::2;;23000:19;:29:::0;;;;::::2;::::0;;23045:49:::2;::::0;;-1:-1:-1;;;;;23045:49:6;::::2;::::0;;::::2;::::0;::::2;::::0;;;;;::::2;::::0;;;;;;;;;::::2;6182:1;;21981:1120:::0;;;;:::o;12116:1291::-;12248:17;6488:15;6467:17;:15;:17::i;:::-;:36;;6459:68;;;;;-1:-1:-1;;;6459:68:6;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;6459:68:6;;;;;;;;;;;;;;;6616:17:::1;:15;:17::i;:::-;6596;;:37;6588:74;;;::::0;;-1:-1:-1;;;6588:74:6;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;-1:-1:-1;;;;;;;;;;;6588:74:6;;;;;;;;;;;;;::::1;;12313:11:::0;12305:55:::2;;;::::0;;-1:-1:-1;;;12305:55:6;;::::2;;::::0;::::2;::::0;::::2;::::0;;;;::::2;::::0;;;;;;;;;;;;;::::2;;12371:18;12392:17;:15;:17::i;:::-;12371:38;;12423:32;12461:41;12479:10;12491;12461:17;:41::i;:::-;12420:82;;;;12848:19;12870:52;12899:10;12911;12870:28;:52::i;:::-;12848:74;;12932:29;;:::i;:::-;12964:54;:9:::0;12998:11:::2;::::0;::::2;13011:6:::0;12964:54:::2;:33;:54;:::i;:::-;12932:86:::0;-1:-1:-1;13028:37:6::2;:23;12932:86:::0;13028:37:::2;:28;:37;:::i;:::-;13314:28;::::0;::::2;::::0;13344:17;;13363:24:::2;::::0;;::::2;::::0;13292:96:::2;::::0;;;;;;;::::2;::::0;;;13302:10:::2;::::0;13292:96:::2;::::0;;;;;;;::::2;6672:1;;;;12116:1291:::0;;;:::o;3955:136:9:-;4028:7;4054:12;;;;;;;;;;:30;;4078:5;4054:30;:23;:30;:::i;:::-;4047:37;;3955:136;;;;;:::o;2940:137::-;3009:4;3032:12;;;;;;;;;;:38;;3062:7;3032:38;:29;:38;:::i;24840:449:6:-;24958:17;6488:15;6467:17;:15;:17::i;:::-;:36;;6459:68;;;;;-1:-1:-1;;;6459:68:6;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;6459:68:6;;;;;;;;;;;;;;;6135:10:::1;:8;:10::i;:::-;6127:45;;;::::0;;-1:-1:-1;;;6127:45:6;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;-1:-1:-1;;;6127:45:6;;;;;;;;;;;;;::::1;;25032:17:::2;:15;:17::i;:::-;25013:15;;:36;;25005:76;;;::::0;;-1:-1:-1;;;25005:76:6;;::::2;;::::0;::::2;::::0;::::2;::::0;;;;::::2;::::0;;;;;;;;;;;;;::::2;;25117:6;::::0;:31:::2;::::0;;-1:-1:-1;;;25117:31:6;;25142:4:::2;25117:31;::::0;::::2;::::0;;;25091:23:::2;::::0;-1:-1:-1;;;;;25117:6:6::2;::::0;:16:::2;::::0;:31;;;;;::::2;::::0;;;;;;;;:6;:31;::::2;;2:2:-1::0;::::2;;;27:1;24::::0;17:12:::2;2:2;25117:31:6;;;;8:9:-1;5:2;;;45:16;42:1;39::::0;24:38:::2;77:16;74:1;67:27;5:2;25117:31:6;;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28::::0;21:12:::2;4:2;-1:-1:::0;25117:31:6;25166:6:::2;::::0;:47:::2;::::0;;-1:-1:-1;;;25166:47:6;;-1:-1:-1;;;;;25166:47:6;;::::2;;::::0;::::2;::::0;;;;;;;;;25117:31;;-1:-1:-1;25166:6:6;::::2;::::0;:15:::2;::::0;:47;;;;;25117:31:::2;::::0;25166:47;;;;;;;;:6:::2;::::0;:47;::::2;;2:2:-1::0;::::2;;;27:1;24::::0;17:12:::2;2:2;25166:47:6;;;;8:9:-1;5:2;;;45:16;42:1;39::::0;24:38:::2;77:16;74:1;67:27;5:2;25166:47:6;;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28::::0;21:12:::2;4:2;-1:-1:::0;25166:47:6;25158:56:::2;;12:1:-1;9::::0;2:12:::2;25158:56:6;25229:16;::::0;::::2;::::0;;;::::2;25268:13;-1:-1:-1::0;;;;;25255:27:6::2;;1717:49:9::0;1762:4;1717:49;:::o;18210:275:6:-;-1:-1:-1;;;;;18383:19:6;18293:17;18383:19;;;:7;:19;;;;;18430;;18451:26;;;;;18430:19;;18210:275::o;5855:62::-;;;;;;;;;;;;;;;;;;;:::o;17821:107::-;17902:19;;17821:107;:::o;20437:438::-;20576:17;6488:15;6467:17;:15;:17::i;:::-;:36;;6459:68;;;;;-1:-1:-1;;;6459:68:6;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;6459:68:6;;;;;;;;;;;;;;;20613:11;20609:48:::1;;20640:7;;20609:48;20675:6;::::0;:54:::1;::::0;;-1:-1:-1;;;20675:54:6;;20695:10:::1;20675:54;::::0;::::1;::::0;20715:4:::1;20675:54:::0;;;;;;;;;;;;-1:-1:-1;;;;;20675:6:6;;::::1;::::0;:19:::1;::::0;:54;;;;;::::1;::::0;;;;;;;;;:6:::1;::::0;:54;::::1;;2:2:-1::0;::::1;;;27:1;24::::0;17:12:::1;2:2;20675:54:6;;;;8:9:-1;5:2;;;45:16;42:1;39::::0;24:38:::1;77:16;74:1;67:27;5:2;20675:54:6;;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28::::0;21:12:::1;4:2;-1:-1:::0;20675:54:6;20667:82:::1;;;::::0;;-1:-1:-1;;;20667:82:6;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;-1:-1:-1;;;20667:82:6;;;;;;;;;;;;;::::1;;20781:19;::::0;:31:::1;::::0;20805:6;20781:31:::1;:23;:31;:::i;:::-;20759:19;:53:::0;20827:41:::1;::::0;;20849:10:::1;20827:41:::0;;::::1;::::0;::::1;::::0;;;;;::::1;::::0;;;;;;;;;::::1;20437:438:::0;;;:::o;4241:66::-;4281:26;;;-1:-1:-1;;;4281:26:6;;;;;;;;;;;;4241:66;:::o;19576:424::-;-1:-1:-1;;;;;19772:19:6;19643:17;19772:19;;;:7;:19;;;;;19813:11;;;:21;19863:28;;;;19914:16;;19863:28;19965;;;;19813:21;;19863:28;;19914:16;19965:28;19576:424::o;5652:45::-;;;;;;:::o;3245:125:9:-;3308:7;3334:12;;;;;;;;;;:29;;:27;:29::i;5091:226::-;5183:6;:12;;;;;;;;;;:22;;;5175:45;;5207:12;:10;:12::i;5175:45::-;5167:106;;;;-1:-1:-1;;;5167:106:9;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;10912:564:6;11035:17;6488:15;6467:17;:15;:17::i;:::-;:36;;6459:68;;;;;-1:-1:-1;;;6459:68:6;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;6459:68:6;;;;;;;;;;;;;;;6616:17:::1;:15;:17::i;:::-;6596;;:37;6588:74;;;::::0;;-1:-1:-1;;;6588:74:6;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;-1:-1:-1;;;;;;;;;;;6588:74:6;;;;;;;;;;;;;::::1;;11109:10:::2;11092:14;11150:17;:15;:17::i;:::-;11129:38;;11180:32;11218:37;11236:6;11244:10;11218:17;:37::i;:::-;11177:78;;;;11266:29;;:::i;:::-;11332:26;::::0;::::2;::::0;;11305:24:::2;::::0;::::2;:53:::0;;;11397:1:::2;11368:30:::0;;;11409:60:::2;::::0;11427:6;;11305:7;;11409:17:::2;:60::i;5712:42::-:0;;;;;;:::o;5770:37::-;;;;:::o;11618:491::-;11739:17;6488:15;6467:17;:15;:17::i;:::-;:36;;6459:68;;;;;-1:-1:-1;;;6459:68:6;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;6459:68:6;;;;;;;;;;;;;;;6616:17:::1;:15;:17::i;:::-;6596;;:37;6588:74;;;::::0;;-1:-1:-1;;;6588:74:6;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;-1:-1:-1;;;;;;;;;;;6588:74:6;;;;;;;;;;;;;::::1;;11813:10:::2;11796:14;11854:17;:15;:17::i;:::-;11833:38;;11884:32;11922:37;11940:6;11948:10;11922:17;:37::i;:::-;-1:-1:-1::0;11970:59:6::2;::::0;;;;::::2;::::0;;;;;;;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;11881:78;;-1:-1:-1;11970:59:6::2;::::0;-1:-1:-1;11988:6:6;;12007:21:::2;11881:78:::0;12007:19:::2;:21::i;:::-;11970:17;:59::i;:::-;12068:1;12039:26;::::0;::::2;:30:::0;;;12079:23;;-1:-1:-1;;;;11618:491:6:o;8505:831::-;8635:17;6488:15;6467:17;:15;:17::i;:::-;:36;;6459:68;;;;;-1:-1:-1;;;6459:68:6;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;6459:68:6;;;;;;;;;;;;;;;6616:17:::1;:15;:17::i;:::-;6596;;:37;6588:74;;;::::0;;-1:-1:-1;;;6588:74:6;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;-1:-1:-1;;;;;;;;;;;6588:74:6;;;;;;;;;;;;;::::1;;8712:11:::0;;;::::2;::::0;8733:352:::2;;8773:6;::::0;:54:::2;::::0;;-1:-1:-1;;;8773:54:6;;8793:10:::2;8773:54;::::0;::::2;::::0;8813:4:::2;8773:54:::0;;;;;;;;;;;;-1:-1:-1;;;;;8773:6:6;;::::2;::::0;:19:::2;::::0;:54;;;;;::::2;::::0;;;;;;;;;:6:::2;::::0;:54;::::2;;2:2:-1::0;::::2;;;27:1;24::::0;17:12:::2;2:2;8773:54:6;;;;8:9:-1;5:2;;;45:16;42:1;39::::0;24:38:::2;77:16;74:1;67:27;5:2;8773:54:6;;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28::::0;21:12:::2;4:2;-1:-1:::0;8773:54:6;8765:82:::2;;;::::0;;-1:-1:-1;;;8765:82:6;;::::2;;::::0;::::2;::::0;::::2;::::0;;;;-1:-1:-1;;;8765:82:6;;;;;;;;;;;;;::::2;;8887:23;::::0;:35:::2;::::0;8915:6;8887:35:::2;:27;:35;:::i;:::-;8861:23;:61:::0;8972:23:::2;:33:::0;:45:::2;::::0;9010:6;8972:45:::2;:37;:45;:::i;:::-;8936:23;:81:::0;9036:38:::2;::::0;;;;;;;9055:10:::2;::::0;9036:38:::2;::::0;;;;;::::2;::::0;;::::2;8733:352;9095:18;9116:17;:15;:17::i;:::-;9095:38;;9146:32;9183:41;9201:10;9213;9183:17;:41::i;:::-;9143:81;;;;9239:12;9235:95;;;9289:19:::0;;:31:::2;::::0;9313:6;9289:31:::2;:23;:31;:::i;:::-;9267:53:::0;;-1:-1:-1;;;;;8505:831:6:o;4427:20::-;;;-1:-1:-1;;;;;4427:20:6;;:::o;21018:208::-;21135:17;6488:15;6467:17;:15;:17::i;:::-;:36;;6459:68;;;;;-1:-1:-1;;;6459:68:6;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;6459:68:6;;;;;;;;;;;;;;;6283:10:::1;:8;:10::i;:::-;:48;;;-1:-1:-1::0;4281:26:6::1;::::0;;-1:-1:-1;;;4281:26:6;;;;;;;;::::1;::::0;;;6297:34:::1;::::0;6320:10:::1;6297:7;:34::i;:::-;6275:97;;;;-1:-1:-1::0;;;6275:97:6::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;21189:30:::2;21207:11;21189:17;:30::i;5242:32::-:0;;;;:::o;874:176:10:-;932:7;963:5;;;986:6;;;;978:46;;;;;-1:-1:-1;;;978:46:10;;;;;;;;;;;;;;;;;;;;;;;;;;;4864:141:15;4934:4;4957:41;4962:3;-1:-1:-1;;;;;4982:14:15;;4957:4;:41::i;25673:111:6:-;25715:4;25738:39;25715:4;25766:10;25738:7;:39::i;:::-;25731:46;;25673:111;:::o;25560:106::-;25647:12;25560:106;:::o;26015:390::-;26093:21;;26146:148;;;;;;;;;;26195:17;:15;:17::i;:::-;26146:148;;;;;;;;;-1:-1:-1;26124:19:6;;;:14;:19;;;;;:170;;;;;;;;;;;;26328:21;;:28;;;:25;:28;:::i;:::-;26304:21;:52;26372:26;;;;;;;;26388:3;;26372:26;;;;;;;;;;26015:390;;:::o;590:104:8:-;677:10;590:104;:::o;7015:184:9:-;7088:6;:12;;;;;;;;;;:33;;7113:7;7088:33;:24;:33;:::i;:::-;7084:109;;;7169:12;:10;:12::i;:::-;-1:-1:-1;;;;;7142:40:9;7160:7;-1:-1:-1;;;;;7142:40:9;7154:4;7142:40;;;;;;;;;;7015:184;;:::o;26933:255:6:-;26999:26;27028:17;:15;:17::i;:::-;26999:46;;27089:18;27075:11;:32;:67;;27131:11;27075:67;;;27110:18;27075:67;27055:17;:87;;;27157:24;;;;;;;;;;;;;;;;26933:255;;:::o;7205:188:9:-;7279:6;:12;;;;;;;;;;:36;;7307:7;7279:36;:27;:36;:::i;:::-;7275:112;;;7363:12;:10;:12::i;:::-;-1:-1:-1;;;;;7336:40:9;7354:7;-1:-1:-1;;;;;7336:40:9;7348:4;7336:40;;;;;;;;;;7205:188;;:::o;31612:2694:6:-;31706:39;;:::i;:::-;-1:-1:-1;;;;;31835:15:6;;31747:32;31835:15;;;:7;:15;;;;;;;;31932:10;:18;;;;;;31747:32;31897:13;;;31747:32;31961:1673;31983:19;;31979:23;;31961:1673;;;32020:20;;:::i;:::-;32043:12;32056:1;32043:15;;;;;;;;;;;;;;;;;32020:38;;;;;;;;32043:15;;;;;;;32020:38;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;32077:18;;32020:38;;-1:-1:-1;32077:29:6;-1:-1:-1;32073:191:6;;;-1:-1:-1;32126:3:6;;32241:8;;32073:191;32340:7;;;;:17;32308:27;;:50;;;:31;:50;:::i;:::-;32278:80;;32652:7;;;;;:24;;;32613:34;;;;:64;;;:38;:64;:::i;:::-;32576:34;;;:101;32978:19;;-1:-1:-1;;32978:23:6;33019:13;;;33015:92;;33070:12;33083:8;33070:22;;;;;;;;;;;;;;;;;;33052:12;33065:1;33052:15;;;;;;;;;;;;;;;;:40;;:15;;;;;:40;;;;;;;;;;;;;;;;;;;;33015:92;33605:12;:18;;;;;;;;;;;;;;;-1:-1:-1;;33605:18:6;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;31961:1673:6;;;;-1:-1:-1;33699:19:6;;33695:77;;-1:-1:-1;;;;;33746:15:6;;;;;;:7;:15;;;;;33739:22;;;;;;;;;33746:15;33739:22;;;;33746:15;33739:22;:::i;:::-;;;33695:77;33794:27;;:32;;;:75;;-1:-1:-1;33830:34:6;;;;:39;;33794:75;33782:87;;33883:9;33879:421;;;33940:27;;33969:34;;;;;33914:90;;;;;;;;;;;;-1:-1:-1;;;;;33914:90:6;;;;;;;;;;;;34019:44;:20;34045:17;34019:44;:25;:44;:::i;:::-;34081:19;;:24;34077:103;;34125:40;:6;34147:17;34125:40;:21;:40;:::i;:::-;34194:47;:23;34223:17;34194:47;:28;:47;:::i;:::-;34256:33;:9;34271:17;34256:33;:14;:33;:::i;:::-;31612:2694;;;;;;;:::o;2944:671:1:-;3040:20;;:::i;:::-;3105:6;3080:4;:21;;;:31;3076:533;;3151:21;;;;:33;;3177:6;3151:33;:25;:33;:::i;:::-;3127:21;;;:57;3198:24;;;:33;;;3076:533;;;3293:21;;;;3282:33;;:6;;:33;:10;:33;:::i;:::-;3262:53;;;3459:14;;:37;;;:18;:37;:::i;:::-;3442:54;;3538:21;;;;;;3511:24;;;:48;3442:14;3573:25;;-1:-1:-1;3511:24:1;2944:671::o;27885:818:6:-;27999:11;;27995:702;;28057:7;:24;;;28034:19;;:47;;28026:92;;;;;-1:-1:-1;;;28026:92:6;;;;;;;;;;;;;;;;;;;;;;;;;;;;;28140:6;;:31;;;-1:-1:-1;;;28140:31:6;;-1:-1:-1;;;;;28140:31:6;;;;;;;;;;;;;;;:6;;;;;:15;;:31;;;;;;;;;;;;;;:6;;:31;;;2:2:-1;;;;27:1;24;17:12;2:2;28140:31:6;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;28140:31:6;;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;28140:31:6;28132:59;;;;;-1:-1:-1;;;28132:59:6;;;;;;;;;;;;-1:-1:-1;;;28132:59:6;;;;;;;;;;;;;;;28252:24;;;;28228:19;;:49;;;:23;:49;:::i;:::-;28206:19;:71;28345:17;;28317:23;;:46;;;:27;:46;:::i;:::-;28291:23;:72;28377:37;:23;28406:7;28377:37;:28;:37;:::i;:::-;28641:17;;28660:24;;;;;28620:65;;;;;;;;;;;;28629:10;;28620:65;;;;;;;;;27885:818;;;:::o;28710:2895::-;-1:-1:-1;;;;;28858:15:6;;28815:19;28858:15;;;:7;:15;;;;;;28903:23;:11;;;:21;:23::i;:::-;28883:43;-1:-1:-1;28940:14:6;;28936:1369;;29070:16;;29349:28;;;;29334:879;29383:21;;29379:1;:25;29334:879;;;29429:37;29469:17;;;:14;:17;;;;;29697:19;;:34;-1:-1:-1;29697:34:6;29689:71;;;;;-1:-1:-1;;;29689:71:6;;;;;;;;;;;;;;;;;;;;;;;;;;;;29868:21;;29798:8;;29841:1;29837:5;;;29864:25;;29860:192;;;29913:42;29958:17;;;:14;:17;;;;;30009:24;;-1:-1:-1;29860:192:6;30082:75;30107:9;30118:8;:13;;;30145:11;30133:9;:23;30082:24;:75::i;:::-;30070:87;-1:-1:-1;30189:9:6;;-1:-1:-1;;;29406:3:6;;29334:879;;;-1:-1:-1;30272:11:6;;;:21;30258:36;;:9;;:36;:13;:36;:::i;:::-;30227:28;;;:67;-1:-1:-1;28936:1369:6;30315:27;;;30384:21;;:58;;30441:1;30384:58;;;30437:1;30413:21;;:25;30384:58;30352:28;;;:91;;;31546:11;;;:21;31569:28;;;;31486:112;;;;;;;;;;;;;;;-1:-1:-1;;;;;31486:112:6;;;;;;;;;;;;28710:2895;;;;;:::o;1046:150:1:-;1166:22;;;;1146:15;;1116:7;;1146:43;;:15;:43;:19;:43;:::i;4355:238::-;4474:20;;:::i;:::-;4520:39;4546:4;4552:6;4520:25;:39::i;:::-;4510:49;;4569:17;4574:2;4578:7;4569:4;:17::i;:::-;4355:238;;;;;:::o;1594:220::-;1710:16;;1693:12;;:34;;;:16;:34;:::i;:::-;1678:49;;1783:23;;;;1759:19;;;;:48;;;:23;:48;:::i;:::-;1737:2;:19;;:70;;;;1594:220;;:::o;1321:134:10:-;1379:7;1405:43;1409:1;1412;1405:43;;;;;;;;;;;;;;;;;:3;:43::i;3873:224:1:-;3985:20;;:::i;:::-;4031:32;4050:4;4056:6;4031:18;:32::i;2065:230::-;2187:16;;2168:14;;:36;;;:18;:36;:::i;:::-;2151:53;;2264:23;;;;2238:21;;;;:50;;;:25;:50;:::i;6085:147:15:-;6159:7;6201:22;6205:3;6217:5;6201:3;:22::i;5401:156::-;5481:4;5504:46;5514:3;-1:-1:-1;;;;;5534:14:15;;5504:9;:46::i;5638:115::-;5701:7;5727:19;5735:3;5727:7;:19::i;26522:148:6:-;26592:19;:33;;;;;-1:-1:-1;;26592:33:6;;;;;;;;26640:23;;;;;;;;;;;;;;;;26522:148;:::o;1611:404:15:-;1674:4;1695:21;1705:3;1710:5;1695:9;:21::i;:::-;1690:319;;-1:-1:-1;27:10;;39:1;23:18;;;45:23;;1732:11:15;:23;;;;;;;;;;;;;1912:18;;1890:19;;;:12;;;:19;;;;;;:40;;;;1944:11;;1690:319;-1:-1:-1;1993:5:15;1986:12;;5173:147;5246:4;5269:44;5277:3;-1:-1:-1;;;;;5297:14:15;;5269:7;:44::i;1391:457:3:-;1494:7;1524:317;1557:260;1579:197;1619:26;1643:1;1619:22;:26::i;:::-;1667:87;1714:5;1747:6;1667:18;:87::i;:::-;1579:17;:197::i;:::-;1798:1;1557:3;:260::i;:::-;1831:9;1524:18;:317::i;:::-;1517:324;1391:457;-1:-1:-1;;;;1391:457:3:o;1746:187:10:-;1832:7;1867:12;1859:6;;;;1851:29;;;;-1:-1:-1;;;1851:29:10;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;1851:29:10;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;1902:5:10;;;1746:187::o;2302:635:1:-;2391:20;;:::i;:::-;2431:14;;:24;-1:-1:-1;2427:504:1;;2488:14;;:26;;2507:6;2488:26;:18;:26;:::i;:::-;2471:43;;2528:26;;;2427:504;;;2622:14;;2611:26;;:6;;:26;:10;:26;:::i;:::-;2584:24;;;:53;;;2788:21;;;;:51;;;:25;:51;:::i;:::-;2764:21;;;:75;2874:14;;2854:34;;2874:14;2902:18;;;-1:-1:-1;2854:34:1;2302:635::o;4423:201:15:-;4517:18;;4490:7;;4517:26;-1:-1:-1;4509:73:15;;;;-1:-1:-1;;;4509:73:15;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4599:3;:11;;4611:5;4599:18;;;;;;;;;;;;;;;;4592:25;;4423:201;;;;:::o;3776:127::-;3849:4;3872:19;;;:12;;;;;:19;;;;;;:24;;;3776:127::o;3984:107::-;4066:18;;3984:107::o;2183:1512::-;2249:4;2386:19;;;:12;;;:19;;;;;;2420:15;;2416:1273;;2849:18;;-1:-1:-1;;2801:14:15;;;;2849:22;;;;2777:21;;2849:3;;:22;;3131;;;;;;;;;;;;;;3111:42;;3274:9;3245:3;:11;;3257:13;3245:26;;;;;;;;;;;;;;;;;;;:38;;;;3349:23;;;3391:1;3349:12;;;:23;;;;;;3375:17;;;3349:43;;3498:17;;3349:3;;3498:17;;;;;;;;;;;;;;;;;;;;;;3590:3;:12;;:19;3603:5;3590:19;;;;;;;;;;;3583:26;;;3631:4;3624:11;;;;;;;;2416:1273;3673:5;3666:12;;;;;1928:134:0;1981:6;2009:18;2004:1;:23;;1995:33;;12:1:-1;9;2:12;1995:33:0;-1:-1:-1;2054:2:0;2049:7;;1928:134::o;8234:203::-;8294:6;8317;8308:16;;12:1:-1;9;2:12;8308:16:0;8330:14;8347:12;8354:1;8357;8347:5;:12::i;:::-;8330:29;-1:-1:-1;;;;;;;;;;;8374:29:0;;;;8365:39;;12:1:-1;9;2:12;3364:191:0;3421:6;3451:13;:9;;;:13;;;;;-1:-1:-1;;;;;;3479:19:0;;;;;:42;;-1:-1:-1;;;;;;3502:19:0;;;3479:42;3470:52;;12:1:-1;9;2:12;1013:371:3;1079:8;1107:26;1131:1;1107:22;:26::i;:::-;1103:30;;1144:234;1151:6;;1144:234;;1182:1;1178:5;;1177:12;1173:195;;1213:24;1232:1;1235;1213:17;:24::i;:::-;1209:28;;1260:1;1255:6;;;;1173:195;;;1304:24;1323:1;1326;1304:17;:24::i;:::-;1300:28;;1352:1;1346:7;;;;;1173:195;1144:234;;5958:455:0;6017:7;6036:6;6032:20;;-1:-1:-1;6051:1:0;6044:8;;6032:20;6073:1;6068;:6;;;;6059:16;;12:1:-1;9;2:12;6059:16:0;6096:11;;;;-1:-1:-1;;;;;6111:38:0;;6096:54;;6155:2;6095:62;;6196:3;6191:8;;;6176:24;-1:-1:-1;;;;;6216:56:0;;;6207:66;;12:1:-1;9;2:12;6207:66:0;6286:2;6279:9;6316:71;;6304:83;;;6295:93;;12:1:-1;9;2:12;6295:93:0;6401:7;;5958:455;-1:-1:-1;;;5958:455:0:o;20447:1218::-;20507:7;20531:6;20522:16;;12:1:-1;9;2:12;20522:16:0;20545:14;-1:-1:-1;;;;;20570:1:0;:55;20566:1005;;20654:1;20648:2;20643:1;:7;;20642:13;;;;;;20633:22;;20566:1005;;;20688:3;20712:8;;;20738:11;20732:17;;20728:48;;20760:2;20764:9;;;;20753;20728:48;20793:7;20787:2;:13;20783:44;;20811:2;20815:9;;;;20804;20783:44;20844:5;20838:2;:11;20834:40;;20860:1;20863:8;;;;20853;20834:40;20891:4;20885:2;:10;20881:39;;20906:1;20909:8;;;;20899;20881:39;20937:3;20931:2;:9;20927:38;;20951:1;20954:8;;;;20944;20927:38;20982:3;20976:2;:9;20972:23;;20994:1;20987:8;;;;20972:23;21081:3;21075;:9;21070:1;21066;:5;:18;;21088:1;21065:24;21057:3;21051;:9;21046:1;:14;;21045:45;;;;;;21036:54;;-1:-1:-1;;;;;21107:6:0;:44;;21098:54;;12:1:-1;9;2:12;21098:54:0;21189:3;21184:8;;;21174:19;;-1:-1:-1;;;;;21224:38:0;;21214:49;;21290:3;21285:8;;;21319:2;21314:7;;;21334;;;21330:20;;;21349:1;21343:7;;;;21330:20;21422:3;21416:9;;;;21358:8;;21437:7;;;21433:20;;;21452:1;21446:7;;;;21433:20;21461:8;;;21535:3;21529:9;;;21523:15;;21515:24;;;;21563:1;21558:2;:6;;;;;;21548:16;;;;20566:1005;;;;;;;-1:-1:-1;;;;;21586:6:0;:44;;21577:54;;12:1:-1;9;2:12;4186:197:0;4243:6;4273:13;:9;;;:13;;;;;4290:2;4273:19;-1:-1:-1;;;;;;4307:19:0;;;;;:42;;-1:-1:-1;;;;;;4330:19:0;;;4298:52;;12:1:-1;9;2:12;-1:-1;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;:::i;:::-;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\",\n  \"source\": \"// SPDX-License-Identifier:Apache-2.0\\n//------------------------------------------------------------------------------\\n//\\n//   Copyright 2020 Fetch.AI Limited\\n//\\n//   Licensed under the Apache License, Version 2.0 (the \\\"License\\\");\\n//   you may not use this file except in compliance with the License.\\n//   You may obtain a copy of the License at\\n//\\n//       http://www.apache.org/licenses/LICENSE-2.0\\n//\\n//   Unless required by applicable law or agreed to in writing, software\\n//   distributed under the License is distributed on an \\\"AS IS\\\" BASIS,\\n//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\\n//   See the License for the specific language governing permissions and\\n//   limitations under the License.\\n//\\n//------------------------------------------------------------------------------\\n\\npragma solidity ^0.6.0;\\n\\nimport \\\"../openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"../openzeppelin/contracts/access/AccessControl.sol\\\";\\nimport \\\"./Finance.sol\\\";\\n\\n\\n// [Canonical ERC20-FET] = 10**(-18)x[ECR20-FET]\\ncontract Staking is AccessControl {\\n    using SafeMath for uint256;\\n    using AssetLib for AssetLib.Asset;\\n\\n    struct InterestRatePerBlock {\\n        uint256 sinceBlock;\\n        // NOTE(pb): To simplify, interest rate value can *not* be negative\\n        uint256 rate; // Signed interest rate in [10**18] units => real_rate = rate / 10**18.\\n        //// Number of users who bound stake while this particular interest rate was still in effect.\\n        //// This enables to identify when we can delete interest rates which are no more used by anyone\\n        //// (continuously from the beginning).\\n        //uint256 numberOfRegisteredUsers;\\n    }\\n\\n    struct Stake {\\n        uint256 sinceBlock;\\n        uint256 sinceInterestRateIndex;\\n        AssetLib.Asset asset;\\n    }\\n\\n    struct LockedAsset {\\n        uint256 liquidSinceBlock;\\n        AssetLib.Asset asset;\\n    }\\n\\n    struct Locked {\\n        AssetLib.Asset aggregate;\\n        LockedAsset[] assets;\\n    }\\n\\n    // *******    EVENTS    ********\\n    event BindStake(\\n          address indexed stakerAddress\\n        , uint256 indexed sinceInterestRateIndex\\n        , uint256 principal\\n        , uint256 compoundInterest\\n    );\\n\\n    /**\\n     * @dev This event is triggered exclusivelly to recalculate the compount interest of ALREADY staked asset\\n     *      for the poriod since it was calculated the last time. This means this event does *NOT* include *YET*\\n     *      any added (resp. removed) asset user is currently binding (resp. unbinding).\\n     *      The main motivation for this event is to give listener opportunity to get feedback what is the \\n     *      user's staked asset value with compound interrest recalculated to *CURRENT* block *BEFORE* user's\\n     *      action (binding resp. unbinding) affects user's staked asset value.\\n     */\\n    event StakeCompoundInterest(\\n          address indexed stakerAddress\\n        , uint256 indexed sinceInterestRateIndex\\n        , uint256 principal // = previous_principal\\n        , uint256 compoundInterest // = previous_principal * (pow(1+interest, _getBlockNumber()-since_block) - 1)\\n    );\\n\\n    event LiquidityDeposited(\\n          address indexed stakerAddress\\n        , uint256 amount\\n    );\\n\\n    event LiquidityUnlocked(\\n          address indexed stakerAddress\\n        , uint256 principal\\n        , uint256 compoundInterest\\n    );\\n\\n    event UnbindStake(\\n          address indexed stakerAddress\\n        , uint256 indexed liquidSinceBlock\\n        , uint256 principal\\n        , uint256 compoundInterest\\n    );\\n\\n    event NewInterestRate(\\n          uint256 indexed index\\n        , uint256 rate // Signed interest rate in [10**18] units => real_rate = rate / 10**18\\n    );\\n\\n    event Withdraw(\\n          address indexed stakerAddress\\n        , uint256 principal\\n        , uint256 compoundInterest\\n    );\\n\\n    event LockPeriod(uint64 numOfBlocks);\\n    event Pause(uint256 sinceBlock);\\n    event TokenWithdrawal(address targetAddress, uint256 amount);\\n    event ExcessTokenWithdrawal(address targetAddress, uint256 amount);\\n    event RewardsPoolTokenTopUp(address sender, uint256 amount);\\n    event RewardsPoolTokenWithdrawal(address targetAddress, uint256 amount);\\n    event DeleteContract();\\n\\n\\n    bytes32 public constant DELEGATE_ROLE = keccak256(\\\"DELEGATE_ROLE\\\");\\n    uint256 public constant DELETE_PROTECTION_PERIOD = 370285;// 60*24*60*60[s] / (14[s/block]) = 370285[block];\\n\\n    IERC20 public _token;\\n\\n    // NOTE(pb): This needs to be either completely replaced by multisig concept,\\n    //           or at least joined with multisig.\\n    //           This contract does not have, by-design on conceptual level, any clearly defined repeating\\n    //           life-cycle behaviour (for instance: `initialise -> staking-period -> locked-period` cycle\\n    //           with clear start & end of each life-cycle. Life-cycle of this contract is single monolithic\\n    //           period `creation -> delete-contract`, where there is no clear place where to `update` the\\n    //           earliest deletion block value, thus it would need to be set once at the contract creation\\n    //           point what completely defeats the protection by time delay.\\n    uint256 public _earliestDelete;\\n    \\n    uint256 public _pausedSinceBlock;\\n    uint64 public _lockPeriodInBlocks;\\n\\n    // Represents amount of reward funds which are dedicated to cover accrued compound interest during user withdrawals.\\n    uint256 public _rewardsPoolBalance;\\n    // Accumulated global value of all principals (from all users) currently held in this contract (liquid, bound and locked).\\n    uint256 public _accruedGlobalPrincipal;\\n    AssetLib.Asset public _accruedGlobalLiquidity; // Exact\\n    AssetLib.Asset public _accruedGlobalLocked; // Exact\\n\\n    uint256 public _interestRatesStartIdx;\\n    uint256 public _interestRatesNextIdx;\\n    mapping(uint256 => InterestRatePerBlock) public _interestRates;\\n\\n    mapping(address => Stake) _stakes;\\n    mapping(address => Locked) _locked;\\n    mapping(address => AssetLib.Asset) public _liquidity;\\n\\n\\n    /* Only callable by owner */\\n    modifier onlyOwner() {\\n        require(_isOwner(), \\\"Caller is not an owner\\\");\\n        _;\\n    }\\n\\n    /* Only callable by owner or delegate */\\n    modifier onlyDelegate() {\\n        require(_isOwner() || hasRole(DELEGATE_ROLE, msg.sender), \\\"Caller is neither owner nor delegate\\\");\\n        _;\\n    }\\n\\n    modifier verifyTxExpiration(uint256 expirationBlock) {\\n        require(_getBlockNumber() <= expirationBlock, \\\"Transaction expired\\\");\\n        _;\\n    }\\n\\n    modifier verifyNotPaused() {\\n        require(_pausedSinceBlock > _getBlockNumber(), \\\"Contract has been paused\\\");\\n        _;\\n    }\\n\\n\\n    /*******************\\n    Contract start\\n    *******************/\\n    /**\\n     * @param ERC20Address address of the ERC20 contract\\n     */\\n    constructor(\\n          address ERC20Address\\n        , uint256 interestRatePerBlock\\n        , uint256 pausedSinceBlock\\n        , uint64  lockPeriodInBlocks) \\n    public \\n    {\\n        _setupRole(DEFAULT_ADMIN_ROLE, msg.sender);\\n\\n        _token = IERC20(ERC20Address);\\n        _earliestDelete = _getBlockNumber().add(DELETE_PROTECTION_PERIOD);\\n        \\n        // NOTE(pb): Unnecessary initialisations, shall be done implicitly by VM\\n        //_interestRatesStartIdx = 0;\\n        //_interestRatesNextIdx = 0;\\n        //_rewardsPoolBalance = 0;\\n        //_accruedGlobalPrincipal = 0;\\n        //_accruedGlobalLiquidity = 0;\\n        //_accruedGlobalLocked = 0;\\n\\n        _updateLockPeriod(lockPeriodInBlocks);\\n        _addInterestRate(interestRatePerBlock);\\n        _pauseSince(pausedSinceBlock /* uint256(0) */);\\n    }\\n\\n\\n    /**\\n     * @notice Add new interest rate in to the ordered container of previously added interest rates\\n     * @param rate - signed interest rate value in [10**18] units => real_rate [1] = rate [10**18] / 10**18\\n     * @param expirationBlock - block number beyond which is the carrier Tx considered expired, and so rejected.\\n     *                     This is for protection of Tx sender to exactly define lifecycle length of the Tx,\\n     *                     and so avoiding uncertainty of how long Tx sender needs to wait for Tx processing.\\n     *                     Tx can be withheld\\n     * @dev expiration period\\n     */\\n    function addInterestRate(\\n        uint256 rate,\\n        uint256 expirationBlock\\n        )\\n        external\\n        onlyDelegate()\\n        verifyTxExpiration(expirationBlock)\\n    {\\n        _addInterestRate(rate);\\n    }\\n\\n\\n    function deposit(\\n        uint256 amount,\\n        uint256 txExpirationBlock\\n        )\\n        external\\n        verifyTxExpiration(txExpirationBlock)\\n        verifyNotPaused\\n    {\\n        bool makeTransfer = amount != 0;\\n        if (makeTransfer) {\\n            require(_token.transferFrom(msg.sender, address(this), amount), \\\"Transfer failed\\\");\\n            _accruedGlobalPrincipal = _accruedGlobalPrincipal.add(amount);\\n            _accruedGlobalLiquidity.principal = _accruedGlobalLiquidity.principal.add(amount);\\n            emit LiquidityDeposited(msg.sender, amount);\\n        }\\n\\n        uint256 curr_block = _getBlockNumber();\\n        (, AssetLib.Asset storage liquidity,) = _collectLiquidity(msg.sender, curr_block);\\n\\n        if (makeTransfer) {\\n            liquidity.principal = liquidity.principal.add(amount);\\n       }\\n    }\\n\\n\\n    /**\\n     * @notice Withdraws amount from sender' available liquidity pool back to sender address,\\n     *         preferring withdrawal from compound interest dimension of liquidity.\\n     *\\n     * @param amount - value to withdraw\\n     *\\n     * @dev public access\\n     */\\n    function withdraw(\\n        uint256 amount,\\n        uint256 txExpirationBlock\\n        )\\n        external\\n        verifyTxExpiration(txExpirationBlock)\\n        verifyNotPaused\\n    {\\n        address sender = msg.sender;\\n        uint256 curr_block = _getBlockNumber();\\n        (, AssetLib.Asset storage liquidity,) = _collectLiquidity(sender, curr_block);\\n\\n        AssetLib.Asset memory _amount = liquidity.iSubCompoundInterestFirst(amount);\\n        _finaliseWithdraw(sender, _amount, amount);\\n    }\\n\\n\\n    /**\\n     * @notice Withdraws *WHOLE* compound interest amount available to sender.\\n     *\\n     * @dev public access\\n     */\\n    function withdrawPrincipal(\\n        uint256 txExpirationBlock\\n        )\\n        external\\n        verifyTxExpiration(txExpirationBlock)\\n        verifyNotPaused\\n    {\\n        address sender = msg.sender;\\n        uint256 curr_block = _getBlockNumber();\\n        (, AssetLib.Asset storage liquidity, ) = _collectLiquidity(sender, curr_block);\\n\\n        AssetLib.Asset memory _amount;\\n        _amount.principal = liquidity.principal;\\n        liquidity.principal = 0;\\n\\n        _finaliseWithdraw(sender, _amount, _amount.principal);\\n    }\\n\\n\\n    /**\\n     * @notice Withdraws *WHOLE* compound interest amount available to sender.\\n     *\\n     * @dev public access\\n     */\\n    function withdrawCompoundInterest(\\n        uint256 txExpirationBlock\\n        )\\n        external\\n        verifyTxExpiration(txExpirationBlock)\\n        verifyNotPaused\\n    {\\n        address sender = msg.sender;\\n        uint256 curr_block = _getBlockNumber();\\n        (, AssetLib.Asset storage liquidity, ) = _collectLiquidity(sender, curr_block);\\n\\n        AssetLib.Asset memory _amount;\\n        _amount.compoundInterest = liquidity.compoundInterest;\\n        liquidity.compoundInterest = 0;\\n\\n        _finaliseWithdraw(sender, _amount, _amount.compoundInterest);\\n    }\\n\\n\\n    /**\\n     * @notice Withdraws whole liquidity available to sender back to sender' address,\\n     *\\n     * @dev public access\\n     */\\n    function withdrawWholeLiquidity(\\n        uint256 txExpirationBlock\\n        )\\n        external\\n        verifyTxExpiration(txExpirationBlock)\\n        verifyNotPaused\\n    {\\n        address sender = msg.sender;\\n        uint256 curr_block = _getBlockNumber();\\n        (, AssetLib.Asset storage liquidity, ) = _collectLiquidity(sender, curr_block);\\n\\n        _finaliseWithdraw(sender, liquidity, liquidity.composite());\\n        liquidity.compoundInterest = 0;\\n        liquidity.principal = 0;\\n    }\\n\\n\\n    function bindStake(\\n        uint256 amount,\\n        uint256 txExpirationBlock\\n        )\\n        external\\n        verifyTxExpiration(txExpirationBlock)\\n        verifyNotPaused\\n    {\\n        require(amount != 0, \\\"Amount must be higher than zero\\\");\\n\\n        uint256 curr_block = _getBlockNumber();\\n\\n        (, AssetLib.Asset storage liquidity, ) = _collectLiquidity(msg.sender, curr_block);\\n\\n        //// NOTE(pb): Strictly speaking, the following check is not necessary, since the requirement will be checked\\n        ////           during the `iRelocatePrincipalFirst(...)` method code flow (see bellow).\\n        //uint256 composite = liquidity.composite();\\n        //require(amount <= composite, \\\"Insufficient liquidity.\\\");\\n\\n        Stake storage stake = _updateStakeCompoundInterest(msg.sender, curr_block);\\n        AssetLib.Asset memory _amount = liquidity.iRelocatePrincipalFirst(stake.asset, amount);\\n        _accruedGlobalLiquidity.iSub(_amount);\\n\\n       //// NOTE(pb): Emitting only info about Tx input `amount` value, decomposed to principal & compound interest\\n       ////           coordinates based on liquidity available.\\n       //if (amount > 0) {\\n            emit BindStake(msg.sender, stake.sinceInterestRateIndex, _amount.principal, _amount.compoundInterest);\\n        //}\\n    }\\n\\n\\n    /**\\n     * @notice Unbinds amount from the stake of sender of the transaction,\\n     *         and *LOCKS* it for number of blocks defined by value of the\\n     *         `_lockPeriodInBlocks` state of this contract at the point\\n     *         of this call.\\n     *         The locked amount can *NOT* be withdrawn from the contract\\n     *         *BEFORE* the lock period ends.\\n     *\\n     *         Unbinding (=calling this method) also means, that compound\\n     *         interest will be calculated for period since la.\\n     *\\n     * @param amount - value to un-bind from the stake\\n     *                 If `amount=0` then the **WHOLE** stake (including\\n     *                 compound interest) will be unbound.\\n     *\\n     * @dev public access\\n     */\\n    function unbindStake(\\n        uint256 amount, //NOTE: If zero, then all stake is withdrawn\\n        uint256 txExpirationBlock\\n        )\\n        external\\n        verifyTxExpiration(txExpirationBlock)\\n        verifyNotPaused\\n    {\\n        uint256 curr_block = _getBlockNumber();\\n        address sender = msg.sender;\\n        Stake storage stake = _updateStakeCompoundInterest(sender, curr_block);\\n\\n        uint256 stake_composite = stake.asset.composite();\\n        AssetLib.Asset memory _amount;\\n\\n        if (amount > 0) {\\n            // TODO(pb): Failing this way is expensive (causing rollback of state change).\\n            //           It would be beneficial to retain newly calculated liquidity value\\n            //           in to the state, thus the invested calculation would not come to wain.\\n            //           However that comes with another implication - this would need\\n            //           to return status/error code instead of reverting = caller MUST actually\\n            //           check the return value, what might be trap for callers who do not expect\\n            //           this behaviour (Tx execution passed , but in fact the essential feature\\n            //           has not been fully executed).\\n            require(amount <= stake_composite, \\\"Amount is higher than stake\\\");\\n\\n            if (_lockPeriodInBlocks == 0) {\\n                _amount = stake.asset.iRelocateCompoundInterestFirst(_liquidity[sender], amount);\\n                _accruedGlobalLiquidity.iAdd(_amount);\\n                emit UnbindStake(sender, curr_block, _amount.principal, _amount.compoundInterest);\\n                emit LiquidityUnlocked(sender, _amount.principal, _amount.compoundInterest);\\n            } else {\\n                Locked storage locked = _locked[sender];\\n                LockedAsset storage newLockedAsset = locked.assets.push();\\n                newLockedAsset.liquidSinceBlock = curr_block.add(_lockPeriodInBlocks);\\n                _amount = stake.asset.iRelocateCompoundInterestFirst(newLockedAsset.asset, amount);\\n\\n                _accruedGlobalLocked.iAdd(_amount);\\n                locked.aggregate.iAdd(_amount);\\n\\n                // NOTE: Emitting only info about Tx input values, not resulting compound values\\n                emit UnbindStake(sender, newLockedAsset.liquidSinceBlock, _amount.principal, _amount.compoundInterest);\\n            }\\n        } else {\\n            if (stake_composite == 0) {\\n                // NOTE(pb): Nothing to do\\n                return;\\n            }\\n\\n            _amount = stake.asset;\\n            stake.asset.principal = 0;\\n            stake.asset.compoundInterest = 0;\\n\\n            if (_lockPeriodInBlocks == 0) {\\n                _liquidity[sender].iAdd(_amount);\\n                _accruedGlobalLiquidity.iAdd(_amount);\\n                emit UnbindStake(sender, curr_block, _amount.principal, _amount.compoundInterest);\\n                emit LiquidityUnlocked(sender, _amount.principal, _amount.compoundInterest);\\n            } else {\\n                Locked storage locked = _locked[sender];\\n                LockedAsset storage newLockedAsset = locked.assets.push();\\n                newLockedAsset.liquidSinceBlock = curr_block.add(_lockPeriodInBlocks);\\n                newLockedAsset.asset = _amount;\\n\\n                _accruedGlobalLocked.iAdd(_amount);\\n                locked.aggregate.iAdd(_amount);\\n\\n                // NOTE: Emitting only info about Tx input values, not resulting compound values\\n                emit UnbindStake(msg.sender, newLockedAsset.liquidSinceBlock, newLockedAsset.asset.principal, newLockedAsset.asset.compoundInterest);\\n            }\\n        }\\n    }\\n\\n\\n    function getRewardsPoolBalance() external view returns(uint256) {\\n        return _rewardsPoolBalance;\\n    }\\n\\n\\n    function getEarliestDeleteBlock() external view returns(uint256) {\\n        return _earliestDelete;\\n    }\\n\\n\\n    function getNumberOfLockedAssetsForUser(address forAddress) external view returns(uint256 length) {\\n        length = _locked[forAddress].assets.length;\\n    }\\n\\n\\n    function getLockedAssetsAggregateForUser(address forAddress) external view returns(uint256 principal, uint256 compoundInterest) {\\n        AssetLib.Asset storage aggregate = _locked[forAddress].aggregate;\\n        return (aggregate.principal, aggregate.compoundInterest);\\n    }\\n\\n\\n    /**\\n     * @dev Returns locked assets decomposed in to 3 separate arrays (principal, compound interest, liquid since block)\\n     *      NOTE(pb): This method might be quite expensive, depending on size of locked assets\\n     */\\n    function getLockedAssetsForUser(address forAddress)\\n        external view\\n        returns(uint256[] memory principal, uint256[] memory compoundInterest, uint256[] memory liquidSinceBlock)\\n    {\\n        LockedAsset[] storage lockedAssets = _locked[forAddress].assets;\\n        uint256 length = lockedAssets.length;\\n        if (length != 0) {\\n            principal = new uint256[](length);\\n            compoundInterest = new uint256[](length);\\n            liquidSinceBlock = new uint256[](length);\\n\\n            for (uint256 i=0; i < length; ++i) {\\n                LockedAsset storage la = lockedAssets[i];\\n                AssetLib.Asset storage a = la.asset;\\n                principal[i] = a.principal;\\n                compoundInterest[i] = a.compoundInterest;\\n                liquidSinceBlock[i] = la.liquidSinceBlock;\\n            }\\n        }\\n    }\\n\\n\\n    function getStakeForUser(address forAddress) external view returns(uint256 principal, uint256 compoundInterest, uint256 sinceBlock, uint256 sinceInterestRateIndex) {\\n        Stake storage stake = _stakes[forAddress];\\n        principal = stake.asset.principal;\\n        compoundInterest = stake.asset.compoundInterest;\\n        sinceBlock = stake.sinceBlock;\\n        sinceInterestRateIndex = stake.sinceInterestRateIndex;\\n    }\\n\\n\\n    /**\\n       @dev Even though this is considered as administrative action (is not affected by\\n            by contract paused state, it can be executed by anyone who wishes to\\n            top-up the rewards pool (funds are sent in to contract, *not* the other way around).\\n            The Rewards Pool is exclusively dedicated to cover withdrawals of user' compound interest,\\n            which is effectively the reward.\\n     */\\n    function topUpRewardsPool(\\n        uint256 amount,\\n        uint256 txExpirationBlock\\n        )\\n        external\\n        verifyTxExpiration(txExpirationBlock)\\n    {\\n        if (amount == 0) {\\n            return;\\n        }\\n\\n        require(_token.transferFrom(msg.sender, address(this), amount), \\\"Transfer failed\\\");\\n        _rewardsPoolBalance = _rewardsPoolBalance.add(amount);\\n        emit RewardsPoolTokenTopUp(msg.sender, amount);\\n    }\\n\\n\\n    /**\\n     * @notice Updates Lock Period value\\n     * @param numOfBlocks  length of the lock period\\n     * @dev Delegate only\\n     */\\n    function updateLockPeriod(uint64 numOfBlocks, uint256 txExpirationBlock)\\n        external\\n        verifyTxExpiration(txExpirationBlock)\\n        onlyDelegate\\n    {\\n        _updateLockPeriod(numOfBlocks);\\n    }\\n\\n\\n    /**\\n     * @notice Pauses all NON-administrative interaction with the contract since the specidfed block number \\n     * @param blockNumber block number since which non-admin interaction will be paused (for all _getBlockNumber() >= blockNumber)\\n     * @dev Delegate only\\n     */\\n    function pauseSince(uint256 blockNumber, uint256 txExpirationBlock)\\n        external\\n        verifyTxExpiration(txExpirationBlock)\\n        onlyDelegate\\n    {\\n        _pauseSince(blockNumber);\\n    }\\n\\n\\n    /**\\n     * @dev Withdraw tokens from rewards pool.\\n     *\\n     * @param amount : amount to withdraw.\\n     *                 If `amount == 0` then whole amount in rewards pool will be withdrawn.\\n     * @param targetAddress : address to send tokens to\\n     */\\n    function withdrawFromRewardsPool(uint256 amount, address payable targetAddress,\\n        uint256 txExpirationBlock\\n        )\\n        external\\n        verifyTxExpiration(txExpirationBlock)\\n        onlyOwner\\n    {\\n        if (amount == 0) {\\n            amount = _rewardsPoolBalance;\\n        } else {\\n            require(amount <= _rewardsPoolBalance, \\\"Amount higher than rewards pool\\\");\\n        }\\n\\n        // NOTE(pb): Strictly speaking, consistency check in following lines is not necessary,\\n        //           the if-else code above guarantees that everything is alright:\\n        uint256 contractBalance = _token.balanceOf(address(this));\\n        uint256 expectedMinContractBalance = _accruedGlobalPrincipal.add(amount);\\n        require(expectedMinContractBalance <= contractBalance, \\\"Contract inconsistency.\\\");\\n\\n        require(_token.transfer(targetAddress, amount), \\\"Not enough funds on contr. addr.\\\");\\n\\n        // NOTE(pb): No need for SafeMath.sub since the overflow is checked in the if-else code above.\\n        _rewardsPoolBalance -= amount;\\n\\n        emit RewardsPoolTokenWithdrawal(targetAddress, amount);\\n    }\\n\\n\\n    /**\\n     * @dev Withdraw \\\"excess\\\" tokens, which were sent to contract directly via direct ERC20.transfer(...),\\n     *      without interacting with API of this (Staking) contract, what could be done only by mistake.\\n     *      Thus this method is meant to be used primarily for rescue purposes, enabling withdrawal of such\\n     *      \\\"excess\\\" tokens out of contract.\\n     * @param targetAddress : address to send tokens to\\n     * @param txExpirationBlock : block number until which is the transaction valid (inclusive).\\n     *                            When transaction is processed after this block, it fails.\\n     */\\n    function withdrawExcessTokens(address payable targetAddress, uint256 txExpirationBlock)\\n        external\\n        verifyTxExpiration(txExpirationBlock)\\n        onlyOwner\\n    {\\n        uint256 contractBalance = _token.balanceOf(address(this));\\n        uint256 expectedMinContractBalance = _accruedGlobalPrincipal.add(_rewardsPoolBalance);\\n        // NOTE(pb): The following subtraction shall *fail* (revert) IF the contract is in *INCONSISTENT* state,\\n        //           = when contract balance is less than minial expected balance:\\n        uint256 excessAmount = contractBalance.sub(expectedMinContractBalance);\\n        require(_token.transfer(targetAddress, excessAmount), \\\"Not enough funds on contr. addr.\\\");\\n        emit ExcessTokenWithdrawal(targetAddress, excessAmount);\\n    }\\n\\n\\n    /**\\n     * @notice Delete the contract, transfers the remaining token and ether balance to the specified\\n       payoutAddress\\n     * @param payoutAddress address to transfer the balances to. Ensure that this is able to handle ERC20 tokens\\n     * @dev owner only + only on or after `_earliestDelete` block\\n     */\\n    function deleteContract(address payable payoutAddress, uint256 txExpirationBlock)\\n    external\\n    verifyTxExpiration(txExpirationBlock)\\n    onlyOwner\\n    {\\n        require(_earliestDelete >= _getBlockNumber(), \\\"Earliest delete not reached\\\");\\n        uint256 contractBalance = _token.balanceOf(address(this));\\n        require(_token.transfer(payoutAddress, contractBalance));\\n        emit DeleteContract();\\n        selfdestruct(payoutAddress);\\n    }\\n \\n\\n    // **********************************************************\\n    // ******************    INTERNAL METHODS   *****************\\n\\n\\n    /**\\n     * @dev VIRTUAL Method returning bock number. Introduced for \\n     *      testing purposes (allows mocking).\\n     */\\n    function _getBlockNumber() internal view virtual returns(uint256)\\n    {\\n        return block.number;\\n    }\\n\\n\\n    function _isOwner() internal view returns(bool) {\\n        return hasRole(DEFAULT_ADMIN_ROLE, msg.sender);\\n    }\\n\\n\\n    /**\\n     * @notice Add new interest rate in to the ordered container of previously added interest rates\\n     * @param rate - signed interest rate value in [10**18] units => real_rate [1] = rate [10**18] / 10**18\\n     */\\n    function _addInterestRate(uint256 rate) internal \\n    {\\n        uint256 idx = _interestRatesNextIdx;\\n        _interestRates[idx] = InterestRatePerBlock({\\n              sinceBlock: _getBlockNumber()\\n            , rate: rate\\n            //,numberOfRegisteredUsers: 0\\n            });\\n        _interestRatesNextIdx = _interestRatesNextIdx.add(1);\\n\\n        emit NewInterestRate(idx, rate);\\n    }\\n\\n\\n    /**\\n     * @notice Updates Lock Period value\\n     * @param numOfBlocks  length of the lock period\\n     */\\n    function _updateLockPeriod(uint64 numOfBlocks) internal\\n    {\\n        _lockPeriodInBlocks = numOfBlocks;\\n        emit LockPeriod(numOfBlocks);\\n    }\\n\\n\\n    /**\\n     * @notice Pauses all NON-administrative interaction with the contract since the specidfed block number \\n     * @param blockNumber block number since which non-admin interaction will be paused (for all _getBlockNumber() >= blockNumber)\\n     */\\n    function _pauseSince(uint256 blockNumber) internal \\n    {\\n        uint256 currentBlockNumber = _getBlockNumber();\\n        _pausedSinceBlock = blockNumber < currentBlockNumber ? currentBlockNumber : blockNumber;\\n        emit Pause(_pausedSinceBlock);\\n    }\\n\\n\\n    /**\\n     * @notice Withdraws amount from sender' available liquidity pool back to sender address,\\n     *         preferring withdrawal from compound interest dimension of liquidity.\\n     *\\n     * @param amount - value to withdraw\\n     *\\n     * @dev NOTE(pb): Passing redundant `uint256 amount` (on top of the `Asset _amount`) in the name\\n     *                of performance to avoid calculating it again from `_amount` (or the other way around).\\n     *                IMPLICATION: Caller **MUST** pass correct values, ensuring that `amount == _amount.composite()`,\\n     *                since this private method is **NOT** verifying this condition due to performance reasons.\\n     */\\n    function _finaliseWithdraw(address sender, AssetLib.Asset memory _amount, uint256 amount) internal {\\n         if (amount != 0) {\\n            require(_rewardsPoolBalance >= _amount.compoundInterest, \\\"Not enough funds in rewards pool\\\");\\n            require(_token.transfer(sender, amount), \\\"Transfer failed\\\");\\n\\n            _rewardsPoolBalance = _rewardsPoolBalance.sub(_amount.compoundInterest);\\n            _accruedGlobalPrincipal = _accruedGlobalPrincipal.sub(_amount.principal);\\n            _accruedGlobalLiquidity.iSub(_amount);\\n\\n            // NOTE(pb): Emitting only info about Tx input `amount` value, decomposed to principal & compound interest\\n            //           coordinates based on liquidity available.\\n            emit Withdraw(msg.sender, _amount.principal, _amount.compoundInterest);\\n         }\\n    }\\n\\n\\n    function _updateStakeCompoundInterest(address sender, uint256 at_block)\\n        internal\\n        returns(Stake storage stake)\\n    {\\n        stake = _stakes[sender];\\n        uint256 composite = stake.asset.composite();\\n        if (composite != 0)\\n        {\\n            // TODO(pb): There is more effective algorithm than this.\\n            uint256 start_block = stake.sinceBlock;\\n            // NOTE(pb): Probability of `++i`  or `j=i+1` overflowing is limitly approaching zero,\\n            // since we would need to create `(1<<256)-1`, resp `1<<256)-2`,  number of interrest rates in order to reach the overflow\\n            for (uint256 i=stake.sinceInterestRateIndex; i < _interestRatesNextIdx; ++i) {\\n                InterestRatePerBlock storage interest = _interestRates[i];\\n                // TODO(pb): It is not strictly necessary to do this assert, and rather fully rely\\n                //           on correctness of `addInterestRate(...)` implementation.\\n                require(interest.sinceBlock <= start_block, \\\"sinceBlock inconsistency\\\");\\n                uint256 end_block = at_block;\\n\\n                uint256 j = i + 1;\\n                if (j < _interestRatesNextIdx) {\\n                    InterestRatePerBlock storage next_interest = _interestRates[j];\\n                    end_block = next_interest.sinceBlock;\\n                }\\n\\n                composite = Finance.compoundInterest(composite, interest.rate, end_block - start_block);\\n                start_block = end_block;\\n            }\\n\\n            stake.asset.compoundInterest = composite.sub(stake.asset.principal);\\n        }\\n\\n        stake.sinceBlock = at_block;\\n        stake.sinceInterestRateIndex = (_interestRatesNextIdx != 0 ? _interestRatesNextIdx - 1 : 0);\\n        // TODO(pb): Careful: The `StakeCompoundInterest` event doers not carry explicit block number value - it relies\\n        //           on the fact that Event implicitly carries value block.number where the event has been triggered,\\n        //           what however can be different than value of the `at_block` input parameter passed in.\\n        //           Thus this method needs to be EITHER refactored to drop the `at_block` parameter (and so get the\\n        //           value internally by calling the `_getBlockNumber()` method), OR the `StakeCompoundInterest` event\\n        //           needs to be extended to include the `uint256 sinceBlock` attribute.\\n        //           The original reason for passing the `at_block` parameter was to spare gas for calling the\\n        //           `_getBlockNumber()` method twice (by the caller of this method + by this method), what might NOT be\\n        //           relevant anymore (after refactoring), since caller might not need to use the block number value anymore.\\n        emit StakeCompoundInterest(sender, stake.sinceInterestRateIndex, stake.asset.principal, stake.asset.compoundInterest);\\n    }\\n\\n\\n    function _collectLiquidity(address sender, uint256 at_block)\\n        internal\\n        returns(AssetLib.Asset memory unlockedLiquidity, AssetLib.Asset storage liquidity, bool collected)\\n    {\\n        Locked storage locked = _locked[sender];\\n        LockedAsset[] storage lockedAssets = locked.assets;\\n        liquidity = _liquidity[sender];\\n\\n        for (uint256 i=0; i < lockedAssets.length; ) {\\n            LockedAsset memory l = lockedAssets[i];\\n\\n            if (l.liquidSinceBlock > at_block) {\\n                ++i; // NOTE(pb): Probability of overflow is zero, what is ensured by condition in this for cycle.\\n                continue;\\n            }\\n\\n            unlockedLiquidity.principal = unlockedLiquidity.principal.add(l.asset.principal);\\n            // NOTE(pb): The following can potentially overflow, since accrued compound interest can be high, depending on values on sequence of interest rates & length of compounding intervals involved.\\n            unlockedLiquidity.compoundInterest = unlockedLiquidity.compoundInterest.add(l.asset.compoundInterest);\\n\\n            // Copying last element of the array in to the current one,\\n            // so that the last one can be popped out of the array.\\n            // NOTE(pb): Probability of overflow during `-` operation is zero, what is ensured by condition in this for cycle.\\n            uint256 last_idx = lockedAssets.length - 1;\\n            if (i != last_idx) {\\n                lockedAssets[i] = lockedAssets[last_idx];\\n            }\\n            // TODO(pb): It will be cheaper (GAS consumption-wise) to simply leave\\n            // elements in array (do NOT delete them) and rather store \\\"amortised\\\"\\n            // size of the array in secondary separate store variable (= do NOT\\n            // use `array.length` as primary indication of array length).\\n            // Destruction of the array items is expensive. Excess of \\\"allocated\\\"\\n            // array storage can be left temporarily (or even permanently) unused.\\n            lockedAssets.pop();\\n        }\\n\\n        // TODO(pb): This should not be necessary.\\n        if (lockedAssets.length == 0) {\\n            delete _locked[sender];\\n        }\\n\\n        collected = unlockedLiquidity.principal != 0 || unlockedLiquidity.compoundInterest != 0;\\n        if (collected) {\\n             emit LiquidityUnlocked(sender, unlockedLiquidity.principal, unlockedLiquidity.compoundInterest);\\n\\n            _accruedGlobalLocked.iSub(unlockedLiquidity);\\n            if (lockedAssets.length != 0) {\\n                locked.aggregate.iSub(unlockedLiquidity);\\n            }\\n\\n            _accruedGlobalLiquidity.iAdd(unlockedLiquidity);\\n\\n            liquidity.iAdd(unlockedLiquidity);\\n        }\\n    }\\n\\n}\\n\",\n  \"sourcePath\": \"/Users/pb/code/fetch/cosmos/ledger-staking-contract/contracts/Staking.sol\",\n  \"ast\": {\n    \"absolutePath\": \"/Users/pb/code/fetch/cosmos/ledger-staking-contract/contracts/Staking.sol\",\n    \"exportedSymbols\": {\n      \"Staking\": [\n        5490\n      ]\n    },\n    \"id\": 5491,\n    \"license\": \"Apache-2.0\",\n    \"nodeType\": \"SourceUnit\",\n    \"nodes\": [\n      {\n        \"id\": 3625,\n        \"literals\": [\n          \"solidity\",\n          \"^\",\n          \"0.6\",\n          \".0\"\n        ],\n        \"nodeType\": \"PragmaDirective\",\n        \"src\": \"820:23:6\"\n      },\n      {\n        \"absolutePath\": \"/Users/pb/code/fetch/cosmos/ledger-staking-contract/openzeppelin/contracts/token/ERC20/IERC20.sol\",\n        \"file\": \"../openzeppelin/contracts/token/ERC20/IERC20.sol\",\n        \"id\": 3626,\n        \"nodeType\": \"ImportDirective\",\n        \"scope\": 5491,\n        \"sourceUnit\": 6708,\n        \"src\": \"845:58:6\",\n        \"symbolAliases\": [],\n        \"unitAlias\": \"\"\n      },\n      {\n        \"absolutePath\": \"/Users/pb/code/fetch/cosmos/ledger-staking-contract/openzeppelin/contracts/access/AccessControl.sol\",\n        \"file\": \"../openzeppelin/contracts/access/AccessControl.sol\",\n        \"id\": 3627,\n        \"nodeType\": \"ImportDirective\",\n        \"scope\": 5491,\n        \"sourceUnit\": 5842,\n        \"src\": \"904:60:6\",\n        \"symbolAliases\": [],\n        \"unitAlias\": \"\"\n      },\n      {\n        \"absolutePath\": \"/Users/pb/code/fetch/cosmos/ledger-staking-contract/contracts/Finance.sol\",\n        \"file\": \"./Finance.sol\",\n        \"id\": 3628,\n        \"nodeType\": \"ImportDirective\",\n        \"scope\": 5491,\n        \"sourceUnit\": 3319,\n        \"src\": \"965:23:6\",\n        \"symbolAliases\": [],\n        \"unitAlias\": \"\"\n      },\n      {\n        \"abstract\": false,\n        \"baseContracts\": [\n          {\n            \"arguments\": null,\n            \"baseName\": {\n              \"contractScope\": null,\n              \"id\": 3629,\n              \"name\": \"AccessControl\",\n              \"nodeType\": \"UserDefinedTypeName\",\n              \"referencedDeclaration\": 5841,\n              \"src\": \"1060:13:6\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_contract$_AccessControl_$5841\",\n                \"typeString\": \"contract AccessControl\"\n              }\n            },\n            \"id\": 3630,\n            \"nodeType\": \"InheritanceSpecifier\",\n            \"src\": \"1060:13:6\"\n          }\n        ],\n        \"contractDependencies\": [\n          5558,\n          5841\n        ],\n        \"contractKind\": \"contract\",\n        \"documentation\": null,\n        \"fullyImplemented\": true,\n        \"id\": 5490,\n        \"linearizedBaseContracts\": [\n          5490,\n          5841,\n          5558\n        ],\n        \"name\": \"Staking\",\n        \"nodeType\": \"ContractDefinition\",\n        \"nodes\": [\n          {\n            \"id\": 3633,\n            \"libraryName\": {\n              \"contractScope\": null,\n              \"id\": 3631,\n              \"name\": \"SafeMath\",\n              \"nodeType\": \"UserDefinedTypeName\",\n              \"referencedDeclaration\": 6037,\n              \"src\": \"1086:8:6\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_contract$_SafeMath_$6037\",\n                \"typeString\": \"library SafeMath\"\n              }\n            },\n            \"nodeType\": \"UsingForDirective\",\n            \"src\": \"1080:27:6\",\n            \"typeName\": {\n              \"id\": 3632,\n              \"name\": \"uint256\",\n              \"nodeType\": \"ElementaryTypeName\",\n              \"src\": \"1099:7:6\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_uint256\",\n                \"typeString\": \"uint256\"\n              }\n            }\n          },\n          {\n            \"id\": 3636,\n            \"libraryName\": {\n              \"contractScope\": null,\n              \"id\": 3634,\n              \"name\": \"AssetLib\",\n              \"nodeType\": \"UserDefinedTypeName\",\n              \"referencedDeclaration\": 3121,\n              \"src\": \"1118:8:6\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_contract$_AssetLib_$3121\",\n                \"typeString\": \"library AssetLib\"\n              }\n            },\n            \"nodeType\": \"UsingForDirective\",\n            \"src\": \"1112:34:6\",\n            \"typeName\": {\n              \"contractScope\": null,\n              \"id\": 3635,\n              \"name\": \"AssetLib.Asset\",\n              \"nodeType\": \"UserDefinedTypeName\",\n              \"referencedDeclaration\": 2788,\n              \"src\": \"1131:14:6\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                \"typeString\": \"struct AssetLib.Asset\"\n              }\n            }\n          },\n          {\n            \"canonicalName\": \"Staking.InterestRatePerBlock\",\n            \"id\": 3641,\n            \"members\": [\n              {\n                \"constant\": false,\n                \"id\": 3638,\n                \"mutability\": \"mutable\",\n                \"name\": \"sinceBlock\",\n                \"nodeType\": \"VariableDeclaration\",\n                \"overrides\": null,\n                \"scope\": 3641,\n                \"src\": \"1190:18:6\",\n                \"stateVariable\": false,\n                \"storageLocation\": \"default\",\n                \"typeDescriptions\": {\n                  \"typeIdentifier\": \"t_uint256\",\n                  \"typeString\": \"uint256\"\n                },\n                \"typeName\": {\n                  \"id\": 3637,\n                  \"name\": \"uint256\",\n                  \"nodeType\": \"ElementaryTypeName\",\n                  \"src\": \"1190:7:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  }\n                },\n                \"value\": null,\n                \"visibility\": \"internal\"\n              },\n              {\n                \"constant\": false,\n                \"id\": 3640,\n                \"mutability\": \"mutable\",\n                \"name\": \"rate\",\n                \"nodeType\": \"VariableDeclaration\",\n                \"overrides\": null,\n                \"scope\": 3641,\n                \"src\": \"1294:12:6\",\n                \"stateVariable\": false,\n                \"storageLocation\": \"default\",\n                \"typeDescriptions\": {\n                  \"typeIdentifier\": \"t_uint256\",\n                  \"typeString\": \"uint256\"\n                },\n                \"typeName\": {\n                  \"id\": 3639,\n                  \"name\": \"uint256\",\n                  \"nodeType\": \"ElementaryTypeName\",\n                  \"src\": \"1294:7:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  }\n                },\n                \"value\": null,\n                \"visibility\": \"internal\"\n              }\n            ],\n            \"name\": \"InterestRatePerBlock\",\n            \"nodeType\": \"StructDefinition\",\n            \"scope\": 5490,\n            \"src\": \"1152:531:6\",\n            \"visibility\": \"public\"\n          },\n          {\n            \"canonicalName\": \"Staking.Stake\",\n            \"id\": 3648,\n            \"members\": [\n              {\n                \"constant\": false,\n                \"id\": 3643,\n                \"mutability\": \"mutable\",\n                \"name\": \"sinceBlock\",\n                \"nodeType\": \"VariableDeclaration\",\n                \"overrides\": null,\n                \"scope\": 3648,\n                \"src\": \"1712:18:6\",\n                \"stateVariable\": false,\n                \"storageLocation\": \"default\",\n                \"typeDescriptions\": {\n                  \"typeIdentifier\": \"t_uint256\",\n                  \"typeString\": \"uint256\"\n                },\n                \"typeName\": {\n                  \"id\": 3642,\n                  \"name\": \"uint256\",\n                  \"nodeType\": \"ElementaryTypeName\",\n                  \"src\": \"1712:7:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  }\n                },\n                \"value\": null,\n                \"visibility\": \"internal\"\n              },\n              {\n                \"constant\": false,\n                \"id\": 3645,\n                \"mutability\": \"mutable\",\n                \"name\": \"sinceInterestRateIndex\",\n                \"nodeType\": \"VariableDeclaration\",\n                \"overrides\": null,\n                \"scope\": 3648,\n                \"src\": \"1740:30:6\",\n                \"stateVariable\": false,\n                \"storageLocation\": \"default\",\n                \"typeDescriptions\": {\n                  \"typeIdentifier\": \"t_uint256\",\n                  \"typeString\": \"uint256\"\n                },\n                \"typeName\": {\n                  \"id\": 3644,\n                  \"name\": \"uint256\",\n                  \"nodeType\": \"ElementaryTypeName\",\n                  \"src\": \"1740:7:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  }\n                },\n                \"value\": null,\n                \"visibility\": \"internal\"\n              },\n              {\n                \"constant\": false,\n                \"id\": 3647,\n                \"mutability\": \"mutable\",\n                \"name\": \"asset\",\n                \"nodeType\": \"VariableDeclaration\",\n                \"overrides\": null,\n                \"scope\": 3648,\n                \"src\": \"1780:20:6\",\n                \"stateVariable\": false,\n                \"storageLocation\": \"default\",\n                \"typeDescriptions\": {\n                  \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                  \"typeString\": \"struct AssetLib.Asset\"\n                },\n                \"typeName\": {\n                  \"contractScope\": null,\n                  \"id\": 3646,\n                  \"name\": \"AssetLib.Asset\",\n                  \"nodeType\": \"UserDefinedTypeName\",\n                  \"referencedDeclaration\": 2788,\n                  \"src\": \"1780:14:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                    \"typeString\": \"struct AssetLib.Asset\"\n                  }\n                },\n                \"value\": null,\n                \"visibility\": \"internal\"\n              }\n            ],\n            \"name\": \"Stake\",\n            \"nodeType\": \"StructDefinition\",\n            \"scope\": 5490,\n            \"src\": \"1689:118:6\",\n            \"visibility\": \"public\"\n          },\n          {\n            \"canonicalName\": \"Staking.LockedAsset\",\n            \"id\": 3653,\n            \"members\": [\n              {\n                \"constant\": false,\n                \"id\": 3650,\n                \"mutability\": \"mutable\",\n                \"name\": \"liquidSinceBlock\",\n                \"nodeType\": \"VariableDeclaration\",\n                \"overrides\": null,\n                \"scope\": 3653,\n                \"src\": \"1842:24:6\",\n                \"stateVariable\": false,\n                \"storageLocation\": \"default\",\n                \"typeDescriptions\": {\n                  \"typeIdentifier\": \"t_uint256\",\n                  \"typeString\": \"uint256\"\n                },\n                \"typeName\": {\n                  \"id\": 3649,\n                  \"name\": \"uint256\",\n                  \"nodeType\": \"ElementaryTypeName\",\n                  \"src\": \"1842:7:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  }\n                },\n                \"value\": null,\n                \"visibility\": \"internal\"\n              },\n              {\n                \"constant\": false,\n                \"id\": 3652,\n                \"mutability\": \"mutable\",\n                \"name\": \"asset\",\n                \"nodeType\": \"VariableDeclaration\",\n                \"overrides\": null,\n                \"scope\": 3653,\n                \"src\": \"1876:20:6\",\n                \"stateVariable\": false,\n                \"storageLocation\": \"default\",\n                \"typeDescriptions\": {\n                  \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                  \"typeString\": \"struct AssetLib.Asset\"\n                },\n                \"typeName\": {\n                  \"contractScope\": null,\n                  \"id\": 3651,\n                  \"name\": \"AssetLib.Asset\",\n                  \"nodeType\": \"UserDefinedTypeName\",\n                  \"referencedDeclaration\": 2788,\n                  \"src\": \"1876:14:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                    \"typeString\": \"struct AssetLib.Asset\"\n                  }\n                },\n                \"value\": null,\n                \"visibility\": \"internal\"\n              }\n            ],\n            \"name\": \"LockedAsset\",\n            \"nodeType\": \"StructDefinition\",\n            \"scope\": 5490,\n            \"src\": \"1813:90:6\",\n            \"visibility\": \"public\"\n          },\n          {\n            \"canonicalName\": \"Staking.Locked\",\n            \"id\": 3659,\n            \"members\": [\n              {\n                \"constant\": false,\n                \"id\": 3655,\n                \"mutability\": \"mutable\",\n                \"name\": \"aggregate\",\n                \"nodeType\": \"VariableDeclaration\",\n                \"overrides\": null,\n                \"scope\": 3659,\n                \"src\": \"1933:24:6\",\n                \"stateVariable\": false,\n                \"storageLocation\": \"default\",\n                \"typeDescriptions\": {\n                  \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                  \"typeString\": \"struct AssetLib.Asset\"\n                },\n                \"typeName\": {\n                  \"contractScope\": null,\n                  \"id\": 3654,\n                  \"name\": \"AssetLib.Asset\",\n                  \"nodeType\": \"UserDefinedTypeName\",\n                  \"referencedDeclaration\": 2788,\n                  \"src\": \"1933:14:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                    \"typeString\": \"struct AssetLib.Asset\"\n                  }\n                },\n                \"value\": null,\n                \"visibility\": \"internal\"\n              },\n              {\n                \"constant\": false,\n                \"id\": 3658,\n                \"mutability\": \"mutable\",\n                \"name\": \"assets\",\n                \"nodeType\": \"VariableDeclaration\",\n                \"overrides\": null,\n                \"scope\": 3659,\n                \"src\": \"1967:20:6\",\n                \"stateVariable\": false,\n                \"storageLocation\": \"default\",\n                \"typeDescriptions\": {\n                  \"typeIdentifier\": \"t_array$_t_struct$_LockedAsset_$3653_storage_$dyn_storage_ptr\",\n                  \"typeString\": \"struct Staking.LockedAsset[]\"\n                },\n                \"typeName\": {\n                  \"baseType\": {\n                    \"contractScope\": null,\n                    \"id\": 3656,\n                    \"name\": \"LockedAsset\",\n                    \"nodeType\": \"UserDefinedTypeName\",\n                    \"referencedDeclaration\": 3653,\n                    \"src\": \"1967:11:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_struct$_LockedAsset_$3653_storage_ptr\",\n                      \"typeString\": \"struct Staking.LockedAsset\"\n                    }\n                  },\n                  \"id\": 3657,\n                  \"length\": null,\n                  \"nodeType\": \"ArrayTypeName\",\n                  \"src\": \"1967:13:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_array$_t_struct$_LockedAsset_$3653_storage_$dyn_storage_ptr\",\n                    \"typeString\": \"struct Staking.LockedAsset[]\"\n                  }\n                },\n                \"value\": null,\n                \"visibility\": \"internal\"\n              }\n            ],\n            \"name\": \"Locked\",\n            \"nodeType\": \"StructDefinition\",\n            \"scope\": 5490,\n            \"src\": \"1909:85:6\",\n            \"visibility\": \"public\"\n          },\n          {\n            \"anonymous\": false,\n            \"documentation\": null,\n            \"id\": 3669,\n            \"name\": \"BindStake\",\n            \"nodeType\": \"EventDefinition\",\n            \"parameters\": {\n              \"id\": 3668,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 3661,\n                  \"indexed\": true,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"stakerAddress\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3669,\n                  \"src\": \"2064:29:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_address\",\n                    \"typeString\": \"address\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3660,\n                    \"name\": \"address\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"2064:7:6\",\n                    \"stateMutability\": \"nonpayable\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address\",\n                      \"typeString\": \"address\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 3663,\n                  \"indexed\": true,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"sinceInterestRateIndex\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3669,\n                  \"src\": \"2104:38:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3662,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"2104:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 3665,\n                  \"indexed\": false,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"principal\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3669,\n                  \"src\": \"2153:17:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3664,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"2153:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 3667,\n                  \"indexed\": false,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"compoundInterest\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3669,\n                  \"src\": \"2181:24:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3666,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"2181:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"2052:159:6\"\n            },\n            \"src\": \"2037:175:6\"\n          },\n          {\n            \"anonymous\": false,\n            \"documentation\": {\n              \"id\": 3670,\n              \"nodeType\": \"StructuredDocumentation\",\n              \"src\": \"2218:621:6\",\n              \"text\": \"@dev This event is triggered exclusivelly to recalculate the compount interest of ALREADY staked asset\\n     for the poriod since it was calculated the last time. This means this event does *NOT* include *YET*\\n     any added (resp. removed) asset user is currently binding (resp. unbinding).\\n     The main motivation for this event is to give listener opportunity to get feedback what is the \\n     user's staked asset value with compound interrest recalculated to *CURRENT* block *BEFORE* user's\\n     action (binding resp. unbinding) affects user's staked asset value.\"\n            },\n            \"id\": 3680,\n            \"name\": \"StakeCompoundInterest\",\n            \"nodeType\": \"EventDefinition\",\n            \"parameters\": {\n              \"id\": 3679,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 3672,\n                  \"indexed\": true,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"stakerAddress\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3680,\n                  \"src\": \"2883:29:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_address\",\n                    \"typeString\": \"address\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3671,\n                    \"name\": \"address\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"2883:7:6\",\n                    \"stateMutability\": \"nonpayable\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address\",\n                      \"typeString\": \"address\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 3674,\n                  \"indexed\": true,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"sinceInterestRateIndex\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3680,\n                  \"src\": \"2923:38:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3673,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"2923:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 3676,\n                  \"indexed\": false,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"principal\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3680,\n                  \"src\": \"2972:17:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3675,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"2972:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 3678,\n                  \"indexed\": false,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"compoundInterest\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3680,\n                  \"src\": \"3024:24:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3677,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"3024:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"2871:262:6\"\n            },\n            \"src\": \"2844:290:6\"\n          },\n          {\n            \"anonymous\": false,\n            \"documentation\": null,\n            \"id\": 3686,\n            \"name\": \"LiquidityDeposited\",\n            \"nodeType\": \"EventDefinition\",\n            \"parameters\": {\n              \"id\": 3685,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 3682,\n                  \"indexed\": true,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"stakerAddress\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3686,\n                  \"src\": \"3176:29:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_address\",\n                    \"typeString\": \"address\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3681,\n                    \"name\": \"address\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"3176:7:6\",\n                    \"stateMutability\": \"nonpayable\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address\",\n                      \"typeString\": \"address\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 3684,\n                  \"indexed\": false,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"amount\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3686,\n                  \"src\": \"3216:14:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3683,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"3216:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"3164:72:6\"\n            },\n            \"src\": \"3140:97:6\"\n          },\n          {\n            \"anonymous\": false,\n            \"documentation\": null,\n            \"id\": 3694,\n            \"name\": \"LiquidityUnlocked\",\n            \"nodeType\": \"EventDefinition\",\n            \"parameters\": {\n              \"id\": 3693,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 3688,\n                  \"indexed\": true,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"stakerAddress\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3694,\n                  \"src\": \"3278:29:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_address\",\n                    \"typeString\": \"address\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3687,\n                    \"name\": \"address\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"3278:7:6\",\n                    \"stateMutability\": \"nonpayable\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address\",\n                      \"typeString\": \"address\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 3690,\n                  \"indexed\": false,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"principal\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3694,\n                  \"src\": \"3318:17:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3689,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"3318:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 3692,\n                  \"indexed\": false,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"compoundInterest\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3694,\n                  \"src\": \"3346:24:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3691,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"3346:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"3266:110:6\"\n            },\n            \"src\": \"3243:134:6\"\n          },\n          {\n            \"anonymous\": false,\n            \"documentation\": null,\n            \"id\": 3704,\n            \"name\": \"UnbindStake\",\n            \"nodeType\": \"EventDefinition\",\n            \"parameters\": {\n              \"id\": 3703,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 3696,\n                  \"indexed\": true,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"stakerAddress\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3704,\n                  \"src\": \"3412:29:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_address\",\n                    \"typeString\": \"address\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3695,\n                    \"name\": \"address\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"3412:7:6\",\n                    \"stateMutability\": \"nonpayable\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address\",\n                      \"typeString\": \"address\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 3698,\n                  \"indexed\": true,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"liquidSinceBlock\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3704,\n                  \"src\": \"3452:32:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3697,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"3452:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 3700,\n                  \"indexed\": false,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"principal\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3704,\n                  \"src\": \"3495:17:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3699,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"3495:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 3702,\n                  \"indexed\": false,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"compoundInterest\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3704,\n                  \"src\": \"3523:24:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3701,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"3523:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"3400:153:6\"\n            },\n            \"src\": \"3383:171:6\"\n          },\n          {\n            \"anonymous\": false,\n            \"documentation\": null,\n            \"id\": 3710,\n            \"name\": \"NewInterestRate\",\n            \"nodeType\": \"EventDefinition\",\n            \"parameters\": {\n              \"id\": 3709,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 3706,\n                  \"indexed\": true,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"index\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3710,\n                  \"src\": \"3593:21:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3705,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"3593:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 3708,\n                  \"indexed\": false,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"rate\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3710,\n                  \"src\": \"3625:12:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3707,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"3625:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"3581:133:6\"\n            },\n            \"src\": \"3560:155:6\"\n          },\n          {\n            \"anonymous\": false,\n            \"documentation\": null,\n            \"id\": 3718,\n            \"name\": \"Withdraw\",\n            \"nodeType\": \"EventDefinition\",\n            \"parameters\": {\n              \"id\": 3717,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 3712,\n                  \"indexed\": true,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"stakerAddress\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3718,\n                  \"src\": \"3747:29:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_address\",\n                    \"typeString\": \"address\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3711,\n                    \"name\": \"address\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"3747:7:6\",\n                    \"stateMutability\": \"nonpayable\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address\",\n                      \"typeString\": \"address\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 3714,\n                  \"indexed\": false,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"principal\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3718,\n                  \"src\": \"3787:17:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3713,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"3787:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 3716,\n                  \"indexed\": false,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"compoundInterest\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3718,\n                  \"src\": \"3815:24:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3715,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"3815:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"3735:110:6\"\n            },\n            \"src\": \"3721:125:6\"\n          },\n          {\n            \"anonymous\": false,\n            \"documentation\": null,\n            \"id\": 3722,\n            \"name\": \"LockPeriod\",\n            \"nodeType\": \"EventDefinition\",\n            \"parameters\": {\n              \"id\": 3721,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 3720,\n                  \"indexed\": false,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"numOfBlocks\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3722,\n                  \"src\": \"3869:18:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint64\",\n                    \"typeString\": \"uint64\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3719,\n                    \"name\": \"uint64\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"3869:6:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint64\",\n                      \"typeString\": \"uint64\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"3868:20:6\"\n            },\n            \"src\": \"3852:37:6\"\n          },\n          {\n            \"anonymous\": false,\n            \"documentation\": null,\n            \"id\": 3726,\n            \"name\": \"Pause\",\n            \"nodeType\": \"EventDefinition\",\n            \"parameters\": {\n              \"id\": 3725,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 3724,\n                  \"indexed\": false,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"sinceBlock\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3726,\n                  \"src\": \"3906:18:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3723,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"3906:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"3905:20:6\"\n            },\n            \"src\": \"3894:32:6\"\n          },\n          {\n            \"anonymous\": false,\n            \"documentation\": null,\n            \"id\": 3732,\n            \"name\": \"TokenWithdrawal\",\n            \"nodeType\": \"EventDefinition\",\n            \"parameters\": {\n              \"id\": 3731,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 3728,\n                  \"indexed\": false,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"targetAddress\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3732,\n                  \"src\": \"3953:21:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_address\",\n                    \"typeString\": \"address\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3727,\n                    \"name\": \"address\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"3953:7:6\",\n                    \"stateMutability\": \"nonpayable\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address\",\n                      \"typeString\": \"address\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 3730,\n                  \"indexed\": false,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"amount\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3732,\n                  \"src\": \"3976:14:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3729,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"3976:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"3952:39:6\"\n            },\n            \"src\": \"3931:61:6\"\n          },\n          {\n            \"anonymous\": false,\n            \"documentation\": null,\n            \"id\": 3738,\n            \"name\": \"ExcessTokenWithdrawal\",\n            \"nodeType\": \"EventDefinition\",\n            \"parameters\": {\n              \"id\": 3737,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 3734,\n                  \"indexed\": false,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"targetAddress\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3738,\n                  \"src\": \"4025:21:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_address\",\n                    \"typeString\": \"address\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3733,\n                    \"name\": \"address\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"4025:7:6\",\n                    \"stateMutability\": \"nonpayable\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address\",\n                      \"typeString\": \"address\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 3736,\n                  \"indexed\": false,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"amount\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3738,\n                  \"src\": \"4048:14:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3735,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"4048:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"4024:39:6\"\n            },\n            \"src\": \"3997:67:6\"\n          },\n          {\n            \"anonymous\": false,\n            \"documentation\": null,\n            \"id\": 3744,\n            \"name\": \"RewardsPoolTokenTopUp\",\n            \"nodeType\": \"EventDefinition\",\n            \"parameters\": {\n              \"id\": 3743,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 3740,\n                  \"indexed\": false,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"sender\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3744,\n                  \"src\": \"4097:14:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_address\",\n                    \"typeString\": \"address\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3739,\n                    \"name\": \"address\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"4097:7:6\",\n                    \"stateMutability\": \"nonpayable\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address\",\n                      \"typeString\": \"address\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 3742,\n                  \"indexed\": false,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"amount\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3744,\n                  \"src\": \"4113:14:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3741,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"4113:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"4096:32:6\"\n            },\n            \"src\": \"4069:60:6\"\n          },\n          {\n            \"anonymous\": false,\n            \"documentation\": null,\n            \"id\": 3750,\n            \"name\": \"RewardsPoolTokenWithdrawal\",\n            \"nodeType\": \"EventDefinition\",\n            \"parameters\": {\n              \"id\": 3749,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 3746,\n                  \"indexed\": false,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"targetAddress\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3750,\n                  \"src\": \"4167:21:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_address\",\n                    \"typeString\": \"address\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3745,\n                    \"name\": \"address\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"4167:7:6\",\n                    \"stateMutability\": \"nonpayable\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address\",\n                      \"typeString\": \"address\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 3748,\n                  \"indexed\": false,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"amount\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3750,\n                  \"src\": \"4190:14:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3747,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"4190:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"4166:39:6\"\n            },\n            \"src\": \"4134:72:6\"\n          },\n          {\n            \"anonymous\": false,\n            \"documentation\": null,\n            \"id\": 3752,\n            \"name\": \"DeleteContract\",\n            \"nodeType\": \"EventDefinition\",\n            \"parameters\": {\n              \"id\": 3751,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"4231:2:6\"\n            },\n            \"src\": \"4211:23:6\"\n          },\n          {\n            \"constant\": true,\n            \"functionSelector\": \"c0ba241b\",\n            \"id\": 3757,\n            \"mutability\": \"constant\",\n            \"name\": \"DELEGATE_ROLE\",\n            \"nodeType\": \"VariableDeclaration\",\n            \"overrides\": null,\n            \"scope\": 5490,\n            \"src\": \"4241:66:6\",\n            \"stateVariable\": true,\n            \"storageLocation\": \"default\",\n            \"typeDescriptions\": {\n              \"typeIdentifier\": \"t_bytes32\",\n              \"typeString\": \"bytes32\"\n            },\n            \"typeName\": {\n              \"id\": 3753,\n              \"name\": \"bytes32\",\n              \"nodeType\": \"ElementaryTypeName\",\n              \"src\": \"4241:7:6\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_bytes32\",\n                \"typeString\": \"bytes32\"\n              }\n            },\n            \"value\": {\n              \"argumentTypes\": null,\n              \"arguments\": [\n                {\n                  \"argumentTypes\": null,\n                  \"hexValue\": \"44454c45474154455f524f4c45\",\n                  \"id\": 3755,\n                  \"isConstant\": false,\n                  \"isLValue\": false,\n                  \"isPure\": true,\n                  \"kind\": \"string\",\n                  \"lValueRequested\": false,\n                  \"nodeType\": \"Literal\",\n                  \"src\": \"4291:15:6\",\n                  \"subdenomination\": null,\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_stringliteral_1a82baf2b928242f69f7147fb92490c6288d044f7257b88817e6284f1eec0f15\",\n                    \"typeString\": \"literal_string \\\"DELEGATE_ROLE\\\"\"\n                  },\n                  \"value\": \"DELEGATE_ROLE\"\n                }\n              ],\n              \"expression\": {\n                \"argumentTypes\": [\n                  {\n                    \"typeIdentifier\": \"t_stringliteral_1a82baf2b928242f69f7147fb92490c6288d044f7257b88817e6284f1eec0f15\",\n                    \"typeString\": \"literal_string \\\"DELEGATE_ROLE\\\"\"\n                  }\n                ],\n                \"id\": 3754,\n                \"name\": \"keccak256\",\n                \"nodeType\": \"Identifier\",\n                \"overloadedDeclarations\": [],\n                \"referencedDeclaration\": -8,\n                \"src\": \"4281:9:6\",\n                \"typeDescriptions\": {\n                  \"typeIdentifier\": \"t_function_keccak256_pure$_t_bytes_memory_ptr_$returns$_t_bytes32_$\",\n                  \"typeString\": \"function (bytes memory) pure returns (bytes32)\"\n                }\n              },\n              \"id\": 3756,\n              \"isConstant\": false,\n              \"isLValue\": false,\n              \"isPure\": true,\n              \"kind\": \"functionCall\",\n              \"lValueRequested\": false,\n              \"names\": [],\n              \"nodeType\": \"FunctionCall\",\n              \"src\": \"4281:26:6\",\n              \"tryCall\": false,\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_bytes32\",\n                \"typeString\": \"bytes32\"\n              }\n            },\n            \"visibility\": \"public\"\n          },\n          {\n            \"constant\": true,\n            \"functionSelector\": \"372646bb\",\n            \"id\": 3760,\n            \"mutability\": \"constant\",\n            \"name\": \"DELETE_PROTECTION_PERIOD\",\n            \"nodeType\": \"VariableDeclaration\",\n            \"overrides\": null,\n            \"scope\": 5490,\n            \"src\": \"4313:57:6\",\n            \"stateVariable\": true,\n            \"storageLocation\": \"default\",\n            \"typeDescriptions\": {\n              \"typeIdentifier\": \"t_uint256\",\n              \"typeString\": \"uint256\"\n            },\n            \"typeName\": {\n              \"id\": 3758,\n              \"name\": \"uint256\",\n              \"nodeType\": \"ElementaryTypeName\",\n              \"src\": \"4313:7:6\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_uint256\",\n                \"typeString\": \"uint256\"\n              }\n            },\n            \"value\": {\n              \"argumentTypes\": null,\n              \"hexValue\": \"333730323835\",\n              \"id\": 3759,\n              \"isConstant\": false,\n              \"isLValue\": false,\n              \"isPure\": true,\n              \"kind\": \"number\",\n              \"lValueRequested\": false,\n              \"nodeType\": \"Literal\",\n              \"src\": \"4364:6:6\",\n              \"subdenomination\": null,\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_rational_370285_by_1\",\n                \"typeString\": \"int_const 370285\"\n              },\n              \"value\": \"370285\"\n            },\n            \"visibility\": \"public\"\n          },\n          {\n            \"constant\": false,\n            \"functionSelector\": \"ecd0c0c3\",\n            \"id\": 3762,\n            \"mutability\": \"mutable\",\n            \"name\": \"_token\",\n            \"nodeType\": \"VariableDeclaration\",\n            \"overrides\": null,\n            \"scope\": 5490,\n            \"src\": \"4427:20:6\",\n            \"stateVariable\": true,\n            \"storageLocation\": \"default\",\n            \"typeDescriptions\": {\n              \"typeIdentifier\": \"t_contract$_IERC20_$6707\",\n              \"typeString\": \"contract IERC20\"\n            },\n            \"typeName\": {\n              \"contractScope\": null,\n              \"id\": 3761,\n              \"name\": \"IERC20\",\n              \"nodeType\": \"UserDefinedTypeName\",\n              \"referencedDeclaration\": 6707,\n              \"src\": \"4427:6:6\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_contract$_IERC20_$6707\",\n                \"typeString\": \"contract IERC20\"\n              }\n            },\n            \"value\": null,\n            \"visibility\": \"public\"\n          },\n          {\n            \"constant\": false,\n            \"functionSelector\": \"32a1bd70\",\n            \"id\": 3764,\n            \"mutability\": \"mutable\",\n            \"name\": \"_earliestDelete\",\n            \"nodeType\": \"VariableDeclaration\",\n            \"overrides\": null,\n            \"scope\": 5490,\n            \"src\": \"5201:30:6\",\n            \"stateVariable\": true,\n            \"storageLocation\": \"default\",\n            \"typeDescriptions\": {\n              \"typeIdentifier\": \"t_uint256\",\n              \"typeString\": \"uint256\"\n            },\n            \"typeName\": {\n              \"id\": 3763,\n              \"name\": \"uint256\",\n              \"nodeType\": \"ElementaryTypeName\",\n              \"src\": \"5201:7:6\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_uint256\",\n                \"typeString\": \"uint256\"\n              }\n            },\n            \"value\": null,\n            \"visibility\": \"public\"\n          },\n          {\n            \"constant\": false,\n            \"functionSelector\": \"f1209ef7\",\n            \"id\": 3766,\n            \"mutability\": \"mutable\",\n            \"name\": \"_pausedSinceBlock\",\n            \"nodeType\": \"VariableDeclaration\",\n            \"overrides\": null,\n            \"scope\": 5490,\n            \"src\": \"5242:32:6\",\n            \"stateVariable\": true,\n            \"storageLocation\": \"default\",\n            \"typeDescriptions\": {\n              \"typeIdentifier\": \"t_uint256\",\n              \"typeString\": \"uint256\"\n            },\n            \"typeName\": {\n              \"id\": 3765,\n              \"name\": \"uint256\",\n              \"nodeType\": \"ElementaryTypeName\",\n              \"src\": \"5242:7:6\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_uint256\",\n                \"typeString\": \"uint256\"\n              }\n            },\n            \"value\": null,\n            \"visibility\": \"public\"\n          },\n          {\n            \"constant\": false,\n            \"functionSelector\": \"2514c50a\",\n            \"id\": 3768,\n            \"mutability\": \"mutable\",\n            \"name\": \"_lockPeriodInBlocks\",\n            \"nodeType\": \"VariableDeclaration\",\n            \"overrides\": null,\n            \"scope\": 5490,\n            \"src\": \"5280:33:6\",\n            \"stateVariable\": true,\n            \"storageLocation\": \"default\",\n            \"typeDescriptions\": {\n              \"typeIdentifier\": \"t_uint64\",\n              \"typeString\": \"uint64\"\n            },\n            \"typeName\": {\n              \"id\": 3767,\n              \"name\": \"uint64\",\n              \"nodeType\": \"ElementaryTypeName\",\n              \"src\": \"5280:6:6\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_uint64\",\n                \"typeString\": \"uint64\"\n              }\n            },\n            \"value\": null,\n            \"visibility\": \"public\"\n          },\n          {\n            \"constant\": false,\n            \"functionSelector\": \"0c450f9d\",\n            \"id\": 3770,\n            \"mutability\": \"mutable\",\n            \"name\": \"_rewardsPoolBalance\",\n            \"nodeType\": \"VariableDeclaration\",\n            \"overrides\": null,\n            \"scope\": 5490,\n            \"src\": \"5441:34:6\",\n            \"stateVariable\": true,\n            \"storageLocation\": \"default\",\n            \"typeDescriptions\": {\n              \"typeIdentifier\": \"t_uint256\",\n              \"typeString\": \"uint256\"\n            },\n            \"typeName\": {\n              \"id\": 3769,\n              \"name\": \"uint256\",\n              \"nodeType\": \"ElementaryTypeName\",\n              \"src\": \"5441:7:6\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_uint256\",\n                \"typeString\": \"uint256\"\n              }\n            },\n            \"value\": null,\n            \"visibility\": \"public\"\n          },\n          {\n            \"constant\": false,\n            \"functionSelector\": \"292911fb\",\n            \"id\": 3772,\n            \"mutability\": \"mutable\",\n            \"name\": \"_accruedGlobalPrincipal\",\n            \"nodeType\": \"VariableDeclaration\",\n            \"overrides\": null,\n            \"scope\": 5490,\n            \"src\": \"5608:38:6\",\n            \"stateVariable\": true,\n            \"storageLocation\": \"default\",\n            \"typeDescriptions\": {\n              \"typeIdentifier\": \"t_uint256\",\n              \"typeString\": \"uint256\"\n            },\n            \"typeName\": {\n              \"id\": 3771,\n              \"name\": \"uint256\",\n              \"nodeType\": \"ElementaryTypeName\",\n              \"src\": \"5608:7:6\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_uint256\",\n                \"typeString\": \"uint256\"\n              }\n            },\n            \"value\": null,\n            \"visibility\": \"public\"\n          },\n          {\n            \"constant\": false,\n            \"functionSelector\": \"c8984ab2\",\n            \"id\": 3774,\n            \"mutability\": \"mutable\",\n            \"name\": \"_accruedGlobalLiquidity\",\n            \"nodeType\": \"VariableDeclaration\",\n            \"overrides\": null,\n            \"scope\": 5490,\n            \"src\": \"5652:45:6\",\n            \"stateVariable\": true,\n            \"storageLocation\": \"default\",\n            \"typeDescriptions\": {\n              \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n              \"typeString\": \"struct AssetLib.Asset\"\n            },\n            \"typeName\": {\n              \"contractScope\": null,\n              \"id\": 3773,\n              \"name\": \"AssetLib.Asset\",\n              \"nodeType\": \"UserDefinedTypeName\",\n              \"referencedDeclaration\": 2788,\n              \"src\": \"5652:14:6\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                \"typeString\": \"struct AssetLib.Asset\"\n              }\n            },\n            \"value\": null,\n            \"visibility\": \"public\"\n          },\n          {\n            \"constant\": false,\n            \"functionSelector\": \"d9b202c9\",\n            \"id\": 3776,\n            \"mutability\": \"mutable\",\n            \"name\": \"_accruedGlobalLocked\",\n            \"nodeType\": \"VariableDeclaration\",\n            \"overrides\": null,\n            \"scope\": 5490,\n            \"src\": \"5712:42:6\",\n            \"stateVariable\": true,\n            \"storageLocation\": \"default\",\n            \"typeDescriptions\": {\n              \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n              \"typeString\": \"struct AssetLib.Asset\"\n            },\n            \"typeName\": {\n              \"contractScope\": null,\n              \"id\": 3775,\n              \"name\": \"AssetLib.Asset\",\n              \"nodeType\": \"UserDefinedTypeName\",\n              \"referencedDeclaration\": 2788,\n              \"src\": \"5712:14:6\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                \"typeString\": \"struct AssetLib.Asset\"\n              }\n            },\n            \"value\": null,\n            \"visibility\": \"public\"\n          },\n          {\n            \"constant\": false,\n            \"functionSelector\": \"d9d8e783\",\n            \"id\": 3778,\n            \"mutability\": \"mutable\",\n            \"name\": \"_interestRatesStartIdx\",\n            \"nodeType\": \"VariableDeclaration\",\n            \"overrides\": null,\n            \"scope\": 5490,\n            \"src\": \"5770:37:6\",\n            \"stateVariable\": true,\n            \"storageLocation\": \"default\",\n            \"typeDescriptions\": {\n              \"typeIdentifier\": \"t_uint256\",\n              \"typeString\": \"uint256\"\n            },\n            \"typeName\": {\n              \"id\": 3777,\n              \"name\": \"uint256\",\n              \"nodeType\": \"ElementaryTypeName\",\n              \"src\": \"5770:7:6\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_uint256\",\n                \"typeString\": \"uint256\"\n              }\n            },\n            \"value\": null,\n            \"visibility\": \"public\"\n          },\n          {\n            \"constant\": false,\n            \"functionSelector\": \"4164b001\",\n            \"id\": 3780,\n            \"mutability\": \"mutable\",\n            \"name\": \"_interestRatesNextIdx\",\n            \"nodeType\": \"VariableDeclaration\",\n            \"overrides\": null,\n            \"scope\": 5490,\n            \"src\": \"5813:36:6\",\n            \"stateVariable\": true,\n            \"storageLocation\": \"default\",\n            \"typeDescriptions\": {\n              \"typeIdentifier\": \"t_uint256\",\n              \"typeString\": \"uint256\"\n            },\n            \"typeName\": {\n              \"id\": 3779,\n              \"name\": \"uint256\",\n              \"nodeType\": \"ElementaryTypeName\",\n              \"src\": \"5813:7:6\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_uint256\",\n                \"typeString\": \"uint256\"\n              }\n            },\n            \"value\": null,\n            \"visibility\": \"public\"\n          },\n          {\n            \"constant\": false,\n            \"functionSelector\": \"aa700ff2\",\n            \"id\": 3784,\n            \"mutability\": \"mutable\",\n            \"name\": \"_interestRates\",\n            \"nodeType\": \"VariableDeclaration\",\n            \"overrides\": null,\n            \"scope\": 5490,\n            \"src\": \"5855:62:6\",\n            \"stateVariable\": true,\n            \"storageLocation\": \"default\",\n            \"typeDescriptions\": {\n              \"typeIdentifier\": \"t_mapping$_t_uint256_$_t_struct$_InterestRatePerBlock_$3641_storage_$\",\n              \"typeString\": \"mapping(uint256 => struct Staking.InterestRatePerBlock)\"\n            },\n            \"typeName\": {\n              \"id\": 3783,\n              \"keyType\": {\n                \"id\": 3781,\n                \"name\": \"uint256\",\n                \"nodeType\": \"ElementaryTypeName\",\n                \"src\": \"5863:7:6\",\n                \"typeDescriptions\": {\n                  \"typeIdentifier\": \"t_uint256\",\n                  \"typeString\": \"uint256\"\n                }\n              },\n              \"nodeType\": \"Mapping\",\n              \"src\": \"5855:40:6\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_mapping$_t_uint256_$_t_struct$_InterestRatePerBlock_$3641_storage_$\",\n                \"typeString\": \"mapping(uint256 => struct Staking.InterestRatePerBlock)\"\n              },\n              \"valueType\": {\n                \"contractScope\": null,\n                \"id\": 3782,\n                \"name\": \"InterestRatePerBlock\",\n                \"nodeType\": \"UserDefinedTypeName\",\n                \"referencedDeclaration\": 3641,\n                \"src\": \"5874:20:6\",\n                \"typeDescriptions\": {\n                  \"typeIdentifier\": \"t_struct$_InterestRatePerBlock_$3641_storage_ptr\",\n                  \"typeString\": \"struct Staking.InterestRatePerBlock\"\n                }\n              }\n            },\n            \"value\": null,\n            \"visibility\": \"public\"\n          },\n          {\n            \"constant\": false,\n            \"id\": 3788,\n            \"mutability\": \"mutable\",\n            \"name\": \"_stakes\",\n            \"nodeType\": \"VariableDeclaration\",\n            \"overrides\": null,\n            \"scope\": 5490,\n            \"src\": \"5924:33:6\",\n            \"stateVariable\": true,\n            \"storageLocation\": \"default\",\n            \"typeDescriptions\": {\n              \"typeIdentifier\": \"t_mapping$_t_address_$_t_struct$_Stake_$3648_storage_$\",\n              \"typeString\": \"mapping(address => struct Staking.Stake)\"\n            },\n            \"typeName\": {\n              \"id\": 3787,\n              \"keyType\": {\n                \"id\": 3785,\n                \"name\": \"address\",\n                \"nodeType\": \"ElementaryTypeName\",\n                \"src\": \"5932:7:6\",\n                \"typeDescriptions\": {\n                  \"typeIdentifier\": \"t_address\",\n                  \"typeString\": \"address\"\n                }\n              },\n              \"nodeType\": \"Mapping\",\n              \"src\": \"5924:25:6\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_mapping$_t_address_$_t_struct$_Stake_$3648_storage_$\",\n                \"typeString\": \"mapping(address => struct Staking.Stake)\"\n              },\n              \"valueType\": {\n                \"contractScope\": null,\n                \"id\": 3786,\n                \"name\": \"Stake\",\n                \"nodeType\": \"UserDefinedTypeName\",\n                \"referencedDeclaration\": 3648,\n                \"src\": \"5943:5:6\",\n                \"typeDescriptions\": {\n                  \"typeIdentifier\": \"t_struct$_Stake_$3648_storage_ptr\",\n                  \"typeString\": \"struct Staking.Stake\"\n                }\n              }\n            },\n            \"value\": null,\n            \"visibility\": \"internal\"\n          },\n          {\n            \"constant\": false,\n            \"id\": 3792,\n            \"mutability\": \"mutable\",\n            \"name\": \"_locked\",\n            \"nodeType\": \"VariableDeclaration\",\n            \"overrides\": null,\n            \"scope\": 5490,\n            \"src\": \"5963:34:6\",\n            \"stateVariable\": true,\n            \"storageLocation\": \"default\",\n            \"typeDescriptions\": {\n              \"typeIdentifier\": \"t_mapping$_t_address_$_t_struct$_Locked_$3659_storage_$\",\n              \"typeString\": \"mapping(address => struct Staking.Locked)\"\n            },\n            \"typeName\": {\n              \"id\": 3791,\n              \"keyType\": {\n                \"id\": 3789,\n                \"name\": \"address\",\n                \"nodeType\": \"ElementaryTypeName\",\n                \"src\": \"5971:7:6\",\n                \"typeDescriptions\": {\n                  \"typeIdentifier\": \"t_address\",\n                  \"typeString\": \"address\"\n                }\n              },\n              \"nodeType\": \"Mapping\",\n              \"src\": \"5963:26:6\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_mapping$_t_address_$_t_struct$_Locked_$3659_storage_$\",\n                \"typeString\": \"mapping(address => struct Staking.Locked)\"\n              },\n              \"valueType\": {\n                \"contractScope\": null,\n                \"id\": 3790,\n                \"name\": \"Locked\",\n                \"nodeType\": \"UserDefinedTypeName\",\n                \"referencedDeclaration\": 3659,\n                \"src\": \"5982:6:6\",\n                \"typeDescriptions\": {\n                  \"typeIdentifier\": \"t_struct$_Locked_$3659_storage_ptr\",\n                  \"typeString\": \"struct Staking.Locked\"\n                }\n              }\n            },\n            \"value\": null,\n            \"visibility\": \"internal\"\n          },\n          {\n            \"constant\": false,\n            \"functionSelector\": \"67ce50c0\",\n            \"id\": 3796,\n            \"mutability\": \"mutable\",\n            \"name\": \"_liquidity\",\n            \"nodeType\": \"VariableDeclaration\",\n            \"overrides\": null,\n            \"scope\": 5490,\n            \"src\": \"6003:52:6\",\n            \"stateVariable\": true,\n            \"storageLocation\": \"default\",\n            \"typeDescriptions\": {\n              \"typeIdentifier\": \"t_mapping$_t_address_$_t_struct$_Asset_$2788_storage_$\",\n              \"typeString\": \"mapping(address => struct AssetLib.Asset)\"\n            },\n            \"typeName\": {\n              \"id\": 3795,\n              \"keyType\": {\n                \"id\": 3793,\n                \"name\": \"address\",\n                \"nodeType\": \"ElementaryTypeName\",\n                \"src\": \"6011:7:6\",\n                \"typeDescriptions\": {\n                  \"typeIdentifier\": \"t_address\",\n                  \"typeString\": \"address\"\n                }\n              },\n              \"nodeType\": \"Mapping\",\n              \"src\": \"6003:34:6\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_mapping$_t_address_$_t_struct$_Asset_$2788_storage_$\",\n                \"typeString\": \"mapping(address => struct AssetLib.Asset)\"\n              },\n              \"valueType\": {\n                \"contractScope\": null,\n                \"id\": 3794,\n                \"name\": \"AssetLib.Asset\",\n                \"nodeType\": \"UserDefinedTypeName\",\n                \"referencedDeclaration\": 2788,\n                \"src\": \"6022:14:6\",\n                \"typeDescriptions\": {\n                  \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                  \"typeString\": \"struct AssetLib.Asset\"\n                }\n              }\n            },\n            \"value\": null,\n            \"visibility\": \"public\"\n          },\n          {\n            \"body\": {\n              \"id\": 3805,\n              \"nodeType\": \"Block\",\n              \"src\": \"6117:73:6\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"arguments\": [],\n                        \"expression\": {\n                          \"argumentTypes\": [],\n                          \"id\": 3799,\n                          \"name\": \"_isOwner\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 5031,\n                          \"src\": \"6135:8:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_function_internal_view$__$returns$_t_bool_$\",\n                            \"typeString\": \"function () view returns (bool)\"\n                          }\n                        },\n                        \"id\": 3800,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"kind\": \"functionCall\",\n                        \"lValueRequested\": false,\n                        \"names\": [],\n                        \"nodeType\": \"FunctionCall\",\n                        \"src\": \"6135:10:6\",\n                        \"tryCall\": false,\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"hexValue\": \"43616c6c6572206973206e6f7420616e206f776e6572\",\n                        \"id\": 3801,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": true,\n                        \"kind\": \"string\",\n                        \"lValueRequested\": false,\n                        \"nodeType\": \"Literal\",\n                        \"src\": \"6147:24:6\",\n                        \"subdenomination\": null,\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_stringliteral_fba574a628f13337c8d554e12acf25c09c56b020b31ccfaf084049163a70a41b\",\n                          \"typeString\": \"literal_string \\\"Caller is not an owner\\\"\"\n                        },\n                        \"value\": \"Caller is not an owner\"\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_stringliteral_fba574a628f13337c8d554e12acf25c09c56b020b31ccfaf084049163a70a41b\",\n                          \"typeString\": \"literal_string \\\"Caller is not an owner\\\"\"\n                        }\n                      ],\n                      \"id\": 3798,\n                      \"name\": \"require\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [\n                        -18,\n                        -18\n                      ],\n                      \"referencedDeclaration\": -18,\n                      \"src\": \"6127:7:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$\",\n                        \"typeString\": \"function (bool,string memory) pure\"\n                      }\n                    },\n                    \"id\": 3802,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"6127:45:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 3803,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"6127:45:6\"\n                },\n                {\n                  \"id\": 3804,\n                  \"nodeType\": \"PlaceholderStatement\",\n                  \"src\": \"6182:1:6\"\n                }\n              ]\n            },\n            \"documentation\": null,\n            \"id\": 3806,\n            \"name\": \"onlyOwner\",\n            \"nodeType\": \"ModifierDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 3797,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"6114:2:6\"\n            },\n            \"src\": \"6096:94:6\",\n            \"virtual\": false,\n            \"visibility\": \"internal\"\n          },\n          {\n            \"body\": {\n              \"id\": 3821,\n              \"nodeType\": \"Block\",\n              \"src\": \"6265:125:6\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"commonType\": {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        },\n                        \"id\": 3816,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"leftExpression\": {\n                          \"argumentTypes\": null,\n                          \"arguments\": [],\n                          \"expression\": {\n                            \"argumentTypes\": [],\n                            \"id\": 3809,\n                            \"name\": \"_isOwner\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 5031,\n                            \"src\": \"6283:8:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_function_internal_view$__$returns$_t_bool_$\",\n                              \"typeString\": \"function () view returns (bool)\"\n                            }\n                          },\n                          \"id\": 3810,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"kind\": \"functionCall\",\n                          \"lValueRequested\": false,\n                          \"names\": [],\n                          \"nodeType\": \"FunctionCall\",\n                          \"src\": \"6283:10:6\",\n                          \"tryCall\": false,\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_bool\",\n                            \"typeString\": \"bool\"\n                          }\n                        },\n                        \"nodeType\": \"BinaryOperation\",\n                        \"operator\": \"||\",\n                        \"rightExpression\": {\n                          \"argumentTypes\": null,\n                          \"arguments\": [\n                            {\n                              \"argumentTypes\": null,\n                              \"id\": 3812,\n                              \"name\": \"DELEGATE_ROLE\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 3757,\n                              \"src\": \"6305:13:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_bytes32\",\n                                \"typeString\": \"bytes32\"\n                              }\n                            },\n                            {\n                              \"argumentTypes\": null,\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"id\": 3813,\n                                \"name\": \"msg\",\n                                \"nodeType\": \"Identifier\",\n                                \"overloadedDeclarations\": [],\n                                \"referencedDeclaration\": -15,\n                                \"src\": \"6320:3:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_magic_message\",\n                                  \"typeString\": \"msg\"\n                                }\n                              },\n                              \"id\": 3814,\n                              \"isConstant\": false,\n                              \"isLValue\": false,\n                              \"isPure\": false,\n                              \"lValueRequested\": false,\n                              \"memberName\": \"sender\",\n                              \"nodeType\": \"MemberAccess\",\n                              \"referencedDeclaration\": null,\n                              \"src\": \"6320:10:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_address_payable\",\n                                \"typeString\": \"address payable\"\n                              }\n                            }\n                          ],\n                          \"expression\": {\n                            \"argumentTypes\": [\n                              {\n                                \"typeIdentifier\": \"t_bytes32\",\n                                \"typeString\": \"bytes32\"\n                              },\n                              {\n                                \"typeIdentifier\": \"t_address_payable\",\n                                \"typeString\": \"address payable\"\n                              }\n                            ],\n                            \"id\": 3811,\n                            \"name\": \"hasRole\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 5630,\n                            \"src\": \"6297:7:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_function_internal_view$_t_bytes32_$_t_address_$returns$_t_bool_$\",\n                              \"typeString\": \"function (bytes32,address) view returns (bool)\"\n                            }\n                          },\n                          \"id\": 3815,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"kind\": \"functionCall\",\n                          \"lValueRequested\": false,\n                          \"names\": [],\n                          \"nodeType\": \"FunctionCall\",\n                          \"src\": \"6297:34:6\",\n                          \"tryCall\": false,\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_bool\",\n                            \"typeString\": \"bool\"\n                          }\n                        },\n                        \"src\": \"6283:48:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"hexValue\": \"43616c6c6572206973206e656974686572206f776e6572206e6f722064656c6567617465\",\n                        \"id\": 3817,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": true,\n                        \"kind\": \"string\",\n                        \"lValueRequested\": false,\n                        \"nodeType\": \"Literal\",\n                        \"src\": \"6333:38:6\",\n                        \"subdenomination\": null,\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_stringliteral_3c2cbf62f56025e2baf3b46dabe4ee1ab0f4be1432d0bef94b4d166423814999\",\n                          \"typeString\": \"literal_string \\\"Caller is neither owner nor delegate\\\"\"\n                        },\n                        \"value\": \"Caller is neither owner nor delegate\"\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_stringliteral_3c2cbf62f56025e2baf3b46dabe4ee1ab0f4be1432d0bef94b4d166423814999\",\n                          \"typeString\": \"literal_string \\\"Caller is neither owner nor delegate\\\"\"\n                        }\n                      ],\n                      \"id\": 3808,\n                      \"name\": \"require\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [\n                        -18,\n                        -18\n                      ],\n                      \"referencedDeclaration\": -18,\n                      \"src\": \"6275:7:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$\",\n                        \"typeString\": \"function (bool,string memory) pure\"\n                      }\n                    },\n                    \"id\": 3818,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"6275:97:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 3819,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"6275:97:6\"\n                },\n                {\n                  \"id\": 3820,\n                  \"nodeType\": \"PlaceholderStatement\",\n                  \"src\": \"6382:1:6\"\n                }\n              ]\n            },\n            \"documentation\": null,\n            \"id\": 3822,\n            \"name\": \"onlyDelegate\",\n            \"nodeType\": \"ModifierDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 3807,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"6262:2:6\"\n            },\n            \"src\": \"6241:149:6\",\n            \"virtual\": false,\n            \"visibility\": \"internal\"\n          },\n          {\n            \"body\": {\n              \"id\": 3835,\n              \"nodeType\": \"Block\",\n              \"src\": \"6449:96:6\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"commonType\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        },\n                        \"id\": 3830,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"leftExpression\": {\n                          \"argumentTypes\": null,\n                          \"arguments\": [],\n                          \"expression\": {\n                            \"argumentTypes\": [],\n                            \"id\": 3827,\n                            \"name\": \"_getBlockNumber\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 5019,\n                            \"src\": \"6467:15:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_function_internal_view$__$returns$_t_uint256_$\",\n                              \"typeString\": \"function () view returns (uint256)\"\n                            }\n                          },\n                          \"id\": 3828,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"kind\": \"functionCall\",\n                          \"lValueRequested\": false,\n                          \"names\": [],\n                          \"nodeType\": \"FunctionCall\",\n                          \"src\": \"6467:17:6\",\n                          \"tryCall\": false,\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"nodeType\": \"BinaryOperation\",\n                        \"operator\": \"<=\",\n                        \"rightExpression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 3829,\n                          \"name\": \"expirationBlock\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 3824,\n                          \"src\": \"6488:15:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"src\": \"6467:36:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"hexValue\": \"5472616e73616374696f6e2065787069726564\",\n                        \"id\": 3831,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": true,\n                        \"kind\": \"string\",\n                        \"lValueRequested\": false,\n                        \"nodeType\": \"Literal\",\n                        \"src\": \"6505:21:6\",\n                        \"subdenomination\": null,\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_stringliteral_38b57334da13daffb65e2d9cfe97bc3051af86f72807115eae867384ed846551\",\n                          \"typeString\": \"literal_string \\\"Transaction expired\\\"\"\n                        },\n                        \"value\": \"Transaction expired\"\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_stringliteral_38b57334da13daffb65e2d9cfe97bc3051af86f72807115eae867384ed846551\",\n                          \"typeString\": \"literal_string \\\"Transaction expired\\\"\"\n                        }\n                      ],\n                      \"id\": 3826,\n                      \"name\": \"require\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [\n                        -18,\n                        -18\n                      ],\n                      \"referencedDeclaration\": -18,\n                      \"src\": \"6459:7:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$\",\n                        \"typeString\": \"function (bool,string memory) pure\"\n                      }\n                    },\n                    \"id\": 3832,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"6459:68:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 3833,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"6459:68:6\"\n                },\n                {\n                  \"id\": 3834,\n                  \"nodeType\": \"PlaceholderStatement\",\n                  \"src\": \"6537:1:6\"\n                }\n              ]\n            },\n            \"documentation\": null,\n            \"id\": 3836,\n            \"name\": \"verifyTxExpiration\",\n            \"nodeType\": \"ModifierDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 3825,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 3824,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"expirationBlock\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3836,\n                  \"src\": \"6424:23:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3823,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"6424:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"6423:25:6\"\n            },\n            \"src\": \"6396:149:6\",\n            \"virtual\": false,\n            \"visibility\": \"internal\"\n          },\n          {\n            \"body\": {\n              \"id\": 3847,\n              \"nodeType\": \"Block\",\n              \"src\": \"6578:102:6\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"commonType\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        },\n                        \"id\": 3842,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"leftExpression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 3839,\n                          \"name\": \"_pausedSinceBlock\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 3766,\n                          \"src\": \"6596:17:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"nodeType\": \"BinaryOperation\",\n                        \"operator\": \">\",\n                        \"rightExpression\": {\n                          \"argumentTypes\": null,\n                          \"arguments\": [],\n                          \"expression\": {\n                            \"argumentTypes\": [],\n                            \"id\": 3840,\n                            \"name\": \"_getBlockNumber\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 5019,\n                            \"src\": \"6616:15:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_function_internal_view$__$returns$_t_uint256_$\",\n                              \"typeString\": \"function () view returns (uint256)\"\n                            }\n                          },\n                          \"id\": 3841,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"kind\": \"functionCall\",\n                          \"lValueRequested\": false,\n                          \"names\": [],\n                          \"nodeType\": \"FunctionCall\",\n                          \"src\": \"6616:17:6\",\n                          \"tryCall\": false,\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"src\": \"6596:37:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"hexValue\": \"436f6e747261637420686173206265656e20706175736564\",\n                        \"id\": 3843,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": true,\n                        \"kind\": \"string\",\n                        \"lValueRequested\": false,\n                        \"nodeType\": \"Literal\",\n                        \"src\": \"6635:26:6\",\n                        \"subdenomination\": null,\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_stringliteral_6993ab713d4a8a857f0654d36ec91738ef7ba3b8999d96006199fec5b907c586\",\n                          \"typeString\": \"literal_string \\\"Contract has been paused\\\"\"\n                        },\n                        \"value\": \"Contract has been paused\"\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_stringliteral_6993ab713d4a8a857f0654d36ec91738ef7ba3b8999d96006199fec5b907c586\",\n                          \"typeString\": \"literal_string \\\"Contract has been paused\\\"\"\n                        }\n                      ],\n                      \"id\": 3838,\n                      \"name\": \"require\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [\n                        -18,\n                        -18\n                      ],\n                      \"referencedDeclaration\": -18,\n                      \"src\": \"6588:7:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$\",\n                        \"typeString\": \"function (bool,string memory) pure\"\n                      }\n                    },\n                    \"id\": 3844,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"6588:74:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 3845,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"6588:74:6\"\n                },\n                {\n                  \"id\": 3846,\n                  \"nodeType\": \"PlaceholderStatement\",\n                  \"src\": \"6672:1:6\"\n                }\n              ]\n            },\n            \"documentation\": null,\n            \"id\": 3848,\n            \"name\": \"verifyNotPaused\",\n            \"nodeType\": \"ModifierDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 3837,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"6575:2:6\"\n            },\n            \"src\": \"6551:129:6\",\n            \"virtual\": false,\n            \"visibility\": \"internal\"\n          },\n          {\n            \"body\": {\n              \"id\": 3892,\n              \"nodeType\": \"Block\",\n              \"src\": \"7002:640:6\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 3861,\n                        \"name\": \"DEFAULT_ADMIN_ROLE\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 5584,\n                        \"src\": \"7023:18:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_bytes32\",\n                          \"typeString\": \"bytes32\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 3862,\n                          \"name\": \"msg\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": -15,\n                          \"src\": \"7043:3:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_magic_message\",\n                            \"typeString\": \"msg\"\n                          }\n                        },\n                        \"id\": 3863,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"memberName\": \"sender\",\n                        \"nodeType\": \"MemberAccess\",\n                        \"referencedDeclaration\": null,\n                        \"src\": \"7043:10:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_bytes32\",\n                          \"typeString\": \"bytes32\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        }\n                      ],\n                      \"id\": 3860,\n                      \"name\": \"_setupRole\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5767,\n                      \"src\": \"7012:10:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_nonpayable$_t_bytes32_$_t_address_$returns$__$\",\n                        \"typeString\": \"function (bytes32,address)\"\n                      }\n                    },\n                    \"id\": 3864,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"7012:42:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 3865,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"7012:42:6\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 3870,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 3866,\n                      \"name\": \"_token\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 3762,\n                      \"src\": \"7065:6:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_contract$_IERC20_$6707\",\n                        \"typeString\": \"contract IERC20\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"arguments\": [\n                        {\n                          \"argumentTypes\": null,\n                          \"id\": 3868,\n                          \"name\": \"ERC20Address\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 3851,\n                          \"src\": \"7081:12:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_address\",\n                            \"typeString\": \"address\"\n                          }\n                        }\n                      ],\n                      \"expression\": {\n                        \"argumentTypes\": [\n                          {\n                            \"typeIdentifier\": \"t_address\",\n                            \"typeString\": \"address\"\n                          }\n                        ],\n                        \"id\": 3867,\n                        \"name\": \"IERC20\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 6707,\n                        \"src\": \"7074:6:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_type$_t_contract$_IERC20_$6707_$\",\n                          \"typeString\": \"type(contract IERC20)\"\n                        }\n                      },\n                      \"id\": 3869,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": false,\n                      \"kind\": \"typeConversion\",\n                      \"lValueRequested\": false,\n                      \"names\": [],\n                      \"nodeType\": \"FunctionCall\",\n                      \"src\": \"7074:20:6\",\n                      \"tryCall\": false,\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_contract$_IERC20_$6707\",\n                        \"typeString\": \"contract IERC20\"\n                      }\n                    },\n                    \"src\": \"7065:29:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_contract$_IERC20_$6707\",\n                      \"typeString\": \"contract IERC20\"\n                    }\n                  },\n                  \"id\": 3871,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"7065:29:6\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 3878,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 3872,\n                      \"name\": \"_earliestDelete\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 3764,\n                      \"src\": \"7104:15:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"arguments\": [\n                        {\n                          \"argumentTypes\": null,\n                          \"id\": 3876,\n                          \"name\": \"DELETE_PROTECTION_PERIOD\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 3760,\n                          \"src\": \"7144:24:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        }\n                      ],\n                      \"expression\": {\n                        \"argumentTypes\": [\n                          {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        ],\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"arguments\": [],\n                          \"expression\": {\n                            \"argumentTypes\": [],\n                            \"id\": 3873,\n                            \"name\": \"_getBlockNumber\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 5019,\n                            \"src\": \"7122:15:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_function_internal_view$__$returns$_t_uint256_$\",\n                              \"typeString\": \"function () view returns (uint256)\"\n                            }\n                          },\n                          \"id\": 3874,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"kind\": \"functionCall\",\n                          \"lValueRequested\": false,\n                          \"names\": [],\n                          \"nodeType\": \"FunctionCall\",\n                          \"src\": \"7122:17:6\",\n                          \"tryCall\": false,\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"id\": 3875,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"memberName\": \"add\",\n                        \"nodeType\": \"MemberAccess\",\n                        \"referencedDeclaration\": 5870,\n                        \"src\": \"7122:21:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_function_internal_pure$_t_uint256_$_t_uint256_$returns$_t_uint256_$bound_to$_t_uint256_$\",\n                          \"typeString\": \"function (uint256,uint256) pure returns (uint256)\"\n                        }\n                      },\n                      \"id\": 3877,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": false,\n                      \"kind\": \"functionCall\",\n                      \"lValueRequested\": false,\n                      \"names\": [],\n                      \"nodeType\": \"FunctionCall\",\n                      \"src\": \"7122:47:6\",\n                      \"tryCall\": false,\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"src\": \"7104:65:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"id\": 3879,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"7104:65:6\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 3881,\n                        \"name\": \"lockPeriodInBlocks\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 3857,\n                        \"src\": \"7512:18:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint64\",\n                          \"typeString\": \"uint64\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_uint64\",\n                          \"typeString\": \"uint64\"\n                        }\n                      ],\n                      \"id\": 3880,\n                      \"name\": \"_updateLockPeriod\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5079,\n                      \"src\": \"7494:17:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_nonpayable$_t_uint64_$returns$__$\",\n                        \"typeString\": \"function (uint64)\"\n                      }\n                    },\n                    \"id\": 3882,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"7494:37:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 3883,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"7494:37:6\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 3885,\n                        \"name\": \"interestRatePerBlock\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 3853,\n                        \"src\": \"7558:20:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"id\": 3884,\n                      \"name\": \"_addInterestRate\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5064,\n                      \"src\": \"7541:16:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_nonpayable$_t_uint256_$returns$__$\",\n                        \"typeString\": \"function (uint256)\"\n                      }\n                    },\n                    \"id\": 3886,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"7541:38:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 3887,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"7541:38:6\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 3889,\n                        \"name\": \"pausedSinceBlock\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 3855,\n                        \"src\": \"7601:16:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"id\": 3888,\n                      \"name\": \"_pauseSince\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5104,\n                      \"src\": \"7589:11:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_nonpayable$_t_uint256_$returns$__$\",\n                        \"typeString\": \"function (uint256)\"\n                      }\n                    },\n                    \"id\": 3890,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"7589:46:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 3891,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"7589:46:6\"\n                }\n              ]\n            },\n            \"documentation\": {\n              \"id\": 3849,\n              \"nodeType\": \"StructuredDocumentation\",\n              \"src\": \"6756:68:6\",\n              \"text\": \"@param ERC20Address address of the ERC20 contract\"\n            },\n            \"id\": 3893,\n            \"implemented\": true,\n            \"kind\": \"constructor\",\n            \"modifiers\": [],\n            \"name\": \"\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 3858,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 3851,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"ERC20Address\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3893,\n                  \"src\": \"6852:20:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_address\",\n                    \"typeString\": \"address\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3850,\n                    \"name\": \"address\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"6852:7:6\",\n                    \"stateMutability\": \"nonpayable\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address\",\n                      \"typeString\": \"address\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 3853,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"interestRatePerBlock\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3893,\n                  \"src\": \"6883:28:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3852,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"6883:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 3855,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"pausedSinceBlock\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3893,\n                  \"src\": \"6922:24:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3854,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"6922:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 3857,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"lockPeriodInBlocks\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3893,\n                  \"src\": \"6957:26:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint64\",\n                    \"typeString\": \"uint64\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3856,\n                    \"name\": \"uint64\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"6957:6:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint64\",\n                      \"typeString\": \"uint64\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"6840:144:6\"\n            },\n            \"returnParameters\": {\n              \"id\": 3859,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"7002:0:6\"\n            },\n            \"scope\": 5490,\n            \"src\": \"6829:813:6\",\n            \"stateMutability\": \"nonpayable\",\n            \"virtual\": false,\n            \"visibility\": \"public\"\n          },\n          {\n            \"body\": {\n              \"id\": 3910,\n              \"nodeType\": \"Block\",\n              \"src\": \"8459:39:6\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 3907,\n                        \"name\": \"rate\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 3896,\n                        \"src\": \"8486:4:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"id\": 3906,\n                      \"name\": \"_addInterestRate\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5064,\n                      \"src\": \"8469:16:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_nonpayable$_t_uint256_$returns$__$\",\n                        \"typeString\": \"function (uint256)\"\n                      }\n                    },\n                    \"id\": 3908,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"8469:22:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 3909,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"8469:22:6\"\n                }\n              ]\n            },\n            \"documentation\": {\n              \"id\": 3894,\n              \"nodeType\": \"StructuredDocumentation\",\n              \"src\": \"7649:627:6\",\n              \"text\": \"@notice Add new interest rate in to the ordered container of previously added interest rates\\n@param rate - signed interest rate value in [10**18] units => real_rate [1] = rate [10**18] / 10**18\\n@param expirationBlock - block number beyond which is the carrier Tx considered expired, and so rejected.\\n                    This is for protection of Tx sender to exactly define lifecycle length of the Tx,\\n                    and so avoiding uncertainty of how long Tx sender needs to wait for Tx processing.\\n                    Tx can be withheld\\n@dev expiration period\"\n            },\n            \"functionSelector\": \"13384039\",\n            \"id\": 3911,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [\n              {\n                \"arguments\": [],\n                \"id\": 3901,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 3900,\n                  \"name\": \"onlyDelegate\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 3822,\n                  \"src\": \"8396:12:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$__$\",\n                    \"typeString\": \"modifier ()\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"8396:14:6\"\n              },\n              {\n                \"arguments\": [\n                  {\n                    \"argumentTypes\": null,\n                    \"id\": 3903,\n                    \"name\": \"expirationBlock\",\n                    \"nodeType\": \"Identifier\",\n                    \"overloadedDeclarations\": [],\n                    \"referencedDeclaration\": 3898,\n                    \"src\": \"8438:15:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  }\n                ],\n                \"id\": 3904,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 3902,\n                  \"name\": \"verifyTxExpiration\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 3836,\n                  \"src\": \"8419:18:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$_t_uint256_$\",\n                    \"typeString\": \"modifier (uint256)\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"8419:35:6\"\n              }\n            ],\n            \"name\": \"addInterestRate\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 3899,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 3896,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"rate\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3911,\n                  \"src\": \"8315:12:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3895,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"8315:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 3898,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"expirationBlock\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3911,\n                  \"src\": \"8337:23:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3897,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"8337:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"8305:65:6\"\n            },\n            \"returnParameters\": {\n              \"id\": 3905,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"8459:0:6\"\n            },\n            \"scope\": 5490,\n            \"src\": \"8281:217:6\",\n            \"stateMutability\": \"nonpayable\",\n            \"virtual\": false,\n            \"visibility\": \"external\"\n          },\n          {\n            \"body\": {\n              \"id\": 3997,\n              \"nodeType\": \"Block\",\n              \"src\": \"8682:654:6\",\n              \"statements\": [\n                {\n                  \"assignments\": [\n                    3924\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 3924,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"makeTransfer\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 3997,\n                      \"src\": \"8692:17:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"default\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_bool\",\n                        \"typeString\": \"bool\"\n                      },\n                      \"typeName\": {\n                        \"id\": 3923,\n                        \"name\": \"bool\",\n                        \"nodeType\": \"ElementaryTypeName\",\n                        \"src\": \"8692:4:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 3928,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"commonType\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    },\n                    \"id\": 3927,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftExpression\": {\n                      \"argumentTypes\": null,\n                      \"id\": 3925,\n                      \"name\": \"amount\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 3913,\n                      \"src\": \"8712:6:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"BinaryOperation\",\n                    \"operator\": \"!=\",\n                    \"rightExpression\": {\n                      \"argumentTypes\": null,\n                      \"hexValue\": \"30\",\n                      \"id\": 3926,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": true,\n                      \"kind\": \"number\",\n                      \"lValueRequested\": false,\n                      \"nodeType\": \"Literal\",\n                      \"src\": \"8722:1:6\",\n                      \"subdenomination\": null,\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_rational_0_by_1\",\n                        \"typeString\": \"int_const 0\"\n                      },\n                      \"value\": \"0\"\n                    },\n                    \"src\": \"8712:11:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_bool\",\n                      \"typeString\": \"bool\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"8692:31:6\"\n                },\n                {\n                  \"condition\": {\n                    \"argumentTypes\": null,\n                    \"id\": 3929,\n                    \"name\": \"makeTransfer\",\n                    \"nodeType\": \"Identifier\",\n                    \"overloadedDeclarations\": [],\n                    \"referencedDeclaration\": 3924,\n                    \"src\": \"8737:12:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_bool\",\n                      \"typeString\": \"bool\"\n                    }\n                  },\n                  \"falseBody\": null,\n                  \"id\": 3968,\n                  \"nodeType\": \"IfStatement\",\n                  \"src\": \"8733:352:6\",\n                  \"trueBody\": {\n                    \"id\": 3967,\n                    \"nodeType\": \"Block\",\n                    \"src\": \"8751:334:6\",\n                    \"statements\": [\n                      {\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"arguments\": [\n                            {\n                              \"argumentTypes\": null,\n                              \"arguments\": [\n                                {\n                                  \"argumentTypes\": null,\n                                  \"expression\": {\n                                    \"argumentTypes\": null,\n                                    \"id\": 3933,\n                                    \"name\": \"msg\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": -15,\n                                    \"src\": \"8793:3:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_magic_message\",\n                                      \"typeString\": \"msg\"\n                                    }\n                                  },\n                                  \"id\": 3934,\n                                  \"isConstant\": false,\n                                  \"isLValue\": false,\n                                  \"isPure\": false,\n                                  \"lValueRequested\": false,\n                                  \"memberName\": \"sender\",\n                                  \"nodeType\": \"MemberAccess\",\n                                  \"referencedDeclaration\": null,\n                                  \"src\": \"8793:10:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_address_payable\",\n                                    \"typeString\": \"address payable\"\n                                  }\n                                },\n                                {\n                                  \"argumentTypes\": null,\n                                  \"arguments\": [\n                                    {\n                                      \"argumentTypes\": null,\n                                      \"id\": 3937,\n                                      \"name\": \"this\",\n                                      \"nodeType\": \"Identifier\",\n                                      \"overloadedDeclarations\": [],\n                                      \"referencedDeclaration\": -28,\n                                      \"src\": \"8813:4:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_contract$_Staking_$5490\",\n                                        \"typeString\": \"contract Staking\"\n                                      }\n                                    }\n                                  ],\n                                  \"expression\": {\n                                    \"argumentTypes\": [\n                                      {\n                                        \"typeIdentifier\": \"t_contract$_Staking_$5490\",\n                                        \"typeString\": \"contract Staking\"\n                                      }\n                                    ],\n                                    \"id\": 3936,\n                                    \"isConstant\": false,\n                                    \"isLValue\": false,\n                                    \"isPure\": true,\n                                    \"lValueRequested\": false,\n                                    \"nodeType\": \"ElementaryTypeNameExpression\",\n                                    \"src\": \"8805:7:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_type$_t_address_$\",\n                                      \"typeString\": \"type(address)\"\n                                    },\n                                    \"typeName\": {\n                                      \"id\": 3935,\n                                      \"name\": \"address\",\n                                      \"nodeType\": \"ElementaryTypeName\",\n                                      \"src\": \"8805:7:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": null,\n                                        \"typeString\": null\n                                      }\n                                    }\n                                  },\n                                  \"id\": 3938,\n                                  \"isConstant\": false,\n                                  \"isLValue\": false,\n                                  \"isPure\": false,\n                                  \"kind\": \"typeConversion\",\n                                  \"lValueRequested\": false,\n                                  \"names\": [],\n                                  \"nodeType\": \"FunctionCall\",\n                                  \"src\": \"8805:13:6\",\n                                  \"tryCall\": false,\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_address\",\n                                    \"typeString\": \"address\"\n                                  }\n                                },\n                                {\n                                  \"argumentTypes\": null,\n                                  \"id\": 3939,\n                                  \"name\": \"amount\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 3913,\n                                  \"src\": \"8820:6:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_uint256\",\n                                    \"typeString\": \"uint256\"\n                                  }\n                                }\n                              ],\n                              \"expression\": {\n                                \"argumentTypes\": [\n                                  {\n                                    \"typeIdentifier\": \"t_address_payable\",\n                                    \"typeString\": \"address payable\"\n                                  },\n                                  {\n                                    \"typeIdentifier\": \"t_address\",\n                                    \"typeString\": \"address\"\n                                  },\n                                  {\n                                    \"typeIdentifier\": \"t_uint256\",\n                                    \"typeString\": \"uint256\"\n                                  }\n                                ],\n                                \"expression\": {\n                                  \"argumentTypes\": null,\n                                  \"id\": 3931,\n                                  \"name\": \"_token\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 3762,\n                                  \"src\": \"8773:6:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_contract$_IERC20_$6707\",\n                                    \"typeString\": \"contract IERC20\"\n                                  }\n                                },\n                                \"id\": 3932,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": false,\n                                \"lValueRequested\": false,\n                                \"memberName\": \"transferFrom\",\n                                \"nodeType\": \"MemberAccess\",\n                                \"referencedDeclaration\": 6688,\n                                \"src\": \"8773:19:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_function_external_nonpayable$_t_address_$_t_address_$_t_uint256_$returns$_t_bool_$\",\n                                  \"typeString\": \"function (address,address,uint256) external returns (bool)\"\n                                }\n                              },\n                              \"id\": 3940,\n                              \"isConstant\": false,\n                              \"isLValue\": false,\n                              \"isPure\": false,\n                              \"kind\": \"functionCall\",\n                              \"lValueRequested\": false,\n                              \"names\": [],\n                              \"nodeType\": \"FunctionCall\",\n                              \"src\": \"8773:54:6\",\n                              \"tryCall\": false,\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_bool\",\n                                \"typeString\": \"bool\"\n                              }\n                            },\n                            {\n                              \"argumentTypes\": null,\n                              \"hexValue\": \"5472616e73666572206661696c6564\",\n                              \"id\": 3941,\n                              \"isConstant\": false,\n                              \"isLValue\": false,\n                              \"isPure\": true,\n                              \"kind\": \"string\",\n                              \"lValueRequested\": false,\n                              \"nodeType\": \"Literal\",\n                              \"src\": \"8829:17:6\",\n                              \"subdenomination\": null,\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_stringliteral_25adaa6d082ce15f901e0d8a3d393e7462ef9edf2e6bc8321fa14d1615b6fc51\",\n                                \"typeString\": \"literal_string \\\"Transfer failed\\\"\"\n                              },\n                              \"value\": \"Transfer failed\"\n                            }\n                          ],\n                          \"expression\": {\n                            \"argumentTypes\": [\n                              {\n                                \"typeIdentifier\": \"t_bool\",\n                                \"typeString\": \"bool\"\n                              },\n                              {\n                                \"typeIdentifier\": \"t_stringliteral_25adaa6d082ce15f901e0d8a3d393e7462ef9edf2e6bc8321fa14d1615b6fc51\",\n                                \"typeString\": \"literal_string \\\"Transfer failed\\\"\"\n                              }\n                            ],\n                            \"id\": 3930,\n                            \"name\": \"require\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [\n                              -18,\n                              -18\n                            ],\n                            \"referencedDeclaration\": -18,\n                            \"src\": \"8765:7:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$\",\n                              \"typeString\": \"function (bool,string memory) pure\"\n                            }\n                          },\n                          \"id\": 3942,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"kind\": \"functionCall\",\n                          \"lValueRequested\": false,\n                          \"names\": [],\n                          \"nodeType\": \"FunctionCall\",\n                          \"src\": \"8765:82:6\",\n                          \"tryCall\": false,\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_tuple$__$\",\n                            \"typeString\": \"tuple()\"\n                          }\n                        },\n                        \"id\": 3943,\n                        \"nodeType\": \"ExpressionStatement\",\n                        \"src\": \"8765:82:6\"\n                      },\n                      {\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 3949,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"leftHandSide\": {\n                            \"argumentTypes\": null,\n                            \"id\": 3944,\n                            \"name\": \"_accruedGlobalPrincipal\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 3772,\n                            \"src\": \"8861:23:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"nodeType\": \"Assignment\",\n                          \"operator\": \"=\",\n                          \"rightHandSide\": {\n                            \"argumentTypes\": null,\n                            \"arguments\": [\n                              {\n                                \"argumentTypes\": null,\n                                \"id\": 3947,\n                                \"name\": \"amount\",\n                                \"nodeType\": \"Identifier\",\n                                \"overloadedDeclarations\": [],\n                                \"referencedDeclaration\": 3913,\n                                \"src\": \"8915:6:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              }\n                            ],\n                            \"expression\": {\n                              \"argumentTypes\": [\n                                {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              ],\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"id\": 3945,\n                                \"name\": \"_accruedGlobalPrincipal\",\n                                \"nodeType\": \"Identifier\",\n                                \"overloadedDeclarations\": [],\n                                \"referencedDeclaration\": 3772,\n                                \"src\": \"8887:23:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              },\n                              \"id\": 3946,\n                              \"isConstant\": false,\n                              \"isLValue\": false,\n                              \"isPure\": false,\n                              \"lValueRequested\": false,\n                              \"memberName\": \"add\",\n                              \"nodeType\": \"MemberAccess\",\n                              \"referencedDeclaration\": 5870,\n                              \"src\": \"8887:27:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_function_internal_pure$_t_uint256_$_t_uint256_$returns$_t_uint256_$bound_to$_t_uint256_$\",\n                                \"typeString\": \"function (uint256,uint256) pure returns (uint256)\"\n                              }\n                            },\n                            \"id\": 3948,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": false,\n                            \"kind\": \"functionCall\",\n                            \"lValueRequested\": false,\n                            \"names\": [],\n                            \"nodeType\": \"FunctionCall\",\n                            \"src\": \"8887:35:6\",\n                            \"tryCall\": false,\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"src\": \"8861:61:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"id\": 3950,\n                        \"nodeType\": \"ExpressionStatement\",\n                        \"src\": \"8861:61:6\"\n                      },\n                      {\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 3959,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"leftHandSide\": {\n                            \"argumentTypes\": null,\n                            \"expression\": {\n                              \"argumentTypes\": null,\n                              \"id\": 3951,\n                              \"name\": \"_accruedGlobalLiquidity\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 3774,\n                              \"src\": \"8936:23:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                                \"typeString\": \"struct AssetLib.Asset storage ref\"\n                              }\n                            },\n                            \"id\": 3953,\n                            \"isConstant\": false,\n                            \"isLValue\": true,\n                            \"isPure\": false,\n                            \"lValueRequested\": true,\n                            \"memberName\": \"principal\",\n                            \"nodeType\": \"MemberAccess\",\n                            \"referencedDeclaration\": 2785,\n                            \"src\": \"8936:33:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"nodeType\": \"Assignment\",\n                          \"operator\": \"=\",\n                          \"rightHandSide\": {\n                            \"argumentTypes\": null,\n                            \"arguments\": [\n                              {\n                                \"argumentTypes\": null,\n                                \"id\": 3957,\n                                \"name\": \"amount\",\n                                \"nodeType\": \"Identifier\",\n                                \"overloadedDeclarations\": [],\n                                \"referencedDeclaration\": 3913,\n                                \"src\": \"9010:6:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              }\n                            ],\n                            \"expression\": {\n                              \"argumentTypes\": [\n                                {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              ],\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"expression\": {\n                                  \"argumentTypes\": null,\n                                  \"id\": 3954,\n                                  \"name\": \"_accruedGlobalLiquidity\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 3774,\n                                  \"src\": \"8972:23:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                                    \"typeString\": \"struct AssetLib.Asset storage ref\"\n                                  }\n                                },\n                                \"id\": 3955,\n                                \"isConstant\": false,\n                                \"isLValue\": true,\n                                \"isPure\": false,\n                                \"lValueRequested\": false,\n                                \"memberName\": \"principal\",\n                                \"nodeType\": \"MemberAccess\",\n                                \"referencedDeclaration\": 2785,\n                                \"src\": \"8972:33:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              },\n                              \"id\": 3956,\n                              \"isConstant\": false,\n                              \"isLValue\": false,\n                              \"isPure\": false,\n                              \"lValueRequested\": false,\n                              \"memberName\": \"add\",\n                              \"nodeType\": \"MemberAccess\",\n                              \"referencedDeclaration\": 5870,\n                              \"src\": \"8972:37:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_function_internal_pure$_t_uint256_$_t_uint256_$returns$_t_uint256_$bound_to$_t_uint256_$\",\n                                \"typeString\": \"function (uint256,uint256) pure returns (uint256)\"\n                              }\n                            },\n                            \"id\": 3958,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": false,\n                            \"kind\": \"functionCall\",\n                            \"lValueRequested\": false,\n                            \"names\": [],\n                            \"nodeType\": \"FunctionCall\",\n                            \"src\": \"8972:45:6\",\n                            \"tryCall\": false,\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"src\": \"8936:81:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"id\": 3960,\n                        \"nodeType\": \"ExpressionStatement\",\n                        \"src\": \"8936:81:6\"\n                      },\n                      {\n                        \"eventCall\": {\n                          \"argumentTypes\": null,\n                          \"arguments\": [\n                            {\n                              \"argumentTypes\": null,\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"id\": 3962,\n                                \"name\": \"msg\",\n                                \"nodeType\": \"Identifier\",\n                                \"overloadedDeclarations\": [],\n                                \"referencedDeclaration\": -15,\n                                \"src\": \"9055:3:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_magic_message\",\n                                  \"typeString\": \"msg\"\n                                }\n                              },\n                              \"id\": 3963,\n                              \"isConstant\": false,\n                              \"isLValue\": false,\n                              \"isPure\": false,\n                              \"lValueRequested\": false,\n                              \"memberName\": \"sender\",\n                              \"nodeType\": \"MemberAccess\",\n                              \"referencedDeclaration\": null,\n                              \"src\": \"9055:10:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_address_payable\",\n                                \"typeString\": \"address payable\"\n                              }\n                            },\n                            {\n                              \"argumentTypes\": null,\n                              \"id\": 3964,\n                              \"name\": \"amount\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 3913,\n                              \"src\": \"9067:6:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_uint256\",\n                                \"typeString\": \"uint256\"\n                              }\n                            }\n                          ],\n                          \"expression\": {\n                            \"argumentTypes\": [\n                              {\n                                \"typeIdentifier\": \"t_address_payable\",\n                                \"typeString\": \"address payable\"\n                              },\n                              {\n                                \"typeIdentifier\": \"t_uint256\",\n                                \"typeString\": \"uint256\"\n                              }\n                            ],\n                            \"id\": 3961,\n                            \"name\": \"LiquidityDeposited\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 3686,\n                            \"src\": \"9036:18:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_function_event_nonpayable$_t_address_$_t_uint256_$returns$__$\",\n                              \"typeString\": \"function (address,uint256)\"\n                            }\n                          },\n                          \"id\": 3965,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"kind\": \"functionCall\",\n                          \"lValueRequested\": false,\n                          \"names\": [],\n                          \"nodeType\": \"FunctionCall\",\n                          \"src\": \"9036:38:6\",\n                          \"tryCall\": false,\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_tuple$__$\",\n                            \"typeString\": \"tuple()\"\n                          }\n                        },\n                        \"id\": 3966,\n                        \"nodeType\": \"EmitStatement\",\n                        \"src\": \"9031:43:6\"\n                      }\n                    ]\n                  }\n                },\n                {\n                  \"assignments\": [\n                    3970\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 3970,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"curr_block\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 3997,\n                      \"src\": \"9095:18:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"default\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      },\n                      \"typeName\": {\n                        \"id\": 3969,\n                        \"name\": \"uint256\",\n                        \"nodeType\": \"ElementaryTypeName\",\n                        \"src\": \"9095:7:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 3973,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [],\n                    \"expression\": {\n                      \"argumentTypes\": [],\n                      \"id\": 3971,\n                      \"name\": \"_getBlockNumber\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5019,\n                      \"src\": \"9116:15:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_view$__$returns$_t_uint256_$\",\n                        \"typeString\": \"function () view returns (uint256)\"\n                      }\n                    },\n                    \"id\": 3972,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"9116:17:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"9095:38:6\"\n                },\n                {\n                  \"assignments\": [\n                    null,\n                    3977,\n                    null\n                  ],\n                  \"declarations\": [\n                    null,\n                    {\n                      \"constant\": false,\n                      \"id\": 3977,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"liquidity\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 3997,\n                      \"src\": \"9146:32:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"storage\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                        \"typeString\": \"struct AssetLib.Asset\"\n                      },\n                      \"typeName\": {\n                        \"contractScope\": null,\n                        \"id\": 3976,\n                        \"name\": \"AssetLib.Asset\",\n                        \"nodeType\": \"UserDefinedTypeName\",\n                        \"referencedDeclaration\": 2788,\n                        \"src\": \"9146:14:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                          \"typeString\": \"struct AssetLib.Asset\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    },\n                    null\n                  ],\n                  \"id\": 3983,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 3979,\n                          \"name\": \"msg\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": -15,\n                          \"src\": \"9201:3:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_magic_message\",\n                            \"typeString\": \"msg\"\n                          }\n                        },\n                        \"id\": 3980,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"memberName\": \"sender\",\n                        \"nodeType\": \"MemberAccess\",\n                        \"referencedDeclaration\": null,\n                        \"src\": \"9201:10:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 3981,\n                        \"name\": \"curr_block\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 3970,\n                        \"src\": \"9213:10:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"id\": 3978,\n                      \"name\": \"_collectLiquidity\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5489,\n                      \"src\": \"9183:17:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_nonpayable$_t_address_$_t_uint256_$returns$_t_struct$_Asset_$2788_memory_ptr_$_t_struct$_Asset_$2788_storage_ptr_$_t_bool_$\",\n                        \"typeString\": \"function (address,uint256) returns (struct AssetLib.Asset memory,struct AssetLib.Asset storage pointer,bool)\"\n                      }\n                    },\n                    \"id\": 3982,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"9183:41:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$_t_struct$_Asset_$2788_memory_ptr_$_t_struct$_Asset_$2788_storage_ptr_$_t_bool_$\",\n                      \"typeString\": \"tuple(struct AssetLib.Asset memory,struct AssetLib.Asset storage pointer,bool)\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"9143:81:6\"\n                },\n                {\n                  \"condition\": {\n                    \"argumentTypes\": null,\n                    \"id\": 3984,\n                    \"name\": \"makeTransfer\",\n                    \"nodeType\": \"Identifier\",\n                    \"overloadedDeclarations\": [],\n                    \"referencedDeclaration\": 3924,\n                    \"src\": \"9239:12:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_bool\",\n                      \"typeString\": \"bool\"\n                    }\n                  },\n                  \"falseBody\": null,\n                  \"id\": 3996,\n                  \"nodeType\": \"IfStatement\",\n                  \"src\": \"9235:95:6\",\n                  \"trueBody\": {\n                    \"id\": 3995,\n                    \"nodeType\": \"Block\",\n                    \"src\": \"9253:77:6\",\n                    \"statements\": [\n                      {\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 3993,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"leftHandSide\": {\n                            \"argumentTypes\": null,\n                            \"expression\": {\n                              \"argumentTypes\": null,\n                              \"id\": 3985,\n                              \"name\": \"liquidity\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 3977,\n                              \"src\": \"9267:9:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                                \"typeString\": \"struct AssetLib.Asset storage pointer\"\n                              }\n                            },\n                            \"id\": 3987,\n                            \"isConstant\": false,\n                            \"isLValue\": true,\n                            \"isPure\": false,\n                            \"lValueRequested\": true,\n                            \"memberName\": \"principal\",\n                            \"nodeType\": \"MemberAccess\",\n                            \"referencedDeclaration\": 2785,\n                            \"src\": \"9267:19:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"nodeType\": \"Assignment\",\n                          \"operator\": \"=\",\n                          \"rightHandSide\": {\n                            \"argumentTypes\": null,\n                            \"arguments\": [\n                              {\n                                \"argumentTypes\": null,\n                                \"id\": 3991,\n                                \"name\": \"amount\",\n                                \"nodeType\": \"Identifier\",\n                                \"overloadedDeclarations\": [],\n                                \"referencedDeclaration\": 3913,\n                                \"src\": \"9313:6:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              }\n                            ],\n                            \"expression\": {\n                              \"argumentTypes\": [\n                                {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              ],\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"expression\": {\n                                  \"argumentTypes\": null,\n                                  \"id\": 3988,\n                                  \"name\": \"liquidity\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 3977,\n                                  \"src\": \"9289:9:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                                    \"typeString\": \"struct AssetLib.Asset storage pointer\"\n                                  }\n                                },\n                                \"id\": 3989,\n                                \"isConstant\": false,\n                                \"isLValue\": true,\n                                \"isPure\": false,\n                                \"lValueRequested\": false,\n                                \"memberName\": \"principal\",\n                                \"nodeType\": \"MemberAccess\",\n                                \"referencedDeclaration\": 2785,\n                                \"src\": \"9289:19:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              },\n                              \"id\": 3990,\n                              \"isConstant\": false,\n                              \"isLValue\": false,\n                              \"isPure\": false,\n                              \"lValueRequested\": false,\n                              \"memberName\": \"add\",\n                              \"nodeType\": \"MemberAccess\",\n                              \"referencedDeclaration\": 5870,\n                              \"src\": \"9289:23:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_function_internal_pure$_t_uint256_$_t_uint256_$returns$_t_uint256_$bound_to$_t_uint256_$\",\n                                \"typeString\": \"function (uint256,uint256) pure returns (uint256)\"\n                              }\n                            },\n                            \"id\": 3992,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": false,\n                            \"kind\": \"functionCall\",\n                            \"lValueRequested\": false,\n                            \"names\": [],\n                            \"nodeType\": \"FunctionCall\",\n                            \"src\": \"9289:31:6\",\n                            \"tryCall\": false,\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"src\": \"9267:53:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"id\": 3994,\n                        \"nodeType\": \"ExpressionStatement\",\n                        \"src\": \"9267:53:6\"\n                      }\n                    ]\n                  }\n                }\n              ]\n            },\n            \"documentation\": null,\n            \"functionSelector\": \"e2bbb158\",\n            \"id\": 3998,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [\n              {\n                \"arguments\": [\n                  {\n                    \"argumentTypes\": null,\n                    \"id\": 3918,\n                    \"name\": \"txExpirationBlock\",\n                    \"nodeType\": \"Identifier\",\n                    \"overloadedDeclarations\": [],\n                    \"referencedDeclaration\": 3915,\n                    \"src\": \"8635:17:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  }\n                ],\n                \"id\": 3919,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 3917,\n                  \"name\": \"verifyTxExpiration\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 3836,\n                  \"src\": \"8616:18:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$_t_uint256_$\",\n                    \"typeString\": \"modifier (uint256)\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"8616:37:6\"\n              },\n              {\n                \"arguments\": null,\n                \"id\": 3921,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 3920,\n                  \"name\": \"verifyNotPaused\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 3848,\n                  \"src\": \"8662:15:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$__$\",\n                    \"typeString\": \"modifier ()\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"8662:15:6\"\n              }\n            ],\n            \"name\": \"deposit\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 3916,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 3913,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"amount\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3998,\n                  \"src\": \"8531:14:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3912,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"8531:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 3915,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"txExpirationBlock\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3998,\n                  \"src\": \"8555:25:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3914,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"8555:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"8521:69:6\"\n            },\n            \"returnParameters\": {\n              \"id\": 3922,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"8682:0:6\"\n            },\n            \"scope\": 5490,\n            \"src\": \"8505:831:6\",\n            \"stateMutability\": \"nonpayable\",\n            \"virtual\": false,\n            \"visibility\": \"external\"\n          },\n          {\n            \"body\": {\n              \"id\": 4045,\n              \"nodeType\": \"Block\",\n              \"src\": \"9796:317:6\",\n              \"statements\": [\n                {\n                  \"assignments\": [\n                    4012\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 4012,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"sender\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 4045,\n                      \"src\": \"9806:14:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"default\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_address\",\n                        \"typeString\": \"address\"\n                      },\n                      \"typeName\": {\n                        \"id\": 4011,\n                        \"name\": \"address\",\n                        \"nodeType\": \"ElementaryTypeName\",\n                        \"src\": \"9806:7:6\",\n                        \"stateMutability\": \"nonpayable\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 4015,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"expression\": {\n                      \"argumentTypes\": null,\n                      \"id\": 4013,\n                      \"name\": \"msg\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": -15,\n                      \"src\": \"9823:3:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_magic_message\",\n                        \"typeString\": \"msg\"\n                      }\n                    },\n                    \"id\": 4014,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"memberName\": \"sender\",\n                    \"nodeType\": \"MemberAccess\",\n                    \"referencedDeclaration\": null,\n                    \"src\": \"9823:10:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address_payable\",\n                      \"typeString\": \"address payable\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"9806:27:6\"\n                },\n                {\n                  \"assignments\": [\n                    4017\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 4017,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"curr_block\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 4045,\n                      \"src\": \"9843:18:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"default\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      },\n                      \"typeName\": {\n                        \"id\": 4016,\n                        \"name\": \"uint256\",\n                        \"nodeType\": \"ElementaryTypeName\",\n                        \"src\": \"9843:7:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 4020,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [],\n                    \"expression\": {\n                      \"argumentTypes\": [],\n                      \"id\": 4018,\n                      \"name\": \"_getBlockNumber\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5019,\n                      \"src\": \"9864:15:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_view$__$returns$_t_uint256_$\",\n                        \"typeString\": \"function () view returns (uint256)\"\n                      }\n                    },\n                    \"id\": 4019,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"9864:17:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"9843:38:6\"\n                },\n                {\n                  \"assignments\": [\n                    null,\n                    4024,\n                    null\n                  ],\n                  \"declarations\": [\n                    null,\n                    {\n                      \"constant\": false,\n                      \"id\": 4024,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"liquidity\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 4045,\n                      \"src\": \"9894:32:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"storage\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                        \"typeString\": \"struct AssetLib.Asset\"\n                      },\n                      \"typeName\": {\n                        \"contractScope\": null,\n                        \"id\": 4023,\n                        \"name\": \"AssetLib.Asset\",\n                        \"nodeType\": \"UserDefinedTypeName\",\n                        \"referencedDeclaration\": 2788,\n                        \"src\": \"9894:14:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                          \"typeString\": \"struct AssetLib.Asset\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    },\n                    null\n                  ],\n                  \"id\": 4029,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 4026,\n                        \"name\": \"sender\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4012,\n                        \"src\": \"9949:6:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 4027,\n                        \"name\": \"curr_block\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4017,\n                        \"src\": \"9957:10:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"id\": 4025,\n                      \"name\": \"_collectLiquidity\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5489,\n                      \"src\": \"9931:17:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_nonpayable$_t_address_$_t_uint256_$returns$_t_struct$_Asset_$2788_memory_ptr_$_t_struct$_Asset_$2788_storage_ptr_$_t_bool_$\",\n                        \"typeString\": \"function (address,uint256) returns (struct AssetLib.Asset memory,struct AssetLib.Asset storage pointer,bool)\"\n                      }\n                    },\n                    \"id\": 4028,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"9931:37:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$_t_struct$_Asset_$2788_memory_ptr_$_t_struct$_Asset_$2788_storage_ptr_$_t_bool_$\",\n                      \"typeString\": \"tuple(struct AssetLib.Asset memory,struct AssetLib.Asset storage pointer,bool)\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"9891:77:6\"\n                },\n                {\n                  \"assignments\": [\n                    4033\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 4033,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"_amount\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 4045,\n                      \"src\": \"9979:29:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"memory\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                        \"typeString\": \"struct AssetLib.Asset\"\n                      },\n                      \"typeName\": {\n                        \"contractScope\": null,\n                        \"id\": 4032,\n                        \"name\": \"AssetLib.Asset\",\n                        \"nodeType\": \"UserDefinedTypeName\",\n                        \"referencedDeclaration\": 2788,\n                        \"src\": \"9979:14:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                          \"typeString\": \"struct AssetLib.Asset\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 4038,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 4036,\n                        \"name\": \"amount\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4001,\n                        \"src\": \"10047:6:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 4034,\n                        \"name\": \"liquidity\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4024,\n                        \"src\": \"10011:9:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                          \"typeString\": \"struct AssetLib.Asset storage pointer\"\n                        }\n                      },\n                      \"id\": 4035,\n                      \"isConstant\": false,\n                      \"isLValue\": true,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"memberName\": \"iSubCompoundInterestFirst\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": 3072,\n                      \"src\": \"10011:35:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_nonpayable$_t_struct$_Asset_$2788_storage_ptr_$_t_uint256_$returns$_t_struct$_Asset_$2788_memory_ptr_$bound_to$_t_struct$_Asset_$2788_storage_ptr_$\",\n                        \"typeString\": \"function (struct AssetLib.Asset storage pointer,uint256) returns (struct AssetLib.Asset memory)\"\n                      }\n                    },\n                    \"id\": 4037,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"10011:43:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                      \"typeString\": \"struct AssetLib.Asset memory\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"9979:75:6\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 4040,\n                        \"name\": \"sender\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4012,\n                        \"src\": \"10082:6:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 4041,\n                        \"name\": \"_amount\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4033,\n                        \"src\": \"10090:7:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                          \"typeString\": \"struct AssetLib.Asset memory\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 4042,\n                        \"name\": \"amount\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4001,\n                        \"src\": \"10099:6:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                          \"typeString\": \"struct AssetLib.Asset memory\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"id\": 4039,\n                      \"name\": \"_finaliseWithdraw\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5168,\n                      \"src\": \"10064:17:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_nonpayable$_t_address_$_t_struct$_Asset_$2788_memory_ptr_$_t_uint256_$returns$__$\",\n                        \"typeString\": \"function (address,struct AssetLib.Asset memory,uint256)\"\n                      }\n                    },\n                    \"id\": 4043,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"10064:42:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 4044,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"10064:42:6\"\n                }\n              ]\n            },\n            \"documentation\": {\n              \"id\": 3999,\n              \"nodeType\": \"StructuredDocumentation\",\n              \"src\": \"9343:270:6\",\n              \"text\": \"@notice Withdraws amount from sender' available liquidity pool back to sender address,\\n        preferring withdrawal from compound interest dimension of liquidity.\\n     * @param amount - value to withdraw\\n     * @dev public access\"\n            },\n            \"functionSelector\": \"441a3e70\",\n            \"id\": 4046,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [\n              {\n                \"arguments\": [\n                  {\n                    \"argumentTypes\": null,\n                    \"id\": 4006,\n                    \"name\": \"txExpirationBlock\",\n                    \"nodeType\": \"Identifier\",\n                    \"overloadedDeclarations\": [],\n                    \"referencedDeclaration\": 4003,\n                    \"src\": \"9749:17:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  }\n                ],\n                \"id\": 4007,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 4005,\n                  \"name\": \"verifyTxExpiration\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 3836,\n                  \"src\": \"9730:18:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$_t_uint256_$\",\n                    \"typeString\": \"modifier (uint256)\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"9730:37:6\"\n              },\n              {\n                \"arguments\": null,\n                \"id\": 4009,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 4008,\n                  \"name\": \"verifyNotPaused\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 3848,\n                  \"src\": \"9776:15:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$__$\",\n                    \"typeString\": \"modifier ()\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"9776:15:6\"\n              }\n            ],\n            \"name\": \"withdraw\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 4004,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 4001,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"amount\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4046,\n                  \"src\": \"9645:14:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 4000,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"9645:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 4003,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"txExpirationBlock\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4046,\n                  \"src\": \"9669:25:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 4002,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"9669:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"9635:69:6\"\n            },\n            \"returnParameters\": {\n              \"id\": 4010,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"9796:0:6\"\n            },\n            \"scope\": 5490,\n            \"src\": \"9618:495:6\",\n            \"stateMutability\": \"nonpayable\",\n            \"virtual\": false,\n            \"visibility\": \"external\"\n          },\n          {\n            \"body\": {\n              \"id\": 4101,\n              \"nodeType\": \"Block\",\n              \"src\": \"10411:366:6\",\n              \"statements\": [\n                {\n                  \"assignments\": [\n                    4058\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 4058,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"sender\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 4101,\n                      \"src\": \"10421:14:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"default\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_address\",\n                        \"typeString\": \"address\"\n                      },\n                      \"typeName\": {\n                        \"id\": 4057,\n                        \"name\": \"address\",\n                        \"nodeType\": \"ElementaryTypeName\",\n                        \"src\": \"10421:7:6\",\n                        \"stateMutability\": \"nonpayable\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 4061,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"expression\": {\n                      \"argumentTypes\": null,\n                      \"id\": 4059,\n                      \"name\": \"msg\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": -15,\n                      \"src\": \"10438:3:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_magic_message\",\n                        \"typeString\": \"msg\"\n                      }\n                    },\n                    \"id\": 4060,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"memberName\": \"sender\",\n                    \"nodeType\": \"MemberAccess\",\n                    \"referencedDeclaration\": null,\n                    \"src\": \"10438:10:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address_payable\",\n                      \"typeString\": \"address payable\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"10421:27:6\"\n                },\n                {\n                  \"assignments\": [\n                    4063\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 4063,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"curr_block\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 4101,\n                      \"src\": \"10458:18:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"default\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      },\n                      \"typeName\": {\n                        \"id\": 4062,\n                        \"name\": \"uint256\",\n                        \"nodeType\": \"ElementaryTypeName\",\n                        \"src\": \"10458:7:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 4066,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [],\n                    \"expression\": {\n                      \"argumentTypes\": [],\n                      \"id\": 4064,\n                      \"name\": \"_getBlockNumber\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5019,\n                      \"src\": \"10479:15:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_view$__$returns$_t_uint256_$\",\n                        \"typeString\": \"function () view returns (uint256)\"\n                      }\n                    },\n                    \"id\": 4065,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"10479:17:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"10458:38:6\"\n                },\n                {\n                  \"assignments\": [\n                    null,\n                    4070,\n                    null\n                  ],\n                  \"declarations\": [\n                    null,\n                    {\n                      \"constant\": false,\n                      \"id\": 4070,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"liquidity\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 4101,\n                      \"src\": \"10509:32:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"storage\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                        \"typeString\": \"struct AssetLib.Asset\"\n                      },\n                      \"typeName\": {\n                        \"contractScope\": null,\n                        \"id\": 4069,\n                        \"name\": \"AssetLib.Asset\",\n                        \"nodeType\": \"UserDefinedTypeName\",\n                        \"referencedDeclaration\": 2788,\n                        \"src\": \"10509:14:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                          \"typeString\": \"struct AssetLib.Asset\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    },\n                    null\n                  ],\n                  \"id\": 4075,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 4072,\n                        \"name\": \"sender\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4058,\n                        \"src\": \"10565:6:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 4073,\n                        \"name\": \"curr_block\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4063,\n                        \"src\": \"10573:10:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"id\": 4071,\n                      \"name\": \"_collectLiquidity\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5489,\n                      \"src\": \"10547:17:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_nonpayable$_t_address_$_t_uint256_$returns$_t_struct$_Asset_$2788_memory_ptr_$_t_struct$_Asset_$2788_storage_ptr_$_t_bool_$\",\n                        \"typeString\": \"function (address,uint256) returns (struct AssetLib.Asset memory,struct AssetLib.Asset storage pointer,bool)\"\n                      }\n                    },\n                    \"id\": 4074,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"10547:37:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$_t_struct$_Asset_$2788_memory_ptr_$_t_struct$_Asset_$2788_storage_ptr_$_t_bool_$\",\n                      \"typeString\": \"tuple(struct AssetLib.Asset memory,struct AssetLib.Asset storage pointer,bool)\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"10506:78:6\"\n                },\n                {\n                  \"assignments\": [\n                    4079\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 4079,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"_amount\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 4101,\n                      \"src\": \"10595:29:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"memory\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                        \"typeString\": \"struct AssetLib.Asset\"\n                      },\n                      \"typeName\": {\n                        \"contractScope\": null,\n                        \"id\": 4078,\n                        \"name\": \"AssetLib.Asset\",\n                        \"nodeType\": \"UserDefinedTypeName\",\n                        \"referencedDeclaration\": 2788,\n                        \"src\": \"10595:14:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                          \"typeString\": \"struct AssetLib.Asset\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 4080,\n                  \"initialValue\": null,\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"10595:29:6\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 4086,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 4081,\n                        \"name\": \"_amount\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4079,\n                        \"src\": \"10634:7:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                          \"typeString\": \"struct AssetLib.Asset memory\"\n                        }\n                      },\n                      \"id\": 4083,\n                      \"isConstant\": false,\n                      \"isLValue\": true,\n                      \"isPure\": false,\n                      \"lValueRequested\": true,\n                      \"memberName\": \"principal\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": 2785,\n                      \"src\": \"10634:17:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 4084,\n                        \"name\": \"liquidity\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4070,\n                        \"src\": \"10654:9:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                          \"typeString\": \"struct AssetLib.Asset storage pointer\"\n                        }\n                      },\n                      \"id\": 4085,\n                      \"isConstant\": false,\n                      \"isLValue\": true,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"memberName\": \"principal\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": 2785,\n                      \"src\": \"10654:19:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"src\": \"10634:39:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"id\": 4087,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"10634:39:6\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 4092,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 4088,\n                        \"name\": \"liquidity\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4070,\n                        \"src\": \"10683:9:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                          \"typeString\": \"struct AssetLib.Asset storage pointer\"\n                        }\n                      },\n                      \"id\": 4090,\n                      \"isConstant\": false,\n                      \"isLValue\": true,\n                      \"isPure\": false,\n                      \"lValueRequested\": true,\n                      \"memberName\": \"principal\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": 2785,\n                      \"src\": \"10683:19:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"hexValue\": \"30\",\n                      \"id\": 4091,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": true,\n                      \"kind\": \"number\",\n                      \"lValueRequested\": false,\n                      \"nodeType\": \"Literal\",\n                      \"src\": \"10705:1:6\",\n                      \"subdenomination\": null,\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_rational_0_by_1\",\n                        \"typeString\": \"int_const 0\"\n                      },\n                      \"value\": \"0\"\n                    },\n                    \"src\": \"10683:23:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"id\": 4093,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"10683:23:6\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 4095,\n                        \"name\": \"sender\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4058,\n                        \"src\": \"10735:6:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 4096,\n                        \"name\": \"_amount\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4079,\n                        \"src\": \"10743:7:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                          \"typeString\": \"struct AssetLib.Asset memory\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 4097,\n                          \"name\": \"_amount\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 4079,\n                          \"src\": \"10752:7:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                            \"typeString\": \"struct AssetLib.Asset memory\"\n                          }\n                        },\n                        \"id\": 4098,\n                        \"isConstant\": false,\n                        \"isLValue\": true,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"memberName\": \"principal\",\n                        \"nodeType\": \"MemberAccess\",\n                        \"referencedDeclaration\": 2785,\n                        \"src\": \"10752:17:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                          \"typeString\": \"struct AssetLib.Asset memory\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"id\": 4094,\n                      \"name\": \"_finaliseWithdraw\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5168,\n                      \"src\": \"10717:17:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_nonpayable$_t_address_$_t_struct$_Asset_$2788_memory_ptr_$_t_uint256_$returns$__$\",\n                        \"typeString\": \"function (address,struct AssetLib.Asset memory,uint256)\"\n                      }\n                    },\n                    \"id\": 4099,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"10717:53:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 4100,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"10717:53:6\"\n                }\n              ]\n            },\n            \"documentation\": {\n              \"id\": 4047,\n              \"nodeType\": \"StructuredDocumentation\",\n              \"src\": \"10120:123:6\",\n              \"text\": \"@notice Withdraws *WHOLE* compound interest amount available to sender.\\n     * @dev public access\"\n            },\n            \"functionSelector\": \"658e28a4\",\n            \"id\": 4102,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [\n              {\n                \"arguments\": [\n                  {\n                    \"argumentTypes\": null,\n                    \"id\": 4052,\n                    \"name\": \"txExpirationBlock\",\n                    \"nodeType\": \"Identifier\",\n                    \"overloadedDeclarations\": [],\n                    \"referencedDeclaration\": 4049,\n                    \"src\": \"10364:17:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  }\n                ],\n                \"id\": 4053,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 4051,\n                  \"name\": \"verifyTxExpiration\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 3836,\n                  \"src\": \"10345:18:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$_t_uint256_$\",\n                    \"typeString\": \"modifier (uint256)\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"10345:37:6\"\n              },\n              {\n                \"arguments\": null,\n                \"id\": 4055,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 4054,\n                  \"name\": \"verifyNotPaused\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 3848,\n                  \"src\": \"10391:15:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$__$\",\n                    \"typeString\": \"modifier ()\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"10391:15:6\"\n              }\n            ],\n            \"name\": \"withdrawPrincipal\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 4050,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 4049,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"txExpirationBlock\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4102,\n                  \"src\": \"10284:25:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 4048,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"10284:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"10274:45:6\"\n            },\n            \"returnParameters\": {\n              \"id\": 4056,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"10411:0:6\"\n            },\n            \"scope\": 5490,\n            \"src\": \"10248:529:6\",\n            \"stateMutability\": \"nonpayable\",\n            \"virtual\": false,\n            \"visibility\": \"external\"\n          },\n          {\n            \"body\": {\n              \"id\": 4157,\n              \"nodeType\": \"Block\",\n              \"src\": \"11082:394:6\",\n              \"statements\": [\n                {\n                  \"assignments\": [\n                    4114\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 4114,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"sender\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 4157,\n                      \"src\": \"11092:14:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"default\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_address\",\n                        \"typeString\": \"address\"\n                      },\n                      \"typeName\": {\n                        \"id\": 4113,\n                        \"name\": \"address\",\n                        \"nodeType\": \"ElementaryTypeName\",\n                        \"src\": \"11092:7:6\",\n                        \"stateMutability\": \"nonpayable\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 4117,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"expression\": {\n                      \"argumentTypes\": null,\n                      \"id\": 4115,\n                      \"name\": \"msg\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": -15,\n                      \"src\": \"11109:3:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_magic_message\",\n                        \"typeString\": \"msg\"\n                      }\n                    },\n                    \"id\": 4116,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"memberName\": \"sender\",\n                    \"nodeType\": \"MemberAccess\",\n                    \"referencedDeclaration\": null,\n                    \"src\": \"11109:10:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address_payable\",\n                      \"typeString\": \"address payable\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"11092:27:6\"\n                },\n                {\n                  \"assignments\": [\n                    4119\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 4119,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"curr_block\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 4157,\n                      \"src\": \"11129:18:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"default\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      },\n                      \"typeName\": {\n                        \"id\": 4118,\n                        \"name\": \"uint256\",\n                        \"nodeType\": \"ElementaryTypeName\",\n                        \"src\": \"11129:7:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 4122,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [],\n                    \"expression\": {\n                      \"argumentTypes\": [],\n                      \"id\": 4120,\n                      \"name\": \"_getBlockNumber\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5019,\n                      \"src\": \"11150:15:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_view$__$returns$_t_uint256_$\",\n                        \"typeString\": \"function () view returns (uint256)\"\n                      }\n                    },\n                    \"id\": 4121,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"11150:17:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"11129:38:6\"\n                },\n                {\n                  \"assignments\": [\n                    null,\n                    4126,\n                    null\n                  ],\n                  \"declarations\": [\n                    null,\n                    {\n                      \"constant\": false,\n                      \"id\": 4126,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"liquidity\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 4157,\n                      \"src\": \"11180:32:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"storage\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                        \"typeString\": \"struct AssetLib.Asset\"\n                      },\n                      \"typeName\": {\n                        \"contractScope\": null,\n                        \"id\": 4125,\n                        \"name\": \"AssetLib.Asset\",\n                        \"nodeType\": \"UserDefinedTypeName\",\n                        \"referencedDeclaration\": 2788,\n                        \"src\": \"11180:14:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                          \"typeString\": \"struct AssetLib.Asset\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    },\n                    null\n                  ],\n                  \"id\": 4131,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 4128,\n                        \"name\": \"sender\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4114,\n                        \"src\": \"11236:6:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 4129,\n                        \"name\": \"curr_block\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4119,\n                        \"src\": \"11244:10:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"id\": 4127,\n                      \"name\": \"_collectLiquidity\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5489,\n                      \"src\": \"11218:17:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_nonpayable$_t_address_$_t_uint256_$returns$_t_struct$_Asset_$2788_memory_ptr_$_t_struct$_Asset_$2788_storage_ptr_$_t_bool_$\",\n                        \"typeString\": \"function (address,uint256) returns (struct AssetLib.Asset memory,struct AssetLib.Asset storage pointer,bool)\"\n                      }\n                    },\n                    \"id\": 4130,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"11218:37:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$_t_struct$_Asset_$2788_memory_ptr_$_t_struct$_Asset_$2788_storage_ptr_$_t_bool_$\",\n                      \"typeString\": \"tuple(struct AssetLib.Asset memory,struct AssetLib.Asset storage pointer,bool)\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"11177:78:6\"\n                },\n                {\n                  \"assignments\": [\n                    4135\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 4135,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"_amount\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 4157,\n                      \"src\": \"11266:29:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"memory\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                        \"typeString\": \"struct AssetLib.Asset\"\n                      },\n                      \"typeName\": {\n                        \"contractScope\": null,\n                        \"id\": 4134,\n                        \"name\": \"AssetLib.Asset\",\n                        \"nodeType\": \"UserDefinedTypeName\",\n                        \"referencedDeclaration\": 2788,\n                        \"src\": \"11266:14:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                          \"typeString\": \"struct AssetLib.Asset\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 4136,\n                  \"initialValue\": null,\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"11266:29:6\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 4142,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 4137,\n                        \"name\": \"_amount\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4135,\n                        \"src\": \"11305:7:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                          \"typeString\": \"struct AssetLib.Asset memory\"\n                        }\n                      },\n                      \"id\": 4139,\n                      \"isConstant\": false,\n                      \"isLValue\": true,\n                      \"isPure\": false,\n                      \"lValueRequested\": true,\n                      \"memberName\": \"compoundInterest\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": 2787,\n                      \"src\": \"11305:24:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 4140,\n                        \"name\": \"liquidity\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4126,\n                        \"src\": \"11332:9:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                          \"typeString\": \"struct AssetLib.Asset storage pointer\"\n                        }\n                      },\n                      \"id\": 4141,\n                      \"isConstant\": false,\n                      \"isLValue\": true,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"memberName\": \"compoundInterest\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": 2787,\n                      \"src\": \"11332:26:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"src\": \"11305:53:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"id\": 4143,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"11305:53:6\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 4148,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 4144,\n                        \"name\": \"liquidity\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4126,\n                        \"src\": \"11368:9:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                          \"typeString\": \"struct AssetLib.Asset storage pointer\"\n                        }\n                      },\n                      \"id\": 4146,\n                      \"isConstant\": false,\n                      \"isLValue\": true,\n                      \"isPure\": false,\n                      \"lValueRequested\": true,\n                      \"memberName\": \"compoundInterest\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": 2787,\n                      \"src\": \"11368:26:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"hexValue\": \"30\",\n                      \"id\": 4147,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": true,\n                      \"kind\": \"number\",\n                      \"lValueRequested\": false,\n                      \"nodeType\": \"Literal\",\n                      \"src\": \"11397:1:6\",\n                      \"subdenomination\": null,\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_rational_0_by_1\",\n                        \"typeString\": \"int_const 0\"\n                      },\n                      \"value\": \"0\"\n                    },\n                    \"src\": \"11368:30:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"id\": 4149,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"11368:30:6\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 4151,\n                        \"name\": \"sender\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4114,\n                        \"src\": \"11427:6:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 4152,\n                        \"name\": \"_amount\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4135,\n                        \"src\": \"11435:7:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                          \"typeString\": \"struct AssetLib.Asset memory\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 4153,\n                          \"name\": \"_amount\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 4135,\n                          \"src\": \"11444:7:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                            \"typeString\": \"struct AssetLib.Asset memory\"\n                          }\n                        },\n                        \"id\": 4154,\n                        \"isConstant\": false,\n                        \"isLValue\": true,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"memberName\": \"compoundInterest\",\n                        \"nodeType\": \"MemberAccess\",\n                        \"referencedDeclaration\": 2787,\n                        \"src\": \"11444:24:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                          \"typeString\": \"struct AssetLib.Asset memory\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"id\": 4150,\n                      \"name\": \"_finaliseWithdraw\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5168,\n                      \"src\": \"11409:17:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_nonpayable$_t_address_$_t_struct$_Asset_$2788_memory_ptr_$_t_uint256_$returns$__$\",\n                        \"typeString\": \"function (address,struct AssetLib.Asset memory,uint256)\"\n                      }\n                    },\n                    \"id\": 4155,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"11409:60:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 4156,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"11409:60:6\"\n                }\n              ]\n            },\n            \"documentation\": {\n              \"id\": 4103,\n              \"nodeType\": \"StructuredDocumentation\",\n              \"src\": \"10784:123:6\",\n              \"text\": \"@notice Withdraws *WHOLE* compound interest amount available to sender.\\n     * @dev public access\"\n            },\n            \"functionSelector\": \"d8cd3999\",\n            \"id\": 4158,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [\n              {\n                \"arguments\": [\n                  {\n                    \"argumentTypes\": null,\n                    \"id\": 4108,\n                    \"name\": \"txExpirationBlock\",\n                    \"nodeType\": \"Identifier\",\n                    \"overloadedDeclarations\": [],\n                    \"referencedDeclaration\": 4105,\n                    \"src\": \"11035:17:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  }\n                ],\n                \"id\": 4109,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 4107,\n                  \"name\": \"verifyTxExpiration\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 3836,\n                  \"src\": \"11016:18:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$_t_uint256_$\",\n                    \"typeString\": \"modifier (uint256)\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"11016:37:6\"\n              },\n              {\n                \"arguments\": null,\n                \"id\": 4111,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 4110,\n                  \"name\": \"verifyNotPaused\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 3848,\n                  \"src\": \"11062:15:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$__$\",\n                    \"typeString\": \"modifier ()\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"11062:15:6\"\n              }\n            ],\n            \"name\": \"withdrawCompoundInterest\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 4106,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 4105,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"txExpirationBlock\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4158,\n                  \"src\": \"10955:25:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 4104,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"10955:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"10945:45:6\"\n            },\n            \"returnParameters\": {\n              \"id\": 4112,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"11082:0:6\"\n            },\n            \"scope\": 5490,\n            \"src\": \"10912:564:6\",\n            \"stateMutability\": \"nonpayable\",\n            \"virtual\": false,\n            \"visibility\": \"external\"\n          },\n          {\n            \"body\": {\n              \"id\": 4208,\n              \"nodeType\": \"Block\",\n              \"src\": \"11786:323:6\",\n              \"statements\": [\n                {\n                  \"assignments\": [\n                    4170\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 4170,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"sender\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 4208,\n                      \"src\": \"11796:14:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"default\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_address\",\n                        \"typeString\": \"address\"\n                      },\n                      \"typeName\": {\n                        \"id\": 4169,\n                        \"name\": \"address\",\n                        \"nodeType\": \"ElementaryTypeName\",\n                        \"src\": \"11796:7:6\",\n                        \"stateMutability\": \"nonpayable\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 4173,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"expression\": {\n                      \"argumentTypes\": null,\n                      \"id\": 4171,\n                      \"name\": \"msg\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": -15,\n                      \"src\": \"11813:3:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_magic_message\",\n                        \"typeString\": \"msg\"\n                      }\n                    },\n                    \"id\": 4172,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"memberName\": \"sender\",\n                    \"nodeType\": \"MemberAccess\",\n                    \"referencedDeclaration\": null,\n                    \"src\": \"11813:10:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address_payable\",\n                      \"typeString\": \"address payable\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"11796:27:6\"\n                },\n                {\n                  \"assignments\": [\n                    4175\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 4175,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"curr_block\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 4208,\n                      \"src\": \"11833:18:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"default\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      },\n                      \"typeName\": {\n                        \"id\": 4174,\n                        \"name\": \"uint256\",\n                        \"nodeType\": \"ElementaryTypeName\",\n                        \"src\": \"11833:7:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 4178,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [],\n                    \"expression\": {\n                      \"argumentTypes\": [],\n                      \"id\": 4176,\n                      \"name\": \"_getBlockNumber\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5019,\n                      \"src\": \"11854:15:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_view$__$returns$_t_uint256_$\",\n                        \"typeString\": \"function () view returns (uint256)\"\n                      }\n                    },\n                    \"id\": 4177,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"11854:17:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"11833:38:6\"\n                },\n                {\n                  \"assignments\": [\n                    null,\n                    4182,\n                    null\n                  ],\n                  \"declarations\": [\n                    null,\n                    {\n                      \"constant\": false,\n                      \"id\": 4182,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"liquidity\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 4208,\n                      \"src\": \"11884:32:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"storage\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                        \"typeString\": \"struct AssetLib.Asset\"\n                      },\n                      \"typeName\": {\n                        \"contractScope\": null,\n                        \"id\": 4181,\n                        \"name\": \"AssetLib.Asset\",\n                        \"nodeType\": \"UserDefinedTypeName\",\n                        \"referencedDeclaration\": 2788,\n                        \"src\": \"11884:14:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                          \"typeString\": \"struct AssetLib.Asset\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    },\n                    null\n                  ],\n                  \"id\": 4187,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 4184,\n                        \"name\": \"sender\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4170,\n                        \"src\": \"11940:6:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 4185,\n                        \"name\": \"curr_block\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4175,\n                        \"src\": \"11948:10:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"id\": 4183,\n                      \"name\": \"_collectLiquidity\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5489,\n                      \"src\": \"11922:17:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_nonpayable$_t_address_$_t_uint256_$returns$_t_struct$_Asset_$2788_memory_ptr_$_t_struct$_Asset_$2788_storage_ptr_$_t_bool_$\",\n                        \"typeString\": \"function (address,uint256) returns (struct AssetLib.Asset memory,struct AssetLib.Asset storage pointer,bool)\"\n                      }\n                    },\n                    \"id\": 4186,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"11922:37:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$_t_struct$_Asset_$2788_memory_ptr_$_t_struct$_Asset_$2788_storage_ptr_$_t_bool_$\",\n                      \"typeString\": \"tuple(struct AssetLib.Asset memory,struct AssetLib.Asset storage pointer,bool)\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"11881:78:6\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 4189,\n                        \"name\": \"sender\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4170,\n                        \"src\": \"11988:6:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 4190,\n                        \"name\": \"liquidity\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4182,\n                        \"src\": \"11996:9:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                          \"typeString\": \"struct AssetLib.Asset storage pointer\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"arguments\": [],\n                        \"expression\": {\n                          \"argumentTypes\": [],\n                          \"expression\": {\n                            \"argumentTypes\": null,\n                            \"id\": 4191,\n                            \"name\": \"liquidity\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 4182,\n                            \"src\": \"12007:9:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                              \"typeString\": \"struct AssetLib.Asset storage pointer\"\n                            }\n                          },\n                          \"id\": 4192,\n                          \"isConstant\": false,\n                          \"isLValue\": true,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"memberName\": \"composite\",\n                          \"nodeType\": \"MemberAccess\",\n                          \"referencedDeclaration\": 2803,\n                          \"src\": \"12007:19:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_function_internal_view$_t_struct$_Asset_$2788_storage_ptr_$returns$_t_uint256_$bound_to$_t_struct$_Asset_$2788_storage_ptr_$\",\n                            \"typeString\": \"function (struct AssetLib.Asset storage pointer) view returns (uint256)\"\n                          }\n                        },\n                        \"id\": 4193,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"kind\": \"functionCall\",\n                        \"lValueRequested\": false,\n                        \"names\": [],\n                        \"nodeType\": \"FunctionCall\",\n                        \"src\": \"12007:21:6\",\n                        \"tryCall\": false,\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                          \"typeString\": \"struct AssetLib.Asset storage pointer\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"id\": 4188,\n                      \"name\": \"_finaliseWithdraw\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5168,\n                      \"src\": \"11970:17:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_nonpayable$_t_address_$_t_struct$_Asset_$2788_memory_ptr_$_t_uint256_$returns$__$\",\n                        \"typeString\": \"function (address,struct AssetLib.Asset memory,uint256)\"\n                      }\n                    },\n                    \"id\": 4194,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"11970:59:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 4195,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"11970:59:6\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 4200,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 4196,\n                        \"name\": \"liquidity\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4182,\n                        \"src\": \"12039:9:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                          \"typeString\": \"struct AssetLib.Asset storage pointer\"\n                        }\n                      },\n                      \"id\": 4198,\n                      \"isConstant\": false,\n                      \"isLValue\": true,\n                      \"isPure\": false,\n                      \"lValueRequested\": true,\n                      \"memberName\": \"compoundInterest\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": 2787,\n                      \"src\": \"12039:26:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"hexValue\": \"30\",\n                      \"id\": 4199,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": true,\n                      \"kind\": \"number\",\n                      \"lValueRequested\": false,\n                      \"nodeType\": \"Literal\",\n                      \"src\": \"12068:1:6\",\n                      \"subdenomination\": null,\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_rational_0_by_1\",\n                        \"typeString\": \"int_const 0\"\n                      },\n                      \"value\": \"0\"\n                    },\n                    \"src\": \"12039:30:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"id\": 4201,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"12039:30:6\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 4206,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 4202,\n                        \"name\": \"liquidity\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4182,\n                        \"src\": \"12079:9:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                          \"typeString\": \"struct AssetLib.Asset storage pointer\"\n                        }\n                      },\n                      \"id\": 4204,\n                      \"isConstant\": false,\n                      \"isLValue\": true,\n                      \"isPure\": false,\n                      \"lValueRequested\": true,\n                      \"memberName\": \"principal\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": 2785,\n                      \"src\": \"12079:19:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"hexValue\": \"30\",\n                      \"id\": 4205,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": true,\n                      \"kind\": \"number\",\n                      \"lValueRequested\": false,\n                      \"nodeType\": \"Literal\",\n                      \"src\": \"12101:1:6\",\n                      \"subdenomination\": null,\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_rational_0_by_1\",\n                        \"typeString\": \"int_const 0\"\n                      },\n                      \"value\": \"0\"\n                    },\n                    \"src\": \"12079:23:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"id\": 4207,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"12079:23:6\"\n                }\n              ]\n            },\n            \"documentation\": {\n              \"id\": 4159,\n              \"nodeType\": \"StructuredDocumentation\",\n              \"src\": \"11483:130:6\",\n              \"text\": \"@notice Withdraws whole liquidity available to sender back to sender' address,\\n     * @dev public access\"\n            },\n            \"functionSelector\": \"dca2aa5c\",\n            \"id\": 4209,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [\n              {\n                \"arguments\": [\n                  {\n                    \"argumentTypes\": null,\n                    \"id\": 4164,\n                    \"name\": \"txExpirationBlock\",\n                    \"nodeType\": \"Identifier\",\n                    \"overloadedDeclarations\": [],\n                    \"referencedDeclaration\": 4161,\n                    \"src\": \"11739:17:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  }\n                ],\n                \"id\": 4165,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 4163,\n                  \"name\": \"verifyTxExpiration\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 3836,\n                  \"src\": \"11720:18:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$_t_uint256_$\",\n                    \"typeString\": \"modifier (uint256)\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"11720:37:6\"\n              },\n              {\n                \"arguments\": null,\n                \"id\": 4167,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 4166,\n                  \"name\": \"verifyNotPaused\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 3848,\n                  \"src\": \"11766:15:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$__$\",\n                    \"typeString\": \"modifier ()\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"11766:15:6\"\n              }\n            ],\n            \"name\": \"withdrawWholeLiquidity\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 4162,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 4161,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"txExpirationBlock\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4209,\n                  \"src\": \"11659:25:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 4160,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"11659:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"11649:45:6\"\n            },\n            \"returnParameters\": {\n              \"id\": 4168,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"11786:0:6\"\n            },\n            \"scope\": 5490,\n            \"src\": \"11618:491:6\",\n            \"stateMutability\": \"nonpayable\",\n            \"virtual\": false,\n            \"visibility\": \"external\"\n          },\n          {\n            \"body\": {\n              \"id\": 4279,\n              \"nodeType\": \"Block\",\n              \"src\": \"12295:1112:6\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"commonType\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        },\n                        \"id\": 4224,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"leftExpression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 4222,\n                          \"name\": \"amount\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 4211,\n                          \"src\": \"12313:6:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"nodeType\": \"BinaryOperation\",\n                        \"operator\": \"!=\",\n                        \"rightExpression\": {\n                          \"argumentTypes\": null,\n                          \"hexValue\": \"30\",\n                          \"id\": 4223,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": true,\n                          \"kind\": \"number\",\n                          \"lValueRequested\": false,\n                          \"nodeType\": \"Literal\",\n                          \"src\": \"12323:1:6\",\n                          \"subdenomination\": null,\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_rational_0_by_1\",\n                            \"typeString\": \"int_const 0\"\n                          },\n                          \"value\": \"0\"\n                        },\n                        \"src\": \"12313:11:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"hexValue\": \"416d6f756e74206d75737420626520686967686572207468616e207a65726f\",\n                        \"id\": 4225,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": true,\n                        \"kind\": \"string\",\n                        \"lValueRequested\": false,\n                        \"nodeType\": \"Literal\",\n                        \"src\": \"12326:33:6\",\n                        \"subdenomination\": null,\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_stringliteral_8b5d38bfd9d56e06c511eeb946d76a1a45a72ed25ba1d513f75809a38de68bdb\",\n                          \"typeString\": \"literal_string \\\"Amount must be higher than zero\\\"\"\n                        },\n                        \"value\": \"Amount must be higher than zero\"\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_stringliteral_8b5d38bfd9d56e06c511eeb946d76a1a45a72ed25ba1d513f75809a38de68bdb\",\n                          \"typeString\": \"literal_string \\\"Amount must be higher than zero\\\"\"\n                        }\n                      ],\n                      \"id\": 4221,\n                      \"name\": \"require\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [\n                        -18,\n                        -18\n                      ],\n                      \"referencedDeclaration\": -18,\n                      \"src\": \"12305:7:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$\",\n                        \"typeString\": \"function (bool,string memory) pure\"\n                      }\n                    },\n                    \"id\": 4226,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"12305:55:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 4227,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"12305:55:6\"\n                },\n                {\n                  \"assignments\": [\n                    4229\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 4229,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"curr_block\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 4279,\n                      \"src\": \"12371:18:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"default\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      },\n                      \"typeName\": {\n                        \"id\": 4228,\n                        \"name\": \"uint256\",\n                        \"nodeType\": \"ElementaryTypeName\",\n                        \"src\": \"12371:7:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 4232,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [],\n                    \"expression\": {\n                      \"argumentTypes\": [],\n                      \"id\": 4230,\n                      \"name\": \"_getBlockNumber\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5019,\n                      \"src\": \"12392:15:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_view$__$returns$_t_uint256_$\",\n                        \"typeString\": \"function () view returns (uint256)\"\n                      }\n                    },\n                    \"id\": 4231,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"12392:17:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"12371:38:6\"\n                },\n                {\n                  \"assignments\": [\n                    null,\n                    4236,\n                    null\n                  ],\n                  \"declarations\": [\n                    null,\n                    {\n                      \"constant\": false,\n                      \"id\": 4236,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"liquidity\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 4279,\n                      \"src\": \"12423:32:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"storage\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                        \"typeString\": \"struct AssetLib.Asset\"\n                      },\n                      \"typeName\": {\n                        \"contractScope\": null,\n                        \"id\": 4235,\n                        \"name\": \"AssetLib.Asset\",\n                        \"nodeType\": \"UserDefinedTypeName\",\n                        \"referencedDeclaration\": 2788,\n                        \"src\": \"12423:14:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                          \"typeString\": \"struct AssetLib.Asset\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    },\n                    null\n                  ],\n                  \"id\": 4242,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 4238,\n                          \"name\": \"msg\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": -15,\n                          \"src\": \"12479:3:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_magic_message\",\n                            \"typeString\": \"msg\"\n                          }\n                        },\n                        \"id\": 4239,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"memberName\": \"sender\",\n                        \"nodeType\": \"MemberAccess\",\n                        \"referencedDeclaration\": null,\n                        \"src\": \"12479:10:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 4240,\n                        \"name\": \"curr_block\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4229,\n                        \"src\": \"12491:10:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"id\": 4237,\n                      \"name\": \"_collectLiquidity\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5489,\n                      \"src\": \"12461:17:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_nonpayable$_t_address_$_t_uint256_$returns$_t_struct$_Asset_$2788_memory_ptr_$_t_struct$_Asset_$2788_storage_ptr_$_t_bool_$\",\n                        \"typeString\": \"function (address,uint256) returns (struct AssetLib.Asset memory,struct AssetLib.Asset storage pointer,bool)\"\n                      }\n                    },\n                    \"id\": 4241,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"12461:41:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$_t_struct$_Asset_$2788_memory_ptr_$_t_struct$_Asset_$2788_storage_ptr_$_t_bool_$\",\n                      \"typeString\": \"tuple(struct AssetLib.Asset memory,struct AssetLib.Asset storage pointer,bool)\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"12420:82:6\"\n                },\n                {\n                  \"assignments\": [\n                    4244\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 4244,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"stake\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 4279,\n                      \"src\": \"12848:19:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"storage\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_struct$_Stake_$3648_storage_ptr\",\n                        \"typeString\": \"struct Staking.Stake\"\n                      },\n                      \"typeName\": {\n                        \"contractScope\": null,\n                        \"id\": 4243,\n                        \"name\": \"Stake\",\n                        \"nodeType\": \"UserDefinedTypeName\",\n                        \"referencedDeclaration\": 3648,\n                        \"src\": \"12848:5:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Stake_$3648_storage_ptr\",\n                          \"typeString\": \"struct Staking.Stake\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 4250,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 4246,\n                          \"name\": \"msg\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": -15,\n                          \"src\": \"12899:3:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_magic_message\",\n                            \"typeString\": \"msg\"\n                          }\n                        },\n                        \"id\": 4247,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"memberName\": \"sender\",\n                        \"nodeType\": \"MemberAccess\",\n                        \"referencedDeclaration\": null,\n                        \"src\": \"12899:10:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 4248,\n                        \"name\": \"curr_block\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4229,\n                        \"src\": \"12911:10:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"id\": 4245,\n                      \"name\": \"_updateStakeCompoundInterest\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5315,\n                      \"src\": \"12870:28:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_nonpayable$_t_address_$_t_uint256_$returns$_t_struct$_Stake_$3648_storage_ptr_$\",\n                        \"typeString\": \"function (address,uint256) returns (struct Staking.Stake storage pointer)\"\n                      }\n                    },\n                    \"id\": 4249,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"12870:52:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_struct$_Stake_$3648_storage_ptr\",\n                      \"typeString\": \"struct Staking.Stake storage pointer\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"12848:74:6\"\n                },\n                {\n                  \"assignments\": [\n                    4254\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 4254,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"_amount\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 4279,\n                      \"src\": \"12932:29:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"memory\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                        \"typeString\": \"struct AssetLib.Asset\"\n                      },\n                      \"typeName\": {\n                        \"contractScope\": null,\n                        \"id\": 4253,\n                        \"name\": \"AssetLib.Asset\",\n                        \"nodeType\": \"UserDefinedTypeName\",\n                        \"referencedDeclaration\": 2788,\n                        \"src\": \"12932:14:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                          \"typeString\": \"struct AssetLib.Asset\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 4261,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 4257,\n                          \"name\": \"stake\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 4244,\n                          \"src\": \"12998:5:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_struct$_Stake_$3648_storage_ptr\",\n                            \"typeString\": \"struct Staking.Stake storage pointer\"\n                          }\n                        },\n                        \"id\": 4258,\n                        \"isConstant\": false,\n                        \"isLValue\": true,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"memberName\": \"asset\",\n                        \"nodeType\": \"MemberAccess\",\n                        \"referencedDeclaration\": 3647,\n                        \"src\": \"12998:11:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                          \"typeString\": \"struct AssetLib.Asset storage ref\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 4259,\n                        \"name\": \"amount\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4211,\n                        \"src\": \"13011:6:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                          \"typeString\": \"struct AssetLib.Asset storage ref\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 4255,\n                        \"name\": \"liquidity\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4236,\n                        \"src\": \"12964:9:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                          \"typeString\": \"struct AssetLib.Asset storage pointer\"\n                        }\n                      },\n                      \"id\": 4256,\n                      \"isConstant\": false,\n                      \"isLValue\": true,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"memberName\": \"iRelocatePrincipalFirst\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": 3096,\n                      \"src\": \"12964:33:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_nonpayable$_t_struct$_Asset_$2788_storage_ptr_$_t_struct$_Asset_$2788_storage_ptr_$_t_uint256_$returns$_t_struct$_Asset_$2788_memory_ptr_$bound_to$_t_struct$_Asset_$2788_storage_ptr_$\",\n                        \"typeString\": \"function (struct AssetLib.Asset storage pointer,struct AssetLib.Asset storage pointer,uint256) returns (struct AssetLib.Asset memory)\"\n                      }\n                    },\n                    \"id\": 4260,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"12964:54:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                      \"typeString\": \"struct AssetLib.Asset memory\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"12932:86:6\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 4265,\n                        \"name\": \"_amount\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4254,\n                        \"src\": \"13057:7:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                          \"typeString\": \"struct AssetLib.Asset memory\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                          \"typeString\": \"struct AssetLib.Asset memory\"\n                        }\n                      ],\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 4262,\n                        \"name\": \"_accruedGlobalLiquidity\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 3774,\n                        \"src\": \"13028:23:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                          \"typeString\": \"struct AssetLib.Asset storage ref\"\n                        }\n                      },\n                      \"id\": 4264,\n                      \"isConstant\": false,\n                      \"isLValue\": true,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"memberName\": \"iSub\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": 2938,\n                      \"src\": \"13028:28:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_nonpayable$_t_struct$_Asset_$2788_storage_ptr_$_t_struct$_Asset_$2788_memory_ptr_$returns$__$bound_to$_t_struct$_Asset_$2788_storage_ptr_$\",\n                        \"typeString\": \"function (struct AssetLib.Asset storage pointer,struct AssetLib.Asset memory)\"\n                      }\n                    },\n                    \"id\": 4266,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"13028:37:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 4267,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"13028:37:6\"\n                },\n                {\n                  \"eventCall\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 4269,\n                          \"name\": \"msg\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": -15,\n                          \"src\": \"13302:3:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_magic_message\",\n                            \"typeString\": \"msg\"\n                          }\n                        },\n                        \"id\": 4270,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"memberName\": \"sender\",\n                        \"nodeType\": \"MemberAccess\",\n                        \"referencedDeclaration\": null,\n                        \"src\": \"13302:10:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 4271,\n                          \"name\": \"stake\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 4244,\n                          \"src\": \"13314:5:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_struct$_Stake_$3648_storage_ptr\",\n                            \"typeString\": \"struct Staking.Stake storage pointer\"\n                          }\n                        },\n                        \"id\": 4272,\n                        \"isConstant\": false,\n                        \"isLValue\": true,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"memberName\": \"sinceInterestRateIndex\",\n                        \"nodeType\": \"MemberAccess\",\n                        \"referencedDeclaration\": 3645,\n                        \"src\": \"13314:28:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 4273,\n                          \"name\": \"_amount\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 4254,\n                          \"src\": \"13344:7:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                            \"typeString\": \"struct AssetLib.Asset memory\"\n                          }\n                        },\n                        \"id\": 4274,\n                        \"isConstant\": false,\n                        \"isLValue\": true,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"memberName\": \"principal\",\n                        \"nodeType\": \"MemberAccess\",\n                        \"referencedDeclaration\": 2785,\n                        \"src\": \"13344:17:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 4275,\n                          \"name\": \"_amount\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 4254,\n                          \"src\": \"13363:7:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                            \"typeString\": \"struct AssetLib.Asset memory\"\n                          }\n                        },\n                        \"id\": 4276,\n                        \"isConstant\": false,\n                        \"isLValue\": true,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"memberName\": \"compoundInterest\",\n                        \"nodeType\": \"MemberAccess\",\n                        \"referencedDeclaration\": 2787,\n                        \"src\": \"13363:24:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"id\": 4268,\n                      \"name\": \"BindStake\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 3669,\n                      \"src\": \"13292:9:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_event_nonpayable$_t_address_$_t_uint256_$_t_uint256_$_t_uint256_$returns$__$\",\n                        \"typeString\": \"function (address,uint256,uint256,uint256)\"\n                      }\n                    },\n                    \"id\": 4277,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"13292:96:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 4278,\n                  \"nodeType\": \"EmitStatement\",\n                  \"src\": \"13287:101:6\"\n                }\n              ]\n            },\n            \"documentation\": null,\n            \"functionSelector\": \"88cedd5e\",\n            \"id\": 4280,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [\n              {\n                \"arguments\": [\n                  {\n                    \"argumentTypes\": null,\n                    \"id\": 4216,\n                    \"name\": \"txExpirationBlock\",\n                    \"nodeType\": \"Identifier\",\n                    \"overloadedDeclarations\": [],\n                    \"referencedDeclaration\": 4213,\n                    \"src\": \"12248:17:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  }\n                ],\n                \"id\": 4217,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 4215,\n                  \"name\": \"verifyTxExpiration\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 3836,\n                  \"src\": \"12229:18:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$_t_uint256_$\",\n                    \"typeString\": \"modifier (uint256)\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"12229:37:6\"\n              },\n              {\n                \"arguments\": null,\n                \"id\": 4219,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 4218,\n                  \"name\": \"verifyNotPaused\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 3848,\n                  \"src\": \"12275:15:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$__$\",\n                    \"typeString\": \"modifier ()\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"12275:15:6\"\n              }\n            ],\n            \"name\": \"bindStake\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 4214,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 4211,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"amount\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4280,\n                  \"src\": \"12144:14:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 4210,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"12144:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 4213,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"txExpirationBlock\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4280,\n                  \"src\": \"12168:25:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 4212,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"12168:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"12134:69:6\"\n            },\n            \"returnParameters\": {\n              \"id\": 4220,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"12295:0:6\"\n            },\n            \"scope\": 5490,\n            \"src\": \"12116:1291:6\",\n            \"stateMutability\": \"nonpayable\",\n            \"virtual\": false,\n            \"visibility\": \"external\"\n          },\n          {\n            \"body\": {\n              \"id\": 4549,\n              \"nodeType\": \"Block\",\n              \"src\": \"14400:3414:6\",\n              \"statements\": [\n                {\n                  \"assignments\": [\n                    4294\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 4294,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"curr_block\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 4549,\n                      \"src\": \"14410:18:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"default\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      },\n                      \"typeName\": {\n                        \"id\": 4293,\n                        \"name\": \"uint256\",\n                        \"nodeType\": \"ElementaryTypeName\",\n                        \"src\": \"14410:7:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 4297,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [],\n                    \"expression\": {\n                      \"argumentTypes\": [],\n                      \"id\": 4295,\n                      \"name\": \"_getBlockNumber\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5019,\n                      \"src\": \"14431:15:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_view$__$returns$_t_uint256_$\",\n                        \"typeString\": \"function () view returns (uint256)\"\n                      }\n                    },\n                    \"id\": 4296,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"14431:17:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"14410:38:6\"\n                },\n                {\n                  \"assignments\": [\n                    4299\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 4299,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"sender\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 4549,\n                      \"src\": \"14458:14:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"default\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_address\",\n                        \"typeString\": \"address\"\n                      },\n                      \"typeName\": {\n                        \"id\": 4298,\n                        \"name\": \"address\",\n                        \"nodeType\": \"ElementaryTypeName\",\n                        \"src\": \"14458:7:6\",\n                        \"stateMutability\": \"nonpayable\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 4302,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"expression\": {\n                      \"argumentTypes\": null,\n                      \"id\": 4300,\n                      \"name\": \"msg\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": -15,\n                      \"src\": \"14475:3:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_magic_message\",\n                        \"typeString\": \"msg\"\n                      }\n                    },\n                    \"id\": 4301,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"memberName\": \"sender\",\n                    \"nodeType\": \"MemberAccess\",\n                    \"referencedDeclaration\": null,\n                    \"src\": \"14475:10:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address_payable\",\n                      \"typeString\": \"address payable\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"14458:27:6\"\n                },\n                {\n                  \"assignments\": [\n                    4304\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 4304,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"stake\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 4549,\n                      \"src\": \"14495:19:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"storage\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_struct$_Stake_$3648_storage_ptr\",\n                        \"typeString\": \"struct Staking.Stake\"\n                      },\n                      \"typeName\": {\n                        \"contractScope\": null,\n                        \"id\": 4303,\n                        \"name\": \"Stake\",\n                        \"nodeType\": \"UserDefinedTypeName\",\n                        \"referencedDeclaration\": 3648,\n                        \"src\": \"14495:5:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Stake_$3648_storage_ptr\",\n                          \"typeString\": \"struct Staking.Stake\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 4309,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 4306,\n                        \"name\": \"sender\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4299,\n                        \"src\": \"14546:6:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 4307,\n                        \"name\": \"curr_block\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4294,\n                        \"src\": \"14554:10:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"id\": 4305,\n                      \"name\": \"_updateStakeCompoundInterest\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5315,\n                      \"src\": \"14517:28:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_nonpayable$_t_address_$_t_uint256_$returns$_t_struct$_Stake_$3648_storage_ptr_$\",\n                        \"typeString\": \"function (address,uint256) returns (struct Staking.Stake storage pointer)\"\n                      }\n                    },\n                    \"id\": 4308,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"14517:48:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_struct$_Stake_$3648_storage_ptr\",\n                      \"typeString\": \"struct Staking.Stake storage pointer\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"14495:70:6\"\n                },\n                {\n                  \"assignments\": [\n                    4311\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 4311,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"stake_composite\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 4549,\n                      \"src\": \"14576:23:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"default\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      },\n                      \"typeName\": {\n                        \"id\": 4310,\n                        \"name\": \"uint256\",\n                        \"nodeType\": \"ElementaryTypeName\",\n                        \"src\": \"14576:7:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 4316,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [],\n                    \"expression\": {\n                      \"argumentTypes\": [],\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 4312,\n                          \"name\": \"stake\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 4304,\n                          \"src\": \"14602:5:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_struct$_Stake_$3648_storage_ptr\",\n                            \"typeString\": \"struct Staking.Stake storage pointer\"\n                          }\n                        },\n                        \"id\": 4313,\n                        \"isConstant\": false,\n                        \"isLValue\": true,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"memberName\": \"asset\",\n                        \"nodeType\": \"MemberAccess\",\n                        \"referencedDeclaration\": 3647,\n                        \"src\": \"14602:11:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                          \"typeString\": \"struct AssetLib.Asset storage ref\"\n                        }\n                      },\n                      \"id\": 4314,\n                      \"isConstant\": false,\n                      \"isLValue\": true,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"memberName\": \"composite\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": 2803,\n                      \"src\": \"14602:21:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_view$_t_struct$_Asset_$2788_storage_ptr_$returns$_t_uint256_$bound_to$_t_struct$_Asset_$2788_storage_ptr_$\",\n                        \"typeString\": \"function (struct AssetLib.Asset storage pointer) view returns (uint256)\"\n                      }\n                    },\n                    \"id\": 4315,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"14602:23:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"14576:49:6\"\n                },\n                {\n                  \"assignments\": [\n                    4320\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 4320,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"_amount\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 4549,\n                      \"src\": \"14635:29:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"memory\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                        \"typeString\": \"struct AssetLib.Asset\"\n                      },\n                      \"typeName\": {\n                        \"contractScope\": null,\n                        \"id\": 4319,\n                        \"name\": \"AssetLib.Asset\",\n                        \"nodeType\": \"UserDefinedTypeName\",\n                        \"referencedDeclaration\": 2788,\n                        \"src\": \"14635:14:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                          \"typeString\": \"struct AssetLib.Asset\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 4321,\n                  \"initialValue\": null,\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"14635:29:6\"\n                },\n                {\n                  \"condition\": {\n                    \"argumentTypes\": null,\n                    \"commonType\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    },\n                    \"id\": 4324,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftExpression\": {\n                      \"argumentTypes\": null,\n                      \"id\": 4322,\n                      \"name\": \"amount\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 4283,\n                      \"src\": \"14679:6:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"BinaryOperation\",\n                    \"operator\": \">\",\n                    \"rightExpression\": {\n                      \"argumentTypes\": null,\n                      \"hexValue\": \"30\",\n                      \"id\": 4323,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": true,\n                      \"kind\": \"number\",\n                      \"lValueRequested\": false,\n                      \"nodeType\": \"Literal\",\n                      \"src\": \"14688:1:6\",\n                      \"subdenomination\": null,\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_rational_0_by_1\",\n                        \"typeString\": \"int_const 0\"\n                      },\n                      \"value\": \"0\"\n                    },\n                    \"src\": \"14679:10:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_bool\",\n                      \"typeString\": \"bool\"\n                    }\n                  },\n                  \"falseBody\": {\n                    \"id\": 4547,\n                    \"nodeType\": \"Block\",\n                    \"src\": \"16562:1246:6\",\n                    \"statements\": [\n                      {\n                        \"condition\": {\n                          \"argumentTypes\": null,\n                          \"commonType\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          },\n                          \"id\": 4431,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"leftExpression\": {\n                            \"argumentTypes\": null,\n                            \"id\": 4429,\n                            \"name\": \"stake_composite\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 4311,\n                            \"src\": \"16580:15:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"nodeType\": \"BinaryOperation\",\n                          \"operator\": \"==\",\n                          \"rightExpression\": {\n                            \"argumentTypes\": null,\n                            \"hexValue\": \"30\",\n                            \"id\": 4430,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": true,\n                            \"kind\": \"number\",\n                            \"lValueRequested\": false,\n                            \"nodeType\": \"Literal\",\n                            \"src\": \"16599:1:6\",\n                            \"subdenomination\": null,\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_rational_0_by_1\",\n                              \"typeString\": \"int_const 0\"\n                            },\n                            \"value\": \"0\"\n                          },\n                          \"src\": \"16580:20:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_bool\",\n                            \"typeString\": \"bool\"\n                          }\n                        },\n                        \"falseBody\": null,\n                        \"id\": 4434,\n                        \"nodeType\": \"IfStatement\",\n                        \"src\": \"16576:108:6\",\n                        \"trueBody\": {\n                          \"id\": 4433,\n                          \"nodeType\": \"Block\",\n                          \"src\": \"16602:82:6\",\n                          \"statements\": [\n                            {\n                              \"expression\": null,\n                              \"functionReturnParameters\": 4292,\n                              \"id\": 4432,\n                              \"nodeType\": \"Return\",\n                              \"src\": \"16663:7:6\"\n                            }\n                          ]\n                        }\n                      },\n                      {\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 4438,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"leftHandSide\": {\n                            \"argumentTypes\": null,\n                            \"id\": 4435,\n                            \"name\": \"_amount\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 4320,\n                            \"src\": \"16698:7:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                              \"typeString\": \"struct AssetLib.Asset memory\"\n                            }\n                          },\n                          \"nodeType\": \"Assignment\",\n                          \"operator\": \"=\",\n                          \"rightHandSide\": {\n                            \"argumentTypes\": null,\n                            \"expression\": {\n                              \"argumentTypes\": null,\n                              \"id\": 4436,\n                              \"name\": \"stake\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 4304,\n                              \"src\": \"16708:5:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_struct$_Stake_$3648_storage_ptr\",\n                                \"typeString\": \"struct Staking.Stake storage pointer\"\n                              }\n                            },\n                            \"id\": 4437,\n                            \"isConstant\": false,\n                            \"isLValue\": true,\n                            \"isPure\": false,\n                            \"lValueRequested\": false,\n                            \"memberName\": \"asset\",\n                            \"nodeType\": \"MemberAccess\",\n                            \"referencedDeclaration\": 3647,\n                            \"src\": \"16708:11:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                              \"typeString\": \"struct AssetLib.Asset storage ref\"\n                            }\n                          },\n                          \"src\": \"16698:21:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                            \"typeString\": \"struct AssetLib.Asset memory\"\n                          }\n                        },\n                        \"id\": 4439,\n                        \"nodeType\": \"ExpressionStatement\",\n                        \"src\": \"16698:21:6\"\n                      },\n                      {\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 4446,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"leftHandSide\": {\n                            \"argumentTypes\": null,\n                            \"expression\": {\n                              \"argumentTypes\": null,\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"id\": 4440,\n                                \"name\": \"stake\",\n                                \"nodeType\": \"Identifier\",\n                                \"overloadedDeclarations\": [],\n                                \"referencedDeclaration\": 4304,\n                                \"src\": \"16733:5:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_struct$_Stake_$3648_storage_ptr\",\n                                  \"typeString\": \"struct Staking.Stake storage pointer\"\n                                }\n                              },\n                              \"id\": 4443,\n                              \"isConstant\": false,\n                              \"isLValue\": true,\n                              \"isPure\": false,\n                              \"lValueRequested\": false,\n                              \"memberName\": \"asset\",\n                              \"nodeType\": \"MemberAccess\",\n                              \"referencedDeclaration\": 3647,\n                              \"src\": \"16733:11:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                                \"typeString\": \"struct AssetLib.Asset storage ref\"\n                              }\n                            },\n                            \"id\": 4444,\n                            \"isConstant\": false,\n                            \"isLValue\": true,\n                            \"isPure\": false,\n                            \"lValueRequested\": true,\n                            \"memberName\": \"principal\",\n                            \"nodeType\": \"MemberAccess\",\n                            \"referencedDeclaration\": 2785,\n                            \"src\": \"16733:21:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"nodeType\": \"Assignment\",\n                          \"operator\": \"=\",\n                          \"rightHandSide\": {\n                            \"argumentTypes\": null,\n                            \"hexValue\": \"30\",\n                            \"id\": 4445,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": true,\n                            \"kind\": \"number\",\n                            \"lValueRequested\": false,\n                            \"nodeType\": \"Literal\",\n                            \"src\": \"16757:1:6\",\n                            \"subdenomination\": null,\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_rational_0_by_1\",\n                              \"typeString\": \"int_const 0\"\n                            },\n                            \"value\": \"0\"\n                          },\n                          \"src\": \"16733:25:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"id\": 4447,\n                        \"nodeType\": \"ExpressionStatement\",\n                        \"src\": \"16733:25:6\"\n                      },\n                      {\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 4454,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"leftHandSide\": {\n                            \"argumentTypes\": null,\n                            \"expression\": {\n                              \"argumentTypes\": null,\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"id\": 4448,\n                                \"name\": \"stake\",\n                                \"nodeType\": \"Identifier\",\n                                \"overloadedDeclarations\": [],\n                                \"referencedDeclaration\": 4304,\n                                \"src\": \"16772:5:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_struct$_Stake_$3648_storage_ptr\",\n                                  \"typeString\": \"struct Staking.Stake storage pointer\"\n                                }\n                              },\n                              \"id\": 4451,\n                              \"isConstant\": false,\n                              \"isLValue\": true,\n                              \"isPure\": false,\n                              \"lValueRequested\": false,\n                              \"memberName\": \"asset\",\n                              \"nodeType\": \"MemberAccess\",\n                              \"referencedDeclaration\": 3647,\n                              \"src\": \"16772:11:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                                \"typeString\": \"struct AssetLib.Asset storage ref\"\n                              }\n                            },\n                            \"id\": 4452,\n                            \"isConstant\": false,\n                            \"isLValue\": true,\n                            \"isPure\": false,\n                            \"lValueRequested\": true,\n                            \"memberName\": \"compoundInterest\",\n                            \"nodeType\": \"MemberAccess\",\n                            \"referencedDeclaration\": 2787,\n                            \"src\": \"16772:28:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"nodeType\": \"Assignment\",\n                          \"operator\": \"=\",\n                          \"rightHandSide\": {\n                            \"argumentTypes\": null,\n                            \"hexValue\": \"30\",\n                            \"id\": 4453,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": true,\n                            \"kind\": \"number\",\n                            \"lValueRequested\": false,\n                            \"nodeType\": \"Literal\",\n                            \"src\": \"16803:1:6\",\n                            \"subdenomination\": null,\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_rational_0_by_1\",\n                              \"typeString\": \"int_const 0\"\n                            },\n                            \"value\": \"0\"\n                          },\n                          \"src\": \"16772:32:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"id\": 4455,\n                        \"nodeType\": \"ExpressionStatement\",\n                        \"src\": \"16772:32:6\"\n                      },\n                      {\n                        \"condition\": {\n                          \"argumentTypes\": null,\n                          \"commonType\": {\n                            \"typeIdentifier\": \"t_uint64\",\n                            \"typeString\": \"uint64\"\n                          },\n                          \"id\": 4458,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"leftExpression\": {\n                            \"argumentTypes\": null,\n                            \"id\": 4456,\n                            \"name\": \"_lockPeriodInBlocks\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 3768,\n                            \"src\": \"16823:19:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint64\",\n                              \"typeString\": \"uint64\"\n                            }\n                          },\n                          \"nodeType\": \"BinaryOperation\",\n                          \"operator\": \"==\",\n                          \"rightExpression\": {\n                            \"argumentTypes\": null,\n                            \"hexValue\": \"30\",\n                            \"id\": 4457,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": true,\n                            \"kind\": \"number\",\n                            \"lValueRequested\": false,\n                            \"nodeType\": \"Literal\",\n                            \"src\": \"16846:1:6\",\n                            \"subdenomination\": null,\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_rational_0_by_1\",\n                              \"typeString\": \"int_const 0\"\n                            },\n                            \"value\": \"0\"\n                          },\n                          \"src\": \"16823:24:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_bool\",\n                            \"typeString\": \"bool\"\n                          }\n                        },\n                        \"falseBody\": {\n                          \"id\": 4545,\n                          \"nodeType\": \"Block\",\n                          \"src\": \"17167:631:6\",\n                          \"statements\": [\n                            {\n                              \"assignments\": [\n                                4491\n                              ],\n                              \"declarations\": [\n                                {\n                                  \"constant\": false,\n                                  \"id\": 4491,\n                                  \"mutability\": \"mutable\",\n                                  \"name\": \"locked\",\n                                  \"nodeType\": \"VariableDeclaration\",\n                                  \"overrides\": null,\n                                  \"scope\": 4545,\n                                  \"src\": \"17185:21:6\",\n                                  \"stateVariable\": false,\n                                  \"storageLocation\": \"storage\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_struct$_Locked_$3659_storage_ptr\",\n                                    \"typeString\": \"struct Staking.Locked\"\n                                  },\n                                  \"typeName\": {\n                                    \"contractScope\": null,\n                                    \"id\": 4490,\n                                    \"name\": \"Locked\",\n                                    \"nodeType\": \"UserDefinedTypeName\",\n                                    \"referencedDeclaration\": 3659,\n                                    \"src\": \"17185:6:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_struct$_Locked_$3659_storage_ptr\",\n                                      \"typeString\": \"struct Staking.Locked\"\n                                    }\n                                  },\n                                  \"value\": null,\n                                  \"visibility\": \"internal\"\n                                }\n                              ],\n                              \"id\": 4495,\n                              \"initialValue\": {\n                                \"argumentTypes\": null,\n                                \"baseExpression\": {\n                                  \"argumentTypes\": null,\n                                  \"id\": 4492,\n                                  \"name\": \"_locked\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 3792,\n                                  \"src\": \"17209:7:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_mapping$_t_address_$_t_struct$_Locked_$3659_storage_$\",\n                                    \"typeString\": \"mapping(address => struct Staking.Locked storage ref)\"\n                                  }\n                                },\n                                \"id\": 4494,\n                                \"indexExpression\": {\n                                  \"argumentTypes\": null,\n                                  \"id\": 4493,\n                                  \"name\": \"sender\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 4299,\n                                  \"src\": \"17217:6:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_address\",\n                                    \"typeString\": \"address\"\n                                  }\n                                },\n                                \"isConstant\": false,\n                                \"isLValue\": true,\n                                \"isPure\": false,\n                                \"lValueRequested\": false,\n                                \"nodeType\": \"IndexAccess\",\n                                \"src\": \"17209:15:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_struct$_Locked_$3659_storage\",\n                                  \"typeString\": \"struct Staking.Locked storage ref\"\n                                }\n                              },\n                              \"nodeType\": \"VariableDeclarationStatement\",\n                              \"src\": \"17185:39:6\"\n                            },\n                            {\n                              \"assignments\": [\n                                4497\n                              ],\n                              \"declarations\": [\n                                {\n                                  \"constant\": false,\n                                  \"id\": 4497,\n                                  \"mutability\": \"mutable\",\n                                  \"name\": \"newLockedAsset\",\n                                  \"nodeType\": \"VariableDeclaration\",\n                                  \"overrides\": null,\n                                  \"scope\": 4545,\n                                  \"src\": \"17242:34:6\",\n                                  \"stateVariable\": false,\n                                  \"storageLocation\": \"storage\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_struct$_LockedAsset_$3653_storage_ptr\",\n                                    \"typeString\": \"struct Staking.LockedAsset\"\n                                  },\n                                  \"typeName\": {\n                                    \"contractScope\": null,\n                                    \"id\": 4496,\n                                    \"name\": \"LockedAsset\",\n                                    \"nodeType\": \"UserDefinedTypeName\",\n                                    \"referencedDeclaration\": 3653,\n                                    \"src\": \"17242:11:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_struct$_LockedAsset_$3653_storage_ptr\",\n                                      \"typeString\": \"struct Staking.LockedAsset\"\n                                    }\n                                  },\n                                  \"value\": null,\n                                  \"visibility\": \"internal\"\n                                }\n                              ],\n                              \"id\": 4502,\n                              \"initialValue\": {\n                                \"argumentTypes\": null,\n                                \"arguments\": [],\n                                \"expression\": {\n                                  \"argumentTypes\": [],\n                                  \"expression\": {\n                                    \"argumentTypes\": null,\n                                    \"expression\": {\n                                      \"argumentTypes\": null,\n                                      \"id\": 4498,\n                                      \"name\": \"locked\",\n                                      \"nodeType\": \"Identifier\",\n                                      \"overloadedDeclarations\": [],\n                                      \"referencedDeclaration\": 4491,\n                                      \"src\": \"17279:6:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_struct$_Locked_$3659_storage_ptr\",\n                                        \"typeString\": \"struct Staking.Locked storage pointer\"\n                                      }\n                                    },\n                                    \"id\": 4499,\n                                    \"isConstant\": false,\n                                    \"isLValue\": true,\n                                    \"isPure\": false,\n                                    \"lValueRequested\": false,\n                                    \"memberName\": \"assets\",\n                                    \"nodeType\": \"MemberAccess\",\n                                    \"referencedDeclaration\": 3658,\n                                    \"src\": \"17279:13:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_array$_t_struct$_LockedAsset_$3653_storage_$dyn_storage\",\n                                      \"typeString\": \"struct Staking.LockedAsset storage ref[] storage ref\"\n                                    }\n                                  },\n                                  \"id\": 4500,\n                                  \"isConstant\": false,\n                                  \"isLValue\": false,\n                                  \"isPure\": false,\n                                  \"lValueRequested\": false,\n                                  \"memberName\": \"push\",\n                                  \"nodeType\": \"MemberAccess\",\n                                  \"referencedDeclaration\": null,\n                                  \"src\": \"17279:18:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_function_arraypush_nonpayable$__$returns$_t_struct$_LockedAsset_$3653_storage_$\",\n                                    \"typeString\": \"function () returns (struct Staking.LockedAsset storage ref)\"\n                                  }\n                                },\n                                \"id\": 4501,\n                                \"isConstant\": false,\n                                \"isLValue\": true,\n                                \"isPure\": false,\n                                \"kind\": \"functionCall\",\n                                \"lValueRequested\": false,\n                                \"names\": [],\n                                \"nodeType\": \"FunctionCall\",\n                                \"src\": \"17279:20:6\",\n                                \"tryCall\": false,\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_struct$_LockedAsset_$3653_storage\",\n                                  \"typeString\": \"struct Staking.LockedAsset storage ref\"\n                                }\n                              },\n                              \"nodeType\": \"VariableDeclarationStatement\",\n                              \"src\": \"17242:57:6\"\n                            },\n                            {\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"id\": 4510,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": false,\n                                \"lValueRequested\": false,\n                                \"leftHandSide\": {\n                                  \"argumentTypes\": null,\n                                  \"expression\": {\n                                    \"argumentTypes\": null,\n                                    \"id\": 4503,\n                                    \"name\": \"newLockedAsset\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 4497,\n                                    \"src\": \"17317:14:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_struct$_LockedAsset_$3653_storage_ptr\",\n                                      \"typeString\": \"struct Staking.LockedAsset storage pointer\"\n                                    }\n                                  },\n                                  \"id\": 4505,\n                                  \"isConstant\": false,\n                                  \"isLValue\": true,\n                                  \"isPure\": false,\n                                  \"lValueRequested\": true,\n                                  \"memberName\": \"liquidSinceBlock\",\n                                  \"nodeType\": \"MemberAccess\",\n                                  \"referencedDeclaration\": 3650,\n                                  \"src\": \"17317:31:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_uint256\",\n                                    \"typeString\": \"uint256\"\n                                  }\n                                },\n                                \"nodeType\": \"Assignment\",\n                                \"operator\": \"=\",\n                                \"rightHandSide\": {\n                                  \"argumentTypes\": null,\n                                  \"arguments\": [\n                                    {\n                                      \"argumentTypes\": null,\n                                      \"id\": 4508,\n                                      \"name\": \"_lockPeriodInBlocks\",\n                                      \"nodeType\": \"Identifier\",\n                                      \"overloadedDeclarations\": [],\n                                      \"referencedDeclaration\": 3768,\n                                      \"src\": \"17366:19:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_uint64\",\n                                        \"typeString\": \"uint64\"\n                                      }\n                                    }\n                                  ],\n                                  \"expression\": {\n                                    \"argumentTypes\": [\n                                      {\n                                        \"typeIdentifier\": \"t_uint64\",\n                                        \"typeString\": \"uint64\"\n                                      }\n                                    ],\n                                    \"expression\": {\n                                      \"argumentTypes\": null,\n                                      \"id\": 4506,\n                                      \"name\": \"curr_block\",\n                                      \"nodeType\": \"Identifier\",\n                                      \"overloadedDeclarations\": [],\n                                      \"referencedDeclaration\": 4294,\n                                      \"src\": \"17351:10:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_uint256\",\n                                        \"typeString\": \"uint256\"\n                                      }\n                                    },\n                                    \"id\": 4507,\n                                    \"isConstant\": false,\n                                    \"isLValue\": false,\n                                    \"isPure\": false,\n                                    \"lValueRequested\": false,\n                                    \"memberName\": \"add\",\n                                    \"nodeType\": \"MemberAccess\",\n                                    \"referencedDeclaration\": 5870,\n                                    \"src\": \"17351:14:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_function_internal_pure$_t_uint256_$_t_uint256_$returns$_t_uint256_$bound_to$_t_uint256_$\",\n                                      \"typeString\": \"function (uint256,uint256) pure returns (uint256)\"\n                                    }\n                                  },\n                                  \"id\": 4509,\n                                  \"isConstant\": false,\n                                  \"isLValue\": false,\n                                  \"isPure\": false,\n                                  \"kind\": \"functionCall\",\n                                  \"lValueRequested\": false,\n                                  \"names\": [],\n                                  \"nodeType\": \"FunctionCall\",\n                                  \"src\": \"17351:35:6\",\n                                  \"tryCall\": false,\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_uint256\",\n                                    \"typeString\": \"uint256\"\n                                  }\n                                },\n                                \"src\": \"17317:69:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              },\n                              \"id\": 4511,\n                              \"nodeType\": \"ExpressionStatement\",\n                              \"src\": \"17317:69:6\"\n                            },\n                            {\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"id\": 4516,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": false,\n                                \"lValueRequested\": false,\n                                \"leftHandSide\": {\n                                  \"argumentTypes\": null,\n                                  \"expression\": {\n                                    \"argumentTypes\": null,\n                                    \"id\": 4512,\n                                    \"name\": \"newLockedAsset\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 4497,\n                                    \"src\": \"17404:14:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_struct$_LockedAsset_$3653_storage_ptr\",\n                                      \"typeString\": \"struct Staking.LockedAsset storage pointer\"\n                                    }\n                                  },\n                                  \"id\": 4514,\n                                  \"isConstant\": false,\n                                  \"isLValue\": true,\n                                  \"isPure\": false,\n                                  \"lValueRequested\": true,\n                                  \"memberName\": \"asset\",\n                                  \"nodeType\": \"MemberAccess\",\n                                  \"referencedDeclaration\": 3652,\n                                  \"src\": \"17404:20:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                                    \"typeString\": \"struct AssetLib.Asset storage ref\"\n                                  }\n                                },\n                                \"nodeType\": \"Assignment\",\n                                \"operator\": \"=\",\n                                \"rightHandSide\": {\n                                  \"argumentTypes\": null,\n                                  \"id\": 4515,\n                                  \"name\": \"_amount\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 4320,\n                                  \"src\": \"17427:7:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                    \"typeString\": \"struct AssetLib.Asset memory\"\n                                  }\n                                },\n                                \"src\": \"17404:30:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                                  \"typeString\": \"struct AssetLib.Asset storage ref\"\n                                }\n                              },\n                              \"id\": 4517,\n                              \"nodeType\": \"ExpressionStatement\",\n                              \"src\": \"17404:30:6\"\n                            },\n                            {\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"arguments\": [\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"id\": 4521,\n                                    \"name\": \"_amount\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 4320,\n                                    \"src\": \"17479:7:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                      \"typeString\": \"struct AssetLib.Asset memory\"\n                                    }\n                                  }\n                                ],\n                                \"expression\": {\n                                  \"argumentTypes\": [\n                                    {\n                                      \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                      \"typeString\": \"struct AssetLib.Asset memory\"\n                                    }\n                                  ],\n                                  \"expression\": {\n                                    \"argumentTypes\": null,\n                                    \"id\": 4518,\n                                    \"name\": \"_accruedGlobalLocked\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 3776,\n                                    \"src\": \"17453:20:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                                      \"typeString\": \"struct AssetLib.Asset storage ref\"\n                                    }\n                                  },\n                                  \"id\": 4520,\n                                  \"isConstant\": false,\n                                  \"isLValue\": true,\n                                  \"isPure\": false,\n                                  \"lValueRequested\": false,\n                                  \"memberName\": \"iAdd\",\n                                  \"nodeType\": \"MemberAccess\",\n                                  \"referencedDeclaration\": 2878,\n                                  \"src\": \"17453:25:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_function_internal_nonpayable$_t_struct$_Asset_$2788_storage_ptr_$_t_struct$_Asset_$2788_memory_ptr_$returns$__$bound_to$_t_struct$_Asset_$2788_storage_ptr_$\",\n                                    \"typeString\": \"function (struct AssetLib.Asset storage pointer,struct AssetLib.Asset memory)\"\n                                  }\n                                },\n                                \"id\": 4522,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": false,\n                                \"kind\": \"functionCall\",\n                                \"lValueRequested\": false,\n                                \"names\": [],\n                                \"nodeType\": \"FunctionCall\",\n                                \"src\": \"17453:34:6\",\n                                \"tryCall\": false,\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_tuple$__$\",\n                                  \"typeString\": \"tuple()\"\n                                }\n                              },\n                              \"id\": 4523,\n                              \"nodeType\": \"ExpressionStatement\",\n                              \"src\": \"17453:34:6\"\n                            },\n                            {\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"arguments\": [\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"id\": 4529,\n                                    \"name\": \"_amount\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 4320,\n                                    \"src\": \"17527:7:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                      \"typeString\": \"struct AssetLib.Asset memory\"\n                                    }\n                                  }\n                                ],\n                                \"expression\": {\n                                  \"argumentTypes\": [\n                                    {\n                                      \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                      \"typeString\": \"struct AssetLib.Asset memory\"\n                                    }\n                                  ],\n                                  \"expression\": {\n                                    \"argumentTypes\": null,\n                                    \"expression\": {\n                                      \"argumentTypes\": null,\n                                      \"id\": 4524,\n                                      \"name\": \"locked\",\n                                      \"nodeType\": \"Identifier\",\n                                      \"overloadedDeclarations\": [],\n                                      \"referencedDeclaration\": 4491,\n                                      \"src\": \"17505:6:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_struct$_Locked_$3659_storage_ptr\",\n                                        \"typeString\": \"struct Staking.Locked storage pointer\"\n                                      }\n                                    },\n                                    \"id\": 4527,\n                                    \"isConstant\": false,\n                                    \"isLValue\": true,\n                                    \"isPure\": false,\n                                    \"lValueRequested\": false,\n                                    \"memberName\": \"aggregate\",\n                                    \"nodeType\": \"MemberAccess\",\n                                    \"referencedDeclaration\": 3655,\n                                    \"src\": \"17505:16:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                                      \"typeString\": \"struct AssetLib.Asset storage ref\"\n                                    }\n                                  },\n                                  \"id\": 4528,\n                                  \"isConstant\": false,\n                                  \"isLValue\": true,\n                                  \"isPure\": false,\n                                  \"lValueRequested\": false,\n                                  \"memberName\": \"iAdd\",\n                                  \"nodeType\": \"MemberAccess\",\n                                  \"referencedDeclaration\": 2878,\n                                  \"src\": \"17505:21:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_function_internal_nonpayable$_t_struct$_Asset_$2788_storage_ptr_$_t_struct$_Asset_$2788_memory_ptr_$returns$__$bound_to$_t_struct$_Asset_$2788_storage_ptr_$\",\n                                    \"typeString\": \"function (struct AssetLib.Asset storage pointer,struct AssetLib.Asset memory)\"\n                                  }\n                                },\n                                \"id\": 4530,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": false,\n                                \"kind\": \"functionCall\",\n                                \"lValueRequested\": false,\n                                \"names\": [],\n                                \"nodeType\": \"FunctionCall\",\n                                \"src\": \"17505:30:6\",\n                                \"tryCall\": false,\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_tuple$__$\",\n                                  \"typeString\": \"tuple()\"\n                                }\n                              },\n                              \"id\": 4531,\n                              \"nodeType\": \"ExpressionStatement\",\n                              \"src\": \"17505:30:6\"\n                            },\n                            {\n                              \"eventCall\": {\n                                \"argumentTypes\": null,\n                                \"arguments\": [\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"expression\": {\n                                      \"argumentTypes\": null,\n                                      \"id\": 4533,\n                                      \"name\": \"msg\",\n                                      \"nodeType\": \"Identifier\",\n                                      \"overloadedDeclarations\": [],\n                                      \"referencedDeclaration\": -15,\n                                      \"src\": \"17668:3:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_magic_message\",\n                                        \"typeString\": \"msg\"\n                                      }\n                                    },\n                                    \"id\": 4534,\n                                    \"isConstant\": false,\n                                    \"isLValue\": false,\n                                    \"isPure\": false,\n                                    \"lValueRequested\": false,\n                                    \"memberName\": \"sender\",\n                                    \"nodeType\": \"MemberAccess\",\n                                    \"referencedDeclaration\": null,\n                                    \"src\": \"17668:10:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_address_payable\",\n                                      \"typeString\": \"address payable\"\n                                    }\n                                  },\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"expression\": {\n                                      \"argumentTypes\": null,\n                                      \"id\": 4535,\n                                      \"name\": \"newLockedAsset\",\n                                      \"nodeType\": \"Identifier\",\n                                      \"overloadedDeclarations\": [],\n                                      \"referencedDeclaration\": 4497,\n                                      \"src\": \"17680:14:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_struct$_LockedAsset_$3653_storage_ptr\",\n                                        \"typeString\": \"struct Staking.LockedAsset storage pointer\"\n                                      }\n                                    },\n                                    \"id\": 4536,\n                                    \"isConstant\": false,\n                                    \"isLValue\": true,\n                                    \"isPure\": false,\n                                    \"lValueRequested\": false,\n                                    \"memberName\": \"liquidSinceBlock\",\n                                    \"nodeType\": \"MemberAccess\",\n                                    \"referencedDeclaration\": 3650,\n                                    \"src\": \"17680:31:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    }\n                                  },\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"expression\": {\n                                      \"argumentTypes\": null,\n                                      \"expression\": {\n                                        \"argumentTypes\": null,\n                                        \"id\": 4537,\n                                        \"name\": \"newLockedAsset\",\n                                        \"nodeType\": \"Identifier\",\n                                        \"overloadedDeclarations\": [],\n                                        \"referencedDeclaration\": 4497,\n                                        \"src\": \"17713:14:6\",\n                                        \"typeDescriptions\": {\n                                          \"typeIdentifier\": \"t_struct$_LockedAsset_$3653_storage_ptr\",\n                                          \"typeString\": \"struct Staking.LockedAsset storage pointer\"\n                                        }\n                                      },\n                                      \"id\": 4538,\n                                      \"isConstant\": false,\n                                      \"isLValue\": true,\n                                      \"isPure\": false,\n                                      \"lValueRequested\": false,\n                                      \"memberName\": \"asset\",\n                                      \"nodeType\": \"MemberAccess\",\n                                      \"referencedDeclaration\": 3652,\n                                      \"src\": \"17713:20:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                                        \"typeString\": \"struct AssetLib.Asset storage ref\"\n                                      }\n                                    },\n                                    \"id\": 4539,\n                                    \"isConstant\": false,\n                                    \"isLValue\": true,\n                                    \"isPure\": false,\n                                    \"lValueRequested\": false,\n                                    \"memberName\": \"principal\",\n                                    \"nodeType\": \"MemberAccess\",\n                                    \"referencedDeclaration\": 2785,\n                                    \"src\": \"17713:30:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    }\n                                  },\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"expression\": {\n                                      \"argumentTypes\": null,\n                                      \"expression\": {\n                                        \"argumentTypes\": null,\n                                        \"id\": 4540,\n                                        \"name\": \"newLockedAsset\",\n                                        \"nodeType\": \"Identifier\",\n                                        \"overloadedDeclarations\": [],\n                                        \"referencedDeclaration\": 4497,\n                                        \"src\": \"17745:14:6\",\n                                        \"typeDescriptions\": {\n                                          \"typeIdentifier\": \"t_struct$_LockedAsset_$3653_storage_ptr\",\n                                          \"typeString\": \"struct Staking.LockedAsset storage pointer\"\n                                        }\n                                      },\n                                      \"id\": 4541,\n                                      \"isConstant\": false,\n                                      \"isLValue\": true,\n                                      \"isPure\": false,\n                                      \"lValueRequested\": false,\n                                      \"memberName\": \"asset\",\n                                      \"nodeType\": \"MemberAccess\",\n                                      \"referencedDeclaration\": 3652,\n                                      \"src\": \"17745:20:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                                        \"typeString\": \"struct AssetLib.Asset storage ref\"\n                                      }\n                                    },\n                                    \"id\": 4542,\n                                    \"isConstant\": false,\n                                    \"isLValue\": true,\n                                    \"isPure\": false,\n                                    \"lValueRequested\": false,\n                                    \"memberName\": \"compoundInterest\",\n                                    \"nodeType\": \"MemberAccess\",\n                                    \"referencedDeclaration\": 2787,\n                                    \"src\": \"17745:37:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    }\n                                  }\n                                ],\n                                \"expression\": {\n                                  \"argumentTypes\": [\n                                    {\n                                      \"typeIdentifier\": \"t_address_payable\",\n                                      \"typeString\": \"address payable\"\n                                    },\n                                    {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    },\n                                    {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    },\n                                    {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    }\n                                  ],\n                                  \"id\": 4532,\n                                  \"name\": \"UnbindStake\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 3704,\n                                  \"src\": \"17656:11:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_function_event_nonpayable$_t_address_$_t_uint256_$_t_uint256_$_t_uint256_$returns$__$\",\n                                    \"typeString\": \"function (address,uint256,uint256,uint256)\"\n                                  }\n                                },\n                                \"id\": 4543,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": false,\n                                \"kind\": \"functionCall\",\n                                \"lValueRequested\": false,\n                                \"names\": [],\n                                \"nodeType\": \"FunctionCall\",\n                                \"src\": \"17656:127:6\",\n                                \"tryCall\": false,\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_tuple$__$\",\n                                  \"typeString\": \"tuple()\"\n                                }\n                              },\n                              \"id\": 4544,\n                              \"nodeType\": \"EmitStatement\",\n                              \"src\": \"17651:132:6\"\n                            }\n                          ]\n                        },\n                        \"id\": 4546,\n                        \"nodeType\": \"IfStatement\",\n                        \"src\": \"16819:979:6\",\n                        \"trueBody\": {\n                          \"id\": 4489,\n                          \"nodeType\": \"Block\",\n                          \"src\": \"16849:312:6\",\n                          \"statements\": [\n                            {\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"arguments\": [\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"id\": 4463,\n                                    \"name\": \"_amount\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 4320,\n                                    \"src\": \"16891:7:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                      \"typeString\": \"struct AssetLib.Asset memory\"\n                                    }\n                                  }\n                                ],\n                                \"expression\": {\n                                  \"argumentTypes\": [\n                                    {\n                                      \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                      \"typeString\": \"struct AssetLib.Asset memory\"\n                                    }\n                                  ],\n                                  \"expression\": {\n                                    \"argumentTypes\": null,\n                                    \"baseExpression\": {\n                                      \"argumentTypes\": null,\n                                      \"id\": 4459,\n                                      \"name\": \"_liquidity\",\n                                      \"nodeType\": \"Identifier\",\n                                      \"overloadedDeclarations\": [],\n                                      \"referencedDeclaration\": 3796,\n                                      \"src\": \"16867:10:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_mapping$_t_address_$_t_struct$_Asset_$2788_storage_$\",\n                                        \"typeString\": \"mapping(address => struct AssetLib.Asset storage ref)\"\n                                      }\n                                    },\n                                    \"id\": 4461,\n                                    \"indexExpression\": {\n                                      \"argumentTypes\": null,\n                                      \"id\": 4460,\n                                      \"name\": \"sender\",\n                                      \"nodeType\": \"Identifier\",\n                                      \"overloadedDeclarations\": [],\n                                      \"referencedDeclaration\": 4299,\n                                      \"src\": \"16878:6:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_address\",\n                                        \"typeString\": \"address\"\n                                      }\n                                    },\n                                    \"isConstant\": false,\n                                    \"isLValue\": true,\n                                    \"isPure\": false,\n                                    \"lValueRequested\": false,\n                                    \"nodeType\": \"IndexAccess\",\n                                    \"src\": \"16867:18:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                                      \"typeString\": \"struct AssetLib.Asset storage ref\"\n                                    }\n                                  },\n                                  \"id\": 4462,\n                                  \"isConstant\": false,\n                                  \"isLValue\": true,\n                                  \"isPure\": false,\n                                  \"lValueRequested\": false,\n                                  \"memberName\": \"iAdd\",\n                                  \"nodeType\": \"MemberAccess\",\n                                  \"referencedDeclaration\": 2878,\n                                  \"src\": \"16867:23:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_function_internal_nonpayable$_t_struct$_Asset_$2788_storage_ptr_$_t_struct$_Asset_$2788_memory_ptr_$returns$__$bound_to$_t_struct$_Asset_$2788_storage_ptr_$\",\n                                    \"typeString\": \"function (struct AssetLib.Asset storage pointer,struct AssetLib.Asset memory)\"\n                                  }\n                                },\n                                \"id\": 4464,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": false,\n                                \"kind\": \"functionCall\",\n                                \"lValueRequested\": false,\n                                \"names\": [],\n                                \"nodeType\": \"FunctionCall\",\n                                \"src\": \"16867:32:6\",\n                                \"tryCall\": false,\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_tuple$__$\",\n                                  \"typeString\": \"tuple()\"\n                                }\n                              },\n                              \"id\": 4465,\n                              \"nodeType\": \"ExpressionStatement\",\n                              \"src\": \"16867:32:6\"\n                            },\n                            {\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"arguments\": [\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"id\": 4469,\n                                    \"name\": \"_amount\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 4320,\n                                    \"src\": \"16946:7:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                      \"typeString\": \"struct AssetLib.Asset memory\"\n                                    }\n                                  }\n                                ],\n                                \"expression\": {\n                                  \"argumentTypes\": [\n                                    {\n                                      \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                      \"typeString\": \"struct AssetLib.Asset memory\"\n                                    }\n                                  ],\n                                  \"expression\": {\n                                    \"argumentTypes\": null,\n                                    \"id\": 4466,\n                                    \"name\": \"_accruedGlobalLiquidity\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 3774,\n                                    \"src\": \"16917:23:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                                      \"typeString\": \"struct AssetLib.Asset storage ref\"\n                                    }\n                                  },\n                                  \"id\": 4468,\n                                  \"isConstant\": false,\n                                  \"isLValue\": true,\n                                  \"isPure\": false,\n                                  \"lValueRequested\": false,\n                                  \"memberName\": \"iAdd\",\n                                  \"nodeType\": \"MemberAccess\",\n                                  \"referencedDeclaration\": 2878,\n                                  \"src\": \"16917:28:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_function_internal_nonpayable$_t_struct$_Asset_$2788_storage_ptr_$_t_struct$_Asset_$2788_memory_ptr_$returns$__$bound_to$_t_struct$_Asset_$2788_storage_ptr_$\",\n                                    \"typeString\": \"function (struct AssetLib.Asset storage pointer,struct AssetLib.Asset memory)\"\n                                  }\n                                },\n                                \"id\": 4470,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": false,\n                                \"kind\": \"functionCall\",\n                                \"lValueRequested\": false,\n                                \"names\": [],\n                                \"nodeType\": \"FunctionCall\",\n                                \"src\": \"16917:37:6\",\n                                \"tryCall\": false,\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_tuple$__$\",\n                                  \"typeString\": \"tuple()\"\n                                }\n                              },\n                              \"id\": 4471,\n                              \"nodeType\": \"ExpressionStatement\",\n                              \"src\": \"16917:37:6\"\n                            },\n                            {\n                              \"eventCall\": {\n                                \"argumentTypes\": null,\n                                \"arguments\": [\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"id\": 4473,\n                                    \"name\": \"sender\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 4299,\n                                    \"src\": \"16989:6:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_address\",\n                                      \"typeString\": \"address\"\n                                    }\n                                  },\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"id\": 4474,\n                                    \"name\": \"curr_block\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 4294,\n                                    \"src\": \"16997:10:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    }\n                                  },\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"expression\": {\n                                      \"argumentTypes\": null,\n                                      \"id\": 4475,\n                                      \"name\": \"_amount\",\n                                      \"nodeType\": \"Identifier\",\n                                      \"overloadedDeclarations\": [],\n                                      \"referencedDeclaration\": 4320,\n                                      \"src\": \"17009:7:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                        \"typeString\": \"struct AssetLib.Asset memory\"\n                                      }\n                                    },\n                                    \"id\": 4476,\n                                    \"isConstant\": false,\n                                    \"isLValue\": true,\n                                    \"isPure\": false,\n                                    \"lValueRequested\": false,\n                                    \"memberName\": \"principal\",\n                                    \"nodeType\": \"MemberAccess\",\n                                    \"referencedDeclaration\": 2785,\n                                    \"src\": \"17009:17:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    }\n                                  },\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"expression\": {\n                                      \"argumentTypes\": null,\n                                      \"id\": 4477,\n                                      \"name\": \"_amount\",\n                                      \"nodeType\": \"Identifier\",\n                                      \"overloadedDeclarations\": [],\n                                      \"referencedDeclaration\": 4320,\n                                      \"src\": \"17028:7:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                        \"typeString\": \"struct AssetLib.Asset memory\"\n                                      }\n                                    },\n                                    \"id\": 4478,\n                                    \"isConstant\": false,\n                                    \"isLValue\": true,\n                                    \"isPure\": false,\n                                    \"lValueRequested\": false,\n                                    \"memberName\": \"compoundInterest\",\n                                    \"nodeType\": \"MemberAccess\",\n                                    \"referencedDeclaration\": 2787,\n                                    \"src\": \"17028:24:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    }\n                                  }\n                                ],\n                                \"expression\": {\n                                  \"argumentTypes\": [\n                                    {\n                                      \"typeIdentifier\": \"t_address\",\n                                      \"typeString\": \"address\"\n                                    },\n                                    {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    },\n                                    {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    },\n                                    {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    }\n                                  ],\n                                  \"id\": 4472,\n                                  \"name\": \"UnbindStake\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 3704,\n                                  \"src\": \"16977:11:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_function_event_nonpayable$_t_address_$_t_uint256_$_t_uint256_$_t_uint256_$returns$__$\",\n                                    \"typeString\": \"function (address,uint256,uint256,uint256)\"\n                                  }\n                                },\n                                \"id\": 4479,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": false,\n                                \"kind\": \"functionCall\",\n                                \"lValueRequested\": false,\n                                \"names\": [],\n                                \"nodeType\": \"FunctionCall\",\n                                \"src\": \"16977:76:6\",\n                                \"tryCall\": false,\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_tuple$__$\",\n                                  \"typeString\": \"tuple()\"\n                                }\n                              },\n                              \"id\": 4480,\n                              \"nodeType\": \"EmitStatement\",\n                              \"src\": \"16972:81:6\"\n                            },\n                            {\n                              \"eventCall\": {\n                                \"argumentTypes\": null,\n                                \"arguments\": [\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"id\": 4482,\n                                    \"name\": \"sender\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 4299,\n                                    \"src\": \"17094:6:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_address\",\n                                      \"typeString\": \"address\"\n                                    }\n                                  },\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"expression\": {\n                                      \"argumentTypes\": null,\n                                      \"id\": 4483,\n                                      \"name\": \"_amount\",\n                                      \"nodeType\": \"Identifier\",\n                                      \"overloadedDeclarations\": [],\n                                      \"referencedDeclaration\": 4320,\n                                      \"src\": \"17102:7:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                        \"typeString\": \"struct AssetLib.Asset memory\"\n                                      }\n                                    },\n                                    \"id\": 4484,\n                                    \"isConstant\": false,\n                                    \"isLValue\": true,\n                                    \"isPure\": false,\n                                    \"lValueRequested\": false,\n                                    \"memberName\": \"principal\",\n                                    \"nodeType\": \"MemberAccess\",\n                                    \"referencedDeclaration\": 2785,\n                                    \"src\": \"17102:17:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    }\n                                  },\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"expression\": {\n                                      \"argumentTypes\": null,\n                                      \"id\": 4485,\n                                      \"name\": \"_amount\",\n                                      \"nodeType\": \"Identifier\",\n                                      \"overloadedDeclarations\": [],\n                                      \"referencedDeclaration\": 4320,\n                                      \"src\": \"17121:7:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                        \"typeString\": \"struct AssetLib.Asset memory\"\n                                      }\n                                    },\n                                    \"id\": 4486,\n                                    \"isConstant\": false,\n                                    \"isLValue\": true,\n                                    \"isPure\": false,\n                                    \"lValueRequested\": false,\n                                    \"memberName\": \"compoundInterest\",\n                                    \"nodeType\": \"MemberAccess\",\n                                    \"referencedDeclaration\": 2787,\n                                    \"src\": \"17121:24:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    }\n                                  }\n                                ],\n                                \"expression\": {\n                                  \"argumentTypes\": [\n                                    {\n                                      \"typeIdentifier\": \"t_address\",\n                                      \"typeString\": \"address\"\n                                    },\n                                    {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    },\n                                    {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    }\n                                  ],\n                                  \"id\": 4481,\n                                  \"name\": \"LiquidityUnlocked\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 3694,\n                                  \"src\": \"17076:17:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_function_event_nonpayable$_t_address_$_t_uint256_$_t_uint256_$returns$__$\",\n                                    \"typeString\": \"function (address,uint256,uint256)\"\n                                  }\n                                },\n                                \"id\": 4487,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": false,\n                                \"kind\": \"functionCall\",\n                                \"lValueRequested\": false,\n                                \"names\": [],\n                                \"nodeType\": \"FunctionCall\",\n                                \"src\": \"17076:70:6\",\n                                \"tryCall\": false,\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_tuple$__$\",\n                                  \"typeString\": \"tuple()\"\n                                }\n                              },\n                              \"id\": 4488,\n                              \"nodeType\": \"EmitStatement\",\n                              \"src\": \"17071:75:6\"\n                            }\n                          ]\n                        }\n                      }\n                    ]\n                  },\n                  \"id\": 4548,\n                  \"nodeType\": \"IfStatement\",\n                  \"src\": \"14675:3133:6\",\n                  \"trueBody\": {\n                    \"id\": 4428,\n                    \"nodeType\": \"Block\",\n                    \"src\": \"14691:1865:6\",\n                    \"statements\": [\n                      {\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"arguments\": [\n                            {\n                              \"argumentTypes\": null,\n                              \"commonType\": {\n                                \"typeIdentifier\": \"t_uint256\",\n                                \"typeString\": \"uint256\"\n                              },\n                              \"id\": 4328,\n                              \"isConstant\": false,\n                              \"isLValue\": false,\n                              \"isPure\": false,\n                              \"lValueRequested\": false,\n                              \"leftExpression\": {\n                                \"argumentTypes\": null,\n                                \"id\": 4326,\n                                \"name\": \"amount\",\n                                \"nodeType\": \"Identifier\",\n                                \"overloadedDeclarations\": [],\n                                \"referencedDeclaration\": 4283,\n                                \"src\": \"15425:6:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              },\n                              \"nodeType\": \"BinaryOperation\",\n                              \"operator\": \"<=\",\n                              \"rightExpression\": {\n                                \"argumentTypes\": null,\n                                \"id\": 4327,\n                                \"name\": \"stake_composite\",\n                                \"nodeType\": \"Identifier\",\n                                \"overloadedDeclarations\": [],\n                                \"referencedDeclaration\": 4311,\n                                \"src\": \"15435:15:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              },\n                              \"src\": \"15425:25:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_bool\",\n                                \"typeString\": \"bool\"\n                              }\n                            },\n                            {\n                              \"argumentTypes\": null,\n                              \"hexValue\": \"416d6f756e7420697320686967686572207468616e207374616b65\",\n                              \"id\": 4329,\n                              \"isConstant\": false,\n                              \"isLValue\": false,\n                              \"isPure\": true,\n                              \"kind\": \"string\",\n                              \"lValueRequested\": false,\n                              \"nodeType\": \"Literal\",\n                              \"src\": \"15452:29:6\",\n                              \"subdenomination\": null,\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_stringliteral_8bda5dc5d5057eb9094b795367834747986b50a0bac9d1f451ae725565808bcd\",\n                                \"typeString\": \"literal_string \\\"Amount is higher than stake\\\"\"\n                              },\n                              \"value\": \"Amount is higher than stake\"\n                            }\n                          ],\n                          \"expression\": {\n                            \"argumentTypes\": [\n                              {\n                                \"typeIdentifier\": \"t_bool\",\n                                \"typeString\": \"bool\"\n                              },\n                              {\n                                \"typeIdentifier\": \"t_stringliteral_8bda5dc5d5057eb9094b795367834747986b50a0bac9d1f451ae725565808bcd\",\n                                \"typeString\": \"literal_string \\\"Amount is higher than stake\\\"\"\n                              }\n                            ],\n                            \"id\": 4325,\n                            \"name\": \"require\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [\n                              -18,\n                              -18\n                            ],\n                            \"referencedDeclaration\": -18,\n                            \"src\": \"15417:7:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$\",\n                              \"typeString\": \"function (bool,string memory) pure\"\n                            }\n                          },\n                          \"id\": 4330,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"kind\": \"functionCall\",\n                          \"lValueRequested\": false,\n                          \"names\": [],\n                          \"nodeType\": \"FunctionCall\",\n                          \"src\": \"15417:65:6\",\n                          \"tryCall\": false,\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_tuple$__$\",\n                            \"typeString\": \"tuple()\"\n                          }\n                        },\n                        \"id\": 4331,\n                        \"nodeType\": \"ExpressionStatement\",\n                        \"src\": \"15417:65:6\"\n                      },\n                      {\n                        \"condition\": {\n                          \"argumentTypes\": null,\n                          \"commonType\": {\n                            \"typeIdentifier\": \"t_uint64\",\n                            \"typeString\": \"uint64\"\n                          },\n                          \"id\": 4334,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"leftExpression\": {\n                            \"argumentTypes\": null,\n                            \"id\": 4332,\n                            \"name\": \"_lockPeriodInBlocks\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 3768,\n                            \"src\": \"15501:19:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint64\",\n                              \"typeString\": \"uint64\"\n                            }\n                          },\n                          \"nodeType\": \"BinaryOperation\",\n                          \"operator\": \"==\",\n                          \"rightExpression\": {\n                            \"argumentTypes\": null,\n                            \"hexValue\": \"30\",\n                            \"id\": 4333,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": true,\n                            \"kind\": \"number\",\n                            \"lValueRequested\": false,\n                            \"nodeType\": \"Literal\",\n                            \"src\": \"15524:1:6\",\n                            \"subdenomination\": null,\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_rational_0_by_1\",\n                              \"typeString\": \"int_const 0\"\n                            },\n                            \"value\": \"0\"\n                          },\n                          \"src\": \"15501:24:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_bool\",\n                            \"typeString\": \"bool\"\n                          }\n                        },\n                        \"falseBody\": {\n                          \"id\": 4426,\n                          \"nodeType\": \"Block\",\n                          \"src\": \"15893:653:6\",\n                          \"statements\": [\n                            {\n                              \"assignments\": [\n                                4371\n                              ],\n                              \"declarations\": [\n                                {\n                                  \"constant\": false,\n                                  \"id\": 4371,\n                                  \"mutability\": \"mutable\",\n                                  \"name\": \"locked\",\n                                  \"nodeType\": \"VariableDeclaration\",\n                                  \"overrides\": null,\n                                  \"scope\": 4426,\n                                  \"src\": \"15911:21:6\",\n                                  \"stateVariable\": false,\n                                  \"storageLocation\": \"storage\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_struct$_Locked_$3659_storage_ptr\",\n                                    \"typeString\": \"struct Staking.Locked\"\n                                  },\n                                  \"typeName\": {\n                                    \"contractScope\": null,\n                                    \"id\": 4370,\n                                    \"name\": \"Locked\",\n                                    \"nodeType\": \"UserDefinedTypeName\",\n                                    \"referencedDeclaration\": 3659,\n                                    \"src\": \"15911:6:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_struct$_Locked_$3659_storage_ptr\",\n                                      \"typeString\": \"struct Staking.Locked\"\n                                    }\n                                  },\n                                  \"value\": null,\n                                  \"visibility\": \"internal\"\n                                }\n                              ],\n                              \"id\": 4375,\n                              \"initialValue\": {\n                                \"argumentTypes\": null,\n                                \"baseExpression\": {\n                                  \"argumentTypes\": null,\n                                  \"id\": 4372,\n                                  \"name\": \"_locked\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 3792,\n                                  \"src\": \"15935:7:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_mapping$_t_address_$_t_struct$_Locked_$3659_storage_$\",\n                                    \"typeString\": \"mapping(address => struct Staking.Locked storage ref)\"\n                                  }\n                                },\n                                \"id\": 4374,\n                                \"indexExpression\": {\n                                  \"argumentTypes\": null,\n                                  \"id\": 4373,\n                                  \"name\": \"sender\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 4299,\n                                  \"src\": \"15943:6:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_address\",\n                                    \"typeString\": \"address\"\n                                  }\n                                },\n                                \"isConstant\": false,\n                                \"isLValue\": true,\n                                \"isPure\": false,\n                                \"lValueRequested\": false,\n                                \"nodeType\": \"IndexAccess\",\n                                \"src\": \"15935:15:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_struct$_Locked_$3659_storage\",\n                                  \"typeString\": \"struct Staking.Locked storage ref\"\n                                }\n                              },\n                              \"nodeType\": \"VariableDeclarationStatement\",\n                              \"src\": \"15911:39:6\"\n                            },\n                            {\n                              \"assignments\": [\n                                4377\n                              ],\n                              \"declarations\": [\n                                {\n                                  \"constant\": false,\n                                  \"id\": 4377,\n                                  \"mutability\": \"mutable\",\n                                  \"name\": \"newLockedAsset\",\n                                  \"nodeType\": \"VariableDeclaration\",\n                                  \"overrides\": null,\n                                  \"scope\": 4426,\n                                  \"src\": \"15968:34:6\",\n                                  \"stateVariable\": false,\n                                  \"storageLocation\": \"storage\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_struct$_LockedAsset_$3653_storage_ptr\",\n                                    \"typeString\": \"struct Staking.LockedAsset\"\n                                  },\n                                  \"typeName\": {\n                                    \"contractScope\": null,\n                                    \"id\": 4376,\n                                    \"name\": \"LockedAsset\",\n                                    \"nodeType\": \"UserDefinedTypeName\",\n                                    \"referencedDeclaration\": 3653,\n                                    \"src\": \"15968:11:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_struct$_LockedAsset_$3653_storage_ptr\",\n                                      \"typeString\": \"struct Staking.LockedAsset\"\n                                    }\n                                  },\n                                  \"value\": null,\n                                  \"visibility\": \"internal\"\n                                }\n                              ],\n                              \"id\": 4382,\n                              \"initialValue\": {\n                                \"argumentTypes\": null,\n                                \"arguments\": [],\n                                \"expression\": {\n                                  \"argumentTypes\": [],\n                                  \"expression\": {\n                                    \"argumentTypes\": null,\n                                    \"expression\": {\n                                      \"argumentTypes\": null,\n                                      \"id\": 4378,\n                                      \"name\": \"locked\",\n                                      \"nodeType\": \"Identifier\",\n                                      \"overloadedDeclarations\": [],\n                                      \"referencedDeclaration\": 4371,\n                                      \"src\": \"16005:6:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_struct$_Locked_$3659_storage_ptr\",\n                                        \"typeString\": \"struct Staking.Locked storage pointer\"\n                                      }\n                                    },\n                                    \"id\": 4379,\n                                    \"isConstant\": false,\n                                    \"isLValue\": true,\n                                    \"isPure\": false,\n                                    \"lValueRequested\": false,\n                                    \"memberName\": \"assets\",\n                                    \"nodeType\": \"MemberAccess\",\n                                    \"referencedDeclaration\": 3658,\n                                    \"src\": \"16005:13:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_array$_t_struct$_LockedAsset_$3653_storage_$dyn_storage\",\n                                      \"typeString\": \"struct Staking.LockedAsset storage ref[] storage ref\"\n                                    }\n                                  },\n                                  \"id\": 4380,\n                                  \"isConstant\": false,\n                                  \"isLValue\": false,\n                                  \"isPure\": false,\n                                  \"lValueRequested\": false,\n                                  \"memberName\": \"push\",\n                                  \"nodeType\": \"MemberAccess\",\n                                  \"referencedDeclaration\": null,\n                                  \"src\": \"16005:18:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_function_arraypush_nonpayable$__$returns$_t_struct$_LockedAsset_$3653_storage_$\",\n                                    \"typeString\": \"function () returns (struct Staking.LockedAsset storage ref)\"\n                                  }\n                                },\n                                \"id\": 4381,\n                                \"isConstant\": false,\n                                \"isLValue\": true,\n                                \"isPure\": false,\n                                \"kind\": \"functionCall\",\n                                \"lValueRequested\": false,\n                                \"names\": [],\n                                \"nodeType\": \"FunctionCall\",\n                                \"src\": \"16005:20:6\",\n                                \"tryCall\": false,\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_struct$_LockedAsset_$3653_storage\",\n                                  \"typeString\": \"struct Staking.LockedAsset storage ref\"\n                                }\n                              },\n                              \"nodeType\": \"VariableDeclarationStatement\",\n                              \"src\": \"15968:57:6\"\n                            },\n                            {\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"id\": 4390,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": false,\n                                \"lValueRequested\": false,\n                                \"leftHandSide\": {\n                                  \"argumentTypes\": null,\n                                  \"expression\": {\n                                    \"argumentTypes\": null,\n                                    \"id\": 4383,\n                                    \"name\": \"newLockedAsset\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 4377,\n                                    \"src\": \"16043:14:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_struct$_LockedAsset_$3653_storage_ptr\",\n                                      \"typeString\": \"struct Staking.LockedAsset storage pointer\"\n                                    }\n                                  },\n                                  \"id\": 4385,\n                                  \"isConstant\": false,\n                                  \"isLValue\": true,\n                                  \"isPure\": false,\n                                  \"lValueRequested\": true,\n                                  \"memberName\": \"liquidSinceBlock\",\n                                  \"nodeType\": \"MemberAccess\",\n                                  \"referencedDeclaration\": 3650,\n                                  \"src\": \"16043:31:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_uint256\",\n                                    \"typeString\": \"uint256\"\n                                  }\n                                },\n                                \"nodeType\": \"Assignment\",\n                                \"operator\": \"=\",\n                                \"rightHandSide\": {\n                                  \"argumentTypes\": null,\n                                  \"arguments\": [\n                                    {\n                                      \"argumentTypes\": null,\n                                      \"id\": 4388,\n                                      \"name\": \"_lockPeriodInBlocks\",\n                                      \"nodeType\": \"Identifier\",\n                                      \"overloadedDeclarations\": [],\n                                      \"referencedDeclaration\": 3768,\n                                      \"src\": \"16092:19:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_uint64\",\n                                        \"typeString\": \"uint64\"\n                                      }\n                                    }\n                                  ],\n                                  \"expression\": {\n                                    \"argumentTypes\": [\n                                      {\n                                        \"typeIdentifier\": \"t_uint64\",\n                                        \"typeString\": \"uint64\"\n                                      }\n                                    ],\n                                    \"expression\": {\n                                      \"argumentTypes\": null,\n                                      \"id\": 4386,\n                                      \"name\": \"curr_block\",\n                                      \"nodeType\": \"Identifier\",\n                                      \"overloadedDeclarations\": [],\n                                      \"referencedDeclaration\": 4294,\n                                      \"src\": \"16077:10:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_uint256\",\n                                        \"typeString\": \"uint256\"\n                                      }\n                                    },\n                                    \"id\": 4387,\n                                    \"isConstant\": false,\n                                    \"isLValue\": false,\n                                    \"isPure\": false,\n                                    \"lValueRequested\": false,\n                                    \"memberName\": \"add\",\n                                    \"nodeType\": \"MemberAccess\",\n                                    \"referencedDeclaration\": 5870,\n                                    \"src\": \"16077:14:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_function_internal_pure$_t_uint256_$_t_uint256_$returns$_t_uint256_$bound_to$_t_uint256_$\",\n                                      \"typeString\": \"function (uint256,uint256) pure returns (uint256)\"\n                                    }\n                                  },\n                                  \"id\": 4389,\n                                  \"isConstant\": false,\n                                  \"isLValue\": false,\n                                  \"isPure\": false,\n                                  \"kind\": \"functionCall\",\n                                  \"lValueRequested\": false,\n                                  \"names\": [],\n                                  \"nodeType\": \"FunctionCall\",\n                                  \"src\": \"16077:35:6\",\n                                  \"tryCall\": false,\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_uint256\",\n                                    \"typeString\": \"uint256\"\n                                  }\n                                },\n                                \"src\": \"16043:69:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              },\n                              \"id\": 4391,\n                              \"nodeType\": \"ExpressionStatement\",\n                              \"src\": \"16043:69:6\"\n                            },\n                            {\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"id\": 4400,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": false,\n                                \"lValueRequested\": false,\n                                \"leftHandSide\": {\n                                  \"argumentTypes\": null,\n                                  \"id\": 4392,\n                                  \"name\": \"_amount\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 4320,\n                                  \"src\": \"16130:7:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                    \"typeString\": \"struct AssetLib.Asset memory\"\n                                  }\n                                },\n                                \"nodeType\": \"Assignment\",\n                                \"operator\": \"=\",\n                                \"rightHandSide\": {\n                                  \"argumentTypes\": null,\n                                  \"arguments\": [\n                                    {\n                                      \"argumentTypes\": null,\n                                      \"expression\": {\n                                        \"argumentTypes\": null,\n                                        \"id\": 4396,\n                                        \"name\": \"newLockedAsset\",\n                                        \"nodeType\": \"Identifier\",\n                                        \"overloadedDeclarations\": [],\n                                        \"referencedDeclaration\": 4377,\n                                        \"src\": \"16183:14:6\",\n                                        \"typeDescriptions\": {\n                                          \"typeIdentifier\": \"t_struct$_LockedAsset_$3653_storage_ptr\",\n                                          \"typeString\": \"struct Staking.LockedAsset storage pointer\"\n                                        }\n                                      },\n                                      \"id\": 4397,\n                                      \"isConstant\": false,\n                                      \"isLValue\": true,\n                                      \"isPure\": false,\n                                      \"lValueRequested\": false,\n                                      \"memberName\": \"asset\",\n                                      \"nodeType\": \"MemberAccess\",\n                                      \"referencedDeclaration\": 3652,\n                                      \"src\": \"16183:20:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                                        \"typeString\": \"struct AssetLib.Asset storage ref\"\n                                      }\n                                    },\n                                    {\n                                      \"argumentTypes\": null,\n                                      \"id\": 4398,\n                                      \"name\": \"amount\",\n                                      \"nodeType\": \"Identifier\",\n                                      \"overloadedDeclarations\": [],\n                                      \"referencedDeclaration\": 4283,\n                                      \"src\": \"16205:6:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_uint256\",\n                                        \"typeString\": \"uint256\"\n                                      }\n                                    }\n                                  ],\n                                  \"expression\": {\n                                    \"argumentTypes\": [\n                                      {\n                                        \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                                        \"typeString\": \"struct AssetLib.Asset storage ref\"\n                                      },\n                                      {\n                                        \"typeIdentifier\": \"t_uint256\",\n                                        \"typeString\": \"uint256\"\n                                      }\n                                    ],\n                                    \"expression\": {\n                                      \"argumentTypes\": null,\n                                      \"expression\": {\n                                        \"argumentTypes\": null,\n                                        \"id\": 4393,\n                                        \"name\": \"stake\",\n                                        \"nodeType\": \"Identifier\",\n                                        \"overloadedDeclarations\": [],\n                                        \"referencedDeclaration\": 4304,\n                                        \"src\": \"16140:5:6\",\n                                        \"typeDescriptions\": {\n                                          \"typeIdentifier\": \"t_struct$_Stake_$3648_storage_ptr\",\n                                          \"typeString\": \"struct Staking.Stake storage pointer\"\n                                        }\n                                      },\n                                      \"id\": 4394,\n                                      \"isConstant\": false,\n                                      \"isLValue\": true,\n                                      \"isPure\": false,\n                                      \"lValueRequested\": false,\n                                      \"memberName\": \"asset\",\n                                      \"nodeType\": \"MemberAccess\",\n                                      \"referencedDeclaration\": 3647,\n                                      \"src\": \"16140:11:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                                        \"typeString\": \"struct AssetLib.Asset storage ref\"\n                                      }\n                                    },\n                                    \"id\": 4395,\n                                    \"isConstant\": false,\n                                    \"isLValue\": true,\n                                    \"isPure\": false,\n                                    \"lValueRequested\": false,\n                                    \"memberName\": \"iRelocateCompoundInterestFirst\",\n                                    \"nodeType\": \"MemberAccess\",\n                                    \"referencedDeclaration\": 3120,\n                                    \"src\": \"16140:42:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_function_internal_nonpayable$_t_struct$_Asset_$2788_storage_ptr_$_t_struct$_Asset_$2788_storage_ptr_$_t_uint256_$returns$_t_struct$_Asset_$2788_memory_ptr_$bound_to$_t_struct$_Asset_$2788_storage_ptr_$\",\n                                      \"typeString\": \"function (struct AssetLib.Asset storage pointer,struct AssetLib.Asset storage pointer,uint256) returns (struct AssetLib.Asset memory)\"\n                                    }\n                                  },\n                                  \"id\": 4399,\n                                  \"isConstant\": false,\n                                  \"isLValue\": false,\n                                  \"isPure\": false,\n                                  \"kind\": \"functionCall\",\n                                  \"lValueRequested\": false,\n                                  \"names\": [],\n                                  \"nodeType\": \"FunctionCall\",\n                                  \"src\": \"16140:72:6\",\n                                  \"tryCall\": false,\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                    \"typeString\": \"struct AssetLib.Asset memory\"\n                                  }\n                                },\n                                \"src\": \"16130:82:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                  \"typeString\": \"struct AssetLib.Asset memory\"\n                                }\n                              },\n                              \"id\": 4401,\n                              \"nodeType\": \"ExpressionStatement\",\n                              \"src\": \"16130:82:6\"\n                            },\n                            {\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"arguments\": [\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"id\": 4405,\n                                    \"name\": \"_amount\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 4320,\n                                    \"src\": \"16257:7:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                      \"typeString\": \"struct AssetLib.Asset memory\"\n                                    }\n                                  }\n                                ],\n                                \"expression\": {\n                                  \"argumentTypes\": [\n                                    {\n                                      \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                      \"typeString\": \"struct AssetLib.Asset memory\"\n                                    }\n                                  ],\n                                  \"expression\": {\n                                    \"argumentTypes\": null,\n                                    \"id\": 4402,\n                                    \"name\": \"_accruedGlobalLocked\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 3776,\n                                    \"src\": \"16231:20:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                                      \"typeString\": \"struct AssetLib.Asset storage ref\"\n                                    }\n                                  },\n                                  \"id\": 4404,\n                                  \"isConstant\": false,\n                                  \"isLValue\": true,\n                                  \"isPure\": false,\n                                  \"lValueRequested\": false,\n                                  \"memberName\": \"iAdd\",\n                                  \"nodeType\": \"MemberAccess\",\n                                  \"referencedDeclaration\": 2878,\n                                  \"src\": \"16231:25:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_function_internal_nonpayable$_t_struct$_Asset_$2788_storage_ptr_$_t_struct$_Asset_$2788_memory_ptr_$returns$__$bound_to$_t_struct$_Asset_$2788_storage_ptr_$\",\n                                    \"typeString\": \"function (struct AssetLib.Asset storage pointer,struct AssetLib.Asset memory)\"\n                                  }\n                                },\n                                \"id\": 4406,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": false,\n                                \"kind\": \"functionCall\",\n                                \"lValueRequested\": false,\n                                \"names\": [],\n                                \"nodeType\": \"FunctionCall\",\n                                \"src\": \"16231:34:6\",\n                                \"tryCall\": false,\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_tuple$__$\",\n                                  \"typeString\": \"tuple()\"\n                                }\n                              },\n                              \"id\": 4407,\n                              \"nodeType\": \"ExpressionStatement\",\n                              \"src\": \"16231:34:6\"\n                            },\n                            {\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"arguments\": [\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"id\": 4413,\n                                    \"name\": \"_amount\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 4320,\n                                    \"src\": \"16305:7:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                      \"typeString\": \"struct AssetLib.Asset memory\"\n                                    }\n                                  }\n                                ],\n                                \"expression\": {\n                                  \"argumentTypes\": [\n                                    {\n                                      \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                      \"typeString\": \"struct AssetLib.Asset memory\"\n                                    }\n                                  ],\n                                  \"expression\": {\n                                    \"argumentTypes\": null,\n                                    \"expression\": {\n                                      \"argumentTypes\": null,\n                                      \"id\": 4408,\n                                      \"name\": \"locked\",\n                                      \"nodeType\": \"Identifier\",\n                                      \"overloadedDeclarations\": [],\n                                      \"referencedDeclaration\": 4371,\n                                      \"src\": \"16283:6:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_struct$_Locked_$3659_storage_ptr\",\n                                        \"typeString\": \"struct Staking.Locked storage pointer\"\n                                      }\n                                    },\n                                    \"id\": 4411,\n                                    \"isConstant\": false,\n                                    \"isLValue\": true,\n                                    \"isPure\": false,\n                                    \"lValueRequested\": false,\n                                    \"memberName\": \"aggregate\",\n                                    \"nodeType\": \"MemberAccess\",\n                                    \"referencedDeclaration\": 3655,\n                                    \"src\": \"16283:16:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                                      \"typeString\": \"struct AssetLib.Asset storage ref\"\n                                    }\n                                  },\n                                  \"id\": 4412,\n                                  \"isConstant\": false,\n                                  \"isLValue\": true,\n                                  \"isPure\": false,\n                                  \"lValueRequested\": false,\n                                  \"memberName\": \"iAdd\",\n                                  \"nodeType\": \"MemberAccess\",\n                                  \"referencedDeclaration\": 2878,\n                                  \"src\": \"16283:21:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_function_internal_nonpayable$_t_struct$_Asset_$2788_storage_ptr_$_t_struct$_Asset_$2788_memory_ptr_$returns$__$bound_to$_t_struct$_Asset_$2788_storage_ptr_$\",\n                                    \"typeString\": \"function (struct AssetLib.Asset storage pointer,struct AssetLib.Asset memory)\"\n                                  }\n                                },\n                                \"id\": 4414,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": false,\n                                \"kind\": \"functionCall\",\n                                \"lValueRequested\": false,\n                                \"names\": [],\n                                \"nodeType\": \"FunctionCall\",\n                                \"src\": \"16283:30:6\",\n                                \"tryCall\": false,\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_tuple$__$\",\n                                  \"typeString\": \"tuple()\"\n                                }\n                              },\n                              \"id\": 4415,\n                              \"nodeType\": \"ExpressionStatement\",\n                              \"src\": \"16283:30:6\"\n                            },\n                            {\n                              \"eventCall\": {\n                                \"argumentTypes\": null,\n                                \"arguments\": [\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"id\": 4417,\n                                    \"name\": \"sender\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 4299,\n                                    \"src\": \"16446:6:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_address\",\n                                      \"typeString\": \"address\"\n                                    }\n                                  },\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"expression\": {\n                                      \"argumentTypes\": null,\n                                      \"id\": 4418,\n                                      \"name\": \"newLockedAsset\",\n                                      \"nodeType\": \"Identifier\",\n                                      \"overloadedDeclarations\": [],\n                                      \"referencedDeclaration\": 4377,\n                                      \"src\": \"16454:14:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_struct$_LockedAsset_$3653_storage_ptr\",\n                                        \"typeString\": \"struct Staking.LockedAsset storage pointer\"\n                                      }\n                                    },\n                                    \"id\": 4419,\n                                    \"isConstant\": false,\n                                    \"isLValue\": true,\n                                    \"isPure\": false,\n                                    \"lValueRequested\": false,\n                                    \"memberName\": \"liquidSinceBlock\",\n                                    \"nodeType\": \"MemberAccess\",\n                                    \"referencedDeclaration\": 3650,\n                                    \"src\": \"16454:31:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    }\n                                  },\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"expression\": {\n                                      \"argumentTypes\": null,\n                                      \"id\": 4420,\n                                      \"name\": \"_amount\",\n                                      \"nodeType\": \"Identifier\",\n                                      \"overloadedDeclarations\": [],\n                                      \"referencedDeclaration\": 4320,\n                                      \"src\": \"16487:7:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                        \"typeString\": \"struct AssetLib.Asset memory\"\n                                      }\n                                    },\n                                    \"id\": 4421,\n                                    \"isConstant\": false,\n                                    \"isLValue\": true,\n                                    \"isPure\": false,\n                                    \"lValueRequested\": false,\n                                    \"memberName\": \"principal\",\n                                    \"nodeType\": \"MemberAccess\",\n                                    \"referencedDeclaration\": 2785,\n                                    \"src\": \"16487:17:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    }\n                                  },\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"expression\": {\n                                      \"argumentTypes\": null,\n                                      \"id\": 4422,\n                                      \"name\": \"_amount\",\n                                      \"nodeType\": \"Identifier\",\n                                      \"overloadedDeclarations\": [],\n                                      \"referencedDeclaration\": 4320,\n                                      \"src\": \"16506:7:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                        \"typeString\": \"struct AssetLib.Asset memory\"\n                                      }\n                                    },\n                                    \"id\": 4423,\n                                    \"isConstant\": false,\n                                    \"isLValue\": true,\n                                    \"isPure\": false,\n                                    \"lValueRequested\": false,\n                                    \"memberName\": \"compoundInterest\",\n                                    \"nodeType\": \"MemberAccess\",\n                                    \"referencedDeclaration\": 2787,\n                                    \"src\": \"16506:24:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    }\n                                  }\n                                ],\n                                \"expression\": {\n                                  \"argumentTypes\": [\n                                    {\n                                      \"typeIdentifier\": \"t_address\",\n                                      \"typeString\": \"address\"\n                                    },\n                                    {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    },\n                                    {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    },\n                                    {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    }\n                                  ],\n                                  \"id\": 4416,\n                                  \"name\": \"UnbindStake\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 3704,\n                                  \"src\": \"16434:11:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_function_event_nonpayable$_t_address_$_t_uint256_$_t_uint256_$_t_uint256_$returns$__$\",\n                                    \"typeString\": \"function (address,uint256,uint256,uint256)\"\n                                  }\n                                },\n                                \"id\": 4424,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": false,\n                                \"kind\": \"functionCall\",\n                                \"lValueRequested\": false,\n                                \"names\": [],\n                                \"nodeType\": \"FunctionCall\",\n                                \"src\": \"16434:97:6\",\n                                \"tryCall\": false,\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_tuple$__$\",\n                                  \"typeString\": \"tuple()\"\n                                }\n                              },\n                              \"id\": 4425,\n                              \"nodeType\": \"EmitStatement\",\n                              \"src\": \"16429:102:6\"\n                            }\n                          ]\n                        },\n                        \"id\": 4427,\n                        \"nodeType\": \"IfStatement\",\n                        \"src\": \"15497:1049:6\",\n                        \"trueBody\": {\n                          \"id\": 4369,\n                          \"nodeType\": \"Block\",\n                          \"src\": \"15527:360:6\",\n                          \"statements\": [\n                            {\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"id\": 4344,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": false,\n                                \"lValueRequested\": false,\n                                \"leftHandSide\": {\n                                  \"argumentTypes\": null,\n                                  \"id\": 4335,\n                                  \"name\": \"_amount\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 4320,\n                                  \"src\": \"15545:7:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                    \"typeString\": \"struct AssetLib.Asset memory\"\n                                  }\n                                },\n                                \"nodeType\": \"Assignment\",\n                                \"operator\": \"=\",\n                                \"rightHandSide\": {\n                                  \"argumentTypes\": null,\n                                  \"arguments\": [\n                                    {\n                                      \"argumentTypes\": null,\n                                      \"baseExpression\": {\n                                        \"argumentTypes\": null,\n                                        \"id\": 4339,\n                                        \"name\": \"_liquidity\",\n                                        \"nodeType\": \"Identifier\",\n                                        \"overloadedDeclarations\": [],\n                                        \"referencedDeclaration\": 3796,\n                                        \"src\": \"15598:10:6\",\n                                        \"typeDescriptions\": {\n                                          \"typeIdentifier\": \"t_mapping$_t_address_$_t_struct$_Asset_$2788_storage_$\",\n                                          \"typeString\": \"mapping(address => struct AssetLib.Asset storage ref)\"\n                                        }\n                                      },\n                                      \"id\": 4341,\n                                      \"indexExpression\": {\n                                        \"argumentTypes\": null,\n                                        \"id\": 4340,\n                                        \"name\": \"sender\",\n                                        \"nodeType\": \"Identifier\",\n                                        \"overloadedDeclarations\": [],\n                                        \"referencedDeclaration\": 4299,\n                                        \"src\": \"15609:6:6\",\n                                        \"typeDescriptions\": {\n                                          \"typeIdentifier\": \"t_address\",\n                                          \"typeString\": \"address\"\n                                        }\n                                      },\n                                      \"isConstant\": false,\n                                      \"isLValue\": true,\n                                      \"isPure\": false,\n                                      \"lValueRequested\": false,\n                                      \"nodeType\": \"IndexAccess\",\n                                      \"src\": \"15598:18:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                                        \"typeString\": \"struct AssetLib.Asset storage ref\"\n                                      }\n                                    },\n                                    {\n                                      \"argumentTypes\": null,\n                                      \"id\": 4342,\n                                      \"name\": \"amount\",\n                                      \"nodeType\": \"Identifier\",\n                                      \"overloadedDeclarations\": [],\n                                      \"referencedDeclaration\": 4283,\n                                      \"src\": \"15618:6:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_uint256\",\n                                        \"typeString\": \"uint256\"\n                                      }\n                                    }\n                                  ],\n                                  \"expression\": {\n                                    \"argumentTypes\": [\n                                      {\n                                        \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                                        \"typeString\": \"struct AssetLib.Asset storage ref\"\n                                      },\n                                      {\n                                        \"typeIdentifier\": \"t_uint256\",\n                                        \"typeString\": \"uint256\"\n                                      }\n                                    ],\n                                    \"expression\": {\n                                      \"argumentTypes\": null,\n                                      \"expression\": {\n                                        \"argumentTypes\": null,\n                                        \"id\": 4336,\n                                        \"name\": \"stake\",\n                                        \"nodeType\": \"Identifier\",\n                                        \"overloadedDeclarations\": [],\n                                        \"referencedDeclaration\": 4304,\n                                        \"src\": \"15555:5:6\",\n                                        \"typeDescriptions\": {\n                                          \"typeIdentifier\": \"t_struct$_Stake_$3648_storage_ptr\",\n                                          \"typeString\": \"struct Staking.Stake storage pointer\"\n                                        }\n                                      },\n                                      \"id\": 4337,\n                                      \"isConstant\": false,\n                                      \"isLValue\": true,\n                                      \"isPure\": false,\n                                      \"lValueRequested\": false,\n                                      \"memberName\": \"asset\",\n                                      \"nodeType\": \"MemberAccess\",\n                                      \"referencedDeclaration\": 3647,\n                                      \"src\": \"15555:11:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                                        \"typeString\": \"struct AssetLib.Asset storage ref\"\n                                      }\n                                    },\n                                    \"id\": 4338,\n                                    \"isConstant\": false,\n                                    \"isLValue\": true,\n                                    \"isPure\": false,\n                                    \"lValueRequested\": false,\n                                    \"memberName\": \"iRelocateCompoundInterestFirst\",\n                                    \"nodeType\": \"MemberAccess\",\n                                    \"referencedDeclaration\": 3120,\n                                    \"src\": \"15555:42:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_function_internal_nonpayable$_t_struct$_Asset_$2788_storage_ptr_$_t_struct$_Asset_$2788_storage_ptr_$_t_uint256_$returns$_t_struct$_Asset_$2788_memory_ptr_$bound_to$_t_struct$_Asset_$2788_storage_ptr_$\",\n                                      \"typeString\": \"function (struct AssetLib.Asset storage pointer,struct AssetLib.Asset storage pointer,uint256) returns (struct AssetLib.Asset memory)\"\n                                    }\n                                  },\n                                  \"id\": 4343,\n                                  \"isConstant\": false,\n                                  \"isLValue\": false,\n                                  \"isPure\": false,\n                                  \"kind\": \"functionCall\",\n                                  \"lValueRequested\": false,\n                                  \"names\": [],\n                                  \"nodeType\": \"FunctionCall\",\n                                  \"src\": \"15555:70:6\",\n                                  \"tryCall\": false,\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                    \"typeString\": \"struct AssetLib.Asset memory\"\n                                  }\n                                },\n                                \"src\": \"15545:80:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                  \"typeString\": \"struct AssetLib.Asset memory\"\n                                }\n                              },\n                              \"id\": 4345,\n                              \"nodeType\": \"ExpressionStatement\",\n                              \"src\": \"15545:80:6\"\n                            },\n                            {\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"arguments\": [\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"id\": 4349,\n                                    \"name\": \"_amount\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 4320,\n                                    \"src\": \"15672:7:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                      \"typeString\": \"struct AssetLib.Asset memory\"\n                                    }\n                                  }\n                                ],\n                                \"expression\": {\n                                  \"argumentTypes\": [\n                                    {\n                                      \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                      \"typeString\": \"struct AssetLib.Asset memory\"\n                                    }\n                                  ],\n                                  \"expression\": {\n                                    \"argumentTypes\": null,\n                                    \"id\": 4346,\n                                    \"name\": \"_accruedGlobalLiquidity\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 3774,\n                                    \"src\": \"15643:23:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                                      \"typeString\": \"struct AssetLib.Asset storage ref\"\n                                    }\n                                  },\n                                  \"id\": 4348,\n                                  \"isConstant\": false,\n                                  \"isLValue\": true,\n                                  \"isPure\": false,\n                                  \"lValueRequested\": false,\n                                  \"memberName\": \"iAdd\",\n                                  \"nodeType\": \"MemberAccess\",\n                                  \"referencedDeclaration\": 2878,\n                                  \"src\": \"15643:28:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_function_internal_nonpayable$_t_struct$_Asset_$2788_storage_ptr_$_t_struct$_Asset_$2788_memory_ptr_$returns$__$bound_to$_t_struct$_Asset_$2788_storage_ptr_$\",\n                                    \"typeString\": \"function (struct AssetLib.Asset storage pointer,struct AssetLib.Asset memory)\"\n                                  }\n                                },\n                                \"id\": 4350,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": false,\n                                \"kind\": \"functionCall\",\n                                \"lValueRequested\": false,\n                                \"names\": [],\n                                \"nodeType\": \"FunctionCall\",\n                                \"src\": \"15643:37:6\",\n                                \"tryCall\": false,\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_tuple$__$\",\n                                  \"typeString\": \"tuple()\"\n                                }\n                              },\n                              \"id\": 4351,\n                              \"nodeType\": \"ExpressionStatement\",\n                              \"src\": \"15643:37:6\"\n                            },\n                            {\n                              \"eventCall\": {\n                                \"argumentTypes\": null,\n                                \"arguments\": [\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"id\": 4353,\n                                    \"name\": \"sender\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 4299,\n                                    \"src\": \"15715:6:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_address\",\n                                      \"typeString\": \"address\"\n                                    }\n                                  },\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"id\": 4354,\n                                    \"name\": \"curr_block\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 4294,\n                                    \"src\": \"15723:10:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    }\n                                  },\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"expression\": {\n                                      \"argumentTypes\": null,\n                                      \"id\": 4355,\n                                      \"name\": \"_amount\",\n                                      \"nodeType\": \"Identifier\",\n                                      \"overloadedDeclarations\": [],\n                                      \"referencedDeclaration\": 4320,\n                                      \"src\": \"15735:7:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                        \"typeString\": \"struct AssetLib.Asset memory\"\n                                      }\n                                    },\n                                    \"id\": 4356,\n                                    \"isConstant\": false,\n                                    \"isLValue\": true,\n                                    \"isPure\": false,\n                                    \"lValueRequested\": false,\n                                    \"memberName\": \"principal\",\n                                    \"nodeType\": \"MemberAccess\",\n                                    \"referencedDeclaration\": 2785,\n                                    \"src\": \"15735:17:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    }\n                                  },\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"expression\": {\n                                      \"argumentTypes\": null,\n                                      \"id\": 4357,\n                                      \"name\": \"_amount\",\n                                      \"nodeType\": \"Identifier\",\n                                      \"overloadedDeclarations\": [],\n                                      \"referencedDeclaration\": 4320,\n                                      \"src\": \"15754:7:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                        \"typeString\": \"struct AssetLib.Asset memory\"\n                                      }\n                                    },\n                                    \"id\": 4358,\n                                    \"isConstant\": false,\n                                    \"isLValue\": true,\n                                    \"isPure\": false,\n                                    \"lValueRequested\": false,\n                                    \"memberName\": \"compoundInterest\",\n                                    \"nodeType\": \"MemberAccess\",\n                                    \"referencedDeclaration\": 2787,\n                                    \"src\": \"15754:24:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    }\n                                  }\n                                ],\n                                \"expression\": {\n                                  \"argumentTypes\": [\n                                    {\n                                      \"typeIdentifier\": \"t_address\",\n                                      \"typeString\": \"address\"\n                                    },\n                                    {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    },\n                                    {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    },\n                                    {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    }\n                                  ],\n                                  \"id\": 4352,\n                                  \"name\": \"UnbindStake\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 3704,\n                                  \"src\": \"15703:11:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_function_event_nonpayable$_t_address_$_t_uint256_$_t_uint256_$_t_uint256_$returns$__$\",\n                                    \"typeString\": \"function (address,uint256,uint256,uint256)\"\n                                  }\n                                },\n                                \"id\": 4359,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": false,\n                                \"kind\": \"functionCall\",\n                                \"lValueRequested\": false,\n                                \"names\": [],\n                                \"nodeType\": \"FunctionCall\",\n                                \"src\": \"15703:76:6\",\n                                \"tryCall\": false,\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_tuple$__$\",\n                                  \"typeString\": \"tuple()\"\n                                }\n                              },\n                              \"id\": 4360,\n                              \"nodeType\": \"EmitStatement\",\n                              \"src\": \"15698:81:6\"\n                            },\n                            {\n                              \"eventCall\": {\n                                \"argumentTypes\": null,\n                                \"arguments\": [\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"id\": 4362,\n                                    \"name\": \"sender\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 4299,\n                                    \"src\": \"15820:6:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_address\",\n                                      \"typeString\": \"address\"\n                                    }\n                                  },\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"expression\": {\n                                      \"argumentTypes\": null,\n                                      \"id\": 4363,\n                                      \"name\": \"_amount\",\n                                      \"nodeType\": \"Identifier\",\n                                      \"overloadedDeclarations\": [],\n                                      \"referencedDeclaration\": 4320,\n                                      \"src\": \"15828:7:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                        \"typeString\": \"struct AssetLib.Asset memory\"\n                                      }\n                                    },\n                                    \"id\": 4364,\n                                    \"isConstant\": false,\n                                    \"isLValue\": true,\n                                    \"isPure\": false,\n                                    \"lValueRequested\": false,\n                                    \"memberName\": \"principal\",\n                                    \"nodeType\": \"MemberAccess\",\n                                    \"referencedDeclaration\": 2785,\n                                    \"src\": \"15828:17:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    }\n                                  },\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"expression\": {\n                                      \"argumentTypes\": null,\n                                      \"id\": 4365,\n                                      \"name\": \"_amount\",\n                                      \"nodeType\": \"Identifier\",\n                                      \"overloadedDeclarations\": [],\n                                      \"referencedDeclaration\": 4320,\n                                      \"src\": \"15847:7:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                        \"typeString\": \"struct AssetLib.Asset memory\"\n                                      }\n                                    },\n                                    \"id\": 4366,\n                                    \"isConstant\": false,\n                                    \"isLValue\": true,\n                                    \"isPure\": false,\n                                    \"lValueRequested\": false,\n                                    \"memberName\": \"compoundInterest\",\n                                    \"nodeType\": \"MemberAccess\",\n                                    \"referencedDeclaration\": 2787,\n                                    \"src\": \"15847:24:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    }\n                                  }\n                                ],\n                                \"expression\": {\n                                  \"argumentTypes\": [\n                                    {\n                                      \"typeIdentifier\": \"t_address\",\n                                      \"typeString\": \"address\"\n                                    },\n                                    {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    },\n                                    {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    }\n                                  ],\n                                  \"id\": 4361,\n                                  \"name\": \"LiquidityUnlocked\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 3694,\n                                  \"src\": \"15802:17:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_function_event_nonpayable$_t_address_$_t_uint256_$_t_uint256_$returns$__$\",\n                                    \"typeString\": \"function (address,uint256,uint256)\"\n                                  }\n                                },\n                                \"id\": 4367,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": false,\n                                \"kind\": \"functionCall\",\n                                \"lValueRequested\": false,\n                                \"names\": [],\n                                \"nodeType\": \"FunctionCall\",\n                                \"src\": \"15802:70:6\",\n                                \"tryCall\": false,\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_tuple$__$\",\n                                  \"typeString\": \"tuple()\"\n                                }\n                              },\n                              \"id\": 4368,\n                              \"nodeType\": \"EmitStatement\",\n                              \"src\": \"15797:75:6\"\n                            }\n                          ]\n                        }\n                      }\n                    ]\n                  }\n                }\n              ]\n            },\n            \"documentation\": {\n              \"id\": 4281,\n              \"nodeType\": \"StructuredDocumentation\",\n              \"src\": \"13414:755:6\",\n              \"text\": \"@notice Unbinds amount from the stake of sender of the transaction,\\n        and *LOCKS* it for number of blocks defined by value of the\\n        `_lockPeriodInBlocks` state of this contract at the point\\n        of this call.\\n        The locked amount can *NOT* be withdrawn from the contract\\n        *BEFORE* the lock period ends.\\n     *         Unbinding (=calling this method) also means, that compound\\n        interest will be calculated for period since la.\\n     * @param amount - value to un-bind from the stake\\n                If `amount=0` then the **WHOLE** stake (including\\n                compound interest) will be unbound.\\n     * @dev public access\"\n            },\n            \"functionSelector\": \"52885d8d\",\n            \"id\": 4550,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [\n              {\n                \"arguments\": [\n                  {\n                    \"argumentTypes\": null,\n                    \"id\": 4288,\n                    \"name\": \"txExpirationBlock\",\n                    \"nodeType\": \"Identifier\",\n                    \"overloadedDeclarations\": [],\n                    \"referencedDeclaration\": 4285,\n                    \"src\": \"14353:17:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  }\n                ],\n                \"id\": 4289,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 4287,\n                  \"name\": \"verifyTxExpiration\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 3836,\n                  \"src\": \"14334:18:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$_t_uint256_$\",\n                    \"typeString\": \"modifier (uint256)\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"14334:37:6\"\n              },\n              {\n                \"arguments\": null,\n                \"id\": 4291,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 4290,\n                  \"name\": \"verifyNotPaused\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 3848,\n                  \"src\": \"14380:15:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$__$\",\n                    \"typeString\": \"modifier ()\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"14380:15:6\"\n              }\n            ],\n            \"name\": \"unbindStake\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 4286,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 4283,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"amount\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4550,\n                  \"src\": \"14204:14:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 4282,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"14204:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 4285,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"txExpirationBlock\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4550,\n                  \"src\": \"14273:25:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 4284,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"14273:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"14194:114:6\"\n            },\n            \"returnParameters\": {\n              \"id\": 4292,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"14400:0:6\"\n            },\n            \"scope\": 5490,\n            \"src\": \"14174:3640:6\",\n            \"stateMutability\": \"nonpayable\",\n            \"virtual\": false,\n            \"visibility\": \"external\"\n          },\n          {\n            \"body\": {\n              \"id\": 4557,\n              \"nodeType\": \"Block\",\n              \"src\": \"17885:43:6\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 4555,\n                    \"name\": \"_rewardsPoolBalance\",\n                    \"nodeType\": \"Identifier\",\n                    \"overloadedDeclarations\": [],\n                    \"referencedDeclaration\": 3770,\n                    \"src\": \"17902:19:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"functionReturnParameters\": 4554,\n                  \"id\": 4556,\n                  \"nodeType\": \"Return\",\n                  \"src\": \"17895:26:6\"\n                }\n              ]\n            },\n            \"documentation\": null,\n            \"functionSelector\": \"adf55101\",\n            \"id\": 4558,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [],\n            \"name\": \"getRewardsPoolBalance\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 4551,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"17851:2:6\"\n            },\n            \"returnParameters\": {\n              \"id\": 4554,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 4553,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4558,\n                  \"src\": \"17876:7:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 4552,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"17876:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"17875:9:6\"\n            },\n            \"scope\": 5490,\n            \"src\": \"17821:107:6\",\n            \"stateMutability\": \"view\",\n            \"virtual\": false,\n            \"visibility\": \"external\"\n          },\n          {\n            \"body\": {\n              \"id\": 4565,\n              \"nodeType\": \"Block\",\n              \"src\": \"18000:39:6\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 4563,\n                    \"name\": \"_earliestDelete\",\n                    \"nodeType\": \"Identifier\",\n                    \"overloadedDeclarations\": [],\n                    \"referencedDeclaration\": 3764,\n                    \"src\": \"18017:15:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"functionReturnParameters\": 4562,\n                  \"id\": 4564,\n                  \"nodeType\": \"Return\",\n                  \"src\": \"18010:22:6\"\n                }\n              ]\n            },\n            \"documentation\": null,\n            \"functionSelector\": \"085313ec\",\n            \"id\": 4566,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [],\n            \"name\": \"getEarliestDeleteBlock\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 4559,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"17966:2:6\"\n            },\n            \"returnParameters\": {\n              \"id\": 4562,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 4561,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4566,\n                  \"src\": \"17991:7:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 4560,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"17991:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"17990:9:6\"\n            },\n            \"scope\": 5490,\n            \"src\": \"17935:104:6\",\n            \"stateMutability\": \"view\",\n            \"virtual\": false,\n            \"visibility\": \"external\"\n          },\n          {\n            \"body\": {\n              \"id\": 4581,\n              \"nodeType\": \"Block\",\n              \"src\": \"18144:59:6\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 4579,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 4573,\n                      \"name\": \"length\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 4571,\n                      \"src\": \"18154:6:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"baseExpression\": {\n                            \"argumentTypes\": null,\n                            \"id\": 4574,\n                            \"name\": \"_locked\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 3792,\n                            \"src\": \"18163:7:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_mapping$_t_address_$_t_struct$_Locked_$3659_storage_$\",\n                              \"typeString\": \"mapping(address => struct Staking.Locked storage ref)\"\n                            }\n                          },\n                          \"id\": 4576,\n                          \"indexExpression\": {\n                            \"argumentTypes\": null,\n                            \"id\": 4575,\n                            \"name\": \"forAddress\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 4568,\n                            \"src\": \"18171:10:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_address\",\n                              \"typeString\": \"address\"\n                            }\n                          },\n                          \"isConstant\": false,\n                          \"isLValue\": true,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"nodeType\": \"IndexAccess\",\n                          \"src\": \"18163:19:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_struct$_Locked_$3659_storage\",\n                            \"typeString\": \"struct Staking.Locked storage ref\"\n                          }\n                        },\n                        \"id\": 4577,\n                        \"isConstant\": false,\n                        \"isLValue\": true,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"memberName\": \"assets\",\n                        \"nodeType\": \"MemberAccess\",\n                        \"referencedDeclaration\": 3658,\n                        \"src\": \"18163:26:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_array$_t_struct$_LockedAsset_$3653_storage_$dyn_storage\",\n                          \"typeString\": \"struct Staking.LockedAsset storage ref[] storage ref\"\n                        }\n                      },\n                      \"id\": 4578,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"memberName\": \"length\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": null,\n                      \"src\": \"18163:33:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"src\": \"18154:42:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"id\": 4580,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"18154:42:6\"\n                }\n              ]\n            },\n            \"documentation\": null,\n            \"functionSelector\": \"40e97903\",\n            \"id\": 4582,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [],\n            \"name\": \"getNumberOfLockedAssetsForUser\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 4569,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 4568,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"forAddress\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4582,\n                  \"src\": \"18086:18:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_address\",\n                    \"typeString\": \"address\"\n                  },\n                  \"typeName\": {\n                    \"id\": 4567,\n                    \"name\": \"address\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"18086:7:6\",\n                    \"stateMutability\": \"nonpayable\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address\",\n                      \"typeString\": \"address\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"18085:20:6\"\n            },\n            \"returnParameters\": {\n              \"id\": 4572,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 4571,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"length\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4582,\n                  \"src\": \"18128:14:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 4570,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"18128:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"18127:16:6\"\n            },\n            \"scope\": 5490,\n            \"src\": \"18046:157:6\",\n            \"stateMutability\": \"view\",\n            \"virtual\": false,\n            \"visibility\": \"external\"\n          },\n          {\n            \"body\": {\n              \"id\": 4606,\n              \"nodeType\": \"Block\",\n              \"src\": \"18338:147:6\",\n              \"statements\": [\n                {\n                  \"assignments\": [\n                    4594\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 4594,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"aggregate\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 4606,\n                      \"src\": \"18348:32:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"storage\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                        \"typeString\": \"struct AssetLib.Asset\"\n                      },\n                      \"typeName\": {\n                        \"contractScope\": null,\n                        \"id\": 4593,\n                        \"name\": \"AssetLib.Asset\",\n                        \"nodeType\": \"UserDefinedTypeName\",\n                        \"referencedDeclaration\": 2788,\n                        \"src\": \"18348:14:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                          \"typeString\": \"struct AssetLib.Asset\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 4599,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"expression\": {\n                      \"argumentTypes\": null,\n                      \"baseExpression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 4595,\n                        \"name\": \"_locked\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 3792,\n                        \"src\": \"18383:7:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_mapping$_t_address_$_t_struct$_Locked_$3659_storage_$\",\n                          \"typeString\": \"mapping(address => struct Staking.Locked storage ref)\"\n                        }\n                      },\n                      \"id\": 4597,\n                      \"indexExpression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 4596,\n                        \"name\": \"forAddress\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4584,\n                        \"src\": \"18391:10:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        }\n                      },\n                      \"isConstant\": false,\n                      \"isLValue\": true,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"nodeType\": \"IndexAccess\",\n                      \"src\": \"18383:19:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_struct$_Locked_$3659_storage\",\n                        \"typeString\": \"struct Staking.Locked storage ref\"\n                      }\n                    },\n                    \"id\": 4598,\n                    \"isConstant\": false,\n                    \"isLValue\": true,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"memberName\": \"aggregate\",\n                    \"nodeType\": \"MemberAccess\",\n                    \"referencedDeclaration\": 3655,\n                    \"src\": \"18383:29:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                      \"typeString\": \"struct AssetLib.Asset storage ref\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"18348:64:6\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"components\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 4600,\n                          \"name\": \"aggregate\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 4594,\n                          \"src\": \"18430:9:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                            \"typeString\": \"struct AssetLib.Asset storage pointer\"\n                          }\n                        },\n                        \"id\": 4601,\n                        \"isConstant\": false,\n                        \"isLValue\": true,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"memberName\": \"principal\",\n                        \"nodeType\": \"MemberAccess\",\n                        \"referencedDeclaration\": 2785,\n                        \"src\": \"18430:19:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 4602,\n                          \"name\": \"aggregate\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 4594,\n                          \"src\": \"18451:9:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                            \"typeString\": \"struct AssetLib.Asset storage pointer\"\n                          }\n                        },\n                        \"id\": 4603,\n                        \"isConstant\": false,\n                        \"isLValue\": true,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"memberName\": \"compoundInterest\",\n                        \"nodeType\": \"MemberAccess\",\n                        \"referencedDeclaration\": 2787,\n                        \"src\": \"18451:26:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"id\": 4604,\n                    \"isConstant\": false,\n                    \"isInlineArray\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"nodeType\": \"TupleExpression\",\n                    \"src\": \"18429:49:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$_t_uint256_$_t_uint256_$\",\n                      \"typeString\": \"tuple(uint256,uint256)\"\n                    }\n                  },\n                  \"functionReturnParameters\": 4590,\n                  \"id\": 4605,\n                  \"nodeType\": \"Return\",\n                  \"src\": \"18422:56:6\"\n                }\n              ]\n            },\n            \"documentation\": null,\n            \"functionSelector\": \"a8f1b4c4\",\n            \"id\": 4607,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [],\n            \"name\": \"getLockedAssetsAggregateForUser\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 4585,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 4584,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"forAddress\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4607,\n                  \"src\": \"18251:18:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_address\",\n                    \"typeString\": \"address\"\n                  },\n                  \"typeName\": {\n                    \"id\": 4583,\n                    \"name\": \"address\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"18251:7:6\",\n                    \"stateMutability\": \"nonpayable\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address\",\n                      \"typeString\": \"address\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"18250:20:6\"\n            },\n            \"returnParameters\": {\n              \"id\": 4590,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 4587,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"principal\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4607,\n                  \"src\": \"18293:17:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 4586,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"18293:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 4589,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"compoundInterest\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4607,\n                  \"src\": \"18312:24:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 4588,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"18312:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"18292:45:6\"\n            },\n            \"scope\": 5490,\n            \"src\": \"18210:275:6\",\n            \"stateMutability\": \"view\",\n            \"virtual\": false,\n            \"visibility\": \"external\"\n          },\n          {\n            \"body\": {\n              \"id\": 4711,\n              \"nodeType\": \"Block\",\n              \"src\": \"18915:654:6\",\n              \"statements\": [\n                {\n                  \"assignments\": [\n                    4625\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 4625,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"lockedAssets\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 4711,\n                      \"src\": \"18925:34:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"storage\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_array$_t_struct$_LockedAsset_$3653_storage_$dyn_storage_ptr\",\n                        \"typeString\": \"struct Staking.LockedAsset[]\"\n                      },\n                      \"typeName\": {\n                        \"baseType\": {\n                          \"contractScope\": null,\n                          \"id\": 4623,\n                          \"name\": \"LockedAsset\",\n                          \"nodeType\": \"UserDefinedTypeName\",\n                          \"referencedDeclaration\": 3653,\n                          \"src\": \"18925:11:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_struct$_LockedAsset_$3653_storage_ptr\",\n                            \"typeString\": \"struct Staking.LockedAsset\"\n                          }\n                        },\n                        \"id\": 4624,\n                        \"length\": null,\n                        \"nodeType\": \"ArrayTypeName\",\n                        \"src\": \"18925:13:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_array$_t_struct$_LockedAsset_$3653_storage_$dyn_storage_ptr\",\n                          \"typeString\": \"struct Staking.LockedAsset[]\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 4630,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"expression\": {\n                      \"argumentTypes\": null,\n                      \"baseExpression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 4626,\n                        \"name\": \"_locked\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 3792,\n                        \"src\": \"18962:7:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_mapping$_t_address_$_t_struct$_Locked_$3659_storage_$\",\n                          \"typeString\": \"mapping(address => struct Staking.Locked storage ref)\"\n                        }\n                      },\n                      \"id\": 4628,\n                      \"indexExpression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 4627,\n                        \"name\": \"forAddress\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4610,\n                        \"src\": \"18970:10:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        }\n                      },\n                      \"isConstant\": false,\n                      \"isLValue\": true,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"nodeType\": \"IndexAccess\",\n                      \"src\": \"18962:19:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_struct$_Locked_$3659_storage\",\n                        \"typeString\": \"struct Staking.Locked storage ref\"\n                      }\n                    },\n                    \"id\": 4629,\n                    \"isConstant\": false,\n                    \"isLValue\": true,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"memberName\": \"assets\",\n                    \"nodeType\": \"MemberAccess\",\n                    \"referencedDeclaration\": 3658,\n                    \"src\": \"18962:26:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_array$_t_struct$_LockedAsset_$3653_storage_$dyn_storage\",\n                      \"typeString\": \"struct Staking.LockedAsset storage ref[] storage ref\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"18925:63:6\"\n                },\n                {\n                  \"assignments\": [\n                    4632\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 4632,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"length\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 4711,\n                      \"src\": \"18998:14:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"default\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      },\n                      \"typeName\": {\n                        \"id\": 4631,\n                        \"name\": \"uint256\",\n                        \"nodeType\": \"ElementaryTypeName\",\n                        \"src\": \"18998:7:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 4635,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"expression\": {\n                      \"argumentTypes\": null,\n                      \"id\": 4633,\n                      \"name\": \"lockedAssets\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 4625,\n                      \"src\": \"19015:12:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_array$_t_struct$_LockedAsset_$3653_storage_$dyn_storage_ptr\",\n                        \"typeString\": \"struct Staking.LockedAsset storage ref[] storage pointer\"\n                      }\n                    },\n                    \"id\": 4634,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"memberName\": \"length\",\n                    \"nodeType\": \"MemberAccess\",\n                    \"referencedDeclaration\": null,\n                    \"src\": \"19015:19:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"18998:36:6\"\n                },\n                {\n                  \"condition\": {\n                    \"argumentTypes\": null,\n                    \"commonType\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    },\n                    \"id\": 4638,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftExpression\": {\n                      \"argumentTypes\": null,\n                      \"id\": 4636,\n                      \"name\": \"length\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 4632,\n                      \"src\": \"19048:6:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"BinaryOperation\",\n                    \"operator\": \"!=\",\n                    \"rightExpression\": {\n                      \"argumentTypes\": null,\n                      \"hexValue\": \"30\",\n                      \"id\": 4637,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": true,\n                      \"kind\": \"number\",\n                      \"lValueRequested\": false,\n                      \"nodeType\": \"Literal\",\n                      \"src\": \"19058:1:6\",\n                      \"subdenomination\": null,\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_rational_0_by_1\",\n                        \"typeString\": \"int_const 0\"\n                      },\n                      \"value\": \"0\"\n                    },\n                    \"src\": \"19048:11:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_bool\",\n                      \"typeString\": \"bool\"\n                    }\n                  },\n                  \"falseBody\": null,\n                  \"id\": 4710,\n                  \"nodeType\": \"IfStatement\",\n                  \"src\": \"19044:519:6\",\n                  \"trueBody\": {\n                    \"id\": 4709,\n                    \"nodeType\": \"Block\",\n                    \"src\": \"19061:502:6\",\n                    \"statements\": [\n                      {\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 4645,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"leftHandSide\": {\n                            \"argumentTypes\": null,\n                            \"id\": 4639,\n                            \"name\": \"principal\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 4614,\n                            \"src\": \"19075:9:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_array$_t_uint256_$dyn_memory_ptr\",\n                              \"typeString\": \"uint256[] memory\"\n                            }\n                          },\n                          \"nodeType\": \"Assignment\",\n                          \"operator\": \"=\",\n                          \"rightHandSide\": {\n                            \"argumentTypes\": null,\n                            \"arguments\": [\n                              {\n                                \"argumentTypes\": null,\n                                \"id\": 4643,\n                                \"name\": \"length\",\n                                \"nodeType\": \"Identifier\",\n                                \"overloadedDeclarations\": [],\n                                \"referencedDeclaration\": 4632,\n                                \"src\": \"19101:6:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              }\n                            ],\n                            \"expression\": {\n                              \"argumentTypes\": [\n                                {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              ],\n                              \"id\": 4642,\n                              \"isConstant\": false,\n                              \"isLValue\": false,\n                              \"isPure\": true,\n                              \"lValueRequested\": false,\n                              \"nodeType\": \"NewExpression\",\n                              \"src\": \"19087:13:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_function_objectcreation_pure$_t_uint256_$returns$_t_array$_t_uint256_$dyn_memory_ptr_$\",\n                                \"typeString\": \"function (uint256) pure returns (uint256[] memory)\"\n                              },\n                              \"typeName\": {\n                                \"baseType\": {\n                                  \"id\": 4640,\n                                  \"name\": \"uint256\",\n                                  \"nodeType\": \"ElementaryTypeName\",\n                                  \"src\": \"19091:7:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_uint256\",\n                                    \"typeString\": \"uint256\"\n                                  }\n                                },\n                                \"id\": 4641,\n                                \"length\": null,\n                                \"nodeType\": \"ArrayTypeName\",\n                                \"src\": \"19091:9:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_array$_t_uint256_$dyn_storage_ptr\",\n                                  \"typeString\": \"uint256[]\"\n                                }\n                              }\n                            },\n                            \"id\": 4644,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": false,\n                            \"kind\": \"functionCall\",\n                            \"lValueRequested\": false,\n                            \"names\": [],\n                            \"nodeType\": \"FunctionCall\",\n                            \"src\": \"19087:21:6\",\n                            \"tryCall\": false,\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_array$_t_uint256_$dyn_memory_ptr\",\n                              \"typeString\": \"uint256[] memory\"\n                            }\n                          },\n                          \"src\": \"19075:33:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_array$_t_uint256_$dyn_memory_ptr\",\n                            \"typeString\": \"uint256[] memory\"\n                          }\n                        },\n                        \"id\": 4646,\n                        \"nodeType\": \"ExpressionStatement\",\n                        \"src\": \"19075:33:6\"\n                      },\n                      {\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 4653,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"leftHandSide\": {\n                            \"argumentTypes\": null,\n                            \"id\": 4647,\n                            \"name\": \"compoundInterest\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 4617,\n                            \"src\": \"19122:16:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_array$_t_uint256_$dyn_memory_ptr\",\n                              \"typeString\": \"uint256[] memory\"\n                            }\n                          },\n                          \"nodeType\": \"Assignment\",\n                          \"operator\": \"=\",\n                          \"rightHandSide\": {\n                            \"argumentTypes\": null,\n                            \"arguments\": [\n                              {\n                                \"argumentTypes\": null,\n                                \"id\": 4651,\n                                \"name\": \"length\",\n                                \"nodeType\": \"Identifier\",\n                                \"overloadedDeclarations\": [],\n                                \"referencedDeclaration\": 4632,\n                                \"src\": \"19155:6:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              }\n                            ],\n                            \"expression\": {\n                              \"argumentTypes\": [\n                                {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              ],\n                              \"id\": 4650,\n                              \"isConstant\": false,\n                              \"isLValue\": false,\n                              \"isPure\": true,\n                              \"lValueRequested\": false,\n                              \"nodeType\": \"NewExpression\",\n                              \"src\": \"19141:13:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_function_objectcreation_pure$_t_uint256_$returns$_t_array$_t_uint256_$dyn_memory_ptr_$\",\n                                \"typeString\": \"function (uint256) pure returns (uint256[] memory)\"\n                              },\n                              \"typeName\": {\n                                \"baseType\": {\n                                  \"id\": 4648,\n                                  \"name\": \"uint256\",\n                                  \"nodeType\": \"ElementaryTypeName\",\n                                  \"src\": \"19145:7:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_uint256\",\n                                    \"typeString\": \"uint256\"\n                                  }\n                                },\n                                \"id\": 4649,\n                                \"length\": null,\n                                \"nodeType\": \"ArrayTypeName\",\n                                \"src\": \"19145:9:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_array$_t_uint256_$dyn_storage_ptr\",\n                                  \"typeString\": \"uint256[]\"\n                                }\n                              }\n                            },\n                            \"id\": 4652,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": false,\n                            \"kind\": \"functionCall\",\n                            \"lValueRequested\": false,\n                            \"names\": [],\n                            \"nodeType\": \"FunctionCall\",\n                            \"src\": \"19141:21:6\",\n                            \"tryCall\": false,\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_array$_t_uint256_$dyn_memory_ptr\",\n                              \"typeString\": \"uint256[] memory\"\n                            }\n                          },\n                          \"src\": \"19122:40:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_array$_t_uint256_$dyn_memory_ptr\",\n                            \"typeString\": \"uint256[] memory\"\n                          }\n                        },\n                        \"id\": 4654,\n                        \"nodeType\": \"ExpressionStatement\",\n                        \"src\": \"19122:40:6\"\n                      },\n                      {\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 4661,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"leftHandSide\": {\n                            \"argumentTypes\": null,\n                            \"id\": 4655,\n                            \"name\": \"liquidSinceBlock\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 4620,\n                            \"src\": \"19176:16:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_array$_t_uint256_$dyn_memory_ptr\",\n                              \"typeString\": \"uint256[] memory\"\n                            }\n                          },\n                          \"nodeType\": \"Assignment\",\n                          \"operator\": \"=\",\n                          \"rightHandSide\": {\n                            \"argumentTypes\": null,\n                            \"arguments\": [\n                              {\n                                \"argumentTypes\": null,\n                                \"id\": 4659,\n                                \"name\": \"length\",\n                                \"nodeType\": \"Identifier\",\n                                \"overloadedDeclarations\": [],\n                                \"referencedDeclaration\": 4632,\n                                \"src\": \"19209:6:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              }\n                            ],\n                            \"expression\": {\n                              \"argumentTypes\": [\n                                {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              ],\n                              \"id\": 4658,\n                              \"isConstant\": false,\n                              \"isLValue\": false,\n                              \"isPure\": true,\n                              \"lValueRequested\": false,\n                              \"nodeType\": \"NewExpression\",\n                              \"src\": \"19195:13:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_function_objectcreation_pure$_t_uint256_$returns$_t_array$_t_uint256_$dyn_memory_ptr_$\",\n                                \"typeString\": \"function (uint256) pure returns (uint256[] memory)\"\n                              },\n                              \"typeName\": {\n                                \"baseType\": {\n                                  \"id\": 4656,\n                                  \"name\": \"uint256\",\n                                  \"nodeType\": \"ElementaryTypeName\",\n                                  \"src\": \"19199:7:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_uint256\",\n                                    \"typeString\": \"uint256\"\n                                  }\n                                },\n                                \"id\": 4657,\n                                \"length\": null,\n                                \"nodeType\": \"ArrayTypeName\",\n                                \"src\": \"19199:9:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_array$_t_uint256_$dyn_storage_ptr\",\n                                  \"typeString\": \"uint256[]\"\n                                }\n                              }\n                            },\n                            \"id\": 4660,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": false,\n                            \"kind\": \"functionCall\",\n                            \"lValueRequested\": false,\n                            \"names\": [],\n                            \"nodeType\": \"FunctionCall\",\n                            \"src\": \"19195:21:6\",\n                            \"tryCall\": false,\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_array$_t_uint256_$dyn_memory_ptr\",\n                              \"typeString\": \"uint256[] memory\"\n                            }\n                          },\n                          \"src\": \"19176:40:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_array$_t_uint256_$dyn_memory_ptr\",\n                            \"typeString\": \"uint256[] memory\"\n                          }\n                        },\n                        \"id\": 4662,\n                        \"nodeType\": \"ExpressionStatement\",\n                        \"src\": \"19176:40:6\"\n                      },\n                      {\n                        \"body\": {\n                          \"id\": 4707,\n                          \"nodeType\": \"Block\",\n                          \"src\": \"19266:287:6\",\n                          \"statements\": [\n                            {\n                              \"assignments\": [\n                                4674\n                              ],\n                              \"declarations\": [\n                                {\n                                  \"constant\": false,\n                                  \"id\": 4674,\n                                  \"mutability\": \"mutable\",\n                                  \"name\": \"la\",\n                                  \"nodeType\": \"VariableDeclaration\",\n                                  \"overrides\": null,\n                                  \"scope\": 4707,\n                                  \"src\": \"19284:22:6\",\n                                  \"stateVariable\": false,\n                                  \"storageLocation\": \"storage\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_struct$_LockedAsset_$3653_storage_ptr\",\n                                    \"typeString\": \"struct Staking.LockedAsset\"\n                                  },\n                                  \"typeName\": {\n                                    \"contractScope\": null,\n                                    \"id\": 4673,\n                                    \"name\": \"LockedAsset\",\n                                    \"nodeType\": \"UserDefinedTypeName\",\n                                    \"referencedDeclaration\": 3653,\n                                    \"src\": \"19284:11:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_struct$_LockedAsset_$3653_storage_ptr\",\n                                      \"typeString\": \"struct Staking.LockedAsset\"\n                                    }\n                                  },\n                                  \"value\": null,\n                                  \"visibility\": \"internal\"\n                                }\n                              ],\n                              \"id\": 4678,\n                              \"initialValue\": {\n                                \"argumentTypes\": null,\n                                \"baseExpression\": {\n                                  \"argumentTypes\": null,\n                                  \"id\": 4675,\n                                  \"name\": \"lockedAssets\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 4625,\n                                  \"src\": \"19309:12:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_array$_t_struct$_LockedAsset_$3653_storage_$dyn_storage_ptr\",\n                                    \"typeString\": \"struct Staking.LockedAsset storage ref[] storage pointer\"\n                                  }\n                                },\n                                \"id\": 4677,\n                                \"indexExpression\": {\n                                  \"argumentTypes\": null,\n                                  \"id\": 4676,\n                                  \"name\": \"i\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 4664,\n                                  \"src\": \"19322:1:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_uint256\",\n                                    \"typeString\": \"uint256\"\n                                  }\n                                },\n                                \"isConstant\": false,\n                                \"isLValue\": true,\n                                \"isPure\": false,\n                                \"lValueRequested\": false,\n                                \"nodeType\": \"IndexAccess\",\n                                \"src\": \"19309:15:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_struct$_LockedAsset_$3653_storage\",\n                                  \"typeString\": \"struct Staking.LockedAsset storage ref\"\n                                }\n                              },\n                              \"nodeType\": \"VariableDeclarationStatement\",\n                              \"src\": \"19284:40:6\"\n                            },\n                            {\n                              \"assignments\": [\n                                4682\n                              ],\n                              \"declarations\": [\n                                {\n                                  \"constant\": false,\n                                  \"id\": 4682,\n                                  \"mutability\": \"mutable\",\n                                  \"name\": \"a\",\n                                  \"nodeType\": \"VariableDeclaration\",\n                                  \"overrides\": null,\n                                  \"scope\": 4707,\n                                  \"src\": \"19342:24:6\",\n                                  \"stateVariable\": false,\n                                  \"storageLocation\": \"storage\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                                    \"typeString\": \"struct AssetLib.Asset\"\n                                  },\n                                  \"typeName\": {\n                                    \"contractScope\": null,\n                                    \"id\": 4681,\n                                    \"name\": \"AssetLib.Asset\",\n                                    \"nodeType\": \"UserDefinedTypeName\",\n                                    \"referencedDeclaration\": 2788,\n                                    \"src\": \"19342:14:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                                      \"typeString\": \"struct AssetLib.Asset\"\n                                    }\n                                  },\n                                  \"value\": null,\n                                  \"visibility\": \"internal\"\n                                }\n                              ],\n                              \"id\": 4685,\n                              \"initialValue\": {\n                                \"argumentTypes\": null,\n                                \"expression\": {\n                                  \"argumentTypes\": null,\n                                  \"id\": 4683,\n                                  \"name\": \"la\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 4674,\n                                  \"src\": \"19369:2:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_struct$_LockedAsset_$3653_storage_ptr\",\n                                    \"typeString\": \"struct Staking.LockedAsset storage pointer\"\n                                  }\n                                },\n                                \"id\": 4684,\n                                \"isConstant\": false,\n                                \"isLValue\": true,\n                                \"isPure\": false,\n                                \"lValueRequested\": false,\n                                \"memberName\": \"asset\",\n                                \"nodeType\": \"MemberAccess\",\n                                \"referencedDeclaration\": 3652,\n                                \"src\": \"19369:8:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                                  \"typeString\": \"struct AssetLib.Asset storage ref\"\n                                }\n                              },\n                              \"nodeType\": \"VariableDeclarationStatement\",\n                              \"src\": \"19342:35:6\"\n                            },\n                            {\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"id\": 4691,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": false,\n                                \"lValueRequested\": false,\n                                \"leftHandSide\": {\n                                  \"argumentTypes\": null,\n                                  \"baseExpression\": {\n                                    \"argumentTypes\": null,\n                                    \"id\": 4686,\n                                    \"name\": \"principal\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 4614,\n                                    \"src\": \"19395:9:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_array$_t_uint256_$dyn_memory_ptr\",\n                                      \"typeString\": \"uint256[] memory\"\n                                    }\n                                  },\n                                  \"id\": 4688,\n                                  \"indexExpression\": {\n                                    \"argumentTypes\": null,\n                                    \"id\": 4687,\n                                    \"name\": \"i\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 4664,\n                                    \"src\": \"19405:1:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    }\n                                  },\n                                  \"isConstant\": false,\n                                  \"isLValue\": true,\n                                  \"isPure\": false,\n                                  \"lValueRequested\": true,\n                                  \"nodeType\": \"IndexAccess\",\n                                  \"src\": \"19395:12:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_uint256\",\n                                    \"typeString\": \"uint256\"\n                                  }\n                                },\n                                \"nodeType\": \"Assignment\",\n                                \"operator\": \"=\",\n                                \"rightHandSide\": {\n                                  \"argumentTypes\": null,\n                                  \"expression\": {\n                                    \"argumentTypes\": null,\n                                    \"id\": 4689,\n                                    \"name\": \"a\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 4682,\n                                    \"src\": \"19410:1:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                                      \"typeString\": \"struct AssetLib.Asset storage pointer\"\n                                    }\n                                  },\n                                  \"id\": 4690,\n                                  \"isConstant\": false,\n                                  \"isLValue\": true,\n                                  \"isPure\": false,\n                                  \"lValueRequested\": false,\n                                  \"memberName\": \"principal\",\n                                  \"nodeType\": \"MemberAccess\",\n                                  \"referencedDeclaration\": 2785,\n                                  \"src\": \"19410:11:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_uint256\",\n                                    \"typeString\": \"uint256\"\n                                  }\n                                },\n                                \"src\": \"19395:26:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              },\n                              \"id\": 4692,\n                              \"nodeType\": \"ExpressionStatement\",\n                              \"src\": \"19395:26:6\"\n                            },\n                            {\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"id\": 4698,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": false,\n                                \"lValueRequested\": false,\n                                \"leftHandSide\": {\n                                  \"argumentTypes\": null,\n                                  \"baseExpression\": {\n                                    \"argumentTypes\": null,\n                                    \"id\": 4693,\n                                    \"name\": \"compoundInterest\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 4617,\n                                    \"src\": \"19439:16:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_array$_t_uint256_$dyn_memory_ptr\",\n                                      \"typeString\": \"uint256[] memory\"\n                                    }\n                                  },\n                                  \"id\": 4695,\n                                  \"indexExpression\": {\n                                    \"argumentTypes\": null,\n                                    \"id\": 4694,\n                                    \"name\": \"i\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 4664,\n                                    \"src\": \"19456:1:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    }\n                                  },\n                                  \"isConstant\": false,\n                                  \"isLValue\": true,\n                                  \"isPure\": false,\n                                  \"lValueRequested\": true,\n                                  \"nodeType\": \"IndexAccess\",\n                                  \"src\": \"19439:19:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_uint256\",\n                                    \"typeString\": \"uint256\"\n                                  }\n                                },\n                                \"nodeType\": \"Assignment\",\n                                \"operator\": \"=\",\n                                \"rightHandSide\": {\n                                  \"argumentTypes\": null,\n                                  \"expression\": {\n                                    \"argumentTypes\": null,\n                                    \"id\": 4696,\n                                    \"name\": \"a\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 4682,\n                                    \"src\": \"19461:1:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                                      \"typeString\": \"struct AssetLib.Asset storage pointer\"\n                                    }\n                                  },\n                                  \"id\": 4697,\n                                  \"isConstant\": false,\n                                  \"isLValue\": true,\n                                  \"isPure\": false,\n                                  \"lValueRequested\": false,\n                                  \"memberName\": \"compoundInterest\",\n                                  \"nodeType\": \"MemberAccess\",\n                                  \"referencedDeclaration\": 2787,\n                                  \"src\": \"19461:18:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_uint256\",\n                                    \"typeString\": \"uint256\"\n                                  }\n                                },\n                                \"src\": \"19439:40:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              },\n                              \"id\": 4699,\n                              \"nodeType\": \"ExpressionStatement\",\n                              \"src\": \"19439:40:6\"\n                            },\n                            {\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"id\": 4705,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": false,\n                                \"lValueRequested\": false,\n                                \"leftHandSide\": {\n                                  \"argumentTypes\": null,\n                                  \"baseExpression\": {\n                                    \"argumentTypes\": null,\n                                    \"id\": 4700,\n                                    \"name\": \"liquidSinceBlock\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 4620,\n                                    \"src\": \"19497:16:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_array$_t_uint256_$dyn_memory_ptr\",\n                                      \"typeString\": \"uint256[] memory\"\n                                    }\n                                  },\n                                  \"id\": 4702,\n                                  \"indexExpression\": {\n                                    \"argumentTypes\": null,\n                                    \"id\": 4701,\n                                    \"name\": \"i\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 4664,\n                                    \"src\": \"19514:1:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    }\n                                  },\n                                  \"isConstant\": false,\n                                  \"isLValue\": true,\n                                  \"isPure\": false,\n                                  \"lValueRequested\": true,\n                                  \"nodeType\": \"IndexAccess\",\n                                  \"src\": \"19497:19:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_uint256\",\n                                    \"typeString\": \"uint256\"\n                                  }\n                                },\n                                \"nodeType\": \"Assignment\",\n                                \"operator\": \"=\",\n                                \"rightHandSide\": {\n                                  \"argumentTypes\": null,\n                                  \"expression\": {\n                                    \"argumentTypes\": null,\n                                    \"id\": 4703,\n                                    \"name\": \"la\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 4674,\n                                    \"src\": \"19519:2:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_struct$_LockedAsset_$3653_storage_ptr\",\n                                      \"typeString\": \"struct Staking.LockedAsset storage pointer\"\n                                    }\n                                  },\n                                  \"id\": 4704,\n                                  \"isConstant\": false,\n                                  \"isLValue\": true,\n                                  \"isPure\": false,\n                                  \"lValueRequested\": false,\n                                  \"memberName\": \"liquidSinceBlock\",\n                                  \"nodeType\": \"MemberAccess\",\n                                  \"referencedDeclaration\": 3650,\n                                  \"src\": \"19519:19:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_uint256\",\n                                    \"typeString\": \"uint256\"\n                                  }\n                                },\n                                \"src\": \"19497:41:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              },\n                              \"id\": 4706,\n                              \"nodeType\": \"ExpressionStatement\",\n                              \"src\": \"19497:41:6\"\n                            }\n                          ]\n                        },\n                        \"condition\": {\n                          \"argumentTypes\": null,\n                          \"commonType\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          },\n                          \"id\": 4669,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"leftExpression\": {\n                            \"argumentTypes\": null,\n                            \"id\": 4667,\n                            \"name\": \"i\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 4664,\n                            \"src\": \"19249:1:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"nodeType\": \"BinaryOperation\",\n                          \"operator\": \"<\",\n                          \"rightExpression\": {\n                            \"argumentTypes\": null,\n                            \"id\": 4668,\n                            \"name\": \"length\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 4632,\n                            \"src\": \"19253:6:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"src\": \"19249:10:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_bool\",\n                            \"typeString\": \"bool\"\n                          }\n                        },\n                        \"id\": 4708,\n                        \"initializationExpression\": {\n                          \"assignments\": [\n                            4664\n                          ],\n                          \"declarations\": [\n                            {\n                              \"constant\": false,\n                              \"id\": 4664,\n                              \"mutability\": \"mutable\",\n                              \"name\": \"i\",\n                              \"nodeType\": \"VariableDeclaration\",\n                              \"overrides\": null,\n                              \"scope\": 4708,\n                              \"src\": \"19236:9:6\",\n                              \"stateVariable\": false,\n                              \"storageLocation\": \"default\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_uint256\",\n                                \"typeString\": \"uint256\"\n                              },\n                              \"typeName\": {\n                                \"id\": 4663,\n                                \"name\": \"uint256\",\n                                \"nodeType\": \"ElementaryTypeName\",\n                                \"src\": \"19236:7:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              },\n                              \"value\": null,\n                              \"visibility\": \"internal\"\n                            }\n                          ],\n                          \"id\": 4666,\n                          \"initialValue\": {\n                            \"argumentTypes\": null,\n                            \"hexValue\": \"30\",\n                            \"id\": 4665,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": true,\n                            \"kind\": \"number\",\n                            \"lValueRequested\": false,\n                            \"nodeType\": \"Literal\",\n                            \"src\": \"19246:1:6\",\n                            \"subdenomination\": null,\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_rational_0_by_1\",\n                              \"typeString\": \"int_const 0\"\n                            },\n                            \"value\": \"0\"\n                          },\n                          \"nodeType\": \"VariableDeclarationStatement\",\n                          \"src\": \"19236:11:6\"\n                        },\n                        \"loopExpression\": {\n                          \"expression\": {\n                            \"argumentTypes\": null,\n                            \"id\": 4671,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": false,\n                            \"lValueRequested\": false,\n                            \"nodeType\": \"UnaryOperation\",\n                            \"operator\": \"++\",\n                            \"prefix\": true,\n                            \"src\": \"19261:3:6\",\n                            \"subExpression\": {\n                              \"argumentTypes\": null,\n                              \"id\": 4670,\n                              \"name\": \"i\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 4664,\n                              \"src\": \"19263:1:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_uint256\",\n                                \"typeString\": \"uint256\"\n                              }\n                            },\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"id\": 4672,\n                          \"nodeType\": \"ExpressionStatement\",\n                          \"src\": \"19261:3:6\"\n                        },\n                        \"nodeType\": \"ForStatement\",\n                        \"src\": \"19231:322:6\"\n                      }\n                    ]\n                  }\n                }\n              ]\n            },\n            \"documentation\": {\n              \"id\": 4608,\n              \"nodeType\": \"StructuredDocumentation\",\n              \"src\": \"18492:226:6\",\n              \"text\": \"@dev Returns locked assets decomposed in to 3 separate arrays (principal, compound interest, liquid since block)\\n     NOTE(pb): This method might be quite expensive, depending on size of locked assets\"\n            },\n            \"functionSelector\": \"5f208f34\",\n            \"id\": 4712,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [],\n            \"name\": \"getLockedAssetsForUser\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 4611,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 4610,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"forAddress\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4712,\n                  \"src\": \"18755:18:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_address\",\n                    \"typeString\": \"address\"\n                  },\n                  \"typeName\": {\n                    \"id\": 4609,\n                    \"name\": \"address\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"18755:7:6\",\n                    \"stateMutability\": \"nonpayable\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address\",\n                      \"typeString\": \"address\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"18754:20:6\"\n            },\n            \"returnParameters\": {\n              \"id\": 4621,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 4614,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"principal\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4712,\n                  \"src\": \"18813:26:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"memory\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_array$_t_uint256_$dyn_memory_ptr\",\n                    \"typeString\": \"uint256[]\"\n                  },\n                  \"typeName\": {\n                    \"baseType\": {\n                      \"id\": 4612,\n                      \"name\": \"uint256\",\n                      \"nodeType\": \"ElementaryTypeName\",\n                      \"src\": \"18813:7:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"id\": 4613,\n                    \"length\": null,\n                    \"nodeType\": \"ArrayTypeName\",\n                    \"src\": \"18813:9:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_array$_t_uint256_$dyn_storage_ptr\",\n                      \"typeString\": \"uint256[]\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 4617,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"compoundInterest\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4712,\n                  \"src\": \"18841:33:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"memory\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_array$_t_uint256_$dyn_memory_ptr\",\n                    \"typeString\": \"uint256[]\"\n                  },\n                  \"typeName\": {\n                    \"baseType\": {\n                      \"id\": 4615,\n                      \"name\": \"uint256\",\n                      \"nodeType\": \"ElementaryTypeName\",\n                      \"src\": \"18841:7:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"id\": 4616,\n                    \"length\": null,\n                    \"nodeType\": \"ArrayTypeName\",\n                    \"src\": \"18841:9:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_array$_t_uint256_$dyn_storage_ptr\",\n                      \"typeString\": \"uint256[]\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 4620,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"liquidSinceBlock\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4712,\n                  \"src\": \"18876:33:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"memory\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_array$_t_uint256_$dyn_memory_ptr\",\n                    \"typeString\": \"uint256[]\"\n                  },\n                  \"typeName\": {\n                    \"baseType\": {\n                      \"id\": 4618,\n                      \"name\": \"uint256\",\n                      \"nodeType\": \"ElementaryTypeName\",\n                      \"src\": \"18876:7:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"id\": 4619,\n                    \"length\": null,\n                    \"nodeType\": \"ArrayTypeName\",\n                    \"src\": \"18876:9:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_array$_t_uint256_$dyn_storage_ptr\",\n                      \"typeString\": \"uint256[]\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"18812:98:6\"\n            },\n            \"scope\": 5490,\n            \"src\": \"18723:846:6\",\n            \"stateMutability\": \"view\",\n            \"virtual\": false,\n            \"visibility\": \"external\"\n          },\n          {\n            \"body\": {\n              \"id\": 4753,\n              \"nodeType\": \"Block\",\n              \"src\": \"19740:260:6\",\n              \"statements\": [\n                {\n                  \"assignments\": [\n                    4726\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 4726,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"stake\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 4753,\n                      \"src\": \"19750:19:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"storage\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_struct$_Stake_$3648_storage_ptr\",\n                        \"typeString\": \"struct Staking.Stake\"\n                      },\n                      \"typeName\": {\n                        \"contractScope\": null,\n                        \"id\": 4725,\n                        \"name\": \"Stake\",\n                        \"nodeType\": \"UserDefinedTypeName\",\n                        \"referencedDeclaration\": 3648,\n                        \"src\": \"19750:5:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Stake_$3648_storage_ptr\",\n                          \"typeString\": \"struct Staking.Stake\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 4730,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"baseExpression\": {\n                      \"argumentTypes\": null,\n                      \"id\": 4727,\n                      \"name\": \"_stakes\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 3788,\n                      \"src\": \"19772:7:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_mapping$_t_address_$_t_struct$_Stake_$3648_storage_$\",\n                        \"typeString\": \"mapping(address => struct Staking.Stake storage ref)\"\n                      }\n                    },\n                    \"id\": 4729,\n                    \"indexExpression\": {\n                      \"argumentTypes\": null,\n                      \"id\": 4728,\n                      \"name\": \"forAddress\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 4714,\n                      \"src\": \"19780:10:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_address\",\n                        \"typeString\": \"address\"\n                      }\n                    },\n                    \"isConstant\": false,\n                    \"isLValue\": true,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"nodeType\": \"IndexAccess\",\n                    \"src\": \"19772:19:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_struct$_Stake_$3648_storage\",\n                      \"typeString\": \"struct Staking.Stake storage ref\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"19750:41:6\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 4735,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 4731,\n                      \"name\": \"principal\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 4717,\n                      \"src\": \"19801:9:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 4732,\n                          \"name\": \"stake\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 4726,\n                          \"src\": \"19813:5:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_struct$_Stake_$3648_storage_ptr\",\n                            \"typeString\": \"struct Staking.Stake storage pointer\"\n                          }\n                        },\n                        \"id\": 4733,\n                        \"isConstant\": false,\n                        \"isLValue\": true,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"memberName\": \"asset\",\n                        \"nodeType\": \"MemberAccess\",\n                        \"referencedDeclaration\": 3647,\n                        \"src\": \"19813:11:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                          \"typeString\": \"struct AssetLib.Asset storage ref\"\n                        }\n                      },\n                      \"id\": 4734,\n                      \"isConstant\": false,\n                      \"isLValue\": true,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"memberName\": \"principal\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": 2785,\n                      \"src\": \"19813:21:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"src\": \"19801:33:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"id\": 4736,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"19801:33:6\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 4741,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 4737,\n                      \"name\": \"compoundInterest\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 4719,\n                      \"src\": \"19844:16:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 4738,\n                          \"name\": \"stake\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 4726,\n                          \"src\": \"19863:5:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_struct$_Stake_$3648_storage_ptr\",\n                            \"typeString\": \"struct Staking.Stake storage pointer\"\n                          }\n                        },\n                        \"id\": 4739,\n                        \"isConstant\": false,\n                        \"isLValue\": true,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"memberName\": \"asset\",\n                        \"nodeType\": \"MemberAccess\",\n                        \"referencedDeclaration\": 3647,\n                        \"src\": \"19863:11:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                          \"typeString\": \"struct AssetLib.Asset storage ref\"\n                        }\n                      },\n                      \"id\": 4740,\n                      \"isConstant\": false,\n                      \"isLValue\": true,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"memberName\": \"compoundInterest\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": 2787,\n                      \"src\": \"19863:28:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"src\": \"19844:47:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"id\": 4742,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"19844:47:6\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 4746,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 4743,\n                      \"name\": \"sinceBlock\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 4721,\n                      \"src\": \"19901:10:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 4744,\n                        \"name\": \"stake\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4726,\n                        \"src\": \"19914:5:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Stake_$3648_storage_ptr\",\n                          \"typeString\": \"struct Staking.Stake storage pointer\"\n                        }\n                      },\n                      \"id\": 4745,\n                      \"isConstant\": false,\n                      \"isLValue\": true,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"memberName\": \"sinceBlock\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": 3643,\n                      \"src\": \"19914:16:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"src\": \"19901:29:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"id\": 4747,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"19901:29:6\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 4751,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 4748,\n                      \"name\": \"sinceInterestRateIndex\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 4723,\n                      \"src\": \"19940:22:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 4749,\n                        \"name\": \"stake\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4726,\n                        \"src\": \"19965:5:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Stake_$3648_storage_ptr\",\n                          \"typeString\": \"struct Staking.Stake storage pointer\"\n                        }\n                      },\n                      \"id\": 4750,\n                      \"isConstant\": false,\n                      \"isLValue\": true,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"memberName\": \"sinceInterestRateIndex\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": 3645,\n                      \"src\": \"19965:28:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"src\": \"19940:53:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"id\": 4752,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"19940:53:6\"\n                }\n              ]\n            },\n            \"documentation\": null,\n            \"functionSelector\": \"c30f75cf\",\n            \"id\": 4754,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [],\n            \"name\": \"getStakeForUser\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 4715,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 4714,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"forAddress\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4754,\n                  \"src\": \"19601:18:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_address\",\n                    \"typeString\": \"address\"\n                  },\n                  \"typeName\": {\n                    \"id\": 4713,\n                    \"name\": \"address\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"19601:7:6\",\n                    \"stateMutability\": \"nonpayable\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address\",\n                      \"typeString\": \"address\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"19600:20:6\"\n            },\n            \"returnParameters\": {\n              \"id\": 4724,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 4717,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"principal\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4754,\n                  \"src\": \"19643:17:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 4716,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"19643:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 4719,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"compoundInterest\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4754,\n                  \"src\": \"19662:24:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 4718,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"19662:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 4721,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"sinceBlock\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4754,\n                  \"src\": \"19688:18:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 4720,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"19688:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 4723,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"sinceInterestRateIndex\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4754,\n                  \"src\": \"19708:30:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 4722,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"19708:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"19642:97:6\"\n            },\n            \"scope\": 5490,\n            \"src\": \"19576:424:6\",\n            \"stateMutability\": \"view\",\n            \"virtual\": false,\n            \"visibility\": \"external\"\n          },\n          {\n            \"body\": {\n              \"id\": 4798,\n              \"nodeType\": \"Block\",\n              \"src\": \"20599:276:6\",\n              \"statements\": [\n                {\n                  \"condition\": {\n                    \"argumentTypes\": null,\n                    \"commonType\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    },\n                    \"id\": 4767,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftExpression\": {\n                      \"argumentTypes\": null,\n                      \"id\": 4765,\n                      \"name\": \"amount\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 4757,\n                      \"src\": \"20613:6:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"BinaryOperation\",\n                    \"operator\": \"==\",\n                    \"rightExpression\": {\n                      \"argumentTypes\": null,\n                      \"hexValue\": \"30\",\n                      \"id\": 4766,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": true,\n                      \"kind\": \"number\",\n                      \"lValueRequested\": false,\n                      \"nodeType\": \"Literal\",\n                      \"src\": \"20623:1:6\",\n                      \"subdenomination\": null,\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_rational_0_by_1\",\n                        \"typeString\": \"int_const 0\"\n                      },\n                      \"value\": \"0\"\n                    },\n                    \"src\": \"20613:11:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_bool\",\n                      \"typeString\": \"bool\"\n                    }\n                  },\n                  \"falseBody\": null,\n                  \"id\": 4770,\n                  \"nodeType\": \"IfStatement\",\n                  \"src\": \"20609:48:6\",\n                  \"trueBody\": {\n                    \"id\": 4769,\n                    \"nodeType\": \"Block\",\n                    \"src\": \"20626:31:6\",\n                    \"statements\": [\n                      {\n                        \"expression\": null,\n                        \"functionReturnParameters\": 4764,\n                        \"id\": 4768,\n                        \"nodeType\": \"Return\",\n                        \"src\": \"20640:7:6\"\n                      }\n                    ]\n                  }\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"arguments\": [\n                          {\n                            \"argumentTypes\": null,\n                            \"expression\": {\n                              \"argumentTypes\": null,\n                              \"id\": 4774,\n                              \"name\": \"msg\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": -15,\n                              \"src\": \"20695:3:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_magic_message\",\n                                \"typeString\": \"msg\"\n                              }\n                            },\n                            \"id\": 4775,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": false,\n                            \"lValueRequested\": false,\n                            \"memberName\": \"sender\",\n                            \"nodeType\": \"MemberAccess\",\n                            \"referencedDeclaration\": null,\n                            \"src\": \"20695:10:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_address_payable\",\n                              \"typeString\": \"address payable\"\n                            }\n                          },\n                          {\n                            \"argumentTypes\": null,\n                            \"arguments\": [\n                              {\n                                \"argumentTypes\": null,\n                                \"id\": 4778,\n                                \"name\": \"this\",\n                                \"nodeType\": \"Identifier\",\n                                \"overloadedDeclarations\": [],\n                                \"referencedDeclaration\": -28,\n                                \"src\": \"20715:4:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_contract$_Staking_$5490\",\n                                  \"typeString\": \"contract Staking\"\n                                }\n                              }\n                            ],\n                            \"expression\": {\n                              \"argumentTypes\": [\n                                {\n                                  \"typeIdentifier\": \"t_contract$_Staking_$5490\",\n                                  \"typeString\": \"contract Staking\"\n                                }\n                              ],\n                              \"id\": 4777,\n                              \"isConstant\": false,\n                              \"isLValue\": false,\n                              \"isPure\": true,\n                              \"lValueRequested\": false,\n                              \"nodeType\": \"ElementaryTypeNameExpression\",\n                              \"src\": \"20707:7:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_type$_t_address_$\",\n                                \"typeString\": \"type(address)\"\n                              },\n                              \"typeName\": {\n                                \"id\": 4776,\n                                \"name\": \"address\",\n                                \"nodeType\": \"ElementaryTypeName\",\n                                \"src\": \"20707:7:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": null,\n                                  \"typeString\": null\n                                }\n                              }\n                            },\n                            \"id\": 4779,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": false,\n                            \"kind\": \"typeConversion\",\n                            \"lValueRequested\": false,\n                            \"names\": [],\n                            \"nodeType\": \"FunctionCall\",\n                            \"src\": \"20707:13:6\",\n                            \"tryCall\": false,\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_address\",\n                              \"typeString\": \"address\"\n                            }\n                          },\n                          {\n                            \"argumentTypes\": null,\n                            \"id\": 4780,\n                            \"name\": \"amount\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 4757,\n                            \"src\": \"20722:6:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          }\n                        ],\n                        \"expression\": {\n                          \"argumentTypes\": [\n                            {\n                              \"typeIdentifier\": \"t_address_payable\",\n                              \"typeString\": \"address payable\"\n                            },\n                            {\n                              \"typeIdentifier\": \"t_address\",\n                              \"typeString\": \"address\"\n                            },\n                            {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          ],\n                          \"expression\": {\n                            \"argumentTypes\": null,\n                            \"id\": 4772,\n                            \"name\": \"_token\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 3762,\n                            \"src\": \"20675:6:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_contract$_IERC20_$6707\",\n                              \"typeString\": \"contract IERC20\"\n                            }\n                          },\n                          \"id\": 4773,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"memberName\": \"transferFrom\",\n                          \"nodeType\": \"MemberAccess\",\n                          \"referencedDeclaration\": 6688,\n                          \"src\": \"20675:19:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_function_external_nonpayable$_t_address_$_t_address_$_t_uint256_$returns$_t_bool_$\",\n                            \"typeString\": \"function (address,address,uint256) external returns (bool)\"\n                          }\n                        },\n                        \"id\": 4781,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"kind\": \"functionCall\",\n                        \"lValueRequested\": false,\n                        \"names\": [],\n                        \"nodeType\": \"FunctionCall\",\n                        \"src\": \"20675:54:6\",\n                        \"tryCall\": false,\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"hexValue\": \"5472616e73666572206661696c6564\",\n                        \"id\": 4782,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": true,\n                        \"kind\": \"string\",\n                        \"lValueRequested\": false,\n                        \"nodeType\": \"Literal\",\n                        \"src\": \"20731:17:6\",\n                        \"subdenomination\": null,\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_stringliteral_25adaa6d082ce15f901e0d8a3d393e7462ef9edf2e6bc8321fa14d1615b6fc51\",\n                          \"typeString\": \"literal_string \\\"Transfer failed\\\"\"\n                        },\n                        \"value\": \"Transfer failed\"\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_stringliteral_25adaa6d082ce15f901e0d8a3d393e7462ef9edf2e6bc8321fa14d1615b6fc51\",\n                          \"typeString\": \"literal_string \\\"Transfer failed\\\"\"\n                        }\n                      ],\n                      \"id\": 4771,\n                      \"name\": \"require\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [\n                        -18,\n                        -18\n                      ],\n                      \"referencedDeclaration\": -18,\n                      \"src\": \"20667:7:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$\",\n                        \"typeString\": \"function (bool,string memory) pure\"\n                      }\n                    },\n                    \"id\": 4783,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"20667:82:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 4784,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"20667:82:6\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 4790,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 4785,\n                      \"name\": \"_rewardsPoolBalance\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 3770,\n                      \"src\": \"20759:19:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"arguments\": [\n                        {\n                          \"argumentTypes\": null,\n                          \"id\": 4788,\n                          \"name\": \"amount\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 4757,\n                          \"src\": \"20805:6:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        }\n                      ],\n                      \"expression\": {\n                        \"argumentTypes\": [\n                          {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        ],\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 4786,\n                          \"name\": \"_rewardsPoolBalance\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 3770,\n                          \"src\": \"20781:19:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"id\": 4787,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"memberName\": \"add\",\n                        \"nodeType\": \"MemberAccess\",\n                        \"referencedDeclaration\": 5870,\n                        \"src\": \"20781:23:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_function_internal_pure$_t_uint256_$_t_uint256_$returns$_t_uint256_$bound_to$_t_uint256_$\",\n                          \"typeString\": \"function (uint256,uint256) pure returns (uint256)\"\n                        }\n                      },\n                      \"id\": 4789,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": false,\n                      \"kind\": \"functionCall\",\n                      \"lValueRequested\": false,\n                      \"names\": [],\n                      \"nodeType\": \"FunctionCall\",\n                      \"src\": \"20781:31:6\",\n                      \"tryCall\": false,\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"src\": \"20759:53:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"id\": 4791,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"20759:53:6\"\n                },\n                {\n                  \"eventCall\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 4793,\n                          \"name\": \"msg\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": -15,\n                          \"src\": \"20849:3:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_magic_message\",\n                            \"typeString\": \"msg\"\n                          }\n                        },\n                        \"id\": 4794,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"memberName\": \"sender\",\n                        \"nodeType\": \"MemberAccess\",\n                        \"referencedDeclaration\": null,\n                        \"src\": \"20849:10:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 4795,\n                        \"name\": \"amount\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4757,\n                        \"src\": \"20861:6:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"id\": 4792,\n                      \"name\": \"RewardsPoolTokenTopUp\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 3744,\n                      \"src\": \"20827:21:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_event_nonpayable$_t_address_$_t_uint256_$returns$__$\",\n                        \"typeString\": \"function (address,uint256)\"\n                      }\n                    },\n                    \"id\": 4796,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"20827:41:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 4797,\n                  \"nodeType\": \"EmitStatement\",\n                  \"src\": \"20822:46:6\"\n                }\n              ]\n            },\n            \"documentation\": {\n              \"id\": 4755,\n              \"nodeType\": \"StructuredDocumentation\",\n              \"src\": \"20007:425:6\",\n              \"text\": \"@dev Even though this is considered as administrative action (is not affected by\\nby contract paused state, it can be executed by anyone who wishes to\\ntop-up the rewards pool (funds are sent in to contract, *not* the other way around).\\nThe Rewards Pool is exclusively dedicated to cover withdrawals of user' compound interest,\\nwhich is effectively the reward.\"\n            },\n            \"functionSelector\": \"ba92a4c5\",\n            \"id\": 4799,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [\n              {\n                \"arguments\": [\n                  {\n                    \"argumentTypes\": null,\n                    \"id\": 4762,\n                    \"name\": \"txExpirationBlock\",\n                    \"nodeType\": \"Identifier\",\n                    \"overloadedDeclarations\": [],\n                    \"referencedDeclaration\": 4759,\n                    \"src\": \"20576:17:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  }\n                ],\n                \"id\": 4763,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 4761,\n                  \"name\": \"verifyTxExpiration\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 3836,\n                  \"src\": \"20557:18:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$_t_uint256_$\",\n                    \"typeString\": \"modifier (uint256)\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"20557:37:6\"\n              }\n            ],\n            \"name\": \"topUpRewardsPool\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 4760,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 4757,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"amount\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4799,\n                  \"src\": \"20472:14:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 4756,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"20472:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 4759,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"txExpirationBlock\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4799,\n                  \"src\": \"20496:25:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 4758,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"20496:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"20462:69:6\"\n            },\n            \"returnParameters\": {\n              \"id\": 4764,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"20599:0:6\"\n            },\n            \"scope\": 5490,\n            \"src\": \"20437:438:6\",\n            \"stateMutability\": \"nonpayable\",\n            \"virtual\": false,\n            \"visibility\": \"external\"\n          },\n          {\n            \"body\": {\n              \"id\": 4816,\n              \"nodeType\": \"Block\",\n              \"src\": \"21179:47:6\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 4813,\n                        \"name\": \"numOfBlocks\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4802,\n                        \"src\": \"21207:11:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint64\",\n                          \"typeString\": \"uint64\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_uint64\",\n                          \"typeString\": \"uint64\"\n                        }\n                      ],\n                      \"id\": 4812,\n                      \"name\": \"_updateLockPeriod\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5079,\n                      \"src\": \"21189:17:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_nonpayable$_t_uint64_$returns$__$\",\n                        \"typeString\": \"function (uint64)\"\n                      }\n                    },\n                    \"id\": 4814,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"21189:30:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 4815,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"21189:30:6\"\n                }\n              ]\n            },\n            \"documentation\": {\n              \"id\": 4800,\n              \"nodeType\": \"StructuredDocumentation\",\n              \"src\": \"20882:131:6\",\n              \"text\": \"@notice Updates Lock Period value\\n@param numOfBlocks  length of the lock period\\n@dev Delegate only\"\n            },\n            \"functionSelector\": \"f0895e52\",\n            \"id\": 4817,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [\n              {\n                \"arguments\": [\n                  {\n                    \"argumentTypes\": null,\n                    \"id\": 4807,\n                    \"name\": \"txExpirationBlock\",\n                    \"nodeType\": \"Identifier\",\n                    \"overloadedDeclarations\": [],\n                    \"referencedDeclaration\": 4804,\n                    \"src\": \"21135:17:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  }\n                ],\n                \"id\": 4808,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 4806,\n                  \"name\": \"verifyTxExpiration\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 3836,\n                  \"src\": \"21116:18:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$_t_uint256_$\",\n                    \"typeString\": \"modifier (uint256)\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"21116:37:6\"\n              },\n              {\n                \"arguments\": null,\n                \"id\": 4810,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 4809,\n                  \"name\": \"onlyDelegate\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 3822,\n                  \"src\": \"21162:12:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$__$\",\n                    \"typeString\": \"modifier ()\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"21162:12:6\"\n              }\n            ],\n            \"name\": \"updateLockPeriod\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 4805,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 4802,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"numOfBlocks\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4817,\n                  \"src\": \"21044:18:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint64\",\n                    \"typeString\": \"uint64\"\n                  },\n                  \"typeName\": {\n                    \"id\": 4801,\n                    \"name\": \"uint64\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"21044:6:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint64\",\n                      \"typeString\": \"uint64\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 4804,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"txExpirationBlock\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4817,\n                  \"src\": \"21064:25:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 4803,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"21064:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"21043:47:6\"\n            },\n            \"returnParameters\": {\n              \"id\": 4811,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"21179:0:6\"\n            },\n            \"scope\": 5490,\n            \"src\": \"21018:208:6\",\n            \"stateMutability\": \"nonpayable\",\n            \"virtual\": false,\n            \"visibility\": \"external\"\n          },\n          {\n            \"body\": {\n              \"id\": 4834,\n              \"nodeType\": \"Block\",\n              \"src\": \"21671:41:6\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 4831,\n                        \"name\": \"blockNumber\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4820,\n                        \"src\": \"21693:11:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"id\": 4830,\n                      \"name\": \"_pauseSince\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5104,\n                      \"src\": \"21681:11:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_nonpayable$_t_uint256_$returns$__$\",\n                        \"typeString\": \"function (uint256)\"\n                      }\n                    },\n                    \"id\": 4832,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"21681:24:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 4833,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"21681:24:6\"\n                }\n              ]\n            },\n            \"documentation\": {\n              \"id\": 4818,\n              \"nodeType\": \"StructuredDocumentation\",\n              \"src\": \"21233:277:6\",\n              \"text\": \"@notice Pauses all NON-administrative interaction with the contract since the specidfed block number \\n@param blockNumber block number since which non-admin interaction will be paused (for all _getBlockNumber() >= blockNumber)\\n@dev Delegate only\"\n            },\n            \"functionSelector\": \"347908df\",\n            \"id\": 4835,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [\n              {\n                \"arguments\": [\n                  {\n                    \"argumentTypes\": null,\n                    \"id\": 4825,\n                    \"name\": \"txExpirationBlock\",\n                    \"nodeType\": \"Identifier\",\n                    \"overloadedDeclarations\": [],\n                    \"referencedDeclaration\": 4822,\n                    \"src\": \"21627:17:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  }\n                ],\n                \"id\": 4826,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 4824,\n                  \"name\": \"verifyTxExpiration\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 3836,\n                  \"src\": \"21608:18:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$_t_uint256_$\",\n                    \"typeString\": \"modifier (uint256)\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"21608:37:6\"\n              },\n              {\n                \"arguments\": null,\n                \"id\": 4828,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 4827,\n                  \"name\": \"onlyDelegate\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 3822,\n                  \"src\": \"21654:12:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$__$\",\n                    \"typeString\": \"modifier ()\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"21654:12:6\"\n              }\n            ],\n            \"name\": \"pauseSince\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 4823,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 4820,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"blockNumber\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4835,\n                  \"src\": \"21535:19:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 4819,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"21535:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 4822,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"txExpirationBlock\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4835,\n                  \"src\": \"21556:25:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 4821,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"21556:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"21534:48:6\"\n            },\n            \"returnParameters\": {\n              \"id\": 4829,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"21671:0:6\"\n            },\n            \"scope\": 5490,\n            \"src\": \"21515:197:6\",\n            \"stateMutability\": \"nonpayable\",\n            \"virtual\": false,\n            \"visibility\": \"external\"\n          },\n          {\n            \"body\": {\n              \"id\": 4909,\n              \"nodeType\": \"Block\",\n              \"src\": \"22190:911:6\",\n              \"statements\": [\n                {\n                  \"condition\": {\n                    \"argumentTypes\": null,\n                    \"commonType\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    },\n                    \"id\": 4852,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftExpression\": {\n                      \"argumentTypes\": null,\n                      \"id\": 4850,\n                      \"name\": \"amount\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 4838,\n                      \"src\": \"22204:6:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"BinaryOperation\",\n                    \"operator\": \"==\",\n                    \"rightExpression\": {\n                      \"argumentTypes\": null,\n                      \"hexValue\": \"30\",\n                      \"id\": 4851,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": true,\n                      \"kind\": \"number\",\n                      \"lValueRequested\": false,\n                      \"nodeType\": \"Literal\",\n                      \"src\": \"22214:1:6\",\n                      \"subdenomination\": null,\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_rational_0_by_1\",\n                        \"typeString\": \"int_const 0\"\n                      },\n                      \"value\": \"0\"\n                    },\n                    \"src\": \"22204:11:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_bool\",\n                      \"typeString\": \"bool\"\n                    }\n                  },\n                  \"falseBody\": {\n                    \"id\": 4865,\n                    \"nodeType\": \"Block\",\n                    \"src\": \"22276:98:6\",\n                    \"statements\": [\n                      {\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"arguments\": [\n                            {\n                              \"argumentTypes\": null,\n                              \"commonType\": {\n                                \"typeIdentifier\": \"t_uint256\",\n                                \"typeString\": \"uint256\"\n                              },\n                              \"id\": 4861,\n                              \"isConstant\": false,\n                              \"isLValue\": false,\n                              \"isPure\": false,\n                              \"lValueRequested\": false,\n                              \"leftExpression\": {\n                                \"argumentTypes\": null,\n                                \"id\": 4859,\n                                \"name\": \"amount\",\n                                \"nodeType\": \"Identifier\",\n                                \"overloadedDeclarations\": [],\n                                \"referencedDeclaration\": 4838,\n                                \"src\": \"22298:6:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              },\n                              \"nodeType\": \"BinaryOperation\",\n                              \"operator\": \"<=\",\n                              \"rightExpression\": {\n                                \"argumentTypes\": null,\n                                \"id\": 4860,\n                                \"name\": \"_rewardsPoolBalance\",\n                                \"nodeType\": \"Identifier\",\n                                \"overloadedDeclarations\": [],\n                                \"referencedDeclaration\": 3770,\n                                \"src\": \"22308:19:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              },\n                              \"src\": \"22298:29:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_bool\",\n                                \"typeString\": \"bool\"\n                              }\n                            },\n                            {\n                              \"argumentTypes\": null,\n                              \"hexValue\": \"416d6f756e7420686967686572207468616e207265776172647320706f6f6c\",\n                              \"id\": 4862,\n                              \"isConstant\": false,\n                              \"isLValue\": false,\n                              \"isPure\": true,\n                              \"kind\": \"string\",\n                              \"lValueRequested\": false,\n                              \"nodeType\": \"Literal\",\n                              \"src\": \"22329:33:6\",\n                              \"subdenomination\": null,\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_stringliteral_587ce66cc8dcf85ee5804e9c2a7ad26da4041f2a6217e351e0d49635c54a34e6\",\n                                \"typeString\": \"literal_string \\\"Amount higher than rewards pool\\\"\"\n                              },\n                              \"value\": \"Amount higher than rewards pool\"\n                            }\n                          ],\n                          \"expression\": {\n                            \"argumentTypes\": [\n                              {\n                                \"typeIdentifier\": \"t_bool\",\n                                \"typeString\": \"bool\"\n                              },\n                              {\n                                \"typeIdentifier\": \"t_stringliteral_587ce66cc8dcf85ee5804e9c2a7ad26da4041f2a6217e351e0d49635c54a34e6\",\n                                \"typeString\": \"literal_string \\\"Amount higher than rewards pool\\\"\"\n                              }\n                            ],\n                            \"id\": 4858,\n                            \"name\": \"require\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [\n                              -18,\n                              -18\n                            ],\n                            \"referencedDeclaration\": -18,\n                            \"src\": \"22290:7:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$\",\n                              \"typeString\": \"function (bool,string memory) pure\"\n                            }\n                          },\n                          \"id\": 4863,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"kind\": \"functionCall\",\n                          \"lValueRequested\": false,\n                          \"names\": [],\n                          \"nodeType\": \"FunctionCall\",\n                          \"src\": \"22290:73:6\",\n                          \"tryCall\": false,\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_tuple$__$\",\n                            \"typeString\": \"tuple()\"\n                          }\n                        },\n                        \"id\": 4864,\n                        \"nodeType\": \"ExpressionStatement\",\n                        \"src\": \"22290:73:6\"\n                      }\n                    ]\n                  },\n                  \"id\": 4866,\n                  \"nodeType\": \"IfStatement\",\n                  \"src\": \"22200:174:6\",\n                  \"trueBody\": {\n                    \"id\": 4857,\n                    \"nodeType\": \"Block\",\n                    \"src\": \"22217:53:6\",\n                    \"statements\": [\n                      {\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 4855,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"leftHandSide\": {\n                            \"argumentTypes\": null,\n                            \"id\": 4853,\n                            \"name\": \"amount\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 4838,\n                            \"src\": \"22231:6:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"nodeType\": \"Assignment\",\n                          \"operator\": \"=\",\n                          \"rightHandSide\": {\n                            \"argumentTypes\": null,\n                            \"id\": 4854,\n                            \"name\": \"_rewardsPoolBalance\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 3770,\n                            \"src\": \"22240:19:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"src\": \"22231:28:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"id\": 4856,\n                        \"nodeType\": \"ExpressionStatement\",\n                        \"src\": \"22231:28:6\"\n                      }\n                    ]\n                  }\n                },\n                {\n                  \"assignments\": [\n                    4868\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 4868,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"contractBalance\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 4909,\n                      \"src\": \"22562:23:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"default\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      },\n                      \"typeName\": {\n                        \"id\": 4867,\n                        \"name\": \"uint256\",\n                        \"nodeType\": \"ElementaryTypeName\",\n                        \"src\": \"22562:7:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 4876,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"arguments\": [\n                          {\n                            \"argumentTypes\": null,\n                            \"id\": 4873,\n                            \"name\": \"this\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": -28,\n                            \"src\": \"22613:4:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_contract$_Staking_$5490\",\n                              \"typeString\": \"contract Staking\"\n                            }\n                          }\n                        ],\n                        \"expression\": {\n                          \"argumentTypes\": [\n                            {\n                              \"typeIdentifier\": \"t_contract$_Staking_$5490\",\n                              \"typeString\": \"contract Staking\"\n                            }\n                          ],\n                          \"id\": 4872,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": true,\n                          \"lValueRequested\": false,\n                          \"nodeType\": \"ElementaryTypeNameExpression\",\n                          \"src\": \"22605:7:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_type$_t_address_$\",\n                            \"typeString\": \"type(address)\"\n                          },\n                          \"typeName\": {\n                            \"id\": 4871,\n                            \"name\": \"address\",\n                            \"nodeType\": \"ElementaryTypeName\",\n                            \"src\": \"22605:7:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": null,\n                              \"typeString\": null\n                            }\n                          }\n                        },\n                        \"id\": 4874,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"kind\": \"typeConversion\",\n                        \"lValueRequested\": false,\n                        \"names\": [],\n                        \"nodeType\": \"FunctionCall\",\n                        \"src\": \"22605:13:6\",\n                        \"tryCall\": false,\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        }\n                      ],\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 4869,\n                        \"name\": \"_token\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 3762,\n                        \"src\": \"22588:6:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_contract$_IERC20_$6707\",\n                          \"typeString\": \"contract IERC20\"\n                        }\n                      },\n                      \"id\": 4870,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"memberName\": \"balanceOf\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": 6646,\n                      \"src\": \"22588:16:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_external_view$_t_address_$returns$_t_uint256_$\",\n                        \"typeString\": \"function (address) view external returns (uint256)\"\n                      }\n                    },\n                    \"id\": 4875,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"22588:31:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"22562:57:6\"\n                },\n                {\n                  \"assignments\": [\n                    4878\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 4878,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"expectedMinContractBalance\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 4909,\n                      \"src\": \"22629:34:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"default\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      },\n                      \"typeName\": {\n                        \"id\": 4877,\n                        \"name\": \"uint256\",\n                        \"nodeType\": \"ElementaryTypeName\",\n                        \"src\": \"22629:7:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 4883,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 4881,\n                        \"name\": \"amount\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4838,\n                        \"src\": \"22694:6:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 4879,\n                        \"name\": \"_accruedGlobalPrincipal\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 3772,\n                        \"src\": \"22666:23:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      \"id\": 4880,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"memberName\": \"add\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": 5870,\n                      \"src\": \"22666:27:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_pure$_t_uint256_$_t_uint256_$returns$_t_uint256_$bound_to$_t_uint256_$\",\n                        \"typeString\": \"function (uint256,uint256) pure returns (uint256)\"\n                      }\n                    },\n                    \"id\": 4882,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"22666:35:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"22629:72:6\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"commonType\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        },\n                        \"id\": 4887,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"leftExpression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 4885,\n                          \"name\": \"expectedMinContractBalance\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 4878,\n                          \"src\": \"22719:26:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"nodeType\": \"BinaryOperation\",\n                        \"operator\": \"<=\",\n                        \"rightExpression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 4886,\n                          \"name\": \"contractBalance\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 4868,\n                          \"src\": \"22749:15:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"src\": \"22719:45:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"hexValue\": \"436f6e747261637420696e636f6e73697374656e63792e\",\n                        \"id\": 4888,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": true,\n                        \"kind\": \"string\",\n                        \"lValueRequested\": false,\n                        \"nodeType\": \"Literal\",\n                        \"src\": \"22766:25:6\",\n                        \"subdenomination\": null,\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_stringliteral_391f4d8f0a702da0afb416db97e6f601a29dc7e134644564cd5e78cc8b2ef1d5\",\n                          \"typeString\": \"literal_string \\\"Contract inconsistency.\\\"\"\n                        },\n                        \"value\": \"Contract inconsistency.\"\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_stringliteral_391f4d8f0a702da0afb416db97e6f601a29dc7e134644564cd5e78cc8b2ef1d5\",\n                          \"typeString\": \"literal_string \\\"Contract inconsistency.\\\"\"\n                        }\n                      ],\n                      \"id\": 4884,\n                      \"name\": \"require\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [\n                        -18,\n                        -18\n                      ],\n                      \"referencedDeclaration\": -18,\n                      \"src\": \"22711:7:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$\",\n                        \"typeString\": \"function (bool,string memory) pure\"\n                      }\n                    },\n                    \"id\": 4889,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"22711:81:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 4890,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"22711:81:6\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"arguments\": [\n                          {\n                            \"argumentTypes\": null,\n                            \"id\": 4894,\n                            \"name\": \"targetAddress\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 4840,\n                            \"src\": \"22827:13:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_address_payable\",\n                              \"typeString\": \"address payable\"\n                            }\n                          },\n                          {\n                            \"argumentTypes\": null,\n                            \"id\": 4895,\n                            \"name\": \"amount\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 4838,\n                            \"src\": \"22842:6:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          }\n                        ],\n                        \"expression\": {\n                          \"argumentTypes\": [\n                            {\n                              \"typeIdentifier\": \"t_address_payable\",\n                              \"typeString\": \"address payable\"\n                            },\n                            {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          ],\n                          \"expression\": {\n                            \"argumentTypes\": null,\n                            \"id\": 4892,\n                            \"name\": \"_token\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 3762,\n                            \"src\": \"22811:6:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_contract$_IERC20_$6707\",\n                              \"typeString\": \"contract IERC20\"\n                            }\n                          },\n                          \"id\": 4893,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"memberName\": \"transfer\",\n                          \"nodeType\": \"MemberAccess\",\n                          \"referencedDeclaration\": 6656,\n                          \"src\": \"22811:15:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_function_external_nonpayable$_t_address_$_t_uint256_$returns$_t_bool_$\",\n                            \"typeString\": \"function (address,uint256) external returns (bool)\"\n                          }\n                        },\n                        \"id\": 4896,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"kind\": \"functionCall\",\n                        \"lValueRequested\": false,\n                        \"names\": [],\n                        \"nodeType\": \"FunctionCall\",\n                        \"src\": \"22811:38:6\",\n                        \"tryCall\": false,\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"hexValue\": \"4e6f7420656e6f7567682066756e6473206f6e20636f6e74722e20616464722e\",\n                        \"id\": 4897,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": true,\n                        \"kind\": \"string\",\n                        \"lValueRequested\": false,\n                        \"nodeType\": \"Literal\",\n                        \"src\": \"22851:34:6\",\n                        \"subdenomination\": null,\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_stringliteral_fd3fa1113e097b10bbbc2a9e78e5896bda814123efe5dcd9c1d96e852dae5f82\",\n                          \"typeString\": \"literal_string \\\"Not enough funds on contr. addr.\\\"\"\n                        },\n                        \"value\": \"Not enough funds on contr. addr.\"\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_stringliteral_fd3fa1113e097b10bbbc2a9e78e5896bda814123efe5dcd9c1d96e852dae5f82\",\n                          \"typeString\": \"literal_string \\\"Not enough funds on contr. addr.\\\"\"\n                        }\n                      ],\n                      \"id\": 4891,\n                      \"name\": \"require\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [\n                        -18,\n                        -18\n                      ],\n                      \"referencedDeclaration\": -18,\n                      \"src\": \"22803:7:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$\",\n                        \"typeString\": \"function (bool,string memory) pure\"\n                      }\n                    },\n                    \"id\": 4898,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"22803:83:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 4899,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"22803:83:6\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 4902,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 4900,\n                      \"name\": \"_rewardsPoolBalance\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 3770,\n                      \"src\": \"23000:19:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"-=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 4901,\n                      \"name\": \"amount\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 4838,\n                      \"src\": \"23023:6:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"src\": \"23000:29:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"id\": 4903,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"23000:29:6\"\n                },\n                {\n                  \"eventCall\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 4905,\n                        \"name\": \"targetAddress\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4840,\n                        \"src\": \"23072:13:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 4906,\n                        \"name\": \"amount\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4838,\n                        \"src\": \"23087:6:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"id\": 4904,\n                      \"name\": \"RewardsPoolTokenWithdrawal\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 3750,\n                      \"src\": \"23045:26:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_event_nonpayable$_t_address_$_t_uint256_$returns$__$\",\n                        \"typeString\": \"function (address,uint256)\"\n                      }\n                    },\n                    \"id\": 4907,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"23045:49:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 4908,\n                  \"nodeType\": \"EmitStatement\",\n                  \"src\": \"23040:54:6\"\n                }\n              ]\n            },\n            \"documentation\": {\n              \"id\": 4836,\n              \"nodeType\": \"StructuredDocumentation\",\n              \"src\": \"21719:257:6\",\n              \"text\": \"@dev Withdraw tokens from rewards pool.\\n     * @param amount : amount to withdraw.\\n                If `amount == 0` then whole amount in rewards pool will be withdrawn.\\n@param targetAddress : address to send tokens to\"\n            },\n            \"functionSelector\": \"68bccfcf\",\n            \"id\": 4910,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [\n              {\n                \"arguments\": [\n                  {\n                    \"argumentTypes\": null,\n                    \"id\": 4845,\n                    \"name\": \"txExpirationBlock\",\n                    \"nodeType\": \"Identifier\",\n                    \"overloadedDeclarations\": [],\n                    \"referencedDeclaration\": 4842,\n                    \"src\": \"22149:17:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  }\n                ],\n                \"id\": 4846,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 4844,\n                  \"name\": \"verifyTxExpiration\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 3836,\n                  \"src\": \"22130:18:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$_t_uint256_$\",\n                    \"typeString\": \"modifier (uint256)\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"22130:37:6\"\n              },\n              {\n                \"arguments\": null,\n                \"id\": 4848,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 4847,\n                  \"name\": \"onlyOwner\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 3806,\n                  \"src\": \"22176:9:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$__$\",\n                    \"typeString\": \"modifier ()\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"22176:9:6\"\n              }\n            ],\n            \"name\": \"withdrawFromRewardsPool\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 4843,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 4838,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"amount\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4910,\n                  \"src\": \"22014:14:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 4837,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"22014:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 4840,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"targetAddress\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4910,\n                  \"src\": \"22030:29:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_address_payable\",\n                    \"typeString\": \"address payable\"\n                  },\n                  \"typeName\": {\n                    \"id\": 4839,\n                    \"name\": \"address\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"22030:15:6\",\n                    \"stateMutability\": \"payable\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address_payable\",\n                      \"typeString\": \"address payable\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 4842,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"txExpirationBlock\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4910,\n                  \"src\": \"22069:25:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 4841,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"22069:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"22013:91:6\"\n            },\n            \"returnParameters\": {\n              \"id\": 4849,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"22190:0:6\"\n            },\n            \"scope\": 5490,\n            \"src\": \"21981:1120:6\",\n            \"stateMutability\": \"nonpayable\",\n            \"virtual\": false,\n            \"visibility\": \"external\"\n          },\n          {\n            \"body\": {\n              \"id\": 4961,\n              \"nodeType\": \"Block\",\n              \"src\": \"23907:609:6\",\n              \"statements\": [\n                {\n                  \"assignments\": [\n                    4924\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 4924,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"contractBalance\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 4961,\n                      \"src\": \"23917:23:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"default\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      },\n                      \"typeName\": {\n                        \"id\": 4923,\n                        \"name\": \"uint256\",\n                        \"nodeType\": \"ElementaryTypeName\",\n                        \"src\": \"23917:7:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 4932,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"arguments\": [\n                          {\n                            \"argumentTypes\": null,\n                            \"id\": 4929,\n                            \"name\": \"this\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": -28,\n                            \"src\": \"23968:4:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_contract$_Staking_$5490\",\n                              \"typeString\": \"contract Staking\"\n                            }\n                          }\n                        ],\n                        \"expression\": {\n                          \"argumentTypes\": [\n                            {\n                              \"typeIdentifier\": \"t_contract$_Staking_$5490\",\n                              \"typeString\": \"contract Staking\"\n                            }\n                          ],\n                          \"id\": 4928,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": true,\n                          \"lValueRequested\": false,\n                          \"nodeType\": \"ElementaryTypeNameExpression\",\n                          \"src\": \"23960:7:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_type$_t_address_$\",\n                            \"typeString\": \"type(address)\"\n                          },\n                          \"typeName\": {\n                            \"id\": 4927,\n                            \"name\": \"address\",\n                            \"nodeType\": \"ElementaryTypeName\",\n                            \"src\": \"23960:7:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": null,\n                              \"typeString\": null\n                            }\n                          }\n                        },\n                        \"id\": 4930,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"kind\": \"typeConversion\",\n                        \"lValueRequested\": false,\n                        \"names\": [],\n                        \"nodeType\": \"FunctionCall\",\n                        \"src\": \"23960:13:6\",\n                        \"tryCall\": false,\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        }\n                      ],\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 4925,\n                        \"name\": \"_token\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 3762,\n                        \"src\": \"23943:6:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_contract$_IERC20_$6707\",\n                          \"typeString\": \"contract IERC20\"\n                        }\n                      },\n                      \"id\": 4926,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"memberName\": \"balanceOf\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": 6646,\n                      \"src\": \"23943:16:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_external_view$_t_address_$returns$_t_uint256_$\",\n                        \"typeString\": \"function (address) view external returns (uint256)\"\n                      }\n                    },\n                    \"id\": 4931,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"23943:31:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"23917:57:6\"\n                },\n                {\n                  \"assignments\": [\n                    4934\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 4934,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"expectedMinContractBalance\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 4961,\n                      \"src\": \"23984:34:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"default\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      },\n                      \"typeName\": {\n                        \"id\": 4933,\n                        \"name\": \"uint256\",\n                        \"nodeType\": \"ElementaryTypeName\",\n                        \"src\": \"23984:7:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 4939,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 4937,\n                        \"name\": \"_rewardsPoolBalance\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 3770,\n                        \"src\": \"24049:19:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 4935,\n                        \"name\": \"_accruedGlobalPrincipal\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 3772,\n                        \"src\": \"24021:23:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      \"id\": 4936,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"memberName\": \"add\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": 5870,\n                      \"src\": \"24021:27:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_pure$_t_uint256_$_t_uint256_$returns$_t_uint256_$bound_to$_t_uint256_$\",\n                        \"typeString\": \"function (uint256,uint256) pure returns (uint256)\"\n                      }\n                    },\n                    \"id\": 4938,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"24021:48:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"23984:85:6\"\n                },\n                {\n                  \"assignments\": [\n                    4941\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 4941,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"excessAmount\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 4961,\n                      \"src\": \"24275:20:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"default\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      },\n                      \"typeName\": {\n                        \"id\": 4940,\n                        \"name\": \"uint256\",\n                        \"nodeType\": \"ElementaryTypeName\",\n                        \"src\": \"24275:7:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 4946,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 4944,\n                        \"name\": \"expectedMinContractBalance\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4934,\n                        \"src\": \"24318:26:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 4942,\n                        \"name\": \"contractBalance\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4924,\n                        \"src\": \"24298:15:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      \"id\": 4943,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"memberName\": \"sub\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": 5887,\n                      \"src\": \"24298:19:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_pure$_t_uint256_$_t_uint256_$returns$_t_uint256_$bound_to$_t_uint256_$\",\n                        \"typeString\": \"function (uint256,uint256) pure returns (uint256)\"\n                      }\n                    },\n                    \"id\": 4945,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"24298:47:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"24275:70:6\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"arguments\": [\n                          {\n                            \"argumentTypes\": null,\n                            \"id\": 4950,\n                            \"name\": \"targetAddress\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 4913,\n                            \"src\": \"24379:13:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_address_payable\",\n                              \"typeString\": \"address payable\"\n                            }\n                          },\n                          {\n                            \"argumentTypes\": null,\n                            \"id\": 4951,\n                            \"name\": \"excessAmount\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 4941,\n                            \"src\": \"24394:12:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          }\n                        ],\n                        \"expression\": {\n                          \"argumentTypes\": [\n                            {\n                              \"typeIdentifier\": \"t_address_payable\",\n                              \"typeString\": \"address payable\"\n                            },\n                            {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          ],\n                          \"expression\": {\n                            \"argumentTypes\": null,\n                            \"id\": 4948,\n                            \"name\": \"_token\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 3762,\n                            \"src\": \"24363:6:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_contract$_IERC20_$6707\",\n                              \"typeString\": \"contract IERC20\"\n                            }\n                          },\n                          \"id\": 4949,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"memberName\": \"transfer\",\n                          \"nodeType\": \"MemberAccess\",\n                          \"referencedDeclaration\": 6656,\n                          \"src\": \"24363:15:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_function_external_nonpayable$_t_address_$_t_uint256_$returns$_t_bool_$\",\n                            \"typeString\": \"function (address,uint256) external returns (bool)\"\n                          }\n                        },\n                        \"id\": 4952,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"kind\": \"functionCall\",\n                        \"lValueRequested\": false,\n                        \"names\": [],\n                        \"nodeType\": \"FunctionCall\",\n                        \"src\": \"24363:44:6\",\n                        \"tryCall\": false,\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"hexValue\": \"4e6f7420656e6f7567682066756e6473206f6e20636f6e74722e20616464722e\",\n                        \"id\": 4953,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": true,\n                        \"kind\": \"string\",\n                        \"lValueRequested\": false,\n                        \"nodeType\": \"Literal\",\n                        \"src\": \"24409:34:6\",\n                        \"subdenomination\": null,\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_stringliteral_fd3fa1113e097b10bbbc2a9e78e5896bda814123efe5dcd9c1d96e852dae5f82\",\n                          \"typeString\": \"literal_string \\\"Not enough funds on contr. addr.\\\"\"\n                        },\n                        \"value\": \"Not enough funds on contr. addr.\"\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_stringliteral_fd3fa1113e097b10bbbc2a9e78e5896bda814123efe5dcd9c1d96e852dae5f82\",\n                          \"typeString\": \"literal_string \\\"Not enough funds on contr. addr.\\\"\"\n                        }\n                      ],\n                      \"id\": 4947,\n                      \"name\": \"require\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [\n                        -18,\n                        -18\n                      ],\n                      \"referencedDeclaration\": -18,\n                      \"src\": \"24355:7:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$\",\n                        \"typeString\": \"function (bool,string memory) pure\"\n                      }\n                    },\n                    \"id\": 4954,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"24355:89:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 4955,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"24355:89:6\"\n                },\n                {\n                  \"eventCall\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 4957,\n                        \"name\": \"targetAddress\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4913,\n                        \"src\": \"24481:13:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 4958,\n                        \"name\": \"excessAmount\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4941,\n                        \"src\": \"24496:12:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"id\": 4956,\n                      \"name\": \"ExcessTokenWithdrawal\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 3738,\n                      \"src\": \"24459:21:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_event_nonpayable$_t_address_$_t_uint256_$returns$__$\",\n                        \"typeString\": \"function (address,uint256)\"\n                      }\n                    },\n                    \"id\": 4959,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"24459:50:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 4960,\n                  \"nodeType\": \"EmitStatement\",\n                  \"src\": \"24454:55:6\"\n                }\n              ]\n            },\n            \"documentation\": {\n              \"id\": 4911,\n              \"nodeType\": \"StructuredDocumentation\",\n              \"src\": \"23108:621:6\",\n              \"text\": \"@dev Withdraw \\\"excess\\\" tokens, which were sent to contract directly via direct ERC20.transfer(...),\\n     without interacting with API of this (Staking) contract, what could be done only by mistake.\\n     Thus this method is meant to be used primarily for rescue purposes, enabling withdrawal of such\\n     \\\"excess\\\" tokens out of contract.\\n@param targetAddress : address to send tokens to\\n@param txExpirationBlock : block number until which is the transaction valid (inclusive).\\n                           When transaction is processed after this block, it fails.\"\n            },\n            \"functionSelector\": \"53e052ac\",\n            \"id\": 4962,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [\n              {\n                \"arguments\": [\n                  {\n                    \"argumentTypes\": null,\n                    \"id\": 4918,\n                    \"name\": \"txExpirationBlock\",\n                    \"nodeType\": \"Identifier\",\n                    \"overloadedDeclarations\": [],\n                    \"referencedDeclaration\": 4915,\n                    \"src\": \"23866:17:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  }\n                ],\n                \"id\": 4919,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 4917,\n                  \"name\": \"verifyTxExpiration\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 3836,\n                  \"src\": \"23847:18:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$_t_uint256_$\",\n                    \"typeString\": \"modifier (uint256)\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"23847:37:6\"\n              },\n              {\n                \"arguments\": null,\n                \"id\": 4921,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 4920,\n                  \"name\": \"onlyOwner\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 3806,\n                  \"src\": \"23893:9:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$__$\",\n                    \"typeString\": \"modifier ()\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"23893:9:6\"\n              }\n            ],\n            \"name\": \"withdrawExcessTokens\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 4916,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 4913,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"targetAddress\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4962,\n                  \"src\": \"23764:29:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_address_payable\",\n                    \"typeString\": \"address payable\"\n                  },\n                  \"typeName\": {\n                    \"id\": 4912,\n                    \"name\": \"address\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"23764:15:6\",\n                    \"stateMutability\": \"payable\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address_payable\",\n                      \"typeString\": \"address payable\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 4915,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"txExpirationBlock\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4962,\n                  \"src\": \"23795:25:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 4914,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"23795:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"23763:58:6\"\n            },\n            \"returnParameters\": {\n              \"id\": 4922,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"23907:0:6\"\n            },\n            \"scope\": 5490,\n            \"src\": \"23734:782:6\",\n            \"stateMutability\": \"nonpayable\",\n            \"virtual\": false,\n            \"visibility\": \"external\"\n          },\n          {\n            \"body\": {\n              \"id\": 5008,\n              \"nodeType\": \"Block\",\n              \"src\": \"24995:294:6\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"commonType\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        },\n                        \"id\": 4979,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"leftExpression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 4976,\n                          \"name\": \"_earliestDelete\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 3764,\n                          \"src\": \"25013:15:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"nodeType\": \"BinaryOperation\",\n                        \"operator\": \">=\",\n                        \"rightExpression\": {\n                          \"argumentTypes\": null,\n                          \"arguments\": [],\n                          \"expression\": {\n                            \"argumentTypes\": [],\n                            \"id\": 4977,\n                            \"name\": \"_getBlockNumber\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 5019,\n                            \"src\": \"25032:15:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_function_internal_view$__$returns$_t_uint256_$\",\n                              \"typeString\": \"function () view returns (uint256)\"\n                            }\n                          },\n                          \"id\": 4978,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"kind\": \"functionCall\",\n                          \"lValueRequested\": false,\n                          \"names\": [],\n                          \"nodeType\": \"FunctionCall\",\n                          \"src\": \"25032:17:6\",\n                          \"tryCall\": false,\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"src\": \"25013:36:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"hexValue\": \"4561726c696573742064656c657465206e6f742072656163686564\",\n                        \"id\": 4980,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": true,\n                        \"kind\": \"string\",\n                        \"lValueRequested\": false,\n                        \"nodeType\": \"Literal\",\n                        \"src\": \"25051:29:6\",\n                        \"subdenomination\": null,\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_stringliteral_5f181249ab5034a5754d3db6b5f7492a28b118cbf69c6f93d3cfe542886db22a\",\n                          \"typeString\": \"literal_string \\\"Earliest delete not reached\\\"\"\n                        },\n                        \"value\": \"Earliest delete not reached\"\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_stringliteral_5f181249ab5034a5754d3db6b5f7492a28b118cbf69c6f93d3cfe542886db22a\",\n                          \"typeString\": \"literal_string \\\"Earliest delete not reached\\\"\"\n                        }\n                      ],\n                      \"id\": 4975,\n                      \"name\": \"require\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [\n                        -18,\n                        -18\n                      ],\n                      \"referencedDeclaration\": -18,\n                      \"src\": \"25005:7:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$\",\n                        \"typeString\": \"function (bool,string memory) pure\"\n                      }\n                    },\n                    \"id\": 4981,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"25005:76:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 4982,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"25005:76:6\"\n                },\n                {\n                  \"assignments\": [\n                    4984\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 4984,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"contractBalance\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 5008,\n                      \"src\": \"25091:23:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"default\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      },\n                      \"typeName\": {\n                        \"id\": 4983,\n                        \"name\": \"uint256\",\n                        \"nodeType\": \"ElementaryTypeName\",\n                        \"src\": \"25091:7:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 4992,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"arguments\": [\n                          {\n                            \"argumentTypes\": null,\n                            \"id\": 4989,\n                            \"name\": \"this\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": -28,\n                            \"src\": \"25142:4:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_contract$_Staking_$5490\",\n                              \"typeString\": \"contract Staking\"\n                            }\n                          }\n                        ],\n                        \"expression\": {\n                          \"argumentTypes\": [\n                            {\n                              \"typeIdentifier\": \"t_contract$_Staking_$5490\",\n                              \"typeString\": \"contract Staking\"\n                            }\n                          ],\n                          \"id\": 4988,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": true,\n                          \"lValueRequested\": false,\n                          \"nodeType\": \"ElementaryTypeNameExpression\",\n                          \"src\": \"25134:7:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_type$_t_address_$\",\n                            \"typeString\": \"type(address)\"\n                          },\n                          \"typeName\": {\n                            \"id\": 4987,\n                            \"name\": \"address\",\n                            \"nodeType\": \"ElementaryTypeName\",\n                            \"src\": \"25134:7:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": null,\n                              \"typeString\": null\n                            }\n                          }\n                        },\n                        \"id\": 4990,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"kind\": \"typeConversion\",\n                        \"lValueRequested\": false,\n                        \"names\": [],\n                        \"nodeType\": \"FunctionCall\",\n                        \"src\": \"25134:13:6\",\n                        \"tryCall\": false,\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        }\n                      ],\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 4985,\n                        \"name\": \"_token\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 3762,\n                        \"src\": \"25117:6:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_contract$_IERC20_$6707\",\n                          \"typeString\": \"contract IERC20\"\n                        }\n                      },\n                      \"id\": 4986,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"memberName\": \"balanceOf\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": 6646,\n                      \"src\": \"25117:16:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_external_view$_t_address_$returns$_t_uint256_$\",\n                        \"typeString\": \"function (address) view external returns (uint256)\"\n                      }\n                    },\n                    \"id\": 4991,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"25117:31:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"25091:57:6\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"arguments\": [\n                          {\n                            \"argumentTypes\": null,\n                            \"id\": 4996,\n                            \"name\": \"payoutAddress\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 4965,\n                            \"src\": \"25182:13:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_address_payable\",\n                              \"typeString\": \"address payable\"\n                            }\n                          },\n                          {\n                            \"argumentTypes\": null,\n                            \"id\": 4997,\n                            \"name\": \"contractBalance\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 4984,\n                            \"src\": \"25197:15:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          }\n                        ],\n                        \"expression\": {\n                          \"argumentTypes\": [\n                            {\n                              \"typeIdentifier\": \"t_address_payable\",\n                              \"typeString\": \"address payable\"\n                            },\n                            {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          ],\n                          \"expression\": {\n                            \"argumentTypes\": null,\n                            \"id\": 4994,\n                            \"name\": \"_token\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 3762,\n                            \"src\": \"25166:6:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_contract$_IERC20_$6707\",\n                              \"typeString\": \"contract IERC20\"\n                            }\n                          },\n                          \"id\": 4995,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"memberName\": \"transfer\",\n                          \"nodeType\": \"MemberAccess\",\n                          \"referencedDeclaration\": 6656,\n                          \"src\": \"25166:15:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_function_external_nonpayable$_t_address_$_t_uint256_$returns$_t_bool_$\",\n                            \"typeString\": \"function (address,uint256) external returns (bool)\"\n                          }\n                        },\n                        \"id\": 4998,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"kind\": \"functionCall\",\n                        \"lValueRequested\": false,\n                        \"names\": [],\n                        \"nodeType\": \"FunctionCall\",\n                        \"src\": \"25166:47:6\",\n                        \"tryCall\": false,\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        }\n                      ],\n                      \"id\": 4993,\n                      \"name\": \"require\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [\n                        -18,\n                        -18\n                      ],\n                      \"referencedDeclaration\": -18,\n                      \"src\": \"25158:7:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_require_pure$_t_bool_$returns$__$\",\n                        \"typeString\": \"function (bool) pure\"\n                      }\n                    },\n                    \"id\": 4999,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"25158:56:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 5000,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"25158:56:6\"\n                },\n                {\n                  \"eventCall\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [],\n                    \"expression\": {\n                      \"argumentTypes\": [],\n                      \"id\": 5001,\n                      \"name\": \"DeleteContract\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 3752,\n                      \"src\": \"25229:14:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_event_nonpayable$__$returns$__$\",\n                        \"typeString\": \"function ()\"\n                      }\n                    },\n                    \"id\": 5002,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"25229:16:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 5003,\n                  \"nodeType\": \"EmitStatement\",\n                  \"src\": \"25224:21:6\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 5005,\n                        \"name\": \"payoutAddress\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4965,\n                        \"src\": \"25268:13:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        }\n                      ],\n                      \"id\": 5004,\n                      \"name\": \"selfdestruct\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": -21,\n                      \"src\": \"25255:12:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_selfdestruct_nonpayable$_t_address_payable_$returns$__$\",\n                        \"typeString\": \"function (address payable)\"\n                      }\n                    },\n                    \"id\": 5006,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"25255:27:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 5007,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"25255:27:6\"\n                }\n              ]\n            },\n            \"documentation\": {\n              \"id\": 4963,\n              \"nodeType\": \"StructuredDocumentation\",\n              \"src\": \"24523:312:6\",\n              \"text\": \"@notice Delete the contract, transfers the remaining token and ether balance to the specified\\npayoutAddress\\n@param payoutAddress address to transfer the balances to. Ensure that this is able to handle ERC20 tokens\\n@dev owner only + only on or after `_earliestDelete` block\"\n            },\n            \"functionSelector\": \"9608df4b\",\n            \"id\": 5009,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [\n              {\n                \"arguments\": [\n                  {\n                    \"argumentTypes\": null,\n                    \"id\": 4970,\n                    \"name\": \"txExpirationBlock\",\n                    \"nodeType\": \"Identifier\",\n                    \"overloadedDeclarations\": [],\n                    \"referencedDeclaration\": 4967,\n                    \"src\": \"24958:17:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  }\n                ],\n                \"id\": 4971,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 4969,\n                  \"name\": \"verifyTxExpiration\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 3836,\n                  \"src\": \"24939:18:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$_t_uint256_$\",\n                    \"typeString\": \"modifier (uint256)\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"24939:37:6\"\n              },\n              {\n                \"arguments\": null,\n                \"id\": 4973,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 4972,\n                  \"name\": \"onlyOwner\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 3806,\n                  \"src\": \"24981:9:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$__$\",\n                    \"typeString\": \"modifier ()\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"24981:9:6\"\n              }\n            ],\n            \"name\": \"deleteContract\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 4968,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 4965,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"payoutAddress\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 5009,\n                  \"src\": \"24864:29:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_address_payable\",\n                    \"typeString\": \"address payable\"\n                  },\n                  \"typeName\": {\n                    \"id\": 4964,\n                    \"name\": \"address\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"24864:15:6\",\n                    \"stateMutability\": \"payable\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address_payable\",\n                      \"typeString\": \"address payable\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 4967,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"txExpirationBlock\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 5009,\n                  \"src\": \"24895:25:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 4966,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"24895:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"24863:58:6\"\n            },\n            \"returnParameters\": {\n              \"id\": 4974,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"24995:0:6\"\n            },\n            \"scope\": 5490,\n            \"src\": \"24840:449:6\",\n            \"stateMutability\": \"nonpayable\",\n            \"virtual\": false,\n            \"visibility\": \"external\"\n          },\n          {\n            \"body\": {\n              \"id\": 5018,\n              \"nodeType\": \"Block\",\n              \"src\": \"25630:36:6\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"expression\": {\n                      \"argumentTypes\": null,\n                      \"id\": 5015,\n                      \"name\": \"block\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": -4,\n                      \"src\": \"25647:5:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_magic_block\",\n                        \"typeString\": \"block\"\n                      }\n                    },\n                    \"id\": 5016,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"memberName\": \"number\",\n                    \"nodeType\": \"MemberAccess\",\n                    \"referencedDeclaration\": null,\n                    \"src\": \"25647:12:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"functionReturnParameters\": 5014,\n                  \"id\": 5017,\n                  \"nodeType\": \"Return\",\n                  \"src\": \"25640:19:6\"\n                }\n              ]\n            },\n            \"documentation\": {\n              \"id\": 5010,\n              \"nodeType\": \"StructuredDocumentation\",\n              \"src\": \"25431:124:6\",\n              \"text\": \"@dev VIRTUAL Method returning bock number. Introduced for \\n     testing purposes (allows mocking).\"\n            },\n            \"id\": 5019,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [],\n            \"name\": \"_getBlockNumber\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 5011,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"25584:2:6\"\n            },\n            \"returnParameters\": {\n              \"id\": 5014,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 5013,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 5019,\n                  \"src\": \"25617:7:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 5012,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"25617:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"25616:9:6\"\n            },\n            \"scope\": 5490,\n            \"src\": \"25560:106:6\",\n            \"stateMutability\": \"view\",\n            \"virtual\": true,\n            \"visibility\": \"internal\"\n          },\n          {\n            \"body\": {\n              \"id\": 5030,\n              \"nodeType\": \"Block\",\n              \"src\": \"25721:63:6\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 5025,\n                        \"name\": \"DEFAULT_ADMIN_ROLE\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 5584,\n                        \"src\": \"25746:18:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_bytes32\",\n                          \"typeString\": \"bytes32\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 5026,\n                          \"name\": \"msg\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": -15,\n                          \"src\": \"25766:3:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_magic_message\",\n                            \"typeString\": \"msg\"\n                          }\n                        },\n                        \"id\": 5027,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"memberName\": \"sender\",\n                        \"nodeType\": \"MemberAccess\",\n                        \"referencedDeclaration\": null,\n                        \"src\": \"25766:10:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_bytes32\",\n                          \"typeString\": \"bytes32\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        }\n                      ],\n                      \"id\": 5024,\n                      \"name\": \"hasRole\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5630,\n                      \"src\": \"25738:7:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_view$_t_bytes32_$_t_address_$returns$_t_bool_$\",\n                        \"typeString\": \"function (bytes32,address) view returns (bool)\"\n                      }\n                    },\n                    \"id\": 5028,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"25738:39:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_bool\",\n                      \"typeString\": \"bool\"\n                    }\n                  },\n                  \"functionReturnParameters\": 5023,\n                  \"id\": 5029,\n                  \"nodeType\": \"Return\",\n                  \"src\": \"25731:46:6\"\n                }\n              ]\n            },\n            \"documentation\": null,\n            \"id\": 5031,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [],\n            \"name\": \"_isOwner\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 5020,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"25690:2:6\"\n            },\n            \"returnParameters\": {\n              \"id\": 5023,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 5022,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 5031,\n                  \"src\": \"25715:4:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_bool\",\n                    \"typeString\": \"bool\"\n                  },\n                  \"typeName\": {\n                    \"id\": 5021,\n                    \"name\": \"bool\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"25715:4:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_bool\",\n                      \"typeString\": \"bool\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"25714:6:6\"\n            },\n            \"scope\": 5490,\n            \"src\": \"25673:111:6\",\n            \"stateMutability\": \"view\",\n            \"virtual\": false,\n            \"visibility\": \"internal\"\n          },\n          {\n            \"body\": {\n              \"id\": 5063,\n              \"nodeType\": \"Block\",\n              \"src\": \"26069:336:6\",\n              \"statements\": [\n                {\n                  \"assignments\": [\n                    5038\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 5038,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"idx\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 5063,\n                      \"src\": \"26079:11:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"default\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      },\n                      \"typeName\": {\n                        \"id\": 5037,\n                        \"name\": \"uint256\",\n                        \"nodeType\": \"ElementaryTypeName\",\n                        \"src\": \"26079:7:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 5040,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"id\": 5039,\n                    \"name\": \"_interestRatesNextIdx\",\n                    \"nodeType\": \"Identifier\",\n                    \"overloadedDeclarations\": [],\n                    \"referencedDeclaration\": 3780,\n                    \"src\": \"26093:21:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"26079:35:6\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 5049,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"baseExpression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 5041,\n                        \"name\": \"_interestRates\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 3784,\n                        \"src\": \"26124:14:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_mapping$_t_uint256_$_t_struct$_InterestRatePerBlock_$3641_storage_$\",\n                          \"typeString\": \"mapping(uint256 => struct Staking.InterestRatePerBlock storage ref)\"\n                        }\n                      },\n                      \"id\": 5043,\n                      \"indexExpression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 5042,\n                        \"name\": \"idx\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 5038,\n                        \"src\": \"26139:3:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      \"isConstant\": false,\n                      \"isLValue\": true,\n                      \"isPure\": false,\n                      \"lValueRequested\": true,\n                      \"nodeType\": \"IndexAccess\",\n                      \"src\": \"26124:19:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_struct$_InterestRatePerBlock_$3641_storage\",\n                        \"typeString\": \"struct Staking.InterestRatePerBlock storage ref\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"arguments\": [\n                        {\n                          \"argumentTypes\": null,\n                          \"arguments\": [],\n                          \"expression\": {\n                            \"argumentTypes\": [],\n                            \"id\": 5045,\n                            \"name\": \"_getBlockNumber\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 5019,\n                            \"src\": \"26195:15:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_function_internal_view$__$returns$_t_uint256_$\",\n                              \"typeString\": \"function () view returns (uint256)\"\n                            }\n                          },\n                          \"id\": 5046,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"kind\": \"functionCall\",\n                          \"lValueRequested\": false,\n                          \"names\": [],\n                          \"nodeType\": \"FunctionCall\",\n                          \"src\": \"26195:17:6\",\n                          \"tryCall\": false,\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        {\n                          \"argumentTypes\": null,\n                          \"id\": 5047,\n                          \"name\": \"rate\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 5034,\n                          \"src\": \"26233:4:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        }\n                      ],\n                      \"expression\": {\n                        \"argumentTypes\": [\n                          {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          },\n                          {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        ],\n                        \"id\": 5044,\n                        \"name\": \"InterestRatePerBlock\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 3641,\n                        \"src\": \"26146:20:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_type$_t_struct$_InterestRatePerBlock_$3641_storage_ptr_$\",\n                          \"typeString\": \"type(struct Staking.InterestRatePerBlock storage pointer)\"\n                        }\n                      },\n                      \"id\": 5048,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": false,\n                      \"kind\": \"structConstructorCall\",\n                      \"lValueRequested\": false,\n                      \"names\": [\n                        \"sinceBlock\",\n                        \"rate\"\n                      ],\n                      \"nodeType\": \"FunctionCall\",\n                      \"src\": \"26146:148:6\",\n                      \"tryCall\": false,\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_struct$_InterestRatePerBlock_$3641_memory_ptr\",\n                        \"typeString\": \"struct Staking.InterestRatePerBlock memory\"\n                      }\n                    },\n                    \"src\": \"26124:170:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_struct$_InterestRatePerBlock_$3641_storage\",\n                      \"typeString\": \"struct Staking.InterestRatePerBlock storage ref\"\n                    }\n                  },\n                  \"id\": 5050,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"26124:170:6\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 5056,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 5051,\n                      \"name\": \"_interestRatesNextIdx\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 3780,\n                      \"src\": \"26304:21:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"arguments\": [\n                        {\n                          \"argumentTypes\": null,\n                          \"hexValue\": \"31\",\n                          \"id\": 5054,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": true,\n                          \"kind\": \"number\",\n                          \"lValueRequested\": false,\n                          \"nodeType\": \"Literal\",\n                          \"src\": \"26354:1:6\",\n                          \"subdenomination\": null,\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_rational_1_by_1\",\n                            \"typeString\": \"int_const 1\"\n                          },\n                          \"value\": \"1\"\n                        }\n                      ],\n                      \"expression\": {\n                        \"argumentTypes\": [\n                          {\n                            \"typeIdentifier\": \"t_rational_1_by_1\",\n                            \"typeString\": \"int_const 1\"\n                          }\n                        ],\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 5052,\n                          \"name\": \"_interestRatesNextIdx\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 3780,\n                          \"src\": \"26328:21:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"id\": 5053,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"memberName\": \"add\",\n                        \"nodeType\": \"MemberAccess\",\n                        \"referencedDeclaration\": 5870,\n                        \"src\": \"26328:25:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_function_internal_pure$_t_uint256_$_t_uint256_$returns$_t_uint256_$bound_to$_t_uint256_$\",\n                          \"typeString\": \"function (uint256,uint256) pure returns (uint256)\"\n                        }\n                      },\n                      \"id\": 5055,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": false,\n                      \"kind\": \"functionCall\",\n                      \"lValueRequested\": false,\n                      \"names\": [],\n                      \"nodeType\": \"FunctionCall\",\n                      \"src\": \"26328:28:6\",\n                      \"tryCall\": false,\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"src\": \"26304:52:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"id\": 5057,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"26304:52:6\"\n                },\n                {\n                  \"eventCall\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 5059,\n                        \"name\": \"idx\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 5038,\n                        \"src\": \"26388:3:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 5060,\n                        \"name\": \"rate\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 5034,\n                        \"src\": \"26393:4:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"id\": 5058,\n                      \"name\": \"NewInterestRate\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 3710,\n                      \"src\": \"26372:15:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_event_nonpayable$_t_uint256_$_t_uint256_$returns$__$\",\n                        \"typeString\": \"function (uint256,uint256)\"\n                      }\n                    },\n                    \"id\": 5061,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"26372:26:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 5062,\n                  \"nodeType\": \"EmitStatement\",\n                  \"src\": \"26367:31:6\"\n                }\n              ]\n            },\n            \"documentation\": {\n              \"id\": 5032,\n              \"nodeType\": \"StructuredDocumentation\",\n              \"src\": \"25791:219:6\",\n              \"text\": \"@notice Add new interest rate in to the ordered container of previously added interest rates\\n@param rate - signed interest rate value in [10**18] units => real_rate [1] = rate [10**18] / 10**18\"\n            },\n            \"id\": 5064,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [],\n            \"name\": \"_addInterestRate\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 5035,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 5034,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"rate\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 5064,\n                  \"src\": \"26041:12:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 5033,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"26041:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"26040:14:6\"\n            },\n            \"returnParameters\": {\n              \"id\": 5036,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"26069:0:6\"\n            },\n            \"scope\": 5490,\n            \"src\": \"26015:390:6\",\n            \"stateMutability\": \"nonpayable\",\n            \"virtual\": false,\n            \"visibility\": \"internal\"\n          },\n          {\n            \"body\": {\n              \"id\": 5078,\n              \"nodeType\": \"Block\",\n              \"src\": \"26582:88:6\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 5072,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 5070,\n                      \"name\": \"_lockPeriodInBlocks\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 3768,\n                      \"src\": \"26592:19:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint64\",\n                        \"typeString\": \"uint64\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 5071,\n                      \"name\": \"numOfBlocks\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5067,\n                      \"src\": \"26614:11:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint64\",\n                        \"typeString\": \"uint64\"\n                      }\n                    },\n                    \"src\": \"26592:33:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint64\",\n                      \"typeString\": \"uint64\"\n                    }\n                  },\n                  \"id\": 5073,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"26592:33:6\"\n                },\n                {\n                  \"eventCall\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 5075,\n                        \"name\": \"numOfBlocks\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 5067,\n                        \"src\": \"26651:11:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint64\",\n                          \"typeString\": \"uint64\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_uint64\",\n                          \"typeString\": \"uint64\"\n                        }\n                      ],\n                      \"id\": 5074,\n                      \"name\": \"LockPeriod\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 3722,\n                      \"src\": \"26640:10:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_event_nonpayable$_t_uint64_$returns$__$\",\n                        \"typeString\": \"function (uint64)\"\n                      }\n                    },\n                    \"id\": 5076,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"26640:23:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 5077,\n                  \"nodeType\": \"EmitStatement\",\n                  \"src\": \"26635:28:6\"\n                }\n              ]\n            },\n            \"documentation\": {\n              \"id\": 5065,\n              \"nodeType\": \"StructuredDocumentation\",\n              \"src\": \"26412:105:6\",\n              \"text\": \"@notice Updates Lock Period value\\n@param numOfBlocks  length of the lock period\"\n            },\n            \"id\": 5079,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [],\n            \"name\": \"_updateLockPeriod\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 5068,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 5067,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"numOfBlocks\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 5079,\n                  \"src\": \"26549:18:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint64\",\n                    \"typeString\": \"uint64\"\n                  },\n                  \"typeName\": {\n                    \"id\": 5066,\n                    \"name\": \"uint64\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"26549:6:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint64\",\n                      \"typeString\": \"uint64\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"26548:20:6\"\n            },\n            \"returnParameters\": {\n              \"id\": 5069,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"26582:0:6\"\n            },\n            \"scope\": 5490,\n            \"src\": \"26522:148:6\",\n            \"stateMutability\": \"nonpayable\",\n            \"virtual\": false,\n            \"visibility\": \"internal\"\n          },\n          {\n            \"body\": {\n              \"id\": 5103,\n              \"nodeType\": \"Block\",\n              \"src\": \"26989:199:6\",\n              \"statements\": [\n                {\n                  \"assignments\": [\n                    5086\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 5086,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"currentBlockNumber\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 5103,\n                      \"src\": \"26999:26:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"default\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      },\n                      \"typeName\": {\n                        \"id\": 5085,\n                        \"name\": \"uint256\",\n                        \"nodeType\": \"ElementaryTypeName\",\n                        \"src\": \"26999:7:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 5089,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [],\n                    \"expression\": {\n                      \"argumentTypes\": [],\n                      \"id\": 5087,\n                      \"name\": \"_getBlockNumber\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5019,\n                      \"src\": \"27028:15:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_view$__$returns$_t_uint256_$\",\n                        \"typeString\": \"function () view returns (uint256)\"\n                      }\n                    },\n                    \"id\": 5088,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"27028:17:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"26999:46:6\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 5097,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 5090,\n                      \"name\": \"_pausedSinceBlock\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 3766,\n                      \"src\": \"27055:17:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"condition\": {\n                        \"argumentTypes\": null,\n                        \"commonType\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        },\n                        \"id\": 5093,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"leftExpression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 5091,\n                          \"name\": \"blockNumber\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 5082,\n                          \"src\": \"27075:11:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"nodeType\": \"BinaryOperation\",\n                        \"operator\": \"<\",\n                        \"rightExpression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 5092,\n                          \"name\": \"currentBlockNumber\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 5086,\n                          \"src\": \"27089:18:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"src\": \"27075:32:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        }\n                      },\n                      \"falseExpression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 5095,\n                        \"name\": \"blockNumber\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 5082,\n                        \"src\": \"27131:11:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      \"id\": 5096,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"nodeType\": \"Conditional\",\n                      \"src\": \"27075:67:6\",\n                      \"trueExpression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 5094,\n                        \"name\": \"currentBlockNumber\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 5086,\n                        \"src\": \"27110:18:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"src\": \"27055:87:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"id\": 5098,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"27055:87:6\"\n                },\n                {\n                  \"eventCall\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 5100,\n                        \"name\": \"_pausedSinceBlock\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 3766,\n                        \"src\": \"27163:17:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"id\": 5099,\n                      \"name\": \"Pause\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 3726,\n                      \"src\": \"27157:5:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_event_nonpayable$_t_uint256_$returns$__$\",\n                        \"typeString\": \"function (uint256)\"\n                      }\n                    },\n                    \"id\": 5101,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"27157:24:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 5102,\n                  \"nodeType\": \"EmitStatement\",\n                  \"src\": \"27152:29:6\"\n                }\n              ]\n            },\n            \"documentation\": {\n              \"id\": 5080,\n              \"nodeType\": \"StructuredDocumentation\",\n              \"src\": \"26677:251:6\",\n              \"text\": \"@notice Pauses all NON-administrative interaction with the contract since the specidfed block number \\n@param blockNumber block number since which non-admin interaction will be paused (for all _getBlockNumber() >= blockNumber)\"\n            },\n            \"id\": 5104,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [],\n            \"name\": \"_pauseSince\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 5083,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 5082,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"blockNumber\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 5104,\n                  \"src\": \"26954:19:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 5081,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"26954:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"26953:21:6\"\n            },\n            \"returnParameters\": {\n              \"id\": 5084,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"26989:0:6\"\n            },\n            \"scope\": 5490,\n            \"src\": \"26933:255:6\",\n            \"stateMutability\": \"nonpayable\",\n            \"virtual\": false,\n            \"visibility\": \"internal\"\n          },\n          {\n            \"body\": {\n              \"id\": 5167,\n              \"nodeType\": \"Block\",\n              \"src\": \"27984:719:6\",\n              \"statements\": [\n                {\n                  \"condition\": {\n                    \"argumentTypes\": null,\n                    \"commonType\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    },\n                    \"id\": 5116,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftExpression\": {\n                      \"argumentTypes\": null,\n                      \"id\": 5114,\n                      \"name\": \"amount\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5111,\n                      \"src\": \"27999:6:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"BinaryOperation\",\n                    \"operator\": \"!=\",\n                    \"rightExpression\": {\n                      \"argumentTypes\": null,\n                      \"hexValue\": \"30\",\n                      \"id\": 5115,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": true,\n                      \"kind\": \"number\",\n                      \"lValueRequested\": false,\n                      \"nodeType\": \"Literal\",\n                      \"src\": \"28009:1:6\",\n                      \"subdenomination\": null,\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_rational_0_by_1\",\n                        \"typeString\": \"int_const 0\"\n                      },\n                      \"value\": \"0\"\n                    },\n                    \"src\": \"27999:11:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_bool\",\n                      \"typeString\": \"bool\"\n                    }\n                  },\n                  \"falseBody\": null,\n                  \"id\": 5166,\n                  \"nodeType\": \"IfStatement\",\n                  \"src\": \"27995:702:6\",\n                  \"trueBody\": {\n                    \"id\": 5165,\n                    \"nodeType\": \"Block\",\n                    \"src\": \"28012:685:6\",\n                    \"statements\": [\n                      {\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"arguments\": [\n                            {\n                              \"argumentTypes\": null,\n                              \"commonType\": {\n                                \"typeIdentifier\": \"t_uint256\",\n                                \"typeString\": \"uint256\"\n                              },\n                              \"id\": 5121,\n                              \"isConstant\": false,\n                              \"isLValue\": false,\n                              \"isPure\": false,\n                              \"lValueRequested\": false,\n                              \"leftExpression\": {\n                                \"argumentTypes\": null,\n                                \"id\": 5118,\n                                \"name\": \"_rewardsPoolBalance\",\n                                \"nodeType\": \"Identifier\",\n                                \"overloadedDeclarations\": [],\n                                \"referencedDeclaration\": 3770,\n                                \"src\": \"28034:19:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              },\n                              \"nodeType\": \"BinaryOperation\",\n                              \"operator\": \">=\",\n                              \"rightExpression\": {\n                                \"argumentTypes\": null,\n                                \"expression\": {\n                                  \"argumentTypes\": null,\n                                  \"id\": 5119,\n                                  \"name\": \"_amount\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 5109,\n                                  \"src\": \"28057:7:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                    \"typeString\": \"struct AssetLib.Asset memory\"\n                                  }\n                                },\n                                \"id\": 5120,\n                                \"isConstant\": false,\n                                \"isLValue\": true,\n                                \"isPure\": false,\n                                \"lValueRequested\": false,\n                                \"memberName\": \"compoundInterest\",\n                                \"nodeType\": \"MemberAccess\",\n                                \"referencedDeclaration\": 2787,\n                                \"src\": \"28057:24:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              },\n                              \"src\": \"28034:47:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_bool\",\n                                \"typeString\": \"bool\"\n                              }\n                            },\n                            {\n                              \"argumentTypes\": null,\n                              \"hexValue\": \"4e6f7420656e6f7567682066756e647320696e207265776172647320706f6f6c\",\n                              \"id\": 5122,\n                              \"isConstant\": false,\n                              \"isLValue\": false,\n                              \"isPure\": true,\n                              \"kind\": \"string\",\n                              \"lValueRequested\": false,\n                              \"nodeType\": \"Literal\",\n                              \"src\": \"28083:34:6\",\n                              \"subdenomination\": null,\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_stringliteral_eea74719e5ae8f4b294d08561dadf2343b6f65323137e057e863d77438841724\",\n                                \"typeString\": \"literal_string \\\"Not enough funds in rewards pool\\\"\"\n                              },\n                              \"value\": \"Not enough funds in rewards pool\"\n                            }\n                          ],\n                          \"expression\": {\n                            \"argumentTypes\": [\n                              {\n                                \"typeIdentifier\": \"t_bool\",\n                                \"typeString\": \"bool\"\n                              },\n                              {\n                                \"typeIdentifier\": \"t_stringliteral_eea74719e5ae8f4b294d08561dadf2343b6f65323137e057e863d77438841724\",\n                                \"typeString\": \"literal_string \\\"Not enough funds in rewards pool\\\"\"\n                              }\n                            ],\n                            \"id\": 5117,\n                            \"name\": \"require\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [\n                              -18,\n                              -18\n                            ],\n                            \"referencedDeclaration\": -18,\n                            \"src\": \"28026:7:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$\",\n                              \"typeString\": \"function (bool,string memory) pure\"\n                            }\n                          },\n                          \"id\": 5123,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"kind\": \"functionCall\",\n                          \"lValueRequested\": false,\n                          \"names\": [],\n                          \"nodeType\": \"FunctionCall\",\n                          \"src\": \"28026:92:6\",\n                          \"tryCall\": false,\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_tuple$__$\",\n                            \"typeString\": \"tuple()\"\n                          }\n                        },\n                        \"id\": 5124,\n                        \"nodeType\": \"ExpressionStatement\",\n                        \"src\": \"28026:92:6\"\n                      },\n                      {\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"arguments\": [\n                            {\n                              \"argumentTypes\": null,\n                              \"arguments\": [\n                                {\n                                  \"argumentTypes\": null,\n                                  \"id\": 5128,\n                                  \"name\": \"sender\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 5107,\n                                  \"src\": \"28156:6:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_address\",\n                                    \"typeString\": \"address\"\n                                  }\n                                },\n                                {\n                                  \"argumentTypes\": null,\n                                  \"id\": 5129,\n                                  \"name\": \"amount\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 5111,\n                                  \"src\": \"28164:6:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_uint256\",\n                                    \"typeString\": \"uint256\"\n                                  }\n                                }\n                              ],\n                              \"expression\": {\n                                \"argumentTypes\": [\n                                  {\n                                    \"typeIdentifier\": \"t_address\",\n                                    \"typeString\": \"address\"\n                                  },\n                                  {\n                                    \"typeIdentifier\": \"t_uint256\",\n                                    \"typeString\": \"uint256\"\n                                  }\n                                ],\n                                \"expression\": {\n                                  \"argumentTypes\": null,\n                                  \"id\": 5126,\n                                  \"name\": \"_token\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 3762,\n                                  \"src\": \"28140:6:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_contract$_IERC20_$6707\",\n                                    \"typeString\": \"contract IERC20\"\n                                  }\n                                },\n                                \"id\": 5127,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": false,\n                                \"lValueRequested\": false,\n                                \"memberName\": \"transfer\",\n                                \"nodeType\": \"MemberAccess\",\n                                \"referencedDeclaration\": 6656,\n                                \"src\": \"28140:15:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_function_external_nonpayable$_t_address_$_t_uint256_$returns$_t_bool_$\",\n                                  \"typeString\": \"function (address,uint256) external returns (bool)\"\n                                }\n                              },\n                              \"id\": 5130,\n                              \"isConstant\": false,\n                              \"isLValue\": false,\n                              \"isPure\": false,\n                              \"kind\": \"functionCall\",\n                              \"lValueRequested\": false,\n                              \"names\": [],\n                              \"nodeType\": \"FunctionCall\",\n                              \"src\": \"28140:31:6\",\n                              \"tryCall\": false,\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_bool\",\n                                \"typeString\": \"bool\"\n                              }\n                            },\n                            {\n                              \"argumentTypes\": null,\n                              \"hexValue\": \"5472616e73666572206661696c6564\",\n                              \"id\": 5131,\n                              \"isConstant\": false,\n                              \"isLValue\": false,\n                              \"isPure\": true,\n                              \"kind\": \"string\",\n                              \"lValueRequested\": false,\n                              \"nodeType\": \"Literal\",\n                              \"src\": \"28173:17:6\",\n                              \"subdenomination\": null,\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_stringliteral_25adaa6d082ce15f901e0d8a3d393e7462ef9edf2e6bc8321fa14d1615b6fc51\",\n                                \"typeString\": \"literal_string \\\"Transfer failed\\\"\"\n                              },\n                              \"value\": \"Transfer failed\"\n                            }\n                          ],\n                          \"expression\": {\n                            \"argumentTypes\": [\n                              {\n                                \"typeIdentifier\": \"t_bool\",\n                                \"typeString\": \"bool\"\n                              },\n                              {\n                                \"typeIdentifier\": \"t_stringliteral_25adaa6d082ce15f901e0d8a3d393e7462ef9edf2e6bc8321fa14d1615b6fc51\",\n                                \"typeString\": \"literal_string \\\"Transfer failed\\\"\"\n                              }\n                            ],\n                            \"id\": 5125,\n                            \"name\": \"require\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [\n                              -18,\n                              -18\n                            ],\n                            \"referencedDeclaration\": -18,\n                            \"src\": \"28132:7:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$\",\n                              \"typeString\": \"function (bool,string memory) pure\"\n                            }\n                          },\n                          \"id\": 5132,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"kind\": \"functionCall\",\n                          \"lValueRequested\": false,\n                          \"names\": [],\n                          \"nodeType\": \"FunctionCall\",\n                          \"src\": \"28132:59:6\",\n                          \"tryCall\": false,\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_tuple$__$\",\n                            \"typeString\": \"tuple()\"\n                          }\n                        },\n                        \"id\": 5133,\n                        \"nodeType\": \"ExpressionStatement\",\n                        \"src\": \"28132:59:6\"\n                      },\n                      {\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 5140,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"leftHandSide\": {\n                            \"argumentTypes\": null,\n                            \"id\": 5134,\n                            \"name\": \"_rewardsPoolBalance\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 3770,\n                            \"src\": \"28206:19:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"nodeType\": \"Assignment\",\n                          \"operator\": \"=\",\n                          \"rightHandSide\": {\n                            \"argumentTypes\": null,\n                            \"arguments\": [\n                              {\n                                \"argumentTypes\": null,\n                                \"expression\": {\n                                  \"argumentTypes\": null,\n                                  \"id\": 5137,\n                                  \"name\": \"_amount\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 5109,\n                                  \"src\": \"28252:7:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                    \"typeString\": \"struct AssetLib.Asset memory\"\n                                  }\n                                },\n                                \"id\": 5138,\n                                \"isConstant\": false,\n                                \"isLValue\": true,\n                                \"isPure\": false,\n                                \"lValueRequested\": false,\n                                \"memberName\": \"compoundInterest\",\n                                \"nodeType\": \"MemberAccess\",\n                                \"referencedDeclaration\": 2787,\n                                \"src\": \"28252:24:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              }\n                            ],\n                            \"expression\": {\n                              \"argumentTypes\": [\n                                {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              ],\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"id\": 5135,\n                                \"name\": \"_rewardsPoolBalance\",\n                                \"nodeType\": \"Identifier\",\n                                \"overloadedDeclarations\": [],\n                                \"referencedDeclaration\": 3770,\n                                \"src\": \"28228:19:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              },\n                              \"id\": 5136,\n                              \"isConstant\": false,\n                              \"isLValue\": false,\n                              \"isPure\": false,\n                              \"lValueRequested\": false,\n                              \"memberName\": \"sub\",\n                              \"nodeType\": \"MemberAccess\",\n                              \"referencedDeclaration\": 5887,\n                              \"src\": \"28228:23:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_function_internal_pure$_t_uint256_$_t_uint256_$returns$_t_uint256_$bound_to$_t_uint256_$\",\n                                \"typeString\": \"function (uint256,uint256) pure returns (uint256)\"\n                              }\n                            },\n                            \"id\": 5139,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": false,\n                            \"kind\": \"functionCall\",\n                            \"lValueRequested\": false,\n                            \"names\": [],\n                            \"nodeType\": \"FunctionCall\",\n                            \"src\": \"28228:49:6\",\n                            \"tryCall\": false,\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"src\": \"28206:71:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"id\": 5141,\n                        \"nodeType\": \"ExpressionStatement\",\n                        \"src\": \"28206:71:6\"\n                      },\n                      {\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 5148,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"leftHandSide\": {\n                            \"argumentTypes\": null,\n                            \"id\": 5142,\n                            \"name\": \"_accruedGlobalPrincipal\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 3772,\n                            \"src\": \"28291:23:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"nodeType\": \"Assignment\",\n                          \"operator\": \"=\",\n                          \"rightHandSide\": {\n                            \"argumentTypes\": null,\n                            \"arguments\": [\n                              {\n                                \"argumentTypes\": null,\n                                \"expression\": {\n                                  \"argumentTypes\": null,\n                                  \"id\": 5145,\n                                  \"name\": \"_amount\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 5109,\n                                  \"src\": \"28345:7:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                    \"typeString\": \"struct AssetLib.Asset memory\"\n                                  }\n                                },\n                                \"id\": 5146,\n                                \"isConstant\": false,\n                                \"isLValue\": true,\n                                \"isPure\": false,\n                                \"lValueRequested\": false,\n                                \"memberName\": \"principal\",\n                                \"nodeType\": \"MemberAccess\",\n                                \"referencedDeclaration\": 2785,\n                                \"src\": \"28345:17:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              }\n                            ],\n                            \"expression\": {\n                              \"argumentTypes\": [\n                                {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              ],\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"id\": 5143,\n                                \"name\": \"_accruedGlobalPrincipal\",\n                                \"nodeType\": \"Identifier\",\n                                \"overloadedDeclarations\": [],\n                                \"referencedDeclaration\": 3772,\n                                \"src\": \"28317:23:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              },\n                              \"id\": 5144,\n                              \"isConstant\": false,\n                              \"isLValue\": false,\n                              \"isPure\": false,\n                              \"lValueRequested\": false,\n                              \"memberName\": \"sub\",\n                              \"nodeType\": \"MemberAccess\",\n                              \"referencedDeclaration\": 5887,\n                              \"src\": \"28317:27:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_function_internal_pure$_t_uint256_$_t_uint256_$returns$_t_uint256_$bound_to$_t_uint256_$\",\n                                \"typeString\": \"function (uint256,uint256) pure returns (uint256)\"\n                              }\n                            },\n                            \"id\": 5147,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": false,\n                            \"kind\": \"functionCall\",\n                            \"lValueRequested\": false,\n                            \"names\": [],\n                            \"nodeType\": \"FunctionCall\",\n                            \"src\": \"28317:46:6\",\n                            \"tryCall\": false,\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"src\": \"28291:72:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"id\": 5149,\n                        \"nodeType\": \"ExpressionStatement\",\n                        \"src\": \"28291:72:6\"\n                      },\n                      {\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"arguments\": [\n                            {\n                              \"argumentTypes\": null,\n                              \"id\": 5153,\n                              \"name\": \"_amount\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 5109,\n                              \"src\": \"28406:7:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                \"typeString\": \"struct AssetLib.Asset memory\"\n                              }\n                            }\n                          ],\n                          \"expression\": {\n                            \"argumentTypes\": [\n                              {\n                                \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                \"typeString\": \"struct AssetLib.Asset memory\"\n                              }\n                            ],\n                            \"expression\": {\n                              \"argumentTypes\": null,\n                              \"id\": 5150,\n                              \"name\": \"_accruedGlobalLiquidity\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 3774,\n                              \"src\": \"28377:23:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                                \"typeString\": \"struct AssetLib.Asset storage ref\"\n                              }\n                            },\n                            \"id\": 5152,\n                            \"isConstant\": false,\n                            \"isLValue\": true,\n                            \"isPure\": false,\n                            \"lValueRequested\": false,\n                            \"memberName\": \"iSub\",\n                            \"nodeType\": \"MemberAccess\",\n                            \"referencedDeclaration\": 2938,\n                            \"src\": \"28377:28:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_function_internal_nonpayable$_t_struct$_Asset_$2788_storage_ptr_$_t_struct$_Asset_$2788_memory_ptr_$returns$__$bound_to$_t_struct$_Asset_$2788_storage_ptr_$\",\n                              \"typeString\": \"function (struct AssetLib.Asset storage pointer,struct AssetLib.Asset memory)\"\n                            }\n                          },\n                          \"id\": 5154,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"kind\": \"functionCall\",\n                          \"lValueRequested\": false,\n                          \"names\": [],\n                          \"nodeType\": \"FunctionCall\",\n                          \"src\": \"28377:37:6\",\n                          \"tryCall\": false,\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_tuple$__$\",\n                            \"typeString\": \"tuple()\"\n                          }\n                        },\n                        \"id\": 5155,\n                        \"nodeType\": \"ExpressionStatement\",\n                        \"src\": \"28377:37:6\"\n                      },\n                      {\n                        \"eventCall\": {\n                          \"argumentTypes\": null,\n                          \"arguments\": [\n                            {\n                              \"argumentTypes\": null,\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"id\": 5157,\n                                \"name\": \"msg\",\n                                \"nodeType\": \"Identifier\",\n                                \"overloadedDeclarations\": [],\n                                \"referencedDeclaration\": -15,\n                                \"src\": \"28629:3:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_magic_message\",\n                                  \"typeString\": \"msg\"\n                                }\n                              },\n                              \"id\": 5158,\n                              \"isConstant\": false,\n                              \"isLValue\": false,\n                              \"isPure\": false,\n                              \"lValueRequested\": false,\n                              \"memberName\": \"sender\",\n                              \"nodeType\": \"MemberAccess\",\n                              \"referencedDeclaration\": null,\n                              \"src\": \"28629:10:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_address_payable\",\n                                \"typeString\": \"address payable\"\n                              }\n                            },\n                            {\n                              \"argumentTypes\": null,\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"id\": 5159,\n                                \"name\": \"_amount\",\n                                \"nodeType\": \"Identifier\",\n                                \"overloadedDeclarations\": [],\n                                \"referencedDeclaration\": 5109,\n                                \"src\": \"28641:7:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                  \"typeString\": \"struct AssetLib.Asset memory\"\n                                }\n                              },\n                              \"id\": 5160,\n                              \"isConstant\": false,\n                              \"isLValue\": true,\n                              \"isPure\": false,\n                              \"lValueRequested\": false,\n                              \"memberName\": \"principal\",\n                              \"nodeType\": \"MemberAccess\",\n                              \"referencedDeclaration\": 2785,\n                              \"src\": \"28641:17:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_uint256\",\n                                \"typeString\": \"uint256\"\n                              }\n                            },\n                            {\n                              \"argumentTypes\": null,\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"id\": 5161,\n                                \"name\": \"_amount\",\n                                \"nodeType\": \"Identifier\",\n                                \"overloadedDeclarations\": [],\n                                \"referencedDeclaration\": 5109,\n                                \"src\": \"28660:7:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                  \"typeString\": \"struct AssetLib.Asset memory\"\n                                }\n                              },\n                              \"id\": 5162,\n                              \"isConstant\": false,\n                              \"isLValue\": true,\n                              \"isPure\": false,\n                              \"lValueRequested\": false,\n                              \"memberName\": \"compoundInterest\",\n                              \"nodeType\": \"MemberAccess\",\n                              \"referencedDeclaration\": 2787,\n                              \"src\": \"28660:24:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_uint256\",\n                                \"typeString\": \"uint256\"\n                              }\n                            }\n                          ],\n                          \"expression\": {\n                            \"argumentTypes\": [\n                              {\n                                \"typeIdentifier\": \"t_address_payable\",\n                                \"typeString\": \"address payable\"\n                              },\n                              {\n                                \"typeIdentifier\": \"t_uint256\",\n                                \"typeString\": \"uint256\"\n                              },\n                              {\n                                \"typeIdentifier\": \"t_uint256\",\n                                \"typeString\": \"uint256\"\n                              }\n                            ],\n                            \"id\": 5156,\n                            \"name\": \"Withdraw\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 3718,\n                            \"src\": \"28620:8:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_function_event_nonpayable$_t_address_$_t_uint256_$_t_uint256_$returns$__$\",\n                              \"typeString\": \"function (address,uint256,uint256)\"\n                            }\n                          },\n                          \"id\": 5163,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"kind\": \"functionCall\",\n                          \"lValueRequested\": false,\n                          \"names\": [],\n                          \"nodeType\": \"FunctionCall\",\n                          \"src\": \"28620:65:6\",\n                          \"tryCall\": false,\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_tuple$__$\",\n                            \"typeString\": \"tuple()\"\n                          }\n                        },\n                        \"id\": 5164,\n                        \"nodeType\": \"EmitStatement\",\n                        \"src\": \"28615:70:6\"\n                      }\n                    ]\n                  }\n                }\n              ]\n            },\n            \"documentation\": {\n              \"id\": 5105,\n              \"nodeType\": \"StructuredDocumentation\",\n              \"src\": \"27195:685:6\",\n              \"text\": \"@notice Withdraws amount from sender' available liquidity pool back to sender address,\\n        preferring withdrawal from compound interest dimension of liquidity.\\n     * @param amount - value to withdraw\\n     * @dev NOTE(pb): Passing redundant `uint256 amount` (on top of the `Asset _amount`) in the name\\n               of performance to avoid calculating it again from `_amount` (or the other way around).\\n               IMPLICATION: Caller **MUST** pass correct values, ensuring that `amount == _amount.composite()`,\\n               since this private method is **NOT** verifying this condition due to performance reasons.\"\n            },\n            \"id\": 5168,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [],\n            \"name\": \"_finaliseWithdraw\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 5112,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 5107,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"sender\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 5168,\n                  \"src\": \"27912:14:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_address\",\n                    \"typeString\": \"address\"\n                  },\n                  \"typeName\": {\n                    \"id\": 5106,\n                    \"name\": \"address\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"27912:7:6\",\n                    \"stateMutability\": \"nonpayable\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address\",\n                      \"typeString\": \"address\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 5109,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"_amount\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 5168,\n                  \"src\": \"27928:29:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"memory\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                    \"typeString\": \"struct AssetLib.Asset\"\n                  },\n                  \"typeName\": {\n                    \"contractScope\": null,\n                    \"id\": 5108,\n                    \"name\": \"AssetLib.Asset\",\n                    \"nodeType\": \"UserDefinedTypeName\",\n                    \"referencedDeclaration\": 2788,\n                    \"src\": \"27928:14:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                      \"typeString\": \"struct AssetLib.Asset\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 5111,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"amount\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 5168,\n                  \"src\": \"27959:14:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 5110,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"27959:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"27911:63:6\"\n            },\n            \"returnParameters\": {\n              \"id\": 5113,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"27984:0:6\"\n            },\n            \"scope\": 5490,\n            \"src\": \"27885:818:6\",\n            \"stateMutability\": \"nonpayable\",\n            \"virtual\": false,\n            \"visibility\": \"internal\"\n          },\n          {\n            \"body\": {\n              \"id\": 5314,\n              \"nodeType\": \"Block\",\n              \"src\": \"28840:2765:6\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 5181,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 5177,\n                      \"name\": \"stake\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5175,\n                      \"src\": \"28850:5:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_struct$_Stake_$3648_storage_ptr\",\n                        \"typeString\": \"struct Staking.Stake storage pointer\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"baseExpression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 5178,\n                        \"name\": \"_stakes\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 3788,\n                        \"src\": \"28858:7:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_mapping$_t_address_$_t_struct$_Stake_$3648_storage_$\",\n                          \"typeString\": \"mapping(address => struct Staking.Stake storage ref)\"\n                        }\n                      },\n                      \"id\": 5180,\n                      \"indexExpression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 5179,\n                        \"name\": \"sender\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 5170,\n                        \"src\": \"28866:6:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        }\n                      },\n                      \"isConstant\": false,\n                      \"isLValue\": true,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"nodeType\": \"IndexAccess\",\n                      \"src\": \"28858:15:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_struct$_Stake_$3648_storage\",\n                        \"typeString\": \"struct Staking.Stake storage ref\"\n                      }\n                    },\n                    \"src\": \"28850:23:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_struct$_Stake_$3648_storage_ptr\",\n                      \"typeString\": \"struct Staking.Stake storage pointer\"\n                    }\n                  },\n                  \"id\": 5182,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"28850:23:6\"\n                },\n                {\n                  \"assignments\": [\n                    5184\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 5184,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"composite\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 5314,\n                      \"src\": \"28883:17:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"default\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      },\n                      \"typeName\": {\n                        \"id\": 5183,\n                        \"name\": \"uint256\",\n                        \"nodeType\": \"ElementaryTypeName\",\n                        \"src\": \"28883:7:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 5189,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [],\n                    \"expression\": {\n                      \"argumentTypes\": [],\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 5185,\n                          \"name\": \"stake\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 5175,\n                          \"src\": \"28903:5:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_struct$_Stake_$3648_storage_ptr\",\n                            \"typeString\": \"struct Staking.Stake storage pointer\"\n                          }\n                        },\n                        \"id\": 5186,\n                        \"isConstant\": false,\n                        \"isLValue\": true,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"memberName\": \"asset\",\n                        \"nodeType\": \"MemberAccess\",\n                        \"referencedDeclaration\": 3647,\n                        \"src\": \"28903:11:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                          \"typeString\": \"struct AssetLib.Asset storage ref\"\n                        }\n                      },\n                      \"id\": 5187,\n                      \"isConstant\": false,\n                      \"isLValue\": true,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"memberName\": \"composite\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": 2803,\n                      \"src\": \"28903:21:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_view$_t_struct$_Asset_$2788_storage_ptr_$returns$_t_uint256_$bound_to$_t_struct$_Asset_$2788_storage_ptr_$\",\n                        \"typeString\": \"function (struct AssetLib.Asset storage pointer) view returns (uint256)\"\n                      }\n                    },\n                    \"id\": 5188,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"28903:23:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"28883:43:6\"\n                },\n                {\n                  \"condition\": {\n                    \"argumentTypes\": null,\n                    \"commonType\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    },\n                    \"id\": 5192,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftExpression\": {\n                      \"argumentTypes\": null,\n                      \"id\": 5190,\n                      \"name\": \"composite\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5184,\n                      \"src\": \"28940:9:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"BinaryOperation\",\n                    \"operator\": \"!=\",\n                    \"rightExpression\": {\n                      \"argumentTypes\": null,\n                      \"hexValue\": \"30\",\n                      \"id\": 5191,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": true,\n                      \"kind\": \"number\",\n                      \"lValueRequested\": false,\n                      \"nodeType\": \"Literal\",\n                      \"src\": \"28953:1:6\",\n                      \"subdenomination\": null,\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_rational_0_by_1\",\n                        \"typeString\": \"int_const 0\"\n                      },\n                      \"value\": \"0\"\n                    },\n                    \"src\": \"28940:14:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_bool\",\n                      \"typeString\": \"bool\"\n                    }\n                  },\n                  \"falseBody\": null,\n                  \"id\": 5281,\n                  \"nodeType\": \"IfStatement\",\n                  \"src\": \"28936:1369:6\",\n                  \"trueBody\": {\n                    \"id\": 5280,\n                    \"nodeType\": \"Block\",\n                    \"src\": \"28964:1341:6\",\n                    \"statements\": [\n                      {\n                        \"assignments\": [\n                          5194\n                        ],\n                        \"declarations\": [\n                          {\n                            \"constant\": false,\n                            \"id\": 5194,\n                            \"mutability\": \"mutable\",\n                            \"name\": \"start_block\",\n                            \"nodeType\": \"VariableDeclaration\",\n                            \"overrides\": null,\n                            \"scope\": 5280,\n                            \"src\": \"29048:19:6\",\n                            \"stateVariable\": false,\n                            \"storageLocation\": \"default\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            },\n                            \"typeName\": {\n                              \"id\": 5193,\n                              \"name\": \"uint256\",\n                              \"nodeType\": \"ElementaryTypeName\",\n                              \"src\": \"29048:7:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_uint256\",\n                                \"typeString\": \"uint256\"\n                              }\n                            },\n                            \"value\": null,\n                            \"visibility\": \"internal\"\n                          }\n                        ],\n                        \"id\": 5197,\n                        \"initialValue\": {\n                          \"argumentTypes\": null,\n                          \"expression\": {\n                            \"argumentTypes\": null,\n                            \"id\": 5195,\n                            \"name\": \"stake\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 5175,\n                            \"src\": \"29070:5:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_struct$_Stake_$3648_storage_ptr\",\n                              \"typeString\": \"struct Staking.Stake storage pointer\"\n                            }\n                          },\n                          \"id\": 5196,\n                          \"isConstant\": false,\n                          \"isLValue\": true,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"memberName\": \"sinceBlock\",\n                          \"nodeType\": \"MemberAccess\",\n                          \"referencedDeclaration\": 3643,\n                          \"src\": \"29070:16:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"nodeType\": \"VariableDeclarationStatement\",\n                        \"src\": \"29048:38:6\"\n                      },\n                      {\n                        \"body\": {\n                          \"id\": 5265,\n                          \"nodeType\": \"Block\",\n                          \"src\": \"29411:802:6\",\n                          \"statements\": [\n                            {\n                              \"assignments\": [\n                                5210\n                              ],\n                              \"declarations\": [\n                                {\n                                  \"constant\": false,\n                                  \"id\": 5210,\n                                  \"mutability\": \"mutable\",\n                                  \"name\": \"interest\",\n                                  \"nodeType\": \"VariableDeclaration\",\n                                  \"overrides\": null,\n                                  \"scope\": 5265,\n                                  \"src\": \"29429:37:6\",\n                                  \"stateVariable\": false,\n                                  \"storageLocation\": \"storage\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_struct$_InterestRatePerBlock_$3641_storage_ptr\",\n                                    \"typeString\": \"struct Staking.InterestRatePerBlock\"\n                                  },\n                                  \"typeName\": {\n                                    \"contractScope\": null,\n                                    \"id\": 5209,\n                                    \"name\": \"InterestRatePerBlock\",\n                                    \"nodeType\": \"UserDefinedTypeName\",\n                                    \"referencedDeclaration\": 3641,\n                                    \"src\": \"29429:20:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_struct$_InterestRatePerBlock_$3641_storage_ptr\",\n                                      \"typeString\": \"struct Staking.InterestRatePerBlock\"\n                                    }\n                                  },\n                                  \"value\": null,\n                                  \"visibility\": \"internal\"\n                                }\n                              ],\n                              \"id\": 5214,\n                              \"initialValue\": {\n                                \"argumentTypes\": null,\n                                \"baseExpression\": {\n                                  \"argumentTypes\": null,\n                                  \"id\": 5211,\n                                  \"name\": \"_interestRates\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 3784,\n                                  \"src\": \"29469:14:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_mapping$_t_uint256_$_t_struct$_InterestRatePerBlock_$3641_storage_$\",\n                                    \"typeString\": \"mapping(uint256 => struct Staking.InterestRatePerBlock storage ref)\"\n                                  }\n                                },\n                                \"id\": 5213,\n                                \"indexExpression\": {\n                                  \"argumentTypes\": null,\n                                  \"id\": 5212,\n                                  \"name\": \"i\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 5199,\n                                  \"src\": \"29484:1:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_uint256\",\n                                    \"typeString\": \"uint256\"\n                                  }\n                                },\n                                \"isConstant\": false,\n                                \"isLValue\": true,\n                                \"isPure\": false,\n                                \"lValueRequested\": false,\n                                \"nodeType\": \"IndexAccess\",\n                                \"src\": \"29469:17:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_struct$_InterestRatePerBlock_$3641_storage\",\n                                  \"typeString\": \"struct Staking.InterestRatePerBlock storage ref\"\n                                }\n                              },\n                              \"nodeType\": \"VariableDeclarationStatement\",\n                              \"src\": \"29429:57:6\"\n                            },\n                            {\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"arguments\": [\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"commonType\": {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    },\n                                    \"id\": 5219,\n                                    \"isConstant\": false,\n                                    \"isLValue\": false,\n                                    \"isPure\": false,\n                                    \"lValueRequested\": false,\n                                    \"leftExpression\": {\n                                      \"argumentTypes\": null,\n                                      \"expression\": {\n                                        \"argumentTypes\": null,\n                                        \"id\": 5216,\n                                        \"name\": \"interest\",\n                                        \"nodeType\": \"Identifier\",\n                                        \"overloadedDeclarations\": [],\n                                        \"referencedDeclaration\": 5210,\n                                        \"src\": \"29697:8:6\",\n                                        \"typeDescriptions\": {\n                                          \"typeIdentifier\": \"t_struct$_InterestRatePerBlock_$3641_storage_ptr\",\n                                          \"typeString\": \"struct Staking.InterestRatePerBlock storage pointer\"\n                                        }\n                                      },\n                                      \"id\": 5217,\n                                      \"isConstant\": false,\n                                      \"isLValue\": true,\n                                      \"isPure\": false,\n                                      \"lValueRequested\": false,\n                                      \"memberName\": \"sinceBlock\",\n                                      \"nodeType\": \"MemberAccess\",\n                                      \"referencedDeclaration\": 3638,\n                                      \"src\": \"29697:19:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_uint256\",\n                                        \"typeString\": \"uint256\"\n                                      }\n                                    },\n                                    \"nodeType\": \"BinaryOperation\",\n                                    \"operator\": \"<=\",\n                                    \"rightExpression\": {\n                                      \"argumentTypes\": null,\n                                      \"id\": 5218,\n                                      \"name\": \"start_block\",\n                                      \"nodeType\": \"Identifier\",\n                                      \"overloadedDeclarations\": [],\n                                      \"referencedDeclaration\": 5194,\n                                      \"src\": \"29720:11:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_uint256\",\n                                        \"typeString\": \"uint256\"\n                                      }\n                                    },\n                                    \"src\": \"29697:34:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_bool\",\n                                      \"typeString\": \"bool\"\n                                    }\n                                  },\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"hexValue\": \"73696e6365426c6f636b20696e636f6e73697374656e6379\",\n                                    \"id\": 5220,\n                                    \"isConstant\": false,\n                                    \"isLValue\": false,\n                                    \"isPure\": true,\n                                    \"kind\": \"string\",\n                                    \"lValueRequested\": false,\n                                    \"nodeType\": \"Literal\",\n                                    \"src\": \"29733:26:6\",\n                                    \"subdenomination\": null,\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_stringliteral_0b30ca9f63e0c2596e072157a3416c4519a0da0c7a77930c294d44b40e819c8c\",\n                                      \"typeString\": \"literal_string \\\"sinceBlock inconsistency\\\"\"\n                                    },\n                                    \"value\": \"sinceBlock inconsistency\"\n                                  }\n                                ],\n                                \"expression\": {\n                                  \"argumentTypes\": [\n                                    {\n                                      \"typeIdentifier\": \"t_bool\",\n                                      \"typeString\": \"bool\"\n                                    },\n                                    {\n                                      \"typeIdentifier\": \"t_stringliteral_0b30ca9f63e0c2596e072157a3416c4519a0da0c7a77930c294d44b40e819c8c\",\n                                      \"typeString\": \"literal_string \\\"sinceBlock inconsistency\\\"\"\n                                    }\n                                  ],\n                                  \"id\": 5215,\n                                  \"name\": \"require\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [\n                                    -18,\n                                    -18\n                                  ],\n                                  \"referencedDeclaration\": -18,\n                                  \"src\": \"29689:7:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$\",\n                                    \"typeString\": \"function (bool,string memory) pure\"\n                                  }\n                                },\n                                \"id\": 5221,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": false,\n                                \"kind\": \"functionCall\",\n                                \"lValueRequested\": false,\n                                \"names\": [],\n                                \"nodeType\": \"FunctionCall\",\n                                \"src\": \"29689:71:6\",\n                                \"tryCall\": false,\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_tuple$__$\",\n                                  \"typeString\": \"tuple()\"\n                                }\n                              },\n                              \"id\": 5222,\n                              \"nodeType\": \"ExpressionStatement\",\n                              \"src\": \"29689:71:6\"\n                            },\n                            {\n                              \"assignments\": [\n                                5224\n                              ],\n                              \"declarations\": [\n                                {\n                                  \"constant\": false,\n                                  \"id\": 5224,\n                                  \"mutability\": \"mutable\",\n                                  \"name\": \"end_block\",\n                                  \"nodeType\": \"VariableDeclaration\",\n                                  \"overrides\": null,\n                                  \"scope\": 5265,\n                                  \"src\": \"29778:17:6\",\n                                  \"stateVariable\": false,\n                                  \"storageLocation\": \"default\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_uint256\",\n                                    \"typeString\": \"uint256\"\n                                  },\n                                  \"typeName\": {\n                                    \"id\": 5223,\n                                    \"name\": \"uint256\",\n                                    \"nodeType\": \"ElementaryTypeName\",\n                                    \"src\": \"29778:7:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    }\n                                  },\n                                  \"value\": null,\n                                  \"visibility\": \"internal\"\n                                }\n                              ],\n                              \"id\": 5226,\n                              \"initialValue\": {\n                                \"argumentTypes\": null,\n                                \"id\": 5225,\n                                \"name\": \"at_block\",\n                                \"nodeType\": \"Identifier\",\n                                \"overloadedDeclarations\": [],\n                                \"referencedDeclaration\": 5172,\n                                \"src\": \"29798:8:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              },\n                              \"nodeType\": \"VariableDeclarationStatement\",\n                              \"src\": \"29778:28:6\"\n                            },\n                            {\n                              \"assignments\": [\n                                5228\n                              ],\n                              \"declarations\": [\n                                {\n                                  \"constant\": false,\n                                  \"id\": 5228,\n                                  \"mutability\": \"mutable\",\n                                  \"name\": \"j\",\n                                  \"nodeType\": \"VariableDeclaration\",\n                                  \"overrides\": null,\n                                  \"scope\": 5265,\n                                  \"src\": \"29825:9:6\",\n                                  \"stateVariable\": false,\n                                  \"storageLocation\": \"default\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_uint256\",\n                                    \"typeString\": \"uint256\"\n                                  },\n                                  \"typeName\": {\n                                    \"id\": 5227,\n                                    \"name\": \"uint256\",\n                                    \"nodeType\": \"ElementaryTypeName\",\n                                    \"src\": \"29825:7:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    }\n                                  },\n                                  \"value\": null,\n                                  \"visibility\": \"internal\"\n                                }\n                              ],\n                              \"id\": 5232,\n                              \"initialValue\": {\n                                \"argumentTypes\": null,\n                                \"commonType\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                },\n                                \"id\": 5231,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": false,\n                                \"lValueRequested\": false,\n                                \"leftExpression\": {\n                                  \"argumentTypes\": null,\n                                  \"id\": 5229,\n                                  \"name\": \"i\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 5199,\n                                  \"src\": \"29837:1:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_uint256\",\n                                    \"typeString\": \"uint256\"\n                                  }\n                                },\n                                \"nodeType\": \"BinaryOperation\",\n                                \"operator\": \"+\",\n                                \"rightExpression\": {\n                                  \"argumentTypes\": null,\n                                  \"hexValue\": \"31\",\n                                  \"id\": 5230,\n                                  \"isConstant\": false,\n                                  \"isLValue\": false,\n                                  \"isPure\": true,\n                                  \"kind\": \"number\",\n                                  \"lValueRequested\": false,\n                                  \"nodeType\": \"Literal\",\n                                  \"src\": \"29841:1:6\",\n                                  \"subdenomination\": null,\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_rational_1_by_1\",\n                                    \"typeString\": \"int_const 1\"\n                                  },\n                                  \"value\": \"1\"\n                                },\n                                \"src\": \"29837:5:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              },\n                              \"nodeType\": \"VariableDeclarationStatement\",\n                              \"src\": \"29825:17:6\"\n                            },\n                            {\n                              \"condition\": {\n                                \"argumentTypes\": null,\n                                \"commonType\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                },\n                                \"id\": 5235,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": false,\n                                \"lValueRequested\": false,\n                                \"leftExpression\": {\n                                  \"argumentTypes\": null,\n                                  \"id\": 5233,\n                                  \"name\": \"j\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 5228,\n                                  \"src\": \"29864:1:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_uint256\",\n                                    \"typeString\": \"uint256\"\n                                  }\n                                },\n                                \"nodeType\": \"BinaryOperation\",\n                                \"operator\": \"<\",\n                                \"rightExpression\": {\n                                  \"argumentTypes\": null,\n                                  \"id\": 5234,\n                                  \"name\": \"_interestRatesNextIdx\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 3780,\n                                  \"src\": \"29868:21:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_uint256\",\n                                    \"typeString\": \"uint256\"\n                                  }\n                                },\n                                \"src\": \"29864:25:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_bool\",\n                                  \"typeString\": \"bool\"\n                                }\n                              },\n                              \"falseBody\": null,\n                              \"id\": 5248,\n                              \"nodeType\": \"IfStatement\",\n                              \"src\": \"29860:192:6\",\n                              \"trueBody\": {\n                                \"id\": 5247,\n                                \"nodeType\": \"Block\",\n                                \"src\": \"29891:161:6\",\n                                \"statements\": [\n                                  {\n                                    \"assignments\": [\n                                      5237\n                                    ],\n                                    \"declarations\": [\n                                      {\n                                        \"constant\": false,\n                                        \"id\": 5237,\n                                        \"mutability\": \"mutable\",\n                                        \"name\": \"next_interest\",\n                                        \"nodeType\": \"VariableDeclaration\",\n                                        \"overrides\": null,\n                                        \"scope\": 5247,\n                                        \"src\": \"29913:42:6\",\n                                        \"stateVariable\": false,\n                                        \"storageLocation\": \"storage\",\n                                        \"typeDescriptions\": {\n                                          \"typeIdentifier\": \"t_struct$_InterestRatePerBlock_$3641_storage_ptr\",\n                                          \"typeString\": \"struct Staking.InterestRatePerBlock\"\n                                        },\n                                        \"typeName\": {\n                                          \"contractScope\": null,\n                                          \"id\": 5236,\n                                          \"name\": \"InterestRatePerBlock\",\n                                          \"nodeType\": \"UserDefinedTypeName\",\n                                          \"referencedDeclaration\": 3641,\n                                          \"src\": \"29913:20:6\",\n                                          \"typeDescriptions\": {\n                                            \"typeIdentifier\": \"t_struct$_InterestRatePerBlock_$3641_storage_ptr\",\n                                            \"typeString\": \"struct Staking.InterestRatePerBlock\"\n                                          }\n                                        },\n                                        \"value\": null,\n                                        \"visibility\": \"internal\"\n                                      }\n                                    ],\n                                    \"id\": 5241,\n                                    \"initialValue\": {\n                                      \"argumentTypes\": null,\n                                      \"baseExpression\": {\n                                        \"argumentTypes\": null,\n                                        \"id\": 5238,\n                                        \"name\": \"_interestRates\",\n                                        \"nodeType\": \"Identifier\",\n                                        \"overloadedDeclarations\": [],\n                                        \"referencedDeclaration\": 3784,\n                                        \"src\": \"29958:14:6\",\n                                        \"typeDescriptions\": {\n                                          \"typeIdentifier\": \"t_mapping$_t_uint256_$_t_struct$_InterestRatePerBlock_$3641_storage_$\",\n                                          \"typeString\": \"mapping(uint256 => struct Staking.InterestRatePerBlock storage ref)\"\n                                        }\n                                      },\n                                      \"id\": 5240,\n                                      \"indexExpression\": {\n                                        \"argumentTypes\": null,\n                                        \"id\": 5239,\n                                        \"name\": \"j\",\n                                        \"nodeType\": \"Identifier\",\n                                        \"overloadedDeclarations\": [],\n                                        \"referencedDeclaration\": 5228,\n                                        \"src\": \"29973:1:6\",\n                                        \"typeDescriptions\": {\n                                          \"typeIdentifier\": \"t_uint256\",\n                                          \"typeString\": \"uint256\"\n                                        }\n                                      },\n                                      \"isConstant\": false,\n                                      \"isLValue\": true,\n                                      \"isPure\": false,\n                                      \"lValueRequested\": false,\n                                      \"nodeType\": \"IndexAccess\",\n                                      \"src\": \"29958:17:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_struct$_InterestRatePerBlock_$3641_storage\",\n                                        \"typeString\": \"struct Staking.InterestRatePerBlock storage ref\"\n                                      }\n                                    },\n                                    \"nodeType\": \"VariableDeclarationStatement\",\n                                    \"src\": \"29913:62:6\"\n                                  },\n                                  {\n                                    \"expression\": {\n                                      \"argumentTypes\": null,\n                                      \"id\": 5245,\n                                      \"isConstant\": false,\n                                      \"isLValue\": false,\n                                      \"isPure\": false,\n                                      \"lValueRequested\": false,\n                                      \"leftHandSide\": {\n                                        \"argumentTypes\": null,\n                                        \"id\": 5242,\n                                        \"name\": \"end_block\",\n                                        \"nodeType\": \"Identifier\",\n                                        \"overloadedDeclarations\": [],\n                                        \"referencedDeclaration\": 5224,\n                                        \"src\": \"29997:9:6\",\n                                        \"typeDescriptions\": {\n                                          \"typeIdentifier\": \"t_uint256\",\n                                          \"typeString\": \"uint256\"\n                                        }\n                                      },\n                                      \"nodeType\": \"Assignment\",\n                                      \"operator\": \"=\",\n                                      \"rightHandSide\": {\n                                        \"argumentTypes\": null,\n                                        \"expression\": {\n                                          \"argumentTypes\": null,\n                                          \"id\": 5243,\n                                          \"name\": \"next_interest\",\n                                          \"nodeType\": \"Identifier\",\n                                          \"overloadedDeclarations\": [],\n                                          \"referencedDeclaration\": 5237,\n                                          \"src\": \"30009:13:6\",\n                                          \"typeDescriptions\": {\n                                            \"typeIdentifier\": \"t_struct$_InterestRatePerBlock_$3641_storage_ptr\",\n                                            \"typeString\": \"struct Staking.InterestRatePerBlock storage pointer\"\n                                          }\n                                        },\n                                        \"id\": 5244,\n                                        \"isConstant\": false,\n                                        \"isLValue\": true,\n                                        \"isPure\": false,\n                                        \"lValueRequested\": false,\n                                        \"memberName\": \"sinceBlock\",\n                                        \"nodeType\": \"MemberAccess\",\n                                        \"referencedDeclaration\": 3638,\n                                        \"src\": \"30009:24:6\",\n                                        \"typeDescriptions\": {\n                                          \"typeIdentifier\": \"t_uint256\",\n                                          \"typeString\": \"uint256\"\n                                        }\n                                      },\n                                      \"src\": \"29997:36:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_uint256\",\n                                        \"typeString\": \"uint256\"\n                                      }\n                                    },\n                                    \"id\": 5246,\n                                    \"nodeType\": \"ExpressionStatement\",\n                                    \"src\": \"29997:36:6\"\n                                  }\n                                ]\n                              }\n                            },\n                            {\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"id\": 5259,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": false,\n                                \"lValueRequested\": false,\n                                \"leftHandSide\": {\n                                  \"argumentTypes\": null,\n                                  \"id\": 5249,\n                                  \"name\": \"composite\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 5184,\n                                  \"src\": \"30070:9:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_uint256\",\n                                    \"typeString\": \"uint256\"\n                                  }\n                                },\n                                \"nodeType\": \"Assignment\",\n                                \"operator\": \"=\",\n                                \"rightHandSide\": {\n                                  \"argumentTypes\": null,\n                                  \"arguments\": [\n                                    {\n                                      \"argumentTypes\": null,\n                                      \"id\": 5252,\n                                      \"name\": \"composite\",\n                                      \"nodeType\": \"Identifier\",\n                                      \"overloadedDeclarations\": [],\n                                      \"referencedDeclaration\": 5184,\n                                      \"src\": \"30107:9:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_uint256\",\n                                        \"typeString\": \"uint256\"\n                                      }\n                                    },\n                                    {\n                                      \"argumentTypes\": null,\n                                      \"expression\": {\n                                        \"argumentTypes\": null,\n                                        \"id\": 5253,\n                                        \"name\": \"interest\",\n                                        \"nodeType\": \"Identifier\",\n                                        \"overloadedDeclarations\": [],\n                                        \"referencedDeclaration\": 5210,\n                                        \"src\": \"30118:8:6\",\n                                        \"typeDescriptions\": {\n                                          \"typeIdentifier\": \"t_struct$_InterestRatePerBlock_$3641_storage_ptr\",\n                                          \"typeString\": \"struct Staking.InterestRatePerBlock storage pointer\"\n                                        }\n                                      },\n                                      \"id\": 5254,\n                                      \"isConstant\": false,\n                                      \"isLValue\": true,\n                                      \"isPure\": false,\n                                      \"lValueRequested\": false,\n                                      \"memberName\": \"rate\",\n                                      \"nodeType\": \"MemberAccess\",\n                                      \"referencedDeclaration\": 3640,\n                                      \"src\": \"30118:13:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_uint256\",\n                                        \"typeString\": \"uint256\"\n                                      }\n                                    },\n                                    {\n                                      \"argumentTypes\": null,\n                                      \"commonType\": {\n                                        \"typeIdentifier\": \"t_uint256\",\n                                        \"typeString\": \"uint256\"\n                                      },\n                                      \"id\": 5257,\n                                      \"isConstant\": false,\n                                      \"isLValue\": false,\n                                      \"isPure\": false,\n                                      \"lValueRequested\": false,\n                                      \"leftExpression\": {\n                                        \"argumentTypes\": null,\n                                        \"id\": 5255,\n                                        \"name\": \"end_block\",\n                                        \"nodeType\": \"Identifier\",\n                                        \"overloadedDeclarations\": [],\n                                        \"referencedDeclaration\": 5224,\n                                        \"src\": \"30133:9:6\",\n                                        \"typeDescriptions\": {\n                                          \"typeIdentifier\": \"t_uint256\",\n                                          \"typeString\": \"uint256\"\n                                        }\n                                      },\n                                      \"nodeType\": \"BinaryOperation\",\n                                      \"operator\": \"-\",\n                                      \"rightExpression\": {\n                                        \"argumentTypes\": null,\n                                        \"id\": 5256,\n                                        \"name\": \"start_block\",\n                                        \"nodeType\": \"Identifier\",\n                                        \"overloadedDeclarations\": [],\n                                        \"referencedDeclaration\": 5194,\n                                        \"src\": \"30145:11:6\",\n                                        \"typeDescriptions\": {\n                                          \"typeIdentifier\": \"t_uint256\",\n                                          \"typeString\": \"uint256\"\n                                        }\n                                      },\n                                      \"src\": \"30133:23:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_uint256\",\n                                        \"typeString\": \"uint256\"\n                                      }\n                                    }\n                                  ],\n                                  \"expression\": {\n                                    \"argumentTypes\": [\n                                      {\n                                        \"typeIdentifier\": \"t_uint256\",\n                                        \"typeString\": \"uint256\"\n                                      },\n                                      {\n                                        \"typeIdentifier\": \"t_uint256\",\n                                        \"typeString\": \"uint256\"\n                                      },\n                                      {\n                                        \"typeIdentifier\": \"t_uint256\",\n                                        \"typeString\": \"uint256\"\n                                      }\n                                    ],\n                                    \"expression\": {\n                                      \"argumentTypes\": null,\n                                      \"id\": 5250,\n                                      \"name\": \"Finance\",\n                                      \"nodeType\": \"Identifier\",\n                                      \"overloadedDeclarations\": [],\n                                      \"referencedDeclaration\": 3318,\n                                      \"src\": \"30082:7:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_type$_t_contract$_Finance_$3318_$\",\n                                        \"typeString\": \"type(library Finance)\"\n                                      }\n                                    },\n                                    \"id\": 5251,\n                                    \"isConstant\": false,\n                                    \"isLValue\": false,\n                                    \"isPure\": false,\n                                    \"lValueRequested\": false,\n                                    \"memberName\": \"compoundInterest\",\n                                    \"nodeType\": \"MemberAccess\",\n                                    \"referencedDeclaration\": 3249,\n                                    \"src\": \"30082:24:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_function_internal_pure$_t_uint256_$_t_uint256_$_t_uint256_$returns$_t_uint256_$\",\n                                      \"typeString\": \"function (uint256,uint256,uint256) pure returns (uint256)\"\n                                    }\n                                  },\n                                  \"id\": 5258,\n                                  \"isConstant\": false,\n                                  \"isLValue\": false,\n                                  \"isPure\": false,\n                                  \"kind\": \"functionCall\",\n                                  \"lValueRequested\": false,\n                                  \"names\": [],\n                                  \"nodeType\": \"FunctionCall\",\n                                  \"src\": \"30082:75:6\",\n                                  \"tryCall\": false,\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_uint256\",\n                                    \"typeString\": \"uint256\"\n                                  }\n                                },\n                                \"src\": \"30070:87:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              },\n                              \"id\": 5260,\n                              \"nodeType\": \"ExpressionStatement\",\n                              \"src\": \"30070:87:6\"\n                            },\n                            {\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"id\": 5263,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": false,\n                                \"lValueRequested\": false,\n                                \"leftHandSide\": {\n                                  \"argumentTypes\": null,\n                                  \"id\": 5261,\n                                  \"name\": \"start_block\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 5194,\n                                  \"src\": \"30175:11:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_uint256\",\n                                    \"typeString\": \"uint256\"\n                                  }\n                                },\n                                \"nodeType\": \"Assignment\",\n                                \"operator\": \"=\",\n                                \"rightHandSide\": {\n                                  \"argumentTypes\": null,\n                                  \"id\": 5262,\n                                  \"name\": \"end_block\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 5224,\n                                  \"src\": \"30189:9:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_uint256\",\n                                    \"typeString\": \"uint256\"\n                                  }\n                                },\n                                \"src\": \"30175:23:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              },\n                              \"id\": 5264,\n                              \"nodeType\": \"ExpressionStatement\",\n                              \"src\": \"30175:23:6\"\n                            }\n                          ]\n                        },\n                        \"condition\": {\n                          \"argumentTypes\": null,\n                          \"commonType\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          },\n                          \"id\": 5205,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"leftExpression\": {\n                            \"argumentTypes\": null,\n                            \"id\": 5203,\n                            \"name\": \"i\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 5199,\n                            \"src\": \"29379:1:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"nodeType\": \"BinaryOperation\",\n                          \"operator\": \"<\",\n                          \"rightExpression\": {\n                            \"argumentTypes\": null,\n                            \"id\": 5204,\n                            \"name\": \"_interestRatesNextIdx\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 3780,\n                            \"src\": \"29383:21:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"src\": \"29379:25:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_bool\",\n                            \"typeString\": \"bool\"\n                          }\n                        },\n                        \"id\": 5266,\n                        \"initializationExpression\": {\n                          \"assignments\": [\n                            5199\n                          ],\n                          \"declarations\": [\n                            {\n                              \"constant\": false,\n                              \"id\": 5199,\n                              \"mutability\": \"mutable\",\n                              \"name\": \"i\",\n                              \"nodeType\": \"VariableDeclaration\",\n                              \"overrides\": null,\n                              \"scope\": 5266,\n                              \"src\": \"29339:9:6\",\n                              \"stateVariable\": false,\n                              \"storageLocation\": \"default\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_uint256\",\n                                \"typeString\": \"uint256\"\n                              },\n                              \"typeName\": {\n                                \"id\": 5198,\n                                \"name\": \"uint256\",\n                                \"nodeType\": \"ElementaryTypeName\",\n                                \"src\": \"29339:7:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              },\n                              \"value\": null,\n                              \"visibility\": \"internal\"\n                            }\n                          ],\n                          \"id\": 5202,\n                          \"initialValue\": {\n                            \"argumentTypes\": null,\n                            \"expression\": {\n                              \"argumentTypes\": null,\n                              \"id\": 5200,\n                              \"name\": \"stake\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 5175,\n                              \"src\": \"29349:5:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_struct$_Stake_$3648_storage_ptr\",\n                                \"typeString\": \"struct Staking.Stake storage pointer\"\n                              }\n                            },\n                            \"id\": 5201,\n                            \"isConstant\": false,\n                            \"isLValue\": true,\n                            \"isPure\": false,\n                            \"lValueRequested\": false,\n                            \"memberName\": \"sinceInterestRateIndex\",\n                            \"nodeType\": \"MemberAccess\",\n                            \"referencedDeclaration\": 3645,\n                            \"src\": \"29349:28:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"nodeType\": \"VariableDeclarationStatement\",\n                          \"src\": \"29339:38:6\"\n                        },\n                        \"loopExpression\": {\n                          \"expression\": {\n                            \"argumentTypes\": null,\n                            \"id\": 5207,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": false,\n                            \"lValueRequested\": false,\n                            \"nodeType\": \"UnaryOperation\",\n                            \"operator\": \"++\",\n                            \"prefix\": true,\n                            \"src\": \"29406:3:6\",\n                            \"subExpression\": {\n                              \"argumentTypes\": null,\n                              \"id\": 5206,\n                              \"name\": \"i\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 5199,\n                              \"src\": \"29408:1:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_uint256\",\n                                \"typeString\": \"uint256\"\n                              }\n                            },\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"id\": 5208,\n                          \"nodeType\": \"ExpressionStatement\",\n                          \"src\": \"29406:3:6\"\n                        },\n                        \"nodeType\": \"ForStatement\",\n                        \"src\": \"29334:879:6\"\n                      },\n                      {\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 5278,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"leftHandSide\": {\n                            \"argumentTypes\": null,\n                            \"expression\": {\n                              \"argumentTypes\": null,\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"id\": 5267,\n                                \"name\": \"stake\",\n                                \"nodeType\": \"Identifier\",\n                                \"overloadedDeclarations\": [],\n                                \"referencedDeclaration\": 5175,\n                                \"src\": \"30227:5:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_struct$_Stake_$3648_storage_ptr\",\n                                  \"typeString\": \"struct Staking.Stake storage pointer\"\n                                }\n                              },\n                              \"id\": 5270,\n                              \"isConstant\": false,\n                              \"isLValue\": true,\n                              \"isPure\": false,\n                              \"lValueRequested\": false,\n                              \"memberName\": \"asset\",\n                              \"nodeType\": \"MemberAccess\",\n                              \"referencedDeclaration\": 3647,\n                              \"src\": \"30227:11:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                                \"typeString\": \"struct AssetLib.Asset storage ref\"\n                              }\n                            },\n                            \"id\": 5271,\n                            \"isConstant\": false,\n                            \"isLValue\": true,\n                            \"isPure\": false,\n                            \"lValueRequested\": true,\n                            \"memberName\": \"compoundInterest\",\n                            \"nodeType\": \"MemberAccess\",\n                            \"referencedDeclaration\": 2787,\n                            \"src\": \"30227:28:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"nodeType\": \"Assignment\",\n                          \"operator\": \"=\",\n                          \"rightHandSide\": {\n                            \"argumentTypes\": null,\n                            \"arguments\": [\n                              {\n                                \"argumentTypes\": null,\n                                \"expression\": {\n                                  \"argumentTypes\": null,\n                                  \"expression\": {\n                                    \"argumentTypes\": null,\n                                    \"id\": 5274,\n                                    \"name\": \"stake\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 5175,\n                                    \"src\": \"30272:5:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_struct$_Stake_$3648_storage_ptr\",\n                                      \"typeString\": \"struct Staking.Stake storage pointer\"\n                                    }\n                                  },\n                                  \"id\": 5275,\n                                  \"isConstant\": false,\n                                  \"isLValue\": true,\n                                  \"isPure\": false,\n                                  \"lValueRequested\": false,\n                                  \"memberName\": \"asset\",\n                                  \"nodeType\": \"MemberAccess\",\n                                  \"referencedDeclaration\": 3647,\n                                  \"src\": \"30272:11:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                                    \"typeString\": \"struct AssetLib.Asset storage ref\"\n                                  }\n                                },\n                                \"id\": 5276,\n                                \"isConstant\": false,\n                                \"isLValue\": true,\n                                \"isPure\": false,\n                                \"lValueRequested\": false,\n                                \"memberName\": \"principal\",\n                                \"nodeType\": \"MemberAccess\",\n                                \"referencedDeclaration\": 2785,\n                                \"src\": \"30272:21:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              }\n                            ],\n                            \"expression\": {\n                              \"argumentTypes\": [\n                                {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              ],\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"id\": 5272,\n                                \"name\": \"composite\",\n                                \"nodeType\": \"Identifier\",\n                                \"overloadedDeclarations\": [],\n                                \"referencedDeclaration\": 5184,\n                                \"src\": \"30258:9:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              },\n                              \"id\": 5273,\n                              \"isConstant\": false,\n                              \"isLValue\": false,\n                              \"isPure\": false,\n                              \"lValueRequested\": false,\n                              \"memberName\": \"sub\",\n                              \"nodeType\": \"MemberAccess\",\n                              \"referencedDeclaration\": 5887,\n                              \"src\": \"30258:13:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_function_internal_pure$_t_uint256_$_t_uint256_$returns$_t_uint256_$bound_to$_t_uint256_$\",\n                                \"typeString\": \"function (uint256,uint256) pure returns (uint256)\"\n                              }\n                            },\n                            \"id\": 5277,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": false,\n                            \"kind\": \"functionCall\",\n                            \"lValueRequested\": false,\n                            \"names\": [],\n                            \"nodeType\": \"FunctionCall\",\n                            \"src\": \"30258:36:6\",\n                            \"tryCall\": false,\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"src\": \"30227:67:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"id\": 5279,\n                        \"nodeType\": \"ExpressionStatement\",\n                        \"src\": \"30227:67:6\"\n                      }\n                    ]\n                  }\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 5286,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 5282,\n                        \"name\": \"stake\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 5175,\n                        \"src\": \"30315:5:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Stake_$3648_storage_ptr\",\n                          \"typeString\": \"struct Staking.Stake storage pointer\"\n                        }\n                      },\n                      \"id\": 5284,\n                      \"isConstant\": false,\n                      \"isLValue\": true,\n                      \"isPure\": false,\n                      \"lValueRequested\": true,\n                      \"memberName\": \"sinceBlock\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": 3643,\n                      \"src\": \"30315:16:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 5285,\n                      \"name\": \"at_block\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5172,\n                      \"src\": \"30334:8:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"src\": \"30315:27:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"id\": 5287,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"30315:27:6\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 5300,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 5288,\n                        \"name\": \"stake\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 5175,\n                        \"src\": \"30352:5:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Stake_$3648_storage_ptr\",\n                          \"typeString\": \"struct Staking.Stake storage pointer\"\n                        }\n                      },\n                      \"id\": 5290,\n                      \"isConstant\": false,\n                      \"isLValue\": true,\n                      \"isPure\": false,\n                      \"lValueRequested\": true,\n                      \"memberName\": \"sinceInterestRateIndex\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": 3645,\n                      \"src\": \"30352:28:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"components\": [\n                        {\n                          \"argumentTypes\": null,\n                          \"condition\": {\n                            \"argumentTypes\": null,\n                            \"commonType\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            },\n                            \"id\": 5293,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": false,\n                            \"lValueRequested\": false,\n                            \"leftExpression\": {\n                              \"argumentTypes\": null,\n                              \"id\": 5291,\n                              \"name\": \"_interestRatesNextIdx\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 3780,\n                              \"src\": \"30384:21:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_uint256\",\n                                \"typeString\": \"uint256\"\n                              }\n                            },\n                            \"nodeType\": \"BinaryOperation\",\n                            \"operator\": \"!=\",\n                            \"rightExpression\": {\n                              \"argumentTypes\": null,\n                              \"hexValue\": \"30\",\n                              \"id\": 5292,\n                              \"isConstant\": false,\n                              \"isLValue\": false,\n                              \"isPure\": true,\n                              \"kind\": \"number\",\n                              \"lValueRequested\": false,\n                              \"nodeType\": \"Literal\",\n                              \"src\": \"30409:1:6\",\n                              \"subdenomination\": null,\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_rational_0_by_1\",\n                                \"typeString\": \"int_const 0\"\n                              },\n                              \"value\": \"0\"\n                            },\n                            \"src\": \"30384:26:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_bool\",\n                              \"typeString\": \"bool\"\n                            }\n                          },\n                          \"falseExpression\": {\n                            \"argumentTypes\": null,\n                            \"hexValue\": \"30\",\n                            \"id\": 5297,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": true,\n                            \"kind\": \"number\",\n                            \"lValueRequested\": false,\n                            \"nodeType\": \"Literal\",\n                            \"src\": \"30441:1:6\",\n                            \"subdenomination\": null,\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_rational_0_by_1\",\n                              \"typeString\": \"int_const 0\"\n                            },\n                            \"value\": \"0\"\n                          },\n                          \"id\": 5298,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"nodeType\": \"Conditional\",\n                          \"src\": \"30384:58:6\",\n                          \"trueExpression\": {\n                            \"argumentTypes\": null,\n                            \"commonType\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            },\n                            \"id\": 5296,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": false,\n                            \"lValueRequested\": false,\n                            \"leftExpression\": {\n                              \"argumentTypes\": null,\n                              \"id\": 5294,\n                              \"name\": \"_interestRatesNextIdx\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 3780,\n                              \"src\": \"30413:21:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_uint256\",\n                                \"typeString\": \"uint256\"\n                              }\n                            },\n                            \"nodeType\": \"BinaryOperation\",\n                            \"operator\": \"-\",\n                            \"rightExpression\": {\n                              \"argumentTypes\": null,\n                              \"hexValue\": \"31\",\n                              \"id\": 5295,\n                              \"isConstant\": false,\n                              \"isLValue\": false,\n                              \"isPure\": true,\n                              \"kind\": \"number\",\n                              \"lValueRequested\": false,\n                              \"nodeType\": \"Literal\",\n                              \"src\": \"30437:1:6\",\n                              \"subdenomination\": null,\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_rational_1_by_1\",\n                                \"typeString\": \"int_const 1\"\n                              },\n                              \"value\": \"1\"\n                            },\n                            \"src\": \"30413:25:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        }\n                      ],\n                      \"id\": 5299,\n                      \"isConstant\": false,\n                      \"isInlineArray\": false,\n                      \"isLValue\": false,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"nodeType\": \"TupleExpression\",\n                      \"src\": \"30383:60:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"src\": \"30352:91:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"id\": 5301,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"30352:91:6\"\n                },\n                {\n                  \"eventCall\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 5303,\n                        \"name\": \"sender\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 5170,\n                        \"src\": \"31508:6:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 5304,\n                          \"name\": \"stake\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 5175,\n                          \"src\": \"31516:5:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_struct$_Stake_$3648_storage_ptr\",\n                            \"typeString\": \"struct Staking.Stake storage pointer\"\n                          }\n                        },\n                        \"id\": 5305,\n                        \"isConstant\": false,\n                        \"isLValue\": true,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"memberName\": \"sinceInterestRateIndex\",\n                        \"nodeType\": \"MemberAccess\",\n                        \"referencedDeclaration\": 3645,\n                        \"src\": \"31516:28:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"expression\": {\n                            \"argumentTypes\": null,\n                            \"id\": 5306,\n                            \"name\": \"stake\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 5175,\n                            \"src\": \"31546:5:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_struct$_Stake_$3648_storage_ptr\",\n                              \"typeString\": \"struct Staking.Stake storage pointer\"\n                            }\n                          },\n                          \"id\": 5307,\n                          \"isConstant\": false,\n                          \"isLValue\": true,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"memberName\": \"asset\",\n                          \"nodeType\": \"MemberAccess\",\n                          \"referencedDeclaration\": 3647,\n                          \"src\": \"31546:11:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                            \"typeString\": \"struct AssetLib.Asset storage ref\"\n                          }\n                        },\n                        \"id\": 5308,\n                        \"isConstant\": false,\n                        \"isLValue\": true,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"memberName\": \"principal\",\n                        \"nodeType\": \"MemberAccess\",\n                        \"referencedDeclaration\": 2785,\n                        \"src\": \"31546:21:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"expression\": {\n                            \"argumentTypes\": null,\n                            \"id\": 5309,\n                            \"name\": \"stake\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 5175,\n                            \"src\": \"31569:5:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_struct$_Stake_$3648_storage_ptr\",\n                              \"typeString\": \"struct Staking.Stake storage pointer\"\n                            }\n                          },\n                          \"id\": 5310,\n                          \"isConstant\": false,\n                          \"isLValue\": true,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"memberName\": \"asset\",\n                          \"nodeType\": \"MemberAccess\",\n                          \"referencedDeclaration\": 3647,\n                          \"src\": \"31569:11:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                            \"typeString\": \"struct AssetLib.Asset storage ref\"\n                          }\n                        },\n                        \"id\": 5311,\n                        \"isConstant\": false,\n                        \"isLValue\": true,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"memberName\": \"compoundInterest\",\n                        \"nodeType\": \"MemberAccess\",\n                        \"referencedDeclaration\": 2787,\n                        \"src\": \"31569:28:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"id\": 5302,\n                      \"name\": \"StakeCompoundInterest\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 3680,\n                      \"src\": \"31486:21:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_event_nonpayable$_t_address_$_t_uint256_$_t_uint256_$_t_uint256_$returns$__$\",\n                        \"typeString\": \"function (address,uint256,uint256,uint256)\"\n                      }\n                    },\n                    \"id\": 5312,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"31486:112:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 5313,\n                  \"nodeType\": \"EmitStatement\",\n                  \"src\": \"31481:117:6\"\n                }\n              ]\n            },\n            \"documentation\": null,\n            \"id\": 5315,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [],\n            \"name\": \"_updateStakeCompoundInterest\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 5173,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 5170,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"sender\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 5315,\n                  \"src\": \"28748:14:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_address\",\n                    \"typeString\": \"address\"\n                  },\n                  \"typeName\": {\n                    \"id\": 5169,\n                    \"name\": \"address\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"28748:7:6\",\n                    \"stateMutability\": \"nonpayable\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address\",\n                      \"typeString\": \"address\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 5172,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"at_block\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 5315,\n                  \"src\": \"28764:16:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 5171,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"28764:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"28747:34:6\"\n            },\n            \"returnParameters\": {\n              \"id\": 5176,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 5175,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"stake\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 5315,\n                  \"src\": \"28815:19:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"storage\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_struct$_Stake_$3648_storage_ptr\",\n                    \"typeString\": \"struct Staking.Stake\"\n                  },\n                  \"typeName\": {\n                    \"contractScope\": null,\n                    \"id\": 5174,\n                    \"name\": \"Stake\",\n                    \"nodeType\": \"UserDefinedTypeName\",\n                    \"referencedDeclaration\": 3648,\n                    \"src\": \"28815:5:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_struct$_Stake_$3648_storage_ptr\",\n                      \"typeString\": \"struct Staking.Stake\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"28814:21:6\"\n            },\n            \"scope\": 5490,\n            \"src\": \"28710:2895:6\",\n            \"stateMutability\": \"nonpayable\",\n            \"virtual\": false,\n            \"visibility\": \"internal\"\n          },\n          {\n            \"body\": {\n              \"id\": 5488,\n              \"nodeType\": \"Block\",\n              \"src\": \"31801:2505:6\",\n              \"statements\": [\n                {\n                  \"assignments\": [\n                    5329\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 5329,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"locked\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 5488,\n                      \"src\": \"31811:21:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"storage\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_struct$_Locked_$3659_storage_ptr\",\n                        \"typeString\": \"struct Staking.Locked\"\n                      },\n                      \"typeName\": {\n                        \"contractScope\": null,\n                        \"id\": 5328,\n                        \"name\": \"Locked\",\n                        \"nodeType\": \"UserDefinedTypeName\",\n                        \"referencedDeclaration\": 3659,\n                        \"src\": \"31811:6:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Locked_$3659_storage_ptr\",\n                          \"typeString\": \"struct Staking.Locked\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 5333,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"baseExpression\": {\n                      \"argumentTypes\": null,\n                      \"id\": 5330,\n                      \"name\": \"_locked\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 3792,\n                      \"src\": \"31835:7:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_mapping$_t_address_$_t_struct$_Locked_$3659_storage_$\",\n                        \"typeString\": \"mapping(address => struct Staking.Locked storage ref)\"\n                      }\n                    },\n                    \"id\": 5332,\n                    \"indexExpression\": {\n                      \"argumentTypes\": null,\n                      \"id\": 5331,\n                      \"name\": \"sender\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5317,\n                      \"src\": \"31843:6:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_address\",\n                        \"typeString\": \"address\"\n                      }\n                    },\n                    \"isConstant\": false,\n                    \"isLValue\": true,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"nodeType\": \"IndexAccess\",\n                    \"src\": \"31835:15:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_struct$_Locked_$3659_storage\",\n                      \"typeString\": \"struct Staking.Locked storage ref\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"31811:39:6\"\n                },\n                {\n                  \"assignments\": [\n                    5337\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 5337,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"lockedAssets\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 5488,\n                      \"src\": \"31860:34:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"storage\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_array$_t_struct$_LockedAsset_$3653_storage_$dyn_storage_ptr\",\n                        \"typeString\": \"struct Staking.LockedAsset[]\"\n                      },\n                      \"typeName\": {\n                        \"baseType\": {\n                          \"contractScope\": null,\n                          \"id\": 5335,\n                          \"name\": \"LockedAsset\",\n                          \"nodeType\": \"UserDefinedTypeName\",\n                          \"referencedDeclaration\": 3653,\n                          \"src\": \"31860:11:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_struct$_LockedAsset_$3653_storage_ptr\",\n                            \"typeString\": \"struct Staking.LockedAsset\"\n                          }\n                        },\n                        \"id\": 5336,\n                        \"length\": null,\n                        \"nodeType\": \"ArrayTypeName\",\n                        \"src\": \"31860:13:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_array$_t_struct$_LockedAsset_$3653_storage_$dyn_storage_ptr\",\n                          \"typeString\": \"struct Staking.LockedAsset[]\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 5340,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"expression\": {\n                      \"argumentTypes\": null,\n                      \"id\": 5338,\n                      \"name\": \"locked\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5329,\n                      \"src\": \"31897:6:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_struct$_Locked_$3659_storage_ptr\",\n                        \"typeString\": \"struct Staking.Locked storage pointer\"\n                      }\n                    },\n                    \"id\": 5339,\n                    \"isConstant\": false,\n                    \"isLValue\": true,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"memberName\": \"assets\",\n                    \"nodeType\": \"MemberAccess\",\n                    \"referencedDeclaration\": 3658,\n                    \"src\": \"31897:13:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_array$_t_struct$_LockedAsset_$3653_storage_$dyn_storage\",\n                      \"typeString\": \"struct Staking.LockedAsset storage ref[] storage ref\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"31860:50:6\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 5345,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 5341,\n                      \"name\": \"liquidity\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5324,\n                      \"src\": \"31920:9:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                        \"typeString\": \"struct AssetLib.Asset storage pointer\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"baseExpression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 5342,\n                        \"name\": \"_liquidity\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 3796,\n                        \"src\": \"31932:10:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_mapping$_t_address_$_t_struct$_Asset_$2788_storage_$\",\n                          \"typeString\": \"mapping(address => struct AssetLib.Asset storage ref)\"\n                        }\n                      },\n                      \"id\": 5344,\n                      \"indexExpression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 5343,\n                        \"name\": \"sender\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 5317,\n                        \"src\": \"31943:6:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        }\n                      },\n                      \"isConstant\": false,\n                      \"isLValue\": true,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"nodeType\": \"IndexAccess\",\n                      \"src\": \"31932:18:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                        \"typeString\": \"struct AssetLib.Asset storage ref\"\n                      }\n                    },\n                    \"src\": \"31920:30:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                      \"typeString\": \"struct AssetLib.Asset storage pointer\"\n                    }\n                  },\n                  \"id\": 5346,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"31920:30:6\"\n                },\n                {\n                  \"body\": {\n                    \"id\": 5420,\n                    \"nodeType\": \"Block\",\n                    \"src\": \"32006:1628:6\",\n                    \"statements\": [\n                      {\n                        \"assignments\": [\n                          5356\n                        ],\n                        \"declarations\": [\n                          {\n                            \"constant\": false,\n                            \"id\": 5356,\n                            \"mutability\": \"mutable\",\n                            \"name\": \"l\",\n                            \"nodeType\": \"VariableDeclaration\",\n                            \"overrides\": null,\n                            \"scope\": 5420,\n                            \"src\": \"32020:20:6\",\n                            \"stateVariable\": false,\n                            \"storageLocation\": \"memory\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_struct$_LockedAsset_$3653_memory_ptr\",\n                              \"typeString\": \"struct Staking.LockedAsset\"\n                            },\n                            \"typeName\": {\n                              \"contractScope\": null,\n                              \"id\": 5355,\n                              \"name\": \"LockedAsset\",\n                              \"nodeType\": \"UserDefinedTypeName\",\n                              \"referencedDeclaration\": 3653,\n                              \"src\": \"32020:11:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_struct$_LockedAsset_$3653_storage_ptr\",\n                                \"typeString\": \"struct Staking.LockedAsset\"\n                              }\n                            },\n                            \"value\": null,\n                            \"visibility\": \"internal\"\n                          }\n                        ],\n                        \"id\": 5360,\n                        \"initialValue\": {\n                          \"argumentTypes\": null,\n                          \"baseExpression\": {\n                            \"argumentTypes\": null,\n                            \"id\": 5357,\n                            \"name\": \"lockedAssets\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 5337,\n                            \"src\": \"32043:12:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_array$_t_struct$_LockedAsset_$3653_storage_$dyn_storage_ptr\",\n                              \"typeString\": \"struct Staking.LockedAsset storage ref[] storage pointer\"\n                            }\n                          },\n                          \"id\": 5359,\n                          \"indexExpression\": {\n                            \"argumentTypes\": null,\n                            \"id\": 5358,\n                            \"name\": \"i\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 5348,\n                            \"src\": \"32056:1:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"isConstant\": false,\n                          \"isLValue\": true,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"nodeType\": \"IndexAccess\",\n                          \"src\": \"32043:15:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_struct$_LockedAsset_$3653_storage\",\n                            \"typeString\": \"struct Staking.LockedAsset storage ref\"\n                          }\n                        },\n                        \"nodeType\": \"VariableDeclarationStatement\",\n                        \"src\": \"32020:38:6\"\n                      },\n                      {\n                        \"condition\": {\n                          \"argumentTypes\": null,\n                          \"commonType\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          },\n                          \"id\": 5364,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"leftExpression\": {\n                            \"argumentTypes\": null,\n                            \"expression\": {\n                              \"argumentTypes\": null,\n                              \"id\": 5361,\n                              \"name\": \"l\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 5356,\n                              \"src\": \"32077:1:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_struct$_LockedAsset_$3653_memory_ptr\",\n                                \"typeString\": \"struct Staking.LockedAsset memory\"\n                              }\n                            },\n                            \"id\": 5362,\n                            \"isConstant\": false,\n                            \"isLValue\": true,\n                            \"isPure\": false,\n                            \"lValueRequested\": false,\n                            \"memberName\": \"liquidSinceBlock\",\n                            \"nodeType\": \"MemberAccess\",\n                            \"referencedDeclaration\": 3650,\n                            \"src\": \"32077:18:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"nodeType\": \"BinaryOperation\",\n                          \"operator\": \">\",\n                          \"rightExpression\": {\n                            \"argumentTypes\": null,\n                            \"id\": 5363,\n                            \"name\": \"at_block\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 5319,\n                            \"src\": \"32098:8:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"src\": \"32077:29:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_bool\",\n                            \"typeString\": \"bool\"\n                          }\n                        },\n                        \"falseBody\": null,\n                        \"id\": 5370,\n                        \"nodeType\": \"IfStatement\",\n                        \"src\": \"32073:191:6\",\n                        \"trueBody\": {\n                          \"id\": 5369,\n                          \"nodeType\": \"Block\",\n                          \"src\": \"32108:156:6\",\n                          \"statements\": [\n                            {\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"id\": 5366,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": false,\n                                \"lValueRequested\": false,\n                                \"nodeType\": \"UnaryOperation\",\n                                \"operator\": \"++\",\n                                \"prefix\": true,\n                                \"src\": \"32126:3:6\",\n                                \"subExpression\": {\n                                  \"argumentTypes\": null,\n                                  \"id\": 5365,\n                                  \"name\": \"i\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 5348,\n                                  \"src\": \"32128:1:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_uint256\",\n                                    \"typeString\": \"uint256\"\n                                  }\n                                },\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              },\n                              \"id\": 5367,\n                              \"nodeType\": \"ExpressionStatement\",\n                              \"src\": \"32126:3:6\"\n                            },\n                            {\n                              \"id\": 5368,\n                              \"nodeType\": \"Continue\",\n                              \"src\": \"32241:8:6\"\n                            }\n                          ]\n                        }\n                      },\n                      {\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 5381,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"leftHandSide\": {\n                            \"argumentTypes\": null,\n                            \"expression\": {\n                              \"argumentTypes\": null,\n                              \"id\": 5371,\n                              \"name\": \"unlockedLiquidity\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 5322,\n                              \"src\": \"32278:17:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                \"typeString\": \"struct AssetLib.Asset memory\"\n                              }\n                            },\n                            \"id\": 5373,\n                            \"isConstant\": false,\n                            \"isLValue\": true,\n                            \"isPure\": false,\n                            \"lValueRequested\": true,\n                            \"memberName\": \"principal\",\n                            \"nodeType\": \"MemberAccess\",\n                            \"referencedDeclaration\": 2785,\n                            \"src\": \"32278:27:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"nodeType\": \"Assignment\",\n                          \"operator\": \"=\",\n                          \"rightHandSide\": {\n                            \"argumentTypes\": null,\n                            \"arguments\": [\n                              {\n                                \"argumentTypes\": null,\n                                \"expression\": {\n                                  \"argumentTypes\": null,\n                                  \"expression\": {\n                                    \"argumentTypes\": null,\n                                    \"id\": 5377,\n                                    \"name\": \"l\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 5356,\n                                    \"src\": \"32340:1:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_struct$_LockedAsset_$3653_memory_ptr\",\n                                      \"typeString\": \"struct Staking.LockedAsset memory\"\n                                    }\n                                  },\n                                  \"id\": 5378,\n                                  \"isConstant\": false,\n                                  \"isLValue\": true,\n                                  \"isPure\": false,\n                                  \"lValueRequested\": false,\n                                  \"memberName\": \"asset\",\n                                  \"nodeType\": \"MemberAccess\",\n                                  \"referencedDeclaration\": 3652,\n                                  \"src\": \"32340:7:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                    \"typeString\": \"struct AssetLib.Asset memory\"\n                                  }\n                                },\n                                \"id\": 5379,\n                                \"isConstant\": false,\n                                \"isLValue\": true,\n                                \"isPure\": false,\n                                \"lValueRequested\": false,\n                                \"memberName\": \"principal\",\n                                \"nodeType\": \"MemberAccess\",\n                                \"referencedDeclaration\": 2785,\n                                \"src\": \"32340:17:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              }\n                            ],\n                            \"expression\": {\n                              \"argumentTypes\": [\n                                {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              ],\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"expression\": {\n                                  \"argumentTypes\": null,\n                                  \"id\": 5374,\n                                  \"name\": \"unlockedLiquidity\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 5322,\n                                  \"src\": \"32308:17:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                    \"typeString\": \"struct AssetLib.Asset memory\"\n                                  }\n                                },\n                                \"id\": 5375,\n                                \"isConstant\": false,\n                                \"isLValue\": true,\n                                \"isPure\": false,\n                                \"lValueRequested\": false,\n                                \"memberName\": \"principal\",\n                                \"nodeType\": \"MemberAccess\",\n                                \"referencedDeclaration\": 2785,\n                                \"src\": \"32308:27:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              },\n                              \"id\": 5376,\n                              \"isConstant\": false,\n                              \"isLValue\": false,\n                              \"isPure\": false,\n                              \"lValueRequested\": false,\n                              \"memberName\": \"add\",\n                              \"nodeType\": \"MemberAccess\",\n                              \"referencedDeclaration\": 5870,\n                              \"src\": \"32308:31:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_function_internal_pure$_t_uint256_$_t_uint256_$returns$_t_uint256_$bound_to$_t_uint256_$\",\n                                \"typeString\": \"function (uint256,uint256) pure returns (uint256)\"\n                              }\n                            },\n                            \"id\": 5380,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": false,\n                            \"kind\": \"functionCall\",\n                            \"lValueRequested\": false,\n                            \"names\": [],\n                            \"nodeType\": \"FunctionCall\",\n                            \"src\": \"32308:50:6\",\n                            \"tryCall\": false,\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"src\": \"32278:80:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"id\": 5382,\n                        \"nodeType\": \"ExpressionStatement\",\n                        \"src\": \"32278:80:6\"\n                      },\n                      {\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 5393,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"leftHandSide\": {\n                            \"argumentTypes\": null,\n                            \"expression\": {\n                              \"argumentTypes\": null,\n                              \"id\": 5383,\n                              \"name\": \"unlockedLiquidity\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 5322,\n                              \"src\": \"32576:17:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                \"typeString\": \"struct AssetLib.Asset memory\"\n                              }\n                            },\n                            \"id\": 5385,\n                            \"isConstant\": false,\n                            \"isLValue\": true,\n                            \"isPure\": false,\n                            \"lValueRequested\": true,\n                            \"memberName\": \"compoundInterest\",\n                            \"nodeType\": \"MemberAccess\",\n                            \"referencedDeclaration\": 2787,\n                            \"src\": \"32576:34:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"nodeType\": \"Assignment\",\n                          \"operator\": \"=\",\n                          \"rightHandSide\": {\n                            \"argumentTypes\": null,\n                            \"arguments\": [\n                              {\n                                \"argumentTypes\": null,\n                                \"expression\": {\n                                  \"argumentTypes\": null,\n                                  \"expression\": {\n                                    \"argumentTypes\": null,\n                                    \"id\": 5389,\n                                    \"name\": \"l\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 5356,\n                                    \"src\": \"32652:1:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_struct$_LockedAsset_$3653_memory_ptr\",\n                                      \"typeString\": \"struct Staking.LockedAsset memory\"\n                                    }\n                                  },\n                                  \"id\": 5390,\n                                  \"isConstant\": false,\n                                  \"isLValue\": true,\n                                  \"isPure\": false,\n                                  \"lValueRequested\": false,\n                                  \"memberName\": \"asset\",\n                                  \"nodeType\": \"MemberAccess\",\n                                  \"referencedDeclaration\": 3652,\n                                  \"src\": \"32652:7:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                    \"typeString\": \"struct AssetLib.Asset memory\"\n                                  }\n                                },\n                                \"id\": 5391,\n                                \"isConstant\": false,\n                                \"isLValue\": true,\n                                \"isPure\": false,\n                                \"lValueRequested\": false,\n                                \"memberName\": \"compoundInterest\",\n                                \"nodeType\": \"MemberAccess\",\n                                \"referencedDeclaration\": 2787,\n                                \"src\": \"32652:24:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              }\n                            ],\n                            \"expression\": {\n                              \"argumentTypes\": [\n                                {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              ],\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"expression\": {\n                                  \"argumentTypes\": null,\n                                  \"id\": 5386,\n                                  \"name\": \"unlockedLiquidity\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 5322,\n                                  \"src\": \"32613:17:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                    \"typeString\": \"struct AssetLib.Asset memory\"\n                                  }\n                                },\n                                \"id\": 5387,\n                                \"isConstant\": false,\n                                \"isLValue\": true,\n                                \"isPure\": false,\n                                \"lValueRequested\": false,\n                                \"memberName\": \"compoundInterest\",\n                                \"nodeType\": \"MemberAccess\",\n                                \"referencedDeclaration\": 2787,\n                                \"src\": \"32613:34:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              },\n                              \"id\": 5388,\n                              \"isConstant\": false,\n                              \"isLValue\": false,\n                              \"isPure\": false,\n                              \"lValueRequested\": false,\n                              \"memberName\": \"add\",\n                              \"nodeType\": \"MemberAccess\",\n                              \"referencedDeclaration\": 5870,\n                              \"src\": \"32613:38:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_function_internal_pure$_t_uint256_$_t_uint256_$returns$_t_uint256_$bound_to$_t_uint256_$\",\n                                \"typeString\": \"function (uint256,uint256) pure returns (uint256)\"\n                              }\n                            },\n                            \"id\": 5392,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": false,\n                            \"kind\": \"functionCall\",\n                            \"lValueRequested\": false,\n                            \"names\": [],\n                            \"nodeType\": \"FunctionCall\",\n                            \"src\": \"32613:64:6\",\n                            \"tryCall\": false,\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"src\": \"32576:101:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"id\": 5394,\n                        \"nodeType\": \"ExpressionStatement\",\n                        \"src\": \"32576:101:6\"\n                      },\n                      {\n                        \"assignments\": [\n                          5396\n                        ],\n                        \"declarations\": [\n                          {\n                            \"constant\": false,\n                            \"id\": 5396,\n                            \"mutability\": \"mutable\",\n                            \"name\": \"last_idx\",\n                            \"nodeType\": \"VariableDeclaration\",\n                            \"overrides\": null,\n                            \"scope\": 5420,\n                            \"src\": \"32959:16:6\",\n                            \"stateVariable\": false,\n                            \"storageLocation\": \"default\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            },\n                            \"typeName\": {\n                              \"id\": 5395,\n                              \"name\": \"uint256\",\n                              \"nodeType\": \"ElementaryTypeName\",\n                              \"src\": \"32959:7:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_uint256\",\n                                \"typeString\": \"uint256\"\n                              }\n                            },\n                            \"value\": null,\n                            \"visibility\": \"internal\"\n                          }\n                        ],\n                        \"id\": 5401,\n                        \"initialValue\": {\n                          \"argumentTypes\": null,\n                          \"commonType\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          },\n                          \"id\": 5400,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"leftExpression\": {\n                            \"argumentTypes\": null,\n                            \"expression\": {\n                              \"argumentTypes\": null,\n                              \"id\": 5397,\n                              \"name\": \"lockedAssets\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 5337,\n                              \"src\": \"32978:12:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_array$_t_struct$_LockedAsset_$3653_storage_$dyn_storage_ptr\",\n                                \"typeString\": \"struct Staking.LockedAsset storage ref[] storage pointer\"\n                              }\n                            },\n                            \"id\": 5398,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": false,\n                            \"lValueRequested\": false,\n                            \"memberName\": \"length\",\n                            \"nodeType\": \"MemberAccess\",\n                            \"referencedDeclaration\": null,\n                            \"src\": \"32978:19:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"nodeType\": \"BinaryOperation\",\n                          \"operator\": \"-\",\n                          \"rightExpression\": {\n                            \"argumentTypes\": null,\n                            \"hexValue\": \"31\",\n                            \"id\": 5399,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": true,\n                            \"kind\": \"number\",\n                            \"lValueRequested\": false,\n                            \"nodeType\": \"Literal\",\n                            \"src\": \"33000:1:6\",\n                            \"subdenomination\": null,\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_rational_1_by_1\",\n                              \"typeString\": \"int_const 1\"\n                            },\n                            \"value\": \"1\"\n                          },\n                          \"src\": \"32978:23:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"nodeType\": \"VariableDeclarationStatement\",\n                        \"src\": \"32959:42:6\"\n                      },\n                      {\n                        \"condition\": {\n                          \"argumentTypes\": null,\n                          \"commonType\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          },\n                          \"id\": 5404,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"leftExpression\": {\n                            \"argumentTypes\": null,\n                            \"id\": 5402,\n                            \"name\": \"i\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 5348,\n                            \"src\": \"33019:1:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"nodeType\": \"BinaryOperation\",\n                          \"operator\": \"!=\",\n                          \"rightExpression\": {\n                            \"argumentTypes\": null,\n                            \"id\": 5403,\n                            \"name\": \"last_idx\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 5396,\n                            \"src\": \"33024:8:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"src\": \"33019:13:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_bool\",\n                            \"typeString\": \"bool\"\n                          }\n                        },\n                        \"falseBody\": null,\n                        \"id\": 5414,\n                        \"nodeType\": \"IfStatement\",\n                        \"src\": \"33015:92:6\",\n                        \"trueBody\": {\n                          \"id\": 5413,\n                          \"nodeType\": \"Block\",\n                          \"src\": \"33034:73:6\",\n                          \"statements\": [\n                            {\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"id\": 5411,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": false,\n                                \"lValueRequested\": false,\n                                \"leftHandSide\": {\n                                  \"argumentTypes\": null,\n                                  \"baseExpression\": {\n                                    \"argumentTypes\": null,\n                                    \"id\": 5405,\n                                    \"name\": \"lockedAssets\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 5337,\n                                    \"src\": \"33052:12:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_array$_t_struct$_LockedAsset_$3653_storage_$dyn_storage_ptr\",\n                                      \"typeString\": \"struct Staking.LockedAsset storage ref[] storage pointer\"\n                                    }\n                                  },\n                                  \"id\": 5407,\n                                  \"indexExpression\": {\n                                    \"argumentTypes\": null,\n                                    \"id\": 5406,\n                                    \"name\": \"i\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 5348,\n                                    \"src\": \"33065:1:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    }\n                                  },\n                                  \"isConstant\": false,\n                                  \"isLValue\": true,\n                                  \"isPure\": false,\n                                  \"lValueRequested\": true,\n                                  \"nodeType\": \"IndexAccess\",\n                                  \"src\": \"33052:15:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_struct$_LockedAsset_$3653_storage\",\n                                    \"typeString\": \"struct Staking.LockedAsset storage ref\"\n                                  }\n                                },\n                                \"nodeType\": \"Assignment\",\n                                \"operator\": \"=\",\n                                \"rightHandSide\": {\n                                  \"argumentTypes\": null,\n                                  \"baseExpression\": {\n                                    \"argumentTypes\": null,\n                                    \"id\": 5408,\n                                    \"name\": \"lockedAssets\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 5337,\n                                    \"src\": \"33070:12:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_array$_t_struct$_LockedAsset_$3653_storage_$dyn_storage_ptr\",\n                                      \"typeString\": \"struct Staking.LockedAsset storage ref[] storage pointer\"\n                                    }\n                                  },\n                                  \"id\": 5410,\n                                  \"indexExpression\": {\n                                    \"argumentTypes\": null,\n                                    \"id\": 5409,\n                                    \"name\": \"last_idx\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 5396,\n                                    \"src\": \"33083:8:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    }\n                                  },\n                                  \"isConstant\": false,\n                                  \"isLValue\": true,\n                                  \"isPure\": false,\n                                  \"lValueRequested\": false,\n                                  \"nodeType\": \"IndexAccess\",\n                                  \"src\": \"33070:22:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_struct$_LockedAsset_$3653_storage\",\n                                    \"typeString\": \"struct Staking.LockedAsset storage ref\"\n                                  }\n                                },\n                                \"src\": \"33052:40:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_struct$_LockedAsset_$3653_storage\",\n                                  \"typeString\": \"struct Staking.LockedAsset storage ref\"\n                                }\n                              },\n                              \"id\": 5412,\n                              \"nodeType\": \"ExpressionStatement\",\n                              \"src\": \"33052:40:6\"\n                            }\n                          ]\n                        }\n                      },\n                      {\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"arguments\": [],\n                          \"expression\": {\n                            \"argumentTypes\": [],\n                            \"expression\": {\n                              \"argumentTypes\": null,\n                              \"id\": 5415,\n                              \"name\": \"lockedAssets\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 5337,\n                              \"src\": \"33605:12:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_array$_t_struct$_LockedAsset_$3653_storage_$dyn_storage_ptr\",\n                                \"typeString\": \"struct Staking.LockedAsset storage ref[] storage pointer\"\n                              }\n                            },\n                            \"id\": 5417,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": false,\n                            \"lValueRequested\": false,\n                            \"memberName\": \"pop\",\n                            \"nodeType\": \"MemberAccess\",\n                            \"referencedDeclaration\": null,\n                            \"src\": \"33605:16:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_function_arraypop_nonpayable$__$returns$__$\",\n                              \"typeString\": \"function ()\"\n                            }\n                          },\n                          \"id\": 5418,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"kind\": \"functionCall\",\n                          \"lValueRequested\": false,\n                          \"names\": [],\n                          \"nodeType\": \"FunctionCall\",\n                          \"src\": \"33605:18:6\",\n                          \"tryCall\": false,\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_tuple$__$\",\n                            \"typeString\": \"tuple()\"\n                          }\n                        },\n                        \"id\": 5419,\n                        \"nodeType\": \"ExpressionStatement\",\n                        \"src\": \"33605:18:6\"\n                      }\n                    ]\n                  },\n                  \"condition\": {\n                    \"argumentTypes\": null,\n                    \"commonType\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    },\n                    \"id\": 5354,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftExpression\": {\n                      \"argumentTypes\": null,\n                      \"id\": 5351,\n                      \"name\": \"i\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5348,\n                      \"src\": \"31979:1:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"BinaryOperation\",\n                    \"operator\": \"<\",\n                    \"rightExpression\": {\n                      \"argumentTypes\": null,\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 5352,\n                        \"name\": \"lockedAssets\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 5337,\n                        \"src\": \"31983:12:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_array$_t_struct$_LockedAsset_$3653_storage_$dyn_storage_ptr\",\n                          \"typeString\": \"struct Staking.LockedAsset storage ref[] storage pointer\"\n                        }\n                      },\n                      \"id\": 5353,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"memberName\": \"length\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": null,\n                      \"src\": \"31983:19:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"src\": \"31979:23:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_bool\",\n                      \"typeString\": \"bool\"\n                    }\n                  },\n                  \"id\": 5421,\n                  \"initializationExpression\": {\n                    \"assignments\": [\n                      5348\n                    ],\n                    \"declarations\": [\n                      {\n                        \"constant\": false,\n                        \"id\": 5348,\n                        \"mutability\": \"mutable\",\n                        \"name\": \"i\",\n                        \"nodeType\": \"VariableDeclaration\",\n                        \"overrides\": null,\n                        \"scope\": 5421,\n                        \"src\": \"31966:9:6\",\n                        \"stateVariable\": false,\n                        \"storageLocation\": \"default\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        },\n                        \"typeName\": {\n                          \"id\": 5347,\n                          \"name\": \"uint256\",\n                          \"nodeType\": \"ElementaryTypeName\",\n                          \"src\": \"31966:7:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"value\": null,\n                        \"visibility\": \"internal\"\n                      }\n                    ],\n                    \"id\": 5350,\n                    \"initialValue\": {\n                      \"argumentTypes\": null,\n                      \"hexValue\": \"30\",\n                      \"id\": 5349,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": true,\n                      \"kind\": \"number\",\n                      \"lValueRequested\": false,\n                      \"nodeType\": \"Literal\",\n                      \"src\": \"31976:1:6\",\n                      \"subdenomination\": null,\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_rational_0_by_1\",\n                        \"typeString\": \"int_const 0\"\n                      },\n                      \"value\": \"0\"\n                    },\n                    \"nodeType\": \"VariableDeclarationStatement\",\n                    \"src\": \"31966:11:6\"\n                  },\n                  \"loopExpression\": null,\n                  \"nodeType\": \"ForStatement\",\n                  \"src\": \"31961:1673:6\"\n                },\n                {\n                  \"condition\": {\n                    \"argumentTypes\": null,\n                    \"commonType\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    },\n                    \"id\": 5425,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftExpression\": {\n                      \"argumentTypes\": null,\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 5422,\n                        \"name\": \"lockedAssets\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 5337,\n                        \"src\": \"33699:12:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_array$_t_struct$_LockedAsset_$3653_storage_$dyn_storage_ptr\",\n                          \"typeString\": \"struct Staking.LockedAsset storage ref[] storage pointer\"\n                        }\n                      },\n                      \"id\": 5423,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"memberName\": \"length\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": null,\n                      \"src\": \"33699:19:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"BinaryOperation\",\n                    \"operator\": \"==\",\n                    \"rightExpression\": {\n                      \"argumentTypes\": null,\n                      \"hexValue\": \"30\",\n                      \"id\": 5424,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": true,\n                      \"kind\": \"number\",\n                      \"lValueRequested\": false,\n                      \"nodeType\": \"Literal\",\n                      \"src\": \"33722:1:6\",\n                      \"subdenomination\": null,\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_rational_0_by_1\",\n                        \"typeString\": \"int_const 0\"\n                      },\n                      \"value\": \"0\"\n                    },\n                    \"src\": \"33699:24:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_bool\",\n                      \"typeString\": \"bool\"\n                    }\n                  },\n                  \"falseBody\": null,\n                  \"id\": 5432,\n                  \"nodeType\": \"IfStatement\",\n                  \"src\": \"33695:77:6\",\n                  \"trueBody\": {\n                    \"id\": 5431,\n                    \"nodeType\": \"Block\",\n                    \"src\": \"33725:47:6\",\n                    \"statements\": [\n                      {\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 5429,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"nodeType\": \"UnaryOperation\",\n                          \"operator\": \"delete\",\n                          \"prefix\": true,\n                          \"src\": \"33739:22:6\",\n                          \"subExpression\": {\n                            \"argumentTypes\": null,\n                            \"baseExpression\": {\n                              \"argumentTypes\": null,\n                              \"id\": 5426,\n                              \"name\": \"_locked\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 3792,\n                              \"src\": \"33746:7:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_mapping$_t_address_$_t_struct$_Locked_$3659_storage_$\",\n                                \"typeString\": \"mapping(address => struct Staking.Locked storage ref)\"\n                              }\n                            },\n                            \"id\": 5428,\n                            \"indexExpression\": {\n                              \"argumentTypes\": null,\n                              \"id\": 5427,\n                              \"name\": \"sender\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 5317,\n                              \"src\": \"33754:6:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_address\",\n                                \"typeString\": \"address\"\n                              }\n                            },\n                            \"isConstant\": false,\n                            \"isLValue\": true,\n                            \"isPure\": false,\n                            \"lValueRequested\": true,\n                            \"nodeType\": \"IndexAccess\",\n                            \"src\": \"33746:15:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_struct$_Locked_$3659_storage\",\n                              \"typeString\": \"struct Staking.Locked storage ref\"\n                            }\n                          },\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_tuple$__$\",\n                            \"typeString\": \"tuple()\"\n                          }\n                        },\n                        \"id\": 5430,\n                        \"nodeType\": \"ExpressionStatement\",\n                        \"src\": \"33739:22:6\"\n                      }\n                    ]\n                  }\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 5443,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 5433,\n                      \"name\": \"collected\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5326,\n                      \"src\": \"33782:9:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_bool\",\n                        \"typeString\": \"bool\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"commonType\": {\n                        \"typeIdentifier\": \"t_bool\",\n                        \"typeString\": \"bool\"\n                      },\n                      \"id\": 5442,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"leftExpression\": {\n                        \"argumentTypes\": null,\n                        \"commonType\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        },\n                        \"id\": 5437,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"leftExpression\": {\n                          \"argumentTypes\": null,\n                          \"expression\": {\n                            \"argumentTypes\": null,\n                            \"id\": 5434,\n                            \"name\": \"unlockedLiquidity\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 5322,\n                            \"src\": \"33794:17:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                              \"typeString\": \"struct AssetLib.Asset memory\"\n                            }\n                          },\n                          \"id\": 5435,\n                          \"isConstant\": false,\n                          \"isLValue\": true,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"memberName\": \"principal\",\n                          \"nodeType\": \"MemberAccess\",\n                          \"referencedDeclaration\": 2785,\n                          \"src\": \"33794:27:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"nodeType\": \"BinaryOperation\",\n                        \"operator\": \"!=\",\n                        \"rightExpression\": {\n                          \"argumentTypes\": null,\n                          \"hexValue\": \"30\",\n                          \"id\": 5436,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": true,\n                          \"kind\": \"number\",\n                          \"lValueRequested\": false,\n                          \"nodeType\": \"Literal\",\n                          \"src\": \"33825:1:6\",\n                          \"subdenomination\": null,\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_rational_0_by_1\",\n                            \"typeString\": \"int_const 0\"\n                          },\n                          \"value\": \"0\"\n                        },\n                        \"src\": \"33794:32:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        }\n                      },\n                      \"nodeType\": \"BinaryOperation\",\n                      \"operator\": \"||\",\n                      \"rightExpression\": {\n                        \"argumentTypes\": null,\n                        \"commonType\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        },\n                        \"id\": 5441,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"leftExpression\": {\n                          \"argumentTypes\": null,\n                          \"expression\": {\n                            \"argumentTypes\": null,\n                            \"id\": 5438,\n                            \"name\": \"unlockedLiquidity\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 5322,\n                            \"src\": \"33830:17:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                              \"typeString\": \"struct AssetLib.Asset memory\"\n                            }\n                          },\n                          \"id\": 5439,\n                          \"isConstant\": false,\n                          \"isLValue\": true,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"memberName\": \"compoundInterest\",\n                          \"nodeType\": \"MemberAccess\",\n                          \"referencedDeclaration\": 2787,\n                          \"src\": \"33830:34:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"nodeType\": \"BinaryOperation\",\n                        \"operator\": \"!=\",\n                        \"rightExpression\": {\n                          \"argumentTypes\": null,\n                          \"hexValue\": \"30\",\n                          \"id\": 5440,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": true,\n                          \"kind\": \"number\",\n                          \"lValueRequested\": false,\n                          \"nodeType\": \"Literal\",\n                          \"src\": \"33868:1:6\",\n                          \"subdenomination\": null,\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_rational_0_by_1\",\n                            \"typeString\": \"int_const 0\"\n                          },\n                          \"value\": \"0\"\n                        },\n                        \"src\": \"33830:39:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        }\n                      },\n                      \"src\": \"33794:75:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_bool\",\n                        \"typeString\": \"bool\"\n                      }\n                    },\n                    \"src\": \"33782:87:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_bool\",\n                      \"typeString\": \"bool\"\n                    }\n                  },\n                  \"id\": 5444,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"33782:87:6\"\n                },\n                {\n                  \"condition\": {\n                    \"argumentTypes\": null,\n                    \"id\": 5445,\n                    \"name\": \"collected\",\n                    \"nodeType\": \"Identifier\",\n                    \"overloadedDeclarations\": [],\n                    \"referencedDeclaration\": 5326,\n                    \"src\": \"33883:9:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_bool\",\n                      \"typeString\": \"bool\"\n                    }\n                  },\n                  \"falseBody\": null,\n                  \"id\": 5487,\n                  \"nodeType\": \"IfStatement\",\n                  \"src\": \"33879:421:6\",\n                  \"trueBody\": {\n                    \"id\": 5486,\n                    \"nodeType\": \"Block\",\n                    \"src\": \"33894:406:6\",\n                    \"statements\": [\n                      {\n                        \"eventCall\": {\n                          \"argumentTypes\": null,\n                          \"arguments\": [\n                            {\n                              \"argumentTypes\": null,\n                              \"id\": 5447,\n                              \"name\": \"sender\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 5317,\n                              \"src\": \"33932:6:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_address\",\n                                \"typeString\": \"address\"\n                              }\n                            },\n                            {\n                              \"argumentTypes\": null,\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"id\": 5448,\n                                \"name\": \"unlockedLiquidity\",\n                                \"nodeType\": \"Identifier\",\n                                \"overloadedDeclarations\": [],\n                                \"referencedDeclaration\": 5322,\n                                \"src\": \"33940:17:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                  \"typeString\": \"struct AssetLib.Asset memory\"\n                                }\n                              },\n                              \"id\": 5449,\n                              \"isConstant\": false,\n                              \"isLValue\": true,\n                              \"isPure\": false,\n                              \"lValueRequested\": false,\n                              \"memberName\": \"principal\",\n                              \"nodeType\": \"MemberAccess\",\n                              \"referencedDeclaration\": 2785,\n                              \"src\": \"33940:27:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_uint256\",\n                                \"typeString\": \"uint256\"\n                              }\n                            },\n                            {\n                              \"argumentTypes\": null,\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"id\": 5450,\n                                \"name\": \"unlockedLiquidity\",\n                                \"nodeType\": \"Identifier\",\n                                \"overloadedDeclarations\": [],\n                                \"referencedDeclaration\": 5322,\n                                \"src\": \"33969:17:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                  \"typeString\": \"struct AssetLib.Asset memory\"\n                                }\n                              },\n                              \"id\": 5451,\n                              \"isConstant\": false,\n                              \"isLValue\": true,\n                              \"isPure\": false,\n                              \"lValueRequested\": false,\n                              \"memberName\": \"compoundInterest\",\n                              \"nodeType\": \"MemberAccess\",\n                              \"referencedDeclaration\": 2787,\n                              \"src\": \"33969:34:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_uint256\",\n                                \"typeString\": \"uint256\"\n                              }\n                            }\n                          ],\n                          \"expression\": {\n                            \"argumentTypes\": [\n                              {\n                                \"typeIdentifier\": \"t_address\",\n                                \"typeString\": \"address\"\n                              },\n                              {\n                                \"typeIdentifier\": \"t_uint256\",\n                                \"typeString\": \"uint256\"\n                              },\n                              {\n                                \"typeIdentifier\": \"t_uint256\",\n                                \"typeString\": \"uint256\"\n                              }\n                            ],\n                            \"id\": 5446,\n                            \"name\": \"LiquidityUnlocked\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 3694,\n                            \"src\": \"33914:17:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_function_event_nonpayable$_t_address_$_t_uint256_$_t_uint256_$returns$__$\",\n                              \"typeString\": \"function (address,uint256,uint256)\"\n                            }\n                          },\n                          \"id\": 5452,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"kind\": \"functionCall\",\n                          \"lValueRequested\": false,\n                          \"names\": [],\n                          \"nodeType\": \"FunctionCall\",\n                          \"src\": \"33914:90:6\",\n                          \"tryCall\": false,\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_tuple$__$\",\n                            \"typeString\": \"tuple()\"\n                          }\n                        },\n                        \"id\": 5453,\n                        \"nodeType\": \"EmitStatement\",\n                        \"src\": \"33909:95:6\"\n                      },\n                      {\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"arguments\": [\n                            {\n                              \"argumentTypes\": null,\n                              \"id\": 5457,\n                              \"name\": \"unlockedLiquidity\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 5322,\n                              \"src\": \"34045:17:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                \"typeString\": \"struct AssetLib.Asset memory\"\n                              }\n                            }\n                          ],\n                          \"expression\": {\n                            \"argumentTypes\": [\n                              {\n                                \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                \"typeString\": \"struct AssetLib.Asset memory\"\n                              }\n                            ],\n                            \"expression\": {\n                              \"argumentTypes\": null,\n                              \"id\": 5454,\n                              \"name\": \"_accruedGlobalLocked\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 3776,\n                              \"src\": \"34019:20:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                                \"typeString\": \"struct AssetLib.Asset storage ref\"\n                              }\n                            },\n                            \"id\": 5456,\n                            \"isConstant\": false,\n                            \"isLValue\": true,\n                            \"isPure\": false,\n                            \"lValueRequested\": false,\n                            \"memberName\": \"iSub\",\n                            \"nodeType\": \"MemberAccess\",\n                            \"referencedDeclaration\": 2938,\n                            \"src\": \"34019:25:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_function_internal_nonpayable$_t_struct$_Asset_$2788_storage_ptr_$_t_struct$_Asset_$2788_memory_ptr_$returns$__$bound_to$_t_struct$_Asset_$2788_storage_ptr_$\",\n                              \"typeString\": \"function (struct AssetLib.Asset storage pointer,struct AssetLib.Asset memory)\"\n                            }\n                          },\n                          \"id\": 5458,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"kind\": \"functionCall\",\n                          \"lValueRequested\": false,\n                          \"names\": [],\n                          \"nodeType\": \"FunctionCall\",\n                          \"src\": \"34019:44:6\",\n                          \"tryCall\": false,\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_tuple$__$\",\n                            \"typeString\": \"tuple()\"\n                          }\n                        },\n                        \"id\": 5459,\n                        \"nodeType\": \"ExpressionStatement\",\n                        \"src\": \"34019:44:6\"\n                      },\n                      {\n                        \"condition\": {\n                          \"argumentTypes\": null,\n                          \"commonType\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          },\n                          \"id\": 5463,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"leftExpression\": {\n                            \"argumentTypes\": null,\n                            \"expression\": {\n                              \"argumentTypes\": null,\n                              \"id\": 5460,\n                              \"name\": \"lockedAssets\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 5337,\n                              \"src\": \"34081:12:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_array$_t_struct$_LockedAsset_$3653_storage_$dyn_storage_ptr\",\n                                \"typeString\": \"struct Staking.LockedAsset storage ref[] storage pointer\"\n                              }\n                            },\n                            \"id\": 5461,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": false,\n                            \"lValueRequested\": false,\n                            \"memberName\": \"length\",\n                            \"nodeType\": \"MemberAccess\",\n                            \"referencedDeclaration\": null,\n                            \"src\": \"34081:19:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"nodeType\": \"BinaryOperation\",\n                          \"operator\": \"!=\",\n                          \"rightExpression\": {\n                            \"argumentTypes\": null,\n                            \"hexValue\": \"30\",\n                            \"id\": 5462,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": true,\n                            \"kind\": \"number\",\n                            \"lValueRequested\": false,\n                            \"nodeType\": \"Literal\",\n                            \"src\": \"34104:1:6\",\n                            \"subdenomination\": null,\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_rational_0_by_1\",\n                              \"typeString\": \"int_const 0\"\n                            },\n                            \"value\": \"0\"\n                          },\n                          \"src\": \"34081:24:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_bool\",\n                            \"typeString\": \"bool\"\n                          }\n                        },\n                        \"falseBody\": null,\n                        \"id\": 5473,\n                        \"nodeType\": \"IfStatement\",\n                        \"src\": \"34077:103:6\",\n                        \"trueBody\": {\n                          \"id\": 5472,\n                          \"nodeType\": \"Block\",\n                          \"src\": \"34107:73:6\",\n                          \"statements\": [\n                            {\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"arguments\": [\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"id\": 5469,\n                                    \"name\": \"unlockedLiquidity\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 5322,\n                                    \"src\": \"34147:17:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                      \"typeString\": \"struct AssetLib.Asset memory\"\n                                    }\n                                  }\n                                ],\n                                \"expression\": {\n                                  \"argumentTypes\": [\n                                    {\n                                      \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                      \"typeString\": \"struct AssetLib.Asset memory\"\n                                    }\n                                  ],\n                                  \"expression\": {\n                                    \"argumentTypes\": null,\n                                    \"expression\": {\n                                      \"argumentTypes\": null,\n                                      \"id\": 5464,\n                                      \"name\": \"locked\",\n                                      \"nodeType\": \"Identifier\",\n                                      \"overloadedDeclarations\": [],\n                                      \"referencedDeclaration\": 5329,\n                                      \"src\": \"34125:6:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_struct$_Locked_$3659_storage_ptr\",\n                                        \"typeString\": \"struct Staking.Locked storage pointer\"\n                                      }\n                                    },\n                                    \"id\": 5467,\n                                    \"isConstant\": false,\n                                    \"isLValue\": true,\n                                    \"isPure\": false,\n                                    \"lValueRequested\": false,\n                                    \"memberName\": \"aggregate\",\n                                    \"nodeType\": \"MemberAccess\",\n                                    \"referencedDeclaration\": 3655,\n                                    \"src\": \"34125:16:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                                      \"typeString\": \"struct AssetLib.Asset storage ref\"\n                                    }\n                                  },\n                                  \"id\": 5468,\n                                  \"isConstant\": false,\n                                  \"isLValue\": true,\n                                  \"isPure\": false,\n                                  \"lValueRequested\": false,\n                                  \"memberName\": \"iSub\",\n                                  \"nodeType\": \"MemberAccess\",\n                                  \"referencedDeclaration\": 2938,\n                                  \"src\": \"34125:21:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_function_internal_nonpayable$_t_struct$_Asset_$2788_storage_ptr_$_t_struct$_Asset_$2788_memory_ptr_$returns$__$bound_to$_t_struct$_Asset_$2788_storage_ptr_$\",\n                                    \"typeString\": \"function (struct AssetLib.Asset storage pointer,struct AssetLib.Asset memory)\"\n                                  }\n                                },\n                                \"id\": 5470,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": false,\n                                \"kind\": \"functionCall\",\n                                \"lValueRequested\": false,\n                                \"names\": [],\n                                \"nodeType\": \"FunctionCall\",\n                                \"src\": \"34125:40:6\",\n                                \"tryCall\": false,\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_tuple$__$\",\n                                  \"typeString\": \"tuple()\"\n                                }\n                              },\n                              \"id\": 5471,\n                              \"nodeType\": \"ExpressionStatement\",\n                              \"src\": \"34125:40:6\"\n                            }\n                          ]\n                        }\n                      },\n                      {\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"arguments\": [\n                            {\n                              \"argumentTypes\": null,\n                              \"id\": 5477,\n                              \"name\": \"unlockedLiquidity\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 5322,\n                              \"src\": \"34223:17:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                \"typeString\": \"struct AssetLib.Asset memory\"\n                              }\n                            }\n                          ],\n                          \"expression\": {\n                            \"argumentTypes\": [\n                              {\n                                \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                \"typeString\": \"struct AssetLib.Asset memory\"\n                              }\n                            ],\n                            \"expression\": {\n                              \"argumentTypes\": null,\n                              \"id\": 5474,\n                              \"name\": \"_accruedGlobalLiquidity\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 3774,\n                              \"src\": \"34194:23:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                                \"typeString\": \"struct AssetLib.Asset storage ref\"\n                              }\n                            },\n                            \"id\": 5476,\n                            \"isConstant\": false,\n                            \"isLValue\": true,\n                            \"isPure\": false,\n                            \"lValueRequested\": false,\n                            \"memberName\": \"iAdd\",\n                            \"nodeType\": \"MemberAccess\",\n                            \"referencedDeclaration\": 2878,\n                            \"src\": \"34194:28:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_function_internal_nonpayable$_t_struct$_Asset_$2788_storage_ptr_$_t_struct$_Asset_$2788_memory_ptr_$returns$__$bound_to$_t_struct$_Asset_$2788_storage_ptr_$\",\n                              \"typeString\": \"function (struct AssetLib.Asset storage pointer,struct AssetLib.Asset memory)\"\n                            }\n                          },\n                          \"id\": 5478,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"kind\": \"functionCall\",\n                          \"lValueRequested\": false,\n                          \"names\": [],\n                          \"nodeType\": \"FunctionCall\",\n                          \"src\": \"34194:47:6\",\n                          \"tryCall\": false,\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_tuple$__$\",\n                            \"typeString\": \"tuple()\"\n                          }\n                        },\n                        \"id\": 5479,\n                        \"nodeType\": \"ExpressionStatement\",\n                        \"src\": \"34194:47:6\"\n                      },\n                      {\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"arguments\": [\n                            {\n                              \"argumentTypes\": null,\n                              \"id\": 5483,\n                              \"name\": \"unlockedLiquidity\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 5322,\n                              \"src\": \"34271:17:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                \"typeString\": \"struct AssetLib.Asset memory\"\n                              }\n                            }\n                          ],\n                          \"expression\": {\n                            \"argumentTypes\": [\n                              {\n                                \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                \"typeString\": \"struct AssetLib.Asset memory\"\n                              }\n                            ],\n                            \"expression\": {\n                              \"argumentTypes\": null,\n                              \"id\": 5480,\n                              \"name\": \"liquidity\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 5324,\n                              \"src\": \"34256:9:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                                \"typeString\": \"struct AssetLib.Asset storage pointer\"\n                              }\n                            },\n                            \"id\": 5482,\n                            \"isConstant\": false,\n                            \"isLValue\": true,\n                            \"isPure\": false,\n                            \"lValueRequested\": false,\n                            \"memberName\": \"iAdd\",\n                            \"nodeType\": \"MemberAccess\",\n                            \"referencedDeclaration\": 2878,\n                            \"src\": \"34256:14:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_function_internal_nonpayable$_t_struct$_Asset_$2788_storage_ptr_$_t_struct$_Asset_$2788_memory_ptr_$returns$__$bound_to$_t_struct$_Asset_$2788_storage_ptr_$\",\n                              \"typeString\": \"function (struct AssetLib.Asset storage pointer,struct AssetLib.Asset memory)\"\n                            }\n                          },\n                          \"id\": 5484,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"kind\": \"functionCall\",\n                          \"lValueRequested\": false,\n                          \"names\": [],\n                          \"nodeType\": \"FunctionCall\",\n                          \"src\": \"34256:33:6\",\n                          \"tryCall\": false,\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_tuple$__$\",\n                            \"typeString\": \"tuple()\"\n                          }\n                        },\n                        \"id\": 5485,\n                        \"nodeType\": \"ExpressionStatement\",\n                        \"src\": \"34256:33:6\"\n                      }\n                    ]\n                  }\n                }\n              ]\n            },\n            \"documentation\": null,\n            \"id\": 5489,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [],\n            \"name\": \"_collectLiquidity\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 5320,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 5317,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"sender\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 5489,\n                  \"src\": \"31639:14:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_address\",\n                    \"typeString\": \"address\"\n                  },\n                  \"typeName\": {\n                    \"id\": 5316,\n                    \"name\": \"address\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"31639:7:6\",\n                    \"stateMutability\": \"nonpayable\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address\",\n                      \"typeString\": \"address\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 5319,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"at_block\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 5489,\n                  \"src\": \"31655:16:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 5318,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"31655:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"31638:34:6\"\n            },\n            \"returnParameters\": {\n              \"id\": 5327,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 5322,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"unlockedLiquidity\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 5489,\n                  \"src\": \"31706:39:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"memory\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                    \"typeString\": \"struct AssetLib.Asset\"\n                  },\n                  \"typeName\": {\n                    \"contractScope\": null,\n                    \"id\": 5321,\n                    \"name\": \"AssetLib.Asset\",\n                    \"nodeType\": \"UserDefinedTypeName\",\n                    \"referencedDeclaration\": 2788,\n                    \"src\": \"31706:14:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                      \"typeString\": \"struct AssetLib.Asset\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 5324,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"liquidity\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 5489,\n                  \"src\": \"31747:32:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"storage\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                    \"typeString\": \"struct AssetLib.Asset\"\n                  },\n                  \"typeName\": {\n                    \"contractScope\": null,\n                    \"id\": 5323,\n                    \"name\": \"AssetLib.Asset\",\n                    \"nodeType\": \"UserDefinedTypeName\",\n                    \"referencedDeclaration\": 2788,\n                    \"src\": \"31747:14:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                      \"typeString\": \"struct AssetLib.Asset\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 5326,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"collected\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 5489,\n                  \"src\": \"31781:14:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_bool\",\n                    \"typeString\": \"bool\"\n                  },\n                  \"typeName\": {\n                    \"id\": 5325,\n                    \"name\": \"bool\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"31781:4:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_bool\",\n                      \"typeString\": \"bool\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"31705:91:6\"\n            },\n            \"scope\": 5490,\n            \"src\": \"31612:2694:6\",\n            \"stateMutability\": \"nonpayable\",\n            \"virtual\": false,\n            \"visibility\": \"internal\"\n          }\n        ],\n        \"scope\": 5491,\n        \"src\": \"1040:33269:6\"\n      }\n    ],\n    \"src\": \"820:33490:6\"\n  },\n  \"legacyAST\": {\n    \"absolutePath\": \"/Users/pb/code/fetch/cosmos/ledger-staking-contract/contracts/Staking.sol\",\n    \"exportedSymbols\": {\n      \"Staking\": [\n        5490\n      ]\n    },\n    \"id\": 5491,\n    \"license\": \"Apache-2.0\",\n    \"nodeType\": \"SourceUnit\",\n    \"nodes\": [\n      {\n        \"id\": 3625,\n        \"literals\": [\n          \"solidity\",\n          \"^\",\n          \"0.6\",\n          \".0\"\n        ],\n        \"nodeType\": \"PragmaDirective\",\n        \"src\": \"820:23:6\"\n      },\n      {\n        \"absolutePath\": \"/Users/pb/code/fetch/cosmos/ledger-staking-contract/openzeppelin/contracts/token/ERC20/IERC20.sol\",\n        \"file\": \"../openzeppelin/contracts/token/ERC20/IERC20.sol\",\n        \"id\": 3626,\n        \"nodeType\": \"ImportDirective\",\n        \"scope\": 5491,\n        \"sourceUnit\": 6708,\n        \"src\": \"845:58:6\",\n        \"symbolAliases\": [],\n        \"unitAlias\": \"\"\n      },\n      {\n        \"absolutePath\": \"/Users/pb/code/fetch/cosmos/ledger-staking-contract/openzeppelin/contracts/access/AccessControl.sol\",\n        \"file\": \"../openzeppelin/contracts/access/AccessControl.sol\",\n        \"id\": 3627,\n        \"nodeType\": \"ImportDirective\",\n        \"scope\": 5491,\n        \"sourceUnit\": 5842,\n        \"src\": \"904:60:6\",\n        \"symbolAliases\": [],\n        \"unitAlias\": \"\"\n      },\n      {\n        \"absolutePath\": \"/Users/pb/code/fetch/cosmos/ledger-staking-contract/contracts/Finance.sol\",\n        \"file\": \"./Finance.sol\",\n        \"id\": 3628,\n        \"nodeType\": \"ImportDirective\",\n        \"scope\": 5491,\n        \"sourceUnit\": 3319,\n        \"src\": \"965:23:6\",\n        \"symbolAliases\": [],\n        \"unitAlias\": \"\"\n      },\n      {\n        \"abstract\": false,\n        \"baseContracts\": [\n          {\n            \"arguments\": null,\n            \"baseName\": {\n              \"contractScope\": null,\n              \"id\": 3629,\n              \"name\": \"AccessControl\",\n              \"nodeType\": \"UserDefinedTypeName\",\n              \"referencedDeclaration\": 5841,\n              \"src\": \"1060:13:6\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_contract$_AccessControl_$5841\",\n                \"typeString\": \"contract AccessControl\"\n              }\n            },\n            \"id\": 3630,\n            \"nodeType\": \"InheritanceSpecifier\",\n            \"src\": \"1060:13:6\"\n          }\n        ],\n        \"contractDependencies\": [\n          5558,\n          5841\n        ],\n        \"contractKind\": \"contract\",\n        \"documentation\": null,\n        \"fullyImplemented\": true,\n        \"id\": 5490,\n        \"linearizedBaseContracts\": [\n          5490,\n          5841,\n          5558\n        ],\n        \"name\": \"Staking\",\n        \"nodeType\": \"ContractDefinition\",\n        \"nodes\": [\n          {\n            \"id\": 3633,\n            \"libraryName\": {\n              \"contractScope\": null,\n              \"id\": 3631,\n              \"name\": \"SafeMath\",\n              \"nodeType\": \"UserDefinedTypeName\",\n              \"referencedDeclaration\": 6037,\n              \"src\": \"1086:8:6\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_contract$_SafeMath_$6037\",\n                \"typeString\": \"library SafeMath\"\n              }\n            },\n            \"nodeType\": \"UsingForDirective\",\n            \"src\": \"1080:27:6\",\n            \"typeName\": {\n              \"id\": 3632,\n              \"name\": \"uint256\",\n              \"nodeType\": \"ElementaryTypeName\",\n              \"src\": \"1099:7:6\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_uint256\",\n                \"typeString\": \"uint256\"\n              }\n            }\n          },\n          {\n            \"id\": 3636,\n            \"libraryName\": {\n              \"contractScope\": null,\n              \"id\": 3634,\n              \"name\": \"AssetLib\",\n              \"nodeType\": \"UserDefinedTypeName\",\n              \"referencedDeclaration\": 3121,\n              \"src\": \"1118:8:6\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_contract$_AssetLib_$3121\",\n                \"typeString\": \"library AssetLib\"\n              }\n            },\n            \"nodeType\": \"UsingForDirective\",\n            \"src\": \"1112:34:6\",\n            \"typeName\": {\n              \"contractScope\": null,\n              \"id\": 3635,\n              \"name\": \"AssetLib.Asset\",\n              \"nodeType\": \"UserDefinedTypeName\",\n              \"referencedDeclaration\": 2788,\n              \"src\": \"1131:14:6\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                \"typeString\": \"struct AssetLib.Asset\"\n              }\n            }\n          },\n          {\n            \"canonicalName\": \"Staking.InterestRatePerBlock\",\n            \"id\": 3641,\n            \"members\": [\n              {\n                \"constant\": false,\n                \"id\": 3638,\n                \"mutability\": \"mutable\",\n                \"name\": \"sinceBlock\",\n                \"nodeType\": \"VariableDeclaration\",\n                \"overrides\": null,\n                \"scope\": 3641,\n                \"src\": \"1190:18:6\",\n                \"stateVariable\": false,\n                \"storageLocation\": \"default\",\n                \"typeDescriptions\": {\n                  \"typeIdentifier\": \"t_uint256\",\n                  \"typeString\": \"uint256\"\n                },\n                \"typeName\": {\n                  \"id\": 3637,\n                  \"name\": \"uint256\",\n                  \"nodeType\": \"ElementaryTypeName\",\n                  \"src\": \"1190:7:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  }\n                },\n                \"value\": null,\n                \"visibility\": \"internal\"\n              },\n              {\n                \"constant\": false,\n                \"id\": 3640,\n                \"mutability\": \"mutable\",\n                \"name\": \"rate\",\n                \"nodeType\": \"VariableDeclaration\",\n                \"overrides\": null,\n                \"scope\": 3641,\n                \"src\": \"1294:12:6\",\n                \"stateVariable\": false,\n                \"storageLocation\": \"default\",\n                \"typeDescriptions\": {\n                  \"typeIdentifier\": \"t_uint256\",\n                  \"typeString\": \"uint256\"\n                },\n                \"typeName\": {\n                  \"id\": 3639,\n                  \"name\": \"uint256\",\n                  \"nodeType\": \"ElementaryTypeName\",\n                  \"src\": \"1294:7:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  }\n                },\n                \"value\": null,\n                \"visibility\": \"internal\"\n              }\n            ],\n            \"name\": \"InterestRatePerBlock\",\n            \"nodeType\": \"StructDefinition\",\n            \"scope\": 5490,\n            \"src\": \"1152:531:6\",\n            \"visibility\": \"public\"\n          },\n          {\n            \"canonicalName\": \"Staking.Stake\",\n            \"id\": 3648,\n            \"members\": [\n              {\n                \"constant\": false,\n                \"id\": 3643,\n                \"mutability\": \"mutable\",\n                \"name\": \"sinceBlock\",\n                \"nodeType\": \"VariableDeclaration\",\n                \"overrides\": null,\n                \"scope\": 3648,\n                \"src\": \"1712:18:6\",\n                \"stateVariable\": false,\n                \"storageLocation\": \"default\",\n                \"typeDescriptions\": {\n                  \"typeIdentifier\": \"t_uint256\",\n                  \"typeString\": \"uint256\"\n                },\n                \"typeName\": {\n                  \"id\": 3642,\n                  \"name\": \"uint256\",\n                  \"nodeType\": \"ElementaryTypeName\",\n                  \"src\": \"1712:7:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  }\n                },\n                \"value\": null,\n                \"visibility\": \"internal\"\n              },\n              {\n                \"constant\": false,\n                \"id\": 3645,\n                \"mutability\": \"mutable\",\n                \"name\": \"sinceInterestRateIndex\",\n                \"nodeType\": \"VariableDeclaration\",\n                \"overrides\": null,\n                \"scope\": 3648,\n                \"src\": \"1740:30:6\",\n                \"stateVariable\": false,\n                \"storageLocation\": \"default\",\n                \"typeDescriptions\": {\n                  \"typeIdentifier\": \"t_uint256\",\n                  \"typeString\": \"uint256\"\n                },\n                \"typeName\": {\n                  \"id\": 3644,\n                  \"name\": \"uint256\",\n                  \"nodeType\": \"ElementaryTypeName\",\n                  \"src\": \"1740:7:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  }\n                },\n                \"value\": null,\n                \"visibility\": \"internal\"\n              },\n              {\n                \"constant\": false,\n                \"id\": 3647,\n                \"mutability\": \"mutable\",\n                \"name\": \"asset\",\n                \"nodeType\": \"VariableDeclaration\",\n                \"overrides\": null,\n                \"scope\": 3648,\n                \"src\": \"1780:20:6\",\n                \"stateVariable\": false,\n                \"storageLocation\": \"default\",\n                \"typeDescriptions\": {\n                  \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                  \"typeString\": \"struct AssetLib.Asset\"\n                },\n                \"typeName\": {\n                  \"contractScope\": null,\n                  \"id\": 3646,\n                  \"name\": \"AssetLib.Asset\",\n                  \"nodeType\": \"UserDefinedTypeName\",\n                  \"referencedDeclaration\": 2788,\n                  \"src\": \"1780:14:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                    \"typeString\": \"struct AssetLib.Asset\"\n                  }\n                },\n                \"value\": null,\n                \"visibility\": \"internal\"\n              }\n            ],\n            \"name\": \"Stake\",\n            \"nodeType\": \"StructDefinition\",\n            \"scope\": 5490,\n            \"src\": \"1689:118:6\",\n            \"visibility\": \"public\"\n          },\n          {\n            \"canonicalName\": \"Staking.LockedAsset\",\n            \"id\": 3653,\n            \"members\": [\n              {\n                \"constant\": false,\n                \"id\": 3650,\n                \"mutability\": \"mutable\",\n                \"name\": \"liquidSinceBlock\",\n                \"nodeType\": \"VariableDeclaration\",\n                \"overrides\": null,\n                \"scope\": 3653,\n                \"src\": \"1842:24:6\",\n                \"stateVariable\": false,\n                \"storageLocation\": \"default\",\n                \"typeDescriptions\": {\n                  \"typeIdentifier\": \"t_uint256\",\n                  \"typeString\": \"uint256\"\n                },\n                \"typeName\": {\n                  \"id\": 3649,\n                  \"name\": \"uint256\",\n                  \"nodeType\": \"ElementaryTypeName\",\n                  \"src\": \"1842:7:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  }\n                },\n                \"value\": null,\n                \"visibility\": \"internal\"\n              },\n              {\n                \"constant\": false,\n                \"id\": 3652,\n                \"mutability\": \"mutable\",\n                \"name\": \"asset\",\n                \"nodeType\": \"VariableDeclaration\",\n                \"overrides\": null,\n                \"scope\": 3653,\n                \"src\": \"1876:20:6\",\n                \"stateVariable\": false,\n                \"storageLocation\": \"default\",\n                \"typeDescriptions\": {\n                  \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                  \"typeString\": \"struct AssetLib.Asset\"\n                },\n                \"typeName\": {\n                  \"contractScope\": null,\n                  \"id\": 3651,\n                  \"name\": \"AssetLib.Asset\",\n                  \"nodeType\": \"UserDefinedTypeName\",\n                  \"referencedDeclaration\": 2788,\n                  \"src\": \"1876:14:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                    \"typeString\": \"struct AssetLib.Asset\"\n                  }\n                },\n                \"value\": null,\n                \"visibility\": \"internal\"\n              }\n            ],\n            \"name\": \"LockedAsset\",\n            \"nodeType\": \"StructDefinition\",\n            \"scope\": 5490,\n            \"src\": \"1813:90:6\",\n            \"visibility\": \"public\"\n          },\n          {\n            \"canonicalName\": \"Staking.Locked\",\n            \"id\": 3659,\n            \"members\": [\n              {\n                \"constant\": false,\n                \"id\": 3655,\n                \"mutability\": \"mutable\",\n                \"name\": \"aggregate\",\n                \"nodeType\": \"VariableDeclaration\",\n                \"overrides\": null,\n                \"scope\": 3659,\n                \"src\": \"1933:24:6\",\n                \"stateVariable\": false,\n                \"storageLocation\": \"default\",\n                \"typeDescriptions\": {\n                  \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                  \"typeString\": \"struct AssetLib.Asset\"\n                },\n                \"typeName\": {\n                  \"contractScope\": null,\n                  \"id\": 3654,\n                  \"name\": \"AssetLib.Asset\",\n                  \"nodeType\": \"UserDefinedTypeName\",\n                  \"referencedDeclaration\": 2788,\n                  \"src\": \"1933:14:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                    \"typeString\": \"struct AssetLib.Asset\"\n                  }\n                },\n                \"value\": null,\n                \"visibility\": \"internal\"\n              },\n              {\n                \"constant\": false,\n                \"id\": 3658,\n                \"mutability\": \"mutable\",\n                \"name\": \"assets\",\n                \"nodeType\": \"VariableDeclaration\",\n                \"overrides\": null,\n                \"scope\": 3659,\n                \"src\": \"1967:20:6\",\n                \"stateVariable\": false,\n                \"storageLocation\": \"default\",\n                \"typeDescriptions\": {\n                  \"typeIdentifier\": \"t_array$_t_struct$_LockedAsset_$3653_storage_$dyn_storage_ptr\",\n                  \"typeString\": \"struct Staking.LockedAsset[]\"\n                },\n                \"typeName\": {\n                  \"baseType\": {\n                    \"contractScope\": null,\n                    \"id\": 3656,\n                    \"name\": \"LockedAsset\",\n                    \"nodeType\": \"UserDefinedTypeName\",\n                    \"referencedDeclaration\": 3653,\n                    \"src\": \"1967:11:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_struct$_LockedAsset_$3653_storage_ptr\",\n                      \"typeString\": \"struct Staking.LockedAsset\"\n                    }\n                  },\n                  \"id\": 3657,\n                  \"length\": null,\n                  \"nodeType\": \"ArrayTypeName\",\n                  \"src\": \"1967:13:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_array$_t_struct$_LockedAsset_$3653_storage_$dyn_storage_ptr\",\n                    \"typeString\": \"struct Staking.LockedAsset[]\"\n                  }\n                },\n                \"value\": null,\n                \"visibility\": \"internal\"\n              }\n            ],\n            \"name\": \"Locked\",\n            \"nodeType\": \"StructDefinition\",\n            \"scope\": 5490,\n            \"src\": \"1909:85:6\",\n            \"visibility\": \"public\"\n          },\n          {\n            \"anonymous\": false,\n            \"documentation\": null,\n            \"id\": 3669,\n            \"name\": \"BindStake\",\n            \"nodeType\": \"EventDefinition\",\n            \"parameters\": {\n              \"id\": 3668,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 3661,\n                  \"indexed\": true,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"stakerAddress\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3669,\n                  \"src\": \"2064:29:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_address\",\n                    \"typeString\": \"address\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3660,\n                    \"name\": \"address\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"2064:7:6\",\n                    \"stateMutability\": \"nonpayable\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address\",\n                      \"typeString\": \"address\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 3663,\n                  \"indexed\": true,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"sinceInterestRateIndex\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3669,\n                  \"src\": \"2104:38:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3662,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"2104:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 3665,\n                  \"indexed\": false,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"principal\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3669,\n                  \"src\": \"2153:17:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3664,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"2153:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 3667,\n                  \"indexed\": false,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"compoundInterest\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3669,\n                  \"src\": \"2181:24:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3666,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"2181:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"2052:159:6\"\n            },\n            \"src\": \"2037:175:6\"\n          },\n          {\n            \"anonymous\": false,\n            \"documentation\": {\n              \"id\": 3670,\n              \"nodeType\": \"StructuredDocumentation\",\n              \"src\": \"2218:621:6\",\n              \"text\": \"@dev This event is triggered exclusivelly to recalculate the compount interest of ALREADY staked asset\\n     for the poriod since it was calculated the last time. This means this event does *NOT* include *YET*\\n     any added (resp. removed) asset user is currently binding (resp. unbinding).\\n     The main motivation for this event is to give listener opportunity to get feedback what is the \\n     user's staked asset value with compound interrest recalculated to *CURRENT* block *BEFORE* user's\\n     action (binding resp. unbinding) affects user's staked asset value.\"\n            },\n            \"id\": 3680,\n            \"name\": \"StakeCompoundInterest\",\n            \"nodeType\": \"EventDefinition\",\n            \"parameters\": {\n              \"id\": 3679,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 3672,\n                  \"indexed\": true,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"stakerAddress\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3680,\n                  \"src\": \"2883:29:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_address\",\n                    \"typeString\": \"address\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3671,\n                    \"name\": \"address\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"2883:7:6\",\n                    \"stateMutability\": \"nonpayable\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address\",\n                      \"typeString\": \"address\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 3674,\n                  \"indexed\": true,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"sinceInterestRateIndex\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3680,\n                  \"src\": \"2923:38:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3673,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"2923:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 3676,\n                  \"indexed\": false,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"principal\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3680,\n                  \"src\": \"2972:17:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3675,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"2972:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 3678,\n                  \"indexed\": false,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"compoundInterest\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3680,\n                  \"src\": \"3024:24:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3677,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"3024:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"2871:262:6\"\n            },\n            \"src\": \"2844:290:6\"\n          },\n          {\n            \"anonymous\": false,\n            \"documentation\": null,\n            \"id\": 3686,\n            \"name\": \"LiquidityDeposited\",\n            \"nodeType\": \"EventDefinition\",\n            \"parameters\": {\n              \"id\": 3685,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 3682,\n                  \"indexed\": true,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"stakerAddress\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3686,\n                  \"src\": \"3176:29:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_address\",\n                    \"typeString\": \"address\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3681,\n                    \"name\": \"address\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"3176:7:6\",\n                    \"stateMutability\": \"nonpayable\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address\",\n                      \"typeString\": \"address\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 3684,\n                  \"indexed\": false,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"amount\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3686,\n                  \"src\": \"3216:14:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3683,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"3216:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"3164:72:6\"\n            },\n            \"src\": \"3140:97:6\"\n          },\n          {\n            \"anonymous\": false,\n            \"documentation\": null,\n            \"id\": 3694,\n            \"name\": \"LiquidityUnlocked\",\n            \"nodeType\": \"EventDefinition\",\n            \"parameters\": {\n              \"id\": 3693,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 3688,\n                  \"indexed\": true,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"stakerAddress\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3694,\n                  \"src\": \"3278:29:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_address\",\n                    \"typeString\": \"address\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3687,\n                    \"name\": \"address\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"3278:7:6\",\n                    \"stateMutability\": \"nonpayable\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address\",\n                      \"typeString\": \"address\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 3690,\n                  \"indexed\": false,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"principal\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3694,\n                  \"src\": \"3318:17:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3689,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"3318:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 3692,\n                  \"indexed\": false,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"compoundInterest\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3694,\n                  \"src\": \"3346:24:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3691,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"3346:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"3266:110:6\"\n            },\n            \"src\": \"3243:134:6\"\n          },\n          {\n            \"anonymous\": false,\n            \"documentation\": null,\n            \"id\": 3704,\n            \"name\": \"UnbindStake\",\n            \"nodeType\": \"EventDefinition\",\n            \"parameters\": {\n              \"id\": 3703,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 3696,\n                  \"indexed\": true,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"stakerAddress\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3704,\n                  \"src\": \"3412:29:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_address\",\n                    \"typeString\": \"address\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3695,\n                    \"name\": \"address\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"3412:7:6\",\n                    \"stateMutability\": \"nonpayable\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address\",\n                      \"typeString\": \"address\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 3698,\n                  \"indexed\": true,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"liquidSinceBlock\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3704,\n                  \"src\": \"3452:32:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3697,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"3452:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 3700,\n                  \"indexed\": false,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"principal\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3704,\n                  \"src\": \"3495:17:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3699,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"3495:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 3702,\n                  \"indexed\": false,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"compoundInterest\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3704,\n                  \"src\": \"3523:24:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3701,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"3523:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"3400:153:6\"\n            },\n            \"src\": \"3383:171:6\"\n          },\n          {\n            \"anonymous\": false,\n            \"documentation\": null,\n            \"id\": 3710,\n            \"name\": \"NewInterestRate\",\n            \"nodeType\": \"EventDefinition\",\n            \"parameters\": {\n              \"id\": 3709,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 3706,\n                  \"indexed\": true,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"index\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3710,\n                  \"src\": \"3593:21:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3705,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"3593:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 3708,\n                  \"indexed\": false,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"rate\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3710,\n                  \"src\": \"3625:12:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3707,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"3625:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"3581:133:6\"\n            },\n            \"src\": \"3560:155:6\"\n          },\n          {\n            \"anonymous\": false,\n            \"documentation\": null,\n            \"id\": 3718,\n            \"name\": \"Withdraw\",\n            \"nodeType\": \"EventDefinition\",\n            \"parameters\": {\n              \"id\": 3717,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 3712,\n                  \"indexed\": true,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"stakerAddress\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3718,\n                  \"src\": \"3747:29:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_address\",\n                    \"typeString\": \"address\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3711,\n                    \"name\": \"address\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"3747:7:6\",\n                    \"stateMutability\": \"nonpayable\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address\",\n                      \"typeString\": \"address\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 3714,\n                  \"indexed\": false,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"principal\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3718,\n                  \"src\": \"3787:17:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3713,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"3787:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 3716,\n                  \"indexed\": false,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"compoundInterest\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3718,\n                  \"src\": \"3815:24:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3715,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"3815:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"3735:110:6\"\n            },\n            \"src\": \"3721:125:6\"\n          },\n          {\n            \"anonymous\": false,\n            \"documentation\": null,\n            \"id\": 3722,\n            \"name\": \"LockPeriod\",\n            \"nodeType\": \"EventDefinition\",\n            \"parameters\": {\n              \"id\": 3721,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 3720,\n                  \"indexed\": false,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"numOfBlocks\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3722,\n                  \"src\": \"3869:18:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint64\",\n                    \"typeString\": \"uint64\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3719,\n                    \"name\": \"uint64\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"3869:6:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint64\",\n                      \"typeString\": \"uint64\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"3868:20:6\"\n            },\n            \"src\": \"3852:37:6\"\n          },\n          {\n            \"anonymous\": false,\n            \"documentation\": null,\n            \"id\": 3726,\n            \"name\": \"Pause\",\n            \"nodeType\": \"EventDefinition\",\n            \"parameters\": {\n              \"id\": 3725,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 3724,\n                  \"indexed\": false,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"sinceBlock\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3726,\n                  \"src\": \"3906:18:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3723,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"3906:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"3905:20:6\"\n            },\n            \"src\": \"3894:32:6\"\n          },\n          {\n            \"anonymous\": false,\n            \"documentation\": null,\n            \"id\": 3732,\n            \"name\": \"TokenWithdrawal\",\n            \"nodeType\": \"EventDefinition\",\n            \"parameters\": {\n              \"id\": 3731,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 3728,\n                  \"indexed\": false,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"targetAddress\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3732,\n                  \"src\": \"3953:21:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_address\",\n                    \"typeString\": \"address\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3727,\n                    \"name\": \"address\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"3953:7:6\",\n                    \"stateMutability\": \"nonpayable\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address\",\n                      \"typeString\": \"address\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 3730,\n                  \"indexed\": false,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"amount\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3732,\n                  \"src\": \"3976:14:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3729,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"3976:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"3952:39:6\"\n            },\n            \"src\": \"3931:61:6\"\n          },\n          {\n            \"anonymous\": false,\n            \"documentation\": null,\n            \"id\": 3738,\n            \"name\": \"ExcessTokenWithdrawal\",\n            \"nodeType\": \"EventDefinition\",\n            \"parameters\": {\n              \"id\": 3737,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 3734,\n                  \"indexed\": false,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"targetAddress\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3738,\n                  \"src\": \"4025:21:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_address\",\n                    \"typeString\": \"address\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3733,\n                    \"name\": \"address\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"4025:7:6\",\n                    \"stateMutability\": \"nonpayable\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address\",\n                      \"typeString\": \"address\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 3736,\n                  \"indexed\": false,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"amount\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3738,\n                  \"src\": \"4048:14:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3735,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"4048:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"4024:39:6\"\n            },\n            \"src\": \"3997:67:6\"\n          },\n          {\n            \"anonymous\": false,\n            \"documentation\": null,\n            \"id\": 3744,\n            \"name\": \"RewardsPoolTokenTopUp\",\n            \"nodeType\": \"EventDefinition\",\n            \"parameters\": {\n              \"id\": 3743,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 3740,\n                  \"indexed\": false,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"sender\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3744,\n                  \"src\": \"4097:14:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_address\",\n                    \"typeString\": \"address\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3739,\n                    \"name\": \"address\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"4097:7:6\",\n                    \"stateMutability\": \"nonpayable\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address\",\n                      \"typeString\": \"address\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 3742,\n                  \"indexed\": false,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"amount\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3744,\n                  \"src\": \"4113:14:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3741,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"4113:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"4096:32:6\"\n            },\n            \"src\": \"4069:60:6\"\n          },\n          {\n            \"anonymous\": false,\n            \"documentation\": null,\n            \"id\": 3750,\n            \"name\": \"RewardsPoolTokenWithdrawal\",\n            \"nodeType\": \"EventDefinition\",\n            \"parameters\": {\n              \"id\": 3749,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 3746,\n                  \"indexed\": false,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"targetAddress\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3750,\n                  \"src\": \"4167:21:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_address\",\n                    \"typeString\": \"address\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3745,\n                    \"name\": \"address\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"4167:7:6\",\n                    \"stateMutability\": \"nonpayable\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address\",\n                      \"typeString\": \"address\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 3748,\n                  \"indexed\": false,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"amount\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3750,\n                  \"src\": \"4190:14:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3747,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"4190:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"4166:39:6\"\n            },\n            \"src\": \"4134:72:6\"\n          },\n          {\n            \"anonymous\": false,\n            \"documentation\": null,\n            \"id\": 3752,\n            \"name\": \"DeleteContract\",\n            \"nodeType\": \"EventDefinition\",\n            \"parameters\": {\n              \"id\": 3751,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"4231:2:6\"\n            },\n            \"src\": \"4211:23:6\"\n          },\n          {\n            \"constant\": true,\n            \"functionSelector\": \"c0ba241b\",\n            \"id\": 3757,\n            \"mutability\": \"constant\",\n            \"name\": \"DELEGATE_ROLE\",\n            \"nodeType\": \"VariableDeclaration\",\n            \"overrides\": null,\n            \"scope\": 5490,\n            \"src\": \"4241:66:6\",\n            \"stateVariable\": true,\n            \"storageLocation\": \"default\",\n            \"typeDescriptions\": {\n              \"typeIdentifier\": \"t_bytes32\",\n              \"typeString\": \"bytes32\"\n            },\n            \"typeName\": {\n              \"id\": 3753,\n              \"name\": \"bytes32\",\n              \"nodeType\": \"ElementaryTypeName\",\n              \"src\": \"4241:7:6\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_bytes32\",\n                \"typeString\": \"bytes32\"\n              }\n            },\n            \"value\": {\n              \"argumentTypes\": null,\n              \"arguments\": [\n                {\n                  \"argumentTypes\": null,\n                  \"hexValue\": \"44454c45474154455f524f4c45\",\n                  \"id\": 3755,\n                  \"isConstant\": false,\n                  \"isLValue\": false,\n                  \"isPure\": true,\n                  \"kind\": \"string\",\n                  \"lValueRequested\": false,\n                  \"nodeType\": \"Literal\",\n                  \"src\": \"4291:15:6\",\n                  \"subdenomination\": null,\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_stringliteral_1a82baf2b928242f69f7147fb92490c6288d044f7257b88817e6284f1eec0f15\",\n                    \"typeString\": \"literal_string \\\"DELEGATE_ROLE\\\"\"\n                  },\n                  \"value\": \"DELEGATE_ROLE\"\n                }\n              ],\n              \"expression\": {\n                \"argumentTypes\": [\n                  {\n                    \"typeIdentifier\": \"t_stringliteral_1a82baf2b928242f69f7147fb92490c6288d044f7257b88817e6284f1eec0f15\",\n                    \"typeString\": \"literal_string \\\"DELEGATE_ROLE\\\"\"\n                  }\n                ],\n                \"id\": 3754,\n                \"name\": \"keccak256\",\n                \"nodeType\": \"Identifier\",\n                \"overloadedDeclarations\": [],\n                \"referencedDeclaration\": -8,\n                \"src\": \"4281:9:6\",\n                \"typeDescriptions\": {\n                  \"typeIdentifier\": \"t_function_keccak256_pure$_t_bytes_memory_ptr_$returns$_t_bytes32_$\",\n                  \"typeString\": \"function (bytes memory) pure returns (bytes32)\"\n                }\n              },\n              \"id\": 3756,\n              \"isConstant\": false,\n              \"isLValue\": false,\n              \"isPure\": true,\n              \"kind\": \"functionCall\",\n              \"lValueRequested\": false,\n              \"names\": [],\n              \"nodeType\": \"FunctionCall\",\n              \"src\": \"4281:26:6\",\n              \"tryCall\": false,\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_bytes32\",\n                \"typeString\": \"bytes32\"\n              }\n            },\n            \"visibility\": \"public\"\n          },\n          {\n            \"constant\": true,\n            \"functionSelector\": \"372646bb\",\n            \"id\": 3760,\n            \"mutability\": \"constant\",\n            \"name\": \"DELETE_PROTECTION_PERIOD\",\n            \"nodeType\": \"VariableDeclaration\",\n            \"overrides\": null,\n            \"scope\": 5490,\n            \"src\": \"4313:57:6\",\n            \"stateVariable\": true,\n            \"storageLocation\": \"default\",\n            \"typeDescriptions\": {\n              \"typeIdentifier\": \"t_uint256\",\n              \"typeString\": \"uint256\"\n            },\n            \"typeName\": {\n              \"id\": 3758,\n              \"name\": \"uint256\",\n              \"nodeType\": \"ElementaryTypeName\",\n              \"src\": \"4313:7:6\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_uint256\",\n                \"typeString\": \"uint256\"\n              }\n            },\n            \"value\": {\n              \"argumentTypes\": null,\n              \"hexValue\": \"333730323835\",\n              \"id\": 3759,\n              \"isConstant\": false,\n              \"isLValue\": false,\n              \"isPure\": true,\n              \"kind\": \"number\",\n              \"lValueRequested\": false,\n              \"nodeType\": \"Literal\",\n              \"src\": \"4364:6:6\",\n              \"subdenomination\": null,\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_rational_370285_by_1\",\n                \"typeString\": \"int_const 370285\"\n              },\n              \"value\": \"370285\"\n            },\n            \"visibility\": \"public\"\n          },\n          {\n            \"constant\": false,\n            \"functionSelector\": \"ecd0c0c3\",\n            \"id\": 3762,\n            \"mutability\": \"mutable\",\n            \"name\": \"_token\",\n            \"nodeType\": \"VariableDeclaration\",\n            \"overrides\": null,\n            \"scope\": 5490,\n            \"src\": \"4427:20:6\",\n            \"stateVariable\": true,\n            \"storageLocation\": \"default\",\n            \"typeDescriptions\": {\n              \"typeIdentifier\": \"t_contract$_IERC20_$6707\",\n              \"typeString\": \"contract IERC20\"\n            },\n            \"typeName\": {\n              \"contractScope\": null,\n              \"id\": 3761,\n              \"name\": \"IERC20\",\n              \"nodeType\": \"UserDefinedTypeName\",\n              \"referencedDeclaration\": 6707,\n              \"src\": \"4427:6:6\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_contract$_IERC20_$6707\",\n                \"typeString\": \"contract IERC20\"\n              }\n            },\n            \"value\": null,\n            \"visibility\": \"public\"\n          },\n          {\n            \"constant\": false,\n            \"functionSelector\": \"32a1bd70\",\n            \"id\": 3764,\n            \"mutability\": \"mutable\",\n            \"name\": \"_earliestDelete\",\n            \"nodeType\": \"VariableDeclaration\",\n            \"overrides\": null,\n            \"scope\": 5490,\n            \"src\": \"5201:30:6\",\n            \"stateVariable\": true,\n            \"storageLocation\": \"default\",\n            \"typeDescriptions\": {\n              \"typeIdentifier\": \"t_uint256\",\n              \"typeString\": \"uint256\"\n            },\n            \"typeName\": {\n              \"id\": 3763,\n              \"name\": \"uint256\",\n              \"nodeType\": \"ElementaryTypeName\",\n              \"src\": \"5201:7:6\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_uint256\",\n                \"typeString\": \"uint256\"\n              }\n            },\n            \"value\": null,\n            \"visibility\": \"public\"\n          },\n          {\n            \"constant\": false,\n            \"functionSelector\": \"f1209ef7\",\n            \"id\": 3766,\n            \"mutability\": \"mutable\",\n            \"name\": \"_pausedSinceBlock\",\n            \"nodeType\": \"VariableDeclaration\",\n            \"overrides\": null,\n            \"scope\": 5490,\n            \"src\": \"5242:32:6\",\n            \"stateVariable\": true,\n            \"storageLocation\": \"default\",\n            \"typeDescriptions\": {\n              \"typeIdentifier\": \"t_uint256\",\n              \"typeString\": \"uint256\"\n            },\n            \"typeName\": {\n              \"id\": 3765,\n              \"name\": \"uint256\",\n              \"nodeType\": \"ElementaryTypeName\",\n              \"src\": \"5242:7:6\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_uint256\",\n                \"typeString\": \"uint256\"\n              }\n            },\n            \"value\": null,\n            \"visibility\": \"public\"\n          },\n          {\n            \"constant\": false,\n            \"functionSelector\": \"2514c50a\",\n            \"id\": 3768,\n            \"mutability\": \"mutable\",\n            \"name\": \"_lockPeriodInBlocks\",\n            \"nodeType\": \"VariableDeclaration\",\n            \"overrides\": null,\n            \"scope\": 5490,\n            \"src\": \"5280:33:6\",\n            \"stateVariable\": true,\n            \"storageLocation\": \"default\",\n            \"typeDescriptions\": {\n              \"typeIdentifier\": \"t_uint64\",\n              \"typeString\": \"uint64\"\n            },\n            \"typeName\": {\n              \"id\": 3767,\n              \"name\": \"uint64\",\n              \"nodeType\": \"ElementaryTypeName\",\n              \"src\": \"5280:6:6\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_uint64\",\n                \"typeString\": \"uint64\"\n              }\n            },\n            \"value\": null,\n            \"visibility\": \"public\"\n          },\n          {\n            \"constant\": false,\n            \"functionSelector\": \"0c450f9d\",\n            \"id\": 3770,\n            \"mutability\": \"mutable\",\n            \"name\": \"_rewardsPoolBalance\",\n            \"nodeType\": \"VariableDeclaration\",\n            \"overrides\": null,\n            \"scope\": 5490,\n            \"src\": \"5441:34:6\",\n            \"stateVariable\": true,\n            \"storageLocation\": \"default\",\n            \"typeDescriptions\": {\n              \"typeIdentifier\": \"t_uint256\",\n              \"typeString\": \"uint256\"\n            },\n            \"typeName\": {\n              \"id\": 3769,\n              \"name\": \"uint256\",\n              \"nodeType\": \"ElementaryTypeName\",\n              \"src\": \"5441:7:6\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_uint256\",\n                \"typeString\": \"uint256\"\n              }\n            },\n            \"value\": null,\n            \"visibility\": \"public\"\n          },\n          {\n            \"constant\": false,\n            \"functionSelector\": \"292911fb\",\n            \"id\": 3772,\n            \"mutability\": \"mutable\",\n            \"name\": \"_accruedGlobalPrincipal\",\n            \"nodeType\": \"VariableDeclaration\",\n            \"overrides\": null,\n            \"scope\": 5490,\n            \"src\": \"5608:38:6\",\n            \"stateVariable\": true,\n            \"storageLocation\": \"default\",\n            \"typeDescriptions\": {\n              \"typeIdentifier\": \"t_uint256\",\n              \"typeString\": \"uint256\"\n            },\n            \"typeName\": {\n              \"id\": 3771,\n              \"name\": \"uint256\",\n              \"nodeType\": \"ElementaryTypeName\",\n              \"src\": \"5608:7:6\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_uint256\",\n                \"typeString\": \"uint256\"\n              }\n            },\n            \"value\": null,\n            \"visibility\": \"public\"\n          },\n          {\n            \"constant\": false,\n            \"functionSelector\": \"c8984ab2\",\n            \"id\": 3774,\n            \"mutability\": \"mutable\",\n            \"name\": \"_accruedGlobalLiquidity\",\n            \"nodeType\": \"VariableDeclaration\",\n            \"overrides\": null,\n            \"scope\": 5490,\n            \"src\": \"5652:45:6\",\n            \"stateVariable\": true,\n            \"storageLocation\": \"default\",\n            \"typeDescriptions\": {\n              \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n              \"typeString\": \"struct AssetLib.Asset\"\n            },\n            \"typeName\": {\n              \"contractScope\": null,\n              \"id\": 3773,\n              \"name\": \"AssetLib.Asset\",\n              \"nodeType\": \"UserDefinedTypeName\",\n              \"referencedDeclaration\": 2788,\n              \"src\": \"5652:14:6\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                \"typeString\": \"struct AssetLib.Asset\"\n              }\n            },\n            \"value\": null,\n            \"visibility\": \"public\"\n          },\n          {\n            \"constant\": false,\n            \"functionSelector\": \"d9b202c9\",\n            \"id\": 3776,\n            \"mutability\": \"mutable\",\n            \"name\": \"_accruedGlobalLocked\",\n            \"nodeType\": \"VariableDeclaration\",\n            \"overrides\": null,\n            \"scope\": 5490,\n            \"src\": \"5712:42:6\",\n            \"stateVariable\": true,\n            \"storageLocation\": \"default\",\n            \"typeDescriptions\": {\n              \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n              \"typeString\": \"struct AssetLib.Asset\"\n            },\n            \"typeName\": {\n              \"contractScope\": null,\n              \"id\": 3775,\n              \"name\": \"AssetLib.Asset\",\n              \"nodeType\": \"UserDefinedTypeName\",\n              \"referencedDeclaration\": 2788,\n              \"src\": \"5712:14:6\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                \"typeString\": \"struct AssetLib.Asset\"\n              }\n            },\n            \"value\": null,\n            \"visibility\": \"public\"\n          },\n          {\n            \"constant\": false,\n            \"functionSelector\": \"d9d8e783\",\n            \"id\": 3778,\n            \"mutability\": \"mutable\",\n            \"name\": \"_interestRatesStartIdx\",\n            \"nodeType\": \"VariableDeclaration\",\n            \"overrides\": null,\n            \"scope\": 5490,\n            \"src\": \"5770:37:6\",\n            \"stateVariable\": true,\n            \"storageLocation\": \"default\",\n            \"typeDescriptions\": {\n              \"typeIdentifier\": \"t_uint256\",\n              \"typeString\": \"uint256\"\n            },\n            \"typeName\": {\n              \"id\": 3777,\n              \"name\": \"uint256\",\n              \"nodeType\": \"ElementaryTypeName\",\n              \"src\": \"5770:7:6\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_uint256\",\n                \"typeString\": \"uint256\"\n              }\n            },\n            \"value\": null,\n            \"visibility\": \"public\"\n          },\n          {\n            \"constant\": false,\n            \"functionSelector\": \"4164b001\",\n            \"id\": 3780,\n            \"mutability\": \"mutable\",\n            \"name\": \"_interestRatesNextIdx\",\n            \"nodeType\": \"VariableDeclaration\",\n            \"overrides\": null,\n            \"scope\": 5490,\n            \"src\": \"5813:36:6\",\n            \"stateVariable\": true,\n            \"storageLocation\": \"default\",\n            \"typeDescriptions\": {\n              \"typeIdentifier\": \"t_uint256\",\n              \"typeString\": \"uint256\"\n            },\n            \"typeName\": {\n              \"id\": 3779,\n              \"name\": \"uint256\",\n              \"nodeType\": \"ElementaryTypeName\",\n              \"src\": \"5813:7:6\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_uint256\",\n                \"typeString\": \"uint256\"\n              }\n            },\n            \"value\": null,\n            \"visibility\": \"public\"\n          },\n          {\n            \"constant\": false,\n            \"functionSelector\": \"aa700ff2\",\n            \"id\": 3784,\n            \"mutability\": \"mutable\",\n            \"name\": \"_interestRates\",\n            \"nodeType\": \"VariableDeclaration\",\n            \"overrides\": null,\n            \"scope\": 5490,\n            \"src\": \"5855:62:6\",\n            \"stateVariable\": true,\n            \"storageLocation\": \"default\",\n            \"typeDescriptions\": {\n              \"typeIdentifier\": \"t_mapping$_t_uint256_$_t_struct$_InterestRatePerBlock_$3641_storage_$\",\n              \"typeString\": \"mapping(uint256 => struct Staking.InterestRatePerBlock)\"\n            },\n            \"typeName\": {\n              \"id\": 3783,\n              \"keyType\": {\n                \"id\": 3781,\n                \"name\": \"uint256\",\n                \"nodeType\": \"ElementaryTypeName\",\n                \"src\": \"5863:7:6\",\n                \"typeDescriptions\": {\n                  \"typeIdentifier\": \"t_uint256\",\n                  \"typeString\": \"uint256\"\n                }\n              },\n              \"nodeType\": \"Mapping\",\n              \"src\": \"5855:40:6\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_mapping$_t_uint256_$_t_struct$_InterestRatePerBlock_$3641_storage_$\",\n                \"typeString\": \"mapping(uint256 => struct Staking.InterestRatePerBlock)\"\n              },\n              \"valueType\": {\n                \"contractScope\": null,\n                \"id\": 3782,\n                \"name\": \"InterestRatePerBlock\",\n                \"nodeType\": \"UserDefinedTypeName\",\n                \"referencedDeclaration\": 3641,\n                \"src\": \"5874:20:6\",\n                \"typeDescriptions\": {\n                  \"typeIdentifier\": \"t_struct$_InterestRatePerBlock_$3641_storage_ptr\",\n                  \"typeString\": \"struct Staking.InterestRatePerBlock\"\n                }\n              }\n            },\n            \"value\": null,\n            \"visibility\": \"public\"\n          },\n          {\n            \"constant\": false,\n            \"id\": 3788,\n            \"mutability\": \"mutable\",\n            \"name\": \"_stakes\",\n            \"nodeType\": \"VariableDeclaration\",\n            \"overrides\": null,\n            \"scope\": 5490,\n            \"src\": \"5924:33:6\",\n            \"stateVariable\": true,\n            \"storageLocation\": \"default\",\n            \"typeDescriptions\": {\n              \"typeIdentifier\": \"t_mapping$_t_address_$_t_struct$_Stake_$3648_storage_$\",\n              \"typeString\": \"mapping(address => struct Staking.Stake)\"\n            },\n            \"typeName\": {\n              \"id\": 3787,\n              \"keyType\": {\n                \"id\": 3785,\n                \"name\": \"address\",\n                \"nodeType\": \"ElementaryTypeName\",\n                \"src\": \"5932:7:6\",\n                \"typeDescriptions\": {\n                  \"typeIdentifier\": \"t_address\",\n                  \"typeString\": \"address\"\n                }\n              },\n              \"nodeType\": \"Mapping\",\n              \"src\": \"5924:25:6\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_mapping$_t_address_$_t_struct$_Stake_$3648_storage_$\",\n                \"typeString\": \"mapping(address => struct Staking.Stake)\"\n              },\n              \"valueType\": {\n                \"contractScope\": null,\n                \"id\": 3786,\n                \"name\": \"Stake\",\n                \"nodeType\": \"UserDefinedTypeName\",\n                \"referencedDeclaration\": 3648,\n                \"src\": \"5943:5:6\",\n                \"typeDescriptions\": {\n                  \"typeIdentifier\": \"t_struct$_Stake_$3648_storage_ptr\",\n                  \"typeString\": \"struct Staking.Stake\"\n                }\n              }\n            },\n            \"value\": null,\n            \"visibility\": \"internal\"\n          },\n          {\n            \"constant\": false,\n            \"id\": 3792,\n            \"mutability\": \"mutable\",\n            \"name\": \"_locked\",\n            \"nodeType\": \"VariableDeclaration\",\n            \"overrides\": null,\n            \"scope\": 5490,\n            \"src\": \"5963:34:6\",\n            \"stateVariable\": true,\n            \"storageLocation\": \"default\",\n            \"typeDescriptions\": {\n              \"typeIdentifier\": \"t_mapping$_t_address_$_t_struct$_Locked_$3659_storage_$\",\n              \"typeString\": \"mapping(address => struct Staking.Locked)\"\n            },\n            \"typeName\": {\n              \"id\": 3791,\n              \"keyType\": {\n                \"id\": 3789,\n                \"name\": \"address\",\n                \"nodeType\": \"ElementaryTypeName\",\n                \"src\": \"5971:7:6\",\n                \"typeDescriptions\": {\n                  \"typeIdentifier\": \"t_address\",\n                  \"typeString\": \"address\"\n                }\n              },\n              \"nodeType\": \"Mapping\",\n              \"src\": \"5963:26:6\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_mapping$_t_address_$_t_struct$_Locked_$3659_storage_$\",\n                \"typeString\": \"mapping(address => struct Staking.Locked)\"\n              },\n              \"valueType\": {\n                \"contractScope\": null,\n                \"id\": 3790,\n                \"name\": \"Locked\",\n                \"nodeType\": \"UserDefinedTypeName\",\n                \"referencedDeclaration\": 3659,\n                \"src\": \"5982:6:6\",\n                \"typeDescriptions\": {\n                  \"typeIdentifier\": \"t_struct$_Locked_$3659_storage_ptr\",\n                  \"typeString\": \"struct Staking.Locked\"\n                }\n              }\n            },\n            \"value\": null,\n            \"visibility\": \"internal\"\n          },\n          {\n            \"constant\": false,\n            \"functionSelector\": \"67ce50c0\",\n            \"id\": 3796,\n            \"mutability\": \"mutable\",\n            \"name\": \"_liquidity\",\n            \"nodeType\": \"VariableDeclaration\",\n            \"overrides\": null,\n            \"scope\": 5490,\n            \"src\": \"6003:52:6\",\n            \"stateVariable\": true,\n            \"storageLocation\": \"default\",\n            \"typeDescriptions\": {\n              \"typeIdentifier\": \"t_mapping$_t_address_$_t_struct$_Asset_$2788_storage_$\",\n              \"typeString\": \"mapping(address => struct AssetLib.Asset)\"\n            },\n            \"typeName\": {\n              \"id\": 3795,\n              \"keyType\": {\n                \"id\": 3793,\n                \"name\": \"address\",\n                \"nodeType\": \"ElementaryTypeName\",\n                \"src\": \"6011:7:6\",\n                \"typeDescriptions\": {\n                  \"typeIdentifier\": \"t_address\",\n                  \"typeString\": \"address\"\n                }\n              },\n              \"nodeType\": \"Mapping\",\n              \"src\": \"6003:34:6\",\n              \"typeDescriptions\": {\n                \"typeIdentifier\": \"t_mapping$_t_address_$_t_struct$_Asset_$2788_storage_$\",\n                \"typeString\": \"mapping(address => struct AssetLib.Asset)\"\n              },\n              \"valueType\": {\n                \"contractScope\": null,\n                \"id\": 3794,\n                \"name\": \"AssetLib.Asset\",\n                \"nodeType\": \"UserDefinedTypeName\",\n                \"referencedDeclaration\": 2788,\n                \"src\": \"6022:14:6\",\n                \"typeDescriptions\": {\n                  \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                  \"typeString\": \"struct AssetLib.Asset\"\n                }\n              }\n            },\n            \"value\": null,\n            \"visibility\": \"public\"\n          },\n          {\n            \"body\": {\n              \"id\": 3805,\n              \"nodeType\": \"Block\",\n              \"src\": \"6117:73:6\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"arguments\": [],\n                        \"expression\": {\n                          \"argumentTypes\": [],\n                          \"id\": 3799,\n                          \"name\": \"_isOwner\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 5031,\n                          \"src\": \"6135:8:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_function_internal_view$__$returns$_t_bool_$\",\n                            \"typeString\": \"function () view returns (bool)\"\n                          }\n                        },\n                        \"id\": 3800,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"kind\": \"functionCall\",\n                        \"lValueRequested\": false,\n                        \"names\": [],\n                        \"nodeType\": \"FunctionCall\",\n                        \"src\": \"6135:10:6\",\n                        \"tryCall\": false,\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"hexValue\": \"43616c6c6572206973206e6f7420616e206f776e6572\",\n                        \"id\": 3801,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": true,\n                        \"kind\": \"string\",\n                        \"lValueRequested\": false,\n                        \"nodeType\": \"Literal\",\n                        \"src\": \"6147:24:6\",\n                        \"subdenomination\": null,\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_stringliteral_fba574a628f13337c8d554e12acf25c09c56b020b31ccfaf084049163a70a41b\",\n                          \"typeString\": \"literal_string \\\"Caller is not an owner\\\"\"\n                        },\n                        \"value\": \"Caller is not an owner\"\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_stringliteral_fba574a628f13337c8d554e12acf25c09c56b020b31ccfaf084049163a70a41b\",\n                          \"typeString\": \"literal_string \\\"Caller is not an owner\\\"\"\n                        }\n                      ],\n                      \"id\": 3798,\n                      \"name\": \"require\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [\n                        -18,\n                        -18\n                      ],\n                      \"referencedDeclaration\": -18,\n                      \"src\": \"6127:7:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$\",\n                        \"typeString\": \"function (bool,string memory) pure\"\n                      }\n                    },\n                    \"id\": 3802,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"6127:45:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 3803,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"6127:45:6\"\n                },\n                {\n                  \"id\": 3804,\n                  \"nodeType\": \"PlaceholderStatement\",\n                  \"src\": \"6182:1:6\"\n                }\n              ]\n            },\n            \"documentation\": null,\n            \"id\": 3806,\n            \"name\": \"onlyOwner\",\n            \"nodeType\": \"ModifierDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 3797,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"6114:2:6\"\n            },\n            \"src\": \"6096:94:6\",\n            \"virtual\": false,\n            \"visibility\": \"internal\"\n          },\n          {\n            \"body\": {\n              \"id\": 3821,\n              \"nodeType\": \"Block\",\n              \"src\": \"6265:125:6\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"commonType\": {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        },\n                        \"id\": 3816,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"leftExpression\": {\n                          \"argumentTypes\": null,\n                          \"arguments\": [],\n                          \"expression\": {\n                            \"argumentTypes\": [],\n                            \"id\": 3809,\n                            \"name\": \"_isOwner\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 5031,\n                            \"src\": \"6283:8:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_function_internal_view$__$returns$_t_bool_$\",\n                              \"typeString\": \"function () view returns (bool)\"\n                            }\n                          },\n                          \"id\": 3810,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"kind\": \"functionCall\",\n                          \"lValueRequested\": false,\n                          \"names\": [],\n                          \"nodeType\": \"FunctionCall\",\n                          \"src\": \"6283:10:6\",\n                          \"tryCall\": false,\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_bool\",\n                            \"typeString\": \"bool\"\n                          }\n                        },\n                        \"nodeType\": \"BinaryOperation\",\n                        \"operator\": \"||\",\n                        \"rightExpression\": {\n                          \"argumentTypes\": null,\n                          \"arguments\": [\n                            {\n                              \"argumentTypes\": null,\n                              \"id\": 3812,\n                              \"name\": \"DELEGATE_ROLE\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 3757,\n                              \"src\": \"6305:13:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_bytes32\",\n                                \"typeString\": \"bytes32\"\n                              }\n                            },\n                            {\n                              \"argumentTypes\": null,\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"id\": 3813,\n                                \"name\": \"msg\",\n                                \"nodeType\": \"Identifier\",\n                                \"overloadedDeclarations\": [],\n                                \"referencedDeclaration\": -15,\n                                \"src\": \"6320:3:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_magic_message\",\n                                  \"typeString\": \"msg\"\n                                }\n                              },\n                              \"id\": 3814,\n                              \"isConstant\": false,\n                              \"isLValue\": false,\n                              \"isPure\": false,\n                              \"lValueRequested\": false,\n                              \"memberName\": \"sender\",\n                              \"nodeType\": \"MemberAccess\",\n                              \"referencedDeclaration\": null,\n                              \"src\": \"6320:10:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_address_payable\",\n                                \"typeString\": \"address payable\"\n                              }\n                            }\n                          ],\n                          \"expression\": {\n                            \"argumentTypes\": [\n                              {\n                                \"typeIdentifier\": \"t_bytes32\",\n                                \"typeString\": \"bytes32\"\n                              },\n                              {\n                                \"typeIdentifier\": \"t_address_payable\",\n                                \"typeString\": \"address payable\"\n                              }\n                            ],\n                            \"id\": 3811,\n                            \"name\": \"hasRole\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 5630,\n                            \"src\": \"6297:7:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_function_internal_view$_t_bytes32_$_t_address_$returns$_t_bool_$\",\n                              \"typeString\": \"function (bytes32,address) view returns (bool)\"\n                            }\n                          },\n                          \"id\": 3815,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"kind\": \"functionCall\",\n                          \"lValueRequested\": false,\n                          \"names\": [],\n                          \"nodeType\": \"FunctionCall\",\n                          \"src\": \"6297:34:6\",\n                          \"tryCall\": false,\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_bool\",\n                            \"typeString\": \"bool\"\n                          }\n                        },\n                        \"src\": \"6283:48:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"hexValue\": \"43616c6c6572206973206e656974686572206f776e6572206e6f722064656c6567617465\",\n                        \"id\": 3817,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": true,\n                        \"kind\": \"string\",\n                        \"lValueRequested\": false,\n                        \"nodeType\": \"Literal\",\n                        \"src\": \"6333:38:6\",\n                        \"subdenomination\": null,\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_stringliteral_3c2cbf62f56025e2baf3b46dabe4ee1ab0f4be1432d0bef94b4d166423814999\",\n                          \"typeString\": \"literal_string \\\"Caller is neither owner nor delegate\\\"\"\n                        },\n                        \"value\": \"Caller is neither owner nor delegate\"\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_stringliteral_3c2cbf62f56025e2baf3b46dabe4ee1ab0f4be1432d0bef94b4d166423814999\",\n                          \"typeString\": \"literal_string \\\"Caller is neither owner nor delegate\\\"\"\n                        }\n                      ],\n                      \"id\": 3808,\n                      \"name\": \"require\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [\n                        -18,\n                        -18\n                      ],\n                      \"referencedDeclaration\": -18,\n                      \"src\": \"6275:7:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$\",\n                        \"typeString\": \"function (bool,string memory) pure\"\n                      }\n                    },\n                    \"id\": 3818,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"6275:97:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 3819,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"6275:97:6\"\n                },\n                {\n                  \"id\": 3820,\n                  \"nodeType\": \"PlaceholderStatement\",\n                  \"src\": \"6382:1:6\"\n                }\n              ]\n            },\n            \"documentation\": null,\n            \"id\": 3822,\n            \"name\": \"onlyDelegate\",\n            \"nodeType\": \"ModifierDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 3807,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"6262:2:6\"\n            },\n            \"src\": \"6241:149:6\",\n            \"virtual\": false,\n            \"visibility\": \"internal\"\n          },\n          {\n            \"body\": {\n              \"id\": 3835,\n              \"nodeType\": \"Block\",\n              \"src\": \"6449:96:6\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"commonType\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        },\n                        \"id\": 3830,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"leftExpression\": {\n                          \"argumentTypes\": null,\n                          \"arguments\": [],\n                          \"expression\": {\n                            \"argumentTypes\": [],\n                            \"id\": 3827,\n                            \"name\": \"_getBlockNumber\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 5019,\n                            \"src\": \"6467:15:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_function_internal_view$__$returns$_t_uint256_$\",\n                              \"typeString\": \"function () view returns (uint256)\"\n                            }\n                          },\n                          \"id\": 3828,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"kind\": \"functionCall\",\n                          \"lValueRequested\": false,\n                          \"names\": [],\n                          \"nodeType\": \"FunctionCall\",\n                          \"src\": \"6467:17:6\",\n                          \"tryCall\": false,\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"nodeType\": \"BinaryOperation\",\n                        \"operator\": \"<=\",\n                        \"rightExpression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 3829,\n                          \"name\": \"expirationBlock\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 3824,\n                          \"src\": \"6488:15:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"src\": \"6467:36:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"hexValue\": \"5472616e73616374696f6e2065787069726564\",\n                        \"id\": 3831,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": true,\n                        \"kind\": \"string\",\n                        \"lValueRequested\": false,\n                        \"nodeType\": \"Literal\",\n                        \"src\": \"6505:21:6\",\n                        \"subdenomination\": null,\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_stringliteral_38b57334da13daffb65e2d9cfe97bc3051af86f72807115eae867384ed846551\",\n                          \"typeString\": \"literal_string \\\"Transaction expired\\\"\"\n                        },\n                        \"value\": \"Transaction expired\"\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_stringliteral_38b57334da13daffb65e2d9cfe97bc3051af86f72807115eae867384ed846551\",\n                          \"typeString\": \"literal_string \\\"Transaction expired\\\"\"\n                        }\n                      ],\n                      \"id\": 3826,\n                      \"name\": \"require\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [\n                        -18,\n                        -18\n                      ],\n                      \"referencedDeclaration\": -18,\n                      \"src\": \"6459:7:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$\",\n                        \"typeString\": \"function (bool,string memory) pure\"\n                      }\n                    },\n                    \"id\": 3832,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"6459:68:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 3833,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"6459:68:6\"\n                },\n                {\n                  \"id\": 3834,\n                  \"nodeType\": \"PlaceholderStatement\",\n                  \"src\": \"6537:1:6\"\n                }\n              ]\n            },\n            \"documentation\": null,\n            \"id\": 3836,\n            \"name\": \"verifyTxExpiration\",\n            \"nodeType\": \"ModifierDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 3825,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 3824,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"expirationBlock\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3836,\n                  \"src\": \"6424:23:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3823,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"6424:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"6423:25:6\"\n            },\n            \"src\": \"6396:149:6\",\n            \"virtual\": false,\n            \"visibility\": \"internal\"\n          },\n          {\n            \"body\": {\n              \"id\": 3847,\n              \"nodeType\": \"Block\",\n              \"src\": \"6578:102:6\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"commonType\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        },\n                        \"id\": 3842,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"leftExpression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 3839,\n                          \"name\": \"_pausedSinceBlock\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 3766,\n                          \"src\": \"6596:17:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"nodeType\": \"BinaryOperation\",\n                        \"operator\": \">\",\n                        \"rightExpression\": {\n                          \"argumentTypes\": null,\n                          \"arguments\": [],\n                          \"expression\": {\n                            \"argumentTypes\": [],\n                            \"id\": 3840,\n                            \"name\": \"_getBlockNumber\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 5019,\n                            \"src\": \"6616:15:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_function_internal_view$__$returns$_t_uint256_$\",\n                              \"typeString\": \"function () view returns (uint256)\"\n                            }\n                          },\n                          \"id\": 3841,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"kind\": \"functionCall\",\n                          \"lValueRequested\": false,\n                          \"names\": [],\n                          \"nodeType\": \"FunctionCall\",\n                          \"src\": \"6616:17:6\",\n                          \"tryCall\": false,\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"src\": \"6596:37:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"hexValue\": \"436f6e747261637420686173206265656e20706175736564\",\n                        \"id\": 3843,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": true,\n                        \"kind\": \"string\",\n                        \"lValueRequested\": false,\n                        \"nodeType\": \"Literal\",\n                        \"src\": \"6635:26:6\",\n                        \"subdenomination\": null,\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_stringliteral_6993ab713d4a8a857f0654d36ec91738ef7ba3b8999d96006199fec5b907c586\",\n                          \"typeString\": \"literal_string \\\"Contract has been paused\\\"\"\n                        },\n                        \"value\": \"Contract has been paused\"\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_stringliteral_6993ab713d4a8a857f0654d36ec91738ef7ba3b8999d96006199fec5b907c586\",\n                          \"typeString\": \"literal_string \\\"Contract has been paused\\\"\"\n                        }\n                      ],\n                      \"id\": 3838,\n                      \"name\": \"require\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [\n                        -18,\n                        -18\n                      ],\n                      \"referencedDeclaration\": -18,\n                      \"src\": \"6588:7:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$\",\n                        \"typeString\": \"function (bool,string memory) pure\"\n                      }\n                    },\n                    \"id\": 3844,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"6588:74:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 3845,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"6588:74:6\"\n                },\n                {\n                  \"id\": 3846,\n                  \"nodeType\": \"PlaceholderStatement\",\n                  \"src\": \"6672:1:6\"\n                }\n              ]\n            },\n            \"documentation\": null,\n            \"id\": 3848,\n            \"name\": \"verifyNotPaused\",\n            \"nodeType\": \"ModifierDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 3837,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"6575:2:6\"\n            },\n            \"src\": \"6551:129:6\",\n            \"virtual\": false,\n            \"visibility\": \"internal\"\n          },\n          {\n            \"body\": {\n              \"id\": 3892,\n              \"nodeType\": \"Block\",\n              \"src\": \"7002:640:6\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 3861,\n                        \"name\": \"DEFAULT_ADMIN_ROLE\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 5584,\n                        \"src\": \"7023:18:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_bytes32\",\n                          \"typeString\": \"bytes32\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 3862,\n                          \"name\": \"msg\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": -15,\n                          \"src\": \"7043:3:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_magic_message\",\n                            \"typeString\": \"msg\"\n                          }\n                        },\n                        \"id\": 3863,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"memberName\": \"sender\",\n                        \"nodeType\": \"MemberAccess\",\n                        \"referencedDeclaration\": null,\n                        \"src\": \"7043:10:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_bytes32\",\n                          \"typeString\": \"bytes32\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        }\n                      ],\n                      \"id\": 3860,\n                      \"name\": \"_setupRole\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5767,\n                      \"src\": \"7012:10:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_nonpayable$_t_bytes32_$_t_address_$returns$__$\",\n                        \"typeString\": \"function (bytes32,address)\"\n                      }\n                    },\n                    \"id\": 3864,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"7012:42:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 3865,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"7012:42:6\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 3870,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 3866,\n                      \"name\": \"_token\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 3762,\n                      \"src\": \"7065:6:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_contract$_IERC20_$6707\",\n                        \"typeString\": \"contract IERC20\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"arguments\": [\n                        {\n                          \"argumentTypes\": null,\n                          \"id\": 3868,\n                          \"name\": \"ERC20Address\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 3851,\n                          \"src\": \"7081:12:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_address\",\n                            \"typeString\": \"address\"\n                          }\n                        }\n                      ],\n                      \"expression\": {\n                        \"argumentTypes\": [\n                          {\n                            \"typeIdentifier\": \"t_address\",\n                            \"typeString\": \"address\"\n                          }\n                        ],\n                        \"id\": 3867,\n                        \"name\": \"IERC20\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 6707,\n                        \"src\": \"7074:6:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_type$_t_contract$_IERC20_$6707_$\",\n                          \"typeString\": \"type(contract IERC20)\"\n                        }\n                      },\n                      \"id\": 3869,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": false,\n                      \"kind\": \"typeConversion\",\n                      \"lValueRequested\": false,\n                      \"names\": [],\n                      \"nodeType\": \"FunctionCall\",\n                      \"src\": \"7074:20:6\",\n                      \"tryCall\": false,\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_contract$_IERC20_$6707\",\n                        \"typeString\": \"contract IERC20\"\n                      }\n                    },\n                    \"src\": \"7065:29:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_contract$_IERC20_$6707\",\n                      \"typeString\": \"contract IERC20\"\n                    }\n                  },\n                  \"id\": 3871,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"7065:29:6\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 3878,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 3872,\n                      \"name\": \"_earliestDelete\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 3764,\n                      \"src\": \"7104:15:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"arguments\": [\n                        {\n                          \"argumentTypes\": null,\n                          \"id\": 3876,\n                          \"name\": \"DELETE_PROTECTION_PERIOD\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 3760,\n                          \"src\": \"7144:24:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        }\n                      ],\n                      \"expression\": {\n                        \"argumentTypes\": [\n                          {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        ],\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"arguments\": [],\n                          \"expression\": {\n                            \"argumentTypes\": [],\n                            \"id\": 3873,\n                            \"name\": \"_getBlockNumber\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 5019,\n                            \"src\": \"7122:15:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_function_internal_view$__$returns$_t_uint256_$\",\n                              \"typeString\": \"function () view returns (uint256)\"\n                            }\n                          },\n                          \"id\": 3874,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"kind\": \"functionCall\",\n                          \"lValueRequested\": false,\n                          \"names\": [],\n                          \"nodeType\": \"FunctionCall\",\n                          \"src\": \"7122:17:6\",\n                          \"tryCall\": false,\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"id\": 3875,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"memberName\": \"add\",\n                        \"nodeType\": \"MemberAccess\",\n                        \"referencedDeclaration\": 5870,\n                        \"src\": \"7122:21:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_function_internal_pure$_t_uint256_$_t_uint256_$returns$_t_uint256_$bound_to$_t_uint256_$\",\n                          \"typeString\": \"function (uint256,uint256) pure returns (uint256)\"\n                        }\n                      },\n                      \"id\": 3877,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": false,\n                      \"kind\": \"functionCall\",\n                      \"lValueRequested\": false,\n                      \"names\": [],\n                      \"nodeType\": \"FunctionCall\",\n                      \"src\": \"7122:47:6\",\n                      \"tryCall\": false,\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"src\": \"7104:65:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"id\": 3879,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"7104:65:6\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 3881,\n                        \"name\": \"lockPeriodInBlocks\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 3857,\n                        \"src\": \"7512:18:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint64\",\n                          \"typeString\": \"uint64\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_uint64\",\n                          \"typeString\": \"uint64\"\n                        }\n                      ],\n                      \"id\": 3880,\n                      \"name\": \"_updateLockPeriod\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5079,\n                      \"src\": \"7494:17:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_nonpayable$_t_uint64_$returns$__$\",\n                        \"typeString\": \"function (uint64)\"\n                      }\n                    },\n                    \"id\": 3882,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"7494:37:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 3883,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"7494:37:6\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 3885,\n                        \"name\": \"interestRatePerBlock\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 3853,\n                        \"src\": \"7558:20:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"id\": 3884,\n                      \"name\": \"_addInterestRate\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5064,\n                      \"src\": \"7541:16:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_nonpayable$_t_uint256_$returns$__$\",\n                        \"typeString\": \"function (uint256)\"\n                      }\n                    },\n                    \"id\": 3886,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"7541:38:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 3887,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"7541:38:6\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 3889,\n                        \"name\": \"pausedSinceBlock\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 3855,\n                        \"src\": \"7601:16:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"id\": 3888,\n                      \"name\": \"_pauseSince\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5104,\n                      \"src\": \"7589:11:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_nonpayable$_t_uint256_$returns$__$\",\n                        \"typeString\": \"function (uint256)\"\n                      }\n                    },\n                    \"id\": 3890,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"7589:46:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 3891,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"7589:46:6\"\n                }\n              ]\n            },\n            \"documentation\": {\n              \"id\": 3849,\n              \"nodeType\": \"StructuredDocumentation\",\n              \"src\": \"6756:68:6\",\n              \"text\": \"@param ERC20Address address of the ERC20 contract\"\n            },\n            \"id\": 3893,\n            \"implemented\": true,\n            \"kind\": \"constructor\",\n            \"modifiers\": [],\n            \"name\": \"\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 3858,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 3851,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"ERC20Address\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3893,\n                  \"src\": \"6852:20:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_address\",\n                    \"typeString\": \"address\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3850,\n                    \"name\": \"address\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"6852:7:6\",\n                    \"stateMutability\": \"nonpayable\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address\",\n                      \"typeString\": \"address\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 3853,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"interestRatePerBlock\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3893,\n                  \"src\": \"6883:28:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3852,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"6883:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 3855,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"pausedSinceBlock\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3893,\n                  \"src\": \"6922:24:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3854,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"6922:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 3857,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"lockPeriodInBlocks\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3893,\n                  \"src\": \"6957:26:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint64\",\n                    \"typeString\": \"uint64\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3856,\n                    \"name\": \"uint64\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"6957:6:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint64\",\n                      \"typeString\": \"uint64\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"6840:144:6\"\n            },\n            \"returnParameters\": {\n              \"id\": 3859,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"7002:0:6\"\n            },\n            \"scope\": 5490,\n            \"src\": \"6829:813:6\",\n            \"stateMutability\": \"nonpayable\",\n            \"virtual\": false,\n            \"visibility\": \"public\"\n          },\n          {\n            \"body\": {\n              \"id\": 3910,\n              \"nodeType\": \"Block\",\n              \"src\": \"8459:39:6\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 3907,\n                        \"name\": \"rate\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 3896,\n                        \"src\": \"8486:4:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"id\": 3906,\n                      \"name\": \"_addInterestRate\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5064,\n                      \"src\": \"8469:16:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_nonpayable$_t_uint256_$returns$__$\",\n                        \"typeString\": \"function (uint256)\"\n                      }\n                    },\n                    \"id\": 3908,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"8469:22:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 3909,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"8469:22:6\"\n                }\n              ]\n            },\n            \"documentation\": {\n              \"id\": 3894,\n              \"nodeType\": \"StructuredDocumentation\",\n              \"src\": \"7649:627:6\",\n              \"text\": \"@notice Add new interest rate in to the ordered container of previously added interest rates\\n@param rate - signed interest rate value in [10**18] units => real_rate [1] = rate [10**18] / 10**18\\n@param expirationBlock - block number beyond which is the carrier Tx considered expired, and so rejected.\\n                    This is for protection of Tx sender to exactly define lifecycle length of the Tx,\\n                    and so avoiding uncertainty of how long Tx sender needs to wait for Tx processing.\\n                    Tx can be withheld\\n@dev expiration period\"\n            },\n            \"functionSelector\": \"13384039\",\n            \"id\": 3911,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [\n              {\n                \"arguments\": [],\n                \"id\": 3901,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 3900,\n                  \"name\": \"onlyDelegate\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 3822,\n                  \"src\": \"8396:12:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$__$\",\n                    \"typeString\": \"modifier ()\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"8396:14:6\"\n              },\n              {\n                \"arguments\": [\n                  {\n                    \"argumentTypes\": null,\n                    \"id\": 3903,\n                    \"name\": \"expirationBlock\",\n                    \"nodeType\": \"Identifier\",\n                    \"overloadedDeclarations\": [],\n                    \"referencedDeclaration\": 3898,\n                    \"src\": \"8438:15:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  }\n                ],\n                \"id\": 3904,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 3902,\n                  \"name\": \"verifyTxExpiration\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 3836,\n                  \"src\": \"8419:18:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$_t_uint256_$\",\n                    \"typeString\": \"modifier (uint256)\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"8419:35:6\"\n              }\n            ],\n            \"name\": \"addInterestRate\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 3899,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 3896,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"rate\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3911,\n                  \"src\": \"8315:12:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3895,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"8315:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 3898,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"expirationBlock\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3911,\n                  \"src\": \"8337:23:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3897,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"8337:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"8305:65:6\"\n            },\n            \"returnParameters\": {\n              \"id\": 3905,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"8459:0:6\"\n            },\n            \"scope\": 5490,\n            \"src\": \"8281:217:6\",\n            \"stateMutability\": \"nonpayable\",\n            \"virtual\": false,\n            \"visibility\": \"external\"\n          },\n          {\n            \"body\": {\n              \"id\": 3997,\n              \"nodeType\": \"Block\",\n              \"src\": \"8682:654:6\",\n              \"statements\": [\n                {\n                  \"assignments\": [\n                    3924\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 3924,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"makeTransfer\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 3997,\n                      \"src\": \"8692:17:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"default\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_bool\",\n                        \"typeString\": \"bool\"\n                      },\n                      \"typeName\": {\n                        \"id\": 3923,\n                        \"name\": \"bool\",\n                        \"nodeType\": \"ElementaryTypeName\",\n                        \"src\": \"8692:4:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 3928,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"commonType\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    },\n                    \"id\": 3927,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftExpression\": {\n                      \"argumentTypes\": null,\n                      \"id\": 3925,\n                      \"name\": \"amount\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 3913,\n                      \"src\": \"8712:6:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"BinaryOperation\",\n                    \"operator\": \"!=\",\n                    \"rightExpression\": {\n                      \"argumentTypes\": null,\n                      \"hexValue\": \"30\",\n                      \"id\": 3926,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": true,\n                      \"kind\": \"number\",\n                      \"lValueRequested\": false,\n                      \"nodeType\": \"Literal\",\n                      \"src\": \"8722:1:6\",\n                      \"subdenomination\": null,\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_rational_0_by_1\",\n                        \"typeString\": \"int_const 0\"\n                      },\n                      \"value\": \"0\"\n                    },\n                    \"src\": \"8712:11:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_bool\",\n                      \"typeString\": \"bool\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"8692:31:6\"\n                },\n                {\n                  \"condition\": {\n                    \"argumentTypes\": null,\n                    \"id\": 3929,\n                    \"name\": \"makeTransfer\",\n                    \"nodeType\": \"Identifier\",\n                    \"overloadedDeclarations\": [],\n                    \"referencedDeclaration\": 3924,\n                    \"src\": \"8737:12:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_bool\",\n                      \"typeString\": \"bool\"\n                    }\n                  },\n                  \"falseBody\": null,\n                  \"id\": 3968,\n                  \"nodeType\": \"IfStatement\",\n                  \"src\": \"8733:352:6\",\n                  \"trueBody\": {\n                    \"id\": 3967,\n                    \"nodeType\": \"Block\",\n                    \"src\": \"8751:334:6\",\n                    \"statements\": [\n                      {\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"arguments\": [\n                            {\n                              \"argumentTypes\": null,\n                              \"arguments\": [\n                                {\n                                  \"argumentTypes\": null,\n                                  \"expression\": {\n                                    \"argumentTypes\": null,\n                                    \"id\": 3933,\n                                    \"name\": \"msg\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": -15,\n                                    \"src\": \"8793:3:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_magic_message\",\n                                      \"typeString\": \"msg\"\n                                    }\n                                  },\n                                  \"id\": 3934,\n                                  \"isConstant\": false,\n                                  \"isLValue\": false,\n                                  \"isPure\": false,\n                                  \"lValueRequested\": false,\n                                  \"memberName\": \"sender\",\n                                  \"nodeType\": \"MemberAccess\",\n                                  \"referencedDeclaration\": null,\n                                  \"src\": \"8793:10:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_address_payable\",\n                                    \"typeString\": \"address payable\"\n                                  }\n                                },\n                                {\n                                  \"argumentTypes\": null,\n                                  \"arguments\": [\n                                    {\n                                      \"argumentTypes\": null,\n                                      \"id\": 3937,\n                                      \"name\": \"this\",\n                                      \"nodeType\": \"Identifier\",\n                                      \"overloadedDeclarations\": [],\n                                      \"referencedDeclaration\": -28,\n                                      \"src\": \"8813:4:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_contract$_Staking_$5490\",\n                                        \"typeString\": \"contract Staking\"\n                                      }\n                                    }\n                                  ],\n                                  \"expression\": {\n                                    \"argumentTypes\": [\n                                      {\n                                        \"typeIdentifier\": \"t_contract$_Staking_$5490\",\n                                        \"typeString\": \"contract Staking\"\n                                      }\n                                    ],\n                                    \"id\": 3936,\n                                    \"isConstant\": false,\n                                    \"isLValue\": false,\n                                    \"isPure\": true,\n                                    \"lValueRequested\": false,\n                                    \"nodeType\": \"ElementaryTypeNameExpression\",\n                                    \"src\": \"8805:7:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_type$_t_address_$\",\n                                      \"typeString\": \"type(address)\"\n                                    },\n                                    \"typeName\": {\n                                      \"id\": 3935,\n                                      \"name\": \"address\",\n                                      \"nodeType\": \"ElementaryTypeName\",\n                                      \"src\": \"8805:7:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": null,\n                                        \"typeString\": null\n                                      }\n                                    }\n                                  },\n                                  \"id\": 3938,\n                                  \"isConstant\": false,\n                                  \"isLValue\": false,\n                                  \"isPure\": false,\n                                  \"kind\": \"typeConversion\",\n                                  \"lValueRequested\": false,\n                                  \"names\": [],\n                                  \"nodeType\": \"FunctionCall\",\n                                  \"src\": \"8805:13:6\",\n                                  \"tryCall\": false,\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_address\",\n                                    \"typeString\": \"address\"\n                                  }\n                                },\n                                {\n                                  \"argumentTypes\": null,\n                                  \"id\": 3939,\n                                  \"name\": \"amount\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 3913,\n                                  \"src\": \"8820:6:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_uint256\",\n                                    \"typeString\": \"uint256\"\n                                  }\n                                }\n                              ],\n                              \"expression\": {\n                                \"argumentTypes\": [\n                                  {\n                                    \"typeIdentifier\": \"t_address_payable\",\n                                    \"typeString\": \"address payable\"\n                                  },\n                                  {\n                                    \"typeIdentifier\": \"t_address\",\n                                    \"typeString\": \"address\"\n                                  },\n                                  {\n                                    \"typeIdentifier\": \"t_uint256\",\n                                    \"typeString\": \"uint256\"\n                                  }\n                                ],\n                                \"expression\": {\n                                  \"argumentTypes\": null,\n                                  \"id\": 3931,\n                                  \"name\": \"_token\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 3762,\n                                  \"src\": \"8773:6:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_contract$_IERC20_$6707\",\n                                    \"typeString\": \"contract IERC20\"\n                                  }\n                                },\n                                \"id\": 3932,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": false,\n                                \"lValueRequested\": false,\n                                \"memberName\": \"transferFrom\",\n                                \"nodeType\": \"MemberAccess\",\n                                \"referencedDeclaration\": 6688,\n                                \"src\": \"8773:19:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_function_external_nonpayable$_t_address_$_t_address_$_t_uint256_$returns$_t_bool_$\",\n                                  \"typeString\": \"function (address,address,uint256) external returns (bool)\"\n                                }\n                              },\n                              \"id\": 3940,\n                              \"isConstant\": false,\n                              \"isLValue\": false,\n                              \"isPure\": false,\n                              \"kind\": \"functionCall\",\n                              \"lValueRequested\": false,\n                              \"names\": [],\n                              \"nodeType\": \"FunctionCall\",\n                              \"src\": \"8773:54:6\",\n                              \"tryCall\": false,\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_bool\",\n                                \"typeString\": \"bool\"\n                              }\n                            },\n                            {\n                              \"argumentTypes\": null,\n                              \"hexValue\": \"5472616e73666572206661696c6564\",\n                              \"id\": 3941,\n                              \"isConstant\": false,\n                              \"isLValue\": false,\n                              \"isPure\": true,\n                              \"kind\": \"string\",\n                              \"lValueRequested\": false,\n                              \"nodeType\": \"Literal\",\n                              \"src\": \"8829:17:6\",\n                              \"subdenomination\": null,\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_stringliteral_25adaa6d082ce15f901e0d8a3d393e7462ef9edf2e6bc8321fa14d1615b6fc51\",\n                                \"typeString\": \"literal_string \\\"Transfer failed\\\"\"\n                              },\n                              \"value\": \"Transfer failed\"\n                            }\n                          ],\n                          \"expression\": {\n                            \"argumentTypes\": [\n                              {\n                                \"typeIdentifier\": \"t_bool\",\n                                \"typeString\": \"bool\"\n                              },\n                              {\n                                \"typeIdentifier\": \"t_stringliteral_25adaa6d082ce15f901e0d8a3d393e7462ef9edf2e6bc8321fa14d1615b6fc51\",\n                                \"typeString\": \"literal_string \\\"Transfer failed\\\"\"\n                              }\n                            ],\n                            \"id\": 3930,\n                            \"name\": \"require\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [\n                              -18,\n                              -18\n                            ],\n                            \"referencedDeclaration\": -18,\n                            \"src\": \"8765:7:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$\",\n                              \"typeString\": \"function (bool,string memory) pure\"\n                            }\n                          },\n                          \"id\": 3942,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"kind\": \"functionCall\",\n                          \"lValueRequested\": false,\n                          \"names\": [],\n                          \"nodeType\": \"FunctionCall\",\n                          \"src\": \"8765:82:6\",\n                          \"tryCall\": false,\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_tuple$__$\",\n                            \"typeString\": \"tuple()\"\n                          }\n                        },\n                        \"id\": 3943,\n                        \"nodeType\": \"ExpressionStatement\",\n                        \"src\": \"8765:82:6\"\n                      },\n                      {\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 3949,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"leftHandSide\": {\n                            \"argumentTypes\": null,\n                            \"id\": 3944,\n                            \"name\": \"_accruedGlobalPrincipal\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 3772,\n                            \"src\": \"8861:23:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"nodeType\": \"Assignment\",\n                          \"operator\": \"=\",\n                          \"rightHandSide\": {\n                            \"argumentTypes\": null,\n                            \"arguments\": [\n                              {\n                                \"argumentTypes\": null,\n                                \"id\": 3947,\n                                \"name\": \"amount\",\n                                \"nodeType\": \"Identifier\",\n                                \"overloadedDeclarations\": [],\n                                \"referencedDeclaration\": 3913,\n                                \"src\": \"8915:6:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              }\n                            ],\n                            \"expression\": {\n                              \"argumentTypes\": [\n                                {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              ],\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"id\": 3945,\n                                \"name\": \"_accruedGlobalPrincipal\",\n                                \"nodeType\": \"Identifier\",\n                                \"overloadedDeclarations\": [],\n                                \"referencedDeclaration\": 3772,\n                                \"src\": \"8887:23:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              },\n                              \"id\": 3946,\n                              \"isConstant\": false,\n                              \"isLValue\": false,\n                              \"isPure\": false,\n                              \"lValueRequested\": false,\n                              \"memberName\": \"add\",\n                              \"nodeType\": \"MemberAccess\",\n                              \"referencedDeclaration\": 5870,\n                              \"src\": \"8887:27:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_function_internal_pure$_t_uint256_$_t_uint256_$returns$_t_uint256_$bound_to$_t_uint256_$\",\n                                \"typeString\": \"function (uint256,uint256) pure returns (uint256)\"\n                              }\n                            },\n                            \"id\": 3948,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": false,\n                            \"kind\": \"functionCall\",\n                            \"lValueRequested\": false,\n                            \"names\": [],\n                            \"nodeType\": \"FunctionCall\",\n                            \"src\": \"8887:35:6\",\n                            \"tryCall\": false,\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"src\": \"8861:61:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"id\": 3950,\n                        \"nodeType\": \"ExpressionStatement\",\n                        \"src\": \"8861:61:6\"\n                      },\n                      {\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 3959,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"leftHandSide\": {\n                            \"argumentTypes\": null,\n                            \"expression\": {\n                              \"argumentTypes\": null,\n                              \"id\": 3951,\n                              \"name\": \"_accruedGlobalLiquidity\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 3774,\n                              \"src\": \"8936:23:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                                \"typeString\": \"struct AssetLib.Asset storage ref\"\n                              }\n                            },\n                            \"id\": 3953,\n                            \"isConstant\": false,\n                            \"isLValue\": true,\n                            \"isPure\": false,\n                            \"lValueRequested\": true,\n                            \"memberName\": \"principal\",\n                            \"nodeType\": \"MemberAccess\",\n                            \"referencedDeclaration\": 2785,\n                            \"src\": \"8936:33:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"nodeType\": \"Assignment\",\n                          \"operator\": \"=\",\n                          \"rightHandSide\": {\n                            \"argumentTypes\": null,\n                            \"arguments\": [\n                              {\n                                \"argumentTypes\": null,\n                                \"id\": 3957,\n                                \"name\": \"amount\",\n                                \"nodeType\": \"Identifier\",\n                                \"overloadedDeclarations\": [],\n                                \"referencedDeclaration\": 3913,\n                                \"src\": \"9010:6:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              }\n                            ],\n                            \"expression\": {\n                              \"argumentTypes\": [\n                                {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              ],\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"expression\": {\n                                  \"argumentTypes\": null,\n                                  \"id\": 3954,\n                                  \"name\": \"_accruedGlobalLiquidity\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 3774,\n                                  \"src\": \"8972:23:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                                    \"typeString\": \"struct AssetLib.Asset storage ref\"\n                                  }\n                                },\n                                \"id\": 3955,\n                                \"isConstant\": false,\n                                \"isLValue\": true,\n                                \"isPure\": false,\n                                \"lValueRequested\": false,\n                                \"memberName\": \"principal\",\n                                \"nodeType\": \"MemberAccess\",\n                                \"referencedDeclaration\": 2785,\n                                \"src\": \"8972:33:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              },\n                              \"id\": 3956,\n                              \"isConstant\": false,\n                              \"isLValue\": false,\n                              \"isPure\": false,\n                              \"lValueRequested\": false,\n                              \"memberName\": \"add\",\n                              \"nodeType\": \"MemberAccess\",\n                              \"referencedDeclaration\": 5870,\n                              \"src\": \"8972:37:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_function_internal_pure$_t_uint256_$_t_uint256_$returns$_t_uint256_$bound_to$_t_uint256_$\",\n                                \"typeString\": \"function (uint256,uint256) pure returns (uint256)\"\n                              }\n                            },\n                            \"id\": 3958,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": false,\n                            \"kind\": \"functionCall\",\n                            \"lValueRequested\": false,\n                            \"names\": [],\n                            \"nodeType\": \"FunctionCall\",\n                            \"src\": \"8972:45:6\",\n                            \"tryCall\": false,\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"src\": \"8936:81:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"id\": 3960,\n                        \"nodeType\": \"ExpressionStatement\",\n                        \"src\": \"8936:81:6\"\n                      },\n                      {\n                        \"eventCall\": {\n                          \"argumentTypes\": null,\n                          \"arguments\": [\n                            {\n                              \"argumentTypes\": null,\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"id\": 3962,\n                                \"name\": \"msg\",\n                                \"nodeType\": \"Identifier\",\n                                \"overloadedDeclarations\": [],\n                                \"referencedDeclaration\": -15,\n                                \"src\": \"9055:3:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_magic_message\",\n                                  \"typeString\": \"msg\"\n                                }\n                              },\n                              \"id\": 3963,\n                              \"isConstant\": false,\n                              \"isLValue\": false,\n                              \"isPure\": false,\n                              \"lValueRequested\": false,\n                              \"memberName\": \"sender\",\n                              \"nodeType\": \"MemberAccess\",\n                              \"referencedDeclaration\": null,\n                              \"src\": \"9055:10:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_address_payable\",\n                                \"typeString\": \"address payable\"\n                              }\n                            },\n                            {\n                              \"argumentTypes\": null,\n                              \"id\": 3964,\n                              \"name\": \"amount\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 3913,\n                              \"src\": \"9067:6:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_uint256\",\n                                \"typeString\": \"uint256\"\n                              }\n                            }\n                          ],\n                          \"expression\": {\n                            \"argumentTypes\": [\n                              {\n                                \"typeIdentifier\": \"t_address_payable\",\n                                \"typeString\": \"address payable\"\n                              },\n                              {\n                                \"typeIdentifier\": \"t_uint256\",\n                                \"typeString\": \"uint256\"\n                              }\n                            ],\n                            \"id\": 3961,\n                            \"name\": \"LiquidityDeposited\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 3686,\n                            \"src\": \"9036:18:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_function_event_nonpayable$_t_address_$_t_uint256_$returns$__$\",\n                              \"typeString\": \"function (address,uint256)\"\n                            }\n                          },\n                          \"id\": 3965,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"kind\": \"functionCall\",\n                          \"lValueRequested\": false,\n                          \"names\": [],\n                          \"nodeType\": \"FunctionCall\",\n                          \"src\": \"9036:38:6\",\n                          \"tryCall\": false,\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_tuple$__$\",\n                            \"typeString\": \"tuple()\"\n                          }\n                        },\n                        \"id\": 3966,\n                        \"nodeType\": \"EmitStatement\",\n                        \"src\": \"9031:43:6\"\n                      }\n                    ]\n                  }\n                },\n                {\n                  \"assignments\": [\n                    3970\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 3970,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"curr_block\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 3997,\n                      \"src\": \"9095:18:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"default\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      },\n                      \"typeName\": {\n                        \"id\": 3969,\n                        \"name\": \"uint256\",\n                        \"nodeType\": \"ElementaryTypeName\",\n                        \"src\": \"9095:7:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 3973,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [],\n                    \"expression\": {\n                      \"argumentTypes\": [],\n                      \"id\": 3971,\n                      \"name\": \"_getBlockNumber\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5019,\n                      \"src\": \"9116:15:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_view$__$returns$_t_uint256_$\",\n                        \"typeString\": \"function () view returns (uint256)\"\n                      }\n                    },\n                    \"id\": 3972,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"9116:17:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"9095:38:6\"\n                },\n                {\n                  \"assignments\": [\n                    null,\n                    3977,\n                    null\n                  ],\n                  \"declarations\": [\n                    null,\n                    {\n                      \"constant\": false,\n                      \"id\": 3977,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"liquidity\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 3997,\n                      \"src\": \"9146:32:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"storage\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                        \"typeString\": \"struct AssetLib.Asset\"\n                      },\n                      \"typeName\": {\n                        \"contractScope\": null,\n                        \"id\": 3976,\n                        \"name\": \"AssetLib.Asset\",\n                        \"nodeType\": \"UserDefinedTypeName\",\n                        \"referencedDeclaration\": 2788,\n                        \"src\": \"9146:14:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                          \"typeString\": \"struct AssetLib.Asset\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    },\n                    null\n                  ],\n                  \"id\": 3983,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 3979,\n                          \"name\": \"msg\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": -15,\n                          \"src\": \"9201:3:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_magic_message\",\n                            \"typeString\": \"msg\"\n                          }\n                        },\n                        \"id\": 3980,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"memberName\": \"sender\",\n                        \"nodeType\": \"MemberAccess\",\n                        \"referencedDeclaration\": null,\n                        \"src\": \"9201:10:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 3981,\n                        \"name\": \"curr_block\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 3970,\n                        \"src\": \"9213:10:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"id\": 3978,\n                      \"name\": \"_collectLiquidity\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5489,\n                      \"src\": \"9183:17:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_nonpayable$_t_address_$_t_uint256_$returns$_t_struct$_Asset_$2788_memory_ptr_$_t_struct$_Asset_$2788_storage_ptr_$_t_bool_$\",\n                        \"typeString\": \"function (address,uint256) returns (struct AssetLib.Asset memory,struct AssetLib.Asset storage pointer,bool)\"\n                      }\n                    },\n                    \"id\": 3982,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"9183:41:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$_t_struct$_Asset_$2788_memory_ptr_$_t_struct$_Asset_$2788_storage_ptr_$_t_bool_$\",\n                      \"typeString\": \"tuple(struct AssetLib.Asset memory,struct AssetLib.Asset storage pointer,bool)\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"9143:81:6\"\n                },\n                {\n                  \"condition\": {\n                    \"argumentTypes\": null,\n                    \"id\": 3984,\n                    \"name\": \"makeTransfer\",\n                    \"nodeType\": \"Identifier\",\n                    \"overloadedDeclarations\": [],\n                    \"referencedDeclaration\": 3924,\n                    \"src\": \"9239:12:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_bool\",\n                      \"typeString\": \"bool\"\n                    }\n                  },\n                  \"falseBody\": null,\n                  \"id\": 3996,\n                  \"nodeType\": \"IfStatement\",\n                  \"src\": \"9235:95:6\",\n                  \"trueBody\": {\n                    \"id\": 3995,\n                    \"nodeType\": \"Block\",\n                    \"src\": \"9253:77:6\",\n                    \"statements\": [\n                      {\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 3993,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"leftHandSide\": {\n                            \"argumentTypes\": null,\n                            \"expression\": {\n                              \"argumentTypes\": null,\n                              \"id\": 3985,\n                              \"name\": \"liquidity\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 3977,\n                              \"src\": \"9267:9:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                                \"typeString\": \"struct AssetLib.Asset storage pointer\"\n                              }\n                            },\n                            \"id\": 3987,\n                            \"isConstant\": false,\n                            \"isLValue\": true,\n                            \"isPure\": false,\n                            \"lValueRequested\": true,\n                            \"memberName\": \"principal\",\n                            \"nodeType\": \"MemberAccess\",\n                            \"referencedDeclaration\": 2785,\n                            \"src\": \"9267:19:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"nodeType\": \"Assignment\",\n                          \"operator\": \"=\",\n                          \"rightHandSide\": {\n                            \"argumentTypes\": null,\n                            \"arguments\": [\n                              {\n                                \"argumentTypes\": null,\n                                \"id\": 3991,\n                                \"name\": \"amount\",\n                                \"nodeType\": \"Identifier\",\n                                \"overloadedDeclarations\": [],\n                                \"referencedDeclaration\": 3913,\n                                \"src\": \"9313:6:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              }\n                            ],\n                            \"expression\": {\n                              \"argumentTypes\": [\n                                {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              ],\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"expression\": {\n                                  \"argumentTypes\": null,\n                                  \"id\": 3988,\n                                  \"name\": \"liquidity\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 3977,\n                                  \"src\": \"9289:9:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                                    \"typeString\": \"struct AssetLib.Asset storage pointer\"\n                                  }\n                                },\n                                \"id\": 3989,\n                                \"isConstant\": false,\n                                \"isLValue\": true,\n                                \"isPure\": false,\n                                \"lValueRequested\": false,\n                                \"memberName\": \"principal\",\n                                \"nodeType\": \"MemberAccess\",\n                                \"referencedDeclaration\": 2785,\n                                \"src\": \"9289:19:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              },\n                              \"id\": 3990,\n                              \"isConstant\": false,\n                              \"isLValue\": false,\n                              \"isPure\": false,\n                              \"lValueRequested\": false,\n                              \"memberName\": \"add\",\n                              \"nodeType\": \"MemberAccess\",\n                              \"referencedDeclaration\": 5870,\n                              \"src\": \"9289:23:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_function_internal_pure$_t_uint256_$_t_uint256_$returns$_t_uint256_$bound_to$_t_uint256_$\",\n                                \"typeString\": \"function (uint256,uint256) pure returns (uint256)\"\n                              }\n                            },\n                            \"id\": 3992,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": false,\n                            \"kind\": \"functionCall\",\n                            \"lValueRequested\": false,\n                            \"names\": [],\n                            \"nodeType\": \"FunctionCall\",\n                            \"src\": \"9289:31:6\",\n                            \"tryCall\": false,\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"src\": \"9267:53:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"id\": 3994,\n                        \"nodeType\": \"ExpressionStatement\",\n                        \"src\": \"9267:53:6\"\n                      }\n                    ]\n                  }\n                }\n              ]\n            },\n            \"documentation\": null,\n            \"functionSelector\": \"e2bbb158\",\n            \"id\": 3998,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [\n              {\n                \"arguments\": [\n                  {\n                    \"argumentTypes\": null,\n                    \"id\": 3918,\n                    \"name\": \"txExpirationBlock\",\n                    \"nodeType\": \"Identifier\",\n                    \"overloadedDeclarations\": [],\n                    \"referencedDeclaration\": 3915,\n                    \"src\": \"8635:17:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  }\n                ],\n                \"id\": 3919,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 3917,\n                  \"name\": \"verifyTxExpiration\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 3836,\n                  \"src\": \"8616:18:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$_t_uint256_$\",\n                    \"typeString\": \"modifier (uint256)\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"8616:37:6\"\n              },\n              {\n                \"arguments\": null,\n                \"id\": 3921,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 3920,\n                  \"name\": \"verifyNotPaused\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 3848,\n                  \"src\": \"8662:15:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$__$\",\n                    \"typeString\": \"modifier ()\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"8662:15:6\"\n              }\n            ],\n            \"name\": \"deposit\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 3916,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 3913,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"amount\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3998,\n                  \"src\": \"8531:14:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3912,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"8531:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 3915,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"txExpirationBlock\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 3998,\n                  \"src\": \"8555:25:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 3914,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"8555:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"8521:69:6\"\n            },\n            \"returnParameters\": {\n              \"id\": 3922,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"8682:0:6\"\n            },\n            \"scope\": 5490,\n            \"src\": \"8505:831:6\",\n            \"stateMutability\": \"nonpayable\",\n            \"virtual\": false,\n            \"visibility\": \"external\"\n          },\n          {\n            \"body\": {\n              \"id\": 4045,\n              \"nodeType\": \"Block\",\n              \"src\": \"9796:317:6\",\n              \"statements\": [\n                {\n                  \"assignments\": [\n                    4012\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 4012,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"sender\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 4045,\n                      \"src\": \"9806:14:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"default\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_address\",\n                        \"typeString\": \"address\"\n                      },\n                      \"typeName\": {\n                        \"id\": 4011,\n                        \"name\": \"address\",\n                        \"nodeType\": \"ElementaryTypeName\",\n                        \"src\": \"9806:7:6\",\n                        \"stateMutability\": \"nonpayable\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 4015,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"expression\": {\n                      \"argumentTypes\": null,\n                      \"id\": 4013,\n                      \"name\": \"msg\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": -15,\n                      \"src\": \"9823:3:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_magic_message\",\n                        \"typeString\": \"msg\"\n                      }\n                    },\n                    \"id\": 4014,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"memberName\": \"sender\",\n                    \"nodeType\": \"MemberAccess\",\n                    \"referencedDeclaration\": null,\n                    \"src\": \"9823:10:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address_payable\",\n                      \"typeString\": \"address payable\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"9806:27:6\"\n                },\n                {\n                  \"assignments\": [\n                    4017\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 4017,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"curr_block\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 4045,\n                      \"src\": \"9843:18:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"default\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      },\n                      \"typeName\": {\n                        \"id\": 4016,\n                        \"name\": \"uint256\",\n                        \"nodeType\": \"ElementaryTypeName\",\n                        \"src\": \"9843:7:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 4020,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [],\n                    \"expression\": {\n                      \"argumentTypes\": [],\n                      \"id\": 4018,\n                      \"name\": \"_getBlockNumber\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5019,\n                      \"src\": \"9864:15:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_view$__$returns$_t_uint256_$\",\n                        \"typeString\": \"function () view returns (uint256)\"\n                      }\n                    },\n                    \"id\": 4019,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"9864:17:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"9843:38:6\"\n                },\n                {\n                  \"assignments\": [\n                    null,\n                    4024,\n                    null\n                  ],\n                  \"declarations\": [\n                    null,\n                    {\n                      \"constant\": false,\n                      \"id\": 4024,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"liquidity\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 4045,\n                      \"src\": \"9894:32:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"storage\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                        \"typeString\": \"struct AssetLib.Asset\"\n                      },\n                      \"typeName\": {\n                        \"contractScope\": null,\n                        \"id\": 4023,\n                        \"name\": \"AssetLib.Asset\",\n                        \"nodeType\": \"UserDefinedTypeName\",\n                        \"referencedDeclaration\": 2788,\n                        \"src\": \"9894:14:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                          \"typeString\": \"struct AssetLib.Asset\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    },\n                    null\n                  ],\n                  \"id\": 4029,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 4026,\n                        \"name\": \"sender\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4012,\n                        \"src\": \"9949:6:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 4027,\n                        \"name\": \"curr_block\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4017,\n                        \"src\": \"9957:10:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"id\": 4025,\n                      \"name\": \"_collectLiquidity\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5489,\n                      \"src\": \"9931:17:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_nonpayable$_t_address_$_t_uint256_$returns$_t_struct$_Asset_$2788_memory_ptr_$_t_struct$_Asset_$2788_storage_ptr_$_t_bool_$\",\n                        \"typeString\": \"function (address,uint256) returns (struct AssetLib.Asset memory,struct AssetLib.Asset storage pointer,bool)\"\n                      }\n                    },\n                    \"id\": 4028,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"9931:37:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$_t_struct$_Asset_$2788_memory_ptr_$_t_struct$_Asset_$2788_storage_ptr_$_t_bool_$\",\n                      \"typeString\": \"tuple(struct AssetLib.Asset memory,struct AssetLib.Asset storage pointer,bool)\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"9891:77:6\"\n                },\n                {\n                  \"assignments\": [\n                    4033\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 4033,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"_amount\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 4045,\n                      \"src\": \"9979:29:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"memory\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                        \"typeString\": \"struct AssetLib.Asset\"\n                      },\n                      \"typeName\": {\n                        \"contractScope\": null,\n                        \"id\": 4032,\n                        \"name\": \"AssetLib.Asset\",\n                        \"nodeType\": \"UserDefinedTypeName\",\n                        \"referencedDeclaration\": 2788,\n                        \"src\": \"9979:14:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                          \"typeString\": \"struct AssetLib.Asset\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 4038,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 4036,\n                        \"name\": \"amount\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4001,\n                        \"src\": \"10047:6:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 4034,\n                        \"name\": \"liquidity\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4024,\n                        \"src\": \"10011:9:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                          \"typeString\": \"struct AssetLib.Asset storage pointer\"\n                        }\n                      },\n                      \"id\": 4035,\n                      \"isConstant\": false,\n                      \"isLValue\": true,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"memberName\": \"iSubCompoundInterestFirst\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": 3072,\n                      \"src\": \"10011:35:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_nonpayable$_t_struct$_Asset_$2788_storage_ptr_$_t_uint256_$returns$_t_struct$_Asset_$2788_memory_ptr_$bound_to$_t_struct$_Asset_$2788_storage_ptr_$\",\n                        \"typeString\": \"function (struct AssetLib.Asset storage pointer,uint256) returns (struct AssetLib.Asset memory)\"\n                      }\n                    },\n                    \"id\": 4037,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"10011:43:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                      \"typeString\": \"struct AssetLib.Asset memory\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"9979:75:6\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 4040,\n                        \"name\": \"sender\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4012,\n                        \"src\": \"10082:6:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 4041,\n                        \"name\": \"_amount\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4033,\n                        \"src\": \"10090:7:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                          \"typeString\": \"struct AssetLib.Asset memory\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 4042,\n                        \"name\": \"amount\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4001,\n                        \"src\": \"10099:6:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                          \"typeString\": \"struct AssetLib.Asset memory\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"id\": 4039,\n                      \"name\": \"_finaliseWithdraw\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5168,\n                      \"src\": \"10064:17:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_nonpayable$_t_address_$_t_struct$_Asset_$2788_memory_ptr_$_t_uint256_$returns$__$\",\n                        \"typeString\": \"function (address,struct AssetLib.Asset memory,uint256)\"\n                      }\n                    },\n                    \"id\": 4043,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"10064:42:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 4044,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"10064:42:6\"\n                }\n              ]\n            },\n            \"documentation\": {\n              \"id\": 3999,\n              \"nodeType\": \"StructuredDocumentation\",\n              \"src\": \"9343:270:6\",\n              \"text\": \"@notice Withdraws amount from sender' available liquidity pool back to sender address,\\n        preferring withdrawal from compound interest dimension of liquidity.\\n     * @param amount - value to withdraw\\n     * @dev public access\"\n            },\n            \"functionSelector\": \"441a3e70\",\n            \"id\": 4046,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [\n              {\n                \"arguments\": [\n                  {\n                    \"argumentTypes\": null,\n                    \"id\": 4006,\n                    \"name\": \"txExpirationBlock\",\n                    \"nodeType\": \"Identifier\",\n                    \"overloadedDeclarations\": [],\n                    \"referencedDeclaration\": 4003,\n                    \"src\": \"9749:17:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  }\n                ],\n                \"id\": 4007,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 4005,\n                  \"name\": \"verifyTxExpiration\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 3836,\n                  \"src\": \"9730:18:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$_t_uint256_$\",\n                    \"typeString\": \"modifier (uint256)\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"9730:37:6\"\n              },\n              {\n                \"arguments\": null,\n                \"id\": 4009,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 4008,\n                  \"name\": \"verifyNotPaused\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 3848,\n                  \"src\": \"9776:15:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$__$\",\n                    \"typeString\": \"modifier ()\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"9776:15:6\"\n              }\n            ],\n            \"name\": \"withdraw\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 4004,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 4001,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"amount\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4046,\n                  \"src\": \"9645:14:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 4000,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"9645:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 4003,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"txExpirationBlock\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4046,\n                  \"src\": \"9669:25:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 4002,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"9669:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"9635:69:6\"\n            },\n            \"returnParameters\": {\n              \"id\": 4010,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"9796:0:6\"\n            },\n            \"scope\": 5490,\n            \"src\": \"9618:495:6\",\n            \"stateMutability\": \"nonpayable\",\n            \"virtual\": false,\n            \"visibility\": \"external\"\n          },\n          {\n            \"body\": {\n              \"id\": 4101,\n              \"nodeType\": \"Block\",\n              \"src\": \"10411:366:6\",\n              \"statements\": [\n                {\n                  \"assignments\": [\n                    4058\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 4058,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"sender\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 4101,\n                      \"src\": \"10421:14:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"default\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_address\",\n                        \"typeString\": \"address\"\n                      },\n                      \"typeName\": {\n                        \"id\": 4057,\n                        \"name\": \"address\",\n                        \"nodeType\": \"ElementaryTypeName\",\n                        \"src\": \"10421:7:6\",\n                        \"stateMutability\": \"nonpayable\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 4061,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"expression\": {\n                      \"argumentTypes\": null,\n                      \"id\": 4059,\n                      \"name\": \"msg\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": -15,\n                      \"src\": \"10438:3:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_magic_message\",\n                        \"typeString\": \"msg\"\n                      }\n                    },\n                    \"id\": 4060,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"memberName\": \"sender\",\n                    \"nodeType\": \"MemberAccess\",\n                    \"referencedDeclaration\": null,\n                    \"src\": \"10438:10:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address_payable\",\n                      \"typeString\": \"address payable\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"10421:27:6\"\n                },\n                {\n                  \"assignments\": [\n                    4063\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 4063,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"curr_block\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 4101,\n                      \"src\": \"10458:18:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"default\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      },\n                      \"typeName\": {\n                        \"id\": 4062,\n                        \"name\": \"uint256\",\n                        \"nodeType\": \"ElementaryTypeName\",\n                        \"src\": \"10458:7:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 4066,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [],\n                    \"expression\": {\n                      \"argumentTypes\": [],\n                      \"id\": 4064,\n                      \"name\": \"_getBlockNumber\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5019,\n                      \"src\": \"10479:15:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_view$__$returns$_t_uint256_$\",\n                        \"typeString\": \"function () view returns (uint256)\"\n                      }\n                    },\n                    \"id\": 4065,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"10479:17:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"10458:38:6\"\n                },\n                {\n                  \"assignments\": [\n                    null,\n                    4070,\n                    null\n                  ],\n                  \"declarations\": [\n                    null,\n                    {\n                      \"constant\": false,\n                      \"id\": 4070,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"liquidity\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 4101,\n                      \"src\": \"10509:32:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"storage\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                        \"typeString\": \"struct AssetLib.Asset\"\n                      },\n                      \"typeName\": {\n                        \"contractScope\": null,\n                        \"id\": 4069,\n                        \"name\": \"AssetLib.Asset\",\n                        \"nodeType\": \"UserDefinedTypeName\",\n                        \"referencedDeclaration\": 2788,\n                        \"src\": \"10509:14:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                          \"typeString\": \"struct AssetLib.Asset\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    },\n                    null\n                  ],\n                  \"id\": 4075,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 4072,\n                        \"name\": \"sender\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4058,\n                        \"src\": \"10565:6:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 4073,\n                        \"name\": \"curr_block\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4063,\n                        \"src\": \"10573:10:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"id\": 4071,\n                      \"name\": \"_collectLiquidity\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5489,\n                      \"src\": \"10547:17:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_nonpayable$_t_address_$_t_uint256_$returns$_t_struct$_Asset_$2788_memory_ptr_$_t_struct$_Asset_$2788_storage_ptr_$_t_bool_$\",\n                        \"typeString\": \"function (address,uint256) returns (struct AssetLib.Asset memory,struct AssetLib.Asset storage pointer,bool)\"\n                      }\n                    },\n                    \"id\": 4074,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"10547:37:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$_t_struct$_Asset_$2788_memory_ptr_$_t_struct$_Asset_$2788_storage_ptr_$_t_bool_$\",\n                      \"typeString\": \"tuple(struct AssetLib.Asset memory,struct AssetLib.Asset storage pointer,bool)\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"10506:78:6\"\n                },\n                {\n                  \"assignments\": [\n                    4079\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 4079,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"_amount\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 4101,\n                      \"src\": \"10595:29:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"memory\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                        \"typeString\": \"struct AssetLib.Asset\"\n                      },\n                      \"typeName\": {\n                        \"contractScope\": null,\n                        \"id\": 4078,\n                        \"name\": \"AssetLib.Asset\",\n                        \"nodeType\": \"UserDefinedTypeName\",\n                        \"referencedDeclaration\": 2788,\n                        \"src\": \"10595:14:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                          \"typeString\": \"struct AssetLib.Asset\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 4080,\n                  \"initialValue\": null,\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"10595:29:6\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 4086,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 4081,\n                        \"name\": \"_amount\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4079,\n                        \"src\": \"10634:7:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                          \"typeString\": \"struct AssetLib.Asset memory\"\n                        }\n                      },\n                      \"id\": 4083,\n                      \"isConstant\": false,\n                      \"isLValue\": true,\n                      \"isPure\": false,\n                      \"lValueRequested\": true,\n                      \"memberName\": \"principal\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": 2785,\n                      \"src\": \"10634:17:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 4084,\n                        \"name\": \"liquidity\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4070,\n                        \"src\": \"10654:9:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                          \"typeString\": \"struct AssetLib.Asset storage pointer\"\n                        }\n                      },\n                      \"id\": 4085,\n                      \"isConstant\": false,\n                      \"isLValue\": true,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"memberName\": \"principal\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": 2785,\n                      \"src\": \"10654:19:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"src\": \"10634:39:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"id\": 4087,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"10634:39:6\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 4092,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 4088,\n                        \"name\": \"liquidity\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4070,\n                        \"src\": \"10683:9:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                          \"typeString\": \"struct AssetLib.Asset storage pointer\"\n                        }\n                      },\n                      \"id\": 4090,\n                      \"isConstant\": false,\n                      \"isLValue\": true,\n                      \"isPure\": false,\n                      \"lValueRequested\": true,\n                      \"memberName\": \"principal\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": 2785,\n                      \"src\": \"10683:19:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"hexValue\": \"30\",\n                      \"id\": 4091,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": true,\n                      \"kind\": \"number\",\n                      \"lValueRequested\": false,\n                      \"nodeType\": \"Literal\",\n                      \"src\": \"10705:1:6\",\n                      \"subdenomination\": null,\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_rational_0_by_1\",\n                        \"typeString\": \"int_const 0\"\n                      },\n                      \"value\": \"0\"\n                    },\n                    \"src\": \"10683:23:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"id\": 4093,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"10683:23:6\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 4095,\n                        \"name\": \"sender\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4058,\n                        \"src\": \"10735:6:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 4096,\n                        \"name\": \"_amount\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4079,\n                        \"src\": \"10743:7:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                          \"typeString\": \"struct AssetLib.Asset memory\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 4097,\n                          \"name\": \"_amount\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 4079,\n                          \"src\": \"10752:7:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                            \"typeString\": \"struct AssetLib.Asset memory\"\n                          }\n                        },\n                        \"id\": 4098,\n                        \"isConstant\": false,\n                        \"isLValue\": true,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"memberName\": \"principal\",\n                        \"nodeType\": \"MemberAccess\",\n                        \"referencedDeclaration\": 2785,\n                        \"src\": \"10752:17:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                          \"typeString\": \"struct AssetLib.Asset memory\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"id\": 4094,\n                      \"name\": \"_finaliseWithdraw\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5168,\n                      \"src\": \"10717:17:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_nonpayable$_t_address_$_t_struct$_Asset_$2788_memory_ptr_$_t_uint256_$returns$__$\",\n                        \"typeString\": \"function (address,struct AssetLib.Asset memory,uint256)\"\n                      }\n                    },\n                    \"id\": 4099,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"10717:53:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 4100,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"10717:53:6\"\n                }\n              ]\n            },\n            \"documentation\": {\n              \"id\": 4047,\n              \"nodeType\": \"StructuredDocumentation\",\n              \"src\": \"10120:123:6\",\n              \"text\": \"@notice Withdraws *WHOLE* compound interest amount available to sender.\\n     * @dev public access\"\n            },\n            \"functionSelector\": \"658e28a4\",\n            \"id\": 4102,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [\n              {\n                \"arguments\": [\n                  {\n                    \"argumentTypes\": null,\n                    \"id\": 4052,\n                    \"name\": \"txExpirationBlock\",\n                    \"nodeType\": \"Identifier\",\n                    \"overloadedDeclarations\": [],\n                    \"referencedDeclaration\": 4049,\n                    \"src\": \"10364:17:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  }\n                ],\n                \"id\": 4053,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 4051,\n                  \"name\": \"verifyTxExpiration\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 3836,\n                  \"src\": \"10345:18:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$_t_uint256_$\",\n                    \"typeString\": \"modifier (uint256)\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"10345:37:6\"\n              },\n              {\n                \"arguments\": null,\n                \"id\": 4055,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 4054,\n                  \"name\": \"verifyNotPaused\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 3848,\n                  \"src\": \"10391:15:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$__$\",\n                    \"typeString\": \"modifier ()\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"10391:15:6\"\n              }\n            ],\n            \"name\": \"withdrawPrincipal\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 4050,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 4049,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"txExpirationBlock\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4102,\n                  \"src\": \"10284:25:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 4048,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"10284:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"10274:45:6\"\n            },\n            \"returnParameters\": {\n              \"id\": 4056,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"10411:0:6\"\n            },\n            \"scope\": 5490,\n            \"src\": \"10248:529:6\",\n            \"stateMutability\": \"nonpayable\",\n            \"virtual\": false,\n            \"visibility\": \"external\"\n          },\n          {\n            \"body\": {\n              \"id\": 4157,\n              \"nodeType\": \"Block\",\n              \"src\": \"11082:394:6\",\n              \"statements\": [\n                {\n                  \"assignments\": [\n                    4114\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 4114,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"sender\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 4157,\n                      \"src\": \"11092:14:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"default\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_address\",\n                        \"typeString\": \"address\"\n                      },\n                      \"typeName\": {\n                        \"id\": 4113,\n                        \"name\": \"address\",\n                        \"nodeType\": \"ElementaryTypeName\",\n                        \"src\": \"11092:7:6\",\n                        \"stateMutability\": \"nonpayable\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 4117,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"expression\": {\n                      \"argumentTypes\": null,\n                      \"id\": 4115,\n                      \"name\": \"msg\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": -15,\n                      \"src\": \"11109:3:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_magic_message\",\n                        \"typeString\": \"msg\"\n                      }\n                    },\n                    \"id\": 4116,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"memberName\": \"sender\",\n                    \"nodeType\": \"MemberAccess\",\n                    \"referencedDeclaration\": null,\n                    \"src\": \"11109:10:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address_payable\",\n                      \"typeString\": \"address payable\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"11092:27:6\"\n                },\n                {\n                  \"assignments\": [\n                    4119\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 4119,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"curr_block\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 4157,\n                      \"src\": \"11129:18:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"default\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      },\n                      \"typeName\": {\n                        \"id\": 4118,\n                        \"name\": \"uint256\",\n                        \"nodeType\": \"ElementaryTypeName\",\n                        \"src\": \"11129:7:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 4122,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [],\n                    \"expression\": {\n                      \"argumentTypes\": [],\n                      \"id\": 4120,\n                      \"name\": \"_getBlockNumber\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5019,\n                      \"src\": \"11150:15:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_view$__$returns$_t_uint256_$\",\n                        \"typeString\": \"function () view returns (uint256)\"\n                      }\n                    },\n                    \"id\": 4121,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"11150:17:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"11129:38:6\"\n                },\n                {\n                  \"assignments\": [\n                    null,\n                    4126,\n                    null\n                  ],\n                  \"declarations\": [\n                    null,\n                    {\n                      \"constant\": false,\n                      \"id\": 4126,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"liquidity\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 4157,\n                      \"src\": \"11180:32:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"storage\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                        \"typeString\": \"struct AssetLib.Asset\"\n                      },\n                      \"typeName\": {\n                        \"contractScope\": null,\n                        \"id\": 4125,\n                        \"name\": \"AssetLib.Asset\",\n                        \"nodeType\": \"UserDefinedTypeName\",\n                        \"referencedDeclaration\": 2788,\n                        \"src\": \"11180:14:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                          \"typeString\": \"struct AssetLib.Asset\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    },\n                    null\n                  ],\n                  \"id\": 4131,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 4128,\n                        \"name\": \"sender\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4114,\n                        \"src\": \"11236:6:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 4129,\n                        \"name\": \"curr_block\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4119,\n                        \"src\": \"11244:10:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"id\": 4127,\n                      \"name\": \"_collectLiquidity\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5489,\n                      \"src\": \"11218:17:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_nonpayable$_t_address_$_t_uint256_$returns$_t_struct$_Asset_$2788_memory_ptr_$_t_struct$_Asset_$2788_storage_ptr_$_t_bool_$\",\n                        \"typeString\": \"function (address,uint256) returns (struct AssetLib.Asset memory,struct AssetLib.Asset storage pointer,bool)\"\n                      }\n                    },\n                    \"id\": 4130,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"11218:37:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$_t_struct$_Asset_$2788_memory_ptr_$_t_struct$_Asset_$2788_storage_ptr_$_t_bool_$\",\n                      \"typeString\": \"tuple(struct AssetLib.Asset memory,struct AssetLib.Asset storage pointer,bool)\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"11177:78:6\"\n                },\n                {\n                  \"assignments\": [\n                    4135\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 4135,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"_amount\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 4157,\n                      \"src\": \"11266:29:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"memory\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                        \"typeString\": \"struct AssetLib.Asset\"\n                      },\n                      \"typeName\": {\n                        \"contractScope\": null,\n                        \"id\": 4134,\n                        \"name\": \"AssetLib.Asset\",\n                        \"nodeType\": \"UserDefinedTypeName\",\n                        \"referencedDeclaration\": 2788,\n                        \"src\": \"11266:14:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                          \"typeString\": \"struct AssetLib.Asset\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 4136,\n                  \"initialValue\": null,\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"11266:29:6\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 4142,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 4137,\n                        \"name\": \"_amount\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4135,\n                        \"src\": \"11305:7:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                          \"typeString\": \"struct AssetLib.Asset memory\"\n                        }\n                      },\n                      \"id\": 4139,\n                      \"isConstant\": false,\n                      \"isLValue\": true,\n                      \"isPure\": false,\n                      \"lValueRequested\": true,\n                      \"memberName\": \"compoundInterest\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": 2787,\n                      \"src\": \"11305:24:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 4140,\n                        \"name\": \"liquidity\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4126,\n                        \"src\": \"11332:9:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                          \"typeString\": \"struct AssetLib.Asset storage pointer\"\n                        }\n                      },\n                      \"id\": 4141,\n                      \"isConstant\": false,\n                      \"isLValue\": true,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"memberName\": \"compoundInterest\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": 2787,\n                      \"src\": \"11332:26:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"src\": \"11305:53:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"id\": 4143,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"11305:53:6\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 4148,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 4144,\n                        \"name\": \"liquidity\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4126,\n                        \"src\": \"11368:9:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                          \"typeString\": \"struct AssetLib.Asset storage pointer\"\n                        }\n                      },\n                      \"id\": 4146,\n                      \"isConstant\": false,\n                      \"isLValue\": true,\n                      \"isPure\": false,\n                      \"lValueRequested\": true,\n                      \"memberName\": \"compoundInterest\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": 2787,\n                      \"src\": \"11368:26:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"hexValue\": \"30\",\n                      \"id\": 4147,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": true,\n                      \"kind\": \"number\",\n                      \"lValueRequested\": false,\n                      \"nodeType\": \"Literal\",\n                      \"src\": \"11397:1:6\",\n                      \"subdenomination\": null,\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_rational_0_by_1\",\n                        \"typeString\": \"int_const 0\"\n                      },\n                      \"value\": \"0\"\n                    },\n                    \"src\": \"11368:30:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"id\": 4149,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"11368:30:6\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 4151,\n                        \"name\": \"sender\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4114,\n                        \"src\": \"11427:6:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 4152,\n                        \"name\": \"_amount\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4135,\n                        \"src\": \"11435:7:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                          \"typeString\": \"struct AssetLib.Asset memory\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 4153,\n                          \"name\": \"_amount\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 4135,\n                          \"src\": \"11444:7:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                            \"typeString\": \"struct AssetLib.Asset memory\"\n                          }\n                        },\n                        \"id\": 4154,\n                        \"isConstant\": false,\n                        \"isLValue\": true,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"memberName\": \"compoundInterest\",\n                        \"nodeType\": \"MemberAccess\",\n                        \"referencedDeclaration\": 2787,\n                        \"src\": \"11444:24:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                          \"typeString\": \"struct AssetLib.Asset memory\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"id\": 4150,\n                      \"name\": \"_finaliseWithdraw\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5168,\n                      \"src\": \"11409:17:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_nonpayable$_t_address_$_t_struct$_Asset_$2788_memory_ptr_$_t_uint256_$returns$__$\",\n                        \"typeString\": \"function (address,struct AssetLib.Asset memory,uint256)\"\n                      }\n                    },\n                    \"id\": 4155,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"11409:60:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 4156,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"11409:60:6\"\n                }\n              ]\n            },\n            \"documentation\": {\n              \"id\": 4103,\n              \"nodeType\": \"StructuredDocumentation\",\n              \"src\": \"10784:123:6\",\n              \"text\": \"@notice Withdraws *WHOLE* compound interest amount available to sender.\\n     * @dev public access\"\n            },\n            \"functionSelector\": \"d8cd3999\",\n            \"id\": 4158,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [\n              {\n                \"arguments\": [\n                  {\n                    \"argumentTypes\": null,\n                    \"id\": 4108,\n                    \"name\": \"txExpirationBlock\",\n                    \"nodeType\": \"Identifier\",\n                    \"overloadedDeclarations\": [],\n                    \"referencedDeclaration\": 4105,\n                    \"src\": \"11035:17:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  }\n                ],\n                \"id\": 4109,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 4107,\n                  \"name\": \"verifyTxExpiration\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 3836,\n                  \"src\": \"11016:18:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$_t_uint256_$\",\n                    \"typeString\": \"modifier (uint256)\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"11016:37:6\"\n              },\n              {\n                \"arguments\": null,\n                \"id\": 4111,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 4110,\n                  \"name\": \"verifyNotPaused\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 3848,\n                  \"src\": \"11062:15:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$__$\",\n                    \"typeString\": \"modifier ()\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"11062:15:6\"\n              }\n            ],\n            \"name\": \"withdrawCompoundInterest\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 4106,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 4105,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"txExpirationBlock\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4158,\n                  \"src\": \"10955:25:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 4104,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"10955:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"10945:45:6\"\n            },\n            \"returnParameters\": {\n              \"id\": 4112,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"11082:0:6\"\n            },\n            \"scope\": 5490,\n            \"src\": \"10912:564:6\",\n            \"stateMutability\": \"nonpayable\",\n            \"virtual\": false,\n            \"visibility\": \"external\"\n          },\n          {\n            \"body\": {\n              \"id\": 4208,\n              \"nodeType\": \"Block\",\n              \"src\": \"11786:323:6\",\n              \"statements\": [\n                {\n                  \"assignments\": [\n                    4170\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 4170,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"sender\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 4208,\n                      \"src\": \"11796:14:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"default\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_address\",\n                        \"typeString\": \"address\"\n                      },\n                      \"typeName\": {\n                        \"id\": 4169,\n                        \"name\": \"address\",\n                        \"nodeType\": \"ElementaryTypeName\",\n                        \"src\": \"11796:7:6\",\n                        \"stateMutability\": \"nonpayable\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 4173,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"expression\": {\n                      \"argumentTypes\": null,\n                      \"id\": 4171,\n                      \"name\": \"msg\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": -15,\n                      \"src\": \"11813:3:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_magic_message\",\n                        \"typeString\": \"msg\"\n                      }\n                    },\n                    \"id\": 4172,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"memberName\": \"sender\",\n                    \"nodeType\": \"MemberAccess\",\n                    \"referencedDeclaration\": null,\n                    \"src\": \"11813:10:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address_payable\",\n                      \"typeString\": \"address payable\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"11796:27:6\"\n                },\n                {\n                  \"assignments\": [\n                    4175\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 4175,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"curr_block\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 4208,\n                      \"src\": \"11833:18:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"default\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      },\n                      \"typeName\": {\n                        \"id\": 4174,\n                        \"name\": \"uint256\",\n                        \"nodeType\": \"ElementaryTypeName\",\n                        \"src\": \"11833:7:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 4178,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [],\n                    \"expression\": {\n                      \"argumentTypes\": [],\n                      \"id\": 4176,\n                      \"name\": \"_getBlockNumber\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5019,\n                      \"src\": \"11854:15:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_view$__$returns$_t_uint256_$\",\n                        \"typeString\": \"function () view returns (uint256)\"\n                      }\n                    },\n                    \"id\": 4177,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"11854:17:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"11833:38:6\"\n                },\n                {\n                  \"assignments\": [\n                    null,\n                    4182,\n                    null\n                  ],\n                  \"declarations\": [\n                    null,\n                    {\n                      \"constant\": false,\n                      \"id\": 4182,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"liquidity\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 4208,\n                      \"src\": \"11884:32:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"storage\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                        \"typeString\": \"struct AssetLib.Asset\"\n                      },\n                      \"typeName\": {\n                        \"contractScope\": null,\n                        \"id\": 4181,\n                        \"name\": \"AssetLib.Asset\",\n                        \"nodeType\": \"UserDefinedTypeName\",\n                        \"referencedDeclaration\": 2788,\n                        \"src\": \"11884:14:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                          \"typeString\": \"struct AssetLib.Asset\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    },\n                    null\n                  ],\n                  \"id\": 4187,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 4184,\n                        \"name\": \"sender\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4170,\n                        \"src\": \"11940:6:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 4185,\n                        \"name\": \"curr_block\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4175,\n                        \"src\": \"11948:10:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"id\": 4183,\n                      \"name\": \"_collectLiquidity\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5489,\n                      \"src\": \"11922:17:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_nonpayable$_t_address_$_t_uint256_$returns$_t_struct$_Asset_$2788_memory_ptr_$_t_struct$_Asset_$2788_storage_ptr_$_t_bool_$\",\n                        \"typeString\": \"function (address,uint256) returns (struct AssetLib.Asset memory,struct AssetLib.Asset storage pointer,bool)\"\n                      }\n                    },\n                    \"id\": 4186,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"11922:37:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$_t_struct$_Asset_$2788_memory_ptr_$_t_struct$_Asset_$2788_storage_ptr_$_t_bool_$\",\n                      \"typeString\": \"tuple(struct AssetLib.Asset memory,struct AssetLib.Asset storage pointer,bool)\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"11881:78:6\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 4189,\n                        \"name\": \"sender\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4170,\n                        \"src\": \"11988:6:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 4190,\n                        \"name\": \"liquidity\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4182,\n                        \"src\": \"11996:9:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                          \"typeString\": \"struct AssetLib.Asset storage pointer\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"arguments\": [],\n                        \"expression\": {\n                          \"argumentTypes\": [],\n                          \"expression\": {\n                            \"argumentTypes\": null,\n                            \"id\": 4191,\n                            \"name\": \"liquidity\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 4182,\n                            \"src\": \"12007:9:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                              \"typeString\": \"struct AssetLib.Asset storage pointer\"\n                            }\n                          },\n                          \"id\": 4192,\n                          \"isConstant\": false,\n                          \"isLValue\": true,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"memberName\": \"composite\",\n                          \"nodeType\": \"MemberAccess\",\n                          \"referencedDeclaration\": 2803,\n                          \"src\": \"12007:19:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_function_internal_view$_t_struct$_Asset_$2788_storage_ptr_$returns$_t_uint256_$bound_to$_t_struct$_Asset_$2788_storage_ptr_$\",\n                            \"typeString\": \"function (struct AssetLib.Asset storage pointer) view returns (uint256)\"\n                          }\n                        },\n                        \"id\": 4193,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"kind\": \"functionCall\",\n                        \"lValueRequested\": false,\n                        \"names\": [],\n                        \"nodeType\": \"FunctionCall\",\n                        \"src\": \"12007:21:6\",\n                        \"tryCall\": false,\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                          \"typeString\": \"struct AssetLib.Asset storage pointer\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"id\": 4188,\n                      \"name\": \"_finaliseWithdraw\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5168,\n                      \"src\": \"11970:17:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_nonpayable$_t_address_$_t_struct$_Asset_$2788_memory_ptr_$_t_uint256_$returns$__$\",\n                        \"typeString\": \"function (address,struct AssetLib.Asset memory,uint256)\"\n                      }\n                    },\n                    \"id\": 4194,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"11970:59:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 4195,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"11970:59:6\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 4200,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 4196,\n                        \"name\": \"liquidity\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4182,\n                        \"src\": \"12039:9:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                          \"typeString\": \"struct AssetLib.Asset storage pointer\"\n                        }\n                      },\n                      \"id\": 4198,\n                      \"isConstant\": false,\n                      \"isLValue\": true,\n                      \"isPure\": false,\n                      \"lValueRequested\": true,\n                      \"memberName\": \"compoundInterest\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": 2787,\n                      \"src\": \"12039:26:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"hexValue\": \"30\",\n                      \"id\": 4199,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": true,\n                      \"kind\": \"number\",\n                      \"lValueRequested\": false,\n                      \"nodeType\": \"Literal\",\n                      \"src\": \"12068:1:6\",\n                      \"subdenomination\": null,\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_rational_0_by_1\",\n                        \"typeString\": \"int_const 0\"\n                      },\n                      \"value\": \"0\"\n                    },\n                    \"src\": \"12039:30:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"id\": 4201,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"12039:30:6\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 4206,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 4202,\n                        \"name\": \"liquidity\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4182,\n                        \"src\": \"12079:9:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                          \"typeString\": \"struct AssetLib.Asset storage pointer\"\n                        }\n                      },\n                      \"id\": 4204,\n                      \"isConstant\": false,\n                      \"isLValue\": true,\n                      \"isPure\": false,\n                      \"lValueRequested\": true,\n                      \"memberName\": \"principal\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": 2785,\n                      \"src\": \"12079:19:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"hexValue\": \"30\",\n                      \"id\": 4205,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": true,\n                      \"kind\": \"number\",\n                      \"lValueRequested\": false,\n                      \"nodeType\": \"Literal\",\n                      \"src\": \"12101:1:6\",\n                      \"subdenomination\": null,\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_rational_0_by_1\",\n                        \"typeString\": \"int_const 0\"\n                      },\n                      \"value\": \"0\"\n                    },\n                    \"src\": \"12079:23:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"id\": 4207,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"12079:23:6\"\n                }\n              ]\n            },\n            \"documentation\": {\n              \"id\": 4159,\n              \"nodeType\": \"StructuredDocumentation\",\n              \"src\": \"11483:130:6\",\n              \"text\": \"@notice Withdraws whole liquidity available to sender back to sender' address,\\n     * @dev public access\"\n            },\n            \"functionSelector\": \"dca2aa5c\",\n            \"id\": 4209,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [\n              {\n                \"arguments\": [\n                  {\n                    \"argumentTypes\": null,\n                    \"id\": 4164,\n                    \"name\": \"txExpirationBlock\",\n                    \"nodeType\": \"Identifier\",\n                    \"overloadedDeclarations\": [],\n                    \"referencedDeclaration\": 4161,\n                    \"src\": \"11739:17:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  }\n                ],\n                \"id\": 4165,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 4163,\n                  \"name\": \"verifyTxExpiration\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 3836,\n                  \"src\": \"11720:18:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$_t_uint256_$\",\n                    \"typeString\": \"modifier (uint256)\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"11720:37:6\"\n              },\n              {\n                \"arguments\": null,\n                \"id\": 4167,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 4166,\n                  \"name\": \"verifyNotPaused\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 3848,\n                  \"src\": \"11766:15:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$__$\",\n                    \"typeString\": \"modifier ()\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"11766:15:6\"\n              }\n            ],\n            \"name\": \"withdrawWholeLiquidity\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 4162,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 4161,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"txExpirationBlock\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4209,\n                  \"src\": \"11659:25:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 4160,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"11659:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"11649:45:6\"\n            },\n            \"returnParameters\": {\n              \"id\": 4168,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"11786:0:6\"\n            },\n            \"scope\": 5490,\n            \"src\": \"11618:491:6\",\n            \"stateMutability\": \"nonpayable\",\n            \"virtual\": false,\n            \"visibility\": \"external\"\n          },\n          {\n            \"body\": {\n              \"id\": 4279,\n              \"nodeType\": \"Block\",\n              \"src\": \"12295:1112:6\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"commonType\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        },\n                        \"id\": 4224,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"leftExpression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 4222,\n                          \"name\": \"amount\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 4211,\n                          \"src\": \"12313:6:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"nodeType\": \"BinaryOperation\",\n                        \"operator\": \"!=\",\n                        \"rightExpression\": {\n                          \"argumentTypes\": null,\n                          \"hexValue\": \"30\",\n                          \"id\": 4223,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": true,\n                          \"kind\": \"number\",\n                          \"lValueRequested\": false,\n                          \"nodeType\": \"Literal\",\n                          \"src\": \"12323:1:6\",\n                          \"subdenomination\": null,\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_rational_0_by_1\",\n                            \"typeString\": \"int_const 0\"\n                          },\n                          \"value\": \"0\"\n                        },\n                        \"src\": \"12313:11:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"hexValue\": \"416d6f756e74206d75737420626520686967686572207468616e207a65726f\",\n                        \"id\": 4225,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": true,\n                        \"kind\": \"string\",\n                        \"lValueRequested\": false,\n                        \"nodeType\": \"Literal\",\n                        \"src\": \"12326:33:6\",\n                        \"subdenomination\": null,\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_stringliteral_8b5d38bfd9d56e06c511eeb946d76a1a45a72ed25ba1d513f75809a38de68bdb\",\n                          \"typeString\": \"literal_string \\\"Amount must be higher than zero\\\"\"\n                        },\n                        \"value\": \"Amount must be higher than zero\"\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_stringliteral_8b5d38bfd9d56e06c511eeb946d76a1a45a72ed25ba1d513f75809a38de68bdb\",\n                          \"typeString\": \"literal_string \\\"Amount must be higher than zero\\\"\"\n                        }\n                      ],\n                      \"id\": 4221,\n                      \"name\": \"require\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [\n                        -18,\n                        -18\n                      ],\n                      \"referencedDeclaration\": -18,\n                      \"src\": \"12305:7:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$\",\n                        \"typeString\": \"function (bool,string memory) pure\"\n                      }\n                    },\n                    \"id\": 4226,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"12305:55:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 4227,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"12305:55:6\"\n                },\n                {\n                  \"assignments\": [\n                    4229\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 4229,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"curr_block\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 4279,\n                      \"src\": \"12371:18:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"default\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      },\n                      \"typeName\": {\n                        \"id\": 4228,\n                        \"name\": \"uint256\",\n                        \"nodeType\": \"ElementaryTypeName\",\n                        \"src\": \"12371:7:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 4232,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [],\n                    \"expression\": {\n                      \"argumentTypes\": [],\n                      \"id\": 4230,\n                      \"name\": \"_getBlockNumber\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5019,\n                      \"src\": \"12392:15:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_view$__$returns$_t_uint256_$\",\n                        \"typeString\": \"function () view returns (uint256)\"\n                      }\n                    },\n                    \"id\": 4231,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"12392:17:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"12371:38:6\"\n                },\n                {\n                  \"assignments\": [\n                    null,\n                    4236,\n                    null\n                  ],\n                  \"declarations\": [\n                    null,\n                    {\n                      \"constant\": false,\n                      \"id\": 4236,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"liquidity\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 4279,\n                      \"src\": \"12423:32:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"storage\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                        \"typeString\": \"struct AssetLib.Asset\"\n                      },\n                      \"typeName\": {\n                        \"contractScope\": null,\n                        \"id\": 4235,\n                        \"name\": \"AssetLib.Asset\",\n                        \"nodeType\": \"UserDefinedTypeName\",\n                        \"referencedDeclaration\": 2788,\n                        \"src\": \"12423:14:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                          \"typeString\": \"struct AssetLib.Asset\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    },\n                    null\n                  ],\n                  \"id\": 4242,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 4238,\n                          \"name\": \"msg\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": -15,\n                          \"src\": \"12479:3:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_magic_message\",\n                            \"typeString\": \"msg\"\n                          }\n                        },\n                        \"id\": 4239,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"memberName\": \"sender\",\n                        \"nodeType\": \"MemberAccess\",\n                        \"referencedDeclaration\": null,\n                        \"src\": \"12479:10:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 4240,\n                        \"name\": \"curr_block\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4229,\n                        \"src\": \"12491:10:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"id\": 4237,\n                      \"name\": \"_collectLiquidity\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5489,\n                      \"src\": \"12461:17:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_nonpayable$_t_address_$_t_uint256_$returns$_t_struct$_Asset_$2788_memory_ptr_$_t_struct$_Asset_$2788_storage_ptr_$_t_bool_$\",\n                        \"typeString\": \"function (address,uint256) returns (struct AssetLib.Asset memory,struct AssetLib.Asset storage pointer,bool)\"\n                      }\n                    },\n                    \"id\": 4241,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"12461:41:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$_t_struct$_Asset_$2788_memory_ptr_$_t_struct$_Asset_$2788_storage_ptr_$_t_bool_$\",\n                      \"typeString\": \"tuple(struct AssetLib.Asset memory,struct AssetLib.Asset storage pointer,bool)\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"12420:82:6\"\n                },\n                {\n                  \"assignments\": [\n                    4244\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 4244,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"stake\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 4279,\n                      \"src\": \"12848:19:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"storage\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_struct$_Stake_$3648_storage_ptr\",\n                        \"typeString\": \"struct Staking.Stake\"\n                      },\n                      \"typeName\": {\n                        \"contractScope\": null,\n                        \"id\": 4243,\n                        \"name\": \"Stake\",\n                        \"nodeType\": \"UserDefinedTypeName\",\n                        \"referencedDeclaration\": 3648,\n                        \"src\": \"12848:5:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Stake_$3648_storage_ptr\",\n                          \"typeString\": \"struct Staking.Stake\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 4250,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 4246,\n                          \"name\": \"msg\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": -15,\n                          \"src\": \"12899:3:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_magic_message\",\n                            \"typeString\": \"msg\"\n                          }\n                        },\n                        \"id\": 4247,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"memberName\": \"sender\",\n                        \"nodeType\": \"MemberAccess\",\n                        \"referencedDeclaration\": null,\n                        \"src\": \"12899:10:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 4248,\n                        \"name\": \"curr_block\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4229,\n                        \"src\": \"12911:10:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"id\": 4245,\n                      \"name\": \"_updateStakeCompoundInterest\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5315,\n                      \"src\": \"12870:28:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_nonpayable$_t_address_$_t_uint256_$returns$_t_struct$_Stake_$3648_storage_ptr_$\",\n                        \"typeString\": \"function (address,uint256) returns (struct Staking.Stake storage pointer)\"\n                      }\n                    },\n                    \"id\": 4249,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"12870:52:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_struct$_Stake_$3648_storage_ptr\",\n                      \"typeString\": \"struct Staking.Stake storage pointer\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"12848:74:6\"\n                },\n                {\n                  \"assignments\": [\n                    4254\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 4254,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"_amount\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 4279,\n                      \"src\": \"12932:29:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"memory\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                        \"typeString\": \"struct AssetLib.Asset\"\n                      },\n                      \"typeName\": {\n                        \"contractScope\": null,\n                        \"id\": 4253,\n                        \"name\": \"AssetLib.Asset\",\n                        \"nodeType\": \"UserDefinedTypeName\",\n                        \"referencedDeclaration\": 2788,\n                        \"src\": \"12932:14:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                          \"typeString\": \"struct AssetLib.Asset\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 4261,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 4257,\n                          \"name\": \"stake\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 4244,\n                          \"src\": \"12998:5:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_struct$_Stake_$3648_storage_ptr\",\n                            \"typeString\": \"struct Staking.Stake storage pointer\"\n                          }\n                        },\n                        \"id\": 4258,\n                        \"isConstant\": false,\n                        \"isLValue\": true,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"memberName\": \"asset\",\n                        \"nodeType\": \"MemberAccess\",\n                        \"referencedDeclaration\": 3647,\n                        \"src\": \"12998:11:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                          \"typeString\": \"struct AssetLib.Asset storage ref\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 4259,\n                        \"name\": \"amount\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4211,\n                        \"src\": \"13011:6:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                          \"typeString\": \"struct AssetLib.Asset storage ref\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 4255,\n                        \"name\": \"liquidity\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4236,\n                        \"src\": \"12964:9:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                          \"typeString\": \"struct AssetLib.Asset storage pointer\"\n                        }\n                      },\n                      \"id\": 4256,\n                      \"isConstant\": false,\n                      \"isLValue\": true,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"memberName\": \"iRelocatePrincipalFirst\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": 3096,\n                      \"src\": \"12964:33:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_nonpayable$_t_struct$_Asset_$2788_storage_ptr_$_t_struct$_Asset_$2788_storage_ptr_$_t_uint256_$returns$_t_struct$_Asset_$2788_memory_ptr_$bound_to$_t_struct$_Asset_$2788_storage_ptr_$\",\n                        \"typeString\": \"function (struct AssetLib.Asset storage pointer,struct AssetLib.Asset storage pointer,uint256) returns (struct AssetLib.Asset memory)\"\n                      }\n                    },\n                    \"id\": 4260,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"12964:54:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                      \"typeString\": \"struct AssetLib.Asset memory\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"12932:86:6\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 4265,\n                        \"name\": \"_amount\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4254,\n                        \"src\": \"13057:7:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                          \"typeString\": \"struct AssetLib.Asset memory\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                          \"typeString\": \"struct AssetLib.Asset memory\"\n                        }\n                      ],\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 4262,\n                        \"name\": \"_accruedGlobalLiquidity\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 3774,\n                        \"src\": \"13028:23:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                          \"typeString\": \"struct AssetLib.Asset storage ref\"\n                        }\n                      },\n                      \"id\": 4264,\n                      \"isConstant\": false,\n                      \"isLValue\": true,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"memberName\": \"iSub\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": 2938,\n                      \"src\": \"13028:28:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_nonpayable$_t_struct$_Asset_$2788_storage_ptr_$_t_struct$_Asset_$2788_memory_ptr_$returns$__$bound_to$_t_struct$_Asset_$2788_storage_ptr_$\",\n                        \"typeString\": \"function (struct AssetLib.Asset storage pointer,struct AssetLib.Asset memory)\"\n                      }\n                    },\n                    \"id\": 4266,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"13028:37:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 4267,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"13028:37:6\"\n                },\n                {\n                  \"eventCall\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 4269,\n                          \"name\": \"msg\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": -15,\n                          \"src\": \"13302:3:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_magic_message\",\n                            \"typeString\": \"msg\"\n                          }\n                        },\n                        \"id\": 4270,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"memberName\": \"sender\",\n                        \"nodeType\": \"MemberAccess\",\n                        \"referencedDeclaration\": null,\n                        \"src\": \"13302:10:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 4271,\n                          \"name\": \"stake\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 4244,\n                          \"src\": \"13314:5:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_struct$_Stake_$3648_storage_ptr\",\n                            \"typeString\": \"struct Staking.Stake storage pointer\"\n                          }\n                        },\n                        \"id\": 4272,\n                        \"isConstant\": false,\n                        \"isLValue\": true,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"memberName\": \"sinceInterestRateIndex\",\n                        \"nodeType\": \"MemberAccess\",\n                        \"referencedDeclaration\": 3645,\n                        \"src\": \"13314:28:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 4273,\n                          \"name\": \"_amount\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 4254,\n                          \"src\": \"13344:7:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                            \"typeString\": \"struct AssetLib.Asset memory\"\n                          }\n                        },\n                        \"id\": 4274,\n                        \"isConstant\": false,\n                        \"isLValue\": true,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"memberName\": \"principal\",\n                        \"nodeType\": \"MemberAccess\",\n                        \"referencedDeclaration\": 2785,\n                        \"src\": \"13344:17:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 4275,\n                          \"name\": \"_amount\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 4254,\n                          \"src\": \"13363:7:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                            \"typeString\": \"struct AssetLib.Asset memory\"\n                          }\n                        },\n                        \"id\": 4276,\n                        \"isConstant\": false,\n                        \"isLValue\": true,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"memberName\": \"compoundInterest\",\n                        \"nodeType\": \"MemberAccess\",\n                        \"referencedDeclaration\": 2787,\n                        \"src\": \"13363:24:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"id\": 4268,\n                      \"name\": \"BindStake\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 3669,\n                      \"src\": \"13292:9:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_event_nonpayable$_t_address_$_t_uint256_$_t_uint256_$_t_uint256_$returns$__$\",\n                        \"typeString\": \"function (address,uint256,uint256,uint256)\"\n                      }\n                    },\n                    \"id\": 4277,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"13292:96:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 4278,\n                  \"nodeType\": \"EmitStatement\",\n                  \"src\": \"13287:101:6\"\n                }\n              ]\n            },\n            \"documentation\": null,\n            \"functionSelector\": \"88cedd5e\",\n            \"id\": 4280,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [\n              {\n                \"arguments\": [\n                  {\n                    \"argumentTypes\": null,\n                    \"id\": 4216,\n                    \"name\": \"txExpirationBlock\",\n                    \"nodeType\": \"Identifier\",\n                    \"overloadedDeclarations\": [],\n                    \"referencedDeclaration\": 4213,\n                    \"src\": \"12248:17:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  }\n                ],\n                \"id\": 4217,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 4215,\n                  \"name\": \"verifyTxExpiration\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 3836,\n                  \"src\": \"12229:18:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$_t_uint256_$\",\n                    \"typeString\": \"modifier (uint256)\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"12229:37:6\"\n              },\n              {\n                \"arguments\": null,\n                \"id\": 4219,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 4218,\n                  \"name\": \"verifyNotPaused\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 3848,\n                  \"src\": \"12275:15:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$__$\",\n                    \"typeString\": \"modifier ()\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"12275:15:6\"\n              }\n            ],\n            \"name\": \"bindStake\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 4214,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 4211,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"amount\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4280,\n                  \"src\": \"12144:14:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 4210,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"12144:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 4213,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"txExpirationBlock\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4280,\n                  \"src\": \"12168:25:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 4212,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"12168:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"12134:69:6\"\n            },\n            \"returnParameters\": {\n              \"id\": 4220,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"12295:0:6\"\n            },\n            \"scope\": 5490,\n            \"src\": \"12116:1291:6\",\n            \"stateMutability\": \"nonpayable\",\n            \"virtual\": false,\n            \"visibility\": \"external\"\n          },\n          {\n            \"body\": {\n              \"id\": 4549,\n              \"nodeType\": \"Block\",\n              \"src\": \"14400:3414:6\",\n              \"statements\": [\n                {\n                  \"assignments\": [\n                    4294\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 4294,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"curr_block\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 4549,\n                      \"src\": \"14410:18:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"default\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      },\n                      \"typeName\": {\n                        \"id\": 4293,\n                        \"name\": \"uint256\",\n                        \"nodeType\": \"ElementaryTypeName\",\n                        \"src\": \"14410:7:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 4297,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [],\n                    \"expression\": {\n                      \"argumentTypes\": [],\n                      \"id\": 4295,\n                      \"name\": \"_getBlockNumber\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5019,\n                      \"src\": \"14431:15:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_view$__$returns$_t_uint256_$\",\n                        \"typeString\": \"function () view returns (uint256)\"\n                      }\n                    },\n                    \"id\": 4296,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"14431:17:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"14410:38:6\"\n                },\n                {\n                  \"assignments\": [\n                    4299\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 4299,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"sender\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 4549,\n                      \"src\": \"14458:14:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"default\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_address\",\n                        \"typeString\": \"address\"\n                      },\n                      \"typeName\": {\n                        \"id\": 4298,\n                        \"name\": \"address\",\n                        \"nodeType\": \"ElementaryTypeName\",\n                        \"src\": \"14458:7:6\",\n                        \"stateMutability\": \"nonpayable\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 4302,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"expression\": {\n                      \"argumentTypes\": null,\n                      \"id\": 4300,\n                      \"name\": \"msg\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": -15,\n                      \"src\": \"14475:3:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_magic_message\",\n                        \"typeString\": \"msg\"\n                      }\n                    },\n                    \"id\": 4301,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"memberName\": \"sender\",\n                    \"nodeType\": \"MemberAccess\",\n                    \"referencedDeclaration\": null,\n                    \"src\": \"14475:10:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address_payable\",\n                      \"typeString\": \"address payable\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"14458:27:6\"\n                },\n                {\n                  \"assignments\": [\n                    4304\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 4304,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"stake\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 4549,\n                      \"src\": \"14495:19:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"storage\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_struct$_Stake_$3648_storage_ptr\",\n                        \"typeString\": \"struct Staking.Stake\"\n                      },\n                      \"typeName\": {\n                        \"contractScope\": null,\n                        \"id\": 4303,\n                        \"name\": \"Stake\",\n                        \"nodeType\": \"UserDefinedTypeName\",\n                        \"referencedDeclaration\": 3648,\n                        \"src\": \"14495:5:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Stake_$3648_storage_ptr\",\n                          \"typeString\": \"struct Staking.Stake\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 4309,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 4306,\n                        \"name\": \"sender\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4299,\n                        \"src\": \"14546:6:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 4307,\n                        \"name\": \"curr_block\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4294,\n                        \"src\": \"14554:10:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"id\": 4305,\n                      \"name\": \"_updateStakeCompoundInterest\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5315,\n                      \"src\": \"14517:28:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_nonpayable$_t_address_$_t_uint256_$returns$_t_struct$_Stake_$3648_storage_ptr_$\",\n                        \"typeString\": \"function (address,uint256) returns (struct Staking.Stake storage pointer)\"\n                      }\n                    },\n                    \"id\": 4308,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"14517:48:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_struct$_Stake_$3648_storage_ptr\",\n                      \"typeString\": \"struct Staking.Stake storage pointer\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"14495:70:6\"\n                },\n                {\n                  \"assignments\": [\n                    4311\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 4311,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"stake_composite\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 4549,\n                      \"src\": \"14576:23:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"default\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      },\n                      \"typeName\": {\n                        \"id\": 4310,\n                        \"name\": \"uint256\",\n                        \"nodeType\": \"ElementaryTypeName\",\n                        \"src\": \"14576:7:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 4316,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [],\n                    \"expression\": {\n                      \"argumentTypes\": [],\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 4312,\n                          \"name\": \"stake\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 4304,\n                          \"src\": \"14602:5:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_struct$_Stake_$3648_storage_ptr\",\n                            \"typeString\": \"struct Staking.Stake storage pointer\"\n                          }\n                        },\n                        \"id\": 4313,\n                        \"isConstant\": false,\n                        \"isLValue\": true,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"memberName\": \"asset\",\n                        \"nodeType\": \"MemberAccess\",\n                        \"referencedDeclaration\": 3647,\n                        \"src\": \"14602:11:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                          \"typeString\": \"struct AssetLib.Asset storage ref\"\n                        }\n                      },\n                      \"id\": 4314,\n                      \"isConstant\": false,\n                      \"isLValue\": true,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"memberName\": \"composite\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": 2803,\n                      \"src\": \"14602:21:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_view$_t_struct$_Asset_$2788_storage_ptr_$returns$_t_uint256_$bound_to$_t_struct$_Asset_$2788_storage_ptr_$\",\n                        \"typeString\": \"function (struct AssetLib.Asset storage pointer) view returns (uint256)\"\n                      }\n                    },\n                    \"id\": 4315,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"14602:23:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"14576:49:6\"\n                },\n                {\n                  \"assignments\": [\n                    4320\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 4320,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"_amount\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 4549,\n                      \"src\": \"14635:29:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"memory\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                        \"typeString\": \"struct AssetLib.Asset\"\n                      },\n                      \"typeName\": {\n                        \"contractScope\": null,\n                        \"id\": 4319,\n                        \"name\": \"AssetLib.Asset\",\n                        \"nodeType\": \"UserDefinedTypeName\",\n                        \"referencedDeclaration\": 2788,\n                        \"src\": \"14635:14:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                          \"typeString\": \"struct AssetLib.Asset\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 4321,\n                  \"initialValue\": null,\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"14635:29:6\"\n                },\n                {\n                  \"condition\": {\n                    \"argumentTypes\": null,\n                    \"commonType\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    },\n                    \"id\": 4324,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftExpression\": {\n                      \"argumentTypes\": null,\n                      \"id\": 4322,\n                      \"name\": \"amount\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 4283,\n                      \"src\": \"14679:6:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"BinaryOperation\",\n                    \"operator\": \">\",\n                    \"rightExpression\": {\n                      \"argumentTypes\": null,\n                      \"hexValue\": \"30\",\n                      \"id\": 4323,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": true,\n                      \"kind\": \"number\",\n                      \"lValueRequested\": false,\n                      \"nodeType\": \"Literal\",\n                      \"src\": \"14688:1:6\",\n                      \"subdenomination\": null,\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_rational_0_by_1\",\n                        \"typeString\": \"int_const 0\"\n                      },\n                      \"value\": \"0\"\n                    },\n                    \"src\": \"14679:10:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_bool\",\n                      \"typeString\": \"bool\"\n                    }\n                  },\n                  \"falseBody\": {\n                    \"id\": 4547,\n                    \"nodeType\": \"Block\",\n                    \"src\": \"16562:1246:6\",\n                    \"statements\": [\n                      {\n                        \"condition\": {\n                          \"argumentTypes\": null,\n                          \"commonType\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          },\n                          \"id\": 4431,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"leftExpression\": {\n                            \"argumentTypes\": null,\n                            \"id\": 4429,\n                            \"name\": \"stake_composite\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 4311,\n                            \"src\": \"16580:15:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"nodeType\": \"BinaryOperation\",\n                          \"operator\": \"==\",\n                          \"rightExpression\": {\n                            \"argumentTypes\": null,\n                            \"hexValue\": \"30\",\n                            \"id\": 4430,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": true,\n                            \"kind\": \"number\",\n                            \"lValueRequested\": false,\n                            \"nodeType\": \"Literal\",\n                            \"src\": \"16599:1:6\",\n                            \"subdenomination\": null,\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_rational_0_by_1\",\n                              \"typeString\": \"int_const 0\"\n                            },\n                            \"value\": \"0\"\n                          },\n                          \"src\": \"16580:20:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_bool\",\n                            \"typeString\": \"bool\"\n                          }\n                        },\n                        \"falseBody\": null,\n                        \"id\": 4434,\n                        \"nodeType\": \"IfStatement\",\n                        \"src\": \"16576:108:6\",\n                        \"trueBody\": {\n                          \"id\": 4433,\n                          \"nodeType\": \"Block\",\n                          \"src\": \"16602:82:6\",\n                          \"statements\": [\n                            {\n                              \"expression\": null,\n                              \"functionReturnParameters\": 4292,\n                              \"id\": 4432,\n                              \"nodeType\": \"Return\",\n                              \"src\": \"16663:7:6\"\n                            }\n                          ]\n                        }\n                      },\n                      {\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 4438,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"leftHandSide\": {\n                            \"argumentTypes\": null,\n                            \"id\": 4435,\n                            \"name\": \"_amount\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 4320,\n                            \"src\": \"16698:7:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                              \"typeString\": \"struct AssetLib.Asset memory\"\n                            }\n                          },\n                          \"nodeType\": \"Assignment\",\n                          \"operator\": \"=\",\n                          \"rightHandSide\": {\n                            \"argumentTypes\": null,\n                            \"expression\": {\n                              \"argumentTypes\": null,\n                              \"id\": 4436,\n                              \"name\": \"stake\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 4304,\n                              \"src\": \"16708:5:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_struct$_Stake_$3648_storage_ptr\",\n                                \"typeString\": \"struct Staking.Stake storage pointer\"\n                              }\n                            },\n                            \"id\": 4437,\n                            \"isConstant\": false,\n                            \"isLValue\": true,\n                            \"isPure\": false,\n                            \"lValueRequested\": false,\n                            \"memberName\": \"asset\",\n                            \"nodeType\": \"MemberAccess\",\n                            \"referencedDeclaration\": 3647,\n                            \"src\": \"16708:11:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                              \"typeString\": \"struct AssetLib.Asset storage ref\"\n                            }\n                          },\n                          \"src\": \"16698:21:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                            \"typeString\": \"struct AssetLib.Asset memory\"\n                          }\n                        },\n                        \"id\": 4439,\n                        \"nodeType\": \"ExpressionStatement\",\n                        \"src\": \"16698:21:6\"\n                      },\n                      {\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 4446,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"leftHandSide\": {\n                            \"argumentTypes\": null,\n                            \"expression\": {\n                              \"argumentTypes\": null,\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"id\": 4440,\n                                \"name\": \"stake\",\n                                \"nodeType\": \"Identifier\",\n                                \"overloadedDeclarations\": [],\n                                \"referencedDeclaration\": 4304,\n                                \"src\": \"16733:5:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_struct$_Stake_$3648_storage_ptr\",\n                                  \"typeString\": \"struct Staking.Stake storage pointer\"\n                                }\n                              },\n                              \"id\": 4443,\n                              \"isConstant\": false,\n                              \"isLValue\": true,\n                              \"isPure\": false,\n                              \"lValueRequested\": false,\n                              \"memberName\": \"asset\",\n                              \"nodeType\": \"MemberAccess\",\n                              \"referencedDeclaration\": 3647,\n                              \"src\": \"16733:11:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                                \"typeString\": \"struct AssetLib.Asset storage ref\"\n                              }\n                            },\n                            \"id\": 4444,\n                            \"isConstant\": false,\n                            \"isLValue\": true,\n                            \"isPure\": false,\n                            \"lValueRequested\": true,\n                            \"memberName\": \"principal\",\n                            \"nodeType\": \"MemberAccess\",\n                            \"referencedDeclaration\": 2785,\n                            \"src\": \"16733:21:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"nodeType\": \"Assignment\",\n                          \"operator\": \"=\",\n                          \"rightHandSide\": {\n                            \"argumentTypes\": null,\n                            \"hexValue\": \"30\",\n                            \"id\": 4445,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": true,\n                            \"kind\": \"number\",\n                            \"lValueRequested\": false,\n                            \"nodeType\": \"Literal\",\n                            \"src\": \"16757:1:6\",\n                            \"subdenomination\": null,\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_rational_0_by_1\",\n                              \"typeString\": \"int_const 0\"\n                            },\n                            \"value\": \"0\"\n                          },\n                          \"src\": \"16733:25:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"id\": 4447,\n                        \"nodeType\": \"ExpressionStatement\",\n                        \"src\": \"16733:25:6\"\n                      },\n                      {\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 4454,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"leftHandSide\": {\n                            \"argumentTypes\": null,\n                            \"expression\": {\n                              \"argumentTypes\": null,\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"id\": 4448,\n                                \"name\": \"stake\",\n                                \"nodeType\": \"Identifier\",\n                                \"overloadedDeclarations\": [],\n                                \"referencedDeclaration\": 4304,\n                                \"src\": \"16772:5:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_struct$_Stake_$3648_storage_ptr\",\n                                  \"typeString\": \"struct Staking.Stake storage pointer\"\n                                }\n                              },\n                              \"id\": 4451,\n                              \"isConstant\": false,\n                              \"isLValue\": true,\n                              \"isPure\": false,\n                              \"lValueRequested\": false,\n                              \"memberName\": \"asset\",\n                              \"nodeType\": \"MemberAccess\",\n                              \"referencedDeclaration\": 3647,\n                              \"src\": \"16772:11:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                                \"typeString\": \"struct AssetLib.Asset storage ref\"\n                              }\n                            },\n                            \"id\": 4452,\n                            \"isConstant\": false,\n                            \"isLValue\": true,\n                            \"isPure\": false,\n                            \"lValueRequested\": true,\n                            \"memberName\": \"compoundInterest\",\n                            \"nodeType\": \"MemberAccess\",\n                            \"referencedDeclaration\": 2787,\n                            \"src\": \"16772:28:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"nodeType\": \"Assignment\",\n                          \"operator\": \"=\",\n                          \"rightHandSide\": {\n                            \"argumentTypes\": null,\n                            \"hexValue\": \"30\",\n                            \"id\": 4453,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": true,\n                            \"kind\": \"number\",\n                            \"lValueRequested\": false,\n                            \"nodeType\": \"Literal\",\n                            \"src\": \"16803:1:6\",\n                            \"subdenomination\": null,\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_rational_0_by_1\",\n                              \"typeString\": \"int_const 0\"\n                            },\n                            \"value\": \"0\"\n                          },\n                          \"src\": \"16772:32:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"id\": 4455,\n                        \"nodeType\": \"ExpressionStatement\",\n                        \"src\": \"16772:32:6\"\n                      },\n                      {\n                        \"condition\": {\n                          \"argumentTypes\": null,\n                          \"commonType\": {\n                            \"typeIdentifier\": \"t_uint64\",\n                            \"typeString\": \"uint64\"\n                          },\n                          \"id\": 4458,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"leftExpression\": {\n                            \"argumentTypes\": null,\n                            \"id\": 4456,\n                            \"name\": \"_lockPeriodInBlocks\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 3768,\n                            \"src\": \"16823:19:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint64\",\n                              \"typeString\": \"uint64\"\n                            }\n                          },\n                          \"nodeType\": \"BinaryOperation\",\n                          \"operator\": \"==\",\n                          \"rightExpression\": {\n                            \"argumentTypes\": null,\n                            \"hexValue\": \"30\",\n                            \"id\": 4457,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": true,\n                            \"kind\": \"number\",\n                            \"lValueRequested\": false,\n                            \"nodeType\": \"Literal\",\n                            \"src\": \"16846:1:6\",\n                            \"subdenomination\": null,\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_rational_0_by_1\",\n                              \"typeString\": \"int_const 0\"\n                            },\n                            \"value\": \"0\"\n                          },\n                          \"src\": \"16823:24:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_bool\",\n                            \"typeString\": \"bool\"\n                          }\n                        },\n                        \"falseBody\": {\n                          \"id\": 4545,\n                          \"nodeType\": \"Block\",\n                          \"src\": \"17167:631:6\",\n                          \"statements\": [\n                            {\n                              \"assignments\": [\n                                4491\n                              ],\n                              \"declarations\": [\n                                {\n                                  \"constant\": false,\n                                  \"id\": 4491,\n                                  \"mutability\": \"mutable\",\n                                  \"name\": \"locked\",\n                                  \"nodeType\": \"VariableDeclaration\",\n                                  \"overrides\": null,\n                                  \"scope\": 4545,\n                                  \"src\": \"17185:21:6\",\n                                  \"stateVariable\": false,\n                                  \"storageLocation\": \"storage\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_struct$_Locked_$3659_storage_ptr\",\n                                    \"typeString\": \"struct Staking.Locked\"\n                                  },\n                                  \"typeName\": {\n                                    \"contractScope\": null,\n                                    \"id\": 4490,\n                                    \"name\": \"Locked\",\n                                    \"nodeType\": \"UserDefinedTypeName\",\n                                    \"referencedDeclaration\": 3659,\n                                    \"src\": \"17185:6:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_struct$_Locked_$3659_storage_ptr\",\n                                      \"typeString\": \"struct Staking.Locked\"\n                                    }\n                                  },\n                                  \"value\": null,\n                                  \"visibility\": \"internal\"\n                                }\n                              ],\n                              \"id\": 4495,\n                              \"initialValue\": {\n                                \"argumentTypes\": null,\n                                \"baseExpression\": {\n                                  \"argumentTypes\": null,\n                                  \"id\": 4492,\n                                  \"name\": \"_locked\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 3792,\n                                  \"src\": \"17209:7:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_mapping$_t_address_$_t_struct$_Locked_$3659_storage_$\",\n                                    \"typeString\": \"mapping(address => struct Staking.Locked storage ref)\"\n                                  }\n                                },\n                                \"id\": 4494,\n                                \"indexExpression\": {\n                                  \"argumentTypes\": null,\n                                  \"id\": 4493,\n                                  \"name\": \"sender\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 4299,\n                                  \"src\": \"17217:6:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_address\",\n                                    \"typeString\": \"address\"\n                                  }\n                                },\n                                \"isConstant\": false,\n                                \"isLValue\": true,\n                                \"isPure\": false,\n                                \"lValueRequested\": false,\n                                \"nodeType\": \"IndexAccess\",\n                                \"src\": \"17209:15:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_struct$_Locked_$3659_storage\",\n                                  \"typeString\": \"struct Staking.Locked storage ref\"\n                                }\n                              },\n                              \"nodeType\": \"VariableDeclarationStatement\",\n                              \"src\": \"17185:39:6\"\n                            },\n                            {\n                              \"assignments\": [\n                                4497\n                              ],\n                              \"declarations\": [\n                                {\n                                  \"constant\": false,\n                                  \"id\": 4497,\n                                  \"mutability\": \"mutable\",\n                                  \"name\": \"newLockedAsset\",\n                                  \"nodeType\": \"VariableDeclaration\",\n                                  \"overrides\": null,\n                                  \"scope\": 4545,\n                                  \"src\": \"17242:34:6\",\n                                  \"stateVariable\": false,\n                                  \"storageLocation\": \"storage\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_struct$_LockedAsset_$3653_storage_ptr\",\n                                    \"typeString\": \"struct Staking.LockedAsset\"\n                                  },\n                                  \"typeName\": {\n                                    \"contractScope\": null,\n                                    \"id\": 4496,\n                                    \"name\": \"LockedAsset\",\n                                    \"nodeType\": \"UserDefinedTypeName\",\n                                    \"referencedDeclaration\": 3653,\n                                    \"src\": \"17242:11:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_struct$_LockedAsset_$3653_storage_ptr\",\n                                      \"typeString\": \"struct Staking.LockedAsset\"\n                                    }\n                                  },\n                                  \"value\": null,\n                                  \"visibility\": \"internal\"\n                                }\n                              ],\n                              \"id\": 4502,\n                              \"initialValue\": {\n                                \"argumentTypes\": null,\n                                \"arguments\": [],\n                                \"expression\": {\n                                  \"argumentTypes\": [],\n                                  \"expression\": {\n                                    \"argumentTypes\": null,\n                                    \"expression\": {\n                                      \"argumentTypes\": null,\n                                      \"id\": 4498,\n                                      \"name\": \"locked\",\n                                      \"nodeType\": \"Identifier\",\n                                      \"overloadedDeclarations\": [],\n                                      \"referencedDeclaration\": 4491,\n                                      \"src\": \"17279:6:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_struct$_Locked_$3659_storage_ptr\",\n                                        \"typeString\": \"struct Staking.Locked storage pointer\"\n                                      }\n                                    },\n                                    \"id\": 4499,\n                                    \"isConstant\": false,\n                                    \"isLValue\": true,\n                                    \"isPure\": false,\n                                    \"lValueRequested\": false,\n                                    \"memberName\": \"assets\",\n                                    \"nodeType\": \"MemberAccess\",\n                                    \"referencedDeclaration\": 3658,\n                                    \"src\": \"17279:13:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_array$_t_struct$_LockedAsset_$3653_storage_$dyn_storage\",\n                                      \"typeString\": \"struct Staking.LockedAsset storage ref[] storage ref\"\n                                    }\n                                  },\n                                  \"id\": 4500,\n                                  \"isConstant\": false,\n                                  \"isLValue\": false,\n                                  \"isPure\": false,\n                                  \"lValueRequested\": false,\n                                  \"memberName\": \"push\",\n                                  \"nodeType\": \"MemberAccess\",\n                                  \"referencedDeclaration\": null,\n                                  \"src\": \"17279:18:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_function_arraypush_nonpayable$__$returns$_t_struct$_LockedAsset_$3653_storage_$\",\n                                    \"typeString\": \"function () returns (struct Staking.LockedAsset storage ref)\"\n                                  }\n                                },\n                                \"id\": 4501,\n                                \"isConstant\": false,\n                                \"isLValue\": true,\n                                \"isPure\": false,\n                                \"kind\": \"functionCall\",\n                                \"lValueRequested\": false,\n                                \"names\": [],\n                                \"nodeType\": \"FunctionCall\",\n                                \"src\": \"17279:20:6\",\n                                \"tryCall\": false,\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_struct$_LockedAsset_$3653_storage\",\n                                  \"typeString\": \"struct Staking.LockedAsset storage ref\"\n                                }\n                              },\n                              \"nodeType\": \"VariableDeclarationStatement\",\n                              \"src\": \"17242:57:6\"\n                            },\n                            {\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"id\": 4510,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": false,\n                                \"lValueRequested\": false,\n                                \"leftHandSide\": {\n                                  \"argumentTypes\": null,\n                                  \"expression\": {\n                                    \"argumentTypes\": null,\n                                    \"id\": 4503,\n                                    \"name\": \"newLockedAsset\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 4497,\n                                    \"src\": \"17317:14:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_struct$_LockedAsset_$3653_storage_ptr\",\n                                      \"typeString\": \"struct Staking.LockedAsset storage pointer\"\n                                    }\n                                  },\n                                  \"id\": 4505,\n                                  \"isConstant\": false,\n                                  \"isLValue\": true,\n                                  \"isPure\": false,\n                                  \"lValueRequested\": true,\n                                  \"memberName\": \"liquidSinceBlock\",\n                                  \"nodeType\": \"MemberAccess\",\n                                  \"referencedDeclaration\": 3650,\n                                  \"src\": \"17317:31:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_uint256\",\n                                    \"typeString\": \"uint256\"\n                                  }\n                                },\n                                \"nodeType\": \"Assignment\",\n                                \"operator\": \"=\",\n                                \"rightHandSide\": {\n                                  \"argumentTypes\": null,\n                                  \"arguments\": [\n                                    {\n                                      \"argumentTypes\": null,\n                                      \"id\": 4508,\n                                      \"name\": \"_lockPeriodInBlocks\",\n                                      \"nodeType\": \"Identifier\",\n                                      \"overloadedDeclarations\": [],\n                                      \"referencedDeclaration\": 3768,\n                                      \"src\": \"17366:19:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_uint64\",\n                                        \"typeString\": \"uint64\"\n                                      }\n                                    }\n                                  ],\n                                  \"expression\": {\n                                    \"argumentTypes\": [\n                                      {\n                                        \"typeIdentifier\": \"t_uint64\",\n                                        \"typeString\": \"uint64\"\n                                      }\n                                    ],\n                                    \"expression\": {\n                                      \"argumentTypes\": null,\n                                      \"id\": 4506,\n                                      \"name\": \"curr_block\",\n                                      \"nodeType\": \"Identifier\",\n                                      \"overloadedDeclarations\": [],\n                                      \"referencedDeclaration\": 4294,\n                                      \"src\": \"17351:10:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_uint256\",\n                                        \"typeString\": \"uint256\"\n                                      }\n                                    },\n                                    \"id\": 4507,\n                                    \"isConstant\": false,\n                                    \"isLValue\": false,\n                                    \"isPure\": false,\n                                    \"lValueRequested\": false,\n                                    \"memberName\": \"add\",\n                                    \"nodeType\": \"MemberAccess\",\n                                    \"referencedDeclaration\": 5870,\n                                    \"src\": \"17351:14:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_function_internal_pure$_t_uint256_$_t_uint256_$returns$_t_uint256_$bound_to$_t_uint256_$\",\n                                      \"typeString\": \"function (uint256,uint256) pure returns (uint256)\"\n                                    }\n                                  },\n                                  \"id\": 4509,\n                                  \"isConstant\": false,\n                                  \"isLValue\": false,\n                                  \"isPure\": false,\n                                  \"kind\": \"functionCall\",\n                                  \"lValueRequested\": false,\n                                  \"names\": [],\n                                  \"nodeType\": \"FunctionCall\",\n                                  \"src\": \"17351:35:6\",\n                                  \"tryCall\": false,\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_uint256\",\n                                    \"typeString\": \"uint256\"\n                                  }\n                                },\n                                \"src\": \"17317:69:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              },\n                              \"id\": 4511,\n                              \"nodeType\": \"ExpressionStatement\",\n                              \"src\": \"17317:69:6\"\n                            },\n                            {\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"id\": 4516,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": false,\n                                \"lValueRequested\": false,\n                                \"leftHandSide\": {\n                                  \"argumentTypes\": null,\n                                  \"expression\": {\n                                    \"argumentTypes\": null,\n                                    \"id\": 4512,\n                                    \"name\": \"newLockedAsset\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 4497,\n                                    \"src\": \"17404:14:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_struct$_LockedAsset_$3653_storage_ptr\",\n                                      \"typeString\": \"struct Staking.LockedAsset storage pointer\"\n                                    }\n                                  },\n                                  \"id\": 4514,\n                                  \"isConstant\": false,\n                                  \"isLValue\": true,\n                                  \"isPure\": false,\n                                  \"lValueRequested\": true,\n                                  \"memberName\": \"asset\",\n                                  \"nodeType\": \"MemberAccess\",\n                                  \"referencedDeclaration\": 3652,\n                                  \"src\": \"17404:20:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                                    \"typeString\": \"struct AssetLib.Asset storage ref\"\n                                  }\n                                },\n                                \"nodeType\": \"Assignment\",\n                                \"operator\": \"=\",\n                                \"rightHandSide\": {\n                                  \"argumentTypes\": null,\n                                  \"id\": 4515,\n                                  \"name\": \"_amount\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 4320,\n                                  \"src\": \"17427:7:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                    \"typeString\": \"struct AssetLib.Asset memory\"\n                                  }\n                                },\n                                \"src\": \"17404:30:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                                  \"typeString\": \"struct AssetLib.Asset storage ref\"\n                                }\n                              },\n                              \"id\": 4517,\n                              \"nodeType\": \"ExpressionStatement\",\n                              \"src\": \"17404:30:6\"\n                            },\n                            {\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"arguments\": [\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"id\": 4521,\n                                    \"name\": \"_amount\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 4320,\n                                    \"src\": \"17479:7:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                      \"typeString\": \"struct AssetLib.Asset memory\"\n                                    }\n                                  }\n                                ],\n                                \"expression\": {\n                                  \"argumentTypes\": [\n                                    {\n                                      \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                      \"typeString\": \"struct AssetLib.Asset memory\"\n                                    }\n                                  ],\n                                  \"expression\": {\n                                    \"argumentTypes\": null,\n                                    \"id\": 4518,\n                                    \"name\": \"_accruedGlobalLocked\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 3776,\n                                    \"src\": \"17453:20:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                                      \"typeString\": \"struct AssetLib.Asset storage ref\"\n                                    }\n                                  },\n                                  \"id\": 4520,\n                                  \"isConstant\": false,\n                                  \"isLValue\": true,\n                                  \"isPure\": false,\n                                  \"lValueRequested\": false,\n                                  \"memberName\": \"iAdd\",\n                                  \"nodeType\": \"MemberAccess\",\n                                  \"referencedDeclaration\": 2878,\n                                  \"src\": \"17453:25:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_function_internal_nonpayable$_t_struct$_Asset_$2788_storage_ptr_$_t_struct$_Asset_$2788_memory_ptr_$returns$__$bound_to$_t_struct$_Asset_$2788_storage_ptr_$\",\n                                    \"typeString\": \"function (struct AssetLib.Asset storage pointer,struct AssetLib.Asset memory)\"\n                                  }\n                                },\n                                \"id\": 4522,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": false,\n                                \"kind\": \"functionCall\",\n                                \"lValueRequested\": false,\n                                \"names\": [],\n                                \"nodeType\": \"FunctionCall\",\n                                \"src\": \"17453:34:6\",\n                                \"tryCall\": false,\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_tuple$__$\",\n                                  \"typeString\": \"tuple()\"\n                                }\n                              },\n                              \"id\": 4523,\n                              \"nodeType\": \"ExpressionStatement\",\n                              \"src\": \"17453:34:6\"\n                            },\n                            {\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"arguments\": [\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"id\": 4529,\n                                    \"name\": \"_amount\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 4320,\n                                    \"src\": \"17527:7:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                      \"typeString\": \"struct AssetLib.Asset memory\"\n                                    }\n                                  }\n                                ],\n                                \"expression\": {\n                                  \"argumentTypes\": [\n                                    {\n                                      \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                      \"typeString\": \"struct AssetLib.Asset memory\"\n                                    }\n                                  ],\n                                  \"expression\": {\n                                    \"argumentTypes\": null,\n                                    \"expression\": {\n                                      \"argumentTypes\": null,\n                                      \"id\": 4524,\n                                      \"name\": \"locked\",\n                                      \"nodeType\": \"Identifier\",\n                                      \"overloadedDeclarations\": [],\n                                      \"referencedDeclaration\": 4491,\n                                      \"src\": \"17505:6:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_struct$_Locked_$3659_storage_ptr\",\n                                        \"typeString\": \"struct Staking.Locked storage pointer\"\n                                      }\n                                    },\n                                    \"id\": 4527,\n                                    \"isConstant\": false,\n                                    \"isLValue\": true,\n                                    \"isPure\": false,\n                                    \"lValueRequested\": false,\n                                    \"memberName\": \"aggregate\",\n                                    \"nodeType\": \"MemberAccess\",\n                                    \"referencedDeclaration\": 3655,\n                                    \"src\": \"17505:16:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                                      \"typeString\": \"struct AssetLib.Asset storage ref\"\n                                    }\n                                  },\n                                  \"id\": 4528,\n                                  \"isConstant\": false,\n                                  \"isLValue\": true,\n                                  \"isPure\": false,\n                                  \"lValueRequested\": false,\n                                  \"memberName\": \"iAdd\",\n                                  \"nodeType\": \"MemberAccess\",\n                                  \"referencedDeclaration\": 2878,\n                                  \"src\": \"17505:21:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_function_internal_nonpayable$_t_struct$_Asset_$2788_storage_ptr_$_t_struct$_Asset_$2788_memory_ptr_$returns$__$bound_to$_t_struct$_Asset_$2788_storage_ptr_$\",\n                                    \"typeString\": \"function (struct AssetLib.Asset storage pointer,struct AssetLib.Asset memory)\"\n                                  }\n                                },\n                                \"id\": 4530,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": false,\n                                \"kind\": \"functionCall\",\n                                \"lValueRequested\": false,\n                                \"names\": [],\n                                \"nodeType\": \"FunctionCall\",\n                                \"src\": \"17505:30:6\",\n                                \"tryCall\": false,\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_tuple$__$\",\n                                  \"typeString\": \"tuple()\"\n                                }\n                              },\n                              \"id\": 4531,\n                              \"nodeType\": \"ExpressionStatement\",\n                              \"src\": \"17505:30:6\"\n                            },\n                            {\n                              \"eventCall\": {\n                                \"argumentTypes\": null,\n                                \"arguments\": [\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"expression\": {\n                                      \"argumentTypes\": null,\n                                      \"id\": 4533,\n                                      \"name\": \"msg\",\n                                      \"nodeType\": \"Identifier\",\n                                      \"overloadedDeclarations\": [],\n                                      \"referencedDeclaration\": -15,\n                                      \"src\": \"17668:3:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_magic_message\",\n                                        \"typeString\": \"msg\"\n                                      }\n                                    },\n                                    \"id\": 4534,\n                                    \"isConstant\": false,\n                                    \"isLValue\": false,\n                                    \"isPure\": false,\n                                    \"lValueRequested\": false,\n                                    \"memberName\": \"sender\",\n                                    \"nodeType\": \"MemberAccess\",\n                                    \"referencedDeclaration\": null,\n                                    \"src\": \"17668:10:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_address_payable\",\n                                      \"typeString\": \"address payable\"\n                                    }\n                                  },\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"expression\": {\n                                      \"argumentTypes\": null,\n                                      \"id\": 4535,\n                                      \"name\": \"newLockedAsset\",\n                                      \"nodeType\": \"Identifier\",\n                                      \"overloadedDeclarations\": [],\n                                      \"referencedDeclaration\": 4497,\n                                      \"src\": \"17680:14:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_struct$_LockedAsset_$3653_storage_ptr\",\n                                        \"typeString\": \"struct Staking.LockedAsset storage pointer\"\n                                      }\n                                    },\n                                    \"id\": 4536,\n                                    \"isConstant\": false,\n                                    \"isLValue\": true,\n                                    \"isPure\": false,\n                                    \"lValueRequested\": false,\n                                    \"memberName\": \"liquidSinceBlock\",\n                                    \"nodeType\": \"MemberAccess\",\n                                    \"referencedDeclaration\": 3650,\n                                    \"src\": \"17680:31:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    }\n                                  },\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"expression\": {\n                                      \"argumentTypes\": null,\n                                      \"expression\": {\n                                        \"argumentTypes\": null,\n                                        \"id\": 4537,\n                                        \"name\": \"newLockedAsset\",\n                                        \"nodeType\": \"Identifier\",\n                                        \"overloadedDeclarations\": [],\n                                        \"referencedDeclaration\": 4497,\n                                        \"src\": \"17713:14:6\",\n                                        \"typeDescriptions\": {\n                                          \"typeIdentifier\": \"t_struct$_LockedAsset_$3653_storage_ptr\",\n                                          \"typeString\": \"struct Staking.LockedAsset storage pointer\"\n                                        }\n                                      },\n                                      \"id\": 4538,\n                                      \"isConstant\": false,\n                                      \"isLValue\": true,\n                                      \"isPure\": false,\n                                      \"lValueRequested\": false,\n                                      \"memberName\": \"asset\",\n                                      \"nodeType\": \"MemberAccess\",\n                                      \"referencedDeclaration\": 3652,\n                                      \"src\": \"17713:20:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                                        \"typeString\": \"struct AssetLib.Asset storage ref\"\n                                      }\n                                    },\n                                    \"id\": 4539,\n                                    \"isConstant\": false,\n                                    \"isLValue\": true,\n                                    \"isPure\": false,\n                                    \"lValueRequested\": false,\n                                    \"memberName\": \"principal\",\n                                    \"nodeType\": \"MemberAccess\",\n                                    \"referencedDeclaration\": 2785,\n                                    \"src\": \"17713:30:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    }\n                                  },\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"expression\": {\n                                      \"argumentTypes\": null,\n                                      \"expression\": {\n                                        \"argumentTypes\": null,\n                                        \"id\": 4540,\n                                        \"name\": \"newLockedAsset\",\n                                        \"nodeType\": \"Identifier\",\n                                        \"overloadedDeclarations\": [],\n                                        \"referencedDeclaration\": 4497,\n                                        \"src\": \"17745:14:6\",\n                                        \"typeDescriptions\": {\n                                          \"typeIdentifier\": \"t_struct$_LockedAsset_$3653_storage_ptr\",\n                                          \"typeString\": \"struct Staking.LockedAsset storage pointer\"\n                                        }\n                                      },\n                                      \"id\": 4541,\n                                      \"isConstant\": false,\n                                      \"isLValue\": true,\n                                      \"isPure\": false,\n                                      \"lValueRequested\": false,\n                                      \"memberName\": \"asset\",\n                                      \"nodeType\": \"MemberAccess\",\n                                      \"referencedDeclaration\": 3652,\n                                      \"src\": \"17745:20:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                                        \"typeString\": \"struct AssetLib.Asset storage ref\"\n                                      }\n                                    },\n                                    \"id\": 4542,\n                                    \"isConstant\": false,\n                                    \"isLValue\": true,\n                                    \"isPure\": false,\n                                    \"lValueRequested\": false,\n                                    \"memberName\": \"compoundInterest\",\n                                    \"nodeType\": \"MemberAccess\",\n                                    \"referencedDeclaration\": 2787,\n                                    \"src\": \"17745:37:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    }\n                                  }\n                                ],\n                                \"expression\": {\n                                  \"argumentTypes\": [\n                                    {\n                                      \"typeIdentifier\": \"t_address_payable\",\n                                      \"typeString\": \"address payable\"\n                                    },\n                                    {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    },\n                                    {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    },\n                                    {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    }\n                                  ],\n                                  \"id\": 4532,\n                                  \"name\": \"UnbindStake\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 3704,\n                                  \"src\": \"17656:11:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_function_event_nonpayable$_t_address_$_t_uint256_$_t_uint256_$_t_uint256_$returns$__$\",\n                                    \"typeString\": \"function (address,uint256,uint256,uint256)\"\n                                  }\n                                },\n                                \"id\": 4543,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": false,\n                                \"kind\": \"functionCall\",\n                                \"lValueRequested\": false,\n                                \"names\": [],\n                                \"nodeType\": \"FunctionCall\",\n                                \"src\": \"17656:127:6\",\n                                \"tryCall\": false,\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_tuple$__$\",\n                                  \"typeString\": \"tuple()\"\n                                }\n                              },\n                              \"id\": 4544,\n                              \"nodeType\": \"EmitStatement\",\n                              \"src\": \"17651:132:6\"\n                            }\n                          ]\n                        },\n                        \"id\": 4546,\n                        \"nodeType\": \"IfStatement\",\n                        \"src\": \"16819:979:6\",\n                        \"trueBody\": {\n                          \"id\": 4489,\n                          \"nodeType\": \"Block\",\n                          \"src\": \"16849:312:6\",\n                          \"statements\": [\n                            {\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"arguments\": [\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"id\": 4463,\n                                    \"name\": \"_amount\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 4320,\n                                    \"src\": \"16891:7:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                      \"typeString\": \"struct AssetLib.Asset memory\"\n                                    }\n                                  }\n                                ],\n                                \"expression\": {\n                                  \"argumentTypes\": [\n                                    {\n                                      \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                      \"typeString\": \"struct AssetLib.Asset memory\"\n                                    }\n                                  ],\n                                  \"expression\": {\n                                    \"argumentTypes\": null,\n                                    \"baseExpression\": {\n                                      \"argumentTypes\": null,\n                                      \"id\": 4459,\n                                      \"name\": \"_liquidity\",\n                                      \"nodeType\": \"Identifier\",\n                                      \"overloadedDeclarations\": [],\n                                      \"referencedDeclaration\": 3796,\n                                      \"src\": \"16867:10:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_mapping$_t_address_$_t_struct$_Asset_$2788_storage_$\",\n                                        \"typeString\": \"mapping(address => struct AssetLib.Asset storage ref)\"\n                                      }\n                                    },\n                                    \"id\": 4461,\n                                    \"indexExpression\": {\n                                      \"argumentTypes\": null,\n                                      \"id\": 4460,\n                                      \"name\": \"sender\",\n                                      \"nodeType\": \"Identifier\",\n                                      \"overloadedDeclarations\": [],\n                                      \"referencedDeclaration\": 4299,\n                                      \"src\": \"16878:6:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_address\",\n                                        \"typeString\": \"address\"\n                                      }\n                                    },\n                                    \"isConstant\": false,\n                                    \"isLValue\": true,\n                                    \"isPure\": false,\n                                    \"lValueRequested\": false,\n                                    \"nodeType\": \"IndexAccess\",\n                                    \"src\": \"16867:18:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                                      \"typeString\": \"struct AssetLib.Asset storage ref\"\n                                    }\n                                  },\n                                  \"id\": 4462,\n                                  \"isConstant\": false,\n                                  \"isLValue\": true,\n                                  \"isPure\": false,\n                                  \"lValueRequested\": false,\n                                  \"memberName\": \"iAdd\",\n                                  \"nodeType\": \"MemberAccess\",\n                                  \"referencedDeclaration\": 2878,\n                                  \"src\": \"16867:23:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_function_internal_nonpayable$_t_struct$_Asset_$2788_storage_ptr_$_t_struct$_Asset_$2788_memory_ptr_$returns$__$bound_to$_t_struct$_Asset_$2788_storage_ptr_$\",\n                                    \"typeString\": \"function (struct AssetLib.Asset storage pointer,struct AssetLib.Asset memory)\"\n                                  }\n                                },\n                                \"id\": 4464,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": false,\n                                \"kind\": \"functionCall\",\n                                \"lValueRequested\": false,\n                                \"names\": [],\n                                \"nodeType\": \"FunctionCall\",\n                                \"src\": \"16867:32:6\",\n                                \"tryCall\": false,\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_tuple$__$\",\n                                  \"typeString\": \"tuple()\"\n                                }\n                              },\n                              \"id\": 4465,\n                              \"nodeType\": \"ExpressionStatement\",\n                              \"src\": \"16867:32:6\"\n                            },\n                            {\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"arguments\": [\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"id\": 4469,\n                                    \"name\": \"_amount\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 4320,\n                                    \"src\": \"16946:7:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                      \"typeString\": \"struct AssetLib.Asset memory\"\n                                    }\n                                  }\n                                ],\n                                \"expression\": {\n                                  \"argumentTypes\": [\n                                    {\n                                      \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                      \"typeString\": \"struct AssetLib.Asset memory\"\n                                    }\n                                  ],\n                                  \"expression\": {\n                                    \"argumentTypes\": null,\n                                    \"id\": 4466,\n                                    \"name\": \"_accruedGlobalLiquidity\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 3774,\n                                    \"src\": \"16917:23:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                                      \"typeString\": \"struct AssetLib.Asset storage ref\"\n                                    }\n                                  },\n                                  \"id\": 4468,\n                                  \"isConstant\": false,\n                                  \"isLValue\": true,\n                                  \"isPure\": false,\n                                  \"lValueRequested\": false,\n                                  \"memberName\": \"iAdd\",\n                                  \"nodeType\": \"MemberAccess\",\n                                  \"referencedDeclaration\": 2878,\n                                  \"src\": \"16917:28:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_function_internal_nonpayable$_t_struct$_Asset_$2788_storage_ptr_$_t_struct$_Asset_$2788_memory_ptr_$returns$__$bound_to$_t_struct$_Asset_$2788_storage_ptr_$\",\n                                    \"typeString\": \"function (struct AssetLib.Asset storage pointer,struct AssetLib.Asset memory)\"\n                                  }\n                                },\n                                \"id\": 4470,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": false,\n                                \"kind\": \"functionCall\",\n                                \"lValueRequested\": false,\n                                \"names\": [],\n                                \"nodeType\": \"FunctionCall\",\n                                \"src\": \"16917:37:6\",\n                                \"tryCall\": false,\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_tuple$__$\",\n                                  \"typeString\": \"tuple()\"\n                                }\n                              },\n                              \"id\": 4471,\n                              \"nodeType\": \"ExpressionStatement\",\n                              \"src\": \"16917:37:6\"\n                            },\n                            {\n                              \"eventCall\": {\n                                \"argumentTypes\": null,\n                                \"arguments\": [\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"id\": 4473,\n                                    \"name\": \"sender\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 4299,\n                                    \"src\": \"16989:6:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_address\",\n                                      \"typeString\": \"address\"\n                                    }\n                                  },\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"id\": 4474,\n                                    \"name\": \"curr_block\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 4294,\n                                    \"src\": \"16997:10:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    }\n                                  },\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"expression\": {\n                                      \"argumentTypes\": null,\n                                      \"id\": 4475,\n                                      \"name\": \"_amount\",\n                                      \"nodeType\": \"Identifier\",\n                                      \"overloadedDeclarations\": [],\n                                      \"referencedDeclaration\": 4320,\n                                      \"src\": \"17009:7:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                        \"typeString\": \"struct AssetLib.Asset memory\"\n                                      }\n                                    },\n                                    \"id\": 4476,\n                                    \"isConstant\": false,\n                                    \"isLValue\": true,\n                                    \"isPure\": false,\n                                    \"lValueRequested\": false,\n                                    \"memberName\": \"principal\",\n                                    \"nodeType\": \"MemberAccess\",\n                                    \"referencedDeclaration\": 2785,\n                                    \"src\": \"17009:17:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    }\n                                  },\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"expression\": {\n                                      \"argumentTypes\": null,\n                                      \"id\": 4477,\n                                      \"name\": \"_amount\",\n                                      \"nodeType\": \"Identifier\",\n                                      \"overloadedDeclarations\": [],\n                                      \"referencedDeclaration\": 4320,\n                                      \"src\": \"17028:7:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                        \"typeString\": \"struct AssetLib.Asset memory\"\n                                      }\n                                    },\n                                    \"id\": 4478,\n                                    \"isConstant\": false,\n                                    \"isLValue\": true,\n                                    \"isPure\": false,\n                                    \"lValueRequested\": false,\n                                    \"memberName\": \"compoundInterest\",\n                                    \"nodeType\": \"MemberAccess\",\n                                    \"referencedDeclaration\": 2787,\n                                    \"src\": \"17028:24:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    }\n                                  }\n                                ],\n                                \"expression\": {\n                                  \"argumentTypes\": [\n                                    {\n                                      \"typeIdentifier\": \"t_address\",\n                                      \"typeString\": \"address\"\n                                    },\n                                    {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    },\n                                    {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    },\n                                    {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    }\n                                  ],\n                                  \"id\": 4472,\n                                  \"name\": \"UnbindStake\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 3704,\n                                  \"src\": \"16977:11:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_function_event_nonpayable$_t_address_$_t_uint256_$_t_uint256_$_t_uint256_$returns$__$\",\n                                    \"typeString\": \"function (address,uint256,uint256,uint256)\"\n                                  }\n                                },\n                                \"id\": 4479,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": false,\n                                \"kind\": \"functionCall\",\n                                \"lValueRequested\": false,\n                                \"names\": [],\n                                \"nodeType\": \"FunctionCall\",\n                                \"src\": \"16977:76:6\",\n                                \"tryCall\": false,\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_tuple$__$\",\n                                  \"typeString\": \"tuple()\"\n                                }\n                              },\n                              \"id\": 4480,\n                              \"nodeType\": \"EmitStatement\",\n                              \"src\": \"16972:81:6\"\n                            },\n                            {\n                              \"eventCall\": {\n                                \"argumentTypes\": null,\n                                \"arguments\": [\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"id\": 4482,\n                                    \"name\": \"sender\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 4299,\n                                    \"src\": \"17094:6:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_address\",\n                                      \"typeString\": \"address\"\n                                    }\n                                  },\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"expression\": {\n                                      \"argumentTypes\": null,\n                                      \"id\": 4483,\n                                      \"name\": \"_amount\",\n                                      \"nodeType\": \"Identifier\",\n                                      \"overloadedDeclarations\": [],\n                                      \"referencedDeclaration\": 4320,\n                                      \"src\": \"17102:7:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                        \"typeString\": \"struct AssetLib.Asset memory\"\n                                      }\n                                    },\n                                    \"id\": 4484,\n                                    \"isConstant\": false,\n                                    \"isLValue\": true,\n                                    \"isPure\": false,\n                                    \"lValueRequested\": false,\n                                    \"memberName\": \"principal\",\n                                    \"nodeType\": \"MemberAccess\",\n                                    \"referencedDeclaration\": 2785,\n                                    \"src\": \"17102:17:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    }\n                                  },\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"expression\": {\n                                      \"argumentTypes\": null,\n                                      \"id\": 4485,\n                                      \"name\": \"_amount\",\n                                      \"nodeType\": \"Identifier\",\n                                      \"overloadedDeclarations\": [],\n                                      \"referencedDeclaration\": 4320,\n                                      \"src\": \"17121:7:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                        \"typeString\": \"struct AssetLib.Asset memory\"\n                                      }\n                                    },\n                                    \"id\": 4486,\n                                    \"isConstant\": false,\n                                    \"isLValue\": true,\n                                    \"isPure\": false,\n                                    \"lValueRequested\": false,\n                                    \"memberName\": \"compoundInterest\",\n                                    \"nodeType\": \"MemberAccess\",\n                                    \"referencedDeclaration\": 2787,\n                                    \"src\": \"17121:24:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    }\n                                  }\n                                ],\n                                \"expression\": {\n                                  \"argumentTypes\": [\n                                    {\n                                      \"typeIdentifier\": \"t_address\",\n                                      \"typeString\": \"address\"\n                                    },\n                                    {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    },\n                                    {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    }\n                                  ],\n                                  \"id\": 4481,\n                                  \"name\": \"LiquidityUnlocked\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 3694,\n                                  \"src\": \"17076:17:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_function_event_nonpayable$_t_address_$_t_uint256_$_t_uint256_$returns$__$\",\n                                    \"typeString\": \"function (address,uint256,uint256)\"\n                                  }\n                                },\n                                \"id\": 4487,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": false,\n                                \"kind\": \"functionCall\",\n                                \"lValueRequested\": false,\n                                \"names\": [],\n                                \"nodeType\": \"FunctionCall\",\n                                \"src\": \"17076:70:6\",\n                                \"tryCall\": false,\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_tuple$__$\",\n                                  \"typeString\": \"tuple()\"\n                                }\n                              },\n                              \"id\": 4488,\n                              \"nodeType\": \"EmitStatement\",\n                              \"src\": \"17071:75:6\"\n                            }\n                          ]\n                        }\n                      }\n                    ]\n                  },\n                  \"id\": 4548,\n                  \"nodeType\": \"IfStatement\",\n                  \"src\": \"14675:3133:6\",\n                  \"trueBody\": {\n                    \"id\": 4428,\n                    \"nodeType\": \"Block\",\n                    \"src\": \"14691:1865:6\",\n                    \"statements\": [\n                      {\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"arguments\": [\n                            {\n                              \"argumentTypes\": null,\n                              \"commonType\": {\n                                \"typeIdentifier\": \"t_uint256\",\n                                \"typeString\": \"uint256\"\n                              },\n                              \"id\": 4328,\n                              \"isConstant\": false,\n                              \"isLValue\": false,\n                              \"isPure\": false,\n                              \"lValueRequested\": false,\n                              \"leftExpression\": {\n                                \"argumentTypes\": null,\n                                \"id\": 4326,\n                                \"name\": \"amount\",\n                                \"nodeType\": \"Identifier\",\n                                \"overloadedDeclarations\": [],\n                                \"referencedDeclaration\": 4283,\n                                \"src\": \"15425:6:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              },\n                              \"nodeType\": \"BinaryOperation\",\n                              \"operator\": \"<=\",\n                              \"rightExpression\": {\n                                \"argumentTypes\": null,\n                                \"id\": 4327,\n                                \"name\": \"stake_composite\",\n                                \"nodeType\": \"Identifier\",\n                                \"overloadedDeclarations\": [],\n                                \"referencedDeclaration\": 4311,\n                                \"src\": \"15435:15:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              },\n                              \"src\": \"15425:25:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_bool\",\n                                \"typeString\": \"bool\"\n                              }\n                            },\n                            {\n                              \"argumentTypes\": null,\n                              \"hexValue\": \"416d6f756e7420697320686967686572207468616e207374616b65\",\n                              \"id\": 4329,\n                              \"isConstant\": false,\n                              \"isLValue\": false,\n                              \"isPure\": true,\n                              \"kind\": \"string\",\n                              \"lValueRequested\": false,\n                              \"nodeType\": \"Literal\",\n                              \"src\": \"15452:29:6\",\n                              \"subdenomination\": null,\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_stringliteral_8bda5dc5d5057eb9094b795367834747986b50a0bac9d1f451ae725565808bcd\",\n                                \"typeString\": \"literal_string \\\"Amount is higher than stake\\\"\"\n                              },\n                              \"value\": \"Amount is higher than stake\"\n                            }\n                          ],\n                          \"expression\": {\n                            \"argumentTypes\": [\n                              {\n                                \"typeIdentifier\": \"t_bool\",\n                                \"typeString\": \"bool\"\n                              },\n                              {\n                                \"typeIdentifier\": \"t_stringliteral_8bda5dc5d5057eb9094b795367834747986b50a0bac9d1f451ae725565808bcd\",\n                                \"typeString\": \"literal_string \\\"Amount is higher than stake\\\"\"\n                              }\n                            ],\n                            \"id\": 4325,\n                            \"name\": \"require\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [\n                              -18,\n                              -18\n                            ],\n                            \"referencedDeclaration\": -18,\n                            \"src\": \"15417:7:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$\",\n                              \"typeString\": \"function (bool,string memory) pure\"\n                            }\n                          },\n                          \"id\": 4330,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"kind\": \"functionCall\",\n                          \"lValueRequested\": false,\n                          \"names\": [],\n                          \"nodeType\": \"FunctionCall\",\n                          \"src\": \"15417:65:6\",\n                          \"tryCall\": false,\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_tuple$__$\",\n                            \"typeString\": \"tuple()\"\n                          }\n                        },\n                        \"id\": 4331,\n                        \"nodeType\": \"ExpressionStatement\",\n                        \"src\": \"15417:65:6\"\n                      },\n                      {\n                        \"condition\": {\n                          \"argumentTypes\": null,\n                          \"commonType\": {\n                            \"typeIdentifier\": \"t_uint64\",\n                            \"typeString\": \"uint64\"\n                          },\n                          \"id\": 4334,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"leftExpression\": {\n                            \"argumentTypes\": null,\n                            \"id\": 4332,\n                            \"name\": \"_lockPeriodInBlocks\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 3768,\n                            \"src\": \"15501:19:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint64\",\n                              \"typeString\": \"uint64\"\n                            }\n                          },\n                          \"nodeType\": \"BinaryOperation\",\n                          \"operator\": \"==\",\n                          \"rightExpression\": {\n                            \"argumentTypes\": null,\n                            \"hexValue\": \"30\",\n                            \"id\": 4333,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": true,\n                            \"kind\": \"number\",\n                            \"lValueRequested\": false,\n                            \"nodeType\": \"Literal\",\n                            \"src\": \"15524:1:6\",\n                            \"subdenomination\": null,\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_rational_0_by_1\",\n                              \"typeString\": \"int_const 0\"\n                            },\n                            \"value\": \"0\"\n                          },\n                          \"src\": \"15501:24:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_bool\",\n                            \"typeString\": \"bool\"\n                          }\n                        },\n                        \"falseBody\": {\n                          \"id\": 4426,\n                          \"nodeType\": \"Block\",\n                          \"src\": \"15893:653:6\",\n                          \"statements\": [\n                            {\n                              \"assignments\": [\n                                4371\n                              ],\n                              \"declarations\": [\n                                {\n                                  \"constant\": false,\n                                  \"id\": 4371,\n                                  \"mutability\": \"mutable\",\n                                  \"name\": \"locked\",\n                                  \"nodeType\": \"VariableDeclaration\",\n                                  \"overrides\": null,\n                                  \"scope\": 4426,\n                                  \"src\": \"15911:21:6\",\n                                  \"stateVariable\": false,\n                                  \"storageLocation\": \"storage\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_struct$_Locked_$3659_storage_ptr\",\n                                    \"typeString\": \"struct Staking.Locked\"\n                                  },\n                                  \"typeName\": {\n                                    \"contractScope\": null,\n                                    \"id\": 4370,\n                                    \"name\": \"Locked\",\n                                    \"nodeType\": \"UserDefinedTypeName\",\n                                    \"referencedDeclaration\": 3659,\n                                    \"src\": \"15911:6:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_struct$_Locked_$3659_storage_ptr\",\n                                      \"typeString\": \"struct Staking.Locked\"\n                                    }\n                                  },\n                                  \"value\": null,\n                                  \"visibility\": \"internal\"\n                                }\n                              ],\n                              \"id\": 4375,\n                              \"initialValue\": {\n                                \"argumentTypes\": null,\n                                \"baseExpression\": {\n                                  \"argumentTypes\": null,\n                                  \"id\": 4372,\n                                  \"name\": \"_locked\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 3792,\n                                  \"src\": \"15935:7:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_mapping$_t_address_$_t_struct$_Locked_$3659_storage_$\",\n                                    \"typeString\": \"mapping(address => struct Staking.Locked storage ref)\"\n                                  }\n                                },\n                                \"id\": 4374,\n                                \"indexExpression\": {\n                                  \"argumentTypes\": null,\n                                  \"id\": 4373,\n                                  \"name\": \"sender\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 4299,\n                                  \"src\": \"15943:6:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_address\",\n                                    \"typeString\": \"address\"\n                                  }\n                                },\n                                \"isConstant\": false,\n                                \"isLValue\": true,\n                                \"isPure\": false,\n                                \"lValueRequested\": false,\n                                \"nodeType\": \"IndexAccess\",\n                                \"src\": \"15935:15:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_struct$_Locked_$3659_storage\",\n                                  \"typeString\": \"struct Staking.Locked storage ref\"\n                                }\n                              },\n                              \"nodeType\": \"VariableDeclarationStatement\",\n                              \"src\": \"15911:39:6\"\n                            },\n                            {\n                              \"assignments\": [\n                                4377\n                              ],\n                              \"declarations\": [\n                                {\n                                  \"constant\": false,\n                                  \"id\": 4377,\n                                  \"mutability\": \"mutable\",\n                                  \"name\": \"newLockedAsset\",\n                                  \"nodeType\": \"VariableDeclaration\",\n                                  \"overrides\": null,\n                                  \"scope\": 4426,\n                                  \"src\": \"15968:34:6\",\n                                  \"stateVariable\": false,\n                                  \"storageLocation\": \"storage\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_struct$_LockedAsset_$3653_storage_ptr\",\n                                    \"typeString\": \"struct Staking.LockedAsset\"\n                                  },\n                                  \"typeName\": {\n                                    \"contractScope\": null,\n                                    \"id\": 4376,\n                                    \"name\": \"LockedAsset\",\n                                    \"nodeType\": \"UserDefinedTypeName\",\n                                    \"referencedDeclaration\": 3653,\n                                    \"src\": \"15968:11:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_struct$_LockedAsset_$3653_storage_ptr\",\n                                      \"typeString\": \"struct Staking.LockedAsset\"\n                                    }\n                                  },\n                                  \"value\": null,\n                                  \"visibility\": \"internal\"\n                                }\n                              ],\n                              \"id\": 4382,\n                              \"initialValue\": {\n                                \"argumentTypes\": null,\n                                \"arguments\": [],\n                                \"expression\": {\n                                  \"argumentTypes\": [],\n                                  \"expression\": {\n                                    \"argumentTypes\": null,\n                                    \"expression\": {\n                                      \"argumentTypes\": null,\n                                      \"id\": 4378,\n                                      \"name\": \"locked\",\n                                      \"nodeType\": \"Identifier\",\n                                      \"overloadedDeclarations\": [],\n                                      \"referencedDeclaration\": 4371,\n                                      \"src\": \"16005:6:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_struct$_Locked_$3659_storage_ptr\",\n                                        \"typeString\": \"struct Staking.Locked storage pointer\"\n                                      }\n                                    },\n                                    \"id\": 4379,\n                                    \"isConstant\": false,\n                                    \"isLValue\": true,\n                                    \"isPure\": false,\n                                    \"lValueRequested\": false,\n                                    \"memberName\": \"assets\",\n                                    \"nodeType\": \"MemberAccess\",\n                                    \"referencedDeclaration\": 3658,\n                                    \"src\": \"16005:13:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_array$_t_struct$_LockedAsset_$3653_storage_$dyn_storage\",\n                                      \"typeString\": \"struct Staking.LockedAsset storage ref[] storage ref\"\n                                    }\n                                  },\n                                  \"id\": 4380,\n                                  \"isConstant\": false,\n                                  \"isLValue\": false,\n                                  \"isPure\": false,\n                                  \"lValueRequested\": false,\n                                  \"memberName\": \"push\",\n                                  \"nodeType\": \"MemberAccess\",\n                                  \"referencedDeclaration\": null,\n                                  \"src\": \"16005:18:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_function_arraypush_nonpayable$__$returns$_t_struct$_LockedAsset_$3653_storage_$\",\n                                    \"typeString\": \"function () returns (struct Staking.LockedAsset storage ref)\"\n                                  }\n                                },\n                                \"id\": 4381,\n                                \"isConstant\": false,\n                                \"isLValue\": true,\n                                \"isPure\": false,\n                                \"kind\": \"functionCall\",\n                                \"lValueRequested\": false,\n                                \"names\": [],\n                                \"nodeType\": \"FunctionCall\",\n                                \"src\": \"16005:20:6\",\n                                \"tryCall\": false,\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_struct$_LockedAsset_$3653_storage\",\n                                  \"typeString\": \"struct Staking.LockedAsset storage ref\"\n                                }\n                              },\n                              \"nodeType\": \"VariableDeclarationStatement\",\n                              \"src\": \"15968:57:6\"\n                            },\n                            {\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"id\": 4390,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": false,\n                                \"lValueRequested\": false,\n                                \"leftHandSide\": {\n                                  \"argumentTypes\": null,\n                                  \"expression\": {\n                                    \"argumentTypes\": null,\n                                    \"id\": 4383,\n                                    \"name\": \"newLockedAsset\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 4377,\n                                    \"src\": \"16043:14:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_struct$_LockedAsset_$3653_storage_ptr\",\n                                      \"typeString\": \"struct Staking.LockedAsset storage pointer\"\n                                    }\n                                  },\n                                  \"id\": 4385,\n                                  \"isConstant\": false,\n                                  \"isLValue\": true,\n                                  \"isPure\": false,\n                                  \"lValueRequested\": true,\n                                  \"memberName\": \"liquidSinceBlock\",\n                                  \"nodeType\": \"MemberAccess\",\n                                  \"referencedDeclaration\": 3650,\n                                  \"src\": \"16043:31:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_uint256\",\n                                    \"typeString\": \"uint256\"\n                                  }\n                                },\n                                \"nodeType\": \"Assignment\",\n                                \"operator\": \"=\",\n                                \"rightHandSide\": {\n                                  \"argumentTypes\": null,\n                                  \"arguments\": [\n                                    {\n                                      \"argumentTypes\": null,\n                                      \"id\": 4388,\n                                      \"name\": \"_lockPeriodInBlocks\",\n                                      \"nodeType\": \"Identifier\",\n                                      \"overloadedDeclarations\": [],\n                                      \"referencedDeclaration\": 3768,\n                                      \"src\": \"16092:19:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_uint64\",\n                                        \"typeString\": \"uint64\"\n                                      }\n                                    }\n                                  ],\n                                  \"expression\": {\n                                    \"argumentTypes\": [\n                                      {\n                                        \"typeIdentifier\": \"t_uint64\",\n                                        \"typeString\": \"uint64\"\n                                      }\n                                    ],\n                                    \"expression\": {\n                                      \"argumentTypes\": null,\n                                      \"id\": 4386,\n                                      \"name\": \"curr_block\",\n                                      \"nodeType\": \"Identifier\",\n                                      \"overloadedDeclarations\": [],\n                                      \"referencedDeclaration\": 4294,\n                                      \"src\": \"16077:10:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_uint256\",\n                                        \"typeString\": \"uint256\"\n                                      }\n                                    },\n                                    \"id\": 4387,\n                                    \"isConstant\": false,\n                                    \"isLValue\": false,\n                                    \"isPure\": false,\n                                    \"lValueRequested\": false,\n                                    \"memberName\": \"add\",\n                                    \"nodeType\": \"MemberAccess\",\n                                    \"referencedDeclaration\": 5870,\n                                    \"src\": \"16077:14:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_function_internal_pure$_t_uint256_$_t_uint256_$returns$_t_uint256_$bound_to$_t_uint256_$\",\n                                      \"typeString\": \"function (uint256,uint256) pure returns (uint256)\"\n                                    }\n                                  },\n                                  \"id\": 4389,\n                                  \"isConstant\": false,\n                                  \"isLValue\": false,\n                                  \"isPure\": false,\n                                  \"kind\": \"functionCall\",\n                                  \"lValueRequested\": false,\n                                  \"names\": [],\n                                  \"nodeType\": \"FunctionCall\",\n                                  \"src\": \"16077:35:6\",\n                                  \"tryCall\": false,\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_uint256\",\n                                    \"typeString\": \"uint256\"\n                                  }\n                                },\n                                \"src\": \"16043:69:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              },\n                              \"id\": 4391,\n                              \"nodeType\": \"ExpressionStatement\",\n                              \"src\": \"16043:69:6\"\n                            },\n                            {\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"id\": 4400,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": false,\n                                \"lValueRequested\": false,\n                                \"leftHandSide\": {\n                                  \"argumentTypes\": null,\n                                  \"id\": 4392,\n                                  \"name\": \"_amount\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 4320,\n                                  \"src\": \"16130:7:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                    \"typeString\": \"struct AssetLib.Asset memory\"\n                                  }\n                                },\n                                \"nodeType\": \"Assignment\",\n                                \"operator\": \"=\",\n                                \"rightHandSide\": {\n                                  \"argumentTypes\": null,\n                                  \"arguments\": [\n                                    {\n                                      \"argumentTypes\": null,\n                                      \"expression\": {\n                                        \"argumentTypes\": null,\n                                        \"id\": 4396,\n                                        \"name\": \"newLockedAsset\",\n                                        \"nodeType\": \"Identifier\",\n                                        \"overloadedDeclarations\": [],\n                                        \"referencedDeclaration\": 4377,\n                                        \"src\": \"16183:14:6\",\n                                        \"typeDescriptions\": {\n                                          \"typeIdentifier\": \"t_struct$_LockedAsset_$3653_storage_ptr\",\n                                          \"typeString\": \"struct Staking.LockedAsset storage pointer\"\n                                        }\n                                      },\n                                      \"id\": 4397,\n                                      \"isConstant\": false,\n                                      \"isLValue\": true,\n                                      \"isPure\": false,\n                                      \"lValueRequested\": false,\n                                      \"memberName\": \"asset\",\n                                      \"nodeType\": \"MemberAccess\",\n                                      \"referencedDeclaration\": 3652,\n                                      \"src\": \"16183:20:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                                        \"typeString\": \"struct AssetLib.Asset storage ref\"\n                                      }\n                                    },\n                                    {\n                                      \"argumentTypes\": null,\n                                      \"id\": 4398,\n                                      \"name\": \"amount\",\n                                      \"nodeType\": \"Identifier\",\n                                      \"overloadedDeclarations\": [],\n                                      \"referencedDeclaration\": 4283,\n                                      \"src\": \"16205:6:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_uint256\",\n                                        \"typeString\": \"uint256\"\n                                      }\n                                    }\n                                  ],\n                                  \"expression\": {\n                                    \"argumentTypes\": [\n                                      {\n                                        \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                                        \"typeString\": \"struct AssetLib.Asset storage ref\"\n                                      },\n                                      {\n                                        \"typeIdentifier\": \"t_uint256\",\n                                        \"typeString\": \"uint256\"\n                                      }\n                                    ],\n                                    \"expression\": {\n                                      \"argumentTypes\": null,\n                                      \"expression\": {\n                                        \"argumentTypes\": null,\n                                        \"id\": 4393,\n                                        \"name\": \"stake\",\n                                        \"nodeType\": \"Identifier\",\n                                        \"overloadedDeclarations\": [],\n                                        \"referencedDeclaration\": 4304,\n                                        \"src\": \"16140:5:6\",\n                                        \"typeDescriptions\": {\n                                          \"typeIdentifier\": \"t_struct$_Stake_$3648_storage_ptr\",\n                                          \"typeString\": \"struct Staking.Stake storage pointer\"\n                                        }\n                                      },\n                                      \"id\": 4394,\n                                      \"isConstant\": false,\n                                      \"isLValue\": true,\n                                      \"isPure\": false,\n                                      \"lValueRequested\": false,\n                                      \"memberName\": \"asset\",\n                                      \"nodeType\": \"MemberAccess\",\n                                      \"referencedDeclaration\": 3647,\n                                      \"src\": \"16140:11:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                                        \"typeString\": \"struct AssetLib.Asset storage ref\"\n                                      }\n                                    },\n                                    \"id\": 4395,\n                                    \"isConstant\": false,\n                                    \"isLValue\": true,\n                                    \"isPure\": false,\n                                    \"lValueRequested\": false,\n                                    \"memberName\": \"iRelocateCompoundInterestFirst\",\n                                    \"nodeType\": \"MemberAccess\",\n                                    \"referencedDeclaration\": 3120,\n                                    \"src\": \"16140:42:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_function_internal_nonpayable$_t_struct$_Asset_$2788_storage_ptr_$_t_struct$_Asset_$2788_storage_ptr_$_t_uint256_$returns$_t_struct$_Asset_$2788_memory_ptr_$bound_to$_t_struct$_Asset_$2788_storage_ptr_$\",\n                                      \"typeString\": \"function (struct AssetLib.Asset storage pointer,struct AssetLib.Asset storage pointer,uint256) returns (struct AssetLib.Asset memory)\"\n                                    }\n                                  },\n                                  \"id\": 4399,\n                                  \"isConstant\": false,\n                                  \"isLValue\": false,\n                                  \"isPure\": false,\n                                  \"kind\": \"functionCall\",\n                                  \"lValueRequested\": false,\n                                  \"names\": [],\n                                  \"nodeType\": \"FunctionCall\",\n                                  \"src\": \"16140:72:6\",\n                                  \"tryCall\": false,\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                    \"typeString\": \"struct AssetLib.Asset memory\"\n                                  }\n                                },\n                                \"src\": \"16130:82:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                  \"typeString\": \"struct AssetLib.Asset memory\"\n                                }\n                              },\n                              \"id\": 4401,\n                              \"nodeType\": \"ExpressionStatement\",\n                              \"src\": \"16130:82:6\"\n                            },\n                            {\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"arguments\": [\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"id\": 4405,\n                                    \"name\": \"_amount\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 4320,\n                                    \"src\": \"16257:7:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                      \"typeString\": \"struct AssetLib.Asset memory\"\n                                    }\n                                  }\n                                ],\n                                \"expression\": {\n                                  \"argumentTypes\": [\n                                    {\n                                      \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                      \"typeString\": \"struct AssetLib.Asset memory\"\n                                    }\n                                  ],\n                                  \"expression\": {\n                                    \"argumentTypes\": null,\n                                    \"id\": 4402,\n                                    \"name\": \"_accruedGlobalLocked\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 3776,\n                                    \"src\": \"16231:20:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                                      \"typeString\": \"struct AssetLib.Asset storage ref\"\n                                    }\n                                  },\n                                  \"id\": 4404,\n                                  \"isConstant\": false,\n                                  \"isLValue\": true,\n                                  \"isPure\": false,\n                                  \"lValueRequested\": false,\n                                  \"memberName\": \"iAdd\",\n                                  \"nodeType\": \"MemberAccess\",\n                                  \"referencedDeclaration\": 2878,\n                                  \"src\": \"16231:25:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_function_internal_nonpayable$_t_struct$_Asset_$2788_storage_ptr_$_t_struct$_Asset_$2788_memory_ptr_$returns$__$bound_to$_t_struct$_Asset_$2788_storage_ptr_$\",\n                                    \"typeString\": \"function (struct AssetLib.Asset storage pointer,struct AssetLib.Asset memory)\"\n                                  }\n                                },\n                                \"id\": 4406,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": false,\n                                \"kind\": \"functionCall\",\n                                \"lValueRequested\": false,\n                                \"names\": [],\n                                \"nodeType\": \"FunctionCall\",\n                                \"src\": \"16231:34:6\",\n                                \"tryCall\": false,\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_tuple$__$\",\n                                  \"typeString\": \"tuple()\"\n                                }\n                              },\n                              \"id\": 4407,\n                              \"nodeType\": \"ExpressionStatement\",\n                              \"src\": \"16231:34:6\"\n                            },\n                            {\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"arguments\": [\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"id\": 4413,\n                                    \"name\": \"_amount\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 4320,\n                                    \"src\": \"16305:7:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                      \"typeString\": \"struct AssetLib.Asset memory\"\n                                    }\n                                  }\n                                ],\n                                \"expression\": {\n                                  \"argumentTypes\": [\n                                    {\n                                      \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                      \"typeString\": \"struct AssetLib.Asset memory\"\n                                    }\n                                  ],\n                                  \"expression\": {\n                                    \"argumentTypes\": null,\n                                    \"expression\": {\n                                      \"argumentTypes\": null,\n                                      \"id\": 4408,\n                                      \"name\": \"locked\",\n                                      \"nodeType\": \"Identifier\",\n                                      \"overloadedDeclarations\": [],\n                                      \"referencedDeclaration\": 4371,\n                                      \"src\": \"16283:6:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_struct$_Locked_$3659_storage_ptr\",\n                                        \"typeString\": \"struct Staking.Locked storage pointer\"\n                                      }\n                                    },\n                                    \"id\": 4411,\n                                    \"isConstant\": false,\n                                    \"isLValue\": true,\n                                    \"isPure\": false,\n                                    \"lValueRequested\": false,\n                                    \"memberName\": \"aggregate\",\n                                    \"nodeType\": \"MemberAccess\",\n                                    \"referencedDeclaration\": 3655,\n                                    \"src\": \"16283:16:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                                      \"typeString\": \"struct AssetLib.Asset storage ref\"\n                                    }\n                                  },\n                                  \"id\": 4412,\n                                  \"isConstant\": false,\n                                  \"isLValue\": true,\n                                  \"isPure\": false,\n                                  \"lValueRequested\": false,\n                                  \"memberName\": \"iAdd\",\n                                  \"nodeType\": \"MemberAccess\",\n                                  \"referencedDeclaration\": 2878,\n                                  \"src\": \"16283:21:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_function_internal_nonpayable$_t_struct$_Asset_$2788_storage_ptr_$_t_struct$_Asset_$2788_memory_ptr_$returns$__$bound_to$_t_struct$_Asset_$2788_storage_ptr_$\",\n                                    \"typeString\": \"function (struct AssetLib.Asset storage pointer,struct AssetLib.Asset memory)\"\n                                  }\n                                },\n                                \"id\": 4414,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": false,\n                                \"kind\": \"functionCall\",\n                                \"lValueRequested\": false,\n                                \"names\": [],\n                                \"nodeType\": \"FunctionCall\",\n                                \"src\": \"16283:30:6\",\n                                \"tryCall\": false,\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_tuple$__$\",\n                                  \"typeString\": \"tuple()\"\n                                }\n                              },\n                              \"id\": 4415,\n                              \"nodeType\": \"ExpressionStatement\",\n                              \"src\": \"16283:30:6\"\n                            },\n                            {\n                              \"eventCall\": {\n                                \"argumentTypes\": null,\n                                \"arguments\": [\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"id\": 4417,\n                                    \"name\": \"sender\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 4299,\n                                    \"src\": \"16446:6:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_address\",\n                                      \"typeString\": \"address\"\n                                    }\n                                  },\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"expression\": {\n                                      \"argumentTypes\": null,\n                                      \"id\": 4418,\n                                      \"name\": \"newLockedAsset\",\n                                      \"nodeType\": \"Identifier\",\n                                      \"overloadedDeclarations\": [],\n                                      \"referencedDeclaration\": 4377,\n                                      \"src\": \"16454:14:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_struct$_LockedAsset_$3653_storage_ptr\",\n                                        \"typeString\": \"struct Staking.LockedAsset storage pointer\"\n                                      }\n                                    },\n                                    \"id\": 4419,\n                                    \"isConstant\": false,\n                                    \"isLValue\": true,\n                                    \"isPure\": false,\n                                    \"lValueRequested\": false,\n                                    \"memberName\": \"liquidSinceBlock\",\n                                    \"nodeType\": \"MemberAccess\",\n                                    \"referencedDeclaration\": 3650,\n                                    \"src\": \"16454:31:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    }\n                                  },\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"expression\": {\n                                      \"argumentTypes\": null,\n                                      \"id\": 4420,\n                                      \"name\": \"_amount\",\n                                      \"nodeType\": \"Identifier\",\n                                      \"overloadedDeclarations\": [],\n                                      \"referencedDeclaration\": 4320,\n                                      \"src\": \"16487:7:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                        \"typeString\": \"struct AssetLib.Asset memory\"\n                                      }\n                                    },\n                                    \"id\": 4421,\n                                    \"isConstant\": false,\n                                    \"isLValue\": true,\n                                    \"isPure\": false,\n                                    \"lValueRequested\": false,\n                                    \"memberName\": \"principal\",\n                                    \"nodeType\": \"MemberAccess\",\n                                    \"referencedDeclaration\": 2785,\n                                    \"src\": \"16487:17:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    }\n                                  },\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"expression\": {\n                                      \"argumentTypes\": null,\n                                      \"id\": 4422,\n                                      \"name\": \"_amount\",\n                                      \"nodeType\": \"Identifier\",\n                                      \"overloadedDeclarations\": [],\n                                      \"referencedDeclaration\": 4320,\n                                      \"src\": \"16506:7:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                        \"typeString\": \"struct AssetLib.Asset memory\"\n                                      }\n                                    },\n                                    \"id\": 4423,\n                                    \"isConstant\": false,\n                                    \"isLValue\": true,\n                                    \"isPure\": false,\n                                    \"lValueRequested\": false,\n                                    \"memberName\": \"compoundInterest\",\n                                    \"nodeType\": \"MemberAccess\",\n                                    \"referencedDeclaration\": 2787,\n                                    \"src\": \"16506:24:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    }\n                                  }\n                                ],\n                                \"expression\": {\n                                  \"argumentTypes\": [\n                                    {\n                                      \"typeIdentifier\": \"t_address\",\n                                      \"typeString\": \"address\"\n                                    },\n                                    {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    },\n                                    {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    },\n                                    {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    }\n                                  ],\n                                  \"id\": 4416,\n                                  \"name\": \"UnbindStake\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 3704,\n                                  \"src\": \"16434:11:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_function_event_nonpayable$_t_address_$_t_uint256_$_t_uint256_$_t_uint256_$returns$__$\",\n                                    \"typeString\": \"function (address,uint256,uint256,uint256)\"\n                                  }\n                                },\n                                \"id\": 4424,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": false,\n                                \"kind\": \"functionCall\",\n                                \"lValueRequested\": false,\n                                \"names\": [],\n                                \"nodeType\": \"FunctionCall\",\n                                \"src\": \"16434:97:6\",\n                                \"tryCall\": false,\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_tuple$__$\",\n                                  \"typeString\": \"tuple()\"\n                                }\n                              },\n                              \"id\": 4425,\n                              \"nodeType\": \"EmitStatement\",\n                              \"src\": \"16429:102:6\"\n                            }\n                          ]\n                        },\n                        \"id\": 4427,\n                        \"nodeType\": \"IfStatement\",\n                        \"src\": \"15497:1049:6\",\n                        \"trueBody\": {\n                          \"id\": 4369,\n                          \"nodeType\": \"Block\",\n                          \"src\": \"15527:360:6\",\n                          \"statements\": [\n                            {\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"id\": 4344,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": false,\n                                \"lValueRequested\": false,\n                                \"leftHandSide\": {\n                                  \"argumentTypes\": null,\n                                  \"id\": 4335,\n                                  \"name\": \"_amount\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 4320,\n                                  \"src\": \"15545:7:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                    \"typeString\": \"struct AssetLib.Asset memory\"\n                                  }\n                                },\n                                \"nodeType\": \"Assignment\",\n                                \"operator\": \"=\",\n                                \"rightHandSide\": {\n                                  \"argumentTypes\": null,\n                                  \"arguments\": [\n                                    {\n                                      \"argumentTypes\": null,\n                                      \"baseExpression\": {\n                                        \"argumentTypes\": null,\n                                        \"id\": 4339,\n                                        \"name\": \"_liquidity\",\n                                        \"nodeType\": \"Identifier\",\n                                        \"overloadedDeclarations\": [],\n                                        \"referencedDeclaration\": 3796,\n                                        \"src\": \"15598:10:6\",\n                                        \"typeDescriptions\": {\n                                          \"typeIdentifier\": \"t_mapping$_t_address_$_t_struct$_Asset_$2788_storage_$\",\n                                          \"typeString\": \"mapping(address => struct AssetLib.Asset storage ref)\"\n                                        }\n                                      },\n                                      \"id\": 4341,\n                                      \"indexExpression\": {\n                                        \"argumentTypes\": null,\n                                        \"id\": 4340,\n                                        \"name\": \"sender\",\n                                        \"nodeType\": \"Identifier\",\n                                        \"overloadedDeclarations\": [],\n                                        \"referencedDeclaration\": 4299,\n                                        \"src\": \"15609:6:6\",\n                                        \"typeDescriptions\": {\n                                          \"typeIdentifier\": \"t_address\",\n                                          \"typeString\": \"address\"\n                                        }\n                                      },\n                                      \"isConstant\": false,\n                                      \"isLValue\": true,\n                                      \"isPure\": false,\n                                      \"lValueRequested\": false,\n                                      \"nodeType\": \"IndexAccess\",\n                                      \"src\": \"15598:18:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                                        \"typeString\": \"struct AssetLib.Asset storage ref\"\n                                      }\n                                    },\n                                    {\n                                      \"argumentTypes\": null,\n                                      \"id\": 4342,\n                                      \"name\": \"amount\",\n                                      \"nodeType\": \"Identifier\",\n                                      \"overloadedDeclarations\": [],\n                                      \"referencedDeclaration\": 4283,\n                                      \"src\": \"15618:6:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_uint256\",\n                                        \"typeString\": \"uint256\"\n                                      }\n                                    }\n                                  ],\n                                  \"expression\": {\n                                    \"argumentTypes\": [\n                                      {\n                                        \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                                        \"typeString\": \"struct AssetLib.Asset storage ref\"\n                                      },\n                                      {\n                                        \"typeIdentifier\": \"t_uint256\",\n                                        \"typeString\": \"uint256\"\n                                      }\n                                    ],\n                                    \"expression\": {\n                                      \"argumentTypes\": null,\n                                      \"expression\": {\n                                        \"argumentTypes\": null,\n                                        \"id\": 4336,\n                                        \"name\": \"stake\",\n                                        \"nodeType\": \"Identifier\",\n                                        \"overloadedDeclarations\": [],\n                                        \"referencedDeclaration\": 4304,\n                                        \"src\": \"15555:5:6\",\n                                        \"typeDescriptions\": {\n                                          \"typeIdentifier\": \"t_struct$_Stake_$3648_storage_ptr\",\n                                          \"typeString\": \"struct Staking.Stake storage pointer\"\n                                        }\n                                      },\n                                      \"id\": 4337,\n                                      \"isConstant\": false,\n                                      \"isLValue\": true,\n                                      \"isPure\": false,\n                                      \"lValueRequested\": false,\n                                      \"memberName\": \"asset\",\n                                      \"nodeType\": \"MemberAccess\",\n                                      \"referencedDeclaration\": 3647,\n                                      \"src\": \"15555:11:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                                        \"typeString\": \"struct AssetLib.Asset storage ref\"\n                                      }\n                                    },\n                                    \"id\": 4338,\n                                    \"isConstant\": false,\n                                    \"isLValue\": true,\n                                    \"isPure\": false,\n                                    \"lValueRequested\": false,\n                                    \"memberName\": \"iRelocateCompoundInterestFirst\",\n                                    \"nodeType\": \"MemberAccess\",\n                                    \"referencedDeclaration\": 3120,\n                                    \"src\": \"15555:42:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_function_internal_nonpayable$_t_struct$_Asset_$2788_storage_ptr_$_t_struct$_Asset_$2788_storage_ptr_$_t_uint256_$returns$_t_struct$_Asset_$2788_memory_ptr_$bound_to$_t_struct$_Asset_$2788_storage_ptr_$\",\n                                      \"typeString\": \"function (struct AssetLib.Asset storage pointer,struct AssetLib.Asset storage pointer,uint256) returns (struct AssetLib.Asset memory)\"\n                                    }\n                                  },\n                                  \"id\": 4343,\n                                  \"isConstant\": false,\n                                  \"isLValue\": false,\n                                  \"isPure\": false,\n                                  \"kind\": \"functionCall\",\n                                  \"lValueRequested\": false,\n                                  \"names\": [],\n                                  \"nodeType\": \"FunctionCall\",\n                                  \"src\": \"15555:70:6\",\n                                  \"tryCall\": false,\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                    \"typeString\": \"struct AssetLib.Asset memory\"\n                                  }\n                                },\n                                \"src\": \"15545:80:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                  \"typeString\": \"struct AssetLib.Asset memory\"\n                                }\n                              },\n                              \"id\": 4345,\n                              \"nodeType\": \"ExpressionStatement\",\n                              \"src\": \"15545:80:6\"\n                            },\n                            {\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"arguments\": [\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"id\": 4349,\n                                    \"name\": \"_amount\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 4320,\n                                    \"src\": \"15672:7:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                      \"typeString\": \"struct AssetLib.Asset memory\"\n                                    }\n                                  }\n                                ],\n                                \"expression\": {\n                                  \"argumentTypes\": [\n                                    {\n                                      \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                      \"typeString\": \"struct AssetLib.Asset memory\"\n                                    }\n                                  ],\n                                  \"expression\": {\n                                    \"argumentTypes\": null,\n                                    \"id\": 4346,\n                                    \"name\": \"_accruedGlobalLiquidity\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 3774,\n                                    \"src\": \"15643:23:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                                      \"typeString\": \"struct AssetLib.Asset storage ref\"\n                                    }\n                                  },\n                                  \"id\": 4348,\n                                  \"isConstant\": false,\n                                  \"isLValue\": true,\n                                  \"isPure\": false,\n                                  \"lValueRequested\": false,\n                                  \"memberName\": \"iAdd\",\n                                  \"nodeType\": \"MemberAccess\",\n                                  \"referencedDeclaration\": 2878,\n                                  \"src\": \"15643:28:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_function_internal_nonpayable$_t_struct$_Asset_$2788_storage_ptr_$_t_struct$_Asset_$2788_memory_ptr_$returns$__$bound_to$_t_struct$_Asset_$2788_storage_ptr_$\",\n                                    \"typeString\": \"function (struct AssetLib.Asset storage pointer,struct AssetLib.Asset memory)\"\n                                  }\n                                },\n                                \"id\": 4350,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": false,\n                                \"kind\": \"functionCall\",\n                                \"lValueRequested\": false,\n                                \"names\": [],\n                                \"nodeType\": \"FunctionCall\",\n                                \"src\": \"15643:37:6\",\n                                \"tryCall\": false,\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_tuple$__$\",\n                                  \"typeString\": \"tuple()\"\n                                }\n                              },\n                              \"id\": 4351,\n                              \"nodeType\": \"ExpressionStatement\",\n                              \"src\": \"15643:37:6\"\n                            },\n                            {\n                              \"eventCall\": {\n                                \"argumentTypes\": null,\n                                \"arguments\": [\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"id\": 4353,\n                                    \"name\": \"sender\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 4299,\n                                    \"src\": \"15715:6:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_address\",\n                                      \"typeString\": \"address\"\n                                    }\n                                  },\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"id\": 4354,\n                                    \"name\": \"curr_block\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 4294,\n                                    \"src\": \"15723:10:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    }\n                                  },\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"expression\": {\n                                      \"argumentTypes\": null,\n                                      \"id\": 4355,\n                                      \"name\": \"_amount\",\n                                      \"nodeType\": \"Identifier\",\n                                      \"overloadedDeclarations\": [],\n                                      \"referencedDeclaration\": 4320,\n                                      \"src\": \"15735:7:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                        \"typeString\": \"struct AssetLib.Asset memory\"\n                                      }\n                                    },\n                                    \"id\": 4356,\n                                    \"isConstant\": false,\n                                    \"isLValue\": true,\n                                    \"isPure\": false,\n                                    \"lValueRequested\": false,\n                                    \"memberName\": \"principal\",\n                                    \"nodeType\": \"MemberAccess\",\n                                    \"referencedDeclaration\": 2785,\n                                    \"src\": \"15735:17:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    }\n                                  },\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"expression\": {\n                                      \"argumentTypes\": null,\n                                      \"id\": 4357,\n                                      \"name\": \"_amount\",\n                                      \"nodeType\": \"Identifier\",\n                                      \"overloadedDeclarations\": [],\n                                      \"referencedDeclaration\": 4320,\n                                      \"src\": \"15754:7:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                        \"typeString\": \"struct AssetLib.Asset memory\"\n                                      }\n                                    },\n                                    \"id\": 4358,\n                                    \"isConstant\": false,\n                                    \"isLValue\": true,\n                                    \"isPure\": false,\n                                    \"lValueRequested\": false,\n                                    \"memberName\": \"compoundInterest\",\n                                    \"nodeType\": \"MemberAccess\",\n                                    \"referencedDeclaration\": 2787,\n                                    \"src\": \"15754:24:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    }\n                                  }\n                                ],\n                                \"expression\": {\n                                  \"argumentTypes\": [\n                                    {\n                                      \"typeIdentifier\": \"t_address\",\n                                      \"typeString\": \"address\"\n                                    },\n                                    {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    },\n                                    {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    },\n                                    {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    }\n                                  ],\n                                  \"id\": 4352,\n                                  \"name\": \"UnbindStake\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 3704,\n                                  \"src\": \"15703:11:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_function_event_nonpayable$_t_address_$_t_uint256_$_t_uint256_$_t_uint256_$returns$__$\",\n                                    \"typeString\": \"function (address,uint256,uint256,uint256)\"\n                                  }\n                                },\n                                \"id\": 4359,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": false,\n                                \"kind\": \"functionCall\",\n                                \"lValueRequested\": false,\n                                \"names\": [],\n                                \"nodeType\": \"FunctionCall\",\n                                \"src\": \"15703:76:6\",\n                                \"tryCall\": false,\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_tuple$__$\",\n                                  \"typeString\": \"tuple()\"\n                                }\n                              },\n                              \"id\": 4360,\n                              \"nodeType\": \"EmitStatement\",\n                              \"src\": \"15698:81:6\"\n                            },\n                            {\n                              \"eventCall\": {\n                                \"argumentTypes\": null,\n                                \"arguments\": [\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"id\": 4362,\n                                    \"name\": \"sender\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 4299,\n                                    \"src\": \"15820:6:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_address\",\n                                      \"typeString\": \"address\"\n                                    }\n                                  },\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"expression\": {\n                                      \"argumentTypes\": null,\n                                      \"id\": 4363,\n                                      \"name\": \"_amount\",\n                                      \"nodeType\": \"Identifier\",\n                                      \"overloadedDeclarations\": [],\n                                      \"referencedDeclaration\": 4320,\n                                      \"src\": \"15828:7:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                        \"typeString\": \"struct AssetLib.Asset memory\"\n                                      }\n                                    },\n                                    \"id\": 4364,\n                                    \"isConstant\": false,\n                                    \"isLValue\": true,\n                                    \"isPure\": false,\n                                    \"lValueRequested\": false,\n                                    \"memberName\": \"principal\",\n                                    \"nodeType\": \"MemberAccess\",\n                                    \"referencedDeclaration\": 2785,\n                                    \"src\": \"15828:17:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    }\n                                  },\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"expression\": {\n                                      \"argumentTypes\": null,\n                                      \"id\": 4365,\n                                      \"name\": \"_amount\",\n                                      \"nodeType\": \"Identifier\",\n                                      \"overloadedDeclarations\": [],\n                                      \"referencedDeclaration\": 4320,\n                                      \"src\": \"15847:7:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                        \"typeString\": \"struct AssetLib.Asset memory\"\n                                      }\n                                    },\n                                    \"id\": 4366,\n                                    \"isConstant\": false,\n                                    \"isLValue\": true,\n                                    \"isPure\": false,\n                                    \"lValueRequested\": false,\n                                    \"memberName\": \"compoundInterest\",\n                                    \"nodeType\": \"MemberAccess\",\n                                    \"referencedDeclaration\": 2787,\n                                    \"src\": \"15847:24:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    }\n                                  }\n                                ],\n                                \"expression\": {\n                                  \"argumentTypes\": [\n                                    {\n                                      \"typeIdentifier\": \"t_address\",\n                                      \"typeString\": \"address\"\n                                    },\n                                    {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    },\n                                    {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    }\n                                  ],\n                                  \"id\": 4361,\n                                  \"name\": \"LiquidityUnlocked\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 3694,\n                                  \"src\": \"15802:17:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_function_event_nonpayable$_t_address_$_t_uint256_$_t_uint256_$returns$__$\",\n                                    \"typeString\": \"function (address,uint256,uint256)\"\n                                  }\n                                },\n                                \"id\": 4367,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": false,\n                                \"kind\": \"functionCall\",\n                                \"lValueRequested\": false,\n                                \"names\": [],\n                                \"nodeType\": \"FunctionCall\",\n                                \"src\": \"15802:70:6\",\n                                \"tryCall\": false,\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_tuple$__$\",\n                                  \"typeString\": \"tuple()\"\n                                }\n                              },\n                              \"id\": 4368,\n                              \"nodeType\": \"EmitStatement\",\n                              \"src\": \"15797:75:6\"\n                            }\n                          ]\n                        }\n                      }\n                    ]\n                  }\n                }\n              ]\n            },\n            \"documentation\": {\n              \"id\": 4281,\n              \"nodeType\": \"StructuredDocumentation\",\n              \"src\": \"13414:755:6\",\n              \"text\": \"@notice Unbinds amount from the stake of sender of the transaction,\\n        and *LOCKS* it for number of blocks defined by value of the\\n        `_lockPeriodInBlocks` state of this contract at the point\\n        of this call.\\n        The locked amount can *NOT* be withdrawn from the contract\\n        *BEFORE* the lock period ends.\\n     *         Unbinding (=calling this method) also means, that compound\\n        interest will be calculated for period since la.\\n     * @param amount - value to un-bind from the stake\\n                If `amount=0` then the **WHOLE** stake (including\\n                compound interest) will be unbound.\\n     * @dev public access\"\n            },\n            \"functionSelector\": \"52885d8d\",\n            \"id\": 4550,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [\n              {\n                \"arguments\": [\n                  {\n                    \"argumentTypes\": null,\n                    \"id\": 4288,\n                    \"name\": \"txExpirationBlock\",\n                    \"nodeType\": \"Identifier\",\n                    \"overloadedDeclarations\": [],\n                    \"referencedDeclaration\": 4285,\n                    \"src\": \"14353:17:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  }\n                ],\n                \"id\": 4289,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 4287,\n                  \"name\": \"verifyTxExpiration\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 3836,\n                  \"src\": \"14334:18:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$_t_uint256_$\",\n                    \"typeString\": \"modifier (uint256)\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"14334:37:6\"\n              },\n              {\n                \"arguments\": null,\n                \"id\": 4291,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 4290,\n                  \"name\": \"verifyNotPaused\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 3848,\n                  \"src\": \"14380:15:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$__$\",\n                    \"typeString\": \"modifier ()\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"14380:15:6\"\n              }\n            ],\n            \"name\": \"unbindStake\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 4286,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 4283,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"amount\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4550,\n                  \"src\": \"14204:14:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 4282,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"14204:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 4285,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"txExpirationBlock\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4550,\n                  \"src\": \"14273:25:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 4284,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"14273:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"14194:114:6\"\n            },\n            \"returnParameters\": {\n              \"id\": 4292,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"14400:0:6\"\n            },\n            \"scope\": 5490,\n            \"src\": \"14174:3640:6\",\n            \"stateMutability\": \"nonpayable\",\n            \"virtual\": false,\n            \"visibility\": \"external\"\n          },\n          {\n            \"body\": {\n              \"id\": 4557,\n              \"nodeType\": \"Block\",\n              \"src\": \"17885:43:6\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 4555,\n                    \"name\": \"_rewardsPoolBalance\",\n                    \"nodeType\": \"Identifier\",\n                    \"overloadedDeclarations\": [],\n                    \"referencedDeclaration\": 3770,\n                    \"src\": \"17902:19:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"functionReturnParameters\": 4554,\n                  \"id\": 4556,\n                  \"nodeType\": \"Return\",\n                  \"src\": \"17895:26:6\"\n                }\n              ]\n            },\n            \"documentation\": null,\n            \"functionSelector\": \"adf55101\",\n            \"id\": 4558,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [],\n            \"name\": \"getRewardsPoolBalance\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 4551,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"17851:2:6\"\n            },\n            \"returnParameters\": {\n              \"id\": 4554,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 4553,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4558,\n                  \"src\": \"17876:7:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 4552,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"17876:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"17875:9:6\"\n            },\n            \"scope\": 5490,\n            \"src\": \"17821:107:6\",\n            \"stateMutability\": \"view\",\n            \"virtual\": false,\n            \"visibility\": \"external\"\n          },\n          {\n            \"body\": {\n              \"id\": 4565,\n              \"nodeType\": \"Block\",\n              \"src\": \"18000:39:6\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 4563,\n                    \"name\": \"_earliestDelete\",\n                    \"nodeType\": \"Identifier\",\n                    \"overloadedDeclarations\": [],\n                    \"referencedDeclaration\": 3764,\n                    \"src\": \"18017:15:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"functionReturnParameters\": 4562,\n                  \"id\": 4564,\n                  \"nodeType\": \"Return\",\n                  \"src\": \"18010:22:6\"\n                }\n              ]\n            },\n            \"documentation\": null,\n            \"functionSelector\": \"085313ec\",\n            \"id\": 4566,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [],\n            \"name\": \"getEarliestDeleteBlock\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 4559,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"17966:2:6\"\n            },\n            \"returnParameters\": {\n              \"id\": 4562,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 4561,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4566,\n                  \"src\": \"17991:7:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 4560,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"17991:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"17990:9:6\"\n            },\n            \"scope\": 5490,\n            \"src\": \"17935:104:6\",\n            \"stateMutability\": \"view\",\n            \"virtual\": false,\n            \"visibility\": \"external\"\n          },\n          {\n            \"body\": {\n              \"id\": 4581,\n              \"nodeType\": \"Block\",\n              \"src\": \"18144:59:6\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 4579,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 4573,\n                      \"name\": \"length\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 4571,\n                      \"src\": \"18154:6:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"baseExpression\": {\n                            \"argumentTypes\": null,\n                            \"id\": 4574,\n                            \"name\": \"_locked\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 3792,\n                            \"src\": \"18163:7:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_mapping$_t_address_$_t_struct$_Locked_$3659_storage_$\",\n                              \"typeString\": \"mapping(address => struct Staking.Locked storage ref)\"\n                            }\n                          },\n                          \"id\": 4576,\n                          \"indexExpression\": {\n                            \"argumentTypes\": null,\n                            \"id\": 4575,\n                            \"name\": \"forAddress\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 4568,\n                            \"src\": \"18171:10:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_address\",\n                              \"typeString\": \"address\"\n                            }\n                          },\n                          \"isConstant\": false,\n                          \"isLValue\": true,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"nodeType\": \"IndexAccess\",\n                          \"src\": \"18163:19:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_struct$_Locked_$3659_storage\",\n                            \"typeString\": \"struct Staking.Locked storage ref\"\n                          }\n                        },\n                        \"id\": 4577,\n                        \"isConstant\": false,\n                        \"isLValue\": true,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"memberName\": \"assets\",\n                        \"nodeType\": \"MemberAccess\",\n                        \"referencedDeclaration\": 3658,\n                        \"src\": \"18163:26:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_array$_t_struct$_LockedAsset_$3653_storage_$dyn_storage\",\n                          \"typeString\": \"struct Staking.LockedAsset storage ref[] storage ref\"\n                        }\n                      },\n                      \"id\": 4578,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"memberName\": \"length\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": null,\n                      \"src\": \"18163:33:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"src\": \"18154:42:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"id\": 4580,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"18154:42:6\"\n                }\n              ]\n            },\n            \"documentation\": null,\n            \"functionSelector\": \"40e97903\",\n            \"id\": 4582,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [],\n            \"name\": \"getNumberOfLockedAssetsForUser\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 4569,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 4568,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"forAddress\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4582,\n                  \"src\": \"18086:18:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_address\",\n                    \"typeString\": \"address\"\n                  },\n                  \"typeName\": {\n                    \"id\": 4567,\n                    \"name\": \"address\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"18086:7:6\",\n                    \"stateMutability\": \"nonpayable\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address\",\n                      \"typeString\": \"address\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"18085:20:6\"\n            },\n            \"returnParameters\": {\n              \"id\": 4572,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 4571,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"length\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4582,\n                  \"src\": \"18128:14:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 4570,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"18128:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"18127:16:6\"\n            },\n            \"scope\": 5490,\n            \"src\": \"18046:157:6\",\n            \"stateMutability\": \"view\",\n            \"virtual\": false,\n            \"visibility\": \"external\"\n          },\n          {\n            \"body\": {\n              \"id\": 4606,\n              \"nodeType\": \"Block\",\n              \"src\": \"18338:147:6\",\n              \"statements\": [\n                {\n                  \"assignments\": [\n                    4594\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 4594,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"aggregate\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 4606,\n                      \"src\": \"18348:32:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"storage\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                        \"typeString\": \"struct AssetLib.Asset\"\n                      },\n                      \"typeName\": {\n                        \"contractScope\": null,\n                        \"id\": 4593,\n                        \"name\": \"AssetLib.Asset\",\n                        \"nodeType\": \"UserDefinedTypeName\",\n                        \"referencedDeclaration\": 2788,\n                        \"src\": \"18348:14:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                          \"typeString\": \"struct AssetLib.Asset\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 4599,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"expression\": {\n                      \"argumentTypes\": null,\n                      \"baseExpression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 4595,\n                        \"name\": \"_locked\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 3792,\n                        \"src\": \"18383:7:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_mapping$_t_address_$_t_struct$_Locked_$3659_storage_$\",\n                          \"typeString\": \"mapping(address => struct Staking.Locked storage ref)\"\n                        }\n                      },\n                      \"id\": 4597,\n                      \"indexExpression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 4596,\n                        \"name\": \"forAddress\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4584,\n                        \"src\": \"18391:10:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        }\n                      },\n                      \"isConstant\": false,\n                      \"isLValue\": true,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"nodeType\": \"IndexAccess\",\n                      \"src\": \"18383:19:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_struct$_Locked_$3659_storage\",\n                        \"typeString\": \"struct Staking.Locked storage ref\"\n                      }\n                    },\n                    \"id\": 4598,\n                    \"isConstant\": false,\n                    \"isLValue\": true,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"memberName\": \"aggregate\",\n                    \"nodeType\": \"MemberAccess\",\n                    \"referencedDeclaration\": 3655,\n                    \"src\": \"18383:29:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                      \"typeString\": \"struct AssetLib.Asset storage ref\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"18348:64:6\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"components\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 4600,\n                          \"name\": \"aggregate\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 4594,\n                          \"src\": \"18430:9:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                            \"typeString\": \"struct AssetLib.Asset storage pointer\"\n                          }\n                        },\n                        \"id\": 4601,\n                        \"isConstant\": false,\n                        \"isLValue\": true,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"memberName\": \"principal\",\n                        \"nodeType\": \"MemberAccess\",\n                        \"referencedDeclaration\": 2785,\n                        \"src\": \"18430:19:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 4602,\n                          \"name\": \"aggregate\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 4594,\n                          \"src\": \"18451:9:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                            \"typeString\": \"struct AssetLib.Asset storage pointer\"\n                          }\n                        },\n                        \"id\": 4603,\n                        \"isConstant\": false,\n                        \"isLValue\": true,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"memberName\": \"compoundInterest\",\n                        \"nodeType\": \"MemberAccess\",\n                        \"referencedDeclaration\": 2787,\n                        \"src\": \"18451:26:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"id\": 4604,\n                    \"isConstant\": false,\n                    \"isInlineArray\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"nodeType\": \"TupleExpression\",\n                    \"src\": \"18429:49:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$_t_uint256_$_t_uint256_$\",\n                      \"typeString\": \"tuple(uint256,uint256)\"\n                    }\n                  },\n                  \"functionReturnParameters\": 4590,\n                  \"id\": 4605,\n                  \"nodeType\": \"Return\",\n                  \"src\": \"18422:56:6\"\n                }\n              ]\n            },\n            \"documentation\": null,\n            \"functionSelector\": \"a8f1b4c4\",\n            \"id\": 4607,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [],\n            \"name\": \"getLockedAssetsAggregateForUser\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 4585,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 4584,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"forAddress\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4607,\n                  \"src\": \"18251:18:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_address\",\n                    \"typeString\": \"address\"\n                  },\n                  \"typeName\": {\n                    \"id\": 4583,\n                    \"name\": \"address\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"18251:7:6\",\n                    \"stateMutability\": \"nonpayable\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address\",\n                      \"typeString\": \"address\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"18250:20:6\"\n            },\n            \"returnParameters\": {\n              \"id\": 4590,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 4587,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"principal\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4607,\n                  \"src\": \"18293:17:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 4586,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"18293:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 4589,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"compoundInterest\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4607,\n                  \"src\": \"18312:24:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 4588,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"18312:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"18292:45:6\"\n            },\n            \"scope\": 5490,\n            \"src\": \"18210:275:6\",\n            \"stateMutability\": \"view\",\n            \"virtual\": false,\n            \"visibility\": \"external\"\n          },\n          {\n            \"body\": {\n              \"id\": 4711,\n              \"nodeType\": \"Block\",\n              \"src\": \"18915:654:6\",\n              \"statements\": [\n                {\n                  \"assignments\": [\n                    4625\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 4625,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"lockedAssets\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 4711,\n                      \"src\": \"18925:34:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"storage\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_array$_t_struct$_LockedAsset_$3653_storage_$dyn_storage_ptr\",\n                        \"typeString\": \"struct Staking.LockedAsset[]\"\n                      },\n                      \"typeName\": {\n                        \"baseType\": {\n                          \"contractScope\": null,\n                          \"id\": 4623,\n                          \"name\": \"LockedAsset\",\n                          \"nodeType\": \"UserDefinedTypeName\",\n                          \"referencedDeclaration\": 3653,\n                          \"src\": \"18925:11:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_struct$_LockedAsset_$3653_storage_ptr\",\n                            \"typeString\": \"struct Staking.LockedAsset\"\n                          }\n                        },\n                        \"id\": 4624,\n                        \"length\": null,\n                        \"nodeType\": \"ArrayTypeName\",\n                        \"src\": \"18925:13:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_array$_t_struct$_LockedAsset_$3653_storage_$dyn_storage_ptr\",\n                          \"typeString\": \"struct Staking.LockedAsset[]\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 4630,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"expression\": {\n                      \"argumentTypes\": null,\n                      \"baseExpression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 4626,\n                        \"name\": \"_locked\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 3792,\n                        \"src\": \"18962:7:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_mapping$_t_address_$_t_struct$_Locked_$3659_storage_$\",\n                          \"typeString\": \"mapping(address => struct Staking.Locked storage ref)\"\n                        }\n                      },\n                      \"id\": 4628,\n                      \"indexExpression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 4627,\n                        \"name\": \"forAddress\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4610,\n                        \"src\": \"18970:10:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        }\n                      },\n                      \"isConstant\": false,\n                      \"isLValue\": true,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"nodeType\": \"IndexAccess\",\n                      \"src\": \"18962:19:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_struct$_Locked_$3659_storage\",\n                        \"typeString\": \"struct Staking.Locked storage ref\"\n                      }\n                    },\n                    \"id\": 4629,\n                    \"isConstant\": false,\n                    \"isLValue\": true,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"memberName\": \"assets\",\n                    \"nodeType\": \"MemberAccess\",\n                    \"referencedDeclaration\": 3658,\n                    \"src\": \"18962:26:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_array$_t_struct$_LockedAsset_$3653_storage_$dyn_storage\",\n                      \"typeString\": \"struct Staking.LockedAsset storage ref[] storage ref\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"18925:63:6\"\n                },\n                {\n                  \"assignments\": [\n                    4632\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 4632,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"length\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 4711,\n                      \"src\": \"18998:14:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"default\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      },\n                      \"typeName\": {\n                        \"id\": 4631,\n                        \"name\": \"uint256\",\n                        \"nodeType\": \"ElementaryTypeName\",\n                        \"src\": \"18998:7:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 4635,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"expression\": {\n                      \"argumentTypes\": null,\n                      \"id\": 4633,\n                      \"name\": \"lockedAssets\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 4625,\n                      \"src\": \"19015:12:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_array$_t_struct$_LockedAsset_$3653_storage_$dyn_storage_ptr\",\n                        \"typeString\": \"struct Staking.LockedAsset storage ref[] storage pointer\"\n                      }\n                    },\n                    \"id\": 4634,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"memberName\": \"length\",\n                    \"nodeType\": \"MemberAccess\",\n                    \"referencedDeclaration\": null,\n                    \"src\": \"19015:19:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"18998:36:6\"\n                },\n                {\n                  \"condition\": {\n                    \"argumentTypes\": null,\n                    \"commonType\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    },\n                    \"id\": 4638,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftExpression\": {\n                      \"argumentTypes\": null,\n                      \"id\": 4636,\n                      \"name\": \"length\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 4632,\n                      \"src\": \"19048:6:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"BinaryOperation\",\n                    \"operator\": \"!=\",\n                    \"rightExpression\": {\n                      \"argumentTypes\": null,\n                      \"hexValue\": \"30\",\n                      \"id\": 4637,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": true,\n                      \"kind\": \"number\",\n                      \"lValueRequested\": false,\n                      \"nodeType\": \"Literal\",\n                      \"src\": \"19058:1:6\",\n                      \"subdenomination\": null,\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_rational_0_by_1\",\n                        \"typeString\": \"int_const 0\"\n                      },\n                      \"value\": \"0\"\n                    },\n                    \"src\": \"19048:11:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_bool\",\n                      \"typeString\": \"bool\"\n                    }\n                  },\n                  \"falseBody\": null,\n                  \"id\": 4710,\n                  \"nodeType\": \"IfStatement\",\n                  \"src\": \"19044:519:6\",\n                  \"trueBody\": {\n                    \"id\": 4709,\n                    \"nodeType\": \"Block\",\n                    \"src\": \"19061:502:6\",\n                    \"statements\": [\n                      {\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 4645,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"leftHandSide\": {\n                            \"argumentTypes\": null,\n                            \"id\": 4639,\n                            \"name\": \"principal\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 4614,\n                            \"src\": \"19075:9:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_array$_t_uint256_$dyn_memory_ptr\",\n                              \"typeString\": \"uint256[] memory\"\n                            }\n                          },\n                          \"nodeType\": \"Assignment\",\n                          \"operator\": \"=\",\n                          \"rightHandSide\": {\n                            \"argumentTypes\": null,\n                            \"arguments\": [\n                              {\n                                \"argumentTypes\": null,\n                                \"id\": 4643,\n                                \"name\": \"length\",\n                                \"nodeType\": \"Identifier\",\n                                \"overloadedDeclarations\": [],\n                                \"referencedDeclaration\": 4632,\n                                \"src\": \"19101:6:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              }\n                            ],\n                            \"expression\": {\n                              \"argumentTypes\": [\n                                {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              ],\n                              \"id\": 4642,\n                              \"isConstant\": false,\n                              \"isLValue\": false,\n                              \"isPure\": true,\n                              \"lValueRequested\": false,\n                              \"nodeType\": \"NewExpression\",\n                              \"src\": \"19087:13:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_function_objectcreation_pure$_t_uint256_$returns$_t_array$_t_uint256_$dyn_memory_ptr_$\",\n                                \"typeString\": \"function (uint256) pure returns (uint256[] memory)\"\n                              },\n                              \"typeName\": {\n                                \"baseType\": {\n                                  \"id\": 4640,\n                                  \"name\": \"uint256\",\n                                  \"nodeType\": \"ElementaryTypeName\",\n                                  \"src\": \"19091:7:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_uint256\",\n                                    \"typeString\": \"uint256\"\n                                  }\n                                },\n                                \"id\": 4641,\n                                \"length\": null,\n                                \"nodeType\": \"ArrayTypeName\",\n                                \"src\": \"19091:9:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_array$_t_uint256_$dyn_storage_ptr\",\n                                  \"typeString\": \"uint256[]\"\n                                }\n                              }\n                            },\n                            \"id\": 4644,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": false,\n                            \"kind\": \"functionCall\",\n                            \"lValueRequested\": false,\n                            \"names\": [],\n                            \"nodeType\": \"FunctionCall\",\n                            \"src\": \"19087:21:6\",\n                            \"tryCall\": false,\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_array$_t_uint256_$dyn_memory_ptr\",\n                              \"typeString\": \"uint256[] memory\"\n                            }\n                          },\n                          \"src\": \"19075:33:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_array$_t_uint256_$dyn_memory_ptr\",\n                            \"typeString\": \"uint256[] memory\"\n                          }\n                        },\n                        \"id\": 4646,\n                        \"nodeType\": \"ExpressionStatement\",\n                        \"src\": \"19075:33:6\"\n                      },\n                      {\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 4653,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"leftHandSide\": {\n                            \"argumentTypes\": null,\n                            \"id\": 4647,\n                            \"name\": \"compoundInterest\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 4617,\n                            \"src\": \"19122:16:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_array$_t_uint256_$dyn_memory_ptr\",\n                              \"typeString\": \"uint256[] memory\"\n                            }\n                          },\n                          \"nodeType\": \"Assignment\",\n                          \"operator\": \"=\",\n                          \"rightHandSide\": {\n                            \"argumentTypes\": null,\n                            \"arguments\": [\n                              {\n                                \"argumentTypes\": null,\n                                \"id\": 4651,\n                                \"name\": \"length\",\n                                \"nodeType\": \"Identifier\",\n                                \"overloadedDeclarations\": [],\n                                \"referencedDeclaration\": 4632,\n                                \"src\": \"19155:6:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              }\n                            ],\n                            \"expression\": {\n                              \"argumentTypes\": [\n                                {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              ],\n                              \"id\": 4650,\n                              \"isConstant\": false,\n                              \"isLValue\": false,\n                              \"isPure\": true,\n                              \"lValueRequested\": false,\n                              \"nodeType\": \"NewExpression\",\n                              \"src\": \"19141:13:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_function_objectcreation_pure$_t_uint256_$returns$_t_array$_t_uint256_$dyn_memory_ptr_$\",\n                                \"typeString\": \"function (uint256) pure returns (uint256[] memory)\"\n                              },\n                              \"typeName\": {\n                                \"baseType\": {\n                                  \"id\": 4648,\n                                  \"name\": \"uint256\",\n                                  \"nodeType\": \"ElementaryTypeName\",\n                                  \"src\": \"19145:7:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_uint256\",\n                                    \"typeString\": \"uint256\"\n                                  }\n                                },\n                                \"id\": 4649,\n                                \"length\": null,\n                                \"nodeType\": \"ArrayTypeName\",\n                                \"src\": \"19145:9:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_array$_t_uint256_$dyn_storage_ptr\",\n                                  \"typeString\": \"uint256[]\"\n                                }\n                              }\n                            },\n                            \"id\": 4652,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": false,\n                            \"kind\": \"functionCall\",\n                            \"lValueRequested\": false,\n                            \"names\": [],\n                            \"nodeType\": \"FunctionCall\",\n                            \"src\": \"19141:21:6\",\n                            \"tryCall\": false,\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_array$_t_uint256_$dyn_memory_ptr\",\n                              \"typeString\": \"uint256[] memory\"\n                            }\n                          },\n                          \"src\": \"19122:40:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_array$_t_uint256_$dyn_memory_ptr\",\n                            \"typeString\": \"uint256[] memory\"\n                          }\n                        },\n                        \"id\": 4654,\n                        \"nodeType\": \"ExpressionStatement\",\n                        \"src\": \"19122:40:6\"\n                      },\n                      {\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 4661,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"leftHandSide\": {\n                            \"argumentTypes\": null,\n                            \"id\": 4655,\n                            \"name\": \"liquidSinceBlock\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 4620,\n                            \"src\": \"19176:16:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_array$_t_uint256_$dyn_memory_ptr\",\n                              \"typeString\": \"uint256[] memory\"\n                            }\n                          },\n                          \"nodeType\": \"Assignment\",\n                          \"operator\": \"=\",\n                          \"rightHandSide\": {\n                            \"argumentTypes\": null,\n                            \"arguments\": [\n                              {\n                                \"argumentTypes\": null,\n                                \"id\": 4659,\n                                \"name\": \"length\",\n                                \"nodeType\": \"Identifier\",\n                                \"overloadedDeclarations\": [],\n                                \"referencedDeclaration\": 4632,\n                                \"src\": \"19209:6:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              }\n                            ],\n                            \"expression\": {\n                              \"argumentTypes\": [\n                                {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              ],\n                              \"id\": 4658,\n                              \"isConstant\": false,\n                              \"isLValue\": false,\n                              \"isPure\": true,\n                              \"lValueRequested\": false,\n                              \"nodeType\": \"NewExpression\",\n                              \"src\": \"19195:13:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_function_objectcreation_pure$_t_uint256_$returns$_t_array$_t_uint256_$dyn_memory_ptr_$\",\n                                \"typeString\": \"function (uint256) pure returns (uint256[] memory)\"\n                              },\n                              \"typeName\": {\n                                \"baseType\": {\n                                  \"id\": 4656,\n                                  \"name\": \"uint256\",\n                                  \"nodeType\": \"ElementaryTypeName\",\n                                  \"src\": \"19199:7:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_uint256\",\n                                    \"typeString\": \"uint256\"\n                                  }\n                                },\n                                \"id\": 4657,\n                                \"length\": null,\n                                \"nodeType\": \"ArrayTypeName\",\n                                \"src\": \"19199:9:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_array$_t_uint256_$dyn_storage_ptr\",\n                                  \"typeString\": \"uint256[]\"\n                                }\n                              }\n                            },\n                            \"id\": 4660,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": false,\n                            \"kind\": \"functionCall\",\n                            \"lValueRequested\": false,\n                            \"names\": [],\n                            \"nodeType\": \"FunctionCall\",\n                            \"src\": \"19195:21:6\",\n                            \"tryCall\": false,\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_array$_t_uint256_$dyn_memory_ptr\",\n                              \"typeString\": \"uint256[] memory\"\n                            }\n                          },\n                          \"src\": \"19176:40:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_array$_t_uint256_$dyn_memory_ptr\",\n                            \"typeString\": \"uint256[] memory\"\n                          }\n                        },\n                        \"id\": 4662,\n                        \"nodeType\": \"ExpressionStatement\",\n                        \"src\": \"19176:40:6\"\n                      },\n                      {\n                        \"body\": {\n                          \"id\": 4707,\n                          \"nodeType\": \"Block\",\n                          \"src\": \"19266:287:6\",\n                          \"statements\": [\n                            {\n                              \"assignments\": [\n                                4674\n                              ],\n                              \"declarations\": [\n                                {\n                                  \"constant\": false,\n                                  \"id\": 4674,\n                                  \"mutability\": \"mutable\",\n                                  \"name\": \"la\",\n                                  \"nodeType\": \"VariableDeclaration\",\n                                  \"overrides\": null,\n                                  \"scope\": 4707,\n                                  \"src\": \"19284:22:6\",\n                                  \"stateVariable\": false,\n                                  \"storageLocation\": \"storage\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_struct$_LockedAsset_$3653_storage_ptr\",\n                                    \"typeString\": \"struct Staking.LockedAsset\"\n                                  },\n                                  \"typeName\": {\n                                    \"contractScope\": null,\n                                    \"id\": 4673,\n                                    \"name\": \"LockedAsset\",\n                                    \"nodeType\": \"UserDefinedTypeName\",\n                                    \"referencedDeclaration\": 3653,\n                                    \"src\": \"19284:11:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_struct$_LockedAsset_$3653_storage_ptr\",\n                                      \"typeString\": \"struct Staking.LockedAsset\"\n                                    }\n                                  },\n                                  \"value\": null,\n                                  \"visibility\": \"internal\"\n                                }\n                              ],\n                              \"id\": 4678,\n                              \"initialValue\": {\n                                \"argumentTypes\": null,\n                                \"baseExpression\": {\n                                  \"argumentTypes\": null,\n                                  \"id\": 4675,\n                                  \"name\": \"lockedAssets\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 4625,\n                                  \"src\": \"19309:12:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_array$_t_struct$_LockedAsset_$3653_storage_$dyn_storage_ptr\",\n                                    \"typeString\": \"struct Staking.LockedAsset storage ref[] storage pointer\"\n                                  }\n                                },\n                                \"id\": 4677,\n                                \"indexExpression\": {\n                                  \"argumentTypes\": null,\n                                  \"id\": 4676,\n                                  \"name\": \"i\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 4664,\n                                  \"src\": \"19322:1:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_uint256\",\n                                    \"typeString\": \"uint256\"\n                                  }\n                                },\n                                \"isConstant\": false,\n                                \"isLValue\": true,\n                                \"isPure\": false,\n                                \"lValueRequested\": false,\n                                \"nodeType\": \"IndexAccess\",\n                                \"src\": \"19309:15:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_struct$_LockedAsset_$3653_storage\",\n                                  \"typeString\": \"struct Staking.LockedAsset storage ref\"\n                                }\n                              },\n                              \"nodeType\": \"VariableDeclarationStatement\",\n                              \"src\": \"19284:40:6\"\n                            },\n                            {\n                              \"assignments\": [\n                                4682\n                              ],\n                              \"declarations\": [\n                                {\n                                  \"constant\": false,\n                                  \"id\": 4682,\n                                  \"mutability\": \"mutable\",\n                                  \"name\": \"a\",\n                                  \"nodeType\": \"VariableDeclaration\",\n                                  \"overrides\": null,\n                                  \"scope\": 4707,\n                                  \"src\": \"19342:24:6\",\n                                  \"stateVariable\": false,\n                                  \"storageLocation\": \"storage\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                                    \"typeString\": \"struct AssetLib.Asset\"\n                                  },\n                                  \"typeName\": {\n                                    \"contractScope\": null,\n                                    \"id\": 4681,\n                                    \"name\": \"AssetLib.Asset\",\n                                    \"nodeType\": \"UserDefinedTypeName\",\n                                    \"referencedDeclaration\": 2788,\n                                    \"src\": \"19342:14:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                                      \"typeString\": \"struct AssetLib.Asset\"\n                                    }\n                                  },\n                                  \"value\": null,\n                                  \"visibility\": \"internal\"\n                                }\n                              ],\n                              \"id\": 4685,\n                              \"initialValue\": {\n                                \"argumentTypes\": null,\n                                \"expression\": {\n                                  \"argumentTypes\": null,\n                                  \"id\": 4683,\n                                  \"name\": \"la\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 4674,\n                                  \"src\": \"19369:2:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_struct$_LockedAsset_$3653_storage_ptr\",\n                                    \"typeString\": \"struct Staking.LockedAsset storage pointer\"\n                                  }\n                                },\n                                \"id\": 4684,\n                                \"isConstant\": false,\n                                \"isLValue\": true,\n                                \"isPure\": false,\n                                \"lValueRequested\": false,\n                                \"memberName\": \"asset\",\n                                \"nodeType\": \"MemberAccess\",\n                                \"referencedDeclaration\": 3652,\n                                \"src\": \"19369:8:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                                  \"typeString\": \"struct AssetLib.Asset storage ref\"\n                                }\n                              },\n                              \"nodeType\": \"VariableDeclarationStatement\",\n                              \"src\": \"19342:35:6\"\n                            },\n                            {\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"id\": 4691,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": false,\n                                \"lValueRequested\": false,\n                                \"leftHandSide\": {\n                                  \"argumentTypes\": null,\n                                  \"baseExpression\": {\n                                    \"argumentTypes\": null,\n                                    \"id\": 4686,\n                                    \"name\": \"principal\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 4614,\n                                    \"src\": \"19395:9:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_array$_t_uint256_$dyn_memory_ptr\",\n                                      \"typeString\": \"uint256[] memory\"\n                                    }\n                                  },\n                                  \"id\": 4688,\n                                  \"indexExpression\": {\n                                    \"argumentTypes\": null,\n                                    \"id\": 4687,\n                                    \"name\": \"i\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 4664,\n                                    \"src\": \"19405:1:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    }\n                                  },\n                                  \"isConstant\": false,\n                                  \"isLValue\": true,\n                                  \"isPure\": false,\n                                  \"lValueRequested\": true,\n                                  \"nodeType\": \"IndexAccess\",\n                                  \"src\": \"19395:12:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_uint256\",\n                                    \"typeString\": \"uint256\"\n                                  }\n                                },\n                                \"nodeType\": \"Assignment\",\n                                \"operator\": \"=\",\n                                \"rightHandSide\": {\n                                  \"argumentTypes\": null,\n                                  \"expression\": {\n                                    \"argumentTypes\": null,\n                                    \"id\": 4689,\n                                    \"name\": \"a\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 4682,\n                                    \"src\": \"19410:1:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                                      \"typeString\": \"struct AssetLib.Asset storage pointer\"\n                                    }\n                                  },\n                                  \"id\": 4690,\n                                  \"isConstant\": false,\n                                  \"isLValue\": true,\n                                  \"isPure\": false,\n                                  \"lValueRequested\": false,\n                                  \"memberName\": \"principal\",\n                                  \"nodeType\": \"MemberAccess\",\n                                  \"referencedDeclaration\": 2785,\n                                  \"src\": \"19410:11:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_uint256\",\n                                    \"typeString\": \"uint256\"\n                                  }\n                                },\n                                \"src\": \"19395:26:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              },\n                              \"id\": 4692,\n                              \"nodeType\": \"ExpressionStatement\",\n                              \"src\": \"19395:26:6\"\n                            },\n                            {\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"id\": 4698,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": false,\n                                \"lValueRequested\": false,\n                                \"leftHandSide\": {\n                                  \"argumentTypes\": null,\n                                  \"baseExpression\": {\n                                    \"argumentTypes\": null,\n                                    \"id\": 4693,\n                                    \"name\": \"compoundInterest\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 4617,\n                                    \"src\": \"19439:16:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_array$_t_uint256_$dyn_memory_ptr\",\n                                      \"typeString\": \"uint256[] memory\"\n                                    }\n                                  },\n                                  \"id\": 4695,\n                                  \"indexExpression\": {\n                                    \"argumentTypes\": null,\n                                    \"id\": 4694,\n                                    \"name\": \"i\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 4664,\n                                    \"src\": \"19456:1:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    }\n                                  },\n                                  \"isConstant\": false,\n                                  \"isLValue\": true,\n                                  \"isPure\": false,\n                                  \"lValueRequested\": true,\n                                  \"nodeType\": \"IndexAccess\",\n                                  \"src\": \"19439:19:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_uint256\",\n                                    \"typeString\": \"uint256\"\n                                  }\n                                },\n                                \"nodeType\": \"Assignment\",\n                                \"operator\": \"=\",\n                                \"rightHandSide\": {\n                                  \"argumentTypes\": null,\n                                  \"expression\": {\n                                    \"argumentTypes\": null,\n                                    \"id\": 4696,\n                                    \"name\": \"a\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 4682,\n                                    \"src\": \"19461:1:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                                      \"typeString\": \"struct AssetLib.Asset storage pointer\"\n                                    }\n                                  },\n                                  \"id\": 4697,\n                                  \"isConstant\": false,\n                                  \"isLValue\": true,\n                                  \"isPure\": false,\n                                  \"lValueRequested\": false,\n                                  \"memberName\": \"compoundInterest\",\n                                  \"nodeType\": \"MemberAccess\",\n                                  \"referencedDeclaration\": 2787,\n                                  \"src\": \"19461:18:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_uint256\",\n                                    \"typeString\": \"uint256\"\n                                  }\n                                },\n                                \"src\": \"19439:40:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              },\n                              \"id\": 4699,\n                              \"nodeType\": \"ExpressionStatement\",\n                              \"src\": \"19439:40:6\"\n                            },\n                            {\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"id\": 4705,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": false,\n                                \"lValueRequested\": false,\n                                \"leftHandSide\": {\n                                  \"argumentTypes\": null,\n                                  \"baseExpression\": {\n                                    \"argumentTypes\": null,\n                                    \"id\": 4700,\n                                    \"name\": \"liquidSinceBlock\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 4620,\n                                    \"src\": \"19497:16:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_array$_t_uint256_$dyn_memory_ptr\",\n                                      \"typeString\": \"uint256[] memory\"\n                                    }\n                                  },\n                                  \"id\": 4702,\n                                  \"indexExpression\": {\n                                    \"argumentTypes\": null,\n                                    \"id\": 4701,\n                                    \"name\": \"i\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 4664,\n                                    \"src\": \"19514:1:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    }\n                                  },\n                                  \"isConstant\": false,\n                                  \"isLValue\": true,\n                                  \"isPure\": false,\n                                  \"lValueRequested\": true,\n                                  \"nodeType\": \"IndexAccess\",\n                                  \"src\": \"19497:19:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_uint256\",\n                                    \"typeString\": \"uint256\"\n                                  }\n                                },\n                                \"nodeType\": \"Assignment\",\n                                \"operator\": \"=\",\n                                \"rightHandSide\": {\n                                  \"argumentTypes\": null,\n                                  \"expression\": {\n                                    \"argumentTypes\": null,\n                                    \"id\": 4703,\n                                    \"name\": \"la\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 4674,\n                                    \"src\": \"19519:2:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_struct$_LockedAsset_$3653_storage_ptr\",\n                                      \"typeString\": \"struct Staking.LockedAsset storage pointer\"\n                                    }\n                                  },\n                                  \"id\": 4704,\n                                  \"isConstant\": false,\n                                  \"isLValue\": true,\n                                  \"isPure\": false,\n                                  \"lValueRequested\": false,\n                                  \"memberName\": \"liquidSinceBlock\",\n                                  \"nodeType\": \"MemberAccess\",\n                                  \"referencedDeclaration\": 3650,\n                                  \"src\": \"19519:19:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_uint256\",\n                                    \"typeString\": \"uint256\"\n                                  }\n                                },\n                                \"src\": \"19497:41:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              },\n                              \"id\": 4706,\n                              \"nodeType\": \"ExpressionStatement\",\n                              \"src\": \"19497:41:6\"\n                            }\n                          ]\n                        },\n                        \"condition\": {\n                          \"argumentTypes\": null,\n                          \"commonType\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          },\n                          \"id\": 4669,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"leftExpression\": {\n                            \"argumentTypes\": null,\n                            \"id\": 4667,\n                            \"name\": \"i\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 4664,\n                            \"src\": \"19249:1:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"nodeType\": \"BinaryOperation\",\n                          \"operator\": \"<\",\n                          \"rightExpression\": {\n                            \"argumentTypes\": null,\n                            \"id\": 4668,\n                            \"name\": \"length\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 4632,\n                            \"src\": \"19253:6:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"src\": \"19249:10:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_bool\",\n                            \"typeString\": \"bool\"\n                          }\n                        },\n                        \"id\": 4708,\n                        \"initializationExpression\": {\n                          \"assignments\": [\n                            4664\n                          ],\n                          \"declarations\": [\n                            {\n                              \"constant\": false,\n                              \"id\": 4664,\n                              \"mutability\": \"mutable\",\n                              \"name\": \"i\",\n                              \"nodeType\": \"VariableDeclaration\",\n                              \"overrides\": null,\n                              \"scope\": 4708,\n                              \"src\": \"19236:9:6\",\n                              \"stateVariable\": false,\n                              \"storageLocation\": \"default\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_uint256\",\n                                \"typeString\": \"uint256\"\n                              },\n                              \"typeName\": {\n                                \"id\": 4663,\n                                \"name\": \"uint256\",\n                                \"nodeType\": \"ElementaryTypeName\",\n                                \"src\": \"19236:7:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              },\n                              \"value\": null,\n                              \"visibility\": \"internal\"\n                            }\n                          ],\n                          \"id\": 4666,\n                          \"initialValue\": {\n                            \"argumentTypes\": null,\n                            \"hexValue\": \"30\",\n                            \"id\": 4665,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": true,\n                            \"kind\": \"number\",\n                            \"lValueRequested\": false,\n                            \"nodeType\": \"Literal\",\n                            \"src\": \"19246:1:6\",\n                            \"subdenomination\": null,\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_rational_0_by_1\",\n                              \"typeString\": \"int_const 0\"\n                            },\n                            \"value\": \"0\"\n                          },\n                          \"nodeType\": \"VariableDeclarationStatement\",\n                          \"src\": \"19236:11:6\"\n                        },\n                        \"loopExpression\": {\n                          \"expression\": {\n                            \"argumentTypes\": null,\n                            \"id\": 4671,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": false,\n                            \"lValueRequested\": false,\n                            \"nodeType\": \"UnaryOperation\",\n                            \"operator\": \"++\",\n                            \"prefix\": true,\n                            \"src\": \"19261:3:6\",\n                            \"subExpression\": {\n                              \"argumentTypes\": null,\n                              \"id\": 4670,\n                              \"name\": \"i\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 4664,\n                              \"src\": \"19263:1:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_uint256\",\n                                \"typeString\": \"uint256\"\n                              }\n                            },\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"id\": 4672,\n                          \"nodeType\": \"ExpressionStatement\",\n                          \"src\": \"19261:3:6\"\n                        },\n                        \"nodeType\": \"ForStatement\",\n                        \"src\": \"19231:322:6\"\n                      }\n                    ]\n                  }\n                }\n              ]\n            },\n            \"documentation\": {\n              \"id\": 4608,\n              \"nodeType\": \"StructuredDocumentation\",\n              \"src\": \"18492:226:6\",\n              \"text\": \"@dev Returns locked assets decomposed in to 3 separate arrays (principal, compound interest, liquid since block)\\n     NOTE(pb): This method might be quite expensive, depending on size of locked assets\"\n            },\n            \"functionSelector\": \"5f208f34\",\n            \"id\": 4712,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [],\n            \"name\": \"getLockedAssetsForUser\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 4611,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 4610,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"forAddress\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4712,\n                  \"src\": \"18755:18:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_address\",\n                    \"typeString\": \"address\"\n                  },\n                  \"typeName\": {\n                    \"id\": 4609,\n                    \"name\": \"address\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"18755:7:6\",\n                    \"stateMutability\": \"nonpayable\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address\",\n                      \"typeString\": \"address\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"18754:20:6\"\n            },\n            \"returnParameters\": {\n              \"id\": 4621,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 4614,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"principal\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4712,\n                  \"src\": \"18813:26:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"memory\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_array$_t_uint256_$dyn_memory_ptr\",\n                    \"typeString\": \"uint256[]\"\n                  },\n                  \"typeName\": {\n                    \"baseType\": {\n                      \"id\": 4612,\n                      \"name\": \"uint256\",\n                      \"nodeType\": \"ElementaryTypeName\",\n                      \"src\": \"18813:7:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"id\": 4613,\n                    \"length\": null,\n                    \"nodeType\": \"ArrayTypeName\",\n                    \"src\": \"18813:9:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_array$_t_uint256_$dyn_storage_ptr\",\n                      \"typeString\": \"uint256[]\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 4617,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"compoundInterest\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4712,\n                  \"src\": \"18841:33:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"memory\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_array$_t_uint256_$dyn_memory_ptr\",\n                    \"typeString\": \"uint256[]\"\n                  },\n                  \"typeName\": {\n                    \"baseType\": {\n                      \"id\": 4615,\n                      \"name\": \"uint256\",\n                      \"nodeType\": \"ElementaryTypeName\",\n                      \"src\": \"18841:7:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"id\": 4616,\n                    \"length\": null,\n                    \"nodeType\": \"ArrayTypeName\",\n                    \"src\": \"18841:9:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_array$_t_uint256_$dyn_storage_ptr\",\n                      \"typeString\": \"uint256[]\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 4620,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"liquidSinceBlock\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4712,\n                  \"src\": \"18876:33:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"memory\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_array$_t_uint256_$dyn_memory_ptr\",\n                    \"typeString\": \"uint256[]\"\n                  },\n                  \"typeName\": {\n                    \"baseType\": {\n                      \"id\": 4618,\n                      \"name\": \"uint256\",\n                      \"nodeType\": \"ElementaryTypeName\",\n                      \"src\": \"18876:7:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"id\": 4619,\n                    \"length\": null,\n                    \"nodeType\": \"ArrayTypeName\",\n                    \"src\": \"18876:9:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_array$_t_uint256_$dyn_storage_ptr\",\n                      \"typeString\": \"uint256[]\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"18812:98:6\"\n            },\n            \"scope\": 5490,\n            \"src\": \"18723:846:6\",\n            \"stateMutability\": \"view\",\n            \"virtual\": false,\n            \"visibility\": \"external\"\n          },\n          {\n            \"body\": {\n              \"id\": 4753,\n              \"nodeType\": \"Block\",\n              \"src\": \"19740:260:6\",\n              \"statements\": [\n                {\n                  \"assignments\": [\n                    4726\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 4726,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"stake\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 4753,\n                      \"src\": \"19750:19:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"storage\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_struct$_Stake_$3648_storage_ptr\",\n                        \"typeString\": \"struct Staking.Stake\"\n                      },\n                      \"typeName\": {\n                        \"contractScope\": null,\n                        \"id\": 4725,\n                        \"name\": \"Stake\",\n                        \"nodeType\": \"UserDefinedTypeName\",\n                        \"referencedDeclaration\": 3648,\n                        \"src\": \"19750:5:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Stake_$3648_storage_ptr\",\n                          \"typeString\": \"struct Staking.Stake\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 4730,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"baseExpression\": {\n                      \"argumentTypes\": null,\n                      \"id\": 4727,\n                      \"name\": \"_stakes\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 3788,\n                      \"src\": \"19772:7:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_mapping$_t_address_$_t_struct$_Stake_$3648_storage_$\",\n                        \"typeString\": \"mapping(address => struct Staking.Stake storage ref)\"\n                      }\n                    },\n                    \"id\": 4729,\n                    \"indexExpression\": {\n                      \"argumentTypes\": null,\n                      \"id\": 4728,\n                      \"name\": \"forAddress\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 4714,\n                      \"src\": \"19780:10:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_address\",\n                        \"typeString\": \"address\"\n                      }\n                    },\n                    \"isConstant\": false,\n                    \"isLValue\": true,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"nodeType\": \"IndexAccess\",\n                    \"src\": \"19772:19:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_struct$_Stake_$3648_storage\",\n                      \"typeString\": \"struct Staking.Stake storage ref\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"19750:41:6\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 4735,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 4731,\n                      \"name\": \"principal\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 4717,\n                      \"src\": \"19801:9:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 4732,\n                          \"name\": \"stake\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 4726,\n                          \"src\": \"19813:5:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_struct$_Stake_$3648_storage_ptr\",\n                            \"typeString\": \"struct Staking.Stake storage pointer\"\n                          }\n                        },\n                        \"id\": 4733,\n                        \"isConstant\": false,\n                        \"isLValue\": true,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"memberName\": \"asset\",\n                        \"nodeType\": \"MemberAccess\",\n                        \"referencedDeclaration\": 3647,\n                        \"src\": \"19813:11:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                          \"typeString\": \"struct AssetLib.Asset storage ref\"\n                        }\n                      },\n                      \"id\": 4734,\n                      \"isConstant\": false,\n                      \"isLValue\": true,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"memberName\": \"principal\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": 2785,\n                      \"src\": \"19813:21:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"src\": \"19801:33:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"id\": 4736,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"19801:33:6\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 4741,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 4737,\n                      \"name\": \"compoundInterest\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 4719,\n                      \"src\": \"19844:16:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 4738,\n                          \"name\": \"stake\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 4726,\n                          \"src\": \"19863:5:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_struct$_Stake_$3648_storage_ptr\",\n                            \"typeString\": \"struct Staking.Stake storage pointer\"\n                          }\n                        },\n                        \"id\": 4739,\n                        \"isConstant\": false,\n                        \"isLValue\": true,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"memberName\": \"asset\",\n                        \"nodeType\": \"MemberAccess\",\n                        \"referencedDeclaration\": 3647,\n                        \"src\": \"19863:11:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                          \"typeString\": \"struct AssetLib.Asset storage ref\"\n                        }\n                      },\n                      \"id\": 4740,\n                      \"isConstant\": false,\n                      \"isLValue\": true,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"memberName\": \"compoundInterest\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": 2787,\n                      \"src\": \"19863:28:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"src\": \"19844:47:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"id\": 4742,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"19844:47:6\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 4746,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 4743,\n                      \"name\": \"sinceBlock\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 4721,\n                      \"src\": \"19901:10:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 4744,\n                        \"name\": \"stake\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4726,\n                        \"src\": \"19914:5:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Stake_$3648_storage_ptr\",\n                          \"typeString\": \"struct Staking.Stake storage pointer\"\n                        }\n                      },\n                      \"id\": 4745,\n                      \"isConstant\": false,\n                      \"isLValue\": true,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"memberName\": \"sinceBlock\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": 3643,\n                      \"src\": \"19914:16:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"src\": \"19901:29:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"id\": 4747,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"19901:29:6\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 4751,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 4748,\n                      \"name\": \"sinceInterestRateIndex\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 4723,\n                      \"src\": \"19940:22:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 4749,\n                        \"name\": \"stake\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4726,\n                        \"src\": \"19965:5:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Stake_$3648_storage_ptr\",\n                          \"typeString\": \"struct Staking.Stake storage pointer\"\n                        }\n                      },\n                      \"id\": 4750,\n                      \"isConstant\": false,\n                      \"isLValue\": true,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"memberName\": \"sinceInterestRateIndex\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": 3645,\n                      \"src\": \"19965:28:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"src\": \"19940:53:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"id\": 4752,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"19940:53:6\"\n                }\n              ]\n            },\n            \"documentation\": null,\n            \"functionSelector\": \"c30f75cf\",\n            \"id\": 4754,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [],\n            \"name\": \"getStakeForUser\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 4715,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 4714,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"forAddress\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4754,\n                  \"src\": \"19601:18:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_address\",\n                    \"typeString\": \"address\"\n                  },\n                  \"typeName\": {\n                    \"id\": 4713,\n                    \"name\": \"address\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"19601:7:6\",\n                    \"stateMutability\": \"nonpayable\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address\",\n                      \"typeString\": \"address\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"19600:20:6\"\n            },\n            \"returnParameters\": {\n              \"id\": 4724,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 4717,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"principal\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4754,\n                  \"src\": \"19643:17:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 4716,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"19643:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 4719,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"compoundInterest\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4754,\n                  \"src\": \"19662:24:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 4718,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"19662:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 4721,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"sinceBlock\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4754,\n                  \"src\": \"19688:18:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 4720,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"19688:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 4723,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"sinceInterestRateIndex\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4754,\n                  \"src\": \"19708:30:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 4722,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"19708:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"19642:97:6\"\n            },\n            \"scope\": 5490,\n            \"src\": \"19576:424:6\",\n            \"stateMutability\": \"view\",\n            \"virtual\": false,\n            \"visibility\": \"external\"\n          },\n          {\n            \"body\": {\n              \"id\": 4798,\n              \"nodeType\": \"Block\",\n              \"src\": \"20599:276:6\",\n              \"statements\": [\n                {\n                  \"condition\": {\n                    \"argumentTypes\": null,\n                    \"commonType\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    },\n                    \"id\": 4767,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftExpression\": {\n                      \"argumentTypes\": null,\n                      \"id\": 4765,\n                      \"name\": \"amount\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 4757,\n                      \"src\": \"20613:6:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"BinaryOperation\",\n                    \"operator\": \"==\",\n                    \"rightExpression\": {\n                      \"argumentTypes\": null,\n                      \"hexValue\": \"30\",\n                      \"id\": 4766,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": true,\n                      \"kind\": \"number\",\n                      \"lValueRequested\": false,\n                      \"nodeType\": \"Literal\",\n                      \"src\": \"20623:1:6\",\n                      \"subdenomination\": null,\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_rational_0_by_1\",\n                        \"typeString\": \"int_const 0\"\n                      },\n                      \"value\": \"0\"\n                    },\n                    \"src\": \"20613:11:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_bool\",\n                      \"typeString\": \"bool\"\n                    }\n                  },\n                  \"falseBody\": null,\n                  \"id\": 4770,\n                  \"nodeType\": \"IfStatement\",\n                  \"src\": \"20609:48:6\",\n                  \"trueBody\": {\n                    \"id\": 4769,\n                    \"nodeType\": \"Block\",\n                    \"src\": \"20626:31:6\",\n                    \"statements\": [\n                      {\n                        \"expression\": null,\n                        \"functionReturnParameters\": 4764,\n                        \"id\": 4768,\n                        \"nodeType\": \"Return\",\n                        \"src\": \"20640:7:6\"\n                      }\n                    ]\n                  }\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"arguments\": [\n                          {\n                            \"argumentTypes\": null,\n                            \"expression\": {\n                              \"argumentTypes\": null,\n                              \"id\": 4774,\n                              \"name\": \"msg\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": -15,\n                              \"src\": \"20695:3:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_magic_message\",\n                                \"typeString\": \"msg\"\n                              }\n                            },\n                            \"id\": 4775,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": false,\n                            \"lValueRequested\": false,\n                            \"memberName\": \"sender\",\n                            \"nodeType\": \"MemberAccess\",\n                            \"referencedDeclaration\": null,\n                            \"src\": \"20695:10:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_address_payable\",\n                              \"typeString\": \"address payable\"\n                            }\n                          },\n                          {\n                            \"argumentTypes\": null,\n                            \"arguments\": [\n                              {\n                                \"argumentTypes\": null,\n                                \"id\": 4778,\n                                \"name\": \"this\",\n                                \"nodeType\": \"Identifier\",\n                                \"overloadedDeclarations\": [],\n                                \"referencedDeclaration\": -28,\n                                \"src\": \"20715:4:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_contract$_Staking_$5490\",\n                                  \"typeString\": \"contract Staking\"\n                                }\n                              }\n                            ],\n                            \"expression\": {\n                              \"argumentTypes\": [\n                                {\n                                  \"typeIdentifier\": \"t_contract$_Staking_$5490\",\n                                  \"typeString\": \"contract Staking\"\n                                }\n                              ],\n                              \"id\": 4777,\n                              \"isConstant\": false,\n                              \"isLValue\": false,\n                              \"isPure\": true,\n                              \"lValueRequested\": false,\n                              \"nodeType\": \"ElementaryTypeNameExpression\",\n                              \"src\": \"20707:7:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_type$_t_address_$\",\n                                \"typeString\": \"type(address)\"\n                              },\n                              \"typeName\": {\n                                \"id\": 4776,\n                                \"name\": \"address\",\n                                \"nodeType\": \"ElementaryTypeName\",\n                                \"src\": \"20707:7:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": null,\n                                  \"typeString\": null\n                                }\n                              }\n                            },\n                            \"id\": 4779,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": false,\n                            \"kind\": \"typeConversion\",\n                            \"lValueRequested\": false,\n                            \"names\": [],\n                            \"nodeType\": \"FunctionCall\",\n                            \"src\": \"20707:13:6\",\n                            \"tryCall\": false,\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_address\",\n                              \"typeString\": \"address\"\n                            }\n                          },\n                          {\n                            \"argumentTypes\": null,\n                            \"id\": 4780,\n                            \"name\": \"amount\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 4757,\n                            \"src\": \"20722:6:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          }\n                        ],\n                        \"expression\": {\n                          \"argumentTypes\": [\n                            {\n                              \"typeIdentifier\": \"t_address_payable\",\n                              \"typeString\": \"address payable\"\n                            },\n                            {\n                              \"typeIdentifier\": \"t_address\",\n                              \"typeString\": \"address\"\n                            },\n                            {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          ],\n                          \"expression\": {\n                            \"argumentTypes\": null,\n                            \"id\": 4772,\n                            \"name\": \"_token\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 3762,\n                            \"src\": \"20675:6:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_contract$_IERC20_$6707\",\n                              \"typeString\": \"contract IERC20\"\n                            }\n                          },\n                          \"id\": 4773,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"memberName\": \"transferFrom\",\n                          \"nodeType\": \"MemberAccess\",\n                          \"referencedDeclaration\": 6688,\n                          \"src\": \"20675:19:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_function_external_nonpayable$_t_address_$_t_address_$_t_uint256_$returns$_t_bool_$\",\n                            \"typeString\": \"function (address,address,uint256) external returns (bool)\"\n                          }\n                        },\n                        \"id\": 4781,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"kind\": \"functionCall\",\n                        \"lValueRequested\": false,\n                        \"names\": [],\n                        \"nodeType\": \"FunctionCall\",\n                        \"src\": \"20675:54:6\",\n                        \"tryCall\": false,\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"hexValue\": \"5472616e73666572206661696c6564\",\n                        \"id\": 4782,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": true,\n                        \"kind\": \"string\",\n                        \"lValueRequested\": false,\n                        \"nodeType\": \"Literal\",\n                        \"src\": \"20731:17:6\",\n                        \"subdenomination\": null,\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_stringliteral_25adaa6d082ce15f901e0d8a3d393e7462ef9edf2e6bc8321fa14d1615b6fc51\",\n                          \"typeString\": \"literal_string \\\"Transfer failed\\\"\"\n                        },\n                        \"value\": \"Transfer failed\"\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_stringliteral_25adaa6d082ce15f901e0d8a3d393e7462ef9edf2e6bc8321fa14d1615b6fc51\",\n                          \"typeString\": \"literal_string \\\"Transfer failed\\\"\"\n                        }\n                      ],\n                      \"id\": 4771,\n                      \"name\": \"require\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [\n                        -18,\n                        -18\n                      ],\n                      \"referencedDeclaration\": -18,\n                      \"src\": \"20667:7:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$\",\n                        \"typeString\": \"function (bool,string memory) pure\"\n                      }\n                    },\n                    \"id\": 4783,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"20667:82:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 4784,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"20667:82:6\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 4790,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 4785,\n                      \"name\": \"_rewardsPoolBalance\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 3770,\n                      \"src\": \"20759:19:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"arguments\": [\n                        {\n                          \"argumentTypes\": null,\n                          \"id\": 4788,\n                          \"name\": \"amount\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 4757,\n                          \"src\": \"20805:6:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        }\n                      ],\n                      \"expression\": {\n                        \"argumentTypes\": [\n                          {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        ],\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 4786,\n                          \"name\": \"_rewardsPoolBalance\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 3770,\n                          \"src\": \"20781:19:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"id\": 4787,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"memberName\": \"add\",\n                        \"nodeType\": \"MemberAccess\",\n                        \"referencedDeclaration\": 5870,\n                        \"src\": \"20781:23:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_function_internal_pure$_t_uint256_$_t_uint256_$returns$_t_uint256_$bound_to$_t_uint256_$\",\n                          \"typeString\": \"function (uint256,uint256) pure returns (uint256)\"\n                        }\n                      },\n                      \"id\": 4789,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": false,\n                      \"kind\": \"functionCall\",\n                      \"lValueRequested\": false,\n                      \"names\": [],\n                      \"nodeType\": \"FunctionCall\",\n                      \"src\": \"20781:31:6\",\n                      \"tryCall\": false,\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"src\": \"20759:53:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"id\": 4791,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"20759:53:6\"\n                },\n                {\n                  \"eventCall\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 4793,\n                          \"name\": \"msg\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": -15,\n                          \"src\": \"20849:3:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_magic_message\",\n                            \"typeString\": \"msg\"\n                          }\n                        },\n                        \"id\": 4794,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"memberName\": \"sender\",\n                        \"nodeType\": \"MemberAccess\",\n                        \"referencedDeclaration\": null,\n                        \"src\": \"20849:10:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 4795,\n                        \"name\": \"amount\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4757,\n                        \"src\": \"20861:6:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"id\": 4792,\n                      \"name\": \"RewardsPoolTokenTopUp\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 3744,\n                      \"src\": \"20827:21:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_event_nonpayable$_t_address_$_t_uint256_$returns$__$\",\n                        \"typeString\": \"function (address,uint256)\"\n                      }\n                    },\n                    \"id\": 4796,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"20827:41:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 4797,\n                  \"nodeType\": \"EmitStatement\",\n                  \"src\": \"20822:46:6\"\n                }\n              ]\n            },\n            \"documentation\": {\n              \"id\": 4755,\n              \"nodeType\": \"StructuredDocumentation\",\n              \"src\": \"20007:425:6\",\n              \"text\": \"@dev Even though this is considered as administrative action (is not affected by\\nby contract paused state, it can be executed by anyone who wishes to\\ntop-up the rewards pool (funds are sent in to contract, *not* the other way around).\\nThe Rewards Pool is exclusively dedicated to cover withdrawals of user' compound interest,\\nwhich is effectively the reward.\"\n            },\n            \"functionSelector\": \"ba92a4c5\",\n            \"id\": 4799,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [\n              {\n                \"arguments\": [\n                  {\n                    \"argumentTypes\": null,\n                    \"id\": 4762,\n                    \"name\": \"txExpirationBlock\",\n                    \"nodeType\": \"Identifier\",\n                    \"overloadedDeclarations\": [],\n                    \"referencedDeclaration\": 4759,\n                    \"src\": \"20576:17:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  }\n                ],\n                \"id\": 4763,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 4761,\n                  \"name\": \"verifyTxExpiration\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 3836,\n                  \"src\": \"20557:18:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$_t_uint256_$\",\n                    \"typeString\": \"modifier (uint256)\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"20557:37:6\"\n              }\n            ],\n            \"name\": \"topUpRewardsPool\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 4760,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 4757,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"amount\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4799,\n                  \"src\": \"20472:14:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 4756,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"20472:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 4759,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"txExpirationBlock\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4799,\n                  \"src\": \"20496:25:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 4758,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"20496:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"20462:69:6\"\n            },\n            \"returnParameters\": {\n              \"id\": 4764,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"20599:0:6\"\n            },\n            \"scope\": 5490,\n            \"src\": \"20437:438:6\",\n            \"stateMutability\": \"nonpayable\",\n            \"virtual\": false,\n            \"visibility\": \"external\"\n          },\n          {\n            \"body\": {\n              \"id\": 4816,\n              \"nodeType\": \"Block\",\n              \"src\": \"21179:47:6\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 4813,\n                        \"name\": \"numOfBlocks\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4802,\n                        \"src\": \"21207:11:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint64\",\n                          \"typeString\": \"uint64\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_uint64\",\n                          \"typeString\": \"uint64\"\n                        }\n                      ],\n                      \"id\": 4812,\n                      \"name\": \"_updateLockPeriod\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5079,\n                      \"src\": \"21189:17:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_nonpayable$_t_uint64_$returns$__$\",\n                        \"typeString\": \"function (uint64)\"\n                      }\n                    },\n                    \"id\": 4814,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"21189:30:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 4815,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"21189:30:6\"\n                }\n              ]\n            },\n            \"documentation\": {\n              \"id\": 4800,\n              \"nodeType\": \"StructuredDocumentation\",\n              \"src\": \"20882:131:6\",\n              \"text\": \"@notice Updates Lock Period value\\n@param numOfBlocks  length of the lock period\\n@dev Delegate only\"\n            },\n            \"functionSelector\": \"f0895e52\",\n            \"id\": 4817,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [\n              {\n                \"arguments\": [\n                  {\n                    \"argumentTypes\": null,\n                    \"id\": 4807,\n                    \"name\": \"txExpirationBlock\",\n                    \"nodeType\": \"Identifier\",\n                    \"overloadedDeclarations\": [],\n                    \"referencedDeclaration\": 4804,\n                    \"src\": \"21135:17:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  }\n                ],\n                \"id\": 4808,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 4806,\n                  \"name\": \"verifyTxExpiration\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 3836,\n                  \"src\": \"21116:18:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$_t_uint256_$\",\n                    \"typeString\": \"modifier (uint256)\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"21116:37:6\"\n              },\n              {\n                \"arguments\": null,\n                \"id\": 4810,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 4809,\n                  \"name\": \"onlyDelegate\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 3822,\n                  \"src\": \"21162:12:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$__$\",\n                    \"typeString\": \"modifier ()\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"21162:12:6\"\n              }\n            ],\n            \"name\": \"updateLockPeriod\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 4805,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 4802,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"numOfBlocks\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4817,\n                  \"src\": \"21044:18:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint64\",\n                    \"typeString\": \"uint64\"\n                  },\n                  \"typeName\": {\n                    \"id\": 4801,\n                    \"name\": \"uint64\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"21044:6:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint64\",\n                      \"typeString\": \"uint64\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 4804,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"txExpirationBlock\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4817,\n                  \"src\": \"21064:25:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 4803,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"21064:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"21043:47:6\"\n            },\n            \"returnParameters\": {\n              \"id\": 4811,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"21179:0:6\"\n            },\n            \"scope\": 5490,\n            \"src\": \"21018:208:6\",\n            \"stateMutability\": \"nonpayable\",\n            \"virtual\": false,\n            \"visibility\": \"external\"\n          },\n          {\n            \"body\": {\n              \"id\": 4834,\n              \"nodeType\": \"Block\",\n              \"src\": \"21671:41:6\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 4831,\n                        \"name\": \"blockNumber\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4820,\n                        \"src\": \"21693:11:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"id\": 4830,\n                      \"name\": \"_pauseSince\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5104,\n                      \"src\": \"21681:11:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_nonpayable$_t_uint256_$returns$__$\",\n                        \"typeString\": \"function (uint256)\"\n                      }\n                    },\n                    \"id\": 4832,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"21681:24:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 4833,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"21681:24:6\"\n                }\n              ]\n            },\n            \"documentation\": {\n              \"id\": 4818,\n              \"nodeType\": \"StructuredDocumentation\",\n              \"src\": \"21233:277:6\",\n              \"text\": \"@notice Pauses all NON-administrative interaction with the contract since the specidfed block number \\n@param blockNumber block number since which non-admin interaction will be paused (for all _getBlockNumber() >= blockNumber)\\n@dev Delegate only\"\n            },\n            \"functionSelector\": \"347908df\",\n            \"id\": 4835,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [\n              {\n                \"arguments\": [\n                  {\n                    \"argumentTypes\": null,\n                    \"id\": 4825,\n                    \"name\": \"txExpirationBlock\",\n                    \"nodeType\": \"Identifier\",\n                    \"overloadedDeclarations\": [],\n                    \"referencedDeclaration\": 4822,\n                    \"src\": \"21627:17:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  }\n                ],\n                \"id\": 4826,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 4824,\n                  \"name\": \"verifyTxExpiration\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 3836,\n                  \"src\": \"21608:18:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$_t_uint256_$\",\n                    \"typeString\": \"modifier (uint256)\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"21608:37:6\"\n              },\n              {\n                \"arguments\": null,\n                \"id\": 4828,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 4827,\n                  \"name\": \"onlyDelegate\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 3822,\n                  \"src\": \"21654:12:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$__$\",\n                    \"typeString\": \"modifier ()\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"21654:12:6\"\n              }\n            ],\n            \"name\": \"pauseSince\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 4823,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 4820,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"blockNumber\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4835,\n                  \"src\": \"21535:19:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 4819,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"21535:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 4822,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"txExpirationBlock\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4835,\n                  \"src\": \"21556:25:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 4821,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"21556:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"21534:48:6\"\n            },\n            \"returnParameters\": {\n              \"id\": 4829,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"21671:0:6\"\n            },\n            \"scope\": 5490,\n            \"src\": \"21515:197:6\",\n            \"stateMutability\": \"nonpayable\",\n            \"virtual\": false,\n            \"visibility\": \"external\"\n          },\n          {\n            \"body\": {\n              \"id\": 4909,\n              \"nodeType\": \"Block\",\n              \"src\": \"22190:911:6\",\n              \"statements\": [\n                {\n                  \"condition\": {\n                    \"argumentTypes\": null,\n                    \"commonType\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    },\n                    \"id\": 4852,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftExpression\": {\n                      \"argumentTypes\": null,\n                      \"id\": 4850,\n                      \"name\": \"amount\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 4838,\n                      \"src\": \"22204:6:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"BinaryOperation\",\n                    \"operator\": \"==\",\n                    \"rightExpression\": {\n                      \"argumentTypes\": null,\n                      \"hexValue\": \"30\",\n                      \"id\": 4851,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": true,\n                      \"kind\": \"number\",\n                      \"lValueRequested\": false,\n                      \"nodeType\": \"Literal\",\n                      \"src\": \"22214:1:6\",\n                      \"subdenomination\": null,\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_rational_0_by_1\",\n                        \"typeString\": \"int_const 0\"\n                      },\n                      \"value\": \"0\"\n                    },\n                    \"src\": \"22204:11:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_bool\",\n                      \"typeString\": \"bool\"\n                    }\n                  },\n                  \"falseBody\": {\n                    \"id\": 4865,\n                    \"nodeType\": \"Block\",\n                    \"src\": \"22276:98:6\",\n                    \"statements\": [\n                      {\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"arguments\": [\n                            {\n                              \"argumentTypes\": null,\n                              \"commonType\": {\n                                \"typeIdentifier\": \"t_uint256\",\n                                \"typeString\": \"uint256\"\n                              },\n                              \"id\": 4861,\n                              \"isConstant\": false,\n                              \"isLValue\": false,\n                              \"isPure\": false,\n                              \"lValueRequested\": false,\n                              \"leftExpression\": {\n                                \"argumentTypes\": null,\n                                \"id\": 4859,\n                                \"name\": \"amount\",\n                                \"nodeType\": \"Identifier\",\n                                \"overloadedDeclarations\": [],\n                                \"referencedDeclaration\": 4838,\n                                \"src\": \"22298:6:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              },\n                              \"nodeType\": \"BinaryOperation\",\n                              \"operator\": \"<=\",\n                              \"rightExpression\": {\n                                \"argumentTypes\": null,\n                                \"id\": 4860,\n                                \"name\": \"_rewardsPoolBalance\",\n                                \"nodeType\": \"Identifier\",\n                                \"overloadedDeclarations\": [],\n                                \"referencedDeclaration\": 3770,\n                                \"src\": \"22308:19:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              },\n                              \"src\": \"22298:29:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_bool\",\n                                \"typeString\": \"bool\"\n                              }\n                            },\n                            {\n                              \"argumentTypes\": null,\n                              \"hexValue\": \"416d6f756e7420686967686572207468616e207265776172647320706f6f6c\",\n                              \"id\": 4862,\n                              \"isConstant\": false,\n                              \"isLValue\": false,\n                              \"isPure\": true,\n                              \"kind\": \"string\",\n                              \"lValueRequested\": false,\n                              \"nodeType\": \"Literal\",\n                              \"src\": \"22329:33:6\",\n                              \"subdenomination\": null,\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_stringliteral_587ce66cc8dcf85ee5804e9c2a7ad26da4041f2a6217e351e0d49635c54a34e6\",\n                                \"typeString\": \"literal_string \\\"Amount higher than rewards pool\\\"\"\n                              },\n                              \"value\": \"Amount higher than rewards pool\"\n                            }\n                          ],\n                          \"expression\": {\n                            \"argumentTypes\": [\n                              {\n                                \"typeIdentifier\": \"t_bool\",\n                                \"typeString\": \"bool\"\n                              },\n                              {\n                                \"typeIdentifier\": \"t_stringliteral_587ce66cc8dcf85ee5804e9c2a7ad26da4041f2a6217e351e0d49635c54a34e6\",\n                                \"typeString\": \"literal_string \\\"Amount higher than rewards pool\\\"\"\n                              }\n                            ],\n                            \"id\": 4858,\n                            \"name\": \"require\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [\n                              -18,\n                              -18\n                            ],\n                            \"referencedDeclaration\": -18,\n                            \"src\": \"22290:7:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$\",\n                              \"typeString\": \"function (bool,string memory) pure\"\n                            }\n                          },\n                          \"id\": 4863,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"kind\": \"functionCall\",\n                          \"lValueRequested\": false,\n                          \"names\": [],\n                          \"nodeType\": \"FunctionCall\",\n                          \"src\": \"22290:73:6\",\n                          \"tryCall\": false,\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_tuple$__$\",\n                            \"typeString\": \"tuple()\"\n                          }\n                        },\n                        \"id\": 4864,\n                        \"nodeType\": \"ExpressionStatement\",\n                        \"src\": \"22290:73:6\"\n                      }\n                    ]\n                  },\n                  \"id\": 4866,\n                  \"nodeType\": \"IfStatement\",\n                  \"src\": \"22200:174:6\",\n                  \"trueBody\": {\n                    \"id\": 4857,\n                    \"nodeType\": \"Block\",\n                    \"src\": \"22217:53:6\",\n                    \"statements\": [\n                      {\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 4855,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"leftHandSide\": {\n                            \"argumentTypes\": null,\n                            \"id\": 4853,\n                            \"name\": \"amount\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 4838,\n                            \"src\": \"22231:6:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"nodeType\": \"Assignment\",\n                          \"operator\": \"=\",\n                          \"rightHandSide\": {\n                            \"argumentTypes\": null,\n                            \"id\": 4854,\n                            \"name\": \"_rewardsPoolBalance\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 3770,\n                            \"src\": \"22240:19:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"src\": \"22231:28:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"id\": 4856,\n                        \"nodeType\": \"ExpressionStatement\",\n                        \"src\": \"22231:28:6\"\n                      }\n                    ]\n                  }\n                },\n                {\n                  \"assignments\": [\n                    4868\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 4868,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"contractBalance\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 4909,\n                      \"src\": \"22562:23:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"default\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      },\n                      \"typeName\": {\n                        \"id\": 4867,\n                        \"name\": \"uint256\",\n                        \"nodeType\": \"ElementaryTypeName\",\n                        \"src\": \"22562:7:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 4876,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"arguments\": [\n                          {\n                            \"argumentTypes\": null,\n                            \"id\": 4873,\n                            \"name\": \"this\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": -28,\n                            \"src\": \"22613:4:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_contract$_Staking_$5490\",\n                              \"typeString\": \"contract Staking\"\n                            }\n                          }\n                        ],\n                        \"expression\": {\n                          \"argumentTypes\": [\n                            {\n                              \"typeIdentifier\": \"t_contract$_Staking_$5490\",\n                              \"typeString\": \"contract Staking\"\n                            }\n                          ],\n                          \"id\": 4872,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": true,\n                          \"lValueRequested\": false,\n                          \"nodeType\": \"ElementaryTypeNameExpression\",\n                          \"src\": \"22605:7:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_type$_t_address_$\",\n                            \"typeString\": \"type(address)\"\n                          },\n                          \"typeName\": {\n                            \"id\": 4871,\n                            \"name\": \"address\",\n                            \"nodeType\": \"ElementaryTypeName\",\n                            \"src\": \"22605:7:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": null,\n                              \"typeString\": null\n                            }\n                          }\n                        },\n                        \"id\": 4874,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"kind\": \"typeConversion\",\n                        \"lValueRequested\": false,\n                        \"names\": [],\n                        \"nodeType\": \"FunctionCall\",\n                        \"src\": \"22605:13:6\",\n                        \"tryCall\": false,\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        }\n                      ],\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 4869,\n                        \"name\": \"_token\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 3762,\n                        \"src\": \"22588:6:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_contract$_IERC20_$6707\",\n                          \"typeString\": \"contract IERC20\"\n                        }\n                      },\n                      \"id\": 4870,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"memberName\": \"balanceOf\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": 6646,\n                      \"src\": \"22588:16:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_external_view$_t_address_$returns$_t_uint256_$\",\n                        \"typeString\": \"function (address) view external returns (uint256)\"\n                      }\n                    },\n                    \"id\": 4875,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"22588:31:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"22562:57:6\"\n                },\n                {\n                  \"assignments\": [\n                    4878\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 4878,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"expectedMinContractBalance\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 4909,\n                      \"src\": \"22629:34:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"default\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      },\n                      \"typeName\": {\n                        \"id\": 4877,\n                        \"name\": \"uint256\",\n                        \"nodeType\": \"ElementaryTypeName\",\n                        \"src\": \"22629:7:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 4883,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 4881,\n                        \"name\": \"amount\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4838,\n                        \"src\": \"22694:6:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 4879,\n                        \"name\": \"_accruedGlobalPrincipal\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 3772,\n                        \"src\": \"22666:23:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      \"id\": 4880,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"memberName\": \"add\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": 5870,\n                      \"src\": \"22666:27:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_pure$_t_uint256_$_t_uint256_$returns$_t_uint256_$bound_to$_t_uint256_$\",\n                        \"typeString\": \"function (uint256,uint256) pure returns (uint256)\"\n                      }\n                    },\n                    \"id\": 4882,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"22666:35:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"22629:72:6\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"commonType\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        },\n                        \"id\": 4887,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"leftExpression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 4885,\n                          \"name\": \"expectedMinContractBalance\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 4878,\n                          \"src\": \"22719:26:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"nodeType\": \"BinaryOperation\",\n                        \"operator\": \"<=\",\n                        \"rightExpression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 4886,\n                          \"name\": \"contractBalance\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 4868,\n                          \"src\": \"22749:15:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"src\": \"22719:45:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"hexValue\": \"436f6e747261637420696e636f6e73697374656e63792e\",\n                        \"id\": 4888,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": true,\n                        \"kind\": \"string\",\n                        \"lValueRequested\": false,\n                        \"nodeType\": \"Literal\",\n                        \"src\": \"22766:25:6\",\n                        \"subdenomination\": null,\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_stringliteral_391f4d8f0a702da0afb416db97e6f601a29dc7e134644564cd5e78cc8b2ef1d5\",\n                          \"typeString\": \"literal_string \\\"Contract inconsistency.\\\"\"\n                        },\n                        \"value\": \"Contract inconsistency.\"\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_stringliteral_391f4d8f0a702da0afb416db97e6f601a29dc7e134644564cd5e78cc8b2ef1d5\",\n                          \"typeString\": \"literal_string \\\"Contract inconsistency.\\\"\"\n                        }\n                      ],\n                      \"id\": 4884,\n                      \"name\": \"require\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [\n                        -18,\n                        -18\n                      ],\n                      \"referencedDeclaration\": -18,\n                      \"src\": \"22711:7:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$\",\n                        \"typeString\": \"function (bool,string memory) pure\"\n                      }\n                    },\n                    \"id\": 4889,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"22711:81:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 4890,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"22711:81:6\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"arguments\": [\n                          {\n                            \"argumentTypes\": null,\n                            \"id\": 4894,\n                            \"name\": \"targetAddress\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 4840,\n                            \"src\": \"22827:13:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_address_payable\",\n                              \"typeString\": \"address payable\"\n                            }\n                          },\n                          {\n                            \"argumentTypes\": null,\n                            \"id\": 4895,\n                            \"name\": \"amount\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 4838,\n                            \"src\": \"22842:6:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          }\n                        ],\n                        \"expression\": {\n                          \"argumentTypes\": [\n                            {\n                              \"typeIdentifier\": \"t_address_payable\",\n                              \"typeString\": \"address payable\"\n                            },\n                            {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          ],\n                          \"expression\": {\n                            \"argumentTypes\": null,\n                            \"id\": 4892,\n                            \"name\": \"_token\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 3762,\n                            \"src\": \"22811:6:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_contract$_IERC20_$6707\",\n                              \"typeString\": \"contract IERC20\"\n                            }\n                          },\n                          \"id\": 4893,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"memberName\": \"transfer\",\n                          \"nodeType\": \"MemberAccess\",\n                          \"referencedDeclaration\": 6656,\n                          \"src\": \"22811:15:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_function_external_nonpayable$_t_address_$_t_uint256_$returns$_t_bool_$\",\n                            \"typeString\": \"function (address,uint256) external returns (bool)\"\n                          }\n                        },\n                        \"id\": 4896,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"kind\": \"functionCall\",\n                        \"lValueRequested\": false,\n                        \"names\": [],\n                        \"nodeType\": \"FunctionCall\",\n                        \"src\": \"22811:38:6\",\n                        \"tryCall\": false,\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"hexValue\": \"4e6f7420656e6f7567682066756e6473206f6e20636f6e74722e20616464722e\",\n                        \"id\": 4897,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": true,\n                        \"kind\": \"string\",\n                        \"lValueRequested\": false,\n                        \"nodeType\": \"Literal\",\n                        \"src\": \"22851:34:6\",\n                        \"subdenomination\": null,\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_stringliteral_fd3fa1113e097b10bbbc2a9e78e5896bda814123efe5dcd9c1d96e852dae5f82\",\n                          \"typeString\": \"literal_string \\\"Not enough funds on contr. addr.\\\"\"\n                        },\n                        \"value\": \"Not enough funds on contr. addr.\"\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_stringliteral_fd3fa1113e097b10bbbc2a9e78e5896bda814123efe5dcd9c1d96e852dae5f82\",\n                          \"typeString\": \"literal_string \\\"Not enough funds on contr. addr.\\\"\"\n                        }\n                      ],\n                      \"id\": 4891,\n                      \"name\": \"require\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [\n                        -18,\n                        -18\n                      ],\n                      \"referencedDeclaration\": -18,\n                      \"src\": \"22803:7:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$\",\n                        \"typeString\": \"function (bool,string memory) pure\"\n                      }\n                    },\n                    \"id\": 4898,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"22803:83:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 4899,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"22803:83:6\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 4902,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 4900,\n                      \"name\": \"_rewardsPoolBalance\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 3770,\n                      \"src\": \"23000:19:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"-=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 4901,\n                      \"name\": \"amount\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 4838,\n                      \"src\": \"23023:6:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"src\": \"23000:29:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"id\": 4903,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"23000:29:6\"\n                },\n                {\n                  \"eventCall\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 4905,\n                        \"name\": \"targetAddress\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4840,\n                        \"src\": \"23072:13:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 4906,\n                        \"name\": \"amount\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4838,\n                        \"src\": \"23087:6:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"id\": 4904,\n                      \"name\": \"RewardsPoolTokenWithdrawal\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 3750,\n                      \"src\": \"23045:26:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_event_nonpayable$_t_address_$_t_uint256_$returns$__$\",\n                        \"typeString\": \"function (address,uint256)\"\n                      }\n                    },\n                    \"id\": 4907,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"23045:49:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 4908,\n                  \"nodeType\": \"EmitStatement\",\n                  \"src\": \"23040:54:6\"\n                }\n              ]\n            },\n            \"documentation\": {\n              \"id\": 4836,\n              \"nodeType\": \"StructuredDocumentation\",\n              \"src\": \"21719:257:6\",\n              \"text\": \"@dev Withdraw tokens from rewards pool.\\n     * @param amount : amount to withdraw.\\n                If `amount == 0` then whole amount in rewards pool will be withdrawn.\\n@param targetAddress : address to send tokens to\"\n            },\n            \"functionSelector\": \"68bccfcf\",\n            \"id\": 4910,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [\n              {\n                \"arguments\": [\n                  {\n                    \"argumentTypes\": null,\n                    \"id\": 4845,\n                    \"name\": \"txExpirationBlock\",\n                    \"nodeType\": \"Identifier\",\n                    \"overloadedDeclarations\": [],\n                    \"referencedDeclaration\": 4842,\n                    \"src\": \"22149:17:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  }\n                ],\n                \"id\": 4846,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 4844,\n                  \"name\": \"verifyTxExpiration\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 3836,\n                  \"src\": \"22130:18:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$_t_uint256_$\",\n                    \"typeString\": \"modifier (uint256)\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"22130:37:6\"\n              },\n              {\n                \"arguments\": null,\n                \"id\": 4848,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 4847,\n                  \"name\": \"onlyOwner\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 3806,\n                  \"src\": \"22176:9:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$__$\",\n                    \"typeString\": \"modifier ()\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"22176:9:6\"\n              }\n            ],\n            \"name\": \"withdrawFromRewardsPool\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 4843,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 4838,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"amount\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4910,\n                  \"src\": \"22014:14:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 4837,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"22014:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 4840,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"targetAddress\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4910,\n                  \"src\": \"22030:29:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_address_payable\",\n                    \"typeString\": \"address payable\"\n                  },\n                  \"typeName\": {\n                    \"id\": 4839,\n                    \"name\": \"address\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"22030:15:6\",\n                    \"stateMutability\": \"payable\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address_payable\",\n                      \"typeString\": \"address payable\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 4842,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"txExpirationBlock\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4910,\n                  \"src\": \"22069:25:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 4841,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"22069:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"22013:91:6\"\n            },\n            \"returnParameters\": {\n              \"id\": 4849,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"22190:0:6\"\n            },\n            \"scope\": 5490,\n            \"src\": \"21981:1120:6\",\n            \"stateMutability\": \"nonpayable\",\n            \"virtual\": false,\n            \"visibility\": \"external\"\n          },\n          {\n            \"body\": {\n              \"id\": 4961,\n              \"nodeType\": \"Block\",\n              \"src\": \"23907:609:6\",\n              \"statements\": [\n                {\n                  \"assignments\": [\n                    4924\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 4924,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"contractBalance\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 4961,\n                      \"src\": \"23917:23:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"default\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      },\n                      \"typeName\": {\n                        \"id\": 4923,\n                        \"name\": \"uint256\",\n                        \"nodeType\": \"ElementaryTypeName\",\n                        \"src\": \"23917:7:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 4932,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"arguments\": [\n                          {\n                            \"argumentTypes\": null,\n                            \"id\": 4929,\n                            \"name\": \"this\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": -28,\n                            \"src\": \"23968:4:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_contract$_Staking_$5490\",\n                              \"typeString\": \"contract Staking\"\n                            }\n                          }\n                        ],\n                        \"expression\": {\n                          \"argumentTypes\": [\n                            {\n                              \"typeIdentifier\": \"t_contract$_Staking_$5490\",\n                              \"typeString\": \"contract Staking\"\n                            }\n                          ],\n                          \"id\": 4928,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": true,\n                          \"lValueRequested\": false,\n                          \"nodeType\": \"ElementaryTypeNameExpression\",\n                          \"src\": \"23960:7:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_type$_t_address_$\",\n                            \"typeString\": \"type(address)\"\n                          },\n                          \"typeName\": {\n                            \"id\": 4927,\n                            \"name\": \"address\",\n                            \"nodeType\": \"ElementaryTypeName\",\n                            \"src\": \"23960:7:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": null,\n                              \"typeString\": null\n                            }\n                          }\n                        },\n                        \"id\": 4930,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"kind\": \"typeConversion\",\n                        \"lValueRequested\": false,\n                        \"names\": [],\n                        \"nodeType\": \"FunctionCall\",\n                        \"src\": \"23960:13:6\",\n                        \"tryCall\": false,\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        }\n                      ],\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 4925,\n                        \"name\": \"_token\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 3762,\n                        \"src\": \"23943:6:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_contract$_IERC20_$6707\",\n                          \"typeString\": \"contract IERC20\"\n                        }\n                      },\n                      \"id\": 4926,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"memberName\": \"balanceOf\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": 6646,\n                      \"src\": \"23943:16:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_external_view$_t_address_$returns$_t_uint256_$\",\n                        \"typeString\": \"function (address) view external returns (uint256)\"\n                      }\n                    },\n                    \"id\": 4931,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"23943:31:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"23917:57:6\"\n                },\n                {\n                  \"assignments\": [\n                    4934\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 4934,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"expectedMinContractBalance\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 4961,\n                      \"src\": \"23984:34:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"default\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      },\n                      \"typeName\": {\n                        \"id\": 4933,\n                        \"name\": \"uint256\",\n                        \"nodeType\": \"ElementaryTypeName\",\n                        \"src\": \"23984:7:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 4939,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 4937,\n                        \"name\": \"_rewardsPoolBalance\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 3770,\n                        \"src\": \"24049:19:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 4935,\n                        \"name\": \"_accruedGlobalPrincipal\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 3772,\n                        \"src\": \"24021:23:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      \"id\": 4936,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"memberName\": \"add\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": 5870,\n                      \"src\": \"24021:27:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_pure$_t_uint256_$_t_uint256_$returns$_t_uint256_$bound_to$_t_uint256_$\",\n                        \"typeString\": \"function (uint256,uint256) pure returns (uint256)\"\n                      }\n                    },\n                    \"id\": 4938,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"24021:48:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"23984:85:6\"\n                },\n                {\n                  \"assignments\": [\n                    4941\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 4941,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"excessAmount\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 4961,\n                      \"src\": \"24275:20:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"default\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      },\n                      \"typeName\": {\n                        \"id\": 4940,\n                        \"name\": \"uint256\",\n                        \"nodeType\": \"ElementaryTypeName\",\n                        \"src\": \"24275:7:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 4946,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 4944,\n                        \"name\": \"expectedMinContractBalance\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4934,\n                        \"src\": \"24318:26:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 4942,\n                        \"name\": \"contractBalance\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4924,\n                        \"src\": \"24298:15:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      \"id\": 4943,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"memberName\": \"sub\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": 5887,\n                      \"src\": \"24298:19:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_pure$_t_uint256_$_t_uint256_$returns$_t_uint256_$bound_to$_t_uint256_$\",\n                        \"typeString\": \"function (uint256,uint256) pure returns (uint256)\"\n                      }\n                    },\n                    \"id\": 4945,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"24298:47:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"24275:70:6\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"arguments\": [\n                          {\n                            \"argumentTypes\": null,\n                            \"id\": 4950,\n                            \"name\": \"targetAddress\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 4913,\n                            \"src\": \"24379:13:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_address_payable\",\n                              \"typeString\": \"address payable\"\n                            }\n                          },\n                          {\n                            \"argumentTypes\": null,\n                            \"id\": 4951,\n                            \"name\": \"excessAmount\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 4941,\n                            \"src\": \"24394:12:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          }\n                        ],\n                        \"expression\": {\n                          \"argumentTypes\": [\n                            {\n                              \"typeIdentifier\": \"t_address_payable\",\n                              \"typeString\": \"address payable\"\n                            },\n                            {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          ],\n                          \"expression\": {\n                            \"argumentTypes\": null,\n                            \"id\": 4948,\n                            \"name\": \"_token\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 3762,\n                            \"src\": \"24363:6:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_contract$_IERC20_$6707\",\n                              \"typeString\": \"contract IERC20\"\n                            }\n                          },\n                          \"id\": 4949,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"memberName\": \"transfer\",\n                          \"nodeType\": \"MemberAccess\",\n                          \"referencedDeclaration\": 6656,\n                          \"src\": \"24363:15:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_function_external_nonpayable$_t_address_$_t_uint256_$returns$_t_bool_$\",\n                            \"typeString\": \"function (address,uint256) external returns (bool)\"\n                          }\n                        },\n                        \"id\": 4952,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"kind\": \"functionCall\",\n                        \"lValueRequested\": false,\n                        \"names\": [],\n                        \"nodeType\": \"FunctionCall\",\n                        \"src\": \"24363:44:6\",\n                        \"tryCall\": false,\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"hexValue\": \"4e6f7420656e6f7567682066756e6473206f6e20636f6e74722e20616464722e\",\n                        \"id\": 4953,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": true,\n                        \"kind\": \"string\",\n                        \"lValueRequested\": false,\n                        \"nodeType\": \"Literal\",\n                        \"src\": \"24409:34:6\",\n                        \"subdenomination\": null,\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_stringliteral_fd3fa1113e097b10bbbc2a9e78e5896bda814123efe5dcd9c1d96e852dae5f82\",\n                          \"typeString\": \"literal_string \\\"Not enough funds on contr. addr.\\\"\"\n                        },\n                        \"value\": \"Not enough funds on contr. addr.\"\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_stringliteral_fd3fa1113e097b10bbbc2a9e78e5896bda814123efe5dcd9c1d96e852dae5f82\",\n                          \"typeString\": \"literal_string \\\"Not enough funds on contr. addr.\\\"\"\n                        }\n                      ],\n                      \"id\": 4947,\n                      \"name\": \"require\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [\n                        -18,\n                        -18\n                      ],\n                      \"referencedDeclaration\": -18,\n                      \"src\": \"24355:7:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$\",\n                        \"typeString\": \"function (bool,string memory) pure\"\n                      }\n                    },\n                    \"id\": 4954,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"24355:89:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 4955,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"24355:89:6\"\n                },\n                {\n                  \"eventCall\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 4957,\n                        \"name\": \"targetAddress\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4913,\n                        \"src\": \"24481:13:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 4958,\n                        \"name\": \"excessAmount\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4941,\n                        \"src\": \"24496:12:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"id\": 4956,\n                      \"name\": \"ExcessTokenWithdrawal\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 3738,\n                      \"src\": \"24459:21:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_event_nonpayable$_t_address_$_t_uint256_$returns$__$\",\n                        \"typeString\": \"function (address,uint256)\"\n                      }\n                    },\n                    \"id\": 4959,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"24459:50:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 4960,\n                  \"nodeType\": \"EmitStatement\",\n                  \"src\": \"24454:55:6\"\n                }\n              ]\n            },\n            \"documentation\": {\n              \"id\": 4911,\n              \"nodeType\": \"StructuredDocumentation\",\n              \"src\": \"23108:621:6\",\n              \"text\": \"@dev Withdraw \\\"excess\\\" tokens, which were sent to contract directly via direct ERC20.transfer(...),\\n     without interacting with API of this (Staking) contract, what could be done only by mistake.\\n     Thus this method is meant to be used primarily for rescue purposes, enabling withdrawal of such\\n     \\\"excess\\\" tokens out of contract.\\n@param targetAddress : address to send tokens to\\n@param txExpirationBlock : block number until which is the transaction valid (inclusive).\\n                           When transaction is processed after this block, it fails.\"\n            },\n            \"functionSelector\": \"53e052ac\",\n            \"id\": 4962,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [\n              {\n                \"arguments\": [\n                  {\n                    \"argumentTypes\": null,\n                    \"id\": 4918,\n                    \"name\": \"txExpirationBlock\",\n                    \"nodeType\": \"Identifier\",\n                    \"overloadedDeclarations\": [],\n                    \"referencedDeclaration\": 4915,\n                    \"src\": \"23866:17:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  }\n                ],\n                \"id\": 4919,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 4917,\n                  \"name\": \"verifyTxExpiration\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 3836,\n                  \"src\": \"23847:18:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$_t_uint256_$\",\n                    \"typeString\": \"modifier (uint256)\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"23847:37:6\"\n              },\n              {\n                \"arguments\": null,\n                \"id\": 4921,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 4920,\n                  \"name\": \"onlyOwner\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 3806,\n                  \"src\": \"23893:9:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$__$\",\n                    \"typeString\": \"modifier ()\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"23893:9:6\"\n              }\n            ],\n            \"name\": \"withdrawExcessTokens\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 4916,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 4913,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"targetAddress\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4962,\n                  \"src\": \"23764:29:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_address_payable\",\n                    \"typeString\": \"address payable\"\n                  },\n                  \"typeName\": {\n                    \"id\": 4912,\n                    \"name\": \"address\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"23764:15:6\",\n                    \"stateMutability\": \"payable\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address_payable\",\n                      \"typeString\": \"address payable\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 4915,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"txExpirationBlock\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 4962,\n                  \"src\": \"23795:25:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 4914,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"23795:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"23763:58:6\"\n            },\n            \"returnParameters\": {\n              \"id\": 4922,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"23907:0:6\"\n            },\n            \"scope\": 5490,\n            \"src\": \"23734:782:6\",\n            \"stateMutability\": \"nonpayable\",\n            \"virtual\": false,\n            \"visibility\": \"external\"\n          },\n          {\n            \"body\": {\n              \"id\": 5008,\n              \"nodeType\": \"Block\",\n              \"src\": \"24995:294:6\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"commonType\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        },\n                        \"id\": 4979,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"leftExpression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 4976,\n                          \"name\": \"_earliestDelete\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 3764,\n                          \"src\": \"25013:15:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"nodeType\": \"BinaryOperation\",\n                        \"operator\": \">=\",\n                        \"rightExpression\": {\n                          \"argumentTypes\": null,\n                          \"arguments\": [],\n                          \"expression\": {\n                            \"argumentTypes\": [],\n                            \"id\": 4977,\n                            \"name\": \"_getBlockNumber\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 5019,\n                            \"src\": \"25032:15:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_function_internal_view$__$returns$_t_uint256_$\",\n                              \"typeString\": \"function () view returns (uint256)\"\n                            }\n                          },\n                          \"id\": 4978,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"kind\": \"functionCall\",\n                          \"lValueRequested\": false,\n                          \"names\": [],\n                          \"nodeType\": \"FunctionCall\",\n                          \"src\": \"25032:17:6\",\n                          \"tryCall\": false,\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"src\": \"25013:36:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"hexValue\": \"4561726c696573742064656c657465206e6f742072656163686564\",\n                        \"id\": 4980,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": true,\n                        \"kind\": \"string\",\n                        \"lValueRequested\": false,\n                        \"nodeType\": \"Literal\",\n                        \"src\": \"25051:29:6\",\n                        \"subdenomination\": null,\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_stringliteral_5f181249ab5034a5754d3db6b5f7492a28b118cbf69c6f93d3cfe542886db22a\",\n                          \"typeString\": \"literal_string \\\"Earliest delete not reached\\\"\"\n                        },\n                        \"value\": \"Earliest delete not reached\"\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_stringliteral_5f181249ab5034a5754d3db6b5f7492a28b118cbf69c6f93d3cfe542886db22a\",\n                          \"typeString\": \"literal_string \\\"Earliest delete not reached\\\"\"\n                        }\n                      ],\n                      \"id\": 4975,\n                      \"name\": \"require\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [\n                        -18,\n                        -18\n                      ],\n                      \"referencedDeclaration\": -18,\n                      \"src\": \"25005:7:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$\",\n                        \"typeString\": \"function (bool,string memory) pure\"\n                      }\n                    },\n                    \"id\": 4981,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"25005:76:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 4982,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"25005:76:6\"\n                },\n                {\n                  \"assignments\": [\n                    4984\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 4984,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"contractBalance\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 5008,\n                      \"src\": \"25091:23:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"default\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      },\n                      \"typeName\": {\n                        \"id\": 4983,\n                        \"name\": \"uint256\",\n                        \"nodeType\": \"ElementaryTypeName\",\n                        \"src\": \"25091:7:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 4992,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"arguments\": [\n                          {\n                            \"argumentTypes\": null,\n                            \"id\": 4989,\n                            \"name\": \"this\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": -28,\n                            \"src\": \"25142:4:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_contract$_Staking_$5490\",\n                              \"typeString\": \"contract Staking\"\n                            }\n                          }\n                        ],\n                        \"expression\": {\n                          \"argumentTypes\": [\n                            {\n                              \"typeIdentifier\": \"t_contract$_Staking_$5490\",\n                              \"typeString\": \"contract Staking\"\n                            }\n                          ],\n                          \"id\": 4988,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": true,\n                          \"lValueRequested\": false,\n                          \"nodeType\": \"ElementaryTypeNameExpression\",\n                          \"src\": \"25134:7:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_type$_t_address_$\",\n                            \"typeString\": \"type(address)\"\n                          },\n                          \"typeName\": {\n                            \"id\": 4987,\n                            \"name\": \"address\",\n                            \"nodeType\": \"ElementaryTypeName\",\n                            \"src\": \"25134:7:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": null,\n                              \"typeString\": null\n                            }\n                          }\n                        },\n                        \"id\": 4990,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"kind\": \"typeConversion\",\n                        \"lValueRequested\": false,\n                        \"names\": [],\n                        \"nodeType\": \"FunctionCall\",\n                        \"src\": \"25134:13:6\",\n                        \"tryCall\": false,\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        }\n                      ],\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 4985,\n                        \"name\": \"_token\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 3762,\n                        \"src\": \"25117:6:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_contract$_IERC20_$6707\",\n                          \"typeString\": \"contract IERC20\"\n                        }\n                      },\n                      \"id\": 4986,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"memberName\": \"balanceOf\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": 6646,\n                      \"src\": \"25117:16:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_external_view$_t_address_$returns$_t_uint256_$\",\n                        \"typeString\": \"function (address) view external returns (uint256)\"\n                      }\n                    },\n                    \"id\": 4991,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"25117:31:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"25091:57:6\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"arguments\": [\n                          {\n                            \"argumentTypes\": null,\n                            \"id\": 4996,\n                            \"name\": \"payoutAddress\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 4965,\n                            \"src\": \"25182:13:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_address_payable\",\n                              \"typeString\": \"address payable\"\n                            }\n                          },\n                          {\n                            \"argumentTypes\": null,\n                            \"id\": 4997,\n                            \"name\": \"contractBalance\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 4984,\n                            \"src\": \"25197:15:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          }\n                        ],\n                        \"expression\": {\n                          \"argumentTypes\": [\n                            {\n                              \"typeIdentifier\": \"t_address_payable\",\n                              \"typeString\": \"address payable\"\n                            },\n                            {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          ],\n                          \"expression\": {\n                            \"argumentTypes\": null,\n                            \"id\": 4994,\n                            \"name\": \"_token\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 3762,\n                            \"src\": \"25166:6:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_contract$_IERC20_$6707\",\n                              \"typeString\": \"contract IERC20\"\n                            }\n                          },\n                          \"id\": 4995,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"memberName\": \"transfer\",\n                          \"nodeType\": \"MemberAccess\",\n                          \"referencedDeclaration\": 6656,\n                          \"src\": \"25166:15:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_function_external_nonpayable$_t_address_$_t_uint256_$returns$_t_bool_$\",\n                            \"typeString\": \"function (address,uint256) external returns (bool)\"\n                          }\n                        },\n                        \"id\": 4998,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"kind\": \"functionCall\",\n                        \"lValueRequested\": false,\n                        \"names\": [],\n                        \"nodeType\": \"FunctionCall\",\n                        \"src\": \"25166:47:6\",\n                        \"tryCall\": false,\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        }\n                      ],\n                      \"id\": 4993,\n                      \"name\": \"require\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [\n                        -18,\n                        -18\n                      ],\n                      \"referencedDeclaration\": -18,\n                      \"src\": \"25158:7:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_require_pure$_t_bool_$returns$__$\",\n                        \"typeString\": \"function (bool) pure\"\n                      }\n                    },\n                    \"id\": 4999,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"25158:56:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 5000,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"25158:56:6\"\n                },\n                {\n                  \"eventCall\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [],\n                    \"expression\": {\n                      \"argumentTypes\": [],\n                      \"id\": 5001,\n                      \"name\": \"DeleteContract\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 3752,\n                      \"src\": \"25229:14:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_event_nonpayable$__$returns$__$\",\n                        \"typeString\": \"function ()\"\n                      }\n                    },\n                    \"id\": 5002,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"25229:16:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 5003,\n                  \"nodeType\": \"EmitStatement\",\n                  \"src\": \"25224:21:6\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 5005,\n                        \"name\": \"payoutAddress\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 4965,\n                        \"src\": \"25268:13:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        }\n                      ],\n                      \"id\": 5004,\n                      \"name\": \"selfdestruct\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": -21,\n                      \"src\": \"25255:12:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_selfdestruct_nonpayable$_t_address_payable_$returns$__$\",\n                        \"typeString\": \"function (address payable)\"\n                      }\n                    },\n                    \"id\": 5006,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"25255:27:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 5007,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"25255:27:6\"\n                }\n              ]\n            },\n            \"documentation\": {\n              \"id\": 4963,\n              \"nodeType\": \"StructuredDocumentation\",\n              \"src\": \"24523:312:6\",\n              \"text\": \"@notice Delete the contract, transfers the remaining token and ether balance to the specified\\npayoutAddress\\n@param payoutAddress address to transfer the balances to. Ensure that this is able to handle ERC20 tokens\\n@dev owner only + only on or after `_earliestDelete` block\"\n            },\n            \"functionSelector\": \"9608df4b\",\n            \"id\": 5009,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [\n              {\n                \"arguments\": [\n                  {\n                    \"argumentTypes\": null,\n                    \"id\": 4970,\n                    \"name\": \"txExpirationBlock\",\n                    \"nodeType\": \"Identifier\",\n                    \"overloadedDeclarations\": [],\n                    \"referencedDeclaration\": 4967,\n                    \"src\": \"24958:17:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  }\n                ],\n                \"id\": 4971,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 4969,\n                  \"name\": \"verifyTxExpiration\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 3836,\n                  \"src\": \"24939:18:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$_t_uint256_$\",\n                    \"typeString\": \"modifier (uint256)\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"24939:37:6\"\n              },\n              {\n                \"arguments\": null,\n                \"id\": 4973,\n                \"modifierName\": {\n                  \"argumentTypes\": null,\n                  \"id\": 4972,\n                  \"name\": \"onlyOwner\",\n                  \"nodeType\": \"Identifier\",\n                  \"overloadedDeclarations\": [],\n                  \"referencedDeclaration\": 3806,\n                  \"src\": \"24981:9:6\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_modifier$__$\",\n                    \"typeString\": \"modifier ()\"\n                  }\n                },\n                \"nodeType\": \"ModifierInvocation\",\n                \"src\": \"24981:9:6\"\n              }\n            ],\n            \"name\": \"deleteContract\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 4968,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 4965,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"payoutAddress\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 5009,\n                  \"src\": \"24864:29:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_address_payable\",\n                    \"typeString\": \"address payable\"\n                  },\n                  \"typeName\": {\n                    \"id\": 4964,\n                    \"name\": \"address\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"24864:15:6\",\n                    \"stateMutability\": \"payable\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address_payable\",\n                      \"typeString\": \"address payable\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 4967,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"txExpirationBlock\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 5009,\n                  \"src\": \"24895:25:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 4966,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"24895:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"24863:58:6\"\n            },\n            \"returnParameters\": {\n              \"id\": 4974,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"24995:0:6\"\n            },\n            \"scope\": 5490,\n            \"src\": \"24840:449:6\",\n            \"stateMutability\": \"nonpayable\",\n            \"virtual\": false,\n            \"visibility\": \"external\"\n          },\n          {\n            \"body\": {\n              \"id\": 5018,\n              \"nodeType\": \"Block\",\n              \"src\": \"25630:36:6\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"expression\": {\n                      \"argumentTypes\": null,\n                      \"id\": 5015,\n                      \"name\": \"block\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": -4,\n                      \"src\": \"25647:5:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_magic_block\",\n                        \"typeString\": \"block\"\n                      }\n                    },\n                    \"id\": 5016,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"memberName\": \"number\",\n                    \"nodeType\": \"MemberAccess\",\n                    \"referencedDeclaration\": null,\n                    \"src\": \"25647:12:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"functionReturnParameters\": 5014,\n                  \"id\": 5017,\n                  \"nodeType\": \"Return\",\n                  \"src\": \"25640:19:6\"\n                }\n              ]\n            },\n            \"documentation\": {\n              \"id\": 5010,\n              \"nodeType\": \"StructuredDocumentation\",\n              \"src\": \"25431:124:6\",\n              \"text\": \"@dev VIRTUAL Method returning bock number. Introduced for \\n     testing purposes (allows mocking).\"\n            },\n            \"id\": 5019,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [],\n            \"name\": \"_getBlockNumber\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 5011,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"25584:2:6\"\n            },\n            \"returnParameters\": {\n              \"id\": 5014,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 5013,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 5019,\n                  \"src\": \"25617:7:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 5012,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"25617:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"25616:9:6\"\n            },\n            \"scope\": 5490,\n            \"src\": \"25560:106:6\",\n            \"stateMutability\": \"view\",\n            \"virtual\": true,\n            \"visibility\": \"internal\"\n          },\n          {\n            \"body\": {\n              \"id\": 5030,\n              \"nodeType\": \"Block\",\n              \"src\": \"25721:63:6\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 5025,\n                        \"name\": \"DEFAULT_ADMIN_ROLE\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 5584,\n                        \"src\": \"25746:18:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_bytes32\",\n                          \"typeString\": \"bytes32\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 5026,\n                          \"name\": \"msg\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": -15,\n                          \"src\": \"25766:3:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_magic_message\",\n                            \"typeString\": \"msg\"\n                          }\n                        },\n                        \"id\": 5027,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"memberName\": \"sender\",\n                        \"nodeType\": \"MemberAccess\",\n                        \"referencedDeclaration\": null,\n                        \"src\": \"25766:10:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_bytes32\",\n                          \"typeString\": \"bytes32\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_address_payable\",\n                          \"typeString\": \"address payable\"\n                        }\n                      ],\n                      \"id\": 5024,\n                      \"name\": \"hasRole\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5630,\n                      \"src\": \"25738:7:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_view$_t_bytes32_$_t_address_$returns$_t_bool_$\",\n                        \"typeString\": \"function (bytes32,address) view returns (bool)\"\n                      }\n                    },\n                    \"id\": 5028,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"25738:39:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_bool\",\n                      \"typeString\": \"bool\"\n                    }\n                  },\n                  \"functionReturnParameters\": 5023,\n                  \"id\": 5029,\n                  \"nodeType\": \"Return\",\n                  \"src\": \"25731:46:6\"\n                }\n              ]\n            },\n            \"documentation\": null,\n            \"id\": 5031,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [],\n            \"name\": \"_isOwner\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 5020,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"25690:2:6\"\n            },\n            \"returnParameters\": {\n              \"id\": 5023,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 5022,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 5031,\n                  \"src\": \"25715:4:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_bool\",\n                    \"typeString\": \"bool\"\n                  },\n                  \"typeName\": {\n                    \"id\": 5021,\n                    \"name\": \"bool\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"25715:4:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_bool\",\n                      \"typeString\": \"bool\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"25714:6:6\"\n            },\n            \"scope\": 5490,\n            \"src\": \"25673:111:6\",\n            \"stateMutability\": \"view\",\n            \"virtual\": false,\n            \"visibility\": \"internal\"\n          },\n          {\n            \"body\": {\n              \"id\": 5063,\n              \"nodeType\": \"Block\",\n              \"src\": \"26069:336:6\",\n              \"statements\": [\n                {\n                  \"assignments\": [\n                    5038\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 5038,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"idx\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 5063,\n                      \"src\": \"26079:11:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"default\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      },\n                      \"typeName\": {\n                        \"id\": 5037,\n                        \"name\": \"uint256\",\n                        \"nodeType\": \"ElementaryTypeName\",\n                        \"src\": \"26079:7:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 5040,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"id\": 5039,\n                    \"name\": \"_interestRatesNextIdx\",\n                    \"nodeType\": \"Identifier\",\n                    \"overloadedDeclarations\": [],\n                    \"referencedDeclaration\": 3780,\n                    \"src\": \"26093:21:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"26079:35:6\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 5049,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"baseExpression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 5041,\n                        \"name\": \"_interestRates\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 3784,\n                        \"src\": \"26124:14:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_mapping$_t_uint256_$_t_struct$_InterestRatePerBlock_$3641_storage_$\",\n                          \"typeString\": \"mapping(uint256 => struct Staking.InterestRatePerBlock storage ref)\"\n                        }\n                      },\n                      \"id\": 5043,\n                      \"indexExpression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 5042,\n                        \"name\": \"idx\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 5038,\n                        \"src\": \"26139:3:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      \"isConstant\": false,\n                      \"isLValue\": true,\n                      \"isPure\": false,\n                      \"lValueRequested\": true,\n                      \"nodeType\": \"IndexAccess\",\n                      \"src\": \"26124:19:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_struct$_InterestRatePerBlock_$3641_storage\",\n                        \"typeString\": \"struct Staking.InterestRatePerBlock storage ref\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"arguments\": [\n                        {\n                          \"argumentTypes\": null,\n                          \"arguments\": [],\n                          \"expression\": {\n                            \"argumentTypes\": [],\n                            \"id\": 5045,\n                            \"name\": \"_getBlockNumber\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 5019,\n                            \"src\": \"26195:15:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_function_internal_view$__$returns$_t_uint256_$\",\n                              \"typeString\": \"function () view returns (uint256)\"\n                            }\n                          },\n                          \"id\": 5046,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"kind\": \"functionCall\",\n                          \"lValueRequested\": false,\n                          \"names\": [],\n                          \"nodeType\": \"FunctionCall\",\n                          \"src\": \"26195:17:6\",\n                          \"tryCall\": false,\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        {\n                          \"argumentTypes\": null,\n                          \"id\": 5047,\n                          \"name\": \"rate\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 5034,\n                          \"src\": \"26233:4:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        }\n                      ],\n                      \"expression\": {\n                        \"argumentTypes\": [\n                          {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          },\n                          {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        ],\n                        \"id\": 5044,\n                        \"name\": \"InterestRatePerBlock\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 3641,\n                        \"src\": \"26146:20:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_type$_t_struct$_InterestRatePerBlock_$3641_storage_ptr_$\",\n                          \"typeString\": \"type(struct Staking.InterestRatePerBlock storage pointer)\"\n                        }\n                      },\n                      \"id\": 5048,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": false,\n                      \"kind\": \"structConstructorCall\",\n                      \"lValueRequested\": false,\n                      \"names\": [\n                        \"sinceBlock\",\n                        \"rate\"\n                      ],\n                      \"nodeType\": \"FunctionCall\",\n                      \"src\": \"26146:148:6\",\n                      \"tryCall\": false,\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_struct$_InterestRatePerBlock_$3641_memory_ptr\",\n                        \"typeString\": \"struct Staking.InterestRatePerBlock memory\"\n                      }\n                    },\n                    \"src\": \"26124:170:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_struct$_InterestRatePerBlock_$3641_storage\",\n                      \"typeString\": \"struct Staking.InterestRatePerBlock storage ref\"\n                    }\n                  },\n                  \"id\": 5050,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"26124:170:6\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 5056,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 5051,\n                      \"name\": \"_interestRatesNextIdx\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 3780,\n                      \"src\": \"26304:21:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"arguments\": [\n                        {\n                          \"argumentTypes\": null,\n                          \"hexValue\": \"31\",\n                          \"id\": 5054,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": true,\n                          \"kind\": \"number\",\n                          \"lValueRequested\": false,\n                          \"nodeType\": \"Literal\",\n                          \"src\": \"26354:1:6\",\n                          \"subdenomination\": null,\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_rational_1_by_1\",\n                            \"typeString\": \"int_const 1\"\n                          },\n                          \"value\": \"1\"\n                        }\n                      ],\n                      \"expression\": {\n                        \"argumentTypes\": [\n                          {\n                            \"typeIdentifier\": \"t_rational_1_by_1\",\n                            \"typeString\": \"int_const 1\"\n                          }\n                        ],\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 5052,\n                          \"name\": \"_interestRatesNextIdx\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 3780,\n                          \"src\": \"26328:21:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"id\": 5053,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"memberName\": \"add\",\n                        \"nodeType\": \"MemberAccess\",\n                        \"referencedDeclaration\": 5870,\n                        \"src\": \"26328:25:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_function_internal_pure$_t_uint256_$_t_uint256_$returns$_t_uint256_$bound_to$_t_uint256_$\",\n                          \"typeString\": \"function (uint256,uint256) pure returns (uint256)\"\n                        }\n                      },\n                      \"id\": 5055,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": false,\n                      \"kind\": \"functionCall\",\n                      \"lValueRequested\": false,\n                      \"names\": [],\n                      \"nodeType\": \"FunctionCall\",\n                      \"src\": \"26328:28:6\",\n                      \"tryCall\": false,\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"src\": \"26304:52:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"id\": 5057,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"26304:52:6\"\n                },\n                {\n                  \"eventCall\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 5059,\n                        \"name\": \"idx\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 5038,\n                        \"src\": \"26388:3:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 5060,\n                        \"name\": \"rate\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 5034,\n                        \"src\": \"26393:4:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"id\": 5058,\n                      \"name\": \"NewInterestRate\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 3710,\n                      \"src\": \"26372:15:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_event_nonpayable$_t_uint256_$_t_uint256_$returns$__$\",\n                        \"typeString\": \"function (uint256,uint256)\"\n                      }\n                    },\n                    \"id\": 5061,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"26372:26:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 5062,\n                  \"nodeType\": \"EmitStatement\",\n                  \"src\": \"26367:31:6\"\n                }\n              ]\n            },\n            \"documentation\": {\n              \"id\": 5032,\n              \"nodeType\": \"StructuredDocumentation\",\n              \"src\": \"25791:219:6\",\n              \"text\": \"@notice Add new interest rate in to the ordered container of previously added interest rates\\n@param rate - signed interest rate value in [10**18] units => real_rate [1] = rate [10**18] / 10**18\"\n            },\n            \"id\": 5064,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [],\n            \"name\": \"_addInterestRate\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 5035,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 5034,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"rate\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 5064,\n                  \"src\": \"26041:12:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 5033,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"26041:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"26040:14:6\"\n            },\n            \"returnParameters\": {\n              \"id\": 5036,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"26069:0:6\"\n            },\n            \"scope\": 5490,\n            \"src\": \"26015:390:6\",\n            \"stateMutability\": \"nonpayable\",\n            \"virtual\": false,\n            \"visibility\": \"internal\"\n          },\n          {\n            \"body\": {\n              \"id\": 5078,\n              \"nodeType\": \"Block\",\n              \"src\": \"26582:88:6\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 5072,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 5070,\n                      \"name\": \"_lockPeriodInBlocks\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 3768,\n                      \"src\": \"26592:19:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint64\",\n                        \"typeString\": \"uint64\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 5071,\n                      \"name\": \"numOfBlocks\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5067,\n                      \"src\": \"26614:11:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint64\",\n                        \"typeString\": \"uint64\"\n                      }\n                    },\n                    \"src\": \"26592:33:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint64\",\n                      \"typeString\": \"uint64\"\n                    }\n                  },\n                  \"id\": 5073,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"26592:33:6\"\n                },\n                {\n                  \"eventCall\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 5075,\n                        \"name\": \"numOfBlocks\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 5067,\n                        \"src\": \"26651:11:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint64\",\n                          \"typeString\": \"uint64\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_uint64\",\n                          \"typeString\": \"uint64\"\n                        }\n                      ],\n                      \"id\": 5074,\n                      \"name\": \"LockPeriod\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 3722,\n                      \"src\": \"26640:10:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_event_nonpayable$_t_uint64_$returns$__$\",\n                        \"typeString\": \"function (uint64)\"\n                      }\n                    },\n                    \"id\": 5076,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"26640:23:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 5077,\n                  \"nodeType\": \"EmitStatement\",\n                  \"src\": \"26635:28:6\"\n                }\n              ]\n            },\n            \"documentation\": {\n              \"id\": 5065,\n              \"nodeType\": \"StructuredDocumentation\",\n              \"src\": \"26412:105:6\",\n              \"text\": \"@notice Updates Lock Period value\\n@param numOfBlocks  length of the lock period\"\n            },\n            \"id\": 5079,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [],\n            \"name\": \"_updateLockPeriod\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 5068,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 5067,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"numOfBlocks\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 5079,\n                  \"src\": \"26549:18:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint64\",\n                    \"typeString\": \"uint64\"\n                  },\n                  \"typeName\": {\n                    \"id\": 5066,\n                    \"name\": \"uint64\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"26549:6:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint64\",\n                      \"typeString\": \"uint64\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"26548:20:6\"\n            },\n            \"returnParameters\": {\n              \"id\": 5069,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"26582:0:6\"\n            },\n            \"scope\": 5490,\n            \"src\": \"26522:148:6\",\n            \"stateMutability\": \"nonpayable\",\n            \"virtual\": false,\n            \"visibility\": \"internal\"\n          },\n          {\n            \"body\": {\n              \"id\": 5103,\n              \"nodeType\": \"Block\",\n              \"src\": \"26989:199:6\",\n              \"statements\": [\n                {\n                  \"assignments\": [\n                    5086\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 5086,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"currentBlockNumber\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 5103,\n                      \"src\": \"26999:26:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"default\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      },\n                      \"typeName\": {\n                        \"id\": 5085,\n                        \"name\": \"uint256\",\n                        \"nodeType\": \"ElementaryTypeName\",\n                        \"src\": \"26999:7:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 5089,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [],\n                    \"expression\": {\n                      \"argumentTypes\": [],\n                      \"id\": 5087,\n                      \"name\": \"_getBlockNumber\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5019,\n                      \"src\": \"27028:15:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_view$__$returns$_t_uint256_$\",\n                        \"typeString\": \"function () view returns (uint256)\"\n                      }\n                    },\n                    \"id\": 5088,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"27028:17:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"26999:46:6\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 5097,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 5090,\n                      \"name\": \"_pausedSinceBlock\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 3766,\n                      \"src\": \"27055:17:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"condition\": {\n                        \"argumentTypes\": null,\n                        \"commonType\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        },\n                        \"id\": 5093,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"leftExpression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 5091,\n                          \"name\": \"blockNumber\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 5082,\n                          \"src\": \"27075:11:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"nodeType\": \"BinaryOperation\",\n                        \"operator\": \"<\",\n                        \"rightExpression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 5092,\n                          \"name\": \"currentBlockNumber\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 5086,\n                          \"src\": \"27089:18:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"src\": \"27075:32:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        }\n                      },\n                      \"falseExpression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 5095,\n                        \"name\": \"blockNumber\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 5082,\n                        \"src\": \"27131:11:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      \"id\": 5096,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"nodeType\": \"Conditional\",\n                      \"src\": \"27075:67:6\",\n                      \"trueExpression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 5094,\n                        \"name\": \"currentBlockNumber\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 5086,\n                        \"src\": \"27110:18:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"src\": \"27055:87:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"id\": 5098,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"27055:87:6\"\n                },\n                {\n                  \"eventCall\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 5100,\n                        \"name\": \"_pausedSinceBlock\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 3766,\n                        \"src\": \"27163:17:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"id\": 5099,\n                      \"name\": \"Pause\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 3726,\n                      \"src\": \"27157:5:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_event_nonpayable$_t_uint256_$returns$__$\",\n                        \"typeString\": \"function (uint256)\"\n                      }\n                    },\n                    \"id\": 5101,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"27157:24:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 5102,\n                  \"nodeType\": \"EmitStatement\",\n                  \"src\": \"27152:29:6\"\n                }\n              ]\n            },\n            \"documentation\": {\n              \"id\": 5080,\n              \"nodeType\": \"StructuredDocumentation\",\n              \"src\": \"26677:251:6\",\n              \"text\": \"@notice Pauses all NON-administrative interaction with the contract since the specidfed block number \\n@param blockNumber block number since which non-admin interaction will be paused (for all _getBlockNumber() >= blockNumber)\"\n            },\n            \"id\": 5104,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [],\n            \"name\": \"_pauseSince\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 5083,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 5082,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"blockNumber\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 5104,\n                  \"src\": \"26954:19:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 5081,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"26954:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"26953:21:6\"\n            },\n            \"returnParameters\": {\n              \"id\": 5084,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"26989:0:6\"\n            },\n            \"scope\": 5490,\n            \"src\": \"26933:255:6\",\n            \"stateMutability\": \"nonpayable\",\n            \"virtual\": false,\n            \"visibility\": \"internal\"\n          },\n          {\n            \"body\": {\n              \"id\": 5167,\n              \"nodeType\": \"Block\",\n              \"src\": \"27984:719:6\",\n              \"statements\": [\n                {\n                  \"condition\": {\n                    \"argumentTypes\": null,\n                    \"commonType\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    },\n                    \"id\": 5116,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftExpression\": {\n                      \"argumentTypes\": null,\n                      \"id\": 5114,\n                      \"name\": \"amount\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5111,\n                      \"src\": \"27999:6:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"BinaryOperation\",\n                    \"operator\": \"!=\",\n                    \"rightExpression\": {\n                      \"argumentTypes\": null,\n                      \"hexValue\": \"30\",\n                      \"id\": 5115,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": true,\n                      \"kind\": \"number\",\n                      \"lValueRequested\": false,\n                      \"nodeType\": \"Literal\",\n                      \"src\": \"28009:1:6\",\n                      \"subdenomination\": null,\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_rational_0_by_1\",\n                        \"typeString\": \"int_const 0\"\n                      },\n                      \"value\": \"0\"\n                    },\n                    \"src\": \"27999:11:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_bool\",\n                      \"typeString\": \"bool\"\n                    }\n                  },\n                  \"falseBody\": null,\n                  \"id\": 5166,\n                  \"nodeType\": \"IfStatement\",\n                  \"src\": \"27995:702:6\",\n                  \"trueBody\": {\n                    \"id\": 5165,\n                    \"nodeType\": \"Block\",\n                    \"src\": \"28012:685:6\",\n                    \"statements\": [\n                      {\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"arguments\": [\n                            {\n                              \"argumentTypes\": null,\n                              \"commonType\": {\n                                \"typeIdentifier\": \"t_uint256\",\n                                \"typeString\": \"uint256\"\n                              },\n                              \"id\": 5121,\n                              \"isConstant\": false,\n                              \"isLValue\": false,\n                              \"isPure\": false,\n                              \"lValueRequested\": false,\n                              \"leftExpression\": {\n                                \"argumentTypes\": null,\n                                \"id\": 5118,\n                                \"name\": \"_rewardsPoolBalance\",\n                                \"nodeType\": \"Identifier\",\n                                \"overloadedDeclarations\": [],\n                                \"referencedDeclaration\": 3770,\n                                \"src\": \"28034:19:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              },\n                              \"nodeType\": \"BinaryOperation\",\n                              \"operator\": \">=\",\n                              \"rightExpression\": {\n                                \"argumentTypes\": null,\n                                \"expression\": {\n                                  \"argumentTypes\": null,\n                                  \"id\": 5119,\n                                  \"name\": \"_amount\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 5109,\n                                  \"src\": \"28057:7:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                    \"typeString\": \"struct AssetLib.Asset memory\"\n                                  }\n                                },\n                                \"id\": 5120,\n                                \"isConstant\": false,\n                                \"isLValue\": true,\n                                \"isPure\": false,\n                                \"lValueRequested\": false,\n                                \"memberName\": \"compoundInterest\",\n                                \"nodeType\": \"MemberAccess\",\n                                \"referencedDeclaration\": 2787,\n                                \"src\": \"28057:24:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              },\n                              \"src\": \"28034:47:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_bool\",\n                                \"typeString\": \"bool\"\n                              }\n                            },\n                            {\n                              \"argumentTypes\": null,\n                              \"hexValue\": \"4e6f7420656e6f7567682066756e647320696e207265776172647320706f6f6c\",\n                              \"id\": 5122,\n                              \"isConstant\": false,\n                              \"isLValue\": false,\n                              \"isPure\": true,\n                              \"kind\": \"string\",\n                              \"lValueRequested\": false,\n                              \"nodeType\": \"Literal\",\n                              \"src\": \"28083:34:6\",\n                              \"subdenomination\": null,\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_stringliteral_eea74719e5ae8f4b294d08561dadf2343b6f65323137e057e863d77438841724\",\n                                \"typeString\": \"literal_string \\\"Not enough funds in rewards pool\\\"\"\n                              },\n                              \"value\": \"Not enough funds in rewards pool\"\n                            }\n                          ],\n                          \"expression\": {\n                            \"argumentTypes\": [\n                              {\n                                \"typeIdentifier\": \"t_bool\",\n                                \"typeString\": \"bool\"\n                              },\n                              {\n                                \"typeIdentifier\": \"t_stringliteral_eea74719e5ae8f4b294d08561dadf2343b6f65323137e057e863d77438841724\",\n                                \"typeString\": \"literal_string \\\"Not enough funds in rewards pool\\\"\"\n                              }\n                            ],\n                            \"id\": 5117,\n                            \"name\": \"require\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [\n                              -18,\n                              -18\n                            ],\n                            \"referencedDeclaration\": -18,\n                            \"src\": \"28026:7:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$\",\n                              \"typeString\": \"function (bool,string memory) pure\"\n                            }\n                          },\n                          \"id\": 5123,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"kind\": \"functionCall\",\n                          \"lValueRequested\": false,\n                          \"names\": [],\n                          \"nodeType\": \"FunctionCall\",\n                          \"src\": \"28026:92:6\",\n                          \"tryCall\": false,\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_tuple$__$\",\n                            \"typeString\": \"tuple()\"\n                          }\n                        },\n                        \"id\": 5124,\n                        \"nodeType\": \"ExpressionStatement\",\n                        \"src\": \"28026:92:6\"\n                      },\n                      {\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"arguments\": [\n                            {\n                              \"argumentTypes\": null,\n                              \"arguments\": [\n                                {\n                                  \"argumentTypes\": null,\n                                  \"id\": 5128,\n                                  \"name\": \"sender\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 5107,\n                                  \"src\": \"28156:6:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_address\",\n                                    \"typeString\": \"address\"\n                                  }\n                                },\n                                {\n                                  \"argumentTypes\": null,\n                                  \"id\": 5129,\n                                  \"name\": \"amount\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 5111,\n                                  \"src\": \"28164:6:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_uint256\",\n                                    \"typeString\": \"uint256\"\n                                  }\n                                }\n                              ],\n                              \"expression\": {\n                                \"argumentTypes\": [\n                                  {\n                                    \"typeIdentifier\": \"t_address\",\n                                    \"typeString\": \"address\"\n                                  },\n                                  {\n                                    \"typeIdentifier\": \"t_uint256\",\n                                    \"typeString\": \"uint256\"\n                                  }\n                                ],\n                                \"expression\": {\n                                  \"argumentTypes\": null,\n                                  \"id\": 5126,\n                                  \"name\": \"_token\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 3762,\n                                  \"src\": \"28140:6:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_contract$_IERC20_$6707\",\n                                    \"typeString\": \"contract IERC20\"\n                                  }\n                                },\n                                \"id\": 5127,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": false,\n                                \"lValueRequested\": false,\n                                \"memberName\": \"transfer\",\n                                \"nodeType\": \"MemberAccess\",\n                                \"referencedDeclaration\": 6656,\n                                \"src\": \"28140:15:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_function_external_nonpayable$_t_address_$_t_uint256_$returns$_t_bool_$\",\n                                  \"typeString\": \"function (address,uint256) external returns (bool)\"\n                                }\n                              },\n                              \"id\": 5130,\n                              \"isConstant\": false,\n                              \"isLValue\": false,\n                              \"isPure\": false,\n                              \"kind\": \"functionCall\",\n                              \"lValueRequested\": false,\n                              \"names\": [],\n                              \"nodeType\": \"FunctionCall\",\n                              \"src\": \"28140:31:6\",\n                              \"tryCall\": false,\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_bool\",\n                                \"typeString\": \"bool\"\n                              }\n                            },\n                            {\n                              \"argumentTypes\": null,\n                              \"hexValue\": \"5472616e73666572206661696c6564\",\n                              \"id\": 5131,\n                              \"isConstant\": false,\n                              \"isLValue\": false,\n                              \"isPure\": true,\n                              \"kind\": \"string\",\n                              \"lValueRequested\": false,\n                              \"nodeType\": \"Literal\",\n                              \"src\": \"28173:17:6\",\n                              \"subdenomination\": null,\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_stringliteral_25adaa6d082ce15f901e0d8a3d393e7462ef9edf2e6bc8321fa14d1615b6fc51\",\n                                \"typeString\": \"literal_string \\\"Transfer failed\\\"\"\n                              },\n                              \"value\": \"Transfer failed\"\n                            }\n                          ],\n                          \"expression\": {\n                            \"argumentTypes\": [\n                              {\n                                \"typeIdentifier\": \"t_bool\",\n                                \"typeString\": \"bool\"\n                              },\n                              {\n                                \"typeIdentifier\": \"t_stringliteral_25adaa6d082ce15f901e0d8a3d393e7462ef9edf2e6bc8321fa14d1615b6fc51\",\n                                \"typeString\": \"literal_string \\\"Transfer failed\\\"\"\n                              }\n                            ],\n                            \"id\": 5125,\n                            \"name\": \"require\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [\n                              -18,\n                              -18\n                            ],\n                            \"referencedDeclaration\": -18,\n                            \"src\": \"28132:7:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$\",\n                              \"typeString\": \"function (bool,string memory) pure\"\n                            }\n                          },\n                          \"id\": 5132,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"kind\": \"functionCall\",\n                          \"lValueRequested\": false,\n                          \"names\": [],\n                          \"nodeType\": \"FunctionCall\",\n                          \"src\": \"28132:59:6\",\n                          \"tryCall\": false,\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_tuple$__$\",\n                            \"typeString\": \"tuple()\"\n                          }\n                        },\n                        \"id\": 5133,\n                        \"nodeType\": \"ExpressionStatement\",\n                        \"src\": \"28132:59:6\"\n                      },\n                      {\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 5140,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"leftHandSide\": {\n                            \"argumentTypes\": null,\n                            \"id\": 5134,\n                            \"name\": \"_rewardsPoolBalance\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 3770,\n                            \"src\": \"28206:19:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"nodeType\": \"Assignment\",\n                          \"operator\": \"=\",\n                          \"rightHandSide\": {\n                            \"argumentTypes\": null,\n                            \"arguments\": [\n                              {\n                                \"argumentTypes\": null,\n                                \"expression\": {\n                                  \"argumentTypes\": null,\n                                  \"id\": 5137,\n                                  \"name\": \"_amount\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 5109,\n                                  \"src\": \"28252:7:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                    \"typeString\": \"struct AssetLib.Asset memory\"\n                                  }\n                                },\n                                \"id\": 5138,\n                                \"isConstant\": false,\n                                \"isLValue\": true,\n                                \"isPure\": false,\n                                \"lValueRequested\": false,\n                                \"memberName\": \"compoundInterest\",\n                                \"nodeType\": \"MemberAccess\",\n                                \"referencedDeclaration\": 2787,\n                                \"src\": \"28252:24:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              }\n                            ],\n                            \"expression\": {\n                              \"argumentTypes\": [\n                                {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              ],\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"id\": 5135,\n                                \"name\": \"_rewardsPoolBalance\",\n                                \"nodeType\": \"Identifier\",\n                                \"overloadedDeclarations\": [],\n                                \"referencedDeclaration\": 3770,\n                                \"src\": \"28228:19:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              },\n                              \"id\": 5136,\n                              \"isConstant\": false,\n                              \"isLValue\": false,\n                              \"isPure\": false,\n                              \"lValueRequested\": false,\n                              \"memberName\": \"sub\",\n                              \"nodeType\": \"MemberAccess\",\n                              \"referencedDeclaration\": 5887,\n                              \"src\": \"28228:23:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_function_internal_pure$_t_uint256_$_t_uint256_$returns$_t_uint256_$bound_to$_t_uint256_$\",\n                                \"typeString\": \"function (uint256,uint256) pure returns (uint256)\"\n                              }\n                            },\n                            \"id\": 5139,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": false,\n                            \"kind\": \"functionCall\",\n                            \"lValueRequested\": false,\n                            \"names\": [],\n                            \"nodeType\": \"FunctionCall\",\n                            \"src\": \"28228:49:6\",\n                            \"tryCall\": false,\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"src\": \"28206:71:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"id\": 5141,\n                        \"nodeType\": \"ExpressionStatement\",\n                        \"src\": \"28206:71:6\"\n                      },\n                      {\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 5148,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"leftHandSide\": {\n                            \"argumentTypes\": null,\n                            \"id\": 5142,\n                            \"name\": \"_accruedGlobalPrincipal\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 3772,\n                            \"src\": \"28291:23:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"nodeType\": \"Assignment\",\n                          \"operator\": \"=\",\n                          \"rightHandSide\": {\n                            \"argumentTypes\": null,\n                            \"arguments\": [\n                              {\n                                \"argumentTypes\": null,\n                                \"expression\": {\n                                  \"argumentTypes\": null,\n                                  \"id\": 5145,\n                                  \"name\": \"_amount\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 5109,\n                                  \"src\": \"28345:7:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                    \"typeString\": \"struct AssetLib.Asset memory\"\n                                  }\n                                },\n                                \"id\": 5146,\n                                \"isConstant\": false,\n                                \"isLValue\": true,\n                                \"isPure\": false,\n                                \"lValueRequested\": false,\n                                \"memberName\": \"principal\",\n                                \"nodeType\": \"MemberAccess\",\n                                \"referencedDeclaration\": 2785,\n                                \"src\": \"28345:17:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              }\n                            ],\n                            \"expression\": {\n                              \"argumentTypes\": [\n                                {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              ],\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"id\": 5143,\n                                \"name\": \"_accruedGlobalPrincipal\",\n                                \"nodeType\": \"Identifier\",\n                                \"overloadedDeclarations\": [],\n                                \"referencedDeclaration\": 3772,\n                                \"src\": \"28317:23:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              },\n                              \"id\": 5144,\n                              \"isConstant\": false,\n                              \"isLValue\": false,\n                              \"isPure\": false,\n                              \"lValueRequested\": false,\n                              \"memberName\": \"sub\",\n                              \"nodeType\": \"MemberAccess\",\n                              \"referencedDeclaration\": 5887,\n                              \"src\": \"28317:27:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_function_internal_pure$_t_uint256_$_t_uint256_$returns$_t_uint256_$bound_to$_t_uint256_$\",\n                                \"typeString\": \"function (uint256,uint256) pure returns (uint256)\"\n                              }\n                            },\n                            \"id\": 5147,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": false,\n                            \"kind\": \"functionCall\",\n                            \"lValueRequested\": false,\n                            \"names\": [],\n                            \"nodeType\": \"FunctionCall\",\n                            \"src\": \"28317:46:6\",\n                            \"tryCall\": false,\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"src\": \"28291:72:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"id\": 5149,\n                        \"nodeType\": \"ExpressionStatement\",\n                        \"src\": \"28291:72:6\"\n                      },\n                      {\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"arguments\": [\n                            {\n                              \"argumentTypes\": null,\n                              \"id\": 5153,\n                              \"name\": \"_amount\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 5109,\n                              \"src\": \"28406:7:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                \"typeString\": \"struct AssetLib.Asset memory\"\n                              }\n                            }\n                          ],\n                          \"expression\": {\n                            \"argumentTypes\": [\n                              {\n                                \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                \"typeString\": \"struct AssetLib.Asset memory\"\n                              }\n                            ],\n                            \"expression\": {\n                              \"argumentTypes\": null,\n                              \"id\": 5150,\n                              \"name\": \"_accruedGlobalLiquidity\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 3774,\n                              \"src\": \"28377:23:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                                \"typeString\": \"struct AssetLib.Asset storage ref\"\n                              }\n                            },\n                            \"id\": 5152,\n                            \"isConstant\": false,\n                            \"isLValue\": true,\n                            \"isPure\": false,\n                            \"lValueRequested\": false,\n                            \"memberName\": \"iSub\",\n                            \"nodeType\": \"MemberAccess\",\n                            \"referencedDeclaration\": 2938,\n                            \"src\": \"28377:28:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_function_internal_nonpayable$_t_struct$_Asset_$2788_storage_ptr_$_t_struct$_Asset_$2788_memory_ptr_$returns$__$bound_to$_t_struct$_Asset_$2788_storage_ptr_$\",\n                              \"typeString\": \"function (struct AssetLib.Asset storage pointer,struct AssetLib.Asset memory)\"\n                            }\n                          },\n                          \"id\": 5154,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"kind\": \"functionCall\",\n                          \"lValueRequested\": false,\n                          \"names\": [],\n                          \"nodeType\": \"FunctionCall\",\n                          \"src\": \"28377:37:6\",\n                          \"tryCall\": false,\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_tuple$__$\",\n                            \"typeString\": \"tuple()\"\n                          }\n                        },\n                        \"id\": 5155,\n                        \"nodeType\": \"ExpressionStatement\",\n                        \"src\": \"28377:37:6\"\n                      },\n                      {\n                        \"eventCall\": {\n                          \"argumentTypes\": null,\n                          \"arguments\": [\n                            {\n                              \"argumentTypes\": null,\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"id\": 5157,\n                                \"name\": \"msg\",\n                                \"nodeType\": \"Identifier\",\n                                \"overloadedDeclarations\": [],\n                                \"referencedDeclaration\": -15,\n                                \"src\": \"28629:3:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_magic_message\",\n                                  \"typeString\": \"msg\"\n                                }\n                              },\n                              \"id\": 5158,\n                              \"isConstant\": false,\n                              \"isLValue\": false,\n                              \"isPure\": false,\n                              \"lValueRequested\": false,\n                              \"memberName\": \"sender\",\n                              \"nodeType\": \"MemberAccess\",\n                              \"referencedDeclaration\": null,\n                              \"src\": \"28629:10:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_address_payable\",\n                                \"typeString\": \"address payable\"\n                              }\n                            },\n                            {\n                              \"argumentTypes\": null,\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"id\": 5159,\n                                \"name\": \"_amount\",\n                                \"nodeType\": \"Identifier\",\n                                \"overloadedDeclarations\": [],\n                                \"referencedDeclaration\": 5109,\n                                \"src\": \"28641:7:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                  \"typeString\": \"struct AssetLib.Asset memory\"\n                                }\n                              },\n                              \"id\": 5160,\n                              \"isConstant\": false,\n                              \"isLValue\": true,\n                              \"isPure\": false,\n                              \"lValueRequested\": false,\n                              \"memberName\": \"principal\",\n                              \"nodeType\": \"MemberAccess\",\n                              \"referencedDeclaration\": 2785,\n                              \"src\": \"28641:17:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_uint256\",\n                                \"typeString\": \"uint256\"\n                              }\n                            },\n                            {\n                              \"argumentTypes\": null,\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"id\": 5161,\n                                \"name\": \"_amount\",\n                                \"nodeType\": \"Identifier\",\n                                \"overloadedDeclarations\": [],\n                                \"referencedDeclaration\": 5109,\n                                \"src\": \"28660:7:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                  \"typeString\": \"struct AssetLib.Asset memory\"\n                                }\n                              },\n                              \"id\": 5162,\n                              \"isConstant\": false,\n                              \"isLValue\": true,\n                              \"isPure\": false,\n                              \"lValueRequested\": false,\n                              \"memberName\": \"compoundInterest\",\n                              \"nodeType\": \"MemberAccess\",\n                              \"referencedDeclaration\": 2787,\n                              \"src\": \"28660:24:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_uint256\",\n                                \"typeString\": \"uint256\"\n                              }\n                            }\n                          ],\n                          \"expression\": {\n                            \"argumentTypes\": [\n                              {\n                                \"typeIdentifier\": \"t_address_payable\",\n                                \"typeString\": \"address payable\"\n                              },\n                              {\n                                \"typeIdentifier\": \"t_uint256\",\n                                \"typeString\": \"uint256\"\n                              },\n                              {\n                                \"typeIdentifier\": \"t_uint256\",\n                                \"typeString\": \"uint256\"\n                              }\n                            ],\n                            \"id\": 5156,\n                            \"name\": \"Withdraw\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 3718,\n                            \"src\": \"28620:8:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_function_event_nonpayable$_t_address_$_t_uint256_$_t_uint256_$returns$__$\",\n                              \"typeString\": \"function (address,uint256,uint256)\"\n                            }\n                          },\n                          \"id\": 5163,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"kind\": \"functionCall\",\n                          \"lValueRequested\": false,\n                          \"names\": [],\n                          \"nodeType\": \"FunctionCall\",\n                          \"src\": \"28620:65:6\",\n                          \"tryCall\": false,\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_tuple$__$\",\n                            \"typeString\": \"tuple()\"\n                          }\n                        },\n                        \"id\": 5164,\n                        \"nodeType\": \"EmitStatement\",\n                        \"src\": \"28615:70:6\"\n                      }\n                    ]\n                  }\n                }\n              ]\n            },\n            \"documentation\": {\n              \"id\": 5105,\n              \"nodeType\": \"StructuredDocumentation\",\n              \"src\": \"27195:685:6\",\n              \"text\": \"@notice Withdraws amount from sender' available liquidity pool back to sender address,\\n        preferring withdrawal from compound interest dimension of liquidity.\\n     * @param amount - value to withdraw\\n     * @dev NOTE(pb): Passing redundant `uint256 amount` (on top of the `Asset _amount`) in the name\\n               of performance to avoid calculating it again from `_amount` (or the other way around).\\n               IMPLICATION: Caller **MUST** pass correct values, ensuring that `amount == _amount.composite()`,\\n               since this private method is **NOT** verifying this condition due to performance reasons.\"\n            },\n            \"id\": 5168,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [],\n            \"name\": \"_finaliseWithdraw\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 5112,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 5107,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"sender\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 5168,\n                  \"src\": \"27912:14:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_address\",\n                    \"typeString\": \"address\"\n                  },\n                  \"typeName\": {\n                    \"id\": 5106,\n                    \"name\": \"address\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"27912:7:6\",\n                    \"stateMutability\": \"nonpayable\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address\",\n                      \"typeString\": \"address\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 5109,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"_amount\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 5168,\n                  \"src\": \"27928:29:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"memory\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                    \"typeString\": \"struct AssetLib.Asset\"\n                  },\n                  \"typeName\": {\n                    \"contractScope\": null,\n                    \"id\": 5108,\n                    \"name\": \"AssetLib.Asset\",\n                    \"nodeType\": \"UserDefinedTypeName\",\n                    \"referencedDeclaration\": 2788,\n                    \"src\": \"27928:14:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                      \"typeString\": \"struct AssetLib.Asset\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 5111,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"amount\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 5168,\n                  \"src\": \"27959:14:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 5110,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"27959:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"27911:63:6\"\n            },\n            \"returnParameters\": {\n              \"id\": 5113,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [],\n              \"src\": \"27984:0:6\"\n            },\n            \"scope\": 5490,\n            \"src\": \"27885:818:6\",\n            \"stateMutability\": \"nonpayable\",\n            \"virtual\": false,\n            \"visibility\": \"internal\"\n          },\n          {\n            \"body\": {\n              \"id\": 5314,\n              \"nodeType\": \"Block\",\n              \"src\": \"28840:2765:6\",\n              \"statements\": [\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 5181,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 5177,\n                      \"name\": \"stake\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5175,\n                      \"src\": \"28850:5:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_struct$_Stake_$3648_storage_ptr\",\n                        \"typeString\": \"struct Staking.Stake storage pointer\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"baseExpression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 5178,\n                        \"name\": \"_stakes\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 3788,\n                        \"src\": \"28858:7:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_mapping$_t_address_$_t_struct$_Stake_$3648_storage_$\",\n                          \"typeString\": \"mapping(address => struct Staking.Stake storage ref)\"\n                        }\n                      },\n                      \"id\": 5180,\n                      \"indexExpression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 5179,\n                        \"name\": \"sender\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 5170,\n                        \"src\": \"28866:6:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        }\n                      },\n                      \"isConstant\": false,\n                      \"isLValue\": true,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"nodeType\": \"IndexAccess\",\n                      \"src\": \"28858:15:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_struct$_Stake_$3648_storage\",\n                        \"typeString\": \"struct Staking.Stake storage ref\"\n                      }\n                    },\n                    \"src\": \"28850:23:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_struct$_Stake_$3648_storage_ptr\",\n                      \"typeString\": \"struct Staking.Stake storage pointer\"\n                    }\n                  },\n                  \"id\": 5182,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"28850:23:6\"\n                },\n                {\n                  \"assignments\": [\n                    5184\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 5184,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"composite\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 5314,\n                      \"src\": \"28883:17:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"default\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      },\n                      \"typeName\": {\n                        \"id\": 5183,\n                        \"name\": \"uint256\",\n                        \"nodeType\": \"ElementaryTypeName\",\n                        \"src\": \"28883:7:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 5189,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [],\n                    \"expression\": {\n                      \"argumentTypes\": [],\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 5185,\n                          \"name\": \"stake\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 5175,\n                          \"src\": \"28903:5:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_struct$_Stake_$3648_storage_ptr\",\n                            \"typeString\": \"struct Staking.Stake storage pointer\"\n                          }\n                        },\n                        \"id\": 5186,\n                        \"isConstant\": false,\n                        \"isLValue\": true,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"memberName\": \"asset\",\n                        \"nodeType\": \"MemberAccess\",\n                        \"referencedDeclaration\": 3647,\n                        \"src\": \"28903:11:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                          \"typeString\": \"struct AssetLib.Asset storage ref\"\n                        }\n                      },\n                      \"id\": 5187,\n                      \"isConstant\": false,\n                      \"isLValue\": true,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"memberName\": \"composite\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": 2803,\n                      \"src\": \"28903:21:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_internal_view$_t_struct$_Asset_$2788_storage_ptr_$returns$_t_uint256_$bound_to$_t_struct$_Asset_$2788_storage_ptr_$\",\n                        \"typeString\": \"function (struct AssetLib.Asset storage pointer) view returns (uint256)\"\n                      }\n                    },\n                    \"id\": 5188,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"28903:23:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"28883:43:6\"\n                },\n                {\n                  \"condition\": {\n                    \"argumentTypes\": null,\n                    \"commonType\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    },\n                    \"id\": 5192,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftExpression\": {\n                      \"argumentTypes\": null,\n                      \"id\": 5190,\n                      \"name\": \"composite\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5184,\n                      \"src\": \"28940:9:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"BinaryOperation\",\n                    \"operator\": \"!=\",\n                    \"rightExpression\": {\n                      \"argumentTypes\": null,\n                      \"hexValue\": \"30\",\n                      \"id\": 5191,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": true,\n                      \"kind\": \"number\",\n                      \"lValueRequested\": false,\n                      \"nodeType\": \"Literal\",\n                      \"src\": \"28953:1:6\",\n                      \"subdenomination\": null,\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_rational_0_by_1\",\n                        \"typeString\": \"int_const 0\"\n                      },\n                      \"value\": \"0\"\n                    },\n                    \"src\": \"28940:14:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_bool\",\n                      \"typeString\": \"bool\"\n                    }\n                  },\n                  \"falseBody\": null,\n                  \"id\": 5281,\n                  \"nodeType\": \"IfStatement\",\n                  \"src\": \"28936:1369:6\",\n                  \"trueBody\": {\n                    \"id\": 5280,\n                    \"nodeType\": \"Block\",\n                    \"src\": \"28964:1341:6\",\n                    \"statements\": [\n                      {\n                        \"assignments\": [\n                          5194\n                        ],\n                        \"declarations\": [\n                          {\n                            \"constant\": false,\n                            \"id\": 5194,\n                            \"mutability\": \"mutable\",\n                            \"name\": \"start_block\",\n                            \"nodeType\": \"VariableDeclaration\",\n                            \"overrides\": null,\n                            \"scope\": 5280,\n                            \"src\": \"29048:19:6\",\n                            \"stateVariable\": false,\n                            \"storageLocation\": \"default\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            },\n                            \"typeName\": {\n                              \"id\": 5193,\n                              \"name\": \"uint256\",\n                              \"nodeType\": \"ElementaryTypeName\",\n                              \"src\": \"29048:7:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_uint256\",\n                                \"typeString\": \"uint256\"\n                              }\n                            },\n                            \"value\": null,\n                            \"visibility\": \"internal\"\n                          }\n                        ],\n                        \"id\": 5197,\n                        \"initialValue\": {\n                          \"argumentTypes\": null,\n                          \"expression\": {\n                            \"argumentTypes\": null,\n                            \"id\": 5195,\n                            \"name\": \"stake\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 5175,\n                            \"src\": \"29070:5:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_struct$_Stake_$3648_storage_ptr\",\n                              \"typeString\": \"struct Staking.Stake storage pointer\"\n                            }\n                          },\n                          \"id\": 5196,\n                          \"isConstant\": false,\n                          \"isLValue\": true,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"memberName\": \"sinceBlock\",\n                          \"nodeType\": \"MemberAccess\",\n                          \"referencedDeclaration\": 3643,\n                          \"src\": \"29070:16:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"nodeType\": \"VariableDeclarationStatement\",\n                        \"src\": \"29048:38:6\"\n                      },\n                      {\n                        \"body\": {\n                          \"id\": 5265,\n                          \"nodeType\": \"Block\",\n                          \"src\": \"29411:802:6\",\n                          \"statements\": [\n                            {\n                              \"assignments\": [\n                                5210\n                              ],\n                              \"declarations\": [\n                                {\n                                  \"constant\": false,\n                                  \"id\": 5210,\n                                  \"mutability\": \"mutable\",\n                                  \"name\": \"interest\",\n                                  \"nodeType\": \"VariableDeclaration\",\n                                  \"overrides\": null,\n                                  \"scope\": 5265,\n                                  \"src\": \"29429:37:6\",\n                                  \"stateVariable\": false,\n                                  \"storageLocation\": \"storage\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_struct$_InterestRatePerBlock_$3641_storage_ptr\",\n                                    \"typeString\": \"struct Staking.InterestRatePerBlock\"\n                                  },\n                                  \"typeName\": {\n                                    \"contractScope\": null,\n                                    \"id\": 5209,\n                                    \"name\": \"InterestRatePerBlock\",\n                                    \"nodeType\": \"UserDefinedTypeName\",\n                                    \"referencedDeclaration\": 3641,\n                                    \"src\": \"29429:20:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_struct$_InterestRatePerBlock_$3641_storage_ptr\",\n                                      \"typeString\": \"struct Staking.InterestRatePerBlock\"\n                                    }\n                                  },\n                                  \"value\": null,\n                                  \"visibility\": \"internal\"\n                                }\n                              ],\n                              \"id\": 5214,\n                              \"initialValue\": {\n                                \"argumentTypes\": null,\n                                \"baseExpression\": {\n                                  \"argumentTypes\": null,\n                                  \"id\": 5211,\n                                  \"name\": \"_interestRates\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 3784,\n                                  \"src\": \"29469:14:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_mapping$_t_uint256_$_t_struct$_InterestRatePerBlock_$3641_storage_$\",\n                                    \"typeString\": \"mapping(uint256 => struct Staking.InterestRatePerBlock storage ref)\"\n                                  }\n                                },\n                                \"id\": 5213,\n                                \"indexExpression\": {\n                                  \"argumentTypes\": null,\n                                  \"id\": 5212,\n                                  \"name\": \"i\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 5199,\n                                  \"src\": \"29484:1:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_uint256\",\n                                    \"typeString\": \"uint256\"\n                                  }\n                                },\n                                \"isConstant\": false,\n                                \"isLValue\": true,\n                                \"isPure\": false,\n                                \"lValueRequested\": false,\n                                \"nodeType\": \"IndexAccess\",\n                                \"src\": \"29469:17:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_struct$_InterestRatePerBlock_$3641_storage\",\n                                  \"typeString\": \"struct Staking.InterestRatePerBlock storage ref\"\n                                }\n                              },\n                              \"nodeType\": \"VariableDeclarationStatement\",\n                              \"src\": \"29429:57:6\"\n                            },\n                            {\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"arguments\": [\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"commonType\": {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    },\n                                    \"id\": 5219,\n                                    \"isConstant\": false,\n                                    \"isLValue\": false,\n                                    \"isPure\": false,\n                                    \"lValueRequested\": false,\n                                    \"leftExpression\": {\n                                      \"argumentTypes\": null,\n                                      \"expression\": {\n                                        \"argumentTypes\": null,\n                                        \"id\": 5216,\n                                        \"name\": \"interest\",\n                                        \"nodeType\": \"Identifier\",\n                                        \"overloadedDeclarations\": [],\n                                        \"referencedDeclaration\": 5210,\n                                        \"src\": \"29697:8:6\",\n                                        \"typeDescriptions\": {\n                                          \"typeIdentifier\": \"t_struct$_InterestRatePerBlock_$3641_storage_ptr\",\n                                          \"typeString\": \"struct Staking.InterestRatePerBlock storage pointer\"\n                                        }\n                                      },\n                                      \"id\": 5217,\n                                      \"isConstant\": false,\n                                      \"isLValue\": true,\n                                      \"isPure\": false,\n                                      \"lValueRequested\": false,\n                                      \"memberName\": \"sinceBlock\",\n                                      \"nodeType\": \"MemberAccess\",\n                                      \"referencedDeclaration\": 3638,\n                                      \"src\": \"29697:19:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_uint256\",\n                                        \"typeString\": \"uint256\"\n                                      }\n                                    },\n                                    \"nodeType\": \"BinaryOperation\",\n                                    \"operator\": \"<=\",\n                                    \"rightExpression\": {\n                                      \"argumentTypes\": null,\n                                      \"id\": 5218,\n                                      \"name\": \"start_block\",\n                                      \"nodeType\": \"Identifier\",\n                                      \"overloadedDeclarations\": [],\n                                      \"referencedDeclaration\": 5194,\n                                      \"src\": \"29720:11:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_uint256\",\n                                        \"typeString\": \"uint256\"\n                                      }\n                                    },\n                                    \"src\": \"29697:34:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_bool\",\n                                      \"typeString\": \"bool\"\n                                    }\n                                  },\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"hexValue\": \"73696e6365426c6f636b20696e636f6e73697374656e6379\",\n                                    \"id\": 5220,\n                                    \"isConstant\": false,\n                                    \"isLValue\": false,\n                                    \"isPure\": true,\n                                    \"kind\": \"string\",\n                                    \"lValueRequested\": false,\n                                    \"nodeType\": \"Literal\",\n                                    \"src\": \"29733:26:6\",\n                                    \"subdenomination\": null,\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_stringliteral_0b30ca9f63e0c2596e072157a3416c4519a0da0c7a77930c294d44b40e819c8c\",\n                                      \"typeString\": \"literal_string \\\"sinceBlock inconsistency\\\"\"\n                                    },\n                                    \"value\": \"sinceBlock inconsistency\"\n                                  }\n                                ],\n                                \"expression\": {\n                                  \"argumentTypes\": [\n                                    {\n                                      \"typeIdentifier\": \"t_bool\",\n                                      \"typeString\": \"bool\"\n                                    },\n                                    {\n                                      \"typeIdentifier\": \"t_stringliteral_0b30ca9f63e0c2596e072157a3416c4519a0da0c7a77930c294d44b40e819c8c\",\n                                      \"typeString\": \"literal_string \\\"sinceBlock inconsistency\\\"\"\n                                    }\n                                  ],\n                                  \"id\": 5215,\n                                  \"name\": \"require\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [\n                                    -18,\n                                    -18\n                                  ],\n                                  \"referencedDeclaration\": -18,\n                                  \"src\": \"29689:7:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$\",\n                                    \"typeString\": \"function (bool,string memory) pure\"\n                                  }\n                                },\n                                \"id\": 5221,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": false,\n                                \"kind\": \"functionCall\",\n                                \"lValueRequested\": false,\n                                \"names\": [],\n                                \"nodeType\": \"FunctionCall\",\n                                \"src\": \"29689:71:6\",\n                                \"tryCall\": false,\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_tuple$__$\",\n                                  \"typeString\": \"tuple()\"\n                                }\n                              },\n                              \"id\": 5222,\n                              \"nodeType\": \"ExpressionStatement\",\n                              \"src\": \"29689:71:6\"\n                            },\n                            {\n                              \"assignments\": [\n                                5224\n                              ],\n                              \"declarations\": [\n                                {\n                                  \"constant\": false,\n                                  \"id\": 5224,\n                                  \"mutability\": \"mutable\",\n                                  \"name\": \"end_block\",\n                                  \"nodeType\": \"VariableDeclaration\",\n                                  \"overrides\": null,\n                                  \"scope\": 5265,\n                                  \"src\": \"29778:17:6\",\n                                  \"stateVariable\": false,\n                                  \"storageLocation\": \"default\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_uint256\",\n                                    \"typeString\": \"uint256\"\n                                  },\n                                  \"typeName\": {\n                                    \"id\": 5223,\n                                    \"name\": \"uint256\",\n                                    \"nodeType\": \"ElementaryTypeName\",\n                                    \"src\": \"29778:7:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    }\n                                  },\n                                  \"value\": null,\n                                  \"visibility\": \"internal\"\n                                }\n                              ],\n                              \"id\": 5226,\n                              \"initialValue\": {\n                                \"argumentTypes\": null,\n                                \"id\": 5225,\n                                \"name\": \"at_block\",\n                                \"nodeType\": \"Identifier\",\n                                \"overloadedDeclarations\": [],\n                                \"referencedDeclaration\": 5172,\n                                \"src\": \"29798:8:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              },\n                              \"nodeType\": \"VariableDeclarationStatement\",\n                              \"src\": \"29778:28:6\"\n                            },\n                            {\n                              \"assignments\": [\n                                5228\n                              ],\n                              \"declarations\": [\n                                {\n                                  \"constant\": false,\n                                  \"id\": 5228,\n                                  \"mutability\": \"mutable\",\n                                  \"name\": \"j\",\n                                  \"nodeType\": \"VariableDeclaration\",\n                                  \"overrides\": null,\n                                  \"scope\": 5265,\n                                  \"src\": \"29825:9:6\",\n                                  \"stateVariable\": false,\n                                  \"storageLocation\": \"default\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_uint256\",\n                                    \"typeString\": \"uint256\"\n                                  },\n                                  \"typeName\": {\n                                    \"id\": 5227,\n                                    \"name\": \"uint256\",\n                                    \"nodeType\": \"ElementaryTypeName\",\n                                    \"src\": \"29825:7:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    }\n                                  },\n                                  \"value\": null,\n                                  \"visibility\": \"internal\"\n                                }\n                              ],\n                              \"id\": 5232,\n                              \"initialValue\": {\n                                \"argumentTypes\": null,\n                                \"commonType\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                },\n                                \"id\": 5231,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": false,\n                                \"lValueRequested\": false,\n                                \"leftExpression\": {\n                                  \"argumentTypes\": null,\n                                  \"id\": 5229,\n                                  \"name\": \"i\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 5199,\n                                  \"src\": \"29837:1:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_uint256\",\n                                    \"typeString\": \"uint256\"\n                                  }\n                                },\n                                \"nodeType\": \"BinaryOperation\",\n                                \"operator\": \"+\",\n                                \"rightExpression\": {\n                                  \"argumentTypes\": null,\n                                  \"hexValue\": \"31\",\n                                  \"id\": 5230,\n                                  \"isConstant\": false,\n                                  \"isLValue\": false,\n                                  \"isPure\": true,\n                                  \"kind\": \"number\",\n                                  \"lValueRequested\": false,\n                                  \"nodeType\": \"Literal\",\n                                  \"src\": \"29841:1:6\",\n                                  \"subdenomination\": null,\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_rational_1_by_1\",\n                                    \"typeString\": \"int_const 1\"\n                                  },\n                                  \"value\": \"1\"\n                                },\n                                \"src\": \"29837:5:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              },\n                              \"nodeType\": \"VariableDeclarationStatement\",\n                              \"src\": \"29825:17:6\"\n                            },\n                            {\n                              \"condition\": {\n                                \"argumentTypes\": null,\n                                \"commonType\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                },\n                                \"id\": 5235,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": false,\n                                \"lValueRequested\": false,\n                                \"leftExpression\": {\n                                  \"argumentTypes\": null,\n                                  \"id\": 5233,\n                                  \"name\": \"j\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 5228,\n                                  \"src\": \"29864:1:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_uint256\",\n                                    \"typeString\": \"uint256\"\n                                  }\n                                },\n                                \"nodeType\": \"BinaryOperation\",\n                                \"operator\": \"<\",\n                                \"rightExpression\": {\n                                  \"argumentTypes\": null,\n                                  \"id\": 5234,\n                                  \"name\": \"_interestRatesNextIdx\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 3780,\n                                  \"src\": \"29868:21:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_uint256\",\n                                    \"typeString\": \"uint256\"\n                                  }\n                                },\n                                \"src\": \"29864:25:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_bool\",\n                                  \"typeString\": \"bool\"\n                                }\n                              },\n                              \"falseBody\": null,\n                              \"id\": 5248,\n                              \"nodeType\": \"IfStatement\",\n                              \"src\": \"29860:192:6\",\n                              \"trueBody\": {\n                                \"id\": 5247,\n                                \"nodeType\": \"Block\",\n                                \"src\": \"29891:161:6\",\n                                \"statements\": [\n                                  {\n                                    \"assignments\": [\n                                      5237\n                                    ],\n                                    \"declarations\": [\n                                      {\n                                        \"constant\": false,\n                                        \"id\": 5237,\n                                        \"mutability\": \"mutable\",\n                                        \"name\": \"next_interest\",\n                                        \"nodeType\": \"VariableDeclaration\",\n                                        \"overrides\": null,\n                                        \"scope\": 5247,\n                                        \"src\": \"29913:42:6\",\n                                        \"stateVariable\": false,\n                                        \"storageLocation\": \"storage\",\n                                        \"typeDescriptions\": {\n                                          \"typeIdentifier\": \"t_struct$_InterestRatePerBlock_$3641_storage_ptr\",\n                                          \"typeString\": \"struct Staking.InterestRatePerBlock\"\n                                        },\n                                        \"typeName\": {\n                                          \"contractScope\": null,\n                                          \"id\": 5236,\n                                          \"name\": \"InterestRatePerBlock\",\n                                          \"nodeType\": \"UserDefinedTypeName\",\n                                          \"referencedDeclaration\": 3641,\n                                          \"src\": \"29913:20:6\",\n                                          \"typeDescriptions\": {\n                                            \"typeIdentifier\": \"t_struct$_InterestRatePerBlock_$3641_storage_ptr\",\n                                            \"typeString\": \"struct Staking.InterestRatePerBlock\"\n                                          }\n                                        },\n                                        \"value\": null,\n                                        \"visibility\": \"internal\"\n                                      }\n                                    ],\n                                    \"id\": 5241,\n                                    \"initialValue\": {\n                                      \"argumentTypes\": null,\n                                      \"baseExpression\": {\n                                        \"argumentTypes\": null,\n                                        \"id\": 5238,\n                                        \"name\": \"_interestRates\",\n                                        \"nodeType\": \"Identifier\",\n                                        \"overloadedDeclarations\": [],\n                                        \"referencedDeclaration\": 3784,\n                                        \"src\": \"29958:14:6\",\n                                        \"typeDescriptions\": {\n                                          \"typeIdentifier\": \"t_mapping$_t_uint256_$_t_struct$_InterestRatePerBlock_$3641_storage_$\",\n                                          \"typeString\": \"mapping(uint256 => struct Staking.InterestRatePerBlock storage ref)\"\n                                        }\n                                      },\n                                      \"id\": 5240,\n                                      \"indexExpression\": {\n                                        \"argumentTypes\": null,\n                                        \"id\": 5239,\n                                        \"name\": \"j\",\n                                        \"nodeType\": \"Identifier\",\n                                        \"overloadedDeclarations\": [],\n                                        \"referencedDeclaration\": 5228,\n                                        \"src\": \"29973:1:6\",\n                                        \"typeDescriptions\": {\n                                          \"typeIdentifier\": \"t_uint256\",\n                                          \"typeString\": \"uint256\"\n                                        }\n                                      },\n                                      \"isConstant\": false,\n                                      \"isLValue\": true,\n                                      \"isPure\": false,\n                                      \"lValueRequested\": false,\n                                      \"nodeType\": \"IndexAccess\",\n                                      \"src\": \"29958:17:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_struct$_InterestRatePerBlock_$3641_storage\",\n                                        \"typeString\": \"struct Staking.InterestRatePerBlock storage ref\"\n                                      }\n                                    },\n                                    \"nodeType\": \"VariableDeclarationStatement\",\n                                    \"src\": \"29913:62:6\"\n                                  },\n                                  {\n                                    \"expression\": {\n                                      \"argumentTypes\": null,\n                                      \"id\": 5245,\n                                      \"isConstant\": false,\n                                      \"isLValue\": false,\n                                      \"isPure\": false,\n                                      \"lValueRequested\": false,\n                                      \"leftHandSide\": {\n                                        \"argumentTypes\": null,\n                                        \"id\": 5242,\n                                        \"name\": \"end_block\",\n                                        \"nodeType\": \"Identifier\",\n                                        \"overloadedDeclarations\": [],\n                                        \"referencedDeclaration\": 5224,\n                                        \"src\": \"29997:9:6\",\n                                        \"typeDescriptions\": {\n                                          \"typeIdentifier\": \"t_uint256\",\n                                          \"typeString\": \"uint256\"\n                                        }\n                                      },\n                                      \"nodeType\": \"Assignment\",\n                                      \"operator\": \"=\",\n                                      \"rightHandSide\": {\n                                        \"argumentTypes\": null,\n                                        \"expression\": {\n                                          \"argumentTypes\": null,\n                                          \"id\": 5243,\n                                          \"name\": \"next_interest\",\n                                          \"nodeType\": \"Identifier\",\n                                          \"overloadedDeclarations\": [],\n                                          \"referencedDeclaration\": 5237,\n                                          \"src\": \"30009:13:6\",\n                                          \"typeDescriptions\": {\n                                            \"typeIdentifier\": \"t_struct$_InterestRatePerBlock_$3641_storage_ptr\",\n                                            \"typeString\": \"struct Staking.InterestRatePerBlock storage pointer\"\n                                          }\n                                        },\n                                        \"id\": 5244,\n                                        \"isConstant\": false,\n                                        \"isLValue\": true,\n                                        \"isPure\": false,\n                                        \"lValueRequested\": false,\n                                        \"memberName\": \"sinceBlock\",\n                                        \"nodeType\": \"MemberAccess\",\n                                        \"referencedDeclaration\": 3638,\n                                        \"src\": \"30009:24:6\",\n                                        \"typeDescriptions\": {\n                                          \"typeIdentifier\": \"t_uint256\",\n                                          \"typeString\": \"uint256\"\n                                        }\n                                      },\n                                      \"src\": \"29997:36:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_uint256\",\n                                        \"typeString\": \"uint256\"\n                                      }\n                                    },\n                                    \"id\": 5246,\n                                    \"nodeType\": \"ExpressionStatement\",\n                                    \"src\": \"29997:36:6\"\n                                  }\n                                ]\n                              }\n                            },\n                            {\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"id\": 5259,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": false,\n                                \"lValueRequested\": false,\n                                \"leftHandSide\": {\n                                  \"argumentTypes\": null,\n                                  \"id\": 5249,\n                                  \"name\": \"composite\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 5184,\n                                  \"src\": \"30070:9:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_uint256\",\n                                    \"typeString\": \"uint256\"\n                                  }\n                                },\n                                \"nodeType\": \"Assignment\",\n                                \"operator\": \"=\",\n                                \"rightHandSide\": {\n                                  \"argumentTypes\": null,\n                                  \"arguments\": [\n                                    {\n                                      \"argumentTypes\": null,\n                                      \"id\": 5252,\n                                      \"name\": \"composite\",\n                                      \"nodeType\": \"Identifier\",\n                                      \"overloadedDeclarations\": [],\n                                      \"referencedDeclaration\": 5184,\n                                      \"src\": \"30107:9:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_uint256\",\n                                        \"typeString\": \"uint256\"\n                                      }\n                                    },\n                                    {\n                                      \"argumentTypes\": null,\n                                      \"expression\": {\n                                        \"argumentTypes\": null,\n                                        \"id\": 5253,\n                                        \"name\": \"interest\",\n                                        \"nodeType\": \"Identifier\",\n                                        \"overloadedDeclarations\": [],\n                                        \"referencedDeclaration\": 5210,\n                                        \"src\": \"30118:8:6\",\n                                        \"typeDescriptions\": {\n                                          \"typeIdentifier\": \"t_struct$_InterestRatePerBlock_$3641_storage_ptr\",\n                                          \"typeString\": \"struct Staking.InterestRatePerBlock storage pointer\"\n                                        }\n                                      },\n                                      \"id\": 5254,\n                                      \"isConstant\": false,\n                                      \"isLValue\": true,\n                                      \"isPure\": false,\n                                      \"lValueRequested\": false,\n                                      \"memberName\": \"rate\",\n                                      \"nodeType\": \"MemberAccess\",\n                                      \"referencedDeclaration\": 3640,\n                                      \"src\": \"30118:13:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_uint256\",\n                                        \"typeString\": \"uint256\"\n                                      }\n                                    },\n                                    {\n                                      \"argumentTypes\": null,\n                                      \"commonType\": {\n                                        \"typeIdentifier\": \"t_uint256\",\n                                        \"typeString\": \"uint256\"\n                                      },\n                                      \"id\": 5257,\n                                      \"isConstant\": false,\n                                      \"isLValue\": false,\n                                      \"isPure\": false,\n                                      \"lValueRequested\": false,\n                                      \"leftExpression\": {\n                                        \"argumentTypes\": null,\n                                        \"id\": 5255,\n                                        \"name\": \"end_block\",\n                                        \"nodeType\": \"Identifier\",\n                                        \"overloadedDeclarations\": [],\n                                        \"referencedDeclaration\": 5224,\n                                        \"src\": \"30133:9:6\",\n                                        \"typeDescriptions\": {\n                                          \"typeIdentifier\": \"t_uint256\",\n                                          \"typeString\": \"uint256\"\n                                        }\n                                      },\n                                      \"nodeType\": \"BinaryOperation\",\n                                      \"operator\": \"-\",\n                                      \"rightExpression\": {\n                                        \"argumentTypes\": null,\n                                        \"id\": 5256,\n                                        \"name\": \"start_block\",\n                                        \"nodeType\": \"Identifier\",\n                                        \"overloadedDeclarations\": [],\n                                        \"referencedDeclaration\": 5194,\n                                        \"src\": \"30145:11:6\",\n                                        \"typeDescriptions\": {\n                                          \"typeIdentifier\": \"t_uint256\",\n                                          \"typeString\": \"uint256\"\n                                        }\n                                      },\n                                      \"src\": \"30133:23:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_uint256\",\n                                        \"typeString\": \"uint256\"\n                                      }\n                                    }\n                                  ],\n                                  \"expression\": {\n                                    \"argumentTypes\": [\n                                      {\n                                        \"typeIdentifier\": \"t_uint256\",\n                                        \"typeString\": \"uint256\"\n                                      },\n                                      {\n                                        \"typeIdentifier\": \"t_uint256\",\n                                        \"typeString\": \"uint256\"\n                                      },\n                                      {\n                                        \"typeIdentifier\": \"t_uint256\",\n                                        \"typeString\": \"uint256\"\n                                      }\n                                    ],\n                                    \"expression\": {\n                                      \"argumentTypes\": null,\n                                      \"id\": 5250,\n                                      \"name\": \"Finance\",\n                                      \"nodeType\": \"Identifier\",\n                                      \"overloadedDeclarations\": [],\n                                      \"referencedDeclaration\": 3318,\n                                      \"src\": \"30082:7:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_type$_t_contract$_Finance_$3318_$\",\n                                        \"typeString\": \"type(library Finance)\"\n                                      }\n                                    },\n                                    \"id\": 5251,\n                                    \"isConstant\": false,\n                                    \"isLValue\": false,\n                                    \"isPure\": false,\n                                    \"lValueRequested\": false,\n                                    \"memberName\": \"compoundInterest\",\n                                    \"nodeType\": \"MemberAccess\",\n                                    \"referencedDeclaration\": 3249,\n                                    \"src\": \"30082:24:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_function_internal_pure$_t_uint256_$_t_uint256_$_t_uint256_$returns$_t_uint256_$\",\n                                      \"typeString\": \"function (uint256,uint256,uint256) pure returns (uint256)\"\n                                    }\n                                  },\n                                  \"id\": 5258,\n                                  \"isConstant\": false,\n                                  \"isLValue\": false,\n                                  \"isPure\": false,\n                                  \"kind\": \"functionCall\",\n                                  \"lValueRequested\": false,\n                                  \"names\": [],\n                                  \"nodeType\": \"FunctionCall\",\n                                  \"src\": \"30082:75:6\",\n                                  \"tryCall\": false,\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_uint256\",\n                                    \"typeString\": \"uint256\"\n                                  }\n                                },\n                                \"src\": \"30070:87:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              },\n                              \"id\": 5260,\n                              \"nodeType\": \"ExpressionStatement\",\n                              \"src\": \"30070:87:6\"\n                            },\n                            {\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"id\": 5263,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": false,\n                                \"lValueRequested\": false,\n                                \"leftHandSide\": {\n                                  \"argumentTypes\": null,\n                                  \"id\": 5261,\n                                  \"name\": \"start_block\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 5194,\n                                  \"src\": \"30175:11:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_uint256\",\n                                    \"typeString\": \"uint256\"\n                                  }\n                                },\n                                \"nodeType\": \"Assignment\",\n                                \"operator\": \"=\",\n                                \"rightHandSide\": {\n                                  \"argumentTypes\": null,\n                                  \"id\": 5262,\n                                  \"name\": \"end_block\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 5224,\n                                  \"src\": \"30189:9:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_uint256\",\n                                    \"typeString\": \"uint256\"\n                                  }\n                                },\n                                \"src\": \"30175:23:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              },\n                              \"id\": 5264,\n                              \"nodeType\": \"ExpressionStatement\",\n                              \"src\": \"30175:23:6\"\n                            }\n                          ]\n                        },\n                        \"condition\": {\n                          \"argumentTypes\": null,\n                          \"commonType\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          },\n                          \"id\": 5205,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"leftExpression\": {\n                            \"argumentTypes\": null,\n                            \"id\": 5203,\n                            \"name\": \"i\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 5199,\n                            \"src\": \"29379:1:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"nodeType\": \"BinaryOperation\",\n                          \"operator\": \"<\",\n                          \"rightExpression\": {\n                            \"argumentTypes\": null,\n                            \"id\": 5204,\n                            \"name\": \"_interestRatesNextIdx\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 3780,\n                            \"src\": \"29383:21:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"src\": \"29379:25:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_bool\",\n                            \"typeString\": \"bool\"\n                          }\n                        },\n                        \"id\": 5266,\n                        \"initializationExpression\": {\n                          \"assignments\": [\n                            5199\n                          ],\n                          \"declarations\": [\n                            {\n                              \"constant\": false,\n                              \"id\": 5199,\n                              \"mutability\": \"mutable\",\n                              \"name\": \"i\",\n                              \"nodeType\": \"VariableDeclaration\",\n                              \"overrides\": null,\n                              \"scope\": 5266,\n                              \"src\": \"29339:9:6\",\n                              \"stateVariable\": false,\n                              \"storageLocation\": \"default\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_uint256\",\n                                \"typeString\": \"uint256\"\n                              },\n                              \"typeName\": {\n                                \"id\": 5198,\n                                \"name\": \"uint256\",\n                                \"nodeType\": \"ElementaryTypeName\",\n                                \"src\": \"29339:7:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              },\n                              \"value\": null,\n                              \"visibility\": \"internal\"\n                            }\n                          ],\n                          \"id\": 5202,\n                          \"initialValue\": {\n                            \"argumentTypes\": null,\n                            \"expression\": {\n                              \"argumentTypes\": null,\n                              \"id\": 5200,\n                              \"name\": \"stake\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 5175,\n                              \"src\": \"29349:5:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_struct$_Stake_$3648_storage_ptr\",\n                                \"typeString\": \"struct Staking.Stake storage pointer\"\n                              }\n                            },\n                            \"id\": 5201,\n                            \"isConstant\": false,\n                            \"isLValue\": true,\n                            \"isPure\": false,\n                            \"lValueRequested\": false,\n                            \"memberName\": \"sinceInterestRateIndex\",\n                            \"nodeType\": \"MemberAccess\",\n                            \"referencedDeclaration\": 3645,\n                            \"src\": \"29349:28:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"nodeType\": \"VariableDeclarationStatement\",\n                          \"src\": \"29339:38:6\"\n                        },\n                        \"loopExpression\": {\n                          \"expression\": {\n                            \"argumentTypes\": null,\n                            \"id\": 5207,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": false,\n                            \"lValueRequested\": false,\n                            \"nodeType\": \"UnaryOperation\",\n                            \"operator\": \"++\",\n                            \"prefix\": true,\n                            \"src\": \"29406:3:6\",\n                            \"subExpression\": {\n                              \"argumentTypes\": null,\n                              \"id\": 5206,\n                              \"name\": \"i\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 5199,\n                              \"src\": \"29408:1:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_uint256\",\n                                \"typeString\": \"uint256\"\n                              }\n                            },\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"id\": 5208,\n                          \"nodeType\": \"ExpressionStatement\",\n                          \"src\": \"29406:3:6\"\n                        },\n                        \"nodeType\": \"ForStatement\",\n                        \"src\": \"29334:879:6\"\n                      },\n                      {\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 5278,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"leftHandSide\": {\n                            \"argumentTypes\": null,\n                            \"expression\": {\n                              \"argumentTypes\": null,\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"id\": 5267,\n                                \"name\": \"stake\",\n                                \"nodeType\": \"Identifier\",\n                                \"overloadedDeclarations\": [],\n                                \"referencedDeclaration\": 5175,\n                                \"src\": \"30227:5:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_struct$_Stake_$3648_storage_ptr\",\n                                  \"typeString\": \"struct Staking.Stake storage pointer\"\n                                }\n                              },\n                              \"id\": 5270,\n                              \"isConstant\": false,\n                              \"isLValue\": true,\n                              \"isPure\": false,\n                              \"lValueRequested\": false,\n                              \"memberName\": \"asset\",\n                              \"nodeType\": \"MemberAccess\",\n                              \"referencedDeclaration\": 3647,\n                              \"src\": \"30227:11:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                                \"typeString\": \"struct AssetLib.Asset storage ref\"\n                              }\n                            },\n                            \"id\": 5271,\n                            \"isConstant\": false,\n                            \"isLValue\": true,\n                            \"isPure\": false,\n                            \"lValueRequested\": true,\n                            \"memberName\": \"compoundInterest\",\n                            \"nodeType\": \"MemberAccess\",\n                            \"referencedDeclaration\": 2787,\n                            \"src\": \"30227:28:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"nodeType\": \"Assignment\",\n                          \"operator\": \"=\",\n                          \"rightHandSide\": {\n                            \"argumentTypes\": null,\n                            \"arguments\": [\n                              {\n                                \"argumentTypes\": null,\n                                \"expression\": {\n                                  \"argumentTypes\": null,\n                                  \"expression\": {\n                                    \"argumentTypes\": null,\n                                    \"id\": 5274,\n                                    \"name\": \"stake\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 5175,\n                                    \"src\": \"30272:5:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_struct$_Stake_$3648_storage_ptr\",\n                                      \"typeString\": \"struct Staking.Stake storage pointer\"\n                                    }\n                                  },\n                                  \"id\": 5275,\n                                  \"isConstant\": false,\n                                  \"isLValue\": true,\n                                  \"isPure\": false,\n                                  \"lValueRequested\": false,\n                                  \"memberName\": \"asset\",\n                                  \"nodeType\": \"MemberAccess\",\n                                  \"referencedDeclaration\": 3647,\n                                  \"src\": \"30272:11:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                                    \"typeString\": \"struct AssetLib.Asset storage ref\"\n                                  }\n                                },\n                                \"id\": 5276,\n                                \"isConstant\": false,\n                                \"isLValue\": true,\n                                \"isPure\": false,\n                                \"lValueRequested\": false,\n                                \"memberName\": \"principal\",\n                                \"nodeType\": \"MemberAccess\",\n                                \"referencedDeclaration\": 2785,\n                                \"src\": \"30272:21:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              }\n                            ],\n                            \"expression\": {\n                              \"argumentTypes\": [\n                                {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              ],\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"id\": 5272,\n                                \"name\": \"composite\",\n                                \"nodeType\": \"Identifier\",\n                                \"overloadedDeclarations\": [],\n                                \"referencedDeclaration\": 5184,\n                                \"src\": \"30258:9:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              },\n                              \"id\": 5273,\n                              \"isConstant\": false,\n                              \"isLValue\": false,\n                              \"isPure\": false,\n                              \"lValueRequested\": false,\n                              \"memberName\": \"sub\",\n                              \"nodeType\": \"MemberAccess\",\n                              \"referencedDeclaration\": 5887,\n                              \"src\": \"30258:13:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_function_internal_pure$_t_uint256_$_t_uint256_$returns$_t_uint256_$bound_to$_t_uint256_$\",\n                                \"typeString\": \"function (uint256,uint256) pure returns (uint256)\"\n                              }\n                            },\n                            \"id\": 5277,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": false,\n                            \"kind\": \"functionCall\",\n                            \"lValueRequested\": false,\n                            \"names\": [],\n                            \"nodeType\": \"FunctionCall\",\n                            \"src\": \"30258:36:6\",\n                            \"tryCall\": false,\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"src\": \"30227:67:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"id\": 5279,\n                        \"nodeType\": \"ExpressionStatement\",\n                        \"src\": \"30227:67:6\"\n                      }\n                    ]\n                  }\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 5286,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 5282,\n                        \"name\": \"stake\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 5175,\n                        \"src\": \"30315:5:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Stake_$3648_storage_ptr\",\n                          \"typeString\": \"struct Staking.Stake storage pointer\"\n                        }\n                      },\n                      \"id\": 5284,\n                      \"isConstant\": false,\n                      \"isLValue\": true,\n                      \"isPure\": false,\n                      \"lValueRequested\": true,\n                      \"memberName\": \"sinceBlock\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": 3643,\n                      \"src\": \"30315:16:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 5285,\n                      \"name\": \"at_block\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5172,\n                      \"src\": \"30334:8:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"src\": \"30315:27:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"id\": 5287,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"30315:27:6\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 5300,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 5288,\n                        \"name\": \"stake\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 5175,\n                        \"src\": \"30352:5:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Stake_$3648_storage_ptr\",\n                          \"typeString\": \"struct Staking.Stake storage pointer\"\n                        }\n                      },\n                      \"id\": 5290,\n                      \"isConstant\": false,\n                      \"isLValue\": true,\n                      \"isPure\": false,\n                      \"lValueRequested\": true,\n                      \"memberName\": \"sinceInterestRateIndex\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": 3645,\n                      \"src\": \"30352:28:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"components\": [\n                        {\n                          \"argumentTypes\": null,\n                          \"condition\": {\n                            \"argumentTypes\": null,\n                            \"commonType\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            },\n                            \"id\": 5293,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": false,\n                            \"lValueRequested\": false,\n                            \"leftExpression\": {\n                              \"argumentTypes\": null,\n                              \"id\": 5291,\n                              \"name\": \"_interestRatesNextIdx\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 3780,\n                              \"src\": \"30384:21:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_uint256\",\n                                \"typeString\": \"uint256\"\n                              }\n                            },\n                            \"nodeType\": \"BinaryOperation\",\n                            \"operator\": \"!=\",\n                            \"rightExpression\": {\n                              \"argumentTypes\": null,\n                              \"hexValue\": \"30\",\n                              \"id\": 5292,\n                              \"isConstant\": false,\n                              \"isLValue\": false,\n                              \"isPure\": true,\n                              \"kind\": \"number\",\n                              \"lValueRequested\": false,\n                              \"nodeType\": \"Literal\",\n                              \"src\": \"30409:1:6\",\n                              \"subdenomination\": null,\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_rational_0_by_1\",\n                                \"typeString\": \"int_const 0\"\n                              },\n                              \"value\": \"0\"\n                            },\n                            \"src\": \"30384:26:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_bool\",\n                              \"typeString\": \"bool\"\n                            }\n                          },\n                          \"falseExpression\": {\n                            \"argumentTypes\": null,\n                            \"hexValue\": \"30\",\n                            \"id\": 5297,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": true,\n                            \"kind\": \"number\",\n                            \"lValueRequested\": false,\n                            \"nodeType\": \"Literal\",\n                            \"src\": \"30441:1:6\",\n                            \"subdenomination\": null,\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_rational_0_by_1\",\n                              \"typeString\": \"int_const 0\"\n                            },\n                            \"value\": \"0\"\n                          },\n                          \"id\": 5298,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"nodeType\": \"Conditional\",\n                          \"src\": \"30384:58:6\",\n                          \"trueExpression\": {\n                            \"argumentTypes\": null,\n                            \"commonType\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            },\n                            \"id\": 5296,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": false,\n                            \"lValueRequested\": false,\n                            \"leftExpression\": {\n                              \"argumentTypes\": null,\n                              \"id\": 5294,\n                              \"name\": \"_interestRatesNextIdx\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 3780,\n                              \"src\": \"30413:21:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_uint256\",\n                                \"typeString\": \"uint256\"\n                              }\n                            },\n                            \"nodeType\": \"BinaryOperation\",\n                            \"operator\": \"-\",\n                            \"rightExpression\": {\n                              \"argumentTypes\": null,\n                              \"hexValue\": \"31\",\n                              \"id\": 5295,\n                              \"isConstant\": false,\n                              \"isLValue\": false,\n                              \"isPure\": true,\n                              \"kind\": \"number\",\n                              \"lValueRequested\": false,\n                              \"nodeType\": \"Literal\",\n                              \"src\": \"30437:1:6\",\n                              \"subdenomination\": null,\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_rational_1_by_1\",\n                                \"typeString\": \"int_const 1\"\n                              },\n                              \"value\": \"1\"\n                            },\n                            \"src\": \"30413:25:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        }\n                      ],\n                      \"id\": 5299,\n                      \"isConstant\": false,\n                      \"isInlineArray\": false,\n                      \"isLValue\": false,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"nodeType\": \"TupleExpression\",\n                      \"src\": \"30383:60:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"src\": \"30352:91:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"id\": 5301,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"30352:91:6\"\n                },\n                {\n                  \"eventCall\": {\n                    \"argumentTypes\": null,\n                    \"arguments\": [\n                      {\n                        \"argumentTypes\": null,\n                        \"id\": 5303,\n                        \"name\": \"sender\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 5170,\n                        \"src\": \"31508:6:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 5304,\n                          \"name\": \"stake\",\n                          \"nodeType\": \"Identifier\",\n                          \"overloadedDeclarations\": [],\n                          \"referencedDeclaration\": 5175,\n                          \"src\": \"31516:5:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_struct$_Stake_$3648_storage_ptr\",\n                            \"typeString\": \"struct Staking.Stake storage pointer\"\n                          }\n                        },\n                        \"id\": 5305,\n                        \"isConstant\": false,\n                        \"isLValue\": true,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"memberName\": \"sinceInterestRateIndex\",\n                        \"nodeType\": \"MemberAccess\",\n                        \"referencedDeclaration\": 3645,\n                        \"src\": \"31516:28:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"expression\": {\n                            \"argumentTypes\": null,\n                            \"id\": 5306,\n                            \"name\": \"stake\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 5175,\n                            \"src\": \"31546:5:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_struct$_Stake_$3648_storage_ptr\",\n                              \"typeString\": \"struct Staking.Stake storage pointer\"\n                            }\n                          },\n                          \"id\": 5307,\n                          \"isConstant\": false,\n                          \"isLValue\": true,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"memberName\": \"asset\",\n                          \"nodeType\": \"MemberAccess\",\n                          \"referencedDeclaration\": 3647,\n                          \"src\": \"31546:11:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                            \"typeString\": \"struct AssetLib.Asset storage ref\"\n                          }\n                        },\n                        \"id\": 5308,\n                        \"isConstant\": false,\n                        \"isLValue\": true,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"memberName\": \"principal\",\n                        \"nodeType\": \"MemberAccess\",\n                        \"referencedDeclaration\": 2785,\n                        \"src\": \"31546:21:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      },\n                      {\n                        \"argumentTypes\": null,\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"expression\": {\n                            \"argumentTypes\": null,\n                            \"id\": 5309,\n                            \"name\": \"stake\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 5175,\n                            \"src\": \"31569:5:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_struct$_Stake_$3648_storage_ptr\",\n                              \"typeString\": \"struct Staking.Stake storage pointer\"\n                            }\n                          },\n                          \"id\": 5310,\n                          \"isConstant\": false,\n                          \"isLValue\": true,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"memberName\": \"asset\",\n                          \"nodeType\": \"MemberAccess\",\n                          \"referencedDeclaration\": 3647,\n                          \"src\": \"31569:11:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                            \"typeString\": \"struct AssetLib.Asset storage ref\"\n                          }\n                        },\n                        \"id\": 5311,\n                        \"isConstant\": false,\n                        \"isLValue\": true,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"memberName\": \"compoundInterest\",\n                        \"nodeType\": \"MemberAccess\",\n                        \"referencedDeclaration\": 2787,\n                        \"src\": \"31569:28:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      }\n                    ],\n                    \"expression\": {\n                      \"argumentTypes\": [\n                        {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        },\n                        {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        }\n                      ],\n                      \"id\": 5302,\n                      \"name\": \"StakeCompoundInterest\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 3680,\n                      \"src\": \"31486:21:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_function_event_nonpayable$_t_address_$_t_uint256_$_t_uint256_$_t_uint256_$returns$__$\",\n                        \"typeString\": \"function (address,uint256,uint256,uint256)\"\n                      }\n                    },\n                    \"id\": 5312,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"kind\": \"functionCall\",\n                    \"lValueRequested\": false,\n                    \"names\": [],\n                    \"nodeType\": \"FunctionCall\",\n                    \"src\": \"31486:112:6\",\n                    \"tryCall\": false,\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_tuple$__$\",\n                      \"typeString\": \"tuple()\"\n                    }\n                  },\n                  \"id\": 5313,\n                  \"nodeType\": \"EmitStatement\",\n                  \"src\": \"31481:117:6\"\n                }\n              ]\n            },\n            \"documentation\": null,\n            \"id\": 5315,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [],\n            \"name\": \"_updateStakeCompoundInterest\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 5173,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 5170,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"sender\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 5315,\n                  \"src\": \"28748:14:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_address\",\n                    \"typeString\": \"address\"\n                  },\n                  \"typeName\": {\n                    \"id\": 5169,\n                    \"name\": \"address\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"28748:7:6\",\n                    \"stateMutability\": \"nonpayable\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address\",\n                      \"typeString\": \"address\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 5172,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"at_block\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 5315,\n                  \"src\": \"28764:16:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 5171,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"28764:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"28747:34:6\"\n            },\n            \"returnParameters\": {\n              \"id\": 5176,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 5175,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"stake\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 5315,\n                  \"src\": \"28815:19:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"storage\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_struct$_Stake_$3648_storage_ptr\",\n                    \"typeString\": \"struct Staking.Stake\"\n                  },\n                  \"typeName\": {\n                    \"contractScope\": null,\n                    \"id\": 5174,\n                    \"name\": \"Stake\",\n                    \"nodeType\": \"UserDefinedTypeName\",\n                    \"referencedDeclaration\": 3648,\n                    \"src\": \"28815:5:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_struct$_Stake_$3648_storage_ptr\",\n                      \"typeString\": \"struct Staking.Stake\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"28814:21:6\"\n            },\n            \"scope\": 5490,\n            \"src\": \"28710:2895:6\",\n            \"stateMutability\": \"nonpayable\",\n            \"virtual\": false,\n            \"visibility\": \"internal\"\n          },\n          {\n            \"body\": {\n              \"id\": 5488,\n              \"nodeType\": \"Block\",\n              \"src\": \"31801:2505:6\",\n              \"statements\": [\n                {\n                  \"assignments\": [\n                    5329\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 5329,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"locked\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 5488,\n                      \"src\": \"31811:21:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"storage\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_struct$_Locked_$3659_storage_ptr\",\n                        \"typeString\": \"struct Staking.Locked\"\n                      },\n                      \"typeName\": {\n                        \"contractScope\": null,\n                        \"id\": 5328,\n                        \"name\": \"Locked\",\n                        \"nodeType\": \"UserDefinedTypeName\",\n                        \"referencedDeclaration\": 3659,\n                        \"src\": \"31811:6:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_struct$_Locked_$3659_storage_ptr\",\n                          \"typeString\": \"struct Staking.Locked\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 5333,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"baseExpression\": {\n                      \"argumentTypes\": null,\n                      \"id\": 5330,\n                      \"name\": \"_locked\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 3792,\n                      \"src\": \"31835:7:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_mapping$_t_address_$_t_struct$_Locked_$3659_storage_$\",\n                        \"typeString\": \"mapping(address => struct Staking.Locked storage ref)\"\n                      }\n                    },\n                    \"id\": 5332,\n                    \"indexExpression\": {\n                      \"argumentTypes\": null,\n                      \"id\": 5331,\n                      \"name\": \"sender\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5317,\n                      \"src\": \"31843:6:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_address\",\n                        \"typeString\": \"address\"\n                      }\n                    },\n                    \"isConstant\": false,\n                    \"isLValue\": true,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"nodeType\": \"IndexAccess\",\n                    \"src\": \"31835:15:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_struct$_Locked_$3659_storage\",\n                      \"typeString\": \"struct Staking.Locked storage ref\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"31811:39:6\"\n                },\n                {\n                  \"assignments\": [\n                    5337\n                  ],\n                  \"declarations\": [\n                    {\n                      \"constant\": false,\n                      \"id\": 5337,\n                      \"mutability\": \"mutable\",\n                      \"name\": \"lockedAssets\",\n                      \"nodeType\": \"VariableDeclaration\",\n                      \"overrides\": null,\n                      \"scope\": 5488,\n                      \"src\": \"31860:34:6\",\n                      \"stateVariable\": false,\n                      \"storageLocation\": \"storage\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_array$_t_struct$_LockedAsset_$3653_storage_$dyn_storage_ptr\",\n                        \"typeString\": \"struct Staking.LockedAsset[]\"\n                      },\n                      \"typeName\": {\n                        \"baseType\": {\n                          \"contractScope\": null,\n                          \"id\": 5335,\n                          \"name\": \"LockedAsset\",\n                          \"nodeType\": \"UserDefinedTypeName\",\n                          \"referencedDeclaration\": 3653,\n                          \"src\": \"31860:11:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_struct$_LockedAsset_$3653_storage_ptr\",\n                            \"typeString\": \"struct Staking.LockedAsset\"\n                          }\n                        },\n                        \"id\": 5336,\n                        \"length\": null,\n                        \"nodeType\": \"ArrayTypeName\",\n                        \"src\": \"31860:13:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_array$_t_struct$_LockedAsset_$3653_storage_$dyn_storage_ptr\",\n                          \"typeString\": \"struct Staking.LockedAsset[]\"\n                        }\n                      },\n                      \"value\": null,\n                      \"visibility\": \"internal\"\n                    }\n                  ],\n                  \"id\": 5340,\n                  \"initialValue\": {\n                    \"argumentTypes\": null,\n                    \"expression\": {\n                      \"argumentTypes\": null,\n                      \"id\": 5338,\n                      \"name\": \"locked\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5329,\n                      \"src\": \"31897:6:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_struct$_Locked_$3659_storage_ptr\",\n                        \"typeString\": \"struct Staking.Locked storage pointer\"\n                      }\n                    },\n                    \"id\": 5339,\n                    \"isConstant\": false,\n                    \"isLValue\": true,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"memberName\": \"assets\",\n                    \"nodeType\": \"MemberAccess\",\n                    \"referencedDeclaration\": 3658,\n                    \"src\": \"31897:13:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_array$_t_struct$_LockedAsset_$3653_storage_$dyn_storage\",\n                      \"typeString\": \"struct Staking.LockedAsset storage ref[] storage ref\"\n                    }\n                  },\n                  \"nodeType\": \"VariableDeclarationStatement\",\n                  \"src\": \"31860:50:6\"\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 5345,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 5341,\n                      \"name\": \"liquidity\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5324,\n                      \"src\": \"31920:9:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                        \"typeString\": \"struct AssetLib.Asset storage pointer\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"baseExpression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 5342,\n                        \"name\": \"_liquidity\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 3796,\n                        \"src\": \"31932:10:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_mapping$_t_address_$_t_struct$_Asset_$2788_storage_$\",\n                          \"typeString\": \"mapping(address => struct AssetLib.Asset storage ref)\"\n                        }\n                      },\n                      \"id\": 5344,\n                      \"indexExpression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 5343,\n                        \"name\": \"sender\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 5317,\n                        \"src\": \"31943:6:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_address\",\n                          \"typeString\": \"address\"\n                        }\n                      },\n                      \"isConstant\": false,\n                      \"isLValue\": true,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"nodeType\": \"IndexAccess\",\n                      \"src\": \"31932:18:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                        \"typeString\": \"struct AssetLib.Asset storage ref\"\n                      }\n                    },\n                    \"src\": \"31920:30:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                      \"typeString\": \"struct AssetLib.Asset storage pointer\"\n                    }\n                  },\n                  \"id\": 5346,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"31920:30:6\"\n                },\n                {\n                  \"body\": {\n                    \"id\": 5420,\n                    \"nodeType\": \"Block\",\n                    \"src\": \"32006:1628:6\",\n                    \"statements\": [\n                      {\n                        \"assignments\": [\n                          5356\n                        ],\n                        \"declarations\": [\n                          {\n                            \"constant\": false,\n                            \"id\": 5356,\n                            \"mutability\": \"mutable\",\n                            \"name\": \"l\",\n                            \"nodeType\": \"VariableDeclaration\",\n                            \"overrides\": null,\n                            \"scope\": 5420,\n                            \"src\": \"32020:20:6\",\n                            \"stateVariable\": false,\n                            \"storageLocation\": \"memory\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_struct$_LockedAsset_$3653_memory_ptr\",\n                              \"typeString\": \"struct Staking.LockedAsset\"\n                            },\n                            \"typeName\": {\n                              \"contractScope\": null,\n                              \"id\": 5355,\n                              \"name\": \"LockedAsset\",\n                              \"nodeType\": \"UserDefinedTypeName\",\n                              \"referencedDeclaration\": 3653,\n                              \"src\": \"32020:11:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_struct$_LockedAsset_$3653_storage_ptr\",\n                                \"typeString\": \"struct Staking.LockedAsset\"\n                              }\n                            },\n                            \"value\": null,\n                            \"visibility\": \"internal\"\n                          }\n                        ],\n                        \"id\": 5360,\n                        \"initialValue\": {\n                          \"argumentTypes\": null,\n                          \"baseExpression\": {\n                            \"argumentTypes\": null,\n                            \"id\": 5357,\n                            \"name\": \"lockedAssets\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 5337,\n                            \"src\": \"32043:12:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_array$_t_struct$_LockedAsset_$3653_storage_$dyn_storage_ptr\",\n                              \"typeString\": \"struct Staking.LockedAsset storage ref[] storage pointer\"\n                            }\n                          },\n                          \"id\": 5359,\n                          \"indexExpression\": {\n                            \"argumentTypes\": null,\n                            \"id\": 5358,\n                            \"name\": \"i\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 5348,\n                            \"src\": \"32056:1:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"isConstant\": false,\n                          \"isLValue\": true,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"nodeType\": \"IndexAccess\",\n                          \"src\": \"32043:15:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_struct$_LockedAsset_$3653_storage\",\n                            \"typeString\": \"struct Staking.LockedAsset storage ref\"\n                          }\n                        },\n                        \"nodeType\": \"VariableDeclarationStatement\",\n                        \"src\": \"32020:38:6\"\n                      },\n                      {\n                        \"condition\": {\n                          \"argumentTypes\": null,\n                          \"commonType\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          },\n                          \"id\": 5364,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"leftExpression\": {\n                            \"argumentTypes\": null,\n                            \"expression\": {\n                              \"argumentTypes\": null,\n                              \"id\": 5361,\n                              \"name\": \"l\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 5356,\n                              \"src\": \"32077:1:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_struct$_LockedAsset_$3653_memory_ptr\",\n                                \"typeString\": \"struct Staking.LockedAsset memory\"\n                              }\n                            },\n                            \"id\": 5362,\n                            \"isConstant\": false,\n                            \"isLValue\": true,\n                            \"isPure\": false,\n                            \"lValueRequested\": false,\n                            \"memberName\": \"liquidSinceBlock\",\n                            \"nodeType\": \"MemberAccess\",\n                            \"referencedDeclaration\": 3650,\n                            \"src\": \"32077:18:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"nodeType\": \"BinaryOperation\",\n                          \"operator\": \">\",\n                          \"rightExpression\": {\n                            \"argumentTypes\": null,\n                            \"id\": 5363,\n                            \"name\": \"at_block\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 5319,\n                            \"src\": \"32098:8:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"src\": \"32077:29:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_bool\",\n                            \"typeString\": \"bool\"\n                          }\n                        },\n                        \"falseBody\": null,\n                        \"id\": 5370,\n                        \"nodeType\": \"IfStatement\",\n                        \"src\": \"32073:191:6\",\n                        \"trueBody\": {\n                          \"id\": 5369,\n                          \"nodeType\": \"Block\",\n                          \"src\": \"32108:156:6\",\n                          \"statements\": [\n                            {\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"id\": 5366,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": false,\n                                \"lValueRequested\": false,\n                                \"nodeType\": \"UnaryOperation\",\n                                \"operator\": \"++\",\n                                \"prefix\": true,\n                                \"src\": \"32126:3:6\",\n                                \"subExpression\": {\n                                  \"argumentTypes\": null,\n                                  \"id\": 5365,\n                                  \"name\": \"i\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 5348,\n                                  \"src\": \"32128:1:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_uint256\",\n                                    \"typeString\": \"uint256\"\n                                  }\n                                },\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              },\n                              \"id\": 5367,\n                              \"nodeType\": \"ExpressionStatement\",\n                              \"src\": \"32126:3:6\"\n                            },\n                            {\n                              \"id\": 5368,\n                              \"nodeType\": \"Continue\",\n                              \"src\": \"32241:8:6\"\n                            }\n                          ]\n                        }\n                      },\n                      {\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 5381,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"leftHandSide\": {\n                            \"argumentTypes\": null,\n                            \"expression\": {\n                              \"argumentTypes\": null,\n                              \"id\": 5371,\n                              \"name\": \"unlockedLiquidity\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 5322,\n                              \"src\": \"32278:17:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                \"typeString\": \"struct AssetLib.Asset memory\"\n                              }\n                            },\n                            \"id\": 5373,\n                            \"isConstant\": false,\n                            \"isLValue\": true,\n                            \"isPure\": false,\n                            \"lValueRequested\": true,\n                            \"memberName\": \"principal\",\n                            \"nodeType\": \"MemberAccess\",\n                            \"referencedDeclaration\": 2785,\n                            \"src\": \"32278:27:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"nodeType\": \"Assignment\",\n                          \"operator\": \"=\",\n                          \"rightHandSide\": {\n                            \"argumentTypes\": null,\n                            \"arguments\": [\n                              {\n                                \"argumentTypes\": null,\n                                \"expression\": {\n                                  \"argumentTypes\": null,\n                                  \"expression\": {\n                                    \"argumentTypes\": null,\n                                    \"id\": 5377,\n                                    \"name\": \"l\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 5356,\n                                    \"src\": \"32340:1:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_struct$_LockedAsset_$3653_memory_ptr\",\n                                      \"typeString\": \"struct Staking.LockedAsset memory\"\n                                    }\n                                  },\n                                  \"id\": 5378,\n                                  \"isConstant\": false,\n                                  \"isLValue\": true,\n                                  \"isPure\": false,\n                                  \"lValueRequested\": false,\n                                  \"memberName\": \"asset\",\n                                  \"nodeType\": \"MemberAccess\",\n                                  \"referencedDeclaration\": 3652,\n                                  \"src\": \"32340:7:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                    \"typeString\": \"struct AssetLib.Asset memory\"\n                                  }\n                                },\n                                \"id\": 5379,\n                                \"isConstant\": false,\n                                \"isLValue\": true,\n                                \"isPure\": false,\n                                \"lValueRequested\": false,\n                                \"memberName\": \"principal\",\n                                \"nodeType\": \"MemberAccess\",\n                                \"referencedDeclaration\": 2785,\n                                \"src\": \"32340:17:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              }\n                            ],\n                            \"expression\": {\n                              \"argumentTypes\": [\n                                {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              ],\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"expression\": {\n                                  \"argumentTypes\": null,\n                                  \"id\": 5374,\n                                  \"name\": \"unlockedLiquidity\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 5322,\n                                  \"src\": \"32308:17:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                    \"typeString\": \"struct AssetLib.Asset memory\"\n                                  }\n                                },\n                                \"id\": 5375,\n                                \"isConstant\": false,\n                                \"isLValue\": true,\n                                \"isPure\": false,\n                                \"lValueRequested\": false,\n                                \"memberName\": \"principal\",\n                                \"nodeType\": \"MemberAccess\",\n                                \"referencedDeclaration\": 2785,\n                                \"src\": \"32308:27:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              },\n                              \"id\": 5376,\n                              \"isConstant\": false,\n                              \"isLValue\": false,\n                              \"isPure\": false,\n                              \"lValueRequested\": false,\n                              \"memberName\": \"add\",\n                              \"nodeType\": \"MemberAccess\",\n                              \"referencedDeclaration\": 5870,\n                              \"src\": \"32308:31:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_function_internal_pure$_t_uint256_$_t_uint256_$returns$_t_uint256_$bound_to$_t_uint256_$\",\n                                \"typeString\": \"function (uint256,uint256) pure returns (uint256)\"\n                              }\n                            },\n                            \"id\": 5380,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": false,\n                            \"kind\": \"functionCall\",\n                            \"lValueRequested\": false,\n                            \"names\": [],\n                            \"nodeType\": \"FunctionCall\",\n                            \"src\": \"32308:50:6\",\n                            \"tryCall\": false,\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"src\": \"32278:80:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"id\": 5382,\n                        \"nodeType\": \"ExpressionStatement\",\n                        \"src\": \"32278:80:6\"\n                      },\n                      {\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 5393,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"leftHandSide\": {\n                            \"argumentTypes\": null,\n                            \"expression\": {\n                              \"argumentTypes\": null,\n                              \"id\": 5383,\n                              \"name\": \"unlockedLiquidity\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 5322,\n                              \"src\": \"32576:17:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                \"typeString\": \"struct AssetLib.Asset memory\"\n                              }\n                            },\n                            \"id\": 5385,\n                            \"isConstant\": false,\n                            \"isLValue\": true,\n                            \"isPure\": false,\n                            \"lValueRequested\": true,\n                            \"memberName\": \"compoundInterest\",\n                            \"nodeType\": \"MemberAccess\",\n                            \"referencedDeclaration\": 2787,\n                            \"src\": \"32576:34:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"nodeType\": \"Assignment\",\n                          \"operator\": \"=\",\n                          \"rightHandSide\": {\n                            \"argumentTypes\": null,\n                            \"arguments\": [\n                              {\n                                \"argumentTypes\": null,\n                                \"expression\": {\n                                  \"argumentTypes\": null,\n                                  \"expression\": {\n                                    \"argumentTypes\": null,\n                                    \"id\": 5389,\n                                    \"name\": \"l\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 5356,\n                                    \"src\": \"32652:1:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_struct$_LockedAsset_$3653_memory_ptr\",\n                                      \"typeString\": \"struct Staking.LockedAsset memory\"\n                                    }\n                                  },\n                                  \"id\": 5390,\n                                  \"isConstant\": false,\n                                  \"isLValue\": true,\n                                  \"isPure\": false,\n                                  \"lValueRequested\": false,\n                                  \"memberName\": \"asset\",\n                                  \"nodeType\": \"MemberAccess\",\n                                  \"referencedDeclaration\": 3652,\n                                  \"src\": \"32652:7:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                    \"typeString\": \"struct AssetLib.Asset memory\"\n                                  }\n                                },\n                                \"id\": 5391,\n                                \"isConstant\": false,\n                                \"isLValue\": true,\n                                \"isPure\": false,\n                                \"lValueRequested\": false,\n                                \"memberName\": \"compoundInterest\",\n                                \"nodeType\": \"MemberAccess\",\n                                \"referencedDeclaration\": 2787,\n                                \"src\": \"32652:24:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              }\n                            ],\n                            \"expression\": {\n                              \"argumentTypes\": [\n                                {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              ],\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"expression\": {\n                                  \"argumentTypes\": null,\n                                  \"id\": 5386,\n                                  \"name\": \"unlockedLiquidity\",\n                                  \"nodeType\": \"Identifier\",\n                                  \"overloadedDeclarations\": [],\n                                  \"referencedDeclaration\": 5322,\n                                  \"src\": \"32613:17:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                    \"typeString\": \"struct AssetLib.Asset memory\"\n                                  }\n                                },\n                                \"id\": 5387,\n                                \"isConstant\": false,\n                                \"isLValue\": true,\n                                \"isPure\": false,\n                                \"lValueRequested\": false,\n                                \"memberName\": \"compoundInterest\",\n                                \"nodeType\": \"MemberAccess\",\n                                \"referencedDeclaration\": 2787,\n                                \"src\": \"32613:34:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_uint256\",\n                                  \"typeString\": \"uint256\"\n                                }\n                              },\n                              \"id\": 5388,\n                              \"isConstant\": false,\n                              \"isLValue\": false,\n                              \"isPure\": false,\n                              \"lValueRequested\": false,\n                              \"memberName\": \"add\",\n                              \"nodeType\": \"MemberAccess\",\n                              \"referencedDeclaration\": 5870,\n                              \"src\": \"32613:38:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_function_internal_pure$_t_uint256_$_t_uint256_$returns$_t_uint256_$bound_to$_t_uint256_$\",\n                                \"typeString\": \"function (uint256,uint256) pure returns (uint256)\"\n                              }\n                            },\n                            \"id\": 5392,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": false,\n                            \"kind\": \"functionCall\",\n                            \"lValueRequested\": false,\n                            \"names\": [],\n                            \"nodeType\": \"FunctionCall\",\n                            \"src\": \"32613:64:6\",\n                            \"tryCall\": false,\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"src\": \"32576:101:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"id\": 5394,\n                        \"nodeType\": \"ExpressionStatement\",\n                        \"src\": \"32576:101:6\"\n                      },\n                      {\n                        \"assignments\": [\n                          5396\n                        ],\n                        \"declarations\": [\n                          {\n                            \"constant\": false,\n                            \"id\": 5396,\n                            \"mutability\": \"mutable\",\n                            \"name\": \"last_idx\",\n                            \"nodeType\": \"VariableDeclaration\",\n                            \"overrides\": null,\n                            \"scope\": 5420,\n                            \"src\": \"32959:16:6\",\n                            \"stateVariable\": false,\n                            \"storageLocation\": \"default\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            },\n                            \"typeName\": {\n                              \"id\": 5395,\n                              \"name\": \"uint256\",\n                              \"nodeType\": \"ElementaryTypeName\",\n                              \"src\": \"32959:7:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_uint256\",\n                                \"typeString\": \"uint256\"\n                              }\n                            },\n                            \"value\": null,\n                            \"visibility\": \"internal\"\n                          }\n                        ],\n                        \"id\": 5401,\n                        \"initialValue\": {\n                          \"argumentTypes\": null,\n                          \"commonType\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          },\n                          \"id\": 5400,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"leftExpression\": {\n                            \"argumentTypes\": null,\n                            \"expression\": {\n                              \"argumentTypes\": null,\n                              \"id\": 5397,\n                              \"name\": \"lockedAssets\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 5337,\n                              \"src\": \"32978:12:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_array$_t_struct$_LockedAsset_$3653_storage_$dyn_storage_ptr\",\n                                \"typeString\": \"struct Staking.LockedAsset storage ref[] storage pointer\"\n                              }\n                            },\n                            \"id\": 5398,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": false,\n                            \"lValueRequested\": false,\n                            \"memberName\": \"length\",\n                            \"nodeType\": \"MemberAccess\",\n                            \"referencedDeclaration\": null,\n                            \"src\": \"32978:19:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"nodeType\": \"BinaryOperation\",\n                          \"operator\": \"-\",\n                          \"rightExpression\": {\n                            \"argumentTypes\": null,\n                            \"hexValue\": \"31\",\n                            \"id\": 5399,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": true,\n                            \"kind\": \"number\",\n                            \"lValueRequested\": false,\n                            \"nodeType\": \"Literal\",\n                            \"src\": \"33000:1:6\",\n                            \"subdenomination\": null,\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_rational_1_by_1\",\n                              \"typeString\": \"int_const 1\"\n                            },\n                            \"value\": \"1\"\n                          },\n                          \"src\": \"32978:23:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"nodeType\": \"VariableDeclarationStatement\",\n                        \"src\": \"32959:42:6\"\n                      },\n                      {\n                        \"condition\": {\n                          \"argumentTypes\": null,\n                          \"commonType\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          },\n                          \"id\": 5404,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"leftExpression\": {\n                            \"argumentTypes\": null,\n                            \"id\": 5402,\n                            \"name\": \"i\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 5348,\n                            \"src\": \"33019:1:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"nodeType\": \"BinaryOperation\",\n                          \"operator\": \"!=\",\n                          \"rightExpression\": {\n                            \"argumentTypes\": null,\n                            \"id\": 5403,\n                            \"name\": \"last_idx\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 5396,\n                            \"src\": \"33024:8:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"src\": \"33019:13:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_bool\",\n                            \"typeString\": \"bool\"\n                          }\n                        },\n                        \"falseBody\": null,\n                        \"id\": 5414,\n                        \"nodeType\": \"IfStatement\",\n                        \"src\": \"33015:92:6\",\n                        \"trueBody\": {\n                          \"id\": 5413,\n                          \"nodeType\": \"Block\",\n                          \"src\": \"33034:73:6\",\n                          \"statements\": [\n                            {\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"id\": 5411,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": false,\n                                \"lValueRequested\": false,\n                                \"leftHandSide\": {\n                                  \"argumentTypes\": null,\n                                  \"baseExpression\": {\n                                    \"argumentTypes\": null,\n                                    \"id\": 5405,\n                                    \"name\": \"lockedAssets\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 5337,\n                                    \"src\": \"33052:12:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_array$_t_struct$_LockedAsset_$3653_storage_$dyn_storage_ptr\",\n                                      \"typeString\": \"struct Staking.LockedAsset storage ref[] storage pointer\"\n                                    }\n                                  },\n                                  \"id\": 5407,\n                                  \"indexExpression\": {\n                                    \"argumentTypes\": null,\n                                    \"id\": 5406,\n                                    \"name\": \"i\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 5348,\n                                    \"src\": \"33065:1:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    }\n                                  },\n                                  \"isConstant\": false,\n                                  \"isLValue\": true,\n                                  \"isPure\": false,\n                                  \"lValueRequested\": true,\n                                  \"nodeType\": \"IndexAccess\",\n                                  \"src\": \"33052:15:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_struct$_LockedAsset_$3653_storage\",\n                                    \"typeString\": \"struct Staking.LockedAsset storage ref\"\n                                  }\n                                },\n                                \"nodeType\": \"Assignment\",\n                                \"operator\": \"=\",\n                                \"rightHandSide\": {\n                                  \"argumentTypes\": null,\n                                  \"baseExpression\": {\n                                    \"argumentTypes\": null,\n                                    \"id\": 5408,\n                                    \"name\": \"lockedAssets\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 5337,\n                                    \"src\": \"33070:12:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_array$_t_struct$_LockedAsset_$3653_storage_$dyn_storage_ptr\",\n                                      \"typeString\": \"struct Staking.LockedAsset storage ref[] storage pointer\"\n                                    }\n                                  },\n                                  \"id\": 5410,\n                                  \"indexExpression\": {\n                                    \"argumentTypes\": null,\n                                    \"id\": 5409,\n                                    \"name\": \"last_idx\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 5396,\n                                    \"src\": \"33083:8:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_uint256\",\n                                      \"typeString\": \"uint256\"\n                                    }\n                                  },\n                                  \"isConstant\": false,\n                                  \"isLValue\": true,\n                                  \"isPure\": false,\n                                  \"lValueRequested\": false,\n                                  \"nodeType\": \"IndexAccess\",\n                                  \"src\": \"33070:22:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_struct$_LockedAsset_$3653_storage\",\n                                    \"typeString\": \"struct Staking.LockedAsset storage ref\"\n                                  }\n                                },\n                                \"src\": \"33052:40:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_struct$_LockedAsset_$3653_storage\",\n                                  \"typeString\": \"struct Staking.LockedAsset storage ref\"\n                                }\n                              },\n                              \"id\": 5412,\n                              \"nodeType\": \"ExpressionStatement\",\n                              \"src\": \"33052:40:6\"\n                            }\n                          ]\n                        }\n                      },\n                      {\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"arguments\": [],\n                          \"expression\": {\n                            \"argumentTypes\": [],\n                            \"expression\": {\n                              \"argumentTypes\": null,\n                              \"id\": 5415,\n                              \"name\": \"lockedAssets\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 5337,\n                              \"src\": \"33605:12:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_array$_t_struct$_LockedAsset_$3653_storage_$dyn_storage_ptr\",\n                                \"typeString\": \"struct Staking.LockedAsset storage ref[] storage pointer\"\n                              }\n                            },\n                            \"id\": 5417,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": false,\n                            \"lValueRequested\": false,\n                            \"memberName\": \"pop\",\n                            \"nodeType\": \"MemberAccess\",\n                            \"referencedDeclaration\": null,\n                            \"src\": \"33605:16:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_function_arraypop_nonpayable$__$returns$__$\",\n                              \"typeString\": \"function ()\"\n                            }\n                          },\n                          \"id\": 5418,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"kind\": \"functionCall\",\n                          \"lValueRequested\": false,\n                          \"names\": [],\n                          \"nodeType\": \"FunctionCall\",\n                          \"src\": \"33605:18:6\",\n                          \"tryCall\": false,\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_tuple$__$\",\n                            \"typeString\": \"tuple()\"\n                          }\n                        },\n                        \"id\": 5419,\n                        \"nodeType\": \"ExpressionStatement\",\n                        \"src\": \"33605:18:6\"\n                      }\n                    ]\n                  },\n                  \"condition\": {\n                    \"argumentTypes\": null,\n                    \"commonType\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    },\n                    \"id\": 5354,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftExpression\": {\n                      \"argumentTypes\": null,\n                      \"id\": 5351,\n                      \"name\": \"i\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5348,\n                      \"src\": \"31979:1:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"BinaryOperation\",\n                    \"operator\": \"<\",\n                    \"rightExpression\": {\n                      \"argumentTypes\": null,\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 5352,\n                        \"name\": \"lockedAssets\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 5337,\n                        \"src\": \"31983:12:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_array$_t_struct$_LockedAsset_$3653_storage_$dyn_storage_ptr\",\n                          \"typeString\": \"struct Staking.LockedAsset storage ref[] storage pointer\"\n                        }\n                      },\n                      \"id\": 5353,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"memberName\": \"length\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": null,\n                      \"src\": \"31983:19:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"src\": \"31979:23:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_bool\",\n                      \"typeString\": \"bool\"\n                    }\n                  },\n                  \"id\": 5421,\n                  \"initializationExpression\": {\n                    \"assignments\": [\n                      5348\n                    ],\n                    \"declarations\": [\n                      {\n                        \"constant\": false,\n                        \"id\": 5348,\n                        \"mutability\": \"mutable\",\n                        \"name\": \"i\",\n                        \"nodeType\": \"VariableDeclaration\",\n                        \"overrides\": null,\n                        \"scope\": 5421,\n                        \"src\": \"31966:9:6\",\n                        \"stateVariable\": false,\n                        \"storageLocation\": \"default\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        },\n                        \"typeName\": {\n                          \"id\": 5347,\n                          \"name\": \"uint256\",\n                          \"nodeType\": \"ElementaryTypeName\",\n                          \"src\": \"31966:7:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"value\": null,\n                        \"visibility\": \"internal\"\n                      }\n                    ],\n                    \"id\": 5350,\n                    \"initialValue\": {\n                      \"argumentTypes\": null,\n                      \"hexValue\": \"30\",\n                      \"id\": 5349,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": true,\n                      \"kind\": \"number\",\n                      \"lValueRequested\": false,\n                      \"nodeType\": \"Literal\",\n                      \"src\": \"31976:1:6\",\n                      \"subdenomination\": null,\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_rational_0_by_1\",\n                        \"typeString\": \"int_const 0\"\n                      },\n                      \"value\": \"0\"\n                    },\n                    \"nodeType\": \"VariableDeclarationStatement\",\n                    \"src\": \"31966:11:6\"\n                  },\n                  \"loopExpression\": null,\n                  \"nodeType\": \"ForStatement\",\n                  \"src\": \"31961:1673:6\"\n                },\n                {\n                  \"condition\": {\n                    \"argumentTypes\": null,\n                    \"commonType\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    },\n                    \"id\": 5425,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftExpression\": {\n                      \"argumentTypes\": null,\n                      \"expression\": {\n                        \"argumentTypes\": null,\n                        \"id\": 5422,\n                        \"name\": \"lockedAssets\",\n                        \"nodeType\": \"Identifier\",\n                        \"overloadedDeclarations\": [],\n                        \"referencedDeclaration\": 5337,\n                        \"src\": \"33699:12:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_array$_t_struct$_LockedAsset_$3653_storage_$dyn_storage_ptr\",\n                          \"typeString\": \"struct Staking.LockedAsset storage ref[] storage pointer\"\n                        }\n                      },\n                      \"id\": 5423,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"memberName\": \"length\",\n                      \"nodeType\": \"MemberAccess\",\n                      \"referencedDeclaration\": null,\n                      \"src\": \"33699:19:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_uint256\",\n                        \"typeString\": \"uint256\"\n                      }\n                    },\n                    \"nodeType\": \"BinaryOperation\",\n                    \"operator\": \"==\",\n                    \"rightExpression\": {\n                      \"argumentTypes\": null,\n                      \"hexValue\": \"30\",\n                      \"id\": 5424,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": true,\n                      \"kind\": \"number\",\n                      \"lValueRequested\": false,\n                      \"nodeType\": \"Literal\",\n                      \"src\": \"33722:1:6\",\n                      \"subdenomination\": null,\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_rational_0_by_1\",\n                        \"typeString\": \"int_const 0\"\n                      },\n                      \"value\": \"0\"\n                    },\n                    \"src\": \"33699:24:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_bool\",\n                      \"typeString\": \"bool\"\n                    }\n                  },\n                  \"falseBody\": null,\n                  \"id\": 5432,\n                  \"nodeType\": \"IfStatement\",\n                  \"src\": \"33695:77:6\",\n                  \"trueBody\": {\n                    \"id\": 5431,\n                    \"nodeType\": \"Block\",\n                    \"src\": \"33725:47:6\",\n                    \"statements\": [\n                      {\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"id\": 5429,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"nodeType\": \"UnaryOperation\",\n                          \"operator\": \"delete\",\n                          \"prefix\": true,\n                          \"src\": \"33739:22:6\",\n                          \"subExpression\": {\n                            \"argumentTypes\": null,\n                            \"baseExpression\": {\n                              \"argumentTypes\": null,\n                              \"id\": 5426,\n                              \"name\": \"_locked\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 3792,\n                              \"src\": \"33746:7:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_mapping$_t_address_$_t_struct$_Locked_$3659_storage_$\",\n                                \"typeString\": \"mapping(address => struct Staking.Locked storage ref)\"\n                              }\n                            },\n                            \"id\": 5428,\n                            \"indexExpression\": {\n                              \"argumentTypes\": null,\n                              \"id\": 5427,\n                              \"name\": \"sender\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 5317,\n                              \"src\": \"33754:6:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_address\",\n                                \"typeString\": \"address\"\n                              }\n                            },\n                            \"isConstant\": false,\n                            \"isLValue\": true,\n                            \"isPure\": false,\n                            \"lValueRequested\": true,\n                            \"nodeType\": \"IndexAccess\",\n                            \"src\": \"33746:15:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_struct$_Locked_$3659_storage\",\n                              \"typeString\": \"struct Staking.Locked storage ref\"\n                            }\n                          },\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_tuple$__$\",\n                            \"typeString\": \"tuple()\"\n                          }\n                        },\n                        \"id\": 5430,\n                        \"nodeType\": \"ExpressionStatement\",\n                        \"src\": \"33739:22:6\"\n                      }\n                    ]\n                  }\n                },\n                {\n                  \"expression\": {\n                    \"argumentTypes\": null,\n                    \"id\": 5443,\n                    \"isConstant\": false,\n                    \"isLValue\": false,\n                    \"isPure\": false,\n                    \"lValueRequested\": false,\n                    \"leftHandSide\": {\n                      \"argumentTypes\": null,\n                      \"id\": 5433,\n                      \"name\": \"collected\",\n                      \"nodeType\": \"Identifier\",\n                      \"overloadedDeclarations\": [],\n                      \"referencedDeclaration\": 5326,\n                      \"src\": \"33782:9:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_bool\",\n                        \"typeString\": \"bool\"\n                      }\n                    },\n                    \"nodeType\": \"Assignment\",\n                    \"operator\": \"=\",\n                    \"rightHandSide\": {\n                      \"argumentTypes\": null,\n                      \"commonType\": {\n                        \"typeIdentifier\": \"t_bool\",\n                        \"typeString\": \"bool\"\n                      },\n                      \"id\": 5442,\n                      \"isConstant\": false,\n                      \"isLValue\": false,\n                      \"isPure\": false,\n                      \"lValueRequested\": false,\n                      \"leftExpression\": {\n                        \"argumentTypes\": null,\n                        \"commonType\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        },\n                        \"id\": 5437,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"leftExpression\": {\n                          \"argumentTypes\": null,\n                          \"expression\": {\n                            \"argumentTypes\": null,\n                            \"id\": 5434,\n                            \"name\": \"unlockedLiquidity\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 5322,\n                            \"src\": \"33794:17:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                              \"typeString\": \"struct AssetLib.Asset memory\"\n                            }\n                          },\n                          \"id\": 5435,\n                          \"isConstant\": false,\n                          \"isLValue\": true,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"memberName\": \"principal\",\n                          \"nodeType\": \"MemberAccess\",\n                          \"referencedDeclaration\": 2785,\n                          \"src\": \"33794:27:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"nodeType\": \"BinaryOperation\",\n                        \"operator\": \"!=\",\n                        \"rightExpression\": {\n                          \"argumentTypes\": null,\n                          \"hexValue\": \"30\",\n                          \"id\": 5436,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": true,\n                          \"kind\": \"number\",\n                          \"lValueRequested\": false,\n                          \"nodeType\": \"Literal\",\n                          \"src\": \"33825:1:6\",\n                          \"subdenomination\": null,\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_rational_0_by_1\",\n                            \"typeString\": \"int_const 0\"\n                          },\n                          \"value\": \"0\"\n                        },\n                        \"src\": \"33794:32:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        }\n                      },\n                      \"nodeType\": \"BinaryOperation\",\n                      \"operator\": \"||\",\n                      \"rightExpression\": {\n                        \"argumentTypes\": null,\n                        \"commonType\": {\n                          \"typeIdentifier\": \"t_uint256\",\n                          \"typeString\": \"uint256\"\n                        },\n                        \"id\": 5441,\n                        \"isConstant\": false,\n                        \"isLValue\": false,\n                        \"isPure\": false,\n                        \"lValueRequested\": false,\n                        \"leftExpression\": {\n                          \"argumentTypes\": null,\n                          \"expression\": {\n                            \"argumentTypes\": null,\n                            \"id\": 5438,\n                            \"name\": \"unlockedLiquidity\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 5322,\n                            \"src\": \"33830:17:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                              \"typeString\": \"struct AssetLib.Asset memory\"\n                            }\n                          },\n                          \"id\": 5439,\n                          \"isConstant\": false,\n                          \"isLValue\": true,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"memberName\": \"compoundInterest\",\n                          \"nodeType\": \"MemberAccess\",\n                          \"referencedDeclaration\": 2787,\n                          \"src\": \"33830:34:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          }\n                        },\n                        \"nodeType\": \"BinaryOperation\",\n                        \"operator\": \"!=\",\n                        \"rightExpression\": {\n                          \"argumentTypes\": null,\n                          \"hexValue\": \"30\",\n                          \"id\": 5440,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": true,\n                          \"kind\": \"number\",\n                          \"lValueRequested\": false,\n                          \"nodeType\": \"Literal\",\n                          \"src\": \"33868:1:6\",\n                          \"subdenomination\": null,\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_rational_0_by_1\",\n                            \"typeString\": \"int_const 0\"\n                          },\n                          \"value\": \"0\"\n                        },\n                        \"src\": \"33830:39:6\",\n                        \"typeDescriptions\": {\n                          \"typeIdentifier\": \"t_bool\",\n                          \"typeString\": \"bool\"\n                        }\n                      },\n                      \"src\": \"33794:75:6\",\n                      \"typeDescriptions\": {\n                        \"typeIdentifier\": \"t_bool\",\n                        \"typeString\": \"bool\"\n                      }\n                    },\n                    \"src\": \"33782:87:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_bool\",\n                      \"typeString\": \"bool\"\n                    }\n                  },\n                  \"id\": 5444,\n                  \"nodeType\": \"ExpressionStatement\",\n                  \"src\": \"33782:87:6\"\n                },\n                {\n                  \"condition\": {\n                    \"argumentTypes\": null,\n                    \"id\": 5445,\n                    \"name\": \"collected\",\n                    \"nodeType\": \"Identifier\",\n                    \"overloadedDeclarations\": [],\n                    \"referencedDeclaration\": 5326,\n                    \"src\": \"33883:9:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_bool\",\n                      \"typeString\": \"bool\"\n                    }\n                  },\n                  \"falseBody\": null,\n                  \"id\": 5487,\n                  \"nodeType\": \"IfStatement\",\n                  \"src\": \"33879:421:6\",\n                  \"trueBody\": {\n                    \"id\": 5486,\n                    \"nodeType\": \"Block\",\n                    \"src\": \"33894:406:6\",\n                    \"statements\": [\n                      {\n                        \"eventCall\": {\n                          \"argumentTypes\": null,\n                          \"arguments\": [\n                            {\n                              \"argumentTypes\": null,\n                              \"id\": 5447,\n                              \"name\": \"sender\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 5317,\n                              \"src\": \"33932:6:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_address\",\n                                \"typeString\": \"address\"\n                              }\n                            },\n                            {\n                              \"argumentTypes\": null,\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"id\": 5448,\n                                \"name\": \"unlockedLiquidity\",\n                                \"nodeType\": \"Identifier\",\n                                \"overloadedDeclarations\": [],\n                                \"referencedDeclaration\": 5322,\n                                \"src\": \"33940:17:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                  \"typeString\": \"struct AssetLib.Asset memory\"\n                                }\n                              },\n                              \"id\": 5449,\n                              \"isConstant\": false,\n                              \"isLValue\": true,\n                              \"isPure\": false,\n                              \"lValueRequested\": false,\n                              \"memberName\": \"principal\",\n                              \"nodeType\": \"MemberAccess\",\n                              \"referencedDeclaration\": 2785,\n                              \"src\": \"33940:27:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_uint256\",\n                                \"typeString\": \"uint256\"\n                              }\n                            },\n                            {\n                              \"argumentTypes\": null,\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"id\": 5450,\n                                \"name\": \"unlockedLiquidity\",\n                                \"nodeType\": \"Identifier\",\n                                \"overloadedDeclarations\": [],\n                                \"referencedDeclaration\": 5322,\n                                \"src\": \"33969:17:6\",\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                  \"typeString\": \"struct AssetLib.Asset memory\"\n                                }\n                              },\n                              \"id\": 5451,\n                              \"isConstant\": false,\n                              \"isLValue\": true,\n                              \"isPure\": false,\n                              \"lValueRequested\": false,\n                              \"memberName\": \"compoundInterest\",\n                              \"nodeType\": \"MemberAccess\",\n                              \"referencedDeclaration\": 2787,\n                              \"src\": \"33969:34:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_uint256\",\n                                \"typeString\": \"uint256\"\n                              }\n                            }\n                          ],\n                          \"expression\": {\n                            \"argumentTypes\": [\n                              {\n                                \"typeIdentifier\": \"t_address\",\n                                \"typeString\": \"address\"\n                              },\n                              {\n                                \"typeIdentifier\": \"t_uint256\",\n                                \"typeString\": \"uint256\"\n                              },\n                              {\n                                \"typeIdentifier\": \"t_uint256\",\n                                \"typeString\": \"uint256\"\n                              }\n                            ],\n                            \"id\": 5446,\n                            \"name\": \"LiquidityUnlocked\",\n                            \"nodeType\": \"Identifier\",\n                            \"overloadedDeclarations\": [],\n                            \"referencedDeclaration\": 3694,\n                            \"src\": \"33914:17:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_function_event_nonpayable$_t_address_$_t_uint256_$_t_uint256_$returns$__$\",\n                              \"typeString\": \"function (address,uint256,uint256)\"\n                            }\n                          },\n                          \"id\": 5452,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"kind\": \"functionCall\",\n                          \"lValueRequested\": false,\n                          \"names\": [],\n                          \"nodeType\": \"FunctionCall\",\n                          \"src\": \"33914:90:6\",\n                          \"tryCall\": false,\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_tuple$__$\",\n                            \"typeString\": \"tuple()\"\n                          }\n                        },\n                        \"id\": 5453,\n                        \"nodeType\": \"EmitStatement\",\n                        \"src\": \"33909:95:6\"\n                      },\n                      {\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"arguments\": [\n                            {\n                              \"argumentTypes\": null,\n                              \"id\": 5457,\n                              \"name\": \"unlockedLiquidity\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 5322,\n                              \"src\": \"34045:17:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                \"typeString\": \"struct AssetLib.Asset memory\"\n                              }\n                            }\n                          ],\n                          \"expression\": {\n                            \"argumentTypes\": [\n                              {\n                                \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                \"typeString\": \"struct AssetLib.Asset memory\"\n                              }\n                            ],\n                            \"expression\": {\n                              \"argumentTypes\": null,\n                              \"id\": 5454,\n                              \"name\": \"_accruedGlobalLocked\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 3776,\n                              \"src\": \"34019:20:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                                \"typeString\": \"struct AssetLib.Asset storage ref\"\n                              }\n                            },\n                            \"id\": 5456,\n                            \"isConstant\": false,\n                            \"isLValue\": true,\n                            \"isPure\": false,\n                            \"lValueRequested\": false,\n                            \"memberName\": \"iSub\",\n                            \"nodeType\": \"MemberAccess\",\n                            \"referencedDeclaration\": 2938,\n                            \"src\": \"34019:25:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_function_internal_nonpayable$_t_struct$_Asset_$2788_storage_ptr_$_t_struct$_Asset_$2788_memory_ptr_$returns$__$bound_to$_t_struct$_Asset_$2788_storage_ptr_$\",\n                              \"typeString\": \"function (struct AssetLib.Asset storage pointer,struct AssetLib.Asset memory)\"\n                            }\n                          },\n                          \"id\": 5458,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"kind\": \"functionCall\",\n                          \"lValueRequested\": false,\n                          \"names\": [],\n                          \"nodeType\": \"FunctionCall\",\n                          \"src\": \"34019:44:6\",\n                          \"tryCall\": false,\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_tuple$__$\",\n                            \"typeString\": \"tuple()\"\n                          }\n                        },\n                        \"id\": 5459,\n                        \"nodeType\": \"ExpressionStatement\",\n                        \"src\": \"34019:44:6\"\n                      },\n                      {\n                        \"condition\": {\n                          \"argumentTypes\": null,\n                          \"commonType\": {\n                            \"typeIdentifier\": \"t_uint256\",\n                            \"typeString\": \"uint256\"\n                          },\n                          \"id\": 5463,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"lValueRequested\": false,\n                          \"leftExpression\": {\n                            \"argumentTypes\": null,\n                            \"expression\": {\n                              \"argumentTypes\": null,\n                              \"id\": 5460,\n                              \"name\": \"lockedAssets\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 5337,\n                              \"src\": \"34081:12:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_array$_t_struct$_LockedAsset_$3653_storage_$dyn_storage_ptr\",\n                                \"typeString\": \"struct Staking.LockedAsset storage ref[] storage pointer\"\n                              }\n                            },\n                            \"id\": 5461,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": false,\n                            \"lValueRequested\": false,\n                            \"memberName\": \"length\",\n                            \"nodeType\": \"MemberAccess\",\n                            \"referencedDeclaration\": null,\n                            \"src\": \"34081:19:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_uint256\",\n                              \"typeString\": \"uint256\"\n                            }\n                          },\n                          \"nodeType\": \"BinaryOperation\",\n                          \"operator\": \"!=\",\n                          \"rightExpression\": {\n                            \"argumentTypes\": null,\n                            \"hexValue\": \"30\",\n                            \"id\": 5462,\n                            \"isConstant\": false,\n                            \"isLValue\": false,\n                            \"isPure\": true,\n                            \"kind\": \"number\",\n                            \"lValueRequested\": false,\n                            \"nodeType\": \"Literal\",\n                            \"src\": \"34104:1:6\",\n                            \"subdenomination\": null,\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_rational_0_by_1\",\n                              \"typeString\": \"int_const 0\"\n                            },\n                            \"value\": \"0\"\n                          },\n                          \"src\": \"34081:24:6\",\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_bool\",\n                            \"typeString\": \"bool\"\n                          }\n                        },\n                        \"falseBody\": null,\n                        \"id\": 5473,\n                        \"nodeType\": \"IfStatement\",\n                        \"src\": \"34077:103:6\",\n                        \"trueBody\": {\n                          \"id\": 5472,\n                          \"nodeType\": \"Block\",\n                          \"src\": \"34107:73:6\",\n                          \"statements\": [\n                            {\n                              \"expression\": {\n                                \"argumentTypes\": null,\n                                \"arguments\": [\n                                  {\n                                    \"argumentTypes\": null,\n                                    \"id\": 5469,\n                                    \"name\": \"unlockedLiquidity\",\n                                    \"nodeType\": \"Identifier\",\n                                    \"overloadedDeclarations\": [],\n                                    \"referencedDeclaration\": 5322,\n                                    \"src\": \"34147:17:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                      \"typeString\": \"struct AssetLib.Asset memory\"\n                                    }\n                                  }\n                                ],\n                                \"expression\": {\n                                  \"argumentTypes\": [\n                                    {\n                                      \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                      \"typeString\": \"struct AssetLib.Asset memory\"\n                                    }\n                                  ],\n                                  \"expression\": {\n                                    \"argumentTypes\": null,\n                                    \"expression\": {\n                                      \"argumentTypes\": null,\n                                      \"id\": 5464,\n                                      \"name\": \"locked\",\n                                      \"nodeType\": \"Identifier\",\n                                      \"overloadedDeclarations\": [],\n                                      \"referencedDeclaration\": 5329,\n                                      \"src\": \"34125:6:6\",\n                                      \"typeDescriptions\": {\n                                        \"typeIdentifier\": \"t_struct$_Locked_$3659_storage_ptr\",\n                                        \"typeString\": \"struct Staking.Locked storage pointer\"\n                                      }\n                                    },\n                                    \"id\": 5467,\n                                    \"isConstant\": false,\n                                    \"isLValue\": true,\n                                    \"isPure\": false,\n                                    \"lValueRequested\": false,\n                                    \"memberName\": \"aggregate\",\n                                    \"nodeType\": \"MemberAccess\",\n                                    \"referencedDeclaration\": 3655,\n                                    \"src\": \"34125:16:6\",\n                                    \"typeDescriptions\": {\n                                      \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                                      \"typeString\": \"struct AssetLib.Asset storage ref\"\n                                    }\n                                  },\n                                  \"id\": 5468,\n                                  \"isConstant\": false,\n                                  \"isLValue\": true,\n                                  \"isPure\": false,\n                                  \"lValueRequested\": false,\n                                  \"memberName\": \"iSub\",\n                                  \"nodeType\": \"MemberAccess\",\n                                  \"referencedDeclaration\": 2938,\n                                  \"src\": \"34125:21:6\",\n                                  \"typeDescriptions\": {\n                                    \"typeIdentifier\": \"t_function_internal_nonpayable$_t_struct$_Asset_$2788_storage_ptr_$_t_struct$_Asset_$2788_memory_ptr_$returns$__$bound_to$_t_struct$_Asset_$2788_storage_ptr_$\",\n                                    \"typeString\": \"function (struct AssetLib.Asset storage pointer,struct AssetLib.Asset memory)\"\n                                  }\n                                },\n                                \"id\": 5470,\n                                \"isConstant\": false,\n                                \"isLValue\": false,\n                                \"isPure\": false,\n                                \"kind\": \"functionCall\",\n                                \"lValueRequested\": false,\n                                \"names\": [],\n                                \"nodeType\": \"FunctionCall\",\n                                \"src\": \"34125:40:6\",\n                                \"tryCall\": false,\n                                \"typeDescriptions\": {\n                                  \"typeIdentifier\": \"t_tuple$__$\",\n                                  \"typeString\": \"tuple()\"\n                                }\n                              },\n                              \"id\": 5471,\n                              \"nodeType\": \"ExpressionStatement\",\n                              \"src\": \"34125:40:6\"\n                            }\n                          ]\n                        }\n                      },\n                      {\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"arguments\": [\n                            {\n                              \"argumentTypes\": null,\n                              \"id\": 5477,\n                              \"name\": \"unlockedLiquidity\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 5322,\n                              \"src\": \"34223:17:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                \"typeString\": \"struct AssetLib.Asset memory\"\n                              }\n                            }\n                          ],\n                          \"expression\": {\n                            \"argumentTypes\": [\n                              {\n                                \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                \"typeString\": \"struct AssetLib.Asset memory\"\n                              }\n                            ],\n                            \"expression\": {\n                              \"argumentTypes\": null,\n                              \"id\": 5474,\n                              \"name\": \"_accruedGlobalLiquidity\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 3774,\n                              \"src\": \"34194:23:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_struct$_Asset_$2788_storage\",\n                                \"typeString\": \"struct AssetLib.Asset storage ref\"\n                              }\n                            },\n                            \"id\": 5476,\n                            \"isConstant\": false,\n                            \"isLValue\": true,\n                            \"isPure\": false,\n                            \"lValueRequested\": false,\n                            \"memberName\": \"iAdd\",\n                            \"nodeType\": \"MemberAccess\",\n                            \"referencedDeclaration\": 2878,\n                            \"src\": \"34194:28:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_function_internal_nonpayable$_t_struct$_Asset_$2788_storage_ptr_$_t_struct$_Asset_$2788_memory_ptr_$returns$__$bound_to$_t_struct$_Asset_$2788_storage_ptr_$\",\n                              \"typeString\": \"function (struct AssetLib.Asset storage pointer,struct AssetLib.Asset memory)\"\n                            }\n                          },\n                          \"id\": 5478,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"kind\": \"functionCall\",\n                          \"lValueRequested\": false,\n                          \"names\": [],\n                          \"nodeType\": \"FunctionCall\",\n                          \"src\": \"34194:47:6\",\n                          \"tryCall\": false,\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_tuple$__$\",\n                            \"typeString\": \"tuple()\"\n                          }\n                        },\n                        \"id\": 5479,\n                        \"nodeType\": \"ExpressionStatement\",\n                        \"src\": \"34194:47:6\"\n                      },\n                      {\n                        \"expression\": {\n                          \"argumentTypes\": null,\n                          \"arguments\": [\n                            {\n                              \"argumentTypes\": null,\n                              \"id\": 5483,\n                              \"name\": \"unlockedLiquidity\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 5322,\n                              \"src\": \"34271:17:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                \"typeString\": \"struct AssetLib.Asset memory\"\n                              }\n                            }\n                          ],\n                          \"expression\": {\n                            \"argumentTypes\": [\n                              {\n                                \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                                \"typeString\": \"struct AssetLib.Asset memory\"\n                              }\n                            ],\n                            \"expression\": {\n                              \"argumentTypes\": null,\n                              \"id\": 5480,\n                              \"name\": \"liquidity\",\n                              \"nodeType\": \"Identifier\",\n                              \"overloadedDeclarations\": [],\n                              \"referencedDeclaration\": 5324,\n                              \"src\": \"34256:9:6\",\n                              \"typeDescriptions\": {\n                                \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                                \"typeString\": \"struct AssetLib.Asset storage pointer\"\n                              }\n                            },\n                            \"id\": 5482,\n                            \"isConstant\": false,\n                            \"isLValue\": true,\n                            \"isPure\": false,\n                            \"lValueRequested\": false,\n                            \"memberName\": \"iAdd\",\n                            \"nodeType\": \"MemberAccess\",\n                            \"referencedDeclaration\": 2878,\n                            \"src\": \"34256:14:6\",\n                            \"typeDescriptions\": {\n                              \"typeIdentifier\": \"t_function_internal_nonpayable$_t_struct$_Asset_$2788_storage_ptr_$_t_struct$_Asset_$2788_memory_ptr_$returns$__$bound_to$_t_struct$_Asset_$2788_storage_ptr_$\",\n                              \"typeString\": \"function (struct AssetLib.Asset storage pointer,struct AssetLib.Asset memory)\"\n                            }\n                          },\n                          \"id\": 5484,\n                          \"isConstant\": false,\n                          \"isLValue\": false,\n                          \"isPure\": false,\n                          \"kind\": \"functionCall\",\n                          \"lValueRequested\": false,\n                          \"names\": [],\n                          \"nodeType\": \"FunctionCall\",\n                          \"src\": \"34256:33:6\",\n                          \"tryCall\": false,\n                          \"typeDescriptions\": {\n                            \"typeIdentifier\": \"t_tuple$__$\",\n                            \"typeString\": \"tuple()\"\n                          }\n                        },\n                        \"id\": 5485,\n                        \"nodeType\": \"ExpressionStatement\",\n                        \"src\": \"34256:33:6\"\n                      }\n                    ]\n                  }\n                }\n              ]\n            },\n            \"documentation\": null,\n            \"id\": 5489,\n            \"implemented\": true,\n            \"kind\": \"function\",\n            \"modifiers\": [],\n            \"name\": \"_collectLiquidity\",\n            \"nodeType\": \"FunctionDefinition\",\n            \"overrides\": null,\n            \"parameters\": {\n              \"id\": 5320,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 5317,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"sender\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 5489,\n                  \"src\": \"31639:14:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_address\",\n                    \"typeString\": \"address\"\n                  },\n                  \"typeName\": {\n                    \"id\": 5316,\n                    \"name\": \"address\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"31639:7:6\",\n                    \"stateMutability\": \"nonpayable\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_address\",\n                      \"typeString\": \"address\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 5319,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"at_block\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 5489,\n                  \"src\": \"31655:16:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_uint256\",\n                    \"typeString\": \"uint256\"\n                  },\n                  \"typeName\": {\n                    \"id\": 5318,\n                    \"name\": \"uint256\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"31655:7:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_uint256\",\n                      \"typeString\": \"uint256\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"31638:34:6\"\n            },\n            \"returnParameters\": {\n              \"id\": 5327,\n              \"nodeType\": \"ParameterList\",\n              \"parameters\": [\n                {\n                  \"constant\": false,\n                  \"id\": 5322,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"unlockedLiquidity\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 5489,\n                  \"src\": \"31706:39:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"memory\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_struct$_Asset_$2788_memory_ptr\",\n                    \"typeString\": \"struct AssetLib.Asset\"\n                  },\n                  \"typeName\": {\n                    \"contractScope\": null,\n                    \"id\": 5321,\n                    \"name\": \"AssetLib.Asset\",\n                    \"nodeType\": \"UserDefinedTypeName\",\n                    \"referencedDeclaration\": 2788,\n                    \"src\": \"31706:14:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                      \"typeString\": \"struct AssetLib.Asset\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 5324,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"liquidity\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 5489,\n                  \"src\": \"31747:32:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"storage\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                    \"typeString\": \"struct AssetLib.Asset\"\n                  },\n                  \"typeName\": {\n                    \"contractScope\": null,\n                    \"id\": 5323,\n                    \"name\": \"AssetLib.Asset\",\n                    \"nodeType\": \"UserDefinedTypeName\",\n                    \"referencedDeclaration\": 2788,\n                    \"src\": \"31747:14:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_struct$_Asset_$2788_storage_ptr\",\n                      \"typeString\": \"struct AssetLib.Asset\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                },\n                {\n                  \"constant\": false,\n                  \"id\": 5326,\n                  \"mutability\": \"mutable\",\n                  \"name\": \"collected\",\n                  \"nodeType\": \"VariableDeclaration\",\n                  \"overrides\": null,\n                  \"scope\": 5489,\n                  \"src\": \"31781:14:6\",\n                  \"stateVariable\": false,\n                  \"storageLocation\": \"default\",\n                  \"typeDescriptions\": {\n                    \"typeIdentifier\": \"t_bool\",\n                    \"typeString\": \"bool\"\n                  },\n                  \"typeName\": {\n                    \"id\": 5325,\n                    \"name\": \"bool\",\n                    \"nodeType\": \"ElementaryTypeName\",\n                    \"src\": \"31781:4:6\",\n                    \"typeDescriptions\": {\n                      \"typeIdentifier\": \"t_bool\",\n                      \"typeString\": \"bool\"\n                    }\n                  },\n                  \"value\": null,\n                  \"visibility\": \"internal\"\n                }\n              ],\n              \"src\": \"31705:91:6\"\n            },\n            \"scope\": 5490,\n            \"src\": \"31612:2694:6\",\n            \"stateMutability\": \"nonpayable\",\n            \"virtual\": false,\n            \"visibility\": \"internal\"\n          }\n        ],\n        \"scope\": 5491,\n        \"src\": \"1040:33269:6\"\n      }\n    ],\n    \"src\": \"820:33490:6\"\n  },\n  \"compiler\": {\n    \"name\": \"solc\",\n    \"version\": \"0.6.8+commit.0bbfe453.Emscripten.clang\"\n  },\n  \"networks\": {},\n  \"schemaVersion\": \"3.1.0\",\n  \"updatedAt\": \"2020-10-13T17:26:53.190Z\",\n  \"devdoc\": {\n    \"methods\": {\n      \"addInterestRate(uint256,uint256)\": {\n        \"details\": \"expiration period\",\n        \"params\": {\n          \"expirationBlock\": \"- block number beyond which is the carrier Tx considered expired, and so rejected.                    This is for protection of Tx sender to exactly define lifecycle length of the Tx,                    and so avoiding uncertainty of how long Tx sender needs to wait for Tx processing.                    Tx can be withheld\",\n          \"rate\": \"- signed interest rate value in [10**18] units => real_rate [1] = rate [10**18] / 10**18\"\n        }\n      },\n      \"constructor\": {\n        \"params\": {\n          \"ERC20Address\": \"address of the ERC20 contract\"\n        }\n      },\n      \"deleteContract(address,uint256)\": {\n        \"details\": \"owner only + only on or after `_earliestDelete` block\",\n        \"params\": {\n          \"payoutAddress\": \"address to transfer the balances to. Ensure that this is able to handle ERC20 tokens\"\n        }\n      },\n      \"getLockedAssetsForUser(address)\": {\n        \"details\": \"Returns locked assets decomposed in to 3 separate arrays (principal, compound interest, liquid since block)     NOTE(pb): This method might be quite expensive, depending on size of locked assets\"\n      },\n      \"getRoleAdmin(bytes32)\": {\n        \"details\": \"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}.     * To change a role's admin, use {_setRoleAdmin}.\"\n      },\n      \"getRoleMember(bytes32,uint256)\": {\n        \"details\": \"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive.     * Role bearers are not sorted in any particular way, and their ordering may change at any point.     * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information.\"\n      },\n      \"getRoleMemberCount(bytes32)\": {\n        \"details\": \"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role.\"\n      },\n      \"grantRole(bytes32,address)\": {\n        \"details\": \"Grants `role` to `account`.     * If `account` had not been already granted `role`, emits a {RoleGranted} event.     * Requirements:     * - the caller must have ``role``'s admin role.\"\n      },\n      \"hasRole(bytes32,address)\": {\n        \"details\": \"Returns `true` if `account` has been granted `role`.\"\n      },\n      \"pauseSince(uint256,uint256)\": {\n        \"details\": \"Delegate only\",\n        \"params\": {\n          \"blockNumber\": \"block number since which non-admin interaction will be paused (for all _getBlockNumber() >= blockNumber)\"\n        }\n      },\n      \"renounceRole(bytes32,address)\": {\n        \"details\": \"Revokes `role` from the calling account.     * Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced).     * If the calling account had been granted `role`, emits a {RoleRevoked} event.     * Requirements:     * - the caller must be `account`.\"\n      },\n      \"revokeRole(bytes32,address)\": {\n        \"details\": \"Revokes `role` from `account`.     * If `account` had been granted `role`, emits a {RoleRevoked} event.     * Requirements:     * - the caller must have ``role``'s admin role.\"\n      },\n      \"topUpRewardsPool(uint256,uint256)\": {\n        \"details\": \"Even though this is considered as administrative action (is not affected by by contract paused state, it can be executed by anyone who wishes to top-up the rewards pool (funds are sent in to contract, *not* the other way around). The Rewards Pool is exclusively dedicated to cover withdrawals of user' compound interest, which is effectively the reward.\"\n      },\n      \"unbindStake(uint256,uint256)\": {\n        \"details\": \"public access\",\n        \"params\": {\n          \"amount\": \"- value to un-bind from the stake                If `amount=0` then the **WHOLE** stake (including                compound interest) will be unbound.\"\n        }\n      },\n      \"updateLockPeriod(uint64,uint256)\": {\n        \"details\": \"Delegate only\",\n        \"params\": {\n          \"numOfBlocks\": \"length of the lock period\"\n        }\n      },\n      \"withdraw(uint256,uint256)\": {\n        \"details\": \"public access\",\n        \"params\": {\n          \"amount\": \"- value to withdraw\"\n        }\n      },\n      \"withdrawCompoundInterest(uint256)\": {\n        \"details\": \"public access\"\n      },\n      \"withdrawExcessTokens(address,uint256)\": {\n        \"details\": \"Withdraw \\\"excess\\\" tokens, which were sent to contract directly via direct ERC20.transfer(...),     without interacting with API of this (Staking) contract, what could be done only by mistake.     Thus this method is meant to be used primarily for rescue purposes, enabling withdrawal of such     \\\"excess\\\" tokens out of contract.\",\n        \"params\": {\n          \"targetAddress\": \": address to send tokens to\",\n          \"txExpirationBlock\": \": block number until which is the transaction valid (inclusive).                           When transaction is processed after this block, it fails.\"\n        }\n      },\n      \"withdrawFromRewardsPool(uint256,address,uint256)\": {\n        \"details\": \"Withdraw tokens from rewards pool.\",\n        \"params\": {\n          \"amount\": \": amount to withdraw.                If `amount == 0` then whole amount in rewards pool will be withdrawn.\",\n          \"targetAddress\": \": address to send tokens to\"\n        }\n      },\n      \"withdrawPrincipal(uint256)\": {\n        \"details\": \"public access\"\n      },\n      \"withdrawWholeLiquidity(uint256)\": {\n        \"details\": \"public access\"\n      }\n    }\n  },\n  \"userdoc\": {\n    \"methods\": {\n      \"addInterestRate(uint256,uint256)\": {\n        \"notice\": \"Add new interest rate in to the ordered container of previously added interest rates\"\n      },\n      \"deleteContract(address,uint256)\": {\n        \"notice\": \"Delete the contract, transfers the remaining token and ether balance to the specified payoutAddress\"\n      },\n      \"pauseSince(uint256,uint256)\": {\n        \"notice\": \"Pauses all NON-administrative interaction with the contract since the specidfed block number \"\n      },\n      \"unbindStake(uint256,uint256)\": {\n        \"notice\": \"Unbinds amount from the stake of sender of the transaction,        and *LOCKS* it for number of blocks defined by value of the        `_lockPeriodInBlocks` state of this contract at the point        of this call.        The locked amount can *NOT* be withdrawn from the contract        *BEFORE* the lock period ends.     *         Unbinding (=calling this method) also means, that compound        interest will be calculated for period since la.\"\n      },\n      \"updateLockPeriod(uint64,uint256)\": {\n        \"notice\": \"Updates Lock Period value\"\n      },\n      \"withdraw(uint256,uint256)\": {\n        \"notice\": \"Withdraws amount from sender' available liquidity pool back to sender address,        preferring withdrawal from compound interest dimension of liquidity.\"\n      },\n      \"withdrawCompoundInterest(uint256)\": {\n        \"notice\": \"Withdraws *WHOLE* compound interest amount available to sender.\"\n      },\n      \"withdrawPrincipal(uint256)\": {\n        \"notice\": \"Withdraws *WHOLE* compound interest amount available to sender.\"\n      },\n      \"withdrawWholeLiquidity(uint256)\": {\n        \"notice\": \"Withdraws whole liquidity available to sender back to sender' address,\"\n      }\n    }\n  }\n}"
  },
  {
    "path": "packages/fetchai/contracts/staking_erc20/contract.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the erc1155 contract definition.\"\"\"\n\nimport logging\n\nfrom aea_ledger_ethereum import EthereumApi\n\nfrom aea.common import Address, JSONLike\nfrom aea.configurations.base import PublicId\nfrom aea.contracts.base import Contract\nfrom aea.crypto.base import LedgerApi\n\n\n_default_logger = logging.getLogger(\n    \"aea.packages.fetchai.contracts.staking_erc20.contract\"\n)\n\nPUBLIC_ID = PublicId.from_str(\"fetchai/staking_erc20:0.10.3\")\n\n\nclass StakingERC20(Contract):\n    \"\"\"The ERC1155 contract class which acts as a bridge between AEA framework and ERC1155 ABI.\"\"\"\n\n    contract_id = PUBLIC_ID\n\n    @classmethod\n    def get_stake(\n        cls,\n        ledger_api: LedgerApi,\n        contract_address: Address,\n        address: Address,\n    ) -> JSONLike:\n        \"\"\"\n        Get the balance for a specific token id.\n\n        :param ledger_api: the ledger API\n        :param contract_address: the address of the contract\n        :param address: the address\n        :return: the balance in a dictionary - {\"balance\": {token_id: int, balance: int}}\n        \"\"\"\n        if ledger_api.identifier == EthereumApi.identifier:\n            instance = cls.get_instance(ledger_api, contract_address)\n            result = instance.functions.getStakeForUser(address).call()\n            return {\"stake\": result[0]}\n        raise NotImplementedError\n"
  },
  {
    "path": "packages/fetchai/contracts/staking_erc20/contract.yaml",
    "content": "name: staking_erc20\nauthor: fetchai\nversion: 0.10.3\ntype: contract\ndescription: The staking_erc20 contract contains the main staking contract of Fetch.ai\n  for Ethereum mainnet.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: QmXcVNZrAEX5Ja2fPKBYDVV77s5JKXtyGP19pgZfJNerrw\n  __init__.py: QmdKarQHWsEyedE8E3X6my3zLZkdTGGrbmyJaidti3Sqyx\n  build/Migrations.json: QmfFYYWoq1L1Ni6YPBWWoRPvCZKBLZ7qzN3UDX537mCeuE\n  build/staking_erc20.json: QmVf2BuDDJPoCHDwEQKHdgfph4CbTFpqJJvcDLaM9tyoQq\n  contract.py: QmWgc5hyfnxZ5R5YTo6HZpTsqBuL3WuhJzQdkjqgFnZNyh\nfingerprint_ignore_patterns: []\nclass_name: StakingERC20\ncontract_interface_paths:\n  ethereum: build/staking_erc20.json\ndependencies:\n  aea-ledger-ethereum:\n    version: <2.0.0,>=1.0.0\n"
  },
  {
    "path": "packages/fetchai/protocols/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the protocol packages authored by Fetch.ai.\"\"\"\n"
  },
  {
    "path": "packages/fetchai/protocols/acn/README.md",
    "content": "# ACN Protocol\n\n## Description\n\nThis is a protocol for ACN (agent communication network) envelope delivery.\n\n## Specification\n\n```yaml\n---\nname: acn\nauthor: fetchai\nversion: 1.1.7\ndescription: The protocol used for envelope delivery on the ACN.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nprotocol_specification_id: aea/acn:1.0.0\nspeech_acts:\n  register:\n    record: ct:AgentRecord\n  lookup_request:\n    agent_address: pt:str\n  lookup_response:\n    record: ct:AgentRecord\n  aea_envelope:\n    envelope: pt:bytes\n    record: ct:AgentRecord\n  status:\n    body: ct:StatusBody\n...\n---\nct:AgentRecord:\n  string service_id = 1;\n  string ledger_id = 2;\n  string address = 3;\n  string public_key = 4;\n  string peer_public_key = 5;\n  string signature = 6;\n  string not_before = 7;\n  string not_after = 8;\nct:StatusBody: |\n  enum StatusCodeEnum {\n    // common (0x)\n    SUCCESS = 0;\n    ERROR_UNSUPPORTED_VERSION = 1;\n    ERROR_UNEXPECTED_PAYLOAD = 2;\n    ERROR_GENERIC = 3;\n    ERROR_DECODE = 4;\n    // register (1x)\n    ERROR_WRONG_AGENT_ADDRESS = 10;\n    ERROR_WRONG_PUBLIC_KEY = 11;\n    ERROR_INVALID_PROOF = 12;\n    ERROR_UNSUPPORTED_LEDGER = 13;\n    // lookup & delivery (2x) \n    ERROR_UNKNOWN_AGENT_ADDRESS = 20;\n    ERROR_AGENT_NOT_READY = 21;\n  }\n  StatusCodeEnum code = 1;\n  repeated string msgs = 2;\n...\n---\ninitiation: [register, lookup_request, aea_envelope]\nreply:\n  register: [status]\n  lookup_request: [lookup_response, status]\n  aea_envelope: [status]\n  status: []\n  lookup_response: []\ntermination: [status, lookup_response]\nroles: {node}\nend_states: [successful, failed]\nkeep_terminal_state_dialogues: false\n...\n```\n\n## Links\n"
  },
  {
    "path": "packages/fetchai/protocols/acn/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nThis module contains the support resources for the acn protocol.\n\nIt was created with protocol buffer compiler version `libprotoc 3.19.4` and aea version `1.2.5`.\n\"\"\"\n\nfrom packages.fetchai.protocols.acn.message import AcnMessage\nfrom packages.fetchai.protocols.acn.serialization import AcnSerializer\n\n\nAcnMessage.serializer = AcnSerializer\n"
  },
  {
    "path": "packages/fetchai/protocols/acn/acn.proto",
    "content": "syntax = \"proto3\";\n\npackage aea.aea.acn.v1_0_0;\n\nmessage AcnMessage{\n\n  // Custom Types\n  message AgentRecord{\n    string service_id = 1;\n    string ledger_id = 2;\n    string address = 3;\n    string public_key = 4;\n    string peer_public_key = 5;\n    string signature = 6;\n    string not_before = 7;\n    string not_after = 8;\n  }\n\n  message StatusBody{\n    enum StatusCodeEnum {\n      // common (0x)\n      SUCCESS = 0;\n      ERROR_UNSUPPORTED_VERSION = 1;\n      ERROR_UNEXPECTED_PAYLOAD = 2;\n      ERROR_GENERIC = 3;\n      ERROR_DECODE = 4;\n      // register (1x)\n      ERROR_WRONG_AGENT_ADDRESS = 10;\n      ERROR_WRONG_PUBLIC_KEY = 11;\n      ERROR_INVALID_PROOF = 12;\n      ERROR_UNSUPPORTED_LEDGER = 13;\n      // lookup & delivery (2x) \n      ERROR_UNKNOWN_AGENT_ADDRESS = 20;\n      ERROR_AGENT_NOT_READY = 21;\n    }\n    StatusCodeEnum code = 1;\n    repeated string msgs = 2;\n  }\n\n\n  // Performatives and contents\n  message Register_Performative{\n    AgentRecord record = 1;\n  }\n\n  message Lookup_Request_Performative{\n    string agent_address = 1;\n  }\n\n  message Lookup_Response_Performative{\n    AgentRecord record = 1;\n  }\n\n  message Aea_Envelope_Performative{\n    bytes envelope = 1;\n    AgentRecord record = 2;\n  }\n\n  message Status_Performative{\n    StatusBody body = 1;\n  }\n\n\n  oneof performative{\n    Aea_Envelope_Performative aea_envelope = 5;\n    Lookup_Request_Performative lookup_request = 6;\n    Lookup_Response_Performative lookup_response = 7;\n    Register_Performative register = 8;\n    Status_Performative status = 9;\n  }\n}\n"
  },
  {
    "path": "packages/fetchai/protocols/acn/acn_pb2.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by the protocol buffer compiler.  DO NOT EDIT!\n# source: acn.proto\n\"\"\"Generated protocol buffer code.\"\"\"\nfrom google.protobuf import descriptor as _descriptor\nfrom google.protobuf import descriptor_pool as _descriptor_pool\nfrom google.protobuf import message as _message\nfrom google.protobuf import reflection as _reflection\nfrom google.protobuf import symbol_database as _symbol_database\n\n# @@protoc_insertion_point(imports)\n\n_sym_db = _symbol_database.Default()\n\n\nDESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(\n    b'\\n\\tacn.proto\\x12\\x12\\x61\\x65\\x61.aea.acn.v1_0_0\"\\x92\\x0b\\n\\nAcnMessage\\x12P\\n\\x0c\\x61\\x65\\x61_envelope\\x18\\x05 \\x01(\\x0b\\x32\\x38.aea.aea.acn.v1_0_0.AcnMessage.Aea_Envelope_PerformativeH\\x00\\x12T\\n\\x0elookup_request\\x18\\x06 \\x01(\\x0b\\x32:.aea.aea.acn.v1_0_0.AcnMessage.Lookup_Request_PerformativeH\\x00\\x12V\\n\\x0flookup_response\\x18\\x07 \\x01(\\x0b\\x32;.aea.aea.acn.v1_0_0.AcnMessage.Lookup_Response_PerformativeH\\x00\\x12H\\n\\x08register\\x18\\x08 \\x01(\\x0b\\x32\\x34.aea.aea.acn.v1_0_0.AcnMessage.Register_PerformativeH\\x00\\x12\\x44\\n\\x06status\\x18\\t \\x01(\\x0b\\x32\\x32.aea.aea.acn.v1_0_0.AcnMessage.Status_PerformativeH\\x00\\x1a\\xac\\x01\\n\\x0b\\x41gentRecord\\x12\\x12\\n\\nservice_id\\x18\\x01 \\x01(\\t\\x12\\x11\\n\\tledger_id\\x18\\x02 \\x01(\\t\\x12\\x0f\\n\\x07\\x61\\x64\\x64ress\\x18\\x03 \\x01(\\t\\x12\\x12\\n\\npublic_key\\x18\\x04 \\x01(\\t\\x12\\x17\\n\\x0fpeer_public_key\\x18\\x05 \\x01(\\t\\x12\\x11\\n\\tsignature\\x18\\x06 \\x01(\\t\\x12\\x12\\n\\nnot_before\\x18\\x07 \\x01(\\t\\x12\\x11\\n\\tnot_after\\x18\\x08 \\x01(\\t\\x1a\\x92\\x03\\n\\nStatusBody\\x12\\x46\\n\\x04\\x63ode\\x18\\x01 \\x01(\\x0e\\x32\\x38.aea.aea.acn.v1_0_0.AcnMessage.StatusBody.StatusCodeEnum\\x12\\x0c\\n\\x04msgs\\x18\\x02 \\x03(\\t\"\\xad\\x02\\n\\x0eStatusCodeEnum\\x12\\x0b\\n\\x07SUCCESS\\x10\\x00\\x12\\x1d\\n\\x19\\x45RROR_UNSUPPORTED_VERSION\\x10\\x01\\x12\\x1c\\n\\x18\\x45RROR_UNEXPECTED_PAYLOAD\\x10\\x02\\x12\\x11\\n\\rERROR_GENERIC\\x10\\x03\\x12\\x10\\n\\x0c\\x45RROR_DECODE\\x10\\x04\\x12\\x1d\\n\\x19\\x45RROR_WRONG_AGENT_ADDRESS\\x10\\n\\x12\\x1a\\n\\x16\\x45RROR_WRONG_PUBLIC_KEY\\x10\\x0b\\x12\\x17\\n\\x13\\x45RROR_INVALID_PROOF\\x10\\x0c\\x12\\x1c\\n\\x18\\x45RROR_UNSUPPORTED_LEDGER\\x10\\r\\x12\\x1f\\n\\x1b\\x45RROR_UNKNOWN_AGENT_ADDRESS\\x10\\x14\\x12\\x19\\n\\x15\\x45RROR_AGENT_NOT_READY\\x10\\x15\\x1aS\\n\\x15Register_Performative\\x12:\\n\\x06record\\x18\\x01 \\x01(\\x0b\\x32*.aea.aea.acn.v1_0_0.AcnMessage.AgentRecord\\x1a\\x34\\n\\x1bLookup_Request_Performative\\x12\\x15\\n\\ragent_address\\x18\\x01 \\x01(\\t\\x1aZ\\n\\x1cLookup_Response_Performative\\x12:\\n\\x06record\\x18\\x01 \\x01(\\x0b\\x32*.aea.aea.acn.v1_0_0.AcnMessage.AgentRecord\\x1ai\\n\\x19\\x41\\x65\\x61_Envelope_Performative\\x12\\x10\\n\\x08\\x65nvelope\\x18\\x01 \\x01(\\x0c\\x12:\\n\\x06record\\x18\\x02 \\x01(\\x0b\\x32*.aea.aea.acn.v1_0_0.AcnMessage.AgentRecord\\x1aN\\n\\x13Status_Performative\\x12\\x37\\n\\x04\\x62ody\\x18\\x01 \\x01(\\x0b\\x32).aea.aea.acn.v1_0_0.AcnMessage.StatusBodyB\\x0e\\n\\x0cperformativeb\\x06proto3'\n)\n\n\n_ACNMESSAGE = DESCRIPTOR.message_types_by_name[\"AcnMessage\"]\n_ACNMESSAGE_AGENTRECORD = _ACNMESSAGE.nested_types_by_name[\"AgentRecord\"]\n_ACNMESSAGE_STATUSBODY = _ACNMESSAGE.nested_types_by_name[\"StatusBody\"]\n_ACNMESSAGE_REGISTER_PERFORMATIVE = _ACNMESSAGE.nested_types_by_name[\n    \"Register_Performative\"\n]\n_ACNMESSAGE_LOOKUP_REQUEST_PERFORMATIVE = _ACNMESSAGE.nested_types_by_name[\n    \"Lookup_Request_Performative\"\n]\n_ACNMESSAGE_LOOKUP_RESPONSE_PERFORMATIVE = _ACNMESSAGE.nested_types_by_name[\n    \"Lookup_Response_Performative\"\n]\n_ACNMESSAGE_AEA_ENVELOPE_PERFORMATIVE = _ACNMESSAGE.nested_types_by_name[\n    \"Aea_Envelope_Performative\"\n]\n_ACNMESSAGE_STATUS_PERFORMATIVE = _ACNMESSAGE.nested_types_by_name[\n    \"Status_Performative\"\n]\n_ACNMESSAGE_STATUSBODY_STATUSCODEENUM = _ACNMESSAGE_STATUSBODY.enum_types_by_name[\n    \"StatusCodeEnum\"\n]\nAcnMessage = _reflection.GeneratedProtocolMessageType(\n    \"AcnMessage\",\n    (_message.Message,),\n    {\n        \"AgentRecord\": _reflection.GeneratedProtocolMessageType(\n            \"AgentRecord\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _ACNMESSAGE_AGENTRECORD,\n                \"__module__\": \"acn_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.aea.acn.v1_0_0.AcnMessage.AgentRecord)\n            },\n        ),\n        \"StatusBody\": _reflection.GeneratedProtocolMessageType(\n            \"StatusBody\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _ACNMESSAGE_STATUSBODY,\n                \"__module__\": \"acn_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.aea.acn.v1_0_0.AcnMessage.StatusBody)\n            },\n        ),\n        \"Register_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Register_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _ACNMESSAGE_REGISTER_PERFORMATIVE,\n                \"__module__\": \"acn_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.aea.acn.v1_0_0.AcnMessage.Register_Performative)\n            },\n        ),\n        \"Lookup_Request_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Lookup_Request_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _ACNMESSAGE_LOOKUP_REQUEST_PERFORMATIVE,\n                \"__module__\": \"acn_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.aea.acn.v1_0_0.AcnMessage.Lookup_Request_Performative)\n            },\n        ),\n        \"Lookup_Response_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Lookup_Response_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _ACNMESSAGE_LOOKUP_RESPONSE_PERFORMATIVE,\n                \"__module__\": \"acn_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.aea.acn.v1_0_0.AcnMessage.Lookup_Response_Performative)\n            },\n        ),\n        \"Aea_Envelope_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Aea_Envelope_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _ACNMESSAGE_AEA_ENVELOPE_PERFORMATIVE,\n                \"__module__\": \"acn_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.aea.acn.v1_0_0.AcnMessage.Aea_Envelope_Performative)\n            },\n        ),\n        \"Status_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Status_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _ACNMESSAGE_STATUS_PERFORMATIVE,\n                \"__module__\": \"acn_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.aea.acn.v1_0_0.AcnMessage.Status_Performative)\n            },\n        ),\n        \"DESCRIPTOR\": _ACNMESSAGE,\n        \"__module__\": \"acn_pb2\"\n        # @@protoc_insertion_point(class_scope:aea.aea.acn.v1_0_0.AcnMessage)\n    },\n)\n_sym_db.RegisterMessage(AcnMessage)\n_sym_db.RegisterMessage(AcnMessage.AgentRecord)\n_sym_db.RegisterMessage(AcnMessage.StatusBody)\n_sym_db.RegisterMessage(AcnMessage.Register_Performative)\n_sym_db.RegisterMessage(AcnMessage.Lookup_Request_Performative)\n_sym_db.RegisterMessage(AcnMessage.Lookup_Response_Performative)\n_sym_db.RegisterMessage(AcnMessage.Aea_Envelope_Performative)\n_sym_db.RegisterMessage(AcnMessage.Status_Performative)\n\nif _descriptor._USE_C_DESCRIPTORS == False:\n\n    DESCRIPTOR._options = None\n    _ACNMESSAGE._serialized_start = 34\n    _ACNMESSAGE._serialized_end = 1460\n    _ACNMESSAGE_AGENTRECORD._serialized_start = 449\n    _ACNMESSAGE_AGENTRECORD._serialized_end = 621\n    _ACNMESSAGE_STATUSBODY._serialized_start = 624\n    _ACNMESSAGE_STATUSBODY._serialized_end = 1026\n    _ACNMESSAGE_STATUSBODY_STATUSCODEENUM._serialized_start = 725\n    _ACNMESSAGE_STATUSBODY_STATUSCODEENUM._serialized_end = 1026\n    _ACNMESSAGE_REGISTER_PERFORMATIVE._serialized_start = 1028\n    _ACNMESSAGE_REGISTER_PERFORMATIVE._serialized_end = 1111\n    _ACNMESSAGE_LOOKUP_REQUEST_PERFORMATIVE._serialized_start = 1113\n    _ACNMESSAGE_LOOKUP_REQUEST_PERFORMATIVE._serialized_end = 1165\n    _ACNMESSAGE_LOOKUP_RESPONSE_PERFORMATIVE._serialized_start = 1167\n    _ACNMESSAGE_LOOKUP_RESPONSE_PERFORMATIVE._serialized_end = 1257\n    _ACNMESSAGE_AEA_ENVELOPE_PERFORMATIVE._serialized_start = 1259\n    _ACNMESSAGE_AEA_ENVELOPE_PERFORMATIVE._serialized_end = 1364\n    _ACNMESSAGE_STATUS_PERFORMATIVE._serialized_start = 1366\n    _ACNMESSAGE_STATUS_PERFORMATIVE._serialized_end = 1444\n# @@protoc_insertion_point(module_scope)\n"
  },
  {
    "path": "packages/fetchai/protocols/acn/custom_types.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains class representations corresponding to every custom type in the protocol specification.\"\"\"\n\nfrom enum import Enum\nfrom typing import Any, List\n\nfrom aea.helpers.base import SimpleId, SimpleIdOrStr\n\n\nclass AgentRecord:\n    \"\"\"\n    This class represents an instance of AgentRecord.\n\n    Eventually needs to be unified with `aea.helpers.acn.agent_record`.\n    \"\"\"\n\n    __slots__ = (\n        \"_address\",\n        \"_public_key\",\n        \"_peer_public_key\",\n        \"_signature\",\n        \"_service_id\",\n        \"_ledger_id\",\n        \"_message_format\",\n        \"_message\",\n    )\n\n    def __init__(\n        self,\n        address: str,\n        public_key: str,\n        peer_public_key: str,\n        signature: str,\n        service_id: SimpleIdOrStr,\n        ledger_id: SimpleIdOrStr,\n    ) -> None:\n        \"\"\"Initialise an instance of AgentRecord.\"\"\"\n        self._address = address\n        self._public_key = public_key\n        self._peer_public_key = peer_public_key\n        self._signature = signature\n        self._service_id = str(SimpleId(service_id))\n        self._ledger_id = str(SimpleId(ledger_id))\n\n    @property\n    def address(self) -> str:\n        \"\"\"Get agent address\"\"\"\n        return self._address\n\n    @property\n    def public_key(self) -> str:\n        \"\"\"Get agent public key\"\"\"\n        return self._public_key\n\n    @property\n    def peer_public_key(self) -> str:\n        \"\"\"Get agent representative's public key\"\"\"\n        return self._peer_public_key\n\n    @property\n    def signature(self) -> str:\n        \"\"\"Get record signature\"\"\"\n        return self._signature\n\n    @property\n    def service_id(self) -> SimpleIdOrStr:\n        \"\"\"Get the identifier.\"\"\"\n        return self._service_id\n\n    @property\n    def ledger_id(self) -> SimpleIdOrStr:\n        \"\"\"Get ledger id.\"\"\"\n        return self._ledger_id\n\n    @staticmethod\n    def encode(\n        agent_record_protobuf_object: Any, agent_record_object: \"AgentRecord\"\n    ) -> None:\n        \"\"\"\n        Encode an instance of this class into the protocol buffer object.\n\n        The protocol buffer object in the agent_record_protobuf_object argument is matched with the instance of this class in the 'agent_record_object' argument.\n\n        :param agent_record_protobuf_object: the protocol buffer object whose type corresponds with this class.\n        :param agent_record_object: an instance of this class to be encoded in the protocol buffer object.\n        \"\"\"\n        agent_record_protobuf_object.address = agent_record_object.address\n        agent_record_protobuf_object.public_key = agent_record_object.public_key\n        agent_record_protobuf_object.peer_public_key = (\n            agent_record_object.peer_public_key\n        )\n        agent_record_protobuf_object.signature = agent_record_object.signature\n        agent_record_protobuf_object.service_id = agent_record_object.service_id\n        agent_record_protobuf_object.ledger_id = agent_record_object.ledger_id\n\n    @classmethod\n    def decode(cls, agent_record_protobuf_object: Any) -> \"AgentRecord\":\n        \"\"\"\n        Decode a protocol buffer object that corresponds with this class into an instance of this class.\n\n        A new instance of this class is created that matches the protocol buffer object in the 'agent_record_protobuf_object' argument.\n\n        :param agent_record_protobuf_object: the protocol buffer object whose type corresponds with this class.\n        :return: A new instance of this class that matches the protocol buffer object in the 'agent_record_protobuf_object' argument.\n        \"\"\"\n        record = cls(\n            address=agent_record_protobuf_object.address,\n            public_key=agent_record_protobuf_object.public_key,\n            peer_public_key=agent_record_protobuf_object.peer_public_key,\n            signature=agent_record_protobuf_object.signature,\n            service_id=agent_record_protobuf_object.service_id,\n            ledger_id=agent_record_protobuf_object.ledger_id,\n        )\n        return record\n\n    def __eq__(self, other: Any) -> bool:\n        \"\"\"Compare to objects of this class.\"\"\"\n        return (\n            isinstance(other, AgentRecord)\n            and self.address == other.address\n            and self.public_key == other.public_key\n        )\n\n\nclass StatusBody:\n    \"\"\"This class represents an instance of StatusBody.\"\"\"\n\n    __slots__ = (\n        \"_status_code\",\n        \"_msgs\",\n    )\n\n    class StatusCode(Enum):\n        \"\"\"Status code enum.\"\"\"\n\n        SUCCESS = 0\n        ERROR_UNSUPPORTED_VERSION = 1\n        ERROR_UNEXPECTED_PAYLOAD = 2\n        ERROR_GENERIC = 3\n        ERROR_DECODE = 4\n\n        ERROR_WRONG_AGENT_ADDRESS = 10\n        ERROR_WRONG_PUBLIC_KEY = 11\n        ERROR_INVALID_PROOF = 12\n        ERROR_UNSUPPORTED_LEDGER = 13\n\n        ERROR_UNKNOWN_AGENT_ADDRESS = 20\n        ERROR_AGENT_NOT_READY = 21\n\n        def __int__(self) -> int:\n            \"\"\"Get string representation.\"\"\"\n            return self.value\n\n    def __init__(self, status_code: StatusCode, msgs: List[str]) -> None:\n        \"\"\"Initialise an instance of StatusBody.\"\"\"\n        self._status_code = status_code\n        self._msgs = msgs\n\n    @property\n    def status_code(self) -> \"StatusCode\":\n        \"\"\"Get the status code.\"\"\"\n        return self._status_code\n\n    @property\n    def msgs(self) -> List[str]:\n        \"\"\"Get the list of messages.\"\"\"\n        return self._msgs\n\n    @staticmethod\n    def encode(\n        status_body_protobuf_object: Any, status_body_object: \"StatusBody\"\n    ) -> None:\n        \"\"\"\n        Encode an instance of this class into the protocol buffer object.\n\n        The protocol buffer object in the status_body_protobuf_object argument is matched with the instance of this class in the 'status_body_object' argument.\n\n        :param status_body_protobuf_object: the protocol buffer object whose type corresponds with this class.\n        :param status_body_object: an instance of this class to be encoded in the protocol buffer object.\n        \"\"\"\n        status_body_protobuf_object.code = int(status_body_object.status_code)\n        status_body_protobuf_object.msgs.extend(status_body_object.msgs)\n\n    @classmethod\n    def decode(cls, status_body_protobuf_object: Any) -> \"StatusBody\":\n        \"\"\"\n        Decode a protocol buffer object that corresponds with this class into an instance of this class.\n\n        A new instance of this class is created that matches the protocol buffer object in the 'status_body_protobuf_object' argument.\n\n        :param status_body_protobuf_object: the protocol buffer object whose type corresponds with this class.\n        :return: A new instance of this class that matches the protocol buffer object in the 'status_body_protobuf_object' argument.\n        \"\"\"\n        status_body = cls(\n            status_code=cls.StatusCode(status_body_protobuf_object.code),\n            msgs=status_body_protobuf_object.msgs,\n        )\n        return status_body\n\n    def __eq__(self, other: Any) -> bool:\n        \"\"\"Compare to objects of this class.\"\"\"\n        return (\n            isinstance(other, StatusBody)\n            and self.status_code == other.status_code\n            and self.msgs == other.msgs\n        )\n"
  },
  {
    "path": "packages/fetchai/protocols/acn/dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nThis module contains the classes required for acn dialogue management.\n\n- AcnDialogue: The dialogue class maintains state of a dialogue and manages it.\n- AcnDialogues: The dialogues class keeps track of all dialogues.\n\"\"\"\n\nfrom abc import ABC\nfrom typing import Callable, Dict, FrozenSet, Type, cast\n\nfrom aea.common import Address\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue, DialogueLabel, Dialogues\n\nfrom packages.fetchai.protocols.acn.message import AcnMessage\n\n\nclass AcnDialogue(Dialogue):\n    \"\"\"The acn dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    INITIAL_PERFORMATIVES: FrozenSet[Message.Performative] = frozenset(\n        {\n            AcnMessage.Performative.REGISTER,\n            AcnMessage.Performative.LOOKUP_REQUEST,\n            AcnMessage.Performative.AEA_ENVELOPE,\n        }\n    )\n    TERMINAL_PERFORMATIVES: FrozenSet[Message.Performative] = frozenset(\n        {AcnMessage.Performative.STATUS, AcnMessage.Performative.LOOKUP_RESPONSE}\n    )\n    VALID_REPLIES: Dict[Message.Performative, FrozenSet[Message.Performative]] = {\n        AcnMessage.Performative.AEA_ENVELOPE: frozenset(\n            {AcnMessage.Performative.STATUS}\n        ),\n        AcnMessage.Performative.LOOKUP_REQUEST: frozenset(\n            {AcnMessage.Performative.LOOKUP_RESPONSE, AcnMessage.Performative.STATUS}\n        ),\n        AcnMessage.Performative.LOOKUP_RESPONSE: frozenset(),\n        AcnMessage.Performative.REGISTER: frozenset({AcnMessage.Performative.STATUS}),\n        AcnMessage.Performative.STATUS: frozenset(),\n    }\n\n    class Role(Dialogue.Role):\n        \"\"\"This class defines the agent's role in a acn dialogue.\"\"\"\n\n        NODE = \"node\"\n\n    class EndState(Dialogue.EndState):\n        \"\"\"This class defines the end states of a acn dialogue.\"\"\"\n\n        SUCCESSFUL = 0\n        FAILED = 1\n\n    def __init__(\n        self,\n        dialogue_label: DialogueLabel,\n        self_address: Address,\n        role: Dialogue.Role,\n        message_class: Type[AcnMessage] = AcnMessage,\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n        :param message_class: the message class used\n        \"\"\"\n        Dialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            message_class=message_class,\n            self_address=self_address,\n            role=role,\n        )\n\n\nclass AcnDialogues(Dialogues, ABC):\n    \"\"\"This class keeps track of all acn dialogues.\"\"\"\n\n    END_STATES = frozenset(\n        {AcnDialogue.EndState.SUCCESSFUL, AcnDialogue.EndState.FAILED}\n    )\n\n    _keep_terminal_state_dialogues = False\n\n    def __init__(\n        self,\n        self_address: Address,\n        role_from_first_message: Callable[[Message, Address], Dialogue.Role],\n        dialogue_class: Type[AcnDialogue] = AcnDialogue,\n    ) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param self_address: the address of the entity for whom dialogues are maintained\n        :param dialogue_class: the dialogue class used\n        :param role_from_first_message: the callable determining role from first message\n        \"\"\"\n        Dialogues.__init__(\n            self,\n            self_address=self_address,\n            end_states=cast(FrozenSet[Dialogue.EndState], self.END_STATES),\n            message_class=AcnMessage,\n            dialogue_class=dialogue_class,\n            role_from_first_message=role_from_first_message,\n        )\n"
  },
  {
    "path": "packages/fetchai/protocols/acn/message.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains acn's message definition.\"\"\"\n\n# pylint: disable=too-many-statements,too-many-locals,no-member,too-few-public-methods,too-many-branches,not-an-iterable,unidiomatic-typecheck,unsubscriptable-object\nimport logging\nfrom typing import Any, Set, Tuple, cast\n\nfrom aea.configurations.base import PublicId\nfrom aea.exceptions import AEAEnforceError, enforce\nfrom aea.protocols.base import Message\n\nfrom packages.fetchai.protocols.acn.custom_types import AgentRecord as CustomAgentRecord\nfrom packages.fetchai.protocols.acn.custom_types import StatusBody as CustomStatusBody\n\n\n_default_logger = logging.getLogger(\"aea.packages.fetchai.protocols.acn.message\")\n\nDEFAULT_BODY_SIZE = 4\n\n\nclass AcnMessage(Message):\n    \"\"\"The protocol used for envelope delivery on the ACN.\"\"\"\n\n    protocol_id = PublicId.from_str(\"fetchai/acn:1.1.7\")\n    protocol_specification_id = PublicId.from_str(\"aea/acn:1.0.0\")\n\n    AgentRecord = CustomAgentRecord\n\n    StatusBody = CustomStatusBody\n\n    class Performative(Message.Performative):\n        \"\"\"Performatives for the acn protocol.\"\"\"\n\n        AEA_ENVELOPE = \"aea_envelope\"\n        LOOKUP_REQUEST = \"lookup_request\"\n        LOOKUP_RESPONSE = \"lookup_response\"\n        REGISTER = \"register\"\n        STATUS = \"status\"\n\n        def __str__(self) -> str:\n            \"\"\"Get the string representation.\"\"\"\n            return str(self.value)\n\n    _performatives = {\n        \"aea_envelope\",\n        \"lookup_request\",\n        \"lookup_response\",\n        \"register\",\n        \"status\",\n    }\n    __slots__: Tuple[str, ...] = tuple()\n\n    class _SlotsCls:\n        __slots__ = (\n            \"agent_address\",\n            \"body\",\n            \"dialogue_reference\",\n            \"envelope\",\n            \"message_id\",\n            \"performative\",\n            \"record\",\n            \"target\",\n        )\n\n    def __init__(\n        self,\n        performative: Performative,\n        dialogue_reference: Tuple[str, str] = (\"\", \"\"),\n        message_id: int = 1,\n        target: int = 0,\n        **kwargs: Any,\n    ):\n        \"\"\"\n        Initialise an instance of AcnMessage.\n\n        :param message_id: the message id.\n        :param dialogue_reference: the dialogue reference.\n        :param target: the message target.\n        :param performative: the message performative.\n        :param **kwargs: extra options.\n        \"\"\"\n        super().__init__(\n            dialogue_reference=dialogue_reference,\n            message_id=message_id,\n            target=target,\n            performative=AcnMessage.Performative(performative),\n            **kwargs,\n        )\n\n    @property\n    def valid_performatives(self) -> Set[str]:\n        \"\"\"Get valid performatives.\"\"\"\n        return self._performatives\n\n    @property\n    def dialogue_reference(self) -> Tuple[str, str]:\n        \"\"\"Get the dialogue_reference of the message.\"\"\"\n        enforce(self.is_set(\"dialogue_reference\"), \"dialogue_reference is not set.\")\n        return cast(Tuple[str, str], self.get(\"dialogue_reference\"))\n\n    @property\n    def message_id(self) -> int:\n        \"\"\"Get the message_id of the message.\"\"\"\n        enforce(self.is_set(\"message_id\"), \"message_id is not set.\")\n        return cast(int, self.get(\"message_id\"))\n\n    @property\n    def performative(self) -> Performative:  # type: ignore # noqa: F821\n        \"\"\"Get the performative of the message.\"\"\"\n        enforce(self.is_set(\"performative\"), \"performative is not set.\")\n        return cast(AcnMessage.Performative, self.get(\"performative\"))\n\n    @property\n    def target(self) -> int:\n        \"\"\"Get the target of the message.\"\"\"\n        enforce(self.is_set(\"target\"), \"target is not set.\")\n        return cast(int, self.get(\"target\"))\n\n    @property\n    def agent_address(self) -> str:\n        \"\"\"Get the 'agent_address' content from the message.\"\"\"\n        enforce(self.is_set(\"agent_address\"), \"'agent_address' content is not set.\")\n        return cast(str, self.get(\"agent_address\"))\n\n    @property\n    def body(self) -> CustomStatusBody:\n        \"\"\"Get the 'body' content from the message.\"\"\"\n        enforce(self.is_set(\"body\"), \"'body' content is not set.\")\n        return cast(CustomStatusBody, self.get(\"body\"))\n\n    @property\n    def envelope(self) -> bytes:\n        \"\"\"Get the 'envelope' content from the message.\"\"\"\n        enforce(self.is_set(\"envelope\"), \"'envelope' content is not set.\")\n        return cast(bytes, self.get(\"envelope\"))\n\n    @property\n    def record(self) -> CustomAgentRecord:\n        \"\"\"Get the 'record' content from the message.\"\"\"\n        enforce(self.is_set(\"record\"), \"'record' content is not set.\")\n        return cast(CustomAgentRecord, self.get(\"record\"))\n\n    def _is_consistent(self) -> bool:\n        \"\"\"Check that the message follows the acn protocol.\"\"\"\n        try:\n            enforce(\n                isinstance(self.dialogue_reference, tuple),\n                \"Invalid type for 'dialogue_reference'. Expected 'tuple'. Found '{}'.\".format(\n                    type(self.dialogue_reference)\n                ),\n            )\n            enforce(\n                isinstance(self.dialogue_reference[0], str),\n                \"Invalid type for 'dialogue_reference[0]'. Expected 'str'. Found '{}'.\".format(\n                    type(self.dialogue_reference[0])\n                ),\n            )\n            enforce(\n                isinstance(self.dialogue_reference[1], str),\n                \"Invalid type for 'dialogue_reference[1]'. Expected 'str'. Found '{}'.\".format(\n                    type(self.dialogue_reference[1])\n                ),\n            )\n            enforce(\n                type(self.message_id) is int,\n                \"Invalid type for 'message_id'. Expected 'int'. Found '{}'.\".format(\n                    type(self.message_id)\n                ),\n            )\n            enforce(\n                type(self.target) is int,\n                \"Invalid type for 'target'. Expected 'int'. Found '{}'.\".format(\n                    type(self.target)\n                ),\n            )\n\n            # Light Protocol Rule 2\n            # Check correct performative\n            enforce(\n                isinstance(self.performative, AcnMessage.Performative),\n                \"Invalid 'performative'. Expected either of '{}'. Found '{}'.\".format(\n                    self.valid_performatives, self.performative\n                ),\n            )\n\n            # Check correct contents\n            actual_nb_of_contents = len(self._body) - DEFAULT_BODY_SIZE\n            expected_nb_of_contents = 0\n            if self.performative == AcnMessage.Performative.REGISTER:\n                expected_nb_of_contents = 1\n                enforce(\n                    isinstance(self.record, CustomAgentRecord),\n                    \"Invalid type for content 'record'. Expected 'AgentRecord'. Found '{}'.\".format(\n                        type(self.record)\n                    ),\n                )\n            elif self.performative == AcnMessage.Performative.LOOKUP_REQUEST:\n                expected_nb_of_contents = 1\n                enforce(\n                    isinstance(self.agent_address, str),\n                    \"Invalid type for content 'agent_address'. Expected 'str'. Found '{}'.\".format(\n                        type(self.agent_address)\n                    ),\n                )\n            elif self.performative == AcnMessage.Performative.LOOKUP_RESPONSE:\n                expected_nb_of_contents = 1\n                enforce(\n                    isinstance(self.record, CustomAgentRecord),\n                    \"Invalid type for content 'record'. Expected 'AgentRecord'. Found '{}'.\".format(\n                        type(self.record)\n                    ),\n                )\n            elif self.performative == AcnMessage.Performative.AEA_ENVELOPE:\n                expected_nb_of_contents = 2\n                enforce(\n                    isinstance(self.envelope, bytes),\n                    \"Invalid type for content 'envelope'. Expected 'bytes'. Found '{}'.\".format(\n                        type(self.envelope)\n                    ),\n                )\n                enforce(\n                    isinstance(self.record, CustomAgentRecord),\n                    \"Invalid type for content 'record'. Expected 'AgentRecord'. Found '{}'.\".format(\n                        type(self.record)\n                    ),\n                )\n            elif self.performative == AcnMessage.Performative.STATUS:\n                expected_nb_of_contents = 1\n                enforce(\n                    isinstance(self.body, CustomStatusBody),\n                    \"Invalid type for content 'body'. Expected 'StatusBody'. Found '{}'.\".format(\n                        type(self.body)\n                    ),\n                )\n\n            # Check correct content count\n            enforce(\n                expected_nb_of_contents == actual_nb_of_contents,\n                \"Incorrect number of contents. Expected {}. Found {}\".format(\n                    expected_nb_of_contents, actual_nb_of_contents\n                ),\n            )\n\n            # Light Protocol Rule 3\n            if self.message_id == 1:\n                enforce(\n                    self.target == 0,\n                    \"Invalid 'target'. Expected 0 (because 'message_id' is 1). Found {}.\".format(\n                        self.target\n                    ),\n                )\n        except (AEAEnforceError, ValueError, KeyError) as e:\n            _default_logger.error(str(e))\n            return False\n\n        return True\n"
  },
  {
    "path": "packages/fetchai/protocols/acn/protocol.yaml",
    "content": "name: acn\nauthor: fetchai\nversion: 1.1.7\nprotocol_specification_id: aea/acn:1.0.0\ntype: protocol\ndescription: The protocol used for envelope delivery on the ACN.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: QmfMfnMxXNv96uBwMk9EcFE9vKTLwNn7afLTdMNKUBLgX7\n  __init__.py: QmXYL7CpbddU18HUG1Jf334np9yiWjYDsQYg7qBQjBrL9o\n  acn.proto: QmVWvXETUNe7QZTvBgzwpofNP3suFthwyxbTVUqSx8mdnE\n  acn_pb2.py: Qmf3HYmJtGwugpCuWSmJEDVHwZcnCF6BWmeEouUSpBRs45\n  custom_types.py: QmQNMAGx2JGSM3CKXCos2oWpzSoCa7vsrmQc57j5QY8NFz\n  dialogues.py: QmUbvA3jgzdGMseRtPyDoMApVrVZ5h4pspt5UY77EM9kR9\n  message.py: QmdrjeM3ShmDKLsB46TbDzigsW7bPZCdLKEdtxUiZenkn9\n  serialization.py: QmQ8QfHCvKNg2D3Fcb7u4tJmRw4gce16YUsbwvGfBMEk38\nfingerprint_ignore_patterns: []\ndependencies:\n  protobuf: {}\n"
  },
  {
    "path": "packages/fetchai/protocols/acn/serialization.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Serialization module for acn protocol.\"\"\"\n\n# pylint: disable=too-many-statements,too-many-locals,no-member,too-few-public-methods,redefined-builtin\nfrom typing import Any, Dict, cast\n\nfrom aea.mail.base_pb2 import DialogueMessage\nfrom aea.mail.base_pb2 import Message as ProtobufMessage\nfrom aea.protocols.base import Message, Serializer\n\nfrom packages.fetchai.protocols.acn import acn_pb2\nfrom packages.fetchai.protocols.acn.custom_types import AgentRecord, StatusBody\nfrom packages.fetchai.protocols.acn.message import AcnMessage\n\n\nclass AcnSerializer(Serializer):\n    \"\"\"Serialization for the 'acn' protocol.\"\"\"\n\n    @staticmethod\n    def encode(msg: Message) -> bytes:\n        \"\"\"\n        Encode a 'Acn' message into bytes.\n\n        :param msg: the message object.\n        :return: the bytes.\n        \"\"\"\n        msg = cast(AcnMessage, msg)\n        message_pb = ProtobufMessage()\n        dialogue_message_pb = DialogueMessage()\n        acn_msg = acn_pb2.AcnMessage()\n\n        dialogue_message_pb.message_id = msg.message_id\n        dialogue_reference = msg.dialogue_reference\n        dialogue_message_pb.dialogue_starter_reference = dialogue_reference[0]\n        dialogue_message_pb.dialogue_responder_reference = dialogue_reference[1]\n        dialogue_message_pb.target = msg.target\n\n        performative_id = msg.performative\n        if performative_id == AcnMessage.Performative.REGISTER:\n            performative = acn_pb2.AcnMessage.Register_Performative()  # type: ignore\n            record = msg.record\n            AgentRecord.encode(performative.record, record)\n            acn_msg.register.CopyFrom(performative)\n        elif performative_id == AcnMessage.Performative.LOOKUP_REQUEST:\n            performative = acn_pb2.AcnMessage.Lookup_Request_Performative()  # type: ignore\n            agent_address = msg.agent_address\n            performative.agent_address = agent_address\n            acn_msg.lookup_request.CopyFrom(performative)\n        elif performative_id == AcnMessage.Performative.LOOKUP_RESPONSE:\n            performative = acn_pb2.AcnMessage.Lookup_Response_Performative()  # type: ignore\n            record = msg.record\n            AgentRecord.encode(performative.record, record)\n            acn_msg.lookup_response.CopyFrom(performative)\n        elif performative_id == AcnMessage.Performative.AEA_ENVELOPE:\n            performative = acn_pb2.AcnMessage.Aea_Envelope_Performative()  # type: ignore\n            envelope = msg.envelope\n            performative.envelope = envelope\n            record = msg.record\n            AgentRecord.encode(performative.record, record)\n            acn_msg.aea_envelope.CopyFrom(performative)\n        elif performative_id == AcnMessage.Performative.STATUS:\n            performative = acn_pb2.AcnMessage.Status_Performative()  # type: ignore\n            body = msg.body\n            StatusBody.encode(performative.body, body)\n            acn_msg.status.CopyFrom(performative)\n        else:\n            raise ValueError(\"Performative not valid: {}\".format(performative_id))\n\n        dialogue_message_pb.content = acn_msg.SerializeToString()\n\n        message_pb.dialogue_message.CopyFrom(dialogue_message_pb)\n        message_bytes = message_pb.SerializeToString()\n        return message_bytes\n\n    @staticmethod\n    def decode(obj: bytes) -> Message:\n        \"\"\"\n        Decode bytes into a 'Acn' message.\n\n        :param obj: the bytes object.\n        :return: the 'Acn' message.\n        \"\"\"\n        message_pb = ProtobufMessage()\n        acn_pb = acn_pb2.AcnMessage()\n        message_pb.ParseFromString(obj)\n        message_id = message_pb.dialogue_message.message_id\n        dialogue_reference = (\n            message_pb.dialogue_message.dialogue_starter_reference,\n            message_pb.dialogue_message.dialogue_responder_reference,\n        )\n        target = message_pb.dialogue_message.target\n\n        acn_pb.ParseFromString(message_pb.dialogue_message.content)\n        performative = acn_pb.WhichOneof(\"performative\")\n        performative_id = AcnMessage.Performative(str(performative))\n        performative_content = {}  # type: Dict[str, Any]\n        if performative_id == AcnMessage.Performative.REGISTER:\n            pb2_record = acn_pb.register.record\n            record = AgentRecord.decode(pb2_record)\n            performative_content[\"record\"] = record\n        elif performative_id == AcnMessage.Performative.LOOKUP_REQUEST:\n            agent_address = acn_pb.lookup_request.agent_address\n            performative_content[\"agent_address\"] = agent_address\n        elif performative_id == AcnMessage.Performative.LOOKUP_RESPONSE:\n            pb2_record = acn_pb.lookup_response.record\n            record = AgentRecord.decode(pb2_record)\n            performative_content[\"record\"] = record\n        elif performative_id == AcnMessage.Performative.AEA_ENVELOPE:\n            envelope = acn_pb.aea_envelope.envelope\n            performative_content[\"envelope\"] = envelope\n            pb2_record = acn_pb.aea_envelope.record\n            record = AgentRecord.decode(pb2_record)\n            performative_content[\"record\"] = record\n        elif performative_id == AcnMessage.Performative.STATUS:\n            pb2_body = acn_pb.status.body\n            body = StatusBody.decode(pb2_body)\n            performative_content[\"body\"] = body\n        else:\n            raise ValueError(\"Performative not valid: {}.\".format(performative_id))\n\n        return AcnMessage(\n            message_id=message_id,\n            dialogue_reference=dialogue_reference,\n            target=target,\n            performative=performative,\n            **performative_content\n        )\n"
  },
  {
    "path": "packages/fetchai/protocols/aggregation/README.md",
    "content": "# Aggregation Protocol\n\n## Description\n\nThis is an aggregation protocol for aggregating observations.\n\n## Specification\n\n```yaml\n---\nname: aggregation\nauthor: fetchai\nversion: 0.2.7\ndescription: A protocol for agents to aggregate individual observations\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nprotocol_specification_id: fetchai/aggregation:0.2.7\nspeech_acts:\n  observation:\n    value: pt:int\n    time: pt:str\n    source: pt:str\n    signature: pt:str\n  aggregation:\n    value: pt:int\n    time: pt:str\n    contributors: pt:list[pt:str]\n    signature: pt:str\n...\n---\ninitiation: [observation, aggregation]\nreply:\n  observation: []\n  aggregation: []\ntermination: [observation, aggregation]\nroles: {agent}\nend_states: [successful, failed]\nkeep_terminal_state_dialogues: false\n...\n```\n\n## Links\n"
  },
  {
    "path": "packages/fetchai/protocols/aggregation/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nThis module contains the support resources for the aggregation protocol.\n\nIt was created with protocol buffer compiler version `libprotoc 3.19.4` and aea version `1.2.5`.\n\"\"\"\n\nfrom packages.fetchai.protocols.aggregation.message import AggregationMessage\nfrom packages.fetchai.protocols.aggregation.serialization import AggregationSerializer\n\n\nAggregationMessage.serializer = AggregationSerializer\n"
  },
  {
    "path": "packages/fetchai/protocols/aggregation/aggregation.proto",
    "content": "syntax = \"proto3\";\n\npackage aea.fetchai.aggregation.v0_2_7;\n\nmessage AggregationMessage{\n\n  // Performatives and contents\n  message Observation_Performative{\n    int64 value = 1;\n    string time = 2;\n    string source = 3;\n    string signature = 4;\n  }\n\n  message Aggregation_Performative{\n    int64 value = 1;\n    string time = 2;\n    repeated string contributors = 3;\n    string signature = 4;\n  }\n\n\n  oneof performative{\n    Aggregation_Performative aggregation = 5;\n    Observation_Performative observation = 6;\n  }\n}\n"
  },
  {
    "path": "packages/fetchai/protocols/aggregation/aggregation_pb2.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by the protocol buffer compiler.  DO NOT EDIT!\n# source: aggregation.proto\n\"\"\"Generated protocol buffer code.\"\"\"\nfrom google.protobuf import descriptor as _descriptor\nfrom google.protobuf import descriptor_pool as _descriptor_pool\nfrom google.protobuf import message as _message\nfrom google.protobuf import reflection as _reflection\nfrom google.protobuf import symbol_database as _symbol_database\n\n# @@protoc_insertion_point(imports)\n\n_sym_db = _symbol_database.Default()\n\n\nDESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(\n    b'\\n\\x11\\x61ggregation.proto\\x12\\x1e\\x61\\x65\\x61.fetchai.aggregation.v0_2_7\"\\xaa\\x03\\n\\x12\\x41ggregationMessage\\x12\\x62\\n\\x0b\\x61ggregation\\x18\\x05 \\x01(\\x0b\\x32K.aea.fetchai.aggregation.v0_2_7.AggregationMessage.Aggregation_PerformativeH\\x00\\x12\\x62\\n\\x0bobservation\\x18\\x06 \\x01(\\x0b\\x32K.aea.fetchai.aggregation.v0_2_7.AggregationMessage.Observation_PerformativeH\\x00\\x1aZ\\n\\x18Observation_Performative\\x12\\r\\n\\x05value\\x18\\x01 \\x01(\\x03\\x12\\x0c\\n\\x04time\\x18\\x02 \\x01(\\t\\x12\\x0e\\n\\x06source\\x18\\x03 \\x01(\\t\\x12\\x11\\n\\tsignature\\x18\\x04 \\x01(\\t\\x1a`\\n\\x18\\x41ggregation_Performative\\x12\\r\\n\\x05value\\x18\\x01 \\x01(\\x03\\x12\\x0c\\n\\x04time\\x18\\x02 \\x01(\\t\\x12\\x14\\n\\x0c\\x63ontributors\\x18\\x03 \\x03(\\t\\x12\\x11\\n\\tsignature\\x18\\x04 \\x01(\\tB\\x0e\\n\\x0cperformativeb\\x06proto3'\n)\n\n\n_AGGREGATIONMESSAGE = DESCRIPTOR.message_types_by_name[\"AggregationMessage\"]\n_AGGREGATIONMESSAGE_OBSERVATION_PERFORMATIVE = _AGGREGATIONMESSAGE.nested_types_by_name[\n    \"Observation_Performative\"\n]\n_AGGREGATIONMESSAGE_AGGREGATION_PERFORMATIVE = _AGGREGATIONMESSAGE.nested_types_by_name[\n    \"Aggregation_Performative\"\n]\nAggregationMessage = _reflection.GeneratedProtocolMessageType(\n    \"AggregationMessage\",\n    (_message.Message,),\n    {\n        \"Observation_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Observation_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _AGGREGATIONMESSAGE_OBSERVATION_PERFORMATIVE,\n                \"__module__\": \"aggregation_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.aggregation.v0_2_7.AggregationMessage.Observation_Performative)\n            },\n        ),\n        \"Aggregation_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Aggregation_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _AGGREGATIONMESSAGE_AGGREGATION_PERFORMATIVE,\n                \"__module__\": \"aggregation_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.aggregation.v0_2_7.AggregationMessage.Aggregation_Performative)\n            },\n        ),\n        \"DESCRIPTOR\": _AGGREGATIONMESSAGE,\n        \"__module__\": \"aggregation_pb2\"\n        # @@protoc_insertion_point(class_scope:aea.fetchai.aggregation.v0_2_7.AggregationMessage)\n    },\n)\n_sym_db.RegisterMessage(AggregationMessage)\n_sym_db.RegisterMessage(AggregationMessage.Observation_Performative)\n_sym_db.RegisterMessage(AggregationMessage.Aggregation_Performative)\n\nif _descriptor._USE_C_DESCRIPTORS == False:\n\n    DESCRIPTOR._options = None\n    _AGGREGATIONMESSAGE._serialized_start = 54\n    _AGGREGATIONMESSAGE._serialized_end = 480\n    _AGGREGATIONMESSAGE_OBSERVATION_PERFORMATIVE._serialized_start = 276\n    _AGGREGATIONMESSAGE_OBSERVATION_PERFORMATIVE._serialized_end = 366\n    _AGGREGATIONMESSAGE_AGGREGATION_PERFORMATIVE._serialized_start = 368\n    _AGGREGATIONMESSAGE_AGGREGATION_PERFORMATIVE._serialized_end = 464\n# @@protoc_insertion_point(module_scope)\n"
  },
  {
    "path": "packages/fetchai/protocols/aggregation/dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nThis module contains the classes required for aggregation dialogue management.\n\n- AggregationDialogue: The dialogue class maintains state of a dialogue and manages it.\n- AggregationDialogues: The dialogues class keeps track of all dialogues.\n\"\"\"\n\nfrom abc import ABC\nfrom typing import Callable, Dict, FrozenSet, Type, cast\n\nfrom aea.common import Address\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue, DialogueLabel, Dialogues\n\nfrom packages.fetchai.protocols.aggregation.message import AggregationMessage\n\n\nclass AggregationDialogue(Dialogue):\n    \"\"\"The aggregation dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    INITIAL_PERFORMATIVES: FrozenSet[Message.Performative] = frozenset(\n        {\n            AggregationMessage.Performative.OBSERVATION,\n            AggregationMessage.Performative.AGGREGATION,\n        }\n    )\n    TERMINAL_PERFORMATIVES: FrozenSet[Message.Performative] = frozenset(\n        {\n            AggregationMessage.Performative.OBSERVATION,\n            AggregationMessage.Performative.AGGREGATION,\n        }\n    )\n    VALID_REPLIES: Dict[Message.Performative, FrozenSet[Message.Performative]] = {\n        AggregationMessage.Performative.AGGREGATION: frozenset(),\n        AggregationMessage.Performative.OBSERVATION: frozenset(),\n    }\n\n    class Role(Dialogue.Role):\n        \"\"\"This class defines the agent's role in a aggregation dialogue.\"\"\"\n\n        AGENT = \"agent\"\n\n    class EndState(Dialogue.EndState):\n        \"\"\"This class defines the end states of a aggregation dialogue.\"\"\"\n\n        SUCCESSFUL = 0\n        FAILED = 1\n\n    def __init__(\n        self,\n        dialogue_label: DialogueLabel,\n        self_address: Address,\n        role: Dialogue.Role,\n        message_class: Type[AggregationMessage] = AggregationMessage,\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n        :param message_class: the message class used\n        \"\"\"\n        Dialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            message_class=message_class,\n            self_address=self_address,\n            role=role,\n        )\n\n\nclass AggregationDialogues(Dialogues, ABC):\n    \"\"\"This class keeps track of all aggregation dialogues.\"\"\"\n\n    END_STATES = frozenset(\n        {AggregationDialogue.EndState.SUCCESSFUL, AggregationDialogue.EndState.FAILED}\n    )\n\n    _keep_terminal_state_dialogues = False\n\n    def __init__(\n        self,\n        self_address: Address,\n        role_from_first_message: Callable[[Message, Address], Dialogue.Role],\n        dialogue_class: Type[AggregationDialogue] = AggregationDialogue,\n    ) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param self_address: the address of the entity for whom dialogues are maintained\n        :param dialogue_class: the dialogue class used\n        :param role_from_first_message: the callable determining role from first message\n        \"\"\"\n        Dialogues.__init__(\n            self,\n            self_address=self_address,\n            end_states=cast(FrozenSet[Dialogue.EndState], self.END_STATES),\n            message_class=AggregationMessage,\n            dialogue_class=dialogue_class,\n            role_from_first_message=role_from_first_message,\n        )\n"
  },
  {
    "path": "packages/fetchai/protocols/aggregation/message.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains aggregation's message definition.\"\"\"\n\n# pylint: disable=too-many-statements,too-many-locals,no-member,too-few-public-methods,too-many-branches,not-an-iterable,unidiomatic-typecheck,unsubscriptable-object\nimport logging\nfrom typing import Any, Set, Tuple, cast\n\nfrom aea.configurations.base import PublicId\nfrom aea.exceptions import AEAEnforceError, enforce\nfrom aea.protocols.base import Message\n\n\n_default_logger = logging.getLogger(\n    \"aea.packages.fetchai.protocols.aggregation.message\"\n)\n\nDEFAULT_BODY_SIZE = 4\n\n\nclass AggregationMessage(Message):\n    \"\"\"A protocol for agents to aggregate individual observations\"\"\"\n\n    protocol_id = PublicId.from_str(\"fetchai/aggregation:0.2.7\")\n    protocol_specification_id = PublicId.from_str(\"fetchai/aggregation:0.2.7\")\n\n    class Performative(Message.Performative):\n        \"\"\"Performatives for the aggregation protocol.\"\"\"\n\n        AGGREGATION = \"aggregation\"\n        OBSERVATION = \"observation\"\n\n        def __str__(self) -> str:\n            \"\"\"Get the string representation.\"\"\"\n            return str(self.value)\n\n    _performatives = {\"aggregation\", \"observation\"}\n    __slots__: Tuple[str, ...] = tuple()\n\n    class _SlotsCls:\n        __slots__ = (\n            \"contributors\",\n            \"dialogue_reference\",\n            \"message_id\",\n            \"performative\",\n            \"signature\",\n            \"source\",\n            \"target\",\n            \"time\",\n            \"value\",\n        )\n\n    def __init__(\n        self,\n        performative: Performative,\n        dialogue_reference: Tuple[str, str] = (\"\", \"\"),\n        message_id: int = 1,\n        target: int = 0,\n        **kwargs: Any,\n    ):\n        \"\"\"\n        Initialise an instance of AggregationMessage.\n\n        :param message_id: the message id.\n        :param dialogue_reference: the dialogue reference.\n        :param target: the message target.\n        :param performative: the message performative.\n        :param **kwargs: extra options.\n        \"\"\"\n        super().__init__(\n            dialogue_reference=dialogue_reference,\n            message_id=message_id,\n            target=target,\n            performative=AggregationMessage.Performative(performative),\n            **kwargs,\n        )\n\n    @property\n    def valid_performatives(self) -> Set[str]:\n        \"\"\"Get valid performatives.\"\"\"\n        return self._performatives\n\n    @property\n    def dialogue_reference(self) -> Tuple[str, str]:\n        \"\"\"Get the dialogue_reference of the message.\"\"\"\n        enforce(self.is_set(\"dialogue_reference\"), \"dialogue_reference is not set.\")\n        return cast(Tuple[str, str], self.get(\"dialogue_reference\"))\n\n    @property\n    def message_id(self) -> int:\n        \"\"\"Get the message_id of the message.\"\"\"\n        enforce(self.is_set(\"message_id\"), \"message_id is not set.\")\n        return cast(int, self.get(\"message_id\"))\n\n    @property\n    def performative(self) -> Performative:  # type: ignore # noqa: F821\n        \"\"\"Get the performative of the message.\"\"\"\n        enforce(self.is_set(\"performative\"), \"performative is not set.\")\n        return cast(AggregationMessage.Performative, self.get(\"performative\"))\n\n    @property\n    def target(self) -> int:\n        \"\"\"Get the target of the message.\"\"\"\n        enforce(self.is_set(\"target\"), \"target is not set.\")\n        return cast(int, self.get(\"target\"))\n\n    @property\n    def contributors(self) -> Tuple[str, ...]:\n        \"\"\"Get the 'contributors' content from the message.\"\"\"\n        enforce(self.is_set(\"contributors\"), \"'contributors' content is not set.\")\n        return cast(Tuple[str, ...], self.get(\"contributors\"))\n\n    @property\n    def signature(self) -> str:\n        \"\"\"Get the 'signature' content from the message.\"\"\"\n        enforce(self.is_set(\"signature\"), \"'signature' content is not set.\")\n        return cast(str, self.get(\"signature\"))\n\n    @property\n    def source(self) -> str:\n        \"\"\"Get the 'source' content from the message.\"\"\"\n        enforce(self.is_set(\"source\"), \"'source' content is not set.\")\n        return cast(str, self.get(\"source\"))\n\n    @property\n    def time(self) -> str:\n        \"\"\"Get the 'time' content from the message.\"\"\"\n        enforce(self.is_set(\"time\"), \"'time' content is not set.\")\n        return cast(str, self.get(\"time\"))\n\n    @property\n    def value(self) -> int:\n        \"\"\"Get the 'value' content from the message.\"\"\"\n        enforce(self.is_set(\"value\"), \"'value' content is not set.\")\n        return cast(int, self.get(\"value\"))\n\n    def _is_consistent(self) -> bool:\n        \"\"\"Check that the message follows the aggregation protocol.\"\"\"\n        try:\n            enforce(\n                isinstance(self.dialogue_reference, tuple),\n                \"Invalid type for 'dialogue_reference'. Expected 'tuple'. Found '{}'.\".format(\n                    type(self.dialogue_reference)\n                ),\n            )\n            enforce(\n                isinstance(self.dialogue_reference[0], str),\n                \"Invalid type for 'dialogue_reference[0]'. Expected 'str'. Found '{}'.\".format(\n                    type(self.dialogue_reference[0])\n                ),\n            )\n            enforce(\n                isinstance(self.dialogue_reference[1], str),\n                \"Invalid type for 'dialogue_reference[1]'. Expected 'str'. Found '{}'.\".format(\n                    type(self.dialogue_reference[1])\n                ),\n            )\n            enforce(\n                type(self.message_id) is int,\n                \"Invalid type for 'message_id'. Expected 'int'. Found '{}'.\".format(\n                    type(self.message_id)\n                ),\n            )\n            enforce(\n                type(self.target) is int,\n                \"Invalid type for 'target'. Expected 'int'. Found '{}'.\".format(\n                    type(self.target)\n                ),\n            )\n\n            # Light Protocol Rule 2\n            # Check correct performative\n            enforce(\n                isinstance(self.performative, AggregationMessage.Performative),\n                \"Invalid 'performative'. Expected either of '{}'. Found '{}'.\".format(\n                    self.valid_performatives, self.performative\n                ),\n            )\n\n            # Check correct contents\n            actual_nb_of_contents = len(self._body) - DEFAULT_BODY_SIZE\n            expected_nb_of_contents = 0\n            if self.performative == AggregationMessage.Performative.OBSERVATION:\n                expected_nb_of_contents = 4\n                enforce(\n                    type(self.value) is int,\n                    \"Invalid type for content 'value'. Expected 'int'. Found '{}'.\".format(\n                        type(self.value)\n                    ),\n                )\n                enforce(\n                    isinstance(self.time, str),\n                    \"Invalid type for content 'time'. Expected 'str'. Found '{}'.\".format(\n                        type(self.time)\n                    ),\n                )\n                enforce(\n                    isinstance(self.source, str),\n                    \"Invalid type for content 'source'. Expected 'str'. Found '{}'.\".format(\n                        type(self.source)\n                    ),\n                )\n                enforce(\n                    isinstance(self.signature, str),\n                    \"Invalid type for content 'signature'. Expected 'str'. Found '{}'.\".format(\n                        type(self.signature)\n                    ),\n                )\n            elif self.performative == AggregationMessage.Performative.AGGREGATION:\n                expected_nb_of_contents = 4\n                enforce(\n                    type(self.value) is int,\n                    \"Invalid type for content 'value'. Expected 'int'. Found '{}'.\".format(\n                        type(self.value)\n                    ),\n                )\n                enforce(\n                    isinstance(self.time, str),\n                    \"Invalid type for content 'time'. Expected 'str'. Found '{}'.\".format(\n                        type(self.time)\n                    ),\n                )\n                enforce(\n                    isinstance(self.contributors, tuple),\n                    \"Invalid type for content 'contributors'. Expected 'tuple'. Found '{}'.\".format(\n                        type(self.contributors)\n                    ),\n                )\n                enforce(\n                    all(isinstance(element, str) for element in self.contributors),\n                    \"Invalid type for tuple elements in content 'contributors'. Expected 'str'.\",\n                )\n                enforce(\n                    isinstance(self.signature, str),\n                    \"Invalid type for content 'signature'. Expected 'str'. Found '{}'.\".format(\n                        type(self.signature)\n                    ),\n                )\n\n            # Check correct content count\n            enforce(\n                expected_nb_of_contents == actual_nb_of_contents,\n                \"Incorrect number of contents. Expected {}. Found {}\".format(\n                    expected_nb_of_contents, actual_nb_of_contents\n                ),\n            )\n\n            # Light Protocol Rule 3\n            if self.message_id == 1:\n                enforce(\n                    self.target == 0,\n                    \"Invalid 'target'. Expected 0 (because 'message_id' is 1). Found {}.\".format(\n                        self.target\n                    ),\n                )\n        except (AEAEnforceError, ValueError, KeyError) as e:\n            _default_logger.error(str(e))\n            return False\n\n        return True\n"
  },
  {
    "path": "packages/fetchai/protocols/aggregation/protocol.yaml",
    "content": "name: aggregation\nauthor: fetchai\nversion: 0.2.7\nprotocol_specification_id: fetchai/aggregation:0.2.7\ntype: protocol\ndescription: A protocol for agents to aggregate individual observations\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: Qmbab8fKDdNxLUP1i4Mszem1Z5sTknSkgEmMqMftGySPw2\n  __init__.py: QmPLeQvFJqhZ39qb2TchPVMUNqh7Y8qb11MRdJXVr34Bqw\n  aggregation.proto: QmNpnRdmU4sMxxCkuJj1fz3QkEkwAmoP4vHk5ZdeTffDup\n  aggregation_pb2.py: QmVyjn8ySVvya7oacMCB9ibhhHESud414YSbEag7Fat6Hw\n  dialogues.py: QmbvTvfkrmWn7WoNg5AHjSQfC2ofv1Z7MJPXjk67YRq9A5\n  message.py: QmZXRaozSHTD1ABstrjA2xxb46u6iEzRHiB56X4DpF61j6\n  serialization.py: QmbHocoXnB9h6HPwBoYZ1N2ULF4FAuuZKs6uHF7jHw85eM\nfingerprint_ignore_patterns: []\ndependencies:\n  protobuf: {}\n"
  },
  {
    "path": "packages/fetchai/protocols/aggregation/serialization.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Serialization module for aggregation protocol.\"\"\"\n\n# pylint: disable=too-many-statements,too-many-locals,no-member,too-few-public-methods,redefined-builtin\nfrom typing import Any, Dict, cast\n\nfrom aea.mail.base_pb2 import DialogueMessage\nfrom aea.mail.base_pb2 import Message as ProtobufMessage\nfrom aea.protocols.base import Message, Serializer\n\nfrom packages.fetchai.protocols.aggregation import aggregation_pb2\nfrom packages.fetchai.protocols.aggregation.message import AggregationMessage\n\n\nclass AggregationSerializer(Serializer):\n    \"\"\"Serialization for the 'aggregation' protocol.\"\"\"\n\n    @staticmethod\n    def encode(msg: Message) -> bytes:\n        \"\"\"\n        Encode a 'Aggregation' message into bytes.\n\n        :param msg: the message object.\n        :return: the bytes.\n        \"\"\"\n        msg = cast(AggregationMessage, msg)\n        message_pb = ProtobufMessage()\n        dialogue_message_pb = DialogueMessage()\n        aggregation_msg = aggregation_pb2.AggregationMessage()\n\n        dialogue_message_pb.message_id = msg.message_id\n        dialogue_reference = msg.dialogue_reference\n        dialogue_message_pb.dialogue_starter_reference = dialogue_reference[0]\n        dialogue_message_pb.dialogue_responder_reference = dialogue_reference[1]\n        dialogue_message_pb.target = msg.target\n\n        performative_id = msg.performative\n        if performative_id == AggregationMessage.Performative.OBSERVATION:\n            performative = aggregation_pb2.AggregationMessage.Observation_Performative()  # type: ignore\n            value = msg.value\n            performative.value = value\n            time = msg.time\n            performative.time = time\n            source = msg.source\n            performative.source = source\n            signature = msg.signature\n            performative.signature = signature\n            aggregation_msg.observation.CopyFrom(performative)\n        elif performative_id == AggregationMessage.Performative.AGGREGATION:\n            performative = aggregation_pb2.AggregationMessage.Aggregation_Performative()  # type: ignore\n            value = msg.value\n            performative.value = value\n            time = msg.time\n            performative.time = time\n            contributors = msg.contributors\n            performative.contributors.extend(contributors)\n            signature = msg.signature\n            performative.signature = signature\n            aggregation_msg.aggregation.CopyFrom(performative)\n        else:\n            raise ValueError(\"Performative not valid: {}\".format(performative_id))\n\n        dialogue_message_pb.content = aggregation_msg.SerializeToString()\n\n        message_pb.dialogue_message.CopyFrom(dialogue_message_pb)\n        message_bytes = message_pb.SerializeToString()\n        return message_bytes\n\n    @staticmethod\n    def decode(obj: bytes) -> Message:\n        \"\"\"\n        Decode bytes into a 'Aggregation' message.\n\n        :param obj: the bytes object.\n        :return: the 'Aggregation' message.\n        \"\"\"\n        message_pb = ProtobufMessage()\n        aggregation_pb = aggregation_pb2.AggregationMessage()\n        message_pb.ParseFromString(obj)\n        message_id = message_pb.dialogue_message.message_id\n        dialogue_reference = (\n            message_pb.dialogue_message.dialogue_starter_reference,\n            message_pb.dialogue_message.dialogue_responder_reference,\n        )\n        target = message_pb.dialogue_message.target\n\n        aggregation_pb.ParseFromString(message_pb.dialogue_message.content)\n        performative = aggregation_pb.WhichOneof(\"performative\")\n        performative_id = AggregationMessage.Performative(str(performative))\n        performative_content = {}  # type: Dict[str, Any]\n        if performative_id == AggregationMessage.Performative.OBSERVATION:\n            value = aggregation_pb.observation.value\n            performative_content[\"value\"] = value\n            time = aggregation_pb.observation.time\n            performative_content[\"time\"] = time\n            source = aggregation_pb.observation.source\n            performative_content[\"source\"] = source\n            signature = aggregation_pb.observation.signature\n            performative_content[\"signature\"] = signature\n        elif performative_id == AggregationMessage.Performative.AGGREGATION:\n            value = aggregation_pb.aggregation.value\n            performative_content[\"value\"] = value\n            time = aggregation_pb.aggregation.time\n            performative_content[\"time\"] = time\n            contributors = aggregation_pb.aggregation.contributors\n            contributors_tuple = tuple(contributors)\n            performative_content[\"contributors\"] = contributors_tuple\n            signature = aggregation_pb.aggregation.signature\n            performative_content[\"signature\"] = signature\n        else:\n            raise ValueError(\"Performative not valid: {}.\".format(performative_id))\n\n        return AggregationMessage(\n            message_id=message_id,\n            dialogue_reference=dialogue_reference,\n            target=target,\n            performative=performative,\n            **performative_content\n        )\n"
  },
  {
    "path": "packages/fetchai/protocols/contract_api/README.md",
    "content": "# Contract API Protocol\n\n## Description\n\nThis is a protocol for contract APIs' requests and responses.\n\n## Specification\n\n```yaml\n---\nname: contract_api\nauthor: fetchai\nversion: 1.1.7\ndescription: A protocol for contract APIs requests and responses.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nprotocol_specification_id: fetchai/contract_api:1.0.0\nspeech_acts:\n  get_deploy_transaction:\n    ledger_id: pt:str\n    contract_id: pt:str\n    callable: pt:str\n    kwargs: ct:Kwargs\n  get_raw_transaction:\n    ledger_id: pt:str\n    contract_id: pt:str\n    contract_address: pt:str\n    callable: pt:str\n    kwargs: ct:Kwargs\n  get_raw_message:\n    ledger_id: pt:str\n    contract_id: pt:str\n    contract_address: pt:str\n    callable: pt:str\n    kwargs: ct:Kwargs\n  get_state:\n    ledger_id: pt:str\n    contract_id: pt:str\n    contract_address: pt:str\n    callable: pt:str\n    kwargs: ct:Kwargs\n  state:\n    state: ct:State\n  raw_transaction:\n    raw_transaction: ct:RawTransaction\n  raw_message:\n    raw_message: ct:RawMessage\n  error:\n    code: pt:optional[pt:int]\n    message: pt:optional[pt:str]\n    data: pt:bytes\n...\n---\nct:Kwargs:\n  bytes kwargs = 1;\nct:State:\n  bytes state = 1;\nct:RawTransaction:\n  bytes raw_transaction = 1;\nct:RawMessage:\n  bytes raw_message = 1;\n...\n---\ninitiation: [get_deploy_transaction, get_raw_transaction, get_raw_message, get_state]\nreply:\n  get_deploy_transaction: [raw_transaction, error]\n  get_raw_transaction: [raw_transaction, error]\n  get_raw_message: [raw_message, error]\n  get_state: [state, error]\n  raw_transaction: []\n  raw_message: []\n  state: []\n  error: []\ntermination: [state, raw_transaction, raw_message, error]\nroles: {agent, ledger}\nend_states: [successful, failed]\nkeep_terminal_state_dialogues: false\n...\n```\n\n## Links\n"
  },
  {
    "path": "packages/fetchai/protocols/contract_api/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nThis module contains the support resources for the contract_api protocol.\n\nIt was created with protocol buffer compiler version `libprotoc 3.19.4` and aea version `1.2.5`.\n\"\"\"\n\nfrom packages.fetchai.protocols.contract_api.message import ContractApiMessage\nfrom packages.fetchai.protocols.contract_api.serialization import ContractApiSerializer\n\n\nContractApiMessage.serializer = ContractApiSerializer\n"
  },
  {
    "path": "packages/fetchai/protocols/contract_api/contract_api.proto",
    "content": "syntax = \"proto3\";\n\npackage aea.fetchai.contract_api.v1_0_0;\n\nmessage ContractApiMessage{\n\n  // Custom Types\n  message Kwargs{\n    bytes kwargs = 1;\n  }\n\n  message RawMessage{\n    bytes raw_message = 1;\n  }\n\n  message RawTransaction{\n    bytes raw_transaction = 1;\n  }\n\n  message State{\n    bytes state = 1;\n  }\n\n\n  // Performatives and contents\n  message Get_Deploy_Transaction_Performative{\n    string ledger_id = 1;\n    string contract_id = 2;\n    string callable = 3;\n    Kwargs kwargs = 4;\n  }\n\n  message Get_Raw_Transaction_Performative{\n    string ledger_id = 1;\n    string contract_id = 2;\n    string contract_address = 3;\n    string callable = 4;\n    Kwargs kwargs = 5;\n  }\n\n  message Get_Raw_Message_Performative{\n    string ledger_id = 1;\n    string contract_id = 2;\n    string contract_address = 3;\n    string callable = 4;\n    Kwargs kwargs = 5;\n  }\n\n  message Get_State_Performative{\n    string ledger_id = 1;\n    string contract_id = 2;\n    string contract_address = 3;\n    string callable = 4;\n    Kwargs kwargs = 5;\n  }\n\n  message State_Performative{\n    State state = 1;\n  }\n\n  message Raw_Transaction_Performative{\n    RawTransaction raw_transaction = 1;\n  }\n\n  message Raw_Message_Performative{\n    RawMessage raw_message = 1;\n  }\n\n  message Error_Performative{\n    int64 code = 1;\n    bool code_is_set = 2;\n    string message = 3;\n    bool message_is_set = 4;\n    bytes data = 5;\n  }\n\n\n  oneof performative{\n    Error_Performative error = 5;\n    Get_Deploy_Transaction_Performative get_deploy_transaction = 6;\n    Get_Raw_Message_Performative get_raw_message = 7;\n    Get_Raw_Transaction_Performative get_raw_transaction = 8;\n    Get_State_Performative get_state = 9;\n    Raw_Message_Performative raw_message = 10;\n    Raw_Transaction_Performative raw_transaction = 11;\n    State_Performative state = 12;\n  }\n}\n"
  },
  {
    "path": "packages/fetchai/protocols/contract_api/contract_api_pb2.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by the protocol buffer compiler.  DO NOT EDIT!\n# source: contract_api.proto\n\"\"\"Generated protocol buffer code.\"\"\"\nfrom google.protobuf import descriptor as _descriptor\nfrom google.protobuf import descriptor_pool as _descriptor_pool\nfrom google.protobuf import message as _message\nfrom google.protobuf import reflection as _reflection\nfrom google.protobuf import symbol_database as _symbol_database\n\n# @@protoc_insertion_point(imports)\n\n_sym_db = _symbol_database.Default()\n\n\nDESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(\n    b'\\n\\x12\\x63ontract_api.proto\\x12\\x1f\\x61\\x65\\x61.fetchai.contract_api.v1_0_0\"\\x93\\x11\\n\\x12\\x43ontractApiMessage\\x12W\\n\\x05\\x65rror\\x18\\x05 \\x01(\\x0b\\x32\\x46.aea.fetchai.contract_api.v1_0_0.ContractApiMessage.Error_PerformativeH\\x00\\x12y\\n\\x16get_deploy_transaction\\x18\\x06 \\x01(\\x0b\\x32W.aea.fetchai.contract_api.v1_0_0.ContractApiMessage.Get_Deploy_Transaction_PerformativeH\\x00\\x12k\\n\\x0fget_raw_message\\x18\\x07 \\x01(\\x0b\\x32P.aea.fetchai.contract_api.v1_0_0.ContractApiMessage.Get_Raw_Message_PerformativeH\\x00\\x12s\\n\\x13get_raw_transaction\\x18\\x08 \\x01(\\x0b\\x32T.aea.fetchai.contract_api.v1_0_0.ContractApiMessage.Get_Raw_Transaction_PerformativeH\\x00\\x12_\\n\\tget_state\\x18\\t \\x01(\\x0b\\x32J.aea.fetchai.contract_api.v1_0_0.ContractApiMessage.Get_State_PerformativeH\\x00\\x12\\x63\\n\\x0braw_message\\x18\\n \\x01(\\x0b\\x32L.aea.fetchai.contract_api.v1_0_0.ContractApiMessage.Raw_Message_PerformativeH\\x00\\x12k\\n\\x0fraw_transaction\\x18\\x0b \\x01(\\x0b\\x32P.aea.fetchai.contract_api.v1_0_0.ContractApiMessage.Raw_Transaction_PerformativeH\\x00\\x12W\\n\\x05state\\x18\\x0c \\x01(\\x0b\\x32\\x46.aea.fetchai.contract_api.v1_0_0.ContractApiMessage.State_PerformativeH\\x00\\x1a\\x18\\n\\x06Kwargs\\x12\\x0e\\n\\x06kwargs\\x18\\x01 \\x01(\\x0c\\x1a!\\n\\nRawMessage\\x12\\x13\\n\\x0braw_message\\x18\\x01 \\x01(\\x0c\\x1a)\\n\\x0eRawTransaction\\x12\\x17\\n\\x0fraw_transaction\\x18\\x01 \\x01(\\x0c\\x1a\\x16\\n\\x05State\\x12\\r\\n\\x05state\\x18\\x01 \\x01(\\x0c\\x1a\\xab\\x01\\n#Get_Deploy_Transaction_Performative\\x12\\x11\\n\\tledger_id\\x18\\x01 \\x01(\\t\\x12\\x13\\n\\x0b\\x63ontract_id\\x18\\x02 \\x01(\\t\\x12\\x10\\n\\x08\\x63\\x61llable\\x18\\x03 \\x01(\\t\\x12J\\n\\x06kwargs\\x18\\x04 \\x01(\\x0b\\x32:.aea.fetchai.contract_api.v1_0_0.ContractApiMessage.Kwargs\\x1a\\xc2\\x01\\n Get_Raw_Transaction_Performative\\x12\\x11\\n\\tledger_id\\x18\\x01 \\x01(\\t\\x12\\x13\\n\\x0b\\x63ontract_id\\x18\\x02 \\x01(\\t\\x12\\x18\\n\\x10\\x63ontract_address\\x18\\x03 \\x01(\\t\\x12\\x10\\n\\x08\\x63\\x61llable\\x18\\x04 \\x01(\\t\\x12J\\n\\x06kwargs\\x18\\x05 \\x01(\\x0b\\x32:.aea.fetchai.contract_api.v1_0_0.ContractApiMessage.Kwargs\\x1a\\xbe\\x01\\n\\x1cGet_Raw_Message_Performative\\x12\\x11\\n\\tledger_id\\x18\\x01 \\x01(\\t\\x12\\x13\\n\\x0b\\x63ontract_id\\x18\\x02 \\x01(\\t\\x12\\x18\\n\\x10\\x63ontract_address\\x18\\x03 \\x01(\\t\\x12\\x10\\n\\x08\\x63\\x61llable\\x18\\x04 \\x01(\\t\\x12J\\n\\x06kwargs\\x18\\x05 \\x01(\\x0b\\x32:.aea.fetchai.contract_api.v1_0_0.ContractApiMessage.Kwargs\\x1a\\xb8\\x01\\n\\x16Get_State_Performative\\x12\\x11\\n\\tledger_id\\x18\\x01 \\x01(\\t\\x12\\x13\\n\\x0b\\x63ontract_id\\x18\\x02 \\x01(\\t\\x12\\x18\\n\\x10\\x63ontract_address\\x18\\x03 \\x01(\\t\\x12\\x10\\n\\x08\\x63\\x61llable\\x18\\x04 \\x01(\\t\\x12J\\n\\x06kwargs\\x18\\x05 \\x01(\\x0b\\x32:.aea.fetchai.contract_api.v1_0_0.ContractApiMessage.Kwargs\\x1a^\\n\\x12State_Performative\\x12H\\n\\x05state\\x18\\x01 \\x01(\\x0b\\x32\\x39.aea.fetchai.contract_api.v1_0_0.ContractApiMessage.State\\x1a{\\n\\x1cRaw_Transaction_Performative\\x12[\\n\\x0fraw_transaction\\x18\\x01 \\x01(\\x0b\\x32\\x42.aea.fetchai.contract_api.v1_0_0.ContractApiMessage.RawTransaction\\x1ao\\n\\x18Raw_Message_Performative\\x12S\\n\\x0braw_message\\x18\\x01 \\x01(\\x0b\\x32>.aea.fetchai.contract_api.v1_0_0.ContractApiMessage.RawMessage\\x1an\\n\\x12\\x45rror_Performative\\x12\\x0c\\n\\x04\\x63ode\\x18\\x01 \\x01(\\x03\\x12\\x13\\n\\x0b\\x63ode_is_set\\x18\\x02 \\x01(\\x08\\x12\\x0f\\n\\x07message\\x18\\x03 \\x01(\\t\\x12\\x16\\n\\x0emessage_is_set\\x18\\x04 \\x01(\\x08\\x12\\x0c\\n\\x04\\x64\\x61ta\\x18\\x05 \\x01(\\x0c\\x42\\x0e\\n\\x0cperformativeb\\x06proto3'\n)\n\n\n_CONTRACTAPIMESSAGE = DESCRIPTOR.message_types_by_name[\"ContractApiMessage\"]\n_CONTRACTAPIMESSAGE_KWARGS = _CONTRACTAPIMESSAGE.nested_types_by_name[\"Kwargs\"]\n_CONTRACTAPIMESSAGE_RAWMESSAGE = _CONTRACTAPIMESSAGE.nested_types_by_name[\"RawMessage\"]\n_CONTRACTAPIMESSAGE_RAWTRANSACTION = _CONTRACTAPIMESSAGE.nested_types_by_name[\n    \"RawTransaction\"\n]\n_CONTRACTAPIMESSAGE_STATE = _CONTRACTAPIMESSAGE.nested_types_by_name[\"State\"]\n_CONTRACTAPIMESSAGE_GET_DEPLOY_TRANSACTION_PERFORMATIVE = (\n    _CONTRACTAPIMESSAGE.nested_types_by_name[\"Get_Deploy_Transaction_Performative\"]\n)\n_CONTRACTAPIMESSAGE_GET_RAW_TRANSACTION_PERFORMATIVE = (\n    _CONTRACTAPIMESSAGE.nested_types_by_name[\"Get_Raw_Transaction_Performative\"]\n)\n_CONTRACTAPIMESSAGE_GET_RAW_MESSAGE_PERFORMATIVE = (\n    _CONTRACTAPIMESSAGE.nested_types_by_name[\"Get_Raw_Message_Performative\"]\n)\n_CONTRACTAPIMESSAGE_GET_STATE_PERFORMATIVE = _CONTRACTAPIMESSAGE.nested_types_by_name[\n    \"Get_State_Performative\"\n]\n_CONTRACTAPIMESSAGE_STATE_PERFORMATIVE = _CONTRACTAPIMESSAGE.nested_types_by_name[\n    \"State_Performative\"\n]\n_CONTRACTAPIMESSAGE_RAW_TRANSACTION_PERFORMATIVE = (\n    _CONTRACTAPIMESSAGE.nested_types_by_name[\"Raw_Transaction_Performative\"]\n)\n_CONTRACTAPIMESSAGE_RAW_MESSAGE_PERFORMATIVE = _CONTRACTAPIMESSAGE.nested_types_by_name[\n    \"Raw_Message_Performative\"\n]\n_CONTRACTAPIMESSAGE_ERROR_PERFORMATIVE = _CONTRACTAPIMESSAGE.nested_types_by_name[\n    \"Error_Performative\"\n]\nContractApiMessage = _reflection.GeneratedProtocolMessageType(\n    \"ContractApiMessage\",\n    (_message.Message,),\n    {\n        \"Kwargs\": _reflection.GeneratedProtocolMessageType(\n            \"Kwargs\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _CONTRACTAPIMESSAGE_KWARGS,\n                \"__module__\": \"contract_api_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.contract_api.v1_0_0.ContractApiMessage.Kwargs)\n            },\n        ),\n        \"RawMessage\": _reflection.GeneratedProtocolMessageType(\n            \"RawMessage\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _CONTRACTAPIMESSAGE_RAWMESSAGE,\n                \"__module__\": \"contract_api_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.contract_api.v1_0_0.ContractApiMessage.RawMessage)\n            },\n        ),\n        \"RawTransaction\": _reflection.GeneratedProtocolMessageType(\n            \"RawTransaction\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _CONTRACTAPIMESSAGE_RAWTRANSACTION,\n                \"__module__\": \"contract_api_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.contract_api.v1_0_0.ContractApiMessage.RawTransaction)\n            },\n        ),\n        \"State\": _reflection.GeneratedProtocolMessageType(\n            \"State\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _CONTRACTAPIMESSAGE_STATE,\n                \"__module__\": \"contract_api_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.contract_api.v1_0_0.ContractApiMessage.State)\n            },\n        ),\n        \"Get_Deploy_Transaction_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Get_Deploy_Transaction_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _CONTRACTAPIMESSAGE_GET_DEPLOY_TRANSACTION_PERFORMATIVE,\n                \"__module__\": \"contract_api_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.contract_api.v1_0_0.ContractApiMessage.Get_Deploy_Transaction_Performative)\n            },\n        ),\n        \"Get_Raw_Transaction_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Get_Raw_Transaction_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _CONTRACTAPIMESSAGE_GET_RAW_TRANSACTION_PERFORMATIVE,\n                \"__module__\": \"contract_api_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.contract_api.v1_0_0.ContractApiMessage.Get_Raw_Transaction_Performative)\n            },\n        ),\n        \"Get_Raw_Message_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Get_Raw_Message_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _CONTRACTAPIMESSAGE_GET_RAW_MESSAGE_PERFORMATIVE,\n                \"__module__\": \"contract_api_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.contract_api.v1_0_0.ContractApiMessage.Get_Raw_Message_Performative)\n            },\n        ),\n        \"Get_State_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Get_State_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _CONTRACTAPIMESSAGE_GET_STATE_PERFORMATIVE,\n                \"__module__\": \"contract_api_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.contract_api.v1_0_0.ContractApiMessage.Get_State_Performative)\n            },\n        ),\n        \"State_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"State_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _CONTRACTAPIMESSAGE_STATE_PERFORMATIVE,\n                \"__module__\": \"contract_api_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.contract_api.v1_0_0.ContractApiMessage.State_Performative)\n            },\n        ),\n        \"Raw_Transaction_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Raw_Transaction_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _CONTRACTAPIMESSAGE_RAW_TRANSACTION_PERFORMATIVE,\n                \"__module__\": \"contract_api_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.contract_api.v1_0_0.ContractApiMessage.Raw_Transaction_Performative)\n            },\n        ),\n        \"Raw_Message_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Raw_Message_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _CONTRACTAPIMESSAGE_RAW_MESSAGE_PERFORMATIVE,\n                \"__module__\": \"contract_api_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.contract_api.v1_0_0.ContractApiMessage.Raw_Message_Performative)\n            },\n        ),\n        \"Error_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Error_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _CONTRACTAPIMESSAGE_ERROR_PERFORMATIVE,\n                \"__module__\": \"contract_api_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.contract_api.v1_0_0.ContractApiMessage.Error_Performative)\n            },\n        ),\n        \"DESCRIPTOR\": _CONTRACTAPIMESSAGE,\n        \"__module__\": \"contract_api_pb2\"\n        # @@protoc_insertion_point(class_scope:aea.fetchai.contract_api.v1_0_0.ContractApiMessage)\n    },\n)\n_sym_db.RegisterMessage(ContractApiMessage)\n_sym_db.RegisterMessage(ContractApiMessage.Kwargs)\n_sym_db.RegisterMessage(ContractApiMessage.RawMessage)\n_sym_db.RegisterMessage(ContractApiMessage.RawTransaction)\n_sym_db.RegisterMessage(ContractApiMessage.State)\n_sym_db.RegisterMessage(ContractApiMessage.Get_Deploy_Transaction_Performative)\n_sym_db.RegisterMessage(ContractApiMessage.Get_Raw_Transaction_Performative)\n_sym_db.RegisterMessage(ContractApiMessage.Get_Raw_Message_Performative)\n_sym_db.RegisterMessage(ContractApiMessage.Get_State_Performative)\n_sym_db.RegisterMessage(ContractApiMessage.State_Performative)\n_sym_db.RegisterMessage(ContractApiMessage.Raw_Transaction_Performative)\n_sym_db.RegisterMessage(ContractApiMessage.Raw_Message_Performative)\n_sym_db.RegisterMessage(ContractApiMessage.Error_Performative)\n\nif _descriptor._USE_C_DESCRIPTORS == False:\n\n    DESCRIPTOR._options = None\n    _CONTRACTAPIMESSAGE._serialized_start = 56\n    _CONTRACTAPIMESSAGE._serialized_end = 2251\n    _CONTRACTAPIMESSAGE_KWARGS._serialized_start = 912\n    _CONTRACTAPIMESSAGE_KWARGS._serialized_end = 936\n    _CONTRACTAPIMESSAGE_RAWMESSAGE._serialized_start = 938\n    _CONTRACTAPIMESSAGE_RAWMESSAGE._serialized_end = 971\n    _CONTRACTAPIMESSAGE_RAWTRANSACTION._serialized_start = 973\n    _CONTRACTAPIMESSAGE_RAWTRANSACTION._serialized_end = 1014\n    _CONTRACTAPIMESSAGE_STATE._serialized_start = 1016\n    _CONTRACTAPIMESSAGE_STATE._serialized_end = 1038\n    _CONTRACTAPIMESSAGE_GET_DEPLOY_TRANSACTION_PERFORMATIVE._serialized_start = 1041\n    _CONTRACTAPIMESSAGE_GET_DEPLOY_TRANSACTION_PERFORMATIVE._serialized_end = 1212\n    _CONTRACTAPIMESSAGE_GET_RAW_TRANSACTION_PERFORMATIVE._serialized_start = 1215\n    _CONTRACTAPIMESSAGE_GET_RAW_TRANSACTION_PERFORMATIVE._serialized_end = 1409\n    _CONTRACTAPIMESSAGE_GET_RAW_MESSAGE_PERFORMATIVE._serialized_start = 1412\n    _CONTRACTAPIMESSAGE_GET_RAW_MESSAGE_PERFORMATIVE._serialized_end = 1602\n    _CONTRACTAPIMESSAGE_GET_STATE_PERFORMATIVE._serialized_start = 1605\n    _CONTRACTAPIMESSAGE_GET_STATE_PERFORMATIVE._serialized_end = 1789\n    _CONTRACTAPIMESSAGE_STATE_PERFORMATIVE._serialized_start = 1791\n    _CONTRACTAPIMESSAGE_STATE_PERFORMATIVE._serialized_end = 1885\n    _CONTRACTAPIMESSAGE_RAW_TRANSACTION_PERFORMATIVE._serialized_start = 1887\n    _CONTRACTAPIMESSAGE_RAW_TRANSACTION_PERFORMATIVE._serialized_end = 2010\n    _CONTRACTAPIMESSAGE_RAW_MESSAGE_PERFORMATIVE._serialized_start = 2012\n    _CONTRACTAPIMESSAGE_RAW_MESSAGE_PERFORMATIVE._serialized_end = 2123\n    _CONTRACTAPIMESSAGE_ERROR_PERFORMATIVE._serialized_start = 2125\n    _CONTRACTAPIMESSAGE_ERROR_PERFORMATIVE._serialized_end = 2235\n# @@protoc_insertion_point(module_scope)\n"
  },
  {
    "path": "packages/fetchai/protocols/contract_api/custom_types.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains class representations corresponding to every custom type in the protocol specification.\"\"\"\n\nfrom typing import Any\n\nfrom aea.common import JSONLike\nfrom aea.exceptions import enforce\nfrom aea.helpers.serializers import DictProtobufStructSerializer\nfrom aea.helpers.transaction.base import RawMessage as BaseRawMessage\nfrom aea.helpers.transaction.base import RawTransaction as BaseRawTransaction\nfrom aea.helpers.transaction.base import State as BaseState\n\n\nRawMessage = BaseRawMessage\nRawTransaction = BaseRawTransaction\nState = BaseState\n\n\nclass Kwargs:\n    \"\"\"This class represents an instance of Kwargs.\"\"\"\n\n    __slots__ = (\"_body\",)\n\n    def __init__(\n        self,\n        body: JSONLike,\n    ):\n        \"\"\"Initialise an instance of RawTransaction.\"\"\"\n        self._body = body\n        self._check_consistency()\n\n    def _check_consistency(self) -> None:\n        \"\"\"Check consistency of the object.\"\"\"\n        enforce(\n            isinstance(self._body, dict)\n            and all(isinstance(key, str) for key in self._body.keys()),\n            \"Body must be dict and keys must be str.\",\n        )\n\n    @property\n    def body(self) -> JSONLike:\n        \"\"\"Get the body.\"\"\"\n        return self._body\n\n    @staticmethod\n    def encode(kwargs_protobuf_object: Any, kwargs_object: \"Kwargs\") -> None:\n        \"\"\"\n        Encode an instance of this class into the protocol buffer object.\n\n        The protocol buffer object in the kwargs_protobuf_object argument is matched with the instance of this class in the 'kwargs_object' argument.\n\n        :param kwargs_protobuf_object: the protocol buffer object whose type corresponds with this class.\n        :param kwargs_object: an instance of this class to be encoded in the protocol buffer object.\n        \"\"\"\n        kwargs_protobuf_object.kwargs = DictProtobufStructSerializer.encode(\n            kwargs_object.body\n        )\n\n    @classmethod\n    def decode(cls, kwargs_protobuf_object: Any) -> \"Kwargs\":\n        \"\"\"\n        Decode a protocol buffer object that corresponds with this class into an instance of this class.\n\n        A new instance of this class is created that matches the protocol buffer object in the 'kwargs_protobuf_object' argument.\n\n        :param kwargs_protobuf_object: the protocol buffer object whose type corresponds with this class.\n        :return: A new instance of this class that matches the protocol buffer object in the 'kwargs_protobuf_object' argument.\n        \"\"\"\n        kwargs = DictProtobufStructSerializer.decode(kwargs_protobuf_object.kwargs)\n        return cls(kwargs)\n\n    def __eq__(self, other: Any) -> bool:\n        \"\"\"Check equality.\"\"\"\n        return isinstance(other, Kwargs) and self.body == other.body\n\n    def __str__(self) -> str:\n        \"\"\"Get string representation.\"\"\"\n        return \"Kwargs: body={}\".format(self.body)\n"
  },
  {
    "path": "packages/fetchai/protocols/contract_api/dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nThis module contains the classes required for contract_api dialogue management.\n\n- ContractApiDialogue: The dialogue class maintains state of a dialogue and manages it.\n- ContractApiDialogues: The dialogues class keeps track of all dialogues.\n\"\"\"\n\nfrom abc import ABC\nfrom typing import Callable, Dict, FrozenSet, Type, cast\n\nfrom aea.common import Address\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue, DialogueLabel, Dialogues\n\nfrom packages.fetchai.protocols.contract_api.message import ContractApiMessage\n\n\nclass ContractApiDialogue(Dialogue):\n    \"\"\"The contract_api dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    INITIAL_PERFORMATIVES: FrozenSet[Message.Performative] = frozenset(\n        {\n            ContractApiMessage.Performative.GET_DEPLOY_TRANSACTION,\n            ContractApiMessage.Performative.GET_RAW_TRANSACTION,\n            ContractApiMessage.Performative.GET_RAW_MESSAGE,\n            ContractApiMessage.Performative.GET_STATE,\n        }\n    )\n    TERMINAL_PERFORMATIVES: FrozenSet[Message.Performative] = frozenset(\n        {\n            ContractApiMessage.Performative.STATE,\n            ContractApiMessage.Performative.RAW_TRANSACTION,\n            ContractApiMessage.Performative.RAW_MESSAGE,\n            ContractApiMessage.Performative.ERROR,\n        }\n    )\n    VALID_REPLIES: Dict[Message.Performative, FrozenSet[Message.Performative]] = {\n        ContractApiMessage.Performative.ERROR: frozenset(),\n        ContractApiMessage.Performative.GET_DEPLOY_TRANSACTION: frozenset(\n            {\n                ContractApiMessage.Performative.RAW_TRANSACTION,\n                ContractApiMessage.Performative.ERROR,\n            }\n        ),\n        ContractApiMessage.Performative.GET_RAW_MESSAGE: frozenset(\n            {\n                ContractApiMessage.Performative.RAW_MESSAGE,\n                ContractApiMessage.Performative.ERROR,\n            }\n        ),\n        ContractApiMessage.Performative.GET_RAW_TRANSACTION: frozenset(\n            {\n                ContractApiMessage.Performative.RAW_TRANSACTION,\n                ContractApiMessage.Performative.ERROR,\n            }\n        ),\n        ContractApiMessage.Performative.GET_STATE: frozenset(\n            {\n                ContractApiMessage.Performative.STATE,\n                ContractApiMessage.Performative.ERROR,\n            }\n        ),\n        ContractApiMessage.Performative.RAW_MESSAGE: frozenset(),\n        ContractApiMessage.Performative.RAW_TRANSACTION: frozenset(),\n        ContractApiMessage.Performative.STATE: frozenset(),\n    }\n\n    class Role(Dialogue.Role):\n        \"\"\"This class defines the agent's role in a contract_api dialogue.\"\"\"\n\n        AGENT = \"agent\"\n        LEDGER = \"ledger\"\n\n    class EndState(Dialogue.EndState):\n        \"\"\"This class defines the end states of a contract_api dialogue.\"\"\"\n\n        SUCCESSFUL = 0\n        FAILED = 1\n\n    def __init__(\n        self,\n        dialogue_label: DialogueLabel,\n        self_address: Address,\n        role: Dialogue.Role,\n        message_class: Type[ContractApiMessage] = ContractApiMessage,\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n        :param message_class: the message class used\n        \"\"\"\n        Dialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            message_class=message_class,\n            self_address=self_address,\n            role=role,\n        )\n\n\nclass ContractApiDialogues(Dialogues, ABC):\n    \"\"\"This class keeps track of all contract_api dialogues.\"\"\"\n\n    END_STATES = frozenset(\n        {ContractApiDialogue.EndState.SUCCESSFUL, ContractApiDialogue.EndState.FAILED}\n    )\n\n    _keep_terminal_state_dialogues = False\n\n    def __init__(\n        self,\n        self_address: Address,\n        role_from_first_message: Callable[[Message, Address], Dialogue.Role],\n        dialogue_class: Type[ContractApiDialogue] = ContractApiDialogue,\n    ) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param self_address: the address of the entity for whom dialogues are maintained\n        :param dialogue_class: the dialogue class used\n        :param role_from_first_message: the callable determining role from first message\n        \"\"\"\n        Dialogues.__init__(\n            self,\n            self_address=self_address,\n            end_states=cast(FrozenSet[Dialogue.EndState], self.END_STATES),\n            message_class=ContractApiMessage,\n            dialogue_class=dialogue_class,\n            role_from_first_message=role_from_first_message,\n        )\n"
  },
  {
    "path": "packages/fetchai/protocols/contract_api/message.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains contract_api's message definition.\"\"\"\n\n# pylint: disable=too-many-statements,too-many-locals,no-member,too-few-public-methods,too-many-branches,not-an-iterable,unidiomatic-typecheck,unsubscriptable-object\nimport logging\nfrom typing import Any, Optional, Set, Tuple, cast\n\nfrom aea.configurations.base import PublicId\nfrom aea.exceptions import AEAEnforceError, enforce\nfrom aea.protocols.base import Message\n\nfrom packages.fetchai.protocols.contract_api.custom_types import Kwargs as CustomKwargs\nfrom packages.fetchai.protocols.contract_api.custom_types import (\n    RawMessage as CustomRawMessage,\n)\nfrom packages.fetchai.protocols.contract_api.custom_types import (\n    RawTransaction as CustomRawTransaction,\n)\nfrom packages.fetchai.protocols.contract_api.custom_types import State as CustomState\n\n\n_default_logger = logging.getLogger(\n    \"aea.packages.fetchai.protocols.contract_api.message\"\n)\n\nDEFAULT_BODY_SIZE = 4\n\n\nclass ContractApiMessage(Message):\n    \"\"\"A protocol for contract APIs requests and responses.\"\"\"\n\n    protocol_id = PublicId.from_str(\"fetchai/contract_api:1.1.7\")\n    protocol_specification_id = PublicId.from_str(\"fetchai/contract_api:1.0.0\")\n\n    Kwargs = CustomKwargs\n\n    RawMessage = CustomRawMessage\n\n    RawTransaction = CustomRawTransaction\n\n    State = CustomState\n\n    class Performative(Message.Performative):\n        \"\"\"Performatives for the contract_api protocol.\"\"\"\n\n        ERROR = \"error\"\n        GET_DEPLOY_TRANSACTION = \"get_deploy_transaction\"\n        GET_RAW_MESSAGE = \"get_raw_message\"\n        GET_RAW_TRANSACTION = \"get_raw_transaction\"\n        GET_STATE = \"get_state\"\n        RAW_MESSAGE = \"raw_message\"\n        RAW_TRANSACTION = \"raw_transaction\"\n        STATE = \"state\"\n\n        def __str__(self) -> str:\n            \"\"\"Get the string representation.\"\"\"\n            return str(self.value)\n\n    _performatives = {\n        \"error\",\n        \"get_deploy_transaction\",\n        \"get_raw_message\",\n        \"get_raw_transaction\",\n        \"get_state\",\n        \"raw_message\",\n        \"raw_transaction\",\n        \"state\",\n    }\n    __slots__: Tuple[str, ...] = tuple()\n\n    class _SlotsCls:\n        __slots__ = (\n            \"callable\",\n            \"code\",\n            \"contract_address\",\n            \"contract_id\",\n            \"data\",\n            \"dialogue_reference\",\n            \"kwargs\",\n            \"ledger_id\",\n            \"message\",\n            \"message_id\",\n            \"performative\",\n            \"raw_message\",\n            \"raw_transaction\",\n            \"state\",\n            \"target\",\n        )\n\n    def __init__(\n        self,\n        performative: Performative,\n        dialogue_reference: Tuple[str, str] = (\"\", \"\"),\n        message_id: int = 1,\n        target: int = 0,\n        **kwargs: Any,\n    ):\n        \"\"\"\n        Initialise an instance of ContractApiMessage.\n\n        :param message_id: the message id.\n        :param dialogue_reference: the dialogue reference.\n        :param target: the message target.\n        :param performative: the message performative.\n        :param **kwargs: extra options.\n        \"\"\"\n        super().__init__(\n            dialogue_reference=dialogue_reference,\n            message_id=message_id,\n            target=target,\n            performative=ContractApiMessage.Performative(performative),\n            **kwargs,\n        )\n\n    @property\n    def valid_performatives(self) -> Set[str]:\n        \"\"\"Get valid performatives.\"\"\"\n        return self._performatives\n\n    @property\n    def dialogue_reference(self) -> Tuple[str, str]:\n        \"\"\"Get the dialogue_reference of the message.\"\"\"\n        enforce(self.is_set(\"dialogue_reference\"), \"dialogue_reference is not set.\")\n        return cast(Tuple[str, str], self.get(\"dialogue_reference\"))\n\n    @property\n    def message_id(self) -> int:\n        \"\"\"Get the message_id of the message.\"\"\"\n        enforce(self.is_set(\"message_id\"), \"message_id is not set.\")\n        return cast(int, self.get(\"message_id\"))\n\n    @property\n    def performative(self) -> Performative:  # type: ignore # noqa: F821\n        \"\"\"Get the performative of the message.\"\"\"\n        enforce(self.is_set(\"performative\"), \"performative is not set.\")\n        return cast(ContractApiMessage.Performative, self.get(\"performative\"))\n\n    @property\n    def target(self) -> int:\n        \"\"\"Get the target of the message.\"\"\"\n        enforce(self.is_set(\"target\"), \"target is not set.\")\n        return cast(int, self.get(\"target\"))\n\n    @property\n    def callable(self) -> str:\n        \"\"\"Get the 'callable' content from the message.\"\"\"\n        enforce(self.is_set(\"callable\"), \"'callable' content is not set.\")\n        return cast(str, self.get(\"callable\"))\n\n    @property\n    def code(self) -> Optional[int]:\n        \"\"\"Get the 'code' content from the message.\"\"\"\n        return cast(Optional[int], self.get(\"code\"))\n\n    @property\n    def contract_address(self) -> str:\n        \"\"\"Get the 'contract_address' content from the message.\"\"\"\n        enforce(\n            self.is_set(\"contract_address\"), \"'contract_address' content is not set.\"\n        )\n        return cast(str, self.get(\"contract_address\"))\n\n    @property\n    def contract_id(self) -> str:\n        \"\"\"Get the 'contract_id' content from the message.\"\"\"\n        enforce(self.is_set(\"contract_id\"), \"'contract_id' content is not set.\")\n        return cast(str, self.get(\"contract_id\"))\n\n    @property\n    def data(self) -> bytes:\n        \"\"\"Get the 'data' content from the message.\"\"\"\n        enforce(self.is_set(\"data\"), \"'data' content is not set.\")\n        return cast(bytes, self.get(\"data\"))\n\n    @property\n    def kwargs(self) -> CustomKwargs:\n        \"\"\"Get the 'kwargs' content from the message.\"\"\"\n        enforce(self.is_set(\"kwargs\"), \"'kwargs' content is not set.\")\n        return cast(CustomKwargs, self.get(\"kwargs\"))\n\n    @property\n    def ledger_id(self) -> str:\n        \"\"\"Get the 'ledger_id' content from the message.\"\"\"\n        enforce(self.is_set(\"ledger_id\"), \"'ledger_id' content is not set.\")\n        return cast(str, self.get(\"ledger_id\"))\n\n    @property\n    def message(self) -> Optional[str]:\n        \"\"\"Get the 'message' content from the message.\"\"\"\n        return cast(Optional[str], self.get(\"message\"))\n\n    @property\n    def raw_message(self) -> CustomRawMessage:\n        \"\"\"Get the 'raw_message' content from the message.\"\"\"\n        enforce(self.is_set(\"raw_message\"), \"'raw_message' content is not set.\")\n        return cast(CustomRawMessage, self.get(\"raw_message\"))\n\n    @property\n    def raw_transaction(self) -> CustomRawTransaction:\n        \"\"\"Get the 'raw_transaction' content from the message.\"\"\"\n        enforce(self.is_set(\"raw_transaction\"), \"'raw_transaction' content is not set.\")\n        return cast(CustomRawTransaction, self.get(\"raw_transaction\"))\n\n    @property\n    def state(self) -> CustomState:\n        \"\"\"Get the 'state' content from the message.\"\"\"\n        enforce(self.is_set(\"state\"), \"'state' content is not set.\")\n        return cast(CustomState, self.get(\"state\"))\n\n    def _is_consistent(self) -> bool:\n        \"\"\"Check that the message follows the contract_api protocol.\"\"\"\n        try:\n            enforce(\n                isinstance(self.dialogue_reference, tuple),\n                \"Invalid type for 'dialogue_reference'. Expected 'tuple'. Found '{}'.\".format(\n                    type(self.dialogue_reference)\n                ),\n            )\n            enforce(\n                isinstance(self.dialogue_reference[0], str),\n                \"Invalid type for 'dialogue_reference[0]'. Expected 'str'. Found '{}'.\".format(\n                    type(self.dialogue_reference[0])\n                ),\n            )\n            enforce(\n                isinstance(self.dialogue_reference[1], str),\n                \"Invalid type for 'dialogue_reference[1]'. Expected 'str'. Found '{}'.\".format(\n                    type(self.dialogue_reference[1])\n                ),\n            )\n            enforce(\n                type(self.message_id) is int,\n                \"Invalid type for 'message_id'. Expected 'int'. Found '{}'.\".format(\n                    type(self.message_id)\n                ),\n            )\n            enforce(\n                type(self.target) is int,\n                \"Invalid type for 'target'. Expected 'int'. Found '{}'.\".format(\n                    type(self.target)\n                ),\n            )\n\n            # Light Protocol Rule 2\n            # Check correct performative\n            enforce(\n                isinstance(self.performative, ContractApiMessage.Performative),\n                \"Invalid 'performative'. Expected either of '{}'. Found '{}'.\".format(\n                    self.valid_performatives, self.performative\n                ),\n            )\n\n            # Check correct contents\n            actual_nb_of_contents = len(self._body) - DEFAULT_BODY_SIZE\n            expected_nb_of_contents = 0\n            if (\n                self.performative\n                == ContractApiMessage.Performative.GET_DEPLOY_TRANSACTION\n            ):\n                expected_nb_of_contents = 4\n                enforce(\n                    isinstance(self.ledger_id, str),\n                    \"Invalid type for content 'ledger_id'. Expected 'str'. Found '{}'.\".format(\n                        type(self.ledger_id)\n                    ),\n                )\n                enforce(\n                    isinstance(self.contract_id, str),\n                    \"Invalid type for content 'contract_id'. Expected 'str'. Found '{}'.\".format(\n                        type(self.contract_id)\n                    ),\n                )\n                enforce(\n                    isinstance(self.callable, str),\n                    \"Invalid type for content 'callable'. Expected 'str'. Found '{}'.\".format(\n                        type(self.callable)\n                    ),\n                )\n                enforce(\n                    isinstance(self.kwargs, CustomKwargs),\n                    \"Invalid type for content 'kwargs'. Expected 'Kwargs'. Found '{}'.\".format(\n                        type(self.kwargs)\n                    ),\n                )\n            elif (\n                self.performative == ContractApiMessage.Performative.GET_RAW_TRANSACTION\n            ):\n                expected_nb_of_contents = 5\n                enforce(\n                    isinstance(self.ledger_id, str),\n                    \"Invalid type for content 'ledger_id'. Expected 'str'. Found '{}'.\".format(\n                        type(self.ledger_id)\n                    ),\n                )\n                enforce(\n                    isinstance(self.contract_id, str),\n                    \"Invalid type for content 'contract_id'. Expected 'str'. Found '{}'.\".format(\n                        type(self.contract_id)\n                    ),\n                )\n                enforce(\n                    isinstance(self.contract_address, str),\n                    \"Invalid type for content 'contract_address'. Expected 'str'. Found '{}'.\".format(\n                        type(self.contract_address)\n                    ),\n                )\n                enforce(\n                    isinstance(self.callable, str),\n                    \"Invalid type for content 'callable'. Expected 'str'. Found '{}'.\".format(\n                        type(self.callable)\n                    ),\n                )\n                enforce(\n                    isinstance(self.kwargs, CustomKwargs),\n                    \"Invalid type for content 'kwargs'. Expected 'Kwargs'. Found '{}'.\".format(\n                        type(self.kwargs)\n                    ),\n                )\n            elif self.performative == ContractApiMessage.Performative.GET_RAW_MESSAGE:\n                expected_nb_of_contents = 5\n                enforce(\n                    isinstance(self.ledger_id, str),\n                    \"Invalid type for content 'ledger_id'. Expected 'str'. Found '{}'.\".format(\n                        type(self.ledger_id)\n                    ),\n                )\n                enforce(\n                    isinstance(self.contract_id, str),\n                    \"Invalid type for content 'contract_id'. Expected 'str'. Found '{}'.\".format(\n                        type(self.contract_id)\n                    ),\n                )\n                enforce(\n                    isinstance(self.contract_address, str),\n                    \"Invalid type for content 'contract_address'. Expected 'str'. Found '{}'.\".format(\n                        type(self.contract_address)\n                    ),\n                )\n                enforce(\n                    isinstance(self.callable, str),\n                    \"Invalid type for content 'callable'. Expected 'str'. Found '{}'.\".format(\n                        type(self.callable)\n                    ),\n                )\n                enforce(\n                    isinstance(self.kwargs, CustomKwargs),\n                    \"Invalid type for content 'kwargs'. Expected 'Kwargs'. Found '{}'.\".format(\n                        type(self.kwargs)\n                    ),\n                )\n            elif self.performative == ContractApiMessage.Performative.GET_STATE:\n                expected_nb_of_contents = 5\n                enforce(\n                    isinstance(self.ledger_id, str),\n                    \"Invalid type for content 'ledger_id'. Expected 'str'. Found '{}'.\".format(\n                        type(self.ledger_id)\n                    ),\n                )\n                enforce(\n                    isinstance(self.contract_id, str),\n                    \"Invalid type for content 'contract_id'. Expected 'str'. Found '{}'.\".format(\n                        type(self.contract_id)\n                    ),\n                )\n                enforce(\n                    isinstance(self.contract_address, str),\n                    \"Invalid type for content 'contract_address'. Expected 'str'. Found '{}'.\".format(\n                        type(self.contract_address)\n                    ),\n                )\n                enforce(\n                    isinstance(self.callable, str),\n                    \"Invalid type for content 'callable'. Expected 'str'. Found '{}'.\".format(\n                        type(self.callable)\n                    ),\n                )\n                enforce(\n                    isinstance(self.kwargs, CustomKwargs),\n                    \"Invalid type for content 'kwargs'. Expected 'Kwargs'. Found '{}'.\".format(\n                        type(self.kwargs)\n                    ),\n                )\n            elif self.performative == ContractApiMessage.Performative.STATE:\n                expected_nb_of_contents = 1\n                enforce(\n                    isinstance(self.state, CustomState),\n                    \"Invalid type for content 'state'. Expected 'State'. Found '{}'.\".format(\n                        type(self.state)\n                    ),\n                )\n            elif self.performative == ContractApiMessage.Performative.RAW_TRANSACTION:\n                expected_nb_of_contents = 1\n                enforce(\n                    isinstance(self.raw_transaction, CustomRawTransaction),\n                    \"Invalid type for content 'raw_transaction'. Expected 'RawTransaction'. Found '{}'.\".format(\n                        type(self.raw_transaction)\n                    ),\n                )\n            elif self.performative == ContractApiMessage.Performative.RAW_MESSAGE:\n                expected_nb_of_contents = 1\n                enforce(\n                    isinstance(self.raw_message, CustomRawMessage),\n                    \"Invalid type for content 'raw_message'. Expected 'RawMessage'. Found '{}'.\".format(\n                        type(self.raw_message)\n                    ),\n                )\n            elif self.performative == ContractApiMessage.Performative.ERROR:\n                expected_nb_of_contents = 1\n                if self.is_set(\"code\"):\n                    expected_nb_of_contents += 1\n                    code = cast(int, self.code)\n                    enforce(\n                        type(code) is int,\n                        \"Invalid type for content 'code'. Expected 'int'. Found '{}'.\".format(\n                            type(code)\n                        ),\n                    )\n                if self.is_set(\"message\"):\n                    expected_nb_of_contents += 1\n                    message = cast(str, self.message)\n                    enforce(\n                        isinstance(message, str),\n                        \"Invalid type for content 'message'. Expected 'str'. Found '{}'.\".format(\n                            type(message)\n                        ),\n                    )\n                enforce(\n                    isinstance(self.data, bytes),\n                    \"Invalid type for content 'data'. Expected 'bytes'. Found '{}'.\".format(\n                        type(self.data)\n                    ),\n                )\n\n            # Check correct content count\n            enforce(\n                expected_nb_of_contents == actual_nb_of_contents,\n                \"Incorrect number of contents. Expected {}. Found {}\".format(\n                    expected_nb_of_contents, actual_nb_of_contents\n                ),\n            )\n\n            # Light Protocol Rule 3\n            if self.message_id == 1:\n                enforce(\n                    self.target == 0,\n                    \"Invalid 'target'. Expected 0 (because 'message_id' is 1). Found {}.\".format(\n                        self.target\n                    ),\n                )\n        except (AEAEnforceError, ValueError, KeyError) as e:\n            _default_logger.error(str(e))\n            return False\n\n        return True\n"
  },
  {
    "path": "packages/fetchai/protocols/contract_api/protocol.yaml",
    "content": "name: contract_api\nauthor: fetchai\nversion: 1.1.7\nprotocol_specification_id: fetchai/contract_api:1.0.0\ntype: protocol\ndescription: A protocol for contract APIs requests and responses.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: Qmbbumi4uwtWACodswSRbf6YZkXBgzhByLkY9ZTz846aKQ\n  __init__.py: QmSU7kcQHDrWyFvCZpLnN2qH5CE29JrWnpTBp9tiSrhCkB\n  contract_api.proto: QmXP6TkLcQcsFWE66Z7ffgNcW3p6xAB63GXh4UsnEbHd9D\n  contract_api_pb2.py: QmXqZFRTtRZeLytmmWKRxExKGua1Be3Ux5Eq1qLabsbe2Y\n  custom_types.py: QmXbRNjRpLvV4qhoGPHndQZfgTC5BMDoUDW8ZP9MrWKCG4\n  dialogues.py: QmXCtZ8beuCEXueFoJRHAEP7Y7UHfBhMCFSjtQWmCQGVzP\n  message.py: QmfQSKdcr5CcpPC9apArdoqgdKcAsFVNnTGBPs4dXLUWka\n  serialization.py: QmcVXMQWnw76k5iwMnvWnQfCgJBUoTXBpnGDFqnkNRyfhZ\nfingerprint_ignore_patterns: []\ndependencies:\n  protobuf: {}\n"
  },
  {
    "path": "packages/fetchai/protocols/contract_api/serialization.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Serialization module for contract_api protocol.\"\"\"\n\n# pylint: disable=too-many-statements,too-many-locals,no-member,too-few-public-methods,redefined-builtin\nfrom typing import Any, Dict, cast\n\nfrom aea.mail.base_pb2 import DialogueMessage\nfrom aea.mail.base_pb2 import Message as ProtobufMessage\nfrom aea.protocols.base import Message, Serializer\n\nfrom packages.fetchai.protocols.contract_api import contract_api_pb2\nfrom packages.fetchai.protocols.contract_api.custom_types import (\n    Kwargs,\n    RawMessage,\n    RawTransaction,\n    State,\n)\nfrom packages.fetchai.protocols.contract_api.message import ContractApiMessage\n\n\nclass ContractApiSerializer(Serializer):\n    \"\"\"Serialization for the 'contract_api' protocol.\"\"\"\n\n    @staticmethod\n    def encode(msg: Message) -> bytes:\n        \"\"\"\n        Encode a 'ContractApi' message into bytes.\n\n        :param msg: the message object.\n        :return: the bytes.\n        \"\"\"\n        msg = cast(ContractApiMessage, msg)\n        message_pb = ProtobufMessage()\n        dialogue_message_pb = DialogueMessage()\n        contract_api_msg = contract_api_pb2.ContractApiMessage()\n\n        dialogue_message_pb.message_id = msg.message_id\n        dialogue_reference = msg.dialogue_reference\n        dialogue_message_pb.dialogue_starter_reference = dialogue_reference[0]\n        dialogue_message_pb.dialogue_responder_reference = dialogue_reference[1]\n        dialogue_message_pb.target = msg.target\n\n        performative_id = msg.performative\n        if performative_id == ContractApiMessage.Performative.GET_DEPLOY_TRANSACTION:\n            performative = contract_api_pb2.ContractApiMessage.Get_Deploy_Transaction_Performative()  # type: ignore\n            ledger_id = msg.ledger_id\n            performative.ledger_id = ledger_id\n            contract_id = msg.contract_id\n            performative.contract_id = contract_id\n            callable = msg.callable\n            performative.callable = callable\n            kwargs = msg.kwargs\n            Kwargs.encode(performative.kwargs, kwargs)\n            contract_api_msg.get_deploy_transaction.CopyFrom(performative)\n        elif performative_id == ContractApiMessage.Performative.GET_RAW_TRANSACTION:\n            performative = contract_api_pb2.ContractApiMessage.Get_Raw_Transaction_Performative()  # type: ignore\n            ledger_id = msg.ledger_id\n            performative.ledger_id = ledger_id\n            contract_id = msg.contract_id\n            performative.contract_id = contract_id\n            contract_address = msg.contract_address\n            performative.contract_address = contract_address\n            callable = msg.callable\n            performative.callable = callable\n            kwargs = msg.kwargs\n            Kwargs.encode(performative.kwargs, kwargs)\n            contract_api_msg.get_raw_transaction.CopyFrom(performative)\n        elif performative_id == ContractApiMessage.Performative.GET_RAW_MESSAGE:\n            performative = contract_api_pb2.ContractApiMessage.Get_Raw_Message_Performative()  # type: ignore\n            ledger_id = msg.ledger_id\n            performative.ledger_id = ledger_id\n            contract_id = msg.contract_id\n            performative.contract_id = contract_id\n            contract_address = msg.contract_address\n            performative.contract_address = contract_address\n            callable = msg.callable\n            performative.callable = callable\n            kwargs = msg.kwargs\n            Kwargs.encode(performative.kwargs, kwargs)\n            contract_api_msg.get_raw_message.CopyFrom(performative)\n        elif performative_id == ContractApiMessage.Performative.GET_STATE:\n            performative = contract_api_pb2.ContractApiMessage.Get_State_Performative()  # type: ignore\n            ledger_id = msg.ledger_id\n            performative.ledger_id = ledger_id\n            contract_id = msg.contract_id\n            performative.contract_id = contract_id\n            contract_address = msg.contract_address\n            performative.contract_address = contract_address\n            callable = msg.callable\n            performative.callable = callable\n            kwargs = msg.kwargs\n            Kwargs.encode(performative.kwargs, kwargs)\n            contract_api_msg.get_state.CopyFrom(performative)\n        elif performative_id == ContractApiMessage.Performative.STATE:\n            performative = contract_api_pb2.ContractApiMessage.State_Performative()  # type: ignore\n            state = msg.state\n            State.encode(performative.state, state)\n            contract_api_msg.state.CopyFrom(performative)\n        elif performative_id == ContractApiMessage.Performative.RAW_TRANSACTION:\n            performative = contract_api_pb2.ContractApiMessage.Raw_Transaction_Performative()  # type: ignore\n            raw_transaction = msg.raw_transaction\n            RawTransaction.encode(performative.raw_transaction, raw_transaction)\n            contract_api_msg.raw_transaction.CopyFrom(performative)\n        elif performative_id == ContractApiMessage.Performative.RAW_MESSAGE:\n            performative = contract_api_pb2.ContractApiMessage.Raw_Message_Performative()  # type: ignore\n            raw_message = msg.raw_message\n            RawMessage.encode(performative.raw_message, raw_message)\n            contract_api_msg.raw_message.CopyFrom(performative)\n        elif performative_id == ContractApiMessage.Performative.ERROR:\n            performative = contract_api_pb2.ContractApiMessage.Error_Performative()  # type: ignore\n            if msg.is_set(\"code\"):\n                performative.code_is_set = True\n                code = msg.code\n                performative.code = code\n            if msg.is_set(\"message\"):\n                performative.message_is_set = True\n                message = msg.message\n                performative.message = message\n            data = msg.data\n            performative.data = data\n            contract_api_msg.error.CopyFrom(performative)\n        else:\n            raise ValueError(\"Performative not valid: {}\".format(performative_id))\n\n        dialogue_message_pb.content = contract_api_msg.SerializeToString()\n\n        message_pb.dialogue_message.CopyFrom(dialogue_message_pb)\n        message_bytes = message_pb.SerializeToString()\n        return message_bytes\n\n    @staticmethod\n    def decode(obj: bytes) -> Message:\n        \"\"\"\n        Decode bytes into a 'ContractApi' message.\n\n        :param obj: the bytes object.\n        :return: the 'ContractApi' message.\n        \"\"\"\n        message_pb = ProtobufMessage()\n        contract_api_pb = contract_api_pb2.ContractApiMessage()\n        message_pb.ParseFromString(obj)\n        message_id = message_pb.dialogue_message.message_id\n        dialogue_reference = (\n            message_pb.dialogue_message.dialogue_starter_reference,\n            message_pb.dialogue_message.dialogue_responder_reference,\n        )\n        target = message_pb.dialogue_message.target\n\n        contract_api_pb.ParseFromString(message_pb.dialogue_message.content)\n        performative = contract_api_pb.WhichOneof(\"performative\")\n        performative_id = ContractApiMessage.Performative(str(performative))\n        performative_content = {}  # type: Dict[str, Any]\n        if performative_id == ContractApiMessage.Performative.GET_DEPLOY_TRANSACTION:\n            ledger_id = contract_api_pb.get_deploy_transaction.ledger_id\n            performative_content[\"ledger_id\"] = ledger_id\n            contract_id = contract_api_pb.get_deploy_transaction.contract_id\n            performative_content[\"contract_id\"] = contract_id\n            callable = contract_api_pb.get_deploy_transaction.callable\n            performative_content[\"callable\"] = callable\n            pb2_kwargs = contract_api_pb.get_deploy_transaction.kwargs\n            kwargs = Kwargs.decode(pb2_kwargs)\n            performative_content[\"kwargs\"] = kwargs\n        elif performative_id == ContractApiMessage.Performative.GET_RAW_TRANSACTION:\n            ledger_id = contract_api_pb.get_raw_transaction.ledger_id\n            performative_content[\"ledger_id\"] = ledger_id\n            contract_id = contract_api_pb.get_raw_transaction.contract_id\n            performative_content[\"contract_id\"] = contract_id\n            contract_address = contract_api_pb.get_raw_transaction.contract_address\n            performative_content[\"contract_address\"] = contract_address\n            callable = contract_api_pb.get_raw_transaction.callable\n            performative_content[\"callable\"] = callable\n            pb2_kwargs = contract_api_pb.get_raw_transaction.kwargs\n            kwargs = Kwargs.decode(pb2_kwargs)\n            performative_content[\"kwargs\"] = kwargs\n        elif performative_id == ContractApiMessage.Performative.GET_RAW_MESSAGE:\n            ledger_id = contract_api_pb.get_raw_message.ledger_id\n            performative_content[\"ledger_id\"] = ledger_id\n            contract_id = contract_api_pb.get_raw_message.contract_id\n            performative_content[\"contract_id\"] = contract_id\n            contract_address = contract_api_pb.get_raw_message.contract_address\n            performative_content[\"contract_address\"] = contract_address\n            callable = contract_api_pb.get_raw_message.callable\n            performative_content[\"callable\"] = callable\n            pb2_kwargs = contract_api_pb.get_raw_message.kwargs\n            kwargs = Kwargs.decode(pb2_kwargs)\n            performative_content[\"kwargs\"] = kwargs\n        elif performative_id == ContractApiMessage.Performative.GET_STATE:\n            ledger_id = contract_api_pb.get_state.ledger_id\n            performative_content[\"ledger_id\"] = ledger_id\n            contract_id = contract_api_pb.get_state.contract_id\n            performative_content[\"contract_id\"] = contract_id\n            contract_address = contract_api_pb.get_state.contract_address\n            performative_content[\"contract_address\"] = contract_address\n            callable = contract_api_pb.get_state.callable\n            performative_content[\"callable\"] = callable\n            pb2_kwargs = contract_api_pb.get_state.kwargs\n            kwargs = Kwargs.decode(pb2_kwargs)\n            performative_content[\"kwargs\"] = kwargs\n        elif performative_id == ContractApiMessage.Performative.STATE:\n            pb2_state = contract_api_pb.state.state\n            state = State.decode(pb2_state)\n            performative_content[\"state\"] = state\n        elif performative_id == ContractApiMessage.Performative.RAW_TRANSACTION:\n            pb2_raw_transaction = contract_api_pb.raw_transaction.raw_transaction\n            raw_transaction = RawTransaction.decode(pb2_raw_transaction)\n            performative_content[\"raw_transaction\"] = raw_transaction\n        elif performative_id == ContractApiMessage.Performative.RAW_MESSAGE:\n            pb2_raw_message = contract_api_pb.raw_message.raw_message\n            raw_message = RawMessage.decode(pb2_raw_message)\n            performative_content[\"raw_message\"] = raw_message\n        elif performative_id == ContractApiMessage.Performative.ERROR:\n            if contract_api_pb.error.code_is_set:\n                code = contract_api_pb.error.code\n                performative_content[\"code\"] = code\n            if contract_api_pb.error.message_is_set:\n                message = contract_api_pb.error.message\n                performative_content[\"message\"] = message\n            data = contract_api_pb.error.data\n            performative_content[\"data\"] = data\n        else:\n            raise ValueError(\"Performative not valid: {}.\".format(performative_id))\n\n        return ContractApiMessage(\n            message_id=message_id,\n            dialogue_reference=dialogue_reference,\n            target=target,\n            performative=performative,\n            **performative_content\n        )\n"
  },
  {
    "path": "packages/fetchai/protocols/cosm_trade/README.md",
    "content": "# Ledger API Protocol\n\n## Description\n\nThis is a protocol for preparing an atomic swap bilateral transaction for cosmos-based ledgers, including fetchai's.\nFor two parties A and B to atomically swap tokens on cosmos-based networks, A has to send its public key to B.\nThen B constructs the transaction using both his public key and A's, signs the transaction, adds its signature to the list of signatures in the transaction and sends this to A. After receiving, A signs the transaction, adds its signature to the list of signatures in the transaction and broadcasts it to the network for processing.\n\n## Specification\n\n```yaml\n---\nname: cosm_trade\nauthor: fetchai\nversion: 0.2.7\ndescription: A protocol for preparing an atomic swap bilateral transaction for cosmos-based ledgers, including fetchai's.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nprotocol_specification_id: fetchai/cosm_trade:1.0.0\nspeech_acts:\n  inform_public_key:\n    public_key: pt:str\n  inform_signed_transaction:\n    signed_transaction: ct:SignedTransaction\n    fipa_dialogue_id: pt:optional[pt:list[pt:str]]\n  error:\n    code: pt:int\n    message: pt:optional[pt:str]\n    data: pt:optional[pt:bytes]\n  end: {}\n...\n---\nct:SignedTransaction: |\n  bytes signed_transaction = 1;\n...\n---\ninitiation: [inform_public_key, inform_signed_transaction]\nreply:\n  inform_public_key: [inform_signed_transaction, error]\n  inform_signed_transaction: [error, end]\n  error: []\n  end: []\ntermination: [error, end]\nroles: {agent}\nend_states: [successful, failed]\nkeep_terminal_state_dialogues: false\n...\n```\n\n## Links\n"
  },
  {
    "path": "packages/fetchai/protocols/cosm_trade/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nThis module contains the support resources for the cosm_trade protocol.\n\nIt was created with protocol buffer compiler version `libprotoc 3.19.4` and aea version `1.2.5`.\n\"\"\"\n\nfrom packages.fetchai.protocols.cosm_trade.message import CosmTradeMessage\nfrom packages.fetchai.protocols.cosm_trade.serialization import CosmTradeSerializer\n\n\nCosmTradeMessage.serializer = CosmTradeSerializer\n"
  },
  {
    "path": "packages/fetchai/protocols/cosm_trade/cosm_trade.proto",
    "content": "syntax = \"proto3\";\n\npackage aea.fetchai.cosm_trade.v1_0_0;\n\nmessage CosmTradeMessage{\n\n  // Custom Types\n  message SignedTransaction{\n    bytes signed_transaction = 1;\n  }\n\n\n  // Performatives and contents\n  message Inform_Public_Key_Performative{\n    string public_key = 1;\n  }\n\n  message Inform_Signed_Transaction_Performative{\n    SignedTransaction signed_transaction = 1;\n    repeated string fipa_dialogue_id = 2;\n    bool fipa_dialogue_id_is_set = 3;\n  }\n\n  message Error_Performative{\n    int64 code = 1;\n    string message = 2;\n    bool message_is_set = 3;\n    bytes data = 4;\n    bool data_is_set = 5;\n  }\n\n  message End_Performative{\n  }\n\n\n  oneof performative{\n    End_Performative end = 5;\n    Error_Performative error = 6;\n    Inform_Public_Key_Performative inform_public_key = 7;\n    Inform_Signed_Transaction_Performative inform_signed_transaction = 8;\n  }\n}\n"
  },
  {
    "path": "packages/fetchai/protocols/cosm_trade/cosm_trade_pb2.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by the protocol buffer compiler.  DO NOT EDIT!\n# source: cosm_trade.proto\n\"\"\"Generated protocol buffer code.\"\"\"\nfrom google.protobuf import descriptor as _descriptor\nfrom google.protobuf import descriptor_pool as _descriptor_pool\nfrom google.protobuf import message as _message\nfrom google.protobuf import reflection as _reflection\nfrom google.protobuf import symbol_database as _symbol_database\n\n# @@protoc_insertion_point(imports)\n\n_sym_db = _symbol_database.Default()\n\n\nDESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(\n    b'\\n\\x10\\x63osm_trade.proto\\x12\\x1d\\x61\\x65\\x61.fetchai.cosm_trade.v1_0_0\"\\xe2\\x06\\n\\x10\\x43osmTradeMessage\\x12O\\n\\x03\\x65nd\\x18\\x05 \\x01(\\x0b\\x32@.aea.fetchai.cosm_trade.v1_0_0.CosmTradeMessage.End_PerformativeH\\x00\\x12S\\n\\x05\\x65rror\\x18\\x06 \\x01(\\x0b\\x32\\x42.aea.fetchai.cosm_trade.v1_0_0.CosmTradeMessage.Error_PerformativeH\\x00\\x12k\\n\\x11inform_public_key\\x18\\x07 \\x01(\\x0b\\x32N.aea.fetchai.cosm_trade.v1_0_0.CosmTradeMessage.Inform_Public_Key_PerformativeH\\x00\\x12{\\n\\x19inform_signed_transaction\\x18\\x08 \\x01(\\x0b\\x32V.aea.fetchai.cosm_trade.v1_0_0.CosmTradeMessage.Inform_Signed_Transaction_PerformativeH\\x00\\x1a/\\n\\x11SignedTransaction\\x12\\x1a\\n\\x12signed_transaction\\x18\\x01 \\x01(\\x0c\\x1a\\x34\\n\\x1eInform_Public_Key_Performative\\x12\\x12\\n\\npublic_key\\x18\\x01 \\x01(\\t\\x1a\\xc2\\x01\\n&Inform_Signed_Transaction_Performative\\x12]\\n\\x12signed_transaction\\x18\\x01 \\x01(\\x0b\\x32\\x41.aea.fetchai.cosm_trade.v1_0_0.CosmTradeMessage.SignedTransaction\\x12\\x18\\n\\x10\\x66ipa_dialogue_id\\x18\\x02 \\x03(\\t\\x12\\x1f\\n\\x17\\x66ipa_dialogue_id_is_set\\x18\\x03 \\x01(\\x08\\x1an\\n\\x12\\x45rror_Performative\\x12\\x0c\\n\\x04\\x63ode\\x18\\x01 \\x01(\\x03\\x12\\x0f\\n\\x07message\\x18\\x02 \\x01(\\t\\x12\\x16\\n\\x0emessage_is_set\\x18\\x03 \\x01(\\x08\\x12\\x0c\\n\\x04\\x64\\x61ta\\x18\\x04 \\x01(\\x0c\\x12\\x13\\n\\x0b\\x64\\x61ta_is_set\\x18\\x05 \\x01(\\x08\\x1a\\x12\\n\\x10\\x45nd_PerformativeB\\x0e\\n\\x0cperformativeb\\x06proto3'\n)\n\n\n_COSMTRADEMESSAGE = DESCRIPTOR.message_types_by_name[\"CosmTradeMessage\"]\n_COSMTRADEMESSAGE_SIGNEDTRANSACTION = _COSMTRADEMESSAGE.nested_types_by_name[\n    \"SignedTransaction\"\n]\n_COSMTRADEMESSAGE_INFORM_PUBLIC_KEY_PERFORMATIVE = (\n    _COSMTRADEMESSAGE.nested_types_by_name[\"Inform_Public_Key_Performative\"]\n)\n_COSMTRADEMESSAGE_INFORM_SIGNED_TRANSACTION_PERFORMATIVE = (\n    _COSMTRADEMESSAGE.nested_types_by_name[\"Inform_Signed_Transaction_Performative\"]\n)\n_COSMTRADEMESSAGE_ERROR_PERFORMATIVE = _COSMTRADEMESSAGE.nested_types_by_name[\n    \"Error_Performative\"\n]\n_COSMTRADEMESSAGE_END_PERFORMATIVE = _COSMTRADEMESSAGE.nested_types_by_name[\n    \"End_Performative\"\n]\nCosmTradeMessage = _reflection.GeneratedProtocolMessageType(\n    \"CosmTradeMessage\",\n    (_message.Message,),\n    {\n        \"SignedTransaction\": _reflection.GeneratedProtocolMessageType(\n            \"SignedTransaction\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _COSMTRADEMESSAGE_SIGNEDTRANSACTION,\n                \"__module__\": \"cosm_trade_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.cosm_trade.v1_0_0.CosmTradeMessage.SignedTransaction)\n            },\n        ),\n        \"Inform_Public_Key_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Inform_Public_Key_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _COSMTRADEMESSAGE_INFORM_PUBLIC_KEY_PERFORMATIVE,\n                \"__module__\": \"cosm_trade_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.cosm_trade.v1_0_0.CosmTradeMessage.Inform_Public_Key_Performative)\n            },\n        ),\n        \"Inform_Signed_Transaction_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Inform_Signed_Transaction_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _COSMTRADEMESSAGE_INFORM_SIGNED_TRANSACTION_PERFORMATIVE,\n                \"__module__\": \"cosm_trade_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.cosm_trade.v1_0_0.CosmTradeMessage.Inform_Signed_Transaction_Performative)\n            },\n        ),\n        \"Error_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Error_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _COSMTRADEMESSAGE_ERROR_PERFORMATIVE,\n                \"__module__\": \"cosm_trade_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.cosm_trade.v1_0_0.CosmTradeMessage.Error_Performative)\n            },\n        ),\n        \"End_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"End_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _COSMTRADEMESSAGE_END_PERFORMATIVE,\n                \"__module__\": \"cosm_trade_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.cosm_trade.v1_0_0.CosmTradeMessage.End_Performative)\n            },\n        ),\n        \"DESCRIPTOR\": _COSMTRADEMESSAGE,\n        \"__module__\": \"cosm_trade_pb2\"\n        # @@protoc_insertion_point(class_scope:aea.fetchai.cosm_trade.v1_0_0.CosmTradeMessage)\n    },\n)\n_sym_db.RegisterMessage(CosmTradeMessage)\n_sym_db.RegisterMessage(CosmTradeMessage.SignedTransaction)\n_sym_db.RegisterMessage(CosmTradeMessage.Inform_Public_Key_Performative)\n_sym_db.RegisterMessage(CosmTradeMessage.Inform_Signed_Transaction_Performative)\n_sym_db.RegisterMessage(CosmTradeMessage.Error_Performative)\n_sym_db.RegisterMessage(CosmTradeMessage.End_Performative)\n\nif _descriptor._USE_C_DESCRIPTORS == False:\n\n    DESCRIPTOR._options = None\n    _COSMTRADEMESSAGE._serialized_start = 52\n    _COSMTRADEMESSAGE._serialized_end = 918\n    _COSMTRADEMESSAGE_SIGNEDTRANSACTION._serialized_start = 472\n    _COSMTRADEMESSAGE_SIGNEDTRANSACTION._serialized_end = 519\n    _COSMTRADEMESSAGE_INFORM_PUBLIC_KEY_PERFORMATIVE._serialized_start = 521\n    _COSMTRADEMESSAGE_INFORM_PUBLIC_KEY_PERFORMATIVE._serialized_end = 573\n    _COSMTRADEMESSAGE_INFORM_SIGNED_TRANSACTION_PERFORMATIVE._serialized_start = 576\n    _COSMTRADEMESSAGE_INFORM_SIGNED_TRANSACTION_PERFORMATIVE._serialized_end = 770\n    _COSMTRADEMESSAGE_ERROR_PERFORMATIVE._serialized_start = 772\n    _COSMTRADEMESSAGE_ERROR_PERFORMATIVE._serialized_end = 882\n    _COSMTRADEMESSAGE_END_PERFORMATIVE._serialized_start = 884\n    _COSMTRADEMESSAGE_END_PERFORMATIVE._serialized_end = 902\n# @@protoc_insertion_point(module_scope)\n"
  },
  {
    "path": "packages/fetchai/protocols/cosm_trade/custom_types.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains class representations corresponding to every custom type in the protocol specification.\"\"\"\n\nfrom aea.helpers.transaction.base import SignedTransaction as BaseSignedTransaction\n\n\nSignedTransaction = BaseSignedTransaction\n"
  },
  {
    "path": "packages/fetchai/protocols/cosm_trade/dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nThis module contains the classes required for cosm_trade dialogue management.\n\n- CosmTradeDialogue: The dialogue class maintains state of a dialogue and manages it.\n- CosmTradeDialogues: The dialogues class keeps track of all dialogues.\n\"\"\"\n\nfrom abc import ABC\nfrom typing import Callable, Dict, FrozenSet, Type, cast\n\nfrom aea.common import Address\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue, DialogueLabel, Dialogues\n\nfrom packages.fetchai.protocols.cosm_trade.message import CosmTradeMessage\n\n\nclass CosmTradeDialogue(Dialogue):\n    \"\"\"The cosm_trade dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    INITIAL_PERFORMATIVES: FrozenSet[Message.Performative] = frozenset(\n        {\n            CosmTradeMessage.Performative.INFORM_PUBLIC_KEY,\n            CosmTradeMessage.Performative.INFORM_SIGNED_TRANSACTION,\n        }\n    )\n    TERMINAL_PERFORMATIVES: FrozenSet[Message.Performative] = frozenset(\n        {CosmTradeMessage.Performative.ERROR, CosmTradeMessage.Performative.END}\n    )\n    VALID_REPLIES: Dict[Message.Performative, FrozenSet[Message.Performative]] = {\n        CosmTradeMessage.Performative.END: frozenset(),\n        CosmTradeMessage.Performative.ERROR: frozenset(),\n        CosmTradeMessage.Performative.INFORM_PUBLIC_KEY: frozenset(\n            {\n                CosmTradeMessage.Performative.INFORM_SIGNED_TRANSACTION,\n                CosmTradeMessage.Performative.ERROR,\n            }\n        ),\n        CosmTradeMessage.Performative.INFORM_SIGNED_TRANSACTION: frozenset(\n            {CosmTradeMessage.Performative.ERROR, CosmTradeMessage.Performative.END}\n        ),\n    }\n\n    class Role(Dialogue.Role):\n        \"\"\"This class defines the agent's role in a cosm_trade dialogue.\"\"\"\n\n        AGENT = \"agent\"\n\n    class EndState(Dialogue.EndState):\n        \"\"\"This class defines the end states of a cosm_trade dialogue.\"\"\"\n\n        SUCCESSFUL = 0\n        FAILED = 1\n\n    def __init__(\n        self,\n        dialogue_label: DialogueLabel,\n        self_address: Address,\n        role: Dialogue.Role,\n        message_class: Type[CosmTradeMessage] = CosmTradeMessage,\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n        :param message_class: the message class used\n        \"\"\"\n        Dialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            message_class=message_class,\n            self_address=self_address,\n            role=role,\n        )\n\n\nclass CosmTradeDialogues(Dialogues, ABC):\n    \"\"\"This class keeps track of all cosm_trade dialogues.\"\"\"\n\n    END_STATES = frozenset(\n        {CosmTradeDialogue.EndState.SUCCESSFUL, CosmTradeDialogue.EndState.FAILED}\n    )\n\n    _keep_terminal_state_dialogues = False\n\n    def __init__(\n        self,\n        self_address: Address,\n        role_from_first_message: Callable[[Message, Address], Dialogue.Role],\n        dialogue_class: Type[CosmTradeDialogue] = CosmTradeDialogue,\n    ) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param self_address: the address of the entity for whom dialogues are maintained\n        :param dialogue_class: the dialogue class used\n        :param role_from_first_message: the callable determining role from first message\n        \"\"\"\n        Dialogues.__init__(\n            self,\n            self_address=self_address,\n            end_states=cast(FrozenSet[Dialogue.EndState], self.END_STATES),\n            message_class=CosmTradeMessage,\n            dialogue_class=dialogue_class,\n            role_from_first_message=role_from_first_message,\n        )\n"
  },
  {
    "path": "packages/fetchai/protocols/cosm_trade/message.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains cosm_trade's message definition.\"\"\"\n\n# pylint: disable=too-many-statements,too-many-locals,no-member,too-few-public-methods,too-many-branches,not-an-iterable,unidiomatic-typecheck,unsubscriptable-object\nimport logging\nfrom typing import Any, Optional, Set, Tuple, cast\n\nfrom aea.configurations.base import PublicId\nfrom aea.exceptions import AEAEnforceError, enforce\nfrom aea.protocols.base import Message\n\nfrom packages.fetchai.protocols.cosm_trade.custom_types import (\n    SignedTransaction as CustomSignedTransaction,\n)\n\n\n_default_logger = logging.getLogger(\"aea.packages.fetchai.protocols.cosm_trade.message\")\n\nDEFAULT_BODY_SIZE = 4\n\n\nclass CosmTradeMessage(Message):\n    \"\"\"A protocol for preparing an atomic swap bilateral transaction for cosmos-based ledgers, including fetchai's.\"\"\"\n\n    protocol_id = PublicId.from_str(\"fetchai/cosm_trade:0.2.7\")\n    protocol_specification_id = PublicId.from_str(\"fetchai/cosm_trade:1.0.0\")\n\n    SignedTransaction = CustomSignedTransaction\n\n    class Performative(Message.Performative):\n        \"\"\"Performatives for the cosm_trade protocol.\"\"\"\n\n        END = \"end\"\n        ERROR = \"error\"\n        INFORM_PUBLIC_KEY = \"inform_public_key\"\n        INFORM_SIGNED_TRANSACTION = \"inform_signed_transaction\"\n\n        def __str__(self) -> str:\n            \"\"\"Get the string representation.\"\"\"\n            return str(self.value)\n\n    _performatives = {\"end\", \"error\", \"inform_public_key\", \"inform_signed_transaction\"}\n    __slots__: Tuple[str, ...] = tuple()\n\n    class _SlotsCls:\n        __slots__ = (\n            \"code\",\n            \"data\",\n            \"dialogue_reference\",\n            \"fipa_dialogue_id\",\n            \"message\",\n            \"message_id\",\n            \"performative\",\n            \"public_key\",\n            \"signed_transaction\",\n            \"target\",\n        )\n\n    def __init__(\n        self,\n        performative: Performative,\n        dialogue_reference: Tuple[str, str] = (\"\", \"\"),\n        message_id: int = 1,\n        target: int = 0,\n        **kwargs: Any,\n    ):\n        \"\"\"\n        Initialise an instance of CosmTradeMessage.\n\n        :param message_id: the message id.\n        :param dialogue_reference: the dialogue reference.\n        :param target: the message target.\n        :param performative: the message performative.\n        :param **kwargs: extra options.\n        \"\"\"\n        super().__init__(\n            dialogue_reference=dialogue_reference,\n            message_id=message_id,\n            target=target,\n            performative=CosmTradeMessage.Performative(performative),\n            **kwargs,\n        )\n\n    @property\n    def valid_performatives(self) -> Set[str]:\n        \"\"\"Get valid performatives.\"\"\"\n        return self._performatives\n\n    @property\n    def dialogue_reference(self) -> Tuple[str, str]:\n        \"\"\"Get the dialogue_reference of the message.\"\"\"\n        enforce(self.is_set(\"dialogue_reference\"), \"dialogue_reference is not set.\")\n        return cast(Tuple[str, str], self.get(\"dialogue_reference\"))\n\n    @property\n    def message_id(self) -> int:\n        \"\"\"Get the message_id of the message.\"\"\"\n        enforce(self.is_set(\"message_id\"), \"message_id is not set.\")\n        return cast(int, self.get(\"message_id\"))\n\n    @property\n    def performative(self) -> Performative:  # type: ignore # noqa: F821\n        \"\"\"Get the performative of the message.\"\"\"\n        enforce(self.is_set(\"performative\"), \"performative is not set.\")\n        return cast(CosmTradeMessage.Performative, self.get(\"performative\"))\n\n    @property\n    def target(self) -> int:\n        \"\"\"Get the target of the message.\"\"\"\n        enforce(self.is_set(\"target\"), \"target is not set.\")\n        return cast(int, self.get(\"target\"))\n\n    @property\n    def code(self) -> int:\n        \"\"\"Get the 'code' content from the message.\"\"\"\n        enforce(self.is_set(\"code\"), \"'code' content is not set.\")\n        return cast(int, self.get(\"code\"))\n\n    @property\n    def data(self) -> Optional[bytes]:\n        \"\"\"Get the 'data' content from the message.\"\"\"\n        return cast(Optional[bytes], self.get(\"data\"))\n\n    @property\n    def fipa_dialogue_id(self) -> Optional[Tuple[str, ...]]:\n        \"\"\"Get the 'fipa_dialogue_id' content from the message.\"\"\"\n        return cast(Optional[Tuple[str, ...]], self.get(\"fipa_dialogue_id\"))\n\n    @property\n    def message(self) -> Optional[str]:\n        \"\"\"Get the 'message' content from the message.\"\"\"\n        return cast(Optional[str], self.get(\"message\"))\n\n    @property\n    def public_key(self) -> str:\n        \"\"\"Get the 'public_key' content from the message.\"\"\"\n        enforce(self.is_set(\"public_key\"), \"'public_key' content is not set.\")\n        return cast(str, self.get(\"public_key\"))\n\n    @property\n    def signed_transaction(self) -> CustomSignedTransaction:\n        \"\"\"Get the 'signed_transaction' content from the message.\"\"\"\n        enforce(\n            self.is_set(\"signed_transaction\"),\n            \"'signed_transaction' content is not set.\",\n        )\n        return cast(CustomSignedTransaction, self.get(\"signed_transaction\"))\n\n    def _is_consistent(self) -> bool:\n        \"\"\"Check that the message follows the cosm_trade protocol.\"\"\"\n        try:\n            enforce(\n                isinstance(self.dialogue_reference, tuple),\n                \"Invalid type for 'dialogue_reference'. Expected 'tuple'. Found '{}'.\".format(\n                    type(self.dialogue_reference)\n                ),\n            )\n            enforce(\n                isinstance(self.dialogue_reference[0], str),\n                \"Invalid type for 'dialogue_reference[0]'. Expected 'str'. Found '{}'.\".format(\n                    type(self.dialogue_reference[0])\n                ),\n            )\n            enforce(\n                isinstance(self.dialogue_reference[1], str),\n                \"Invalid type for 'dialogue_reference[1]'. Expected 'str'. Found '{}'.\".format(\n                    type(self.dialogue_reference[1])\n                ),\n            )\n            enforce(\n                type(self.message_id) is int,\n                \"Invalid type for 'message_id'. Expected 'int'. Found '{}'.\".format(\n                    type(self.message_id)\n                ),\n            )\n            enforce(\n                type(self.target) is int,\n                \"Invalid type for 'target'. Expected 'int'. Found '{}'.\".format(\n                    type(self.target)\n                ),\n            )\n\n            # Light Protocol Rule 2\n            # Check correct performative\n            enforce(\n                isinstance(self.performative, CosmTradeMessage.Performative),\n                \"Invalid 'performative'. Expected either of '{}'. Found '{}'.\".format(\n                    self.valid_performatives, self.performative\n                ),\n            )\n\n            # Check correct contents\n            actual_nb_of_contents = len(self._body) - DEFAULT_BODY_SIZE\n            expected_nb_of_contents = 0\n            if self.performative == CosmTradeMessage.Performative.INFORM_PUBLIC_KEY:\n                expected_nb_of_contents = 1\n                enforce(\n                    isinstance(self.public_key, str),\n                    \"Invalid type for content 'public_key'. Expected 'str'. Found '{}'.\".format(\n                        type(self.public_key)\n                    ),\n                )\n            elif (\n                self.performative\n                == CosmTradeMessage.Performative.INFORM_SIGNED_TRANSACTION\n            ):\n                expected_nb_of_contents = 1\n                enforce(\n                    isinstance(self.signed_transaction, CustomSignedTransaction),\n                    \"Invalid type for content 'signed_transaction'. Expected 'SignedTransaction'. Found '{}'.\".format(\n                        type(self.signed_transaction)\n                    ),\n                )\n                if self.is_set(\"fipa_dialogue_id\"):\n                    expected_nb_of_contents += 1\n                    fipa_dialogue_id = cast(Tuple[str, ...], self.fipa_dialogue_id)\n                    enforce(\n                        isinstance(fipa_dialogue_id, tuple),\n                        \"Invalid type for content 'fipa_dialogue_id'. Expected 'tuple'. Found '{}'.\".format(\n                            type(fipa_dialogue_id)\n                        ),\n                    )\n                    enforce(\n                        all(isinstance(element, str) for element in fipa_dialogue_id),\n                        \"Invalid type for tuple elements in content 'fipa_dialogue_id'. Expected 'str'.\",\n                    )\n            elif self.performative == CosmTradeMessage.Performative.ERROR:\n                expected_nb_of_contents = 1\n                enforce(\n                    type(self.code) is int,\n                    \"Invalid type for content 'code'. Expected 'int'. Found '{}'.\".format(\n                        type(self.code)\n                    ),\n                )\n                if self.is_set(\"message\"):\n                    expected_nb_of_contents += 1\n                    message = cast(str, self.message)\n                    enforce(\n                        isinstance(message, str),\n                        \"Invalid type for content 'message'. Expected 'str'. Found '{}'.\".format(\n                            type(message)\n                        ),\n                    )\n                if self.is_set(\"data\"):\n                    expected_nb_of_contents += 1\n                    data = cast(bytes, self.data)\n                    enforce(\n                        isinstance(data, bytes),\n                        \"Invalid type for content 'data'. Expected 'bytes'. Found '{}'.\".format(\n                            type(data)\n                        ),\n                    )\n            elif self.performative == CosmTradeMessage.Performative.END:\n                expected_nb_of_contents = 0\n\n            # Check correct content count\n            enforce(\n                expected_nb_of_contents == actual_nb_of_contents,\n                \"Incorrect number of contents. Expected {}. Found {}\".format(\n                    expected_nb_of_contents, actual_nb_of_contents\n                ),\n            )\n\n            # Light Protocol Rule 3\n            if self.message_id == 1:\n                enforce(\n                    self.target == 0,\n                    \"Invalid 'target'. Expected 0 (because 'message_id' is 1). Found {}.\".format(\n                        self.target\n                    ),\n                )\n        except (AEAEnforceError, ValueError, KeyError) as e:\n            _default_logger.error(str(e))\n            return False\n\n        return True\n"
  },
  {
    "path": "packages/fetchai/protocols/cosm_trade/protocol.yaml",
    "content": "name: cosm_trade\nauthor: fetchai\nversion: 0.2.7\nprotocol_specification_id: fetchai/cosm_trade:1.0.0\ntype: protocol\ndescription: A protocol for preparing an atomic swap bilateral transaction for cosmos-based\n  ledgers, including fetchai's.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: QmU2AsQPL4v5qPsPxh17pbNQCFV5qgqbXbsUe5kMJPCyum\n  __init__.py: QmcBn4zeHdnsdkMKwbiWaKpPKELmzKSrv4aFPPSp3EgUqb\n  cosm_trade.proto: QmWJZbNWJD8Qz1A1ju89wWoxFjMhC7RHn1pkeVPW3s3CPT\n  cosm_trade_pb2.py: Qma3GnRA8g9t6RADbYyagW747CcDmuNUEqahpjHvsroTTx\n  custom_types.py: QmZPHKmNPKwPGQu6cswi7MsfWGUHm8YG1XWowtnxVBstXS\n  dialogues.py: QmThJHxUPEeiaVqNJz3QgNvJXAVxwxppM5VHK8TSEuPdxk\n  message.py: QmdbUwDBj5v6DkcvjtHgHz6HPHjZndDTEQH12RwL4eQCR6\n  serialization.py: QmT2faXciRfykDBg3kXUvma2wjNgjHZ37nDfxiGD6mMtrB\nfingerprint_ignore_patterns: []\ndependencies:\n  protobuf: {}\n"
  },
  {
    "path": "packages/fetchai/protocols/cosm_trade/serialization.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Serialization module for cosm_trade protocol.\"\"\"\n\n# pylint: disable=too-many-statements,too-many-locals,no-member,too-few-public-methods,redefined-builtin\nfrom typing import Any, Dict, cast\n\nfrom aea.mail.base_pb2 import DialogueMessage\nfrom aea.mail.base_pb2 import Message as ProtobufMessage\nfrom aea.protocols.base import Message, Serializer\n\nfrom packages.fetchai.protocols.cosm_trade import cosm_trade_pb2\nfrom packages.fetchai.protocols.cosm_trade.custom_types import SignedTransaction\nfrom packages.fetchai.protocols.cosm_trade.message import CosmTradeMessage\n\n\nclass CosmTradeSerializer(Serializer):\n    \"\"\"Serialization for the 'cosm_trade' protocol.\"\"\"\n\n    @staticmethod\n    def encode(msg: Message) -> bytes:\n        \"\"\"\n        Encode a 'CosmTrade' message into bytes.\n\n        :param msg: the message object.\n        :return: the bytes.\n        \"\"\"\n        msg = cast(CosmTradeMessage, msg)\n        message_pb = ProtobufMessage()\n        dialogue_message_pb = DialogueMessage()\n        cosm_trade_msg = cosm_trade_pb2.CosmTradeMessage()\n\n        dialogue_message_pb.message_id = msg.message_id\n        dialogue_reference = msg.dialogue_reference\n        dialogue_message_pb.dialogue_starter_reference = dialogue_reference[0]\n        dialogue_message_pb.dialogue_responder_reference = dialogue_reference[1]\n        dialogue_message_pb.target = msg.target\n\n        performative_id = msg.performative\n        if performative_id == CosmTradeMessage.Performative.INFORM_PUBLIC_KEY:\n            performative = cosm_trade_pb2.CosmTradeMessage.Inform_Public_Key_Performative()  # type: ignore\n            public_key = msg.public_key\n            performative.public_key = public_key\n            cosm_trade_msg.inform_public_key.CopyFrom(performative)\n        elif performative_id == CosmTradeMessage.Performative.INFORM_SIGNED_TRANSACTION:\n            performative = cosm_trade_pb2.CosmTradeMessage.Inform_Signed_Transaction_Performative()  # type: ignore\n            signed_transaction = msg.signed_transaction\n            SignedTransaction.encode(\n                performative.signed_transaction, signed_transaction\n            )\n            if msg.is_set(\"fipa_dialogue_id\"):\n                performative.fipa_dialogue_id_is_set = True\n                fipa_dialogue_id = msg.fipa_dialogue_id\n                performative.fipa_dialogue_id.extend(fipa_dialogue_id)\n            cosm_trade_msg.inform_signed_transaction.CopyFrom(performative)\n        elif performative_id == CosmTradeMessage.Performative.ERROR:\n            performative = cosm_trade_pb2.CosmTradeMessage.Error_Performative()  # type: ignore\n            code = msg.code\n            performative.code = code\n            if msg.is_set(\"message\"):\n                performative.message_is_set = True\n                message = msg.message\n                performative.message = message\n            if msg.is_set(\"data\"):\n                performative.data_is_set = True\n                data = msg.data\n                performative.data = data\n            cosm_trade_msg.error.CopyFrom(performative)\n        elif performative_id == CosmTradeMessage.Performative.END:\n            performative = cosm_trade_pb2.CosmTradeMessage.End_Performative()  # type: ignore\n            cosm_trade_msg.end.CopyFrom(performative)\n        else:\n            raise ValueError(\"Performative not valid: {}\".format(performative_id))\n\n        dialogue_message_pb.content = cosm_trade_msg.SerializeToString()\n\n        message_pb.dialogue_message.CopyFrom(dialogue_message_pb)\n        message_bytes = message_pb.SerializeToString()\n        return message_bytes\n\n    @staticmethod\n    def decode(obj: bytes) -> Message:\n        \"\"\"\n        Decode bytes into a 'CosmTrade' message.\n\n        :param obj: the bytes object.\n        :return: the 'CosmTrade' message.\n        \"\"\"\n        message_pb = ProtobufMessage()\n        cosm_trade_pb = cosm_trade_pb2.CosmTradeMessage()\n        message_pb.ParseFromString(obj)\n        message_id = message_pb.dialogue_message.message_id\n        dialogue_reference = (\n            message_pb.dialogue_message.dialogue_starter_reference,\n            message_pb.dialogue_message.dialogue_responder_reference,\n        )\n        target = message_pb.dialogue_message.target\n\n        cosm_trade_pb.ParseFromString(message_pb.dialogue_message.content)\n        performative = cosm_trade_pb.WhichOneof(\"performative\")\n        performative_id = CosmTradeMessage.Performative(str(performative))\n        performative_content = {}  # type: Dict[str, Any]\n        if performative_id == CosmTradeMessage.Performative.INFORM_PUBLIC_KEY:\n            public_key = cosm_trade_pb.inform_public_key.public_key\n            performative_content[\"public_key\"] = public_key\n        elif performative_id == CosmTradeMessage.Performative.INFORM_SIGNED_TRANSACTION:\n            pb2_signed_transaction = (\n                cosm_trade_pb.inform_signed_transaction.signed_transaction\n            )\n            signed_transaction = SignedTransaction.decode(pb2_signed_transaction)\n            performative_content[\"signed_transaction\"] = signed_transaction\n            if cosm_trade_pb.inform_signed_transaction.fipa_dialogue_id_is_set:\n                fipa_dialogue_id = (\n                    cosm_trade_pb.inform_signed_transaction.fipa_dialogue_id\n                )\n                fipa_dialogue_id_tuple = tuple(fipa_dialogue_id)\n                performative_content[\"fipa_dialogue_id\"] = fipa_dialogue_id_tuple\n        elif performative_id == CosmTradeMessage.Performative.ERROR:\n            code = cosm_trade_pb.error.code\n            performative_content[\"code\"] = code\n            if cosm_trade_pb.error.message_is_set:\n                message = cosm_trade_pb.error.message\n                performative_content[\"message\"] = message\n            if cosm_trade_pb.error.data_is_set:\n                data = cosm_trade_pb.error.data\n                performative_content[\"data\"] = data\n        elif performative_id == CosmTradeMessage.Performative.END:\n            pass\n        else:\n            raise ValueError(\"Performative not valid: {}.\".format(performative_id))\n\n        return CosmTradeMessage(\n            message_id=message_id,\n            dialogue_reference=dialogue_reference,\n            target=target,\n            performative=performative,\n            **performative_content\n        )\n"
  },
  {
    "path": "packages/fetchai/protocols/default/README.md",
    "content": "# Default Protocol\n\n## Description\n\nThis is a protocol for two agents exchanging any bytes messages.\n\n## Specification\n\n```yaml\n---\nname: default\nauthor: fetchai\nversion: 1.1.7\ndescription: A protocol for exchanging any bytes message.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nprotocol_specification_id: fetchai/default:1.0.0\nspeech_acts:\n  bytes:\n    content: pt:bytes\n  error:\n    error_code: ct:ErrorCode\n    error_msg: pt:str\n    error_data: pt:dict[pt:str, pt:bytes]\n  end: {}\n...\n---\nct:ErrorCode: |\n  enum ErrorCodeEnum {\n      UNSUPPORTED_PROTOCOL = 0;\n      DECODING_ERROR = 1;\n      INVALID_MESSAGE = 2;\n      UNSUPPORTED_SKILL = 3;\n      INVALID_DIALOGUE = 4;\n    }\n  ErrorCodeEnum error_code = 1;\n...\n---\ninitiation: [bytes, error]\nreply:\n  bytes: [bytes, error, end]\n  error: []\n  end: []\ntermination: [end, error]\nroles: {agent}\nend_states: [successful, failed]\nkeep_terminal_state_dialogues: true\n...\n```\n\n## Links\n"
  },
  {
    "path": "packages/fetchai/protocols/default/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nThis module contains the support resources for the default protocol.\n\nIt was created with protocol buffer compiler version `libprotoc 3.19.4` and aea version `1.2.5`.\n\"\"\"\n\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.protocols.default.serialization import DefaultSerializer\n\n\nDefaultMessage.serializer = DefaultSerializer\n"
  },
  {
    "path": "packages/fetchai/protocols/default/custom_types.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains class representations corresponding to every custom type in the protocol specification.\"\"\"\n\nfrom enum import Enum\nfrom typing import Any\n\n\nclass ErrorCode(Enum):\n    \"\"\"This class represents an instance of ErrorCode.\"\"\"\n\n    UNSUPPORTED_PROTOCOL = 0\n    DECODING_ERROR = 1\n    INVALID_MESSAGE = 2\n    UNSUPPORTED_SKILL = 3\n    INVALID_DIALOGUE = 4\n\n    @staticmethod\n    def encode(error_code_protobuf_object: Any, error_code_object: \"ErrorCode\") -> None:\n        \"\"\"\n        Encode an instance of this class into the protocol buffer object.\n\n        The protocol buffer object in the error_code_protobuf_object argument is matched with the instance of this class in the 'error_code_object' argument.\n\n        :param error_code_protobuf_object: the protocol buffer object whose type corresponds with this class.\n        :param error_code_object: an instance of this class to be encoded in the protocol buffer object.\n        \"\"\"\n        error_code_protobuf_object.error_code = error_code_object.value\n\n    @classmethod\n    def decode(cls, error_code_protobuf_object: Any) -> \"ErrorCode\":\n        \"\"\"\n        Decode a protocol buffer object that corresponds with this class into an instance of this class.\n\n        A new instance of this class is created that matches the protocol buffer object in the 'error_code_protobuf_object' argument.\n\n        :param error_code_protobuf_object: the protocol buffer object whose type corresponds with this class.\n        :return: A new instance of this class that matches the protocol buffer object in the 'error_code_protobuf_object' argument.\n        \"\"\"\n        enum_value_from_pb2 = error_code_protobuf_object.error_code\n        return ErrorCode(enum_value_from_pb2)\n"
  },
  {
    "path": "packages/fetchai/protocols/default/default.proto",
    "content": "syntax = \"proto3\";\n\npackage aea.fetchai.default.v1_0_0;\n\nmessage DefaultMessage{\n\n  // Custom Types\n  message ErrorCode{\n    enum ErrorCodeEnum {\n      UNSUPPORTED_PROTOCOL = 0;\n      DECODING_ERROR = 1;\n      INVALID_MESSAGE = 2;\n      UNSUPPORTED_SKILL = 3;\n      INVALID_DIALOGUE = 4;\n    }\n    ErrorCodeEnum error_code = 1;\n  }\n\n\n  // Performatives and contents\n  message Bytes_Performative{\n    bytes content = 1;\n  }\n\n  message Error_Performative{\n    ErrorCode error_code = 1;\n    string error_msg = 2;\n    map<string, bytes> error_data = 3;\n  }\n\n  message End_Performative{\n  }\n\n\n  oneof performative{\n    Bytes_Performative bytes = 5;\n    End_Performative end = 6;\n    Error_Performative error = 7;\n  }\n}\n"
  },
  {
    "path": "packages/fetchai/protocols/default/default_pb2.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by the protocol buffer compiler.  DO NOT EDIT!\n# source: default.proto\n\"\"\"Generated protocol buffer code.\"\"\"\nfrom google.protobuf import descriptor as _descriptor\nfrom google.protobuf import descriptor_pool as _descriptor_pool\nfrom google.protobuf import message as _message\nfrom google.protobuf import reflection as _reflection\nfrom google.protobuf import symbol_database as _symbol_database\n\n# @@protoc_insertion_point(imports)\n\n_sym_db = _symbol_database.Default()\n\n\nDESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(\n    b'\\n\\rdefault.proto\\x12\\x1a\\x61\\x65\\x61.fetchai.default.v1_0_0\"\\xb6\\x06\\n\\x0e\\x44\\x65\\x66\\x61ultMessage\\x12N\\n\\x05\\x62ytes\\x18\\x05 \\x01(\\x0b\\x32=.aea.fetchai.default.v1_0_0.DefaultMessage.Bytes_PerformativeH\\x00\\x12J\\n\\x03\\x65nd\\x18\\x06 \\x01(\\x0b\\x32;.aea.fetchai.default.v1_0_0.DefaultMessage.End_PerformativeH\\x00\\x12N\\n\\x05\\x65rror\\x18\\x07 \\x01(\\x0b\\x32=.aea.fetchai.default.v1_0_0.DefaultMessage.Error_PerformativeH\\x00\\x1a\\xe4\\x01\\n\\tErrorCode\\x12V\\n\\nerror_code\\x18\\x01 \\x01(\\x0e\\x32\\x42.aea.fetchai.default.v1_0_0.DefaultMessage.ErrorCode.ErrorCodeEnum\"\\x7f\\n\\rErrorCodeEnum\\x12\\x18\\n\\x14UNSUPPORTED_PROTOCOL\\x10\\x00\\x12\\x12\\n\\x0e\\x44\\x45\\x43ODING_ERROR\\x10\\x01\\x12\\x13\\n\\x0fINVALID_MESSAGE\\x10\\x02\\x12\\x15\\n\\x11UNSUPPORTED_SKILL\\x10\\x03\\x12\\x14\\n\\x10INVALID_DIALOGUE\\x10\\x04\\x1a%\\n\\x12\\x42ytes_Performative\\x12\\x0f\\n\\x07\\x63ontent\\x18\\x01 \\x01(\\x0c\\x1a\\x85\\x02\\n\\x12\\x45rror_Performative\\x12H\\n\\nerror_code\\x18\\x01 \\x01(\\x0b\\x32\\x34.aea.fetchai.default.v1_0_0.DefaultMessage.ErrorCode\\x12\\x11\\n\\terror_msg\\x18\\x02 \\x01(\\t\\x12`\\n\\nerror_data\\x18\\x03 \\x03(\\x0b\\x32L.aea.fetchai.default.v1_0_0.DefaultMessage.Error_Performative.ErrorDataEntry\\x1a\\x30\\n\\x0e\\x45rrorDataEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\t\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\x0c:\\x02\\x38\\x01\\x1a\\x12\\n\\x10\\x45nd_PerformativeB\\x0e\\n\\x0cperformativeb\\x06proto3'\n)\n\n\n_DEFAULTMESSAGE = DESCRIPTOR.message_types_by_name[\"DefaultMessage\"]\n_DEFAULTMESSAGE_ERRORCODE = _DEFAULTMESSAGE.nested_types_by_name[\"ErrorCode\"]\n_DEFAULTMESSAGE_BYTES_PERFORMATIVE = _DEFAULTMESSAGE.nested_types_by_name[\n    \"Bytes_Performative\"\n]\n_DEFAULTMESSAGE_ERROR_PERFORMATIVE = _DEFAULTMESSAGE.nested_types_by_name[\n    \"Error_Performative\"\n]\n_DEFAULTMESSAGE_ERROR_PERFORMATIVE_ERRORDATAENTRY = (\n    _DEFAULTMESSAGE_ERROR_PERFORMATIVE.nested_types_by_name[\"ErrorDataEntry\"]\n)\n_DEFAULTMESSAGE_END_PERFORMATIVE = _DEFAULTMESSAGE.nested_types_by_name[\n    \"End_Performative\"\n]\n_DEFAULTMESSAGE_ERRORCODE_ERRORCODEENUM = _DEFAULTMESSAGE_ERRORCODE.enum_types_by_name[\n    \"ErrorCodeEnum\"\n]\nDefaultMessage = _reflection.GeneratedProtocolMessageType(\n    \"DefaultMessage\",\n    (_message.Message,),\n    {\n        \"ErrorCode\": _reflection.GeneratedProtocolMessageType(\n            \"ErrorCode\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _DEFAULTMESSAGE_ERRORCODE,\n                \"__module__\": \"default_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.default.v1_0_0.DefaultMessage.ErrorCode)\n            },\n        ),\n        \"Bytes_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Bytes_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _DEFAULTMESSAGE_BYTES_PERFORMATIVE,\n                \"__module__\": \"default_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.default.v1_0_0.DefaultMessage.Bytes_Performative)\n            },\n        ),\n        \"Error_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Error_Performative\",\n            (_message.Message,),\n            {\n                \"ErrorDataEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"ErrorDataEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _DEFAULTMESSAGE_ERROR_PERFORMATIVE_ERRORDATAENTRY,\n                        \"__module__\": \"default_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.fetchai.default.v1_0_0.DefaultMessage.Error_Performative.ErrorDataEntry)\n                    },\n                ),\n                \"DESCRIPTOR\": _DEFAULTMESSAGE_ERROR_PERFORMATIVE,\n                \"__module__\": \"default_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.default.v1_0_0.DefaultMessage.Error_Performative)\n            },\n        ),\n        \"End_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"End_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _DEFAULTMESSAGE_END_PERFORMATIVE,\n                \"__module__\": \"default_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.default.v1_0_0.DefaultMessage.End_Performative)\n            },\n        ),\n        \"DESCRIPTOR\": _DEFAULTMESSAGE,\n        \"__module__\": \"default_pb2\"\n        # @@protoc_insertion_point(class_scope:aea.fetchai.default.v1_0_0.DefaultMessage)\n    },\n)\n_sym_db.RegisterMessage(DefaultMessage)\n_sym_db.RegisterMessage(DefaultMessage.ErrorCode)\n_sym_db.RegisterMessage(DefaultMessage.Bytes_Performative)\n_sym_db.RegisterMessage(DefaultMessage.Error_Performative)\n_sym_db.RegisterMessage(DefaultMessage.Error_Performative.ErrorDataEntry)\n_sym_db.RegisterMessage(DefaultMessage.End_Performative)\n\nif _descriptor._USE_C_DESCRIPTORS == False:\n\n    DESCRIPTOR._options = None\n    _DEFAULTMESSAGE_ERROR_PERFORMATIVE_ERRORDATAENTRY._options = None\n    _DEFAULTMESSAGE_ERROR_PERFORMATIVE_ERRORDATAENTRY._serialized_options = b\"8\\001\"\n    _DEFAULTMESSAGE._serialized_start = 46\n    _DEFAULTMESSAGE._serialized_end = 868\n    _DEFAULTMESSAGE_ERRORCODE._serialized_start = 301\n    _DEFAULTMESSAGE_ERRORCODE._serialized_end = 529\n    _DEFAULTMESSAGE_ERRORCODE_ERRORCODEENUM._serialized_start = 402\n    _DEFAULTMESSAGE_ERRORCODE_ERRORCODEENUM._serialized_end = 529\n    _DEFAULTMESSAGE_BYTES_PERFORMATIVE._serialized_start = 531\n    _DEFAULTMESSAGE_BYTES_PERFORMATIVE._serialized_end = 568\n    _DEFAULTMESSAGE_ERROR_PERFORMATIVE._serialized_start = 571\n    _DEFAULTMESSAGE_ERROR_PERFORMATIVE._serialized_end = 832\n    _DEFAULTMESSAGE_ERROR_PERFORMATIVE_ERRORDATAENTRY._serialized_start = 784\n    _DEFAULTMESSAGE_ERROR_PERFORMATIVE_ERRORDATAENTRY._serialized_end = 832\n    _DEFAULTMESSAGE_END_PERFORMATIVE._serialized_start = 834\n    _DEFAULTMESSAGE_END_PERFORMATIVE._serialized_end = 852\n# @@protoc_insertion_point(module_scope)\n"
  },
  {
    "path": "packages/fetchai/protocols/default/dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nThis module contains the classes required for default dialogue management.\n\n- DefaultDialogue: The dialogue class maintains state of a dialogue and manages it.\n- DefaultDialogues: The dialogues class keeps track of all dialogues.\n\"\"\"\n\nfrom abc import ABC\nfrom typing import Callable, Dict, FrozenSet, Type, cast\n\nfrom aea.common import Address\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue, DialogueLabel, Dialogues\n\nfrom packages.fetchai.protocols.default.message import DefaultMessage\n\n\nclass DefaultDialogue(Dialogue):\n    \"\"\"The default dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    INITIAL_PERFORMATIVES: FrozenSet[Message.Performative] = frozenset(\n        {DefaultMessage.Performative.BYTES, DefaultMessage.Performative.ERROR}\n    )\n    TERMINAL_PERFORMATIVES: FrozenSet[Message.Performative] = frozenset(\n        {DefaultMessage.Performative.END, DefaultMessage.Performative.ERROR}\n    )\n    VALID_REPLIES: Dict[Message.Performative, FrozenSet[Message.Performative]] = {\n        DefaultMessage.Performative.BYTES: frozenset(\n            {\n                DefaultMessage.Performative.BYTES,\n                DefaultMessage.Performative.ERROR,\n                DefaultMessage.Performative.END,\n            }\n        ),\n        DefaultMessage.Performative.END: frozenset(),\n        DefaultMessage.Performative.ERROR: frozenset(),\n    }\n\n    class Role(Dialogue.Role):\n        \"\"\"This class defines the agent's role in a default dialogue.\"\"\"\n\n        AGENT = \"agent\"\n\n    class EndState(Dialogue.EndState):\n        \"\"\"This class defines the end states of a default dialogue.\"\"\"\n\n        SUCCESSFUL = 0\n        FAILED = 1\n\n    def __init__(\n        self,\n        dialogue_label: DialogueLabel,\n        self_address: Address,\n        role: Dialogue.Role,\n        message_class: Type[DefaultMessage] = DefaultMessage,\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n        :param message_class: the message class used\n        \"\"\"\n        Dialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            message_class=message_class,\n            self_address=self_address,\n            role=role,\n        )\n\n\nclass DefaultDialogues(Dialogues, ABC):\n    \"\"\"This class keeps track of all default dialogues.\"\"\"\n\n    END_STATES = frozenset(\n        {DefaultDialogue.EndState.SUCCESSFUL, DefaultDialogue.EndState.FAILED}\n    )\n\n    _keep_terminal_state_dialogues = True\n\n    def __init__(\n        self,\n        self_address: Address,\n        role_from_first_message: Callable[[Message, Address], Dialogue.Role],\n        dialogue_class: Type[DefaultDialogue] = DefaultDialogue,\n    ) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param self_address: the address of the entity for whom dialogues are maintained\n        :param dialogue_class: the dialogue class used\n        :param role_from_first_message: the callable determining role from first message\n        \"\"\"\n        Dialogues.__init__(\n            self,\n            self_address=self_address,\n            end_states=cast(FrozenSet[Dialogue.EndState], self.END_STATES),\n            message_class=DefaultMessage,\n            dialogue_class=dialogue_class,\n            role_from_first_message=role_from_first_message,\n        )\n"
  },
  {
    "path": "packages/fetchai/protocols/default/message.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains default's message definition.\"\"\"\n\n# pylint: disable=too-many-statements,too-many-locals,no-member,too-few-public-methods,too-many-branches,not-an-iterable,unidiomatic-typecheck,unsubscriptable-object\nimport logging\nfrom typing import Any, Dict, Set, Tuple, cast\n\nfrom aea.configurations.base import PublicId\nfrom aea.exceptions import AEAEnforceError, enforce\nfrom aea.protocols.base import Message\n\nfrom packages.fetchai.protocols.default.custom_types import ErrorCode as CustomErrorCode\n\n\n_default_logger = logging.getLogger(\"aea.packages.fetchai.protocols.default.message\")\n\nDEFAULT_BODY_SIZE = 4\n\n\nclass DefaultMessage(Message):\n    \"\"\"A protocol for exchanging any bytes message.\"\"\"\n\n    protocol_id = PublicId.from_str(\"fetchai/default:1.1.7\")\n    protocol_specification_id = PublicId.from_str(\"fetchai/default:1.0.0\")\n\n    ErrorCode = CustomErrorCode\n\n    class Performative(Message.Performative):\n        \"\"\"Performatives for the default protocol.\"\"\"\n\n        BYTES = \"bytes\"\n        END = \"end\"\n        ERROR = \"error\"\n\n        def __str__(self) -> str:\n            \"\"\"Get the string representation.\"\"\"\n            return str(self.value)\n\n    _performatives = {\"bytes\", \"end\", \"error\"}\n    __slots__: Tuple[str, ...] = tuple()\n\n    class _SlotsCls:\n        __slots__ = (\n            \"content\",\n            \"dialogue_reference\",\n            \"error_code\",\n            \"error_data\",\n            \"error_msg\",\n            \"message_id\",\n            \"performative\",\n            \"target\",\n        )\n\n    def __init__(\n        self,\n        performative: Performative,\n        dialogue_reference: Tuple[str, str] = (\"\", \"\"),\n        message_id: int = 1,\n        target: int = 0,\n        **kwargs: Any,\n    ):\n        \"\"\"\n        Initialise an instance of DefaultMessage.\n\n        :param message_id: the message id.\n        :param dialogue_reference: the dialogue reference.\n        :param target: the message target.\n        :param performative: the message performative.\n        :param **kwargs: extra options.\n        \"\"\"\n        super().__init__(\n            dialogue_reference=dialogue_reference,\n            message_id=message_id,\n            target=target,\n            performative=DefaultMessage.Performative(performative),\n            **kwargs,\n        )\n\n    @property\n    def valid_performatives(self) -> Set[str]:\n        \"\"\"Get valid performatives.\"\"\"\n        return self._performatives\n\n    @property\n    def dialogue_reference(self) -> Tuple[str, str]:\n        \"\"\"Get the dialogue_reference of the message.\"\"\"\n        enforce(self.is_set(\"dialogue_reference\"), \"dialogue_reference is not set.\")\n        return cast(Tuple[str, str], self.get(\"dialogue_reference\"))\n\n    @property\n    def message_id(self) -> int:\n        \"\"\"Get the message_id of the message.\"\"\"\n        enforce(self.is_set(\"message_id\"), \"message_id is not set.\")\n        return cast(int, self.get(\"message_id\"))\n\n    @property\n    def performative(self) -> Performative:  # type: ignore # noqa: F821\n        \"\"\"Get the performative of the message.\"\"\"\n        enforce(self.is_set(\"performative\"), \"performative is not set.\")\n        return cast(DefaultMessage.Performative, self.get(\"performative\"))\n\n    @property\n    def target(self) -> int:\n        \"\"\"Get the target of the message.\"\"\"\n        enforce(self.is_set(\"target\"), \"target is not set.\")\n        return cast(int, self.get(\"target\"))\n\n    @property\n    def content(self) -> bytes:\n        \"\"\"Get the 'content' content from the message.\"\"\"\n        enforce(self.is_set(\"content\"), \"'content' content is not set.\")\n        return cast(bytes, self.get(\"content\"))\n\n    @property\n    def error_code(self) -> CustomErrorCode:\n        \"\"\"Get the 'error_code' content from the message.\"\"\"\n        enforce(self.is_set(\"error_code\"), \"'error_code' content is not set.\")\n        return cast(CustomErrorCode, self.get(\"error_code\"))\n\n    @property\n    def error_data(self) -> Dict[str, bytes]:\n        \"\"\"Get the 'error_data' content from the message.\"\"\"\n        enforce(self.is_set(\"error_data\"), \"'error_data' content is not set.\")\n        return cast(Dict[str, bytes], self.get(\"error_data\"))\n\n    @property\n    def error_msg(self) -> str:\n        \"\"\"Get the 'error_msg' content from the message.\"\"\"\n        enforce(self.is_set(\"error_msg\"), \"'error_msg' content is not set.\")\n        return cast(str, self.get(\"error_msg\"))\n\n    def _is_consistent(self) -> bool:\n        \"\"\"Check that the message follows the default protocol.\"\"\"\n        try:\n            enforce(\n                isinstance(self.dialogue_reference, tuple),\n                \"Invalid type for 'dialogue_reference'. Expected 'tuple'. Found '{}'.\".format(\n                    type(self.dialogue_reference)\n                ),\n            )\n            enforce(\n                isinstance(self.dialogue_reference[0], str),\n                \"Invalid type for 'dialogue_reference[0]'. Expected 'str'. Found '{}'.\".format(\n                    type(self.dialogue_reference[0])\n                ),\n            )\n            enforce(\n                isinstance(self.dialogue_reference[1], str),\n                \"Invalid type for 'dialogue_reference[1]'. Expected 'str'. Found '{}'.\".format(\n                    type(self.dialogue_reference[1])\n                ),\n            )\n            enforce(\n                type(self.message_id) is int,\n                \"Invalid type for 'message_id'. Expected 'int'. Found '{}'.\".format(\n                    type(self.message_id)\n                ),\n            )\n            enforce(\n                type(self.target) is int,\n                \"Invalid type for 'target'. Expected 'int'. Found '{}'.\".format(\n                    type(self.target)\n                ),\n            )\n\n            # Light Protocol Rule 2\n            # Check correct performative\n            enforce(\n                isinstance(self.performative, DefaultMessage.Performative),\n                \"Invalid 'performative'. Expected either of '{}'. Found '{}'.\".format(\n                    self.valid_performatives, self.performative\n                ),\n            )\n\n            # Check correct contents\n            actual_nb_of_contents = len(self._body) - DEFAULT_BODY_SIZE\n            expected_nb_of_contents = 0\n            if self.performative == DefaultMessage.Performative.BYTES:\n                expected_nb_of_contents = 1\n                enforce(\n                    isinstance(self.content, bytes),\n                    \"Invalid type for content 'content'. Expected 'bytes'. Found '{}'.\".format(\n                        type(self.content)\n                    ),\n                )\n            elif self.performative == DefaultMessage.Performative.ERROR:\n                expected_nb_of_contents = 3\n                enforce(\n                    isinstance(self.error_code, CustomErrorCode),\n                    \"Invalid type for content 'error_code'. Expected 'ErrorCode'. Found '{}'.\".format(\n                        type(self.error_code)\n                    ),\n                )\n                enforce(\n                    isinstance(self.error_msg, str),\n                    \"Invalid type for content 'error_msg'. Expected 'str'. Found '{}'.\".format(\n                        type(self.error_msg)\n                    ),\n                )\n                enforce(\n                    isinstance(self.error_data, dict),\n                    \"Invalid type for content 'error_data'. Expected 'dict'. Found '{}'.\".format(\n                        type(self.error_data)\n                    ),\n                )\n                for key_of_error_data, value_of_error_data in self.error_data.items():\n                    enforce(\n                        isinstance(key_of_error_data, str),\n                        \"Invalid type for dictionary keys in content 'error_data'. Expected 'str'. Found '{}'.\".format(\n                            type(key_of_error_data)\n                        ),\n                    )\n                    enforce(\n                        isinstance(value_of_error_data, bytes),\n                        \"Invalid type for dictionary values in content 'error_data'. Expected 'bytes'. Found '{}'.\".format(\n                            type(value_of_error_data)\n                        ),\n                    )\n            elif self.performative == DefaultMessage.Performative.END:\n                expected_nb_of_contents = 0\n\n            # Check correct content count\n            enforce(\n                expected_nb_of_contents == actual_nb_of_contents,\n                \"Incorrect number of contents. Expected {}. Found {}\".format(\n                    expected_nb_of_contents, actual_nb_of_contents\n                ),\n            )\n\n            # Light Protocol Rule 3\n            if self.message_id == 1:\n                enforce(\n                    self.target == 0,\n                    \"Invalid 'target'. Expected 0 (because 'message_id' is 1). Found {}.\".format(\n                        self.target\n                    ),\n                )\n        except (AEAEnforceError, ValueError, KeyError) as e:\n            _default_logger.error(str(e))\n            return False\n\n        return True\n"
  },
  {
    "path": "packages/fetchai/protocols/default/protocol.yaml",
    "content": "name: default\nauthor: fetchai\nversion: 1.1.7\nprotocol_specification_id: fetchai/default:1.0.0\ntype: protocol\ndescription: A protocol for exchanging any bytes message.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: Qma4UhkBrAwxD1qdNwiMwTVYYQB7cBHd7UXJQ1SQWYi8Zs\n  __init__.py: QmQgKC4pQPaoCXwfSkJimbqpyMN1qGUq7RfBAU2591yTap\n  custom_types.py: QmQUFTE8WVj8V1PyrhuCvmPbTLoTuFWjiK97XJKavDQfyC\n  default.proto: QmWYzTSHVbz7FBS84iKFMhGSXPxay2mss29vY7ufz2BFJ8\n  default_pb2.py: QmPX9tm18ddM5Q928JLd1HmdUZKp2ssKhCJzhZ53FJmjxM\n  dialogues.py: QmPbCt78gFSSPbmBu87R6REMc2gD3JU9UWMkVNF9mP9A7x\n  message.py: QmRL8PiNCoCMsHmrR4LnbphEtm4oEPR8AAhSgoADHV29D7\n  serialization.py: QmepsqanTZV4Wg3Dg9qDtSqwe5AyRS2BUgURndk1h9kjNt\nfingerprint_ignore_patterns: []\ndependencies:\n  protobuf: {}\n"
  },
  {
    "path": "packages/fetchai/protocols/default/serialization.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Serialization module for default protocol.\"\"\"\n\n# pylint: disable=too-many-statements,too-many-locals,no-member,too-few-public-methods,redefined-builtin\nfrom typing import Any, Dict, cast\n\nfrom aea.mail.base_pb2 import DialogueMessage\nfrom aea.mail.base_pb2 import Message as ProtobufMessage\nfrom aea.protocols.base import Message, Serializer\n\nfrom packages.fetchai.protocols.default import default_pb2\nfrom packages.fetchai.protocols.default.custom_types import ErrorCode\nfrom packages.fetchai.protocols.default.message import DefaultMessage\n\n\nclass DefaultSerializer(Serializer):\n    \"\"\"Serialization for the 'default' protocol.\"\"\"\n\n    @staticmethod\n    def encode(msg: Message) -> bytes:\n        \"\"\"\n        Encode a 'Default' message into bytes.\n\n        :param msg: the message object.\n        :return: the bytes.\n        \"\"\"\n        msg = cast(DefaultMessage, msg)\n        message_pb = ProtobufMessage()\n        dialogue_message_pb = DialogueMessage()\n        default_msg = default_pb2.DefaultMessage()\n\n        dialogue_message_pb.message_id = msg.message_id\n        dialogue_reference = msg.dialogue_reference\n        dialogue_message_pb.dialogue_starter_reference = dialogue_reference[0]\n        dialogue_message_pb.dialogue_responder_reference = dialogue_reference[1]\n        dialogue_message_pb.target = msg.target\n\n        performative_id = msg.performative\n        if performative_id == DefaultMessage.Performative.BYTES:\n            performative = default_pb2.DefaultMessage.Bytes_Performative()  # type: ignore\n            content = msg.content\n            performative.content = content\n            default_msg.bytes.CopyFrom(performative)\n        elif performative_id == DefaultMessage.Performative.ERROR:\n            performative = default_pb2.DefaultMessage.Error_Performative()  # type: ignore\n            error_code = msg.error_code\n            ErrorCode.encode(performative.error_code, error_code)\n            error_msg = msg.error_msg\n            performative.error_msg = error_msg\n            error_data = msg.error_data\n            performative.error_data.update(error_data)\n            default_msg.error.CopyFrom(performative)\n        elif performative_id == DefaultMessage.Performative.END:\n            performative = default_pb2.DefaultMessage.End_Performative()  # type: ignore\n            default_msg.end.CopyFrom(performative)\n        else:\n            raise ValueError(\"Performative not valid: {}\".format(performative_id))\n\n        dialogue_message_pb.content = default_msg.SerializeToString()\n\n        message_pb.dialogue_message.CopyFrom(dialogue_message_pb)\n        message_bytes = message_pb.SerializeToString()\n        return message_bytes\n\n    @staticmethod\n    def decode(obj: bytes) -> Message:\n        \"\"\"\n        Decode bytes into a 'Default' message.\n\n        :param obj: the bytes object.\n        :return: the 'Default' message.\n        \"\"\"\n        message_pb = ProtobufMessage()\n        default_pb = default_pb2.DefaultMessage()\n        message_pb.ParseFromString(obj)\n        message_id = message_pb.dialogue_message.message_id\n        dialogue_reference = (\n            message_pb.dialogue_message.dialogue_starter_reference,\n            message_pb.dialogue_message.dialogue_responder_reference,\n        )\n        target = message_pb.dialogue_message.target\n\n        default_pb.ParseFromString(message_pb.dialogue_message.content)\n        performative = default_pb.WhichOneof(\"performative\")\n        performative_id = DefaultMessage.Performative(str(performative))\n        performative_content = {}  # type: Dict[str, Any]\n        if performative_id == DefaultMessage.Performative.BYTES:\n            content = default_pb.bytes.content\n            performative_content[\"content\"] = content\n        elif performative_id == DefaultMessage.Performative.ERROR:\n            pb2_error_code = default_pb.error.error_code\n            error_code = ErrorCode.decode(pb2_error_code)\n            performative_content[\"error_code\"] = error_code\n            error_msg = default_pb.error.error_msg\n            performative_content[\"error_msg\"] = error_msg\n            error_data = default_pb.error.error_data\n            error_data_dict = dict(error_data)\n            performative_content[\"error_data\"] = error_data_dict\n        elif performative_id == DefaultMessage.Performative.END:\n            pass\n        else:\n            raise ValueError(\"Performative not valid: {}.\".format(performative_id))\n\n        return DefaultMessage(\n            message_id=message_id,\n            dialogue_reference=dialogue_reference,\n            target=target,\n            performative=performative,\n            **performative_content\n        )\n"
  },
  {
    "path": "packages/fetchai/protocols/fipa/README.md",
    "content": "# Fipa Protocol\n\n## Description\n\nThis is a protocol for two agents to negotiate over a fixed set of resources.\n\n## Specification\n\n```yaml\n---\nname: fipa\nauthor: fetchai\nversion: 1.1.7\ndescription: A protocol for FIPA ACL.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nprotocol_specification_id: fetchai/fipa:1.0.0\nspeech_acts:\n  cfp:\n    query: ct:Query\n  propose:\n    proposal: ct:Description\n  accept_w_inform:\n    info: pt:dict[pt:str, pt:str]\n  match_accept_w_inform:\n    info: pt:dict[pt:str, pt:str]\n  inform:\n    info: pt:dict[pt:str, pt:str]\n  accept: {}\n  decline: {}\n  match_accept: {}\n  end: {}\n...\n---\nct:Query: |\n  bytes query_bytes = 1;\nct:Description: |\n  bytes description_bytes = 1;\n...\n---\ninitiation: [cfp]\nreply:\n  cfp: [propose, decline]\n  propose: [accept, accept_w_inform, decline, propose]\n  accept: [decline, match_accept, match_accept_w_inform]\n  accept_w_inform: [decline, match_accept, match_accept_w_inform]\n  decline: []\n  match_accept: [inform, end]\n  match_accept_w_inform: [inform, end]\n  inform: [inform, end]\n  end: []\ntermination: [decline, end]\nroles: {seller, buyer}\nend_states: [successful, declined_cfp, declined_propose, declined_accept]\nkeep_terminal_state_dialogues: true\n...\n```\n\n## Links\n\n- <a href=\"http://www.fipa.org\" target=\"_blank\">FIPA Foundation</a>\n"
  },
  {
    "path": "packages/fetchai/protocols/fipa/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nThis module contains the support resources for the fipa protocol.\n\nIt was created with protocol buffer compiler version `libprotoc 3.19.4` and aea version `1.2.5`.\n\"\"\"\n\nfrom packages.fetchai.protocols.fipa.message import FipaMessage\nfrom packages.fetchai.protocols.fipa.serialization import FipaSerializer\n\n\nFipaMessage.serializer = FipaSerializer\n"
  },
  {
    "path": "packages/fetchai/protocols/fipa/custom_types.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains class representations corresponding to every custom type in the protocol specification.\"\"\"\n\n\nfrom aea.helpers.search.models import Description as BaseDescription\nfrom aea.helpers.search.models import Query as BaseQuery\n\n\nDescription = BaseDescription\n\nQuery = BaseQuery\n"
  },
  {
    "path": "packages/fetchai/protocols/fipa/dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nThis module contains the classes required for fipa dialogue management.\n\n- FipaDialogue: The dialogue class maintains state of a dialogue and manages it.\n- FipaDialogues: The dialogues class keeps track of all dialogues.\n\"\"\"\n\nfrom abc import ABC\nfrom typing import Callable, Dict, FrozenSet, Type, cast\n\nfrom aea.common import Address\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue, DialogueLabel, Dialogues\n\nfrom packages.fetchai.protocols.fipa.message import FipaMessage\n\n\nclass FipaDialogue(Dialogue):\n    \"\"\"The fipa dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    INITIAL_PERFORMATIVES: FrozenSet[Message.Performative] = frozenset(\n        {FipaMessage.Performative.CFP}\n    )\n    TERMINAL_PERFORMATIVES: FrozenSet[Message.Performative] = frozenset(\n        {FipaMessage.Performative.DECLINE, FipaMessage.Performative.END}\n    )\n    VALID_REPLIES: Dict[Message.Performative, FrozenSet[Message.Performative]] = {\n        FipaMessage.Performative.ACCEPT: frozenset(\n            {\n                FipaMessage.Performative.DECLINE,\n                FipaMessage.Performative.MATCH_ACCEPT,\n                FipaMessage.Performative.MATCH_ACCEPT_W_INFORM,\n            }\n        ),\n        FipaMessage.Performative.ACCEPT_W_INFORM: frozenset(\n            {\n                FipaMessage.Performative.DECLINE,\n                FipaMessage.Performative.MATCH_ACCEPT,\n                FipaMessage.Performative.MATCH_ACCEPT_W_INFORM,\n            }\n        ),\n        FipaMessage.Performative.CFP: frozenset(\n            {FipaMessage.Performative.PROPOSE, FipaMessage.Performative.DECLINE}\n        ),\n        FipaMessage.Performative.DECLINE: frozenset(),\n        FipaMessage.Performative.END: frozenset(),\n        FipaMessage.Performative.INFORM: frozenset(\n            {FipaMessage.Performative.INFORM, FipaMessage.Performative.END}\n        ),\n        FipaMessage.Performative.MATCH_ACCEPT: frozenset(\n            {FipaMessage.Performative.INFORM, FipaMessage.Performative.END}\n        ),\n        FipaMessage.Performative.MATCH_ACCEPT_W_INFORM: frozenset(\n            {FipaMessage.Performative.INFORM, FipaMessage.Performative.END}\n        ),\n        FipaMessage.Performative.PROPOSE: frozenset(\n            {\n                FipaMessage.Performative.ACCEPT,\n                FipaMessage.Performative.ACCEPT_W_INFORM,\n                FipaMessage.Performative.DECLINE,\n                FipaMessage.Performative.PROPOSE,\n            }\n        ),\n    }\n\n    class Role(Dialogue.Role):\n        \"\"\"This class defines the agent's role in a fipa dialogue.\"\"\"\n\n        BUYER = \"buyer\"\n        SELLER = \"seller\"\n\n    class EndState(Dialogue.EndState):\n        \"\"\"This class defines the end states of a fipa dialogue.\"\"\"\n\n        SUCCESSFUL = 0\n        DECLINED_CFP = 1\n        DECLINED_PROPOSE = 2\n        DECLINED_ACCEPT = 3\n\n    def __init__(\n        self,\n        dialogue_label: DialogueLabel,\n        self_address: Address,\n        role: Dialogue.Role,\n        message_class: Type[FipaMessage] = FipaMessage,\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n        :param message_class: the message class used\n        \"\"\"\n        Dialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            message_class=message_class,\n            self_address=self_address,\n            role=role,\n        )\n\n\nclass FipaDialogues(Dialogues, ABC):\n    \"\"\"This class keeps track of all fipa dialogues.\"\"\"\n\n    END_STATES = frozenset(\n        {\n            FipaDialogue.EndState.SUCCESSFUL,\n            FipaDialogue.EndState.DECLINED_CFP,\n            FipaDialogue.EndState.DECLINED_PROPOSE,\n            FipaDialogue.EndState.DECLINED_ACCEPT,\n        }\n    )\n\n    _keep_terminal_state_dialogues = True\n\n    def __init__(\n        self,\n        self_address: Address,\n        role_from_first_message: Callable[[Message, Address], Dialogue.Role],\n        dialogue_class: Type[FipaDialogue] = FipaDialogue,\n    ) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param self_address: the address of the entity for whom dialogues are maintained\n        :param dialogue_class: the dialogue class used\n        :param role_from_first_message: the callable determining role from first message\n        \"\"\"\n        Dialogues.__init__(\n            self,\n            self_address=self_address,\n            end_states=cast(FrozenSet[Dialogue.EndState], self.END_STATES),\n            message_class=FipaMessage,\n            dialogue_class=dialogue_class,\n            role_from_first_message=role_from_first_message,\n        )\n"
  },
  {
    "path": "packages/fetchai/protocols/fipa/fipa.proto",
    "content": "syntax = \"proto3\";\n\npackage aea.fetchai.fipa.v1_0_0;\n\nmessage FipaMessage{\n\n  // Custom Types\n  message Description{\n    bytes description_bytes = 1;\n  }\n\n  message Query{\n    bytes query_bytes = 1;\n  }\n\n\n  // Performatives and contents\n  message Cfp_Performative{\n    Query query = 1;\n  }\n\n  message Propose_Performative{\n    Description proposal = 1;\n  }\n\n  message Accept_W_Inform_Performative{\n    map<string, string> info = 1;\n  }\n\n  message Match_Accept_W_Inform_Performative{\n    map<string, string> info = 1;\n  }\n\n  message Inform_Performative{\n    map<string, string> info = 1;\n  }\n\n  message Accept_Performative{\n  }\n\n  message Decline_Performative{\n  }\n\n  message Match_Accept_Performative{\n  }\n\n  message End_Performative{\n  }\n\n\n  oneof performative{\n    Accept_Performative accept = 5;\n    Accept_W_Inform_Performative accept_w_inform = 6;\n    Cfp_Performative cfp = 7;\n    Decline_Performative decline = 8;\n    End_Performative end = 9;\n    Inform_Performative inform = 10;\n    Match_Accept_Performative match_accept = 11;\n    Match_Accept_W_Inform_Performative match_accept_w_inform = 12;\n    Propose_Performative propose = 13;\n  }\n}\n"
  },
  {
    "path": "packages/fetchai/protocols/fipa/fipa_pb2.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by the protocol buffer compiler.  DO NOT EDIT!\n# source: fipa.proto\n\"\"\"Generated protocol buffer code.\"\"\"\nfrom google.protobuf import descriptor as _descriptor\nfrom google.protobuf import descriptor_pool as _descriptor_pool\nfrom google.protobuf import message as _message\nfrom google.protobuf import reflection as _reflection\nfrom google.protobuf import symbol_database as _symbol_database\n\n# @@protoc_insertion_point(imports)\n\n_sym_db = _symbol_database.Default()\n\n\nDESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(\n    b'\\n\\nfipa.proto\\x12\\x17\\x61\\x65\\x61.fetchai.fipa.v1_0_0\"\\xc5\\x0c\\n\\x0b\\x46ipaMessage\\x12J\\n\\x06\\x61\\x63\\x63\\x65pt\\x18\\x05 \\x01(\\x0b\\x32\\x38.aea.fetchai.fipa.v1_0_0.FipaMessage.Accept_PerformativeH\\x00\\x12\\\\\\n\\x0f\\x61\\x63\\x63\\x65pt_w_inform\\x18\\x06 \\x01(\\x0b\\x32\\x41.aea.fetchai.fipa.v1_0_0.FipaMessage.Accept_W_Inform_PerformativeH\\x00\\x12\\x44\\n\\x03\\x63\\x66p\\x18\\x07 \\x01(\\x0b\\x32\\x35.aea.fetchai.fipa.v1_0_0.FipaMessage.Cfp_PerformativeH\\x00\\x12L\\n\\x07\\x64\\x65\\x63line\\x18\\x08 \\x01(\\x0b\\x32\\x39.aea.fetchai.fipa.v1_0_0.FipaMessage.Decline_PerformativeH\\x00\\x12\\x44\\n\\x03\\x65nd\\x18\\t \\x01(\\x0b\\x32\\x35.aea.fetchai.fipa.v1_0_0.FipaMessage.End_PerformativeH\\x00\\x12J\\n\\x06inform\\x18\\n \\x01(\\x0b\\x32\\x38.aea.fetchai.fipa.v1_0_0.FipaMessage.Inform_PerformativeH\\x00\\x12V\\n\\x0cmatch_accept\\x18\\x0b \\x01(\\x0b\\x32>.aea.fetchai.fipa.v1_0_0.FipaMessage.Match_Accept_PerformativeH\\x00\\x12h\\n\\x15match_accept_w_inform\\x18\\x0c \\x01(\\x0b\\x32G.aea.fetchai.fipa.v1_0_0.FipaMessage.Match_Accept_W_Inform_PerformativeH\\x00\\x12L\\n\\x07propose\\x18\\r \\x01(\\x0b\\x32\\x39.aea.fetchai.fipa.v1_0_0.FipaMessage.Propose_PerformativeH\\x00\\x1a(\\n\\x0b\\x44\\x65scription\\x12\\x19\\n\\x11\\x64\\x65scription_bytes\\x18\\x01 \\x01(\\x0c\\x1a\\x1c\\n\\x05Query\\x12\\x13\\n\\x0bquery_bytes\\x18\\x01 \\x01(\\x0c\\x1aM\\n\\x10\\x43\\x66p_Performative\\x12\\x39\\n\\x05query\\x18\\x01 \\x01(\\x0b\\x32*.aea.fetchai.fipa.v1_0_0.FipaMessage.Query\\x1aZ\\n\\x14Propose_Performative\\x12\\x42\\n\\x08proposal\\x18\\x01 \\x01(\\x0b\\x32\\x30.aea.fetchai.fipa.v1_0_0.FipaMessage.Description\\x1a\\xa6\\x01\\n\\x1c\\x41\\x63\\x63\\x65pt_W_Inform_Performative\\x12Y\\n\\x04info\\x18\\x01 \\x03(\\x0b\\x32K.aea.fetchai.fipa.v1_0_0.FipaMessage.Accept_W_Inform_Performative.InfoEntry\\x1a+\\n\\tInfoEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\t\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\t:\\x02\\x38\\x01\\x1a\\xb2\\x01\\n\"Match_Accept_W_Inform_Performative\\x12_\\n\\x04info\\x18\\x01 \\x03(\\x0b\\x32Q.aea.fetchai.fipa.v1_0_0.FipaMessage.Match_Accept_W_Inform_Performative.InfoEntry\\x1a+\\n\\tInfoEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\t\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\t:\\x02\\x38\\x01\\x1a\\x94\\x01\\n\\x13Inform_Performative\\x12P\\n\\x04info\\x18\\x01 \\x03(\\x0b\\x32\\x42.aea.fetchai.fipa.v1_0_0.FipaMessage.Inform_Performative.InfoEntry\\x1a+\\n\\tInfoEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\t\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\t:\\x02\\x38\\x01\\x1a\\x15\\n\\x13\\x41\\x63\\x63\\x65pt_Performative\\x1a\\x16\\n\\x14\\x44\\x65\\x63line_Performative\\x1a\\x1b\\n\\x19Match_Accept_Performative\\x1a\\x12\\n\\x10\\x45nd_PerformativeB\\x0e\\n\\x0cperformativeb\\x06proto3'\n)\n\n\n_FIPAMESSAGE = DESCRIPTOR.message_types_by_name[\"FipaMessage\"]\n_FIPAMESSAGE_DESCRIPTION = _FIPAMESSAGE.nested_types_by_name[\"Description\"]\n_FIPAMESSAGE_QUERY = _FIPAMESSAGE.nested_types_by_name[\"Query\"]\n_FIPAMESSAGE_CFP_PERFORMATIVE = _FIPAMESSAGE.nested_types_by_name[\"Cfp_Performative\"]\n_FIPAMESSAGE_PROPOSE_PERFORMATIVE = _FIPAMESSAGE.nested_types_by_name[\n    \"Propose_Performative\"\n]\n_FIPAMESSAGE_ACCEPT_W_INFORM_PERFORMATIVE = _FIPAMESSAGE.nested_types_by_name[\n    \"Accept_W_Inform_Performative\"\n]\n_FIPAMESSAGE_ACCEPT_W_INFORM_PERFORMATIVE_INFOENTRY = (\n    _FIPAMESSAGE_ACCEPT_W_INFORM_PERFORMATIVE.nested_types_by_name[\"InfoEntry\"]\n)\n_FIPAMESSAGE_MATCH_ACCEPT_W_INFORM_PERFORMATIVE = _FIPAMESSAGE.nested_types_by_name[\n    \"Match_Accept_W_Inform_Performative\"\n]\n_FIPAMESSAGE_MATCH_ACCEPT_W_INFORM_PERFORMATIVE_INFOENTRY = (\n    _FIPAMESSAGE_MATCH_ACCEPT_W_INFORM_PERFORMATIVE.nested_types_by_name[\"InfoEntry\"]\n)\n_FIPAMESSAGE_INFORM_PERFORMATIVE = _FIPAMESSAGE.nested_types_by_name[\n    \"Inform_Performative\"\n]\n_FIPAMESSAGE_INFORM_PERFORMATIVE_INFOENTRY = (\n    _FIPAMESSAGE_INFORM_PERFORMATIVE.nested_types_by_name[\"InfoEntry\"]\n)\n_FIPAMESSAGE_ACCEPT_PERFORMATIVE = _FIPAMESSAGE.nested_types_by_name[\n    \"Accept_Performative\"\n]\n_FIPAMESSAGE_DECLINE_PERFORMATIVE = _FIPAMESSAGE.nested_types_by_name[\n    \"Decline_Performative\"\n]\n_FIPAMESSAGE_MATCH_ACCEPT_PERFORMATIVE = _FIPAMESSAGE.nested_types_by_name[\n    \"Match_Accept_Performative\"\n]\n_FIPAMESSAGE_END_PERFORMATIVE = _FIPAMESSAGE.nested_types_by_name[\"End_Performative\"]\nFipaMessage = _reflection.GeneratedProtocolMessageType(\n    \"FipaMessage\",\n    (_message.Message,),\n    {\n        \"Description\": _reflection.GeneratedProtocolMessageType(\n            \"Description\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _FIPAMESSAGE_DESCRIPTION,\n                \"__module__\": \"fipa_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.fipa.v1_0_0.FipaMessage.Description)\n            },\n        ),\n        \"Query\": _reflection.GeneratedProtocolMessageType(\n            \"Query\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _FIPAMESSAGE_QUERY,\n                \"__module__\": \"fipa_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.fipa.v1_0_0.FipaMessage.Query)\n            },\n        ),\n        \"Cfp_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Cfp_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _FIPAMESSAGE_CFP_PERFORMATIVE,\n                \"__module__\": \"fipa_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.fipa.v1_0_0.FipaMessage.Cfp_Performative)\n            },\n        ),\n        \"Propose_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Propose_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _FIPAMESSAGE_PROPOSE_PERFORMATIVE,\n                \"__module__\": \"fipa_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.fipa.v1_0_0.FipaMessage.Propose_Performative)\n            },\n        ),\n        \"Accept_W_Inform_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Accept_W_Inform_Performative\",\n            (_message.Message,),\n            {\n                \"InfoEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"InfoEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _FIPAMESSAGE_ACCEPT_W_INFORM_PERFORMATIVE_INFOENTRY,\n                        \"__module__\": \"fipa_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.fetchai.fipa.v1_0_0.FipaMessage.Accept_W_Inform_Performative.InfoEntry)\n                    },\n                ),\n                \"DESCRIPTOR\": _FIPAMESSAGE_ACCEPT_W_INFORM_PERFORMATIVE,\n                \"__module__\": \"fipa_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.fipa.v1_0_0.FipaMessage.Accept_W_Inform_Performative)\n            },\n        ),\n        \"Match_Accept_W_Inform_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Match_Accept_W_Inform_Performative\",\n            (_message.Message,),\n            {\n                \"InfoEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"InfoEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _FIPAMESSAGE_MATCH_ACCEPT_W_INFORM_PERFORMATIVE_INFOENTRY,\n                        \"__module__\": \"fipa_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.fetchai.fipa.v1_0_0.FipaMessage.Match_Accept_W_Inform_Performative.InfoEntry)\n                    },\n                ),\n                \"DESCRIPTOR\": _FIPAMESSAGE_MATCH_ACCEPT_W_INFORM_PERFORMATIVE,\n                \"__module__\": \"fipa_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.fipa.v1_0_0.FipaMessage.Match_Accept_W_Inform_Performative)\n            },\n        ),\n        \"Inform_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Inform_Performative\",\n            (_message.Message,),\n            {\n                \"InfoEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"InfoEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _FIPAMESSAGE_INFORM_PERFORMATIVE_INFOENTRY,\n                        \"__module__\": \"fipa_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.fetchai.fipa.v1_0_0.FipaMessage.Inform_Performative.InfoEntry)\n                    },\n                ),\n                \"DESCRIPTOR\": _FIPAMESSAGE_INFORM_PERFORMATIVE,\n                \"__module__\": \"fipa_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.fipa.v1_0_0.FipaMessage.Inform_Performative)\n            },\n        ),\n        \"Accept_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Accept_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _FIPAMESSAGE_ACCEPT_PERFORMATIVE,\n                \"__module__\": \"fipa_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.fipa.v1_0_0.FipaMessage.Accept_Performative)\n            },\n        ),\n        \"Decline_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Decline_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _FIPAMESSAGE_DECLINE_PERFORMATIVE,\n                \"__module__\": \"fipa_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.fipa.v1_0_0.FipaMessage.Decline_Performative)\n            },\n        ),\n        \"Match_Accept_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Match_Accept_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _FIPAMESSAGE_MATCH_ACCEPT_PERFORMATIVE,\n                \"__module__\": \"fipa_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.fipa.v1_0_0.FipaMessage.Match_Accept_Performative)\n            },\n        ),\n        \"End_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"End_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _FIPAMESSAGE_END_PERFORMATIVE,\n                \"__module__\": \"fipa_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.fipa.v1_0_0.FipaMessage.End_Performative)\n            },\n        ),\n        \"DESCRIPTOR\": _FIPAMESSAGE,\n        \"__module__\": \"fipa_pb2\"\n        # @@protoc_insertion_point(class_scope:aea.fetchai.fipa.v1_0_0.FipaMessage)\n    },\n)\n_sym_db.RegisterMessage(FipaMessage)\n_sym_db.RegisterMessage(FipaMessage.Description)\n_sym_db.RegisterMessage(FipaMessage.Query)\n_sym_db.RegisterMessage(FipaMessage.Cfp_Performative)\n_sym_db.RegisterMessage(FipaMessage.Propose_Performative)\n_sym_db.RegisterMessage(FipaMessage.Accept_W_Inform_Performative)\n_sym_db.RegisterMessage(FipaMessage.Accept_W_Inform_Performative.InfoEntry)\n_sym_db.RegisterMessage(FipaMessage.Match_Accept_W_Inform_Performative)\n_sym_db.RegisterMessage(FipaMessage.Match_Accept_W_Inform_Performative.InfoEntry)\n_sym_db.RegisterMessage(FipaMessage.Inform_Performative)\n_sym_db.RegisterMessage(FipaMessage.Inform_Performative.InfoEntry)\n_sym_db.RegisterMessage(FipaMessage.Accept_Performative)\n_sym_db.RegisterMessage(FipaMessage.Decline_Performative)\n_sym_db.RegisterMessage(FipaMessage.Match_Accept_Performative)\n_sym_db.RegisterMessage(FipaMessage.End_Performative)\n\nif _descriptor._USE_C_DESCRIPTORS == False:\n\n    DESCRIPTOR._options = None\n    _FIPAMESSAGE_ACCEPT_W_INFORM_PERFORMATIVE_INFOENTRY._options = None\n    _FIPAMESSAGE_ACCEPT_W_INFORM_PERFORMATIVE_INFOENTRY._serialized_options = b\"8\\001\"\n    _FIPAMESSAGE_MATCH_ACCEPT_W_INFORM_PERFORMATIVE_INFOENTRY._options = None\n    _FIPAMESSAGE_MATCH_ACCEPT_W_INFORM_PERFORMATIVE_INFOENTRY._serialized_options = (\n        b\"8\\001\"\n    )\n    _FIPAMESSAGE_INFORM_PERFORMATIVE_INFOENTRY._options = None\n    _FIPAMESSAGE_INFORM_PERFORMATIVE_INFOENTRY._serialized_options = b\"8\\001\"\n    _FIPAMESSAGE._serialized_start = 40\n    _FIPAMESSAGE._serialized_end = 1645\n    _FIPAMESSAGE_DESCRIPTION._serialized_start = 791\n    _FIPAMESSAGE_DESCRIPTION._serialized_end = 831\n    _FIPAMESSAGE_QUERY._serialized_start = 833\n    _FIPAMESSAGE_QUERY._serialized_end = 861\n    _FIPAMESSAGE_CFP_PERFORMATIVE._serialized_start = 863\n    _FIPAMESSAGE_CFP_PERFORMATIVE._serialized_end = 940\n    _FIPAMESSAGE_PROPOSE_PERFORMATIVE._serialized_start = 942\n    _FIPAMESSAGE_PROPOSE_PERFORMATIVE._serialized_end = 1032\n    _FIPAMESSAGE_ACCEPT_W_INFORM_PERFORMATIVE._serialized_start = 1035\n    _FIPAMESSAGE_ACCEPT_W_INFORM_PERFORMATIVE._serialized_end = 1201\n    _FIPAMESSAGE_ACCEPT_W_INFORM_PERFORMATIVE_INFOENTRY._serialized_start = 1158\n    _FIPAMESSAGE_ACCEPT_W_INFORM_PERFORMATIVE_INFOENTRY._serialized_end = 1201\n    _FIPAMESSAGE_MATCH_ACCEPT_W_INFORM_PERFORMATIVE._serialized_start = 1204\n    _FIPAMESSAGE_MATCH_ACCEPT_W_INFORM_PERFORMATIVE._serialized_end = 1382\n    _FIPAMESSAGE_MATCH_ACCEPT_W_INFORM_PERFORMATIVE_INFOENTRY._serialized_start = 1158\n    _FIPAMESSAGE_MATCH_ACCEPT_W_INFORM_PERFORMATIVE_INFOENTRY._serialized_end = 1201\n    _FIPAMESSAGE_INFORM_PERFORMATIVE._serialized_start = 1385\n    _FIPAMESSAGE_INFORM_PERFORMATIVE._serialized_end = 1533\n    _FIPAMESSAGE_INFORM_PERFORMATIVE_INFOENTRY._serialized_start = 1158\n    _FIPAMESSAGE_INFORM_PERFORMATIVE_INFOENTRY._serialized_end = 1201\n    _FIPAMESSAGE_ACCEPT_PERFORMATIVE._serialized_start = 1535\n    _FIPAMESSAGE_ACCEPT_PERFORMATIVE._serialized_end = 1556\n    _FIPAMESSAGE_DECLINE_PERFORMATIVE._serialized_start = 1558\n    _FIPAMESSAGE_DECLINE_PERFORMATIVE._serialized_end = 1580\n    _FIPAMESSAGE_MATCH_ACCEPT_PERFORMATIVE._serialized_start = 1582\n    _FIPAMESSAGE_MATCH_ACCEPT_PERFORMATIVE._serialized_end = 1609\n    _FIPAMESSAGE_END_PERFORMATIVE._serialized_start = 1611\n    _FIPAMESSAGE_END_PERFORMATIVE._serialized_end = 1629\n# @@protoc_insertion_point(module_scope)\n"
  },
  {
    "path": "packages/fetchai/protocols/fipa/message.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains fipa's message definition.\"\"\"\n\n# pylint: disable=too-many-statements,too-many-locals,no-member,too-few-public-methods,too-many-branches,not-an-iterable,unidiomatic-typecheck,unsubscriptable-object\nimport logging\nfrom typing import Any, Dict, Set, Tuple, cast\n\nfrom aea.configurations.base import PublicId\nfrom aea.exceptions import AEAEnforceError, enforce\nfrom aea.protocols.base import Message\n\nfrom packages.fetchai.protocols.fipa.custom_types import (\n    Description as CustomDescription,\n)\nfrom packages.fetchai.protocols.fipa.custom_types import Query as CustomQuery\n\n\n_default_logger = logging.getLogger(\"aea.packages.fetchai.protocols.fipa.message\")\n\nDEFAULT_BODY_SIZE = 4\n\n\nclass FipaMessage(Message):\n    \"\"\"A protocol for FIPA ACL.\"\"\"\n\n    protocol_id = PublicId.from_str(\"fetchai/fipa:1.1.7\")\n    protocol_specification_id = PublicId.from_str(\"fetchai/fipa:1.0.0\")\n\n    Description = CustomDescription\n\n    Query = CustomQuery\n\n    class Performative(Message.Performative):\n        \"\"\"Performatives for the fipa protocol.\"\"\"\n\n        ACCEPT = \"accept\"\n        ACCEPT_W_INFORM = \"accept_w_inform\"\n        CFP = \"cfp\"\n        DECLINE = \"decline\"\n        END = \"end\"\n        INFORM = \"inform\"\n        MATCH_ACCEPT = \"match_accept\"\n        MATCH_ACCEPT_W_INFORM = \"match_accept_w_inform\"\n        PROPOSE = \"propose\"\n\n        def __str__(self) -> str:\n            \"\"\"Get the string representation.\"\"\"\n            return str(self.value)\n\n    _performatives = {\n        \"accept\",\n        \"accept_w_inform\",\n        \"cfp\",\n        \"decline\",\n        \"end\",\n        \"inform\",\n        \"match_accept\",\n        \"match_accept_w_inform\",\n        \"propose\",\n    }\n    __slots__: Tuple[str, ...] = tuple()\n\n    class _SlotsCls:\n        __slots__ = (\n            \"dialogue_reference\",\n            \"info\",\n            \"message_id\",\n            \"performative\",\n            \"proposal\",\n            \"query\",\n            \"target\",\n        )\n\n    def __init__(\n        self,\n        performative: Performative,\n        dialogue_reference: Tuple[str, str] = (\"\", \"\"),\n        message_id: int = 1,\n        target: int = 0,\n        **kwargs: Any,\n    ):\n        \"\"\"\n        Initialise an instance of FipaMessage.\n\n        :param message_id: the message id.\n        :param dialogue_reference: the dialogue reference.\n        :param target: the message target.\n        :param performative: the message performative.\n        :param **kwargs: extra options.\n        \"\"\"\n        super().__init__(\n            dialogue_reference=dialogue_reference,\n            message_id=message_id,\n            target=target,\n            performative=FipaMessage.Performative(performative),\n            **kwargs,\n        )\n\n    @property\n    def valid_performatives(self) -> Set[str]:\n        \"\"\"Get valid performatives.\"\"\"\n        return self._performatives\n\n    @property\n    def dialogue_reference(self) -> Tuple[str, str]:\n        \"\"\"Get the dialogue_reference of the message.\"\"\"\n        enforce(self.is_set(\"dialogue_reference\"), \"dialogue_reference is not set.\")\n        return cast(Tuple[str, str], self.get(\"dialogue_reference\"))\n\n    @property\n    def message_id(self) -> int:\n        \"\"\"Get the message_id of the message.\"\"\"\n        enforce(self.is_set(\"message_id\"), \"message_id is not set.\")\n        return cast(int, self.get(\"message_id\"))\n\n    @property\n    def performative(self) -> Performative:  # type: ignore # noqa: F821\n        \"\"\"Get the performative of the message.\"\"\"\n        enforce(self.is_set(\"performative\"), \"performative is not set.\")\n        return cast(FipaMessage.Performative, self.get(\"performative\"))\n\n    @property\n    def target(self) -> int:\n        \"\"\"Get the target of the message.\"\"\"\n        enforce(self.is_set(\"target\"), \"target is not set.\")\n        return cast(int, self.get(\"target\"))\n\n    @property\n    def info(self) -> Dict[str, str]:\n        \"\"\"Get the 'info' content from the message.\"\"\"\n        enforce(self.is_set(\"info\"), \"'info' content is not set.\")\n        return cast(Dict[str, str], self.get(\"info\"))\n\n    @property\n    def proposal(self) -> CustomDescription:\n        \"\"\"Get the 'proposal' content from the message.\"\"\"\n        enforce(self.is_set(\"proposal\"), \"'proposal' content is not set.\")\n        return cast(CustomDescription, self.get(\"proposal\"))\n\n    @property\n    def query(self) -> CustomQuery:\n        \"\"\"Get the 'query' content from the message.\"\"\"\n        enforce(self.is_set(\"query\"), \"'query' content is not set.\")\n        return cast(CustomQuery, self.get(\"query\"))\n\n    def _is_consistent(self) -> bool:\n        \"\"\"Check that the message follows the fipa protocol.\"\"\"\n        try:\n            enforce(\n                isinstance(self.dialogue_reference, tuple),\n                \"Invalid type for 'dialogue_reference'. Expected 'tuple'. Found '{}'.\".format(\n                    type(self.dialogue_reference)\n                ),\n            )\n            enforce(\n                isinstance(self.dialogue_reference[0], str),\n                \"Invalid type for 'dialogue_reference[0]'. Expected 'str'. Found '{}'.\".format(\n                    type(self.dialogue_reference[0])\n                ),\n            )\n            enforce(\n                isinstance(self.dialogue_reference[1], str),\n                \"Invalid type for 'dialogue_reference[1]'. Expected 'str'. Found '{}'.\".format(\n                    type(self.dialogue_reference[1])\n                ),\n            )\n            enforce(\n                type(self.message_id) is int,\n                \"Invalid type for 'message_id'. Expected 'int'. Found '{}'.\".format(\n                    type(self.message_id)\n                ),\n            )\n            enforce(\n                type(self.target) is int,\n                \"Invalid type for 'target'. Expected 'int'. Found '{}'.\".format(\n                    type(self.target)\n                ),\n            )\n\n            # Light Protocol Rule 2\n            # Check correct performative\n            enforce(\n                isinstance(self.performative, FipaMessage.Performative),\n                \"Invalid 'performative'. Expected either of '{}'. Found '{}'.\".format(\n                    self.valid_performatives, self.performative\n                ),\n            )\n\n            # Check correct contents\n            actual_nb_of_contents = len(self._body) - DEFAULT_BODY_SIZE\n            expected_nb_of_contents = 0\n            if self.performative == FipaMessage.Performative.CFP:\n                expected_nb_of_contents = 1\n                enforce(\n                    isinstance(self.query, CustomQuery),\n                    \"Invalid type for content 'query'. Expected 'Query'. Found '{}'.\".format(\n                        type(self.query)\n                    ),\n                )\n            elif self.performative == FipaMessage.Performative.PROPOSE:\n                expected_nb_of_contents = 1\n                enforce(\n                    isinstance(self.proposal, CustomDescription),\n                    \"Invalid type for content 'proposal'. Expected 'Description'. Found '{}'.\".format(\n                        type(self.proposal)\n                    ),\n                )\n            elif self.performative == FipaMessage.Performative.ACCEPT_W_INFORM:\n                expected_nb_of_contents = 1\n                enforce(\n                    isinstance(self.info, dict),\n                    \"Invalid type for content 'info'. Expected 'dict'. Found '{}'.\".format(\n                        type(self.info)\n                    ),\n                )\n                for key_of_info, value_of_info in self.info.items():\n                    enforce(\n                        isinstance(key_of_info, str),\n                        \"Invalid type for dictionary keys in content 'info'. Expected 'str'. Found '{}'.\".format(\n                            type(key_of_info)\n                        ),\n                    )\n                    enforce(\n                        isinstance(value_of_info, str),\n                        \"Invalid type for dictionary values in content 'info'. Expected 'str'. Found '{}'.\".format(\n                            type(value_of_info)\n                        ),\n                    )\n            elif self.performative == FipaMessage.Performative.MATCH_ACCEPT_W_INFORM:\n                expected_nb_of_contents = 1\n                enforce(\n                    isinstance(self.info, dict),\n                    \"Invalid type for content 'info'. Expected 'dict'. Found '{}'.\".format(\n                        type(self.info)\n                    ),\n                )\n                for key_of_info, value_of_info in self.info.items():\n                    enforce(\n                        isinstance(key_of_info, str),\n                        \"Invalid type for dictionary keys in content 'info'. Expected 'str'. Found '{}'.\".format(\n                            type(key_of_info)\n                        ),\n                    )\n                    enforce(\n                        isinstance(value_of_info, str),\n                        \"Invalid type for dictionary values in content 'info'. Expected 'str'. Found '{}'.\".format(\n                            type(value_of_info)\n                        ),\n                    )\n            elif self.performative == FipaMessage.Performative.INFORM:\n                expected_nb_of_contents = 1\n                enforce(\n                    isinstance(self.info, dict),\n                    \"Invalid type for content 'info'. Expected 'dict'. Found '{}'.\".format(\n                        type(self.info)\n                    ),\n                )\n                for key_of_info, value_of_info in self.info.items():\n                    enforce(\n                        isinstance(key_of_info, str),\n                        \"Invalid type for dictionary keys in content 'info'. Expected 'str'. Found '{}'.\".format(\n                            type(key_of_info)\n                        ),\n                    )\n                    enforce(\n                        isinstance(value_of_info, str),\n                        \"Invalid type for dictionary values in content 'info'. Expected 'str'. Found '{}'.\".format(\n                            type(value_of_info)\n                        ),\n                    )\n            elif self.performative == FipaMessage.Performative.ACCEPT:\n                expected_nb_of_contents = 0\n            elif self.performative == FipaMessage.Performative.DECLINE:\n                expected_nb_of_contents = 0\n            elif self.performative == FipaMessage.Performative.MATCH_ACCEPT:\n                expected_nb_of_contents = 0\n            elif self.performative == FipaMessage.Performative.END:\n                expected_nb_of_contents = 0\n\n            # Check correct content count\n            enforce(\n                expected_nb_of_contents == actual_nb_of_contents,\n                \"Incorrect number of contents. Expected {}. Found {}\".format(\n                    expected_nb_of_contents, actual_nb_of_contents\n                ),\n            )\n\n            # Light Protocol Rule 3\n            if self.message_id == 1:\n                enforce(\n                    self.target == 0,\n                    \"Invalid 'target'. Expected 0 (because 'message_id' is 1). Found {}.\".format(\n                        self.target\n                    ),\n                )\n        except (AEAEnforceError, ValueError, KeyError) as e:\n            _default_logger.error(str(e))\n            return False\n\n        return True\n"
  },
  {
    "path": "packages/fetchai/protocols/fipa/protocol.yaml",
    "content": "name: fipa\nauthor: fetchai\nversion: 1.1.7\nprotocol_specification_id: fetchai/fipa:1.0.0\ntype: protocol\ndescription: A protocol for FIPA ACL.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: Qmb3nuPdF326cWYMVYJjqxdpGMkdR4ENFdCXbMEv9t7Doj\n  __init__.py: QmcKvopHYdkJwfnAYmgtPbUZZvcnP3bffhKjFWMXJFwno9\n  custom_types.py: QmNibpgi18PbM4drwbYxw18GwMkBAToh21EhKimnF3j7Sg\n  dialogues.py: QmS2o9G3AyW7n7R6Ec9n3KSSntMx5MrGARD3Ya67FDAa2s\n  fipa.proto: QmS7aXZ2JoG3oyMHWiPYoP9RJ7iChsoTC9KQLsj6vi3ejR\n  fipa_pb2.py: QmT6CxDiwyz3ucsNxZSxtNZXE9NThshV68zvXEYtiWjEUP\n  message.py: QmZKYP3yu7KRRxJsip9FKbuuW91FUwnDuVsFTaxqeuccuT\n  serialization.py: QmUHydPjLVt5B4JAoN3XccNieB3EFiUoMzvs2N9UQmZXJZ\nfingerprint_ignore_patterns: []\ndependencies:\n  protobuf: {}\n"
  },
  {
    "path": "packages/fetchai/protocols/fipa/serialization.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Serialization module for fipa protocol.\"\"\"\n\n# pylint: disable=too-many-statements,too-many-locals,no-member,too-few-public-methods,redefined-builtin\nfrom typing import Any, Dict, cast\n\nfrom aea.mail.base_pb2 import DialogueMessage\nfrom aea.mail.base_pb2 import Message as ProtobufMessage\nfrom aea.protocols.base import Message, Serializer\n\nfrom packages.fetchai.protocols.fipa import fipa_pb2\nfrom packages.fetchai.protocols.fipa.custom_types import Description, Query\nfrom packages.fetchai.protocols.fipa.message import FipaMessage\n\n\nclass FipaSerializer(Serializer):\n    \"\"\"Serialization for the 'fipa' protocol.\"\"\"\n\n    @staticmethod\n    def encode(msg: Message) -> bytes:\n        \"\"\"\n        Encode a 'Fipa' message into bytes.\n\n        :param msg: the message object.\n        :return: the bytes.\n        \"\"\"\n        msg = cast(FipaMessage, msg)\n        message_pb = ProtobufMessage()\n        dialogue_message_pb = DialogueMessage()\n        fipa_msg = fipa_pb2.FipaMessage()\n\n        dialogue_message_pb.message_id = msg.message_id\n        dialogue_reference = msg.dialogue_reference\n        dialogue_message_pb.dialogue_starter_reference = dialogue_reference[0]\n        dialogue_message_pb.dialogue_responder_reference = dialogue_reference[1]\n        dialogue_message_pb.target = msg.target\n\n        performative_id = msg.performative\n        if performative_id == FipaMessage.Performative.CFP:\n            performative = fipa_pb2.FipaMessage.Cfp_Performative()  # type: ignore\n            query = msg.query\n            Query.encode(performative.query, query)\n            fipa_msg.cfp.CopyFrom(performative)\n        elif performative_id == FipaMessage.Performative.PROPOSE:\n            performative = fipa_pb2.FipaMessage.Propose_Performative()  # type: ignore\n            proposal = msg.proposal\n            Description.encode(performative.proposal, proposal)\n            fipa_msg.propose.CopyFrom(performative)\n        elif performative_id == FipaMessage.Performative.ACCEPT_W_INFORM:\n            performative = fipa_pb2.FipaMessage.Accept_W_Inform_Performative()  # type: ignore\n            info = msg.info\n            performative.info.update(info)\n            fipa_msg.accept_w_inform.CopyFrom(performative)\n        elif performative_id == FipaMessage.Performative.MATCH_ACCEPT_W_INFORM:\n            performative = fipa_pb2.FipaMessage.Match_Accept_W_Inform_Performative()  # type: ignore\n            info = msg.info\n            performative.info.update(info)\n            fipa_msg.match_accept_w_inform.CopyFrom(performative)\n        elif performative_id == FipaMessage.Performative.INFORM:\n            performative = fipa_pb2.FipaMessage.Inform_Performative()  # type: ignore\n            info = msg.info\n            performative.info.update(info)\n            fipa_msg.inform.CopyFrom(performative)\n        elif performative_id == FipaMessage.Performative.ACCEPT:\n            performative = fipa_pb2.FipaMessage.Accept_Performative()  # type: ignore\n            fipa_msg.accept.CopyFrom(performative)\n        elif performative_id == FipaMessage.Performative.DECLINE:\n            performative = fipa_pb2.FipaMessage.Decline_Performative()  # type: ignore\n            fipa_msg.decline.CopyFrom(performative)\n        elif performative_id == FipaMessage.Performative.MATCH_ACCEPT:\n            performative = fipa_pb2.FipaMessage.Match_Accept_Performative()  # type: ignore\n            fipa_msg.match_accept.CopyFrom(performative)\n        elif performative_id == FipaMessage.Performative.END:\n            performative = fipa_pb2.FipaMessage.End_Performative()  # type: ignore\n            fipa_msg.end.CopyFrom(performative)\n        else:\n            raise ValueError(\"Performative not valid: {}\".format(performative_id))\n\n        dialogue_message_pb.content = fipa_msg.SerializeToString()\n\n        message_pb.dialogue_message.CopyFrom(dialogue_message_pb)\n        message_bytes = message_pb.SerializeToString()\n        return message_bytes\n\n    @staticmethod\n    def decode(obj: bytes) -> Message:\n        \"\"\"\n        Decode bytes into a 'Fipa' message.\n\n        :param obj: the bytes object.\n        :return: the 'Fipa' message.\n        \"\"\"\n        message_pb = ProtobufMessage()\n        fipa_pb = fipa_pb2.FipaMessage()\n        message_pb.ParseFromString(obj)\n        message_id = message_pb.dialogue_message.message_id\n        dialogue_reference = (\n            message_pb.dialogue_message.dialogue_starter_reference,\n            message_pb.dialogue_message.dialogue_responder_reference,\n        )\n        target = message_pb.dialogue_message.target\n\n        fipa_pb.ParseFromString(message_pb.dialogue_message.content)\n        performative = fipa_pb.WhichOneof(\"performative\")\n        performative_id = FipaMessage.Performative(str(performative))\n        performative_content = {}  # type: Dict[str, Any]\n        if performative_id == FipaMessage.Performative.CFP:\n            pb2_query = fipa_pb.cfp.query\n            query = Query.decode(pb2_query)\n            performative_content[\"query\"] = query\n        elif performative_id == FipaMessage.Performative.PROPOSE:\n            pb2_proposal = fipa_pb.propose.proposal\n            proposal = Description.decode(pb2_proposal)\n            performative_content[\"proposal\"] = proposal\n        elif performative_id == FipaMessage.Performative.ACCEPT_W_INFORM:\n            info = fipa_pb.accept_w_inform.info\n            info_dict = dict(info)\n            performative_content[\"info\"] = info_dict\n        elif performative_id == FipaMessage.Performative.MATCH_ACCEPT_W_INFORM:\n            info = fipa_pb.match_accept_w_inform.info\n            info_dict = dict(info)\n            performative_content[\"info\"] = info_dict\n        elif performative_id == FipaMessage.Performative.INFORM:\n            info = fipa_pb.inform.info\n            info_dict = dict(info)\n            performative_content[\"info\"] = info_dict\n        elif performative_id == FipaMessage.Performative.ACCEPT:\n            pass\n        elif performative_id == FipaMessage.Performative.DECLINE:\n            pass\n        elif performative_id == FipaMessage.Performative.MATCH_ACCEPT:\n            pass\n        elif performative_id == FipaMessage.Performative.END:\n            pass\n        else:\n            raise ValueError(\"Performative not valid: {}.\".format(performative_id))\n\n        return FipaMessage(\n            message_id=message_id,\n            dialogue_reference=dialogue_reference,\n            target=target,\n            performative=performative,\n            **performative_content\n        )\n"
  },
  {
    "path": "packages/fetchai/protocols/gym/README.md",
    "content": "# Gym Protocol\n\n## Description\n\nThis is a protocol for interacting with a gym connection.\n\n## Specification\n\n```yaml\n---\nname: gym\nauthor: fetchai\nversion: 1.1.7\ndescription: A protocol for interacting with a gym connection.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nprotocol_specification_id: fetchai/gym:1.0.0\nspeech_acts:\n  act:\n    action: ct:AnyObject\n    step_id: pt:int\n  percept:\n    step_id: pt:int\n    observation: ct:AnyObject\n    reward: pt:float\n    done: pt:bool\n    info: ct:AnyObject\n  status:\n    content: pt:dict[pt:str, pt:str]\n  reset: {}\n  close: {}\n...\n---\nct:AnyObject: |\n  bytes any = 1;\n...\n---\ninitiation: [reset]\nreply:\n  reset: [status]\n  status: [act, close, reset]\n  act: [percept]\n  percept: [act, close, reset]\n  close: []\ntermination: [close]\nroles: {agent, environment}\nend_states: [successful]\nkeep_terminal_state_dialogues: false\n...\n```\n\n## Links\n\n- <a href=\"https://gym.openai.com\" target=\"_blank\">OpenAI Gym</a>\n"
  },
  {
    "path": "packages/fetchai/protocols/gym/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nThis module contains the support resources for the gym protocol.\n\nIt was created with protocol buffer compiler version `libprotoc 3.19.4` and aea version `1.2.5`.\n\"\"\"\n\nfrom packages.fetchai.protocols.gym.message import GymMessage\nfrom packages.fetchai.protocols.gym.serialization import GymSerializer\n\n\nGymMessage.serializer = GymSerializer\n"
  },
  {
    "path": "packages/fetchai/protocols/gym/custom_types.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains class representations corresponding to every custom type in the protocol specification.\"\"\"\n\nimport pickle  # nosec\nfrom typing import Any\n\n\nclass AnyObject:\n    \"\"\"This class represents an instance of AnyObject.\"\"\"\n\n    __slots__ = (\"any\",)\n\n    def __init__(self, _any: Any):\n        \"\"\"Initialise an instance of AnyObject.\"\"\"\n        self.any = _any\n\n    @staticmethod\n    def encode(any_object_protobuf_object: Any, any_object_object: \"AnyObject\") -> None:\n        \"\"\"\n        Encode an instance of this class into the protocol buffer object.\n\n        The protocol buffer object in the any_object_protobuf_object argument is matched with the instance of this class in the 'any_object_object' argument.\n\n        :param any_object_protobuf_object: the protocol buffer object whose type corresponds with this class.\n        :param any_object_object: an instance of this class to be encoded in the protocol buffer object.\n        \"\"\"\n        any_object_protobuf_object.any = pickle.dumps(any_object_object)  # nosec\n\n    @classmethod\n    def decode(cls, any_object_protobuf_object: Any) -> \"AnyObject\":\n        \"\"\"\n        Decode a protocol buffer object that corresponds with this class into an instance of this class.\n\n        A new instance of this class is created that matches the protocol buffer object in the 'any_object_protobuf_object' argument.\n\n        :param any_object_protobuf_object: the protocol buffer object whose type corresponds with this class.\n        :return: A new instance of this class that matches the protocol buffer object in the 'any_object_protobuf_object' argument.\n        \"\"\"\n        return pickle.loads(any_object_protobuf_object.any)  # nosec\n\n    def __eq__(self, other: Any) -> bool:\n        \"\"\"Check equality.\"\"\"\n        return self.any == other.any\n"
  },
  {
    "path": "packages/fetchai/protocols/gym/dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nThis module contains the classes required for gym dialogue management.\n\n- GymDialogue: The dialogue class maintains state of a dialogue and manages it.\n- GymDialogues: The dialogues class keeps track of all dialogues.\n\"\"\"\n\nfrom abc import ABC\nfrom typing import Callable, Dict, FrozenSet, Type, cast\n\nfrom aea.common import Address\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue, DialogueLabel, Dialogues\n\nfrom packages.fetchai.protocols.gym.message import GymMessage\n\n\nclass GymDialogue(Dialogue):\n    \"\"\"The gym dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    INITIAL_PERFORMATIVES: FrozenSet[Message.Performative] = frozenset(\n        {GymMessage.Performative.RESET}\n    )\n    TERMINAL_PERFORMATIVES: FrozenSet[Message.Performative] = frozenset(\n        {GymMessage.Performative.CLOSE}\n    )\n    VALID_REPLIES: Dict[Message.Performative, FrozenSet[Message.Performative]] = {\n        GymMessage.Performative.ACT: frozenset({GymMessage.Performative.PERCEPT}),\n        GymMessage.Performative.CLOSE: frozenset(),\n        GymMessage.Performative.PERCEPT: frozenset(\n            {\n                GymMessage.Performative.ACT,\n                GymMessage.Performative.CLOSE,\n                GymMessage.Performative.RESET,\n            }\n        ),\n        GymMessage.Performative.RESET: frozenset({GymMessage.Performative.STATUS}),\n        GymMessage.Performative.STATUS: frozenset(\n            {\n                GymMessage.Performative.ACT,\n                GymMessage.Performative.CLOSE,\n                GymMessage.Performative.RESET,\n            }\n        ),\n    }\n\n    class Role(Dialogue.Role):\n        \"\"\"This class defines the agent's role in a gym dialogue.\"\"\"\n\n        AGENT = \"agent\"\n        ENVIRONMENT = \"environment\"\n\n    class EndState(Dialogue.EndState):\n        \"\"\"This class defines the end states of a gym dialogue.\"\"\"\n\n        SUCCESSFUL = 0\n\n    def __init__(\n        self,\n        dialogue_label: DialogueLabel,\n        self_address: Address,\n        role: Dialogue.Role,\n        message_class: Type[GymMessage] = GymMessage,\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n        :param message_class: the message class used\n        \"\"\"\n        Dialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            message_class=message_class,\n            self_address=self_address,\n            role=role,\n        )\n\n\nclass GymDialogues(Dialogues, ABC):\n    \"\"\"This class keeps track of all gym dialogues.\"\"\"\n\n    END_STATES = frozenset({GymDialogue.EndState.SUCCESSFUL})\n\n    _keep_terminal_state_dialogues = False\n\n    def __init__(\n        self,\n        self_address: Address,\n        role_from_first_message: Callable[[Message, Address], Dialogue.Role],\n        dialogue_class: Type[GymDialogue] = GymDialogue,\n    ) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param self_address: the address of the entity for whom dialogues are maintained\n        :param dialogue_class: the dialogue class used\n        :param role_from_first_message: the callable determining role from first message\n        \"\"\"\n        Dialogues.__init__(\n            self,\n            self_address=self_address,\n            end_states=cast(FrozenSet[Dialogue.EndState], self.END_STATES),\n            message_class=GymMessage,\n            dialogue_class=dialogue_class,\n            role_from_first_message=role_from_first_message,\n        )\n"
  },
  {
    "path": "packages/fetchai/protocols/gym/gym.proto",
    "content": "syntax = \"proto3\";\n\npackage aea.fetchai.gym.v1_0_0;\n\nmessage GymMessage{\n\n  // Custom Types\n  message AnyObject{\n    bytes any = 1;\n  }\n\n\n  // Performatives and contents\n  message Act_Performative{\n    AnyObject action = 1;\n    int64 step_id = 2;\n  }\n\n  message Percept_Performative{\n    int64 step_id = 1;\n    AnyObject observation = 2;\n    float reward = 3;\n    bool done = 4;\n    AnyObject info = 5;\n  }\n\n  message Status_Performative{\n    map<string, string> content = 1;\n  }\n\n  message Reset_Performative{\n  }\n\n  message Close_Performative{\n  }\n\n\n  oneof performative{\n    Act_Performative act = 5;\n    Close_Performative close = 6;\n    Percept_Performative percept = 7;\n    Reset_Performative reset = 8;\n    Status_Performative status = 9;\n  }\n}\n"
  },
  {
    "path": "packages/fetchai/protocols/gym/gym_pb2.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by the protocol buffer compiler.  DO NOT EDIT!\n# source: gym.proto\n\"\"\"Generated protocol buffer code.\"\"\"\nfrom google.protobuf import descriptor as _descriptor\nfrom google.protobuf import descriptor_pool as _descriptor_pool\nfrom google.protobuf import message as _message\nfrom google.protobuf import reflection as _reflection\nfrom google.protobuf import symbol_database as _symbol_database\n\n# @@protoc_insertion_point(imports)\n\n_sym_db = _symbol_database.Default()\n\n\nDESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(\n    b'\\n\\tgym.proto\\x12\\x16\\x61\\x65\\x61.fetchai.gym.v1_0_0\"\\x94\\x07\\n\\nGymMessage\\x12\\x42\\n\\x03\\x61\\x63t\\x18\\x05 \\x01(\\x0b\\x32\\x33.aea.fetchai.gym.v1_0_0.GymMessage.Act_PerformativeH\\x00\\x12\\x46\\n\\x05\\x63lose\\x18\\x06 \\x01(\\x0b\\x32\\x35.aea.fetchai.gym.v1_0_0.GymMessage.Close_PerformativeH\\x00\\x12J\\n\\x07percept\\x18\\x07 \\x01(\\x0b\\x32\\x37.aea.fetchai.gym.v1_0_0.GymMessage.Percept_PerformativeH\\x00\\x12\\x46\\n\\x05reset\\x18\\x08 \\x01(\\x0b\\x32\\x35.aea.fetchai.gym.v1_0_0.GymMessage.Reset_PerformativeH\\x00\\x12H\\n\\x06status\\x18\\t \\x01(\\x0b\\x32\\x36.aea.fetchai.gym.v1_0_0.GymMessage.Status_PerformativeH\\x00\\x1a\\x18\\n\\tAnyObject\\x12\\x0b\\n\\x03\\x61ny\\x18\\x01 \\x01(\\x0c\\x1a\\x61\\n\\x10\\x41\\x63t_Performative\\x12<\\n\\x06\\x61\\x63tion\\x18\\x01 \\x01(\\x0b\\x32,.aea.fetchai.gym.v1_0_0.GymMessage.AnyObject\\x12\\x0f\\n\\x07step_id\\x18\\x02 \\x01(\\x03\\x1a\\xc4\\x01\\n\\x14Percept_Performative\\x12\\x0f\\n\\x07step_id\\x18\\x01 \\x01(\\x03\\x12\\x41\\n\\x0bobservation\\x18\\x02 \\x01(\\x0b\\x32,.aea.fetchai.gym.v1_0_0.GymMessage.AnyObject\\x12\\x0e\\n\\x06reward\\x18\\x03 \\x01(\\x02\\x12\\x0c\\n\\x04\\x64one\\x18\\x04 \\x01(\\x08\\x12:\\n\\x04info\\x18\\x05 \\x01(\\x0b\\x32,.aea.fetchai.gym.v1_0_0.GymMessage.AnyObject\\x1a\\x9b\\x01\\n\\x13Status_Performative\\x12T\\n\\x07\\x63ontent\\x18\\x01 \\x03(\\x0b\\x32\\x43.aea.fetchai.gym.v1_0_0.GymMessage.Status_Performative.ContentEntry\\x1a.\\n\\x0c\\x43ontentEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\t\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\t:\\x02\\x38\\x01\\x1a\\x14\\n\\x12Reset_Performative\\x1a\\x14\\n\\x12\\x43lose_PerformativeB\\x0e\\n\\x0cperformativeb\\x06proto3'\n)\n\n\n_GYMMESSAGE = DESCRIPTOR.message_types_by_name[\"GymMessage\"]\n_GYMMESSAGE_ANYOBJECT = _GYMMESSAGE.nested_types_by_name[\"AnyObject\"]\n_GYMMESSAGE_ACT_PERFORMATIVE = _GYMMESSAGE.nested_types_by_name[\"Act_Performative\"]\n_GYMMESSAGE_PERCEPT_PERFORMATIVE = _GYMMESSAGE.nested_types_by_name[\n    \"Percept_Performative\"\n]\n_GYMMESSAGE_STATUS_PERFORMATIVE = _GYMMESSAGE.nested_types_by_name[\n    \"Status_Performative\"\n]\n_GYMMESSAGE_STATUS_PERFORMATIVE_CONTENTENTRY = (\n    _GYMMESSAGE_STATUS_PERFORMATIVE.nested_types_by_name[\"ContentEntry\"]\n)\n_GYMMESSAGE_RESET_PERFORMATIVE = _GYMMESSAGE.nested_types_by_name[\"Reset_Performative\"]\n_GYMMESSAGE_CLOSE_PERFORMATIVE = _GYMMESSAGE.nested_types_by_name[\"Close_Performative\"]\nGymMessage = _reflection.GeneratedProtocolMessageType(\n    \"GymMessage\",\n    (_message.Message,),\n    {\n        \"AnyObject\": _reflection.GeneratedProtocolMessageType(\n            \"AnyObject\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _GYMMESSAGE_ANYOBJECT,\n                \"__module__\": \"gym_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.gym.v1_0_0.GymMessage.AnyObject)\n            },\n        ),\n        \"Act_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Act_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _GYMMESSAGE_ACT_PERFORMATIVE,\n                \"__module__\": \"gym_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.gym.v1_0_0.GymMessage.Act_Performative)\n            },\n        ),\n        \"Percept_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Percept_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _GYMMESSAGE_PERCEPT_PERFORMATIVE,\n                \"__module__\": \"gym_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.gym.v1_0_0.GymMessage.Percept_Performative)\n            },\n        ),\n        \"Status_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Status_Performative\",\n            (_message.Message,),\n            {\n                \"ContentEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"ContentEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _GYMMESSAGE_STATUS_PERFORMATIVE_CONTENTENTRY,\n                        \"__module__\": \"gym_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.fetchai.gym.v1_0_0.GymMessage.Status_Performative.ContentEntry)\n                    },\n                ),\n                \"DESCRIPTOR\": _GYMMESSAGE_STATUS_PERFORMATIVE,\n                \"__module__\": \"gym_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.gym.v1_0_0.GymMessage.Status_Performative)\n            },\n        ),\n        \"Reset_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Reset_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _GYMMESSAGE_RESET_PERFORMATIVE,\n                \"__module__\": \"gym_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.gym.v1_0_0.GymMessage.Reset_Performative)\n            },\n        ),\n        \"Close_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Close_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _GYMMESSAGE_CLOSE_PERFORMATIVE,\n                \"__module__\": \"gym_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.gym.v1_0_0.GymMessage.Close_Performative)\n            },\n        ),\n        \"DESCRIPTOR\": _GYMMESSAGE,\n        \"__module__\": \"gym_pb2\"\n        # @@protoc_insertion_point(class_scope:aea.fetchai.gym.v1_0_0.GymMessage)\n    },\n)\n_sym_db.RegisterMessage(GymMessage)\n_sym_db.RegisterMessage(GymMessage.AnyObject)\n_sym_db.RegisterMessage(GymMessage.Act_Performative)\n_sym_db.RegisterMessage(GymMessage.Percept_Performative)\n_sym_db.RegisterMessage(GymMessage.Status_Performative)\n_sym_db.RegisterMessage(GymMessage.Status_Performative.ContentEntry)\n_sym_db.RegisterMessage(GymMessage.Reset_Performative)\n_sym_db.RegisterMessage(GymMessage.Close_Performative)\n\nif _descriptor._USE_C_DESCRIPTORS == False:\n\n    DESCRIPTOR._options = None\n    _GYMMESSAGE_STATUS_PERFORMATIVE_CONTENTENTRY._options = None\n    _GYMMESSAGE_STATUS_PERFORMATIVE_CONTENTENTRY._serialized_options = b\"8\\001\"\n    _GYMMESSAGE._serialized_start = 38\n    _GYMMESSAGE._serialized_end = 954\n    _GYMMESSAGE_ANYOBJECT._serialized_start = 414\n    _GYMMESSAGE_ANYOBJECT._serialized_end = 438\n    _GYMMESSAGE_ACT_PERFORMATIVE._serialized_start = 440\n    _GYMMESSAGE_ACT_PERFORMATIVE._serialized_end = 537\n    _GYMMESSAGE_PERCEPT_PERFORMATIVE._serialized_start = 540\n    _GYMMESSAGE_PERCEPT_PERFORMATIVE._serialized_end = 736\n    _GYMMESSAGE_STATUS_PERFORMATIVE._serialized_start = 739\n    _GYMMESSAGE_STATUS_PERFORMATIVE._serialized_end = 894\n    _GYMMESSAGE_STATUS_PERFORMATIVE_CONTENTENTRY._serialized_start = 848\n    _GYMMESSAGE_STATUS_PERFORMATIVE_CONTENTENTRY._serialized_end = 894\n    _GYMMESSAGE_RESET_PERFORMATIVE._serialized_start = 896\n    _GYMMESSAGE_RESET_PERFORMATIVE._serialized_end = 916\n    _GYMMESSAGE_CLOSE_PERFORMATIVE._serialized_start = 918\n    _GYMMESSAGE_CLOSE_PERFORMATIVE._serialized_end = 938\n# @@protoc_insertion_point(module_scope)\n"
  },
  {
    "path": "packages/fetchai/protocols/gym/message.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains gym's message definition.\"\"\"\n\n# pylint: disable=too-many-statements,too-many-locals,no-member,too-few-public-methods,too-many-branches,not-an-iterable,unidiomatic-typecheck,unsubscriptable-object\nimport logging\nfrom typing import Any, Dict, Set, Tuple, cast\n\nfrom aea.configurations.base import PublicId\nfrom aea.exceptions import AEAEnforceError, enforce\nfrom aea.protocols.base import Message\n\nfrom packages.fetchai.protocols.gym.custom_types import AnyObject as CustomAnyObject\n\n\n_default_logger = logging.getLogger(\"aea.packages.fetchai.protocols.gym.message\")\n\nDEFAULT_BODY_SIZE = 4\n\n\nclass GymMessage(Message):\n    \"\"\"A protocol for interacting with a gym connection.\"\"\"\n\n    protocol_id = PublicId.from_str(\"fetchai/gym:1.1.7\")\n    protocol_specification_id = PublicId.from_str(\"fetchai/gym:1.0.0\")\n\n    AnyObject = CustomAnyObject\n\n    class Performative(Message.Performative):\n        \"\"\"Performatives for the gym protocol.\"\"\"\n\n        ACT = \"act\"\n        CLOSE = \"close\"\n        PERCEPT = \"percept\"\n        RESET = \"reset\"\n        STATUS = \"status\"\n\n        def __str__(self) -> str:\n            \"\"\"Get the string representation.\"\"\"\n            return str(self.value)\n\n    _performatives = {\"act\", \"close\", \"percept\", \"reset\", \"status\"}\n    __slots__: Tuple[str, ...] = tuple()\n\n    class _SlotsCls:\n        __slots__ = (\n            \"action\",\n            \"content\",\n            \"dialogue_reference\",\n            \"done\",\n            \"info\",\n            \"message_id\",\n            \"observation\",\n            \"performative\",\n            \"reward\",\n            \"step_id\",\n            \"target\",\n        )\n\n    def __init__(\n        self,\n        performative: Performative,\n        dialogue_reference: Tuple[str, str] = (\"\", \"\"),\n        message_id: int = 1,\n        target: int = 0,\n        **kwargs: Any,\n    ):\n        \"\"\"\n        Initialise an instance of GymMessage.\n\n        :param message_id: the message id.\n        :param dialogue_reference: the dialogue reference.\n        :param target: the message target.\n        :param performative: the message performative.\n        :param **kwargs: extra options.\n        \"\"\"\n        super().__init__(\n            dialogue_reference=dialogue_reference,\n            message_id=message_id,\n            target=target,\n            performative=GymMessage.Performative(performative),\n            **kwargs,\n        )\n\n    @property\n    def valid_performatives(self) -> Set[str]:\n        \"\"\"Get valid performatives.\"\"\"\n        return self._performatives\n\n    @property\n    def dialogue_reference(self) -> Tuple[str, str]:\n        \"\"\"Get the dialogue_reference of the message.\"\"\"\n        enforce(self.is_set(\"dialogue_reference\"), \"dialogue_reference is not set.\")\n        return cast(Tuple[str, str], self.get(\"dialogue_reference\"))\n\n    @property\n    def message_id(self) -> int:\n        \"\"\"Get the message_id of the message.\"\"\"\n        enforce(self.is_set(\"message_id\"), \"message_id is not set.\")\n        return cast(int, self.get(\"message_id\"))\n\n    @property\n    def performative(self) -> Performative:  # type: ignore # noqa: F821\n        \"\"\"Get the performative of the message.\"\"\"\n        enforce(self.is_set(\"performative\"), \"performative is not set.\")\n        return cast(GymMessage.Performative, self.get(\"performative\"))\n\n    @property\n    def target(self) -> int:\n        \"\"\"Get the target of the message.\"\"\"\n        enforce(self.is_set(\"target\"), \"target is not set.\")\n        return cast(int, self.get(\"target\"))\n\n    @property\n    def action(self) -> CustomAnyObject:\n        \"\"\"Get the 'action' content from the message.\"\"\"\n        enforce(self.is_set(\"action\"), \"'action' content is not set.\")\n        return cast(CustomAnyObject, self.get(\"action\"))\n\n    @property\n    def content(self) -> Dict[str, str]:\n        \"\"\"Get the 'content' content from the message.\"\"\"\n        enforce(self.is_set(\"content\"), \"'content' content is not set.\")\n        return cast(Dict[str, str], self.get(\"content\"))\n\n    @property\n    def done(self) -> bool:\n        \"\"\"Get the 'done' content from the message.\"\"\"\n        enforce(self.is_set(\"done\"), \"'done' content is not set.\")\n        return cast(bool, self.get(\"done\"))\n\n    @property\n    def info(self) -> CustomAnyObject:\n        \"\"\"Get the 'info' content from the message.\"\"\"\n        enforce(self.is_set(\"info\"), \"'info' content is not set.\")\n        return cast(CustomAnyObject, self.get(\"info\"))\n\n    @property\n    def observation(self) -> CustomAnyObject:\n        \"\"\"Get the 'observation' content from the message.\"\"\"\n        enforce(self.is_set(\"observation\"), \"'observation' content is not set.\")\n        return cast(CustomAnyObject, self.get(\"observation\"))\n\n    @property\n    def reward(self) -> float:\n        \"\"\"Get the 'reward' content from the message.\"\"\"\n        enforce(self.is_set(\"reward\"), \"'reward' content is not set.\")\n        return cast(float, self.get(\"reward\"))\n\n    @property\n    def step_id(self) -> int:\n        \"\"\"Get the 'step_id' content from the message.\"\"\"\n        enforce(self.is_set(\"step_id\"), \"'step_id' content is not set.\")\n        return cast(int, self.get(\"step_id\"))\n\n    def _is_consistent(self) -> bool:\n        \"\"\"Check that the message follows the gym protocol.\"\"\"\n        try:\n            enforce(\n                isinstance(self.dialogue_reference, tuple),\n                \"Invalid type for 'dialogue_reference'. Expected 'tuple'. Found '{}'.\".format(\n                    type(self.dialogue_reference)\n                ),\n            )\n            enforce(\n                isinstance(self.dialogue_reference[0], str),\n                \"Invalid type for 'dialogue_reference[0]'. Expected 'str'. Found '{}'.\".format(\n                    type(self.dialogue_reference[0])\n                ),\n            )\n            enforce(\n                isinstance(self.dialogue_reference[1], str),\n                \"Invalid type for 'dialogue_reference[1]'. Expected 'str'. Found '{}'.\".format(\n                    type(self.dialogue_reference[1])\n                ),\n            )\n            enforce(\n                type(self.message_id) is int,\n                \"Invalid type for 'message_id'. Expected 'int'. Found '{}'.\".format(\n                    type(self.message_id)\n                ),\n            )\n            enforce(\n                type(self.target) is int,\n                \"Invalid type for 'target'. Expected 'int'. Found '{}'.\".format(\n                    type(self.target)\n                ),\n            )\n\n            # Light Protocol Rule 2\n            # Check correct performative\n            enforce(\n                isinstance(self.performative, GymMessage.Performative),\n                \"Invalid 'performative'. Expected either of '{}'. Found '{}'.\".format(\n                    self.valid_performatives, self.performative\n                ),\n            )\n\n            # Check correct contents\n            actual_nb_of_contents = len(self._body) - DEFAULT_BODY_SIZE\n            expected_nb_of_contents = 0\n            if self.performative == GymMessage.Performative.ACT:\n                expected_nb_of_contents = 2\n                enforce(\n                    isinstance(self.action, CustomAnyObject),\n                    \"Invalid type for content 'action'. Expected 'AnyObject'. Found '{}'.\".format(\n                        type(self.action)\n                    ),\n                )\n                enforce(\n                    type(self.step_id) is int,\n                    \"Invalid type for content 'step_id'. Expected 'int'. Found '{}'.\".format(\n                        type(self.step_id)\n                    ),\n                )\n            elif self.performative == GymMessage.Performative.PERCEPT:\n                expected_nb_of_contents = 5\n                enforce(\n                    type(self.step_id) is int,\n                    \"Invalid type for content 'step_id'. Expected 'int'. Found '{}'.\".format(\n                        type(self.step_id)\n                    ),\n                )\n                enforce(\n                    isinstance(self.observation, CustomAnyObject),\n                    \"Invalid type for content 'observation'. Expected 'AnyObject'. Found '{}'.\".format(\n                        type(self.observation)\n                    ),\n                )\n                enforce(\n                    isinstance(self.reward, float),\n                    \"Invalid type for content 'reward'. Expected 'float'. Found '{}'.\".format(\n                        type(self.reward)\n                    ),\n                )\n                enforce(\n                    isinstance(self.done, bool),\n                    \"Invalid type for content 'done'. Expected 'bool'. Found '{}'.\".format(\n                        type(self.done)\n                    ),\n                )\n                enforce(\n                    isinstance(self.info, CustomAnyObject),\n                    \"Invalid type for content 'info'. Expected 'AnyObject'. Found '{}'.\".format(\n                        type(self.info)\n                    ),\n                )\n            elif self.performative == GymMessage.Performative.STATUS:\n                expected_nb_of_contents = 1\n                enforce(\n                    isinstance(self.content, dict),\n                    \"Invalid type for content 'content'. Expected 'dict'. Found '{}'.\".format(\n                        type(self.content)\n                    ),\n                )\n                for key_of_content, value_of_content in self.content.items():\n                    enforce(\n                        isinstance(key_of_content, str),\n                        \"Invalid type for dictionary keys in content 'content'. Expected 'str'. Found '{}'.\".format(\n                            type(key_of_content)\n                        ),\n                    )\n                    enforce(\n                        isinstance(value_of_content, str),\n                        \"Invalid type for dictionary values in content 'content'. Expected 'str'. Found '{}'.\".format(\n                            type(value_of_content)\n                        ),\n                    )\n            elif self.performative == GymMessage.Performative.RESET:\n                expected_nb_of_contents = 0\n            elif self.performative == GymMessage.Performative.CLOSE:\n                expected_nb_of_contents = 0\n\n            # Check correct content count\n            enforce(\n                expected_nb_of_contents == actual_nb_of_contents,\n                \"Incorrect number of contents. Expected {}. Found {}\".format(\n                    expected_nb_of_contents, actual_nb_of_contents\n                ),\n            )\n\n            # Light Protocol Rule 3\n            if self.message_id == 1:\n                enforce(\n                    self.target == 0,\n                    \"Invalid 'target'. Expected 0 (because 'message_id' is 1). Found {}.\".format(\n                        self.target\n                    ),\n                )\n        except (AEAEnforceError, ValueError, KeyError) as e:\n            _default_logger.error(str(e))\n            return False\n\n        return True\n"
  },
  {
    "path": "packages/fetchai/protocols/gym/protocol.yaml",
    "content": "name: gym\nauthor: fetchai\nversion: 1.1.7\nprotocol_specification_id: fetchai/gym:1.0.0\ntype: protocol\ndescription: A protocol for interacting with a gym connection.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: QmVpaTeAZL4HN37449d3KAPMQw9uY1gH1Apm9XDhZkfGmE\n  __init__.py: QmVpAS5VMF6ABFdnmthK6fbcuaLLEx94hebtVgaosTePTU\n  custom_types.py: QmX11ojHWTmPcEVWk8fzDiHdKwDQDccTLPYx8KoPiKiPPS\n  dialogues.py: QmTjYmokn1ayZYPSosarwJMpTPU4jAHfy4rftDgzcvNGLb\n  gym.proto: QmdCRYrHpG1AGzGfGAisbDZEJA2gdgJvhivtHqttTsQeYE\n  gym_pb2.py: QmXhaUyFbsLoKbHBK83SR6a9zvAGAsvWGu7tA2BTTyw26W\n  message.py: QmcCwF8uJpPACDTzcNS5SmgJV86uudxfNpvk4bHHoSvSqS\n  serialization.py: QmYf3hsqiLZ9NQcoSXaVypD11NPUFczXw9zi1EinRzv7hV\nfingerprint_ignore_patterns: []\ndependencies:\n  protobuf: {}\n"
  },
  {
    "path": "packages/fetchai/protocols/gym/serialization.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Serialization module for gym protocol.\"\"\"\n\n# pylint: disable=too-many-statements,too-many-locals,no-member,too-few-public-methods,redefined-builtin\nfrom typing import Any, Dict, cast\n\nfrom aea.mail.base_pb2 import DialogueMessage\nfrom aea.mail.base_pb2 import Message as ProtobufMessage\nfrom aea.protocols.base import Message, Serializer\n\nfrom packages.fetchai.protocols.gym import gym_pb2\nfrom packages.fetchai.protocols.gym.custom_types import AnyObject\nfrom packages.fetchai.protocols.gym.message import GymMessage\n\n\nclass GymSerializer(Serializer):\n    \"\"\"Serialization for the 'gym' protocol.\"\"\"\n\n    @staticmethod\n    def encode(msg: Message) -> bytes:\n        \"\"\"\n        Encode a 'Gym' message into bytes.\n\n        :param msg: the message object.\n        :return: the bytes.\n        \"\"\"\n        msg = cast(GymMessage, msg)\n        message_pb = ProtobufMessage()\n        dialogue_message_pb = DialogueMessage()\n        gym_msg = gym_pb2.GymMessage()\n\n        dialogue_message_pb.message_id = msg.message_id\n        dialogue_reference = msg.dialogue_reference\n        dialogue_message_pb.dialogue_starter_reference = dialogue_reference[0]\n        dialogue_message_pb.dialogue_responder_reference = dialogue_reference[1]\n        dialogue_message_pb.target = msg.target\n\n        performative_id = msg.performative\n        if performative_id == GymMessage.Performative.ACT:\n            performative = gym_pb2.GymMessage.Act_Performative()  # type: ignore\n            action = msg.action\n            AnyObject.encode(performative.action, action)\n            step_id = msg.step_id\n            performative.step_id = step_id\n            gym_msg.act.CopyFrom(performative)\n        elif performative_id == GymMessage.Performative.PERCEPT:\n            performative = gym_pb2.GymMessage.Percept_Performative()  # type: ignore\n            step_id = msg.step_id\n            performative.step_id = step_id\n            observation = msg.observation\n            AnyObject.encode(performative.observation, observation)\n            reward = msg.reward\n            performative.reward = reward\n            done = msg.done\n            performative.done = done\n            info = msg.info\n            AnyObject.encode(performative.info, info)\n            gym_msg.percept.CopyFrom(performative)\n        elif performative_id == GymMessage.Performative.STATUS:\n            performative = gym_pb2.GymMessage.Status_Performative()  # type: ignore\n            content = msg.content\n            performative.content.update(content)\n            gym_msg.status.CopyFrom(performative)\n        elif performative_id == GymMessage.Performative.RESET:\n            performative = gym_pb2.GymMessage.Reset_Performative()  # type: ignore\n            gym_msg.reset.CopyFrom(performative)\n        elif performative_id == GymMessage.Performative.CLOSE:\n            performative = gym_pb2.GymMessage.Close_Performative()  # type: ignore\n            gym_msg.close.CopyFrom(performative)\n        else:\n            raise ValueError(\"Performative not valid: {}\".format(performative_id))\n\n        dialogue_message_pb.content = gym_msg.SerializeToString()\n\n        message_pb.dialogue_message.CopyFrom(dialogue_message_pb)\n        message_bytes = message_pb.SerializeToString()\n        return message_bytes\n\n    @staticmethod\n    def decode(obj: bytes) -> Message:\n        \"\"\"\n        Decode bytes into a 'Gym' message.\n\n        :param obj: the bytes object.\n        :return: the 'Gym' message.\n        \"\"\"\n        message_pb = ProtobufMessage()\n        gym_pb = gym_pb2.GymMessage()\n        message_pb.ParseFromString(obj)\n        message_id = message_pb.dialogue_message.message_id\n        dialogue_reference = (\n            message_pb.dialogue_message.dialogue_starter_reference,\n            message_pb.dialogue_message.dialogue_responder_reference,\n        )\n        target = message_pb.dialogue_message.target\n\n        gym_pb.ParseFromString(message_pb.dialogue_message.content)\n        performative = gym_pb.WhichOneof(\"performative\")\n        performative_id = GymMessage.Performative(str(performative))\n        performative_content = {}  # type: Dict[str, Any]\n        if performative_id == GymMessage.Performative.ACT:\n            pb2_action = gym_pb.act.action\n            action = AnyObject.decode(pb2_action)\n            performative_content[\"action\"] = action\n            step_id = gym_pb.act.step_id\n            performative_content[\"step_id\"] = step_id\n        elif performative_id == GymMessage.Performative.PERCEPT:\n            step_id = gym_pb.percept.step_id\n            performative_content[\"step_id\"] = step_id\n            pb2_observation = gym_pb.percept.observation\n            observation = AnyObject.decode(pb2_observation)\n            performative_content[\"observation\"] = observation\n            reward = gym_pb.percept.reward\n            performative_content[\"reward\"] = reward\n            done = gym_pb.percept.done\n            performative_content[\"done\"] = done\n            pb2_info = gym_pb.percept.info\n            info = AnyObject.decode(pb2_info)\n            performative_content[\"info\"] = info\n        elif performative_id == GymMessage.Performative.STATUS:\n            content = gym_pb.status.content\n            content_dict = dict(content)\n            performative_content[\"content\"] = content_dict\n        elif performative_id == GymMessage.Performative.RESET:\n            pass\n        elif performative_id == GymMessage.Performative.CLOSE:\n            pass\n        else:\n            raise ValueError(\"Performative not valid: {}.\".format(performative_id))\n\n        return GymMessage(\n            message_id=message_id,\n            dialogue_reference=dialogue_reference,\n            target=target,\n            performative=performative,\n            **performative_content\n        )\n"
  },
  {
    "path": "packages/fetchai/protocols/http/README.md",
    "content": "# HTTP Protocol\n\n## Description\n\nThis is a protocol for interacting with a client/server via HTTP requests and responses.\n\n## Specification\n\n```yaml\n---\nname: http\nauthor: fetchai\nversion: 1.1.7\ndescription: A protocol for HTTP requests and responses.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nprotocol_specification_id: fetchai/http:1.0.0\nspeech_acts:\n  request:\n    method: pt:str\n    url: pt:str\n    version: pt:str\n    headers: pt:str\n    body: pt:bytes\n  response:\n    version: pt:str\n    status_code: pt:int\n    status_text: pt:str\n    headers: pt:str\n    body: pt:bytes\n...\n---\ninitiation: [request]\nreply:\n  request: [response]\n  response: []\ntermination: [response]\nroles: {client, server}\nend_states: [successful]\nkeep_terminal_state_dialogues: false\n...\n```\n\n## Links\n\n- <a href=\"https://www.w3.org/Protocols/rfc2616/rfc2616.html\" target=\"_blank\">HTTP Specification</a>\n"
  },
  {
    "path": "packages/fetchai/protocols/http/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nThis module contains the support resources for the http protocol.\n\nIt was created with protocol buffer compiler version `libprotoc 3.19.4` and aea version `1.2.5`.\n\"\"\"\n\nfrom packages.fetchai.protocols.http.message import HttpMessage\nfrom packages.fetchai.protocols.http.serialization import HttpSerializer\n\n\nHttpMessage.serializer = HttpSerializer\n"
  },
  {
    "path": "packages/fetchai/protocols/http/dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nThis module contains the classes required for http dialogue management.\n\n- HttpDialogue: The dialogue class maintains state of a dialogue and manages it.\n- HttpDialogues: The dialogues class keeps track of all dialogues.\n\"\"\"\n\nfrom abc import ABC\nfrom typing import Callable, Dict, FrozenSet, Type, cast\n\nfrom aea.common import Address\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue, DialogueLabel, Dialogues\n\nfrom packages.fetchai.protocols.http.message import HttpMessage\n\n\nclass HttpDialogue(Dialogue):\n    \"\"\"The http dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    INITIAL_PERFORMATIVES: FrozenSet[Message.Performative] = frozenset(\n        {HttpMessage.Performative.REQUEST}\n    )\n    TERMINAL_PERFORMATIVES: FrozenSet[Message.Performative] = frozenset(\n        {HttpMessage.Performative.RESPONSE}\n    )\n    VALID_REPLIES: Dict[Message.Performative, FrozenSet[Message.Performative]] = {\n        HttpMessage.Performative.REQUEST: frozenset(\n            {HttpMessage.Performative.RESPONSE}\n        ),\n        HttpMessage.Performative.RESPONSE: frozenset(),\n    }\n\n    class Role(Dialogue.Role):\n        \"\"\"This class defines the agent's role in a http dialogue.\"\"\"\n\n        CLIENT = \"client\"\n        SERVER = \"server\"\n\n    class EndState(Dialogue.EndState):\n        \"\"\"This class defines the end states of a http dialogue.\"\"\"\n\n        SUCCESSFUL = 0\n\n    def __init__(\n        self,\n        dialogue_label: DialogueLabel,\n        self_address: Address,\n        role: Dialogue.Role,\n        message_class: Type[HttpMessage] = HttpMessage,\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n        :param message_class: the message class used\n        \"\"\"\n        Dialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            message_class=message_class,\n            self_address=self_address,\n            role=role,\n        )\n\n\nclass HttpDialogues(Dialogues, ABC):\n    \"\"\"This class keeps track of all http dialogues.\"\"\"\n\n    END_STATES = frozenset({HttpDialogue.EndState.SUCCESSFUL})\n\n    _keep_terminal_state_dialogues = False\n\n    def __init__(\n        self,\n        self_address: Address,\n        role_from_first_message: Callable[[Message, Address], Dialogue.Role],\n        dialogue_class: Type[HttpDialogue] = HttpDialogue,\n    ) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param self_address: the address of the entity for whom dialogues are maintained\n        :param dialogue_class: the dialogue class used\n        :param role_from_first_message: the callable determining role from first message\n        \"\"\"\n        Dialogues.__init__(\n            self,\n            self_address=self_address,\n            end_states=cast(FrozenSet[Dialogue.EndState], self.END_STATES),\n            message_class=HttpMessage,\n            dialogue_class=dialogue_class,\n            role_from_first_message=role_from_first_message,\n        )\n"
  },
  {
    "path": "packages/fetchai/protocols/http/http.proto",
    "content": "syntax = \"proto3\";\n\npackage aea.fetchai.http.v1_0_0;\n\nmessage HttpMessage{\n\n  // Performatives and contents\n  message Request_Performative{\n    string method = 1;\n    string url = 2;\n    string version = 3;\n    string headers = 4;\n    bytes body = 5;\n  }\n\n  message Response_Performative{\n    string version = 1;\n    int64 status_code = 2;\n    string status_text = 3;\n    string headers = 4;\n    bytes body = 5;\n  }\n\n\n  oneof performative{\n    Request_Performative request = 5;\n    Response_Performative response = 6;\n  }\n}\n"
  },
  {
    "path": "packages/fetchai/protocols/http/http_pb2.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by the protocol buffer compiler.  DO NOT EDIT!\n# source: http.proto\n\"\"\"Generated protocol buffer code.\"\"\"\nfrom google.protobuf import descriptor as _descriptor\nfrom google.protobuf import descriptor_pool as _descriptor_pool\nfrom google.protobuf import message as _message\nfrom google.protobuf import reflection as _reflection\nfrom google.protobuf import symbol_database as _symbol_database\n\n# @@protoc_insertion_point(imports)\n\n_sym_db = _symbol_database.Default()\n\n\nDESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(\n    b'\\n\\nhttp.proto\\x12\\x17\\x61\\x65\\x61.fetchai.http.v1_0_0\"\\x93\\x03\\n\\x0bHttpMessage\\x12L\\n\\x07request\\x18\\x05 \\x01(\\x0b\\x32\\x39.aea.fetchai.http.v1_0_0.HttpMessage.Request_PerformativeH\\x00\\x12N\\n\\x08response\\x18\\x06 \\x01(\\x0b\\x32:.aea.fetchai.http.v1_0_0.HttpMessage.Response_PerformativeH\\x00\\x1a\\x63\\n\\x14Request_Performative\\x12\\x0e\\n\\x06method\\x18\\x01 \\x01(\\t\\x12\\x0b\\n\\x03url\\x18\\x02 \\x01(\\t\\x12\\x0f\\n\\x07version\\x18\\x03 \\x01(\\t\\x12\\x0f\\n\\x07headers\\x18\\x04 \\x01(\\t\\x12\\x0c\\n\\x04\\x62ody\\x18\\x05 \\x01(\\x0c\\x1aq\\n\\x15Response_Performative\\x12\\x0f\\n\\x07version\\x18\\x01 \\x01(\\t\\x12\\x13\\n\\x0bstatus_code\\x18\\x02 \\x01(\\x03\\x12\\x13\\n\\x0bstatus_text\\x18\\x03 \\x01(\\t\\x12\\x0f\\n\\x07headers\\x18\\x04 \\x01(\\t\\x12\\x0c\\n\\x04\\x62ody\\x18\\x05 \\x01(\\x0c\\x42\\x0e\\n\\x0cperformativeb\\x06proto3'\n)\n\n\n_HTTPMESSAGE = DESCRIPTOR.message_types_by_name[\"HttpMessage\"]\n_HTTPMESSAGE_REQUEST_PERFORMATIVE = _HTTPMESSAGE.nested_types_by_name[\n    \"Request_Performative\"\n]\n_HTTPMESSAGE_RESPONSE_PERFORMATIVE = _HTTPMESSAGE.nested_types_by_name[\n    \"Response_Performative\"\n]\nHttpMessage = _reflection.GeneratedProtocolMessageType(\n    \"HttpMessage\",\n    (_message.Message,),\n    {\n        \"Request_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Request_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _HTTPMESSAGE_REQUEST_PERFORMATIVE,\n                \"__module__\": \"http_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.http.v1_0_0.HttpMessage.Request_Performative)\n            },\n        ),\n        \"Response_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Response_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _HTTPMESSAGE_RESPONSE_PERFORMATIVE,\n                \"__module__\": \"http_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.http.v1_0_0.HttpMessage.Response_Performative)\n            },\n        ),\n        \"DESCRIPTOR\": _HTTPMESSAGE,\n        \"__module__\": \"http_pb2\"\n        # @@protoc_insertion_point(class_scope:aea.fetchai.http.v1_0_0.HttpMessage)\n    },\n)\n_sym_db.RegisterMessage(HttpMessage)\n_sym_db.RegisterMessage(HttpMessage.Request_Performative)\n_sym_db.RegisterMessage(HttpMessage.Response_Performative)\n\nif _descriptor._USE_C_DESCRIPTORS == False:\n\n    DESCRIPTOR._options = None\n    _HTTPMESSAGE._serialized_start = 40\n    _HTTPMESSAGE._serialized_end = 443\n    _HTTPMESSAGE_REQUEST_PERFORMATIVE._serialized_start = 213\n    _HTTPMESSAGE_REQUEST_PERFORMATIVE._serialized_end = 312\n    _HTTPMESSAGE_RESPONSE_PERFORMATIVE._serialized_start = 314\n    _HTTPMESSAGE_RESPONSE_PERFORMATIVE._serialized_end = 427\n# @@protoc_insertion_point(module_scope)\n"
  },
  {
    "path": "packages/fetchai/protocols/http/message.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains http's message definition.\"\"\"\n\n# pylint: disable=too-many-statements,too-many-locals,no-member,too-few-public-methods,too-many-branches,not-an-iterable,unidiomatic-typecheck,unsubscriptable-object\nimport logging\nfrom typing import Any, Set, Tuple, cast\n\nfrom aea.configurations.base import PublicId\nfrom aea.exceptions import AEAEnforceError, enforce\nfrom aea.protocols.base import Message\n\n\n_default_logger = logging.getLogger(\"aea.packages.fetchai.protocols.http.message\")\n\nDEFAULT_BODY_SIZE = 4\n\n\nclass HttpMessage(Message):\n    \"\"\"A protocol for HTTP requests and responses.\"\"\"\n\n    protocol_id = PublicId.from_str(\"fetchai/http:1.1.7\")\n    protocol_specification_id = PublicId.from_str(\"fetchai/http:1.0.0\")\n\n    class Performative(Message.Performative):\n        \"\"\"Performatives for the http protocol.\"\"\"\n\n        REQUEST = \"request\"\n        RESPONSE = \"response\"\n\n        def __str__(self) -> str:\n            \"\"\"Get the string representation.\"\"\"\n            return str(self.value)\n\n    _performatives = {\"request\", \"response\"}\n    __slots__: Tuple[str, ...] = tuple()\n\n    class _SlotsCls:\n        __slots__ = (\n            \"body\",\n            \"dialogue_reference\",\n            \"headers\",\n            \"message_id\",\n            \"method\",\n            \"performative\",\n            \"status_code\",\n            \"status_text\",\n            \"target\",\n            \"url\",\n            \"version\",\n        )\n\n    def __init__(\n        self,\n        performative: Performative,\n        dialogue_reference: Tuple[str, str] = (\"\", \"\"),\n        message_id: int = 1,\n        target: int = 0,\n        **kwargs: Any,\n    ):\n        \"\"\"\n        Initialise an instance of HttpMessage.\n\n        :param message_id: the message id.\n        :param dialogue_reference: the dialogue reference.\n        :param target: the message target.\n        :param performative: the message performative.\n        :param **kwargs: extra options.\n        \"\"\"\n        super().__init__(\n            dialogue_reference=dialogue_reference,\n            message_id=message_id,\n            target=target,\n            performative=HttpMessage.Performative(performative),\n            **kwargs,\n        )\n\n    @property\n    def valid_performatives(self) -> Set[str]:\n        \"\"\"Get valid performatives.\"\"\"\n        return self._performatives\n\n    @property\n    def dialogue_reference(self) -> Tuple[str, str]:\n        \"\"\"Get the dialogue_reference of the message.\"\"\"\n        enforce(self.is_set(\"dialogue_reference\"), \"dialogue_reference is not set.\")\n        return cast(Tuple[str, str], self.get(\"dialogue_reference\"))\n\n    @property\n    def message_id(self) -> int:\n        \"\"\"Get the message_id of the message.\"\"\"\n        enforce(self.is_set(\"message_id\"), \"message_id is not set.\")\n        return cast(int, self.get(\"message_id\"))\n\n    @property\n    def performative(self) -> Performative:  # type: ignore # noqa: F821\n        \"\"\"Get the performative of the message.\"\"\"\n        enforce(self.is_set(\"performative\"), \"performative is not set.\")\n        return cast(HttpMessage.Performative, self.get(\"performative\"))\n\n    @property\n    def target(self) -> int:\n        \"\"\"Get the target of the message.\"\"\"\n        enforce(self.is_set(\"target\"), \"target is not set.\")\n        return cast(int, self.get(\"target\"))\n\n    @property\n    def body(self) -> bytes:\n        \"\"\"Get the 'body' content from the message.\"\"\"\n        enforce(self.is_set(\"body\"), \"'body' content is not set.\")\n        return cast(bytes, self.get(\"body\"))\n\n    @property\n    def headers(self) -> str:\n        \"\"\"Get the 'headers' content from the message.\"\"\"\n        enforce(self.is_set(\"headers\"), \"'headers' content is not set.\")\n        return cast(str, self.get(\"headers\"))\n\n    @property\n    def method(self) -> str:\n        \"\"\"Get the 'method' content from the message.\"\"\"\n        enforce(self.is_set(\"method\"), \"'method' content is not set.\")\n        return cast(str, self.get(\"method\"))\n\n    @property\n    def status_code(self) -> int:\n        \"\"\"Get the 'status_code' content from the message.\"\"\"\n        enforce(self.is_set(\"status_code\"), \"'status_code' content is not set.\")\n        return cast(int, self.get(\"status_code\"))\n\n    @property\n    def status_text(self) -> str:\n        \"\"\"Get the 'status_text' content from the message.\"\"\"\n        enforce(self.is_set(\"status_text\"), \"'status_text' content is not set.\")\n        return cast(str, self.get(\"status_text\"))\n\n    @property\n    def url(self) -> str:\n        \"\"\"Get the 'url' content from the message.\"\"\"\n        enforce(self.is_set(\"url\"), \"'url' content is not set.\")\n        return cast(str, self.get(\"url\"))\n\n    @property\n    def version(self) -> str:\n        \"\"\"Get the 'version' content from the message.\"\"\"\n        enforce(self.is_set(\"version\"), \"'version' content is not set.\")\n        return cast(str, self.get(\"version\"))\n\n    def _is_consistent(self) -> bool:\n        \"\"\"Check that the message follows the http protocol.\"\"\"\n        try:\n            enforce(\n                isinstance(self.dialogue_reference, tuple),\n                \"Invalid type for 'dialogue_reference'. Expected 'tuple'. Found '{}'.\".format(\n                    type(self.dialogue_reference)\n                ),\n            )\n            enforce(\n                isinstance(self.dialogue_reference[0], str),\n                \"Invalid type for 'dialogue_reference[0]'. Expected 'str'. Found '{}'.\".format(\n                    type(self.dialogue_reference[0])\n                ),\n            )\n            enforce(\n                isinstance(self.dialogue_reference[1], str),\n                \"Invalid type for 'dialogue_reference[1]'. Expected 'str'. Found '{}'.\".format(\n                    type(self.dialogue_reference[1])\n                ),\n            )\n            enforce(\n                type(self.message_id) is int,\n                \"Invalid type for 'message_id'. Expected 'int'. Found '{}'.\".format(\n                    type(self.message_id)\n                ),\n            )\n            enforce(\n                type(self.target) is int,\n                \"Invalid type for 'target'. Expected 'int'. Found '{}'.\".format(\n                    type(self.target)\n                ),\n            )\n\n            # Light Protocol Rule 2\n            # Check correct performative\n            enforce(\n                isinstance(self.performative, HttpMessage.Performative),\n                \"Invalid 'performative'. Expected either of '{}'. Found '{}'.\".format(\n                    self.valid_performatives, self.performative\n                ),\n            )\n\n            # Check correct contents\n            actual_nb_of_contents = len(self._body) - DEFAULT_BODY_SIZE\n            expected_nb_of_contents = 0\n            if self.performative == HttpMessage.Performative.REQUEST:\n                expected_nb_of_contents = 5\n                enforce(\n                    isinstance(self.method, str),\n                    \"Invalid type for content 'method'. Expected 'str'. Found '{}'.\".format(\n                        type(self.method)\n                    ),\n                )\n                enforce(\n                    isinstance(self.url, str),\n                    \"Invalid type for content 'url'. Expected 'str'. Found '{}'.\".format(\n                        type(self.url)\n                    ),\n                )\n                enforce(\n                    isinstance(self.version, str),\n                    \"Invalid type for content 'version'. Expected 'str'. Found '{}'.\".format(\n                        type(self.version)\n                    ),\n                )\n                enforce(\n                    isinstance(self.headers, str),\n                    \"Invalid type for content 'headers'. Expected 'str'. Found '{}'.\".format(\n                        type(self.headers)\n                    ),\n                )\n                enforce(\n                    isinstance(self.body, bytes),\n                    \"Invalid type for content 'body'. Expected 'bytes'. Found '{}'.\".format(\n                        type(self.body)\n                    ),\n                )\n            elif self.performative == HttpMessage.Performative.RESPONSE:\n                expected_nb_of_contents = 5\n                enforce(\n                    isinstance(self.version, str),\n                    \"Invalid type for content 'version'. Expected 'str'. Found '{}'.\".format(\n                        type(self.version)\n                    ),\n                )\n                enforce(\n                    type(self.status_code) is int,\n                    \"Invalid type for content 'status_code'. Expected 'int'. Found '{}'.\".format(\n                        type(self.status_code)\n                    ),\n                )\n                enforce(\n                    isinstance(self.status_text, str),\n                    \"Invalid type for content 'status_text'. Expected 'str'. Found '{}'.\".format(\n                        type(self.status_text)\n                    ),\n                )\n                enforce(\n                    isinstance(self.headers, str),\n                    \"Invalid type for content 'headers'. Expected 'str'. Found '{}'.\".format(\n                        type(self.headers)\n                    ),\n                )\n                enforce(\n                    isinstance(self.body, bytes),\n                    \"Invalid type for content 'body'. Expected 'bytes'. Found '{}'.\".format(\n                        type(self.body)\n                    ),\n                )\n\n            # Check correct content count\n            enforce(\n                expected_nb_of_contents == actual_nb_of_contents,\n                \"Incorrect number of contents. Expected {}. Found {}\".format(\n                    expected_nb_of_contents, actual_nb_of_contents\n                ),\n            )\n\n            # Light Protocol Rule 3\n            if self.message_id == 1:\n                enforce(\n                    self.target == 0,\n                    \"Invalid 'target'. Expected 0 (because 'message_id' is 1). Found {}.\".format(\n                        self.target\n                    ),\n                )\n        except (AEAEnforceError, ValueError, KeyError) as e:\n            _default_logger.error(str(e))\n            return False\n\n        return True\n"
  },
  {
    "path": "packages/fetchai/protocols/http/protocol.yaml",
    "content": "name: http\nauthor: fetchai\nversion: 1.1.7\nprotocol_specification_id: fetchai/http:1.0.0\ntype: protocol\ndescription: A protocol for HTTP requests and responses.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: QmWqoWa2LrKVLYdmURDriMkUYSUxoWXL1wgatFshQMUzha\n  __init__.py: QmPXrzMrmAGjAqvjXEKC9WvdrVgng9viYX8WuEJYDcfVCv\n  dialogues.py: QmUcjazcTHwvVMQk2vPjsJQjscbm5mE1mKBHYVUrNJbTsR\n  http.proto: Qmag9uQYVPQwsdZfH1GEaBX5xgikoYuphQpXnWP2xob6Ys\n  http_pb2.py: QmPck55KUSn1KfGQ3jGTq6eh2Fhh6Kdn5HPotrpFJeJ8u3\n  message.py: Qmf545etJNhTDu4YoL3EcNFqrB6WCrXGFvZN2WLJozB3Dk\n  serialization.py: QmaPKtCLFJSV6Jxtft5k4vz2CuuG5eWz8GsMSbTtdrFxyx\nfingerprint_ignore_patterns: []\ndependencies:\n  protobuf: {}\n"
  },
  {
    "path": "packages/fetchai/protocols/http/serialization.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Serialization module for http protocol.\"\"\"\n\n# pylint: disable=too-many-statements,too-many-locals,no-member,too-few-public-methods,redefined-builtin\nfrom typing import Any, Dict, cast\n\nfrom aea.mail.base_pb2 import DialogueMessage\nfrom aea.mail.base_pb2 import Message as ProtobufMessage\nfrom aea.protocols.base import Message, Serializer\n\nfrom packages.fetchai.protocols.http import http_pb2\nfrom packages.fetchai.protocols.http.message import HttpMessage\n\n\nclass HttpSerializer(Serializer):\n    \"\"\"Serialization for the 'http' protocol.\"\"\"\n\n    @staticmethod\n    def encode(msg: Message) -> bytes:\n        \"\"\"\n        Encode a 'Http' message into bytes.\n\n        :param msg: the message object.\n        :return: the bytes.\n        \"\"\"\n        msg = cast(HttpMessage, msg)\n        message_pb = ProtobufMessage()\n        dialogue_message_pb = DialogueMessage()\n        http_msg = http_pb2.HttpMessage()\n\n        dialogue_message_pb.message_id = msg.message_id\n        dialogue_reference = msg.dialogue_reference\n        dialogue_message_pb.dialogue_starter_reference = dialogue_reference[0]\n        dialogue_message_pb.dialogue_responder_reference = dialogue_reference[1]\n        dialogue_message_pb.target = msg.target\n\n        performative_id = msg.performative\n        if performative_id == HttpMessage.Performative.REQUEST:\n            performative = http_pb2.HttpMessage.Request_Performative()  # type: ignore\n            method = msg.method\n            performative.method = method\n            url = msg.url\n            performative.url = url\n            version = msg.version\n            performative.version = version\n            headers = msg.headers\n            performative.headers = headers\n            body = msg.body\n            performative.body = body\n            http_msg.request.CopyFrom(performative)\n        elif performative_id == HttpMessage.Performative.RESPONSE:\n            performative = http_pb2.HttpMessage.Response_Performative()  # type: ignore\n            version = msg.version\n            performative.version = version\n            status_code = msg.status_code\n            performative.status_code = status_code\n            status_text = msg.status_text\n            performative.status_text = status_text\n            headers = msg.headers\n            performative.headers = headers\n            body = msg.body\n            performative.body = body\n            http_msg.response.CopyFrom(performative)\n        else:\n            raise ValueError(\"Performative not valid: {}\".format(performative_id))\n\n        dialogue_message_pb.content = http_msg.SerializeToString()\n\n        message_pb.dialogue_message.CopyFrom(dialogue_message_pb)\n        message_bytes = message_pb.SerializeToString()\n        return message_bytes\n\n    @staticmethod\n    def decode(obj: bytes) -> Message:\n        \"\"\"\n        Decode bytes into a 'Http' message.\n\n        :param obj: the bytes object.\n        :return: the 'Http' message.\n        \"\"\"\n        message_pb = ProtobufMessage()\n        http_pb = http_pb2.HttpMessage()\n        message_pb.ParseFromString(obj)\n        message_id = message_pb.dialogue_message.message_id\n        dialogue_reference = (\n            message_pb.dialogue_message.dialogue_starter_reference,\n            message_pb.dialogue_message.dialogue_responder_reference,\n        )\n        target = message_pb.dialogue_message.target\n\n        http_pb.ParseFromString(message_pb.dialogue_message.content)\n        performative = http_pb.WhichOneof(\"performative\")\n        performative_id = HttpMessage.Performative(str(performative))\n        performative_content = {}  # type: Dict[str, Any]\n        if performative_id == HttpMessage.Performative.REQUEST:\n            method = http_pb.request.method\n            performative_content[\"method\"] = method\n            url = http_pb.request.url\n            performative_content[\"url\"] = url\n            version = http_pb.request.version\n            performative_content[\"version\"] = version\n            headers = http_pb.request.headers\n            performative_content[\"headers\"] = headers\n            body = http_pb.request.body\n            performative_content[\"body\"] = body\n        elif performative_id == HttpMessage.Performative.RESPONSE:\n            version = http_pb.response.version\n            performative_content[\"version\"] = version\n            status_code = http_pb.response.status_code\n            performative_content[\"status_code\"] = status_code\n            status_text = http_pb.response.status_text\n            performative_content[\"status_text\"] = status_text\n            headers = http_pb.response.headers\n            performative_content[\"headers\"] = headers\n            body = http_pb.response.body\n            performative_content[\"body\"] = body\n        else:\n            raise ValueError(\"Performative not valid: {}.\".format(performative_id))\n\n        return HttpMessage(\n            message_id=message_id,\n            dialogue_reference=dialogue_reference,\n            target=target,\n            performative=performative,\n            **performative_content\n        )\n"
  },
  {
    "path": "packages/fetchai/protocols/ledger_api/README.md",
    "content": "# Ledger API Protocol\n\n## Description\n\nThis is a protocol for interacting with ledger APIs.\n\n## Specification\n\n```yaml\n---\nname: ledger_api\nauthor: fetchai\nversion: 1.1.7\ndescription: A protocol for ledger APIs requests and responses.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nprotocol_specification_id: fetchai/ledger_api:1.0.0\nspeech_acts:\n  get_balance:\n    ledger_id: pt:str\n    address: pt:str\n  get_raw_transaction:\n    terms: ct:Terms\n  send_signed_transaction:\n    signed_transaction: ct:SignedTransaction\n  get_transaction_receipt:\n    transaction_digest: ct:TransactionDigest\n  balance:\n    ledger_id: pt:str\n    balance: pt:int\n  raw_transaction:\n    raw_transaction: ct:RawTransaction\n  transaction_digest:\n    transaction_digest: ct:TransactionDigest\n  transaction_receipt:\n    transaction_receipt: ct:TransactionReceipt\n  get_state:\n    ledger_id: pt:str\n    callable: pt:str\n    args: pt:list[pt:str]\n    kwargs: ct:Kwargs\n  state:\n    ledger_id: pt:str\n    state: ct:State\n  error:\n    code: pt:int\n    message: pt:optional[pt:str]\n    data: pt:optional[pt:bytes]\n...\n---\nct:Terms: |\n  bytes terms = 1;\nct:Kwargs: |\n  bytes kwargs = 1;\nct:State: |\n  bytes state = 1;\nct:SignedTransaction: |\n  bytes signed_transaction = 1;\nct:RawTransaction: |\n  bytes raw_transaction = 1;\nct:TransactionDigest: |\n  bytes transaction_digest = 1;\nct:TransactionReceipt: |\n  bytes transaction_receipt = 1;\n...\n---\ninitiation: [get_balance, get_state, get_raw_transaction, send_signed_transaction, get_transaction_receipt]\nreply:\n  get_balance: [balance, error]\n  balance: []\n  get_state: [state, error]\n  state: []\n  get_raw_transaction: [raw_transaction, error]\n  raw_transaction: [send_signed_transaction]\n  send_signed_transaction: [transaction_digest, error]\n  transaction_digest: [get_transaction_receipt]\n  get_transaction_receipt: [transaction_receipt, error]\n  transaction_receipt: []\n  error: []\ntermination: [balance, state, transaction_receipt, error]\nroles: {agent, ledger}\nend_states: [successful]\nkeep_terminal_state_dialogues: false\n...\n```\n\n## Links\n"
  },
  {
    "path": "packages/fetchai/protocols/ledger_api/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nThis module contains the support resources for the ledger_api protocol.\n\nIt was created with protocol buffer compiler version `libprotoc 3.19.4` and aea version `1.2.5`.\n\"\"\"\n\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\nfrom packages.fetchai.protocols.ledger_api.serialization import LedgerApiSerializer\n\n\nLedgerApiMessage.serializer = LedgerApiSerializer\n"
  },
  {
    "path": "packages/fetchai/protocols/ledger_api/custom_types.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains class representations corresponding to every custom type in the protocol specification.\"\"\"\n\nfrom typing import Any\n\nfrom aea.common import JSONLike\nfrom aea.exceptions import enforce\nfrom aea.helpers.serializers import DictProtobufStructSerializer\nfrom aea.helpers.transaction.base import RawTransaction as BaseRawTransaction\nfrom aea.helpers.transaction.base import SignedTransaction as BaseSignedTransaction\nfrom aea.helpers.transaction.base import State as BaseState\nfrom aea.helpers.transaction.base import Terms as BaseTerms\nfrom aea.helpers.transaction.base import TransactionDigest as BaseTransactionDigest\nfrom aea.helpers.transaction.base import TransactionReceipt as BaseTransactionReceipt\n\n\nRawTransaction = BaseRawTransaction\nSignedTransaction = BaseSignedTransaction\nState = BaseState\nTerms = BaseTerms\nTransactionDigest = BaseTransactionDigest\nTransactionReceipt = BaseTransactionReceipt\n\n\nclass Kwargs:\n    \"\"\"This class represents an instance of Kwargs.\"\"\"\n\n    __slots__ = (\"_body\",)\n\n    def __init__(\n        self,\n        body: JSONLike,\n    ):\n        \"\"\"Initialise an instance of RawTransaction.\"\"\"\n        self._body = body\n        self._check_consistency()\n\n    def _check_consistency(self) -> None:\n        \"\"\"Check consistency of the object.\"\"\"\n        enforce(\n            isinstance(self._body, dict)\n            and all(isinstance(key, str) for key in self._body.keys()),\n            \"Body must be dict and keys must be str.\",\n        )\n\n    @property\n    def body(self) -> JSONLike:\n        \"\"\"Get the body.\"\"\"\n        return self._body\n\n    @staticmethod\n    def encode(kwargs_protobuf_object: Any, kwargs_object: \"Kwargs\") -> None:\n        \"\"\"\n        Encode an instance of this class into the protocol buffer object.\n\n        The protocol buffer object in the kwargs_protobuf_object argument is matched with the instance of this class in the 'kwargs_object' argument.\n\n        :param kwargs_protobuf_object: the protocol buffer object whose type corresponds with this class.\n        :param kwargs_object: an instance of this class to be encoded in the protocol buffer object.\n        \"\"\"\n        kwargs_protobuf_object.kwargs = DictProtobufStructSerializer.encode(\n            kwargs_object.body\n        )\n\n    @classmethod\n    def decode(cls, kwargs_protobuf_object: Any) -> \"Kwargs\":\n        \"\"\"\n        Decode a protocol buffer object that corresponds with this class into an instance of this class.\n\n        A new instance of this class is created that matches the protocol buffer object in the 'kwargs_protobuf_object' argument.\n\n        :param kwargs_protobuf_object: the protocol buffer object whose type corresponds with this class.\n        :return: A new instance of this class that matches the protocol buffer object in the 'kwargs_protobuf_object' argument.\n        \"\"\"\n        kwargs = DictProtobufStructSerializer.decode(kwargs_protobuf_object.kwargs)\n        return cls(kwargs)\n\n    def __eq__(self, other: Any) -> bool:\n        \"\"\"Check equality.\"\"\"\n        return isinstance(other, Kwargs) and self.body == other.body\n\n    def __str__(self) -> str:\n        \"\"\"Get string representation.\"\"\"\n        return \"Kwargs: body={}\".format(self.body)\n"
  },
  {
    "path": "packages/fetchai/protocols/ledger_api/dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nThis module contains the classes required for ledger_api dialogue management.\n\n- LedgerApiDialogue: The dialogue class maintains state of a dialogue and manages it.\n- LedgerApiDialogues: The dialogues class keeps track of all dialogues.\n\"\"\"\n\nfrom abc import ABC\nfrom typing import Callable, Dict, FrozenSet, Type, cast\n\nfrom aea.common import Address\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue, DialogueLabel, Dialogues\n\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\n\n\nclass LedgerApiDialogue(Dialogue):\n    \"\"\"The ledger_api dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    INITIAL_PERFORMATIVES: FrozenSet[Message.Performative] = frozenset(\n        {\n            LedgerApiMessage.Performative.GET_BALANCE,\n            LedgerApiMessage.Performative.GET_STATE,\n            LedgerApiMessage.Performative.GET_RAW_TRANSACTION,\n            LedgerApiMessage.Performative.SEND_SIGNED_TRANSACTION,\n            LedgerApiMessage.Performative.GET_TRANSACTION_RECEIPT,\n        }\n    )\n    TERMINAL_PERFORMATIVES: FrozenSet[Message.Performative] = frozenset(\n        {\n            LedgerApiMessage.Performative.BALANCE,\n            LedgerApiMessage.Performative.STATE,\n            LedgerApiMessage.Performative.TRANSACTION_RECEIPT,\n            LedgerApiMessage.Performative.ERROR,\n        }\n    )\n    VALID_REPLIES: Dict[Message.Performative, FrozenSet[Message.Performative]] = {\n        LedgerApiMessage.Performative.BALANCE: frozenset(),\n        LedgerApiMessage.Performative.ERROR: frozenset(),\n        LedgerApiMessage.Performative.GET_BALANCE: frozenset(\n            {LedgerApiMessage.Performative.BALANCE, LedgerApiMessage.Performative.ERROR}\n        ),\n        LedgerApiMessage.Performative.GET_RAW_TRANSACTION: frozenset(\n            {\n                LedgerApiMessage.Performative.RAW_TRANSACTION,\n                LedgerApiMessage.Performative.ERROR,\n            }\n        ),\n        LedgerApiMessage.Performative.GET_STATE: frozenset(\n            {LedgerApiMessage.Performative.STATE, LedgerApiMessage.Performative.ERROR}\n        ),\n        LedgerApiMessage.Performative.GET_TRANSACTION_RECEIPT: frozenset(\n            {\n                LedgerApiMessage.Performative.TRANSACTION_RECEIPT,\n                LedgerApiMessage.Performative.ERROR,\n            }\n        ),\n        LedgerApiMessage.Performative.RAW_TRANSACTION: frozenset(\n            {LedgerApiMessage.Performative.SEND_SIGNED_TRANSACTION}\n        ),\n        LedgerApiMessage.Performative.SEND_SIGNED_TRANSACTION: frozenset(\n            {\n                LedgerApiMessage.Performative.TRANSACTION_DIGEST,\n                LedgerApiMessage.Performative.ERROR,\n            }\n        ),\n        LedgerApiMessage.Performative.STATE: frozenset(),\n        LedgerApiMessage.Performative.TRANSACTION_DIGEST: frozenset(\n            {LedgerApiMessage.Performative.GET_TRANSACTION_RECEIPT}\n        ),\n        LedgerApiMessage.Performative.TRANSACTION_RECEIPT: frozenset(),\n    }\n\n    class Role(Dialogue.Role):\n        \"\"\"This class defines the agent's role in a ledger_api dialogue.\"\"\"\n\n        AGENT = \"agent\"\n        LEDGER = \"ledger\"\n\n    class EndState(Dialogue.EndState):\n        \"\"\"This class defines the end states of a ledger_api dialogue.\"\"\"\n\n        SUCCESSFUL = 0\n\n    def __init__(\n        self,\n        dialogue_label: DialogueLabel,\n        self_address: Address,\n        role: Dialogue.Role,\n        message_class: Type[LedgerApiMessage] = LedgerApiMessage,\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n        :param message_class: the message class used\n        \"\"\"\n        Dialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            message_class=message_class,\n            self_address=self_address,\n            role=role,\n        )\n\n\nclass LedgerApiDialogues(Dialogues, ABC):\n    \"\"\"This class keeps track of all ledger_api dialogues.\"\"\"\n\n    END_STATES = frozenset({LedgerApiDialogue.EndState.SUCCESSFUL})\n\n    _keep_terminal_state_dialogues = False\n\n    def __init__(\n        self,\n        self_address: Address,\n        role_from_first_message: Callable[[Message, Address], Dialogue.Role],\n        dialogue_class: Type[LedgerApiDialogue] = LedgerApiDialogue,\n    ) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param self_address: the address of the entity for whom dialogues are maintained\n        :param dialogue_class: the dialogue class used\n        :param role_from_first_message: the callable determining role from first message\n        \"\"\"\n        Dialogues.__init__(\n            self,\n            self_address=self_address,\n            end_states=cast(FrozenSet[Dialogue.EndState], self.END_STATES),\n            message_class=LedgerApiMessage,\n            dialogue_class=dialogue_class,\n            role_from_first_message=role_from_first_message,\n        )\n"
  },
  {
    "path": "packages/fetchai/protocols/ledger_api/ledger_api.proto",
    "content": "syntax = \"proto3\";\n\npackage aea.fetchai.ledger_api.v1_0_0;\n\nmessage LedgerApiMessage{\n\n  // Custom Types\n  message Kwargs{\n    bytes kwargs = 1;\n  }\n\n  message RawTransaction{\n    bytes raw_transaction = 1;\n  }\n\n  message SignedTransaction{\n    bytes signed_transaction = 1;\n  }\n\n  message State{\n    bytes state = 1;\n  }\n\n  message Terms{\n    bytes terms = 1;\n  }\n\n  message TransactionDigest{\n    bytes transaction_digest = 1;\n  }\n\n  message TransactionReceipt{\n    bytes transaction_receipt = 1;\n  }\n\n\n  // Performatives and contents\n  message Get_Balance_Performative{\n    string ledger_id = 1;\n    string address = 2;\n  }\n\n  message Get_Raw_Transaction_Performative{\n    Terms terms = 1;\n  }\n\n  message Send_Signed_Transaction_Performative{\n    SignedTransaction signed_transaction = 1;\n  }\n\n  message Get_Transaction_Receipt_Performative{\n    TransactionDigest transaction_digest = 1;\n  }\n\n  message Balance_Performative{\n    string ledger_id = 1;\n    int64 balance = 2;\n  }\n\n  message Raw_Transaction_Performative{\n    RawTransaction raw_transaction = 1;\n  }\n\n  message Transaction_Digest_Performative{\n    TransactionDigest transaction_digest = 1;\n  }\n\n  message Transaction_Receipt_Performative{\n    TransactionReceipt transaction_receipt = 1;\n  }\n\n  message Get_State_Performative{\n    string ledger_id = 1;\n    string callable = 2;\n    repeated string args = 3;\n    Kwargs kwargs = 4;\n  }\n\n  message State_Performative{\n    string ledger_id = 1;\n    State state = 2;\n  }\n\n  message Error_Performative{\n    int64 code = 1;\n    string message = 2;\n    bool message_is_set = 3;\n    bytes data = 4;\n    bool data_is_set = 5;\n  }\n\n\n  oneof performative{\n    Balance_Performative balance = 5;\n    Error_Performative error = 6;\n    Get_Balance_Performative get_balance = 7;\n    Get_Raw_Transaction_Performative get_raw_transaction = 8;\n    Get_State_Performative get_state = 9;\n    Get_Transaction_Receipt_Performative get_transaction_receipt = 10;\n    Raw_Transaction_Performative raw_transaction = 11;\n    Send_Signed_Transaction_Performative send_signed_transaction = 12;\n    State_Performative state = 13;\n    Transaction_Digest_Performative transaction_digest = 14;\n    Transaction_Receipt_Performative transaction_receipt = 15;\n  }\n}\n"
  },
  {
    "path": "packages/fetchai/protocols/ledger_api/ledger_api_pb2.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by the protocol buffer compiler.  DO NOT EDIT!\n# source: ledger_api.proto\n\"\"\"Generated protocol buffer code.\"\"\"\nfrom google.protobuf import descriptor as _descriptor\nfrom google.protobuf import descriptor_pool as _descriptor_pool\nfrom google.protobuf import message as _message\nfrom google.protobuf import reflection as _reflection\nfrom google.protobuf import symbol_database as _symbol_database\n\n# @@protoc_insertion_point(imports)\n\n_sym_db = _symbol_database.Default()\n\n\nDESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(\n    b'\\n\\x10ledger_api.proto\\x12\\x1d\\x61\\x65\\x61.fetchai.ledger_api.v1_0_0\"\\x86\\x15\\n\\x10LedgerApiMessage\\x12W\\n\\x07\\x62\\x61lance\\x18\\x05 \\x01(\\x0b\\x32\\x44.aea.fetchai.ledger_api.v1_0_0.LedgerApiMessage.Balance_PerformativeH\\x00\\x12S\\n\\x05\\x65rror\\x18\\x06 \\x01(\\x0b\\x32\\x42.aea.fetchai.ledger_api.v1_0_0.LedgerApiMessage.Error_PerformativeH\\x00\\x12_\\n\\x0bget_balance\\x18\\x07 \\x01(\\x0b\\x32H.aea.fetchai.ledger_api.v1_0_0.LedgerApiMessage.Get_Balance_PerformativeH\\x00\\x12o\\n\\x13get_raw_transaction\\x18\\x08 \\x01(\\x0b\\x32P.aea.fetchai.ledger_api.v1_0_0.LedgerApiMessage.Get_Raw_Transaction_PerformativeH\\x00\\x12[\\n\\tget_state\\x18\\t \\x01(\\x0b\\x32\\x46.aea.fetchai.ledger_api.v1_0_0.LedgerApiMessage.Get_State_PerformativeH\\x00\\x12w\\n\\x17get_transaction_receipt\\x18\\n \\x01(\\x0b\\x32T.aea.fetchai.ledger_api.v1_0_0.LedgerApiMessage.Get_Transaction_Receipt_PerformativeH\\x00\\x12g\\n\\x0fraw_transaction\\x18\\x0b \\x01(\\x0b\\x32L.aea.fetchai.ledger_api.v1_0_0.LedgerApiMessage.Raw_Transaction_PerformativeH\\x00\\x12w\\n\\x17send_signed_transaction\\x18\\x0c \\x01(\\x0b\\x32T.aea.fetchai.ledger_api.v1_0_0.LedgerApiMessage.Send_Signed_Transaction_PerformativeH\\x00\\x12S\\n\\x05state\\x18\\r \\x01(\\x0b\\x32\\x42.aea.fetchai.ledger_api.v1_0_0.LedgerApiMessage.State_PerformativeH\\x00\\x12m\\n\\x12transaction_digest\\x18\\x0e \\x01(\\x0b\\x32O.aea.fetchai.ledger_api.v1_0_0.LedgerApiMessage.Transaction_Digest_PerformativeH\\x00\\x12o\\n\\x13transaction_receipt\\x18\\x0f \\x01(\\x0b\\x32P.aea.fetchai.ledger_api.v1_0_0.LedgerApiMessage.Transaction_Receipt_PerformativeH\\x00\\x1a\\x18\\n\\x06Kwargs\\x12\\x0e\\n\\x06kwargs\\x18\\x01 \\x01(\\x0c\\x1a)\\n\\x0eRawTransaction\\x12\\x17\\n\\x0fraw_transaction\\x18\\x01 \\x01(\\x0c\\x1a/\\n\\x11SignedTransaction\\x12\\x1a\\n\\x12signed_transaction\\x18\\x01 \\x01(\\x0c\\x1a\\x16\\n\\x05State\\x12\\r\\n\\x05state\\x18\\x01 \\x01(\\x0c\\x1a\\x16\\n\\x05Terms\\x12\\r\\n\\x05terms\\x18\\x01 \\x01(\\x0c\\x1a/\\n\\x11TransactionDigest\\x12\\x1a\\n\\x12transaction_digest\\x18\\x01 \\x01(\\x0c\\x1a\\x31\\n\\x12TransactionReceipt\\x12\\x1b\\n\\x13transaction_receipt\\x18\\x01 \\x01(\\x0c\\x1a>\\n\\x18Get_Balance_Performative\\x12\\x11\\n\\tledger_id\\x18\\x01 \\x01(\\t\\x12\\x0f\\n\\x07\\x61\\x64\\x64ress\\x18\\x02 \\x01(\\t\\x1ah\\n Get_Raw_Transaction_Performative\\x12\\x44\\n\\x05terms\\x18\\x01 \\x01(\\x0b\\x32\\x35.aea.fetchai.ledger_api.v1_0_0.LedgerApiMessage.Terms\\x1a\\x85\\x01\\n$Send_Signed_Transaction_Performative\\x12]\\n\\x12signed_transaction\\x18\\x01 \\x01(\\x0b\\x32\\x41.aea.fetchai.ledger_api.v1_0_0.LedgerApiMessage.SignedTransaction\\x1a\\x85\\x01\\n$Get_Transaction_Receipt_Performative\\x12]\\n\\x12transaction_digest\\x18\\x01 \\x01(\\x0b\\x32\\x41.aea.fetchai.ledger_api.v1_0_0.LedgerApiMessage.TransactionDigest\\x1a:\\n\\x14\\x42\\x61lance_Performative\\x12\\x11\\n\\tledger_id\\x18\\x01 \\x01(\\t\\x12\\x0f\\n\\x07\\x62\\x61lance\\x18\\x02 \\x01(\\x03\\x1aw\\n\\x1cRaw_Transaction_Performative\\x12W\\n\\x0fraw_transaction\\x18\\x01 \\x01(\\x0b\\x32>.aea.fetchai.ledger_api.v1_0_0.LedgerApiMessage.RawTransaction\\x1a\\x80\\x01\\n\\x1fTransaction_Digest_Performative\\x12]\\n\\x12transaction_digest\\x18\\x01 \\x01(\\x0b\\x32\\x41.aea.fetchai.ledger_api.v1_0_0.LedgerApiMessage.TransactionDigest\\x1a\\x83\\x01\\n Transaction_Receipt_Performative\\x12_\\n\\x13transaction_receipt\\x18\\x01 \\x01(\\x0b\\x32\\x42.aea.fetchai.ledger_api.v1_0_0.LedgerApiMessage.TransactionReceipt\\x1a\\x93\\x01\\n\\x16Get_State_Performative\\x12\\x11\\n\\tledger_id\\x18\\x01 \\x01(\\t\\x12\\x10\\n\\x08\\x63\\x61llable\\x18\\x02 \\x01(\\t\\x12\\x0c\\n\\x04\\x61rgs\\x18\\x03 \\x03(\\t\\x12\\x46\\n\\x06kwargs\\x18\\x04 \\x01(\\x0b\\x32\\x36.aea.fetchai.ledger_api.v1_0_0.LedgerApiMessage.Kwargs\\x1am\\n\\x12State_Performative\\x12\\x11\\n\\tledger_id\\x18\\x01 \\x01(\\t\\x12\\x44\\n\\x05state\\x18\\x02 \\x01(\\x0b\\x32\\x35.aea.fetchai.ledger_api.v1_0_0.LedgerApiMessage.State\\x1an\\n\\x12\\x45rror_Performative\\x12\\x0c\\n\\x04\\x63ode\\x18\\x01 \\x01(\\x03\\x12\\x0f\\n\\x07message\\x18\\x02 \\x01(\\t\\x12\\x16\\n\\x0emessage_is_set\\x18\\x03 \\x01(\\x08\\x12\\x0c\\n\\x04\\x64\\x61ta\\x18\\x04 \\x01(\\x0c\\x12\\x13\\n\\x0b\\x64\\x61ta_is_set\\x18\\x05 \\x01(\\x08\\x42\\x0e\\n\\x0cperformativeb\\x06proto3'\n)\n\n\n_LEDGERAPIMESSAGE = DESCRIPTOR.message_types_by_name[\"LedgerApiMessage\"]\n_LEDGERAPIMESSAGE_KWARGS = _LEDGERAPIMESSAGE.nested_types_by_name[\"Kwargs\"]\n_LEDGERAPIMESSAGE_RAWTRANSACTION = _LEDGERAPIMESSAGE.nested_types_by_name[\n    \"RawTransaction\"\n]\n_LEDGERAPIMESSAGE_SIGNEDTRANSACTION = _LEDGERAPIMESSAGE.nested_types_by_name[\n    \"SignedTransaction\"\n]\n_LEDGERAPIMESSAGE_STATE = _LEDGERAPIMESSAGE.nested_types_by_name[\"State\"]\n_LEDGERAPIMESSAGE_TERMS = _LEDGERAPIMESSAGE.nested_types_by_name[\"Terms\"]\n_LEDGERAPIMESSAGE_TRANSACTIONDIGEST = _LEDGERAPIMESSAGE.nested_types_by_name[\n    \"TransactionDigest\"\n]\n_LEDGERAPIMESSAGE_TRANSACTIONRECEIPT = _LEDGERAPIMESSAGE.nested_types_by_name[\n    \"TransactionReceipt\"\n]\n_LEDGERAPIMESSAGE_GET_BALANCE_PERFORMATIVE = _LEDGERAPIMESSAGE.nested_types_by_name[\n    \"Get_Balance_Performative\"\n]\n_LEDGERAPIMESSAGE_GET_RAW_TRANSACTION_PERFORMATIVE = (\n    _LEDGERAPIMESSAGE.nested_types_by_name[\"Get_Raw_Transaction_Performative\"]\n)\n_LEDGERAPIMESSAGE_SEND_SIGNED_TRANSACTION_PERFORMATIVE = (\n    _LEDGERAPIMESSAGE.nested_types_by_name[\"Send_Signed_Transaction_Performative\"]\n)\n_LEDGERAPIMESSAGE_GET_TRANSACTION_RECEIPT_PERFORMATIVE = (\n    _LEDGERAPIMESSAGE.nested_types_by_name[\"Get_Transaction_Receipt_Performative\"]\n)\n_LEDGERAPIMESSAGE_BALANCE_PERFORMATIVE = _LEDGERAPIMESSAGE.nested_types_by_name[\n    \"Balance_Performative\"\n]\n_LEDGERAPIMESSAGE_RAW_TRANSACTION_PERFORMATIVE = _LEDGERAPIMESSAGE.nested_types_by_name[\n    \"Raw_Transaction_Performative\"\n]\n_LEDGERAPIMESSAGE_TRANSACTION_DIGEST_PERFORMATIVE = (\n    _LEDGERAPIMESSAGE.nested_types_by_name[\"Transaction_Digest_Performative\"]\n)\n_LEDGERAPIMESSAGE_TRANSACTION_RECEIPT_PERFORMATIVE = (\n    _LEDGERAPIMESSAGE.nested_types_by_name[\"Transaction_Receipt_Performative\"]\n)\n_LEDGERAPIMESSAGE_GET_STATE_PERFORMATIVE = _LEDGERAPIMESSAGE.nested_types_by_name[\n    \"Get_State_Performative\"\n]\n_LEDGERAPIMESSAGE_STATE_PERFORMATIVE = _LEDGERAPIMESSAGE.nested_types_by_name[\n    \"State_Performative\"\n]\n_LEDGERAPIMESSAGE_ERROR_PERFORMATIVE = _LEDGERAPIMESSAGE.nested_types_by_name[\n    \"Error_Performative\"\n]\nLedgerApiMessage = _reflection.GeneratedProtocolMessageType(\n    \"LedgerApiMessage\",\n    (_message.Message,),\n    {\n        \"Kwargs\": _reflection.GeneratedProtocolMessageType(\n            \"Kwargs\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _LEDGERAPIMESSAGE_KWARGS,\n                \"__module__\": \"ledger_api_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.ledger_api.v1_0_0.LedgerApiMessage.Kwargs)\n            },\n        ),\n        \"RawTransaction\": _reflection.GeneratedProtocolMessageType(\n            \"RawTransaction\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _LEDGERAPIMESSAGE_RAWTRANSACTION,\n                \"__module__\": \"ledger_api_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.ledger_api.v1_0_0.LedgerApiMessage.RawTransaction)\n            },\n        ),\n        \"SignedTransaction\": _reflection.GeneratedProtocolMessageType(\n            \"SignedTransaction\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _LEDGERAPIMESSAGE_SIGNEDTRANSACTION,\n                \"__module__\": \"ledger_api_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.ledger_api.v1_0_0.LedgerApiMessage.SignedTransaction)\n            },\n        ),\n        \"State\": _reflection.GeneratedProtocolMessageType(\n            \"State\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _LEDGERAPIMESSAGE_STATE,\n                \"__module__\": \"ledger_api_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.ledger_api.v1_0_0.LedgerApiMessage.State)\n            },\n        ),\n        \"Terms\": _reflection.GeneratedProtocolMessageType(\n            \"Terms\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _LEDGERAPIMESSAGE_TERMS,\n                \"__module__\": \"ledger_api_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.ledger_api.v1_0_0.LedgerApiMessage.Terms)\n            },\n        ),\n        \"TransactionDigest\": _reflection.GeneratedProtocolMessageType(\n            \"TransactionDigest\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _LEDGERAPIMESSAGE_TRANSACTIONDIGEST,\n                \"__module__\": \"ledger_api_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.ledger_api.v1_0_0.LedgerApiMessage.TransactionDigest)\n            },\n        ),\n        \"TransactionReceipt\": _reflection.GeneratedProtocolMessageType(\n            \"TransactionReceipt\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _LEDGERAPIMESSAGE_TRANSACTIONRECEIPT,\n                \"__module__\": \"ledger_api_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.ledger_api.v1_0_0.LedgerApiMessage.TransactionReceipt)\n            },\n        ),\n        \"Get_Balance_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Get_Balance_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _LEDGERAPIMESSAGE_GET_BALANCE_PERFORMATIVE,\n                \"__module__\": \"ledger_api_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.ledger_api.v1_0_0.LedgerApiMessage.Get_Balance_Performative)\n            },\n        ),\n        \"Get_Raw_Transaction_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Get_Raw_Transaction_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _LEDGERAPIMESSAGE_GET_RAW_TRANSACTION_PERFORMATIVE,\n                \"__module__\": \"ledger_api_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.ledger_api.v1_0_0.LedgerApiMessage.Get_Raw_Transaction_Performative)\n            },\n        ),\n        \"Send_Signed_Transaction_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Send_Signed_Transaction_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _LEDGERAPIMESSAGE_SEND_SIGNED_TRANSACTION_PERFORMATIVE,\n                \"__module__\": \"ledger_api_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.ledger_api.v1_0_0.LedgerApiMessage.Send_Signed_Transaction_Performative)\n            },\n        ),\n        \"Get_Transaction_Receipt_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Get_Transaction_Receipt_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _LEDGERAPIMESSAGE_GET_TRANSACTION_RECEIPT_PERFORMATIVE,\n                \"__module__\": \"ledger_api_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.ledger_api.v1_0_0.LedgerApiMessage.Get_Transaction_Receipt_Performative)\n            },\n        ),\n        \"Balance_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Balance_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _LEDGERAPIMESSAGE_BALANCE_PERFORMATIVE,\n                \"__module__\": \"ledger_api_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.ledger_api.v1_0_0.LedgerApiMessage.Balance_Performative)\n            },\n        ),\n        \"Raw_Transaction_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Raw_Transaction_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _LEDGERAPIMESSAGE_RAW_TRANSACTION_PERFORMATIVE,\n                \"__module__\": \"ledger_api_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.ledger_api.v1_0_0.LedgerApiMessage.Raw_Transaction_Performative)\n            },\n        ),\n        \"Transaction_Digest_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Transaction_Digest_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _LEDGERAPIMESSAGE_TRANSACTION_DIGEST_PERFORMATIVE,\n                \"__module__\": \"ledger_api_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.ledger_api.v1_0_0.LedgerApiMessage.Transaction_Digest_Performative)\n            },\n        ),\n        \"Transaction_Receipt_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Transaction_Receipt_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _LEDGERAPIMESSAGE_TRANSACTION_RECEIPT_PERFORMATIVE,\n                \"__module__\": \"ledger_api_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.ledger_api.v1_0_0.LedgerApiMessage.Transaction_Receipt_Performative)\n            },\n        ),\n        \"Get_State_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Get_State_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _LEDGERAPIMESSAGE_GET_STATE_PERFORMATIVE,\n                \"__module__\": \"ledger_api_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.ledger_api.v1_0_0.LedgerApiMessage.Get_State_Performative)\n            },\n        ),\n        \"State_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"State_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _LEDGERAPIMESSAGE_STATE_PERFORMATIVE,\n                \"__module__\": \"ledger_api_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.ledger_api.v1_0_0.LedgerApiMessage.State_Performative)\n            },\n        ),\n        \"Error_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Error_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _LEDGERAPIMESSAGE_ERROR_PERFORMATIVE,\n                \"__module__\": \"ledger_api_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.ledger_api.v1_0_0.LedgerApiMessage.Error_Performative)\n            },\n        ),\n        \"DESCRIPTOR\": _LEDGERAPIMESSAGE,\n        \"__module__\": \"ledger_api_pb2\"\n        # @@protoc_insertion_point(class_scope:aea.fetchai.ledger_api.v1_0_0.LedgerApiMessage)\n    },\n)\n_sym_db.RegisterMessage(LedgerApiMessage)\n_sym_db.RegisterMessage(LedgerApiMessage.Kwargs)\n_sym_db.RegisterMessage(LedgerApiMessage.RawTransaction)\n_sym_db.RegisterMessage(LedgerApiMessage.SignedTransaction)\n_sym_db.RegisterMessage(LedgerApiMessage.State)\n_sym_db.RegisterMessage(LedgerApiMessage.Terms)\n_sym_db.RegisterMessage(LedgerApiMessage.TransactionDigest)\n_sym_db.RegisterMessage(LedgerApiMessage.TransactionReceipt)\n_sym_db.RegisterMessage(LedgerApiMessage.Get_Balance_Performative)\n_sym_db.RegisterMessage(LedgerApiMessage.Get_Raw_Transaction_Performative)\n_sym_db.RegisterMessage(LedgerApiMessage.Send_Signed_Transaction_Performative)\n_sym_db.RegisterMessage(LedgerApiMessage.Get_Transaction_Receipt_Performative)\n_sym_db.RegisterMessage(LedgerApiMessage.Balance_Performative)\n_sym_db.RegisterMessage(LedgerApiMessage.Raw_Transaction_Performative)\n_sym_db.RegisterMessage(LedgerApiMessage.Transaction_Digest_Performative)\n_sym_db.RegisterMessage(LedgerApiMessage.Transaction_Receipt_Performative)\n_sym_db.RegisterMessage(LedgerApiMessage.Get_State_Performative)\n_sym_db.RegisterMessage(LedgerApiMessage.State_Performative)\n_sym_db.RegisterMessage(LedgerApiMessage.Error_Performative)\n\nif _descriptor._USE_C_DESCRIPTORS == False:\n\n    DESCRIPTOR._options = None\n    _LEDGERAPIMESSAGE._serialized_start = 52\n    _LEDGERAPIMESSAGE._serialized_end = 2746\n    _LEDGERAPIMESSAGE_KWARGS._serialized_start = 1205\n    _LEDGERAPIMESSAGE_KWARGS._serialized_end = 1229\n    _LEDGERAPIMESSAGE_RAWTRANSACTION._serialized_start = 1231\n    _LEDGERAPIMESSAGE_RAWTRANSACTION._serialized_end = 1272\n    _LEDGERAPIMESSAGE_SIGNEDTRANSACTION._serialized_start = 1274\n    _LEDGERAPIMESSAGE_SIGNEDTRANSACTION._serialized_end = 1321\n    _LEDGERAPIMESSAGE_STATE._serialized_start = 1323\n    _LEDGERAPIMESSAGE_STATE._serialized_end = 1345\n    _LEDGERAPIMESSAGE_TERMS._serialized_start = 1347\n    _LEDGERAPIMESSAGE_TERMS._serialized_end = 1369\n    _LEDGERAPIMESSAGE_TRANSACTIONDIGEST._serialized_start = 1371\n    _LEDGERAPIMESSAGE_TRANSACTIONDIGEST._serialized_end = 1418\n    _LEDGERAPIMESSAGE_TRANSACTIONRECEIPT._serialized_start = 1420\n    _LEDGERAPIMESSAGE_TRANSACTIONRECEIPT._serialized_end = 1469\n    _LEDGERAPIMESSAGE_GET_BALANCE_PERFORMATIVE._serialized_start = 1471\n    _LEDGERAPIMESSAGE_GET_BALANCE_PERFORMATIVE._serialized_end = 1533\n    _LEDGERAPIMESSAGE_GET_RAW_TRANSACTION_PERFORMATIVE._serialized_start = 1535\n    _LEDGERAPIMESSAGE_GET_RAW_TRANSACTION_PERFORMATIVE._serialized_end = 1639\n    _LEDGERAPIMESSAGE_SEND_SIGNED_TRANSACTION_PERFORMATIVE._serialized_start = 1642\n    _LEDGERAPIMESSAGE_SEND_SIGNED_TRANSACTION_PERFORMATIVE._serialized_end = 1775\n    _LEDGERAPIMESSAGE_GET_TRANSACTION_RECEIPT_PERFORMATIVE._serialized_start = 1778\n    _LEDGERAPIMESSAGE_GET_TRANSACTION_RECEIPT_PERFORMATIVE._serialized_end = 1911\n    _LEDGERAPIMESSAGE_BALANCE_PERFORMATIVE._serialized_start = 1913\n    _LEDGERAPIMESSAGE_BALANCE_PERFORMATIVE._serialized_end = 1971\n    _LEDGERAPIMESSAGE_RAW_TRANSACTION_PERFORMATIVE._serialized_start = 1973\n    _LEDGERAPIMESSAGE_RAW_TRANSACTION_PERFORMATIVE._serialized_end = 2092\n    _LEDGERAPIMESSAGE_TRANSACTION_DIGEST_PERFORMATIVE._serialized_start = 2095\n    _LEDGERAPIMESSAGE_TRANSACTION_DIGEST_PERFORMATIVE._serialized_end = 2223\n    _LEDGERAPIMESSAGE_TRANSACTION_RECEIPT_PERFORMATIVE._serialized_start = 2226\n    _LEDGERAPIMESSAGE_TRANSACTION_RECEIPT_PERFORMATIVE._serialized_end = 2357\n    _LEDGERAPIMESSAGE_GET_STATE_PERFORMATIVE._serialized_start = 2360\n    _LEDGERAPIMESSAGE_GET_STATE_PERFORMATIVE._serialized_end = 2507\n    _LEDGERAPIMESSAGE_STATE_PERFORMATIVE._serialized_start = 2509\n    _LEDGERAPIMESSAGE_STATE_PERFORMATIVE._serialized_end = 2618\n    _LEDGERAPIMESSAGE_ERROR_PERFORMATIVE._serialized_start = 2620\n    _LEDGERAPIMESSAGE_ERROR_PERFORMATIVE._serialized_end = 2730\n# @@protoc_insertion_point(module_scope)\n"
  },
  {
    "path": "packages/fetchai/protocols/ledger_api/message.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains ledger_api's message definition.\"\"\"\n\n# pylint: disable=too-many-statements,too-many-locals,no-member,too-few-public-methods,too-many-branches,not-an-iterable,unidiomatic-typecheck,unsubscriptable-object\nimport logging\nfrom typing import Any, Optional, Set, Tuple, cast\n\nfrom aea.configurations.base import PublicId\nfrom aea.exceptions import AEAEnforceError, enforce\nfrom aea.protocols.base import Message\n\nfrom packages.fetchai.protocols.ledger_api.custom_types import Kwargs as CustomKwargs\nfrom packages.fetchai.protocols.ledger_api.custom_types import (\n    RawTransaction as CustomRawTransaction,\n)\nfrom packages.fetchai.protocols.ledger_api.custom_types import (\n    SignedTransaction as CustomSignedTransaction,\n)\nfrom packages.fetchai.protocols.ledger_api.custom_types import State as CustomState\nfrom packages.fetchai.protocols.ledger_api.custom_types import Terms as CustomTerms\nfrom packages.fetchai.protocols.ledger_api.custom_types import (\n    TransactionDigest as CustomTransactionDigest,\n)\nfrom packages.fetchai.protocols.ledger_api.custom_types import (\n    TransactionReceipt as CustomTransactionReceipt,\n)\n\n\n_default_logger = logging.getLogger(\"aea.packages.fetchai.protocols.ledger_api.message\")\n\nDEFAULT_BODY_SIZE = 4\n\n\nclass LedgerApiMessage(Message):\n    \"\"\"A protocol for ledger APIs requests and responses.\"\"\"\n\n    protocol_id = PublicId.from_str(\"fetchai/ledger_api:1.1.7\")\n    protocol_specification_id = PublicId.from_str(\"fetchai/ledger_api:1.0.0\")\n\n    Kwargs = CustomKwargs\n\n    RawTransaction = CustomRawTransaction\n\n    SignedTransaction = CustomSignedTransaction\n\n    State = CustomState\n\n    Terms = CustomTerms\n\n    TransactionDigest = CustomTransactionDigest\n\n    TransactionReceipt = CustomTransactionReceipt\n\n    class Performative(Message.Performative):\n        \"\"\"Performatives for the ledger_api protocol.\"\"\"\n\n        BALANCE = \"balance\"\n        ERROR = \"error\"\n        GET_BALANCE = \"get_balance\"\n        GET_RAW_TRANSACTION = \"get_raw_transaction\"\n        GET_STATE = \"get_state\"\n        GET_TRANSACTION_RECEIPT = \"get_transaction_receipt\"\n        RAW_TRANSACTION = \"raw_transaction\"\n        SEND_SIGNED_TRANSACTION = \"send_signed_transaction\"\n        STATE = \"state\"\n        TRANSACTION_DIGEST = \"transaction_digest\"\n        TRANSACTION_RECEIPT = \"transaction_receipt\"\n\n        def __str__(self) -> str:\n            \"\"\"Get the string representation.\"\"\"\n            return str(self.value)\n\n    _performatives = {\n        \"balance\",\n        \"error\",\n        \"get_balance\",\n        \"get_raw_transaction\",\n        \"get_state\",\n        \"get_transaction_receipt\",\n        \"raw_transaction\",\n        \"send_signed_transaction\",\n        \"state\",\n        \"transaction_digest\",\n        \"transaction_receipt\",\n    }\n    __slots__: Tuple[str, ...] = tuple()\n\n    class _SlotsCls:\n        __slots__ = (\n            \"address\",\n            \"args\",\n            \"balance\",\n            \"callable\",\n            \"code\",\n            \"data\",\n            \"dialogue_reference\",\n            \"kwargs\",\n            \"ledger_id\",\n            \"message\",\n            \"message_id\",\n            \"performative\",\n            \"raw_transaction\",\n            \"signed_transaction\",\n            \"state\",\n            \"target\",\n            \"terms\",\n            \"transaction_digest\",\n            \"transaction_receipt\",\n        )\n\n    def __init__(\n        self,\n        performative: Performative,\n        dialogue_reference: Tuple[str, str] = (\"\", \"\"),\n        message_id: int = 1,\n        target: int = 0,\n        **kwargs: Any,\n    ):\n        \"\"\"\n        Initialise an instance of LedgerApiMessage.\n\n        :param message_id: the message id.\n        :param dialogue_reference: the dialogue reference.\n        :param target: the message target.\n        :param performative: the message performative.\n        :param **kwargs: extra options.\n        \"\"\"\n        super().__init__(\n            dialogue_reference=dialogue_reference,\n            message_id=message_id,\n            target=target,\n            performative=LedgerApiMessage.Performative(performative),\n            **kwargs,\n        )\n\n    @property\n    def valid_performatives(self) -> Set[str]:\n        \"\"\"Get valid performatives.\"\"\"\n        return self._performatives\n\n    @property\n    def dialogue_reference(self) -> Tuple[str, str]:\n        \"\"\"Get the dialogue_reference of the message.\"\"\"\n        enforce(self.is_set(\"dialogue_reference\"), \"dialogue_reference is not set.\")\n        return cast(Tuple[str, str], self.get(\"dialogue_reference\"))\n\n    @property\n    def message_id(self) -> int:\n        \"\"\"Get the message_id of the message.\"\"\"\n        enforce(self.is_set(\"message_id\"), \"message_id is not set.\")\n        return cast(int, self.get(\"message_id\"))\n\n    @property\n    def performative(self) -> Performative:  # type: ignore # noqa: F821\n        \"\"\"Get the performative of the message.\"\"\"\n        enforce(self.is_set(\"performative\"), \"performative is not set.\")\n        return cast(LedgerApiMessage.Performative, self.get(\"performative\"))\n\n    @property\n    def target(self) -> int:\n        \"\"\"Get the target of the message.\"\"\"\n        enforce(self.is_set(\"target\"), \"target is not set.\")\n        return cast(int, self.get(\"target\"))\n\n    @property\n    def address(self) -> str:\n        \"\"\"Get the 'address' content from the message.\"\"\"\n        enforce(self.is_set(\"address\"), \"'address' content is not set.\")\n        return cast(str, self.get(\"address\"))\n\n    @property\n    def args(self) -> Tuple[str, ...]:\n        \"\"\"Get the 'args' content from the message.\"\"\"\n        enforce(self.is_set(\"args\"), \"'args' content is not set.\")\n        return cast(Tuple[str, ...], self.get(\"args\"))\n\n    @property\n    def balance(self) -> int:\n        \"\"\"Get the 'balance' content from the message.\"\"\"\n        enforce(self.is_set(\"balance\"), \"'balance' content is not set.\")\n        return cast(int, self.get(\"balance\"))\n\n    @property\n    def callable(self) -> str:\n        \"\"\"Get the 'callable' content from the message.\"\"\"\n        enforce(self.is_set(\"callable\"), \"'callable' content is not set.\")\n        return cast(str, self.get(\"callable\"))\n\n    @property\n    def code(self) -> int:\n        \"\"\"Get the 'code' content from the message.\"\"\"\n        enforce(self.is_set(\"code\"), \"'code' content is not set.\")\n        return cast(int, self.get(\"code\"))\n\n    @property\n    def data(self) -> Optional[bytes]:\n        \"\"\"Get the 'data' content from the message.\"\"\"\n        return cast(Optional[bytes], self.get(\"data\"))\n\n    @property\n    def kwargs(self) -> CustomKwargs:\n        \"\"\"Get the 'kwargs' content from the message.\"\"\"\n        enforce(self.is_set(\"kwargs\"), \"'kwargs' content is not set.\")\n        return cast(CustomKwargs, self.get(\"kwargs\"))\n\n    @property\n    def ledger_id(self) -> str:\n        \"\"\"Get the 'ledger_id' content from the message.\"\"\"\n        enforce(self.is_set(\"ledger_id\"), \"'ledger_id' content is not set.\")\n        return cast(str, self.get(\"ledger_id\"))\n\n    @property\n    def message(self) -> Optional[str]:\n        \"\"\"Get the 'message' content from the message.\"\"\"\n        return cast(Optional[str], self.get(\"message\"))\n\n    @property\n    def raw_transaction(self) -> CustomRawTransaction:\n        \"\"\"Get the 'raw_transaction' content from the message.\"\"\"\n        enforce(self.is_set(\"raw_transaction\"), \"'raw_transaction' content is not set.\")\n        return cast(CustomRawTransaction, self.get(\"raw_transaction\"))\n\n    @property\n    def signed_transaction(self) -> CustomSignedTransaction:\n        \"\"\"Get the 'signed_transaction' content from the message.\"\"\"\n        enforce(\n            self.is_set(\"signed_transaction\"),\n            \"'signed_transaction' content is not set.\",\n        )\n        return cast(CustomSignedTransaction, self.get(\"signed_transaction\"))\n\n    @property\n    def state(self) -> CustomState:\n        \"\"\"Get the 'state' content from the message.\"\"\"\n        enforce(self.is_set(\"state\"), \"'state' content is not set.\")\n        return cast(CustomState, self.get(\"state\"))\n\n    @property\n    def terms(self) -> CustomTerms:\n        \"\"\"Get the 'terms' content from the message.\"\"\"\n        enforce(self.is_set(\"terms\"), \"'terms' content is not set.\")\n        return cast(CustomTerms, self.get(\"terms\"))\n\n    @property\n    def transaction_digest(self) -> CustomTransactionDigest:\n        \"\"\"Get the 'transaction_digest' content from the message.\"\"\"\n        enforce(\n            self.is_set(\"transaction_digest\"),\n            \"'transaction_digest' content is not set.\",\n        )\n        return cast(CustomTransactionDigest, self.get(\"transaction_digest\"))\n\n    @property\n    def transaction_receipt(self) -> CustomTransactionReceipt:\n        \"\"\"Get the 'transaction_receipt' content from the message.\"\"\"\n        enforce(\n            self.is_set(\"transaction_receipt\"),\n            \"'transaction_receipt' content is not set.\",\n        )\n        return cast(CustomTransactionReceipt, self.get(\"transaction_receipt\"))\n\n    def _is_consistent(self) -> bool:\n        \"\"\"Check that the message follows the ledger_api protocol.\"\"\"\n        try:\n            enforce(\n                isinstance(self.dialogue_reference, tuple),\n                \"Invalid type for 'dialogue_reference'. Expected 'tuple'. Found '{}'.\".format(\n                    type(self.dialogue_reference)\n                ),\n            )\n            enforce(\n                isinstance(self.dialogue_reference[0], str),\n                \"Invalid type for 'dialogue_reference[0]'. Expected 'str'. Found '{}'.\".format(\n                    type(self.dialogue_reference[0])\n                ),\n            )\n            enforce(\n                isinstance(self.dialogue_reference[1], str),\n                \"Invalid type for 'dialogue_reference[1]'. Expected 'str'. Found '{}'.\".format(\n                    type(self.dialogue_reference[1])\n                ),\n            )\n            enforce(\n                type(self.message_id) is int,\n                \"Invalid type for 'message_id'. Expected 'int'. Found '{}'.\".format(\n                    type(self.message_id)\n                ),\n            )\n            enforce(\n                type(self.target) is int,\n                \"Invalid type for 'target'. Expected 'int'. Found '{}'.\".format(\n                    type(self.target)\n                ),\n            )\n\n            # Light Protocol Rule 2\n            # Check correct performative\n            enforce(\n                isinstance(self.performative, LedgerApiMessage.Performative),\n                \"Invalid 'performative'. Expected either of '{}'. Found '{}'.\".format(\n                    self.valid_performatives, self.performative\n                ),\n            )\n\n            # Check correct contents\n            actual_nb_of_contents = len(self._body) - DEFAULT_BODY_SIZE\n            expected_nb_of_contents = 0\n            if self.performative == LedgerApiMessage.Performative.GET_BALANCE:\n                expected_nb_of_contents = 2\n                enforce(\n                    isinstance(self.ledger_id, str),\n                    \"Invalid type for content 'ledger_id'. Expected 'str'. Found '{}'.\".format(\n                        type(self.ledger_id)\n                    ),\n                )\n                enforce(\n                    isinstance(self.address, str),\n                    \"Invalid type for content 'address'. Expected 'str'. Found '{}'.\".format(\n                        type(self.address)\n                    ),\n                )\n            elif self.performative == LedgerApiMessage.Performative.GET_RAW_TRANSACTION:\n                expected_nb_of_contents = 1\n                enforce(\n                    isinstance(self.terms, CustomTerms),\n                    \"Invalid type for content 'terms'. Expected 'Terms'. Found '{}'.\".format(\n                        type(self.terms)\n                    ),\n                )\n            elif (\n                self.performative\n                == LedgerApiMessage.Performative.SEND_SIGNED_TRANSACTION\n            ):\n                expected_nb_of_contents = 1\n                enforce(\n                    isinstance(self.signed_transaction, CustomSignedTransaction),\n                    \"Invalid type for content 'signed_transaction'. Expected 'SignedTransaction'. Found '{}'.\".format(\n                        type(self.signed_transaction)\n                    ),\n                )\n            elif (\n                self.performative\n                == LedgerApiMessage.Performative.GET_TRANSACTION_RECEIPT\n            ):\n                expected_nb_of_contents = 1\n                enforce(\n                    isinstance(self.transaction_digest, CustomTransactionDigest),\n                    \"Invalid type for content 'transaction_digest'. Expected 'TransactionDigest'. Found '{}'.\".format(\n                        type(self.transaction_digest)\n                    ),\n                )\n            elif self.performative == LedgerApiMessage.Performative.BALANCE:\n                expected_nb_of_contents = 2\n                enforce(\n                    isinstance(self.ledger_id, str),\n                    \"Invalid type for content 'ledger_id'. Expected 'str'. Found '{}'.\".format(\n                        type(self.ledger_id)\n                    ),\n                )\n                enforce(\n                    type(self.balance) is int,\n                    \"Invalid type for content 'balance'. Expected 'int'. Found '{}'.\".format(\n                        type(self.balance)\n                    ),\n                )\n            elif self.performative == LedgerApiMessage.Performative.RAW_TRANSACTION:\n                expected_nb_of_contents = 1\n                enforce(\n                    isinstance(self.raw_transaction, CustomRawTransaction),\n                    \"Invalid type for content 'raw_transaction'. Expected 'RawTransaction'. Found '{}'.\".format(\n                        type(self.raw_transaction)\n                    ),\n                )\n            elif self.performative == LedgerApiMessage.Performative.TRANSACTION_DIGEST:\n                expected_nb_of_contents = 1\n                enforce(\n                    isinstance(self.transaction_digest, CustomTransactionDigest),\n                    \"Invalid type for content 'transaction_digest'. Expected 'TransactionDigest'. Found '{}'.\".format(\n                        type(self.transaction_digest)\n                    ),\n                )\n            elif self.performative == LedgerApiMessage.Performative.TRANSACTION_RECEIPT:\n                expected_nb_of_contents = 1\n                enforce(\n                    isinstance(self.transaction_receipt, CustomTransactionReceipt),\n                    \"Invalid type for content 'transaction_receipt'. Expected 'TransactionReceipt'. Found '{}'.\".format(\n                        type(self.transaction_receipt)\n                    ),\n                )\n            elif self.performative == LedgerApiMessage.Performative.GET_STATE:\n                expected_nb_of_contents = 4\n                enforce(\n                    isinstance(self.ledger_id, str),\n                    \"Invalid type for content 'ledger_id'. Expected 'str'. Found '{}'.\".format(\n                        type(self.ledger_id)\n                    ),\n                )\n                enforce(\n                    isinstance(self.callable, str),\n                    \"Invalid type for content 'callable'. Expected 'str'. Found '{}'.\".format(\n                        type(self.callable)\n                    ),\n                )\n                enforce(\n                    isinstance(self.args, tuple),\n                    \"Invalid type for content 'args'. Expected 'tuple'. Found '{}'.\".format(\n                        type(self.args)\n                    ),\n                )\n                enforce(\n                    all(isinstance(element, str) for element in self.args),\n                    \"Invalid type for tuple elements in content 'args'. Expected 'str'.\",\n                )\n                enforce(\n                    isinstance(self.kwargs, CustomKwargs),\n                    \"Invalid type for content 'kwargs'. Expected 'Kwargs'. Found '{}'.\".format(\n                        type(self.kwargs)\n                    ),\n                )\n            elif self.performative == LedgerApiMessage.Performative.STATE:\n                expected_nb_of_contents = 2\n                enforce(\n                    isinstance(self.ledger_id, str),\n                    \"Invalid type for content 'ledger_id'. Expected 'str'. Found '{}'.\".format(\n                        type(self.ledger_id)\n                    ),\n                )\n                enforce(\n                    isinstance(self.state, CustomState),\n                    \"Invalid type for content 'state'. Expected 'State'. Found '{}'.\".format(\n                        type(self.state)\n                    ),\n                )\n            elif self.performative == LedgerApiMessage.Performative.ERROR:\n                expected_nb_of_contents = 1\n                enforce(\n                    type(self.code) is int,\n                    \"Invalid type for content 'code'. Expected 'int'. Found '{}'.\".format(\n                        type(self.code)\n                    ),\n                )\n                if self.is_set(\"message\"):\n                    expected_nb_of_contents += 1\n                    message = cast(str, self.message)\n                    enforce(\n                        isinstance(message, str),\n                        \"Invalid type for content 'message'. Expected 'str'. Found '{}'.\".format(\n                            type(message)\n                        ),\n                    )\n                if self.is_set(\"data\"):\n                    expected_nb_of_contents += 1\n                    data = cast(bytes, self.data)\n                    enforce(\n                        isinstance(data, bytes),\n                        \"Invalid type for content 'data'. Expected 'bytes'. Found '{}'.\".format(\n                            type(data)\n                        ),\n                    )\n\n            # Check correct content count\n            enforce(\n                expected_nb_of_contents == actual_nb_of_contents,\n                \"Incorrect number of contents. Expected {}. Found {}\".format(\n                    expected_nb_of_contents, actual_nb_of_contents\n                ),\n            )\n\n            # Light Protocol Rule 3\n            if self.message_id == 1:\n                enforce(\n                    self.target == 0,\n                    \"Invalid 'target'. Expected 0 (because 'message_id' is 1). Found {}.\".format(\n                        self.target\n                    ),\n                )\n        except (AEAEnforceError, ValueError, KeyError) as e:\n            _default_logger.error(str(e))\n            return False\n\n        return True\n"
  },
  {
    "path": "packages/fetchai/protocols/ledger_api/protocol.yaml",
    "content": "name: ledger_api\nauthor: fetchai\nversion: 1.1.7\nprotocol_specification_id: fetchai/ledger_api:1.0.0\ntype: protocol\ndescription: A protocol for ledger APIs requests and responses.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: QmPh9s795kuU8tCggTPTuAcHC95dkf6CNPUwRCZvZnQ7ty\n  __init__.py: QmUTxKefDQ2Pek9zDDFkSBG79vJnbPftX7mLvoEWg8Qw2w\n  custom_types.py: QmVHe1LBaErJseoa5QbhpvbEpFZXx4vaaBveREGNmwZs91\n  dialogues.py: QmZ7iDRuQs32KxGEutUrHqTeVHa8UTTje2tvVa8ELu3kDy\n  ledger_api.proto: QmR92cmoxSxKANTvCmm9skftvgzYobNwcWCUanNkduJjyh\n  ledger_api_pb2.py: QmNt9mSa71PcXDHFDwEWb3ay4RAE11KURX8hzZmFj8voEo\n  message.py: QmbeVWQTAkLybFVLyemoMtotXaU7DyjByXz2JW5pxXob1M\n  serialization.py: QmbYMuLC59Emc8hwW8ELcFRaT8xiXakdL2p5vCyBE8PnCg\nfingerprint_ignore_patterns: []\ndependencies:\n  protobuf: {}\n"
  },
  {
    "path": "packages/fetchai/protocols/ledger_api/serialization.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Serialization module for ledger_api protocol.\"\"\"\n\n# pylint: disable=too-many-statements,too-many-locals,no-member,too-few-public-methods,redefined-builtin\nfrom typing import Any, Dict, cast\n\nfrom aea.mail.base_pb2 import DialogueMessage\nfrom aea.mail.base_pb2 import Message as ProtobufMessage\nfrom aea.protocols.base import Message, Serializer\n\nfrom packages.fetchai.protocols.ledger_api import ledger_api_pb2\nfrom packages.fetchai.protocols.ledger_api.custom_types import (\n    Kwargs,\n    RawTransaction,\n    SignedTransaction,\n    State,\n    Terms,\n    TransactionDigest,\n    TransactionReceipt,\n)\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\n\n\nclass LedgerApiSerializer(Serializer):\n    \"\"\"Serialization for the 'ledger_api' protocol.\"\"\"\n\n    @staticmethod\n    def encode(msg: Message) -> bytes:\n        \"\"\"\n        Encode a 'LedgerApi' message into bytes.\n\n        :param msg: the message object.\n        :return: the bytes.\n        \"\"\"\n        msg = cast(LedgerApiMessage, msg)\n        message_pb = ProtobufMessage()\n        dialogue_message_pb = DialogueMessage()\n        ledger_api_msg = ledger_api_pb2.LedgerApiMessage()\n\n        dialogue_message_pb.message_id = msg.message_id\n        dialogue_reference = msg.dialogue_reference\n        dialogue_message_pb.dialogue_starter_reference = dialogue_reference[0]\n        dialogue_message_pb.dialogue_responder_reference = dialogue_reference[1]\n        dialogue_message_pb.target = msg.target\n\n        performative_id = msg.performative\n        if performative_id == LedgerApiMessage.Performative.GET_BALANCE:\n            performative = ledger_api_pb2.LedgerApiMessage.Get_Balance_Performative()  # type: ignore\n            ledger_id = msg.ledger_id\n            performative.ledger_id = ledger_id\n            address = msg.address\n            performative.address = address\n            ledger_api_msg.get_balance.CopyFrom(performative)\n        elif performative_id == LedgerApiMessage.Performative.GET_RAW_TRANSACTION:\n            performative = ledger_api_pb2.LedgerApiMessage.Get_Raw_Transaction_Performative()  # type: ignore\n            terms = msg.terms\n            Terms.encode(performative.terms, terms)\n            ledger_api_msg.get_raw_transaction.CopyFrom(performative)\n        elif performative_id == LedgerApiMessage.Performative.SEND_SIGNED_TRANSACTION:\n            performative = ledger_api_pb2.LedgerApiMessage.Send_Signed_Transaction_Performative()  # type: ignore\n            signed_transaction = msg.signed_transaction\n            SignedTransaction.encode(\n                performative.signed_transaction, signed_transaction\n            )\n            ledger_api_msg.send_signed_transaction.CopyFrom(performative)\n        elif performative_id == LedgerApiMessage.Performative.GET_TRANSACTION_RECEIPT:\n            performative = ledger_api_pb2.LedgerApiMessage.Get_Transaction_Receipt_Performative()  # type: ignore\n            transaction_digest = msg.transaction_digest\n            TransactionDigest.encode(\n                performative.transaction_digest, transaction_digest\n            )\n            ledger_api_msg.get_transaction_receipt.CopyFrom(performative)\n        elif performative_id == LedgerApiMessage.Performative.BALANCE:\n            performative = ledger_api_pb2.LedgerApiMessage.Balance_Performative()  # type: ignore\n            ledger_id = msg.ledger_id\n            performative.ledger_id = ledger_id\n            balance = msg.balance\n            performative.balance = balance\n            ledger_api_msg.balance.CopyFrom(performative)\n        elif performative_id == LedgerApiMessage.Performative.RAW_TRANSACTION:\n            performative = ledger_api_pb2.LedgerApiMessage.Raw_Transaction_Performative()  # type: ignore\n            raw_transaction = msg.raw_transaction\n            RawTransaction.encode(performative.raw_transaction, raw_transaction)\n            ledger_api_msg.raw_transaction.CopyFrom(performative)\n        elif performative_id == LedgerApiMessage.Performative.TRANSACTION_DIGEST:\n            performative = ledger_api_pb2.LedgerApiMessage.Transaction_Digest_Performative()  # type: ignore\n            transaction_digest = msg.transaction_digest\n            TransactionDigest.encode(\n                performative.transaction_digest, transaction_digest\n            )\n            ledger_api_msg.transaction_digest.CopyFrom(performative)\n        elif performative_id == LedgerApiMessage.Performative.TRANSACTION_RECEIPT:\n            performative = ledger_api_pb2.LedgerApiMessage.Transaction_Receipt_Performative()  # type: ignore\n            transaction_receipt = msg.transaction_receipt\n            TransactionReceipt.encode(\n                performative.transaction_receipt, transaction_receipt\n            )\n            ledger_api_msg.transaction_receipt.CopyFrom(performative)\n        elif performative_id == LedgerApiMessage.Performative.GET_STATE:\n            performative = ledger_api_pb2.LedgerApiMessage.Get_State_Performative()  # type: ignore\n            ledger_id = msg.ledger_id\n            performative.ledger_id = ledger_id\n            callable = msg.callable\n            performative.callable = callable\n            args = msg.args\n            performative.args.extend(args)\n            kwargs = msg.kwargs\n            Kwargs.encode(performative.kwargs, kwargs)\n            ledger_api_msg.get_state.CopyFrom(performative)\n        elif performative_id == LedgerApiMessage.Performative.STATE:\n            performative = ledger_api_pb2.LedgerApiMessage.State_Performative()  # type: ignore\n            ledger_id = msg.ledger_id\n            performative.ledger_id = ledger_id\n            state = msg.state\n            State.encode(performative.state, state)\n            ledger_api_msg.state.CopyFrom(performative)\n        elif performative_id == LedgerApiMessage.Performative.ERROR:\n            performative = ledger_api_pb2.LedgerApiMessage.Error_Performative()  # type: ignore\n            code = msg.code\n            performative.code = code\n            if msg.is_set(\"message\"):\n                performative.message_is_set = True\n                message = msg.message\n                performative.message = message\n            if msg.is_set(\"data\"):\n                performative.data_is_set = True\n                data = msg.data\n                performative.data = data\n            ledger_api_msg.error.CopyFrom(performative)\n        else:\n            raise ValueError(\"Performative not valid: {}\".format(performative_id))\n\n        dialogue_message_pb.content = ledger_api_msg.SerializeToString()\n\n        message_pb.dialogue_message.CopyFrom(dialogue_message_pb)\n        message_bytes = message_pb.SerializeToString()\n        return message_bytes\n\n    @staticmethod\n    def decode(obj: bytes) -> Message:\n        \"\"\"\n        Decode bytes into a 'LedgerApi' message.\n\n        :param obj: the bytes object.\n        :return: the 'LedgerApi' message.\n        \"\"\"\n        message_pb = ProtobufMessage()\n        ledger_api_pb = ledger_api_pb2.LedgerApiMessage()\n        message_pb.ParseFromString(obj)\n        message_id = message_pb.dialogue_message.message_id\n        dialogue_reference = (\n            message_pb.dialogue_message.dialogue_starter_reference,\n            message_pb.dialogue_message.dialogue_responder_reference,\n        )\n        target = message_pb.dialogue_message.target\n\n        ledger_api_pb.ParseFromString(message_pb.dialogue_message.content)\n        performative = ledger_api_pb.WhichOneof(\"performative\")\n        performative_id = LedgerApiMessage.Performative(str(performative))\n        performative_content = {}  # type: Dict[str, Any]\n        if performative_id == LedgerApiMessage.Performative.GET_BALANCE:\n            ledger_id = ledger_api_pb.get_balance.ledger_id\n            performative_content[\"ledger_id\"] = ledger_id\n            address = ledger_api_pb.get_balance.address\n            performative_content[\"address\"] = address\n        elif performative_id == LedgerApiMessage.Performative.GET_RAW_TRANSACTION:\n            pb2_terms = ledger_api_pb.get_raw_transaction.terms\n            terms = Terms.decode(pb2_terms)\n            performative_content[\"terms\"] = terms\n        elif performative_id == LedgerApiMessage.Performative.SEND_SIGNED_TRANSACTION:\n            pb2_signed_transaction = (\n                ledger_api_pb.send_signed_transaction.signed_transaction\n            )\n            signed_transaction = SignedTransaction.decode(pb2_signed_transaction)\n            performative_content[\"signed_transaction\"] = signed_transaction\n        elif performative_id == LedgerApiMessage.Performative.GET_TRANSACTION_RECEIPT:\n            pb2_transaction_digest = (\n                ledger_api_pb.get_transaction_receipt.transaction_digest\n            )\n            transaction_digest = TransactionDigest.decode(pb2_transaction_digest)\n            performative_content[\"transaction_digest\"] = transaction_digest\n        elif performative_id == LedgerApiMessage.Performative.BALANCE:\n            ledger_id = ledger_api_pb.balance.ledger_id\n            performative_content[\"ledger_id\"] = ledger_id\n            balance = ledger_api_pb.balance.balance\n            performative_content[\"balance\"] = balance\n        elif performative_id == LedgerApiMessage.Performative.RAW_TRANSACTION:\n            pb2_raw_transaction = ledger_api_pb.raw_transaction.raw_transaction\n            raw_transaction = RawTransaction.decode(pb2_raw_transaction)\n            performative_content[\"raw_transaction\"] = raw_transaction\n        elif performative_id == LedgerApiMessage.Performative.TRANSACTION_DIGEST:\n            pb2_transaction_digest = ledger_api_pb.transaction_digest.transaction_digest\n            transaction_digest = TransactionDigest.decode(pb2_transaction_digest)\n            performative_content[\"transaction_digest\"] = transaction_digest\n        elif performative_id == LedgerApiMessage.Performative.TRANSACTION_RECEIPT:\n            pb2_transaction_receipt = (\n                ledger_api_pb.transaction_receipt.transaction_receipt\n            )\n            transaction_receipt = TransactionReceipt.decode(pb2_transaction_receipt)\n            performative_content[\"transaction_receipt\"] = transaction_receipt\n        elif performative_id == LedgerApiMessage.Performative.GET_STATE:\n            ledger_id = ledger_api_pb.get_state.ledger_id\n            performative_content[\"ledger_id\"] = ledger_id\n            callable = ledger_api_pb.get_state.callable\n            performative_content[\"callable\"] = callable\n            args = ledger_api_pb.get_state.args\n            args_tuple = tuple(args)\n            performative_content[\"args\"] = args_tuple\n            pb2_kwargs = ledger_api_pb.get_state.kwargs\n            kwargs = Kwargs.decode(pb2_kwargs)\n            performative_content[\"kwargs\"] = kwargs\n        elif performative_id == LedgerApiMessage.Performative.STATE:\n            ledger_id = ledger_api_pb.state.ledger_id\n            performative_content[\"ledger_id\"] = ledger_id\n            pb2_state = ledger_api_pb.state.state\n            state = State.decode(pb2_state)\n            performative_content[\"state\"] = state\n        elif performative_id == LedgerApiMessage.Performative.ERROR:\n            code = ledger_api_pb.error.code\n            performative_content[\"code\"] = code\n            if ledger_api_pb.error.message_is_set:\n                message = ledger_api_pb.error.message\n                performative_content[\"message\"] = message\n            if ledger_api_pb.error.data_is_set:\n                data = ledger_api_pb.error.data\n                performative_content[\"data\"] = data\n        else:\n            raise ValueError(\"Performative not valid: {}.\".format(performative_id))\n\n        return LedgerApiMessage(\n            message_id=message_id,\n            dialogue_reference=dialogue_reference,\n            target=target,\n            performative=performative,\n            **performative_content\n        )\n"
  },
  {
    "path": "packages/fetchai/protocols/ml_trade/README.md",
    "content": "# ML Trade Protocol\n\n## Description\n\nThis is a protocol for trading data for training and prediction purposes.\n\n## Specification\n\n```yaml\n---\nname: ml_trade\nauthor: fetchai\nversion: 1.1.7\ndescription: A protocol for trading data for training and prediction purposes.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nprotocol_specification_id: fetchai/ml_trade:1.0.0\nspeech_acts:\n  cfp:\n    query: ct:Query\n  terms:\n    terms: ct:Description\n  accept:\n    terms: ct:Description\n    tx_digest: pt:str\n  data:\n    terms: ct:Description\n    payload: pt:bytes\n...\n---\nct:Query: |\n  bytes query_bytes = 1;\nct:Description: |\n  bytes description_bytes = 1;\n...\n---\ninitiation: [cfp]\nreply:\n  cfp: [terms]\n  terms: [accept]\n  accept: [data]\n  data: []\ntermination: [data]\nroles: {seller, buyer}\nend_states: [successful]\nkeep_terminal_state_dialogues: true\n...\n```\n\n## Links\n"
  },
  {
    "path": "packages/fetchai/protocols/ml_trade/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nThis module contains the support resources for the ml_trade protocol.\n\nIt was created with protocol buffer compiler version `libprotoc 3.19.4` and aea version `1.2.5`.\n\"\"\"\n\nfrom packages.fetchai.protocols.ml_trade.message import MlTradeMessage\nfrom packages.fetchai.protocols.ml_trade.serialization import MlTradeSerializer\n\n\nMlTradeMessage.serializer = MlTradeSerializer\n"
  },
  {
    "path": "packages/fetchai/protocols/ml_trade/custom_types.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains class representations corresponding to every custom type in the protocol specification.\"\"\"\n\nfrom aea.helpers.search.models import Description as BaseDescription\nfrom aea.helpers.search.models import Query as BaseQuery\n\n\nDescription = BaseDescription\n\nQuery = BaseQuery\n"
  },
  {
    "path": "packages/fetchai/protocols/ml_trade/dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nThis module contains the classes required for ml_trade dialogue management.\n\n- MlTradeDialogue: The dialogue class maintains state of a dialogue and manages it.\n- MlTradeDialogues: The dialogues class keeps track of all dialogues.\n\"\"\"\n\nfrom abc import ABC\nfrom typing import Callable, Dict, FrozenSet, Type, cast\n\nfrom aea.common import Address\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue, DialogueLabel, Dialogues\n\nfrom packages.fetchai.protocols.ml_trade.message import MlTradeMessage\n\n\nclass MlTradeDialogue(Dialogue):\n    \"\"\"The ml_trade dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    INITIAL_PERFORMATIVES: FrozenSet[Message.Performative] = frozenset(\n        {MlTradeMessage.Performative.CFP}\n    )\n    TERMINAL_PERFORMATIVES: FrozenSet[Message.Performative] = frozenset(\n        {MlTradeMessage.Performative.DATA}\n    )\n    VALID_REPLIES: Dict[Message.Performative, FrozenSet[Message.Performative]] = {\n        MlTradeMessage.Performative.ACCEPT: frozenset(\n            {MlTradeMessage.Performative.DATA}\n        ),\n        MlTradeMessage.Performative.CFP: frozenset({MlTradeMessage.Performative.TERMS}),\n        MlTradeMessage.Performative.DATA: frozenset(),\n        MlTradeMessage.Performative.TERMS: frozenset(\n            {MlTradeMessage.Performative.ACCEPT}\n        ),\n    }\n\n    class Role(Dialogue.Role):\n        \"\"\"This class defines the agent's role in a ml_trade dialogue.\"\"\"\n\n        BUYER = \"buyer\"\n        SELLER = \"seller\"\n\n    class EndState(Dialogue.EndState):\n        \"\"\"This class defines the end states of a ml_trade dialogue.\"\"\"\n\n        SUCCESSFUL = 0\n\n    def __init__(\n        self,\n        dialogue_label: DialogueLabel,\n        self_address: Address,\n        role: Dialogue.Role,\n        message_class: Type[MlTradeMessage] = MlTradeMessage,\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n        :param message_class: the message class used\n        \"\"\"\n        Dialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            message_class=message_class,\n            self_address=self_address,\n            role=role,\n        )\n\n\nclass MlTradeDialogues(Dialogues, ABC):\n    \"\"\"This class keeps track of all ml_trade dialogues.\"\"\"\n\n    END_STATES = frozenset({MlTradeDialogue.EndState.SUCCESSFUL})\n\n    _keep_terminal_state_dialogues = True\n\n    def __init__(\n        self,\n        self_address: Address,\n        role_from_first_message: Callable[[Message, Address], Dialogue.Role],\n        dialogue_class: Type[MlTradeDialogue] = MlTradeDialogue,\n    ) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param self_address: the address of the entity for whom dialogues are maintained\n        :param dialogue_class: the dialogue class used\n        :param role_from_first_message: the callable determining role from first message\n        \"\"\"\n        Dialogues.__init__(\n            self,\n            self_address=self_address,\n            end_states=cast(FrozenSet[Dialogue.EndState], self.END_STATES),\n            message_class=MlTradeMessage,\n            dialogue_class=dialogue_class,\n            role_from_first_message=role_from_first_message,\n        )\n"
  },
  {
    "path": "packages/fetchai/protocols/ml_trade/message.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains ml_trade's message definition.\"\"\"\n\n# pylint: disable=too-many-statements,too-many-locals,no-member,too-few-public-methods,too-many-branches,not-an-iterable,unidiomatic-typecheck,unsubscriptable-object\nimport logging\nfrom typing import Any, Set, Tuple, cast\n\nfrom aea.configurations.base import PublicId\nfrom aea.exceptions import AEAEnforceError, enforce\nfrom aea.protocols.base import Message\n\nfrom packages.fetchai.protocols.ml_trade.custom_types import (\n    Description as CustomDescription,\n)\nfrom packages.fetchai.protocols.ml_trade.custom_types import Query as CustomQuery\n\n\n_default_logger = logging.getLogger(\"aea.packages.fetchai.protocols.ml_trade.message\")\n\nDEFAULT_BODY_SIZE = 4\n\n\nclass MlTradeMessage(Message):\n    \"\"\"A protocol for trading data for training and prediction purposes.\"\"\"\n\n    protocol_id = PublicId.from_str(\"fetchai/ml_trade:1.1.7\")\n    protocol_specification_id = PublicId.from_str(\"fetchai/ml_trade:1.0.0\")\n\n    Description = CustomDescription\n\n    Query = CustomQuery\n\n    class Performative(Message.Performative):\n        \"\"\"Performatives for the ml_trade protocol.\"\"\"\n\n        ACCEPT = \"accept\"\n        CFP = \"cfp\"\n        DATA = \"data\"\n        TERMS = \"terms\"\n\n        def __str__(self) -> str:\n            \"\"\"Get the string representation.\"\"\"\n            return str(self.value)\n\n    _performatives = {\"accept\", \"cfp\", \"data\", \"terms\"}\n    __slots__: Tuple[str, ...] = tuple()\n\n    class _SlotsCls:\n        __slots__ = (\n            \"dialogue_reference\",\n            \"message_id\",\n            \"payload\",\n            \"performative\",\n            \"query\",\n            \"target\",\n            \"terms\",\n            \"tx_digest\",\n        )\n\n    def __init__(\n        self,\n        performative: Performative,\n        dialogue_reference: Tuple[str, str] = (\"\", \"\"),\n        message_id: int = 1,\n        target: int = 0,\n        **kwargs: Any,\n    ):\n        \"\"\"\n        Initialise an instance of MlTradeMessage.\n\n        :param message_id: the message id.\n        :param dialogue_reference: the dialogue reference.\n        :param target: the message target.\n        :param performative: the message performative.\n        :param **kwargs: extra options.\n        \"\"\"\n        super().__init__(\n            dialogue_reference=dialogue_reference,\n            message_id=message_id,\n            target=target,\n            performative=MlTradeMessage.Performative(performative),\n            **kwargs,\n        )\n\n    @property\n    def valid_performatives(self) -> Set[str]:\n        \"\"\"Get valid performatives.\"\"\"\n        return self._performatives\n\n    @property\n    def dialogue_reference(self) -> Tuple[str, str]:\n        \"\"\"Get the dialogue_reference of the message.\"\"\"\n        enforce(self.is_set(\"dialogue_reference\"), \"dialogue_reference is not set.\")\n        return cast(Tuple[str, str], self.get(\"dialogue_reference\"))\n\n    @property\n    def message_id(self) -> int:\n        \"\"\"Get the message_id of the message.\"\"\"\n        enforce(self.is_set(\"message_id\"), \"message_id is not set.\")\n        return cast(int, self.get(\"message_id\"))\n\n    @property\n    def performative(self) -> Performative:  # type: ignore # noqa: F821\n        \"\"\"Get the performative of the message.\"\"\"\n        enforce(self.is_set(\"performative\"), \"performative is not set.\")\n        return cast(MlTradeMessage.Performative, self.get(\"performative\"))\n\n    @property\n    def target(self) -> int:\n        \"\"\"Get the target of the message.\"\"\"\n        enforce(self.is_set(\"target\"), \"target is not set.\")\n        return cast(int, self.get(\"target\"))\n\n    @property\n    def payload(self) -> bytes:\n        \"\"\"Get the 'payload' content from the message.\"\"\"\n        enforce(self.is_set(\"payload\"), \"'payload' content is not set.\")\n        return cast(bytes, self.get(\"payload\"))\n\n    @property\n    def query(self) -> CustomQuery:\n        \"\"\"Get the 'query' content from the message.\"\"\"\n        enforce(self.is_set(\"query\"), \"'query' content is not set.\")\n        return cast(CustomQuery, self.get(\"query\"))\n\n    @property\n    def terms(self) -> CustomDescription:\n        \"\"\"Get the 'terms' content from the message.\"\"\"\n        enforce(self.is_set(\"terms\"), \"'terms' content is not set.\")\n        return cast(CustomDescription, self.get(\"terms\"))\n\n    @property\n    def tx_digest(self) -> str:\n        \"\"\"Get the 'tx_digest' content from the message.\"\"\"\n        enforce(self.is_set(\"tx_digest\"), \"'tx_digest' content is not set.\")\n        return cast(str, self.get(\"tx_digest\"))\n\n    def _is_consistent(self) -> bool:\n        \"\"\"Check that the message follows the ml_trade protocol.\"\"\"\n        try:\n            enforce(\n                isinstance(self.dialogue_reference, tuple),\n                \"Invalid type for 'dialogue_reference'. Expected 'tuple'. Found '{}'.\".format(\n                    type(self.dialogue_reference)\n                ),\n            )\n            enforce(\n                isinstance(self.dialogue_reference[0], str),\n                \"Invalid type for 'dialogue_reference[0]'. Expected 'str'. Found '{}'.\".format(\n                    type(self.dialogue_reference[0])\n                ),\n            )\n            enforce(\n                isinstance(self.dialogue_reference[1], str),\n                \"Invalid type for 'dialogue_reference[1]'. Expected 'str'. Found '{}'.\".format(\n                    type(self.dialogue_reference[1])\n                ),\n            )\n            enforce(\n                type(self.message_id) is int,\n                \"Invalid type for 'message_id'. Expected 'int'. Found '{}'.\".format(\n                    type(self.message_id)\n                ),\n            )\n            enforce(\n                type(self.target) is int,\n                \"Invalid type for 'target'. Expected 'int'. Found '{}'.\".format(\n                    type(self.target)\n                ),\n            )\n\n            # Light Protocol Rule 2\n            # Check correct performative\n            enforce(\n                isinstance(self.performative, MlTradeMessage.Performative),\n                \"Invalid 'performative'. Expected either of '{}'. Found '{}'.\".format(\n                    self.valid_performatives, self.performative\n                ),\n            )\n\n            # Check correct contents\n            actual_nb_of_contents = len(self._body) - DEFAULT_BODY_SIZE\n            expected_nb_of_contents = 0\n            if self.performative == MlTradeMessage.Performative.CFP:\n                expected_nb_of_contents = 1\n                enforce(\n                    isinstance(self.query, CustomQuery),\n                    \"Invalid type for content 'query'. Expected 'Query'. Found '{}'.\".format(\n                        type(self.query)\n                    ),\n                )\n            elif self.performative == MlTradeMessage.Performative.TERMS:\n                expected_nb_of_contents = 1\n                enforce(\n                    isinstance(self.terms, CustomDescription),\n                    \"Invalid type for content 'terms'. Expected 'Description'. Found '{}'.\".format(\n                        type(self.terms)\n                    ),\n                )\n            elif self.performative == MlTradeMessage.Performative.ACCEPT:\n                expected_nb_of_contents = 2\n                enforce(\n                    isinstance(self.terms, CustomDescription),\n                    \"Invalid type for content 'terms'. Expected 'Description'. Found '{}'.\".format(\n                        type(self.terms)\n                    ),\n                )\n                enforce(\n                    isinstance(self.tx_digest, str),\n                    \"Invalid type for content 'tx_digest'. Expected 'str'. Found '{}'.\".format(\n                        type(self.tx_digest)\n                    ),\n                )\n            elif self.performative == MlTradeMessage.Performative.DATA:\n                expected_nb_of_contents = 2\n                enforce(\n                    isinstance(self.terms, CustomDescription),\n                    \"Invalid type for content 'terms'. Expected 'Description'. Found '{}'.\".format(\n                        type(self.terms)\n                    ),\n                )\n                enforce(\n                    isinstance(self.payload, bytes),\n                    \"Invalid type for content 'payload'. Expected 'bytes'. Found '{}'.\".format(\n                        type(self.payload)\n                    ),\n                )\n\n            # Check correct content count\n            enforce(\n                expected_nb_of_contents == actual_nb_of_contents,\n                \"Incorrect number of contents. Expected {}. Found {}\".format(\n                    expected_nb_of_contents, actual_nb_of_contents\n                ),\n            )\n\n            # Light Protocol Rule 3\n            if self.message_id == 1:\n                enforce(\n                    self.target == 0,\n                    \"Invalid 'target'. Expected 0 (because 'message_id' is 1). Found {}.\".format(\n                        self.target\n                    ),\n                )\n        except (AEAEnforceError, ValueError, KeyError) as e:\n            _default_logger.error(str(e))\n            return False\n\n        return True\n"
  },
  {
    "path": "packages/fetchai/protocols/ml_trade/ml_trade.proto",
    "content": "syntax = \"proto3\";\n\npackage aea.fetchai.ml_trade.v1_0_0;\n\nmessage MlTradeMessage{\n\n  // Custom Types\n  message Description{\n    bytes description_bytes = 1;\n  }\n\n  message Query{\n    bytes query_bytes = 1;\n  }\n\n\n  // Performatives and contents\n  message Cfp_Performative{\n    Query query = 1;\n  }\n\n  message Terms_Performative{\n    Description terms = 1;\n  }\n\n  message Accept_Performative{\n    Description terms = 1;\n    string tx_digest = 2;\n  }\n\n  message Data_Performative{\n    Description terms = 1;\n    bytes payload = 2;\n  }\n\n\n  oneof performative{\n    Accept_Performative accept = 5;\n    Cfp_Performative cfp = 6;\n    Data_Performative data = 7;\n    Terms_Performative terms = 8;\n  }\n}\n"
  },
  {
    "path": "packages/fetchai/protocols/ml_trade/ml_trade_pb2.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by the protocol buffer compiler.  DO NOT EDIT!\n# source: ml_trade.proto\n\"\"\"Generated protocol buffer code.\"\"\"\nfrom google.protobuf import descriptor as _descriptor\nfrom google.protobuf import descriptor_pool as _descriptor_pool\nfrom google.protobuf import message as _message\nfrom google.protobuf import reflection as _reflection\nfrom google.protobuf import symbol_database as _symbol_database\n\n# @@protoc_insertion_point(imports)\n\n_sym_db = _symbol_database.Default()\n\n\nDESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(\n    b'\\n\\x0eml_trade.proto\\x12\\x1b\\x61\\x65\\x61.fetchai.ml_trade.v1_0_0\"\\xbc\\x06\\n\\x0eMlTradeMessage\\x12Q\\n\\x06\\x61\\x63\\x63\\x65pt\\x18\\x05 \\x01(\\x0b\\x32?.aea.fetchai.ml_trade.v1_0_0.MlTradeMessage.Accept_PerformativeH\\x00\\x12K\\n\\x03\\x63\\x66p\\x18\\x06 \\x01(\\x0b\\x32<.aea.fetchai.ml_trade.v1_0_0.MlTradeMessage.Cfp_PerformativeH\\x00\\x12M\\n\\x04\\x64\\x61ta\\x18\\x07 \\x01(\\x0b\\x32=.aea.fetchai.ml_trade.v1_0_0.MlTradeMessage.Data_PerformativeH\\x00\\x12O\\n\\x05terms\\x18\\x08 \\x01(\\x0b\\x32>.aea.fetchai.ml_trade.v1_0_0.MlTradeMessage.Terms_PerformativeH\\x00\\x1a(\\n\\x0b\\x44\\x65scription\\x12\\x19\\n\\x11\\x64\\x65scription_bytes\\x18\\x01 \\x01(\\x0c\\x1a\\x1c\\n\\x05Query\\x12\\x13\\n\\x0bquery_bytes\\x18\\x01 \\x01(\\x0c\\x1aT\\n\\x10\\x43\\x66p_Performative\\x12@\\n\\x05query\\x18\\x01 \\x01(\\x0b\\x32\\x31.aea.fetchai.ml_trade.v1_0_0.MlTradeMessage.Query\\x1a\\\\\\n\\x12Terms_Performative\\x12\\x46\\n\\x05terms\\x18\\x01 \\x01(\\x0b\\x32\\x37.aea.fetchai.ml_trade.v1_0_0.MlTradeMessage.Description\\x1ap\\n\\x13\\x41\\x63\\x63\\x65pt_Performative\\x12\\x46\\n\\x05terms\\x18\\x01 \\x01(\\x0b\\x32\\x37.aea.fetchai.ml_trade.v1_0_0.MlTradeMessage.Description\\x12\\x11\\n\\ttx_digest\\x18\\x02 \\x01(\\t\\x1al\\n\\x11\\x44\\x61ta_Performative\\x12\\x46\\n\\x05terms\\x18\\x01 \\x01(\\x0b\\x32\\x37.aea.fetchai.ml_trade.v1_0_0.MlTradeMessage.Description\\x12\\x0f\\n\\x07payload\\x18\\x02 \\x01(\\x0c\\x42\\x0e\\n\\x0cperformativeb\\x06proto3'\n)\n\n\n_MLTRADEMESSAGE = DESCRIPTOR.message_types_by_name[\"MlTradeMessage\"]\n_MLTRADEMESSAGE_DESCRIPTION = _MLTRADEMESSAGE.nested_types_by_name[\"Description\"]\n_MLTRADEMESSAGE_QUERY = _MLTRADEMESSAGE.nested_types_by_name[\"Query\"]\n_MLTRADEMESSAGE_CFP_PERFORMATIVE = _MLTRADEMESSAGE.nested_types_by_name[\n    \"Cfp_Performative\"\n]\n_MLTRADEMESSAGE_TERMS_PERFORMATIVE = _MLTRADEMESSAGE.nested_types_by_name[\n    \"Terms_Performative\"\n]\n_MLTRADEMESSAGE_ACCEPT_PERFORMATIVE = _MLTRADEMESSAGE.nested_types_by_name[\n    \"Accept_Performative\"\n]\n_MLTRADEMESSAGE_DATA_PERFORMATIVE = _MLTRADEMESSAGE.nested_types_by_name[\n    \"Data_Performative\"\n]\nMlTradeMessage = _reflection.GeneratedProtocolMessageType(\n    \"MlTradeMessage\",\n    (_message.Message,),\n    {\n        \"Description\": _reflection.GeneratedProtocolMessageType(\n            \"Description\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _MLTRADEMESSAGE_DESCRIPTION,\n                \"__module__\": \"ml_trade_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.ml_trade.v1_0_0.MlTradeMessage.Description)\n            },\n        ),\n        \"Query\": _reflection.GeneratedProtocolMessageType(\n            \"Query\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _MLTRADEMESSAGE_QUERY,\n                \"__module__\": \"ml_trade_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.ml_trade.v1_0_0.MlTradeMessage.Query)\n            },\n        ),\n        \"Cfp_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Cfp_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _MLTRADEMESSAGE_CFP_PERFORMATIVE,\n                \"__module__\": \"ml_trade_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.ml_trade.v1_0_0.MlTradeMessage.Cfp_Performative)\n            },\n        ),\n        \"Terms_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Terms_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _MLTRADEMESSAGE_TERMS_PERFORMATIVE,\n                \"__module__\": \"ml_trade_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.ml_trade.v1_0_0.MlTradeMessage.Terms_Performative)\n            },\n        ),\n        \"Accept_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Accept_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _MLTRADEMESSAGE_ACCEPT_PERFORMATIVE,\n                \"__module__\": \"ml_trade_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.ml_trade.v1_0_0.MlTradeMessage.Accept_Performative)\n            },\n        ),\n        \"Data_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Data_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _MLTRADEMESSAGE_DATA_PERFORMATIVE,\n                \"__module__\": \"ml_trade_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.ml_trade.v1_0_0.MlTradeMessage.Data_Performative)\n            },\n        ),\n        \"DESCRIPTOR\": _MLTRADEMESSAGE,\n        \"__module__\": \"ml_trade_pb2\"\n        # @@protoc_insertion_point(class_scope:aea.fetchai.ml_trade.v1_0_0.MlTradeMessage)\n    },\n)\n_sym_db.RegisterMessage(MlTradeMessage)\n_sym_db.RegisterMessage(MlTradeMessage.Description)\n_sym_db.RegisterMessage(MlTradeMessage.Query)\n_sym_db.RegisterMessage(MlTradeMessage.Cfp_Performative)\n_sym_db.RegisterMessage(MlTradeMessage.Terms_Performative)\n_sym_db.RegisterMessage(MlTradeMessage.Accept_Performative)\n_sym_db.RegisterMessage(MlTradeMessage.Data_Performative)\n\nif _descriptor._USE_C_DESCRIPTORS == False:\n\n    DESCRIPTOR._options = None\n    _MLTRADEMESSAGE._serialized_start = 48\n    _MLTRADEMESSAGE._serialized_end = 876\n    _MLTRADEMESSAGE_DESCRIPTION._serialized_start = 386\n    _MLTRADEMESSAGE_DESCRIPTION._serialized_end = 426\n    _MLTRADEMESSAGE_QUERY._serialized_start = 428\n    _MLTRADEMESSAGE_QUERY._serialized_end = 456\n    _MLTRADEMESSAGE_CFP_PERFORMATIVE._serialized_start = 458\n    _MLTRADEMESSAGE_CFP_PERFORMATIVE._serialized_end = 542\n    _MLTRADEMESSAGE_TERMS_PERFORMATIVE._serialized_start = 544\n    _MLTRADEMESSAGE_TERMS_PERFORMATIVE._serialized_end = 636\n    _MLTRADEMESSAGE_ACCEPT_PERFORMATIVE._serialized_start = 638\n    _MLTRADEMESSAGE_ACCEPT_PERFORMATIVE._serialized_end = 750\n    _MLTRADEMESSAGE_DATA_PERFORMATIVE._serialized_start = 752\n    _MLTRADEMESSAGE_DATA_PERFORMATIVE._serialized_end = 860\n# @@protoc_insertion_point(module_scope)\n"
  },
  {
    "path": "packages/fetchai/protocols/ml_trade/protocol.yaml",
    "content": "name: ml_trade\nauthor: fetchai\nversion: 1.1.7\nprotocol_specification_id: fetchai/ml_trade:1.0.0\ntype: protocol\ndescription: A protocol for trading data for training and prediction purposes.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: QmTDDRfEdNV55C5Z34PLoUqn5LKd8p1p96GbrWa5G2S65J\n  __init__.py: QmSE8icQPrhs32YjKAxzz7BZjFaLWEKsZpouXshP516GzA\n  custom_types.py: QmPnyZAfuH2myvv47BaN7hsRDo7E4rmjvzDYWoMCwXwkg8\n  dialogues.py: Qmc63JhVebdh1Y4QxLjDxxLf4eYtaj62pLw9eVqULqFM64\n  message.py: Qmd9923RVn5ABHb9MytPVqPvqC9GKwTp6cfm58EnqYaFUr\n  ml_trade.proto: QmbW2f4qNJJeY8YVgrawHjroqYcTviY5BevCBYVUMVVoH9\n  ml_trade_pb2.py: QmTF6TseznjZxVoJH99vxW9GDz4LrSFhqBwNsfF6s8cv9H\n  serialization.py: QmTAULUySkgNgvXeCmC21gE7AU2a3V8dD4jAbDqAWokcMC\nfingerprint_ignore_patterns: []\ndependencies:\n  protobuf: {}\n"
  },
  {
    "path": "packages/fetchai/protocols/ml_trade/serialization.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Serialization module for ml_trade protocol.\"\"\"\n\n# pylint: disable=too-many-statements,too-many-locals,no-member,too-few-public-methods,redefined-builtin\nfrom typing import Any, Dict, cast\n\nfrom aea.mail.base_pb2 import DialogueMessage\nfrom aea.mail.base_pb2 import Message as ProtobufMessage\nfrom aea.protocols.base import Message, Serializer\n\nfrom packages.fetchai.protocols.ml_trade import ml_trade_pb2\nfrom packages.fetchai.protocols.ml_trade.custom_types import Description, Query\nfrom packages.fetchai.protocols.ml_trade.message import MlTradeMessage\n\n\nclass MlTradeSerializer(Serializer):\n    \"\"\"Serialization for the 'ml_trade' protocol.\"\"\"\n\n    @staticmethod\n    def encode(msg: Message) -> bytes:\n        \"\"\"\n        Encode a 'MlTrade' message into bytes.\n\n        :param msg: the message object.\n        :return: the bytes.\n        \"\"\"\n        msg = cast(MlTradeMessage, msg)\n        message_pb = ProtobufMessage()\n        dialogue_message_pb = DialogueMessage()\n        ml_trade_msg = ml_trade_pb2.MlTradeMessage()\n\n        dialogue_message_pb.message_id = msg.message_id\n        dialogue_reference = msg.dialogue_reference\n        dialogue_message_pb.dialogue_starter_reference = dialogue_reference[0]\n        dialogue_message_pb.dialogue_responder_reference = dialogue_reference[1]\n        dialogue_message_pb.target = msg.target\n\n        performative_id = msg.performative\n        if performative_id == MlTradeMessage.Performative.CFP:\n            performative = ml_trade_pb2.MlTradeMessage.Cfp_Performative()  # type: ignore\n            query = msg.query\n            Query.encode(performative.query, query)\n            ml_trade_msg.cfp.CopyFrom(performative)\n        elif performative_id == MlTradeMessage.Performative.TERMS:\n            performative = ml_trade_pb2.MlTradeMessage.Terms_Performative()  # type: ignore\n            terms = msg.terms\n            Description.encode(performative.terms, terms)\n            ml_trade_msg.terms.CopyFrom(performative)\n        elif performative_id == MlTradeMessage.Performative.ACCEPT:\n            performative = ml_trade_pb2.MlTradeMessage.Accept_Performative()  # type: ignore\n            terms = msg.terms\n            Description.encode(performative.terms, terms)\n            tx_digest = msg.tx_digest\n            performative.tx_digest = tx_digest\n            ml_trade_msg.accept.CopyFrom(performative)\n        elif performative_id == MlTradeMessage.Performative.DATA:\n            performative = ml_trade_pb2.MlTradeMessage.Data_Performative()  # type: ignore\n            terms = msg.terms\n            Description.encode(performative.terms, terms)\n            payload = msg.payload\n            performative.payload = payload\n            ml_trade_msg.data.CopyFrom(performative)\n        else:\n            raise ValueError(\"Performative not valid: {}\".format(performative_id))\n\n        dialogue_message_pb.content = ml_trade_msg.SerializeToString()\n\n        message_pb.dialogue_message.CopyFrom(dialogue_message_pb)\n        message_bytes = message_pb.SerializeToString()\n        return message_bytes\n\n    @staticmethod\n    def decode(obj: bytes) -> Message:\n        \"\"\"\n        Decode bytes into a 'MlTrade' message.\n\n        :param obj: the bytes object.\n        :return: the 'MlTrade' message.\n        \"\"\"\n        message_pb = ProtobufMessage()\n        ml_trade_pb = ml_trade_pb2.MlTradeMessage()\n        message_pb.ParseFromString(obj)\n        message_id = message_pb.dialogue_message.message_id\n        dialogue_reference = (\n            message_pb.dialogue_message.dialogue_starter_reference,\n            message_pb.dialogue_message.dialogue_responder_reference,\n        )\n        target = message_pb.dialogue_message.target\n\n        ml_trade_pb.ParseFromString(message_pb.dialogue_message.content)\n        performative = ml_trade_pb.WhichOneof(\"performative\")\n        performative_id = MlTradeMessage.Performative(str(performative))\n        performative_content = {}  # type: Dict[str, Any]\n        if performative_id == MlTradeMessage.Performative.CFP:\n            pb2_query = ml_trade_pb.cfp.query\n            query = Query.decode(pb2_query)\n            performative_content[\"query\"] = query\n        elif performative_id == MlTradeMessage.Performative.TERMS:\n            pb2_terms = ml_trade_pb.terms.terms\n            terms = Description.decode(pb2_terms)\n            performative_content[\"terms\"] = terms\n        elif performative_id == MlTradeMessage.Performative.ACCEPT:\n            pb2_terms = ml_trade_pb.accept.terms\n            terms = Description.decode(pb2_terms)\n            performative_content[\"terms\"] = terms\n            tx_digest = ml_trade_pb.accept.tx_digest\n            performative_content[\"tx_digest\"] = tx_digest\n        elif performative_id == MlTradeMessage.Performative.DATA:\n            pb2_terms = ml_trade_pb.data.terms\n            terms = Description.decode(pb2_terms)\n            performative_content[\"terms\"] = terms\n            payload = ml_trade_pb.data.payload\n            performative_content[\"payload\"] = payload\n        else:\n            raise ValueError(\"Performative not valid: {}.\".format(performative_id))\n\n        return MlTradeMessage(\n            message_id=message_id,\n            dialogue_reference=dialogue_reference,\n            target=target,\n            performative=performative,\n            **performative_content\n        )\n"
  },
  {
    "path": "packages/fetchai/protocols/oef_search/README.md",
    "content": "# OEF Search Protocol\n\n## Description\n\nThis is a protocol for interacting with an OEF search service.\nIt allows for registering of agents and services, and searching of agents and services using a query language.\n\n## Specification\n\n```yaml\n---\nname: oef_search\nauthor: fetchai\nversion: 1.1.7\ndescription: A protocol for interacting with an OEF search service.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nprotocol_specification_id: fetchai/oef_search:1.0.0\nspeech_acts:\n  register_service:\n    service_description: ct:Description\n  unregister_service:\n    service_description: ct:Description\n  search_services:\n    query: ct:Query\n  search_result:\n    agents: pt:list[pt:str]\n    agents_info: ct:AgentsInfo\n  success:\n    agents_info: ct:AgentsInfo\n  oef_error:\n    oef_error_operation: ct:OefErrorOperation\n...\n---\nct:Query: |\n  bytes query_bytes = 1;\nct:Description: |\n  bytes description_bytes = 1;\nct:AgentsInfo: |\n  bytes agents_info = 1;\nct:OefErrorOperation: |\n  enum OefErrorEnum {\n        REGISTER_SERVICE = 0;\n        UNREGISTER_SERVICE = 1;\n        SEARCH_SERVICES = 2;\n        SEND_MESSAGE = 3;\n      }\n  OefErrorEnum oef_error = 1;\n...\n---\ninitiation: [register_service, unregister_service, search_services]\nreply:\n  register_service: [success, oef_error]\n  unregister_service: [success, oef_error]\n  search_services: [search_result, oef_error]\n  search_result: []\n  oef_error: []\n  success: []\ntermination: [oef_error, search_result, success]\nroles: {agent, oef_node}\nend_states: [successful, failed]\nkeep_terminal_state_dialogues: false\n...\n```\n\n## Links\n"
  },
  {
    "path": "packages/fetchai/protocols/oef_search/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nThis module contains the support resources for the oef_search protocol.\n\nIt was created with protocol buffer compiler version `libprotoc 3.19.4` and aea version `1.2.5`.\n\"\"\"\n\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.protocols.oef_search.serialization import OefSearchSerializer\n\n\nOefSearchMessage.serializer = OefSearchSerializer\n"
  },
  {
    "path": "packages/fetchai/protocols/oef_search/custom_types.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains class representations corresponding to every custom type in the protocol specification.\"\"\"\n\nfrom enum import Enum\nfrom typing import Any, Dict\n\nfrom aea.exceptions import enforce\nfrom aea.helpers.search.models import Description as BaseDescription\nfrom aea.helpers.search.models import Query as BaseQuery\nfrom aea.helpers.serializers import DictProtobufStructSerializer\n\n\nDescription = BaseDescription\n\n\nclass AgentsInfo:\n    \"\"\"This class represents an instance of AgentsInfo.\"\"\"\n\n    __slots__ = (\"_body\",)\n\n    def __init__(self, body: Dict[str, Dict[str, Any]]):\n        \"\"\"Initialise an instance of AgentsInfo.\"\"\"\n        self._body = body\n        self._check_consistency()\n\n    def _check_consistency(self) -> None:\n        \"\"\"Check consistency of the object.\"\"\"\n        if self._body is None:\n            raise ValueError(\"body must not be None\")\n        enforce(\n            isinstance(self._body, dict)\n            and all(isinstance(key, str) for key in self._body.keys())\n            and all(isinstance(value, dict) for value in self._body.values()),\n            \"Body must be dict and keys must be str and values must be dict.\",\n        )\n\n    @property\n    def body(self) -> Dict[str, Dict[str, Any]]:\n        \"\"\"Get the body.\"\"\"\n        return self._body\n\n    def get_info_for_agent(self, agent_address: str) -> Dict[str, Any]:\n        \"\"\"Get the info for the agent address.\"\"\"\n        return self._body.get(agent_address, {})\n\n    @staticmethod\n    def encode(\n        agents_info_protobuf_object: Any, agents_info_object: \"AgentsInfo\"\n    ) -> None:\n        \"\"\"\n        Encode an instance of this class into the protocol buffer object.\n\n        The protocol buffer object in the agents_info_protobuf_object argument is matched with the instance of this class in the 'agents_info_object' argument.\n\n        :param agents_info_protobuf_object: the protocol buffer object whose type corresponds with this class.\n        :param agents_info_object: an instance of this class to be encoded in the protocol buffer object.\n        \"\"\"\n        agents_info_protobuf_object.agents_info = DictProtobufStructSerializer.encode(\n            agents_info_object.body\n        )\n\n    @classmethod\n    def decode(cls, agents_info_protobuf_object: Any) -> \"AgentsInfo\":\n        \"\"\"\n        Decode a protocol buffer object that corresponds with this class into an instance of this class.\n\n        A new instance of this class is created that matches the protocol buffer object in the 'agents_info_protobuf_object' argument.\n\n        :param agents_info_protobuf_object: the protocol buffer object whose type corresponds with this class.\n        :return: A new instance of this class that matches the protocol buffer object in the 'agents_info_protobuf_object' argument.\n        \"\"\"\n        body = DictProtobufStructSerializer.decode(\n            agents_info_protobuf_object.agents_info\n        )\n        return cls(body)\n\n    def __eq__(self, other: Any) -> bool:\n        \"\"\"Compare with another object.\"\"\"\n        if not isinstance(other, AgentsInfo):\n            return False  # pragma: nocover\n        return self.body == other.body\n\n\nclass OefErrorOperation(Enum):\n    \"\"\"This class represents an instance of OefErrorOperation.\"\"\"\n\n    REGISTER_SERVICE = 0\n    UNREGISTER_SERVICE = 1\n    SEARCH_SERVICES = 2\n    SEND_MESSAGE = 3\n\n    OTHER = 10000\n\n    def __str__(self) -> str:\n        \"\"\"Get string representation.\"\"\"\n        return str(self.value)\n\n    @staticmethod\n    def encode(\n        oef_error_operation_protobuf_object: Any,\n        oef_error_operation_object: \"OefErrorOperation\",\n    ) -> None:\n        \"\"\"\n        Encode an instance of this class into the protocol buffer object.\n\n        The protocol buffer object in the oef_error_operation_protobuf_object argument is matched with the instance of this class in the 'oef_error_operation_object'\n        argument.\n\n        :param oef_error_operation_protobuf_object: the protocol buffer object whose type corresponds with this class.\n        :param oef_error_operation_object: an instance of this class to be encoded in the protocol buffer object.\n        \"\"\"\n        oef_error_operation_protobuf_object.oef_error = oef_error_operation_object.value\n\n    @classmethod\n    def decode(cls, oef_error_operation_protobuf_object: Any) -> \"OefErrorOperation\":\n        \"\"\"\n        Decode a protocol buffer object that corresponds with this class into an instance of this class.\n\n        A new instance of this class is created that matches the protocol buffer object in the 'oef_error_operation_protobuf_object' argument.\n\n        :param oef_error_operation_protobuf_object: the protocol buffer object whose type corresponds with this class.\n        :return: A new instance of this class that matches the protocol buffer object in the 'oef_error_operation_protobuf_object' argument.\n        \"\"\"\n        enum_value_from_pb2 = oef_error_operation_protobuf_object.oef_error\n        return OefErrorOperation(enum_value_from_pb2)\n\n\nQuery = BaseQuery\n"
  },
  {
    "path": "packages/fetchai/protocols/oef_search/dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nThis module contains the classes required for oef_search dialogue management.\n\n- OefSearchDialogue: The dialogue class maintains state of a dialogue and manages it.\n- OefSearchDialogues: The dialogues class keeps track of all dialogues.\n\"\"\"\n\nfrom abc import ABC\nfrom typing import Callable, Dict, FrozenSet, Type, cast\n\nfrom aea.common import Address\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue, DialogueLabel, Dialogues\n\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\n\n\nclass OefSearchDialogue(Dialogue):\n    \"\"\"The oef_search dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    INITIAL_PERFORMATIVES: FrozenSet[Message.Performative] = frozenset(\n        {\n            OefSearchMessage.Performative.REGISTER_SERVICE,\n            OefSearchMessage.Performative.UNREGISTER_SERVICE,\n            OefSearchMessage.Performative.SEARCH_SERVICES,\n        }\n    )\n    TERMINAL_PERFORMATIVES: FrozenSet[Message.Performative] = frozenset(\n        {\n            OefSearchMessage.Performative.OEF_ERROR,\n            OefSearchMessage.Performative.SEARCH_RESULT,\n            OefSearchMessage.Performative.SUCCESS,\n        }\n    )\n    VALID_REPLIES: Dict[Message.Performative, FrozenSet[Message.Performative]] = {\n        OefSearchMessage.Performative.OEF_ERROR: frozenset(),\n        OefSearchMessage.Performative.REGISTER_SERVICE: frozenset(\n            {\n                OefSearchMessage.Performative.SUCCESS,\n                OefSearchMessage.Performative.OEF_ERROR,\n            }\n        ),\n        OefSearchMessage.Performative.SEARCH_RESULT: frozenset(),\n        OefSearchMessage.Performative.SEARCH_SERVICES: frozenset(\n            {\n                OefSearchMessage.Performative.SEARCH_RESULT,\n                OefSearchMessage.Performative.OEF_ERROR,\n            }\n        ),\n        OefSearchMessage.Performative.SUCCESS: frozenset(),\n        OefSearchMessage.Performative.UNREGISTER_SERVICE: frozenset(\n            {\n                OefSearchMessage.Performative.SUCCESS,\n                OefSearchMessage.Performative.OEF_ERROR,\n            }\n        ),\n    }\n\n    class Role(Dialogue.Role):\n        \"\"\"This class defines the agent's role in a oef_search dialogue.\"\"\"\n\n        AGENT = \"agent\"\n        OEF_NODE = \"oef_node\"\n\n    class EndState(Dialogue.EndState):\n        \"\"\"This class defines the end states of a oef_search dialogue.\"\"\"\n\n        SUCCESSFUL = 0\n        FAILED = 1\n\n    def __init__(\n        self,\n        dialogue_label: DialogueLabel,\n        self_address: Address,\n        role: Dialogue.Role,\n        message_class: Type[OefSearchMessage] = OefSearchMessage,\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n        :param message_class: the message class used\n        \"\"\"\n        Dialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            message_class=message_class,\n            self_address=self_address,\n            role=role,\n        )\n\n\nclass OefSearchDialogues(Dialogues, ABC):\n    \"\"\"This class keeps track of all oef_search dialogues.\"\"\"\n\n    END_STATES = frozenset(\n        {OefSearchDialogue.EndState.SUCCESSFUL, OefSearchDialogue.EndState.FAILED}\n    )\n\n    _keep_terminal_state_dialogues = False\n\n    def __init__(\n        self,\n        self_address: Address,\n        role_from_first_message: Callable[[Message, Address], Dialogue.Role],\n        dialogue_class: Type[OefSearchDialogue] = OefSearchDialogue,\n    ) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param self_address: the address of the entity for whom dialogues are maintained\n        :param dialogue_class: the dialogue class used\n        :param role_from_first_message: the callable determining role from first message\n        \"\"\"\n        Dialogues.__init__(\n            self,\n            self_address=self_address,\n            end_states=cast(FrozenSet[Dialogue.EndState], self.END_STATES),\n            message_class=OefSearchMessage,\n            dialogue_class=dialogue_class,\n            role_from_first_message=role_from_first_message,\n        )\n"
  },
  {
    "path": "packages/fetchai/protocols/oef_search/message.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains oef_search's message definition.\"\"\"\n\n# pylint: disable=too-many-statements,too-many-locals,no-member,too-few-public-methods,too-many-branches,not-an-iterable,unidiomatic-typecheck,unsubscriptable-object\nimport logging\nfrom typing import Any, Set, Tuple, cast\n\nfrom aea.configurations.base import PublicId\nfrom aea.exceptions import AEAEnforceError, enforce\nfrom aea.protocols.base import Message\n\nfrom packages.fetchai.protocols.oef_search.custom_types import (\n    AgentsInfo as CustomAgentsInfo,\n)\nfrom packages.fetchai.protocols.oef_search.custom_types import (\n    Description as CustomDescription,\n)\nfrom packages.fetchai.protocols.oef_search.custom_types import (\n    OefErrorOperation as CustomOefErrorOperation,\n)\nfrom packages.fetchai.protocols.oef_search.custom_types import Query as CustomQuery\n\n\n_default_logger = logging.getLogger(\"aea.packages.fetchai.protocols.oef_search.message\")\n\nDEFAULT_BODY_SIZE = 4\n\n\nclass OefSearchMessage(Message):\n    \"\"\"A protocol for interacting with an OEF search service.\"\"\"\n\n    protocol_id = PublicId.from_str(\"fetchai/oef_search:1.1.7\")\n    protocol_specification_id = PublicId.from_str(\"fetchai/oef_search:1.0.0\")\n\n    AgentsInfo = CustomAgentsInfo\n\n    Description = CustomDescription\n\n    OefErrorOperation = CustomOefErrorOperation\n\n    Query = CustomQuery\n\n    class Performative(Message.Performative):\n        \"\"\"Performatives for the oef_search protocol.\"\"\"\n\n        OEF_ERROR = \"oef_error\"\n        REGISTER_SERVICE = \"register_service\"\n        SEARCH_RESULT = \"search_result\"\n        SEARCH_SERVICES = \"search_services\"\n        SUCCESS = \"success\"\n        UNREGISTER_SERVICE = \"unregister_service\"\n\n        def __str__(self) -> str:\n            \"\"\"Get the string representation.\"\"\"\n            return str(self.value)\n\n    _performatives = {\n        \"oef_error\",\n        \"register_service\",\n        \"search_result\",\n        \"search_services\",\n        \"success\",\n        \"unregister_service\",\n    }\n    __slots__: Tuple[str, ...] = tuple()\n\n    class _SlotsCls:\n        __slots__ = (\n            \"agents\",\n            \"agents_info\",\n            \"dialogue_reference\",\n            \"message_id\",\n            \"oef_error_operation\",\n            \"performative\",\n            \"query\",\n            \"service_description\",\n            \"target\",\n        )\n\n    def __init__(\n        self,\n        performative: Performative,\n        dialogue_reference: Tuple[str, str] = (\"\", \"\"),\n        message_id: int = 1,\n        target: int = 0,\n        **kwargs: Any,\n    ):\n        \"\"\"\n        Initialise an instance of OefSearchMessage.\n\n        :param message_id: the message id.\n        :param dialogue_reference: the dialogue reference.\n        :param target: the message target.\n        :param performative: the message performative.\n        :param **kwargs: extra options.\n        \"\"\"\n        super().__init__(\n            dialogue_reference=dialogue_reference,\n            message_id=message_id,\n            target=target,\n            performative=OefSearchMessage.Performative(performative),\n            **kwargs,\n        )\n\n    @property\n    def valid_performatives(self) -> Set[str]:\n        \"\"\"Get valid performatives.\"\"\"\n        return self._performatives\n\n    @property\n    def dialogue_reference(self) -> Tuple[str, str]:\n        \"\"\"Get the dialogue_reference of the message.\"\"\"\n        enforce(self.is_set(\"dialogue_reference\"), \"dialogue_reference is not set.\")\n        return cast(Tuple[str, str], self.get(\"dialogue_reference\"))\n\n    @property\n    def message_id(self) -> int:\n        \"\"\"Get the message_id of the message.\"\"\"\n        enforce(self.is_set(\"message_id\"), \"message_id is not set.\")\n        return cast(int, self.get(\"message_id\"))\n\n    @property\n    def performative(self) -> Performative:  # type: ignore # noqa: F821\n        \"\"\"Get the performative of the message.\"\"\"\n        enforce(self.is_set(\"performative\"), \"performative is not set.\")\n        return cast(OefSearchMessage.Performative, self.get(\"performative\"))\n\n    @property\n    def target(self) -> int:\n        \"\"\"Get the target of the message.\"\"\"\n        enforce(self.is_set(\"target\"), \"target is not set.\")\n        return cast(int, self.get(\"target\"))\n\n    @property\n    def agents(self) -> Tuple[str, ...]:\n        \"\"\"Get the 'agents' content from the message.\"\"\"\n        enforce(self.is_set(\"agents\"), \"'agents' content is not set.\")\n        return cast(Tuple[str, ...], self.get(\"agents\"))\n\n    @property\n    def agents_info(self) -> CustomAgentsInfo:\n        \"\"\"Get the 'agents_info' content from the message.\"\"\"\n        enforce(self.is_set(\"agents_info\"), \"'agents_info' content is not set.\")\n        return cast(CustomAgentsInfo, self.get(\"agents_info\"))\n\n    @property\n    def oef_error_operation(self) -> CustomOefErrorOperation:\n        \"\"\"Get the 'oef_error_operation' content from the message.\"\"\"\n        enforce(\n            self.is_set(\"oef_error_operation\"),\n            \"'oef_error_operation' content is not set.\",\n        )\n        return cast(CustomOefErrorOperation, self.get(\"oef_error_operation\"))\n\n    @property\n    def query(self) -> CustomQuery:\n        \"\"\"Get the 'query' content from the message.\"\"\"\n        enforce(self.is_set(\"query\"), \"'query' content is not set.\")\n        return cast(CustomQuery, self.get(\"query\"))\n\n    @property\n    def service_description(self) -> CustomDescription:\n        \"\"\"Get the 'service_description' content from the message.\"\"\"\n        enforce(\n            self.is_set(\"service_description\"),\n            \"'service_description' content is not set.\",\n        )\n        return cast(CustomDescription, self.get(\"service_description\"))\n\n    def _is_consistent(self) -> bool:\n        \"\"\"Check that the message follows the oef_search protocol.\"\"\"\n        try:\n            enforce(\n                isinstance(self.dialogue_reference, tuple),\n                \"Invalid type for 'dialogue_reference'. Expected 'tuple'. Found '{}'.\".format(\n                    type(self.dialogue_reference)\n                ),\n            )\n            enforce(\n                isinstance(self.dialogue_reference[0], str),\n                \"Invalid type for 'dialogue_reference[0]'. Expected 'str'. Found '{}'.\".format(\n                    type(self.dialogue_reference[0])\n                ),\n            )\n            enforce(\n                isinstance(self.dialogue_reference[1], str),\n                \"Invalid type for 'dialogue_reference[1]'. Expected 'str'. Found '{}'.\".format(\n                    type(self.dialogue_reference[1])\n                ),\n            )\n            enforce(\n                type(self.message_id) is int,\n                \"Invalid type for 'message_id'. Expected 'int'. Found '{}'.\".format(\n                    type(self.message_id)\n                ),\n            )\n            enforce(\n                type(self.target) is int,\n                \"Invalid type for 'target'. Expected 'int'. Found '{}'.\".format(\n                    type(self.target)\n                ),\n            )\n\n            # Light Protocol Rule 2\n            # Check correct performative\n            enforce(\n                isinstance(self.performative, OefSearchMessage.Performative),\n                \"Invalid 'performative'. Expected either of '{}'. Found '{}'.\".format(\n                    self.valid_performatives, self.performative\n                ),\n            )\n\n            # Check correct contents\n            actual_nb_of_contents = len(self._body) - DEFAULT_BODY_SIZE\n            expected_nb_of_contents = 0\n            if self.performative == OefSearchMessage.Performative.REGISTER_SERVICE:\n                expected_nb_of_contents = 1\n                enforce(\n                    isinstance(self.service_description, CustomDescription),\n                    \"Invalid type for content 'service_description'. Expected 'Description'. Found '{}'.\".format(\n                        type(self.service_description)\n                    ),\n                )\n            elif self.performative == OefSearchMessage.Performative.UNREGISTER_SERVICE:\n                expected_nb_of_contents = 1\n                enforce(\n                    isinstance(self.service_description, CustomDescription),\n                    \"Invalid type for content 'service_description'. Expected 'Description'. Found '{}'.\".format(\n                        type(self.service_description)\n                    ),\n                )\n            elif self.performative == OefSearchMessage.Performative.SEARCH_SERVICES:\n                expected_nb_of_contents = 1\n                enforce(\n                    isinstance(self.query, CustomQuery),\n                    \"Invalid type for content 'query'. Expected 'Query'. Found '{}'.\".format(\n                        type(self.query)\n                    ),\n                )\n            elif self.performative == OefSearchMessage.Performative.SEARCH_RESULT:\n                expected_nb_of_contents = 2\n                enforce(\n                    isinstance(self.agents, tuple),\n                    \"Invalid type for content 'agents'. Expected 'tuple'. Found '{}'.\".format(\n                        type(self.agents)\n                    ),\n                )\n                enforce(\n                    all(isinstance(element, str) for element in self.agents),\n                    \"Invalid type for tuple elements in content 'agents'. Expected 'str'.\",\n                )\n                enforce(\n                    isinstance(self.agents_info, CustomAgentsInfo),\n                    \"Invalid type for content 'agents_info'. Expected 'AgentsInfo'. Found '{}'.\".format(\n                        type(self.agents_info)\n                    ),\n                )\n            elif self.performative == OefSearchMessage.Performative.SUCCESS:\n                expected_nb_of_contents = 1\n                enforce(\n                    isinstance(self.agents_info, CustomAgentsInfo),\n                    \"Invalid type for content 'agents_info'. Expected 'AgentsInfo'. Found '{}'.\".format(\n                        type(self.agents_info)\n                    ),\n                )\n            elif self.performative == OefSearchMessage.Performative.OEF_ERROR:\n                expected_nb_of_contents = 1\n                enforce(\n                    isinstance(self.oef_error_operation, CustomOefErrorOperation),\n                    \"Invalid type for content 'oef_error_operation'. Expected 'OefErrorOperation'. Found '{}'.\".format(\n                        type(self.oef_error_operation)\n                    ),\n                )\n\n            # Check correct content count\n            enforce(\n                expected_nb_of_contents == actual_nb_of_contents,\n                \"Incorrect number of contents. Expected {}. Found {}\".format(\n                    expected_nb_of_contents, actual_nb_of_contents\n                ),\n            )\n\n            # Light Protocol Rule 3\n            if self.message_id == 1:\n                enforce(\n                    self.target == 0,\n                    \"Invalid 'target'. Expected 0 (because 'message_id' is 1). Found {}.\".format(\n                        self.target\n                    ),\n                )\n        except (AEAEnforceError, ValueError, KeyError) as e:\n            _default_logger.error(str(e))\n            return False\n\n        return True\n"
  },
  {
    "path": "packages/fetchai/protocols/oef_search/oef_search.proto",
    "content": "syntax = \"proto3\";\n\npackage aea.fetchai.oef_search.v1_0_0;\n\nmessage OefSearchMessage{\n\n  // Custom Types\n  message AgentsInfo{\n    bytes agents_info = 1;\n  }\n\n  message Description{\n    bytes description_bytes = 1;\n  }\n\n  message OefErrorOperation{\n    enum OefErrorEnum {\n      REGISTER_SERVICE = 0;\n      UNREGISTER_SERVICE = 1;\n      SEARCH_SERVICES = 2;\n      SEND_MESSAGE = 3;\n    }\n    OefErrorEnum oef_error = 1;\n  }\n\n  message Query{\n    bytes query_bytes = 1;\n  }\n\n\n  // Performatives and contents\n  message Register_Service_Performative{\n    Description service_description = 1;\n  }\n\n  message Unregister_Service_Performative{\n    Description service_description = 1;\n  }\n\n  message Search_Services_Performative{\n    Query query = 1;\n  }\n\n  message Search_Result_Performative{\n    repeated string agents = 1;\n    AgentsInfo agents_info = 2;\n  }\n\n  message Success_Performative{\n    AgentsInfo agents_info = 1;\n  }\n\n  message Oef_Error_Performative{\n    OefErrorOperation oef_error_operation = 1;\n  }\n\n\n  oneof performative{\n    Oef_Error_Performative oef_error = 5;\n    Register_Service_Performative register_service = 6;\n    Search_Result_Performative search_result = 7;\n    Search_Services_Performative search_services = 8;\n    Success_Performative success = 9;\n    Unregister_Service_Performative unregister_service = 10;\n  }\n}\n"
  },
  {
    "path": "packages/fetchai/protocols/oef_search/oef_search_pb2.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by the protocol buffer compiler.  DO NOT EDIT!\n# source: oef_search.proto\n\"\"\"Generated protocol buffer code.\"\"\"\nfrom google.protobuf import descriptor as _descriptor\nfrom google.protobuf import descriptor_pool as _descriptor_pool\nfrom google.protobuf import message as _message\nfrom google.protobuf import reflection as _reflection\nfrom google.protobuf import symbol_database as _symbol_database\n\n# @@protoc_insertion_point(imports)\n\n_sym_db = _symbol_database.Default()\n\n\nDESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(\n    b'\\n\\x10oef_search.proto\\x12\\x1d\\x61\\x65\\x61.fetchai.oef_search.v1_0_0\"\\x89\\r\\n\\x10OefSearchMessage\\x12[\\n\\toef_error\\x18\\x05 \\x01(\\x0b\\x32\\x46.aea.fetchai.oef_search.v1_0_0.OefSearchMessage.Oef_Error_PerformativeH\\x00\\x12i\\n\\x10register_service\\x18\\x06 \\x01(\\x0b\\x32M.aea.fetchai.oef_search.v1_0_0.OefSearchMessage.Register_Service_PerformativeH\\x00\\x12\\x63\\n\\rsearch_result\\x18\\x07 \\x01(\\x0b\\x32J.aea.fetchai.oef_search.v1_0_0.OefSearchMessage.Search_Result_PerformativeH\\x00\\x12g\\n\\x0fsearch_services\\x18\\x08 \\x01(\\x0b\\x32L.aea.fetchai.oef_search.v1_0_0.OefSearchMessage.Search_Services_PerformativeH\\x00\\x12W\\n\\x07success\\x18\\t \\x01(\\x0b\\x32\\x44.aea.fetchai.oef_search.v1_0_0.OefSearchMessage.Success_PerformativeH\\x00\\x12m\\n\\x12unregister_service\\x18\\n \\x01(\\x0b\\x32O.aea.fetchai.oef_search.v1_0_0.OefSearchMessage.Unregister_Service_PerformativeH\\x00\\x1a!\\n\\nAgentsInfo\\x12\\x13\\n\\x0b\\x61gents_info\\x18\\x01 \\x01(\\x0c\\x1a(\\n\\x0b\\x44\\x65scription\\x12\\x19\\n\\x11\\x64\\x65scription_bytes\\x18\\x01 \\x01(\\x0c\\x1a\\xdb\\x01\\n\\x11OefErrorOperation\\x12\\x61\\n\\toef_error\\x18\\x01 \\x01(\\x0e\\x32N.aea.fetchai.oef_search.v1_0_0.OefSearchMessage.OefErrorOperation.OefErrorEnum\"c\\n\\x0cOefErrorEnum\\x12\\x14\\n\\x10REGISTER_SERVICE\\x10\\x00\\x12\\x16\\n\\x12UNREGISTER_SERVICE\\x10\\x01\\x12\\x13\\n\\x0fSEARCH_SERVICES\\x10\\x02\\x12\\x10\\n\\x0cSEND_MESSAGE\\x10\\x03\\x1a\\x1c\\n\\x05Query\\x12\\x13\\n\\x0bquery_bytes\\x18\\x01 \\x01(\\x0c\\x1ay\\n\\x1dRegister_Service_Performative\\x12X\\n\\x13service_description\\x18\\x01 \\x01(\\x0b\\x32;.aea.fetchai.oef_search.v1_0_0.OefSearchMessage.Description\\x1a{\\n\\x1fUnregister_Service_Performative\\x12X\\n\\x13service_description\\x18\\x01 \\x01(\\x0b\\x32;.aea.fetchai.oef_search.v1_0_0.OefSearchMessage.Description\\x1a\\x64\\n\\x1cSearch_Services_Performative\\x12\\x44\\n\\x05query\\x18\\x01 \\x01(\\x0b\\x32\\x35.aea.fetchai.oef_search.v1_0_0.OefSearchMessage.Query\\x1a}\\n\\x1aSearch_Result_Performative\\x12\\x0e\\n\\x06\\x61gents\\x18\\x01 \\x03(\\t\\x12O\\n\\x0b\\x61gents_info\\x18\\x02 \\x01(\\x0b\\x32:.aea.fetchai.oef_search.v1_0_0.OefSearchMessage.AgentsInfo\\x1ag\\n\\x14Success_Performative\\x12O\\n\\x0b\\x61gents_info\\x18\\x01 \\x01(\\x0b\\x32:.aea.fetchai.oef_search.v1_0_0.OefSearchMessage.AgentsInfo\\x1ax\\n\\x16Oef_Error_Performative\\x12^\\n\\x13oef_error_operation\\x18\\x01 \\x01(\\x0b\\x32\\x41.aea.fetchai.oef_search.v1_0_0.OefSearchMessage.OefErrorOperationB\\x0e\\n\\x0cperformativeb\\x06proto3'\n)\n\n\n_OEFSEARCHMESSAGE = DESCRIPTOR.message_types_by_name[\"OefSearchMessage\"]\n_OEFSEARCHMESSAGE_AGENTSINFO = _OEFSEARCHMESSAGE.nested_types_by_name[\"AgentsInfo\"]\n_OEFSEARCHMESSAGE_DESCRIPTION = _OEFSEARCHMESSAGE.nested_types_by_name[\"Description\"]\n_OEFSEARCHMESSAGE_OEFERROROPERATION = _OEFSEARCHMESSAGE.nested_types_by_name[\n    \"OefErrorOperation\"\n]\n_OEFSEARCHMESSAGE_QUERY = _OEFSEARCHMESSAGE.nested_types_by_name[\"Query\"]\n_OEFSEARCHMESSAGE_REGISTER_SERVICE_PERFORMATIVE = (\n    _OEFSEARCHMESSAGE.nested_types_by_name[\"Register_Service_Performative\"]\n)\n_OEFSEARCHMESSAGE_UNREGISTER_SERVICE_PERFORMATIVE = (\n    _OEFSEARCHMESSAGE.nested_types_by_name[\"Unregister_Service_Performative\"]\n)\n_OEFSEARCHMESSAGE_SEARCH_SERVICES_PERFORMATIVE = _OEFSEARCHMESSAGE.nested_types_by_name[\n    \"Search_Services_Performative\"\n]\n_OEFSEARCHMESSAGE_SEARCH_RESULT_PERFORMATIVE = _OEFSEARCHMESSAGE.nested_types_by_name[\n    \"Search_Result_Performative\"\n]\n_OEFSEARCHMESSAGE_SUCCESS_PERFORMATIVE = _OEFSEARCHMESSAGE.nested_types_by_name[\n    \"Success_Performative\"\n]\n_OEFSEARCHMESSAGE_OEF_ERROR_PERFORMATIVE = _OEFSEARCHMESSAGE.nested_types_by_name[\n    \"Oef_Error_Performative\"\n]\n_OEFSEARCHMESSAGE_OEFERROROPERATION_OEFERRORENUM = (\n    _OEFSEARCHMESSAGE_OEFERROROPERATION.enum_types_by_name[\"OefErrorEnum\"]\n)\nOefSearchMessage = _reflection.GeneratedProtocolMessageType(\n    \"OefSearchMessage\",\n    (_message.Message,),\n    {\n        \"AgentsInfo\": _reflection.GeneratedProtocolMessageType(\n            \"AgentsInfo\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _OEFSEARCHMESSAGE_AGENTSINFO,\n                \"__module__\": \"oef_search_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.oef_search.v1_0_0.OefSearchMessage.AgentsInfo)\n            },\n        ),\n        \"Description\": _reflection.GeneratedProtocolMessageType(\n            \"Description\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _OEFSEARCHMESSAGE_DESCRIPTION,\n                \"__module__\": \"oef_search_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.oef_search.v1_0_0.OefSearchMessage.Description)\n            },\n        ),\n        \"OefErrorOperation\": _reflection.GeneratedProtocolMessageType(\n            \"OefErrorOperation\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _OEFSEARCHMESSAGE_OEFERROROPERATION,\n                \"__module__\": \"oef_search_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.oef_search.v1_0_0.OefSearchMessage.OefErrorOperation)\n            },\n        ),\n        \"Query\": _reflection.GeneratedProtocolMessageType(\n            \"Query\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _OEFSEARCHMESSAGE_QUERY,\n                \"__module__\": \"oef_search_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.oef_search.v1_0_0.OefSearchMessage.Query)\n            },\n        ),\n        \"Register_Service_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Register_Service_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _OEFSEARCHMESSAGE_REGISTER_SERVICE_PERFORMATIVE,\n                \"__module__\": \"oef_search_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.oef_search.v1_0_0.OefSearchMessage.Register_Service_Performative)\n            },\n        ),\n        \"Unregister_Service_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Unregister_Service_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _OEFSEARCHMESSAGE_UNREGISTER_SERVICE_PERFORMATIVE,\n                \"__module__\": \"oef_search_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.oef_search.v1_0_0.OefSearchMessage.Unregister_Service_Performative)\n            },\n        ),\n        \"Search_Services_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Search_Services_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _OEFSEARCHMESSAGE_SEARCH_SERVICES_PERFORMATIVE,\n                \"__module__\": \"oef_search_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.oef_search.v1_0_0.OefSearchMessage.Search_Services_Performative)\n            },\n        ),\n        \"Search_Result_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Search_Result_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _OEFSEARCHMESSAGE_SEARCH_RESULT_PERFORMATIVE,\n                \"__module__\": \"oef_search_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.oef_search.v1_0_0.OefSearchMessage.Search_Result_Performative)\n            },\n        ),\n        \"Success_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Success_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _OEFSEARCHMESSAGE_SUCCESS_PERFORMATIVE,\n                \"__module__\": \"oef_search_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.oef_search.v1_0_0.OefSearchMessage.Success_Performative)\n            },\n        ),\n        \"Oef_Error_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Oef_Error_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _OEFSEARCHMESSAGE_OEF_ERROR_PERFORMATIVE,\n                \"__module__\": \"oef_search_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.oef_search.v1_0_0.OefSearchMessage.Oef_Error_Performative)\n            },\n        ),\n        \"DESCRIPTOR\": _OEFSEARCHMESSAGE,\n        \"__module__\": \"oef_search_pb2\"\n        # @@protoc_insertion_point(class_scope:aea.fetchai.oef_search.v1_0_0.OefSearchMessage)\n    },\n)\n_sym_db.RegisterMessage(OefSearchMessage)\n_sym_db.RegisterMessage(OefSearchMessage.AgentsInfo)\n_sym_db.RegisterMessage(OefSearchMessage.Description)\n_sym_db.RegisterMessage(OefSearchMessage.OefErrorOperation)\n_sym_db.RegisterMessage(OefSearchMessage.Query)\n_sym_db.RegisterMessage(OefSearchMessage.Register_Service_Performative)\n_sym_db.RegisterMessage(OefSearchMessage.Unregister_Service_Performative)\n_sym_db.RegisterMessage(OefSearchMessage.Search_Services_Performative)\n_sym_db.RegisterMessage(OefSearchMessage.Search_Result_Performative)\n_sym_db.RegisterMessage(OefSearchMessage.Success_Performative)\n_sym_db.RegisterMessage(OefSearchMessage.Oef_Error_Performative)\n\nif _descriptor._USE_C_DESCRIPTORS == False:\n\n    DESCRIPTOR._options = None\n    _OEFSEARCHMESSAGE._serialized_start = 52\n    _OEFSEARCHMESSAGE._serialized_end = 1725\n    _OEFSEARCHMESSAGE_AGENTSINFO._serialized_start = 678\n    _OEFSEARCHMESSAGE_AGENTSINFO._serialized_end = 711\n    _OEFSEARCHMESSAGE_DESCRIPTION._serialized_start = 713\n    _OEFSEARCHMESSAGE_DESCRIPTION._serialized_end = 753\n    _OEFSEARCHMESSAGE_OEFERROROPERATION._serialized_start = 756\n    _OEFSEARCHMESSAGE_OEFERROROPERATION._serialized_end = 975\n    _OEFSEARCHMESSAGE_OEFERROROPERATION_OEFERRORENUM._serialized_start = 876\n    _OEFSEARCHMESSAGE_OEFERROROPERATION_OEFERRORENUM._serialized_end = 975\n    _OEFSEARCHMESSAGE_QUERY._serialized_start = 977\n    _OEFSEARCHMESSAGE_QUERY._serialized_end = 1005\n    _OEFSEARCHMESSAGE_REGISTER_SERVICE_PERFORMATIVE._serialized_start = 1007\n    _OEFSEARCHMESSAGE_REGISTER_SERVICE_PERFORMATIVE._serialized_end = 1128\n    _OEFSEARCHMESSAGE_UNREGISTER_SERVICE_PERFORMATIVE._serialized_start = 1130\n    _OEFSEARCHMESSAGE_UNREGISTER_SERVICE_PERFORMATIVE._serialized_end = 1253\n    _OEFSEARCHMESSAGE_SEARCH_SERVICES_PERFORMATIVE._serialized_start = 1255\n    _OEFSEARCHMESSAGE_SEARCH_SERVICES_PERFORMATIVE._serialized_end = 1355\n    _OEFSEARCHMESSAGE_SEARCH_RESULT_PERFORMATIVE._serialized_start = 1357\n    _OEFSEARCHMESSAGE_SEARCH_RESULT_PERFORMATIVE._serialized_end = 1482\n    _OEFSEARCHMESSAGE_SUCCESS_PERFORMATIVE._serialized_start = 1484\n    _OEFSEARCHMESSAGE_SUCCESS_PERFORMATIVE._serialized_end = 1587\n    _OEFSEARCHMESSAGE_OEF_ERROR_PERFORMATIVE._serialized_start = 1589\n    _OEFSEARCHMESSAGE_OEF_ERROR_PERFORMATIVE._serialized_end = 1709\n# @@protoc_insertion_point(module_scope)\n"
  },
  {
    "path": "packages/fetchai/protocols/oef_search/protocol.yaml",
    "content": "name: oef_search\nauthor: fetchai\nversion: 1.1.7\nprotocol_specification_id: fetchai/oef_search:1.0.0\ntype: protocol\ndescription: A protocol for interacting with an OEF search service.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: QmZvdgb8Ns3YG1yVHEUHkmW7aLJRtKhSBRjcjLCZbfouGh\n  __init__.py: QmWPibhs94rCa3Vi4kUQNm9Gw2DcWFaihifkz6FJamasB2\n  custom_types.py: QmX9ynYP53vEmENbextDTw9NRkrvbeS5PjnStqLUEDQLS2\n  dialogues.py: Qmf7epXX4QZqLEYKQdAieXpwCYKZCdRthDdZxfmpHsryaq\n  message.py: QmYPaQXBTSSTrk8HUABxbTfFLQRca2pcVqYzicUvTks6gG\n  oef_search.proto: QmaYkawAXEeeNuCcjmwcvdsttnE3owtuP9ouAYVyRu7M2J\n  oef_search_pb2.py: QmSCvcwkLmwWESqiAs2Vj2yioUwLmdzMGaCDRo3sHT1ByL\n  serialization.py: QmRNFL8Gf5pTQdALxkB6YBQumsoJDb9hiQ1CVApoU3qdJ6\nfingerprint_ignore_patterns: []\ndependencies:\n  protobuf: {}\n"
  },
  {
    "path": "packages/fetchai/protocols/oef_search/serialization.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Serialization module for oef_search protocol.\"\"\"\n\n# pylint: disable=too-many-statements,too-many-locals,no-member,too-few-public-methods,redefined-builtin\nfrom typing import Any, Dict, cast\n\nfrom aea.mail.base_pb2 import DialogueMessage\nfrom aea.mail.base_pb2 import Message as ProtobufMessage\nfrom aea.protocols.base import Message, Serializer\n\nfrom packages.fetchai.protocols.oef_search import oef_search_pb2\nfrom packages.fetchai.protocols.oef_search.custom_types import (\n    AgentsInfo,\n    Description,\n    OefErrorOperation,\n    Query,\n)\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\n\n\nclass OefSearchSerializer(Serializer):\n    \"\"\"Serialization for the 'oef_search' protocol.\"\"\"\n\n    @staticmethod\n    def encode(msg: Message) -> bytes:\n        \"\"\"\n        Encode a 'OefSearch' message into bytes.\n\n        :param msg: the message object.\n        :return: the bytes.\n        \"\"\"\n        msg = cast(OefSearchMessage, msg)\n        message_pb = ProtobufMessage()\n        dialogue_message_pb = DialogueMessage()\n        oef_search_msg = oef_search_pb2.OefSearchMessage()\n\n        dialogue_message_pb.message_id = msg.message_id\n        dialogue_reference = msg.dialogue_reference\n        dialogue_message_pb.dialogue_starter_reference = dialogue_reference[0]\n        dialogue_message_pb.dialogue_responder_reference = dialogue_reference[1]\n        dialogue_message_pb.target = msg.target\n\n        performative_id = msg.performative\n        if performative_id == OefSearchMessage.Performative.REGISTER_SERVICE:\n            performative = oef_search_pb2.OefSearchMessage.Register_Service_Performative()  # type: ignore\n            service_description = msg.service_description\n            Description.encode(performative.service_description, service_description)\n            oef_search_msg.register_service.CopyFrom(performative)\n        elif performative_id == OefSearchMessage.Performative.UNREGISTER_SERVICE:\n            performative = oef_search_pb2.OefSearchMessage.Unregister_Service_Performative()  # type: ignore\n            service_description = msg.service_description\n            Description.encode(performative.service_description, service_description)\n            oef_search_msg.unregister_service.CopyFrom(performative)\n        elif performative_id == OefSearchMessage.Performative.SEARCH_SERVICES:\n            performative = oef_search_pb2.OefSearchMessage.Search_Services_Performative()  # type: ignore\n            query = msg.query\n            Query.encode(performative.query, query)\n            oef_search_msg.search_services.CopyFrom(performative)\n        elif performative_id == OefSearchMessage.Performative.SEARCH_RESULT:\n            performative = oef_search_pb2.OefSearchMessage.Search_Result_Performative()  # type: ignore\n            agents = msg.agents\n            performative.agents.extend(agents)\n            agents_info = msg.agents_info\n            AgentsInfo.encode(performative.agents_info, agents_info)\n            oef_search_msg.search_result.CopyFrom(performative)\n        elif performative_id == OefSearchMessage.Performative.SUCCESS:\n            performative = oef_search_pb2.OefSearchMessage.Success_Performative()  # type: ignore\n            agents_info = msg.agents_info\n            AgentsInfo.encode(performative.agents_info, agents_info)\n            oef_search_msg.success.CopyFrom(performative)\n        elif performative_id == OefSearchMessage.Performative.OEF_ERROR:\n            performative = oef_search_pb2.OefSearchMessage.Oef_Error_Performative()  # type: ignore\n            oef_error_operation = msg.oef_error_operation\n            OefErrorOperation.encode(\n                performative.oef_error_operation, oef_error_operation\n            )\n            oef_search_msg.oef_error.CopyFrom(performative)\n        else:\n            raise ValueError(\"Performative not valid: {}\".format(performative_id))\n\n        dialogue_message_pb.content = oef_search_msg.SerializeToString()\n\n        message_pb.dialogue_message.CopyFrom(dialogue_message_pb)\n        message_bytes = message_pb.SerializeToString()\n        return message_bytes\n\n    @staticmethod\n    def decode(obj: bytes) -> Message:\n        \"\"\"\n        Decode bytes into a 'OefSearch' message.\n\n        :param obj: the bytes object.\n        :return: the 'OefSearch' message.\n        \"\"\"\n        message_pb = ProtobufMessage()\n        oef_search_pb = oef_search_pb2.OefSearchMessage()\n        message_pb.ParseFromString(obj)\n        message_id = message_pb.dialogue_message.message_id\n        dialogue_reference = (\n            message_pb.dialogue_message.dialogue_starter_reference,\n            message_pb.dialogue_message.dialogue_responder_reference,\n        )\n        target = message_pb.dialogue_message.target\n\n        oef_search_pb.ParseFromString(message_pb.dialogue_message.content)\n        performative = oef_search_pb.WhichOneof(\"performative\")\n        performative_id = OefSearchMessage.Performative(str(performative))\n        performative_content = {}  # type: Dict[str, Any]\n        if performative_id == OefSearchMessage.Performative.REGISTER_SERVICE:\n            pb2_service_description = oef_search_pb.register_service.service_description\n            service_description = Description.decode(pb2_service_description)\n            performative_content[\"service_description\"] = service_description\n        elif performative_id == OefSearchMessage.Performative.UNREGISTER_SERVICE:\n            pb2_service_description = (\n                oef_search_pb.unregister_service.service_description\n            )\n            service_description = Description.decode(pb2_service_description)\n            performative_content[\"service_description\"] = service_description\n        elif performative_id == OefSearchMessage.Performative.SEARCH_SERVICES:\n            pb2_query = oef_search_pb.search_services.query\n            query = Query.decode(pb2_query)\n            performative_content[\"query\"] = query\n        elif performative_id == OefSearchMessage.Performative.SEARCH_RESULT:\n            agents = oef_search_pb.search_result.agents\n            agents_tuple = tuple(agents)\n            performative_content[\"agents\"] = agents_tuple\n            pb2_agents_info = oef_search_pb.search_result.agents_info\n            agents_info = AgentsInfo.decode(pb2_agents_info)\n            performative_content[\"agents_info\"] = agents_info\n        elif performative_id == OefSearchMessage.Performative.SUCCESS:\n            pb2_agents_info = oef_search_pb.success.agents_info\n            agents_info = AgentsInfo.decode(pb2_agents_info)\n            performative_content[\"agents_info\"] = agents_info\n        elif performative_id == OefSearchMessage.Performative.OEF_ERROR:\n            pb2_oef_error_operation = oef_search_pb.oef_error.oef_error_operation\n            oef_error_operation = OefErrorOperation.decode(pb2_oef_error_operation)\n            performative_content[\"oef_error_operation\"] = oef_error_operation\n        else:\n            raise ValueError(\"Performative not valid: {}.\".format(performative_id))\n\n        return OefSearchMessage(\n            message_id=message_id,\n            dialogue_reference=dialogue_reference,\n            target=target,\n            performative=performative,\n            **performative_content\n        )\n"
  },
  {
    "path": "packages/fetchai/protocols/prometheus/README.md",
    "content": "# Prometheus Protocol\n\n## Description\n\nThis is a protocol for interacting with prometheus connection.\n\n## Specification\n\n```yaml\n---\nname: prometheus\nauthor: fetchai\nversion: 1.1.7\ndescription: A protocol for adding and updating metrics to a prometheus server.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nprotocol_specification_id: fetchai/prometheus:1.0.0\nspeech_acts:\n  add_metric:\n    type: pt:str\n    title: pt:str\n    description: pt:str\n    labels: pt:dict[pt:str, pt:str]\n  update_metric:\n    title: pt:str\n    callable: pt:str\n    value: pt:float\n    labels: pt:dict[pt:str, pt:str]\n  response:\n    code: pt:int\n    message: pt:optional[pt:str]\n...\n---\ninitiation: [add_metric, update_metric]\nreply:\n  add_metric: [response]\n  update_metric: [response]\n  response: []\ntermination: [response]\nroles: {agent, server}\nend_states: [successful]\nkeep_terminal_state_dialogues: false\n...\n```\n\n## Links\n"
  },
  {
    "path": "packages/fetchai/protocols/prometheus/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nThis module contains the support resources for the prometheus protocol.\n\nIt was created with protocol buffer compiler version `libprotoc 3.19.4` and aea version `1.2.5`.\n\"\"\"\n\nfrom packages.fetchai.protocols.prometheus.message import PrometheusMessage\nfrom packages.fetchai.protocols.prometheus.serialization import PrometheusSerializer\n\n\nPrometheusMessage.serializer = PrometheusSerializer\n"
  },
  {
    "path": "packages/fetchai/protocols/prometheus/dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nThis module contains the classes required for prometheus dialogue management.\n\n- PrometheusDialogue: The dialogue class maintains state of a dialogue and manages it.\n- PrometheusDialogues: The dialogues class keeps track of all dialogues.\n\"\"\"\n\nfrom abc import ABC\nfrom typing import Callable, Dict, FrozenSet, Type, cast\n\nfrom aea.common import Address\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue, DialogueLabel, Dialogues\n\nfrom packages.fetchai.protocols.prometheus.message import PrometheusMessage\n\n\nclass PrometheusDialogue(Dialogue):\n    \"\"\"The prometheus dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    INITIAL_PERFORMATIVES: FrozenSet[Message.Performative] = frozenset(\n        {\n            PrometheusMessage.Performative.ADD_METRIC,\n            PrometheusMessage.Performative.UPDATE_METRIC,\n        }\n    )\n    TERMINAL_PERFORMATIVES: FrozenSet[Message.Performative] = frozenset(\n        {PrometheusMessage.Performative.RESPONSE}\n    )\n    VALID_REPLIES: Dict[Message.Performative, FrozenSet[Message.Performative]] = {\n        PrometheusMessage.Performative.ADD_METRIC: frozenset(\n            {PrometheusMessage.Performative.RESPONSE}\n        ),\n        PrometheusMessage.Performative.RESPONSE: frozenset(),\n        PrometheusMessage.Performative.UPDATE_METRIC: frozenset(\n            {PrometheusMessage.Performative.RESPONSE}\n        ),\n    }\n\n    class Role(Dialogue.Role):\n        \"\"\"This class defines the agent's role in a prometheus dialogue.\"\"\"\n\n        AGENT = \"agent\"\n        SERVER = \"server\"\n\n    class EndState(Dialogue.EndState):\n        \"\"\"This class defines the end states of a prometheus dialogue.\"\"\"\n\n        SUCCESSFUL = 0\n\n    def __init__(\n        self,\n        dialogue_label: DialogueLabel,\n        self_address: Address,\n        role: Dialogue.Role,\n        message_class: Type[PrometheusMessage] = PrometheusMessage,\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n        :param message_class: the message class used\n        \"\"\"\n        Dialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            message_class=message_class,\n            self_address=self_address,\n            role=role,\n        )\n\n\nclass PrometheusDialogues(Dialogues, ABC):\n    \"\"\"This class keeps track of all prometheus dialogues.\"\"\"\n\n    END_STATES = frozenset({PrometheusDialogue.EndState.SUCCESSFUL})\n\n    _keep_terminal_state_dialogues = False\n\n    def __init__(\n        self,\n        self_address: Address,\n        role_from_first_message: Callable[[Message, Address], Dialogue.Role],\n        dialogue_class: Type[PrometheusDialogue] = PrometheusDialogue,\n    ) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param self_address: the address of the entity for whom dialogues are maintained\n        :param dialogue_class: the dialogue class used\n        :param role_from_first_message: the callable determining role from first message\n        \"\"\"\n        Dialogues.__init__(\n            self,\n            self_address=self_address,\n            end_states=cast(FrozenSet[Dialogue.EndState], self.END_STATES),\n            message_class=PrometheusMessage,\n            dialogue_class=dialogue_class,\n            role_from_first_message=role_from_first_message,\n        )\n"
  },
  {
    "path": "packages/fetchai/protocols/prometheus/message.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains prometheus's message definition.\"\"\"\n\n# pylint: disable=too-many-statements,too-many-locals,no-member,too-few-public-methods,too-many-branches,not-an-iterable,unidiomatic-typecheck,unsubscriptable-object\nimport logging\nfrom typing import Any, Dict, Optional, Set, Tuple, cast\n\nfrom aea.configurations.base import PublicId\nfrom aea.exceptions import AEAEnforceError, enforce\nfrom aea.protocols.base import Message\n\n\n_default_logger = logging.getLogger(\"aea.packages.fetchai.protocols.prometheus.message\")\n\nDEFAULT_BODY_SIZE = 4\n\n\nclass PrometheusMessage(Message):\n    \"\"\"A protocol for adding and updating metrics to a prometheus server.\"\"\"\n\n    protocol_id = PublicId.from_str(\"fetchai/prometheus:1.1.7\")\n    protocol_specification_id = PublicId.from_str(\"fetchai/prometheus:1.0.0\")\n\n    class Performative(Message.Performative):\n        \"\"\"Performatives for the prometheus protocol.\"\"\"\n\n        ADD_METRIC = \"add_metric\"\n        RESPONSE = \"response\"\n        UPDATE_METRIC = \"update_metric\"\n\n        def __str__(self) -> str:\n            \"\"\"Get the string representation.\"\"\"\n            return str(self.value)\n\n    _performatives = {\"add_metric\", \"response\", \"update_metric\"}\n    __slots__: Tuple[str, ...] = tuple()\n\n    class _SlotsCls:\n        __slots__ = (\n            \"callable\",\n            \"code\",\n            \"description\",\n            \"dialogue_reference\",\n            \"labels\",\n            \"message\",\n            \"message_id\",\n            \"performative\",\n            \"target\",\n            \"title\",\n            \"type\",\n            \"value\",\n        )\n\n    def __init__(\n        self,\n        performative: Performative,\n        dialogue_reference: Tuple[str, str] = (\"\", \"\"),\n        message_id: int = 1,\n        target: int = 0,\n        **kwargs: Any,\n    ):\n        \"\"\"\n        Initialise an instance of PrometheusMessage.\n\n        :param message_id: the message id.\n        :param dialogue_reference: the dialogue reference.\n        :param target: the message target.\n        :param performative: the message performative.\n        :param **kwargs: extra options.\n        \"\"\"\n        super().__init__(\n            dialogue_reference=dialogue_reference,\n            message_id=message_id,\n            target=target,\n            performative=PrometheusMessage.Performative(performative),\n            **kwargs,\n        )\n\n    @property\n    def valid_performatives(self) -> Set[str]:\n        \"\"\"Get valid performatives.\"\"\"\n        return self._performatives\n\n    @property\n    def dialogue_reference(self) -> Tuple[str, str]:\n        \"\"\"Get the dialogue_reference of the message.\"\"\"\n        enforce(self.is_set(\"dialogue_reference\"), \"dialogue_reference is not set.\")\n        return cast(Tuple[str, str], self.get(\"dialogue_reference\"))\n\n    @property\n    def message_id(self) -> int:\n        \"\"\"Get the message_id of the message.\"\"\"\n        enforce(self.is_set(\"message_id\"), \"message_id is not set.\")\n        return cast(int, self.get(\"message_id\"))\n\n    @property\n    def performative(self) -> Performative:  # type: ignore # noqa: F821\n        \"\"\"Get the performative of the message.\"\"\"\n        enforce(self.is_set(\"performative\"), \"performative is not set.\")\n        return cast(PrometheusMessage.Performative, self.get(\"performative\"))\n\n    @property\n    def target(self) -> int:\n        \"\"\"Get the target of the message.\"\"\"\n        enforce(self.is_set(\"target\"), \"target is not set.\")\n        return cast(int, self.get(\"target\"))\n\n    @property\n    def callable(self) -> str:\n        \"\"\"Get the 'callable' content from the message.\"\"\"\n        enforce(self.is_set(\"callable\"), \"'callable' content is not set.\")\n        return cast(str, self.get(\"callable\"))\n\n    @property\n    def code(self) -> int:\n        \"\"\"Get the 'code' content from the message.\"\"\"\n        enforce(self.is_set(\"code\"), \"'code' content is not set.\")\n        return cast(int, self.get(\"code\"))\n\n    @property\n    def description(self) -> str:\n        \"\"\"Get the 'description' content from the message.\"\"\"\n        enforce(self.is_set(\"description\"), \"'description' content is not set.\")\n        return cast(str, self.get(\"description\"))\n\n    @property\n    def labels(self) -> Dict[str, str]:\n        \"\"\"Get the 'labels' content from the message.\"\"\"\n        enforce(self.is_set(\"labels\"), \"'labels' content is not set.\")\n        return cast(Dict[str, str], self.get(\"labels\"))\n\n    @property\n    def message(self) -> Optional[str]:\n        \"\"\"Get the 'message' content from the message.\"\"\"\n        return cast(Optional[str], self.get(\"message\"))\n\n    @property\n    def title(self) -> str:\n        \"\"\"Get the 'title' content from the message.\"\"\"\n        enforce(self.is_set(\"title\"), \"'title' content is not set.\")\n        return cast(str, self.get(\"title\"))\n\n    @property\n    def type(self) -> str:\n        \"\"\"Get the 'type' content from the message.\"\"\"\n        enforce(self.is_set(\"type\"), \"'type' content is not set.\")\n        return cast(str, self.get(\"type\"))\n\n    @property\n    def value(self) -> float:\n        \"\"\"Get the 'value' content from the message.\"\"\"\n        enforce(self.is_set(\"value\"), \"'value' content is not set.\")\n        return cast(float, self.get(\"value\"))\n\n    def _is_consistent(self) -> bool:\n        \"\"\"Check that the message follows the prometheus protocol.\"\"\"\n        try:\n            enforce(\n                isinstance(self.dialogue_reference, tuple),\n                \"Invalid type for 'dialogue_reference'. Expected 'tuple'. Found '{}'.\".format(\n                    type(self.dialogue_reference)\n                ),\n            )\n            enforce(\n                isinstance(self.dialogue_reference[0], str),\n                \"Invalid type for 'dialogue_reference[0]'. Expected 'str'. Found '{}'.\".format(\n                    type(self.dialogue_reference[0])\n                ),\n            )\n            enforce(\n                isinstance(self.dialogue_reference[1], str),\n                \"Invalid type for 'dialogue_reference[1]'. Expected 'str'. Found '{}'.\".format(\n                    type(self.dialogue_reference[1])\n                ),\n            )\n            enforce(\n                type(self.message_id) is int,\n                \"Invalid type for 'message_id'. Expected 'int'. Found '{}'.\".format(\n                    type(self.message_id)\n                ),\n            )\n            enforce(\n                type(self.target) is int,\n                \"Invalid type for 'target'. Expected 'int'. Found '{}'.\".format(\n                    type(self.target)\n                ),\n            )\n\n            # Light Protocol Rule 2\n            # Check correct performative\n            enforce(\n                isinstance(self.performative, PrometheusMessage.Performative),\n                \"Invalid 'performative'. Expected either of '{}'. Found '{}'.\".format(\n                    self.valid_performatives, self.performative\n                ),\n            )\n\n            # Check correct contents\n            actual_nb_of_contents = len(self._body) - DEFAULT_BODY_SIZE\n            expected_nb_of_contents = 0\n            if self.performative == PrometheusMessage.Performative.ADD_METRIC:\n                expected_nb_of_contents = 4\n                enforce(\n                    isinstance(self.type, str),\n                    \"Invalid type for content 'type'. Expected 'str'. Found '{}'.\".format(\n                        type(self.type)\n                    ),\n                )\n                enforce(\n                    isinstance(self.title, str),\n                    \"Invalid type for content 'title'. Expected 'str'. Found '{}'.\".format(\n                        type(self.title)\n                    ),\n                )\n                enforce(\n                    isinstance(self.description, str),\n                    \"Invalid type for content 'description'. Expected 'str'. Found '{}'.\".format(\n                        type(self.description)\n                    ),\n                )\n                enforce(\n                    isinstance(self.labels, dict),\n                    \"Invalid type for content 'labels'. Expected 'dict'. Found '{}'.\".format(\n                        type(self.labels)\n                    ),\n                )\n                for key_of_labels, value_of_labels in self.labels.items():\n                    enforce(\n                        isinstance(key_of_labels, str),\n                        \"Invalid type for dictionary keys in content 'labels'. Expected 'str'. Found '{}'.\".format(\n                            type(key_of_labels)\n                        ),\n                    )\n                    enforce(\n                        isinstance(value_of_labels, str),\n                        \"Invalid type for dictionary values in content 'labels'. Expected 'str'. Found '{}'.\".format(\n                            type(value_of_labels)\n                        ),\n                    )\n            elif self.performative == PrometheusMessage.Performative.UPDATE_METRIC:\n                expected_nb_of_contents = 4\n                enforce(\n                    isinstance(self.title, str),\n                    \"Invalid type for content 'title'. Expected 'str'. Found '{}'.\".format(\n                        type(self.title)\n                    ),\n                )\n                enforce(\n                    isinstance(self.callable, str),\n                    \"Invalid type for content 'callable'. Expected 'str'. Found '{}'.\".format(\n                        type(self.callable)\n                    ),\n                )\n                enforce(\n                    isinstance(self.value, float),\n                    \"Invalid type for content 'value'. Expected 'float'. Found '{}'.\".format(\n                        type(self.value)\n                    ),\n                )\n                enforce(\n                    isinstance(self.labels, dict),\n                    \"Invalid type for content 'labels'. Expected 'dict'. Found '{}'.\".format(\n                        type(self.labels)\n                    ),\n                )\n                for key_of_labels, value_of_labels in self.labels.items():\n                    enforce(\n                        isinstance(key_of_labels, str),\n                        \"Invalid type for dictionary keys in content 'labels'. Expected 'str'. Found '{}'.\".format(\n                            type(key_of_labels)\n                        ),\n                    )\n                    enforce(\n                        isinstance(value_of_labels, str),\n                        \"Invalid type for dictionary values in content 'labels'. Expected 'str'. Found '{}'.\".format(\n                            type(value_of_labels)\n                        ),\n                    )\n            elif self.performative == PrometheusMessage.Performative.RESPONSE:\n                expected_nb_of_contents = 1\n                enforce(\n                    type(self.code) is int,\n                    \"Invalid type for content 'code'. Expected 'int'. Found '{}'.\".format(\n                        type(self.code)\n                    ),\n                )\n                if self.is_set(\"message\"):\n                    expected_nb_of_contents += 1\n                    message = cast(str, self.message)\n                    enforce(\n                        isinstance(message, str),\n                        \"Invalid type for content 'message'. Expected 'str'. Found '{}'.\".format(\n                            type(message)\n                        ),\n                    )\n\n            # Check correct content count\n            enforce(\n                expected_nb_of_contents == actual_nb_of_contents,\n                \"Incorrect number of contents. Expected {}. Found {}\".format(\n                    expected_nb_of_contents, actual_nb_of_contents\n                ),\n            )\n\n            # Light Protocol Rule 3\n            if self.message_id == 1:\n                enforce(\n                    self.target == 0,\n                    \"Invalid 'target'. Expected 0 (because 'message_id' is 1). Found {}.\".format(\n                        self.target\n                    ),\n                )\n        except (AEAEnforceError, ValueError, KeyError) as e:\n            _default_logger.error(str(e))\n            return False\n\n        return True\n"
  },
  {
    "path": "packages/fetchai/protocols/prometheus/prometheus.proto",
    "content": "syntax = \"proto3\";\n\npackage aea.fetchai.prometheus.v1_0_0;\n\nmessage PrometheusMessage{\n\n  // Performatives and contents\n  message Add_Metric_Performative{\n    string type = 1;\n    string title = 2;\n    string description = 3;\n    map<string, string> labels = 4;\n  }\n\n  message Update_Metric_Performative{\n    string title = 1;\n    string callable = 2;\n    float value = 3;\n    map<string, string> labels = 4;\n  }\n\n  message Response_Performative{\n    int64 code = 1;\n    string message = 2;\n    bool message_is_set = 3;\n  }\n\n\n  oneof performative{\n    Add_Metric_Performative add_metric = 5;\n    Response_Performative response = 6;\n    Update_Metric_Performative update_metric = 7;\n  }\n}\n"
  },
  {
    "path": "packages/fetchai/protocols/prometheus/prometheus_pb2.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by the protocol buffer compiler.  DO NOT EDIT!\n# source: prometheus.proto\n\"\"\"Generated protocol buffer code.\"\"\"\nfrom google.protobuf import descriptor as _descriptor\nfrom google.protobuf import descriptor_pool as _descriptor_pool\nfrom google.protobuf import message as _message\nfrom google.protobuf import reflection as _reflection\nfrom google.protobuf import symbol_database as _symbol_database\n\n# @@protoc_insertion_point(imports)\n\n_sym_db = _symbol_database.Default()\n\n\nDESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(\n    b'\\n\\x10prometheus.proto\\x12\\x1d\\x61\\x65\\x61.fetchai.prometheus.v1_0_0\"\\xdf\\x06\\n\\x11PrometheusMessage\\x12^\\n\\nadd_metric\\x18\\x05 \\x01(\\x0b\\x32H.aea.fetchai.prometheus.v1_0_0.PrometheusMessage.Add_Metric_PerformativeH\\x00\\x12Z\\n\\x08response\\x18\\x06 \\x01(\\x0b\\x32\\x46.aea.fetchai.prometheus.v1_0_0.PrometheusMessage.Response_PerformativeH\\x00\\x12\\x64\\n\\rupdate_metric\\x18\\x07 \\x01(\\x0b\\x32K.aea.fetchai.prometheus.v1_0_0.PrometheusMessage.Update_Metric_PerformativeH\\x00\\x1a\\xe0\\x01\\n\\x17\\x41\\x64\\x64_Metric_Performative\\x12\\x0c\\n\\x04type\\x18\\x01 \\x01(\\t\\x12\\r\\n\\x05title\\x18\\x02 \\x01(\\t\\x12\\x13\\n\\x0b\\x64\\x65scription\\x18\\x03 \\x01(\\t\\x12\\x64\\n\\x06labels\\x18\\x04 \\x03(\\x0b\\x32T.aea.fetchai.prometheus.v1_0_0.PrometheusMessage.Add_Metric_Performative.LabelsEntry\\x1a-\\n\\x0bLabelsEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\t\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\t:\\x02\\x38\\x01\\x1a\\xe4\\x01\\n\\x1aUpdate_Metric_Performative\\x12\\r\\n\\x05title\\x18\\x01 \\x01(\\t\\x12\\x10\\n\\x08\\x63\\x61llable\\x18\\x02 \\x01(\\t\\x12\\r\\n\\x05value\\x18\\x03 \\x01(\\x02\\x12g\\n\\x06labels\\x18\\x04 \\x03(\\x0b\\x32W.aea.fetchai.prometheus.v1_0_0.PrometheusMessage.Update_Metric_Performative.LabelsEntry\\x1a-\\n\\x0bLabelsEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\t\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\t:\\x02\\x38\\x01\\x1aN\\n\\x15Response_Performative\\x12\\x0c\\n\\x04\\x63ode\\x18\\x01 \\x01(\\x03\\x12\\x0f\\n\\x07message\\x18\\x02 \\x01(\\t\\x12\\x16\\n\\x0emessage_is_set\\x18\\x03 \\x01(\\x08\\x42\\x0e\\n\\x0cperformativeb\\x06proto3'\n)\n\n\n_PROMETHEUSMESSAGE = DESCRIPTOR.message_types_by_name[\"PrometheusMessage\"]\n_PROMETHEUSMESSAGE_ADD_METRIC_PERFORMATIVE = _PROMETHEUSMESSAGE.nested_types_by_name[\n    \"Add_Metric_Performative\"\n]\n_PROMETHEUSMESSAGE_ADD_METRIC_PERFORMATIVE_LABELSENTRY = (\n    _PROMETHEUSMESSAGE_ADD_METRIC_PERFORMATIVE.nested_types_by_name[\"LabelsEntry\"]\n)\n_PROMETHEUSMESSAGE_UPDATE_METRIC_PERFORMATIVE = _PROMETHEUSMESSAGE.nested_types_by_name[\n    \"Update_Metric_Performative\"\n]\n_PROMETHEUSMESSAGE_UPDATE_METRIC_PERFORMATIVE_LABELSENTRY = (\n    _PROMETHEUSMESSAGE_UPDATE_METRIC_PERFORMATIVE.nested_types_by_name[\"LabelsEntry\"]\n)\n_PROMETHEUSMESSAGE_RESPONSE_PERFORMATIVE = _PROMETHEUSMESSAGE.nested_types_by_name[\n    \"Response_Performative\"\n]\nPrometheusMessage = _reflection.GeneratedProtocolMessageType(\n    \"PrometheusMessage\",\n    (_message.Message,),\n    {\n        \"Add_Metric_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Add_Metric_Performative\",\n            (_message.Message,),\n            {\n                \"LabelsEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"LabelsEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _PROMETHEUSMESSAGE_ADD_METRIC_PERFORMATIVE_LABELSENTRY,\n                        \"__module__\": \"prometheus_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.fetchai.prometheus.v1_0_0.PrometheusMessage.Add_Metric_Performative.LabelsEntry)\n                    },\n                ),\n                \"DESCRIPTOR\": _PROMETHEUSMESSAGE_ADD_METRIC_PERFORMATIVE,\n                \"__module__\": \"prometheus_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.prometheus.v1_0_0.PrometheusMessage.Add_Metric_Performative)\n            },\n        ),\n        \"Update_Metric_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Update_Metric_Performative\",\n            (_message.Message,),\n            {\n                \"LabelsEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"LabelsEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _PROMETHEUSMESSAGE_UPDATE_METRIC_PERFORMATIVE_LABELSENTRY,\n                        \"__module__\": \"prometheus_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.fetchai.prometheus.v1_0_0.PrometheusMessage.Update_Metric_Performative.LabelsEntry)\n                    },\n                ),\n                \"DESCRIPTOR\": _PROMETHEUSMESSAGE_UPDATE_METRIC_PERFORMATIVE,\n                \"__module__\": \"prometheus_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.prometheus.v1_0_0.PrometheusMessage.Update_Metric_Performative)\n            },\n        ),\n        \"Response_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Response_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _PROMETHEUSMESSAGE_RESPONSE_PERFORMATIVE,\n                \"__module__\": \"prometheus_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.prometheus.v1_0_0.PrometheusMessage.Response_Performative)\n            },\n        ),\n        \"DESCRIPTOR\": _PROMETHEUSMESSAGE,\n        \"__module__\": \"prometheus_pb2\"\n        # @@protoc_insertion_point(class_scope:aea.fetchai.prometheus.v1_0_0.PrometheusMessage)\n    },\n)\n_sym_db.RegisterMessage(PrometheusMessage)\n_sym_db.RegisterMessage(PrometheusMessage.Add_Metric_Performative)\n_sym_db.RegisterMessage(PrometheusMessage.Add_Metric_Performative.LabelsEntry)\n_sym_db.RegisterMessage(PrometheusMessage.Update_Metric_Performative)\n_sym_db.RegisterMessage(PrometheusMessage.Update_Metric_Performative.LabelsEntry)\n_sym_db.RegisterMessage(PrometheusMessage.Response_Performative)\n\nif _descriptor._USE_C_DESCRIPTORS == False:\n\n    DESCRIPTOR._options = None\n    _PROMETHEUSMESSAGE_ADD_METRIC_PERFORMATIVE_LABELSENTRY._options = None\n    _PROMETHEUSMESSAGE_ADD_METRIC_PERFORMATIVE_LABELSENTRY._serialized_options = (\n        b\"8\\001\"\n    )\n    _PROMETHEUSMESSAGE_UPDATE_METRIC_PERFORMATIVE_LABELSENTRY._options = None\n    _PROMETHEUSMESSAGE_UPDATE_METRIC_PERFORMATIVE_LABELSENTRY._serialized_options = (\n        b\"8\\001\"\n    )\n    _PROMETHEUSMESSAGE._serialized_start = 52\n    _PROMETHEUSMESSAGE._serialized_end = 915\n    _PROMETHEUSMESSAGE_ADD_METRIC_PERFORMATIVE._serialized_start = 364\n    _PROMETHEUSMESSAGE_ADD_METRIC_PERFORMATIVE._serialized_end = 588\n    _PROMETHEUSMESSAGE_ADD_METRIC_PERFORMATIVE_LABELSENTRY._serialized_start = 543\n    _PROMETHEUSMESSAGE_ADD_METRIC_PERFORMATIVE_LABELSENTRY._serialized_end = 588\n    _PROMETHEUSMESSAGE_UPDATE_METRIC_PERFORMATIVE._serialized_start = 591\n    _PROMETHEUSMESSAGE_UPDATE_METRIC_PERFORMATIVE._serialized_end = 819\n    _PROMETHEUSMESSAGE_UPDATE_METRIC_PERFORMATIVE_LABELSENTRY._serialized_start = 543\n    _PROMETHEUSMESSAGE_UPDATE_METRIC_PERFORMATIVE_LABELSENTRY._serialized_end = 588\n    _PROMETHEUSMESSAGE_RESPONSE_PERFORMATIVE._serialized_start = 821\n    _PROMETHEUSMESSAGE_RESPONSE_PERFORMATIVE._serialized_end = 899\n# @@protoc_insertion_point(module_scope)\n"
  },
  {
    "path": "packages/fetchai/protocols/prometheus/protocol.yaml",
    "content": "name: prometheus\nauthor: fetchai\nversion: 1.1.7\nprotocol_specification_id: fetchai/prometheus:1.0.0\ntype: protocol\ndescription: A protocol for adding and updating metrics to a prometheus server.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: QmQXXjGuq8W29ZJSSRrVyFHEn943hdoiWzQBvtwUufN1eH\n  __init__.py: QmTa48qrS3hbw1t1VEXieZ5pRpCTpR2gRWY92ecNyfRtFy\n  dialogues.py: QmNwiRofM3HPmxs3SSEsr8ZHuyXEPJVkYTApMSgczisZ9H\n  message.py: QmPbTxtc4ctk5h8Yk3KCkT2uHpezsmgLYkjCPQDNAxm8x1\n  prometheus.proto: QmXzFWmrWVqQuxtVgaZwuMgbrEvSRrRVU63htURUsFJ1wv\n  prometheus_pb2.py: QmNuDYT7RWNRmRKSMgsLqD76gmmNSNm88uTCSPcvoxTdHr\n  serialization.py: Qmf7WvXADqkDpQbjD6nZ3n7iKg5jsiqGTR91AWRqSKhiAq\nfingerprint_ignore_patterns: []\ndependencies:\n  protobuf: {}\n"
  },
  {
    "path": "packages/fetchai/protocols/prometheus/serialization.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Serialization module for prometheus protocol.\"\"\"\n\n# pylint: disable=too-many-statements,too-many-locals,no-member,too-few-public-methods,redefined-builtin\nfrom typing import Any, Dict, cast\n\nfrom aea.mail.base_pb2 import DialogueMessage\nfrom aea.mail.base_pb2 import Message as ProtobufMessage\nfrom aea.protocols.base import Message, Serializer\n\nfrom packages.fetchai.protocols.prometheus import prometheus_pb2\nfrom packages.fetchai.protocols.prometheus.message import PrometheusMessage\n\n\nclass PrometheusSerializer(Serializer):\n    \"\"\"Serialization for the 'prometheus' protocol.\"\"\"\n\n    @staticmethod\n    def encode(msg: Message) -> bytes:\n        \"\"\"\n        Encode a 'Prometheus' message into bytes.\n\n        :param msg: the message object.\n        :return: the bytes.\n        \"\"\"\n        msg = cast(PrometheusMessage, msg)\n        message_pb = ProtobufMessage()\n        dialogue_message_pb = DialogueMessage()\n        prometheus_msg = prometheus_pb2.PrometheusMessage()\n\n        dialogue_message_pb.message_id = msg.message_id\n        dialogue_reference = msg.dialogue_reference\n        dialogue_message_pb.dialogue_starter_reference = dialogue_reference[0]\n        dialogue_message_pb.dialogue_responder_reference = dialogue_reference[1]\n        dialogue_message_pb.target = msg.target\n\n        performative_id = msg.performative\n        if performative_id == PrometheusMessage.Performative.ADD_METRIC:\n            performative = prometheus_pb2.PrometheusMessage.Add_Metric_Performative()  # type: ignore\n            type = msg.type\n            performative.type = type\n            title = msg.title\n            performative.title = title\n            description = msg.description\n            performative.description = description\n            labels = msg.labels\n            performative.labels.update(labels)\n            prometheus_msg.add_metric.CopyFrom(performative)\n        elif performative_id == PrometheusMessage.Performative.UPDATE_METRIC:\n            performative = prometheus_pb2.PrometheusMessage.Update_Metric_Performative()  # type: ignore\n            title = msg.title\n            performative.title = title\n            callable = msg.callable\n            performative.callable = callable\n            value = msg.value\n            performative.value = value\n            labels = msg.labels\n            performative.labels.update(labels)\n            prometheus_msg.update_metric.CopyFrom(performative)\n        elif performative_id == PrometheusMessage.Performative.RESPONSE:\n            performative = prometheus_pb2.PrometheusMessage.Response_Performative()  # type: ignore\n            code = msg.code\n            performative.code = code\n            if msg.is_set(\"message\"):\n                performative.message_is_set = True\n                message = msg.message\n                performative.message = message\n            prometheus_msg.response.CopyFrom(performative)\n        else:\n            raise ValueError(\"Performative not valid: {}\".format(performative_id))\n\n        dialogue_message_pb.content = prometheus_msg.SerializeToString()\n\n        message_pb.dialogue_message.CopyFrom(dialogue_message_pb)\n        message_bytes = message_pb.SerializeToString()\n        return message_bytes\n\n    @staticmethod\n    def decode(obj: bytes) -> Message:\n        \"\"\"\n        Decode bytes into a 'Prometheus' message.\n\n        :param obj: the bytes object.\n        :return: the 'Prometheus' message.\n        \"\"\"\n        message_pb = ProtobufMessage()\n        prometheus_pb = prometheus_pb2.PrometheusMessage()\n        message_pb.ParseFromString(obj)\n        message_id = message_pb.dialogue_message.message_id\n        dialogue_reference = (\n            message_pb.dialogue_message.dialogue_starter_reference,\n            message_pb.dialogue_message.dialogue_responder_reference,\n        )\n        target = message_pb.dialogue_message.target\n\n        prometheus_pb.ParseFromString(message_pb.dialogue_message.content)\n        performative = prometheus_pb.WhichOneof(\"performative\")\n        performative_id = PrometheusMessage.Performative(str(performative))\n        performative_content = {}  # type: Dict[str, Any]\n        if performative_id == PrometheusMessage.Performative.ADD_METRIC:\n            type = prometheus_pb.add_metric.type\n            performative_content[\"type\"] = type\n            title = prometheus_pb.add_metric.title\n            performative_content[\"title\"] = title\n            description = prometheus_pb.add_metric.description\n            performative_content[\"description\"] = description\n            labels = prometheus_pb.add_metric.labels\n            labels_dict = dict(labels)\n            performative_content[\"labels\"] = labels_dict\n        elif performative_id == PrometheusMessage.Performative.UPDATE_METRIC:\n            title = prometheus_pb.update_metric.title\n            performative_content[\"title\"] = title\n            callable = prometheus_pb.update_metric.callable\n            performative_content[\"callable\"] = callable\n            value = prometheus_pb.update_metric.value\n            performative_content[\"value\"] = value\n            labels = prometheus_pb.update_metric.labels\n            labels_dict = dict(labels)\n            performative_content[\"labels\"] = labels_dict\n        elif performative_id == PrometheusMessage.Performative.RESPONSE:\n            code = prometheus_pb.response.code\n            performative_content[\"code\"] = code\n            if prometheus_pb.response.message_is_set:\n                message = prometheus_pb.response.message\n                performative_content[\"message\"] = message\n        else:\n            raise ValueError(\"Performative not valid: {}.\".format(performative_id))\n\n        return PrometheusMessage(\n            message_id=message_id,\n            dialogue_reference=dialogue_reference,\n            target=target,\n            performative=performative,\n            **performative_content\n        )\n"
  },
  {
    "path": "packages/fetchai/protocols/register/README.md",
    "content": "# Register Protocol\n\n## Description\n\nThis is a protocol for communication between two AEAs for registration.\n\n## Specification\n\n```yaml\n---\nname: register\nauthor: fetchai\nversion: 1.1.7\ndescription: A protocol for communication between two AEAs for registration.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nprotocol_specification_id: fetchai/register:1.0.0\nspeech_acts:\n  register:\n    info: pt:dict[pt:str, pt:str]\n  success:\n    info: pt:dict[pt:str, pt:str]\n  error:\n    error_code: pt:int\n    error_msg: pt:str\n    info: pt:dict[pt:str, pt:str]\n...\n---\ninitiation: [register]\nreply:\n  register: [success, error]\n  success: []\n  error: []\ntermination: [success, error]\nroles: {agent}\nend_states: [successful, failed]\nkeep_terminal_state_dialogues: true\n...\n```\n\n## Links\n"
  },
  {
    "path": "packages/fetchai/protocols/register/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nThis module contains the support resources for the register protocol.\n\nIt was created with protocol buffer compiler version `libprotoc 3.19.4` and aea version `1.2.5`.\n\"\"\"\n\nfrom packages.fetchai.protocols.register.message import RegisterMessage\nfrom packages.fetchai.protocols.register.serialization import RegisterSerializer\n\n\nRegisterMessage.serializer = RegisterSerializer\n"
  },
  {
    "path": "packages/fetchai/protocols/register/dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nThis module contains the classes required for register dialogue management.\n\n- RegisterDialogue: The dialogue class maintains state of a dialogue and manages it.\n- RegisterDialogues: The dialogues class keeps track of all dialogues.\n\"\"\"\n\nfrom abc import ABC\nfrom typing import Callable, Dict, FrozenSet, Type, cast\n\nfrom aea.common import Address\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue, DialogueLabel, Dialogues\n\nfrom packages.fetchai.protocols.register.message import RegisterMessage\n\n\nclass RegisterDialogue(Dialogue):\n    \"\"\"The register dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    INITIAL_PERFORMATIVES: FrozenSet[Message.Performative] = frozenset(\n        {RegisterMessage.Performative.REGISTER}\n    )\n    TERMINAL_PERFORMATIVES: FrozenSet[Message.Performative] = frozenset(\n        {RegisterMessage.Performative.SUCCESS, RegisterMessage.Performative.ERROR}\n    )\n    VALID_REPLIES: Dict[Message.Performative, FrozenSet[Message.Performative]] = {\n        RegisterMessage.Performative.ERROR: frozenset(),\n        RegisterMessage.Performative.REGISTER: frozenset(\n            {RegisterMessage.Performative.SUCCESS, RegisterMessage.Performative.ERROR}\n        ),\n        RegisterMessage.Performative.SUCCESS: frozenset(),\n    }\n\n    class Role(Dialogue.Role):\n        \"\"\"This class defines the agent's role in a register dialogue.\"\"\"\n\n        AGENT = \"agent\"\n\n    class EndState(Dialogue.EndState):\n        \"\"\"This class defines the end states of a register dialogue.\"\"\"\n\n        SUCCESSFUL = 0\n        FAILED = 1\n\n    def __init__(\n        self,\n        dialogue_label: DialogueLabel,\n        self_address: Address,\n        role: Dialogue.Role,\n        message_class: Type[RegisterMessage] = RegisterMessage,\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n        :param message_class: the message class used\n        \"\"\"\n        Dialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            message_class=message_class,\n            self_address=self_address,\n            role=role,\n        )\n\n\nclass RegisterDialogues(Dialogues, ABC):\n    \"\"\"This class keeps track of all register dialogues.\"\"\"\n\n    END_STATES = frozenset(\n        {RegisterDialogue.EndState.SUCCESSFUL, RegisterDialogue.EndState.FAILED}\n    )\n\n    _keep_terminal_state_dialogues = True\n\n    def __init__(\n        self,\n        self_address: Address,\n        role_from_first_message: Callable[[Message, Address], Dialogue.Role],\n        dialogue_class: Type[RegisterDialogue] = RegisterDialogue,\n    ) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param self_address: the address of the entity for whom dialogues are maintained\n        :param dialogue_class: the dialogue class used\n        :param role_from_first_message: the callable determining role from first message\n        \"\"\"\n        Dialogues.__init__(\n            self,\n            self_address=self_address,\n            end_states=cast(FrozenSet[Dialogue.EndState], self.END_STATES),\n            message_class=RegisterMessage,\n            dialogue_class=dialogue_class,\n            role_from_first_message=role_from_first_message,\n        )\n"
  },
  {
    "path": "packages/fetchai/protocols/register/message.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains register's message definition.\"\"\"\n\n# pylint: disable=too-many-statements,too-many-locals,no-member,too-few-public-methods,too-many-branches,not-an-iterable,unidiomatic-typecheck,unsubscriptable-object\nimport logging\nfrom typing import Any, Dict, Set, Tuple, cast\n\nfrom aea.configurations.base import PublicId\nfrom aea.exceptions import AEAEnforceError, enforce\nfrom aea.protocols.base import Message\n\n\n_default_logger = logging.getLogger(\"aea.packages.fetchai.protocols.register.message\")\n\nDEFAULT_BODY_SIZE = 4\n\n\nclass RegisterMessage(Message):\n    \"\"\"A protocol for communication between two AEAs for registration.\"\"\"\n\n    protocol_id = PublicId.from_str(\"fetchai/register:1.1.7\")\n    protocol_specification_id = PublicId.from_str(\"fetchai/register:1.0.0\")\n\n    class Performative(Message.Performative):\n        \"\"\"Performatives for the register protocol.\"\"\"\n\n        ERROR = \"error\"\n        REGISTER = \"register\"\n        SUCCESS = \"success\"\n\n        def __str__(self) -> str:\n            \"\"\"Get the string representation.\"\"\"\n            return str(self.value)\n\n    _performatives = {\"error\", \"register\", \"success\"}\n    __slots__: Tuple[str, ...] = tuple()\n\n    class _SlotsCls:\n        __slots__ = (\n            \"dialogue_reference\",\n            \"error_code\",\n            \"error_msg\",\n            \"info\",\n            \"message_id\",\n            \"performative\",\n            \"target\",\n        )\n\n    def __init__(\n        self,\n        performative: Performative,\n        dialogue_reference: Tuple[str, str] = (\"\", \"\"),\n        message_id: int = 1,\n        target: int = 0,\n        **kwargs: Any,\n    ):\n        \"\"\"\n        Initialise an instance of RegisterMessage.\n\n        :param message_id: the message id.\n        :param dialogue_reference: the dialogue reference.\n        :param target: the message target.\n        :param performative: the message performative.\n        :param **kwargs: extra options.\n        \"\"\"\n        super().__init__(\n            dialogue_reference=dialogue_reference,\n            message_id=message_id,\n            target=target,\n            performative=RegisterMessage.Performative(performative),\n            **kwargs,\n        )\n\n    @property\n    def valid_performatives(self) -> Set[str]:\n        \"\"\"Get valid performatives.\"\"\"\n        return self._performatives\n\n    @property\n    def dialogue_reference(self) -> Tuple[str, str]:\n        \"\"\"Get the dialogue_reference of the message.\"\"\"\n        enforce(self.is_set(\"dialogue_reference\"), \"dialogue_reference is not set.\")\n        return cast(Tuple[str, str], self.get(\"dialogue_reference\"))\n\n    @property\n    def message_id(self) -> int:\n        \"\"\"Get the message_id of the message.\"\"\"\n        enforce(self.is_set(\"message_id\"), \"message_id is not set.\")\n        return cast(int, self.get(\"message_id\"))\n\n    @property\n    def performative(self) -> Performative:  # type: ignore # noqa: F821\n        \"\"\"Get the performative of the message.\"\"\"\n        enforce(self.is_set(\"performative\"), \"performative is not set.\")\n        return cast(RegisterMessage.Performative, self.get(\"performative\"))\n\n    @property\n    def target(self) -> int:\n        \"\"\"Get the target of the message.\"\"\"\n        enforce(self.is_set(\"target\"), \"target is not set.\")\n        return cast(int, self.get(\"target\"))\n\n    @property\n    def error_code(self) -> int:\n        \"\"\"Get the 'error_code' content from the message.\"\"\"\n        enforce(self.is_set(\"error_code\"), \"'error_code' content is not set.\")\n        return cast(int, self.get(\"error_code\"))\n\n    @property\n    def error_msg(self) -> str:\n        \"\"\"Get the 'error_msg' content from the message.\"\"\"\n        enforce(self.is_set(\"error_msg\"), \"'error_msg' content is not set.\")\n        return cast(str, self.get(\"error_msg\"))\n\n    @property\n    def info(self) -> Dict[str, str]:\n        \"\"\"Get the 'info' content from the message.\"\"\"\n        enforce(self.is_set(\"info\"), \"'info' content is not set.\")\n        return cast(Dict[str, str], self.get(\"info\"))\n\n    def _is_consistent(self) -> bool:\n        \"\"\"Check that the message follows the register protocol.\"\"\"\n        try:\n            enforce(\n                isinstance(self.dialogue_reference, tuple),\n                \"Invalid type for 'dialogue_reference'. Expected 'tuple'. Found '{}'.\".format(\n                    type(self.dialogue_reference)\n                ),\n            )\n            enforce(\n                isinstance(self.dialogue_reference[0], str),\n                \"Invalid type for 'dialogue_reference[0]'. Expected 'str'. Found '{}'.\".format(\n                    type(self.dialogue_reference[0])\n                ),\n            )\n            enforce(\n                isinstance(self.dialogue_reference[1], str),\n                \"Invalid type for 'dialogue_reference[1]'. Expected 'str'. Found '{}'.\".format(\n                    type(self.dialogue_reference[1])\n                ),\n            )\n            enforce(\n                type(self.message_id) is int,\n                \"Invalid type for 'message_id'. Expected 'int'. Found '{}'.\".format(\n                    type(self.message_id)\n                ),\n            )\n            enforce(\n                type(self.target) is int,\n                \"Invalid type for 'target'. Expected 'int'. Found '{}'.\".format(\n                    type(self.target)\n                ),\n            )\n\n            # Light Protocol Rule 2\n            # Check correct performative\n            enforce(\n                isinstance(self.performative, RegisterMessage.Performative),\n                \"Invalid 'performative'. Expected either of '{}'. Found '{}'.\".format(\n                    self.valid_performatives, self.performative\n                ),\n            )\n\n            # Check correct contents\n            actual_nb_of_contents = len(self._body) - DEFAULT_BODY_SIZE\n            expected_nb_of_contents = 0\n            if self.performative == RegisterMessage.Performative.REGISTER:\n                expected_nb_of_contents = 1\n                enforce(\n                    isinstance(self.info, dict),\n                    \"Invalid type for content 'info'. Expected 'dict'. Found '{}'.\".format(\n                        type(self.info)\n                    ),\n                )\n                for key_of_info, value_of_info in self.info.items():\n                    enforce(\n                        isinstance(key_of_info, str),\n                        \"Invalid type for dictionary keys in content 'info'. Expected 'str'. Found '{}'.\".format(\n                            type(key_of_info)\n                        ),\n                    )\n                    enforce(\n                        isinstance(value_of_info, str),\n                        \"Invalid type for dictionary values in content 'info'. Expected 'str'. Found '{}'.\".format(\n                            type(value_of_info)\n                        ),\n                    )\n            elif self.performative == RegisterMessage.Performative.SUCCESS:\n                expected_nb_of_contents = 1\n                enforce(\n                    isinstance(self.info, dict),\n                    \"Invalid type for content 'info'. Expected 'dict'. Found '{}'.\".format(\n                        type(self.info)\n                    ),\n                )\n                for key_of_info, value_of_info in self.info.items():\n                    enforce(\n                        isinstance(key_of_info, str),\n                        \"Invalid type for dictionary keys in content 'info'. Expected 'str'. Found '{}'.\".format(\n                            type(key_of_info)\n                        ),\n                    )\n                    enforce(\n                        isinstance(value_of_info, str),\n                        \"Invalid type for dictionary values in content 'info'. Expected 'str'. Found '{}'.\".format(\n                            type(value_of_info)\n                        ),\n                    )\n            elif self.performative == RegisterMessage.Performative.ERROR:\n                expected_nb_of_contents = 3\n                enforce(\n                    type(self.error_code) is int,\n                    \"Invalid type for content 'error_code'. Expected 'int'. Found '{}'.\".format(\n                        type(self.error_code)\n                    ),\n                )\n                enforce(\n                    isinstance(self.error_msg, str),\n                    \"Invalid type for content 'error_msg'. Expected 'str'. Found '{}'.\".format(\n                        type(self.error_msg)\n                    ),\n                )\n                enforce(\n                    isinstance(self.info, dict),\n                    \"Invalid type for content 'info'. Expected 'dict'. Found '{}'.\".format(\n                        type(self.info)\n                    ),\n                )\n                for key_of_info, value_of_info in self.info.items():\n                    enforce(\n                        isinstance(key_of_info, str),\n                        \"Invalid type for dictionary keys in content 'info'. Expected 'str'. Found '{}'.\".format(\n                            type(key_of_info)\n                        ),\n                    )\n                    enforce(\n                        isinstance(value_of_info, str),\n                        \"Invalid type for dictionary values in content 'info'. Expected 'str'. Found '{}'.\".format(\n                            type(value_of_info)\n                        ),\n                    )\n\n            # Check correct content count\n            enforce(\n                expected_nb_of_contents == actual_nb_of_contents,\n                \"Incorrect number of contents. Expected {}. Found {}\".format(\n                    expected_nb_of_contents, actual_nb_of_contents\n                ),\n            )\n\n            # Light Protocol Rule 3\n            if self.message_id == 1:\n                enforce(\n                    self.target == 0,\n                    \"Invalid 'target'. Expected 0 (because 'message_id' is 1). Found {}.\".format(\n                        self.target\n                    ),\n                )\n        except (AEAEnforceError, ValueError, KeyError) as e:\n            _default_logger.error(str(e))\n            return False\n\n        return True\n"
  },
  {
    "path": "packages/fetchai/protocols/register/protocol.yaml",
    "content": "name: register\nauthor: fetchai\nversion: 1.1.7\nprotocol_specification_id: fetchai/register:1.0.0\ntype: protocol\ndescription: A protocol for communication between two AEAs for registration.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: QmVrcrKFvVrTDLiYDMrcEeTrujcg7r1SXyRAa1H1FbWTLa\n  __init__.py: QmWc6YpAxjsvoQSqhzREAijdZyp1VLgsE5uyp9NXU3H8v1\n  dialogues.py: QmVgE32GY8hLMnZ7xeceBL4zUo9eGb6eD1f4Le6Rx7wnes\n  message.py: QmZwiWBzBF4PHj4j5A9WXYhkhKUTH96azMdVs3WRm26f46\n  register.proto: QmarDZqqxezQX3XLLxWigC32S5Aiu367XjHVMKCjXcpfeN\n  register_pb2.py: QmRisHAzYZK38NFaW4kfhYQx6VpTQnKN7hepxV83LgFW91\n  serialization.py: QmQQPj3hBPTBLJUFVdgvaev4ezxsFrm5G47uGfPpfvzywK\nfingerprint_ignore_patterns: []\ndependencies:\n  protobuf: {}\n"
  },
  {
    "path": "packages/fetchai/protocols/register/register.proto",
    "content": "syntax = \"proto3\";\n\npackage aea.fetchai.register.v1_0_0;\n\nmessage RegisterMessage{\n\n  // Performatives and contents\n  message Register_Performative{\n    map<string, string> info = 1;\n  }\n\n  message Success_Performative{\n    map<string, string> info = 1;\n  }\n\n  message Error_Performative{\n    int64 error_code = 1;\n    string error_msg = 2;\n    map<string, string> info = 3;\n  }\n\n\n  oneof performative{\n    Error_Performative error = 5;\n    Register_Performative register = 6;\n    Success_Performative success = 7;\n  }\n}\n"
  },
  {
    "path": "packages/fetchai/protocols/register/register_pb2.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by the protocol buffer compiler.  DO NOT EDIT!\n# source: register.proto\n\"\"\"Generated protocol buffer code.\"\"\"\nfrom google.protobuf import descriptor as _descriptor\nfrom google.protobuf import descriptor_pool as _descriptor_pool\nfrom google.protobuf import message as _message\nfrom google.protobuf import reflection as _reflection\nfrom google.protobuf import symbol_database as _symbol_database\n\n# @@protoc_insertion_point(imports)\n\n_sym_db = _symbol_database.Default()\n\n\nDESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(\n    b'\\n\\x0eregister.proto\\x12\\x1b\\x61\\x65\\x61.fetchai.register.v1_0_0\"\\xa9\\x06\\n\\x0fRegisterMessage\\x12P\\n\\x05\\x65rror\\x18\\x05 \\x01(\\x0b\\x32?.aea.fetchai.register.v1_0_0.RegisterMessage.Error_PerformativeH\\x00\\x12V\\n\\x08register\\x18\\x06 \\x01(\\x0b\\x32\\x42.aea.fetchai.register.v1_0_0.RegisterMessage.Register_PerformativeH\\x00\\x12T\\n\\x07success\\x18\\x07 \\x01(\\x0b\\x32\\x41.aea.fetchai.register.v1_0_0.RegisterMessage.Success_PerformativeH\\x00\\x1a\\xa0\\x01\\n\\x15Register_Performative\\x12Z\\n\\x04info\\x18\\x01 \\x03(\\x0b\\x32L.aea.fetchai.register.v1_0_0.RegisterMessage.Register_Performative.InfoEntry\\x1a+\\n\\tInfoEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\t\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\t:\\x02\\x38\\x01\\x1a\\x9e\\x01\\n\\x14Success_Performative\\x12Y\\n\\x04info\\x18\\x01 \\x03(\\x0b\\x32K.aea.fetchai.register.v1_0_0.RegisterMessage.Success_Performative.InfoEntry\\x1a+\\n\\tInfoEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\t\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\t:\\x02\\x38\\x01\\x1a\\xc1\\x01\\n\\x12\\x45rror_Performative\\x12\\x12\\n\\nerror_code\\x18\\x01 \\x01(\\x03\\x12\\x11\\n\\terror_msg\\x18\\x02 \\x01(\\t\\x12W\\n\\x04info\\x18\\x03 \\x03(\\x0b\\x32I.aea.fetchai.register.v1_0_0.RegisterMessage.Error_Performative.InfoEntry\\x1a+\\n\\tInfoEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\t\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\t:\\x02\\x38\\x01\\x42\\x0e\\n\\x0cperformativeb\\x06proto3'\n)\n\n\n_REGISTERMESSAGE = DESCRIPTOR.message_types_by_name[\"RegisterMessage\"]\n_REGISTERMESSAGE_REGISTER_PERFORMATIVE = _REGISTERMESSAGE.nested_types_by_name[\n    \"Register_Performative\"\n]\n_REGISTERMESSAGE_REGISTER_PERFORMATIVE_INFOENTRY = (\n    _REGISTERMESSAGE_REGISTER_PERFORMATIVE.nested_types_by_name[\"InfoEntry\"]\n)\n_REGISTERMESSAGE_SUCCESS_PERFORMATIVE = _REGISTERMESSAGE.nested_types_by_name[\n    \"Success_Performative\"\n]\n_REGISTERMESSAGE_SUCCESS_PERFORMATIVE_INFOENTRY = (\n    _REGISTERMESSAGE_SUCCESS_PERFORMATIVE.nested_types_by_name[\"InfoEntry\"]\n)\n_REGISTERMESSAGE_ERROR_PERFORMATIVE = _REGISTERMESSAGE.nested_types_by_name[\n    \"Error_Performative\"\n]\n_REGISTERMESSAGE_ERROR_PERFORMATIVE_INFOENTRY = (\n    _REGISTERMESSAGE_ERROR_PERFORMATIVE.nested_types_by_name[\"InfoEntry\"]\n)\nRegisterMessage = _reflection.GeneratedProtocolMessageType(\n    \"RegisterMessage\",\n    (_message.Message,),\n    {\n        \"Register_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Register_Performative\",\n            (_message.Message,),\n            {\n                \"InfoEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"InfoEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _REGISTERMESSAGE_REGISTER_PERFORMATIVE_INFOENTRY,\n                        \"__module__\": \"register_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.fetchai.register.v1_0_0.RegisterMessage.Register_Performative.InfoEntry)\n                    },\n                ),\n                \"DESCRIPTOR\": _REGISTERMESSAGE_REGISTER_PERFORMATIVE,\n                \"__module__\": \"register_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.register.v1_0_0.RegisterMessage.Register_Performative)\n            },\n        ),\n        \"Success_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Success_Performative\",\n            (_message.Message,),\n            {\n                \"InfoEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"InfoEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _REGISTERMESSAGE_SUCCESS_PERFORMATIVE_INFOENTRY,\n                        \"__module__\": \"register_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.fetchai.register.v1_0_0.RegisterMessage.Success_Performative.InfoEntry)\n                    },\n                ),\n                \"DESCRIPTOR\": _REGISTERMESSAGE_SUCCESS_PERFORMATIVE,\n                \"__module__\": \"register_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.register.v1_0_0.RegisterMessage.Success_Performative)\n            },\n        ),\n        \"Error_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Error_Performative\",\n            (_message.Message,),\n            {\n                \"InfoEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"InfoEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _REGISTERMESSAGE_ERROR_PERFORMATIVE_INFOENTRY,\n                        \"__module__\": \"register_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.fetchai.register.v1_0_0.RegisterMessage.Error_Performative.InfoEntry)\n                    },\n                ),\n                \"DESCRIPTOR\": _REGISTERMESSAGE_ERROR_PERFORMATIVE,\n                \"__module__\": \"register_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.register.v1_0_0.RegisterMessage.Error_Performative)\n            },\n        ),\n        \"DESCRIPTOR\": _REGISTERMESSAGE,\n        \"__module__\": \"register_pb2\"\n        # @@protoc_insertion_point(class_scope:aea.fetchai.register.v1_0_0.RegisterMessage)\n    },\n)\n_sym_db.RegisterMessage(RegisterMessage)\n_sym_db.RegisterMessage(RegisterMessage.Register_Performative)\n_sym_db.RegisterMessage(RegisterMessage.Register_Performative.InfoEntry)\n_sym_db.RegisterMessage(RegisterMessage.Success_Performative)\n_sym_db.RegisterMessage(RegisterMessage.Success_Performative.InfoEntry)\n_sym_db.RegisterMessage(RegisterMessage.Error_Performative)\n_sym_db.RegisterMessage(RegisterMessage.Error_Performative.InfoEntry)\n\nif _descriptor._USE_C_DESCRIPTORS == False:\n\n    DESCRIPTOR._options = None\n    _REGISTERMESSAGE_REGISTER_PERFORMATIVE_INFOENTRY._options = None\n    _REGISTERMESSAGE_REGISTER_PERFORMATIVE_INFOENTRY._serialized_options = b\"8\\001\"\n    _REGISTERMESSAGE_SUCCESS_PERFORMATIVE_INFOENTRY._options = None\n    _REGISTERMESSAGE_SUCCESS_PERFORMATIVE_INFOENTRY._serialized_options = b\"8\\001\"\n    _REGISTERMESSAGE_ERROR_PERFORMATIVE_INFOENTRY._options = None\n    _REGISTERMESSAGE_ERROR_PERFORMATIVE_INFOENTRY._serialized_options = b\"8\\001\"\n    _REGISTERMESSAGE._serialized_start = 48\n    _REGISTERMESSAGE._serialized_end = 857\n    _REGISTERMESSAGE_REGISTER_PERFORMATIVE._serialized_start = 324\n    _REGISTERMESSAGE_REGISTER_PERFORMATIVE._serialized_end = 484\n    _REGISTERMESSAGE_REGISTER_PERFORMATIVE_INFOENTRY._serialized_start = 441\n    _REGISTERMESSAGE_REGISTER_PERFORMATIVE_INFOENTRY._serialized_end = 484\n    _REGISTERMESSAGE_SUCCESS_PERFORMATIVE._serialized_start = 487\n    _REGISTERMESSAGE_SUCCESS_PERFORMATIVE._serialized_end = 645\n    _REGISTERMESSAGE_SUCCESS_PERFORMATIVE_INFOENTRY._serialized_start = 441\n    _REGISTERMESSAGE_SUCCESS_PERFORMATIVE_INFOENTRY._serialized_end = 484\n    _REGISTERMESSAGE_ERROR_PERFORMATIVE._serialized_start = 648\n    _REGISTERMESSAGE_ERROR_PERFORMATIVE._serialized_end = 841\n    _REGISTERMESSAGE_ERROR_PERFORMATIVE_INFOENTRY._serialized_start = 441\n    _REGISTERMESSAGE_ERROR_PERFORMATIVE_INFOENTRY._serialized_end = 484\n# @@protoc_insertion_point(module_scope)\n"
  },
  {
    "path": "packages/fetchai/protocols/register/serialization.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Serialization module for register protocol.\"\"\"\n\n# pylint: disable=too-many-statements,too-many-locals,no-member,too-few-public-methods,redefined-builtin\nfrom typing import Any, Dict, cast\n\nfrom aea.mail.base_pb2 import DialogueMessage\nfrom aea.mail.base_pb2 import Message as ProtobufMessage\nfrom aea.protocols.base import Message, Serializer\n\nfrom packages.fetchai.protocols.register import register_pb2\nfrom packages.fetchai.protocols.register.message import RegisterMessage\n\n\nclass RegisterSerializer(Serializer):\n    \"\"\"Serialization for the 'register' protocol.\"\"\"\n\n    @staticmethod\n    def encode(msg: Message) -> bytes:\n        \"\"\"\n        Encode a 'Register' message into bytes.\n\n        :param msg: the message object.\n        :return: the bytes.\n        \"\"\"\n        msg = cast(RegisterMessage, msg)\n        message_pb = ProtobufMessage()\n        dialogue_message_pb = DialogueMessage()\n        register_msg = register_pb2.RegisterMessage()\n\n        dialogue_message_pb.message_id = msg.message_id\n        dialogue_reference = msg.dialogue_reference\n        dialogue_message_pb.dialogue_starter_reference = dialogue_reference[0]\n        dialogue_message_pb.dialogue_responder_reference = dialogue_reference[1]\n        dialogue_message_pb.target = msg.target\n\n        performative_id = msg.performative\n        if performative_id == RegisterMessage.Performative.REGISTER:\n            performative = register_pb2.RegisterMessage.Register_Performative()  # type: ignore\n            info = msg.info\n            performative.info.update(info)\n            register_msg.register.CopyFrom(performative)\n        elif performative_id == RegisterMessage.Performative.SUCCESS:\n            performative = register_pb2.RegisterMessage.Success_Performative()  # type: ignore\n            info = msg.info\n            performative.info.update(info)\n            register_msg.success.CopyFrom(performative)\n        elif performative_id == RegisterMessage.Performative.ERROR:\n            performative = register_pb2.RegisterMessage.Error_Performative()  # type: ignore\n            error_code = msg.error_code\n            performative.error_code = error_code\n            error_msg = msg.error_msg\n            performative.error_msg = error_msg\n            info = msg.info\n            performative.info.update(info)\n            register_msg.error.CopyFrom(performative)\n        else:\n            raise ValueError(\"Performative not valid: {}\".format(performative_id))\n\n        dialogue_message_pb.content = register_msg.SerializeToString()\n\n        message_pb.dialogue_message.CopyFrom(dialogue_message_pb)\n        message_bytes = message_pb.SerializeToString()\n        return message_bytes\n\n    @staticmethod\n    def decode(obj: bytes) -> Message:\n        \"\"\"\n        Decode bytes into a 'Register' message.\n\n        :param obj: the bytes object.\n        :return: the 'Register' message.\n        \"\"\"\n        message_pb = ProtobufMessage()\n        register_pb = register_pb2.RegisterMessage()\n        message_pb.ParseFromString(obj)\n        message_id = message_pb.dialogue_message.message_id\n        dialogue_reference = (\n            message_pb.dialogue_message.dialogue_starter_reference,\n            message_pb.dialogue_message.dialogue_responder_reference,\n        )\n        target = message_pb.dialogue_message.target\n\n        register_pb.ParseFromString(message_pb.dialogue_message.content)\n        performative = register_pb.WhichOneof(\"performative\")\n        performative_id = RegisterMessage.Performative(str(performative))\n        performative_content = {}  # type: Dict[str, Any]\n        if performative_id == RegisterMessage.Performative.REGISTER:\n            info = register_pb.register.info\n            info_dict = dict(info)\n            performative_content[\"info\"] = info_dict\n        elif performative_id == RegisterMessage.Performative.SUCCESS:\n            info = register_pb.success.info\n            info_dict = dict(info)\n            performative_content[\"info\"] = info_dict\n        elif performative_id == RegisterMessage.Performative.ERROR:\n            error_code = register_pb.error.error_code\n            performative_content[\"error_code\"] = error_code\n            error_msg = register_pb.error.error_msg\n            performative_content[\"error_msg\"] = error_msg\n            info = register_pb.error.info\n            info_dict = dict(info)\n            performative_content[\"info\"] = info_dict\n        else:\n            raise ValueError(\"Performative not valid: {}.\".format(performative_id))\n\n        return RegisterMessage(\n            message_id=message_id,\n            dialogue_reference=dialogue_reference,\n            target=target,\n            performative=performative,\n            **performative_content\n        )\n"
  },
  {
    "path": "packages/fetchai/protocols/signing/README.md",
    "content": "# Signing Protocol\n\n## Description\n\nThis is a protocol for communication between a skill and a decision maker.\n\n## Specification\n\n```yaml\n---\nname: signing\nauthor: fetchai\nversion: 1.1.7\ndescription: A protocol for communication between skills and decision maker.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nprotocol_specification_id: fetchai/signing:1.0.0\nspeech_acts:\n  sign_transaction:\n    terms: ct:Terms\n    raw_transaction: ct:RawTransaction\n  sign_message:\n    terms: ct:Terms\n    raw_message: ct:RawMessage\n  signed_transaction:\n    signed_transaction: ct:SignedTransaction\n  signed_message:\n    signed_message: ct:SignedMessage\n  error:\n    error_code: ct:ErrorCode\n...\n---\nct:ErrorCode: |\n  enum ErrorCodeEnum {\n      UNSUCCESSFUL_MESSAGE_SIGNING = 0;\n      UNSUCCESSFUL_TRANSACTION_SIGNING = 1;\n    }\n  ErrorCodeEnum error_code = 1;\nct:RawMessage: |\n  bytes raw_message = 1;\nct:RawTransaction: |\n  bytes raw_transaction = 1;\nct:SignedMessage: |\n  bytes signed_message = 1;\nct:SignedTransaction: |\n  bytes signed_transaction = 1;\nct:Terms: |\n  bytes terms = 1;\n...\n---\ninitiation: [sign_transaction, sign_message]\nreply:\n  sign_transaction: [signed_transaction, error]\n  sign_message: [signed_message, error]\n  signed_transaction: []\n  signed_message: []\n  error: []\ntermination: [signed_transaction, signed_message, error]\nroles: {skill, decision_maker}\nend_states: [successful, failed]\nkeep_terminal_state_dialogues: false\n...\n```\n\n## Links\n"
  },
  {
    "path": "packages/fetchai/protocols/signing/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nThis module contains the support resources for the signing protocol.\n\nIt was created with protocol buffer compiler version `libprotoc 3.19.4` and aea version `1.2.5`.\n\"\"\"\n\nfrom packages.fetchai.protocols.signing.message import SigningMessage\nfrom packages.fetchai.protocols.signing.serialization import SigningSerializer\n\n\nSigningMessage.serializer = SigningSerializer\n"
  },
  {
    "path": "packages/fetchai/protocols/signing/custom_types.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains class representations corresponding to every custom type in the protocol specification.\"\"\"\n\nfrom enum import Enum\nfrom typing import Any\n\nfrom aea.helpers.transaction.base import RawMessage as BaseRawMessage\nfrom aea.helpers.transaction.base import RawTransaction as BaseRawTransaction\nfrom aea.helpers.transaction.base import SignedMessage as BaseSignedMessage\nfrom aea.helpers.transaction.base import SignedTransaction as BaseSignedTransaction\nfrom aea.helpers.transaction.base import Terms as BaseTerms\n\n\nclass ErrorCode(Enum):\n    \"\"\"This class represents an instance of ErrorCode.\"\"\"\n\n    UNSUCCESSFUL_MESSAGE_SIGNING = 0\n    UNSUCCESSFUL_TRANSACTION_SIGNING = 1\n\n    @staticmethod\n    def encode(error_code_protobuf_object: Any, error_code_object: \"ErrorCode\") -> None:\n        \"\"\"\n        Encode an instance of this class into the protocol buffer object.\n\n        The protocol buffer object in the error_code_protobuf_object argument is matched with the instance of this class in the 'error_code_object' argument.\n\n        :param error_code_protobuf_object: the protocol buffer object whose type corresponds with this class.\n        :param error_code_object: an instance of this class to be encoded in the protocol buffer object.\n        \"\"\"\n        error_code_protobuf_object.error_code = error_code_object.value\n\n    @classmethod\n    def decode(cls, error_code_protobuf_object: Any) -> \"ErrorCode\":\n        \"\"\"\n        Decode a protocol buffer object that corresponds with this class into an instance of this class.\n\n        A new instance of this class is created that matches the protocol buffer object in the 'error_code_protobuf_object' argument.\n\n        :param error_code_protobuf_object: the protocol buffer object whose type corresponds with this class.\n        :return: A new instance of this class that matches the protocol buffer object in the 'error_code_protobuf_object' argument.\n        \"\"\"\n        enum_value_from_pb2 = error_code_protobuf_object.error_code\n        return ErrorCode(enum_value_from_pb2)\n\n\nRawMessage = BaseRawMessage\nRawTransaction = BaseRawTransaction\nSignedMessage = BaseSignedMessage\nSignedTransaction = BaseSignedTransaction\nTerms = BaseTerms\n"
  },
  {
    "path": "packages/fetchai/protocols/signing/dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nThis module contains the classes required for signing dialogue management.\n\n- SigningDialogue: The dialogue class maintains state of a dialogue and manages it.\n- SigningDialogues: The dialogues class keeps track of all dialogues.\n\"\"\"\n\nfrom abc import ABC\nfrom typing import Callable, Dict, FrozenSet, Type, cast\n\nfrom aea.common import Address\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue, DialogueLabel, Dialogues\n\nfrom packages.fetchai.protocols.signing.message import SigningMessage\n\n\nclass SigningDialogue(Dialogue):\n    \"\"\"The signing dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    INITIAL_PERFORMATIVES: FrozenSet[Message.Performative] = frozenset(\n        {\n            SigningMessage.Performative.SIGN_TRANSACTION,\n            SigningMessage.Performative.SIGN_MESSAGE,\n        }\n    )\n    TERMINAL_PERFORMATIVES: FrozenSet[Message.Performative] = frozenset(\n        {\n            SigningMessage.Performative.SIGNED_TRANSACTION,\n            SigningMessage.Performative.SIGNED_MESSAGE,\n            SigningMessage.Performative.ERROR,\n        }\n    )\n    VALID_REPLIES: Dict[Message.Performative, FrozenSet[Message.Performative]] = {\n        SigningMessage.Performative.ERROR: frozenset(),\n        SigningMessage.Performative.SIGN_MESSAGE: frozenset(\n            {\n                SigningMessage.Performative.SIGNED_MESSAGE,\n                SigningMessage.Performative.ERROR,\n            }\n        ),\n        SigningMessage.Performative.SIGN_TRANSACTION: frozenset(\n            {\n                SigningMessage.Performative.SIGNED_TRANSACTION,\n                SigningMessage.Performative.ERROR,\n            }\n        ),\n        SigningMessage.Performative.SIGNED_MESSAGE: frozenset(),\n        SigningMessage.Performative.SIGNED_TRANSACTION: frozenset(),\n    }\n\n    class Role(Dialogue.Role):\n        \"\"\"This class defines the agent's role in a signing dialogue.\"\"\"\n\n        DECISION_MAKER = \"decision_maker\"\n        SKILL = \"skill\"\n\n    class EndState(Dialogue.EndState):\n        \"\"\"This class defines the end states of a signing dialogue.\"\"\"\n\n        SUCCESSFUL = 0\n        FAILED = 1\n\n    def __init__(\n        self,\n        dialogue_label: DialogueLabel,\n        self_address: Address,\n        role: Dialogue.Role,\n        message_class: Type[SigningMessage] = SigningMessage,\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n        :param message_class: the message class used\n        \"\"\"\n        Dialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            message_class=message_class,\n            self_address=self_address,\n            role=role,\n        )\n\n\nclass SigningDialogues(Dialogues, ABC):\n    \"\"\"This class keeps track of all signing dialogues.\"\"\"\n\n    END_STATES = frozenset(\n        {SigningDialogue.EndState.SUCCESSFUL, SigningDialogue.EndState.FAILED}\n    )\n\n    _keep_terminal_state_dialogues = False\n\n    def __init__(\n        self,\n        self_address: Address,\n        role_from_first_message: Callable[[Message, Address], Dialogue.Role],\n        dialogue_class: Type[SigningDialogue] = SigningDialogue,\n    ) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param self_address: the address of the entity for whom dialogues are maintained\n        :param dialogue_class: the dialogue class used\n        :param role_from_first_message: the callable determining role from first message\n        \"\"\"\n        Dialogues.__init__(\n            self,\n            self_address=self_address,\n            end_states=cast(FrozenSet[Dialogue.EndState], self.END_STATES),\n            message_class=SigningMessage,\n            dialogue_class=dialogue_class,\n            role_from_first_message=role_from_first_message,\n        )\n"
  },
  {
    "path": "packages/fetchai/protocols/signing/message.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains signing's message definition.\"\"\"\n\n# pylint: disable=too-many-statements,too-many-locals,no-member,too-few-public-methods,too-many-branches,not-an-iterable,unidiomatic-typecheck,unsubscriptable-object\nimport logging\nfrom typing import Any, Set, Tuple, cast\n\nfrom aea.configurations.base import PublicId\nfrom aea.exceptions import AEAEnforceError, enforce\nfrom aea.protocols.base import Message\n\nfrom packages.fetchai.protocols.signing.custom_types import ErrorCode as CustomErrorCode\nfrom packages.fetchai.protocols.signing.custom_types import (\n    RawMessage as CustomRawMessage,\n)\nfrom packages.fetchai.protocols.signing.custom_types import (\n    RawTransaction as CustomRawTransaction,\n)\nfrom packages.fetchai.protocols.signing.custom_types import (\n    SignedMessage as CustomSignedMessage,\n)\nfrom packages.fetchai.protocols.signing.custom_types import (\n    SignedTransaction as CustomSignedTransaction,\n)\nfrom packages.fetchai.protocols.signing.custom_types import Terms as CustomTerms\n\n\n_default_logger = logging.getLogger(\"aea.packages.fetchai.protocols.signing.message\")\n\nDEFAULT_BODY_SIZE = 4\n\n\nclass SigningMessage(Message):\n    \"\"\"A protocol for communication between skills and decision maker.\"\"\"\n\n    protocol_id = PublicId.from_str(\"fetchai/signing:1.1.7\")\n    protocol_specification_id = PublicId.from_str(\"fetchai/signing:1.0.0\")\n\n    ErrorCode = CustomErrorCode\n\n    RawMessage = CustomRawMessage\n\n    RawTransaction = CustomRawTransaction\n\n    SignedMessage = CustomSignedMessage\n\n    SignedTransaction = CustomSignedTransaction\n\n    Terms = CustomTerms\n\n    class Performative(Message.Performative):\n        \"\"\"Performatives for the signing protocol.\"\"\"\n\n        ERROR = \"error\"\n        SIGN_MESSAGE = \"sign_message\"\n        SIGN_TRANSACTION = \"sign_transaction\"\n        SIGNED_MESSAGE = \"signed_message\"\n        SIGNED_TRANSACTION = \"signed_transaction\"\n\n        def __str__(self) -> str:\n            \"\"\"Get the string representation.\"\"\"\n            return str(self.value)\n\n    _performatives = {\n        \"error\",\n        \"sign_message\",\n        \"sign_transaction\",\n        \"signed_message\",\n        \"signed_transaction\",\n    }\n    __slots__: Tuple[str, ...] = tuple()\n\n    class _SlotsCls:\n        __slots__ = (\n            \"dialogue_reference\",\n            \"error_code\",\n            \"message_id\",\n            \"performative\",\n            \"raw_message\",\n            \"raw_transaction\",\n            \"signed_message\",\n            \"signed_transaction\",\n            \"target\",\n            \"terms\",\n        )\n\n    def __init__(\n        self,\n        performative: Performative,\n        dialogue_reference: Tuple[str, str] = (\"\", \"\"),\n        message_id: int = 1,\n        target: int = 0,\n        **kwargs: Any,\n    ):\n        \"\"\"\n        Initialise an instance of SigningMessage.\n\n        :param message_id: the message id.\n        :param dialogue_reference: the dialogue reference.\n        :param target: the message target.\n        :param performative: the message performative.\n        :param **kwargs: extra options.\n        \"\"\"\n        super().__init__(\n            dialogue_reference=dialogue_reference,\n            message_id=message_id,\n            target=target,\n            performative=SigningMessage.Performative(performative),\n            **kwargs,\n        )\n\n    @property\n    def valid_performatives(self) -> Set[str]:\n        \"\"\"Get valid performatives.\"\"\"\n        return self._performatives\n\n    @property\n    def dialogue_reference(self) -> Tuple[str, str]:\n        \"\"\"Get the dialogue_reference of the message.\"\"\"\n        enforce(self.is_set(\"dialogue_reference\"), \"dialogue_reference is not set.\")\n        return cast(Tuple[str, str], self.get(\"dialogue_reference\"))\n\n    @property\n    def message_id(self) -> int:\n        \"\"\"Get the message_id of the message.\"\"\"\n        enforce(self.is_set(\"message_id\"), \"message_id is not set.\")\n        return cast(int, self.get(\"message_id\"))\n\n    @property\n    def performative(self) -> Performative:  # type: ignore # noqa: F821\n        \"\"\"Get the performative of the message.\"\"\"\n        enforce(self.is_set(\"performative\"), \"performative is not set.\")\n        return cast(SigningMessage.Performative, self.get(\"performative\"))\n\n    @property\n    def target(self) -> int:\n        \"\"\"Get the target of the message.\"\"\"\n        enforce(self.is_set(\"target\"), \"target is not set.\")\n        return cast(int, self.get(\"target\"))\n\n    @property\n    def error_code(self) -> CustomErrorCode:\n        \"\"\"Get the 'error_code' content from the message.\"\"\"\n        enforce(self.is_set(\"error_code\"), \"'error_code' content is not set.\")\n        return cast(CustomErrorCode, self.get(\"error_code\"))\n\n    @property\n    def raw_message(self) -> CustomRawMessage:\n        \"\"\"Get the 'raw_message' content from the message.\"\"\"\n        enforce(self.is_set(\"raw_message\"), \"'raw_message' content is not set.\")\n        return cast(CustomRawMessage, self.get(\"raw_message\"))\n\n    @property\n    def raw_transaction(self) -> CustomRawTransaction:\n        \"\"\"Get the 'raw_transaction' content from the message.\"\"\"\n        enforce(self.is_set(\"raw_transaction\"), \"'raw_transaction' content is not set.\")\n        return cast(CustomRawTransaction, self.get(\"raw_transaction\"))\n\n    @property\n    def signed_message(self) -> CustomSignedMessage:\n        \"\"\"Get the 'signed_message' content from the message.\"\"\"\n        enforce(self.is_set(\"signed_message\"), \"'signed_message' content is not set.\")\n        return cast(CustomSignedMessage, self.get(\"signed_message\"))\n\n    @property\n    def signed_transaction(self) -> CustomSignedTransaction:\n        \"\"\"Get the 'signed_transaction' content from the message.\"\"\"\n        enforce(\n            self.is_set(\"signed_transaction\"),\n            \"'signed_transaction' content is not set.\",\n        )\n        return cast(CustomSignedTransaction, self.get(\"signed_transaction\"))\n\n    @property\n    def terms(self) -> CustomTerms:\n        \"\"\"Get the 'terms' content from the message.\"\"\"\n        enforce(self.is_set(\"terms\"), \"'terms' content is not set.\")\n        return cast(CustomTerms, self.get(\"terms\"))\n\n    def _is_consistent(self) -> bool:\n        \"\"\"Check that the message follows the signing protocol.\"\"\"\n        try:\n            enforce(\n                isinstance(self.dialogue_reference, tuple),\n                \"Invalid type for 'dialogue_reference'. Expected 'tuple'. Found '{}'.\".format(\n                    type(self.dialogue_reference)\n                ),\n            )\n            enforce(\n                isinstance(self.dialogue_reference[0], str),\n                \"Invalid type for 'dialogue_reference[0]'. Expected 'str'. Found '{}'.\".format(\n                    type(self.dialogue_reference[0])\n                ),\n            )\n            enforce(\n                isinstance(self.dialogue_reference[1], str),\n                \"Invalid type for 'dialogue_reference[1]'. Expected 'str'. Found '{}'.\".format(\n                    type(self.dialogue_reference[1])\n                ),\n            )\n            enforce(\n                type(self.message_id) is int,\n                \"Invalid type for 'message_id'. Expected 'int'. Found '{}'.\".format(\n                    type(self.message_id)\n                ),\n            )\n            enforce(\n                type(self.target) is int,\n                \"Invalid type for 'target'. Expected 'int'. Found '{}'.\".format(\n                    type(self.target)\n                ),\n            )\n\n            # Light Protocol Rule 2\n            # Check correct performative\n            enforce(\n                isinstance(self.performative, SigningMessage.Performative),\n                \"Invalid 'performative'. Expected either of '{}'. Found '{}'.\".format(\n                    self.valid_performatives, self.performative\n                ),\n            )\n\n            # Check correct contents\n            actual_nb_of_contents = len(self._body) - DEFAULT_BODY_SIZE\n            expected_nb_of_contents = 0\n            if self.performative == SigningMessage.Performative.SIGN_TRANSACTION:\n                expected_nb_of_contents = 2\n                enforce(\n                    isinstance(self.terms, CustomTerms),\n                    \"Invalid type for content 'terms'. Expected 'Terms'. Found '{}'.\".format(\n                        type(self.terms)\n                    ),\n                )\n                enforce(\n                    isinstance(self.raw_transaction, CustomRawTransaction),\n                    \"Invalid type for content 'raw_transaction'. Expected 'RawTransaction'. Found '{}'.\".format(\n                        type(self.raw_transaction)\n                    ),\n                )\n            elif self.performative == SigningMessage.Performative.SIGN_MESSAGE:\n                expected_nb_of_contents = 2\n                enforce(\n                    isinstance(self.terms, CustomTerms),\n                    \"Invalid type for content 'terms'. Expected 'Terms'. Found '{}'.\".format(\n                        type(self.terms)\n                    ),\n                )\n                enforce(\n                    isinstance(self.raw_message, CustomRawMessage),\n                    \"Invalid type for content 'raw_message'. Expected 'RawMessage'. Found '{}'.\".format(\n                        type(self.raw_message)\n                    ),\n                )\n            elif self.performative == SigningMessage.Performative.SIGNED_TRANSACTION:\n                expected_nb_of_contents = 1\n                enforce(\n                    isinstance(self.signed_transaction, CustomSignedTransaction),\n                    \"Invalid type for content 'signed_transaction'. Expected 'SignedTransaction'. Found '{}'.\".format(\n                        type(self.signed_transaction)\n                    ),\n                )\n            elif self.performative == SigningMessage.Performative.SIGNED_MESSAGE:\n                expected_nb_of_contents = 1\n                enforce(\n                    isinstance(self.signed_message, CustomSignedMessage),\n                    \"Invalid type for content 'signed_message'. Expected 'SignedMessage'. Found '{}'.\".format(\n                        type(self.signed_message)\n                    ),\n                )\n            elif self.performative == SigningMessage.Performative.ERROR:\n                expected_nb_of_contents = 1\n                enforce(\n                    isinstance(self.error_code, CustomErrorCode),\n                    \"Invalid type for content 'error_code'. Expected 'ErrorCode'. Found '{}'.\".format(\n                        type(self.error_code)\n                    ),\n                )\n\n            # Check correct content count\n            enforce(\n                expected_nb_of_contents == actual_nb_of_contents,\n                \"Incorrect number of contents. Expected {}. Found {}\".format(\n                    expected_nb_of_contents, actual_nb_of_contents\n                ),\n            )\n\n            # Light Protocol Rule 3\n            if self.message_id == 1:\n                enforce(\n                    self.target == 0,\n                    \"Invalid 'target'. Expected 0 (because 'message_id' is 1). Found {}.\".format(\n                        self.target\n                    ),\n                )\n        except (AEAEnforceError, ValueError, KeyError) as e:\n            _default_logger.error(str(e))\n            return False\n\n        return True\n"
  },
  {
    "path": "packages/fetchai/protocols/signing/protocol.yaml",
    "content": "name: signing\nauthor: fetchai\nversion: 1.1.7\nprotocol_specification_id: fetchai/signing:1.0.0\ntype: protocol\ndescription: A protocol for communication between skills and decision maker.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: QmWWjq6ppoaiGG46yUQWbgrN78fF3iKcuk5Zn6L7pkVdtA\n  __init__.py: QmQwA8M3CvBeWabUAWUC6Mmt5bUgqQK8TAHt62JpZzsSt1\n  custom_types.py: QmbYjhUzvTMv6kU9UbuGLyVGfyurZPgX8PBGZGj58jDHv3\n  dialogues.py: QmQ9LyN1FamvMZ1o7Pt9H69bZZVY1Yxgm7HhyeN4fSXEUa\n  message.py: QmeugK5PynXtgXgRbvjVyQCBXWwVdvnQvNgWLYScqLhFn1\n  serialization.py: QmPeHDs5eXVApHLj6Xecc6jqBC8LDrmUJcKRgVYDNQ9W2q\n  signing.proto: QmbHQYswu1d5JTq8QD3WY9Trw7CwCFbv4c1wmgwiZC5756\n  signing_pb2.py: QmaYoSC2uxSATBzNY9utPp7J78drWgyYocr4cPjEhyLf7y\nfingerprint_ignore_patterns: []\ndependencies:\n  protobuf: {}\n"
  },
  {
    "path": "packages/fetchai/protocols/signing/serialization.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Serialization module for signing protocol.\"\"\"\n\n# pylint: disable=too-many-statements,too-many-locals,no-member,too-few-public-methods,redefined-builtin\nfrom typing import Any, Dict, cast\n\nfrom aea.mail.base_pb2 import DialogueMessage\nfrom aea.mail.base_pb2 import Message as ProtobufMessage\nfrom aea.protocols.base import Message, Serializer\n\nfrom packages.fetchai.protocols.signing import signing_pb2\nfrom packages.fetchai.protocols.signing.custom_types import (\n    ErrorCode,\n    RawMessage,\n    RawTransaction,\n    SignedMessage,\n    SignedTransaction,\n    Terms,\n)\nfrom packages.fetchai.protocols.signing.message import SigningMessage\n\n\nclass SigningSerializer(Serializer):\n    \"\"\"Serialization for the 'signing' protocol.\"\"\"\n\n    @staticmethod\n    def encode(msg: Message) -> bytes:\n        \"\"\"\n        Encode a 'Signing' message into bytes.\n\n        :param msg: the message object.\n        :return: the bytes.\n        \"\"\"\n        msg = cast(SigningMessage, msg)\n        message_pb = ProtobufMessage()\n        dialogue_message_pb = DialogueMessage()\n        signing_msg = signing_pb2.SigningMessage()\n\n        dialogue_message_pb.message_id = msg.message_id\n        dialogue_reference = msg.dialogue_reference\n        dialogue_message_pb.dialogue_starter_reference = dialogue_reference[0]\n        dialogue_message_pb.dialogue_responder_reference = dialogue_reference[1]\n        dialogue_message_pb.target = msg.target\n\n        performative_id = msg.performative\n        if performative_id == SigningMessage.Performative.SIGN_TRANSACTION:\n            performative = signing_pb2.SigningMessage.Sign_Transaction_Performative()  # type: ignore\n            terms = msg.terms\n            Terms.encode(performative.terms, terms)\n            raw_transaction = msg.raw_transaction\n            RawTransaction.encode(performative.raw_transaction, raw_transaction)\n            signing_msg.sign_transaction.CopyFrom(performative)\n        elif performative_id == SigningMessage.Performative.SIGN_MESSAGE:\n            performative = signing_pb2.SigningMessage.Sign_Message_Performative()  # type: ignore\n            terms = msg.terms\n            Terms.encode(performative.terms, terms)\n            raw_message = msg.raw_message\n            RawMessage.encode(performative.raw_message, raw_message)\n            signing_msg.sign_message.CopyFrom(performative)\n        elif performative_id == SigningMessage.Performative.SIGNED_TRANSACTION:\n            performative = signing_pb2.SigningMessage.Signed_Transaction_Performative()  # type: ignore\n            signed_transaction = msg.signed_transaction\n            SignedTransaction.encode(\n                performative.signed_transaction, signed_transaction\n            )\n            signing_msg.signed_transaction.CopyFrom(performative)\n        elif performative_id == SigningMessage.Performative.SIGNED_MESSAGE:\n            performative = signing_pb2.SigningMessage.Signed_Message_Performative()  # type: ignore\n            signed_message = msg.signed_message\n            SignedMessage.encode(performative.signed_message, signed_message)\n            signing_msg.signed_message.CopyFrom(performative)\n        elif performative_id == SigningMessage.Performative.ERROR:\n            performative = signing_pb2.SigningMessage.Error_Performative()  # type: ignore\n            error_code = msg.error_code\n            ErrorCode.encode(performative.error_code, error_code)\n            signing_msg.error.CopyFrom(performative)\n        else:\n            raise ValueError(\"Performative not valid: {}\".format(performative_id))\n\n        dialogue_message_pb.content = signing_msg.SerializeToString()\n\n        message_pb.dialogue_message.CopyFrom(dialogue_message_pb)\n        message_bytes = message_pb.SerializeToString()\n        return message_bytes\n\n    @staticmethod\n    def decode(obj: bytes) -> Message:\n        \"\"\"\n        Decode bytes into a 'Signing' message.\n\n        :param obj: the bytes object.\n        :return: the 'Signing' message.\n        \"\"\"\n        message_pb = ProtobufMessage()\n        signing_pb = signing_pb2.SigningMessage()\n        message_pb.ParseFromString(obj)\n        message_id = message_pb.dialogue_message.message_id\n        dialogue_reference = (\n            message_pb.dialogue_message.dialogue_starter_reference,\n            message_pb.dialogue_message.dialogue_responder_reference,\n        )\n        target = message_pb.dialogue_message.target\n\n        signing_pb.ParseFromString(message_pb.dialogue_message.content)\n        performative = signing_pb.WhichOneof(\"performative\")\n        performative_id = SigningMessage.Performative(str(performative))\n        performative_content = {}  # type: Dict[str, Any]\n        if performative_id == SigningMessage.Performative.SIGN_TRANSACTION:\n            pb2_terms = signing_pb.sign_transaction.terms\n            terms = Terms.decode(pb2_terms)\n            performative_content[\"terms\"] = terms\n            pb2_raw_transaction = signing_pb.sign_transaction.raw_transaction\n            raw_transaction = RawTransaction.decode(pb2_raw_transaction)\n            performative_content[\"raw_transaction\"] = raw_transaction\n        elif performative_id == SigningMessage.Performative.SIGN_MESSAGE:\n            pb2_terms = signing_pb.sign_message.terms\n            terms = Terms.decode(pb2_terms)\n            performative_content[\"terms\"] = terms\n            pb2_raw_message = signing_pb.sign_message.raw_message\n            raw_message = RawMessage.decode(pb2_raw_message)\n            performative_content[\"raw_message\"] = raw_message\n        elif performative_id == SigningMessage.Performative.SIGNED_TRANSACTION:\n            pb2_signed_transaction = signing_pb.signed_transaction.signed_transaction\n            signed_transaction = SignedTransaction.decode(pb2_signed_transaction)\n            performative_content[\"signed_transaction\"] = signed_transaction\n        elif performative_id == SigningMessage.Performative.SIGNED_MESSAGE:\n            pb2_signed_message = signing_pb.signed_message.signed_message\n            signed_message = SignedMessage.decode(pb2_signed_message)\n            performative_content[\"signed_message\"] = signed_message\n        elif performative_id == SigningMessage.Performative.ERROR:\n            pb2_error_code = signing_pb.error.error_code\n            error_code = ErrorCode.decode(pb2_error_code)\n            performative_content[\"error_code\"] = error_code\n        else:\n            raise ValueError(\"Performative not valid: {}.\".format(performative_id))\n\n        return SigningMessage(\n            message_id=message_id,\n            dialogue_reference=dialogue_reference,\n            target=target,\n            performative=performative,\n            **performative_content\n        )\n"
  },
  {
    "path": "packages/fetchai/protocols/signing/signing.proto",
    "content": "syntax = \"proto3\";\n\npackage aea.fetchai.signing.v1_0_0;\n\nmessage SigningMessage{\n\n  // Custom Types\n  message ErrorCode{\n    enum ErrorCodeEnum {\n      UNSUCCESSFUL_MESSAGE_SIGNING = 0;\n      UNSUCCESSFUL_TRANSACTION_SIGNING = 1;\n    }\n    ErrorCodeEnum error_code = 1;\n  }\n\n  message RawMessage{\n    bytes raw_message = 1;\n  }\n\n  message RawTransaction{\n    bytes raw_transaction = 1;\n  }\n\n  message SignedMessage{\n    bytes signed_message = 1;\n  }\n\n  message SignedTransaction{\n    bytes signed_transaction = 1;\n  }\n\n  message Terms{\n    bytes terms = 1;\n  }\n\n\n  // Performatives and contents\n  message Sign_Transaction_Performative{\n    Terms terms = 1;\n    RawTransaction raw_transaction = 2;\n  }\n\n  message Sign_Message_Performative{\n    Terms terms = 1;\n    RawMessage raw_message = 2;\n  }\n\n  message Signed_Transaction_Performative{\n    SignedTransaction signed_transaction = 1;\n  }\n\n  message Signed_Message_Performative{\n    SignedMessage signed_message = 1;\n  }\n\n  message Error_Performative{\n    ErrorCode error_code = 1;\n  }\n\n\n  oneof performative{\n    Error_Performative error = 5;\n    Sign_Message_Performative sign_message = 6;\n    Sign_Transaction_Performative sign_transaction = 7;\n    Signed_Message_Performative signed_message = 8;\n    Signed_Transaction_Performative signed_transaction = 9;\n  }\n}\n"
  },
  {
    "path": "packages/fetchai/protocols/signing/signing_pb2.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by the protocol buffer compiler.  DO NOT EDIT!\n# source: signing.proto\n\"\"\"Generated protocol buffer code.\"\"\"\nfrom google.protobuf import descriptor as _descriptor\nfrom google.protobuf import descriptor_pool as _descriptor_pool\nfrom google.protobuf import message as _message\nfrom google.protobuf import reflection as _reflection\nfrom google.protobuf import symbol_database as _symbol_database\n\n# @@protoc_insertion_point(imports)\n\n_sym_db = _symbol_database.Default()\n\n\nDESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(\n    b'\\n\\rsigning.proto\\x12\\x1a\\x61\\x65\\x61.fetchai.signing.v1_0_0\"\\xaf\\x0c\\n\\x0eSigningMessage\\x12N\\n\\x05\\x65rror\\x18\\x05 \\x01(\\x0b\\x32=.aea.fetchai.signing.v1_0_0.SigningMessage.Error_PerformativeH\\x00\\x12\\\\\\n\\x0csign_message\\x18\\x06 \\x01(\\x0b\\x32\\x44.aea.fetchai.signing.v1_0_0.SigningMessage.Sign_Message_PerformativeH\\x00\\x12\\x64\\n\\x10sign_transaction\\x18\\x07 \\x01(\\x0b\\x32H.aea.fetchai.signing.v1_0_0.SigningMessage.Sign_Transaction_PerformativeH\\x00\\x12`\\n\\x0esigned_message\\x18\\x08 \\x01(\\x0b\\x32\\x46.aea.fetchai.signing.v1_0_0.SigningMessage.Signed_Message_PerformativeH\\x00\\x12h\\n\\x12signed_transaction\\x18\\t \\x01(\\x0b\\x32J.aea.fetchai.signing.v1_0_0.SigningMessage.Signed_Transaction_PerformativeH\\x00\\x1a\\xbc\\x01\\n\\tErrorCode\\x12V\\n\\nerror_code\\x18\\x01 \\x01(\\x0e\\x32\\x42.aea.fetchai.signing.v1_0_0.SigningMessage.ErrorCode.ErrorCodeEnum\"W\\n\\rErrorCodeEnum\\x12 \\n\\x1cUNSUCCESSFUL_MESSAGE_SIGNING\\x10\\x00\\x12$\\n UNSUCCESSFUL_TRANSACTION_SIGNING\\x10\\x01\\x1a!\\n\\nRawMessage\\x12\\x13\\n\\x0braw_message\\x18\\x01 \\x01(\\x0c\\x1a)\\n\\x0eRawTransaction\\x12\\x17\\n\\x0fraw_transaction\\x18\\x01 \\x01(\\x0c\\x1a\\'\\n\\rSignedMessage\\x12\\x16\\n\\x0esigned_message\\x18\\x01 \\x01(\\x0c\\x1a/\\n\\x11SignedTransaction\\x12\\x1a\\n\\x12signed_transaction\\x18\\x01 \\x01(\\x0c\\x1a\\x16\\n\\x05Terms\\x12\\r\\n\\x05terms\\x18\\x01 \\x01(\\x0c\\x1a\\xb4\\x01\\n\\x1dSign_Transaction_Performative\\x12?\\n\\x05terms\\x18\\x01 \\x01(\\x0b\\x32\\x30.aea.fetchai.signing.v1_0_0.SigningMessage.Terms\\x12R\\n\\x0fraw_transaction\\x18\\x02 \\x01(\\x0b\\x32\\x39.aea.fetchai.signing.v1_0_0.SigningMessage.RawTransaction\\x1a\\xa8\\x01\\n\\x19Sign_Message_Performative\\x12?\\n\\x05terms\\x18\\x01 \\x01(\\x0b\\x32\\x30.aea.fetchai.signing.v1_0_0.SigningMessage.Terms\\x12J\\n\\x0braw_message\\x18\\x02 \\x01(\\x0b\\x32\\x35.aea.fetchai.signing.v1_0_0.SigningMessage.RawMessage\\x1a{\\n\\x1fSigned_Transaction_Performative\\x12X\\n\\x12signed_transaction\\x18\\x01 \\x01(\\x0b\\x32<.aea.fetchai.signing.v1_0_0.SigningMessage.SignedTransaction\\x1ao\\n\\x1bSigned_Message_Performative\\x12P\\n\\x0esigned_message\\x18\\x01 \\x01(\\x0b\\x32\\x38.aea.fetchai.signing.v1_0_0.SigningMessage.SignedMessage\\x1a^\\n\\x12\\x45rror_Performative\\x12H\\n\\nerror_code\\x18\\x01 \\x01(\\x0b\\x32\\x34.aea.fetchai.signing.v1_0_0.SigningMessage.ErrorCodeB\\x0e\\n\\x0cperformativeb\\x06proto3'\n)\n\n\n_SIGNINGMESSAGE = DESCRIPTOR.message_types_by_name[\"SigningMessage\"]\n_SIGNINGMESSAGE_ERRORCODE = _SIGNINGMESSAGE.nested_types_by_name[\"ErrorCode\"]\n_SIGNINGMESSAGE_RAWMESSAGE = _SIGNINGMESSAGE.nested_types_by_name[\"RawMessage\"]\n_SIGNINGMESSAGE_RAWTRANSACTION = _SIGNINGMESSAGE.nested_types_by_name[\"RawTransaction\"]\n_SIGNINGMESSAGE_SIGNEDMESSAGE = _SIGNINGMESSAGE.nested_types_by_name[\"SignedMessage\"]\n_SIGNINGMESSAGE_SIGNEDTRANSACTION = _SIGNINGMESSAGE.nested_types_by_name[\n    \"SignedTransaction\"\n]\n_SIGNINGMESSAGE_TERMS = _SIGNINGMESSAGE.nested_types_by_name[\"Terms\"]\n_SIGNINGMESSAGE_SIGN_TRANSACTION_PERFORMATIVE = _SIGNINGMESSAGE.nested_types_by_name[\n    \"Sign_Transaction_Performative\"\n]\n_SIGNINGMESSAGE_SIGN_MESSAGE_PERFORMATIVE = _SIGNINGMESSAGE.nested_types_by_name[\n    \"Sign_Message_Performative\"\n]\n_SIGNINGMESSAGE_SIGNED_TRANSACTION_PERFORMATIVE = _SIGNINGMESSAGE.nested_types_by_name[\n    \"Signed_Transaction_Performative\"\n]\n_SIGNINGMESSAGE_SIGNED_MESSAGE_PERFORMATIVE = _SIGNINGMESSAGE.nested_types_by_name[\n    \"Signed_Message_Performative\"\n]\n_SIGNINGMESSAGE_ERROR_PERFORMATIVE = _SIGNINGMESSAGE.nested_types_by_name[\n    \"Error_Performative\"\n]\n_SIGNINGMESSAGE_ERRORCODE_ERRORCODEENUM = _SIGNINGMESSAGE_ERRORCODE.enum_types_by_name[\n    \"ErrorCodeEnum\"\n]\nSigningMessage = _reflection.GeneratedProtocolMessageType(\n    \"SigningMessage\",\n    (_message.Message,),\n    {\n        \"ErrorCode\": _reflection.GeneratedProtocolMessageType(\n            \"ErrorCode\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _SIGNINGMESSAGE_ERRORCODE,\n                \"__module__\": \"signing_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.signing.v1_0_0.SigningMessage.ErrorCode)\n            },\n        ),\n        \"RawMessage\": _reflection.GeneratedProtocolMessageType(\n            \"RawMessage\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _SIGNINGMESSAGE_RAWMESSAGE,\n                \"__module__\": \"signing_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.signing.v1_0_0.SigningMessage.RawMessage)\n            },\n        ),\n        \"RawTransaction\": _reflection.GeneratedProtocolMessageType(\n            \"RawTransaction\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _SIGNINGMESSAGE_RAWTRANSACTION,\n                \"__module__\": \"signing_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.signing.v1_0_0.SigningMessage.RawTransaction)\n            },\n        ),\n        \"SignedMessage\": _reflection.GeneratedProtocolMessageType(\n            \"SignedMessage\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _SIGNINGMESSAGE_SIGNEDMESSAGE,\n                \"__module__\": \"signing_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.signing.v1_0_0.SigningMessage.SignedMessage)\n            },\n        ),\n        \"SignedTransaction\": _reflection.GeneratedProtocolMessageType(\n            \"SignedTransaction\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _SIGNINGMESSAGE_SIGNEDTRANSACTION,\n                \"__module__\": \"signing_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.signing.v1_0_0.SigningMessage.SignedTransaction)\n            },\n        ),\n        \"Terms\": _reflection.GeneratedProtocolMessageType(\n            \"Terms\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _SIGNINGMESSAGE_TERMS,\n                \"__module__\": \"signing_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.signing.v1_0_0.SigningMessage.Terms)\n            },\n        ),\n        \"Sign_Transaction_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Sign_Transaction_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _SIGNINGMESSAGE_SIGN_TRANSACTION_PERFORMATIVE,\n                \"__module__\": \"signing_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.signing.v1_0_0.SigningMessage.Sign_Transaction_Performative)\n            },\n        ),\n        \"Sign_Message_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Sign_Message_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _SIGNINGMESSAGE_SIGN_MESSAGE_PERFORMATIVE,\n                \"__module__\": \"signing_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.signing.v1_0_0.SigningMessage.Sign_Message_Performative)\n            },\n        ),\n        \"Signed_Transaction_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Signed_Transaction_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _SIGNINGMESSAGE_SIGNED_TRANSACTION_PERFORMATIVE,\n                \"__module__\": \"signing_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.signing.v1_0_0.SigningMessage.Signed_Transaction_Performative)\n            },\n        ),\n        \"Signed_Message_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Signed_Message_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _SIGNINGMESSAGE_SIGNED_MESSAGE_PERFORMATIVE,\n                \"__module__\": \"signing_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.signing.v1_0_0.SigningMessage.Signed_Message_Performative)\n            },\n        ),\n        \"Error_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Error_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _SIGNINGMESSAGE_ERROR_PERFORMATIVE,\n                \"__module__\": \"signing_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.signing.v1_0_0.SigningMessage.Error_Performative)\n            },\n        ),\n        \"DESCRIPTOR\": _SIGNINGMESSAGE,\n        \"__module__\": \"signing_pb2\"\n        # @@protoc_insertion_point(class_scope:aea.fetchai.signing.v1_0_0.SigningMessage)\n    },\n)\n_sym_db.RegisterMessage(SigningMessage)\n_sym_db.RegisterMessage(SigningMessage.ErrorCode)\n_sym_db.RegisterMessage(SigningMessage.RawMessage)\n_sym_db.RegisterMessage(SigningMessage.RawTransaction)\n_sym_db.RegisterMessage(SigningMessage.SignedMessage)\n_sym_db.RegisterMessage(SigningMessage.SignedTransaction)\n_sym_db.RegisterMessage(SigningMessage.Terms)\n_sym_db.RegisterMessage(SigningMessage.Sign_Transaction_Performative)\n_sym_db.RegisterMessage(SigningMessage.Sign_Message_Performative)\n_sym_db.RegisterMessage(SigningMessage.Signed_Transaction_Performative)\n_sym_db.RegisterMessage(SigningMessage.Signed_Message_Performative)\n_sym_db.RegisterMessage(SigningMessage.Error_Performative)\n\nif _descriptor._USE_C_DESCRIPTORS == False:\n\n    DESCRIPTOR._options = None\n    _SIGNINGMESSAGE._serialized_start = 46\n    _SIGNINGMESSAGE._serialized_end = 1629\n    _SIGNINGMESSAGE_ERRORCODE._serialized_start = 545\n    _SIGNINGMESSAGE_ERRORCODE._serialized_end = 733\n    _SIGNINGMESSAGE_ERRORCODE_ERRORCODEENUM._serialized_start = 646\n    _SIGNINGMESSAGE_ERRORCODE_ERRORCODEENUM._serialized_end = 733\n    _SIGNINGMESSAGE_RAWMESSAGE._serialized_start = 735\n    _SIGNINGMESSAGE_RAWMESSAGE._serialized_end = 768\n    _SIGNINGMESSAGE_RAWTRANSACTION._serialized_start = 770\n    _SIGNINGMESSAGE_RAWTRANSACTION._serialized_end = 811\n    _SIGNINGMESSAGE_SIGNEDMESSAGE._serialized_start = 813\n    _SIGNINGMESSAGE_SIGNEDMESSAGE._serialized_end = 852\n    _SIGNINGMESSAGE_SIGNEDTRANSACTION._serialized_start = 854\n    _SIGNINGMESSAGE_SIGNEDTRANSACTION._serialized_end = 901\n    _SIGNINGMESSAGE_TERMS._serialized_start = 903\n    _SIGNINGMESSAGE_TERMS._serialized_end = 925\n    _SIGNINGMESSAGE_SIGN_TRANSACTION_PERFORMATIVE._serialized_start = 928\n    _SIGNINGMESSAGE_SIGN_TRANSACTION_PERFORMATIVE._serialized_end = 1108\n    _SIGNINGMESSAGE_SIGN_MESSAGE_PERFORMATIVE._serialized_start = 1111\n    _SIGNINGMESSAGE_SIGN_MESSAGE_PERFORMATIVE._serialized_end = 1279\n    _SIGNINGMESSAGE_SIGNED_TRANSACTION_PERFORMATIVE._serialized_start = 1281\n    _SIGNINGMESSAGE_SIGNED_TRANSACTION_PERFORMATIVE._serialized_end = 1404\n    _SIGNINGMESSAGE_SIGNED_MESSAGE_PERFORMATIVE._serialized_start = 1406\n    _SIGNINGMESSAGE_SIGNED_MESSAGE_PERFORMATIVE._serialized_end = 1517\n    _SIGNINGMESSAGE_ERROR_PERFORMATIVE._serialized_start = 1519\n    _SIGNINGMESSAGE_ERROR_PERFORMATIVE._serialized_end = 1613\n# @@protoc_insertion_point(module_scope)\n"
  },
  {
    "path": "packages/fetchai/protocols/state_update/README.md",
    "content": "# State Update Protocol\n\n## Description\n\nThis is a protocol for updating the state of a decision maker.\n\n## Specification\n\n```yaml\n---\nname: state_update\nauthor: fetchai\nversion: 1.1.7\ndescription: A protocol for state updates to the decision maker state.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nprotocol_specification_id: fetchai/state_update:1.0.0\nspeech_acts:\n  initialize:\n    exchange_params_by_currency_id: pt:dict[pt:str, pt:float]\n    utility_params_by_good_id: pt:dict[pt:str, pt:float]\n    amount_by_currency_id: pt:dict[pt:str, pt:int]\n    quantities_by_good_id: pt:dict[pt:str, pt:int]\n  apply:\n    amount_by_currency_id: pt:dict[pt:str, pt:int]\n    quantities_by_good_id: pt:dict[pt:str, pt:int]\n  end: {}\n...\n---\ninitiation: [initialize]\nreply:\n  initialize: [apply]\n  apply: [apply, end]\n  end: []\ntermination: [end]\nroles: {skill, decision_maker}\nend_states: [successful]\nkeep_terminal_state_dialogues: false\n...\n```\n\n## Links\n"
  },
  {
    "path": "packages/fetchai/protocols/state_update/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nThis module contains the support resources for the state_update protocol.\n\nIt was created with protocol buffer compiler version `libprotoc 3.19.4` and aea version `1.2.5`.\n\"\"\"\n\nfrom packages.fetchai.protocols.state_update.message import StateUpdateMessage\nfrom packages.fetchai.protocols.state_update.serialization import StateUpdateSerializer\n\n\nStateUpdateMessage.serializer = StateUpdateSerializer\n"
  },
  {
    "path": "packages/fetchai/protocols/state_update/dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nThis module contains the classes required for state_update dialogue management.\n\n- StateUpdateDialogue: The dialogue class maintains state of a dialogue and manages it.\n- StateUpdateDialogues: The dialogues class keeps track of all dialogues.\n\"\"\"\n\nfrom abc import ABC\nfrom typing import Callable, Dict, FrozenSet, Type, cast\n\nfrom aea.common import Address\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue, DialogueLabel, Dialogues\n\nfrom packages.fetchai.protocols.state_update.message import StateUpdateMessage\n\n\nclass StateUpdateDialogue(Dialogue):\n    \"\"\"The state_update dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    INITIAL_PERFORMATIVES: FrozenSet[Message.Performative] = frozenset(\n        {StateUpdateMessage.Performative.INITIALIZE}\n    )\n    TERMINAL_PERFORMATIVES: FrozenSet[Message.Performative] = frozenset(\n        {StateUpdateMessage.Performative.END}\n    )\n    VALID_REPLIES: Dict[Message.Performative, FrozenSet[Message.Performative]] = {\n        StateUpdateMessage.Performative.APPLY: frozenset(\n            {StateUpdateMessage.Performative.APPLY, StateUpdateMessage.Performative.END}\n        ),\n        StateUpdateMessage.Performative.END: frozenset(),\n        StateUpdateMessage.Performative.INITIALIZE: frozenset(\n            {StateUpdateMessage.Performative.APPLY}\n        ),\n    }\n\n    class Role(Dialogue.Role):\n        \"\"\"This class defines the agent's role in a state_update dialogue.\"\"\"\n\n        DECISION_MAKER = \"decision_maker\"\n        SKILL = \"skill\"\n\n    class EndState(Dialogue.EndState):\n        \"\"\"This class defines the end states of a state_update dialogue.\"\"\"\n\n        SUCCESSFUL = 0\n\n    def __init__(\n        self,\n        dialogue_label: DialogueLabel,\n        self_address: Address,\n        role: Dialogue.Role,\n        message_class: Type[StateUpdateMessage] = StateUpdateMessage,\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n        :param message_class: the message class used\n        \"\"\"\n        Dialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            message_class=message_class,\n            self_address=self_address,\n            role=role,\n        )\n\n\nclass StateUpdateDialogues(Dialogues, ABC):\n    \"\"\"This class keeps track of all state_update dialogues.\"\"\"\n\n    END_STATES = frozenset({StateUpdateDialogue.EndState.SUCCESSFUL})\n\n    _keep_terminal_state_dialogues = False\n\n    def __init__(\n        self,\n        self_address: Address,\n        role_from_first_message: Callable[[Message, Address], Dialogue.Role],\n        dialogue_class: Type[StateUpdateDialogue] = StateUpdateDialogue,\n    ) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param self_address: the address of the entity for whom dialogues are maintained\n        :param dialogue_class: the dialogue class used\n        :param role_from_first_message: the callable determining role from first message\n        \"\"\"\n        Dialogues.__init__(\n            self,\n            self_address=self_address,\n            end_states=cast(FrozenSet[Dialogue.EndState], self.END_STATES),\n            message_class=StateUpdateMessage,\n            dialogue_class=dialogue_class,\n            role_from_first_message=role_from_first_message,\n        )\n"
  },
  {
    "path": "packages/fetchai/protocols/state_update/message.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains state_update's message definition.\"\"\"\n\n# pylint: disable=too-many-statements,too-many-locals,no-member,too-few-public-methods,too-many-branches,not-an-iterable,unidiomatic-typecheck,unsubscriptable-object\nimport logging\nfrom typing import Any, Dict, Set, Tuple, cast\n\nfrom aea.configurations.base import PublicId\nfrom aea.exceptions import AEAEnforceError, enforce\nfrom aea.protocols.base import Message\n\n\n_default_logger = logging.getLogger(\n    \"aea.packages.fetchai.protocols.state_update.message\"\n)\n\nDEFAULT_BODY_SIZE = 4\n\n\nclass StateUpdateMessage(Message):\n    \"\"\"A protocol for state updates to the decision maker state.\"\"\"\n\n    protocol_id = PublicId.from_str(\"fetchai/state_update:1.1.7\")\n    protocol_specification_id = PublicId.from_str(\"fetchai/state_update:1.0.0\")\n\n    class Performative(Message.Performative):\n        \"\"\"Performatives for the state_update protocol.\"\"\"\n\n        APPLY = \"apply\"\n        END = \"end\"\n        INITIALIZE = \"initialize\"\n\n        def __str__(self) -> str:\n            \"\"\"Get the string representation.\"\"\"\n            return str(self.value)\n\n    _performatives = {\"apply\", \"end\", \"initialize\"}\n    __slots__: Tuple[str, ...] = tuple()\n\n    class _SlotsCls:\n        __slots__ = (\n            \"amount_by_currency_id\",\n            \"dialogue_reference\",\n            \"exchange_params_by_currency_id\",\n            \"message_id\",\n            \"performative\",\n            \"quantities_by_good_id\",\n            \"target\",\n            \"utility_params_by_good_id\",\n        )\n\n    def __init__(\n        self,\n        performative: Performative,\n        dialogue_reference: Tuple[str, str] = (\"\", \"\"),\n        message_id: int = 1,\n        target: int = 0,\n        **kwargs: Any,\n    ):\n        \"\"\"\n        Initialise an instance of StateUpdateMessage.\n\n        :param message_id: the message id.\n        :param dialogue_reference: the dialogue reference.\n        :param target: the message target.\n        :param performative: the message performative.\n        :param **kwargs: extra options.\n        \"\"\"\n        super().__init__(\n            dialogue_reference=dialogue_reference,\n            message_id=message_id,\n            target=target,\n            performative=StateUpdateMessage.Performative(performative),\n            **kwargs,\n        )\n\n    @property\n    def valid_performatives(self) -> Set[str]:\n        \"\"\"Get valid performatives.\"\"\"\n        return self._performatives\n\n    @property\n    def dialogue_reference(self) -> Tuple[str, str]:\n        \"\"\"Get the dialogue_reference of the message.\"\"\"\n        enforce(self.is_set(\"dialogue_reference\"), \"dialogue_reference is not set.\")\n        return cast(Tuple[str, str], self.get(\"dialogue_reference\"))\n\n    @property\n    def message_id(self) -> int:\n        \"\"\"Get the message_id of the message.\"\"\"\n        enforce(self.is_set(\"message_id\"), \"message_id is not set.\")\n        return cast(int, self.get(\"message_id\"))\n\n    @property\n    def performative(self) -> Performative:  # type: ignore # noqa: F821\n        \"\"\"Get the performative of the message.\"\"\"\n        enforce(self.is_set(\"performative\"), \"performative is not set.\")\n        return cast(StateUpdateMessage.Performative, self.get(\"performative\"))\n\n    @property\n    def target(self) -> int:\n        \"\"\"Get the target of the message.\"\"\"\n        enforce(self.is_set(\"target\"), \"target is not set.\")\n        return cast(int, self.get(\"target\"))\n\n    @property\n    def amount_by_currency_id(self) -> Dict[str, int]:\n        \"\"\"Get the 'amount_by_currency_id' content from the message.\"\"\"\n        enforce(\n            self.is_set(\"amount_by_currency_id\"),\n            \"'amount_by_currency_id' content is not set.\",\n        )\n        return cast(Dict[str, int], self.get(\"amount_by_currency_id\"))\n\n    @property\n    def exchange_params_by_currency_id(self) -> Dict[str, float]:\n        \"\"\"Get the 'exchange_params_by_currency_id' content from the message.\"\"\"\n        enforce(\n            self.is_set(\"exchange_params_by_currency_id\"),\n            \"'exchange_params_by_currency_id' content is not set.\",\n        )\n        return cast(Dict[str, float], self.get(\"exchange_params_by_currency_id\"))\n\n    @property\n    def quantities_by_good_id(self) -> Dict[str, int]:\n        \"\"\"Get the 'quantities_by_good_id' content from the message.\"\"\"\n        enforce(\n            self.is_set(\"quantities_by_good_id\"),\n            \"'quantities_by_good_id' content is not set.\",\n        )\n        return cast(Dict[str, int], self.get(\"quantities_by_good_id\"))\n\n    @property\n    def utility_params_by_good_id(self) -> Dict[str, float]:\n        \"\"\"Get the 'utility_params_by_good_id' content from the message.\"\"\"\n        enforce(\n            self.is_set(\"utility_params_by_good_id\"),\n            \"'utility_params_by_good_id' content is not set.\",\n        )\n        return cast(Dict[str, float], self.get(\"utility_params_by_good_id\"))\n\n    def _is_consistent(self) -> bool:\n        \"\"\"Check that the message follows the state_update protocol.\"\"\"\n        try:\n            enforce(\n                isinstance(self.dialogue_reference, tuple),\n                \"Invalid type for 'dialogue_reference'. Expected 'tuple'. Found '{}'.\".format(\n                    type(self.dialogue_reference)\n                ),\n            )\n            enforce(\n                isinstance(self.dialogue_reference[0], str),\n                \"Invalid type for 'dialogue_reference[0]'. Expected 'str'. Found '{}'.\".format(\n                    type(self.dialogue_reference[0])\n                ),\n            )\n            enforce(\n                isinstance(self.dialogue_reference[1], str),\n                \"Invalid type for 'dialogue_reference[1]'. Expected 'str'. Found '{}'.\".format(\n                    type(self.dialogue_reference[1])\n                ),\n            )\n            enforce(\n                type(self.message_id) is int,\n                \"Invalid type for 'message_id'. Expected 'int'. Found '{}'.\".format(\n                    type(self.message_id)\n                ),\n            )\n            enforce(\n                type(self.target) is int,\n                \"Invalid type for 'target'. Expected 'int'. Found '{}'.\".format(\n                    type(self.target)\n                ),\n            )\n\n            # Light Protocol Rule 2\n            # Check correct performative\n            enforce(\n                isinstance(self.performative, StateUpdateMessage.Performative),\n                \"Invalid 'performative'. Expected either of '{}'. Found '{}'.\".format(\n                    self.valid_performatives, self.performative\n                ),\n            )\n\n            # Check correct contents\n            actual_nb_of_contents = len(self._body) - DEFAULT_BODY_SIZE\n            expected_nb_of_contents = 0\n            if self.performative == StateUpdateMessage.Performative.INITIALIZE:\n                expected_nb_of_contents = 4\n                enforce(\n                    isinstance(self.exchange_params_by_currency_id, dict),\n                    \"Invalid type for content 'exchange_params_by_currency_id'. Expected 'dict'. Found '{}'.\".format(\n                        type(self.exchange_params_by_currency_id)\n                    ),\n                )\n                for (\n                    key_of_exchange_params_by_currency_id,\n                    value_of_exchange_params_by_currency_id,\n                ) in self.exchange_params_by_currency_id.items():\n                    enforce(\n                        isinstance(key_of_exchange_params_by_currency_id, str),\n                        \"Invalid type for dictionary keys in content 'exchange_params_by_currency_id'. Expected 'str'. Found '{}'.\".format(\n                            type(key_of_exchange_params_by_currency_id)\n                        ),\n                    )\n                    enforce(\n                        isinstance(value_of_exchange_params_by_currency_id, float),\n                        \"Invalid type for dictionary values in content 'exchange_params_by_currency_id'. Expected 'float'. Found '{}'.\".format(\n                            type(value_of_exchange_params_by_currency_id)\n                        ),\n                    )\n                enforce(\n                    isinstance(self.utility_params_by_good_id, dict),\n                    \"Invalid type for content 'utility_params_by_good_id'. Expected 'dict'. Found '{}'.\".format(\n                        type(self.utility_params_by_good_id)\n                    ),\n                )\n                for (\n                    key_of_utility_params_by_good_id,\n                    value_of_utility_params_by_good_id,\n                ) in self.utility_params_by_good_id.items():\n                    enforce(\n                        isinstance(key_of_utility_params_by_good_id, str),\n                        \"Invalid type for dictionary keys in content 'utility_params_by_good_id'. Expected 'str'. Found '{}'.\".format(\n                            type(key_of_utility_params_by_good_id)\n                        ),\n                    )\n                    enforce(\n                        isinstance(value_of_utility_params_by_good_id, float),\n                        \"Invalid type for dictionary values in content 'utility_params_by_good_id'. Expected 'float'. Found '{}'.\".format(\n                            type(value_of_utility_params_by_good_id)\n                        ),\n                    )\n                enforce(\n                    isinstance(self.amount_by_currency_id, dict),\n                    \"Invalid type for content 'amount_by_currency_id'. Expected 'dict'. Found '{}'.\".format(\n                        type(self.amount_by_currency_id)\n                    ),\n                )\n                for (\n                    key_of_amount_by_currency_id,\n                    value_of_amount_by_currency_id,\n                ) in self.amount_by_currency_id.items():\n                    enforce(\n                        isinstance(key_of_amount_by_currency_id, str),\n                        \"Invalid type for dictionary keys in content 'amount_by_currency_id'. Expected 'str'. Found '{}'.\".format(\n                            type(key_of_amount_by_currency_id)\n                        ),\n                    )\n                    enforce(\n                        type(value_of_amount_by_currency_id) is int,\n                        \"Invalid type for dictionary values in content 'amount_by_currency_id'. Expected 'int'. Found '{}'.\".format(\n                            type(value_of_amount_by_currency_id)\n                        ),\n                    )\n                enforce(\n                    isinstance(self.quantities_by_good_id, dict),\n                    \"Invalid type for content 'quantities_by_good_id'. Expected 'dict'. Found '{}'.\".format(\n                        type(self.quantities_by_good_id)\n                    ),\n                )\n                for (\n                    key_of_quantities_by_good_id,\n                    value_of_quantities_by_good_id,\n                ) in self.quantities_by_good_id.items():\n                    enforce(\n                        isinstance(key_of_quantities_by_good_id, str),\n                        \"Invalid type for dictionary keys in content 'quantities_by_good_id'. Expected 'str'. Found '{}'.\".format(\n                            type(key_of_quantities_by_good_id)\n                        ),\n                    )\n                    enforce(\n                        type(value_of_quantities_by_good_id) is int,\n                        \"Invalid type for dictionary values in content 'quantities_by_good_id'. Expected 'int'. Found '{}'.\".format(\n                            type(value_of_quantities_by_good_id)\n                        ),\n                    )\n            elif self.performative == StateUpdateMessage.Performative.APPLY:\n                expected_nb_of_contents = 2\n                enforce(\n                    isinstance(self.amount_by_currency_id, dict),\n                    \"Invalid type for content 'amount_by_currency_id'. Expected 'dict'. Found '{}'.\".format(\n                        type(self.amount_by_currency_id)\n                    ),\n                )\n                for (\n                    key_of_amount_by_currency_id,\n                    value_of_amount_by_currency_id,\n                ) in self.amount_by_currency_id.items():\n                    enforce(\n                        isinstance(key_of_amount_by_currency_id, str),\n                        \"Invalid type for dictionary keys in content 'amount_by_currency_id'. Expected 'str'. Found '{}'.\".format(\n                            type(key_of_amount_by_currency_id)\n                        ),\n                    )\n                    enforce(\n                        type(value_of_amount_by_currency_id) is int,\n                        \"Invalid type for dictionary values in content 'amount_by_currency_id'. Expected 'int'. Found '{}'.\".format(\n                            type(value_of_amount_by_currency_id)\n                        ),\n                    )\n                enforce(\n                    isinstance(self.quantities_by_good_id, dict),\n                    \"Invalid type for content 'quantities_by_good_id'. Expected 'dict'. Found '{}'.\".format(\n                        type(self.quantities_by_good_id)\n                    ),\n                )\n                for (\n                    key_of_quantities_by_good_id,\n                    value_of_quantities_by_good_id,\n                ) in self.quantities_by_good_id.items():\n                    enforce(\n                        isinstance(key_of_quantities_by_good_id, str),\n                        \"Invalid type for dictionary keys in content 'quantities_by_good_id'. Expected 'str'. Found '{}'.\".format(\n                            type(key_of_quantities_by_good_id)\n                        ),\n                    )\n                    enforce(\n                        type(value_of_quantities_by_good_id) is int,\n                        \"Invalid type for dictionary values in content 'quantities_by_good_id'. Expected 'int'. Found '{}'.\".format(\n                            type(value_of_quantities_by_good_id)\n                        ),\n                    )\n            elif self.performative == StateUpdateMessage.Performative.END:\n                expected_nb_of_contents = 0\n\n            # Check correct content count\n            enforce(\n                expected_nb_of_contents == actual_nb_of_contents,\n                \"Incorrect number of contents. Expected {}. Found {}\".format(\n                    expected_nb_of_contents, actual_nb_of_contents\n                ),\n            )\n\n            # Light Protocol Rule 3\n            if self.message_id == 1:\n                enforce(\n                    self.target == 0,\n                    \"Invalid 'target'. Expected 0 (because 'message_id' is 1). Found {}.\".format(\n                        self.target\n                    ),\n                )\n        except (AEAEnforceError, ValueError, KeyError) as e:\n            _default_logger.error(str(e))\n            return False\n\n        return True\n"
  },
  {
    "path": "packages/fetchai/protocols/state_update/protocol.yaml",
    "content": "name: state_update\nauthor: fetchai\nversion: 1.1.7\nprotocol_specification_id: fetchai/state_update:1.0.0\ntype: protocol\ndescription: A protocol for state updates to the decision maker state.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: QmbFH2ySjB5FnvLhKCm68jJPVeasHbGBSTUyEZP4P17mKi\n  __init__.py: Qmboa7WunXM34apxH2fu4z1996CrfxcCaV2HxhvXsjnkxK\n  dialogues.py: QmUugwuLbuHr8zkGRkd7Dimwc7LzbCHYvdNHC6cn3TS7XP\n  message.py: QmPKeMCSAcxDeEXUMzAjRvVvWJ5AUMYoDyGPGjUEoHkKff\n  serialization.py: QmRxkqWUB7EVGp1SnsMXeDssCcsiirvPPJAaeN5TREPBBm\n  state_update.proto: QmdLQpu2jpJUuUFhF34hBeh64Gfv5V1JxLTKCTgY93qduR\n  state_update_pb2.py: QmXmaUALXJ4zV2CuADrGsFpNmy8RhWLSYpm7dXXogfgrw3\nfingerprint_ignore_patterns: []\ndependencies:\n  protobuf: {}\n"
  },
  {
    "path": "packages/fetchai/protocols/state_update/serialization.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Serialization module for state_update protocol.\"\"\"\n\n# pylint: disable=too-many-statements,too-many-locals,no-member,too-few-public-methods,redefined-builtin\nfrom typing import Any, Dict, cast\n\nfrom aea.mail.base_pb2 import DialogueMessage\nfrom aea.mail.base_pb2 import Message as ProtobufMessage\nfrom aea.protocols.base import Message, Serializer\n\nfrom packages.fetchai.protocols.state_update import state_update_pb2\nfrom packages.fetchai.protocols.state_update.message import StateUpdateMessage\n\n\nclass StateUpdateSerializer(Serializer):\n    \"\"\"Serialization for the 'state_update' protocol.\"\"\"\n\n    @staticmethod\n    def encode(msg: Message) -> bytes:\n        \"\"\"\n        Encode a 'StateUpdate' message into bytes.\n\n        :param msg: the message object.\n        :return: the bytes.\n        \"\"\"\n        msg = cast(StateUpdateMessage, msg)\n        message_pb = ProtobufMessage()\n        dialogue_message_pb = DialogueMessage()\n        state_update_msg = state_update_pb2.StateUpdateMessage()\n\n        dialogue_message_pb.message_id = msg.message_id\n        dialogue_reference = msg.dialogue_reference\n        dialogue_message_pb.dialogue_starter_reference = dialogue_reference[0]\n        dialogue_message_pb.dialogue_responder_reference = dialogue_reference[1]\n        dialogue_message_pb.target = msg.target\n\n        performative_id = msg.performative\n        if performative_id == StateUpdateMessage.Performative.INITIALIZE:\n            performative = state_update_pb2.StateUpdateMessage.Initialize_Performative()  # type: ignore\n            exchange_params_by_currency_id = msg.exchange_params_by_currency_id\n            performative.exchange_params_by_currency_id.update(\n                exchange_params_by_currency_id\n            )\n            utility_params_by_good_id = msg.utility_params_by_good_id\n            performative.utility_params_by_good_id.update(utility_params_by_good_id)\n            amount_by_currency_id = msg.amount_by_currency_id\n            performative.amount_by_currency_id.update(amount_by_currency_id)\n            quantities_by_good_id = msg.quantities_by_good_id\n            performative.quantities_by_good_id.update(quantities_by_good_id)\n            state_update_msg.initialize.CopyFrom(performative)\n        elif performative_id == StateUpdateMessage.Performative.APPLY:\n            performative = state_update_pb2.StateUpdateMessage.Apply_Performative()  # type: ignore\n            amount_by_currency_id = msg.amount_by_currency_id\n            performative.amount_by_currency_id.update(amount_by_currency_id)\n            quantities_by_good_id = msg.quantities_by_good_id\n            performative.quantities_by_good_id.update(quantities_by_good_id)\n            state_update_msg.apply.CopyFrom(performative)\n        elif performative_id == StateUpdateMessage.Performative.END:\n            performative = state_update_pb2.StateUpdateMessage.End_Performative()  # type: ignore\n            state_update_msg.end.CopyFrom(performative)\n        else:\n            raise ValueError(\"Performative not valid: {}\".format(performative_id))\n\n        dialogue_message_pb.content = state_update_msg.SerializeToString()\n\n        message_pb.dialogue_message.CopyFrom(dialogue_message_pb)\n        message_bytes = message_pb.SerializeToString()\n        return message_bytes\n\n    @staticmethod\n    def decode(obj: bytes) -> Message:\n        \"\"\"\n        Decode bytes into a 'StateUpdate' message.\n\n        :param obj: the bytes object.\n        :return: the 'StateUpdate' message.\n        \"\"\"\n        message_pb = ProtobufMessage()\n        state_update_pb = state_update_pb2.StateUpdateMessage()\n        message_pb.ParseFromString(obj)\n        message_id = message_pb.dialogue_message.message_id\n        dialogue_reference = (\n            message_pb.dialogue_message.dialogue_starter_reference,\n            message_pb.dialogue_message.dialogue_responder_reference,\n        )\n        target = message_pb.dialogue_message.target\n\n        state_update_pb.ParseFromString(message_pb.dialogue_message.content)\n        performative = state_update_pb.WhichOneof(\"performative\")\n        performative_id = StateUpdateMessage.Performative(str(performative))\n        performative_content = {}  # type: Dict[str, Any]\n        if performative_id == StateUpdateMessage.Performative.INITIALIZE:\n            exchange_params_by_currency_id = (\n                state_update_pb.initialize.exchange_params_by_currency_id\n            )\n            exchange_params_by_currency_id_dict = dict(exchange_params_by_currency_id)\n            performative_content[\n                \"exchange_params_by_currency_id\"\n            ] = exchange_params_by_currency_id_dict\n            utility_params_by_good_id = (\n                state_update_pb.initialize.utility_params_by_good_id\n            )\n            utility_params_by_good_id_dict = dict(utility_params_by_good_id)\n            performative_content[\n                \"utility_params_by_good_id\"\n            ] = utility_params_by_good_id_dict\n            amount_by_currency_id = state_update_pb.initialize.amount_by_currency_id\n            amount_by_currency_id_dict = dict(amount_by_currency_id)\n            performative_content[\"amount_by_currency_id\"] = amount_by_currency_id_dict\n            quantities_by_good_id = state_update_pb.initialize.quantities_by_good_id\n            quantities_by_good_id_dict = dict(quantities_by_good_id)\n            performative_content[\"quantities_by_good_id\"] = quantities_by_good_id_dict\n        elif performative_id == StateUpdateMessage.Performative.APPLY:\n            amount_by_currency_id = state_update_pb.apply.amount_by_currency_id\n            amount_by_currency_id_dict = dict(amount_by_currency_id)\n            performative_content[\"amount_by_currency_id\"] = amount_by_currency_id_dict\n            quantities_by_good_id = state_update_pb.apply.quantities_by_good_id\n            quantities_by_good_id_dict = dict(quantities_by_good_id)\n            performative_content[\"quantities_by_good_id\"] = quantities_by_good_id_dict\n        elif performative_id == StateUpdateMessage.Performative.END:\n            pass\n        else:\n            raise ValueError(\"Performative not valid: {}.\".format(performative_id))\n\n        return StateUpdateMessage(\n            message_id=message_id,\n            dialogue_reference=dialogue_reference,\n            target=target,\n            performative=performative,\n            **performative_content\n        )\n"
  },
  {
    "path": "packages/fetchai/protocols/state_update/state_update.proto",
    "content": "syntax = \"proto3\";\n\npackage aea.fetchai.state_update.v1_0_0;\n\nmessage StateUpdateMessage{\n\n  // Performatives and contents\n  message Initialize_Performative{\n    map<string, float> exchange_params_by_currency_id = 1;\n    map<string, float> utility_params_by_good_id = 2;\n    map<string, int64> amount_by_currency_id = 3;\n    map<string, int64> quantities_by_good_id = 4;\n  }\n\n  message Apply_Performative{\n    map<string, int64> amount_by_currency_id = 1;\n    map<string, int64> quantities_by_good_id = 2;\n  }\n\n  message End_Performative{\n  }\n\n\n  oneof performative{\n    Apply_Performative apply = 5;\n    End_Performative end = 6;\n    Initialize_Performative initialize = 7;\n  }\n}\n"
  },
  {
    "path": "packages/fetchai/protocols/state_update/state_update_pb2.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by the protocol buffer compiler.  DO NOT EDIT!\n# source: state_update.proto\n\"\"\"Generated protocol buffer code.\"\"\"\nfrom google.protobuf import descriptor as _descriptor\nfrom google.protobuf import descriptor_pool as _descriptor_pool\nfrom google.protobuf import message as _message\nfrom google.protobuf import reflection as _reflection\nfrom google.protobuf import symbol_database as _symbol_database\n\n# @@protoc_insertion_point(imports)\n\n_sym_db = _symbol_database.Default()\n\n\nDESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(\n    b'\\n\\x12state_update.proto\\x12\\x1f\\x61\\x65\\x61.fetchai.state_update.v1_0_0\"\\x93\\x0c\\n\\x12StateUpdateMessage\\x12W\\n\\x05\\x61pply\\x18\\x05 \\x01(\\x0b\\x32\\x46.aea.fetchai.state_update.v1_0_0.StateUpdateMessage.Apply_PerformativeH\\x00\\x12S\\n\\x03\\x65nd\\x18\\x06 \\x01(\\x0b\\x32\\x44.aea.fetchai.state_update.v1_0_0.StateUpdateMessage.End_PerformativeH\\x00\\x12\\x61\\n\\ninitialize\\x18\\x07 \\x01(\\x0b\\x32K.aea.fetchai.state_update.v1_0_0.StateUpdateMessage.Initialize_PerformativeH\\x00\\x1a\\xbc\\x06\\n\\x17Initialize_Performative\\x12\\x93\\x01\\n\\x1e\\x65xchange_params_by_currency_id\\x18\\x01 \\x03(\\x0b\\x32k.aea.fetchai.state_update.v1_0_0.StateUpdateMessage.Initialize_Performative.ExchangeParamsByCurrencyIdEntry\\x12\\x89\\x01\\n\\x19utility_params_by_good_id\\x18\\x02 \\x03(\\x0b\\x32\\x66.aea.fetchai.state_update.v1_0_0.StateUpdateMessage.Initialize_Performative.UtilityParamsByGoodIdEntry\\x12\\x82\\x01\\n\\x15\\x61mount_by_currency_id\\x18\\x03 \\x03(\\x0b\\x32\\x63.aea.fetchai.state_update.v1_0_0.StateUpdateMessage.Initialize_Performative.AmountByCurrencyIdEntry\\x12\\x82\\x01\\n\\x15quantities_by_good_id\\x18\\x04 \\x03(\\x0b\\x32\\x63.aea.fetchai.state_update.v1_0_0.StateUpdateMessage.Initialize_Performative.QuantitiesByGoodIdEntry\\x1a\\x41\\n\\x1f\\x45xchangeParamsByCurrencyIdEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\t\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\x02:\\x02\\x38\\x01\\x1a<\\n\\x1aUtilityParamsByGoodIdEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\t\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\x02:\\x02\\x38\\x01\\x1a\\x39\\n\\x17\\x41mountByCurrencyIdEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\t\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\x03:\\x02\\x38\\x01\\x1a\\x39\\n\\x17QuantitiesByGoodIdEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\t\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\x03:\\x02\\x38\\x01\\x1a\\x88\\x03\\n\\x12\\x41pply_Performative\\x12}\\n\\x15\\x61mount_by_currency_id\\x18\\x01 \\x03(\\x0b\\x32^.aea.fetchai.state_update.v1_0_0.StateUpdateMessage.Apply_Performative.AmountByCurrencyIdEntry\\x12}\\n\\x15quantities_by_good_id\\x18\\x02 \\x03(\\x0b\\x32^.aea.fetchai.state_update.v1_0_0.StateUpdateMessage.Apply_Performative.QuantitiesByGoodIdEntry\\x1a\\x39\\n\\x17\\x41mountByCurrencyIdEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\t\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\x03:\\x02\\x38\\x01\\x1a\\x39\\n\\x17QuantitiesByGoodIdEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\t\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\x03:\\x02\\x38\\x01\\x1a\\x12\\n\\x10\\x45nd_PerformativeB\\x0e\\n\\x0cperformativeb\\x06proto3'\n)\n\n\n_STATEUPDATEMESSAGE = DESCRIPTOR.message_types_by_name[\"StateUpdateMessage\"]\n_STATEUPDATEMESSAGE_INITIALIZE_PERFORMATIVE = _STATEUPDATEMESSAGE.nested_types_by_name[\n    \"Initialize_Performative\"\n]\n_STATEUPDATEMESSAGE_INITIALIZE_PERFORMATIVE_EXCHANGEPARAMSBYCURRENCYIDENTRY = (\n    _STATEUPDATEMESSAGE_INITIALIZE_PERFORMATIVE.nested_types_by_name[\n        \"ExchangeParamsByCurrencyIdEntry\"\n    ]\n)\n_STATEUPDATEMESSAGE_INITIALIZE_PERFORMATIVE_UTILITYPARAMSBYGOODIDENTRY = (\n    _STATEUPDATEMESSAGE_INITIALIZE_PERFORMATIVE.nested_types_by_name[\n        \"UtilityParamsByGoodIdEntry\"\n    ]\n)\n_STATEUPDATEMESSAGE_INITIALIZE_PERFORMATIVE_AMOUNTBYCURRENCYIDENTRY = (\n    _STATEUPDATEMESSAGE_INITIALIZE_PERFORMATIVE.nested_types_by_name[\n        \"AmountByCurrencyIdEntry\"\n    ]\n)\n_STATEUPDATEMESSAGE_INITIALIZE_PERFORMATIVE_QUANTITIESBYGOODIDENTRY = (\n    _STATEUPDATEMESSAGE_INITIALIZE_PERFORMATIVE.nested_types_by_name[\n        \"QuantitiesByGoodIdEntry\"\n    ]\n)\n_STATEUPDATEMESSAGE_APPLY_PERFORMATIVE = _STATEUPDATEMESSAGE.nested_types_by_name[\n    \"Apply_Performative\"\n]\n_STATEUPDATEMESSAGE_APPLY_PERFORMATIVE_AMOUNTBYCURRENCYIDENTRY = (\n    _STATEUPDATEMESSAGE_APPLY_PERFORMATIVE.nested_types_by_name[\n        \"AmountByCurrencyIdEntry\"\n    ]\n)\n_STATEUPDATEMESSAGE_APPLY_PERFORMATIVE_QUANTITIESBYGOODIDENTRY = (\n    _STATEUPDATEMESSAGE_APPLY_PERFORMATIVE.nested_types_by_name[\n        \"QuantitiesByGoodIdEntry\"\n    ]\n)\n_STATEUPDATEMESSAGE_END_PERFORMATIVE = _STATEUPDATEMESSAGE.nested_types_by_name[\n    \"End_Performative\"\n]\nStateUpdateMessage = _reflection.GeneratedProtocolMessageType(\n    \"StateUpdateMessage\",\n    (_message.Message,),\n    {\n        \"Initialize_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Initialize_Performative\",\n            (_message.Message,),\n            {\n                \"ExchangeParamsByCurrencyIdEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"ExchangeParamsByCurrencyIdEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _STATEUPDATEMESSAGE_INITIALIZE_PERFORMATIVE_EXCHANGEPARAMSBYCURRENCYIDENTRY,\n                        \"__module__\": \"state_update_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.fetchai.state_update.v1_0_0.StateUpdateMessage.Initialize_Performative.ExchangeParamsByCurrencyIdEntry)\n                    },\n                ),\n                \"UtilityParamsByGoodIdEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"UtilityParamsByGoodIdEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _STATEUPDATEMESSAGE_INITIALIZE_PERFORMATIVE_UTILITYPARAMSBYGOODIDENTRY,\n                        \"__module__\": \"state_update_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.fetchai.state_update.v1_0_0.StateUpdateMessage.Initialize_Performative.UtilityParamsByGoodIdEntry)\n                    },\n                ),\n                \"AmountByCurrencyIdEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"AmountByCurrencyIdEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _STATEUPDATEMESSAGE_INITIALIZE_PERFORMATIVE_AMOUNTBYCURRENCYIDENTRY,\n                        \"__module__\": \"state_update_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.fetchai.state_update.v1_0_0.StateUpdateMessage.Initialize_Performative.AmountByCurrencyIdEntry)\n                    },\n                ),\n                \"QuantitiesByGoodIdEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"QuantitiesByGoodIdEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _STATEUPDATEMESSAGE_INITIALIZE_PERFORMATIVE_QUANTITIESBYGOODIDENTRY,\n                        \"__module__\": \"state_update_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.fetchai.state_update.v1_0_0.StateUpdateMessage.Initialize_Performative.QuantitiesByGoodIdEntry)\n                    },\n                ),\n                \"DESCRIPTOR\": _STATEUPDATEMESSAGE_INITIALIZE_PERFORMATIVE,\n                \"__module__\": \"state_update_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.state_update.v1_0_0.StateUpdateMessage.Initialize_Performative)\n            },\n        ),\n        \"Apply_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Apply_Performative\",\n            (_message.Message,),\n            {\n                \"AmountByCurrencyIdEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"AmountByCurrencyIdEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _STATEUPDATEMESSAGE_APPLY_PERFORMATIVE_AMOUNTBYCURRENCYIDENTRY,\n                        \"__module__\": \"state_update_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.fetchai.state_update.v1_0_0.StateUpdateMessage.Apply_Performative.AmountByCurrencyIdEntry)\n                    },\n                ),\n                \"QuantitiesByGoodIdEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"QuantitiesByGoodIdEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _STATEUPDATEMESSAGE_APPLY_PERFORMATIVE_QUANTITIESBYGOODIDENTRY,\n                        \"__module__\": \"state_update_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.fetchai.state_update.v1_0_0.StateUpdateMessage.Apply_Performative.QuantitiesByGoodIdEntry)\n                    },\n                ),\n                \"DESCRIPTOR\": _STATEUPDATEMESSAGE_APPLY_PERFORMATIVE,\n                \"__module__\": \"state_update_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.state_update.v1_0_0.StateUpdateMessage.Apply_Performative)\n            },\n        ),\n        \"End_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"End_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _STATEUPDATEMESSAGE_END_PERFORMATIVE,\n                \"__module__\": \"state_update_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.state_update.v1_0_0.StateUpdateMessage.End_Performative)\n            },\n        ),\n        \"DESCRIPTOR\": _STATEUPDATEMESSAGE,\n        \"__module__\": \"state_update_pb2\"\n        # @@protoc_insertion_point(class_scope:aea.fetchai.state_update.v1_0_0.StateUpdateMessage)\n    },\n)\n_sym_db.RegisterMessage(StateUpdateMessage)\n_sym_db.RegisterMessage(StateUpdateMessage.Initialize_Performative)\n_sym_db.RegisterMessage(\n    StateUpdateMessage.Initialize_Performative.ExchangeParamsByCurrencyIdEntry\n)\n_sym_db.RegisterMessage(\n    StateUpdateMessage.Initialize_Performative.UtilityParamsByGoodIdEntry\n)\n_sym_db.RegisterMessage(\n    StateUpdateMessage.Initialize_Performative.AmountByCurrencyIdEntry\n)\n_sym_db.RegisterMessage(\n    StateUpdateMessage.Initialize_Performative.QuantitiesByGoodIdEntry\n)\n_sym_db.RegisterMessage(StateUpdateMessage.Apply_Performative)\n_sym_db.RegisterMessage(StateUpdateMessage.Apply_Performative.AmountByCurrencyIdEntry)\n_sym_db.RegisterMessage(StateUpdateMessage.Apply_Performative.QuantitiesByGoodIdEntry)\n_sym_db.RegisterMessage(StateUpdateMessage.End_Performative)\n\nif _descriptor._USE_C_DESCRIPTORS == False:\n\n    DESCRIPTOR._options = None\n    _STATEUPDATEMESSAGE_INITIALIZE_PERFORMATIVE_EXCHANGEPARAMSBYCURRENCYIDENTRY._options = (\n        None\n    )\n    _STATEUPDATEMESSAGE_INITIALIZE_PERFORMATIVE_EXCHANGEPARAMSBYCURRENCYIDENTRY._serialized_options = (\n        b\"8\\001\"\n    )\n    _STATEUPDATEMESSAGE_INITIALIZE_PERFORMATIVE_UTILITYPARAMSBYGOODIDENTRY._options = (\n        None\n    )\n    _STATEUPDATEMESSAGE_INITIALIZE_PERFORMATIVE_UTILITYPARAMSBYGOODIDENTRY._serialized_options = (\n        b\"8\\001\"\n    )\n    _STATEUPDATEMESSAGE_INITIALIZE_PERFORMATIVE_AMOUNTBYCURRENCYIDENTRY._options = None\n    _STATEUPDATEMESSAGE_INITIALIZE_PERFORMATIVE_AMOUNTBYCURRENCYIDENTRY._serialized_options = (\n        b\"8\\001\"\n    )\n    _STATEUPDATEMESSAGE_INITIALIZE_PERFORMATIVE_QUANTITIESBYGOODIDENTRY._options = None\n    _STATEUPDATEMESSAGE_INITIALIZE_PERFORMATIVE_QUANTITIESBYGOODIDENTRY._serialized_options = (\n        b\"8\\001\"\n    )\n    _STATEUPDATEMESSAGE_APPLY_PERFORMATIVE_AMOUNTBYCURRENCYIDENTRY._options = None\n    _STATEUPDATEMESSAGE_APPLY_PERFORMATIVE_AMOUNTBYCURRENCYIDENTRY._serialized_options = (\n        b\"8\\001\"\n    )\n    _STATEUPDATEMESSAGE_APPLY_PERFORMATIVE_QUANTITIESBYGOODIDENTRY._options = None\n    _STATEUPDATEMESSAGE_APPLY_PERFORMATIVE_QUANTITIESBYGOODIDENTRY._serialized_options = (\n        b\"8\\001\"\n    )\n    _STATEUPDATEMESSAGE._serialized_start = 56\n    _STATEUPDATEMESSAGE._serialized_end = 1611\n    _STATEUPDATEMESSAGE_INITIALIZE_PERFORMATIVE._serialized_start = 352\n    _STATEUPDATEMESSAGE_INITIALIZE_PERFORMATIVE._serialized_end = 1180\n    _STATEUPDATEMESSAGE_INITIALIZE_PERFORMATIVE_EXCHANGEPARAMSBYCURRENCYIDENTRY._serialized_start = (\n        935\n    )\n    _STATEUPDATEMESSAGE_INITIALIZE_PERFORMATIVE_EXCHANGEPARAMSBYCURRENCYIDENTRY._serialized_end = (\n        1000\n    )\n    _STATEUPDATEMESSAGE_INITIALIZE_PERFORMATIVE_UTILITYPARAMSBYGOODIDENTRY._serialized_start = (\n        1002\n    )\n    _STATEUPDATEMESSAGE_INITIALIZE_PERFORMATIVE_UTILITYPARAMSBYGOODIDENTRY._serialized_end = (\n        1062\n    )\n    _STATEUPDATEMESSAGE_INITIALIZE_PERFORMATIVE_AMOUNTBYCURRENCYIDENTRY._serialized_start = (\n        1064\n    )\n    _STATEUPDATEMESSAGE_INITIALIZE_PERFORMATIVE_AMOUNTBYCURRENCYIDENTRY._serialized_end = (\n        1121\n    )\n    _STATEUPDATEMESSAGE_INITIALIZE_PERFORMATIVE_QUANTITIESBYGOODIDENTRY._serialized_start = (\n        1123\n    )\n    _STATEUPDATEMESSAGE_INITIALIZE_PERFORMATIVE_QUANTITIESBYGOODIDENTRY._serialized_end = (\n        1180\n    )\n    _STATEUPDATEMESSAGE_APPLY_PERFORMATIVE._serialized_start = 1183\n    _STATEUPDATEMESSAGE_APPLY_PERFORMATIVE._serialized_end = 1575\n    _STATEUPDATEMESSAGE_APPLY_PERFORMATIVE_AMOUNTBYCURRENCYIDENTRY._serialized_start = (\n        1064\n    )\n    _STATEUPDATEMESSAGE_APPLY_PERFORMATIVE_AMOUNTBYCURRENCYIDENTRY._serialized_end = (\n        1121\n    )\n    _STATEUPDATEMESSAGE_APPLY_PERFORMATIVE_QUANTITIESBYGOODIDENTRY._serialized_start = (\n        1123\n    )\n    _STATEUPDATEMESSAGE_APPLY_PERFORMATIVE_QUANTITIESBYGOODIDENTRY._serialized_end = (\n        1180\n    )\n    _STATEUPDATEMESSAGE_END_PERFORMATIVE._serialized_start = 1577\n    _STATEUPDATEMESSAGE_END_PERFORMATIVE._serialized_end = 1595\n# @@protoc_insertion_point(module_scope)\n"
  },
  {
    "path": "packages/fetchai/protocols/tac/README.md",
    "content": "# TAC Protocol\n\n## Description\n\nThis is a protocol for participating in a Trading Agent Competition (TAC).\n\n## Specification\n\n```yaml\n---\nname: tac\nauthor: fetchai\nversion: 1.1.7\ndescription: The tac protocol implements the messages an AEA needs to participate\n  in the TAC.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nprotocol_specification_id: fetchai/tac:1.0.0\nspeech_acts:\n  register:\n    agent_name: pt:str\n  unregister: {}\n  transaction:\n    transaction_id: pt:str\n    ledger_id: pt:str\n    sender_address: pt:str\n    counterparty_address: pt:str\n    amount_by_currency_id: pt:dict[pt:str, pt:int]\n    fee_by_currency_id: pt:dict[pt:str, pt:int]\n    quantities_by_good_id: pt:dict[pt:str, pt:int]\n    nonce: pt:str\n    sender_signature: pt:str\n    counterparty_signature: pt:str\n  cancelled: {}\n  game_data:\n    amount_by_currency_id: pt:dict[pt:str, pt:int]\n    exchange_params_by_currency_id: pt:dict[pt:str, pt:float]\n    quantities_by_good_id: pt:dict[pt:str, pt:int]\n    utility_params_by_good_id: pt:dict[pt:str, pt:float]\n    fee_by_currency_id: pt:dict[pt:str, pt:int]\n    agent_addr_to_name: pt:dict[pt:str, pt:str]\n    currency_id_to_name: pt:dict[pt:str, pt:str]\n    good_id_to_name: pt:dict[pt:str, pt:str]\n    version_id: pt:str\n    info: pt:optional[pt:dict[pt:str, pt:str]]\n  transaction_confirmation:\n    transaction_id: pt:str\n    amount_by_currency_id: pt:dict[pt:str, pt:int]\n    quantities_by_good_id: pt:dict[pt:str, pt:int]\n  tac_error:\n    error_code: ct:ErrorCode\n    info: pt:optional[pt:dict[pt:str, pt:str]]\n...\n---\nct:ErrorCode: |\n  enum ErrorCodeEnum {\n    GENERIC_ERROR = 0;\n    REQUEST_NOT_VALID = 1;\n    AGENT_ADDR_ALREADY_REGISTERED = 2;\n    AGENT_NAME_ALREADY_REGISTERED = 3;\n    AGENT_NOT_REGISTERED = 4;\n    TRANSACTION_NOT_VALID = 5;\n    TRANSACTION_NOT_MATCHING = 6;\n    AGENT_NAME_NOT_IN_WHITELIST = 7;\n    COMPETITION_NOT_RUNNING = 8;\n    DIALOGUE_INCONSISTENT = 9;\n  }\n  ErrorCodeEnum error_code = 1;\n...\n---\ninitiation: [register]\nreply:\n  register: [tac_error, game_data, cancelled, unregister]\n  unregister: [tac_error]\n  transaction: [transaction, transaction_confirmation, tac_error, cancelled]\n  cancelled: []\n  game_data: [transaction, transaction_confirmation, cancelled]\n  transaction_confirmation: [transaction, transaction_confirmation, cancelled]\n  tac_error: [transaction, transaction_confirmation, cancelled]\ntermination: [cancelled]\nroles: {participant, controller}\nend_states: [successful, failed]\nkeep_terminal_state_dialogues: true\n...\n```\n\n## Links\n\n- <a href=\"https://docs.fetch.ai/aea/tac-skills/\" target=\"_blank\">TAC skill in the AEA framework</a>\n"
  },
  {
    "path": "packages/fetchai/protocols/tac/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nThis module contains the support resources for the tac protocol.\n\nIt was created with protocol buffer compiler version `libprotoc 3.19.4` and aea version `1.2.5`.\n\"\"\"\n\nfrom packages.fetchai.protocols.tac.message import TacMessage\nfrom packages.fetchai.protocols.tac.serialization import TacSerializer\n\n\nTacMessage.serializer = TacSerializer\n"
  },
  {
    "path": "packages/fetchai/protocols/tac/custom_types.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains class representations corresponding to every custom type in the protocol specification.\"\"\"\n\nfrom enum import Enum\nfrom typing import Any, Dict\n\n\nCODE_TO_MSG = {\n    0: \"Unexpected error.\",\n    1: \"Request not recognized\",\n    2: \"Agent addr already registered.\",\n    3: \"Agent name already registered.\",\n    4: \"Agent not registered.\",\n    5: \"Error in checking transaction\",\n    6: \"The transaction request does not match with a previous transaction request with the same id.\",\n    7: \"Agent name not in whitelist.\",\n    8: \"The competition is not running yet.\",\n    9: \"The message is inconsistent with the dialogue.\",\n}  # type: Dict[int, str]\n\n\nclass ErrorCode(Enum):\n    \"\"\"This class represents an instance of ErrorCode.\"\"\"\n\n    GENERIC_ERROR = 0\n    REQUEST_NOT_VALID = 1\n    AGENT_ADDR_ALREADY_REGISTERED = 2\n    AGENT_NAME_ALREADY_REGISTERED = 3\n    AGENT_NOT_REGISTERED = 4\n    TRANSACTION_NOT_VALID = 5\n    TRANSACTION_NOT_MATCHING = 6\n    AGENT_NAME_NOT_IN_WHITELIST = 7\n    COMPETITION_NOT_RUNNING = 8\n    DIALOGUE_INCONSISTENT = 9\n\n    @staticmethod\n    def to_msg(error_code: int) -> str:\n        \"\"\"Get the error code.\"\"\"\n        return CODE_TO_MSG[error_code]\n\n    @staticmethod\n    def encode(error_code_protobuf_object: Any, error_code_object: \"ErrorCode\") -> None:\n        \"\"\"\n        Encode an instance of this class into the protocol buffer object.\n\n        The protocol buffer object in the error_code_protobuf_object argument is matched with the instance of this class in the 'error_code_object' argument.\n\n        :param error_code_protobuf_object: the protocol buffer object whose type corresponds with this class.\n        :param error_code_object: an instance of this class to be encoded in the protocol buffer object.\n        \"\"\"\n        error_code_protobuf_object.error_code = error_code_object.value\n\n    @classmethod\n    def decode(cls, error_code_protobuf_object: Any) -> \"ErrorCode\":\n        \"\"\"\n        Decode a protocol buffer object that corresponds with this class into an instance of this class.\n\n        A new instance of this class is created that matches the protocol buffer object in the 'error_code_protobuf_object' argument.\n\n        :param error_code_protobuf_object: the protocol buffer object whose type corresponds with this class.\n        :return: A new instance of this class that matches the protocol buffer object in the 'error_code_protobuf_object' argument.\n        \"\"\"\n        enum_value_from_pb2 = error_code_protobuf_object.error_code\n        return ErrorCode(enum_value_from_pb2)\n"
  },
  {
    "path": "packages/fetchai/protocols/tac/dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nThis module contains the classes required for tac dialogue management.\n\n- TacDialogue: The dialogue class maintains state of a dialogue and manages it.\n- TacDialogues: The dialogues class keeps track of all dialogues.\n\"\"\"\n\nfrom abc import ABC\nfrom typing import Callable, Dict, FrozenSet, Type, cast\n\nfrom aea.common import Address\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue, DialogueLabel, Dialogues\n\nfrom packages.fetchai.protocols.tac.message import TacMessage\n\n\nclass TacDialogue(Dialogue):\n    \"\"\"The tac dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    INITIAL_PERFORMATIVES: FrozenSet[Message.Performative] = frozenset(\n        {TacMessage.Performative.REGISTER}\n    )\n    TERMINAL_PERFORMATIVES: FrozenSet[Message.Performative] = frozenset(\n        {TacMessage.Performative.CANCELLED}\n    )\n    VALID_REPLIES: Dict[Message.Performative, FrozenSet[Message.Performative]] = {\n        TacMessage.Performative.CANCELLED: frozenset(),\n        TacMessage.Performative.GAME_DATA: frozenset(\n            {\n                TacMessage.Performative.TRANSACTION,\n                TacMessage.Performative.TRANSACTION_CONFIRMATION,\n                TacMessage.Performative.CANCELLED,\n            }\n        ),\n        TacMessage.Performative.REGISTER: frozenset(\n            {\n                TacMessage.Performative.TAC_ERROR,\n                TacMessage.Performative.GAME_DATA,\n                TacMessage.Performative.CANCELLED,\n                TacMessage.Performative.UNREGISTER,\n            }\n        ),\n        TacMessage.Performative.TAC_ERROR: frozenset(\n            {\n                TacMessage.Performative.TRANSACTION,\n                TacMessage.Performative.TRANSACTION_CONFIRMATION,\n                TacMessage.Performative.CANCELLED,\n            }\n        ),\n        TacMessage.Performative.TRANSACTION: frozenset(\n            {\n                TacMessage.Performative.TRANSACTION,\n                TacMessage.Performative.TRANSACTION_CONFIRMATION,\n                TacMessage.Performative.TAC_ERROR,\n                TacMessage.Performative.CANCELLED,\n            }\n        ),\n        TacMessage.Performative.TRANSACTION_CONFIRMATION: frozenset(\n            {\n                TacMessage.Performative.TRANSACTION,\n                TacMessage.Performative.TRANSACTION_CONFIRMATION,\n                TacMessage.Performative.CANCELLED,\n            }\n        ),\n        TacMessage.Performative.UNREGISTER: frozenset(\n            {TacMessage.Performative.TAC_ERROR}\n        ),\n    }\n\n    class Role(Dialogue.Role):\n        \"\"\"This class defines the agent's role in a tac dialogue.\"\"\"\n\n        CONTROLLER = \"controller\"\n        PARTICIPANT = \"participant\"\n\n    class EndState(Dialogue.EndState):\n        \"\"\"This class defines the end states of a tac dialogue.\"\"\"\n\n        SUCCESSFUL = 0\n        FAILED = 1\n\n    def __init__(\n        self,\n        dialogue_label: DialogueLabel,\n        self_address: Address,\n        role: Dialogue.Role,\n        message_class: Type[TacMessage] = TacMessage,\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n        :param message_class: the message class used\n        \"\"\"\n        Dialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            message_class=message_class,\n            self_address=self_address,\n            role=role,\n        )\n\n\nclass TacDialogues(Dialogues, ABC):\n    \"\"\"This class keeps track of all tac dialogues.\"\"\"\n\n    END_STATES = frozenset(\n        {TacDialogue.EndState.SUCCESSFUL, TacDialogue.EndState.FAILED}\n    )\n\n    _keep_terminal_state_dialogues = True\n\n    def __init__(\n        self,\n        self_address: Address,\n        role_from_first_message: Callable[[Message, Address], Dialogue.Role],\n        dialogue_class: Type[TacDialogue] = TacDialogue,\n    ) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param self_address: the address of the entity for whom dialogues are maintained\n        :param dialogue_class: the dialogue class used\n        :param role_from_first_message: the callable determining role from first message\n        \"\"\"\n        Dialogues.__init__(\n            self,\n            self_address=self_address,\n            end_states=cast(FrozenSet[Dialogue.EndState], self.END_STATES),\n            message_class=TacMessage,\n            dialogue_class=dialogue_class,\n            role_from_first_message=role_from_first_message,\n        )\n"
  },
  {
    "path": "packages/fetchai/protocols/tac/message.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains tac's message definition.\"\"\"\n\n# pylint: disable=too-many-statements,too-many-locals,no-member,too-few-public-methods,too-many-branches,not-an-iterable,unidiomatic-typecheck,unsubscriptable-object\nimport logging\nfrom typing import Any, Dict, Optional, Set, Tuple, cast\n\nfrom aea.configurations.base import PublicId\nfrom aea.exceptions import AEAEnforceError, enforce\nfrom aea.protocols.base import Message\n\nfrom packages.fetchai.protocols.tac.custom_types import ErrorCode as CustomErrorCode\n\n\n_default_logger = logging.getLogger(\"aea.packages.fetchai.protocols.tac.message\")\n\nDEFAULT_BODY_SIZE = 4\n\n\nclass TacMessage(Message):\n    \"\"\"The tac protocol implements the messages an AEA needs to participate in the TAC.\"\"\"\n\n    protocol_id = PublicId.from_str(\"fetchai/tac:1.1.7\")\n    protocol_specification_id = PublicId.from_str(\"fetchai/tac:1.0.0\")\n\n    ErrorCode = CustomErrorCode\n\n    class Performative(Message.Performative):\n        \"\"\"Performatives for the tac protocol.\"\"\"\n\n        CANCELLED = \"cancelled\"\n        GAME_DATA = \"game_data\"\n        REGISTER = \"register\"\n        TAC_ERROR = \"tac_error\"\n        TRANSACTION = \"transaction\"\n        TRANSACTION_CONFIRMATION = \"transaction_confirmation\"\n        UNREGISTER = \"unregister\"\n\n        def __str__(self) -> str:\n            \"\"\"Get the string representation.\"\"\"\n            return str(self.value)\n\n    _performatives = {\n        \"cancelled\",\n        \"game_data\",\n        \"register\",\n        \"tac_error\",\n        \"transaction\",\n        \"transaction_confirmation\",\n        \"unregister\",\n    }\n    __slots__: Tuple[str, ...] = tuple()\n\n    class _SlotsCls:\n        __slots__ = (\n            \"agent_addr_to_name\",\n            \"agent_name\",\n            \"amount_by_currency_id\",\n            \"counterparty_address\",\n            \"counterparty_signature\",\n            \"currency_id_to_name\",\n            \"dialogue_reference\",\n            \"error_code\",\n            \"exchange_params_by_currency_id\",\n            \"fee_by_currency_id\",\n            \"good_id_to_name\",\n            \"info\",\n            \"ledger_id\",\n            \"message_id\",\n            \"nonce\",\n            \"performative\",\n            \"quantities_by_good_id\",\n            \"sender_address\",\n            \"sender_signature\",\n            \"target\",\n            \"transaction_id\",\n            \"utility_params_by_good_id\",\n            \"version_id\",\n        )\n\n    def __init__(\n        self,\n        performative: Performative,\n        dialogue_reference: Tuple[str, str] = (\"\", \"\"),\n        message_id: int = 1,\n        target: int = 0,\n        **kwargs: Any,\n    ):\n        \"\"\"\n        Initialise an instance of TacMessage.\n\n        :param message_id: the message id.\n        :param dialogue_reference: the dialogue reference.\n        :param target: the message target.\n        :param performative: the message performative.\n        :param **kwargs: extra options.\n        \"\"\"\n        super().__init__(\n            dialogue_reference=dialogue_reference,\n            message_id=message_id,\n            target=target,\n            performative=TacMessage.Performative(performative),\n            **kwargs,\n        )\n\n    @property\n    def valid_performatives(self) -> Set[str]:\n        \"\"\"Get valid performatives.\"\"\"\n        return self._performatives\n\n    @property\n    def dialogue_reference(self) -> Tuple[str, str]:\n        \"\"\"Get the dialogue_reference of the message.\"\"\"\n        enforce(self.is_set(\"dialogue_reference\"), \"dialogue_reference is not set.\")\n        return cast(Tuple[str, str], self.get(\"dialogue_reference\"))\n\n    @property\n    def message_id(self) -> int:\n        \"\"\"Get the message_id of the message.\"\"\"\n        enforce(self.is_set(\"message_id\"), \"message_id is not set.\")\n        return cast(int, self.get(\"message_id\"))\n\n    @property\n    def performative(self) -> Performative:  # type: ignore # noqa: F821\n        \"\"\"Get the performative of the message.\"\"\"\n        enforce(self.is_set(\"performative\"), \"performative is not set.\")\n        return cast(TacMessage.Performative, self.get(\"performative\"))\n\n    @property\n    def target(self) -> int:\n        \"\"\"Get the target of the message.\"\"\"\n        enforce(self.is_set(\"target\"), \"target is not set.\")\n        return cast(int, self.get(\"target\"))\n\n    @property\n    def agent_addr_to_name(self) -> Dict[str, str]:\n        \"\"\"Get the 'agent_addr_to_name' content from the message.\"\"\"\n        enforce(\n            self.is_set(\"agent_addr_to_name\"),\n            \"'agent_addr_to_name' content is not set.\",\n        )\n        return cast(Dict[str, str], self.get(\"agent_addr_to_name\"))\n\n    @property\n    def agent_name(self) -> str:\n        \"\"\"Get the 'agent_name' content from the message.\"\"\"\n        enforce(self.is_set(\"agent_name\"), \"'agent_name' content is not set.\")\n        return cast(str, self.get(\"agent_name\"))\n\n    @property\n    def amount_by_currency_id(self) -> Dict[str, int]:\n        \"\"\"Get the 'amount_by_currency_id' content from the message.\"\"\"\n        enforce(\n            self.is_set(\"amount_by_currency_id\"),\n            \"'amount_by_currency_id' content is not set.\",\n        )\n        return cast(Dict[str, int], self.get(\"amount_by_currency_id\"))\n\n    @property\n    def counterparty_address(self) -> str:\n        \"\"\"Get the 'counterparty_address' content from the message.\"\"\"\n        enforce(\n            self.is_set(\"counterparty_address\"),\n            \"'counterparty_address' content is not set.\",\n        )\n        return cast(str, self.get(\"counterparty_address\"))\n\n    @property\n    def counterparty_signature(self) -> str:\n        \"\"\"Get the 'counterparty_signature' content from the message.\"\"\"\n        enforce(\n            self.is_set(\"counterparty_signature\"),\n            \"'counterparty_signature' content is not set.\",\n        )\n        return cast(str, self.get(\"counterparty_signature\"))\n\n    @property\n    def currency_id_to_name(self) -> Dict[str, str]:\n        \"\"\"Get the 'currency_id_to_name' content from the message.\"\"\"\n        enforce(\n            self.is_set(\"currency_id_to_name\"),\n            \"'currency_id_to_name' content is not set.\",\n        )\n        return cast(Dict[str, str], self.get(\"currency_id_to_name\"))\n\n    @property\n    def error_code(self) -> CustomErrorCode:\n        \"\"\"Get the 'error_code' content from the message.\"\"\"\n        enforce(self.is_set(\"error_code\"), \"'error_code' content is not set.\")\n        return cast(CustomErrorCode, self.get(\"error_code\"))\n\n    @property\n    def exchange_params_by_currency_id(self) -> Dict[str, float]:\n        \"\"\"Get the 'exchange_params_by_currency_id' content from the message.\"\"\"\n        enforce(\n            self.is_set(\"exchange_params_by_currency_id\"),\n            \"'exchange_params_by_currency_id' content is not set.\",\n        )\n        return cast(Dict[str, float], self.get(\"exchange_params_by_currency_id\"))\n\n    @property\n    def fee_by_currency_id(self) -> Dict[str, int]:\n        \"\"\"Get the 'fee_by_currency_id' content from the message.\"\"\"\n        enforce(\n            self.is_set(\"fee_by_currency_id\"),\n            \"'fee_by_currency_id' content is not set.\",\n        )\n        return cast(Dict[str, int], self.get(\"fee_by_currency_id\"))\n\n    @property\n    def good_id_to_name(self) -> Dict[str, str]:\n        \"\"\"Get the 'good_id_to_name' content from the message.\"\"\"\n        enforce(self.is_set(\"good_id_to_name\"), \"'good_id_to_name' content is not set.\")\n        return cast(Dict[str, str], self.get(\"good_id_to_name\"))\n\n    @property\n    def info(self) -> Optional[Dict[str, str]]:\n        \"\"\"Get the 'info' content from the message.\"\"\"\n        return cast(Optional[Dict[str, str]], self.get(\"info\"))\n\n    @property\n    def ledger_id(self) -> str:\n        \"\"\"Get the 'ledger_id' content from the message.\"\"\"\n        enforce(self.is_set(\"ledger_id\"), \"'ledger_id' content is not set.\")\n        return cast(str, self.get(\"ledger_id\"))\n\n    @property\n    def nonce(self) -> str:\n        \"\"\"Get the 'nonce' content from the message.\"\"\"\n        enforce(self.is_set(\"nonce\"), \"'nonce' content is not set.\")\n        return cast(str, self.get(\"nonce\"))\n\n    @property\n    def quantities_by_good_id(self) -> Dict[str, int]:\n        \"\"\"Get the 'quantities_by_good_id' content from the message.\"\"\"\n        enforce(\n            self.is_set(\"quantities_by_good_id\"),\n            \"'quantities_by_good_id' content is not set.\",\n        )\n        return cast(Dict[str, int], self.get(\"quantities_by_good_id\"))\n\n    @property\n    def sender_address(self) -> str:\n        \"\"\"Get the 'sender_address' content from the message.\"\"\"\n        enforce(self.is_set(\"sender_address\"), \"'sender_address' content is not set.\")\n        return cast(str, self.get(\"sender_address\"))\n\n    @property\n    def sender_signature(self) -> str:\n        \"\"\"Get the 'sender_signature' content from the message.\"\"\"\n        enforce(\n            self.is_set(\"sender_signature\"), \"'sender_signature' content is not set.\"\n        )\n        return cast(str, self.get(\"sender_signature\"))\n\n    @property\n    def transaction_id(self) -> str:\n        \"\"\"Get the 'transaction_id' content from the message.\"\"\"\n        enforce(self.is_set(\"transaction_id\"), \"'transaction_id' content is not set.\")\n        return cast(str, self.get(\"transaction_id\"))\n\n    @property\n    def utility_params_by_good_id(self) -> Dict[str, float]:\n        \"\"\"Get the 'utility_params_by_good_id' content from the message.\"\"\"\n        enforce(\n            self.is_set(\"utility_params_by_good_id\"),\n            \"'utility_params_by_good_id' content is not set.\",\n        )\n        return cast(Dict[str, float], self.get(\"utility_params_by_good_id\"))\n\n    @property\n    def version_id(self) -> str:\n        \"\"\"Get the 'version_id' content from the message.\"\"\"\n        enforce(self.is_set(\"version_id\"), \"'version_id' content is not set.\")\n        return cast(str, self.get(\"version_id\"))\n\n    def _is_consistent(self) -> bool:\n        \"\"\"Check that the message follows the tac protocol.\"\"\"\n        try:\n            enforce(\n                isinstance(self.dialogue_reference, tuple),\n                \"Invalid type for 'dialogue_reference'. Expected 'tuple'. Found '{}'.\".format(\n                    type(self.dialogue_reference)\n                ),\n            )\n            enforce(\n                isinstance(self.dialogue_reference[0], str),\n                \"Invalid type for 'dialogue_reference[0]'. Expected 'str'. Found '{}'.\".format(\n                    type(self.dialogue_reference[0])\n                ),\n            )\n            enforce(\n                isinstance(self.dialogue_reference[1], str),\n                \"Invalid type for 'dialogue_reference[1]'. Expected 'str'. Found '{}'.\".format(\n                    type(self.dialogue_reference[1])\n                ),\n            )\n            enforce(\n                type(self.message_id) is int,\n                \"Invalid type for 'message_id'. Expected 'int'. Found '{}'.\".format(\n                    type(self.message_id)\n                ),\n            )\n            enforce(\n                type(self.target) is int,\n                \"Invalid type for 'target'. Expected 'int'. Found '{}'.\".format(\n                    type(self.target)\n                ),\n            )\n\n            # Light Protocol Rule 2\n            # Check correct performative\n            enforce(\n                isinstance(self.performative, TacMessage.Performative),\n                \"Invalid 'performative'. Expected either of '{}'. Found '{}'.\".format(\n                    self.valid_performatives, self.performative\n                ),\n            )\n\n            # Check correct contents\n            actual_nb_of_contents = len(self._body) - DEFAULT_BODY_SIZE\n            expected_nb_of_contents = 0\n            if self.performative == TacMessage.Performative.REGISTER:\n                expected_nb_of_contents = 1\n                enforce(\n                    isinstance(self.agent_name, str),\n                    \"Invalid type for content 'agent_name'. Expected 'str'. Found '{}'.\".format(\n                        type(self.agent_name)\n                    ),\n                )\n            elif self.performative == TacMessage.Performative.UNREGISTER:\n                expected_nb_of_contents = 0\n            elif self.performative == TacMessage.Performative.TRANSACTION:\n                expected_nb_of_contents = 10\n                enforce(\n                    isinstance(self.transaction_id, str),\n                    \"Invalid type for content 'transaction_id'. Expected 'str'. Found '{}'.\".format(\n                        type(self.transaction_id)\n                    ),\n                )\n                enforce(\n                    isinstance(self.ledger_id, str),\n                    \"Invalid type for content 'ledger_id'. Expected 'str'. Found '{}'.\".format(\n                        type(self.ledger_id)\n                    ),\n                )\n                enforce(\n                    isinstance(self.sender_address, str),\n                    \"Invalid type for content 'sender_address'. Expected 'str'. Found '{}'.\".format(\n                        type(self.sender_address)\n                    ),\n                )\n                enforce(\n                    isinstance(self.counterparty_address, str),\n                    \"Invalid type for content 'counterparty_address'. Expected 'str'. Found '{}'.\".format(\n                        type(self.counterparty_address)\n                    ),\n                )\n                enforce(\n                    isinstance(self.amount_by_currency_id, dict),\n                    \"Invalid type for content 'amount_by_currency_id'. Expected 'dict'. Found '{}'.\".format(\n                        type(self.amount_by_currency_id)\n                    ),\n                )\n                for (\n                    key_of_amount_by_currency_id,\n                    value_of_amount_by_currency_id,\n                ) in self.amount_by_currency_id.items():\n                    enforce(\n                        isinstance(key_of_amount_by_currency_id, str),\n                        \"Invalid type for dictionary keys in content 'amount_by_currency_id'. Expected 'str'. Found '{}'.\".format(\n                            type(key_of_amount_by_currency_id)\n                        ),\n                    )\n                    enforce(\n                        type(value_of_amount_by_currency_id) is int,\n                        \"Invalid type for dictionary values in content 'amount_by_currency_id'. Expected 'int'. Found '{}'.\".format(\n                            type(value_of_amount_by_currency_id)\n                        ),\n                    )\n                enforce(\n                    isinstance(self.fee_by_currency_id, dict),\n                    \"Invalid type for content 'fee_by_currency_id'. Expected 'dict'. Found '{}'.\".format(\n                        type(self.fee_by_currency_id)\n                    ),\n                )\n                for (\n                    key_of_fee_by_currency_id,\n                    value_of_fee_by_currency_id,\n                ) in self.fee_by_currency_id.items():\n                    enforce(\n                        isinstance(key_of_fee_by_currency_id, str),\n                        \"Invalid type for dictionary keys in content 'fee_by_currency_id'. Expected 'str'. Found '{}'.\".format(\n                            type(key_of_fee_by_currency_id)\n                        ),\n                    )\n                    enforce(\n                        type(value_of_fee_by_currency_id) is int,\n                        \"Invalid type for dictionary values in content 'fee_by_currency_id'. Expected 'int'. Found '{}'.\".format(\n                            type(value_of_fee_by_currency_id)\n                        ),\n                    )\n                enforce(\n                    isinstance(self.quantities_by_good_id, dict),\n                    \"Invalid type for content 'quantities_by_good_id'. Expected 'dict'. Found '{}'.\".format(\n                        type(self.quantities_by_good_id)\n                    ),\n                )\n                for (\n                    key_of_quantities_by_good_id,\n                    value_of_quantities_by_good_id,\n                ) in self.quantities_by_good_id.items():\n                    enforce(\n                        isinstance(key_of_quantities_by_good_id, str),\n                        \"Invalid type for dictionary keys in content 'quantities_by_good_id'. Expected 'str'. Found '{}'.\".format(\n                            type(key_of_quantities_by_good_id)\n                        ),\n                    )\n                    enforce(\n                        type(value_of_quantities_by_good_id) is int,\n                        \"Invalid type for dictionary values in content 'quantities_by_good_id'. Expected 'int'. Found '{}'.\".format(\n                            type(value_of_quantities_by_good_id)\n                        ),\n                    )\n                enforce(\n                    isinstance(self.nonce, str),\n                    \"Invalid type for content 'nonce'. Expected 'str'. Found '{}'.\".format(\n                        type(self.nonce)\n                    ),\n                )\n                enforce(\n                    isinstance(self.sender_signature, str),\n                    \"Invalid type for content 'sender_signature'. Expected 'str'. Found '{}'.\".format(\n                        type(self.sender_signature)\n                    ),\n                )\n                enforce(\n                    isinstance(self.counterparty_signature, str),\n                    \"Invalid type for content 'counterparty_signature'. Expected 'str'. Found '{}'.\".format(\n                        type(self.counterparty_signature)\n                    ),\n                )\n            elif self.performative == TacMessage.Performative.CANCELLED:\n                expected_nb_of_contents = 0\n            elif self.performative == TacMessage.Performative.GAME_DATA:\n                expected_nb_of_contents = 9\n                enforce(\n                    isinstance(self.amount_by_currency_id, dict),\n                    \"Invalid type for content 'amount_by_currency_id'. Expected 'dict'. Found '{}'.\".format(\n                        type(self.amount_by_currency_id)\n                    ),\n                )\n                for (\n                    key_of_amount_by_currency_id,\n                    value_of_amount_by_currency_id,\n                ) in self.amount_by_currency_id.items():\n                    enforce(\n                        isinstance(key_of_amount_by_currency_id, str),\n                        \"Invalid type for dictionary keys in content 'amount_by_currency_id'. Expected 'str'. Found '{}'.\".format(\n                            type(key_of_amount_by_currency_id)\n                        ),\n                    )\n                    enforce(\n                        type(value_of_amount_by_currency_id) is int,\n                        \"Invalid type for dictionary values in content 'amount_by_currency_id'. Expected 'int'. Found '{}'.\".format(\n                            type(value_of_amount_by_currency_id)\n                        ),\n                    )\n                enforce(\n                    isinstance(self.exchange_params_by_currency_id, dict),\n                    \"Invalid type for content 'exchange_params_by_currency_id'. Expected 'dict'. Found '{}'.\".format(\n                        type(self.exchange_params_by_currency_id)\n                    ),\n                )\n                for (\n                    key_of_exchange_params_by_currency_id,\n                    value_of_exchange_params_by_currency_id,\n                ) in self.exchange_params_by_currency_id.items():\n                    enforce(\n                        isinstance(key_of_exchange_params_by_currency_id, str),\n                        \"Invalid type for dictionary keys in content 'exchange_params_by_currency_id'. Expected 'str'. Found '{}'.\".format(\n                            type(key_of_exchange_params_by_currency_id)\n                        ),\n                    )\n                    enforce(\n                        isinstance(value_of_exchange_params_by_currency_id, float),\n                        \"Invalid type for dictionary values in content 'exchange_params_by_currency_id'. Expected 'float'. Found '{}'.\".format(\n                            type(value_of_exchange_params_by_currency_id)\n                        ),\n                    )\n                enforce(\n                    isinstance(self.quantities_by_good_id, dict),\n                    \"Invalid type for content 'quantities_by_good_id'. Expected 'dict'. Found '{}'.\".format(\n                        type(self.quantities_by_good_id)\n                    ),\n                )\n                for (\n                    key_of_quantities_by_good_id,\n                    value_of_quantities_by_good_id,\n                ) in self.quantities_by_good_id.items():\n                    enforce(\n                        isinstance(key_of_quantities_by_good_id, str),\n                        \"Invalid type for dictionary keys in content 'quantities_by_good_id'. Expected 'str'. Found '{}'.\".format(\n                            type(key_of_quantities_by_good_id)\n                        ),\n                    )\n                    enforce(\n                        type(value_of_quantities_by_good_id) is int,\n                        \"Invalid type for dictionary values in content 'quantities_by_good_id'. Expected 'int'. Found '{}'.\".format(\n                            type(value_of_quantities_by_good_id)\n                        ),\n                    )\n                enforce(\n                    isinstance(self.utility_params_by_good_id, dict),\n                    \"Invalid type for content 'utility_params_by_good_id'. Expected 'dict'. Found '{}'.\".format(\n                        type(self.utility_params_by_good_id)\n                    ),\n                )\n                for (\n                    key_of_utility_params_by_good_id,\n                    value_of_utility_params_by_good_id,\n                ) in self.utility_params_by_good_id.items():\n                    enforce(\n                        isinstance(key_of_utility_params_by_good_id, str),\n                        \"Invalid type for dictionary keys in content 'utility_params_by_good_id'. Expected 'str'. Found '{}'.\".format(\n                            type(key_of_utility_params_by_good_id)\n                        ),\n                    )\n                    enforce(\n                        isinstance(value_of_utility_params_by_good_id, float),\n                        \"Invalid type for dictionary values in content 'utility_params_by_good_id'. Expected 'float'. Found '{}'.\".format(\n                            type(value_of_utility_params_by_good_id)\n                        ),\n                    )\n                enforce(\n                    isinstance(self.fee_by_currency_id, dict),\n                    \"Invalid type for content 'fee_by_currency_id'. Expected 'dict'. Found '{}'.\".format(\n                        type(self.fee_by_currency_id)\n                    ),\n                )\n                for (\n                    key_of_fee_by_currency_id,\n                    value_of_fee_by_currency_id,\n                ) in self.fee_by_currency_id.items():\n                    enforce(\n                        isinstance(key_of_fee_by_currency_id, str),\n                        \"Invalid type for dictionary keys in content 'fee_by_currency_id'. Expected 'str'. Found '{}'.\".format(\n                            type(key_of_fee_by_currency_id)\n                        ),\n                    )\n                    enforce(\n                        type(value_of_fee_by_currency_id) is int,\n                        \"Invalid type for dictionary values in content 'fee_by_currency_id'. Expected 'int'. Found '{}'.\".format(\n                            type(value_of_fee_by_currency_id)\n                        ),\n                    )\n                enforce(\n                    isinstance(self.agent_addr_to_name, dict),\n                    \"Invalid type for content 'agent_addr_to_name'. Expected 'dict'. Found '{}'.\".format(\n                        type(self.agent_addr_to_name)\n                    ),\n                )\n                for (\n                    key_of_agent_addr_to_name,\n                    value_of_agent_addr_to_name,\n                ) in self.agent_addr_to_name.items():\n                    enforce(\n                        isinstance(key_of_agent_addr_to_name, str),\n                        \"Invalid type for dictionary keys in content 'agent_addr_to_name'. Expected 'str'. Found '{}'.\".format(\n                            type(key_of_agent_addr_to_name)\n                        ),\n                    )\n                    enforce(\n                        isinstance(value_of_agent_addr_to_name, str),\n                        \"Invalid type for dictionary values in content 'agent_addr_to_name'. Expected 'str'. Found '{}'.\".format(\n                            type(value_of_agent_addr_to_name)\n                        ),\n                    )\n                enforce(\n                    isinstance(self.currency_id_to_name, dict),\n                    \"Invalid type for content 'currency_id_to_name'. Expected 'dict'. Found '{}'.\".format(\n                        type(self.currency_id_to_name)\n                    ),\n                )\n                for (\n                    key_of_currency_id_to_name,\n                    value_of_currency_id_to_name,\n                ) in self.currency_id_to_name.items():\n                    enforce(\n                        isinstance(key_of_currency_id_to_name, str),\n                        \"Invalid type for dictionary keys in content 'currency_id_to_name'. Expected 'str'. Found '{}'.\".format(\n                            type(key_of_currency_id_to_name)\n                        ),\n                    )\n                    enforce(\n                        isinstance(value_of_currency_id_to_name, str),\n                        \"Invalid type for dictionary values in content 'currency_id_to_name'. Expected 'str'. Found '{}'.\".format(\n                            type(value_of_currency_id_to_name)\n                        ),\n                    )\n                enforce(\n                    isinstance(self.good_id_to_name, dict),\n                    \"Invalid type for content 'good_id_to_name'. Expected 'dict'. Found '{}'.\".format(\n                        type(self.good_id_to_name)\n                    ),\n                )\n                for (\n                    key_of_good_id_to_name,\n                    value_of_good_id_to_name,\n                ) in self.good_id_to_name.items():\n                    enforce(\n                        isinstance(key_of_good_id_to_name, str),\n                        \"Invalid type for dictionary keys in content 'good_id_to_name'. Expected 'str'. Found '{}'.\".format(\n                            type(key_of_good_id_to_name)\n                        ),\n                    )\n                    enforce(\n                        isinstance(value_of_good_id_to_name, str),\n                        \"Invalid type for dictionary values in content 'good_id_to_name'. Expected 'str'. Found '{}'.\".format(\n                            type(value_of_good_id_to_name)\n                        ),\n                    )\n                enforce(\n                    isinstance(self.version_id, str),\n                    \"Invalid type for content 'version_id'. Expected 'str'. Found '{}'.\".format(\n                        type(self.version_id)\n                    ),\n                )\n                if self.is_set(\"info\"):\n                    expected_nb_of_contents += 1\n                    info = cast(Dict[str, str], self.info)\n                    enforce(\n                        isinstance(info, dict),\n                        \"Invalid type for content 'info'. Expected 'dict'. Found '{}'.\".format(\n                            type(info)\n                        ),\n                    )\n                    for key_of_info, value_of_info in info.items():\n                        enforce(\n                            isinstance(key_of_info, str),\n                            \"Invalid type for dictionary keys in content 'info'. Expected 'str'. Found '{}'.\".format(\n                                type(key_of_info)\n                            ),\n                        )\n                        enforce(\n                            isinstance(value_of_info, str),\n                            \"Invalid type for dictionary values in content 'info'. Expected 'str'. Found '{}'.\".format(\n                                type(value_of_info)\n                            ),\n                        )\n            elif self.performative == TacMessage.Performative.TRANSACTION_CONFIRMATION:\n                expected_nb_of_contents = 3\n                enforce(\n                    isinstance(self.transaction_id, str),\n                    \"Invalid type for content 'transaction_id'. Expected 'str'. Found '{}'.\".format(\n                        type(self.transaction_id)\n                    ),\n                )\n                enforce(\n                    isinstance(self.amount_by_currency_id, dict),\n                    \"Invalid type for content 'amount_by_currency_id'. Expected 'dict'. Found '{}'.\".format(\n                        type(self.amount_by_currency_id)\n                    ),\n                )\n                for (\n                    key_of_amount_by_currency_id,\n                    value_of_amount_by_currency_id,\n                ) in self.amount_by_currency_id.items():\n                    enforce(\n                        isinstance(key_of_amount_by_currency_id, str),\n                        \"Invalid type for dictionary keys in content 'amount_by_currency_id'. Expected 'str'. Found '{}'.\".format(\n                            type(key_of_amount_by_currency_id)\n                        ),\n                    )\n                    enforce(\n                        type(value_of_amount_by_currency_id) is int,\n                        \"Invalid type for dictionary values in content 'amount_by_currency_id'. Expected 'int'. Found '{}'.\".format(\n                            type(value_of_amount_by_currency_id)\n                        ),\n                    )\n                enforce(\n                    isinstance(self.quantities_by_good_id, dict),\n                    \"Invalid type for content 'quantities_by_good_id'. Expected 'dict'. Found '{}'.\".format(\n                        type(self.quantities_by_good_id)\n                    ),\n                )\n                for (\n                    key_of_quantities_by_good_id,\n                    value_of_quantities_by_good_id,\n                ) in self.quantities_by_good_id.items():\n                    enforce(\n                        isinstance(key_of_quantities_by_good_id, str),\n                        \"Invalid type for dictionary keys in content 'quantities_by_good_id'. Expected 'str'. Found '{}'.\".format(\n                            type(key_of_quantities_by_good_id)\n                        ),\n                    )\n                    enforce(\n                        type(value_of_quantities_by_good_id) is int,\n                        \"Invalid type for dictionary values in content 'quantities_by_good_id'. Expected 'int'. Found '{}'.\".format(\n                            type(value_of_quantities_by_good_id)\n                        ),\n                    )\n            elif self.performative == TacMessage.Performative.TAC_ERROR:\n                expected_nb_of_contents = 1\n                enforce(\n                    isinstance(self.error_code, CustomErrorCode),\n                    \"Invalid type for content 'error_code'. Expected 'ErrorCode'. Found '{}'.\".format(\n                        type(self.error_code)\n                    ),\n                )\n                if self.is_set(\"info\"):\n                    expected_nb_of_contents += 1\n                    info = cast(Dict[str, str], self.info)\n                    enforce(\n                        isinstance(info, dict),\n                        \"Invalid type for content 'info'. Expected 'dict'. Found '{}'.\".format(\n                            type(info)\n                        ),\n                    )\n                    for key_of_info, value_of_info in info.items():\n                        enforce(\n                            isinstance(key_of_info, str),\n                            \"Invalid type for dictionary keys in content 'info'. Expected 'str'. Found '{}'.\".format(\n                                type(key_of_info)\n                            ),\n                        )\n                        enforce(\n                            isinstance(value_of_info, str),\n                            \"Invalid type for dictionary values in content 'info'. Expected 'str'. Found '{}'.\".format(\n                                type(value_of_info)\n                            ),\n                        )\n\n            # Check correct content count\n            enforce(\n                expected_nb_of_contents == actual_nb_of_contents,\n                \"Incorrect number of contents. Expected {}. Found {}\".format(\n                    expected_nb_of_contents, actual_nb_of_contents\n                ),\n            )\n\n            # Light Protocol Rule 3\n            if self.message_id == 1:\n                enforce(\n                    self.target == 0,\n                    \"Invalid 'target'. Expected 0 (because 'message_id' is 1). Found {}.\".format(\n                        self.target\n                    ),\n                )\n        except (AEAEnforceError, ValueError, KeyError) as e:\n            _default_logger.error(str(e))\n            return False\n\n        return True\n"
  },
  {
    "path": "packages/fetchai/protocols/tac/protocol.yaml",
    "content": "name: tac\nauthor: fetchai\nversion: 1.1.7\nprotocol_specification_id: fetchai/tac:1.0.0\ntype: protocol\ndescription: The tac protocol implements the messages an AEA needs to participate\n  in the TAC.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: QmZdoSoTZHxvDbwdxm6d7xgRjCqvzNDcvhpUKS2inKUAaV\n  __init__.py: QmNxUNMKkhimqesJ52WFyG1jZqXC9CNo7ftsao9EKwAqay\n  custom_types.py: QmWUg194r4jqm6U2SY4B9CADn2bNE56qrpWJrVnGPvSz8v\n  dialogues.py: QmRhZrnyT4YaXsPXAr1ota3ndp64MAcc3XNcGF2sCN4z4Q\n  message.py: QmT3aDoBkR7VYoC9BEnMqNLJFZycSjcPGjG4ThUJNMjRgG\n  serialization.py: QmdHc6cF7GM6eMD3VqNjAwibvY9Bnd98SxvTrzDJW5tsAM\n  tac.proto: QmVLyb1hc9SmouyhBXT2g8RYHsyitqxqDMssnMnPj5AhCx\n  tac_pb2.py: QmdzW9DyYGaEA6evnb4mVHQRkxRyzmgiN1LdiFrck9T6Ai\nfingerprint_ignore_patterns: []\ndependencies:\n  protobuf: {}\n"
  },
  {
    "path": "packages/fetchai/protocols/tac/serialization.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Serialization module for tac protocol.\"\"\"\n\n# pylint: disable=too-many-statements,too-many-locals,no-member,too-few-public-methods,redefined-builtin\nfrom typing import Any, Dict, cast\n\nfrom aea.mail.base_pb2 import DialogueMessage\nfrom aea.mail.base_pb2 import Message as ProtobufMessage\nfrom aea.protocols.base import Message, Serializer\n\nfrom packages.fetchai.protocols.tac import tac_pb2\nfrom packages.fetchai.protocols.tac.custom_types import ErrorCode\nfrom packages.fetchai.protocols.tac.message import TacMessage\n\n\nclass TacSerializer(Serializer):\n    \"\"\"Serialization for the 'tac' protocol.\"\"\"\n\n    @staticmethod\n    def encode(msg: Message) -> bytes:\n        \"\"\"\n        Encode a 'Tac' message into bytes.\n\n        :param msg: the message object.\n        :return: the bytes.\n        \"\"\"\n        msg = cast(TacMessage, msg)\n        message_pb = ProtobufMessage()\n        dialogue_message_pb = DialogueMessage()\n        tac_msg = tac_pb2.TacMessage()\n\n        dialogue_message_pb.message_id = msg.message_id\n        dialogue_reference = msg.dialogue_reference\n        dialogue_message_pb.dialogue_starter_reference = dialogue_reference[0]\n        dialogue_message_pb.dialogue_responder_reference = dialogue_reference[1]\n        dialogue_message_pb.target = msg.target\n\n        performative_id = msg.performative\n        if performative_id == TacMessage.Performative.REGISTER:\n            performative = tac_pb2.TacMessage.Register_Performative()  # type: ignore\n            agent_name = msg.agent_name\n            performative.agent_name = agent_name\n            tac_msg.register.CopyFrom(performative)\n        elif performative_id == TacMessage.Performative.UNREGISTER:\n            performative = tac_pb2.TacMessage.Unregister_Performative()  # type: ignore\n            tac_msg.unregister.CopyFrom(performative)\n        elif performative_id == TacMessage.Performative.TRANSACTION:\n            performative = tac_pb2.TacMessage.Transaction_Performative()  # type: ignore\n            transaction_id = msg.transaction_id\n            performative.transaction_id = transaction_id\n            ledger_id = msg.ledger_id\n            performative.ledger_id = ledger_id\n            sender_address = msg.sender_address\n            performative.sender_address = sender_address\n            counterparty_address = msg.counterparty_address\n            performative.counterparty_address = counterparty_address\n            amount_by_currency_id = msg.amount_by_currency_id\n            performative.amount_by_currency_id.update(amount_by_currency_id)\n            fee_by_currency_id = msg.fee_by_currency_id\n            performative.fee_by_currency_id.update(fee_by_currency_id)\n            quantities_by_good_id = msg.quantities_by_good_id\n            performative.quantities_by_good_id.update(quantities_by_good_id)\n            nonce = msg.nonce\n            performative.nonce = nonce\n            sender_signature = msg.sender_signature\n            performative.sender_signature = sender_signature\n            counterparty_signature = msg.counterparty_signature\n            performative.counterparty_signature = counterparty_signature\n            tac_msg.transaction.CopyFrom(performative)\n        elif performative_id == TacMessage.Performative.CANCELLED:\n            performative = tac_pb2.TacMessage.Cancelled_Performative()  # type: ignore\n            tac_msg.cancelled.CopyFrom(performative)\n        elif performative_id == TacMessage.Performative.GAME_DATA:\n            performative = tac_pb2.TacMessage.Game_Data_Performative()  # type: ignore\n            amount_by_currency_id = msg.amount_by_currency_id\n            performative.amount_by_currency_id.update(amount_by_currency_id)\n            exchange_params_by_currency_id = msg.exchange_params_by_currency_id\n            performative.exchange_params_by_currency_id.update(\n                exchange_params_by_currency_id\n            )\n            quantities_by_good_id = msg.quantities_by_good_id\n            performative.quantities_by_good_id.update(quantities_by_good_id)\n            utility_params_by_good_id = msg.utility_params_by_good_id\n            performative.utility_params_by_good_id.update(utility_params_by_good_id)\n            fee_by_currency_id = msg.fee_by_currency_id\n            performative.fee_by_currency_id.update(fee_by_currency_id)\n            agent_addr_to_name = msg.agent_addr_to_name\n            performative.agent_addr_to_name.update(agent_addr_to_name)\n            currency_id_to_name = msg.currency_id_to_name\n            performative.currency_id_to_name.update(currency_id_to_name)\n            good_id_to_name = msg.good_id_to_name\n            performative.good_id_to_name.update(good_id_to_name)\n            version_id = msg.version_id\n            performative.version_id = version_id\n            if msg.is_set(\"info\"):\n                performative.info_is_set = True\n                info = msg.info\n                performative.info.update(info)\n            tac_msg.game_data.CopyFrom(performative)\n        elif performative_id == TacMessage.Performative.TRANSACTION_CONFIRMATION:\n            performative = tac_pb2.TacMessage.Transaction_Confirmation_Performative()  # type: ignore\n            transaction_id = msg.transaction_id\n            performative.transaction_id = transaction_id\n            amount_by_currency_id = msg.amount_by_currency_id\n            performative.amount_by_currency_id.update(amount_by_currency_id)\n            quantities_by_good_id = msg.quantities_by_good_id\n            performative.quantities_by_good_id.update(quantities_by_good_id)\n            tac_msg.transaction_confirmation.CopyFrom(performative)\n        elif performative_id == TacMessage.Performative.TAC_ERROR:\n            performative = tac_pb2.TacMessage.Tac_Error_Performative()  # type: ignore\n            error_code = msg.error_code\n            ErrorCode.encode(performative.error_code, error_code)\n            if msg.is_set(\"info\"):\n                performative.info_is_set = True\n                info = msg.info\n                performative.info.update(info)\n            tac_msg.tac_error.CopyFrom(performative)\n        else:\n            raise ValueError(\"Performative not valid: {}\".format(performative_id))\n\n        dialogue_message_pb.content = tac_msg.SerializeToString()\n\n        message_pb.dialogue_message.CopyFrom(dialogue_message_pb)\n        message_bytes = message_pb.SerializeToString()\n        return message_bytes\n\n    @staticmethod\n    def decode(obj: bytes) -> Message:\n        \"\"\"\n        Decode bytes into a 'Tac' message.\n\n        :param obj: the bytes object.\n        :return: the 'Tac' message.\n        \"\"\"\n        message_pb = ProtobufMessage()\n        tac_pb = tac_pb2.TacMessage()\n        message_pb.ParseFromString(obj)\n        message_id = message_pb.dialogue_message.message_id\n        dialogue_reference = (\n            message_pb.dialogue_message.dialogue_starter_reference,\n            message_pb.dialogue_message.dialogue_responder_reference,\n        )\n        target = message_pb.dialogue_message.target\n\n        tac_pb.ParseFromString(message_pb.dialogue_message.content)\n        performative = tac_pb.WhichOneof(\"performative\")\n        performative_id = TacMessage.Performative(str(performative))\n        performative_content = {}  # type: Dict[str, Any]\n        if performative_id == TacMessage.Performative.REGISTER:\n            agent_name = tac_pb.register.agent_name\n            performative_content[\"agent_name\"] = agent_name\n        elif performative_id == TacMessage.Performative.UNREGISTER:\n            pass\n        elif performative_id == TacMessage.Performative.TRANSACTION:\n            transaction_id = tac_pb.transaction.transaction_id\n            performative_content[\"transaction_id\"] = transaction_id\n            ledger_id = tac_pb.transaction.ledger_id\n            performative_content[\"ledger_id\"] = ledger_id\n            sender_address = tac_pb.transaction.sender_address\n            performative_content[\"sender_address\"] = sender_address\n            counterparty_address = tac_pb.transaction.counterparty_address\n            performative_content[\"counterparty_address\"] = counterparty_address\n            amount_by_currency_id = tac_pb.transaction.amount_by_currency_id\n            amount_by_currency_id_dict = dict(amount_by_currency_id)\n            performative_content[\"amount_by_currency_id\"] = amount_by_currency_id_dict\n            fee_by_currency_id = tac_pb.transaction.fee_by_currency_id\n            fee_by_currency_id_dict = dict(fee_by_currency_id)\n            performative_content[\"fee_by_currency_id\"] = fee_by_currency_id_dict\n            quantities_by_good_id = tac_pb.transaction.quantities_by_good_id\n            quantities_by_good_id_dict = dict(quantities_by_good_id)\n            performative_content[\"quantities_by_good_id\"] = quantities_by_good_id_dict\n            nonce = tac_pb.transaction.nonce\n            performative_content[\"nonce\"] = nonce\n            sender_signature = tac_pb.transaction.sender_signature\n            performative_content[\"sender_signature\"] = sender_signature\n            counterparty_signature = tac_pb.transaction.counterparty_signature\n            performative_content[\"counterparty_signature\"] = counterparty_signature\n        elif performative_id == TacMessage.Performative.CANCELLED:\n            pass\n        elif performative_id == TacMessage.Performative.GAME_DATA:\n            amount_by_currency_id = tac_pb.game_data.amount_by_currency_id\n            amount_by_currency_id_dict = dict(amount_by_currency_id)\n            performative_content[\"amount_by_currency_id\"] = amount_by_currency_id_dict\n            exchange_params_by_currency_id = (\n                tac_pb.game_data.exchange_params_by_currency_id\n            )\n            exchange_params_by_currency_id_dict = dict(exchange_params_by_currency_id)\n            performative_content[\n                \"exchange_params_by_currency_id\"\n            ] = exchange_params_by_currency_id_dict\n            quantities_by_good_id = tac_pb.game_data.quantities_by_good_id\n            quantities_by_good_id_dict = dict(quantities_by_good_id)\n            performative_content[\"quantities_by_good_id\"] = quantities_by_good_id_dict\n            utility_params_by_good_id = tac_pb.game_data.utility_params_by_good_id\n            utility_params_by_good_id_dict = dict(utility_params_by_good_id)\n            performative_content[\n                \"utility_params_by_good_id\"\n            ] = utility_params_by_good_id_dict\n            fee_by_currency_id = tac_pb.game_data.fee_by_currency_id\n            fee_by_currency_id_dict = dict(fee_by_currency_id)\n            performative_content[\"fee_by_currency_id\"] = fee_by_currency_id_dict\n            agent_addr_to_name = tac_pb.game_data.agent_addr_to_name\n            agent_addr_to_name_dict = dict(agent_addr_to_name)\n            performative_content[\"agent_addr_to_name\"] = agent_addr_to_name_dict\n            currency_id_to_name = tac_pb.game_data.currency_id_to_name\n            currency_id_to_name_dict = dict(currency_id_to_name)\n            performative_content[\"currency_id_to_name\"] = currency_id_to_name_dict\n            good_id_to_name = tac_pb.game_data.good_id_to_name\n            good_id_to_name_dict = dict(good_id_to_name)\n            performative_content[\"good_id_to_name\"] = good_id_to_name_dict\n            version_id = tac_pb.game_data.version_id\n            performative_content[\"version_id\"] = version_id\n            if tac_pb.game_data.info_is_set:\n                info = tac_pb.game_data.info\n                info_dict = dict(info)\n                performative_content[\"info\"] = info_dict\n        elif performative_id == TacMessage.Performative.TRANSACTION_CONFIRMATION:\n            transaction_id = tac_pb.transaction_confirmation.transaction_id\n            performative_content[\"transaction_id\"] = transaction_id\n            amount_by_currency_id = (\n                tac_pb.transaction_confirmation.amount_by_currency_id\n            )\n            amount_by_currency_id_dict = dict(amount_by_currency_id)\n            performative_content[\"amount_by_currency_id\"] = amount_by_currency_id_dict\n            quantities_by_good_id = (\n                tac_pb.transaction_confirmation.quantities_by_good_id\n            )\n            quantities_by_good_id_dict = dict(quantities_by_good_id)\n            performative_content[\"quantities_by_good_id\"] = quantities_by_good_id_dict\n        elif performative_id == TacMessage.Performative.TAC_ERROR:\n            pb2_error_code = tac_pb.tac_error.error_code\n            error_code = ErrorCode.decode(pb2_error_code)\n            performative_content[\"error_code\"] = error_code\n            if tac_pb.tac_error.info_is_set:\n                info = tac_pb.tac_error.info\n                info_dict = dict(info)\n                performative_content[\"info\"] = info_dict\n        else:\n            raise ValueError(\"Performative not valid: {}.\".format(performative_id))\n\n        return TacMessage(\n            message_id=message_id,\n            dialogue_reference=dialogue_reference,\n            target=target,\n            performative=performative,\n            **performative_content\n        )\n"
  },
  {
    "path": "packages/fetchai/protocols/tac/tac.proto",
    "content": "syntax = \"proto3\";\n\npackage aea.fetchai.tac.v1_0_0;\n\nmessage TacMessage{\n\n  // Custom Types\n  message ErrorCode{\n    enum ErrorCodeEnum {\n      GENERIC_ERROR = 0;\n      REQUEST_NOT_VALID = 1;\n      AGENT_ADDR_ALREADY_REGISTERED = 2;\n      AGENT_NAME_ALREADY_REGISTERED = 3;\n      AGENT_NOT_REGISTERED = 4;\n      TRANSACTION_NOT_VALID = 5;\n      TRANSACTION_NOT_MATCHING = 6;\n      AGENT_NAME_NOT_IN_WHITELIST = 7;\n      COMPETITION_NOT_RUNNING = 8;\n      DIALOGUE_INCONSISTENT = 9;\n    }\n    ErrorCodeEnum error_code = 1;\n  }\n\n\n  // Performatives and contents\n  message Register_Performative{\n    string agent_name = 1;\n  }\n\n  message Unregister_Performative{\n  }\n\n  message Transaction_Performative{\n    string transaction_id = 1;\n    string ledger_id = 2;\n    string sender_address = 3;\n    string counterparty_address = 4;\n    map<string, int64> amount_by_currency_id = 5;\n    map<string, int64> fee_by_currency_id = 6;\n    map<string, int64> quantities_by_good_id = 7;\n    string nonce = 8;\n    string sender_signature = 9;\n    string counterparty_signature = 10;\n  }\n\n  message Cancelled_Performative{\n  }\n\n  message Game_Data_Performative{\n    map<string, int64> amount_by_currency_id = 1;\n    map<string, float> exchange_params_by_currency_id = 2;\n    map<string, int64> quantities_by_good_id = 3;\n    map<string, float> utility_params_by_good_id = 4;\n    map<string, int64> fee_by_currency_id = 5;\n    map<string, string> agent_addr_to_name = 6;\n    map<string, string> currency_id_to_name = 7;\n    map<string, string> good_id_to_name = 8;\n    string version_id = 9;\n    map<string, string> info = 10;\n    bool info_is_set = 11;\n  }\n\n  message Transaction_Confirmation_Performative{\n    string transaction_id = 1;\n    map<string, int64> amount_by_currency_id = 2;\n    map<string, int64> quantities_by_good_id = 3;\n  }\n\n  message Tac_Error_Performative{\n    ErrorCode error_code = 1;\n    map<string, string> info = 2;\n    bool info_is_set = 3;\n  }\n\n\n  oneof performative{\n    Cancelled_Performative cancelled = 5;\n    Game_Data_Performative game_data = 6;\n    Register_Performative register = 7;\n    Tac_Error_Performative tac_error = 8;\n    Transaction_Performative transaction = 9;\n    Transaction_Confirmation_Performative transaction_confirmation = 10;\n    Unregister_Performative unregister = 11;\n  }\n}\n"
  },
  {
    "path": "packages/fetchai/protocols/tac/tac_pb2.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by the protocol buffer compiler.  DO NOT EDIT!\n# source: tac.proto\n\"\"\"Generated protocol buffer code.\"\"\"\nfrom google.protobuf import descriptor as _descriptor\nfrom google.protobuf import descriptor_pool as _descriptor_pool\nfrom google.protobuf import message as _message\nfrom google.protobuf import reflection as _reflection\nfrom google.protobuf import symbol_database as _symbol_database\n\n# @@protoc_insertion_point(imports)\n\n_sym_db = _symbol_database.Default()\n\n\nDESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(\n    b'\\n\\ttac.proto\\x12\\x16\\x61\\x65\\x61.fetchai.tac.v1_0_0\"\\xf9\\x1f\\n\\nTacMessage\\x12N\\n\\tcancelled\\x18\\x05 \\x01(\\x0b\\x32\\x39.aea.fetchai.tac.v1_0_0.TacMessage.Cancelled_PerformativeH\\x00\\x12N\\n\\tgame_data\\x18\\x06 \\x01(\\x0b\\x32\\x39.aea.fetchai.tac.v1_0_0.TacMessage.Game_Data_PerformativeH\\x00\\x12L\\n\\x08register\\x18\\x07 \\x01(\\x0b\\x32\\x38.aea.fetchai.tac.v1_0_0.TacMessage.Register_PerformativeH\\x00\\x12N\\n\\ttac_error\\x18\\x08 \\x01(\\x0b\\x32\\x39.aea.fetchai.tac.v1_0_0.TacMessage.Tac_Error_PerformativeH\\x00\\x12R\\n\\x0btransaction\\x18\\t \\x01(\\x0b\\x32;.aea.fetchai.tac.v1_0_0.TacMessage.Transaction_PerformativeH\\x00\\x12l\\n\\x18transaction_confirmation\\x18\\n \\x01(\\x0b\\x32H.aea.fetchai.tac.v1_0_0.TacMessage.Transaction_Confirmation_PerformativeH\\x00\\x12P\\n\\nunregister\\x18\\x0b \\x01(\\x0b\\x32:.aea.fetchai.tac.v1_0_0.TacMessage.Unregister_PerformativeH\\x00\\x1a\\x89\\x03\\n\\tErrorCode\\x12N\\n\\nerror_code\\x18\\x01 \\x01(\\x0e\\x32:.aea.fetchai.tac.v1_0_0.TacMessage.ErrorCode.ErrorCodeEnum\"\\xab\\x02\\n\\rErrorCodeEnum\\x12\\x11\\n\\rGENERIC_ERROR\\x10\\x00\\x12\\x15\\n\\x11REQUEST_NOT_VALID\\x10\\x01\\x12!\\n\\x1d\\x41GENT_ADDR_ALREADY_REGISTERED\\x10\\x02\\x12!\\n\\x1d\\x41GENT_NAME_ALREADY_REGISTERED\\x10\\x03\\x12\\x18\\n\\x14\\x41GENT_NOT_REGISTERED\\x10\\x04\\x12\\x19\\n\\x15TRANSACTION_NOT_VALID\\x10\\x05\\x12\\x1c\\n\\x18TRANSACTION_NOT_MATCHING\\x10\\x06\\x12\\x1f\\n\\x1b\\x41GENT_NAME_NOT_IN_WHITELIST\\x10\\x07\\x12\\x1b\\n\\x17\\x43OMPETITION_NOT_RUNNING\\x10\\x08\\x12\\x19\\n\\x15\\x44IALOGUE_INCONSISTENT\\x10\\t\\x1a+\\n\\x15Register_Performative\\x12\\x12\\n\\nagent_name\\x18\\x01 \\x01(\\t\\x1a\\x19\\n\\x17Unregister_Performative\\x1a\\xc8\\x05\\n\\x18Transaction_Performative\\x12\\x16\\n\\x0etransaction_id\\x18\\x01 \\x01(\\t\\x12\\x11\\n\\tledger_id\\x18\\x02 \\x01(\\t\\x12\\x16\\n\\x0esender_address\\x18\\x03 \\x01(\\t\\x12\\x1c\\n\\x14\\x63ounterparty_address\\x18\\x04 \\x01(\\t\\x12r\\n\\x15\\x61mount_by_currency_id\\x18\\x05 \\x03(\\x0b\\x32S.aea.fetchai.tac.v1_0_0.TacMessage.Transaction_Performative.AmountByCurrencyIdEntry\\x12l\\n\\x12\\x66\\x65\\x65_by_currency_id\\x18\\x06 \\x03(\\x0b\\x32P.aea.fetchai.tac.v1_0_0.TacMessage.Transaction_Performative.FeeByCurrencyIdEntry\\x12r\\n\\x15quantities_by_good_id\\x18\\x07 \\x03(\\x0b\\x32S.aea.fetchai.tac.v1_0_0.TacMessage.Transaction_Performative.QuantitiesByGoodIdEntry\\x12\\r\\n\\x05nonce\\x18\\x08 \\x01(\\t\\x12\\x18\\n\\x10sender_signature\\x18\\t \\x01(\\t\\x12\\x1e\\n\\x16\\x63ounterparty_signature\\x18\\n \\x01(\\t\\x1a\\x39\\n\\x17\\x41mountByCurrencyIdEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\t\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\x03:\\x02\\x38\\x01\\x1a\\x36\\n\\x14\\x46\\x65\\x65\\x42yCurrencyIdEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\t\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\x03:\\x02\\x38\\x01\\x1a\\x39\\n\\x17QuantitiesByGoodIdEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\t\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\x03:\\x02\\x38\\x01\\x1a\\x18\\n\\x16\\x43\\x61ncelled_Performative\\x1a\\xa3\\x0c\\n\\x16Game_Data_Performative\\x12p\\n\\x15\\x61mount_by_currency_id\\x18\\x01 \\x03(\\x0b\\x32Q.aea.fetchai.tac.v1_0_0.TacMessage.Game_Data_Performative.AmountByCurrencyIdEntry\\x12\\x81\\x01\\n\\x1e\\x65xchange_params_by_currency_id\\x18\\x02 \\x03(\\x0b\\x32Y.aea.fetchai.tac.v1_0_0.TacMessage.Game_Data_Performative.ExchangeParamsByCurrencyIdEntry\\x12p\\n\\x15quantities_by_good_id\\x18\\x03 \\x03(\\x0b\\x32Q.aea.fetchai.tac.v1_0_0.TacMessage.Game_Data_Performative.QuantitiesByGoodIdEntry\\x12w\\n\\x19utility_params_by_good_id\\x18\\x04 \\x03(\\x0b\\x32T.aea.fetchai.tac.v1_0_0.TacMessage.Game_Data_Performative.UtilityParamsByGoodIdEntry\\x12j\\n\\x12\\x66\\x65\\x65_by_currency_id\\x18\\x05 \\x03(\\x0b\\x32N.aea.fetchai.tac.v1_0_0.TacMessage.Game_Data_Performative.FeeByCurrencyIdEntry\\x12j\\n\\x12\\x61gent_addr_to_name\\x18\\x06 \\x03(\\x0b\\x32N.aea.fetchai.tac.v1_0_0.TacMessage.Game_Data_Performative.AgentAddrToNameEntry\\x12l\\n\\x13\\x63urrency_id_to_name\\x18\\x07 \\x03(\\x0b\\x32O.aea.fetchai.tac.v1_0_0.TacMessage.Game_Data_Performative.CurrencyIdToNameEntry\\x12\\x64\\n\\x0fgood_id_to_name\\x18\\x08 \\x03(\\x0b\\x32K.aea.fetchai.tac.v1_0_0.TacMessage.Game_Data_Performative.GoodIdToNameEntry\\x12\\x12\\n\\nversion_id\\x18\\t \\x01(\\t\\x12Q\\n\\x04info\\x18\\n \\x03(\\x0b\\x32\\x43.aea.fetchai.tac.v1_0_0.TacMessage.Game_Data_Performative.InfoEntry\\x12\\x13\\n\\x0binfo_is_set\\x18\\x0b \\x01(\\x08\\x1a\\x39\\n\\x17\\x41mountByCurrencyIdEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\t\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\x03:\\x02\\x38\\x01\\x1a\\x41\\n\\x1f\\x45xchangeParamsByCurrencyIdEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\t\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\x02:\\x02\\x38\\x01\\x1a\\x39\\n\\x17QuantitiesByGoodIdEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\t\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\x03:\\x02\\x38\\x01\\x1a<\\n\\x1aUtilityParamsByGoodIdEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\t\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\x02:\\x02\\x38\\x01\\x1a\\x36\\n\\x14\\x46\\x65\\x65\\x42yCurrencyIdEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\t\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\x03:\\x02\\x38\\x01\\x1a\\x36\\n\\x14\\x41gentAddrToNameEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\t\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\t:\\x02\\x38\\x01\\x1a\\x37\\n\\x15\\x43urrencyIdToNameEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\t\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\t:\\x02\\x38\\x01\\x1a\\x33\\n\\x11GoodIdToNameEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\t\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\t:\\x02\\x38\\x01\\x1a+\\n\\tInfoEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\t\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\t:\\x02\\x38\\x01\\x1a\\xb7\\x03\\n%Transaction_Confirmation_Performative\\x12\\x16\\n\\x0etransaction_id\\x18\\x01 \\x01(\\t\\x12\\x7f\\n\\x15\\x61mount_by_currency_id\\x18\\x02 \\x03(\\x0b\\x32`.aea.fetchai.tac.v1_0_0.TacMessage.Transaction_Confirmation_Performative.AmountByCurrencyIdEntry\\x12\\x7f\\n\\x15quantities_by_good_id\\x18\\x03 \\x03(\\x0b\\x32`.aea.fetchai.tac.v1_0_0.TacMessage.Transaction_Confirmation_Performative.QuantitiesByGoodIdEntry\\x1a\\x39\\n\\x17\\x41mountByCurrencyIdEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\t\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\x03:\\x02\\x38\\x01\\x1a\\x39\\n\\x17QuantitiesByGoodIdEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\t\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\x03:\\x02\\x38\\x01\\x1a\\xef\\x01\\n\\x16Tac_Error_Performative\\x12@\\n\\nerror_code\\x18\\x01 \\x01(\\x0b\\x32,.aea.fetchai.tac.v1_0_0.TacMessage.ErrorCode\\x12Q\\n\\x04info\\x18\\x02 \\x03(\\x0b\\x32\\x43.aea.fetchai.tac.v1_0_0.TacMessage.Tac_Error_Performative.InfoEntry\\x12\\x13\\n\\x0binfo_is_set\\x18\\x03 \\x01(\\x08\\x1a+\\n\\tInfoEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\t\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\t:\\x02\\x38\\x01\\x42\\x0e\\n\\x0cperformativeb\\x06proto3'\n)\n\n\n_TACMESSAGE = DESCRIPTOR.message_types_by_name[\"TacMessage\"]\n_TACMESSAGE_ERRORCODE = _TACMESSAGE.nested_types_by_name[\"ErrorCode\"]\n_TACMESSAGE_REGISTER_PERFORMATIVE = _TACMESSAGE.nested_types_by_name[\n    \"Register_Performative\"\n]\n_TACMESSAGE_UNREGISTER_PERFORMATIVE = _TACMESSAGE.nested_types_by_name[\n    \"Unregister_Performative\"\n]\n_TACMESSAGE_TRANSACTION_PERFORMATIVE = _TACMESSAGE.nested_types_by_name[\n    \"Transaction_Performative\"\n]\n_TACMESSAGE_TRANSACTION_PERFORMATIVE_AMOUNTBYCURRENCYIDENTRY = (\n    _TACMESSAGE_TRANSACTION_PERFORMATIVE.nested_types_by_name[\"AmountByCurrencyIdEntry\"]\n)\n_TACMESSAGE_TRANSACTION_PERFORMATIVE_FEEBYCURRENCYIDENTRY = (\n    _TACMESSAGE_TRANSACTION_PERFORMATIVE.nested_types_by_name[\"FeeByCurrencyIdEntry\"]\n)\n_TACMESSAGE_TRANSACTION_PERFORMATIVE_QUANTITIESBYGOODIDENTRY = (\n    _TACMESSAGE_TRANSACTION_PERFORMATIVE.nested_types_by_name[\"QuantitiesByGoodIdEntry\"]\n)\n_TACMESSAGE_CANCELLED_PERFORMATIVE = _TACMESSAGE.nested_types_by_name[\n    \"Cancelled_Performative\"\n]\n_TACMESSAGE_GAME_DATA_PERFORMATIVE = _TACMESSAGE.nested_types_by_name[\n    \"Game_Data_Performative\"\n]\n_TACMESSAGE_GAME_DATA_PERFORMATIVE_AMOUNTBYCURRENCYIDENTRY = (\n    _TACMESSAGE_GAME_DATA_PERFORMATIVE.nested_types_by_name[\"AmountByCurrencyIdEntry\"]\n)\n_TACMESSAGE_GAME_DATA_PERFORMATIVE_EXCHANGEPARAMSBYCURRENCYIDENTRY = (\n    _TACMESSAGE_GAME_DATA_PERFORMATIVE.nested_types_by_name[\n        \"ExchangeParamsByCurrencyIdEntry\"\n    ]\n)\n_TACMESSAGE_GAME_DATA_PERFORMATIVE_QUANTITIESBYGOODIDENTRY = (\n    _TACMESSAGE_GAME_DATA_PERFORMATIVE.nested_types_by_name[\"QuantitiesByGoodIdEntry\"]\n)\n_TACMESSAGE_GAME_DATA_PERFORMATIVE_UTILITYPARAMSBYGOODIDENTRY = (\n    _TACMESSAGE_GAME_DATA_PERFORMATIVE.nested_types_by_name[\n        \"UtilityParamsByGoodIdEntry\"\n    ]\n)\n_TACMESSAGE_GAME_DATA_PERFORMATIVE_FEEBYCURRENCYIDENTRY = (\n    _TACMESSAGE_GAME_DATA_PERFORMATIVE.nested_types_by_name[\"FeeByCurrencyIdEntry\"]\n)\n_TACMESSAGE_GAME_DATA_PERFORMATIVE_AGENTADDRTONAMEENTRY = (\n    _TACMESSAGE_GAME_DATA_PERFORMATIVE.nested_types_by_name[\"AgentAddrToNameEntry\"]\n)\n_TACMESSAGE_GAME_DATA_PERFORMATIVE_CURRENCYIDTONAMEENTRY = (\n    _TACMESSAGE_GAME_DATA_PERFORMATIVE.nested_types_by_name[\"CurrencyIdToNameEntry\"]\n)\n_TACMESSAGE_GAME_DATA_PERFORMATIVE_GOODIDTONAMEENTRY = (\n    _TACMESSAGE_GAME_DATA_PERFORMATIVE.nested_types_by_name[\"GoodIdToNameEntry\"]\n)\n_TACMESSAGE_GAME_DATA_PERFORMATIVE_INFOENTRY = (\n    _TACMESSAGE_GAME_DATA_PERFORMATIVE.nested_types_by_name[\"InfoEntry\"]\n)\n_TACMESSAGE_TRANSACTION_CONFIRMATION_PERFORMATIVE = _TACMESSAGE.nested_types_by_name[\n    \"Transaction_Confirmation_Performative\"\n]\n_TACMESSAGE_TRANSACTION_CONFIRMATION_PERFORMATIVE_AMOUNTBYCURRENCYIDENTRY = (\n    _TACMESSAGE_TRANSACTION_CONFIRMATION_PERFORMATIVE.nested_types_by_name[\n        \"AmountByCurrencyIdEntry\"\n    ]\n)\n_TACMESSAGE_TRANSACTION_CONFIRMATION_PERFORMATIVE_QUANTITIESBYGOODIDENTRY = (\n    _TACMESSAGE_TRANSACTION_CONFIRMATION_PERFORMATIVE.nested_types_by_name[\n        \"QuantitiesByGoodIdEntry\"\n    ]\n)\n_TACMESSAGE_TAC_ERROR_PERFORMATIVE = _TACMESSAGE.nested_types_by_name[\n    \"Tac_Error_Performative\"\n]\n_TACMESSAGE_TAC_ERROR_PERFORMATIVE_INFOENTRY = (\n    _TACMESSAGE_TAC_ERROR_PERFORMATIVE.nested_types_by_name[\"InfoEntry\"]\n)\n_TACMESSAGE_ERRORCODE_ERRORCODEENUM = _TACMESSAGE_ERRORCODE.enum_types_by_name[\n    \"ErrorCodeEnum\"\n]\nTacMessage = _reflection.GeneratedProtocolMessageType(\n    \"TacMessage\",\n    (_message.Message,),\n    {\n        \"ErrorCode\": _reflection.GeneratedProtocolMessageType(\n            \"ErrorCode\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _TACMESSAGE_ERRORCODE,\n                \"__module__\": \"tac_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.tac.v1_0_0.TacMessage.ErrorCode)\n            },\n        ),\n        \"Register_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Register_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _TACMESSAGE_REGISTER_PERFORMATIVE,\n                \"__module__\": \"tac_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.tac.v1_0_0.TacMessage.Register_Performative)\n            },\n        ),\n        \"Unregister_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Unregister_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _TACMESSAGE_UNREGISTER_PERFORMATIVE,\n                \"__module__\": \"tac_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.tac.v1_0_0.TacMessage.Unregister_Performative)\n            },\n        ),\n        \"Transaction_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Transaction_Performative\",\n            (_message.Message,),\n            {\n                \"AmountByCurrencyIdEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"AmountByCurrencyIdEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _TACMESSAGE_TRANSACTION_PERFORMATIVE_AMOUNTBYCURRENCYIDENTRY,\n                        \"__module__\": \"tac_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.fetchai.tac.v1_0_0.TacMessage.Transaction_Performative.AmountByCurrencyIdEntry)\n                    },\n                ),\n                \"FeeByCurrencyIdEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"FeeByCurrencyIdEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _TACMESSAGE_TRANSACTION_PERFORMATIVE_FEEBYCURRENCYIDENTRY,\n                        \"__module__\": \"tac_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.fetchai.tac.v1_0_0.TacMessage.Transaction_Performative.FeeByCurrencyIdEntry)\n                    },\n                ),\n                \"QuantitiesByGoodIdEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"QuantitiesByGoodIdEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _TACMESSAGE_TRANSACTION_PERFORMATIVE_QUANTITIESBYGOODIDENTRY,\n                        \"__module__\": \"tac_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.fetchai.tac.v1_0_0.TacMessage.Transaction_Performative.QuantitiesByGoodIdEntry)\n                    },\n                ),\n                \"DESCRIPTOR\": _TACMESSAGE_TRANSACTION_PERFORMATIVE,\n                \"__module__\": \"tac_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.tac.v1_0_0.TacMessage.Transaction_Performative)\n            },\n        ),\n        \"Cancelled_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Cancelled_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _TACMESSAGE_CANCELLED_PERFORMATIVE,\n                \"__module__\": \"tac_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.tac.v1_0_0.TacMessage.Cancelled_Performative)\n            },\n        ),\n        \"Game_Data_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Game_Data_Performative\",\n            (_message.Message,),\n            {\n                \"AmountByCurrencyIdEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"AmountByCurrencyIdEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _TACMESSAGE_GAME_DATA_PERFORMATIVE_AMOUNTBYCURRENCYIDENTRY,\n                        \"__module__\": \"tac_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.fetchai.tac.v1_0_0.TacMessage.Game_Data_Performative.AmountByCurrencyIdEntry)\n                    },\n                ),\n                \"ExchangeParamsByCurrencyIdEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"ExchangeParamsByCurrencyIdEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _TACMESSAGE_GAME_DATA_PERFORMATIVE_EXCHANGEPARAMSBYCURRENCYIDENTRY,\n                        \"__module__\": \"tac_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.fetchai.tac.v1_0_0.TacMessage.Game_Data_Performative.ExchangeParamsByCurrencyIdEntry)\n                    },\n                ),\n                \"QuantitiesByGoodIdEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"QuantitiesByGoodIdEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _TACMESSAGE_GAME_DATA_PERFORMATIVE_QUANTITIESBYGOODIDENTRY,\n                        \"__module__\": \"tac_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.fetchai.tac.v1_0_0.TacMessage.Game_Data_Performative.QuantitiesByGoodIdEntry)\n                    },\n                ),\n                \"UtilityParamsByGoodIdEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"UtilityParamsByGoodIdEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _TACMESSAGE_GAME_DATA_PERFORMATIVE_UTILITYPARAMSBYGOODIDENTRY,\n                        \"__module__\": \"tac_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.fetchai.tac.v1_0_0.TacMessage.Game_Data_Performative.UtilityParamsByGoodIdEntry)\n                    },\n                ),\n                \"FeeByCurrencyIdEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"FeeByCurrencyIdEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _TACMESSAGE_GAME_DATA_PERFORMATIVE_FEEBYCURRENCYIDENTRY,\n                        \"__module__\": \"tac_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.fetchai.tac.v1_0_0.TacMessage.Game_Data_Performative.FeeByCurrencyIdEntry)\n                    },\n                ),\n                \"AgentAddrToNameEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"AgentAddrToNameEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _TACMESSAGE_GAME_DATA_PERFORMATIVE_AGENTADDRTONAMEENTRY,\n                        \"__module__\": \"tac_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.fetchai.tac.v1_0_0.TacMessage.Game_Data_Performative.AgentAddrToNameEntry)\n                    },\n                ),\n                \"CurrencyIdToNameEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"CurrencyIdToNameEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _TACMESSAGE_GAME_DATA_PERFORMATIVE_CURRENCYIDTONAMEENTRY,\n                        \"__module__\": \"tac_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.fetchai.tac.v1_0_0.TacMessage.Game_Data_Performative.CurrencyIdToNameEntry)\n                    },\n                ),\n                \"GoodIdToNameEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"GoodIdToNameEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _TACMESSAGE_GAME_DATA_PERFORMATIVE_GOODIDTONAMEENTRY,\n                        \"__module__\": \"tac_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.fetchai.tac.v1_0_0.TacMessage.Game_Data_Performative.GoodIdToNameEntry)\n                    },\n                ),\n                \"InfoEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"InfoEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _TACMESSAGE_GAME_DATA_PERFORMATIVE_INFOENTRY,\n                        \"__module__\": \"tac_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.fetchai.tac.v1_0_0.TacMessage.Game_Data_Performative.InfoEntry)\n                    },\n                ),\n                \"DESCRIPTOR\": _TACMESSAGE_GAME_DATA_PERFORMATIVE,\n                \"__module__\": \"tac_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.tac.v1_0_0.TacMessage.Game_Data_Performative)\n            },\n        ),\n        \"Transaction_Confirmation_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Transaction_Confirmation_Performative\",\n            (_message.Message,),\n            {\n                \"AmountByCurrencyIdEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"AmountByCurrencyIdEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _TACMESSAGE_TRANSACTION_CONFIRMATION_PERFORMATIVE_AMOUNTBYCURRENCYIDENTRY,\n                        \"__module__\": \"tac_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.fetchai.tac.v1_0_0.TacMessage.Transaction_Confirmation_Performative.AmountByCurrencyIdEntry)\n                    },\n                ),\n                \"QuantitiesByGoodIdEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"QuantitiesByGoodIdEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _TACMESSAGE_TRANSACTION_CONFIRMATION_PERFORMATIVE_QUANTITIESBYGOODIDENTRY,\n                        \"__module__\": \"tac_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.fetchai.tac.v1_0_0.TacMessage.Transaction_Confirmation_Performative.QuantitiesByGoodIdEntry)\n                    },\n                ),\n                \"DESCRIPTOR\": _TACMESSAGE_TRANSACTION_CONFIRMATION_PERFORMATIVE,\n                \"__module__\": \"tac_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.tac.v1_0_0.TacMessage.Transaction_Confirmation_Performative)\n            },\n        ),\n        \"Tac_Error_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Tac_Error_Performative\",\n            (_message.Message,),\n            {\n                \"InfoEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"InfoEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _TACMESSAGE_TAC_ERROR_PERFORMATIVE_INFOENTRY,\n                        \"__module__\": \"tac_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.fetchai.tac.v1_0_0.TacMessage.Tac_Error_Performative.InfoEntry)\n                    },\n                ),\n                \"DESCRIPTOR\": _TACMESSAGE_TAC_ERROR_PERFORMATIVE,\n                \"__module__\": \"tac_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.fetchai.tac.v1_0_0.TacMessage.Tac_Error_Performative)\n            },\n        ),\n        \"DESCRIPTOR\": _TACMESSAGE,\n        \"__module__\": \"tac_pb2\"\n        # @@protoc_insertion_point(class_scope:aea.fetchai.tac.v1_0_0.TacMessage)\n    },\n)\n_sym_db.RegisterMessage(TacMessage)\n_sym_db.RegisterMessage(TacMessage.ErrorCode)\n_sym_db.RegisterMessage(TacMessage.Register_Performative)\n_sym_db.RegisterMessage(TacMessage.Unregister_Performative)\n_sym_db.RegisterMessage(TacMessage.Transaction_Performative)\n_sym_db.RegisterMessage(TacMessage.Transaction_Performative.AmountByCurrencyIdEntry)\n_sym_db.RegisterMessage(TacMessage.Transaction_Performative.FeeByCurrencyIdEntry)\n_sym_db.RegisterMessage(TacMessage.Transaction_Performative.QuantitiesByGoodIdEntry)\n_sym_db.RegisterMessage(TacMessage.Cancelled_Performative)\n_sym_db.RegisterMessage(TacMessage.Game_Data_Performative)\n_sym_db.RegisterMessage(TacMessage.Game_Data_Performative.AmountByCurrencyIdEntry)\n_sym_db.RegisterMessage(\n    TacMessage.Game_Data_Performative.ExchangeParamsByCurrencyIdEntry\n)\n_sym_db.RegisterMessage(TacMessage.Game_Data_Performative.QuantitiesByGoodIdEntry)\n_sym_db.RegisterMessage(TacMessage.Game_Data_Performative.UtilityParamsByGoodIdEntry)\n_sym_db.RegisterMessage(TacMessage.Game_Data_Performative.FeeByCurrencyIdEntry)\n_sym_db.RegisterMessage(TacMessage.Game_Data_Performative.AgentAddrToNameEntry)\n_sym_db.RegisterMessage(TacMessage.Game_Data_Performative.CurrencyIdToNameEntry)\n_sym_db.RegisterMessage(TacMessage.Game_Data_Performative.GoodIdToNameEntry)\n_sym_db.RegisterMessage(TacMessage.Game_Data_Performative.InfoEntry)\n_sym_db.RegisterMessage(TacMessage.Transaction_Confirmation_Performative)\n_sym_db.RegisterMessage(\n    TacMessage.Transaction_Confirmation_Performative.AmountByCurrencyIdEntry\n)\n_sym_db.RegisterMessage(\n    TacMessage.Transaction_Confirmation_Performative.QuantitiesByGoodIdEntry\n)\n_sym_db.RegisterMessage(TacMessage.Tac_Error_Performative)\n_sym_db.RegisterMessage(TacMessage.Tac_Error_Performative.InfoEntry)\n\nif _descriptor._USE_C_DESCRIPTORS == False:\n\n    DESCRIPTOR._options = None\n    _TACMESSAGE_TRANSACTION_PERFORMATIVE_AMOUNTBYCURRENCYIDENTRY._options = None\n    _TACMESSAGE_TRANSACTION_PERFORMATIVE_AMOUNTBYCURRENCYIDENTRY._serialized_options = (\n        b\"8\\001\"\n    )\n    _TACMESSAGE_TRANSACTION_PERFORMATIVE_FEEBYCURRENCYIDENTRY._options = None\n    _TACMESSAGE_TRANSACTION_PERFORMATIVE_FEEBYCURRENCYIDENTRY._serialized_options = (\n        b\"8\\001\"\n    )\n    _TACMESSAGE_TRANSACTION_PERFORMATIVE_QUANTITIESBYGOODIDENTRY._options = None\n    _TACMESSAGE_TRANSACTION_PERFORMATIVE_QUANTITIESBYGOODIDENTRY._serialized_options = (\n        b\"8\\001\"\n    )\n    _TACMESSAGE_GAME_DATA_PERFORMATIVE_AMOUNTBYCURRENCYIDENTRY._options = None\n    _TACMESSAGE_GAME_DATA_PERFORMATIVE_AMOUNTBYCURRENCYIDENTRY._serialized_options = (\n        b\"8\\001\"\n    )\n    _TACMESSAGE_GAME_DATA_PERFORMATIVE_EXCHANGEPARAMSBYCURRENCYIDENTRY._options = None\n    _TACMESSAGE_GAME_DATA_PERFORMATIVE_EXCHANGEPARAMSBYCURRENCYIDENTRY._serialized_options = (\n        b\"8\\001\"\n    )\n    _TACMESSAGE_GAME_DATA_PERFORMATIVE_QUANTITIESBYGOODIDENTRY._options = None\n    _TACMESSAGE_GAME_DATA_PERFORMATIVE_QUANTITIESBYGOODIDENTRY._serialized_options = (\n        b\"8\\001\"\n    )\n    _TACMESSAGE_GAME_DATA_PERFORMATIVE_UTILITYPARAMSBYGOODIDENTRY._options = None\n    _TACMESSAGE_GAME_DATA_PERFORMATIVE_UTILITYPARAMSBYGOODIDENTRY._serialized_options = (\n        b\"8\\001\"\n    )\n    _TACMESSAGE_GAME_DATA_PERFORMATIVE_FEEBYCURRENCYIDENTRY._options = None\n    _TACMESSAGE_GAME_DATA_PERFORMATIVE_FEEBYCURRENCYIDENTRY._serialized_options = (\n        b\"8\\001\"\n    )\n    _TACMESSAGE_GAME_DATA_PERFORMATIVE_AGENTADDRTONAMEENTRY._options = None\n    _TACMESSAGE_GAME_DATA_PERFORMATIVE_AGENTADDRTONAMEENTRY._serialized_options = (\n        b\"8\\001\"\n    )\n    _TACMESSAGE_GAME_DATA_PERFORMATIVE_CURRENCYIDTONAMEENTRY._options = None\n    _TACMESSAGE_GAME_DATA_PERFORMATIVE_CURRENCYIDTONAMEENTRY._serialized_options = (\n        b\"8\\001\"\n    )\n    _TACMESSAGE_GAME_DATA_PERFORMATIVE_GOODIDTONAMEENTRY._options = None\n    _TACMESSAGE_GAME_DATA_PERFORMATIVE_GOODIDTONAMEENTRY._serialized_options = b\"8\\001\"\n    _TACMESSAGE_GAME_DATA_PERFORMATIVE_INFOENTRY._options = None\n    _TACMESSAGE_GAME_DATA_PERFORMATIVE_INFOENTRY._serialized_options = b\"8\\001\"\n    _TACMESSAGE_TRANSACTION_CONFIRMATION_PERFORMATIVE_AMOUNTBYCURRENCYIDENTRY._options = (\n        None\n    )\n    _TACMESSAGE_TRANSACTION_CONFIRMATION_PERFORMATIVE_AMOUNTBYCURRENCYIDENTRY._serialized_options = (\n        b\"8\\001\"\n    )\n    _TACMESSAGE_TRANSACTION_CONFIRMATION_PERFORMATIVE_QUANTITIESBYGOODIDENTRY._options = (\n        None\n    )\n    _TACMESSAGE_TRANSACTION_CONFIRMATION_PERFORMATIVE_QUANTITIESBYGOODIDENTRY._serialized_options = (\n        b\"8\\001\"\n    )\n    _TACMESSAGE_TAC_ERROR_PERFORMATIVE_INFOENTRY._options = None\n    _TACMESSAGE_TAC_ERROR_PERFORMATIVE_INFOENTRY._serialized_options = b\"8\\001\"\n    _TACMESSAGE._serialized_start = 38\n    _TACMESSAGE._serialized_end = 4127\n    _TACMESSAGE_ERRORCODE._serialized_start = 647\n    _TACMESSAGE_ERRORCODE._serialized_end = 1040\n    _TACMESSAGE_ERRORCODE_ERRORCODEENUM._serialized_start = 741\n    _TACMESSAGE_ERRORCODE_ERRORCODEENUM._serialized_end = 1040\n    _TACMESSAGE_REGISTER_PERFORMATIVE._serialized_start = 1042\n    _TACMESSAGE_REGISTER_PERFORMATIVE._serialized_end = 1085\n    _TACMESSAGE_UNREGISTER_PERFORMATIVE._serialized_start = 1087\n    _TACMESSAGE_UNREGISTER_PERFORMATIVE._serialized_end = 1112\n    _TACMESSAGE_TRANSACTION_PERFORMATIVE._serialized_start = 1115\n    _TACMESSAGE_TRANSACTION_PERFORMATIVE._serialized_end = 1827\n    _TACMESSAGE_TRANSACTION_PERFORMATIVE_AMOUNTBYCURRENCYIDENTRY._serialized_start = (\n        1655\n    )\n    _TACMESSAGE_TRANSACTION_PERFORMATIVE_AMOUNTBYCURRENCYIDENTRY._serialized_end = 1712\n    _TACMESSAGE_TRANSACTION_PERFORMATIVE_FEEBYCURRENCYIDENTRY._serialized_start = 1714\n    _TACMESSAGE_TRANSACTION_PERFORMATIVE_FEEBYCURRENCYIDENTRY._serialized_end = 1768\n    _TACMESSAGE_TRANSACTION_PERFORMATIVE_QUANTITIESBYGOODIDENTRY._serialized_start = (\n        1770\n    )\n    _TACMESSAGE_TRANSACTION_PERFORMATIVE_QUANTITIESBYGOODIDENTRY._serialized_end = 1827\n    _TACMESSAGE_CANCELLED_PERFORMATIVE._serialized_start = 1829\n    _TACMESSAGE_CANCELLED_PERFORMATIVE._serialized_end = 1853\n    _TACMESSAGE_GAME_DATA_PERFORMATIVE._serialized_start = 1856\n    _TACMESSAGE_GAME_DATA_PERFORMATIVE._serialized_end = 3427\n    _TACMESSAGE_GAME_DATA_PERFORMATIVE_AMOUNTBYCURRENCYIDENTRY._serialized_start = 1655\n    _TACMESSAGE_GAME_DATA_PERFORMATIVE_AMOUNTBYCURRENCYIDENTRY._serialized_end = 1712\n    _TACMESSAGE_GAME_DATA_PERFORMATIVE_EXCHANGEPARAMSBYCURRENCYIDENTRY._serialized_start = (\n        2974\n    )\n    _TACMESSAGE_GAME_DATA_PERFORMATIVE_EXCHANGEPARAMSBYCURRENCYIDENTRY._serialized_end = (\n        3039\n    )\n    _TACMESSAGE_GAME_DATA_PERFORMATIVE_QUANTITIESBYGOODIDENTRY._serialized_start = 1770\n    _TACMESSAGE_GAME_DATA_PERFORMATIVE_QUANTITIESBYGOODIDENTRY._serialized_end = 1827\n    _TACMESSAGE_GAME_DATA_PERFORMATIVE_UTILITYPARAMSBYGOODIDENTRY._serialized_start = (\n        3100\n    )\n    _TACMESSAGE_GAME_DATA_PERFORMATIVE_UTILITYPARAMSBYGOODIDENTRY._serialized_end = 3160\n    _TACMESSAGE_GAME_DATA_PERFORMATIVE_FEEBYCURRENCYIDENTRY._serialized_start = 1714\n    _TACMESSAGE_GAME_DATA_PERFORMATIVE_FEEBYCURRENCYIDENTRY._serialized_end = 1768\n    _TACMESSAGE_GAME_DATA_PERFORMATIVE_AGENTADDRTONAMEENTRY._serialized_start = 3218\n    _TACMESSAGE_GAME_DATA_PERFORMATIVE_AGENTADDRTONAMEENTRY._serialized_end = 3272\n    _TACMESSAGE_GAME_DATA_PERFORMATIVE_CURRENCYIDTONAMEENTRY._serialized_start = 3274\n    _TACMESSAGE_GAME_DATA_PERFORMATIVE_CURRENCYIDTONAMEENTRY._serialized_end = 3329\n    _TACMESSAGE_GAME_DATA_PERFORMATIVE_GOODIDTONAMEENTRY._serialized_start = 3331\n    _TACMESSAGE_GAME_DATA_PERFORMATIVE_GOODIDTONAMEENTRY._serialized_end = 3382\n    _TACMESSAGE_GAME_DATA_PERFORMATIVE_INFOENTRY._serialized_start = 3384\n    _TACMESSAGE_GAME_DATA_PERFORMATIVE_INFOENTRY._serialized_end = 3427\n    _TACMESSAGE_TRANSACTION_CONFIRMATION_PERFORMATIVE._serialized_start = 3430\n    _TACMESSAGE_TRANSACTION_CONFIRMATION_PERFORMATIVE._serialized_end = 3869\n    _TACMESSAGE_TRANSACTION_CONFIRMATION_PERFORMATIVE_AMOUNTBYCURRENCYIDENTRY._serialized_start = (\n        1655\n    )\n    _TACMESSAGE_TRANSACTION_CONFIRMATION_PERFORMATIVE_AMOUNTBYCURRENCYIDENTRY._serialized_end = (\n        1712\n    )\n    _TACMESSAGE_TRANSACTION_CONFIRMATION_PERFORMATIVE_QUANTITIESBYGOODIDENTRY._serialized_start = (\n        1770\n    )\n    _TACMESSAGE_TRANSACTION_CONFIRMATION_PERFORMATIVE_QUANTITIESBYGOODIDENTRY._serialized_end = (\n        1827\n    )\n    _TACMESSAGE_TAC_ERROR_PERFORMATIVE._serialized_start = 3872\n    _TACMESSAGE_TAC_ERROR_PERFORMATIVE._serialized_end = 4111\n    _TACMESSAGE_TAC_ERROR_PERFORMATIVE_INFOENTRY._serialized_start = 3384\n    _TACMESSAGE_TAC_ERROR_PERFORMATIVE_INFOENTRY._serialized_end = 3427\n# @@protoc_insertion_point(module_scope)\n"
  },
  {
    "path": "packages/fetchai/skills/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the skill packages authored by Fetch.ai.\"\"\"\n"
  },
  {
    "path": "packages/fetchai/skills/advanced_data_request/README.md",
    "content": "# Advanced Data Request\n\n## Description\n\nThis skill is used to get specific data from an API, which can either be shared with other agent skills or made available by http request.\n\n## Behaviours\n\n- `advanced_data_request_behaviour`: requests data from specified source every `tick_interval` seconds from the API endpoint `url` specified in the skill configuration.\n\n## Handlers\n\n- `http`: handles incoming `http` messages, retrieves the data from the appropriate response, stores it in shared state under the key: `observation`, and responds to requests satisfying the API specification listed in `api_spec.yaml`.\n"
  },
  {
    "path": "packages/fetchai/skills/advanced_data_request/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the implementation of the AdvancedDataRequest skill.\"\"\"\n\nfrom aea.configurations.base import PublicId\n\n\nPUBLIC_ID = PublicId.from_str(\"fetchai/advanced_data_request:0.7.6\")\n"
  },
  {
    "path": "packages/fetchai/skills/advanced_data_request/api_spec.yaml",
    "content": "openapi: \"3.0.0\"\ninfo:\n  version: 0.1.0\n  title: advanced_data_request_api\npaths:\n  /data:\n    get:\n      summary: Advanced data request\n      operationId: data\n      responses:\n        '200':\n          description: A JSON response including the data\n          content:\n            application/json:\n              schema:\n                type: object\n        '404':\n          description: The specified data was not found.\n        default:\n          description: Unexpected error"
  },
  {
    "path": "packages/fetchai/skills/advanced_data_request/behaviours.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains a behaviour for fetching data from an API.\"\"\"\n\nimport json\nfrom typing import Any, Dict, cast\n\nfrom aea.skills.behaviours import TickerBehaviour\n\nfrom packages.fetchai.connections.http_client.connection import (\n    PUBLIC_ID as HTTP_CLIENT_ID,\n)\nfrom packages.fetchai.connections.prometheus.connection import (\n    PUBLIC_ID as PROM_CONNECTION_ID,\n)\nfrom packages.fetchai.protocols.http.message import HttpMessage\nfrom packages.fetchai.protocols.prometheus.message import PrometheusMessage\nfrom packages.fetchai.skills.advanced_data_request.dialogues import (\n    HttpDialogues,\n    PrometheusDialogues,\n)\nfrom packages.fetchai.skills.advanced_data_request.models import (\n    AdvancedDataRequestModel,\n)\n\n\nclass AdvancedDataRequestBehaviour(TickerBehaviour):\n    \"\"\"This class provides a simple behaviour to fetch data.\"\"\"\n\n    def __init__(self, **kwargs: Any):\n        \"\"\"Initialize the advanced data request behaviour.\"\"\"\n\n        super().__init__(**kwargs)\n\n    def send_http_request_message(self) -> None:\n        \"\"\"Send an http request message.\"\"\"\n\n        # context\n        http_dialogues = cast(HttpDialogues, self.context.http_dialogues)\n        model = cast(AdvancedDataRequestModel, self.context.advanced_data_request_model)\n        content = model.body\n\n        # http request message\n        request_http_message, _ = http_dialogues.create(\n            counterparty=str(HTTP_CLIENT_ID),\n            performative=HttpMessage.Performative.REQUEST,\n            method=model.method,\n            url=model.url,\n            headers=\"Content-Type: application/json\",\n            version=\"\",\n            body=b\"\" if content is None else json.dumps(content).encode(\"utf-8\"),\n        )\n\n        # send message\n        self.context.outbox.put_message(message=request_http_message)\n\n    def add_prometheus_metric(\n        self,\n        metric_name: str,\n        metric_type: str,\n        description: str,\n        labels: Dict[str, str],\n    ) -> None:\n        \"\"\"\n        Add a prometheus metric.\n\n        :param metric_name: the name of the metric to add.\n        :param metric_type: the type of the metric.\n        :param description: a description of the metric.\n        :param labels: the metric labels.\n        \"\"\"\n\n        # context\n        prom_dialogues = cast(PrometheusDialogues, self.context.prometheus_dialogues)\n\n        # prometheus update message\n        message, _ = prom_dialogues.create(\n            counterparty=str(PROM_CONNECTION_ID),\n            performative=PrometheusMessage.Performative.ADD_METRIC,\n            type=metric_type,\n            title=metric_name,\n            description=description,\n            labels=labels,\n        )\n\n        # send message\n        self.context.outbox.put_message(message=message)\n\n    def update_prometheus_metric(\n        self,\n        metric_name: str,\n        update_func: str,\n        value: float,\n        labels: Dict[str, str],\n    ) -> None:\n        \"\"\"\n        Update a prometheus metric.\n\n        :param metric_name: the name of the metric.\n        :param update_func: the name of the update function (e.g. inc, dec, set, ...).\n        :param value: the value to provide to the update function.\n        :param labels: the metric labels.\n        \"\"\"\n\n        # context\n        prom_dialogues = cast(PrometheusDialogues, self.context.prometheus_dialogues)\n\n        # prometheus update message\n        message, _ = prom_dialogues.create(\n            counterparty=str(PROM_CONNECTION_ID),\n            performative=PrometheusMessage.Performative.UPDATE_METRIC,\n            title=metric_name,\n            callable=update_func,\n            value=value,\n            labels=labels,\n        )\n\n        # send message\n        self.context.outbox.put_message(message=message)\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup.\"\"\"\n        self.context.logger.info(\"setting up AdvancedDataRequestBehaviour\")\n\n        prom_dialogues = cast(PrometheusDialogues, self.context.prometheus_dialogues)\n\n        if prom_dialogues.enabled:\n            for metric in prom_dialogues.metrics:\n                metric_name = metric[\"name\"]\n                self.context.logger.info(\"Adding Prometheus metric: \" + metric_name)\n                self.add_prometheus_metric(\n                    metric_name,\n                    metric[\"type\"],\n                    metric[\"description\"],\n                    dict(metric[\"labels\"]),\n                )\n\n    def act(self) -> None:\n        \"\"\"Implement the act.\"\"\"\n        model = cast(AdvancedDataRequestModel, self.context.advanced_data_request_model)\n        self.context.logger.info(f\"Fetching data from {model.url}\")\n        self.send_http_request_message()\n\n    def teardown(self) -> None:\n        \"\"\"Implement the task teardown.\"\"\"\n        self.context.logger.info(\"tearing down AdvancedDataRequestBehaviour\")\n"
  },
  {
    "path": "packages/fetchai/skills/advanced_data_request/dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains dialogues used by the advanced_data_request skill.\"\"\"\n\nfrom typing import Any\n\nfrom aea.protocols.base import Address, Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\nfrom aea.skills.base import Model\n\nfrom packages.fetchai.protocols.http.dialogues import HttpDialogue as BaseHttpDialogue\nfrom packages.fetchai.protocols.http.dialogues import HttpDialogues as BaseHttpDialogues\nfrom packages.fetchai.protocols.http.message import HttpMessage\nfrom packages.fetchai.protocols.prometheus.dialogues import (\n    PrometheusDialogue as BasePrometheusDialogue,\n)\nfrom packages.fetchai.protocols.prometheus.dialogues import (\n    PrometheusDialogues as BasePrometheusDialogues,\n)\n\n\nHttpDialogue = BaseHttpDialogue\nPrometheusDialogue = BasePrometheusDialogue\n\n\nclass HttpDialogues(Model, BaseHttpDialogues):\n    \"\"\"This class keeps track of all http dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent in this dialogue\n            \"\"\"\n            if (\n                message.performative == HttpMessage.Performative.REQUEST\n                and message.sender != receiver_address\n            ) or (\n                message.performative == HttpMessage.Performative.RESPONSE\n                and message.sender == receiver_address\n            ):\n                return BaseHttpDialogue.Role.SERVER\n\n            return BaseHttpDialogue.Role.CLIENT\n\n        BaseHttpDialogues.__init__(\n            self,\n            self_address=str(self.skill_id),\n            role_from_first_message=role_from_first_message,\n        )\n\n\nclass PrometheusDialogues(Model, BasePrometheusDialogues):\n    \"\"\"The dialogues class keeps track of all prometheus dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        self.enabled = kwargs.pop(\"enabled\", False)\n        self.metrics = kwargs.pop(\"metrics\", [])\n\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return PrometheusDialogue.Role.AGENT\n\n        BasePrometheusDialogues.__init__(\n            self,\n            self_address=str(self.skill_id),\n            role_from_first_message=role_from_first_message,\n        )\n"
  },
  {
    "path": "packages/fetchai/skills/advanced_data_request/handlers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains handlers for the advanced_data_request skill.\"\"\"\n\nimport json\nfrom typing import Any, Dict, Optional, SupportsFloat, cast\n\nfrom aea.configurations.base import PublicId\nfrom aea.protocols.base import Message\nfrom aea.skills.base import Handler\n\nfrom packages.fetchai.protocols.http.message import HttpMessage\nfrom packages.fetchai.protocols.prometheus.message import PrometheusMessage\nfrom packages.fetchai.skills.advanced_data_request.dialogues import (\n    HttpDialogue,\n    HttpDialogues,\n    PrometheusDialogue,\n    PrometheusDialogues,\n)\n\n\ndef find(dotted_path: str, data: Dict[str, Any]) -> Optional[Any]:\n    \"\"\"Find entry at dotted_path in data\"\"\"\n\n    keys = dotted_path.split(\".\")\n    value = data\n    for key in keys:\n        value = value.get(key, {})\n    return None if value == {} else value\n\n\ndef is_number(value: SupportsFloat) -> bool:\n    \"\"\"Test if value is a number\"\"\"\n    if value is None:\n        return False\n    try:\n        float(value)\n        return True\n    except ValueError:\n        return False\n\n\nclass HttpHandler(Handler):\n    \"\"\"This class provides a simple http handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = HttpMessage.protocol_id\n\n    def __init__(self, **kwargs: Any):\n        \"\"\"Initialize the handler.\"\"\"\n        super().__init__(**kwargs)\n\n        self._http_server_id = None  # type: Optional[PublicId]\n\n    def setup(self) -> None:\n        \"\"\"Set up the handler.\"\"\"\n        self.context.logger.info(\"setting up HttpHandler\")\n\n        # skill can be used with or without http server\n        if (\n            self.context.advanced_data_request_model.use_http_server\n        ):  # pylint: disable=import-outside-toplevel\n            from packages.fetchai.connections.http_server.connection import (\n                PUBLIC_ID as HTTP_SERVER_ID,\n            )\n\n            self._http_server_id = HTTP_SERVER_ID\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to a message.\n\n        :param message: the message\n        \"\"\"\n\n        message = cast(HttpMessage, message)\n\n        # recover dialogue\n        http_dialogues = cast(HttpDialogues, self.context.http_dialogues)\n        http_dialogue = cast(HttpDialogue, http_dialogues.update(message))\n        if http_dialogue is None:\n            self._handle_unidentified_dialogue(message)\n            return\n\n        if (\n            message.performative == HttpMessage.Performative.RESPONSE\n            and message.status_code == 200\n        ):\n            self._handle_response(message)\n        elif message.performative == HttpMessage.Performative.REQUEST:\n            self._handle_request(message, http_dialogue)\n        else:\n            self.context.logger.info(\n                f\"got unexpected http message: code = {message.status_code}\"\n            )\n\n    def _handle_response(self, http_msg: HttpMessage) -> None:\n        \"\"\"\n        Handle an Http response.\n\n        :param http_msg: the http message\n        \"\"\"\n\n        model = self.context.advanced_data_request_model\n\n        msg_body = json.loads(http_msg.body)\n\n        success = False\n        for output in model.outputs:\n            json_path = output[\"json_path\"]\n\n            # find desired output data in msg_body\n            value = cast(SupportsFloat, find(json_path, msg_body))\n\n            # if value is a numeric type, store it as fixed-point with number of decimals\n            if is_number(value):\n                float_value = float(value)\n                int_value = int(float_value * 10**model.decimals)\n                observation = {\n                    output[\"name\"]: {\"value\": int_value, \"decimals\": model.decimals}\n                }\n            elif isinstance(value, str):\n                observation = {output[\"name\"]: {\"value\": value}}\n            else:\n                self.context.logger.warning(\n                    f\"No valid output for {output['name']} found in response.\"\n                )\n                continue\n            success = True\n            self.context.shared_state.update(observation)\n            self.context.logger.info(f\"Observation: {observation}\")\n\n        if success and self.context.prometheus_dialogues.enabled:\n            metric_name = \"num_retrievals\"\n            self.context.behaviours.advanced_data_request_behaviour.update_prometheus_metric(\n                metric_name, \"inc\", 1.0, {}\n            )\n\n    def _handle_request(\n        self, http_msg: HttpMessage, http_dialogue: HttpDialogue\n    ) -> None:\n        \"\"\"\n        Handle a Http request.\n\n        :param http_msg: the http message\n        :param http_dialogue: the http dialogue\n        \"\"\"\n        self.context.logger.info(\n            \"received http request with method={}, url={} and body={!r}\".format(\n                http_msg.method,\n                http_msg.url,\n                http_msg.body,\n            )\n        )\n\n        if self._http_server_id:\n            if http_msg.method == \"get\":\n                self._handle_get(http_msg, http_dialogue)\n            elif http_msg.method == \"post\":\n                self.context.logger.info(\"method 'post' is not supported.\")\n        else:\n            self.context.logger.info(\"http server is not enabled.\")\n\n    def _handle_get(self, http_msg: HttpMessage, http_dialogue: HttpDialogue) -> None:\n        \"\"\"\n        Handle a Http request of verb GET.\n\n        :param http_msg: the http message\n        :param http_dialogue: the http dialogue\n        \"\"\"\n        model = self.context.advanced_data_request_model\n        outputs = [output[\"name\"] for output in model.outputs]\n        data = {\n            key: value\n            for (key, value) in self.context.shared_state.items()\n            if key in outputs\n        }\n\n        http_response = http_dialogue.reply(\n            performative=HttpMessage.Performative.RESPONSE,\n            target_message=http_msg,\n            version=http_msg.version,\n            status_code=200,\n            status_text=\"Success\",\n            headers=http_msg.headers,\n            body=json.dumps(data).encode(\"utf-8\"),\n        )\n        self.context.logger.info(\"responding with: {}\".format(http_response))\n        self.context.outbox.put_message(message=http_response)\n\n        if self.context.prometheus_dialogues.enabled:\n            metric_name = \"num_requests\"\n            self.context.behaviours.advanced_data_request_behaviour.update_prometheus_metric(\n                metric_name, \"inc\", 1.0, {}\n            )\n\n    def _handle_unidentified_dialogue(self, msg: Message) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param msg: the unidentified message to be handled\n        \"\"\"\n        self.context.logger.info(\n            \"received invalid message={}, unidentified dialogue.\".format(msg)\n        )\n\n    def teardown(self) -> None:\n        \"\"\"Teardown the handler.\"\"\"\n\n\nclass PrometheusHandler(Handler):\n    \"\"\"This class handles responses from the prometheus server.\"\"\"\n\n    SUPPORTED_PROTOCOL = PrometheusMessage.protocol_id\n\n    def setup(self) -> None:\n        \"\"\"Set up the handler.\"\"\"\n        self.context.logger.info(\"setting up PrometheusHandler\")\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to a message.\n\n        :param message: the message\n        \"\"\"\n        message = cast(PrometheusMessage, message)\n\n        # recover dialogue\n        prometheus_dialogues = cast(\n            PrometheusDialogues, self.context.prometheus_dialogues\n        )\n        prometheus_dialogue = cast(\n            PrometheusDialogue, prometheus_dialogues.update(message)\n        )\n        if prometheus_dialogue is None:\n            self._handle_unidentified_dialogue(message)\n            return\n\n        if message.performative == PrometheusMessage.Performative.RESPONSE:\n            self.context.logger.debug(\n                f\"Prometheus response ({message.code}): {message.message}\"\n            )\n        else:  # pragma: nocover\n            self.context.logger.debug(\n                f\"got unexpected prometheus message: Performative = {PrometheusMessage.Performative}\"\n            )\n\n    def _handle_unidentified_dialogue(self, msg: Message) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param msg: the unidentified message to be handled\n        \"\"\"\n\n        self.context.logger.info(\n            \"received invalid message={}, unidentified dialogue.\".format(msg)\n        )\n\n    def teardown(self) -> None:\n        \"\"\"Teardown the handler.\"\"\"\n"
  },
  {
    "path": "packages/fetchai/skills/advanced_data_request/models.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains a model for the AdvancedDataRequest skill\"\"\"\n\nfrom typing import Any\n\nfrom aea.skills.base import Model\n\n\nDEFAULT_URL = \"\"\nDEFAULT_METHOD = \"GET\"\nDEFAULT_BODY = \"\"\nDEFAULT_OUTPUTS = None\nDEFAULT_DECIMALS = 5\nDEFAULT_USE_HTTP_SERVER = False\n\nHTTP_REQUEST_METHODS = {\"GET\", \"PUT\", \"POST\", \"PATCH\", \"DELETE\"}\n\n\nclass AdvancedDataRequestModel(Model):\n    \"\"\"This class models the AdvancedDataRequest skill.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        self.url = kwargs.pop(\"url\", DEFAULT_URL)\n        self.method = kwargs.pop(\"method\", DEFAULT_METHOD)\n        self.body = kwargs.pop(\"body\", DEFAULT_BODY)\n        self.outputs = kwargs.pop(\"outputs\", DEFAULT_OUTPUTS)\n        self.decimals = kwargs.pop(\"decimals\", DEFAULT_DECIMALS)\n        self.use_http_server = kwargs.pop(\"use_http_server\", DEFAULT_USE_HTTP_SERVER)\n\n        Model.__init__(self, **kwargs)\n\n        self._validate_config()\n\n    def _validate_config(self) -> None:  # pragma: nocover\n        \"\"\"Ensure the configuration settings are all valid.\"\"\"\n        msg = []\n        if not isinstance(self.url, str):\n            msg.append(\"'url' must be provided as a string\")\n        if self.method not in HTTP_REQUEST_METHODS:\n            msg.append(f\"'method' must be one of {HTTP_REQUEST_METHODS}\")\n        if not isinstance(self.body, str):\n            msg.append(\"'body' must be provided as a string\")\n        if not isinstance(self.outputs, list):\n            msg.append(\"outputs must be provided as a list\")\n        else:\n            for (ind, output) in enumerate(self.outputs):\n                if not isinstance(output, dict):\n                    msg.append(f\"output {ind} must be a dict\")\n                else:\n                    if \"name\" not in output:\n                        msg.append(f\"output {ind} must include key 'name'\")\n                    if \"json_path\" not in output:\n                        msg.append(f\"output {ind} must include key 'json_path'\")\n        if not isinstance(self.decimals, int):\n            msg.append(\"'decimals' must be provided as an integer\")\n        if not isinstance(self.use_http_server, bool):\n            msg.append(\"'use_http_server' must be provided as a bool\")\n\n        if msg:\n            raise ValueError(\"Invalid skill configuration: \" + \",\".join(msg))\n"
  },
  {
    "path": "packages/fetchai/skills/advanced_data_request/skill.yaml",
    "content": "name: advanced_data_request\nauthor: fetchai\nversion: 0.7.6\ntype: skill\ndescription: Retrieve data from an API\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: QmaibnVqk95FVuhSXKCsYvUQFAkLCwYtPyWDmaNVDSFWvp\n  __init__.py: QmenhXvYML3HKHzYufiHqxCKqyaFLxdyDvAzQGdEF31ZSy\n  api_spec.yaml: QmUPhCYr6tWDMysdMCQxT67oAKRdMbGpgqDfAA5wpei12s\n  behaviours.py: QmNubn8GCjV2d12FQu2Zv3FjXyoxoEsKzAg3fbskhtL3S2\n  dialogues.py: QmQxtJ6xqwGkbTEJX2rn8YDDhdvSCe3HhbyQYTaz9FknrG\n  handlers.py: QmP3hpp4LmW3ZX63LScByXKojaa9CVpTKocWf8eLu978nw\n  models.py: QmV7PcnNvogzj4PwAMZ8CQvsTaxEKJMKVgkatSHba1RJxt\nfingerprint_ignore_patterns: []\ncontracts: []\nprotocols:\n- fetchai/http:1.1.7\n- fetchai/prometheus:1.1.7\nskills: []\nbehaviours:\n  advanced_data_request_behaviour:\n    args:\n      tick_interval: 5\n    class_name: AdvancedDataRequestBehaviour\nhandlers:\n  http:\n    args: {}\n    class_name: HttpHandler\n  prometheus:\n    args: {}\n    class_name: PrometheusHandler\nmodels:\n  advanced_data_request_model:\n    args:\n      body: ''\n      decimals: 5\n      method: GET\n      outputs: []\n      url: ''\n      use_http_server: false\n    class_name: AdvancedDataRequestModel\n  http_dialogues:\n    args: {}\n    class_name: HttpDialogues\n  prometheus_dialogues:\n    args:\n      enabled: true\n      metrics:\n      - name: num_retrievals\n        type: Gauge\n        description: Number of data retrievals\n        labels: {}\n      - name: num_requests\n        type: Gauge\n        description: Number of data requests served\n        labels: {}\n    class_name: PrometheusDialogues\ndependencies: {}\nis_abstract: false\nconnections: []\n"
  },
  {
    "path": "packages/fetchai/skills/aries_alice/README.md",
    "content": "# Aries Alice\n\n## Description\n\nThis skill emulates the Alice actor in <a href=\"https://github.com/hyperledger/aries-cloudagent-python/blob/master/demo/README.md\" target=\"_blank\">this demo</a>.\n\nThis skill is part of the Fetch.ai Aries demo. It simulates the Alice actor of the demo linked above. It first registers Alice on the sOEF. It then receives invitation details from Faber AEA. Then it connects with an underlying Aries cloud agent (ACA) instance and executes an `accept-invitation` command.\n\n## Behaviours\n\n- `alice`: registers and unregisters Alice AEA on the sOEF\n\n## Handlers\n\n- `default`: handles `default` messages for the invitation detail it receives from the Faber AEA\n- `http`: handles `http` messages for communicating with Alice ACA\n- `oef_search`: handles `oef_search` messages if registration on the sOEF was erratic\n\n## Links\n\n- <a href=\"https://docs.fetch.ai/aea/aries-cloud-agent-demo/\" target=\"_blank\">AEA Aries Demo</a>\n- <a href=\"https://github.com/hyperledger/aries-cloudagent-python/blob/master/demo/README.md\" target=\"_blank\">Hyperledger Demo</a>\n"
  },
  {
    "path": "packages/fetchai/skills/aries_alice/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the implementation of the aries_alice skill.\"\"\"\n\nfrom aea.configurations.base import PublicId\n\n\nPUBLIC_ID = PublicId.from_str(\"fetchai/aries_alice:0.26.6\")\n"
  },
  {
    "path": "packages/fetchai/skills/aries_alice/behaviours.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains the behaviour of a generic seller AEA.\"\"\"\n\nimport json\nfrom typing import Any, Dict, Optional, cast\n\nfrom aea.helpers.search.models import Description\nfrom aea.skills.behaviours import TickerBehaviour\n\nfrom packages.fetchai.connections.http_client.connection import (\n    PUBLIC_ID as HTTP_CLIENT_PUBLIC_ID,\n)\nfrom packages.fetchai.protocols.http.message import HttpMessage\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.skills.aries_alice.dialogues import (\n    HttpDialogues,\n    OefSearchDialogues,\n)\nfrom packages.fetchai.skills.aries_alice.strategy import Strategy\n\n\nDEFAULT_MAX_SOEF_REGISTRATION_RETRIES = 5\nDEFAULT_SERVICES_INTERVAL = 60.0\n\n\nclass AliceBehaviour(TickerBehaviour):\n    \"\"\"This class implements a behaviour.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"Initialise the behaviour.\"\"\"\n\n        services_interval = kwargs.pop(\n            \"services_interval\", DEFAULT_SERVICES_INTERVAL\n        )  # type: int\n        self._max_soef_registration_retries = kwargs.pop(\n            \"max_soef_registration_retries\", DEFAULT_MAX_SOEF_REGISTRATION_RETRIES\n        )  # type: int\n        super().__init__(tick_interval=services_interval, **kwargs)\n        self.failed_registration_msg = None  # type: Optional[OefSearchMessage]\n        self._nb_retries = 0\n\n    def send_http_request_message(\n        self, method: str, url: str, content: Dict = None\n    ) -> None:\n        \"\"\"\n        Send an http request message.\n\n        :param method: the http request method (i.e. 'GET' or 'POST').\n        :param url: the url to send the message to.\n        :param content: the payload.\n        \"\"\"\n        # context\n        http_dialogues = cast(HttpDialogues, self.context.http_dialogues)\n\n        # http request message\n        request_http_message, _ = http_dialogues.create(\n            counterparty=str(HTTP_CLIENT_PUBLIC_ID),\n            performative=HttpMessage.Performative.REQUEST,\n            method=method,\n            url=url,\n            headers=\"Content-Type: application/json\",\n            version=\"\",\n            body=b\"\" if content is None else json.dumps(content).encode(\"utf-8\"),\n        )\n        # send\n        self.context.outbox.put_message(message=request_http_message)\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup.\"\"\"\n        self.context.logger.info(\"My address is: \" + self.context.agent_address)\n        self._register_agent()\n\n    def act(self) -> None:\n        \"\"\"Implement the act.\"\"\"\n        self._retry_failed_registration()\n        self.perform_agents_search()\n\n    def perform_agents_search(self) -> None:\n        \"\"\"Perform agents search to query proofs from.\"\"\"\n        strategy = cast(Strategy, self.context.strategy)\n        if not strategy.is_searching:\n            return\n\n        query = strategy.get_location_and_service_query()\n        oef_search_dialogues = cast(\n            OefSearchDialogues, self.context.oef_search_dialogues\n        )\n        oef_search_msg, _ = oef_search_dialogues.create(\n            counterparty=self.context.search_service_address,\n            performative=OefSearchMessage.Performative.SEARCH_SERVICES,\n            query=query,\n        )\n        self.context.outbox.put_message(message=oef_search_msg)\n        self.context.logger.info(\"Searching for agents on SOEF...\")\n\n    def teardown(self) -> None:\n        \"\"\"Implement the task teardown.\"\"\"\n        self._unregister_service()\n        self._unregister_agent()\n\n    def _retry_failed_registration(self) -> None:\n        \"\"\"Retry a failed registration.\"\"\"\n        if self.failed_registration_msg is not None:\n            self._nb_retries += 1\n            if self._nb_retries > self._max_soef_registration_retries:\n                self.context.is_active = False\n                return\n\n            oef_search_dialogues = cast(\n                OefSearchDialogues, self.context.oef_search_dialogues\n            )\n            oef_search_msg, _ = oef_search_dialogues.create(\n                counterparty=self.failed_registration_msg.to,\n                performative=self.failed_registration_msg.performative,\n                service_description=self.failed_registration_msg.service_description,\n            )\n            self.context.outbox.put_message(message=oef_search_msg)\n            self.context.logger.info(\n                f\"Retrying registration on SOEF. Retry {self._nb_retries} out of {self._max_soef_registration_retries}.\"\n            )\n\n            self.failed_registration_msg = None\n\n    def _register(self, description: Description, logger_msg: str) -> None:\n        \"\"\"\n        Register something on the SOEF.\n\n        :param description: the description of what is being registered\n        :param logger_msg: the logger message to print after the registration\n        \"\"\"\n        oef_search_dialogues = cast(\n            OefSearchDialogues, self.context.oef_search_dialogues\n        )\n        oef_search_msg, _ = oef_search_dialogues.create(\n            counterparty=self.context.search_service_address,\n            performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n            service_description=description,\n        )\n        self.context.outbox.put_message(message=oef_search_msg)\n        self.context.logger.info(logger_msg)\n\n    def _register_agent(self) -> None:\n        \"\"\"Register the agent's location.\"\"\"\n        strategy = cast(Strategy, self.context.strategy)\n        description = strategy.get_location_description()\n        self._register(description, \"registering agent on SOEF.\")\n\n    def register_service(self) -> None:\n        \"\"\"Register the agent's service.\"\"\"\n        strategy = cast(Strategy, self.context.strategy)\n        description = strategy.get_register_service_description()\n        self._register(description, \"registering agent's service on the SOEF.\")\n\n    def register_genus(self) -> None:\n        \"\"\"Register the agent's personality genus.\"\"\"\n        strategy = cast(Strategy, self.context.strategy)\n        description = strategy.get_register_personality_description()\n        self._register(\n            description, \"registering agent's personality genus on the SOEF.\"\n        )\n\n    def register_classification(self) -> None:\n        \"\"\"Register the agent's personality classification.\"\"\"\n        strategy = cast(Strategy, self.context.strategy)\n        description = strategy.get_register_classification_description()\n        self._register(\n            description, \"registering agent's personality classification on the SOEF.\"\n        )\n\n    def _unregister_service(self) -> None:\n        \"\"\"Unregister service from the SOEF.\"\"\"\n        strategy = cast(Strategy, self.context.strategy)\n        description = strategy.get_unregister_service_description()\n        oef_search_dialogues = cast(\n            OefSearchDialogues, self.context.oef_search_dialogues\n        )\n        oef_search_msg, _ = oef_search_dialogues.create(\n            counterparty=self.context.search_service_address,\n            performative=OefSearchMessage.Performative.UNREGISTER_SERVICE,\n            service_description=description,\n        )\n        self.context.outbox.put_message(message=oef_search_msg)\n        self.context.logger.info(\"unregistering service from SOEF.\")\n\n    def _unregister_agent(self) -> None:\n        \"\"\"Unregister agent from the SOEF.\"\"\"\n        strategy = cast(Strategy, self.context.strategy)\n        description = strategy.get_location_description()\n        oef_search_dialogues = cast(\n            OefSearchDialogues, self.context.oef_search_dialogues\n        )\n        oef_search_msg, _ = oef_search_dialogues.create(\n            counterparty=self.context.search_service_address,\n            performative=OefSearchMessage.Performative.UNREGISTER_SERVICE,\n            service_description=description,\n        )\n        self.context.outbox.put_message(message=oef_search_msg)\n        self.context.logger.info(\"unregistering agent from SOEF.\")\n"
  },
  {
    "path": "packages/fetchai/skills/aries_alice/dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nThis module contains the classes required for dialogue management.\n\n- Dialogue: The dialogue class maintains state of a dialogue and manages it.\n- Dialogues: The dialogues class keeps track of all dialogues.\n\"\"\"\n\nfrom typing import Any\n\nfrom aea.protocols.base import Address, Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\nfrom aea.skills.base import Model\n\nfrom packages.fetchai.protocols.default.dialogues import (\n    DefaultDialogue as BaseDefaultDialogue,\n)\nfrom packages.fetchai.protocols.default.dialogues import (\n    DefaultDialogues as BaseDefaultDialogues,\n)\nfrom packages.fetchai.protocols.http.dialogues import HttpDialogue as BaseHttpDialogue\nfrom packages.fetchai.protocols.http.dialogues import HttpDialogues as BaseHttpDialogues\nfrom packages.fetchai.protocols.oef_search.dialogues import (\n    OefSearchDialogue as BaseOefSearchDialogue,\n)\nfrom packages.fetchai.protocols.oef_search.dialogues import (\n    OefSearchDialogues as BaseOefSearchDialogues,\n)\n\n\nDefaultDialogue = BaseDefaultDialogue\n\n\nclass DefaultDialogues(Model, BaseDefaultDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return DefaultDialogue.Role.AGENT\n\n        BaseDefaultDialogues.__init__(\n            self,\n            self_address=self.context.agent_address,\n            role_from_first_message=role_from_first_message,\n        )\n\n\nHttpDialogue = BaseHttpDialogue\n\n\nclass HttpDialogues(Model, BaseHttpDialogues):\n    \"\"\"This class keeps track of all http dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return BaseHttpDialogue.Role.CLIENT\n\n        BaseHttpDialogues.__init__(\n            self,\n            self_address=str(self.skill_id),\n            role_from_first_message=role_from_first_message,\n        )\n\n\nOefSearchDialogue = BaseOefSearchDialogue\n\n\nclass OefSearchDialogues(Model, BaseOefSearchDialogues):\n    \"\"\"This class keeps track of all oef_search dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return BaseOefSearchDialogue.Role.AGENT\n\n        BaseOefSearchDialogues.__init__(\n            self,\n            self_address=str(self.skill_id),\n            role_from_first_message=role_from_first_message,\n        )\n"
  },
  {
    "path": "packages/fetchai/skills/aries_alice/handlers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This package contains the handlers for the aries_alice skill.\"\"\"\nimport json\nfrom typing import Any, Dict, List, Optional, cast\n\nfrom aea.common import Address\nfrom aea.configurations.base import PublicId\nfrom aea.protocols.base import Message\nfrom aea.skills.base import Handler\n\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.protocols.http.message import HttpMessage\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.skills.aries_alice.behaviours import AliceBehaviour\nfrom packages.fetchai.skills.aries_alice.dialogues import (\n    DefaultDialogue,\n    DefaultDialogues,\n    HttpDialogue,\n    HttpDialogues,\n    OefSearchDialogue,\n    OefSearchDialogues,\n)\nfrom packages.fetchai.skills.aries_alice.strategy import (\n    ADMIN_COMMAND_CREATE_INVITATION,\n    ADMIN_COMMAND_RECEIVE_INVITE,\n    Strategy,\n)\n\n\nclass DefaultHandler(Handler):\n    \"\"\"This class represents alice's handler for default messages.\"\"\"\n\n    SUPPORTED_PROTOCOL = DefaultMessage.protocol_id  # type: Optional[PublicId]\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to an envelope.\n\n        :param message: the message\n        \"\"\"\n        message = cast(DefaultMessage, message)\n        # recover dialogue\n        default_dialogues = cast(DefaultDialogues, self.context.default_dialogues)\n        default_dialogue = cast(\n            Optional[DefaultDialogue], default_dialogues.update(message)\n        )\n        if default_dialogue is None:\n            self.context.logger.error(\n                \"alice -> default_handler -> handle(): something went wrong when adding the incoming default message to the dialogue.\"\n            )\n            return\n\n        if message.performative == DefaultMessage.Performative.BYTES:\n            content_bytes = message.content\n            content = json.loads(content_bytes)\n            self.context.logger.info(\"Received message content:\" + repr(content))\n            # accept invite\n            if \"@type\" in content:\n                strategy = cast(Strategy, self.context.strategy)\n                strategy.invitations[content[\"@id\"]] = message.sender\n                self.context.behaviours.alice.send_http_request_message(\n                    method=\"POST\",\n                    url=strategy.admin_url\n                    + ADMIN_COMMAND_RECEIVE_INVITE\n                    + \"?auto_accept=true\",\n                    content=content,\n                )\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n\n\nclass HttpHandler(Handler):\n    \"\"\"This class represents alice's handler for HTTP messages.\"\"\"\n\n    SUPPORTED_PROTOCOL = HttpMessage.protocol_id  # type: Optional[PublicId]\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"Initialize the handler.\"\"\"\n        super().__init__(**kwargs)\n\n        self.connected: Dict[str, Address] = {}  # conn_id: agent addr\n        self.addr_names: Dict[Address, str] = {}  # agent addr: agent name\n        self.connections_sent: Dict[str, Address] = {}  # conn_id: agent addr\n        self.cred_def_id: Optional[str] = None\n        self.presentation_requests: List[Dict] = []\n\n    @property\n    def invitations(self) -> Dict[str, str]:\n        \"\"\"Get list of invitation sent from the strategy object.\"\"\"\n        strategy = cast(Strategy, self.context.strategy)\n        return strategy.invitations\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to an envelope.\n\n        :param message: the message\n        \"\"\"\n        message = cast(HttpMessage, message)\n        strategy = cast(Strategy, self.context.strategy)\n\n        # recover dialogue\n        http_dialogues = cast(HttpDialogues, self.context.http_dialogues)\n        http_dialogue = cast(Optional[HttpDialogue], http_dialogues.update(message))\n        if http_dialogue is None:\n            self.context.logger.error(\n                \"alice -> http_handler -> handle() -> REQUEST: something went wrong when adding the incoming HTTP webhook request message to the dialogue.\"\n            )\n            return\n\n        if message.performative == HttpMessage.Performative.REQUEST:  # webhook\n            content_bytes = message.body\n            self.context.logger.info(\n                \"Received webhook message content:\" + str(content_bytes)\n            )\n            content = json.loads(content_bytes)\n\n            if \"invitation_msg_id\" in content:\n                if content[\"invitation_msg_id\"] in self.invitations:\n                    if (\n                        content[\"state\"] == \"active\"\n                        and content[\"connection_id\"] not in self.connected\n                    ):\n                        self.context.logger.info(\n                            f\"Connected to {content['their_label']}\"\n                        )\n                        self.connected[content[\"connection_id\"]] = self.invitations[\n                            content[\"invitation_msg_id\"]\n                        ]\n                        name = content[\"their_label\"]\n                        self.addr_names[\n                            self.invitations[content[\"invitation_msg_id\"]]\n                        ] = name\n                        if name != \"faber\":\n                            body = {\n                                \"connection_id\": content[\"connection_id\"],\n                                \"proof_request\": {\n                                    \"name\": \"Proof of Education\",\n                                    \"version\": \"1.0\",\n                                    \"requested_attributes\": {\n                                        \"0_name_uuid\": {\n                                            \"name\": \"name\",\n                                            \"restrictions\": [\n                                                {\"cred_def_id\": self.cred_def_id}\n                                            ],\n                                        },\n                                        \"0_date_uuid\": {\n                                            \"name\": \"date\",\n                                            \"restrictions\": [\n                                                {\"cred_def_id\": self.cred_def_id}\n                                            ],\n                                        },\n                                        \"0_degree_uuid\": {\n                                            \"name\": \"degree\",\n                                            \"restrictions\": [\n                                                {\"cred_def_id\": self.cred_def_id}\n                                            ],\n                                        },\n                                        \"0_self_attested_thing_uuid\": {\n                                            \"name\": \"self_attested_thing\"\n                                        },\n                                    },\n                                    \"requested_predicates\": {},\n                                },\n                            }\n                            self.context.behaviours.alice.send_http_request_message(\n                                method=\"POST\",\n                                url=strategy.admin_url + \"/present-proof/send-request\",\n                                content=body,\n                            )\n                            self.context.logger.info(\n                                f\"Sent credentials proof request to {name}\"\n                            )\n            elif \"presentation_request_dict\" in content:\n                if content[\"role\"] == \"prover\":\n                    if content[\"state\"] == \"request_received\":\n                        self.context.behaviours.alice.send_http_request_message(\n                            method=\"GET\",\n                            url=strategy.admin_url\n                            + f\"/present-proof/records/{content['presentation_exchange_id']}/credentials\",\n                        )\n                        self.presentation_requests.append(content)\n                        self.context.logger.info(\"Got credentials proof request\")\n                elif (\n                    content[\"role\"] == \"verifier\"\n                    and content[\"state\"] == \"presentation_received\"\n                ):\n                    name = self.addr_names[self.connected[content[\"connection_id\"]]]\n                    self.context.logger.info(f\"Got credentials proof from {name}\")\n            elif \"credential_proposal_dict\" in content:\n                if content[\"state\"] == \"credential_acked\":\n                    self.cred_def_id = content[\"raw_credential\"][\"cred_def_id\"]\n                    self.context.logger.info(\n                        f\"Got crendetials from faber: schema:{self.cred_def_id} {content['credential_proposal_dict']['credential_proposal']}\"\n                    )\n\n                    strategy.is_searching = True\n                    self.context.behaviours.alice.perform_agents_search()\n            else:\n                self.context.logger.warning(f\"unknown message {content}\")\n        elif (\n            message.performative == HttpMessage.Performative.RESPONSE\n        ):  # response to http_client request\n            content_bytes = message.body\n            content = json.loads(content_bytes)\n            self.context.logger.info(f\"Got response {content}\")\n\n            if \"Error\" in content:\n                self.context.logger.error(\n                    \"Something went wrong after I sent the administrative command of 'invitation receive'\"\n                )\n            elif \"presentation_referents\" in str(content):\n                self._handle_creds_for_proof_request(content)\n            else:\n                self.context.logger.info(\n                    f\"Received http response message content:{str(content)}\"\n                )\n                if \"invitation\" in content:\n                    self._send_invitation_message(content)\n\n    def _handle_creds_for_proof_request(self, credentials: Dict) -> None:\n        self.context.logger.info(\"start proof generating\")\n        strategy = cast(Strategy, self.context.strategy)\n        credentials_by_ref = {}  # type: ignore\n        revealed = {}\n        self_attested = {}\n        predicates = {}\n        if not self.presentation_requests:\n            self.context.logger.warning(\"No presentastion requests pending\")\n            return\n        presentation_request = self.presentation_requests.pop()\n        if credentials:\n            for row in credentials:\n                for referent in row[\"presentation_referents\"]:\n                    if referent not in credentials_by_ref:\n                        credentials_by_ref[referent] = row\n\n        for referent in presentation_request[\"presentation_request\"][\n            \"requested_attributes\"\n        ]:\n            if referent in credentials_by_ref:\n                revealed[referent] = {\n                    \"cred_id\": credentials_by_ref[referent][\"cred_info\"][\"referent\"],\n                    \"revealed\": True,\n                }\n            else:\n                self_attested[referent] = \"my self-attested value\"\n\n        for referent in presentation_request[\"presentation_request\"][\n            \"requested_predicates\"\n        ]:\n            if referent in credentials_by_ref:\n                predicates[referent] = {\n                    \"cred_id\": credentials_by_ref[referent][\"cred_info\"][\"referent\"],\n                    \"revealed\": True,\n                }\n\n        request = {\n            \"requested_predicates\": predicates,\n            \"requested_attributes\": revealed,\n            \"self_attested_attributes\": self_attested,\n        }\n        presentation_exchange_id = presentation_request[\"presentation_exchange_id\"]\n        self.context.behaviours.alice.send_http_request_message(\n            method=\"POST\",\n            url=strategy.admin_url\n            + \"/present-proof/records/\"\n            + f\"{presentation_exchange_id}/send-presentation\",\n            content=request,\n        )\n        self.context.logger.info(\"proof generated and sent\")\n\n    def _send_invitation_message(self, connection: Dict) -> None:\n        \"\"\"\n        Send a default message to Alice.\n\n        :param connection: the content of the connection message.\n        \"\"\"\n        strategy = cast(Strategy, self.context.strategy)\n        # context\n        connections_unsent = list(\n            set(strategy.aea_addresses) - set(self.connections_sent.values())\n        )\n        if not connections_unsent:\n            self.context.logger.info(\n                \"Every invitation pushed, skip this new connection\"\n            )\n            return\n        target = connections_unsent[0]\n        invitation = connection[\"invitation\"]\n\n        self.connections_sent[connection[\"connection_id\"]] = target\n\n        default_dialogues = cast(DefaultDialogues, self.context.default_dialogues)\n        message, _ = default_dialogues.create(\n            counterparty=target,\n            performative=DefaultMessage.Performative.BYTES,\n            content=json.dumps(invitation).encode(\"utf-8\"),\n        )\n        # send\n        self.context.outbox.put_message(message=message)\n\n        self.context.logger.info(f\"connection: {str(connection)}\")\n        self.context.logger.info(f\"connection id: {connection['connection_id']}\")  # type: ignore\n        self.context.logger.info(f\"invitation: {str(invitation)}\")\n        self.context.logger.info(\n            f\"Sent invitation to {target}. Waiting for the invitation from agent {target} to finalise the connection...\"\n        )\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n\n\nclass OefSearchHandler(Handler):\n    \"\"\"This class implements an OEF search handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = OefSearchMessage.protocol_id  # type: Optional[PublicId]\n\n    def setup(self) -> None:\n        \"\"\"Call to setup the handler.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to a message.\n\n        :param message: the message\n        \"\"\"\n        oef_search_msg = cast(OefSearchMessage, message)\n\n        # recover dialogue\n        oef_search_dialogues = cast(\n            OefSearchDialogues, self.context.oef_search_dialogues\n        )\n        oef_search_dialogue = cast(\n            Optional[OefSearchDialogue], oef_search_dialogues.update(oef_search_msg)\n        )\n        if oef_search_dialogue is None:\n            self._handle_unidentified_dialogue(oef_search_msg)\n            return\n\n        # handle message\n        if oef_search_msg.performative == OefSearchMessage.Performative.SUCCESS:\n            self._handle_success(oef_search_msg, oef_search_dialogue)\n        elif oef_search_msg.performative == OefSearchMessage.Performative.OEF_ERROR:\n            self._handle_error(oef_search_msg, oef_search_dialogue)\n        elif oef_search_msg.performative is OefSearchMessage.Performative.SEARCH_RESULT:\n            self._handle_search(oef_search_msg)\n        else:\n            self._handle_invalid(oef_search_msg, oef_search_dialogue)\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n\n    def _handle_unidentified_dialogue(self, oef_search_msg: OefSearchMessage) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param oef_search_msg: the oef search message\n        \"\"\"\n        self.context.logger.info(\n            \"received invalid oef_search message={}, unidentified dialogue.\".format(\n                oef_search_msg\n            )\n        )\n\n    def _handle_success(\n        self,\n        oef_search_success_msg: OefSearchMessage,\n        oef_search_dialogue: OefSearchDialogue,\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param oef_search_success_msg: the oef search message\n        :param oef_search_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.info(\n            \"received oef_search success message={} in dialogue={}.\".format(\n                oef_search_success_msg, oef_search_dialogue\n            )\n        )\n        target_message = cast(\n            OefSearchMessage,\n            oef_search_dialogue.get_message_by_id(oef_search_success_msg.target),\n        )\n        if (\n            target_message.performative\n            == OefSearchMessage.Performative.REGISTER_SERVICE\n        ):\n            description = target_message.service_description\n            data_model_name = description.data_model.name\n            registration_behaviour = cast(\n                AliceBehaviour,\n                self.context.behaviours.alice,\n            )\n            if \"location_agent\" in data_model_name:\n                registration_behaviour.register_service()\n            elif \"set_service_key\" in data_model_name:\n                registration_behaviour.register_genus()\n            elif (\n                \"personality_agent\" in data_model_name\n                and description.values[\"piece\"] == \"genus\"\n            ):\n                registration_behaviour.register_classification()\n            elif (\n                \"personality_agent\" in data_model_name\n                and description.values[\"piece\"] == \"classification\"\n            ):\n                self.context.logger.info(\n                    \"the agent, with its genus and classification, and its service are successfully registered on the SOEF.\"\n                )\n            else:\n                self.context.logger.warning(\n                    f\"received soef SUCCESS message as a reply to the following unexpected message: {target_message}\"\n                )\n\n    def _handle_search(self, oef_search_msg: OefSearchMessage) -> None:\n        \"\"\"\n        Handle the search response.\n\n        :param oef_search_msg: the oef search message to be handled\n        \"\"\"\n\n        if len(oef_search_msg.agents) == 0:\n            self.context.logger.info(\"No agents found. Keep searching\")\n            return\n\n        self.context.logger.info(\n            f\"found agents {', '.join(oef_search_msg.agents)}, stopping search.\"\n        )\n\n        strategy = cast(Strategy, self.context.strategy)\n        strategy.is_searching = False\n\n        strategy.aea_addresses = list(oef_search_msg.agents)\n\n        # send invitations\n        for addr in strategy.aea_addresses:\n            self.context.behaviours.alice.send_http_request_message(\n                method=\"POST\",\n                url=strategy.admin_url + ADMIN_COMMAND_CREATE_INVITATION,\n            )\n            self.context.logger.info(f\"created an invitation for {addr}.\")\n\n    def _handle_error(\n        self,\n        oef_search_error_msg: OefSearchMessage,\n        oef_search_dialogue: OefSearchDialogue,\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param oef_search_error_msg: the oef search message\n        :param oef_search_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.info(\n            \"received oef_search error message={} in dialogue={}.\".format(\n                oef_search_error_msg, oef_search_dialogue\n            )\n        )\n        target_message = cast(\n            OefSearchMessage,\n            oef_search_dialogue.get_message_by_id(oef_search_error_msg.target),\n        )\n        if (\n            target_message.performative\n            == OefSearchMessage.Performative.REGISTER_SERVICE\n        ):\n            alice_behaviour = cast(\n                AliceBehaviour,\n                self.context.behaviours.alice,\n            )\n            alice_behaviour.failed_registration_msg = target_message\n\n    def _handle_invalid(\n        self, oef_search_msg: OefSearchMessage, oef_search_dialogue: OefSearchDialogue\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param oef_search_msg: the oef search message\n        :param oef_search_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.warning(\n            \"cannot handle oef_search message of performative={} in dialogue={}.\".format(\n                oef_search_msg.performative,\n                oef_search_dialogue,\n            )\n        )\n"
  },
  {
    "path": "packages/fetchai/skills/aries_alice/skill.yaml",
    "content": "name: aries_alice\nauthor: fetchai\nversion: 0.26.6\ntype: skill\ndescription: The aries_alice skill implements the alice player in the aries cloud\n  agent demo\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: QmdtgELuz8SmSp3xdHdktd1SvmzSFsavwVYXjZxPMke5ij\n  __init__.py: QmRdtdKnWntg3VjdGRQq4Yc2SErjD5k3epVVPmthAbZJXj\n  behaviours.py: QmYc2UCizXg86mBBjS43K73Bq3URdnsW5BefnzfzA7fz4k\n  dialogues.py: QmQvsX9sx5bDf588rrXmT2kzZSZapVpix2TkX4x422iTiu\n  handlers.py: QmZ4fc49cqp92ApccgyE27WtkSkYbPj3CTendnEgYyVVuL\n  strategy.py: QmP63YEBF9tQKSDYENn26D6x8fLqFtpU2npNK4mysdxsBz\nfingerprint_ignore_patterns: []\nconnections:\n- fetchai/http_client:0.24.6\ncontracts: []\nprotocols:\n- fetchai/default:1.1.7\n- fetchai/http:1.1.7\n- fetchai/oef_search:1.1.7\nskills: []\nbehaviours:\n  alice:\n    args:\n      max_soef_registration_retries: 5\n      services_interval: 20\n    class_name: AliceBehaviour\nhandlers:\n  default:\n    args: {}\n    class_name: DefaultHandler\n  http:\n    args: {}\n    class_name: HttpHandler\n  oef_search:\n    args: {}\n    class_name: OefSearchHandler\nmodels:\n  default_dialogues:\n    args: {}\n    class_name: DefaultDialogues\n  http_dialogues:\n    args: {}\n    class_name: HttpDialogues\n  oef_search_dialogues:\n    args: {}\n    class_name: OefSearchDialogues\n  strategy:\n    args:\n      admin_host: 127.0.0.1\n      admin_port: 8031\n      classification:\n        piece: classification\n        value: identity.aries.alice\n      location:\n        latitude: 51.5194\n        longitude: 0.127\n      personality_data:\n        piece: genus\n        value: data\n      search_query:\n        constraint_type: ==\n        search_key: intro_service\n        search_value: intro_alice\n      seed: null\n      service_data:\n        key: intro_service\n        value: intro_alice\n    class_name: Strategy\ndependencies: {}\nis_abstract: false\n"
  },
  {
    "path": "packages/fetchai/skills/aries_alice/strategy.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the strategy class.\"\"\"\nimport random\nfrom typing import Any, Dict, List\n\nfrom aea.common import Address\nfrom aea.exceptions import enforce\nfrom aea.helpers.search.generic import (\n    AGENT_LOCATION_MODEL,\n    AGENT_PERSONALITY_MODEL,\n    AGENT_REMOVE_SERVICE_MODEL,\n    AGENT_SET_SERVICE_MODEL,\n)\nfrom aea.helpers.search.models import (\n    Constraint,\n    ConstraintType,\n    Description,\n    Location,\n    Query,\n)\nfrom aea.skills.base import Model\n\n\n# Search\nDEFAULT_LOCATION = {\"longitude\": 0.1270, \"latitude\": 51.5194}\nDEFAULT_SEARCH_QUERY = {\n    \"search_key\": \"intro_service\",\n    \"search_value\": \"intro_alice\",\n    \"constraint_type\": \"==\",\n}\nDEFAULT_SEARCH_RADIUS = 5.0\n\n\n# default configs\nDEFAULT_ADMIN_HOST = \"127.0.0.1\"\nDEFAULT_ADMIN_PORT = 8031\n\n# commands\nADMIN_COMMAND_RECEIVE_INVITE = \"/connections/receive-invitation\"\nADMIN_COMMAND_CREATE_INVITATION = \"/connections/create-invitation\"\n\n# convenience\nALICE_ACA_IDENTITY = \"Alice_ACA\"\nHTTP_COUNTERPARTY = \"HTTP Server\"\n\n# search\nDEFAULT_LOCATION = {\"longitude\": 0.1270, \"latitude\": 51.5194}\nDEFAULT_SERVICE_DATA = {\"key\": \"intro_service\", \"value\": \"intro_alice\"}\nDEFAULT_PERSONALITY_DATA = {\"piece\": \"genus\", \"value\": \"data\"}\nDEFAULT_CLASSIFICATION = {\"piece\": \"classification\", \"value\": \"identity.aries.alice\"}\n\n\nclass Strategy(Model):\n    \"\"\"This class defines a strategy for the agent.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize the strategy of the agent.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        # config\n        self._admin_host = kwargs.pop(\"admin_host\", DEFAULT_ADMIN_HOST)\n        self._admin_port = kwargs.pop(\"admin_port\", DEFAULT_ADMIN_PORT)\n\n        self._admin_url = f\"http://{self.admin_host}:{self.admin_port}\"\n\n        self._seed = (\n            kwargs.pop(\n                \"seed\",\n                None,\n            )\n            or (\n                \"my_seed_000000000000000000000000\"\n                + str(random.randint(100_000, 999_999))  # nosec\n            )[-32:]\n        )\n\n        # search\n        location = kwargs.pop(\"location\", DEFAULT_LOCATION)\n        self._agent_location = {\n            \"location\": Location(\n                latitude=location[\"latitude\"], longitude=location[\"longitude\"]\n            )\n        }\n        self._set_personality_data = kwargs.pop(\n            \"personality_data\", DEFAULT_PERSONALITY_DATA\n        )\n        enforce(\n            len(self._set_personality_data) == 2\n            and \"piece\" in self._set_personality_data\n            and \"value\" in self._set_personality_data,\n            \"personality_data must contain keys `key` and `value`\",\n        )\n        self._set_classification = kwargs.pop(\"classification\", DEFAULT_CLASSIFICATION)\n        enforce(\n            len(self._set_classification) == 2\n            and \"piece\" in self._set_classification\n            and \"value\" in self._set_classification,\n            \"classification must contain keys `key` and `value`\",\n        )\n        self._set_service_data = kwargs.pop(\"service_data\", DEFAULT_SERVICE_DATA)\n        enforce(\n            len(self._set_service_data) == 2\n            and \"key\" in self._set_service_data\n            and \"value\" in self._set_service_data,\n            \"service_data must contain keys `key` and `value`\",\n        )\n        self._remove_service_data = {\"key\": self._set_service_data[\"key\"]}\n        self.is_searching = False\n        # Search\n        self._search_query = kwargs.pop(\"search_query\", DEFAULT_SEARCH_QUERY)\n        location = kwargs.pop(\"location\", DEFAULT_LOCATION)\n        self._radius = kwargs.pop(\"search_radius\", DEFAULT_SEARCH_RADIUS)\n        self.invitations: Dict[str, Address] = {}\n        self.connections: Dict[str, Address] = {}\n        self.aea_addresses: List[Address] = []\n\n        super().__init__(**kwargs)\n\n    @property\n    def admin_host(self) -> str:\n        \"\"\"Get the admin host.\"\"\"\n        return self._admin_host\n\n    @property\n    def admin_port(self) -> str:\n        \"\"\"Get the admin port.\"\"\"\n        return self._admin_port\n\n    @property\n    def admin_url(self) -> str:\n        \"\"\"Get the admin URL.\"\"\"\n        return self._admin_url\n\n    @property\n    def seed(self) -> str:\n        \"\"\"Get the wallet seed.\"\"\"\n        return self._seed\n\n    def get_location_and_service_query(self) -> Query:\n        \"\"\"\n        Get the location and service query of the agent.\n\n        :return: the query\n        \"\"\"\n        close_to_my_service = Constraint(\n            \"location\",\n            ConstraintType(\n                \"distance\", (self._agent_location[\"location\"], self._radius)\n            ),\n        )\n        service_key_filter = Constraint(\n            self._search_query[\"search_key\"],\n            ConstraintType(\n                self._search_query[\"constraint_type\"],\n                self._search_query[\"search_value\"],\n            ),\n        )\n        query = Query(\n            [close_to_my_service, service_key_filter],\n        )\n        return query\n\n    def get_location_description(self) -> Description:\n        \"\"\"\n        Get the location description.\n\n        :return: a description of the agent's location\n        \"\"\"\n        description = Description(\n            self._agent_location,\n            data_model=AGENT_LOCATION_MODEL,\n        )\n        return description\n\n    def get_register_service_description(self) -> Description:\n        \"\"\"\n        Get the register service description.\n\n        :return: a description of the offered services\n        \"\"\"\n        description = Description(\n            self._set_service_data,\n            data_model=AGENT_SET_SERVICE_MODEL,\n        )\n        return description\n\n    def get_register_personality_description(self) -> Description:\n        \"\"\"\n        Get the register personality description.\n\n        :return: a description of the personality\n        \"\"\"\n        description = Description(\n            self._set_personality_data,\n            data_model=AGENT_PERSONALITY_MODEL,\n        )\n        return description\n\n    def get_register_classification_description(self) -> Description:\n        \"\"\"\n        Get the register classification description.\n\n        :return: a description of the classification\n        \"\"\"\n        description = Description(\n            self._set_classification,\n            data_model=AGENT_PERSONALITY_MODEL,\n        )\n        return description\n\n    def get_unregister_service_description(self) -> Description:\n        \"\"\"\n        Get the unregister service description.\n\n        :return: a description of the to be removed service\n        \"\"\"\n        description = Description(\n            self._remove_service_data,\n            data_model=AGENT_REMOVE_SERVICE_MODEL,\n        )\n        return description\n"
  },
  {
    "path": "packages/fetchai/skills/aries_faber/README.md",
    "content": "# Aries Faber\n\n## Description\n\nThis skill emulates the Faber actor in <a href=\"https://github.com/hyperledger/aries-cloudagent-python/blob/master/demo/README.md\" target=\"_blank\">this demo</a>.\n\nThis skill is part of the Fetch.ai Aries demo. It simulates the Faber actor of the demo linked above. It first registers a decentralised ID on an underlying ledger. It then connects with an underlying Aries cloud agent (ACA) instance, and forwards the following instructions:\n\n- register schema definition\n- register credential definition\n- create an invitation\n\nIt then sends the invitation detail to an Alice agent that it finds via the sOEF.\n\n## Behaviours\n\n- `faber`: searches for Alice AEA\n\n## Handlers\n\n- `http`: handles `http` messages for communicating with the ledger and Faber ACA\n- `oef_search`: handles `oef_search` messages of finding Alice on the sOEF\n\n## Links\n\n- <a href=\"https://docs.fetch.ai/aea/aries-cloud-agent-demo/\" target=\"_blank\">AEA Aries Demo</a>\n- <a href=\"https://github.com/hyperledger/aries-cloudagent-python/blob/master/demo/README.md\" target=\"_blank\">Hyperledger Demo</a>\n"
  },
  {
    "path": "packages/fetchai/skills/aries_faber/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the implementation of the aries_faber skill.\"\"\"\n\nfrom aea.configurations.base import PublicId\n\n\nPUBLIC_ID = PublicId.from_str(\"fetchai/aries_faber:0.24.5\")\n"
  },
  {
    "path": "packages/fetchai/skills/aries_faber/behaviours.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains the behaviour for the aries_faber skill.\"\"\"\n\nimport json\nfrom typing import Any, Dict, cast\n\nfrom aea.skills.behaviours import TickerBehaviour\n\nfrom packages.fetchai.connections.http_client.connection import (\n    PUBLIC_ID as HTTP_CLIENT_PUBLIC_ID,\n)\nfrom packages.fetchai.protocols.http.message import HttpMessage\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.skills.aries_faber.dialogues import (\n    HttpDialogues,\n    OefSearchDialogues,\n)\nfrom packages.fetchai.skills.aries_faber.strategy import Strategy\n\n\nDEFAULT_SEARCH_INTERVAL = 5.0\n\n\nclass FaberBehaviour(TickerBehaviour):\n    \"\"\"This class represents the behaviour of faber.\"\"\"\n\n    def __init__(self, **kwargs: Any):\n        \"\"\"Initialize the handler.\"\"\"\n        search_interval = cast(\n            float, kwargs.pop(\"search_interval\", DEFAULT_SEARCH_INTERVAL)\n        )\n        super().__init__(tick_interval=search_interval, **kwargs)\n\n    def send_http_request_message(\n        self, method: str, url: str, content: Dict = None\n    ) -> None:\n        \"\"\"\n        Send an http request message.\n\n        :param method: the http request method (i.e. 'GET' or 'POST').\n        :param url: the url to send the message to.\n        :param content: the payload.\n        \"\"\"\n        # context\n        http_dialogues = cast(HttpDialogues, self.context.http_dialogues)\n\n        # http request message\n        request_http_message, _ = http_dialogues.create(\n            counterparty=str(HTTP_CLIENT_PUBLIC_ID),\n            performative=HttpMessage.Performative.REQUEST,\n            method=method,\n            url=url,\n            headers=\"Content-Type: application/json\",\n            version=\"\",\n            body=b\"\" if content is None else json.dumps(content).encode(\"utf-8\"),\n        )\n        # send\n        self.context.outbox.put_message(message=request_http_message)\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup.\"\"\"\n        strategy = cast(Strategy, self.context.strategy)\n        strategy.is_searching = True\n\n    def act(self) -> None:\n        \"\"\"Implement the act.\"\"\"\n        strategy = cast(Strategy, self.context.strategy)\n        if strategy.is_searching:\n            query = strategy.get_location_and_service_query()\n            oef_search_dialogues = cast(\n                OefSearchDialogues, self.context.oef_search_dialogues\n            )\n            oef_search_msg, _ = oef_search_dialogues.create(\n                counterparty=self.context.search_service_address,\n                performative=OefSearchMessage.Performative.SEARCH_SERVICES,\n                query=query,\n            )\n            self.context.outbox.put_message(message=oef_search_msg)\n            self.context.logger.info(\"Searching for Alice on SOEF...\")\n\n    def teardown(self) -> None:\n        \"\"\"Implement the task teardown.\"\"\"\n"
  },
  {
    "path": "packages/fetchai/skills/aries_faber/dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nThis module contains the classes required for dialogue management.\n\n- OefSearchDialogue: The dialogue class maintains state of a dialogue of type oef search and manages it.\n- OefSearchDialogues: The dialogues class keeps track of all dialogues of type oef search.\n\"\"\"\n\nfrom typing import Any\n\nfrom aea.protocols.base import Address, Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\nfrom aea.skills.base import Model\n\nfrom packages.fetchai.protocols.default.dialogues import (\n    DefaultDialogue as BaseDefaultDialogue,\n)\nfrom packages.fetchai.protocols.default.dialogues import (\n    DefaultDialogues as BaseDefaultDialogues,\n)\nfrom packages.fetchai.protocols.http.dialogues import HttpDialogue as BaseHttpDialogue\nfrom packages.fetchai.protocols.http.dialogues import HttpDialogues as BaseHttpDialogues\nfrom packages.fetchai.protocols.oef_search.dialogues import (\n    OefSearchDialogue as BaseOefSearchDialogue,\n)\nfrom packages.fetchai.protocols.oef_search.dialogues import (\n    OefSearchDialogues as BaseOefSearchDialogues,\n)\n\n\nDefaultDialogue = BaseDefaultDialogue\n\n\nclass DefaultDialogues(Model, BaseDefaultDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return DefaultDialogue.Role.AGENT\n\n        BaseDefaultDialogues.__init__(\n            self,\n            self_address=self.context.agent_address,\n            role_from_first_message=role_from_first_message,\n        )\n\n\nHttpDialogue = BaseHttpDialogue\n\n\nclass HttpDialogues(Model, BaseHttpDialogues):\n    \"\"\"This class keeps track of all http dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return BaseHttpDialogue.Role.CLIENT\n\n        BaseHttpDialogues.__init__(\n            self,\n            self_address=str(self.skill_id),\n            role_from_first_message=role_from_first_message,\n        )\n\n\nOefSearchDialogue = BaseOefSearchDialogue\n\n\nclass OefSearchDialogues(Model, BaseOefSearchDialogues):\n    \"\"\"This class keeps track of all oef_search dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return BaseOefSearchDialogue.Role.AGENT\n\n        BaseOefSearchDialogues.__init__(\n            self,\n            self_address=str(self.context.skill_id),\n            role_from_first_message=role_from_first_message,\n        )\n"
  },
  {
    "path": "packages/fetchai/skills/aries_faber/handlers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This package contains the handlers for the faber_alice skill.\"\"\"\nimport json\nimport random\nfrom typing import Any, Dict, List, Optional, cast\n\nfrom aea.common import Address\nfrom aea.configurations.base import PublicId\nfrom aea.protocols.base import Message\nfrom aea.skills.base import Handler\n\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.protocols.http.message import HttpMessage\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.skills.aries_faber.dialogues import (\n    DefaultDialogues,\n    HttpDialogue,\n    HttpDialogues,\n    OefSearchDialogue,\n    OefSearchDialogues,\n)\nfrom packages.fetchai.skills.aries_faber.strategy import (\n    ADMIN_COMMAND_CREATE_INVITATION,\n    ADMIN_COMMAND_CREDDEF,\n    ADMIN_COMMAND_REGISTGER_PUBLIC_DID,\n    ADMIN_COMMAND_SCEHMAS,\n    ADMIN_COMMAND_STATUS,\n    FABER_ACA_IDENTITY,\n    LEDGER_COMMAND_REGISTER_DID,\n    Strategy,\n)\n\n\nDEFAULT_SEARCH_INTERVAL = 5.0\nSUPPORT_REVOCATION = False\n\n\nclass HttpHandler(Handler):\n    \"\"\"This class represents faber's handler for default messages.\"\"\"\n\n    SUPPORTED_PROTOCOL = HttpMessage.protocol_id  # type: Optional[PublicId]\n\n    def __init__(self, **kwargs: Any):\n        \"\"\"Initialize the handler.\"\"\"\n        super().__init__(**kwargs)\n\n        # ACA stuff\n        self.faber_identity = FABER_ACA_IDENTITY\n\n        self.did = None  # type: Optional[str]\n        self._schema_id = None  # type: Optional[str]\n        self.credential_definition_id = None  # type: Optional[str]\n\n        # connections\n        self.connections_sent: Dict[str, Address] = {}\n        self.connections_set: Dict[str, Address] = {}\n        self.counterparts_names: Dict[Address, str] = {}\n\n    @property\n    def schema_id(self) -> str:\n        \"\"\"Get schema id.\"\"\"\n        if self._schema_id is None:\n            raise ValueError(\"schema_id not set\")\n        return self._schema_id\n\n    def _send_invitation_message(self, connection: Dict) -> None:\n        \"\"\"\n        Send a default message to Alice.\n\n        :param connection: the content of the connection message.\n        \"\"\"\n        strategy = cast(Strategy, self.context.strategy)\n        # context\n        connections_unsent = list(\n            set(strategy.aea_addresses) - set(self.connections_sent.values())\n        )\n        if not connections_unsent:\n            self.context.logger.info(\n                \"Every invitation pushed, skip this new connection\"\n            )\n            return\n        target = connections_unsent[0]\n        invitation = connection[\"invitation\"]\n\n        self.connections_sent[connection[\"connection_id\"]] = target\n\n        default_dialogues = cast(DefaultDialogues, self.context.default_dialogues)\n        message, _ = default_dialogues.create(\n            counterparty=target,\n            performative=DefaultMessage.Performative.BYTES,\n            content=json.dumps(invitation).encode(\"utf-8\"),\n        )\n        # send\n        self.context.outbox.put_message(message=message)\n\n        self.context.logger.info(f\"connection: {str(connection)}\")\n        self.context.logger.info(f\"connection id: {connection['connection_id']}\")  # type: ignore\n        self.context.logger.info(f\"invitation: {str(invitation)}\")\n        self.context.logger.info(\n            f\"Sent invitation to {target}. Waiting for the invitation from agent {target} to finalise the connection...\"\n        )\n\n    def _register_public_did_on_acapy(self) -> None:\n        \"\"\"Register DID on the ACA PY.\"\"\"\n        strategy = cast(Strategy, self.context.strategy)\n        self.context.behaviours.faber.send_http_request_message(\n            method=\"POST\",\n            url=strategy.admin_url\n            + ADMIN_COMMAND_REGISTGER_PUBLIC_DID\n            + f\"?did={self.did}\",\n            content=\"\",\n        )\n\n    def _register_did(self) -> None:\n        \"\"\"Register DID on the ledger.\"\"\"\n        strategy = cast(Strategy, self.context.strategy)\n        self.context.logger.info(\n            f\"Registering Faber_ACA with seed {str(strategy.seed)}\"\n        )\n        data = {\n            \"alias\": self.faber_identity,\n            \"seed\": strategy.seed,\n            \"role\": \"TRUST_ANCHOR\",\n        }\n        self.context.behaviours.faber.send_http_request_message(\n            method=\"POST\",\n            url=strategy.ledger_url + LEDGER_COMMAND_REGISTER_DID,\n            content=data,\n        )\n\n    def _register_schema(\n        self, schema_name: str, version: str, schema_attrs: List[str]\n    ) -> None:\n        \"\"\"\n        Register schema definition.\n\n        :param schema_name: the name of the schema\n        :param version: the version of the schema\n        :param schema_attrs: the attributes of the schema\n        \"\"\"\n        strategy = cast(Strategy, self.context.strategy)\n        schema_body = {\n            \"schema_name\": schema_name,\n            \"schema_version\": version,\n            \"attributes\": schema_attrs,\n        }\n        self.context.logger.info(f\"Registering schema {str(schema_body)}\")\n        # The following call isn't responded to. This is most probably because of missing options when running the accompanying ACA.\n        # The accompanying ACA is not properly connected to the von network ledger (missing pointer to genesis file/wallet type)\n        self.context.behaviours.faber.send_http_request_message(\n            method=\"POST\",\n            url=strategy.admin_url + ADMIN_COMMAND_SCEHMAS,\n            content=schema_body,\n        )\n\n    def _register_creddef(self, schema_id: str) -> None:\n        \"\"\"\n        Register credential definition.\n\n        :param schema_id: the id of the schema definition registered on the ledger\n        \"\"\"\n        strategy = cast(Strategy, self.context.strategy)\n        credential_definition_body = {\n            \"schema_id\": schema_id,\n            \"support_revocation\": SUPPORT_REVOCATION,\n        }\n        self.context.behaviours.faber.send_http_request_message(\n            method=\"POST\",\n            url=strategy.admin_url + ADMIN_COMMAND_CREDDEF,\n            content=credential_definition_body,\n        )\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to an envelope.\n\n        :param message: the message\n        \"\"\"\n        message = cast(HttpMessage, message)\n\n        # recover dialogue\n        http_dialogues = cast(HttpDialogues, self.context.http_dialogues)\n        http_dialogue = cast(Optional[HttpDialogue], http_dialogues.update(message))\n        if http_dialogue is None:\n            self.context.logger.error(\n                \"something went wrong when adding the incoming HTTP message to the dialogue.\"\n            )\n            return\n\n        strategy = cast(Strategy, self.context.strategy)\n\n        if (\n            message.performative == HttpMessage.Performative.RESPONSE\n            and message.status_code == 200\n        ):  # response to http request\n            content_bytes = message.body  # type: ignore\n            content = json.loads(content_bytes)\n            self.context.logger.info(f\"Received message: {str(content)}\")\n            if \"version\" in content:  # response to /status\n                self._register_did()\n            elif \"did\" in content:\n                self.did = content[\"did\"]\n                self.context.logger.info(f\"Received DID: {self.did}\")\n                self._register_public_did_on_acapy()\n            elif \"result\" in content and \"posture\" in content[\"result\"]:\n                self.context.logger.info(f\"Registered public DID: {content}\")\n                self._register_schema(\n                    schema_name=\"degree schema\",\n                    version=\"0.0.1\",\n                    schema_attrs=[\"average\", \"date\", \"degree\", \"name\"],\n                )\n            elif \"schema_id\" in content:\n                self._schema_id = content[\"schema_id\"]\n                self._register_creddef(self.schema_id)\n            elif \"credential_definition_id\" in content:\n                self.credential_definition_id = content[\"credential_definition_id\"]\n                for _ in strategy.aea_addresses:\n                    # issue invitation for every agent\n                    self.context.behaviours.faber.send_http_request_message(\n                        method=\"POST\",\n                        url=strategy.admin_url + ADMIN_COMMAND_CREATE_INVITATION,\n                    )\n            elif \"invitation\" in content:\n                connection = content\n                self._send_invitation_message(connection)\n\n            elif \"credential_proposal_dict\" in content:\n                connection_id = content[\"connection_id\"]\n                addr = self.connections_set[connection_id]\n                name = self.counterparts_names[addr]\n                self.context.logger.info(\n                    f\"Credential issued for {name}({addr}): {content['credential_offer_dict']['credential_preview']}\"\n                )\n            else:\n                self.context.logger.warning(\"UNKNOWN HTTP MESSAGE RESPONSE\", message)\n        elif (\n            message.performative == HttpMessage.Performative.REQUEST\n        ):  # webhook request\n            content_bytes = message.body\n            content = json.loads(content_bytes)\n            self.context.logger.info(f\"Received webhook message content:{str(content)}\")\n            if \"connection_id\" in content:\n                connection_id = content[\"connection_id\"]\n                if connection_id not in self.connections_sent:\n                    return\n                if not (\n                    content[\"state\"] == \"active\"\n                    and connection_id not in self.connections_set\n                ):\n                    return\n                addr = self.connections_sent[connection_id]\n                name = content[\"their_label\"]\n                self.counterparts_names[addr] = name\n                self.connections_set[connection_id] = addr\n                self.context.logger.info(f\"Connected to {name}({addr})\")\n                self.issue_crendetials_for(name, addr, connection_id)\n\n    def issue_crendetials_for(\n        self, name: str, address: Address, connection_id: str\n    ) -> None:\n        \"\"\"Issue credentials for the agent.\"\"\"\n        cred = {\n            \"connection_id\": connection_id,\n            \"cred_def_id\": self.credential_definition_id,\n            \"credential_proposal\": {\n                \"@type\": \"did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/issue-credential/1.0/credential-preview\",\n                \"attributes\": [\n                    {\"name\": \"name\", \"value\": name},\n                    {\"name\": \"date\", \"value\": \"2022-01-01\"},\n                    {\n                        \"name\": \"degree\",\n                        \"value\": random.choice(  # nosec\n                            [\"Physics\", \"Chemistry\", \"Mathematics\", \"History\"]\n                        ),\n                    },\n                    {\n                        \"name\": \"average\",\n                        \"value\": str(random.choice([3, 4, 5])),  # nosec\n                    },\n                ],\n            },\n        }\n        strategy = cast(Strategy, self.context.strategy)\n        self.context.behaviours.faber.send_http_request_message(\n            method=\"POST\",\n            url=strategy.admin_url + \"/issue-credential/send\",\n            content=cred,\n        )\n\n        self.context.logger.info(\n            f\"Credentials issue requested for {name}({address}) {cred}\"\n        )\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n\n\nclass OefSearchHandler(Handler):\n    \"\"\"This class implements an OEF search handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = OefSearchMessage.protocol_id  # type: Optional[PublicId]\n\n    def setup(self) -> None:\n        \"\"\"Call to setup the handler.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to a message.\n\n        :param message: the message\n        \"\"\"\n        self.context.logger.info(\"Handling SOEF message...\")\n        oef_search_msg = cast(OefSearchMessage, message)\n\n        # recover dialogue\n        oef_search_dialogues = cast(\n            OefSearchDialogues, self.context.oef_search_dialogues\n        )\n        oef_search_dialogue = cast(\n            Optional[OefSearchDialogue], oef_search_dialogues.update(oef_search_msg)\n        )\n        if oef_search_dialogue is None:\n            self._handle_unidentified_dialogue(oef_search_msg)\n            return\n\n        # handle message\n        if oef_search_msg.performative is OefSearchMessage.Performative.OEF_ERROR:\n            self._handle_error(oef_search_msg, oef_search_dialogue)\n        elif oef_search_msg.performative is OefSearchMessage.Performative.SEARCH_RESULT:\n            self._handle_search(oef_search_msg)\n        else:\n            self._handle_invalid(oef_search_msg, oef_search_dialogue)\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n\n    def _handle_unidentified_dialogue(self, oef_search_msg: OefSearchMessage) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param oef_search_msg: the oef search message to be handled\n        \"\"\"\n        self.context.logger.info(\n            \"received invalid oef_search message={}, unidentified dialogue.\".format(\n                oef_search_msg\n            )\n        )\n\n    def _handle_error(\n        self, oef_search_msg: OefSearchMessage, oef_search_dialogue: OefSearchDialogue\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param oef_search_msg: the oef search message to be handled\n        :param oef_search_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.info(\n            \"received oef_search error message={} in dialogue={}.\".format(\n                oef_search_msg, oef_search_dialogue\n            )\n        )\n\n    def _handle_search(self, oef_search_msg: OefSearchMessage) -> None:\n        \"\"\"\n        Handle the search response.\n\n        :param oef_search_msg: the oef search message to be handled\n        \"\"\"\n\n        if len(oef_search_msg.agents) <= 1:\n            self.context.logger.info(\"Waiting for more agents.\")\n            return\n\n        self.context.logger.info(\n            f\"found agents {', '.join(oef_search_msg.agents)}, stopping search.\"\n        )\n\n        strategy = cast(Strategy, self.context.strategy)\n        strategy.is_searching = False  # stopping search\n\n        # set alice address\n        strategy.aea_addresses = list(oef_search_msg.agents)\n\n        # check ACA is running\n        self.context.behaviours.faber.send_http_request_message(\n            \"GET\", strategy.admin_url + ADMIN_COMMAND_STATUS\n        )\n\n    def _handle_invalid(\n        self, oef_search_msg: OefSearchMessage, oef_search_dialogue: OefSearchDialogue\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param oef_search_msg: the oef search message\n        :param oef_search_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.warning(\n            \"cannot handle oef_search message of performative={} in dialogue={}.\".format(\n                oef_search_msg.performative,\n                oef_search_dialogue,\n            )\n        )\n"
  },
  {
    "path": "packages/fetchai/skills/aries_faber/skill.yaml",
    "content": "name: aries_faber\nauthor: fetchai\nversion: 0.24.5\ntype: skill\ndescription: The aries_faber skill implements the faber player in the aries cloud\n  agent demo\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: QmYKuXNqtkUvz4esnYnmg2iUvN3cNKTUzF92NmwPbD66L3\n  __init__.py: QmYToaj574eCcrzJ71BKJW4AZFGZ7SyT3Z7RLw3q2AVSiJ\n  behaviours.py: QmZRkMM7UMa7x6jdUkHyDtGq1kBXVTHDwszcDna3HNQsdE\n  dialogues.py: QmRXXA2vT1r65yb8iKAdhCbys7s2wy2M9Cjpf6jfEX6KZB\n  handlers.py: QmfLxGW9MZkA4rkRFrZRLDSyWktrHa42mFRLZ1YPRcWMEi\n  strategy.py: QmXeDdFngwnNb3F3TYusLX4j2DCCDdbkXTRcHHCa6xV6Wr\nfingerprint_ignore_patterns: []\nconnections:\n- fetchai/http_client:0.24.6\ncontracts: []\nprotocols:\n- fetchai/default:1.1.7\n- fetchai/http:1.1.7\n- fetchai/oef_search:1.1.7\nskills: []\nbehaviours:\n  faber:\n    args:\n      search_interval: 5\n    class_name: FaberBehaviour\nhandlers:\n  http:\n    args: {}\n    class_name: HttpHandler\n  oef_search:\n    args: {}\n    class_name: OefSearchHandler\nmodels:\n  default_dialogues:\n    args: {}\n    class_name: DefaultDialogues\n  http_dialogues:\n    args: {}\n    class_name: HttpDialogues\n  oef_search_dialogues:\n    args: {}\n    class_name: OefSearchDialogues\n  strategy:\n    args:\n      admin_host: 127.0.0.1\n      admin_port: 8021\n      ledger_url: http://127.0.0.1:9000\n      location:\n        latitude: 51.5194\n        longitude: 0.127\n      search_query:\n        constraint_type: ==\n        search_key: intro_service\n        search_value: intro_alice\n      search_radius: 5.0\n      seed: null\n    class_name: Strategy\ndependencies: {}\nis_abstract: false\n"
  },
  {
    "path": "packages/fetchai/skills/aries_faber/strategy.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the strategy class.\"\"\"\nimport random\nfrom typing import Any, List\n\nfrom aea.common import Address\nfrom aea.exceptions import enforce\nfrom aea.helpers.search.models import Constraint, ConstraintType, Location, Query\nfrom aea.skills.base import Model\n\n\n# Default Config\nDEFAULT_ADMIN_HOST = \"127.0.0.1\"\nDEFAULT_ADMIN_PORT = 8021\nDEFAULT_LEDGER_URL = \"http://127.0.0.1:9000\"\n\n# Commands\nADMIN_COMMAND_CREATE_INVITATION = \"/connections/create-invitation\"\nADMIN_COMMAND_STATUS = \"/status\"\nADMIN_COMMAND_SCEHMAS = \"/schemas\"\nADMIN_COMMAND_CREDDEF = \"/credential-definitions\"\nADMIN_COMMAND_REGISTGER_PUBLIC_DID = \"/wallet/did/public\"\nLEDGER_COMMAND_REGISTER_DID = \"/register\"\n\n# Convenience\nFABER_ACA_IDENTITY = \"Faber_ACA\"\n\n# Search\nDEFAULT_LOCATION = {\"longitude\": 0.1270, \"latitude\": 51.5194}\nDEFAULT_SEARCH_QUERY = {\n    \"search_key\": \"intro_service\",\n    \"search_value\": \"intro_alice\",\n    \"constraint_type\": \"==\",\n}\nDEFAULT_SEARCH_RADIUS = 5.0\n\n\nclass Strategy(Model):\n    \"\"\"This class defines a strategy for the agent.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize the strategy of the agent.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        # config\n        self._admin_host = kwargs.pop(\"admin_host\", DEFAULT_ADMIN_HOST)\n        self._admin_port = kwargs.pop(\"admin_port\", DEFAULT_ADMIN_PORT)\n        self._ledger_url = kwargs.pop(\"ledger_url\", DEFAULT_LEDGER_URL)\n\n        self._seed = (\n            kwargs.pop(\n                \"seed\",\n                None,\n            )\n            or (\n                \"my_seed_000000000000000000000000\"\n                + str(random.randint(100_000, 999_999))  # nosec\n            )[-32:]\n        )\n\n        # derived config\n        self._admin_url = f\"http://{self.admin_host}:{self.admin_port}\"\n        self._aea_addresses: List[Address] = []\n\n        # Search\n        self._search_query = kwargs.pop(\"search_query\", DEFAULT_SEARCH_QUERY)\n        location = kwargs.pop(\"location\", DEFAULT_LOCATION)\n        self._agent_location = Location(\n            latitude=location[\"latitude\"], longitude=location[\"longitude\"]\n        )\n        self._radius = kwargs.pop(\"search_radius\", DEFAULT_SEARCH_RADIUS)\n\n        super().__init__(**kwargs)\n        self._is_searching = False\n\n    @property\n    def admin_host(self) -> str:\n        \"\"\"Get the admin host.\"\"\"\n        return self._admin_host\n\n    @property\n    def admin_port(self) -> str:\n        \"\"\"Get the admin port.\"\"\"\n        return self._admin_port\n\n    @property\n    def ledger_url(self) -> str:\n        \"\"\"Get the ledger URL.\"\"\"\n        return self._ledger_url\n\n    @property\n    def seed(self) -> str:\n        \"\"\"Get the wallet seed.\"\"\"\n        return self._seed\n\n    @property\n    def admin_url(self) -> str:\n        \"\"\"Get the admin URL.\"\"\"\n        return self._admin_url\n\n    @property\n    def aea_addresses(self) -> List[Address]:\n        \"\"\"Get Alice's address.\"\"\"\n        return self._aea_addresses\n\n    @aea_addresses.setter\n    def aea_addresses(self, addresses: List[Address]) -> None:\n        self._aea_addresses = addresses\n\n    @property\n    def is_searching(self) -> bool:\n        \"\"\"Check if the agent is searching.\"\"\"\n        return self._is_searching\n\n    @is_searching.setter\n    def is_searching(self, is_searching: bool) -> None:\n        \"\"\"Check if the agent is searching.\"\"\"\n        enforce(isinstance(is_searching, bool), \"Can only set bool on is_searching!\")\n        self._is_searching = is_searching\n\n    def get_location_and_service_query(self) -> Query:\n        \"\"\"\n        Get the location and service query of the agent.\n\n        :return: the query\n        \"\"\"\n        close_to_my_service = Constraint(\n            \"location\", ConstraintType(\"distance\", (self._agent_location, self._radius))\n        )\n        service_key_filter = Constraint(\n            self._search_query[\"search_key\"],\n            ConstraintType(\n                self._search_query[\"constraint_type\"],\n                self._search_query[\"search_value\"],\n            ),\n        )\n        query = Query(\n            [close_to_my_service, service_key_filter],\n        )\n        return query\n"
  },
  {
    "path": "packages/fetchai/skills/carpark_client/README.md",
    "content": "# Car Park Client\n\n## Description\n\nThis skill purchases information on available car parking spaces in a vicinity.\n\nThis skill finds an agent on the sOEF which sells car park availability data in a vicinity, requests this data, negotiates the price, pays the proposed amount if agreement is reach, and receives the data bought.\n\n## Behaviours\n\n- `search`: searches for car park data selling service on the sOEF\n- `transaction`: sequentially processes transactions' settlements on a blockchain\n\n## Handlers\n\n- `fipa`: handles `fipa` messages for negotiation\n- `ledger_api`: handles `ledger_api` messages for interacting with a ledger\n- `oef_search`: handles `oef_search` messages to manage the sellers found\n- `signing`: handles `signing` messages for transaction signing by the decision maker\n\n## Links\n\n- <a href=\"https://docs.fetch.ai/aea/car-park-skills/\" target=\"_blank\">Car Park Demo</a>\n"
  },
  {
    "path": "packages/fetchai/skills/carpark_client/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the implementation of the carpark client skill.\"\"\"\n\nfrom aea.configurations.base import PublicId\n\n\nPUBLIC_ID = PublicId.from_str(\"fetchai/carpark_client:0.27.6\")\n"
  },
  {
    "path": "packages/fetchai/skills/carpark_client/behaviours.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains the behaviours of the agent.\"\"\"\n\nfrom packages.fetchai.skills.generic_buyer.behaviours import (\n    GenericSearchBehaviour,\n    GenericTransactionBehaviour,\n)\n\n\nSearchBehaviour = GenericSearchBehaviour\nTransactionBehaviour = GenericTransactionBehaviour\n"
  },
  {
    "path": "packages/fetchai/skills/carpark_client/dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nThis module contains the classes required for dialogue management.\n\n- DefaultDialogues: The dialogues class keeps track of all dialogues of type default.\n- FipaDialogues: The dialogues class keeps track of all dialogues of type fipa.\n- LedgerApiDialogues: The dialogues class keeps track of all dialogues of type ledger_api.\n- OefSearchDialogues: The dialogues class keeps track of all dialogues of type oef_search.\n- SigningDialogues: The dialogues class keeps track of all dialogues of type signing.\n\"\"\"\n\nfrom packages.fetchai.skills.generic_buyer.dialogues import (\n    DefaultDialogues as GenericDefaultDialogues,\n)\nfrom packages.fetchai.skills.generic_buyer.dialogues import (\n    FipaDialogues as GenericFipaDialogues,\n)\nfrom packages.fetchai.skills.generic_buyer.dialogues import (\n    LedgerApiDialogues as GenericLedgerApiDialogues,\n)\nfrom packages.fetchai.skills.generic_buyer.dialogues import (\n    OefSearchDialogues as GenericOefSearchDialogues,\n)\nfrom packages.fetchai.skills.generic_buyer.dialogues import (\n    SigningDialogues as GenericSigningDialogues,\n)\n\n\nDefaultDialogues = GenericDefaultDialogues\nFipaDialogues = GenericFipaDialogues\nLedgerApiDialogues = GenericLedgerApiDialogues\nOefSearchDialogues = GenericOefSearchDialogues\nSigningDialogues = GenericSigningDialogues\n"
  },
  {
    "path": "packages/fetchai/skills/carpark_client/handlers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains the handlers of the agent.\"\"\"\n\nfrom packages.fetchai.skills.generic_buyer.handlers import (\n    GenericFipaHandler,\n    GenericLedgerApiHandler,\n    GenericOefSearchHandler,\n    GenericSigningHandler,\n)\n\n\nFipaHandler = GenericFipaHandler\nLedgerApiHandler = GenericLedgerApiHandler\nOefSearchHandler = GenericOefSearchHandler\nSigningHandler = GenericSigningHandler\n"
  },
  {
    "path": "packages/fetchai/skills/carpark_client/skill.yaml",
    "content": "name: carpark_client\nauthor: fetchai\nversion: 0.27.6\ntype: skill\ndescription: The carpark client skill implements the functionality to run a client\n  for carpark data.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: QmdrvGfoAncV3e76Aiq5irJSKYXXwmhJTv7w8hPoadcFgt\n  __init__.py: QmVsQFQFm8gBa2cKGmERfJYkq1aufHahgv2p1dF5eRwXhb\n  behaviours.py: QmSr6fB3N7dhVo1cLY1TGd2q8usjGwNmTCNjBBbtgtVf9j\n  dialogues.py: QmXgXcs25v9ob9a9XwT49wvK788vbUdZyYxUgG3ndHjrix\n  handlers.py: QmP3Q6x3NMcWgRi6H5GtDtvnLWSoB1HeG8vTd4zcRZUgNj\n  strategy.py: QmdHPLehqRr1dxuCbp4ENYmVMb8Ykvzg2Uzfos5kFJSr3D\nfingerprint_ignore_patterns: []\nconnections: []\ncontracts: []\nprotocols:\n- fetchai/default:1.1.7\n- fetchai/fipa:1.1.7\n- fetchai/ledger_api:1.1.7\n- fetchai/oef_search:1.1.7\n- fetchai/signing:1.1.7\nskills:\n- fetchai/generic_buyer:0.27.6\nbehaviours:\n  search:\n    args:\n      search_interval: 5\n    class_name: SearchBehaviour\n  transaction:\n    args:\n      max_processing: 420\n      transaction_interval: 2\n    class_name: TransactionBehaviour\nhandlers:\n  fipa:\n    args: {}\n    class_name: FipaHandler\n  ledger_api:\n    args: {}\n    class_name: LedgerApiHandler\n  oef_search:\n    args: {}\n    class_name: OefSearchHandler\n  signing:\n    args: {}\n    class_name: SigningHandler\nmodels:\n  default_dialogues:\n    args: {}\n    class_name: DefaultDialogues\n  fipa_dialogues:\n    args: {}\n    class_name: FipaDialogues\n  ledger_api_dialogues:\n    args: {}\n    class_name: LedgerApiDialogues\n  oef_search_dialogues:\n    args: {}\n    class_name: OefSearchDialogues\n  signing_dialogues:\n    args: {}\n    class_name: SigningDialogues\n  strategy:\n    args:\n      is_ledger_tx: true\n      location:\n        latitude: 51.5194\n        longitude: 0.127\n      max_negotiations: 1\n      max_quantity: 100\n      max_tx_fee: 3550000000000000\n      max_unit_price: 20\n      min_quantity: 1\n      search_query:\n        constraint_type: ==\n        search_key: seller_service\n        search_value: car_park_service\n      search_radius: 5.0\n      service_id: car_park_service\n    class_name: Strategy\ndependencies: {}\nis_abstract: false\n"
  },
  {
    "path": "packages/fetchai/skills/carpark_client/strategy.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the strategy class.\"\"\"\n\nfrom packages.fetchai.skills.generic_buyer.strategy import GenericStrategy\n\n\nStrategy = GenericStrategy\n"
  },
  {
    "path": "packages/fetchai/skills/carpark_detection/README.md",
    "content": "# Car Park Detection\n\n## Description\n\nThis skill sells information on the number of car parking spaces available in a given vicinity.\n\nThis skill is part of the Fetch.ai car park demo. It registers the \"car park availability selling service\" on the sOEF. It can be requested (for example by an agent with the `carpark_client` skill) to provide its data. It then negotiates the price and delivers the data after it receives payment.\n\n## Behaviours\n\n- `service_registration`: registers car park info selling service on the sOEF\n\n## Handlers\n\n- `fipa`: handles `fipa` messages for negotiation\n- `ledger_api`: handles `ledger_api` messages for interacting with a ledger\n- `oef_search`: handles `oef_search` messages if service registration on the sOEF is unsuccessful\n\n## Links\n\n- <a href=\"https://docs.fetch.ai/aea/car-park-skills/\" target=\"_blank\">Car Park Demo</a>\n"
  },
  {
    "path": "packages/fetchai/skills/carpark_detection/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the implementation of the car park detection skill.\"\"\"\n\nfrom aea.configurations.base import PublicId\n\n\nPUBLIC_ID = PublicId.from_str(\"fetchai/carpark_detection:0.27.6\")\n"
  },
  {
    "path": "packages/fetchai/skills/carpark_detection/behaviours.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains a scaffold of a behaviour.\"\"\"\n\nfrom packages.fetchai.skills.generic_seller.behaviours import (\n    GenericServiceRegistrationBehaviour,\n)\n\n\nServiceRegistrationBehaviour = GenericServiceRegistrationBehaviour\n"
  },
  {
    "path": "packages/fetchai/skills/carpark_detection/database.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Communicate between the database and the python objects.\"\"\"\n\nimport logging\nimport os\nimport shutil\nimport sqlite3\nimport time\nfrom typing import Dict, List, Optional, Tuple, Union\n\nimport skimage  # type: ignore\n\n\n_default_logger = logging.getLogger(\n    \"aea.packages.fetchai.skills.carpark_detection.detection_database\"\n)\n\n\nclass DetectionDatabase:  # pylint: disable=too-many-public-methods\n    \"\"\"Communicate between the database and the python objects.\"\"\"\n\n    def __init__(\n        self,\n        temp_dir: str,\n        create_if_not_present: bool = True,\n        logger: Optional[logging.Logger] = None,\n    ) -> None:\n        \"\"\"Initialise the Detection Database Communication class.\"\"\"\n        self.this_dir = os.path.dirname(__file__)\n        self.temp_dir = temp_dir\n\n        self.mask_image_path = self.temp_dir + \"/mask.tiff\"\n        self.mask_ref_image_path = self.temp_dir + \"/mask_ref.tiff\"\n        self.raw_image_dir = self.temp_dir + \"/db_raw_images/\"\n        self.processed_image_dir = self.temp_dir + \"/db_processed_images/\"\n        # Note that this path should be under source control\n        self.default_mask_ref_path = self.this_dir + \"/default_mask_ref.png\"\n        self.num_digits_time = (\n            12  # need to match this up with the generate functions below\n        )\n        self.image_file_ext = \".png\"\n        self.database_path = self.temp_dir + \"/\" + \"detection_results.db\"\n\n        if create_if_not_present:\n            self.initialise_backend()\n\n        self.logger = logger if logger is not None else _default_logger\n\n    def is_db_exits(self) -> bool:\n        \"\"\"Return true if database exists and is set up.\"\"\"\n        if not os.path.isfile(self.database_path):\n            return False\n\n        ret = self.get_system_status(\"db\", False) == \"Exists\"\n        return ret\n\n    def reset_database(self) -> None:  # pragma: nocover\n        \"\"\"Reset the database and remove all data.\"\"\"\n        # If we need to reset the database, then remove the table and any stored images\n        self.logger.info(\"Database being reset.\")\n\n        # Remove the actual database file\n        if os.path.isfile(self.database_path):\n            os.remove(self.database_path)\n\n        # Clear stored images\n        shutil.rmtree(self.raw_image_dir)\n        shutil.rmtree(self.processed_image_dir)\n\n        # Recreate them\n        self.logger.info(\"Initialising backend ...\")\n        self.initialise_backend()\n        self.logger.info(\"Finished initialising backend!\")\n\n    def reset_mask(self) -> None:  # pragma: nocover\n        \"\"\"Just reset the detection mask.\"\"\"\n        # If we need to reset the database, then remove the table and any stored images\n        self.logger.info(\"Mask being reset.\")\n\n        # Remove the actual database file\n        if os.path.isfile(self.mask_image_path):\n            os.remove(self.mask_image_path)\n        if os.path.isfile(self.mask_ref_image_path):\n            os.remove(self.mask_ref_image_path)\n        self.ensure_dirs_exist()\n\n    def initialise_backend(self) -> None:\n        \"\"\"Set up database and initialise the tables.\"\"\"\n        self.ensure_dirs_exist()\n        self.execute_single_sql(\n            \"CREATE TABLE IF NOT EXISTS images (epoch INTEGER, raw_image_path TEXT, \"\n            \"processed_image_path TEXT, total_count INTEGER, \"\n            \"moving_count INTEGER, free_spaces INTEGER, lat TEXT, lon TEXT)\"\n        )\n\n        self.execute_single_sql(\n            \"CREATE TABLE IF NOT EXISTS fet_table (id INTEGER PRIMARY KEY, amount BIGINT, last_updated TEXT)\"\n        )\n\n        self.execute_single_sql(\n            \"CREATE TABLE IF NOT EXISTS status_table (system_name TEXT PRIMARY KEY, status TEXT)\"\n        )\n\n        self.execute_single_sql(\n            \"CREATE TABLE IF NOT EXISTS name_lookup2 (oef_key TEXT PRIMARY KEY, friendly_name TEXT, epoch INT, is_self BIT)\"\n        )\n\n        self.execute_single_sql(\n            \"CREATE TABLE IF NOT EXISTS transaction_history (tx TEXT PRIMARY KEY, epoch INT, oef_key_payer TEXT, oef_key_payee TEXT, amount BIGINT, status TEXT)\"\n        )\n\n        self.execute_single_sql(\n            \"CREATE TABLE IF NOT EXISTS dialogue_statuses (dialogue_id TEXT, epoch DECIMAL, other_agent_key TEXT, received_msg TEXT, sent_msg TEXT)\"\n        )\n\n        if not self.is_db_exits():\n            self.set_system_status(\"lat\", \"UNKNOWN\")\n            self.set_system_status(\"lon\", \"UNKNOWN\")\n        self.set_system_status(\"db\", \"Exists\")\n\n    def set_fet(self, amount: int, t: str) -> None:  # pragma: nocover\n        \"\"\"Record how much FET we have and when we last read it from the ledger.\"\"\"\n        command = (\n            \"INSERT OR REPLACE INTO fet_table(id, amount, last_updated) values(0, ?, ?)\"\n        )\n        variables = (str(amount), str(t))\n        self.execute_single_sql(command, variables)\n\n    def get_fet(self) -> int:  # pragma: nocover\n        \"\"\"Read how much FET we have.\"\"\"\n        result = self.execute_single_sql(\"SELECT amount FROM fet_table WHERE id=0\")\n        if len(result) != 0:\n            return result[0][0]\n        return -99\n\n    def save_max_capacity(self, max_capacity: int) -> None:  # pragma: nocover\n        \"\"\"Record the maximum number of spaces we can report on.\"\"\"\n        self.set_system_status(\"max_capacity\", str(max_capacity))\n\n    def get_max_capacity(self) -> Optional[int]:  # pragma: nocover\n        \"\"\"Read the maximum number of spaces we can report on.\"\"\"\n        max_capacity = self.get_system_status(\"max_capacity\")\n\n        if max_capacity == \"UNKNOWN\":\n            return None\n        return int(max_capacity)\n\n    def save_lat_lon(self, lat: float, lon: float) -> None:  # pragma: nocover\n        \"\"\"Record the longitude and latitude of our device.\"\"\"\n        self.set_system_status(\"lat\", str(lat))\n        self.set_system_status(\"lon\", str(lon))\n\n    def get_lat_lon(self) -> Tuple[Optional[float], Optional[float]]:\n        \"\"\"Read the longitude and latitude of our device.\"\"\"\n        lat = self.get_system_status(\"lat\")\n        lon = self.get_system_status(\"lon\")\n        if lat == \"UNKNOWN\" or lon == \"UNKNOWN\":\n            return None, None\n        return float(lat), float(lon)\n\n    def set_system_status(self, system_name: str, status: str) -> None:\n        \"\"\"Record the status of one of the systems.\"\"\"\n        command = (\n            \"INSERT OR REPLACE INTO status_table(system_name, status) values(?, ?)\"\n        )\n        variables = (str(system_name), str(status))\n        self.execute_single_sql(command, variables)\n\n    def get_system_status(self, system_name: str, print_exceptions: bool = True) -> str:\n        \"\"\"Read the status of one of the systems.\"\"\"\n        command = \"SELECT status FROM status_table WHERE system_name=?\"\n        variables = (str(system_name),)\n        result = self.execute_single_sql(command, variables, print_exceptions)\n        if len(result) != 0:\n            return result[0][0]\n        return \"UNKNOWN\"\n\n    def set_dialogue_status(\n        self, dialogue_id: int, other_agent_key: str, received_msg: str, sent_msg: str\n    ) -> None:  # pragma: nocover\n        \"\"\"Record the status of a dialog we are having.\"\"\"\n        t = time.time()\n        command = \"INSERT INTO dialogue_statuses(dialogue_id, epoch, other_agent_key, received_msg, sent_msg) VALUES(?,?,?,?,?)\"\n        variables = (\n            str(dialogue_id),\n            str(t),\n            str(other_agent_key),\n            str(received_msg),\n            str(sent_msg),\n        )\n        self.execute_single_sql(command, variables)\n\n    def get_dialogue_statuses(self) -> List[Dict]:  # pragma: nocover\n        \"\"\"Read the statuses of all the dialog we are having.\"\"\"\n        data = self.execute_single_sql(\n            \"SELECT * FROM dialogue_statuses ORDER BY epoch DESC LIMIT 100\"\n        )\n        results = []\n        for datum in data:\n            result = {}\n            result[\"dialog_id\"] = datum[0]\n            result[\"epoch\"] = datum[1]\n            result[\"other_agent_key\"] = datum[2]\n            result[\"received_msg\"] = datum[3]\n            result[\"sent_msg\"] = datum[4]\n            results.append(result)\n\n        return results\n\n    def calc_uncleared_fet(self) -> int:  # pragma: nocover\n        \"\"\"Calc our uncleared fet.\"\"\"\n        cleared_fet_result = self.execute_single_sql(\n            \"SELECT amount FROM fet_table WHERE id=0\"\n        )\n        if len(cleared_fet_result) != 0:\n            uncleared_fet_result = self.execute_single_sql(\n                \"SELECT SUM(amount) FROM transaction_history WHERE status = 'in_progress'\"\n            )\n            if len(uncleared_fet_result) == 0 or uncleared_fet_result[0][0] is None:\n                return cleared_fet_result[0][0]\n            return cleared_fet_result[0][0] + uncleared_fet_result[0][0]\n        return -99\n\n    def add_friendly_name(\n        self, oef_key: str, friendly_name: str, is_self: bool = False\n    ) -> None:  # pragma: nocover\n        \"\"\"Record the friendly name of one the agents we are dealing with (including ourselves).\"\"\"\n        t = int(time.time())\n        command = \"INSERT OR REPLACE INTO name_lookup2(oef_key, friendly_name, epoch, is_self) VALUES(?, ?, ?, ?)\"\n        variables = (str(oef_key), str(friendly_name), t, 1 if is_self else 0)\n        self.execute_single_sql(command, variables)\n\n    def add_in_progress_transaction(\n        self, tx: str, oef_key_payer: str, oef_key_payee: str, amount: int\n    ) -> None:  # pragma: nocover\n        \"\"\"Record that a transaction in underway.\"\"\"\n        t = int(time.time())\n        command = \"INSERT OR REPLACE INTO transaction_history(tx, epoch, oef_key_payer, oef_key_payee, amount, status) VALUES(?, ?, ?, ?, ?, 'in_progress')\"\n        variables = (str(tx), t, str(oef_key_payer), str(oef_key_payee), amount)\n        self.execute_single_sql(command, variables)\n\n    def get_in_progress_transactions(self) -> List[Dict]:  # pragma: nocover\n        \"\"\"Read all in-progress transactions.\"\"\"\n        return self.get_transactions_with_status(\"in_progress\")\n\n    def get_complete_transactions(self) -> List[Dict]:  # pragma: nocover\n        \"\"\"Read all complete transactions.\"\"\"\n        return self.get_transactions_with_status(\"complete\")\n\n    def get_transactions_with_status(\n        self, status: str\n    ) -> List[Dict]:  # pragma: nocover\n        \"\"\"Read all transactions with a given status.\"\"\"\n        command = (\n            \"SELECT * from transaction_history WHERE status = ? ORDER BY epoch DESC\"\n        )\n        variables = (str(status),)\n        data = self.execute_single_sql(command, variables)\n        results = []\n        for datum in data:\n            result = {}\n            result[\"tx_hash\"] = datum[0]\n            result[\"epoch\"] = datum[1]\n            result[\"oef_key_payer\"] = datum[2]\n            result[\"oef_key_payee\"] = datum[3]\n            result[\"amount\"] = datum[4]\n            result[\"status\"] = datum[5]\n            results.append(result)\n\n        return results\n\n    def get_n_transactions(self, count: int) -> List[Dict]:  # pragma: nocover\n        \"\"\"Get the most resent N transactions.\"\"\"\n        command = \"SELECT * from transaction_history ORDER BY epoch DESC LIMIT ?\"\n        variables = (count,)\n        data = self.execute_single_sql(command, variables)\n        results = []\n        for datum in data:\n            result = {}\n            result[\"tx_hash\"] = datum[0]\n            result[\"epoch\"] = datum[1]\n            result[\"oef_key_payer\"] = datum[2]\n            result[\"oef_key_payee\"] = datum[3]\n            result[\"amount\"] = datum[4]\n            result[\"status\"] = datum[5]\n            results.append(result)\n\n        return results\n\n    def set_transaction_complete(self, tx: str) -> None:  # pragma: nocover\n        \"\"\"Set a specific transaction as complete.\"\"\"\n        command = \"UPDATE transaction_history SET status ='complete' WHERE tx = ?\"\n        variables = (str(tx),)\n        self.execute_single_sql(command, variables)\n\n    def lookup_friendly_name(self, oef_key: str) -> Optional[str]:  # pragma: nocover\n        \"\"\"Look up friendly name given the OEF key.\"\"\"\n        command = \"SELECT * FROM name_lookup2 WHERE oef_key = ? ORDER BY epoch DESC\"\n        variables = (str(oef_key),)\n        results = self.execute_single_sql(command, variables)\n        if len(results) == 0:\n            return None\n        return results[0][1]\n\n    def lookup_self_names(\n        self,\n    ) -> Tuple[Optional[str], Optional[str]]:  # pragma: nocover\n        \"\"\"Return out own name and key.\"\"\"\n        results = self.execute_single_sql(\n            \"SELECT oef_key, friendly_name FROM name_lookup2 WHERE is_self = 1 ORDER BY epoch DESC\"\n        )\n        if len(results) == 0:\n            return None, None\n        return results[0][0], results[0][1]\n\n    def add_entry_no_save(\n        self,\n        raw_path: str,\n        processed_path: str,\n        total_count: int,\n        moving_count: int,\n        free_spaces: int,\n        lat: float,\n        lon: float,\n    ) -> None:  # pragma: nocover\n        \"\"\"Add an entry into the detection database but do not save anything to disk.\"\"\"\n        # need to extract the time!\n        t = self.extract_time_from_raw_path(raw_path)\n        command = \"INSERT INTO images VALUES (?, ?, ?, ?, ?, ?, ?, ?)\"\n        variables = (\n            t,\n            raw_path,\n            processed_path,\n            total_count,\n            moving_count,\n            free_spaces,\n            lat,\n            lon,\n        )\n        self.execute_single_sql(command, variables)\n\n    def add_entry(\n        self,\n        raw_image: str,\n        processed_image: str,\n        total_count: int,\n        moving_count: int,\n        free_spaces: int,\n        lat: float,\n        lon: float,\n    ) -> None:  # pragma: nocover\n        \"\"\"Add an entry into the detection database and record images to disk.\"\"\"\n        t = int(time.time())\n        raw_path = self.generate_raw_image_path(t)\n        processed_path = self.generate_processed_path(t)\n\n        skimage.io.imsave(raw_path, raw_image)\n        skimage.io.imsave(processed_path, processed_image)\n        command = \"INSERT INTO images VALUES (?, ?, ?, ?, ?, ?, ?, ?)\"\n        variables = (\n            t,\n            raw_path,\n            processed_path,\n            total_count,\n            moving_count,\n            free_spaces,\n            lat,\n            lon,\n        )\n        self.execute_single_sql(command, variables)\n\n    def execute_single_sql(\n        self,\n        command: str,\n        variables: Tuple[Union[str, int, float], ...] = (),\n        print_exceptions: bool = True,\n    ) -> List:\n        \"\"\"Query the database - all the other functions use this under the hood.\"\"\"\n        conn = None\n        ret = []\n        try:\n            conn = sqlite3.connect(self.database_path, timeout=300)  # 5 mins\n            c = conn.cursor()\n            c.execute(command, variables)\n            ret = c.fetchall()\n            conn.commit()\n        except Exception as e:  # pragma: nocover # pylint: disable=broad-except\n            if print_exceptions:\n                self.logger.warning(\"Exception in database: {}\".format(e))\n        finally:\n            if conn is not None:\n                conn.close()\n\n        return ret\n\n    def get_latest_detection_data(self, max_num_rows: int) -> List[Dict]:\n        \"\"\"Return the most recent detection data.\"\"\"\n        command = \"\"\"SELECT * FROM images ORDER BY epoch DESC LIMIT ?\"\"\"\n        variables = (max_num_rows,)\n        results = self.execute_single_sql(command, variables)\n\n        if results is None:\n            return None\n        ret_data = []\n        for r in results:\n            this_data = {}\n            this_data[\"epoch\"] = r[0]\n            this_data[\"raw_image_path\"] = r[1]\n            this_data[\"processed_image_path\"] = r[2]\n            this_data[\"total_count\"] = r[3]\n            this_data[\"moving_count\"] = r[4]\n            this_data[\"free_spaces\"] = r[5]\n            this_data[\"lat\"] = r[6]\n            this_data[\"lon\"] = r[7]\n            ret_data.append(this_data)\n\n        return ret_data\n\n    def prune_image_table(self, max_entries: int) -> None:  # pragma: nocover\n        \"\"\"Remove image data if table longer than max_entries.\"\"\"\n        self.prune_table(\"images\", max_entries)\n\n    def prune_transaction_table(self, max_entries: int) -> None:  # pragma: nocover\n        \"\"\"Remove transaction data if table longer than max_entries.\"\"\"\n        self.prune_table(\"transaction_history\", max_entries)\n\n    def prune_table(self, table_name: str, max_entries: int) -> None:  # pragma: nocover\n        \"\"\"Remove any data if table longer than max_entries.\"\"\"\n        command = \"SELECT epoch FROM ? ORDER BY epoch DESC LIMIT 1 OFFSET ?\"\n        variables = (\n            table_name,\n            max_entries - 1,\n        )\n        results = self.execute_single_sql(command=command, variables=variables)\n\n        if len(results) != 0:\n            last_epoch = results[0][0]\n            command = \"\"\"DELETE FROM ? WHERE epoch<?\"\"\"\n            variables = (\n                table_name,\n                last_epoch,\n            )\n            self.execute_single_sql(command, variables)\n\n    def ensure_dirs_exist(self) -> None:\n        \"\"\"Test if we have our temp directories, and if we don't create them.\"\"\"\n        if not os.path.isdir(self.temp_dir):\n            os.mkdir(self.temp_dir)\n        if not os.path.isdir(self.raw_image_dir):\n            os.mkdir(self.raw_image_dir)\n        if not os.path.isdir(self.processed_image_dir):\n            os.mkdir(self.processed_image_dir)\n\n    def generate_raw_image_path(self, t: int) -> str:  # pragma: nocover\n        \"\"\"Return path where we store raw images.\"\"\"\n        return (\n            self.raw_image_dir\n            + \"{0:012d}\".format(t)\n            + \"_raw_image\"\n            + self.image_file_ext\n        )\n\n    def generate_processed_path(self, t: int) -> str:  # pragma: nocover\n        \"\"\"Return path where we store processed images.\"\"\"\n        return (\n            self.processed_image_dir\n            + \"{0:012d}\".format(t)\n            + \"_processed_image\"\n            + self.image_file_ext\n        )\n\n    def generate_processed_from_raw_path(self, raw_name: str) -> str:  # pragma: nocover\n        \"\"\"Given the raw path, return the processes path.\"\"\"\n        return raw_name.replace(\"_raw_image.\", \"_processed_image.\").replace(\n            self.raw_image_dir, self.processed_image_dir\n        )\n\n    def extract_time_from_raw_path(self, raw_name: str) -> int:  # pragma: nocover\n        \"\"\"Given the raw path name, return the time the detection happened.\"\"\"\n        start_index = len(self.raw_image_dir)\n        extracted_num = raw_name[start_index : start_index + self.num_digits_time]\n        return int(extracted_num)\n"
  },
  {
    "path": "packages/fetchai/skills/carpark_detection/dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nThis module contains the classes required for dialogue management.\n\n- DefaultDialogues: The dialogues class keeps track of all dialogues of type default.\n- FipaDialogues: The dialogues class keeps track of all dialogues of type fipa.\n- LedgerApiDialogues: The dialogues class keeps track of all dialogues of type ledger_api.\n- OefSearchDialogues: The dialogues class keeps track of all dialogues of type oef_search.\n\"\"\"\n\nfrom packages.fetchai.skills.generic_seller.dialogues import (\n    DefaultDialogues as GenericDefaultDialogues,\n)\nfrom packages.fetchai.skills.generic_seller.dialogues import (\n    FipaDialogues as GenericFipaDialogues,\n)\nfrom packages.fetchai.skills.generic_seller.dialogues import (\n    LedgerApiDialogues as GenericLedgerApiDialogues,\n)\nfrom packages.fetchai.skills.generic_seller.dialogues import (\n    OefSearchDialogues as GenericOefSearchDialogues,\n)\n\n\nDefaultDialogues = GenericDefaultDialogues\nFipaDialogues = GenericFipaDialogues\nLedgerApiDialogues = GenericLedgerApiDialogues\nOefSearchDialogues = GenericOefSearchDialogues\n"
  },
  {
    "path": "packages/fetchai/skills/carpark_detection/handlers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains the handlers.\"\"\"\n\nfrom packages.fetchai.skills.generic_seller.handlers import (\n    GenericFipaHandler,\n    GenericLedgerApiHandler,\n    GenericOefSearchHandler,\n)\n\n\nFipaHandler = GenericFipaHandler\nLedgerApiHandler = GenericLedgerApiHandler\nOefSearchHandler = GenericOefSearchHandler\n"
  },
  {
    "path": "packages/fetchai/skills/carpark_detection/skill.yaml",
    "content": "name: carpark_detection\nauthor: fetchai\nversion: 0.27.6\ntype: skill\ndescription: The carpark detection skill implements the detection and trading functionality\n  for a carpark agent.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: QmZYxDqNu3RnTkhNCgp7VPBMpYxaqRT4Hb64ipgYvgJ5wn\n  __init__.py: QmSiwGgkdvRNCiyF4EBEvoDpBFa5hBGLQ1F93Sd4byZ9bi\n  behaviours.py: QmYgNwz5EA4yhEnMyiV3oe16g1MAKpFPJsTENfkVMySfr8\n  database.py: QmQ2Gh58YtC1eHAu1bavLPh6D9xeDaAGgye8vG2Z1SYjgA\n  dialogues.py: QmZckK3x2oPgXmnP4XaEBJQoaPp8Gh4ojDHnxzeNsTf4tC\n  handlers.py: QmecBakMGUcam9w9hzTv5Tdi3DrABqsoDYHgk9XojEv8Ay\n  strategy.py: QmTHYX6BzXApbJnrYUMmtPPf7Ye388mQEhJ1gtURU9UV5c\nfingerprint_ignore_patterns:\n- temp_files_placeholder/*\nconnections: []\ncontracts: []\nprotocols:\n- fetchai/default:1.1.7\n- fetchai/fipa:1.1.7\n- fetchai/ledger_api:1.1.7\n- fetchai/oef_search:1.1.7\nskills:\n- fetchai/generic_seller:0.28.6\nbehaviours:\n  service_registration:\n    args:\n      services_interval: 20\n    class_name: ServiceRegistrationBehaviour\nhandlers:\n  fipa:\n    args: {}\n    class_name: GenericFipaHandler\n  ledger_api:\n    args: {}\n    class_name: GenericLedgerApiHandler\n  oef_search:\n    args: {}\n    class_name: GenericOefSearchHandler\nmodels:\n  default_dialogues:\n    args: {}\n    class_name: DefaultDialogues\n  fipa_dialogues:\n    args: {}\n    class_name: FipaDialogues\n  ledger_api_dialogues:\n    args: {}\n    class_name: LedgerApiDialogues\n  oef_search_dialogues:\n    args: {}\n    class_name: OefSearchDialogues\n  strategy:\n    args:\n      classification:\n        piece: classification\n        value: seller\n      data_for_sale:\n        free_spaces: 0\n      has_data_source: false\n      is_ledger_tx: true\n      location:\n        latitude: 51.5194\n        longitude: 0.127\n      personality_data:\n        piece: genus\n        value: data\n      service_data:\n        key: seller_service\n        value: car_park_service\n      service_id: car_park_service\n      unit_price: 10\n    class_name: Strategy\ndependencies:\n  scikit-image: {}\nis_abstract: false\n"
  },
  {
    "path": "packages/fetchai/skills/carpark_detection/strategy.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the strategy class.\"\"\"\n\nimport os\nfrom typing import Any, Dict\n\nfrom aea.exceptions import enforce\n\nfrom packages.fetchai.skills.carpark_detection.database import DetectionDatabase\nfrom packages.fetchai.skills.generic_seller.strategy import GenericStrategy\n\n\nDEFAULT_DB_IS_REL_TO_CWD = False\nDEFAULT_DB_REL_DIR = \"temp_files_placeholder\"\n\n\nclass Strategy(GenericStrategy):\n    \"\"\"This class defines a strategy for the agent.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize the strategy of the agent.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        db_is_rel_to_cwd = kwargs.pop(\"db_is_rel_to_cwd\", DEFAULT_DB_IS_REL_TO_CWD)\n        db_rel_dir = kwargs.pop(\"db_rel_dir\", DEFAULT_DB_REL_DIR)\n\n        if db_is_rel_to_cwd:\n            db_dir = os.path.join(os.getcwd(), db_rel_dir)\n        else:\n            db_dir = os.path.join(os.path.dirname(__file__), db_rel_dir)\n\n        if not os.path.isdir(db_dir):\n            raise ValueError(\"Database directory does not exist!\")\n\n        super().__init__(**kwargs)\n        self.db = DetectionDatabase(db_dir, False, logger=self.context.logger)\n        self._update_service_data()\n\n    def collect_from_data_source(self) -> Dict[str, str]:\n        \"\"\"\n        Build the data payload.\n\n        :return: the data\n        \"\"\"\n        enforce(self.db.is_db_exits(), \"Db doesn't exist.\")\n        data = self.db.get_latest_detection_data(1)\n        enforce(len(data) > 0, \"Did not find any data.\")\n        free_spaces = data[0][\"free_spaces\"]\n        return {\"free_spaces\": str(free_spaces)}\n\n    def _update_service_data(self) -> None:\n        \"\"\"Update lat and long in service data if db present.\"\"\"\n        if self.db.is_db_exits() and len(self.db.get_latest_detection_data(1)) > 0:\n            lat, lon = self.db.get_lat_lon()\n            if lat is not None and lon is not None:\n                data = {\n                    \"latitude\": lat,\n                    \"longitude\": lon,\n                }\n                self._service_data = data\n"
  },
  {
    "path": "packages/fetchai/skills/confirmation_aw1/README.md",
    "content": "# Confirmation AW1\n\n## Description\n\nThe `confirmation_aw1` skill is for handling registrations in Agent World 1.\n\n## Behaviours\n\n- `transaction`: sequentially processes transactions' settlements on a blockchain\n\n## Handlers\n\n- `contract_api`: handles `contract_api` messages for communication with a staking contract\n- `ledger_api`: handles `ledger_api` messages for interacting with a ledger\n- `registration`: handles `register` messages for registration requests\n- `signing`: handles `signing` messages for transaction signing by the decision maker\n\n## Models\n\n- `strategy`: contains the confirmation configuration\n"
  },
  {
    "path": "packages/fetchai/skills/confirmation_aw1/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the implementation of the default skill.\"\"\"\n\nfrom aea.configurations.base import PublicId\n\n\nPUBLIC_ID = PublicId.from_str(\"fetchai/confirmation_aw1:0.15.6\")\n"
  },
  {
    "path": "packages/fetchai/skills/confirmation_aw1/behaviours.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains the behaviour for the confirmation aw1 skill.\"\"\"\n\nfrom typing import Any, List, Optional, Set, cast\n\nfrom aea.protocols.dialogue.base import DialogueLabel\nfrom aea.skills.behaviours import TickerBehaviour\n\nfrom packages.fetchai.connections.ledger.base import (\n    CONNECTION_ID as LEDGER_CONNECTION_PUBLIC_ID,\n)\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\nfrom packages.fetchai.skills.confirmation_aw1.dialogues import (\n    LedgerApiDialogue,\n    LedgerApiDialogues,\n    RegisterDialogue,\n)\n\n\nDEFAULT_MAX_PROCESSING = 120\nDEFAULT_TX_INTERVAL = 2.0\nLEDGER_API_ADDRESS = str(LEDGER_CONNECTION_PUBLIC_ID)\n\n\nclass TransactionBehaviour(TickerBehaviour):\n    \"\"\"A behaviour to sequentially submit transactions to the blockchain.\"\"\"\n\n    def __init__(self, **kwargs: Any):\n        \"\"\"Initialize the transaction behaviour.\"\"\"\n        tx_interval = cast(\n            float, kwargs.pop(\"transaction_interval\", DEFAULT_TX_INTERVAL)\n        )\n        self.max_processing = cast(\n            float, kwargs.pop(\"max_processing\", DEFAULT_MAX_PROCESSING)\n        )\n        self.processing_time = 0.0\n        self.waiting: List[RegisterDialogue] = []\n        self.processing: Optional[LedgerApiDialogue] = None\n        self.timedout: Set[DialogueLabel] = set()\n        super().__init__(tick_interval=tx_interval, **kwargs)\n\n    def setup(self) -> None:\n        \"\"\"Setup behaviour.\"\"\"\n\n    def act(self) -> None:\n        \"\"\"Implement the act.\"\"\"\n        if self.processing is not None:\n            if self.processing_time <= self.max_processing:\n                # already processing\n                self.processing_time += self.tick_interval\n                return\n            self._timeout_processing()\n        if len(self.waiting) == 0:\n            # nothing to process\n            return\n        self._start_processing()\n\n    def _start_processing(self) -> None:\n        \"\"\"Process the next transaction.\"\"\"\n        register_dialogue = self.waiting.pop(0)\n        self.context.logger.info(\n            f\"Processing transaction, {len(self.waiting)} transactions remaining\"\n        )\n        ledger_api_dialogues = cast(\n            LedgerApiDialogues, self.context.ledger_api_dialogues\n        )\n        ledger_api_msg, ledger_api_dialogue = ledger_api_dialogues.create(\n            counterparty=LEDGER_API_ADDRESS,\n            performative=LedgerApiMessage.Performative.GET_RAW_TRANSACTION,\n            terms=register_dialogue.terms,\n        )\n        ledger_api_dialogue = cast(LedgerApiDialogue, ledger_api_dialogue)\n        ledger_api_dialogue.associated_register_dialogue = register_dialogue\n        self.processing_time = 0.0\n        self.processing = ledger_api_dialogue\n        self.context.logger.info(\n            f\"requesting transfer transaction from ledger api for message={ledger_api_msg}...\"\n        )\n        self.context.outbox.put_message(message=ledger_api_msg)\n\n    def teardown(self) -> None:\n        \"\"\"Teardown behaviour.\"\"\"\n\n    def _timeout_processing(self) -> None:\n        \"\"\"Timeout processing.\"\"\"\n        if self.processing is None:\n            return\n        self.timedout.add(self.processing.dialogue_label)\n        self.waiting.append(self.processing.associated_register_dialogue)\n        self.processing_time = 0.0\n        self.processing = None\n\n    def finish_processing(self, ledger_api_dialogue: LedgerApiDialogue) -> None:\n        \"\"\"\n        Finish processing.\n\n        :param ledger_api_dialogue: the ledger api dialogue\n        \"\"\"\n        if self.processing == ledger_api_dialogue:\n            self.processing_time = 0.0\n            self.processing = None\n            return\n        if ledger_api_dialogue.dialogue_label not in self.timedout:\n            raise ValueError(\n                f\"Non-matching dialogues in transaction behaviour: {self.processing} and {ledger_api_dialogue}\"\n            )\n        self.timedout.remove(ledger_api_dialogue.dialogue_label)\n        self.context.logger.debug(\n            f\"Timeout dialogue in transaction processing: {ledger_api_dialogue}\"\n        )\n        # don't reset, as another might be processing\n\n    def failed_processing(self, ledger_api_dialogue: LedgerApiDialogue) -> None:\n        \"\"\"\n        Failed processing.\n\n        Currently, we retry processing indefinitely.\n\n        :param ledger_api_dialogue: the ledger api dialogue\n        \"\"\"\n        self.finish_processing(ledger_api_dialogue)\n        self.waiting.append(ledger_api_dialogue.associated_register_dialogue)\n"
  },
  {
    "path": "packages/fetchai/skills/confirmation_aw1/dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nThis module contains the classes required for dialogue management.\n\n- OefSearchDialogue: The dialogue class maintains state of a dialogue and manages it.\n- OefSearchDialogues: The dialogues class keeps track of all dialogues.\n\"\"\"\n\nfrom typing import Any, Optional, Type\n\nfrom aea.exceptions import AEAEnforceError, enforce\nfrom aea.helpers.transaction.base import Terms\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\nfrom aea.protocols.dialogue.base import DialogueLabel as BaseDialogueLabel\nfrom aea.skills.base import Address, Model\n\nfrom packages.fetchai.protocols.contract_api.dialogues import (\n    ContractApiDialogue as BaseContractApiDialogue,\n)\nfrom packages.fetchai.protocols.contract_api.dialogues import (\n    ContractApiDialogues as BaseContractApiDialogues,\n)\nfrom packages.fetchai.protocols.contract_api.message import ContractApiMessage\nfrom packages.fetchai.protocols.default.dialogues import (\n    DefaultDialogue as BaseDefaultDialogue,\n)\nfrom packages.fetchai.protocols.default.dialogues import (\n    DefaultDialogues as BaseDefaultDialogues,\n)\nfrom packages.fetchai.protocols.ledger_api.dialogues import (\n    LedgerApiDialogue as BaseLedgerApiDialogue,\n)\nfrom packages.fetchai.protocols.ledger_api.dialogues import (\n    LedgerApiDialogues as BaseLedgerApiDialogues,\n)\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\nfrom packages.fetchai.protocols.register.dialogues import (\n    RegisterDialogue as BaseRegisterDialogue,\n)\nfrom packages.fetchai.protocols.register.dialogues import (\n    RegisterDialogues as BaseRegisterDialogues,\n)\nfrom packages.fetchai.protocols.register.message import RegisterMessage\nfrom packages.fetchai.protocols.signing.dialogues import (\n    SigningDialogue as BaseSigningDialogue,\n)\nfrom packages.fetchai.protocols.signing.dialogues import (\n    SigningDialogues as BaseSigningDialogues,\n)\nfrom packages.fetchai.protocols.signing.message import SigningMessage\n\n\nDefaultDialogue = BaseDefaultDialogue\n\n\nclass DefaultDialogues(Model, BaseDefaultDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return DefaultDialogue.Role.AGENT\n\n        BaseDefaultDialogues.__init__(\n            self,\n            self_address=self.context.agent_address,\n            role_from_first_message=role_from_first_message,\n        )\n\n\nclass RegisterDialogue(BaseRegisterDialogue):\n    \"\"\"The dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    __slots__ = (\"_terms\",)\n\n    def __init__(\n        self,\n        dialogue_label: BaseDialogueLabel,\n        self_address: Address,\n        role: BaseDialogue.Role,\n        message_class: Type[RegisterMessage] = RegisterMessage,\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n        :param message_class: the message class\n        \"\"\"\n        BaseRegisterDialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            self_address=self_address,\n            role=role,\n            message_class=message_class,\n        )\n        self._terms = None  # type: Optional[Terms]\n\n    @property\n    def terms(self) -> Terms:\n        \"\"\"Get terms.\"\"\"\n        if self._terms is None:\n            raise AEAEnforceError(\"Terms not set!\")\n        return self._terms\n\n    @terms.setter\n    def terms(self, terms: Terms) -> None:\n        \"\"\"Set terms.\"\"\"\n        enforce(self._terms is None, \"Terms already set!\")\n        self._terms = terms\n\n\nclass RegisterDialogues(Model, BaseRegisterDialogues):\n    \"\"\"This class keeps track of all register dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return BaseRegisterDialogue.Role.AGENT\n\n        BaseRegisterDialogues.__init__(\n            self,\n            self_address=self.context.agent_address,\n            role_from_first_message=role_from_first_message,\n            dialogue_class=RegisterDialogue,\n        )\n\n\nclass ContractApiDialogue(BaseContractApiDialogue):\n    \"\"\"The dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    __slots__ = (\"_terms\", \"_associated_register_dialogue\")\n\n    def __init__(\n        self,\n        dialogue_label: BaseDialogueLabel,\n        self_address: Address,\n        role: BaseDialogue.Role,\n        message_class: Type[ContractApiMessage] = ContractApiMessage,\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n        :param message_class: the message class\n        \"\"\"\n        BaseContractApiDialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            self_address=self_address,\n            role=role,\n            message_class=message_class,\n        )\n        self._terms = None  # type: Optional[Terms]\n        self._associated_register_dialogue = None  # type: Optional[RegisterDialogue]\n\n    @property\n    def terms(self) -> Terms:\n        \"\"\"Get the terms.\"\"\"\n        if self._terms is None:\n            raise ValueError(\"Terms not set!\")\n        return self._terms\n\n    @terms.setter\n    def terms(self, terms: Terms) -> None:\n        \"\"\"Set the terms.\"\"\"\n        enforce(self._terms is None, \"Terms already set!\")\n        self._terms = terms\n\n    @property\n    def associated_register_dialogue(self) -> RegisterDialogue:\n        \"\"\"Get the associated register dialogue.\"\"\"\n        if self._associated_register_dialogue is None:\n            raise ValueError(\"Associated register dialogue not set!\")\n        return self._associated_register_dialogue\n\n    @associated_register_dialogue.setter\n    def associated_register_dialogue(\n        self, associated_register_dialogue: RegisterDialogue\n    ) -> None:\n        \"\"\"Set the associated register dialogue.\"\"\"\n        enforce(\n            self._associated_register_dialogue is None,\n            \"Associated register dialogue already set!\",\n        )\n        self._associated_register_dialogue = associated_register_dialogue\n\n\nclass ContractApiDialogues(Model, BaseContractApiDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return ContractApiDialogue.Role.AGENT\n\n        BaseContractApiDialogues.__init__(\n            self,\n            self_address=str(self.skill_id),\n            role_from_first_message=role_from_first_message,\n            dialogue_class=ContractApiDialogue,\n        )\n\n\nclass LedgerApiDialogue(BaseLedgerApiDialogue):\n    \"\"\"The dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    __slots__ = (\"_associated_register_dialogue\", \"_terms\")\n\n    def __init__(\n        self,\n        dialogue_label: BaseDialogueLabel,\n        self_address: Address,\n        role: BaseDialogue.Role,\n        message_class: Type[LedgerApiMessage] = LedgerApiMessage,\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n        :param message_class: the message class\n        \"\"\"\n        BaseLedgerApiDialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            self_address=self_address,\n            role=role,\n            message_class=message_class,\n        )\n        self._associated_register_dialogue = None  # type: Optional[RegisterDialogue]\n        self._terms = None  # type: Optional[Terms]\n\n    @property\n    def associated_register_dialogue(self) -> RegisterDialogue:\n        \"\"\"Get associated_register_dialogue.\"\"\"\n        if self._associated_register_dialogue is None:\n            raise AEAEnforceError(\"RegisterDialogue not set!\")\n        return self._associated_register_dialogue\n\n    @associated_register_dialogue.setter\n    def associated_register_dialogue(self, register_dialogue: RegisterDialogue) -> None:\n        \"\"\"Set associated_fipa_dialogue\"\"\"\n        enforce(\n            self._associated_register_dialogue is None, \"RegisterDialogue already set!\"\n        )\n        self._associated_register_dialogue = register_dialogue\n\n\nclass LedgerApiDialogues(Model, BaseLedgerApiDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return BaseLedgerApiDialogue.Role.AGENT\n\n        BaseLedgerApiDialogues.__init__(\n            self,\n            self_address=str(self.skill_id),\n            role_from_first_message=role_from_first_message,\n            dialogue_class=LedgerApiDialogue,\n        )\n\n\nclass SigningDialogue(BaseSigningDialogue):\n    \"\"\"The dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    __slots__ = (\"_associated_ledger_api_dialogue\",)\n\n    def __init__(\n        self,\n        dialogue_label: BaseDialogueLabel,\n        self_address: Address,\n        role: BaseDialogue.Role,\n        message_class: Type[SigningMessage] = SigningMessage,\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n        :param message_class: the message class\n        \"\"\"\n        BaseSigningDialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            self_address=self_address,\n            role=role,\n            message_class=message_class,\n        )\n        self._associated_ledger_api_dialogue = None  # type: Optional[LedgerApiDialogue]\n\n    @property\n    def associated_ledger_api_dialogue(self) -> LedgerApiDialogue:\n        \"\"\"Get associated_ledger_dialogue.\"\"\"\n        if self._associated_ledger_api_dialogue is None:\n            raise AEAEnforceError(\"LedgerApiDialogue not set!\")\n        return self._associated_ledger_api_dialogue\n\n    @associated_ledger_api_dialogue.setter\n    def associated_ledger_api_dialogue(\n        self, ledger_api_dialogue: LedgerApiDialogue\n    ) -> None:\n        \"\"\"Set associated_ledger_dialogue\"\"\"\n        enforce(\n            self._associated_ledger_api_dialogue is None,\n            \"LedgerApiDialogue already set!\",\n        )\n        self._associated_ledger_api_dialogue = ledger_api_dialogue\n\n\nclass SigningDialogues(Model, BaseSigningDialogues):\n    \"\"\"This class keeps track of all signing dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return BaseSigningDialogue.Role.SKILL\n\n        BaseSigningDialogues.__init__(\n            self,\n            self_address=str(self.skill_id),\n            role_from_first_message=role_from_first_message,\n            dialogue_class=SigningDialogue,\n        )\n"
  },
  {
    "path": "packages/fetchai/skills/confirmation_aw1/handlers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains a scaffold of a handler.\"\"\"\n\nfrom typing import Optional, cast\n\nfrom aea.configurations.base import PublicId\nfrom aea.crypto.ledger_apis import LedgerApis\nfrom aea.protocols.base import Message\nfrom aea.skills.base import Handler\n\nfrom packages.fetchai.connections.ledger.base import (\n    CONNECTION_ID as LEDGER_CONNECTION_PUBLIC_ID,\n)\nfrom packages.fetchai.protocols.contract_api.message import ContractApiMessage\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\nfrom packages.fetchai.protocols.register.message import RegisterMessage\nfrom packages.fetchai.protocols.signing.message import SigningMessage\nfrom packages.fetchai.skills.confirmation_aw1.behaviours import TransactionBehaviour\nfrom packages.fetchai.skills.confirmation_aw1.dialogues import (\n    ContractApiDialogue,\n    ContractApiDialogues,\n    DefaultDialogues,\n    LedgerApiDialogue,\n    LedgerApiDialogues,\n    RegisterDialogue,\n    RegisterDialogues,\n    SigningDialogue,\n    SigningDialogues,\n)\nfrom packages.fetchai.skills.confirmation_aw1.strategy import Strategy\n\n\nLEDGER_API_ADDRESS = str(LEDGER_CONNECTION_PUBLIC_ID)\n\n\nclass AW1RegistrationHandler(Handler):\n    \"\"\"This class handles register messages.\"\"\"\n\n    SUPPORTED_PROTOCOL = RegisterMessage.protocol_id\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to an envelope.\n\n        :param message: the message\n        \"\"\"\n        register_msg = cast(RegisterMessage, message)\n\n        # recover dialogue\n        register_dialogues = cast(RegisterDialogues, self.context.register_dialogues)\n        register_dialogue = cast(\n            Optional[RegisterDialogue], register_dialogues.update(register_msg)\n        )\n        if register_dialogue is None:\n            self._handle_unidentified_dialogue(register_msg)\n            return\n\n        # handle message\n        if register_msg.performative is RegisterMessage.Performative.REGISTER:\n            self._handle_register(register_msg, register_dialogue)\n        else:\n            self._handle_invalid(register_msg, register_dialogue)\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n\n    def _handle_unidentified_dialogue(self, register_msg: RegisterMessage) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param register_msg: the register message\n        \"\"\"\n        self.context.logger.info(\n            f\"received invalid register_msg message={register_msg}, unidentified dialogue.\"\n        )\n\n    def _handle_register(\n        self, register_msg: RegisterMessage, register_dialogue: RegisterDialogue\n    ) -> None:\n        \"\"\"\n        Handle an register message.\n\n        :param register_msg: the register message\n        :param register_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.info(\n            f\"received register_msg register message={register_msg} in dialogue={register_dialogue}.\"\n        )\n        strategy = cast(Strategy, self.context.strategy)\n        is_valid, error_code, error_msg = strategy.valid_registration(\n            register_msg.info, register_msg.sender\n        )\n        if is_valid:\n            strategy.lock_registration_temporarily(\n                register_msg.sender, register_msg.info\n            )\n            self.context.logger.info(\n                f\"valid registration={register_msg.info}. Verifying if tokens staked.\"\n            )\n            terms = strategy.get_terms(register_msg.sender)\n            if not strategy.developer_handle_only:\n                contract_api_dialogues = cast(\n                    ContractApiDialogues, self.context.contract_api_dialogues\n                )\n                kwargs = strategy.get_kwargs(register_msg.info)\n                contract_api_msg, contract_api_dialogue = contract_api_dialogues.create(\n                    counterparty=LEDGER_API_ADDRESS,\n                    performative=ContractApiMessage.Performative.GET_STATE,\n                    ledger_id=strategy.contract_ledger_id,\n                    contract_id=strategy.contract_id,\n                    contract_address=strategy.contract_address,\n                    callable=strategy.contract_callable,\n                    kwargs=ContractApiMessage.Kwargs(kwargs),\n                )\n                contract_api_dialogue = cast(ContractApiDialogue, contract_api_dialogue)\n                contract_api_dialogue.terms = terms\n                contract_api_dialogue.associated_register_dialogue = register_dialogue\n                self.context.outbox.put_message(contract_api_msg)\n            else:\n                strategy.finalize_registration(register_msg.sender)\n                register_dialogue.terms = terms\n                tx_behaviour = cast(\n                    TransactionBehaviour, self.context.behaviours.transaction\n                )\n                tx_behaviour.waiting.append(register_dialogue)\n        else:\n            self.context.logger.info(\n                f\"invalid registration={register_msg.info}. Rejecting.\"\n            )\n            reply = register_dialogue.reply(\n                performative=RegisterMessage.Performative.ERROR,\n                error_code=error_code,\n                error_msg=error_msg,\n                info={},\n            )\n            self.context.outbox.put_message(reply)\n\n    def _handle_invalid(\n        self, register_msg: RegisterMessage, register_dialogue: RegisterDialogue\n    ) -> None:\n        \"\"\"\n        Handle an register message.\n\n        :param register_msg: the register message\n        :param register_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.warning(\n            f\"cannot handle register_msg message of performative={register_msg.performative} in dialogue={register_dialogue}.\"\n        )\n\n\nclass ContractApiHandler(Handler):\n    \"\"\"Implement the contract api handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = ContractApiMessage.protocol_id  # type: Optional[PublicId]\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup for the handler.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to a message.\n\n        :param message: the message\n        \"\"\"\n        contract_api_msg = cast(ContractApiMessage, message)\n\n        # recover dialogue\n        contract_api_dialogues = cast(\n            ContractApiDialogues, self.context.contract_api_dialogues\n        )\n        contract_api_dialogue = cast(\n            Optional[ContractApiDialogue],\n            contract_api_dialogues.update(contract_api_msg),\n        )\n        if contract_api_dialogue is None:\n            self._handle_unidentified_dialogue(contract_api_msg)\n            return\n\n        # handle message\n        if contract_api_msg.performative is ContractApiMessage.Performative.STATE:\n            self._handle_state(contract_api_msg, contract_api_dialogue)\n        elif contract_api_msg.performative == ContractApiMessage.Performative.ERROR:\n            self._handle_error(contract_api_msg, contract_api_dialogue)\n        else:\n            self._handle_invalid(contract_api_msg, contract_api_dialogue)\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n\n    def _handle_unidentified_dialogue(\n        self, contract_api_msg: ContractApiMessage\n    ) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param contract_api_msg: the contract api message\n        \"\"\"\n        self.context.logger.info(\n            f\"received invalid contract_api message={contract_api_msg}, unidentified dialogue.\"\n        )\n\n    def _handle_state(\n        self,\n        contract_api_msg: ContractApiMessage,\n        contract_api_dialogue: ContractApiDialogue,\n    ) -> None:\n        \"\"\"\n        Handle a message of raw_message performative.\n\n        :param contract_api_msg: the ledger api message\n        :param contract_api_dialogue: the ledger api dialogue\n        \"\"\"\n        self.context.logger.info(f\"received state message={contract_api_msg}\")\n        register_dialogue = contract_api_dialogue.associated_register_dialogue\n        register_msg = cast(\n            Optional[RegisterMessage], register_dialogue.last_incoming_message\n        )\n        if register_msg is None:\n            raise ValueError(\"Could not retrieve fipa message\")\n        strategy = cast(Strategy, self.context.strategy)\n        if strategy.has_staked(contract_api_msg.state.body):\n            self.context.logger.info(\"Has staked! Requesting funds release.\")\n            strategy.finalize_registration(register_msg.sender)\n            register_dialogue.terms = contract_api_dialogue.terms\n            tx_behaviour = cast(\n                TransactionBehaviour, self.context.behaviours.transaction\n            )\n            tx_behaviour.waiting.append(register_dialogue)\n        else:\n            strategy.unlock_registration(register_msg.sender)\n            self.context.logger.info(\n                f\"invalid registration={register_msg.info}. Rejecting.\"\n            )\n            reply = register_dialogue.reply(\n                performative=RegisterMessage.Performative.ERROR,\n                error_code=1,\n                error_msg=\"No funds staked!\",\n                info={},\n            )\n            self.context.outbox.put_message(reply)\n\n    def _handle_error(\n        self,\n        contract_api_msg: ContractApiMessage,\n        contract_api_dialogue: ContractApiDialogue,\n    ) -> None:\n        \"\"\"\n        Handle a message of error performative.\n\n        :param contract_api_msg: the ledger api message\n        :param contract_api_dialogue: the ledger api dialogue\n        \"\"\"\n        self.context.logger.info(\n            f\"received ledger_api error message={contract_api_msg} in dialogue={contract_api_dialogue}.\"\n        )\n        register_dialogue = contract_api_dialogue.associated_register_dialogue\n        register_msg = cast(\n            Optional[RegisterMessage], register_dialogue.last_incoming_message\n        )\n        if register_msg is None:\n            raise ValueError(\"Could not retrieve fipa message\")\n        strategy = cast(Strategy, self.context.strategy)\n        strategy.unlock_registration(register_msg.sender)\n\n    def _handle_invalid(\n        self,\n        contract_api_msg: ContractApiMessage,\n        contract_api_dialogue: ContractApiDialogue,\n    ) -> None:\n        \"\"\"\n        Handle a message of invalid performative.\n\n        :param contract_api_msg: the ledger api message\n        :param contract_api_dialogue: the ledger api dialogue\n        \"\"\"\n        self.context.logger.warning(\n            f\"cannot handle contract_api message of performative={contract_api_msg.performative} in dialogue={contract_api_dialogue}.\"\n        )\n\n\nclass LedgerApiHandler(Handler):\n    \"\"\"Implement the ledger handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = LedgerApiMessage.protocol_id  # type: Optional[PublicId]\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup for the handler.\"\"\"\n        strategy = cast(Strategy, self.context.strategy)\n        for registered_aea in strategy.all_registered_aeas:\n            self._send_confirmation_details_to_awx_aeas(registered_aea)\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to a message.\n\n        :param message: the message\n        \"\"\"\n        ledger_api_msg = cast(LedgerApiMessage, message)\n\n        # recover dialogue\n        ledger_api_dialogues = cast(\n            LedgerApiDialogues, self.context.ledger_api_dialogues\n        )\n        ledger_api_dialogue = cast(\n            Optional[LedgerApiDialogue], ledger_api_dialogues.update(ledger_api_msg)\n        )\n        if ledger_api_dialogue is None:\n            self._handle_unidentified_dialogue(ledger_api_msg)\n            return\n\n        # handle message\n        if ledger_api_msg.performative is LedgerApiMessage.Performative.RAW_TRANSACTION:\n            self._handle_raw_transaction(ledger_api_msg, ledger_api_dialogue)\n        elif (\n            ledger_api_msg.performative\n            == LedgerApiMessage.Performative.TRANSACTION_DIGEST\n        ):\n            self._handle_transaction_digest(ledger_api_msg, ledger_api_dialogue)\n        elif (\n            ledger_api_msg.performative\n            == LedgerApiMessage.Performative.TRANSACTION_RECEIPT\n        ):\n            self._handle_transaction_receipt(ledger_api_msg, ledger_api_dialogue)\n        elif ledger_api_msg.performative == LedgerApiMessage.Performative.ERROR:\n            self._handle_error(ledger_api_msg, ledger_api_dialogue)\n        else:\n            self._handle_invalid(ledger_api_msg, ledger_api_dialogue)\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n\n    def _handle_unidentified_dialogue(self, ledger_api_msg: LedgerApiMessage) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param ledger_api_msg: the ledger api message\n        \"\"\"\n        self.context.logger.info(\n            f\"received invalid ledger_api message={ledger_api_msg}, unidentified dialogue.\"\n        )\n\n    def _handle_raw_transaction(\n        self, ledger_api_msg: LedgerApiMessage, ledger_api_dialogue: LedgerApiDialogue\n    ) -> None:\n        \"\"\"\n        Handle a message of raw_transaction performative.\n\n        :param ledger_api_msg: the ledger api message\n        :param ledger_api_dialogue: the ledger api dialogue\n        \"\"\"\n        self.context.logger.info(f\"received raw transaction={ledger_api_msg}\")\n        signing_dialogues = cast(SigningDialogues, self.context.signing_dialogues)\n        signing_msg, signing_dialogue = signing_dialogues.create(\n            counterparty=self.context.decision_maker_address,\n            performative=SigningMessage.Performative.SIGN_TRANSACTION,\n            raw_transaction=ledger_api_msg.raw_transaction,\n            terms=ledger_api_dialogue.associated_register_dialogue.terms,\n        )\n        signing_dialogue = cast(SigningDialogue, signing_dialogue)\n        signing_dialogue.associated_ledger_api_dialogue = ledger_api_dialogue\n        self.context.decision_maker_message_queue.put_nowait(signing_msg)\n        self.context.logger.info(\n            \"proposing the transaction to the decision maker. Waiting for confirmation ...\"\n        )\n\n    def _handle_transaction_digest(\n        self, ledger_api_msg: LedgerApiMessage, ledger_api_dialogue: LedgerApiDialogue\n    ) -> None:\n        \"\"\"\n        Handle a message of transaction_digest performative.\n\n        :param ledger_api_msg: the ledger api message\n        :param ledger_api_dialogue: the ledger api dialogue\n        \"\"\"\n        self.context.logger.info(\n            \"transaction was successfully submitted. Transaction digest={}\".format(\n                ledger_api_msg.transaction_digest\n            )\n        )\n        ledger_api_msg_ = ledger_api_dialogue.reply(\n            performative=LedgerApiMessage.Performative.GET_TRANSACTION_RECEIPT,\n            target_message=ledger_api_msg,\n            transaction_digest=ledger_api_msg.transaction_digest,\n        )\n        self.context.logger.info(\"checking transaction is settled.\")\n        self.context.outbox.put_message(message=ledger_api_msg_)\n\n    def _handle_transaction_receipt(\n        self, ledger_api_msg: LedgerApiMessage, ledger_api_dialogue: LedgerApiDialogue\n    ) -> None:\n        \"\"\"\n        Handle a message of balance performative.\n\n        :param ledger_api_msg: the ledger api message\n        :param ledger_api_dialogue: the ledger api dialogue\n        \"\"\"\n        register_dialogue = ledger_api_dialogue.associated_register_dialogue\n        is_settled = LedgerApis.is_transaction_settled(\n            register_dialogue.terms.ledger_id,\n            ledger_api_msg.transaction_receipt.receipt,\n        )\n        tx_behaviour = cast(TransactionBehaviour, self.context.behaviours.transaction)\n        if is_settled:\n            tx_behaviour.finish_processing(ledger_api_dialogue)\n            ledger_api_msg_ = cast(\n                Optional[LedgerApiMessage], ledger_api_dialogue.last_outgoing_message\n            )\n            if ledger_api_msg_ is None:\n                raise ValueError(  # pragma: nocover\n                    \"Could not retrieve last ledger_api message\"\n                )\n            register_msg = cast(\n                Optional[RegisterMessage], register_dialogue.last_incoming_message\n            )\n            if register_msg is None:\n                raise ValueError(\"Could not retrieve last register message\")\n            response = register_dialogue.reply(\n                performative=RegisterMessage.Performative.SUCCESS,\n                target_message=register_msg,\n                info={\"transaction_digest\": ledger_api_msg_.transaction_digest.body},\n            )\n            self.context.outbox.put_message(message=response)\n            self.context.logger.info(\n                f\"informing counterparty={response.to} of registration success.\"\n            )\n            self._send_confirmation_details_to_awx_aeas(response.to)\n        else:\n            tx_behaviour.failed_processing(ledger_api_dialogue)\n            self.context.logger.info(\n                \"transaction_receipt={} not settled or not valid, aborting\".format(\n                    ledger_api_msg.transaction_receipt\n                )\n            )\n\n    def _send_confirmation_details_to_awx_aeas(self, confirmed_aea: str) -> None:\n        \"\"\"\n        Send a confirmation of registration to aw2 AEAs.\n\n        :param confirmed_aea: the confirmed aea's address\n        \"\"\"\n        strategy = cast(Strategy, self.context.strategy)\n        if strategy.awx_aeas != []:\n            developer_handle = strategy.get_developer_handle(confirmed_aea)\n            self.context.logger.info(\n                f\"informing awx_aeas={strategy.awx_aeas} of registration success of confirmed aea={confirmed_aea} of developer={developer_handle}.\"\n            )\n            default_dialogues = cast(DefaultDialogues, self.context.default_dialogues)\n            for awx_aea in strategy.awx_aeas:\n                msg, _ = default_dialogues.create(\n                    counterparty=awx_aea,\n                    performative=DefaultMessage.Performative.BYTES,\n                    content=f\"{confirmed_aea}_{developer_handle}\".encode(\"utf-8\"),\n                )\n                self.context.outbox.put_message(message=msg)\n\n    def _handle_error(\n        self, ledger_api_msg: LedgerApiMessage, ledger_api_dialogue: LedgerApiDialogue\n    ) -> None:\n        \"\"\"\n        Handle a message of error performative.\n\n        :param ledger_api_msg: the ledger api message\n        :param ledger_api_dialogue: the ledger api dialogue\n        \"\"\"\n        self.context.logger.info(\n            f\"received ledger_api error message={ledger_api_msg} in dialogue={ledger_api_dialogue}.\"\n        )\n        ledger_api_msg_ = cast(\n            Optional[LedgerApiMessage], ledger_api_dialogue.last_outgoing_message\n        )\n        if (\n            ledger_api_msg_ is not None\n            and ledger_api_msg_.performative\n            != LedgerApiMessage.Performative.GET_BALANCE\n        ):\n            tx_behaviour = cast(\n                TransactionBehaviour, self.context.behaviours.transaction\n            )\n            tx_behaviour.failed_processing(ledger_api_dialogue)\n\n    def _handle_invalid(\n        self, ledger_api_msg: LedgerApiMessage, ledger_api_dialogue: LedgerApiDialogue\n    ) -> None:\n        \"\"\"\n        Handle a message of invalid performative.\n\n        :param ledger_api_msg: the ledger api message\n        :param ledger_api_dialogue: the ledger api dialogue\n        \"\"\"\n        self.context.logger.warning(\n            f\"cannot handle ledger_api message of performative={ledger_api_msg.performative} in dialogue={ledger_api_dialogue}.\"\n        )\n\n\nclass SigningHandler(Handler):\n    \"\"\"Implement the signing handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = SigningMessage.protocol_id  # type: Optional[PublicId]\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup for the handler.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to a message.\n\n        :param message: the message\n        \"\"\"\n        signing_msg = cast(SigningMessage, message)\n\n        # recover dialogue\n        signing_dialogues = cast(SigningDialogues, self.context.signing_dialogues)\n        signing_dialogue = cast(\n            Optional[SigningDialogue], signing_dialogues.update(signing_msg)\n        )\n        if signing_dialogue is None:\n            self._handle_unidentified_dialogue(signing_msg)\n            return\n\n        # handle message\n        if signing_msg.performative is SigningMessage.Performative.SIGNED_TRANSACTION:\n            self._handle_signed_transaction(signing_msg, signing_dialogue)\n        elif signing_msg.performative is SigningMessage.Performative.ERROR:\n            self._handle_error(signing_msg, signing_dialogue)\n        else:\n            self._handle_invalid(signing_msg, signing_dialogue)\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n\n    def _handle_unidentified_dialogue(self, signing_msg: SigningMessage) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param signing_msg: the message\n        \"\"\"\n        self.context.logger.info(\n            f\"received invalid signing message={signing_msg}, unidentified dialogue.\"\n        )\n\n    def _handle_signed_transaction(\n        self, signing_msg: SigningMessage, signing_dialogue: SigningDialogue\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param signing_msg: the signing message\n        :param signing_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.info(\"transaction signing was successful.\")\n        ledger_api_dialogue = signing_dialogue.associated_ledger_api_dialogue\n        last_ledger_api_msg = ledger_api_dialogue.last_incoming_message\n        if last_ledger_api_msg is None:\n            raise ValueError(\"Could not retrieve last message in ledger api dialogue\")\n        ledger_api_msg = ledger_api_dialogue.reply(\n            performative=LedgerApiMessage.Performative.SEND_SIGNED_TRANSACTION,\n            target_message=last_ledger_api_msg,\n            signed_transaction=signing_msg.signed_transaction,\n        )\n        self.context.outbox.put_message(message=ledger_api_msg)\n        self.context.logger.info(\"sending transaction to ledger.\")\n\n    def _handle_error(\n        self, signing_msg: SigningMessage, signing_dialogue: SigningDialogue\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param signing_msg: the signing message\n        :param signing_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.info(\n            f\"transaction signing was not successful. Error_code={signing_msg.error_code} in dialogue={signing_dialogue}\"\n        )\n        signing_msg_ = cast(\n            Optional[SigningMessage], signing_dialogue.last_outgoing_message\n        )\n        if (\n            signing_msg_ is not None\n            and signing_msg_.performative\n            == SigningMessage.Performative.SIGN_TRANSACTION\n        ):\n            tx_behaviour = cast(\n                TransactionBehaviour, self.context.behaviours.transaction\n            )\n            ledger_api_dialogue = signing_dialogue.associated_ledger_api_dialogue\n            tx_behaviour.failed_processing(ledger_api_dialogue)\n\n    def _handle_invalid(\n        self, signing_msg: SigningMessage, signing_dialogue: SigningDialogue\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param signing_msg: the signing message\n        :param signing_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.warning(\n            f\"cannot handle signing message of performative={signing_msg.performative} in dialogue={signing_dialogue}.\"\n        )\n"
  },
  {
    "path": "packages/fetchai/skills/confirmation_aw1/registration_db.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains a the registration db model.\"\"\"\n\nimport logging\nimport os\nimport sqlite3\nfrom typing import Any, List, Tuple\n\nfrom aea.skills.base import Model\n\n\n_default_logger = logging.getLogger(\n    \"aea.packages.fetchai.skills.carpark_detection.detection_database\"\n)\n\n\nclass RegistrationDB(Model):\n    \"\"\"Communicate between the database and the python objects.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"Initialise the class.\"\"\"\n        custom_path = kwargs.pop(\"custom_path\", None)\n        super().__init__(**kwargs)\n        this_dir = os.getcwd()\n        self.db_path = (\n            os.path.join(this_dir, \"registration.db\")\n            if custom_path is None\n            else custom_path\n        )\n        if not os.path.exists(os.path.dirname(os.path.abspath(self.db_path))):\n            raise ValueError(f\"Path={self.db_path} not valid!\")  # pragma: nocover\n        self._initialise_backend()\n\n    def _initialise_backend(self) -> None:\n        \"\"\"Set up database and initialise the tables.\"\"\"\n        if os.path.isfile(self.db_path):\n            return\n        self._execute_single_sql(\n            \"CREATE TABLE IF NOT EXISTS registered_table (address TEXT, ethereum_address TEXT, \"\n            \"ethereum_signature TEXT, fetchai_signature TEXT, \"\n            \"developer_handle TEXT, tweet TEXT)\"\n        )\n\n    def set_registered(\n        self,\n        address: str,\n        ethereum_address: str,\n        ethereum_signature: str,\n        fetchai_signature: str,\n        developer_handle: str,\n        tweet: str,\n    ) -> None:\n        \"\"\"Record a registration.\"\"\"\n        command = \"INSERT OR REPLACE INTO registered_table(address, ethereum_address, ethereum_signature, fetchai_signature, developer_handle, tweet) values(?, ?, ?, ?, ?, ?)\"\n        variables = (\n            address,\n            ethereum_address,\n            ethereum_signature,\n            fetchai_signature,\n            developer_handle,\n            tweet,\n        )\n        self._execute_single_sql(command, variables)\n\n    def set_registered_developer_only(\n        self,\n        address: str,\n        developer_handle: str,\n    ) -> None:\n        \"\"\"Record a registration.\"\"\"\n        command = \"INSERT OR REPLACE INTO registered_table(address, developer_handle) values(?, ?)\"\n        variables = (\n            address,\n            developer_handle,\n        )\n        self._execute_single_sql(command, variables)\n\n    def is_registered(self, address: str) -> bool:\n        \"\"\"Check if an address is registered.\"\"\"\n        command = \"SELECT * FROM registered_table WHERE address=?\"\n        variables = (address,)\n        result = self._execute_single_sql(command, variables)\n        return len(result) != 0\n\n    def get_developer_handle(self, address: str) -> str:\n        \"\"\"Get developer handle relating to an address.\"\"\"\n        command = \"SELECT developer_handle FROM registered_table WHERE address=?\"\n        variables = (address,)\n        result = self._execute_single_sql(command, variables)\n        if len(result[0]) != 1:\n            raise ValueError(\n                f\"More than one developer_handle found for address={address}.\"\n            )\n        return result[0][0]\n\n    def get_ethereum_address(\n        self, address: str, developer_handle: str\n    ) -> str:  # pragma: no cover\n        \"\"\"Get ethereum address relating to an address (hacky for backwards compatibility).\"\"\"\n        command = \"SELECT ethereum_address FROM registered_table WHERE address=?\"\n        variables = (address,)\n        result = self._execute_single_sql(command, variables)\n        if len(result) != 0 and len(result[0]) != 1:\n            raise ValueError(\n                f\"More than one ethereum_address found for address={address}.\"\n            )\n        if len(result) != 0 and (result[0][0] != \"\" or developer_handle == \"\"):\n            return result[0][0]\n        command = (\n            \"SELECT ethereum_address FROM registered_table WHERE developer_handle=?\"\n        )\n        variables = (developer_handle,)\n        result = self._execute_single_sql(command, variables)\n        if len(result) == 0:\n            raise ValueError(\n                f\"No ethereum_address found for address={address} and developer_handle={developer_handle}.\"\n            )\n        if len(result[0]) != 1:\n            raise ValueError(\n                f\"More than one ethereum_address found for developer_handle={developer_handle}.\"\n            )\n        return result[0][0]\n\n    def get_all_registered(self) -> List[str]:\n        \"\"\"Get all registered AW-1 AEAs.\"\"\"\n        command = \"SELECT address FROM registered_table\"\n        variables = ()\n        results = self._execute_single_sql(command, variables)\n        registered = [result[0] for result in results]\n        return registered\n\n    def _execute_single_sql(\n        self,\n        command: str,\n        variables: Tuple[str, ...] = (),\n        print_exceptions: bool = True,\n    ) -> List[Tuple[str, ...]]:\n        \"\"\"Query the database - all the other functions use this under the hood.\"\"\"\n        conn = None\n        ret = []\n        try:\n            conn = sqlite3.connect(self.db_path, timeout=300)  # 5 mins\n            c = conn.cursor()\n            c.execute(command, variables)\n            ret = c.fetchall()\n            conn.commit()\n        except Exception as e:  # pragma: nocover # pylint: disable=broad-except\n            if print_exceptions:\n                self.context.logger.warning(f\"Exception in database: {e}\")\n        finally:\n            if conn is not None:\n                conn.close()\n\n        return ret\n"
  },
  {
    "path": "packages/fetchai/skills/confirmation_aw1/skill.yaml",
    "content": "name: confirmation_aw1\nauthor: fetchai\nversion: 0.15.6\ntype: skill\ndescription: The confirmation_aw1 skill is a skill to confirm registration for Agent\n  World 1.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: QmaGTwfKyYVAJEfqHjGVViTYer2f3JJj22ftQH19NuA3eQ\n  __init__.py: QmcNQVFKDuc6tFhTJzWvQnZkLXiiDCy1eUoAH9FYoGnrNw\n  behaviours.py: QmZVaGLyZZZJu5HBR1rNukpfnvpvEFxn8tA2JKL8JgFWUB\n  dialogues.py: QmQnYQyRtmFYhHxCirxg5vchWSogwnKVEgozKBwL19svGe\n  handlers.py: QmNsrvzaLfxHwd51ssWZjTGoVMvzemWamqLXN2oLW4gf95\n  registration_db.py: QmWWYUrickqQsp1CCxGwJdW67qBb9brbAEHAJGCFUWQ7Fc\n  strategy.py: QmUfD9UH7UrPLG25RPB7qr1fS9wvCoc8eb3BALttY12REW\nfingerprint_ignore_patterns: []\nconnections:\n- fetchai/ledger:0.21.5\ncontracts:\n- fetchai/staking_erc20:0.10.3\nprotocols:\n- fetchai/default:1.1.7\n- fetchai/ledger_api:1.1.7\n- fetchai/register:1.1.7\n- fetchai/signing:1.1.7\nskills: []\nbehaviours:\n  transaction:\n    args:\n      max_processing: 420\n      transaction_interval: 2\n    class_name: TransactionBehaviour\nhandlers:\n  contract_api:\n    args: {}\n    class_name: ContractApiHandler\n  ledger_api:\n    args: {}\n    class_name: LedgerApiHandler\n  registration:\n    args: {}\n    class_name: AW1RegistrationHandler\n  signing:\n    args: {}\n    class_name: SigningHandler\nmodels:\n  contract_api_dialogues:\n    args: {}\n    class_name: ContractApiDialogues\n  default_dialogues:\n    args: {}\n    class_name: DefaultDialogues\n  ledger_api_dialogues:\n    args: {}\n    class_name: LedgerApiDialogues\n  register_dialogues:\n    args: {}\n    class_name: RegisterDialogues\n  registration_db:\n    args:\n      custom_path: path_to_db\n    class_name: RegistrationDB\n  signing_dialogues:\n    args: {}\n    class_name: SigningDialogues\n  strategy:\n    args:\n      awx_aeas: []\n      developer_handle_only: false\n      fetchai_staking_contract_address: '0x351bac612b50e87b46e4b10a282f632d41397de2'\n      override_staking_check: false\n      token_denomination: atestfet\n      token_dispense_amount: 100000\n    class_name: Strategy\ndependencies:\n  aea-ledger-ethereum:\n    version: <2.0.0,>=1.0.0\n  aea-ledger-fetchai:\n    version: <2.0.0,>=1.0.0\nis_abstract: false\n"
  },
  {
    "path": "packages/fetchai/skills/confirmation_aw1/strategy.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains the strategy model.\"\"\"\n\nfrom typing import Any, Dict, List, Optional, Tuple, cast\n\nfrom aea.common import JSONLike\nfrom aea.crypto.ledger_apis import LedgerApis\nfrom aea.helpers.transaction.base import Terms\nfrom aea.skills.base import Model\n\nfrom packages.fetchai.contracts.staking_erc20.contract import PUBLIC_ID\nfrom packages.fetchai.skills.confirmation_aw1.registration_db import RegistrationDB\n\n\nREQUIRED_KEYS = [\n    \"ethereum_address\",\n    \"fetchai_address\",\n    \"signature_of_ethereum_address\",\n    \"signature_of_fetchai_address\",\n    \"developer_handle\",\n]\nDEVELOPER_ONLY_REQUIRED_KEYS = [\n    \"fetchai_address\",\n    \"developer_handle\",\n]\nDEFAULT_TOKEN_DISPENSE_AMOUNT = 100000\nDEFAULT_TOKEN_DENOMINATION = \"atestfet\"  # nosec\nDEFAULT_CONTRACT_ADDRESS = \"0x351bac612b50e87b46e4b10a282f632d41397de2\"\nDEFAULT_OVERRIDE = False\n\n\nclass Strategy(Model):\n    \"\"\"This class is the strategy model.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize the strategy of the agent.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        self._token_denomination = kwargs.pop(\n            \"token_denomination\", DEFAULT_TOKEN_DENOMINATION\n        )\n        self._token_dispense_amount = kwargs.pop(\n            \"token_dispense_amount\", DEFAULT_TOKEN_DISPENSE_AMOUNT\n        )\n        self._fetchai_staking_contract_address = kwargs.pop(\n            \"fetchai_staking_contract_address\", DEFAULT_CONTRACT_ADDRESS\n        )\n        self._override_staking_check = kwargs.pop(\n            \"override_staking_check\", DEFAULT_OVERRIDE\n        )\n        self.developer_handle_only = kwargs.pop(\"developer_handle_only\", False)\n        self._awx_aeas: List[str] = kwargs.pop(\"awx_aeas\", [])\n        super().__init__(**kwargs)\n        self._is_ready_to_register = False\n        self._is_registered = False\n        self.is_registration_pending = False\n        self.signature_of_ethereum_address: Optional[str] = None\n        self._ledger_id = self.context.default_ledger_id\n        self._max_tx_fee = 100\n        self._contract_ledger_id = \"ethereum\"\n        self._contract_callable = \"get_stake\"\n        self._contract_id = str(PUBLIC_ID)\n        self._in_process_registrations: Dict[str, Dict[str, str]] = {}\n\n    @property\n    def contract_id(self) -> str:\n        \"\"\"Get the ledger on which the contract is deployed.\"\"\"\n        return self._contract_id\n\n    @property\n    def contract_address(self) -> str:\n        \"\"\"Get contract address.\"\"\"\n        return self._fetchai_staking_contract_address\n\n    @property\n    def contract_ledger_id(self) -> str:\n        \"\"\"Get the ledger on which the contract is deployed.\"\"\"\n        return self._contract_ledger_id\n\n    @property\n    def contract_callable(self) -> str:\n        \"\"\"Get the ledger on which the contract is deployed.\"\"\"\n        return self._contract_callable\n\n    @property\n    def awx_aeas(self) -> List[str]:\n        \"\"\"Get list of AWx AEAs.\"\"\"\n        return self._awx_aeas\n\n    @property\n    def all_registered_aeas(self) -> List[str]:\n        \"\"\"Get all the registered AEAs.\"\"\"\n        registration_db = cast(RegistrationDB, self.context.registration_db)\n        all_registered = registration_db.get_all_registered()\n        return all_registered\n\n    def lock_registration_temporarily(self, address: str, info: Dict[str, str]) -> None:\n        \"\"\"Lock this address for registration.\"\"\"\n        self._in_process_registrations.update({address: info})\n\n    def finalize_registration(self, address: str) -> None:\n        \"\"\"Lock this address for registration.\"\"\"\n        info = self._in_process_registrations.pop(address)\n        self.context.logger.info(\n            f\"finalizing registration for address={address}, info={info}\"\n        )\n        registration_db = cast(RegistrationDB, self.context.registration_db)\n        if self.developer_handle_only:\n            registration_db.set_registered_developer_only(\n                address=address,\n                developer_handle=info[\"developer_handle\"],\n            )\n        else:\n            registration_db.set_registered(\n                address=address,\n                ethereum_address=info[\"ethereum_address\"],\n                ethereum_signature=info[\"signature_of_ethereum_address\"],\n                fetchai_signature=info[\"signature_of_fetchai_address\"],\n                developer_handle=info[\"developer_handle\"],\n                tweet=info.get(\"tweet\", \"\"),\n            )\n\n    def unlock_registration(self, address: str) -> None:\n        \"\"\"Unlock this address for registration.\"\"\"\n        info = self._in_process_registrations.pop(address, {})\n        self.context.logger.info(\n            f\"registration info did not pass staking checks = {info}\"\n        )\n\n    def get_developer_handle(self, address: str) -> str:\n        \"\"\"Get developer handle.\"\"\"\n        registration_db = cast(RegistrationDB, self.context.registration_db)\n        handle = registration_db.get_developer_handle(address)\n        return handle\n\n    def _valid_registration_developer_only(\n        self, registration_info: Dict[str, str], sender: str\n    ) -> Tuple[bool, int, str]:\n        \"\"\"\n        Check if the registration info is valid.\n\n        :param registration_info: the registration info\n        :param sender: the sender\n        :return: tuple of success, error code and error message\n        \"\"\"\n        if not sender == registration_info[\"fetchai_address\"]:\n            return (\n                False,\n                1,\n                \"fetchai address of agent and registration info do not match!\",\n            )\n        if registration_info[\"developer_handle\"] in (\"\", None):\n            return (False, 1, \"missing developer_handle!\")\n        if sender in self._in_process_registrations:\n            return (False, 1, \"registration in process for this address!\")\n        registration_db = cast(RegistrationDB, self.context.registration_db)\n        if registration_db.is_registered(sender):\n            return (False, 1, \"already registered!\")\n        return (True, 0, \"all good!\")\n\n    def valid_registration(\n        self, registration_info: Dict[str, str], sender: str\n    ) -> Tuple[bool, int, str]:\n        \"\"\"\n        Check if the registration info is valid.\n\n        :param registration_info: the registration info\n        :param sender: the sender\n        :return: tuple of success, error code and error message\n        \"\"\"\n        if self.developer_handle_only:\n            if not all(\n                key in registration_info for key in DEVELOPER_ONLY_REQUIRED_KEYS\n            ):\n                return (\n                    False,\n                    1,\n                    f\"missing keys in registration info, required: {DEVELOPER_ONLY_REQUIRED_KEYS}!\",\n                )\n\n            is_valid, error_code, error_msg = self._valid_registration_developer_only(\n                registration_info, sender\n            )\n            return (is_valid, error_code, error_msg)\n\n        if not all(key in registration_info for key in REQUIRED_KEYS):\n            return (\n                False,\n                1,\n                f\"missing keys in registration info, required: {REQUIRED_KEYS}!\",\n            )\n        is_valid, error_code, error_msg = self._valid_registration_developer_only(\n            registration_info, sender\n        )\n        if not is_valid:\n            return (is_valid, error_code, error_msg)\n\n        if not self._valid_signature(\n            registration_info[\"ethereum_address\"],\n            registration_info[\"signature_of_fetchai_address\"],\n            sender,\n            \"ethereum\",\n        ):\n            return (False, 1, \"fetchai address and signature do not match!\")\n        if not self._valid_signature(\n            sender,\n            registration_info[\"signature_of_ethereum_address\"],\n            registration_info[\"ethereum_address\"],\n            \"fetchai\",\n        ):\n            return (False, 1, \"ethereum address and signature do not match!\")\n        return (True, 0, \"all good!\")\n\n    def _valid_signature(\n        self, expected_signer: str, signature: str, message_str: str, ledger_id: str\n    ) -> bool:\n        \"\"\"\n        Check if the signature and message match the expected signer.\n\n        :param expected_signer: the signer\n        :param signature: the signature\n        :param message_str: the message\n        :param ledger_id: the ledger id\n        :return: bool indicating validity\n        \"\"\"\n        try:\n            result = expected_signer in LedgerApis.recover_message(\n                ledger_id, message_str.encode(\"utf-8\"), signature\n            )\n        except Exception as e:  # pylint: disable=broad-except\n            self.context.logger.warning(f\"Signing exception: {e}\")\n            result = False\n        return result\n\n    def get_terms(self, counterparty: str) -> Terms:\n        \"\"\"\n        Get terms of transaction.\n\n        :param counterparty: the counterparty to receive funds\n        :return: the terms\n        \"\"\"\n        terms = Terms(\n            ledger_id=self._ledger_id,\n            sender_address=self.context.agent_address,\n            counterparty_address=counterparty,\n            amount_by_currency_id={\n                self._token_denomination: -self._token_dispense_amount\n            },\n            quantities_by_good_id={},\n            is_sender_payable_tx_fee=True,\n            nonce=\"some\",\n            fee_by_currency_id={self._token_denomination: self._max_tx_fee},\n        )\n        return terms\n\n    @staticmethod\n    def get_kwargs(info: Dict[str, str]) -> JSONLike:\n        \"\"\"\n        Get the kwargs for the contract state call.\n\n        :param info: info dict\n        :return: kwargs json\n        \"\"\"\n        counterparty = info[\"ethereum_address\"]\n        return {\"address\": counterparty}\n\n    def has_staked(self, state: JSONLike) -> bool:\n        \"\"\"\n        Check if the agent has staked.\n\n        :param state: json state\n        :return: bool, indicating outcome\n        \"\"\"\n        if self._override_staking_check:\n            return True\n        result = int(cast(str, state.get(\"stake\", \"0\"))) > 0\n        return result\n"
  },
  {
    "path": "packages/fetchai/skills/confirmation_aw2/README.md",
    "content": "# Confirmation AW2\n\n## Description\n\nThis skill purchases information from other agents as specified in its configuration. It acts as the confirmation AEA in Agent World 2.\n\nThis skill searches for an agent in a vicinity on the sOEF that sells the data this skill is configured to buy. Once it found some agents which match Agent World 2 criteria, it requests this data, negotiates the price, pays the proposed amount if agreement is reached, and receives the data bought.\n\n## Behaviours\n\n- `search`: searches for data selling service on the sOEF\n- `transaction`: sequentially processes transactions' settlements on a blockchain\n\n## Handlers\n\n- `default`: handles `default` messages for registration\n- `fipa`: handles `fipa` messages for negotiation\n- `ledger_api`: handles `ledger_api` messages for interacting with a ledger\n- `oef_search`: handles `oef_search` messages to manage the sellers found\n- `signing`: handles `signing` messages for transaction signing by the decision maker\n\n## Models\n\n- `strategy`: allows the configuration of the purchasing. In particular, location and `search_radius` together determine the vicinity where the service is searched for, `search_query` specifies the query, and the remaining configuration specifies the terms of trade. Also, rules regarding Agent World 2 are enforced.\n"
  },
  {
    "path": "packages/fetchai/skills/confirmation_aw2/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the implementation of the confirmation_aw2 skill.\"\"\"\n\nfrom aea.configurations.base import PublicId\n\n\nPUBLIC_ID = PublicId.from_str(\"fetchai/confirmation_aw2:0.13.6\")\n"
  },
  {
    "path": "packages/fetchai/skills/confirmation_aw2/behaviours.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains the behaviours of the agent.\"\"\"\n\nfrom packages.fetchai.skills.generic_buyer.behaviours import (\n    GenericSearchBehaviour,\n    GenericTransactionBehaviour,\n)\n\n\nSearchBehaviour = GenericSearchBehaviour\nTransactionBehaviour = GenericTransactionBehaviour\n"
  },
  {
    "path": "packages/fetchai/skills/confirmation_aw2/dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nThis module contains the classes required for dialogue management.\n\n- DefaultDialogues: The dialogues class keeps track of all dialogues of type default.\n- FipaDialogues: The dialogues class keeps track of all dialogues of type fipa.\n- LedgerApiDialogues: The dialogues class keeps track of all dialogues of type ledger_api.\n- OefSearchDialogues: The dialogues class keeps track of all dialogues of type oef_search.\n- SigningDialogues: The dialogues class keeps track of all dialogues of type signing.\n\"\"\"\n\nfrom packages.fetchai.skills.generic_buyer.dialogues import (\n    DefaultDialogues as GenericDefaultDialogues,\n)\nfrom packages.fetchai.skills.generic_buyer.dialogues import (\n    FipaDialogues as GenericFipaDialogues,\n)\nfrom packages.fetchai.skills.generic_buyer.dialogues import (\n    LedgerApiDialogues as GenericLedgerApiDialogues,\n)\nfrom packages.fetchai.skills.generic_buyer.dialogues import (\n    OefSearchDialogues as GenericOefSearchDialogues,\n)\nfrom packages.fetchai.skills.generic_buyer.dialogues import (\n    SigningDialogues as GenericSigningDialogues,\n)\n\n\nDefaultDialogues = GenericDefaultDialogues\nFipaDialogues = GenericFipaDialogues\nLedgerApiDialogues = GenericLedgerApiDialogues\nOefSearchDialogues = GenericOefSearchDialogues\nSigningDialogues = GenericSigningDialogues\n"
  },
  {
    "path": "packages/fetchai/skills/confirmation_aw2/handlers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains the handlers of the agent.\"\"\"\n\nfrom typing import Optional, cast\n\nfrom aea.configurations.base import PublicId\nfrom aea.crypto.ledger_apis import LedgerApis\nfrom aea.protocols.base import Message\nfrom aea.skills.base import Handler\n\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.skills.confirmation_aw2.strategy import Strategy\nfrom packages.fetchai.skills.generic_buyer.dialogues import (\n    DefaultDialogue,\n    DefaultDialogues,\n)\nfrom packages.fetchai.skills.generic_buyer.handlers import (\n    GenericFipaHandler,\n    GenericLedgerApiHandler,\n    GenericOefSearchHandler,\n    GenericSigningHandler,\n)\n\n\nFipaHandler = GenericFipaHandler\nLedgerApiHandler = GenericLedgerApiHandler\nOefSearchHandler = GenericOefSearchHandler\nSigningHandler = GenericSigningHandler\n\n\nclass DefaultHandler(Handler):\n    \"\"\"This class implements the default handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = DefaultMessage.protocol_id  # type: Optional[PublicId]\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to an envelope.\n\n        :param message: the message\n        \"\"\"\n        default_msg = cast(DefaultMessage, message)\n\n        # recover dialogue\n        default_dialogues = cast(DefaultDialogues, self.context.default_dialogues)\n        default_dialogue = cast(DefaultDialogue, default_dialogues.update(default_msg))\n        if default_dialogue is None:\n            self._handle_unidentified_dialogue(default_msg)\n            return\n\n        # handle message\n        if default_msg.performative == DefaultMessage.Performative.BYTES:\n            self._handle_bytes(default_msg, default_dialogue)\n        else:\n            self._handle_invalid(default_msg, default_dialogue)\n\n    def _handle_unidentified_dialogue(self, default_msg: DefaultMessage) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param default_msg: the message\n        \"\"\"\n        self.context.logger.info(\n            f\"received invalid default message={default_msg}, unidentified dialogue.\"\n        )\n\n    def _handle_bytes(\n        self, default_msg: DefaultMessage, default_dialogue: DefaultDialogue\n    ) -> None:\n        \"\"\"\n        Handle a default message of invalid performative.\n\n        :param default_msg: the message\n        :param default_dialogue: the default dialogue\n        \"\"\"\n        strategy = cast(Strategy, self.context.strategy)\n        if default_msg.sender == strategy.aw1_aea:\n            try:\n                confirmed_aea, developer_handle = default_msg.content.decode(\n                    \"utf-8\"\n                ).split(\"_\")\n            except Exception:  # pylint: disable=broad-except\n                confirmed_aea, developer_handle = \"\", \"\"\n            if not LedgerApis.is_valid_address(\"fetchai\", confirmed_aea):\n                self.context.logger.warning(\n                    f\"received invalid address={confirmed_aea} in dialogue={default_dialogue}.\"\n                )\n                return\n            if developer_handle == \"\":\n                self.context.logger.warning(\n                    f\"received invalid developer_handle={developer_handle}.\"\n                )\n                return\n            self.context.logger.info(\n                f\"adding confirmed_aea={confirmed_aea} with developer_handle={developer_handle} to db.\"\n            )\n            strategy.register_counterparty(confirmed_aea, developer_handle)\n        else:\n            self.context.logger.warning(\n                f\"cannot handle default message of performative={default_msg.performative} in dialogue={default_dialogue}. Invalid sender={default_msg.sender}\"\n            )\n\n    def _handle_invalid(\n        self, default_msg: DefaultMessage, default_dialogue: DefaultDialogue\n    ) -> None:\n        \"\"\"\n        Handle a default message of invalid performative.\n\n        :param default_msg: the message\n        :param default_dialogue: the default dialogue\n        \"\"\"\n        self.context.logger.warning(\n            f\"cannot handle default message of performative={default_msg.performative} in dialogue={default_dialogue}.\"\n        )\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n"
  },
  {
    "path": "packages/fetchai/skills/confirmation_aw2/registration_db.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains a the registration db model.\"\"\"\n\nimport datetime\nimport json\nimport logging\nimport os\nimport sqlite3\nfrom typing import Any, Dict, List, Optional, Tuple\n\nfrom aea.skills.base import Model\n\n\n_default_logger = logging.getLogger(\n    \"aea.packages.fetchai.skills.confirmation_aw2.registration_db\"\n)\n\n\nclass RegistrationDB(Model):\n    \"\"\"Communicate between the database and the python objects.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"Initialise the class.\"\"\"\n        custom_path = kwargs.pop(\"custom_path\", None)\n        super().__init__(**kwargs)\n        this_dir = os.getcwd()\n        self.db_path = (\n            os.path.join(this_dir, \"registration.db\")\n            if custom_path is None\n            else custom_path\n        )\n        if not os.path.exists(os.path.dirname(os.path.abspath(self.db_path))):\n            raise ValueError(f\"Path={self.db_path} not valid!\")  # pragma: nocover\n        self._initialise_backend()\n\n    def _initialise_backend(self) -> None:\n        \"\"\"Set up database and initialise the tables.\"\"\"\n        self._execute_single_sql(\n            \"CREATE TABLE IF NOT EXISTS registered_table (address TEXT, ethereum_address TEXT, \"\n            \"ethereum_signature TEXT, fetchai_signature TEXT, \"\n            \"developer_handle TEXT, tweet TEXT)\"\n        )\n        self._execute_single_sql(\n            \"CREATE TABLE IF NOT EXISTS trade_table (address TEXT PRIMARY KEY, first_trade timestamp, \"\n            \"second_trade timestamp, first_info TEXT, second_info TEXT)\"\n        )\n\n    def set_trade(\n        self,\n        address: str,\n        timestamp: datetime.datetime,\n        data: Dict[str, str],\n    ) -> None:\n        \"\"\"Record a registration.\"\"\"\n        record = self.get_trade_table(address)\n        if record is None:\n            command = \"INSERT INTO trade_table(address, first_trade, second_trade, first_info, second_info) values(?, ?, ?, ?, ?)\"\n            variables: Tuple[\n                str, datetime.datetime, Optional[datetime.datetime], str, Optional[str]\n            ] = (address, timestamp, None, json.dumps(data), None)\n        else:\n            _, first_trade, second_trade, first_info, _ = record\n            is_second = first_trade is not None and second_trade is None\n            is_more_than_two = first_trade is not None and second_trade is not None\n            if is_more_than_two or not is_second:\n                return\n            command = \"INSERT or REPLACE into trade_table(address, first_trade, second_trade, first_info, second_info) values(?, ?, ?, ?, ?)\"\n            variables = (\n                address,\n                first_trade,\n                timestamp,\n                first_info,\n                json.dumps(data),\n            )\n        self._execute_single_sql(command, variables)\n\n    def get_trade_table(self, address: str) -> Optional[Tuple]:\n        \"\"\"Check whether a trade is second or not.\"\"\"\n        command = \"SELECT * FROM trade_table where address=?\"\n        ret = self._execute_single_sql(command, (address,))\n        return ret[0] if len(ret) > 0 else None\n\n    def set_registered(self, address: str, developer_handle: str) -> None:\n        \"\"\"Record a registration.\"\"\"\n        if self.is_registered(address):\n            return\n        command = \"INSERT OR REPLACE INTO registered_table(address, ethereum_address, ethereum_signature, fetchai_signature, developer_handle, tweet) values(?, ?, ?, ?, ?, ?)\"\n        variables = (\n            address,\n            \"\",\n            \"\",\n            \"\",\n            developer_handle,\n            \"\",\n        )\n        self._execute_single_sql(command, variables)\n\n    def is_registered(self, address: str) -> bool:\n        \"\"\"Check if an address is registered.\"\"\"\n        command = \"SELECT * FROM registered_table WHERE address=?\"\n        variables = (address,)\n        result = self._execute_single_sql(command, variables)\n        return len(result) != 0\n\n    def is_allowed_to_trade(self, address: str, minimum_hours_between_txs: int) -> bool:\n        \"\"\"Check if an address is registered.\"\"\"\n        record = self.get_trade_table(address)\n        if record is None:\n            # no record on trade: go ahead\n            return True\n        first_trade: Optional[str] = record[1]\n        second_trade: Optional[str] = record[2]\n        first_trade_present: bool = first_trade is not None\n        second_trade_present: bool = second_trade is not None\n        if not first_trade_present and not second_trade_present:\n            # all trades empty: go ahead\n            return True\n        if first_trade is not None and not second_trade_present:\n            now = datetime.datetime.now()\n            first_trade_dt = datetime.datetime.strptime(\n                first_trade, \"%Y-%m-%d %H:%M:%S.%f\"\n            )\n            is_allowed_to_trade_ = now - first_trade_dt > datetime.timedelta(\n                hours=minimum_hours_between_txs\n            )\n            if not is_allowed_to_trade_:\n                self.context.logger.info(\n                    f\"Invalid attempt for counterparty={address}, not enough time since last trade!\"\n                )\n            return is_allowed_to_trade_\n        self.context.logger.info(\n            f\"Invalid attempt for counterparty={address}, already completed 2 trades!\"\n        )\n        return False\n\n    def has_completed_two_trades(self, address: str) -> bool:\n        \"\"\"\n        Check if address has completed two trades.\n\n        :param address: the address to check\n        :return: bool\n        \"\"\"\n        record = self.get_trade_table(address)\n        if record is None:\n            return False\n        first_trade: Optional[str] = record[1]\n        second_trade: Optional[str] = record[2]\n        first_trade_present: bool = first_trade is not None\n        second_trade_present: bool = second_trade is not None\n        return first_trade_present and second_trade_present\n\n    def completed_two_trades(self) -> List[Tuple[str, str, str]]:\n        \"\"\"\n        Get the address, ethereum_address and developer handle combos which completed two trades.\n\n        :return: (address, ethereum_address, developer_handle)\n        \"\"\"\n        command = \"SELECT * FROM registered_table\"\n        variables = ()\n        result = self._execute_single_sql(command, variables)\n        completed: List[Tuple[str, str, str]] = []\n        for row in result:\n            address = row[0]\n            ethereum_address = row[1]\n            developer_handle = row[4]\n            if self.has_completed_two_trades(address):\n                completed.append((address, ethereum_address, developer_handle))\n        return completed\n\n    def _execute_single_sql(\n        self,\n        command: str,\n        variables: Tuple[Any, ...] = (),\n        print_exceptions: bool = True,\n    ) -> List[Tuple[str, ...]]:\n        \"\"\"Query the database - all the other functions use this under the hood.\"\"\"\n        conn = None\n        ret: List[Tuple[str, ...]] = []\n        try:\n            conn = sqlite3.connect(self.db_path, timeout=300)  # 5 mins\n            c = conn.cursor()\n            c.execute(command, variables)\n            ret = c.fetchall()\n            conn.commit()\n        except Exception as e:  # pragma: nocover # pylint: disable=broad-except\n            if print_exceptions:\n                self.context.logger.warning(f\"Exception in database: {e}\")\n        finally:\n            if conn is not None:\n                conn.close()\n\n        return ret\n"
  },
  {
    "path": "packages/fetchai/skills/confirmation_aw2/skill.yaml",
    "content": "name: confirmation_aw2\nauthor: fetchai\nversion: 0.13.6\ntype: skill\ndescription: This skill purchases information from other agents as specified in its\n  configuration. It is the confirmation buyer for Agent World 2.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: QmSQgVJrmh5XBGLKVmzEzUVmeEr6BmZmeWebqixq6EBftd\n  __init__.py: QmT9TnpHa8E3EGvPupDbjTJm3quhLTgUGAYjPXKGVnbsYs\n  behaviours.py: QmSr6fB3N7dhVo1cLY1TGd2q8usjGwNmTCNjBBbtgtVf9j\n  dialogues.py: QmXgXcs25v9ob9a9XwT49wvK788vbUdZyYxUgG3ndHjrix\n  handlers.py: QmNvKz36cN7H53yUpdW7GDAFbk5YThSVnFd691GLi3N4uN\n  registration_db.py: QmW4h9dsk7V5JmAwyJArYsAdUeKNKWL2q4cPK6FXpZV21C\n  strategy.py: QmYAdTnztBNQXDp3CqMx1PEVhtz3zFdcLuQz8muZysDfyj\nfingerprint_ignore_patterns: []\nconnections:\n- fetchai/ledger:0.21.5\ncontracts: []\nprotocols:\n- fetchai/default:1.1.7\n- fetchai/fipa:1.1.7\n- fetchai/ledger_api:1.1.7\n- fetchai/oef_search:1.1.7\n- fetchai/signing:1.1.7\nskills:\n- fetchai/generic_buyer:0.27.6\nbehaviours:\n  search:\n    args:\n      search_interval: 5\n    class_name: SearchBehaviour\n  transaction:\n    args:\n      max_processing: 420\n      transaction_interval: 2\n    class_name: TransactionBehaviour\nhandlers:\n  default_handler:\n    args: {}\n    class_name: DefaultHandler\n  fipa:\n    args: {}\n    class_name: FipaHandler\n  ledger_api:\n    args: {}\n    class_name: LedgerApiHandler\n  oef_search:\n    args: {}\n    class_name: OefSearchHandler\n  signing:\n    args: {}\n    class_name: SigningHandler\nmodels:\n  default_dialogues:\n    args: {}\n    class_name: DefaultDialogues\n  fipa_dialogues:\n    args: {}\n    class_name: FipaDialogues\n  ledger_api_dialogues:\n    args: {}\n    class_name: LedgerApiDialogues\n  oef_search_dialogues:\n    args: {}\n    class_name: OefSearchDialogues\n  registration_db:\n    args:\n      custom_path: path_to_db\n    class_name: RegistrationDB\n  signing_dialogues:\n    args: {}\n    class_name: SigningDialogues\n  strategy:\n    args:\n      aw1_aea: null\n      is_ledger_tx: true\n      location:\n        latitude: 51.5194\n        longitude: 0.127\n      max_negotiations: 1\n      max_quantity: 100\n      max_tx_fee: 3550000000000000\n      max_unit_price: 20\n      minimum_hours_between_txs: 4\n      minimum_minutes_since_last_attempt: 2\n      search_query:\n        constraint_type: ==\n        search_key: seller_service\n        search_value: weather_data\n      search_radius: 50.0\n      service_id: weather_data\n      stop_searching_on_result: false\n    class_name: Strategy\ndependencies:\n  aea-ledger-fetchai:\n    version: <2.0.0,>=1.0.0\nis_abstract: false\n"
  },
  {
    "path": "packages/fetchai/skills/confirmation_aw2/strategy.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the strategy class.\"\"\"\n\nimport datetime\nfrom typing import Any, Dict, List, Optional, Tuple, cast\n\nfrom packages.fetchai.skills.confirmation_aw2.registration_db import RegistrationDB\nfrom packages.fetchai.skills.generic_buyer.strategy import GenericStrategy\n\n\nclass Strategy(GenericStrategy):\n    \"\"\"Strategy class extending Generic Strategy.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize the strategy of the agent.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        aw1_aea: Optional[str] = kwargs.pop(\"aw1_aea\", None)\n        if aw1_aea is None:\n            raise ValueError(\"aw1_aea must be provided!\")\n        self.aw1_aea = aw1_aea\n        self.minimum_hours_between_txs = kwargs.pop(\"mininum_hours_between_txs\", 4)\n        self.minimum_minutes_since_last_attempt = kwargs.pop(\n            \"minimum_minutes_since_last_attempt\", 2\n        )\n        super().__init__(**kwargs)\n        self.last_attempt: Dict[str, datetime.datetime] = {}\n\n    def get_acceptable_counterparties(\n        self, counterparties: Tuple[str, ...]\n    ) -> Tuple[str, ...]:\n        \"\"\"\n        Process counterparties and drop unacceptable ones.\n\n        :param counterparties: a tuple of counterparties\n        :return: list of counterparties\n        \"\"\"\n        valid_counterparties: List[str] = []\n        for counterparty in counterparties:\n            if self.is_valid_counterparty(counterparty):\n                valid_counterparties.append(counterparty)\n        return tuple(valid_counterparties)\n\n    def is_enough_time_since_last_attempt(self, counterparty: str) -> bool:\n        \"\"\"\n        Check if enough time has passed since last attempt for potential previous trade to complete.\n\n        :param counterparty: the counterparty\n        :return: bool indicating validity\n        \"\"\"\n        last_time = self.last_attempt.get(counterparty, None)\n        if last_time is None:\n            return True\n        result = datetime.datetime.now() > last_time + datetime.timedelta(\n            minutes=self.minimum_minutes_since_last_attempt\n        )\n        return result\n\n    def is_valid_counterparty(self, counterparty: str) -> bool:\n        \"\"\"\n        Check if the counterparty is valid.\n\n        :param counterparty: the counterparty\n        :return: bool indicating validity\n        \"\"\"\n        registration_db = cast(RegistrationDB, self.context.registration_db)\n        if not registration_db.is_registered(counterparty):\n            self.context.logger.info(\n                f\"Invalid counterparty={counterparty}, not registered!\"\n            )\n            return False\n        if not self.is_enough_time_since_last_attempt(counterparty):\n            self.context.logger.debug(\n                f\"Not enough time since last attempt for counterparty={counterparty}!\"\n            )\n            return False\n        self.last_attempt[counterparty] = datetime.datetime.now()\n        if not registration_db.is_allowed_to_trade(\n            counterparty, self.minimum_hours_between_txs\n        ):\n            return False\n        return True\n\n    def successful_trade_with_counterparty(\n        self, counterparty: str, data: Dict[str, str]\n    ) -> None:\n        \"\"\"\n        Do something on successful trade.\n\n        :param counterparty: the counterparty address\n        :param data: the data\n        \"\"\"\n        registration_db = cast(RegistrationDB, self.context.registration_db)\n        registration_db.set_trade(counterparty, datetime.datetime.now(), data)\n        self.context.logger.info(\n            f\"Successful trade with={counterparty}. Data acquired={data}!\"\n        )\n\n    def register_counterparty(self, counterparty: str, developer_handle: str) -> None:\n        \"\"\"\n        Register a counterparty.\n\n        :param counterparty: the counterparty address\n        :param developer_handle: the developer handle\n        \"\"\"\n        registration_db = cast(RegistrationDB, self.context.registration_db)\n        registration_db.set_registered(counterparty, developer_handle)\n"
  },
  {
    "path": "packages/fetchai/skills/confirmation_aw3/README.md",
    "content": "# Confirmation AW3\n\n## Description\n\nThis skill purchases information from other agents as specified in its configuration. It acts as the confirmation AEA in Agent World 3.\n\nThis skill searches for an agent in a vicinity on the sOEF that sells the data this skill is configured to buy. Once it found some agents which match Agent World 3 criteria, it requests this data, negotiates the price, pays the proposed amount if agreement is reached, and receives the data bought. The skill just randomly selects the location in which it searches and the query from a list. On each search it completes as many trade as possible.\n\n## Behaviours\n\n- `search`: searches for data selling service on the sOEF\n- `transaction`: sequentially processes transactions' settlements on a blockchain\n\n## Handlers\n\n- `default`: handles `default` messages for registration\n- `fipa`: handles `fipa` messages for negotiation\n- `ledger_api`: handles `ledger_api` messages for interacting with a ledger\n- `oef_search`: handles `oef_search` messages to manage the sellers found\n- `signing`: handles `signing` messages for transaction signing by the decision maker\n\n## Models\n\n- `strategy`: allows the configuration of the purchasing. In particular, location and `search_radius` together determine the vicinity where the service is searched for, `search_query` specifies the query, and the remaining configuration specifies the terms of trade. Also, rules regarding Agent World 3 are enforced.\n"
  },
  {
    "path": "packages/fetchai/skills/confirmation_aw3/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the implementation of the confirmation_aw3 skill.\"\"\"\n\nfrom aea.configurations.base import PublicId\n\n\nPUBLIC_ID = PublicId.from_str(\"fetchai/confirmation_aw3:0.12.6\")\n"
  },
  {
    "path": "packages/fetchai/skills/confirmation_aw3/behaviours.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains the behaviours of the agent.\"\"\"\n\nfrom packages.fetchai.skills.generic_buyer.behaviours import (\n    GenericSearchBehaviour,\n    GenericTransactionBehaviour,\n)\n\n\nTransactionBehaviour = GenericTransactionBehaviour\nSearchBehaviour = GenericSearchBehaviour\n"
  },
  {
    "path": "packages/fetchai/skills/confirmation_aw3/dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nThis module contains the classes required for dialogue management.\n\n- DefaultDialogues: The dialogues class keeps track of all dialogues of type default.\n- FipaDialogues: The dialogues class keeps track of all dialogues of type fipa.\n- LedgerApiDialogues: The dialogues class keeps track of all dialogues of type ledger_api.\n- OefSearchDialogues: The dialogues class keeps track of all dialogues of type oef_search.\n- SigningDialogues: The dialogues class keeps track of all dialogues of type signing.\n\"\"\"\nfrom typing import Any\n\nfrom aea.common import Address\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\nfrom aea.skills.base import Model\n\nfrom packages.fetchai.protocols.http.dialogues import HttpDialogue as BaseHttpDialogue\nfrom packages.fetchai.protocols.http.dialogues import HttpDialogues as BaseHttpDialogues\nfrom packages.fetchai.skills.generic_buyer.dialogues import (\n    DefaultDialogue as GenericDefaultDialogue,\n)\nfrom packages.fetchai.skills.generic_buyer.dialogues import (\n    DefaultDialogues as GenericDefaultDialogues,\n)\nfrom packages.fetchai.skills.generic_buyer.dialogues import (\n    FipaDialogues as GenericFipaDialogues,\n)\nfrom packages.fetchai.skills.generic_buyer.dialogues import (\n    LedgerApiDialogues as GenericLedgerApiDialogues,\n)\nfrom packages.fetchai.skills.generic_buyer.dialogues import (\n    OefSearchDialogues as GenericOefSearchDialogues,\n)\nfrom packages.fetchai.skills.generic_buyer.dialogues import (\n    SigningDialogues as GenericSigningDialogues,\n)\n\n\nDefaultDialogue = GenericDefaultDialogue\nDefaultDialogues = GenericDefaultDialogues\nFipaDialogues = GenericFipaDialogues\nLedgerApiDialogues = GenericLedgerApiDialogues\nOefSearchDialogues = GenericOefSearchDialogues\nSigningDialogues = GenericSigningDialogues\nHttpDialogue = BaseHttpDialogue\n\n\nclass HttpDialogues(Model, BaseHttpDialogues):\n    \"\"\"This class keeps track of all http dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return BaseHttpDialogue.Role.CLIENT\n\n        BaseHttpDialogues.__init__(\n            self,\n            self_address=str(self.skill_id),\n            role_from_first_message=role_from_first_message,\n        )\n"
  },
  {
    "path": "packages/fetchai/skills/confirmation_aw3/handlers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains the handlers of the agent.\"\"\"\n\nfrom typing import Optional, cast\n\nfrom aea.configurations.base import PublicId\nfrom aea.crypto.ledger_apis import LedgerApis\nfrom aea.protocols.base import Message\nfrom aea.skills.base import Handler\n\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.protocols.http.message import HttpMessage\nfrom packages.fetchai.skills.confirmation_aw3.dialogues import (\n    DefaultDialogue,\n    DefaultDialogues,\n    HttpDialogue,\n    HttpDialogues,\n)\nfrom packages.fetchai.skills.confirmation_aw3.strategy import Strategy\nfrom packages.fetchai.skills.generic_buyer.handlers import (\n    GenericFipaHandler,\n    GenericLedgerApiHandler,\n    GenericOefSearchHandler,\n    GenericSigningHandler,\n)\n\n\nFipaHandler = GenericFipaHandler\nLedgerApiHandler = GenericLedgerApiHandler\nOefSearchHandler = GenericOefSearchHandler\nSigningHandler = GenericSigningHandler\n\n\nclass DefaultHandler(Handler):\n    \"\"\"This class implements the default handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = DefaultMessage.protocol_id  # type: Optional[PublicId]\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to an envelope.\n\n        :param message: the message\n        \"\"\"\n        default_msg = cast(DefaultMessage, message)\n\n        # recover dialogue\n        default_dialogues = cast(DefaultDialogues, self.context.default_dialogues)\n        default_dialogue = cast(DefaultDialogue, default_dialogues.update(default_msg))\n        if default_dialogue is None:\n            self._handle_unidentified_dialogue(default_msg)\n            return\n\n        # handle message\n        if default_msg.performative == DefaultMessage.Performative.BYTES:\n            self._handle_bytes(default_msg, default_dialogue)\n        else:\n            self._handle_invalid(default_msg, default_dialogue)\n\n    def _handle_unidentified_dialogue(self, default_msg: DefaultMessage) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param default_msg: the message\n        \"\"\"\n        self.context.logger.info(\n            f\"received invalid default message={default_msg}, unidentified dialogue.\"\n        )\n\n    def _handle_bytes(\n        self, default_msg: DefaultMessage, default_dialogue: DefaultDialogue\n    ) -> None:\n        \"\"\"\n        Handle a default message of invalid performative.\n\n        :param default_msg: the message\n        :param default_dialogue: the default dialogue\n        \"\"\"\n        strategy = cast(Strategy, self.context.strategy)\n        if default_msg.sender == strategy.aw1_aea:\n            try:\n                confirmed_aea, developer_handle = default_msg.content.decode(\n                    \"utf-8\"\n                ).split(\"_\")\n            except Exception:  # pylint: disable=broad-except\n                confirmed_aea, developer_handle = \"\", \"\"\n            if not LedgerApis.is_valid_address(\"fetchai\", confirmed_aea):\n                self.context.logger.warning(\n                    f\"received invalid address={confirmed_aea} in dialogue={default_dialogue}.\"\n                )\n                return\n            if developer_handle == \"\":\n                self.context.logger.warning(\n                    f\"received invalid developer_handle={developer_handle}.\"\n                )\n                return\n            self.context.logger.info(\n                f\"adding confirmed_aea={confirmed_aea} with developer_handle={developer_handle} to db.\"\n            )\n            strategy.register_counterparty(confirmed_aea, developer_handle)\n        else:\n            self.context.logger.warning(\n                f\"cannot handle default message of performative={default_msg.performative} in dialogue={default_dialogue}. Invalid sender={default_msg.sender}\"\n            )\n\n    def _handle_invalid(\n        self, default_msg: DefaultMessage, default_dialogue: DefaultDialogue\n    ) -> None:\n        \"\"\"\n        Handle a default message of invalid performative.\n\n        :param default_msg: the message\n        :param default_dialogue: the default dialogue\n        \"\"\"\n        self.context.logger.warning(\n            f\"cannot handle default message of performative={default_msg.performative} in dialogue={default_dialogue}.\"\n        )\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n\n\nclass HttpHandler(Handler):\n    \"\"\"This implements the http handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = HttpMessage.protocol_id\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to an envelope.\n\n        :param message: the message\n        \"\"\"\n        http_msg = cast(HttpMessage, message)\n\n        # recover dialogue\n        http_dialogues = cast(HttpDialogues, self.context.http_dialogues)\n        http_dialogue = cast(HttpDialogue, http_dialogues.update(http_msg))\n        if http_dialogue is None:\n            self._handle_unidentified_dialogue(http_msg)\n            return\n\n        # handle message\n        if http_msg.performative == HttpMessage.Performative.RESPONSE:\n            self._handle_response(http_msg, http_dialogue)\n        else:\n            self._handle_invalid(http_msg, http_dialogue)\n\n    def _handle_unidentified_dialogue(self, http_msg: HttpMessage) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param http_msg: the message\n        \"\"\"\n        self.context.logger.info(\n            \"received invalid http message={}, unidentified dialogue.\".format(http_msg)\n        )\n\n    def _handle_response(\n        self, http_msg: HttpMessage, http_dialogue: HttpDialogue\n    ) -> None:\n        \"\"\"\n        Handle a Http response.\n\n        :param http_msg: the http message\n        :param http_dialogue: the http dialogue\n        \"\"\"\n        self.context.logger.info(\n            \"received http response with status_code={}, status_text={} and body={!r} in dialogue={}\".format(\n                http_msg.status_code, http_msg.status_text, http_msg.body, http_dialogue\n            )\n        )\n\n    def _handle_invalid(\n        self, http_msg: HttpMessage, http_dialogue: HttpDialogue\n    ) -> None:\n        \"\"\"\n        Handle an invalid http message.\n\n        :param http_msg: the http message\n        :param http_dialogue: the http dialogue\n        \"\"\"\n        self.context.logger.warning(\n            \"cannot handle http message of performative={} in dialogue={}.\".format(\n                http_msg.performative, http_dialogue\n            )\n        )\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n"
  },
  {
    "path": "packages/fetchai/skills/confirmation_aw3/registration_db.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains a the registration db model.\"\"\"\n\nimport datetime\nimport json\nimport logging\nimport os\nimport sqlite3\nfrom collections import defaultdict\nfrom typing import Any, Dict, List, Tuple, cast\n\nfrom aea.skills.base import Model\n\n\n_default_logger = logging.getLogger(\n    \"aea.packages.fetchai.skills.confirmation_aw3.registration_db\"\n)\n\n\nclass RegistrationDB(Model):\n    \"\"\"Communicate between the database and the python objects.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"Initialise the class.\"\"\"\n        custom_path = kwargs.pop(\"custom_path\", None)\n        super().__init__(**kwargs)\n        this_dir = os.getcwd()\n        self.db_path = (\n            os.path.join(this_dir, \"registration.db\")\n            if custom_path is None\n            else custom_path\n        )\n        if not os.path.exists(os.path.dirname(os.path.abspath(self.db_path))):\n            raise ValueError(f\"Path={self.db_path} not valid!\")  # pragma: nocover\n        self._initialise_backend()\n\n    def _initialise_backend(self) -> None:\n        \"\"\"Set up database and initialise the tables.\"\"\"\n        self._execute_single_sql(\n            \"CREATE TABLE IF NOT EXISTS registered_table (address TEXT NOT NULL, ethereum_address TEXT, \"\n            \"ethereum_signature TEXT, fetchai_signature TEXT, \"\n            \"developer_handle TEXT NOT NULL, tweet TEXT, PRIMARY KEY (address, developer_handle))\"\n        )\n        self._execute_single_sql(\n            \"CREATE TABLE IF NOT EXISTS trades_table (address TEXT, created_at timestamp, data TEXT)\"\n        )\n\n    def set_trade(\n        self,\n        address: str,\n        timestamp: datetime.datetime,\n        data: Dict[str, str],\n    ) -> None:\n        \"\"\"Record a registration.\"\"\"\n        command = \"INSERT INTO trades_table(address, created_at, data) values(?, ?, ?)\"\n        variables: Tuple[str, datetime.datetime, str] = (\n            address,\n            timestamp,\n            json.dumps(data),\n        )\n        self._execute_single_sql(command, variables)\n\n    def get_trade_count(self, address: str) -> int:\n        \"\"\"Get trade count.\"\"\"\n        command = \"SELECT COUNT(*) FROM trades_table where address=?\"\n        ret = self._execute_single_sql(command, (address,))\n        return int(ret[0][0])\n\n    def get_developer_handle(self, address: str) -> str:\n        \"\"\"Get developer handle for address.\"\"\"\n        command = \"SELECT developer_handle FROM registered_table where address=?\"\n        ret = self._execute_single_sql(command, (address,))\n        if len(ret[0]) != 1:\n            raise ValueError(\n                f\"More than one developer_handle found for address={address}.\"\n            )\n        return ret[0][0]\n\n    def get_addresses(self, developer_handle: str) -> List[str]:\n        \"\"\"Get addresses for developer handle.\"\"\"\n        command = \"SELECT address FROM registered_table where developer_handle=?\"\n        ret = self._execute_single_sql(command, (developer_handle,))\n        addresses = [address[0] for address in ret]\n        if len(addresses) == 0:\n            raise ValueError(\n                f\"Should find at least one address for developer_handle={developer_handle}.\"\n            )\n        return addresses\n\n    def get_handle_and_trades(self, address: str) -> Tuple[str, int]:\n        \"\"\"Get developer and number of trades for address.\"\"\"\n        developer_handle = self.get_developer_handle(address)\n        addresses = self.get_addresses(developer_handle)\n        trades = 0\n        for address_ in addresses:\n            trades += self.get_trade_count(address_)\n        return (developer_handle, trades)\n\n    def get_all_addresses_and_handles(self) -> List[Tuple[str, str]]:\n        \"\"\"Get all addresses.\"\"\"\n        command = \"SELECT address, developer_handle FROM registered_table\"\n        results = cast(List[Tuple[str, str]], self._execute_single_sql(command, ()))\n        return results\n\n    def get_leaderboard(self) -> List[Tuple[str, str, int]]:\n        \"\"\"Get the leader board.\"\"\"\n        addresses_and_handles = self.get_all_addresses_and_handles()\n        results_dir: Dict[Tuple[str, str], int] = defaultdict(int)\n        for address, developer_handle in addresses_and_handles:\n            trades = self.get_trade_count(address)\n            if trades == 0:\n                continue\n            results_dir[(address, developer_handle)] += trades\n        results = [(k[0], k[1], v) for k, v in results_dir.items()]\n        results.sort(key=lambda x: x[2], reverse=True)\n        return results\n\n    def set_registered(self, address: str, developer_handle: str) -> None:\n        \"\"\"Record a registration.\"\"\"\n        if self.is_registered(address):\n            return\n        command = \"INSERT OR REPLACE INTO registered_table(address, ethereum_address, ethereum_signature, fetchai_signature, developer_handle, tweet) values(?, ?, ?, ?, ?, ?)\"\n        variables = (\n            address,\n            \"\",\n            \"\",\n            \"\",\n            developer_handle,\n            \"\",\n        )\n        self._execute_single_sql(command, variables)\n\n    def is_registered(self, address: str) -> bool:\n        \"\"\"Check if an address is registered.\"\"\"\n        command = \"SELECT * FROM registered_table WHERE address=?\"\n        variables = (address,)\n        result = self._execute_single_sql(command, variables)\n        return len(result) != 0\n\n    def _execute_single_sql(\n        self,\n        command: str,\n        variables: Tuple[Any, ...] = (),\n        print_exceptions: bool = True,\n    ) -> List[Tuple[str, ...]]:\n        \"\"\"Query the database - all the other functions use this under the hood.\"\"\"\n        conn = None\n        ret: List[Tuple[str, ...]] = []\n        try:\n            conn = sqlite3.connect(self.db_path, timeout=300)  # 5 mins\n            c = conn.cursor()\n            c.execute(command, variables)\n            ret = c.fetchall()\n            conn.commit()\n        except Exception as e:  # pragma: nocover # pylint: disable=broad-except\n            if print_exceptions:\n                self.context.logger.warning(f\"Exception in database: {e}\")\n        finally:\n            if conn is not None:\n                conn.close()\n\n        return ret\n"
  },
  {
    "path": "packages/fetchai/skills/confirmation_aw3/skill.yaml",
    "content": "name: confirmation_aw3\nauthor: fetchai\nversion: 0.12.6\ntype: skill\ndescription: This skill purchases information from other agents as specified in its\n  configuration. It is the confirmation buyer for Agent World 3.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: Qmc4XzqCbGB6mS17ZuvW2xuYnR796NX5KD3fyaNqchLirS\n  __init__.py: QmSDPS2qm1UPFGfhMtKnSrAKsksRSuypqwF1rw1AP5PTEQ\n  behaviours.py: QmagZNufvC8QgMRkPokWg71Gg2nbNSL5bBurxZtvgpGVhw\n  dialogues.py: QmXzPttMCTFQxh7R1BXzqFcdezGp7yybstkZDPJFzjECMM\n  handlers.py: QmSBUW5akPUegJqSAThyEtPtkhiFwTNQ7iqdadeztGAwhB\n  registration_db.py: QmPXfcm3mmJyaTfyKvEdwSVhwtrA4aTiBQLENDNUHmzMvc\n  strategy.py: QmaSrYsAtniAEpW5NrnqBqQiBfvhhSZ6aBWRFDtXowJjQJ\nfingerprint_ignore_patterns: []\nconnections:\n- fetchai/http_client:0.24.6\n- fetchai/ledger:0.21.5\ncontracts: []\nprotocols:\n- fetchai/default:1.1.7\n- fetchai/fipa:1.1.7\n- fetchai/ledger_api:1.1.7\n- fetchai/oef_search:1.1.7\n- fetchai/signing:1.1.7\nskills:\n- fetchai/generic_buyer:0.27.6\nbehaviours:\n  search:\n    args:\n      search_interval: 1800\n    class_name: SearchBehaviour\n  transaction:\n    args:\n      max_processing: 420\n      transaction_interval: 2\n    class_name: TransactionBehaviour\nhandlers:\n  default_handler:\n    args: {}\n    class_name: DefaultHandler\n  fipa:\n    args: {}\n    class_name: FipaHandler\n  http_handler:\n    args: {}\n    class_name: HttpHandler\n  ledger_api:\n    args: {}\n    class_name: LedgerApiHandler\n  oef_search:\n    args: {}\n    class_name: OefSearchHandler\n  signing:\n    args: {}\n    class_name: SigningHandler\nmodels:\n  default_dialogues:\n    args: {}\n    class_name: DefaultDialogues\n  fipa_dialogues:\n    args: {}\n    class_name: FipaDialogues\n  http_dialogues:\n    args: {}\n    class_name: HttpDialogues\n  ledger_api_dialogues:\n    args: {}\n    class_name: LedgerApiDialogues\n  oef_search_dialogues:\n    args: {}\n    class_name: OefSearchDialogues\n  registration_db:\n    args:\n      custom_path: path_to_db\n    class_name: RegistrationDB\n  signing_dialogues:\n    args: {}\n    class_name: SigningDialogues\n  strategy:\n    args:\n      aw1_aea: null\n      is_ledger_tx: true\n      leaderboard_token: null\n      leaderboard_url: null\n      locations:\n        berlin:\n          latitude: 52.52\n          longitude: 13.405\n        london:\n          latitude: 51.5074\n          longitude: -0.1278\n        san_francisco:\n          latitude: 37.7749\n          longitude: -122.4194\n        shanghai:\n          latitude: 31.2304\n          longitude: 121.4737\n        rome:\n          latitude: 41.9028\n          longitude: 12.4964\n        rio_de_janeiro:\n          latitude: -22.9068\n          longitude: -43.1729\n        sydney:\n          latitude: -33.8688\n          longitude: 151.2093\n        delhi:\n          latitude: 28.7041\n          longitude: 77.1025\n        tokyo:\n          latitude: 35.6762\n          longitude: 139.6503\n        mexico_city:\n          latitude: 19.4326\n          longitude: -99.1332\n        cairo:\n          latitude: 30.0444\n          longitude: 31.2357\n        kinshasa:\n          latitude: -4.4419\n          longitude: 15.2663\n      max_negotiations: 1\n      max_quantity: 100\n      max_tx_fee: 3550000000000000\n      max_unit_price: 20\n      min_quantity: 1\n      search_queries:\n        weather:\n          constraint_type: ==\n          search_key: seller_service\n          search_value: weather_data\n        mobility:\n          constraint_type: ==\n          search_key: seller_service\n          search_value: mobility_data\n      search_radius: 50.0\n      stop_searching_on_result: false\n    class_name: Strategy\ndependencies:\n  aea-ledger-fetchai:\n    version: <2.0.0,>=1.0.0\nis_abstract: false\n"
  },
  {
    "path": "packages/fetchai/skills/confirmation_aw3/strategy.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the strategy class.\"\"\"\n\nimport datetime\nimport json\nimport random\nfrom typing import Any, Dict, List, Optional, Tuple, cast\n\nfrom aea.helpers.search.models import Location\n\nfrom packages.fetchai.connections.http_client.connection import (\n    PUBLIC_ID as HTTP_CLIENT_PUBLIC_ID,\n)\nfrom packages.fetchai.protocols.http.message import HttpMessage\nfrom packages.fetchai.skills.confirmation_aw3.dialogues import HttpDialogues\nfrom packages.fetchai.skills.confirmation_aw3.registration_db import RegistrationDB\nfrom packages.fetchai.skills.generic_buyer.strategy import GenericStrategy\n\n\nclass Strategy(GenericStrategy):\n    \"\"\"Strategy class extending Generic Strategy.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize the strategy of the agent.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        aw1_aea: Optional[str] = kwargs.pop(\"aw1_aea\", None)\n        if aw1_aea is None:\n            raise ValueError(\"aw1_aea must be provided!\")\n        self.aw1_aea = aw1_aea\n        self._locations = kwargs.pop(\"locations\", {})\n        if len(self._locations) == 0:\n            raise ValueError(\"locations must have at least one entry\")\n        _, location = next(iter(self._locations.items()))\n        kwargs[\"location\"] = location\n        self._search_queries = kwargs.pop(\"search_queries\", {})\n        if len(self._search_queries) == 0:\n            raise ValueError(\"search_queries must have at least one entry\")\n        _, search_query = next(iter(self._search_queries.items()))\n        kwargs[\"search_query\"] = search_query\n        kwargs[\"service_id\"] = search_query[\"search_value\"]\n        leaderboard_url = kwargs.pop(\"leaderboard_url\", None)\n        if leaderboard_url is None:\n            raise ValueError(\"No leader board url provided!\")\n        self.leaderboard_url = f\"{leaderboard_url}/insert\"\n        leaderboard_token = kwargs.pop(\"leaderboard_token\")\n        if leaderboard_token is None:\n            raise ValueError(\"No leader board token provided!\")\n        self.leaderboard_token = leaderboard_token\n        super().__init__(**kwargs)\n\n    def get_acceptable_counterparties(\n        self, counterparties: Tuple[str, ...]\n    ) -> Tuple[str, ...]:\n        \"\"\"\n        Process counterparties and drop unacceptable ones.\n\n        :param counterparties: tuple of counterparties\n        :return: list of counterparties\n        \"\"\"\n        valid_counterparties: List[str] = []\n        for counterparty in counterparties:\n            if self.is_valid_counterparty(counterparty):\n                valid_counterparties.append(counterparty)\n        return tuple(valid_counterparties)\n\n    def is_valid_counterparty(self, counterparty: str) -> bool:\n        \"\"\"\n        Check if the counterparty is valid.\n\n        :param counterparty: the counterparty\n        :return: bool indicating validity\n        \"\"\"\n        registration_db = cast(RegistrationDB, self.context.registration_db)\n        if not registration_db.is_registered(counterparty):\n            self.context.logger.info(\n                f\"Invalid counterparty={counterparty}, not registered!\"\n            )\n            return False\n        return True\n\n    def successful_trade_with_counterparty(\n        self, counterparty: str, data: Dict[str, str]\n    ) -> None:\n        \"\"\"\n        Do something on successful trade.\n\n        :param counterparty: the counterparty address\n        :param data: the data\n        \"\"\"\n        registration_db = cast(RegistrationDB, self.context.registration_db)\n        registration_db.set_trade(counterparty, datetime.datetime.now(), data)\n        self.context.logger.info(f\"Successful trade with={counterparty}.\")\n        developer_handle, nb_trades = registration_db.get_handle_and_trades(\n            counterparty\n        )\n        http_dialogues = cast(HttpDialogues, self.context.http_dialogues)\n        request_http_message, _ = http_dialogues.create(\n            counterparty=str(HTTP_CLIENT_PUBLIC_ID),\n            performative=HttpMessage.Performative.REQUEST,\n            method=\"POST\",\n            url=self.leaderboard_url,\n            headers=\"Content-Type: application/json; charset=utf-8\",\n            version=\"\",\n            body=json.dumps(\n                {\n                    \"name\": developer_handle,\n                    \"points\": nb_trades,\n                    \"token\": self.leaderboard_token,\n                }\n            ).encode(\"utf-8\"),\n        )\n        self.context.outbox.put_message(message=request_http_message)\n        self.context.logger.info(\n            f\"Notifying leaderboard: developer_handle={developer_handle}, nb_trades={nb_trades}.\"\n        )\n\n    def register_counterparty(self, counterparty: str, developer_handle: str) -> None:\n        \"\"\"\n        Register a counterparty.\n\n        :param counterparty: the counterparty address\n        :param developer_handle: the developer handle\n        \"\"\"\n        registration_db = cast(RegistrationDB, self.context.registration_db)\n        registration_db.set_registered(counterparty, developer_handle)\n\n    def update_search_query_params(self) -> None:\n        \"\"\"Update agent location and query for search.\"\"\"\n        search_query_type, search_query = random.choice(  # nosec\n            list(self._search_queries.items())\n        )\n        self._search_query = search_query\n        self._service_id = search_query[\"search_value\"]\n        location_name, location = random.choice(list(self._locations.items()))  # nosec\n        self._agent_location = Location(\n            latitude=location[\"latitude\"], longitude=location[\"longitude\"]\n        )\n        self.context.logger.info(\n            f\"New search_type={search_query_type} and location={location_name}.\"\n        )\n"
  },
  {
    "path": "packages/fetchai/skills/echo/README.md",
    "content": "# Echo\n\n## Description\n\nThis skill sends back the contents of any message it receives.\n\n## Behaviours\n\n- `echo`: outputs messages\n\n## Handlers\n\n- `echo`: handles `default` messages for echoing back the contents of any message received\n\n## Links\n\n- <a href=\"https://docs.fetch.ai/aea/quickstart/\" target=\"_blank\">Quick Start</a>\n- <a href=\"https://docs.fetch.ai/aea/build-aea-programmatically/\" target=\"_blank\">Programmatically Build an AEA</a>\n"
  },
  {
    "path": "packages/fetchai/skills/echo/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains an example of skill for an AEA.\"\"\"\n\nfrom aea.configurations.base import PublicId\n\n\nPUBLIC_ID = PublicId.from_str(\"fetchai/echo:0.20.6\")\n"
  },
  {
    "path": "packages/fetchai/skills/echo/behaviours.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the behaviours for the 'echo' skill.\"\"\"\n\nfrom aea.skills.behaviours import TickerBehaviour\n\n\nclass EchoBehaviour(TickerBehaviour):\n    \"\"\"Echo behaviour.\"\"\"\n\n    def setup(self) -> None:\n        \"\"\"Set up the behaviour.\"\"\"\n        self.context.logger.info(\"Echo Behaviour: setup method called.\")\n\n    def act(self) -> None:\n        \"\"\"Act according to the behaviour.\"\"\"\n        self.context.logger.info(\"Echo Behaviour: act method called.\")\n\n    def teardown(self) -> None:\n        \"\"\"Teardown the behaviour.\"\"\"\n        self.context.logger.info(\"Echo Behaviour: teardown method called.\")\n"
  },
  {
    "path": "packages/fetchai/skills/echo/dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the classes required for dialogue management.\"\"\"\n\nfrom typing import Any\n\nfrom aea.protocols.base import Address, Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\nfrom aea.skills.base import Model\n\nfrom packages.fetchai.protocols.default.dialogues import (\n    DefaultDialogue as BaseDefaultDialogue,\n)\nfrom packages.fetchai.protocols.default.dialogues import (\n    DefaultDialogues as BaseDefaultDialogues,\n)\n\n\nDefaultDialogue = BaseDefaultDialogue\n\n\nclass DefaultDialogues(Model, BaseDefaultDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return DefaultDialogue.Role.AGENT\n\n        BaseDefaultDialogues.__init__(\n            self,\n            self_address=self.context.agent_name,\n            role_from_first_message=role_from_first_message,\n        )\n"
  },
  {
    "path": "packages/fetchai/skills/echo/handlers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the handler for the 'echo' skill.\"\"\"\nfrom typing import cast\n\nfrom aea.protocols.base import Message\nfrom aea.skills.base import Handler\n\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.skills.echo.dialogues import DefaultDialogue, DefaultDialogues\n\n\nclass EchoHandler(Handler):\n    \"\"\"Echo handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = DefaultMessage.protocol_id\n\n    def setup(self) -> None:\n        \"\"\"Set up the handler.\"\"\"\n        self.context.logger.info(\"Echo Handler: setup method called.\")\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Handle the message.\n\n        :param message: the message.\n        \"\"\"\n        default_message = cast(DefaultMessage, message)\n\n        # recover dialogue\n        default_dialogues = cast(DefaultDialogues, self.context.default_dialogues)\n        default_dialogue = cast(DefaultDialogue, default_dialogues.update(message))\n\n        if default_dialogue is None:\n            self._handle_unidentified_dialogue(default_message)\n            return\n\n        # handle message\n        if message.performative == DefaultMessage.Performative.BYTES:\n            self._handle_bytes(default_message, default_dialogue)\n        elif message.performative == DefaultMessage.Performative.ERROR:\n            self._handle_error(default_message, default_dialogue)\n        else:\n            self._handle_invalid(default_message, default_dialogue)\n\n    def teardown(self) -> None:\n        \"\"\"Teardown the handler.\"\"\"\n        self.context.logger.info(\"Echo Handler: teardown method called.\")\n\n    def _handle_unidentified_dialogue(self, message: DefaultMessage) -> None:\n        \"\"\"\n        Handle unidentified dialogue.\n\n        :param message: the message.\n        \"\"\"\n        self.context.logger.info(\n            \"received invalid default message={}, unidentified dialogue.\".format(\n                message\n            )\n        )\n        default_dialogues = cast(DefaultDialogues, self.context.default_dialogues)\n        reply, _ = default_dialogues.create(\n            counterparty=message.sender,\n            performative=DefaultMessage.Performative.ERROR,\n            error_code=DefaultMessage.ErrorCode.INVALID_DIALOGUE,\n            error_msg=\"Invalid dialogue.\",\n            error_data={\"default_message\": message.encode()},\n        )\n        self.context.outbox.put_message(message=reply)\n\n    def _handle_error(self, message: DefaultMessage, dialogue: DefaultDialogue) -> None:\n        \"\"\"\n        Handle a message of error performative.\n\n        :param message: the default message.\n        :param dialogue: the dialogue.\n        \"\"\"\n        self.context.logger.info(\n            \"received default error message={} in dialogue={}.\".format(\n                message, dialogue\n            )\n        )\n\n    def _handle_bytes(self, message: DefaultMessage, dialogue: DefaultDialogue) -> None:\n        \"\"\"\n        Handle a message of bytes performative.\n\n        :param message: the default message.\n        :param dialogue: the default dialogue.\n        \"\"\"\n        self.context.logger.info(\n            \"Echo Handler: message={}, sender={}\".format(message, message.sender)\n        )\n        reply = dialogue.reply(\n            performative=DefaultMessage.Performative.BYTES,\n            target_message=message,\n            content=message.content,\n        )\n        self.context.outbox.put_message(message=reply)\n\n    def _handle_invalid(\n        self, message: DefaultMessage, dialogue: DefaultDialogue\n    ) -> None:\n        \"\"\"\n        Handle an invalid message.\n\n        :param message: the message.\n        :param dialogue: the dialogue.\n        \"\"\"\n        self.context.logger.info(\n            \"received invalid message={} in dialogue={}.\".format(message, dialogue)\n        )\n"
  },
  {
    "path": "packages/fetchai/skills/echo/skill.yaml",
    "content": "name: echo\nauthor: fetchai\nversion: 0.20.6\ntype: skill\ndescription: The echo skill implements simple echo functionality.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: QmNijzN1uUKmcH64VUGCfZBDzAnJjkqjUrnFALVaAceU6i\n  __init__.py: QmNPzngDudTFkW8jKh61U9fPKHKR1m5iPsTAqBbM8X1nqa\n  behaviours.py: QmRAFuVFQr6LkXLU8jMkHksd2YUiTrx2ABSSTZgFrJpFxT\n  dialogues.py: QmeV9E8Qf5cLCjWD3F5MLthpoP5oZwr52RJrAXc4p9ZntY\n  handlers.py: QmPFAH8Ae3wKxZxu2xn2XAftgjg1cv9vaxdFqr3FJAfnTG\nfingerprint_ignore_patterns: []\nconnections: []\ncontracts: []\nprotocols:\n- fetchai/default:1.1.7\nskills: []\nbehaviours:\n  echo:\n    args:\n      tick_interval: 1.0\n    class_name: EchoBehaviour\nhandlers:\n  echo:\n    args: {}\n    class_name: EchoHandler\nmodels:\n  default_dialogues:\n    args: {}\n    class_name: DefaultDialogues\ndependencies: {}\nis_abstract: false\n"
  },
  {
    "path": "packages/fetchai/skills/erc1155_client/README.md",
    "content": "# ERC1155 Client\n\n## Description\n\nThis is a skill for demoing the purchase of data via a smart contract.\n\nThis skill finds an `ERC1155 contract deployment AEA` on the sOEF, requests specific data, negotiates the price, pays the proposed amount via smart contract if agreement is reach, and receives the data bought.\n\n## Behaviours\n\n- `search`: searches for the ERC1155 deployment agent on the sOEF\n\n## Handlers\n\n- `contract_api`: handles `contract_api` messages for interactions with the smart contract\n- `fipa`: handles `fipa` messages for negotiation\n- `ledger_api`: handles `ledger_api` messages for interacting with a ledger\n- `oef_search`: handles `oef_search` messages to manage the sellers found\n- `signing`: handles `signing` messages for transaction signing by the decision maker\n\n## Links\n\n- <a href=\"https://docs.fetch.ai/aea/erc1155-skills/\" target=\"_blank\">Contract Deployment Guide</a>\n"
  },
  {
    "path": "packages/fetchai/skills/erc1155_client/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the implementation of the erc-1155 client skill.\"\"\"\n\nfrom aea.configurations.base import PublicId\n\n\nPUBLIC_ID = PublicId.from_str(\"fetchai/erc1155_client:0.29.6\")\n"
  },
  {
    "path": "packages/fetchai/skills/erc1155_client/behaviours.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains the behaviour for the erc-1155 client skill.\"\"\"\n\nfrom typing import Any, cast\n\nfrom aea.skills.behaviours import TickerBehaviour\n\nfrom packages.fetchai.connections.ledger.base import (\n    CONNECTION_ID as LEDGER_CONNECTION_PUBLIC_ID,\n)\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.skills.erc1155_client.dialogues import (\n    LedgerApiDialogues,\n    OefSearchDialogues,\n)\nfrom packages.fetchai.skills.erc1155_client.strategy import Strategy\n\n\nDEFAULT_SEARCH_INTERVAL = 5.0\nLEDGER_API_ADDRESS = str(LEDGER_CONNECTION_PUBLIC_ID)\n\n\nclass SearchBehaviour(TickerBehaviour):\n    \"\"\"This class implements a search behaviour.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"Initialize the search behaviour.\"\"\"\n        search_interval = cast(\n            float, kwargs.pop(\"search_interval\", DEFAULT_SEARCH_INTERVAL)\n        )\n        super().__init__(tick_interval=search_interval, **kwargs)\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup for the behaviour.\"\"\"\n        strategy = cast(Strategy, self.context.strategy)\n        ledger_api_dialogues = cast(\n            LedgerApiDialogues, self.context.ledger_api_dialogues\n        )\n        ledger_api_msg, _ = ledger_api_dialogues.create(\n            counterparty=LEDGER_API_ADDRESS,\n            performative=LedgerApiMessage.Performative.GET_BALANCE,\n            ledger_id=strategy.ledger_id,\n            address=cast(str, self.context.agent_addresses.get(strategy.ledger_id)),\n        )\n        self.context.outbox.put_message(message=ledger_api_msg)\n\n    def act(self) -> None:\n        \"\"\"Implement the act.\"\"\"\n        strategy = cast(Strategy, self.context.strategy)\n        if strategy.is_searching:\n            query = strategy.get_location_and_service_query()\n            oef_search_dialogues = cast(\n                OefSearchDialogues, self.context.oef_search_dialogues\n            )\n            oef_search_msg, _ = oef_search_dialogues.create(\n                counterparty=self.context.search_service_address,\n                performative=OefSearchMessage.Performative.SEARCH_SERVICES,\n                query=query,\n            )\n            self.context.outbox.put_message(message=oef_search_msg)\n\n    def teardown(self) -> None:\n        \"\"\"Implement the task teardown.\"\"\"\n"
  },
  {
    "path": "packages/fetchai/skills/erc1155_client/dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nThis module contains the classes required for dialogue management.\n\n- Dialogue: The dialogue class maintains state of a dialogue and manages it.\n- Dialogues: The dialogues class keeps track of all dialogues.\n\"\"\"\n\nfrom typing import Any, Optional, Type\n\nfrom aea.common import Address\nfrom aea.exceptions import enforce\nfrom aea.helpers.transaction.base import Terms\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\nfrom aea.protocols.dialogue.base import DialogueLabel as BaseDialogueLabel\nfrom aea.skills.base import Model\n\nfrom packages.fetchai.protocols.contract_api.dialogues import (\n    ContractApiDialogue as BaseContractApiDialogue,\n)\nfrom packages.fetchai.protocols.contract_api.dialogues import (\n    ContractApiDialogues as BaseContractApiDialogues,\n)\nfrom packages.fetchai.protocols.contract_api.message import ContractApiMessage\nfrom packages.fetchai.protocols.default.dialogues import (\n    DefaultDialogue as BaseDefaultDialogue,\n)\nfrom packages.fetchai.protocols.default.dialogues import (\n    DefaultDialogues as BaseDefaultDialogues,\n)\nfrom packages.fetchai.protocols.fipa.dialogues import FipaDialogue as BaseFipaDialogue\nfrom packages.fetchai.protocols.fipa.dialogues import FipaDialogues as BaseFipaDialogues\nfrom packages.fetchai.protocols.ledger_api.dialogues import (\n    LedgerApiDialogue as BaseLedgerApiDialogue,\n)\nfrom packages.fetchai.protocols.ledger_api.dialogues import (\n    LedgerApiDialogues as BaseLedgerApiDialogues,\n)\nfrom packages.fetchai.protocols.oef_search.dialogues import (\n    OefSearchDialogue as BaseOefSearchDialogue,\n)\nfrom packages.fetchai.protocols.oef_search.dialogues import (\n    OefSearchDialogues as BaseOefSearchDialogues,\n)\nfrom packages.fetchai.protocols.signing.dialogues import (\n    SigningDialogue as BaseSigningDialogue,\n)\nfrom packages.fetchai.protocols.signing.dialogues import (\n    SigningDialogues as BaseSigningDialogues,\n)\nfrom packages.fetchai.protocols.signing.message import SigningMessage\n\n\nclass ContractApiDialogue(BaseContractApiDialogue):\n    \"\"\"The dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    __slots__ = (\"_terms\", \"_associated_fipa_dialogue\")\n\n    def __init__(\n        self,\n        dialogue_label: BaseDialogueLabel,\n        self_address: Address,\n        role: BaseDialogue.Role,\n        message_class: Type[ContractApiMessage] = ContractApiMessage,\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n        :param message_class: message class\n        \"\"\"\n        BaseContractApiDialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            self_address=self_address,\n            role=role,\n            message_class=message_class,\n        )\n        self._terms = None  # type: Optional[Terms]\n        self._associated_fipa_dialogue = None  # type: Optional[BaseFipaDialogue]\n\n    @property\n    def terms(self) -> Terms:\n        \"\"\"Get the terms.\"\"\"\n        if self._terms is None:\n            raise ValueError(\"Terms not set!\")\n        return self._terms\n\n    @terms.setter\n    def terms(self, terms: Terms) -> None:\n        \"\"\"Set the terms.\"\"\"\n        enforce(self._terms is None, \"Terms already set!\")\n        self._terms = terms\n\n    @property\n    def associated_fipa_dialogue(self) -> BaseFipaDialogue:\n        \"\"\"Get the associated fipa dialogue.\"\"\"\n        if self._associated_fipa_dialogue is None:\n            raise ValueError(\"Associated fipa dialogue not set!\")\n        return self._associated_fipa_dialogue\n\n    @associated_fipa_dialogue.setter\n    def associated_fipa_dialogue(\n        self, associated_fipa_dialogue: BaseFipaDialogue\n    ) -> None:\n        \"\"\"Set the associated  fipa dialogue.\"\"\"\n        enforce(\n            self._associated_fipa_dialogue is None,\n            \"Associated fipa dialogue already set!\",\n        )\n        self._associated_fipa_dialogue = associated_fipa_dialogue\n\n\nclass ContractApiDialogues(Model, BaseContractApiDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return ContractApiDialogue.Role.AGENT\n\n        BaseContractApiDialogues.__init__(\n            self,\n            self_address=str(self.skill_id),\n            role_from_first_message=role_from_first_message,\n            dialogue_class=ContractApiDialogue,\n        )\n\n\nDefaultDialogue = BaseDefaultDialogue\n\n\nclass DefaultDialogues(Model, BaseDefaultDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return DefaultDialogue.Role.AGENT\n\n        BaseDefaultDialogues.__init__(\n            self,\n            self_address=self.context.agent_address,\n            role_from_first_message=role_from_first_message,\n        )\n\n\nFipaDialogue = BaseFipaDialogue\n\n\nclass FipaDialogues(Model, BaseFipaDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return BaseFipaDialogue.Role.SELLER\n\n        BaseFipaDialogues.__init__(\n            self,\n            self_address=self.context.agent_address,\n            role_from_first_message=role_from_first_message,\n        )\n\n\nLedgerApiDialogue = BaseLedgerApiDialogue\n\n\nclass LedgerApiDialogues(Model, BaseLedgerApiDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return BaseLedgerApiDialogue.Role.AGENT\n\n        BaseLedgerApiDialogues.__init__(\n            self,\n            self_address=str(self.skill_id),\n            role_from_first_message=role_from_first_message,\n        )\n\n\nOefSearchDialogue = BaseOefSearchDialogue\n\n\nclass OefSearchDialogues(Model, BaseOefSearchDialogues):\n    \"\"\"This class keeps track of all oef_search dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return BaseOefSearchDialogue.Role.AGENT\n\n        BaseOefSearchDialogues.__init__(\n            self,\n            self_address=str(self.skill_id),\n            role_from_first_message=role_from_first_message,\n        )\n\n\nclass SigningDialogue(BaseSigningDialogue):\n    \"\"\"The dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    __slots__ = (\"_associated_contract_api_dialogue\",)\n\n    def __init__(\n        self,\n        dialogue_label: BaseDialogueLabel,\n        self_address: Address,\n        role: BaseDialogue.Role,\n        message_class: Type[SigningMessage] = SigningMessage,\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n        :param message_class: message class\n        \"\"\"\n        BaseSigningDialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            self_address=self_address,\n            role=role,\n            message_class=message_class,\n        )\n        self._associated_contract_api_dialogue = (\n            None\n        )  # type: Optional[ContractApiDialogue]\n\n    @property\n    def associated_contract_api_dialogue(self) -> ContractApiDialogue:\n        \"\"\"Get the associated contract api dialogue.\"\"\"\n        if self._associated_contract_api_dialogue is None:\n            raise ValueError(\"Associated contract api dialogue not set!\")\n        return self._associated_contract_api_dialogue\n\n    @associated_contract_api_dialogue.setter\n    def associated_contract_api_dialogue(\n        self, associated_contract_api_dialogue: ContractApiDialogue\n    ) -> None:\n        \"\"\"Set the associated contract api dialogue.\"\"\"\n        enforce(\n            self._associated_contract_api_dialogue is None,\n            \"Associated contract api dialogue already set!\",\n        )\n        self._associated_contract_api_dialogue = associated_contract_api_dialogue\n\n\nclass SigningDialogues(Model, BaseSigningDialogues):\n    \"\"\"This class keeps track of all oef_search dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return BaseSigningDialogue.Role.SKILL\n\n        BaseSigningDialogues.__init__(\n            self,\n            self_address=str(self.skill_id),\n            role_from_first_message=role_from_first_message,\n            dialogue_class=SigningDialogue,\n        )\n"
  },
  {
    "path": "packages/fetchai/skills/erc1155_client/handlers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains handlers for the erc1155-client skill.\"\"\"\n\nfrom typing import Optional, cast\n\nfrom aea.configurations.base import PublicId\nfrom aea.helpers.transaction.base import RawMessage, Terms\nfrom aea.protocols.base import Message\nfrom aea.skills.base import Handler\n\nfrom packages.fetchai.connections.ledger.base import (\n    CONNECTION_ID as LEDGER_CONNECTION_PUBLIC_ID,\n)\nfrom packages.fetchai.protocols.contract_api.message import ContractApiMessage\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.protocols.fipa.message import FipaMessage\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.protocols.signing.message import SigningMessage\nfrom packages.fetchai.skills.erc1155_client.dialogues import (\n    ContractApiDialogue,\n    ContractApiDialogues,\n    DefaultDialogues,\n    FipaDialogue,\n    FipaDialogues,\n    LedgerApiDialogue,\n    LedgerApiDialogues,\n    OefSearchDialogue,\n    OefSearchDialogues,\n    SigningDialogue,\n    SigningDialogues,\n)\nfrom packages.fetchai.skills.erc1155_client.strategy import Strategy\n\n\nLEDGER_API_ADDRESS = str(LEDGER_CONNECTION_PUBLIC_ID)\n\n\nclass FipaHandler(Handler):\n    \"\"\"This class implements a FIPA handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = FipaMessage.protocol_id  # type: Optional[PublicId]\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to a message.\n\n        :param message: the message\n        \"\"\"\n        fipa_msg = cast(FipaMessage, message)\n\n        # recover dialogue\n        fipa_dialogues = cast(FipaDialogues, self.context.fipa_dialogues)\n        fipa_dialogue = cast(FipaDialogue, fipa_dialogues.update(fipa_msg))\n        if fipa_dialogue is None:\n            self._handle_unidentified_dialogue(fipa_msg)\n            return\n\n        # handle message\n        if fipa_msg.performative == FipaMessage.Performative.PROPOSE:\n            self._handle_propose(fipa_msg, fipa_dialogue)\n        else:\n            self._handle_invalid(fipa_msg, fipa_dialogue)\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n\n    def _handle_unidentified_dialogue(self, fipa_msg: FipaMessage) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        Respond to the sender with a default message containing the appropriate error information.\n\n        :param fipa_msg: the message\n        \"\"\"\n        self.context.logger.info(\n            \"unidentified dialogue for message={}.\".format(fipa_msg)\n        )\n        default_dialogues = cast(DefaultDialogues, self.context.default_dialogues)\n        default_msg, _ = default_dialogues.create(\n            counterparty=fipa_msg.sender,\n            performative=DefaultMessage.Performative.ERROR,\n            error_code=DefaultMessage.ErrorCode.INVALID_DIALOGUE,\n            error_msg=\"Invalid dialogue.\",\n            error_data={\"fipa_message\": fipa_msg.encode()},\n        )\n        self.context.outbox.put_message(message=default_msg)\n\n    def _handle_propose(\n        self, fipa_msg: FipaMessage, fipa_dialogue: FipaDialogue\n    ) -> None:\n        \"\"\"\n        Handle the CFP.\n\n        If the CFP matches the supplied services then send a PROPOSE, otherwise send a DECLINE.\n\n        :param fipa_msg: the message\n        :param fipa_dialogue: the dialogue object\n        \"\"\"\n        if all(\n            key\n            in [\n                \"contract_address\",\n                \"from_supply\",\n                \"to_supply\",\n                \"value\",\n                \"trade_nonce\",\n                \"token_id\",\n            ]\n            for key in fipa_msg.proposal.values.keys()\n        ):\n            # accept any proposal with the correct keys\n            self.context.logger.info(\n                \"received valid PROPOSE from sender={}: proposal={}\".format(\n                    fipa_msg.sender[-5:],\n                    fipa_msg.proposal.values,\n                )\n            )\n            strategy = cast(Strategy, self.context.strategy)\n            contract_api_dialogues = cast(\n                ContractApiDialogues, self.context.contract_api_dialogues\n            )\n            contract_api_msg, contract_api_dialogue = contract_api_dialogues.create(\n                counterparty=LEDGER_API_ADDRESS,\n                performative=ContractApiMessage.Performative.GET_RAW_MESSAGE,\n                ledger_id=strategy.ledger_id,\n                contract_id=strategy.contract_id,\n                contract_address=fipa_msg.proposal.values[\"contract_address\"],\n                callable=\"get_hash_single\",\n                kwargs=ContractApiMessage.Kwargs(\n                    {\n                        \"from_address\": fipa_msg.sender,\n                        \"to_address\": self.context.agent_address,\n                        \"token_id\": int(fipa_msg.proposal.values[\"token_id\"]),\n                        \"from_supply\": int(fipa_msg.proposal.values[\"from_supply\"]),\n                        \"to_supply\": int(fipa_msg.proposal.values[\"to_supply\"]),\n                        \"value\": int(fipa_msg.proposal.values[\"value\"]),\n                        \"trade_nonce\": int(fipa_msg.proposal.values[\"trade_nonce\"]),\n                    }\n                ),\n            )\n            terms = Terms(\n                ledger_id=strategy.ledger_id,\n                sender_address=self.context.agent_address,\n                counterparty_address=fipa_msg.sender,\n                amount_by_currency_id={},\n                quantities_by_good_id={\n                    str(fipa_msg.proposal.values[\"token_id\"]): int(\n                        fipa_msg.proposal.values[\"from_supply\"]\n                    )\n                    - int(fipa_msg.proposal.values[\"to_supply\"])\n                },\n                is_sender_payable_tx_fee=False,\n                nonce=str(fipa_msg.proposal.values[\"trade_nonce\"]),\n            )\n            contract_api_dialogue = cast(ContractApiDialogue, contract_api_dialogue)\n            contract_api_dialogue.terms = terms\n            contract_api_dialogue.associated_fipa_dialogue = fipa_dialogue\n            self.context.outbox.put_message(message=contract_api_msg)\n            self.context.logger.info(\n                \"requesting single hash message from contract api...\"\n            )\n        else:\n            self.context.logger.info(\n                \"received invalid PROPOSE from sender={}: proposal={}\".format(\n                    fipa_msg.sender[-5:],\n                    fipa_msg.proposal.values,\n                )\n            )\n\n    def _handle_invalid(\n        self, fipa_msg: FipaMessage, fipa_dialogue: FipaDialogue\n    ) -> None:\n        \"\"\"\n        Handle a fipa message of invalid performative.\n\n        :param fipa_msg: the message\n        :param fipa_dialogue: the dialogue object\n        \"\"\"\n        self.context.logger.warning(\n            \"cannot handle fipa message of performative={} in dialogue={}.\".format(\n                fipa_msg.performative, fipa_dialogue\n            )\n        )\n\n\nclass OefSearchHandler(Handler):\n    \"\"\"This class implements an OEF search handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = OefSearchMessage.protocol_id  # type: Optional[PublicId]\n\n    def setup(self) -> None:\n        \"\"\"Call to setup the handler.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to a message.\n\n        :param message: the message\n        \"\"\"\n        oef_search_msg = cast(OefSearchMessage, message)\n\n        # recover dialogue\n        oef_search_dialogues = cast(\n            OefSearchDialogues, self.context.oef_search_dialogues\n        )\n        oef_search_dialogue = cast(\n            Optional[OefSearchDialogue], oef_search_dialogues.update(oef_search_msg)\n        )\n        if oef_search_dialogue is None:\n            self._handle_unidentified_dialogue(oef_search_msg)\n            return\n\n        # handle message\n        if oef_search_msg.performative is OefSearchMessage.Performative.OEF_ERROR:\n            self._handle_error(oef_search_msg, oef_search_dialogue)\n        elif oef_search_msg.performative is OefSearchMessage.Performative.SEARCH_RESULT:\n            self._handle_search(oef_search_msg, oef_search_dialogue)\n        else:\n            self._handle_invalid(oef_search_msg, oef_search_dialogue)\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n\n    def _handle_unidentified_dialogue(self, oef_search_msg: OefSearchMessage) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param oef_search_msg: the oef search message\n        \"\"\"\n        self.context.logger.info(\n            \"received invalid oef_search message={}, unidentified dialogue.\".format(\n                oef_search_msg\n            )\n        )\n\n    def _handle_error(\n        self, oef_search_msg: OefSearchMessage, oef_search_dialogue: OefSearchDialogue\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param oef_search_msg: the oef search message\n        :param oef_search_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.info(\n            \"received oef_search error message={} in dialogue={}.\".format(\n                oef_search_msg, oef_search_dialogue\n            )\n        )\n\n    def _handle_search(\n        self, oef_search_msg: OefSearchMessage, oef_search_dialogue: OefSearchDialogue\n    ) -> None:\n        \"\"\"\n        Handle the search response.\n\n        :param oef_search_msg: the oef search message\n        :param oef_search_dialogue: the dialogue\n        \"\"\"\n        if len(oef_search_msg.agents) == 0:\n            self.context.logger.info(\n                \"found no agents in dialogue={}, continue searching.\".format(\n                    oef_search_dialogue\n                )\n            )\n            return\n\n        self.context.logger.info(\n            \"found agents={}, stopping search.\".format(\n                list(map(lambda x: x[-5:], oef_search_msg.agents)),\n            )\n        )\n        strategy = cast(Strategy, self.context.strategy)\n        strategy.is_searching = False\n        query = strategy.get_service_query()\n        fipa_dialogues = cast(FipaDialogues, self.context.fipa_dialogues)\n        for opponent_address in oef_search_msg.agents:\n            cfp_msg, _ = fipa_dialogues.create(\n                counterparty=opponent_address,\n                performative=FipaMessage.Performative.CFP,\n                query=query,\n            )\n            self.context.logger.info(\n                \"sending CFP to agent={}\".format(opponent_address[-5:])\n            )\n            self.context.outbox.put_message(message=cfp_msg)\n\n    def _handle_invalid(\n        self, oef_search_msg: OefSearchMessage, oef_search_dialogue: OefSearchDialogue\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param oef_search_msg: the oef search message\n        :param oef_search_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.warning(\n            \"cannot handle oef_search message of performative={} in dialogue={}.\".format(\n                oef_search_msg.performative,\n                oef_search_dialogue,\n            )\n        )\n\n\nclass ContractApiHandler(Handler):\n    \"\"\"Implement the contract api handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = ContractApiMessage.protocol_id  # type: Optional[PublicId]\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup for the handler.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to a message.\n\n        :param message: the message\n        \"\"\"\n        contract_api_msg = cast(ContractApiMessage, message)\n\n        # recover dialogue\n        contract_api_dialogues = cast(\n            ContractApiDialogues, self.context.contract_api_dialogues\n        )\n        contract_api_dialogue = cast(\n            Optional[ContractApiDialogue],\n            contract_api_dialogues.update(contract_api_msg),\n        )\n        if contract_api_dialogue is None:\n            self._handle_unidentified_dialogue(contract_api_msg)\n            return\n\n        # handle message\n        if contract_api_msg.performative is ContractApiMessage.Performative.RAW_MESSAGE:\n            self._handle_raw_message(contract_api_msg, contract_api_dialogue)\n        elif contract_api_msg.performative == ContractApiMessage.Performative.ERROR:\n            self._handle_error(contract_api_msg, contract_api_dialogue)\n        else:\n            self._handle_invalid(contract_api_msg, contract_api_dialogue)\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n\n    def _handle_unidentified_dialogue(\n        self, contract_api_msg: ContractApiMessage\n    ) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param contract_api_msg: the contract api message\n        \"\"\"\n        self.context.logger.info(\n            \"received invalid contract_api message={}, unidentified dialogue.\".format(\n                contract_api_msg\n            )\n        )\n\n    def _handle_raw_message(\n        self,\n        contract_api_msg: ContractApiMessage,\n        contract_api_dialogue: ContractApiDialogue,\n    ) -> None:\n        \"\"\"\n        Handle a message of raw_message performative.\n\n        :param contract_api_msg: the ledger api message\n        :param contract_api_dialogue: the ledger api dialogue\n        \"\"\"\n        self.context.logger.info(\"received raw message={}\".format(contract_api_msg))\n        signing_dialogues = cast(SigningDialogues, self.context.signing_dialogues)\n        signing_msg, signing_dialogue = signing_dialogues.create(\n            counterparty=self.context.decision_maker_address,\n            performative=SigningMessage.Performative.SIGN_MESSAGE,\n            raw_message=RawMessage(\n                contract_api_msg.raw_message.ledger_id,\n                contract_api_msg.raw_message.body,\n                is_deprecated_mode=True,\n            ),\n            terms=contract_api_dialogue.terms,\n        )\n        signing_dialogue = cast(SigningDialogue, signing_dialogue)\n        signing_dialogue.associated_contract_api_dialogue = contract_api_dialogue\n        self.context.decision_maker_message_queue.put_nowait(signing_msg)\n        self.context.logger.info(\n            \"proposing the transaction to the decision maker. Waiting for confirmation ...\"\n        )\n\n    def _handle_error(\n        self,\n        contract_api_msg: ContractApiMessage,\n        contract_api_dialogue: ContractApiDialogue,\n    ) -> None:\n        \"\"\"\n        Handle a message of error performative.\n\n        :param contract_api_msg: the ledger api message\n        :param contract_api_dialogue: the ledger api dialogue\n        \"\"\"\n        self.context.logger.info(\n            \"received contract_api error message={} in dialogue={}.\".format(\n                contract_api_msg, contract_api_dialogue\n            )\n        )\n\n    def _handle_invalid(\n        self,\n        contract_api_msg: ContractApiMessage,\n        contract_api_dialogue: ContractApiDialogue,\n    ) -> None:\n        \"\"\"\n        Handle a message of invalid performative.\n\n        :param contract_api_msg: the ledger api message\n        :param contract_api_dialogue: the ledger api dialogue\n        \"\"\"\n        self.context.logger.warning(\n            \"cannot handle contract_api message of performative={} in dialogue={}.\".format(\n                contract_api_msg.performative,\n                contract_api_dialogue,\n            )\n        )\n\n\nclass SigningHandler(Handler):\n    \"\"\"Implement the transaction handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = SigningMessage.protocol_id  # type: Optional[PublicId]\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup for the handler.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to a message.\n\n        :param message: the message\n        \"\"\"\n        signing_msg = cast(SigningMessage, message)\n\n        # recover dialogue\n        signing_dialogues = cast(SigningDialogues, self.context.signing_dialogues)\n        signing_dialogue = cast(\n            Optional[SigningDialogue], signing_dialogues.update(signing_msg)\n        )\n        if signing_dialogue is None:\n            self._handle_unidentified_dialogue(signing_msg)\n            return\n\n        # handle message\n        if signing_msg.performative is SigningMessage.Performative.SIGNED_MESSAGE:\n            self._handle_signed_message(signing_msg, signing_dialogue)\n        elif signing_msg.performative is SigningMessage.Performative.ERROR:\n            self._handle_error(signing_msg, signing_dialogue)\n        else:\n            self._handle_invalid(signing_msg, signing_dialogue)\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n\n    def _handle_unidentified_dialogue(self, signing_msg: SigningMessage) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param signing_msg: the message\n        \"\"\"\n        self.context.logger.info(\n            \"received invalid signing message={}, unidentified dialogue.\".format(\n                signing_msg\n            )\n        )\n\n    def _handle_signed_message(\n        self, signing_msg: SigningMessage, signing_dialogue: SigningDialogue\n    ) -> None:\n        \"\"\"\n        Handle a signed message.\n\n        :param signing_msg: the signing message\n        :param signing_dialogue: the dialogue\n        \"\"\"\n        fipa_dialogue = (\n            signing_dialogue.associated_contract_api_dialogue.associated_fipa_dialogue\n        )\n        last_fipa_msg = fipa_dialogue.last_incoming_message\n        if last_fipa_msg is None:  # pragma: nocover\n            raise ValueError(\"Could not retrieve last fipa message.\")\n        inform_msg = fipa_dialogue.reply(\n            performative=FipaMessage.Performative.ACCEPT_W_INFORM,\n            target_message=last_fipa_msg,\n            info={\"tx_signature\": signing_msg.signed_message.body},\n        )\n        self.context.logger.info(\n            \"sending ACCEPT_W_INFORM to agent={}: tx_signature={}\".format(\n                last_fipa_msg.sender[-5:],\n                signing_msg.signed_message,\n            )\n        )\n        self.context.outbox.put_message(message=inform_msg)\n\n    def _handle_error(\n        self, signing_msg: SigningMessage, signing_dialogue: SigningDialogue\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param signing_msg: the signing message\n        :param signing_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.info(\n            \"transaction signing was not successful. Error_code={} in dialogue={}\".format(\n                signing_msg.error_code, signing_dialogue\n            )\n        )\n\n    def _handle_invalid(\n        self, signing_msg: SigningMessage, signing_dialogue: SigningDialogue\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param signing_msg: the signing message\n        :param signing_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.warning(\n            \"cannot handle signing message of performative={} in dialogue={}.\".format(\n                signing_msg.performative, signing_dialogue\n            )\n        )\n\n\nclass LedgerApiHandler(Handler):\n    \"\"\"Implement the ledger api handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = LedgerApiMessage.protocol_id  # type: Optional[PublicId]\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup for the handler.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to a message.\n\n        :param message: the message\n        \"\"\"\n        ledger_api_msg = cast(LedgerApiMessage, message)\n\n        # recover dialogue\n        ledger_api_dialogues = cast(\n            LedgerApiDialogues, self.context.ledger_api_dialogues\n        )\n        ledger_api_dialogue = cast(\n            Optional[LedgerApiDialogue], ledger_api_dialogues.update(ledger_api_msg)\n        )\n        if ledger_api_dialogue is None:\n            self._handle_unidentified_dialogue(ledger_api_msg)\n            return\n\n        # handle message\n        if ledger_api_msg.performative is LedgerApiMessage.Performative.BALANCE:\n            self._handle_balance(ledger_api_msg)\n        elif ledger_api_msg.performative == LedgerApiMessage.Performative.ERROR:\n            self._handle_error(ledger_api_msg, ledger_api_dialogue)\n        else:\n            self._handle_invalid(ledger_api_msg, ledger_api_dialogue)\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n\n    def _handle_unidentified_dialogue(self, ledger_api_msg: LedgerApiMessage) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param ledger_api_msg: the ledger api message\n        \"\"\"\n        self.context.logger.info(\n            \"received invalid ledger_api message={}, unidentified dialogue.\".format(\n                ledger_api_msg\n            )\n        )\n\n    def _handle_balance(self, ledger_api_msg: LedgerApiMessage) -> None:\n        \"\"\"\n        Handle a message of balance performative.\n\n        :param ledger_api_msg: the ledger api message\n        \"\"\"\n        self.context.logger.info(\n            \"starting balance on {} ledger={}.\".format(\n                ledger_api_msg.ledger_id,\n                ledger_api_msg.balance,\n            )\n        )\n\n    def _handle_error(\n        self, ledger_api_msg: LedgerApiMessage, ledger_api_dialogue: LedgerApiDialogue\n    ) -> None:\n        \"\"\"\n        Handle a message of error performative.\n\n        :param ledger_api_msg: the ledger api message\n        :param ledger_api_dialogue: the ledger api dialogue\n        \"\"\"\n        self.context.logger.info(\n            \"received ledger_api error message={} in dialogue={}.\".format(\n                ledger_api_msg, ledger_api_dialogue\n            )\n        )\n\n    def _handle_invalid(\n        self, ledger_api_msg: LedgerApiMessage, ledger_api_dialogue: LedgerApiDialogue\n    ) -> None:\n        \"\"\"\n        Handle a message of invalid performative.\n\n        :param ledger_api_msg: the ledger api message\n        :param ledger_api_dialogue: the ledger api dialogue\n        \"\"\"\n        self.context.logger.warning(\n            \"cannot handle ledger_api message of performative={} in dialogue={}.\".format(\n                ledger_api_msg.performative,\n                ledger_api_dialogue,\n            )\n        )\n"
  },
  {
    "path": "packages/fetchai/skills/erc1155_client/skill.yaml",
    "content": "name: erc1155_client\nauthor: fetchai\nversion: 0.29.6\ntype: skill\ndescription: The erc1155 client interacts with the erc1155 deployer to conduct an\n  atomic swap.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: QmYpkQVUiWY7aWc8xN8FMzxKWSawHs2cyjWijzK6PDbsLX\n  __init__.py: QmXJGNqfPNrhiwQoZZySRPGbP8dPgKnyQ3ZvRhrK11e3Ve\n  behaviours.py: QmQohMmSi8PYAeyjGcusSaMbEAeSsVXGcVtS5XZjLgdPg1\n  dialogues.py: QmVFyavVzUv88AZGD8Wca4yyV4y9DU3Akw5M4RFxqnAnUm\n  handlers.py: QmcxgzUjJyGUH5idHEfD8dn5mScTEzzMRoUhQ7ExwFQHud\n  strategy.py: QmWtHkAyvkYZdHNZoc6r12cfJfruT1S9GXydeH9qUFDN7X\nfingerprint_ignore_patterns: []\nconnections:\n- fetchai/ledger:0.21.5\ncontracts:\n- fetchai/erc1155:0.23.3\nprotocols:\n- fetchai/contract_api:1.1.7\n- fetchai/default:1.1.7\n- fetchai/fipa:1.1.7\n- fetchai/ledger_api:1.1.7\n- fetchai/oef_search:1.1.7\n- fetchai/signing:1.1.7\nskills: []\nbehaviours:\n  search:\n    args:\n      search_interval: 5\n    class_name: SearchBehaviour\nhandlers:\n  contract_api:\n    args: {}\n    class_name: ContractApiHandler\n  fipa:\n    args: {}\n    class_name: FipaHandler\n  ledger_api:\n    args: {}\n    class_name: LedgerApiHandler\n  oef_search:\n    args: {}\n    class_name: OefSearchHandler\n  signing:\n    args: {}\n    class_name: SigningHandler\nmodels:\n  contract_api_dialogues:\n    args: {}\n    class_name: ContractApiDialogues\n  default_dialogues:\n    args: {}\n    class_name: DefaultDialogues\n  fipa_dialogues:\n    args: {}\n    class_name: FipaDialogues\n  ledger_api_dialogues:\n    args: {}\n    class_name: LedgerApiDialogues\n  oef_search_dialogues:\n    args: {}\n    class_name: OefSearchDialogues\n  signing_dialogues:\n    args: {}\n    class_name: SigningDialogues\n  strategy:\n    args:\n      location:\n        latitude: 51.5194\n        longitude: 0.127\n      search_query:\n        constraint_type: ==\n        search_key: seller_service\n        search_value: erc1155_contract\n      search_radius: 5.0\n    class_name: Strategy\ndependencies: {}\nis_abstract: false\n"
  },
  {
    "path": "packages/fetchai/skills/erc1155_client/strategy.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the strategy class.\"\"\"\n\nfrom typing import Any\n\nfrom aea.helpers.search.generic import SIMPLE_SERVICE_MODEL\nfrom aea.helpers.search.models import Constraint, ConstraintType, Location, Query\nfrom aea.skills.base import Model\n\nfrom packages.fetchai.contracts.erc1155.contract import PUBLIC_ID as CONTRACT_ID\n\n\nDEFAULT_LOCATION = {\"longitude\": 0.1270, \"latitude\": 51.5194}\nDEFAULT_SEARCH_QUERY = {\n    \"search_key\": \"seller_service\",\n    \"search_value\": \"erc1155_contract\",\n    \"constraint_type\": \"==\",\n}\nDEFAULT_SEARCH_RADIUS = 5.0\n\n\nclass Strategy(Model):\n    \"\"\"This class defines a strategy for the agent.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize the strategy of the agent.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        self._search_query = kwargs.pop(\"search_query\", DEFAULT_SEARCH_QUERY)\n        location = kwargs.pop(\"location\", DEFAULT_LOCATION)\n        self._agent_location = Location(\n            latitude=location[\"latitude\"], longitude=location[\"longitude\"]\n        )\n        self._radius = kwargs.pop(\"search_radius\", DEFAULT_SEARCH_RADIUS)\n\n        ledger_id = kwargs.pop(\"ledger_id\", None)\n        super().__init__(**kwargs)\n        self._ledger_id = (\n            ledger_id if ledger_id is not None else self.context.default_ledger_id\n        )\n        self.is_searching = True\n        self._contract_id = str(CONTRACT_ID)\n\n    @property\n    def ledger_id(self) -> str:\n        \"\"\"Get the ledger id.\"\"\"\n        return self._ledger_id\n\n    @property\n    def contract_id(self) -> str:\n        \"\"\"Get the contract id.\"\"\"\n        return self._contract_id\n\n    def get_location_and_service_query(self) -> Query:\n        \"\"\"\n        Get the location and service query of the agent.\n\n        :return: the query\n        \"\"\"\n        close_to_my_service = Constraint(\n            \"location\", ConstraintType(\"distance\", (self._agent_location, self._radius))\n        )\n        service_key_filter = Constraint(\n            self._search_query[\"search_key\"],\n            ConstraintType(\n                self._search_query[\"constraint_type\"],\n                self._search_query[\"search_value\"],\n            ),\n        )\n        query = Query(\n            [close_to_my_service, service_key_filter],\n        )\n        return query\n\n    def get_service_query(self) -> Query:\n        \"\"\"\n        Get the service query of the agent.\n\n        :return: the query\n        \"\"\"\n        service_key_filter = Constraint(\n            self._search_query[\"search_key\"],\n            ConstraintType(\n                self._search_query[\"constraint_type\"],\n                self._search_query[\"search_value\"],\n            ),\n        )\n        query = Query([service_key_filter], model=SIMPLE_SERVICE_MODEL)\n        return query\n"
  },
  {
    "path": "packages/fetchai/skills/erc1155_deploy/README.md",
    "content": "# ERC1155 Deploy\n\n## Description\n\nThis is a skill for selling data via a smart contract.\n\nThis skill registers some data selling service on the sOEF. It can be requested (for example by an agent with the `generic_buyer` skill) to provide specific data. It then negotiates the price and delivers the data after it receives payment.\n\n## Behaviours\n\n- `service_registration`: Deploys the smart contract, creates and mints tokens, registers `ERC1155 data selling service` on the sOEF\n\n## Handlers\n\n- `contract_api`: handles `contract_api` messages for interactions with the smart contract\n- `fipa`: handles `fipa` messages for negotiation\n- `ledger_api`: handles `ledger_api` messages for interacting with a ledger.\n- `oef_search`: handles `oef_search` messages if service registration on the sOEF is unsuccessful\n- `signing`: handles `signing` messages for transaction signing by the decision maker\n\n## Links\n\n- <a href=\"https://docs.fetch.ai/aea/erc1155-skills/\" target=\"_blank\">Contract Deployment Guide</a>\n"
  },
  {
    "path": "packages/fetchai/skills/erc1155_deploy/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the implementation of the erc1155 deploy skill.\"\"\"\n\nfrom aea.configurations.base import PublicId\n\n\nPUBLIC_ID = PublicId.from_str(\"fetchai/erc1155_deploy:0.31.6\")\n"
  },
  {
    "path": "packages/fetchai/skills/erc1155_deploy/behaviours.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains the behaviour of a erc1155 deploy skill AEA.\"\"\"\n\nfrom typing import Any, Optional, cast\n\nfrom aea.helpers.search.models import Description\nfrom aea.skills.behaviours import TickerBehaviour\n\nfrom packages.fetchai.connections.ledger.base import (\n    CONNECTION_ID as LEDGER_CONNECTION_PUBLIC_ID,\n)\nfrom packages.fetchai.protocols.contract_api.message import ContractApiMessage\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.skills.erc1155_deploy.dialogues import (\n    ContractApiDialogue,\n    ContractApiDialogues,\n    LedgerApiDialogues,\n    OefSearchDialogues,\n)\nfrom packages.fetchai.skills.erc1155_deploy.strategy import Strategy\n\n\nDEFAULT_SERVICES_INTERVAL = 30.0\nDEFAULT_MAX_SOEF_REGISTRATION_RETRIES = 5\nLEDGER_API_ADDRESS = str(LEDGER_CONNECTION_PUBLIC_ID)\n\n\nclass ServiceRegistrationBehaviour(TickerBehaviour):\n    \"\"\"This class implements a behaviour.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"Initialise the behaviour.\"\"\"\n        services_interval = kwargs.pop(\n            \"services_interval\", DEFAULT_SERVICES_INTERVAL\n        )  # type: int\n        self._max_soef_registration_retries = kwargs.pop(\n            \"max_soef_registration_retries\", DEFAULT_MAX_SOEF_REGISTRATION_RETRIES\n        )  # type: int\n        super().__init__(tick_interval=services_interval, **kwargs)\n        self.is_registered = False\n        self.registration_in_progress = False\n        self.failed_registration_msg = None  # type: Optional[OefSearchMessage]\n        self._nb_retries = 0\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup.\"\"\"\n        self._request_balance()\n        strategy = cast(Strategy, self.context.strategy)\n        if not strategy.is_contract_deployed:\n            self._request_contract_deploy_transaction()\n\n    def act(self) -> None:\n        \"\"\"Implement the act.\"\"\"\n        self._retry_failed_registration()\n\n        strategy = cast(Strategy, self.context.strategy)\n        if not strategy.is_behaviour_active:\n            return\n\n        if strategy.is_contract_deployed and not strategy.is_tokens_created:\n            self._request_token_create_transaction()\n        elif (\n            strategy.is_contract_deployed\n            and strategy.is_tokens_created\n            and not strategy.is_tokens_minted\n        ):\n            self._request_token_mint_transaction()\n        elif (\n            strategy.is_contract_deployed\n            and strategy.is_tokens_created\n            and strategy.is_tokens_minted\n            and not self.registration_in_progress\n            and not self.is_registered\n        ):\n            self.registration_in_progress = True\n            self._register_agent()\n\n    def teardown(self) -> None:\n        \"\"\"Implement the task teardown.\"\"\"\n        self._unregister_service()\n        self._unregister_agent()\n\n    def _retry_failed_registration(self) -> None:\n        \"\"\"Retry a failed registration.\"\"\"\n        if self.failed_registration_msg is not None:\n            self._nb_retries += 1\n            if self._nb_retries > self._max_soef_registration_retries:\n                self.context.is_active = False\n                return\n\n            oef_search_dialogues = cast(\n                OefSearchDialogues, self.context.oef_search_dialogues\n            )\n            oef_search_msg, _ = oef_search_dialogues.create(\n                counterparty=self.failed_registration_msg.to,\n                performative=self.failed_registration_msg.performative,\n                service_description=self.failed_registration_msg.service_description,\n            )\n            self.context.outbox.put_message(message=oef_search_msg)\n            self.context.logger.info(\n                f\"Retrying registration on SOEF. Retry {self._nb_retries} out of {self._max_soef_registration_retries}.\"\n            )\n\n            self.failed_registration_msg = None\n\n    def _request_balance(self) -> None:\n        \"\"\"Request ledger balance.\"\"\"\n        strategy = cast(Strategy, self.context.strategy)\n        ledger_api_dialogues = cast(\n            LedgerApiDialogues, self.context.ledger_api_dialogues\n        )\n        ledger_api_msg, _ = ledger_api_dialogues.create(\n            counterparty=LEDGER_API_ADDRESS,\n            performative=LedgerApiMessage.Performative.GET_BALANCE,\n            ledger_id=strategy.ledger_id,\n            address=cast(str, self.context.agent_addresses.get(strategy.ledger_id)),\n        )\n        self.context.outbox.put_message(message=ledger_api_msg)\n\n    def _request_contract_deploy_transaction(self) -> None:\n        \"\"\"Request contract deploy transaction\"\"\"\n        strategy = cast(Strategy, self.context.strategy)\n        strategy.is_behaviour_active = False\n        contract_api_dialogues = cast(\n            ContractApiDialogues, self.context.contract_api_dialogues\n        )\n        contract_api_msg, contract_api_dialogue = contract_api_dialogues.create(\n            counterparty=LEDGER_API_ADDRESS,\n            performative=ContractApiMessage.Performative.GET_DEPLOY_TRANSACTION,\n            ledger_id=strategy.ledger_id,\n            contract_id=strategy.contract_id,\n            callable=\"get_deploy_transaction\",\n            kwargs=ContractApiMessage.Kwargs(\n                {\"deployer_address\": self.context.agent_address, \"gas\": strategy.gas}\n            ),\n        )\n        contract_api_dialogue = cast(\n            ContractApiDialogue,\n            contract_api_dialogue,\n        )\n        contract_api_dialogue.terms = strategy.get_deploy_terms()\n        self.context.outbox.put_message(message=contract_api_msg)\n        self.context.logger.info(\"requesting contract deployment transaction...\")\n\n    def _request_token_create_transaction(self) -> None:\n        \"\"\"Request token create transaction.\"\"\"\n        strategy = cast(Strategy, self.context.strategy)\n        strategy.is_behaviour_active = False\n        contract_api_dialogues = cast(\n            ContractApiDialogues, self.context.contract_api_dialogues\n        )\n        contract_api_msg, contract_api_dialogue = contract_api_dialogues.create(\n            counterparty=LEDGER_API_ADDRESS,\n            performative=ContractApiMessage.Performative.GET_RAW_TRANSACTION,\n            ledger_id=strategy.ledger_id,\n            contract_id=strategy.contract_id,\n            contract_address=strategy.contract_address,\n            callable=\"get_create_batch_transaction\",\n            kwargs=ContractApiMessage.Kwargs(\n                {\n                    \"deployer_address\": self.context.agent_address,\n                    \"token_ids\": strategy.token_ids,\n                    \"gas\": strategy.gas,\n                }\n            ),\n        )\n        contract_api_dialogue = cast(ContractApiDialogue, contract_api_dialogue)\n        contract_api_dialogue.terms = strategy.get_create_token_terms()\n        self.context.outbox.put_message(message=contract_api_msg)\n        self.context.logger.info(\"requesting create batch transaction...\")\n\n    def _request_token_mint_transaction(self) -> None:\n        \"\"\"Request token mint transaction.\"\"\"\n        strategy = cast(Strategy, self.context.strategy)\n        strategy.is_behaviour_active = False\n        contract_api_dialogues = cast(\n            ContractApiDialogues, self.context.contract_api_dialogues\n        )\n        contract_api_msg, contract_api_dialogue = contract_api_dialogues.create(\n            counterparty=LEDGER_API_ADDRESS,\n            performative=ContractApiMessage.Performative.GET_RAW_TRANSACTION,\n            ledger_id=strategy.ledger_id,\n            contract_id=strategy.contract_id,\n            contract_address=strategy.contract_address,\n            callable=\"get_mint_batch_transaction\",\n            kwargs=ContractApiMessage.Kwargs(\n                {\n                    \"deployer_address\": self.context.agent_address,\n                    \"recipient_address\": self.context.agent_address,\n                    \"token_ids\": strategy.token_ids,\n                    \"mint_quantities\": strategy.mint_quantities,\n                    \"gas\": strategy.gas,\n                }\n            ),\n        )\n        contract_api_dialogue = cast(ContractApiDialogue, contract_api_dialogue)\n        contract_api_dialogue.terms = strategy.get_mint_token_terms()\n        self.context.outbox.put_message(message=contract_api_msg)\n        self.context.logger.info(\"requesting mint batch transaction...\")\n\n    def _register(self, description: Description, logger_msg: str) -> None:\n        \"\"\"\n        Register something on the SOEF.\n\n        :param description: the description of what is being registered\n        :param logger_msg: the logger message to print after the registration\n        \"\"\"\n        oef_search_dialogues = cast(\n            OefSearchDialogues, self.context.oef_search_dialogues\n        )\n        oef_search_msg, _ = oef_search_dialogues.create(\n            counterparty=self.context.search_service_address,\n            performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n            service_description=description,\n        )\n        self.context.outbox.put_message(message=oef_search_msg)\n        self.context.logger.info(logger_msg)\n\n    def _register_agent(self) -> None:\n        \"\"\"Register the agent's location.\"\"\"\n        strategy = cast(Strategy, self.context.strategy)\n        description = strategy.get_location_description()\n        self._register(description, \"registering agent on SOEF.\")\n\n    def register_service(self) -> None:\n        \"\"\"Register the agent's service.\"\"\"\n        strategy = cast(Strategy, self.context.strategy)\n        description = strategy.get_register_service_description()\n        self._register(description, \"registering agent's service on the SOEF.\")\n\n    def register_genus(self) -> None:\n        \"\"\"Register the agent's personality genus.\"\"\"\n        strategy = cast(Strategy, self.context.strategy)\n        description = strategy.get_register_personality_description()\n        self._register(\n            description, \"registering agent's personality genus on the SOEF.\"\n        )\n\n    def register_classification(self) -> None:\n        \"\"\"Register the agent's personality classification.\"\"\"\n        strategy = cast(Strategy, self.context.strategy)\n        description = strategy.get_register_classification_description()\n        self._register(\n            description, \"registering agent's personality classification on the SOEF.\"\n        )\n\n    def _unregister_service(self) -> None:\n        \"\"\"Unregister service from the SOEF.\"\"\"\n        strategy = cast(Strategy, self.context.strategy)\n        description = strategy.get_unregister_service_description()\n        oef_search_dialogues = cast(\n            OefSearchDialogues, self.context.oef_search_dialogues\n        )\n        oef_search_msg, _ = oef_search_dialogues.create(\n            counterparty=self.context.search_service_address,\n            performative=OefSearchMessage.Performative.UNREGISTER_SERVICE,\n            service_description=description,\n        )\n        self.context.outbox.put_message(message=oef_search_msg)\n        self.context.logger.info(\"unregistering service from SOEF.\")\n\n    def _unregister_agent(self) -> None:\n        \"\"\"Unregister agent from the SOEF.\"\"\"\n        strategy = cast(Strategy, self.context.strategy)\n        description = strategy.get_location_description()\n        oef_search_dialogues = cast(\n            OefSearchDialogues, self.context.oef_search_dialogues\n        )\n        oef_search_msg, _ = oef_search_dialogues.create(\n            counterparty=self.context.search_service_address,\n            performative=OefSearchMessage.Performative.UNREGISTER_SERVICE,\n            service_description=description,\n        )\n        self.context.outbox.put_message(message=oef_search_msg)\n        self.context.logger.info(\"unregistering agent from SOEF.\")\n"
  },
  {
    "path": "packages/fetchai/skills/erc1155_deploy/dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nThis module contains the classes required for dialogue management.\n\n- Dialogue: The dialogue class maintains state of a dialogue and manages it.\n- Dialogues: The dialogues class keeps track of all dialogues.\n\"\"\"\n\nfrom typing import Any, Optional, Type\n\nfrom aea.common import Address\nfrom aea.exceptions import enforce\nfrom aea.helpers.search.models import Description\nfrom aea.helpers.transaction.base import Terms\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\nfrom aea.protocols.dialogue.base import DialogueLabel as BaseDialogueLabel\nfrom aea.skills.base import Model\n\nfrom packages.fetchai.protocols.contract_api.dialogues import (\n    ContractApiDialogue as BaseContractApiDialogue,\n)\nfrom packages.fetchai.protocols.contract_api.dialogues import (\n    ContractApiDialogues as BaseContractApiDialogues,\n)\nfrom packages.fetchai.protocols.contract_api.message import ContractApiMessage\nfrom packages.fetchai.protocols.default.dialogues import (\n    DefaultDialogue as BaseDefaultDialogue,\n)\nfrom packages.fetchai.protocols.default.dialogues import (\n    DefaultDialogues as BaseDefaultDialogues,\n)\nfrom packages.fetchai.protocols.fipa.dialogues import FipaDialogue as BaseFipaDialogue\nfrom packages.fetchai.protocols.fipa.dialogues import FipaDialogues as BaseFipaDialogues\nfrom packages.fetchai.protocols.fipa.message import FipaMessage\nfrom packages.fetchai.protocols.ledger_api.dialogues import (\n    LedgerApiDialogue as BaseLedgerApiDialogue,\n)\nfrom packages.fetchai.protocols.ledger_api.dialogues import (\n    LedgerApiDialogues as BaseLedgerApiDialogues,\n)\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\nfrom packages.fetchai.protocols.oef_search.dialogues import (\n    OefSearchDialogue as BaseOefSearchDialogue,\n)\nfrom packages.fetchai.protocols.oef_search.dialogues import (\n    OefSearchDialogues as BaseOefSearchDialogues,\n)\nfrom packages.fetchai.protocols.signing.dialogues import (\n    SigningDialogue as BaseSigningDialogue,\n)\nfrom packages.fetchai.protocols.signing.dialogues import (\n    SigningDialogues as BaseSigningDialogues,\n)\nfrom packages.fetchai.protocols.signing.message import SigningMessage\n\n\nclass ContractApiDialogue(BaseContractApiDialogue):\n    \"\"\"The dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    __slots__ = (\"_terms\",)\n\n    def __init__(\n        self,\n        dialogue_label: BaseDialogueLabel,\n        self_address: Address,\n        role: BaseDialogue.Role,\n        message_class: Type[ContractApiMessage] = ContractApiMessage,\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n        :param message_class: the message class\n        \"\"\"\n        BaseContractApiDialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            self_address=self_address,\n            role=role,\n            message_class=message_class,\n        )\n        self._terms = None  # type: Optional[Terms]\n\n    @property\n    def terms(self) -> Terms:\n        \"\"\"Get the terms.\"\"\"\n        if self._terms is None:\n            raise ValueError(\"Terms not set!\")\n        return self._terms\n\n    @terms.setter\n    def terms(self, terms: Terms) -> None:\n        \"\"\"Set the terms.\"\"\"\n        enforce(self._terms is None, \"Terms already set!\")\n        self._terms = terms\n\n\nclass ContractApiDialogues(Model, BaseContractApiDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return ContractApiDialogue.Role.AGENT\n\n        BaseContractApiDialogues.__init__(\n            self,\n            self_address=str(self.skill_id),\n            role_from_first_message=role_from_first_message,\n            dialogue_class=ContractApiDialogue,\n        )\n\n\nDefaultDialogue = BaseDefaultDialogue\n\n\nclass DefaultDialogues(Model, BaseDefaultDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return DefaultDialogue.Role.AGENT\n\n        BaseDefaultDialogues.__init__(\n            self,\n            self_address=self.context.agent_address,\n            role_from_first_message=role_from_first_message,\n        )\n\n\nclass FipaDialogue(BaseFipaDialogue):\n    \"\"\"The dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    __slots__ = (\"_proposal\",)\n\n    def __init__(\n        self,\n        dialogue_label: BaseDialogueLabel,\n        self_address: Address,\n        role: BaseDialogue.Role,\n        message_class: Type[FipaMessage] = FipaMessage,\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n        :param message_class: the message class\n        \"\"\"\n        BaseFipaDialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            self_address=self_address,\n            role=role,\n            message_class=message_class,\n        )\n        self._proposal = None  # type: Optional[Description]\n\n    @property\n    def proposal(self) -> Description:\n        \"\"\"Get the proposal.\"\"\"\n        if self._proposal is None:\n            raise ValueError(\"Proposal not set!\")\n        return self._proposal\n\n    @proposal.setter\n    def proposal(self, proposal: Description) -> None:\n        \"\"\"Set the proposal.\"\"\"\n        enforce(self._proposal is None, \"Proposal already set!\")\n        self._proposal = proposal\n\n\nclass FipaDialogues(Model, BaseFipaDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return BaseFipaDialogue.Role.SELLER\n\n        BaseFipaDialogues.__init__(\n            self,\n            self_address=self.context.agent_address,\n            role_from_first_message=role_from_first_message,\n            dialogue_class=FipaDialogue,\n        )\n\n\nclass LedgerApiDialogue(BaseLedgerApiDialogue):\n    \"\"\"The dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    __slots__ = (\"_associated_signing_dialogue\",)\n\n    def __init__(\n        self,\n        dialogue_label: BaseDialogueLabel,\n        self_address: Address,\n        role: BaseDialogue.Role,\n        message_class: Type[LedgerApiMessage] = LedgerApiMessage,\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n        :param message_class: the message class\n        \"\"\"\n        BaseLedgerApiDialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            self_address=self_address,\n            role=role,\n            message_class=message_class,\n        )\n        self._associated_signing_dialogue = None  # type: Optional[SigningDialogue]\n\n    @property\n    def associated_signing_dialogue(self) -> \"SigningDialogue\":\n        \"\"\"Get the associated signing dialogue.\"\"\"\n        if self._associated_signing_dialogue is None:\n            raise ValueError(\"Associated signing dialogue not set!\")\n        return self._associated_signing_dialogue\n\n    @associated_signing_dialogue.setter\n    def associated_signing_dialogue(\n        self, associated_signing_dialogue: \"SigningDialogue\"\n    ) -> None:\n        \"\"\"Set the associated signing dialogue.\"\"\"\n        enforce(\n            self._associated_signing_dialogue is None,\n            \"Associated signing dialogue already set!\",\n        )\n        self._associated_signing_dialogue = associated_signing_dialogue\n\n\nclass LedgerApiDialogues(Model, BaseLedgerApiDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return BaseLedgerApiDialogue.Role.AGENT\n\n        BaseLedgerApiDialogues.__init__(\n            self,\n            self_address=str(self.skill_id),\n            role_from_first_message=role_from_first_message,\n            dialogue_class=LedgerApiDialogue,\n        )\n\n\nOefSearchDialogue = BaseOefSearchDialogue\n\n\nclass OefSearchDialogues(Model, BaseOefSearchDialogues):\n    \"\"\"This class keeps track of all oef_search dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return BaseOefSearchDialogue.Role.AGENT\n\n        BaseOefSearchDialogues.__init__(\n            self,\n            self_address=str(self.skill_id),\n            role_from_first_message=role_from_first_message,\n        )\n\n\nclass SigningDialogue(BaseSigningDialogue):\n    \"\"\"The dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    __slots__ = (\"_associated_contract_api_dialogue\",)\n\n    def __init__(\n        self,\n        dialogue_label: BaseDialogueLabel,\n        self_address: Address,\n        role: BaseDialogue.Role,\n        message_class: Type[SigningMessage] = SigningMessage,\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n        :param message_class: the message class\n        \"\"\"\n        BaseSigningDialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            self_address=self_address,\n            role=role,\n            message_class=message_class,\n        )\n        self._associated_contract_api_dialogue = (\n            None\n        )  # type: Optional[ContractApiDialogue]\n\n    @property\n    def associated_contract_api_dialogue(self) -> ContractApiDialogue:\n        \"\"\"Get the associated contract api dialogue.\"\"\"\n        if self._associated_contract_api_dialogue is None:\n            raise ValueError(\"Associated contract api dialogue not set!\")\n        return self._associated_contract_api_dialogue\n\n    @associated_contract_api_dialogue.setter\n    def associated_contract_api_dialogue(\n        self, associated_contract_api_dialogue: ContractApiDialogue\n    ) -> None:\n        \"\"\"Set the associated contract api dialogue.\"\"\"\n        enforce(\n            self._associated_contract_api_dialogue is None,\n            \"Associated contract api dialogue already set!\",\n        )\n        self._associated_contract_api_dialogue = associated_contract_api_dialogue\n\n\nclass SigningDialogues(Model, BaseSigningDialogues):\n    \"\"\"This class keeps track of all oef_search dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return BaseSigningDialogue.Role.SKILL\n\n        BaseSigningDialogues.__init__(\n            self,\n            self_address=str(self.skill_id),\n            role_from_first_message=role_from_first_message,\n            dialogue_class=SigningDialogue,\n        )\n"
  },
  {
    "path": "packages/fetchai/skills/erc1155_deploy/handlers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains the handlers of the erc1155 deploy skill AEA.\"\"\"\n\nfrom typing import Optional, cast\n\nfrom aea.configurations.base import PublicId\nfrom aea.crypto.ledger_apis import LedgerApis\nfrom aea.protocols.base import Message\nfrom aea.skills.base import Handler\n\nfrom packages.fetchai.connections.ledger.base import (\n    CONNECTION_ID as LEDGER_CONNECTION_PUBLIC_ID,\n)\nfrom packages.fetchai.protocols.contract_api.message import ContractApiMessage\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.protocols.fipa.message import FipaMessage\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.protocols.signing.message import SigningMessage\nfrom packages.fetchai.skills.erc1155_deploy.behaviours import (\n    ServiceRegistrationBehaviour,\n)\nfrom packages.fetchai.skills.erc1155_deploy.dialogues import (\n    ContractApiDialogue,\n    ContractApiDialogues,\n    DefaultDialogues,\n    FipaDialogue,\n    FipaDialogues,\n    LedgerApiDialogue,\n    LedgerApiDialogues,\n    OefSearchDialogue,\n    OefSearchDialogues,\n    SigningDialogue,\n    SigningDialogues,\n)\nfrom packages.fetchai.skills.erc1155_deploy.strategy import Strategy\n\n\nLEDGER_API_ADDRESS = str(LEDGER_CONNECTION_PUBLIC_ID)\n\n\nclass FipaHandler(Handler):\n    \"\"\"This class implements a FIPA handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = FipaMessage.protocol_id  # type: Optional[PublicId]\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup for the handler.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to a message.\n\n        :param message: the message\n        \"\"\"\n        fipa_msg = cast(FipaMessage, message)\n\n        # recover dialogue\n        fipa_dialogues = cast(FipaDialogues, self.context.fipa_dialogues)\n        fipa_dialogue = cast(FipaDialogue, fipa_dialogues.update(fipa_msg))\n        if fipa_dialogue is None:\n            self._handle_unidentified_dialogue(fipa_msg)\n            return\n\n        if fipa_msg.performative == FipaMessage.Performative.CFP:\n            self._handle_cfp(fipa_msg, fipa_dialogue)\n        elif fipa_msg.performative == FipaMessage.Performative.ACCEPT_W_INFORM:\n            self._handle_accept_w_inform(fipa_msg, fipa_dialogue)\n        else:\n            self._handle_invalid(fipa_msg, fipa_dialogue)\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n\n    def _handle_unidentified_dialogue(self, fipa_msg: FipaMessage) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        Respond to the sender with a default message containing the appropriate error information.\n\n        :param fipa_msg: the message\n        \"\"\"\n        self.context.logger.info(\n            \"unidentified dialogue for message={}.\".format(fipa_msg)\n        )\n        default_dialogues = cast(DefaultDialogues, self.context.default_dialogues)\n        default_msg, _ = default_dialogues.create(\n            counterparty=fipa_msg.sender,\n            performative=DefaultMessage.Performative.ERROR,\n            error_code=DefaultMessage.ErrorCode.INVALID_DIALOGUE,\n            error_msg=\"Invalid dialogue.\",\n            error_data={\"fipa_message\": fipa_msg.encode()},\n        )\n        self.context.outbox.put_message(message=default_msg)\n\n    def _handle_cfp(self, fipa_msg: FipaMessage, fipa_dialogue: FipaDialogue) -> None:\n        \"\"\"\n        Handle the CFP.\n\n        If the CFP matches the supplied services then send a PROPOSE, otherwise send a DECLINE.\n\n        :param fipa_msg: the message\n        :param fipa_dialogue: the dialogue object\n        \"\"\"\n        strategy = cast(Strategy, self.context.strategy)\n        self.context.logger.info(\n            \"received CFP from sender={}\".format(fipa_msg.sender[-5:])\n        )\n        if not strategy.is_tokens_minted:\n            self.context.logger.info(\"Contract items not minted yet. Try again later.\")\n            return\n\n        # simply send the same proposal, independent of the query\n        fipa_dialogue.proposal = strategy.get_proposal()\n        proposal_msg = fipa_dialogue.reply(\n            performative=FipaMessage.Performative.PROPOSE,\n            target_message=fipa_msg,\n            proposal=fipa_dialogue.proposal,\n        )\n        self.context.logger.info(\n            \"sending PROPOSE to agent={}: proposal={}\".format(\n                fipa_msg.sender[-5:],\n                fipa_dialogue.proposal.values,\n            )\n        )\n        self.context.outbox.put_message(message=proposal_msg)\n\n    def _handle_accept_w_inform(\n        self, fipa_msg: FipaMessage, fipa_dialogue: FipaDialogue\n    ) -> None:\n        \"\"\"\n        Handle the ACCEPT_W_INFORM.\n\n        If the ACCEPT_W_INFORM message contains the signed transaction, sign it too, otherwise do nothing.\n\n        :param fipa_msg: the message\n        :param fipa_dialogue: the dialogue object\n        \"\"\"\n        tx_signature = fipa_msg.info.get(\"tx_signature\", None)\n        if tx_signature is not None:\n            self.context.logger.info(\n                \"received ACCEPT_W_INFORM from sender={}: tx_signature={}\".format(\n                    fipa_msg.sender[-5:], tx_signature\n                )\n            )\n            strategy = cast(Strategy, self.context.strategy)\n            contract_api_dialogues = cast(\n                ContractApiDialogues, self.context.contract_api_dialogues\n            )\n            contract_api_msg, contract_api_dialogue = contract_api_dialogues.create(\n                counterparty=LEDGER_API_ADDRESS,\n                performative=ContractApiMessage.Performative.GET_RAW_TRANSACTION,\n                ledger_id=strategy.ledger_id,\n                contract_id=strategy.contract_id,\n                contract_address=strategy.contract_address,\n                callable=\"get_atomic_swap_single_transaction\",\n                kwargs=ContractApiMessage.Kwargs(\n                    {\n                        \"from_address\": self.context.agent_address,\n                        \"to_address\": fipa_msg.sender,\n                        \"token_id\": int(fipa_dialogue.proposal.values[\"token_id\"]),\n                        \"from_supply\": int(\n                            fipa_dialogue.proposal.values[\"from_supply\"]\n                        ),\n                        \"to_supply\": int(fipa_dialogue.proposal.values[\"to_supply\"]),\n                        \"value\": int(fipa_dialogue.proposal.values[\"value\"]),\n                        \"trade_nonce\": int(\n                            fipa_dialogue.proposal.values[\"trade_nonce\"]\n                        ),\n                        \"signature\": tx_signature,\n                    }\n                ),\n            )\n            contract_api_dialogue = cast(ContractApiDialogue, contract_api_dialogue)\n            contract_api_dialogue.terms = strategy.get_single_swap_terms(\n                fipa_dialogue.proposal, fipa_msg.sender\n            )\n            self.context.outbox.put_message(message=contract_api_msg)\n            self.context.logger.info(\"requesting single atomic swap transaction...\")\n        else:\n            self.context.logger.info(\n                \"received ACCEPT_W_INFORM from sender={} with no signature.\".format(\n                    fipa_msg.sender[-5:]\n                )\n            )\n\n    def _handle_invalid(\n        self, fipa_msg: FipaMessage, fipa_dialogue: FipaDialogue\n    ) -> None:\n        \"\"\"\n        Handle a fipa message of invalid performative.\n\n        :param fipa_msg: the message\n        :param fipa_dialogue: the dialogue object\n        \"\"\"\n        self.context.logger.warning(\n            \"cannot handle fipa message of performative={} in dialogue={}.\".format(\n                fipa_msg.performative, fipa_dialogue\n            )\n        )\n\n\nclass LedgerApiHandler(Handler):\n    \"\"\"Implement the ledger api handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = LedgerApiMessage.protocol_id  # type: Optional[PublicId]\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup for the handler.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to a message.\n\n        :param message: the message\n        \"\"\"\n        ledger_api_msg = cast(LedgerApiMessage, message)\n\n        # recover dialogue\n        ledger_api_dialogues = cast(\n            LedgerApiDialogues, self.context.ledger_api_dialogues\n        )\n        ledger_api_dialogue = cast(\n            Optional[LedgerApiDialogue], ledger_api_dialogues.update(ledger_api_msg)\n        )\n        if ledger_api_dialogue is None:\n            self._handle_unidentified_dialogue(ledger_api_msg)\n            return\n\n        # handle message\n        if ledger_api_msg.performative is LedgerApiMessage.Performative.BALANCE:\n            self._handle_balance(ledger_api_msg)\n        elif (\n            ledger_api_msg.performative\n            is LedgerApiMessage.Performative.TRANSACTION_DIGEST\n        ):\n            self._handle_transaction_digest(ledger_api_msg, ledger_api_dialogue)\n        elif (\n            ledger_api_msg.performative\n            is LedgerApiMessage.Performative.TRANSACTION_RECEIPT\n        ):\n            self._handle_transaction_receipt(ledger_api_msg)\n        elif ledger_api_msg.performative == LedgerApiMessage.Performative.ERROR:\n            self._handle_error(ledger_api_msg, ledger_api_dialogue)\n        else:\n            self._handle_invalid(ledger_api_msg, ledger_api_dialogue)\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n\n    def _handle_unidentified_dialogue(self, ledger_api_msg: LedgerApiMessage) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param ledger_api_msg: the message\n        \"\"\"\n        self.context.logger.info(\n            \"received invalid ledger_api message={}, unidentified dialogue.\".format(\n                ledger_api_msg\n            )\n        )\n\n    def _handle_balance(self, ledger_api_msg: LedgerApiMessage) -> None:\n        \"\"\"\n        Handle a message of balance performative.\n\n        :param ledger_api_msg: the ledger api message\n        \"\"\"\n        self.context.logger.info(\n            \"starting balance on {} ledger={}.\".format(\n                ledger_api_msg.ledger_id,\n                ledger_api_msg.balance,\n            )\n        )\n\n    def _handle_transaction_digest(\n        self, ledger_api_msg: LedgerApiMessage, ledger_api_dialogue: LedgerApiDialogue\n    ) -> None:\n        \"\"\"\n        Handle a message of transaction_digest performative.\n\n        :param ledger_api_msg: the ledger api message\n        :param ledger_api_dialogue: the ledger api dialogue\n        \"\"\"\n        self.context.logger.info(\n            \"transaction was successfully submitted. Transaction digest={}\".format(\n                ledger_api_msg.transaction_digest\n            )\n        )\n        msg = ledger_api_dialogue.reply(\n            performative=LedgerApiMessage.Performative.GET_TRANSACTION_RECEIPT,\n            target_message=ledger_api_msg,\n            transaction_digest=ledger_api_msg.transaction_digest,\n        )\n        self.context.outbox.put_message(message=msg)\n        self.context.logger.info(\"requesting transaction receipt.\")\n\n    def _handle_transaction_receipt(self, ledger_api_msg: LedgerApiMessage) -> None:\n        \"\"\"\n        Handle a message of transaction_receipt performative.\n\n        :param ledger_api_msg: the ledger api message\n        \"\"\"\n        is_transaction_successful = LedgerApis.is_transaction_settled(\n            ledger_api_msg.transaction_receipt.ledger_id,\n            ledger_api_msg.transaction_receipt.receipt,\n        )\n        if is_transaction_successful:\n            self.context.logger.info(\n                \"transaction was successfully settled. Transaction receipt={}\".format(\n                    ledger_api_msg.transaction_receipt\n                )\n            )\n            strategy = cast(Strategy, self.context.strategy)\n            if not strategy.is_contract_deployed:\n                contract_address = cast(\n                    Optional[str],\n                    ledger_api_msg.transaction_receipt.receipt.get(\n                        \"contractAddress\", None\n                    ),\n                )\n                if contract_address is None:\n                    raise ValueError(\"No contract address found.\")  # pragma: nocover\n                strategy.contract_address = contract_address\n                strategy.is_contract_deployed = is_transaction_successful\n                strategy.is_behaviour_active = is_transaction_successful\n            elif not strategy.is_tokens_created:\n                strategy.is_tokens_created = is_transaction_successful\n                strategy.is_behaviour_active = is_transaction_successful\n            elif not strategy.is_tokens_minted:\n                strategy.is_tokens_minted = is_transaction_successful\n                strategy.is_behaviour_active = is_transaction_successful\n            elif strategy.is_tokens_minted:\n                self.context.is_active = False\n                self.context.logger.info(\"demo finished!\")\n            else:  # pragma: no cover\n                self.context.logger.error(\"unexpected transaction receipt!\")\n        else:\n            self.context.logger.error(\n                \"transaction failed. Transaction receipt={}\".format(\n                    ledger_api_msg.transaction_receipt\n                )\n            )\n\n    def _handle_error(\n        self, ledger_api_msg: LedgerApiMessage, ledger_api_dialogue: LedgerApiDialogue\n    ) -> None:\n        \"\"\"\n        Handle a message of error performative.\n\n        :param ledger_api_msg: the ledger api message\n        :param ledger_api_dialogue: the ledger api dialogue\n        \"\"\"\n        self.context.logger.info(\n            \"received ledger_api error message={} in dialogue={}.\".format(\n                ledger_api_msg, ledger_api_dialogue\n            )\n        )\n\n    def _handle_invalid(\n        self, ledger_api_msg: LedgerApiMessage, ledger_api_dialogue: LedgerApiDialogue\n    ) -> None:\n        \"\"\"\n        Handle a message of invalid performative.\n\n        :param ledger_api_msg: the ledger api message\n        :param ledger_api_dialogue: the ledger api dialogue\n        \"\"\"\n        self.context.logger.warning(\n            \"cannot handle ledger_api message of performative={} in dialogue={}.\".format(\n                ledger_api_msg.performative,\n                ledger_api_dialogue,\n            )\n        )\n\n\nclass ContractApiHandler(Handler):\n    \"\"\"Implement the contract api handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = ContractApiMessage.protocol_id  # type: Optional[PublicId]\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup for the handler.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to a message.\n\n        :param message: the message\n        \"\"\"\n        contract_api_msg = cast(ContractApiMessage, message)\n\n        # recover dialogue\n        contract_api_dialogues = cast(\n            ContractApiDialogues, self.context.contract_api_dialogues\n        )\n        contract_api_dialogue = cast(\n            Optional[ContractApiDialogue],\n            contract_api_dialogues.update(contract_api_msg),\n        )\n        if contract_api_dialogue is None:\n            self._handle_unidentified_dialogue(contract_api_msg)\n            return\n\n        # handle message\n        if (\n            contract_api_msg.performative\n            is ContractApiMessage.Performative.RAW_TRANSACTION\n        ):\n            self._handle_raw_transaction(contract_api_msg, contract_api_dialogue)\n        elif contract_api_msg.performative == ContractApiMessage.Performative.ERROR:\n            self._handle_error(contract_api_msg, contract_api_dialogue)\n        else:\n            self._handle_invalid(contract_api_msg, contract_api_dialogue)\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n\n    def _handle_unidentified_dialogue(\n        self, contract_api_msg: ContractApiMessage\n    ) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param contract_api_msg: the message\n        \"\"\"\n        self.context.logger.info(\n            \"received invalid contract_api message={}, unidentified dialogue.\".format(\n                contract_api_msg\n            )\n        )\n\n    def _handle_raw_transaction(\n        self,\n        contract_api_msg: ContractApiMessage,\n        contract_api_dialogue: ContractApiDialogue,\n    ) -> None:\n        \"\"\"\n        Handle a message of raw_transaction performative.\n\n        :param contract_api_msg: the ledger api message\n        :param contract_api_dialogue: the ledger api dialogue\n        \"\"\"\n        self.context.logger.info(\"received raw transaction={}\".format(contract_api_msg))\n        signing_dialogues = cast(SigningDialogues, self.context.signing_dialogues)\n        signing_msg, signing_dialogue = signing_dialogues.create(\n            counterparty=self.context.decision_maker_address,\n            performative=SigningMessage.Performative.SIGN_TRANSACTION,\n            raw_transaction=contract_api_msg.raw_transaction,\n            terms=contract_api_dialogue.terms,\n        )\n        signing_dialogue = cast(SigningDialogue, signing_dialogue)\n        signing_dialogue.associated_contract_api_dialogue = contract_api_dialogue\n        self.context.decision_maker_message_queue.put_nowait(signing_msg)\n        self.context.logger.info(\n            \"proposing the transaction to the decision maker. Waiting for confirmation ...\"\n        )\n\n    def _handle_error(\n        self,\n        contract_api_msg: ContractApiMessage,\n        contract_api_dialogue: ContractApiDialogue,\n    ) -> None:\n        \"\"\"\n        Handle a message of error performative.\n\n        :param contract_api_msg: the ledger api message\n        :param contract_api_dialogue: the ledger api dialogue\n        \"\"\"\n        self.context.logger.info(\n            \"received contract_api error message={} in dialogue={}.\".format(\n                contract_api_msg, contract_api_dialogue\n            )\n        )\n\n    def _handle_invalid(\n        self,\n        contract_api_msg: ContractApiMessage,\n        contract_api_dialogue: ContractApiDialogue,\n    ) -> None:\n        \"\"\"\n        Handle a message of invalid performative.\n\n        :param contract_api_msg: the ledger api message\n        :param contract_api_dialogue: the ledger api dialogue\n        \"\"\"\n        self.context.logger.warning(\n            \"cannot handle contract_api message of performative={} in dialogue={}.\".format(\n                contract_api_msg.performative,\n                contract_api_dialogue,\n            )\n        )\n\n\nclass SigningHandler(Handler):\n    \"\"\"Implement the transaction handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = SigningMessage.protocol_id  # type: Optional[PublicId]\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup for the handler.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to a message.\n\n        :param message: the message\n        \"\"\"\n        signing_msg = cast(SigningMessage, message)\n\n        # recover dialogue\n        signing_dialogues = cast(SigningDialogues, self.context.signing_dialogues)\n        signing_dialogue = cast(\n            Optional[SigningDialogue], signing_dialogues.update(signing_msg)\n        )\n        if signing_dialogue is None:\n            self._handle_unidentified_dialogue(signing_msg)\n            return\n\n        # handle message\n        if signing_msg.performative is SigningMessage.Performative.SIGNED_TRANSACTION:\n            self._handle_signed_transaction(signing_msg, signing_dialogue)\n        elif signing_msg.performative is SigningMessage.Performative.ERROR:\n            self._handle_error(signing_msg, signing_dialogue)\n        else:\n            self._handle_invalid(signing_msg, signing_dialogue)\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n\n    def _handle_unidentified_dialogue(self, signing_msg: SigningMessage) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param signing_msg: the message\n        \"\"\"\n        self.context.logger.info(\n            \"received invalid signing message={}, unidentified dialogue.\".format(\n                signing_msg\n            )\n        )\n\n    def _handle_signed_transaction(\n        self, signing_msg: SigningMessage, signing_dialogue: SigningDialogue\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param signing_msg: the signing message\n        :param signing_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.info(\"transaction signing was successful.\")\n        ledger_api_dialogues = cast(\n            LedgerApiDialogues, self.context.ledger_api_dialogues\n        )\n        ledger_api_msg, ledger_api_dialogue = ledger_api_dialogues.create(\n            counterparty=LEDGER_API_ADDRESS,\n            performative=LedgerApiMessage.Performative.SEND_SIGNED_TRANSACTION,\n            signed_transaction=signing_msg.signed_transaction,\n        )\n        ledger_api_dialogue = cast(LedgerApiDialogue, ledger_api_dialogue)\n        ledger_api_dialogue.associated_signing_dialogue = signing_dialogue\n        self.context.outbox.put_message(message=ledger_api_msg)\n        self.context.logger.info(\"sending transaction to ledger.\")\n\n    def _handle_error(\n        self, signing_msg: SigningMessage, signing_dialogue: SigningDialogue\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param signing_msg: the signing message\n        :param signing_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.info(\n            \"transaction signing was not successful. Error_code={} in dialogue={}\".format(\n                signing_msg.error_code, signing_dialogue\n            )\n        )\n\n    def _handle_invalid(\n        self, signing_msg: SigningMessage, signing_dialogue: SigningDialogue\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param signing_msg: the signing message\n        :param signing_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.warning(\n            \"cannot handle signing message of performative={} in dialogue={}.\".format(\n                signing_msg.performative, signing_dialogue\n            )\n        )\n\n\nclass OefSearchHandler(Handler):\n    \"\"\"This class implements an OEF search handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = OefSearchMessage.protocol_id  # type: Optional[PublicId]\n\n    def setup(self) -> None:\n        \"\"\"Call to setup the handler.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to a message.\n\n        :param message: the message\n        \"\"\"\n        oef_search_msg = cast(OefSearchMessage, message)\n\n        # recover dialogue\n        oef_search_dialogues = cast(\n            OefSearchDialogues, self.context.oef_search_dialogues\n        )\n        oef_search_dialogue = cast(\n            Optional[OefSearchDialogue], oef_search_dialogues.update(oef_search_msg)\n        )\n        if oef_search_dialogue is None:\n            self._handle_unidentified_dialogue(oef_search_msg)\n            return\n\n        # handle message\n        if oef_search_msg.performative == OefSearchMessage.Performative.SUCCESS:\n            self._handle_success(oef_search_msg, oef_search_dialogue)\n        elif oef_search_msg.performative == OefSearchMessage.Performative.OEF_ERROR:\n            self._handle_error(oef_search_msg, oef_search_dialogue)\n        else:\n            self._handle_invalid(oef_search_msg, oef_search_dialogue)\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n\n    def _handle_unidentified_dialogue(self, oef_search_msg: OefSearchMessage) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param oef_search_msg: the message\n        \"\"\"\n        self.context.logger.info(\n            \"received invalid oef_search message={}, unidentified dialogue.\".format(\n                oef_search_msg\n            )\n        )\n\n    def _handle_success(\n        self,\n        oef_search_success_msg: OefSearchMessage,\n        oef_search_dialogue: OefSearchDialogue,\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param oef_search_success_msg: the oef search message\n        :param oef_search_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.info(\n            \"received oef_search success message={} in dialogue={}.\".format(\n                oef_search_success_msg, oef_search_dialogue\n            )\n        )\n        target_message = cast(\n            OefSearchMessage,\n            oef_search_dialogue.get_message_by_id(oef_search_success_msg.target),\n        )\n        if (\n            target_message.performative\n            == OefSearchMessage.Performative.REGISTER_SERVICE\n        ):\n            description = target_message.service_description\n            data_model_name = description.data_model.name\n            registration_behaviour = cast(\n                ServiceRegistrationBehaviour,\n                self.context.behaviours.service_registration,\n            )\n            if \"location_agent\" in data_model_name:\n                registration_behaviour.register_service()\n            elif \"set_service_key\" in data_model_name:\n                registration_behaviour.register_genus()\n            elif (\n                \"personality_agent\" in data_model_name\n                and description.values[\"piece\"] == \"genus\"\n            ):\n                registration_behaviour.register_classification()\n            elif (\n                \"personality_agent\" in data_model_name\n                and description.values[\"piece\"] == \"classification\"\n            ):\n                registration_behaviour.is_registered = True\n                registration_behaviour.registration_in_progress = False\n                self.context.logger.info(\n                    \"the agent, with its genus and classification, and its service are successfully registered on the SOEF.\"\n                )\n            else:\n                self.context.logger.warning(\n                    f\"received soef SUCCESS message as a reply to the following unexpected message: {target_message}\"\n                )\n\n    def _handle_error(\n        self,\n        oef_search_error_msg: OefSearchMessage,\n        oef_search_dialogue: OefSearchDialogue,\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param oef_search_error_msg: the oef search message\n        :param oef_search_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.info(\n            \"received oef_search error message={} in dialogue={}.\".format(\n                oef_search_error_msg, oef_search_dialogue\n            )\n        )\n        target_message = cast(\n            OefSearchMessage,\n            oef_search_dialogue.get_message_by_id(oef_search_error_msg.target),\n        )\n        if (\n            target_message.performative\n            == OefSearchMessage.Performative.REGISTER_SERVICE\n        ):\n            registration_behaviour = cast(\n                ServiceRegistrationBehaviour,\n                self.context.behaviours.service_registration,\n            )\n            registration_behaviour.failed_registration_msg = target_message\n\n    def _handle_invalid(\n        self, oef_search_msg: OefSearchMessage, oef_search_dialogue: OefSearchDialogue\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param oef_search_msg: the oef search message\n        :param oef_search_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.warning(\n            \"cannot handle oef_search message of performative={} in dialogue={}.\".format(\n                oef_search_msg.performative,\n                oef_search_dialogue,\n            )\n        )\n"
  },
  {
    "path": "packages/fetchai/skills/erc1155_deploy/skill.yaml",
    "content": "name: erc1155_deploy\nauthor: fetchai\nversion: 0.31.6\ntype: skill\ndescription: The ERC1155 deploy skill has the ability to deploy and interact with\n  the smart contract.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: QmX98yCz4tVKF5dJUDUVh6T4vD3y9Gv42semKkpckqXjAA\n  __init__.py: QmbtD65LEy39PpMtRMfXtR5D5JXALiuWNuTSoqoCpvDLsG\n  behaviours.py: QmXxfA42Zi2eYgfRQEKDxcotw628KTTRPTCyeJv6aBJmuH\n  dialogues.py: QmRsL56kWqrs6pf8MKBdU1bxrYpuwgt63yugtMYnjWmzvo\n  handlers.py: QmeNBxsimbf9wjQ5Yar8NfUdzRKbpvVys3LA8Hdirk7QeZ\n  strategy.py: QmR5ZEaGtBW57EJoGMVfKZGoPvFdzecwA4mmsWm1aomcB5\nfingerprint_ignore_patterns: []\nconnections:\n- fetchai/ledger:0.21.5\ncontracts:\n- fetchai/erc1155:0.23.3\nprotocols:\n- fetchai/contract_api:1.1.7\n- fetchai/default:1.1.7\n- fetchai/fipa:1.1.7\n- fetchai/ledger_api:1.1.7\n- fetchai/oef_search:1.1.7\n- fetchai/signing:1.1.7\nskills: []\nbehaviours:\n  service_registration:\n    args:\n      max_soef_registration_retries: 5\n      services_interval: 20\n    class_name: ServiceRegistrationBehaviour\nhandlers:\n  contract_api:\n    args: {}\n    class_name: ContractApiHandler\n  fipa:\n    args: {}\n    class_name: FipaHandler\n  ledger_api:\n    args: {}\n    class_name: LedgerApiHandler\n  oef_search:\n    args: {}\n    class_name: OefSearchHandler\n  signing:\n    args: {}\n    class_name: SigningHandler\nmodels:\n  contract_api_dialogues:\n    args: {}\n    class_name: ContractApiDialogues\n  default_dialogues:\n    args: {}\n    class_name: DefaultDialogues\n  fipa_dialogues:\n    args: {}\n    class_name: FipaDialogues\n  ledger_api_dialogues:\n    args: {}\n    class_name: LedgerApiDialogues\n  oef_search_dialogues:\n    args: {}\n    class_name: OefSearchDialogues\n  signing_dialogues:\n    args: {}\n    class_name: SigningDialogues\n  strategy:\n    args:\n      classification:\n        piece: classification\n        value: seller\n      from_supply: 10\n      location:\n        latitude: 51.5194\n        longitude: 0.127\n      mint_quantities:\n      - 100\n      - 100\n      - 100\n      - 100\n      - 100\n      - 100\n      - 100\n      - 100\n      - 100\n      - 100\n      nb_tokens: 10\n      personality_data:\n        piece: genus\n        value: data\n      service_data:\n        key: seller_service\n        value: erc1155_contract\n      to_supply: 0\n      token_type: 2\n      value: 0\n    class_name: Strategy\ndependencies:\n  aea-ledger-ethereum:\n    version: <2.0.0,>=1.0.0\nis_abstract: false\n"
  },
  {
    "path": "packages/fetchai/skills/erc1155_deploy/strategy.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the strategy class.\"\"\"\n\nimport random  # nosec\nfrom typing import Any, List\n\nfrom aea.exceptions import enforce\nfrom aea.helpers.search.generic import (\n    AGENT_LOCATION_MODEL,\n    AGENT_PERSONALITY_MODEL,\n    AGENT_REMOVE_SERVICE_MODEL,\n    AGENT_SET_SERVICE_MODEL,\n    SIMPLE_SERVICE_MODEL,\n)\nfrom aea.helpers.search.models import Description, Location\nfrom aea.helpers.transaction.base import Terms\nfrom aea.skills.base import Model\n\nfrom packages.fetchai.contracts.erc1155.contract import ERC1155Contract\n\n\nDEFAULT_IS_LEDGER_TX = True\nDEFAULT_NFT = 1\nDEFAULT_FT = 2\nDEFAULT_TOKEN_TYPE = DEFAULT_NFT\nDEFAULT_NB_TOKENS = 10\nDEFAULT_MINT_QUANTITIES = [100, 100, 100, 100, 100, 100, 100, 100, 100, 100]\nDEFAULT_FROM_SUPPLY = 10\nDEFAULT_TO_SUPPLY = 0\nDEFAULT_VALUE = 0\nDEFAULT_LOCATION = {\"longitude\": 0.1270, \"latitude\": 51.5194}\nDEFAULT_SERVICE_DATA = {\"key\": \"seller_service\", \"value\": \"erc1155_contract\"}\nDEFAULT_PERSONALITY_DATA = {\"piece\": \"genus\", \"value\": \"data\"}\nDEFAULT_CLASSIFICATION = {\"piece\": \"classification\", \"value\": \"seller\"}\nDEFAULT_GAS = 5000000\n\n\nclass Strategy(Model):\n    \"\"\"This class defines a strategy for the agent.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"Initialize the strategy of the agent.\"\"\"\n        ledger_id = kwargs.pop(\"ledger_id\", None)\n        self._token_type = kwargs.pop(\"token_type\", DEFAULT_TOKEN_TYPE)\n        enforce(self._token_type in [1, 2], \"Token type must be 1 (NFT) or 2 (FT)\")\n        self._nb_tokens = kwargs.pop(\"nb_tokens\", DEFAULT_NB_TOKENS)\n        self._token_ids = kwargs.pop(\"token_ids\", None)\n        self._mint_quantities = kwargs.pop(\"mint_quantities\", DEFAULT_MINT_QUANTITIES)\n        enforce(\n            len(self._mint_quantities) == self._nb_tokens,\n            \"Number of tokens must match mint quantities array size.\",\n        )\n        if self._token_type == 1:\n            enforce(\n                all(quantity == 1 for quantity in self._mint_quantities),\n                \"NFTs must have a quantity of 1\",\n            )\n        self._contract_address = kwargs.pop(\"contract_address\", None)\n        enforce(\n            (self._token_ids is None and self._contract_address is None)\n            or (self._token_ids is not None and self._contract_address is not None),\n            \"Either provide contract address and token ids or provide neither.\",\n        )\n\n        self.from_supply = kwargs.pop(\"from_supply\", DEFAULT_FROM_SUPPLY)\n        self.to_supply = kwargs.pop(\"to_supply\", DEFAULT_TO_SUPPLY)\n        self.value = kwargs.pop(\"value\", DEFAULT_VALUE)\n\n        location = kwargs.pop(\"location\", DEFAULT_LOCATION)\n        self._agent_location = {\n            \"location\": Location(\n                latitude=location[\"latitude\"], longitude=location[\"longitude\"]\n            )\n        }\n        self._set_personality_data = kwargs.pop(\n            \"personality_data\", DEFAULT_PERSONALITY_DATA\n        )\n        enforce(\n            len(self._set_personality_data) == 2\n            and \"piece\" in self._set_personality_data\n            and \"value\" in self._set_personality_data,\n            \"personality_data must contain keys `key` and `value`\",\n        )\n        self._set_classification = kwargs.pop(\"classification\", DEFAULT_CLASSIFICATION)\n        enforce(\n            len(self._set_classification) == 2\n            and \"piece\" in self._set_classification\n            and \"value\" in self._set_classification,\n            \"classification must contain keys `key` and `value`\",\n        )\n        self._set_service_data = kwargs.pop(\"service_data\", DEFAULT_SERVICE_DATA)\n        enforce(\n            len(self._set_service_data) == 2\n            and \"key\" in self._set_service_data\n            and \"value\" in self._set_service_data,\n            \"service_data must contain keys `key` and `value`\",\n        )\n        self._remove_service_data = {\"key\": self._set_service_data[\"key\"]}\n        self._simple_service_data = {\n            self._set_service_data[\"key\"]: self._set_service_data[\"value\"]\n        }\n        self._gas = kwargs.pop(\"gas\", DEFAULT_GAS)\n\n        super().__init__(**kwargs)\n        self._ledger_id = (\n            ledger_id if ledger_id is not None else self.context.default_ledger_id\n        )\n        self._contract_id = str(ERC1155Contract.contract_id)\n        self.is_behaviour_active = True\n        self._is_contract_deployed = self._contract_address is not None\n        self._is_tokens_created = self._token_ids is not None\n        self._is_tokens_minted = self._token_ids is not None\n        if self._token_ids is None:\n            self._token_ids = ERC1155Contract.generate_token_ids(\n                token_type=self._token_type, nb_tokens=self._nb_tokens\n            )\n\n    @property\n    def ledger_id(self) -> str:\n        \"\"\"Get the ledger id.\"\"\"\n        return self._ledger_id\n\n    @property\n    def contract_id(self) -> str:\n        \"\"\"Get the contract id.\"\"\"\n        return self._contract_id\n\n    @property\n    def mint_quantities(self) -> List[int]:\n        \"\"\"Get the list of mint quantities.\"\"\"\n        return self._mint_quantities\n\n    @property\n    def token_ids(self) -> List[int]:\n        \"\"\"Get the token ids.\"\"\"\n        if self._token_ids is None:\n            raise ValueError(\"Token ids not set.\")\n        return self._token_ids\n\n    @property\n    def contract_address(self) -> str:\n        \"\"\"Get the contract address.\"\"\"\n        if self._contract_address is None:\n            raise ValueError(\"Contract address not set!\")\n        return self._contract_address\n\n    @contract_address.setter\n    def contract_address(self, contract_address: str) -> None:\n        \"\"\"Set the contract address.\"\"\"\n        enforce(self._contract_address is None, \"Contract address already set!\")\n        self._contract_address = contract_address\n\n    @property\n    def is_contract_deployed(self) -> bool:\n        \"\"\"Get contract deploy status.\"\"\"\n        return self._is_contract_deployed\n\n    @is_contract_deployed.setter\n    def is_contract_deployed(self, is_contract_deployed: bool) -> None:\n        \"\"\"Set contract deploy status.\"\"\"\n        enforce(\n            not self._is_contract_deployed and is_contract_deployed,\n            \"Only allowed to switch to true.\",\n        )\n        self._is_contract_deployed = is_contract_deployed\n\n    @property\n    def is_tokens_created(self) -> bool:\n        \"\"\"Get token created status.\"\"\"\n        return self._is_tokens_created\n\n    @is_tokens_created.setter\n    def is_tokens_created(self, is_tokens_created: bool) -> None:\n        \"\"\"Set token created status.\"\"\"\n        enforce(\n            not self._is_tokens_created and is_tokens_created,\n            \"Only allowed to switch to true.\",\n        )\n        self._is_tokens_created = is_tokens_created\n\n    @property\n    def is_tokens_minted(self) -> bool:\n        \"\"\"Get token minted status.\"\"\"\n        return self._is_tokens_minted\n\n    @is_tokens_minted.setter\n    def is_tokens_minted(self, is_tokens_minted: bool) -> None:\n        \"\"\"Set token minted status.\"\"\"\n        enforce(\n            not self._is_tokens_minted and is_tokens_minted,\n            \"Only allowed to switch to true.\",\n        )\n        self._is_tokens_minted = is_tokens_minted\n\n    @property\n    def gas(self) -> int:\n        \"\"\"Get gas.\"\"\"\n        return self._gas\n\n    def get_location_description(self) -> Description:\n        \"\"\"\n        Get the location description.\n\n        :return: a description of the agent's location\n        \"\"\"\n        description = Description(\n            self._agent_location,\n            data_model=AGENT_LOCATION_MODEL,\n        )\n        return description\n\n    def get_register_service_description(self) -> Description:\n        \"\"\"\n        Get the register service description.\n\n        :return: a description of the offered services\n        \"\"\"\n        description = Description(\n            self._set_service_data,\n            data_model=AGENT_SET_SERVICE_MODEL,\n        )\n        return description\n\n    def get_register_personality_description(self) -> Description:\n        \"\"\"\n        Get the register personality description.\n\n        :return: a description of the personality\n        \"\"\"\n        description = Description(\n            self._set_personality_data,\n            data_model=AGENT_PERSONALITY_MODEL,\n        )\n        return description\n\n    def get_register_classification_description(self) -> Description:\n        \"\"\"\n        Get the register classification description.\n\n        :return: a description of the classification\n        \"\"\"\n        description = Description(\n            self._set_classification,\n            data_model=AGENT_PERSONALITY_MODEL,\n        )\n        return description\n\n    def get_service_description(self) -> Description:\n        \"\"\"\n        Get the simple service description.\n\n        :return: a description of the offered services\n        \"\"\"\n        description = Description(\n            self._simple_service_data,\n            data_model=SIMPLE_SERVICE_MODEL,\n        )\n        return description\n\n    def get_unregister_service_description(self) -> Description:\n        \"\"\"\n        Get the unregister service description.\n\n        :return: a description of the to be removed service\n        \"\"\"\n        description = Description(\n            self._remove_service_data,\n            data_model=AGENT_REMOVE_SERVICE_MODEL,\n        )\n        return description\n\n    def get_deploy_terms(self) -> Terms:\n        \"\"\"\n        Get deploy terms of deployment.\n\n        :return: terms\n        \"\"\"\n        terms = Terms(\n            ledger_id=self.ledger_id,\n            sender_address=self.context.agent_address,\n            counterparty_address=self.context.agent_address,\n            amount_by_currency_id={},\n            quantities_by_good_id={},\n            nonce=\"\",\n        )\n        return terms\n\n    def get_create_token_terms(self) -> Terms:\n        \"\"\"\n        Get create token terms of deployment.\n\n        :return: terms\n        \"\"\"\n        terms = Terms(\n            ledger_id=self.ledger_id,\n            sender_address=self.context.agent_address,\n            counterparty_address=self.context.agent_address,\n            amount_by_currency_id={},\n            quantities_by_good_id={},\n            nonce=\"\",\n        )\n        return terms\n\n    def get_mint_token_terms(self) -> Terms:\n        \"\"\"\n        Get mint token terms of deployment.\n\n        :return: terms\n        \"\"\"\n        terms = Terms(\n            ledger_id=self.ledger_id,\n            sender_address=self.context.agent_address,\n            counterparty_address=self.context.agent_address,\n            amount_by_currency_id={},\n            quantities_by_good_id={},\n            nonce=\"\",\n        )\n        return terms\n\n    def get_proposal(self) -> Description:\n        \"\"\"Get the proposal.\"\"\"\n        trade_nonce = random.randrange(  # nosec\n            0, 10000000\n        )  # quickfix, to avoid contract call\n        token_id = self.token_ids[0]\n        proposal = Description(\n            {\n                \"contract_address\": self.contract_address,\n                \"token_id\": str(token_id),\n                \"trade_nonce\": str(trade_nonce),\n                \"from_supply\": str(self.from_supply),\n                \"to_supply\": str(self.to_supply),\n                \"value\": str(self.value),\n            }\n        )\n        return proposal\n\n    def get_single_swap_terms(\n        self, proposal: Description, counterparty_address: str\n    ) -> Terms:\n        \"\"\"Get the proposal.\"\"\"\n        terms = Terms(\n            ledger_id=self.ledger_id,\n            sender_address=self.context.agent_address,\n            counterparty_address=counterparty_address,\n            amount_by_currency_id={\n                str(proposal.values[\"token_id\"]): int(proposal.values[\"from_supply\"])\n                - int(proposal.values[\"to_supply\"])\n            },\n            quantities_by_good_id={},\n            is_sender_payable_tx_fee=True,\n            nonce=str(proposal.values[\"trade_nonce\"]),\n            fee_by_currency_id={},\n        )\n        return terms\n"
  },
  {
    "path": "packages/fetchai/skills/error/README.md",
    "content": "# Error\n\n## Description\n\nThe error skill is used to handle incoming envelops that cannot be properly handled by the framework.\n\nIt handles the following cases:\n\n- AEA receives an envelope referencing an unsupported protocol,\n- AEA experiences a decoding error when reading an envelope,\n- AEA receives an envelope referencing a protocol for which no skill is active.\n\n## Handlers\n\n- `error_handler`: handles `default` messages for problematic envelopes/messages.\n"
  },
  {
    "path": "packages/fetchai/skills/error/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the implementation of the error skill.\"\"\"\n\nfrom aea.configurations.base import PublicId\n\n\nPUBLIC_ID = PublicId.from_str(\"fetchai/error:0.18.6\")\n"
  },
  {
    "path": "packages/fetchai/skills/error/handlers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains the implementation of the handler for the 'default' protocol.\"\"\"\n\nimport base64\nfrom typing import Optional\n\nfrom aea.configurations.base import PublicId\nfrom aea.mail.base import Envelope\nfrom aea.protocols.base import Message\nfrom aea.skills.base import Handler\n\nfrom packages.fetchai.protocols.default.message import DefaultMessage\n\n\nclass ErrorHandler(Handler):\n    \"\"\"This class implements the error handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = DefaultMessage.protocol_id  # type: Optional[PublicId]\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to an envelope.\n\n        :param message: the message\n        \"\"\"\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n\n    def send_unsupported_protocol(self, envelope: Envelope) -> None:\n        \"\"\"\n        Handle the received envelope in case the protocol is not supported.\n\n        :param envelope: the envelope\n        \"\"\"\n        self.context.logger.warning(\n            \"Unsupported protocol: {}. You might want to add a handler for this protocol.\".format(\n                envelope.protocol_specification_id\n            )\n        )\n        encoded_protocol_specification_id = base64.b85encode(\n            str.encode(str(envelope.protocol_specification_id))\n        )\n        encoded_envelope = base64.b85encode(envelope.encode())\n        reply = DefaultMessage(\n            dialogue_reference=(\"\", \"\"),\n            message_id=1,\n            target=0,\n            performative=DefaultMessage.Performative.ERROR,\n            error_code=DefaultMessage.ErrorCode.UNSUPPORTED_PROTOCOL,\n            error_msg=\"Unsupported protocol.\",\n            error_data={\n                \"protocol_id\": encoded_protocol_specification_id,\n                \"envelope\": encoded_envelope,\n            },\n        )\n        reply.sender = self.context.agent_address\n        reply.to = envelope.sender\n        self.context.outbox.put_message(message=reply)\n\n    def send_decoding_error(self, envelope: Envelope) -> None:\n        \"\"\"\n        Handle a decoding error.\n\n        :param envelope: the envelope\n        \"\"\"\n        self.context.logger.warning(\n            \"Decoding error for envelope: {}. protocol_specification_id='{}' and message='{!r}' are inconsistent.\".format(\n                envelope, envelope.protocol_specification_id, envelope.message\n            )\n        )\n        encoded_envelope = base64.b85encode(envelope.encode())\n        reply = DefaultMessage(\n            dialogue_reference=(\"\", \"\"),\n            message_id=1,\n            target=0,\n            performative=DefaultMessage.Performative.ERROR,\n            error_code=DefaultMessage.ErrorCode.DECODING_ERROR,\n            error_msg=\"Decoding error.\",\n            error_data={\"envelope\": encoded_envelope},\n        )\n        reply.sender = self.context.agent_address\n        reply.to = envelope.sender\n        self.context.outbox.put_message(message=reply)\n\n    def send_unsupported_skill(self, envelope: Envelope) -> None:\n        \"\"\"\n        Handle the received envelope in case the skill is not supported.\n\n        :param envelope: the envelope\n        \"\"\"\n        self.context.logger.warning(\n            \"Cannot handle envelope: no active handler registered for the protocol_specification_id='{}'.\".format(\n                envelope.protocol_specification_id\n            )\n        )\n        encoded_envelope = base64.b85encode(envelope.encode())\n        reply = DefaultMessage(\n            dialogue_reference=(\"\", \"\"),\n            message_id=1,\n            target=0,\n            performative=DefaultMessage.Performative.ERROR,\n            error_code=DefaultMessage.ErrorCode.UNSUPPORTED_SKILL,\n            error_msg=\"Unsupported skill.\",\n            error_data={\"envelope\": encoded_envelope},\n        )\n        reply.sender = self.context.agent_address\n        reply.to = envelope.sender\n        self.context.outbox.put_message(message=reply)\n"
  },
  {
    "path": "packages/fetchai/skills/error/skill.yaml",
    "content": "name: error\nauthor: fetchai\nversion: 0.18.6\ntype: skill\ndescription: The error skill implements basic error handling required by all AEAs.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: QmNw5XkR9DfMycuD3j7dpGdvnyQEZTBRoYdraFiTXYTLkv\n  __init__.py: QmPNutzpA7C3YzSNpnKYY6fRkXiyx8HwZW1CEjiPJ56CJv\n  handlers.py: QmfEqAzS2PTcxrgh7crVrvuDVkjF3Fa2GndRyUu8UPUSq4\nfingerprint_ignore_patterns: []\nconnections: []\ncontracts: []\nprotocols:\n- fetchai/default:1.1.7\nskills: []\nbehaviours: {}\nhandlers:\n  error_handler:\n    args: {}\n    class_name: ErrorHandler\nmodels: {}\ndependencies: {}\nis_abstract: false\n"
  },
  {
    "path": "packages/fetchai/skills/error_test_skill/README.md",
    "content": "# Error Test Skill\n\n## Description\n\nSkill raises an exception on behaviour's act\n\n## Behaviours\n\n- RaiseError - just raises an error on act\n\n## Handlers\n\n## Links\n"
  },
  {
    "path": "packages/fetchai/skills/error_test_skill/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains an example of skill raises exception for an AEA.\"\"\"\n\nfrom aea.configurations.base import PublicId\n\n\nPUBLIC_ID = PublicId.from_str(\"fetchai/error_test_skill:0.1.2\")\n"
  },
  {
    "path": "packages/fetchai/skills/error_test_skill/behaviours.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the behaviours for the 'error_test' skill.\"\"\"\n\nfrom aea.skills.behaviours import TickerBehaviour\n\n\nclass RaiseErrorBehaviour(TickerBehaviour):\n    \"\"\"Echo behaviour.\"\"\"\n\n    def setup(self) -> None:\n        \"\"\"Set up the behaviour.\"\"\"\n        self.context.logger.info(\"Raise Error Behaviour: setup method called.\")\n\n    def act(self) -> None:\n        \"\"\"Act according to the behaviour.\"\"\"\n        self.context.logger.info(\"Raise Error Behaviour: act method called.\")\n        raise Exception(\"Expected exception!\")\n\n    def teardown(self) -> None:\n        \"\"\"Teardown the behaviour.\"\"\"\n        self.context.logger.info(\"Raise Error Behaviour: teardown method called.\")\n"
  },
  {
    "path": "packages/fetchai/skills/error_test_skill/skill.yaml",
    "content": "name: error_test_skill\nauthor: fetchai\nversion: 0.1.2\ntype: skill\ndescription: The error test skil for testing.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: QmWt4ZwTxErR6E8jhJGNoL7aJ2Re1W9WjZ9J13gh2xzKeX\n  __init__.py: QmeCKAnqeT1GdRGtj8sJBvUw5BnP6aVDzpDdsCSGj3fZCP\n  behaviours.py: Qmcfd3fEUiKgSPcXpeTMtCojfjpGBc9LjRwx3X22TsMxKW\nfingerprint_ignore_patterns: []\nconnections: []\ncontracts: []\nprotocols: []\nskills: []\nbehaviours:\n  raiseerror:\n    args:\n      tick_interval: 1.0\n    class_name: RaiseErrorBehaviour\nhandlers: {}\nmodels: {}\ndependencies: {}\nis_abstract: false\n"
  },
  {
    "path": "packages/fetchai/skills/fetch_block/README.md",
    "content": "# Fetch Block\n\n## Description\n\nThis skill is used to get the latest block data from the Fetch ledger.\n\n## Behaviours\n\n- `fetch_block_behaviour`: requests latest block data every `tick_interval` seconds from the REST endpoint for the FetchAI ledger.\n\n## Handlers\n\n- `http`: handles incoming `http` messages, retrieves the block data from the appropriate response, and stores it in shared state under the key: `block_data`.\n"
  },
  {
    "path": "packages/fetchai/skills/fetch_block/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the implementation of the FetchBlock skill.\"\"\"\n\nfrom aea.configurations.base import PublicId\n\n\nPUBLIC_ID = PublicId.from_str(\"fetchai/fetch_block:0.12.6\")\n"
  },
  {
    "path": "packages/fetchai/skills/fetch_block/behaviours.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains the behaviour to get the latest block from the Fetch ledger.\"\"\"\n\nfrom typing import Any, cast\n\nfrom aea.skills.behaviours import TickerBehaviour\n\nfrom packages.fetchai.connections.ledger.base import CONNECTION_ID as LEDGER_API_ADDRESS\nfrom packages.fetchai.protocols.ledger_api.custom_types import Kwargs\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\nfrom packages.fetchai.skills.fetch_block.dialogues import LedgerApiDialogues\n\n\nclass FetchBlockBehaviour(TickerBehaviour):\n    \"\"\"This class provides a behaviour to get the latest block from the Fetch ledger.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"Initialize the fetch block behaviour.\"\"\"\n\n        super().__init__(**kwargs)\n\n    def _get_block(self) -> None:\n        \"\"\"Request the latest block by sending a message to the ledger API.\"\"\"\n        ledger_api_dialogues = cast(\n            LedgerApiDialogues, self.context.ledger_api_dialogues\n        )\n        ledger_api_msg, _ = ledger_api_dialogues.create(\n            counterparty=str(LEDGER_API_ADDRESS),\n            performative=LedgerApiMessage.Performative.GET_STATE,\n            ledger_id=self.context.default_ledger_id,\n            callable=\"blocks\",\n            args=(\"latest\",),\n            kwargs=Kwargs({}),\n        )\n        self.context.outbox.put_message(message=ledger_api_msg)\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup.\"\"\"\n        self.context.logger.info(\"setting up FetchBlockBehaviour\")\n\n    def act(self) -> None:\n        \"\"\"Implement the act.\"\"\"\n\n        self.context.logger.info(\"Fetching latest block...\")\n        self._get_block()\n\n    def teardown(self) -> None:\n        \"\"\"Implement the task teardown.\"\"\"\n        self.context.logger.info(\"tearing down FetchBlockBehaviour\")\n"
  },
  {
    "path": "packages/fetchai/skills/fetch_block/dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains dialogues used by the fetch_block skill.\"\"\"\n\nfrom typing import Any, Type\n\nfrom aea.protocols.base import Address, Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\nfrom aea.protocols.dialogue.base import DialogueLabel as BaseDialogueLabel\nfrom aea.skills.base import Model\n\nfrom packages.fetchai.protocols.ledger_api.dialogues import (\n    LedgerApiDialogue as BaseLedgerApiDialogue,\n)\nfrom packages.fetchai.protocols.ledger_api.dialogues import (\n    LedgerApiDialogues as BaseLedgerApiDialogues,\n)\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\n\n\nclass LedgerApiDialogue(BaseLedgerApiDialogue):\n    \"\"\"The dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    def __init__(\n        self,\n        dialogue_label: BaseDialogueLabel,\n        self_address: Address,\n        role: BaseDialogue.Role,\n        message_class: Type[LedgerApiMessage] = LedgerApiMessage,\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n        :param message_class: the message class\n        \"\"\"\n        BaseLedgerApiDialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            self_address=self_address,\n            role=role,\n            message_class=message_class,\n        )\n\n\nclass LedgerApiDialogues(Model, BaseLedgerApiDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return BaseLedgerApiDialogue.Role.AGENT\n\n        BaseLedgerApiDialogues.__init__(\n            self,\n            self_address=str(self.skill_id),\n            role_from_first_message=role_from_first_message,\n            dialogue_class=LedgerApiDialogue,\n        )\n"
  },
  {
    "path": "packages/fetchai/skills/fetch_block/handlers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains handlers for the fetch_block skill.\"\"\"\n\nfrom typing import Any, Dict, Optional, cast\n\nfrom aea.configurations.base import PublicId\nfrom aea.protocols.base import Message\nfrom aea.skills.base import Handler\n\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\nfrom packages.fetchai.skills.fetch_block.dialogues import (\n    LedgerApiDialogue,\n    LedgerApiDialogues,\n)\n\n\nclass LedgerApiHandler(Handler):\n    \"\"\"Implement the ledger api handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = LedgerApiMessage.protocol_id  # type: Optional[PublicId]\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup for the handler.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to a message.\n\n        :param message: the message\n        \"\"\"\n        self.context.logger.info(\"Handling ledger api msg\")\n\n        ledger_api_msg = cast(LedgerApiMessage, message)\n\n        # recover dialogue\n        ledger_api_dialogues = cast(\n            LedgerApiDialogues, self.context.ledger_api_dialogues\n        )\n        ledger_api_dialogue = cast(\n            Optional[LedgerApiDialogue], ledger_api_dialogues.update(ledger_api_msg)\n        )\n        if ledger_api_dialogue is None:\n            self._handle_unidentified_dialogue(ledger_api_msg)\n            return\n\n        # handle message\n        if ledger_api_msg.performative is LedgerApiMessage.Performative.STATE:\n            self._handle_state(ledger_api_msg)\n        elif ledger_api_msg.performative == LedgerApiMessage.Performative.ERROR:\n            self._handle_error(ledger_api_msg, ledger_api_dialogue)  # pragma: nocover\n        else:\n            self._handle_invalid(ledger_api_msg, ledger_api_dialogue)\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n\n    def _handle_unidentified_dialogue(self, ledger_api_msg: LedgerApiMessage) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param ledger_api_msg: the message\n        \"\"\"\n        self.context.logger.info(\n            \"received invalid ledger_api message={}, unidentified dialogue.\".format(\n                ledger_api_msg\n            )\n        )\n\n    def _handle_state(self, ledger_api_msg: LedgerApiMessage) -> None:\n        \"\"\"\n        Handle a message of state performative.\n\n        :param ledger_api_msg: the ledger api message\n        \"\"\"\n\n        self.context.logger.debug(f\"Handling ledger API message: {ledger_api_msg}\")\n\n        block_info = ledger_api_msg.state.body  # type: Dict[str, Any]\n\n        block_height_str = (\n            block_info.get(\"block\", {}).get(\"header\", {}).get(\"height\", None)\n        )\n\n        if block_height_str:\n            block_height = int(block_height_str)  # type: Optional[int]\n        else:\n            block_height = None  # pragma: nocover\n\n        if block_height is None:  # pragma: nocover\n            self.context.logger.info(\"block height not present\")\n        else:\n            self.context.logger.info(\n                \"Retrieved latest block: \" + str({\"block_height\": block_height})\n            )\n            self.context.shared_state[\"observation\"] = {\"block\": block_info}\n\n    def _handle_error(\n        self, ledger_api_msg: LedgerApiMessage, ledger_api_dialogue: LedgerApiDialogue\n    ) -> None:\n        \"\"\"\n        Handle a message of error performative.\n\n        :param ledger_api_msg: the ledger api message\n        :param ledger_api_dialogue: the ledger api dialogue\n        \"\"\"\n        self.context.logger.info(  # pragma: nocover\n            \"received ledger_api error message={} in dialogue={}.\".format(\n                ledger_api_msg, ledger_api_dialogue\n            )\n        )\n\n    def _handle_invalid(\n        self, ledger_api_msg: LedgerApiMessage, ledger_api_dialogue: LedgerApiDialogue\n    ) -> None:\n        \"\"\"\n        Handle a message of invalid performative.\n\n        :param ledger_api_msg: the ledger api message\n        :param ledger_api_dialogue: the ledger api dialogue\n        \"\"\"\n        self.context.logger.warning(\n            \"cannot handle ledger_api message of performative={} in dialogue={}.\".format(\n                ledger_api_msg.performative,\n                ledger_api_dialogue,\n            )\n        )\n"
  },
  {
    "path": "packages/fetchai/skills/fetch_block/skill.yaml",
    "content": "name: fetch_block\nauthor: fetchai\nversion: 0.12.6\ntype: skill\ndescription: Retrieve the latest block from the Fetch ledger\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: QmNi2rZ6b8pgx5Uop4FMvNagGLbzHEJUruwFzbqHMHpYtd\n  __init__.py: QmbjWVWAaMcaAiv9ynLGttHRbC5t3RGVEMUkctR2XXTkqS\n  behaviours.py: Qmdg334UUoAyvcuqv2eVKAG42fMYzB4kqTjDcyBZsWtoYJ\n  dialogues.py: Qma1KWoLRxPJMaxacGLbVEdkuvERG7UbmA4hT385KYww3A\n  handlers.py: QmYhe8XfYmbrWxqZqFiCuiSnSFpiBkKRQKo62brchcAG1s\nfingerprint_ignore_patterns: []\nconnections:\n- fetchai/ledger:0.21.5\ncontracts: []\nprotocols:\n- fetchai/ledger_api:1.1.7\nskills: []\nbehaviours:\n  fetch_block_behaviour:\n    args:\n      tick_interval: 5\n    class_name: FetchBlockBehaviour\nhandlers:\n  ledger_api:\n    args: {}\n    class_name: LedgerApiHandler\nmodels:\n  ledger_api_dialogues:\n    args: {}\n    class_name: LedgerApiDialogues\ndependencies:\n  aea-ledger-ethereum:\n    version: <2.0.0,>=1.0.0\nis_abstract: false\n"
  },
  {
    "path": "packages/fetchai/skills/fipa_dummy_buyer/README.md",
    "content": "# Fipa Dummy Buyer\n\n## Description\n\nA sample skill to interact with a simple seller using the `fetchai/fipa` protocol.\n"
  },
  {
    "path": "packages/fetchai/skills/fipa_dummy_buyer/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the implementation of the fipa dummy buyer skill.\"\"\"\n\nfrom aea.configurations.base import PublicId\n\n\nPUBLIC_ID = PublicId.from_str(\"fetchai/fipa_dummy_buyer:0.3.6\")\n"
  },
  {
    "path": "packages/fetchai/skills/fipa_dummy_buyer/behaviours.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This package contains the behaviour for the fipa dummy buyer skill.\"\"\"\n\nfrom typing import Any, cast\n\nfrom aea.helpers.search.models import Constraint, ConstraintType, Query\nfrom aea.skills.behaviours import TickerBehaviour\n\nfrom packages.fetchai.protocols.fipa.message import FipaMessage\nfrom packages.fetchai.skills.fipa_dummy_buyer.dialogues import FipaDialogues\n\n\nclass FIPAInitializerBehaviour(TickerBehaviour):\n    \"\"\"Fipa buyer cfp initializer.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"Init fipa behaviour.\"\"\"\n        if \"opponent_address\" not in kwargs:\n            raise ValueError(\"Opponent address has to be specified for behaviour!\")\n        self.opponent_address: str = cast(str, kwargs.pop(\"opponent_address\", None))\n        self.is_enabled: bool = True\n        super().__init__(**kwargs)\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup for the behaviour.\"\"\"\n\n    def act(self) -> None:\n        \"\"\"\n        Implement the act.\n\n        :return: None\n        \"\"\"\n        if not self.is_enabled:\n            return\n        dialogues = cast(FipaDialogues, self.context.fipa_dialogues)\n        cfp_msg, _ = dialogues.create(\n            counterparty=self.opponent_address,\n            performative=FipaMessage.Performative.CFP,\n            query=Query([Constraint(\"something\", ConstraintType(\">\", 1))]),\n        )\n        self.context.outbox.put_message(cfp_msg)\n        self.context.logger.info(\"CFP message sent.\")\n\n    def teardown(self) -> None:\n        \"\"\"Implement the task teardown.\"\"\"\n"
  },
  {
    "path": "packages/fetchai/skills/fipa_dummy_buyer/dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nThis module contains the classes required for dialogue management.\n\n- FipaDialogue: The dialogue class maintains state of a dialogue of type fipa and manages it.\n- FipaDialogues: The dialogues class keeps track of all dialogues of type fipa.\n\"\"\"\n\nfrom typing import Any\n\nfrom aea.common import Address\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\nfrom aea.skills.base import Model\n\nfrom packages.fetchai.protocols.fipa.dialogues import FipaDialogue as BaseFipaDialogue\nfrom packages.fetchai.protocols.fipa.dialogues import FipaDialogues as BaseFipaDialogues\n\n\nFipaDialogue = BaseFipaDialogue\n\n\nclass FipaDialogues(Model, BaseFipaDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return BaseFipaDialogue.Role.BUYER\n\n        BaseFipaDialogues.__init__(\n            self,\n            self_address=self.context.agent_address,\n            role_from_first_message=role_from_first_message,\n            dialogue_class=FipaDialogue,\n        )\n"
  },
  {
    "path": "packages/fetchai/skills/fipa_dummy_buyer/handlers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This package contains handlers for the fipa dummy buyer skill.\"\"\"\nfrom typing import Optional, cast\n\nfrom aea.configurations.base import PublicId\nfrom aea.protocols.base import Message\nfrom aea.skills.base import Handler\n\nfrom packages.fetchai.protocols.fipa.message import FipaMessage\nfrom packages.fetchai.skills.fipa_dummy_buyer.dialogues import FipaDialogues\n\n\nclass FipaBuyerHandler(Handler):\n    \"\"\"This class implements a FIPA handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = FipaMessage.protocol_id  # type: Optional[PublicId]\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"Handle an evelope.\"\"\"\n        dialogues = cast(FipaDialogues, self.context.fipa_dialogues)\n        if message.performative == FipaMessage.Performative.PROPOSE:\n            buyer_dialogue = dialogues.update(message)\n            if not buyer_dialogue:\n                self.context.logger.error(\"error on propose message dialogue update\")\n                return\n            # got a message, switch off initializer\n            self.context.behaviours.initializer.is_enabled = False\n            accept_msg = buyer_dialogue.reply(\n                performative=FipaMessage.Performative.ACCEPT, target_message=message\n            )\n            self.context.outbox.put_message(message=accept_msg)\n        elif message.performative == FipaMessage.Performative.MATCH_ACCEPT:\n            buyer_dialogue = dialogues.update(message)\n            if not buyer_dialogue:\n                self.context.logger.error(\n                    \"error on MATCH_ACCEPT message dialogue update\"\n                )\n                return\n            end_msg = buyer_dialogue.reply(\n                performative=FipaMessage.Performative.END, target_message=message\n            )\n            self.context.outbox.put_message(message=end_msg)\n            self.context.logger.info(\"FIPA INTERACTION COMPLETE\")\n        else:\n            self.context.logger.error(\n                f\"unsupported performative: {message.performative}\"\n            )\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n"
  },
  {
    "path": "packages/fetchai/skills/fipa_dummy_buyer/skill.yaml",
    "content": "name: fipa_dummy_buyer\nauthor: fetchai\nversion: 0.3.6\ntype: skill\ndescription: Sample skill for FIPA interaction as a buyer.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: QmRvuk8JPFrir9kwiT1zRBWYZvYUBrjyqMurk2UMaDBABW\n  __init__.py: QmU7MygHSwN2hqvoVvJmJpFBwLYRW3ouqLkbCA5ogtXMZ6\n  behaviours.py: QmZXfki7foJ6sjuqvbRUxAN5oiQR3LNnwx7zpMGPqtvRp9\n  dialogues.py: QmSEr25YWaUsk6pM2prJtJHQmjdM5ESwXc5JhHrcu8dVJc\n  handlers.py: QmVv174YGzezt8twwkGuPz1dFAY9TNnXVvcJSdDvZVqVAL\nfingerprint_ignore_patterns: []\nconnections: []\ncontracts: []\nprotocols:\n- fetchai/fipa:1.1.7\nskills: []\nbehaviours:\n  initializer:\n    args:\n      opponent_address: opponent_address\n      tick_interval: 5.0\n    class_name: FIPAInitializerBehaviour\nhandlers:\n  fipa:\n    args: {}\n    class_name: FipaBuyerHandler\nmodels:\n  fipa_dialogues:\n    args: {}\n    class_name: FipaDialogues\ndependencies:\n  aea-ledger-fetchai:\n    version: <2.0.0,>=1.0.0\nis_abstract: false\n"
  },
  {
    "path": "packages/fetchai/skills/generic_buyer/README.md",
    "content": "# Generic Buyer\n\n## Description\n\nThis is a generic skill for buying data.\n\nThis skill finds an agent on the sOEF which sells data, requests specific data, negotiates the price, pays the proposed amount if agreement is reach, and receives the data bought.\n\n## Behaviours\n\n- `search`: searches for data selling service on the sOEF\n- `transaction`: sequentially processes transactions' settlements on a blockchain\n\n## Handlers\n\n- `fipa`: handles `fipa` messages for negotiation\n- `ledger_api`: handles `ledger_api` messages for interacting with a ledger\n- `oef_search`: handles `oef_search` messages to manage the sellers found\n- `signing`: handles `signing` messages for transaction signing by the decision maker\n\n## Links\n\n- <a href=\"https://docs.fetch.ai/aea/generic-skills/\" target=\"_blank\">Generic Skills</a>\n- <a href=\"https://docs.fetch.ai/aea/generic-skills-step-by-step/\" target=\"_blank\">Generic Skill Step by Step Guide</a>\n"
  },
  {
    "path": "packages/fetchai/skills/generic_buyer/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the implementation of the generic buyer skill.\"\"\"\n\nfrom aea.configurations.base import PublicId\n\n\nPUBLIC_ID = PublicId.from_str(\"fetchai/generic_buyer:0.27.6\")\n"
  },
  {
    "path": "packages/fetchai/skills/generic_buyer/behaviours.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains the behaviour for the generic buyer skill.\"\"\"\n\nfrom typing import Any, List, Optional, Set, cast\n\nfrom aea.protocols.dialogue.base import DialogueLabel\nfrom aea.skills.behaviours import TickerBehaviour\n\nfrom packages.fetchai.connections.ledger.base import (\n    CONNECTION_ID as LEDGER_CONNECTION_PUBLIC_ID,\n)\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.skills.generic_buyer.dialogues import (\n    FipaDialogue,\n    LedgerApiDialogue,\n    LedgerApiDialogues,\n    OefSearchDialogues,\n)\nfrom packages.fetchai.skills.generic_buyer.strategy import GenericStrategy\n\n\nDEFAULT_MAX_PROCESSING = 120\nDEFAULT_TX_INTERVAL = 2.0\nDEFAULT_SEARCH_INTERVAL = 5.0\nLEDGER_API_ADDRESS = str(LEDGER_CONNECTION_PUBLIC_ID)\n\n\nclass GenericSearchBehaviour(TickerBehaviour):\n    \"\"\"This class implements a search behaviour.\"\"\"\n\n    def __init__(self, **kwargs: Any):\n        \"\"\"Initialize the search behaviour.\"\"\"\n        search_interval = cast(\n            float, kwargs.pop(\"search_interval\", DEFAULT_SEARCH_INTERVAL)\n        )\n        super().__init__(tick_interval=search_interval, **kwargs)\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup for the behaviour.\"\"\"\n        strategy = cast(GenericStrategy, self.context.strategy)\n        if strategy.is_ledger_tx:\n            ledger_api_dialogues = cast(\n                LedgerApiDialogues, self.context.ledger_api_dialogues\n            )\n            ledger_api_msg, _ = ledger_api_dialogues.create(\n                counterparty=LEDGER_API_ADDRESS,\n                performative=LedgerApiMessage.Performative.GET_BALANCE,\n                ledger_id=strategy.ledger_id,\n                address=cast(str, self.context.agent_addresses.get(strategy.ledger_id)),\n            )\n            self.context.outbox.put_message(message=ledger_api_msg)\n        else:\n            strategy.is_searching = True\n\n    def act(self) -> None:\n        \"\"\"Implement the act.\"\"\"\n        strategy = cast(GenericStrategy, self.context.strategy)\n        if not strategy.is_searching:\n            return\n        transaction_behaviour = cast(\n            GenericTransactionBehaviour, self.context.behaviours.transaction\n        )\n        remaining_transactions_count = len(transaction_behaviour.waiting)\n        if remaining_transactions_count > 0:\n            self.context.logger.info(\n                f\"Transaction behaviour has {remaining_transactions_count} transactions remaining. Skipping search!\"\n            )\n            return\n        strategy.update_search_query_params()\n        query = strategy.get_location_and_service_query()\n        oef_search_dialogues = cast(\n            OefSearchDialogues, self.context.oef_search_dialogues\n        )\n        oef_search_msg, _ = oef_search_dialogues.create(\n            counterparty=self.context.search_service_address,\n            performative=OefSearchMessage.Performative.SEARCH_SERVICES,\n            query=query,\n        )\n        self.context.outbox.put_message(message=oef_search_msg)\n\n    def teardown(self) -> None:\n        \"\"\"Implement the task teardown.\"\"\"\n\n\nclass GenericTransactionBehaviour(TickerBehaviour):\n    \"\"\"A behaviour to sequentially submit transactions to the blockchain.\"\"\"\n\n    def __init__(self, **kwargs: Any):\n        \"\"\"Initialize the transaction behaviour.\"\"\"\n        tx_interval = cast(\n            float, kwargs.pop(\"transaction_interval\", DEFAULT_TX_INTERVAL)\n        )\n        self.max_processing = cast(\n            float, kwargs.pop(\"max_processing\", DEFAULT_MAX_PROCESSING)\n        )\n        self.processing_time = 0.0\n        self.waiting: List[FipaDialogue] = []\n        self.processing: Optional[LedgerApiDialogue] = None\n        self.timedout: Set[DialogueLabel] = set()\n        super().__init__(tick_interval=tx_interval, **kwargs)\n\n    def setup(self) -> None:\n        \"\"\"Setup behaviour.\"\"\"\n\n    def act(self) -> None:\n        \"\"\"Implement the act.\"\"\"\n        if self.processing is not None:\n            if self.processing_time <= self.max_processing:\n                # already processing\n                self.processing_time += self.tick_interval\n                return\n            self._timeout_processing()\n        if len(self.waiting) == 0:\n            # nothing to process\n            return\n        self._start_processing()\n\n    def _start_processing(self) -> None:\n        \"\"\"Process the next transaction.\"\"\"\n        fipa_dialogue = self.waiting.pop(0)\n        self.context.logger.info(\n            f\"Processing transaction, {len(self.waiting)} transactions remaining\"\n        )\n        ledger_api_dialogues = cast(\n            LedgerApiDialogues, self.context.ledger_api_dialogues\n        )\n        ledger_api_msg, ledger_api_dialogue = ledger_api_dialogues.create(\n            counterparty=LEDGER_API_ADDRESS,\n            performative=LedgerApiMessage.Performative.GET_RAW_TRANSACTION,\n            terms=fipa_dialogue.terms,\n        )\n        ledger_api_dialogue = cast(LedgerApiDialogue, ledger_api_dialogue)\n        ledger_api_dialogue.associated_fipa_dialogue = fipa_dialogue\n        self.processing_time = 0.0\n        self.processing = ledger_api_dialogue\n        self.context.logger.info(\n            f\"requesting transfer transaction from ledger api for message={ledger_api_msg}...\"\n        )\n        self.context.outbox.put_message(message=ledger_api_msg)\n\n    def teardown(self) -> None:\n        \"\"\"Teardown behaviour.\"\"\"\n\n    def _timeout_processing(self) -> None:\n        \"\"\"Timeout processing.\"\"\"\n        if self.processing is None:\n            return\n        self.timedout.add(self.processing.dialogue_label)\n        self.waiting.append(self.processing.associated_fipa_dialogue)\n        self.processing_time = 0.0\n        self.processing = None\n\n    def finish_processing(self, ledger_api_dialogue: LedgerApiDialogue) -> None:\n        \"\"\"\n        Finish processing.\n\n        :param ledger_api_dialogue: the ledger api dialogue\n        \"\"\"\n        if self.processing == ledger_api_dialogue:\n            self.processing_time = 0.0\n            self.processing = None\n            return\n        if ledger_api_dialogue.dialogue_label not in self.timedout:\n            raise ValueError(\n                f\"Non-matching dialogues in transaction behaviour: {self.processing} and {ledger_api_dialogue}\"\n            )\n        self.timedout.remove(ledger_api_dialogue.dialogue_label)\n        self.context.logger.debug(\n            f\"Timeout dialogue in transaction processing: {ledger_api_dialogue}\"\n        )\n        # don't reset, as another might be processing\n\n    def failed_processing(self, ledger_api_dialogue: LedgerApiDialogue) -> None:\n        \"\"\"\n        Failed processing.\n\n        Currently, we retry processing indefinitely.\n\n        :param ledger_api_dialogue: the ledger api dialogue\n        \"\"\"\n        self.finish_processing(ledger_api_dialogue)\n        self.waiting.append(ledger_api_dialogue.associated_fipa_dialogue)\n"
  },
  {
    "path": "packages/fetchai/skills/generic_buyer/dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nThis module contains the classes required for dialogue management.\n\n- FipaDialogue: The dialogue class maintains state of a dialogue of type fipa and manages it.\n- FipaDialogues: The dialogues class keeps track of all dialogues of type fipa.\n- LedgerApiDialogue: The dialogue class maintains state of a dialogue of type ledger_api and manages it.\n- LedgerApiDialogues: The dialogues class keeps track of all dialogues of type ledger_api.\n\"\"\"\n\nfrom typing import Any, Optional, Type\n\nfrom aea.common import Address\nfrom aea.exceptions import AEAEnforceError, enforce\nfrom aea.helpers.transaction.base import Terms\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\nfrom aea.protocols.dialogue.base import DialogueLabel as BaseDialogueLabel\nfrom aea.skills.base import Model\n\nfrom packages.fetchai.protocols.default.dialogues import (\n    DefaultDialogue as BaseDefaultDialogue,\n)\nfrom packages.fetchai.protocols.default.dialogues import (\n    DefaultDialogues as BaseDefaultDialogues,\n)\nfrom packages.fetchai.protocols.fipa.dialogues import FipaDialogue as BaseFipaDialogue\nfrom packages.fetchai.protocols.fipa.dialogues import FipaDialogues as BaseFipaDialogues\nfrom packages.fetchai.protocols.fipa.message import FipaMessage\nfrom packages.fetchai.protocols.ledger_api.dialogues import (\n    LedgerApiDialogue as BaseLedgerApiDialogue,\n)\nfrom packages.fetchai.protocols.ledger_api.dialogues import (\n    LedgerApiDialogues as BaseLedgerApiDialogues,\n)\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\nfrom packages.fetchai.protocols.oef_search.dialogues import (\n    OefSearchDialogue as BaseOefSearchDialogue,\n)\nfrom packages.fetchai.protocols.oef_search.dialogues import (\n    OefSearchDialogues as BaseOefSearchDialogues,\n)\nfrom packages.fetchai.protocols.signing.dialogues import (\n    SigningDialogue as BaseSigningDialogue,\n)\nfrom packages.fetchai.protocols.signing.dialogues import (\n    SigningDialogues as BaseSigningDialogues,\n)\nfrom packages.fetchai.protocols.signing.message import SigningMessage\n\n\nDefaultDialogue = BaseDefaultDialogue\n\n\nclass DefaultDialogues(Model, BaseDefaultDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return DefaultDialogue.Role.AGENT\n\n        BaseDefaultDialogues.__init__(\n            self,\n            self_address=self.context.agent_address,\n            role_from_first_message=role_from_first_message,\n        )\n\n\nclass FipaDialogue(BaseFipaDialogue):\n    \"\"\"The dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    __slots__ = (\n        \"_terms\",\n        \"_associated_ledger_api_dialogue\",\n    )\n\n    def __init__(\n        self,\n        dialogue_label: BaseDialogueLabel,\n        self_address: Address,\n        role: BaseDialogue.Role,\n        message_class: Type[FipaMessage] = FipaMessage,\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n        :param message_class: the message class\n        \"\"\"\n        BaseFipaDialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            self_address=self_address,\n            role=role,\n            message_class=message_class,\n        )\n        self._terms = None  # type: Optional[Terms]\n\n    @property\n    def terms(self) -> Terms:\n        \"\"\"Get terms.\"\"\"\n        if self._terms is None:\n            raise AEAEnforceError(\"Terms not set!\")\n        return self._terms\n\n    @terms.setter\n    def terms(self, terms: Terms) -> None:\n        \"\"\"Set terms.\"\"\"\n        enforce(self._terms is None, \"Terms already set!\")\n        self._terms = terms\n\n\nclass FipaDialogues(Model, BaseFipaDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return BaseFipaDialogue.Role.BUYER\n\n        BaseFipaDialogues.__init__(\n            self,\n            self_address=self.context.agent_address,\n            role_from_first_message=role_from_first_message,\n            dialogue_class=FipaDialogue,\n        )\n\n\nclass LedgerApiDialogue(BaseLedgerApiDialogue):\n    \"\"\"The dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    __slots__ = (\"_associated_fipa_dialogue\",)\n\n    def __init__(\n        self,\n        dialogue_label: BaseDialogueLabel,\n        self_address: Address,\n        role: BaseDialogue.Role,\n        message_class: Type[LedgerApiMessage] = LedgerApiMessage,\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n        :param message_class: the message class\n        \"\"\"\n        BaseLedgerApiDialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            self_address=self_address,\n            role=role,\n            message_class=message_class,\n        )\n        self._associated_fipa_dialogue = None  # type: Optional[FipaDialogue]\n\n    @property\n    def associated_fipa_dialogue(self) -> FipaDialogue:\n        \"\"\"Get associated_fipa_dialogue.\"\"\"\n        if self._associated_fipa_dialogue is None:\n            raise AEAEnforceError(\"FipaDialogue not set!\")\n        return self._associated_fipa_dialogue\n\n    @associated_fipa_dialogue.setter\n    def associated_fipa_dialogue(self, fipa_dialogue: FipaDialogue) -> None:\n        \"\"\"Set associated_fipa_dialogue\"\"\"\n        enforce(self._associated_fipa_dialogue is None, \"FipaDialogue already set!\")\n        self._associated_fipa_dialogue = fipa_dialogue\n\n\nclass LedgerApiDialogues(Model, BaseLedgerApiDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return BaseLedgerApiDialogue.Role.AGENT\n\n        BaseLedgerApiDialogues.__init__(\n            self,\n            self_address=str(self.skill_id),\n            role_from_first_message=role_from_first_message,\n            dialogue_class=LedgerApiDialogue,\n        )\n\n\nOefSearchDialogue = BaseOefSearchDialogue\n\n\nclass OefSearchDialogues(Model, BaseOefSearchDialogues):\n    \"\"\"This class keeps track of all oef_search dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return BaseOefSearchDialogue.Role.AGENT\n\n        BaseOefSearchDialogues.__init__(\n            self,\n            self_address=str(self.skill_id),\n            role_from_first_message=role_from_first_message,\n        )\n\n\nclass SigningDialogue(BaseSigningDialogue):\n    \"\"\"The dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    __slots__ = (\"_associated_ledger_api_dialogue\",)\n\n    def __init__(\n        self,\n        dialogue_label: BaseDialogueLabel,\n        self_address: Address,\n        role: BaseDialogue.Role,\n        message_class: Type[SigningMessage] = SigningMessage,\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n        :param message_class: the message class\n        \"\"\"\n        BaseSigningDialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            self_address=self_address,\n            role=role,\n            message_class=message_class,\n        )\n        self._associated_ledger_api_dialogue = None  # type: Optional[LedgerApiDialogue]\n\n    @property\n    def associated_ledger_api_dialogue(self) -> LedgerApiDialogue:\n        \"\"\"Get associated_ledger_api_dialogue.\"\"\"\n        if self._associated_ledger_api_dialogue is None:\n            raise AEAEnforceError(\"LedgerApiDialogue not set!\")\n        return self._associated_ledger_api_dialogue\n\n    @associated_ledger_api_dialogue.setter\n    def associated_ledger_api_dialogue(\n        self, ledger_api_dialogue: LedgerApiDialogue\n    ) -> None:\n        \"\"\"Set associated_ledger_api_dialogue\"\"\"\n        enforce(\n            self._associated_ledger_api_dialogue is None,\n            \"LedgerApiDialogue already set!\",\n        )\n        self._associated_ledger_api_dialogue = ledger_api_dialogue\n\n\nclass SigningDialogues(Model, BaseSigningDialogues):\n    \"\"\"This class keeps track of all oef_search dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return BaseSigningDialogue.Role.SKILL\n\n        BaseSigningDialogues.__init__(\n            self,\n            self_address=str(self.skill_id),\n            role_from_first_message=role_from_first_message,\n            dialogue_class=SigningDialogue,\n        )\n"
  },
  {
    "path": "packages/fetchai/skills/generic_buyer/handlers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains handlers for the generic buyer skill.\"\"\"\n\nimport pprint\nfrom typing import Optional, cast\n\nfrom aea.configurations.base import PublicId\nfrom aea.crypto.ledger_apis import LedgerApis\nfrom aea.protocols.base import Message\nfrom aea.skills.base import Handler\n\nfrom packages.fetchai.connections.ledger.base import (\n    CONNECTION_ID as LEDGER_CONNECTION_PUBLIC_ID,\n)\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.protocols.fipa.message import FipaMessage\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.protocols.signing.message import SigningMessage\nfrom packages.fetchai.skills.generic_buyer.behaviours import GenericTransactionBehaviour\nfrom packages.fetchai.skills.generic_buyer.dialogues import (\n    DefaultDialogues,\n    FipaDialogue,\n    FipaDialogues,\n    LedgerApiDialogue,\n    LedgerApiDialogues,\n    OefSearchDialogue,\n    OefSearchDialogues,\n    SigningDialogue,\n    SigningDialogues,\n)\nfrom packages.fetchai.skills.generic_buyer.strategy import GenericStrategy\n\n\nLEDGER_API_ADDRESS = str(LEDGER_CONNECTION_PUBLIC_ID)\n\n\nclass GenericFipaHandler(Handler):\n    \"\"\"This class implements a FIPA handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = FipaMessage.protocol_id  # type: Optional[PublicId]\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to a message.\n\n        :param message: the message\n        \"\"\"\n        fipa_msg = cast(FipaMessage, message)\n\n        # recover dialogue\n        fipa_dialogues = cast(FipaDialogues, self.context.fipa_dialogues)\n        fipa_dialogue = cast(FipaDialogue, fipa_dialogues.update(fipa_msg))\n        if fipa_dialogue is None:\n            self._handle_unidentified_dialogue(fipa_msg)\n            return\n\n        # handle message\n        if fipa_msg.performative == FipaMessage.Performative.PROPOSE:\n            self._handle_propose(fipa_msg, fipa_dialogue)\n        elif fipa_msg.performative == FipaMessage.Performative.DECLINE:\n            self._handle_decline(fipa_msg, fipa_dialogue, fipa_dialogues)\n        elif fipa_msg.performative == FipaMessage.Performative.MATCH_ACCEPT_W_INFORM:\n            self._handle_match_accept(fipa_msg, fipa_dialogue)\n        elif fipa_msg.performative == FipaMessage.Performative.INFORM:\n            self._handle_inform(fipa_msg, fipa_dialogue, fipa_dialogues)\n        else:\n            self._handle_invalid(fipa_msg, fipa_dialogue)\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n\n    def _handle_unidentified_dialogue(self, fipa_msg: FipaMessage) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param fipa_msg: the message\n        \"\"\"\n        self.context.logger.info(\n            \"received invalid fipa message={}, unidentified dialogue.\".format(fipa_msg)\n        )\n        default_dialogues = cast(DefaultDialogues, self.context.default_dialogues)\n        default_msg, _ = default_dialogues.create(\n            counterparty=fipa_msg.sender,\n            performative=DefaultMessage.Performative.ERROR,\n            error_code=DefaultMessage.ErrorCode.INVALID_DIALOGUE,\n            error_msg=\"Invalid dialogue.\",\n            error_data={\"fipa_message\": fipa_msg.encode()},\n        )\n        self.context.outbox.put_message(message=default_msg)\n\n    def _handle_propose(\n        self, fipa_msg: FipaMessage, fipa_dialogue: FipaDialogue\n    ) -> None:\n        \"\"\"\n        Handle the propose.\n\n        :param fipa_msg: the message\n        :param fipa_dialogue: the dialogue object\n        \"\"\"\n        self.context.logger.info(\n            \"received proposal={} from sender={}\".format(\n                fipa_msg.proposal.values,\n                fipa_msg.sender[-5:],\n            )\n        )\n        strategy = cast(GenericStrategy, self.context.strategy)\n        acceptable = strategy.is_acceptable_proposal(fipa_msg.proposal)\n        affordable = strategy.is_affordable_proposal(fipa_msg.proposal)\n        if acceptable and affordable:\n            self.context.logger.info(\n                \"accepting the proposal from sender={}\".format(fipa_msg.sender[-5:])\n            )\n            terms = strategy.terms_from_proposal(fipa_msg.proposal, fipa_msg.sender)\n            fipa_dialogue.terms = terms\n            accept_msg = fipa_dialogue.reply(\n                performative=FipaMessage.Performative.ACCEPT,\n                target_message=fipa_msg,\n            )\n            self.context.outbox.put_message(message=accept_msg)\n        else:\n            self.context.logger.info(\n                \"declining the proposal from sender={}\".format(fipa_msg.sender[-5:])\n            )\n            decline_msg = fipa_dialogue.reply(\n                performative=FipaMessage.Performative.DECLINE,\n                target_message=fipa_msg,\n            )\n            self.context.outbox.put_message(message=decline_msg)\n\n    def _handle_decline(\n        self,\n        fipa_msg: FipaMessage,\n        fipa_dialogue: FipaDialogue,\n        fipa_dialogues: FipaDialogues,\n    ) -> None:\n        \"\"\"\n        Handle the decline.\n\n        :param fipa_msg: the message\n        :param fipa_dialogue: the fipa dialogue\n        :param fipa_dialogues: the fipa dialogues\n        \"\"\"\n        self.context.logger.info(\n            \"received DECLINE from sender={}\".format(fipa_msg.sender[-5:])\n        )\n        target_message = fipa_dialogue.get_message_by_id(fipa_msg.target)\n\n        if not target_message:\n            raise ValueError(\"Can not find target message!\")  # pragma: nocover\n\n        declined_performative = target_message.performative\n\n        if declined_performative == FipaMessage.Performative.CFP:\n            fipa_dialogues.dialogue_stats.add_dialogue_endstate(\n                FipaDialogue.EndState.DECLINED_CFP, fipa_dialogue.is_self_initiated\n            )\n        if declined_performative == FipaMessage.Performative.ACCEPT:\n            fipa_dialogues.dialogue_stats.add_dialogue_endstate(\n                FipaDialogue.EndState.DECLINED_ACCEPT, fipa_dialogue.is_self_initiated\n            )\n\n    def _handle_match_accept(\n        self, fipa_msg: FipaMessage, fipa_dialogue: FipaDialogue\n    ) -> None:\n        \"\"\"\n        Handle the match accept.\n\n        :param fipa_msg: the message\n        :param fipa_dialogue: the dialogue object\n        \"\"\"\n        self.context.logger.info(\n            \"received MATCH_ACCEPT_W_INFORM from sender={} with info={}\".format(\n                fipa_msg.sender[-5:], fipa_msg.info\n            )\n        )\n        strategy = cast(GenericStrategy, self.context.strategy)\n        if strategy.is_ledger_tx:\n            transfer_address = fipa_msg.info.get(\"address\", None)\n            if transfer_address is not None and isinstance(transfer_address, str):\n                fipa_dialogue.terms.counterparty_address = (  # pragma: nocover\n                    transfer_address\n                )\n\n            tx_behaviour = cast(\n                GenericTransactionBehaviour, self.context.behaviours.transaction\n            )\n            tx_behaviour.waiting.append(fipa_dialogue)\n        else:\n            inform_msg = fipa_dialogue.reply(\n                performative=FipaMessage.Performative.INFORM,\n                target_message=fipa_msg,\n                info={\"Done\": \"Sending payment via bank transfer\"},\n            )\n            self.context.outbox.put_message(message=inform_msg)\n            self.context.logger.info(\n                \"informing counterparty={} of payment.\".format(fipa_msg.sender[-5:])\n            )\n\n    def _handle_inform(\n        self,\n        fipa_msg: FipaMessage,\n        fipa_dialogue: FipaDialogue,\n        fipa_dialogues: FipaDialogues,\n    ) -> None:\n        \"\"\"\n        Handle the match inform.\n\n        :param fipa_msg: the message\n        :param fipa_dialogue: the fipa dialogue\n        :param fipa_dialogues: the fipa dialogues\n        \"\"\"\n        self.context.logger.info(\n            \"received INFORM from sender={}\".format(fipa_msg.sender[-5:])\n        )\n        if len(fipa_msg.info.keys()) >= 1:\n            data = fipa_msg.info\n            data_string = pprint.pformat(data)[:1000]\n            self.context.logger.info(f\"received the following data={data_string}\")\n            fipa_dialogues.dialogue_stats.add_dialogue_endstate(\n                FipaDialogue.EndState.SUCCESSFUL, fipa_dialogue.is_self_initiated\n            )\n            strategy = cast(GenericStrategy, self.context.strategy)\n            strategy.successful_trade_with_counterparty(fipa_msg.sender, data)\n        else:\n            self.context.logger.info(\n                \"received no data from sender={}\".format(fipa_msg.sender[-5:])\n            )\n\n    def _handle_invalid(\n        self, fipa_msg: FipaMessage, fipa_dialogue: FipaDialogue\n    ) -> None:\n        \"\"\"\n        Handle a fipa message of invalid performative.\n\n        :param fipa_msg: the message\n        :param fipa_dialogue: the fipa dialogue\n        \"\"\"\n        self.context.logger.warning(\n            \"cannot handle fipa message of performative={} in dialogue={}.\".format(\n                fipa_msg.performative, fipa_dialogue\n            )\n        )\n\n\nclass GenericOefSearchHandler(Handler):\n    \"\"\"This class implements an OEF search handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = OefSearchMessage.protocol_id  # type: Optional[PublicId]\n\n    def setup(self) -> None:\n        \"\"\"Call to setup the handler.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to a message.\n\n        :param message: the message\n        \"\"\"\n        oef_search_msg = cast(OefSearchMessage, message)\n\n        # recover dialogue\n        oef_search_dialogues = cast(\n            OefSearchDialogues, self.context.oef_search_dialogues\n        )\n        oef_search_dialogue = cast(\n            Optional[OefSearchDialogue], oef_search_dialogues.update(oef_search_msg)\n        )\n        if oef_search_dialogue is None:\n            self._handle_unidentified_dialogue(oef_search_msg)\n            return\n\n        # handle message\n        if oef_search_msg.performative is OefSearchMessage.Performative.OEF_ERROR:\n            self._handle_error(oef_search_msg, oef_search_dialogue)\n        elif oef_search_msg.performative is OefSearchMessage.Performative.SEARCH_RESULT:\n            self._handle_search(oef_search_msg, oef_search_dialogue)\n        else:\n            self._handle_invalid(oef_search_msg, oef_search_dialogue)\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n\n    def _handle_unidentified_dialogue(self, oef_search_msg: OefSearchMessage) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param oef_search_msg: the message\n        \"\"\"\n        self.context.logger.info(\n            \"received invalid oef_search message={}, unidentified dialogue.\".format(\n                oef_search_msg\n            )\n        )\n\n    def _handle_error(\n        self, oef_search_msg: OefSearchMessage, oef_search_dialogue: OefSearchDialogue\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param oef_search_msg: the oef search message\n        :param oef_search_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.info(\n            \"received oef_search error message={} in dialogue={}.\".format(\n                oef_search_msg, oef_search_dialogue\n            )\n        )\n\n    def _handle_search(\n        self, oef_search_msg: OefSearchMessage, oef_search_dialogue: OefSearchDialogue\n    ) -> None:\n        \"\"\"\n        Handle the search response.\n\n        :param oef_search_msg: the oef search message\n        :param oef_search_dialogue: the dialogue\n        \"\"\"\n        if len(oef_search_msg.agents) == 0:\n            self.context.logger.info(\n                f\"found no agents in dialogue={oef_search_dialogue}, continue searching.\"\n            )\n            return\n        strategy = cast(GenericStrategy, self.context.strategy)\n        if strategy.is_stop_searching_on_result:\n            self.context.logger.info(\n                \"found agents={}, stopping search.\".format(\n                    list(map(lambda x: x[-5:], oef_search_msg.agents)),\n                )\n            )\n            strategy.is_searching = False  # stopping search\n        else:\n            self.context.logger.info(\n                \"found agents={}.\".format(\n                    list(map(lambda x: x[-5:], oef_search_msg.agents)),\n                )\n            )\n        query = strategy.get_service_query()\n        fipa_dialogues = cast(FipaDialogues, self.context.fipa_dialogues)\n        counterparties = strategy.get_acceptable_counterparties(oef_search_msg.agents)\n        for counterparty in counterparties:\n            cfp_msg, _ = fipa_dialogues.create(\n                counterparty=counterparty,\n                performative=FipaMessage.Performative.CFP,\n                query=query,\n            )\n            self.context.outbox.put_message(message=cfp_msg)\n            self.context.logger.info(\n                \"sending CFP to agent={}\".format(counterparty[-5:])\n            )\n\n    def _handle_invalid(\n        self, oef_search_msg: OefSearchMessage, oef_search_dialogue: OefSearchDialogue\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param oef_search_msg: the oef search message\n        :param oef_search_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.warning(\n            \"cannot handle oef_search message of performative={} in dialogue={}.\".format(\n                oef_search_msg.performative,\n                oef_search_dialogue,\n            )\n        )\n\n\nclass GenericSigningHandler(Handler):\n    \"\"\"Implement the signing handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = SigningMessage.protocol_id  # type: Optional[PublicId]\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup for the handler.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to a message.\n\n        :param message: the message\n        \"\"\"\n        signing_msg = cast(SigningMessage, message)\n\n        # recover dialogue\n        signing_dialogues = cast(SigningDialogues, self.context.signing_dialogues)\n        signing_dialogue = cast(\n            Optional[SigningDialogue], signing_dialogues.update(signing_msg)\n        )\n        if signing_dialogue is None:\n            self._handle_unidentified_dialogue(signing_msg)\n            return\n\n        # handle message\n        if signing_msg.performative is SigningMessage.Performative.SIGNED_TRANSACTION:\n            self._handle_signed_transaction(signing_msg, signing_dialogue)\n        elif signing_msg.performative is SigningMessage.Performative.ERROR:\n            self._handle_error(signing_msg, signing_dialogue)\n        else:\n            self._handle_invalid(signing_msg, signing_dialogue)\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n\n    def _handle_unidentified_dialogue(self, signing_msg: SigningMessage) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param signing_msg: the message\n        \"\"\"\n        self.context.logger.info(\n            \"received invalid signing message={}, unidentified dialogue.\".format(\n                signing_msg\n            )\n        )\n\n    def _handle_signed_transaction(\n        self, signing_msg: SigningMessage, signing_dialogue: SigningDialogue\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param signing_msg: the signing message\n        :param signing_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.info(\"transaction signing was successful.\")\n        ledger_api_dialogue = signing_dialogue.associated_ledger_api_dialogue\n        last_ledger_api_msg = ledger_api_dialogue.last_incoming_message\n        if last_ledger_api_msg is None:\n            raise ValueError(\"Could not retrieve last message in ledger api dialogue\")\n        ledger_api_msg = ledger_api_dialogue.reply(\n            performative=LedgerApiMessage.Performative.SEND_SIGNED_TRANSACTION,\n            target_message=last_ledger_api_msg,\n            signed_transaction=signing_msg.signed_transaction,\n        )\n        self.context.outbox.put_message(message=ledger_api_msg)\n        self.context.logger.info(\"sending transaction to ledger.\")\n\n    def _handle_error(\n        self, signing_msg: SigningMessage, signing_dialogue: SigningDialogue\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param signing_msg: the signing message\n        :param signing_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.info(\n            \"transaction signing was not successful. Error_code={} in dialogue={}\".format(\n                signing_msg.error_code, signing_dialogue\n            )\n        )\n        signing_msg_ = cast(\n            Optional[SigningMessage], signing_dialogue.last_outgoing_message\n        )\n        if (\n            signing_msg_ is not None\n            and signing_msg_.performative\n            == SigningMessage.Performative.SIGN_TRANSACTION\n        ):\n            tx_behaviour = cast(\n                GenericTransactionBehaviour, self.context.behaviours.transaction\n            )\n            ledger_api_dialogue = signing_dialogue.associated_ledger_api_dialogue\n            tx_behaviour.failed_processing(ledger_api_dialogue)\n\n    def _handle_invalid(\n        self, signing_msg: SigningMessage, signing_dialogue: SigningDialogue\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param signing_msg: the signing message\n        :param signing_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.warning(\n            \"cannot handle signing message of performative={} in dialogue={}.\".format(\n                signing_msg.performative, signing_dialogue\n            )\n        )\n\n\nclass GenericLedgerApiHandler(Handler):\n    \"\"\"Implement the ledger handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = LedgerApiMessage.protocol_id  # type: Optional[PublicId]\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup for the handler.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to a message.\n\n        :param message: the message\n        \"\"\"\n        ledger_api_msg = cast(LedgerApiMessage, message)\n\n        # recover dialogue\n        ledger_api_dialogues = cast(\n            LedgerApiDialogues, self.context.ledger_api_dialogues\n        )\n        ledger_api_dialogue = cast(\n            Optional[LedgerApiDialogue], ledger_api_dialogues.update(ledger_api_msg)\n        )\n        if ledger_api_dialogue is None:\n            self._handle_unidentified_dialogue(ledger_api_msg)\n            return\n\n        # handle message\n        if ledger_api_msg.performative is LedgerApiMessage.Performative.BALANCE:\n            self._handle_balance(ledger_api_msg)\n        elif (\n            ledger_api_msg.performative is LedgerApiMessage.Performative.RAW_TRANSACTION\n        ):\n            self._handle_raw_transaction(ledger_api_msg, ledger_api_dialogue)\n        elif (\n            ledger_api_msg.performative\n            == LedgerApiMessage.Performative.TRANSACTION_DIGEST\n        ):\n            self._handle_transaction_digest(ledger_api_msg, ledger_api_dialogue)\n        elif (\n            ledger_api_msg.performative\n            == LedgerApiMessage.Performative.TRANSACTION_RECEIPT\n        ):\n            self._handle_transaction_receipt(ledger_api_msg, ledger_api_dialogue)\n        elif ledger_api_msg.performative == LedgerApiMessage.Performative.ERROR:\n            self._handle_error(ledger_api_msg, ledger_api_dialogue)\n        else:\n            self._handle_invalid(ledger_api_msg, ledger_api_dialogue)\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n\n    def _handle_unidentified_dialogue(self, ledger_api_msg: LedgerApiMessage) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param ledger_api_msg: the message\n        \"\"\"\n        self.context.logger.info(\n            \"received invalid ledger_api message={}, unidentified dialogue.\".format(\n                ledger_api_msg\n            )\n        )\n\n    def _handle_balance(self, ledger_api_msg: LedgerApiMessage) -> None:\n        \"\"\"\n        Handle a message of balance performative.\n\n        :param ledger_api_msg: the ledger api message\n        \"\"\"\n        strategy = cast(GenericStrategy, self.context.strategy)\n        if ledger_api_msg.balance > 0:\n            self.context.logger.info(\n                \"starting balance on {} ledger={}.\".format(\n                    strategy.ledger_id,\n                    ledger_api_msg.balance,\n                )\n            )\n            strategy.balance = ledger_api_msg.balance\n            strategy.is_searching = True\n        else:\n            self.context.logger.warning(\n                f\"you have no starting balance on {strategy.ledger_id} ledger! Stopping skill {self.skill_id}.\"\n            )\n            self.context.is_active = False\n\n    def _handle_raw_transaction(\n        self, ledger_api_msg: LedgerApiMessage, ledger_api_dialogue: LedgerApiDialogue\n    ) -> None:\n        \"\"\"\n        Handle a message of raw_transaction performative.\n\n        :param ledger_api_msg: the ledger api message\n        :param ledger_api_dialogue: the ledger api dialogue\n        \"\"\"\n        self.context.logger.info(\"received raw transaction={}\".format(ledger_api_msg))\n        signing_dialogues = cast(SigningDialogues, self.context.signing_dialogues)\n        signing_msg, signing_dialogue = signing_dialogues.create(\n            counterparty=self.context.decision_maker_address,\n            performative=SigningMessage.Performative.SIGN_TRANSACTION,\n            raw_transaction=ledger_api_msg.raw_transaction,\n            terms=ledger_api_dialogue.associated_fipa_dialogue.terms,\n        )\n        signing_dialogue = cast(SigningDialogue, signing_dialogue)\n        signing_dialogue.associated_ledger_api_dialogue = ledger_api_dialogue\n        self.context.decision_maker_message_queue.put_nowait(signing_msg)\n        self.context.logger.info(\n            \"proposing the transaction to the decision maker. Waiting for confirmation ...\"\n        )\n\n    def _handle_transaction_digest(\n        self, ledger_api_msg: LedgerApiMessage, ledger_api_dialogue: LedgerApiDialogue\n    ) -> None:\n        \"\"\"\n        Handle a message of transaction_digest performative.\n\n        :param ledger_api_msg: the ledger api message\n        :param ledger_api_dialogue: the ledger api dialogue\n        \"\"\"\n        self.context.logger.info(\n            \"transaction was successfully submitted. Transaction digest={}\".format(\n                ledger_api_msg.transaction_digest\n            )\n        )\n        ledger_api_msg_ = ledger_api_dialogue.reply(\n            performative=LedgerApiMessage.Performative.GET_TRANSACTION_RECEIPT,\n            target_message=ledger_api_msg,\n            transaction_digest=ledger_api_msg.transaction_digest,\n        )\n        self.context.logger.info(\"checking transaction is settled.\")\n        self.context.outbox.put_message(message=ledger_api_msg_)\n\n    def _handle_transaction_receipt(\n        self, ledger_api_msg: LedgerApiMessage, ledger_api_dialogue: LedgerApiDialogue\n    ) -> None:\n        \"\"\"\n        Handle a message of balance performative.\n\n        :param ledger_api_msg: the ledger api message\n        :param ledger_api_dialogue: the ledger api dialogue\n        \"\"\"\n        fipa_dialogue = ledger_api_dialogue.associated_fipa_dialogue\n        is_settled = LedgerApis.is_transaction_settled(\n            fipa_dialogue.terms.ledger_id, ledger_api_msg.transaction_receipt.receipt\n        )\n        tx_behaviour = cast(\n            GenericTransactionBehaviour, self.context.behaviours.transaction\n        )\n        if is_settled:\n            tx_behaviour.finish_processing(ledger_api_dialogue)\n            ledger_api_msg_ = cast(\n                Optional[LedgerApiMessage], ledger_api_dialogue.last_outgoing_message\n            )\n            if ledger_api_msg_ is None:\n                raise ValueError(  # pragma: nocover\n                    \"Could not retrieve last ledger_api message\"\n                )\n            fipa_msg = cast(Optional[FipaMessage], fipa_dialogue.last_incoming_message)\n            if fipa_msg is None:\n                raise ValueError(\"Could not retrieve last fipa message\")\n            inform_msg = fipa_dialogue.reply(\n                performative=FipaMessage.Performative.INFORM,\n                target_message=fipa_msg,\n                info={\"transaction_digest\": ledger_api_msg_.transaction_digest.body},\n            )\n            self.context.outbox.put_message(message=inform_msg)\n            self.context.logger.info(\n                \"transaction confirmed, informing counterparty={} of transaction digest.\".format(\n                    fipa_dialogue.dialogue_label.dialogue_opponent_addr[-5:],\n                )\n            )\n        else:\n            tx_behaviour.failed_processing(ledger_api_dialogue)\n            self.context.logger.info(\n                \"transaction_receipt={} not settled or not valid, aborting\".format(\n                    ledger_api_msg.transaction_receipt\n                )\n            )\n\n    def _handle_error(\n        self, ledger_api_msg: LedgerApiMessage, ledger_api_dialogue: LedgerApiDialogue\n    ) -> None:\n        \"\"\"\n        Handle a message of error performative.\n\n        :param ledger_api_msg: the ledger api message\n        :param ledger_api_dialogue: the ledger api dialogue\n        \"\"\"\n        self.context.logger.info(\n            \"received ledger_api error message={} in dialogue={}.\".format(\n                ledger_api_msg, ledger_api_dialogue\n            )\n        )\n        ledger_api_msg_ = cast(\n            Optional[LedgerApiMessage], ledger_api_dialogue.last_outgoing_message\n        )\n        if (\n            ledger_api_msg_ is not None\n            and ledger_api_msg_.performative\n            != LedgerApiMessage.Performative.GET_BALANCE\n        ):\n            tx_behaviour = cast(\n                GenericTransactionBehaviour, self.context.behaviours.transaction\n            )\n            tx_behaviour.failed_processing(ledger_api_dialogue)\n\n    def _handle_invalid(\n        self, ledger_api_msg: LedgerApiMessage, ledger_api_dialogue: LedgerApiDialogue\n    ) -> None:\n        \"\"\"\n        Handle a message of invalid performative.\n\n        :param ledger_api_msg: the ledger api message\n        :param ledger_api_dialogue: the ledger api dialogue\n        \"\"\"\n        self.context.logger.warning(\n            \"cannot handle ledger_api message of performative={} in dialogue={}.\".format(\n                ledger_api_msg.performative,\n                ledger_api_dialogue,\n            )\n        )\n"
  },
  {
    "path": "packages/fetchai/skills/generic_buyer/skill.yaml",
    "content": "name: generic_buyer\nauthor: fetchai\nversion: 0.27.6\ntype: skill\ndescription: The weather client skill implements the skill to purchase weather data.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: QmRUURLxvnfRR8Qq1UBeecFRoKiJLxQJj5GtUyKP7SyhTu\n  __init__.py: QmYCvgy81AT3SjWrUKCnjAnmdenDCrdFRE91BhW8tBuLDL\n  behaviours.py: QmVydJUVMEG4o2WNFdPN1bo8Rv46c7Mpt8K5jQkF2fpPLz\n  dialogues.py: QmZ8yqZRJ8KhFXcfA5H7XWBTyqZf9tCyCR22HVUpfb6aJs\n  handlers.py: QmQfGNxqDncaP4ekRKZvjE4SE8P5KSLGFDSLSQbWbM3xaA\n  strategy.py: QmWZfWVGpbxuZTWPigAzK6mrrHfgwEbsvf41SNq9FggpKr\nfingerprint_ignore_patterns: []\nconnections:\n- fetchai/ledger:0.21.5\ncontracts: []\nprotocols:\n- fetchai/default:1.1.7\n- fetchai/fipa:1.1.7\n- fetchai/ledger_api:1.1.7\n- fetchai/oef_search:1.1.7\n- fetchai/signing:1.1.7\nskills: []\nbehaviours:\n  search:\n    args:\n      search_interval: 5\n    class_name: GenericSearchBehaviour\n  transaction:\n    args:\n      max_processing: 420\n      transaction_interval: 2\n    class_name: GenericTransactionBehaviour\nhandlers:\n  fipa:\n    args: {}\n    class_name: GenericFipaHandler\n  ledger_api:\n    args: {}\n    class_name: GenericLedgerApiHandler\n  oef_search:\n    args: {}\n    class_name: GenericOefSearchHandler\n  signing:\n    args: {}\n    class_name: GenericSigningHandler\nmodels:\n  default_dialogues:\n    args: {}\n    class_name: DefaultDialogues\n  fipa_dialogues:\n    args: {}\n    class_name: FipaDialogues\n  ledger_api_dialogues:\n    args: {}\n    class_name: LedgerApiDialogues\n  oef_search_dialogues:\n    args: {}\n    class_name: OefSearchDialogues\n  signing_dialogues:\n    args: {}\n    class_name: SigningDialogues\n  strategy:\n    args:\n      is_ledger_tx: true\n      location:\n        latitude: 51.5194\n        longitude: 0.127\n      max_negotiations: 1\n      max_quantity: 100\n      max_tx_fee: 3550000000000000\n      max_unit_price: 20\n      min_quantity: 1\n      search_query:\n        constraint_type: ==\n        search_key: seller_service\n        search_value: generic_service\n      search_radius: 5.0\n      service_id: generic_service\n      stop_searching_on_result: true\n    class_name: GenericStrategy\ndependencies:\n  aea-ledger-fetchai:\n    version: <2.0.0,>=1.0.0\nis_abstract: true\n"
  },
  {
    "path": "packages/fetchai/skills/generic_buyer/strategy.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the strategy class.\"\"\"\n\nfrom typing import Any, Dict, List, Tuple\n\nfrom aea.common import Address\nfrom aea.exceptions import enforce\nfrom aea.helpers.search.generic import SIMPLE_SERVICE_MODEL\nfrom aea.helpers.search.models import (\n    Constraint,\n    ConstraintType,\n    Description,\n    Location,\n    Query,\n)\nfrom aea.helpers.transaction.base import Terms\nfrom aea.skills.base import Model\n\n\nDEFAULT_IS_LEDGER_TX = True\n\nDEFAULT_MAX_UNIT_PRICE = 5\nDEFAULT_MAX_TX_FEE = 2\nDEFAULT_SERVICE_ID = \"generic_service\"\nDEFAULT_MIN_QUANTITY = 1\nDEFAULT_MAX_QUANTITY = 100\n\nDEFAULT_LOCATION = {\"longitude\": 0.1270, \"latitude\": 51.5194}\nDEFAULT_SEARCH_QUERY = {\n    \"search_key\": \"seller_service\",\n    \"search_value\": \"generic_service\",\n    \"constraint_type\": \"==\",\n}\nDEFAULT_SEARCH_RADIUS = 5.0\n\nDEFAULT_MAX_NEGOTIATIONS = 2\n\n\nclass GenericStrategy(Model):\n    \"\"\"This class defines a strategy for the agent.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize the strategy of the agent.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        ledger_id = kwargs.pop(\"ledger_id\", None)\n        currency_id = kwargs.pop(\"currency_id\", None)\n        self._is_ledger_tx = kwargs.pop(\"is_ledger_tx\", DEFAULT_IS_LEDGER_TX)\n\n        self._max_unit_price = kwargs.pop(\"max_unit_price\", DEFAULT_MAX_UNIT_PRICE)\n        self._min_quantity = kwargs.pop(\"min_quantity\", DEFAULT_MIN_QUANTITY)\n        self._max_quantity = kwargs.pop(\"max_quantity\", DEFAULT_MAX_QUANTITY)\n        self._max_tx_fee = kwargs.pop(\"max_tx_fee\", DEFAULT_MAX_TX_FEE)\n        self._service_id = kwargs.pop(\"service_id\", DEFAULT_SERVICE_ID)\n\n        self._search_query = kwargs.pop(\"search_query\", DEFAULT_SEARCH_QUERY)\n        location = kwargs.pop(\"location\", DEFAULT_LOCATION)\n        self._agent_location = Location(\n            latitude=location[\"latitude\"], longitude=location[\"longitude\"]\n        )\n        self._radius = kwargs.pop(\"search_radius\", DEFAULT_SEARCH_RADIUS)\n\n        self._max_negotiations = kwargs.pop(\n            \"max_negotiations\", DEFAULT_MAX_NEGOTIATIONS\n        )\n        self._is_stop_searching_on_result = kwargs.pop(\"stop_searching_on_result\", True)\n\n        super().__init__(**kwargs)\n        self._ledger_id = (\n            ledger_id if ledger_id is not None else self.context.default_ledger_id\n        )\n        if currency_id is None:\n            currency_id = self.context.currency_denominations.get(self._ledger_id, None)\n            enforce(\n                currency_id is not None,\n                f\"Currency denomination for ledger_id={self._ledger_id} not specified.\",\n            )\n        self._currency_id = currency_id\n        self._is_searching = False\n        self._balance = 0\n\n    @property\n    def ledger_id(self) -> str:\n        \"\"\"Get the ledger id.\"\"\"\n        return self._ledger_id\n\n    @property\n    def is_ledger_tx(self) -> bool:\n        \"\"\"Check whether or not tx are settled on a ledger.\"\"\"\n        return self._is_ledger_tx\n\n    @property\n    def is_stop_searching_on_result(self) -> bool:\n        \"\"\"Check if search is stopped on result.\"\"\"\n        return self._is_stop_searching_on_result\n\n    @property\n    def is_searching(self) -> bool:\n        \"\"\"Check if the agent is searching.\"\"\"\n        return self._is_searching\n\n    @is_searching.setter\n    def is_searching(self, is_searching: bool) -> None:\n        \"\"\"Check if the agent is searching.\"\"\"\n        enforce(isinstance(is_searching, bool), \"Can only set bool on is_searching!\")\n        self._is_searching = is_searching\n\n    @property\n    def balance(self) -> int:\n        \"\"\"Get the balance.\"\"\"\n        return self._balance\n\n    @balance.setter\n    def balance(self, balance: int) -> None:\n        \"\"\"Set the balance.\"\"\"\n        self._balance = balance\n\n    @property\n    def max_negotiations(self) -> int:\n        \"\"\"Get the maximum number of negotiations the agent can start.\"\"\"\n        return self._max_negotiations\n\n    def get_location_and_service_query(self) -> Query:\n        \"\"\"\n        Get the location and service query of the agent.\n\n        :return: the query\n        \"\"\"\n        close_to_my_service = Constraint(\n            \"location\", ConstraintType(\"distance\", (self._agent_location, self._radius))\n        )\n        service_key_filter = Constraint(\n            self._search_query[\"search_key\"],\n            ConstraintType(\n                self._search_query[\"constraint_type\"],\n                self._search_query[\"search_value\"],\n            ),\n        )\n        query = Query(\n            [close_to_my_service, service_key_filter],\n        )\n        return query\n\n    def get_service_query(self) -> Query:\n        \"\"\"\n        Get the service query of the agent.\n\n        :return: the query\n        \"\"\"\n        service_key_filter = Constraint(\n            self._search_query[\"search_key\"],\n            ConstraintType(\n                self._search_query[\"constraint_type\"],\n                self._search_query[\"search_value\"],\n            ),\n        )\n        query = Query([service_key_filter], model=SIMPLE_SERVICE_MODEL)\n        return query\n\n    def is_acceptable_proposal(self, proposal: Description) -> bool:\n        \"\"\"\n        Check whether it is an acceptable proposal.\n\n        :param proposal: a description\n        :return: whether it is acceptable\n        \"\"\"\n        result = (\n            all(\n                key in proposal.values\n                for key in [\n                    \"ledger_id\",\n                    \"currency_id\",\n                    \"price\",\n                    \"service_id\",\n                    \"quantity\",\n                    \"tx_nonce\",\n                ]\n            )\n            and proposal.values[\"ledger_id\"] == self.ledger_id\n            and proposal.values[\"price\"] > 0\n            and proposal.values[\"quantity\"] >= self._min_quantity\n            and proposal.values[\"quantity\"] <= self._max_quantity\n            and proposal.values[\"price\"]\n            <= proposal.values[\"quantity\"] * self._max_unit_price\n            and proposal.values[\"currency_id\"] == self._currency_id\n            and proposal.values[\"service_id\"] == self._service_id\n            and isinstance(proposal.values[\"tx_nonce\"], str)\n            and proposal.values[\"tx_nonce\"] != \"\"\n        )\n        return result\n\n    def is_affordable_proposal(self, proposal: Description) -> bool:\n        \"\"\"\n        Check whether it is an affordable proposal.\n\n        :param proposal: a description\n        :return: whether it is affordable\n        \"\"\"\n        if self.is_ledger_tx:\n            payable = proposal.values.get(\"price\", 0) + self._max_tx_fee\n            result = self.balance >= payable\n        else:\n            result = True\n        return result\n\n    def get_acceptable_counterparties(\n        self, counterparties: Tuple[str, ...]\n    ) -> Tuple[str, ...]:\n        \"\"\"\n        Process counterparties and drop unacceptable ones.\n\n        :param counterparties: a tuple of counterparties\n        :return: list of counterparties\n        \"\"\"\n        valid_counterparties: List[str] = []\n        for idx, counterparty in enumerate(counterparties):\n            if idx < self.max_negotiations:\n                valid_counterparties.append(counterparty)\n        return tuple(valid_counterparties)\n\n    def terms_from_proposal(\n        self, proposal: Description, counterparty_address: Address\n    ) -> Terms:\n        \"\"\"\n        Get the terms from a proposal.\n\n        :param proposal: the proposal\n        :param counterparty_address: the counterparty\n        :return: terms\n        \"\"\"\n        buyer_address = self.context.agent_addresses[proposal.values[\"ledger_id\"]]\n        terms = Terms(\n            ledger_id=proposal.values[\"ledger_id\"],\n            sender_address=buyer_address,\n            counterparty_address=counterparty_address,\n            amount_by_currency_id={\n                proposal.values[\"currency_id\"]: -proposal.values[\"price\"]\n            },\n            quantities_by_good_id={\n                proposal.values[\"service_id\"]: proposal.values[\"quantity\"]\n            },\n            is_sender_payable_tx_fee=True,\n            nonce=proposal.values[\"tx_nonce\"],\n            fee_by_currency_id={proposal.values[\"currency_id\"]: self._max_tx_fee},\n        )\n        return terms\n\n    def successful_trade_with_counterparty(\n        self, counterparty: str, data: Dict[str, str]\n    ) -> None:\n        \"\"\"\n        Do something on successful trade.\n\n        :param counterparty: the counterparty address\n        :param data: the data\n        \"\"\"\n\n    def update_search_query_params(self) -> None:\n        \"\"\"Update agent location and query for search.\"\"\"\n"
  },
  {
    "path": "packages/fetchai/skills/generic_seller/README.md",
    "content": "# Generic Seller\n\n## Description\n\nThis is a generic skill for selling data.\n\nThis skill registers some data selling service on the sOEF. It can be requested (for example by an agent with the `generic_buyer` skill) to provide specific data. It then negotiates the price and delivers the data after it receives payment.\n\n## Behaviours\n\n- `service_registration`: registers data selling service on the sOEF\n\n## Handlers\n\n- `fipa`: handles `fipa` messages for negotiation\n- `ledger_api`: handles `ledger_api` messages for interacting with a ledger\n- `oef_search`: handles `oef_search` messages if service registration on the sOEF is unsuccessful\n\n## Links\n\n- <a href=\"https://docs.fetch.ai/aea/generic-skills/\" target=\"_blank\">Generic Skills</a>\n- <a href=\"https://docs.fetch.ai/aea/generic-skills-step-by-step/\" target=\"_blank\">Generic Skill Step by Step Guide</a>\n"
  },
  {
    "path": "packages/fetchai/skills/generic_seller/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the implementation of the generic seller skill.\"\"\"\n\nfrom aea.configurations.base import PublicId\n\n\nPUBLIC_ID = PublicId.from_str(\"fetchai/generic_seller:0.28.6\")\n"
  },
  {
    "path": "packages/fetchai/skills/generic_seller/behaviours.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains the behaviour of a generic seller AEA.\"\"\"\n\nfrom typing import Any, Optional, cast\n\nfrom aea.helpers.search.models import Description\nfrom aea.skills.behaviours import TickerBehaviour\n\nfrom packages.fetchai.connections.ledger.base import (\n    CONNECTION_ID as LEDGER_CONNECTION_PUBLIC_ID,\n)\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.skills.generic_seller.dialogues import (\n    LedgerApiDialogues,\n    OefSearchDialogues,\n)\nfrom packages.fetchai.skills.generic_seller.strategy import GenericStrategy\n\n\nDEFAULT_SERVICES_INTERVAL = 60.0\nDEFAULT_MAX_SOEF_REGISTRATION_RETRIES = 5\nLEDGER_API_ADDRESS = str(LEDGER_CONNECTION_PUBLIC_ID)\n\n\nclass GenericServiceRegistrationBehaviour(TickerBehaviour):\n    \"\"\"This class implements a behaviour.\"\"\"\n\n    def __init__(self, **kwargs: Any):\n        \"\"\"Initialise the behaviour.\"\"\"\n        services_interval = kwargs.pop(\n            \"services_interval\", DEFAULT_SERVICES_INTERVAL\n        )  # type: int\n        self._max_soef_registration_retries = kwargs.pop(\n            \"max_soef_registration_retries\", DEFAULT_MAX_SOEF_REGISTRATION_RETRIES\n        )  # type: int\n        super().__init__(tick_interval=services_interval, **kwargs)\n\n        self.failed_registration_msg = None  # type: Optional[OefSearchMessage]\n        self._nb_retries = 0\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup.\"\"\"\n        strategy = cast(GenericStrategy, self.context.strategy)\n        if strategy.is_ledger_tx:\n            ledger_api_dialogues = cast(\n                LedgerApiDialogues, self.context.ledger_api_dialogues\n            )\n            ledger_api_msg, _ = ledger_api_dialogues.create(\n                counterparty=LEDGER_API_ADDRESS,\n                performative=LedgerApiMessage.Performative.GET_BALANCE,\n                ledger_id=strategy.ledger_id,\n                address=cast(str, self.context.agent_addresses.get(strategy.ledger_id)),\n            )\n            self.context.outbox.put_message(message=ledger_api_msg)\n        self._register_agent()\n\n    def act(self) -> None:\n        \"\"\"Implement the act.\"\"\"\n        self._retry_failed_registration()\n\n    def teardown(self) -> None:\n        \"\"\"Implement the task teardown.\"\"\"\n        self._unregister_service()\n        self._unregister_agent()\n\n    def _retry_failed_registration(self) -> None:\n        \"\"\"Retry a failed registration.\"\"\"\n        if self.failed_registration_msg is not None:\n            self._nb_retries += 1\n            if self._nb_retries > self._max_soef_registration_retries:\n                self.context.is_active = False\n                return\n\n            oef_search_dialogues = cast(\n                OefSearchDialogues, self.context.oef_search_dialogues\n            )\n            oef_search_msg, _ = oef_search_dialogues.create(\n                counterparty=self.failed_registration_msg.to,\n                performative=self.failed_registration_msg.performative,\n                service_description=self.failed_registration_msg.service_description,\n            )\n            self.context.outbox.put_message(message=oef_search_msg)\n            self.context.logger.info(\n                f\"Retrying registration on SOEF. Retry {self._nb_retries} out of {self._max_soef_registration_retries}.\"\n            )\n\n            self.failed_registration_msg = None\n\n    def _register(self, description: Description, logger_msg: str) -> None:\n        \"\"\"\n        Register something on the SOEF.\n\n        :param description: the description of what is being registered\n        :param logger_msg: the logger message to print after the registration\n        \"\"\"\n        oef_search_dialogues = cast(\n            OefSearchDialogues, self.context.oef_search_dialogues\n        )\n        oef_search_msg, _ = oef_search_dialogues.create(\n            counterparty=self.context.search_service_address,\n            performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n            service_description=description,\n        )\n        self.context.outbox.put_message(message=oef_search_msg)\n        self.context.logger.info(logger_msg)\n\n    def _register_agent(self) -> None:\n        \"\"\"Register the agent's location.\"\"\"\n        strategy = cast(GenericStrategy, self.context.strategy)\n        description = strategy.get_location_description()\n        self._register(description, \"registering agent on SOEF.\")\n\n    def register_service(self) -> None:\n        \"\"\"Register the agent's service.\"\"\"\n        strategy = cast(GenericStrategy, self.context.strategy)\n        description = strategy.get_register_service_description()\n        self._register(description, \"registering agent's service on the SOEF.\")\n\n    def register_genus(self) -> None:\n        \"\"\"Register the agent's personality genus.\"\"\"\n        strategy = cast(GenericStrategy, self.context.strategy)\n        description = strategy.get_register_personality_description()\n        self._register(\n            description, \"registering agent's personality genus on the SOEF.\"\n        )\n\n    def register_classification(self) -> None:\n        \"\"\"Register the agent's personality classification.\"\"\"\n        strategy = cast(GenericStrategy, self.context.strategy)\n        description = strategy.get_register_classification_description()\n        self._register(\n            description, \"registering agent's personality classification on the SOEF.\"\n        )\n\n    def _unregister_service(self) -> None:\n        \"\"\"Unregister service from the SOEF.\"\"\"\n        strategy = cast(GenericStrategy, self.context.strategy)\n        description = strategy.get_unregister_service_description()\n        oef_search_dialogues = cast(\n            OefSearchDialogues, self.context.oef_search_dialogues\n        )\n        oef_search_msg, _ = oef_search_dialogues.create(\n            counterparty=self.context.search_service_address,\n            performative=OefSearchMessage.Performative.UNREGISTER_SERVICE,\n            service_description=description,\n        )\n        self.context.outbox.put_message(message=oef_search_msg)\n        self.context.logger.info(\"unregistering service from SOEF.\")\n\n    def _unregister_agent(self) -> None:\n        \"\"\"Unregister agent from the SOEF.\"\"\"\n        strategy = cast(GenericStrategy, self.context.strategy)\n        description = strategy.get_location_description()\n        oef_search_dialogues = cast(\n            OefSearchDialogues, self.context.oef_search_dialogues\n        )\n        oef_search_msg, _ = oef_search_dialogues.create(\n            counterparty=self.context.search_service_address,\n            performative=OefSearchMessage.Performative.UNREGISTER_SERVICE,\n            service_description=description,\n        )\n        self.context.outbox.put_message(message=oef_search_msg)\n        self.context.logger.info(\"unregistering agent from SOEF.\")\n"
  },
  {
    "path": "packages/fetchai/skills/generic_seller/dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nThis module contains the classes required for dialogue management.\n\n- Dialogue: The dialogue class maintains state of a dialogue and manages it.\n- Dialogues: The dialogues class keeps track of all dialogues.\n\"\"\"\n\nfrom typing import Any, Dict, Optional, Type\n\nfrom aea.common import Address\nfrom aea.exceptions import AEAEnforceError, enforce\nfrom aea.helpers.transaction.base import Terms\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\nfrom aea.protocols.dialogue.base import DialogueLabel as BaseDialogueLabel\nfrom aea.skills.base import Model\n\nfrom packages.fetchai.protocols.default.dialogues import (\n    DefaultDialogue as BaseDefaultDialogue,\n)\nfrom packages.fetchai.protocols.default.dialogues import (\n    DefaultDialogues as BaseDefaultDialogues,\n)\nfrom packages.fetchai.protocols.fipa.dialogues import FipaDialogue as BaseFipaDialogue\nfrom packages.fetchai.protocols.fipa.dialogues import FipaDialogues as BaseFipaDialogues\nfrom packages.fetchai.protocols.fipa.message import FipaMessage\nfrom packages.fetchai.protocols.ledger_api.dialogues import (\n    LedgerApiDialogue as BaseLedgerApiDialogue,\n)\nfrom packages.fetchai.protocols.ledger_api.dialogues import (\n    LedgerApiDialogues as BaseLedgerApiDialogues,\n)\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\nfrom packages.fetchai.protocols.oef_search.dialogues import (\n    OefSearchDialogue as BaseOefSearchDialogue,\n)\nfrom packages.fetchai.protocols.oef_search.dialogues import (\n    OefSearchDialogues as BaseOefSearchDialogues,\n)\n\n\nDefaultDialogue = BaseDefaultDialogue\n\n\nclass DefaultDialogues(Model, BaseDefaultDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return DefaultDialogue.Role.AGENT\n\n        BaseDefaultDialogues.__init__(\n            self,\n            self_address=self.context.agent_address,\n            role_from_first_message=role_from_first_message,\n        )\n\n\nclass FipaDialogue(BaseFipaDialogue):\n    \"\"\"The dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    __slots__ = (\"data_for_sale\", \"_terms\")\n\n    def __init__(\n        self,\n        dialogue_label: BaseDialogueLabel,\n        self_address: Address,\n        role: BaseDialogue.Role,\n        message_class: Type[FipaMessage] = FipaMessage,\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n        :param message_class: the message class\n        \"\"\"\n        BaseFipaDialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            self_address=self_address,\n            role=role,\n            message_class=message_class,\n        )\n        self.data_for_sale = None  # type: Optional[Dict[str, str]]\n        self._terms = None  # type: Optional[Terms]\n\n    @property\n    def terms(self) -> Terms:\n        \"\"\"Get terms.\"\"\"\n        if self._terms is None:\n            raise AEAEnforceError(\"Terms not set!\")\n        return self._terms\n\n    @terms.setter\n    def terms(self, terms: Terms) -> None:\n        \"\"\"Set terms.\"\"\"\n        enforce(self._terms is None, \"Terms already set!\")\n        self._terms = terms\n\n\nclass FipaDialogues(Model, BaseFipaDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return FipaDialogue.Role.SELLER\n\n        BaseFipaDialogues.__init__(\n            self,\n            self_address=self.context.agent_address,\n            role_from_first_message=role_from_first_message,\n            dialogue_class=FipaDialogue,\n        )\n\n\nclass LedgerApiDialogue(BaseLedgerApiDialogue):\n    \"\"\"The dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    __slots__ = (\"_associated_fipa_dialogue\",)\n\n    def __init__(\n        self,\n        dialogue_label: BaseDialogueLabel,\n        self_address: Address,\n        role: BaseDialogue.Role,\n        message_class: Type[LedgerApiMessage] = LedgerApiMessage,\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n        :param message_class: the message class\n        \"\"\"\n        BaseLedgerApiDialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            self_address=self_address,\n            role=role,\n            message_class=message_class,\n        )\n        self._associated_fipa_dialogue = None  # type: Optional[FipaDialogue]\n\n    @property\n    def associated_fipa_dialogue(self) -> FipaDialogue:\n        \"\"\"Get associated_fipa_dialogue.\"\"\"\n        if self._associated_fipa_dialogue is None:\n            raise AEAEnforceError(\"FipaDialogue not set!\")\n        return self._associated_fipa_dialogue\n\n    @associated_fipa_dialogue.setter\n    def associated_fipa_dialogue(self, fipa_dialogue: FipaDialogue) -> None:\n        \"\"\"Set associated_fipa_dialogue\"\"\"\n        enforce(self._associated_fipa_dialogue is None, \"FipaDialogue already set!\")\n        self._associated_fipa_dialogue = fipa_dialogue\n\n\nclass LedgerApiDialogues(Model, BaseLedgerApiDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return BaseLedgerApiDialogue.Role.AGENT\n\n        BaseLedgerApiDialogues.__init__(\n            self,\n            self_address=str(self.skill_id),\n            role_from_first_message=role_from_first_message,\n            dialogue_class=LedgerApiDialogue,\n        )\n\n\nOefSearchDialogue = BaseOefSearchDialogue\n\n\nclass OefSearchDialogues(Model, BaseOefSearchDialogues):\n    \"\"\"This class keeps track of all oef_search dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return BaseOefSearchDialogue.Role.AGENT\n\n        BaseOefSearchDialogues.__init__(\n            self,\n            self_address=str(self.skill_id),\n            role_from_first_message=role_from_first_message,\n        )\n"
  },
  {
    "path": "packages/fetchai/skills/generic_seller/handlers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains the handlers of a generic seller AEA.\"\"\"\n\nfrom typing import Optional, cast\n\nfrom aea.configurations.base import PublicId\nfrom aea.crypto.ledger_apis import LedgerApis\nfrom aea.helpers.transaction.base import TransactionDigest\nfrom aea.protocols.base import Message\nfrom aea.skills.base import Handler\n\nfrom packages.fetchai.connections.ledger.base import (\n    CONNECTION_ID as LEDGER_CONNECTION_PUBLIC_ID,\n)\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.protocols.fipa.message import FipaMessage\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.skills.generic_seller.behaviours import (\n    GenericServiceRegistrationBehaviour,\n)\nfrom packages.fetchai.skills.generic_seller.dialogues import (\n    DefaultDialogues,\n    FipaDialogue,\n    FipaDialogues,\n    LedgerApiDialogue,\n    LedgerApiDialogues,\n    OefSearchDialogue,\n    OefSearchDialogues,\n)\nfrom packages.fetchai.skills.generic_seller.strategy import GenericStrategy\n\n\nLEDGER_API_ADDRESS = str(LEDGER_CONNECTION_PUBLIC_ID)\n\n\nclass GenericFipaHandler(Handler):\n    \"\"\"This class implements a FIPA handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = FipaMessage.protocol_id  # type: Optional[PublicId]\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup for the handler.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to a message.\n\n        :param message: the message\n        \"\"\"\n        fipa_msg = cast(FipaMessage, message)\n\n        # recover dialogue\n        fipa_dialogues = cast(FipaDialogues, self.context.fipa_dialogues)\n        fipa_dialogue = cast(FipaDialogue, fipa_dialogues.update(fipa_msg))\n        if fipa_dialogue is None:\n            self._handle_unidentified_dialogue(fipa_msg)\n            return\n\n        # handle message\n        if fipa_msg.performative == FipaMessage.Performative.CFP:\n            self._handle_cfp(fipa_msg, fipa_dialogue)\n        elif fipa_msg.performative == FipaMessage.Performative.DECLINE:\n            self._handle_decline(fipa_msg, fipa_dialogue, fipa_dialogues)\n        elif fipa_msg.performative == FipaMessage.Performative.ACCEPT:\n            self._handle_accept(fipa_msg, fipa_dialogue)\n        elif fipa_msg.performative == FipaMessage.Performative.INFORM:\n            self._handle_inform(fipa_msg, fipa_dialogue)\n        else:\n            self._handle_invalid(fipa_msg, fipa_dialogue)\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n\n    def _handle_unidentified_dialogue(self, fipa_msg: FipaMessage) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param fipa_msg: the message\n        \"\"\"\n        self.context.logger.info(\n            \"received invalid fipa message={}, unidentified dialogue.\".format(fipa_msg)\n        )\n        default_dialogues = cast(DefaultDialogues, self.context.default_dialogues)\n        default_msg, _ = default_dialogues.create(\n            counterparty=fipa_msg.sender,\n            performative=DefaultMessage.Performative.ERROR,\n            error_code=DefaultMessage.ErrorCode.INVALID_DIALOGUE,\n            error_msg=\"Invalid dialogue.\",\n            error_data={\"fipa_message\": fipa_msg.encode()},\n        )\n        self.context.outbox.put_message(message=default_msg)\n\n    def _handle_cfp(self, fipa_msg: FipaMessage, fipa_dialogue: FipaDialogue) -> None:\n        \"\"\"\n        Handle the CFP.\n\n        If the CFP matches the supplied services then send a PROPOSE, otherwise send a DECLINE.\n\n        :param fipa_msg: the message\n        :param fipa_dialogue: the dialogue object\n        \"\"\"\n        self.context.logger.info(\n            \"received CFP from sender={}\".format(fipa_msg.sender[-5:])\n        )\n        strategy = cast(GenericStrategy, self.context.strategy)\n        if strategy.is_matching_supply(fipa_msg.query):\n            proposal, terms, data_for_sale = strategy.generate_proposal_terms_and_data(\n                fipa_msg.query, fipa_msg.sender\n            )\n            fipa_dialogue.data_for_sale = data_for_sale\n            fipa_dialogue.terms = terms\n            self.context.logger.info(\n                \"sending a PROPOSE with proposal={} to sender={}\".format(\n                    proposal.values, fipa_msg.sender[-5:]\n                )\n            )\n            proposal_msg = fipa_dialogue.reply(\n                performative=FipaMessage.Performative.PROPOSE,\n                target_message=fipa_msg,\n                proposal=proposal,\n            )\n            self.context.outbox.put_message(message=proposal_msg)\n        else:\n            self.context.logger.info(\n                \"declined the CFP from sender={}\".format(fipa_msg.sender[-5:])\n            )\n            decline_msg = fipa_dialogue.reply(\n                performative=FipaMessage.Performative.DECLINE,\n                target_message=fipa_msg,\n            )\n            self.context.outbox.put_message(message=decline_msg)\n\n    def _handle_decline(\n        self,\n        fipa_msg: FipaMessage,\n        fipa_dialogue: FipaDialogue,\n        fipa_dialogues: FipaDialogues,\n    ) -> None:\n        \"\"\"\n        Handle the DECLINE.\n\n        Close the dialogue.\n\n        :param fipa_msg: the message\n        :param fipa_dialogue: the dialogue object\n        :param fipa_dialogues: the dialogues object\n        \"\"\"\n        self.context.logger.info(\n            \"received DECLINE from sender={}\".format(fipa_msg.sender[-5:])\n        )\n        fipa_dialogues.dialogue_stats.add_dialogue_endstate(\n            FipaDialogue.EndState.DECLINED_PROPOSE, fipa_dialogue.is_self_initiated\n        )\n\n    def _handle_accept(\n        self, fipa_msg: FipaMessage, fipa_dialogue: FipaDialogue\n    ) -> None:\n        \"\"\"\n        Handle the ACCEPT.\n\n        Respond with a MATCH_ACCEPT_W_INFORM which contains the address to send the funds to.\n\n        :param fipa_msg: the message\n        :param fipa_dialogue: the dialogue object\n        \"\"\"\n        self.context.logger.info(\n            \"received ACCEPT from sender={}\".format(fipa_msg.sender[-5:])\n        )\n        info = {\"address\": fipa_dialogue.terms.sender_address}\n        match_accept_msg = fipa_dialogue.reply(\n            performative=FipaMessage.Performative.MATCH_ACCEPT_W_INFORM,\n            target_message=fipa_msg,\n            info=info,\n        )\n        self.context.logger.info(\n            \"sending MATCH_ACCEPT_W_INFORM to sender={} with info={}\".format(\n                fipa_msg.sender[-5:],\n                info,\n            )\n        )\n        self.context.outbox.put_message(message=match_accept_msg)\n\n    def _handle_inform(\n        self, fipa_msg: FipaMessage, fipa_dialogue: FipaDialogue\n    ) -> None:\n        \"\"\"\n        Handle the INFORM.\n\n        If the INFORM message contains the transaction_digest then verify that it is settled, otherwise do nothing.\n        If the transaction is settled, send the data, otherwise do nothing.\n\n        :param fipa_msg: the message\n        :param fipa_dialogue: the dialogue object\n        \"\"\"\n        self.context.logger.info(\n            \"received INFORM from sender={}\".format(fipa_msg.sender[-5:])\n        )\n\n        strategy = cast(GenericStrategy, self.context.strategy)\n        if strategy.is_ledger_tx and \"transaction_digest\" in fipa_msg.info.keys():\n            self.context.logger.info(\n                \"checking whether transaction={} has been received ...\".format(\n                    fipa_msg.info[\"transaction_digest\"]\n                )\n            )\n            ledger_api_dialogues = cast(\n                LedgerApiDialogues, self.context.ledger_api_dialogues\n            )\n            ledger_api_msg, ledger_api_dialogue = ledger_api_dialogues.create(\n                counterparty=LEDGER_API_ADDRESS,\n                performative=LedgerApiMessage.Performative.GET_TRANSACTION_RECEIPT,\n                transaction_digest=TransactionDigest(\n                    fipa_dialogue.terms.ledger_id, fipa_msg.info[\"transaction_digest\"]\n                ),\n            )\n            ledger_api_dialogue = cast(LedgerApiDialogue, ledger_api_dialogue)\n            ledger_api_dialogue.associated_fipa_dialogue = fipa_dialogue\n            self.context.outbox.put_message(message=ledger_api_msg)\n        elif strategy.is_ledger_tx:\n            self.context.logger.warning(\n                \"did not receive transaction digest from sender={}.\".format(\n                    fipa_msg.sender[-5:]\n                )\n            )\n        elif not strategy.is_ledger_tx and \"Done\" in fipa_msg.info.keys():\n            inform_msg = fipa_dialogue.reply(\n                performative=FipaMessage.Performative.INFORM,\n                target_message=fipa_msg,\n                info=fipa_dialogue.data_for_sale,\n            )\n            self.context.outbox.put_message(message=inform_msg)\n            fipa_dialogues = cast(FipaDialogues, self.context.fipa_dialogues)\n            fipa_dialogues.dialogue_stats.add_dialogue_endstate(\n                FipaDialogue.EndState.SUCCESSFUL, fipa_dialogue.is_self_initiated\n            )\n            self.context.logger.info(\n                \"transaction confirmed, sending data={} to buyer={}.\".format(\n                    fipa_dialogue.data_for_sale,\n                    fipa_msg.sender[-5:],\n                )\n            )\n        else:\n            self.context.logger.warning(\n                \"did not receive transaction confirmation from sender={}.\".format(\n                    fipa_msg.sender[-5:]\n                )\n            )\n\n    def _handle_invalid(\n        self, fipa_msg: FipaMessage, fipa_dialogue: FipaDialogue\n    ) -> None:\n        \"\"\"\n        Handle a fipa message of invalid performative.\n\n        :param fipa_msg: the message\n        :param fipa_dialogue: the dialogue object\n        \"\"\"\n        self.context.logger.warning(\n            \"cannot handle fipa message of performative={} in dialogue={}.\".format(\n                fipa_msg.performative, fipa_dialogue\n            )\n        )\n\n\nclass GenericLedgerApiHandler(Handler):\n    \"\"\"Implement the ledger handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = LedgerApiMessage.protocol_id  # type: Optional[PublicId]\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup for the handler.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to a message.\n\n        :param message: the message\n        \"\"\"\n        ledger_api_msg = cast(LedgerApiMessage, message)\n\n        # recover dialogue\n        ledger_api_dialogues = cast(\n            LedgerApiDialogues, self.context.ledger_api_dialogues\n        )\n        ledger_api_dialogue = cast(\n            Optional[LedgerApiDialogue], ledger_api_dialogues.update(ledger_api_msg)\n        )\n        if ledger_api_dialogue is None:\n            self._handle_unidentified_dialogue(ledger_api_msg)\n            return\n\n        # handle message\n        if ledger_api_msg.performative is LedgerApiMessage.Performative.BALANCE:\n            self._handle_balance(ledger_api_msg)\n        elif (\n            ledger_api_msg.performative\n            is LedgerApiMessage.Performative.TRANSACTION_RECEIPT\n        ):\n            self._handle_transaction_receipt(ledger_api_msg, ledger_api_dialogue)\n        elif ledger_api_msg.performative == LedgerApiMessage.Performative.ERROR:\n            self._handle_error(ledger_api_msg, ledger_api_dialogue)\n        else:\n            self._handle_invalid(ledger_api_msg, ledger_api_dialogue)\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n\n    def _handle_unidentified_dialogue(self, ledger_api_msg: LedgerApiMessage) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param ledger_api_msg: the message\n        \"\"\"\n        self.context.logger.info(\n            \"received invalid ledger_api message={}, unidentified dialogue.\".format(\n                ledger_api_msg\n            )\n        )\n\n    def _handle_balance(self, ledger_api_msg: LedgerApiMessage) -> None:\n        \"\"\"\n        Handle a message of balance performative.\n\n        :param ledger_api_msg: the ledger api message\n        \"\"\"\n        self.context.logger.info(\n            \"starting balance on {} ledger={}.\".format(\n                ledger_api_msg.ledger_id,\n                ledger_api_msg.balance,\n            )\n        )\n\n    def _handle_transaction_receipt(\n        self, ledger_api_msg: LedgerApiMessage, ledger_api_dialogue: LedgerApiDialogue\n    ) -> None:\n        \"\"\"\n        Handle a message of balance performative.\n\n        :param ledger_api_msg: the ledger api message\n        :param ledger_api_dialogue: the ledger api dialogue\n        \"\"\"\n        fipa_dialogue = ledger_api_dialogue.associated_fipa_dialogue\n        is_settled = LedgerApis.is_transaction_settled(\n            fipa_dialogue.terms.ledger_id, ledger_api_msg.transaction_receipt.receipt\n        )\n        is_valid = LedgerApis.is_transaction_valid(\n            fipa_dialogue.terms.ledger_id,\n            ledger_api_msg.transaction_receipt.transaction,\n            fipa_dialogue.terms.sender_address,\n            fipa_dialogue.terms.counterparty_address,\n            fipa_dialogue.terms.nonce,\n            fipa_dialogue.terms.counterparty_payable_amount,\n        )\n        if is_settled and is_valid:\n            last_message = cast(\n                Optional[FipaMessage], fipa_dialogue.last_incoming_message\n            )\n            if last_message is None:\n                raise ValueError(\"Cannot retrieve last fipa message.\")\n            inform_msg = fipa_dialogue.reply(\n                performative=FipaMessage.Performative.INFORM,\n                target_message=last_message,\n                info=fipa_dialogue.data_for_sale,\n            )\n            self.context.outbox.put_message(message=inform_msg)\n            fipa_dialogues = cast(FipaDialogues, self.context.fipa_dialogues)\n            fipa_dialogues.dialogue_stats.add_dialogue_endstate(\n                FipaDialogue.EndState.SUCCESSFUL, fipa_dialogue.is_self_initiated\n            )\n            self.context.logger.info(\n                \"transaction confirmed, sending data={} to buyer={}.\".format(\n                    fipa_dialogue.data_for_sale,\n                    last_message.sender[-5:],\n                )\n            )\n        else:\n            self.context.logger.info(\n                \"transaction_receipt={} not settled or not valid, aborting\".format(\n                    ledger_api_msg.transaction_receipt\n                )\n            )\n\n    def _handle_error(\n        self, ledger_api_msg: LedgerApiMessage, ledger_api_dialogue: LedgerApiDialogue\n    ) -> None:\n        \"\"\"\n        Handle a message of error performative.\n\n        :param ledger_api_msg: the ledger api message\n        :param ledger_api_dialogue: the ledger api dialogue\n        \"\"\"\n        self.context.logger.info(\n            \"received ledger_api error message={} in dialogue={}.\".format(\n                ledger_api_msg, ledger_api_dialogue\n            )\n        )\n\n    def _handle_invalid(\n        self, ledger_api_msg: LedgerApiMessage, ledger_api_dialogue: LedgerApiDialogue\n    ) -> None:\n        \"\"\"\n        Handle a message of invalid performative.\n\n        :param ledger_api_msg: the ledger api message\n        :param ledger_api_dialogue: the ledger api dialogue\n        \"\"\"\n        self.context.logger.warning(\n            \"cannot handle ledger_api message of performative={} in dialogue={}.\".format(\n                ledger_api_msg.performative,\n                ledger_api_dialogue,\n            )\n        )\n\n\nclass GenericOefSearchHandler(Handler):\n    \"\"\"This class implements an OEF search handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = OefSearchMessage.protocol_id  # type: Optional[PublicId]\n\n    def setup(self) -> None:\n        \"\"\"Call to setup the handler.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to a message.\n\n        :param message: the message\n        \"\"\"\n        oef_search_msg = cast(OefSearchMessage, message)\n\n        # recover dialogue\n        oef_search_dialogues = cast(\n            OefSearchDialogues, self.context.oef_search_dialogues\n        )\n        oef_search_dialogue = cast(\n            Optional[OefSearchDialogue], oef_search_dialogues.update(oef_search_msg)\n        )\n        if oef_search_dialogue is None:\n            self._handle_unidentified_dialogue(oef_search_msg)\n            return\n\n        # handle message\n        if oef_search_msg.performative == OefSearchMessage.Performative.SUCCESS:\n            self._handle_success(oef_search_msg, oef_search_dialogue)\n        elif oef_search_msg.performative == OefSearchMessage.Performative.OEF_ERROR:\n            self._handle_error(oef_search_msg, oef_search_dialogue)\n        else:\n            self._handle_invalid(oef_search_msg, oef_search_dialogue)\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n\n    def _handle_unidentified_dialogue(self, oef_search_msg: OefSearchMessage) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param oef_search_msg: the message\n        \"\"\"\n        self.context.logger.info(\n            \"received invalid oef_search message={}, unidentified dialogue.\".format(\n                oef_search_msg\n            )\n        )\n\n    def _handle_success(\n        self,\n        oef_search_success_msg: OefSearchMessage,\n        oef_search_dialogue: OefSearchDialogue,\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param oef_search_success_msg: the oef search message\n        :param oef_search_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.info(\n            \"received oef_search success message={} in dialogue={}.\".format(\n                oef_search_success_msg, oef_search_dialogue\n            )\n        )\n        target_message = cast(\n            OefSearchMessage,\n            oef_search_dialogue.get_message_by_id(oef_search_success_msg.target),\n        )\n        if (\n            target_message.performative\n            == OefSearchMessage.Performative.REGISTER_SERVICE\n        ):\n            description = target_message.service_description\n            data_model_name = description.data_model.name\n            registration_behaviour = cast(\n                GenericServiceRegistrationBehaviour,\n                self.context.behaviours.service_registration,\n            )\n            if \"location_agent\" in data_model_name:\n                registration_behaviour.register_service()\n            elif \"set_service_key\" in data_model_name:\n                registration_behaviour.register_genus()\n            elif (\n                \"personality_agent\" in data_model_name\n                and description.values[\"piece\"] == \"genus\"\n            ):\n                registration_behaviour.register_classification()\n            elif (\n                \"personality_agent\" in data_model_name\n                and description.values[\"piece\"] == \"classification\"\n            ):\n                self.context.logger.info(\n                    \"the agent, with its genus and classification, and its service are successfully registered on the SOEF.\"\n                )\n            else:\n                self.context.logger.warning(\n                    f\"received soef SUCCESS message as a reply to the following unexpected message: {target_message}\"\n                )\n\n    def _handle_error(\n        self,\n        oef_search_error_msg: OefSearchMessage,\n        oef_search_dialogue: OefSearchDialogue,\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param oef_search_error_msg: the oef search message\n        :param oef_search_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.info(\n            \"received oef_search error message={} in dialogue={}.\".format(\n                oef_search_error_msg, oef_search_dialogue\n            )\n        )\n        target_message = cast(\n            OefSearchMessage,\n            oef_search_dialogue.get_message_by_id(oef_search_error_msg.target),\n        )\n        if (\n            target_message.performative\n            == OefSearchMessage.Performative.REGISTER_SERVICE\n        ):\n            registration_behaviour = cast(\n                GenericServiceRegistrationBehaviour,\n                self.context.behaviours.service_registration,\n            )\n            registration_behaviour.failed_registration_msg = target_message\n\n    def _handle_invalid(\n        self, oef_search_msg: OefSearchMessage, oef_search_dialogue: OefSearchDialogue\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param oef_search_msg: the oef search message\n        :param oef_search_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.warning(\n            \"cannot handle oef_search message of performative={} in dialogue={}.\".format(\n                oef_search_msg.performative,\n                oef_search_dialogue,\n            )\n        )\n"
  },
  {
    "path": "packages/fetchai/skills/generic_seller/skill.yaml",
    "content": "name: generic_seller\nauthor: fetchai\nversion: 0.28.6\ntype: skill\ndescription: The weather station skill implements the functionality to sell weather\n  data.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: QmfQM11g1zjQYDUmia3eFmeckab2FDBCGwG8QDRZfEG4RY\n  __init__.py: QmSSfdZmyPsMVbLsS3bjTFL3CCGousHYM3QkJHw6AY1efL\n  behaviours.py: QmNmZHrFPVninUyyNDWng6o9fBLZ2vJmVLRxP1fzMapLai\n  dialogues.py: QmXcoYGuAdAD5HerA2khymJicPqf9VgtZ9YS6zx4mx8MWy\n  handlers.py: QmaXoWxvFBMdtqhChLc3eaWPEsDpur3jwmfJ8Z8DkNrMaD\n  strategy.py: QmZU5jR78iZ515rMdxUE5KiPRwo9UhDw4yXkZguzN8hnBd\nfingerprint_ignore_patterns: []\nconnections:\n- fetchai/ledger:0.21.5\ncontracts: []\nprotocols:\n- fetchai/default:1.1.7\n- fetchai/fipa:1.1.7\n- fetchai/ledger_api:1.1.7\n- fetchai/oef_search:1.1.7\nskills: []\nbehaviours:\n  service_registration:\n    args:\n      max_soef_registration_retries: 5\n      services_interval: 20\n    class_name: GenericServiceRegistrationBehaviour\nhandlers:\n  fipa:\n    args: {}\n    class_name: GenericFipaHandler\n  ledger_api:\n    args: {}\n    class_name: GenericLedgerApiHandler\n  oef_search:\n    args: {}\n    class_name: GenericOefSearchHandler\nmodels:\n  default_dialogues:\n    args: {}\n    class_name: DefaultDialogues\n  fipa_dialogues:\n    args: {}\n    class_name: FipaDialogues\n  ledger_api_dialogues:\n    args: {}\n    class_name: LedgerApiDialogues\n  oef_search_dialogues:\n    args: {}\n    class_name: OefSearchDialogues\n  strategy:\n    args:\n      classification:\n        piece: classification\n        value: seller\n      data_for_sale:\n        generic: data\n      has_data_source: false\n      is_ledger_tx: true\n      location:\n        latitude: 51.5194\n        longitude: 0.127\n      personality_data:\n        piece: genus\n        value: data\n      service_data:\n        key: seller_service\n        value: generic_service\n      service_id: generic_service\n      unit_price: 10\n    class_name: GenericStrategy\ndependencies:\n  aea-ledger-fetchai:\n    version: <2.0.0,>=1.0.0\nis_abstract: true\n"
  },
  {
    "path": "packages/fetchai/skills/generic_seller/strategy.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the strategy class.\"\"\"\n\nimport uuid\nfrom typing import Any, Dict, Optional, Tuple\n\nfrom aea.common import Address\nfrom aea.crypto.ledger_apis import LedgerApis\nfrom aea.exceptions import enforce\nfrom aea.helpers.search.generic import (\n    AGENT_LOCATION_MODEL,\n    AGENT_PERSONALITY_MODEL,\n    AGENT_REMOVE_SERVICE_MODEL,\n    AGENT_SET_SERVICE_MODEL,\n    SIMPLE_SERVICE_MODEL,\n)\nfrom aea.helpers.search.models import Description, Location, Query\nfrom aea.helpers.transaction.base import Terms\nfrom aea.skills.base import Model\n\n\nDEFAULT_IS_LEDGER_TX = True\n\nDEFAULT_UNIT_PRICE = 4\nDEFAULT_SERVICE_ID = \"generic_service\"\n\nDEFAULT_LOCATION = {\"longitude\": 0.1270, \"latitude\": 51.5194}\nDEFAULT_SERVICE_DATA = {\"key\": \"seller_service\", \"value\": \"generic_service\"}\nDEFAULT_PERSONALITY_DATA = {\"piece\": \"genus\", \"value\": \"data\"}\nDEFAULT_CLASSIFICATION = {\"piece\": \"classification\", \"value\": \"seller\"}\n\nDEFAULT_HAS_DATA_SOURCE = False\nDEFAULT_DATA_FOR_SALE = {\n    \"some_generic_data_key\": \"some_generic_data_value\"\n}  # type: Optional[Dict[str, Any]]\n\n\nclass GenericStrategy(Model):\n    \"\"\"This class defines a strategy for the agent.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize the strategy of the agent.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        ledger_id = kwargs.pop(\"ledger_id\", None)\n        currency_id = kwargs.pop(\"currency_id\", None)\n        self._is_ledger_tx = kwargs.pop(\"is_ledger_tx\", DEFAULT_IS_LEDGER_TX)\n\n        self._unit_price = kwargs.pop(\"unit_price\", DEFAULT_UNIT_PRICE)\n        self._service_id = kwargs.pop(\"service_id\", DEFAULT_SERVICE_ID)\n\n        location = kwargs.pop(\"location\", DEFAULT_LOCATION)\n        self._agent_location = {\n            \"location\": Location(\n                latitude=location[\"latitude\"], longitude=location[\"longitude\"]\n            )\n        }\n        self._set_personality_data = kwargs.pop(\n            \"personality_data\", DEFAULT_PERSONALITY_DATA\n        )\n        enforce(\n            len(self._set_personality_data) == 2\n            and \"piece\" in self._set_personality_data\n            and \"value\" in self._set_personality_data,\n            \"personality_data must contain keys `key` and `value`\",\n        )\n        self._set_classification = kwargs.pop(\"classification\", DEFAULT_CLASSIFICATION)\n        enforce(\n            len(self._set_classification) == 2\n            and \"piece\" in self._set_classification\n            and \"value\" in self._set_classification,\n            \"classification must contain keys `key` and `value`\",\n        )\n        self._set_service_data = kwargs.pop(\"service_data\", DEFAULT_SERVICE_DATA)\n        enforce(\n            len(self._set_service_data) == 2\n            and \"key\" in self._set_service_data\n            and \"value\" in self._set_service_data,\n            \"service_data must contain keys `key` and `value`\",\n        )\n        self._remove_service_data = {\"key\": self._set_service_data[\"key\"]}\n        self._simple_service_data = {\n            self._set_service_data[\"key\"]: self._set_service_data[\"value\"]\n        }\n\n        self._has_data_source = kwargs.pop(\"has_data_source\", DEFAULT_HAS_DATA_SOURCE)\n        data_for_sale_ordered = kwargs.pop(\"data_for_sale\", DEFAULT_DATA_FOR_SALE)\n        data_for_sale = {\n            str(key): str(value) for key, value in data_for_sale_ordered.items()\n        }\n\n        super().__init__(**kwargs)\n        self._ledger_id = (\n            ledger_id if ledger_id is not None else self.context.default_ledger_id\n        )\n        if currency_id is None:\n            currency_id = self.context.currency_denominations.get(self._ledger_id, None)\n            enforce(\n                currency_id is not None,\n                f\"Currency denomination for ledger_id={self._ledger_id} not specified.\",\n            )\n        self._currency_id = currency_id\n        enforce(\n            self.context.agent_addresses.get(self._ledger_id, None) is not None,\n            \"Wallet does not contain cryptos for provided ledger id.\",\n        )\n        self._data_for_sale = data_for_sale\n\n    @property\n    def data_for_sale(self) -> Dict[str, str]:\n        \"\"\"Get the data for sale.\"\"\"\n        if self._has_data_source:\n            return self.collect_from_data_source()  # pragma: nocover\n        return self._data_for_sale\n\n    @property\n    def ledger_id(self) -> str:\n        \"\"\"Get the ledger id.\"\"\"\n        return self._ledger_id\n\n    @property\n    def is_ledger_tx(self) -> bool:\n        \"\"\"Check whether or not tx are settled on a ledger.\"\"\"\n        return self._is_ledger_tx\n\n    def get_location_description(self) -> Description:\n        \"\"\"\n        Get the location description.\n\n        :return: a description of the agent's location\n        \"\"\"\n        description = Description(\n            self._agent_location,\n            data_model=AGENT_LOCATION_MODEL,\n        )\n        return description\n\n    def get_register_service_description(self) -> Description:\n        \"\"\"\n        Get the register service description.\n\n        :return: a description of the offered services\n        \"\"\"\n        description = Description(\n            self._set_service_data,\n            data_model=AGENT_SET_SERVICE_MODEL,\n        )\n        return description\n\n    def get_register_personality_description(self) -> Description:\n        \"\"\"\n        Get the register personality description.\n\n        :return: a description of the personality\n        \"\"\"\n        description = Description(\n            self._set_personality_data,\n            data_model=AGENT_PERSONALITY_MODEL,\n        )\n        return description\n\n    def get_register_classification_description(self) -> Description:\n        \"\"\"\n        Get the register classification description.\n\n        :return: a description of the classification\n        \"\"\"\n        description = Description(\n            self._set_classification,\n            data_model=AGENT_PERSONALITY_MODEL,\n        )\n        return description\n\n    def get_service_description(self) -> Description:\n        \"\"\"\n        Get the simple service description.\n\n        :return: a description of the offered services\n        \"\"\"\n        description = Description(\n            self._simple_service_data,\n            data_model=SIMPLE_SERVICE_MODEL,\n        )\n        return description\n\n    def get_unregister_service_description(self) -> Description:\n        \"\"\"\n        Get the unregister service description.\n\n        :return: a description of the to be removed service\n        \"\"\"\n        description = Description(\n            self._remove_service_data,\n            data_model=AGENT_REMOVE_SERVICE_MODEL,\n        )\n        return description\n\n    def is_matching_supply(self, query: Query) -> bool:\n        \"\"\"\n        Check if the query matches the supply.\n\n        :param query: the query\n        :return: bool indicating whether matches or not\n        \"\"\"\n        return query.check(self.get_service_description())\n\n    def generate_proposal_terms_and_data(  # pylint: disable=unused-argument\n        self, query: Query, counterparty_address: Address\n    ) -> Tuple[Description, Terms, Dict[str, str]]:\n        \"\"\"\n        Generate a proposal matching the query.\n\n        :param query: the query\n        :param counterparty_address: the counterparty of the proposal.\n        :return: a tuple of proposal, terms and the weather data\n        \"\"\"\n        data_for_sale = self.data_for_sale\n        sale_quantity = len(data_for_sale)\n        seller_address = self.context.agent_addresses[self.ledger_id]\n        total_price = sale_quantity * self._unit_price\n        if self.is_ledger_tx:\n            tx_nonce = LedgerApis.generate_tx_nonce(\n                identifier=self.ledger_id,\n                seller=seller_address,\n                client=counterparty_address,\n            )\n        else:\n            tx_nonce = uuid.uuid4().hex  # pragma: nocover\n        proposal = Description(\n            {\n                \"ledger_id\": self.ledger_id,\n                \"price\": total_price,\n                \"currency_id\": self._currency_id,\n                \"service_id\": self._service_id,\n                \"quantity\": sale_quantity,\n                \"tx_nonce\": tx_nonce,\n            }\n        )\n        terms = Terms(\n            ledger_id=self.ledger_id,\n            sender_address=seller_address,\n            counterparty_address=counterparty_address,\n            amount_by_currency_id={self._currency_id: total_price},\n            quantities_by_good_id={self._service_id: -sale_quantity},\n            is_sender_payable_tx_fee=False,\n            nonce=tx_nonce,\n            fee_by_currency_id={self._currency_id: 0},\n        )\n        return proposal, terms, data_for_sale\n\n    def collect_from_data_source(self) -> Dict[str, str]:\n        \"\"\"Implement the logic to communicate with the sensor.\"\"\"\n        raise NotImplementedError\n"
  },
  {
    "path": "packages/fetchai/skills/gym/README.md",
    "content": "# Gym\n\n## Description\n\nThis skill trains an RL algorithm using OpenAI Gym.\n\nThis skill is part of the Fetch.ai Gym demo. It trains a reinforcement learning (RL) algorithm using OpenAI Gym. It demonstrates how to wrap an RL agent in a skill by decoupling the RL agent from `gym.Env`, allowing them to run in separate execution environments.\n\n## Handlers\n\n- `gym`: handles `gym` messages for interactions with a gym environment.\n\n## Links\n\n- <a href=\"https://docs.fetch.ai/aea/gym-skill/\" target=\"_blank\">Gym Demo</a>\n- <a href=\"https://docs.fetch.ai/aea/gym-example/\" target=\"_blank\">Gym Example</a>\n- <a href=\"https://gym.openai.com\" target=\"_blank\">OpenAI Gym</a>\n"
  },
  {
    "path": "packages/fetchai/skills/gym/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains an example of skill for an AEA.\"\"\"\n\nfrom aea.configurations.base import PublicId\n\n\nPUBLIC_ID = PublicId.from_str(\"fetchai/gym:0.21.6\")\n"
  },
  {
    "path": "packages/fetchai/skills/gym/dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nThis module contains the classes required for dialogue management.\n\n- DefaultDialogue: The dialogue class maintains state of a dialogue of type default and manages it.\n- DefaultDialogues: The dialogues class keeps track of all dialogues of type default.\n- GymDialogue: The dialogue class maintains state of a dialogue of type gym and manages it.\n- GymDialogues: The dialogues class keeps track of all dialogues of type gym.\n\"\"\"\nfrom typing import Any\n\nfrom aea.protocols.base import Address, Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\nfrom aea.skills.base import Model\n\nfrom packages.fetchai.protocols.default.dialogues import (\n    DefaultDialogue as BaseDefaultDialogue,\n)\nfrom packages.fetchai.protocols.default.dialogues import (\n    DefaultDialogues as BaseDefaultDialogues,\n)\nfrom packages.fetchai.protocols.gym.dialogues import GymDialogue as BaseGymDialogue\nfrom packages.fetchai.protocols.gym.dialogues import GymDialogues as BaseGymDialogues\n\n\nDefaultDialogue = BaseDefaultDialogue\n\n\nclass DefaultDialogues(Model, BaseDefaultDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return DefaultDialogue.Role.AGENT\n\n        BaseDefaultDialogues.__init__(\n            self,\n            self_address=str(self.context.skill_id),\n            role_from_first_message=role_from_first_message,\n        )\n\n\nGymDialogue = BaseGymDialogue\n\n\nclass GymDialogues(Model, BaseGymDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return BaseGymDialogue.Role.AGENT\n\n        BaseGymDialogues.__init__(\n            self,\n            self_address=str(self.skill_id),\n            role_from_first_message=role_from_first_message,\n        )\n"
  },
  {
    "path": "packages/fetchai/skills/gym/handlers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the handler for the 'gym' skill.\"\"\"\n\nfrom typing import Any, Optional, cast\n\nfrom aea.protocols.base import Message\nfrom aea.skills.base import Handler\n\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.protocols.gym.message import GymMessage\nfrom packages.fetchai.skills.gym.dialogues import (\n    DefaultDialogues,\n    GymDialogue,\n    GymDialogues,\n)\nfrom packages.fetchai.skills.gym.rl_agent import DEFAULT_NB_STEPS\nfrom packages.fetchai.skills.gym.tasks import GymTask\n\n\nclass GymHandler(Handler):\n    \"\"\"Gym handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = GymMessage.protocol_id\n\n    def __init__(self, **kwargs: Any):\n        \"\"\"Initialize the handler.\"\"\"\n        nb_steps = kwargs.pop(\"nb_steps\", DEFAULT_NB_STEPS)\n        super().__init__(**kwargs)\n        self.task = GymTask(self.context, nb_steps)\n        self._task_id: Optional[int] = None\n\n    def setup(self) -> None:\n        \"\"\"Set up the handler.\"\"\"\n        self.context.logger.info(\"Gym handler: setup method called.\")\n        # launch the task\n        self._task_id = self.context.task_manager.enqueue_task(self.task)\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement messages.\n\n        :param message: the message\n        :return: None\n        \"\"\"\n        gym_msg = cast(GymMessage, message)\n\n        # recover dialogue\n        gym_dialogues = cast(GymDialogues, self.context.gym_dialogues)\n        gym_dialogue = cast(GymDialogue, gym_dialogues.update(gym_msg))\n        if gym_dialogue is None:\n            self._handle_unidentified_dialogue(gym_msg)\n            return\n\n        # handle message\n        if gym_msg.performative == GymMessage.Performative.PERCEPT:\n            self._handle_percept(gym_msg, gym_dialogue)\n        elif gym_msg.performative == GymMessage.Performative.STATUS:\n            self._handle_status(gym_msg, gym_dialogue)\n        else:\n            self._handle_invalid(gym_msg, gym_dialogue)\n\n    def _handle_unidentified_dialogue(self, gym_msg: GymMessage) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param gym_msg: the message\n        \"\"\"\n        self.context.logger.info(\n            \"received invalid gym message={}, unidentified dialogue.\".format(gym_msg)\n        )\n        default_dialogues = cast(DefaultDialogues, self.context.default_dialogues)\n        default_msg, _ = default_dialogues.create(\n            counterparty=gym_msg.sender,\n            performative=DefaultMessage.Performative.ERROR,\n            error_code=DefaultMessage.ErrorCode.INVALID_DIALOGUE,\n            error_msg=\"Invalid dialogue.\",\n            error_data={\"gym_message\": gym_msg.encode()},\n        )\n        self.context.outbox.put_message(message=default_msg)\n\n    def _handle_percept(self, gym_msg: GymMessage, gym_dialogue: GymDialogue) -> None:\n        \"\"\"\n        Handle messages.\n\n        :param gym_msg: the gym message\n        :param gym_dialogue: the gym dialogue\n        \"\"\"\n        if self.task.proxy_env.active_gym_dialogue == gym_dialogue:\n            self.task.proxy_env_queue.put(gym_msg)\n        else:\n            self.context.logger.warning(\"gym dialogue not active dialogue.\")\n\n    def _handle_status(self, gym_msg: GymMessage, gym_dialogue: GymDialogue) -> None:\n        \"\"\"\n        Handle messages.\n\n        :param gym_msg: the gym message\n        :param gym_dialogue: the gym dialogue\n        \"\"\"\n        if (\n            self.task.proxy_env.active_gym_dialogue == gym_dialogue\n            and gym_msg.content.get(\"reset\", \"failure\") == \"success\"\n        ):\n            self.task.proxy_env_queue.put(gym_msg)\n        else:\n            self.context.logger.warning(\"gym dialogue not active dialogue.\")\n\n    def _handle_invalid(self, gym_msg: GymMessage, gym_dialogue: GymDialogue) -> None:\n        \"\"\"\n        Handle an invalid http message.\n\n        :param gym_msg: the gym message\n        :param gym_dialogue: the gym dialogue\n        \"\"\"\n        self.context.logger.warning(\n            \"cannot handle gym message of performative={} in dialogue={}.\".format(\n                gym_msg.performative, gym_dialogue\n            )\n        )\n\n    def teardown(self) -> None:\n        \"\"\"Teardown the handler.\"\"\"\n        self.context.logger.info(\"Gym handler: teardown method called.\")\n        if self._task_id is None:\n            return  # pragma: nocover\n        self.task.teardown()\n        result = self.context.task_manager.get_task_result(self._task_id)\n        if not result.successful():\n            self.context.logger.warning(\"Task not successful!\")\n"
  },
  {
    "path": "packages/fetchai/skills/gym/helpers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\n\"\"\"This module contains the helpers for the 'gym' skill.\"\"\"\n\nfrom abc import ABC, abstractmethod\nfrom queue import Queue\nfrom typing import Any, Optional, Tuple, cast\n\nimport gym\n\nfrom aea.protocols.base import Message\nfrom aea.skills.base import SkillContext\n\nfrom packages.fetchai.connections.gym.connection import (\n    PUBLIC_ID as GYM_CONNECTION_PUBLIC_ID,\n)\nfrom packages.fetchai.protocols.gym.message import GymMessage\nfrom packages.fetchai.skills.gym.dialogues import GymDialogue, GymDialogues\n\n\nAction = Any\nObservation = Any\nReward = float\nDone = bool\nInfo = dict\nFeedback = Tuple[Observation, Reward, Done, Info]\n\nNB_STEPS = 500\n\n\nclass ProxyEnv(gym.Env):\n    \"\"\"This class is an implementation of the ProxyEnv, using bandit RL solution.\"\"\"\n\n    def __init__(self, skill_context: SkillContext) -> None:\n        \"\"\"\n        Instantiate the proxy environment.\n\n        :param skill_context: the skill context\n        \"\"\"\n        super().__init__()\n        self._skill_context = skill_context\n        self._queue = Queue()  # type: Queue\n        self._is_rl_agent_trained = False\n        self._step_count = 0\n        self._active_dialogue = None  # type: Optional[GymDialogue]\n        self.gym_address = str(GYM_CONNECTION_PUBLIC_ID)\n\n    @property\n    def gym_dialogues(self) -> GymDialogues:\n        \"\"\"Get the gym dialogues.\"\"\"\n        return cast(GymDialogues, self._skill_context.gym_dialogues)\n\n    @property\n    def active_gym_dialogue(self) -> GymDialogue:\n        \"\"\"Get the active gym dialogue.\"\"\"\n        if self._active_dialogue is None:\n            raise ValueError(\"GymDialogue not set yet.\")\n        return self._active_dialogue\n\n    @property\n    def queue(self) -> Queue:\n        \"\"\"Get queue.\"\"\"\n        return self._queue\n\n    @property\n    def is_rl_agent_trained(self) -> bool:\n        \"\"\"Get training status.\"\"\"\n        return self._is_rl_agent_trained\n\n    def step(self, action: Action) -> Feedback:  # type: ignore\n        \"\"\"\n        Run one time-step of the environment's dynamics.\n\n        Mirrors the standard 'step' method of a gym environment.\n\n        - The action is given to _encode_action, which does the necessary conversion to an envelope.\n        - The envelope is given to the outbox of the proxy agent.\n        - The method blocks until the _queue returns an envelope.\n        - The envelope is decoded with _decode_percept to a message.\n        - The message is converted into the standard observation, reward, done and info via _message_to_percept\n\n        :param action: the action sent to the step method (e.g. the output of an RL algorithm)\n        :return: a Tuple containing the Feedback of Observation, Reward, Done and Info\n        \"\"\"\n        self._step_count += 1\n        step_id = self._step_count\n\n        self._encode_and_send_action(action, step_id)\n\n        # Wait (blocking!) for the response envelope from the environment\n        gym_msg = self._queue.get(block=True, timeout=None)  # type: GymMessage\n\n        if gym_msg.performative != GymMessage.Performative.PERCEPT:\n            raise ValueError(\n                \"Unexpected performative. Expected={} got={}\".format(\n                    GymMessage.Performative.PERCEPT, gym_msg.performative\n                )\n            )\n\n        if gym_msg.step_id == step_id:\n            observation, reward, done, info = self._message_to_percept(gym_msg)\n        else:\n            raise ValueError(\n                \"Unexpected step id! expected={}, actual={}\".format(\n                    step_id, gym_msg.step_id\n                )\n            )\n\n        return observation, reward, done, info\n\n    def render(self, mode: str = \"human\") -> None:\n        \"\"\"\n        Render the environment.\n\n        :param mode: the mode\n        \"\"\"\n\n    def reset(self) -> None:  # type: ignore # pylint: disable=arguments-differ\n        \"\"\"Reset the environment.\"\"\"\n        self._step_count = 0\n        self._is_rl_agent_trained = False\n        gym_msg, gym_dialogue = self.gym_dialogues.create(\n            counterparty=self.gym_address,\n            performative=GymMessage.Performative.RESET,\n        )\n        gym_dialogue = cast(GymDialogue, gym_dialogue)\n        self._active_dialogue = gym_dialogue\n        self._skill_context.outbox.put_message(message=gym_msg)\n\n        # Wait (blocking!) for the response envelope from the environment\n        response_msg = self._queue.get(block=True, timeout=None)  # type: GymMessage\n\n        if response_msg.performative != GymMessage.Performative.STATUS:\n            raise ValueError(\n                \"Unexpected performative. Expected={} got={}\".format(\n                    GymMessage.Performative.STATUS, response_msg.performative\n                )\n            )\n\n    def close(self) -> None:\n        \"\"\"Close the environment.\"\"\"\n        self._is_rl_agent_trained = True\n        last_msg = self.active_gym_dialogue.last_message\n        if last_msg is None:  # pragma: nocover\n            raise ValueError(\"Cannot retrieve last message.\")\n        gym_msg = self.active_gym_dialogue.reply(\n            performative=GymMessage.Performative.CLOSE,\n            target_message=last_msg,\n        )\n        self._skill_context.outbox.put_message(message=gym_msg)\n\n    def _encode_and_send_action(self, action: Action, step_id: int) -> None:\n        \"\"\"\n        Encode the 'action' sent to the step function and send it.\n\n        :param action: the action that is the output of an RL algorithm.\n        :param step_id: the step id\n        \"\"\"\n        last_msg = self.active_gym_dialogue.last_message\n        if last_msg is None:  # pragma: nocover\n            raise ValueError(\"Cannot retrieve last message.\")\n        gym_msg = self.active_gym_dialogue.reply(\n            performative=GymMessage.Performative.ACT,\n            target_message=last_msg,\n            action=GymMessage.AnyObject(action),\n            step_id=step_id,\n        )\n        # Send the message via the proxy agent and to the environment\n        self._skill_context.outbox.put_message(message=gym_msg)\n\n    @staticmethod\n    def _message_to_percept(message: Message) -> Feedback:\n        \"\"\"\n        Transform the message received from the gym environment into observation, reward, done, info.\n\n        :param message: the message received as a response to the action performed in apply_action.\n        :return: the standard feedback (observation, reward, done, info) of a gym environment.\n        \"\"\"\n        msg = cast(GymMessage, message)\n        observation = msg.observation.any\n        reward = msg.reward\n        done = msg.done\n        info = msg.info.any\n\n        return observation, reward, done, info\n\n\nclass RLAgent(ABC):\n    \"\"\"Abstract RL Agent.\"\"\"\n\n    @abstractmethod\n    def fit(self, proxy_env: ProxyEnv, nb_steps: int) -> None:\n        \"\"\"\n        Train the agent on the given proxy environment.\n\n        :param proxy_env: the proxy gym environment\n        :param nb_steps: number of training steps to be performed.\n        \"\"\"\n"
  },
  {
    "path": "packages/fetchai/skills/gym/rl_agent.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This contains the rl agent class.\"\"\"\n\nimport logging\nimport random\nfrom typing import Any, Dict, Tuple\n\nimport numpy as np\n\nfrom packages.fetchai.skills.gym.helpers import ProxyEnv, RLAgent\n\n\nDEFAULT_NB_STEPS = 4000\nNB_GOODS = 10\n\n_default_logger = logging.getLogger(\"aea.packages.fetchai.skills.gym.rl_agent\")\n\n\nclass PriceBandit:\n    \"\"\"A class for a multi-armed bandit model of price.\"\"\"\n\n    def __init__(self, price: float, beta_a: float = 1.0, beta_b: float = 1.0):\n        \"\"\"\n        Instantiate a price bandit object.\n\n        :param price: the price this bandit is modelling\n        :param beta_a: the a parameter of the beta distribution\n        :param beta_b: the b parameter of the beta distribution\n        \"\"\"\n        self.price = price\n        # default params imply a uniform random prior\n        self.beta_a = beta_a\n        self.beta_b = beta_b\n\n    def sample(self) -> int:\n        \"\"\"\n        Sample from the bandit.\n\n        :return: the sampled value\n        \"\"\"\n        return round(np.random.beta(self.beta_a, self.beta_b))\n\n    def update(self, outcome: bool) -> None:\n        \"\"\"\n        Update the bandit.\n\n        :param outcome: the outcome used for updating\n        \"\"\"\n        outcome_int = 1 if outcome else 0  # explicit type conversion\n        self.beta_a += outcome_int\n        self.beta_b += 1 - outcome_int\n\n\nclass GoodPriceModel:\n    \"\"\"A class for a price model of a good.\"\"\"\n\n    def __init__(self, bound: int = 100):\n        \"\"\"Instantiate a good price model.\"\"\"\n        self.price_bandits = dict(\n            (price, PriceBandit(price)) for price in range(bound + 1)\n        )\n\n    def update(self, outcome: bool, price: int) -> None:\n        \"\"\"\n        Update the respective bandit.\n\n        :param price: the price to be updated\n        :param outcome: the negotiation outcome\n        \"\"\"\n        bandit = self.price_bandits[price]\n        bandit.update(outcome)\n\n    def get_price_expectation(self) -> int:\n        \"\"\"\n        Get best price.\n\n        :return: the winning price\n        \"\"\"\n        maxsample = -1\n        winning_price = 0\n        for price, bandit in self.price_bandits.items():\n            sample = bandit.sample()\n            if sample > maxsample:\n                maxsample = sample\n                winning_price = price\n        return winning_price\n\n\nclass MyRLAgent(RLAgent):\n    \"\"\"This class is a reinforcement learning agent that interacts with the agent framework.\"\"\"\n\n    def __init__(self, nb_goods: int, logger: logging.Logger = _default_logger) -> None:\n        \"\"\"\n        Instantiate the RL agent.\n\n        :param nb_goods: number of goods\n        :param logger: the logger.\n        \"\"\"\n        self.good_price_models = dict(\n            (good_id, GoodPriceModel()) for good_id in range(nb_goods)\n        )  # type: Dict[int, GoodPriceModel]\n        self.logger = logger\n\n    def _pick_an_action(self) -> Any:\n        \"\"\"\n        Pick an action.\n\n        :return: any\n        \"\"\"\n        # Get the good\n        good_id = self._get_random_next_good()\n\n        # Pick the best price based on own model.\n        good_price_model = self.good_price_models[good_id]\n        price = good_price_model.get_price_expectation()\n\n        action = [good_id, price]\n\n        return action\n\n    def _update_model(  # pylint: disable=unused-argument\n        self,\n        observation: Any,\n        reward: float,\n        done: bool,\n        info: Dict,\n        action: Tuple[int, int],\n    ) -> None:\n        \"\"\"\n        Update the model.\n\n        :param: observation: agent's observation of the current environment\n        :param: reward: amount of reward returned after previous action\n        :param: done: whether the episode has ended\n        :param: info: auxiliary diagnostic information\n        :param: action: action the agent performed on the environment to which the response was the above 4\n        \"\"\"\n        good_id, price = action\n\n        # Update the price model:\n        good_price_model = self.good_price_models[good_id]\n        outcome = reward == 1.0\n        good_price_model.update(outcome, price)\n\n    def _get_random_next_good(self) -> int:\n        \"\"\"\n        Get the next good for trading (randomly).\n\n        :return: a random good\n        \"\"\"\n        return random.choice(list(self.good_price_models.keys()))  # nosec\n\n    def fit(self, proxy_env: ProxyEnv, nb_steps: int) -> None:\n        \"\"\"\n        Train the agent on the given proxy environment.\n\n        :param proxy_env: the proxy gym environment\n        :param nb_steps: number of training steps to be performed.\n        \"\"\"\n        action_counter = 0\n\n        proxy_env.reset()\n        while action_counter < nb_steps:\n            action = self._pick_an_action()\n            obs, reward, done, info = proxy_env.step(action)\n            self._update_model(obs, reward, done, info, action)\n            action_counter += 1\n            if action_counter % 10 == 0:\n                self.logger.info(\n                    \"Action: step_id='{}' action='{}' reward='{}'\".format(\n                        action_counter, action, reward\n                    )\n                )\n        proxy_env.close()\n"
  },
  {
    "path": "packages/fetchai/skills/gym/skill.yaml",
    "content": "name: gym\nauthor: fetchai\nversion: 0.21.6\ntype: skill\ndescription: The gym skill wraps an RL agent.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: QmeYFajc1RJmSTi37WtrT6bY6cBNs5jua7oVkxbUegK3tW\n  __init__.py: QmV7evSScN3xK5CzvebBb7bMrkgtinK44yZ1yirgNu7aX5\n  dialogues.py: QmVePSYdPfXczXsriLxWguySkzHrRqkvs17HYhCu3W1poH\n  handlers.py: QmQB9c4Pf4Unr4qDEbsFinKeLJGZVukq5V4k8U3jcfqcAo\n  helpers.py: QmQ5esD6NubPdadz2zLmXjPHk6RcECyrHYfXhxdLzdKGBA\n  rl_agent.py: QmPZc3gtESxa3VjPZ2TciB8cPsGRA14f5udyCZKiFyhJhp\n  tasks.py: QmUx77jqj4BtWUL5pSxmiAnhhpTVww1g8JZmNXFyGHECFE\nfingerprint_ignore_patterns: []\nconnections:\n- fetchai/gym:0.20.6\ncontracts: []\nprotocols:\n- fetchai/gym:1.1.7\nskills: []\nbehaviours: {}\nhandlers:\n  gym:\n    args:\n      nb_steps: 4000\n    class_name: GymHandler\nmodels:\n  default_dialogues:\n    args: {}\n    class_name: DefaultDialogues\n  gym_dialogues:\n    args: {}\n    class_name: GymDialogues\ndependencies:\n  gym: {}\nis_abstract: false\n"
  },
  {
    "path": "packages/fetchai/skills/gym/tasks.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tasks for the 'gym' skill.\"\"\"\n\nfrom queue import Queue\nfrom typing import Any\n\nfrom aea.skills.base import SkillContext\nfrom aea.skills.tasks import Task\n\nfrom packages.fetchai.skills.gym.helpers import ProxyEnv\nfrom packages.fetchai.skills.gym.rl_agent import DEFAULT_NB_STEPS, MyRLAgent, NB_GOODS\n\n\nclass GymTask(Task):\n    \"\"\"Gym task.\"\"\"\n\n    def __init__(self, skill_context: SkillContext, nb_steps: int = DEFAULT_NB_STEPS):\n        \"\"\"Initialize the task.\"\"\"\n        super().__init__(logger=skill_context.logger)\n        self.logger.debug(\"GymTask.__init__: arguments: nb_steps={}\".format(nb_steps))\n        self._rl_agent = MyRLAgent(NB_GOODS, self.logger)\n        self._proxy_env = ProxyEnv(skill_context)\n        self.nb_steps = nb_steps\n        self.is_rl_agent_training = False\n\n    def _fit(self, proxy_env: ProxyEnv, nb_steps: int) -> None:\n        \"\"\"Fit the RL agent.\"\"\"\n        self._rl_agent.fit(proxy_env, nb_steps)\n        self.logger.info(\"Training finished. You can exit now via CTRL+C.\")\n\n    @property\n    def proxy_env(self) -> ProxyEnv:\n        \"\"\"Get the queue.\"\"\"\n        return self._proxy_env\n\n    @property\n    def proxy_env_queue(self) -> Queue:\n        \"\"\"Get the queue.\"\"\"\n        return self._proxy_env.queue\n\n    def setup(self) -> None:\n        \"\"\"Set up the task.\"\"\"\n        self.logger.info(\"Gym task: setup method called.\")\n\n    def execute(self, *args: Any, **kwargs: Any) -> None:\n        \"\"\"Execute the task.\"\"\"\n        if not self._proxy_env.is_rl_agent_trained and not self.is_rl_agent_training:\n            self._start_training()\n        if self._proxy_env.is_rl_agent_trained and self.is_rl_agent_training:\n            self._stop_training()\n\n    def teardown(self) -> None:\n        \"\"\"Teardown the task.\"\"\"\n        self.logger.info(\"Gym Task: teardown method called.\")\n        if self.is_rl_agent_training:\n            self._stop_training()\n\n    def _start_training(self) -> None:\n        \"\"\"Start training the RL agent.\"\"\"\n        self.logger.info(\"Training starting ...\")\n        self.is_rl_agent_training = True\n        self._fit(self._proxy_env, self.nb_steps)\n\n    def _stop_training(self) -> None:\n        \"\"\"Stop training the RL agent.\"\"\"\n        if self.is_rl_agent_training:\n            self.is_rl_agent_training = False\n            self._proxy_env.close()\n"
  },
  {
    "path": "packages/fetchai/skills/hello_world/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the implementation of the 'Hello World!' skill.\"\"\"\n\nfrom aea.configurations.base import PublicId\n\n\nPUBLIC_ID = PublicId.from_str(\"fetchai/hello_world:0.1.5\")\n"
  },
  {
    "path": "packages/fetchai/skills/hello_world/behaviours.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the behaviour of the 'Hello World!' skill.\"\"\"\n\nfrom typing import Any\n\nfrom aea.skills.behaviours import OneShotBehaviour\n\n\nDEFAULT_MESSAGE = \"Hello World!\"\n\n\nclass HelloWorld(OneShotBehaviour):\n    \"\"\"This skill prints 'Hello World!' on the screen.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"Initialise the behaviour.\"\"\"\n\n        self.message = kwargs.pop(\"message\", DEFAULT_MESSAGE)  # type: str\n        super().__init__(**kwargs)\n\n    def setup(self) -> None:\n        \"\"\"The setup.\"\"\"\n\n    def act(self) -> None:\n        \"\"\"The act.\"\"\"\n        self.context.logger.info(self.message)\n\n    def teardown(self) -> None:\n        \"\"\"The teardown.\"\"\"\n"
  },
  {
    "path": "packages/fetchai/skills/hello_world/skill.yaml",
    "content": "name: hello_world\nauthor: fetchai\nversion: 0.1.5\ntype: skill\ndescription: This skill prints `Hello World!` on the screen. The message can be configured\n  to be any different string.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  __init__.py: QmbChC9LnP2VDCELBpdvjQVWQeGxNGMBSxUCJkYvQAfQyC\n  behaviours.py: QmageynDzUCdo4SUpQ7S3MxhW2Lfe6HVbWGdkX86rE82hm\nfingerprint_ignore_patterns: []\nconnections: []\ncontracts: []\nprotocols: []\nskills: []\nbehaviours:\n  hello_world:\n    args:\n      message: Hello World!\n    class_name: HelloWorld\nhandlers: {}\nmodels: {}\ndependencies: {}\nis_abstract: false\n"
  },
  {
    "path": "packages/fetchai/skills/http_echo/README.md",
    "content": "# HTTP Echo\n\n## Description\n\nThis skill echoes the HTTP requests it receives as HTTP response.\n\nThis skill is part of the Fetch.ai \"HTTP Connection and Skill\" guide. Upon receiving an HTTP request, it sends back the same information in the request as an HTTP response.\n\n## Handlers\n\n- `http_handler`: handles `http` messages for echoing back an HTTP request as an HTTP response.\n\n## Links\n\n- <a href=\"https://docs.fetch.ai/aea/http-connection-and-skill/\" target=\"_blank\">HTTP Connection and Skill</a>\n"
  },
  {
    "path": "packages/fetchai/skills/http_echo/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the implementation of the http echo skill.\"\"\"\n\nfrom aea.configurations.base import PublicId\n\n\nPUBLIC_ID = PublicId.from_str(\"fetchai/http_echo:0.21.6\")\n"
  },
  {
    "path": "packages/fetchai/skills/http_echo/dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nThis module contains the classes required for dialogue management.\n\n- DefaultDialogue: The dialogue class maintains state of a dialogue of type default and manages it.\n- DefaultDialogues: The dialogues class keeps track of all dialogues of type default.\n- HttpDialogue: The dialogue class maintains state of a dialogue of type http and manages it.\n- HttpDialogues: The dialogues class keeps track of all dialogues of type http.\n\"\"\"\nfrom typing import Any\n\nfrom aea.protocols.base import Address, Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\nfrom aea.skills.base import Model\n\nfrom packages.fetchai.protocols.default.dialogues import (\n    DefaultDialogue as BaseDefaultDialogue,\n)\nfrom packages.fetchai.protocols.default.dialogues import (\n    DefaultDialogues as BaseDefaultDialogues,\n)\nfrom packages.fetchai.protocols.http.dialogues import HttpDialogue as BaseHttpDialogue\nfrom packages.fetchai.protocols.http.dialogues import HttpDialogues as BaseHttpDialogues\n\n\nDefaultDialogue = BaseDefaultDialogue\n\n\nclass DefaultDialogues(Model, BaseDefaultDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return DefaultDialogue.Role.AGENT\n\n        BaseDefaultDialogues.__init__(\n            self,\n            self_address=self.context.agent_address,\n            role_from_first_message=role_from_first_message,\n        )\n\n\nHttpDialogue = BaseHttpDialogue\n\n\nclass HttpDialogues(Model, BaseHttpDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return BaseHttpDialogue.Role.SERVER\n\n        BaseHttpDialogues.__init__(\n            self,\n            self_address=str(self.skill_id),\n            role_from_first_message=role_from_first_message,\n        )\n"
  },
  {
    "path": "packages/fetchai/skills/http_echo/handlers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the handler for the 'http_echo' skill.\"\"\"\n\nimport json\nfrom typing import cast\n\nfrom aea.protocols.base import Message\nfrom aea.skills.base import Handler\n\nfrom packages.fetchai.protocols.default import DefaultMessage\nfrom packages.fetchai.protocols.http.message import HttpMessage\nfrom packages.fetchai.skills.http_echo.dialogues import (\n    DefaultDialogues,\n    HttpDialogue,\n    HttpDialogues,\n)\n\n\nclass HttpHandler(Handler):\n    \"\"\"This implements the echo handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = HttpMessage.protocol_id\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to an envelope.\n\n        :param message: the message\n        \"\"\"\n        http_msg = cast(HttpMessage, message)\n\n        # recover dialogue\n        http_dialogues = cast(HttpDialogues, self.context.http_dialogues)\n        http_dialogue = cast(HttpDialogue, http_dialogues.update(http_msg))\n        if http_dialogue is None:\n            self._handle_unidentified_dialogue(http_msg)\n            return\n\n        # handle message\n        if http_msg.performative == HttpMessage.Performative.REQUEST:\n            self._handle_request(http_msg, http_dialogue)\n        else:\n            self._handle_invalid(http_msg, http_dialogue)\n\n    def _handle_unidentified_dialogue(self, http_msg: HttpMessage) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param http_msg: the message\n        \"\"\"\n        self.context.logger.info(\n            \"received invalid http message={}, unidentified dialogue.\".format(http_msg)\n        )\n        default_dialogues = cast(DefaultDialogues, self.context.default_dialogues)\n        default_msg, _ = default_dialogues.create(\n            counterparty=http_msg.sender,\n            performative=DefaultMessage.Performative.ERROR,\n            error_code=DefaultMessage.ErrorCode.INVALID_DIALOGUE,\n            error_msg=\"Invalid dialogue.\",\n            error_data={\"http_message\": http_msg.encode()},\n        )\n        self.context.outbox.put_message(message=default_msg)\n\n    def _handle_request(\n        self, http_msg: HttpMessage, http_dialogue: HttpDialogue\n    ) -> None:\n        \"\"\"\n        Handle a Http request.\n\n        :param http_msg: the http message\n        :param http_dialogue: the http dialogue\n        \"\"\"\n        self.context.logger.info(\n            \"received http request with method={}, url={} and body={!r}\".format(\n                http_msg.method,\n                http_msg.url,\n                http_msg.body,\n            )\n        )\n        if http_msg.method == \"get\":\n            self._handle_get(http_msg, http_dialogue)\n        elif http_msg.method == \"post\":\n            self._handle_post(http_msg, http_dialogue)\n\n    def _handle_get(self, http_msg: HttpMessage, http_dialogue: HttpDialogue) -> None:\n        \"\"\"\n        Handle a Http request of verb GET.\n\n        :param http_msg: the http message\n        :param http_dialogue: the http dialogue\n        \"\"\"\n        http_response = http_dialogue.reply(\n            performative=HttpMessage.Performative.RESPONSE,\n            target_message=http_msg,\n            version=http_msg.version,\n            status_code=200,\n            status_text=\"Success\",\n            headers=http_msg.headers,\n            body=json.dumps({\"tom\": {\"type\": \"cat\", \"age\": 10}}).encode(\"utf-8\"),\n        )\n        self.context.logger.info(\"responding with: {}\".format(http_response))\n        self.context.outbox.put_message(message=http_response)\n\n    def _handle_post(self, http_msg: HttpMessage, http_dialogue: HttpDialogue) -> None:\n        \"\"\"\n        Handle a Http request of verb POST.\n\n        :param http_msg: the http message\n        :param http_dialogue: the http dialogue\n        \"\"\"\n        http_response = http_dialogue.reply(\n            performative=HttpMessage.Performative.RESPONSE,\n            target_message=http_msg,\n            version=http_msg.version,\n            status_code=200,\n            status_text=\"Success\",\n            headers=http_msg.headers,\n            body=http_msg.body,\n        )\n        self.context.logger.info(\"responding with: {}\".format(http_response))\n        self.context.outbox.put_message(message=http_response)\n\n    def _handle_invalid(\n        self, http_msg: HttpMessage, http_dialogue: HttpDialogue\n    ) -> None:\n        \"\"\"\n        Handle an invalid http message.\n\n        :param http_msg: the http message\n        :param http_dialogue: the http dialogue\n        \"\"\"\n        self.context.logger.warning(\n            \"cannot handle http message of performative={} in dialogue={}.\".format(\n                http_msg.performative, http_dialogue\n            )\n        )\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n"
  },
  {
    "path": "packages/fetchai/skills/http_echo/skill.yaml",
    "content": "name: http_echo\nauthor: fetchai\nversion: 0.21.6\ntype: skill\ndescription: The http echo skill prints out the content of received http messages\n  and responds with success.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: QmPCkgR8tH6rUeBhiykisZsQ3qi4eoSRVSx2xhyjCULnu1\n  __init__.py: QmNiooQ4Y6DYyysoPNNhhQsbAksh58y6ec5KxVVLptP4Hv\n  dialogues.py: QmXft7PHDgb8MgEicPukB768qKLxNgYorX6VpNR4vDSLU6\n  handlers.py: QmQrwrsyp5qpFeerfSM8iBVdsowTfZa9Fwso5juN1Q8Vw8\nfingerprint_ignore_patterns: []\nconnections:\n- fetchai/http_server:0.23.6\ncontracts: []\nprotocols:\n- fetchai/http:1.1.7\nskills: []\nbehaviours: {}\nhandlers:\n  http_handler:\n    args: {}\n    class_name: HttpHandler\nmodels:\n  default_dialogues:\n    args: {}\n    class_name: DefaultDialogues\n  http_dialogues:\n    args: {}\n    class_name: HttpDialogues\ndependencies: {}\nis_abstract: false\n"
  },
  {
    "path": "packages/fetchai/skills/ml_data_provider/README.md",
    "content": "# ML Train Provider\n\n## Description\n\nThis skill sells ML data for training.\n\nThis skill is part of the Fetch.ai ML skill demo. It registers its \"ML data selling service\" on the sOEF. It can be requested (for example by an agent with the `ml_train` skill) to provide specific data samples, which it delivers after it receives payment.\n\n## Behaviours\n\n- `service_registration`: registers service on the sOEF search service\n\n## Handlers\n\n- `ml_trade`: handles `ml_trade` messages for negotiating the terms of trade\n- `ledger_api`: handles `ledger_api` messages for interacting with a ledger\n- `oef_search`: handles `oef_search` messages if service registration on the sOEF is unsuccessful\n\n## Links\n\n- <a href=\"https://docs.fetch.ai/aea/ml-skills/\" target=\"_blank\">ML Demo</a>\n"
  },
  {
    "path": "packages/fetchai/skills/ml_data_provider/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the implementation of the ml train and predict skill.\"\"\"\n\nfrom aea.configurations.base import PublicId\n\n\nPUBLIC_ID = PublicId.from_str(\"fetchai/ml_data_provider:0.27.6\")\n"
  },
  {
    "path": "packages/fetchai/skills/ml_data_provider/behaviours.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the behaviours of the agent.\"\"\"\n\nfrom packages.fetchai.skills.generic_seller.behaviours import (\n    GenericServiceRegistrationBehaviour,\n)\n\n\nServiceRegistrationBehaviour = GenericServiceRegistrationBehaviour\n"
  },
  {
    "path": "packages/fetchai/skills/ml_data_provider/dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nThis module contains the classes required for dialogue management.\n\n- DefaultDialogue: The dialogue class maintains state of a dialogue of type default and manages it.\n- DefaultDialogues: The dialogues class keeps track of all dialogues of type default.\n- MlTradeDialogue: The dialogue class maintains state of a dialogue of type ml_trade and manages it.\n- MlTradeDialogues: The dialogues class keeps track of all dialogues of type ml_trade.\n- OefSearchDialogue: The dialogue class maintains state of a dialogue of type oef_search and manages it.\n- OefSearchDialogues: The dialogues class keeps track of all dialogues of type oef_search.\n\"\"\"\n\nfrom typing import Any\n\nfrom aea.protocols.base import Address, Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\nfrom aea.skills.base import Model\n\nfrom packages.fetchai.protocols.default.dialogues import (\n    DefaultDialogue as BaseDefaultDialogue,\n)\nfrom packages.fetchai.protocols.default.dialogues import (\n    DefaultDialogues as BaseDefaultDialogues,\n)\nfrom packages.fetchai.protocols.ledger_api.dialogues import (\n    LedgerApiDialogue as BaseLedgerApiDialogue,\n)\nfrom packages.fetchai.protocols.ledger_api.dialogues import (\n    LedgerApiDialogues as BaseLedgerApiDialogues,\n)\nfrom packages.fetchai.protocols.ml_trade.dialogues import (\n    MlTradeDialogue as BaseMlTradeDialogue,\n)\nfrom packages.fetchai.protocols.ml_trade.dialogues import (\n    MlTradeDialogues as BaseMlTradeDialogues,\n)\nfrom packages.fetchai.protocols.oef_search.dialogues import (\n    OefSearchDialogue as BaseOefSearchDialogue,\n)\nfrom packages.fetchai.protocols.oef_search.dialogues import (\n    OefSearchDialogues as BaseOefSearchDialogues,\n)\n\n\nDefaultDialogue = BaseDefaultDialogue\n\n\nclass DefaultDialogues(Model, BaseDefaultDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return DefaultDialogue.Role.AGENT\n\n        BaseDefaultDialogues.__init__(\n            self,\n            self_address=self.context.agent_address,\n            role_from_first_message=role_from_first_message,\n        )\n\n\nMlTradeDialogue = BaseMlTradeDialogue\n\n\nclass MlTradeDialogues(Model, BaseMlTradeDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return MlTradeDialogue.Role.SELLER\n\n        BaseMlTradeDialogues.__init__(\n            self,\n            self_address=self.context.agent_address,\n            role_from_first_message=role_from_first_message,\n        )\n\n\nLedgerApiDialogue = BaseLedgerApiDialogue\n\n\nclass LedgerApiDialogues(Model, BaseLedgerApiDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return BaseLedgerApiDialogue.Role.AGENT\n\n        BaseLedgerApiDialogues.__init__(\n            self,\n            self_address=str(self.skill_id),\n            role_from_first_message=role_from_first_message,\n        )\n\n\nOefSearchDialogue = BaseOefSearchDialogue\n\n\nclass OefSearchDialogues(Model, BaseOefSearchDialogues):\n    \"\"\"This class keeps track of all oef_search dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return BaseOefSearchDialogue.Role.AGENT\n\n        BaseOefSearchDialogues.__init__(\n            self,\n            self_address=str(self.skill_id),\n            role_from_first_message=role_from_first_message,\n        )\n"
  },
  {
    "path": "packages/fetchai/skills/ml_data_provider/handlers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the handler for the 'ml_data_provider' skill.\"\"\"\n\nfrom typing import Optional, cast\n\nfrom aea.configurations.base import PublicId\nfrom aea.protocols.base import Message\nfrom aea.skills.base import Handler\n\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\nfrom packages.fetchai.protocols.ml_trade.message import MlTradeMessage\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.skills.ml_data_provider.behaviours import (\n    ServiceRegistrationBehaviour,\n)\nfrom packages.fetchai.skills.ml_data_provider.dialogues import (\n    DefaultDialogues,\n    LedgerApiDialogue,\n    LedgerApiDialogues,\n    MlTradeDialogue,\n    MlTradeDialogues,\n    OefSearchDialogue,\n    OefSearchDialogues,\n)\nfrom packages.fetchai.skills.ml_data_provider.strategy import Strategy\n\n\nclass MlTradeHandler(Handler):\n    \"\"\"ML trade handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = MlTradeMessage.protocol_id\n\n    def setup(self) -> None:\n        \"\"\"Set up the handler.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to a message.\n\n        :param message: the message\n        \"\"\"\n        ml_trade_msg = cast(MlTradeMessage, message)\n\n        # recover dialogue\n        ml_trade_dialogues = cast(MlTradeDialogues, self.context.ml_trade_dialogues)\n        ml_trade_dialogue = cast(\n            MlTradeDialogue, ml_trade_dialogues.update(ml_trade_msg)\n        )\n        if ml_trade_dialogue is None:\n            self._handle_unidentified_dialogue(ml_trade_msg)\n            return\n\n        # handle message\n        if ml_trade_msg.performative == MlTradeMessage.Performative.CFP:\n            self._handle_cft(ml_trade_msg, ml_trade_dialogue)\n        elif ml_trade_msg.performative == MlTradeMessage.Performative.ACCEPT:\n            self._handle_accept(ml_trade_msg, ml_trade_dialogue)\n        else:\n            self._handle_invalid(ml_trade_msg, ml_trade_dialogue)\n\n    def teardown(self) -> None:\n        \"\"\"Teardown the handler.\"\"\"\n\n    def _handle_unidentified_dialogue(self, ml_trade_msg: MlTradeMessage) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param ml_trade_msg: the message\n        \"\"\"\n        self.context.logger.info(\n            \"received invalid ml_trade message={}, unidentified dialogue.\".format(\n                ml_trade_msg\n            )\n        )\n        default_dialogues = cast(DefaultDialogues, self.context.default_dialogues)\n        default_msg, _ = default_dialogues.create(\n            counterparty=ml_trade_msg.sender,\n            performative=DefaultMessage.Performative.ERROR,\n            error_code=DefaultMessage.ErrorCode.INVALID_DIALOGUE,\n            error_msg=\"Invalid dialogue.\",\n            error_data={\"ml_trade_message\": ml_trade_msg.encode()},\n        )\n        self.context.outbox.put_message(message=default_msg)\n\n    def _handle_cft(\n        self, ml_trade_msg: MlTradeMessage, ml_trade_dialogue: MlTradeDialogue\n    ) -> None:\n        \"\"\"\n        Handle call for terms.\n\n        :param ml_trade_msg: the ml trade message\n        :param ml_trade_dialogue: the dialogue object\n        \"\"\"\n        query = ml_trade_msg.query\n        self.context.logger.info(\n            \"got a Call for Terms from {}.\".format(ml_trade_msg.sender[-5:])\n        )\n        strategy = cast(Strategy, self.context.strategy)\n        if not strategy.is_matching_supply(query):\n            self.context.logger.info(\"query does not match supply.\")\n            return\n        terms = strategy.generate_terms()\n        self.context.logger.info(\n            \"sending to the address={} a Terms message: {}\".format(\n                ml_trade_msg.sender[-5:], terms.values\n            )\n        )\n        terms_msg = ml_trade_dialogue.reply(\n            performative=MlTradeMessage.Performative.TERMS,\n            target_message=ml_trade_msg,\n            terms=terms,\n        )\n        self.context.outbox.put_message(message=terms_msg)\n\n    def _handle_accept(\n        self, ml_trade_msg: MlTradeMessage, ml_trade_dialogue: MlTradeDialogue\n    ) -> None:\n        \"\"\"\n        Handle accept.\n\n        :param ml_trade_msg: the ml trade message\n        :param ml_trade_dialogue: the dialogue object\n        \"\"\"\n        terms = ml_trade_msg.terms\n        self.context.logger.info(\n            \"got an Accept from {}: {}\".format(ml_trade_msg.sender[-5:], terms.values)\n        )\n        strategy = cast(Strategy, self.context.strategy)\n        if not strategy.is_valid_terms(terms):\n            self.context.logger.info(\"terms are not valid.\")\n            return\n        data = strategy.sample_data(terms.values[\"batch_size\"])\n        self.context.logger.info(\n            \"sending to address={} a Data message: shape={}\".format(\n                ml_trade_msg.sender[-5:], data[0].shape\n            )\n        )\n        payload = strategy.encode_sample_data(data)\n        data_msg = ml_trade_dialogue.reply(\n            performative=MlTradeMessage.Performative.DATA,\n            target_message=ml_trade_msg,\n            terms=terms,\n            payload=payload,\n        )\n        self.context.outbox.put_message(message=data_msg)\n\n    def _handle_invalid(\n        self, ml_trade_msg: MlTradeMessage, ml_trade_dialogue: MlTradeDialogue\n    ) -> None:\n        \"\"\"\n        Handle a fipa message of invalid performative.\n\n        :param ml_trade_msg: the message\n        :param ml_trade_dialogue: the dialogue object\n        \"\"\"\n        self.context.logger.warning(\n            \"cannot handle ml_trade message of performative={} in dialogue={}.\".format(\n                ml_trade_msg.performative, ml_trade_dialogue\n            )\n        )\n\n\nclass LedgerApiHandler(Handler):\n    \"\"\"Implement the ledger handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = LedgerApiMessage.protocol_id  # type: Optional[PublicId]\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup for the handler.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to a message.\n\n        :param message: the message\n        \"\"\"\n        ledger_api_msg = cast(LedgerApiMessage, message)\n\n        # recover dialogue\n        ledger_api_dialogues = cast(\n            LedgerApiDialogues, self.context.ledger_api_dialogues\n        )\n        ledger_api_dialogue = cast(\n            Optional[LedgerApiDialogue], ledger_api_dialogues.update(ledger_api_msg)\n        )\n        if ledger_api_dialogue is None:\n            self._handle_unidentified_dialogue(ledger_api_msg)\n            return\n\n        # handle message\n        if ledger_api_msg.performative is LedgerApiMessage.Performative.BALANCE:\n            self._handle_balance(ledger_api_msg)\n        elif ledger_api_msg.performative == LedgerApiMessage.Performative.ERROR:\n            self._handle_error(ledger_api_msg, ledger_api_dialogue)\n        else:\n            self._handle_invalid(ledger_api_msg, ledger_api_dialogue)\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n\n    def _handle_unidentified_dialogue(self, ledger_api_msg: LedgerApiMessage) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param ledger_api_msg: the message\n        \"\"\"\n        self.context.logger.info(\n            \"received invalid ledger_api message={}, unidentified dialogue.\".format(\n                ledger_api_msg\n            )\n        )\n\n    def _handle_balance(self, ledger_api_msg: LedgerApiMessage) -> None:\n        \"\"\"\n        Handle a message of balance performative.\n\n        :param ledger_api_msg: the ledger api message\n        \"\"\"\n        self.context.logger.info(\n            \"starting balance on {} ledger={}.\".format(\n                ledger_api_msg.ledger_id,\n                ledger_api_msg.balance,\n            )\n        )\n\n    def _handle_error(\n        self, ledger_api_msg: LedgerApiMessage, ledger_api_dialogue: LedgerApiDialogue\n    ) -> None:\n        \"\"\"\n        Handle a message of error performative.\n\n        :param ledger_api_msg: the ledger api message\n        :param ledger_api_dialogue: the ledger api dialogue\n        \"\"\"\n        self.context.logger.info(\n            \"received ledger_api error message={} in dialogue={}.\".format(\n                ledger_api_msg, ledger_api_dialogue\n            )\n        )\n\n    def _handle_invalid(\n        self, ledger_api_msg: LedgerApiMessage, ledger_api_dialogue: LedgerApiDialogue\n    ) -> None:\n        \"\"\"\n        Handle a message of invalid performative.\n\n        :param ledger_api_msg: the ledger api message\n        :param ledger_api_dialogue: the ledger api dialogue\n        \"\"\"\n        self.context.logger.warning(\n            \"cannot handle ledger_api message of performative={} in dialogue={}.\".format(\n                ledger_api_msg.performative,\n                ledger_api_dialogue,\n            )\n        )\n\n\nclass OefSearchHandler(Handler):\n    \"\"\"This class implements an OEF search handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = OefSearchMessage.protocol_id  # type: Optional[PublicId]\n\n    def setup(self) -> None:\n        \"\"\"Call to setup the handler.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to a message.\n\n        :param message: the message\n        \"\"\"\n        oef_search_msg = cast(OefSearchMessage, message)\n\n        # recover dialogue\n        oef_search_dialogues = cast(\n            OefSearchDialogues, self.context.oef_search_dialogues\n        )\n        oef_search_dialogue = cast(\n            Optional[OefSearchDialogue], oef_search_dialogues.update(oef_search_msg)\n        )\n        if oef_search_dialogue is None:\n            self._handle_unidentified_dialogue(oef_search_msg)\n            return\n\n        # handle message\n        if oef_search_msg.performative == OefSearchMessage.Performative.SUCCESS:\n            self._handle_success(oef_search_msg, oef_search_dialogue)\n        elif oef_search_msg.performative == OefSearchMessage.Performative.OEF_ERROR:\n            self._handle_error(oef_search_msg, oef_search_dialogue)\n        else:\n            self._handle_invalid(oef_search_msg, oef_search_dialogue)\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n\n    def _handle_unidentified_dialogue(self, oef_search_msg: OefSearchMessage) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param oef_search_msg: the message\n        \"\"\"\n        self.context.logger.info(\n            \"received invalid oef_search message={}, unidentified dialogue.\".format(\n                oef_search_msg\n            )\n        )\n\n    def _handle_success(\n        self,\n        oef_search_success_msg: OefSearchMessage,\n        oef_search_dialogue: OefSearchDialogue,\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param oef_search_success_msg: the oef search message\n        :param oef_search_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.info(\n            \"received oef_search success message={} in dialogue={}.\".format(\n                oef_search_success_msg, oef_search_dialogue\n            )\n        )\n        target_message = cast(\n            OefSearchMessage,\n            oef_search_dialogue.get_message_by_id(oef_search_success_msg.target),\n        )\n        if (\n            target_message.performative\n            == OefSearchMessage.Performative.REGISTER_SERVICE\n        ):\n            description = target_message.service_description\n            data_model_name = description.data_model.name\n            registration_behaviour = cast(\n                ServiceRegistrationBehaviour,\n                self.context.behaviours.service_registration,\n            )\n            if \"location_agent\" in data_model_name:\n                registration_behaviour.register_service()\n            elif \"set_service_key\" in data_model_name:\n                registration_behaviour.register_genus()\n            elif (\n                \"personality_agent\" in data_model_name\n                and description.values[\"piece\"] == \"genus\"\n            ):\n                registration_behaviour.register_classification()\n            elif (\n                \"personality_agent\" in data_model_name\n                and description.values[\"piece\"] == \"classification\"\n            ):\n                self.context.logger.info(\n                    \"the agent, with its genus and classification, and its service are successfully registered on the SOEF.\"\n                )\n            else:\n                self.context.logger.warning(\n                    f\"received soef SUCCESS message as a reply to the following unexpected message: {target_message}\"\n                )\n\n    def _handle_error(\n        self,\n        oef_search_error_msg: OefSearchMessage,\n        oef_search_dialogue: OefSearchDialogue,\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param oef_search_error_msg: the oef search message\n        :param oef_search_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.info(\n            \"received oef_search error message={} in dialogue={}.\".format(\n                oef_search_error_msg, oef_search_dialogue\n            )\n        )\n        target_message = cast(\n            OefSearchMessage,\n            oef_search_dialogue.get_message_by_id(oef_search_error_msg.target),\n        )\n        if (\n            target_message.performative\n            == OefSearchMessage.Performative.REGISTER_SERVICE\n        ):\n            registration_behaviour = cast(\n                ServiceRegistrationBehaviour,\n                self.context.behaviours.service_registration,\n            )\n            registration_behaviour.failed_registration_msg = target_message\n\n    def _handle_invalid(\n        self, oef_search_msg: OefSearchMessage, oef_search_dialogue: OefSearchDialogue\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param oef_search_msg: the oef search message\n        :param oef_search_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.warning(\n            \"cannot handle oef_search message of performative={} in dialogue={}.\".format(\n                oef_search_msg.performative,\n                oef_search_dialogue,\n            )\n        )\n"
  },
  {
    "path": "packages/fetchai/skills/ml_data_provider/skill.yaml",
    "content": "name: ml_data_provider\nauthor: fetchai\nversion: 0.27.6\ntype: skill\ndescription: The ml data provider skill implements a provider for Machine Learning\n  datasets in order to monetize data.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: QmcPsTwjWbUTMamK8aH94yRgYrKrmCwzffmMUueLya5wAg\n  __init__.py: Qma4KbWbeEcrX2gSghAwGU2fjpvS1xyEWZPTaiifxYgSEM\n  behaviours.py: QmZvLViapWxG1H41wn4e6Mzt8nmV6yyuk2sSsLJKZTQy2c\n  dialogues.py: QmaVve3Ldt3TN1QSA1x58tBruPDRZ5bnVYHencsVHvfsoh\n  handlers.py: QmYkHwQSjJh7CsMDRscidGzn4DMcWTJrFYMhV9yVaGNFZF\n  strategy.py: QmW8SBVyZyfpQG4b25xvjtEQVuKNPbqryYLdMVzkjtYFxc\nfingerprint_ignore_patterns: []\nconnections: []\ncontracts: []\nprotocols:\n- fetchai/default:1.1.7\n- fetchai/ledger_api:1.1.7\n- fetchai/ml_trade:1.1.7\n- fetchai/oef_search:1.1.7\nskills:\n- fetchai/generic_seller:0.28.6\nbehaviours:\n  service_registration:\n    args:\n      services_interval: 20\n    class_name: ServiceRegistrationBehaviour\nhandlers:\n  ledger_api:\n    args: {}\n    class_name: LedgerApiHandler\n  ml_trade:\n    args: {}\n    class_name: MlTradeHandler\n  oef_search:\n    args: {}\n    class_name: OefSearchHandler\nmodels:\n  default_dialogues:\n    args: {}\n    class_name: DefaultDialogues\n  ledger_api_dialogues:\n    args: {}\n    class_name: LedgerApiDialogues\n  ml_trade_dialogues:\n    args: {}\n    class_name: MlTradeDialogues\n  oef_search_dialogues:\n    args: {}\n    class_name: OefSearchDialogues\n  strategy:\n    args:\n      batch_size: 2\n      buyer_tx_fee: 1550000000000000\n      classification:\n        piece: classification\n        value: seller\n      is_ledger_tx: true\n      location:\n        latitude: 51.5194\n        longitude: 0.127\n      personality_data:\n        piece: genus\n        value: data\n      price_per_data_batch: 100\n      seller_tx_fee: 0\n      service_data:\n        key: dataset_id\n        value: fmnist\n      service_id: data_service\n    class_name: Strategy\ndependencies:\n  numpy: {}\n  tensorflow:\n    version: <3.0.0,>=2.4.0\nis_abstract: false\n"
  },
  {
    "path": "packages/fetchai/skills/ml_data_provider/strategy.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the strategy class.\"\"\"\n\nimport json\nimport uuid\nfrom typing import Any, Tuple\n\nimport numpy as np\n\nfrom aea.exceptions import enforce\nfrom aea.helpers.search.generic import (\n    AGENT_LOCATION_MODEL,\n    AGENT_PERSONALITY_MODEL,\n    AGENT_REMOVE_SERVICE_MODEL,\n    AGENT_SET_SERVICE_MODEL,\n    SIMPLE_DATA_MODEL,\n)\nfrom aea.helpers.search.models import Description, Location, Query\nfrom aea.skills.base import Model\n\n\nDEFAULT_PRICE_PER_DATA_BATCH = 10\nDEFAULT_BATCH_SIZE = 32\nDEFAULT_SELLER_TX_FEE = 0\nDEFAULT_BUYER_TX_FEE = 0\nDEFAULT_SERVICE_ID = \"data_service\"\n\nDEFAULT_LOCATION = {\"longitude\": 0.1270, \"latitude\": 51.5194}\nDEFAULT_PERSONALITY_DATA = {\"piece\": \"genus\", \"value\": \"data\"}\nDEFAULT_SERVICE_DATA = {\"key\": \"dataset_id\", \"value\": \"fmnist\"}\nDEFAULT_CLASSIFICATION = {\"piece\": \"classification\", \"value\": \"seller\"}\n\n\nclass NumpyArrayEncoder(json.JSONEncoder):\n    \"\"\"This class defines a custom JSON encoder for numpy ndarray objects.\"\"\"\n\n    def default(  # pylint: disable=arguments-differ,arguments-renamed\n        self, obj: Any\n    ) -> Any:\n        \"\"\"Encode an object (including a numpy ndarray) into its JSON representation.\"\"\"\n        if isinstance(obj, np.ndarray):\n            return obj.tolist()\n        return json.JSONEncoder.default(self, obj)  # pragma: nocover\n\n\nclass Strategy(Model):\n    \"\"\"This class defines a strategy for the agent.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"Initialize the strategy of the agent.\"\"\"\n        self.price_per_data_batch = kwargs.pop(\n            \"price_per_data_batch\", DEFAULT_PRICE_PER_DATA_BATCH\n        )\n        self.batch_size = kwargs.pop(\"batch_size\", DEFAULT_BATCH_SIZE)\n        self.seller_tx_fee = kwargs.pop(\"seller_tx_fee\", DEFAULT_SELLER_TX_FEE)\n        self.buyer_tx_fee = kwargs.pop(\"buyer_tx_fee\", DEFAULT_BUYER_TX_FEE)\n        currency_id = kwargs.pop(\"currency_id\", None)\n        ledger_id = kwargs.pop(\"ledger_id\", None)\n        self._is_ledger_tx = kwargs.pop(\"is_ledger_tx\", False)\n        self._service_id = kwargs.pop(\"service_id\", DEFAULT_SERVICE_ID)\n\n        location = kwargs.pop(\"location\", DEFAULT_LOCATION)\n        self._agent_location = {\n            \"location\": Location(\n                latitude=location[\"latitude\"], longitude=location[\"longitude\"]\n            )\n        }\n        self._set_personality_data = kwargs.pop(\n            \"personality_data\", DEFAULT_PERSONALITY_DATA\n        )\n        enforce(\n            len(self._set_personality_data) == 2\n            and \"piece\" in self._set_personality_data\n            and \"value\" in self._set_personality_data,\n            \"personality_data must contain keys `key` and `value`\",\n        )\n        self._set_classification = kwargs.pop(\"classification\", DEFAULT_CLASSIFICATION)\n        enforce(\n            len(self._set_classification) == 2\n            and \"piece\" in self._set_classification\n            and \"value\" in self._set_classification,\n            \"classification must contain keys `key` and `value`\",\n        )\n        self._set_service_data = kwargs.pop(\"service_data\", DEFAULT_SERVICE_DATA)\n        enforce(\n            len(self._set_service_data) == 2\n            and \"key\" in self._set_service_data\n            and \"value\" in self._set_service_data,\n            \"service_data must contain keys `key` and `value`\",\n        )\n        self._remove_service_data = {\"key\": self._set_service_data[\"key\"]}\n        self._simple_service_data = {\n            self._set_service_data[\"key\"]: self._set_service_data[\"value\"]\n        }\n\n        super().__init__(**kwargs)\n        self._ledger_id = (\n            ledger_id if ledger_id is not None else self.context.default_ledger_id\n        )\n        if currency_id is None:\n            currency_id = self.context.currency_denominations.get(self._ledger_id, None)\n            enforce(\n                currency_id is not None,\n                f\"Currency denomination for ledger_id={self._ledger_id} not specified.\",\n            )\n        self._currency_id = currency_id\n        # loading ML dataset\n        # (this could be parametrized)\n        from tensorflow import keras  # pylint: disable=import-outside-toplevel\n\n        (\n            (self.train_x, self.train_y),\n            (self.test_x, self.test_y),\n        ) = keras.datasets.fashion_mnist.load_data()\n\n    @property\n    def ledger_id(self) -> str:\n        \"\"\"Get the ledger id.\"\"\"\n        return self._ledger_id\n\n    @property\n    def is_ledger_tx(self) -> str:\n        \"\"\"Get the is_ledger_tx.\"\"\"\n        return self._is_ledger_tx\n\n    def get_location_description(self) -> Description:\n        \"\"\"\n        Get the location description.\n\n        :return: a description of the agent's location\n        \"\"\"\n        description = Description(\n            self._agent_location,\n            data_model=AGENT_LOCATION_MODEL,\n        )\n        return description\n\n    def get_register_personality_description(self) -> Description:\n        \"\"\"\n        Get the register personality description.\n\n        :return: a description of the personality\n        \"\"\"\n        description = Description(\n            self._set_personality_data,\n            data_model=AGENT_PERSONALITY_MODEL,\n        )\n        return description\n\n    def get_register_classification_description(self) -> Description:\n        \"\"\"\n        Get the register classification description.\n\n        :return: a description of the classification\n        \"\"\"\n        description = Description(\n            self._set_classification,\n            data_model=AGENT_PERSONALITY_MODEL,\n        )\n        return description\n\n    def get_register_service_description(self) -> Description:\n        \"\"\"\n        Get the register service description.\n\n        :return: a description of the offered services\n        \"\"\"\n        description = Description(\n            self._set_service_data,\n            data_model=AGENT_SET_SERVICE_MODEL,\n        )\n        return description\n\n    def get_service_description(self) -> Description:\n        \"\"\"\n        Get the simple service description.\n\n        :return: a description of the offered services\n        \"\"\"\n        description = Description(\n            self._simple_service_data,\n            data_model=SIMPLE_DATA_MODEL,\n        )\n        return description\n\n    def get_unregister_service_description(self) -> Description:\n        \"\"\"\n        Get the unregister service description.\n\n        :return: a description of the to be removed service\n        \"\"\"\n        description = Description(\n            self._remove_service_data,\n            data_model=AGENT_REMOVE_SERVICE_MODEL,\n        )\n        return description\n\n    def sample_data(self, n: int) -> Tuple:\n        \"\"\"Sample N rows from data.\"\"\"\n        idx = np.arange(self.train_x.shape[0])\n        mask = np.zeros_like(idx, dtype=bool)\n\n        selected = np.random.choice(idx, n, replace=False)\n        mask[selected] = True\n\n        x_sample = self.train_x[mask]\n        y_sample = self.train_y[mask]\n        return x_sample, y_sample\n\n    @staticmethod\n    def encode_sample_data(data: Tuple) -> bytes:\n        \"\"\"Serialize data (a tuple of two numpy ndarrays) into bytes.\"\"\"\n        data_dict = {\n            \"data_0\": data[0],\n            \"data_1\": data[1],\n        }\n        return json.dumps(data_dict, cls=NumpyArrayEncoder).encode(\"utf-8\")\n\n    def is_matching_supply(self, query: Query) -> bool:\n        \"\"\"\n        Check if the query matches the supply.\n\n        :param query: the query\n        :return: bool indicating whether matches or not\n        \"\"\"\n        service_desc = self.get_service_description()\n        return query.check(service_desc)\n\n    def generate_terms(self) -> Description:\n        \"\"\"\n        Generate a proposal.\n\n        :return: a tuple of proposal and the weather data\n        \"\"\"\n        address = self.context.agent_addresses[self.ledger_id]\n        proposal = Description(\n            {\n                \"batch_size\": self.batch_size,\n                \"price\": self.price_per_data_batch,\n                \"seller_tx_fee\": self.seller_tx_fee,\n                \"buyer_tx_fee\": self.buyer_tx_fee,\n                \"currency_id\": self._currency_id,\n                \"ledger_id\": self.ledger_id,\n                \"address\": address,\n                \"service_id\": self._service_id,\n                \"nonce\": uuid.uuid4().hex,\n            }\n        )\n        return proposal\n\n    def is_valid_terms(self, terms: Description) -> bool:\n        \"\"\"\n        Check the terms are valid.\n\n        :param terms: the terms\n        :return: boolean\n        \"\"\"\n        generated_terms = self.generate_terms()\n        return all(\n            terms.values[key] == generated_terms.values[key]\n            for key in [\n                \"batch_size\",\n                \"price\",\n                \"seller_tx_fee\",\n                \"buyer_tx_fee\",\n                \"currency_id\",\n                \"ledger_id\",\n                \"address\",\n                \"service_id\",\n            ]\n        )\n"
  },
  {
    "path": "packages/fetchai/skills/ml_train/README.md",
    "content": "# ML Train\n\n## Description\n\nThis skill buys ML data for training.\n\nThis skill is part of the Fetch.ai ML skill demo. It finds an agent which sells ML data, requests data and pays the proposed amount. Then trains an ML model using the bought data.\n\n## Behaviours\n\n- `search`: searches for ML data selling service on the sOEF\n- `transaction`: sequentially processes transactions' settlements on a blockchain\n\n## Handlers\n\n- `ml_trade`: handles `ml_trade` messages for negotiating the terms of trade\n- `ledger_api`: handles `ledger_api` messages for interacting with a ledger\n- `oef_search`: handles `oef_search` messages to manage the sellers found\n- `signing`: handles `signing` messages for transaction signing by the decision maker\n\n## Links\n\n- <a href=\"https://docs.fetch.ai/aea/ml-skills/\" target=\"_blank\">ML Demo</a>\n"
  },
  {
    "path": "packages/fetchai/skills/ml_train/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the implementation of the ml train and predict skill.\"\"\"\n\nfrom aea.configurations.base import PublicId\n\n\nPUBLIC_ID = PublicId.from_str(\"fetchai/ml_train:0.29.6\")\n"
  },
  {
    "path": "packages/fetchai/skills/ml_train/behaviours.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains the behaviours.\"\"\"\n\nfrom typing import Any, List, Optional, Set, cast\n\nfrom aea.protocols.dialogue.base import DialogueLabel\nfrom aea.skills.behaviours import TickerBehaviour\n\nfrom packages.fetchai.connections.ledger.base import (\n    CONNECTION_ID as LEDGER_CONNECTION_PUBLIC_ID,\n)\nfrom packages.fetchai.protocols.ledger_api import LedgerApiMessage\nfrom packages.fetchai.skills.generic_buyer.behaviours import GenericSearchBehaviour\nfrom packages.fetchai.skills.ml_train.dialogues import (\n    LedgerApiDialogue,\n    LedgerApiDialogues,\n    MlTradeDialogue,\n)\nfrom packages.fetchai.skills.ml_train.strategy import Strategy\nfrom packages.fetchai.skills.ml_train.tasks import MLTrainTask\n\n\nDEFAULT_MAX_PROCESSING = 120\nDEFAULT_TX_INTERVAL = 2.0\nDEFAULT_SEARCH_INTERVAL = 5.0\nLEDGER_API_ADDRESS = str(LEDGER_CONNECTION_PUBLIC_ID)\n\n\nclass SearchBehaviour(GenericSearchBehaviour):\n    \"\"\"This class implements a search behaviour for the ML skill.\"\"\"\n\n    def act(self) -> None:\n        \"\"\"Implement the act.\"\"\"\n        strategy = cast(Strategy, self.context.strategy)\n\n        if strategy.current_task_id is not None:\n            result = self.context.task_manager.get_task_result(strategy.current_task_id)\n\n            if not result.ready():\n                return\n\n            if not result.successful():\n                return\n\n            strategy.weights = result.get()\n            strategy.current_task_id = None\n\n        if len(strategy.data) > 0:\n            data = strategy.data.pop(0)\n            ml_task_id = self.context.task_manager.enqueue_task(\n                MLTrainTask(\n                    train_data=data[:2], epochs_per_batch=5, weights=strategy.weights\n                )\n            )\n            strategy.current_task_id = ml_task_id\n            return\n\n        super().act()\n\n\nclass TransactionBehaviour(TickerBehaviour):\n    \"\"\"A behaviour to sequentially submit transactions to the blockchain.\"\"\"\n\n    def __init__(self, **kwargs: Any):\n        \"\"\"Initialize the transaction behaviour.\"\"\"\n        tx_interval = cast(\n            float, kwargs.pop(\"transaction_interval\", DEFAULT_TX_INTERVAL)\n        )\n        self.max_processing = cast(\n            float, kwargs.pop(\"max_processing\", DEFAULT_MAX_PROCESSING)\n        )\n        self.processing_time = 0.0\n        self.waiting: List[MlTradeDialogue] = []\n        self.processing: Optional[LedgerApiDialogue] = None\n        self.timedout: Set[DialogueLabel] = set()\n        super().__init__(tick_interval=tx_interval, **kwargs)\n\n    def setup(self) -> None:\n        \"\"\"Setup behaviour.\"\"\"\n\n    def act(self) -> None:\n        \"\"\"Implement the act.\"\"\"\n        if self.processing is not None:\n            if self.processing_time <= self.max_processing:\n                # already processing\n                self.processing_time += self.tick_interval\n                return\n            self._timeout_processing()\n        if len(self.waiting) == 0:\n            # nothing to process\n            return\n        self._start_processing()\n\n    def _start_processing(self) -> None:\n        \"\"\"Process the next transaction.\"\"\"\n        ml_trade_dialogue = self.waiting.pop(0)\n        self.context.logger.info(\n            f\"Processing transaction, {len(self.waiting)} transactions remaining\"\n        )\n\n        ledger_api_dialogues = cast(\n            LedgerApiDialogues, self.context.ledger_api_dialogues\n        )\n        ledger_api_msg, ledger_api_dialogue = ledger_api_dialogues.create(\n            counterparty=LEDGER_API_ADDRESS,\n            performative=LedgerApiMessage.Performative.GET_RAW_TRANSACTION,\n            terms=ml_trade_dialogue.terms,\n        )\n        ledger_api_dialogue = cast(LedgerApiDialogue, ledger_api_dialogue)\n        ledger_api_dialogue.associated_ml_trade_dialogue = ml_trade_dialogue\n        self.processing_time = 0.0\n        self.processing = ledger_api_dialogue\n        self.context.logger.info(\n            f\"requesting transfer transaction from ledger api for message={ledger_api_msg}...\"\n        )\n        self.context.outbox.put_message(message=ledger_api_msg)\n\n    def teardown(self) -> None:\n        \"\"\"Teardown behaviour.\"\"\"\n\n    def _timeout_processing(self) -> None:\n        \"\"\"Timeout processing.\"\"\"\n        if self.processing is None:\n            return\n        self.timedout.add(self.processing.dialogue_label)\n        self.waiting.append(self.processing.associated_ml_trade_dialogue)\n        self.processing_time = 0.0\n        self.processing = None\n\n    def finish_processing(self, ledger_api_dialogue: LedgerApiDialogue) -> None:\n        \"\"\"\n        Finish processing.\n\n        :param ledger_api_dialogue: the ledger api dialogue\n        \"\"\"\n        if self.processing == ledger_api_dialogue:\n            self.processing_time = 0.0\n            self.processing = None\n            return\n        if ledger_api_dialogue.dialogue_label not in self.timedout:\n            raise ValueError(\n                f\"Non-matching dialogues in transaction behaviour: {self.processing} and {ledger_api_dialogue}\"\n            )\n        self.timedout.remove(ledger_api_dialogue.dialogue_label)\n        self.context.logger.debug(\n            f\"Timeout dialogue in transaction processing: {ledger_api_dialogue}\"\n        )\n        # don't reset, as another might be processing\n\n    def failed_processing(self, ledger_api_dialogue: LedgerApiDialogue) -> None:\n        \"\"\"\n        Failed processing.\n\n        Currently, we retry processing indefinitely.\n\n        :param ledger_api_dialogue: the ledger api dialogue\n        \"\"\"\n        self.finish_processing(ledger_api_dialogue)\n        self.waiting.append(ledger_api_dialogue.associated_ml_trade_dialogue)\n"
  },
  {
    "path": "packages/fetchai/skills/ml_train/dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nThis module contains the classes required for dialogue management.\n\n- DefaultDialogue: The dialogue class maintains state of a dialogue of type default and manages it.\n- DefaultDialogues: The dialogues class keeps track of all dialogues of type default.\n- LedgerApiDialogue: The dialogue class maintains state of a dialogue of type ledger_api and manages it.\n- LedgerApiDialogues: The dialogues class keeps track of all dialogues of type ledger_api.\n- MlTradeDialogue: The dialogue class maintains state of a dialogue of type ml_trade and manages it.\n- MlTradeDialogues: The dialogues class keeps track of all dialogues of type ml_trade.\n\"\"\"\n\nfrom typing import Any, Dict, Optional, Type\n\nfrom aea.common import Address\nfrom aea.exceptions import AEAEnforceError, enforce\nfrom aea.helpers.transaction.base import Terms\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\nfrom aea.protocols.dialogue.base import DialogueLabel as BaseDialogueLabel\nfrom aea.skills.base import Model\n\nfrom packages.fetchai.protocols.default.dialogues import (\n    DefaultDialogue as BaseDefaultDialogue,\n)\nfrom packages.fetchai.protocols.default.dialogues import (\n    DefaultDialogues as BaseDefaultDialogues,\n)\nfrom packages.fetchai.protocols.ledger_api.dialogues import (\n    LedgerApiDialogue as BaseLedgerApiDialogue,\n)\nfrom packages.fetchai.protocols.ledger_api.dialogues import (\n    LedgerApiDialogues as BaseLedgerApiDialogues,\n)\nfrom packages.fetchai.protocols.ledger_api.dialogues import LedgerApiMessage\nfrom packages.fetchai.protocols.ml_trade.dialogues import (\n    MlTradeDialogue as BaseMlTradeDialogue,\n)\nfrom packages.fetchai.protocols.ml_trade.dialogues import (\n    MlTradeDialogues as BaseMlTradeDialogues,\n)\nfrom packages.fetchai.protocols.ml_trade.message import MlTradeMessage\nfrom packages.fetchai.protocols.oef_search.dialogues import (\n    OefSearchDialogue as BaseOefSearchDialogue,\n)\nfrom packages.fetchai.protocols.oef_search.dialogues import (\n    OefSearchDialogues as BaseOefSearchDialogues,\n)\nfrom packages.fetchai.protocols.signing.dialogues import (\n    SigningDialogue as BaseSigningDialogue,\n)\nfrom packages.fetchai.protocols.signing.dialogues import (\n    SigningDialogues as BaseSigningDialogues,\n)\nfrom packages.fetchai.protocols.signing.message import SigningMessage\n\n\nDefaultDialogue = BaseDefaultDialogue\n\n\nclass DefaultDialogues(Model, BaseDefaultDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return DefaultDialogue.Role.AGENT\n\n        BaseDefaultDialogues.__init__(\n            self,\n            self_address=self.context.agent_address,\n            role_from_first_message=role_from_first_message,\n        )\n\n\nclass MlTradeDialogue(BaseMlTradeDialogue):\n    \"\"\"The dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    __slots__ = (\"data_for_sale\", \"_terms\")\n\n    def __init__(\n        self,\n        dialogue_label: BaseDialogueLabel,\n        self_address: Address,\n        role: BaseDialogue.Role,\n        message_class: Type[MlTradeMessage] = MlTradeMessage,\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n        :param message_class: the message class\n        \"\"\"\n        BaseMlTradeDialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            self_address=self_address,\n            role=role,\n            message_class=message_class,\n        )\n        self.data_for_sale = None  # type: Optional[Dict[str, str]]\n        self._terms = None  # type: Optional[Terms]\n\n    @property\n    def terms(self) -> Terms:\n        \"\"\"Get terms.\"\"\"\n        if self._terms is None:\n            raise AEAEnforceError(\"Terms not set!\")\n        return self._terms\n\n    @terms.setter\n    def terms(self, terms: Terms) -> None:\n        \"\"\"Set terms.\"\"\"\n        enforce(self._terms is None, \"Terms already set!\")\n        self._terms = terms\n\n\nclass MlTradeDialogues(Model, BaseMlTradeDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return BaseMlTradeDialogue.Role.BUYER\n\n        BaseMlTradeDialogues.__init__(\n            self,\n            self_address=self.context.agent_address,\n            role_from_first_message=role_from_first_message,\n        )\n\n\nclass LedgerApiDialogue(BaseLedgerApiDialogue):\n    \"\"\"The dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    __slots__ = (\"_associated_ml_trade_dialogue\",)\n\n    def __init__(\n        self,\n        dialogue_label: BaseDialogueLabel,\n        self_address: Address,\n        role: BaseDialogue.Role,\n        message_class: Type[LedgerApiMessage] = LedgerApiMessage,\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n        :param message_class: the message class\n        \"\"\"\n        BaseLedgerApiDialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            self_address=self_address,\n            role=role,\n            message_class=message_class,\n        )\n        self._associated_ml_trade_dialogue = None  # type: Optional[MlTradeDialogue]\n\n    @property\n    def associated_ml_trade_dialogue(self) -> MlTradeDialogue:\n        \"\"\"Get associated_ml_trade_dialogue.\"\"\"\n        if self._associated_ml_trade_dialogue is None:\n            raise AEAEnforceError(\"MlTradeDialogue not set!\")\n        return self._associated_ml_trade_dialogue\n\n    @associated_ml_trade_dialogue.setter\n    def associated_ml_trade_dialogue(self, ml_trade_dialogue: MlTradeDialogue) -> None:\n        \"\"\"Set associated_ml_trade_dialogue\"\"\"\n        enforce(\n            self._associated_ml_trade_dialogue is None, \"MlTradeDialogue already set!\"\n        )\n        self._associated_ml_trade_dialogue = ml_trade_dialogue\n\n\nclass LedgerApiDialogues(Model, BaseLedgerApiDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return BaseLedgerApiDialogue.Role.AGENT\n\n        BaseLedgerApiDialogues.__init__(\n            self,\n            self_address=str(self.skill_id),\n            role_from_first_message=role_from_first_message,\n            dialogue_class=LedgerApiDialogue,\n        )\n\n\nOefSearchDialogue = BaseOefSearchDialogue\n\n\nclass OefSearchDialogues(Model, BaseOefSearchDialogues):\n    \"\"\"This class keeps track of all oef_search dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return BaseOefSearchDialogue.Role.AGENT\n\n        BaseOefSearchDialogues.__init__(\n            self,\n            self_address=str(self.skill_id),\n            role_from_first_message=role_from_first_message,\n        )\n\n\nclass SigningDialogue(BaseSigningDialogue):\n    \"\"\"The dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    __slots__ = (\"_associated_ledger_api_dialogue\",)\n\n    def __init__(\n        self,\n        dialogue_label: BaseDialogueLabel,\n        self_address: Address,\n        role: BaseDialogue.Role,\n        message_class: Type[SigningMessage] = SigningMessage,\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n        :param message_class: the message class\n        \"\"\"\n        BaseSigningDialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            self_address=self_address,\n            role=role,\n            message_class=message_class,\n        )\n        self._associated_ledger_api_dialogue = None  # type: Optional[LedgerApiDialogue]\n\n    @property\n    def associated_ledger_api_dialogue(self) -> LedgerApiDialogue:\n        \"\"\"Get associated_ledger_api_dialogue.\"\"\"\n        if self._associated_ledger_api_dialogue is None:\n            raise AEAEnforceError(\"LedgerApiDialogue not set!\")\n        return self._associated_ledger_api_dialogue\n\n    @associated_ledger_api_dialogue.setter\n    def associated_ledger_api_dialogue(\n        self, ledger_api_dialogue: LedgerApiDialogue\n    ) -> None:\n        \"\"\"Set associated_ledger_api_dialogue\"\"\"\n        enforce(\n            self._associated_ledger_api_dialogue is None,\n            \"LedgerApiDialogue already set!\",\n        )\n        self._associated_ledger_api_dialogue = ledger_api_dialogue\n\n\nclass SigningDialogues(Model, BaseSigningDialogues):\n    \"\"\"This class keeps track of all oef_search dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return BaseSigningDialogue.Role.SKILL\n\n        BaseSigningDialogues.__init__(\n            self,\n            self_address=str(self.skill_id),\n            role_from_first_message=role_from_first_message,\n            dialogue_class=SigningDialogue,\n        )\n"
  },
  {
    "path": "packages/fetchai/skills/ml_train/handlers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the handler for the 'ml_train' skill.\"\"\"\n\nfrom typing import Optional, cast\n\nfrom aea.configurations.base import PublicId\nfrom aea.crypto.ledger_apis import LedgerApis\nfrom aea.protocols.base import Message\nfrom aea.skills.base import Handler\n\nfrom packages.fetchai.connections.ledger.base import (\n    CONNECTION_ID as LEDGER_CONNECTION_PUBLIC_ID,\n)\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\nfrom packages.fetchai.protocols.ml_trade.message import MlTradeMessage\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.protocols.signing.message import SigningMessage\nfrom packages.fetchai.skills.ml_train.behaviours import TransactionBehaviour\nfrom packages.fetchai.skills.ml_train.dialogues import (\n    DefaultDialogues,\n    LedgerApiDialogue,\n    LedgerApiDialogues,\n    MlTradeDialogue,\n    MlTradeDialogues,\n    OefSearchDialogue,\n    OefSearchDialogues,\n    SigningDialogue,\n    SigningDialogues,\n)\nfrom packages.fetchai.skills.ml_train.strategy import Strategy\n\n\nDUMMY_DIGEST = \"dummy_digest\"\nLEDGER_API_ADDRESS = str(LEDGER_CONNECTION_PUBLIC_ID)\n\n\nclass MlTradeHandler(Handler):\n    \"\"\"ML trade handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = MlTradeMessage.protocol_id\n\n    def setup(self) -> None:\n        \"\"\"Set up the handler.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Handle messages.\n\n        :param message: the message\n        \"\"\"\n        ml_trade_msg = cast(MlTradeMessage, message)\n\n        # recover dialogue\n        ml_trade_dialogues = cast(MlTradeDialogues, self.context.ml_trade_dialogues)\n        ml_trade_dialogue = cast(\n            MlTradeDialogue, ml_trade_dialogues.update(ml_trade_msg)\n        )\n        if ml_trade_dialogue is None:\n            self._handle_unidentified_dialogue(ml_trade_msg)\n            return\n\n        # handle message\n        if ml_trade_msg.performative == MlTradeMessage.Performative.TERMS:\n            self._handle_terms(ml_trade_msg, ml_trade_dialogue)\n        elif ml_trade_msg.performative == MlTradeMessage.Performative.DATA:\n            self._handle_data(ml_trade_msg)\n        else:\n            self._handle_invalid(ml_trade_msg, ml_trade_dialogue)\n\n    def teardown(self) -> None:\n        \"\"\"Teardown the handler.\"\"\"\n\n    def _handle_unidentified_dialogue(self, ml_trade_msg: MlTradeMessage) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param ml_trade_msg: the message\n        \"\"\"\n        self.context.logger.info(\n            \"received invalid ml_trade message={}, unidentified dialogue.\".format(\n                ml_trade_msg\n            )\n        )\n        default_dialogues = cast(DefaultDialogues, self.context.default_dialogues)\n        default_msg, _ = default_dialogues.create(\n            counterparty=ml_trade_msg.sender,\n            performative=DefaultMessage.Performative.ERROR,\n            error_code=DefaultMessage.ErrorCode.INVALID_DIALOGUE,\n            error_msg=\"Invalid dialogue.\",\n            error_data={\"ml_trade_message\": ml_trade_msg.encode()},\n        )\n        self.context.outbox.put_message(message=default_msg)\n\n    def _handle_terms(\n        self, ml_trade_msg: MlTradeMessage, ml_trade_dialogue: MlTradeDialogue\n    ) -> None:\n        \"\"\"\n        Handle the terms of the request.\n\n        :param ml_trade_msg: the ml trade message\n        :param ml_trade_dialogue: the dialogue object\n        \"\"\"\n        proposal_terms = ml_trade_msg.terms\n        self.context.logger.info(\n            \"received terms message from {}: terms={}\".format(\n                ml_trade_msg.sender[-5:], proposal_terms.values\n            )\n        )\n\n        strategy = cast(Strategy, self.context.strategy)\n        acceptable = strategy.is_acceptable_terms(proposal_terms)\n        affordable = strategy.is_affordable_terms(proposal_terms)\n        if not (acceptable and affordable):\n            self.context.logger.info(\n                \"rejecting, terms are not acceptable and/or affordable\"\n            )\n            return\n\n        if strategy.is_ledger_tx:\n            terms = strategy.terms_from_proposal(proposal_terms)\n            ml_trade_dialogue.terms = terms\n            tx_behaviour = cast(\n                TransactionBehaviour, self.context.behaviours.transaction\n            )\n            tx_behaviour.waiting.append(ml_trade_dialogue)\n        else:\n            # accept directly with a dummy transaction digest, no settlement\n            ml_accept = ml_trade_dialogue.reply(\n                performative=MlTradeMessage.Performative.ACCEPT,\n                target_message=ml_trade_msg,\n                tx_digest=DUMMY_DIGEST,\n                terms=proposal_terms,\n            )\n            self.context.outbox.put_message(message=ml_accept)\n            self.context.logger.info(\"sending dummy transaction digest ...\")\n\n    def _handle_data(self, ml_trade_msg: MlTradeMessage) -> None:\n        \"\"\"\n        Handle the data.\n\n        :param ml_trade_msg: the ml trade message\n        \"\"\"\n        strategy = cast(Strategy, self.context.strategy)\n        terms = ml_trade_msg.terms\n        payload = ml_trade_msg.payload\n        data = strategy.decode_sample_data(payload)\n        if data is None:\n            self.context.logger.info(\n                \"received data message with no data from {}\".format(\n                    ml_trade_msg.sender[-5:]\n                )\n            )\n        else:\n            self.context.logger.info(\n                \"received data message from {}: data shape={}, terms={}\".format(\n                    ml_trade_msg.sender[-5:], data[0].shape, terms.values\n                )\n            )\n            strategy.data.append(data)\n            strategy.is_searching = True\n\n    def _handle_invalid(\n        self, ml_trade_msg: MlTradeMessage, ml_trade_dialogue: MlTradeDialogue\n    ) -> None:\n        \"\"\"\n        Handle a fipa message of invalid performative.\n\n        :param ml_trade_msg: the message\n        :param ml_trade_dialogue: the dialogue object\n        \"\"\"\n        self.context.logger.warning(\n            \"cannot handle ml_trade message of performative={} in dialogue={}.\".format(\n                ml_trade_msg.performative, ml_trade_dialogue\n            )\n        )\n\n\nclass OEFSearchHandler(Handler):\n    \"\"\"The OEF search handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = OefSearchMessage.protocol_id  # type: Optional[PublicId]\n\n    def setup(self) -> None:\n        \"\"\"Call to setup the handler.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to a message.\n\n        :param message: the message\n        \"\"\"\n        oef_search_msg = cast(OefSearchMessage, message)\n\n        # recover dialogue\n        oef_search_dialogues = cast(\n            OefSearchDialogues, self.context.oef_search_dialogues\n        )\n        oef_search_dialogue = cast(\n            Optional[OefSearchDialogue], oef_search_dialogues.update(oef_search_msg)\n        )\n        if oef_search_dialogue is None:\n            self._handle_unidentified_dialogue(oef_search_msg)\n            return\n\n        # handle message\n        if oef_search_msg.performative is OefSearchMessage.Performative.OEF_ERROR:\n            self._handle_error(oef_search_msg, oef_search_dialogue)\n        elif oef_search_msg.performative is OefSearchMessage.Performative.SEARCH_RESULT:\n            self._handle_search(oef_search_msg, oef_search_dialogue)\n        else:\n            self._handle_invalid(oef_search_msg, oef_search_dialogue)\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n\n    def _handle_unidentified_dialogue(self, oef_search_msg: OefSearchMessage) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param oef_search_msg: the message\n        \"\"\"\n        self.context.logger.info(\n            \"received invalid oef_search message={}, unidentified dialogue.\".format(\n                oef_search_msg\n            )\n        )\n\n    def _handle_error(\n        self, oef_search_msg: OefSearchMessage, oef_search_dialogue: OefSearchDialogue\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param oef_search_msg: the oef search message\n        :param oef_search_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.info(\n            \"received oef_search error message={} in dialogue={}.\".format(\n                oef_search_msg, oef_search_dialogue\n            )\n        )\n\n    def _handle_search(\n        self, oef_search_msg: OefSearchMessage, oef_search_dialogue: OefSearchDialogue\n    ) -> None:\n        \"\"\"\n        Handle the search response.\n\n        :param oef_search_msg: the oef search message\n        :param oef_search_dialogue: the dialogue\n        \"\"\"\n        if len(oef_search_msg.agents) == 0:\n            self.context.logger.info(\n                \"found no agents in dialogue={}, continue searching.\".format(\n                    oef_search_dialogue\n                )\n            )\n            return\n\n        self.context.logger.info(\n            \"found agents={}, stopping search.\".format(\n                list(map(lambda x: x[-5:], oef_search_msg.agents)),\n            )\n        )\n        strategy = cast(Strategy, self.context.strategy)\n        strategy.is_searching = False\n        query = strategy.get_service_query()\n        ml_trade_dialogues = cast(MlTradeDialogues, self.context.ml_trade_dialogues)\n        for idx, opponent_address in enumerate(oef_search_msg.agents):\n            if idx >= strategy.max_negotiations:\n                continue\n            self.context.logger.info(\n                \"sending CFT to agent={}\".format(opponent_address[-5:])\n            )\n            cft_msg, _ = ml_trade_dialogues.create(\n                counterparty=opponent_address,\n                performative=MlTradeMessage.Performative.CFP,\n                query=query,\n            )\n            self.context.outbox.put_message(message=cft_msg)\n\n    def _handle_invalid(\n        self, oef_search_msg: OefSearchMessage, oef_search_dialogue: OefSearchDialogue\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param oef_search_msg: the oef search message\n        :param oef_search_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.warning(\n            \"cannot handle oef_search message of performative={} in dialogue={}.\".format(\n                oef_search_msg.performative,\n                oef_search_dialogue,\n            )\n        )\n\n\nclass LedgerApiHandler(Handler):\n    \"\"\"Implement the ledger handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = LedgerApiMessage.protocol_id  # type: Optional[PublicId]\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup for the handler.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to a message.\n\n        :param message: the message\n        \"\"\"\n        ledger_api_msg = cast(LedgerApiMessage, message)\n\n        # recover dialogue\n        ledger_api_dialogues = cast(\n            LedgerApiDialogues, self.context.ledger_api_dialogues\n        )\n        ledger_api_dialogue = cast(\n            Optional[LedgerApiDialogue], ledger_api_dialogues.update(ledger_api_msg)\n        )\n        if ledger_api_dialogue is None:\n            self._handle_unidentified_dialogue(ledger_api_msg)\n            return\n\n        # handle message\n        if ledger_api_msg.performative is LedgerApiMessage.Performative.BALANCE:\n            self._handle_balance(ledger_api_msg)\n        elif (\n            ledger_api_msg.performative is LedgerApiMessage.Performative.RAW_TRANSACTION\n        ):\n            self._handle_raw_transaction(ledger_api_msg, ledger_api_dialogue)\n        elif (\n            ledger_api_msg.performative\n            == LedgerApiMessage.Performative.TRANSACTION_DIGEST\n        ):\n            self._handle_transaction_digest(ledger_api_msg, ledger_api_dialogue)\n        elif (\n            ledger_api_msg.performative\n            == LedgerApiMessage.Performative.TRANSACTION_RECEIPT\n        ):\n            self._handle_transaction_receipt(ledger_api_msg, ledger_api_dialogue)\n        elif ledger_api_msg.performative == LedgerApiMessage.Performative.ERROR:\n            self._handle_error(ledger_api_msg, ledger_api_dialogue)\n        else:\n            self._handle_invalid(ledger_api_msg, ledger_api_dialogue)\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n\n    def _handle_unidentified_dialogue(self, ledger_api_msg: LedgerApiMessage) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param ledger_api_msg: the message\n        \"\"\"\n        self.context.logger.info(\n            \"received invalid ledger_api message={}, unidentified dialogue.\".format(\n                ledger_api_msg\n            )\n        )\n\n    def _handle_balance(self, ledger_api_msg: LedgerApiMessage) -> None:\n        \"\"\"\n        Handle a message of balance performative.\n\n        :param ledger_api_msg: the ledger api message\n        \"\"\"\n        strategy = cast(Strategy, self.context.strategy)\n        if ledger_api_msg.balance > 0:\n            self.context.logger.info(\n                \"starting balance on {} ledger={}.\".format(\n                    strategy.ledger_id,\n                    ledger_api_msg.balance,\n                )\n            )\n            strategy.is_searching = True\n            strategy.balance = ledger_api_msg.balance\n        else:\n            self.context.logger.warning(\n                \"you have no starting balance on {} ledger!\".format(strategy.ledger_id)\n            )\n            self.context.is_active = False\n\n    def _handle_raw_transaction(\n        self, ledger_api_msg: LedgerApiMessage, ledger_api_dialogue: LedgerApiDialogue\n    ) -> None:\n        \"\"\"\n        Handle a message of raw_transaction performative.\n\n        :param ledger_api_msg: the ledger api message\n        :param ledger_api_dialogue: the ledger api dialogue\n        \"\"\"\n        self.context.logger.info(\"received raw transaction={}\".format(ledger_api_msg))\n        signing_dialogues = cast(SigningDialogues, self.context.signing_dialogues)\n        last_msg = cast(LedgerApiMessage, ledger_api_dialogue.last_outgoing_message)\n        if last_msg is None:\n            raise ValueError(  # pragma: nocover\n                \"Could not retrive last outgoing ledger_api_msg.\"\n            )\n        signing_msg, signing_dialogue = signing_dialogues.create(\n            counterparty=self.context.decision_maker_address,\n            performative=SigningMessage.Performative.SIGN_TRANSACTION,\n            raw_transaction=ledger_api_msg.raw_transaction,\n            terms=last_msg.terms,\n        )\n        signing_dialogue = cast(SigningDialogue, signing_dialogue)\n        signing_dialogue.associated_ledger_api_dialogue = ledger_api_dialogue\n        self.context.decision_maker_message_queue.put_nowait(signing_msg)\n        self.context.logger.info(\n            \"proposing the transaction to the decision maker. Waiting for confirmation ...\"\n        )\n\n    def _handle_transaction_digest(\n        self, ledger_api_msg: LedgerApiMessage, ledger_api_dialogue: LedgerApiDialogue\n    ) -> None:\n        \"\"\"\n        Handle a message of transaction_digest performative.\n\n        :param ledger_api_msg: the ledger api message\n        :param ledger_api_dialogue: the ledger api dialogue\n        \"\"\"\n        self.context.logger.info(\n            \"transaction was successfully submitted. Transaction digest={}\".format(\n                ledger_api_msg.transaction_digest\n            )\n        )\n        ledger_api_msg_ = ledger_api_dialogue.reply(\n            performative=LedgerApiMessage.Performative.GET_TRANSACTION_RECEIPT,\n            target_message=ledger_api_msg,\n            transaction_digest=ledger_api_msg.transaction_digest,\n        )\n        self.context.logger.info(\"checking transaction is settled.\")\n        self.context.outbox.put_message(message=ledger_api_msg_)\n\n    def _handle_transaction_receipt(\n        self, ledger_api_msg: LedgerApiMessage, ledger_api_dialogue: LedgerApiDialogue\n    ) -> None:\n        \"\"\"\n        Handle a message of balance performative.\n\n        :param ledger_api_msg: the ledger api message\n        :param ledger_api_dialogue: the ledger api dialogue\n        \"\"\"\n        ml_trade_dialogue = ledger_api_dialogue.associated_ml_trade_dialogue\n        is_settled = LedgerApis.is_transaction_settled(\n            ml_trade_dialogue.terms.ledger_id,\n            ledger_api_msg.transaction_receipt.receipt,\n        )\n        tx_behaviour = cast(TransactionBehaviour, self.context.behaviours.transaction)\n        if is_settled:\n            tx_behaviour.finish_processing(ledger_api_dialogue)\n            ledger_api_msg_ = cast(\n                Optional[LedgerApiMessage], ledger_api_dialogue.last_outgoing_message\n            )\n            if ledger_api_msg_ is None:\n                raise ValueError(  # pragma: nocover\n                    \"Could not retrieve last ledger_api message\"\n                )\n            ml_trade_msg = cast(\n                Optional[MlTradeMessage], ml_trade_dialogue.last_incoming_message\n            )\n            if ml_trade_msg is None:\n                raise ValueError(\"Could not retrieve last ml_trade message\")\n            ml_accept = ml_trade_dialogue.reply(\n                performative=MlTradeMessage.Performative.ACCEPT,\n                target_message=ml_trade_msg,\n                tx_digest=ledger_api_msg_.transaction_digest.body,\n                terms=ml_trade_msg.terms,\n            )\n            self.context.outbox.put_message(message=ml_accept)\n            self.context.logger.info(\n                \"informing counterparty={} of transaction digest={}.\".format(\n                    ml_trade_msg.sender[-5:],\n                    ledger_api_msg_.transaction_digest,\n                )\n            )\n        else:\n            tx_behaviour.failed_processing(ledger_api_dialogue)\n            self.context.logger.info(\n                \"transaction_receipt={} not settled or not valid, aborting\".format(\n                    ledger_api_msg.transaction_receipt\n                )\n            )\n\n    def _handle_error(\n        self, ledger_api_msg: LedgerApiMessage, ledger_api_dialogue: LedgerApiDialogue\n    ) -> None:\n        \"\"\"\n        Handle a message of error performative.\n\n        :param ledger_api_msg: the ledger api message\n        :param ledger_api_dialogue: the ledger api dialogue\n        \"\"\"\n        self.context.logger.info(\n            \"received ledger_api error message={} in dialogue={}.\".format(\n                ledger_api_msg, ledger_api_dialogue\n            )\n        )\n        ledger_api_msg_ = cast(\n            Optional[LedgerApiMessage], ledger_api_dialogue.last_outgoing_message\n        )\n        if (\n            ledger_api_msg_ is not None\n            and ledger_api_msg_.performative\n            != LedgerApiMessage.Performative.GET_BALANCE\n        ):\n            tx_behaviour = cast(\n                TransactionBehaviour, self.context.behaviours.transaction\n            )\n            tx_behaviour.failed_processing(ledger_api_dialogue)\n\n    def _handle_invalid(\n        self, ledger_api_msg: LedgerApiMessage, ledger_api_dialogue: LedgerApiDialogue\n    ) -> None:\n        \"\"\"\n        Handle a message of invalid performative.\n\n        :param ledger_api_msg: the ledger api message\n        :param ledger_api_dialogue: the ledger api dialogue\n        \"\"\"\n        self.context.logger.warning(\n            \"cannot handle ledger_api message of performative={} in dialogue={}.\".format(\n                ledger_api_msg.performative,\n                ledger_api_dialogue,\n            )\n        )\n\n\nclass SigningHandler(Handler):\n    \"\"\"Implement the transaction handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = SigningMessage.protocol_id  # type: Optional[PublicId]\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup for the handler.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to a message.\n\n        :param message: the message\n        \"\"\"\n        signing_msg = cast(SigningMessage, message)\n\n        # recover dialogue\n        signing_dialogues = cast(SigningDialogues, self.context.signing_dialogues)\n        signing_dialogue = cast(\n            Optional[SigningDialogue], signing_dialogues.update(signing_msg)\n        )\n        if signing_dialogue is None:\n            self._handle_unidentified_dialogue(signing_msg)\n            return\n\n        # handle message\n        if signing_msg.performative is SigningMessage.Performative.SIGNED_TRANSACTION:\n            self._handle_signed_transaction(signing_msg, signing_dialogue)\n        elif signing_msg.performative is SigningMessage.Performative.ERROR:\n            self._handle_error(signing_msg, signing_dialogue)\n        else:\n            self._handle_invalid(signing_msg, signing_dialogue)\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n\n    def _handle_unidentified_dialogue(self, signing_msg: SigningMessage) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param signing_msg: the message\n        \"\"\"\n        self.context.logger.info(\n            \"received invalid signing message={}, unidentified dialogue.\".format(\n                signing_msg\n            )\n        )\n\n    def _handle_signed_transaction(\n        self, signing_msg: SigningMessage, signing_dialogue: SigningDialogue\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param signing_msg: the signing message\n        :param signing_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.info(\"transaction signing was successful.\")\n        ledger_api_dialogue = signing_dialogue.associated_ledger_api_dialogue\n        last_ledger_api_msg = cast(\n            Optional[LedgerApiMessage], ledger_api_dialogue.last_incoming_message\n        )\n        if last_ledger_api_msg is None:\n            raise ValueError(\"Could not retrieve last message in ledger api dialogue\")\n        ledger_api_msg = ledger_api_dialogue.reply(\n            performative=LedgerApiMessage.Performative.SEND_SIGNED_TRANSACTION,\n            target_message=last_ledger_api_msg,\n            signed_transaction=signing_msg.signed_transaction,\n        )\n        self.context.outbox.put_message(message=ledger_api_msg)\n        self.context.logger.info(\"sending transaction to ledger.\")\n\n    def _handle_error(\n        self, signing_msg: SigningMessage, signing_dialogue: SigningDialogue\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param signing_msg: the signing message\n        :param signing_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.info(\n            \"transaction signing was not successful. Error_code={} in dialogue={}\".format(\n                signing_msg.error_code, signing_dialogue\n            )\n        )\n        signing_msg_ = cast(\n            Optional[SigningMessage], signing_dialogue.last_outgoing_message\n        )\n        if (\n            signing_msg_ is not None\n            and signing_msg_.performative\n            == SigningMessage.Performative.SIGN_TRANSACTION\n        ):\n            tx_behaviour = cast(\n                TransactionBehaviour, self.context.behaviours.transaction\n            )\n            ledger_api_dialogue = signing_dialogue.associated_ledger_api_dialogue\n            tx_behaviour.failed_processing(ledger_api_dialogue)\n\n    def _handle_invalid(\n        self, signing_msg: SigningMessage, signing_dialogue: SigningDialogue\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param signing_msg: the signing message\n        :param signing_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.warning(\n            \"cannot handle signing message of performative={} in dialogue={}.\".format(\n                signing_msg.performative, signing_dialogue\n            )\n        )\n"
  },
  {
    "path": "packages/fetchai/skills/ml_train/skill.yaml",
    "content": "name: ml_train\nauthor: fetchai\nversion: 0.29.6\ntype: skill\ndescription: The ml train and predict skill implements a simple skill which buys training\n  data, trains a model and sells predictions.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: QmPzgPycfq5bRWQhFqy1ARH1vMyXzDZucn9zXuf4V3hGnS\n  __init__.py: QmXZYbUeGUQrEZszz8eJGCqXqxMx4VPf4xvy8jZYUSmxip\n  behaviours.py: QmWeexaVncgAR3vZa3CBDfvzTfZDTcG6GXHwFjbM6wzJed\n  dialogues.py: QmdVwUF6wjX8bkfpsnog7KGF269HK5395DUjmqD1eT3qUR\n  handlers.py: QmezY9DZ6Sgi6SqZnyc3Gcte4NUmKSsQUSbZDmr6kWsbAt\n  strategy.py: QmYmzBsWDe4pxGYpYt1iNHQQz2MFRgMAULygW9Zdu4UkQR\n  tasks.py: QmPLZyT4pX2Kq2HGkBdS5Jwyz6CFgsk4B4SSBUxJu1kP3C\nfingerprint_ignore_patterns: []\nconnections:\n- fetchai/ledger:0.21.5\ncontracts: []\nprotocols:\n- fetchai/default:1.1.7\n- fetchai/ledger_api:1.1.7\n- fetchai/ml_trade:1.1.7\n- fetchai/oef_search:1.1.7\n- fetchai/signing:1.1.7\nskills:\n- fetchai/generic_buyer:0.27.6\nbehaviours:\n  search:\n    args:\n      search_interval: 10\n    class_name: SearchBehaviour\n  transaction:\n    args:\n      max_processing: 420\n      transaction_interval: 2\n    class_name: TransactionBehaviour\nhandlers:\n  ledger_api:\n    args: {}\n    class_name: LedgerApiHandler\n  ml_trade:\n    args: {}\n    class_name: MlTradeHandler\n  oef_search:\n    args: {}\n    class_name: OEFSearchHandler\n  signing:\n    args: {}\n    class_name: SigningHandler\nmodels:\n  default_dialogues:\n    args: {}\n    class_name: DefaultDialogues\n  ledger_api_dialogues:\n    args: {}\n    class_name: LedgerApiDialogues\n  ml_trade_dialogues:\n    args: {}\n    class_name: MlTradeDialogues\n  oef_search_dialogues:\n    args: {}\n    class_name: OefSearchDialogues\n  signing_dialogues:\n    args: {}\n    class_name: SigningDialogues\n  strategy:\n    args:\n      is_ledger_tx: true\n      location:\n        latitude: 51.5194\n        longitude: 0.127\n      max_buyer_tx_fee: 1550000000000000\n      max_negotiations: 2\n      max_unit_price: 70\n      search_query:\n        constraint_type: ==\n        search_key: dataset_id\n        search_value: fmnist\n      search_radius: 5.0\n      service_id: data_service\n    class_name: Strategy\ndependencies:\n  aea-ledger-fetchai:\n    version: <2.0.0,>=1.0.0\n  numpy: {}\n  tensorflow:\n    version: <3.0.0,>=2.4.0\nis_abstract: false\n"
  },
  {
    "path": "packages/fetchai/skills/ml_train/strategy.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the strategy class.\"\"\"\n\nimport json\nfrom typing import Any, List, Optional, Tuple\n\nimport numpy as np\n\nfrom aea.exceptions import enforce\nfrom aea.helpers.search.generic import SIMPLE_DATA_MODEL\nfrom aea.helpers.search.models import (\n    Constraint,\n    ConstraintType,\n    Description,\n    Location,\n    Query,\n)\nfrom aea.helpers.transaction.base import Terms\nfrom aea.skills.base import Model\n\n\nDEFAULT_MAX_ROW_PRICE = 5\nDEFAULT_MAX_TX_FEE = 2\nDEFAULT_MAX_NEGOTIATIONS = 1\nDEFAULT_SERVICE_ID = \"service_data\"\n\nDEFAULT_LOCATION = {\"longitude\": 0.1270, \"latitude\": 51.5194}\nDEFAULT_SEARCH_QUERY = {\n    \"search_key\": \"dataset_id\",\n    \"search_value\": \"fmnist\",\n    \"constraint_type\": \"==\",\n}\nDEFAULT_SEARCH_RADIUS = 5.0\n\n\nclass Strategy(Model):\n    \"\"\"This class defines a strategy for the agent.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"Initialize the strategy of the agent.\"\"\"\n        self._max_unit_price = kwargs.pop(\"max_unit_price\", DEFAULT_MAX_ROW_PRICE)\n        self._max_buyer_tx_fee = kwargs.pop(\"max_buyer_tx_fee\", DEFAULT_MAX_TX_FEE)\n        currency_id = kwargs.pop(\"currency_id\", None)\n        ledger_id = kwargs.pop(\"ledger_id\", None)\n        self._is_ledger_tx = kwargs.pop(\"is_ledger_tx\", False)\n        self._max_negotiations = kwargs.pop(\n            \"max_negotiations\", DEFAULT_MAX_NEGOTIATIONS\n        )\n        self._service_id = kwargs.pop(\"service_id\", DEFAULT_SERVICE_ID)\n\n        self._search_query = kwargs.pop(\"search_query\", DEFAULT_SEARCH_QUERY)\n        location = kwargs.pop(\"location\", DEFAULT_LOCATION)\n        self._agent_location = Location(\n            latitude=location[\"latitude\"], longitude=location[\"longitude\"]\n        )\n        self._radius = kwargs.pop(\"search_radius\", DEFAULT_SEARCH_RADIUS)\n\n        super().__init__(**kwargs)\n        self._ledger_id = (\n            ledger_id if ledger_id is not None else self.context.default_ledger_id\n        )\n        if currency_id is None:\n            currency_id = self.context.currency_denominations.get(self._ledger_id, None)\n            enforce(\n                currency_id is not None,\n                f\"Currency denomination for ledger_id={self._ledger_id} not specified.\",\n            )\n        self._currency_id = currency_id\n        self._is_searching = False\n        self._tx_id = 0\n        self._balance = 0\n\n        self._current_task_id = None  # type: Optional[int]\n        self._weights = None  # type: Optional[Any]\n        self.data = []  # type: List[Any]\n\n    @property\n    def ledger_id(self) -> str:\n        \"\"\"Get the ledger id.\"\"\"\n        return self._ledger_id\n\n    @property\n    def is_ledger_tx(self) -> str:\n        \"\"\"Get the is_ledger_tx.\"\"\"\n        return self._is_ledger_tx\n\n    @property\n    def max_negotiations(self) -> int:\n        \"\"\"Get the max negotiations.\"\"\"\n        return self._max_negotiations\n\n    @property\n    def is_searching(self) -> bool:\n        \"\"\"Check if the agent is searching.\"\"\"\n        return self._is_searching\n\n    @is_searching.setter\n    def is_searching(self, is_searching: bool) -> None:\n        \"\"\"Check if the agent is searching.\"\"\"\n        enforce(isinstance(is_searching, bool), \"Can only set bool on is_searching!\")\n        self._is_searching = is_searching\n\n    @property\n    def balance(self) -> int:\n        \"\"\"Get the balance.\"\"\"\n        return self._balance\n\n    @balance.setter\n    def balance(self, balance: int) -> None:\n        \"\"\"Set the balance.\"\"\"\n        self._balance = balance\n\n    @property\n    def current_task_id(self) -> Optional[int]:\n        \"\"\"Get the current_task_id.\"\"\"\n        return self._current_task_id\n\n    @current_task_id.setter\n    def current_task_id(self, task_id: int) -> None:\n        \"\"\"Set the current_task_id.\"\"\"\n        self._current_task_id = task_id\n\n    @property\n    def weights(self) -> Optional[List[np.ndarray]]:\n        \"\"\"Get the weights.\"\"\"\n        return self._weights\n\n    @weights.setter\n    def weights(self, weights: List[np.ndarray]) -> None:\n        \"\"\"Set the weights.\"\"\"\n        self._weights = weights\n\n    def get_next_transaction_id(self) -> str:\n        \"\"\"\n        Get the next transaction id.\n\n        :return: The next transaction id\n        \"\"\"\n        self._tx_id += 1\n        return \"transaction_{}\".format(self._tx_id)\n\n    def get_location_and_service_query(self) -> Query:\n        \"\"\"\n        Get the location and service query of the agent.\n\n        :return: the query\n        \"\"\"\n        close_to_my_service = Constraint(\n            \"location\", ConstraintType(\"distance\", (self._agent_location, self._radius))\n        )\n        service_key_filter = Constraint(\n            self._search_query[\"search_key\"],\n            ConstraintType(\n                self._search_query[\"constraint_type\"],\n                self._search_query[\"search_value\"],\n            ),\n        )\n        query = Query(\n            [close_to_my_service, service_key_filter],\n        )\n        return query\n\n    def get_service_query(self) -> Query:\n        \"\"\"\n        Get the service query of the agent.\n\n        :return: the query\n        \"\"\"\n        service_key_filter = Constraint(\n            self._search_query[\"search_key\"],\n            ConstraintType(\n                self._search_query[\"constraint_type\"],\n                self._search_query[\"search_value\"],\n            ),\n        )\n        query = Query([service_key_filter], model=SIMPLE_DATA_MODEL)\n        return query\n\n    def is_acceptable_terms(self, terms: Description) -> bool:\n        \"\"\"\n        Check whether the terms are acceptable.\n\n        :param terms: the terms\n        :return: boolean\n        \"\"\"\n        result = (\n            (terms.values[\"price\"] - terms.values[\"seller_tx_fee\"] > 0)\n            and (\n                terms.values[\"price\"]\n                <= self._max_unit_price * terms.values[\"batch_size\"]\n            )\n            and (terms.values[\"buyer_tx_fee\"] <= self._max_buyer_tx_fee)\n            and (terms.values[\"currency_id\"] == self._currency_id)\n            and (terms.values[\"ledger_id\"] == self._ledger_id)\n            and (terms.values[\"service_id\"] == self._service_id)\n        )\n        return result\n\n    def is_affordable_terms(self, terms: Description) -> bool:\n        \"\"\"\n        Check whether the terms are affordable.\n\n        :param terms: the terms\n        :return: whether it is affordable\n        \"\"\"\n        if self.is_ledger_tx:\n            payable = (\n                terms.values[\"price\"]\n                - terms.values[\"seller_tx_fee\"]\n                + terms.values[\"buyer_tx_fee\"]\n            )\n            result = self.balance >= payable\n        else:\n            result = True\n        return result\n\n    def terms_from_proposal(self, proposal: Description) -> Terms:\n        \"\"\"\n        Get the terms from a proposal.\n\n        :param proposal: the proposal\n        :return: terms\n        \"\"\"\n        buyer_address = self.context.agent_addresses[proposal.values[\"ledger_id\"]]\n        terms = Terms(\n            ledger_id=proposal.values[\"ledger_id\"],\n            sender_address=buyer_address,\n            counterparty_address=proposal.values[\"address\"],\n            amount_by_currency_id={\n                proposal.values[\"currency_id\"]: -proposal.values[\"price\"]\n            },\n            quantities_by_good_id={\n                proposal.values[\"service_id\"]: proposal.values[\"batch_size\"]\n            },\n            is_sender_payable_tx_fee=True,\n            nonce=proposal.values[\"nonce\"],\n            fee_by_currency_id={proposal.values[\"currency_id\"]: self._max_buyer_tx_fee},\n        )\n        return terms\n\n    def update_search_query_params(self) -> None:\n        \"\"\"Update search query params.\"\"\"\n\n    @staticmethod\n    def decode_sample_data(payload: bytes) -> Optional[Tuple[np.ndarray, np.ndarray]]:\n        \"\"\"Deserialize a bytes payload into data (a tuple of two numpy ndarrays or None).\"\"\"\n        decoded_payload = json.loads(payload)\n        if decoded_payload is None:\n            return None\n\n        numpy_data_0 = np.asarray(decoded_payload[\"data_0\"])\n        numpy_data_1 = np.asarray(decoded_payload[\"data_1\"])\n\n        decoded_data = (numpy_data_0, numpy_data_1)\n        return decoded_data\n"
  },
  {
    "path": "packages/fetchai/skills/ml_train/tasks.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tasks for the 'ml_train' skill.\"\"\"\nfrom typing import Any, List, Optional, Tuple\n\nimport numpy as np\n\nfrom aea.skills.tasks import Task\n\n\nclass MLTrainTask(Task):\n    \"\"\"ML train task.\"\"\"\n\n    def __init__(\n        self,\n        train_data: Tuple[np.ndarray, np.ndarray],\n        epochs_per_batch: int = 10,\n        weights: Optional[List[np.ndarray]] = None,\n    ):\n        \"\"\"Initialize the task.\"\"\"\n        super().__init__()\n\n        self.train_x, self.train_y = train_data\n        self.epochs_per_batch = epochs_per_batch\n        self.weights = weights\n\n    def setup(self) -> None:\n        \"\"\"Set up the task.\"\"\"\n        self.logger.info(\"ML Train task: setup method called.\")\n\n    def make_model(self) -> Any:\n        \"\"\"Make model.\"\"\"\n        import tensorflow as tf  # pylint: disable=import-outside-toplevel\n\n        model = tf.keras.Sequential(\n            [\n                tf.keras.layers.Flatten(input_shape=(28, 28)),\n                tf.keras.layers.Dense(128, activation=\"relu\"),\n                tf.keras.layers.Dense(10, activation=\"softmax\"),\n            ]\n        )\n        model.compile(\n            optimizer=\"adam\",\n            loss=\"sparse_categorical_crossentropy\",\n            metrics=[\"accuracy\"],\n        )\n\n        if self.weights is not None:\n            model.set_weights(self.weights)\n\n        return model\n\n    def execute(self, *args: Any, **kwargs: Any) -> Any:\n        \"\"\"Execute the task.\"\"\"\n        self.logger.info(f\"Start training with {self.train_x.shape[0]} rows\")\n\n        model = self.make_model()\n\n        model.fit(self.train_x, self.train_y, epochs=self.epochs_per_batch)\n        new_weights = model.get_weights()\n\n        loss, acc = model.evaluate(self.train_x, self.train_y, verbose=2)\n        self.logger.info(\"Loss: {}, Acc: {}\".format(loss, acc))\n\n        return new_weights\n\n    def teardown(self) -> None:\n        \"\"\"Teardown the task.\"\"\"\n        self.logger.info(\"ML Train task: teardown method called.\")\n"
  },
  {
    "path": "packages/fetchai/skills/registration_aw1/README.md",
    "content": "# Registration AW1\n\n## Description\n\nThe `registration_aw1` skill is for registration in Agent World 1.\n\n## Behaviours\n\n- `registration`: manages the registration flow.\n\n## Handlers\n\n- `registration`: handles `register` messages.\n- `signing`: handles `signing` messages for transaction signing by the decision maker\n\n## Models\n\n- `strategy`: contains the registration configurations\n"
  },
  {
    "path": "packages/fetchai/skills/registration_aw1/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the implementation of the default skill.\"\"\"\n\nfrom aea.configurations.base import PublicId\n\n\nPUBLIC_ID = PublicId.from_str(\"fetchai/registration_aw1:0.13.6\")\n"
  },
  {
    "path": "packages/fetchai/skills/registration_aw1/behaviours.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains a scaffold of a behaviour.\"\"\"\n\nfrom typing import Dict, List, Optional, Set, cast\n\nfrom aea.helpers.transaction.base import RawMessage, Terms\nfrom aea.skills.behaviours import TickerBehaviour\n\nfrom packages.fetchai.protocols.register.message import RegisterMessage\nfrom packages.fetchai.protocols.signing.message import SigningMessage\nfrom packages.fetchai.skills.registration_aw1.dialogues import (\n    RegisterDialogues,\n    SigningDialogues,\n)\nfrom packages.fetchai.skills.registration_aw1.strategy import Strategy\n\n\nclass AW1RegistrationBehaviour(TickerBehaviour):\n    \"\"\"This class scaffolds a behaviour.\"\"\"\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup.\"\"\"\n        strategy = cast(Strategy, self.context.strategy)\n        if strategy.announce_termination_key is not None:\n            self.context.shared_state[strategy.announce_termination_key] = False\n\n        if not strategy.developer_handle_only:\n            signing_dialogues = cast(SigningDialogues, self.context.signing_dialogues)\n            msg, _ = signing_dialogues.create(\n                counterparty=self.context.decision_maker_address,\n                performative=SigningMessage.Performative.SIGN_MESSAGE,\n                raw_message=RawMessage(\n                    strategy.ledger_id, strategy.ethereum_address.encode(\"utf-8\")\n                ),\n                terms=Terms(\n                    ledger_id=strategy.ledger_id,\n                    sender_address=\"\",\n                    counterparty_address=\"\",\n                    amount_by_currency_id={},\n                    quantities_by_good_id={},\n                    nonce=\"\",\n                ),\n            )\n            self.context.logger.info(\"sending signing_msg to decision maker...\")\n            self.context.decision_maker_message_queue.put_nowait(msg)\n\n    def act(self) -> None:\n        \"\"\"Implement the act.\"\"\"\n        strategy = cast(Strategy, self.context.strategy)\n        if not strategy.is_ready_to_register:\n            return\n\n        aw1_registration_aeas: Optional[Set[str]] = self.context.shared_state.get(\n            strategy.shared_storage_key, None\n        )\n        if aw1_registration_aeas is None:\n            return\n\n        if strategy.is_registered or strategy.is_registration_pending:\n            return\n\n        strategy.is_registration_pending = True\n\n        self._register_for_aw1(\n            aw1_registration_aeas, strategy.registration_info, strategy.whitelist\n        )\n\n    def teardown(self) -> None:\n        \"\"\"Implement the task teardown.\"\"\"\n\n    def _register_for_aw1(\n        self,\n        aw1_registration_aeas: Set[str],\n        registration_info: Dict[str, str],\n        whitelist: List[str],\n    ) -> None:\n        \"\"\"\n        Register for Agent World 1.\n\n        :param aw1_registration_aeas: the AEAs to register with\n        :param registration_info: the info to send\n        :param whitelist: the allowed agents\n        \"\"\"\n        register_dialogues = cast(RegisterDialogues, self.context.register_dialogues)\n        for agent in aw1_registration_aeas:\n            if agent not in whitelist:\n                self.context.logger.info(f\"agent={agent} not in whitelist={whitelist}\")\n                return\n            msg, _ = register_dialogues.create(\n                counterparty=agent,\n                performative=RegisterMessage.Performative.REGISTER,\n                info=registration_info,\n            )\n            self.context.logger.info(f\"sending registration info: {registration_info}\")\n            self.context.outbox.put_message(msg)\n"
  },
  {
    "path": "packages/fetchai/skills/registration_aw1/dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nThis module contains the classes required for dialogue management.\n\n- OefSearchDialogue: The dialogue class maintains state of a dialogue and manages it.\n- OefSearchDialogues: The dialogues class keeps track of all dialogues.\n\"\"\"\n\nfrom typing import Any\n\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\nfrom aea.skills.base import Address, Model\n\nfrom packages.fetchai.protocols.register.dialogues import (\n    RegisterDialogue as BaseRegisterDialogue,\n)\nfrom packages.fetchai.protocols.register.dialogues import (\n    RegisterDialogues as BaseRegisterDialogues,\n)\nfrom packages.fetchai.protocols.signing.dialogues import (\n    SigningDialogue as BaseSigningDialogue,\n)\nfrom packages.fetchai.protocols.signing.dialogues import (\n    SigningDialogues as BaseSigningDialogues,\n)\n\n\nRegisterDialogue = BaseRegisterDialogue\n\n\nclass RegisterDialogues(Model, BaseRegisterDialogues):\n    \"\"\"This class keeps track of all register dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return BaseRegisterDialogue.Role.AGENT\n\n        BaseRegisterDialogues.__init__(\n            self,\n            self_address=self.context.agent_address,\n            role_from_first_message=role_from_first_message,\n        )\n\n\nSigningDialogue = BaseSigningDialogue\n\n\nclass SigningDialogues(Model, BaseSigningDialogues):\n    \"\"\"This class keeps track of all signing dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return BaseSigningDialogue.Role.SKILL\n\n        BaseSigningDialogues.__init__(\n            self,\n            self_address=str(self.skill_id),\n            role_from_first_message=role_from_first_message,\n        )\n"
  },
  {
    "path": "packages/fetchai/skills/registration_aw1/handlers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains a scaffold of a handler.\"\"\"\n\nfrom typing import Optional, cast\n\nfrom aea.protocols.base import Message\nfrom aea.skills.base import Handler\n\nfrom packages.fetchai.protocols.register.message import RegisterMessage\nfrom packages.fetchai.protocols.signing.message import SigningMessage\nfrom packages.fetchai.skills.registration_aw1.dialogues import (\n    RegisterDialogue,\n    RegisterDialogues,\n    SigningDialogue,\n    SigningDialogues,\n)\nfrom packages.fetchai.skills.registration_aw1.strategy import Strategy\n\n\nclass AW1RegistrationHandler(Handler):\n    \"\"\"This class handles register messages.\"\"\"\n\n    SUPPORTED_PROTOCOL = RegisterMessage.protocol_id\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to an envelope.\n\n        :param message: the message\n        \"\"\"\n        register_msg = cast(RegisterMessage, message)\n\n        # recover dialogue\n        register_dialogues = cast(RegisterDialogues, self.context.register_dialogues)\n        register_dialogue = cast(\n            Optional[RegisterDialogue], register_dialogues.update(register_msg)\n        )\n        if register_dialogue is None:\n            self._handle_unidentified_dialogue(register_msg)\n            return\n\n        # handle message\n        if register_msg.performative is RegisterMessage.Performative.SUCCESS:\n            self._handle_success(register_msg, register_dialogue)\n        elif register_msg.performative is RegisterMessage.Performative.ERROR:\n            self._handle_error(register_msg, register_dialogue)\n        else:\n            self._handle_invalid(register_msg, register_dialogue)\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n\n    def _handle_unidentified_dialogue(self, register_msg: RegisterMessage) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param register_msg: the message\n        \"\"\"\n        self.context.logger.info(\n            f\"received invalid register_msg message={register_msg}, unidentified dialogue.\"\n        )\n\n    def _handle_success(\n        self, register_msg: RegisterMessage, register_dialogue: RegisterDialogue\n    ) -> None:\n        \"\"\"\n        Handle an register message.\n\n        :param register_msg: the register message\n        :param register_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.debug(\n            f\"received register_msg success message={register_msg} in dialogue={register_dialogue}.\"\n        )\n        self.context.logger.info(\n            f\"received register message success, info={register_msg.info}. Stop me now!\"\n        )\n        strategy = cast(Strategy, self.context.strategy)\n        strategy.is_registered = True\n        strategy.is_registration_pending = False\n        strategy.is_ready_to_register = False\n\n        if strategy.announce_termination_key is not None:\n            self.context.shared_state[strategy.announce_termination_key] = True\n\n    def _handle_error(\n        self, register_msg: RegisterMessage, register_dialogue: RegisterDialogue\n    ) -> None:\n        \"\"\"\n        Handle an register message.\n\n        :param register_msg: the register message\n        :param register_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.debug(\n            f\"received register_msg error message={register_msg} in dialogue={register_dialogue}.\"\n        )\n        self.context.logger.info(\n            f\"received register message error, error_msg={register_msg.error_msg}. Stop me now!\"\n        )\n        strategy = cast(Strategy, self.context.strategy)\n        strategy.is_registration_pending = False\n        strategy.is_ready_to_register = False\n\n    def _handle_invalid(\n        self, register_msg: RegisterMessage, register_dialogue: RegisterDialogue\n    ) -> None:\n        \"\"\"\n        Handle an register message.\n\n        :param register_msg: the register message\n        :param register_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.warning(\n            f\"cannot handle register_msg message of performative={register_msg.performative} in dialogue={register_dialogue}.\"\n        )\n\n\nclass SigningHandler(Handler):\n    \"\"\"Implement the transaction handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = SigningMessage.protocol_id\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup for the handler.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to a message.\n\n        :param message: the message\n        \"\"\"\n        signing_msg = cast(SigningMessage, message)\n\n        # recover dialogue\n        signing_dialogues = cast(SigningDialogues, self.context.signing_dialogues)\n        signing_dialogue = cast(\n            Optional[SigningDialogue], signing_dialogues.update(signing_msg)\n        )\n        if signing_dialogue is None:\n            self._handle_unidentified_dialogue(signing_msg)\n            return\n\n        # handle message\n        if signing_msg.performative is SigningMessage.Performative.SIGNED_MESSAGE:\n            self._handle_signed_message(signing_msg, signing_dialogue)\n        elif signing_msg.performative is SigningMessage.Performative.ERROR:\n            self._handle_error(signing_msg, signing_dialogue)\n        else:\n            self._handle_invalid(signing_msg, signing_dialogue)\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n\n    def _handle_unidentified_dialogue(self, signing_msg: SigningMessage) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param signing_msg: the message\n        \"\"\"\n        self.context.logger.info(\n            f\"received invalid signing message={signing_msg}, unidentified dialogue.\"\n        )\n\n    def _handle_signed_message(\n        self, signing_msg: SigningMessage, signing_dialogue: SigningDialogue\n    ) -> None:\n        \"\"\"\n        Handle a signed message.\n\n        :param signing_msg: the signing message\n        :param signing_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.debug(\n            f\"received signing message from decision maker, message={signing_msg} in dialogue={signing_dialogue}\"\n        )\n        self.context.logger.info(\n            f\"received signing message from decision maker, signature={signing_msg.signed_message.body} stored!\"\n        )\n        strategy = cast(Strategy, self.context.strategy)\n        strategy.signature_of_ethereum_address = signing_msg.signed_message.body\n        strategy.is_ready_to_register = True\n\n    def _handle_error(\n        self, signing_msg: SigningMessage, signing_dialogue: SigningDialogue\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param signing_msg: the signing message\n        :param signing_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.info(\n            f\"transaction signing was not successful. Error_code={signing_msg.error_code} in dialogue={signing_dialogue}\"\n        )\n\n    def _handle_invalid(\n        self, signing_msg: SigningMessage, signing_dialogue: SigningDialogue\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param signing_msg: the signing message\n        :param signing_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.warning(\n            f\"cannot handle signing message of performative={signing_msg.performative} in dialogue={signing_dialogue}.\"\n        )\n"
  },
  {
    "path": "packages/fetchai/skills/registration_aw1/skill.yaml",
    "content": "name: registration_aw1\nauthor: fetchai\nversion: 0.13.6\ntype: skill\ndescription: The registration_aw1 skill is a skill for registration in Agent World\n  1.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: QmUMdQxB7uC3SuP92vfiCRr4fHUeWMcfJNmJ74BoCk8eHT\n  __init__.py: QmYQgGit93v872iD5etZ5k5F2tNo1b5W6Sjtv7nyNwjDh3\n  behaviours.py: QmS5mMwaq2pQSaphNPA4QRxXRBBUpVerLvpYfg532Hb9wk\n  dialogues.py: QmbdecnniJWxH7dnNUB14JKU16BwSKx37USyqcJahEQpVw\n  handlers.py: QmUi9Ry9xd7R8RPFbeW3wePBT26s5q4Mvojs2zuR4xFXfW\n  strategy.py: QmZp5WvwW1qKvgRfWemUDtFiYEQExUqkLuwe89RdBZmtdt\nfingerprint_ignore_patterns: []\nconnections: []\ncontracts: []\nprotocols:\n- fetchai/register:1.1.7\n- fetchai/signing:1.1.7\nskills:\n- fetchai/simple_service_search:0.11.6\nbehaviours:\n  registration:\n    args:\n      tick_interval: 10\n    class_name: AW1RegistrationBehaviour\nhandlers:\n  registration:\n    args: {}\n    class_name: AW1RegistrationHandler\n  signing:\n    args: {}\n    class_name: SigningHandler\nmodels:\n  register_dialogues:\n    args: {}\n    class_name: RegisterDialogues\n  signing_dialogues:\n    args: {}\n    class_name: SigningDialogues\n  strategy:\n    args:\n      announce_termination_key: null\n      developer_handle: PUT_YOUR_DEVELOPER_HANDLE_HERE\n      developer_handle_only: false\n      ethereum_address: PUT_YOUR_ETHEREUM_ADDRESS_HERE\n      shared_storage_key: agents_found\n      signature_of_fetchai_address: PUT_YOUR_SIGNATURE_HERE\n      tweet: PUT_THE_LINK_TO_YOUR_TWEET_HERE\n      whitelist: []\n    class_name: Strategy\ndependencies:\n  aea-ledger-ethereum:\n    version: <2.0.0,>=1.0.0\nis_abstract: false\n"
  },
  {
    "path": "packages/fetchai/skills/registration_aw1/strategy.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains a scaffold of a model.\"\"\"\n\nfrom typing import Any, Dict, List, Optional\n\nfrom aea.crypto.ledger_apis import LedgerApis\nfrom aea.exceptions import enforce\nfrom aea.skills.base import Model\n\n\nDEFAULT_SHARED_STORAGE_KEY = \"agents_found\"\nDEFAULT_ETHEREUM_ADDRESS = \"PUT_YOUR_ETHEREUM_ADDRESS_HERE\"\nDEFAULT_SIGNATURE_OF_FETCHAI_ADDRESS = \"PUT_YOUR_SIGNATURE_HERE\"\nDEFAULT_DEVELOPER_HANDLE = \"PUT_YOUR_DEVELOPER_HANDLE_HERE\"\nDEFAULT_TWEET = \"PUT_THE_LINK_TO_YOUR_TWEET_HERE\"\nDEFAULT_WHITELIST: List[str] = []\n\n\nclass Strategy(Model):\n    \"\"\"This class is the strategy model.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize the strategy of the agent.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        developer_handle = kwargs.pop(\"developer_handle\", DEFAULT_DEVELOPER_HANDLE)\n        enforce(\n            developer_handle != DEFAULT_DEVELOPER_HANDLE\n            and isinstance(developer_handle, str),\n            f\"Not a valid developer_handle: {developer_handle}\",\n        )\n        self._developer_handle = developer_handle\n        self._whitelist = kwargs.pop(\"whitelist\", DEFAULT_WHITELIST)\n        self._shared_storage_key = kwargs.pop(\n            \"shared_storage_key\", DEFAULT_SHARED_STORAGE_KEY\n        )\n        self.announce_termination_key = kwargs.pop(\"announce_termination_key\", None)\n\n        self.developer_handle_only = kwargs.pop(\"developer_handle_only\", False)\n        if not self.developer_handle_only:\n            ethereum_address = kwargs.pop(\"ethereum_address\", DEFAULT_ETHEREUM_ADDRESS)\n            enforce(\n                ethereum_address != DEFAULT_ETHEREUM_ADDRESS\n                and LedgerApis.is_valid_address(\"ethereum\", ethereum_address),\n                f\"Not a valid ethereum_address: {ethereum_address}\",\n            )\n            self._ethereum_address = ethereum_address\n            signature_of_fetchai_address = kwargs.pop(\n                \"signature_of_fetchai_address\", DEFAULT_SIGNATURE_OF_FETCHAI_ADDRESS\n            )\n            enforce(\n                signature_of_fetchai_address != DEFAULT_SIGNATURE_OF_FETCHAI_ADDRESS\n                and isinstance(signature_of_fetchai_address, str),\n                f\"Not a valid signature_of_fetchai_address: {signature_of_fetchai_address}\",\n            )\n            self._signature_of_fetchai_address = signature_of_fetchai_address\n            tweet = kwargs.pop(\"tweet\", DEFAULT_TWEET)\n            enforce(isinstance(tweet, str), \"Not a valid tweet link\")\n            self._tweet = tweet\n            self._is_ready_to_register = False\n        else:\n            self._is_ready_to_register = True\n            self._ethereum_address = \"some_dummy_address\"\n            self._signature_of_fetchai_address = None\n            self._tweet = None\n        super().__init__(**kwargs)\n        self._is_registered = False\n        self.is_registration_pending = False\n        self.signature_of_ethereum_address: Optional[str] = None\n        self._ledger_id = self.context.default_ledger_id\n\n    @property\n    def shared_storage_key(self) -> str:\n        \"\"\"Get shared storage key.\"\"\"\n        return self._shared_storage_key\n\n    @property\n    def whitelist(self) -> List[str]:\n        \"\"\"Get the whitelist.\"\"\"\n        return self._whitelist\n\n    @property\n    def ethereum_address(self) -> str:\n        \"\"\"Get the ethereum address.\"\"\"\n        return self._ethereum_address\n\n    @property\n    def ledger_id(self) -> str:\n        \"\"\"Get ledger id.\"\"\"\n        return self._ledger_id\n\n    @property\n    def is_ready_to_register(self) -> bool:\n        \"\"\"Get readiness for registration.\"\"\"\n        return self._is_ready_to_register\n\n    @is_ready_to_register.setter\n    def is_ready_to_register(self, is_ready_to_register: bool) -> None:\n        \"\"\"Set readiness for registration.\"\"\"\n        self._is_ready_to_register = is_ready_to_register\n\n    @property\n    def is_registered(self) -> bool:\n        \"\"\"Get registration status.\"\"\"\n        return self._is_registered\n\n    @is_registered.setter\n    def is_registered(self, is_registered: bool) -> None:\n        \"\"\"Set registration status.\"\"\"\n        enforce(not self._is_registered, \"Can only switch to true.\")\n        self._is_registered = is_registered\n\n    @property\n    def registration_info(self) -> Dict[str, str]:\n        \"\"\"\n        Get the location description.\n\n        :return: a description of the agent's location\n        \"\"\"\n        if self.developer_handle_only:\n            info = {\n                \"fetchai_address\": self.context.agent_address,\n                \"developer_handle\": self._developer_handle,\n            }\n        else:\n            info = {\n                \"ethereum_address\": self._ethereum_address,\n                \"fetchai_address\": self.context.agent_address,\n                \"signature_of_ethereum_address\": self.signature_of_ethereum_address,\n                \"signature_of_fetchai_address\": self._signature_of_fetchai_address,\n                \"developer_handle\": self._developer_handle,\n            }\n            if self._tweet != DEFAULT_TWEET:\n                info.update({\"tweet\": self._tweet})\n        return info\n"
  },
  {
    "path": "packages/fetchai/skills/simple_aggregation/README.md",
    "content": "# Simple Aggregation\n\n## Description\n\nThis skill is used to find peers on the agent communication network, exchange observations of some real-world quantity, and periodically aggregate the collected observations.\n\n## Behaviours\n\n- `search_behaviour`: searches for other aggregating peers every `search_interval` seconds, as specified in the skill configuration.\n- `aggregation_behaviour`: makes observations and aggregates those received from peers every `aggregation_interval` seconds, as specified in the skill configuration.\n\n## Handlers\n\n- `aggregation`: handles `aggregation` messages to and from peers\n- `oef_search`: handles `oef_search` messages for interacting with the SOEF\n"
  },
  {
    "path": "packages/fetchai/skills/simple_aggregation/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the implementation of the oracle aggregation skill.\"\"\"\n\nfrom aea.configurations.base import PublicId\n\n\nPUBLIC_ID = PublicId.from_str(\"fetchai/simple_aggregation:0.3.6\")\n"
  },
  {
    "path": "packages/fetchai/skills/simple_aggregation/behaviours.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains the behaviours for the oracle aggregation skill.\"\"\"\n\nfrom time import time\nfrom typing import Any, Optional, cast\n\nfrom aea.helpers.search.models import Description\nfrom aea.skills.behaviours import TickerBehaviour\n\nfrom packages.fetchai.protocols.aggregation.message import AggregationMessage\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.skills.simple_aggregation.dialogues import (\n    AggregationDialogues,\n    OefSearchDialogues,\n)\nfrom packages.fetchai.skills.simple_aggregation.strategy import AggregationStrategy\n\n\nDEFAULT_SEARCH_INTERVAL = 30.0\nDEFAULT_MAX_SOEF_REGISTRATION_RETRIES = 5\nDEFAULT_AGGREGATION_INTERVAL = 5.0\nDEFAULT_SOURCE = \"\"\nDEFAULT_SIGNATURE = \"\"\n\n\nclass SearchBehaviour(TickerBehaviour):\n    \"\"\"This class implements the service registration behaviour for the simple aggregation skill\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"Initialize the search behaviour.\"\"\"\n        search_interval = cast(\n            float, kwargs.pop(\"search_interval\", DEFAULT_SEARCH_INTERVAL)\n        )\n        self._max_soef_registration_retries = kwargs.pop(\n            \"max_soef_registration_retries\", DEFAULT_MAX_SOEF_REGISTRATION_RETRIES\n        )  # type: int\n        super().__init__(tick_interval=search_interval, **kwargs)\n\n        self.failed_registration_msg = None  # type: Optional[OefSearchMessage]\n        self._nb_retries = 0\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup for the behaviour.\"\"\"\n        self._register_agent()\n\n    def act(self) -> None:\n        \"\"\"Implement the act.\"\"\"\n        self._retry_failed_registration()\n\n        strategy = cast(AggregationStrategy, self.context.strategy)\n        query = strategy.get_location_and_service_query()\n        oef_search_dialogues = cast(\n            OefSearchDialogues, self.context.oef_search_dialogues\n        )\n        oef_search_msg, _ = oef_search_dialogues.create(\n            counterparty=self.context.search_service_address,\n            performative=OefSearchMessage.Performative.SEARCH_SERVICES,\n            query=query,\n        )\n        self.context.outbox.put_message(message=oef_search_msg)\n\n    def teardown(self) -> None:\n        \"\"\"Implement the task teardown.\"\"\"\n        self._unregister_service()\n        self._unregister_agent()\n\n    def _retry_failed_registration(self) -> None:\n        \"\"\"Retry a failed registration.\"\"\"\n        if self.failed_registration_msg is not None:\n            self._nb_retries += 1\n            if self._nb_retries > self._max_soef_registration_retries:\n                self.context.is_active = False\n                return\n\n            oef_search_dialogues = cast(\n                OefSearchDialogues, self.context.oef_search_dialogues\n            )\n            oef_search_msg, _ = oef_search_dialogues.create(\n                counterparty=self.failed_registration_msg.to,\n                performative=self.failed_registration_msg.performative,\n                service_description=self.failed_registration_msg.service_description,\n            )\n            self.context.outbox.put_message(message=oef_search_msg)\n            self.context.logger.info(\n                f\"Retrying registration on SOEF. Retry {self._nb_retries} out of {self._max_soef_registration_retries}.\"\n            )\n\n            self.failed_registration_msg = None\n\n    def _register(self, description: Description, logger_msg: str) -> None:\n        \"\"\"\n        Register something on the SOEF.\n\n        :param description: the description of what is being registered\n        :param logger_msg: the logger message to print after the registration\n        \"\"\"\n        oef_search_dialogues = cast(\n            OefSearchDialogues, self.context.oef_search_dialogues\n        )\n        oef_search_msg, _ = oef_search_dialogues.create(\n            counterparty=self.context.search_service_address,\n            performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n            service_description=description,\n        )\n        self.context.outbox.put_message(message=oef_search_msg)\n        self.context.logger.info(logger_msg)\n\n    def _register_agent(self) -> None:\n        \"\"\"Register the agent's location.\"\"\"\n        strategy = cast(AggregationStrategy, self.context.strategy)\n        description = strategy.get_location_description()\n        self._register(description, \"registering agent on SOEF.\")\n\n    def register_service(self) -> None:\n        \"\"\"Register the agent's service.\"\"\"\n        strategy = cast(AggregationStrategy, self.context.strategy)\n        description = strategy.get_register_service_description()\n        self._register(description, \"registering agent's service on the SOEF.\")\n\n    def register_genus(self) -> None:\n        \"\"\"Register the agent's personality genus.\"\"\"\n        strategy = cast(AggregationStrategy, self.context.strategy)\n        description = strategy.get_register_personality_description()\n        self._register(\n            description, \"registering agent's personality genus on the SOEF.\"\n        )\n\n    def register_classification(self) -> None:\n        \"\"\"Register the agent's personality classification.\"\"\"\n        strategy = cast(AggregationStrategy, self.context.strategy)\n        description = strategy.get_register_classification_description()\n        self._register(\n            description, \"registering agent's personality classification on the SOEF.\"\n        )\n\n    def _unregister_service(self) -> None:\n        \"\"\"Unregister service from the SOEF.\"\"\"\n        strategy = cast(AggregationStrategy, self.context.strategy)\n        description = strategy.get_unregister_service_description()\n        oef_search_dialogues = cast(\n            OefSearchDialogues, self.context.oef_search_dialogues\n        )\n        oef_search_msg, _ = oef_search_dialogues.create(\n            counterparty=self.context.search_service_address,\n            performative=OefSearchMessage.Performative.UNREGISTER_SERVICE,\n            service_description=description,\n        )\n        self.context.outbox.put_message(message=oef_search_msg)\n        self.context.logger.info(\"unregistering service from SOEF.\")\n\n    def _unregister_agent(self) -> None:\n        \"\"\"Unregister agent from the SOEF.\"\"\"\n        strategy = cast(AggregationStrategy, self.context.strategy)\n        description = strategy.get_location_description()\n        oef_search_dialogues = cast(\n            OefSearchDialogues, self.context.oef_search_dialogues\n        )\n        oef_search_msg, _ = oef_search_dialogues.create(\n            counterparty=self.context.search_service_address,\n            performative=OefSearchMessage.Performative.UNREGISTER_SERVICE,\n            service_description=description,\n        )\n        self.context.outbox.put_message(message=oef_search_msg)\n        self.context.logger.info(\"unregistering agent from SOEF.\")\n\n\nclass AggregationBehaviour(TickerBehaviour):\n    \"\"\"This class implements an aggregation behaviour.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"Initialize the aggregation behaviour.\"\"\"\n        aggregation_interval = cast(\n            float, kwargs.pop(\"aggregation_interval\", DEFAULT_AGGREGATION_INTERVAL)\n        )\n        super().__init__(tick_interval=aggregation_interval, **kwargs)\n\n    def act(self) -> None:\n        \"\"\"Implement the act.\"\"\"\n        strategy = cast(AggregationStrategy, self.context.strategy)\n        quantity = self.context.shared_state.get(strategy.quantity_name, {})\n        value = quantity.get(\"value\", None)\n        if value:\n            strategy.make_observation(\n                value,\n                str(time()),\n                source=DEFAULT_SOURCE,\n                signature=DEFAULT_SIGNATURE,\n            )\n        self.broadcast_observation()\n\n    def broadcast_observation(self) -> None:\n        \"\"\"Send latest observation to current list of peers.\"\"\"\n        strategy = cast(AggregationStrategy, self.context.strategy)\n        obs = strategy.observation\n        if obs is None:\n            self.context.logger.info(\"No observation to send\")\n            return\n        aggregation_dialogues = cast(\n            AggregationDialogues, self.context.aggregation_dialogues\n        )\n        for counterparty in strategy.peers:\n            obs_msg, _ = aggregation_dialogues.create(\n                counterparty=counterparty,\n                performative=AggregationMessage.Performative.OBSERVATION,\n                **obs,\n            )\n            self.context.outbox.put_message(message=obs_msg)\n            self.context.logger.info(\n                \"sending observation to peer={}\".format(counterparty[-5:])\n            )\n"
  },
  {
    "path": "packages/fetchai/skills/simple_aggregation/dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains the dialogues for the oracle aggregation skill.\"\"\"\n\n\nfrom typing import Any\n\nfrom aea.common import Address\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\nfrom aea.skills.base import Model\n\nfrom packages.fetchai.protocols.aggregation.dialogues import (\n    AggregationDialogue as BaseAggregationDialogue,\n)\nfrom packages.fetchai.protocols.aggregation.dialogues import (\n    AggregationDialogues as BaseAggregationDialogues,\n)\nfrom packages.fetchai.protocols.default.dialogues import (\n    DefaultDialogue as BaseDefaultDialogue,\n)\nfrom packages.fetchai.protocols.default.dialogues import (\n    DefaultDialogues as BaseDefaultDialogues,\n)\nfrom packages.fetchai.protocols.oef_search.dialogues import (\n    OefSearchDialogue as BaseOefSearchDialogue,\n)\nfrom packages.fetchai.protocols.oef_search.dialogues import (\n    OefSearchDialogues as BaseOefSearchDialogues,\n)\n\n\nDefaultDialogue = BaseDefaultDialogue\n\n\nclass DefaultDialogues(Model, BaseDefaultDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return DefaultDialogue.Role.AGENT\n\n        BaseDefaultDialogues.__init__(\n            self,\n            self_address=self.context.agent_address,\n            role_from_first_message=role_from_first_message,\n        )\n\n\nAggregationDialogue = BaseAggregationDialogue\n\n\nclass AggregationDialogues(Model, BaseAggregationDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return BaseAggregationDialogue.Role.AGENT\n\n        BaseAggregationDialogues.__init__(\n            self,\n            self_address=self.context.agent_address,\n            role_from_first_message=role_from_first_message,\n            dialogue_class=AggregationDialogue,\n        )\n\n\nOefSearchDialogue = BaseOefSearchDialogue\n\n\nclass OefSearchDialogues(Model, BaseOefSearchDialogues):\n    \"\"\"This class keeps track of all oef_search dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return BaseOefSearchDialogue.Role.AGENT\n\n        BaseOefSearchDialogues.__init__(\n            self,\n            self_address=str(self.skill_id),\n            role_from_first_message=role_from_first_message,\n        )\n"
  },
  {
    "path": "packages/fetchai/skills/simple_aggregation/handlers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains the handlers for the oracle aggregation skill.\"\"\"\n\nfrom typing import Any, Dict, Optional, cast\n\nfrom aea.configurations.base import PublicId\nfrom aea.protocols.base import Message\nfrom aea.skills.base import Handler\n\nfrom packages.fetchai.protocols.aggregation.message import AggregationMessage\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.skills.simple_aggregation.behaviours import SearchBehaviour\nfrom packages.fetchai.skills.simple_aggregation.dialogues import (\n    AggregationDialogue,\n    AggregationDialogues,\n    DefaultDialogues,\n    OefSearchDialogue,\n    OefSearchDialogues,\n)\nfrom packages.fetchai.skills.simple_aggregation.strategy import AggregationStrategy\n\n\ndef get_observation_from_message(obs_msg: AggregationMessage) -> Dict[str, Any]:\n    \"\"\"\n    Extract the observation from an observation message\n\n    :param obs_msg: the message\n    :return: the observation dict\n    \"\"\"\n    obs = {\n        \"value\": obs_msg.value,\n        \"time\": obs_msg.time,\n        \"source\": obs_msg.source,\n        \"signature\": obs_msg.signature,\n    }\n    return obs\n\n\nclass AggregationHandler(Handler):\n    \"\"\"This class implements a simple aggregation handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = AggregationMessage.protocol_id  # type: Optional[PublicId]\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup for the handler.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to a message.\n\n        :param message: the message\n        \"\"\"\n        aggregation_msg = cast(AggregationMessage, message)\n\n        # recover dialogue\n        aggregation_dialogues = cast(\n            AggregationDialogues, self.context.aggregation_dialogues\n        )\n        aggregation_dialogue = cast(\n            AggregationDialogue, aggregation_dialogues.update(aggregation_msg)\n        )\n        if aggregation_dialogue is None:\n            self._handle_unidentified_dialogue(aggregation_msg)\n            return\n\n        # handle message\n        if aggregation_msg.performative == AggregationMessage.Performative.OBSERVATION:\n            self._handle_observation(aggregation_msg)\n        elif (\n            aggregation_msg.performative == AggregationMessage.Performative.AGGREGATION\n        ):\n            self._handle_aggregation(aggregation_msg)\n        else:\n            self._handle_invalid(\n                aggregation_msg, aggregation_dialogue\n            )  # pragma: nocover\n\n    def _handle_unidentified_dialogue(\n        self, aggregation_msg: AggregationMessage\n    ) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param aggregation_msg: the message\n        \"\"\"\n        self.context.logger.info(\n            \"received invalid aggregation message={}, unidentified dialogue.\".format(\n                aggregation_msg\n            )\n        )\n        default_dialogues = cast(DefaultDialogues, self.context.default_dialogues)\n        default_msg, _ = default_dialogues.create(\n            counterparty=aggregation_msg.sender,\n            performative=DefaultMessage.Performative.ERROR,\n            error_code=DefaultMessage.ErrorCode.INVALID_DIALOGUE,\n            error_msg=\"Invalid dialogue.\",\n            error_data={\"aggregation_message\": aggregation_msg.encode()},\n        )\n        self.context.outbox.put_message(message=default_msg)\n\n    def _handle_observation(self, obs_msg: AggregationMessage) -> None:\n        \"\"\"\n        Handle the observation.\n\n        :param obs_msg: the message\n        \"\"\"\n        self.context.logger.info(\n            \"received observation from sender={}\".format(obs_msg.sender[-5:])\n        )\n\n        strategy = cast(AggregationStrategy, self.context.strategy)\n        obs = get_observation_from_message(obs_msg)\n\n        strategy.add_observation(obs_msg.sender, obs)\n        strategy.aggregate_observations()\n\n        self.context.logger.info(f\"observation: {obs}\")\n\n    def _handle_aggregation(self, aggregation_msg: AggregationMessage) -> None:\n        \"\"\"\n        Handle the aggregation.\n\n        :param aggregation_msg: the message\n        \"\"\"\n        self.context.logger.info(\n            \"received aggregation from sender={}\".format(aggregation_msg.sender[-5:])\n        )\n\n    def _handle_invalid(\n        self,\n        aggregation_msg: AggregationMessage,\n        aggregation_dialogue: AggregationDialogue,\n    ) -> None:\n        \"\"\"\n        Handle a aggregation message of invalid performative.\n\n        :param aggregation_msg: the message\n        :param aggregation_dialogue: the dialogue object\n        \"\"\"\n        self.context.logger.warning(\n            \"cannot handle aggregation message of performative={} in dialogue={}.\".format(\n                aggregation_msg.performative, aggregation_dialogue\n            )\n        )  # pragma: nocover\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n\n\nclass OefSearchHandler(Handler):\n    \"\"\"This class implements an OEF search handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = OefSearchMessage.protocol_id  # type: Optional[PublicId]\n\n    def setup(self) -> None:\n        \"\"\"Call to setup the handler.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to a message.\n\n        :param message: the message\n        \"\"\"\n        oef_search_msg = cast(OefSearchMessage, message)\n\n        # recover dialogue\n        oef_search_dialogues = cast(\n            OefSearchDialogues, self.context.oef_search_dialogues\n        )\n        oef_search_dialogue = cast(\n            Optional[OefSearchDialogue], oef_search_dialogues.update(oef_search_msg)\n        )\n        if oef_search_dialogue is None:\n            self._handle_unidentified_dialogue(oef_search_msg)\n            return\n\n        # handle message\n        if oef_search_msg.performative == OefSearchMessage.Performative.SUCCESS:\n            self._handle_success(oef_search_msg, oef_search_dialogue)\n        elif oef_search_msg.performative == OefSearchMessage.Performative.OEF_ERROR:\n            self._handle_error(oef_search_msg, oef_search_dialogue)\n        elif oef_search_msg.performative is OefSearchMessage.Performative.SEARCH_RESULT:\n            self._handle_search(oef_search_msg, oef_search_dialogue)\n        else:\n            self._handle_invalid(oef_search_msg, oef_search_dialogue)\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n\n    def _handle_unidentified_dialogue(self, oef_search_msg: OefSearchMessage) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param oef_search_msg: the message\n        \"\"\"\n        self.context.logger.info(\n            \"received invalid oef_search message={}, unidentified dialogue.\".format(\n                oef_search_msg\n            )\n        )\n\n    def _handle_success(\n        self,\n        oef_search_success_msg: OefSearchMessage,\n        oef_search_dialogue: OefSearchDialogue,\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param oef_search_success_msg: the oef search message\n        :param oef_search_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.info(\n            \"received oef_search success message={} in dialogue={}.\".format(\n                oef_search_success_msg, oef_search_dialogue\n            )\n        )\n        target_message = cast(\n            OefSearchMessage,\n            oef_search_dialogue.get_message_by_id(oef_search_success_msg.target),\n        )\n        if (\n            target_message.performative\n            == OefSearchMessage.Performative.REGISTER_SERVICE\n        ):\n            description = target_message.service_description\n            data_model_name = description.data_model.name\n            registration_behaviour = cast(\n                SearchBehaviour,\n                self.context.behaviours.search,\n            )\n            if \"location_agent\" in data_model_name:\n                registration_behaviour.register_service()\n            elif \"set_service_key\" in data_model_name:\n                registration_behaviour.register_genus()\n            elif (\n                \"personality_agent\" in data_model_name\n                and description.values[\"piece\"] == \"genus\"\n            ):\n                registration_behaviour.register_classification()\n            elif (\n                \"personality_agent\" in data_model_name\n                and description.values[\"piece\"] == \"classification\"\n            ):\n                self.context.logger.info(\n                    \"the agent, with its genus and classification, and its service are successfully registered on the SOEF.\"\n                )\n            else:\n                self.context.logger.warning(\n                    f\"received soef SUCCESS message as a reply to the following unexpected message: {target_message}\"\n                )\n\n    def _handle_error(\n        self,\n        oef_search_error_msg: OefSearchMessage,\n        oef_search_dialogue: OefSearchDialogue,\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param oef_search_error_msg: the oef search message\n        :param oef_search_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.info(\n            \"received oef_search error message={} in dialogue={}.\".format(\n                oef_search_error_msg, oef_search_dialogue\n            )\n        )\n        target_message = cast(\n            OefSearchMessage,\n            oef_search_dialogue.get_message_by_id(oef_search_error_msg.target),\n        )\n        if (\n            target_message.performative\n            == OefSearchMessage.Performative.REGISTER_SERVICE\n        ):\n            registration_behaviour = cast(\n                SearchBehaviour,\n                self.context.behaviours.search,\n            )\n            registration_behaviour.failed_registration_msg = target_message\n\n    def _handle_search(\n        self, oef_search_msg: OefSearchMessage, oef_search_dialogue: OefSearchDialogue\n    ) -> None:\n        \"\"\"\n        Handle the search response.\n\n        :param oef_search_msg: the oef search message\n        :param oef_search_dialogue: the dialogue\n        \"\"\"\n        if len(oef_search_msg.agents) == 0:\n            self.context.logger.info(\n                f\"found no agents in dialogue={oef_search_dialogue}, continue searching.\"\n            )\n            return\n        strategy = cast(AggregationStrategy, self.context.strategy)\n        self.context.logger.info(\n            \"found agents={}.\".format(\n                list(map(lambda x: x[-5:], oef_search_msg.agents)),\n            )\n        )\n        strategy.add_peers(oef_search_msg.agents)\n\n    def _handle_invalid(\n        self, oef_search_msg: OefSearchMessage, oef_search_dialogue: OefSearchDialogue\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param oef_search_msg: the oef search message\n        :param oef_search_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.warning(\n            \"cannot handle oef_search message of performative={} in dialogue={}.\".format(\n                oef_search_msg.performative,\n                oef_search_dialogue,\n            )\n        )\n"
  },
  {
    "path": "packages/fetchai/skills/simple_aggregation/skill.yaml",
    "content": "name: simple_aggregation\nauthor: fetchai\nversion: 0.3.6\ntype: skill\ndescription: The skill for aggregating observations between AEAs\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: QmcHh82NQkgDx4w2cNN6sGzWquSXEYp4BgPrbSBo5tTf2w\n  __init__.py: QmacrtqzSrgzHTp2bqiVLPjDMydiVKNN6AtJG8sEzRVu1o\n  behaviours.py: QmXsdJUEC9MPAGQvUgUYuZV8du9Dtejexbe941sqgYaSzh\n  dialogues.py: QmeGB6miynaHtBG9LU96tiwCp8AKZwJ8y9oGqVeRNkWpvW\n  handlers.py: QmNYga7nHVfyrqsnHCPYXKSVkY9gvsxHCQufHR4Ls2AVyD\n  strategy.py: QmTepCGXskTbVh9AqigU5JN4my9Qbj4prvtsPVrreYnt6p\nfingerprint_ignore_patterns: []\ncontracts: []\nprotocols:\n- fetchai/aggregation:0.2.7\n- fetchai/default:1.1.7\n- fetchai/oef_search:1.1.7\nskills: []\nbehaviours:\n  aggregation:\n    args:\n      aggregation_interval: 10\n    class_name: AggregationBehaviour\n  search:\n    args:\n      max_soef_registration_retries: 5\n      search_interval: 10\n    class_name: SearchBehaviour\nhandlers:\n  aggregation:\n    args: {}\n    class_name: AggregationHandler\n  oef_search:\n    args: {}\n    class_name: OefSearchHandler\nmodels:\n  aggregation_dialogues:\n    args: {}\n    class_name: AggregationDialogues\n  default_dialogues:\n    args: {}\n    class_name: DefaultDialogues\n  oef_search_dialogues:\n    args: {}\n    class_name: OefSearchDialogues\n  strategy:\n    args:\n      aggregation_function: mean\n      classification:\n        piece: classification\n        value: agent\n      decimals: 0\n      location:\n        latitude: 51.5194\n        longitude: 0.127\n      personality_data:\n        piece: genus\n        value: data\n      quantity_name: null\n      search_query:\n        constraint_type: ==\n        search_key: service\n        search_value: generic_aggregation_service\n      search_radius: 5.0\n      service_id: generic_aggregation_service\n    class_name: AggregationStrategy\ndependencies: {}\nis_abstract: false\nconnections: []\n"
  },
  {
    "path": "packages/fetchai/skills/simple_aggregation/strategy.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains the strategy for the oracle aggregation skill.\"\"\"\n\nimport statistics\nfrom typing import Any, Dict, Optional, Set, Tuple\n\nfrom aea.common import Address\nfrom aea.exceptions import enforce\nfrom aea.helpers.search.generic import (\n    AGENT_LOCATION_MODEL,\n    AGENT_PERSONALITY_MODEL,\n    AGENT_REMOVE_SERVICE_MODEL,\n    AGENT_SET_SERVICE_MODEL,\n)\nfrom aea.helpers.search.models import (\n    Constraint,\n    ConstraintType,\n    Description,\n    Location,\n    Query,\n)\nfrom aea.skills.base import Model\n\n\nDEFAULT_SEARCH_RADIUS = 5.0\nDEFAULT_SERVICE_ID = \"aggregation\"\nDEFAULT_AGGREGATION_FUNCTION = \"mean\"\nDEFAULT_SERVICE_DATA = {\"key\": \"service\", \"value\": \"generic_aggregation_service\"}\nDEFAULT_QUANTITY_NAME = \"quantity\"\nDEFAULT_PERSONALITY_DATA = {\"piece\": \"genus\", \"value\": \"data\"}\nDEFAULT_CLASSIFICATION = {\"piece\": \"classification\", \"value\": \"agent\"}\nDEFAULT_LOCATION = {\"longitude\": 0.1270, \"latitude\": 51.5194}\nDEFAULT_SEARCH_QUERY = {\n    \"search_key\": \"service\",\n    \"search_value\": \"generic_aggregation_service\",\n    \"constraint_type\": \"==\",\n}\nIMPLEMENTED_AGGREGATION_FUNCTIONS = {\"mean\", \"median\", \"mode\"}\nDEFAULT_DECIMALS = 0\n\n\nclass AggregationStrategy(Model):\n    \"\"\"This class defines a strategy for the agent.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize the strategy of the agent.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n\n        self._round = 0\n        self._peers = set()  # type: Set[Address]\n        self._observations = {}  # type: Dict[Address, Dict[str, Any]]\n        self._aggregation = None  # type: Optional[Any]\n\n        self._quantity_name = kwargs.pop(\"quantity_name\", DEFAULT_QUANTITY_NAME)\n        self._service_id = kwargs.pop(\"service_id\", DEFAULT_SERVICE_ID)\n        self._aggregation_function = kwargs.pop(\n            \"aggregation_function\", DEFAULT_AGGREGATION_FUNCTION\n        )\n        enforce(\n            self._aggregation_function in IMPLEMENTED_AGGREGATION_FUNCTIONS,\n            f\"aggregation_function must be one of {IMPLEMENTED_AGGREGATION_FUNCTIONS}\",\n        )\n        self._aggregate = getattr(statistics, self._aggregation_function)\n\n        self._search_query = kwargs.pop(\"search_query\", DEFAULT_SEARCH_QUERY)\n        location = kwargs.pop(\"location\", DEFAULT_LOCATION)\n        self._agent_location = {\n            \"location\": Location(\n                latitude=location[\"latitude\"], longitude=location[\"longitude\"]\n            )\n        }\n        self._radius = kwargs.pop(\"search_radius\", DEFAULT_SEARCH_RADIUS)\n        self._decimals = kwargs.pop(\"decimals\", DEFAULT_DECIMALS)\n\n        self._set_personality_data = kwargs.pop(\n            \"personality_data\", DEFAULT_PERSONALITY_DATA\n        )\n        enforce(\n            len(self._set_personality_data) == 2\n            and \"piece\" in self._set_personality_data\n            and \"value\" in self._set_personality_data,\n            \"personality_data must contain keys `key` and `value`\",\n        )\n        self._set_classification = kwargs.pop(\"classification\", DEFAULT_CLASSIFICATION)\n        enforce(\n            len(self._set_classification) == 2\n            and \"piece\" in self._set_classification\n            and \"value\" in self._set_classification,\n            \"classification must contain keys `key` and `value`\",\n        )\n        self._set_service_data = kwargs.pop(\"service_data\", DEFAULT_SERVICE_DATA)\n        enforce(\n            len(self._set_service_data) == 2\n            and \"key\" in self._set_service_data\n            and \"value\" in self._set_service_data,\n            \"service_data must contain keys `key` and `value`\",\n        )\n        self._remove_service_data = {\"key\": self._set_service_data[\"key\"]}\n        self._simple_service_data = {\n            self._set_service_data[\"key\"]: self._set_service_data[\"value\"]\n        }\n\n        super().__init__(**kwargs)\n\n        ledger_id = kwargs.pop(\"ledger_id\", None)\n        self._ledger_id = (\n            ledger_id if ledger_id is not None else self.context.default_ledger_id\n        )\n\n    @property\n    def ledger_id(self) -> str:\n        \"\"\"Get the ledger id.\"\"\"\n        return self._ledger_id  # pragma: nocover\n\n    @property\n    def observation(self) -> Optional[Dict[str, Any]]:\n        \"\"\"Get latest observation\"\"\"\n        my_address = self.context.agent_addresses[self._ledger_id]\n        return self._observations.get(my_address, None)\n\n    @property\n    def peers(self) -> Set[str]:\n        \"\"\"Get registered peers.\"\"\"\n        return self._peers\n\n    @property\n    def quantity_name(self) -> str:\n        \"\"\"Get the name of the quantity to aggregate.\"\"\"\n        return self._quantity_name\n\n    def add_peers(self, found_peers: Tuple[str, ...]) -> None:\n        \"\"\"\n        Update registered peers with list found in search\n\n        :param found_peers: the peers found\n        \"\"\"\n        for _, peer in enumerate(found_peers):\n            self._peers.add(peer)\n\n    def add_observation(self, peer: Address, obs: Dict[str, Any]) -> None:\n        \"\"\"Add new observation to list of observations\"\"\"\n        if peer in self._peers:\n            self._observations[peer] = obs\n\n    def make_observation(\n        self, value: int, obs_time: str, source: str = \"\", signature: str = \"\"\n    ) -> None:\n        \"\"\"Make observation of oracle value\"\"\"\n        my_address = self.context.agent_addresses[self._ledger_id]\n        observation = dict(\n            value=value, time=obs_time, source=source, signature=signature\n        )\n        self.context.logger.info(f\"Observation: {observation}\")\n        self._observations[my_address] = observation\n\n    def aggregate_observations(self) -> None:\n        \"\"\"Aggregate values from all observations from myself and peers\"\"\"\n        values = [float(obs[\"value\"]) for obs in self._observations.values()]\n        if len(values) == 0:  # pragma: nocover\n            self.context.logger.info(\"No observations to aggregate\")\n            return\n        self._aggregation = self._aggregate(values)\n        aggregated_key = self.quantity_name + \"_\" + self._aggregation_function\n        self.context.shared_state[aggregated_key] = {\n            \"value\": int(self._aggregation),\n            \"decimals\": self._decimals,\n        }\n        self.context.logger.info(f\"Observations: {values}\")\n        self.context.logger.info(\n            f\"Aggregation ({self._aggregation_function}): {self._aggregation}\"\n        )\n\n    def get_location_description(self) -> Description:\n        \"\"\"\n        Get the location description.\n\n        :return: a description of the agent's location\n        \"\"\"\n        description = Description(\n            self._agent_location,\n            data_model=AGENT_LOCATION_MODEL,\n        )\n        return description\n\n    def get_register_service_description(self) -> Description:\n        \"\"\"\n        Get the register service description.\n\n        :return: a description of the offered services\n        \"\"\"\n        description = Description(\n            self._set_service_data,\n            data_model=AGENT_SET_SERVICE_MODEL,\n        )\n        return description\n\n    def get_register_personality_description(self) -> Description:\n        \"\"\"\n        Get the register personality description.\n\n        :return: a description of the personality\n        \"\"\"\n        description = Description(\n            self._set_personality_data,\n            data_model=AGENT_PERSONALITY_MODEL,\n        )\n        return description\n\n    def get_register_classification_description(self) -> Description:\n        \"\"\"\n        Get the register classification description.\n\n        :return: a description of the classification\n        \"\"\"\n        description = Description(\n            self._set_classification,\n            data_model=AGENT_PERSONALITY_MODEL,\n        )\n        return description\n\n    def get_unregister_service_description(self) -> Description:\n        \"\"\"\n        Get the unregister service description.\n\n        :return: a description of the to be removed service\n        \"\"\"\n        description = Description(\n            self._remove_service_data,\n            data_model=AGENT_REMOVE_SERVICE_MODEL,\n        )\n        return description\n\n    def get_location_and_service_query(self) -> Query:\n        \"\"\"\n        Get the location and service query of the agent.\n\n        :return: the query\n        \"\"\"\n        close_to_my_service = Constraint(\n            \"location\",\n            ConstraintType(\n                \"distance\", (self._agent_location[\"location\"], self._radius)\n            ),\n        )\n        service_key_filter = Constraint(\n            self._search_query[\"search_key\"],\n            ConstraintType(\n                self._search_query[\"constraint_type\"],\n                self._search_query[\"search_value\"],\n            ),\n        )\n        query = Query(\n            [close_to_my_service, service_key_filter],\n        )\n        return query\n"
  },
  {
    "path": "packages/fetchai/skills/simple_buyer/README.md",
    "content": "# Simple Buyer\n\n## Description\n\nThis skill purchases information from other agents as specified in its configuration.\n\nThis skill searches for an agent in a vicinity on the sOEF that sells the data this skill is configured to buy. Once found, it requests this data, negotiates the price, pays the proposed amount if agreement is reached, and receives the data bought.\n\n## Behaviours\n\n- `search`: searches for data selling service on the sOEF\n- `transaction`: sequentially processes transactions' settlements on a blockchain\n\n## Handlers\n\n- `fipa`: handles `fipa` messages for negotiation\n- `ledger_api`: handles `ledger_api` messages for interacting with a ledger\n- `oef_search`: handles `oef_search` messages to manage the sellers found\n- `signing`: handles `signing` messages for transaction signing by the decision maker\n\n## Models\n\n- `strategy`: allows the configuration of the purchasing. In particular, `location` and `search_radius` together determine the vicinity where the service is searched for, `search_query` specifies the query, and the remaining configuration specifies the terms of trade.\n"
  },
  {
    "path": "packages/fetchai/skills/simple_buyer/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the implementation of the buyer_aw2 skill.\"\"\"\n\nfrom aea.configurations.base import PublicId\n\n\nPUBLIC_ID = PublicId.from_str(\"fetchai/simple_buyer:0.13.6\")\n"
  },
  {
    "path": "packages/fetchai/skills/simple_buyer/behaviours.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains the behaviours of the agent.\"\"\"\n\nfrom packages.fetchai.skills.generic_buyer.behaviours import (\n    GenericSearchBehaviour,\n    GenericTransactionBehaviour,\n)\n\n\nSearchBehaviour = GenericSearchBehaviour\nTransactionBehaviour = GenericTransactionBehaviour\n"
  },
  {
    "path": "packages/fetchai/skills/simple_buyer/dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nThis module contains the classes required for dialogue management.\n\n- DefaultDialogues: The dialogues class keeps track of all dialogues of type default.\n- FipaDialogues: The dialogues class keeps track of all dialogues of type fipa.\n- LedgerApiDialogues: The dialogues class keeps track of all dialogues of type ledger_api.\n- OefSearchDialogues: The dialogues class keeps track of all dialogues of type oef_search.\n- SigningDialogues: The dialogues class keeps track of all dialogues of type signing.\n\"\"\"\n\nfrom packages.fetchai.skills.generic_buyer.dialogues import (\n    DefaultDialogues as GenericDefaultDialogues,\n)\nfrom packages.fetchai.skills.generic_buyer.dialogues import (\n    FipaDialogues as GenericFipaDialogues,\n)\nfrom packages.fetchai.skills.generic_buyer.dialogues import (\n    LedgerApiDialogues as GenericLedgerApiDialogues,\n)\nfrom packages.fetchai.skills.generic_buyer.dialogues import (\n    OefSearchDialogues as GenericOefSearchDialogues,\n)\nfrom packages.fetchai.skills.generic_buyer.dialogues import (\n    SigningDialogues as GenericSigningDialogues,\n)\n\n\nDefaultDialogues = GenericDefaultDialogues\nFipaDialogues = GenericFipaDialogues\nLedgerApiDialogues = GenericLedgerApiDialogues\nOefSearchDialogues = GenericOefSearchDialogues\nSigningDialogues = GenericSigningDialogues\n"
  },
  {
    "path": "packages/fetchai/skills/simple_buyer/handlers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains the handlers of the agent.\"\"\"\n\nfrom packages.fetchai.skills.generic_buyer.handlers import (\n    GenericFipaHandler,\n    GenericLedgerApiHandler,\n    GenericOefSearchHandler,\n    GenericSigningHandler,\n)\n\n\nFipaHandler = GenericFipaHandler\nLedgerApiHandler = GenericLedgerApiHandler\nOefSearchHandler = GenericOefSearchHandler\nSigningHandler = GenericSigningHandler\n"
  },
  {
    "path": "packages/fetchai/skills/simple_buyer/skill.yaml",
    "content": "name: simple_buyer\nauthor: fetchai\nversion: 0.13.6\ntype: skill\ndescription: This skill purchases information from other agents as specified in its\n  configuration.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: QmSYbruWV7Cte46FvKgPK8LcJXsShGMTmW6Q2oMxekz327\n  __init__.py: QmRTEKXBc4r4iTUSUTR49ypjPLCZtMGPs13Fuu1c7XNQtM\n  behaviours.py: QmSr6fB3N7dhVo1cLY1TGd2q8usjGwNmTCNjBBbtgtVf9j\n  dialogues.py: QmXgXcs25v9ob9a9XwT49wvK788vbUdZyYxUgG3ndHjrix\n  handlers.py: QmP3Q6x3NMcWgRi6H5GtDtvnLWSoB1HeG8vTd4zcRZUgNj\n  strategy.py: QmdHPLehqRr1dxuCbp4ENYmVMb8Ykvzg2Uzfos5kFJSr3D\nfingerprint_ignore_patterns: []\nconnections:\n- fetchai/ledger:0.21.5\ncontracts: []\nprotocols:\n- fetchai/default:1.1.7\n- fetchai/fipa:1.1.7\n- fetchai/ledger_api:1.1.7\n- fetchai/oef_search:1.1.7\n- fetchai/signing:1.1.7\nskills:\n- fetchai/generic_buyer:0.27.6\nbehaviours:\n  search:\n    args:\n      search_interval: 5\n    class_name: SearchBehaviour\n  transaction:\n    args:\n      max_processing: 420\n      transaction_interval: 2\n    class_name: TransactionBehaviour\nhandlers:\n  fipa:\n    args: {}\n    class_name: FipaHandler\n  ledger_api:\n    args: {}\n    class_name: LedgerApiHandler\n  oef_search:\n    args: {}\n    class_name: OefSearchHandler\n  signing:\n    args: {}\n    class_name: SigningHandler\nmodels:\n  default_dialogues:\n    args: {}\n    class_name: DefaultDialogues\n  fipa_dialogues:\n    args: {}\n    class_name: FipaDialogues\n  ledger_api_dialogues:\n    args: {}\n    class_name: LedgerApiDialogues\n  oef_search_dialogues:\n    args: {}\n    class_name: OefSearchDialogues\n  signing_dialogues:\n    args: {}\n    class_name: SigningDialogues\n  strategy:\n    args:\n      is_ledger_tx: true\n      location:\n        latitude: 51.5194\n        longitude: 0.127\n      max_negotiations: 1\n      max_quantity: 100\n      max_tx_fee: 3550000000000000\n      max_unit_price: 20\n      min_quantity: 1\n      search_query:\n        constraint_type: ==\n        search_key: seller_service\n        search_value: weather_data\n      search_radius: 50.0\n      service_id: weather_data\n    class_name: Strategy\ndependencies: {}\nis_abstract: false\n"
  },
  {
    "path": "packages/fetchai/skills/simple_buyer/strategy.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the strategy class.\"\"\"\n\nfrom packages.fetchai.skills.generic_buyer.strategy import GenericStrategy\n\n\nStrategy = GenericStrategy\n"
  },
  {
    "path": "packages/fetchai/skills/simple_data_request/README.md",
    "content": "# Simple Data Request\n\n## Description\n\nThis skill is used to request data from a HTTP endpoint and then save it in the AEA's shared state for use by other skills.\n\n## Behaviours\n\n- `http_request`: requests data every `request_interval` seconds from a HTTP endpoint using the `url`, `method` and `body` specified in the skill configuration.\n\n## Handlers\n\n- `http`: handles incoming `http` messages. Data received in responses is saved in the shared state using the key specified in the skill configuration: `shared_state_key`.\n"
  },
  {
    "path": "packages/fetchai/skills/simple_data_request/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the implementation of the simple_data_request skill.\"\"\"\n\nfrom aea.configurations.base import PublicId\n\n\nPUBLIC_ID = PublicId.from_str(\"fetchai/simple_data_request:0.14.6\")\n"
  },
  {
    "path": "packages/fetchai/skills/simple_data_request/behaviours.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains a a behaviour to request data from a HTTP endpoint.\"\"\"\n\nimport json\nfrom typing import Any, cast\n\nfrom aea.skills.behaviours import TickerBehaviour\n\nfrom packages.fetchai.connections.http_client.connection import (\n    PUBLIC_ID as HTTP_CLIENT_PUBLIC_ID,\n)\nfrom packages.fetchai.protocols.http.message import HttpMessage\nfrom packages.fetchai.skills.simple_data_request.dialogues import HttpDialogues\n\n\nDEFAULT_REQUEST_INTERVAL = 20.0\n\n\nclass HttpRequestBehaviour(TickerBehaviour):\n    \"\"\"This class defines an http request behaviour.\"\"\"\n\n    def __init__(self, **kwargs: Any):\n        \"\"\"Initialise the behaviour.\"\"\"\n        request_interval = kwargs.pop(\n            \"request_interval\", DEFAULT_REQUEST_INTERVAL\n        )  # type: int\n        self.url = kwargs.pop(\"url\", None)\n        self.method = kwargs.pop(\"method\", None)\n        self.body = kwargs.pop(\"body\", None)\n        self.lookup_termination_key = kwargs.pop(\"lookup_termination_key\", None)\n        if self.url is None or self.method is None or self.body is None:\n            raise ValueError(\"Url, method and body must be provided.\")\n        super().__init__(tick_interval=request_interval, **kwargs)\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup.\"\"\"\n\n    def act(self) -> None:\n        \"\"\"Implement the act.\"\"\"\n        if self.lookup_termination_key is not None:\n            prerequisite_satisfied = self.context.shared_state.get(\n                self.lookup_termination_key, False\n            )\n            if not prerequisite_satisfied:\n                return\n\n        self._generate_http_request()\n\n    def _generate_http_request(self) -> None:\n        \"\"\"Generate http request to provided url with provided body and method.\"\"\"\n        http_dialogues = cast(HttpDialogues, self.context.http_dialogues)\n        request_http_message, _ = http_dialogues.create(\n            counterparty=str(HTTP_CLIENT_PUBLIC_ID),\n            performative=HttpMessage.Performative.REQUEST,\n            method=self.method,\n            url=self.url,\n            headers=\"\",\n            version=\"\",\n            body=json.dumps(self.body).encode(\"utf-8\"),\n        )\n        self.context.outbox.put_message(message=request_http_message)\n\n    def teardown(self) -> None:\n        \"\"\"Implement the task teardown.\"\"\"\n"
  },
  {
    "path": "packages/fetchai/skills/simple_data_request/dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nThis module contains the classes required for dialogue management.\n\n- HttpDialogue: The dialogue class maintains state of a http dialogue and manages it.\n- HttpDialogues: The dialogues class keeps track of all http dialogues.\n\"\"\"\n\nfrom typing import Any\n\nfrom aea.protocols.base import Address, Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\nfrom aea.skills.base import Model\n\nfrom packages.fetchai.protocols.http.dialogues import HttpDialogue as BaseHttpDialogue\nfrom packages.fetchai.protocols.http.dialogues import HttpDialogues as BaseHttpDialogues\n\n\nHttpDialogue = BaseHttpDialogue\n\n\nclass HttpDialogues(Model, BaseHttpDialogues):\n    \"\"\"This class keeps track of all http dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return BaseHttpDialogue.Role.CLIENT\n\n        BaseHttpDialogues.__init__(\n            self,\n            self_address=str(self.skill_id),\n            role_from_first_message=role_from_first_message,\n        )\n"
  },
  {
    "path": "packages/fetchai/skills/simple_data_request/handlers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains a handler to process HTTP responses.\"\"\"\n\nfrom typing import Any, cast\n\nfrom aea.protocols.base import Message\nfrom aea.skills.base import Handler\n\nfrom packages.fetchai.protocols.http.message import HttpMessage\nfrom packages.fetchai.skills.simple_data_request.dialogues import (\n    HttpDialogue,\n    HttpDialogues,\n)\n\n\nclass HttpHandler(Handler):\n    \"\"\"This class represents the handler for HTTP messages.\"\"\"\n\n    SUPPORTED_PROTOCOL = HttpMessage.protocol_id\n\n    def __init__(self, **kwargs: Any):\n        \"\"\"\n        Initialize the handler.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        self.shared_state_key = kwargs.pop(\"shared_state_key\", None)\n        if self.shared_state_key is None:\n            raise ValueError(\"No shared_state_key provided!\")\n        super().__init__(**kwargs)\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to an envelope.\n\n        :param message: the message\n        \"\"\"\n        http_msg = cast(HttpMessage, message)\n\n        # recover dialogue\n        http_dialogues = cast(HttpDialogues, self.context.http_dialogues)\n        http_dialogue = cast(HttpDialogue, http_dialogues.update(http_msg))\n        if http_dialogue is None:\n            self._handle_unidentified_dialogue(http_msg)\n            return\n\n        # handle message (only process responses, we do not expect requests)\n        if http_msg.performative == HttpMessage.Performative.RESPONSE:\n            self._handle_response(http_msg, http_dialogue)\n        else:\n            self._handle_invalid(http_msg, http_dialogue)\n\n    def _handle_unidentified_dialogue(self, http_msg: HttpMessage) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param http_msg: the message\n        \"\"\"\n        self.context.logger.info(\n            \"received invalid http message={}, unidentified dialogue.\".format(http_msg)\n        )\n\n    def _handle_response(\n        self, http_msg: HttpMessage, http_dialogue: HttpDialogue\n    ) -> None:\n        \"\"\"\n        Handle a http response.\n\n        :param http_msg: the message\n        :param http_dialogue: the dialogue object\n        \"\"\"\n        self.context.logger.debug(\n            \"received http response={} in dialogue={}.\".format(http_msg, http_dialogue)\n        )\n        data_received = http_msg.body\n\n        # save the data in the shared state to make it accessible to other skills\n        self.context.logger.info(\n            \"updating shared_state with received data={!r}!\".format(data_received)\n        )\n        self.context.shared_state[self.shared_state_key] = data_received\n\n    def _handle_invalid(\n        self, http_msg: HttpMessage, http_dialogue: HttpDialogue\n    ) -> None:\n        \"\"\"\n        Handle a http message of invalid performative.\n\n        :param http_msg: the message\n        :param http_dialogue: the dialogue object\n        \"\"\"\n        self.context.logger.warning(\n            \"cannot handle http message of performative={} in dialogue={}.\".format(\n                http_msg.performative, http_dialogue\n            )\n        )\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n"
  },
  {
    "path": "packages/fetchai/skills/simple_data_request/skill.yaml",
    "content": "name: simple_data_request\nauthor: fetchai\nversion: 0.14.6\ntype: skill\ndescription: This skill is used to request data from a HTTP endpoint and then saving\n  it in the AEA's shared state for use by other skills.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: QmemL4YrZjQSMjhF2uymRmntNHSoyvAQ66R9TtnEwmDxiv\n  __init__.py: QmW6iSrqrczrFvKxaTgkyQXneR4ckMimYZheFu8EHsB66N\n  behaviours.py: QmcAsxDGEjf2zofag5X3PxmaPBwrjqf9zoSZVdLwCUFRaC\n  dialogues.py: QmVYsxmS1okvCqTQFs6PwNRWvzP1YeguD1FxLopQWe1a9h\n  handlers.py: QmZ52t9KWAzLLrUv5ZZvfFT4CgB4YvN9HceDcWuQBvRqxT\nfingerprint_ignore_patterns: []\nconnections:\n- fetchai/http_client:0.24.6\ncontracts: []\nprotocols:\n- fetchai/http:1.1.7\nskills: []\nbehaviours:\n  http_request:\n    args:\n      body: ''\n      lookup_termination_key: null\n      method: null\n      request_interval: 20\n      url: null\n    class_name: HttpRequestBehaviour\nhandlers:\n  http:\n    args:\n      shared_state_key: null\n    class_name: HttpHandler\nmodels:\n  http_dialogues:\n    args: {}\n    class_name: HttpDialogues\ndependencies: {}\nis_abstract: false\n"
  },
  {
    "path": "packages/fetchai/skills/simple_oracle/README.md",
    "content": "# Simple Oracle\n\n## Description\n\nThis skill is used to deploy an oracle smart contract to a ledger, grant oracle permissions, and periodically update the oracle value in the contract.\n\n## Behaviours\n\n- `simple_oracle_behaviour`: deploys oracle contract, grants the oracle role to the agent address, and updates the oracle value every `tick_interval` seconds, as specified in the skill configuration.\n\n## Handlers\n\n- `contract_api`: handles `contract_api` messages for interactions with a smart contract\n- `ledger_api`: handles `ledger_api` messages for interacting with a ledger\n- `prometheus`: handles `prometheus` messages for interactions with a prometheus server\n- `signing`: handles `signing` messages for transaction signing by the decision maker\n"
  },
  {
    "path": "packages/fetchai/skills/simple_oracle/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the implementation of the simple oracle skill.\"\"\"\n\nfrom aea.configurations.base import PublicId\n\n\nPUBLIC_ID = PublicId.from_str(\"fetchai/simple_oracle:0.16.5\")\n"
  },
  {
    "path": "packages/fetchai/skills/simple_oracle/behaviours.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains a simple Fetch oracle contract deployment behaviour.\"\"\"\n\nfrom typing import Any, Dict, cast\n\nfrom aea.skills.behaviours import TickerBehaviour\n\nfrom packages.fetchai.connections.ledger.base import CONNECTION_ID as LEDGER_API_ADDRESS\nfrom packages.fetchai.connections.prometheus.connection import (\n    PUBLIC_ID as PROM_CONNECTION_ID,\n)\nfrom packages.fetchai.contracts.oracle.contract import PUBLIC_ID as CONTRACT_PUBLIC_ID\nfrom packages.fetchai.protocols.contract_api.message import ContractApiMessage\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\nfrom packages.fetchai.protocols.prometheus.message import PrometheusMessage\nfrom packages.fetchai.skills.simple_oracle.dialogues import (\n    ContractApiDialogue,\n    ContractApiDialogues,\n    LedgerApiDialogues,\n    PrometheusDialogues,\n)\nfrom packages.fetchai.skills.simple_oracle.strategy import Strategy\n\n\nDEFAULT_UPDATE_INTERVAL = 5\nDEFAULT_DECIMALS = 5\nEXPIRATION_BLOCK = 1000000000000000\n\n\nclass SimpleOracleBehaviour(TickerBehaviour):\n    \"\"\"This class implements a behaviour that deploys a Fetch oracle contract.\"\"\"\n\n    def __init__(self, **kwargs: Any):\n        \"\"\"Initialise the behaviour.\"\"\"\n        update_interval = kwargs.pop(\n            \"update_interval\", DEFAULT_UPDATE_INTERVAL\n        )  # type: int\n        super().__init__(tick_interval=update_interval, **kwargs)\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup.\"\"\"\n        self.context.logger.info(\"Setting up Fetch oracle contract...\")\n        strategy = cast(Strategy, self.context.strategy)\n\n        if not strategy.is_contract_deployed:\n            self._request_contract_deploy_transaction()\n        else:\n            self.context.logger.info(\"Fetch oracle contract address already added\")\n\n        if strategy.is_oracle_role_granted:\n            self.context.logger.info(\"Oracle role already granted\")\n\n        prom_dialogues = cast(PrometheusDialogues, self.context.prometheus_dialogues)\n\n        if prom_dialogues.enabled:\n            for metric in prom_dialogues.metrics:\n                metric_name = metric[\"name\"]\n                self.context.logger.info(\"Adding Prometheus metric: \" + metric_name)\n                self.add_prometheus_metric(\n                    metric_name,\n                    metric[\"type\"],\n                    metric[\"description\"],\n                    dict(metric[\"labels\"]),\n                )\n\n    def act(self) -> None:\n        \"\"\"Implement the act.\"\"\"\n        strategy = cast(Strategy, self.context.strategy)\n\n        # Request account balance\n        self._get_balance()\n\n        if not strategy.is_contract_deployed:\n            self.context.logger.info(\"Oracle contract not yet deployed\")\n            return\n\n        if not strategy.is_oracle_role_granted:\n            self.context.logger.info(\"Oracle not yet created\")\n            self._request_grant_role_transaction()\n            return\n\n        # Check for oracle from data collecting skill\n        oracle_data = self.context.shared_state.get(strategy.oracle_value_name, None)\n\n        if oracle_data is None:\n            self.context.logger.info(\"No oracle value to publish\")\n        else:\n            self.context.logger.info(\"Publishing oracle value\")\n            self.context.logger.info(f\"Update kwargs: {oracle_data}\")\n            self._request_update_transaction(oracle_data)\n\n    def _request_contract_deploy_transaction(self) -> None:\n        \"\"\"Request contract deployment transaction.\"\"\"\n        strategy = cast(Strategy, self.context.strategy)\n        strategy.is_behaviour_active = False\n        contract_api_dialogues = cast(\n            ContractApiDialogues, self.context.contract_api_dialogues\n        )\n        contract_api_msg, contract_api_dialogue = contract_api_dialogues.create(\n            counterparty=str(LEDGER_API_ADDRESS),\n            performative=ContractApiMessage.Performative.GET_DEPLOY_TRANSACTION,\n            ledger_id=strategy.ledger_id,\n            contract_id=str(CONTRACT_PUBLIC_ID),\n            callable=\"get_deploy_transaction\",\n            kwargs=strategy.get_deploy_kwargs(),\n        )\n        contract_api_dialogue = cast(\n            ContractApiDialogue,\n            contract_api_dialogue,\n        )\n        contract_api_dialogue.terms = strategy.get_deploy_terms()\n        self.context.outbox.put_message(message=contract_api_msg)\n        self.context.logger.info(\"requesting contract deployment transaction...\")\n\n    def _request_grant_role_transaction(self) -> None:\n        \"\"\"Request transaction that grants oracle role in a Fetch oracle contract.\"\"\"\n        strategy = cast(Strategy, self.context.strategy)\n        strategy.is_behaviour_active = False\n        contract_api_dialogues = cast(\n            ContractApiDialogues, self.context.contract_api_dialogues\n        )\n        contract_api_msg, contract_api_dialogue = contract_api_dialogues.create(\n            counterparty=str(LEDGER_API_ADDRESS),\n            performative=ContractApiMessage.Performative.GET_RAW_TRANSACTION,\n            ledger_id=strategy.ledger_id,\n            contract_id=str(CONTRACT_PUBLIC_ID),\n            contract_address=strategy.contract_address,\n            callable=\"get_grant_role_transaction\",\n            kwargs=ContractApiMessage.Kwargs(\n                {\n                    \"oracle_address\": self.context.agent_address,\n                    \"gas\": strategy.gas_limit_grant_role,\n                    \"tx_fee\": strategy.gas_price * strategy.gas_limit_grant_role,\n                }\n            ),\n        )\n        contract_api_dialogue = cast(ContractApiDialogue, contract_api_dialogue)\n        contract_api_dialogue.terms = strategy.get_grant_role_terms()\n        self.context.outbox.put_message(message=contract_api_msg)\n        self.context.logger.info(\"requesting grant role transaction...\")\n\n    @staticmethod\n    def _get_tx_expriration_block() -> int:\n        \"\"\"Return max block number for no expiration.\"\"\"\n        return 2**256 - 1\n\n    def _request_update_transaction(self, update_kwargs: Dict[str, Any]) -> None:\n        \"\"\"Request transaction that updates value in Fetch oracle contract.\"\"\"\n        strategy = cast(Strategy, self.context.strategy)\n        strategy.is_behaviour_active = False\n        contract_api_dialogues = cast(\n            ContractApiDialogues, self.context.contract_api_dialogues\n        )\n        update_kwargs = {\n            **update_kwargs,\n            \"txExpirationBlock\": self._get_tx_expriration_block(),\n        }\n        contract_api_msg, contract_api_dialogue = contract_api_dialogues.create(\n            counterparty=str(LEDGER_API_ADDRESS),\n            performative=ContractApiMessage.Performative.GET_RAW_TRANSACTION,\n            ledger_id=strategy.ledger_id,\n            contract_id=str(CONTRACT_PUBLIC_ID),\n            contract_address=strategy.contract_address,\n            callable=\"get_update_transaction\",\n            kwargs=ContractApiMessage.Kwargs(\n                {\n                    \"oracle_address\": self.context.agent_address,\n                    \"update_function\": strategy.update_function,\n                    \"update_kwargs\": update_kwargs,\n                    \"gas\": strategy.gas_limit_update,\n                    \"tx_fee\": strategy.gas_price * strategy.gas_limit_update,\n                }\n            ),\n        )\n        contract_api_dialogue = cast(ContractApiDialogue, contract_api_dialogue)\n        contract_api_dialogue.terms = strategy.get_update_terms()\n        self.context.outbox.put_message(message=contract_api_msg)\n        self.context.logger.info(\"requesting update transaction...\")\n\n    def _get_balance(self) -> None:\n        \"\"\"Request balance of agent account by sending a message to the ledger API.\"\"\"\n        strategy = cast(Strategy, self.context.strategy)\n        ledger_api_dialogues = cast(\n            LedgerApiDialogues, self.context.ledger_api_dialogues\n        )\n        ledger_api_msg, _ = ledger_api_dialogues.create(\n            counterparty=str(LEDGER_API_ADDRESS),\n            performative=LedgerApiMessage.Performative.GET_BALANCE,\n            ledger_id=strategy.ledger_id,\n            address=cast(str, self.context.agent_addresses.get(strategy.ledger_id)),\n        )\n        self.context.outbox.put_message(message=ledger_api_msg)\n\n    def add_prometheus_metric(\n        self,\n        metric_name: str,\n        metric_type: str,\n        description: str,\n        labels: Dict[str, str],\n    ) -> None:\n        \"\"\"\n        Add a prometheus metric.\n\n        :param metric_name: the name of the metric to add.\n        :param metric_type: the type of the metric.\n        :param description: a description of the metric.\n        :param labels: the metric labels.\n        \"\"\"\n        # context\n        prom_dialogues = cast(PrometheusDialogues, self.context.prometheus_dialogues)\n\n        # prometheus update message\n        message, _ = prom_dialogues.create(\n            counterparty=str(PROM_CONNECTION_ID),\n            performative=PrometheusMessage.Performative.ADD_METRIC,\n            type=metric_type,\n            title=metric_name,\n            description=description,\n            labels=labels,\n        )\n\n        # send message\n        self.context.outbox.put_message(message=message)\n\n    def update_prometheus_metric(\n        self,\n        metric_name: str,\n        update_func: str,\n        value: float,\n        labels: Dict[str, str],\n    ) -> None:\n        \"\"\"\n        Update a prometheus metric.\n\n        :param metric_name: the name of the metric.\n        :param update_func: the name of the update function (e.g. inc, dec, set, ...).\n        :param value: the value to provide to the update function.\n        :param labels: the metric labels.\n        \"\"\"\n        # context\n        prom_dialogues = cast(PrometheusDialogues, self.context.prometheus_dialogues)\n\n        # prometheus update message\n        message, _ = prom_dialogues.create(\n            counterparty=str(PROM_CONNECTION_ID),\n            performative=PrometheusMessage.Performative.UPDATE_METRIC,\n            title=metric_name,\n            callable=update_func,\n            value=value,\n            labels=labels,\n        )\n\n        # send message\n        self.context.outbox.put_message(message=message)\n\n    def teardown(self) -> None:\n        \"\"\"Implement the task teardown.\"\"\"\n"
  },
  {
    "path": "packages/fetchai/skills/simple_oracle/dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains the ContractAPI and LedgerAPI dialogues.\"\"\"\n\nfrom typing import Any, Optional, Type\n\nfrom aea.common import Address\nfrom aea.exceptions import enforce\nfrom aea.helpers.transaction.base import Terms\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\nfrom aea.protocols.dialogue.base import DialogueLabel as BaseDialogueLabel\nfrom aea.skills.base import Model\n\nfrom packages.fetchai.protocols.contract_api.dialogues import (\n    ContractApiDialogue as BaseContractApiDialogue,\n)\nfrom packages.fetchai.protocols.contract_api.dialogues import (\n    ContractApiDialogues as BaseContractApiDialogues,\n)\nfrom packages.fetchai.protocols.contract_api.message import ContractApiMessage\nfrom packages.fetchai.protocols.ledger_api.dialogues import (\n    LedgerApiDialogue as BaseLedgerApiDialogue,\n)\nfrom packages.fetchai.protocols.ledger_api.dialogues import (\n    LedgerApiDialogues as BaseLedgerApiDialogues,\n)\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\nfrom packages.fetchai.protocols.prometheus.dialogues import (\n    PrometheusDialogue as BasePrometheusDialogue,\n)\nfrom packages.fetchai.protocols.prometheus.dialogues import (\n    PrometheusDialogues as BasePrometheusDialogues,\n)\nfrom packages.fetchai.protocols.signing.dialogues import (\n    SigningDialogue as BaseSigningDialogue,\n)\nfrom packages.fetchai.protocols.signing.dialogues import (\n    SigningDialogues as BaseSigningDialogues,\n)\nfrom packages.fetchai.protocols.signing.message import SigningMessage\n\n\nPrometheusDialogue = BasePrometheusDialogue\n\n\nclass ContractApiDialogue(BaseContractApiDialogue):\n    \"\"\"The dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    __slots__ = (\"_terms\",)\n\n    def __init__(\n        self,\n        dialogue_label: BaseDialogueLabel,\n        self_address: Address,\n        role: BaseDialogue.Role,\n        message_class: Type[ContractApiMessage] = ContractApiMessage,\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n        :param message_class: the message class\n        \"\"\"\n        BaseContractApiDialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            self_address=self_address,\n            role=role,\n            message_class=message_class,\n        )\n        self._terms = None  # type: Optional[Terms]\n\n    @property\n    def terms(self) -> Terms:\n        \"\"\"Get the terms.\"\"\"\n        if self._terms is None:  # pragma: nocover\n            raise ValueError(\"Terms not set!\")\n        return self._terms\n\n    @terms.setter\n    def terms(self, terms: Terms) -> None:\n        \"\"\"Set the terms.\"\"\"\n        enforce(self._terms is None, \"Terms already set!\")\n        self._terms = terms\n\n\nclass ContractApiDialogues(Model, BaseContractApiDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return ContractApiDialogue.Role.AGENT\n\n        BaseContractApiDialogues.__init__(\n            self,\n            self_address=str(self.skill_id),\n            role_from_first_message=role_from_first_message,\n            dialogue_class=ContractApiDialogue,\n        )\n\n\nclass LedgerApiDialogue(BaseLedgerApiDialogue):\n    \"\"\"The dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    __slots__ = (\"_associated_signing_dialogue\", \"_associated_transaction_type\")\n\n    def __init__(\n        self,\n        dialogue_label: BaseDialogueLabel,\n        self_address: Address,\n        role: BaseDialogue.Role,\n        message_class: Type[LedgerApiMessage] = LedgerApiMessage,\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n        :param message_class: the message class\n        \"\"\"\n        BaseLedgerApiDialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            self_address=self_address,\n            role=role,\n            message_class=message_class,\n        )\n        self._associated_signing_dialogue = None  # type: Optional[SigningDialogue]\n        self._associated_transaction_type = None  # type: Optional[str]\n\n    @property\n    def associated_signing_dialogue(self) -> \"SigningDialogue\":\n        \"\"\"Get the associated signing dialogue.\"\"\"\n        if self._associated_signing_dialogue is None:  # pragma: nocover\n            raise ValueError(\"Associated signing dialogue not set!\")\n        return self._associated_signing_dialogue\n\n    @associated_signing_dialogue.setter\n    def associated_signing_dialogue(\n        self, associated_signing_dialogue: \"SigningDialogue\"\n    ) -> None:\n        \"\"\"Set the associated signing dialogue.\"\"\"\n        enforce(\n            self._associated_signing_dialogue is None,\n            \"Associated signing dialogue already set!\",\n        )\n        self._associated_signing_dialogue = associated_signing_dialogue\n\n\nclass LedgerApiDialogues(Model, BaseLedgerApiDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return BaseLedgerApiDialogue.Role.AGENT\n\n        BaseLedgerApiDialogues.__init__(\n            self,\n            self_address=str(self.skill_id),\n            role_from_first_message=role_from_first_message,\n            dialogue_class=LedgerApiDialogue,\n        )\n\n\nclass SigningDialogue(BaseSigningDialogue):\n    \"\"\"The dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    __slots__ = (\"_associated_contract_api_dialogue\",)\n\n    def __init__(\n        self,\n        dialogue_label: BaseDialogueLabel,\n        self_address: Address,\n        role: BaseDialogue.Role,\n        message_class: Type[SigningMessage] = SigningMessage,\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n        :param message_class: the message class\n        \"\"\"\n        BaseSigningDialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            self_address=self_address,\n            role=role,\n            message_class=message_class,\n        )\n        self._associated_contract_api_dialogue = (\n            None\n        )  # type: Optional[ContractApiDialogue]\n\n    @property\n    def associated_contract_api_dialogue(self) -> ContractApiDialogue:\n        \"\"\"Get the associated contract api dialogue.\"\"\"\n        if self._associated_contract_api_dialogue is None:  # pragma: nocover\n            raise ValueError(\"Associated contract api dialogue not set!\")\n        return self._associated_contract_api_dialogue\n\n    @associated_contract_api_dialogue.setter\n    def associated_contract_api_dialogue(\n        self, associated_contract_api_dialogue: ContractApiDialogue\n    ) -> None:\n        \"\"\"Set the associated contract api dialogue.\"\"\"\n        enforce(\n            self._associated_contract_api_dialogue is None,\n            \"Associated contract api dialogue already set!\",\n        )\n        self._associated_contract_api_dialogue = associated_contract_api_dialogue\n\n\nclass SigningDialogues(Model, BaseSigningDialogues):\n    \"\"\"This class keeps track of all oef_search dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return BaseSigningDialogue.Role.SKILL\n\n        BaseSigningDialogues.__init__(\n            self,\n            self_address=str(self.skill_id),\n            role_from_first_message=role_from_first_message,\n            dialogue_class=SigningDialogue,\n        )\n\n\nclass PrometheusDialogues(Model, BasePrometheusDialogues):\n    \"\"\"The dialogues class keeps track of all prometheus dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        self.enabled = kwargs.pop(\"enabled\", False)\n        self.metrics = kwargs.pop(\"metrics\", [])\n\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return PrometheusDialogue.Role.AGENT\n\n        BasePrometheusDialogues.__init__(\n            self,\n            self_address=str(self.skill_id),\n            role_from_first_message=role_from_first_message,\n        )\n"
  },
  {
    "path": "packages/fetchai/skills/simple_oracle/handlers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains the handlers for the Fetch oracle contract deployer.\"\"\"\n\nfrom typing import Optional, cast\n\nfrom aea_ledger_fetchai import FetchAIApi\n\nfrom aea.common import JSONLike\nfrom aea.configurations.base import PublicId\nfrom aea.crypto.ledger_apis import LedgerApis\nfrom aea.protocols.base import Message\nfrom aea.skills.base import Handler\n\nfrom packages.fetchai.connections.ledger.base import CONNECTION_ID as LEDGER_API_ADDRESS\nfrom packages.fetchai.contracts.oracle.contract import PUBLIC_ID as CONTRACT_PUBLIC_ID\nfrom packages.fetchai.protocols.contract_api.message import ContractApiMessage\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\nfrom packages.fetchai.protocols.prometheus.message import PrometheusMessage\nfrom packages.fetchai.protocols.signing.message import SigningMessage\nfrom packages.fetchai.skills.simple_oracle.dialogues import (\n    ContractApiDialogue,\n    ContractApiDialogues,\n    LedgerApiDialogue,\n    LedgerApiDialogues,\n    PrometheusDialogue,\n    PrometheusDialogues,\n    SigningDialogue,\n    SigningDialogues,\n)\nfrom packages.fetchai.skills.simple_oracle.strategy import Strategy\n\n\nclass LedgerApiHandler(Handler):\n    \"\"\"Implement the ledger api handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = LedgerApiMessage.protocol_id  # type: Optional[PublicId]\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup for the handler.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to a message.\n\n        :param message: the message\n        \"\"\"\n\n        self.context.logger.info(\"Handling ledger api msg\")\n\n        ledger_api_msg = cast(LedgerApiMessage, message)\n\n        # recover dialogue\n        ledger_api_dialogues = cast(\n            LedgerApiDialogues, self.context.ledger_api_dialogues\n        )\n        ledger_api_dialogue = cast(\n            Optional[LedgerApiDialogue], ledger_api_dialogues.update(ledger_api_msg)\n        )\n        if ledger_api_dialogue is None:\n            self._handle_unidentified_dialogue(ledger_api_msg)\n            return\n\n        # handle message\n        if ledger_api_msg.performative is LedgerApiMessage.Performative.BALANCE:\n            self._handle_balance(ledger_api_msg)\n        elif (\n            ledger_api_msg.performative\n            is LedgerApiMessage.Performative.TRANSACTION_DIGEST\n        ):\n            self._handle_transaction_digest(ledger_api_msg, ledger_api_dialogue)\n        elif (\n            ledger_api_msg.performative\n            is LedgerApiMessage.Performative.TRANSACTION_RECEIPT\n        ):\n            self._handle_transaction_receipt(ledger_api_msg, ledger_api_dialogue)\n        elif ledger_api_msg.performative == LedgerApiMessage.Performative.ERROR:\n            self._handle_error(ledger_api_msg, ledger_api_dialogue)\n        else:\n            self._handle_invalid(ledger_api_msg, ledger_api_dialogue)\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n\n    def _handle_unidentified_dialogue(self, ledger_api_msg: LedgerApiMessage) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param ledger_api_msg: the message\n        \"\"\"\n        self.context.logger.info(\n            \"received invalid ledger_api message={}, unidentified dialogue.\".format(\n                ledger_api_msg\n            )\n        )\n\n    def _handle_balance(self, ledger_api_msg: LedgerApiMessage) -> None:\n        \"\"\"\n        Handle a message of balance performative.\n\n        :param ledger_api_msg: the ledger api message\n        \"\"\"\n        self.context.logger.info(\n            \"Balance on {} ledger={}.\".format(\n                ledger_api_msg.ledger_id,\n                ledger_api_msg.balance,\n            )\n        )\n        if self.context.prometheus_dialogues.enabled:\n            metric_name = \"oracle_account_balance_ETH\"\n            self.context.behaviours.simple_oracle_behaviour.update_prometheus_metric(\n                metric_name, \"set\", float(ledger_api_msg.balance), {}\n            )\n\n    def _handle_transaction_digest(\n        self, ledger_api_msg: LedgerApiMessage, ledger_api_dialogue: LedgerApiDialogue\n    ) -> None:\n        \"\"\"\n        Handle a message of transaction_digest performative.\n\n        :param ledger_api_msg: the ledger api message\n        :param ledger_api_dialogue: the ledger api dialogue\n        \"\"\"\n        self.context.logger.info(\n            \"transaction was successfully submitted. Transaction digest={}\".format(\n                ledger_api_msg.transaction_digest\n            )\n        )\n        msg = ledger_api_dialogue.reply(\n            performative=LedgerApiMessage.Performative.GET_TRANSACTION_RECEIPT,\n            target_message=ledger_api_msg,\n            transaction_digest=ledger_api_msg.transaction_digest,\n        )\n        self.context.outbox.put_message(message=msg)\n        self.context.logger.info(\"requesting transaction receipt.\")\n\n    def _request_init_transaction(self, ledger_id: str, tx_receipt: JSONLike) -> None:\n        \"\"\"\n        Send a message to request the initialisation transaction to finalise contract deployment\n\n        :param ledger_id: the ledger id\n        :param tx_receipt: the transaction receipt\n        \"\"\"\n        strategy = cast(Strategy, self.context.strategy)\n        contract_api_dialogues = cast(\n            ContractApiDialogues, self.context.contract_api_dialogues\n        )\n        fetchai_api = cast(FetchAIApi, LedgerApis.get_api(ledger_id))\n        code_id = fetchai_api.get_code_id(tx_receipt)  # type: Optional[int]\n        if code_id:\n            contract_api_msg, dialogue = contract_api_dialogues.create(\n                counterparty=str(LEDGER_API_ADDRESS),\n                performative=ContractApiMessage.Performative.GET_DEPLOY_TRANSACTION,\n                ledger_id=ledger_id,\n                contract_id=str(CONTRACT_PUBLIC_ID),\n                callable=\"get_deploy_transaction\",\n                kwargs=ContractApiMessage.Kwargs(\n                    {\n                        \"label\": \"OracleContract\",\n                        \"init_msg\": {\"fee\": str(strategy.initial_fee_deploy)},\n                        \"gas\": strategy.gas_limit_instantiate,\n                        \"tx_fee\": strategy.gas_price * strategy.gas_limit_instantiate,\n                        \"amount\": 1,\n                        \"code_id\": code_id,\n                        \"deployer_address\": self.context.agent_address,\n                    }\n                ),\n            )\n            contract_api_dialogue = cast(ContractApiDialogue, dialogue)\n            contract_api_dialogue.terms = strategy.get_deploy_terms(\n                is_init_transaction=True\n            )\n            self.context.outbox.put_message(message=contract_api_msg)\n        else:  # pragma: nocover\n            self.context.logger.info(\"Failed to initialize contract: code_id not found\")\n\n    def _save_contract_address_to_file(self) -> None:\n        \"\"\"Save the oracle contract address to a text file if specified in config.\"\"\"\n        strategy = cast(Strategy, self.context.strategy)\n        if strategy.contract_address_file:  # pragma: nocover\n            self.context.logger.info(\n                f\"Saving contract address to file: {strategy.contract_address_file}\"\n            )\n            with open(strategy.contract_address_file, \"w\", encoding=\"utf-8\") as file:\n                file.write(strategy.contract_address)\n\n    def _handle_transaction_receipt(\n        self, ledger_api_msg: LedgerApiMessage, ledger_api_dialogue: LedgerApiDialogue\n    ) -> None:\n        \"\"\"\n        Handle a message of transaction_receipt performative.\n\n        :param ledger_api_msg: the ledger api message\n        :param ledger_api_dialogue: the ledger api dialogue\n        \"\"\"\n        ledger_id = cast(str, ledger_api_msg.transaction_receipt.ledger_id)\n        tx_receipt = cast(JSONLike, ledger_api_msg.transaction_receipt.receipt)\n\n        is_transaction_successful = LedgerApis.is_transaction_settled(\n            ledger_id,\n            tx_receipt,\n        )\n        if is_transaction_successful:\n            self.context.logger.info(\n                \"transaction was successfully settled. Transaction receipt={}\".format(\n                    ledger_api_msg.transaction_receipt\n                )\n            )\n            strategy = cast(Strategy, self.context.strategy)\n            contract_api_dialogue = (\n                ledger_api_dialogue.associated_signing_dialogue.associated_contract_api_dialogue\n            )\n            transaction_label = contract_api_dialogue.terms.kwargs.get(\"label\", \"None\")\n\n            if not strategy.is_contract_deployed:\n                if transaction_label == \"store\":\n                    self._request_init_transaction(ledger_id, tx_receipt)\n                elif transaction_label in {\"deploy\", \"init\"}:\n                    contract_address = LedgerApis.get_contract_address(\n                        ledger_id, tx_receipt\n                    )\n                    if contract_address is None:\n                        raise ValueError(\n                            \"No contract address found.\"\n                        )  # pragma: nocover\n                    strategy.contract_address = contract_address\n                    strategy.is_contract_deployed = True\n                    self._save_contract_address_to_file()\n                    self.context.logger.info(\n                        f\"Oracle contract successfully deployed at address: {contract_address}\"\n                    )\n                else:\n                    self.context.logger.error(\n                        f\"Invalid transaction label: {transaction_label}\"\n                    )  # pragma: nocover\n            elif (\n                not strategy.is_oracle_role_granted\n                and transaction_label == \"grant_role\"\n            ):\n                strategy.is_oracle_role_granted = is_transaction_successful\n                if is_transaction_successful:\n                    self.context.logger.info(\"Oracle role successfully granted!\")\n                else:  # pragma: nocover\n                    self.context.logger.info(\"Failed to grant oracle role\")\n            elif transaction_label == \"update\":\n                self.context.logger.info(\"Oracle value successfully updated!\")\n                if self.context.prometheus_dialogues.enabled:\n                    metric_name = \"num_oracle_updates\"\n                    self.context.behaviours.simple_oracle_behaviour.update_prometheus_metric(\n                        metric_name, \"inc\", 1.0, {}\n                    )\n            else:  # pragma: nocover\n                self.context.logger.error(\"unexpected transaction receipt!\")\n        else:\n            self.context.logger.error(\n                \"transaction failed. Transaction receipt={}\".format(\n                    ledger_api_msg.transaction_receipt\n                )\n            )\n\n    def _handle_error(\n        self, ledger_api_msg: LedgerApiMessage, ledger_api_dialogue: LedgerApiDialogue\n    ) -> None:\n        \"\"\"\n        Handle a message of error performative.\n\n        :param ledger_api_msg: the ledger api message\n        :param ledger_api_dialogue: the ledger api dialogue\n        \"\"\"\n        self.context.logger.info(\n            \"received ledger_api error message={} in dialogue={}.\".format(\n                ledger_api_msg, ledger_api_dialogue\n            )\n        )\n\n    def _handle_invalid(\n        self, ledger_api_msg: LedgerApiMessage, ledger_api_dialogue: LedgerApiDialogue\n    ) -> None:\n        \"\"\"\n        Handle a message of invalid performative.\n\n        :param ledger_api_msg: the ledger api message\n        :param ledger_api_dialogue: the ledger api dialogue\n        \"\"\"\n        self.context.logger.warning(\n            \"cannot handle ledger_api message of performative={} in dialogue={}.\".format(\n                ledger_api_msg.performative,\n                ledger_api_dialogue,\n            )\n        )\n\n\nclass ContractApiHandler(Handler):\n    \"\"\"Implement the contract api handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = ContractApiMessage.protocol_id  # type: Optional[PublicId]\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup for the handler.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to a message.\n\n        :param message: the message\n        \"\"\"\n\n        self.context.logger.info(\"Handling contract api msg\")\n\n        contract_api_msg = cast(ContractApiMessage, message)\n\n        # recover dialogue\n        contract_api_dialogues = cast(\n            ContractApiDialogues, self.context.contract_api_dialogues\n        )\n        contract_api_dialogue = cast(\n            Optional[ContractApiDialogue],\n            contract_api_dialogues.update(contract_api_msg),\n        )\n        if contract_api_dialogue is None:\n            self._handle_unidentified_dialogue(contract_api_msg)\n            return\n\n        # handle message\n        if (\n            contract_api_msg.performative\n            is ContractApiMessage.Performative.RAW_TRANSACTION\n        ):\n            self._handle_raw_transaction(contract_api_msg, contract_api_dialogue)\n        elif contract_api_msg.performative == ContractApiMessage.Performative.ERROR:\n            self._handle_error(contract_api_msg, contract_api_dialogue)\n        else:\n            self._handle_invalid(contract_api_msg, contract_api_dialogue)\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n\n    def _handle_unidentified_dialogue(\n        self, contract_api_msg: ContractApiMessage\n    ) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param contract_api_msg: the message\n        \"\"\"\n        self.context.logger.info(\n            \"received invalid contract_api message={}, unidentified dialogue.\".format(\n                contract_api_msg\n            )\n        )\n\n    def _handle_raw_transaction(\n        self,\n        contract_api_msg: ContractApiMessage,\n        contract_api_dialogue: ContractApiDialogue,\n    ) -> None:\n        \"\"\"\n        Handle a message of raw_transaction performative.\n\n        :param contract_api_msg: the ledger api message\n        :param contract_api_dialogue: the ledger api dialogue\n        \"\"\"\n        self.context.logger.info(\"received raw transaction={}\".format(contract_api_msg))\n        signing_dialogues = cast(SigningDialogues, self.context.signing_dialogues)\n        signing_msg, signing_dialogue = signing_dialogues.create(\n            counterparty=self.context.decision_maker_address,\n            performative=SigningMessage.Performative.SIGN_TRANSACTION,\n            raw_transaction=contract_api_msg.raw_transaction,\n            terms=contract_api_dialogue.terms,\n        )\n        signing_dialogue = cast(SigningDialogue, signing_dialogue)\n        signing_dialogue.associated_contract_api_dialogue = contract_api_dialogue\n        self.context.decision_maker_message_queue.put_nowait(signing_msg)\n        self.context.logger.info(\n            \"proposing the transaction to the decision maker. Waiting for confirmation ...\"\n        )\n\n    def _handle_error(\n        self,\n        contract_api_msg: ContractApiMessage,\n        contract_api_dialogue: ContractApiDialogue,\n    ) -> None:\n        \"\"\"\n        Handle a message of error performative.\n\n        :param contract_api_msg: the ledger api message\n        :param contract_api_dialogue: the ledger api dialogue\n        \"\"\"\n        self.context.logger.info(\n            \"received ledger_api error message={} in dialogue={}.\".format(\n                contract_api_msg, contract_api_dialogue\n            )\n        )\n\n    def _handle_invalid(\n        self,\n        contract_api_msg: ContractApiMessage,\n        contract_api_dialogue: ContractApiDialogue,\n    ) -> None:\n        \"\"\"\n        Handle a message of invalid performative.\n\n        :param contract_api_msg: the ledger api message\n        :param contract_api_dialogue: the ledger api dialogue\n        \"\"\"\n        self.context.logger.warning(\n            \"cannot handle contract_api message of performative={} in dialogue={}.\".format(\n                contract_api_msg.performative,\n                contract_api_dialogue,\n            )\n        )\n\n\nclass SigningHandler(Handler):\n    \"\"\"Implement the transaction handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = SigningMessage.protocol_id  # type: Optional[PublicId]\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup for the handler.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to a message.\n\n        :param message: the message\n        \"\"\"\n        signing_msg = cast(SigningMessage, message)\n\n        # recover dialogue\n        signing_dialogues = cast(SigningDialogues, self.context.signing_dialogues)\n        signing_dialogue = cast(\n            Optional[SigningDialogue], signing_dialogues.update(signing_msg)\n        )\n        if signing_dialogue is None:\n            self._handle_unidentified_dialogue(signing_msg)\n            return\n\n        # handle message\n        if signing_msg.performative is SigningMessage.Performative.SIGNED_TRANSACTION:\n            self._handle_signed_transaction(signing_msg, signing_dialogue)\n        elif signing_msg.performative is SigningMessage.Performative.ERROR:\n            self._handle_error(signing_msg, signing_dialogue)\n        else:\n            self._handle_invalid(signing_msg, signing_dialogue)\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n\n    def _handle_unidentified_dialogue(self, signing_msg: SigningMessage) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param signing_msg: the message\n        \"\"\"\n        self.context.logger.info(\n            \"received invalid signing message={}, unidentified dialogue.\".format(\n                signing_msg\n            )\n        )\n\n    def _handle_signed_transaction(\n        self, signing_msg: SigningMessage, signing_dialogue: SigningDialogue\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param signing_msg: the signing message\n        :param signing_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.info(\"transaction signing was successful.\")\n        ledger_api_dialogues = cast(\n            LedgerApiDialogues, self.context.ledger_api_dialogues\n        )\n        ledger_api_msg, ledger_api_dialogue = ledger_api_dialogues.create(\n            counterparty=str(LEDGER_API_ADDRESS),\n            performative=LedgerApiMessage.Performative.SEND_SIGNED_TRANSACTION,\n            signed_transaction=signing_msg.signed_transaction,\n        )\n        ledger_api_dialogue = cast(LedgerApiDialogue, ledger_api_dialogue)\n        ledger_api_dialogue.associated_signing_dialogue = signing_dialogue\n        self.context.outbox.put_message(message=ledger_api_msg)\n        self.context.logger.info(\"sending transaction to ledger.\")\n\n    def _handle_error(\n        self, signing_msg: SigningMessage, signing_dialogue: SigningDialogue\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param signing_msg: the signing message\n        :param signing_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.info(\n            \"transaction signing was not successful. Error_code={} in dialogue={}\".format(\n                signing_msg.error_code, signing_dialogue\n            )\n        )\n\n    def _handle_invalid(\n        self, signing_msg: SigningMessage, signing_dialogue: SigningDialogue\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param signing_msg: the signing message\n        :param signing_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.warning(\n            \"cannot handle signing message of performative={} in dialogue={}.\".format(\n                signing_msg.performative, signing_dialogue\n            )\n        )\n\n\nclass PrometheusHandler(Handler):\n    \"\"\"This class handles responses from the prometheus server.\"\"\"\n\n    SUPPORTED_PROTOCOL = PrometheusMessage.protocol_id\n\n    def setup(self) -> None:\n        \"\"\"Set up the handler.\"\"\"\n        if self.context.prometheus_dialogues.enabled:\n            self.context.logger.info(\"setting up PrometheusHandler\")\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to a message.\n\n        :param message: the message\n        \"\"\"\n\n        message = cast(PrometheusMessage, message)\n\n        # recover dialogue\n        prometheus_dialogues = cast(\n            PrometheusDialogues, self.context.prometheus_dialogues\n        )\n        prometheus_dialogue = cast(\n            PrometheusDialogue, prometheus_dialogues.update(message)\n        )\n        if prometheus_dialogue is None:\n            self._handle_unidentified_dialogue(message)\n            return\n\n        if message.performative == PrometheusMessage.Performative.RESPONSE:\n            self.context.logger.debug(\n                f\"Prometheus response ({message.code}): {message.message}\"\n            )\n        else:  # pragma: nocover\n            self.context.logger.debug(\n                f\"got unexpected prometheus message: Performative = {PrometheusMessage.Performative}\"\n            )\n\n    def _handle_unidentified_dialogue(self, msg: Message) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param msg: the unidentified message to be handled\n        \"\"\"\n\n        self.context.logger.info(\n            \"received invalid message={}, unidentified dialogue.\".format(msg)\n        )\n\n    def teardown(self) -> None:\n        \"\"\"Teardown the handler.\"\"\"\n"
  },
  {
    "path": "packages/fetchai/skills/simple_oracle/skill.yaml",
    "content": "name: simple_oracle\nauthor: fetchai\nversion: 0.16.5\ntype: skill\ndescription: This skill deploys a Fetch oracle contract\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: Qme3QavjkmFm4HWMLEAJpAHCYd4miKq2j2LXayRDSRSGiw\n  __init__.py: QmYuLwWrL7SLS8H2W3R5SkVtpp5ufJSmjuNkzko6AbN6zS\n  behaviours.py: QmXyscjzvxLeJcssKgpuxqXwDyX1QGcwPPvEcMa5ymyTbH\n  dialogues.py: QmS4XJDpNXxjKewDUk6HREXrm8pa3KndTR7vzppVcAURCt\n  handlers.py: QmQm7ofZBu3HHB1ETwBzmnQiTFHNeouVFssNrfQeJ9Rpfd\n  strategy.py: QmWw9SzUtphNC1mjST5KNnT5zkjAP7EPu9n4qkeDtJXL2B\nfingerprint_ignore_patterns: []\ncontracts:\n- fetchai/oracle:0.12.3\nprotocols:\n- fetchai/contract_api:1.1.7\n- fetchai/default:1.1.7\n- fetchai/ledger_api:1.1.7\n- fetchai/prometheus:1.1.7\n- fetchai/signing:1.1.7\nskills: []\nbehaviours:\n  simple_oracle_behaviour:\n    args:\n      update_interval: 15\n    class_name: SimpleOracleBehaviour\nhandlers:\n  contract_api:\n    args: {}\n    class_name: ContractApiHandler\n  ledger_api:\n    args: {}\n    class_name: LedgerApiHandler\n  prometheus:\n    args: {}\n    class_name: PrometheusHandler\n  signing:\n    args: {}\n    class_name: SigningHandler\nmodels:\n  contract_api_dialogues:\n    args: {}\n    class_name: ContractApiDialogues\n  ledger_api_dialogues:\n    args: {}\n    class_name: LedgerApiDialogues\n  prometheus_dialogues:\n    args:\n      enabled: true\n      metrics:\n      - name: oracle_account_balance_ETH\n        type: Gauge\n        description: Balance of oracle contract (ETH)\n        labels: {}\n      - name: num_oracle_updates\n        type: Gauge\n        description: Number of updates published to oracle contract\n        labels: {}\n    class_name: PrometheusDialogues\n  signing_dialogues:\n    args: {}\n    class_name: SigningDialogues\n  strategy:\n    args:\n      contract_address: null\n      contract_address_file: null\n      erc20_address: '0x0000000000000000000000000000000000000000'\n      gas_limit_deploy: 1500000\n      gas_limit_grant_role: 1500000\n      gas_limit_instantiate: 500000\n      gas_limit_update: 1500000\n      gas_price: 1000000000\n      initial_fee_deploy: 1000000000000\n      is_oracle_role_granted: false\n      ledger_id: null\n      oracle_value_name: null\n      update_function: null\n    class_name: Strategy\ndependencies:\n  aea-ledger-ethereum:\n    version: <2.0.0,>=1.0.0\n  aea-ledger-fetchai:\n    version: <2.0.0,>=1.0.0\nis_abstract: false\nconnections: []\n"
  },
  {
    "path": "packages/fetchai/skills/simple_oracle/strategy.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the strategy class.\"\"\"\n\nfrom typing import Any\n\nfrom aea_ledger_ethereum import EthereumApi\n\nfrom aea.configurations.constants import DEFAULT_LEDGER\nfrom aea.exceptions import enforce\nfrom aea.helpers.transaction.base import Terms\nfrom aea.skills.base import Model\n\nfrom packages.fetchai.protocols.contract_api.custom_types import Kwargs\n\n\nDEFAULT_LEDGER_ID = DEFAULT_LEDGER\nMAX_BLOCK_HEIGHT = 1000000000000000000\nDEFAULT_ORACLE_VALUE_NAME = \"oracle_value\"\n\n\nclass Strategy(Model):\n    \"\"\"This class defines a strategy for the agent.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"Initialize the strategy of the agent.\"\"\"\n        self._ledger_id = kwargs.pop(\"ledger_id\", DEFAULT_LEDGER_ID)\n        self._contract_address = kwargs.pop(\"contract_address\", None)\n        self._erc20_address = kwargs.pop(\"erc20_address\", None)\n        self._update_function = kwargs.pop(\"update_function\", None)\n        self._is_oracle_role_granted = kwargs.pop(\"is_oracle_role_granted\", False)\n        self._initial_fee_deploy = kwargs.pop(\"initial_fee_deploy\", 0)\n        self._gas_limit_deploy = kwargs.pop(\"gas_limit_deploy\", 0)\n        self._gas_limit_instantiate = kwargs.pop(\"gas_limit_instantiate\", 0)\n        self._gas_limit_grant_role = kwargs.pop(\"gas_limit_grant_role\", 0)\n        self._gas_limit_update = kwargs.pop(\"gas_limit_update\", 0)\n        self._gas_price = kwargs.pop(\"gas_price\", 0)\n        self._oracle_value_name = kwargs.pop(\n            \"oracle_value_name\", DEFAULT_ORACLE_VALUE_NAME\n        )\n        self._contract_address_file = kwargs.pop(\"contract_address_file\", None)\n\n        super().__init__(**kwargs)\n\n        self.is_behaviour_active = True\n        self._is_contract_deployed = self._contract_address is not None\n\n    @property\n    def ledger_id(self) -> str:\n        \"\"\"Get the ledger id.\"\"\"\n        return self._ledger_id\n\n    @property\n    def update_function(self) -> str:\n        \"\"\"Get the name of the oracle value update function.\"\"\"\n        return self._update_function\n\n    @property\n    def initial_fee_deploy(self) -> int:\n        \"\"\"Get the initial for contract deployment.\"\"\"\n        return self._initial_fee_deploy\n\n    @property\n    def gas_limit_deploy(self) -> int:\n        \"\"\"Get the gas limit for deploying a contract.\"\"\"\n        return self._gas_limit_deploy\n\n    @property\n    def gas_limit_instantiate(self) -> int:\n        \"\"\"Get the default gas for instantiating a contract.\"\"\"\n        return self._gas_limit_instantiate\n\n    @property\n    def gas_limit_grant_role(self) -> int:\n        \"\"\"Get the gas limit for role granting.\"\"\"\n        return self._gas_limit_grant_role\n\n    @property\n    def gas_limit_update(self) -> int:\n        \"\"\"Get the gas limit for updating a value.\"\"\"\n        return self._gas_limit_update\n\n    @property\n    def gas_price(self) -> int:\n        \"\"\"Get the gas price.\"\"\"\n        return self._gas_price\n\n    @property\n    def oracle_value_name(self) -> str:\n        \"\"\"Get the name of the oracle value.\"\"\"\n        return self._oracle_value_name\n\n    @property\n    def contract_address_file(self) -> str:\n        \"\"\"Get the filename where the oracle contract is to be stored.\"\"\"\n        return self._contract_address_file\n\n    @property\n    def contract_address(self) -> str:\n        \"\"\"Get the contract address.\"\"\"\n        if self._contract_address is None:  # pragma: nocover\n            raise ValueError(\"Contract address not set!\")\n        return self._contract_address\n\n    @contract_address.setter\n    def contract_address(self, contract_address: str) -> None:\n        \"\"\"Set the contract address.\"\"\"\n        enforce(self._contract_address is None, \"Contract address already set!\")\n        self._contract_address = contract_address\n\n    @property\n    def erc20_address(self) -> str:\n        \"\"\"Get the erc20 address for token payment.\"\"\"\n        if self._erc20_address is None:  # pragma: nocover\n            raise ValueError(\"ERC20 address not set!\")\n        return self._erc20_address\n\n    @erc20_address.setter\n    def erc20_address(self, erc20_address: str) -> None:  # pragma: nocover\n        \"\"\"Set the erc20 address for token payment.\"\"\"\n        enforce(self._erc20_address is None, \"ERC20 address already set!\")\n        self._erc20_address = erc20_address\n\n    @property\n    def is_contract_deployed(self) -> bool:\n        \"\"\"Get contract deploy status.\"\"\"\n        return self._is_contract_deployed\n\n    @is_contract_deployed.setter\n    def is_contract_deployed(self, is_contract_deployed: bool) -> None:\n        \"\"\"Set contract deploy status.\"\"\"\n        enforce(\n            not self._is_contract_deployed and is_contract_deployed,\n            \"Only allowed to switch to true.\",\n        )\n        self._is_contract_deployed = is_contract_deployed\n\n    @property\n    def is_oracle_role_granted(self) -> bool:\n        \"\"\"Get oracle role status.\"\"\"\n        return self._is_oracle_role_granted\n\n    @is_oracle_role_granted.setter\n    def is_oracle_role_granted(self, is_oracle_role_granted: bool) -> None:\n        \"\"\"Set oracle role status.\"\"\"\n        enforce(\n            not self._is_oracle_role_granted and is_oracle_role_granted,\n            \"Only allowed to switch to true.\",\n        )\n        self._is_oracle_role_granted = is_oracle_role_granted\n\n    def get_deploy_terms(self, is_init_transaction: bool = False) -> Terms:\n        \"\"\"\n        Get terms of deployment.\n\n        :param is_init_transaction: whether the transaction is init or store.\n        :return: terms\n        \"\"\"\n        if self.ledger_id == EthereumApi.identifier:\n            label = \"deploy\"\n        else:\n            if is_init_transaction:\n                label = \"init\"\n            else:\n                label = \"store\"\n\n        terms = Terms(\n            ledger_id=self.ledger_id,\n            sender_address=self.context.agent_address,\n            counterparty_address=self.context.agent_address,\n            amount_by_currency_id={},\n            quantities_by_good_id={},\n            nonce=\"\",\n            label=label,\n        )\n        return terms\n\n    def get_grant_role_terms(self) -> Terms:\n        \"\"\"\n        Get terms of oracle role granting.\n\n        :return: terms\n        \"\"\"\n        terms = Terms(\n            ledger_id=self.ledger_id,\n            sender_address=self.context.agent_address,\n            counterparty_address=self.context.agent_address,\n            amount_by_currency_id={},\n            quantities_by_good_id={},\n            nonce=\"\",\n            label=\"grant_role\",\n        )\n        return terms\n\n    def get_update_terms(self) -> Terms:\n        \"\"\"\n        Get terms of update transaction.\n\n        :return: terms\n        \"\"\"\n        terms = Terms(\n            ledger_id=self.ledger_id,\n            sender_address=self.context.agent_address,\n            counterparty_address=self.context.agent_address,\n            amount_by_currency_id={},\n            quantities_by_good_id={},\n            nonce=\"\",\n            label=\"update\",\n        )\n        return terms\n\n    def get_deploy_kwargs(self) -> Kwargs:\n        \"\"\"\n        Get kwargs for the contract deployment\n\n        :return: kwargs\n        \"\"\"\n        if self.ledger_id == EthereumApi.identifier:\n            kwargs = Kwargs(\n                {\n                    \"deployer_address\": self.context.agent_address,\n                    \"gas\": self.gas_limit_deploy,\n                    \"ERC20Address\": self.erc20_address,\n                    \"initialFee\": self.initial_fee_deploy,\n                }\n            )\n        else:\n            kwargs = Kwargs(\n                {\n                    \"deployer_address\": self.context.agent_address,\n                    \"gas\": self.gas_limit_deploy,\n                    \"tx_fee\": self.gas_price * self.gas_limit_deploy,\n                }\n            )\n        return kwargs\n"
  },
  {
    "path": "packages/fetchai/skills/simple_oracle_client/README.md",
    "content": "# Simple Oracle Client\n\n## Description\n\nThis skill is used to deploy an oracle client smart contract to a ledger, approve the contract to make FET payments on behalf of the agent, and periodically call the contract function that requests the oracle value.\n\n## Behaviours\n\n- `simple_oracle_client_behaviour`: deploys oracle client contract, approves contract transactions, and calls the contract to request the oracle value every `tick_interval` seconds, as specified in the skill configuration.\n\n## Handlers\n\n- `contract_api`: handles `contract_api` messages for interactions with the smart contract\n- `ledger_api`: handles `ledger_api` messages for interacting with a ledger\n- `signing`: handles `signing` messages for transaction signing by the decision maker\n"
  },
  {
    "path": "packages/fetchai/skills/simple_oracle_client/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the implementation of the simple oracle client skill.\"\"\"\n\nfrom aea.configurations.base import PublicId\n\n\nPUBLIC_ID = PublicId.from_str(\"fetchai/simple_oracle_client:0.13.5\")\n"
  },
  {
    "path": "packages/fetchai/skills/simple_oracle_client/behaviours.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains a simple Fetch oracle client behaviour.\"\"\"\n\nfrom typing import Any, cast\n\nfrom aea_ledger_ethereum import EthereumApi\n\nfrom aea.skills.behaviours import TickerBehaviour\n\nfrom packages.fetchai.connections.ledger.base import CONNECTION_ID as LEDGER_API_ADDRESS\nfrom packages.fetchai.contracts.fet_erc20.contract import (\n    PUBLIC_ID as FET_ERC20_PUBLIC_ID,\n)\nfrom packages.fetchai.contracts.oracle_client.contract import (\n    PUBLIC_ID as CLIENT_CONTRACT_PUBLIC_ID,\n)\nfrom packages.fetchai.protocols.contract_api.message import ContractApiMessage\nfrom packages.fetchai.skills.simple_oracle_client.dialogues import (\n    ContractApiDialogue,\n    ContractApiDialogues,\n)\nfrom packages.fetchai.skills.simple_oracle_client.strategy import Strategy\n\n\nDEFAULT_QUERY_INTERVAL = 5\n\n\nclass SimpleOracleClientBehaviour(TickerBehaviour):\n    \"\"\"This class implements a behaviour that deploys a Fetch oracle client contract.\"\"\"\n\n    def __init__(self, **kwargs: Any):\n        \"\"\"Initialise the behaviour.\"\"\"\n        query_interval = kwargs.pop(\n            \"query_interval\", DEFAULT_QUERY_INTERVAL\n        )  # type: int\n        super().__init__(tick_interval=query_interval, **kwargs)\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup.\"\"\"\n        self.context.logger.info(\"Setting up Fetch oracle client contract...\")\n        strategy = cast(Strategy, self.context.strategy)\n\n        if not strategy.is_client_contract_deployed:\n            self._request_contract_deploy_transaction()\n        else:\n            self.context.logger.info(\n                \"Fetch oracle client contract address already added\"\n            )\n\n    def act(self) -> None:\n        \"\"\"Implement the act.\"\"\"\n        strategy = cast(Strategy, self.context.strategy)\n\n        if not strategy.is_client_contract_deployed:\n            self.context.logger.info(\"Oracle client contract not yet deployed\")\n            return\n        if (\n            strategy.ledger_id == EthereumApi.identifier\n            and not strategy.is_oracle_transaction_approved\n        ):\n            self.context.logger.info(\n                \"Oracle client contract not yet approved to spend tokens\"\n            )\n            self._request_approve_transaction()\n            return\n\n        # Call contract function that queries oracle value\n        self.context.logger.info(\"Calling contract to request oracle value...\")\n        self._request_query_transaction()\n\n    def _request_contract_deploy_transaction(self) -> None:\n        \"\"\"Request contract deployment transaction\"\"\"\n        strategy = cast(Strategy, self.context.strategy)\n        strategy.is_behaviour_active = False\n        contract_api_dialogues = cast(\n            ContractApiDialogues, self.context.contract_api_dialogues\n        )\n        contract_api_msg, contract_api_dialogue = contract_api_dialogues.create(\n            counterparty=str(LEDGER_API_ADDRESS),\n            performative=ContractApiMessage.Performative.GET_DEPLOY_TRANSACTION,\n            ledger_id=strategy.ledger_id,\n            contract_id=str(CLIENT_CONTRACT_PUBLIC_ID),\n            callable=\"get_deploy_transaction\",\n            kwargs=strategy.get_deploy_kwargs(),\n        )\n        contract_api_dialogue = cast(\n            ContractApiDialogue,\n            contract_api_dialogue,\n        )\n        contract_api_dialogue.terms = strategy.get_deploy_terms()\n        self.context.outbox.put_message(message=contract_api_msg)\n        self.context.logger.info(\"requesting contract deployment transaction...\")\n\n    def _request_approve_transaction(self) -> None:\n        \"\"\"Request transaction that approves client contract to spend tokens on behalf of sender.\"\"\"\n        strategy = cast(Strategy, self.context.strategy)\n        strategy.is_behaviour_active = False\n        contract_api_dialogues = cast(\n            ContractApiDialogues, self.context.contract_api_dialogues\n        )\n        contract_api_msg, contract_api_dialogue = contract_api_dialogues.create(\n            counterparty=str(LEDGER_API_ADDRESS),\n            performative=ContractApiMessage.Performative.GET_RAW_TRANSACTION,\n            ledger_id=strategy.ledger_id,\n            contract_id=str(FET_ERC20_PUBLIC_ID),\n            contract_address=strategy.erc20_address,\n            callable=\"get_approve_transaction\",\n            kwargs=ContractApiMessage.Kwargs(\n                {\n                    \"from_address\": self.context.agent_address,\n                    \"spender\": strategy.client_contract_address,\n                    \"amount\": strategy.approve_amount,\n                    \"gas\": strategy.gas_limit_approve,\n                }\n            ),\n        )\n        contract_api_dialogue = cast(ContractApiDialogue, contract_api_dialogue)\n        contract_api_dialogue.terms = strategy.get_approve_terms()\n        self.context.outbox.put_message(message=contract_api_msg)\n        self.context.logger.info(\"requesting query transaction...\")\n\n    def _request_query_transaction(self) -> None:\n        \"\"\"Request transaction that requests value from Fetch oracle contract.\"\"\"\n        strategy = cast(Strategy, self.context.strategy)\n        strategy.is_behaviour_active = False\n        contract_api_dialogues = cast(\n            ContractApiDialogues, self.context.contract_api_dialogues\n        )\n        contract_api_msg, contract_api_dialogue = contract_api_dialogues.create(\n            counterparty=str(LEDGER_API_ADDRESS),\n            performative=ContractApiMessage.Performative.GET_RAW_TRANSACTION,\n            ledger_id=strategy.ledger_id,\n            contract_id=str(CLIENT_CONTRACT_PUBLIC_ID),\n            contract_address=strategy.client_contract_address,\n            callable=\"get_query_transaction\",\n            kwargs=ContractApiMessage.Kwargs(\n                {\n                    \"from_address\": self.context.agent_address,\n                    \"query_function\": strategy.query_function,\n                    \"amount\": strategy.query_oracle_fee,\n                    \"gas\": strategy.gas_limit_query,\n                    \"tx_fee\": strategy.gas_price * strategy.gas_limit_query,\n                }\n            ),\n        )\n        contract_api_dialogue = cast(ContractApiDialogue, contract_api_dialogue)\n        contract_api_dialogue.terms = strategy.get_query_terms()\n        self.context.outbox.put_message(message=contract_api_msg)\n        self.context.logger.info(\"requesting query transaction...\")\n\n    def teardown(self) -> None:\n        \"\"\"Implement the task teardown.\"\"\"\n"
  },
  {
    "path": "packages/fetchai/skills/simple_oracle_client/dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains the ContractAPI and LedgerAPI dialogues for the simple oracle client skill.\"\"\"\n\nfrom typing import Any, Optional, Type\n\nfrom aea.common import Address\nfrom aea.exceptions import enforce\nfrom aea.helpers.transaction.base import Terms\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\nfrom aea.protocols.dialogue.base import DialogueLabel as BaseDialogueLabel\nfrom aea.skills.base import Model\n\nfrom packages.fetchai.protocols.contract_api.dialogues import (\n    ContractApiDialogue as BaseContractApiDialogue,\n)\nfrom packages.fetchai.protocols.contract_api.dialogues import (\n    ContractApiDialogues as BaseContractApiDialogues,\n)\nfrom packages.fetchai.protocols.contract_api.message import ContractApiMessage\nfrom packages.fetchai.protocols.ledger_api.dialogues import (\n    LedgerApiDialogue as BaseLedgerApiDialogue,\n)\nfrom packages.fetchai.protocols.ledger_api.dialogues import (\n    LedgerApiDialogues as BaseLedgerApiDialogues,\n)\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\nfrom packages.fetchai.protocols.signing.dialogues import (\n    SigningDialogue as BaseSigningDialogue,\n)\nfrom packages.fetchai.protocols.signing.dialogues import (\n    SigningDialogues as BaseSigningDialogues,\n)\nfrom packages.fetchai.protocols.signing.message import SigningMessage\n\n\nclass ContractApiDialogue(BaseContractApiDialogue):\n    \"\"\"The dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    __slots__ = (\"_terms\",)\n\n    def __init__(\n        self,\n        dialogue_label: BaseDialogueLabel,\n        self_address: Address,\n        role: BaseDialogue.Role,\n        message_class: Type[ContractApiMessage] = ContractApiMessage,\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n        :param message_class: the message class\n        \"\"\"\n        BaseContractApiDialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            self_address=self_address,\n            role=role,\n            message_class=message_class,\n        )\n        self._terms = None  # type: Optional[Terms]\n\n    @property\n    def terms(self) -> Terms:\n        \"\"\"Get the terms.\"\"\"\n        if self._terms is None:  # pragma: nocover\n            raise ValueError(\"Terms not set!\")\n        return self._terms\n\n    @terms.setter\n    def terms(self, terms: Terms) -> None:\n        \"\"\"Set the terms.\"\"\"\n        enforce(self._terms is None, \"Terms already set!\")\n        self._terms = terms\n\n\nclass ContractApiDialogues(Model, BaseContractApiDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return ContractApiDialogue.Role.AGENT\n\n        BaseContractApiDialogues.__init__(\n            self,\n            self_address=str(self.skill_id),\n            role_from_first_message=role_from_first_message,\n            dialogue_class=ContractApiDialogue,\n        )\n\n\nclass LedgerApiDialogue(BaseLedgerApiDialogue):\n    \"\"\"The dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    __slots__ = (\"_associated_signing_dialogue\", \"_associated_transaction_type\")\n\n    def __init__(\n        self,\n        dialogue_label: BaseDialogueLabel,\n        self_address: Address,\n        role: BaseDialogue.Role,\n        message_class: Type[LedgerApiMessage] = LedgerApiMessage,\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n        :param message_class: the message class\n        \"\"\"\n        BaseLedgerApiDialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            self_address=self_address,\n            role=role,\n            message_class=message_class,\n        )\n        self._associated_signing_dialogue = None  # type: Optional[SigningDialogue]\n        self._associated_transaction_type = None  # type: Optional[str]\n\n    @property\n    def associated_signing_dialogue(self) -> \"SigningDialogue\":\n        \"\"\"Get the associated signing dialogue.\"\"\"\n        if self._associated_signing_dialogue is None:  # pragma: nocover\n            raise ValueError(\"Associated signing dialogue not set!\")\n        return self._associated_signing_dialogue\n\n    @associated_signing_dialogue.setter\n    def associated_signing_dialogue(\n        self, associated_signing_dialogue: \"SigningDialogue\"\n    ) -> None:\n        \"\"\"Set the associated signing dialogue.\"\"\"\n        enforce(\n            self._associated_signing_dialogue is None,\n            \"Associated signing dialogue already set!\",\n        )\n        self._associated_signing_dialogue = associated_signing_dialogue\n\n\nclass LedgerApiDialogues(Model, BaseLedgerApiDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return BaseLedgerApiDialogue.Role.AGENT\n\n        BaseLedgerApiDialogues.__init__(\n            self,\n            self_address=str(self.skill_id),\n            role_from_first_message=role_from_first_message,\n            dialogue_class=LedgerApiDialogue,\n        )\n\n\nclass SigningDialogue(BaseSigningDialogue):\n    \"\"\"The dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    __slots__ = (\"_associated_contract_api_dialogue\",)\n\n    def __init__(\n        self,\n        dialogue_label: BaseDialogueLabel,\n        self_address: Address,\n        role: BaseDialogue.Role,\n        message_class: Type[SigningMessage] = SigningMessage,\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n        :param message_class: the message class\n        \"\"\"\n        BaseSigningDialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            self_address=self_address,\n            role=role,\n            message_class=message_class,\n        )\n        self._associated_contract_api_dialogue = (\n            None\n        )  # type: Optional[ContractApiDialogue]\n\n    @property\n    def associated_contract_api_dialogue(self) -> ContractApiDialogue:\n        \"\"\"Get the associated contract api dialogue.\"\"\"\n        if self._associated_contract_api_dialogue is None:  # pragma: nocover\n            raise ValueError(\"Associated contract api dialogue not set!\")\n        return self._associated_contract_api_dialogue\n\n    @associated_contract_api_dialogue.setter\n    def associated_contract_api_dialogue(\n        self, associated_contract_api_dialogue: ContractApiDialogue\n    ) -> None:\n        \"\"\"Set the associated contract api dialogue.\"\"\"\n        enforce(\n            self._associated_contract_api_dialogue is None,\n            \"Associated contract api dialogue already set!\",\n        )\n        self._associated_contract_api_dialogue = associated_contract_api_dialogue\n\n\nclass SigningDialogues(Model, BaseSigningDialogues):\n    \"\"\"This class keeps track of all oef_search dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return BaseSigningDialogue.Role.SKILL\n\n        BaseSigningDialogues.__init__(\n            self,\n            self_address=str(self.skill_id),\n            role_from_first_message=role_from_first_message,\n            dialogue_class=SigningDialogue,\n        )\n"
  },
  {
    "path": "packages/fetchai/skills/simple_oracle_client/handlers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains the handlers for the Fetch oracle client skill.\"\"\"\n\nfrom typing import Optional, cast\n\nfrom aea_ledger_fetchai import FetchAIApi\n\nfrom aea.common import JSONLike\nfrom aea.configurations.base import PublicId\nfrom aea.crypto.ledger_apis import LedgerApis\nfrom aea.protocols.base import Message\nfrom aea.skills.base import Handler\n\nfrom packages.fetchai.connections.ledger.base import CONNECTION_ID as LEDGER_API_ADDRESS\nfrom packages.fetchai.contracts.oracle_client.contract import (\n    PUBLIC_ID as CONTRACT_PUBLIC_ID,\n)\nfrom packages.fetchai.protocols.contract_api.message import ContractApiMessage\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\nfrom packages.fetchai.protocols.signing.message import SigningMessage\nfrom packages.fetchai.skills.simple_oracle_client.dialogues import (\n    ContractApiDialogue,\n    ContractApiDialogues,\n    LedgerApiDialogue,\n    LedgerApiDialogues,\n    SigningDialogue,\n    SigningDialogues,\n)\nfrom packages.fetchai.skills.simple_oracle_client.strategy import Strategy\n\n\nclass LedgerApiHandler(Handler):\n    \"\"\"Implement the ledger api handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = LedgerApiMessage.protocol_id  # type: Optional[PublicId]\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup for the handler.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to a message.\n\n        :param message: the message\n        \"\"\"\n\n        self.context.logger.info(\"Handling ledger api msg\")\n\n        ledger_api_msg = cast(LedgerApiMessage, message)\n\n        # recover dialogue\n        ledger_api_dialogues = cast(\n            LedgerApiDialogues, self.context.ledger_api_dialogues\n        )\n        ledger_api_dialogue = cast(\n            Optional[LedgerApiDialogue], ledger_api_dialogues.update(ledger_api_msg)\n        )\n        if ledger_api_dialogue is None:\n            self._handle_unidentified_dialogue(ledger_api_msg)\n            return\n\n        # handle message\n        if ledger_api_msg.performative is LedgerApiMessage.Performative.BALANCE:\n            self._handle_balance(ledger_api_msg)\n        elif (\n            ledger_api_msg.performative\n            is LedgerApiMessage.Performative.TRANSACTION_DIGEST\n        ):\n            self._handle_transaction_digest(ledger_api_msg, ledger_api_dialogue)\n        elif (\n            ledger_api_msg.performative\n            is LedgerApiMessage.Performative.TRANSACTION_RECEIPT\n        ):\n            self._handle_transaction_receipt(ledger_api_msg, ledger_api_dialogue)\n        elif ledger_api_msg.performative == LedgerApiMessage.Performative.ERROR:\n            self._handle_error(ledger_api_msg, ledger_api_dialogue)\n        else:\n            self._handle_invalid(ledger_api_msg, ledger_api_dialogue)\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n\n    def _handle_unidentified_dialogue(self, ledger_api_msg: LedgerApiMessage) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param ledger_api_msg: the message\n        \"\"\"\n        self.context.logger.info(\n            \"received invalid ledger_api message={}, unidentified dialogue.\".format(\n                ledger_api_msg\n            )\n        )\n\n    def _handle_balance(self, ledger_api_msg: LedgerApiMessage) -> None:\n        \"\"\"\n        Handle a message of balance performative.\n\n        :param ledger_api_msg: the ledger api message\n        \"\"\"\n        self.context.logger.info(\n            \"starting balance on {} ledger={}.\".format(\n                ledger_api_msg.ledger_id,\n                ledger_api_msg.balance,\n            )\n        )\n\n    def _handle_transaction_digest(\n        self, ledger_api_msg: LedgerApiMessage, ledger_api_dialogue: LedgerApiDialogue\n    ) -> None:\n        \"\"\"\n        Handle a message of transaction_digest performative.\n\n        :param ledger_api_msg: the ledger api message\n        :param ledger_api_dialogue: the ledger api dialogue\n        \"\"\"\n        self.context.logger.info(\n            \"transaction was successfully submitted. Transaction digest={}\".format(\n                ledger_api_msg.transaction_digest\n            )\n        )\n        msg = ledger_api_dialogue.reply(\n            performative=LedgerApiMessage.Performative.GET_TRANSACTION_RECEIPT,\n            target_message=ledger_api_msg,\n            transaction_digest=ledger_api_msg.transaction_digest,\n        )\n        self.context.outbox.put_message(message=msg)\n        self.context.logger.info(\"requesting transaction receipt.\")\n\n    def _request_init_transaction(self, ledger_id: str, tx_receipt: JSONLike) -> None:\n        \"\"\"\n        Send a message to request the initialisation transaction to finalise contract deployment\n\n        :param ledger_id: the ledger id\n        :param tx_receipt: the transaction receipt\n        \"\"\"\n        strategy = cast(Strategy, self.context.strategy)\n        contract_api_dialogues = cast(\n            ContractApiDialogues, self.context.contract_api_dialogues\n        )\n        fetchai_api = cast(FetchAIApi, LedgerApis.get_api(ledger_id))\n        code_id = fetchai_api.get_code_id(tx_receipt)  # type: Optional[int]\n        if code_id:\n            contract_api_msg, dialogue = contract_api_dialogues.create(\n                counterparty=str(LEDGER_API_ADDRESS),\n                performative=ContractApiMessage.Performative.GET_DEPLOY_TRANSACTION,\n                ledger_id=ledger_id,\n                contract_id=str(CONTRACT_PUBLIC_ID),\n                callable=\"get_deploy_transaction\",\n                kwargs=ContractApiMessage.Kwargs(\n                    {\n                        \"label\": \"OracleContract\",\n                        \"init_msg\": {\n                            \"oracle_contract_address\": strategy.oracle_contract_address\n                        },\n                        \"gas\": strategy.gas_limit_instantiate,\n                        \"tx_fee\": strategy.gas_price * strategy.gas_limit_instantiate,\n                        \"amount\": 0,\n                        \"code_id\": code_id,\n                        \"deployer_address\": self.context.agent_address,\n                    }\n                ),\n            )\n            contract_api_dialogue = cast(ContractApiDialogue, dialogue)\n            contract_api_dialogue.terms = strategy.get_deploy_terms(\n                is_init_transaction=True\n            )\n            self.context.outbox.put_message(message=contract_api_msg)\n        else:  # pragma: nocover\n            self.context.logger.info(\"Failed to initialize contract: code_id not found\")\n\n    def _handle_transaction_receipt(\n        self, ledger_api_msg: LedgerApiMessage, ledger_api_dialogue: LedgerApiDialogue\n    ) -> None:\n        \"\"\"\n        Handle a message of transaction_receipt performative.\n\n        :param ledger_api_msg: the ledger api message\n        :param ledger_api_dialogue: the ledger api dialogue\n        \"\"\"\n        ledger_id = cast(str, ledger_api_msg.transaction_receipt.ledger_id)\n        tx_receipt = cast(JSONLike, ledger_api_msg.transaction_receipt.receipt)\n\n        is_transaction_successful = LedgerApis.is_transaction_settled(\n            ledger_api_msg.transaction_receipt.ledger_id,\n            ledger_api_msg.transaction_receipt.receipt,\n        )\n        if is_transaction_successful:\n            self.context.logger.info(\n                \"transaction was successfully settled. Transaction receipt={}\".format(\n                    ledger_api_msg.transaction_receipt\n                )\n            )\n            strategy = cast(Strategy, self.context.strategy)\n\n            contract_api_dialogue = (\n                ledger_api_dialogue.associated_signing_dialogue.associated_contract_api_dialogue\n            )\n\n            transaction_label = contract_api_dialogue.terms.kwargs.get(\"label\", \"None\")\n\n            if not strategy.is_client_contract_deployed:\n                if transaction_label == \"store\":\n                    self._request_init_transaction(ledger_id, tx_receipt)\n                elif transaction_label in {\"deploy\", \"init\"}:\n                    client_contract_address = LedgerApis.get_contract_address(\n                        ledger_id, tx_receipt\n                    )\n                    if client_contract_address is None:\n                        raise ValueError(\n                            \"No contract address found.\"\n                        )  # pragma: nocover\n                    strategy.client_contract_address = client_contract_address\n                    strategy.is_client_contract_deployed = True\n                    self.context.logger.info(\n                        f\"Oracle client contract successfully deployed at address: {client_contract_address}\"\n                    )\n                else:\n                    self.context.logger.error(\n                        f\"Invalid transaction label: {transaction_label}\"\n                    )  # pragma: nocover\n            elif (\n                not strategy.is_oracle_transaction_approved\n                and transaction_label == \"approve\"\n            ):\n                strategy.is_oracle_transaction_approved = is_transaction_successful\n                if is_transaction_successful:\n                    self.context.logger.info(\"Oracle client transactions approved!\")\n                else:  # pragma: nocover\n                    self.context.logger.info(\n                        \"Failed to approve oracle client transactions\"\n                    )\n            elif transaction_label == \"query\":\n                self.context.logger.info(\"Oracle value successfully requested!\")\n            else:  # pragma nocover\n                self.context.logger.error(\"unexpected transaction receipt!\")\n        else:\n            self.context.logger.error(\n                \"transaction failed. Transaction receipt={}\".format(\n                    ledger_api_msg.transaction_receipt\n                )\n            )\n\n    def _handle_error(\n        self, ledger_api_msg: LedgerApiMessage, ledger_api_dialogue: LedgerApiDialogue\n    ) -> None:\n        \"\"\"\n        Handle a message of error performative.\n\n        :param ledger_api_msg: the ledger api message\n        :param ledger_api_dialogue: the ledger api dialogue\n        \"\"\"\n        self.context.logger.info(\n            \"received ledger_api error message={} in dialogue={}.\".format(\n                ledger_api_msg, ledger_api_dialogue\n            )\n        )\n\n    def _handle_invalid(\n        self, ledger_api_msg: LedgerApiMessage, ledger_api_dialogue: LedgerApiDialogue\n    ) -> None:\n        \"\"\"\n        Handle a message of invalid performative.\n\n        :param ledger_api_msg: the ledger api message\n        :param ledger_api_dialogue: the ledger api dialogue\n        \"\"\"\n        self.context.logger.warning(\n            \"cannot handle ledger_api message of performative={} in dialogue={}.\".format(\n                ledger_api_msg.performative,\n                ledger_api_dialogue,\n            )\n        )\n\n\nclass ContractApiHandler(Handler):\n    \"\"\"Implement the contract api handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = ContractApiMessage.protocol_id  # type: Optional[PublicId]\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup for the handler.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to a message.\n\n        :param message: the message\n        \"\"\"\n\n        self.context.logger.info(\"Handling contract api msg\")\n\n        contract_api_msg = cast(ContractApiMessage, message)\n\n        # recover dialogue\n        contract_api_dialogues = cast(\n            ContractApiDialogues, self.context.contract_api_dialogues\n        )\n        contract_api_dialogue = cast(\n            Optional[ContractApiDialogue],\n            contract_api_dialogues.update(contract_api_msg),\n        )\n        if contract_api_dialogue is None:\n            self._handle_unidentified_dialogue(contract_api_msg)\n            return\n\n        # handle message\n        if (\n            contract_api_msg.performative\n            is ContractApiMessage.Performative.RAW_TRANSACTION\n        ):\n            self._handle_raw_transaction(contract_api_msg, contract_api_dialogue)\n        elif contract_api_msg.performative == ContractApiMessage.Performative.ERROR:\n            self._handle_error(contract_api_msg, contract_api_dialogue)\n        else:\n            self._handle_invalid(contract_api_msg, contract_api_dialogue)\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n\n    def _handle_unidentified_dialogue(\n        self, contract_api_msg: ContractApiMessage\n    ) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param contract_api_msg: the message\n        \"\"\"\n        self.context.logger.info(\n            \"received invalid contract_api message={}, unidentified dialogue.\".format(\n                contract_api_msg\n            )\n        )\n\n    def _handle_raw_transaction(\n        self,\n        contract_api_msg: ContractApiMessage,\n        contract_api_dialogue: ContractApiDialogue,\n    ) -> None:\n        \"\"\"\n        Handle a message of raw_transaction performative.\n\n        :param contract_api_msg: the ledger api message\n        :param contract_api_dialogue: the ledger api dialogue\n        \"\"\"\n        self.context.logger.info(\"received raw transaction={}\".format(contract_api_msg))\n        signing_dialogues = cast(SigningDialogues, self.context.signing_dialogues)\n        signing_msg, signing_dialogue = signing_dialogues.create(\n            counterparty=self.context.decision_maker_address,\n            performative=SigningMessage.Performative.SIGN_TRANSACTION,\n            raw_transaction=contract_api_msg.raw_transaction,\n            terms=contract_api_dialogue.terms,\n        )\n        signing_dialogue = cast(SigningDialogue, signing_dialogue)\n        signing_dialogue.associated_contract_api_dialogue = contract_api_dialogue\n        self.context.decision_maker_message_queue.put_nowait(signing_msg)\n        self.context.logger.info(\n            \"proposing the transaction to the decision maker. Waiting for confirmation ...\"\n        )\n\n    def _handle_error(\n        self,\n        contract_api_msg: ContractApiMessage,\n        contract_api_dialogue: ContractApiDialogue,\n    ) -> None:\n        \"\"\"\n        Handle a message of error performative.\n\n        :param contract_api_msg: the ledger api message\n        :param contract_api_dialogue: the ledger api dialogue\n        \"\"\"\n        self.context.logger.info(\n            \"received ledger_api error message={} in dialogue={}.\".format(\n                contract_api_msg, contract_api_dialogue\n            )\n        )\n\n    def _handle_invalid(\n        self,\n        contract_api_msg: ContractApiMessage,\n        contract_api_dialogue: ContractApiDialogue,\n    ) -> None:\n        \"\"\"\n        Handle a message of invalid performative.\n\n        :param contract_api_msg: the ledger api message\n        :param contract_api_dialogue: the ledger api dialogue\n        \"\"\"\n        self.context.logger.warning(\n            \"cannot handle contract_api message of performative={} in dialogue={}.\".format(\n                contract_api_msg.performative,\n                contract_api_dialogue,\n            )\n        )\n\n\nclass SigningHandler(Handler):\n    \"\"\"Implement the transaction handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = SigningMessage.protocol_id  # type: Optional[PublicId]\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup for the handler.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to a message.\n\n        :param message: the message\n        \"\"\"\n        signing_msg = cast(SigningMessage, message)\n\n        # recover dialogue\n        signing_dialogues = cast(SigningDialogues, self.context.signing_dialogues)\n        signing_dialogue = cast(\n            Optional[SigningDialogue], signing_dialogues.update(signing_msg)\n        )\n        if signing_dialogue is None:\n            self._handle_unidentified_dialogue(signing_msg)\n            return\n\n        # handle message\n        if signing_msg.performative is SigningMessage.Performative.SIGNED_TRANSACTION:\n            self._handle_signed_transaction(signing_msg, signing_dialogue)\n        elif signing_msg.performative is SigningMessage.Performative.ERROR:\n            self._handle_error(signing_msg, signing_dialogue)\n        else:\n            self._handle_invalid(signing_msg, signing_dialogue)\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n\n    def _handle_unidentified_dialogue(self, signing_msg: SigningMessage) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param signing_msg: the message\n        \"\"\"\n        self.context.logger.info(\n            \"received invalid signing message={}, unidentified dialogue.\".format(\n                signing_msg\n            )\n        )\n\n    def _handle_signed_transaction(\n        self, signing_msg: SigningMessage, signing_dialogue: SigningDialogue\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param signing_msg: the signing message\n        :param signing_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.info(\"transaction signing was successful.\")\n        ledger_api_dialogues = cast(\n            LedgerApiDialogues, self.context.ledger_api_dialogues\n        )\n        ledger_api_msg, ledger_api_dialogue = ledger_api_dialogues.create(\n            counterparty=str(LEDGER_API_ADDRESS),\n            performative=LedgerApiMessage.Performative.SEND_SIGNED_TRANSACTION,\n            signed_transaction=signing_msg.signed_transaction,\n        )\n        ledger_api_dialogue = cast(LedgerApiDialogue, ledger_api_dialogue)\n        ledger_api_dialogue.associated_signing_dialogue = signing_dialogue\n        self.context.outbox.put_message(message=ledger_api_msg)\n        self.context.logger.info(\"sending transaction to ledger.\")\n\n    def _handle_error(\n        self, signing_msg: SigningMessage, signing_dialogue: SigningDialogue\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param signing_msg: the signing message\n        :param signing_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.info(\n            \"transaction signing was not successful. Error_code={} in dialogue={}\".format(\n                signing_msg.error_code, signing_dialogue\n            )\n        )\n\n    def _handle_invalid(\n        self, signing_msg: SigningMessage, signing_dialogue: SigningDialogue\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param signing_msg: the signing message\n        :param signing_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.warning(\n            \"cannot handle signing message of performative={} in dialogue={}.\".format(\n                signing_msg.performative, signing_dialogue\n            )\n        )\n"
  },
  {
    "path": "packages/fetchai/skills/simple_oracle_client/skill.yaml",
    "content": "name: simple_oracle_client\nauthor: fetchai\nversion: 0.13.5\ntype: skill\ndescription: This skill deploys a Fetch oracle client contract and calls this contract\n  to request an oracle value\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: QmeP17RSTejkr3mmh4UsMFN6H6L8XL2a6EsdEaKQshgXJW\n  __init__.py: QmYnEMkY229Cf6phe8QpcpaNGRMX4HJcLxGTQykHjQp4Mz\n  behaviours.py: QmafcEseTDXqwTHoPF41PSaFT7reEuV2ZUsrXH26L1dNey\n  dialogues.py: QmZJwtbs31WczMtXCK9jfaxh29mohBEY7YdRQ4zaReD2mF\n  handlers.py: QmdHoVdCbSEzDx6ASD4hjdRm742cQPn6d1YCJbe3T3cX3W\n  strategy.py: QmYmPZwE1zDLvbnv8K18b9GbW9jBW7YS9gZB2tEifmzWnT\nfingerprint_ignore_patterns: []\ncontracts:\n- fetchai/fet_erc20:0.9.2\n- fetchai/oracle_client:0.11.3\nprotocols:\n- fetchai/contract_api:1.1.7\n- fetchai/default:1.1.7\n- fetchai/ledger_api:1.1.7\n- fetchai/signing:1.1.7\nskills: []\nbehaviours:\n  simple_oracle_client_behaviour:\n    args:\n      query_interval: 15\n    class_name: SimpleOracleClientBehaviour\nhandlers:\n  contract_api:\n    args: {}\n    class_name: ContractApiHandler\n  ledger_api:\n    args: {}\n    class_name: LedgerApiHandler\n  signing:\n    args: {}\n    class_name: SigningHandler\nmodels:\n  contract_api_dialogues:\n    args: {}\n    class_name: ContractApiDialogues\n  ledger_api_dialogues:\n    args: {}\n    class_name: LedgerApiDialogues\n  signing_dialogues:\n    args: {}\n    class_name: SigningDialogues\n  strategy:\n    args:\n      approve_amount: 1000000000000000000\n      client_contract_address: null\n      erc20_address: null\n      gas_limit_approve: 300000\n      gas_limit_deploy: 1500000\n      gas_limit_instantiate: 500000\n      gas_limit_query: 500000\n      gas_price: 1000000000\n      ledger_id: null\n      oracle_contract_address: null\n      query_function: null\n      query_oracle_fee: 1000000000000\n    class_name: Strategy\ndependencies:\n  aea-ledger-ethereum:\n    version: <2.0.0,>=1.0.0\n  aea-ledger-fetchai:\n    version: <2.0.0,>=1.0.0\nis_abstract: false\nconnections: []\n"
  },
  {
    "path": "packages/fetchai/skills/simple_oracle_client/strategy.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the strategy class.\"\"\"\nfrom typing import Any\n\nfrom aea_ledger_ethereum import EthereumApi\n\nfrom aea.configurations.constants import DEFAULT_LEDGER\nfrom aea.exceptions import enforce\nfrom aea.helpers.transaction.base import Terms\nfrom aea.skills.base import Model\n\nfrom packages.fetchai.protocols.contract_api.custom_types import Kwargs\n\n\nDEFAULT_LEDGER_ID = DEFAULT_LEDGER\nMAX_BLOCK_HEIGHT = 1000000000000000000\n\n\nclass Strategy(Model):\n    \"\"\"This class defines a strategy for the agent.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"Initialize the strategy of the agent.\"\"\"\n        self._ledger_id = kwargs.pop(\"ledger_id\", DEFAULT_LEDGER_ID)\n        self._oracle_contract_address = kwargs.pop(\"oracle_contract_address\", None)\n        self._client_contract_address = kwargs.pop(\"client_contract_address\", None)\n        self._erc20_address = kwargs.pop(\"erc20_address\", None)\n        self._query_function = kwargs.pop(\"query_function\", None)\n        self._query_oracle_fee = kwargs.pop(\"query_oracle_fee\", 0)\n        self._gas_limit_deploy = kwargs.pop(\"gas_limit_deploy\", 0)\n        self._gas_limit_instantiate = kwargs.pop(\"gas_limit_instantiate\", 0)\n        self._gas_limit_query = kwargs.pop(\"gas_limit_query\", 0)\n        self._gas_limit_approve = kwargs.pop(\"gas_limit_approve\", 0)\n        self._gas_price = kwargs.pop(\"gas_price\", 0)\n        self._approve_amount = kwargs.pop(\"approve_amount\", 0)\n\n        super().__init__(**kwargs)\n\n        self.is_behaviour_active = True\n        self._is_oracle_contract_set = self._oracle_contract_address is not None\n        self._is_client_contract_deployed = self._client_contract_address is not None\n        self._is_oracle_transaction_approved = False\n\n    @property\n    def ledger_id(self) -> str:\n        \"\"\"Get the ledger id.\"\"\"\n        return self._ledger_id\n\n    @property\n    def query_function(self) -> str:\n        \"\"\"Get the name of the oracle value query function.\"\"\"\n        return self._query_function\n\n    @property\n    def query_oracle_fee(self) -> str:\n        \"\"\"Get the fee amount for querying the oracle contract.\"\"\"\n        return self._query_oracle_fee\n\n    @property\n    def gas_limit_instantiate(self) -> int:\n        \"\"\"Get the default gas for instantiating a contract.\"\"\"\n        return self._gas_limit_instantiate\n\n    @property\n    def gas_limit_deploy(self) -> int:\n        \"\"\"Get the default gas for deploying a contract.\"\"\"\n        return self._gas_limit_deploy\n\n    @property\n    def gas_limit_query(self) -> int:\n        \"\"\"Get the default gas for querying oracle value.\"\"\"\n        return self._gas_limit_query\n\n    @property\n    def gas_limit_approve(self) -> int:\n        \"\"\"Get the default gas for querying oracle value.\"\"\"\n        return self._gas_limit_query\n\n    @property\n    def gas_price(self) -> int:\n        \"\"\"Get the gas price.\"\"\"\n        return self._gas_price\n\n    @property\n    def approve_amount(self) -> str:\n        \"\"\"Get the amount of tokens to approve for spending by the client contract.\"\"\"\n        return self._approve_amount\n\n    @property\n    def oracle_contract_address(self) -> str:\n        \"\"\"Get the oracle contract address.\"\"\"\n        if self._oracle_contract_address is None:  # pragma: nocover\n            raise ValueError(\"Oracle contract address not set!\")\n        return self._oracle_contract_address\n\n    @oracle_contract_address.setter\n    def oracle_contract_address(self, oracle_contract_address: str) -> None:\n        \"\"\"Set the oracle contract address.\"\"\"\n        enforce(\n            self._oracle_contract_address is None,\n            \"Oracle contract address already set!\",\n        )\n        self._oracle_contract_address = oracle_contract_address\n\n    @property\n    def client_contract_address(self) -> str:\n        \"\"\"Get the client contract address.\"\"\"\n        if self._client_contract_address is None:  # pragma: nocover\n            raise ValueError(\"Oracle client contract address not set!\")\n        return self._client_contract_address\n\n    @client_contract_address.setter\n    def client_contract_address(self, client_contract_address: str) -> None:\n        \"\"\"Set the oracle client contract address.\"\"\"\n        enforce(\n            self._client_contract_address is None,\n            \"Oracle client contract address already set!\",\n        )\n        self._client_contract_address = client_contract_address\n\n    @property\n    def erc20_address(self) -> str:\n        \"\"\"Get the erc20 address for token payment.\"\"\"\n        if self._erc20_address is None:  # pragma: nocover\n            raise ValueError(\"ERC20 address not set!\")\n        return self._erc20_address\n\n    @erc20_address.setter\n    def erc20_address(self, erc20_address: str) -> None:\n        \"\"\"Set the erc20 address for token payment.\"\"\"\n        enforce(self._erc20_address is None, \"ERC20 address already set!\")\n        self._erc20_address = erc20_address\n\n    @property\n    def is_oracle_contract_set(self) -> bool:\n        \"\"\"Get oracle contract status.\"\"\"\n        return self._is_oracle_contract_set\n\n    @is_oracle_contract_set.setter\n    def is_oracle_contract_set(self, is_oracle_contract_set: bool) -> None:\n        \"\"\"Set oracle contract status.\"\"\"\n        enforce(\n            not self._is_oracle_contract_set and is_oracle_contract_set,\n            \"Only allowed to switch to true.\",\n        )\n        self._is_oracle_contract_set = is_oracle_contract_set\n\n    @property\n    def is_oracle_transaction_approved(self) -> bool:\n        \"\"\"Get oracle transaction approval status.\"\"\"\n        return self._is_oracle_transaction_approved\n\n    @is_oracle_transaction_approved.setter\n    def is_oracle_transaction_approved(\n        self, is_oracle_transaction_approved: bool\n    ) -> None:\n        \"\"\"Set oracle transaction approval status.\"\"\"\n        enforce(\n            not self._is_oracle_transaction_approved and is_oracle_transaction_approved,\n            \"Only allowed to switch to true.\",\n        )\n        self._is_oracle_transaction_approved = is_oracle_transaction_approved\n\n    @property\n    def is_client_contract_deployed(self) -> bool:\n        \"\"\"Get oracle contract status.\"\"\"\n        return self._is_client_contract_deployed\n\n    @is_client_contract_deployed.setter\n    def is_client_contract_deployed(self, is_client_contract_deployed: bool) -> None:\n        \"\"\"Set client contract deploy status.\"\"\"\n        enforce(\n            not self._is_client_contract_deployed and is_client_contract_deployed,\n            \"Only allowed to switch to true.\",\n        )\n        self._is_client_contract_deployed = is_client_contract_deployed\n\n    def get_deploy_terms(self, is_init_transaction: bool = False) -> Terms:\n        \"\"\"\n        Get terms of deployment.\n\n        :param is_init_transaction: whether the transaction is init or store.\n        :return: terms\n        \"\"\"\n        if self.ledger_id == EthereumApi.identifier:\n            label = \"deploy\"\n        else:\n            if is_init_transaction:\n                label = \"init\"\n            else:\n                label = \"store\"\n\n        terms = Terms(\n            ledger_id=self.ledger_id,\n            sender_address=self.context.agent_address,\n            counterparty_address=self.context.agent_address,\n            amount_by_currency_id={},\n            quantities_by_good_id={},\n            nonce=\"\",\n            label=label,\n        )\n        return terms\n\n    def get_query_terms(self) -> Terms:\n        \"\"\"\n        Get terms of query transaction.\n\n        :return: terms\n        \"\"\"\n        terms = Terms(\n            ledger_id=self.ledger_id,\n            sender_address=self.context.agent_address,\n            counterparty_address=self.context.agent_address,\n            amount_by_currency_id={},\n            quantities_by_good_id={},\n            nonce=\"\",\n            label=\"query\",\n        )\n        return terms\n\n    def get_approve_terms(self) -> Terms:\n        \"\"\"\n        Get terms of approve transaction.\n\n        :return: terms\n        \"\"\"\n        terms = Terms(\n            ledger_id=self.ledger_id,\n            sender_address=self.context.agent_address,\n            counterparty_address=self.context.agent_address,\n            amount_by_currency_id={},\n            quantities_by_good_id={},\n            nonce=\"\",\n            label=\"approve\",\n        )\n        return terms\n\n    def get_deploy_kwargs(self) -> Kwargs:\n        \"\"\"\n        Get kwargs for the contract deployment\n\n        :return: kwargs\n        \"\"\"\n        if self.ledger_id == EthereumApi.identifier:\n            kwargs = Kwargs(\n                {\n                    \"deployer_address\": self.context.agent_address,\n                    \"fetchOracleContractAddress\": self.oracle_contract_address,\n                    \"gas\": self.gas_limit_deploy,\n                }\n            )\n        else:\n            kwargs = Kwargs(\n                {\n                    \"deployer_address\": self.context.agent_address,\n                    \"gas\": self.gas_limit_deploy,\n                    \"tx_fee\": self.gas_price * self.gas_limit_deploy,\n                }\n            )\n        return kwargs\n"
  },
  {
    "path": "packages/fetchai/skills/simple_seller/README.md",
    "content": "# Simple Seller\n\n## Description\n\nThis skill is used to sell data present in the shared state.\n\n## Behaviours\n\n- `service_registration`: registers data selling service on the sOEF\n\n## Handlers\n\n- `fipa`: handles `fipa` messages for negotiation\n- `ledger_api`: handles `ledger_api` messages for interacting with a ledger\n- `oef_search`: handles `oef_search` messages if service registration on the sOEF is unsuccessful\n\n## Models\n\n- the `strategy` model is extended from the `fetchai/generic_seller` skill and loads data from the shared state using the key `shared_state_key` specified in the skill configuration.\n"
  },
  {
    "path": "packages/fetchai/skills/simple_seller/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the implementation of the simple_seller skill.\"\"\"\n\nfrom aea.configurations.base import PublicId\n\n\nPUBLIC_ID = PublicId.from_str(\"fetchai/simple_seller:0.14.6\")\n"
  },
  {
    "path": "packages/fetchai/skills/simple_seller/behaviours.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains a service registration behaviour (reused from generic_seller skill).\"\"\"\n\nfrom packages.fetchai.skills.generic_seller.behaviours import (\n    GenericServiceRegistrationBehaviour,\n)\n\n\nServiceRegistrationBehaviour = GenericServiceRegistrationBehaviour\n"
  },
  {
    "path": "packages/fetchai/skills/simple_seller/dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nThis module contains the classes required for dialogue management (reused from generic_seller skill).\n\n- DefaultDialogues: The dialogues class keeps track of all dialogues of type default.\n- FipaDialogues: The dialogues class keeps track of all dialogues of type fipa.\n- LedgerApiDialogues: The dialogues class keeps track of all dialogues of type ledger_api.\n- OefSearchDialogues: The dialogues class keeps track of all dialogues of type oef_search.\n\"\"\"\n\nfrom packages.fetchai.skills.generic_seller.dialogues import (\n    DefaultDialogues as GenericDefaultDialogues,\n)\nfrom packages.fetchai.skills.generic_seller.dialogues import (\n    FipaDialogues as GenericFipaDialogues,\n)\nfrom packages.fetchai.skills.generic_seller.dialogues import (\n    LedgerApiDialogues as GenericLedgerApiDialogues,\n)\nfrom packages.fetchai.skills.generic_seller.dialogues import (\n    OefSearchDialogues as GenericOefSearchDialogues,\n)\n\n\nDefaultDialogues = GenericDefaultDialogues\nFipaDialogues = GenericFipaDialogues\nLedgerApiDialogues = GenericLedgerApiDialogues\nOefSearchDialogues = GenericOefSearchDialogues\n"
  },
  {
    "path": "packages/fetchai/skills/simple_seller/handlers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains handlers (reused from the generic_seller skill).\"\"\"\n\nfrom packages.fetchai.skills.generic_seller.handlers import (\n    GenericFipaHandler,\n    GenericLedgerApiHandler,\n    GenericOefSearchHandler,\n)\n\n\nFipaHandler = GenericFipaHandler\nLedgerApiHandler = GenericLedgerApiHandler\nOefSearchHandler = GenericOefSearchHandler\n"
  },
  {
    "path": "packages/fetchai/skills/simple_seller/skill.yaml",
    "content": "name: simple_seller\nauthor: fetchai\nversion: 0.14.6\ntype: skill\ndescription: The simple_seller skill extends the generic_seller skill and sells data\n  from the shared state of the AEA.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: QmcBRmTneLHvBfHcw4ZfVKkMw8cZFbvHdmAactNhNrd4HU\n  __init__.py: QmQztRLPBQZyWCZmW1ZBpgSTz3JFSnBt6dCYTpTBYsrUhr\n  behaviours.py: QmPjoQS4RdWpsmhh2xabtW3MDRAdRch4J2MMe8MdpSGFYp\n  dialogues.py: QmSY1VNCShSjiVuwToNvu7k5pfYEXiHjRQP5fHRkrx8UHz\n  handlers.py: QmZhWji4oE5odDoxJbWhrMS9yzj42nKhBfwM3KgG5GnrdA\n  strategy.py: QmUdEa63iofjreKba2oQc3CkACV6PYyevmTTyiit6pWnij\nfingerprint_ignore_patterns: []\nconnections:\n- fetchai/ledger:0.21.5\ncontracts: []\nprotocols:\n- fetchai/default:1.1.7\n- fetchai/fipa:1.1.7\n- fetchai/ledger_api:1.1.7\n- fetchai/oef_search:1.1.7\nskills:\n- fetchai/generic_seller:0.28.6\nbehaviours:\n  service_registration:\n    args:\n      services_interval: 20\n    class_name: ServiceRegistrationBehaviour\nhandlers:\n  fipa:\n    args: {}\n    class_name: FipaHandler\n  ledger_api:\n    args: {}\n    class_name: LedgerApiHandler\n  oef_search:\n    args: {}\n    class_name: OefSearchHandler\nmodels:\n  default_dialogues:\n    args: {}\n    class_name: DefaultDialogues\n  fipa_dialogues:\n    args: {}\n    class_name: FipaDialogues\n  ledger_api_dialogues:\n    args: {}\n    class_name: LedgerApiDialogues\n  oef_search_dialogues:\n    args: {}\n    class_name: OefSearchDialogues\n  strategy:\n    args:\n      classification:\n        piece: classification\n        value: seller\n      has_data_source: true\n      is_ledger_tx: true\n      location:\n        latitude: 51.5194\n        longitude: 0.127\n      personality_data:\n        piece: genus\n        value: data\n      service_data:\n        key: seller_service\n        value: weather_data\n      service_id: weather_data\n      shared_state_key: null\n      unit_price: 10\n    class_name: Strategy\ndependencies: {}\nis_abstract: false\n"
  },
  {
    "path": "packages/fetchai/skills/simple_seller/strategy.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the strategy class (extended from the generic_seller skill).\"\"\"\n\nimport json\nfrom typing import Any, Dict\n\nfrom packages.fetchai.skills.generic_seller.strategy import GenericStrategy\n\n\nclass Strategy(GenericStrategy):\n    \"\"\"This class defines a strategy for the agent.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize the strategy of the agent.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        self.shared_state_key = kwargs.pop(\"shared_state_key\", None)\n        if self.shared_state_key is None:\n            raise ValueError(\"No shared_state_key provided!\")\n        super().__init__(**kwargs)\n\n    def collect_from_data_source(self) -> Dict[str, str]:\n        \"\"\"\n        Build the data payload.\n\n        :return: a dict of the data found in the shared state.\n        \"\"\"\n        data = self.context.shared_state.get(self.shared_state_key, b\"{}\")\n        formatted_data = self._format_data(data)\n        return formatted_data\n\n    def _format_data(self, data: bytes) -> Dict[str, str]:\n        \"\"\"\n        Convert to dict.\n\n        :param data: the bytes data to format\n        :return: a dict with key and values as strings\n        \"\"\"\n        result: Dict[str, str] = {}\n        try:\n            loaded = json.loads(data)\n            if isinstance(loaded, dict) and all(\n                isinstance(key, str) and isinstance(value, str)\n                for key, value in loaded.items()\n            ):\n                result = loaded\n            else:\n                result = {\"data\": json.dumps(loaded)}\n        except json.decoder.JSONDecodeError as e:\n            self.context.logger.warning(f\"error when loading json: {e}\")\n        return result\n"
  },
  {
    "path": "packages/fetchai/skills/simple_service_registration/README.md",
    "content": "# Simple Service Registration\n\n## Description\n\nThis skill registers and unregisters an agent and service on the sOEF.\n\nThis skill is used in the \"Guide on Writing a Skill\" section in the documentation. On start, it registers an agent and its service on the sOEF, and on termination it unregisters the agent and its service from sOEF.\n\n## Behaviours\n\n- `service`: registers and unregisters a service on the sOEF\n\n## Handlers\n\n- `oef_search`: handles `oef_search` messages if interactions with the sOEF is erratic\n\n## Links\n\n- <a href=\"https://docs.fetch.ai/aea/skill-guide/\" target=\"_blank\">Guide on Building a Skill</a>\n"
  },
  {
    "path": "packages/fetchai/skills/simple_service_registration/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the implementation of the default skill.\"\"\"\n\nfrom aea.configurations.base import PublicId\n\n\nPUBLIC_ID = PublicId.from_str(\"fetchai/simple_service_registration:0.23.6\")\n"
  },
  {
    "path": "packages/fetchai/skills/simple_service_registration/behaviours.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains a simple behaviour to register a service.\"\"\"\n\nfrom typing import Any, Optional, cast\n\nfrom aea.helpers.search.models import Description\nfrom aea.skills.behaviours import TickerBehaviour\n\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.skills.simple_service_registration.dialogues import (\n    OefSearchDialogues,\n)\nfrom packages.fetchai.skills.simple_service_registration.strategy import Strategy\n\n\nDEFAULT_MAX_SOEF_REGISTRATION_RETRIES = 5\nDEFAULT_SERVICES_INTERVAL = 30.0\n\n\nclass ServiceRegistrationBehaviour(TickerBehaviour):\n    \"\"\"This class implements a behaviour.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"Initialise the behaviour.\"\"\"\n        services_interval = kwargs.pop(\n            \"services_interval\", DEFAULT_SERVICES_INTERVAL\n        )  # type: int\n        self._max_soef_registration_retries = kwargs.pop(\n            \"max_soef_registration_retries\", DEFAULT_MAX_SOEF_REGISTRATION_RETRIES\n        )  # type: int\n        super().__init__(tick_interval=services_interval, **kwargs)\n\n        self.failed_registration_msg = None  # type: Optional[OefSearchMessage]\n        self._nb_retries = 0\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup.\"\"\"\n        self._register_agent()\n\n    def act(self) -> None:\n        \"\"\"Implement the act.\"\"\"\n        self._retry_failed_registration()\n\n    def teardown(self) -> None:\n        \"\"\"Implement the task teardown.\"\"\"\n        self._unregister_service()\n        self._unregister_agent()\n\n    def _retry_failed_registration(self) -> None:\n        \"\"\"Retry a failed registration.\"\"\"\n        if self.failed_registration_msg is not None:\n            self._nb_retries += 1\n            if self._nb_retries > self._max_soef_registration_retries:\n                self.context.is_active = False\n                return\n\n            oef_search_dialogues = cast(\n                OefSearchDialogues, self.context.oef_search_dialogues\n            )\n            oef_search_msg, _ = oef_search_dialogues.create(\n                counterparty=self.failed_registration_msg.to,\n                performative=self.failed_registration_msg.performative,\n                service_description=self.failed_registration_msg.service_description,\n            )\n            self.context.outbox.put_message(message=oef_search_msg)\n            self.context.logger.info(\n                f\"Retrying registration on SOEF. Retry {self._nb_retries} out of {self._max_soef_registration_retries}.\"\n            )\n\n            self.failed_registration_msg = None\n\n    def _register(self, description: Description, logger_msg: str) -> None:\n        \"\"\"\n        Register something on the SOEF.\n\n        :param description: the description of what is being registered\n        :param logger_msg: the logger message to print after the registration\n        \"\"\"\n        oef_search_dialogues = cast(\n            OefSearchDialogues, self.context.oef_search_dialogues\n        )\n        oef_search_msg, _ = oef_search_dialogues.create(\n            counterparty=self.context.search_service_address,\n            performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n            service_description=description,\n        )\n        self.context.outbox.put_message(message=oef_search_msg)\n        self.context.logger.info(logger_msg)\n\n    def _register_agent(self) -> None:\n        \"\"\"Register the agent's location.\"\"\"\n        strategy = cast(Strategy, self.context.strategy)\n        description = strategy.get_location_description()\n        self._register(description, \"registering agent on SOEF.\")\n\n    def register_service(self) -> None:\n        \"\"\"Register the agent's service.\"\"\"\n        strategy = cast(Strategy, self.context.strategy)\n        description = strategy.get_register_service_description()\n        self._register(description, \"registering agent's service on the SOEF.\")\n\n    def register_genus(self) -> None:\n        \"\"\"Register the agent's personality genus.\"\"\"\n        strategy = cast(Strategy, self.context.strategy)\n        description = strategy.get_register_personality_description()\n        self._register(\n            description, \"registering agent's personality genus on the SOEF.\"\n        )\n\n    def register_classification(self) -> None:\n        \"\"\"Register the agent's personality classification.\"\"\"\n        strategy = cast(Strategy, self.context.strategy)\n        description = strategy.get_register_classification_description()\n        self._register(\n            description, \"registering agent's personality classification on the SOEF.\"\n        )\n\n    def _unregister_service(self) -> None:\n        \"\"\"Unregister service from the SOEF.\"\"\"\n        strategy = cast(Strategy, self.context.strategy)\n        description = strategy.get_unregister_service_description()\n        oef_search_dialogues = cast(\n            OefSearchDialogues, self.context.oef_search_dialogues\n        )\n        oef_search_msg, _ = oef_search_dialogues.create(\n            counterparty=self.context.search_service_address,\n            performative=OefSearchMessage.Performative.UNREGISTER_SERVICE,\n            service_description=description,\n        )\n        self.context.outbox.put_message(message=oef_search_msg)\n        self.context.logger.info(\"unregistering service from SOEF.\")\n\n    def _unregister_agent(self) -> None:\n        \"\"\"Unregister agent from the SOEF.\"\"\"\n        strategy = cast(Strategy, self.context.strategy)\n        description = strategy.get_location_description()\n        oef_search_dialogues = cast(\n            OefSearchDialogues, self.context.oef_search_dialogues\n        )\n        oef_search_msg, _ = oef_search_dialogues.create(\n            counterparty=self.context.search_service_address,\n            performative=OefSearchMessage.Performative.UNREGISTER_SERVICE,\n            service_description=description,\n        )\n        self.context.outbox.put_message(message=oef_search_msg)\n        self.context.logger.info(\"unregistering agent from SOEF.\")\n"
  },
  {
    "path": "packages/fetchai/skills/simple_service_registration/dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nThis module contains the classes required for dialogue management.\n\n- OefSearchDialogue: The dialogue class maintains state of a dialogue and manages it.\n- OefSearchDialogues: The dialogues class keeps track of all dialogues.\n\"\"\"\nfrom typing import Any\n\nfrom aea.protocols.base import Address, Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\nfrom aea.skills.base import Model\n\nfrom packages.fetchai.protocols.oef_search.dialogues import (\n    OefSearchDialogue as BaseOefSearchDialogue,\n)\nfrom packages.fetchai.protocols.oef_search.dialogues import (\n    OefSearchDialogues as BaseOefSearchDialogues,\n)\n\n\nOefSearchDialogue = BaseOefSearchDialogue\n\n\nclass OefSearchDialogues(Model, BaseOefSearchDialogues):\n    \"\"\"This class keeps track of all oef_search dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return BaseOefSearchDialogue.Role.AGENT\n\n        BaseOefSearchDialogues.__init__(\n            self,\n            self_address=str(self.skill_id),\n            role_from_first_message=role_from_first_message,\n        )\n"
  },
  {
    "path": "packages/fetchai/skills/simple_service_registration/handlers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains the handlers of a generic seller AEA.\"\"\"\n\nfrom typing import Optional, cast\n\nfrom aea.configurations.base import PublicId\nfrom aea.protocols.base import Message\nfrom aea.skills.base import Handler\n\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.skills.simple_service_registration.behaviours import (\n    ServiceRegistrationBehaviour,\n)\nfrom packages.fetchai.skills.simple_service_registration.dialogues import (\n    OefSearchDialogue,\n    OefSearchDialogues,\n)\n\n\nclass OefSearchHandler(Handler):\n    \"\"\"This class implements an OEF search handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = OefSearchMessage.protocol_id  # type: Optional[PublicId]\n\n    def setup(self) -> None:\n        \"\"\"Call to setup the handler.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to a message.\n\n        :param message: the message\n        \"\"\"\n        oef_search_msg = cast(OefSearchMessage, message)\n\n        # recover dialogue\n        oef_search_dialogues = cast(\n            OefSearchDialogues, self.context.oef_search_dialogues\n        )\n        oef_search_dialogue = cast(\n            Optional[OefSearchDialogue], oef_search_dialogues.update(oef_search_msg)\n        )\n        if oef_search_dialogue is None:\n            self._handle_unidentified_dialogue(oef_search_msg)\n            return\n\n        # handle message\n        if oef_search_msg.performative == OefSearchMessage.Performative.SUCCESS:\n            self._handle_success(oef_search_msg, oef_search_dialogue)\n        elif oef_search_msg.performative == OefSearchMessage.Performative.OEF_ERROR:\n            self._handle_error(oef_search_msg, oef_search_dialogue)\n        else:\n            self._handle_invalid(oef_search_msg, oef_search_dialogue)\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n\n    def _handle_unidentified_dialogue(self, oef_search_msg: OefSearchMessage) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param oef_search_msg: the message\n        \"\"\"\n        self.context.logger.info(\n            \"received invalid oef_search message={}, unidentified dialogue.\".format(\n                oef_search_msg\n            )\n        )\n\n    def _handle_success(\n        self,\n        oef_search_success_msg: OefSearchMessage,\n        oef_search_dialogue: OefSearchDialogue,\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param oef_search_success_msg: the oef search message\n        :param oef_search_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.info(\n            \"received oef_search success message={} in dialogue={}.\".format(\n                oef_search_success_msg, oef_search_dialogue\n            )\n        )\n        target_message = cast(\n            OefSearchMessage,\n            oef_search_dialogue.get_message_by_id(oef_search_success_msg.target),\n        )\n        if (\n            target_message.performative\n            == OefSearchMessage.Performative.REGISTER_SERVICE\n        ):\n            description = target_message.service_description\n            data_model_name = description.data_model.name\n            registration_behaviour = cast(\n                ServiceRegistrationBehaviour,\n                self.context.behaviours.service,\n            )\n            if \"location_agent\" in data_model_name:\n                registration_behaviour.register_service()\n            elif \"set_service_key\" in data_model_name:\n                registration_behaviour.register_genus()\n            elif (\n                \"personality_agent\" in data_model_name\n                and description.values[\"piece\"] == \"genus\"\n            ):\n                registration_behaviour.register_classification()\n            elif (\n                \"personality_agent\" in data_model_name\n                and description.values[\"piece\"] == \"classification\"\n            ):\n                self.context.logger.info(\n                    \"the agent, with its genus and classification, and its service are successfully registered on the SOEF.\"\n                )\n            else:\n                self.context.logger.warning(\n                    f\"received soef SUCCESS message as a reply to the following unexpected message: {target_message}\"\n                )\n\n    def _handle_error(\n        self,\n        oef_search_error_msg: OefSearchMessage,\n        oef_search_dialogue: OefSearchDialogue,\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param oef_search_error_msg: the oef search message\n        :param oef_search_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.info(\n            \"received oef_search error message={} in dialogue={}.\".format(\n                oef_search_error_msg, oef_search_dialogue\n            )\n        )\n        target_message = cast(\n            OefSearchMessage,\n            oef_search_dialogue.get_message_by_id(oef_search_error_msg.target),\n        )\n        if (\n            target_message.performative\n            == OefSearchMessage.Performative.REGISTER_SERVICE\n        ):\n            registration_behaviour = cast(\n                ServiceRegistrationBehaviour,\n                self.context.behaviours.service,\n            )\n            registration_behaviour.failed_registration_msg = target_message\n\n    def _handle_invalid(\n        self, oef_search_msg: OefSearchMessage, oef_search_dialogue: OefSearchDialogue\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param oef_search_msg: the oef search message\n        :param oef_search_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.warning(\n            \"cannot handle oef_search message of performative={} in dialogue={}.\".format(\n                oef_search_msg.performative,\n                oef_search_dialogue,\n            )\n        )\n"
  },
  {
    "path": "packages/fetchai/skills/simple_service_registration/skill.yaml",
    "content": "name: simple_service_registration\nauthor: fetchai\nversion: 0.23.6\ntype: skill\ndescription: The simple service registration skills is a skill to register a service.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: QmcAU3oi7tWS86UmAePbubQLinLutQsSQ1eGce5LperZty\n  __init__.py: QmTBYeERGsytUjBYUFCBCA55yuXaQSetGT235Zz8fbV16L\n  behaviours.py: QmWuomUzWYZXeshgbnnzzeC9xE3tNwJReGwCBtbqhMXcaY\n  dialogues.py: QmbgKy2b6WiWSFXxdwDaawAsoBY2VsBAdhRgUL6WTaGhEt\n  handlers.py: QmehzwbrYqX2VAoAzVC7754rdJFjYoNCs58R5oBu5ChnDq\n  strategy.py: QmcwQhz4RsqN35BiApeTDoyuggqXXooezW6HvsTx9ugXGj\nfingerprint_ignore_patterns: []\nconnections: []\ncontracts: []\nprotocols:\n- fetchai/oef_search:1.1.7\nskills: []\nbehaviours:\n  service:\n    args:\n      max_soef_registration_retries: 5\n      services_interval: 30\n    class_name: ServiceRegistrationBehaviour\nhandlers:\n  oef_search:\n    args: {}\n    class_name: OefSearchHandler\nmodels:\n  oef_search_dialogues:\n    args: {}\n    class_name: OefSearchDialogues\n  strategy:\n    args:\n      classification:\n        piece: classification\n        value: seller\n      location:\n        latitude: 51.5194\n        longitude: 0.127\n      personality_data:\n        piece: genus\n        value: data\n      service_data:\n        key: seller_service\n        value: generic_service\n    class_name: Strategy\ndependencies: {}\nis_abstract: false\n"
  },
  {
    "path": "packages/fetchai/skills/simple_service_registration/strategy.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains a strategy model.\"\"\"\n\nfrom typing import Any\n\nfrom aea.exceptions import enforce\nfrom aea.helpers.search.generic import (\n    AGENT_LOCATION_MODEL,\n    AGENT_PERSONALITY_MODEL,\n    AGENT_REMOVE_SERVICE_MODEL,\n    AGENT_SET_SERVICE_MODEL,\n)\nfrom aea.helpers.search.models import Description, Location\nfrom aea.skills.base import Model\n\n\nDEFAULT_LOCATION = {\"longitude\": 0.1270, \"latitude\": 51.5194}\nDEFAULT_SERVICE_DATA = {\"key\": \"seller_service\", \"value\": \"generic_service\"}\nDEFAULT_PERSONALITY_DATA = {\"piece\": \"genus\", \"value\": \"data\"}\nDEFAULT_CLASSIFICATION = {\"piece\": \"classification\", \"value\": \"seller\"}\n\n\nclass Strategy(Model):\n    \"\"\"This class defines a strategy for the agent.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize the strategy of the agent.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        location = kwargs.pop(\"location\", DEFAULT_LOCATION)\n        self._agent_location = {\n            \"location\": Location(\n                latitude=location[\"latitude\"], longitude=location[\"longitude\"]\n            )\n        }\n        self._set_personality_data = kwargs.pop(\n            \"personality_data\", DEFAULT_PERSONALITY_DATA\n        )\n        enforce(\n            len(self._set_personality_data) == 2\n            and \"piece\" in self._set_personality_data\n            and \"value\" in self._set_personality_data,\n            \"personality_data must contain keys `key` and `value`\",\n        )\n        self._set_classification = kwargs.pop(\"classification\", DEFAULT_CLASSIFICATION)\n        enforce(\n            len(self._set_classification) == 2\n            and \"piece\" in self._set_classification\n            and \"value\" in self._set_classification,\n            \"classification must contain keys `key` and `value`\",\n        )\n        self._set_service_data = kwargs.pop(\"service_data\", DEFAULT_SERVICE_DATA)\n        enforce(\n            len(self._set_service_data) == 2\n            and \"key\" in self._set_service_data\n            and \"value\" in self._set_service_data,\n            \"service_data must contain keys `key` and `value`\",\n        )\n        self._remove_service_data = {\"key\": self._set_service_data[\"key\"]}\n        super().__init__(**kwargs)\n\n    def get_location_description(self) -> Description:\n        \"\"\"\n        Get the location description.\n\n        :return: a description of the agent's location\n        \"\"\"\n        description = Description(\n            self._agent_location,\n            data_model=AGENT_LOCATION_MODEL,\n        )\n        return description\n\n    def get_register_service_description(self) -> Description:\n        \"\"\"\n        Get the register service description.\n\n        :return: a description of the offered services\n        \"\"\"\n        description = Description(\n            self._set_service_data,\n            data_model=AGENT_SET_SERVICE_MODEL,\n        )\n        return description\n\n    def get_register_personality_description(self) -> Description:\n        \"\"\"\n        Get the register personality description.\n\n        :return: a description of the personality\n        \"\"\"\n        description = Description(\n            self._set_personality_data,\n            data_model=AGENT_PERSONALITY_MODEL,\n        )\n        return description\n\n    def get_register_classification_description(self) -> Description:\n        \"\"\"\n        Get the register classification description.\n\n        :return: a description of the classification\n        \"\"\"\n        description = Description(\n            self._set_classification,\n            data_model=AGENT_PERSONALITY_MODEL,\n        )\n        return description\n\n    def get_unregister_service_description(self) -> Description:\n        \"\"\"\n        Get the unregister service description.\n\n        :return: a description of the to be removed service\n        \"\"\"\n        description = Description(\n            self._remove_service_data,\n            data_model=AGENT_REMOVE_SERVICE_MODEL,\n        )\n        return description\n"
  },
  {
    "path": "packages/fetchai/skills/simple_service_search/README.md",
    "content": "# Simple Service Search\n\n## Description\n\nThis skill searches for services on the sOEF.\n\n## Behaviours\n\n- `service_search`: sends search queries to the sOEF using the `oef_search` protocol.\n\n## Handlers\n\n- `oef_search`: handles `oef_search` messages, in particular search responses. Search results are stored in the shared state using the key `shared_storage_key`.\n\n## Models\n\n- `strategy`: builds the search query from the data provided in the skill configuration: `search_location`, `search_query` and `search_radius`.\n"
  },
  {
    "path": "packages/fetchai/skills/simple_service_search/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the implementation of the simple service search skill.\"\"\"\n\nfrom aea.configurations.base import PublicId\n\n\nPUBLIC_ID = PublicId.from_str(\"fetchai/simple_service_search:0.11.6\")\n"
  },
  {
    "path": "packages/fetchai/skills/simple_service_search/behaviours.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains a simple behaviour to search a service.\"\"\"\n\nfrom typing import cast\n\nfrom aea.skills.behaviours import TickerBehaviour\n\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.skills.simple_service_search.dialogues import OefSearchDialogues\nfrom packages.fetchai.skills.simple_service_search.strategy import Strategy\n\n\nclass ServiceSearchBehaviour(TickerBehaviour):\n    \"\"\"This class provides a simple search behaviour.\"\"\"\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup.\"\"\"\n\n    def act(self) -> None:\n        \"\"\"Implement the act.\"\"\"\n        strategy = cast(Strategy, self.context.strategy)\n        oef_search_dialogues = cast(\n            OefSearchDialogues, self.context.oef_search_dialogues\n        )\n        search_request, _ = oef_search_dialogues.create(\n            counterparty=self.context.search_service_address,\n            performative=OefSearchMessage.Performative.SEARCH_SERVICES,\n            query=strategy.get_query(),\n        )\n        self.context.logger.info(\"sending search request to OEF search node\")\n        self.context.outbox.put_message(message=search_request)\n\n    def teardown(self) -> None:\n        \"\"\"Implement the task teardown.\"\"\"\n"
  },
  {
    "path": "packages/fetchai/skills/simple_service_search/dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nThis module contains the classes required for dialogue management.\n\n- OefSearchDialogue: The dialogue class maintains state of a dialogue and manages it.\n- OefSearchDialogues: The dialogues class keeps track of all dialogues.\n\"\"\"\nfrom typing import Any\n\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\nfrom aea.skills.base import Address, Model\n\nfrom packages.fetchai.protocols.oef_search.dialogues import (\n    OefSearchDialogue as BaseOefSearchDialogue,\n)\nfrom packages.fetchai.protocols.oef_search.dialogues import (\n    OefSearchDialogues as BaseOefSearchDialogues,\n)\n\n\nOefSearchDialogue = BaseOefSearchDialogue\n\n\nclass OefSearchDialogues(Model, BaseOefSearchDialogues):\n    \"\"\"This class keeps track of all oef_search dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return BaseOefSearchDialogue.Role.AGENT\n\n        BaseOefSearchDialogues.__init__(\n            self,\n            self_address=str(self.skill_id),  # problem\n            role_from_first_message=role_from_first_message,\n        )\n"
  },
  {
    "path": "packages/fetchai/skills/simple_service_search/handlers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains the handlers of a simple service searching AEA.\"\"\"\n\nfrom typing import Optional, cast\n\nfrom aea.protocols.base import Message\nfrom aea.skills.base import Handler\n\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.skills.simple_service_search.dialogues import (\n    OefSearchDialogue,\n    OefSearchDialogues,\n)\nfrom packages.fetchai.skills.simple_service_search.strategy import Strategy\n\n\nclass OefSearchHandler(Handler):\n    \"\"\"This class provides a simple search handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = OefSearchMessage.protocol_id\n\n    def setup(self) -> None:\n        \"\"\"Set up the handler.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to a message.\n\n        :param message: the message\n        \"\"\"\n        oef_search_msg = cast(OefSearchMessage, message)\n\n        # recover dialogue\n        oef_search_dialogues = cast(\n            OefSearchDialogues, self.context.oef_search_dialogues\n        )\n        oef_search_dialogue = cast(\n            Optional[OefSearchDialogue], oef_search_dialogues.update(oef_search_msg)\n        )\n        if oef_search_dialogue is None:\n            self._handle_unidentified_dialogue(oef_search_msg)\n            return\n\n        # handle message\n        if oef_search_msg.performative is OefSearchMessage.Performative.OEF_ERROR:\n            self._handle_error(oef_search_msg, oef_search_dialogue)\n        elif oef_search_msg.performative is OefSearchMessage.Performative.SEARCH_RESULT:\n            self._handle_search(oef_search_msg)\n        else:\n            self._handle_invalid(oef_search_msg, oef_search_dialogue)\n\n    def _handle_unidentified_dialogue(self, oef_search_msg: OefSearchMessage) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param oef_search_msg: the message\n        \"\"\"\n        self.context.logger.info(\n            \"received invalid oef_search message={}, unidentified dialogue.\".format(\n                oef_search_msg\n            )\n        )\n\n    def _handle_error(\n        self, oef_search_msg: OefSearchMessage, oef_search_dialogue: OefSearchDialogue\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param oef_search_msg: the oef search message\n        :param oef_search_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.info(\n            \"received oef_search error message={} in dialogue={}.\".format(\n                oef_search_msg, oef_search_dialogue\n            )\n        )\n\n    def _handle_search(self, oef_search_msg: OefSearchMessage) -> None:\n        \"\"\"\n        Handle the search response.\n\n        :param oef_search_msg: the oef search message\n        \"\"\"\n        agents = list(oef_search_msg.agents)\n        nb_agents = len(agents)\n        if nb_agents == 0:\n            self.context.logger.info(\n                f\"no agents found, search_response={oef_search_msg}\"\n            )\n            return\n\n        strategy = cast(Strategy, self.context.strategy)\n        self.context.logger.info(\n            f\"found number of agents={nb_agents}, search_response={oef_search_msg}\"\n        )\n        if self.context.shared_state.get(strategy.shared_storage_key, None) is None:\n            self.context.shared_state[strategy.shared_storage_key] = set()\n        for agent in agents:\n            self.context.shared_state[strategy.shared_storage_key].add(agent)\n\n    def _handle_invalid(\n        self, oef_search_msg: OefSearchMessage, oef_search_dialogue: OefSearchDialogue\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param oef_search_msg: the oef search message\n        :param oef_search_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.warning(\n            \"cannot handle oef_search message of performative={} in dialogue={}.\".format(\n                oef_search_msg.performative,\n                oef_search_dialogue,\n            )\n        )\n\n    def teardown(self) -> None:\n        \"\"\"Teardown the handler.\"\"\"\n"
  },
  {
    "path": "packages/fetchai/skills/simple_service_search/skill.yaml",
    "content": "name: simple_service_search\nauthor: fetchai\nversion: 0.11.6\ntype: skill\ndescription: A simple search skill utilising the SOEF search node.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: Qme6VKFeMeJe4BjUEeqL1tTVisW4QUEFDu3PCgcHyUJWG8\n  __init__.py: QmcbnC34XeYwZkpeUXdBEoaD8NQ35xpzQ2VT2Y5tpXAxu6\n  behaviours.py: QmQVn5ASsL6fPgyvLJbKt9DHKaPRtQbtvNbj4L9Wk1zKr8\n  dialogues.py: QmazwDnVLDM3UsfDHPcamVWaipNVnNDAsRqTZe8vB6cXTn\n  handlers.py: Qmd8rkgUezaM9LbHmZnAp7Mn9uCGJ14WaCPgeMQF6QPWy7\n  strategy.py: QmZ6vRXXSMJgzFxgWT8rZcdxZ4oBuXbuWooGnfo8neWqr9\nfingerprint_ignore_patterns: []\nconnections: []\ncontracts: []\nprotocols:\n- fetchai/oef_search:1.1.7\nskills: []\nbehaviours:\n  service_search:\n    args:\n      tick_interval: 30\n    class_name: ServiceSearchBehaviour\nhandlers:\n  oef_search:\n    args: {}\n    class_name: OefSearchHandler\nmodels:\n  oef_search_dialogues:\n    args: {}\n    class_name: OefSearchDialogues\n  strategy:\n    args:\n      search_location:\n        latitude: 51.5194\n        longitude: 0.127\n      search_query:\n        constraint_type: ==\n        search_key: seller_service\n        search_value: generic_service\n      search_radius: 5.0\n      shared_storage_key: agents_found\n    class_name: Strategy\ndependencies: {}\nis_abstract: false\n"
  },
  {
    "path": "packages/fetchai/skills/simple_service_search/strategy.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains a strategy model.\"\"\"\n\nfrom typing import Any\n\nfrom aea.helpers.search.models import Constraint, ConstraintType, Location, Query\nfrom aea.skills.base import Model\n\n\nDEFAULT_SEARCH_LOCATION = {\"longitude\": 0.1270, \"latitude\": 51.5194}\nDEFAULT_SEARCH_QUERY = {\n    \"search_key\": \"seller_service\",\n    \"search_value\": \"generic_service\",\n    \"constraint_type\": \"==\",\n}\nDEFAULT_SEARCH_RADIUS = 5.0\nDEFAULT_SHARED_STORAGE_KEY = \"agents_found\"\n\n\nclass Strategy(Model):\n    \"\"\"This class defines a strategy for the agent.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize the strategy of the agent.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        self._search_query = kwargs.pop(\"search_query\", DEFAULT_SEARCH_QUERY)\n        location = kwargs.pop(\"search_location\", DEFAULT_SEARCH_LOCATION)\n        self._agent_location = Location(\n            latitude=location[\"latitude\"], longitude=location[\"longitude\"]\n        )\n        self._radius = kwargs.pop(\"search_radius\", DEFAULT_SEARCH_RADIUS)\n        self._shared_storage_key = kwargs.pop(\n            \"shared_storage_key\", DEFAULT_SHARED_STORAGE_KEY\n        )\n        super().__init__(**kwargs)\n\n    @property\n    def shared_storage_key(self) -> str:\n        \"\"\"Get shared storage key.\"\"\"\n        return self._shared_storage_key\n\n    def get_query(self) -> Query:\n        \"\"\"\n        Get the location description.\n\n        :return: a description of the agent's location\n        \"\"\"\n        close_to_my_service = Constraint(\n            \"location\", ConstraintType(\"distance\", (self._agent_location, self._radius))\n        )\n        service_key_filter = Constraint(\n            self._search_query[\"search_key\"],\n            ConstraintType(\n                self._search_query[\"constraint_type\"],\n                self._search_query[\"search_value\"],\n            ),\n        )\n        query = Query([close_to_my_service, service_key_filter])\n        return query\n"
  },
  {
    "path": "packages/fetchai/skills/tac_control/README.md",
    "content": "# TAC Control\n\n## Description\n\nThis is the skill for managing a TAC.\n\nThis skill is part of the Fetch.ai TAC demo. It manages the progression of the competition along its various stages.\n\n## Behaviours\n\n- `tac`: manages progression of the competition\n\n## Handlers\n\n- `tac`: handles `tac` messages for managing the competition\n- `oef`: handles `oef_search` messages if registration or unregistration on the sOEF is unsuccessful\n\n## Links\n\n- <a href=\"https://docs.fetch.ai/aea/tac-skills-contract/\" target=\"_blank\">TAC Demo</a>\n"
  },
  {
    "path": "packages/fetchai/skills/tac_control/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the implementation of the tac control skill.\"\"\"\n\nfrom aea.configurations.base import PublicId\n\n\nPUBLIC_ID = PublicId.from_str(\"fetchai/tac_control:0.25.6\")\n"
  },
  {
    "path": "packages/fetchai/skills/tac_control/behaviours.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains a the behaviours.\"\"\"\n\nimport datetime\nfrom typing import Any, Optional, cast\n\nfrom aea.helpers.search.models import Description\nfrom aea.skills.base import Behaviour\n\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.protocols.tac.message import TacMessage\nfrom packages.fetchai.skills.tac_control.dialogues import (\n    OefSearchDialogues,\n    TacDialogues,\n)\nfrom packages.fetchai.skills.tac_control.game import Game, Phase\nfrom packages.fetchai.skills.tac_control.parameters import Parameters\n\n\nDEFAULT_MAX_SOEF_REGISTRATION_RETRIES = 5\n\n\nclass TacBehaviour(Behaviour):\n    \"\"\"This class implements the TAC control behaviour.\"\"\"\n\n    def __init__(self, **kwargs: Any):\n        \"\"\"Instantiate the behaviour.\"\"\"\n        self._max_soef_registration_retries = kwargs.pop(\n            \"max_soef_registration_retries\", DEFAULT_MAX_SOEF_REGISTRATION_RETRIES\n        )  # type: int\n        super().__init__(**kwargs)\n        self._registered_description = None  # type: Optional[Description]\n        self.failed_registration_msg = None  # type: Optional[OefSearchMessage]\n        self._nb_retries = 0\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup.\"\"\"\n        self._register_agent()\n\n    def act(self) -> None:\n        \"\"\"Implement the act.\"\"\"\n        self._retry_failed_registration()\n\n        game = cast(Game, self.context.game)\n        parameters = cast(Parameters, self.context.parameters)\n        now = datetime.datetime.now()\n        if (\n            game.phase.value == Phase.PRE_GAME.value\n            and parameters.registration_start_time < now < parameters.start_time\n            and game.is_registered_agent\n        ):\n            game.phase = Phase.GAME_REGISTRATION\n            self._register_tac()\n            self.context.logger.info(\n                \"TAC open for registration until: {}\".format(parameters.start_time)\n            )\n        elif (\n            game.phase.value == Phase.GAME_REGISTRATION.value\n            and parameters.start_time < now < parameters.end_time\n        ):\n            if game.registration.nb_agents < parameters.min_nb_agents:\n                self._cancel_tac(game)\n                game.phase = Phase.POST_GAME\n                self._unregister_tac()\n            else:\n                game.phase = Phase.GAME_SETUP\n                game.create()\n                self._start_tac(game)\n                self._unregister_tac()\n                game.phase = Phase.GAME\n        elif game.phase.value == Phase.GAME.value and now > parameters.end_time:\n            self._cancel_tac(game)\n            game.phase = Phase.POST_GAME\n\n    def teardown(self) -> None:\n        \"\"\"Implement the task teardown.\"\"\"\n        self._unregister_tac()\n        self._unregister_agent()\n\n    def _retry_failed_registration(self) -> None:\n        \"\"\"Retry a failed registration.\"\"\"\n        if self.failed_registration_msg is not None:\n            self._nb_retries += 1\n            if self._nb_retries > self._max_soef_registration_retries:\n                self.context.is_active = False\n                return\n\n            oef_search_dialogues = cast(\n                OefSearchDialogues, self.context.oef_search_dialogues\n            )\n            oef_search_msg, _ = oef_search_dialogues.create(\n                counterparty=self.failed_registration_msg.to,\n                performative=self.failed_registration_msg.performative,\n                service_description=self.failed_registration_msg.service_description,\n            )\n            self.context.outbox.put_message(message=oef_search_msg)\n            self.context.logger.info(\n                f\"Retrying registration on SOEF. Retry {self._nb_retries} out of {self._max_soef_registration_retries}.\"\n            )\n\n            self.failed_registration_msg = None\n\n    def _register(self, description: Description, logger_msg: str) -> None:\n        \"\"\"\n        Register something on the SOEF.\n\n        :param description: the description of what is being registered\n        :param logger_msg: the logger message to print after the registration\n        \"\"\"\n        oef_search_dialogues = cast(\n            OefSearchDialogues, self.context.oef_search_dialogues\n        )\n        oef_search_msg, _ = oef_search_dialogues.create(\n            counterparty=self.context.search_service_address,\n            performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n            service_description=description,\n        )\n        self.context.outbox.put_message(message=oef_search_msg)\n        self.context.logger.info(logger_msg)\n\n    def _register_agent(self) -> None:\n        \"\"\"Register the agent's location.\"\"\"\n        game = cast(Game, self.context.game)\n        description = game.get_location_description()\n        self._register(description, \"registering agent on SOEF.\")\n\n    def register_genus(self) -> None:\n        \"\"\"Register the agent's personality genus.\"\"\"\n        game = cast(Game, self.context.game)\n        description = game.get_register_personality_description()\n        self._register(\n            description, \"registering agent's personality genus on the SOEF.\"\n        )\n\n    def register_classification(self) -> None:\n        \"\"\"Register the agent's personality classification.\"\"\"\n        game = cast(Game, self.context.game)\n        description = game.get_register_classification_description()\n        self._register(\n            description, \"registering agent's personality classification on the SOEF.\"\n        )\n\n    def _register_tac(self) -> None:\n        \"\"\"Register the agent's TAC controller service on the SOEF.\"\"\"\n        game = cast(Game, self.context.game)\n        description = game.get_register_tac_description()\n        self._register(description, \"registering TAC data model on SOEF.\")\n\n    def _unregister_tac(self) -> None:\n        \"\"\"Unregister from the OEF as a TAC controller agent.\"\"\"\n        game = cast(Game, self.context.game)\n        description = game.get_unregister_tac_description()\n        oef_search_dialogues = cast(\n            OefSearchDialogues, self.context.oef_search_dialogues\n        )\n        oef_search_msg, _ = oef_search_dialogues.create(\n            counterparty=self.context.search_service_address,\n            performative=OefSearchMessage.Performative.UNREGISTER_SERVICE,\n            service_description=description,\n        )\n        self.context.outbox.put_message(message=oef_search_msg)\n        self._registered_description = None\n        self.context.logger.info(\"unregistering TAC data model from SOEF.\")\n\n    def _unregister_agent(self) -> None:\n        \"\"\"Unregister agent from the SOEF.\"\"\"\n        game = cast(Game, self.context.game)\n        description = game.get_location_description()\n        oef_search_dialogues = cast(\n            OefSearchDialogues, self.context.oef_search_dialogues\n        )\n        oef_search_msg, _ = oef_search_dialogues.create(\n            counterparty=self.context.search_service_address,\n            performative=OefSearchMessage.Performative.UNREGISTER_SERVICE,\n            service_description=description,\n        )\n        self.context.outbox.put_message(message=oef_search_msg)\n        self.context.logger.info(\"unregistering agent from SOEF.\")\n\n    def _start_tac(self, game: Game) -> None:\n        \"\"\"\n        Create a game and send the game configuration to every registered agent.\n\n        :param game: the game\n        \"\"\"\n        count = len(game.conf.agent_addr_to_name)\n        participant_names = sorted(list(game.conf.agent_addr_to_name.values()))\n        self.context.logger.info(\n            f\"starting competition with {count} participants and list of participants: {participant_names}\"\n        )\n        self.context.logger.info(\n            \"started competition:\\n{}\".format(game.holdings_summary)\n        )\n        self.context.logger.info(\n            \"computed equilibrium:\\n{}\".format(game.equilibrium_summary)\n        )\n        tac_dialogues = cast(TacDialogues, self.context.tac_dialogues)\n        for agent_address in game.conf.agent_addr_to_name.keys():\n            _tac_dialogues = tac_dialogues.get_dialogues_with_counterparty(\n                agent_address\n            )\n            if len(_tac_dialogues) != 1:\n                raise ValueError(\"Error when retrieving dialogue.\")\n            tac_dialogue = _tac_dialogues[0]\n            last_msg = tac_dialogue.last_message\n            if last_msg is None:\n                raise ValueError(\"Error when retrieving last message.\")\n            agent_state = game.current_agent_states[agent_address]\n            info = (\n                {\"contract_address\": game.conf.contract_address}\n                if game.conf.has_contract_address\n                else {}\n            )\n            tac_msg = tac_dialogue.reply(\n                performative=TacMessage.Performative.GAME_DATA,\n                target_message=last_msg,\n                amount_by_currency_id=agent_state.amount_by_currency_id,\n                exchange_params_by_currency_id=agent_state.exchange_params_by_currency_id,\n                quantities_by_good_id=agent_state.quantities_by_good_id,\n                utility_params_by_good_id=agent_state.utility_params_by_good_id,\n                fee_by_currency_id=game.conf.fee_by_currency_id,\n                currency_id_to_name=game.conf.currency_id_to_name,\n                agent_addr_to_name=game.conf.agent_addr_to_name,\n                good_id_to_name=game.conf.good_id_to_name,\n                version_id=game.conf.version_id,\n                info=info,\n            )\n            self.context.outbox.put_message(message=tac_msg)\n            self.context.logger.debug(\n                \"sending game data to '{}': {}\".format(agent_address, str(tac_msg))\n            )\n\n    def _cancel_tac(self, game: Game) -> None:\n        \"\"\"\n        Notify agents that the TAC is cancelled.\n\n        :param game: the game\n        \"\"\"\n        self.context.logger.info(\"notifying agents that TAC is cancelled.\")\n        tac_dialogues = cast(TacDialogues, self.context.tac_dialogues)\n        for agent_address in game.registration.agent_addr_to_name.keys():\n            _tac_dialogues = tac_dialogues.get_dialogues_with_counterparty(\n                agent_address\n            )\n            if len(_tac_dialogues) != 1:\n                raise ValueError(\"Error when retrieving dialogue.\")\n            tac_dialogue = _tac_dialogues[0]\n            last_msg = tac_dialogue.last_message\n            if last_msg is None:  # pragma: nocover\n                raise ValueError(\"Error when retrieving last message.\")\n            tac_msg = tac_dialogue.reply(\n                performative=TacMessage.Performative.CANCELLED,\n            )\n            self.context.outbox.put_message(message=tac_msg)\n        if game.phase == Phase.GAME:\n            self.context.logger.info(\n                \"finished competition:\\n{}\".format(game.holdings_summary)\n            )\n            self.context.logger.info(\n                \"computed equilibrium:\\n{}\".format(game.equilibrium_summary)\n            )\n            self.context.is_active = False\n"
  },
  {
    "path": "packages/fetchai/skills/tac_control/dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nThis module contains the classes required for dialogue management.\n\n- DefaultDialogue: The dialogue class maintains state of a dialogue of type default and manages it.\n- DefaultDialogues: The dialogues class keeps track of all dialogues of type default.\n- OefSearchDialogue: The dialogue class maintains state of a dialogue of type oef_search and manages it.\n- OefSearchDialogues: The dialogues class keeps track of all dialogues of type oef_search.\n- TacDialogue: The dialogue class maintains state of a dialogue of type tac and manages it.\n- TacDialogues: The dialogues class keeps track of all dialogues of type tac.\n\"\"\"\nfrom typing import Any\n\nfrom aea.protocols.base import Address, Message\nfrom aea.protocols.dialogue.base import Dialogue\nfrom aea.skills.base import Model\n\nfrom packages.fetchai.protocols.default.dialogues import (\n    DefaultDialogue as BaseDefaultDialogue,\n)\nfrom packages.fetchai.protocols.default.dialogues import (\n    DefaultDialogues as BaseDefaultDialogues,\n)\nfrom packages.fetchai.protocols.oef_search.dialogues import (\n    OefSearchDialogue as BaseOefSearchDialogue,\n)\nfrom packages.fetchai.protocols.oef_search.dialogues import (\n    OefSearchDialogues as BaseOefSearchDialogues,\n)\nfrom packages.fetchai.protocols.tac.dialogues import TacDialogue as BaseTacDialogue\nfrom packages.fetchai.protocols.tac.dialogues import TacDialogues as BaseTacDialogues\n\n\nDefaultDialogue = BaseDefaultDialogue\n\n\nclass DefaultDialogues(Model, BaseDefaultDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> Dialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return DefaultDialogue.Role.AGENT\n\n        BaseDefaultDialogues.__init__(\n            self,\n            self_address=self.context.agent_address,\n            role_from_first_message=role_from_first_message,\n        )\n\n\nOefSearchDialogue = BaseOefSearchDialogue\n\n\nclass OefSearchDialogues(Model, BaseOefSearchDialogues):\n    \"\"\"This class keeps track of all oef_search dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> Dialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return BaseOefSearchDialogue.Role.AGENT\n\n        BaseOefSearchDialogues.__init__(\n            self,\n            self_address=str(self.skill_id),\n            role_from_first_message=role_from_first_message,\n        )\n\n\nTacDialogue = BaseTacDialogue\n\n\nclass TacDialogues(Model, BaseTacDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> Dialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return TacDialogue.Role.CONTROLLER\n\n        BaseTacDialogues.__init__(\n            self,\n            self_address=self.context.agent_address,\n            role_from_first_message=role_from_first_message,\n        )\n"
  },
  {
    "path": "packages/fetchai/skills/tac_control/game.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains a class representing the game.\"\"\"\n\nimport copy\nimport datetime\nimport pprint\nfrom enum import Enum\nfrom typing import Any, Dict, List, Optional, cast\n\nfrom aea.common import Address\nfrom aea.crypto.ledger_apis import LedgerApis\nfrom aea.exceptions import AEAEnforceError, enforce\nfrom aea.helpers.preference_representations.base import (\n    linear_utility,\n    logarithmic_utility,\n)\nfrom aea.helpers.search.generic import (\n    AGENT_LOCATION_MODEL,\n    AGENT_PERSONALITY_MODEL,\n    AGENT_REMOVE_SERVICE_MODEL,\n    AGENT_SET_SERVICE_MODEL,\n)\nfrom aea.helpers.search.models import Description\nfrom aea.helpers.transaction.base import Terms\nfrom aea.skills.base import Model\n\nfrom packages.fetchai.protocols.tac.message import TacMessage\nfrom packages.fetchai.skills.tac_control.helpers import (\n    determine_scaling_factor,\n    generate_currency_endowments,\n    generate_equilibrium_prices_and_holdings,\n    generate_exchange_params,\n    generate_good_endowments,\n    generate_utility_params,\n)\nfrom packages.fetchai.skills.tac_control.parameters import Parameters\n\n\nGoodId = str\nCurrencyId = str\nQuantity = int\nEquilibriumQuantity = float\nParameter = float\nTransactionId = str\nCurrencyEndowment = Dict[CurrencyId, Quantity]\nExchangeParams = Dict[CurrencyId, Parameter]\nGoodEndowment = Dict[GoodId, Quantity]\nUtilityParams = Dict[GoodId, Parameter]\nEquilibriumCurrencyHoldings = Dict[CurrencyId, EquilibriumQuantity]\nEquilibriumGoodHoldings = Dict[GoodId, EquilibriumQuantity]\n\n\nclass Phase(Enum):\n    \"\"\"This class defines the phases of the game.\"\"\"\n\n    PRE_GAME = \"pre_game\"\n    CONTRACT_DEPLOYMENT_PROPOSAL = \"contract_deployment_proposal\"\n    CONTRACT_DEPLOYED = \"contract_deployed\"\n    GAME_REGISTRATION = \"game_registration\"\n    GAME_SETUP = \"game_setup\"\n    TOKENS_CREATION_PROPOSAL = \"token_creation_proposal\"  # nosec\n    TOKENS_CREATED = \"tokens_created\"  # nosec\n    TOKENS_MINTING_PROPOSAL = \"token_minting_proposal\"\n    TOKENS_MINTED = \"tokens_minted\"  # nosec\n    GAME = \"game\"\n    POST_GAME = \"post_game\"\n    CANCELLED_GAME = \"cancelled_game\"\n\n\nclass Configuration:\n    \"\"\"Class containing the configuration of the game.\"\"\"\n\n    def __init__(\n        self,\n        version_id: str,\n        tx_fee: int,\n        agent_addr_to_name: Dict[Address, str],\n        currency_id_to_name: Dict[str, str],\n        good_id_to_name: Dict[str, str],\n    ):\n        \"\"\"\n        Instantiate a game configuration.\n\n        :param version_id: the version of the game.\n        :param tx_fee: the fee for a transaction.\n        :param agent_addr_to_name: a dictionary mapping agent addresses to agent names (as strings).\n        :param currency_id_to_name: the mapping of currency id to name.\n        :param good_id_to_name: the mapping of good id to name.\n        \"\"\"\n        self._version_id = version_id\n        self._tx_fee = tx_fee\n        self._agent_addr_to_name = agent_addr_to_name\n        self._currency_id_to_name = currency_id_to_name\n        self._good_id_to_name = good_id_to_name\n        self._contract_address = None  # type: Optional[str]\n        self._check_consistency()\n\n    @property\n    def version_id(self) -> str:\n        \"\"\"Agent number of a TAC instance.\"\"\"\n        return self._version_id\n\n    @property\n    def fee_by_currency_id(self) -> Dict[str, int]:\n        \"\"\"Transaction fee for the TAC instance.\"\"\"\n        return {next(iter(self.currency_id_to_name.keys())): self._tx_fee}\n\n    @property\n    def agent_addr_to_name(self) -> Dict[Address, str]:\n        \"\"\"Map agent addresses to names.\"\"\"\n        return self._agent_addr_to_name\n\n    @property\n    def currency_id_to_name(self) -> Dict[str, str]:\n        \"\"\"Map currency ids to names.\"\"\"\n        return self._currency_id_to_name\n\n    @property\n    def good_id_to_name(self) -> Dict[str, str]:\n        \"\"\"Map good ids to names.\"\"\"\n        return self._good_id_to_name\n\n    @property\n    def has_contract_address(self) -> bool:\n        \"\"\"Check if contract address is present.\"\"\"\n        return self._contract_address is not None\n\n    @property\n    def contract_address(self) -> str:\n        \"\"\"Get the contract address for the game.\"\"\"\n        if self._contract_address is None:\n            raise AEAEnforceError(\"Contract_address not set yet!\")\n        return self._contract_address\n\n    @contract_address.setter\n    def contract_address(self, contract_address: str) -> None:\n        \"\"\"Set the contract address for the game.\"\"\"\n        enforce(self._contract_address is None, \"Contract_address already set!\")\n        self._contract_address = contract_address\n\n    def _check_consistency(self) -> None:\n        \"\"\"\n        Check the consistency of the game configuration.\n\n        :raises: AEAEnforceError: if some constraint is not satisfied.\n        \"\"\"\n        if self.version_id is None:\n            raise AEAEnforceError(\"A version id must be set.\")\n\n        enforce(self._tx_fee >= 0, \"Tx fee must be non-negative.\")\n        enforce(len(self.agent_addr_to_name) >= 2, \"Must have at least two agents.\")\n        enforce(len(self.good_id_to_name) >= 2, \"Must have at least two goods.\")\n        enforce(len(self.currency_id_to_name) == 1, \"Must have exactly one currency.\")\n        enforce(\n            next(iter(self.currency_id_to_name)) not in self.good_id_to_name,\n            \"Currency id and good ids cannot overlap.\",\n        )\n\n\nclass Initialization:\n    \"\"\"Class containing the initialization of the game.\"\"\"\n\n    def __init__(\n        self,\n        agent_addr_to_currency_endowments: Dict[Address, CurrencyEndowment],\n        agent_addr_to_exchange_params: Dict[Address, ExchangeParams],\n        agent_addr_to_good_endowments: Dict[Address, GoodEndowment],\n        agent_addr_to_utility_params: Dict[Address, UtilityParams],\n        good_id_to_eq_prices: Dict[GoodId, float],\n        agent_addr_to_eq_good_holdings: Dict[Address, EquilibriumGoodHoldings],\n        agent_addr_to_eq_currency_holdings: Dict[Address, EquilibriumCurrencyHoldings],\n    ):\n        \"\"\"\n        Instantiate a game initialization.\n\n        :param agent_addr_to_currency_endowments: the currency endowments of the agents. A nested dict where the outer key is the agent id\n                            and the inner key is the currency id.\n        :param agent_addr_to_exchange_params: the exchange params representing the exchange rate the agents use between currencies.\n        :param agent_addr_to_good_endowments: the good endowments of the agents. A nested dict where the outer key is the agent id\n                            and the inner key is the good id.\n        :param agent_addr_to_utility_params: the utility params representing the preferences of the agents.\n        :param good_id_to_eq_prices: the competitive equilibrium prices of the goods. A list.\n        :param agent_addr_to_eq_good_holdings: the competitive equilibrium good holdings of the agents.\n        :param agent_addr_to_eq_currency_holdings: the competitive equilibrium money holdings of the agents.\n        \"\"\"\n        self._agent_addr_to_currency_endowments = agent_addr_to_currency_endowments\n        self._agent_addr_to_exchange_params = agent_addr_to_exchange_params\n        self._agent_addr_to_good_endowments = agent_addr_to_good_endowments\n        self._agent_addr_to_utility_params = agent_addr_to_utility_params\n        self._good_id_to_eq_prices = good_id_to_eq_prices\n        self._agent_addr_to_eq_good_holdings = agent_addr_to_eq_good_holdings\n        self._agent_addr_to_eq_currency_holdings = agent_addr_to_eq_currency_holdings\n        self._check_consistency()\n\n    @property\n    def agent_addr_to_currency_endowments(self) -> Dict[Address, CurrencyEndowment]:\n        \"\"\"Get currency endowments of agents.\"\"\"\n        return self._agent_addr_to_currency_endowments\n\n    @property\n    def agent_addr_to_exchange_params(self) -> Dict[Address, ExchangeParams]:\n        \"\"\"Get exchange params of agents.\"\"\"\n        return self._agent_addr_to_exchange_params\n\n    @property\n    def agent_addr_to_good_endowments(self) -> Dict[Address, GoodEndowment]:\n        \"\"\"Get good endowments of the agents.\"\"\"\n        return self._agent_addr_to_good_endowments\n\n    @property\n    def agent_addr_to_utility_params(self) -> Dict[Address, UtilityParams]:\n        \"\"\"Get utility parameters of agents.\"\"\"\n        return self._agent_addr_to_utility_params\n\n    @property\n    def good_id_to_eq_prices(self) -> Dict[GoodId, float]:\n        \"\"\"Get theoretical equilibrium prices (a benchmark).\"\"\"\n        return self._good_id_to_eq_prices\n\n    @property\n    def agent_addr_to_eq_good_holdings(self) -> Dict[Address, EquilibriumGoodHoldings]:\n        \"\"\"Get theoretical equilibrium good holdings (a benchmark).\"\"\"\n        return self._agent_addr_to_eq_good_holdings\n\n    @property\n    def agent_addr_to_eq_currency_holdings(\n        self,\n    ) -> Dict[Address, EquilibriumCurrencyHoldings]:\n        \"\"\"Get theoretical equilibrium currency holdings (a benchmark).\"\"\"\n        return self._agent_addr_to_eq_currency_holdings\n\n    def _check_consistency(self) -> None:\n        \"\"\"Check the consistency of the game configuration.\"\"\"\n        enforce(\n            all(\n                c_e >= 0\n                for currency_endowments in self.agent_addr_to_currency_endowments.values()\n                for c_e in currency_endowments.values()\n            ),\n            \"Currency endowments must be non-negative.\",\n        )\n        enforce(\n            all(\n                p > 0\n                for params in self.agent_addr_to_exchange_params.values()\n                for p in params.values()\n            ),\n            \"ExchangeParams must be strictly positive.\",\n        )\n        enforce(\n            all(\n                g_e > 0\n                for good_endowments in self.agent_addr_to_good_endowments.values()\n                for g_e in good_endowments.values()\n            ),\n            \"Good endowments must be strictly positive.\",\n        )\n        enforce(\n            all(\n                p > 0\n                for params in self.agent_addr_to_utility_params.values()\n                for p in params.values()\n            ),\n            \"UtilityParams must be strictly positive.\",\n        )\n        enforce(\n            len(self.agent_addr_to_good_endowments.keys())\n            == len(self.agent_addr_to_currency_endowments.keys()),\n            \"Length of endowments must be the same.\",\n        )\n        enforce(\n            len(self.agent_addr_to_exchange_params.keys())\n            == len(self.agent_addr_to_utility_params.keys()),\n            \"Length of params must be the same.\",\n        )\n        enforce(\n            all(\n                len(self.good_id_to_eq_prices.values()) == len(eq_good_holdings)\n                for eq_good_holdings in self.agent_addr_to_eq_good_holdings.values()\n            ),\n            \"Length of eq_prices and an element of eq_good_holdings must be the same.\",\n        )\n        enforce(\n            len(self.agent_addr_to_eq_good_holdings.values())\n            == len(self.agent_addr_to_eq_currency_holdings.values()),\n            \"Length of eq_good_holdings and eq_currency_holdings must be the same.\",\n        )\n        enforce(\n            all(\n                len(self.agent_addr_to_exchange_params[agent_addr]) == len(endowments)\n                for agent_addr, endowments in self.agent_addr_to_currency_endowments.items()\n            ),\n            \"Dimensions for exchange_params and currency_endowments rows must be the same.\",\n        )\n        enforce(\n            all(\n                len(self.agent_addr_to_utility_params[agent_addr]) == len(endowments)\n                for agent_addr, endowments in self.agent_addr_to_good_endowments.items()\n            ),\n            \"Dimensions for utility_params and good_endowments rows must be the same.\",\n        )\n\n\nclass Transaction(Terms):\n    \"\"\"Convenience representation of a transaction.\"\"\"\n\n    def __init__(\n        self,\n        ledger_id: str,\n        sender_address: Address,\n        counterparty_address: Address,\n        amount_by_currency_id: Dict[str, int],\n        quantities_by_good_id: Dict[str, int],\n        is_sender_payable_tx_fee: bool,\n        nonce: str,\n        fee_by_currency_id: Optional[Dict[str, int]],\n        sender_signature: str,\n        counterparty_signature: str,\n    ) -> None:\n        \"\"\"\n        Instantiate transaction.\n\n        This extends a terms object to be used as a transaction.\n\n        :param ledger_id: the ledger on which the terms are to be settled.\n        :param sender_address: the sender address of the transaction.\n        :param counterparty_address: the counterparty address of the transaction.\n        :param amount_by_currency_id: the amount by the currency of the transaction.\n        :param quantities_by_good_id: a map from good id to the quantity of that good involved in the transaction.\n        :param is_sender_payable_tx_fee: whether the sender or counterparty pays the tx fee.\n        :param nonce: nonce to be included in transaction to discriminate otherwise identical transactions.\n        :param fee_by_currency_id: the fee associated with the transaction.\n        :param sender_signature: the signature of the terms by the sender.\n        :param counterparty_signature: the signature of the terms by the counterparty.\n        \"\"\"\n        super().__init__(\n            ledger_id=ledger_id,\n            sender_address=sender_address,\n            counterparty_address=counterparty_address,\n            amount_by_currency_id=amount_by_currency_id,\n            quantities_by_good_id=quantities_by_good_id,\n            is_sender_payable_tx_fee=is_sender_payable_tx_fee,\n            nonce=nonce,\n            fee_by_currency_id=fee_by_currency_id,\n        )\n        self._sender_signature = sender_signature\n        self._counterparty_signature = counterparty_signature\n\n    @property\n    def sender_signature(self) -> str:\n        \"\"\"Get the sender signature.\"\"\"\n        return self._sender_signature\n\n    @property\n    def counterparty_signature(self) -> str:\n        \"\"\"Get the counterparty signature.\"\"\"\n        return self._counterparty_signature\n\n    def has_matching_signatures(self) -> bool:\n        \"\"\"\n        Check that the signatures match the terms of trade.\n\n        :return: True if the transaction has been signed by both parties\n        \"\"\"\n        result = (\n            self.sender_address\n            in LedgerApis.recover_message(  # pylint: disable=no-member\n                identifier=self.ledger_id,\n                message=self.sender_hash.encode(\"utf-8\"),\n                signature=self.sender_signature,\n            )\n        )\n        result = (\n            result\n            and self.counterparty_address\n            in LedgerApis.recover_message(  # pylint: disable=no-member\n                identifier=self.ledger_id,\n                message=self.counterparty_hash.encode(\"utf-8\"),\n                signature=self.counterparty_signature,\n            )\n        )\n        return result\n\n    @classmethod\n    def from_message(cls, message: TacMessage) -> \"Transaction\":\n        \"\"\"\n        Create a transaction from a proposal.\n\n        :param message: the message\n        :return: Transaction\n        \"\"\"\n        enforce(\n            message.performative == TacMessage.Performative.TRANSACTION,\n            \"Wrong performative\",\n        )\n        sender_is_seller = all(\n            value >= 0 for value in message.amount_by_currency_id.values()\n        )\n        transaction = Transaction(\n            ledger_id=message.ledger_id,\n            sender_address=message.sender_address,\n            counterparty_address=message.counterparty_address,\n            amount_by_currency_id=message.amount_by_currency_id,\n            fee_by_currency_id=message.fee_by_currency_id,\n            quantities_by_good_id=message.quantities_by_good_id,\n            is_sender_payable_tx_fee=not sender_is_seller,\n            nonce=message.nonce,\n            sender_signature=message.sender_signature,\n            counterparty_signature=message.counterparty_signature,\n        )\n        enforce(\n            transaction.id == message.transaction_id,\n            \"Transaction content does not match hash.\",\n        )\n        return transaction\n\n    def __eq__(self, other: Any) -> bool:\n        \"\"\"Compare to another object.\"\"\"\n        return (\n            isinstance(other, Transaction)\n            and super().__eq__(other)\n            and self.sender_signature == other.sender_signature\n            and self.counterparty_signature == other.counterparty_signature\n        )\n\n\nclass AgentState:\n    \"\"\"Represent the state of an agent during the game.\"\"\"\n\n    def __init__(\n        self,\n        agent_address: Address,\n        amount_by_currency_id: Dict[CurrencyId, Quantity],\n        exchange_params_by_currency_id: Dict[CurrencyId, Parameter],\n        quantities_by_good_id: Dict[GoodId, Quantity],\n        utility_params_by_good_id: Dict[GoodId, Parameter],\n    ):\n        \"\"\"\n        Instantiate an agent state object.\n\n        :param agent_address: the agent address\n        :param amount_by_currency_id: the amount for each currency\n        :param exchange_params_by_currency_id: the exchange parameters of the different currencies\n        :param quantities_by_good_id: the quantities for each good.\n        :param utility_params_by_good_id: the utility params for every good.\n        \"\"\"\n        enforce(\n            len(amount_by_currency_id.keys())\n            == len(exchange_params_by_currency_id.keys()),\n            \"Different number of elements in amount_by_currency_id and exchange_params_by_currency_id\",\n        )\n        enforce(\n            len(quantities_by_good_id.keys()) == len(utility_params_by_good_id.keys()),\n            \"Different number of elements in quantities_by_good_id and utility_params_by_good_id\",\n        )\n        self._agent_address = agent_address\n        self._amount_by_currency_id = copy.copy(amount_by_currency_id)\n        self._exchange_params_by_currency_id = copy.copy(exchange_params_by_currency_id)\n        self._quantities_by_good_id = quantities_by_good_id\n        self._utility_params_by_good_id = copy.copy(utility_params_by_good_id)\n\n    @property\n    def agent_address(self) -> str:\n        \"\"\"Get address of the agent which state that is.\"\"\"\n        return self._agent_address\n\n    @property\n    def amount_by_currency_id(self) -> Dict[CurrencyId, Quantity]:\n        \"\"\"Get the amount for each currency.\"\"\"\n        return copy.copy(self._amount_by_currency_id)\n\n    @property\n    def exchange_params_by_currency_id(self) -> Dict[CurrencyId, Parameter]:\n        \"\"\"Get the exchange parameters for each currency.\"\"\"\n        return copy.copy(self._exchange_params_by_currency_id)\n\n    @property\n    def quantities_by_good_id(self) -> Dict[GoodId, Quantity]:\n        \"\"\"Get holding of each good.\"\"\"\n        return copy.copy(self._quantities_by_good_id)\n\n    @property\n    def utility_params_by_good_id(self) -> Dict[GoodId, Parameter]:\n        \"\"\"Get utility parameter for each good.\"\"\"\n        return copy.copy(self._utility_params_by_good_id)\n\n    def get_score(self) -> float:\n        \"\"\"\n        Compute the score of the current state.\n\n        The score is computed as the sum of all the utilities for the good holdings\n        with positive quantity plus the money left.\n        :return: the score.\n        \"\"\"\n        goods_score = logarithmic_utility(\n            self.utility_params_by_good_id, self.quantities_by_good_id\n        )\n        money_score = linear_utility(\n            self.exchange_params_by_currency_id, self.amount_by_currency_id\n        )\n        score = goods_score + money_score\n        return score\n\n    def is_consistent_transaction(self, tx: Transaction) -> bool:\n        \"\"\"\n        Check if the transaction is consistent.\n\n        E.g. check that the agent state has enough money if it is a buyer\n        or enough holdings if it is a seller.\n\n        :param tx: the transaction\n        :return: True if the transaction is legal wrt the current state, False otherwise.\n        \"\"\"\n        result = self.agent_address in [tx.sender_address, tx.counterparty_address]\n        result = result and tx.is_single_currency\n        if not result:\n            return result\n        if all(amount == 0 for amount in tx.amount_by_currency_id.values()) and all(\n            quantity == 0 for quantity in tx.quantities_by_good_id.values()\n        ):\n            # reject the transaction when there is no wealth exchange\n            result = False\n        elif all(amount <= 0 for amount in tx.amount_by_currency_id.values()) and all(\n            quantity >= 0 for quantity in tx.quantities_by_good_id.values()\n        ):\n            # sender is buyer, counterparty is seller\n            if self.agent_address == tx.sender_address:\n                # check this sender state has enough money\n                result = result and (\n                    self.amount_by_currency_id[tx.currency_id]\n                    >= tx.sender_payable_amount\n                )\n            elif self.agent_address == tx.counterparty_address:\n                # check this counterparty state has enough goods\n                result = result and all(\n                    self.quantities_by_good_id[good_id] >= quantity\n                    for good_id, quantity in tx.quantities_by_good_id.items()\n                )\n        elif all(amount >= 0 for amount in tx.amount_by_currency_id.values()) and all(\n            quantity <= 0 for quantity in tx.quantities_by_good_id.values()\n        ):\n            # sender is seller, counterparty is buyer\n            # Note, on a ledger, this atomic swap would only be possible for amount == 0!\n            if self.agent_address == tx.sender_address:\n                # check this sender state has enough goods\n                result = result and all(\n                    self.quantities_by_good_id[good_id] >= -quantity\n                    for good_id, quantity in tx.quantities_by_good_id.items()\n                )\n            elif self.agent_address == tx.counterparty_address:\n                # check this counterparty state has enough money\n                result = result and (\n                    self.amount_by_currency_id[tx.currency_id]\n                    >= tx.counterparty_payable_amount\n                )\n        else:\n            result = False\n        return result\n\n    def apply(self, transactions: List[Transaction]) -> \"AgentState\":\n        \"\"\"\n        Apply a list of transactions to the current state.\n\n        :param transactions: the sequence of transaction.\n        :return: the final state.\n        \"\"\"\n        new_state = copy.copy(self)\n        for tx in transactions:\n            new_state.update(tx)\n\n        return new_state\n\n    def update(self, tx: Transaction) -> None:\n        \"\"\"\n        Update the agent state from a transaction.\n\n        :param tx: the transaction.\n        \"\"\"\n        enforce(self.is_consistent_transaction(tx), \"Inconsistent transaction.\")\n\n        new_amount_by_currency_id = self.amount_by_currency_id\n        if self.agent_address == tx.sender_address:\n            # settling the transaction for the sender\n            for currency_id, amount in tx.amount_by_currency_id.items():\n                new_amount_by_currency_id[currency_id] += amount\n        elif self.agent_address == tx.counterparty_address:\n            # settling the transaction for the counterparty\n            for currency_id, amount in tx.amount_by_currency_id.items():\n                new_amount_by_currency_id[currency_id] -= amount\n\n        self._amount_by_currency_id = new_amount_by_currency_id\n\n        new_quantities_by_good_id = self.quantities_by_good_id\n        for good_id, quantity in tx.quantities_by_good_id.items():\n            if self.agent_address == tx.sender_address:\n                new_quantities_by_good_id[good_id] += quantity\n            elif self.agent_address == tx.counterparty_address:\n                new_quantities_by_good_id[good_id] -= quantity\n        self._quantities_by_good_id = new_quantities_by_good_id\n\n    def __copy__(self) -> \"AgentState\":\n        \"\"\"Copy the object.\"\"\"\n        return AgentState(\n            self.agent_address,\n            self.amount_by_currency_id,\n            self.exchange_params_by_currency_id,\n            self.quantities_by_good_id,\n            self.utility_params_by_good_id,\n        )\n\n    def __str__(self) -> str:\n        \"\"\"From object to string.\"\"\"\n        return \"AgentState{}\".format(\n            pprint.pformat(\n                {\n                    \"agent_address\": self.agent_address,\n                    \"amount_by_currency_id\": self.amount_by_currency_id,\n                    \"exchange_params_by_currency_id\": self.exchange_params_by_currency_id,\n                    \"quantities_by_good_id\": self.quantities_by_good_id,\n                    \"utility_params_by_good_id\": self.utility_params_by_good_id,\n                }\n            )\n        )\n\n    def __eq__(self, other: Any) -> bool:\n        \"\"\"Compare equality of two instances of the class.\"\"\"\n        return (\n            isinstance(other, AgentState)\n            and self.agent_address == other.agent_address\n            and self.amount_by_currency_id == other.amount_by_currency_id\n            and self.exchange_params_by_currency_id\n            == other.exchange_params_by_currency_id\n            and self.quantities_by_good_id == other.quantities_by_good_id\n            and self.utility_params_by_good_id == other.utility_params_by_good_id\n        )\n\n\nclass Transactions:\n    \"\"\"Class managing the transactions.\"\"\"\n\n    def __init__(self) -> None:\n        \"\"\"Instantiate the transaction class.\"\"\"\n        self._confirmed = {}  # type: Dict[datetime.datetime, Transaction]\n        self._confirmed_per_agent = (\n            {}\n        )  # type: Dict[Address, Dict[datetime.datetime, Transaction]]\n\n    @property\n    def confirmed(self) -> Dict[datetime.datetime, Transaction]:\n        \"\"\"Get the confirmed transactions.\"\"\"\n        return self._confirmed\n\n    @property\n    def confirmed_per_agent(\n        self,\n    ) -> Dict[Address, Dict[datetime.datetime, Transaction]]:\n        \"\"\"Get the confirmed transactions by agent.\"\"\"\n        return self._confirmed_per_agent\n\n    def add(self, transaction: Transaction) -> None:\n        \"\"\"\n        Add a confirmed transaction.\n\n        :param transaction: the transaction\n        \"\"\"\n        now = datetime.datetime.now()\n        self._confirmed[now] = transaction\n        if self._confirmed_per_agent.get(transaction.sender_address) is None:\n            self._confirmed_per_agent[transaction.sender_address] = {}\n        self._confirmed_per_agent[transaction.sender_address][now] = transaction\n        if self._confirmed_per_agent.get(transaction.counterparty_address) is None:\n            self._confirmed_per_agent[transaction.counterparty_address] = {}\n        self._confirmed_per_agent[transaction.counterparty_address][now] = transaction\n\n\nclass Registration:\n    \"\"\"Class managing the registration of the game.\"\"\"\n\n    def __init__(self) -> None:\n        \"\"\"Instantiate the registration class.\"\"\"\n        self._agent_addr_to_name = {}  # type: Dict[str, str]\n\n    @property\n    def agent_addr_to_name(self) -> Dict[str, str]:\n        \"\"\"Get the registered agent addresses and their names.\"\"\"\n        return self._agent_addr_to_name\n\n    @property\n    def nb_agents(self) -> int:\n        \"\"\"Get the number of registered agents.\"\"\"\n        return len(self._agent_addr_to_name)\n\n    def register_agent(self, agent_addr: Address, agent_name: str) -> None:\n        \"\"\"\n        Register an agent.\n\n        :param agent_addr: the Address of the agent\n        :param agent_name: the name of the agent\n        \"\"\"\n        self._agent_addr_to_name[agent_addr] = agent_name\n\n    def unregister_agent(self, agent_addr: Address) -> None:\n        \"\"\"\n        Register an agent.\n\n        :param agent_addr: the Address of the agent\n        \"\"\"\n        self._agent_addr_to_name.pop(agent_addr)\n\n\nclass Game(Model):\n    \"\"\"A class to manage a TAC instance.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"Instantiate the search class.\"\"\"\n        super().__init__(**kwargs)\n        self._phase = Phase.PRE_GAME\n        self._registration = Registration()\n        self._conf = None  # type: Optional[Configuration]\n        self._initialization = None  # type: Optional[Initialization]\n        self._initial_agent_states = None  # type: Optional[Dict[str, AgentState]]\n        self._current_agent_states = None  # type: Optional[Dict[str, AgentState]]\n        self._transactions = Transactions()\n        self._already_minted_agents = []  # type: List[str]\n        self._is_allowed_to_mint = True\n        self.is_registered_agent = False\n\n    @property\n    def phase(self) -> Phase:\n        \"\"\"Get the game phase.\"\"\"\n        return self._phase\n\n    @phase.setter\n    def phase(self, phase: Phase) -> None:\n        \"\"\"Set the game phase.\"\"\"\n        self.context.logger.debug(\"Game phase set to: {}\".format(phase))\n        self._phase = phase\n\n    @property\n    def registration(self) -> Registration:\n        \"\"\"Get the registration.\"\"\"\n        return self._registration\n\n    @property\n    def conf(self) -> Configuration:\n        \"\"\"Get game configuration.\"\"\"\n        if self._conf is None:\n            raise AEAEnforceError(\"Call create before calling configuration.\")\n        return self._conf\n\n    @property\n    def initialization(self) -> Initialization:\n        \"\"\"Get game initialization.\"\"\"\n        if self._initialization is None:\n            raise AEAEnforceError(\"Call create before calling initialization.\")\n        return self._initialization\n\n    @property\n    def initial_agent_states(self) -> Dict[str, AgentState]:\n        \"\"\"Get initial state of each agent.\"\"\"\n        if self._initial_agent_states is None:\n            raise AEAEnforceError(\"Call create before calling initial_agent_states.\")\n        return self._initial_agent_states\n\n    @property\n    def current_agent_states(self) -> Dict[str, AgentState]:\n        \"\"\"Get current state of each agent.\"\"\"\n        if self._current_agent_states is None:\n            raise AEAEnforceError(\"Call create before calling current_agent_states.\")\n        return self._current_agent_states\n\n    @property\n    def transactions(self) -> Transactions:\n        \"\"\"Get the transactions.\"\"\"\n        return self._transactions\n\n    def create(self) -> None:\n        \"\"\"Create a game.\"\"\"\n        enforce(self.phase != Phase.GAME, \"A game phase is already active.\")\n        self._phase = Phase.GAME_SETUP\n        self._generate()\n\n    @property\n    def is_allowed_to_mint(self) -> bool:\n        \"\"\"Get is allowed to mint.\"\"\"\n        return self._is_allowed_to_mint\n\n    @is_allowed_to_mint.setter\n    def is_allowed_to_mint(self, is_allowed_to_mint: bool) -> None:\n        \"\"\"Get is allowed to mint.\"\"\"\n        self._is_allowed_to_mint = is_allowed_to_mint\n\n    def get_next_agent_state_for_minting(self) -> Optional[AgentState]:\n        \"\"\"Get next agent state for token minting.\"\"\"\n        result = None\n        for agent_addr, agent_state in self.initial_agent_states.items():\n            if agent_addr in self._already_minted_agents:\n                continue\n            self._already_minted_agents.append(agent_addr)\n            result = agent_state\n            break\n        return result\n\n    def _generate(self) -> None:\n        \"\"\"Generate a TAC game.\"\"\"\n        parameters = cast(Parameters, self.context.parameters)\n\n        self._conf = Configuration(\n            parameters.version_id,\n            parameters.tx_fee,\n            self.registration.agent_addr_to_name,\n            parameters.currency_id_to_name,\n            parameters.good_id_to_name,\n        )\n\n        scaling_factor = determine_scaling_factor(parameters.money_endowment)\n\n        agent_addr_to_currency_endowments = generate_currency_endowments(\n            list(self.conf.agent_addr_to_name.keys()),\n            list(self.conf.currency_id_to_name.keys()),\n            parameters.money_endowment,\n        )\n\n        agent_addr_to_exchange_params = generate_exchange_params(\n            list(self.conf.agent_addr_to_name.keys()),\n            list(self.conf.currency_id_to_name.keys()),\n        )\n\n        agent_addr_to_good_endowments = generate_good_endowments(\n            list(self.conf.agent_addr_to_name.keys()),\n            list(self.conf.good_id_to_name.keys()),\n            parameters.base_good_endowment,\n            parameters.lower_bound_factor,\n            parameters.upper_bound_factor,\n        )\n\n        agent_addr_to_utility_params = generate_utility_params(\n            list(self.conf.agent_addr_to_name.keys()),\n            list(self.conf.good_id_to_name.keys()),\n            scaling_factor,\n        )\n\n        (\n            good_id_to_eq_prices,\n            agent_addr_to_eq_good_holdings,\n            agent_addr_to_eq_currency_holdings,\n        ) = generate_equilibrium_prices_and_holdings(\n            agent_addr_to_good_endowments,\n            agent_addr_to_utility_params,\n            agent_addr_to_currency_endowments,\n            agent_addr_to_exchange_params,\n            scaling_factor,\n        )\n\n        self._initialization = Initialization(\n            agent_addr_to_currency_endowments,\n            agent_addr_to_exchange_params,\n            agent_addr_to_good_endowments,\n            agent_addr_to_utility_params,\n            good_id_to_eq_prices,\n            agent_addr_to_eq_good_holdings,\n            agent_addr_to_eq_currency_holdings,\n        )\n\n        self._initial_agent_states = dict(\n            (\n                agent_addr,\n                AgentState(\n                    agent_addr,\n                    self.initialization.agent_addr_to_currency_endowments[agent_addr],\n                    self.initialization.agent_addr_to_exchange_params[agent_addr],\n                    self.initialization.agent_addr_to_good_endowments[agent_addr],\n                    self.initialization.agent_addr_to_utility_params[agent_addr],\n                ),\n            )\n            for agent_addr in self.conf.agent_addr_to_name.keys()\n        )\n\n        self._current_agent_states = dict(\n            (\n                agent_addr,\n                AgentState(\n                    agent_addr,\n                    self.initialization.agent_addr_to_currency_endowments[agent_addr],\n                    self.initialization.agent_addr_to_exchange_params[agent_addr],\n                    self.initialization.agent_addr_to_good_endowments[agent_addr],\n                    self.initialization.agent_addr_to_utility_params[agent_addr],\n                ),\n            )\n            for agent_addr in self.conf.agent_addr_to_name.keys()\n        )\n\n    @property\n    def holdings_summary(self) -> str:\n        \"\"\"Get holdings summary (a string representing the holdings for every agent).\"\"\"\n        result = \"\\n\" + \"Current good & money allocation & score: \\n\"\n        for agent_addr, agent_state in self.current_agent_states.items():\n            result = (\n                result + \"- \" + self.conf.agent_addr_to_name[agent_addr] + \":\" + \"\\n\"\n            )\n            for good_id, quantity in agent_state.quantities_by_good_id.items():\n                result += (\n                    \"    \"\n                    + self.conf.good_id_to_name[good_id]\n                    + \": \"\n                    + str(quantity)\n                    + \"\\n\"\n                )\n            for currency_id, amount in agent_state.amount_by_currency_id.items():\n                result += (\n                    \"    \"\n                    + self.conf.currency_id_to_name[currency_id]\n                    + \": \"\n                    + str(amount)\n                    + \"\\n\"\n                )\n            result += \"    score: \" + str(round(agent_state.get_score(), 2)) + \"\\n\"\n        result = result + \"\\n\"\n        return result\n\n    @property\n    def equilibrium_summary(self) -> str:\n        \"\"\"Get equilibrium summary.\"\"\"\n        result = \"\\n\" + \"Equilibrium prices: \\n\"\n        for good_id, eq_price in self.initialization.good_id_to_eq_prices.items():\n            result = (\n                result + self.conf.good_id_to_name[good_id] + \" \" + str(eq_price) + \"\\n\"\n            )\n        result = result + \"\\n\"\n        result = result + \"Equilibrium good allocation: \\n\"\n        for (\n            agent_addr,\n            eq_allocations,\n        ) in self.initialization.agent_addr_to_eq_good_holdings.items():\n            result = result + \"- \" + self.conf.agent_addr_to_name[agent_addr] + \":\\n\"\n            for good_id, quantity in eq_allocations.items():\n                result = (\n                    result\n                    + \"    \"\n                    + self.conf.good_id_to_name[good_id]\n                    + \": \"\n                    + str(quantity)\n                    + \"\\n\"\n                )\n        result = result + \"\\n\"\n        result = result + \"Equilibrium money allocation: \\n\"\n        for (\n            agent_addr,\n            eq_allocations,\n        ) in self.initialization.agent_addr_to_eq_currency_holdings.items():\n            result = result + \"- \" + self.conf.agent_addr_to_name[agent_addr] + \":\\n\"\n            for currency_id, quantity in eq_allocations.items():\n                result = (\n                    result\n                    + \"    \"\n                    + self.conf.currency_id_to_name[currency_id]\n                    + \": \"\n                    + str(quantity)\n                    + \"\\n\"\n                )\n        result = result + \"\\n\"\n        return result\n\n    def is_transaction_valid(self, tx: Transaction) -> bool:\n        \"\"\"\n        Check whether the transaction is signed correctly and valid given the state of the game.\n\n        :param tx: the transaction.\n        :return: True if the transaction is valid, False otherwise.\n        :raises: AEAEnforceError: if the data in the transaction are not allowed (e.g. negative amount).\n        \"\"\"\n        sender_state = self.current_agent_states[tx.sender_address]\n        counterparty_state = self.current_agent_states[tx.counterparty_address]\n        result = tx.has_matching_signatures()\n        result = result and sender_state.is_consistent_transaction(tx)\n        result = result and counterparty_state.is_consistent_transaction(tx)\n        return result\n\n    def settle_transaction(self, tx: Transaction) -> None:\n        \"\"\"\n        Settle a valid transaction.\n\n        :param tx: the game transaction.\n        :raises: AEAEnforceError if the transaction is not valid.\n        \"\"\"\n        if self._current_agent_states is None:\n            raise AEAEnforceError(\"Call create before calling current_agent_states.\")\n        enforce(self.is_transaction_valid(tx), \"Transaction is not valid.\")\n        sender_state = self.current_agent_states[tx.sender_address]\n        counterparty_state = self.current_agent_states[tx.counterparty_address]\n\n        new_sender_state = sender_state.apply([tx])\n        new_counterparty_state = counterparty_state.apply([tx])\n\n        self.transactions.add(tx)\n        self._current_agent_states.update({tx.sender_address: new_sender_state})\n        self._current_agent_states.update(\n            {tx.counterparty_address: new_counterparty_state}\n        )\n\n    def get_location_description(self) -> Description:\n        \"\"\"\n        Get the location description.\n\n        :return: a description of the agent's location\n        \"\"\"\n        description = Description(\n            self.context.parameters.agent_location,\n            data_model=AGENT_LOCATION_MODEL,\n        )\n        return description\n\n    def get_register_tac_description(self) -> Description:\n        \"\"\"Get the tac description for registering.\"\"\"\n        description = Description(\n            self.context.parameters.set_service_data,\n            data_model=AGENT_SET_SERVICE_MODEL,\n        )\n        return description\n\n    def get_register_personality_description(self) -> Description:\n        \"\"\"\n        Get the register personality description.\n\n        :return: a description of the personality\n        \"\"\"\n        description = Description(\n            self.context.parameters.set_personality_data,\n            data_model=AGENT_PERSONALITY_MODEL,\n        )\n        return description\n\n    def get_register_classification_description(self) -> Description:\n        \"\"\"\n        Get the register classification description.\n\n        :return: a description of the classification\n        \"\"\"\n        description = Description(\n            self.context.parameters.set_classification,\n            data_model=AGENT_PERSONALITY_MODEL,\n        )\n        return description\n\n    def get_unregister_tac_description(self) -> Description:\n        \"\"\"Get the tac description for unregistering.\"\"\"\n        description = Description(\n            self.context.parameters.remove_service_data,\n            data_model=AGENT_REMOVE_SERVICE_MODEL,\n        )\n        return description\n"
  },
  {
    "path": "packages/fetchai/skills/tac_control/handlers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains the handlers.\"\"\"\n\nfrom typing import Optional, cast\n\nfrom aea.protocols.base import Message\nfrom aea.skills.base import Handler\n\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.protocols.tac.message import TacMessage\nfrom packages.fetchai.skills.tac_control.behaviours import TacBehaviour\nfrom packages.fetchai.skills.tac_control.dialogues import (\n    DefaultDialogues,\n    OefSearchDialogue,\n    OefSearchDialogues,\n    TacDialogue,\n    TacDialogues,\n)\nfrom packages.fetchai.skills.tac_control.game import Game, Phase, Transaction\nfrom packages.fetchai.skills.tac_control.parameters import Parameters\n\n\nclass TacHandler(Handler):\n    \"\"\"This class handles oef messages.\"\"\"\n\n    SUPPORTED_PROTOCOL = TacMessage.protocol_id\n\n    def setup(self) -> None:\n        \"\"\"Implement the handler setup.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Handle a register message.\n\n        If the address is already registered, answer with an error message.\n\n        :param message: the 'get agent state' TacMessage.\n        \"\"\"\n        tac_msg = cast(TacMessage, message)\n\n        # recover dialogue\n        tac_dialogues = cast(TacDialogues, self.context.tac_dialogues)\n        tac_dialogue = cast(TacDialogue, tac_dialogues.update(tac_msg))\n        if tac_dialogue is None:\n            self._handle_unidentified_dialogue(tac_msg)\n            return\n\n        self.context.logger.debug(\n            \"handling TAC message. performative={}\".format(tac_msg.performative)\n        )\n        if tac_msg.performative == TacMessage.Performative.REGISTER:\n            self._on_register(tac_msg, tac_dialogue)\n        elif tac_msg.performative == TacMessage.Performative.UNREGISTER:\n            self._on_unregister(tac_msg, tac_dialogue)\n        elif tac_msg.performative == TacMessage.Performative.TRANSACTION:\n            self._on_transaction(tac_msg, tac_dialogue)\n        else:\n            self._handle_invalid(tac_msg, tac_dialogue)\n\n            self.context.logger.warning(\n                \"TAC Message performative not recognized or not permitted.\"\n            )\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n\n    def _handle_unidentified_dialogue(self, tac_msg: TacMessage) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param tac_msg: the message\n        \"\"\"\n        self.context.logger.info(\n            \"received invalid tac message={}, unidentified dialogue (reference={}).\".format(\n                tac_msg, tac_msg.dialogue_reference\n            )\n        )\n        default_dialogues = cast(DefaultDialogues, self.context.default_dialogues)\n        default_msg, _ = default_dialogues.create(\n            counterparty=tac_msg.sender,\n            performative=DefaultMessage.Performative.ERROR,\n            error_code=DefaultMessage.ErrorCode.INVALID_DIALOGUE,\n            error_msg=\"Invalid dialogue.\",\n            error_data={\"tac_message\": tac_msg.encode()},\n        )\n        self.context.outbox.put_message(message=default_msg)\n\n    def _on_register(self, tac_msg: TacMessage, tac_dialogue: TacDialogue) -> None:\n        \"\"\"\n        Handle a register message.\n\n        If the address is not registered, answer with an error message.\n\n        :param tac_msg: the tac message\n        :param tac_dialogue: the tac dialogue\n        \"\"\"\n        game = cast(Game, self.context.game)\n        if not game.phase == Phase.GAME_REGISTRATION:\n            self.context.logger.warning(\n                \"received registration outside of game registration phase: '{}'\".format(\n                    tac_msg\n                )\n            )\n            return\n\n        parameters = cast(Parameters, self.context.parameters)\n        agent_name = tac_msg.agent_name\n        if len(parameters.whitelist) != 0 and agent_name not in parameters.whitelist:\n            self.context.logger.warning(\n                \"agent name not in whitelist: '{}'\".format(agent_name)\n            )\n            error_msg = tac_dialogue.reply(\n                performative=TacMessage.Performative.TAC_ERROR,\n                target_message=tac_msg,\n                error_code=TacMessage.ErrorCode.AGENT_NAME_NOT_IN_WHITELIST,\n            )\n            self.context.outbox.put_message(message=error_msg)\n            return\n\n        game = cast(Game, self.context.game)\n        if tac_msg.sender in game.registration.agent_addr_to_name:\n            self.context.logger.warning(\n                \"agent already registered: '{}'\".format(\n                    game.registration.agent_addr_to_name[tac_msg.sender],\n                )\n            )\n            error_msg = tac_dialogue.reply(\n                performative=TacMessage.Performative.TAC_ERROR,\n                target_message=tac_msg,\n                error_code=TacMessage.ErrorCode.AGENT_ADDR_ALREADY_REGISTERED,\n            )\n            self.context.outbox.put_message(message=error_msg)\n            return\n\n        if agent_name in game.registration.agent_addr_to_name.values():\n            self.context.logger.warning(\n                \"agent with this name already registered: '{}'\".format(agent_name)\n            )\n            error_msg = tac_dialogue.reply(\n                performative=TacMessage.Performative.TAC_ERROR,\n                target_message=tac_msg,\n                error_code=TacMessage.ErrorCode.AGENT_NAME_ALREADY_REGISTERED,\n            )\n            self.context.outbox.put_message(message=error_msg)\n            return\n\n        game.registration.register_agent(tac_msg.sender, agent_name)\n        self.context.logger.info(\n            \"agent '{}' registered as '{}'\".format(tac_msg.sender, agent_name)\n        )\n\n    def _on_unregister(self, tac_msg: TacMessage, tac_dialogue: TacDialogue) -> None:\n        \"\"\"\n        Handle a unregister message.\n\n        If the address is not registered, answer with an error message.\n\n        :param tac_msg: the tac message\n        :param tac_dialogue: the tac dialogue\n        \"\"\"\n        game = cast(Game, self.context.game)\n        if not game.phase == Phase.GAME_REGISTRATION:\n            self.context.logger.warning(\n                \"received unregister outside of game registration phase: '{}'\".format(\n                    tac_msg\n                )\n            )\n            return\n\n        if tac_msg.sender not in game.registration.agent_addr_to_name:\n            self.context.logger.warning(\n                \"agent not registered: '{}'\".format(tac_msg.sender)\n            )\n            error_msg = tac_dialogue.reply(\n                performative=TacMessage.Performative.TAC_ERROR,\n                target_message=tac_msg,\n                error_code=TacMessage.ErrorCode.AGENT_NOT_REGISTERED,\n            )\n            self.context.outbox.put_message(message=error_msg)\n        else:\n            self.context.logger.debug(\n                \"agent unregistered: '{}'\".format(\n                    game.conf.agent_addr_to_name[tac_msg.sender],\n                )\n            )\n            game.registration.unregister_agent(tac_msg.sender)\n\n    def _on_transaction(self, tac_msg: TacMessage, tac_dialogue: TacDialogue) -> None:\n        \"\"\"\n        Handle a transaction TacMessage message.\n\n        If the transaction is invalid (e.g. because the state of the game are not consistent), reply with an error.\n\n        :param tac_msg: the tac message\n        :param tac_dialogue: the tac dialogue\n        \"\"\"\n        game = cast(Game, self.context.game)\n        if not game.phase == Phase.GAME:\n            self.context.logger.warning(\n                \"received transaction outside of game phase: '{}'\".format(tac_msg)\n            )\n            return\n\n        transaction = Transaction.from_message(tac_msg)\n        self.context.logger.debug(\"handling transaction: {}\".format(transaction))\n\n        game = cast(Game, self.context.game)\n        if game.is_transaction_valid(transaction):\n            self._handle_valid_transaction(tac_msg, tac_dialogue, transaction)\n        else:\n            self._handle_invalid_transaction(tac_msg, tac_dialogue)\n\n    def _handle_valid_transaction(\n        self, tac_msg: TacMessage, tac_dialogue: TacDialogue, transaction: Transaction\n    ) -> None:\n        \"\"\"\n        Handle a valid transaction.\n\n        That is:\n        - update the game state\n        - send a transaction confirmation both to the buyer and the seller.\n\n        :param tac_msg: the message\n        :param tac_dialogue: the fipa dialogue\n        :param transaction: the transaction.\n        \"\"\"\n        game = cast(Game, self.context.game)\n        self.context.logger.info(\n            \"handling valid transaction: {}\".format(transaction.id[-10:])\n        )\n        game.settle_transaction(transaction)\n\n        # send the transaction confirmation.\n        sender_tac_msg = tac_dialogue.reply(\n            performative=TacMessage.Performative.TRANSACTION_CONFIRMATION,\n            target_message=tac_msg,\n            transaction_id=transaction.sender_hash,\n            amount_by_currency_id=transaction.amount_by_currency_id,\n            quantities_by_good_id=transaction.quantities_by_good_id,\n        )\n        self.context.outbox.put_message(message=sender_tac_msg)\n\n        tac_dialogues = cast(TacDialogues, self.context.tac_dialogues)\n        recovered_tac_dialogues = tac_dialogues.get_dialogues_with_counterparty(\n            transaction.counterparty_address\n        )\n        if len(recovered_tac_dialogues) != 1:\n            raise ValueError(\"Error when retrieving dialogue.\")\n        recovered_tac_dialogue = recovered_tac_dialogues[0]\n        last_msg = recovered_tac_dialogue.last_message\n        if last_msg is None:\n            raise ValueError(\"Error when retrieving last message.\")\n        counterparty_tac_msg = recovered_tac_dialogue.reply(\n            performative=TacMessage.Performative.TRANSACTION_CONFIRMATION,\n            target_message=last_msg,\n            transaction_id=transaction.counterparty_hash,\n            amount_by_currency_id=transaction.amount_by_currency_id,\n            quantities_by_good_id=transaction.quantities_by_good_id,\n        )\n        self.context.outbox.put_message(message=counterparty_tac_msg)\n\n        # log messages\n        self.context.logger.info(\n            \"transaction '{}' between '{}' and '{}' settled successfully.\".format(\n                transaction.id[-10:], sender_tac_msg.sender, counterparty_tac_msg.sender\n            )\n        )\n        self.context.logger.info(\n            \"total number of transactions settled: {}\".format(\n                len(game.transactions.confirmed)\n            )\n        )\n        self.context.logger.info(\"current state:\\n{}\".format(game.holdings_summary))\n\n    def _handle_invalid_transaction(\n        self, tac_msg: TacMessage, tac_dialogue: TacDialogue\n    ) -> None:\n        \"\"\"Handle an invalid transaction.\"\"\"\n        self.context.logger.info(\n            \"handling invalid transaction: {}, tac_msg={}\".format(\n                tac_msg.transaction_id, tac_msg\n            )\n        )\n        error_msg = tac_dialogue.reply(\n            performative=TacMessage.Performative.TAC_ERROR,\n            target_message=tac_msg,\n            error_code=TacMessage.ErrorCode.TRANSACTION_NOT_VALID,\n            info={\"transaction_id\": tac_msg.transaction_id},\n        )\n        self.context.outbox.put_message(message=error_msg)\n\n    def _handle_invalid(self, tac_msg: TacMessage, tac_dialogue: TacDialogue) -> None:\n        \"\"\"\n        Handle a tac message of invalid performative.\n\n        :param tac_msg: the message\n        :param tac_dialogue: the fipa dialogue\n        \"\"\"\n        self.context.logger.warning(\n            \"cannot handle tac message of performative={} in dialogue={}.\".format(\n                tac_msg.performative, tac_dialogue\n            )\n        )\n\n\nclass OefSearchHandler(Handler):\n    \"\"\"Handle the message exchange with the OEF search node.\"\"\"\n\n    SUPPORTED_PROTOCOL = OefSearchMessage.protocol_id\n\n    def setup(self) -> None:\n        \"\"\"Implement the handler setup.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to a message.\n\n        :param message: the message\n        \"\"\"\n        oef_search_msg = cast(OefSearchMessage, message)\n\n        # recover dialogue\n        oef_search_dialogues = cast(\n            OefSearchDialogues, self.context.oef_search_dialogues\n        )\n        oef_search_dialogue = cast(\n            Optional[OefSearchDialogue], oef_search_dialogues.update(oef_search_msg)\n        )\n        if oef_search_dialogue is None:\n            self._handle_unidentified_dialogue(oef_search_msg)\n            return\n\n        # handle message\n        if oef_search_msg.performative == OefSearchMessage.Performative.SUCCESS:\n            self._handle_success(oef_search_msg, oef_search_dialogue)\n        elif oef_search_msg.performative == OefSearchMessage.Performative.OEF_ERROR:\n            self._handle_error(oef_search_msg, oef_search_dialogue)\n        else:\n            self._handle_invalid(oef_search_msg, oef_search_dialogue)\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n\n    def _handle_unidentified_dialogue(self, oef_search_msg: OefSearchMessage) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param oef_search_msg: the message\n        \"\"\"\n        self.context.logger.info(\n            \"received invalid oef_search message={}, unidentified dialogue.\".format(\n                oef_search_msg\n            )\n        )\n\n    def _handle_success(\n        self,\n        oef_search_success_msg: OefSearchMessage,\n        oef_search_dialogue: OefSearchDialogue,\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param oef_search_success_msg: the oef search message\n        :param oef_search_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.info(\n            \"received oef_search success message={} in dialogue={}.\".format(\n                oef_search_success_msg, oef_search_dialogue\n            )\n        )\n        target_message = cast(\n            OefSearchMessage,\n            oef_search_dialogue.get_message_by_id(oef_search_success_msg.target),\n        )\n        if (\n            target_message.performative\n            == OefSearchMessage.Performative.REGISTER_SERVICE\n        ):\n            description = target_message.service_description\n            data_model_name = description.data_model.name\n            registration_behaviour = cast(\n                TacBehaviour,\n                self.context.behaviours.tac,\n            )\n            if \"location_agent\" in data_model_name:\n                registration_behaviour.register_genus()\n            elif (\n                \"personality_agent\" in data_model_name\n                and description.values[\"piece\"] == \"genus\"\n            ):\n                registration_behaviour.register_classification()\n            elif (\n                \"personality_agent\" in data_model_name\n                and description.values[\"piece\"] == \"classification\"\n            ):\n                game = cast(Game, self.context.game)\n                game.is_registered_agent = True\n                self.context.logger.info(\n                    \"the agent, with its genus and classification, is successfully registered on the SOEF.\"\n                )\n            else:\n                self.context.logger.warning(\n                    f\"received soef SUCCESS message as a reply to the following unexpected message: {target_message}\"\n                )\n\n    def _handle_error(\n        self,\n        oef_search_error_msg: OefSearchMessage,\n        oef_search_dialogue: OefSearchDialogue,\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param oef_search_error_msg: the oef search message\n        :param oef_search_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.info(\n            \"received oef_search error message={} in dialogue={}.\".format(\n                oef_search_error_msg, oef_search_dialogue\n            )\n        )\n        target_message = cast(\n            OefSearchMessage,\n            oef_search_dialogue.get_message_by_id(oef_search_error_msg.target),\n        )\n        if (\n            target_message.performative\n            == OefSearchMessage.Performative.REGISTER_SERVICE\n        ):\n            registration_behaviour = cast(\n                TacBehaviour,\n                self.context.behaviours.tac,\n            )\n            registration_behaviour.failed_registration_msg = target_message\n\n    def _handle_invalid(\n        self, oef_search_msg: OefSearchMessage, oef_search_dialogue: OefSearchDialogue\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param oef_search_msg: the oef search message\n        :param oef_search_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.warning(\n            \"cannot handle oef_search message of performative={} in dialogue={}.\".format(\n                oef_search_msg.performative,\n                oef_search_dialogue,\n            )\n        )\n"
  },
  {
    "path": "packages/fetchai/skills/tac_control/helpers.py",
    "content": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the helpers methods for the controller agent.\"\"\"\n\nimport random\nfrom typing import Dict, List, Tuple, cast\n\nimport numpy as np\n\nfrom aea.exceptions import enforce\n\nfrom packages.fetchai.contracts.erc1155.contract import ERC1155Contract\n\n\nQUANTITY_SHIFT = 1  # Any non-negative integer is fine.\nFT_NAME = \"FT\"\nFT_ID = 2\n\n\ndef generate_good_ids(nb_goods: int, starting_index: int) -> List[int]:\n    \"\"\"\n    Generate ids for things.\n\n    :param nb_goods: the number of things.\n    :param starting_index: the index to start creating from.\n    :return: list of good ids\n    \"\"\"\n    good_ids = ERC1155Contract.generate_token_ids(FT_ID, nb_goods, starting_index)\n    enforce(\n        len(good_ids) == nb_goods, \"Length of good ids and number of goods must match.\"\n    )\n    return good_ids\n\n\ndef generate_currency_ids(nb_currencies: int, starting_index: int) -> List[int]:\n    \"\"\"\n    Generate currency ids.\n\n    :param nb_currencies: the number of currencies.\n    :param starting_index: the index to start creating from.\n    :return: list of currency ids\n    \"\"\"\n    currency_ids = ERC1155Contract.generate_token_ids(\n        FT_ID, nb_currencies, starting_index\n    )\n    enforce(\n        len(currency_ids) == nb_currencies,\n        \"Length of currency ids and number of currencies must match.\",\n    )\n    return currency_ids\n\n\ndef generate_currency_id_to_name(\n    nb_currencies: int, currency_ids: List[int], starting_index: int = 0\n) -> Dict[str, str]:\n    \"\"\"\n    Generate a dictionary mapping good ids to names.\n\n    :param nb_currencies: the number of currencies.\n    :param currency_ids: the currency ids\n    :param starting_index: the starting index\n    :return: a dictionary mapping currency's ids to names.\n    \"\"\"\n    if currency_ids != []:\n        enforce(\n            len(currency_ids) == nb_currencies,\n            \"Length of currency_ids does not match nb_currencies.\",\n        )\n    else:\n        currency_ids = generate_currency_ids(nb_currencies, starting_index)\n    currency_id_to_name = {\n        str(currency_id): \"{}_{}\".format(FT_NAME, currency_id)\n        for currency_id in currency_ids\n    }\n    return currency_id_to_name\n\n\ndef generate_good_id_to_name(\n    nb_goods: int, good_ids: List[int], starting_index: int = 0\n) -> Dict[str, str]:\n    \"\"\"\n    Generate a dictionary mapping good ids to names.\n\n    :param nb_goods: the number of things.\n    :param good_ids: a list of good ids\n    :param starting_index: the starting index\n    :return: a dictionary mapping goods' ids to names.\n    \"\"\"\n    if good_ids != []:\n        enforce(\n            len(good_ids) == nb_goods, \"Length of good_ids does not match nb_goods.\"\n        )\n    else:\n        good_ids = generate_good_ids(nb_goods, starting_index)\n    good_id_to_name = {\n        str(good_id): \"{}_{}\".format(FT_NAME, good_id) for good_id in good_ids\n    }\n    return good_id_to_name\n\n\ndef determine_scaling_factor(money_endowment: int) -> float:\n    \"\"\"\n    Compute the scaling factor based on the money amount.\n\n    :param money_endowment: the endowment of money for the agent\n    :return: the scaling factor\n    \"\"\"\n    scaling_factor = 10.0 ** (len(str(money_endowment)) - 1)\n    return scaling_factor\n\n\ndef generate_good_endowments(\n    agent_addresses: List[str],\n    good_ids: List[str],\n    base_amount: int,\n    uniform_lower_bound_factor: int,\n    uniform_upper_bound_factor: int,\n) -> Dict[str, Dict[str, int]]:\n    \"\"\"\n    Compute good endowments per agent. That is, a matrix of shape (nb_agents, nb_goods).\n\n    :param agent_addresses: the addresses of the agents\n    :param good_ids: the list of good ids\n    :param base_amount: the base amount of instances per good\n    :param uniform_lower_bound_factor: the lower bound of the uniform distribution for the sampling of the good instance number.\n    :param uniform_upper_bound_factor: the upper bound of the uniform distribution for the sampling of the good instance number.\n    :return: the endowments matrix.\n    \"\"\"\n    # sample good instances\n    nb_agents = len(agent_addresses)\n    instances_per_good = _sample_good_instances(\n        nb_agents,\n        good_ids,\n        base_amount,\n        uniform_lower_bound_factor,\n        uniform_upper_bound_factor,\n    )\n    # each agent receives at least base amount of each good\n    base_assignment = {good_id: base_amount for good_id in good_ids}\n    endowments = {agent_addr: base_assignment for agent_addr in agent_addresses}\n    # randomly assign additional goods to create differences\n    for good_id in good_ids:\n        for _ in range(instances_per_good[good_id] - (base_amount * nb_agents)):\n            idx = random.randint(0, nb_agents - 1)  # nosec\n            agent_addr = agent_addresses[idx]\n            endowments[agent_addr][good_id] += 1\n    return endowments\n\n\ndef generate_utility_params(\n    agent_addresses: List[str], good_ids: List[str], scaling_factor: float\n) -> Dict[str, Dict[str, float]]:\n    \"\"\"\n    Compute the preference matrix. That is, a generic element e_ij is the utility of good j for agent i.\n\n    :param agent_addresses: the agent addresses\n    :param good_ids: the list of good ids\n    :param scaling_factor: a scaling factor for all the utility params generated.\n    :return: the preference matrix.\n    \"\"\"\n    decimals = 4 if len(good_ids) < 100 else 8\n    utility_function_params = {}  # type: Dict[str, Dict[str, float]]\n    for agent_addr in agent_addresses:\n        random_integers = [\n            random.randint(1, 101) for _ in range(len(good_ids))  # nosec\n        ]\n        total = sum(random_integers)\n        normalized_fractions = [\n            round(i / float(total), decimals) for i in random_integers\n        ]\n        if not sum(normalized_fractions) == 1.0:  # pragma: no cover\n            normalized_fractions[-1] = round(\n                1.0 - sum(normalized_fractions[0:-1]), decimals\n            )\n        # scale the utility params\n        params = {\n            good_id: param * scaling_factor\n            for good_id, param in zip(good_ids, normalized_fractions)\n        }\n        utility_function_params[agent_addr] = params\n\n    return utility_function_params\n\n\ndef _sample_good_instances(\n    nb_agents: int,\n    good_ids: List[str],\n    base_amount: int,\n    uniform_lower_bound_factor: int,\n    uniform_upper_bound_factor: int,\n) -> Dict[str, int]:\n    \"\"\"\n    Sample the number of instances for a good.\n\n    :param nb_agents: the number of agents\n    :param good_ids: the good ids\n    :param base_amount: the base amount of instances per good\n    :param uniform_lower_bound_factor: the lower bound factor of a uniform distribution\n    :param uniform_upper_bound_factor: the upper bound factor of a uniform distribution\n    :return: the number of instances I sampled.\n    \"\"\"\n    a = base_amount * nb_agents + nb_agents * uniform_lower_bound_factor\n    b = base_amount * nb_agents + nb_agents * uniform_upper_bound_factor\n    # Return random integer in range [a, b]\n    nb_instances = {good_id: round(np.random.uniform(a, b)) for good_id in good_ids}\n    return nb_instances\n\n\ndef generate_currency_endowments(\n    agent_addresses: List[str], currency_ids: List[str], money_endowment: int\n) -> Dict[str, Dict[str, int]]:\n    \"\"\"\n    Compute the initial money amounts for each agent.\n\n    :param agent_addresses: addresses of the agents.\n    :param currency_ids: the currency ids.\n    :param money_endowment: money endowment per agent.\n    :return: the nested dict of currency endowments\n    \"\"\"\n    currency_endowment = {currency_id: money_endowment for currency_id in currency_ids}\n    return {agent_addr: currency_endowment for agent_addr in agent_addresses}\n\n\ndef generate_exchange_params(\n    agent_addresses: List[str],\n    currency_ids: List[str],\n) -> Dict[str, Dict[str, float]]:\n    \"\"\"\n    Compute the exchange parameters for each agent.\n\n    :param agent_addresses: addresses of the agents.\n    :param currency_ids: the currency ids.\n    :return: the nested dict of currency endowments\n    \"\"\"\n    exchange_params = {currency_id: 1.0 for currency_id in currency_ids}\n    return {agent_addr: exchange_params for agent_addr in agent_addresses}\n\n\ndef generate_equilibrium_prices_and_holdings(  # pylint: disable=unused-argument\n    agent_addr_to_good_endowments: Dict[str, Dict[str, int]],\n    agent_addr_to_utility_params: Dict[str, Dict[str, float]],\n    agent_addr_to_currency_endowments: Dict[str, Dict[str, int]],\n    agent_addr_to_exchange_params: Dict[str, Dict[str, float]],\n    scaling_factor: float,\n    quantity_shift: int = QUANTITY_SHIFT,\n) -> Tuple[Dict[str, float], Dict[str, Dict[str, float]], Dict[str, Dict[str, float]]]:\n    \"\"\"\n    Compute the competitive equilibrium prices and allocation.\n\n    :param agent_addr_to_good_endowments: endowments of the agents\n    :param agent_addr_to_utility_params: utility function params of the agents (already scaled)\n    :param agent_addr_to_currency_endowments: money endowment per agent.\n    :param agent_addr_to_exchange_params: exchange params per agent.\n    :param scaling_factor: a scaling factor for all the utility params generated.\n    :param quantity_shift: a factor to shift the quantities in the utility function (to ensure the natural logarithm can be used on the entire range of quantities)\n    :return: the lists of equilibrium prices, equilibrium good holdings and equilibrium money holdings\n    \"\"\"\n    # create ordered lists\n    agent_addresses = []  # type: List[str]\n    good_ids = []  # type: List[str]\n    good_ids_to_idx = {}  # type: Dict[str, int]\n    good_endowments_l = []  # type: List[List[int]]\n    utility_params_l = []  # type: List[List[float]]\n    currency_endowment_l = []  # type: List[int]\n    count = 0\n    currency_id = \"\"\n    for agent_addr, good_endowment in agent_addr_to_good_endowments.items():\n        agent_addresses.append(agent_addr)\n        enforce(\n            len(agent_addr_to_currency_endowments[agent_addr].values()) == 1,\n            \"Cannot have more than one currency.\",\n        )\n        currency_endowment_l.append(\n            list(agent_addr_to_currency_endowments[agent_addr].values())[0]\n        )\n        currency_id = list(agent_addr_to_currency_endowments[agent_addr].keys())[0]\n        enforce(\n            len(good_endowment.keys())\n            == len(agent_addr_to_utility_params[agent_addr].keys()),\n            \"Good endowments and utility params inconsistent.\",\n        )\n        temp_g_e = [0] * len(good_endowment.keys())\n        temp_u_p = [0.0] * len(agent_addr_to_utility_params[agent_addr].keys())\n        idx = 0\n        for good_id, quantity in good_endowment.items():\n            if count == 0:\n                good_ids.append(good_id)\n                good_ids_to_idx[good_id] = idx\n                idx += 1\n            temp_g_e[good_ids_to_idx[good_id]] = quantity\n            temp_u_p[good_ids_to_idx[good_id]] = agent_addr_to_utility_params[\n                agent_addr\n            ][good_id]\n        count += 1\n        good_endowments_l.append(temp_g_e)\n        utility_params_l.append(temp_u_p)\n\n    # maths\n    endowments_a = np.array(good_endowments_l, dtype=int)  # type: ignore\n    scaled_utility_params_a = np.array(  # type: ignore\n        utility_params_l, dtype=float  # type: ignore\n    )  # note, they are already scaled\n    endowments_by_good = np.sum(endowments_a, axis=0)\n    scaled_params_by_good = np.sum(scaled_utility_params_a, axis=0)\n    eq_prices = np.divide(\n        scaled_params_by_good,\n        quantity_shift * len(agent_addresses) + endowments_by_good,\n    )\n    eq_good_holdings = np.divide(scaled_utility_params_a, eq_prices) - quantity_shift\n    eq_currency_holdings = (\n        np.transpose(np.dot(eq_prices, np.transpose(endowments_a + quantity_shift)))\n        + currency_endowment_l\n        - scaling_factor\n    )\n\n    # back to dicts\n    eq_prices_dict = {\n        good_id: cast(float, eq_price)\n        for good_id, eq_price in zip(good_ids, eq_prices.tolist())\n    }\n    eq_good_holdings_dict = {\n        agent_addr: {good_id: cast(float, v) for good_id, v in zip(good_ids, egh)}\n        for agent_addr, egh in zip(agent_addresses, eq_good_holdings.tolist())\n    }\n    eq_currency_holdings_dict = {\n        agent_addr: {currency_id: cast(float, eq_currency_holding)}\n        for agent_addr, eq_currency_holding in zip(\n            agent_addresses, eq_currency_holdings.tolist()\n        )\n    }\n    return eq_prices_dict, eq_good_holdings_dict, eq_currency_holdings_dict\n"
  },
  {
    "path": "packages/fetchai/skills/tac_control/parameters.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains a class representing the game parameters.\"\"\"\n\nimport datetime\nfrom typing import Any, Dict, List, Optional, Set\n\nfrom aea.exceptions import AEAEnforceError, enforce\nfrom aea.helpers.search.models import Location\nfrom aea.skills.base import Model\n\nfrom packages.fetchai.contracts.erc1155.contract import PUBLIC_ID as CONTRACT_ID\nfrom packages.fetchai.skills.tac_control.helpers import (\n    generate_currency_id_to_name,\n    generate_good_id_to_name,\n)\n\n\nDEFAULT_MIN_NB_AGENTS = 2\nDEFAULT_MONEY_ENDOWMENT = 200\nDEFAULT_NB_GOODS = 9  # ERC1155 vyper contract only accepts 10 tokens per mint/create\nDEFAULT_NB_CURRENCIES = 1\nDEFAULT_TX_FEE = 1\nDEFAULT_GAS = 5000000\nDEFAULT_BASE_GOOD_ENDOWMENT = 2\nDEFAULT_LOWER_BOUND_FACTOR = 1\nDEFAULT_UPPER_BOUND_FACTOR = 1\nDEFAULT_REGISTRATION_START_TIME = \"01 01 2020  00:01\"\nDEFAULT_REGISTRATION_TIMEOUT = 60\nDEFAULT_ITEM_SETUP_TIMEOUT = 60\nDEFAULT_COMPETITION_TIMEOUT = 300\nDEFAULT_INACTIVITY_TIMEOUT = 30\nDEFAULT_LOCATION = {\"longitude\": 0.1270, \"latitude\": 51.5194}\nDEFAULT_SERVICE_DATA = {\"key\": \"tac\", \"value\": \"v1\"}\nDEFAULT_PERSONALITY_DATA = {\"piece\": \"genus\", \"value\": \"service\"}\nDEFAULT_CLASSIFICATION = {\"piece\": \"classification\", \"value\": \"tac.controller\"}\n\n\nclass Parameters(Model):\n    \"\"\"This class contains the parameters of the game.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"Instantiate the parameter class.\"\"\"\n        ledger_id = kwargs.pop(\"ledger_id\", None)\n        self._contract_address = kwargs.pop(\n            \"contract_address\", None\n        )  # type: Optional[str]\n        self._good_ids = kwargs.pop(\"good_ids\", [])  # type: List[int]\n        self._currency_ids = kwargs.pop(\"currency_ids\", [])  # type: List[int]\n        self._min_nb_agents = kwargs.pop(\n            \"min_nb_agents\", DEFAULT_MIN_NB_AGENTS\n        )  # type: int\n        self._money_endowment = kwargs.pop(\n            \"money_endowment\", DEFAULT_MONEY_ENDOWMENT\n        )  # type: int\n        self._nb_goods = kwargs.pop(\"nb_goods\", DEFAULT_NB_GOODS)  # type: int\n        self._nb_currencies = kwargs.pop(\n            \"nb_currencies\", DEFAULT_NB_CURRENCIES\n        )  # type: int\n        self._tx_fee = kwargs.pop(\"tx_fee\", DEFAULT_TX_FEE)  # type: int\n        self._gas = kwargs.pop(\"gas\", DEFAULT_GAS)  # type: int\n        self._base_good_endowment = kwargs.pop(\n            \"base_good_endowment\", DEFAULT_BASE_GOOD_ENDOWMENT\n        )  # type: int\n        self._lower_bound_factor = kwargs.pop(\n            \"lower_bound_factor\", DEFAULT_LOWER_BOUND_FACTOR\n        )  # type: int\n        self._upper_bound_factor = kwargs.pop(\n            \"upper_bound_factor\", DEFAULT_UPPER_BOUND_FACTOR\n        )  # type: int\n        registration_start_time = kwargs.pop(\n            \"registration_start_time\", DEFAULT_REGISTRATION_START_TIME\n        )  # type: str\n        self._registration_start_time = datetime.datetime.strptime(\n            registration_start_time, \"%d %m %Y %H:%M\"\n        )  # type: datetime.datetime\n        self._registration_timeout = kwargs.pop(\n            \"registration_timeout\", DEFAULT_REGISTRATION_TIMEOUT\n        )  # type: int\n        self._item_setup_timeout = kwargs.pop(\n            \"item_setup_timeout\", DEFAULT_ITEM_SETUP_TIMEOUT\n        )  # type: int\n        self._competition_timeout = kwargs.pop(\n            \"competition_timeout\", DEFAULT_COMPETITION_TIMEOUT\n        )  # type: int\n        self._inactivity_timeout = kwargs.pop(\n            \"inactivity_timeout\", DEFAULT_INACTIVITY_TIMEOUT\n        )  # type: int\n        self._whitelist = set(kwargs.pop(\"whitelist\", []))  # type: Set[str]\n        self._location = kwargs.pop(\"location\", DEFAULT_LOCATION)\n        self._service_data = kwargs.pop(\"service_data\", DEFAULT_SERVICE_DATA)\n        enforce(\n            len(self._service_data) == 2\n            and \"key\" in self._service_data\n            and \"value\" in self._service_data,\n            \"service_data must contain keys `key` and `value`\",\n        )\n        self._version_id = self._service_data[\"value\"]  # type: str\n\n        self._agent_location = {\n            \"location\": Location(\n                latitude=self._location[\"latitude\"],\n                longitude=self._location[\"longitude\"],\n            )\n        }\n        self._set_personality_data = kwargs.pop(\n            \"personality_data\", DEFAULT_PERSONALITY_DATA\n        )\n        enforce(\n            len(self._set_personality_data) == 2\n            and \"piece\" in self._set_personality_data\n            and \"value\" in self._set_personality_data,\n            \"personality_data must contain keys `key` and `value`\",\n        )\n        self._set_classification = kwargs.pop(\"classification\", DEFAULT_CLASSIFICATION)\n        enforce(\n            len(self._set_classification) == 2\n            and \"piece\" in self._set_classification\n            and \"value\" in self._set_classification,\n            \"classification must contain keys `key` and `value`\",\n        )\n        self._set_service_data = self._service_data\n        self._remove_service_data = {\"key\": self._service_data[\"key\"]}\n        self._simple_service_data = {\n            self._service_data[\"key\"]: self._service_data[\"value\"]\n        }\n\n        super().__init__(**kwargs)\n        self._ledger_id = (\n            ledger_id if ledger_id is not None else self.context.default_ledger_id\n        )\n        self._contract_id = str(CONTRACT_ID)\n        self._currency_id_to_name = generate_currency_id_to_name(\n            self.nb_currencies, self.currency_ids\n        )\n        self._good_id_to_name = generate_good_id_to_name(\n            self.nb_goods, self.good_ids, starting_index=1\n        )\n        self._registration_end_time = (\n            self._registration_start_time\n            + datetime.timedelta(seconds=self._registration_timeout)\n        )\n        self._start_time = self._registration_end_time + datetime.timedelta(\n            seconds=self._item_setup_timeout\n        )\n        self._end_time = self._start_time + datetime.timedelta(\n            seconds=self._competition_timeout\n        )\n        now = datetime.datetime.now()\n        if now > self.registration_start_time:\n            self.context.logger.warning(\n                \"TAC registration start time {} is in the past! Deregistering skill.\".format(\n                    self.registration_start_time\n                )\n            )\n            self.context.is_active = False\n        else:\n            self.context.logger.info(\n                \"TAC registation start time: {}, and registration end time: {}, and start time: {}, and end time: {}\".format(\n                    self.registration_start_time,\n                    self.registration_end_time,\n                    self.start_time,\n                    self.end_time,\n                )\n            )\n        self._check_consistency()\n\n    @property\n    def ledger_id(self) -> str:\n        \"\"\"Get the ledger identifier.\"\"\"\n        return self._ledger_id\n\n    @property\n    def contract_address(self) -> str:\n        \"\"\"The contract address of an already deployed smart-contract.\"\"\"\n        if self._contract_address is None:\n            raise AEAEnforceError(\"No contract address provided.\")\n        return self._contract_address\n\n    @contract_address.setter\n    def contract_address(self, contract_address: str) -> None:\n        \"\"\"Set contract address of an already deployed smart-contract.\"\"\"\n        if self._contract_address is not None:\n            raise AEAEnforceError(\"Contract address already provided.\")\n        self._contract_address = contract_address\n\n    @property\n    def contract_id(self) -> str:\n        \"\"\"Get the contract id.\"\"\"\n        return self._contract_id\n\n    @property\n    def is_contract_deployed(self) -> bool:\n        \"\"\"Check if there is a deployed instance of the contract.\"\"\"\n        return self._contract_address is not None\n\n    @property\n    def good_ids(self) -> List[int]:\n        \"\"\"The item ids of an already deployed smart-contract.\"\"\"\n        return self._good_ids\n\n    @property\n    def currency_ids(self) -> List[int]:\n        \"\"\"The currency ids of an already deployed smart-contract.\"\"\"\n        return self._currency_ids\n\n    @property\n    def min_nb_agents(self) -> int:\n        \"\"\"Minimum number of agents required for a TAC instance.\"\"\"\n        return self._min_nb_agents\n\n    @property\n    def money_endowment(self) -> int:\n        \"\"\"Money endowment per agent for a TAC instance.\"\"\"\n        return self._money_endowment\n\n    @property\n    def nb_goods(self) -> int:\n        \"\"\"Good number for a TAC instance.\"\"\"\n        return self._nb_goods\n\n    @property\n    def nb_currencies(self) -> int:\n        \"\"\"Currency number for a TAC instance.\"\"\"\n        return self._nb_currencies\n\n    @property\n    def currency_id_to_name(self) -> Dict[str, str]:\n        \"\"\"Mapping of currency ids to names\"\"\"\n        return self._currency_id_to_name\n\n    @property\n    def good_id_to_name(self) -> Dict[str, str]:\n        \"\"\"Mapping of good ids to names.\"\"\"\n        return self._good_id_to_name\n\n    @property\n    def tx_fee(self) -> int:\n        \"\"\"Transaction fee for a TAC instance.\"\"\"\n        return self._tx_fee\n\n    @property\n    def gas(self) -> int:\n        \"\"\"Gas for TAC contract operations.\"\"\"\n        return self._gas\n\n    @property\n    def base_good_endowment(self) -> int:\n        \"\"\"Minimum endowment of each agent for each good.\"\"\"\n        return self._base_good_endowment\n\n    @property\n    def lower_bound_factor(self) -> int:\n        \"\"\"Lower bound of a uniform distribution.\"\"\"\n        return self._lower_bound_factor\n\n    @property\n    def upper_bound_factor(self) -> int:\n        \"\"\"Upper bound of a uniform distribution.\"\"\"\n        return self._upper_bound_factor\n\n    @property\n    def registration_start_time(self) -> datetime.datetime:\n        \"\"\"TAC registration start time.\"\"\"\n        return self._registration_start_time\n\n    @property\n    def registration_end_time(self) -> datetime.datetime:\n        \"\"\"TAC registration end time.\"\"\"\n        return self._registration_end_time\n\n    @property\n    def start_time(self) -> datetime.datetime:\n        \"\"\"TAC start time.\"\"\"\n        return self._start_time\n\n    @property\n    def end_time(self) -> datetime.datetime:\n        \"\"\"TAC end time.\"\"\"\n        return self._end_time\n\n    @property\n    def inactivity_timeout(self) -> int:\n        \"\"\"Timeout of agent inactivity from controller perspective (no received transactions).\"\"\"\n        return self._inactivity_timeout\n\n    @property\n    def whitelist(self) -> Set[str]:\n        \"\"\"Whitelist of agent addresses allowed into the TAC instance.\"\"\"\n        return self._whitelist\n\n    @property\n    def version_id(self) -> str:\n        \"\"\"Version id.\"\"\"\n        return self._version_id\n\n    @property\n    def agent_location(self) -> Dict[str, Location]:\n        \"\"\"Get the agent location.\"\"\"\n        return self._agent_location\n\n    @property\n    def set_service_data(self) -> Dict[str, str]:\n        \"\"\"Get the set service data.\"\"\"\n        return self._set_service_data\n\n    @property\n    def set_personality_data(self) -> Dict[str, str]:\n        \"\"\"Get the set service data.\"\"\"\n        return self._set_personality_data\n\n    @property\n    def set_classification(self) -> Dict[str, str]:\n        \"\"\"Get the set service data.\"\"\"\n        return self._set_classification\n\n    @property\n    def remove_service_data(self) -> Dict[str, str]:\n        \"\"\"Get the remove service data.\"\"\"\n        return self._remove_service_data\n\n    @property\n    def simple_service_data(self) -> Dict[str, str]:\n        \"\"\"Get the simple service data.\"\"\"\n        return self._simple_service_data\n\n    def _check_consistency(self) -> None:\n        \"\"\"Check the parameters are consistent.\"\"\"\n        if self._contract_address is not None and (\n            (self._good_ids is not None and len(self._good_ids) != self._nb_goods)\n            or (\n                self._currency_ids is not None\n                and len(self._currency_ids) != self._nb_currencies\n            )\n        ):\n            raise ValueError(\n                \"If the contract address is set, then good ids and currency id must be provided and consistent.\"\n            )\n"
  },
  {
    "path": "packages/fetchai/skills/tac_control/skill.yaml",
    "content": "name: tac_control\nauthor: fetchai\nversion: 0.25.6\ntype: skill\ndescription: The tac control skill implements the logic for an AEA to control an instance\n  of the TAC.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: QmdQcAgQ21CSovduTzvhf1nsxwQZWTYkDAc9Tfsz6gXWMh\n  __init__.py: QmQLj6yg3zW6EBiRVLbZVqQojUSEJPcxwqMjFmUeyxkiAn\n  behaviours.py: QmNmcawRFT6NEFCWpwECwE7bbX7ZnVVZXDLDeP5pKiQSZr\n  dialogues.py: QmQWmTQKxhNV9A8B4h2dfmy917LCut3PY7Ny61nJvdxJPH\n  game.py: QmVsUWKiNaQL3Fv58Huqf2BCTePApxkXiedqGMYgJvXyXE\n  handlers.py: QmYdCncGTRQgdi5XB6VdjKZ7oBtphXKt3atrdYM2VtHU6N\n  helpers.py: QmZByC5bR7Fz7K6eDS9Ccu7jMajUPcnQT6KSQouMmHLR13\n  parameters.py: QmVuYzxPYenwTGUcswCuXC912AeZLaSYb9Sr2Tu3R4chvK\nfingerprint_ignore_patterns: []\nconnections: []\ncontracts:\n- fetchai/erc1155:0.23.3\nprotocols:\n- fetchai/default:1.1.7\n- fetchai/oef_search:1.1.7\n- fetchai/tac:1.1.7\nskills: []\nbehaviours:\n  tac:\n    args:\n      max_soef_registration_retries: 5\n    class_name: TacBehaviour\nhandlers:\n  oef:\n    args: {}\n    class_name: OefSearchHandler\n  tac:\n    args: {}\n    class_name: TacHandler\nmodels:\n  default_dialogues:\n    args: {}\n    class_name: DefaultDialogues\n  game:\n    args: {}\n    class_name: Game\n  oef_search_dialogues:\n    args: {}\n    class_name: OefSearchDialogues\n  parameters:\n    args:\n      base_good_endowment: 2\n      classification:\n        piece: classification\n        value: tac.controller\n      competition_timeout: 180\n      currency_ids: []\n      good_ids: []\n      inactivity_timeout: 60\n      item_setup_timeout: 0\n      location:\n        latitude: 51.5194\n        longitude: 0.127\n      lower_bound_factor: 1\n      min_nb_agents: 2\n      money_endowment: 2000000\n      nb_currencies: 1\n      nb_goods: 9\n      personality_data:\n        piece: genus\n        value: service\n      registration_start_time: 01 01 2020  00:01\n      registration_timeout: 60\n      service_data:\n        key: tac\n        value: v1\n      tx_fee: 1\n      upper_bound_factor: 1\n      whitelist: []\n    class_name: Parameters\n  tac_dialogues:\n    args: {}\n    class_name: TacDialogues\ndependencies:\n  aea-ledger-ethereum:\n    version: <2.0.0,>=1.0.0\n  aea-ledger-fetchai:\n    version: <2.0.0,>=1.0.0\n  numpy: {}\nis_abstract: false\n"
  },
  {
    "path": "packages/fetchai/skills/tac_control_contract/README.md",
    "content": "# TAC Control Contract\n\n## Description\n\nThis is the skill for managing a smart contract-based TAC.\n\nThis skill is part of the Fetch.ai TAC demo. It manages the smart contract (contract deployment, creating tokens, minting tokens) and manages the progression of the competition along its various stages.\n\n## Behaviours\n\n- `tac`:  deploys smart contract, manages progression of the competition\n\n## Handlers\n\n- `contract_api`: handles `contract_api` messages for interaction with a smart contract\n- `ledger_api`: handles `ledger_api` messages for interacting with a ledger\n- `oef`: handles `oef_search` messages if registration or unregistration on the sOEF is unsuccessful\n- `signing`: handles `signing` messages for interaction with the decision maker\n- `tac`: handles `tac` messages for registering/unregistering agents in the TAC\n\n## Links\n\n- <a href=\"https://docs.fetch.ai/aea/tac-skills-contract/\" target=\"_blank\">TAC Demo</a>\n"
  },
  {
    "path": "packages/fetchai/skills/tac_control_contract/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the implementation of the tac control skill.\"\"\"\n\nfrom aea.configurations.base import PublicId\n\n\nPUBLIC_ID = PublicId.from_str(\"fetchai/tac_control_contract:0.27.6\")\n"
  },
  {
    "path": "packages/fetchai/skills/tac_control_contract/behaviours.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This package contains the behaviours.\"\"\"\n\nimport datetime\nfrom typing import List, cast\n\nfrom packages.fetchai.connections.ledger.base import (\n    CONNECTION_ID as LEDGER_CONNECTION_PUBLIC_ID,\n)\nfrom packages.fetchai.protocols.contract_api.message import ContractApiMessage\nfrom packages.fetchai.skills.tac_control.behaviours import (\n    TacBehaviour as BaseTacBehaviour,\n)\nfrom packages.fetchai.skills.tac_control_contract.dialogues import (\n    ContractApiDialogue,\n    ContractApiDialogues,\n)\nfrom packages.fetchai.skills.tac_control_contract.game import Game, Phase\nfrom packages.fetchai.skills.tac_control_contract.parameters import Parameters\n\n\nLEDGER_API_ADDRESS = str(LEDGER_CONNECTION_PUBLIC_ID)\nFETCHAI_LEDGER_ID = \"fetchai\"\n\n\nclass TacBehaviour(BaseTacBehaviour):\n    \"\"\"This class implements the TAC control behaviour.\"\"\"\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup.\"\"\"\n        super().setup()\n        parameters = cast(Parameters, self.context.parameters)\n        if not parameters.is_contract_deployed:\n            game = cast(Game, self.context.game)\n            game.phase = Phase.CONTRACT_DEPLOYMENT_PROPOSAL\n            self._request_contract_deploy_transaction()\n\n    def _request_contract_deploy_transaction(self) -> None:\n        \"\"\"Request contract deploy transaction\"\"\"\n        parameters = cast(Parameters, self.context.parameters)\n        contract_api_dialogues = cast(\n            ContractApiDialogues, self.context.contract_api_dialogues\n        )\n        kwargs = {\n            \"deployer_address\": self.context.agent_address,\n            \"gas\": parameters.gas,\n        }\n        if parameters.ledger_id == FETCHAI_LEDGER_ID:\n            kwargs[\"tx_fee\"] = parameters.contract_deploy_tx_fee\n        contract_api_msg, contract_api_dialogue = contract_api_dialogues.create(\n            counterparty=LEDGER_API_ADDRESS,\n            performative=ContractApiMessage.Performative.GET_DEPLOY_TRANSACTION,\n            ledger_id=parameters.ledger_id,\n            contract_id=parameters.contract_id,\n            callable=ContractApiDialogue.Callable.GET_DEPLOY_TRANSACTION.value,\n            kwargs=ContractApiMessage.Kwargs(kwargs),  # type: ignore\n        )\n        contract_api_dialogue = cast(\n            ContractApiDialogue,\n            contract_api_dialogue,\n        )\n        contract_api_dialogue.terms = parameters.get_deploy_terms()\n        contract_api_dialogue.callable = (\n            ContractApiDialogue.Callable.GET_DEPLOY_TRANSACTION\n        )\n        self.context.outbox.put_message(message=contract_api_msg)\n        self.context.logger.info(\"requesting contract deployment transaction...\")\n\n    def act(self) -> None:\n        \"\"\"Implement the act.\"\"\"\n        game = cast(Game, self.context.game)\n        parameters = cast(Parameters, self.context.parameters)\n        now = datetime.datetime.now()\n        if (\n            game.phase.value == Phase.CONTRACT_DEPLOYED.value\n            and parameters.registration_start_time\n            < now\n            < parameters.registration_end_time\n        ):\n            game.phase = Phase.GAME_REGISTRATION\n            self._register_tac()\n            self.context.logger.info(\n                \"TAC open for registration until: {}\".format(\n                    parameters.registration_end_time\n                )\n            )\n        elif (\n            game.phase.value == Phase.GAME_REGISTRATION.value\n            and parameters.registration_end_time < now < parameters.start_time\n        ):\n            self.context.logger.info(\"closing registration!\")\n            if game.registration.nb_agents < parameters.min_nb_agents:\n                self.context.logger.info(\n                    \"registered agents={}, minimum agents required={}\".format(\n                        game.registration.nb_agents,\n                        parameters.min_nb_agents,\n                    )\n                )\n                self._cancel_tac(game)\n                game.phase = Phase.POST_GAME\n                self._unregister_tac()\n                self.context.is_active = False\n            else:\n                game.phase = Phase.GAME_SETUP\n                game.create()\n                game.conf.contract_address = parameters.contract_address\n                self._unregister_tac()\n        elif (\n            game.phase.value == Phase.GAME_SETUP.value\n            and parameters.registration_end_time < now < parameters.start_time\n        ):\n            game.phase = Phase.TOKENS_CREATION_PROPOSAL\n            self._request_create_items_transaction(game)\n        elif game.phase.value == Phase.TOKENS_CREATED.value:\n            game.phase = Phase.TOKENS_MINTING_PROPOSAL\n            self._request_mint_items_transaction(game)\n        elif game.phase.value == Phase.TOKENS_MINTING_PROPOSAL.value:\n            self._request_mint_items_transaction(game)\n        elif (\n            game.phase.value == Phase.TOKENS_MINTED.value\n            and parameters.start_time < now < parameters.end_time\n        ):\n            game.phase = Phase.GAME\n            self._start_tac(game)\n        elif game.phase.value == Phase.GAME.value and now > parameters.end_time:\n            game.phase = Phase.POST_GAME\n            self._cancel_tac(game)\n            self.context.is_active = False\n\n    def _request_create_items_transaction(self, game: Game) -> None:\n        \"\"\"\n        Request token create transaction\n\n        :param game: the game\n        \"\"\"\n        parameters = cast(Parameters, self.context.parameters)\n        contract_api_dialogues = cast(\n            ContractApiDialogues, self.context.contract_api_dialogues\n        )\n        token_ids = [int(good_id) for good_id in game.conf.good_id_to_name.keys()] + [\n            int(currency_id) for currency_id in game.conf.currency_id_to_name.keys()\n        ]\n\n        kwargs = {\n            \"deployer_address\": self.context.agent_address,\n            \"token_ids\": token_ids,\n            \"gas\": parameters.gas,\n        }\n        if parameters.ledger_id == FETCHAI_LEDGER_ID:\n            kwargs[\"tx_fee\"] = parameters.contract_execute_tx_fee\n\n        contract_api_msg, contract_api_dialogue = contract_api_dialogues.create(\n            counterparty=LEDGER_API_ADDRESS,\n            performative=ContractApiMessage.Performative.GET_RAW_TRANSACTION,\n            ledger_id=parameters.ledger_id,\n            contract_id=parameters.contract_id,\n            contract_address=parameters.contract_address,\n            callable=ContractApiDialogue.Callable.GET_CREATE_BATCH_TRANSACTION.value,\n            kwargs=ContractApiMessage.Kwargs(kwargs),  # type: ignore\n        )\n        contract_api_dialogue = cast(ContractApiDialogue, contract_api_dialogue)\n        contract_api_dialogue.terms = parameters.get_create_token_terms()\n        contract_api_dialogue.callable = (\n            ContractApiDialogue.Callable.GET_CREATE_BATCH_TRANSACTION\n        )\n        self.context.outbox.put_message(message=contract_api_msg)\n        self.context.logger.info(\"requesting create items transaction...\")\n\n    def _request_mint_items_transaction(self, game: Game) -> None:\n        \"\"\"\n        Request token mint transaction\n\n        :param game: the game\n        \"\"\"\n        if not game.is_allowed_to_mint:\n            return\n        game.is_allowed_to_mint = False\n        agent_state = game.get_next_agent_state_for_minting()\n        if agent_state is None:\n            return\n        name = game.registration.agent_addr_to_name[agent_state.agent_address]\n        self.context.logger.info(\n            f\"requesting mint_items transactions for agent={name}.\"\n        )\n        parameters = cast(Parameters, self.context.parameters)\n        token_ids = []  # type: List[int]\n        mint_quantities = []  # type: List[int]\n        for good_id, quantity in agent_state.quantities_by_good_id.items():\n            token_ids.append(int(good_id))\n            mint_quantities.append(quantity)\n        for currency_id, amount in agent_state.amount_by_currency_id.items():\n            token_ids.append(int(currency_id))\n            mint_quantities.append(amount)\n        contract_api_dialogues = cast(\n            ContractApiDialogues, self.context.contract_api_dialogues\n        )\n        kwargs = {\n            \"deployer_address\": self.context.agent_address,\n            \"recipient_address\": agent_state.agent_address,\n            \"token_ids\": token_ids,\n            \"mint_quantities\": mint_quantities,\n            \"gas\": parameters.gas,\n        }\n\n        if parameters.ledger_id == FETCHAI_LEDGER_ID:\n            kwargs[\"tx_fee\"] = parameters.contract_execute_tx_fee  # type: ignore\n\n        contract_api_msg, contract_api_dialogue = contract_api_dialogues.create(\n            counterparty=LEDGER_API_ADDRESS,\n            performative=ContractApiMessage.Performative.GET_RAW_TRANSACTION,\n            ledger_id=parameters.ledger_id,\n            contract_id=parameters.contract_id,\n            contract_address=parameters.contract_address,\n            callable=ContractApiDialogue.Callable.GET_MINT_BATCH_TRANSACTION.value,\n            kwargs=ContractApiMessage.Kwargs(kwargs),  # type: ignore\n        )\n        contract_api_dialogue = cast(ContractApiDialogue, contract_api_dialogue)\n        contract_api_dialogue.terms = parameters.get_mint_token_terms()\n        contract_api_dialogue.callable = (\n            ContractApiDialogue.Callable.GET_MINT_BATCH_TRANSACTION\n        )\n        self.context.outbox.put_message(message=contract_api_msg)\n"
  },
  {
    "path": "packages/fetchai/skills/tac_control_contract/dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nThis module contains the classes required for dialogue management.\n\n- DefaultDialogue: The dialogue class maintains state of a dialogue of type default and manages it.\n- DefaultDialogues: The dialogues class keeps track of all dialogues of type default.\n- OefSearchDialogue: The dialogue class maintains state of a dialogue of type oef_search and manages it.\n- OefSearchDialogues: The dialogues class keeps track of all dialogues of type oef_search.\n- TacDialogue: The dialogue class maintains state of a dialogue of type tac and manages it.\n- TacDialogues: The dialogues class keeps track of all dialogues of type tac.\n\"\"\"\n\nfrom enum import Enum\nfrom typing import Any, Optional, Type\n\nfrom aea.common import Address\nfrom aea.exceptions import enforce\nfrom aea.helpers.transaction.base import Terms\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\nfrom aea.protocols.dialogue.base import DialogueLabel as BaseDialogueLabel\nfrom aea.skills.base import Model\n\nfrom packages.fetchai.protocols.contract_api.dialogues import (\n    ContractApiDialogue as BaseContractApiDialogue,\n)\nfrom packages.fetchai.protocols.contract_api.dialogues import (\n    ContractApiDialogues as BaseContractApiDialogues,\n)\nfrom packages.fetchai.protocols.contract_api.message import ContractApiMessage\nfrom packages.fetchai.protocols.ledger_api.dialogues import (\n    LedgerApiDialogue as BaseLedgerApiDialogue,\n)\nfrom packages.fetchai.protocols.ledger_api.dialogues import (\n    LedgerApiDialogues as BaseLedgerApiDialogues,\n)\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\nfrom packages.fetchai.protocols.signing.dialogues import (\n    SigningDialogue as BaseSigningDialogue,\n)\nfrom packages.fetchai.protocols.signing.dialogues import (\n    SigningDialogues as BaseSigningDialogues,\n)\nfrom packages.fetchai.protocols.signing.message import SigningMessage\nfrom packages.fetchai.skills.tac_control.dialogues import (\n    DefaultDialogue as BaseDefaultDialogue,\n)\nfrom packages.fetchai.skills.tac_control.dialogues import (\n    DefaultDialogues as BaseDefaultDialogues,\n)\nfrom packages.fetchai.skills.tac_control.dialogues import (\n    OefSearchDialogue as BaseOefSearchDialogue,\n)\nfrom packages.fetchai.skills.tac_control.dialogues import (\n    OefSearchDialogues as BaseOefSearchDialogues,\n)\nfrom packages.fetchai.skills.tac_control.dialogues import TacDialogue as BaseTacDialogue\nfrom packages.fetchai.skills.tac_control.dialogues import (\n    TacDialogues as BaseTacDialogues,\n)\n\n\nDefaultDialogue = BaseDefaultDialogue\n\nDefaultDialogues = BaseDefaultDialogues\n\nOefSearchDialogue = BaseOefSearchDialogue\n\nOefSearchDialogues = BaseOefSearchDialogues\n\nTacDialogue = BaseTacDialogue\n\nTacDialogues = BaseTacDialogues\n\n\nclass ContractApiDialogue(BaseContractApiDialogue):\n    \"\"\"The dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    __slots__ = (\"_terms\", \"_callable\")\n\n    class Callable(Enum):\n        \"\"\"Contract callable.\"\"\"\n\n        GET_DEPLOY_TRANSACTION = \"get_deploy_transaction\"\n        GET_CREATE_BATCH_TRANSACTION = \"get_create_batch_transaction\"\n        GET_MINT_BATCH_TRANSACTION = \"get_mint_batch_transaction\"\n\n    def __init__(\n        self,\n        dialogue_label: BaseDialogueLabel,\n        self_address: Address,\n        role: BaseDialogue.Role,\n        message_class: Type[ContractApiMessage] = ContractApiMessage,\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n        :param message_class: the message class\n        \"\"\"\n        BaseContractApiDialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            self_address=self_address,\n            role=role,\n            message_class=message_class,\n        )\n        self._terms = None  # type: Optional[Terms]\n        self._callable = None  # type: Optional[ContractApiDialogue.Callable]\n\n    @property\n    def callable(self) -> \"Callable\":\n        \"\"\"Get the callable.\"\"\"\n        if self._callable is None:\n            raise ValueError(\"Callable not set!\")\n        return self._callable\n\n    @callable.setter\n    def callable(  # pylint: disable=redefined-builtin\n        self, callable: \"Callable\"\n    ) -> None:\n        \"\"\"Set the callable.\"\"\"\n        enforce(self._callable is None, \"Callable already set!\")\n        self._callable = callable\n\n    @property\n    def terms(self) -> Terms:\n        \"\"\"Get the terms.\"\"\"\n        if self._terms is None:\n            raise ValueError(\"Terms not set!\")\n        return self._terms\n\n    @terms.setter\n    def terms(self, terms: Terms) -> None:\n        \"\"\"Set the terms.\"\"\"\n        enforce(self._terms is None, \"Terms already set!\")\n        self._terms = terms\n\n\nclass ContractApiDialogues(Model, BaseContractApiDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return ContractApiDialogue.Role.AGENT\n\n        BaseContractApiDialogues.__init__(\n            self,\n            self_address=str(self.skill_id),\n            role_from_first_message=role_from_first_message,\n            dialogue_class=ContractApiDialogue,\n        )\n\n\nclass SigningDialogue(BaseSigningDialogue):\n    \"\"\"The dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    __slots__ = (\"_associated_contract_api_dialogue\",)\n\n    def __init__(\n        self,\n        dialogue_label: BaseDialogueLabel,\n        self_address: Address,\n        role: BaseDialogue.Role,\n        message_class: Type[SigningMessage] = SigningMessage,\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n        :param message_class: the message class\n        \"\"\"\n        BaseSigningDialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            self_address=self_address,\n            role=role,\n            message_class=message_class,\n        )\n        self._associated_contract_api_dialogue = (\n            None\n        )  # type: Optional[ContractApiDialogue]\n\n    @property\n    def associated_contract_api_dialogue(self) -> ContractApiDialogue:\n        \"\"\"Get the associated contract api dialogue.\"\"\"\n        if self._associated_contract_api_dialogue is None:\n            raise ValueError(\"Associated contract api dialogue not set!\")\n        return self._associated_contract_api_dialogue\n\n    @associated_contract_api_dialogue.setter\n    def associated_contract_api_dialogue(\n        self, associated_contract_api_dialogue: ContractApiDialogue\n    ) -> None:\n        \"\"\"Set the associated contract api dialogue.\"\"\"\n        enforce(\n            self._associated_contract_api_dialogue is None,\n            \"Associated contract api dialogue already set!\",\n        )\n        self._associated_contract_api_dialogue = associated_contract_api_dialogue\n\n\nclass SigningDialogues(Model, BaseSigningDialogues):\n    \"\"\"This class keeps track of all oef_search dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return BaseSigningDialogue.Role.SKILL\n\n        BaseSigningDialogues.__init__(\n            self,\n            self_address=str(self.skill_id),\n            role_from_first_message=role_from_first_message,\n            dialogue_class=SigningDialogue,\n        )\n\n\nclass LedgerApiDialogue(BaseLedgerApiDialogue):\n    \"\"\"The dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    __slots__ = (\"_associated_signing_dialogue\",)\n\n    def __init__(\n        self,\n        dialogue_label: BaseDialogueLabel,\n        self_address: Address,\n        role: BaseDialogue.Role,\n        message_class: Type[LedgerApiMessage] = LedgerApiMessage,\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n        :param message_class: the message class\n        \"\"\"\n        BaseLedgerApiDialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            self_address=self_address,\n            role=role,\n            message_class=message_class,\n        )\n        self._associated_signing_dialogue = None  # type: Optional[SigningDialogue]\n\n    @property\n    def associated_signing_dialogue(self) -> \"SigningDialogue\":\n        \"\"\"Get the associated signing dialogue.\"\"\"\n        if self._associated_signing_dialogue is None:\n            raise ValueError(\"Associated signing dialogue not set!\")\n        return self._associated_signing_dialogue\n\n    @associated_signing_dialogue.setter\n    def associated_signing_dialogue(\n        self, associated_signing_dialogue: \"SigningDialogue\"\n    ) -> None:\n        \"\"\"Set the associated signing dialogue.\"\"\"\n        enforce(\n            self._associated_signing_dialogue is None,\n            \"Associated signing dialogue already set!\",\n        )\n        self._associated_signing_dialogue = associated_signing_dialogue\n\n\nclass LedgerApiDialogues(Model, BaseLedgerApiDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return BaseLedgerApiDialogue.Role.AGENT\n\n        BaseLedgerApiDialogues.__init__(\n            self,\n            self_address=str(self.skill_id),\n            role_from_first_message=role_from_first_message,\n            dialogue_class=LedgerApiDialogue,\n        )\n"
  },
  {
    "path": "packages/fetchai/skills/tac_control_contract/game.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains a class representing the game.\"\"\"\n\nfrom packages.fetchai.skills.tac_control.game import AgentState as BaseAgentState\nfrom packages.fetchai.skills.tac_control.game import Configuration as BaseConfiguration\nfrom packages.fetchai.skills.tac_control.game import Game as BaseGame\nfrom packages.fetchai.skills.tac_control.game import (\n    Initialization as BaseInitialization,\n)\nfrom packages.fetchai.skills.tac_control.game import Phase as BasePhase\nfrom packages.fetchai.skills.tac_control.game import Registration as BaseRegistration\nfrom packages.fetchai.skills.tac_control.game import Transaction as BaseTransaction\nfrom packages.fetchai.skills.tac_control.game import Transactions as BaseTransactions\n\n\nAgentState = BaseAgentState\n\n\nConfiguration = BaseConfiguration\n\n\nGame = BaseGame\n\n\nInitialization = BaseInitialization\n\n\nPhase = BasePhase\n\n\nRegistration = BaseRegistration\n\n\nTransaction = BaseTransaction\n\n\nTransactions = BaseTransactions\n"
  },
  {
    "path": "packages/fetchai/skills/tac_control_contract/handlers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains the handlers.\"\"\"\n\nfrom typing import Optional, cast\n\nfrom aea_ledger_fetchai import FetchAIApi\n\nfrom aea.common import JSONLike\nfrom aea.configurations.base import PublicId\nfrom aea.crypto.ledger_apis import LedgerApis\nfrom aea.protocols.base import Message\nfrom aea.skills.base import Handler\n\nfrom packages.fetchai.connections.ledger.base import (\n    CONNECTION_ID as LEDGER_CONNECTION_PUBLIC_ID,\n)\nfrom packages.fetchai.protocols.signing.message import SigningMessage\nfrom packages.fetchai.skills.tac_control.handlers import (\n    OefSearchHandler as BaseOefSearchHandler,\n)\nfrom packages.fetchai.skills.tac_control.handlers import TacHandler as BaseTacHandler\nfrom packages.fetchai.skills.tac_control_contract.dialogues import (\n    ContractApiDialogue,\n    ContractApiDialogues,\n    ContractApiMessage,\n    LedgerApiDialogue,\n    LedgerApiDialogues,\n    LedgerApiMessage,\n    SigningDialogue,\n    SigningDialogues,\n)\nfrom packages.fetchai.skills.tac_control_contract.game import Game, Phase\nfrom packages.fetchai.skills.tac_control_contract.parameters import Parameters\n\n\nLEDGER_API_ADDRESS = str(LEDGER_CONNECTION_PUBLIC_ID)\n\n\nTacHandler = BaseTacHandler\n\n\nOefSearchHandler = BaseOefSearchHandler\n\n\nclass ContractApiHandler(Handler):\n    \"\"\"Implement the contract api handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = ContractApiMessage.protocol_id  # type: Optional[PublicId]\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup for the handler.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to a message.\n\n        :param message: the message\n        \"\"\"\n        contract_api_msg = cast(ContractApiMessage, message)\n\n        # recover dialogue\n        contract_api_dialogues = cast(\n            ContractApiDialogues, self.context.contract_api_dialogues\n        )\n        contract_api_dialogue = cast(\n            Optional[ContractApiDialogue],\n            contract_api_dialogues.update(contract_api_msg),\n        )\n        if contract_api_dialogue is None:\n            self._handle_unidentified_dialogue(contract_api_msg)\n            return\n\n        # handle message\n        if (\n            contract_api_msg.performative\n            is ContractApiMessage.Performative.RAW_TRANSACTION\n        ):\n            self._handle_raw_transaction(contract_api_msg, contract_api_dialogue)\n        elif contract_api_msg.performative == ContractApiMessage.Performative.ERROR:\n            self._handle_error(contract_api_msg, contract_api_dialogue)\n        else:\n            self._handle_invalid(contract_api_msg, contract_api_dialogue)\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n\n    def _handle_unidentified_dialogue(\n        self, contract_api_msg: ContractApiMessage\n    ) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param contract_api_msg: the message\n        \"\"\"\n        self.context.logger.info(\n            \"received invalid contract_api message={}, unidentified dialogue.\".format(\n                contract_api_msg\n            )\n        )\n\n    def _handle_raw_transaction(\n        self,\n        contract_api_msg: ContractApiMessage,\n        contract_api_dialogue: ContractApiDialogue,\n    ) -> None:\n        \"\"\"\n        Handle a message of raw_transaction performative.\n\n        :param contract_api_msg: the ledger api message\n        :param contract_api_dialogue: the ledger api dialogue\n        \"\"\"\n        self.context.logger.info(\"received raw transaction={}\".format(contract_api_msg))\n        signing_dialogues = cast(SigningDialogues, self.context.signing_dialogues)\n        signing_msg, signing_dialogue = signing_dialogues.create(\n            counterparty=self.context.decision_maker_address,\n            performative=SigningMessage.Performative.SIGN_TRANSACTION,\n            raw_transaction=contract_api_msg.raw_transaction,\n            terms=contract_api_dialogue.terms,\n        )\n        signing_dialogue = cast(SigningDialogue, signing_dialogue)\n        signing_dialogue.associated_contract_api_dialogue = contract_api_dialogue\n        self.context.decision_maker_message_queue.put_nowait(signing_msg)\n        self.context.logger.info(\n            \"proposing the transaction to the decision maker. Waiting for confirmation ...\"\n        )\n\n    def _handle_error(\n        self,\n        contract_api_msg: ContractApiMessage,\n        contract_api_dialogue: ContractApiDialogue,\n    ) -> None:\n        \"\"\"\n        Handle a message of error performative.\n\n        :param contract_api_msg: the ledger api message\n        :param contract_api_dialogue: the ledger api dialogue\n        \"\"\"\n        self.context.logger.info(\n            \"received contract_api error message={} in dialogue={}.\".format(\n                contract_api_msg, contract_api_dialogue\n            )\n        )\n\n    def _handle_invalid(\n        self,\n        contract_api_msg: ContractApiMessage,\n        contract_api_dialogue: ContractApiDialogue,\n    ) -> None:\n        \"\"\"\n        Handle a message of invalid performative.\n\n        :param contract_api_msg: the ledger api message\n        :param contract_api_dialogue: the ledger api dialogue\n        \"\"\"\n        self.context.logger.warning(\n            \"cannot handle contract_api message of performative={} in dialogue={}.\".format(\n                contract_api_msg.performative,\n                contract_api_dialogue,\n            )\n        )\n\n\nclass SigningHandler(Handler):\n    \"\"\"Implement the transaction handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = SigningMessage.protocol_id  # type: Optional[PublicId]\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup for the handler.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to a message.\n\n        :param message: the message\n        \"\"\"\n        signing_msg = cast(SigningMessage, message)\n\n        # recover dialogue\n        signing_dialogues = cast(SigningDialogues, self.context.signing_dialogues)\n        signing_dialogue = cast(\n            Optional[SigningDialogue], signing_dialogues.update(signing_msg)\n        )\n        if signing_dialogue is None:\n            self._handle_unidentified_dialogue(signing_msg)\n            return\n\n        # handle message\n        if signing_msg.performative is SigningMessage.Performative.SIGNED_TRANSACTION:\n            self._handle_signed_transaction(signing_msg, signing_dialogue)\n        elif signing_msg.performative is SigningMessage.Performative.ERROR:\n            self._handle_error(signing_msg, signing_dialogue)\n        else:\n            self._handle_invalid(signing_msg, signing_dialogue)\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n\n    def _handle_unidentified_dialogue(self, signing_msg: SigningMessage) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param signing_msg: the message\n        \"\"\"\n        self.context.logger.info(\n            \"received invalid signing message={}, unidentified dialogue.\".format(\n                signing_msg\n            )\n        )\n\n    def _handle_signed_transaction(\n        self, signing_msg: SigningMessage, signing_dialogue: SigningDialogue\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param signing_msg: the signing message\n        :param signing_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.info(\"transaction signing was successful.\")\n        ledger_api_dialogues = cast(\n            LedgerApiDialogues, self.context.ledger_api_dialogues\n        )\n        ledger_api_msg, ledger_api_dialogue = ledger_api_dialogues.create(\n            counterparty=LEDGER_API_ADDRESS,\n            performative=LedgerApiMessage.Performative.SEND_SIGNED_TRANSACTION,\n            signed_transaction=signing_msg.signed_transaction,\n        )\n        ledger_api_dialogue = cast(LedgerApiDialogue, ledger_api_dialogue)\n        ledger_api_dialogue.associated_signing_dialogue = signing_dialogue\n        self.context.outbox.put_message(message=ledger_api_msg)\n        self.context.logger.info(\"sending transaction to ledger.\")\n\n    def _handle_error(\n        self, signing_msg: SigningMessage, signing_dialogue: SigningDialogue\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param signing_msg: the signing message\n        :param signing_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.info(\n            \"transaction signing was not successful. Error_code={} in dialogue={}\".format(\n                signing_msg.error_code, signing_dialogue\n            )\n        )\n\n    def _handle_invalid(\n        self, signing_msg: SigningMessage, signing_dialogue: SigningDialogue\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param signing_msg: the signing message\n        :param signing_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.warning(\n            \"cannot handle signing message of performative={} in dialogue={}.\".format(\n                signing_msg.performative, signing_dialogue\n            )\n        )\n\n\nclass LedgerApiHandler(Handler):\n    \"\"\"Implement the ledger api handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = LedgerApiMessage.protocol_id  # type: Optional[PublicId]\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup for the handler.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to a message.\n\n        :param message: the message\n        \"\"\"\n        ledger_api_msg = cast(LedgerApiMessage, message)\n\n        # recover dialogue\n        ledger_api_dialogues = cast(\n            LedgerApiDialogues, self.context.ledger_api_dialogues\n        )\n        ledger_api_dialogue = cast(\n            Optional[LedgerApiDialogue], ledger_api_dialogues.update(ledger_api_msg)\n        )\n        if ledger_api_dialogue is None:\n            self._handle_unidentified_dialogue(ledger_api_msg)\n            return\n\n        # handle message\n        if ledger_api_msg.performative is LedgerApiMessage.Performative.BALANCE:\n            self._handle_balance(ledger_api_msg)\n        elif (\n            ledger_api_msg.performative\n            is LedgerApiMessage.Performative.TRANSACTION_DIGEST\n        ):\n            self._handle_transaction_digest(ledger_api_msg, ledger_api_dialogue)\n        elif (\n            ledger_api_msg.performative\n            is LedgerApiMessage.Performative.TRANSACTION_RECEIPT\n        ):\n            self._handle_transaction_receipt(ledger_api_msg, ledger_api_dialogue)\n        elif ledger_api_msg.performative == LedgerApiMessage.Performative.ERROR:\n            self._handle_error(ledger_api_msg, ledger_api_dialogue)\n        else:\n            self._handle_invalid(ledger_api_msg, ledger_api_dialogue)\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n\n    def _handle_unidentified_dialogue(self, ledger_api_msg: LedgerApiMessage) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param ledger_api_msg: the message\n        \"\"\"\n        self.context.logger.info(\n            \"received invalid ledger_api message={}, unidentified dialogue.\".format(\n                ledger_api_msg\n            )\n        )\n\n    def _handle_balance(self, ledger_api_msg: LedgerApiMessage) -> None:\n        \"\"\"\n        Handle a message of balance performative.\n\n        :param ledger_api_msg: the ledger api message\n        \"\"\"\n        self.context.logger.info(\n            \"starting balance on {} ledger={}.\".format(\n                ledger_api_msg.ledger_id,\n                ledger_api_msg.balance,\n            )\n        )\n\n    def _handle_transaction_digest(\n        self, ledger_api_msg: LedgerApiMessage, ledger_api_dialogue: LedgerApiDialogue\n    ) -> None:\n        \"\"\"\n        Handle a message of transaction_digest performative.\n\n        :param ledger_api_msg: the ledger api message\n        :param ledger_api_dialogue: the ledger api dialogue\n        \"\"\"\n        self.context.logger.info(\n            \"transaction was successfully submitted. Transaction digest={}\".format(\n                ledger_api_msg.transaction_digest\n            )\n        )\n        msg = ledger_api_dialogue.reply(\n            performative=LedgerApiMessage.Performative.GET_TRANSACTION_RECEIPT,\n            target_message=ledger_api_msg,\n            transaction_digest=ledger_api_msg.transaction_digest,\n        )\n        self.context.outbox.put_message(message=msg)\n        self.context.logger.info(\"requesting transaction receipt.\")\n\n    def _request_init_transaction(\n        self, ledger_id: str, deployment_tx_receipt: JSONLike\n    ) -> None:\n        \"\"\"\n        Send a message to request the initialisation transaction to finalise contract deployment on fetch ledger\n\n        :param ledger_id: the ledger id\n        :param deployment_tx_receipt: the transaction receipt\n        \"\"\"\n        parameters = cast(Parameters, self.context.parameters)\n        contract_api_dialogues = cast(\n            ContractApiDialogues, self.context.contract_api_dialogues\n        )\n        fetchai_api = cast(FetchAIApi, LedgerApis.get_api(ledger_id))\n        code_id = fetchai_api.get_code_id(deployment_tx_receipt)  # type: Optional[int]\n        if code_id:\n            contract_api_msg, dialogue = contract_api_dialogues.create(\n                counterparty=LEDGER_API_ADDRESS,\n                performative=ContractApiMessage.Performative.GET_DEPLOY_TRANSACTION,\n                ledger_id=parameters.ledger_id,\n                contract_id=parameters.contract_id,\n                callable=ContractApiDialogue.Callable.GET_DEPLOY_TRANSACTION.value,\n                kwargs=ContractApiMessage.Kwargs(\n                    {\n                        \"label\": \"TACERC1155\",\n                        \"init_msg\": {},\n                        \"gas\": parameters.gas,\n                        \"amount\": 0,\n                        \"code_id\": code_id,\n                        \"deployer_address\": self.context.agent_address,\n                        \"tx_fee\": parameters.contract_init_tx_fee,\n                    }\n                ),\n            )\n            contract_api_dialogue = cast(ContractApiDialogue, dialogue)\n            contract_api_dialogue.terms = parameters.get_deploy_terms(\n                is_init_transaction=True\n            )\n            contract_api_dialogue.callable = (\n                ContractApiDialogue.Callable.GET_DEPLOY_TRANSACTION\n            )\n            self.context.outbox.put_message(message=contract_api_msg)\n            self.context.logger.info(\n                \"requesting contract initialisation transaction...\"\n            )\n        else:  # pragma: nocover\n            self.context.logger.info(\"Failed to initialise contract: code_id not found\")\n\n    def _handle_transaction_receipt(\n        self, ledger_api_msg: LedgerApiMessage, ledger_api_dialogue: LedgerApiDialogue\n    ) -> None:\n        \"\"\"\n        Handle a message of transaction_receipt performative.\n\n        :param ledger_api_msg: the ledger api message\n        :param ledger_api_dialogue: the ledger api dialogue\n        \"\"\"\n        ledger_id = ledger_api_msg.transaction_receipt.ledger_id\n        tx_receipt = ledger_api_msg.transaction_receipt.receipt\n\n        is_transaction_successful = LedgerApis.is_transaction_settled(\n            ledger_id, tx_receipt\n        )\n\n        signing_dialogue = ledger_api_dialogue.associated_signing_dialogue\n        contract_api_dialogue = signing_dialogue.associated_contract_api_dialogue\n        if is_transaction_successful:\n            self.context.logger.info(\n                \"transaction was successfully settled. Transaction receipt={}\".format(\n                    ledger_api_msg.transaction_receipt\n                )\n            )\n            parameters = cast(Parameters, self.context.parameters)\n            game = cast(Game, self.context.game)\n            if (\n                contract_api_dialogue.callable\n                == ContractApiDialogue.Callable.GET_DEPLOY_TRANSACTION\n            ):\n                transaction_label = contract_api_dialogue.terms.kwargs.get(\n                    \"label\", None\n                )\n                if game.phase != Phase.CONTRACT_DEPLOYED:\n                    if (\n                        transaction_label == \"store\"\n                    ):  # deploying contract on fetch ledger\n                        self._request_init_transaction(ledger_id, tx_receipt)\n                    elif transaction_label in {\"deploy\", \"init\"}:\n                        contract_address = LedgerApis.get_contract_address(\n                            ledger_id, tx_receipt\n                        )\n                        if contract_address is None:\n                            raise ValueError(\n                                \"No contract address found.\"\n                            )  # pragma: nocover\n                        parameters.contract_address = contract_address\n                        game.phase = Phase.CONTRACT_DEPLOYED\n                        self.context.logger.info(\"contract deployed.\")\n                    else:\n                        self.context.logger.error(\n                            f\"Invalid transaction label: {transaction_label}\"\n                        )  # pragma: nocover\n            elif (\n                contract_api_dialogue.callable\n                == ContractApiDialogue.Callable.GET_CREATE_BATCH_TRANSACTION\n            ):\n                game.phase = Phase.TOKENS_CREATED\n                self.context.logger.info(\"tokens created.\")\n            elif (\n                contract_api_dialogue.callable\n                == ContractApiDialogue.Callable.GET_MINT_BATCH_TRANSACTION\n            ):\n                self.context.logger.info(\"tokens minted.\")\n                parameters.nb_completed_minting += 1\n                game.is_allowed_to_mint = True\n                if game.registration.nb_agents == parameters.nb_completed_minting:\n                    game.phase = Phase.TOKENS_MINTED\n                    self.context.logger.info(\"all tokens minted.\")\n            else:\n                self.context.logger.error(\"unexpected transaction receipt!\")\n        else:\n            self.context.logger.error(\n                \"transaction failed. Transaction receipt={}\".format(\n                    ledger_api_msg.transaction_receipt\n                )\n            )\n\n    def _handle_error(\n        self, ledger_api_msg: LedgerApiMessage, ledger_api_dialogue: LedgerApiDialogue\n    ) -> None:\n        \"\"\"\n        Handle a message of error performative.\n\n        :param ledger_api_msg: the ledger api message\n        :param ledger_api_dialogue: the ledger api dialogue\n        \"\"\"\n        self.context.logger.info(\n            \"received ledger_api error message={} in dialogue={}.\".format(\n                ledger_api_msg, ledger_api_dialogue\n            )\n        )\n\n    def _handle_invalid(\n        self, ledger_api_msg: LedgerApiMessage, ledger_api_dialogue: LedgerApiDialogue\n    ) -> None:\n        \"\"\"\n        Handle a message of invalid performative.\n\n        :param ledger_api_msg: the ledger api message\n        :param ledger_api_dialogue: the ledger api dialogue\n        \"\"\"\n        self.context.logger.warning(\n            \"cannot handle ledger_api message of performative={} in dialogue={}.\".format(\n                ledger_api_msg.performative,\n                ledger_api_dialogue,\n            )\n        )\n"
  },
  {
    "path": "packages/fetchai/skills/tac_control_contract/helpers.py",
    "content": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the helpers methods for the controller agent.\"\"\"\n\nimport random\nfrom typing import Dict, List, Tuple, cast\n\nimport numpy as np\n\nfrom aea.exceptions import enforce\n\nfrom packages.fetchai.contracts.erc1155.contract import ERC1155Contract\n\n\nQUANTITY_SHIFT = 1  # Any non-negative integer is fine.\nFT_NAME = \"FT\"\nFT_ID = 2\nNB_CURRENCIES = 1\n\n\ndef generate_good_id_to_name(good_ids: List[int]) -> Dict[str, str]:\n    \"\"\"\n    Generate a dictionary mapping good ids to names.\n\n    :param good_ids: a list of good ids\n    :return: a dictionary mapping goods' ids to names.\n    \"\"\"\n    good_id_to_name = {\n        str(good_id): \"{}_{}\".format(FT_NAME, good_id) for good_id in good_ids\n    }\n    return good_id_to_name\n\n\ndef generate_good_ids(nb_goods: int) -> List[int]:\n    \"\"\"\n    Generate ids for things.\n\n    :param nb_goods: the number of things.\n    :return: a list of good ids\n    \"\"\"\n    good_ids = ERC1155Contract.generate_token_ids(FT_ID, nb_goods)\n    enforce(\n        len(good_ids) == nb_goods, \"Length of good ids and number of goods must match.\"\n    )\n    return good_ids\n\n\ndef generate_currency_id_to_name(currency_ids: List[int]) -> Dict[str, str]:\n    \"\"\"\n    Generate a dictionary mapping good ids to names.\n\n    :param currency_ids: the currency ids\n    :return: a dictionary mapping currency's ids to names.\n    \"\"\"\n    currency_id_to_name = {\n        str(currency_id): \"{}_{}\".format(FT_NAME, currency_id)\n        for currency_id in currency_ids\n    }\n    return currency_id_to_name\n\n\ndef generate_currency_ids(nb_currencies: int) -> List[int]:\n    \"\"\"\n    Generate currency ids.\n\n    :param nb_currencies: the number of currencies.\n    :return: a list of currency ids\n    \"\"\"\n    currency_ids = ERC1155Contract.generate_token_ids(FT_ID, nb_currencies)\n    enforce(\n        len(currency_ids) == nb_currencies,\n        \"Length of currency ids and number of currencies must match.\",\n    )\n    return currency_ids\n\n\ndef determine_scaling_factor(money_endowment: int) -> float:\n    \"\"\"\n    Compute the scaling factor based on the money amount.\n\n    :param money_endowment: the endowment of money for the agent\n    :return: the scaling factor\n    \"\"\"\n    scaling_factor = 10.0 ** (len(str(money_endowment)) - 1)\n    return scaling_factor\n\n\ndef generate_good_endowments(\n    agent_addresses: List[str],\n    good_ids: List[str],\n    base_amount: int,\n    uniform_lower_bound_factor: int,\n    uniform_upper_bound_factor: int,\n) -> Dict[str, Dict[str, int]]:\n    \"\"\"\n    Compute good endowments per agent. That is, a matrix of shape (nb_agents, nb_goods).\n\n    :param agent_addresses: the addresses of the agents\n    :param good_ids: the list of good ids\n    :param base_amount: the base amount of instances per good\n    :param uniform_lower_bound_factor: the lower bound of the uniform distribution for the sampling of the good instance number.\n    :param uniform_upper_bound_factor: the upper bound of the uniform distribution for the sampling of the good instance number.\n    :return: the endowments matrix.\n    \"\"\"\n    # sample good instances\n    nb_agents = len(agent_addresses)\n    instances_per_good = _sample_good_instances(\n        nb_agents,\n        good_ids,\n        base_amount,\n        uniform_lower_bound_factor,\n        uniform_upper_bound_factor,\n    )\n    # each agent receives at least base amount of each good\n    base_assignment = {good_id: base_amount for good_id in good_ids}\n    endowments = {agent_addr: base_assignment for agent_addr in agent_addresses}\n    # randomly assign additional goods to create differences\n    for good_id in good_ids:\n        for _ in range(instances_per_good[good_id] - (base_amount * nb_agents)):\n            idx = random.randint(0, nb_agents - 1)  # nosec\n            agent_addr = agent_addresses[idx]\n            endowments[agent_addr][good_id] += 1\n    return endowments\n\n\ndef generate_utility_params(\n    agent_addresses: List[str], good_ids: List[str], scaling_factor: float\n) -> Dict[str, Dict[str, float]]:\n    \"\"\"\n    Compute the preference matrix. That is, a generic element e_ij is the utility of good j for agent i.\n\n    :param agent_addresses: the agent addresses\n    :param good_ids: the list of good ids\n    :param scaling_factor: a scaling factor for all the utility params generated.\n    :return: the preference matrix.\n    \"\"\"\n    decimals = 4 if len(good_ids) < 100 else 8\n    utility_function_params = {}  # type: Dict[str, Dict[str, float]]\n    for agent_addr in agent_addresses:\n        random_integers = [\n            random.randint(1, 101) for _ in range(len(good_ids))  # nosec\n        ]\n        total = sum(random_integers)\n        normalized_fractions = [\n            round(i / float(total), decimals) for i in random_integers\n        ]\n        if not sum(normalized_fractions) == 1.0:\n            normalized_fractions[-1] = round(  # pragma: no cover\n                1.0 - sum(normalized_fractions[0:-1]), decimals\n            )\n        # scale the utility params\n        params = {\n            good_id: param * scaling_factor\n            for good_id, param in zip(good_ids, normalized_fractions)\n        }\n        utility_function_params[agent_addr] = params\n\n    return utility_function_params\n\n\ndef _sample_good_instances(\n    nb_agents: int,\n    good_ids: List[str],\n    base_amount: int,\n    uniform_lower_bound_factor: int,\n    uniform_upper_bound_factor: int,\n) -> Dict[str, int]:\n    \"\"\"\n    Sample the number of instances for a good.\n\n    :param nb_agents: the number of agents\n    :param good_ids: the good ids\n    :param base_amount: the base amount of instances per good\n    :param uniform_lower_bound_factor: the lower bound factor of a uniform distribution\n    :param uniform_upper_bound_factor: the upper bound factor of a uniform distribution\n    :return: the number of instances I sampled.\n    \"\"\"\n    a = base_amount * nb_agents + nb_agents * uniform_lower_bound_factor\n    b = base_amount * nb_agents + nb_agents * uniform_upper_bound_factor\n    # Return random integer in range [a, b]\n    nb_instances = {good_id: round(np.random.uniform(a, b)) for good_id in good_ids}\n    return nb_instances\n\n\ndef generate_currency_endowments(\n    agent_addresses: List[str], currency_ids: List[str], money_endowment: int\n) -> Dict[str, Dict[str, int]]:\n    \"\"\"\n    Compute the initial money amounts for each agent.\n\n    :param agent_addresses: addresses of the agents.\n    :param currency_ids: the currency ids.\n    :param money_endowment: money endowment per agent.\n    :return: the nested dict of currency endowments\n    \"\"\"\n    currency_endowment = {currency_id: money_endowment for currency_id in currency_ids}\n    return {agent_addr: currency_endowment for agent_addr in agent_addresses}\n\n\ndef generate_exchange_params(\n    agent_addresses: List[str],\n    currency_ids: List[str],\n) -> Dict[str, Dict[str, float]]:\n    \"\"\"\n    Compute the exchange parameters for each agent.\n\n    :param agent_addresses: addresses of the agents.\n    :param currency_ids: the currency ids.\n    :return: the nested dict of currency endowments\n    \"\"\"\n    exchange_params = {currency_id: 1.0 for currency_id in currency_ids}\n    return {agent_addr: exchange_params for agent_addr in agent_addresses}\n\n\ndef generate_equilibrium_prices_and_holdings(  # pylint: disable=unused-argument\n    agent_addr_to_good_endowments: Dict[str, Dict[str, int]],\n    agent_addr_to_utility_params: Dict[str, Dict[str, float]],\n    agent_addr_to_currency_endowments: Dict[str, Dict[str, int]],\n    agent_addr_to_exchange_params: Dict[str, Dict[str, float]],\n    scaling_factor: float,\n    quantity_shift: int = QUANTITY_SHIFT,\n) -> Tuple[Dict[str, float], Dict[str, Dict[str, float]], Dict[str, float]]:\n    \"\"\"\n    Compute the competitive equilibrium prices and allocation.\n\n    :param agent_addr_to_good_endowments: endowments of the agents\n    :param agent_addr_to_utility_params: utility function params of the agents (already scaled)\n    :param agent_addr_to_currency_endowments: money endowment per agent.\n    :param agent_addr_to_exchange_params: exchange params per agent.\n    :param scaling_factor: a scaling factor for all the utility params generated.\n    :param quantity_shift: a factor to shift the quantities in the utility function (to ensure the natural logarithm can be used on the entire range of quantities)\n    :return: the lists of equilibrium prices, equilibrium good holdings and equilibrium money holdings\n    \"\"\"\n    # create ordered lists\n    agent_addresses = []  # type: List[str]\n    good_ids = []  # type: List[str]\n    good_ids_to_idx = {}  # type: Dict[str, int]\n    good_endowments_l = []  # type: List[List[int]]\n    utility_params_l = []  # type: List[List[float]]\n    currency_endowment_l = []  # type: List[int]\n    count = 0\n    for agent_addr, good_endowment in agent_addr_to_good_endowments.items():\n        agent_addresses.append(agent_addr)\n        enforce(\n            len(agent_addr_to_currency_endowments[agent_addr].values()) == 1,\n            \"Cannot have more than one currency.\",\n        )\n        currency_endowment_l.append(\n            list(agent_addr_to_currency_endowments[agent_addr].values())[0]\n        )\n        enforce(\n            len(good_endowment.keys())\n            == len(agent_addr_to_utility_params[agent_addr].keys()),\n            \"Good endowments and utility params inconsistent.\",\n        )\n        temp_g_e = [0] * len(good_endowment.keys())\n        temp_u_p = [0.0] * len(agent_addr_to_utility_params[agent_addr].keys())\n        idx = 0\n        for good_id, quantity in good_endowment.items():\n            if count == 0:\n                good_ids.append(good_id)\n                good_ids_to_idx[good_id] = idx\n                idx += 1\n            temp_g_e[good_ids_to_idx[good_id]] = quantity\n            temp_u_p[good_ids_to_idx[good_id]] = agent_addr_to_utility_params[\n                agent_addr\n            ][good_id]\n        count += 1\n        good_endowments_l.append(temp_g_e)\n        utility_params_l.append(temp_u_p)\n\n    # maths\n    endowments_a = np.array(good_endowments_l, dtype=int)  # type: ignore\n    scaled_utility_params_a = np.array(  # type: ignore\n        utility_params_l, dtype=float  # type: ignore\n    )  # note, they are already scaled\n    endowments_by_good = np.sum(endowments_a, axis=0)\n    scaled_params_by_good = np.sum(scaled_utility_params_a, axis=0)\n    eq_prices = np.divide(\n        scaled_params_by_good,\n        quantity_shift * len(agent_addresses) + endowments_by_good,\n    )\n    eq_good_holdings = np.divide(scaled_utility_params_a, eq_prices) - quantity_shift\n    eq_currency_holdings = (\n        np.transpose(np.dot(eq_prices, np.transpose(endowments_a + quantity_shift)))\n        + currency_endowment_l\n        - scaling_factor\n    )\n\n    # back to dicts\n    eq_prices_dict = {\n        good_id: cast(float, eq_price)\n        for good_id, eq_price in zip(good_ids, eq_prices.tolist())\n    }\n    eq_good_holdings_dict = {\n        agent_addr: {good_id: cast(float, v) for good_id, v in zip(good_ids, egh)}\n        for agent_addr, egh in zip(agent_addresses, eq_good_holdings.tolist())\n    }\n    eq_currency_holdings_dict = {\n        agent_addr: cast(float, eq_currency_holding)\n        for agent_addr, eq_currency_holding in zip(\n            agent_addresses, eq_currency_holdings.tolist()\n        )\n    }\n    return eq_prices_dict, eq_good_holdings_dict, eq_currency_holdings_dict\n"
  },
  {
    "path": "packages/fetchai/skills/tac_control_contract/parameters.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains a class representing the game parameters.\"\"\"\nfrom typing import Any\n\nfrom aea_ledger_ethereum import EthereumApi\nfrom aea_ledger_fetchai import FetchAIApi\n\nfrom aea.helpers.transaction.base import Terms\n\nfrom packages.fetchai.skills.tac_control.parameters import Parameters as BaseParameters\n\n\nDEFAULT_CONTRACT_DEPLOY_FEE = 2000000000000000\nDEFAULT_CONTRACT_INIT_FEE = 2000000000000000\nDEFAULT_CONTRACT_EXECUTE_FEE = 2000000000000000\n\n\nclass Parameters(BaseParameters):\n    \"\"\"This class contains the parameters of the game.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"Instantiate the parameter class.\"\"\"\n        super().__init__(**kwargs)\n        self.nb_completed_minting = 0\n        self._contract_init_tx_fee = kwargs.pop(\n            \"contract_init_tx_fee\", DEFAULT_CONTRACT_INIT_FEE\n        )  # type: int\n        self._contract_deploy_tx_fee = kwargs.pop(\n            \"contract_deploy_tx_fee\", DEFAULT_CONTRACT_DEPLOY_FEE\n        )  # type: int\n        self._contract_execute_tx_fee = kwargs.pop(\n            \"contract_execute_tx_fee\", DEFAULT_CONTRACT_EXECUTE_FEE\n        )  # type: int\n\n    def get_deploy_terms(self, is_init_transaction: bool = False) -> Terms:\n        \"\"\"\n        Get deploy terms of deployment.\n\n        :param is_init_transaction: whether this is for contract initialisation stage (for fetch ledger) or not.\n        :return: terms\n        \"\"\"\n        if self.ledger_id == EthereumApi.identifier:\n            label = \"deploy\"\n        elif self.ledger_id == FetchAIApi.identifier:\n            label = \"store\"\n            if is_init_transaction:\n                label = \"init\"\n        else:\n            raise ValueError(\n                f\"Unidentified ledger id: {self.ledger_id}\"\n            )  # pragma: nocover\n\n        terms = Terms(\n            ledger_id=self.ledger_id,\n            sender_address=self.context.agent_address,\n            counterparty_address=self.context.agent_address,\n            amount_by_currency_id={},\n            quantities_by_good_id={},\n            nonce=\"\",\n            label=label,\n        )\n        return terms\n\n    def get_create_token_terms(self) -> Terms:\n        \"\"\"\n        Get create token terms of deployment.\n\n        :return: terms\n        \"\"\"\n        terms = Terms(\n            ledger_id=self.ledger_id,\n            sender_address=self.context.agent_address,\n            counterparty_address=self.context.agent_address,\n            amount_by_currency_id={},\n            quantities_by_good_id={},\n            nonce=\"\",\n        )\n        return terms\n\n    def get_mint_token_terms(self) -> Terms:\n        \"\"\"\n        Get mint token terms of deployment.\n\n        :return: terms\n        \"\"\"\n        terms = Terms(\n            ledger_id=self.ledger_id,\n            sender_address=self.context.agent_address,\n            counterparty_address=self.context.agent_address,\n            amount_by_currency_id={},\n            quantities_by_good_id={},\n            nonce=\"\",\n        )\n        return terms\n\n    @property\n    def contract_deploy_tx_fee(self) -> int:\n        \"\"\"Transaction fee for a TAC instance.\"\"\"\n        return self._contract_deploy_tx_fee\n\n    @property\n    def contract_init_tx_fee(self) -> int:\n        \"\"\"Transaction fee for a TAC instance.\"\"\"\n        return self._contract_init_tx_fee\n\n    @property\n    def contract_execute_tx_fee(self) -> int:\n        \"\"\"Transaction fee for a TAC instance.\"\"\"\n        return self._contract_execute_tx_fee\n"
  },
  {
    "path": "packages/fetchai/skills/tac_control_contract/skill.yaml",
    "content": "name: tac_control_contract\nauthor: fetchai\nversion: 0.27.6\ntype: skill\ndescription: The tac control skill implements the logic for an AEA to control an instance\n  of the TAC.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: QmYoLcfTSQNX3FPna6g2ttKTQRjF8DpxpzLxEQLdg4whe1\n  __init__.py: QmVpmZmA7JNrBUTRdeThgw9GTnPMDEg4JRNLu8WUh8ZqWa\n  behaviours.py: QmV6UDZrmUXVfoqU8J5GgQmtanDKNbUd14t6UEJGSaynx8\n  dialogues.py: QmbxjXD42RbKtYWUwnQzscAiKJuijfNgUK3G1WJfU9Lkxf\n  game.py: QmYuh179BNFk4vt2df8WYDWT6C4J7ogJEgm4d1vUUNCEa7\n  handlers.py: QmUF3inkBDQ7ufvYyw238BM5LFeTq2T19FBT2MTBKHK7uo\n  helpers.py: QmdkhuZ1tAb5fn16dSiwLDHzhpF16FKK7DCHp5cJnGobHQ\n  parameters.py: QmcgNoSMmvEj4kwLJSdfZYi6hSG6os6WuwgYuZoj4DbWQc\nfingerprint_ignore_patterns: []\nconnections:\n- fetchai/ledger:0.21.5\ncontracts:\n- fetchai/erc1155:0.23.3\nprotocols:\n- fetchai/contract_api:1.1.7\n- fetchai/default:1.1.7\n- fetchai/ledger_api:1.1.7\n- fetchai/oef_search:1.1.7\n- fetchai/signing:1.1.7\n- fetchai/tac:1.1.7\nskills:\n- fetchai/tac_control:0.25.6\nbehaviours:\n  tac:\n    args: {}\n    class_name: TacBehaviour\nhandlers:\n  contract_api:\n    args: {}\n    class_name: ContractApiHandler\n  ledger_api:\n    args: {}\n    class_name: LedgerApiHandler\n  oef:\n    args: {}\n    class_name: OefSearchHandler\n  signing:\n    args: {}\n    class_name: SigningHandler\n  tac:\n    args: {}\n    class_name: TacHandler\nmodels:\n  contract_api_dialogues:\n    args: {}\n    class_name: ContractApiDialogues\n  default_dialogues:\n    args: {}\n    class_name: DefaultDialogues\n  game:\n    args: {}\n    class_name: Game\n  ledger_api_dialogues:\n    args: {}\n    class_name: LedgerApiDialogues\n  oef_search_dialogues:\n    args: {}\n    class_name: OefSearchDialogues\n  parameters:\n    args:\n      base_good_endowment: 4\n      competition_timeout: 360\n      contract_deploy_tx_fee: 2000000000000000\n      contract_execute_tx_fee: 2000000000000000\n      contract_init_tx_fee: 2000000000000000\n      currency_ids: []\n      good_ids: []\n      inactivity_timeout: 60\n      item_setup_timeout: 120\n      location:\n        latitude: 51.5194\n        longitude: 0.127\n      lower_bound_factor: 1\n      min_nb_agents: 2\n      money_endowment: 2000000\n      nb_currencies: 1\n      nb_goods: 9\n      registration_start_time: 01 01 2020  00:01\n      registration_timeout: 60\n      service_data:\n        key: tac\n        value: v1\n      tx_fee: 1\n      upper_bound_factor: 1\n      whitelist: []\n    class_name: Parameters\n  signing_dialogues:\n    args: {}\n    class_name: SigningDialogues\n  tac_dialogues:\n    args: {}\n    class_name: TacDialogues\ndependencies:\n  aea-ledger-ethereum:\n    version: <2.0.0,>=1.0.0\n  aea-ledger-fetchai:\n    version: <2.0.0,>=1.0.0\n  numpy: {}\nis_abstract: false\n"
  },
  {
    "path": "packages/fetchai/skills/tac_negotiation/README.md",
    "content": "# TAC Negotiation\n\n## Description\n\nThis is the skill for negotiation in a TAC.\n\nThis skill is part of the Fetch.ai TAC demo. It manages registration and searching of agents and services on the sOEF and negotiations of goods with other agents.\n\n## Behaviours\n\n- `clean_up`: updates and cleans up confirmed and pending transactions\n- `tac_negotiation`: registers/unregisters the agent and its buying/selling services on the sOEF\n\n## Handlers\n\n- `contract_api`: handles `contract_api` messages for interaction with a smart contract\n- `fipa`: handles `fipa` messages for negotiation\n- `ledger_api`: handles `ledger_api` messages for interacting with a ledger\n- `oef`: handles `oef_search` messages to manage the buyers/sellers it finds\n- `signing`: handles `signing` messages for transaction signing by the decision maker\n\n## Links\n\n- <a href=\"https://docs.fetch.ai/aea/tac-skills-contract/\" target=\"_blank\">TAC Demo</a>\n"
  },
  {
    "path": "packages/fetchai/skills/tac_negotiation/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the implementation of the tac negotiation skill.\"\"\"\n\nfrom aea.configurations.base import PublicId\n\n\nPUBLIC_ID = PublicId.from_str(\"fetchai/tac_negotiation:0.29.6\")\n"
  },
  {
    "path": "packages/fetchai/skills/tac_negotiation/behaviours.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains a scaffold of a behaviour.\"\"\"\n\nfrom typing import Any, Optional, cast\n\nfrom aea.helpers.search.models import Description\nfrom aea.skills.behaviours import TickerBehaviour\n\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.skills.tac_negotiation.dialogues import (\n    OefSearchDialogue,\n    OefSearchDialogues,\n)\nfrom packages.fetchai.skills.tac_negotiation.strategy import Strategy\nfrom packages.fetchai.skills.tac_negotiation.transactions import Transactions\n\n\nDEFAULT_MAX_SOEF_REGISTRATION_RETRIES = 5\nDEFAULT_REGISTER_AND_SEARCH_INTERVAL = 5.0\n\n\nclass GoodsRegisterAndSearchBehaviour(TickerBehaviour):\n    \"\"\"This class implements the goods register and search behaviour.\"\"\"\n\n    def __init__(self, **kwargs: Any):\n        \"\"\"Initialize the search behaviour.\"\"\"\n        search_interval = cast(\n            float, kwargs.pop(\"search_interval\", DEFAULT_REGISTER_AND_SEARCH_INTERVAL)\n        )\n        self._max_soef_registration_retries = kwargs.pop(\n            \"max_soef_registration_retries\", DEFAULT_MAX_SOEF_REGISTRATION_RETRIES\n        )  # type: int\n        super().__init__(tick_interval=search_interval, **kwargs)\n        self.is_registered = False\n        self.failed_registration_msg = None  # type: Optional[OefSearchMessage]\n        self._nb_retries = 0\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup.\"\"\"\n\n    def act(self) -> None:\n        \"\"\"Implement the act.\"\"\"\n        # the flag \"is_game_finished\" is set by the 'tac_participation'\n        # skill to notify the other skill that the TAC game is finished.\n        if self.context.shared_state.get(\"is_game_finished\", False):\n            self.context.is_active = False\n            return\n\n        if (\n            not self.context.decision_maker_handler_context.goal_pursuit_readiness.is_ready\n        ):\n            return\n\n        strategy = cast(Strategy, self.context.strategy)\n        strategy.tac_version_id = self.context.shared_state.get(\"tac_version_id\", None)\n        if strategy.tac_version_id is None:\n            self.context.logger.error(\"Cannot get the tac_version_id. Stopping!\")\n            self.context.is_active = False\n            return\n\n        if not self.is_registered:\n            self._retry_failed_registration()\n            self._register_agent()\n        self._search_services()\n\n    def teardown(self) -> None:\n        \"\"\"Implement the task teardown.\"\"\"\n        if self.is_registered:\n            self._unregister_service()\n            self._unregister_agent()\n            self.is_registered = False\n\n    def _retry_failed_registration(self) -> None:\n        \"\"\"Retry a failed registration.\"\"\"\n        if self.failed_registration_msg is not None:\n            self._nb_retries += 1\n            if self._nb_retries > self._max_soef_registration_retries:\n                self.context.is_active = False\n                return\n\n            oef_search_dialogues = cast(\n                OefSearchDialogues, self.context.oef_search_dialogues\n            )\n            oef_search_msg, _ = oef_search_dialogues.create(\n                counterparty=self.failed_registration_msg.to,\n                performative=self.failed_registration_msg.performative,\n                service_description=self.failed_registration_msg.service_description,\n            )\n            self.context.outbox.put_message(message=oef_search_msg)\n            self.context.logger.info(\n                f\"Retrying registration on SOEF. Retry {self._nb_retries} out of {self._max_soef_registration_retries}.\"\n            )\n\n            self.failed_registration_msg = None\n\n    def _register(self, description: Description, logger_msg: str) -> None:\n        \"\"\"\n        Register something on the SOEF.\n\n        :param description: the description of what is being registered\n        :param logger_msg: the logger message to print after the registration\n        \"\"\"\n        oef_search_dialogues = cast(\n            OefSearchDialogues, self.context.oef_search_dialogues\n        )\n        oef_search_msg, _ = oef_search_dialogues.create(\n            counterparty=self.context.search_service_address,\n            performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n            service_description=description,\n        )\n        self.context.outbox.put_message(message=oef_search_msg)\n        self.context.logger.info(logger_msg)\n\n    def _register_agent(self) -> None:\n        \"\"\"Register the agent's location.\"\"\"\n        strategy = cast(Strategy, self.context.strategy)\n        description = strategy.get_location_description()\n        self._register(description, \"registering agent on SOEF.\")\n\n    def register_service(self) -> None:\n        \"\"\"Register the agent's service.\"\"\"\n        strategy = cast(Strategy, self.context.strategy)\n        description = strategy.get_register_service_description()\n        self._register(\n            description,\n            \"updating service directory as {}.\".format(strategy.registering_as),\n        )\n\n    def register_genus(self) -> None:\n        \"\"\"Register the agent's personality genus.\"\"\"\n        strategy = cast(Strategy, self.context.strategy)\n        description = strategy.get_register_personality_description()\n        self._register(\n            description, \"registering agent's personality genus on the SOEF.\"\n        )\n\n    def register_classification(self) -> None:\n        \"\"\"Register the agent's personality classification.\"\"\"\n        strategy = cast(Strategy, self.context.strategy)\n        description = strategy.get_register_classification_description()\n        self._register(\n            description, \"registering agent's personality classification on the SOEF.\"\n        )\n\n    def _unregister_service(self) -> None:\n        \"\"\"Unregister service from OEF Service Directory.\"\"\"\n        strategy = cast(Strategy, self.context.strategy)\n        oef_search_dialogues = cast(\n            OefSearchDialogues, self.context.oef_search_dialogues\n        )\n        self.context.logger.debug(\n            \"unregistering from service directory as {}.\".format(\n                strategy.registering_as\n            )\n        )\n        description = strategy.get_unregister_service_description()\n        oef_search_msg, _ = oef_search_dialogues.create(\n            counterparty=self.context.search_service_address,\n            performative=OefSearchMessage.Performative.UNREGISTER_SERVICE,\n            service_description=description,\n        )\n        self.context.outbox.put_message(message=oef_search_msg)\n\n    def _unregister_agent(self) -> None:\n        \"\"\"Unregister agent from the SOEF.\"\"\"\n        strategy = cast(Strategy, self.context.strategy)\n        description = strategy.get_location_description()\n        oef_search_dialogues = cast(\n            OefSearchDialogues, self.context.oef_search_dialogues\n        )\n        oef_search_msg, _ = oef_search_dialogues.create(\n            counterparty=self.context.search_service_address,\n            performative=OefSearchMessage.Performative.UNREGISTER_SERVICE,\n            service_description=description,\n        )\n        self.context.outbox.put_message(message=oef_search_msg)\n        self.context.logger.info(\"unregistering agent from SOEF.\")\n\n    def _search_services(self) -> None:\n        \"\"\"\n        Search on OEF Service Directory.\n\n        In particular, search\n            - for sellers and their supply, or\n            - for buyers and their demand, or\n            - for both.\n        \"\"\"\n        strategy = cast(Strategy, self.context.strategy)\n        oef_search_dialogues = cast(\n            OefSearchDialogues, self.context.oef_search_dialogues\n        )\n        query = strategy.get_location_and_service_query()\n        for (is_seller_search, searching_for) in strategy.searching_for_types:\n            oef_search_msg, oef_search_dialogue = oef_search_dialogues.create(\n                counterparty=self.context.search_service_address,\n                performative=OefSearchMessage.Performative.SEARCH_SERVICES,\n                query=query,\n            )\n            oef_search_dialogue = cast(OefSearchDialogue, oef_search_dialogue)\n            oef_search_dialogue.is_seller_search = is_seller_search\n            self.context.outbox.put_message(message=oef_search_msg)\n            self.context.logger.info(\n                \"searching for {}, search_id={}.\".format(\n                    searching_for, oef_search_msg.dialogue_reference\n                )\n            )\n\n\nclass TransactionCleanUpBehaviour(TickerBehaviour):\n    \"\"\"This class implements the cleanup of the transactions class.\"\"\"\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup.\"\"\"\n\n    def act(self) -> None:\n        \"\"\"Implement the task execution.\"\"\"\n        transactions = cast(Transactions, self.context.transactions)\n        transactions.update_confirmed_transactions()\n        transactions.cleanup_pending_transactions()\n\n    def teardown(self) -> None:\n        \"\"\"Implement the task teardown.\"\"\"\n"
  },
  {
    "path": "packages/fetchai/skills/tac_negotiation/dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nThis module contains the classes required for dialogue management.\n\n- Dialogues: The dialogues class keeps track of all dialogues.\n\"\"\"\n\nfrom typing import Any, Optional, Type, cast\n\nfrom aea.common import Address\nfrom aea.exceptions import enforce\nfrom aea.helpers.search.models import Description\nfrom aea.helpers.transaction.base import Terms\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue, DialogueLabel\nfrom aea.skills.base import Model\n\nfrom packages.fetchai.protocols.contract_api.dialogues import (\n    ContractApiDialogue as BaseContractApiDialogue,\n)\nfrom packages.fetchai.protocols.contract_api.dialogues import (\n    ContractApiDialogues as BaseContractApiDialogues,\n)\nfrom packages.fetchai.protocols.contract_api.message import ContractApiMessage\nfrom packages.fetchai.protocols.cosm_trade.dialogues import (\n    CosmTradeDialogue as BaseCosmTradeDialogue,\n)\nfrom packages.fetchai.protocols.cosm_trade.dialogues import (\n    CosmTradeDialogues as BaseCosmTradeDialogues,\n)\nfrom packages.fetchai.protocols.default.dialogues import (\n    DefaultDialogue as BaseDefaultDialogue,\n)\nfrom packages.fetchai.protocols.default.dialogues import (\n    DefaultDialogues as BaseDefaultDialogues,\n)\nfrom packages.fetchai.protocols.fipa.dialogues import FipaDialogue as BaseFipaDialogue\nfrom packages.fetchai.protocols.fipa.dialogues import FipaDialogues as BaseFipaDialogues\nfrom packages.fetchai.protocols.fipa.message import FipaMessage\nfrom packages.fetchai.protocols.ledger_api.dialogues import (\n    LedgerApiDialogue as BaseLedgerApiDialogue,\n)\nfrom packages.fetchai.protocols.ledger_api.dialogues import (\n    LedgerApiDialogues as BaseLedgerApiDialogues,\n)\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\nfrom packages.fetchai.protocols.oef_search.dialogues import (\n    OefSearchDialogue as BaseOefSearchDialogue,\n)\nfrom packages.fetchai.protocols.oef_search.dialogues import (\n    OefSearchDialogues as BaseOefSearchDialogues,\n)\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.protocols.signing.dialogues import (\n    SigningDialogue as BaseSigningDialogue,\n)\nfrom packages.fetchai.protocols.signing.dialogues import (\n    SigningDialogues as BaseSigningDialogues,\n)\nfrom packages.fetchai.protocols.signing.message import SigningMessage\nfrom packages.fetchai.skills.tac_negotiation.helpers import (\n    DEMAND_DATAMODEL_NAME,\n    SUPPLY_DATAMODEL_NAME,\n)\n\n\nclass FipaDialogue(BaseFipaDialogue):\n    \"\"\"The dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    __slots__ = (\"_proposal\", \"_terms\", \"_counterparty_signature\")\n\n    def __init__(\n        self,\n        dialogue_label: DialogueLabel,\n        self_address: Address,\n        role: Dialogue.Role,\n        message_class: Type[FipaMessage] = FipaMessage,\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n        :param message_class: the message class\n        \"\"\"\n        BaseFipaDialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            self_address=self_address,\n            role=role,\n            message_class=message_class,\n        )\n        self._proposal = None  # type: Optional[Description]\n        self._terms = None  # type: Optional[Terms]\n        self._counterparty_signature = None  # type: Optional[str]\n\n    @property\n    def counterparty_signature(self) -> str:\n        \"\"\"Get counterparty signature.\"\"\"\n        if self._counterparty_signature is None:\n            raise ValueError(\"counterparty_signature not set!\")\n        return self._counterparty_signature\n\n    @counterparty_signature.setter\n    def counterparty_signature(self, counterparty_signature: str) -> None:\n        \"\"\"Set is_seller_search.\"\"\"\n        enforce(\n            self._counterparty_signature is None, \"counterparty_signature already set!\"\n        )\n        self._counterparty_signature = counterparty_signature\n\n    @property\n    def proposal(self) -> Description:\n        \"\"\"Get the proposal.\"\"\"\n        if self._proposal is None:\n            raise ValueError(\"Proposal not set!\")\n        return self._proposal\n\n    @proposal.setter\n    def proposal(self, proposal: Description) -> None:\n        \"\"\"Set the proposal.\"\"\"\n        enforce(self._proposal is None, \"Proposal already set!\")\n        self._proposal = proposal\n\n    @property\n    def terms(self) -> Terms:\n        \"\"\"Get the terms.\"\"\"\n        if self._terms is None:\n            raise ValueError(\"Terms not set!\")\n        return self._terms\n\n    @terms.setter\n    def terms(self, terms: Terms) -> None:\n        \"\"\"Set the terms.\"\"\"\n        enforce(self._terms is None, \"Terms already set!\")\n        self._terms = terms\n\n\nclass FipaDialogues(Model, BaseFipaDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(\n            message: Message, receiver_address: Address\n        ) -> Dialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            fipa_message = cast(FipaMessage, message)\n            if fipa_message.performative != FipaMessage.Performative.CFP:\n                raise ValueError(\"First message must be a CFP!\")  # pragma: nocover\n            query = fipa_message.query\n            if query.model is None:\n                raise ValueError(\"Query must have a data model!\")  # pragma: nocover\n            if query.model.name not in [\n                SUPPLY_DATAMODEL_NAME,\n                DEMAND_DATAMODEL_NAME,\n            ]:\n                raise ValueError(  # pragma: nocover\n                    \"Query data model name must be in [{},{}]\".format(\n                        SUPPLY_DATAMODEL_NAME, DEMAND_DATAMODEL_NAME\n                    )\n                )\n            if message.sender != receiver_address:  # message is by other\n                is_seller = (\n                    query.model.name == SUPPLY_DATAMODEL_NAME\n                )  # the counterparty is querying for supply/sellers (this agent is receiving their CFP so is the seller)\n            else:  # message is by self\n                is_seller = (\n                    query.model.name == DEMAND_DATAMODEL_NAME\n                )  # the agent is querying for demand/buyers (this agent is sending the CFP so it is the seller)\n            role = FipaDialogue.Role.SELLER if is_seller else FipaDialogue.Role.BUYER\n            return role\n\n        BaseFipaDialogues.__init__(\n            self,\n            self_address=self.context.agent_address,\n            role_from_first_message=role_from_first_message,\n            dialogue_class=FipaDialogue,\n        )\n\n\nclass ContractApiDialogue(BaseContractApiDialogue):\n    \"\"\"The dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    __slots__ = (\"_associated_fipa_dialogue\",)\n\n    def __init__(\n        self,\n        dialogue_label: DialogueLabel,\n        self_address: Address,\n        role: Dialogue.Role,\n        message_class: Type[ContractApiMessage] = ContractApiMessage,\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n        :param message_class: the message class\n        \"\"\"\n        BaseContractApiDialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            self_address=self_address,\n            role=role,\n            message_class=message_class,\n        )\n        self._associated_fipa_dialogue: Optional[FipaDialogue] = None\n\n    @property\n    def associated_fipa_dialogue(self) -> FipaDialogue:\n        \"\"\"Get associated_fipa_dialogue.\"\"\"\n        if self._associated_fipa_dialogue is None:\n            raise ValueError(\"associated_fipa_dialogue not set!\")\n        return self._associated_fipa_dialogue\n\n    @associated_fipa_dialogue.setter\n    def associated_fipa_dialogue(self, associated_fipa_dialogue: FipaDialogue) -> None:\n        \"\"\"Set associated_fipa_dialogue.\"\"\"\n        enforce(\n            self._associated_fipa_dialogue is None,\n            \"associated_fipa_dialogue already set!\",\n        )\n        self._associated_fipa_dialogue = associated_fipa_dialogue\n\n\nclass ContractApiDialogues(Model, BaseContractApiDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> Dialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return ContractApiDialogue.Role.AGENT\n\n        BaseContractApiDialogues.__init__(\n            self,\n            self_address=str(self.skill_id),\n            role_from_first_message=role_from_first_message,\n            dialogue_class=ContractApiDialogue,\n        )\n\n\nCosmTradeDialogue = BaseCosmTradeDialogue\n\n\nclass CosmTradeDialogues(Model, BaseCosmTradeDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> Dialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return CosmTradeDialogue.Role.AGENT\n\n        BaseCosmTradeDialogues.__init__(\n            self,\n            self_address=self.context.agent_address,\n            role_from_first_message=role_from_first_message,\n            dialogue_class=CosmTradeDialogue,\n        )\n\n\nDefaultDialogue = BaseDefaultDialogue\n\n\nclass DefaultDialogues(Model, BaseDefaultDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> Dialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return DefaultDialogue.Role.AGENT\n\n        BaseDefaultDialogues.__init__(\n            self,\n            self_address=self.context.agent_address,\n            role_from_first_message=role_from_first_message,\n        )\n\n\nclass LedgerApiDialogue(BaseLedgerApiDialogue):\n    \"\"\"The dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    __slots__ = (\"_associated_signing_dialogue\",)\n\n    def __init__(\n        self,\n        dialogue_label: DialogueLabel,\n        self_address: Address,\n        role: Dialogue.Role,\n        message_class: Type[LedgerApiMessage] = LedgerApiMessage,\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n        :param message_class: the message class\n        \"\"\"\n        BaseLedgerApiDialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            self_address=self_address,\n            role=role,\n            message_class=message_class,\n        )\n        self._associated_signing_dialogue = None  # type: Optional[SigningDialogue]\n\n    @property\n    def associated_signing_dialogue(self) -> \"SigningDialogue\":\n        \"\"\"Get the associated signing dialogue.\"\"\"\n        if self._associated_signing_dialogue is None:\n            raise ValueError(\"Associated signing dialogue not set!\")\n        return self._associated_signing_dialogue\n\n    @associated_signing_dialogue.setter\n    def associated_signing_dialogue(\n        self, associated_signing_dialogue: \"SigningDialogue\"\n    ) -> None:\n        \"\"\"Set the associated signing dialogue.\"\"\"\n        enforce(\n            self._associated_signing_dialogue is None,\n            \"Associated signing dialogue already set!\",\n        )\n        self._associated_signing_dialogue = associated_signing_dialogue\n\n\nclass LedgerApiDialogues(Model, BaseLedgerApiDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> Dialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return BaseLedgerApiDialogue.Role.AGENT\n\n        BaseLedgerApiDialogues.__init__(\n            self,\n            self_address=str(self.skill_id),\n            role_from_first_message=role_from_first_message,\n            dialogue_class=LedgerApiDialogue,\n        )\n\n\nclass OefSearchDialogue(BaseOefSearchDialogue):\n    \"\"\"The dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    __slots__ = (\"_is_seller_search\",)\n\n    def __init__(\n        self,\n        dialogue_label: DialogueLabel,\n        self_address: Address,\n        role: Dialogue.Role,\n        message_class: Type[OefSearchMessage] = OefSearchMessage,\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n        :param message_class: the message class\n        \"\"\"\n        BaseOefSearchDialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            self_address=self_address,\n            role=role,\n            message_class=message_class,\n        )\n        self._is_seller_search = None  # type: Optional[bool]\n\n    @property\n    def is_seller_search(self) -> bool:\n        \"\"\"Get if it is a seller search.\"\"\"\n        if self._is_seller_search is None:\n            raise ValueError(\"is_seller_search not set!\")\n        return self._is_seller_search\n\n    @is_seller_search.setter\n    def is_seller_search(self, is_seller_search: bool) -> None:\n        \"\"\"Set is_seller_search.\"\"\"\n        enforce(self._is_seller_search is None, \"is_seller_search already set!\")\n        self._is_seller_search = is_seller_search\n\n\nclass OefSearchDialogues(Model, BaseOefSearchDialogues):\n    \"\"\"This class keeps track of all oef_search dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> Dialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return BaseOefSearchDialogue.Role.AGENT\n\n        BaseOefSearchDialogues.__init__(\n            self,\n            self_address=str(self.skill_id),\n            role_from_first_message=role_from_first_message,\n            dialogue_class=OefSearchDialogue,\n        )\n\n\nclass SigningDialogue(BaseSigningDialogue):\n    \"\"\"The dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    __slots__ = (\"_associated_fipa_dialogue\",)\n\n    def __init__(\n        self,\n        dialogue_label: DialogueLabel,\n        self_address: Address,\n        role: Dialogue.Role,\n        message_class: Type[SigningMessage] = SigningMessage,\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n        :param message_class: the message class\n        \"\"\"\n        BaseSigningDialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            self_address=self_address,\n            role=role,\n            message_class=message_class,\n        )\n        self._associated_fipa_dialogue: Optional[FipaDialogue] = None\n        self._associated_cosm_trade_dialogue: Optional[CosmTradeDialogue] = None\n\n    @property\n    def associated_fipa_dialogue(self) -> FipaDialogue:\n        \"\"\"Get associated_fipa_dialogue.\"\"\"\n        if self._associated_fipa_dialogue is None:\n            raise ValueError(\"associated_fipa_dialogue not set!\")\n        return self._associated_fipa_dialogue\n\n    @associated_fipa_dialogue.setter\n    def associated_fipa_dialogue(self, associated_fipa_dialogue: FipaDialogue) -> None:\n        \"\"\"Set associated_fipa_dialogue.\"\"\"\n        enforce(\n            self._associated_fipa_dialogue is None,\n            \"associated_fipa_dialogue already set!\",\n        )\n        self._associated_fipa_dialogue = associated_fipa_dialogue\n\n    @property\n    def associated_cosm_trade_dialogue(self) -> Optional[CosmTradeDialogue]:\n        \"\"\"Get associated_cosm_trade_dialogue.\"\"\"\n        return self._associated_cosm_trade_dialogue\n\n    @associated_cosm_trade_dialogue.setter\n    def associated_cosm_trade_dialogue(\n        self, associated_cosm_trade_dialogue: CosmTradeDialogue\n    ) -> None:\n        \"\"\"Set associated_cosm_trade_dialogue.\"\"\"\n        enforce(\n            self._associated_cosm_trade_dialogue is None,\n            \"associated_cosm_trade_dialogue already set!\",\n        )\n        self._associated_cosm_trade_dialogue = associated_cosm_trade_dialogue\n\n\nclass SigningDialogues(Model, BaseSigningDialogues):\n    \"\"\"This class keeps track of all oef_search dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> Dialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return BaseSigningDialogue.Role.SKILL\n\n        BaseSigningDialogues.__init__(\n            self,\n            self_address=str(self.skill_id),\n            role_from_first_message=role_from_first_message,\n            dialogue_class=SigningDialogue,\n        )\n"
  },
  {
    "path": "packages/fetchai/skills/tac_negotiation/handlers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains a scaffold of a handler.\"\"\"\n\nfrom collections import OrderedDict\nfrom typing import Optional, Tuple, cast\n\nfrom aea_ledger_ethereum import EthereumApi\nfrom aea_ledger_fetchai import FetchAIApi\n\nfrom aea.configurations.base import PublicId\nfrom aea.crypto.ledger_apis import LedgerApis\nfrom aea.exceptions import enforce\nfrom aea.helpers.transaction.base import RawMessage, RawTransaction\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import DialogueLabel\nfrom aea.skills.base import Handler\n\nfrom packages.fetchai.connections.ledger.base import (\n    CONNECTION_ID as LEDGER_CONNECTION_PUBLIC_ID,\n)\nfrom packages.fetchai.protocols.contract_api.message import ContractApiMessage\nfrom packages.fetchai.protocols.cosm_trade.message import CosmTradeMessage\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.protocols.fipa.message import FipaMessage\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.protocols.signing.message import SigningMessage\nfrom packages.fetchai.skills.tac_negotiation.behaviours import (\n    GoodsRegisterAndSearchBehaviour,\n)\nfrom packages.fetchai.skills.tac_negotiation.dialogues import (\n    ContractApiDialogue,\n    ContractApiDialogues,\n    CosmTradeDialogue,\n    CosmTradeDialogues,\n    DefaultDialogues,\n    FipaDialogue,\n    FipaDialogues,\n    LedgerApiDialogue,\n    LedgerApiDialogues,\n    OefSearchDialogue,\n    OefSearchDialogues,\n    SigningDialogue,\n    SigningDialogues,\n)\nfrom packages.fetchai.skills.tac_negotiation.strategy import Strategy\nfrom packages.fetchai.skills.tac_negotiation.transactions import Transactions\n\n\nLEDGER_API_ADDRESS = str(LEDGER_CONNECTION_PUBLIC_ID)\n\n\nclass FipaNegotiationHandler(Handler):\n    \"\"\"This class implements the fipa negotiation handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = FipaMessage.protocol_id  # type: Optional[PublicId]\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Dispatch message to relevant handler and respond.\n\n        :param message: the message\n        \"\"\"\n        fipa_msg = cast(FipaMessage, message)\n\n        # recover dialogue\n        fipa_dialogues = cast(FipaDialogues, self.context.fipa_dialogues)\n        fipa_dialogue = cast(FipaDialogue, fipa_dialogues.update(fipa_msg))\n        if fipa_dialogue is None:\n            self._handle_unidentified_dialogue(fipa_msg)\n            return\n\n        self.context.logger.info(\n            \"received {} from {} (as {}), message={}\".format(\n                fipa_msg.performative.value,\n                fipa_msg.sender[-5:],\n                fipa_dialogue.role,\n                fipa_msg,\n            )\n        )\n        if fipa_msg.performative == FipaMessage.Performative.CFP:\n            self._on_cfp(fipa_msg, fipa_dialogue)\n        elif fipa_msg.performative == FipaMessage.Performative.PROPOSE:\n            self._on_propose(fipa_msg, fipa_dialogue)\n        elif fipa_msg.performative == FipaMessage.Performative.DECLINE:\n            self._on_decline(fipa_msg, fipa_dialogue)\n        elif fipa_msg.performative == FipaMessage.Performative.ACCEPT:\n            self._on_accept(fipa_msg, fipa_dialogue)\n        elif fipa_msg.performative == FipaMessage.Performative.MATCH_ACCEPT_W_INFORM:\n            self._on_match_accept(fipa_msg, fipa_dialogue)\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n\n    def _handle_unidentified_dialogue(self, fipa_msg: FipaMessage) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        Respond to the sender with a default message containing the appropriate error information.\n\n        :param fipa_msg: the message\n        \"\"\"\n        self.context.logger.info(\n            \"received invalid fipa message={}, unidentified dialogue.\".format(fipa_msg)\n        )\n        default_dialogues = cast(DefaultDialogues, self.context.default_dialogues)\n        default_msg, _ = default_dialogues.create(\n            counterparty=fipa_msg.sender,\n            performative=DefaultMessage.Performative.ERROR,\n            error_code=DefaultMessage.ErrorCode.INVALID_DIALOGUE,\n            error_msg=\"Invalid dialogue.\",\n            error_data={\"fipa_message\": fipa_msg.encode()},\n        )\n        self.context.outbox.put_message(message=default_msg)\n\n    def _on_cfp(self, cfp: FipaMessage, fipa_dialogue: FipaDialogue) -> None:\n        \"\"\"\n        Handle a CFP.\n\n        :param cfp: the fipa message containing the CFP\n        :param fipa_dialogue: the fipa_dialogue\n        \"\"\"\n        strategy = cast(Strategy, self.context.strategy)\n        proposal = strategy.get_proposal_for_query(\n            cfp.query, cast(FipaDialogue.Role, fipa_dialogue.role)\n        )\n        if proposal is None:\n            fipa_msg = fipa_dialogue.reply(\n                performative=FipaMessage.Performative.DECLINE,\n                target_message=cfp,\n            )\n            fipa_dialogues = cast(FipaDialogues, self.context.fipa_dialogues)\n            fipa_dialogues.dialogue_stats.add_dialogue_endstate(\n                FipaDialogue.EndState.DECLINED_CFP, fipa_dialogue.is_self_initiated\n            )\n        else:\n            transactions = cast(Transactions, self.context.transactions)\n            fipa_msg = fipa_dialogue.reply(\n                performative=FipaMessage.Performative.PROPOSE,\n                target_message=cfp,\n                proposal=proposal,\n            )\n            fipa_dialogue.terms = strategy.terms_from_proposal(\n                proposal,\n                self.context.agent_address,\n                cfp.sender,\n                cast(FipaDialogue.Role, fipa_dialogue.role),\n            )\n            transactions.add_pending_proposal(\n                fipa_dialogue.dialogue_label, fipa_msg.message_id, fipa_dialogue.terms\n            )\n        self.context.logger.info(\n            \"sending {} to {} (as {}), message={}\".format(\n                fipa_msg.performative, fipa_msg.to[-5:], fipa_dialogue.role, fipa_msg\n            )\n        )\n        self.context.outbox.put_message(message=fipa_msg)\n\n    def _on_propose(self, propose: FipaMessage, fipa_dialogue: FipaDialogue) -> None:\n        \"\"\"\n        Handle a Propose.\n\n        :param propose: the message containing the Propose\n        :param fipa_dialogue: the fipa_dialogue\n        \"\"\"\n        strategy = cast(Strategy, self.context.strategy)\n        fipa_dialogue.terms = strategy.terms_from_proposal(\n            propose.proposal,\n            self.context.agent_address,\n            propose.sender,\n            cast(FipaDialogue.Role, fipa_dialogue.role),\n        )\n        transactions = cast(Transactions, self.context.transactions)\n        if strategy.is_profitable_transaction(\n            fipa_dialogue.terms, role=cast(FipaDialogue.Role, fipa_dialogue.role)\n        ):\n            fipa_msg = fipa_dialogue.reply(\n                performative=FipaMessage.Performative.ACCEPT,\n                target_message=propose,\n            )\n            transactions.add_locked_tx(\n                fipa_dialogue.terms, role=cast(FipaDialogue.Role, fipa_dialogue.role)\n            )\n            transactions.add_pending_initial_acceptance(\n                fipa_dialogue.dialogue_label, fipa_msg.message_id, fipa_dialogue.terms\n            )\n        else:\n            fipa_msg = fipa_dialogue.reply(\n                performative=FipaMessage.Performative.DECLINE,\n                target_message=propose,\n            )\n            fipa_dialogues = cast(FipaDialogues, self.context.fipa_dialogues)\n            fipa_dialogues.dialogue_stats.add_dialogue_endstate(\n                FipaDialogue.EndState.DECLINED_PROPOSE, fipa_dialogue.is_self_initiated\n            )\n        self.context.logger.info(\n            \"sending {} to {} (as {}), message={}\".format(\n                fipa_msg.performative, fipa_msg.to[-5:], fipa_dialogue.role, fipa_msg\n            )\n        )\n        self.context.outbox.put_message(message=fipa_msg)\n\n    def _on_decline(self, decline: FipaMessage, fipa_dialogue: FipaDialogue) -> None:\n        \"\"\"\n        Handle a Decline.\n\n        :param decline: the Decline message\n        :param fipa_dialogue: the fipa_dialogue\n        \"\"\"\n        fipa_dialogues = cast(FipaDialogues, self.context.fipa_dialogues)\n\n        target_message = fipa_dialogue.get_message_by_id(decline.target)\n\n        if not target_message:\n            raise ValueError(\"Can not find target message!\")  # pragma: nocover\n\n        declined_performative = target_message.performative\n        if declined_performative == FipaMessage.Performative.CFP:\n            fipa_dialogues.dialogue_stats.add_dialogue_endstate(\n                FipaDialogue.EndState.DECLINED_CFP, fipa_dialogue.is_self_initiated\n            )\n        if declined_performative == FipaMessage.Performative.PROPOSE:\n            fipa_dialogues.dialogue_stats.add_dialogue_endstate(\n                FipaDialogue.EndState.DECLINED_PROPOSE, fipa_dialogue.is_self_initiated\n            )\n            transactions = cast(Transactions, self.context.transactions)\n            terms = transactions.pop_pending_proposal(\n                fipa_dialogue.dialogue_label, decline.target\n            )\n        if declined_performative == FipaMessage.Performative.ACCEPT:\n            fipa_dialogues.dialogue_stats.add_dialogue_endstate(\n                FipaDialogue.EndState.DECLINED_ACCEPT, fipa_dialogue.is_self_initiated\n            )\n            transactions = cast(Transactions, self.context.transactions)\n            terms = transactions.pop_pending_initial_acceptance(\n                fipa_dialogue.dialogue_label, decline.target\n            )\n            transactions.pop_locked_tx(terms)\n\n    def _on_accept(self, accept: FipaMessage, fipa_dialogue: FipaDialogue) -> None:\n        \"\"\"\n        Handle an Accept.\n\n        :param accept: the Accept message\n        :param fipa_dialogue: the fipa_dialogue\n        \"\"\"\n        transactions = cast(Transactions, self.context.transactions)\n        terms = transactions.pop_pending_proposal(\n            fipa_dialogue.dialogue_label, accept.target\n        )\n        strategy = cast(Strategy, self.context.strategy)\n        if strategy.is_profitable_transaction(\n            terms, role=cast(FipaDialogue.Role, fipa_dialogue.role)\n        ):\n            transactions.add_locked_tx(\n                terms, role=cast(FipaDialogue.Role, fipa_dialogue.role)\n            )\n            if strategy.is_contract_tx:\n                if strategy.ledger_id == EthereumApi.identifier:\n                    contract_api_dialogues = cast(\n                        ContractApiDialogues, self.context.contract_api_dialogues\n                    )\n                    kwargs = strategy.kwargs_from_terms(\n                        fipa_dialogue.terms, is_from_terms_sender=False\n                    )\n                    kwargs.pop(\"tx_fee\", None)\n                    (\n                        contract_api_msg,\n                        contract_api_dialogue,\n                    ) = contract_api_dialogues.create(\n                        counterparty=LEDGER_API_ADDRESS,\n                        performative=ContractApiMessage.Performative.GET_RAW_MESSAGE,\n                        ledger_id=strategy.ledger_id,\n                        contract_id=strategy.contract_id,\n                        contract_address=strategy.contract_address,\n                        callable=\"get_hash_batch\",\n                        kwargs=ContractApiMessage.Kwargs(kwargs),\n                    )\n                    contract_api_dialogue = cast(\n                        ContractApiDialogue, contract_api_dialogue\n                    )\n                    contract_api_dialogue.associated_fipa_dialogue = fipa_dialogue\n                    self.context.logger.info(\n                        \"requesting batch transaction hash, sending {} to {}, message={}\".format(\n                            contract_api_msg.performative,\n                            strategy.contract_id,\n                            contract_api_msg,\n                        )\n                    )\n                    self.context.outbox.put_message(message=contract_api_msg)\n                elif strategy.ledger_id == FetchAIApi.identifier:\n                    public_key = self.context.public_keys.get(strategy.ledger_id, None)\n                    if public_key is None:\n                        self.context.logger.info(\n                            f\"Agent has no public key for {strategy.ledger_id}.\"\n                        )\n                        return\n                    fipa_msg = fipa_dialogue.reply(\n                        performative=FipaMessage.Performative.MATCH_ACCEPT_W_INFORM,\n                        info={\"public_key\": public_key},\n                    )\n                    self.context.outbox.put_message(message=fipa_msg)\n                    self.context.logger.info(\n                        \"sending {} to {} (as {}), message={}.\".format(\n                            fipa_msg.performative.value,\n                            fipa_msg.to[-5:],\n                            fipa_dialogue.role,\n                            fipa_msg,\n                        )\n                    )\n                else:\n                    enforce(False, f\"Unidentified ledger id: {strategy.ledger_id}\")\n            else:\n                signing_dialogues = cast(\n                    SigningDialogues, self.context.signing_dialogues\n                )\n                raw_message = RawMessage(\n                    ledger_id=terms.ledger_id, body=terms.sender_hash.encode(\"utf-8\")\n                )\n                signing_msg, signing_dialogue = signing_dialogues.create(\n                    counterparty=self.context.decision_maker_address,\n                    performative=SigningMessage.Performative.SIGN_MESSAGE,\n                    terms=terms,\n                    raw_message=raw_message,\n                )\n                signing_dialogue = cast(SigningDialogue, signing_dialogue)\n                signing_dialogue.associated_fipa_dialogue = fipa_dialogue\n                self.context.logger.info(\n                    \"requesting signature, sending {} to decision_maker, message={}\".format(\n                        signing_msg.performative,\n                        signing_msg,\n                    )\n                )\n                self.context.decision_maker_message_queue.put(signing_msg)\n        else:\n            fipa_msg = fipa_dialogue.reply(\n                performative=FipaMessage.Performative.DECLINE,\n                target_message=accept,\n            )\n            dialogues = cast(FipaDialogues, self.context.fipa_dialogues)\n            dialogues.dialogue_stats.add_dialogue_endstate(\n                FipaDialogue.EndState.DECLINED_ACCEPT, fipa_dialogue.is_self_initiated\n            )\n            self.context.logger.info(\n                \"sending {} to {} (as {}), message={}\".format(\n                    fipa_msg.performative,\n                    fipa_msg.to[-5:],\n                    fipa_dialogue.role,\n                    fipa_msg,\n                )\n            )\n            self.context.outbox.put_message(message=fipa_msg)\n\n    def _on_match_accept(\n        self, match_accept: FipaMessage, fipa_dialogue: FipaDialogue\n    ) -> None:\n        \"\"\"\n        Handle a matching Accept.\n\n        :param match_accept: the MatchAccept message\n        :param fipa_dialogue: the fipa_dialogue\n        \"\"\"\n        strategy = cast(Strategy, self.context.strategy)\n        if strategy.is_contract_tx:\n            if strategy.ledger_id == FetchAIApi.identifier:\n                counterparty_public_key = match_accept.info.get(\"public_key\", None)\n                if counterparty_public_key is None:\n                    self.context.logger.info(\n                        f\"{match_accept.performative} did not contain counterparty public_key!\"\n                    )\n                    return\n                sender_public_key = self.context.public_keys.get(\n                    strategy.ledger_id, None\n                )\n                if sender_public_key is None:\n                    self.context.logger.info(\n                        f\"Agent has no public key for {strategy.ledger_id}.\"\n                    )\n                    return\n                contract_api_dialogues = cast(\n                    ContractApiDialogues, self.context.contract_api_dialogues\n                )\n                contract_api_msg, contract_api_dialogue = contract_api_dialogues.create(\n                    counterparty=LEDGER_API_ADDRESS,\n                    performative=ContractApiMessage.Performative.GET_RAW_TRANSACTION,\n                    ledger_id=strategy.ledger_id,\n                    contract_id=strategy.contract_id,\n                    contract_address=strategy.contract_address,\n                    callable=\"get_atomic_swap_batch_transaction\",\n                    kwargs=ContractApiMessage.Kwargs(\n                        strategy.kwargs_from_terms(\n                            fipa_dialogue.terms,\n                            sender_public_key=sender_public_key,\n                            counterparty_public_key=counterparty_public_key,\n                        )\n                    ),\n                )\n                contract_api_dialogue = cast(ContractApiDialogue, contract_api_dialogue)\n                contract_api_dialogue.associated_fipa_dialogue = fipa_dialogue\n                self.context.logger.info(\n                    \"requesting batch atomic swap transaction, sending {} to {}, message={}\".format(\n                        contract_api_msg.performative,\n                        strategy.contract_id,\n                        contract_api_msg,\n                    )\n                )\n                self.context.outbox.put_message(message=contract_api_msg)\n            elif strategy.ledger_id == EthereumApi.identifier:\n                counterparty_signature = match_accept.info.get(\"signature\")\n                if counterparty_signature is None:\n                    self.context.logger.info(\n                        f\"{match_accept.performative} did not contain counterparty signature!\"\n                    )\n                    return\n                fipa_dialogue.counterparty_signature = counterparty_signature\n                contract_api_dialogues = cast(\n                    ContractApiDialogues, self.context.contract_api_dialogues\n                )\n                contract_api_msg, contract_api_dialogue = contract_api_dialogues.create(\n                    counterparty=LEDGER_API_ADDRESS,\n                    performative=ContractApiMessage.Performative.GET_RAW_TRANSACTION,\n                    ledger_id=strategy.ledger_id,\n                    contract_id=strategy.contract_id,\n                    contract_address=strategy.contract_address,\n                    callable=\"get_atomic_swap_batch_transaction\",\n                    kwargs=ContractApiMessage.Kwargs(\n                        strategy.kwargs_from_terms(\n                            fipa_dialogue.terms,\n                            signature=counterparty_signature,\n                        )\n                    ),\n                )\n                contract_api_dialogue = cast(ContractApiDialogue, contract_api_dialogue)\n                contract_api_dialogue.associated_fipa_dialogue = fipa_dialogue\n                self.context.logger.info(\n                    \"requesting batch atomic swap transaction, sending {} to {}, message={}\".format(\n                        contract_api_msg.performative,\n                        strategy.contract_id,\n                        contract_api_msg,\n                    )\n                )\n                self.context.outbox.put_message(message=contract_api_msg)\n            else:\n                enforce(False, f\"Unidentified ledger id: {strategy.ledger_id}\")\n        else:\n            counterparty_signature = match_accept.info.get(\"signature\")\n            if counterparty_signature is None:\n                self.context.logger.info(\n                    f\"{match_accept.performative} did not contain counterparty signature!\"\n                )\n                return\n            fipa_dialogue.counterparty_signature = counterparty_signature\n            transactions = cast(Transactions, self.context.transactions)\n            terms = transactions.pop_pending_initial_acceptance(\n                fipa_dialogue.dialogue_label, match_accept.target\n            )\n            signing_dialogues = cast(SigningDialogues, self.context.signing_dialogues)\n            raw_message = RawMessage(\n                ledger_id=terms.ledger_id, body=terms.sender_hash.encode(\"utf-8\")\n            )\n            signing_msg, signing_dialogue = signing_dialogues.create(\n                counterparty=self.context.decision_maker_address,\n                performative=SigningMessage.Performative.SIGN_MESSAGE,\n                terms=terms,\n                raw_message=raw_message,\n            )\n            signing_dialogue = cast(SigningDialogue, signing_dialogue)\n            signing_dialogue.associated_fipa_dialogue = fipa_dialogue\n            self.context.logger.info(\n                \"requesting signature, sending {} to decision_maker, message={}\".format(\n                    signing_msg.performative,\n                    signing_msg,\n                )\n            )\n            self.context.decision_maker_message_queue.put(signing_msg)\n\n\nclass CosmTradeHandler(Handler):\n    \"\"\"This class implements the cosm_trade negotiation handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = CosmTradeMessage.protocol_id  # type: Optional[PublicId]\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Dispatch message to relevant handler and respond.\n\n        :param message: the message\n        \"\"\"\n        strategy = cast(Strategy, self.context.strategy)\n        enforce(\n            strategy.is_contract_tx,\n            \"A cosm_trade dialogue is only used in the contract-based TAC\",\n        )\n        enforce(\n            strategy.ledger_id == FetchAIApi.identifier,\n            \"A cosm_trade dialogue is only used in the fetchai-based TAC\",\n        )\n\n        cosm_trade_msg = cast(CosmTradeMessage, message)\n\n        # recover dialogue\n        cosm_trade_dialogues = cast(\n            CosmTradeDialogues, self.context.cosm_trade_dialogues\n        )\n        cosm_trade_dialogue = cast(\n            CosmTradeDialogue, cosm_trade_dialogues.update(cosm_trade_msg)\n        )\n        if cosm_trade_dialogue is None:\n            self._handle_unidentified_dialogue(cosm_trade_msg)\n            return\n\n        self.context.logger.info(\n            \"received {} from {} (as {}), message={}\".format(\n                cosm_trade_msg.performative.value,\n                cosm_trade_msg.sender[-5:],\n                cosm_trade_dialogue.role,\n                cosm_trade_msg,\n            )\n        )\n        if (\n            cosm_trade_msg.performative\n            == CosmTradeMessage.Performative.INFORM_SIGNED_TRANSACTION\n        ):\n            self._on_signed_tx(cosm_trade_msg, cosm_trade_dialogue)\n        elif cosm_trade_msg.performative == CosmTradeMessage.Performative.ERROR:\n            self._on_error(cosm_trade_msg, cosm_trade_dialogue)\n        elif cosm_trade_msg.performative == CosmTradeMessage.Performative.END:\n            self._on_end(cosm_trade_msg, cosm_trade_dialogue)\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n\n    def _handle_unidentified_dialogue(self, cosm_trade_msg: CosmTradeMessage) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        Respond to the sender with a default message containing the appropriate error information.\n\n        :param cosm_trade_msg: the message\n        \"\"\"\n        self.context.logger.info(\n            \"received invalid cosm_trade message={}, unidentified dialogue.\".format(\n                cosm_trade_msg\n            )\n        )\n        default_dialogues = cast(DefaultDialogues, self.context.default_dialogues)\n        default_msg, _ = default_dialogues.create(\n            counterparty=cosm_trade_msg.sender,\n            performative=DefaultMessage.Performative.ERROR,\n            error_code=DefaultMessage.ErrorCode.INVALID_DIALOGUE,\n            error_msg=\"Invalid dialogue.\",\n            error_data={\"cosm_trade_message\": cosm_trade_msg.encode()},\n        )\n        self.context.outbox.put_message(message=default_msg)\n\n    def _on_signed_tx(\n        self, inform_signed_tx: CosmTradeMessage, cosm_trade_dialogue: CosmTradeDialogue\n    ) -> None:\n        \"\"\"\n        Handle a Propose.\n\n        :param inform_signed_tx: the message containing the signed transaction\n        :param cosm_trade_dialogue: the cosm_trade_dialogue\n        \"\"\"\n        tx_signed_by_the_other_party = inform_signed_tx.signed_transaction\n        self.context.logger.info(\n            \"received inform_signed_tx with signed_tx={}\".format(\n                tx_signed_by_the_other_party\n            )\n        )\n\n        fipa_dialogue_ref = inform_signed_tx.fipa_dialogue_id\n        if fipa_dialogue_ref is None:\n            self.context.logger.info(\n                \"inform_signed_tx must contain fipa dialogue reference.\"\n            )\n            return\n\n        fipa_dialogues = cast(FipaDialogues, self.context.fipa_dialogues)\n        dialogue_label = DialogueLabel(\n            cast(Tuple[str, str], fipa_dialogue_ref),\n            inform_signed_tx.sender,\n            inform_signed_tx.sender,\n        )\n        fipa_dialogue = cast(\n            FipaDialogue, fipa_dialogues.get_dialogue_from_label(dialogue_label)\n        )\n\n        signing_dialogues = cast(SigningDialogues, self.context.signing_dialogues)\n        signing_msg, signing_dialogue = signing_dialogues.create(\n            counterparty=self.context.decision_maker_address,\n            performative=SigningMessage.Performative.SIGN_TRANSACTION,\n            raw_transaction=RawTransaction(\n                ledger_id=tx_signed_by_the_other_party.ledger_id,\n                body=tx_signed_by_the_other_party.body,\n            ),\n            terms=fipa_dialogue.terms,\n        )\n        signing_dialogue = cast(SigningDialogue, signing_dialogue)\n        signing_dialogue.associated_fipa_dialogue = fipa_dialogue\n        signing_dialogue.associated_cosm_trade_dialogue = cosm_trade_dialogue\n        self.context.decision_maker_message_queue.put_nowait(signing_msg)\n        self.context.logger.info(\n            \"proposing the transaction to the decision maker. Waiting for confirmation ...\"\n        )\n\n    def _on_error(\n        self, error_msg: CosmTradeMessage, cosm_trade_dialogue: CosmTradeDialogue\n    ) -> None:\n        \"\"\"\n        Handle an Error.\n\n        :param error_msg: the Error message\n        :param cosm_trade_dialogue: the cosm_trade_dialogue\n        \"\"\"\n        self.context.logger.info(\n            \"received cosm_trade_api error message={} in dialogue={}.\".format(\n                error_msg, cosm_trade_dialogue\n            )\n        )\n        cosm_trade_dialogues = cast(\n            CosmTradeDialogues, self.context.cosm_trade_dialogues\n        )\n        cosm_trade_dialogues.dialogue_stats.add_dialogue_endstate(\n            CosmTradeDialogue.EndState.FAILED, cosm_trade_dialogue.is_self_initiated\n        )\n\n    def _on_end(\n        self, end_msg: CosmTradeMessage, cosm_trade_dialogue: CosmTradeDialogue\n    ) -> None:\n        \"\"\"\n        Handle an End.\n\n        :param end_msg: the Accept message\n        :param cosm_trade_dialogue: the fipa_dialogue\n        \"\"\"\n        self.context.logger.info(\n            \"received cosm_trade_api end message={} in dialogue={}.\".format(\n                end_msg, cosm_trade_dialogue\n            )\n        )\n        cosm_trade_dialogues = cast(\n            CosmTradeDialogues, self.context.cosm_trade_dialogues\n        )\n        cosm_trade_dialogues.dialogue_stats.add_dialogue_endstate(\n            CosmTradeDialogue.EndState.SUCCESSFUL, cosm_trade_dialogue.is_self_initiated\n        )\n\n\nclass SigningHandler(Handler):\n    \"\"\"This class implements the transaction handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = SigningMessage.protocol_id  # type: Optional[PublicId]\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Dispatch message to relevant handler and respond.\n\n        :param message: the message\n        \"\"\"\n        signing_msg = cast(SigningMessage, message)\n\n        # recover dialogue\n        signing_dialogues = cast(SigningDialogues, self.context.signing_dialogues)\n        signing_dialogue = cast(\n            Optional[SigningDialogue], signing_dialogues.update(signing_msg)\n        )\n        if signing_dialogue is None:\n            self._handle_unidentified_dialogue(signing_msg)\n            return\n\n        self.context.logger.info(\n            \"received {} from decision_maker, message={}\".format(\n                signing_msg.performative.value,\n                signing_msg,\n            )\n        )\n        # handle message\n        if signing_msg.performative is SigningMessage.Performative.SIGNED_MESSAGE:\n            self._handle_signed_message(signing_msg, signing_dialogue)\n        elif signing_msg.performative is SigningMessage.Performative.SIGNED_TRANSACTION:\n            self._handle_signed_transaction(signing_msg, signing_dialogue)\n        elif signing_msg.performative is SigningMessage.Performative.ERROR:\n            self._handle_error(signing_msg, signing_dialogue)\n        else:\n            self._handle_invalid(signing_msg, signing_dialogue)\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n\n    def _handle_unidentified_dialogue(self, signing_msg: SigningMessage) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param signing_msg: the message\n        \"\"\"\n        self.context.logger.info(\n            \"received invalid signing message={}, unidentified dialogue.\".format(\n                signing_msg\n            )\n        )\n\n    def _handle_signed_message(\n        self, signing_msg: SigningMessage, signing_dialogue: SigningDialogue\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param signing_msg: the signing message\n        :param signing_dialogue: the dialogue\n        \"\"\"\n        fipa_dialogue = signing_dialogue.associated_fipa_dialogue\n        last_fipa_message = cast(FipaMessage, fipa_dialogue.last_incoming_message)\n        enforce(last_fipa_message is not None, \"last message not recovered.\")\n        if last_fipa_message.performative == FipaMessage.Performative.ACCEPT:\n            fipa_msg = fipa_dialogue.reply(\n                performative=FipaMessage.Performative.MATCH_ACCEPT_W_INFORM,\n                target_message=last_fipa_message,\n                info={\"signature\": signing_msg.signed_message.body},\n            )\n            self.context.outbox.put_message(message=fipa_msg)\n            self.context.logger.info(\n                \"sending {} to {} (as {}), message={}.\".format(\n                    fipa_msg.performative.value,\n                    fipa_msg.to[-5:],\n                    fipa_dialogue.role,\n                    fipa_msg,\n                )\n            )\n        elif (\n            last_fipa_message.performative\n            == FipaMessage.Performative.MATCH_ACCEPT_W_INFORM\n        ):\n            counterparty_signature = fipa_dialogue.counterparty_signature\n            tx_id = fipa_dialogue.terms.sender_hash\n            if \"transactions\" not in self.context.shared_state.keys():\n                self.context.shared_state[\"transactions\"] = OrderedDict()\n            tx = {\n                \"terms\": fipa_dialogue.terms,\n                \"sender_signature\": signing_msg.signed_message.body,\n                \"counterparty_signature\": counterparty_signature,\n            }\n            self.context.shared_state[\"transactions\"][tx_id] = tx\n            self.context.logger.info(f\"sending transaction to controller, tx={tx}.\")\n        else:\n            enforce(\n                False, \"last message should be of performative accept or match accept.\"\n            )\n\n    def _handle_signed_transaction(  # pylint: disable=unused-argument\n        self, signing_msg: SigningMessage, signing_dialogue: SigningDialogue\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param signing_msg: the signing message\n        :param signing_dialogue: the dialogue\n        \"\"\"\n        strategy = cast(Strategy, self.context.strategy)\n        if not strategy.is_contract_tx:\n            self.context.logger.warning(\n                \"signed transaction handler only for contract case.\"\n            )\n            return\n\n        cosm_trade_dialogue = signing_dialogue.associated_cosm_trade_dialogue\n        if cosm_trade_dialogue is not None:\n            # tx is now signed by both parties, submit to ledger\n            ledger_api_dialogues = cast(\n                LedgerApiDialogues, self.context.ledger_api_dialogues\n            )\n            ledger_api_msg, ledger_api_dialogue = ledger_api_dialogues.create(\n                counterparty=LEDGER_API_ADDRESS,\n                performative=LedgerApiMessage.Performative.SEND_SIGNED_TRANSACTION,\n                signed_transaction=signing_msg.signed_transaction,\n            )\n            ledger_api_dialogue = cast(LedgerApiDialogue, ledger_api_dialogue)\n            ledger_api_dialogue.associated_signing_dialogue = signing_dialogue\n            self.context.logger.info(\n                \"sending {} to ledger {}, message={}\".format(\n                    ledger_api_msg.performative,\n                    strategy.ledger_id,\n                    ledger_api_msg,\n                )\n            )\n            self.context.outbox.put_message(message=ledger_api_msg)\n            return\n\n        fipa_dialogue = signing_dialogue.associated_fipa_dialogue\n        last_fipa_message = cast(FipaMessage, fipa_dialogue.last_incoming_message)\n        enforce(last_fipa_message is not None, \"last message not recovered.\")\n        if last_fipa_message.performative == FipaMessage.Performative.ACCEPT:\n            fipa_msg = fipa_dialogue.reply(\n                performative=FipaMessage.Performative.MATCH_ACCEPT_W_INFORM,\n                target_message=last_fipa_message,\n                info={\"tx_signature\": signing_msg.signed_transaction},\n            )\n            self.context.logger.info(\n                \"sending {} to {} (as {}), message={}.\".format(\n                    fipa_msg.performative.value,\n                    fipa_msg.to[-5:],\n                    fipa_dialogue.role,\n                    fipa_msg,\n                )\n            )\n            self.context.outbox.put_message(message=fipa_msg)\n        elif (\n            last_fipa_message.performative\n            == FipaMessage.Performative.MATCH_ACCEPT_W_INFORM\n        ):\n            if strategy.ledger_id == EthereumApi.identifier:\n                ledger_api_dialogues = cast(\n                    LedgerApiDialogues, self.context.ledger_api_dialogues\n                )\n                ledger_api_msg, ledger_api_dialogue = ledger_api_dialogues.create(\n                    counterparty=LEDGER_API_ADDRESS,\n                    performative=LedgerApiMessage.Performative.SEND_SIGNED_TRANSACTION,\n                    signed_transaction=signing_msg.signed_transaction,\n                )\n                ledger_api_dialogue = cast(LedgerApiDialogue, ledger_api_dialogue)\n                ledger_api_dialogue.associated_signing_dialogue = signing_dialogue\n                self.context.logger.info(\n                    \"sending {} to ledger {}, message={}\".format(\n                        ledger_api_msg.performative,\n                        strategy.ledger_id,\n                        ledger_api_msg,\n                    )\n                )\n                self.context.outbox.put_message(message=ledger_api_msg)\n            elif strategy.ledger_id == FetchAIApi.identifier:\n                # send the constructed and signed tx to the other party to sign\n                cosm_trade_dialogues = cast(\n                    CosmTradeDialogues, self.context.cosm_trade_dialogues\n                )\n                cosm_trade_msg, _ = cosm_trade_dialogues.create(\n                    counterparty=signing_dialogue.associated_fipa_dialogue.dialogue_label.dialogue_opponent_addr,\n                    performative=CosmTradeMessage.Performative.INFORM_SIGNED_TRANSACTION,\n                    signed_transaction=signing_msg.signed_transaction,\n                    fipa_dialogue_id=signing_dialogue.associated_fipa_dialogue.dialogue_label.dialogue_reference,\n                )\n                self.context.logger.info(\n                    \"sending {} to {}, message={}.\".format(\n                        cosm_trade_msg.performative.value,\n                        cosm_trade_msg.to[-5:],\n                        cosm_trade_msg,\n                    )\n                )\n                self.context.outbox.put_message(message=cosm_trade_msg)\n            else:\n                enforce(False, f\"Unidentified ledger id: {strategy.ledger_id}\")\n        else:\n            enforce(\n                False, \"last message should be of performative accept or match accept.\"\n            )\n\n    def _handle_error(\n        self, signing_msg: SigningMessage, signing_dialogue: SigningDialogue\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param signing_msg: the signing message\n        :param signing_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.info(\n            \"transaction signing was not successful. Error_code={} in dialogue={}\".format(\n                signing_msg.error_code, signing_dialogue\n            )\n        )\n\n    def _handle_invalid(\n        self, signing_msg: SigningMessage, signing_dialogue: SigningDialogue\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param signing_msg: the signing message\n        :param signing_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.warning(\n            \"cannot handle signing message of performative={} in dialogue={}.\".format(\n                signing_msg.performative, signing_dialogue\n            )\n        )\n\n\nclass LedgerApiHandler(Handler):\n    \"\"\"Implement the ledger api handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = LedgerApiMessage.protocol_id  # type: Optional[PublicId]\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup for the handler.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to a message.\n\n        :param message: the message\n        \"\"\"\n        ledger_api_msg = cast(LedgerApiMessage, message)\n\n        # recover dialogue\n        ledger_api_dialogues = cast(\n            LedgerApiDialogues, self.context.ledger_api_dialogues\n        )\n        ledger_api_dialogue = cast(\n            Optional[LedgerApiDialogue], ledger_api_dialogues.update(ledger_api_msg)\n        )\n        if ledger_api_dialogue is None:\n            self._handle_unidentified_dialogue(ledger_api_msg)\n            return\n\n        # handle message\n        if ledger_api_msg.performative is LedgerApiMessage.Performative.BALANCE:\n            self._handle_balance(ledger_api_msg)\n        elif (\n            ledger_api_msg.performative\n            is LedgerApiMessage.Performative.TRANSACTION_DIGEST\n        ):\n            self._handle_transaction_digest(ledger_api_msg, ledger_api_dialogue)\n        elif (\n            ledger_api_msg.performative\n            is LedgerApiMessage.Performative.TRANSACTION_RECEIPT\n        ):\n            self._handle_transaction_receipt(ledger_api_msg)\n        elif ledger_api_msg.performative == LedgerApiMessage.Performative.ERROR:\n            self._handle_error(ledger_api_msg, ledger_api_dialogue)\n        else:\n            self._handle_invalid(ledger_api_msg, ledger_api_dialogue)\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n\n    def _handle_unidentified_dialogue(self, ledger_api_msg: LedgerApiMessage) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param ledger_api_msg: the message\n        \"\"\"\n        self.context.logger.info(\n            \"received invalid ledger_api message={}, unidentified dialogue.\".format(\n                ledger_api_msg\n            )\n        )\n\n    def _handle_balance(self, ledger_api_msg: LedgerApiMessage) -> None:\n        \"\"\"\n        Handle a message of balance performative.\n\n        :param ledger_api_msg: the ledger api message\n        \"\"\"\n        self.context.logger.info(\n            \"starting balance on {} ledger={}.\".format(\n                ledger_api_msg.ledger_id,\n                ledger_api_msg.balance,\n            )\n        )\n\n    def _handle_transaction_digest(\n        self, ledger_api_msg: LedgerApiMessage, ledger_api_dialogue: LedgerApiDialogue\n    ) -> None:\n        \"\"\"\n        Handle a message of transaction_digest performative.\n\n        :param ledger_api_msg: the ledger api message\n        :param ledger_api_dialogue: the ledger api dialogue\n        \"\"\"\n        self.context.logger.info(\n            \"transaction was successfully submitted. Transaction digest={}\".format(\n                ledger_api_msg.transaction_digest\n            )\n        )\n        msg = ledger_api_dialogue.reply(\n            performative=LedgerApiMessage.Performative.GET_TRANSACTION_RECEIPT,\n            target_message=ledger_api_msg,\n            transaction_digest=ledger_api_msg.transaction_digest,\n        )\n        self.context.outbox.put_message(message=msg)\n        self.context.logger.info(\"requesting transaction receipt.\")\n\n    def _handle_transaction_receipt(self, ledger_api_msg: LedgerApiMessage) -> None:\n        \"\"\"\n        Handle a message of transaction_receipt performative.\n\n        :param ledger_api_msg: the ledger api message\n        \"\"\"\n        is_transaction_successful = LedgerApis.is_transaction_settled(\n            ledger_api_msg.transaction_receipt.ledger_id,\n            ledger_api_msg.transaction_receipt.receipt,\n        )\n        if is_transaction_successful:\n            self.context.logger.info(\n                \"transaction was successfully settled. Transaction receipt={}\".format(\n                    ledger_api_msg.transaction_receipt\n                )\n            )\n        else:\n            self.context.logger.error(\n                \"transaction failed. Transaction receipt={}\".format(\n                    ledger_api_msg.transaction_receipt\n                )\n            )\n\n    def _handle_error(\n        self, ledger_api_msg: LedgerApiMessage, ledger_api_dialogue: LedgerApiDialogue\n    ) -> None:\n        \"\"\"\n        Handle a message of error performative.\n\n        :param ledger_api_msg: the ledger api message\n        :param ledger_api_dialogue: the ledger api dialogue\n        \"\"\"\n        self.context.logger.info(\n            \"received ledger_api error message={} in dialogue={}.\".format(\n                ledger_api_msg, ledger_api_dialogue\n            )\n        )\n\n    def _handle_invalid(\n        self, ledger_api_msg: LedgerApiMessage, ledger_api_dialogue: LedgerApiDialogue\n    ) -> None:\n        \"\"\"\n        Handle a message of invalid performative.\n\n        :param ledger_api_msg: the ledger api message\n        :param ledger_api_dialogue: the ledger api dialogue\n        \"\"\"\n        self.context.logger.warning(\n            \"cannot handle ledger_api message of performative={} in dialogue={}.\".format(\n                ledger_api_msg.performative,\n                ledger_api_dialogue,\n            )\n        )\n\n\nclass OefSearchHandler(Handler):\n    \"\"\"This class implements the oef search handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = OefSearchMessage.protocol_id  # type: Optional[PublicId]\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to a message.\n\n        :param message: the message\n        \"\"\"\n        oef_search_msg = cast(OefSearchMessage, message)\n\n        # recover dialogue\n        oef_search_dialogues = cast(\n            OefSearchDialogues, self.context.oef_search_dialogues\n        )\n        oef_search_dialogue = cast(\n            Optional[OefSearchDialogue], oef_search_dialogues.update(oef_search_msg)\n        )\n        if oef_search_dialogue is None:\n            self._handle_unidentified_dialogue(oef_search_msg)\n            return\n\n        # handle message\n        if oef_search_msg.performative == OefSearchMessage.Performative.SEARCH_RESULT:\n            self._on_search_result(oef_search_msg, oef_search_dialogue)\n        elif oef_search_msg.performative == OefSearchMessage.Performative.SUCCESS:\n            self._handle_success(oef_search_msg, oef_search_dialogue)\n        elif oef_search_msg.performative == OefSearchMessage.Performative.OEF_ERROR:\n            self._on_oef_error(oef_search_msg, oef_search_dialogue)\n        else:\n            self._handle_invalid(oef_search_msg, oef_search_dialogue)\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n\n    def _handle_unidentified_dialogue(self, oef_search_msg: OefSearchMessage) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param oef_search_msg: the message\n        \"\"\"\n        self.context.logger.warning(\n            \"received invalid oef_search message={}, unidentified dialogue.\".format(\n                oef_search_msg\n            )\n        )\n\n    def _handle_success(\n        self,\n        oef_search_success_msg: OefSearchMessage,\n        oef_search_dialogue: OefSearchDialogue,\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param oef_search_success_msg: the oef search message\n        :param oef_search_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.info(\n            \"received oef_search success message={} in dialogue={}.\".format(\n                oef_search_success_msg, oef_search_dialogue\n            )\n        )\n        target_message = cast(\n            OefSearchMessage,\n            oef_search_dialogue.get_message_by_id(oef_search_success_msg.target),\n        )\n        if (\n            target_message.performative\n            == OefSearchMessage.Performative.REGISTER_SERVICE\n        ):\n            description = target_message.service_description\n            data_model_name = description.data_model.name\n            registration_behaviour = cast(\n                GoodsRegisterAndSearchBehaviour,\n                self.context.behaviours.tac_negotiation,\n            )\n            if \"location_agent\" in data_model_name:\n                registration_behaviour.register_service()\n            elif \"set_service_key\" in data_model_name:\n                registration_behaviour.register_genus()\n            elif (\n                \"personality_agent\" in data_model_name\n                and description.values[\"piece\"] == \"genus\"\n            ):\n                registration_behaviour.register_classification()\n            elif (\n                \"personality_agent\" in data_model_name\n                and description.values[\"piece\"] == \"classification\"\n            ):\n                registration_behaviour.is_registered = True\n                self.context.logger.info(\n                    \"the agent, with its genus and classification, and its service are successfully registered on the SOEF.\"\n                )\n            else:\n                self.context.logger.warning(\n                    f\"received soef SUCCESS message as a reply to the following unexpected message: {target_message}\"\n                )\n\n    def _on_oef_error(\n        self,\n        oef_search_error_msg: OefSearchMessage,\n        oef_search_dialogue: OefSearchDialogue,\n    ) -> None:\n        \"\"\"\n        Handle an OEF error message.\n\n        :param oef_search_error_msg: the oef search msg\n        :param oef_search_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.warning(\n            \"received OEF Search error: dialogue_reference={}, oef_error_operation={}\".format(\n                oef_search_dialogue.dialogue_label.dialogue_reference,\n                oef_search_error_msg.oef_error_operation,\n            )\n        )\n        target_message = cast(\n            OefSearchMessage,\n            oef_search_dialogue.get_message_by_id(oef_search_error_msg.target),\n        )\n        if (\n            target_message.performative\n            == OefSearchMessage.Performative.REGISTER_SERVICE\n        ):\n            registration_behaviour = cast(\n                GoodsRegisterAndSearchBehaviour,\n                self.context.behaviours.tac_negotiation,\n            )\n            registration_behaviour.failed_registration_msg = target_message\n\n    def _on_search_result(\n        self, oef_search_msg: OefSearchMessage, oef_search_dialogue: OefSearchDialogue\n    ) -> None:\n        \"\"\"\n        Split the search results from the OEF search node.\n\n        :param oef_search_msg: the search result\n        :param oef_search_dialogue: the dialogue\n        \"\"\"\n        agents = list(oef_search_msg.agents)\n        search_id = oef_search_msg.dialogue_reference[0]\n        if self.context.agent_address in agents:\n            agents.remove(self.context.agent_address)\n        agents_less_self = tuple(agents)\n        self._handle_search(\n            agents_less_self,\n            search_id,\n            is_searching_for_sellers=oef_search_dialogue.is_seller_search,\n        )\n\n    def _handle_search(\n        self, agents: Tuple[str, ...], search_id: str, is_searching_for_sellers: bool\n    ) -> None:\n        \"\"\"\n        Handle the search response.\n\n        :param agents: the agents returned by the search\n        :param search_id: the search id\n        :param is_searching_for_sellers: whether the agent is searching for sellers\n        \"\"\"\n        searched_for = \"sellers\" if is_searching_for_sellers else \"buyers\"\n        if len(agents) > 0:\n            self.context.logger.info(\n                \"found potential {} agents={} on search_id={}.\".format(\n                    searched_for,\n                    list(map(lambda x: x[-5:], agents)),\n                    search_id,\n                )\n            )\n            strategy = cast(Strategy, self.context.strategy)\n            fipa_dialogues = cast(FipaDialogues, self.context.fipa_dialogues)\n            query = strategy.get_own_services_query(is_searching_for_sellers)\n\n            for opponent_addr in agents:\n                self.context.logger.info(\n                    \"sending CFP to agent={}\".format(opponent_addr[-5:])\n                )\n                fipa_msg, _ = fipa_dialogues.create(\n                    counterparty=opponent_addr,\n                    performative=FipaMessage.Performative.CFP,\n                    query=query,\n                )\n                self.context.outbox.put_message(message=fipa_msg)\n        else:\n            self.context.logger.info(\n                \"found no {} agents on search_id={}, continue searching.\".format(\n                    searched_for, search_id\n                )\n            )\n\n    def _handle_invalid(\n        self, oef_search_msg: OefSearchMessage, oef_search_dialogue: OefSearchDialogue\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param oef_search_msg: the oef search message\n        :param oef_search_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.warning(\n            \"cannot handle oef_search message of performative={} in dialogue={}.\".format(\n                oef_search_msg.performative,\n                oef_search_dialogue,\n            )\n        )\n\n\nclass ContractApiHandler(Handler):\n    \"\"\"Implement the contract api handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = ContractApiMessage.protocol_id  # type: Optional[PublicId]\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup for the handler.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to a message.\n\n        :param message: the message\n        \"\"\"\n        contract_api_msg = cast(ContractApiMessage, message)\n\n        # recover dialogue\n        contract_api_dialogues = cast(\n            ContractApiDialogues, self.context.contract_api_dialogues\n        )\n        contract_api_dialogue = cast(\n            Optional[ContractApiDialogue],\n            contract_api_dialogues.update(contract_api_msg),\n        )\n        if contract_api_dialogue is None:\n            self._handle_unidentified_dialogue(contract_api_msg)\n            return\n\n        # handle message\n        if contract_api_msg.performative is ContractApiMessage.Performative.RAW_MESSAGE:\n            self._handle_raw_message(contract_api_msg, contract_api_dialogue)\n        elif (\n            contract_api_msg.performative\n            is ContractApiMessage.Performative.RAW_TRANSACTION\n        ):\n            self._handle_raw_transaction(contract_api_msg, contract_api_dialogue)\n        elif contract_api_msg.performative == ContractApiMessage.Performative.ERROR:\n            self._handle_error(contract_api_msg, contract_api_dialogue)\n        else:\n            self._handle_invalid(contract_api_msg, contract_api_dialogue)\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n\n    def _handle_unidentified_dialogue(\n        self, contract_api_msg: ContractApiMessage\n    ) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param contract_api_msg: the message\n        \"\"\"\n        self.context.logger.info(\n            \"received invalid contract_api message={}, unidentified dialogue.\".format(\n                contract_api_msg\n            )\n        )\n\n    def _handle_raw_message(\n        self,\n        contract_api_msg: ContractApiMessage,\n        contract_api_dialogue: ContractApiDialogue,\n    ) -> None:\n        \"\"\"\n        Handle a message of raw_message performative.\n\n        :param contract_api_msg: the ledger api message\n        :param contract_api_dialogue: the ledger api dialogue\n        \"\"\"\n        self.context.logger.info(\"received raw message={}\".format(contract_api_msg))\n        signing_dialogues = cast(SigningDialogues, self.context.signing_dialogues)\n        signing_msg, signing_dialogue = signing_dialogues.create(\n            counterparty=self.context.decision_maker_address,\n            performative=SigningMessage.Performative.SIGN_MESSAGE,\n            raw_message=RawMessage(\n                contract_api_msg.raw_message.ledger_id,\n                contract_api_msg.raw_message.body,\n                is_deprecated_mode=True,\n            ),\n            terms=contract_api_dialogue.associated_fipa_dialogue.terms,\n        )\n        signing_dialogue = cast(SigningDialogue, signing_dialogue)\n        signing_dialogue.associated_fipa_dialogue = (\n            contract_api_dialogue.associated_fipa_dialogue\n        )\n        self.context.decision_maker_message_queue.put_nowait(signing_msg)\n        self.context.logger.info(\n            \"proposing the message to the decision maker. Waiting for confirmation ...\"\n        )\n\n    def _handle_raw_transaction(\n        self,\n        contract_api_msg: ContractApiMessage,\n        contract_api_dialogue: ContractApiDialogue,\n    ) -> None:\n        \"\"\"\n        Handle a message of raw_transaction performative.\n\n        :param contract_api_msg: the ledger api message\n        :param contract_api_dialogue: the ledger api dialogue\n        \"\"\"\n        self.context.logger.info(\"received raw transaction={}\".format(contract_api_msg))\n        signing_dialogues = cast(SigningDialogues, self.context.signing_dialogues)\n        signing_msg, signing_dialogue = signing_dialogues.create(\n            counterparty=self.context.decision_maker_address,\n            performative=SigningMessage.Performative.SIGN_TRANSACTION,\n            raw_transaction=contract_api_msg.raw_transaction,\n            terms=contract_api_dialogue.associated_fipa_dialogue.terms,\n        )\n        signing_dialogue = cast(SigningDialogue, signing_dialogue)\n        signing_dialogue.associated_fipa_dialogue = (\n            contract_api_dialogue.associated_fipa_dialogue\n        )\n        self.context.decision_maker_message_queue.put_nowait(signing_msg)\n        self.context.logger.info(\n            \"proposing the transaction to the decision maker. Waiting for confirmation ...\"\n        )\n\n    def _handle_error(\n        self,\n        contract_api_msg: ContractApiMessage,\n        contract_api_dialogue: ContractApiDialogue,\n    ) -> None:\n        \"\"\"\n        Handle a message of error performative.\n\n        :param contract_api_msg: the ledger api message\n        :param contract_api_dialogue: the ledger api dialogue\n        \"\"\"\n        self.context.logger.info(\n            \"received contract_api error message={} in dialogue={}.\".format(\n                contract_api_msg, contract_api_dialogue\n            )\n        )\n\n    def _handle_invalid(\n        self,\n        contract_api_msg: ContractApiMessage,\n        contract_api_dialogue: ContractApiDialogue,\n    ) -> None:\n        \"\"\"\n        Handle a message of invalid performative.\n\n        :param contract_api_msg: the ledger api message\n        :param contract_api_dialogue: the ledger api dialogue\n        \"\"\"\n        self.context.logger.warning(\n            \"cannot handle contract_api message of performative={} in dialogue={}.\".format(\n                contract_api_msg.performative,\n                contract_api_dialogue,\n            )\n        )\n"
  },
  {
    "path": "packages/fetchai/skills/tac_negotiation/helpers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This class contains the helpers for FIPA negotiation.\"\"\"\n\nimport copy\nfrom typing import Dict, List, Union, cast\n\nfrom aea.helpers.search.models import (\n    Attribute,\n    Constraint,\n    ConstraintExpr,\n    ConstraintType,\n    DataModel,\n    Description,\n    Or,\n    Query,\n)\n\n\nSUPPLY_DATAMODEL_NAME = \"supply\"\nDEMAND_DATAMODEL_NAME = \"demand\"\n\n\ndef _build_goods_datamodel(good_ids: List[str], is_supply: bool) -> DataModel:\n    \"\"\"\n    Build a data model for supply and demand of goods (i.e. for offered or requested goods).\n\n    :param good_ids: a list of ids (i.e. identifiers) of the relevant goods.\n    :param is_supply: Boolean indicating whether it is a supply or demand data model\n\n    :return: the data model.\n    \"\"\"\n    good_quantities_attributes = [\n        Attribute(good_id, int, True, \"A good on offer.\") for good_id in good_ids\n    ]\n    ledger_id_attribute = Attribute(\n        \"ledger_id\", str, True, \"The ledger for transacting.\"\n    )\n    currency_attribute = Attribute(\n        \"currency_id\", str, True, \"The currency for pricing and transacting the goods.\"\n    )\n    price_attribute = Attribute(\n        \"price\", int, False, \"The price of the goods in the currency.\"\n    )\n    fee_attribute = Attribute(\n        \"fee\",\n        int,\n        False,\n        \"The transaction fee payable by the buyer in the currency.\",\n    )\n    nonce_attribute = Attribute(\n        \"nonce\", str, False, \"The nonce to distinguish identical descriptions.\"\n    )\n    description = SUPPLY_DATAMODEL_NAME if is_supply else DEMAND_DATAMODEL_NAME\n    attributes = good_quantities_attributes + [\n        ledger_id_attribute,\n        currency_attribute,\n        price_attribute,\n        fee_attribute,\n        nonce_attribute,\n    ]\n    data_model = DataModel(description, attributes)\n    return data_model\n\n\ndef build_goods_description(\n    quantities_by_good_id: Dict[str, int],\n    currency_id: str,\n    ledger_id: str,\n    is_supply: bool,\n) -> Description:\n    \"\"\"\n    Get the service description (good quantities supplied or demanded and their price).\n\n    :param quantities_by_good_id: a dictionary mapping the ids of the goods to the quantities.\n    :param currency_id: the currency used for pricing and transacting.\n    :param ledger_id: the ledger used for transacting.\n    :param is_supply: True if the description is indicating supply, False if it's indicating demand.\n\n    :return: the description to advertise on the Service Directory.\n    \"\"\"\n    data_model = _build_goods_datamodel(\n        good_ids=list(quantities_by_good_id.keys()), is_supply=is_supply\n    )\n    values = cast(Dict[str, Union[int, str]], copy.copy(quantities_by_good_id))\n    values.update({\"currency_id\": currency_id})\n    values.update({\"ledger_id\": ledger_id})\n    desc = Description(values, data_model=data_model)\n    return desc\n\n\ndef build_goods_query(\n    good_ids: List[str],\n    currency_id: str,\n    ledger_id: str,\n    is_searching_for_sellers: bool,\n) -> Query:\n    \"\"\"\n    Build buyer or seller search query.\n\n    Specifically, build the search query\n        - to look for sellers if the agent is a buyer, or\n        - to look for buyers if the agent is a seller.\n\n    In particular, if the agent is a buyer and the demanded good ids are {'tac_good_0', 'tac_good_2', 'tac_good_3'}, the resulting constraint expression is:\n\n        tac_good_0 >= 1 OR tac_good_2 >= 1 OR tac_good_3 >= 1\n\n    That is, the OEF will return all the sellers that have at least one of the good in the query\n    (assuming that the sellers are registered with the data model specified).\n\n    :param good_ids: the list of good ids to put in the query\n    :param currency_id: the currency used for pricing and transacting.\n    :param ledger_id: the ledger used for transacting.\n    :param is_searching_for_sellers: Boolean indicating whether the query is for sellers (supply) or buyers (demand).\n\n    :return: the query\n    \"\"\"\n    data_model = _build_goods_datamodel(\n        good_ids=good_ids, is_supply=is_searching_for_sellers\n    )\n    constraints = [Constraint(good_id, ConstraintType(\">=\", 1)) for good_id in good_ids]\n    constraints.append(Constraint(\"currency_id\", ConstraintType(\"==\", currency_id)))\n    constraints.append(Constraint(\"ledger_id\", ConstraintType(\"==\", ledger_id)))\n    constraint_expr = cast(List[ConstraintExpr], constraints)\n\n    if len(good_ids) > 1:\n        constraint_expr = [Or(constraint_expr)]\n\n    query = Query(constraint_expr, model=data_model)\n    return query\n"
  },
  {
    "path": "packages/fetchai/skills/tac_negotiation/skill.yaml",
    "content": "name: tac_negotiation\nauthor: fetchai\nversion: 0.29.6\ntype: skill\ndescription: The tac negotiation skill implements the logic for an AEA to do fipa\n  negotiation in the TAC.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: QmNWeRkM9RzqkyPu5vQpdgXw5Qw8DpkX2ghNaAD6cNQnUo\n  __init__.py: Qmecsd4pHWrSSo4vdCLjzyersvLPDGcvQtudp2MdnbydA1\n  behaviours.py: QmP4S2fTjtYXYc4YRAgwafE3uXAAERbPienc4yBuAJojDA\n  dialogues.py: QmT3koAkBQ8ZBRMDrkKQV9K7s71mYxPTVDCDL7b9UcmsRe\n  handlers.py: QmTgPAgrMByEgbQLdR9a3DHfPGvf4LobtnppxVv3HPoTGA\n  helpers.py: QmUdAigxsjxG7qH34AYGTGySj7UXMm6AbruFGibhQXk9U7\n  strategy.py: QmchRFawnZrWso9gqiefSfJ1Z3wz7Z6dWeQLgNxnZ7h8Tx\n  transactions.py: QmbxD3g2Bc52GDhcy6njkbkA77C5Y1RxusNnRZ5Laounov\nfingerprint_ignore_patterns: []\nconnections:\n- fetchai/ledger:0.21.5\ncontracts:\n- fetchai/erc1155:0.23.3\nprotocols:\n- fetchai/contract_api:1.1.7\n- fetchai/cosm_trade:0.2.7\n- fetchai/default:1.1.7\n- fetchai/fipa:1.1.7\n- fetchai/ledger_api:1.1.7\n- fetchai/oef_search:1.1.7\n- fetchai/signing:1.1.7\nskills:\n- fetchai/tac_participation:0.25.6\nbehaviours:\n  clean_up:\n    args:\n      tick_interval: 5.0\n    class_name: TransactionCleanUpBehaviour\n  tac_negotiation:\n    args:\n      max_soef_registration_retries: 5\n      search_interval: 5.0\n    class_name: GoodsRegisterAndSearchBehaviour\nhandlers:\n  contract_api:\n    args: {}\n    class_name: ContractApiHandler\n  cosm_trade:\n    args: {}\n    class_name: CosmTradeHandler\n  fipa:\n    args: {}\n    class_name: FipaNegotiationHandler\n  ledger_api:\n    args: {}\n    class_name: LedgerApiHandler\n  oef:\n    args: {}\n    class_name: OefSearchHandler\n  signing:\n    args: {}\n    class_name: SigningHandler\nmodels:\n  contract_api_dialogues:\n    args: {}\n    class_name: ContractApiDialogues\n  cosm_trade_dialogues:\n    args: {}\n    class_name: CosmTradeDialogues\n  default_dialogues:\n    args: {}\n    class_name: DefaultDialogues\n  fipa_dialogues:\n    args: {}\n    class_name: FipaDialogues\n  ledger_api_dialogues:\n    args: {}\n    class_name: LedgerApiDialogues\n  oef_search_dialogues:\n    args: {}\n    class_name: OefSearchDialogues\n  signing_dialogues:\n    args: {}\n    class_name: SigningDialogues\n  strategy:\n    args:\n      classification:\n        piece: classification\n        value: tac.participant\n      is_contract_tx: false\n      location:\n        latitude: 51.5194\n        longitude: 0.127\n      personality_data:\n        piece: genus\n        value: data\n      register_as: both\n      search_for: both\n      search_radius: 5.0\n      service_key: tac_service\n      tx_fee_proposal: 1500000000000000\n    class_name: Strategy\n  transactions:\n    args:\n      pending_transaction_timeout: 30\n    class_name: Transactions\ndependencies:\n  aea-ledger-ethereum:\n    version: <2.0.0,>=1.0.0\n  aea-ledger-fetchai:\n    version: <2.0.0,>=1.0.0\nis_abstract: false\n"
  },
  {
    "path": "packages/fetchai/skills/tac_negotiation/strategy.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the abstract class defining an agent's strategy for the TAC.\"\"\"\n\nimport copy\nimport random\nfrom enum import Enum\nfrom typing import Any, Dict, List, Optional, Tuple, cast\n\nfrom aea.common import Address\nfrom aea.decision_maker.gop import OwnershipState, Preferences\nfrom aea.exceptions import enforce\nfrom aea.helpers.search.generic import (\n    AGENT_LOCATION_MODEL,\n    AGENT_PERSONALITY_MODEL,\n    AGENT_REMOVE_SERVICE_MODEL,\n    AGENT_SET_SERVICE_MODEL,\n)\nfrom aea.helpers.search.models import (\n    Constraint,\n    ConstraintType,\n    Description,\n    Location,\n    Query,\n)\nfrom aea.helpers.transaction.base import Terms\nfrom aea.skills.base import Model\n\nfrom packages.fetchai.contracts.erc1155.contract import PUBLIC_ID as CONTRACT_ID\nfrom packages.fetchai.skills.tac_negotiation.dialogues import FipaDialogue\nfrom packages.fetchai.skills.tac_negotiation.helpers import (\n    build_goods_description,\n    build_goods_query,\n)\nfrom packages.fetchai.skills.tac_negotiation.transactions import Transactions\n\n\nROUNDING_ADJUSTMENT = 1\nDEFAULT_LOCATION = {\"longitude\": 0.1270, \"latitude\": 51.5194}\nDEFAULT_SERVICE_KEY = \"tac_service\"\nDEFAULT_SEARCH_QUERY = {\n    \"search_key\": \"tac_service\",\n    \"search_value\": \"generic_service\",\n    \"constraint_type\": \"==\",\n}\nDEFAULT_PERSONALITY_DATA = {\"piece\": \"genus\", \"value\": \"data\"}\nDEFAULT_CLASSIFICATION = {\"piece\": \"classification\", \"value\": \"tac.participant\"}\nDEFAULT_SEARCH_RADIUS = 5.0\nDEFAULT_TX_FEE_PROPOSAL = 1500000000000000\n\n\nclass Strategy(Model):\n    \"\"\"This class defines an abstract strategy for the agent.\"\"\"\n\n    class RegisterAs(Enum):\n        \"\"\"This class defines the service registration options.\"\"\"\n\n        SELLER = \"seller\"\n        BUYER = \"buyer\"\n        BOTH = \"both\"\n\n    class SearchFor(Enum):\n        \"\"\"This class defines the service search options.\"\"\"\n\n        SELLERS = \"sellers\"\n        BUYERS = \"buyers\"\n        BOTH = \"both\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize the strategy of the agent.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        self._register_as = Strategy.RegisterAs(kwargs.pop(\"register_as\", \"both\"))\n        self._search_for = Strategy.SearchFor(kwargs.pop(\"search_for\", \"both\"))\n        self._is_contract_tx = kwargs.pop(\"is_contract_tx\", False)\n        ledger_id = kwargs.pop(\"ledger_id\", None)\n\n        location = kwargs.pop(\"location\", DEFAULT_LOCATION)\n        self._agent_location = {\n            \"location\": Location(\n                latitude=location[\"latitude\"], longitude=location[\"longitude\"]\n            )\n        }\n        self._set_personality_data = kwargs.pop(\n            \"personality_data\", DEFAULT_PERSONALITY_DATA\n        )\n        enforce(\n            len(self._set_personality_data) == 2\n            and \"piece\" in self._set_personality_data\n            and \"value\" in self._set_personality_data,\n            \"personality_data must contain keys `key` and `value`\",\n        )\n        self._set_classification = kwargs.pop(\"classification\", DEFAULT_CLASSIFICATION)\n        enforce(\n            len(self._set_classification) == 2\n            and \"piece\" in self._set_classification\n            and \"value\" in self._set_classification,\n            \"classification must contain keys `key` and `value`\",\n        )\n        self.service_key = kwargs.pop(\"service_key\", DEFAULT_SERVICE_KEY)\n        self.tac_version_id: Optional[str] = None\n        self._remove_service_data = {\"key\": self.service_key}\n        self._simple_service_data = {self.service_key: self._register_as.value}\n        self._radius = kwargs.pop(\"search_radius\", DEFAULT_SEARCH_RADIUS)\n        self._tx_fee_proposal = kwargs.pop(\"tx_fee_proposal\", DEFAULT_TX_FEE_PROPOSAL)\n\n        self._contract_id = str(CONTRACT_ID)\n\n        super().__init__(**kwargs)\n        self._ledger_id = (\n            ledger_id if ledger_id is not None else self.context.default_ledger_id\n        )\n\n    @property\n    def registering_as(self) -> str:\n        \"\"\"Get what the agent is registering as.\"\"\"\n        return (\n            self._register_as.value\n            if self._register_as != self.RegisterAs.BOTH\n            else \"buyer and seller\"\n        )\n\n    @property\n    def searching_for(self) -> str:\n        \"\"\"Get what the agent is searching for.\"\"\"\n        return (\n            self._search_for.value\n            if self._search_for != self.SearchFor.BOTH\n            else \"buyer and seller\"\n        )\n\n    @property\n    def searching_for_types(self) -> List[Tuple[bool, str]]:\n        \"\"\"Get the types the agent is searching for.\"\"\"\n        result = []  # type: List[Tuple[bool, str]]\n        if self._search_for in [self.SearchFor.SELLERS, self.SearchFor.BOTH]:\n            result.append((True, \"sellers\"))\n        if self._search_for in [self.SearchFor.BUYERS, self.SearchFor.BOTH]:\n            result.append((False, \"buyers\"))\n        return result\n\n    @property\n    def is_contract_tx(self) -> bool:\n        \"\"\"Check if tx are made against the ERC1155 or not.\"\"\"\n        return self._is_contract_tx\n\n    @property\n    def ledger_id(self) -> str:\n        \"\"\"Get the ledger id.\"\"\"\n        return self._ledger_id\n\n    @property\n    def contract_id(self) -> str:\n        \"\"\"Get the contract id.\"\"\"\n        return self._contract_id\n\n    @property\n    def contract_address(self) -> str:\n        \"\"\"Get the contract address.\"\"\"\n        contract_address = self.context.shared_state.get(\n            \"erc1155_contract_address\", None\n        )\n        enforce(contract_address is not None, \"ERC1155Contract address not set!\")\n        return contract_address\n\n    def get_location_description(self) -> Description:\n        \"\"\"\n        Get the location description.\n\n        :return: a description of the agent's location\n        \"\"\"\n        description = Description(\n            self._agent_location,\n            data_model=AGENT_LOCATION_MODEL,\n        )\n        return description\n\n    def get_register_service_description(self) -> Description:\n        \"\"\"\n        Get the register service description.\n\n        :return: a description of the offered services\n        \"\"\"\n        service_data = {\n            \"key\": f\"{self.service_key}_{self.tac_version_id}\",\n            \"value\": self._register_as.value,\n        }\n        description = Description(\n            service_data,\n            data_model=AGENT_SET_SERVICE_MODEL,\n        )\n        return description\n\n    def get_register_personality_description(self) -> Description:\n        \"\"\"\n        Get the register personality description.\n\n        :return: a description of the personality\n        \"\"\"\n        description = Description(\n            self._set_personality_data,\n            data_model=AGENT_PERSONALITY_MODEL,\n        )\n        return description\n\n    def get_register_classification_description(self) -> Description:\n        \"\"\"\n        Get the register classification description.\n\n        :return: a description of the classification\n        \"\"\"\n        description = Description(\n            self._set_classification,\n            data_model=AGENT_PERSONALITY_MODEL,\n        )\n        return description\n\n    def get_unregister_service_description(self) -> Description:\n        \"\"\"\n        Get the unregister service description.\n\n        :return: a description of the to be removed service\n        \"\"\"\n        description = Description(\n            self._remove_service_data,\n            data_model=AGENT_REMOVE_SERVICE_MODEL,\n        )\n        return description\n\n    def get_location_and_service_query(self) -> Query:\n        \"\"\"\n        Get the location and service query of the agent.\n\n        :return: the query\n        \"\"\"\n        close_to_my_service = Constraint(\n            \"location\",\n            ConstraintType(\n                \"distance\", (self._agent_location[\"location\"], self._radius)\n            ),\n        )\n        search_query = {\n            \"search_key\": f\"{self.service_key}_{self.tac_version_id}\",\n            \"search_value\": self._search_for.value,\n            \"constraint_type\": \"==\",\n        }\n        service_key_filter = Constraint(\n            search_query[\"search_key\"],\n            ConstraintType(\n                search_query[\"constraint_type\"],\n                search_query[\"search_value\"],\n            ),\n        )\n        query = Query(\n            [close_to_my_service, service_key_filter],\n        )\n        return query\n\n    def get_own_service_description(self, is_supply: bool) -> Description:\n        \"\"\"\n        Get the description of the supplied goods (as a seller), or the demanded goods (as a buyer).\n\n        :param is_supply: Boolean indicating whether it is supply or demand.\n        :return: the description (to advertise on the Service Directory).\n        \"\"\"\n        transactions = cast(Transactions, self.context.transactions)\n        ownership_state_after_locks = transactions.ownership_state_after_locks(\n            is_seller=is_supply\n        )\n        quantities_by_good_id = (\n            self._supplied_goods(ownership_state_after_locks.quantities_by_good_id)\n            if is_supply\n            else self._demanded_goods(ownership_state_after_locks.quantities_by_good_id)\n        )\n        currency_id = next(\n            iter(ownership_state_after_locks.amount_by_currency_id.keys())\n        )\n        desc = build_goods_description(\n            quantities_by_good_id=quantities_by_good_id,\n            currency_id=currency_id,\n            ledger_id=self.ledger_id,\n            is_supply=is_supply,\n        )\n        return desc\n\n    @staticmethod\n    def _supplied_goods(good_holdings: Dict[str, int]) -> Dict[str, int]:\n        \"\"\"\n        Generate a dictionary of quantities which are supplied.\n\n        :param good_holdings: a dictionary of current good holdings\n        :return: a dictionary of quantities supplied\n        \"\"\"\n        supply = {}  # type: Dict[str, int]\n        for good_id, quantity in good_holdings.items():\n            supply[good_id] = quantity - 1 if quantity > 1 else 0\n        return supply\n\n    @staticmethod\n    def _demanded_goods(good_holdings: Dict[str, int]) -> Dict[str, int]:\n        \"\"\"\n        Generate a dictionary of quantities which are demanded.\n\n        :param good_holdings: a dictionary of current good holdings\n        :return: a dictionary of quantities supplied\n        \"\"\"\n        demand = {}  # type: Dict[str, int]\n        for good_id in good_holdings.keys():\n            demand[good_id] = 1\n        return demand\n\n    def get_own_services_query(\n        self,\n        is_searching_for_sellers: bool,\n    ) -> Query:\n        \"\"\"\n        Build a query.\n\n        In particular, build the query to look for agents\n            - which supply the agent's demanded goods (i.e. sellers), or\n            - which demand the agent's supplied goods (i.e. buyers).\n\n        :param is_searching_for_sellers: Boolean indicating whether the search is for sellers or buyers.\n\n        :return: the Query, or None.\n        \"\"\"\n        transactions = cast(Transactions, self.context.transactions)\n        ownership_state_after_locks = transactions.ownership_state_after_locks(\n            is_seller=not is_searching_for_sellers\n        )\n        good_id_to_quantities = (\n            self._demanded_goods(ownership_state_after_locks.quantities_by_good_id)\n            if is_searching_for_sellers\n            else self._supplied_goods(ownership_state_after_locks.quantities_by_good_id)\n        )\n        currency_id = next(\n            iter(ownership_state_after_locks.amount_by_currency_id.keys())\n        )\n        query = build_goods_query(\n            good_ids=list(good_id_to_quantities.keys()),\n            currency_id=currency_id,\n            ledger_id=self.ledger_id,\n            is_searching_for_sellers=is_searching_for_sellers,\n        )\n        return query\n\n    def _get_proposal_for_query(\n        self, query: Query, is_seller: bool\n    ) -> Optional[Description]:\n        \"\"\"\n        Generate proposal (in the form of a description) which matches the query.\n\n        :param query: the query for which to build the proposal\n        :param is_seller: whether the agent making the proposal is a seller or not\n\n        :return: a description\n        \"\"\"\n        candidate_proposals = self._generate_candidate_proposals(is_seller)\n        proposals = []\n        for proposal in candidate_proposals:\n            if not query.check(proposal):\n                continue  # pragma: nocover\n            proposals.append(proposal)\n        if not proposals:\n            return None  # pragma: nocover\n        return random.choice(proposals)  # nosec\n\n    def get_proposal_for_query(\n        self, query: Query, role: FipaDialogue.Role\n    ) -> Optional[Description]:\n        \"\"\"\n        Generate proposal (in the form of a description) which matches the query.\n\n        :param query: the query for which to build the proposal\n        :param role: the role of the agent making the proposal (seller or buyer)\n\n        :return: a description\n        \"\"\"\n        is_seller = role == FipaDialogue.Role.SELLER\n\n        own_service_description = self.get_own_service_description(\n            is_supply=is_seller,\n        )\n        if not query.check(own_service_description):  # pragma: nocover\n            self.context.logger.debug(\"current holdings do not satisfy CFP query.\")\n            return None\n        proposal_description = self._get_proposal_for_query(query, is_seller=is_seller)\n        if proposal_description is None:\n            self.context.logger.debug(  # pragma: nocover\n                \"current strategy does not generate proposal that satisfies CFP query.\"\n            )\n        return proposal_description\n\n    def _generate_candidate_proposals(self, is_seller: bool) -> List[Description]:\n        \"\"\"\n        Generate proposals from the agent in the role of seller/buyer.\n\n        :param is_seller: the bool indicating whether the agent is a seller.\n\n        :return: a list of proposals in Description form\n        \"\"\"\n        transactions = cast(Transactions, self.context.transactions)\n        ownership_state_after_locks = transactions.ownership_state_after_locks(\n            is_seller=is_seller\n        )\n        good_id_to_quantities = (\n            self._supplied_goods(ownership_state_after_locks.quantities_by_good_id)\n            if is_seller\n            else self._demanded_goods(ownership_state_after_locks.quantities_by_good_id)\n        )\n        nil_proposal_dict = {\n            good_id: 0 for good_id in good_id_to_quantities.keys()\n        }  # type: Dict[str, int]\n        proposals = []\n        fee_by_currency_id = self.context.shared_state.get(\n            \"tx_fee\", {\"FET\": self._tx_fee_proposal}\n        )\n        buyer_tx_fee = next(iter(fee_by_currency_id.values()))\n        ownership_state = cast(\n            OwnershipState, self.context.decision_maker_handler_context.ownership_state\n        )\n        currency_id = list(ownership_state.amount_by_currency_id.keys())[0]\n        preferences = cast(\n            Preferences, self.context.decision_maker_handler_context.preferences\n        )\n        for good_id, quantity in good_id_to_quantities.items():\n            if is_seller and quantity == 0:\n                continue\n            proposal_dict = copy.copy(nil_proposal_dict)\n            proposal_dict[good_id] = 1\n            proposal = build_goods_description(\n                quantities_by_good_id=proposal_dict,\n                currency_id=currency_id,\n                ledger_id=self.ledger_id,\n                is_supply=is_seller,\n            )\n            if is_seller:\n                delta_quantities_by_good_id = {\n                    good_id: quantity * -1\n                    for good_id, quantity in proposal_dict.items()\n                }  # type: Dict[str, int]\n            else:\n                delta_quantities_by_good_id = proposal_dict\n            marginal_utility_from_delta_good_holdings = preferences.marginal_utility(\n                ownership_state=ownership_state_after_locks,\n                delta_quantities_by_good_id=delta_quantities_by_good_id,\n            )\n            switch = -1 if is_seller else 1\n            breakeven_price_rounded = (\n                round(marginal_utility_from_delta_good_holdings) * switch\n            )\n            if is_seller:\n                proposal.values[\"price\"] = breakeven_price_rounded + ROUNDING_ADJUSTMENT\n            else:\n                proposal.values[\"price\"] = (\n                    breakeven_price_rounded - buyer_tx_fee - ROUNDING_ADJUSTMENT\n                )\n            proposal.values[\"fee\"] = buyer_tx_fee\n            if not proposal.values[\"price\"] > 0:\n                continue\n            nonce = transactions.get_next_nonce()\n            proposal.values[\"nonce\"] = nonce\n            proposals.append(proposal)\n        return proposals\n\n    def is_profitable_transaction(self, terms: Terms, role: FipaDialogue.Role) -> bool:\n        \"\"\"\n        Check if a transaction is profitable.\n\n        Is it a profitable transaction?\n        - apply all the locks for role.\n        - check if the transaction is consistent with the locks (enough money/holdings)\n        - check that we gain score.\n\n        :param terms: the terms\n        :param role: the role of the agent (seller or buyer)\n\n        :return: True if the transaction is good (as stated above), False otherwise.\n        \"\"\"\n        is_seller = role == FipaDialogue.Role.SELLER\n\n        transactions = cast(Transactions, self.context.transactions)\n        ownership_state_after_locks = transactions.ownership_state_after_locks(\n            is_seller\n        )\n        if not ownership_state_after_locks.is_affordable_transaction(terms):\n            return False\n        preferences = cast(\n            Preferences, self.context.decision_maker_handler_context.preferences\n        )\n        proposal_delta_score = preferences.utility_diff_from_transaction(\n            ownership_state_after_locks, terms\n        )\n        return proposal_delta_score >= 0\n\n    @staticmethod\n    def terms_from_proposal(\n        proposal: Description,\n        sender: Address,\n        counterparty: Address,\n        role: FipaDialogue.Role,\n    ) -> Terms:\n        \"\"\"\n        Get the terms from a proposal.\n\n        :param proposal: the proposal\n        :param sender: the sender of the proposal\n        :param counterparty: the receiver of the proposal\n        :param role: the role\n        :return: the terms\n        \"\"\"\n        is_seller = role == FipaDialogue.Role.SELLER\n        goods_component = copy.copy(proposal.values)\n        [  # pylint: disable=expression-not-assigned\n            goods_component.pop(key)\n            for key in [\"fee\", \"price\", \"currency_id\", \"nonce\", \"ledger_id\"]\n        ]\n        # switch signs based on whether seller or buyer role\n        amount = proposal.values[\"price\"] if is_seller else -proposal.values[\"price\"]\n        fee = proposal.values[\"fee\"]\n        if is_seller:\n            for good_id in goods_component.keys():\n                goods_component[good_id] = goods_component[good_id] * (-1)\n        amount_by_currency_id = {proposal.values[\"currency_id\"]: amount}\n        fee_by_currency_id = {proposal.values[\"currency_id\"]: fee}\n        nonce = proposal.values[\"nonce\"]\n        ledger_id = proposal.values[\"ledger_id\"]\n        terms = Terms(\n            ledger_id=ledger_id,\n            sender_address=sender,\n            counterparty_address=counterparty,\n            amount_by_currency_id=amount_by_currency_id,\n            quantities_by_good_id=goods_component,\n            is_sender_payable_tx_fee=not is_seller,\n            nonce=nonce,\n            fee_by_currency_id=fee_by_currency_id,\n        )\n        return terms\n\n    @staticmethod\n    def kwargs_from_terms(\n        terms: Terms,\n        signature: Optional[str] = None,\n        sender_public_key: Optional[str] = None,\n        counterparty_public_key: Optional[str] = None,\n        is_from_terms_sender: bool = True,\n    ) -> Dict[str, Any]:\n        \"\"\"\n        Get the contract api message kwargs from the terms.\n\n        :param terms: the terms\n        :param signature: the signature (for ethereum or non-contract-based case)\n        :param sender_public_key: the sender's public key (for fetchai ledger case)\n        :param counterparty_public_key: the counterparty's public key (for fetchai ledger case)\n        :param is_from_terms_sender: whether from == terms.sender_address (i.e. agent submitting tx is the one which terms are considered)\n        :return: the kwargs\n        \"\"\"\n        all_tokens = {**terms.amount_by_currency_id, **terms.quantities_by_good_id}\n        token_ids = sorted([int(key) for key in all_tokens.keys()])\n        if is_from_terms_sender:\n            from_supplies = [\n                0\n                if int(all_tokens[str(token_id)]) >= 0\n                else -int(all_tokens[str(token_id)])\n                for token_id in token_ids\n            ]\n            to_supplies = [\n                0\n                if int(all_tokens[str(token_id)]) <= 0\n                else int(all_tokens[str(token_id)])\n                for token_id in token_ids\n            ]\n        else:\n            from_supplies = [\n                0\n                if int(all_tokens[str(token_id)]) <= 0\n                else int(all_tokens[str(token_id)])\n                for token_id in token_ids\n            ]\n            to_supplies = [\n                0\n                if int(all_tokens[str(token_id)]) >= 0\n                else -int(all_tokens[str(token_id)])\n                for token_id in token_ids\n            ]\n        kwargs = {\n            \"from_address\": terms.sender_address\n            if is_from_terms_sender\n            else terms.counterparty_address,\n            \"to_address\": terms.counterparty_address\n            if is_from_terms_sender\n            else terms.sender_address,\n            \"token_ids\": token_ids,\n            \"from_supplies\": from_supplies,\n            \"to_supplies\": to_supplies,\n            \"value\": 0,\n            \"trade_nonce\": int(terms.nonce),\n            \"tx_fee\": list(terms.fee_by_currency_id.values())[0],\n        }\n        enforce(\n            sender_public_key is not None\n            and counterparty_public_key is not None\n            or sender_public_key is None\n            and counterparty_public_key is None,\n            \"Either provide both sender's and counterparty's public-keys or neither's.\",\n        )\n        enforce(\n            not (\n                signature is not None\n                and sender_public_key is not None\n                and counterparty_public_key is not None\n            ),\n            \"Either provide signature (for Ethereum-based TAC) or sender and counterparty's public keys (for Fetchai-based TAC), or neither (for and non-contract-based Tac)\",\n        )\n        if signature is not None:\n            kwargs[\"signature\"] = signature\n        elif sender_public_key is not None:\n            kwargs[\"value\"] = 1\n            kwargs[\"from_pubkey\"] = sender_public_key\n            kwargs[\"to_pubkey\"] = counterparty_public_key\n        return kwargs\n"
  },
  {
    "path": "packages/fetchai/skills/tac_negotiation/transactions.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains a class to manage transactions.\"\"\"\n\nimport datetime\nfrom collections import defaultdict, deque\nfrom typing import Any, Deque, Dict, List, Tuple, cast\n\nfrom aea.decision_maker.gop import OwnershipState\nfrom aea.exceptions import enforce\nfrom aea.helpers.transaction.base import Terms\nfrom aea.protocols.dialogue.base import DialogueLabel\nfrom aea.skills.base import Model\n\nfrom packages.fetchai.skills.tac_negotiation.dialogues import FipaDialogue\n\n\nMessageId = int\n\n\nclass Transactions(Model):\n    \"\"\"Class to handle pending transaction proposals/acceptances and locked transactions.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"Initialize the transactions.\"\"\"\n        self._pending_transaction_timeout = kwargs.pop(\n            \"pending_transaction_timeout\", 30\n        )\n        super().__init__(**kwargs)\n        self._pending_proposals = defaultdict(\n            lambda: {}\n        )  # type: Dict[DialogueLabel, Dict[MessageId, Terms]]\n        self._pending_initial_acceptances = defaultdict(\n            lambda: {}\n        )  # type: Dict[DialogueLabel, Dict[MessageId, Terms]]\n\n        self._locked_txs = {}  # type: Dict[str, Terms]\n        self._locked_txs_as_buyer = {}  # type: Dict[str, Terms]\n        self._locked_txs_as_seller = {}  # type: Dict[str, Terms]\n\n        self._last_update_for_transactions = (\n            deque()\n        )  # type: Deque[Tuple[datetime.datetime, str]]\n        self._nonce = 0\n\n    @property\n    def pending_proposals(\n        self,\n    ) -> Dict[DialogueLabel, Dict[MessageId, Terms]]:\n        \"\"\"Get the pending proposals.\"\"\"\n        return self._pending_proposals\n\n    @property\n    def pending_initial_acceptances(\n        self,\n    ) -> Dict[DialogueLabel, Dict[MessageId, Terms]]:\n        \"\"\"Get the pending initial acceptances.\"\"\"\n        return self._pending_initial_acceptances\n\n    def get_next_nonce(self) -> str:\n        \"\"\"Get the next nonce.\"\"\"\n        self._nonce += 1\n        return str(self._nonce)\n\n    def update_confirmed_transactions(self) -> None:\n        \"\"\"Update model wrt to confirmed transactions.\"\"\"\n        confirmed_tx_ids = self.context.shared_state.pop(\n            \"confirmed_tx_ids\", []\n        )  # type: List[str]\n        for transaction_id in confirmed_tx_ids:\n            # remove (safely) the associated pending proposal (if present)\n            self._locked_txs.pop(transaction_id, None)\n            self._locked_txs_as_buyer.pop(transaction_id, None)\n            self._locked_txs_as_seller.pop(transaction_id, None)\n\n    def cleanup_pending_transactions(self) -> None:\n        \"\"\"Remove all the pending messages (i.e. either proposals or acceptances) that have been stored for an amount of time longer than the timeout.\"\"\"\n        queue = self._last_update_for_transactions\n        timeout = datetime.timedelta(0, self._pending_transaction_timeout)\n\n        if len(queue) == 0:\n            return\n\n        next_date, next_item = queue[0]\n\n        while datetime.datetime.now() - next_date > timeout:\n\n            # remove the element from the queue\n            queue.popleft()\n\n            # extract dialogue label and message id\n            transaction_id = next_item\n            self.context.logger.debug(\n                \"removing transaction from pending list: {}\".format(transaction_id)\n            )\n\n            # remove (safely) the associated pending proposal (if present)\n            self._locked_txs.pop(transaction_id, None)\n            self._locked_txs_as_buyer.pop(transaction_id, None)\n            self._locked_txs_as_seller.pop(transaction_id, None)\n\n            # check the next transaction, if present\n            if len(queue) == 0:\n                break  # pragma: no cover\n            next_date, next_item = queue[0]  # pragma: no cover\n\n    def add_pending_proposal(\n        self,\n        dialogue_label: DialogueLabel,\n        proposal_id: int,\n        terms: Terms,\n    ) -> None:\n        \"\"\"\n        Add a proposal (in the form of a transaction) to the pending list.\n\n        :param dialogue_label: the dialogue label associated with the proposal\n        :param proposal_id: the message id of the proposal\n        :param terms: the terms\n        \"\"\"\n        enforce(\n            dialogue_label not in self._pending_proposals\n            and proposal_id not in self._pending_proposals[dialogue_label],\n            \"Proposal is already in the list of pending proposals.\",\n        )\n        self._pending_proposals[dialogue_label][proposal_id] = terms\n\n    def pop_pending_proposal(\n        self, dialogue_label: DialogueLabel, proposal_id: int\n    ) -> Terms:\n        \"\"\"\n        Remove a proposal (in the form of a transaction) from the pending list.\n\n        :param dialogue_label: the dialogue label associated with the proposal\n        :param proposal_id: the message id of the proposal\n        :return: terms\n        \"\"\"\n        enforce(\n            dialogue_label in self._pending_proposals\n            and proposal_id in self._pending_proposals[dialogue_label],\n            \"Cannot find the proposal in the list of pending proposals.\",\n        )\n        terms = self._pending_proposals[dialogue_label].pop(proposal_id)\n        return terms\n\n    def add_pending_initial_acceptance(\n        self,\n        dialogue_label: DialogueLabel,\n        proposal_id: int,\n        terms: Terms,\n    ) -> None:\n        \"\"\"\n        Add an acceptance (in the form of a transaction) to the pending list.\n\n        :param dialogue_label: the dialogue label associated with the proposal\n        :param proposal_id: the message id of the proposal\n        :param terms: the terms\n        \"\"\"\n        enforce(\n            dialogue_label not in self._pending_initial_acceptances\n            and proposal_id not in self._pending_initial_acceptances[dialogue_label],\n            \"Initial acceptance is already in the list of pending initial acceptances.\",\n        )\n        self._pending_initial_acceptances[dialogue_label][proposal_id] = terms\n\n    def pop_pending_initial_acceptance(\n        self, dialogue_label: DialogueLabel, proposal_id: int\n    ) -> Terms:\n        \"\"\"\n        Remove an acceptance (in the form of a transaction) from the pending list.\n\n        :param dialogue_label: the dialogue label associated with the proposal\n        :param proposal_id: the message id of the proposal\n        :return: the transaction message\n        \"\"\"\n        enforce(\n            dialogue_label in self._pending_initial_acceptances\n            and proposal_id in self._pending_initial_acceptances[dialogue_label],\n            \"Cannot find the initial acceptance in the list of pending initial acceptances.\",\n        )\n        terms = self._pending_initial_acceptances[dialogue_label].pop(proposal_id)\n        return terms\n\n    def _register_transaction_with_time(self, transaction_id: str) -> None:\n        \"\"\"\n        Register a transaction with a creation datetime.\n\n        :param transaction_id: the transaction id\n        \"\"\"\n        now = datetime.datetime.now()\n        self._last_update_for_transactions.append((now, transaction_id))\n\n    def add_locked_tx(self, terms: Terms, role: FipaDialogue.Role) -> None:\n        \"\"\"\n        Add a lock (in the form of a transaction).\n\n        :param terms: the terms\n        :param role: the role of the agent (seller or buyer)\n        \"\"\"\n        as_seller = role == FipaDialogue.Role.SELLER\n\n        transaction_id = terms.id\n        enforce(\n            transaction_id not in self._locked_txs,\n            \"This transaction is already a locked transaction.\",\n        )\n        self._register_transaction_with_time(transaction_id)\n        self._locked_txs[transaction_id] = terms\n        if as_seller:\n            self._locked_txs_as_seller[transaction_id] = terms\n        else:\n            self._locked_txs_as_buyer[transaction_id] = terms\n\n    def pop_locked_tx(self, terms: Terms) -> Terms:\n        \"\"\"\n        Remove a lock (in the form of a transaction).\n\n        :param terms: the terms\n        :return: the transaction\n        \"\"\"\n        transaction_id = terms.id\n        enforce(\n            transaction_id in self._locked_txs,\n            \"Cannot find this transaction in the list of locked transactions.\",\n        )\n        terms = self._locked_txs.pop(transaction_id)\n        self._locked_txs_as_buyer.pop(transaction_id, None)\n        self._locked_txs_as_seller.pop(transaction_id, None)\n        return terms\n\n    def ownership_state_after_locks(self, is_seller: bool) -> OwnershipState:\n        \"\"\"\n        Apply all the locks to the current ownership state of the agent.\n\n        This assumes, that all the locked transactions will be successful.\n\n        :param is_seller: Boolean indicating the role of the agent.\n        :return: the agent state with the locks applied to current state\n        \"\"\"\n        all_terms = (\n            list(self._locked_txs_as_seller.values())\n            if is_seller\n            else list(self._locked_txs_as_buyer.values())\n        )\n        ownership_state = cast(\n            OwnershipState, self.context.decision_maker_handler_context.ownership_state\n        )\n        ownership_state_after_locks = ownership_state.apply_transactions(all_terms)\n        return ownership_state_after_locks\n"
  },
  {
    "path": "packages/fetchai/skills/tac_participation/README.md",
    "content": "# TAC Participation\n\n## Description\n\nThis is the skill for participating in a TAC.\n\nThis skill is part of the Fetch.ai TAC demo. It searches for a TAC on the sOEF, and if found, participates in the TAC by communicating with the controller agent.\n\n## Behaviours\n\n- `tac_search`: searches for a TAC\n- `transaction_processing`: processes transactions during the competition\n\n## Handlers\n\n- `tac`: handles `tac` messages by the controller for participating in the competition\n- `oef`: handles `oef_search` messages to find and connect with a controller\n\n## Links\n\n- <a href=\"https://docs.fetch.ai/aea/tac-skills-contract/\" target=\"_blank\">TAC Demo</a>\n"
  },
  {
    "path": "packages/fetchai/skills/tac_participation/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the implementation of the tac participation skill.\"\"\"\n\nfrom aea.configurations.base import PublicId\n\n\nPUBLIC_ID = PublicId.from_str(\"fetchai/tac_participation:0.25.6\")\n"
  },
  {
    "path": "packages/fetchai/skills/tac_participation/behaviours.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains a tac search behaviour.\"\"\"\n\nfrom collections import OrderedDict\nfrom typing import Any, Dict, cast\n\nfrom aea.skills.behaviours import TickerBehaviour\n\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.protocols.tac.message import TacMessage\nfrom packages.fetchai.skills.tac_participation.dialogues import OefSearchDialogues\nfrom packages.fetchai.skills.tac_participation.game import Game, Phase\n\n\nclass TacSearchBehaviour(TickerBehaviour):\n    \"\"\"This class scaffolds a behaviour.\"\"\"\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup.\"\"\"\n\n    def act(self) -> None:\n        \"\"\"Implement the act.\"\"\"\n        game = cast(Game, self.context.game)\n        if game.phase.value == Phase.PRE_GAME.value:\n            self._search_for_tac()\n\n    def teardown(self) -> None:\n        \"\"\"Implement the task teardown.\"\"\"\n\n    def _search_for_tac(self) -> None:\n        \"\"\"\n        Search for active TAC Controller.\n\n        We assume that the controller is registered as a service with the 'tac' data model\n        and with an attribute version = expected_version_id.\n        \"\"\"\n        game = cast(Game, self.context.game)\n        query = game.get_game_query()\n        oef_search_dialogues = cast(\n            OefSearchDialogues, self.context.oef_search_dialogues\n        )\n        oef_search_msg, _ = oef_search_dialogues.create(\n            counterparty=self.context.search_service_address,\n            performative=OefSearchMessage.Performative.SEARCH_SERVICES,\n            query=query,\n        )\n        self.context.outbox.put_message(message=oef_search_msg)\n        self.context.logger.info(\n            \"searching for TAC, search_id={}\".format(oef_search_msg.dialogue_reference)\n        )\n\n\nclass TransactionProcessBehaviour(TickerBehaviour):\n    \"\"\"This class implements the processing of the transactions class.\"\"\"\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup.\"\"\"\n\n    def act(self) -> None:\n        \"\"\"Implement the task execution.\"\"\"\n        game = cast(Game, self.context.game)\n        if game.phase.value == Phase.GAME.value:\n            self._process_transactions()\n\n    def teardown(self) -> None:\n        \"\"\"Implement the task teardown.\"\"\"\n\n    def _process_transactions(self) -> None:\n        \"\"\"Process transactions.\"\"\"\n        game = cast(Game, self.context.game)\n        tac_dialogue = game.tac_dialogue\n        transactions = cast(\n            Dict[str, Dict[str, Any]],\n            self.context.shared_state.get(\"transactions\", OrderedDict()),\n        )\n        tx_ids = list(transactions.keys())\n        for tx_id in tx_ids:\n            last_msg = (\n                tac_dialogue.last_message\n            )  # could be a problem if messages are delivered out of order\n            if last_msg is None:\n                raise ValueError(\"No last message available.\")\n            tx_content = transactions.pop(tx_id, None)\n            if tx_content is None:\n                raise ValueError(\"Tx for id={} not found.\".format(tx_id))\n            terms = tx_content[\"terms\"]\n            sender_signature = tx_content[\"sender_signature\"]\n            counterparty_signature = tx_content[\"counterparty_signature\"]\n            msg = tac_dialogue.reply(\n                performative=TacMessage.Performative.TRANSACTION,\n                target_message=last_msg,\n                transaction_id=tx_id,\n                ledger_id=terms.ledger_id,\n                sender_address=terms.sender_address,\n                counterparty_address=terms.counterparty_address,\n                amount_by_currency_id=terms.amount_by_currency_id,\n                fee_by_currency_id=terms.fee_by_currency_id,\n                quantities_by_good_id=terms.quantities_by_good_id,\n                sender_signature=sender_signature,\n                counterparty_signature=counterparty_signature,\n                nonce=terms.nonce,\n            )\n            self.context.logger.info(\n                \"sending transaction {} to controller, message={}.\".format(tx_id, msg)\n            )\n            self.context.outbox.put_message(message=msg)\n"
  },
  {
    "path": "packages/fetchai/skills/tac_participation/dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nThis module contains the classes required for dialogue management.\n\n- OefSearchDialogue: The dialogue class maintains state of a dialogue of type oef_search and manages it.\n- OefSearchDialogues: The dialogues class keeps track of all dialogues of type oef_search.\n- SigningDialogue: The dialogue class maintains state of a dialogue of type signing and manages it.\n- SigningDialogues: The dialogues class keeps track of all dialogues of type signing.\n- TacDialogue: The dialogue class maintains state of a dialogue of type tac and manages it.\n- TacDialogues: The dialogues class keeps track of all dialogues of type tac.\n\"\"\"\nfrom typing import Any\n\nfrom aea.protocols.base import Address, Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\nfrom aea.skills.base import Model\n\nfrom packages.fetchai.protocols.oef_search.dialogues import (\n    OefSearchDialogue as BaseOefSearchDialogue,\n)\nfrom packages.fetchai.protocols.oef_search.dialogues import (\n    OefSearchDialogues as BaseOefSearchDialogues,\n)\nfrom packages.fetchai.protocols.state_update.dialogues import (\n    StateUpdateDialogue as BaseStateUpdateDialogue,\n)\nfrom packages.fetchai.protocols.state_update.dialogues import (\n    StateUpdateDialogues as BaseStateUpdateDialogues,\n)\nfrom packages.fetchai.protocols.tac.dialogues import TacDialogue as BaseTacDialogue\nfrom packages.fetchai.protocols.tac.dialogues import TacDialogues as BaseTacDialogues\n\n\nOefSearchDialogue = BaseOefSearchDialogue\n\n\nclass OefSearchDialogues(Model, BaseOefSearchDialogues):\n    \"\"\"This class keeps track of all oef_search dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return BaseOefSearchDialogue.Role.AGENT\n\n        BaseOefSearchDialogues.__init__(\n            self,\n            self_address=str(self.skill_id),\n            role_from_first_message=role_from_first_message,\n        )\n\n\nStateUpdateDialogue = BaseStateUpdateDialogue\n\n\nclass StateUpdateDialogues(Model, BaseStateUpdateDialogues):\n    \"\"\"This class keeps track of all state_update dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return BaseStateUpdateDialogue.Role.SKILL\n\n        BaseStateUpdateDialogues.__init__(\n            self,\n            self_address=str(self.skill_id),\n            role_from_first_message=role_from_first_message,\n        )\n\n\nTacDialogue = BaseTacDialogue\n\n\nclass TacDialogues(Model, BaseTacDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return BaseTacDialogue.Role.PARTICIPANT\n\n        BaseTacDialogues.__init__(\n            self,\n            self_address=self.context.agent_address,\n            role_from_first_message=role_from_first_message,\n        )\n"
  },
  {
    "path": "packages/fetchai/skills/tac_participation/game.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains a class representing the game.\"\"\"\nfrom enum import Enum\nfrom typing import Any, Dict, List, Optional\n\nfrom aea.common import Address\nfrom aea.exceptions import AEAEnforceError, enforce\nfrom aea.helpers.search.models import Constraint, ConstraintType, Location, Query\nfrom aea.skills.base import Model\n\nfrom packages.fetchai.protocols.tac.message import TacMessage\nfrom packages.fetchai.skills.tac_participation.dialogues import (\n    StateUpdateDialogue,\n    TacDialogue,\n)\n\n\nDEFAULT_LOCATION = {\"longitude\": 0.1270, \"latitude\": 51.5194}\nDEFAULT_SEARCH_QUERY = {\n    \"search_key\": \"tac\",\n    \"search_value\": \"v1\",\n    \"constraint_type\": \"==\",\n}\nDEFAULT_SEARCH_RADIUS = 5.0\n\n\nclass Phase(Enum):\n    \"\"\"This class defines the phases of the game.\"\"\"\n\n    PRE_GAME = \"pre_game\"\n    GAME_REGISTRATION = \"game_registration\"\n    GAME_SETUP = \"game_setup\"\n    GAME = \"game\"\n    POST_GAME = \"post_game\"\n\n\nclass Configuration:\n    \"\"\"Class containing the game configuration of a TAC instance.\"\"\"\n\n    def __init__(\n        self,\n        version_id: str,\n        fee_by_currency_id: Dict[str, int],\n        agent_addr_to_name: Dict[Address, str],\n        good_id_to_name: Dict[str, str],\n        controller_addr: Address,\n    ):\n        \"\"\"\n        Instantiate a game configuration.\n\n        :param version_id: the version of the game.\n        :param fee_by_currency_id: the fee for a transaction by currency id.\n        :param agent_addr_to_name: a dictionary mapping agent addresses to agent names (as strings).\n        :param good_id_to_name: a dictionary mapping good ids to good names (as strings).\n        :param controller_addr: the address of the controller\n        \"\"\"\n        self._version_id = version_id\n        self._nb_agents = len(agent_addr_to_name)\n        self._nb_goods = len(good_id_to_name)\n        self._fee_by_currency_id = fee_by_currency_id\n        self._agent_addr_to_name = agent_addr_to_name\n        self._good_id_to_name = good_id_to_name\n        self._controller_addr = controller_addr\n\n        self._check_consistency()\n\n    @property\n    def version_id(self) -> str:\n        \"\"\"Agent number of a TAC instance.\"\"\"\n        return self._version_id\n\n    @property\n    def nb_agents(self) -> int:\n        \"\"\"Agent number of a TAC instance.\"\"\"\n        return self._nb_agents\n\n    @property\n    def nb_goods(self) -> int:\n        \"\"\"Good number of a TAC instance.\"\"\"\n        return self._nb_goods\n\n    @property\n    def tx_fee(self) -> int:\n        \"\"\"Transaction fee for the TAC instance.\"\"\"\n        enforce(\n            len(self._fee_by_currency_id) == 1, \"More than one currency id present!\"\n        )\n        value = next(iter(self._fee_by_currency_id.values()))\n        return value\n\n    @property\n    def fee_by_currency_id(self) -> Dict[str, int]:\n        \"\"\"Transaction fee for the TAC instance.\"\"\"\n        return self._fee_by_currency_id\n\n    @property\n    def agent_addr_to_name(self) -> Dict[Address, str]:\n        \"\"\"Map agent addresses to names.\"\"\"\n        return self._agent_addr_to_name\n\n    @property\n    def good_id_to_name(self) -> Dict[Address, str]:\n        \"\"\"Map good ids to names.\"\"\"\n        return self._good_id_to_name\n\n    @property\n    def agent_addresses(self) -> List[Address]:\n        \"\"\"List of agent addresses.\"\"\"\n        return list(self._agent_addr_to_name.keys())\n\n    @property\n    def agent_names(self) -> List[str]:\n        \"\"\"List of agent names.\"\"\"\n        return list(self._agent_addr_to_name.values())\n\n    @property\n    def good_ids(self) -> List[Address]:\n        \"\"\"List of good ids.\"\"\"\n        return list(self._good_id_to_name.keys())\n\n    @property\n    def good_names(self) -> List[str]:\n        \"\"\"List of good names.\"\"\"\n        return list(self._good_id_to_name.values())\n\n    @property\n    def controller_addr(self) -> str:\n        \"\"\"Get the controller address.\"\"\"\n        return self._controller_addr\n\n    def _check_consistency(self) -> None:\n        \"\"\"Check the consistency of the game configuration.\"\"\"\n        enforce(self.version_id is not None, \"A version id must be set.\")\n        enforce(\n            len(self.fee_by_currency_id) == 1 and self.tx_fee >= 0,\n            \"Tx fee must be non-negative.\",\n        )\n        enforce(self.nb_agents > 1, \"Must have at least two agents.\")\n        enforce(self.nb_goods > 1, \"Must have at least two goods.\")\n        enforce(\n            len(self.agent_addresses) == self.nb_agents,\n            \"There must be one address for each agent.\",\n        )\n        enforce(\n            len(set(self.agent_names)) == self.nb_agents,\n            \"Agents' names must be unique.\",\n        )\n        enforce(\n            len(self.good_ids) == self.nb_goods, \"There must be one id for each good.\"\n        )\n        enforce(\n            len(set(self.good_names)) == self.nb_goods, \"Goods' names must be unique.\"\n        )\n\n\nclass Game(Model):\n    \"\"\"This class deals with the game.\"\"\"\n\n    def __init__(self, **kwargs: Any):\n        \"\"\"Instantiate the game class.\"\"\"\n        self._expected_controller_addr = kwargs.pop(\n            \"expected_controller_addr\", None\n        )  # type: Optional[str]\n\n        self._search_query = kwargs.pop(\"search_query\", DEFAULT_SEARCH_QUERY)\n        if \"search_value\" not in self._search_query:  # pragma: nocover\n            raise ValueError(\"search_value not found in search_query\")\n        self._expected_version_id = self._search_query[\"search_value\"]\n        location = kwargs.pop(\"location\", DEFAULT_LOCATION)\n        self._agent_location = Location(\n            latitude=location[\"latitude\"], longitude=location[\"longitude\"]\n        )\n        self._radius = kwargs.pop(\"search_radius\", DEFAULT_SEARCH_RADIUS)\n\n        ledger_id = kwargs.pop(\"ledger_id\", None)\n        self._is_using_contract = kwargs.pop(\"is_using_contract\", False)  # type: bool\n        super().__init__(**kwargs)\n        self._phase = Phase.PRE_GAME\n        self._conf = None  # type: Optional[Configuration]\n        self._contract_address = None  # type: Optional[str]\n        self._tac_dialogue = None  # type: Optional[TacDialogue]\n        self._state_update_dialogue = None  # type: Optional[StateUpdateDialogue]\n        self._ledger_id = (\n            ledger_id if ledger_id is not None else self.context.default_ledger_id\n        )\n\n    @property\n    def ledger_id(self) -> str:\n        \"\"\"Get the ledger id.\"\"\"\n        return self._ledger_id\n\n    @property\n    def is_using_contract(self) -> bool:\n        \"\"\"Returns the is_using_contract.\"\"\"\n        return self._is_using_contract\n\n    @property\n    def expected_version_id(self) -> str:\n        \"\"\"Get the expected version id of the TAC.\"\"\"\n        return self._expected_version_id\n\n    @property\n    def phase(self) -> Phase:\n        \"\"\"Get the game phase.\"\"\"\n        return self._phase\n\n    @property\n    def contract_address(self) -> str:\n        \"\"\"Get the contract address.\"\"\"\n        if self._contract_address is None:\n            raise AEAEnforceError(\"Contract address not set!\")\n        return self._contract_address\n\n    @contract_address.setter\n    def contract_address(self, contract_address: str) -> None:\n        \"\"\"Set the contract address.\"\"\"\n        enforce(self._contract_address is None, \"Contract address already set!\")\n        self._contract_address = contract_address\n\n    @property\n    def tac_dialogue(self) -> TacDialogue:\n        \"\"\"Retrieve the tac dialogue.\"\"\"\n        if self._tac_dialogue is None:\n            raise AEAEnforceError(\"TacDialogue not set!\")\n        return self._tac_dialogue\n\n    @tac_dialogue.setter\n    def tac_dialogue(self, tac_dialogue: TacDialogue) -> None:\n        \"\"\"Set the tac dialogue.\"\"\"\n        enforce(self._tac_dialogue is None, \"TacDialogue already set!\")\n        self._tac_dialogue = tac_dialogue\n\n    @property\n    def state_update_dialogue(self) -> StateUpdateDialogue:\n        \"\"\"Retrieve the state_update dialogue.\"\"\"\n        if self._state_update_dialogue is None:\n            raise AEAEnforceError(\"StateUpdateDialogue not set!\")\n        return self._state_update_dialogue\n\n    @state_update_dialogue.setter\n    def state_update_dialogue(self, state_update_dialogue: StateUpdateDialogue) -> None:\n        \"\"\"Set the state_update dialogue.\"\"\"\n        enforce(self._state_update_dialogue is None, \"StateUpdateDialogue already set!\")\n        self._state_update_dialogue = state_update_dialogue\n\n    @property\n    def expected_controller_addr(self) -> Address:\n        \"\"\"Get the expected controller address.\"\"\"\n        if self._expected_controller_addr is None:\n            raise AEAEnforceError(\"Expected controller address not assigned!\")\n        return self._expected_controller_addr\n\n    @property\n    def conf(self) -> Configuration:\n        \"\"\"Get the game configuration.\"\"\"\n        if self._conf is None:\n            raise AEAEnforceError(\"Game configuration not assigned!\")\n        return self._conf\n\n    def init(self, tac_message: TacMessage, controller_addr: Address) -> None:\n        \"\"\"\n        Populate data structures with the game data.\n\n        :param tac_message: the tac message with the game instance data\n        :param controller_addr: the address of the controller\n        \"\"\"\n        enforce(\n            tac_message.performative == TacMessage.Performative.GAME_DATA,\n            \"Wrong TacMessage for initialization of TAC game.\",\n        )\n        enforce(\n            controller_addr == self.expected_controller_addr,\n            \"TacMessage from unexpected controller.\",\n        )\n        enforce(\n            tac_message.version_id == self.expected_version_id,\n            f\"TacMessage for unexpected game, expected={self.expected_version_id}, found={tac_message.version_id}\",\n        )\n        self._conf = Configuration(\n            tac_message.version_id,\n            tac_message.fee_by_currency_id,\n            tac_message.agent_addr_to_name,\n            tac_message.good_id_to_name,\n            controller_addr,\n        )\n\n    def update_expected_controller_addr(self, controller_addr: Address) -> None:\n        \"\"\"\n        Overwrite the expected controller address.\n\n        :param controller_addr: the address of the controller\n        \"\"\"\n        self.context.logger.warning(\n            \"TAKE CARE! Circumventing controller identity check! For added security provide the expected controller key as an argument to the Game instance and check against it.\"\n        )\n        self._expected_controller_addr = controller_addr\n\n    def update_game_phase(self, phase: Phase) -> None:\n        \"\"\"\n        Update the game phase.\n\n        :param phase: the game phase\n        \"\"\"\n        self._phase = phase\n\n    def get_game_query(self) -> Query:\n        \"\"\"\n        Get the query for the TAC game.\n\n        :return: the query\n        \"\"\"\n        close_to_my_service = Constraint(\n            \"location\", ConstraintType(\"distance\", (self._agent_location, self._radius))\n        )\n        service_key_filter = Constraint(\n            self._search_query[\"search_key\"],\n            ConstraintType(\n                self._search_query[\"constraint_type\"],\n                self._search_query[\"search_value\"],\n            ),\n        )\n        query = Query(\n            [close_to_my_service, service_key_filter],\n        )\n        return query\n"
  },
  {
    "path": "packages/fetchai/skills/tac_participation/handlers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains the handlers.\"\"\"\n\nfrom typing import Dict, Optional, Tuple, cast\n\nfrom aea.common import Address\nfrom aea.protocols.base import Message\nfrom aea.skills.base import Handler\n\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.protocols.state_update.message import StateUpdateMessage\nfrom packages.fetchai.protocols.tac.message import TacMessage\nfrom packages.fetchai.skills.tac_participation.dialogues import (\n    OefSearchDialogue,\n    OefSearchDialogues,\n    StateUpdateDialogue,\n    StateUpdateDialogues,\n    TacDialogue,\n    TacDialogues,\n)\nfrom packages.fetchai.skills.tac_participation.game import Game, Phase\n\n\nclass OefSearchHandler(Handler):\n    \"\"\"This class handles oef messages.\"\"\"\n\n    SUPPORTED_PROTOCOL = OefSearchMessage.protocol_id\n\n    def setup(self) -> None:\n        \"\"\"Implement the handler setup.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to a message.\n\n        :param message: the message\n        \"\"\"\n        oef_search_msg = cast(OefSearchMessage, message)\n\n        # recover dialogue\n        oef_search_dialogues = cast(\n            OefSearchDialogues, self.context.oef_search_dialogues\n        )\n        oef_search_dialogue = cast(\n            Optional[OefSearchDialogue], oef_search_dialogues.update(oef_search_msg)\n        )\n        if oef_search_dialogue is None:\n            self._handle_unidentified_dialogue(oef_search_msg)\n            return\n\n        # handle message\n        if oef_search_msg.performative == OefSearchMessage.Performative.SEARCH_RESULT:\n            self._on_search_result(oef_search_msg, oef_search_dialogue)\n        elif oef_search_msg.performative == OefSearchMessage.Performative.OEF_ERROR:\n            self._on_oef_error(oef_search_msg, oef_search_dialogue)\n        else:\n            self._handle_invalid(oef_search_msg, oef_search_dialogue)\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n\n    def _handle_unidentified_dialogue(self, oef_search_msg: OefSearchMessage) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param oef_search_msg: the message\n        \"\"\"\n        self.context.logger.warning(\n            \"received invalid oef_search message={}, unidentified dialogue.\".format(\n                oef_search_msg\n            )\n        )\n\n    def _on_oef_error(\n        self, oef_search_msg: OefSearchMessage, oef_search_dialogue: OefSearchDialogue\n    ) -> None:\n        \"\"\"\n        Handle an OEF error message.\n\n        :param oef_search_msg: the oef search msg\n        :param oef_search_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.warning(\n            \"received OEF Search error: dialogue_reference={}, oef_error_operation={}\".format(\n                oef_search_dialogue.dialogue_label.dialogue_reference,\n                oef_search_msg.oef_error_operation,\n            )\n        )\n\n    def _on_search_result(\n        self, oef_search_msg: OefSearchMessage, oef_search_dialogue: OefSearchDialogue\n    ) -> None:\n        \"\"\"\n        Split the search results from the OEF search node.\n\n        :param oef_search_msg: the search result\n        :param oef_search_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.debug(\n            \"on search result: dialogue_reference={} agents={}\".format(\n                oef_search_dialogue.dialogue_label.dialogue_reference,\n                oef_search_msg.agents,\n            )\n        )\n        self._on_controller_search_result(oef_search_msg.agents)\n\n    def _handle_invalid(\n        self, oef_search_msg: OefSearchMessage, oef_search_dialogue: OefSearchDialogue\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param oef_search_msg: the oef search message\n        :param oef_search_dialogue: the dialogue\n        \"\"\"\n        self.context.logger.warning(\n            \"cannot handle oef_search message of performative={} in dialogue={}.\".format(\n                oef_search_msg.performative,\n                oef_search_dialogue,\n            )\n        )\n\n    def _on_controller_search_result(\n        self, agent_addresses: Tuple[Address, ...]\n    ) -> None:\n        \"\"\"\n        Process the search result for a controller.\n\n        :param agent_addresses: list of agent addresses\n        \"\"\"\n        game = cast(Game, self.context.game)\n        if game.phase.value != Phase.PRE_GAME.value:\n            self.context.logger.debug(\n                \"ignoring controller search result, the agent is already competing.\"\n            )\n            return\n\n        if len(agent_addresses) == 0:\n            self.context.logger.info(\"couldn't find the TAC controller. Retrying...\")\n        elif len(agent_addresses) > 1:\n            self.context.logger.warning(\n                \"found more than one TAC controller. Retrying...\"\n            )\n        else:\n            self.context.logger.info(\"found the TAC controller. Registering...\")\n            controller_addr = agent_addresses[0]\n            self._register_to_tac(controller_addr)\n\n    def _register_to_tac(self, controller_addr: Address) -> None:\n        \"\"\"\n        Register to active TAC Controller.\n\n        :param controller_addr: the address of the controller.\n        \"\"\"\n        game = cast(Game, self.context.game)\n        game.update_expected_controller_addr(controller_addr)\n        game.update_game_phase(Phase.GAME_REGISTRATION)\n        tac_dialogues = cast(TacDialogues, self.context.tac_dialogues)\n        tac_msg, tac_dialogue = tac_dialogues.create(\n            counterparty=controller_addr,\n            performative=TacMessage.Performative.REGISTER,\n            agent_name=self.context.agent_name,\n        )\n        tac_dialogue = cast(TacDialogue, tac_dialogue)\n        game.tac_dialogue = tac_dialogue\n        self.context.outbox.put_message(message=tac_msg)\n        self.context.behaviours.tac_search.is_active = False\n        self.context.shared_state[\"tac_version_id\"] = game.expected_version_id\n\n\nclass TacHandler(Handler):\n    \"\"\"This class handles oef messages.\"\"\"\n\n    SUPPORTED_PROTOCOL = TacMessage.protocol_id\n\n    def setup(self) -> None:\n        \"\"\"Implement the handler setup.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to a message.\n\n        :param message: the message\n        \"\"\"\n        tac_msg = cast(TacMessage, message)\n\n        # recover dialogue\n        tac_dialogues = cast(TacDialogues, self.context.tac_dialogues)\n        tac_dialogue = cast(Optional[TacDialogue], tac_dialogues.update(tac_msg))\n        if tac_dialogue is None:\n            self._handle_unidentified_dialogue(tac_msg)\n            return\n\n        # handle message\n        game = cast(Game, self.context.game)\n        self.context.logger.debug(\n            \"handling controller response. performative={}\".format(tac_msg.performative)\n        )\n        if tac_msg.sender != game.expected_controller_addr:\n            raise ValueError(\n                \"The sender of the message is not the controller agent we registered with.\"\n            )\n\n        if tac_msg.performative == TacMessage.Performative.TAC_ERROR:\n            self._on_tac_error(tac_msg, tac_dialogue)\n        elif tac_msg.performative == TacMessage.Performative.GAME_DATA:\n            self._on_start(tac_msg)\n        elif tac_msg.performative == TacMessage.Performative.CANCELLED:\n            self._on_cancelled(tac_msg)\n        elif tac_msg.performative == TacMessage.Performative.TRANSACTION_CONFIRMATION:\n            self._on_transaction_confirmed(tac_msg)\n        else:\n            self._handle_invalid(tac_msg, tac_dialogue)\n\n    def teardown(self) -> None:\n        \"\"\"Implement the handler teardown.\"\"\"\n\n    def _handle_unidentified_dialogue(self, tac_msg: TacMessage) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param tac_msg: the message\n        \"\"\"\n        self.context.logger.warning(\n            \"received invalid tac message={}, unidentified dialogue.\".format(tac_msg)\n        )\n\n    def _on_tac_error(self, tac_msg: TacMessage, tac_dialogue: TacDialogue) -> None:\n        \"\"\"\n        Handle 'on tac error' event emitted by the controller.\n\n        :param tac_msg: The tac message.\n        :param tac_dialogue: the tac dialogue\n        \"\"\"\n        error_code = tac_msg.error_code\n        self.context.logger.debug(\n            \"received error from the controller in dialogue={}. error_msg={}\".format(\n                tac_dialogue, TacMessage.ErrorCode.to_msg(error_code.value)\n            )\n        )\n        if error_code == TacMessage.ErrorCode.TRANSACTION_NOT_VALID:\n            info = cast(Dict[str, str], tac_msg.info)\n            transaction_id = (\n                cast(str, info.get(\"transaction_id\"))\n                if (info is not None and info.get(\"transaction_id\") is not None)\n                else \"NO_TX_ID\"\n            )\n            self.context.logger.warning(\n                \"received error on transaction id: {}\".format(transaction_id[-10:])\n            )\n\n    def _on_start(self, tac_msg: TacMessage) -> None:\n        \"\"\"\n        Handle the 'start' event emitted by the controller.\n\n        :param tac_msg: the game data\n        \"\"\"\n        game = cast(Game, self.context.game)\n        if game.phase.value != Phase.GAME_REGISTRATION.value:\n            self.context.logger.warning(\n                \"we do not expect a start message in game phase={}\".format(\n                    game.phase.value\n                )\n            )\n            return\n\n        self.context.logger.info(\n            \"received start event from the controller. Starting to compete...\"\n        )\n        game = cast(Game, self.context.game)\n        game.init(tac_msg, tac_msg.sender)\n        game.update_game_phase(Phase.GAME)\n\n        if game.is_using_contract:\n            contract_address = (\n                None if tac_msg.info is None else tac_msg.info.get(\"contract_address\")\n            )\n\n            if contract_address is not None:\n                game.contract_address = contract_address\n                self.context.shared_state[\"erc1155_contract_address\"] = contract_address\n                self.context.logger.info(\n                    \"received a contract address: {}\".format(contract_address)\n                )\n                self._update_ownership_and_preferences(tac_msg)\n            else:\n                self.context.logger.warning(\"did not receive a contract address!\")\n        else:\n            self._update_ownership_and_preferences(tac_msg)\n\n    def _update_ownership_and_preferences(self, tac_msg: TacMessage) -> None:\n        \"\"\"\n        Update ownership and preferences.\n\n        :param tac_msg: the game data\n        \"\"\"\n        self.context.logger.info(\"processing game data, message={}\".format(tac_msg))\n        state_update_dialogues = cast(\n            StateUpdateDialogues, self.context.state_update_dialogues\n        )\n        state_update_msg, state_update_dialogue = state_update_dialogues.create(\n            counterparty=self.context.decision_maker_address,\n            performative=StateUpdateMessage.Performative.INITIALIZE,\n            amount_by_currency_id=tac_msg.amount_by_currency_id,\n            quantities_by_good_id=tac_msg.quantities_by_good_id,\n            exchange_params_by_currency_id=tac_msg.exchange_params_by_currency_id,\n            utility_params_by_good_id=tac_msg.utility_params_by_good_id,\n        )\n        self.context.shared_state[\"fee_by_currency_id\"] = tac_msg.fee_by_currency_id\n        state_update_dialogue = cast(StateUpdateDialogue, state_update_dialogue)\n        game = cast(Game, self.context.game)\n        game.state_update_dialogue = state_update_dialogue\n        self.context.decision_maker_message_queue.put_nowait(state_update_msg)\n\n    def _on_cancelled(self, tac_msg: TacMessage) -> None:\n        \"\"\"\n        Handle the cancellation of the competition from the TAC controller.\n\n        :param tac_msg: the TacMessage.\n        \"\"\"\n        game = cast(Game, self.context.game)\n        if game.phase.value not in [Phase.GAME_REGISTRATION.value, Phase.GAME.value]:\n            self.context.logger.warning(\n                \"we do not expect a message in game phase={}, received msg={}\".format(\n                    game.phase.value, tac_msg\n                )\n            )\n            return\n\n        self.context.logger.info(\"received cancellation from the controller.\")\n        game = cast(Game, self.context.game)\n        game.update_game_phase(Phase.POST_GAME)\n        self.context.is_active = False\n        self.context.shared_state[\"is_game_finished\"] = True\n\n    def _on_transaction_confirmed(self, tac_msg: TacMessage) -> None:\n        \"\"\"\n        Handle 'on transaction confirmed' event emitted by the controller.\n\n        :param tac_msg: the TacMessage.\n        \"\"\"\n        game = cast(Game, self.context.game)\n        if game.phase.value != Phase.GAME.value:\n            self.context.logger.warning(\n                \"we do not expect a transaction in game phase={}, received msg={}\".format(\n                    game.phase.value, tac_msg\n                )\n            )\n            return\n\n        self.context.logger.info(\n            \"received transaction confirmation from the controller: transaction_id={}\".format(\n                tac_msg.transaction_id\n            )\n        )\n        state_update_dialogue = game.state_update_dialogue\n        last_msg = state_update_dialogue.last_message\n        if last_msg is None:\n            raise ValueError(\"Could not retrieve last message.\")\n        state_update_msg = state_update_dialogue.reply(\n            performative=StateUpdateMessage.Performative.APPLY,\n            target_message=last_msg,\n            amount_by_currency_id=tac_msg.amount_by_currency_id,\n            quantities_by_good_id=tac_msg.quantities_by_good_id,\n        )\n        self.context.decision_maker_message_queue.put_nowait(state_update_msg)\n        if \"confirmed_tx_ids\" not in self.context.shared_state.keys():\n            self.context.shared_state[\"confirmed_tx_ids\"] = []\n        self.context.shared_state[\"confirmed_tx_ids\"].append(tac_msg.transaction_id)\n\n    def _handle_invalid(self, tac_msg: TacMessage, tac_dialogue: TacDialogue) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param tac_msg: the tac message\n        :param tac_dialogue: the tac dialogue\n        \"\"\"\n        self.context.logger.warning(\n            \"cannot handle tac message of performative={} in dialogue={}.\".format(\n                tac_msg.performative, tac_dialogue\n            )\n        )\n"
  },
  {
    "path": "packages/fetchai/skills/tac_participation/skill.yaml",
    "content": "name: tac_participation\nauthor: fetchai\nversion: 0.25.6\ntype: skill\ndescription: The tac participation skill implements the logic for an AEA to participate\n  in the TAC.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: QmW3M9mYP2NdtzpBytNaLCUrkno3xZoNieBZ58cdcku5nm\n  __init__.py: QmNS35yXppvMYqXC9E9P7hw8LYUcuWXdZKP5avkjWNWgT5\n  behaviours.py: QmVVeGX9SfhS59k1FDxdUNTexybigvjLRPZiVkrf2yG5kd\n  dialogues.py: QmWrqCc6RpPQW8Dw4sEocGHSRHPkrnAHfPqLhZsT1H5FJB\n  game.py: QmP5j5YdYyr5oKN2zGnurzCQSm25qGHh4RG9zVqQLkmdix\n  handlers.py: QmRDG5WLmebXtahUMG4DBNVgqKZUBmPv6Whvs5ogS58YuP\nfingerprint_ignore_patterns: []\nconnections: []\ncontracts:\n- fetchai/erc1155:0.23.3\nprotocols:\n- fetchai/oef_search:1.1.7\n- fetchai/state_update:1.1.7\n- fetchai/tac:1.1.7\nskills: []\nbehaviours:\n  tac_search:\n    args:\n      tick_interval: 5\n    class_name: TacSearchBehaviour\n  transaction_processing:\n    args:\n      tick_interval: 2\n    class_name: TransactionProcessBehaviour\nhandlers:\n  oef:\n    args: {}\n    class_name: OefSearchHandler\n  tac:\n    args: {}\n    class_name: TacHandler\nmodels:\n  game:\n    args:\n      is_using_contract: false\n      location:\n        latitude: 51.5194\n        longitude: 0.127\n      search_query:\n        constraint_type: ==\n        search_key: tac\n        search_value: v1\n      search_radius: 5.0\n    class_name: Game\n  oef_search_dialogues:\n    args: {}\n    class_name: OefSearchDialogues\n  state_update_dialogues:\n    args: {}\n    class_name: StateUpdateDialogues\n  tac_dialogues:\n    args: {}\n    class_name: TacDialogues\ndependencies: {}\nis_abstract: false\n"
  },
  {
    "path": "packages/fetchai/skills/task_test_skill/README.md",
    "content": "# Test task skill\n\n## Description\n\nSimple task skill to test\n\n## Handlers\n\n## Links\n"
  },
  {
    "path": "packages/fetchai/skills/task_test_skill/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains an example of skill for an AEA.\"\"\"\n\nfrom aea.configurations.base import PublicId\n\n\nPUBLIC_ID = PublicId.from_str(\"fetchai/task_test_skill:0.1.2\")\n"
  },
  {
    "path": "packages/fetchai/skills/task_test_skill/behaviours.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the behaviours for the 'test task skill' skill.\"\"\"\nfrom typing import Optional\n\nfrom aea.skills.behaviours import TickerBehaviour\nfrom aea.skills.tasks import Task\n\nfrom packages.fetchai.skills.task_test_skill.tasks import SimpleTask\n\n\nclass TaskBehaviour(TickerBehaviour):\n    \"\"\"Echo behaviour.\"\"\"\n\n    task_id: Optional[int]\n    task: Task\n\n    def setup(self) -> None:\n        \"\"\"Set up the behaviour.\"\"\"\n        self.context.logger.info(\"Task Behaviour: setup method called.\")\n        self.task = SimpleTask(\"some data\")\n        self.task_id = None\n\n    def act(self) -> None:\n        \"\"\"Act according to the behaviour.\"\"\"\n        self.context.logger.info(\"Task Behaviour: act method called.\")\n        if self.task_id is None:\n            self.set_task()\n        else:\n            self.get_task_result()\n\n    def set_task(self) -> None:\n        \"\"\"Set background task to run.\"\"\"\n        if self.task_id:\n            return\n        self.task_id = self.context.task_manager.enqueue_task(self.task)\n        self.context.logger.info(\"Task set.\")\n\n    def get_task_result(self) -> None:\n        \"\"\"Get result of the task.\"\"\"\n        if self.task_id is None:\n            return\n        async_result = self.context.task_manager.get_task_result(self.task_id)\n        if not async_result.ready():\n            return\n        self.context.logger.info(f\"Task result is ready: {async_result.get()}\")\n        self.task_id = None\n\n    def teardown(self) -> None:\n        \"\"\"Teardown the behaviour.\"\"\"\n        self.context.logger.info(\"Task Behaviour: teardown method called.\")\n"
  },
  {
    "path": "packages/fetchai/skills/task_test_skill/skill.yaml",
    "content": "name: task_test_skill\nauthor: fetchai\nversion: 0.1.2\ntype: skill\ndescription: Skill with simple task to run.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: QmcXGDniXKQgNuoKwYor6mb5qXMWRHSvFT8cppxTj66Ngz\n  __init__.py: QmVg95RRZXNFRM17PCy8iZSXBzsFo4Xm1PVP9k1nC7epiT\n  behaviours.py: QmSV3NmWaVLDF5GvCLXMjYSxUqZ5dAT5vXtazNZUtiquV8\n  tasks.py: QmUA5k1vGCXVfBA5RTcJZXnbQgy5YL7ZWtVViiJiBVmLiF\nfingerprint_ignore_patterns: []\nconnections: []\ncontracts: []\nprotocols: []\nskills: []\nbehaviours:\n  task:\n    args:\n      tick_interval: 3.0\n    class_name: TaskBehaviour\nhandlers: {}\nmodels: {}\ndependencies: {}\nis_abstract: false\n"
  },
  {
    "path": "packages/fetchai/skills/task_test_skill/tasks.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tasks for the 'task test skill' skill.\"\"\"\nimport time\nfrom typing import Any\n\nfrom aea.skills.tasks import Task\n\n\nclass SimpleTask(Task):\n    \"\"\"Simple task.\"\"\"\n\n    def __init__(self, data: Any):\n        \"\"\"Initialize the task.\"\"\"\n        super().__init__()\n        self.data = data\n\n    def execute(self, *args: Any, **kwargs: Any) -> Any:\n        \"\"\"Execute task.\"\"\"\n        time.sleep(3)\n        return self.data\n"
  },
  {
    "path": "packages/fetchai/skills/thermometer/README.md",
    "content": "# Thermometer\n\n## Description\n\nThis skill sells thermometer data.\n\nThis skill is part of the Fetch.ai thermometer demo. It can be requested (for example by an agent with the `thermometer_client` skill) to provide thermometer data. If agreement is reached on the price via negotiation, it reads data from a (real or fake) thermometer, then delivers it after receiving payment.\n\n## Behaviours\n\n- `service_registration`: registers thermometer data selling service on the sOEF\n\n## Handlers\n\n- `fipa`: handles `fipa` messages for negotiation\n- `ledger_api`: handles `ledger_api` messages for interacting with a ledger\n- `oef_search`: handles `oef_search` messages if service registration on the sOEF is unsuccessful\n\n## Links\n\n- <a href=\"https://docs.fetch.ai/aea/thermometer-skills/\" target=\"_blank\">Thermometer Demo</a>\n"
  },
  {
    "path": "packages/fetchai/skills/thermometer/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the implementation of the default skill.\"\"\"\n\nfrom aea.configurations.base import PublicId\n\n\nPUBLIC_ID = PublicId.from_str(\"fetchai/thermometer:0.27.6\")\n"
  },
  {
    "path": "packages/fetchai/skills/thermometer/behaviours.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the behaviours of the agent.\"\"\"\n\nfrom packages.fetchai.skills.generic_seller.behaviours import (\n    GenericServiceRegistrationBehaviour,\n)\n\n\nServiceRegistrationBehaviour = GenericServiceRegistrationBehaviour\n"
  },
  {
    "path": "packages/fetchai/skills/thermometer/dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nThis module contains the classes required for dialogue management.\n\n- DefaultDialogues: The dialogues class keeps track of all dialogues of type default.\n- FipaDialogues: The dialogues class keeps track of all dialogues of type fipa.\n- LedgerApiDialogues: The dialogues class keeps track of all dialogues of type ledger_api.\n- OefSearchDialogues: The dialogues class keeps track of all dialogues of type oef_search.\n\"\"\"\n\nfrom packages.fetchai.skills.generic_seller.dialogues import (\n    DefaultDialogues as GenericDefaultDialogues,\n)\nfrom packages.fetchai.skills.generic_seller.dialogues import (\n    FipaDialogues as GenericFipaDialogues,\n)\nfrom packages.fetchai.skills.generic_seller.dialogues import (\n    LedgerApiDialogues as GenericLedgerApiDialogues,\n)\nfrom packages.fetchai.skills.generic_seller.dialogues import (\n    OefSearchDialogues as GenericOefSearchDialogues,\n)\n\n\nDefaultDialogues = GenericDefaultDialogues\nFipaDialogues = GenericFipaDialogues\nLedgerApiDialogues = GenericLedgerApiDialogues\nOefSearchDialogues = GenericOefSearchDialogues\n"
  },
  {
    "path": "packages/fetchai/skills/thermometer/handlers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains the handlers of a thermometer AEA.\"\"\"\n\nfrom packages.fetchai.skills.generic_seller.handlers import (\n    GenericFipaHandler,\n    GenericLedgerApiHandler,\n    GenericOefSearchHandler,\n)\n\n\nFipaHandler = GenericFipaHandler\nLedgerApiHandler = GenericLedgerApiHandler\nOefSearchHandler = GenericOefSearchHandler\n"
  },
  {
    "path": "packages/fetchai/skills/thermometer/skill.yaml",
    "content": "name: thermometer\nauthor: fetchai\nversion: 0.27.6\ntype: skill\ndescription: The thermometer skill implements the functionality to sell data.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: QmUTeGxHXAZcM9hLcWTYywxMTdKjw7gQrXs2EAwgqejce9\n  __init__.py: QmNmBXfP81RZWToRq1JAoccVj6fgXg1VRFM9wpCrDjgKHz\n  behaviours.py: QmZvLViapWxG1H41wn4e6Mzt8nmV6yyuk2sSsLJKZTQy2c\n  dialogues.py: QmZckK3x2oPgXmnP4XaEBJQoaPp8Gh4ojDHnxzeNsTf4tC\n  handlers.py: QmZ2gCqdxWntR6nB7CZS5UBtKjFC4Y8g5Ex8afJq2B1b65\n  strategy.py: QmZGPb3pSyKYcz76yg9XiJYN1PZDjTL8VM7Y4tF19NtE9B\nfingerprint_ignore_patterns: []\nconnections: []\ncontracts: []\nprotocols:\n- fetchai/default:1.1.7\n- fetchai/fipa:1.1.7\n- fetchai/ledger_api:1.1.7\n- fetchai/oef_search:1.1.7\nskills:\n- fetchai/generic_seller:0.28.6\nbehaviours:\n  service_registration:\n    args:\n      services_interval: 20\n    class_name: ServiceRegistrationBehaviour\nhandlers:\n  fipa:\n    args: {}\n    class_name: FipaHandler\n  ledger_api:\n    args: {}\n    class_name: LedgerApiHandler\n  oef_search:\n    args: {}\n    class_name: OefSearchHandler\nmodels:\n  default_dialogues:\n    args: {}\n    class_name: DefaultDialogues\n  fipa_dialogues:\n    args: {}\n    class_name: FipaDialogues\n  ledger_api_dialogues:\n    args: {}\n    class_name: LedgerApiDialogues\n  oef_search_dialogues:\n    args: {}\n    class_name: OefSearchDialogues\n  strategy:\n    args:\n      classification:\n        piece: classification\n        value: seller\n      data_for_sale:\n        temperature: 26\n      has_data_source: false\n      is_ledger_tx: true\n      location:\n        latitude: 51.5194\n        longitude: 0.127\n      personality_data:\n        piece: genus\n        value: data\n      service_data:\n        key: seller_service\n        value: thermometer_data\n      service_id: thermometer_data\n      unit_price: 10\n    class_name: Strategy\ndependencies:\n  pyserial: {}\n  temper-py: {}\nis_abstract: false\n"
  },
  {
    "path": "packages/fetchai/skills/thermometer/strategy.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the strategy class.\"\"\"\n\nimport time\nfrom typing import Dict\n\nfrom temper import Temper\n\nfrom packages.fetchai.skills.generic_seller.strategy import GenericStrategy\n\n\nMAX_RETRIES = 10\n\n\nclass Strategy(GenericStrategy):\n    \"\"\"This class defines a strategy for the agent.\"\"\"\n\n    def collect_from_data_source(self) -> Dict[str, str]:\n        \"\"\"\n        Build the data payload.\n\n        :return: the data\n        \"\"\"\n        temper = Temper()\n        retries = 0\n        degrees = {}\n        while retries < MAX_RETRIES:\n            results = temper.read()\n            if \"internal temperature\" in results[0].keys():\n                degrees = {\"thermometer_data\": str(results[0][\"internal temperature\"])}\n                break\n            self.context.logger.debug(\"Couldn't read the sensor I am re-trying.\")\n            time.sleep(0.5)\n            retries += 1\n        return degrees\n"
  },
  {
    "path": "packages/fetchai/skills/thermometer_client/README.md",
    "content": "# Thermometer Client\n\n## Description\n\nThis skill buys thermometer data.\n\nThis skill is part of the Fetch.ai thermometer demo. It finds an agent which sells thermometer data, requests data from a reading and pays the proposed amount.\n\n## Behaviours\n\n- `search`: searches for thermometer data selling service on the sOEF\n- `transaction`: sequentially processes transactions' settlements on a blockchain\n\n## Handlers\n\n- `fipa`: handles `fipa` messages for negotiation\n- `ledger_api`: handles `ledger_api` messages for interacting with a ledger\n- `oef_search`: handles `oef_search` messages to manage the sellers found\n- `signing`: handles `signing` messages for transaction signing by the decision maker\n\n## Links\n\n- <a href=\"https://docs.fetch.ai/aea/thermometer-skills/\" target=\"_blank\">Thermometer Demo</a>\n"
  },
  {
    "path": "packages/fetchai/skills/thermometer_client/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the implementation of the default skill.\"\"\"\n\nfrom aea.configurations.base import PublicId\n\n\nPUBLIC_ID = PublicId.from_str(\"fetchai/thermometer_client:0.26.6\")\n"
  },
  {
    "path": "packages/fetchai/skills/thermometer_client/behaviours.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains the behaviours of the agent.\"\"\"\n\nfrom packages.fetchai.skills.generic_buyer.behaviours import (\n    GenericSearchBehaviour,\n    GenericTransactionBehaviour,\n)\n\n\nSearchBehaviour = GenericSearchBehaviour\nTransactionBehaviour = GenericTransactionBehaviour\n"
  },
  {
    "path": "packages/fetchai/skills/thermometer_client/dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nThis module contains the classes required for dialogue management.\n\n- DefaultDialogues: The dialogues class keeps track of all dialogues of type default.\n- FipaDialogues: The dialogues class keeps track of all dialogues of type fipa.\n- LedgerApiDialogues: The dialogues class keeps track of all dialogues of type ledger_api.\n- OefSearchDialogues: The dialogues class keeps track of all dialogues of type oef_search.\n- SigningDialogues: The dialogues class keeps track of all dialogues of type signing.\n\"\"\"\n\nfrom packages.fetchai.skills.generic_buyer.dialogues import (\n    DefaultDialogues as GenericDefaultDialogues,\n)\nfrom packages.fetchai.skills.generic_buyer.dialogues import (\n    FipaDialogues as GenericFipaDialogues,\n)\nfrom packages.fetchai.skills.generic_buyer.dialogues import (\n    LedgerApiDialogues as GenericLedgerApiDialogues,\n)\nfrom packages.fetchai.skills.generic_buyer.dialogues import (\n    OefSearchDialogues as GenericOefSearchDialogues,\n)\nfrom packages.fetchai.skills.generic_buyer.dialogues import (\n    SigningDialogues as GenericSigningDialogues,\n)\n\n\nDefaultDialogues = GenericDefaultDialogues\nFipaDialogues = GenericFipaDialogues\nLedgerApiDialogues = GenericLedgerApiDialogues\nOefSearchDialogues = GenericOefSearchDialogues\nSigningDialogues = GenericSigningDialogues\n"
  },
  {
    "path": "packages/fetchai/skills/thermometer_client/handlers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains the handlers of the agent.\"\"\"\n\nfrom packages.fetchai.skills.generic_buyer.handlers import (\n    GenericFipaHandler,\n    GenericLedgerApiHandler,\n    GenericOefSearchHandler,\n    GenericSigningHandler,\n)\n\n\nFipaHandler = GenericFipaHandler\nLedgerApiHandler = GenericLedgerApiHandler\nOefSearchHandler = GenericOefSearchHandler\nSigningHandler = GenericSigningHandler\n"
  },
  {
    "path": "packages/fetchai/skills/thermometer_client/skill.yaml",
    "content": "name: thermometer_client\nauthor: fetchai\nversion: 0.26.6\ntype: skill\ndescription: The thermometer client skill implements the skill to purchase temperature\n  data.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: QmdjHRzrhq636HNZYKaR8YCFKromFJqkKL3vMKHFpnmwSq\n  __init__.py: QmcrMiyeunFmRmJM8DsLg8FsHbFfqQaKChn3bcKp1sTumt\n  behaviours.py: QmSr6fB3N7dhVo1cLY1TGd2q8usjGwNmTCNjBBbtgtVf9j\n  dialogues.py: QmXgXcs25v9ob9a9XwT49wvK788vbUdZyYxUgG3ndHjrix\n  handlers.py: QmP3Q6x3NMcWgRi6H5GtDtvnLWSoB1HeG8vTd4zcRZUgNj\n  strategy.py: QmdHPLehqRr1dxuCbp4ENYmVMb8Ykvzg2Uzfos5kFJSr3D\nfingerprint_ignore_patterns: []\nconnections: []\ncontracts: []\nprotocols:\n- fetchai/default:1.1.7\n- fetchai/fipa:1.1.7\n- fetchai/ledger_api:1.1.7\n- fetchai/oef_search:1.1.7\n- fetchai/signing:1.1.7\nskills:\n- fetchai/generic_buyer:0.27.6\nbehaviours:\n  search:\n    args:\n      search_interval: 5\n    class_name: SearchBehaviour\n  transaction:\n    args:\n      max_processing: 420\n      transaction_interval: 2\n    class_name: TransactionBehaviour\nhandlers:\n  fipa:\n    args: {}\n    class_name: FipaHandler\n  ledger_api:\n    args: {}\n    class_name: LedgerApiHandler\n  oef_search:\n    args: {}\n    class_name: OefSearchHandler\n  signing:\n    args: {}\n    class_name: SigningHandler\nmodels:\n  default_dialogues:\n    args: {}\n    class_name: DefaultDialogues\n  fipa_dialogues:\n    args: {}\n    class_name: FipaDialogues\n  ledger_api_dialogues:\n    args: {}\n    class_name: LedgerApiDialogues\n  oef_search_dialogues:\n    args: {}\n    class_name: OefSearchDialogues\n  signing_dialogues:\n    args: {}\n    class_name: SigningDialogues\n  strategy:\n    args:\n      is_ledger_tx: true\n      location:\n        latitude: 51.5194\n        longitude: 0.127\n      max_negotiations: 1\n      max_quantity: 100\n      max_tx_fee: 3550000000000000\n      max_unit_price: 20\n      min_quantity: 1\n      search_query:\n        constraint_type: ==\n        search_key: seller_service\n        search_value: thermometer_data\n      search_radius: 5.0\n      service_id: thermometer_data\n    class_name: Strategy\ndependencies: {}\nis_abstract: false\n"
  },
  {
    "path": "packages/fetchai/skills/thermometer_client/strategy.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the strategy class.\"\"\"\n\nfrom packages.fetchai.skills.generic_buyer.strategy import GenericStrategy\n\n\nStrategy = GenericStrategy\n"
  },
  {
    "path": "packages/fetchai/skills/weather_client/README.md",
    "content": "# Weather Client\n\n## Description\n\nThis skill buys dummy weather data.\n\nThis skill is part of the Fetch.ai weather demo. It finds an agent which sells weather data, requests data for specific dates and pays the proposed amount.\n\n## Behaviours\n\n- `search`: searches for weather data selling service on the sOEF\n- `transaction`: sequentially processes transactions' settlements on a blockchain\n\n## Handlers\n\n- `fipa`: handles `fipa` messages for negotiation\n- `ledger_api`: handles `ledger_api` messages for interacting with a ledger\n- `oef_search`: handles `oef_search` messages to manage the sellers found\n- `signing`: handles `signing` messages for transaction signing by the decision maker\n\n## Links\n\n- <a href=\"https://docs.fetch.ai/aea/weather-skills/\" target=\"_blank\">Weather Demo</a>\n"
  },
  {
    "path": "packages/fetchai/skills/weather_client/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the implementation of the default skill.\"\"\"\n\nfrom aea.configurations.base import PublicId\n\n\nPUBLIC_ID = PublicId.from_str(\"fetchai/weather_client:0.26.6\")\n"
  },
  {
    "path": "packages/fetchai/skills/weather_client/behaviours.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains the behaviours of the agent.\"\"\"\n\nfrom packages.fetchai.skills.generic_buyer.behaviours import (\n    GenericSearchBehaviour,\n    GenericTransactionBehaviour,\n)\n\n\nSearchBehaviour = GenericSearchBehaviour\nTransactionBehaviour = GenericTransactionBehaviour\n"
  },
  {
    "path": "packages/fetchai/skills/weather_client/dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nThis module contains the classes required for dialogue management.\n\n- DefaultDialogues: The dialogues class keeps track of all dialogues of type default.\n- FipaDialogues: The dialogues class keeps track of all dialogues of type fipa.\n- LedgerApiDialogues: The dialogues class keeps track of all dialogues of type ledger_api.\n- OefSearchDialogues: The dialogues class keeps track of all dialogues of type oef_search.\n- SigningDialogues: The dialogues class keeps track of all dialogues of type signing.\n\"\"\"\n\nfrom packages.fetchai.skills.generic_buyer.dialogues import (\n    DefaultDialogues as GenericDefaultDialogues,\n)\nfrom packages.fetchai.skills.generic_buyer.dialogues import (\n    FipaDialogues as GenericFipaDialogues,\n)\nfrom packages.fetchai.skills.generic_buyer.dialogues import (\n    LedgerApiDialogues as GenericLedgerApiDialogues,\n)\nfrom packages.fetchai.skills.generic_buyer.dialogues import (\n    OefSearchDialogues as GenericOefSearchDialogues,\n)\nfrom packages.fetchai.skills.generic_buyer.dialogues import (\n    SigningDialogues as GenericSigningDialogues,\n)\n\n\nDefaultDialogues = GenericDefaultDialogues\nFipaDialogues = GenericFipaDialogues\nLedgerApiDialogues = GenericLedgerApiDialogues\nOefSearchDialogues = GenericOefSearchDialogues\nSigningDialogues = GenericSigningDialogues\n"
  },
  {
    "path": "packages/fetchai/skills/weather_client/handlers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains the handlers of the agent.\"\"\"\n\nfrom packages.fetchai.skills.generic_buyer.handlers import (\n    GenericFipaHandler,\n    GenericLedgerApiHandler,\n    GenericOefSearchHandler,\n    GenericSigningHandler,\n)\n\n\nFipaHandler = GenericFipaHandler\nLedgerApiHandler = GenericLedgerApiHandler\nOefSearchHandler = GenericOefSearchHandler\nSigningHandler = GenericSigningHandler\n"
  },
  {
    "path": "packages/fetchai/skills/weather_client/skill.yaml",
    "content": "name: weather_client\nauthor: fetchai\nversion: 0.26.6\ntype: skill\ndescription: The weather client skill implements the skill to purchase weather data.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: Qma4TrocZKtFcLeL1xKZxwz5no5qVHp5HjLrynYsKpw15Z\n  __init__.py: QmTEC9T2zb2a9pYoVeAJigGhAjKWN48MUnTRuyqm761UdM\n  behaviours.py: QmSr6fB3N7dhVo1cLY1TGd2q8usjGwNmTCNjBBbtgtVf9j\n  dialogues.py: QmXgXcs25v9ob9a9XwT49wvK788vbUdZyYxUgG3ndHjrix\n  handlers.py: QmP3Q6x3NMcWgRi6H5GtDtvnLWSoB1HeG8vTd4zcRZUgNj\n  strategy.py: QmdHPLehqRr1dxuCbp4ENYmVMb8Ykvzg2Uzfos5kFJSr3D\nfingerprint_ignore_patterns: []\nconnections: []\ncontracts: []\nprotocols:\n- fetchai/default:1.1.7\n- fetchai/fipa:1.1.7\n- fetchai/ledger_api:1.1.7\n- fetchai/oef_search:1.1.7\n- fetchai/signing:1.1.7\nskills:\n- fetchai/generic_buyer:0.27.6\nbehaviours:\n  search:\n    args:\n      search_interval: 5\n    class_name: SearchBehaviour\n  transaction:\n    args:\n      max_processing: 420\n      transaction_interval: 2\n    class_name: TransactionBehaviour\nhandlers:\n  fipa:\n    args: {}\n    class_name: FipaHandler\n  ledger_api:\n    args: {}\n    class_name: LedgerApiHandler\n  oef_search:\n    args: {}\n    class_name: OefSearchHandler\n  signing:\n    args: {}\n    class_name: SigningHandler\nmodels:\n  default_dialogues:\n    args: {}\n    class_name: DefaultDialogues\n  fipa_dialogues:\n    args: {}\n    class_name: FipaDialogues\n  ledger_api_dialogues:\n    args: {}\n    class_name: LedgerApiDialogues\n  oef_search_dialogues:\n    args: {}\n    class_name: OefSearchDialogues\n  signing_dialogues:\n    args: {}\n    class_name: SigningDialogues\n  strategy:\n    args:\n      is_ledger_tx: true\n      location:\n        latitude: 51.5194\n        longitude: 0.127\n      max_negotiations: 1\n      max_quantity: 100\n      max_tx_fee: 3550000000000000\n      max_unit_price: 20\n      min_quantity: 1\n      search_query:\n        constraint_type: ==\n        search_key: seller_service\n        search_value: weather_data\n      search_radius: 5.0\n      service_id: weather_data\n    class_name: Strategy\ndependencies: {}\nis_abstract: false\n"
  },
  {
    "path": "packages/fetchai/skills/weather_client/strategy.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the strategy class.\"\"\"\n\nfrom packages.fetchai.skills.generic_buyer.strategy import GenericStrategy\n\n\nStrategy = GenericStrategy\n"
  },
  {
    "path": "packages/fetchai/skills/weather_station/README.md",
    "content": "# Weather Station\n\n## Description\n\nThis skill sells dummy weather data.\n\nThis skill is part of the Fetch.ai weather demo. It reads data from a database, that is populated with  dummy data from a weather station. It can be requested (for example by an agent with the `weather_client` skill) to provide weather data for specific dates, which it delivers after it receives payment.\n\n## Behaviours\n\n- `service_registration`: registers weather selling service on the sOEF\n\n## Handlers\n\n- `fipa`: handles `fipa` messages for negotiation\n- `ledger_api`: handles `ledger_api` messages for interacting with a ledger\n- `oef_search`: handles `oef_search` messages if service registration on the sOEF is unsuccessful\n\n## Links\n\n- <a href=\"https://docs.fetch.ai/aea/weather-skills/\" target=\"_blank\">Weather Demo</a>\n"
  },
  {
    "path": "packages/fetchai/skills/weather_station/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the implementation of the default skill.\"\"\"\n\nfrom aea.configurations.base import PublicId\n\n\nPUBLIC_ID = PublicId.from_str(\"fetchai/weather_station:0.27.6\")\n"
  },
  {
    "path": "packages/fetchai/skills/weather_station/behaviours.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the behaviours of the agent.\"\"\"\n\n\nfrom packages.fetchai.skills.generic_seller.behaviours import (\n    GenericServiceRegistrationBehaviour,\n)\n\n\nServiceRegistrationBehaviour = GenericServiceRegistrationBehaviour\n"
  },
  {
    "path": "packages/fetchai/skills/weather_station/db_communication.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains the Database Communication for the weather agent.\"\"\"\n\nimport datetime\nimport os.path\nimport sqlite3\nfrom typing import Dict, cast\n\n\nmy_path = os.path.dirname(__file__)\n\nDB_SOURCE = os.path.join(my_path, \"dummy_weather_station_data.db\")\n\n\nclass DBCommunication:\n    \"\"\"A class to communicate with a database.\"\"\"\n\n    def __init__(self) -> None:\n        \"\"\"Initialize the database communication.\"\"\"\n        self.source = DB_SOURCE\n\n    def db_connection(self) -> sqlite3.Connection:\n        \"\"\"\n        Get db connection.\n\n        :return: the db connection\n        \"\"\"\n        con = sqlite3.connect(self.source)\n        return con\n\n    def get_data_for_specific_dates(\n        self, start_date: str, end_date: str\n    ) -> Dict[str, int]:\n        \"\"\"\n        Get data for specific dates.\n\n        :param start_date: the start date\n        :param end_date: the end date\n        :return: the data\n        \"\"\"\n        con = self.db_connection()\n        cur = con.cursor()\n        start_dt = datetime.datetime.strptime(start_date, \"%d/%m/%Y\")\n        start = int((start_dt - datetime.datetime.fromtimestamp(0)).total_seconds())\n        end_dt = datetime.datetime.strptime(end_date, \"%d/%m/%Y\")\n        end = int((end_dt - datetime.datetime.fromtimestamp(0)).total_seconds())\n        cur.execute(\n            \"SELECT * FROM data WHERE idx BETWEEN ? AND ?\", (str(start), str(end))\n        )\n        data = cast(Dict[str, int], cur.fetchall())\n        cur.close()\n        con.close()\n        return data\n"
  },
  {
    "path": "packages/fetchai/skills/weather_station/dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nThis module contains the classes required for dialogue management.\n\n- DefaultDialogues: The dialogues class keeps track of all dialogues of type default.\n- FipaDialogues: The dialogues class keeps track of all dialogues of type fipa.\n- LedgerApiDialogues: The dialogues class keeps track of all dialogues of type ledger_api.\n- OefSearchDialogues: The dialogues class keeps track of all dialogues of type oef_search.\n\"\"\"\n\nfrom packages.fetchai.skills.generic_seller.dialogues import (\n    DefaultDialogues as GenericDefaultDialogues,\n)\nfrom packages.fetchai.skills.generic_seller.dialogues import (\n    FipaDialogues as GenericFipaDialogues,\n)\nfrom packages.fetchai.skills.generic_seller.dialogues import (\n    LedgerApiDialogues as GenericLedgerApiDialogues,\n)\nfrom packages.fetchai.skills.generic_seller.dialogues import (\n    OefSearchDialogues as GenericOefSearchDialogues,\n)\n\n\nDefaultDialogues = GenericDefaultDialogues\nFipaDialogues = GenericFipaDialogues\nLedgerApiDialogues = GenericLedgerApiDialogues\nOefSearchDialogues = GenericOefSearchDialogues\n"
  },
  {
    "path": "packages/fetchai/skills/weather_station/dummy_weather_station_data.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains dummy weather station data.\"\"\"\n\nimport datetime\nimport logging\nimport os.path\nimport random\nimport sqlite3\nimport time\nfrom typing import Dict, Union\n\nfrom aea.exceptions import enforce\n\n\n_default_logger = logging.getLogger(\n    \"aea.packages.fetchai.skills.weather_station.dummy_weather_station_data\"\n)\n\nmy_path = os.path.dirname(__file__)\n\nDB_SOURCE = os.path.join(my_path, \"dummy_weather_station_data.db\")\n\n# Checking if the database exists\ncon = sqlite3.connect(DB_SOURCE)\ncur = con.cursor()\n\ncur.close()\ncon.commit()\ncon.close()\n\n# Create a table if it doesn't exist'\ncommand = \"\"\" CREATE TABLE IF NOT EXISTS data (\n                                 abs_pressure REAL,\n                                 delay REAL,\n                                 hum_in REAL,\n                                 hum_out REAL,\n                                 idx TEXT,\n                                 rain REAL,\n                                 temp_in REAL,\n                                 temp_out REAL,\n                                 wind_ave REAL,\n                                 wind_dir REAL,\n                                 wind_gust REAL)\"\"\"\n\ncon = sqlite3.connect(DB_SOURCE)\ncur = con.cursor()\ncur.execute(command)\ncur.close()\ncon.commit()\nif con is not None:\n    _default_logger.debug(\n        \"Weather station: I closed the db after checking it is populated!\"\n    )\n    con.close()\n\n\nclass Forecast:\n    \"\"\"Represents a whether forecast.\"\"\"\n\n    @staticmethod\n    def add_data(tagged_data: Dict[str, Union[int, datetime.datetime]]) -> None:\n        \"\"\"\n        Add data to the forecast.\n\n        :param tagged_data: the data dictionary\n        \"\"\"\n        con_ = sqlite3.connect(DB_SOURCE)\n        cur_ = con_.cursor()\n        cur_.execute(\n            \"\"\"INSERT INTO data(abs_pressure,\n                                       delay,\n                                       hum_in,\n                                       hum_out,\n                                       idx,\n                                       rain,\n                                       temp_in,\n                                       temp_out,\n                                       wind_ave,\n                                       wind_dir,\n                                       wind_gust) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\"\"\",\n            (\n                tagged_data[\"abs_pressure\"],\n                tagged_data[\"delay\"],\n                tagged_data[\"hum_in\"],\n                tagged_data[\"hum_out\"],\n                int(\n                    (\n                        datetime.datetime.now() - datetime.datetime.fromtimestamp(0)\n                    ).total_seconds()\n                ),\n                tagged_data[\"rain\"],\n                tagged_data[\"temp_in\"],\n                tagged_data[\"temp_out\"],\n                tagged_data[\"wind_ave\"],\n                tagged_data[\"wind_dir\"],\n                tagged_data[\"wind_gust\"],\n            ),\n        )\n        _default_logger.info(\"Wheather station: I added data in the db!\")\n        cur_.close()\n        con_.commit()\n        con_.close()\n\n    def generate(self, number_of_entries: int) -> None:\n        \"\"\"Generate weather data.\"\"\"\n        # some arbitrary max number to prevent arbitrarily large entries\n        enforce(number_of_entries <= 1000000, \"number_of_entries is too high!\")\n\n        for _ in range(number_of_entries):  # nosec\n            dict_of_data = {\n                \"abs_pressure\": random.randrange(1022, 1025, 1),\n                \"delay\": random.randint(2, 7),\n                \"hum_in\": random.randrange(33, 40, 1),\n                \"hum_out\": random.randrange(33, 80, 1),\n                \"idx\": datetime.datetime.now(),\n                \"rain\": random.randrange(70, 74, 1),\n                \"temp_in\": random.randrange(18, 28, 1),\n                \"temp_out\": random.randrange(2, 20, 1),\n                \"wind_ave\": random.randrange(0, 10, 1),\n                \"wind_dir\": random.randrange(0, 14, 1),\n                \"wind_gust\": random.randrange(1, 7, 1),\n            }  # type: Dict[str, Union[int, datetime.datetime]]\n            self.add_data(dict_of_data)\n            time.sleep(5)\n\n\nif __name__ == \"__main__\":  # pragma: nocover\n    a = Forecast()\n    a.generate(59)\n"
  },
  {
    "path": "packages/fetchai/skills/weather_station/handlers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains the handlers of a thermometer AEA.\"\"\"\n\nfrom packages.fetchai.skills.generic_seller.handlers import (\n    GenericFipaHandler,\n    GenericLedgerApiHandler,\n    GenericOefSearchHandler,\n)\n\n\nFipaHandler = GenericFipaHandler\nLedgerApiHandler = GenericLedgerApiHandler\nOefSearchHandler = GenericOefSearchHandler\n"
  },
  {
    "path": "packages/fetchai/skills/weather_station/skill.yaml",
    "content": "name: weather_station\nauthor: fetchai\nversion: 0.27.6\ntype: skill\ndescription: The weather station skill implements the functionality to sell weather\n  data.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: QmVbpEJquwxzBZ2feJuRYBWrWjxQ9jhE1Er4LvmPU24ki9\n  __init__.py: QmPR7BN5S1moGnV6Wf9SjNE1Sm8tGd4aXLEp2G48Ys1LWM\n  behaviours.py: QmaRDMaDVsjVfkAtAHkWLU9Fa88UxyLTczdkm97E9c5TFT\n  db_communication.py: QmYY2eMJ8YHSnkKzvrQYe46rgwZJCjwDayCGKv8C2HroRQ\n  dialogues.py: QmZckK3x2oPgXmnP4XaEBJQoaPp8Gh4ojDHnxzeNsTf4tC\n  dummy_weather_station_data.py: QmTXFBa29Zi62jPJksjfUAvNCpRJVBkTGK33bbekaP4Loh\n  handlers.py: QmZ2gCqdxWntR6nB7CZS5UBtKjFC4Y8g5Ex8afJq2B1b65\n  strategy.py: QmTdN7JpBdbfVJ2sSW5VQuWprfB4kUawF5PqQMC3AVcxds\nfingerprint_ignore_patterns:\n- '*.db'\nconnections: []\ncontracts: []\nprotocols:\n- fetchai/default:1.1.7\n- fetchai/fipa:1.1.7\n- fetchai/ledger_api:1.1.7\n- fetchai/oef_search:1.1.7\nskills:\n- fetchai/generic_seller:0.28.6\nbehaviours:\n  service_registration:\n    args:\n      services_interval: 20\n    class_name: ServiceRegistrationBehaviour\nhandlers:\n  fipa:\n    args: {}\n    class_name: FipaHandler\n  ledger_api:\n    args: {}\n    class_name: LedgerApiHandler\n  oef_search:\n    args: {}\n    class_name: OefSearchHandler\nmodels:\n  default_dialogues:\n    args: {}\n    class_name: DefaultDialogues\n  fipa_dialogues:\n    args: {}\n    class_name: FipaDialogues\n  ledger_api_dialogues:\n    args: {}\n    class_name: LedgerApiDialogues\n  oef_search_dialogues:\n    args: {}\n    class_name: OefSearchDialogues\n  strategy:\n    args:\n      classification:\n        piece: classification\n        value: seller\n      data_for_sale:\n        pressure: 20\n        temperature: 26\n        wind: 10\n      has_data_source: false\n      is_ledger_tx: true\n      location:\n        latitude: 51.5194\n        longitude: 0.127\n      personality_data:\n        piece: genus\n        value: data\n      service_data:\n        key: seller_service\n        value: weather_data\n      service_id: weather_data\n      unit_price: 10\n    class_name: Strategy\ndependencies: {}\nis_abstract: false\n"
  },
  {
    "path": "packages/fetchai/skills/weather_station/strategy.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the strategy class.\"\"\"\n\nimport json\nimport time\nfrom typing import Any, Dict\n\nfrom packages.fetchai.skills.generic_seller.strategy import GenericStrategy\nfrom packages.fetchai.skills.weather_station.db_communication import DBCommunication\n\n\nDEFAULT_DATE_ONE = \"3/10/2019\"\nDEFAULT_DATE_TWO = \"15/10/2019\"\n\n\nclass Strategy(GenericStrategy):\n    \"\"\"This class defines a strategy for the agent.\"\"\"\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"\n        Initialize the strategy of the agent.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        self._date_one = kwargs.pop(\"date_one\", DEFAULT_DATE_ONE)\n        self._date_two = kwargs.pop(\"date_two\", DEFAULT_DATE_TWO)\n        self.db = DBCommunication()\n        super().__init__(**kwargs)\n\n    def collect_from_data_source(self) -> Dict[str, str]:\n        \"\"\"\n        Build the data payload.\n\n        :return: a tuple of the data and the rows\n        \"\"\"\n        fetched_data = self.db.get_data_for_specific_dates(\n            self._date_one, self._date_two\n        )\n        weather_data = {}  # type: Dict[str, str]\n        row_data = {}  # type: Dict[int, Dict[str, Any]]\n        counter = 0\n        for items in fetched_data:\n            if counter > 10:  # so not too much data is sent\n                break  # pragma: nocover\n            counter += 1\n            dict_of_data = {\n                \"abs_pressure\": items[0],\n                \"delay\": items[1],\n                \"hum_in\": items[2],\n                \"hum_out\": items[3],\n                \"idx\": time.ctime(int(items[4])),\n                \"rain\": items[5],\n                \"temp_in\": items[6],\n                \"temp_out\": items[7],\n                \"wind_ave\": items[8],\n                \"wind_dir\": items[9],\n                \"wind_gust\": items[10],\n            }\n            row_data[counter] = dict_of_data\n        weather_data[\"weather_data\"] = json.dumps(row_data)\n        return weather_data\n"
  },
  {
    "path": "packages/hashes.csv",
    "content": "fetchai/agents/aries_alice,QmSVGggvwbxziatmYxgzhZBuqNp5GSjmZuuvPYshNstCyK\nfetchai/agents/aries_faber,QmUAAu88wkoa3EM7RZrNsJ9h7Pj6p5w1d1nNHzsSVGyWoh\nfetchai/agents/car_data_buyer,QmTqTbUpRv7ktaXPe1yicvvkfzBvd48uyoEodanMJREQW2\nfetchai/agents/car_detector,QmdQEkPuy7KfpFXttSzoRjw9GoX6KJbroopUjQcYAxHevM\nfetchai/agents/coin_price_feed,QmXiv1BkaBaQcvm6JfKYrUpycY8TQZEf14rzMQnVWtjBuq\nfetchai/agents/coin_price_oracle,QmaT13ZATFEDPuw4BPECZ4hrgpBj9L15XcRx2SxUH5wFZd\nfetchai/agents/coin_price_oracle_client,Qmb9WaU3ZGZBHQjHiSf6e6CShSz8JVpaxm42T6EHuzoGRG\nfetchai/agents/confirmation_aea_aw1,QmRbg76Kh7Ew9VD47hb9L8kC217oUJWn68dtTfeeBj2AZv\nfetchai/agents/confirmation_aea_aw2,QmRUvLAKLB1eppazDByupnH8eErLRoFaiBWQQv5KoHBubu\nfetchai/agents/confirmation_aea_aw3,QmaFMsn4fVCpnnHbMcGZk2GtdVugjbnsEwTyTNwQMznJxo\nfetchai/agents/confirmation_aea_aw5,QmfQbjLsvXm4eK8HtfMJBGaAr2dmLN2WfH59H1fBL6B4Yp\nfetchai/agents/erc1155_client,QmX43bRz1n6ZiFTtwGFMvip4GrKYNEikywbdaYKSXqxEnX\nfetchai/agents/erc1155_deployer,QmTnz2dQ8HxsfM9zYTaZzFgJrouCz5hXstZz7GBanNosCC\nfetchai/agents/error_test,QmQH8h8mzs87wdC4pYoeKEiJAyQmifhVBvaPs643qXk9A2\nfetchai/agents/fipa_dummy_buyer,QmTGcmMQA1aSFF1LvmNrVk72qJ8YQu3k7NcE6FCNAvEggd\nfetchai/agents/generic_buyer,QmPVHoQAcqetX3B2UVsqH2K9LWVSarWxgBgfApePDqbTca\nfetchai/agents/generic_seller,QmdB7xfGviAypy5Xbh3vtattyrYGKXSGsrQqywfo9XspXk\nfetchai/agents/gym_aea,QmfZsRWfudLF4JcG75wMvKHX7ncJa6vSmJKwGcoKfSiEos\nfetchai/agents/hello_world,QmRDz4xeFfW4zMCmndaEkWkg8yz5K6tXgnUrfq6mzmnjot\nfetchai/agents/latest_block_feed,QmQ6VPSxHoC7rnhy3b6K3ksTonJ82TC4MoJRn8qi9VGWP8\nfetchai/agents/ml_data_provider,QmdzzZugBvfTfzZ6TNJoQCfL1mLLg9R7KNSTmBTmU1fbiu\nfetchai/agents/ml_model_trainer,QmNqhDoZpwf8oAxbdcRrHXW9JyjAoMBmjjuGT6EuwCVXua\nfetchai/agents/my_first_aea,QmcCvC8HagrMcpKVDzjADy1SsiqYPGGRjafhBHJa1Xr1qR\nfetchai/agents/registration_aea_aw1,QmU3sSdJ9jpcdiU9Davcz6QtoLShPqEcSgk6CXdRXwMuL4\nfetchai/agents/simple_aggregator,QmWh4zCi4Pbuy8w4Li7FYLzHrr7h7tAxrS5NgY3bSwwmPb\nfetchai/agents/simple_buyer_aw2,QmSxMusFh7FAWQ68kEVCqt4KNHT9r27fmhtgvULqVVZ7Cj\nfetchai/agents/simple_buyer_aw5,QmXyEPAk3CBWFMhko48JUFAJJtKTYfErWj2cU6caRD3bEk\nfetchai/agents/simple_seller_aw2,QmNnStVWhTGVhinc5DkT7qXqhLQa48TafmHf5KqNM3mnLv\nfetchai/agents/simple_seller_aw5,QmcQekaHYcXeCJ31cdiv89Pz3KSe5dPsY9QWso6xntDHms\nfetchai/agents/simple_service_registration,QmejN5MTSFDYqgk55w6mibYaBsUEAQGg9Pt3uaMjkT69vR\nfetchai/agents/simple_service_search,QmToaJcurxQHQG1pX9nfR4UgWGxAfu9vC5uruCu4s4nhRV\nfetchai/agents/tac_controller,QmW1SUYBsGAWfgetVChEUweXYenZv6gbPfJcrXsQW36T7C\nfetchai/agents/tac_controller_contract,QmPWkjkgKNx59jtCgqezKQHnRjoBfzRooShkvE6sT1ti8T\nfetchai/agents/tac_participant,QmbCnA38beKrg86kxjaKa5A87ZfQE1rYgbubHQGhWwdQgp\nfetchai/agents/tac_participant_contract,QmT4PkNF2cpJgpR4oUubwvwxPqdF5qJeTQFhjjLePunCa5\nfetchai/agents/thermometer_aea,QmZ48DA8dpc6bt5qygU9K5RVdrNdSy3yji7z5nM3f38EF1\nfetchai/agents/thermometer_client,QmS5drSLH3kNLhFvDfmdEh5MvtwXnfFdNNEvwFArfyq5Q1\nfetchai/agents/weather_client,QmV3jNVcYG8vrrbRK4ZQ7NSr949iJVKh8awPSxXV6Arsn1\nfetchai/agents/weather_station,QmdHEjfCrn6EmkVC2xuLsq4J8xae2ZPtdga3NmWGfiBrqV\nfetchai/connections/gym,QmYoYrLTgA4HBcprxVmWJwGzrmKcyjsBYVKamcStYVGzJr\nfetchai/connections/http_client,QmPXUdzkaZt2CSUXeyrc1gTj7eHfuNKa9XL3gvoohvoGgt\nfetchai/connections/http_server,QmSA3qQVrztMucpZevvvAe1mLFPknNBKEXZSq9kAQJP1he\nfetchai/connections/ledger,QmcEbe77YiRRwCbAh1JduyPsABSUYDnsJSNZ4BicEoiDDN\nfetchai/connections/local,QmQogxCUruQTzCKQxnrquEnmUNsoV9NjdDYqwng37uhgf7\nfetchai/connections/oef,QmfUr3wQyHMnQ5C57NeD3ypL2JPe2BVMM8w1DZ79e63ycK\nfetchai/connections/p2p_libp2p,QmWpakcMeK6DGa7BSUtnXK7cAW1shLpK2UjDsKwjFu9jcS\nfetchai/connections/p2p_libp2p_client,QmU4NArBA92C5GfGUNuXB1zo8kz5DoNuYjM2Zwmu1g6YHp\nfetchai/connections/p2p_libp2p_mailbox,QmTNxWRQSU6KtuYqBog7WKvYwuTswHJ7XunxtAtbiNTpCv\nfetchai/connections/p2p_stub,QmQjwk8myY3JgVuwKLnoMb4e6DGeomaBY5ETFxgn45cZZ4\nfetchai/connections/prometheus,Qmdb1fEagWSxbwPZsVytdzrQ1xFbKXvo5ZVWUZTxfhtBze\nfetchai/connections/scaffold,QmYRgd4gLA3CtevU3Rj72Vafu9V6sjk4xRrHu5JosvB7gP\nfetchai/connections/soef,QmYU9X28XttovDc27mLWZznG1KHNJjgcUxE8rhNfVLkvah\nfetchai/connections/stub,QmYKqNesPLTz1RiTGTXS5qoZTDnWxsMqP12Dfj93TrT1Yp\nfetchai/connections/tcp,QmdaPEEGf2oL6uV1CGqPR1Dm2t4mh9nadqg3tU2waZPr97\nfetchai/connections/webhook,QmfXrJrSjbX6xw2QpkvZPibdGXmtRAY7mcScTYvUJ9ztvP\nfetchai/contracts/erc1155,QmYd8y8nccJwdsbrh3Muq3xJZgjpEEWXATWeydoPhvuQ78\nfetchai/contracts/fet_erc20,QmPddVorxNKahXJJPAaRFo39AsDkE3bJWerQSDY8iY4zy1\nfetchai/contracts/oracle,QmPdNhJTFquUbFigNQFtM3ne2QH24NMVsz1bvuCezg3T1M\nfetchai/contracts/oracle_client,QmdrkLzEdUFThsLwnhQLmH3gyWG1keB6Fawo2VKLdaYiQQ\nfetchai/contracts/scaffold,QmVgRzr6yJ3AV2Y6DFxz5EMtTgDmSkeg2b6Cx3H2WkFBHR\nfetchai/contracts/staking_erc20,Qmf7hfDNUWCBzZij7bWVtNgKGVVodp41oWTDymzpS5oEKj\nfetchai/protocols/acn,QmNQpXzAGSzu3nBW4sNvnUVrjbxn7x6ZWGoP4ttWyXdrW1\nfetchai/protocols/aggregation,QmX3Mrkk2SagPESD6z8ejtUiVP2ZC8j7w4QRfYTGNj8USe\nfetchai/protocols/contract_api,QmUuKXkDbArLq7URiEjgJy2eN23KciXUsR5f6tV1mdRaYZ\nfetchai/protocols/cosm_trade,QmTpGR4Svn5d9UBix3RpQfRLgWXXHBmpdw9zmbWK7pvH3i\nfetchai/protocols/default,QmVTKic2PP7MbaE5Dnfgy3CLZn6WTwcJ3r6sq5dKBkooLL\nfetchai/protocols/fipa,QmZ4deeTdrcp1tP3UbBDxgSR5jEjsyvRqdN7aiNaNjnD3n\nfetchai/protocols/gym,QmWdcJWAFNb4eCCHS2T8bzzpzDFgpMMkamM8JY3bvgTUuz\nfetchai/protocols/http,Qmb5yKV5p7TiNa1X96VMpdA2MZU6exHAEfrJenhUsjUBWX\nfetchai/protocols/ledger_api,QmVc7nC5T9swaBskuAKQkzzixQVQ6g1gnPpopGYa9f79P1\nfetchai/protocols/ml_trade,QmWyjEdkx6Y2H3kctMP7A6oDZsdDZJYFua61K3c4bFZB8K\nfetchai/protocols/oef_search,QmPZj5Wt7dgL8N2rZT9ThiVe4pehR5sDS6q3j5v9gkSpEQ\nfetchai/protocols/prometheus,QmTiCY15XgeurxmPrmv6euXfrc3GdeM1JmbFy9Tz698xvt\nfetchai/protocols/register,QmQN8wjYTeZ6tGW2vM9cCn47QFwDCawcNBcoPR8AYf4Xae\nfetchai/protocols/scaffold,QmakHDyafqNtxVyV47M17zHyhzf7osfcnzsbfmvsorhydL\nfetchai/protocols/signing,QmZzbiFHPjhmj4FATsAPTrrnnaCMQQco7XR8NYCwrGi3yo\nfetchai/protocols/state_update,QmbyYfchCK6QydpsGdxecShLBZfuKNMoPhamW1qXC68PXy\nfetchai/protocols/tac,QmT2iCyx55dpSFPVoVEarkoosn1o2FcRzfiMPFMs3nybhC\nfetchai/skills/advanced_data_request,QmQs2Mj7WTmvxCajV8TQSdA2RPMPKLSCvYgybNzBQve1Si\nfetchai/skills/aries_alice,QmWy7T7twbXd3fsg4rmmxvmaB21pTDdAGp8Eycpbj6JWfj\nfetchai/skills/aries_faber,QmVZo6pMmLc73W4SGBYrRfwpaqBMHjyG9UGLHh3G2r1QBU\nfetchai/skills/carpark_client,Qmc9qTrfUkXTrc1RcP9rhZ2tackvHBHm5bR6c6q3D8A1kb\nfetchai/skills/carpark_detection,QmURfz1pazMoaCjuEtWqaPce5hU2521PwCjyuYwvbdBqUB\nfetchai/skills/confirmation_aw1,QmeYFKJmTfkzVyjb5VamqNjAVMawuqSSx3mqBT1GZVqU8b\nfetchai/skills/confirmation_aw2,QmPvHhtunr3UZibEabpRx2XMNUQaWSxtFSmJ99SgbdRj8q\nfetchai/skills/confirmation_aw3,QmXzUFTYPgJcH2XoFobWxsw3icf7N86gHNSrwcHg3vychV\nfetchai/skills/echo,QmQQBsarJtA7Eo9dr6hVwz7DziYzxv51zdJeUHjquUGgec\nfetchai/skills/erc1155_client,QmVKTQc1TDVHJ5ZRvAWhCZFBx3rteUHLir3yNJJ8EsPCmE\nfetchai/skills/erc1155_deploy,QmV2v5RU6jf55f3zh2bhxWV439fJMjWqWz9zYTXZheSXAY\nfetchai/skills/error,QmZGZZAuwSCJkZ4atmcUNE3d3q5iErKQ5AZNsjWJnBT1N8\nfetchai/skills/error_test_skill,QmV1AH2aEEzKec9mG76wGm1q1BsrZLxwYH7SFtw4ACfeAd\nfetchai/skills/fetch_block,QmNP6YvsPuNTPB7E2N3dbZ65WDdbCkXrG7WpAJJ9qkbTWG\nfetchai/skills/fipa_dummy_buyer,QmRnMgmXLJ7ZHRX5jFvUVyXVrQMoZy1f7pAi6wY8NfBttD\nfetchai/skills/generic_buyer,QmTCCZsrRuS7R1GY6EdJnKvXAfhsxBV6YJT2pyLVsokkyx\nfetchai/skills/generic_seller,QmZ4HkEwPdad5UXEJ7rcgAvVBUZZ3xSdSqnNGmT6FWtemh\nfetchai/skills/gym,QmPK9MD8xDYDRZM9mvXKycxoyoUvFUvWPkp1aBjR7T8tM1\nfetchai/skills/hello_world,QmUxmB8E9HhQy5At1FGjD4RCELbZFxhxaN97NAgDi7Dx7U\nfetchai/skills/http_echo,QmfAXHmFQ6CPTZxnt82LWVEyDKC6PdrYGraogcHyL8X9Uf\nfetchai/skills/ml_data_provider,QmWgTAUEK9nnSDXE49Gunb2QhrbfBnSkaVhXwGjvTxYfCP\nfetchai/skills/ml_train,QmcWjoaTKSKALwye6guQCFYLw2PNrqmaxMzaUMod9SJSJt\nfetchai/skills/registration_aw1,QmP4JAhVEnTaQLFUSEE1DCBPpDHt2Mb4KYNmAeBixMqCGv\nfetchai/skills/scaffold,QmfMLDBLPiBjQmDJHthYm59565NGNKEp9nCNgU4YaMrgSf\nfetchai/skills/simple_aggregation,QmPQQxmV469eJTuqa7ajPG4LGUiNqQERmHLtpn5NcHd1az\nfetchai/skills/simple_buyer,QmUGHbgtw1TceTzYmEh4AMT73Fv7xsEuuE4xykpXdkZCcc\nfetchai/skills/simple_data_request,QmPxN2aDVEUzyjpBCYy4FB8bzDRHV86f4egMgsngPzvHXa\nfetchai/skills/simple_oracle,QmcckbJGCNffeoQuon7GhSjNkJxaSbmAkRCW6yZk7LQUnf\nfetchai/skills/simple_oracle_client,Qmb13j9KcdgRTuvEHyQSvRRs5Z2gMtHSxf8wmUCfLK5AKt\nfetchai/skills/simple_seller,Qmbt3cy9ZZEWZU2m3QwtsutDVsT1wCkXB32hQLQevbTnXo\nfetchai/skills/simple_service_registration,QmaLvqZDZyz5XaRKjkw4PLTkHpuchUwdiRTne5oajSJc9x\nfetchai/skills/simple_service_search,QmbhL9rGxpdzk2Va4PeNYjNvMSheN9iEHkqPPJWYpwcp2n\nfetchai/skills/tac_control,QmcAH9LkQHULdihxe2b3uPXm3AEYUbY3pio6rr22oB4Mb9\nfetchai/skills/tac_control_contract,QmWVkwj4gZgmKHEg6iH3cqTNNNUpxWJJ5jkfoBfkE7gUK7\nfetchai/skills/tac_negotiation,Qmb4GLTCEU4hfkSdmdJ3NusLMHFv1o5J5P19r3Fwv5xxRB\nfetchai/skills/tac_participation,QmaWj9n5cpp1nWo3HCwVtJbU6M9zB4Qut4prBxRhNha6cC\nfetchai/skills/task_test_skill,QmeSJeSZ8d8Do1jL8AbgiLWtnchNShWaJs9ChL9heFT4Po\nfetchai/skills/thermometer,QmaAyLDL9MaiuFZHnmjoVB42zgVsGxJ8G6eHL8VzwjbJfj\nfetchai/skills/thermometer_client,QmScE56BE6eMDELi1ntNBbjSkhvvfPC3YGEsyGoCN23sq8\nfetchai/skills/weather_client,QmcUvp36Berop9VzuC2T8AD5q2ELx27q5Zvy4jPsPn4Hnk\nfetchai/skills/weather_station,QmXYnZ4Dahc9xoEJ6yAWyw8Ba5Zu7fsrhR8iDEJ6pJNStz\n"
  },
  {
    "path": "plugins/aea-cli-ipfs/LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright 2019 Fetch.AI Limited\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "plugins/aea-cli-ipfs/MANIFEST.in",
    "content": "include README.md LICENSE HISTORY.md\n\nrecursive-include aea_cli_ipfs\nrecursive-include tests *\n"
  },
  {
    "path": "plugins/aea-cli-ipfs/README.md",
    "content": "# AEA CLI IPFS Plug-in\n\nIPFS command to publish and download directories.\n\n## Installation and usage\n\nMake sure you have `aea` installed.\n\nThen, install the plug-in:\n\n``` bash\npip install aea-cli-ipfs\n```\n\nNow you should be able to run `aea ipfs`.\n\n``` bash\nUsage: aea ipfs [OPTIONS] COMMAND [ARGS]...\n\n  IPFS Commands\n\nOptions:\n  --help  Show this message and exit.\n\nCommands:\n  add       Add directory to ipfs, if not directory specified the current...\n  download  Download directory by it's hash, if not target directory...\n  remove    Remove a directory from ipfs by it's hash.\n\n\n\nUsage: aea ipfs add [OPTIONS] [DIR_PATH]\n\n  Add directory to ipfs, if not directory specified the current one will be\n  added.\n\nOptions:\n  -p, --publish\n  --help         Show this message and exit.\n\n\n\nUsage: aea ipfs remove [OPTIONS] hash_id\n\n  Remove a directory from ipfs by it's hash.\n\nOptions:\n  --help  Show this message and exit.\n\n\n\nUsage: aea ipfs download [OPTIONS] hash_id [TARGET_DIR]\n\n  Download directory by it's hash, if not target directory specified will\n  use current one.\n\nOptions:\n  --help  Show this message and exit.\n\n```\n"
  },
  {
    "path": "plugins/aea-cli-ipfs/aea_cli_ipfs/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"IPFS CLI plug-in for the AEA CLI tool.\"\"\"\n"
  },
  {
    "path": "plugins/aea-cli-ipfs/aea_cli_ipfs/core.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Core components for `ipfs cli command`.\"\"\"\nimport os\nimport time\nfrom contextlib import suppress\nfrom typing import Any, Optional\n\nimport click\nfrom aea_cli_ipfs.ipfs_utils import (\n    DownloadError,\n    IPFSTool,\n    NodeError,\n    PublishError,\n    RemoveError,\n)\n\n\n@click.group()\n@click.pass_context\ndef ipfs(click_context: click.Context) -> None:\n    \"\"\"IPFS Commands\"\"\"\n    ipfs_tool = IPFSTool()\n    click_context.obj = ipfs_tool\n    try:\n        ipfs_tool.chec_ipfs_node_running()\n    except NodeError as e:\n        click.echo(\"Can not connect to the local ipfs node. Starting own one.\")\n        ipfs_tool.daemon.start()\n        for _ in range(10):\n            with suppress(NodeError):  # pragma: nocover\n                ipfs_tool.chec_ipfs_node_running()\n                click.echo(\"ipfs node started.\")\n                break\n            time.sleep(1)\n        else:\n            raise click.ClickException(\n                \"Failed to connect or start ipfs node! Please check ipfs is installed or launched!\"\n            ) from e\n\n\n@ipfs.result_callback()\n@click.pass_context\ndef process_result(click_context: click.Context, *_: Any) -> None:\n    \"\"\"Tear down command group.\"\"\"\n    ipfs_tool = click_context.obj\n    if ipfs_tool.daemon.is_started():  # pragma: nocover\n        click.echo(\"Stopping ipfs node launched to execute the command.\")\n        ipfs_tool.daemon.stop()\n        click.echo(\"Daemon stopped.\")\n\n\n@ipfs.command()\n@click.argument(\n    \"dir_path\",\n    type=click.Path(\n        exists=True, dir_okay=True, file_okay=False, resolve_path=True, readable=True\n    ),\n    required=False,\n)\n@click.option(\"-p\", \"--publish\", is_flag=True)\n@click.option(\"--no-pin\", is_flag=True)\n@click.pass_context\ndef add(\n    click_context: click.Context,\n    dir_path: Optional[str],\n    publish: bool = False,\n    no_pin: bool = False,\n) -> None:\n    \"\"\"Add directory to ipfs, if not directory specified the current one will be added.\"\"\"\n    dir_path = dir_path or os.getcwd()\n    ipfs_tool = click_context.obj\n    click.echo(f\"Starting processing: {dir_path}\")\n    name, hash_, _ = ipfs_tool.add(dir_path, pin=(not no_pin))\n    click.echo(f\"Added: `{name}`, hash is {hash_}\")\n    if publish:\n        click.echo(\"Publishing...\")\n        try:\n            response = ipfs_tool.publish(hash_)\n            click.echo(f\"Published to {response['Name']}\")\n        except PublishError as e:\n            raise click.ClickException(f\"Publish failed: {str(e)}\") from e\n\n\n@ipfs.command()\n@click.argument(\n    \"hash_\",\n    metavar=\"hash\",\n    type=str,\n    required=True,\n)\n@click.pass_context\ndef remove(click_context: click.Context, hash_: str) -> None:\n    \"\"\"Remove a directory from ipfs by it's hash.\"\"\"\n    ipfs_tool = click_context.obj\n    try:\n        ipfs_tool.remove(hash_)\n        click.echo(f\"{hash_} was removed successfully\")\n    except RemoveError as e:\n        raise click.ClickException(f\"Remove error: {str(e)}\") from e\n\n\n@ipfs.command()\n@click.argument(\n    \"hash_\",\n    metavar=\"hash\",\n    type=str,\n    required=True,\n)\n@click.argument(\n    \"target_dir\",\n    type=click.Path(dir_okay=True, file_okay=False, resolve_path=True),\n    required=False,\n)\n@click.pass_context\ndef download(\n    click_context: click.Context, hash_: str, target_dir: Optional[str]\n) -> None:\n    \"\"\"Download directory by it's hash, if not target directory specified will use current one.\"\"\"\n    target_dir = target_dir or os.getcwd()\n    ipfs_tool = click_context.obj\n    click.echo(f\"Download {hash_} to {target_dir}\")\n    try:\n        ipfs_tool.download(hash_, target_dir)\n        click.echo(\"Download complete!\")\n    except DownloadError as e:  # pragma: nocover\n        raise click.ClickException(str(e)) from e\n"
  },
  {
    "path": "plugins/aea-cli-ipfs/aea_cli_ipfs/ipfs_utils.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Ipfs utils for `ipfs cli command`.\"\"\"\nimport os\nimport shutil\nimport signal\nimport subprocess  # nosec\nfrom pathlib import Path\nfrom typing import Dict, List, Optional, Tuple\n\nimport ipfshttpclient  # type: ignore\n\n\nclass IPFSDaemon:\n    \"\"\"\n    Set up the IPFS daemon.\n\n    :raises Exception: if IPFS is not installed.\n    \"\"\"\n\n    def __init__(self) -> None:\n        \"\"\"Initialise IPFS daemon.\"\"\"\n        # check we have ipfs\n        self.process = None  # type: Optional[subprocess.Popen]\n\n    def is_started(self) -> bool:\n        \"\"\"Check daemon was started.\"\"\"\n        return bool(self.process)\n\n    def start(self) -> None:\n        \"\"\"Run the ipfs daemon.\"\"\"\n        self.process = subprocess.Popen(  # nosec # pylint: disable=consider-using-with\n            [\"ipfs\", \"daemon\"],\n            stdout=subprocess.PIPE,\n            env=os.environ.copy(),\n        )\n\n    def stop(self) -> None:  # pragma: nocover\n        \"\"\"Terminate the ipfs daemon.\"\"\"\n        if self.process is None:\n            return\n        self.process.send_signal(signal.SIGTERM)\n        self.process.wait(timeout=30)\n        poll = self.process.poll()\n        if poll is None:\n            self.process.terminate()\n            self.process.wait(2)\n\n\nclass BaseIPFSToolException(Exception):\n    \"\"\"Base ipfs tool exception.\"\"\"\n\n\nclass RemoveError(BaseIPFSToolException):\n    \"\"\"Exception on remove.\"\"\"\n\n\nclass PublishError(BaseIPFSToolException):\n    \"\"\"Exception on publish.\"\"\"\n\n\nclass NodeError(BaseIPFSToolException):\n    \"\"\"Exception for node connection check.\"\"\"\n\n\nclass DownloadError(BaseIPFSToolException):\n    \"\"\"Exception on download failed.\"\"\"\n\n\nclass IPFSTool:\n    \"\"\"IPFS tool to add, publish, remove, download directories.\"\"\"\n\n    def __init__(self, client_options: Optional[Dict] = None):\n        \"\"\"\n        Init tool.\n\n        :param client_options: dict, options for ipfshttpclient instance.\n        \"\"\"\n        self.client = ipfshttpclient.Client(**(client_options or {}))\n        self.daemon = IPFSDaemon()\n\n    def add(self, dir_path: str, pin: bool = True) -> Tuple[str, str, List]:\n        \"\"\"\n        Add directory to ipfs.\n\n        It wraps into directory.\n\n        :param dir_path: str, path to dir to publish\n        :param pin: bool, pin object or not\n\n        :return: dir name published, hash, list of items processed\n        \"\"\"\n        response = self.client.add(\n            dir_path, pin=pin, recursive=True, wrap_with_directory=True\n        )\n        return response[-2][\"Name\"], response[-1][\"Hash\"], response[:-1]\n\n    def remove(self, hash_id: str) -> Dict:\n        \"\"\"\n        Remove dir added by it's hash.\n\n        :param hash_id: str. hash of dir to remove\n\n        :return: dict with unlinked items.\n        \"\"\"\n        try:\n            return self.client.pin.rm(hash_id, recursive=True)\n        except ipfshttpclient.exceptions.ErrorResponse as e:\n            raise RemoveError(f\"Error on {hash_id} remove: {str(e)}\") from e\n\n    def download(self, hash_id: str, target_dir: str, fix_path: bool = True) -> None:\n        \"\"\"\n        Download dir by it's hash.\n\n        :param hash_id: str. hash of file to download\n        :param target_dir: str. directory to place downloaded\n        :param fix_path: bool. default True. on download don't wrap result in to hash_id directory.\n        \"\"\"\n        if not os.path.exists(target_dir):  # pragma: nocover\n            os.makedirs(target_dir, exist_ok=True)\n\n        if os.path.exists(os.path.join(target_dir, hash_id)):  # pragma: nocover\n            raise DownloadError(f\"{hash_id} was already downloaded to {target_dir}\")\n\n        self.client.get(hash_id, target_dir)\n\n        downloaded_path = str(Path(target_dir) / hash_id)\n\n        if fix_path:\n            # self.client.get creates result with hash name\n            # and content, but we want content in the target dir\n            try:\n                for each_file in Path(downloaded_path).iterdir():  # grabs all files\n                    shutil.move(str(each_file), target_dir)\n            except shutil.Error as e:  # pragma: nocover\n                raise DownloadError(f\"error on move files {str(e)}\") from e\n\n        os.rmdir(downloaded_path)\n\n    def publish(self, hash_id: str) -> Dict:\n        \"\"\"\n        Publish directory by it's hash id.\n\n        :param hash_id: hash of the directory to publish.\n\n        :return: dict of names it was publish for.\n        \"\"\"\n        try:\n            return self.client.name.publish(hash_id)\n        except ipfshttpclient.exceptions.TimeoutError as e:  # pragma: nocover\n            raise PublishError(\n                \"can not publish within timeout, check internet connection!\"\n            ) from e\n\n    def chec_ipfs_node_running(self) -> None:\n        \"\"\"Check ipfs node running.\"\"\"\n        try:\n            self.client.id()\n        except ipfshttpclient.exceptions.CommunicationError as e:\n            raise NodeError(f\"Can not connect to node. Is node running?:\\n{e}\") from e\n"
  },
  {
    "path": "plugins/aea-cli-ipfs/pyproject.toml",
    "content": "[build-system]\nrequires = [\"setuptools\", \"wheel\"]\nbuild_backend = \"setuptools.build_meta\"\n"
  },
  {
    "path": "plugins/aea-cli-ipfs/setup.py",
    "content": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\n\"\"\"Setup script for the plug-in.\"\"\"\n\n\nfrom setuptools import setup  # type: ignore\n\n\nsetup(\n    name=\"aea-cli-ipfs\",\n    version=\"1.0.4\",\n    author=\"Fetch.AI Limited\",\n    license=\"Apache-2.0\",\n    description=\"CLI extension for AEA framework wrapping IPFS functionality.\",\n    packages=[\"aea_cli_ipfs\"],\n    entry_points={\"aea.cli\": [\"ipfs_cli_command = aea_cli_ipfs.core:ipfs\"]},\n    install_requires=[\"aea>=1.0.0, <2.0.0\", \"ipfshttpclient==0.8.0a2\"],\n    classifiers=[\n        \"Environment :: Console\",\n        \"Environment :: Web Environment\",\n        \"Development Status :: 5 - Production/Stable\",\n        \"Intended Audience :: Developers\",\n        \"License :: OSI Approved :: Apache Software License\",\n        \"Natural Language :: English\",\n        \"Operating System :: MacOS\",\n        \"Operating System :: Microsoft\",\n        \"Operating System :: Unix\",\n        \"Programming Language :: Python :: 3.6\",\n        \"Programming Language :: Python :: 3.7\",\n        \"Programming Language :: Python :: 3.8\",\n        \"Programming Language :: Python :: 3.9\",\n        \"Topic :: Communications\",\n        \"Topic :: Internet\",\n        \"Topic :: Software Development\",\n    ],\n)\n"
  },
  {
    "path": "plugins/aea-cli-ipfs/tests/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Tests for aea client ipfs plugin.\"\"\"\n"
  },
  {
    "path": "plugins/aea-cli-ipfs/tests/test_aea_cli_ipfs.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Tests for aea cli ipfs plugin.\"\"\"\nimport os\nimport sys\nfrom unittest.mock import patch\n\nimport click\nimport ipfshttpclient  # type: ignore\nimport pytest\nfrom click.testing import CliRunner\n\nfrom aea.cli.core import cli\n\n\nsys.path.insert(0, os.path.join(os.path.dirname(__file__), \"..\"))\n\nfrom aea_cli_ipfs.core import (  # noqa # type: ignore  # pylint: disable=wrong-import-position\n    PublishError,\n    ipfs,\n)\n\n\ncli.add_command(ipfs)\n\n\ndef test_ipfs():\n    \"\"\"Test aea ipfs command itself.\"\"\"\n    runner = CliRunner()\n    with patch(\"ipfshttpclient.Client.id\"):\n        r = runner.invoke(cli, [\"ipfs\"], catch_exceptions=False, standalone_mode=False)\n    assert r.exit_code == 0\n\n\ndef test_ipfs_add():\n    \"\"\"Test aea ipfs add.\"\"\"\n    runner = CliRunner()\n    with patch(\"ipfshttpclient.Client.name.publish\") as ipfs_publish, patch(\n        \"ipfshttpclient.Client.id\"\n    ) as ipfs_id, patch(\n        \"ipfshttpclient.Client.add\", return_value=[{\"Name\": \"name\", \"Hash\": \"hash\"}] * 2\n    ) as ipfs_add:\n        r = runner.invoke(cli, [\"ipfs\", \"add\", \"-p\"], catch_exceptions=False)\n    assert r.exit_code == 0\n    ipfs_id.assert_called()\n    ipfs_add.assert_called()\n    ipfs_publish.assert_called()\n\n    with patch(\n        \"ipfshttpclient.Client.name.publish\", side_effect=PublishError(\"oops\")\n    ) as ipfs_publish, patch(\"ipfshttpclient.Client.id\") as ipfs_id, patch(\n        \"ipfshttpclient.Client.add\", return_value=[{\"Name\": \"name\", \"Hash\": \"hash\"}] * 2\n    ) as ipfs_add:\n        with pytest.raises(click.ClickException, match=\"Publish failed.*oops\"):\n            runner.invoke(\n                cli,\n                [\"ipfs\", \"add\", \"-p\"],\n                catch_exceptions=False,\n                standalone_mode=False,\n            )\n\n\ndef test_node_not_alive_can_not_be_started():\n    \"\"\"Test error on node connection failed\"\"\"\n    runner = CliRunner()\n    with patch(\n        \"ipfshttpclient.Client.id\",\n        side_effect=ipfshttpclient.exceptions.CommunicationError(\n            original=Exception(\"oops\")\n        ),\n    ), patch(\"time.sleep\"), patch(\"subprocess.Popen\"):\n\n        with pytest.raises(\n            click.ClickException,\n            match=\"Failed to connect or start ipfs node! Please check ipfs is installed or launched!\",\n        ):\n            runner.invoke(\n                cli,\n                [\"ipfs\", \"add\", \"-p\"],\n                catch_exceptions=False,\n                standalone_mode=False,\n            )\n\n\n@patch(\"ipfshttpclient.Client.id\")\ndef test_ipfs_download(*_):\n    \"\"\"Test aea ipfs download.\"\"\"\n    runner = CliRunner()\n    with patch(\"ipfshttpclient.Client.get\") as ipfs_get, patch(\"os.rmdir\"), patch(\n        \"pathlib.Path.iterdir\", return_value=[1]\n    ), patch(\"shutil.move\"):\n        r = runner.invoke(\n            cli, [\"ipfs\", \"download\", \"some_hash\"], catch_exceptions=False\n        )\n    assert r.exit_code == 0\n    ipfs_get.assert_called()\n\n\n@patch(\"ipfshttpclient.Client.id\")\ndef test_ipfs_remove(*_):\n    \"\"\"Test aea ipfs remove.\"\"\"\n    runner = CliRunner()\n    with patch(\"ipfshttpclient.Client.pin.rm\") as ipfs_rm:\n        r = runner.invoke(cli, [\"ipfs\", \"remove\", \"some_hash\"], catch_exceptions=False)\n    assert r.exit_code == 0\n    ipfs_rm.assert_called()\n\n    with patch(\n        \"ipfshttpclient.Client.pin.rm\",\n        side_effect=ipfshttpclient.exceptions.ErrorResponse(\n            \"oops\", original=Exception()\n        ),\n    ) as ipfs_rm:\n        with pytest.raises(click.ClickException, match=\"Remove error:.*oops\"):\n            runner.invoke(\n                cli,\n                [\"ipfs\", \"remove\", \"some_hash\"],\n                catch_exceptions=False,\n                standalone_mode=False,\n            )\n\n\nif __name__ == \"__main__\":\n    pytest.main([__file__])\n"
  },
  {
    "path": "plugins/aea-ledger-cosmos/LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright 2019 Fetch.AI Limited\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "plugins/aea-ledger-cosmos/MANIFEST.in",
    "content": "include README.md LICENSE HISTORY.md\n\nrecursive-include aea_ledger_cosmos\nrecursive-include tests *\n"
  },
  {
    "path": "plugins/aea-ledger-cosmos/README.md",
    "content": "# Cosmos crypto plug-in\n\nCosmos crypto plug-in for the AEA framework.\n\n## Install\n\n``` bash\npython setup.py install\n```\n\n## Run tests\n\n``` bash\npython setup.py test\n```\n"
  },
  {
    "path": "plugins/aea-ledger-cosmos/aea_ledger_cosmos/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Python package wrapping the public and private key cryptography and ledger api.\"\"\"\n\nfrom .cosmos import *  # noqa isort:skip\nfrom .cosmos import _default_logger, _BYTECODE, _COSMOS, _CosmosApi  # noqa isort:skip\n"
  },
  {
    "path": "plugins/aea-ledger-cosmos/aea_ledger_cosmos/cosmos.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Cosmos module wrapping the public and private key cryptography and ledger api.\"\"\"\nimport base64\nimport gzip\nimport hashlib\nimport json\nimport logging\nimport time\nfrom collections import namedtuple\nfrom itertools import chain\nfrom json.decoder import JSONDecodeError\nfrom pathlib import Path\nfrom typing import Any, Dict, List, Optional, Tuple, cast\n\nfrom Crypto.Cipher import AES  # nosec\nfrom Crypto.Protocol.KDF import scrypt  # nosec\nfrom Crypto.Random import get_random_bytes  # nosec\nfrom bech32 import (  # pylint: disable=wrong-import-order\n    bech32_decode,\n    bech32_encode,\n    convertbits,\n)\nfrom cosmpy.auth.rest_client import AuthRestClient\nfrom cosmpy.bank.rest_client import BankRestClient, QueryBalanceRequest\nfrom cosmpy.common.rest_client import RestClient\nfrom cosmpy.cosmwasm.rest_client import CosmWasmRestClient\nfrom cosmpy.crypto.hashfuncs import ripemd160\nfrom cosmpy.protos.cosmos.auth.v1beta1.auth_pb2 import BaseAccount\nfrom cosmpy.protos.cosmos.auth.v1beta1.query_pb2 import QueryAccountRequest\nfrom cosmpy.protos.cosmos.bank.v1beta1.tx_pb2 import MsgSend\nfrom cosmpy.protos.cosmos.base.v1beta1.coin_pb2 import Coin\nfrom cosmpy.protos.cosmos.crypto.secp256k1.keys_pb2 import PubKey as ProtoPubKey\nfrom cosmpy.protos.cosmos.tx.signing.v1beta1.signing_pb2 import SignMode\nfrom cosmpy.protos.cosmos.tx.v1beta1.service_pb2 import (\n    BroadcastMode,\n    BroadcastTxRequest,\n    GetTxRequest,\n)\nfrom cosmpy.protos.cosmos.tx.v1beta1.tx_pb2 import (\n    AuthInfo,\n    Fee,\n    ModeInfo,\n    SignDoc,\n    SignerInfo,\n    Tx,\n    TxBody,\n)\nfrom cosmpy.protos.cosmwasm.wasm.v1.query_pb2 import QuerySmartContractStateRequest\nfrom cosmpy.protos.cosmwasm.wasm.v1.tx_pb2 import (\n    MsgExecuteContract,\n    MsgInstantiateContract,\n    MsgStoreCode,\n)\nfrom cosmpy.tx.rest_client import TxRestClient\nfrom ecdsa import (  # type: ignore # pylint: disable=wrong-import-order\n    SECP256k1,\n    SigningKey,\n    VerifyingKey,\n)\nfrom ecdsa.util import (  # type: ignore # pylint: disable=wrong-import-order\n    sigencode_string_canonize,\n)\nfrom google.protobuf.any_pb2 import Any as ProtoAny\nfrom google.protobuf.json_format import MessageToDict, ParseDict\n\nfrom aea.common import Address, JSONLike\nfrom aea.crypto.base import Crypto, FaucetApi, Helper, LedgerApi\nfrom aea.crypto.helpers import KeyIsIncorrect, hex_to_bytes_for_key\nfrom aea.exceptions import AEAEnforceError\nfrom aea.helpers import http_requests as requests\nfrom aea.helpers.base import try_decorator\n\n\n_default_logger = logging.getLogger(__name__)\n\n_COSMOS = \"cosmos\"\nTESTNET_NAME = \"testnet\"\nDEFAULT_FAUCET_URL = \"INVALID_URL\"\nDEFAULT_ADDRESS = \"https://cosmos.bigdipper.live\"\nDEFAULT_CURRENCY_DENOM = \"uatom\"\nDEFAULT_CHAIN_ID = \"cosmoshub-3\"\nDEFAULT_GAS_AMOUNT = 1550000\n# Txs will fail if gas_limit is higher than MAXIMUM_GAS_AMOUNT\nMAXIMUM_GAS_AMOUNT = 2000000\n_BYTECODE = \"wasm_byte_code\"\n\n\nclass DataEncrypt:\n    \"\"\"Class to encrypt/decrypt data strings with password provided.\"\"\"\n\n    @classmethod\n    def _aes_encrypt(\n        cls, password: str, data: bytes\n    ) -> Tuple[bytes, bytes, bytes, bytes]:\n        \"\"\"\n        Encryption schema for private keys\n\n        :param password: plaintext password to use for encryption\n        :param data: plaintext data to encrypt\n\n        :return: encrypted data, nonce, tag, salt\n        \"\"\"\n        key, salt = cls._password_to_key_and_salt(password)\n        cipher = AES.new(key, AES.MODE_EAX)\n        ciphertext, tag = cipher.encrypt_and_digest(data)  # type:ignore\n\n        return ciphertext, cipher.nonce, tag, salt  # type:ignore\n\n    @staticmethod\n    def _password_to_key_and_salt(\n        password: str, salt: Optional[bytes] = None\n    ) -> Tuple[bytes, bytes]:\n        salt = salt or get_random_bytes(16)\n        key = scrypt(password, salt, 16, N=2**14, r=8, p=1)  # type: ignore\n        return key, salt  # type: ignore\n\n    @classmethod\n    def _aes_decrypt(\n        cls, password: str, encrypted_data: bytes, nonce: bytes, tag: bytes, salt: bytes\n    ) -> bytes:\n        \"\"\"\n        Decryption schema for private keys.\n\n        :param password: plaintext password used for encryption\n        :param encrypted_data: data to decrypt\n        :param nonce:  bytes\n        :param tag:  bytes\n        :param salt: bytes\n        :return: decrypted data as plaintext\n        \"\"\"\n        # Hash password\n        key, _ = cls._password_to_key_and_salt(password, salt)\n        cipher = AES.new(key, AES.MODE_EAX, nonce)\n        try:\n            decrypted_data = cipher.decrypt_and_verify(  # type:ignore\n                encrypted_data, tag\n            )\n        except ValueError as e:\n            if e.args[0] == \"MAC check failed\":\n                raise ValueError(\"Decrypt error! Bad password?\") from e\n            raise  # pragma: nocover\n        return decrypted_data\n\n    @classmethod\n    def encrypt(cls, data: bytes, password: str) -> bytes:\n        \"\"\"Encrypt data with password.\"\"\"\n        if not isinstance(data, bytes):  # pragma: nocover\n            raise ValueError(f\"data has to be bytes! not {type(data)}\")\n\n        encrypted_data, nonce, tag, salt = cls._aes_encrypt(password, data)\n\n        json_data = {\n            \"encrypted_data\": cls.bytes_encode(encrypted_data),\n            \"nonce\": cls.bytes_encode(nonce),\n            \"tag\": cls.bytes_encode(tag),\n            \"salt\": cls.bytes_encode(salt),\n        }\n        return json.dumps(json_data).encode()\n\n    @staticmethod\n    def bytes_encode(data: bytes) -> str:\n        \"\"\"Encode bytes to ascii friendly string.\"\"\"\n        return base64.b64encode(data).decode()\n\n    @staticmethod\n    def bytes_decode(data: str) -> bytes:\n        \"\"\"Decode ascii friendly string to bytes.\"\"\"\n        return base64.b64decode(data)\n\n    @classmethod\n    def decrypt(cls, encrypted_data: bytes, password: str) -> bytes:\n        \"\"\"Decrypt data with password provided.\"\"\"\n        if not isinstance(encrypted_data, bytes):  # pragma: nocover\n            raise ValueError(\n                f\"encrypted_data has to be str! not {type(encrypted_data)}\"\n            )\n\n        try:\n            json_data = json.loads(encrypted_data)\n            decrypted_data = cls._aes_decrypt(\n                password,\n                encrypted_data=cls.bytes_decode(json_data[\"encrypted_data\"]),\n                nonce=cls.bytes_decode(json_data[\"nonce\"]),\n                tag=cls.bytes_decode(json_data[\"tag\"]),\n                salt=cls.bytes_decode(json_data[\"salt\"]),\n            )\n            return decrypted_data\n        except (KeyError, JSONDecodeError) as e:\n            raise ValueError(f\"Bad encrypted key format!: {str(e)}\") from e\n\n\nclass CosmosHelper(Helper):\n    \"\"\"Helper class usable as Mixin for CosmosApi or as standalone class.\"\"\"\n\n    address_prefix = _COSMOS\n\n    @staticmethod\n    def is_transaction_settled(tx_receipt: JSONLike) -> bool:\n        \"\"\"\n        Check whether a transaction is settled or not.\n\n        :param tx_receipt: the receipt of the transaction.\n        :return: True if the transaction has been settled, False o/w.\n        \"\"\"\n        is_successful = False\n        if tx_receipt is not None:\n            code = tx_receipt.get(\"code\", None)\n            is_successful = code is None\n            if not is_successful:\n                _default_logger.warning(  # pragma: nocover\n                    f\"Transaction {tx_receipt.get('txhash')} not settled. Raw log: {tx_receipt.get('rawLog')}\"\n                )\n        return is_successful\n\n    @classmethod\n    def get_code_id(cls, tx_receipt: JSONLike) -> Optional[int]:\n        \"\"\"\n        Retrieve the `code_id` from a transaction receipt.\n\n        :param tx_receipt: the receipt of the transaction.\n        :return: the code id, if present\n        \"\"\"\n        code_id: Optional[int] = None\n        try:\n            attributes = cls.get_event_attributes(tx_receipt)\n\n            code_id = int(attributes[\"code_id\"])\n        except (KeyError, IndexError):  # pragma: nocover\n            code_id = None\n        return code_id\n\n    @staticmethod\n    def get_event_attributes(tx_receipt: JSONLike) -> Dict:\n        \"\"\"\n        Retrieve events attributes from tx receipt.\n\n        :param tx_receipt: the receipt of the transaction.\n        :return: dict\n        \"\"\"\n        return {\n            i[\"key\"]: i[\"value\"]\n            for i in chain(*[i[\"attributes\"] for i in tx_receipt[\"logs\"][0][\"events\"]])  # type: ignore\n        }\n\n    @classmethod\n    def get_contract_address(cls, tx_receipt: JSONLike) -> Optional[str]:\n        \"\"\"\n        Retrieve the `contract_address` from a transaction receipt.\n\n        :param tx_receipt: the receipt of the transaction.\n        :return: the contract address, if present\n        \"\"\"\n        contract_address: Optional[str] = None\n        try:\n            attributes = cls.get_event_attributes(tx_receipt)\n            contract_address = attributes[\"_contract_address\"]\n        except (KeyError, IndexError):  # pragma: nocover\n            contract_address = None\n        return contract_address\n\n    @staticmethod\n    def is_transaction_valid(\n        tx: JSONLike,\n        seller: Address,\n        client: Address,\n        tx_nonce: str,\n        amount: int,\n    ) -> bool:\n        \"\"\"\n        Check whether a transaction is valid or not.\n\n        :param tx: the transaction.\n        :param seller: the address of the seller.\n        :param client: the address of the client.\n        :param tx_nonce: the transaction nonce.\n        :param amount: the amount we expect to get from the transaction.\n        :return: True if the random_message is equals to tx['input']\n        \"\"\"\n        if tx is None:\n            return False  # pragma: no cover\n\n        try:\n            _tx = cast(dict, tx.get(\"tx\", {})).get(\"body\", {}).get(\"messages\", [])[0]\n            recovered_amount = int(_tx.get(\"amount\")[0].get(\"amount\"))\n            sender = _tx.get(\"fromAddress\")\n            recipient = _tx.get(\"toAddress\")\n            is_valid = (\n                recovered_amount == amount and sender == client and recipient == seller\n            )\n        except (KeyError, IndexError):  # pragma: no cover\n            is_valid = False\n        return is_valid\n\n    @staticmethod\n    def generate_tx_nonce(seller: Address, client: Address) -> str:\n        \"\"\"\n        Generate a unique hash to distinguish transactions with the same terms.\n\n        :param seller: the address of the seller.\n        :param client: the address of the client.\n        :return: return the hash in hex.\n        \"\"\"\n        time_stamp = int(time.time())\n        aggregate_hash = hashlib.sha256(\n            b\"\".join([seller.encode(), client.encode(), time_stamp.to_bytes(32, \"big\")])\n        )\n        return aggregate_hash.hexdigest()\n\n    @classmethod\n    def get_address_from_public_key(cls, public_key: str) -> str:\n        \"\"\"\n        Get the address from the public key.\n\n        :param public_key: the public key\n        :return: str\n        \"\"\"\n        public_key_bytes = bytes.fromhex(public_key)\n        s = hashlib.new(\"sha256\", public_key_bytes).digest()\n        r = ripemd160(s)\n        five_bit_r = convertbits(r, 8, 5)\n        if five_bit_r is None:  # pragma: nocover\n            raise AEAEnforceError(\"Unsuccessful bech32.convertbits call\")\n        address = bech32_encode(cls.address_prefix, five_bit_r)\n        return address\n\n    @classmethod\n    def recover_message(\n        cls, message: bytes, signature: str, is_deprecated_mode: bool = False\n    ) -> Tuple[Address, ...]:\n        \"\"\"\n        Recover the addresses from the hash.\n\n        :param message: the message we expect\n        :param signature: the transaction signature\n        :param is_deprecated_mode: if the deprecated signing was used\n        :return: the recovered addresses\n        \"\"\"\n        public_keys = cls.recover_public_keys_from_message(message, signature)\n        addresses = [\n            cls.get_address_from_public_key(public_key) for public_key in public_keys\n        ]\n        return tuple(addresses)\n\n    @classmethod\n    def recover_public_keys_from_message(\n        cls, message: bytes, signature: str, is_deprecated_mode: bool = False\n    ) -> Tuple[str, ...]:\n        \"\"\"\n        Get the public key used to produce the `signature` of the `message`\n\n        :param message: raw bytes used to produce signature\n        :param signature: signature of the message\n        :param is_deprecated_mode: if the deprecated signing was used\n        :return: the recovered public keys\n        \"\"\"\n        signature_b64 = base64.b64decode(signature)\n        verifying_keys = VerifyingKey.from_public_key_recovery(\n            signature_b64,\n            message,\n            SECP256k1,\n            hashfunc=hashlib.sha256,\n        )\n        public_keys = [\n            verifying_key.to_string(\"compressed\").hex()\n            for verifying_key in verifying_keys\n        ]\n        return tuple(public_keys)\n\n    @staticmethod\n    def get_hash(message: bytes) -> str:\n        \"\"\"\n        Get the hash of a message.\n\n        :param message: the message to be hashed.\n        :return: the hash of the message.\n        \"\"\"\n        digest = hashlib.sha256(message).hexdigest()\n        return digest\n\n    @classmethod\n    def is_valid_address(cls, address: Address) -> bool:\n        \"\"\"\n        Check if the address is valid.\n\n        :param address: the address to validate\n        :return: whether address is valid or not\n        \"\"\"\n        result = bech32_decode(address)\n        return result != (None, None) and result[0] == cls.address_prefix\n\n    @classmethod\n    def load_contract_interface(cls, file_path: Path) -> Dict[str, str]:\n        \"\"\"\n        Load contract interface.\n\n        :param file_path: the file path to the interface\n        :return: the interface\n        \"\"\"\n        with open(file_path, \"rb\") as interface_file_cosmos:\n            contract_interface = {\n                _BYTECODE: str(\n                    base64.b64encode(\n                        gzip.compress(interface_file_cosmos.read(), 6)\n                    ).decode()\n                )\n            }\n        return contract_interface\n\n\nclass CosmosCrypto(Crypto[SigningKey]):\n    \"\"\"Class wrapping the Account Generation from Ethereum ledger.\"\"\"\n\n    identifier = _COSMOS\n    helper = CosmosHelper\n\n    def __init__(\n        self, private_key_path: Optional[str] = None, password: Optional[str] = None\n    ) -> None:\n        \"\"\"\n        Instantiate an ethereum crypto object.\n\n        :param private_key_path: the private key path of the agent\n        :param password: the password to encrypt/decrypt the private key.\n        \"\"\"\n        super().__init__(private_key_path=private_key_path, password=password)\n        self._public_key = self.entity.get_verifying_key().to_string(\"compressed\").hex()\n        self._address = self.helper.get_address_from_public_key(self.public_key)\n\n    @property\n    def private_key(self) -> str:\n        \"\"\"\n        Return a private key.\n\n        :return: a private key string\n        \"\"\"\n        return self.entity.to_string().hex()\n\n    @property\n    def public_key(self) -> str:\n        \"\"\"\n        Return a public key in hex format.\n\n        :return: a public key string in hex format\n        \"\"\"\n        return self._public_key\n\n    @property\n    def address(self) -> str:\n        \"\"\"\n        Return the address for the key pair.\n\n        :return: a display_address str\n        \"\"\"\n        return self._address\n\n    @classmethod\n    def load_private_key_from_path(\n        cls, file_name: str, password: Optional[str] = None\n    ) -> SigningKey:\n        \"\"\"\n        Load a private key in hex format from a file.\n\n        :param file_name: the path to the hex file.\n        :param password: the password to encrypt/decrypt the private key.\n        :return: the Entity.\n        \"\"\"\n        private_key = cls.load(file_name, password)\n        try:\n            signing_key = SigningKey.from_string(\n                hex_to_bytes_for_key(private_key), curve=SECP256k1\n            )\n        except KeyIsIncorrect as e:\n            if not password:\n                raise KeyIsIncorrect(\n                    f\"Error on key `{file_name}` load! Try to specify `password`: Error: {repr(e)} \"\n                ) from e\n            raise KeyIsIncorrect(\n                f\"Error on key `{file_name}` load! Wrong password?: Error: {repr(e)} \"\n            ) from e\n        return signing_key\n\n    def sign_message(\n        self,\n        message: bytes,\n        is_deprecated_mode: bool = False,  # pylint: disable=unused-argument\n    ) -> str:\n        \"\"\"\n        Sign a message in bytes string form.\n\n        :param message: the message to be signed\n        :param is_deprecated_mode: if the deprecated signing is used\n        :return: signature of the message in string form\n        \"\"\"\n        signature_compact = self.entity.sign_deterministic(\n            message,\n            hashfunc=hashlib.sha256,\n            sigencode=sigencode_string_canonize,\n        )\n        signature_base64_str = base64.b64encode(signature_compact).decode(\"utf-8\")\n        return signature_base64_str\n\n    def sign_transaction(self, transaction: JSONLike) -> JSONLike:\n        \"\"\"\n        Sign a transaction in bytes string form.\n\n        :param transaction: the transaction to be signed\n        :return: signed transaction\n        \"\"\"\n        tx = ParseDict(transaction[\"tx\"], Tx())\n\n        # If public key is not already part of transaction\n        if tx.auth_info.signer_infos[0].public_key.value == b\"\":\n            if len(transaction[\"sign_data\"]) == 1:  # type: ignore\n                # Insert public key to auth info\n                from_pub_key_packed = ProtoAny()\n                from_pub_key_pb = ProtoPubKey(key=bytes.fromhex(self.public_key))\n                from_pub_key_packed.Pack(from_pub_key_pb, type_url_prefix=\"/\")  # type: ignore\n\n                tx.auth_info.signer_infos[\n                    0\n                ].public_key.value = from_pub_key_packed.value\n            else:\n                # Fails if public key is not present in transaction with multiple signers\n                raise RuntimeError(\n                    \"Public key can be added during singing only for single message transactions.\"\n                )\n\n        current_sign_data = transaction[\"sign_data\"][self.address]  # type: ignore\n\n        sd = SignDoc()\n        sd.body_bytes = tx.body.SerializeToString()\n        sd.auth_info_bytes = tx.auth_info.SerializeToString()\n        sd.chain_id = current_sign_data[\"chain_id\"]  # type: ignore\n        sd.account_number = current_sign_data[\"account_number\"]  # type: ignore\n\n        data_for_signing = sd.SerializeToString()\n\n        # Generating signature:\n        signature = base64.b64decode(self.sign_message(data_for_signing))\n\n        tx.signatures.extend([signature])\n\n        return {\"tx\": MessageToDict(tx), \"sign_data\": transaction[\"sign_data\"]}\n\n    @classmethod\n    def generate_private_key(cls) -> SigningKey:\n        \"\"\"Generate a key pair for cosmos network.\"\"\"\n        signing_key = SigningKey.generate(curve=SECP256k1)\n        return signing_key\n\n    def encrypt(self, password: str) -> str:\n        \"\"\"\n        Encrypt the private key and return in json.\n\n        :param password: the password to decrypt.\n        :return: json string containing encrypted private key.\n        \"\"\"\n        return DataEncrypt.encrypt(self.private_key.encode(), password).decode()\n\n    @classmethod\n    def decrypt(cls, keyfile_json: str, password: str) -> str:\n        \"\"\"\n        Decrypt the private key and return in raw form.\n\n        :param keyfile_json: json string containing encrypted private key.\n        :param password: the password to decrypt.\n        :return: the raw private key.\n        \"\"\"\n        try:\n            return DataEncrypt.decrypt(keyfile_json.encode(), password).decode()\n        except UnicodeDecodeError as e:\n            raise ValueError(\n                \"key file data can not be translated to string! bad password?\"\n            ) from e\n\n\nclass _CosmosApi(LedgerApi):\n    \"\"\"Class to interact with the Cosmos SDK via a HTTP APIs.\"\"\"\n\n    identifier = _COSMOS\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"Initialize the Cosmos ledger APIs.\"\"\"\n        self._api = None\n        self.network_address = kwargs.pop(\"address\", DEFAULT_ADDRESS)\n        self.denom = kwargs.pop(\"denom\", DEFAULT_CURRENCY_DENOM)\n        self.chain_id = kwargs.pop(\"chain_id\", DEFAULT_CHAIN_ID)\n        self.rest_client = RestClient(self.network_address)\n        self.tx_client = TxRestClient(self.rest_client)\n        self.auth_client = AuthRestClient(self.rest_client)\n        self.wasm_client = CosmWasmRestClient(self.rest_client)\n        self.bank_client = BankRestClient(self.rest_client)\n\n    @property\n    def api(self) -> Any:\n        \"\"\"Get the underlying API object.\"\"\"\n        return self._api\n\n    def get_balance(self, address: Address) -> Optional[int]:\n        \"\"\"Get the balance of a given account.\"\"\"\n        balance = self._try_get_balance(address)\n        return balance\n\n    @try_decorator(\n        \"Encountered exception when trying get balance: {}\",\n        logger_method=_default_logger.warning,\n    )\n    def _try_get_balance(self, address: Address) -> Optional[int]:\n        res = self.bank_client.Balance(\n            QueryBalanceRequest(address=address, denom=self.denom)\n        )\n        return int(res.balance.amount)\n\n    def get_state(\n        self, callable_name: str, *args: Any, **kwargs: Any\n    ) -> Optional[JSONLike]:\n        \"\"\"\n        Call a specified function on the ledger API.\n\n        Based on the cosmos REST\n        API specification, which takes a path (strings separated by '/'). The\n        convention here is to define the root of the path (txs, blocks, etc.)\n        as the callable_name and the rest of the path as args.\n\n        :param callable_name: name of the callable\n        :param args: positional arguments\n        :param kwargs: keyword arguments\n        :return: the transaction dictionary\n        \"\"\"\n        response = self._try_get_state(callable_name, *args, **kwargs)\n        return response\n\n    @try_decorator(\n        \"Encountered exception when trying get state: {}\",\n        logger_method=_default_logger.warning,\n    )\n    def _try_get_state(  # pylint: disable=unused-argument\n        self, callable_name: str, *args: Any, **kwargs: Any\n    ) -> Optional[JSONLike]:\n        \"\"\"Try to call a function on the ledger API.\"\"\"\n        result: Optional[JSONLike] = None\n        query = \"/\".join(args)\n        url = self.network_address + f\"/{callable_name}/{query}\"\n        response = requests.get(url=url)\n        if response.status_code == 200:\n            result = response.json()\n        else:  # pragma: nocover\n            raise ValueError(\"Cannot get state: {}\".format(response.json()))\n        return result\n\n    def get_deploy_transaction(\n        self,\n        contract_interface: Dict[str, str],\n        deployer_address: Address,\n        **kwargs: Any,\n    ) -> Optional[JSONLike]:\n        \"\"\"\n        Get the transaction to deploy the smart contract.\n\n        Dispatches to _get_storage_transaction and _get_init_transaction based on kwargs.\n\n        :param contract_interface: the contract interface.\n        :param deployer_address: The address that will deploy the contract.\n        :param kwargs: keyword arguments.\n        :return: the transaction dictionary.\n        \"\"\"\n        denom = (\n            kwargs.pop(\"denom\") if kwargs.get(\"denom\", None) is not None else self.denom\n        )\n\n        tx_fee_denom = (\n            kwargs.pop(\"tx_fee_denom\")\n            if kwargs.get(\"tx_fee_denom\", None) is not None\n            else denom\n        )\n\n        chain_id = (\n            kwargs.pop(\"chain_id\")\n            if kwargs.get(\"chain_id\", None) is not None\n            else self.chain_id\n        )\n\n        account_number = kwargs.pop(\"account_number\", None)\n        sequence = kwargs.pop(\"sequence\", None)\n\n        if account_number is None or sequence is None:\n            account_number, sequence = self._try_get_account_number_and_sequence(\n                deployer_address\n            )\n            if account_number is None or sequence is None:\n                return None  # pragma: nocover\n\n        label = kwargs.pop(\"label\", None)\n        code_id = kwargs.pop(\"code_id\", None)\n        amount = kwargs.pop(\"amount\", None)\n        init_msg = kwargs.pop(\"init_msg\", None)\n        unexpected_keys = [\n            key for key in kwargs.keys() if key not in [\"tx_fee\", \"gas\", \"memo\"]\n        ]\n        if len(unexpected_keys) != 0:  # pragma: nocover\n            raise ValueError(f\"Unexpected keyword arguments: {unexpected_keys}\")\n        if label is None and code_id is None and amount is None and init_msg is None:\n            return self._get_storage_transaction(\n                contract_interface,\n                deployer_address,\n                tx_fee_denom,\n                chain_id,\n                account_number,\n                sequence,\n                **kwargs,\n            )\n        if label is None:\n            raise ValueError(  # pragma: nocover\n                \"Missing required keyword argument `label` of type `str` for `_get_init_transaction`.\"\n            )\n        if code_id is None:\n            raise ValueError(  # pragma: nocover\n                \"Missing required keyword argument `code_id` of type `int` for `_get_init_transaction`.\"\n            )\n        if amount is None:\n            raise ValueError(  # pragma: nocover\n                \"Missing required keyword argument `amount` of type `int` for `_get_init_transaction`.\"\n            )\n        if init_msg is None:\n            raise ValueError(  # pragma: nocover\n                \"Missing required keyword argument `init_msg` of type `JSONLike` `for `_get_init_transaction`.\"\n            )\n        return self._get_init_transaction(\n            deployer_address,\n            denom,\n            chain_id,\n            account_number,\n            sequence,\n            amount,\n            code_id,\n            init_msg,\n            label,\n            tx_fee_denom,\n            **kwargs,\n        )\n\n    def _get_storage_transaction(\n        self,\n        contract_interface: Dict[str, str],\n        deployer_address: Address,\n        tx_fee_denom: str,\n        chain_id: str,\n        account_number: int,\n        sequence: int,\n        tx_fee: int = 0,\n        gas: int = DEFAULT_GAS_AMOUNT,\n        memo: str = \"\",\n    ) -> Optional[JSONLike]:\n        \"\"\"\n        Create a CosmWasm bytecode deployment transaction.\n\n        :param contract_interface: the contract interface.\n        :param deployer_address: the deployer address.\n        :param tx_fee_denom: the denomination of tx_fee.\n        :param chain_id: the Chain ID of the CosmWasm transaction. Default is 1 (i.e. mainnet).\n        :param account_number: the account number.\n        :param sequence: the sequence number.\n        :param tx_fee: the transaction fee.\n        :param gas: Maximum amount of gas to be used on executing command.\n        :param memo: any string comment.\n        :return: the unsigned CosmWasm contract deploy message\n        \"\"\"\n        store_msg = MsgStoreCode(\n            sender=str(deployer_address),\n            wasm_byte_code=base64.b64decode(contract_interface[_BYTECODE]),\n        )\n        store_msg_packed = ProtoAny()\n        store_msg_packed.Pack(store_msg, type_url_prefix=\"/\")  # type: ignore\n        tx_fee_coins = [Coin(denom=tx_fee_denom, amount=str(tx_fee))]\n        tx = self._get_transaction(\n            account_numbers=[account_number],\n            from_addresses=[str(deployer_address)],\n            chain_id=chain_id,\n            tx_fee=tx_fee_coins,\n            gas=gas,\n            memo=memo,\n            sequences=[sequence],\n            msgs=[store_msg_packed],\n        )\n        return tx\n\n    def _get_init_transaction(\n        self,\n        deployer_address: Address,\n        denom: str,\n        chain_id: str,\n        account_number: int,\n        sequence: int,\n        amount: int,\n        code_id: int,\n        init_msg: JSONLike,\n        label: str,\n        tx_fee_denom: str,\n        tx_fee: int = 0,\n        gas: int = DEFAULT_GAS_AMOUNT,\n        memo: str = \"\",\n    ) -> Optional[JSONLike]:\n        \"\"\"\n        Create a CosmWasm InitMsg transaction.\n\n        :param deployer_address: the deployer address of the message initiator.\n        :param denom: the name of the denomination of the contract funds\n        :param chain_id: the Chain ID of the CosmWasm transaction.\n        :param account_number: the account number of the deployer.\n        :param sequence: the sequence of the deployer.\n        :param amount: Contract's initial funds amount\n        :param code_id: the ID of contract bytecode.\n        :param init_msg: the InitMsg containing parameters for contract constructor.\n        :param label: the label name of the contract.\n        :param tx_fee_denom: Denomination of tx_fee\n        :param tx_fee: the tx fee accepted.\n        :param gas: Maximum amount of gas to be used on executing command.\n        :param memo: any string comment.\n        :return: the unsigned CosmWasm InitMsg\n        \"\"\"\n        if amount == 0:\n            init_funds = []\n        else:\n            init_funds = [Coin(denom=denom, amount=str(amount))]\n\n        tx_fee_coins = [Coin(denom=tx_fee_denom, amount=str(tx_fee))]\n\n        init_msg = MsgInstantiateContract(\n            sender=str(deployer_address),\n            code_id=code_id,\n            msg=json.dumps(init_msg).encode(\"UTF8\"),\n            label=label,\n            funds=init_funds,\n        )\n        init_msg_packed = ProtoAny()\n        init_msg_packed.Pack(init_msg, type_url_prefix=\"/\")  # type: ignore\n\n        tx = self._get_transaction(\n            account_numbers=[account_number],\n            from_addresses=[str(deployer_address)],\n            chain_id=chain_id,\n            tx_fee=tx_fee_coins,\n            gas=gas,\n            memo=memo,\n            sequences=[sequence],\n            msgs=[init_msg_packed],\n        )\n        return tx\n\n    def get_handle_transaction(\n        self,\n        sender_address: Address,\n        contract_address: Address,\n        handle_msg: Any,\n        amount: int,\n        tx_fee: int,\n        denom: Optional[str] = None,\n        gas: int = DEFAULT_GAS_AMOUNT,\n        memo: str = \"\",\n        chain_id: Optional[str] = None,\n        account_number: Optional[int] = None,\n        sequence: Optional[int] = None,\n        tx_fee_denom: Optional[str] = None,\n    ) -> Optional[JSONLike]:\n        \"\"\"\n        Create a CosmWasm HandleMsg transaction.\n\n        :param sender_address: the sender address of the message initiator.\n        :param contract_address: the address of the smart contract.\n        :param handle_msg: HandleMsg in JSON format.\n        :param amount: Funds amount sent with transaction.\n        :param tx_fee: the tx fee accepted.\n        :param denom: the name of the denomination of the contract funds\n        :param gas: Maximum amount of gas to be used on executing command.\n        :param memo: any string comment.\n        :param chain_id: the Chain ID of the CosmWasm transaction. Default is 1 (i.e. mainnet).\n        :param account_number: Account number\n        :param sequence: Sequence\n        :param tx_fee_denom: Denomination of tx_fee, identical with denom param when None\n        :return: the unsigned CosmWasm HandleMsg\n        \"\"\"\n        denom = denom if denom is not None else self.denom\n        chain_id = chain_id if chain_id is not None else self.chain_id\n        tx_fee_denom = tx_fee_denom if tx_fee_denom is not None else denom\n\n        if account_number is None or sequence is None:\n            account_number, sequence = self._try_get_account_number_and_sequence(\n                sender_address\n            )\n            if account_number is None or sequence is None:\n                return None  # pragma: nocover\n\n        if amount == 0:\n            funds = []\n        else:\n            funds = [Coin(denom=denom, amount=str(amount))]\n        tx_fee_coins = [Coin(denom=tx_fee_denom, amount=str(tx_fee))]\n\n        execute_msg = MsgExecuteContract(\n            sender=str(sender_address),\n            contract=contract_address,\n            msg=json.dumps(handle_msg).encode(\"UTF8\"),\n            funds=funds,\n        )\n        execute_msg_packed = ProtoAny()\n        execute_msg_packed.Pack(execute_msg, type_url_prefix=\"/\")  # type: ignore\n\n        tx = self._get_transaction(\n            account_numbers=[account_number],\n            from_addresses=[str(sender_address)],\n            chain_id=chain_id,\n            tx_fee=tx_fee_coins,\n            gas=gas,\n            memo=memo,\n            sequences=[sequence],\n            msgs=[execute_msg_packed],\n        )\n        return tx\n\n    def execute_contract_query(\n        self, contract_address: Address, query_msg: JSONLike\n    ) -> Optional[JSONLike]:\n        \"\"\"\n        Execute a CosmWasm QueryMsg. QueryMsg doesn't require signing.\n\n        :param contract_address: the address of the smart contract.\n        :param query_msg: QueryMsg in JSON format.\n        :return: the message receipt\n        \"\"\"\n        result = self._try_execute_wasm_query(contract_address, query_msg)\n        return result\n\n    @try_decorator(\n        \"Encountered exception when trying to execute wasm query: {}\",\n        logger_method=_default_logger.warning,\n    )\n    def _try_execute_wasm_query(\n        self, contract_address: Address, query_msg: JSONLike\n    ) -> Optional[JSONLike]:\n        \"\"\"\n        Execute a CosmWasm QueryMsg. QueryMsg doesn't require signing.\n\n        :param contract_address: the address of the smart contract.\n        :param query_msg: QueryMsg in JSON format.\n        :return: the message receipt\n        \"\"\"\n        request = QuerySmartContractStateRequest(\n            address=contract_address, query_data=json.dumps(query_msg).encode(\"UTF8\")\n        )\n        res = self.wasm_client.SmartContractState(request)\n        return json.loads(res.data)\n\n    def get_transfer_transaction(  # pylint: disable=arguments-differ\n        self,\n        sender_address: Address,\n        destination_address: Address,\n        amount: int,\n        tx_fee: int,\n        tx_nonce: str,\n        denom: Optional[str] = None,\n        gas: int = DEFAULT_GAS_AMOUNT,\n        memo: str = \"\",\n        chain_id: Optional[str] = None,\n        account_number: Optional[int] = None,\n        sequence: Optional[int] = None,\n        tx_fee_denom: Optional[str] = None,\n        **kwargs: Any,\n    ) -> Optional[JSONLike]:\n        \"\"\"\n        Submit a transfer transaction to the ledger.\n\n        :param sender_address: the sender address of the payer.\n        :param destination_address: the destination address of the payee.\n        :param amount: the amount of wealth to be transferred.\n        :param tx_fee: the transaction fee.\n        :param tx_nonce: verifies the authenticity of the tx\n        :param denom: the denomination of tx fee and amount\n        :param gas: the gas used.\n        :param memo: memo to include in tx.\n        :param chain_id: the chain ID of the transaction.\n        :param account_number: Account number\n        :param sequence: Sequence\n        :param tx_fee_denom: Denomination of tx_fee, identical with denom param when None\n        :param kwargs: keyword arguments.\n        :return: the transfer transaction\n        \"\"\"\n        denom = denom if denom is not None else self.denom\n        chain_id = chain_id if chain_id is not None else self.chain_id\n        tx_fee_denom = tx_fee_denom if tx_fee_denom is not None else denom\n\n        if account_number is None or sequence is None:\n            account_number, sequence = self._try_get_account_number_and_sequence(\n                sender_address\n            )\n            if account_number is None or sequence is None:\n                return None  # pragma: nocover\n\n        tx_fee_coins = [Coin(denom=tx_fee_denom, amount=str(tx_fee))]\n        amount_coins = [Coin(denom=denom, amount=str(amount))]\n\n        msg_send = MsgSend(\n            from_address=str(sender_address),\n            to_address=str(destination_address),\n            amount=amount_coins,\n        )\n        send_msg_packed = ProtoAny()\n        send_msg_packed.Pack(msg_send, type_url_prefix=\"/\")  # type: ignore\n\n        tx = self._get_transaction(\n            account_numbers=[account_number],\n            from_addresses=[str(sender_address)],\n            chain_id=chain_id,\n            tx_fee=tx_fee_coins,\n            gas=gas,\n            memo=memo,\n            sequences=[sequence],\n            msgs=[send_msg_packed],\n        )\n        return tx\n\n    def get_packed_exec_msg(\n        self,\n        sender_address: Address,\n        contract_address: str,\n        msg: JSONLike,\n        funds: int = 0,\n        denom: Optional[str] = None,\n    ) -> ProtoAny:\n        \"\"\"\n        Create and pack MsgExecuteContract\n\n        :param sender_address: Address of sender\n        :param contract_address: Address of contract\n        :param msg: Paramaters to be passed to smart contract\n        :param funds: Funds to be sent to smart contract\n        :param denom: the denomination of funds\n\n        :return: Packed MsgExecuteContract\n        \"\"\"\n        denom = denom if denom is not None else self.denom\n\n        if funds == 0:\n            funds_coins = []\n        else:\n            funds_coins = [Coin(denom=denom, amount=str(funds))]\n\n        msg_send = MsgExecuteContract(\n            sender=str(sender_address),\n            contract=contract_address,\n            msg=json.dumps(msg).encode(\"UTF8\"),\n            funds=funds_coins,\n        )\n        send_msg_packed = ProtoAny()\n        send_msg_packed.Pack(msg_send, type_url_prefix=\"/\")\n\n        return send_msg_packed\n\n    def get_packed_send_msg(\n        self,\n        from_address: Address,\n        to_address: Address,\n        amount: int,\n        denom: Optional[str] = None,\n    ) -> ProtoAny:\n        \"\"\"\n        Generate and pack MsgSend\n\n        :param from_address: Address of sender\n        :param to_address: Address of recipient\n        :param amount: amount of coins to be sent\n        :param denom: the denomination of and amount\n\n        :return: packer ProtoAny type message\n        \"\"\"\n        denom = denom if denom is not None else self.denom\n\n        amount_coins = [Coin(denom=denom, amount=str(amount))]\n\n        msg_send = MsgSend(\n            from_address=str(from_address),\n            to_address=str(to_address),\n            amount=amount_coins,\n        )\n        send_msg_packed = ProtoAny()\n        send_msg_packed.Pack(msg_send, type_url_prefix=\"/\")\n\n        return send_msg_packed\n\n    def get_multi_transaction(\n        self,\n        from_addresses: List[str],\n        pub_keys: Optional[List[bytes]],\n        msgs: List[ProtoAny],\n        gas: int,\n        tx_fee: int = 0,\n        memo: str = \"\",\n        chain_id: Optional[str] = None,\n        denom: Optional[str] = None,\n        tx_fee_denom: Optional[str] = None,\n    ) -> JSONLike:\n        \"\"\"\n        Generate transaction with multiple messages\n\n        :param from_addresses: Addresses of signers\n        :param pub_keys: Public keys of signers\n        :param msgs: Messages to be included in transaction\n        :param gas: the gas used.\n        :param tx_fee: the transaction fee.\n        :param memo: memo to include in tx.\n        :param chain_id: the chain ID of the transaction.\n        :param denom: the denomination of tx fee\n        :param tx_fee_denom: Denomination of tx_fee, identical with denom param when None\n\n        :raises: RuntimeError if number of pubkeys is not equal to number of from_addresses\n\n        :return: the transaction\n        \"\"\"\n        if pub_keys is not None and len(pub_keys) != len(from_addresses):\n            raise RuntimeError(\n                \"Number of pubkeys is not equal to number of addresses\"\n            )  # pragma: nocover\n\n        denom = denom if denom is not None else self.denom\n        chain_id = chain_id if chain_id is not None else self.chain_id\n        tx_fee_denom = tx_fee_denom if tx_fee_denom is not None else denom\n\n        tx_fee_coins = [Coin(denom=tx_fee_denom, amount=str(tx_fee))]\n\n        account_numbers: List[int] = []\n        sequences: List[int] = []\n        for address in from_addresses:\n            account_number, sequence = self._try_get_account_number_and_sequence(\n                address\n            )\n            account_numbers.append(account_number)\n            sequences.append(sequence)\n            # Prevent requests overflow\n            time.sleep(1)\n\n        return self._get_transaction(\n            account_numbers=account_numbers,\n            from_addresses=from_addresses,\n            chain_id=chain_id,\n            tx_fee=tx_fee_coins,\n            gas=gas,\n            memo=memo,\n            sequences=sequences,\n            msgs=msgs,\n            pub_keys=pub_keys,\n        )\n\n    @staticmethod\n    def _get_transaction(\n        account_numbers: List[int],\n        from_addresses: List[str],\n        chain_id: str,\n        tx_fee: List[Coin],\n        gas: int,\n        memo: str,\n        sequences: List[int],\n        msgs: List[ProtoAny],\n        pub_keys: Optional[List[bytes]] = None,\n    ) -> JSONLike:\n        \"\"\"\n        Get a transaction.\n\n        :param account_numbers: Account numbers for each signer.\n        :param from_addresses: Addresses of each sender\n        :param chain_id: the chain ID of the transaction.\n        :param tx_fee: the transaction fee.\n        :param gas: the gas used.\n        :param memo: memo to include in tx.\n        :param sequences: Sequence for each sender.\n        :param msgs: Messages to be part of transaction.\n        :param pub_keys: Public keys of each sender\n\n        :raises: RuntimeError\n\n        :return: the transaction\n        \"\"\"\n\n        # Txs will fail if gas is higher than MAXIMUM_GAS_AMOUNT\n        if gas > MAXIMUM_GAS_AMOUNT:\n            _default_logger.warning(\n                f\"Gas limit {gas} is above maximum gas limit {MAXIMUM_GAS_AMOUNT}. Gas limit was truncated to maximum.\"\n            )\n            gas = MAXIMUM_GAS_AMOUNT\n\n        # Checks\n        if pub_keys is None:\n            if len(from_addresses) == 1:\n                pub_keys = [b\"\"]\n            else:\n                # In case when pubkey is inserted during signing would make second signer to change tx and make the first signature invalid\n                raise RuntimeError(\n                    \"Only transaction with one signer can be generated without pubkeys\"\n                )\n        if len(account_numbers) != len(from_addresses) or len(from_addresses) != len(\n            sequences\n        ):\n            raise RuntimeError(\n                \"Amount of provided from_addresses, sequences and account_numbers is not equal\"\n            )\n\n        # Get account and signer info for each sender\n        signer_infos: List[SignerInfo] = []\n        sign_data: JSONLike = {}\n        for from_address, pub_key, sequence, account_number in zip(\n            from_addresses, pub_keys, sequences, account_numbers\n        ):\n            from_pub_key_packed = ProtoAny()\n            from_pub_key_pb = ProtoPubKey(key=pub_key)\n            from_pub_key_packed.Pack(from_pub_key_pb, type_url_prefix=\"/\")  # type: ignore\n\n            # Prepare auth info\n            single = ModeInfo.Single(mode=SignMode.SIGN_MODE_DIRECT)\n            mode_info = ModeInfo(single=single)\n            signer_info = SignerInfo(\n                public_key=from_pub_key_packed,\n                mode_info=mode_info,\n                sequence=sequence,\n            )\n            signer_infos.append(signer_info)\n\n            sign_data[from_address] = {\n                \"account_number\": account_number,\n                \"chain_id\": chain_id,\n            }\n\n        # Prepare auth info\n        auth_info = AuthInfo(\n            signer_infos=signer_infos,\n            fee=Fee(amount=tx_fee, gas_limit=gas),\n        )\n\n        # Prepare Tx body\n        tx_body = TxBody()\n        tx_body.memo = memo\n        tx_body.messages.extend(msgs)\n\n        # Prepare Tx\n        tx = Tx(body=tx_body, auth_info=auth_info)\n\n        return {\"tx\": MessageToDict(tx), \"sign_data\": sign_data}\n\n    @try_decorator(\n        \"Encountered exception when trying to get account number and sequence: {}\",\n        logger_method=_default_logger.warning,\n    )\n    def _try_get_account_number_and_sequence(\n        self, address: Address\n    ) -> Tuple[Optional[int], Optional[int]]:\n        \"\"\"\n        Try get account number and sequence for an address.\n\n        :param address: the address\n        :return: a tuple of account number and sequence\n        \"\"\"\n        account_response = self.auth_client.Account(\n            QueryAccountRequest(address=address)\n        )\n\n        account = BaseAccount()\n        if account_response.account.Is(BaseAccount.DESCRIPTOR):\n            account_response.account.Unpack(account)\n        else:\n            raise TypeError(\"Unexpected account type\")  # pragma: nocover\n\n        return account.account_number, account.sequence\n\n    def send_signed_transaction(self, tx_signed: JSONLike) -> Optional[str]:\n        \"\"\"\n        Send a signed transaction and wait for confirmation.\n\n        :param tx_signed: the signed transaction\n        :return: tx_digest, if present\n        \"\"\"\n        tx = ParseDict(tx_signed[\"tx\"], Tx())\n\n        tx_data = tx.SerializeToString()\n        broad_tx_req = BroadcastTxRequest(\n            tx_bytes=tx_data, mode=BroadcastMode.BROADCAST_MODE_SYNC\n        )\n        broad_tx_resp = self.tx_client.BroadcastTx(broad_tx_req)\n\n        if broad_tx_resp.tx_response.code != 0:\n            raw_log = broad_tx_resp.tx_response.raw_log\n\n            _default_logger.warning(\n                f\"Sending transaction failed: {raw_log} {broad_tx_resp}\"\n            )\n            tx_digest = None\n        else:\n            tx_digest = broad_tx_resp.tx_response.txhash\n\n        return tx_digest\n\n    def get_transaction_receipt(self, tx_digest: str) -> Optional[JSONLike]:\n        \"\"\"\n        Get the transaction receipt for a transaction digest.\n\n        :param tx_digest: the digest associated to the transaction.\n        :return: the tx receipt, if present\n        \"\"\"\n        tx_with_receipt = self._try_get_transaction_with_receipt(tx_digest)\n\n        if tx_with_receipt is None:\n            return None\n        return tx_with_receipt.get(\"txResponse\")\n\n    @try_decorator(\n        \"Encountered exception when trying to get transaction receipt: {}\",\n        logger_method=_default_logger.warning,\n    )\n    def _try_get_transaction_with_receipt(self, tx_digest: str) -> Optional[JSONLike]:\n        \"\"\"\n        Try get the transaction receipt for a transaction digest.\n\n        :param tx_digest: the digest associated to the transaction.\n        :return: the tx receipt, if present\n        \"\"\"\n\n        tx_request = GetTxRequest(hash=tx_digest)\n        tx_response = self.tx_client.GetTx(tx_request)\n        return MessageToDict(tx_response)\n\n    def get_transaction(self, tx_digest: str) -> Optional[JSONLike]:\n        \"\"\"\n        Get the transaction for a transaction digest.\n\n        :param tx_digest: the digest associated to the transaction.\n        :return: the tx, if present\n        \"\"\"\n        # Cosmos does not distinguish between transaction receipt and transaction\n        tx_with_receipt = self._try_get_transaction_with_receipt(tx_digest)\n        if tx_with_receipt is None:\n            return None  # pragma: nocover\n        return {\"tx\": tx_with_receipt.get(\"tx\")}\n\n    def get_contract_instance(\n        self, contract_interface: Dict[str, str], contract_address: Optional[str] = None\n    ) -> Any:\n        \"\"\"\n        Get the instance of a contract.\n\n        :param contract_interface: the contract interface.\n        :param contract_address: the contract address.\n        :return: the contract instance\n        \"\"\"\n        # Instance object not available for cosmwasm\n        return None\n\n    def update_with_gas_estimate(self, transaction: JSONLike) -> JSONLike:\n        \"\"\"\n        Attempts to update the transaction with a gas estimate\n\n        :param transaction: the transaction\n        :raises: NotImplementedError\n        \"\"\"\n        raise NotImplementedError(  # pragma: nocover\n            \"No gas estimation has been implemented.\"\n        )\n\n\nclass CosmosApi(_CosmosApi, CosmosHelper):\n    \"\"\"Class to interact with the Cosmos SDK via a HTTP APIs.\"\"\"\n\n\n\"\"\" Equivalent to:\n\n@dataclass\nclass CosmosFaucetStatus:\n    tx_digest: Optional[str]\n    status: str\n\"\"\"\nCosmosFaucetStatus = namedtuple(\"CosmosFaucetStatus\", [\"tx_digest\", \"status\"])\n\n\nclass CosmosFaucetApi(FaucetApi):\n    \"\"\"Cosmos testnet faucet API.\"\"\"\n\n    FAUCET_STATUS_PENDING = \"pending\"  # noqa: F841\n    FAUCET_STATUS_PROCESSING = \"processing\"  # noqa: F841\n    FAUCET_STATUS_COMPLETED = \"complete\"  # noqa: F841\n    FAUCET_STATUS_FAILED = \"failed\"  # noqa: F841\n\n    identifier = _COSMOS\n    testnet_faucet_url = DEFAULT_FAUCET_URL\n    testnet_name = TESTNET_NAME\n    max_retry_attempts = 15\n\n    def __init__(\n        self,\n        poll_interval: Optional[float] = None,\n        final_wait_interval: Optional[float] = None,\n    ):\n        \"\"\"Initialize CosmosFaucetApi.\"\"\"\n        self._poll_interval = float(poll_interval or 2)\n        self._final_wait_interval = float(final_wait_interval or 5)\n\n    def get_wealth(self, address: Address, url: Optional[str] = None) -> None:\n        \"\"\"\n        Get wealth from the faucet for the provided address.\n\n        :param address: the address.\n        :param url: the url\n        :raises: RuntimeError of explicit faucet failures\n        \"\"\"\n        uid = self._try_create_faucet_claim(address, url)\n        if uid is None:  # pragma: nocover\n            raise RuntimeError(\"Unable to create faucet claim\")\n\n        retry_attempts = self.max_retry_attempts\n        while retry_attempts > 0:\n            retry_attempts -= 1\n\n            # lookup status form the claim uid\n            status = self._try_check_faucet_claim(uid, url)\n            if status is None:  # pragma: nocover\n                raise RuntimeError(\"Failed to check faucet claim status\")\n\n            # if the status is complete\n            if status.status == self.FAUCET_STATUS_COMPLETED:\n                break\n\n            # if the status is failure\n            if status.status not in (\n                self.FAUCET_STATUS_PENDING,\n                self.FAUCET_STATUS_PROCESSING,\n            ):  # pragma: nocover\n                raise RuntimeError(f\"Failed to get wealth for {address}\")\n\n            # if the status is incomplete\n            time.sleep(self._poll_interval)\n        if retry_attempts == 0:\n            raise ValueError(\"Faucet claim check timed out!\")  # pragma: nocover\n        # Wait to ensure that balance is increased on chain\n        time.sleep(self._final_wait_interval)\n\n    @classmethod\n    @try_decorator(\n        \"An error occured while attempting to request a faucet request:\\n{}\",\n        logger_method=_default_logger.error,\n    )\n    def _try_create_faucet_claim(\n        cls, address: Address, url: Optional[str] = None\n    ) -> Optional[str]:\n        \"\"\"\n        Create a token faucet claim request\n\n        :param address: the address to request funds\n        :param url: the url\n        :return: None on failure, otherwise the request uid\n        \"\"\"\n        uri = cls._faucet_request_uri(url)\n        response = requests.post(url=uri, json={\"address\": address})\n\n        uid = None\n        if response.status_code == 200:\n            try:\n                uid = response.json()[\"uuid\"]\n            except KeyError:  # pragma: nocover\n                ValueError(f\"key `uid` not found in response_json={response.json()}\")\n            _default_logger.info(\"Wealth claim generated, uid: {}\".format(uid))\n        else:  # pragma: no cover\n            _default_logger.warning(\n                \"Response: {}, Text: {}\".format(response.status_code, response.text)\n            )\n\n        return uid\n\n    @classmethod\n    @try_decorator(\n        \"An error occured while attempting to request a faucet request:\\n{}\",\n        logger_method=_default_logger.error,\n    )\n    def _try_check_faucet_claim(\n        cls, uid: str, url: Optional[str] = None\n    ) -> Optional[CosmosFaucetStatus]:\n        \"\"\"\n        Check the status of a faucet request\n\n        :param uid: The request uid to be checked\n        :param url: the url\n        :return: None on failure otherwise a CosmosFaucetStatus for the specified uid\n        \"\"\"\n        response = requests.get(cls._faucet_status_uri(uid, url))\n        if response.status_code != 200:  # pragma: nocover\n            _default_logger.warning(\n                \"Response: {}, Text: {}\".format(response.status_code, response.text)\n            )\n            return None\n\n        # parse the response\n        data = response.json()\n        tx_digest = None\n        if \"txStatus\" in data[\"claim\"]:\n            tx_digest = data[\"claim\"][\"txStatus\"][\"hash\"]\n\n        return CosmosFaucetStatus(\n            tx_digest=tx_digest,\n            status=data[\"claim\"][\"status\"],\n        )\n\n    @classmethod\n    def _faucet_request_uri(cls, url: Optional[str] = None) -> str:\n        \"\"\"\n        Generates the request URI derived from `cls.faucet_base_url` or provided url.\n\n        :param url: the url\n        :return: the faucet request uri\n        \"\"\"\n        if cls.testnet_faucet_url is None:  # pragma: nocover\n            raise ValueError(\"Testnet faucet url not set.\")\n        url = cls.testnet_faucet_url if url is None else url\n        return f\"{url}/api/v3/claims\"\n\n    @classmethod\n    def _faucet_status_uri(cls, uid: str, url: Optional[str] = None) -> str:\n        \"\"\"Generates the status URI derived from `cls.faucet_base_url`.\"\"\"\n        return f\"{cls._faucet_request_uri(url)}/{uid}\"\n"
  },
  {
    "path": "plugins/aea-ledger-cosmos/pyproject.toml",
    "content": "[build-system]\nrequires = [\"setuptools\", \"wheel\"]\nbuild_backend = \"setuptools.build_meta\"\n"
  },
  {
    "path": "plugins/aea-ledger-cosmos/setup.py",
    "content": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Setup script for \"aea_ledger_cosmos\" package.\"\"\"\n\nfrom setuptools import find_packages, setup\n\n\nsetup(\n    name=\"aea-ledger-cosmos\",\n    version=\"1.2.5\",\n    author=\"Fetch.AI Limited\",\n    license=\"Apache-2.0\",\n    description=\"Python package wrapping the public and private key cryptography and ledger api of Cosmos.\",\n    packages=find_packages(include=[\"aea_ledger_cosmos*\"]),\n    install_requires=[\n        \"aea>=1.0.0, <2.0.0\",\n        \"ecdsa>=0.15,<0.17.0\",\n        \"bech32==1.2.0\",\n        \"pycryptodome>=3.10.1,<4.0.0\",\n        \"cosmpy>=0.6.2,<0.7.0\",\n    ],\n    tests_require=[\"pytest\"],\n    entry_points={\n        \"aea.cryptos\": [\"cosmos = aea_ledger_cosmos:CosmosCrypto\"],\n        \"aea.ledger_apis\": [\"cosmos = aea_ledger_cosmos:CosmosApi\"],\n        \"aea.faucet_apis\": [\"cosmos = aea_ledger_cosmos:CosmosFaucetApi\"],\n    },\n    classifiers=[\n        \"Environment :: Console\",\n        \"Environment :: Web Environment\",\n        \"Development Status :: 5 - Production/Stable\",\n        \"Intended Audience :: Developers\",\n        \"License :: OSI Approved :: Apache Software License\",\n        \"Natural Language :: English\",\n        \"Operating System :: MacOS\",\n        \"Operating System :: Microsoft\",\n        \"Operating System :: Unix\",\n        \"Programming Language :: Python :: 3.6\",\n        \"Programming Language :: Python :: 3.7\",\n        \"Programming Language :: Python :: 3.8\",\n        \"Programming Language :: Python :: 3.9\",\n        \"Topic :: Communications\",\n        \"Topic :: Internet\",\n        \"Topic :: Software Development\",\n    ],\n)\n"
  },
  {
    "path": "plugins/aea-ledger-cosmos/tests/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Tests for the aea_ledger_cosmos package.\"\"\"\n"
  },
  {
    "path": "plugins/aea-ledger-cosmos/tests/conftest.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Conftest module for Pytest.\"\"\"\nimport inspect\nimport os\n\nfrom aea_ledger_cosmos import CosmosCrypto\n\n\nCUR_PATH = os.path.dirname(inspect.getfile(inspect.currentframe()))  # type: ignore\nROOT_DIR = os.path.join(CUR_PATH, \"..\")\nMAX_FLAKY_RERUNS = 3\nCOSMOS = CosmosCrypto.identifier\n\nCOSMOS_DEFAULT_ADDRESS = \"INVALID_URL\"\nCOSMOS_DEFAULT_CURRENCY_DENOM = \"INVALID_CURRENCY_DENOM\"\nCOSMOS_DEFAULT_CHAIN_ID = \"INVALID_CHAIN_ID\"\nCOSMOS_TESTNET_CONFIG = {\"address\": COSMOS_DEFAULT_ADDRESS}\n"
  },
  {
    "path": "plugins/aea-ledger-cosmos/tests/data/cosmos_private_key.txt",
    "content": "81b0352f99a08a754b56e529dda965c4ce974edb6db7e90035e01ed193e1b7bc"
  },
  {
    "path": "plugins/aea-ledger-cosmos/tests/data/dummy_contract/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains a dummy contract for an AEA.\"\"\"\n"
  },
  {
    "path": "plugins/aea-ledger-cosmos/tests/data/dummy_contract/build/some.json",
    "content": "{\n  \"contractName\": \"erc1155\",\n  \"abi\": [\n    {\n      \"name\": \"TransferSingle\",\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_operator\",\n          \"indexed\": true\n        },\n        {\n          \"type\": \"address\",\n          \"name\": \"_from\",\n          \"indexed\": true\n        },\n        {\n          \"type\": \"address\",\n          \"name\": \"_to\",\n          \"indexed\": true\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_id\",\n          \"indexed\": false\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_value\",\n          \"indexed\": false\n        }\n      ],\n      \"anonymous\": false,\n      \"type\": \"event\"\n    },\n    {\n      \"name\": \"TransferBatch\",\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_operator\",\n          \"indexed\": true\n        },\n        {\n          \"type\": \"address\",\n          \"name\": \"_from\",\n          \"indexed\": true\n        },\n        {\n          \"type\": \"address\",\n          \"name\": \"_to\",\n          \"indexed\": true\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_ids\",\n          \"indexed\": false\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_values\",\n          \"indexed\": false\n        }\n      ],\n      \"anonymous\": false,\n      \"type\": \"event\"\n    },\n    {\n      \"name\": \"ApprovalForAll\",\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_owner\",\n          \"indexed\": true\n        },\n        {\n          \"type\": \"address\",\n          \"name\": \"_operator\",\n          \"indexed\": true\n        },\n        {\n          \"type\": \"bool\",\n          \"name\": \"_approved\",\n          \"indexed\": false\n        }\n      ],\n      \"anonymous\": false,\n      \"type\": \"event\"\n    },\n    {\n      \"name\": \"URI\",\n      \"inputs\": [\n        {\n          \"type\": \"string\",\n          \"name\": \"_value\",\n          \"indexed\": false\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_id\",\n          \"indexed\": true\n        }\n      ],\n      \"anonymous\": false,\n      \"type\": \"event\"\n    },\n    {\n      \"outputs\": [],\n      \"inputs\": [],\n      \"constant\": false,\n      \"payable\": false,\n      \"type\": \"constructor\"\n    },\n    {\n      \"name\": \"getAddress\",\n      \"outputs\": [\n        {\n          \"type\": \"bytes32\",\n          \"name\": \"out\"\n        }\n      ],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_addr\"\n        }\n      ],\n      \"constant\": true,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 370\n    },\n    {\n      \"name\": \"getHash\",\n      \"outputs\": [\n        {\n          \"type\": \"bytes32\",\n          \"name\": \"out\"\n        }\n      ],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_from\"\n        },\n        {\n          \"type\": \"address\",\n          \"name\": \"_to\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_ids\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_from_supplies\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_to_supplies\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_value_eth\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_nonce\"\n        }\n      ],\n      \"constant\": true,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 11446\n    },\n    {\n      \"name\": \"getSingleHash\",\n      \"outputs\": [\n        {\n          \"type\": \"bytes32\",\n          \"name\": \"out\"\n        }\n      ],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_from\"\n        },\n        {\n          \"type\": \"address\",\n          \"name\": \"_to\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_id\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_from_supply\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_to_supply\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_value_eth\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_nonce\"\n        }\n      ],\n      \"constant\": true,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 2041\n    },\n    {\n      \"name\": \"supportsInterface\",\n      \"outputs\": [\n        {\n          \"type\": \"bool\",\n          \"name\": \"out\"\n        }\n      ],\n      \"inputs\": [\n        {\n          \"type\": \"bytes32\",\n          \"name\": \"_interfaceID\"\n        }\n      ],\n      \"constant\": true,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 868\n    },\n    {\n      \"name\": \"is_nonce_used\",\n      \"outputs\": [\n        {\n          \"type\": \"bool\",\n          \"name\": \"out\"\n        }\n      ],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"addr\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"nonce\"\n        }\n      ],\n      \"constant\": true,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 1052\n    },\n    {\n      \"name\": \"is_token_id_exists\",\n      \"outputs\": [\n        {\n          \"type\": \"bool\",\n          \"name\": \"out\"\n        }\n      ],\n      \"inputs\": [\n        {\n          \"type\": \"uint256\",\n          \"name\": \"token_id\"\n        }\n      ],\n      \"constant\": true,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 928\n    },\n    {\n      \"name\": \"safeTransferFrom\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_from\"\n        },\n        {\n          \"type\": \"address\",\n          \"name\": \"_to\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_id\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_value\"\n        },\n        {\n          \"type\": \"bytes\",\n          \"name\": \"_data\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 80803\n    },\n    {\n      \"name\": \"safeBatchTransferFrom\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_from\"\n        },\n        {\n          \"type\": \"address\",\n          \"name\": \"_to\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_ids\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_values\"\n        },\n        {\n          \"type\": \"bytes\",\n          \"name\": \"_data\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 748184\n    },\n    {\n      \"name\": \"balanceOf\",\n      \"outputs\": [\n        {\n          \"type\": \"uint256\",\n          \"name\": \"out\"\n        }\n      ],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_owner\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_id\"\n        }\n      ],\n      \"constant\": true,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 1172\n    },\n    {\n      \"name\": \"balanceOfBatch\",\n      \"outputs\": [\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"out\"\n        }\n      ],\n      \"inputs\": [\n        {\n          \"type\": \"address[10]\",\n          \"name\": \"_owner\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_ids\"\n        }\n      ],\n      \"constant\": true,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 7524\n    },\n    {\n      \"name\": \"setApprovalForAll\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_operator\"\n        },\n        {\n          \"type\": \"bool\",\n          \"name\": \"_approved\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 38136\n    },\n    {\n      \"name\": \"isApprovedForAll\",\n      \"outputs\": [\n        {\n          \"type\": \"bool\",\n          \"name\": \"out\"\n        }\n      ],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_owner\"\n        },\n        {\n          \"type\": \"address\",\n          \"name\": \"_operator\"\n        }\n      ],\n      \"constant\": true,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 1301\n    },\n    {\n      \"name\": \"createSingle\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_item_owner\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_id\"\n        },\n        {\n          \"type\": \"string\",\n          \"name\": \"_path\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 597461\n    },\n    {\n      \"name\": \"createBatch\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_items_owner\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_ids\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 927926\n    },\n    {\n      \"name\": \"mint\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_to\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_id\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_supply\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": false,\n      \"type\": \"function\"\n    },\n    {\n      \"name\": \"mint\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_to\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_id\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_supply\"\n        },\n        {\n          \"type\": \"bytes\",\n          \"name\": \"_data\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": false,\n      \"type\": \"function\"\n    },\n    {\n      \"name\": \"mintBatch\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_to\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_ids\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_supplies\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": false,\n      \"type\": \"function\"\n    },\n    {\n      \"name\": \"mintBatch\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_to\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_ids\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_supplies\"\n        },\n        {\n          \"type\": \"bytes\",\n          \"name\": \"_data\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": false,\n      \"type\": \"function\"\n    },\n    {\n      \"name\": \"burn\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_id\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_supply\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 40353\n    },\n    {\n      \"name\": \"burnBatch\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_ids\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_supplies\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 382149\n    },\n    {\n      \"name\": \"tradeBatch\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_from\"\n        },\n        {\n          \"type\": \"address\",\n          \"name\": \"_to\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_ids\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_from_supplies\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_to_supplies\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_value_eth\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_nonce\"\n        },\n        {\n          \"type\": \"bytes\",\n          \"name\": \"_signature\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": true,\n      \"type\": \"function\"\n    },\n    {\n      \"name\": \"tradeBatch\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_from\"\n        },\n        {\n          \"type\": \"address\",\n          \"name\": \"_to\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_ids\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_from_supplies\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_to_supplies\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_value_eth\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_nonce\"\n        },\n        {\n          \"type\": \"bytes\",\n          \"name\": \"_signature\"\n        },\n        {\n          \"type\": \"bytes\",\n          \"name\": \"_data\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": true,\n      \"type\": \"function\"\n    },\n    {\n      \"name\": \"trade\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_from\"\n        },\n        {\n          \"type\": \"address\",\n          \"name\": \"_to\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_id\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_from_supply\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_to_supply\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_value_eth\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_nonce\"\n        },\n        {\n          \"type\": \"bytes\",\n          \"name\": \"_signature\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": true,\n      \"type\": \"function\"\n    },\n    {\n      \"name\": \"trade\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_from\"\n        },\n        {\n          \"type\": \"address\",\n          \"name\": \"_to\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_id\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_from_supply\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_to_supply\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_value_eth\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_nonce\"\n        },\n        {\n          \"type\": \"bytes\",\n          \"name\": \"_signature\"\n        },\n        {\n          \"type\": \"bytes\",\n          \"name\": \"_data\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": true,\n      \"type\": \"function\"\n    },\n    {\n      \"name\": \"owner\",\n      \"outputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"out\"\n        }\n      ],\n      \"inputs\": [],\n      \"constant\": true,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 1263\n    }\n  ],\n  \"bytecode\": \"0x740100000000000000000000000000000000000000006020526f7fffffffffffffffffffffffffffffff6040527fffffffffffffffffffffffffffffffff8000000000000000000000000000000060605274012a05f1fffffffffffffffffffffffffdabf41c006080527ffffffffffffffffffffffffed5fa0e000000000000000000000000000000000060a052341561009857600080fd5b6000600155600160006301ffc9a760e05260c052604060c020556001600063d9b67a2660e05260c052604060c020553360025561405a56600035601c52740100000000000000000000000000000000000000006020526f7fffffffffffffffffffffffffffffff6040527fffffffffffffffffffffffffffffffff8000000000000000000000000000000060605274012a05f1fffffffffffffffffffffffffdabf41c006080527ffffffffffffffffffffffffed5fa0e000000000000000000000000000000000060a05263ae22c57d60005114156100d45734156100ac57600080fd5b60043560205181106100bd57600080fd5b50600435610140526101405160005260206000f350005b600015610313575b610580526101405261016052610180526101a0526101c0526101e05261020052610220526102405261026052610280526102a0526102c0526102e05261030052610320526103405261036052610380526103a0526103c0526103e05261040052610420526104405261046052610480526104a0526104c0526104e052610500526105205261054052610560526000610180516020826105c00101526020810190506102c0516020826105c0010152602081019050610400516020826105c0010152602081019050806105c0526105c090508051602082012090506105a0526106606000600a818352015b610660511515156102765760006105a05160208261068001015260208101905061018061066051600a81106101fa57600080fd5b60200201516020826106800101526020810190506102c061066051600a811061022257600080fd5b602002015160208261068001015260208101905061040061066051600a811061024a57600080fd5b6020020151602082610680010152602081019050806106805261068090508051602082012090506105a0525b5b81516001018083528114156101c6575b5050600061014051602082610760010152602081019050610160516020826107600101526020810190506105a0516020826107600101526020810190506105405160208261076001015260208101905061056051602082610760010152602081019050806107605261076090508051602082012090506107405261074051600052600051610580515650005b634a6f823360005114156105c457341561032c57600080fd5b600435602051811061033d57600080fd5b50602435602051811061034f57600080fd5b506000610120525b602061012051016101205261012061012051101561037457610357565b6000610120525b60206101205101610120526101206101205110156103985761037b565b6000610120525b60206101205101610120526101206101205110156103bc5761039f565b6373ad25716101405260043561016052602435610180526101a0604480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250506102e061018480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250506104206102c480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250506104043561056052610424356105805261058051610560516105405161052051610500516104e0516104c0516104a05161048051610460516104405161042051610400516103e0516103c0516103a05161038051610360516103405161032051610300516102e0516102c0516102a05161028051610260516102405161022051610200516101e0516101c0516101a0516101805161016051600658016100dc565b6105e0526105e05160005260206000f350005b600015610909575b610580526101405261016052610180526101a0526101c0526101e05261020052610220526102405261026052610280526102a0526102c0526102e05261030052610320526103405261036052610380526103a0526103c0526103e05261040052610420526104405261046052610480526104a0526104c0526104e052610500526105205261054052610560526000610140516020826105c0010152602081019050610160516020826105c0010152602081019050610180516020826105c00101526020810190506101a0516020826105c00101526020810190506101c0516020826105c00101526020810190506101e0516020826105c0010152602081019050610200516020826105c0010152602081019050610220516020826105c0010152602081019050610240516020826105c0010152602081019050610260516020826105c0010152602081019050610280516020826105c00101526020810190506102a0516020826105c00101526020810190506102c0516020826105c00101526020810190506102e0516020826105c0010152602081019050610300516020826105c0010152602081019050610320516020826105c0010152602081019050610340516020826105c0010152602081019050610360516020826105c0010152602081019050610380516020826105c00101526020810190506103a0516020826105c00101526020810190506103c0516020826105c00101526020810190506103e0516020826105c0010152602081019050610400516020826105c0010152602081019050610420516020826105c0010152602081019050610440516020826105c0010152602081019050610460516020826105c0010152602081019050610480516020826105c00101526020810190506104a0516020826105c00101526020810190506104c0516020826105c00101526020810190506104e0516020826105c0010152602081019050610500516020826105c0010152602081019050610520516020826105c0010152602081019050610540516020826105c0010152602081019050610560516020826105c0010152602081019050806105c0526105c090508051602082012090506105a0526105a051600052600051610580515650005b6000156109e1575b610220526101405261016052610180526101a0526101c0526101e0526102005260006101405160208261026001015260208101905061016051602082610260010152602081019050610180516020826102600101526020810190506101a0516020826102600101526020810190506101c0516020826102600101526020810190506101e05160208261026001015260208101905061020051602082610260010152602081019050806102605261026090508051602082012090506102405261024051600052600051610220515650005b6310660e866000511415610a905734156109fa57600080fd5b6004356020518110610a0b57600080fd5b506024356020518110610a1d57600080fd5b5063155960636101405260043561016052602435610180526044356101a0526064356101c0526084356101e05260a4356102005260c4356102205261022051610200516101e0516101c0516101a051610180516101605160065801610911565b610280526102805160005260206000f350005b600015610cf2575b6101805261014052610160526101a0526000610240525b6101a05160206001820306601f820103905061024051101515610ad157610aea565b610240516101c001526102405160200161024052610aaf565b60005060416101a0511815610b0757600060005260005161018051565b6101a0602060006020835103811315610b1f57600080fd5b046020026020018101519050610280526101a0602060206020835103811315610b4757600080fd5b0460200260200181015190506102a05260406001602082066103a0016101a0518284011115610b7557600080fd5b6041806103c0826020602088068803016101a001600060046018f1505081815280905090509050806020015160008251806020901315610bb457600080fd5b8091901215610bc257600080fd5b606051816020036101000a830480604051901315610bdf57600080fd5b8091901215610bed57600080fd5b9050905090506102c052601b6102c0511215610c30576102c0606051601b82510180604051901315610c1e57600080fd5b8091901215610c2c57600080fd5b8152505b610480601b8152601c81602001525060006104605261046061012060006002818352015b6101205160200261048001516102c0511415610c735760018352610c84565b5b8151600101808352811415610c54575b5050506104605160011415610ce257610140516104c0526102c0516000811215610cad57600080fd5b6104e05261028051610500526102a05161052052602060c060806104c060006001610bb8f15060c05160005260005161018051565b6000600052600051610180515650005b600015610db3575b6101605261014052610140517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff806000811215610d3e578060000360020a8204610d45565b8060020a82025b90509050604051811115610d5857600080fd5b61018052700100000000000000000000000000000000610d7757600080fd5b7001000000000000000000000000000000006101405106604051811115610d9d57600080fd5b6101a05261018051600052600051610160515650005b63f17535506000511415610de8573415610dcc57600080fd5b600060043560e05260c052604060c0205460005260206000f350005b63ac2a2e216000511415610e3d573415610e0157600080fd5b6004356020518110610e1257600080fd5b50600460043560e05260c052604060c02060243560e05260c052604060c0205460005260206000f350005b634026b7556000511415610e72573415610e5657600080fd5b600760043560e05260c052604060c0205460005260206000f350005b63f242432a6000511415611135573415610e8b57600080fd5b6004356020518110610e9c57600080fd5b506024356020518110610eae57600080fd5b5061012060843560040161014037610100608435600401351115610ed157600080fd5b600660043560e05260c052604060c0203360e05260c052604060c02054336004351417610efd57600080fd5b6308c379a06102805260206102a05260206102c0527f43616e6e6f74207472616e7366657220746f207a65726f20616464726573732e6102e0526102c050600060243518610f4c57608461029cfd5b6308c379a0610320526020610340526012610360527f4e6f7420656e6f75676820746f6b656e732e00000000000000000000000000006103805261036050606435600360043560e05260c052604060c02060443560e05260c052604060c020541015610fb957608461033cfd5b600360043560e05260c052604060c02060443560e05260c052604060c02060643581541015610fe757600080fd5b606435815403815550600360243560e05260c052604060c02060443560e05260c052604060c0208054606435825401101561102157600080fd5b6064358154018155506044356103c0526064356103e052602435600435337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6260406103c0a460006024353b1115611133576024353b61107f57600080fd5b602435301861108d57600080fd5b60206106406101c460a063f23a6e6161042052336104405260043561046052604435610480526064356104a052806104c052610140808051602001808461044001828460006004600a8704601201f16110e557600080fd5b50508051820160206001820306601f820103905060200191505061043c905060006024355af161111457600080fd5b600050610640516104005263f23a6e61610400511461113257600080fd5b5b005b63cf36e535600051141561163c57341561114e57600080fd5b600435602051811061115f57600080fd5b50602435602051811061117157600080fd5b506000610120525b602061012051016101205261012061012051101561119657611179565b6000610120525b60206101205101610120526101206101205110156111ba5761119d565b6101206102c435600401610140376101006102c4356004013511156111de57600080fd5b600660043560e05260c052604060c0203360e05260c052604060c0205433600435141761120a57600080fd5b6308c379a06102805260206102a05260206102c0527f43616e6e6f74207472616e7366657220746f207a65726f20616464726573732e6102e0526102c05060006024351861125957608461029cfd5b6103206000600a818352015b604461032051600a811061127857600080fd5b60200201356103405261018461032051600a811061129557600080fd5b6020020135600360043560e05260c052604060c0206103405160e05260c052604060c0205410156112c557600080fd5b5b8151600101808352811415611265575b505060443561036052606435610380526084356103a05260a4356103c05260c4356103e05260e435610400526101043561042052610124356104405261014435610460526101643561048052610184356104a0526101a4356104c0526101c4356104e0526101e435610500526102043561052052610224356105405261024435610560526102643561058052610284356105a0526102a4356105c052602435600435337f514c24e4790d7c31a095a1688a73a01f28d936a9a85d806ba95970d8ee88efa8610280610360a46105e06000600a818352015b60446105e051600a81106113c057600080fd5b602002013561060052600360043560e05260c052604060c0206106005160e05260c052604060c0206101846105e051600a81106113fc57600080fd5b60200201358154101561140e57600080fd5b6101846105e051600a811061142257600080fd5b6020020135815403815550600360243560e05260c052604060c0206106005160e05260c052604060c02080546101846105e051600a811061146257600080fd5b6020020135825401101561147557600080fd5b6101846105e051600a811061148957600080fd5b60200201358154018155505b81516001018083528114156113ad575b505060006024353b111561163a576024353b6114c057600080fd5b60243530186114ce57600080fd5b6020610aa06104046102e063a3bfc206610640523361066052600435610680526106a0604480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250506107e061018480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250508061092052610140808051602001808461066001828460006004600a8704601201f16115ec57600080fd5b50508051820160206001820306601f820103905060200191505061065c905060006024355af161161b57600080fd5b600050610aa0516106205263e324a00d610620511461163957600080fd5b5b005b62fdd58e600051141561169057341561165457600080fd5b600435602051811061166557600080fd5b50600360043560e05260c052604060c02060243560e05260c052604060c0205460005260206000f350005b63fbe31aea60005114156117935734156116a957600080fd5b6000610120525b610120516004013560205181106116c657600080fd5b5060206101205101610120526101206101205110156116e4576116b0565b6000610120525b6020610120510161012052610120610120511015611708576116eb565b6102806000600a818352015b6003600461028051600a811061172957600080fd5b602002013560e05260c052604060c02061014461028051600a811061174d57600080fd5b602002013560e05260c052604060c0205461014061028051600a811061177257600080fd5b60200201525b8151600101808352811415611714575b5050610140610140f3005b63a22cb46560005114156118235734156117ac57600080fd5b60043560205181106117bd57600080fd5b50602435600281106117ce57600080fd5b5060243560063360e05260c052604060c02060043560e05260c052604060c0205560243561014052600435337f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c316020610140a3005b63e985e9c5600051141561188a57341561183c57600080fd5b600435602051811061184d57600080fd5b50602435602051811061185f57600080fd5b50600660043560e05260c052604060c02060243560e05260c052604060c0205460005260206000f350005b63a70b070f6000511415611af85734156118a357600080fd5b60043560205181106118b457600080fd5b50610120604435600401610140376101006044356004013511156118d757600080fd5b6000600435186118e657600080fd5b6308c379a06102805260206102a052601b6102c0527f4f776e6572206f6e6c792063616e20637265617465206974656d2e00000000006102e0526102c050336002541461193457608461029cfd5b6000600360043560e05260c052604060c02060243560e05260c052604060c02055600180546001825401101561196957600080fd5b60018154018155506001600760243560e05260c052604060c0205561014080600560243560e05260c052604060c02060c052602060c020602082510161012060006009818352015b826101205160200211156119c4576119e6565b61012051602002850151610120518501555b81516001018083528114156119b1575b50505050505060206103405261034051610380526101408051602001806103405161038001828460006004600a8704601201f1611a2257600080fd5b5050610320610340516103800151610440818352015b610440610320511115611a4a57611a6b565b600061032051610340516103a00101535b8151600101808352811415611a38575b5050602061034051610380015160206001820306601f8201039050610340510101610340526024357f6bb7ff708619ba0610cba295a58592e0451dee2622938c8755667688daf3529b61034051610380a26024356103a05260006103c0526004356000337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6260406103a0a4005b6319a35d7c6000511415611d43573415611b1157600080fd5b6004356020518110611b2257600080fd5b506000610120525b6020610120510161012052610120610120511015611b4757611b2a565b600060043518611b5657600080fd5b6308c379a061014052602061016052601c610180527f4f776e6572206f6e6c792063616e20637265617465206974656d732e000000006101a052610180503360025414611ba457608461015cfd5b6101e06000600a818352015b60246101e051600a8110611bc357600080fd5b6020020135610200526000600360043560e05260c052604060c0206102005160e05260c052604060c020556001805460018254011015611c0257600080fd5b6001815401815550600160076102005160e05260c052604060c020555b8151600101808352811415611bb0575b5050610220600081526000816020015260008160400152600081606001526000816080015260008160a0015260008160c0015260008160e00152600081610100015260008161012001525060243561036052604435610380526064356103a0526084356103c05260a4356103e05260c4356104005260e43561042052610104356104405261012435610460526101443561048052610220516104a052610240516104c052610260516104e05261028051610500526102a051610520526102c051610540526102e051610560526103005161058052610320516105a052610340516105c0526004356000337f514c24e4790d7c31a095a1688a73a01f28d936a9a85d806ba95970d8ee88efa8610280610360a4005b63156e29f66000511415611d8157600061028052610280805160200180610140828460006004600a8704601201f1611d7a57600080fd5b5050611dce565b63731133e96000511415611dc65761012060643560040161014037610100606435600401351115611db157600080fd5b61014060643560040161014037600050611dce565b60001561208a575b3415611dd957600080fd5b6004356020518110611dea57600080fd5b50600060043518611dfa57600080fd5b6308c379a06102c05260206102e052601a610300527f4f776e6572206f6e6c792063616e206d696e74206974656d732e00000000000061032052610300503360025414611e485760846102dcfd5b610140610380525b61038051516020610380510161038052610380610380511015611e7257611e50565b6320171bef6103a0526024356103c0526103c05160065801610cfa565b61042052610360610380525b6103805152602061038051036103805261014061038051101515611ebe57611e9b565b6104205161036052600261036051146001610360511417611ede57600080fd5b6001610360511415611f5f576308c379a0610440526020610460526028610480527f43616e6e6f74206d696e74204e46542077697468205f737570706c79206d6f726104a0527f65207468616e20310000000000000000000000000000000000000000000000006104c05261048050600160443514611f5e5760a461045cfd5b5b604435600360043560e05260c052604060c02060243560e05260c052604060c0205560243561050052604435610520526004356000337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f626040610500a460006004353b1115612088576004353b611fd557600080fd5b6004353018611fe357600080fd5b60206107806101c460a063f23a6e6161056052336105805260006105a0526024356105c0526044356105e0528061060052610140808051602001808461058001828460006004600a8704601201f161203a57600080fd5b50508051820160206001820306601f820103905060200191505061057c905060006004355af161206957600080fd5b600050610780516105405263f23a6e61610540511461208757600080fd5b5b005b63c671854d60005114156120c857600061028052610280805160200180610140828460006004600a8704601201f16120c157600080fd5b5050612118565b63b07e58756000511415612110576101206102a435600401610140376101006102a4356004013511156120fa57600080fd5b6101406102a43560040161014037600050612118565b6000156124f6575b341561212357600080fd5b600435602051811061213457600080fd5b506000610120525b60206101205101610120526101206101205110156121595761213c565b6000610120525b602061012051016101205261012061012051101561217d57612160565b60006004351861218c57600080fd5b6308c379a06102c05260206102e052601a610300527f4f776e6572206f6e6c792063616e206d696e74206974656d732e000000000000610320526103005033600254146121da5760846102dcfd5b6103606000600a818352015b602461036051600a81106121f957600080fd5b6020020135610380526101406103c0525b6103c0515160206103c051016103c0526103c06103c051101561222c5761220a565b6320171bef6103e05261038051610400526104005160065801610cfa565b610460526103a06103c0525b6103c0515260206103c051036103c0526101406103c05110151561227957612256565b610460516103a05260026103a0511460016103a051141761229957600080fd5b60016103a05114156122cb57600161016461036051600a81106122bb57600080fd5b6020020135146122ca57600080fd5b5b61016461036051600a81106122df57600080fd5b6020020135600360043560e05260c052604060c0206103805160e05260c052604060c020555b81516001018083528114156121e6575b5050602435610480526044356104a0526064356104c0526084356104e05260a4356105005260c4356105205260e4356105405261010435610560526101243561058052610144356105a052610164356105c052610184356105e0526101a435610600526101c435610620526101e4356106405261020435610660526102243561068052610244356106a052610264356106c052610284356106e0526004356000337f514c24e4790d7c31a095a1688a73a01f28d936a9a85d806ba95970d8ee88efa8610280610480a46107006000600a818352015b60006004353b11156124e1576004353b61240357600080fd5b600435301861241157600080fd5b60206109606101c460a063f23a6e61610740523361076052600061078052602461070051600a811061244257600080fd5b60200201356107a05261016461070051600a811061245f57600080fd5b60200201356107c052806107e052610140808051602001808461076001828460006004600a8704601201f161249357600080fd5b50508051820160206001820306601f820103905060200191505061075c905060006004355af16124c257600080fd5b600050610960516107205263f23a6e6161072051146124e057600080fd5b5b5b81516001018083528114156123ea575b5050005b63b390c0ab60005114156125ea57341561250f57600080fd5b6308c379a061014052602061016052601a610180527f4e6f7420656e6f75676820746f6b656e7320746f206275726e2e0000000000006101a0526101805060243560033360e05260c052604060c02060043560e05260c052604060c02054101561257a57608461015cfd5b60033360e05260c052604060c02060043560e05260c052604060c020602435815410156125a657600080fd5b6024358154038155506004356101e05260243561020052600033337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6260406101e0a4005b63b59afe52600051141561282b57341561260357600080fd5b6000610120525b60206101205101610120526101206101205110156126275761260a565b6000610120525b602061012051016101205261012061012051101561264b5761262e565b6101406000600a818352015b600461014051600a811061266a57600080fd5b60200201356101605261014461014051600a811061268757600080fd5b602002013560033360e05260c052604060c0206101605160e05260c052604060c0205410156126b557600080fd5b5b8151600101808352811415612657575b50506101806000600a818352015b600461018051600a81106126e757600080fd5b60200201356101a05260033360e05260c052604060c0206101a05160e05260c052604060c02061014461018051600a811061272157600080fd5b60200201358154101561273357600080fd5b61014461018051600a811061274757600080fd5b60200201358154038155505b81516001018083528114156126d4575b50506004356101c0526024356101e05260443561020052606435610220526084356102405260a4356102605260c4356102805260e4356102a052610104356102c052610124356102e0526101443561030052610164356103205261018435610340526101a435610360526101c435610380526101e4356103a052610204356103c052610224356103e05261024435610400526102643561042052600033337f514c24e4790d7c31a095a1688a73a01f28d936a9a85d806ba95970d8ee88efa86102806101c0a4005b63f2526ada6000511415612869576000610320526103208051602001806101e0828460006004600a8704601201f161286257600080fd5b50506128b9565b63a835c36960005114156128b157610120610464356004016101e0376101006104643560040135111561289b57600080fd5b610140610464356004016101e0376000506128b9565b600015613725575b60043560205181106128ca57600080fd5b5060243560205181106128dc57600080fd5b506000610120525b6020610120510161012052610120610120511015612901576128e4565b6000610120525b602061012051016101205261012061012051101561292557612908565b6000610120525b60206101205101610120526101206101205110156129495761292c565b6061610444356004016101403760416104443560040135111561296b57600080fd5b6308c379a061036052602061038052602c6103a0527f5f66726f6d206d757374206265207468652073656e646572206f7220617070726103c0527f6f766564206164647265737300000000000000000000000000000000000000006103e0526103a050600660043560e05260c052604060c0203360e05260c052604060c020543360043514176129fc5760a461037cfd5b6308c379a0610420526020610440526025610460527f44657374696e6174696f6e2061646472657373206d757374206265206e6f6e2d610480527f7a65726f2e0000000000000000000000000000000000000000000000000000006104a05261046050600060243518612a705760a461043cfd5b6308c379a06104e0526020610500526015610520527f4e6f6e6365206d75737420626520756e757365642e00000000000000000000006105405261052050600460043560e05260c052604060c0206104243560e05260c052604060c0205415612ada5760846104fcfd5b6308c379a06105805260206105a05260256105c0527f53656e64657220686173206e6f742070726f766964656420656e6f75676820656105e0527f746865722e000000000000000000000000000000000000000000000000000000610600526105c050346104043514612b4e5760a461059cfd5b6106406000600a818352015b604461064051600a8110612b6d57600080fd5b602002013561066052600061018461064051600a8110612b8c57600080fd5b60200201351115612c03576102c461064051600a8110612bab57600080fd5b602002013515612bba57600080fd5b61018461064051600a8110612bce57600080fd5b6020020135600360043560e05260c052604060c0206106605160e05260c052604060c020541015612bfe57600080fd5b612c6b565b61018461064051600a8110612c1757600080fd5b602002013515612c2657600080fd5b6102c461064051600a8110612c3a57600080fd5b6020020135600360243560e05260c052604060c0206106605160e05260c052604060c020541015612c6a57600080fd5b5b5b8151600101808352811415612b5a575b50506101406106a0525b6106a0515160206106a051016106a0526106a06106a0511015612ca857612c86565b6373ad25716106c0526004356106e05260243561070052610720604480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e00152806101000135826101000152806101200135826101200152505061086061018480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250506109a06102c480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e00152806101000135826101000152806101200135826101200152505061040435610ae05261042435610b0052610b0051610ae051610ac051610aa051610a8051610a6051610a4051610a2051610a00516109e0516109c0516109a05161098051610960516109405161092051610900516108e0516108c0516108a05161088051610860516108405161082051610800516107e0516107c0516107a05161078051610760516107405161072051610700516106e051600658016100dc565b610b60526106806106a0525b6106a0515260206106a051036106a0526101406106a051101515612ecc57612ea9565b610b605161068052610140610ba0525b610ba051516020610ba05101610ba052610ba0610ba0511015612efe57612edc565b6040636f868168610bc05261068051610be05280610c00526101408080516020018084610be001828460006004600a8704601201f1612f3c57600080fd5b50508051820160206001820306601f820103905060200191505050610c005180610be00180518060206001820306601f82010390508201610ce0525050505b610c20610ce0511015612f8d57612fa2565b610ce051516020610ce05103610ce052612f7b565b610c0051610be05160065801610a98565b610d0052610b80610ba0525b610ba051526020610ba05103610ba052610140610ba051101515612fe257612fbf565b610d0051610b80526308c379a0610d20526020610d40526020610d60527f5369676e657220646f6573206e6f74206d61746368207369676e61747572652e610d8052610d6050602435610b80511461303b576084610d3cfd5b600160043360e05260c052604060c0206104243560e05260c052604060c02055610dc06000600a818352015b6044610dc051600a811061307a57600080fd5b6020020135610de0526000610184610dc051600a811061309957600080fd5b6020020135111561317457600360043560e05260c052604060c020610de05160e05260c052604060c020610184610dc051600a81106130d757600080fd5b6020020135815410156130e957600080fd5b610184610dc051600a81106130fd57600080fd5b6020020135815403815550600360243560e05260c052604060c020610de05160e05260c052604060c0208054610184610dc051600a811061313d57600080fd5b6020020135825401101561315057600080fd5b610184610dc051600a811061316457600080fd5b6020020135815401815550613240565b600360043560e05260c052604060c020610de05160e05260c052604060c02080546102c4610dc051600a81106131a957600080fd5b602002013582540110156131bc57600080fd5b6102c4610dc051600a81106131d057600080fd5b6020020135815401815550600360243560e05260c052604060c020610de05160e05260c052604060c0206102c4610dc051600a811061320e57600080fd5b60200201358154101561322057600080fd5b6102c4610dc051600a811061323457600080fd5b60200201358154038155505b5b8151600101808352811415613067575b50506000600060006000346024356000f161326b57600080fd5b604435610e0052606435610e2052608435610e405260a435610e605260c435610e805260e435610ea05261010435610ec05261012435610ee05261014435610f005261016435610f205261018435610f40526101a435610f60526101c435610f80526101e435610fa05261020435610fc05261022435610fe0526102443561100052610264356110205261028435611040526102a43561106052602435600435337f514c24e4790d7c31a095a1688a73a01f28d936a9a85d806ba95970d8ee88efa8610280610e00a4604435611080526064356110a0526084356110c05260a4356110e05260c4356111005260e43561112052610104356111405261012435611160526101443561118052610164356111a0526102c4356111c0526102e4356111e052610304356112005261032435611220526103443561124052610364356112605261038435611280526103a4356112a0526103c4356112c0526103e4356112e052600435602435337f514c24e4790d7c31a095a1688a73a01f28d936a9a85d806ba95970d8ee88efa8610280611080a460006024353b1115613590576024353b61341657600080fd5b602435301861342457600080fd5b60206117806104046102e063a3bfc20661132052336113405260243561136052611380604480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250506114c061018480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e00152806101000135826101000152806101200135826101200152505080611600526101e0808051602001808461134001828460006004600a8704601201f161354257600080fd5b50508051820160206001820306601f820103905060200191505061133c905060006024355af161357157600080fd5b6000506117805161130052630c97e564611300511461358f57600080fd5b5b60006004353b1115613723576004353b6135a957600080fd5b60043530186135b757600080fd5b6020611c206104046102e063a3bfc2066117c052336117e05260043561180052611820604480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250506119606102c480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e00152806101000135826101000152806101200135826101200152505080611aa0526101e080805160200180846117e001828460006004600a8704601201f16136d557600080fd5b50508051820160206001820306601f82010390506020019150506117dc905060006004355af161370457600080fd5b600050611c20516117a052630c97e5646117a0511461372257600080fd5b5b005b636e8205b26000511415613763576000610320526103208051602001806101e0828460006004600a8704601201f161375c57600080fd5b50506137b3565b63183f5ec560005114156137ab57610120610104356004016101e0376101006101043560040135111561379557600080fd5b610140610104356004016101e0376000506137b3565b600015613f5d575b60043560205181106137c457600080fd5b5060243560205181106137d657600080fd5b50606160e43560040161014037604160e4356004013511156137f757600080fd5b600660043560e05260c052604060c0203360e05260c052604060c0205433600435141761382357600080fd5b6308c379a06103605260206103805260256103a0527f44657374696e6174696f6e2061646472657373206d757374206265206e6f6e2d6103c0527f7a65726f2e0000000000000000000000000000000000000000000000000000006103e0526103a0506000602435186138975760a461037cfd5b6308c379a0610420526020610440526015610460527f4e6f6e6365206d75737420626520756e757365642e00000000000000000000006104805261046050600460043560e05260c052604060c02060c43560e05260c052604060c020541561390057608461043cfd5b6308c379a06104c05260206104e0526025610500527f53656e64657220686173206e6f742070726f766964656420656e6f7567682065610520527f746865722e00000000000000000000000000000000000000000000000000000061054052610500503460a435146139735760a46104dcfd5b600060643511156139bd576084351561398b57600080fd5b606435600360043560e05260c052604060c02060443560e05260c052604060c0205410156139b857600080fd5b6139f8565b606435156139ca57600080fd5b608435600360243560e05260c052604060c02060443560e05260c052604060c0205410156139f757600080fd5b5b6101406105a0525b6105a0515160206105a051016105a0526105a06105a0511015613a2257613a00565b63155960636105c0526004356105e0526024356106005260443561062052606435610640526084356106605260a4356106805260c4356106a0526106a05161068051610660516106405161062051610600516105e05160065801610911565b610700526105806105a0525b6105a0515260206105a051036105a0526101406105a051101515613ab057613a8d565b6107005161058052610140610740525b61074051516020610740510161074052610740610740511015613ae257613ac0565b6040636f868168610760526105805161078052806107a052610140808051602001808461078001828460006004600a8704601201f1613b2057600080fd5b50508051820160206001820306601f8201039050602001915050506107a051806107800180518060206001820306601f82010390508201610880525050505b6107c0610880511015613b7157613b86565b61088051516020610880510361088052613b5f565b6107a0516107805160065801610a98565b6108a052610720610740525b6107405152602061074051036107405261014061074051101515613bc657613ba3565b6108a051610720526308c379a06108c05260206108e0526020610900527f5369676e657220646f6573206e6f74206d61746368207369676e61747572652e61092052610900506024356107205114613c1f5760846108dcfd5b600160043360e05260c052604060c02060c43560e05260c052604060c0205560006064351115613cbf57600360043560e05260c052604060c02060443560e05260c052604060c02060643581541015613c7757600080fd5b606435815403815550600360243560e05260c052604060c02060443560e05260c052604060c02080546064358254011015613cb157600080fd5b606435815401815550613d31565b600360043560e05260c052604060c02060443560e05260c052604060c02080546084358254011015613cf057600080fd5b608435815401815550600360243560e05260c052604060c02060443560e05260c052604060c02060843581541015613d2757600080fd5b6084358154038155505b6000600060006000346024356000f1613d4957600080fd5b6044356109605260643561098052602435600435337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f626040610960a46044356109a0526084356109c052600435602435337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6260406109a0a460006024353b1115613e8e576024353b613dda57600080fd5b6024353018613de857600080fd5b6020610c206101c460a063f23a6e61610a005233610a2052602435610a4052604435610a6052606435610a805280610aa0526101e08080516020018084610a2001828460006004600a8704601201f1613e4057600080fd5b50508051820160206001820306601f8201039050602001915050610a1c905060006024355af1613e6f57600080fd5b600050610c20516109e052630c97e5646109e05114613e8d57600080fd5b5b60006004353b1115613f5b576004353b613ea757600080fd5b6004353018613eb557600080fd5b6020610e806101c460a063f23a6e61610c605233610c8052600435610ca052604435610cc052608435610ce05280610d00526101e08080516020018084610c8001828460006004600a8704601201f1613f0d57600080fd5b50508051820160206001820306601f8201039050602001915050610c7c905060006004355af1613f3c57600080fd5b600050610e8051610c4052630c97e564610c405114613f5a57600080fd5b5b005b638da5cb5b6000511415613f84573415613f7657600080fd5b60025460005260206000f350005b60006000fd5b6100d061405a036100d06000396100d061405a036000f3\",\n  \"deployedBytecode\": \"0x600035601c52740100000000000000000000000000000000000000006020526f7fffffffffffffffffffffffffffffff6040527fffffffffffffffffffffffffffffffff8000000000000000000000000000000060605274012a05f1fffffffffffffffffffffffffdabf41c006080527ffffffffffffffffffffffffed5fa0e000000000000000000000000000000000060a05263ae22c57d60005114156100d45734156100ac57600080fd5b60043560205181106100bd57600080fd5b50600435610140526101405160005260206000f350005b600015610313575b610580526101405261016052610180526101a0526101c0526101e05261020052610220526102405261026052610280526102a0526102c0526102e05261030052610320526103405261036052610380526103a0526103c0526103e05261040052610420526104405261046052610480526104a0526104c0526104e052610500526105205261054052610560526000610180516020826105c00101526020810190506102c0516020826105c0010152602081019050610400516020826105c0010152602081019050806105c0526105c090508051602082012090506105a0526106606000600a818352015b610660511515156102765760006105a05160208261068001015260208101905061018061066051600a81106101fa57600080fd5b60200201516020826106800101526020810190506102c061066051600a811061022257600080fd5b602002015160208261068001015260208101905061040061066051600a811061024a57600080fd5b6020020151602082610680010152602081019050806106805261068090508051602082012090506105a0525b5b81516001018083528114156101c6575b5050600061014051602082610760010152602081019050610160516020826107600101526020810190506105a0516020826107600101526020810190506105405160208261076001015260208101905061056051602082610760010152602081019050806107605261076090508051602082012090506107405261074051600052600051610580515650005b634a6f823360005114156105c457341561032c57600080fd5b600435602051811061033d57600080fd5b50602435602051811061034f57600080fd5b506000610120525b602061012051016101205261012061012051101561037457610357565b6000610120525b60206101205101610120526101206101205110156103985761037b565b6000610120525b60206101205101610120526101206101205110156103bc5761039f565b6373ad25716101405260043561016052602435610180526101a0604480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250506102e061018480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250506104206102c480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250506104043561056052610424356105805261058051610560516105405161052051610500516104e0516104c0516104a05161048051610460516104405161042051610400516103e0516103c0516103a05161038051610360516103405161032051610300516102e0516102c0516102a05161028051610260516102405161022051610200516101e0516101c0516101a0516101805161016051600658016100dc565b6105e0526105e05160005260206000f350005b600015610909575b610580526101405261016052610180526101a0526101c0526101e05261020052610220526102405261026052610280526102a0526102c0526102e05261030052610320526103405261036052610380526103a0526103c0526103e05261040052610420526104405261046052610480526104a0526104c0526104e052610500526105205261054052610560526000610140516020826105c0010152602081019050610160516020826105c0010152602081019050610180516020826105c00101526020810190506101a0516020826105c00101526020810190506101c0516020826105c00101526020810190506101e0516020826105c0010152602081019050610200516020826105c0010152602081019050610220516020826105c0010152602081019050610240516020826105c0010152602081019050610260516020826105c0010152602081019050610280516020826105c00101526020810190506102a0516020826105c00101526020810190506102c0516020826105c00101526020810190506102e0516020826105c0010152602081019050610300516020826105c0010152602081019050610320516020826105c0010152602081019050610340516020826105c0010152602081019050610360516020826105c0010152602081019050610380516020826105c00101526020810190506103a0516020826105c00101526020810190506103c0516020826105c00101526020810190506103e0516020826105c0010152602081019050610400516020826105c0010152602081019050610420516020826105c0010152602081019050610440516020826105c0010152602081019050610460516020826105c0010152602081019050610480516020826105c00101526020810190506104a0516020826105c00101526020810190506104c0516020826105c00101526020810190506104e0516020826105c0010152602081019050610500516020826105c0010152602081019050610520516020826105c0010152602081019050610540516020826105c0010152602081019050610560516020826105c0010152602081019050806105c0526105c090508051602082012090506105a0526105a051600052600051610580515650005b6000156109e1575b610220526101405261016052610180526101a0526101c0526101e0526102005260006101405160208261026001015260208101905061016051602082610260010152602081019050610180516020826102600101526020810190506101a0516020826102600101526020810190506101c0516020826102600101526020810190506101e05160208261026001015260208101905061020051602082610260010152602081019050806102605261026090508051602082012090506102405261024051600052600051610220515650005b6310660e866000511415610a905734156109fa57600080fd5b6004356020518110610a0b57600080fd5b506024356020518110610a1d57600080fd5b5063155960636101405260043561016052602435610180526044356101a0526064356101c0526084356101e05260a4356102005260c4356102205261022051610200516101e0516101c0516101a051610180516101605160065801610911565b610280526102805160005260206000f350005b600015610cf2575b6101805261014052610160526101a0526000610240525b6101a05160206001820306601f820103905061024051101515610ad157610aea565b610240516101c001526102405160200161024052610aaf565b60005060416101a0511815610b0757600060005260005161018051565b6101a0602060006020835103811315610b1f57600080fd5b046020026020018101519050610280526101a0602060206020835103811315610b4757600080fd5b0460200260200181015190506102a05260406001602082066103a0016101a0518284011115610b7557600080fd5b6041806103c0826020602088068803016101a001600060046018f1505081815280905090509050806020015160008251806020901315610bb457600080fd5b8091901215610bc257600080fd5b606051816020036101000a830480604051901315610bdf57600080fd5b8091901215610bed57600080fd5b9050905090506102c052601b6102c0511215610c30576102c0606051601b82510180604051901315610c1e57600080fd5b8091901215610c2c57600080fd5b8152505b610480601b8152601c81602001525060006104605261046061012060006002818352015b6101205160200261048001516102c0511415610c735760018352610c84565b5b8151600101808352811415610c54575b5050506104605160011415610ce257610140516104c0526102c0516000811215610cad57600080fd5b6104e05261028051610500526102a05161052052602060c060806104c060006001610bb8f15060c05160005260005161018051565b6000600052600051610180515650005b600015610db3575b6101605261014052610140517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff806000811215610d3e578060000360020a8204610d45565b8060020a82025b90509050604051811115610d5857600080fd5b61018052700100000000000000000000000000000000610d7757600080fd5b7001000000000000000000000000000000006101405106604051811115610d9d57600080fd5b6101a05261018051600052600051610160515650005b63f17535506000511415610de8573415610dcc57600080fd5b600060043560e05260c052604060c0205460005260206000f350005b63ac2a2e216000511415610e3d573415610e0157600080fd5b6004356020518110610e1257600080fd5b50600460043560e05260c052604060c02060243560e05260c052604060c0205460005260206000f350005b634026b7556000511415610e72573415610e5657600080fd5b600760043560e05260c052604060c0205460005260206000f350005b63f242432a6000511415611135573415610e8b57600080fd5b6004356020518110610e9c57600080fd5b506024356020518110610eae57600080fd5b5061012060843560040161014037610100608435600401351115610ed157600080fd5b600660043560e05260c052604060c0203360e05260c052604060c02054336004351417610efd57600080fd5b6308c379a06102805260206102a05260206102c0527f43616e6e6f74207472616e7366657220746f207a65726f20616464726573732e6102e0526102c050600060243518610f4c57608461029cfd5b6308c379a0610320526020610340526012610360527f4e6f7420656e6f75676820746f6b656e732e00000000000000000000000000006103805261036050606435600360043560e05260c052604060c02060443560e05260c052604060c020541015610fb957608461033cfd5b600360043560e05260c052604060c02060443560e05260c052604060c02060643581541015610fe757600080fd5b606435815403815550600360243560e05260c052604060c02060443560e05260c052604060c0208054606435825401101561102157600080fd5b6064358154018155506044356103c0526064356103e052602435600435337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6260406103c0a460006024353b1115611133576024353b61107f57600080fd5b602435301861108d57600080fd5b60206106406101c460a063f23a6e6161042052336104405260043561046052604435610480526064356104a052806104c052610140808051602001808461044001828460006004600a8704601201f16110e557600080fd5b50508051820160206001820306601f820103905060200191505061043c905060006024355af161111457600080fd5b600050610640516104005263f23a6e61610400511461113257600080fd5b5b005b63cf36e535600051141561163c57341561114e57600080fd5b600435602051811061115f57600080fd5b50602435602051811061117157600080fd5b506000610120525b602061012051016101205261012061012051101561119657611179565b6000610120525b60206101205101610120526101206101205110156111ba5761119d565b6101206102c435600401610140376101006102c4356004013511156111de57600080fd5b600660043560e05260c052604060c0203360e05260c052604060c0205433600435141761120a57600080fd5b6308c379a06102805260206102a05260206102c0527f43616e6e6f74207472616e7366657220746f207a65726f20616464726573732e6102e0526102c05060006024351861125957608461029cfd5b6103206000600a818352015b604461032051600a811061127857600080fd5b60200201356103405261018461032051600a811061129557600080fd5b6020020135600360043560e05260c052604060c0206103405160e05260c052604060c0205410156112c557600080fd5b5b8151600101808352811415611265575b505060443561036052606435610380526084356103a05260a4356103c05260c4356103e05260e435610400526101043561042052610124356104405261014435610460526101643561048052610184356104a0526101a4356104c0526101c4356104e0526101e435610500526102043561052052610224356105405261024435610560526102643561058052610284356105a0526102a4356105c052602435600435337f514c24e4790d7c31a095a1688a73a01f28d936a9a85d806ba95970d8ee88efa8610280610360a46105e06000600a818352015b60446105e051600a81106113c057600080fd5b602002013561060052600360043560e05260c052604060c0206106005160e05260c052604060c0206101846105e051600a81106113fc57600080fd5b60200201358154101561140e57600080fd5b6101846105e051600a811061142257600080fd5b6020020135815403815550600360243560e05260c052604060c0206106005160e05260c052604060c02080546101846105e051600a811061146257600080fd5b6020020135825401101561147557600080fd5b6101846105e051600a811061148957600080fd5b60200201358154018155505b81516001018083528114156113ad575b505060006024353b111561163a576024353b6114c057600080fd5b60243530186114ce57600080fd5b6020610aa06104046102e063a3bfc206610640523361066052600435610680526106a0604480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250506107e061018480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250508061092052610140808051602001808461066001828460006004600a8704601201f16115ec57600080fd5b50508051820160206001820306601f820103905060200191505061065c905060006024355af161161b57600080fd5b600050610aa0516106205263e324a00d610620511461163957600080fd5b5b005b62fdd58e600051141561169057341561165457600080fd5b600435602051811061166557600080fd5b50600360043560e05260c052604060c02060243560e05260c052604060c0205460005260206000f350005b63fbe31aea60005114156117935734156116a957600080fd5b6000610120525b610120516004013560205181106116c657600080fd5b5060206101205101610120526101206101205110156116e4576116b0565b6000610120525b6020610120510161012052610120610120511015611708576116eb565b6102806000600a818352015b6003600461028051600a811061172957600080fd5b602002013560e05260c052604060c02061014461028051600a811061174d57600080fd5b602002013560e05260c052604060c0205461014061028051600a811061177257600080fd5b60200201525b8151600101808352811415611714575b5050610140610140f3005b63a22cb46560005114156118235734156117ac57600080fd5b60043560205181106117bd57600080fd5b50602435600281106117ce57600080fd5b5060243560063360e05260c052604060c02060043560e05260c052604060c0205560243561014052600435337f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c316020610140a3005b63e985e9c5600051141561188a57341561183c57600080fd5b600435602051811061184d57600080fd5b50602435602051811061185f57600080fd5b50600660043560e05260c052604060c02060243560e05260c052604060c0205460005260206000f350005b63a70b070f6000511415611af85734156118a357600080fd5b60043560205181106118b457600080fd5b50610120604435600401610140376101006044356004013511156118d757600080fd5b6000600435186118e657600080fd5b6308c379a06102805260206102a052601b6102c0527f4f776e6572206f6e6c792063616e20637265617465206974656d2e00000000006102e0526102c050336002541461193457608461029cfd5b6000600360043560e05260c052604060c02060243560e05260c052604060c02055600180546001825401101561196957600080fd5b60018154018155506001600760243560e05260c052604060c0205561014080600560243560e05260c052604060c02060c052602060c020602082510161012060006009818352015b826101205160200211156119c4576119e6565b61012051602002850151610120518501555b81516001018083528114156119b1575b50505050505060206103405261034051610380526101408051602001806103405161038001828460006004600a8704601201f1611a2257600080fd5b5050610320610340516103800151610440818352015b610440610320511115611a4a57611a6b565b600061032051610340516103a00101535b8151600101808352811415611a38575b5050602061034051610380015160206001820306601f8201039050610340510101610340526024357f6bb7ff708619ba0610cba295a58592e0451dee2622938c8755667688daf3529b61034051610380a26024356103a05260006103c0526004356000337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6260406103a0a4005b6319a35d7c6000511415611d43573415611b1157600080fd5b6004356020518110611b2257600080fd5b506000610120525b6020610120510161012052610120610120511015611b4757611b2a565b600060043518611b5657600080fd5b6308c379a061014052602061016052601c610180527f4f776e6572206f6e6c792063616e20637265617465206974656d732e000000006101a052610180503360025414611ba457608461015cfd5b6101e06000600a818352015b60246101e051600a8110611bc357600080fd5b6020020135610200526000600360043560e05260c052604060c0206102005160e05260c052604060c020556001805460018254011015611c0257600080fd5b6001815401815550600160076102005160e05260c052604060c020555b8151600101808352811415611bb0575b5050610220600081526000816020015260008160400152600081606001526000816080015260008160a0015260008160c0015260008160e00152600081610100015260008161012001525060243561036052604435610380526064356103a0526084356103c05260a4356103e05260c4356104005260e43561042052610104356104405261012435610460526101443561048052610220516104a052610240516104c052610260516104e05261028051610500526102a051610520526102c051610540526102e051610560526103005161058052610320516105a052610340516105c0526004356000337f514c24e4790d7c31a095a1688a73a01f28d936a9a85d806ba95970d8ee88efa8610280610360a4005b63156e29f66000511415611d8157600061028052610280805160200180610140828460006004600a8704601201f1611d7a57600080fd5b5050611dce565b63731133e96000511415611dc65761012060643560040161014037610100606435600401351115611db157600080fd5b61014060643560040161014037600050611dce565b60001561208a575b3415611dd957600080fd5b6004356020518110611dea57600080fd5b50600060043518611dfa57600080fd5b6308c379a06102c05260206102e052601a610300527f4f776e6572206f6e6c792063616e206d696e74206974656d732e00000000000061032052610300503360025414611e485760846102dcfd5b610140610380525b61038051516020610380510161038052610380610380511015611e7257611e50565b6320171bef6103a0526024356103c0526103c05160065801610cfa565b61042052610360610380525b6103805152602061038051036103805261014061038051101515611ebe57611e9b565b6104205161036052600261036051146001610360511417611ede57600080fd5b6001610360511415611f5f576308c379a0610440526020610460526028610480527f43616e6e6f74206d696e74204e46542077697468205f737570706c79206d6f726104a0527f65207468616e20310000000000000000000000000000000000000000000000006104c05261048050600160443514611f5e5760a461045cfd5b5b604435600360043560e05260c052604060c02060243560e05260c052604060c0205560243561050052604435610520526004356000337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f626040610500a460006004353b1115612088576004353b611fd557600080fd5b6004353018611fe357600080fd5b60206107806101c460a063f23a6e6161056052336105805260006105a0526024356105c0526044356105e0528061060052610140808051602001808461058001828460006004600a8704601201f161203a57600080fd5b50508051820160206001820306601f820103905060200191505061057c905060006004355af161206957600080fd5b600050610780516105405263f23a6e61610540511461208757600080fd5b5b005b63c671854d60005114156120c857600061028052610280805160200180610140828460006004600a8704601201f16120c157600080fd5b5050612118565b63b07e58756000511415612110576101206102a435600401610140376101006102a4356004013511156120fa57600080fd5b6101406102a43560040161014037600050612118565b6000156124f6575b341561212357600080fd5b600435602051811061213457600080fd5b506000610120525b60206101205101610120526101206101205110156121595761213c565b6000610120525b602061012051016101205261012061012051101561217d57612160565b60006004351861218c57600080fd5b6308c379a06102c05260206102e052601a610300527f4f776e6572206f6e6c792063616e206d696e74206974656d732e000000000000610320526103005033600254146121da5760846102dcfd5b6103606000600a818352015b602461036051600a81106121f957600080fd5b6020020135610380526101406103c0525b6103c0515160206103c051016103c0526103c06103c051101561222c5761220a565b6320171bef6103e05261038051610400526104005160065801610cfa565b610460526103a06103c0525b6103c0515260206103c051036103c0526101406103c05110151561227957612256565b610460516103a05260026103a0511460016103a051141761229957600080fd5b60016103a05114156122cb57600161016461036051600a81106122bb57600080fd5b6020020135146122ca57600080fd5b5b61016461036051600a81106122df57600080fd5b6020020135600360043560e05260c052604060c0206103805160e05260c052604060c020555b81516001018083528114156121e6575b5050602435610480526044356104a0526064356104c0526084356104e05260a4356105005260c4356105205260e4356105405261010435610560526101243561058052610144356105a052610164356105c052610184356105e0526101a435610600526101c435610620526101e4356106405261020435610660526102243561068052610244356106a052610264356106c052610284356106e0526004356000337f514c24e4790d7c31a095a1688a73a01f28d936a9a85d806ba95970d8ee88efa8610280610480a46107006000600a818352015b60006004353b11156124e1576004353b61240357600080fd5b600435301861241157600080fd5b60206109606101c460a063f23a6e61610740523361076052600061078052602461070051600a811061244257600080fd5b60200201356107a05261016461070051600a811061245f57600080fd5b60200201356107c052806107e052610140808051602001808461076001828460006004600a8704601201f161249357600080fd5b50508051820160206001820306601f820103905060200191505061075c905060006004355af16124c257600080fd5b600050610960516107205263f23a6e6161072051146124e057600080fd5b5b5b81516001018083528114156123ea575b5050005b63b390c0ab60005114156125ea57341561250f57600080fd5b6308c379a061014052602061016052601a610180527f4e6f7420656e6f75676820746f6b656e7320746f206275726e2e0000000000006101a0526101805060243560033360e05260c052604060c02060043560e05260c052604060c02054101561257a57608461015cfd5b60033360e05260c052604060c02060043560e05260c052604060c020602435815410156125a657600080fd5b6024358154038155506004356101e05260243561020052600033337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6260406101e0a4005b63b59afe52600051141561282b57341561260357600080fd5b6000610120525b60206101205101610120526101206101205110156126275761260a565b6000610120525b602061012051016101205261012061012051101561264b5761262e565b6101406000600a818352015b600461014051600a811061266a57600080fd5b60200201356101605261014461014051600a811061268757600080fd5b602002013560033360e05260c052604060c0206101605160e05260c052604060c0205410156126b557600080fd5b5b8151600101808352811415612657575b50506101806000600a818352015b600461018051600a81106126e757600080fd5b60200201356101a05260033360e05260c052604060c0206101a05160e05260c052604060c02061014461018051600a811061272157600080fd5b60200201358154101561273357600080fd5b61014461018051600a811061274757600080fd5b60200201358154038155505b81516001018083528114156126d4575b50506004356101c0526024356101e05260443561020052606435610220526084356102405260a4356102605260c4356102805260e4356102a052610104356102c052610124356102e0526101443561030052610164356103205261018435610340526101a435610360526101c435610380526101e4356103a052610204356103c052610224356103e05261024435610400526102643561042052600033337f514c24e4790d7c31a095a1688a73a01f28d936a9a85d806ba95970d8ee88efa86102806101c0a4005b63f2526ada6000511415612869576000610320526103208051602001806101e0828460006004600a8704601201f161286257600080fd5b50506128b9565b63a835c36960005114156128b157610120610464356004016101e0376101006104643560040135111561289b57600080fd5b610140610464356004016101e0376000506128b9565b600015613725575b60043560205181106128ca57600080fd5b5060243560205181106128dc57600080fd5b506000610120525b6020610120510161012052610120610120511015612901576128e4565b6000610120525b602061012051016101205261012061012051101561292557612908565b6000610120525b60206101205101610120526101206101205110156129495761292c565b6061610444356004016101403760416104443560040135111561296b57600080fd5b6308c379a061036052602061038052602c6103a0527f5f66726f6d206d757374206265207468652073656e646572206f7220617070726103c0527f6f766564206164647265737300000000000000000000000000000000000000006103e0526103a050600660043560e05260c052604060c0203360e05260c052604060c020543360043514176129fc5760a461037cfd5b6308c379a0610420526020610440526025610460527f44657374696e6174696f6e2061646472657373206d757374206265206e6f6e2d610480527f7a65726f2e0000000000000000000000000000000000000000000000000000006104a05261046050600060243518612a705760a461043cfd5b6308c379a06104e0526020610500526015610520527f4e6f6e6365206d75737420626520756e757365642e00000000000000000000006105405261052050600460043560e05260c052604060c0206104243560e05260c052604060c0205415612ada5760846104fcfd5b6308c379a06105805260206105a05260256105c0527f53656e64657220686173206e6f742070726f766964656420656e6f75676820656105e0527f746865722e000000000000000000000000000000000000000000000000000000610600526105c050346104043514612b4e5760a461059cfd5b6106406000600a818352015b604461064051600a8110612b6d57600080fd5b602002013561066052600061018461064051600a8110612b8c57600080fd5b60200201351115612c03576102c461064051600a8110612bab57600080fd5b602002013515612bba57600080fd5b61018461064051600a8110612bce57600080fd5b6020020135600360043560e05260c052604060c0206106605160e05260c052604060c020541015612bfe57600080fd5b612c6b565b61018461064051600a8110612c1757600080fd5b602002013515612c2657600080fd5b6102c461064051600a8110612c3a57600080fd5b6020020135600360243560e05260c052604060c0206106605160e05260c052604060c020541015612c6a57600080fd5b5b5b8151600101808352811415612b5a575b50506101406106a0525b6106a0515160206106a051016106a0526106a06106a0511015612ca857612c86565b6373ad25716106c0526004356106e05260243561070052610720604480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e00152806101000135826101000152806101200135826101200152505061086061018480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250506109a06102c480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e00152806101000135826101000152806101200135826101200152505061040435610ae05261042435610b0052610b0051610ae051610ac051610aa051610a8051610a6051610a4051610a2051610a00516109e0516109c0516109a05161098051610960516109405161092051610900516108e0516108c0516108a05161088051610860516108405161082051610800516107e0516107c0516107a05161078051610760516107405161072051610700516106e051600658016100dc565b610b60526106806106a0525b6106a0515260206106a051036106a0526101406106a051101515612ecc57612ea9565b610b605161068052610140610ba0525b610ba051516020610ba05101610ba052610ba0610ba0511015612efe57612edc565b6040636f868168610bc05261068051610be05280610c00526101408080516020018084610be001828460006004600a8704601201f1612f3c57600080fd5b50508051820160206001820306601f820103905060200191505050610c005180610be00180518060206001820306601f82010390508201610ce0525050505b610c20610ce0511015612f8d57612fa2565b610ce051516020610ce05103610ce052612f7b565b610c0051610be05160065801610a98565b610d0052610b80610ba0525b610ba051526020610ba05103610ba052610140610ba051101515612fe257612fbf565b610d0051610b80526308c379a0610d20526020610d40526020610d60527f5369676e657220646f6573206e6f74206d61746368207369676e61747572652e610d8052610d6050602435610b80511461303b576084610d3cfd5b600160043360e05260c052604060c0206104243560e05260c052604060c02055610dc06000600a818352015b6044610dc051600a811061307a57600080fd5b6020020135610de0526000610184610dc051600a811061309957600080fd5b6020020135111561317457600360043560e05260c052604060c020610de05160e05260c052604060c020610184610dc051600a81106130d757600080fd5b6020020135815410156130e957600080fd5b610184610dc051600a81106130fd57600080fd5b6020020135815403815550600360243560e05260c052604060c020610de05160e05260c052604060c0208054610184610dc051600a811061313d57600080fd5b6020020135825401101561315057600080fd5b610184610dc051600a811061316457600080fd5b6020020135815401815550613240565b600360043560e05260c052604060c020610de05160e05260c052604060c02080546102c4610dc051600a81106131a957600080fd5b602002013582540110156131bc57600080fd5b6102c4610dc051600a81106131d057600080fd5b6020020135815401815550600360243560e05260c052604060c020610de05160e05260c052604060c0206102c4610dc051600a811061320e57600080fd5b60200201358154101561322057600080fd5b6102c4610dc051600a811061323457600080fd5b60200201358154038155505b5b8151600101808352811415613067575b50506000600060006000346024356000f161326b57600080fd5b604435610e0052606435610e2052608435610e405260a435610e605260c435610e805260e435610ea05261010435610ec05261012435610ee05261014435610f005261016435610f205261018435610f40526101a435610f60526101c435610f80526101e435610fa05261020435610fc05261022435610fe0526102443561100052610264356110205261028435611040526102a43561106052602435600435337f514c24e4790d7c31a095a1688a73a01f28d936a9a85d806ba95970d8ee88efa8610280610e00a4604435611080526064356110a0526084356110c05260a4356110e05260c4356111005260e43561112052610104356111405261012435611160526101443561118052610164356111a0526102c4356111c0526102e4356111e052610304356112005261032435611220526103443561124052610364356112605261038435611280526103a4356112a0526103c4356112c0526103e4356112e052600435602435337f514c24e4790d7c31a095a1688a73a01f28d936a9a85d806ba95970d8ee88efa8610280611080a460006024353b1115613590576024353b61341657600080fd5b602435301861342457600080fd5b60206117806104046102e063a3bfc20661132052336113405260243561136052611380604480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250506114c061018480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e00152806101000135826101000152806101200135826101200152505080611600526101e0808051602001808461134001828460006004600a8704601201f161354257600080fd5b50508051820160206001820306601f820103905060200191505061133c905060006024355af161357157600080fd5b6000506117805161130052630c97e564611300511461358f57600080fd5b5b60006004353b1115613723576004353b6135a957600080fd5b60043530186135b757600080fd5b6020611c206104046102e063a3bfc2066117c052336117e05260043561180052611820604480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250506119606102c480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e00152806101000135826101000152806101200135826101200152505080611aa0526101e080805160200180846117e001828460006004600a8704601201f16136d557600080fd5b50508051820160206001820306601f82010390506020019150506117dc905060006004355af161370457600080fd5b600050611c20516117a052630c97e5646117a0511461372257600080fd5b5b005b636e8205b26000511415613763576000610320526103208051602001806101e0828460006004600a8704601201f161375c57600080fd5b50506137b3565b63183f5ec560005114156137ab57610120610104356004016101e0376101006101043560040135111561379557600080fd5b610140610104356004016101e0376000506137b3565b600015613f5d575b60043560205181106137c457600080fd5b5060243560205181106137d657600080fd5b50606160e43560040161014037604160e4356004013511156137f757600080fd5b600660043560e05260c052604060c0203360e05260c052604060c0205433600435141761382357600080fd5b6308c379a06103605260206103805260256103a0527f44657374696e6174696f6e2061646472657373206d757374206265206e6f6e2d6103c0527f7a65726f2e0000000000000000000000000000000000000000000000000000006103e0526103a0506000602435186138975760a461037cfd5b6308c379a0610420526020610440526015610460527f4e6f6e6365206d75737420626520756e757365642e00000000000000000000006104805261046050600460043560e05260c052604060c02060c43560e05260c052604060c020541561390057608461043cfd5b6308c379a06104c05260206104e0526025610500527f53656e64657220686173206e6f742070726f766964656420656e6f7567682065610520527f746865722e00000000000000000000000000000000000000000000000000000061054052610500503460a435146139735760a46104dcfd5b600060643511156139bd576084351561398b57600080fd5b606435600360043560e05260c052604060c02060443560e05260c052604060c0205410156139b857600080fd5b6139f8565b606435156139ca57600080fd5b608435600360243560e05260c052604060c02060443560e05260c052604060c0205410156139f757600080fd5b5b6101406105a0525b6105a0515160206105a051016105a0526105a06105a0511015613a2257613a00565b63155960636105c0526004356105e0526024356106005260443561062052606435610640526084356106605260a4356106805260c4356106a0526106a05161068051610660516106405161062051610600516105e05160065801610911565b610700526105806105a0525b6105a0515260206105a051036105a0526101406105a051101515613ab057613a8d565b6107005161058052610140610740525b61074051516020610740510161074052610740610740511015613ae257613ac0565b6040636f868168610760526105805161078052806107a052610140808051602001808461078001828460006004600a8704601201f1613b2057600080fd5b50508051820160206001820306601f8201039050602001915050506107a051806107800180518060206001820306601f82010390508201610880525050505b6107c0610880511015613b7157613b86565b61088051516020610880510361088052613b5f565b6107a0516107805160065801610a98565b6108a052610720610740525b6107405152602061074051036107405261014061074051101515613bc657613ba3565b6108a051610720526308c379a06108c05260206108e0526020610900527f5369676e657220646f6573206e6f74206d61746368207369676e61747572652e61092052610900506024356107205114613c1f5760846108dcfd5b600160043360e05260c052604060c02060c43560e05260c052604060c0205560006064351115613cbf57600360043560e05260c052604060c02060443560e05260c052604060c02060643581541015613c7757600080fd5b606435815403815550600360243560e05260c052604060c02060443560e05260c052604060c02080546064358254011015613cb157600080fd5b606435815401815550613d31565b600360043560e05260c052604060c02060443560e05260c052604060c02080546084358254011015613cf057600080fd5b608435815401815550600360243560e05260c052604060c02060443560e05260c052604060c02060843581541015613d2757600080fd5b6084358154038155505b6000600060006000346024356000f1613d4957600080fd5b6044356109605260643561098052602435600435337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f626040610960a46044356109a0526084356109c052600435602435337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6260406109a0a460006024353b1115613e8e576024353b613dda57600080fd5b6024353018613de857600080fd5b6020610c206101c460a063f23a6e61610a005233610a2052602435610a4052604435610a6052606435610a805280610aa0526101e08080516020018084610a2001828460006004600a8704601201f1613e4057600080fd5b50508051820160206001820306601f8201039050602001915050610a1c905060006024355af1613e6f57600080fd5b600050610c20516109e052630c97e5646109e05114613e8d57600080fd5b5b60006004353b1115613f5b576004353b613ea757600080fd5b6004353018613eb557600080fd5b6020610e806101c460a063f23a6e61610c605233610c8052600435610ca052604435610cc052608435610ce05280610d00526101e08080516020018084610c8001828460006004600a8704601201f1613f0d57600080fd5b50508051820160206001820306601f8201039050602001915050610c7c905060006004355af1613f3c57600080fd5b600050610e8051610c4052630c97e564610c405114613f5a57600080fd5b5b005b638da5cb5b6000511415613f84573415613f7657600080fd5b60025460005260206000f350005b60006000fd\",\n  \"source\": \"# Author: Sören Steiger, github.com/ssteiger\\n# Author: Fetch.ai, github.com/fetchai\\n# License: MIT\\n\\n# ERC1155 Token Standard\\n# https://eips.ethereum.org/EIPS/eip-1155\\n\\n########################EXTERNAL-CONTRACTS####################################\\n\\ncontract ERC1155TokenReceiver:\\n    # Note: The ERC-165 identifier for this interface is 0x4e2312e0.\\n\\n    def onERC1155Received(_operator: address, _from: address, _id: uint256, _value: uint256,\\n                          _data: bytes[256]) -> bytes32: modifying  # TODO: should return bytes4\\n    #        \\\"\\\"\\\"\\n    #       @notice Handle the receipt of a single ERC1155 token type.\\n    #       @dev An ERC1155-compliant smart contract MUST call this function on the token recipient contract, at the end of a `safeTransferFrom` after the balance has been updated.        \\n    #       This function MUST return `bytes4(keccak256(\\\"onERC1155Received(address,address,uint256,uint256,bytes)\\\"))` (i.e. 0xf23a6e61) if it accepts the transfer.\\n    #       This function MUST revert if it rejects the transfer.\\n    #       Return of any other value than the prescribed keccak256 generated value MUST result in the transaction being reverted by the caller.\\n    #       @param _operator  The address which initiated the transfer (i.e. msg.sender)\\n    #       @param _from      The address which previously owned the token\\n    #       @param _id        The ID of the token being transferred\\n    #       @param _value     The amount of tokens being transferred\\n    #       @param _data      Additional data with no specified format\\n    #       @return           `bytes4(keccak256(\\\"onERC1155Received(address,address,uint256,uint256,bytes)\\\"))`\\n    #       \\\"\\\"\\\"\\n\\n    def onERC1155BatchReceived(_operator: address, _from: address, _ids: uint256[BATCH_SIZE], _values: uint256[BATCH_SIZE],\\n                               _data: bytes[256]) -> bytes32: modifying  # TODO: should return bytes4\\n    #       \\\"\\\"\\\"\\n    #       @notice Handle the receipt of multiple ERC1155 token types.\\n    #       @dev An ERC1155-compliant smart contract MUST call this function on the token recipient contract, at the end of a `safeBatchTransferFrom` after the balances have been updated.        \\n    #       This function MUST return `bytes4(keccak256(\\\"onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)\\\"))` (i.e. 0xbc197c81) if it accepts the transfer(s).\\n    #       This function MUST revert if it rejects the transfer(s).\\n    #       Return of any other value than the prescribed keccak256 generated value MUST result in the transaction being reverted by the caller.\\n    #       @param _operator  The address which initiated the batch transfer (i.e. msg.sender)\\n    #       @param _from      The address which previously owned the token\\n    #       @param _ids       An array containing ids of each token being transferred (order and length must match _values array)\\n    #       @param _values    An array containing amounts of each token being transferred (order and length must match _ids array)\\n    #       @param _data      Additional data with no specified format\\n    #       @return           `bytes4(keccak256(\\\"onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)\\\"))`\\n    #       \\\"\\\"\\\"\\n\\n########################END-EXTERNAL-CONTRACTS####################################\\n########################EVENTS####################################\\n\\nMAX_URI_SIZE: constant(uint256) = 1024\\n\\nTransferSingle: event({_operator: indexed(address), _from: indexed(address), _to: indexed(address), _id: uint256,\\n                       _value: uint256})\\n#   @dev Either `TransferSingle` or `TransferBatch` MUST emit when tokens are transferred, including zero value transfers as well as minting or burning (see \\\"Safe Transfer Rules\\\" section of the standard).\\n#        The `_operator` argument MUST be the address of an account/contract that is approved to make the transfer (SHOULD be msg.sender).\\n#        The `_from` argument MUST be the address of the holder whose balance is decreased.\\n#        The `_to` argument MUST be the address of the recipient whose balance is increased.\\n#        The `_id` argument MUST be the token type being transferred.\\n#        The `_value` argument MUST be the number of tokens the holder balance is decreased by and match what the recipient balance is increased by.\\n#        When minting/creating tokens, the `_from` argument MUST be set to `0x0` (i.e. zero address).\\n#        When burning/destroying tokens, the `_to` argument MUST be set to `0x0` (i.e. zero address).\\n\\n\\nTransferBatch: event({_operator: indexed(address), _from: indexed(address), _to: indexed(address),\\n                      _ids: uint256[BATCH_SIZE], _values: uint256[BATCH_SIZE]})\\n#   @dev Either `TransferSingle` or `TransferBatch` MUST emit when tokens are transferred, including zero value transfers as well as minting or burning (see \\\"Safe Transfer Rules\\\" section of the standard).\\n#        The `_operator` argument MUST be the address of an account/contract that is approved to make the transfer (SHOULD be msg.sender).\\n#        The `_from` argument MUST be the address of the holder whose balance is decreased.\\n#        The `_to` argument MUST be the address of the recipient whose balance is increased.\\n#        The `_ids` argument MUST be the list of tokens being transferred.\\n#        The `_values` argument MUST be the list of number of tokens (matching the list and order of tokens specified in _ids) the holder balance is decreased by and match what the recipient balance is increased by.\\n#        When minting/creating tokens, the `_from` argument MUST be set to `0x0` (i.e. zero address).\\n#        When burning/destroying tokens, the `_to` argument MUST be set to `0x0` (i.e. zero address).\\n\\n\\nApprovalForAll: event({_owner: indexed(address), _operator: indexed(address), _approved: bool})\\n#   @dev MUST emit when approval for a second party/operator address to manage all tokens for an owner address is enabled or disabled (absence of an event assumes disabled).\\n\\n\\nURI: event({_value: string[MAX_URI_SIZE], _id: indexed(uint256)})\\n#   @dev MUST emit when the URI is updated for a token ID.\\n#        URIs are defined in RFC 3986.\\n#        The URI MUST point to a JSON file that conforms to the \\\"ERC-1155 Metadata URI JSON Schema\\\".\\n\\n########################END-EVENTS####################################\\n########################INITIALIZATION####################################\\n\\nsupportedInterfaces: map(bytes32, bool)\\n# https://eips.ethereum.org/EIPS/eip-165\\nERC165_INTERFACE_ID: constant(bytes32)  = 0x0000000000000000000000000000000000000000000000000000000001ffc9a7\\nERC1155_INTERFACE_ID: constant(bytes32) = 0x00000000000000000000000000000000000000000000000000000000d9b67a26\\ntokensIdCount: uint256\\nowner: public(address)\\n\\nbalancesOf: map(address, map(uint256, uint256))\\nnoncesOf: map(address, map(uint256, bool))\\nuri: map(uint256, string[256])\\noperators: map(address, map(address, bool))\\ntoken_ids: map(uint256, bool)\\n\\n# This is to be set before contract migration!\\nBATCH_SIZE: constant(uint256) = 10\\n\\n\\n@public\\ndef __init__():\\n    \\\"\\\"\\\"\\n    @notice Called once and only upon contract deployment.\\n    \\\"\\\"\\\"\\n    self.tokensIdCount = convert(0, uint256)\\n    self.supportedInterfaces[ERC165_INTERFACE_ID] = True\\n    self.supportedInterfaces[ERC1155_INTERFACE_ID] = True\\n    self.owner = msg.sender\\n\\n########################END-INITIALIZATION####################################\\n########################PRIVATE-FUNCTIONS####################################\\n\\n\\n######### THIS IS A TEMPORARY SOLUTION #################\\n@public\\n@constant\\ndef getAddress(_addr: address) -> bytes32:\\n    hash: bytes32 = convert(_addr, bytes32)\\n    return hash\\n##################### END ##############################\\n\\n@private\\n@constant\\ndef _getHash(_from: address, _to: address, _ids: uint256[BATCH_SIZE], _from_supplies: uint256[BATCH_SIZE], _to_supplies: uint256[BATCH_SIZE], _value_eth: uint256, _nonce: uint256) -> bytes32:\\n    \\\"\\\"\\\"\\n    @notice Get the hash from the tx values.\\n    @param _from          The address of the sender.\\n    @param _to            The address of the receiver.\\n    @param _ids           The ids of the tokens.\\n    @param _from_supplies The supply of token values that will send the _from.\\n    @param _to_supplies   The supply of token values that will send the _from.\\n    @param _value_eth     The value of the ether.\\n    @param _nonce         The nonce.\\n    @return the hash\\n    \\\"\\\"\\\"\\n    aggregate_hash: bytes32 = keccak256(concat(convert(_ids[0], bytes32), convert(_from_supplies[0], bytes32), convert(_to_supplies[0], bytes32)))\\n    for i in range(BATCH_SIZE):\\n      if not i == 0:\\n        aggregate_hash = keccak256(concat(aggregate_hash, convert(_ids[i], bytes32), convert(_from_supplies[i], bytes32), convert(_to_supplies[i], bytes32)))\\n    hash: bytes32 = keccak256(concat(convert(_from, bytes32),\\n                              convert(_to, bytes32),\\n                              aggregate_hash,\\n                              convert(_value_eth, bytes32),\\n                              convert(_nonce, bytes32)))\\n    return hash\\n\\n\\n@public\\n@constant\\ndef getHash(_from: address, _to: address, _ids: uint256[BATCH_SIZE], _from_supplies: uint256[BATCH_SIZE], _to_supplies: uint256[BATCH_SIZE], _value_eth: uint256, _nonce: uint256) -> bytes32:\\n    \\\"\\\"\\\"\\n    @notice Get the hash from the tx values.\\n    @param _from          The address of the sender.\\n    @param _to            The address of the receiver.\\n    @param _ids           The ids of the tokens.\\n    @param _from_supplies The supply of token values that will send the _from.\\n    @param _to_supplies   The supply of token values that will send the _from.\\n    @param _value_eth     The value of the ether.\\n    @param _nonce         The nonce.\\n    @return the hash\\n    \\\"\\\"\\\"\\n    return self._getHash(_from, _to, _ids, _from_supplies, _to_supplies, _value_eth, _nonce)\\n\\n\\n@private\\n@constant\\ndef getHashOld(_from: address, _to: address, _ids: uint256[BATCH_SIZE], _from_supplies: uint256[BATCH_SIZE], _to_supplies: uint256[BATCH_SIZE], _value_eth: uint256, _nonce: uint256) -> bytes32:\\n    \\\"\\\"\\\"\\n    @notice Get the hash from the tx values.\\n    @param _from          The address of the sender.\\n    @param _to            The address of the receiver.\\n    @param _ids           The ids of the tokens.\\n    @param _from_supplies The supply of token values that will send the _from.\\n    @param _to_supplies   The supply of token values that will send the _from.\\n    @param _value_eth     The value of the ether.\\n    @param _nonce         The nonce.\\n    @return the hash\\n    \\\"\\\"\\\"\\n    hash: bytes32 = keccak256(concat(convert(_from, bytes32),\\n                              convert(_to, bytes32),\\n                              convert(_ids[0], bytes32),\\n                              convert(_ids[1], bytes32),\\n                              convert(_ids[2], bytes32),\\n                              convert(_ids[3], bytes32),\\n                              convert(_ids[4], bytes32),\\n                              convert(_ids[5], bytes32),\\n                              convert(_ids[6], bytes32),\\n                              convert(_ids[7], bytes32),\\n                              convert(_ids[8], bytes32),\\n                              convert(_ids[9], bytes32),\\n                              convert(_from_supplies[0], bytes32),\\n                              convert(_from_supplies[1], bytes32),\\n                              convert(_from_supplies[2], bytes32),\\n                              convert(_from_supplies[3], bytes32),\\n                              convert(_from_supplies[4], bytes32),\\n                              convert(_from_supplies[5], bytes32),\\n                              convert(_from_supplies[6], bytes32),\\n                              convert(_from_supplies[7], bytes32),\\n                              convert(_from_supplies[8], bytes32),\\n                              convert(_from_supplies[9], bytes32),\\n                              convert(_to_supplies[0], bytes32),\\n                              convert(_to_supplies[1], bytes32),\\n                              convert(_to_supplies[2], bytes32),\\n                              convert(_to_supplies[3], bytes32),\\n                              convert(_to_supplies[4], bytes32),\\n                              convert(_to_supplies[5], bytes32),\\n                              convert(_to_supplies[6], bytes32),\\n                              convert(_to_supplies[7], bytes32),\\n                              convert(_to_supplies[8], bytes32),\\n                              convert(_to_supplies[9], bytes32),\\n                              convert(_value_eth, bytes32),\\n                              convert(_nonce, bytes32)))\\n    return hash\\n\\n\\n@private\\n@constant\\ndef _getSingleHash(_from: address, _to: address, _id: uint256, _from_supply: uint256, _to_supply: uint256, _value_eth: uint256, _nonce: uint256) -> bytes32:\\n    \\\"\\\"\\\"\\n    @notice Get the hash from the tx values.\\n    @param _from            The address of the sender.\\n    @param _to              The address of the receiver.\\n    @param _id              The id of the tokens.\\n    @param _from_supply     The from token value. (_from sends)\\n    @param _to_supply       The to token value (_to sends).\\n    @param _value_eth       The value of the ether.\\n    @param _nonce           The nonce.\\n    @return the hash\\n    \\\"\\\"\\\"\\n    hash: bytes32 = keccak256(concat(convert(_from, bytes32),\\n                              convert(_to, bytes32),\\n                              convert(_id, bytes32),\\n                              convert(_from_supply, bytes32),\\n                              convert(_to_supply, bytes32),\\n                              convert(_value_eth, bytes32),\\n                              convert(_nonce, bytes32)))\\n    return hash\\n\\n\\n@public\\n@constant\\ndef getSingleHash(_from: address, _to: address, _id: uint256, _from_supply: uint256, _to_supply: uint256, _value_eth: uint256, _nonce: uint256) -> bytes32:\\n    \\\"\\\"\\\"\\n    @notice Get the hash from the tx values.\\n    @param _from            The address of the sender.\\n    @param _to              The address of the receiver.\\n    @param _id              The id of the tokens.\\n    @param _from_supply     The from token value. (_from sends)\\n    @param _to_supply       The to token value (_to sends).\\n    @param _value_eth       The value of the ether.\\n    @param _nonce           The nonce.\\n    @return the hash\\n    \\\"\\\"\\\"\\n    return self._getSingleHash(_from, _to, _id, _from_supply, _to_supply, _value_eth, _nonce)\\n\\n\\n@private\\n@constant\\ndef ecrecoverSig(_hash: bytes32, _sig: bytes[65]) -> address:\\n    \\\"\\\"\\\"\\n    @notice Check whether the the signature matches the hash.\\n    @param _hash The hash to be checked.\\n    @param _sig  The signature which is meant to match the hash.\\n    @return the address which signed the signature or the zero address\\n    \\\"\\\"\\\"\\n    if len(_sig) != 65:\\n        return ZERO_ADDRESS\\n    # ref. https://gist.github.com/axic/5b33912c6f61ae6fd96d6c4a47afde6d\\n    # The signature format is a compact form of:\\n    # {bytes32 r}{bytes32 s}{uint8 v}\\n    r: bytes32 = extract32(_sig, 0, type=bytes32)\\n    s: bytes32 = extract32(_sig, 32, type=bytes32)\\n    v: int128 = convert(slice(_sig, start=64, len=1), int128)\\n    # Version of signature should be 27 or 28, but 0 and 1 are also possible versions.\\n    # geth uses [0, 1] and some clients have followed. This might change, see:\\n    # https://github.com/ethereum/go-ethereum/issues/2053\\n    if v < 27:\\n        v += 27\\n    if v in [27, 28]:\\n        return ecrecover(_hash, convert(v, uint256), convert(r, uint256), convert(s, uint256))\\n    return ZERO_ADDRESS\\n\\n\\n@private\\n@constant\\ndef decode_id(id: uint256) -> int128:\\n    \\\"\\\"\\\"\\n    @notice Decodes the id of the token inorder to find out if it NFT or FT.\\n    @param id: uint256\\n    @return token_id : int128 (Specified id for FT and NFT.)\\n    @dev shift(x, -y): returns x with the bits shifted to the right by y places, which is equivalent to dividing x by 2**y.\\n    \\\"\\\"\\\"\\n    decoded_token_id: int128 = convert(shift(id, -128), int128)\\n    decoded_index: int128 = convert(id % 2 ** 128, int128)\\n    return decoded_token_id\\n\\n########################END-PRIVATE-FUNCTIONS################################\\n########################PUBLIC-FUNCTIONS#####################################\\n\\n@public\\n@constant\\ndef supportsInterface(_interfaceID: bytes32) -> bool:\\n    \\\"\\\"\\\"\\n    @notice Check whether the interface id is supported.\\n    @param _interfaceID The interface id\\n    @return True if the interface id is supported.\\n    \\\"\\\"\\\"\\n    return self.supportedInterfaces[_interfaceID]\\n\\n@public\\n@constant\\ndef is_nonce_used(addr: address, nonce: uint256) -> bool:\\n    \\\"\\\"\\\"\\n    @notice Checks if the given nonce for the give address is unused.\\n    @param nonce: uint256 the counter of the transaction\\n    @param address: the address that want to transact.\\n    \\\"\\\"\\\"\\n    return self.noncesOf[addr][nonce]\\n\\n@public\\n@constant\\ndef is_token_id_exists(token_id: uint256) -> bool:\\n    \\\"\\\"\\\"\\n    @notice Checks if the given token_id is already created.\\n    @param token_id: uint256 the id of the token.\\n    \\\"\\\"\\\"\\n    return self.token_ids[token_id]\\n\\n@public\\ndef safeTransferFrom(_from: address, _to: address, _id: uint256, _value: uint256, _data: bytes[256]):\\n    \\\"\\\"\\\"\\n    @notice Transfers `_value` amount of an `_id` from the `_from` address to the `_to` address specified (with safety call).\\n    @dev Caller must be approved to manage the tokens being transferred out of the `_from` account (see \\\"Approval\\\" section of the standard).\\n         MUST revert if `_to` is the zero address.\\n         MUST revert if balance of holder for token `_id` is lower than the `_value` sent.\\n         MUST revert on any other error.\\n         MUST emit the `TransferSingle` event to reflect the balance change (see \\\"Safe Transfer Rules\\\" section of the standard).\\n         After the above conditions are met, this function MUST check if `_to` is a smart contract (e.g. code size > 0). If so, it MUST call `onERC1155Received` on `_to` and act appropriately (see \\\"Safe Transfer Rules\\\" section of the standard).\\n    @param _from    Source address\\n    @param _to      Target address\\n    @param _id      ID of the token type\\n    @param _value   Transfer amount\\n    @param _data    Additional data with no specified format, MUST be sent unaltered in call to `onERC1155Received` on `_to`\\n    @return None\\n    \\\"\\\"\\\"\\n    assert _from == msg.sender or (self.operators[_from])[msg.sender]\\n    assert _to != ZERO_ADDRESS, \\\"Cannot transfer to zero address.\\\"\\n    assert self.balancesOf[_from][_id] >= _value, \\\"Not enough tokens.\\\"\\n\\n    self.balancesOf[_from][_id] -= _value\\n    self.balancesOf[_to][_id] += _value\\n\\n    log.TransferSingle(msg.sender, _from, _to, _id, _value)\\n\\n    if _to.is_contract:\\n        returnValue: bytes32 = ERC1155TokenReceiver(_to).onERC1155Received(msg.sender, _from, _id, _value, _data)\\n        assert returnValue == method_id(\\\"onERC1155Received(address,address,uint256,uint256,bytes)\\\", bytes32)\\n\\n\\n@public\\ndef safeBatchTransferFrom(_from: address, _to: address, _ids: uint256[BATCH_SIZE], _values: uint256[BATCH_SIZE], _data: bytes[256]):\\n    \\\"\\\"\\\"\\n    @notice Transfers `_values` amount(s) of `_ids` from the `_from` address to the `_to` address specified (with safety call).\\n    @dev Caller must be approved to manage the tokens being transferred out of the `_from` account (see \\\"Approval\\\" section of the standard).\\n        MUST revert if `_to` is the zero address.\\n        MUST revert if length of `_ids` is not the same as length of `_values`.\\n        MUST revert if any of the balance(s) of the holder(s) for token(s) in `_ids` is lower than the respective amount(s) in `_values` sent to the recipient.\\n        MUST revert on any other error.\\n        MUST emit `TransferSingle` or `TransferBatch` event(s) such that all the balance changes are reflected (see \\\"Safe Transfer Rules\\\" section of the standard).\\n        Balance changes and events MUST follow the ordering of the arrays (_ids[0]/_values[0] before _ids[1]/_values[1], etc).\\n        After the above conditions for the transfer(s) in the batch are met, this function MUST check if `_to` is a smart contract (e.g. code size > 0). If so, it MUST call the relevant `ERC1155TokenReceiver` hook(s) on `_to` and act appropriately (see \\\"Safe Transfer Rules\\\" section of the standard).\\n    @param _from    Source address\\n    @param _to      Target address\\n    @param _ids     IDs of each token type (order and length must match _values array)\\n    @param _values  Transfer amounts per token type (order and length must match _ids array)\\n    @param _data    Additional data with no specified format, MUST be sent unaltered in call to the `ERC1155TokenReceiver` hook(s) on `_to`\\n    @return None\\n    \\\"\\\"\\\"\\n    assert _from == msg.sender or (self.operators[_from])[msg.sender]\\n    assert _to != ZERO_ADDRESS, \\\"Cannot transfer to zero address.\\\"\\n    for i in range(BATCH_SIZE):\\n        id: uint256 = _ids[i]\\n        assert self.balancesOf[_from][id] >= _values[i]\\n\\n    log.TransferBatch(msg.sender, _from, _to, _ids, _values)\\n\\n    for i in range(BATCH_SIZE):\\n        id: uint256 = _ids[i]\\n        self.balancesOf[_from][id] -= _values[i]\\n        self.balancesOf[_to][id] += _values[i]\\n\\n    if _to.is_contract:\\n        returnValue: bytes32 = ERC1155TokenReceiver(_to).onERC1155BatchReceived(msg.sender, _from, _ids, _values, _data)\\n        assert returnValue == method_id(\\\"onERC1155BatchReceived(address,address,uint256[BATCH_SIZE],uint256[BATCH_SIZE],bytes)\\\", bytes32)\\n\\n\\n@public\\n@constant\\ndef balanceOf(_owner: address, _id: uint256) -> uint256:\\n    \\\"\\\"\\\"\\n    @notice Get the balance of an account's tokens.\\n    @param  _owner The address of the token holder\\n    @param  _id    ID of the token\\n    @return The _owner's balance of the token type requested\\n    \\\"\\\"\\\"\\n    return self.balancesOf[_owner][_id]\\n\\n\\n@public\\n@constant\\ndef balanceOfBatch( _owner: address[BATCH_SIZE], _ids: uint256[BATCH_SIZE]) -> uint256[BATCH_SIZE]:\\n    \\\"\\\"\\\"\\n    @notice Get the balance of multiple account/token pairs\\n    @param _owners The addresses of the token holders\\n    @param _ids    ID of the tokens\\n    @return The _owner's balance of the token types requested (i.e. balance for each (owner, id) pair)\\n    \\\"\\\"\\\"\\n    returnBalances: uint256[BATCH_SIZE]\\n    for i in range(BATCH_SIZE):\\n        returnBalances[i] = self.balancesOf[_owner[i]][_ids[i]]\\n    return returnBalances\\n\\n\\n@public\\ndef setApprovalForAll(_operator: address, _approved: bool):\\n    \\\"\\\"\\\"\\n    @notice Enable or disable approval for a third party (\\\"operator\\\") to manage all of the caller's tokens.\\n    @dev MUST emit the ApprovalForAll event on success.\\n    @param _operator  Address to add to the set of authorized operators\\n    @param _approved  True if the operator is approved, false to revoke approval\\n    @return None\\n    \\\"\\\"\\\"\\n    (self.operators[msg.sender])[_operator] = _approved\\n    log.ApprovalForAll(msg.sender, _operator, _approved)\\n\\n\\n@public\\n@constant\\ndef isApprovedForAll(_owner: address, _operator: address) -> bool:\\n    \\\"\\\"\\\"\\n    @notice Queries the approval status of an operator for a given owner.\\n    @param _owner     The owner of the tokens.\\n    @param _operator  Address of authorized operator.\\n    @return True if the operator is approved, false if not\\n    \\\"\\\"\\\"\\n    return (self.operators[_owner])[_operator]\\n\\n\\n@public\\ndef createSingle(_item_owner: address, _id: uint256, _path: string[256]):\\n    \\\"\\\"\\\"\\n    @notice Create a new token type that we can mint later.\\n    @param _item_owner The owner of the item.\\n    @param _id         The id of the token.\\n    @param _path       The path to the token data.\\n    @return None\\n    \\\"\\\"\\\"\\n    assert _item_owner != ZERO_ADDRESS\\n    assert self.owner == msg.sender, \\\"Owner only can create item.\\\"\\n    self.balancesOf[_item_owner][_id] = 0\\n    self.tokensIdCount += 1\\n    self.token_ids[_id] = True\\n    self.uri[_id] = _path\\n    log.URI(_path, _id)\\n    log.TransferSingle(msg.sender, ZERO_ADDRESS, _item_owner, _id, 0)\\n\\n\\n@public\\ndef createBatch(_items_owner: address, _ids: uint256[BATCH_SIZE]):\\n    \\\"\\\"\\\"\\n    @notice Create new token types that we can mint later.\\n    @param _items_owner The owner of the items.\\n    @param _ids         The ids of the tokens.\\n    @return None\\n    \\\"\\\"\\\"\\n    assert _items_owner != ZERO_ADDRESS\\n    assert self.owner == msg.sender, \\\"Owner only can create items.\\\"\\n    for i in range(BATCH_SIZE):\\n        id: uint256 = _ids[i]\\n        self.balancesOf[_items_owner][id] = 0\\n        self.tokensIdCount += 1\\n        self.token_ids[id] = True\\n    zero_supply: uint256[BATCH_SIZE] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]\\n    log.TransferBatch(msg.sender, ZERO_ADDRESS, _items_owner, _ids, zero_supply)\\n\\n\\n@public\\ndef mint(_to: address, _id: uint256, _supply: uint256, _data: bytes[256]=\\\"\\\"):\\n    \\\"\\\"\\\"\\n    @notice Mint a token.\\n    @dev This is not part of the standard.\\n    @param _to      The address of the receiver.\\n    @param _id      The id of the token.\\n    @param _supply  The supply to be minted for the token.\\n    @param _data    The data.\\n    @return None\\n    \\\"\\\"\\\"\\n    assert _to != ZERO_ADDRESS\\n    assert self.owner == msg.sender, \\\"Owner only can mint items.\\\"\\n    decoded_id: int128 = self.decode_id(_id)\\n    assert decoded_id == 1 or decoded_id == 2\\n    if decoded_id == 1 :\\n        assert _supply == 1, \\\"Cannot mint NFT with _supply more than 1\\\"\\n    self.balancesOf[_to][_id] = _supply\\n\\n    log.TransferSingle(msg.sender, ZERO_ADDRESS, _to, _id, _supply)\\n\\n    if _to.is_contract:\\n        returnValue: bytes32 = ERC1155TokenReceiver(_to).onERC1155Received(msg.sender, ZERO_ADDRESS, _id, _supply, _data)\\n        assert returnValue == method_id(\\\"onERC1155Received(address,address,uint256,uint256,bytes)\\\", bytes32)\\n\\n\\n@public\\ndef mintBatch(_to: address, _ids: uint256[BATCH_SIZE], _supplies: uint256[BATCH_SIZE], _data: bytes[256]=\\\"\\\"):\\n    \\\"\\\"\\\"\\n    @notice Mint a batch of tokens.\\n    @dev This is not part of the standard.\\n    @param _to      The address of the receiver.\\n    @param _ids     The ids of the tokens.\\n    @param _supplies The supply to be minted for each token.\\n    @param _data    The data.\\n    @return None\\n    \\\"\\\"\\\"\\n    assert _to != ZERO_ADDRESS\\n    assert self.owner == msg.sender, \\\"Owner only can mint items.\\\"\\n\\n    for i in range(BATCH_SIZE):\\n        id: uint256 = _ids[i]\\n        decoded_id: int128 = self.decode_id(id)\\n        assert decoded_id == 1 or decoded_id == 2\\n\\n        if decoded_id == 1 :\\n            assert _supplies[i] == 1\\n\\n        self.balancesOf[_to][id] = _supplies[i]\\n\\n    log.TransferBatch(msg.sender, ZERO_ADDRESS, _to, _ids, _supplies)\\n\\n    for i in range(BATCH_SIZE):\\n        if _to.is_contract:\\n            returnValue: bytes32 = ERC1155TokenReceiver(_to).onERC1155Received(msg.sender, ZERO_ADDRESS, _ids[i], _supplies[i], _data)\\n            assert returnValue == method_id(\\\"onERC1155Received(address,address,uint256,uint256,bytes)\\\", bytes32)\\n\\n\\n@public\\ndef burn(_id: uint256, _supply: uint256):\\n    \\\"\\\"\\\"\\n    @notice Burns the supply of the specified token.\\n    @param _id        The id of the token\\n    @param _supply    Supply to be burned\\n    @return None\\n    \\\"\\\"\\\"\\n    assert self.balancesOf[msg.sender][_id] >= _supply, \\\"Not enough tokens to burn.\\\"\\n    self.balancesOf[msg.sender][_id] -= _supply\\n    log.TransferSingle(msg.sender, msg.sender, ZERO_ADDRESS, _id, _supply)\\n\\n\\n@public\\ndef burnBatch(_ids: uint256[BATCH_SIZE], _supplies: uint256[BATCH_SIZE]):\\n    \\\"\\\"\\\"\\n    @notice Burns the supply of the specified tokens.\\n    @dev At this point anyone can burn items if they own it.\\n    @param _ids        The ids of the token\\n    @param _supplies   Supplies to be burned\\n    @return None\\n    \\\"\\\"\\\"\\n    for i in range(BATCH_SIZE):\\n        id: uint256 = _ids[i]\\n        assert self.balancesOf[msg.sender][id] >= _supplies[i]\\n\\n    for i in range(BATCH_SIZE):\\n        id: uint256 = _ids[i]\\n        self.balancesOf[msg.sender][id] -= _supplies[i]\\n    log.TransferBatch(msg.sender, msg.sender, ZERO_ADDRESS, _ids, _supplies)\\n\\n\\n@public\\n@payable\\ndef tradeBatch(_from: address, _to: address, _ids: uint256[BATCH_SIZE], _from_supplies: uint256[BATCH_SIZE], _to_supplies: uint256[BATCH_SIZE], _value_eth: uint256, _nonce: uint256, _signature: bytes[65], _data: bytes[256]=\\\"\\\"):\\n    \\\"\\\"\\\"\\n    @notice Trade (atomically swap) tokens with tokens or eth.\\n    @dev Caller must be approved to manage the tokens being transferred out of the `_from` account (see \\\"Approval\\\" section of the standard).\\n        MUST revert if `_to` is the zero address.\\n        MUST revert if _from_supplies[i] > 0 and _to_supplies[i] > 0\\n        MUST revert if len(_ids) != len(_from_supplies) != len(_to_supplies)\\n        MUST revert if _value_eth != msg.value\\n        MUST revert if any of the balance(s) of the holder(s) for token(s) in `_ids` is lower than the respective amount(s) in `positive and negative values` sent to the recipient.\\n        MUST revert on any other error.\\n        MUST emit `TransferSingle` or `TransferBatch` event(s) such that all the balance changes are reflected (see \\\"Safe Transfer Rules\\\" section of the standard).\\n        Balance changes and events MUST follow the ordering of the arrays (_ids[0]/_values[0] before _ids[1]/_values[1], etc).\\n        After the above conditions for the transfer(s) in the batch are met, this function MUST check if `_to` is a smart contract (e.g. code size > 0). If so, it MUST call the relevant `ERC1155TokenReceiver` hook(s) on `_to` and act appropriately (see \\\"Safe Transfer Rules\\\" section of the standard).\\n    @param _from          The address of the sender.\\n    @param _to            The address of the receiver.\\n    @param _ids           The ids of the tokens.\\n    @param _from_supplies The supply of token values that will send the _from.\\n    @param _to_supplies   The supply of token values that will send the _from.\\n    @param _value_eth     The value of the ether.\\n    @param _nonce         The nonce.\\n    @param _signature    The signature of the _to address.\\n    @param _data    The data.\\n    @return None\\n    \\\"\\\"\\\"\\n    # Assert the value of the transaction is less than the balance of A.\\n\\n    assert _from == msg.sender or (self.operators[_from])[msg.sender], \\\"_from must be the sender or approved address\\\"\\n    assert _to != ZERO_ADDRESS, \\\"Destination address must be non-zero.\\\"\\n    assert self.noncesOf[_from][_nonce] == False, \\\"Nonce must be unused.\\\"\\n    assert _value_eth == msg.value, \\\"Sender has not provided enough ether.\\\"\\n\\n    for i in range(BATCH_SIZE):\\n       id: uint256 = _ids[i]\\n       if _from_supplies[i] > 0:\\n           assert _to_supplies[i] == 0\\n           assert self.balancesOf[_from][id] >= _from_supplies[i]\\n       else:\\n           assert _from_supplies[i] == 0\\n           assert self.balancesOf[_to][id] >= _to_supplies[i]\\n\\n    # Create hash from variables.\\n    hash: bytes32 = self._getHash(_from, _to, _ids, _from_supplies, _to_supplies, _value_eth, _nonce)\\n\\n    # Assert that the ecrecover(address,signature) returns true.\\n    recovered_to: address = self.ecrecoverSig(hash, _signature)\\n    assert recovered_to == _to, \\\"Signer does not match signature.\\\"\\n\\n    # Store the nonce\\n    self.noncesOf[msg.sender][_nonce] = True\\n\\n    # Update the balances\\n    for i in range(BATCH_SIZE):\\n        id: uint256 = _ids[i]\\n        if _from_supplies[i] > 0:\\n            self.balancesOf[_from][id] -= _from_supplies[i]\\n            self.balancesOf[_to][id] += _from_supplies[i]\\n        else:\\n            self.balancesOf[_from][id] += _to_supplies[i]\\n            self.balancesOf[_to][id] -= _to_supplies[i]\\n\\n    send(_to, msg.value)\\n\\n    log.TransferBatch(msg.sender, _from, _to, _ids, _from_supplies)\\n    log.TransferBatch(msg.sender, _to, _from, _ids, _to_supplies)\\n\\n\\n    if _to.is_contract:\\n        returnValue: bytes32 = ERC1155TokenReceiver(_to).onERC1155BatchReceived(msg.sender, _to, _ids, _from_supplies, _data)\\n        assert returnValue == method_id(\\\"onERC1155BatchReceived(address,address,uint256,uint256,bytes)\\\", bytes32)\\n    if _from.is_contract:\\n        returnValue: bytes32 = ERC1155TokenReceiver(_from).onERC1155BatchReceived(msg.sender, _from, _ids, _to_supplies, _data)\\n        assert returnValue == method_id(\\\"onERC1155BatchReceived(address,address,uint256,uint256,bytes)\\\", bytes32)\\n\\n\\n\\n@public\\n@payable\\ndef trade(_from: address, _to: address, _id: uint256, _from_supply: uint256, _to_supply: uint256, _value_eth: uint256, _nonce: uint256, _signature: bytes[65], _data: bytes[256]=\\\"\\\"):\\n    \\\"\\\"\\\"\\n    @notice Trade (atomically swap) tokens with tokens or eth.\\n    @dev Caller must be approved to manage the tokens being transferred out of the `_from` account (see \\\"Approval\\\" section of the standard).\\n        MUST revert if `_to` is the zero address.\\n        MUST revert if _from_supply > 0 and _to_supply > 0\\n        MUST revert if _value_eth != msg.value\\n        MUST revert if any of the balance(s) of the holder(s) for token(s) in `_id` is lower than the respective amount in `positive or negative value` sent to the recipient.\\n        MUST revert on any other error.\\n        MUST emit `TransferSingle` or `TransferBatch` event(s) such that all the balance changes are reflected (see \\\"Safe Transfer Rules\\\" section of the standard).\\n        Balance changes and events MUST follow the ordering of the arrays (_ids[0]/_values[0] before _ids[1]/_values[1], etc).\\n        After the above conditions for the transfer(s) in the batch are met, this function MUST check if `_to` is a smart contract (e.g. code size > 0). If so, it MUST call the relevant `ERC1155TokenReceiver` hook(s) on `_to` and act appropriately (see \\\"Safe Transfer Rules\\\" section of the standard).\\n    @param _from            The from address (seller of eth, potential receiver of tokens).\\n    @param _to              The receiver address (receiver of tokens).\\n    @param _id              The id of the token\\n    @param _from_supply     The change in value of token (for _from)\\n    @param _to_supply       The change in value of token (for _to)\\n    @param _value_eth       The value of the ETH sent to the _from address.\\n    @param _nonce           The nonce.\\n    @param _signature       The signature of the _to address.\\n    @param _data    The data.\\n    @return None\\n    \\\"\\\"\\\"\\n    # Assert the value of the transaction is less than the balance of A.\\n    assert _from == msg.sender or (self.operators[_from])[msg.sender]\\n    assert _to != ZERO_ADDRESS, \\\"Destination address must be non-zero.\\\"\\n    assert self.noncesOf[_from][_nonce] == False, \\\"Nonce must be unused.\\\"\\n    assert _value_eth == msg.value, \\\"Sender has not provided enough ether.\\\"\\n    if _from_supply > 0:\\n        assert _to_supply == 0\\n        assert self.balancesOf[_from][_id] >= _from_supply\\n    else:\\n        assert _from_supply == 0\\n        assert self.balancesOf[_to][_id] >= _to_supply\\n\\n    # Create hash from variables.\\n    hash: bytes32 = self._getSingleHash(_from, _to, _id, _from_supply, _to_supply, _value_eth, _nonce)\\n\\n    # Assert that the ecrecover(address,signature) returns true.\\n    recovered_to: address = self.ecrecoverSig(hash, _signature)\\n    assert recovered_to == _to, \\\"Signer does not match signature.\\\"\\n\\n    # Store the nonce\\n    self.noncesOf[msg.sender][_nonce] = True\\n\\n    # Update the balances\\n    if _from_supply > 0:\\n        self.balancesOf[_from][_id] -= _from_supply\\n        self.balancesOf[_to][_id] += _from_supply\\n    else:\\n        self.balancesOf[_from][_id] += _to_supply\\n        self.balancesOf[_to][_id] -= _to_supply\\n\\n    send(_to, msg.value)\\n\\n    log.TransferSingle(msg.sender, _from, _to, _id, _from_supply)\\n    log.TransferSingle(msg.sender, _to, _from, _id, _to_supply)\\n\\n    if _to.is_contract:\\n        returnValue: bytes32 = ERC1155TokenReceiver(_to).onERC1155Received(msg.sender, _to, _id, _from_supply, _data)\\n        assert returnValue == method_id(\\\"onERC1155BatchReceived(address,address,uint256,uint256,bytes)\\\", bytes32)\\n    if _from.is_contract:\\n        returnValue: bytes32 = ERC1155TokenReceiver(_from).onERC1155Received(msg.sender, _from, _id, _to_supply, _data)\\n        assert returnValue == method_id(\\\"onERC1155BatchReceived(address,address,uint256,uint256,bytes)\\\", bytes32)\\n\",\n  \"sourcePath\": \"/Users/aristotelistriantafyllidis/Documents/agents-research/erc1155/contracts/erc1155.vy\",\n  \"compiler\": {\n    \"name\": \"vyper\",\n    \"version\": \"0.1.0b12+commit.a01cdc8\"\n  },\n  \"networks\": {\n    \"1583918911727\": {\n      \"events\": {\n        \"0xc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62\": {\n          \"name\": \"TransferSingle\",\n          \"inputs\": [\n            {\n              \"type\": \"address\",\n              \"name\": \"_operator\",\n              \"indexed\": true\n            },\n            {\n              \"type\": \"address\",\n              \"name\": \"_from\",\n              \"indexed\": true\n            },\n            {\n              \"type\": \"address\",\n              \"name\": \"_to\",\n              \"indexed\": true\n            },\n            {\n              \"type\": \"uint256\",\n              \"name\": \"_id\",\n              \"indexed\": false\n            },\n            {\n              \"type\": \"uint256\",\n              \"name\": \"_value\",\n              \"indexed\": false\n            }\n          ],\n          \"anonymous\": false,\n          \"type\": \"event\",\n          \"signature\": \"0xc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62\"\n        },\n        \"0x514c24e4790d7c31a095a1688a73a01f28d936a9a85d806ba95970d8ee88efa8\": {\n          \"name\": \"TransferBatch\",\n          \"inputs\": [\n            {\n              \"type\": \"address\",\n              \"name\": \"_operator\",\n              \"indexed\": true\n            },\n            {\n              \"type\": \"address\",\n              \"name\": \"_from\",\n              \"indexed\": true\n            },\n            {\n              \"type\": \"address\",\n              \"name\": \"_to\",\n              \"indexed\": true\n            },\n            {\n              \"type\": \"uint256[10]\",\n              \"name\": \"_ids\",\n              \"indexed\": false\n            },\n            {\n              \"type\": \"uint256[10]\",\n              \"name\": \"_values\",\n              \"indexed\": false\n            }\n          ],\n          \"anonymous\": false,\n          \"type\": \"event\",\n          \"signature\": \"0x514c24e4790d7c31a095a1688a73a01f28d936a9a85d806ba95970d8ee88efa8\"\n        },\n        \"0x17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31\": {\n          \"name\": \"ApprovalForAll\",\n          \"inputs\": [\n            {\n              \"type\": \"address\",\n              \"name\": \"_owner\",\n              \"indexed\": true\n            },\n            {\n              \"type\": \"address\",\n              \"name\": \"_operator\",\n              \"indexed\": true\n            },\n            {\n              \"type\": \"bool\",\n              \"name\": \"_approved\",\n              \"indexed\": false\n            }\n          ],\n          \"anonymous\": false,\n          \"type\": \"event\",\n          \"signature\": \"0x17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31\"\n        },\n        \"0x6bb7ff708619ba0610cba295a58592e0451dee2622938c8755667688daf3529b\": {\n          \"name\": \"URI\",\n          \"inputs\": [\n            {\n              \"type\": \"string\",\n              \"name\": \"_value\",\n              \"indexed\": false\n            },\n            {\n              \"type\": \"uint256\",\n              \"name\": \"_id\",\n              \"indexed\": true\n            }\n          ],\n          \"anonymous\": false,\n          \"type\": \"event\",\n          \"signature\": \"0x6bb7ff708619ba0610cba295a58592e0451dee2622938c8755667688daf3529b\"\n        }\n      },\n      \"links\": {},\n      \"address\": \"0x9561C133DD8580860B6b7E504bC5Aa500f0f06a7\",\n      \"transactionHash\": \"0x816b272ebd644b189a3addfbd429b0ea0fa7b2403cca3aa038bcd59f09d9c116\"\n    }\n  },\n  \"schemaVersion\": \"3.0.19\",\n  \"updatedAt\": \"2020-03-11T13:47:51.885Z\",\n  \"networkType\": \"ethereum\"\n}"
  },
  {
    "path": "plugins/aea-ledger-cosmos/tests/data/dummy_contract/contract.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains a dummy contract for an AEA.\"\"\"\n\nfrom aea.contracts.base import Contract\nfrom aea.crypto.base import LedgerApi\n\n\nclass DummyContract(Contract):\n    \"\"\"The some contract class.\"\"\"\n\n    @classmethod\n    def some_method(cls, ledger_api: LedgerApi, contract_address: str) -> None:\n        \"\"\"Some method.\"\"\"\n        pass\n"
  },
  {
    "path": "plugins/aea-ledger-cosmos/tests/data/dummy_contract/contract.yaml",
    "content": "name: dummy\nauthor: fetchai\nversion: 0.1.0\ntype: contract\ndescription: A test contract\nlicense: Apache-2.0\naea_version: '>=0.9.0, <0.10.0'\nfingerprint:\n  __init__.py: QmWbNjFh6E5V4n2qBwyZyXZdmmHvcZSVnwKrcM34MAE56S\n  build/some.json: Qma5n7au2NDCg1nLwYfYnmFNwWChFuXtu65w5DV7wAZRvw\n  build/some.wasm: Qmc9gthbdwRSywinTHKjRVQdFzrKTxUuLDx2ryNfQp1xqf\n  contract.py: QmYfn2V3tXv7MCyhT5Kz5ArtX2FZWHC1jfeRmqCNsRxDL5\nfingerprint_ignore_patterns: []\nbuild_entrypoint: path/to/script.py\nclass_name: DummyContract\ncontract_interface_paths:\n  cosmos: build/some.wasm\n  ethereum: build/some.json\n  fetchai: build/some.wasm\ndependencies: {}\n"
  },
  {
    "path": "plugins/aea-ledger-cosmos/tests/test_cosmos.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the ethereum module.\"\"\"\nimport os\nimport shutil\nimport tempfile\nfrom pathlib import Path\nfrom unittest.mock import MagicMock, Mock, patch\nfrom uuid import uuid4\n\nimport pytest  # type:ignore\nfrom aea_ledger_cosmos import CosmosApi, CosmosCrypto, CosmosHelper\nfrom aea_ledger_cosmos.cosmos import _default_logger as cosmos_logger\n\nfrom tests.conftest import COSMOS_TESTNET_CONFIG, ROOT_DIR\n\n\n@pytest.fixture(scope=\"session\")\ndef cosmos_private_key_file():\n    \"\"\"Pytest fixture to create a temporary Cosmos private key file.\"\"\"\n    crypto = CosmosCrypto()\n    temp_dir = Path(tempfile.mkdtemp())\n    try:\n        temp_file = temp_dir / \"private.key\"\n        temp_file.write_text(crypto.private_key)\n        yield str(temp_file)\n    finally:\n        shutil.rmtree(temp_dir)\n\n\ndef test_creation(cosmos_private_key_file):\n    \"\"\"Test the creation of the crypto_objects.\"\"\"\n    assert CosmosCrypto(), \"Did not manage to initialise the crypto module\"\n    assert CosmosCrypto(\n        cosmos_private_key_file\n    ), \"Did not manage to load the cosmos private key\"\n\n\ndef test_key_file_encryption_decryption(cosmos_private_key_file):\n    \"\"\"Test cosmos private key encrypted and decrypted correctly.\"\"\"\n    cosmos = CosmosCrypto(cosmos_private_key_file)\n    pk_data = Path(cosmos_private_key_file).read_text()\n    password = uuid4().hex\n    encrypted_data = cosmos.encrypt(password)\n    decrypted_data = cosmos.decrypt(encrypted_data, password)\n    assert encrypted_data != pk_data\n    assert pk_data == decrypted_data\n\n    with pytest.raises(ValueError, match=\"Decrypt error! Bad password?\"):\n        cosmos.decrypt(encrypted_data, \"BaD_PassWord\")\n\n    with pytest.raises(ValueError, match=\"Bad encrypted key format!\"):\n        cosmos.decrypt(\"some_data\" * 16, \"BaD_PassWord\")\n\n\ndef test_initialization():\n    \"\"\"Test the initialisation of the variables.\"\"\"\n    account = CosmosCrypto()\n    assert account.entity is not None, \"The property must return the account.\"\n    assert (\n        account.address is not None\n    ), \"After creation the display address must not be None\"\n    assert account.address.startswith(\"cosmos\")\n    assert (\n        account.public_key is not None\n    ), \"After creation the public key must no be None\"\n\n\ndef test_sign_and_recover_message(cosmos_private_key_file):\n    \"\"\"Test the signing and the recovery of a message.\"\"\"\n    account = CosmosCrypto(cosmos_private_key_file)\n    sign_bytes = account.sign_message(message=b\"hello\")\n    assert len(sign_bytes) > 0, \"The len(signature) must not be 0\"\n    recovered_addresses = CosmosApi.recover_message(\n        message=b\"hello\", signature=sign_bytes\n    )\n    assert (\n        account.address in recovered_addresses\n    ), \"Failed to recover the correct address.\"\n\n\ndef test_sign_and_recover_message_public_key(cosmos_private_key_file):\n    \"\"\"Test the signing and the recovery function for the eth_crypto.\"\"\"\n    COSMOS_PRIVATE_KEY_PATH = os.path.join(\n        ROOT_DIR, \"tests\", \"data\", \"cosmos_private_key.txt\"\n    )\n    account = CosmosCrypto(COSMOS_PRIVATE_KEY_PATH)\n    sign_bytes = account.sign_message(message=b\"hello\")\n    assert len(sign_bytes) > 0, \"The len(signature) must not be 0\"\n    recovered_public_keys = CosmosApi.recover_public_keys_from_message(\n        message=b\"hello\", signature=sign_bytes\n    )\n    assert len(recovered_public_keys) == 2, \"Wrong number of public keys recovered.\"\n    assert (\n        CosmosApi.get_address_from_public_key(recovered_public_keys[0])\n        == account.address\n    ), \"Failed to recover the correct address.\"\n\n\ndef test_get_hash():\n    \"\"\"Test the get hash functionality.\"\"\"\n    expected_hash = \"2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824\"\n    hash_ = CosmosApi.get_hash(message=b\"hello\")\n    assert expected_hash == hash_\n\n\ndef test_dump_positive(cosmos_private_key_file):\n    \"\"\"Test dump.\"\"\"\n    account = CosmosCrypto(cosmos_private_key_file)\n    account.dump(MagicMock())\n\n\ndef test_api_creation():\n    \"\"\"Test api instantiation.\"\"\"\n    assert CosmosApi(**COSMOS_TESTNET_CONFIG), \"Failed to initialise the api\"\n\n\ndef test_api_none():\n    \"\"\"Test the \"api\" of the cryptoApi is none.\"\"\"\n    cosmos_api = CosmosApi(**COSMOS_TESTNET_CONFIG)\n    assert cosmos_api.api is None, \"The api property is not None.\"\n\n\ndef test_generate_nonce():\n    \"\"\"Test generate nonce.\"\"\"\n    nonce = CosmosApi.generate_tx_nonce(\n        seller=\"some_seller_addr\", client=\"some_buyer_addr\"\n    )\n    assert len(nonce) > 0 and int(\n        nonce, 16\n    ), \"The len(nonce) must not be 0 and must be hex\"\n\n\ndef test_validate_address():\n    \"\"\"Test the is_valid_address functionality.\"\"\"\n    account = CosmosCrypto()\n    assert CosmosApi.is_valid_address(account.address)\n    assert not CosmosApi.is_valid_address(account.address + \"wrong\")\n\n\ndef test_load_contract_interface():\n    \"\"\"Test the load_contract_interface method.\"\"\"\n    path = Path(ROOT_DIR, \"tests\", \"data\", \"dummy_contract\", \"build\", \"some.wasm\")\n    result = CosmosApi.load_contract_interface(path)\n    assert \"wasm_byte_code\" in result\n\n\ndef test_helper_is_settled():\n    \"\"\"Test CosmosHelper.is_transaction_settled.\"\"\"\n    assert CosmosHelper.is_transaction_settled({\"code\": None}) is True\n    with patch.object(cosmos_logger, \"warning\") as warning_mock:\n        assert CosmosHelper.is_transaction_settled({\"code\": \"some value\"}) is False\n        warning_mock.assert_called_once()\n\n\ndef test_helper_get_code_id():\n    \"\"\"Test CosmosHelper.is_transaction_settled.\"\"\"\n    assert (\n        CosmosHelper.get_code_id(\n            {\n                \"logs\": [\n                    {\n                        \"msg_index\": 0,\n                        \"log\": \"\",\n                        \"events\": [\n                            {\n                                \"type\": \"message\",\n                                \"attributes\": [\n                                    {\"key\": \"action\", \"value\": \"store-code\"},\n                                    {\"key\": \"module\", \"value\": \"wasm\"},\n                                    {\n                                        \"key\": \"signer\",\n                                        \"value\": \"fetch1pa7q6urt98dfe2rsvfaefj8zhh792sdfuzym2t\",\n                                    },\n                                    {\"key\": \"code_id\", \"value\": \"631\"},\n                                ],\n                            }\n                        ],\n                    }\n                ]\n            }\n        )\n        == 631\n    )\n\n\ndef test_helper_get_contract_address():\n    \"\"\"Test CosmosHelper.is_transaction_settled.\"\"\"\n    assert (\n        CosmosHelper.get_contract_address(\n            {\n                \"logs\": [\n                    {\n                        \"msg_index\": 0,\n                        \"log\": \"\",\n                        \"events\": [\n                            {\n                                \"type\": \"message\",\n                                \"attributes\": [\n                                    {\"key\": \"action\", \"value\": \"instantiate\"},\n                                    {\"key\": \"module\", \"value\": \"wasm\"},\n                                    {\n                                        \"key\": \"signer\",\n                                        \"value\": \"fetch1pa7q6urt98dfe2rsvfaefj8zhh792sdfuzym2t\",\n                                    },\n                                    {\"key\": \"code_id\", \"value\": \"631\"},\n                                    {\n                                        \"key\": \"_contract_address\",\n                                        \"value\": \"fetch1lhd5t8jdjn0n4q27hsah6c0907nxrswcp5l4nw\",\n                                    },\n                                ],\n                            }\n                        ],\n                    }\n                ]\n            }\n        )\n        == \"fetch1lhd5t8jdjn0n4q27hsah6c0907nxrswcp5l4nw\"\n    )\n\n\n@patch.object(\n    CosmosApi, \"_try_get_account_number_and_sequence\", return_value=(None, None)\n)\ndef test_cosmos_api_get_deploy_transaction(*args):\n    \"\"\"Test CosmosApi._get_deploy_transaction.\"\"\"\n    cosmos_api = CosmosApi()\n    assert cosmos_api.get_deploy_transaction(*[Mock()] * 2) is None\n\n\n@patch.object(\n    CosmosApi, \"_try_get_account_number_and_sequence\", return_value=(None, None)\n)\ndef test_cosmos_api_get_handle_transaction(*args):\n    \"\"\"Test CosmosApi.get_handle_transaction.\"\"\"\n    cosmos_api = CosmosApi()\n    assert cosmos_api.get_handle_transaction(*[Mock()] * 7) is None\n\n\n@patch.object(\n    CosmosApi, \"_try_get_account_number_and_sequence\", return_value=(None, None)\n)\ndef test_cosmos_api_get_transfer_transaction(*args):\n    \"\"\"Test CosmosApi.get_transfer_transaction.\"\"\"\n    cosmos_api = CosmosApi()\n    assert cosmos_api.get_transfer_transaction(*[Mock()] * 7) is None\n"
  },
  {
    "path": "plugins/aea-ledger-ethereum/LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright 2019 Fetch.AI Limited\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "plugins/aea-ledger-ethereum/MANIFEST.in",
    "content": "include README.md LICENSE HISTORY.md\n\nrecursive-include aea_ledger_ethereum\nrecursive-include tests *\n"
  },
  {
    "path": "plugins/aea-ledger-ethereum/README.md",
    "content": "# Ethereum crypto plug-in\n\nEthereum crypto plug-in for the AEA framework.\n\n## Install\n\n``` bash\npython setup.py install\n```\n\n## Run tests\n\n``` bash\npython setup.py test\n```\n"
  },
  {
    "path": "plugins/aea-ledger-ethereum/aea_ledger_ethereum/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Python package wrapping the public and private key cryptography and ledger api of Ethereum.\"\"\"\n\nfrom .ethereum import *  # noqa isort:skip\nfrom .ethereum import _ABI, _BYTECODE, _ETHEREUM  # noqa isort:skip\n"
  },
  {
    "path": "plugins/aea-ledger-ethereum/aea_ledger_ethereum/ethereum.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Ethereum module wrapping the public and private key cryptography and ledger api.\"\"\"\nimport json\nimport logging\nimport threading\nimport time\nimport warnings\nfrom pathlib import Path\nfrom typing import Any, Callable, Dict, List, Optional, Tuple, Union, cast\n\nimport ipfshttpclient  # noqa: F401 # pylint: disable=unused-import\nimport web3._utils.request\nfrom eth_account import Account\nfrom eth_account._utils.signing import to_standard_signature_bytes\nfrom eth_account.datastructures import HexBytes, SignedTransaction\nfrom eth_account.messages import _hash_eip191_message, encode_defunct\nfrom eth_keys import keys\nfrom eth_typing import HexStr\nfrom lru import LRU  # type: ignore  # pylint: disable=no-name-in-module\nfrom web3 import HTTPProvider, Web3\nfrom web3.datastructures import AttributeDict\nfrom web3.gas_strategies.rpc import rpc_gas_price_strategy\nfrom web3.types import TxData, TxParams, TxReceipt, Wei\n\nfrom aea.common import Address, JSONLike\nfrom aea.crypto.base import Crypto, FaucetApi, Helper, LedgerApi\nfrom aea.crypto.helpers import DecryptError, KeyIsIncorrect, hex_to_bytes_for_key\nfrom aea.exceptions import enforce\nfrom aea.helpers import http_requests as requests\nfrom aea.helpers.base import try_decorator\nfrom aea.helpers.io import open_file\n\n\n_default_logger = logging.getLogger(__name__)\n\n_ETHEREUM = \"ethereum\"\nTESTNET_NAME = \"ganache\"\nDEFAULT_ADDRESS = \"http://127.0.0.1:8545\"\nDEFAULT_CHAIN_ID = 1337\nDEFAULT_CURRENCY_DENOM = \"wei\"\nETH_GASSTATION_URL = \"https://ethgasstation.info/api/ethgasAPI.json\"\n_ABI = \"abi\"\n_BYTECODE = \"bytecode\"\n\n\ndef get_gas_price_strategy(\n    gas_price_strategy: Optional[str] = None, api_key: Optional[str] = None\n) -> Callable[[Web3, TxParams], Wei]:\n    \"\"\"Get the gas price strategy.\"\"\"\n    supported_gas_price_modes = [\"safeLow\", \"average\", \"fast\", \"fastest\"]\n    if gas_price_strategy is None:\n        _default_logger.debug(\n            \"Gas price strategy not provided. Falling back to `rpc_gas_price_strategy`.\"\n        )\n        return rpc_gas_price_strategy\n\n    if gas_price_strategy not in supported_gas_price_modes:\n        _default_logger.debug(\n            f\"Gas price strategy `{gas_price_strategy}` not in list of supported modes: {supported_gas_price_modes}. Falling back to `rpc_gas_price_strategy`.\"\n        )\n        return rpc_gas_price_strategy\n\n    if api_key is None:\n        _default_logger.debug(\n            \"No ethgasstation api key provided. Falling back to `rpc_gas_price_strategy`.\"\n        )\n        return rpc_gas_price_strategy\n\n    def gas_station_gas_price_strategy(  # pylint: disable=redefined-outer-name,unused-argument\n        web3: Web3, transaction_params: TxParams\n    ) -> Wei:\n        \"\"\"\n        Get gas price from Eth Gas Station api.\n\n        Visit `https://docs.ethgasstation.info/gas-price` for documentation.\n\n        :param web3: web3 instance\n        :param transaction_params: transaction parameters\n        :return: wei\n        \"\"\"\n        response = requests.get(f\"{ETH_GASSTATION_URL}?api-key={api_key}\")\n        if response.status_code != 200:\n            raise ValueError(  # pragma: nocover\n                f\"Gas station API response: {response.status_code}, {response.text}\"\n            )\n        response_dict = response.json()\n        _default_logger.debug(\"Gas station API response: {}\".format(response_dict))\n        result = response_dict.get(gas_price_strategy, None)\n        if type(result) not in [int, float]:  # pragma: nocover\n            raise ValueError(f\"Invalid return value for `{gas_price_strategy}`!\")\n        gwei_result = result / 10  # adjustment (see api documentation)\n        wei_result = web3.toWei(gwei_result, \"gwei\")\n        return Wei(wei_result)\n\n    return gas_station_gas_price_strategy\n\n\nclass SignedTransactionTranslator:\n    \"\"\"Translator for SignedTransaction.\"\"\"\n\n    @staticmethod\n    def to_dict(signed_transaction: SignedTransaction) -> Dict[str, Union[str, int]]:\n        \"\"\"Write SignedTransaction to dict.\"\"\"\n        signed_transaction_dict = {\n            \"raw_transaction\": signed_transaction.rawTransaction.hex(),\n            \"hash\": signed_transaction.hash.hex(),\n            \"r\": signed_transaction.r,\n            \"s\": signed_transaction.s,\n            \"v\": signed_transaction.v,\n        }\n        return signed_transaction_dict\n\n    @staticmethod\n    def from_dict(signed_transaction_dict: JSONLike) -> SignedTransaction:\n        \"\"\"Get SignedTransaction from dict.\"\"\"\n        if (\n            not isinstance(signed_transaction_dict, dict)\n            and len(signed_transaction_dict) == 5\n        ):\n            raise ValueError(  # pragma: nocover\n                f\"Invalid for conversion. Found object: {signed_transaction_dict}.\"\n            )\n        signed_transaction = SignedTransaction(\n            rawTransaction=HexBytes(signed_transaction_dict[\"raw_transaction\"]),\n            hash=HexBytes(signed_transaction_dict[\"hash\"]),\n            r=signed_transaction_dict[\"r\"],\n            s=signed_transaction_dict[\"s\"],\n            v=signed_transaction_dict[\"v\"],\n        )\n        return signed_transaction\n\n\nclass AttributeDictTranslator:\n    \"\"\"Translator for AttributeDict.\"\"\"\n\n    @classmethod\n    def _remove_hexbytes(cls, value: Any) -> Any:\n        \"\"\"Process value to remove hexbytes.\"\"\"\n        if value is None:\n            return value\n        if isinstance(value, HexBytes):\n            return value.hex()\n        if isinstance(value, list):\n            return cls._process_list(value, cls._remove_hexbytes)\n        if type(value) in (bool, int, float, str, bytes):\n            return value\n        if isinstance(value, AttributeDict):\n            return cls.to_dict(value)\n        raise NotImplementedError(  # pragma: nocover\n            f\"Unknown type conversion. Found type: {type(value)}\"\n        )\n\n    @classmethod\n    def _add_hexbytes(cls, value: Any) -> Any:\n        \"\"\"Process value to add hexbytes.\"\"\"\n        if value is None:\n            return value\n        if isinstance(value, str):\n            try:\n                int(value, 16)\n                return HexBytes(value)\n            except Exception:  # pylint: disable=broad-except\n                return value\n        if isinstance(value, list):\n            return cls._process_list(value, cls._add_hexbytes)\n        if isinstance(value, dict):\n            return cls.from_dict(value)\n        if type(value) in (bool, int, float, bytes):\n            return value\n        raise NotImplementedError(  # pragma: nocover\n            f\"Unknown type conversion. Found type: {type(value)}\"\n        )\n\n    @classmethod\n    def _process_list(cls, li: list, callable_name: Callable) -> List:\n        \"\"\"Simplify a list with process value.\"\"\"\n        return [callable_name(el) for el in li]\n\n    @classmethod\n    def _valid_key(cls, key: Any) -> str:\n        \"\"\"Check validity of key.\"\"\"\n        if isinstance(key, str):\n            return key\n        raise ValueError(\"Key must be string.\")  # pragma: nocover\n\n    @classmethod\n    def to_dict(cls, attr_dict: Union[AttributeDict, TxReceipt, TxData]) -> JSONLike:\n        \"\"\"Simplify to dict.\"\"\"\n        if not isinstance(attr_dict, AttributeDict):\n            raise ValueError(\"No AttributeDict provided.\")  # pragma: nocover\n        result = {\n            cls._valid_key(key): cls._remove_hexbytes(value)\n            for key, value in attr_dict.items()\n        }\n        return result\n\n    @classmethod\n    def from_dict(cls, di: JSONLike) -> AttributeDict:\n        \"\"\"Get back attribute dict.\"\"\"\n        if not isinstance(di, dict):\n            raise ValueError(\"No dict provided.\")  # pragma: nocover\n        processed_dict = {\n            cls._valid_key(key): cls._add_hexbytes(value) for key, value in di.items()\n        }\n        return AttributeDict(processed_dict)\n\n\nclass EthereumCrypto(Crypto[Account]):\n    \"\"\"Class wrapping the Account Generation from Ethereum ledger.\"\"\"\n\n    identifier = _ETHEREUM\n\n    def __init__(\n        self, private_key_path: Optional[str] = None, password: Optional[str] = None\n    ) -> None:\n        \"\"\"\n        Instantiate an ethereum crypto object.\n\n        :param private_key_path: the private key path of the agent\n        :param password: the password to encrypt/decrypt the private key.\n        \"\"\"\n        super().__init__(private_key_path=private_key_path, password=password)\n        bytes_representation = Web3.toBytes(hexstr=self.entity.key.hex())\n        self._public_key = str(keys.PrivateKey(bytes_representation).public_key)\n        self._address = str(self.entity.address)\n\n    @property\n    def private_key(self) -> str:\n        \"\"\"\n        Return a private key.\n\n        :return: a private key string\n        \"\"\"\n        return self.entity.key.hex()\n\n    @property\n    def public_key(self) -> str:\n        \"\"\"\n        Return a public key in hex format.\n\n        :return: a public key string in hex format\n        \"\"\"\n        return self._public_key\n\n    @property\n    def address(self) -> str:\n        \"\"\"\n        Return the address for the key pair.\n\n        :return: a display_address str\n        \"\"\"\n        return self._address\n\n    @classmethod\n    def load_private_key_from_path(\n        cls, file_name: str, password: Optional[str] = None\n    ) -> Account:\n        \"\"\"\n        Load a private key in hex format from a file.\n\n        :param file_name: the path to the hex file.\n        :param password: the password to encrypt/decrypt the private key.\n        :return: the Entity.\n        \"\"\"\n        private_key = cls.load(file_name, password)\n        try:\n            if not private_key.startswith(\"0x\"):\n                hex_to_bytes_for_key(private_key)\n        except KeyIsIncorrect as e:\n            if not password:\n                raise KeyIsIncorrect(\n                    f\"Error on key `{file_name}` load! Try to specify `password`: Error: {repr(e)} \"\n                ) from e\n            raise KeyIsIncorrect(\n                f\"Error on key `{file_name}` load! Wrong password?: Error: {repr(e)} \"\n            ) from e\n\n        account = Account.from_key(  # pylint: disable=no-value-for-parameter\n            private_key=private_key\n        )\n        return account\n\n    def sign_message(self, message: bytes, is_deprecated_mode: bool = False) -> str:\n        \"\"\"\n        Sign a message in bytes string form.\n\n        :param message: the message to be signed\n        :param is_deprecated_mode: if the deprecated signing is used\n        :return: signature of the message in string form\n        \"\"\"\n        if is_deprecated_mode and len(message) == 32:\n            with warnings.catch_warnings():\n                warnings.simplefilter(\"ignore\")\n                signature_dict = self.entity.signHash(message)\n            signed_msg = signature_dict[\"signature\"].hex()\n        else:\n            signable_message = encode_defunct(primitive=message)\n            signature = self.entity.sign_message(signable_message=signable_message)\n            signed_msg = signature[\"signature\"].hex()\n        return signed_msg\n\n    def sign_transaction(self, transaction: JSONLike) -> JSONLike:\n        \"\"\"\n        Sign a transaction in bytes string form.\n\n        :param transaction: the transaction to be signed\n        :return: signed transaction\n        \"\"\"\n        signed_transaction = self.entity.sign_transaction(transaction_dict=transaction)\n        #  Note: self.entity.signTransaction(transaction_dict=transaction) == signed_transaction # noqa: E800\n        signed_transaction_dict = SignedTransactionTranslator.to_dict(\n            signed_transaction\n        )\n        return cast(JSONLike, signed_transaction_dict)\n\n    @classmethod\n    def generate_private_key(cls) -> Account:\n        \"\"\"Generate a key pair for ethereum network.\"\"\"\n        account = Account.create()  # pylint: disable=no-value-for-parameter\n        return account\n\n    def encrypt(self, password: str) -> str:\n        \"\"\"\n        Encrypt the private key and return in json.\n\n        :param password: the password to decrypt.\n        :return: json string containing encrypted private key.\n        \"\"\"\n        encrypted = Account.encrypt(self.private_key, password)\n        return json.dumps(encrypted)\n\n    @classmethod\n    def decrypt(cls, keyfile_json: str, password: str) -> str:\n        \"\"\"\n        Decrypt the private key and return in raw form.\n\n        :param keyfile_json: json str containing encrypted private key.\n        :param password: the password to decrypt.\n        :return: the raw private key.\n        \"\"\"\n        try:\n            private_key = Account.decrypt(keyfile_json, password)\n        except ValueError as e:\n            if e.args[0] == \"MAC mismatch\":\n                raise DecryptError() from e\n            raise\n        return private_key.hex()[2:]\n\n\nclass EthereumHelper(Helper):\n    \"\"\"Helper class usable as Mixin for EthereumApi or as standalone class.\"\"\"\n\n    @staticmethod\n    def is_transaction_settled(tx_receipt: JSONLike) -> bool:\n        \"\"\"\n        Check whether a transaction is settled or not.\n\n        :param tx_receipt: the receipt associated to the transaction.\n        :return: True if the transaction has been settled, False o/w.\n        \"\"\"\n        is_successful = False\n        if tx_receipt is not None:\n            is_successful = tx_receipt.get(\"status\", 0) == 1\n        return is_successful\n\n    @staticmethod\n    def get_contract_address(tx_receipt: JSONLike) -> Optional[str]:\n        \"\"\"\n        Retrieve the `contract_address` from a transaction receipt.\n\n        :param tx_receipt: the receipt of the transaction.\n        :return: the contract address, if present\n        \"\"\"\n        contract_address = cast(Optional[str], tx_receipt.get(\"contractAddress\", None))\n        return contract_address\n\n    @staticmethod\n    def is_transaction_valid(\n        tx: dict,\n        seller: Address,\n        client: Address,\n        tx_nonce: str,\n        amount: int,\n    ) -> bool:\n        \"\"\"\n        Check whether a transaction is valid or not.\n\n        :param tx: the transaction.\n        :param seller: the address of the seller.\n        :param client: the address of the client.\n        :param tx_nonce: the transaction nonce.\n        :param amount: the amount we expect to get from the transaction.\n        :return: True if the random_message is equals to tx['input']\n        \"\"\"\n        is_valid = False\n        if tx is not None:\n            is_valid = (\n                tx.get(\"input\") == tx_nonce\n                and tx.get(\"value\") == amount\n                and tx.get(\"from\") == client\n                and tx.get(\"to\") == seller\n            )\n        return is_valid\n\n    @staticmethod\n    def generate_tx_nonce(seller: Address, client: Address) -> str:\n        \"\"\"\n        Generate a unique hash to distinguish transactions with the same terms.\n\n        :param seller: the address of the seller.\n        :param client: the address of the client.\n        :return: return the hash in hex.\n        \"\"\"\n        time_stamp = int(time.time())\n        aggregate_hash = Web3.keccak(\n            b\"\".join([seller.encode(), client.encode(), time_stamp.to_bytes(32, \"big\")])\n        )\n        return aggregate_hash.hex()\n\n    @classmethod\n    def get_address_from_public_key(cls, public_key: str) -> str:\n        \"\"\"\n        Get the address from the public key.\n\n        :param public_key: the public key\n        :return: str\n        \"\"\"\n        keccak_hash = Web3.keccak(hexstr=public_key)\n        raw_address = keccak_hash[-20:].hex().upper()\n        address = Web3.toChecksumAddress(raw_address)\n        return address\n\n    @classmethod\n    def recover_message(\n        cls, message: bytes, signature: str, is_deprecated_mode: bool = False\n    ) -> Tuple[Address, ...]:\n        \"\"\"\n        Recover the addresses from the hash.\n\n        :param message: the message we expect\n        :param signature: the transaction signature\n        :param is_deprecated_mode: if the deprecated signing was used\n        :return: the recovered addresses\n        \"\"\"\n        if is_deprecated_mode:\n            enforce(len(message) == 32, \"Message must be hashed to exactly 32 bytes.\")\n            with warnings.catch_warnings():\n                warnings.simplefilter(\"ignore\")\n                address = Account.recoverHash(  # pylint: disable=no-value-for-parameter\n                    message_hash=message, signature=signature\n                )\n        else:\n            signable_message = encode_defunct(primitive=message)\n            address = Account.recover_message(  # pylint: disable=no-value-for-parameter\n                signable_message=signable_message, signature=signature\n            )\n        return (address,)\n\n    @classmethod\n    def recover_public_keys_from_message(\n        cls, message: bytes, signature: str, is_deprecated_mode: bool = False\n    ) -> Tuple[str, ...]:\n        \"\"\"\n        Get the public key used to produce the `signature` of the `message`\n\n        :param message: raw bytes used to produce signature\n        :param signature: signature of the message\n        :param is_deprecated_mode: if the deprecated signing was used\n        :return: the recovered public keys\n        \"\"\"\n        if not is_deprecated_mode:\n            signable_message = encode_defunct(primitive=message)\n            message = _hash_eip191_message(signable_message)\n        hash_bytes = HexBytes(message)\n        # code taken from https://github.com/ethereum/eth-account/blob/master/eth_account/account.py#L428\n        if len(hash_bytes) != 32:  # pragma: nocover\n            raise ValueError(\"The message hash must be exactly 32-bytes\")\n        signature_bytes = HexBytes(signature)\n        signature_bytes_standard = to_standard_signature_bytes(signature_bytes)\n        signature_obj = keys.Signature(signature_bytes=signature_bytes_standard)\n        pubkey = signature_obj.recover_public_key_from_msg_hash(hash_bytes)\n        return (str(pubkey),)\n\n    @staticmethod\n    def get_hash(message: bytes) -> str:\n        \"\"\"\n        Get the hash of a message.\n\n        :param message: the message to be hashed.\n        :return: the hash of the message.\n        \"\"\"\n        digest = Web3.keccak(message).hex()\n        return digest\n\n    @classmethod\n    def load_contract_interface(cls, file_path: Path) -> Dict[str, str]:\n        \"\"\"\n        Load contract interface.\n\n        :param file_path: the file path to the interface\n        :return: the interface\n        \"\"\"\n        with open_file(file_path, \"r\") as interface_file_ethereum:\n            contract_interface = json.load(interface_file_ethereum)\n        for key in [_ABI, _BYTECODE]:\n            if key not in contract_interface:  # pragma: nocover\n                raise ValueError(f\"Contract {file_path} missing key {key}.\")\n        return contract_interface\n\n\nclass EthereumApi(LedgerApi, EthereumHelper):\n    \"\"\"Class to interact with the Ethereum Web3 APIs.\"\"\"\n\n    identifier = _ETHEREUM\n\n    def __init__(self, **kwargs: Any):\n        \"\"\"\n        Initialize the Ethereum ledger APIs.\n\n        :param kwargs: keyword arguments\n        \"\"\"\n        self._api = Web3(\n            HTTPProvider(endpoint_uri=kwargs.pop(\"address\", DEFAULT_ADDRESS))\n        )\n        self._chain_id = kwargs.pop(\"chain_id\", DEFAULT_CHAIN_ID)\n        self._gas_price_api_key = kwargs.pop(\"gas_price_api_key\", None)\n\n    @property\n    def api(self) -> Web3:\n        \"\"\"Get the underlying API object.\"\"\"\n        return self._api\n\n    def get_balance(self, address: Address) -> Optional[int]:\n        \"\"\"Get the balance of a given account.\"\"\"\n        return self._try_get_balance(address)\n\n    @try_decorator(\"Unable to retrieve balance: {}\", logger_method=\"warning\")\n    def _try_get_balance(self, address: Address) -> Optional[int]:\n        \"\"\"Get the balance of a given account.\"\"\"\n        check_address = self._api.toChecksumAddress(address)\n        return self._api.eth.getBalance(check_address)  # pylint: disable=no-member\n\n    def get_state(\n        self, callable_name: str, *args: Any, **kwargs: Any\n    ) -> Optional[JSONLike]:\n        \"\"\"Call a specified function on the ledger API.\"\"\"\n        response = self._try_get_state(callable_name, *args, **kwargs)\n        return response\n\n    @try_decorator(\"Unable to get state: {}\", logger_method=\"warning\")\n    def _try_get_state(  # pylint: disable=unused-argument\n        self, callable_name: str, *args: Any, **kwargs: Any\n    ) -> Optional[JSONLike]:\n        \"\"\"Try to call a function on the ledger API.\"\"\"\n\n        function = getattr(self._api.eth, callable_name)\n        response = function(*args, **kwargs)\n\n        if isinstance(response, AttributeDict):\n            result = AttributeDictTranslator.to_dict(response)\n            return result\n\n        if type(response) in (int, float, bytes, str, list, dict):  # pragma: nocover\n            # missing full checks for nested objects\n            return {f\"{callable_name}_result\": response}\n        raise NotImplementedError(  # pragma: nocover\n            f\"Response must be of types=int, float, bytes, str, list, dict. Found={type(response)}.\"\n        )\n\n    def get_transfer_transaction(  # pylint: disable=arguments-differ\n        self,\n        sender_address: Address,\n        destination_address: Address,\n        amount: int,\n        tx_fee: int,\n        tx_nonce: str,\n        chain_id: Optional[int] = None,\n        gas_price: Optional[str] = None,\n        gas_price_strategy: Optional[str] = None,\n        **kwargs: Any,\n    ) -> Optional[JSONLike]:\n        \"\"\"\n        Submit a transfer transaction to the ledger.\n\n        :param sender_address: the sender address of the payer.\n        :param destination_address: the destination address of the payee.\n        :param amount: the amount of wealth to be transferred (in Wei).\n        :param tx_fee: the transaction fee (gas) to be used (in Wei).\n        :param tx_nonce: verifies the authenticity of the tx.\n        :param chain_id: the Chain ID of the Ethereum transaction.\n        :param gas_price: the gas price (in Wei)\n        :param gas_price_strategy: the gas price strategy to be used.\n        :param kwargs: keyword arguments\n        :return: the transfer transaction\n        \"\"\"\n        transaction: Optional[JSONLike] = None\n        chain_id = chain_id if chain_id is not None else self._chain_id\n        gas_price = (\n            self._try_get_gas_price(gas_price_strategy)\n            if gas_price is None\n            else gas_price\n        )\n        if gas_price is None:\n            return transaction  # pragma: nocover\n        nonce = self._try_get_transaction_count(sender_address)\n        if nonce is None:\n            return transaction\n        transaction = {\n            \"nonce\": nonce,\n            \"chainId\": chain_id,\n            \"to\": destination_address,\n            \"value\": amount,\n            \"gas\": tx_fee,\n            \"gasPrice\": gas_price,\n            \"data\": tx_nonce,\n        }\n        transaction = self.update_with_gas_estimate(transaction)\n        return transaction\n\n    @try_decorator(\"Unable to retrieve gas price: {}\", logger_method=\"warning\")\n    def _try_get_gas_price(\n        self, gas_price_strategy: Optional[str] = None\n    ) -> Optional[int]:\n        \"\"\"Try get the gas price based on the provided strategy.\"\"\"\n        gas_price_strategy_callable = get_gas_price_strategy(\n            gas_price_strategy, self._gas_price_api_key\n        )\n        prior_strategy = self._api.eth.gasPriceStrategy\n        try:\n            self._api.eth.setGasPriceStrategy(gas_price_strategy_callable)\n            gas_price = self._api.eth.generateGasPrice()\n        finally:\n            if prior_strategy is not None:\n                self._api.eth.setGasPriceStrategy(prior_strategy)  # pragma: nocover\n        return gas_price\n\n    @try_decorator(\"Unable to retrieve transaction count: {}\", logger_method=\"warning\")\n    def _try_get_transaction_count(self, address: Address) -> Optional[int]:\n        \"\"\"Try get the transaction count.\"\"\"\n        nonce = self._api.eth.getTransactionCount(  # pylint: disable=no-member\n            self._api.toChecksumAddress(address)\n        )\n        return nonce\n\n    def update_with_gas_estimate(self, transaction: JSONLike) -> JSONLike:\n        \"\"\"\n        Attempts to update the transaction with a gas estimate\n\n        :param transaction: the transaction\n        :return: the updated transaction\n        \"\"\"\n        gas_estimate = self._try_get_gas_estimate(transaction)\n        if gas_estimate is not None:\n            specified_gas = transaction[\"gas\"]\n            if specified_gas < gas_estimate:\n                # eventually; there should be some specifiable strategy\n                _default_logger.warning(  # pragma: nocover\n                    f\"Needed to increase gas to cover the gas consumption of the transaction. Estimated gas consumption is: {gas_estimate}. Specified gas was: {specified_gas}.\"\n                )\n            transaction[\"gas\"] = gas_estimate\n        return transaction\n\n    @try_decorator(\"Unable to retrieve gas estimate: {}\", logger_method=\"warning\")\n    def _try_get_gas_estimate(self, transaction: JSONLike) -> Optional[int]:\n        \"\"\"Try get the gas estimate.\"\"\"\n        gas_estimate = self._api.eth.estimateGas(  # pylint: disable=no-member\n            transaction=cast(TxParams, AttributeDictTranslator.from_dict(transaction))\n        )\n        return gas_estimate\n\n    def send_signed_transaction(self, tx_signed: JSONLike) -> Optional[str]:\n        \"\"\"\n        Send a signed transaction and wait for confirmation.\n\n        :param tx_signed: the signed transaction\n        :return: tx_digest, if present\n        \"\"\"\n        tx_digest = self._try_send_signed_transaction(tx_signed)\n        return tx_digest\n\n    @try_decorator(\"Unable to send transaction: {}\", logger_method=\"warning\")\n    def _try_send_signed_transaction(self, tx_signed: JSONLike) -> Optional[str]:\n        \"\"\"\n        Try send a signed transaction.\n\n        :param tx_signed: the signed transaction\n        :return: tx_digest, if present\n        \"\"\"\n        signed_transaction = SignedTransactionTranslator.from_dict(tx_signed)\n        hex_value = self._api.eth.sendRawTransaction(  # pylint: disable=no-member\n            signed_transaction.rawTransaction\n        )\n        tx_digest = hex_value.hex()\n        _default_logger.debug(\n            \"Successfully sent transaction with digest: {}\".format(tx_digest)\n        )\n        return tx_digest\n\n    def get_transaction_receipt(self, tx_digest: str) -> Optional[JSONLike]:\n        \"\"\"\n        Get the transaction receipt for a transaction digest.\n\n        :param tx_digest: the digest associated to the transaction.\n        :return: the tx receipt, if present\n        \"\"\"\n        tx_receipt = self._try_get_transaction_receipt(tx_digest)\n        return tx_receipt\n\n    @try_decorator(\n        \"Error when attempting getting tx receipt: {}\", logger_method=\"debug\"\n    )\n    def _try_get_transaction_receipt(self, tx_digest: str) -> Optional[JSONLike]:\n        \"\"\"\n        Try get the transaction receipt.\n\n        :param tx_digest: the digest associated to the transaction.\n        :return: the tx receipt, if present\n        \"\"\"\n        tx_receipt = self._api.eth.getTransactionReceipt(  # pylint: disable=no-member\n            cast(HexStr, tx_digest)\n        )\n        return AttributeDictTranslator.to_dict(tx_receipt)\n\n    def get_transaction(self, tx_digest: str) -> Optional[JSONLike]:\n        \"\"\"\n        Get the transaction for a transaction digest.\n\n        :param tx_digest: the digest associated to the transaction.\n        :return: the tx, if present\n        \"\"\"\n        tx = self._try_get_transaction(tx_digest)\n        return tx\n\n    @try_decorator(\"Error when attempting getting tx: {}\", logger_method=\"debug\")\n    def _try_get_transaction(self, tx_digest: str) -> Optional[JSONLike]:\n        \"\"\"\n        Get the transaction.\n\n        :param tx_digest: the transaction digest.\n        :return: the tx, if found\n        \"\"\"\n        tx = self._api.eth.getTransaction(\n            cast(HexStr, tx_digest)\n        )  # pylint: disable=no-member\n        return AttributeDictTranslator.to_dict(tx)\n\n    def get_contract_instance(\n        self, contract_interface: Dict[str, str], contract_address: Optional[str] = None\n    ) -> Any:\n        \"\"\"\n        Get the instance of a contract.\n\n        :param contract_interface: the contract interface.\n        :param contract_address: the contract address.\n        :return: the contract instance\n        \"\"\"\n        if contract_address is None:\n            instance = self.api.eth.contract(\n                abi=contract_interface[_ABI],\n                bytecode=contract_interface[_BYTECODE],\n            )\n        else:\n            _contract_address = self.api.toChecksumAddress(contract_address)\n            instance = self.api.eth.contract(  # type: ignore\n                address=_contract_address,\n                abi=contract_interface[_ABI],\n                bytecode=contract_interface[_BYTECODE],\n            )\n        return instance\n\n    def get_deploy_transaction(  # pylint: disable=arguments-differ\n        self,\n        contract_interface: Dict[str, str],\n        deployer_address: Address,\n        value: int = 0,\n        gas: int = 0,\n        gas_price: Optional[str] = None,\n        gas_price_strategy: Optional[str] = None,\n        **kwargs: Any,\n    ) -> Optional[JSONLike]:\n        \"\"\"\n        Get the transaction to deploy the smart contract.\n\n        :param contract_interface: the contract interface.\n        :param deployer_address: The address that will deploy the contract.\n        :param value: value to send to contract (in Wei)\n        :param gas: the gas to be used (in Wei)\n        :param gas_price: the gas price (in Wei)\n        :param gas_price_strategy: the gas price strategy to be used.\n        :param kwargs: keyword arguments\n        :return: the transaction dictionary.\n        \"\"\"\n        transaction: Optional[JSONLike] = None\n        _deployer_address = self.api.toChecksumAddress(deployer_address)\n        nonce = self.api.eth.getTransactionCount(_deployer_address)\n        if nonce is None:\n            return transaction\n        gas_price = (\n            self._try_get_gas_price(gas_price_strategy)\n            if gas_price is None\n            else gas_price\n        )\n        if gas_price is None:\n            return transaction  # pragma: nocover\n        instance = self.get_contract_instance(contract_interface)\n        data = instance.constructor(**kwargs).buildTransaction().get(\"data\", \"0x\")\n        transaction = {\n            \"from\": _deployer_address,  # only 'from' address, don't insert 'to' address!\n            \"value\": value,\n            \"gas\": gas,\n            \"gasPrice\": gas_price,\n            \"nonce\": nonce,\n            \"data\": data,\n        }\n        transaction = self.update_with_gas_estimate(transaction)\n        return transaction\n\n    @classmethod\n    def is_valid_address(cls, address: Address) -> bool:\n        \"\"\"\n        Check if the address is valid.\n\n        :param address: the address to validate\n        :return: whether the address is valid\n        \"\"\"\n        return Web3.isAddress(address)\n\n\nclass EthereumFaucetApi(FaucetApi):\n    \"\"\"Ethereum testnet faucet API.\"\"\"\n\n    identifier = _ETHEREUM\n    testnet_name = TESTNET_NAME\n\n    def get_wealth(self, address: Address, url: Optional[str] = None) -> None:\n        \"\"\"\n        Get wealth from the faucet for the provided address.\n\n        :param address: the address.\n        :param url: the url\n        \"\"\"\n        self._try_get_wealth(address, url)\n\n    @staticmethod\n    @try_decorator(\n        \"An error occured while attempting to generate wealth:\\n{}\",\n        logger_method=\"error\",\n    )\n    def _try_get_wealth(address: Address, url: Optional[str] = None) -> None:\n        \"\"\"\n        Get wealth from the faucet for the provided address.\n\n        :param address: the address.\n        :param url: the url\n        \"\"\"\n        if url is None:\n            raise ValueError(  # pragma: nocover\n                \"Url is none, no default url provided. Please provide a faucet url.\"\n            )\n        response = requests.get(url + address)\n        if response.status_code // 100 == 5:  # pragma: no cover\n            _default_logger.error(\"Response: {}\".format(response.status_code))\n        elif response.status_code // 100 in [3, 4]:  # pragma: nocover\n            response_dict = json.loads(response.text)\n            _default_logger.warning(\n                \"Response: {}\\nMessage: {}\".format(\n                    response.status_code, response_dict.get(\"message\")\n                )\n            )\n        elif response.status_code // 100 == 2:  # pragma: no cover\n            response_dict = json.loads(response.text)\n            _default_logger.info(\n                \"Response: {}\\nMessage: {}\".format(\n                    response.status_code, response_dict.get(\"message\")\n                )\n            )\n\n\nclass LruLockWrapper:\n    \"\"\"Wrapper for LRU with threading.Lock.\"\"\"\n\n    def __init__(self, lru: LRU) -> None:\n        \"\"\"Init wrapper.\"\"\"\n        self.lru = lru\n        self.lock = threading.Lock()\n\n    def __getitem__(self, *args: Any, **kwargs: Any) -> Any:\n        \"\"\"Get item\"\"\"\n        with self.lock:\n            return self.lru.__getitem__(*args, **kwargs)\n\n    def __setitem__(self, *args: Any, **kwargs: Any) -> Any:\n        \"\"\"Set item.\"\"\"\n        with self.lock:\n            return self.lru.__setitem__(*args, **kwargs)\n\n    def __contains__(self, *args: Any, **kwargs: Any) -> Any:\n        \"\"\"Contain item.\"\"\"\n        with self.lock:\n            return self.lru.__contains__(*args, **kwargs)\n\n    def __delitem__(self, *args: Any, **kwargs: Any) -> Any:\n        \"\"\"Del item.\"\"\"\n        with self.lock:\n            return self.lru.__delitem__(*args, **kwargs)\n\n\ndef set_wrapper_for_web3py_session_cache() -> None:\n    \"\"\"Wrap web3py session cache with threading.Lock.\"\"\"\n\n    # pylint: disable=protected-access\n    web3._utils.request._session_cache = LruLockWrapper(\n        web3._utils.request._session_cache\n    )\n\n\nset_wrapper_for_web3py_session_cache()\n"
  },
  {
    "path": "plugins/aea-ledger-ethereum/pyproject.toml",
    "content": "[build-system]\nrequires = [\"setuptools\", \"wheel\"]\nbuild_backend = \"setuptools.build_meta\"\n"
  },
  {
    "path": "plugins/aea-ledger-ethereum/setup.py",
    "content": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Setup script for \"aea_ledger_ethereum\" package.\"\"\"\n\nfrom setuptools import find_packages, setup\n\n\nsetup(\n    name=\"aea-ledger-ethereum\",\n    version=\"1.1.2\",\n    author=\"Fetch.AI Limited\",\n    license=\"Apache-2.0\",\n    description=\"Python package wrapping the public and private key cryptography and ledger api of Ethereum.\",\n    packages=find_packages(include=[\"aea_ledger_ethereum*\"]),\n    install_requires=[\n        \"aea>=1.0.0, <2.0.0\",\n        \"web3==5.31.1\",\n        \"ipfshttpclient==0.8.0a2\",\n    ],\n    tests_require=[\"pytest\"],\n    entry_points={\n        \"aea.cryptos\": [\"ethereum = aea_ledger_ethereum:EthereumCrypto\"],\n        \"aea.ledger_apis\": [\"ethereum = aea_ledger_ethereum:EthereumApi\"],\n        \"aea.faucet_apis\": [\"ethereum = aea_ledger_ethereum:EthereumFaucetApi\"],\n    },\n    classifiers=[\n        \"Environment :: Console\",\n        \"Environment :: Web Environment\",\n        \"Development Status :: 5 - Production/Stable\",\n        \"Intended Audience :: Developers\",\n        \"License :: OSI Approved :: Apache Software License\",\n        \"Natural Language :: English\",\n        \"Operating System :: MacOS\",\n        \"Operating System :: Microsoft\",\n        \"Operating System :: Unix\",\n        \"Programming Language :: Python :: 3.6\",\n        \"Programming Language :: Python :: 3.7\",\n        \"Programming Language :: Python :: 3.8\",\n        \"Programming Language :: Python :: 3.9\",\n        \"Topic :: Communications\",\n        \"Topic :: Internet\",\n        \"Topic :: Software Development\",\n    ],\n)\n"
  },
  {
    "path": "plugins/aea-ledger-ethereum/tests/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Tests for the aea_ledger_ethereum package.\"\"\"\n"
  },
  {
    "path": "plugins/aea-ledger-ethereum/tests/conftest.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Conftest module for Pytest.\"\"\"\nimport inspect\nimport logging\nimport os\nimport platform\nimport shutil\nimport tempfile\nimport time\nfrom functools import wraps\nfrom pathlib import Path\nfrom typing import Callable, Generator\n\nimport docker\nimport pytest\nfrom aea_ledger_ethereum import EthereumCrypto\n\nfrom aea.configurations.constants import PRIVATE_KEY_PATH_SCHEMA\n\nfrom tests.docker_image import DockerImage, GanacheDockerImage\n\n\nCUR_PATH = os.path.dirname(inspect.getfile(inspect.currentframe()))  # type: ignore\nROOT_DIR = os.path.join(CUR_PATH, \"..\")\nMAX_FLAKY_RERUNS = 3\nETHEREUM = EthereumCrypto.identifier\n\nETHEREUM_PRIVATE_KEY_FILE = PRIVATE_KEY_PATH_SCHEMA.format(ETHEREUM)\nETHEREUM_PRIVATE_KEY_PATH = os.path.join(\n    ROOT_DIR, \"tests\", \"data\", ETHEREUM_PRIVATE_KEY_FILE\n)\n\nETHEREUM_DEFAULT_ADDRESS = \"http://127.0.0.1:8545\"\nETHEREUM_DEFAULT_CHAIN_ID = 1337\nETHEREUM_DEFAULT_CURRENCY_DENOM = \"wei\"\nETHEREUM_TESTNET_CONFIG = {\"address\": ETHEREUM_DEFAULT_ADDRESS}\n\n# URL to local Ganache instance\nDEFAULT_GANACHE_ADDR = \"http://127.0.0.1\"\nDEFAULT_GANACHE_PORT = 8545\nDEFAULT_GANACHE_CHAIN_ID = 1337\nGAS_PRICE_API_KEY = \"\"\n\nDEFAULT_AMOUNT = 1000000000000000000000\nFUNDED_ETH_PRIVATE_KEY_1 = (\n    \"0xa337a9149b4e1eafd6c21c421254cf7f98130233595db25f0f6f0a545fb08883\"\n)\nFUNDED_ETH_PRIVATE_KEY_2 = (\n    \"0x04b4cecf78288f2ab09d1b4c60219556928f86220f0fb2dcfc05e6a1c1149dbf\"\n)\nFUNDED_ETH_PRIVATE_KEY_3 = (\n    \"0x6F611408F7EF304947621C51A4B7D84A13A2B9786E9F984DA790A096E8260C64\"\n)\n\nlogger = logging.getLogger(__name__)\n\n\ndef action_for_platform(platform_name: str, skip: bool = True) -> Callable:\n    \"\"\"\n    Decorate a pytest class or method to skip on certain platform.\n\n    :param platform_name: check `platform.system()` for available platforms.\n    :param skip: if True, the test will be skipped; if False, the test will be run ONLY on the chosen platform.\n    :return: decorated object\n    \"\"\"\n\n    # for docstyle.\n    def decorator(pytest_func):\n        \"\"\"\n        For the sake of clarity, assume the chosen platform for the action is \"Windows\".\n\n        If the following condition is true:\n          - the current system is not Windows (is_different) AND we want to skip it (skip)\n         OR\n          - the current system is Windows (not is_different) AND we want to run only on it (not skip)\n        we run the test, else we skip the test.\n\n        logically, the condition is a boolean equivalence\n        between the variables \"is_different\" and \"skip\"\n        Hence, the condition becomes:\n\n        :param pytest_func: the pytest function to wrap\n        :return: the wrapped function\n        \"\"\"\n        is_different = platform.system() != platform_name\n        if is_different is skip:\n            return pytest_func\n\n        def action(*args, **kwargs):\n            if skip:\n                pytest.skip(\n                    f\"Skipping the test since it doesn't work on {platform_name}.\"\n                )\n            else:\n                pytest.skip(\n                    f\"Skipping the test since it works only on {platform_name}.\"\n                )\n\n        if isinstance(pytest_func, type):\n            return type(\n                pytest_func.__name__,\n                (pytest_func,),\n                {\n                    \"setup_class\": action,\n                    \"setup\": action,\n                    \"setUp\": action,\n                    \"_skipped\": True,\n                },\n            )\n\n        @wraps(pytest_func)\n        def wrapper(*args, **kwargs):  # type: ignore\n            action(*args, **kwargs)\n\n        return wrapper\n\n    return decorator\n\n\n@pytest.fixture(scope=\"session\")\ndef ethereum_private_key_file():\n    \"\"\"Pytest fixture to create a temporary Ethereum private key file.\"\"\"\n    crypto = EthereumCrypto()\n    temp_dir = Path(tempfile.mkdtemp())\n    try:\n        temp_file = temp_dir / \"private.key\"\n        temp_file.write_text(crypto.private_key)\n        yield str(temp_file)\n    finally:\n        shutil.rmtree(temp_dir)\n\n\n@pytest.fixture(scope=\"session\")\ndef ethereum_testnet_config(ganache_addr, ganache_port):\n    \"\"\"Get Ethereum ledger api configurations using Ganache.\"\"\"\n    new_uri = f\"{ganache_addr}:{ganache_port}\"\n    new_config = {\n        \"address\": new_uri,\n        \"chain_id\": DEFAULT_GANACHE_CHAIN_ID,\n        \"denom\": ETHEREUM_DEFAULT_CURRENCY_DENOM,\n        \"gas_price_api_key\": GAS_PRICE_API_KEY,\n    }\n    return new_config\n\n\n@pytest.fixture(scope=\"session\")\ndef ganache_addr() -> str:\n    \"\"\"HTTP address to the Ganache node.\"\"\"\n    return DEFAULT_GANACHE_ADDR\n\n\n@pytest.fixture(scope=\"session\")\ndef ganache_port() -> int:\n    \"\"\"Port of the connection to the OEF Node to use during the tests.\"\"\"\n    return DEFAULT_GANACHE_PORT\n\n\n@pytest.fixture(scope=\"session\")\ndef ganache_configuration(ethereum_private_key_file):\n    \"\"\"Get the Ganache configuration for testing purposes.\"\"\"\n    return dict(\n        accounts_balances=[\n            (FUNDED_ETH_PRIVATE_KEY_1, DEFAULT_AMOUNT),\n            (FUNDED_ETH_PRIVATE_KEY_2, DEFAULT_AMOUNT),\n            (FUNDED_ETH_PRIVATE_KEY_3, DEFAULT_AMOUNT),\n            (Path(ethereum_private_key_file).read_text().strip(), DEFAULT_AMOUNT),\n        ],\n    )\n\n\n@pytest.mark.integration\n@pytest.mark.ledger\n@pytest.fixture(scope=\"session\")\n@action_for_platform(\"Linux\", skip=False)\ndef ganache(\n    ganache_configuration,\n    ganache_addr,\n    ganache_port,\n    timeout: float = 2.0,\n    max_attempts: int = 10,\n):\n    \"\"\"Launch the Ganache image.\"\"\"\n    client = docker.from_env()\n    image = GanacheDockerImage(\n        client, \"http://127.0.0.1\", 8545, config=ganache_configuration\n    )\n    yield from _launch_image(image, timeout=timeout, max_attempts=max_attempts)\n\n\ndef _launch_image(\n    image: DockerImage, timeout: float = 2.0, max_attempts: int = 10\n) -> Generator:\n    \"\"\"\n    Launch image.\n\n    :param image: an instance of Docker image.\n    :param timeout: timeout to launch\n    :param max_attempts: max launch attempts\n    :yield: image\n    \"\"\"\n    image.check_skip()\n    image.stop_if_already_running()\n    container = image.create()\n    container.start()\n    logger.info(f\"Setting up image {image.tag}...\")\n    success = image.wait(max_attempts, timeout)\n    if not success:\n        container.stop()\n        container.remove()\n        pytest.fail(f\"{image.tag} doesn't work. Exiting...\")\n    else:\n        logger.info(\"Done!\")\n        time.sleep(timeout)\n        yield\n        logger.info(f\"Stopping the image {image.tag}...\")\n        container.stop()\n        container.remove()\n"
  },
  {
    "path": "plugins/aea-ledger-ethereum/tests/data/dummy_contract/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains a dummy contract for an AEA.\"\"\"\n"
  },
  {
    "path": "plugins/aea-ledger-ethereum/tests/data/dummy_contract/build/some.json",
    "content": "{\n  \"contractName\": \"erc1155\",\n  \"abi\": [\n    {\n      \"name\": \"TransferSingle\",\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_operator\",\n          \"indexed\": true\n        },\n        {\n          \"type\": \"address\",\n          \"name\": \"_from\",\n          \"indexed\": true\n        },\n        {\n          \"type\": \"address\",\n          \"name\": \"_to\",\n          \"indexed\": true\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_id\",\n          \"indexed\": false\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_value\",\n          \"indexed\": false\n        }\n      ],\n      \"anonymous\": false,\n      \"type\": \"event\"\n    },\n    {\n      \"name\": \"TransferBatch\",\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_operator\",\n          \"indexed\": true\n        },\n        {\n          \"type\": \"address\",\n          \"name\": \"_from\",\n          \"indexed\": true\n        },\n        {\n          \"type\": \"address\",\n          \"name\": \"_to\",\n          \"indexed\": true\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_ids\",\n          \"indexed\": false\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_values\",\n          \"indexed\": false\n        }\n      ],\n      \"anonymous\": false,\n      \"type\": \"event\"\n    },\n    {\n      \"name\": \"ApprovalForAll\",\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_owner\",\n          \"indexed\": true\n        },\n        {\n          \"type\": \"address\",\n          \"name\": \"_operator\",\n          \"indexed\": true\n        },\n        {\n          \"type\": \"bool\",\n          \"name\": \"_approved\",\n          \"indexed\": false\n        }\n      ],\n      \"anonymous\": false,\n      \"type\": \"event\"\n    },\n    {\n      \"name\": \"URI\",\n      \"inputs\": [\n        {\n          \"type\": \"string\",\n          \"name\": \"_value\",\n          \"indexed\": false\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_id\",\n          \"indexed\": true\n        }\n      ],\n      \"anonymous\": false,\n      \"type\": \"event\"\n    },\n    {\n      \"outputs\": [],\n      \"inputs\": [],\n      \"constant\": false,\n      \"payable\": false,\n      \"type\": \"constructor\"\n    },\n    {\n      \"name\": \"getAddress\",\n      \"outputs\": [\n        {\n          \"type\": \"bytes32\",\n          \"name\": \"out\"\n        }\n      ],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_addr\"\n        }\n      ],\n      \"constant\": true,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 370\n    },\n    {\n      \"name\": \"getHash\",\n      \"outputs\": [\n        {\n          \"type\": \"bytes32\",\n          \"name\": \"out\"\n        }\n      ],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_from\"\n        },\n        {\n          \"type\": \"address\",\n          \"name\": \"_to\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_ids\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_from_supplies\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_to_supplies\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_value_eth\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_nonce\"\n        }\n      ],\n      \"constant\": true,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 11446\n    },\n    {\n      \"name\": \"getSingleHash\",\n      \"outputs\": [\n        {\n          \"type\": \"bytes32\",\n          \"name\": \"out\"\n        }\n      ],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_from\"\n        },\n        {\n          \"type\": \"address\",\n          \"name\": \"_to\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_id\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_from_supply\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_to_supply\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_value_eth\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_nonce\"\n        }\n      ],\n      \"constant\": true,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 2041\n    },\n    {\n      \"name\": \"supportsInterface\",\n      \"outputs\": [\n        {\n          \"type\": \"bool\",\n          \"name\": \"out\"\n        }\n      ],\n      \"inputs\": [\n        {\n          \"type\": \"bytes32\",\n          \"name\": \"_interfaceID\"\n        }\n      ],\n      \"constant\": true,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 868\n    },\n    {\n      \"name\": \"is_nonce_used\",\n      \"outputs\": [\n        {\n          \"type\": \"bool\",\n          \"name\": \"out\"\n        }\n      ],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"addr\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"nonce\"\n        }\n      ],\n      \"constant\": true,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 1052\n    },\n    {\n      \"name\": \"is_token_id_exists\",\n      \"outputs\": [\n        {\n          \"type\": \"bool\",\n          \"name\": \"out\"\n        }\n      ],\n      \"inputs\": [\n        {\n          \"type\": \"uint256\",\n          \"name\": \"token_id\"\n        }\n      ],\n      \"constant\": true,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 928\n    },\n    {\n      \"name\": \"safeTransferFrom\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_from\"\n        },\n        {\n          \"type\": \"address\",\n          \"name\": \"_to\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_id\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_value\"\n        },\n        {\n          \"type\": \"bytes\",\n          \"name\": \"_data\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 80803\n    },\n    {\n      \"name\": \"safeBatchTransferFrom\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_from\"\n        },\n        {\n          \"type\": \"address\",\n          \"name\": \"_to\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_ids\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_values\"\n        },\n        {\n          \"type\": \"bytes\",\n          \"name\": \"_data\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 748184\n    },\n    {\n      \"name\": \"balanceOf\",\n      \"outputs\": [\n        {\n          \"type\": \"uint256\",\n          \"name\": \"out\"\n        }\n      ],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_owner\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_id\"\n        }\n      ],\n      \"constant\": true,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 1172\n    },\n    {\n      \"name\": \"balanceOfBatch\",\n      \"outputs\": [\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"out\"\n        }\n      ],\n      \"inputs\": [\n        {\n          \"type\": \"address[10]\",\n          \"name\": \"_owner\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_ids\"\n        }\n      ],\n      \"constant\": true,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 7524\n    },\n    {\n      \"name\": \"setApprovalForAll\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_operator\"\n        },\n        {\n          \"type\": \"bool\",\n          \"name\": \"_approved\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 38136\n    },\n    {\n      \"name\": \"isApprovedForAll\",\n      \"outputs\": [\n        {\n          \"type\": \"bool\",\n          \"name\": \"out\"\n        }\n      ],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_owner\"\n        },\n        {\n          \"type\": \"address\",\n          \"name\": \"_operator\"\n        }\n      ],\n      \"constant\": true,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 1301\n    },\n    {\n      \"name\": \"createSingle\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_item_owner\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_id\"\n        },\n        {\n          \"type\": \"string\",\n          \"name\": \"_path\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 597461\n    },\n    {\n      \"name\": \"createBatch\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_items_owner\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_ids\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 927926\n    },\n    {\n      \"name\": \"mint\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_to\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_id\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_supply\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": false,\n      \"type\": \"function\"\n    },\n    {\n      \"name\": \"mint\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_to\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_id\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_supply\"\n        },\n        {\n          \"type\": \"bytes\",\n          \"name\": \"_data\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": false,\n      \"type\": \"function\"\n    },\n    {\n      \"name\": \"mintBatch\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_to\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_ids\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_supplies\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": false,\n      \"type\": \"function\"\n    },\n    {\n      \"name\": \"mintBatch\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_to\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_ids\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_supplies\"\n        },\n        {\n          \"type\": \"bytes\",\n          \"name\": \"_data\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": false,\n      \"type\": \"function\"\n    },\n    {\n      \"name\": \"burn\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_id\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_supply\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 40353\n    },\n    {\n      \"name\": \"burnBatch\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_ids\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_supplies\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 382149\n    },\n    {\n      \"name\": \"tradeBatch\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_from\"\n        },\n        {\n          \"type\": \"address\",\n          \"name\": \"_to\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_ids\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_from_supplies\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_to_supplies\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_value_eth\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_nonce\"\n        },\n        {\n          \"type\": \"bytes\",\n          \"name\": \"_signature\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": true,\n      \"type\": \"function\"\n    },\n    {\n      \"name\": \"tradeBatch\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_from\"\n        },\n        {\n          \"type\": \"address\",\n          \"name\": \"_to\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_ids\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_from_supplies\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_to_supplies\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_value_eth\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_nonce\"\n        },\n        {\n          \"type\": \"bytes\",\n          \"name\": \"_signature\"\n        },\n        {\n          \"type\": \"bytes\",\n          \"name\": \"_data\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": true,\n      \"type\": \"function\"\n    },\n    {\n      \"name\": \"trade\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_from\"\n        },\n        {\n          \"type\": \"address\",\n          \"name\": \"_to\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_id\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_from_supply\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_to_supply\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_value_eth\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_nonce\"\n        },\n        {\n          \"type\": \"bytes\",\n          \"name\": \"_signature\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": true,\n      \"type\": \"function\"\n    },\n    {\n      \"name\": \"trade\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_from\"\n        },\n        {\n          \"type\": \"address\",\n          \"name\": \"_to\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_id\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_from_supply\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_to_supply\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_value_eth\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_nonce\"\n        },\n        {\n          \"type\": \"bytes\",\n          \"name\": \"_signature\"\n        },\n        {\n          \"type\": \"bytes\",\n          \"name\": \"_data\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": true,\n      \"type\": \"function\"\n    },\n    {\n      \"name\": \"owner\",\n      \"outputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"out\"\n        }\n      ],\n      \"inputs\": [],\n      \"constant\": true,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 1263\n    }\n  ],\n  \"bytecode\": \"0x740100000000000000000000000000000000000000006020526f7fffffffffffffffffffffffffffffff6040527fffffffffffffffffffffffffffffffff8000000000000000000000000000000060605274012a05f1fffffffffffffffffffffffffdabf41c006080527ffffffffffffffffffffffffed5fa0e000000000000000000000000000000000060a052341561009857600080fd5b6000600155600160006301ffc9a760e05260c052604060c020556001600063d9b67a2660e05260c052604060c020553360025561405a56600035601c52740100000000000000000000000000000000000000006020526f7fffffffffffffffffffffffffffffff6040527fffffffffffffffffffffffffffffffff8000000000000000000000000000000060605274012a05f1fffffffffffffffffffffffffdabf41c006080527ffffffffffffffffffffffffed5fa0e000000000000000000000000000000000060a05263ae22c57d60005114156100d45734156100ac57600080fd5b60043560205181106100bd57600080fd5b50600435610140526101405160005260206000f350005b600015610313575b610580526101405261016052610180526101a0526101c0526101e05261020052610220526102405261026052610280526102a0526102c0526102e05261030052610320526103405261036052610380526103a0526103c0526103e05261040052610420526104405261046052610480526104a0526104c0526104e052610500526105205261054052610560526000610180516020826105c00101526020810190506102c0516020826105c0010152602081019050610400516020826105c0010152602081019050806105c0526105c090508051602082012090506105a0526106606000600a818352015b610660511515156102765760006105a05160208261068001015260208101905061018061066051600a81106101fa57600080fd5b60200201516020826106800101526020810190506102c061066051600a811061022257600080fd5b602002015160208261068001015260208101905061040061066051600a811061024a57600080fd5b6020020151602082610680010152602081019050806106805261068090508051602082012090506105a0525b5b81516001018083528114156101c6575b5050600061014051602082610760010152602081019050610160516020826107600101526020810190506105a0516020826107600101526020810190506105405160208261076001015260208101905061056051602082610760010152602081019050806107605261076090508051602082012090506107405261074051600052600051610580515650005b634a6f823360005114156105c457341561032c57600080fd5b600435602051811061033d57600080fd5b50602435602051811061034f57600080fd5b506000610120525b602061012051016101205261012061012051101561037457610357565b6000610120525b60206101205101610120526101206101205110156103985761037b565b6000610120525b60206101205101610120526101206101205110156103bc5761039f565b6373ad25716101405260043561016052602435610180526101a0604480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250506102e061018480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250506104206102c480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250506104043561056052610424356105805261058051610560516105405161052051610500516104e0516104c0516104a05161048051610460516104405161042051610400516103e0516103c0516103a05161038051610360516103405161032051610300516102e0516102c0516102a05161028051610260516102405161022051610200516101e0516101c0516101a0516101805161016051600658016100dc565b6105e0526105e05160005260206000f350005b600015610909575b610580526101405261016052610180526101a0526101c0526101e05261020052610220526102405261026052610280526102a0526102c0526102e05261030052610320526103405261036052610380526103a0526103c0526103e05261040052610420526104405261046052610480526104a0526104c0526104e052610500526105205261054052610560526000610140516020826105c0010152602081019050610160516020826105c0010152602081019050610180516020826105c00101526020810190506101a0516020826105c00101526020810190506101c0516020826105c00101526020810190506101e0516020826105c0010152602081019050610200516020826105c0010152602081019050610220516020826105c0010152602081019050610240516020826105c0010152602081019050610260516020826105c0010152602081019050610280516020826105c00101526020810190506102a0516020826105c00101526020810190506102c0516020826105c00101526020810190506102e0516020826105c0010152602081019050610300516020826105c0010152602081019050610320516020826105c0010152602081019050610340516020826105c0010152602081019050610360516020826105c0010152602081019050610380516020826105c00101526020810190506103a0516020826105c00101526020810190506103c0516020826105c00101526020810190506103e0516020826105c0010152602081019050610400516020826105c0010152602081019050610420516020826105c0010152602081019050610440516020826105c0010152602081019050610460516020826105c0010152602081019050610480516020826105c00101526020810190506104a0516020826105c00101526020810190506104c0516020826105c00101526020810190506104e0516020826105c0010152602081019050610500516020826105c0010152602081019050610520516020826105c0010152602081019050610540516020826105c0010152602081019050610560516020826105c0010152602081019050806105c0526105c090508051602082012090506105a0526105a051600052600051610580515650005b6000156109e1575b610220526101405261016052610180526101a0526101c0526101e0526102005260006101405160208261026001015260208101905061016051602082610260010152602081019050610180516020826102600101526020810190506101a0516020826102600101526020810190506101c0516020826102600101526020810190506101e05160208261026001015260208101905061020051602082610260010152602081019050806102605261026090508051602082012090506102405261024051600052600051610220515650005b6310660e866000511415610a905734156109fa57600080fd5b6004356020518110610a0b57600080fd5b506024356020518110610a1d57600080fd5b5063155960636101405260043561016052602435610180526044356101a0526064356101c0526084356101e05260a4356102005260c4356102205261022051610200516101e0516101c0516101a051610180516101605160065801610911565b610280526102805160005260206000f350005b600015610cf2575b6101805261014052610160526101a0526000610240525b6101a05160206001820306601f820103905061024051101515610ad157610aea565b610240516101c001526102405160200161024052610aaf565b60005060416101a0511815610b0757600060005260005161018051565b6101a0602060006020835103811315610b1f57600080fd5b046020026020018101519050610280526101a0602060206020835103811315610b4757600080fd5b0460200260200181015190506102a05260406001602082066103a0016101a0518284011115610b7557600080fd5b6041806103c0826020602088068803016101a001600060046018f1505081815280905090509050806020015160008251806020901315610bb457600080fd5b8091901215610bc257600080fd5b606051816020036101000a830480604051901315610bdf57600080fd5b8091901215610bed57600080fd5b9050905090506102c052601b6102c0511215610c30576102c0606051601b82510180604051901315610c1e57600080fd5b8091901215610c2c57600080fd5b8152505b610480601b8152601c81602001525060006104605261046061012060006002818352015b6101205160200261048001516102c0511415610c735760018352610c84565b5b8151600101808352811415610c54575b5050506104605160011415610ce257610140516104c0526102c0516000811215610cad57600080fd5b6104e05261028051610500526102a05161052052602060c060806104c060006001610bb8f15060c05160005260005161018051565b6000600052600051610180515650005b600015610db3575b6101605261014052610140517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff806000811215610d3e578060000360020a8204610d45565b8060020a82025b90509050604051811115610d5857600080fd5b61018052700100000000000000000000000000000000610d7757600080fd5b7001000000000000000000000000000000006101405106604051811115610d9d57600080fd5b6101a05261018051600052600051610160515650005b63f17535506000511415610de8573415610dcc57600080fd5b600060043560e05260c052604060c0205460005260206000f350005b63ac2a2e216000511415610e3d573415610e0157600080fd5b6004356020518110610e1257600080fd5b50600460043560e05260c052604060c02060243560e05260c052604060c0205460005260206000f350005b634026b7556000511415610e72573415610e5657600080fd5b600760043560e05260c052604060c0205460005260206000f350005b63f242432a6000511415611135573415610e8b57600080fd5b6004356020518110610e9c57600080fd5b506024356020518110610eae57600080fd5b5061012060843560040161014037610100608435600401351115610ed157600080fd5b600660043560e05260c052604060c0203360e05260c052604060c02054336004351417610efd57600080fd5b6308c379a06102805260206102a05260206102c0527f43616e6e6f74207472616e7366657220746f207a65726f20616464726573732e6102e0526102c050600060243518610f4c57608461029cfd5b6308c379a0610320526020610340526012610360527f4e6f7420656e6f75676820746f6b656e732e00000000000000000000000000006103805261036050606435600360043560e05260c052604060c02060443560e05260c052604060c020541015610fb957608461033cfd5b600360043560e05260c052604060c02060443560e05260c052604060c02060643581541015610fe757600080fd5b606435815403815550600360243560e05260c052604060c02060443560e05260c052604060c0208054606435825401101561102157600080fd5b6064358154018155506044356103c0526064356103e052602435600435337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6260406103c0a460006024353b1115611133576024353b61107f57600080fd5b602435301861108d57600080fd5b60206106406101c460a063f23a6e6161042052336104405260043561046052604435610480526064356104a052806104c052610140808051602001808461044001828460006004600a8704601201f16110e557600080fd5b50508051820160206001820306601f820103905060200191505061043c905060006024355af161111457600080fd5b600050610640516104005263f23a6e61610400511461113257600080fd5b5b005b63cf36e535600051141561163c57341561114e57600080fd5b600435602051811061115f57600080fd5b50602435602051811061117157600080fd5b506000610120525b602061012051016101205261012061012051101561119657611179565b6000610120525b60206101205101610120526101206101205110156111ba5761119d565b6101206102c435600401610140376101006102c4356004013511156111de57600080fd5b600660043560e05260c052604060c0203360e05260c052604060c0205433600435141761120a57600080fd5b6308c379a06102805260206102a05260206102c0527f43616e6e6f74207472616e7366657220746f207a65726f20616464726573732e6102e0526102c05060006024351861125957608461029cfd5b6103206000600a818352015b604461032051600a811061127857600080fd5b60200201356103405261018461032051600a811061129557600080fd5b6020020135600360043560e05260c052604060c0206103405160e05260c052604060c0205410156112c557600080fd5b5b8151600101808352811415611265575b505060443561036052606435610380526084356103a05260a4356103c05260c4356103e05260e435610400526101043561042052610124356104405261014435610460526101643561048052610184356104a0526101a4356104c0526101c4356104e0526101e435610500526102043561052052610224356105405261024435610560526102643561058052610284356105a0526102a4356105c052602435600435337f514c24e4790d7c31a095a1688a73a01f28d936a9a85d806ba95970d8ee88efa8610280610360a46105e06000600a818352015b60446105e051600a81106113c057600080fd5b602002013561060052600360043560e05260c052604060c0206106005160e05260c052604060c0206101846105e051600a81106113fc57600080fd5b60200201358154101561140e57600080fd5b6101846105e051600a811061142257600080fd5b6020020135815403815550600360243560e05260c052604060c0206106005160e05260c052604060c02080546101846105e051600a811061146257600080fd5b6020020135825401101561147557600080fd5b6101846105e051600a811061148957600080fd5b60200201358154018155505b81516001018083528114156113ad575b505060006024353b111561163a576024353b6114c057600080fd5b60243530186114ce57600080fd5b6020610aa06104046102e063a3bfc206610640523361066052600435610680526106a0604480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250506107e061018480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250508061092052610140808051602001808461066001828460006004600a8704601201f16115ec57600080fd5b50508051820160206001820306601f820103905060200191505061065c905060006024355af161161b57600080fd5b600050610aa0516106205263e324a00d610620511461163957600080fd5b5b005b62fdd58e600051141561169057341561165457600080fd5b600435602051811061166557600080fd5b50600360043560e05260c052604060c02060243560e05260c052604060c0205460005260206000f350005b63fbe31aea60005114156117935734156116a957600080fd5b6000610120525b610120516004013560205181106116c657600080fd5b5060206101205101610120526101206101205110156116e4576116b0565b6000610120525b6020610120510161012052610120610120511015611708576116eb565b6102806000600a818352015b6003600461028051600a811061172957600080fd5b602002013560e05260c052604060c02061014461028051600a811061174d57600080fd5b602002013560e05260c052604060c0205461014061028051600a811061177257600080fd5b60200201525b8151600101808352811415611714575b5050610140610140f3005b63a22cb46560005114156118235734156117ac57600080fd5b60043560205181106117bd57600080fd5b50602435600281106117ce57600080fd5b5060243560063360e05260c052604060c02060043560e05260c052604060c0205560243561014052600435337f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c316020610140a3005b63e985e9c5600051141561188a57341561183c57600080fd5b600435602051811061184d57600080fd5b50602435602051811061185f57600080fd5b50600660043560e05260c052604060c02060243560e05260c052604060c0205460005260206000f350005b63a70b070f6000511415611af85734156118a357600080fd5b60043560205181106118b457600080fd5b50610120604435600401610140376101006044356004013511156118d757600080fd5b6000600435186118e657600080fd5b6308c379a06102805260206102a052601b6102c0527f4f776e6572206f6e6c792063616e20637265617465206974656d2e00000000006102e0526102c050336002541461193457608461029cfd5b6000600360043560e05260c052604060c02060243560e05260c052604060c02055600180546001825401101561196957600080fd5b60018154018155506001600760243560e05260c052604060c0205561014080600560243560e05260c052604060c02060c052602060c020602082510161012060006009818352015b826101205160200211156119c4576119e6565b61012051602002850151610120518501555b81516001018083528114156119b1575b50505050505060206103405261034051610380526101408051602001806103405161038001828460006004600a8704601201f1611a2257600080fd5b5050610320610340516103800151610440818352015b610440610320511115611a4a57611a6b565b600061032051610340516103a00101535b8151600101808352811415611a38575b5050602061034051610380015160206001820306601f8201039050610340510101610340526024357f6bb7ff708619ba0610cba295a58592e0451dee2622938c8755667688daf3529b61034051610380a26024356103a05260006103c0526004356000337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6260406103a0a4005b6319a35d7c6000511415611d43573415611b1157600080fd5b6004356020518110611b2257600080fd5b506000610120525b6020610120510161012052610120610120511015611b4757611b2a565b600060043518611b5657600080fd5b6308c379a061014052602061016052601c610180527f4f776e6572206f6e6c792063616e20637265617465206974656d732e000000006101a052610180503360025414611ba457608461015cfd5b6101e06000600a818352015b60246101e051600a8110611bc357600080fd5b6020020135610200526000600360043560e05260c052604060c0206102005160e05260c052604060c020556001805460018254011015611c0257600080fd5b6001815401815550600160076102005160e05260c052604060c020555b8151600101808352811415611bb0575b5050610220600081526000816020015260008160400152600081606001526000816080015260008160a0015260008160c0015260008160e00152600081610100015260008161012001525060243561036052604435610380526064356103a0526084356103c05260a4356103e05260c4356104005260e43561042052610104356104405261012435610460526101443561048052610220516104a052610240516104c052610260516104e05261028051610500526102a051610520526102c051610540526102e051610560526103005161058052610320516105a052610340516105c0526004356000337f514c24e4790d7c31a095a1688a73a01f28d936a9a85d806ba95970d8ee88efa8610280610360a4005b63156e29f66000511415611d8157600061028052610280805160200180610140828460006004600a8704601201f1611d7a57600080fd5b5050611dce565b63731133e96000511415611dc65761012060643560040161014037610100606435600401351115611db157600080fd5b61014060643560040161014037600050611dce565b60001561208a575b3415611dd957600080fd5b6004356020518110611dea57600080fd5b50600060043518611dfa57600080fd5b6308c379a06102c05260206102e052601a610300527f4f776e6572206f6e6c792063616e206d696e74206974656d732e00000000000061032052610300503360025414611e485760846102dcfd5b610140610380525b61038051516020610380510161038052610380610380511015611e7257611e50565b6320171bef6103a0526024356103c0526103c05160065801610cfa565b61042052610360610380525b6103805152602061038051036103805261014061038051101515611ebe57611e9b565b6104205161036052600261036051146001610360511417611ede57600080fd5b6001610360511415611f5f576308c379a0610440526020610460526028610480527f43616e6e6f74206d696e74204e46542077697468205f737570706c79206d6f726104a0527f65207468616e20310000000000000000000000000000000000000000000000006104c05261048050600160443514611f5e5760a461045cfd5b5b604435600360043560e05260c052604060c02060243560e05260c052604060c0205560243561050052604435610520526004356000337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f626040610500a460006004353b1115612088576004353b611fd557600080fd5b6004353018611fe357600080fd5b60206107806101c460a063f23a6e6161056052336105805260006105a0526024356105c0526044356105e0528061060052610140808051602001808461058001828460006004600a8704601201f161203a57600080fd5b50508051820160206001820306601f820103905060200191505061057c905060006004355af161206957600080fd5b600050610780516105405263f23a6e61610540511461208757600080fd5b5b005b63c671854d60005114156120c857600061028052610280805160200180610140828460006004600a8704601201f16120c157600080fd5b5050612118565b63b07e58756000511415612110576101206102a435600401610140376101006102a4356004013511156120fa57600080fd5b6101406102a43560040161014037600050612118565b6000156124f6575b341561212357600080fd5b600435602051811061213457600080fd5b506000610120525b60206101205101610120526101206101205110156121595761213c565b6000610120525b602061012051016101205261012061012051101561217d57612160565b60006004351861218c57600080fd5b6308c379a06102c05260206102e052601a610300527f4f776e6572206f6e6c792063616e206d696e74206974656d732e000000000000610320526103005033600254146121da5760846102dcfd5b6103606000600a818352015b602461036051600a81106121f957600080fd5b6020020135610380526101406103c0525b6103c0515160206103c051016103c0526103c06103c051101561222c5761220a565b6320171bef6103e05261038051610400526104005160065801610cfa565b610460526103a06103c0525b6103c0515260206103c051036103c0526101406103c05110151561227957612256565b610460516103a05260026103a0511460016103a051141761229957600080fd5b60016103a05114156122cb57600161016461036051600a81106122bb57600080fd5b6020020135146122ca57600080fd5b5b61016461036051600a81106122df57600080fd5b6020020135600360043560e05260c052604060c0206103805160e05260c052604060c020555b81516001018083528114156121e6575b5050602435610480526044356104a0526064356104c0526084356104e05260a4356105005260c4356105205260e4356105405261010435610560526101243561058052610144356105a052610164356105c052610184356105e0526101a435610600526101c435610620526101e4356106405261020435610660526102243561068052610244356106a052610264356106c052610284356106e0526004356000337f514c24e4790d7c31a095a1688a73a01f28d936a9a85d806ba95970d8ee88efa8610280610480a46107006000600a818352015b60006004353b11156124e1576004353b61240357600080fd5b600435301861241157600080fd5b60206109606101c460a063f23a6e61610740523361076052600061078052602461070051600a811061244257600080fd5b60200201356107a05261016461070051600a811061245f57600080fd5b60200201356107c052806107e052610140808051602001808461076001828460006004600a8704601201f161249357600080fd5b50508051820160206001820306601f820103905060200191505061075c905060006004355af16124c257600080fd5b600050610960516107205263f23a6e6161072051146124e057600080fd5b5b5b81516001018083528114156123ea575b5050005b63b390c0ab60005114156125ea57341561250f57600080fd5b6308c379a061014052602061016052601a610180527f4e6f7420656e6f75676820746f6b656e7320746f206275726e2e0000000000006101a0526101805060243560033360e05260c052604060c02060043560e05260c052604060c02054101561257a57608461015cfd5b60033360e05260c052604060c02060043560e05260c052604060c020602435815410156125a657600080fd5b6024358154038155506004356101e05260243561020052600033337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6260406101e0a4005b63b59afe52600051141561282b57341561260357600080fd5b6000610120525b60206101205101610120526101206101205110156126275761260a565b6000610120525b602061012051016101205261012061012051101561264b5761262e565b6101406000600a818352015b600461014051600a811061266a57600080fd5b60200201356101605261014461014051600a811061268757600080fd5b602002013560033360e05260c052604060c0206101605160e05260c052604060c0205410156126b557600080fd5b5b8151600101808352811415612657575b50506101806000600a818352015b600461018051600a81106126e757600080fd5b60200201356101a05260033360e05260c052604060c0206101a05160e05260c052604060c02061014461018051600a811061272157600080fd5b60200201358154101561273357600080fd5b61014461018051600a811061274757600080fd5b60200201358154038155505b81516001018083528114156126d4575b50506004356101c0526024356101e05260443561020052606435610220526084356102405260a4356102605260c4356102805260e4356102a052610104356102c052610124356102e0526101443561030052610164356103205261018435610340526101a435610360526101c435610380526101e4356103a052610204356103c052610224356103e05261024435610400526102643561042052600033337f514c24e4790d7c31a095a1688a73a01f28d936a9a85d806ba95970d8ee88efa86102806101c0a4005b63f2526ada6000511415612869576000610320526103208051602001806101e0828460006004600a8704601201f161286257600080fd5b50506128b9565b63a835c36960005114156128b157610120610464356004016101e0376101006104643560040135111561289b57600080fd5b610140610464356004016101e0376000506128b9565b600015613725575b60043560205181106128ca57600080fd5b5060243560205181106128dc57600080fd5b506000610120525b6020610120510161012052610120610120511015612901576128e4565b6000610120525b602061012051016101205261012061012051101561292557612908565b6000610120525b60206101205101610120526101206101205110156129495761292c565b6061610444356004016101403760416104443560040135111561296b57600080fd5b6308c379a061036052602061038052602c6103a0527f5f66726f6d206d757374206265207468652073656e646572206f7220617070726103c0527f6f766564206164647265737300000000000000000000000000000000000000006103e0526103a050600660043560e05260c052604060c0203360e05260c052604060c020543360043514176129fc5760a461037cfd5b6308c379a0610420526020610440526025610460527f44657374696e6174696f6e2061646472657373206d757374206265206e6f6e2d610480527f7a65726f2e0000000000000000000000000000000000000000000000000000006104a05261046050600060243518612a705760a461043cfd5b6308c379a06104e0526020610500526015610520527f4e6f6e6365206d75737420626520756e757365642e00000000000000000000006105405261052050600460043560e05260c052604060c0206104243560e05260c052604060c0205415612ada5760846104fcfd5b6308c379a06105805260206105a05260256105c0527f53656e64657220686173206e6f742070726f766964656420656e6f75676820656105e0527f746865722e000000000000000000000000000000000000000000000000000000610600526105c050346104043514612b4e5760a461059cfd5b6106406000600a818352015b604461064051600a8110612b6d57600080fd5b602002013561066052600061018461064051600a8110612b8c57600080fd5b60200201351115612c03576102c461064051600a8110612bab57600080fd5b602002013515612bba57600080fd5b61018461064051600a8110612bce57600080fd5b6020020135600360043560e05260c052604060c0206106605160e05260c052604060c020541015612bfe57600080fd5b612c6b565b61018461064051600a8110612c1757600080fd5b602002013515612c2657600080fd5b6102c461064051600a8110612c3a57600080fd5b6020020135600360243560e05260c052604060c0206106605160e05260c052604060c020541015612c6a57600080fd5b5b5b8151600101808352811415612b5a575b50506101406106a0525b6106a0515160206106a051016106a0526106a06106a0511015612ca857612c86565b6373ad25716106c0526004356106e05260243561070052610720604480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e00152806101000135826101000152806101200135826101200152505061086061018480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250506109a06102c480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e00152806101000135826101000152806101200135826101200152505061040435610ae05261042435610b0052610b0051610ae051610ac051610aa051610a8051610a6051610a4051610a2051610a00516109e0516109c0516109a05161098051610960516109405161092051610900516108e0516108c0516108a05161088051610860516108405161082051610800516107e0516107c0516107a05161078051610760516107405161072051610700516106e051600658016100dc565b610b60526106806106a0525b6106a0515260206106a051036106a0526101406106a051101515612ecc57612ea9565b610b605161068052610140610ba0525b610ba051516020610ba05101610ba052610ba0610ba0511015612efe57612edc565b6040636f868168610bc05261068051610be05280610c00526101408080516020018084610be001828460006004600a8704601201f1612f3c57600080fd5b50508051820160206001820306601f820103905060200191505050610c005180610be00180518060206001820306601f82010390508201610ce0525050505b610c20610ce0511015612f8d57612fa2565b610ce051516020610ce05103610ce052612f7b565b610c0051610be05160065801610a98565b610d0052610b80610ba0525b610ba051526020610ba05103610ba052610140610ba051101515612fe257612fbf565b610d0051610b80526308c379a0610d20526020610d40526020610d60527f5369676e657220646f6573206e6f74206d61746368207369676e61747572652e610d8052610d6050602435610b80511461303b576084610d3cfd5b600160043360e05260c052604060c0206104243560e05260c052604060c02055610dc06000600a818352015b6044610dc051600a811061307a57600080fd5b6020020135610de0526000610184610dc051600a811061309957600080fd5b6020020135111561317457600360043560e05260c052604060c020610de05160e05260c052604060c020610184610dc051600a81106130d757600080fd5b6020020135815410156130e957600080fd5b610184610dc051600a81106130fd57600080fd5b6020020135815403815550600360243560e05260c052604060c020610de05160e05260c052604060c0208054610184610dc051600a811061313d57600080fd5b6020020135825401101561315057600080fd5b610184610dc051600a811061316457600080fd5b6020020135815401815550613240565b600360043560e05260c052604060c020610de05160e05260c052604060c02080546102c4610dc051600a81106131a957600080fd5b602002013582540110156131bc57600080fd5b6102c4610dc051600a81106131d057600080fd5b6020020135815401815550600360243560e05260c052604060c020610de05160e05260c052604060c0206102c4610dc051600a811061320e57600080fd5b60200201358154101561322057600080fd5b6102c4610dc051600a811061323457600080fd5b60200201358154038155505b5b8151600101808352811415613067575b50506000600060006000346024356000f161326b57600080fd5b604435610e0052606435610e2052608435610e405260a435610e605260c435610e805260e435610ea05261010435610ec05261012435610ee05261014435610f005261016435610f205261018435610f40526101a435610f60526101c435610f80526101e435610fa05261020435610fc05261022435610fe0526102443561100052610264356110205261028435611040526102a43561106052602435600435337f514c24e4790d7c31a095a1688a73a01f28d936a9a85d806ba95970d8ee88efa8610280610e00a4604435611080526064356110a0526084356110c05260a4356110e05260c4356111005260e43561112052610104356111405261012435611160526101443561118052610164356111a0526102c4356111c0526102e4356111e052610304356112005261032435611220526103443561124052610364356112605261038435611280526103a4356112a0526103c4356112c0526103e4356112e052600435602435337f514c24e4790d7c31a095a1688a73a01f28d936a9a85d806ba95970d8ee88efa8610280611080a460006024353b1115613590576024353b61341657600080fd5b602435301861342457600080fd5b60206117806104046102e063a3bfc20661132052336113405260243561136052611380604480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250506114c061018480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e00152806101000135826101000152806101200135826101200152505080611600526101e0808051602001808461134001828460006004600a8704601201f161354257600080fd5b50508051820160206001820306601f820103905060200191505061133c905060006024355af161357157600080fd5b6000506117805161130052630c97e564611300511461358f57600080fd5b5b60006004353b1115613723576004353b6135a957600080fd5b60043530186135b757600080fd5b6020611c206104046102e063a3bfc2066117c052336117e05260043561180052611820604480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250506119606102c480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e00152806101000135826101000152806101200135826101200152505080611aa0526101e080805160200180846117e001828460006004600a8704601201f16136d557600080fd5b50508051820160206001820306601f82010390506020019150506117dc905060006004355af161370457600080fd5b600050611c20516117a052630c97e5646117a0511461372257600080fd5b5b005b636e8205b26000511415613763576000610320526103208051602001806101e0828460006004600a8704601201f161375c57600080fd5b50506137b3565b63183f5ec560005114156137ab57610120610104356004016101e0376101006101043560040135111561379557600080fd5b610140610104356004016101e0376000506137b3565b600015613f5d575b60043560205181106137c457600080fd5b5060243560205181106137d657600080fd5b50606160e43560040161014037604160e4356004013511156137f757600080fd5b600660043560e05260c052604060c0203360e05260c052604060c0205433600435141761382357600080fd5b6308c379a06103605260206103805260256103a0527f44657374696e6174696f6e2061646472657373206d757374206265206e6f6e2d6103c0527f7a65726f2e0000000000000000000000000000000000000000000000000000006103e0526103a0506000602435186138975760a461037cfd5b6308c379a0610420526020610440526015610460527f4e6f6e6365206d75737420626520756e757365642e00000000000000000000006104805261046050600460043560e05260c052604060c02060c43560e05260c052604060c020541561390057608461043cfd5b6308c379a06104c05260206104e0526025610500527f53656e64657220686173206e6f742070726f766964656420656e6f7567682065610520527f746865722e00000000000000000000000000000000000000000000000000000061054052610500503460a435146139735760a46104dcfd5b600060643511156139bd576084351561398b57600080fd5b606435600360043560e05260c052604060c02060443560e05260c052604060c0205410156139b857600080fd5b6139f8565b606435156139ca57600080fd5b608435600360243560e05260c052604060c02060443560e05260c052604060c0205410156139f757600080fd5b5b6101406105a0525b6105a0515160206105a051016105a0526105a06105a0511015613a2257613a00565b63155960636105c0526004356105e0526024356106005260443561062052606435610640526084356106605260a4356106805260c4356106a0526106a05161068051610660516106405161062051610600516105e05160065801610911565b610700526105806105a0525b6105a0515260206105a051036105a0526101406105a051101515613ab057613a8d565b6107005161058052610140610740525b61074051516020610740510161074052610740610740511015613ae257613ac0565b6040636f868168610760526105805161078052806107a052610140808051602001808461078001828460006004600a8704601201f1613b2057600080fd5b50508051820160206001820306601f8201039050602001915050506107a051806107800180518060206001820306601f82010390508201610880525050505b6107c0610880511015613b7157613b86565b61088051516020610880510361088052613b5f565b6107a0516107805160065801610a98565b6108a052610720610740525b6107405152602061074051036107405261014061074051101515613bc657613ba3565b6108a051610720526308c379a06108c05260206108e0526020610900527f5369676e657220646f6573206e6f74206d61746368207369676e61747572652e61092052610900506024356107205114613c1f5760846108dcfd5b600160043360e05260c052604060c02060c43560e05260c052604060c0205560006064351115613cbf57600360043560e05260c052604060c02060443560e05260c052604060c02060643581541015613c7757600080fd5b606435815403815550600360243560e05260c052604060c02060443560e05260c052604060c02080546064358254011015613cb157600080fd5b606435815401815550613d31565b600360043560e05260c052604060c02060443560e05260c052604060c02080546084358254011015613cf057600080fd5b608435815401815550600360243560e05260c052604060c02060443560e05260c052604060c02060843581541015613d2757600080fd5b6084358154038155505b6000600060006000346024356000f1613d4957600080fd5b6044356109605260643561098052602435600435337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f626040610960a46044356109a0526084356109c052600435602435337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6260406109a0a460006024353b1115613e8e576024353b613dda57600080fd5b6024353018613de857600080fd5b6020610c206101c460a063f23a6e61610a005233610a2052602435610a4052604435610a6052606435610a805280610aa0526101e08080516020018084610a2001828460006004600a8704601201f1613e4057600080fd5b50508051820160206001820306601f8201039050602001915050610a1c905060006024355af1613e6f57600080fd5b600050610c20516109e052630c97e5646109e05114613e8d57600080fd5b5b60006004353b1115613f5b576004353b613ea757600080fd5b6004353018613eb557600080fd5b6020610e806101c460a063f23a6e61610c605233610c8052600435610ca052604435610cc052608435610ce05280610d00526101e08080516020018084610c8001828460006004600a8704601201f1613f0d57600080fd5b50508051820160206001820306601f8201039050602001915050610c7c905060006004355af1613f3c57600080fd5b600050610e8051610c4052630c97e564610c405114613f5a57600080fd5b5b005b638da5cb5b6000511415613f84573415613f7657600080fd5b60025460005260206000f350005b60006000fd5b6100d061405a036100d06000396100d061405a036000f3\",\n  \"deployedBytecode\": \"0x600035601c52740100000000000000000000000000000000000000006020526f7fffffffffffffffffffffffffffffff6040527fffffffffffffffffffffffffffffffff8000000000000000000000000000000060605274012a05f1fffffffffffffffffffffffffdabf41c006080527ffffffffffffffffffffffffed5fa0e000000000000000000000000000000000060a05263ae22c57d60005114156100d45734156100ac57600080fd5b60043560205181106100bd57600080fd5b50600435610140526101405160005260206000f350005b600015610313575b610580526101405261016052610180526101a0526101c0526101e05261020052610220526102405261026052610280526102a0526102c0526102e05261030052610320526103405261036052610380526103a0526103c0526103e05261040052610420526104405261046052610480526104a0526104c0526104e052610500526105205261054052610560526000610180516020826105c00101526020810190506102c0516020826105c0010152602081019050610400516020826105c0010152602081019050806105c0526105c090508051602082012090506105a0526106606000600a818352015b610660511515156102765760006105a05160208261068001015260208101905061018061066051600a81106101fa57600080fd5b60200201516020826106800101526020810190506102c061066051600a811061022257600080fd5b602002015160208261068001015260208101905061040061066051600a811061024a57600080fd5b6020020151602082610680010152602081019050806106805261068090508051602082012090506105a0525b5b81516001018083528114156101c6575b5050600061014051602082610760010152602081019050610160516020826107600101526020810190506105a0516020826107600101526020810190506105405160208261076001015260208101905061056051602082610760010152602081019050806107605261076090508051602082012090506107405261074051600052600051610580515650005b634a6f823360005114156105c457341561032c57600080fd5b600435602051811061033d57600080fd5b50602435602051811061034f57600080fd5b506000610120525b602061012051016101205261012061012051101561037457610357565b6000610120525b60206101205101610120526101206101205110156103985761037b565b6000610120525b60206101205101610120526101206101205110156103bc5761039f565b6373ad25716101405260043561016052602435610180526101a0604480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250506102e061018480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250506104206102c480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250506104043561056052610424356105805261058051610560516105405161052051610500516104e0516104c0516104a05161048051610460516104405161042051610400516103e0516103c0516103a05161038051610360516103405161032051610300516102e0516102c0516102a05161028051610260516102405161022051610200516101e0516101c0516101a0516101805161016051600658016100dc565b6105e0526105e05160005260206000f350005b600015610909575b610580526101405261016052610180526101a0526101c0526101e05261020052610220526102405261026052610280526102a0526102c0526102e05261030052610320526103405261036052610380526103a0526103c0526103e05261040052610420526104405261046052610480526104a0526104c0526104e052610500526105205261054052610560526000610140516020826105c0010152602081019050610160516020826105c0010152602081019050610180516020826105c00101526020810190506101a0516020826105c00101526020810190506101c0516020826105c00101526020810190506101e0516020826105c0010152602081019050610200516020826105c0010152602081019050610220516020826105c0010152602081019050610240516020826105c0010152602081019050610260516020826105c0010152602081019050610280516020826105c00101526020810190506102a0516020826105c00101526020810190506102c0516020826105c00101526020810190506102e0516020826105c0010152602081019050610300516020826105c0010152602081019050610320516020826105c0010152602081019050610340516020826105c0010152602081019050610360516020826105c0010152602081019050610380516020826105c00101526020810190506103a0516020826105c00101526020810190506103c0516020826105c00101526020810190506103e0516020826105c0010152602081019050610400516020826105c0010152602081019050610420516020826105c0010152602081019050610440516020826105c0010152602081019050610460516020826105c0010152602081019050610480516020826105c00101526020810190506104a0516020826105c00101526020810190506104c0516020826105c00101526020810190506104e0516020826105c0010152602081019050610500516020826105c0010152602081019050610520516020826105c0010152602081019050610540516020826105c0010152602081019050610560516020826105c0010152602081019050806105c0526105c090508051602082012090506105a0526105a051600052600051610580515650005b6000156109e1575b610220526101405261016052610180526101a0526101c0526101e0526102005260006101405160208261026001015260208101905061016051602082610260010152602081019050610180516020826102600101526020810190506101a0516020826102600101526020810190506101c0516020826102600101526020810190506101e05160208261026001015260208101905061020051602082610260010152602081019050806102605261026090508051602082012090506102405261024051600052600051610220515650005b6310660e866000511415610a905734156109fa57600080fd5b6004356020518110610a0b57600080fd5b506024356020518110610a1d57600080fd5b5063155960636101405260043561016052602435610180526044356101a0526064356101c0526084356101e05260a4356102005260c4356102205261022051610200516101e0516101c0516101a051610180516101605160065801610911565b610280526102805160005260206000f350005b600015610cf2575b6101805261014052610160526101a0526000610240525b6101a05160206001820306601f820103905061024051101515610ad157610aea565b610240516101c001526102405160200161024052610aaf565b60005060416101a0511815610b0757600060005260005161018051565b6101a0602060006020835103811315610b1f57600080fd5b046020026020018101519050610280526101a0602060206020835103811315610b4757600080fd5b0460200260200181015190506102a05260406001602082066103a0016101a0518284011115610b7557600080fd5b6041806103c0826020602088068803016101a001600060046018f1505081815280905090509050806020015160008251806020901315610bb457600080fd5b8091901215610bc257600080fd5b606051816020036101000a830480604051901315610bdf57600080fd5b8091901215610bed57600080fd5b9050905090506102c052601b6102c0511215610c30576102c0606051601b82510180604051901315610c1e57600080fd5b8091901215610c2c57600080fd5b8152505b610480601b8152601c81602001525060006104605261046061012060006002818352015b6101205160200261048001516102c0511415610c735760018352610c84565b5b8151600101808352811415610c54575b5050506104605160011415610ce257610140516104c0526102c0516000811215610cad57600080fd5b6104e05261028051610500526102a05161052052602060c060806104c060006001610bb8f15060c05160005260005161018051565b6000600052600051610180515650005b600015610db3575b6101605261014052610140517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff806000811215610d3e578060000360020a8204610d45565b8060020a82025b90509050604051811115610d5857600080fd5b61018052700100000000000000000000000000000000610d7757600080fd5b7001000000000000000000000000000000006101405106604051811115610d9d57600080fd5b6101a05261018051600052600051610160515650005b63f17535506000511415610de8573415610dcc57600080fd5b600060043560e05260c052604060c0205460005260206000f350005b63ac2a2e216000511415610e3d573415610e0157600080fd5b6004356020518110610e1257600080fd5b50600460043560e05260c052604060c02060243560e05260c052604060c0205460005260206000f350005b634026b7556000511415610e72573415610e5657600080fd5b600760043560e05260c052604060c0205460005260206000f350005b63f242432a6000511415611135573415610e8b57600080fd5b6004356020518110610e9c57600080fd5b506024356020518110610eae57600080fd5b5061012060843560040161014037610100608435600401351115610ed157600080fd5b600660043560e05260c052604060c0203360e05260c052604060c02054336004351417610efd57600080fd5b6308c379a06102805260206102a05260206102c0527f43616e6e6f74207472616e7366657220746f207a65726f20616464726573732e6102e0526102c050600060243518610f4c57608461029cfd5b6308c379a0610320526020610340526012610360527f4e6f7420656e6f75676820746f6b656e732e00000000000000000000000000006103805261036050606435600360043560e05260c052604060c02060443560e05260c052604060c020541015610fb957608461033cfd5b600360043560e05260c052604060c02060443560e05260c052604060c02060643581541015610fe757600080fd5b606435815403815550600360243560e05260c052604060c02060443560e05260c052604060c0208054606435825401101561102157600080fd5b6064358154018155506044356103c0526064356103e052602435600435337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6260406103c0a460006024353b1115611133576024353b61107f57600080fd5b602435301861108d57600080fd5b60206106406101c460a063f23a6e6161042052336104405260043561046052604435610480526064356104a052806104c052610140808051602001808461044001828460006004600a8704601201f16110e557600080fd5b50508051820160206001820306601f820103905060200191505061043c905060006024355af161111457600080fd5b600050610640516104005263f23a6e61610400511461113257600080fd5b5b005b63cf36e535600051141561163c57341561114e57600080fd5b600435602051811061115f57600080fd5b50602435602051811061117157600080fd5b506000610120525b602061012051016101205261012061012051101561119657611179565b6000610120525b60206101205101610120526101206101205110156111ba5761119d565b6101206102c435600401610140376101006102c4356004013511156111de57600080fd5b600660043560e05260c052604060c0203360e05260c052604060c0205433600435141761120a57600080fd5b6308c379a06102805260206102a05260206102c0527f43616e6e6f74207472616e7366657220746f207a65726f20616464726573732e6102e0526102c05060006024351861125957608461029cfd5b6103206000600a818352015b604461032051600a811061127857600080fd5b60200201356103405261018461032051600a811061129557600080fd5b6020020135600360043560e05260c052604060c0206103405160e05260c052604060c0205410156112c557600080fd5b5b8151600101808352811415611265575b505060443561036052606435610380526084356103a05260a4356103c05260c4356103e05260e435610400526101043561042052610124356104405261014435610460526101643561048052610184356104a0526101a4356104c0526101c4356104e0526101e435610500526102043561052052610224356105405261024435610560526102643561058052610284356105a0526102a4356105c052602435600435337f514c24e4790d7c31a095a1688a73a01f28d936a9a85d806ba95970d8ee88efa8610280610360a46105e06000600a818352015b60446105e051600a81106113c057600080fd5b602002013561060052600360043560e05260c052604060c0206106005160e05260c052604060c0206101846105e051600a81106113fc57600080fd5b60200201358154101561140e57600080fd5b6101846105e051600a811061142257600080fd5b6020020135815403815550600360243560e05260c052604060c0206106005160e05260c052604060c02080546101846105e051600a811061146257600080fd5b6020020135825401101561147557600080fd5b6101846105e051600a811061148957600080fd5b60200201358154018155505b81516001018083528114156113ad575b505060006024353b111561163a576024353b6114c057600080fd5b60243530186114ce57600080fd5b6020610aa06104046102e063a3bfc206610640523361066052600435610680526106a0604480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250506107e061018480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250508061092052610140808051602001808461066001828460006004600a8704601201f16115ec57600080fd5b50508051820160206001820306601f820103905060200191505061065c905060006024355af161161b57600080fd5b600050610aa0516106205263e324a00d610620511461163957600080fd5b5b005b62fdd58e600051141561169057341561165457600080fd5b600435602051811061166557600080fd5b50600360043560e05260c052604060c02060243560e05260c052604060c0205460005260206000f350005b63fbe31aea60005114156117935734156116a957600080fd5b6000610120525b610120516004013560205181106116c657600080fd5b5060206101205101610120526101206101205110156116e4576116b0565b6000610120525b6020610120510161012052610120610120511015611708576116eb565b6102806000600a818352015b6003600461028051600a811061172957600080fd5b602002013560e05260c052604060c02061014461028051600a811061174d57600080fd5b602002013560e05260c052604060c0205461014061028051600a811061177257600080fd5b60200201525b8151600101808352811415611714575b5050610140610140f3005b63a22cb46560005114156118235734156117ac57600080fd5b60043560205181106117bd57600080fd5b50602435600281106117ce57600080fd5b5060243560063360e05260c052604060c02060043560e05260c052604060c0205560243561014052600435337f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c316020610140a3005b63e985e9c5600051141561188a57341561183c57600080fd5b600435602051811061184d57600080fd5b50602435602051811061185f57600080fd5b50600660043560e05260c052604060c02060243560e05260c052604060c0205460005260206000f350005b63a70b070f6000511415611af85734156118a357600080fd5b60043560205181106118b457600080fd5b50610120604435600401610140376101006044356004013511156118d757600080fd5b6000600435186118e657600080fd5b6308c379a06102805260206102a052601b6102c0527f4f776e6572206f6e6c792063616e20637265617465206974656d2e00000000006102e0526102c050336002541461193457608461029cfd5b6000600360043560e05260c052604060c02060243560e05260c052604060c02055600180546001825401101561196957600080fd5b60018154018155506001600760243560e05260c052604060c0205561014080600560243560e05260c052604060c02060c052602060c020602082510161012060006009818352015b826101205160200211156119c4576119e6565b61012051602002850151610120518501555b81516001018083528114156119b1575b50505050505060206103405261034051610380526101408051602001806103405161038001828460006004600a8704601201f1611a2257600080fd5b5050610320610340516103800151610440818352015b610440610320511115611a4a57611a6b565b600061032051610340516103a00101535b8151600101808352811415611a38575b5050602061034051610380015160206001820306601f8201039050610340510101610340526024357f6bb7ff708619ba0610cba295a58592e0451dee2622938c8755667688daf3529b61034051610380a26024356103a05260006103c0526004356000337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6260406103a0a4005b6319a35d7c6000511415611d43573415611b1157600080fd5b6004356020518110611b2257600080fd5b506000610120525b6020610120510161012052610120610120511015611b4757611b2a565b600060043518611b5657600080fd5b6308c379a061014052602061016052601c610180527f4f776e6572206f6e6c792063616e20637265617465206974656d732e000000006101a052610180503360025414611ba457608461015cfd5b6101e06000600a818352015b60246101e051600a8110611bc357600080fd5b6020020135610200526000600360043560e05260c052604060c0206102005160e05260c052604060c020556001805460018254011015611c0257600080fd5b6001815401815550600160076102005160e05260c052604060c020555b8151600101808352811415611bb0575b5050610220600081526000816020015260008160400152600081606001526000816080015260008160a0015260008160c0015260008160e00152600081610100015260008161012001525060243561036052604435610380526064356103a0526084356103c05260a4356103e05260c4356104005260e43561042052610104356104405261012435610460526101443561048052610220516104a052610240516104c052610260516104e05261028051610500526102a051610520526102c051610540526102e051610560526103005161058052610320516105a052610340516105c0526004356000337f514c24e4790d7c31a095a1688a73a01f28d936a9a85d806ba95970d8ee88efa8610280610360a4005b63156e29f66000511415611d8157600061028052610280805160200180610140828460006004600a8704601201f1611d7a57600080fd5b5050611dce565b63731133e96000511415611dc65761012060643560040161014037610100606435600401351115611db157600080fd5b61014060643560040161014037600050611dce565b60001561208a575b3415611dd957600080fd5b6004356020518110611dea57600080fd5b50600060043518611dfa57600080fd5b6308c379a06102c05260206102e052601a610300527f4f776e6572206f6e6c792063616e206d696e74206974656d732e00000000000061032052610300503360025414611e485760846102dcfd5b610140610380525b61038051516020610380510161038052610380610380511015611e7257611e50565b6320171bef6103a0526024356103c0526103c05160065801610cfa565b61042052610360610380525b6103805152602061038051036103805261014061038051101515611ebe57611e9b565b6104205161036052600261036051146001610360511417611ede57600080fd5b6001610360511415611f5f576308c379a0610440526020610460526028610480527f43616e6e6f74206d696e74204e46542077697468205f737570706c79206d6f726104a0527f65207468616e20310000000000000000000000000000000000000000000000006104c05261048050600160443514611f5e5760a461045cfd5b5b604435600360043560e05260c052604060c02060243560e05260c052604060c0205560243561050052604435610520526004356000337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f626040610500a460006004353b1115612088576004353b611fd557600080fd5b6004353018611fe357600080fd5b60206107806101c460a063f23a6e6161056052336105805260006105a0526024356105c0526044356105e0528061060052610140808051602001808461058001828460006004600a8704601201f161203a57600080fd5b50508051820160206001820306601f820103905060200191505061057c905060006004355af161206957600080fd5b600050610780516105405263f23a6e61610540511461208757600080fd5b5b005b63c671854d60005114156120c857600061028052610280805160200180610140828460006004600a8704601201f16120c157600080fd5b5050612118565b63b07e58756000511415612110576101206102a435600401610140376101006102a4356004013511156120fa57600080fd5b6101406102a43560040161014037600050612118565b6000156124f6575b341561212357600080fd5b600435602051811061213457600080fd5b506000610120525b60206101205101610120526101206101205110156121595761213c565b6000610120525b602061012051016101205261012061012051101561217d57612160565b60006004351861218c57600080fd5b6308c379a06102c05260206102e052601a610300527f4f776e6572206f6e6c792063616e206d696e74206974656d732e000000000000610320526103005033600254146121da5760846102dcfd5b6103606000600a818352015b602461036051600a81106121f957600080fd5b6020020135610380526101406103c0525b6103c0515160206103c051016103c0526103c06103c051101561222c5761220a565b6320171bef6103e05261038051610400526104005160065801610cfa565b610460526103a06103c0525b6103c0515260206103c051036103c0526101406103c05110151561227957612256565b610460516103a05260026103a0511460016103a051141761229957600080fd5b60016103a05114156122cb57600161016461036051600a81106122bb57600080fd5b6020020135146122ca57600080fd5b5b61016461036051600a81106122df57600080fd5b6020020135600360043560e05260c052604060c0206103805160e05260c052604060c020555b81516001018083528114156121e6575b5050602435610480526044356104a0526064356104c0526084356104e05260a4356105005260c4356105205260e4356105405261010435610560526101243561058052610144356105a052610164356105c052610184356105e0526101a435610600526101c435610620526101e4356106405261020435610660526102243561068052610244356106a052610264356106c052610284356106e0526004356000337f514c24e4790d7c31a095a1688a73a01f28d936a9a85d806ba95970d8ee88efa8610280610480a46107006000600a818352015b60006004353b11156124e1576004353b61240357600080fd5b600435301861241157600080fd5b60206109606101c460a063f23a6e61610740523361076052600061078052602461070051600a811061244257600080fd5b60200201356107a05261016461070051600a811061245f57600080fd5b60200201356107c052806107e052610140808051602001808461076001828460006004600a8704601201f161249357600080fd5b50508051820160206001820306601f820103905060200191505061075c905060006004355af16124c257600080fd5b600050610960516107205263f23a6e6161072051146124e057600080fd5b5b5b81516001018083528114156123ea575b5050005b63b390c0ab60005114156125ea57341561250f57600080fd5b6308c379a061014052602061016052601a610180527f4e6f7420656e6f75676820746f6b656e7320746f206275726e2e0000000000006101a0526101805060243560033360e05260c052604060c02060043560e05260c052604060c02054101561257a57608461015cfd5b60033360e05260c052604060c02060043560e05260c052604060c020602435815410156125a657600080fd5b6024358154038155506004356101e05260243561020052600033337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6260406101e0a4005b63b59afe52600051141561282b57341561260357600080fd5b6000610120525b60206101205101610120526101206101205110156126275761260a565b6000610120525b602061012051016101205261012061012051101561264b5761262e565b6101406000600a818352015b600461014051600a811061266a57600080fd5b60200201356101605261014461014051600a811061268757600080fd5b602002013560033360e05260c052604060c0206101605160e05260c052604060c0205410156126b557600080fd5b5b8151600101808352811415612657575b50506101806000600a818352015b600461018051600a81106126e757600080fd5b60200201356101a05260033360e05260c052604060c0206101a05160e05260c052604060c02061014461018051600a811061272157600080fd5b60200201358154101561273357600080fd5b61014461018051600a811061274757600080fd5b60200201358154038155505b81516001018083528114156126d4575b50506004356101c0526024356101e05260443561020052606435610220526084356102405260a4356102605260c4356102805260e4356102a052610104356102c052610124356102e0526101443561030052610164356103205261018435610340526101a435610360526101c435610380526101e4356103a052610204356103c052610224356103e05261024435610400526102643561042052600033337f514c24e4790d7c31a095a1688a73a01f28d936a9a85d806ba95970d8ee88efa86102806101c0a4005b63f2526ada6000511415612869576000610320526103208051602001806101e0828460006004600a8704601201f161286257600080fd5b50506128b9565b63a835c36960005114156128b157610120610464356004016101e0376101006104643560040135111561289b57600080fd5b610140610464356004016101e0376000506128b9565b600015613725575b60043560205181106128ca57600080fd5b5060243560205181106128dc57600080fd5b506000610120525b6020610120510161012052610120610120511015612901576128e4565b6000610120525b602061012051016101205261012061012051101561292557612908565b6000610120525b60206101205101610120526101206101205110156129495761292c565b6061610444356004016101403760416104443560040135111561296b57600080fd5b6308c379a061036052602061038052602c6103a0527f5f66726f6d206d757374206265207468652073656e646572206f7220617070726103c0527f6f766564206164647265737300000000000000000000000000000000000000006103e0526103a050600660043560e05260c052604060c0203360e05260c052604060c020543360043514176129fc5760a461037cfd5b6308c379a0610420526020610440526025610460527f44657374696e6174696f6e2061646472657373206d757374206265206e6f6e2d610480527f7a65726f2e0000000000000000000000000000000000000000000000000000006104a05261046050600060243518612a705760a461043cfd5b6308c379a06104e0526020610500526015610520527f4e6f6e6365206d75737420626520756e757365642e00000000000000000000006105405261052050600460043560e05260c052604060c0206104243560e05260c052604060c0205415612ada5760846104fcfd5b6308c379a06105805260206105a05260256105c0527f53656e64657220686173206e6f742070726f766964656420656e6f75676820656105e0527f746865722e000000000000000000000000000000000000000000000000000000610600526105c050346104043514612b4e5760a461059cfd5b6106406000600a818352015b604461064051600a8110612b6d57600080fd5b602002013561066052600061018461064051600a8110612b8c57600080fd5b60200201351115612c03576102c461064051600a8110612bab57600080fd5b602002013515612bba57600080fd5b61018461064051600a8110612bce57600080fd5b6020020135600360043560e05260c052604060c0206106605160e05260c052604060c020541015612bfe57600080fd5b612c6b565b61018461064051600a8110612c1757600080fd5b602002013515612c2657600080fd5b6102c461064051600a8110612c3a57600080fd5b6020020135600360243560e05260c052604060c0206106605160e05260c052604060c020541015612c6a57600080fd5b5b5b8151600101808352811415612b5a575b50506101406106a0525b6106a0515160206106a051016106a0526106a06106a0511015612ca857612c86565b6373ad25716106c0526004356106e05260243561070052610720604480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e00152806101000135826101000152806101200135826101200152505061086061018480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250506109a06102c480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e00152806101000135826101000152806101200135826101200152505061040435610ae05261042435610b0052610b0051610ae051610ac051610aa051610a8051610a6051610a4051610a2051610a00516109e0516109c0516109a05161098051610960516109405161092051610900516108e0516108c0516108a05161088051610860516108405161082051610800516107e0516107c0516107a05161078051610760516107405161072051610700516106e051600658016100dc565b610b60526106806106a0525b6106a0515260206106a051036106a0526101406106a051101515612ecc57612ea9565b610b605161068052610140610ba0525b610ba051516020610ba05101610ba052610ba0610ba0511015612efe57612edc565b6040636f868168610bc05261068051610be05280610c00526101408080516020018084610be001828460006004600a8704601201f1612f3c57600080fd5b50508051820160206001820306601f820103905060200191505050610c005180610be00180518060206001820306601f82010390508201610ce0525050505b610c20610ce0511015612f8d57612fa2565b610ce051516020610ce05103610ce052612f7b565b610c0051610be05160065801610a98565b610d0052610b80610ba0525b610ba051526020610ba05103610ba052610140610ba051101515612fe257612fbf565b610d0051610b80526308c379a0610d20526020610d40526020610d60527f5369676e657220646f6573206e6f74206d61746368207369676e61747572652e610d8052610d6050602435610b80511461303b576084610d3cfd5b600160043360e05260c052604060c0206104243560e05260c052604060c02055610dc06000600a818352015b6044610dc051600a811061307a57600080fd5b6020020135610de0526000610184610dc051600a811061309957600080fd5b6020020135111561317457600360043560e05260c052604060c020610de05160e05260c052604060c020610184610dc051600a81106130d757600080fd5b6020020135815410156130e957600080fd5b610184610dc051600a81106130fd57600080fd5b6020020135815403815550600360243560e05260c052604060c020610de05160e05260c052604060c0208054610184610dc051600a811061313d57600080fd5b6020020135825401101561315057600080fd5b610184610dc051600a811061316457600080fd5b6020020135815401815550613240565b600360043560e05260c052604060c020610de05160e05260c052604060c02080546102c4610dc051600a81106131a957600080fd5b602002013582540110156131bc57600080fd5b6102c4610dc051600a81106131d057600080fd5b6020020135815401815550600360243560e05260c052604060c020610de05160e05260c052604060c0206102c4610dc051600a811061320e57600080fd5b60200201358154101561322057600080fd5b6102c4610dc051600a811061323457600080fd5b60200201358154038155505b5b8151600101808352811415613067575b50506000600060006000346024356000f161326b57600080fd5b604435610e0052606435610e2052608435610e405260a435610e605260c435610e805260e435610ea05261010435610ec05261012435610ee05261014435610f005261016435610f205261018435610f40526101a435610f60526101c435610f80526101e435610fa05261020435610fc05261022435610fe0526102443561100052610264356110205261028435611040526102a43561106052602435600435337f514c24e4790d7c31a095a1688a73a01f28d936a9a85d806ba95970d8ee88efa8610280610e00a4604435611080526064356110a0526084356110c05260a4356110e05260c4356111005260e43561112052610104356111405261012435611160526101443561118052610164356111a0526102c4356111c0526102e4356111e052610304356112005261032435611220526103443561124052610364356112605261038435611280526103a4356112a0526103c4356112c0526103e4356112e052600435602435337f514c24e4790d7c31a095a1688a73a01f28d936a9a85d806ba95970d8ee88efa8610280611080a460006024353b1115613590576024353b61341657600080fd5b602435301861342457600080fd5b60206117806104046102e063a3bfc20661132052336113405260243561136052611380604480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250506114c061018480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e00152806101000135826101000152806101200135826101200152505080611600526101e0808051602001808461134001828460006004600a8704601201f161354257600080fd5b50508051820160206001820306601f820103905060200191505061133c905060006024355af161357157600080fd5b6000506117805161130052630c97e564611300511461358f57600080fd5b5b60006004353b1115613723576004353b6135a957600080fd5b60043530186135b757600080fd5b6020611c206104046102e063a3bfc2066117c052336117e05260043561180052611820604480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250506119606102c480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e00152806101000135826101000152806101200135826101200152505080611aa0526101e080805160200180846117e001828460006004600a8704601201f16136d557600080fd5b50508051820160206001820306601f82010390506020019150506117dc905060006004355af161370457600080fd5b600050611c20516117a052630c97e5646117a0511461372257600080fd5b5b005b636e8205b26000511415613763576000610320526103208051602001806101e0828460006004600a8704601201f161375c57600080fd5b50506137b3565b63183f5ec560005114156137ab57610120610104356004016101e0376101006101043560040135111561379557600080fd5b610140610104356004016101e0376000506137b3565b600015613f5d575b60043560205181106137c457600080fd5b5060243560205181106137d657600080fd5b50606160e43560040161014037604160e4356004013511156137f757600080fd5b600660043560e05260c052604060c0203360e05260c052604060c0205433600435141761382357600080fd5b6308c379a06103605260206103805260256103a0527f44657374696e6174696f6e2061646472657373206d757374206265206e6f6e2d6103c0527f7a65726f2e0000000000000000000000000000000000000000000000000000006103e0526103a0506000602435186138975760a461037cfd5b6308c379a0610420526020610440526015610460527f4e6f6e6365206d75737420626520756e757365642e00000000000000000000006104805261046050600460043560e05260c052604060c02060c43560e05260c052604060c020541561390057608461043cfd5b6308c379a06104c05260206104e0526025610500527f53656e64657220686173206e6f742070726f766964656420656e6f7567682065610520527f746865722e00000000000000000000000000000000000000000000000000000061054052610500503460a435146139735760a46104dcfd5b600060643511156139bd576084351561398b57600080fd5b606435600360043560e05260c052604060c02060443560e05260c052604060c0205410156139b857600080fd5b6139f8565b606435156139ca57600080fd5b608435600360243560e05260c052604060c02060443560e05260c052604060c0205410156139f757600080fd5b5b6101406105a0525b6105a0515160206105a051016105a0526105a06105a0511015613a2257613a00565b63155960636105c0526004356105e0526024356106005260443561062052606435610640526084356106605260a4356106805260c4356106a0526106a05161068051610660516106405161062051610600516105e05160065801610911565b610700526105806105a0525b6105a0515260206105a051036105a0526101406105a051101515613ab057613a8d565b6107005161058052610140610740525b61074051516020610740510161074052610740610740511015613ae257613ac0565b6040636f868168610760526105805161078052806107a052610140808051602001808461078001828460006004600a8704601201f1613b2057600080fd5b50508051820160206001820306601f8201039050602001915050506107a051806107800180518060206001820306601f82010390508201610880525050505b6107c0610880511015613b7157613b86565b61088051516020610880510361088052613b5f565b6107a0516107805160065801610a98565b6108a052610720610740525b6107405152602061074051036107405261014061074051101515613bc657613ba3565b6108a051610720526308c379a06108c05260206108e0526020610900527f5369676e657220646f6573206e6f74206d61746368207369676e61747572652e61092052610900506024356107205114613c1f5760846108dcfd5b600160043360e05260c052604060c02060c43560e05260c052604060c0205560006064351115613cbf57600360043560e05260c052604060c02060443560e05260c052604060c02060643581541015613c7757600080fd5b606435815403815550600360243560e05260c052604060c02060443560e05260c052604060c02080546064358254011015613cb157600080fd5b606435815401815550613d31565b600360043560e05260c052604060c02060443560e05260c052604060c02080546084358254011015613cf057600080fd5b608435815401815550600360243560e05260c052604060c02060443560e05260c052604060c02060843581541015613d2757600080fd5b6084358154038155505b6000600060006000346024356000f1613d4957600080fd5b6044356109605260643561098052602435600435337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f626040610960a46044356109a0526084356109c052600435602435337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6260406109a0a460006024353b1115613e8e576024353b613dda57600080fd5b6024353018613de857600080fd5b6020610c206101c460a063f23a6e61610a005233610a2052602435610a4052604435610a6052606435610a805280610aa0526101e08080516020018084610a2001828460006004600a8704601201f1613e4057600080fd5b50508051820160206001820306601f8201039050602001915050610a1c905060006024355af1613e6f57600080fd5b600050610c20516109e052630c97e5646109e05114613e8d57600080fd5b5b60006004353b1115613f5b576004353b613ea757600080fd5b6004353018613eb557600080fd5b6020610e806101c460a063f23a6e61610c605233610c8052600435610ca052604435610cc052608435610ce05280610d00526101e08080516020018084610c8001828460006004600a8704601201f1613f0d57600080fd5b50508051820160206001820306601f8201039050602001915050610c7c905060006004355af1613f3c57600080fd5b600050610e8051610c4052630c97e564610c405114613f5a57600080fd5b5b005b638da5cb5b6000511415613f84573415613f7657600080fd5b60025460005260206000f350005b60006000fd\",\n  \"source\": \"# Author: Sören Steiger, github.com/ssteiger\\n# Author: Fetch.ai, github.com/fetchai\\n# License: MIT\\n\\n# ERC1155 Token Standard\\n# https://eips.ethereum.org/EIPS/eip-1155\\n\\n########################EXTERNAL-CONTRACTS####################################\\n\\ncontract ERC1155TokenReceiver:\\n    # Note: The ERC-165 identifier for this interface is 0x4e2312e0.\\n\\n    def onERC1155Received(_operator: address, _from: address, _id: uint256, _value: uint256,\\n                          _data: bytes[256]) -> bytes32: modifying  # TODO: should return bytes4\\n    #        \\\"\\\"\\\"\\n    #       @notice Handle the receipt of a single ERC1155 token type.\\n    #       @dev An ERC1155-compliant smart contract MUST call this function on the token recipient contract, at the end of a `safeTransferFrom` after the balance has been updated.        \\n    #       This function MUST return `bytes4(keccak256(\\\"onERC1155Received(address,address,uint256,uint256,bytes)\\\"))` (i.e. 0xf23a6e61) if it accepts the transfer.\\n    #       This function MUST revert if it rejects the transfer.\\n    #       Return of any other value than the prescribed keccak256 generated value MUST result in the transaction being reverted by the caller.\\n    #       @param _operator  The address which initiated the transfer (i.e. msg.sender)\\n    #       @param _from      The address which previously owned the token\\n    #       @param _id        The ID of the token being transferred\\n    #       @param _value     The amount of tokens being transferred\\n    #       @param _data      Additional data with no specified format\\n    #       @return           `bytes4(keccak256(\\\"onERC1155Received(address,address,uint256,uint256,bytes)\\\"))`\\n    #       \\\"\\\"\\\"\\n\\n    def onERC1155BatchReceived(_operator: address, _from: address, _ids: uint256[BATCH_SIZE], _values: uint256[BATCH_SIZE],\\n                               _data: bytes[256]) -> bytes32: modifying  # TODO: should return bytes4\\n    #       \\\"\\\"\\\"\\n    #       @notice Handle the receipt of multiple ERC1155 token types.\\n    #       @dev An ERC1155-compliant smart contract MUST call this function on the token recipient contract, at the end of a `safeBatchTransferFrom` after the balances have been updated.        \\n    #       This function MUST return `bytes4(keccak256(\\\"onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)\\\"))` (i.e. 0xbc197c81) if it accepts the transfer(s).\\n    #       This function MUST revert if it rejects the transfer(s).\\n    #       Return of any other value than the prescribed keccak256 generated value MUST result in the transaction being reverted by the caller.\\n    #       @param _operator  The address which initiated the batch transfer (i.e. msg.sender)\\n    #       @param _from      The address which previously owned the token\\n    #       @param _ids       An array containing ids of each token being transferred (order and length must match _values array)\\n    #       @param _values    An array containing amounts of each token being transferred (order and length must match _ids array)\\n    #       @param _data      Additional data with no specified format\\n    #       @return           `bytes4(keccak256(\\\"onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)\\\"))`\\n    #       \\\"\\\"\\\"\\n\\n########################END-EXTERNAL-CONTRACTS####################################\\n########################EVENTS####################################\\n\\nMAX_URI_SIZE: constant(uint256) = 1024\\n\\nTransferSingle: event({_operator: indexed(address), _from: indexed(address), _to: indexed(address), _id: uint256,\\n                       _value: uint256})\\n#   @dev Either `TransferSingle` or `TransferBatch` MUST emit when tokens are transferred, including zero value transfers as well as minting or burning (see \\\"Safe Transfer Rules\\\" section of the standard).\\n#        The `_operator` argument MUST be the address of an account/contract that is approved to make the transfer (SHOULD be msg.sender).\\n#        The `_from` argument MUST be the address of the holder whose balance is decreased.\\n#        The `_to` argument MUST be the address of the recipient whose balance is increased.\\n#        The `_id` argument MUST be the token type being transferred.\\n#        The `_value` argument MUST be the number of tokens the holder balance is decreased by and match what the recipient balance is increased by.\\n#        When minting/creating tokens, the `_from` argument MUST be set to `0x0` (i.e. zero address).\\n#        When burning/destroying tokens, the `_to` argument MUST be set to `0x0` (i.e. zero address).\\n\\n\\nTransferBatch: event({_operator: indexed(address), _from: indexed(address), _to: indexed(address),\\n                      _ids: uint256[BATCH_SIZE], _values: uint256[BATCH_SIZE]})\\n#   @dev Either `TransferSingle` or `TransferBatch` MUST emit when tokens are transferred, including zero value transfers as well as minting or burning (see \\\"Safe Transfer Rules\\\" section of the standard).\\n#        The `_operator` argument MUST be the address of an account/contract that is approved to make the transfer (SHOULD be msg.sender).\\n#        The `_from` argument MUST be the address of the holder whose balance is decreased.\\n#        The `_to` argument MUST be the address of the recipient whose balance is increased.\\n#        The `_ids` argument MUST be the list of tokens being transferred.\\n#        The `_values` argument MUST be the list of number of tokens (matching the list and order of tokens specified in _ids) the holder balance is decreased by and match what the recipient balance is increased by.\\n#        When minting/creating tokens, the `_from` argument MUST be set to `0x0` (i.e. zero address).\\n#        When burning/destroying tokens, the `_to` argument MUST be set to `0x0` (i.e. zero address).\\n\\n\\nApprovalForAll: event({_owner: indexed(address), _operator: indexed(address), _approved: bool})\\n#   @dev MUST emit when approval for a second party/operator address to manage all tokens for an owner address is enabled or disabled (absence of an event assumes disabled).\\n\\n\\nURI: event({_value: string[MAX_URI_SIZE], _id: indexed(uint256)})\\n#   @dev MUST emit when the URI is updated for a token ID.\\n#        URIs are defined in RFC 3986.\\n#        The URI MUST point to a JSON file that conforms to the \\\"ERC-1155 Metadata URI JSON Schema\\\".\\n\\n########################END-EVENTS####################################\\n########################INITIALIZATION####################################\\n\\nsupportedInterfaces: map(bytes32, bool)\\n# https://eips.ethereum.org/EIPS/eip-165\\nERC165_INTERFACE_ID: constant(bytes32)  = 0x0000000000000000000000000000000000000000000000000000000001ffc9a7\\nERC1155_INTERFACE_ID: constant(bytes32) = 0x00000000000000000000000000000000000000000000000000000000d9b67a26\\ntokensIdCount: uint256\\nowner: public(address)\\n\\nbalancesOf: map(address, map(uint256, uint256))\\nnoncesOf: map(address, map(uint256, bool))\\nuri: map(uint256, string[256])\\noperators: map(address, map(address, bool))\\ntoken_ids: map(uint256, bool)\\n\\n# This is to be set before contract migration!\\nBATCH_SIZE: constant(uint256) = 10\\n\\n\\n@public\\ndef __init__():\\n    \\\"\\\"\\\"\\n    @notice Called once and only upon contract deployment.\\n    \\\"\\\"\\\"\\n    self.tokensIdCount = convert(0, uint256)\\n    self.supportedInterfaces[ERC165_INTERFACE_ID] = True\\n    self.supportedInterfaces[ERC1155_INTERFACE_ID] = True\\n    self.owner = msg.sender\\n\\n########################END-INITIALIZATION####################################\\n########################PRIVATE-FUNCTIONS####################################\\n\\n\\n######### THIS IS A TEMPORARY SOLUTION #################\\n@public\\n@constant\\ndef getAddress(_addr: address) -> bytes32:\\n    hash: bytes32 = convert(_addr, bytes32)\\n    return hash\\n##################### END ##############################\\n\\n@private\\n@constant\\ndef _getHash(_from: address, _to: address, _ids: uint256[BATCH_SIZE], _from_supplies: uint256[BATCH_SIZE], _to_supplies: uint256[BATCH_SIZE], _value_eth: uint256, _nonce: uint256) -> bytes32:\\n    \\\"\\\"\\\"\\n    @notice Get the hash from the tx values.\\n    @param _from          The address of the sender.\\n    @param _to            The address of the receiver.\\n    @param _ids           The ids of the tokens.\\n    @param _from_supplies The supply of token values that will send the _from.\\n    @param _to_supplies   The supply of token values that will send the _from.\\n    @param _value_eth     The value of the ether.\\n    @param _nonce         The nonce.\\n    @return the hash\\n    \\\"\\\"\\\"\\n    aggregate_hash: bytes32 = keccak256(concat(convert(_ids[0], bytes32), convert(_from_supplies[0], bytes32), convert(_to_supplies[0], bytes32)))\\n    for i in range(BATCH_SIZE):\\n      if not i == 0:\\n        aggregate_hash = keccak256(concat(aggregate_hash, convert(_ids[i], bytes32), convert(_from_supplies[i], bytes32), convert(_to_supplies[i], bytes32)))\\n    hash: bytes32 = keccak256(concat(convert(_from, bytes32),\\n                              convert(_to, bytes32),\\n                              aggregate_hash,\\n                              convert(_value_eth, bytes32),\\n                              convert(_nonce, bytes32)))\\n    return hash\\n\\n\\n@public\\n@constant\\ndef getHash(_from: address, _to: address, _ids: uint256[BATCH_SIZE], _from_supplies: uint256[BATCH_SIZE], _to_supplies: uint256[BATCH_SIZE], _value_eth: uint256, _nonce: uint256) -> bytes32:\\n    \\\"\\\"\\\"\\n    @notice Get the hash from the tx values.\\n    @param _from          The address of the sender.\\n    @param _to            The address of the receiver.\\n    @param _ids           The ids of the tokens.\\n    @param _from_supplies The supply of token values that will send the _from.\\n    @param _to_supplies   The supply of token values that will send the _from.\\n    @param _value_eth     The value of the ether.\\n    @param _nonce         The nonce.\\n    @return the hash\\n    \\\"\\\"\\\"\\n    return self._getHash(_from, _to, _ids, _from_supplies, _to_supplies, _value_eth, _nonce)\\n\\n\\n@private\\n@constant\\ndef getHashOld(_from: address, _to: address, _ids: uint256[BATCH_SIZE], _from_supplies: uint256[BATCH_SIZE], _to_supplies: uint256[BATCH_SIZE], _value_eth: uint256, _nonce: uint256) -> bytes32:\\n    \\\"\\\"\\\"\\n    @notice Get the hash from the tx values.\\n    @param _from          The address of the sender.\\n    @param _to            The address of the receiver.\\n    @param _ids           The ids of the tokens.\\n    @param _from_supplies The supply of token values that will send the _from.\\n    @param _to_supplies   The supply of token values that will send the _from.\\n    @param _value_eth     The value of the ether.\\n    @param _nonce         The nonce.\\n    @return the hash\\n    \\\"\\\"\\\"\\n    hash: bytes32 = keccak256(concat(convert(_from, bytes32),\\n                              convert(_to, bytes32),\\n                              convert(_ids[0], bytes32),\\n                              convert(_ids[1], bytes32),\\n                              convert(_ids[2], bytes32),\\n                              convert(_ids[3], bytes32),\\n                              convert(_ids[4], bytes32),\\n                              convert(_ids[5], bytes32),\\n                              convert(_ids[6], bytes32),\\n                              convert(_ids[7], bytes32),\\n                              convert(_ids[8], bytes32),\\n                              convert(_ids[9], bytes32),\\n                              convert(_from_supplies[0], bytes32),\\n                              convert(_from_supplies[1], bytes32),\\n                              convert(_from_supplies[2], bytes32),\\n                              convert(_from_supplies[3], bytes32),\\n                              convert(_from_supplies[4], bytes32),\\n                              convert(_from_supplies[5], bytes32),\\n                              convert(_from_supplies[6], bytes32),\\n                              convert(_from_supplies[7], bytes32),\\n                              convert(_from_supplies[8], bytes32),\\n                              convert(_from_supplies[9], bytes32),\\n                              convert(_to_supplies[0], bytes32),\\n                              convert(_to_supplies[1], bytes32),\\n                              convert(_to_supplies[2], bytes32),\\n                              convert(_to_supplies[3], bytes32),\\n                              convert(_to_supplies[4], bytes32),\\n                              convert(_to_supplies[5], bytes32),\\n                              convert(_to_supplies[6], bytes32),\\n                              convert(_to_supplies[7], bytes32),\\n                              convert(_to_supplies[8], bytes32),\\n                              convert(_to_supplies[9], bytes32),\\n                              convert(_value_eth, bytes32),\\n                              convert(_nonce, bytes32)))\\n    return hash\\n\\n\\n@private\\n@constant\\ndef _getSingleHash(_from: address, _to: address, _id: uint256, _from_supply: uint256, _to_supply: uint256, _value_eth: uint256, _nonce: uint256) -> bytes32:\\n    \\\"\\\"\\\"\\n    @notice Get the hash from the tx values.\\n    @param _from            The address of the sender.\\n    @param _to              The address of the receiver.\\n    @param _id              The id of the tokens.\\n    @param _from_supply     The from token value. (_from sends)\\n    @param _to_supply       The to token value (_to sends).\\n    @param _value_eth       The value of the ether.\\n    @param _nonce           The nonce.\\n    @return the hash\\n    \\\"\\\"\\\"\\n    hash: bytes32 = keccak256(concat(convert(_from, bytes32),\\n                              convert(_to, bytes32),\\n                              convert(_id, bytes32),\\n                              convert(_from_supply, bytes32),\\n                              convert(_to_supply, bytes32),\\n                              convert(_value_eth, bytes32),\\n                              convert(_nonce, bytes32)))\\n    return hash\\n\\n\\n@public\\n@constant\\ndef getSingleHash(_from: address, _to: address, _id: uint256, _from_supply: uint256, _to_supply: uint256, _value_eth: uint256, _nonce: uint256) -> bytes32:\\n    \\\"\\\"\\\"\\n    @notice Get the hash from the tx values.\\n    @param _from            The address of the sender.\\n    @param _to              The address of the receiver.\\n    @param _id              The id of the tokens.\\n    @param _from_supply     The from token value. (_from sends)\\n    @param _to_supply       The to token value (_to sends).\\n    @param _value_eth       The value of the ether.\\n    @param _nonce           The nonce.\\n    @return the hash\\n    \\\"\\\"\\\"\\n    return self._getSingleHash(_from, _to, _id, _from_supply, _to_supply, _value_eth, _nonce)\\n\\n\\n@private\\n@constant\\ndef ecrecoverSig(_hash: bytes32, _sig: bytes[65]) -> address:\\n    \\\"\\\"\\\"\\n    @notice Check whether the the signature matches the hash.\\n    @param _hash The hash to be checked.\\n    @param _sig  The signature which is meant to match the hash.\\n    @return the address which signed the signature or the zero address\\n    \\\"\\\"\\\"\\n    if len(_sig) != 65:\\n        return ZERO_ADDRESS\\n    # ref. https://gist.github.com/axic/5b33912c6f61ae6fd96d6c4a47afde6d\\n    # The signature format is a compact form of:\\n    # {bytes32 r}{bytes32 s}{uint8 v}\\n    r: bytes32 = extract32(_sig, 0, type=bytes32)\\n    s: bytes32 = extract32(_sig, 32, type=bytes32)\\n    v: int128 = convert(slice(_sig, start=64, len=1), int128)\\n    # Version of signature should be 27 or 28, but 0 and 1 are also possible versions.\\n    # geth uses [0, 1] and some clients have followed. This might change, see:\\n    # https://github.com/ethereum/go-ethereum/issues/2053\\n    if v < 27:\\n        v += 27\\n    if v in [27, 28]:\\n        return ecrecover(_hash, convert(v, uint256), convert(r, uint256), convert(s, uint256))\\n    return ZERO_ADDRESS\\n\\n\\n@private\\n@constant\\ndef decode_id(id: uint256) -> int128:\\n    \\\"\\\"\\\"\\n    @notice Decodes the id of the token inorder to find out if it NFT or FT.\\n    @param id: uint256\\n    @return token_id : int128 (Specified id for FT and NFT.)\\n    @dev shift(x, -y): returns x with the bits shifted to the right by y places, which is equivalent to dividing x by 2**y.\\n    \\\"\\\"\\\"\\n    decoded_token_id: int128 = convert(shift(id, -128), int128)\\n    decoded_index: int128 = convert(id % 2 ** 128, int128)\\n    return decoded_token_id\\n\\n########################END-PRIVATE-FUNCTIONS################################\\n########################PUBLIC-FUNCTIONS#####################################\\n\\n@public\\n@constant\\ndef supportsInterface(_interfaceID: bytes32) -> bool:\\n    \\\"\\\"\\\"\\n    @notice Check whether the interface id is supported.\\n    @param _interfaceID The interface id\\n    @return True if the interface id is supported.\\n    \\\"\\\"\\\"\\n    return self.supportedInterfaces[_interfaceID]\\n\\n@public\\n@constant\\ndef is_nonce_used(addr: address, nonce: uint256) -> bool:\\n    \\\"\\\"\\\"\\n    @notice Checks if the given nonce for the give address is unused.\\n    @param nonce: uint256 the counter of the transaction\\n    @param address: the address that want to transact.\\n    \\\"\\\"\\\"\\n    return self.noncesOf[addr][nonce]\\n\\n@public\\n@constant\\ndef is_token_id_exists(token_id: uint256) -> bool:\\n    \\\"\\\"\\\"\\n    @notice Checks if the given token_id is already created.\\n    @param token_id: uint256 the id of the token.\\n    \\\"\\\"\\\"\\n    return self.token_ids[token_id]\\n\\n@public\\ndef safeTransferFrom(_from: address, _to: address, _id: uint256, _value: uint256, _data: bytes[256]):\\n    \\\"\\\"\\\"\\n    @notice Transfers `_value` amount of an `_id` from the `_from` address to the `_to` address specified (with safety call).\\n    @dev Caller must be approved to manage the tokens being transferred out of the `_from` account (see \\\"Approval\\\" section of the standard).\\n         MUST revert if `_to` is the zero address.\\n         MUST revert if balance of holder for token `_id` is lower than the `_value` sent.\\n         MUST revert on any other error.\\n         MUST emit the `TransferSingle` event to reflect the balance change (see \\\"Safe Transfer Rules\\\" section of the standard).\\n         After the above conditions are met, this function MUST check if `_to` is a smart contract (e.g. code size > 0). If so, it MUST call `onERC1155Received` on `_to` and act appropriately (see \\\"Safe Transfer Rules\\\" section of the standard).\\n    @param _from    Source address\\n    @param _to      Target address\\n    @param _id      ID of the token type\\n    @param _value   Transfer amount\\n    @param _data    Additional data with no specified format, MUST be sent unaltered in call to `onERC1155Received` on `_to`\\n    @return None\\n    \\\"\\\"\\\"\\n    assert _from == msg.sender or (self.operators[_from])[msg.sender]\\n    assert _to != ZERO_ADDRESS, \\\"Cannot transfer to zero address.\\\"\\n    assert self.balancesOf[_from][_id] >= _value, \\\"Not enough tokens.\\\"\\n\\n    self.balancesOf[_from][_id] -= _value\\n    self.balancesOf[_to][_id] += _value\\n\\n    log.TransferSingle(msg.sender, _from, _to, _id, _value)\\n\\n    if _to.is_contract:\\n        returnValue: bytes32 = ERC1155TokenReceiver(_to).onERC1155Received(msg.sender, _from, _id, _value, _data)\\n        assert returnValue == method_id(\\\"onERC1155Received(address,address,uint256,uint256,bytes)\\\", bytes32)\\n\\n\\n@public\\ndef safeBatchTransferFrom(_from: address, _to: address, _ids: uint256[BATCH_SIZE], _values: uint256[BATCH_SIZE], _data: bytes[256]):\\n    \\\"\\\"\\\"\\n    @notice Transfers `_values` amount(s) of `_ids` from the `_from` address to the `_to` address specified (with safety call).\\n    @dev Caller must be approved to manage the tokens being transferred out of the `_from` account (see \\\"Approval\\\" section of the standard).\\n        MUST revert if `_to` is the zero address.\\n        MUST revert if length of `_ids` is not the same as length of `_values`.\\n        MUST revert if any of the balance(s) of the holder(s) for token(s) in `_ids` is lower than the respective amount(s) in `_values` sent to the recipient.\\n        MUST revert on any other error.\\n        MUST emit `TransferSingle` or `TransferBatch` event(s) such that all the balance changes are reflected (see \\\"Safe Transfer Rules\\\" section of the standard).\\n        Balance changes and events MUST follow the ordering of the arrays (_ids[0]/_values[0] before _ids[1]/_values[1], etc).\\n        After the above conditions for the transfer(s) in the batch are met, this function MUST check if `_to` is a smart contract (e.g. code size > 0). If so, it MUST call the relevant `ERC1155TokenReceiver` hook(s) on `_to` and act appropriately (see \\\"Safe Transfer Rules\\\" section of the standard).\\n    @param _from    Source address\\n    @param _to      Target address\\n    @param _ids     IDs of each token type (order and length must match _values array)\\n    @param _values  Transfer amounts per token type (order and length must match _ids array)\\n    @param _data    Additional data with no specified format, MUST be sent unaltered in call to the `ERC1155TokenReceiver` hook(s) on `_to`\\n    @return None\\n    \\\"\\\"\\\"\\n    assert _from == msg.sender or (self.operators[_from])[msg.sender]\\n    assert _to != ZERO_ADDRESS, \\\"Cannot transfer to zero address.\\\"\\n    for i in range(BATCH_SIZE):\\n        id: uint256 = _ids[i]\\n        assert self.balancesOf[_from][id] >= _values[i]\\n\\n    log.TransferBatch(msg.sender, _from, _to, _ids, _values)\\n\\n    for i in range(BATCH_SIZE):\\n        id: uint256 = _ids[i]\\n        self.balancesOf[_from][id] -= _values[i]\\n        self.balancesOf[_to][id] += _values[i]\\n\\n    if _to.is_contract:\\n        returnValue: bytes32 = ERC1155TokenReceiver(_to).onERC1155BatchReceived(msg.sender, _from, _ids, _values, _data)\\n        assert returnValue == method_id(\\\"onERC1155BatchReceived(address,address,uint256[BATCH_SIZE],uint256[BATCH_SIZE],bytes)\\\", bytes32)\\n\\n\\n@public\\n@constant\\ndef balanceOf(_owner: address, _id: uint256) -> uint256:\\n    \\\"\\\"\\\"\\n    @notice Get the balance of an account's tokens.\\n    @param  _owner The address of the token holder\\n    @param  _id    ID of the token\\n    @return The _owner's balance of the token type requested\\n    \\\"\\\"\\\"\\n    return self.balancesOf[_owner][_id]\\n\\n\\n@public\\n@constant\\ndef balanceOfBatch( _owner: address[BATCH_SIZE], _ids: uint256[BATCH_SIZE]) -> uint256[BATCH_SIZE]:\\n    \\\"\\\"\\\"\\n    @notice Get the balance of multiple account/token pairs\\n    @param _owners The addresses of the token holders\\n    @param _ids    ID of the tokens\\n    @return The _owner's balance of the token types requested (i.e. balance for each (owner, id) pair)\\n    \\\"\\\"\\\"\\n    returnBalances: uint256[BATCH_SIZE]\\n    for i in range(BATCH_SIZE):\\n        returnBalances[i] = self.balancesOf[_owner[i]][_ids[i]]\\n    return returnBalances\\n\\n\\n@public\\ndef setApprovalForAll(_operator: address, _approved: bool):\\n    \\\"\\\"\\\"\\n    @notice Enable or disable approval for a third party (\\\"operator\\\") to manage all of the caller's tokens.\\n    @dev MUST emit the ApprovalForAll event on success.\\n    @param _operator  Address to add to the set of authorized operators\\n    @param _approved  True if the operator is approved, false to revoke approval\\n    @return None\\n    \\\"\\\"\\\"\\n    (self.operators[msg.sender])[_operator] = _approved\\n    log.ApprovalForAll(msg.sender, _operator, _approved)\\n\\n\\n@public\\n@constant\\ndef isApprovedForAll(_owner: address, _operator: address) -> bool:\\n    \\\"\\\"\\\"\\n    @notice Queries the approval status of an operator for a given owner.\\n    @param _owner     The owner of the tokens.\\n    @param _operator  Address of authorized operator.\\n    @return True if the operator is approved, false if not\\n    \\\"\\\"\\\"\\n    return (self.operators[_owner])[_operator]\\n\\n\\n@public\\ndef createSingle(_item_owner: address, _id: uint256, _path: string[256]):\\n    \\\"\\\"\\\"\\n    @notice Create a new token type that we can mint later.\\n    @param _item_owner The owner of the item.\\n    @param _id         The id of the token.\\n    @param _path       The path to the token data.\\n    @return None\\n    \\\"\\\"\\\"\\n    assert _item_owner != ZERO_ADDRESS\\n    assert self.owner == msg.sender, \\\"Owner only can create item.\\\"\\n    self.balancesOf[_item_owner][_id] = 0\\n    self.tokensIdCount += 1\\n    self.token_ids[_id] = True\\n    self.uri[_id] = _path\\n    log.URI(_path, _id)\\n    log.TransferSingle(msg.sender, ZERO_ADDRESS, _item_owner, _id, 0)\\n\\n\\n@public\\ndef createBatch(_items_owner: address, _ids: uint256[BATCH_SIZE]):\\n    \\\"\\\"\\\"\\n    @notice Create new token types that we can mint later.\\n    @param _items_owner The owner of the items.\\n    @param _ids         The ids of the tokens.\\n    @return None\\n    \\\"\\\"\\\"\\n    assert _items_owner != ZERO_ADDRESS\\n    assert self.owner == msg.sender, \\\"Owner only can create items.\\\"\\n    for i in range(BATCH_SIZE):\\n        id: uint256 = _ids[i]\\n        self.balancesOf[_items_owner][id] = 0\\n        self.tokensIdCount += 1\\n        self.token_ids[id] = True\\n    zero_supply: uint256[BATCH_SIZE] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]\\n    log.TransferBatch(msg.sender, ZERO_ADDRESS, _items_owner, _ids, zero_supply)\\n\\n\\n@public\\ndef mint(_to: address, _id: uint256, _supply: uint256, _data: bytes[256]=\\\"\\\"):\\n    \\\"\\\"\\\"\\n    @notice Mint a token.\\n    @dev This is not part of the standard.\\n    @param _to      The address of the receiver.\\n    @param _id      The id of the token.\\n    @param _supply  The supply to be minted for the token.\\n    @param _data    The data.\\n    @return None\\n    \\\"\\\"\\\"\\n    assert _to != ZERO_ADDRESS\\n    assert self.owner == msg.sender, \\\"Owner only can mint items.\\\"\\n    decoded_id: int128 = self.decode_id(_id)\\n    assert decoded_id == 1 or decoded_id == 2\\n    if decoded_id == 1 :\\n        assert _supply == 1, \\\"Cannot mint NFT with _supply more than 1\\\"\\n    self.balancesOf[_to][_id] = _supply\\n\\n    log.TransferSingle(msg.sender, ZERO_ADDRESS, _to, _id, _supply)\\n\\n    if _to.is_contract:\\n        returnValue: bytes32 = ERC1155TokenReceiver(_to).onERC1155Received(msg.sender, ZERO_ADDRESS, _id, _supply, _data)\\n        assert returnValue == method_id(\\\"onERC1155Received(address,address,uint256,uint256,bytes)\\\", bytes32)\\n\\n\\n@public\\ndef mintBatch(_to: address, _ids: uint256[BATCH_SIZE], _supplies: uint256[BATCH_SIZE], _data: bytes[256]=\\\"\\\"):\\n    \\\"\\\"\\\"\\n    @notice Mint a batch of tokens.\\n    @dev This is not part of the standard.\\n    @param _to      The address of the receiver.\\n    @param _ids     The ids of the tokens.\\n    @param _supplies The supply to be minted for each token.\\n    @param _data    The data.\\n    @return None\\n    \\\"\\\"\\\"\\n    assert _to != ZERO_ADDRESS\\n    assert self.owner == msg.sender, \\\"Owner only can mint items.\\\"\\n\\n    for i in range(BATCH_SIZE):\\n        id: uint256 = _ids[i]\\n        decoded_id: int128 = self.decode_id(id)\\n        assert decoded_id == 1 or decoded_id == 2\\n\\n        if decoded_id == 1 :\\n            assert _supplies[i] == 1\\n\\n        self.balancesOf[_to][id] = _supplies[i]\\n\\n    log.TransferBatch(msg.sender, ZERO_ADDRESS, _to, _ids, _supplies)\\n\\n    for i in range(BATCH_SIZE):\\n        if _to.is_contract:\\n            returnValue: bytes32 = ERC1155TokenReceiver(_to).onERC1155Received(msg.sender, ZERO_ADDRESS, _ids[i], _supplies[i], _data)\\n            assert returnValue == method_id(\\\"onERC1155Received(address,address,uint256,uint256,bytes)\\\", bytes32)\\n\\n\\n@public\\ndef burn(_id: uint256, _supply: uint256):\\n    \\\"\\\"\\\"\\n    @notice Burns the supply of the specified token.\\n    @param _id        The id of the token\\n    @param _supply    Supply to be burned\\n    @return None\\n    \\\"\\\"\\\"\\n    assert self.balancesOf[msg.sender][_id] >= _supply, \\\"Not enough tokens to burn.\\\"\\n    self.balancesOf[msg.sender][_id] -= _supply\\n    log.TransferSingle(msg.sender, msg.sender, ZERO_ADDRESS, _id, _supply)\\n\\n\\n@public\\ndef burnBatch(_ids: uint256[BATCH_SIZE], _supplies: uint256[BATCH_SIZE]):\\n    \\\"\\\"\\\"\\n    @notice Burns the supply of the specified tokens.\\n    @dev At this point anyone can burn items if they own it.\\n    @param _ids        The ids of the token\\n    @param _supplies   Supplies to be burned\\n    @return None\\n    \\\"\\\"\\\"\\n    for i in range(BATCH_SIZE):\\n        id: uint256 = _ids[i]\\n        assert self.balancesOf[msg.sender][id] >= _supplies[i]\\n\\n    for i in range(BATCH_SIZE):\\n        id: uint256 = _ids[i]\\n        self.balancesOf[msg.sender][id] -= _supplies[i]\\n    log.TransferBatch(msg.sender, msg.sender, ZERO_ADDRESS, _ids, _supplies)\\n\\n\\n@public\\n@payable\\ndef tradeBatch(_from: address, _to: address, _ids: uint256[BATCH_SIZE], _from_supplies: uint256[BATCH_SIZE], _to_supplies: uint256[BATCH_SIZE], _value_eth: uint256, _nonce: uint256, _signature: bytes[65], _data: bytes[256]=\\\"\\\"):\\n    \\\"\\\"\\\"\\n    @notice Trade (atomically swap) tokens with tokens or eth.\\n    @dev Caller must be approved to manage the tokens being transferred out of the `_from` account (see \\\"Approval\\\" section of the standard).\\n        MUST revert if `_to` is the zero address.\\n        MUST revert if _from_supplies[i] > 0 and _to_supplies[i] > 0\\n        MUST revert if len(_ids) != len(_from_supplies) != len(_to_supplies)\\n        MUST revert if _value_eth != msg.value\\n        MUST revert if any of the balance(s) of the holder(s) for token(s) in `_ids` is lower than the respective amount(s) in `positive and negative values` sent to the recipient.\\n        MUST revert on any other error.\\n        MUST emit `TransferSingle` or `TransferBatch` event(s) such that all the balance changes are reflected (see \\\"Safe Transfer Rules\\\" section of the standard).\\n        Balance changes and events MUST follow the ordering of the arrays (_ids[0]/_values[0] before _ids[1]/_values[1], etc).\\n        After the above conditions for the transfer(s) in the batch are met, this function MUST check if `_to` is a smart contract (e.g. code size > 0). If so, it MUST call the relevant `ERC1155TokenReceiver` hook(s) on `_to` and act appropriately (see \\\"Safe Transfer Rules\\\" section of the standard).\\n    @param _from          The address of the sender.\\n    @param _to            The address of the receiver.\\n    @param _ids           The ids of the tokens.\\n    @param _from_supplies The supply of token values that will send the _from.\\n    @param _to_supplies   The supply of token values that will send the _from.\\n    @param _value_eth     The value of the ether.\\n    @param _nonce         The nonce.\\n    @param _signature    The signature of the _to address.\\n    @param _data    The data.\\n    @return None\\n    \\\"\\\"\\\"\\n    # Assert the value of the transaction is less than the balance of A.\\n\\n    assert _from == msg.sender or (self.operators[_from])[msg.sender], \\\"_from must be the sender or approved address\\\"\\n    assert _to != ZERO_ADDRESS, \\\"Destination address must be non-zero.\\\"\\n    assert self.noncesOf[_from][_nonce] == False, \\\"Nonce must be unused.\\\"\\n    assert _value_eth == msg.value, \\\"Sender has not provided enough ether.\\\"\\n\\n    for i in range(BATCH_SIZE):\\n       id: uint256 = _ids[i]\\n       if _from_supplies[i] > 0:\\n           assert _to_supplies[i] == 0\\n           assert self.balancesOf[_from][id] >= _from_supplies[i]\\n       else:\\n           assert _from_supplies[i] == 0\\n           assert self.balancesOf[_to][id] >= _to_supplies[i]\\n\\n    # Create hash from variables.\\n    hash: bytes32 = self._getHash(_from, _to, _ids, _from_supplies, _to_supplies, _value_eth, _nonce)\\n\\n    # Assert that the ecrecover(address,signature) returns true.\\n    recovered_to: address = self.ecrecoverSig(hash, _signature)\\n    assert recovered_to == _to, \\\"Signer does not match signature.\\\"\\n\\n    # Store the nonce\\n    self.noncesOf[msg.sender][_nonce] = True\\n\\n    # Update the balances\\n    for i in range(BATCH_SIZE):\\n        id: uint256 = _ids[i]\\n        if _from_supplies[i] > 0:\\n            self.balancesOf[_from][id] -= _from_supplies[i]\\n            self.balancesOf[_to][id] += _from_supplies[i]\\n        else:\\n            self.balancesOf[_from][id] += _to_supplies[i]\\n            self.balancesOf[_to][id] -= _to_supplies[i]\\n\\n    send(_to, msg.value)\\n\\n    log.TransferBatch(msg.sender, _from, _to, _ids, _from_supplies)\\n    log.TransferBatch(msg.sender, _to, _from, _ids, _to_supplies)\\n\\n\\n    if _to.is_contract:\\n        returnValue: bytes32 = ERC1155TokenReceiver(_to).onERC1155BatchReceived(msg.sender, _to, _ids, _from_supplies, _data)\\n        assert returnValue == method_id(\\\"onERC1155BatchReceived(address,address,uint256,uint256,bytes)\\\", bytes32)\\n    if _from.is_contract:\\n        returnValue: bytes32 = ERC1155TokenReceiver(_from).onERC1155BatchReceived(msg.sender, _from, _ids, _to_supplies, _data)\\n        assert returnValue == method_id(\\\"onERC1155BatchReceived(address,address,uint256,uint256,bytes)\\\", bytes32)\\n\\n\\n\\n@public\\n@payable\\ndef trade(_from: address, _to: address, _id: uint256, _from_supply: uint256, _to_supply: uint256, _value_eth: uint256, _nonce: uint256, _signature: bytes[65], _data: bytes[256]=\\\"\\\"):\\n    \\\"\\\"\\\"\\n    @notice Trade (atomically swap) tokens with tokens or eth.\\n    @dev Caller must be approved to manage the tokens being transferred out of the `_from` account (see \\\"Approval\\\" section of the standard).\\n        MUST revert if `_to` is the zero address.\\n        MUST revert if _from_supply > 0 and _to_supply > 0\\n        MUST revert if _value_eth != msg.value\\n        MUST revert if any of the balance(s) of the holder(s) for token(s) in `_id` is lower than the respective amount in `positive or negative value` sent to the recipient.\\n        MUST revert on any other error.\\n        MUST emit `TransferSingle` or `TransferBatch` event(s) such that all the balance changes are reflected (see \\\"Safe Transfer Rules\\\" section of the standard).\\n        Balance changes and events MUST follow the ordering of the arrays (_ids[0]/_values[0] before _ids[1]/_values[1], etc).\\n        After the above conditions for the transfer(s) in the batch are met, this function MUST check if `_to` is a smart contract (e.g. code size > 0). If so, it MUST call the relevant `ERC1155TokenReceiver` hook(s) on `_to` and act appropriately (see \\\"Safe Transfer Rules\\\" section of the standard).\\n    @param _from            The from address (seller of eth, potential receiver of tokens).\\n    @param _to              The receiver address (receiver of tokens).\\n    @param _id              The id of the token\\n    @param _from_supply     The change in value of token (for _from)\\n    @param _to_supply       The change in value of token (for _to)\\n    @param _value_eth       The value of the ETH sent to the _from address.\\n    @param _nonce           The nonce.\\n    @param _signature       The signature of the _to address.\\n    @param _data    The data.\\n    @return None\\n    \\\"\\\"\\\"\\n    # Assert the value of the transaction is less than the balance of A.\\n    assert _from == msg.sender or (self.operators[_from])[msg.sender]\\n    assert _to != ZERO_ADDRESS, \\\"Destination address must be non-zero.\\\"\\n    assert self.noncesOf[_from][_nonce] == False, \\\"Nonce must be unused.\\\"\\n    assert _value_eth == msg.value, \\\"Sender has not provided enough ether.\\\"\\n    if _from_supply > 0:\\n        assert _to_supply == 0\\n        assert self.balancesOf[_from][_id] >= _from_supply\\n    else:\\n        assert _from_supply == 0\\n        assert self.balancesOf[_to][_id] >= _to_supply\\n\\n    # Create hash from variables.\\n    hash: bytes32 = self._getSingleHash(_from, _to, _id, _from_supply, _to_supply, _value_eth, _nonce)\\n\\n    # Assert that the ecrecover(address,signature) returns true.\\n    recovered_to: address = self.ecrecoverSig(hash, _signature)\\n    assert recovered_to == _to, \\\"Signer does not match signature.\\\"\\n\\n    # Store the nonce\\n    self.noncesOf[msg.sender][_nonce] = True\\n\\n    # Update the balances\\n    if _from_supply > 0:\\n        self.balancesOf[_from][_id] -= _from_supply\\n        self.balancesOf[_to][_id] += _from_supply\\n    else:\\n        self.balancesOf[_from][_id] += _to_supply\\n        self.balancesOf[_to][_id] -= _to_supply\\n\\n    send(_to, msg.value)\\n\\n    log.TransferSingle(msg.sender, _from, _to, _id, _from_supply)\\n    log.TransferSingle(msg.sender, _to, _from, _id, _to_supply)\\n\\n    if _to.is_contract:\\n        returnValue: bytes32 = ERC1155TokenReceiver(_to).onERC1155Received(msg.sender, _to, _id, _from_supply, _data)\\n        assert returnValue == method_id(\\\"onERC1155BatchReceived(address,address,uint256,uint256,bytes)\\\", bytes32)\\n    if _from.is_contract:\\n        returnValue: bytes32 = ERC1155TokenReceiver(_from).onERC1155Received(msg.sender, _from, _id, _to_supply, _data)\\n        assert returnValue == method_id(\\\"onERC1155BatchReceived(address,address,uint256,uint256,bytes)\\\", bytes32)\\n\",\n  \"sourcePath\": \"/Users/aristotelistriantafyllidis/Documents/agents-research/erc1155/contracts/erc1155.vy\",\n  \"compiler\": {\n    \"name\": \"vyper\",\n    \"version\": \"0.1.0b12+commit.a01cdc8\"\n  },\n  \"networks\": {\n    \"1583918911727\": {\n      \"events\": {\n        \"0xc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62\": {\n          \"name\": \"TransferSingle\",\n          \"inputs\": [\n            {\n              \"type\": \"address\",\n              \"name\": \"_operator\",\n              \"indexed\": true\n            },\n            {\n              \"type\": \"address\",\n              \"name\": \"_from\",\n              \"indexed\": true\n            },\n            {\n              \"type\": \"address\",\n              \"name\": \"_to\",\n              \"indexed\": true\n            },\n            {\n              \"type\": \"uint256\",\n              \"name\": \"_id\",\n              \"indexed\": false\n            },\n            {\n              \"type\": \"uint256\",\n              \"name\": \"_value\",\n              \"indexed\": false\n            }\n          ],\n          \"anonymous\": false,\n          \"type\": \"event\",\n          \"signature\": \"0xc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62\"\n        },\n        \"0x514c24e4790d7c31a095a1688a73a01f28d936a9a85d806ba95970d8ee88efa8\": {\n          \"name\": \"TransferBatch\",\n          \"inputs\": [\n            {\n              \"type\": \"address\",\n              \"name\": \"_operator\",\n              \"indexed\": true\n            },\n            {\n              \"type\": \"address\",\n              \"name\": \"_from\",\n              \"indexed\": true\n            },\n            {\n              \"type\": \"address\",\n              \"name\": \"_to\",\n              \"indexed\": true\n            },\n            {\n              \"type\": \"uint256[10]\",\n              \"name\": \"_ids\",\n              \"indexed\": false\n            },\n            {\n              \"type\": \"uint256[10]\",\n              \"name\": \"_values\",\n              \"indexed\": false\n            }\n          ],\n          \"anonymous\": false,\n          \"type\": \"event\",\n          \"signature\": \"0x514c24e4790d7c31a095a1688a73a01f28d936a9a85d806ba95970d8ee88efa8\"\n        },\n        \"0x17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31\": {\n          \"name\": \"ApprovalForAll\",\n          \"inputs\": [\n            {\n              \"type\": \"address\",\n              \"name\": \"_owner\",\n              \"indexed\": true\n            },\n            {\n              \"type\": \"address\",\n              \"name\": \"_operator\",\n              \"indexed\": true\n            },\n            {\n              \"type\": \"bool\",\n              \"name\": \"_approved\",\n              \"indexed\": false\n            }\n          ],\n          \"anonymous\": false,\n          \"type\": \"event\",\n          \"signature\": \"0x17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31\"\n        },\n        \"0x6bb7ff708619ba0610cba295a58592e0451dee2622938c8755667688daf3529b\": {\n          \"name\": \"URI\",\n          \"inputs\": [\n            {\n              \"type\": \"string\",\n              \"name\": \"_value\",\n              \"indexed\": false\n            },\n            {\n              \"type\": \"uint256\",\n              \"name\": \"_id\",\n              \"indexed\": true\n            }\n          ],\n          \"anonymous\": false,\n          \"type\": \"event\",\n          \"signature\": \"0x6bb7ff708619ba0610cba295a58592e0451dee2622938c8755667688daf3529b\"\n        }\n      },\n      \"links\": {},\n      \"address\": \"0x9561C133DD8580860B6b7E504bC5Aa500f0f06a7\",\n      \"transactionHash\": \"0x816b272ebd644b189a3addfbd429b0ea0fa7b2403cca3aa038bcd59f09d9c116\"\n    }\n  },\n  \"schemaVersion\": \"3.0.19\",\n  \"updatedAt\": \"2020-03-11T13:47:51.885Z\",\n  \"networkType\": \"ethereum\"\n}"
  },
  {
    "path": "plugins/aea-ledger-ethereum/tests/data/dummy_contract/contract.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains a dummy contract for an AEA.\"\"\"\n\nfrom aea.contracts.base import Contract\nfrom aea.crypto.base import LedgerApi\n\n\nclass DummyContract(Contract):\n    \"\"\"The some contract class.\"\"\"\n\n    @classmethod\n    def some_method(cls, ledger_api: LedgerApi, contract_address: str) -> None:\n        \"\"\"Some method.\"\"\"\n        pass\n"
  },
  {
    "path": "plugins/aea-ledger-ethereum/tests/data/dummy_contract/contract.yaml",
    "content": "name: dummy\nauthor: fetchai\nversion: 0.1.0\ntype: contract\ndescription: A test contract\nlicense: Apache-2.0\naea_version: '>=0.9.0, <0.10.0'\nfingerprint:\n  __init__.py: QmWbNjFh6E5V4n2qBwyZyXZdmmHvcZSVnwKrcM34MAE56S\n  build/some.json: Qma5n7au2NDCg1nLwYfYnmFNwWChFuXtu65w5DV7wAZRvw\n  build/some.wasm: Qmc9gthbdwRSywinTHKjRVQdFzrKTxUuLDx2ryNfQp1xqf\n  contract.py: QmYfn2V3tXv7MCyhT5Kz5ArtX2FZWHC1jfeRmqCNsRxDL5\nfingerprint_ignore_patterns: []\nbuild_entrypoint: path/to/script.py\nclass_name: DummyContract\ncontract_interface_paths:\n  cosmos: build/some.wasm\n  ethereum: build/some.json\n  fetchai: build/some.wasm\ndependencies: {}\n"
  },
  {
    "path": "plugins/aea-ledger-ethereum/tests/data/ethereum_private_key.txt",
    "content": "0x6F611408F7EF304947621C51A4B7D84A13A2B9786E9F984DA790A096E8260C64"
  },
  {
    "path": "plugins/aea-ledger-ethereum/tests/docker_image.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains testing utilities.\"\"\"\nimport logging\nimport re\nimport shutil\nimport subprocess\nimport time\nfrom abc import ABC, abstractmethod\nfrom typing import Dict, List, Optional\n\nimport docker\nimport pytest\nimport requests\nfrom docker import DockerClient\nfrom docker.models.containers import Container\n\nfrom aea.exceptions import enforce\n\n\nlogger = logging.getLogger(__name__)\n\n\nclass DockerImage(ABC):\n    \"\"\"A class to wrap interatction with a Docker image.\"\"\"\n\n    MINIMUM_DOCKER_VERSION = (19, 0, 0)\n\n    def __init__(self, client: docker.DockerClient):\n        \"\"\"Initialize.\"\"\"\n        self._client = client\n\n    def check_skip(self):\n        \"\"\"\n        Check whether the test should be skipped.\n\n        By default, nothing happens.\n        \"\"\"\n        self._check_docker_binary_available()\n\n    def _check_docker_binary_available(self):\n        \"\"\"Check the 'Docker' CLI tool is in the OS PATH.\"\"\"\n        result = shutil.which(\"docker\")\n        if result is None:\n            pytest.skip(\"Docker not in the OS Path; skipping the test\")\n\n        result = subprocess.run(  # nosec\n            [\"docker\", \"--version\"], stdout=subprocess.PIPE, stderr=subprocess.PIPE\n        )\n        if result.returncode != 0:\n            pytest.skip(\"'docker --version' failed with exit code {result.returncode}\")\n\n        match = re.search(\n            r\"Docker version ([0-9]+)\\.([0-9]+)\\.([0-9]+)\",\n            result.stdout.decode(\"utf-8\"),\n        )\n        if match is None:\n            pytest.skip(\"cannot read version from the output of 'docker --version'\")\n        version = (int(match.group(1)), int(match.group(2)), int(match.group(3)))\n        if version < self.MINIMUM_DOCKER_VERSION:\n            pytest.skip(\n                f\"expected Docker version to be at least {'.'.join(self.MINIMUM_DOCKER_VERSION)}, found {'.'.join(version)}\"\n            )\n\n    @property\n    @abstractmethod\n    def tag(self) -> str:\n        \"\"\"Return the tag of the image.\"\"\"\n\n    def stop_if_already_running(self):\n        \"\"\"Stop the running images with the same tag, if any.\"\"\"\n        client = docker.from_env()\n        for container in client.containers.list():\n            if self.tag in container.image.tags:\n                logger.info(f\"Stopping image {self.tag}...\")\n                container.stop()\n\n    @abstractmethod\n    def create(self) -> Container:\n        \"\"\"Instantiate the image in a container.\"\"\"\n\n    @abstractmethod\n    def wait(self, max_attempts: int = 15, sleep_rate: float = 1.0) -> bool:\n        \"\"\"\n        Wait until the image is running.\n\n        :param max_attempts: max number of attempts.\n        :param sleep_rate: the amount of time to sleep between different requests.\n        :return: True if the wait was successful, False otherwise.\n        \"\"\"\n        return True\n\n\nclass GanacheDockerImage(DockerImage):\n    \"\"\"Wrapper to Ganache Docker image.\"\"\"\n\n    def __init__(\n        self,\n        client: DockerClient,\n        addr: str,\n        port: int,\n        config: Optional[Dict] = None,\n        gas_limit: int = 10000000000000,\n    ):\n        \"\"\"\n        Initialize the Ganache Docker image.\n\n        :param client: the Docker client.\n        :param addr: the address.\n        :param port: the port.\n        :param config: optional configuration to command line.\n        :param gas_limit: the gas limit for blocks.\n        \"\"\"\n        super().__init__(client)\n        self._addr = addr\n        self._port = port\n        self._config = config or {}\n        self._gas_limit = gas_limit\n\n    @property\n    def tag(self) -> str:\n        \"\"\"Get the image tag.\"\"\"\n        return \"trufflesuite/ganache-cli:latest\"\n\n    def _make_ports(self) -> Dict:\n        \"\"\"Make ports dictionary for Docker.\"\"\"\n        return {f\"{self._port}/tcp\": (\"0.0.0.0\", self._port)}  # nosec\n\n    def _build_command(self) -> List[str]:\n        \"\"\"Build command.\"\"\"\n        cmd = [\"ganache-cli\"]\n        cmd += [\"--gasLimit=\" + str(self._gas_limit)]\n        accounts_balances = self._config.get(\"accounts_balances\", [])\n        for account, balance in accounts_balances:\n            cmd += [f\"--account='{account},{balance}'\"]\n        return cmd\n\n    def create(self) -> Container:\n        \"\"\"Create the container.\"\"\"\n        cmd = self._build_command()\n        container = self._client.containers.run(\n            self.tag, command=cmd, detach=True, ports=self._make_ports()\n        )\n        return container\n\n    def wait(self, max_attempts: int = 15, sleep_rate: float = 1.0) -> bool:\n        \"\"\"Wait until the image is up.\"\"\"\n        request = dict(jsonrpc=2.0, method=\"web3_clientVersion\", params=[], id=1)\n        for i in range(max_attempts):\n            try:\n                response = requests.post(f\"{self._addr}:{self._port}\", json=request)\n                enforce(response.status_code == 200, \"\")\n                return True\n            except Exception:\n                logger.info(\n                    \"Attempt %s failed. Retrying in %s seconds...\", i, sleep_rate\n                )\n                time.sleep(sleep_rate)\n        return False\n"
  },
  {
    "path": "plugins/aea-ledger-ethereum/tests/test_ethereum.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the ethereum module.\"\"\"\n\nimport hashlib\nimport logging\nimport tempfile\nimport time\nfrom pathlib import Path\nfrom unittest.mock import MagicMock, patch\n\nimport pytest\nfrom aea_ledger_ethereum import (\n    AttributeDictTranslator,\n    EthereumApi,\n    EthereumCrypto,\n    EthereumFaucetApi,\n    EthereumHelper,\n    LruLockWrapper,\n    get_gas_price_strategy,\n    requests,\n)\nfrom web3 import Web3\nfrom web3._utils.request import _session_cache as session_cache\nfrom web3.gas_strategies.rpc import rpc_gas_price_strategy\n\nfrom aea.crypto.helpers import DecryptError, KeyIsIncorrect\n\nfrom tests.conftest import DEFAULT_GANACHE_CHAIN_ID, MAX_FLAKY_RERUNS, ROOT_DIR\n\n\ndef test_attribute_dict_translator():\n    \"\"\"Test the AttributeDictTranslator.\"\"\"\n    di = {\n        \"1\": None,\n        \"2\": True,\n        \"3\": b\"some\",\n        \"4\": 0.1,\n        \"5\": [1, None, True, {}],\n        \"6\": {\"hex\": \"0x01\"},\n    }\n    res = AttributeDictTranslator.from_dict(di)\n    assert AttributeDictTranslator.to_dict(res) == di\n\n\ndef test_creation(ethereum_private_key_file):\n    \"\"\"Test the creation of the crypto_objects.\"\"\"\n    assert EthereumCrypto(), \"Managed to initialise the eth_account\"\n    assert EthereumCrypto(\n        ethereum_private_key_file\n    ), \"Managed to load the eth private key\"\n\n\ndef test_initialization():\n    \"\"\"Test the initialisation of the variables.\"\"\"\n    account = EthereumCrypto()\n    assert account.entity is not None, \"The property must return the account.\"\n    assert (\n        account.address is not None and type(account.address) == str\n    ), \"After creation the display address must not be None\"\n    assert (\n        account.public_key is not None and type(account.public_key) == str\n    ), \"After creation the public key must no be None\"\n    assert account.entity is not None, \"After creation the entity must no be None\"\n\n\ndef test_derive_address():\n    \"\"\"Test the get_address_from_public_key method\"\"\"\n    account = EthereumCrypto()\n    address = EthereumApi.get_address_from_public_key(account.public_key)\n    assert account.address == address, \"Address derivation incorrect\"\n\n\ndef test_sign_and_recover_message(ethereum_private_key_file):\n    \"\"\"Test the signing and the recovery function for the eth_crypto.\"\"\"\n    account = EthereumCrypto(ethereum_private_key_file)\n    sign_bytes = account.sign_message(message=b\"hello\")\n    assert len(sign_bytes) > 0, \"The len(signature) must not be 0\"\n    recovered_addresses = EthereumApi.recover_message(\n        message=b\"hello\", signature=sign_bytes\n    )\n    assert len(recovered_addresses) == 1, \"Wrong number of addresses recovered.\"\n    assert (\n        recovered_addresses[0] == account.address\n    ), \"Failed to recover the correct address.\"\n\n\ndef test_sign_and_recover_message_deprecated(ethereum_private_key_file):\n    \"\"\"Test the signing and the recovery function for the eth_crypto.\"\"\"\n    account = EthereumCrypto(ethereum_private_key_file)\n    message = b\"hello\"\n    message_hash = hashlib.sha256(message).digest()\n    sign_bytes = account.sign_message(message=message_hash, is_deprecated_mode=True)\n    assert len(sign_bytes) > 0, \"The len(signature) must not be 0\"\n    recovered_addresses = EthereumApi.recover_message(\n        message=message_hash, signature=sign_bytes, is_deprecated_mode=True\n    )\n    assert len(recovered_addresses) == 1, \"Wrong number of addresses recovered.\"\n    assert (\n        recovered_addresses[0] == account.address\n    ), \"Failed to recover the correct address.\"\n\n\ndef test_sign_and_recover_message_public_key(ethereum_private_key_file):\n    \"\"\"Test the signing and the recovery function for the eth_crypto.\"\"\"\n    account = EthereumCrypto(ethereum_private_key_file)\n    sign_bytes = account.sign_message(message=b\"hello\")\n    assert len(sign_bytes) > 0, \"The len(signature) must not be 0\"\n    recovered_public_keys = EthereumApi.recover_public_keys_from_message(\n        message=b\"hello\", signature=sign_bytes\n    )\n    assert len(recovered_public_keys) == 1, \"Wrong number of public keys recovered.\"\n    assert (\n        EthereumApi.get_address_from_public_key(recovered_public_keys[0])\n        == account.address\n    ), \"Failed to recover the correct address.\"\n\n\ndef test_get_hash():\n    \"\"\"Test the get hash functionality.\"\"\"\n    expected_hash = \"0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8\"\n    hash_ = EthereumApi.get_hash(message=b\"hello\")\n    assert expected_hash == hash_\n\n\ndef test_dump_positive(ethereum_private_key_file):\n    \"\"\"Test dump.\"\"\"\n    account = EthereumCrypto(ethereum_private_key_file)\n    account.dump(MagicMock())\n\n\ndef test_api_creation(ethereum_testnet_config):\n    \"\"\"Test api instantiation.\"\"\"\n    assert EthereumApi(**ethereum_testnet_config), \"Failed to initialise the api\"\n\n\ndef test_api_none(ethereum_testnet_config):\n    \"\"\"Test the \"api\" of the cryptoApi is none.\"\"\"\n    eth_api = EthereumApi(**ethereum_testnet_config)\n    assert eth_api.api is not None, \"The api property is None.\"\n\n\ndef test_validate_address():\n    \"\"\"Test the is_valid_address functionality.\"\"\"\n    account = EthereumCrypto()\n    assert EthereumApi.is_valid_address(account.address)\n    assert not EthereumApi.is_valid_address(account.address + \"wrong\")\n\n\n@pytest.mark.flaky(reruns=MAX_FLAKY_RERUNS)\n@pytest.mark.integration\n@pytest.mark.ledger\ndef test_get_balance(ethereum_testnet_config, ganache, ethereum_private_key_file):\n    \"\"\"Test the balance is zero for a new account.\"\"\"\n    ethereum_api = EthereumApi(**ethereum_testnet_config)\n    ec = EthereumCrypto()\n    balance = ethereum_api.get_balance(ec.address)\n    assert balance == 0, \"New account has a positive balance.\"\n    ec = EthereumCrypto(private_key_path=ethereum_private_key_file)\n    balance = ethereum_api.get_balance(ec.address)\n    assert balance > 0, \"Existing account has no balance.\"\n\n\n@pytest.mark.flaky(reruns=MAX_FLAKY_RERUNS)\n@pytest.mark.integration\n@pytest.mark.ledger\ndef test_get_state(ethereum_testnet_config, ganache):\n    \"\"\"Test that get_state() with 'getBlock' function returns something containing the block number.\"\"\"\n    ethereum_api = EthereumApi(**ethereum_testnet_config)\n    callable_name = \"getBlock\"\n    args = (\"latest\",)\n    block = ethereum_api.get_state(callable_name, *args)\n    assert block is not None, \"response to getBlock is empty.\"\n    assert \"number\" in block, \"response to getBlock() does not contain 'number'\"\n\n\n@pytest.mark.flaky(reruns=MAX_FLAKY_RERUNS)\n@pytest.mark.integration\n@pytest.mark.ledger\ndef test_construct_sign_and_submit_transfer_transaction(\n    ethereum_testnet_config, ganache, ethereum_private_key_file\n):\n    \"\"\"Test the construction, signing and submitting of a transfer transaction.\"\"\"\n    account = EthereumCrypto(private_key_path=ethereum_private_key_file)\n    ec2 = EthereumCrypto()\n    ethereum_api = EthereumApi(**ethereum_testnet_config)\n\n    amount = 40000\n    tx_nonce = ethereum_api.generate_tx_nonce(ec2.address, account.address)\n    transfer_transaction = ethereum_api.get_transfer_transaction(\n        sender_address=account.address,\n        destination_address=ec2.address,\n        amount=amount,\n        tx_fee=30000,\n        tx_nonce=tx_nonce,\n        chain_id=DEFAULT_GANACHE_CHAIN_ID,\n    )\n    assert (\n        isinstance(transfer_transaction, dict) and len(transfer_transaction) == 7\n    ), \"Incorrect transfer_transaction constructed.\"\n\n    signed_transaction = account.sign_transaction(transfer_transaction)\n    assert (\n        isinstance(signed_transaction, dict) and len(signed_transaction) == 5\n    ), \"Incorrect signed_transaction constructed.\"\n\n    transaction_digest = ethereum_api.send_signed_transaction(signed_transaction)\n    assert transaction_digest is not None, \"Failed to submit transfer transaction!\"\n\n    not_settled = True\n    elapsed_time = 0\n    while not_settled and elapsed_time < 20:\n        elapsed_time += 1\n        time.sleep(2)\n        transaction_receipt = ethereum_api.get_transaction_receipt(transaction_digest)\n        if transaction_receipt is None:\n            continue\n        is_settled = ethereum_api.is_transaction_settled(transaction_receipt)\n        not_settled = not is_settled\n    assert transaction_receipt is not None, \"Failed to retrieve transaction receipt.\"\n    assert is_settled, \"Failed to verify tx!\"\n\n    tx = ethereum_api.get_transaction(transaction_digest)\n    is_valid = ethereum_api.is_transaction_valid(\n        tx, ec2.address, account.address, tx_nonce, amount\n    )\n    assert is_valid, \"Failed to settle tx correctly!\"\n    assert tx != transaction_receipt, \"Should not be same!\"\n\n\n@pytest.mark.flaky(reruns=MAX_FLAKY_RERUNS)\n@pytest.mark.integration\n@pytest.mark.ledger\ndef test_get_wealth_positive(caplog):\n    \"\"\"Test the balance is zero for a new account.\"\"\"\n    with caplog.at_level(logging.DEBUG, logger=\"aea.crypto.ethereum._default_logger\"):\n        ethereum_faucet_api = EthereumFaucetApi()\n        ec = EthereumCrypto()\n        ethereum_faucet_api.get_wealth(ec.address, \"some_url\")\n        assert (\n            \"Invalid URL\" in caplog.text\n        ), f\"Cannot find message in output: {caplog.text}\"\n\n\n@pytest.mark.flaky(reruns=MAX_FLAKY_RERUNS)\n@pytest.mark.integration\n@pytest.mark.ledger\ndef test_get_deploy_transaction(ethereum_testnet_config, ganache):\n    \"\"\"Test the get deploy transaction method.\"\"\"\n    ethereum_api = EthereumApi(**ethereum_testnet_config)\n    ec2 = EthereumCrypto()\n    interface = {\"abi\": [], \"bytecode\": b\"\"}\n    deploy_tx = ethereum_api.get_deploy_transaction(\n        contract_interface=interface,\n        deployer_address=ec2.address,\n    )\n    assert type(deploy_tx) == dict and len(deploy_tx) == 6\n    assert all(\n        key in [\"from\", \"value\", \"gas\", \"gasPrice\", \"nonce\", \"data\"]\n        for key in deploy_tx.keys()\n    )\n\n\ndef test_load_contract_interface():\n    \"\"\"Test the load_contract_interface method.\"\"\"\n    path = Path(ROOT_DIR, \"tests\", \"data\", \"dummy_contract\", \"build\", \"some.json\")\n    result = EthereumApi.load_contract_interface(path)\n    assert \"abi\" in result\n    assert \"bytecode\" in result\n\n\n@patch.object(EthereumApi, \"_try_get_transaction_count\", return_value=None)\ndef test_ethereum_api_get_transfer_transaction(*args):\n    \"\"\"Test EthereumApi.get_transfer_transaction.\"\"\"\n    ethereum_api = EthereumApi()\n    assert ethereum_api.get_transfer_transaction(*[MagicMock()] * 7) is None\n\n\ndef test_ethereum_api_get_deploy_transaction(*args):\n    \"\"\"Test EthereumApi.get_deploy_transaction.\"\"\"\n    ethereum_api = EthereumApi()\n    with patch.object(ethereum_api.api.eth, \"getTransactionCount\", return_value=None):\n        assert (\n            ethereum_api.get_deploy_transaction(\n                {\"acc\": \"acc\"}, \"0x89205A3A3b2A69De6Dbf7f01ED13B2108B2c43e7\"\n            )\n            is None\n        )\n\n\ndef test_session_cache():\n    \"\"\"Test session cache.\"\"\"\n    assert isinstance(session_cache, LruLockWrapper)\n\n    session_cache[1] = 1\n    assert session_cache[1] == 1\n    del session_cache[1]\n    assert 1 not in session_cache\n\n\ndef test_gas_price_strategy_eth_gasstation():\n    \"\"\"Test the gas price strategy when using eth gasstation.\"\"\"\n    gas_price_strategy = \"fast\"\n    excepted_result = 10\n    callable_ = get_gas_price_strategy(gas_price_strategy, \"api_key\")\n    with patch.object(\n        requests,\n        \"get\",\n        return_value=MagicMock(\n            status_code=200,\n            json=MagicMock(return_value={gas_price_strategy: excepted_result}),\n        ),\n    ):\n        result = callable_(Web3, \"tx_params\")\n    assert result == excepted_result / 10 * 1000000000\n\n\ndef test_gas_price_strategy_not_supported(caplog):\n    \"\"\"Test the gas price strategy when not supported.\"\"\"\n    gas_price_strategy = \"superfast\"\n    with caplog.at_level(logging.DEBUG, logger=\"aea.crypto.ethereum._default_logger\"):\n        callable_ = get_gas_price_strategy(gas_price_strategy, \"api_key\")\n    assert callable_ == rpc_gas_price_strategy\n    assert (\n        f\"Gas price strategy `{gas_price_strategy}` not in list of supported modes:\"\n        in caplog.text\n    )\n\n\ndef test_gas_price_strategy_no_api_key(caplog):\n    \"\"\"Test the gas price strategy when no api key is provided.\"\"\"\n    gas_price_strategy = \"fast\"\n    with caplog.at_level(logging.DEBUG, logger=\"aea.crypto.ethereum._default_logger\"):\n        callable_ = get_gas_price_strategy(gas_price_strategy, None)\n    assert callable_ == rpc_gas_price_strategy\n    assert (\n        \"No ethgasstation api key provided. Falling back to `rpc_gas_price_strategy`.\"\n        in caplog.text\n    )\n\n\ndef test_dump_load_with_password():\n    \"\"\"Test dumping and loading a key with password.\"\"\"\n    with tempfile.TemporaryDirectory() as dirname:\n        encrypted_file_name = Path(dirname, \"eth_key_encrypted\")\n        password = \"somePwd\"  # nosec\n        ec = EthereumCrypto()\n        ec.dump(encrypted_file_name, password)\n        assert encrypted_file_name.exists()\n        with pytest.raises(DecryptError, match=\"Decrypt error! Bad password?\"):\n            ec2 = EthereumCrypto.load_private_key_from_path(\n                encrypted_file_name, \"wrongPassw\"\n            )\n        ec2 = EthereumCrypto(encrypted_file_name, password)\n        assert ec2.private_key == ec.private_key\n\n\ndef test_load_errors():\n    \"\"\"Test load errors: bad password, no password specified.\"\"\"\n    ec = EthereumCrypto()\n    with patch.object(EthereumCrypto, \"load\", return_value=\"bad sTring\"):\n        with pytest.raises(KeyIsIncorrect, match=\"Try to specify `password`\"):\n            ec.load_private_key_from_path(\"any path\")\n\n        with pytest.raises(KeyIsIncorrect, match=\"Wrong password?\"):\n            ec.load_private_key_from_path(\"any path\", password=\"some\")\n\n\ndef test_decrypt_error():\n    \"\"\"Test bad password error on decrypt.\"\"\"\n    ec = EthereumCrypto()\n    ec._pritvate_key = EthereumCrypto.generate_private_key()\n    password = \"test\"\n    encrypted_data = ec.encrypt(password=password)\n    with pytest.raises(DecryptError, match=\"Bad password\"):\n        ec.decrypt(encrypted_data, password + \"some\")\n\n    with patch(\n        \"aea_ledger_ethereum.ethereum.Account.decrypt\",\n        side_effect=ValueError(\"expected\"),\n    ):\n        with pytest.raises(ValueError, match=\"expected\"):\n            ec.decrypt(encrypted_data, password + \"some\")\n\n\ndef test_helper_get_contract_address():\n    \"\"\"Test EthereumHelper.get_contract_address.\"\"\"\n    assert EthereumHelper.get_contract_address({\"contractAddress\": \"123\"}) == \"123\"\n"
  },
  {
    "path": "plugins/aea-ledger-ethereum/tests/test_ethereum_contract.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the ethereum module.\"\"\"\n\nfrom pathlib import Path\nfrom typing import Dict, cast\n\nimport pytest\nfrom aea_ledger_ethereum import EthereumApi, EthereumCrypto\n\nfrom tests.conftest import ETHEREUM_PRIVATE_KEY_PATH, MAX_FLAKY_RERUNS, ROOT_DIR\n\n\n@pytest.mark.flaky(reruns=MAX_FLAKY_RERUNS)\n@pytest.mark.integration\n@pytest.mark.ledger\ndef test_get_contract_instance(ethereum_testnet_config, ganache):\n    \"\"\"Test the get contract instance method.\"\"\"\n    ec = EthereumCrypto(private_key_path=ETHEREUM_PRIVATE_KEY_PATH)\n    ethereum_api = EthereumApi(**ethereum_testnet_config)\n    full_path = Path(ROOT_DIR, \"tests\", \"data\", \"dummy_contract\", \"build\", \"some.json\")\n    contract_interface = ethereum_api.load_contract_interface(full_path)\n    tx = ethereum_api.get_deploy_transaction(\n        contract_interface, ec.address, gas=5000000\n    )\n    gas = ethereum_api.api.eth.estimateGas(transaction=tx)\n    tx[\"gas\"] = gas\n    tx_signed = ec.sign_transaction(tx)\n    tx_receipt = ethereum_api.send_signed_transaction(tx_signed)\n    receipt = ethereum_api.get_transaction_receipt(tx_receipt)\n    erc1155_contract_address = cast(Dict, receipt)[\"contractAddress\"]\n    interface = {\"abi\": [], \"bytecode\": b\"\"}\n    instance = ethereum_api.get_contract_instance(\n        contract_interface=interface,\n        contract_address=erc1155_contract_address,\n    )\n    assert str(type(instance)) == \"<class 'web3._utils.datatypes.Contract'>\"\n    instance = ethereum_api.get_contract_instance(\n        contract_interface=interface,\n    )\n    assert (\n        str(type(instance)) == \"<class 'web3._utils.datatypes.PropertyCheckingFactory'>\"\n    )\n"
  },
  {
    "path": "plugins/aea-ledger-fetchai/LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright 2019 Fetch.AI Limited\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "plugins/aea-ledger-fetchai/MANIFEST.in",
    "content": "include README.md LICENSE HISTORY.md\n\nrecursive-include aea_ledger_fetchai\nrecursive-include tests *\n"
  },
  {
    "path": "plugins/aea-ledger-fetchai/README.md",
    "content": "# Fetch.AI crypto plug-in\n\nFetch.AI crypto plug-in for the AEA framework.\n\n## Install\n\n``` bash\npython setup.py install\n```\n\n## Run tests\n\n``` bash\npython setup.py test\n```\n"
  },
  {
    "path": "plugins/aea-ledger-fetchai/aea_ledger_fetchai/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nPython package wrapping the public and private key cryptography and ledger api.\n\nThe module '_cosmos.py' must be the same of \"aea_ledger_cosmos.cosmos\".\n\"\"\"\n\nfrom .fetchai import *  # noqa isort:skip\nfrom .fetchai import _FETCH, _FETCHAI  # noqa isort:skip\n"
  },
  {
    "path": "plugins/aea-ledger-fetchai/aea_ledger_fetchai/_cosmos.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Cosmos module wrapping the public and private key cryptography and ledger api.\"\"\"\nimport base64\nimport gzip\nimport hashlib\nimport json\nimport logging\nimport time\nfrom collections import namedtuple\nfrom itertools import chain\nfrom json.decoder import JSONDecodeError\nfrom pathlib import Path\nfrom typing import Any, Dict, List, Optional, Tuple, cast\n\nfrom Crypto.Cipher import AES  # nosec\nfrom Crypto.Protocol.KDF import scrypt  # nosec\nfrom Crypto.Random import get_random_bytes  # nosec\nfrom bech32 import (  # pylint: disable=wrong-import-order\n    bech32_decode,\n    bech32_encode,\n    convertbits,\n)\nfrom cosmpy.auth.rest_client import AuthRestClient\nfrom cosmpy.bank.rest_client import BankRestClient, QueryBalanceRequest\nfrom cosmpy.common.rest_client import RestClient\nfrom cosmpy.cosmwasm.rest_client import CosmWasmRestClient\nfrom cosmpy.crypto.hashfuncs import ripemd160\nfrom cosmpy.protos.cosmos.auth.v1beta1.auth_pb2 import BaseAccount\nfrom cosmpy.protos.cosmos.auth.v1beta1.query_pb2 import QueryAccountRequest\nfrom cosmpy.protos.cosmos.bank.v1beta1.tx_pb2 import MsgSend\nfrom cosmpy.protos.cosmos.base.v1beta1.coin_pb2 import Coin\nfrom cosmpy.protos.cosmos.crypto.secp256k1.keys_pb2 import PubKey as ProtoPubKey\nfrom cosmpy.protos.cosmos.tx.signing.v1beta1.signing_pb2 import SignMode\nfrom cosmpy.protos.cosmos.tx.v1beta1.service_pb2 import (\n    BroadcastMode,\n    BroadcastTxRequest,\n    GetTxRequest,\n)\nfrom cosmpy.protos.cosmos.tx.v1beta1.tx_pb2 import (\n    AuthInfo,\n    Fee,\n    ModeInfo,\n    SignDoc,\n    SignerInfo,\n    Tx,\n    TxBody,\n)\nfrom cosmpy.protos.cosmwasm.wasm.v1.query_pb2 import QuerySmartContractStateRequest\nfrom cosmpy.protos.cosmwasm.wasm.v1.tx_pb2 import (\n    MsgExecuteContract,\n    MsgInstantiateContract,\n    MsgStoreCode,\n)\nfrom cosmpy.tx.rest_client import TxRestClient\nfrom ecdsa import (  # type: ignore # pylint: disable=wrong-import-order\n    SECP256k1,\n    SigningKey,\n    VerifyingKey,\n)\nfrom ecdsa.util import (  # type: ignore # pylint: disable=wrong-import-order\n    sigencode_string_canonize,\n)\nfrom google.protobuf.any_pb2 import Any as ProtoAny\nfrom google.protobuf.json_format import MessageToDict, ParseDict\n\nfrom aea.common import Address, JSONLike\nfrom aea.crypto.base import Crypto, FaucetApi, Helper, LedgerApi\nfrom aea.crypto.helpers import KeyIsIncorrect, hex_to_bytes_for_key\nfrom aea.exceptions import AEAEnforceError\nfrom aea.helpers import http_requests as requests\nfrom aea.helpers.base import try_decorator\n\n\n_default_logger = logging.getLogger(__name__)\n\n_COSMOS = \"cosmos\"\nTESTNET_NAME = \"testnet\"\nDEFAULT_FAUCET_URL = \"INVALID_URL\"\nDEFAULT_ADDRESS = \"https://cosmos.bigdipper.live\"\nDEFAULT_CURRENCY_DENOM = \"uatom\"\nDEFAULT_CHAIN_ID = \"cosmoshub-3\"\nDEFAULT_GAS_AMOUNT = 1550000\n# Txs will fail if gas_limit is higher than MAXIMUM_GAS_AMOUNT\nMAXIMUM_GAS_AMOUNT = 2000000\n_BYTECODE = \"wasm_byte_code\"\n\n\nclass DataEncrypt:\n    \"\"\"Class to encrypt/decrypt data strings with password provided.\"\"\"\n\n    @classmethod\n    def _aes_encrypt(\n        cls, password: str, data: bytes\n    ) -> Tuple[bytes, bytes, bytes, bytes]:\n        \"\"\"\n        Encryption schema for private keys\n\n        :param password: plaintext password to use for encryption\n        :param data: plaintext data to encrypt\n\n        :return: encrypted data, nonce, tag, salt\n        \"\"\"\n        key, salt = cls._password_to_key_and_salt(password)\n        cipher = AES.new(key, AES.MODE_EAX)\n        ciphertext, tag = cipher.encrypt_and_digest(data)  # type:ignore\n\n        return ciphertext, cipher.nonce, tag, salt  # type:ignore\n\n    @staticmethod\n    def _password_to_key_and_salt(\n        password: str, salt: Optional[bytes] = None\n    ) -> Tuple[bytes, bytes]:\n        salt = salt or get_random_bytes(16)\n        key = scrypt(password, salt, 16, N=2**14, r=8, p=1)  # type: ignore\n        return key, salt  # type: ignore\n\n    @classmethod\n    def _aes_decrypt(\n        cls, password: str, encrypted_data: bytes, nonce: bytes, tag: bytes, salt: bytes\n    ) -> bytes:\n        \"\"\"\n        Decryption schema for private keys.\n\n        :param password: plaintext password used for encryption\n        :param encrypted_data: data to decrypt\n        :param nonce:  bytes\n        :param tag:  bytes\n        :param salt: bytes\n        :return: decrypted data as plaintext\n        \"\"\"\n        # Hash password\n        key, _ = cls._password_to_key_and_salt(password, salt)\n        cipher = AES.new(key, AES.MODE_EAX, nonce)\n        try:\n            decrypted_data = cipher.decrypt_and_verify(  # type:ignore\n                encrypted_data, tag\n            )\n        except ValueError as e:\n            if e.args[0] == \"MAC check failed\":\n                raise ValueError(\"Decrypt error! Bad password?\") from e\n            raise  # pragma: nocover\n        return decrypted_data\n\n    @classmethod\n    def encrypt(cls, data: bytes, password: str) -> bytes:\n        \"\"\"Encrypt data with password.\"\"\"\n        if not isinstance(data, bytes):  # pragma: nocover\n            raise ValueError(f\"data has to be bytes! not {type(data)}\")\n\n        encrypted_data, nonce, tag, salt = cls._aes_encrypt(password, data)\n\n        json_data = {\n            \"encrypted_data\": cls.bytes_encode(encrypted_data),\n            \"nonce\": cls.bytes_encode(nonce),\n            \"tag\": cls.bytes_encode(tag),\n            \"salt\": cls.bytes_encode(salt),\n        }\n        return json.dumps(json_data).encode()\n\n    @staticmethod\n    def bytes_encode(data: bytes) -> str:\n        \"\"\"Encode bytes to ascii friendly string.\"\"\"\n        return base64.b64encode(data).decode()\n\n    @staticmethod\n    def bytes_decode(data: str) -> bytes:\n        \"\"\"Decode ascii friendly string to bytes.\"\"\"\n        return base64.b64decode(data)\n\n    @classmethod\n    def decrypt(cls, encrypted_data: bytes, password: str) -> bytes:\n        \"\"\"Decrypt data with password provided.\"\"\"\n        if not isinstance(encrypted_data, bytes):  # pragma: nocover\n            raise ValueError(\n                f\"encrypted_data has to be str! not {type(encrypted_data)}\"\n            )\n\n        try:\n            json_data = json.loads(encrypted_data)\n            decrypted_data = cls._aes_decrypt(\n                password,\n                encrypted_data=cls.bytes_decode(json_data[\"encrypted_data\"]),\n                nonce=cls.bytes_decode(json_data[\"nonce\"]),\n                tag=cls.bytes_decode(json_data[\"tag\"]),\n                salt=cls.bytes_decode(json_data[\"salt\"]),\n            )\n            return decrypted_data\n        except (KeyError, JSONDecodeError) as e:\n            raise ValueError(f\"Bad encrypted key format!: {str(e)}\") from e\n\n\nclass CosmosHelper(Helper):\n    \"\"\"Helper class usable as Mixin for CosmosApi or as standalone class.\"\"\"\n\n    address_prefix = _COSMOS\n\n    @staticmethod\n    def is_transaction_settled(tx_receipt: JSONLike) -> bool:\n        \"\"\"\n        Check whether a transaction is settled or not.\n\n        :param tx_receipt: the receipt of the transaction.\n        :return: True if the transaction has been settled, False o/w.\n        \"\"\"\n        is_successful = False\n        if tx_receipt is not None:\n            code = tx_receipt.get(\"code\", None)\n            is_successful = code is None\n            if not is_successful:\n                _default_logger.warning(  # pragma: nocover\n                    f\"Transaction {tx_receipt.get('txhash')} not settled. Raw log: {tx_receipt.get('rawLog')}\"\n                )\n        return is_successful\n\n    @classmethod\n    def get_code_id(cls, tx_receipt: JSONLike) -> Optional[int]:\n        \"\"\"\n        Retrieve the `code_id` from a transaction receipt.\n\n        :param tx_receipt: the receipt of the transaction.\n        :return: the code id, if present\n        \"\"\"\n        code_id: Optional[int] = None\n        try:\n            attributes = cls.get_event_attributes(tx_receipt)\n\n            code_id = int(attributes[\"code_id\"])\n        except (KeyError, IndexError):  # pragma: nocover\n            code_id = None\n        return code_id\n\n    @staticmethod\n    def get_event_attributes(tx_receipt: JSONLike) -> Dict:\n        \"\"\"\n        Retrieve events attributes from tx receipt.\n\n        :param tx_receipt: the receipt of the transaction.\n        :return: dict\n        \"\"\"\n        return {\n            i[\"key\"]: i[\"value\"]\n            for i in chain(*[i[\"attributes\"] for i in tx_receipt[\"logs\"][0][\"events\"]])  # type: ignore\n        }\n\n    @classmethod\n    def get_contract_address(cls, tx_receipt: JSONLike) -> Optional[str]:\n        \"\"\"\n        Retrieve the `contract_address` from a transaction receipt.\n\n        :param tx_receipt: the receipt of the transaction.\n        :return: the contract address, if present\n        \"\"\"\n        contract_address: Optional[str] = None\n        try:\n            attributes = cls.get_event_attributes(tx_receipt)\n            contract_address = attributes[\"_contract_address\"]\n        except (KeyError, IndexError):  # pragma: nocover\n            contract_address = None\n        return contract_address\n\n    @staticmethod\n    def is_transaction_valid(\n        tx: JSONLike,\n        seller: Address,\n        client: Address,\n        tx_nonce: str,\n        amount: int,\n    ) -> bool:\n        \"\"\"\n        Check whether a transaction is valid or not.\n\n        :param tx: the transaction.\n        :param seller: the address of the seller.\n        :param client: the address of the client.\n        :param tx_nonce: the transaction nonce.\n        :param amount: the amount we expect to get from the transaction.\n        :return: True if the random_message is equals to tx['input']\n        \"\"\"\n        if tx is None:\n            return False  # pragma: no cover\n\n        try:\n            _tx = cast(dict, tx.get(\"tx\", {})).get(\"body\", {}).get(\"messages\", [])[0]\n            recovered_amount = int(_tx.get(\"amount\")[0].get(\"amount\"))\n            sender = _tx.get(\"fromAddress\")\n            recipient = _tx.get(\"toAddress\")\n            is_valid = (\n                recovered_amount == amount and sender == client and recipient == seller\n            )\n        except (KeyError, IndexError):  # pragma: no cover\n            is_valid = False\n        return is_valid\n\n    @staticmethod\n    def generate_tx_nonce(seller: Address, client: Address) -> str:\n        \"\"\"\n        Generate a unique hash to distinguish transactions with the same terms.\n\n        :param seller: the address of the seller.\n        :param client: the address of the client.\n        :return: return the hash in hex.\n        \"\"\"\n        time_stamp = int(time.time())\n        aggregate_hash = hashlib.sha256(\n            b\"\".join([seller.encode(), client.encode(), time_stamp.to_bytes(32, \"big\")])\n        )\n        return aggregate_hash.hexdigest()\n\n    @classmethod\n    def get_address_from_public_key(cls, public_key: str) -> str:\n        \"\"\"\n        Get the address from the public key.\n\n        :param public_key: the public key\n        :return: str\n        \"\"\"\n        public_key_bytes = bytes.fromhex(public_key)\n        s = hashlib.new(\"sha256\", public_key_bytes).digest()\n        r = ripemd160(s)\n        five_bit_r = convertbits(r, 8, 5)\n        if five_bit_r is None:  # pragma: nocover\n            raise AEAEnforceError(\"Unsuccessful bech32.convertbits call\")\n        address = bech32_encode(cls.address_prefix, five_bit_r)\n        return address\n\n    @classmethod\n    def recover_message(\n        cls, message: bytes, signature: str, is_deprecated_mode: bool = False\n    ) -> Tuple[Address, ...]:\n        \"\"\"\n        Recover the addresses from the hash.\n\n        :param message: the message we expect\n        :param signature: the transaction signature\n        :param is_deprecated_mode: if the deprecated signing was used\n        :return: the recovered addresses\n        \"\"\"\n        public_keys = cls.recover_public_keys_from_message(message, signature)\n        addresses = [\n            cls.get_address_from_public_key(public_key) for public_key in public_keys\n        ]\n        return tuple(addresses)\n\n    @classmethod\n    def recover_public_keys_from_message(\n        cls, message: bytes, signature: str, is_deprecated_mode: bool = False\n    ) -> Tuple[str, ...]:\n        \"\"\"\n        Get the public key used to produce the `signature` of the `message`\n\n        :param message: raw bytes used to produce signature\n        :param signature: signature of the message\n        :param is_deprecated_mode: if the deprecated signing was used\n        :return: the recovered public keys\n        \"\"\"\n        signature_b64 = base64.b64decode(signature)\n        verifying_keys = VerifyingKey.from_public_key_recovery(\n            signature_b64,\n            message,\n            SECP256k1,\n            hashfunc=hashlib.sha256,\n        )\n        public_keys = [\n            verifying_key.to_string(\"compressed\").hex()\n            for verifying_key in verifying_keys\n        ]\n        return tuple(public_keys)\n\n    @staticmethod\n    def get_hash(message: bytes) -> str:\n        \"\"\"\n        Get the hash of a message.\n\n        :param message: the message to be hashed.\n        :return: the hash of the message.\n        \"\"\"\n        digest = hashlib.sha256(message).hexdigest()\n        return digest\n\n    @classmethod\n    def is_valid_address(cls, address: Address) -> bool:\n        \"\"\"\n        Check if the address is valid.\n\n        :param address: the address to validate\n        :return: whether address is valid or not\n        \"\"\"\n        result = bech32_decode(address)\n        return result != (None, None) and result[0] == cls.address_prefix\n\n    @classmethod\n    def load_contract_interface(cls, file_path: Path) -> Dict[str, str]:\n        \"\"\"\n        Load contract interface.\n\n        :param file_path: the file path to the interface\n        :return: the interface\n        \"\"\"\n        with open(file_path, \"rb\") as interface_file_cosmos:\n            contract_interface = {\n                _BYTECODE: str(\n                    base64.b64encode(\n                        gzip.compress(interface_file_cosmos.read(), 6)\n                    ).decode()\n                )\n            }\n        return contract_interface\n\n\nclass CosmosCrypto(Crypto[SigningKey]):\n    \"\"\"Class wrapping the Account Generation from Ethereum ledger.\"\"\"\n\n    identifier = _COSMOS\n    helper = CosmosHelper\n\n    def __init__(\n        self, private_key_path: Optional[str] = None, password: Optional[str] = None\n    ) -> None:\n        \"\"\"\n        Instantiate an ethereum crypto object.\n\n        :param private_key_path: the private key path of the agent\n        :param password: the password to encrypt/decrypt the private key.\n        \"\"\"\n        super().__init__(private_key_path=private_key_path, password=password)\n        self._public_key = self.entity.get_verifying_key().to_string(\"compressed\").hex()\n        self._address = self.helper.get_address_from_public_key(self.public_key)\n\n    @property\n    def private_key(self) -> str:\n        \"\"\"\n        Return a private key.\n\n        :return: a private key string\n        \"\"\"\n        return self.entity.to_string().hex()\n\n    @property\n    def public_key(self) -> str:\n        \"\"\"\n        Return a public key in hex format.\n\n        :return: a public key string in hex format\n        \"\"\"\n        return self._public_key\n\n    @property\n    def address(self) -> str:\n        \"\"\"\n        Return the address for the key pair.\n\n        :return: a display_address str\n        \"\"\"\n        return self._address\n\n    @classmethod\n    def load_private_key_from_path(\n        cls, file_name: str, password: Optional[str] = None\n    ) -> SigningKey:\n        \"\"\"\n        Load a private key in hex format from a file.\n\n        :param file_name: the path to the hex file.\n        :param password: the password to encrypt/decrypt the private key.\n        :return: the Entity.\n        \"\"\"\n        private_key = cls.load(file_name, password)\n        try:\n            signing_key = SigningKey.from_string(\n                hex_to_bytes_for_key(private_key), curve=SECP256k1\n            )\n        except KeyIsIncorrect as e:\n            if not password:\n                raise KeyIsIncorrect(\n                    f\"Error on key `{file_name}` load! Try to specify `password`: Error: {repr(e)} \"\n                ) from e\n            raise KeyIsIncorrect(\n                f\"Error on key `{file_name}` load! Wrong password?: Error: {repr(e)} \"\n            ) from e\n        return signing_key\n\n    def sign_message(\n        self,\n        message: bytes,\n        is_deprecated_mode: bool = False,  # pylint: disable=unused-argument\n    ) -> str:\n        \"\"\"\n        Sign a message in bytes string form.\n\n        :param message: the message to be signed\n        :param is_deprecated_mode: if the deprecated signing is used\n        :return: signature of the message in string form\n        \"\"\"\n        signature_compact = self.entity.sign_deterministic(\n            message,\n            hashfunc=hashlib.sha256,\n            sigencode=sigencode_string_canonize,\n        )\n        signature_base64_str = base64.b64encode(signature_compact).decode(\"utf-8\")\n        return signature_base64_str\n\n    def sign_transaction(self, transaction: JSONLike) -> JSONLike:\n        \"\"\"\n        Sign a transaction in bytes string form.\n\n        :param transaction: the transaction to be signed\n        :return: signed transaction\n        \"\"\"\n        tx = ParseDict(transaction[\"tx\"], Tx())\n\n        # If public key is not already part of transaction\n        if tx.auth_info.signer_infos[0].public_key.value == b\"\":\n            if len(transaction[\"sign_data\"]) == 1:  # type: ignore\n                # Insert public key to auth info\n                from_pub_key_packed = ProtoAny()\n                from_pub_key_pb = ProtoPubKey(key=bytes.fromhex(self.public_key))\n                from_pub_key_packed.Pack(from_pub_key_pb, type_url_prefix=\"/\")  # type: ignore\n\n                tx.auth_info.signer_infos[\n                    0\n                ].public_key.value = from_pub_key_packed.value\n            else:\n                # Fails if public key is not present in transaction with multiple signers\n                raise RuntimeError(\n                    \"Public key can be added during singing only for single message transactions.\"\n                )\n\n        current_sign_data = transaction[\"sign_data\"][self.address]  # type: ignore\n\n        sd = SignDoc()\n        sd.body_bytes = tx.body.SerializeToString()\n        sd.auth_info_bytes = tx.auth_info.SerializeToString()\n        sd.chain_id = current_sign_data[\"chain_id\"]  # type: ignore\n        sd.account_number = current_sign_data[\"account_number\"]  # type: ignore\n\n        data_for_signing = sd.SerializeToString()\n\n        # Generating signature:\n        signature = base64.b64decode(self.sign_message(data_for_signing))\n\n        tx.signatures.extend([signature])\n\n        return {\"tx\": MessageToDict(tx), \"sign_data\": transaction[\"sign_data\"]}\n\n    @classmethod\n    def generate_private_key(cls) -> SigningKey:\n        \"\"\"Generate a key pair for cosmos network.\"\"\"\n        signing_key = SigningKey.generate(curve=SECP256k1)\n        return signing_key\n\n    def encrypt(self, password: str) -> str:\n        \"\"\"\n        Encrypt the private key and return in json.\n\n        :param password: the password to decrypt.\n        :return: json string containing encrypted private key.\n        \"\"\"\n        return DataEncrypt.encrypt(self.private_key.encode(), password).decode()\n\n    @classmethod\n    def decrypt(cls, keyfile_json: str, password: str) -> str:\n        \"\"\"\n        Decrypt the private key and return in raw form.\n\n        :param keyfile_json: json string containing encrypted private key.\n        :param password: the password to decrypt.\n        :return: the raw private key.\n        \"\"\"\n        try:\n            return DataEncrypt.decrypt(keyfile_json.encode(), password).decode()\n        except UnicodeDecodeError as e:\n            raise ValueError(\n                \"key file data can not be translated to string! bad password?\"\n            ) from e\n\n\nclass _CosmosApi(LedgerApi):\n    \"\"\"Class to interact with the Cosmos SDK via a HTTP APIs.\"\"\"\n\n    identifier = _COSMOS\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"Initialize the Cosmos ledger APIs.\"\"\"\n        self._api = None\n        self.network_address = kwargs.pop(\"address\", DEFAULT_ADDRESS)\n        self.denom = kwargs.pop(\"denom\", DEFAULT_CURRENCY_DENOM)\n        self.chain_id = kwargs.pop(\"chain_id\", DEFAULT_CHAIN_ID)\n        self.rest_client = RestClient(self.network_address)\n        self.tx_client = TxRestClient(self.rest_client)\n        self.auth_client = AuthRestClient(self.rest_client)\n        self.wasm_client = CosmWasmRestClient(self.rest_client)\n        self.bank_client = BankRestClient(self.rest_client)\n\n    @property\n    def api(self) -> Any:\n        \"\"\"Get the underlying API object.\"\"\"\n        return self._api\n\n    def get_balance(self, address: Address) -> Optional[int]:\n        \"\"\"Get the balance of a given account.\"\"\"\n        balance = self._try_get_balance(address)\n        return balance\n\n    @try_decorator(\n        \"Encountered exception when trying get balance: {}\",\n        logger_method=_default_logger.warning,\n    )\n    def _try_get_balance(self, address: Address) -> Optional[int]:\n        res = self.bank_client.Balance(\n            QueryBalanceRequest(address=address, denom=self.denom)\n        )\n        return int(res.balance.amount)\n\n    def get_state(\n        self, callable_name: str, *args: Any, **kwargs: Any\n    ) -> Optional[JSONLike]:\n        \"\"\"\n        Call a specified function on the ledger API.\n\n        Based on the cosmos REST\n        API specification, which takes a path (strings separated by '/'). The\n        convention here is to define the root of the path (txs, blocks, etc.)\n        as the callable_name and the rest of the path as args.\n\n        :param callable_name: name of the callable\n        :param args: positional arguments\n        :param kwargs: keyword arguments\n        :return: the transaction dictionary\n        \"\"\"\n        response = self._try_get_state(callable_name, *args, **kwargs)\n        return response\n\n    @try_decorator(\n        \"Encountered exception when trying get state: {}\",\n        logger_method=_default_logger.warning,\n    )\n    def _try_get_state(  # pylint: disable=unused-argument\n        self, callable_name: str, *args: Any, **kwargs: Any\n    ) -> Optional[JSONLike]:\n        \"\"\"Try to call a function on the ledger API.\"\"\"\n        result: Optional[JSONLike] = None\n        query = \"/\".join(args)\n        url = self.network_address + f\"/{callable_name}/{query}\"\n        response = requests.get(url=url)\n        if response.status_code == 200:\n            result = response.json()\n        else:  # pragma: nocover\n            raise ValueError(\"Cannot get state: {}\".format(response.json()))\n        return result\n\n    def get_deploy_transaction(\n        self,\n        contract_interface: Dict[str, str],\n        deployer_address: Address,\n        **kwargs: Any,\n    ) -> Optional[JSONLike]:\n        \"\"\"\n        Get the transaction to deploy the smart contract.\n\n        Dispatches to _get_storage_transaction and _get_init_transaction based on kwargs.\n\n        :param contract_interface: the contract interface.\n        :param deployer_address: The address that will deploy the contract.\n        :param kwargs: keyword arguments.\n        :return: the transaction dictionary.\n        \"\"\"\n        denom = (\n            kwargs.pop(\"denom\") if kwargs.get(\"denom\", None) is not None else self.denom\n        )\n\n        tx_fee_denom = (\n            kwargs.pop(\"tx_fee_denom\")\n            if kwargs.get(\"tx_fee_denom\", None) is not None\n            else denom\n        )\n\n        chain_id = (\n            kwargs.pop(\"chain_id\")\n            if kwargs.get(\"chain_id\", None) is not None\n            else self.chain_id\n        )\n\n        account_number = kwargs.pop(\"account_number\", None)\n        sequence = kwargs.pop(\"sequence\", None)\n\n        if account_number is None or sequence is None:\n            account_number, sequence = self._try_get_account_number_and_sequence(\n                deployer_address\n            )\n            if account_number is None or sequence is None:\n                return None  # pragma: nocover\n\n        label = kwargs.pop(\"label\", None)\n        code_id = kwargs.pop(\"code_id\", None)\n        amount = kwargs.pop(\"amount\", None)\n        init_msg = kwargs.pop(\"init_msg\", None)\n        unexpected_keys = [\n            key for key in kwargs.keys() if key not in [\"tx_fee\", \"gas\", \"memo\"]\n        ]\n        if len(unexpected_keys) != 0:  # pragma: nocover\n            raise ValueError(f\"Unexpected keyword arguments: {unexpected_keys}\")\n        if label is None and code_id is None and amount is None and init_msg is None:\n            return self._get_storage_transaction(\n                contract_interface,\n                deployer_address,\n                tx_fee_denom,\n                chain_id,\n                account_number,\n                sequence,\n                **kwargs,\n            )\n        if label is None:\n            raise ValueError(  # pragma: nocover\n                \"Missing required keyword argument `label` of type `str` for `_get_init_transaction`.\"\n            )\n        if code_id is None:\n            raise ValueError(  # pragma: nocover\n                \"Missing required keyword argument `code_id` of type `int` for `_get_init_transaction`.\"\n            )\n        if amount is None:\n            raise ValueError(  # pragma: nocover\n                \"Missing required keyword argument `amount` of type `int` for `_get_init_transaction`.\"\n            )\n        if init_msg is None:\n            raise ValueError(  # pragma: nocover\n                \"Missing required keyword argument `init_msg` of type `JSONLike` `for `_get_init_transaction`.\"\n            )\n        return self._get_init_transaction(\n            deployer_address,\n            denom,\n            chain_id,\n            account_number,\n            sequence,\n            amount,\n            code_id,\n            init_msg,\n            label,\n            tx_fee_denom,\n            **kwargs,\n        )\n\n    def _get_storage_transaction(\n        self,\n        contract_interface: Dict[str, str],\n        deployer_address: Address,\n        tx_fee_denom: str,\n        chain_id: str,\n        account_number: int,\n        sequence: int,\n        tx_fee: int = 0,\n        gas: int = DEFAULT_GAS_AMOUNT,\n        memo: str = \"\",\n    ) -> Optional[JSONLike]:\n        \"\"\"\n        Create a CosmWasm bytecode deployment transaction.\n\n        :param contract_interface: the contract interface.\n        :param deployer_address: the deployer address.\n        :param tx_fee_denom: the denomination of tx_fee.\n        :param chain_id: the Chain ID of the CosmWasm transaction. Default is 1 (i.e. mainnet).\n        :param account_number: the account number.\n        :param sequence: the sequence number.\n        :param tx_fee: the transaction fee.\n        :param gas: Maximum amount of gas to be used on executing command.\n        :param memo: any string comment.\n        :return: the unsigned CosmWasm contract deploy message\n        \"\"\"\n        store_msg = MsgStoreCode(\n            sender=str(deployer_address),\n            wasm_byte_code=base64.b64decode(contract_interface[_BYTECODE]),\n        )\n        store_msg_packed = ProtoAny()\n        store_msg_packed.Pack(store_msg, type_url_prefix=\"/\")  # type: ignore\n        tx_fee_coins = [Coin(denom=tx_fee_denom, amount=str(tx_fee))]\n        tx = self._get_transaction(\n            account_numbers=[account_number],\n            from_addresses=[str(deployer_address)],\n            chain_id=chain_id,\n            tx_fee=tx_fee_coins,\n            gas=gas,\n            memo=memo,\n            sequences=[sequence],\n            msgs=[store_msg_packed],\n        )\n        return tx\n\n    def _get_init_transaction(\n        self,\n        deployer_address: Address,\n        denom: str,\n        chain_id: str,\n        account_number: int,\n        sequence: int,\n        amount: int,\n        code_id: int,\n        init_msg: JSONLike,\n        label: str,\n        tx_fee_denom: str,\n        tx_fee: int = 0,\n        gas: int = DEFAULT_GAS_AMOUNT,\n        memo: str = \"\",\n    ) -> Optional[JSONLike]:\n        \"\"\"\n        Create a CosmWasm InitMsg transaction.\n\n        :param deployer_address: the deployer address of the message initiator.\n        :param denom: the name of the denomination of the contract funds\n        :param chain_id: the Chain ID of the CosmWasm transaction.\n        :param account_number: the account number of the deployer.\n        :param sequence: the sequence of the deployer.\n        :param amount: Contract's initial funds amount\n        :param code_id: the ID of contract bytecode.\n        :param init_msg: the InitMsg containing parameters for contract constructor.\n        :param label: the label name of the contract.\n        :param tx_fee_denom: Denomination of tx_fee\n        :param tx_fee: the tx fee accepted.\n        :param gas: Maximum amount of gas to be used on executing command.\n        :param memo: any string comment.\n        :return: the unsigned CosmWasm InitMsg\n        \"\"\"\n        if amount == 0:\n            init_funds = []\n        else:\n            init_funds = [Coin(denom=denom, amount=str(amount))]\n\n        tx_fee_coins = [Coin(denom=tx_fee_denom, amount=str(tx_fee))]\n\n        init_msg = MsgInstantiateContract(\n            sender=str(deployer_address),\n            code_id=code_id,\n            msg=json.dumps(init_msg).encode(\"UTF8\"),\n            label=label,\n            funds=init_funds,\n        )\n        init_msg_packed = ProtoAny()\n        init_msg_packed.Pack(init_msg, type_url_prefix=\"/\")  # type: ignore\n\n        tx = self._get_transaction(\n            account_numbers=[account_number],\n            from_addresses=[str(deployer_address)],\n            chain_id=chain_id,\n            tx_fee=tx_fee_coins,\n            gas=gas,\n            memo=memo,\n            sequences=[sequence],\n            msgs=[init_msg_packed],\n        )\n        return tx\n\n    def get_handle_transaction(\n        self,\n        sender_address: Address,\n        contract_address: Address,\n        handle_msg: Any,\n        amount: int,\n        tx_fee: int,\n        denom: Optional[str] = None,\n        gas: int = DEFAULT_GAS_AMOUNT,\n        memo: str = \"\",\n        chain_id: Optional[str] = None,\n        account_number: Optional[int] = None,\n        sequence: Optional[int] = None,\n        tx_fee_denom: Optional[str] = None,\n    ) -> Optional[JSONLike]:\n        \"\"\"\n        Create a CosmWasm HandleMsg transaction.\n\n        :param sender_address: the sender address of the message initiator.\n        :param contract_address: the address of the smart contract.\n        :param handle_msg: HandleMsg in JSON format.\n        :param amount: Funds amount sent with transaction.\n        :param tx_fee: the tx fee accepted.\n        :param denom: the name of the denomination of the contract funds\n        :param gas: Maximum amount of gas to be used on executing command.\n        :param memo: any string comment.\n        :param chain_id: the Chain ID of the CosmWasm transaction. Default is 1 (i.e. mainnet).\n        :param account_number: Account number\n        :param sequence: Sequence\n        :param tx_fee_denom: Denomination of tx_fee, identical with denom param when None\n        :return: the unsigned CosmWasm HandleMsg\n        \"\"\"\n        denom = denom if denom is not None else self.denom\n        chain_id = chain_id if chain_id is not None else self.chain_id\n        tx_fee_denom = tx_fee_denom if tx_fee_denom is not None else denom\n\n        if account_number is None or sequence is None:\n            account_number, sequence = self._try_get_account_number_and_sequence(\n                sender_address\n            )\n            if account_number is None or sequence is None:\n                return None  # pragma: nocover\n\n        if amount == 0:\n            funds = []\n        else:\n            funds = [Coin(denom=denom, amount=str(amount))]\n        tx_fee_coins = [Coin(denom=tx_fee_denom, amount=str(tx_fee))]\n\n        execute_msg = MsgExecuteContract(\n            sender=str(sender_address),\n            contract=contract_address,\n            msg=json.dumps(handle_msg).encode(\"UTF8\"),\n            funds=funds,\n        )\n        execute_msg_packed = ProtoAny()\n        execute_msg_packed.Pack(execute_msg, type_url_prefix=\"/\")  # type: ignore\n\n        tx = self._get_transaction(\n            account_numbers=[account_number],\n            from_addresses=[str(sender_address)],\n            chain_id=chain_id,\n            tx_fee=tx_fee_coins,\n            gas=gas,\n            memo=memo,\n            sequences=[sequence],\n            msgs=[execute_msg_packed],\n        )\n        return tx\n\n    def execute_contract_query(\n        self, contract_address: Address, query_msg: JSONLike\n    ) -> Optional[JSONLike]:\n        \"\"\"\n        Execute a CosmWasm QueryMsg. QueryMsg doesn't require signing.\n\n        :param contract_address: the address of the smart contract.\n        :param query_msg: QueryMsg in JSON format.\n        :return: the message receipt\n        \"\"\"\n        result = self._try_execute_wasm_query(contract_address, query_msg)\n        return result\n\n    @try_decorator(\n        \"Encountered exception when trying to execute wasm query: {}\",\n        logger_method=_default_logger.warning,\n    )\n    def _try_execute_wasm_query(\n        self, contract_address: Address, query_msg: JSONLike\n    ) -> Optional[JSONLike]:\n        \"\"\"\n        Execute a CosmWasm QueryMsg. QueryMsg doesn't require signing.\n\n        :param contract_address: the address of the smart contract.\n        :param query_msg: QueryMsg in JSON format.\n        :return: the message receipt\n        \"\"\"\n        request = QuerySmartContractStateRequest(\n            address=contract_address, query_data=json.dumps(query_msg).encode(\"UTF8\")\n        )\n        res = self.wasm_client.SmartContractState(request)\n        return json.loads(res.data)\n\n    def get_transfer_transaction(  # pylint: disable=arguments-differ\n        self,\n        sender_address: Address,\n        destination_address: Address,\n        amount: int,\n        tx_fee: int,\n        tx_nonce: str,\n        denom: Optional[str] = None,\n        gas: int = DEFAULT_GAS_AMOUNT,\n        memo: str = \"\",\n        chain_id: Optional[str] = None,\n        account_number: Optional[int] = None,\n        sequence: Optional[int] = None,\n        tx_fee_denom: Optional[str] = None,\n        **kwargs: Any,\n    ) -> Optional[JSONLike]:\n        \"\"\"\n        Submit a transfer transaction to the ledger.\n\n        :param sender_address: the sender address of the payer.\n        :param destination_address: the destination address of the payee.\n        :param amount: the amount of wealth to be transferred.\n        :param tx_fee: the transaction fee.\n        :param tx_nonce: verifies the authenticity of the tx\n        :param denom: the denomination of tx fee and amount\n        :param gas: the gas used.\n        :param memo: memo to include in tx.\n        :param chain_id: the chain ID of the transaction.\n        :param account_number: Account number\n        :param sequence: Sequence\n        :param tx_fee_denom: Denomination of tx_fee, identical with denom param when None\n        :param kwargs: keyword arguments.\n        :return: the transfer transaction\n        \"\"\"\n        denom = denom if denom is not None else self.denom\n        chain_id = chain_id if chain_id is not None else self.chain_id\n        tx_fee_denom = tx_fee_denom if tx_fee_denom is not None else denom\n\n        if account_number is None or sequence is None:\n            account_number, sequence = self._try_get_account_number_and_sequence(\n                sender_address\n            )\n            if account_number is None or sequence is None:\n                return None  # pragma: nocover\n\n        tx_fee_coins = [Coin(denom=tx_fee_denom, amount=str(tx_fee))]\n        amount_coins = [Coin(denom=denom, amount=str(amount))]\n\n        msg_send = MsgSend(\n            from_address=str(sender_address),\n            to_address=str(destination_address),\n            amount=amount_coins,\n        )\n        send_msg_packed = ProtoAny()\n        send_msg_packed.Pack(msg_send, type_url_prefix=\"/\")  # type: ignore\n\n        tx = self._get_transaction(\n            account_numbers=[account_number],\n            from_addresses=[str(sender_address)],\n            chain_id=chain_id,\n            tx_fee=tx_fee_coins,\n            gas=gas,\n            memo=memo,\n            sequences=[sequence],\n            msgs=[send_msg_packed],\n        )\n        return tx\n\n    def get_packed_exec_msg(\n        self,\n        sender_address: Address,\n        contract_address: str,\n        msg: JSONLike,\n        funds: int = 0,\n        denom: Optional[str] = None,\n    ) -> ProtoAny:\n        \"\"\"\n        Create and pack MsgExecuteContract\n\n        :param sender_address: Address of sender\n        :param contract_address: Address of contract\n        :param msg: Paramaters to be passed to smart contract\n        :param funds: Funds to be sent to smart contract\n        :param denom: the denomination of funds\n\n        :return: Packed MsgExecuteContract\n        \"\"\"\n        denom = denom if denom is not None else self.denom\n\n        if funds == 0:\n            funds_coins = []\n        else:\n            funds_coins = [Coin(denom=denom, amount=str(funds))]\n\n        msg_send = MsgExecuteContract(\n            sender=str(sender_address),\n            contract=contract_address,\n            msg=json.dumps(msg).encode(\"UTF8\"),\n            funds=funds_coins,\n        )\n        send_msg_packed = ProtoAny()\n        send_msg_packed.Pack(msg_send, type_url_prefix=\"/\")\n\n        return send_msg_packed\n\n    def get_packed_send_msg(\n        self,\n        from_address: Address,\n        to_address: Address,\n        amount: int,\n        denom: Optional[str] = None,\n    ) -> ProtoAny:\n        \"\"\"\n        Generate and pack MsgSend\n\n        :param from_address: Address of sender\n        :param to_address: Address of recipient\n        :param amount: amount of coins to be sent\n        :param denom: the denomination of and amount\n\n        :return: packer ProtoAny type message\n        \"\"\"\n        denom = denom if denom is not None else self.denom\n\n        amount_coins = [Coin(denom=denom, amount=str(amount))]\n\n        msg_send = MsgSend(\n            from_address=str(from_address),\n            to_address=str(to_address),\n            amount=amount_coins,\n        )\n        send_msg_packed = ProtoAny()\n        send_msg_packed.Pack(msg_send, type_url_prefix=\"/\")\n\n        return send_msg_packed\n\n    def get_multi_transaction(\n        self,\n        from_addresses: List[str],\n        pub_keys: Optional[List[bytes]],\n        msgs: List[ProtoAny],\n        gas: int,\n        tx_fee: int = 0,\n        memo: str = \"\",\n        chain_id: Optional[str] = None,\n        denom: Optional[str] = None,\n        tx_fee_denom: Optional[str] = None,\n    ) -> JSONLike:\n        \"\"\"\n        Generate transaction with multiple messages\n\n        :param from_addresses: Addresses of signers\n        :param pub_keys: Public keys of signers\n        :param msgs: Messages to be included in transaction\n        :param gas: the gas used.\n        :param tx_fee: the transaction fee.\n        :param memo: memo to include in tx.\n        :param chain_id: the chain ID of the transaction.\n        :param denom: the denomination of tx fee\n        :param tx_fee_denom: Denomination of tx_fee, identical with denom param when None\n\n        :raises: RuntimeError if number of pubkeys is not equal to number of from_addresses\n\n        :return: the transaction\n        \"\"\"\n        if pub_keys is not None and len(pub_keys) != len(from_addresses):\n            raise RuntimeError(\n                \"Number of pubkeys is not equal to number of addresses\"\n            )  # pragma: nocover\n\n        denom = denom if denom is not None else self.denom\n        chain_id = chain_id if chain_id is not None else self.chain_id\n        tx_fee_denom = tx_fee_denom if tx_fee_denom is not None else denom\n\n        tx_fee_coins = [Coin(denom=tx_fee_denom, amount=str(tx_fee))]\n\n        account_numbers: List[int] = []\n        sequences: List[int] = []\n        for address in from_addresses:\n            account_number, sequence = self._try_get_account_number_and_sequence(\n                address\n            )\n            account_numbers.append(account_number)\n            sequences.append(sequence)\n            # Prevent requests overflow\n            time.sleep(1)\n\n        return self._get_transaction(\n            account_numbers=account_numbers,\n            from_addresses=from_addresses,\n            chain_id=chain_id,\n            tx_fee=tx_fee_coins,\n            gas=gas,\n            memo=memo,\n            sequences=sequences,\n            msgs=msgs,\n            pub_keys=pub_keys,\n        )\n\n    @staticmethod\n    def _get_transaction(\n        account_numbers: List[int],\n        from_addresses: List[str],\n        chain_id: str,\n        tx_fee: List[Coin],\n        gas: int,\n        memo: str,\n        sequences: List[int],\n        msgs: List[ProtoAny],\n        pub_keys: Optional[List[bytes]] = None,\n    ) -> JSONLike:\n        \"\"\"\n        Get a transaction.\n\n        :param account_numbers: Account numbers for each signer.\n        :param from_addresses: Addresses of each sender\n        :param chain_id: the chain ID of the transaction.\n        :param tx_fee: the transaction fee.\n        :param gas: the gas used.\n        :param memo: memo to include in tx.\n        :param sequences: Sequence for each sender.\n        :param msgs: Messages to be part of transaction.\n        :param pub_keys: Public keys of each sender\n\n        :raises: RuntimeError\n\n        :return: the transaction\n        \"\"\"\n\n        # Txs will fail if gas is higher than MAXIMUM_GAS_AMOUNT\n        if gas > MAXIMUM_GAS_AMOUNT:\n            _default_logger.warning(\n                f\"Gas limit {gas} is above maximum gas limit {MAXIMUM_GAS_AMOUNT}. Gas limit was truncated to maximum.\"\n            )\n            gas = MAXIMUM_GAS_AMOUNT\n\n        # Checks\n        if pub_keys is None:\n            if len(from_addresses) == 1:\n                pub_keys = [b\"\"]\n            else:\n                # In case when pubkey is inserted during signing would make second signer to change tx and make the first signature invalid\n                raise RuntimeError(\n                    \"Only transaction with one signer can be generated without pubkeys\"\n                )\n        if len(account_numbers) != len(from_addresses) or len(from_addresses) != len(\n            sequences\n        ):\n            raise RuntimeError(\n                \"Amount of provided from_addresses, sequences and account_numbers is not equal\"\n            )\n\n        # Get account and signer info for each sender\n        signer_infos: List[SignerInfo] = []\n        sign_data: JSONLike = {}\n        for from_address, pub_key, sequence, account_number in zip(\n            from_addresses, pub_keys, sequences, account_numbers\n        ):\n            from_pub_key_packed = ProtoAny()\n            from_pub_key_pb = ProtoPubKey(key=pub_key)\n            from_pub_key_packed.Pack(from_pub_key_pb, type_url_prefix=\"/\")  # type: ignore\n\n            # Prepare auth info\n            single = ModeInfo.Single(mode=SignMode.SIGN_MODE_DIRECT)\n            mode_info = ModeInfo(single=single)\n            signer_info = SignerInfo(\n                public_key=from_pub_key_packed,\n                mode_info=mode_info,\n                sequence=sequence,\n            )\n            signer_infos.append(signer_info)\n\n            sign_data[from_address] = {\n                \"account_number\": account_number,\n                \"chain_id\": chain_id,\n            }\n\n        # Prepare auth info\n        auth_info = AuthInfo(\n            signer_infos=signer_infos,\n            fee=Fee(amount=tx_fee, gas_limit=gas),\n        )\n\n        # Prepare Tx body\n        tx_body = TxBody()\n        tx_body.memo = memo\n        tx_body.messages.extend(msgs)\n\n        # Prepare Tx\n        tx = Tx(body=tx_body, auth_info=auth_info)\n\n        return {\"tx\": MessageToDict(tx), \"sign_data\": sign_data}\n\n    @try_decorator(\n        \"Encountered exception when trying to get account number and sequence: {}\",\n        logger_method=_default_logger.warning,\n    )\n    def _try_get_account_number_and_sequence(\n        self, address: Address\n    ) -> Tuple[Optional[int], Optional[int]]:\n        \"\"\"\n        Try get account number and sequence for an address.\n\n        :param address: the address\n        :return: a tuple of account number and sequence\n        \"\"\"\n        account_response = self.auth_client.Account(\n            QueryAccountRequest(address=address)\n        )\n\n        account = BaseAccount()\n        if account_response.account.Is(BaseAccount.DESCRIPTOR):\n            account_response.account.Unpack(account)\n        else:\n            raise TypeError(\"Unexpected account type\")  # pragma: nocover\n\n        return account.account_number, account.sequence\n\n    def send_signed_transaction(self, tx_signed: JSONLike) -> Optional[str]:\n        \"\"\"\n        Send a signed transaction and wait for confirmation.\n\n        :param tx_signed: the signed transaction\n        :return: tx_digest, if present\n        \"\"\"\n        tx = ParseDict(tx_signed[\"tx\"], Tx())\n\n        tx_data = tx.SerializeToString()\n        broad_tx_req = BroadcastTxRequest(\n            tx_bytes=tx_data, mode=BroadcastMode.BROADCAST_MODE_SYNC\n        )\n        broad_tx_resp = self.tx_client.BroadcastTx(broad_tx_req)\n\n        if broad_tx_resp.tx_response.code != 0:\n            raw_log = broad_tx_resp.tx_response.raw_log\n\n            _default_logger.warning(\n                f\"Sending transaction failed: {raw_log} {broad_tx_resp}\"\n            )\n            tx_digest = None\n        else:\n            tx_digest = broad_tx_resp.tx_response.txhash\n\n        return tx_digest\n\n    def get_transaction_receipt(self, tx_digest: str) -> Optional[JSONLike]:\n        \"\"\"\n        Get the transaction receipt for a transaction digest.\n\n        :param tx_digest: the digest associated to the transaction.\n        :return: the tx receipt, if present\n        \"\"\"\n        tx_with_receipt = self._try_get_transaction_with_receipt(tx_digest)\n\n        if tx_with_receipt is None:\n            return None\n        return tx_with_receipt.get(\"txResponse\")\n\n    @try_decorator(\n        \"Encountered exception when trying to get transaction receipt: {}\",\n        logger_method=_default_logger.warning,\n    )\n    def _try_get_transaction_with_receipt(self, tx_digest: str) -> Optional[JSONLike]:\n        \"\"\"\n        Try get the transaction receipt for a transaction digest.\n\n        :param tx_digest: the digest associated to the transaction.\n        :return: the tx receipt, if present\n        \"\"\"\n\n        tx_request = GetTxRequest(hash=tx_digest)\n        tx_response = self.tx_client.GetTx(tx_request)\n        return MessageToDict(tx_response)\n\n    def get_transaction(self, tx_digest: str) -> Optional[JSONLike]:\n        \"\"\"\n        Get the transaction for a transaction digest.\n\n        :param tx_digest: the digest associated to the transaction.\n        :return: the tx, if present\n        \"\"\"\n        # Cosmos does not distinguish between transaction receipt and transaction\n        tx_with_receipt = self._try_get_transaction_with_receipt(tx_digest)\n        if tx_with_receipt is None:\n            return None  # pragma: nocover\n        return {\"tx\": tx_with_receipt.get(\"tx\")}\n\n    def get_contract_instance(\n        self, contract_interface: Dict[str, str], contract_address: Optional[str] = None\n    ) -> Any:\n        \"\"\"\n        Get the instance of a contract.\n\n        :param contract_interface: the contract interface.\n        :param contract_address: the contract address.\n        :return: the contract instance\n        \"\"\"\n        # Instance object not available for cosmwasm\n        return None\n\n    def update_with_gas_estimate(self, transaction: JSONLike) -> JSONLike:\n        \"\"\"\n        Attempts to update the transaction with a gas estimate\n\n        :param transaction: the transaction\n        :raises: NotImplementedError\n        \"\"\"\n        raise NotImplementedError(  # pragma: nocover\n            \"No gas estimation has been implemented.\"\n        )\n\n\nclass CosmosApi(_CosmosApi, CosmosHelper):\n    \"\"\"Class to interact with the Cosmos SDK via a HTTP APIs.\"\"\"\n\n\n\"\"\" Equivalent to:\n\n@dataclass\nclass CosmosFaucetStatus:\n    tx_digest: Optional[str]\n    status: str\n\"\"\"\nCosmosFaucetStatus = namedtuple(\"CosmosFaucetStatus\", [\"tx_digest\", \"status\"])\n\n\nclass CosmosFaucetApi(FaucetApi):\n    \"\"\"Cosmos testnet faucet API.\"\"\"\n\n    FAUCET_STATUS_PENDING = \"pending\"  # noqa: F841\n    FAUCET_STATUS_PROCESSING = \"processing\"  # noqa: F841\n    FAUCET_STATUS_COMPLETED = \"complete\"  # noqa: F841\n    FAUCET_STATUS_FAILED = \"failed\"  # noqa: F841\n\n    identifier = _COSMOS\n    testnet_faucet_url = DEFAULT_FAUCET_URL\n    testnet_name = TESTNET_NAME\n    max_retry_attempts = 15\n\n    def __init__(\n        self,\n        poll_interval: Optional[float] = None,\n        final_wait_interval: Optional[float] = None,\n    ):\n        \"\"\"Initialize CosmosFaucetApi.\"\"\"\n        self._poll_interval = float(poll_interval or 2)\n        self._final_wait_interval = float(final_wait_interval or 5)\n\n    def get_wealth(self, address: Address, url: Optional[str] = None) -> None:\n        \"\"\"\n        Get wealth from the faucet for the provided address.\n\n        :param address: the address.\n        :param url: the url\n        :raises: RuntimeError of explicit faucet failures\n        \"\"\"\n        uid = self._try_create_faucet_claim(address, url)\n        if uid is None:  # pragma: nocover\n            raise RuntimeError(\"Unable to create faucet claim\")\n\n        retry_attempts = self.max_retry_attempts\n        while retry_attempts > 0:\n            retry_attempts -= 1\n\n            # lookup status form the claim uid\n            status = self._try_check_faucet_claim(uid, url)\n            if status is None:  # pragma: nocover\n                raise RuntimeError(\"Failed to check faucet claim status\")\n\n            # if the status is complete\n            if status.status == self.FAUCET_STATUS_COMPLETED:\n                break\n\n            # if the status is failure\n            if status.status not in (\n                self.FAUCET_STATUS_PENDING,\n                self.FAUCET_STATUS_PROCESSING,\n            ):  # pragma: nocover\n                raise RuntimeError(f\"Failed to get wealth for {address}\")\n\n            # if the status is incomplete\n            time.sleep(self._poll_interval)\n        if retry_attempts == 0:\n            raise ValueError(\"Faucet claim check timed out!\")  # pragma: nocover\n        # Wait to ensure that balance is increased on chain\n        time.sleep(self._final_wait_interval)\n\n    @classmethod\n    @try_decorator(\n        \"An error occured while attempting to request a faucet request:\\n{}\",\n        logger_method=_default_logger.error,\n    )\n    def _try_create_faucet_claim(\n        cls, address: Address, url: Optional[str] = None\n    ) -> Optional[str]:\n        \"\"\"\n        Create a token faucet claim request\n\n        :param address: the address to request funds\n        :param url: the url\n        :return: None on failure, otherwise the request uid\n        \"\"\"\n        uri = cls._faucet_request_uri(url)\n        response = requests.post(url=uri, json={\"address\": address})\n\n        uid = None\n        if response.status_code == 200:\n            try:\n                uid = response.json()[\"uuid\"]\n            except KeyError:  # pragma: nocover\n                ValueError(f\"key `uid` not found in response_json={response.json()}\")\n            _default_logger.info(\"Wealth claim generated, uid: {}\".format(uid))\n        else:  # pragma: no cover\n            _default_logger.warning(\n                \"Response: {}, Text: {}\".format(response.status_code, response.text)\n            )\n\n        return uid\n\n    @classmethod\n    @try_decorator(\n        \"An error occured while attempting to request a faucet request:\\n{}\",\n        logger_method=_default_logger.error,\n    )\n    def _try_check_faucet_claim(\n        cls, uid: str, url: Optional[str] = None\n    ) -> Optional[CosmosFaucetStatus]:\n        \"\"\"\n        Check the status of a faucet request\n\n        :param uid: The request uid to be checked\n        :param url: the url\n        :return: None on failure otherwise a CosmosFaucetStatus for the specified uid\n        \"\"\"\n        response = requests.get(cls._faucet_status_uri(uid, url))\n        if response.status_code != 200:  # pragma: nocover\n            _default_logger.warning(\n                \"Response: {}, Text: {}\".format(response.status_code, response.text)\n            )\n            return None\n\n        # parse the response\n        data = response.json()\n        tx_digest = None\n        if \"txStatus\" in data[\"claim\"]:\n            tx_digest = data[\"claim\"][\"txStatus\"][\"hash\"]\n\n        return CosmosFaucetStatus(\n            tx_digest=tx_digest,\n            status=data[\"claim\"][\"status\"],\n        )\n\n    @classmethod\n    def _faucet_request_uri(cls, url: Optional[str] = None) -> str:\n        \"\"\"\n        Generates the request URI derived from `cls.faucet_base_url` or provided url.\n\n        :param url: the url\n        :return: the faucet request uri\n        \"\"\"\n        if cls.testnet_faucet_url is None:  # pragma: nocover\n            raise ValueError(\"Testnet faucet url not set.\")\n        url = cls.testnet_faucet_url if url is None else url\n        return f\"{url}/api/v3/claims\"\n\n    @classmethod\n    def _faucet_status_uri(cls, uid: str, url: Optional[str] = None) -> str:\n        \"\"\"Generates the status URI derived from `cls.faucet_base_url`.\"\"\"\n        return f\"{cls._faucet_request_uri(url)}/{uid}\"\n"
  },
  {
    "path": "plugins/aea-ledger-fetchai/aea_ledger_fetchai/fetchai.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Fetchai module wrapping the public and private key cryptography and ledger api.\"\"\"\n\nfrom typing import Any\n\nfrom aea_ledger_fetchai._cosmos import (\n    CosmosCrypto,\n    CosmosFaucetApi,\n    CosmosHelper,\n    _CosmosApi,\n)\n\n\n_FETCHAI = \"fetchai\"\n_FETCH = \"fetch\"\nTESTNET_NAME = \"testnet\"\nFETCHAI_TESTNET_FAUCET_URL = \"https://faucet-dorado.fetch.ai\"\nDEFAULT_ADDRESS = \"https://rest-dorado.fetch.ai:443\"\nDEFAULT_CURRENCY_DENOM = \"atestfet\"\nDEFAULT_CHAIN_ID = \"dorado-1\"\n\n\nclass FetchAIHelper(CosmosHelper):\n    \"\"\"Helper class usable as Mixin for FetchAIApi or as standalone class.\"\"\"\n\n    address_prefix = _FETCH\n\n\nclass FetchAICrypto(CosmosCrypto):  # pylint: disable=W0223\n    \"\"\"Class wrapping the Entity Generation from Fetch.AI ledger.\"\"\"\n\n    identifier = _FETCHAI\n    helper = FetchAIHelper\n\n\nclass FetchAIApi(_CosmosApi, FetchAIHelper):\n    \"\"\"Class to interact with the Fetch ledger APIs.\"\"\"\n\n    identifier = _FETCHAI\n\n    def __init__(self, **kwargs: Any) -> None:\n        \"\"\"Initialize the Fetch.ai ledger APIs.\"\"\"\n        if \"address\" not in kwargs:\n            kwargs[\"address\"] = DEFAULT_ADDRESS  # pragma: nocover\n        if \"denom\" not in kwargs:\n            kwargs[\"denom\"] = DEFAULT_CURRENCY_DENOM\n        if \"chain_id\" not in kwargs:\n            kwargs[\"chain_id\"] = DEFAULT_CHAIN_ID\n        super().__init__(**kwargs)\n\n\nclass FetchAIFaucetApi(CosmosFaucetApi):\n    \"\"\"Fetchai testnet faucet API.\"\"\"\n\n    identifier = _FETCHAI\n    testnet_name = TESTNET_NAME\n    testnet_faucet_url = FETCHAI_TESTNET_FAUCET_URL\n"
  },
  {
    "path": "plugins/aea-ledger-fetchai/pyproject.toml",
    "content": "[build-system]\nrequires = [\"setuptools\", \"wheel\"]\nbuild_backend = \"setuptools.build_meta\"\n"
  },
  {
    "path": "plugins/aea-ledger-fetchai/setup.py",
    "content": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Setup script for \"aea_ledger_fetchai\" package.\"\"\"\n\nimport os\n\nfrom setuptools import find_packages, setup\n\n\nhere = os.path.abspath(os.path.dirname(__file__))\nplugin_dir = os.path.abspath(os.path.join(here, \"..\"))\n\nsetup(\n    name=\"aea-ledger-fetchai\",\n    version=\"1.2.5\",\n    author=\"Fetch.AI Limited\",\n    license=\"Apache-2.0\",\n    description=\"Python package wrapping the public and private key cryptography and ledger API of Fetch.AI.\",\n    packages=find_packages(include=[\"aea_ledger_fetchai*\"]),\n    install_requires=[\n        \"aea>=1.0.0, <2.0.0\",\n        \"ecdsa>=0.15,<0.17.0\",\n        \"bech32==1.2.0\",\n        \"pycryptodome>=3.10.1,<4.0.0\",\n        \"cosmpy>=0.6.2,<0.7.0\",\n    ],\n    tests_require=[\"pytest\"],\n    entry_points={\n        \"aea.cryptos\": [\"fetchai = aea_ledger_fetchai:FetchAICrypto\"],\n        \"aea.ledger_apis\": [\"fetchai = aea_ledger_fetchai:FetchAIApi\"],\n        \"aea.faucet_apis\": [\"fetchai = aea_ledger_fetchai:FetchAIFaucetApi\"],\n    },\n    classifiers=[\n        \"Environment :: Console\",\n        \"Environment :: Web Environment\",\n        \"Development Status :: 5 - Production/Stable\",\n        \"Intended Audience :: Developers\",\n        \"License :: OSI Approved :: Apache Software License\",\n        \"Natural Language :: English\",\n        \"Operating System :: MacOS\",\n        \"Operating System :: Microsoft\",\n        \"Operating System :: Unix\",\n        \"Programming Language :: Python :: 3.6\",\n        \"Programming Language :: Python :: 3.7\",\n        \"Programming Language :: Python :: 3.8\",\n        \"Programming Language :: Python :: 3.9\",\n        \"Topic :: Communications\",\n        \"Topic :: Internet\",\n        \"Topic :: Software Development\",\n    ],\n)\n"
  },
  {
    "path": "plugins/aea-ledger-fetchai/tests/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Tests for the aea_ledger_fetchai package.\"\"\"\n"
  },
  {
    "path": "plugins/aea-ledger-fetchai/tests/conftest.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Conftest module for Pytest.\"\"\"\nimport inspect\nimport os\n\nfrom aea_ledger_fetchai import FetchAICrypto\n\n\nCUR_PATH = os.path.dirname(inspect.getfile(inspect.currentframe()))  # type: ignore\nROOT_DIR = os.path.join(CUR_PATH, \"..\")\nMAX_FLAKY_RERUNS = 3\nFETCHAI = FetchAICrypto.identifier\n\n\nFETCHAI_DEFAULT_ADDRESS = \"https://rest-dorado.fetch.ai:443\"\nFETCHAI_DEFAULT_CURRENCY_DENOM = \"atestfet\"\nFETCHAI_DEFAULT_CHAIN_ID = \"dorado-1\"\nFETCHAI_TESTNET_CONFIG = {\"address\": FETCHAI_DEFAULT_ADDRESS}\n"
  },
  {
    "path": "plugins/aea-ledger-fetchai/tests/data/dummy_contract/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains a dummy contract for an AEA.\"\"\"\n"
  },
  {
    "path": "plugins/aea-ledger-fetchai/tests/data/dummy_contract/build/some.json",
    "content": "{\n  \"contractName\": \"erc1155\",\n  \"abi\": [\n    {\n      \"name\": \"TransferSingle\",\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_operator\",\n          \"indexed\": true\n        },\n        {\n          \"type\": \"address\",\n          \"name\": \"_from\",\n          \"indexed\": true\n        },\n        {\n          \"type\": \"address\",\n          \"name\": \"_to\",\n          \"indexed\": true\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_id\",\n          \"indexed\": false\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_value\",\n          \"indexed\": false\n        }\n      ],\n      \"anonymous\": false,\n      \"type\": \"event\"\n    },\n    {\n      \"name\": \"TransferBatch\",\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_operator\",\n          \"indexed\": true\n        },\n        {\n          \"type\": \"address\",\n          \"name\": \"_from\",\n          \"indexed\": true\n        },\n        {\n          \"type\": \"address\",\n          \"name\": \"_to\",\n          \"indexed\": true\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_ids\",\n          \"indexed\": false\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_values\",\n          \"indexed\": false\n        }\n      ],\n      \"anonymous\": false,\n      \"type\": \"event\"\n    },\n    {\n      \"name\": \"ApprovalForAll\",\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_owner\",\n          \"indexed\": true\n        },\n        {\n          \"type\": \"address\",\n          \"name\": \"_operator\",\n          \"indexed\": true\n        },\n        {\n          \"type\": \"bool\",\n          \"name\": \"_approved\",\n          \"indexed\": false\n        }\n      ],\n      \"anonymous\": false,\n      \"type\": \"event\"\n    },\n    {\n      \"name\": \"URI\",\n      \"inputs\": [\n        {\n          \"type\": \"string\",\n          \"name\": \"_value\",\n          \"indexed\": false\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_id\",\n          \"indexed\": true\n        }\n      ],\n      \"anonymous\": false,\n      \"type\": \"event\"\n    },\n    {\n      \"outputs\": [],\n      \"inputs\": [],\n      \"constant\": false,\n      \"payable\": false,\n      \"type\": \"constructor\"\n    },\n    {\n      \"name\": \"getAddress\",\n      \"outputs\": [\n        {\n          \"type\": \"bytes32\",\n          \"name\": \"out\"\n        }\n      ],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_addr\"\n        }\n      ],\n      \"constant\": true,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 370\n    },\n    {\n      \"name\": \"getHash\",\n      \"outputs\": [\n        {\n          \"type\": \"bytes32\",\n          \"name\": \"out\"\n        }\n      ],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_from\"\n        },\n        {\n          \"type\": \"address\",\n          \"name\": \"_to\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_ids\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_from_supplies\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_to_supplies\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_value_eth\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_nonce\"\n        }\n      ],\n      \"constant\": true,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 11446\n    },\n    {\n      \"name\": \"getSingleHash\",\n      \"outputs\": [\n        {\n          \"type\": \"bytes32\",\n          \"name\": \"out\"\n        }\n      ],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_from\"\n        },\n        {\n          \"type\": \"address\",\n          \"name\": \"_to\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_id\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_from_supply\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_to_supply\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_value_eth\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_nonce\"\n        }\n      ],\n      \"constant\": true,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 2041\n    },\n    {\n      \"name\": \"supportsInterface\",\n      \"outputs\": [\n        {\n          \"type\": \"bool\",\n          \"name\": \"out\"\n        }\n      ],\n      \"inputs\": [\n        {\n          \"type\": \"bytes32\",\n          \"name\": \"_interfaceID\"\n        }\n      ],\n      \"constant\": true,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 868\n    },\n    {\n      \"name\": \"is_nonce_used\",\n      \"outputs\": [\n        {\n          \"type\": \"bool\",\n          \"name\": \"out\"\n        }\n      ],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"addr\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"nonce\"\n        }\n      ],\n      \"constant\": true,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 1052\n    },\n    {\n      \"name\": \"is_token_id_exists\",\n      \"outputs\": [\n        {\n          \"type\": \"bool\",\n          \"name\": \"out\"\n        }\n      ],\n      \"inputs\": [\n        {\n          \"type\": \"uint256\",\n          \"name\": \"token_id\"\n        }\n      ],\n      \"constant\": true,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 928\n    },\n    {\n      \"name\": \"safeTransferFrom\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_from\"\n        },\n        {\n          \"type\": \"address\",\n          \"name\": \"_to\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_id\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_value\"\n        },\n        {\n          \"type\": \"bytes\",\n          \"name\": \"_data\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 80803\n    },\n    {\n      \"name\": \"safeBatchTransferFrom\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_from\"\n        },\n        {\n          \"type\": \"address\",\n          \"name\": \"_to\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_ids\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_values\"\n        },\n        {\n          \"type\": \"bytes\",\n          \"name\": \"_data\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 748184\n    },\n    {\n      \"name\": \"balanceOf\",\n      \"outputs\": [\n        {\n          \"type\": \"uint256\",\n          \"name\": \"out\"\n        }\n      ],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_owner\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_id\"\n        }\n      ],\n      \"constant\": true,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 1172\n    },\n    {\n      \"name\": \"balanceOfBatch\",\n      \"outputs\": [\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"out\"\n        }\n      ],\n      \"inputs\": [\n        {\n          \"type\": \"address[10]\",\n          \"name\": \"_owner\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_ids\"\n        }\n      ],\n      \"constant\": true,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 7524\n    },\n    {\n      \"name\": \"setApprovalForAll\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_operator\"\n        },\n        {\n          \"type\": \"bool\",\n          \"name\": \"_approved\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 38136\n    },\n    {\n      \"name\": \"isApprovedForAll\",\n      \"outputs\": [\n        {\n          \"type\": \"bool\",\n          \"name\": \"out\"\n        }\n      ],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_owner\"\n        },\n        {\n          \"type\": \"address\",\n          \"name\": \"_operator\"\n        }\n      ],\n      \"constant\": true,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 1301\n    },\n    {\n      \"name\": \"createSingle\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_item_owner\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_id\"\n        },\n        {\n          \"type\": \"string\",\n          \"name\": \"_path\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 597461\n    },\n    {\n      \"name\": \"createBatch\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_items_owner\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_ids\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 927926\n    },\n    {\n      \"name\": \"mint\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_to\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_id\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_supply\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": false,\n      \"type\": \"function\"\n    },\n    {\n      \"name\": \"mint\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_to\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_id\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_supply\"\n        },\n        {\n          \"type\": \"bytes\",\n          \"name\": \"_data\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": false,\n      \"type\": \"function\"\n    },\n    {\n      \"name\": \"mintBatch\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_to\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_ids\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_supplies\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": false,\n      \"type\": \"function\"\n    },\n    {\n      \"name\": \"mintBatch\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_to\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_ids\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_supplies\"\n        },\n        {\n          \"type\": \"bytes\",\n          \"name\": \"_data\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": false,\n      \"type\": \"function\"\n    },\n    {\n      \"name\": \"burn\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_id\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_supply\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 40353\n    },\n    {\n      \"name\": \"burnBatch\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_ids\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_supplies\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 382149\n    },\n    {\n      \"name\": \"tradeBatch\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_from\"\n        },\n        {\n          \"type\": \"address\",\n          \"name\": \"_to\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_ids\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_from_supplies\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_to_supplies\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_value_eth\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_nonce\"\n        },\n        {\n          \"type\": \"bytes\",\n          \"name\": \"_signature\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": true,\n      \"type\": \"function\"\n    },\n    {\n      \"name\": \"tradeBatch\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_from\"\n        },\n        {\n          \"type\": \"address\",\n          \"name\": \"_to\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_ids\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_from_supplies\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_to_supplies\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_value_eth\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_nonce\"\n        },\n        {\n          \"type\": \"bytes\",\n          \"name\": \"_signature\"\n        },\n        {\n          \"type\": \"bytes\",\n          \"name\": \"_data\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": true,\n      \"type\": \"function\"\n    },\n    {\n      \"name\": \"trade\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_from\"\n        },\n        {\n          \"type\": \"address\",\n          \"name\": \"_to\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_id\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_from_supply\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_to_supply\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_value_eth\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_nonce\"\n        },\n        {\n          \"type\": \"bytes\",\n          \"name\": \"_signature\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": true,\n      \"type\": \"function\"\n    },\n    {\n      \"name\": \"trade\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_from\"\n        },\n        {\n          \"type\": \"address\",\n          \"name\": \"_to\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_id\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_from_supply\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_to_supply\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_value_eth\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_nonce\"\n        },\n        {\n          \"type\": \"bytes\",\n          \"name\": \"_signature\"\n        },\n        {\n          \"type\": \"bytes\",\n          \"name\": \"_data\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": true,\n      \"type\": \"function\"\n    },\n    {\n      \"name\": \"owner\",\n      \"outputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"out\"\n        }\n      ],\n      \"inputs\": [],\n      \"constant\": true,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 1263\n    }\n  ],\n  \"bytecode\": \"0x740100000000000000000000000000000000000000006020526f7fffffffffffffffffffffffffffffff6040527fffffffffffffffffffffffffffffffff8000000000000000000000000000000060605274012a05f1fffffffffffffffffffffffffdabf41c006080527ffffffffffffffffffffffffed5fa0e000000000000000000000000000000000060a052341561009857600080fd5b6000600155600160006301ffc9a760e05260c052604060c020556001600063d9b67a2660e05260c052604060c020553360025561405a56600035601c52740100000000000000000000000000000000000000006020526f7fffffffffffffffffffffffffffffff6040527fffffffffffffffffffffffffffffffff8000000000000000000000000000000060605274012a05f1fffffffffffffffffffffffffdabf41c006080527ffffffffffffffffffffffffed5fa0e000000000000000000000000000000000060a05263ae22c57d60005114156100d45734156100ac57600080fd5b60043560205181106100bd57600080fd5b50600435610140526101405160005260206000f350005b600015610313575b610580526101405261016052610180526101a0526101c0526101e05261020052610220526102405261026052610280526102a0526102c0526102e05261030052610320526103405261036052610380526103a0526103c0526103e05261040052610420526104405261046052610480526104a0526104c0526104e052610500526105205261054052610560526000610180516020826105c00101526020810190506102c0516020826105c0010152602081019050610400516020826105c0010152602081019050806105c0526105c090508051602082012090506105a0526106606000600a818352015b610660511515156102765760006105a05160208261068001015260208101905061018061066051600a81106101fa57600080fd5b60200201516020826106800101526020810190506102c061066051600a811061022257600080fd5b602002015160208261068001015260208101905061040061066051600a811061024a57600080fd5b6020020151602082610680010152602081019050806106805261068090508051602082012090506105a0525b5b81516001018083528114156101c6575b5050600061014051602082610760010152602081019050610160516020826107600101526020810190506105a0516020826107600101526020810190506105405160208261076001015260208101905061056051602082610760010152602081019050806107605261076090508051602082012090506107405261074051600052600051610580515650005b634a6f823360005114156105c457341561032c57600080fd5b600435602051811061033d57600080fd5b50602435602051811061034f57600080fd5b506000610120525b602061012051016101205261012061012051101561037457610357565b6000610120525b60206101205101610120526101206101205110156103985761037b565b6000610120525b60206101205101610120526101206101205110156103bc5761039f565b6373ad25716101405260043561016052602435610180526101a0604480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250506102e061018480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250506104206102c480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250506104043561056052610424356105805261058051610560516105405161052051610500516104e0516104c0516104a05161048051610460516104405161042051610400516103e0516103c0516103a05161038051610360516103405161032051610300516102e0516102c0516102a05161028051610260516102405161022051610200516101e0516101c0516101a0516101805161016051600658016100dc565b6105e0526105e05160005260206000f350005b600015610909575b610580526101405261016052610180526101a0526101c0526101e05261020052610220526102405261026052610280526102a0526102c0526102e05261030052610320526103405261036052610380526103a0526103c0526103e05261040052610420526104405261046052610480526104a0526104c0526104e052610500526105205261054052610560526000610140516020826105c0010152602081019050610160516020826105c0010152602081019050610180516020826105c00101526020810190506101a0516020826105c00101526020810190506101c0516020826105c00101526020810190506101e0516020826105c0010152602081019050610200516020826105c0010152602081019050610220516020826105c0010152602081019050610240516020826105c0010152602081019050610260516020826105c0010152602081019050610280516020826105c00101526020810190506102a0516020826105c00101526020810190506102c0516020826105c00101526020810190506102e0516020826105c0010152602081019050610300516020826105c0010152602081019050610320516020826105c0010152602081019050610340516020826105c0010152602081019050610360516020826105c0010152602081019050610380516020826105c00101526020810190506103a0516020826105c00101526020810190506103c0516020826105c00101526020810190506103e0516020826105c0010152602081019050610400516020826105c0010152602081019050610420516020826105c0010152602081019050610440516020826105c0010152602081019050610460516020826105c0010152602081019050610480516020826105c00101526020810190506104a0516020826105c00101526020810190506104c0516020826105c00101526020810190506104e0516020826105c0010152602081019050610500516020826105c0010152602081019050610520516020826105c0010152602081019050610540516020826105c0010152602081019050610560516020826105c0010152602081019050806105c0526105c090508051602082012090506105a0526105a051600052600051610580515650005b6000156109e1575b610220526101405261016052610180526101a0526101c0526101e0526102005260006101405160208261026001015260208101905061016051602082610260010152602081019050610180516020826102600101526020810190506101a0516020826102600101526020810190506101c0516020826102600101526020810190506101e05160208261026001015260208101905061020051602082610260010152602081019050806102605261026090508051602082012090506102405261024051600052600051610220515650005b6310660e866000511415610a905734156109fa57600080fd5b6004356020518110610a0b57600080fd5b506024356020518110610a1d57600080fd5b5063155960636101405260043561016052602435610180526044356101a0526064356101c0526084356101e05260a4356102005260c4356102205261022051610200516101e0516101c0516101a051610180516101605160065801610911565b610280526102805160005260206000f350005b600015610cf2575b6101805261014052610160526101a0526000610240525b6101a05160206001820306601f820103905061024051101515610ad157610aea565b610240516101c001526102405160200161024052610aaf565b60005060416101a0511815610b0757600060005260005161018051565b6101a0602060006020835103811315610b1f57600080fd5b046020026020018101519050610280526101a0602060206020835103811315610b4757600080fd5b0460200260200181015190506102a05260406001602082066103a0016101a0518284011115610b7557600080fd5b6041806103c0826020602088068803016101a001600060046018f1505081815280905090509050806020015160008251806020901315610bb457600080fd5b8091901215610bc257600080fd5b606051816020036101000a830480604051901315610bdf57600080fd5b8091901215610bed57600080fd5b9050905090506102c052601b6102c0511215610c30576102c0606051601b82510180604051901315610c1e57600080fd5b8091901215610c2c57600080fd5b8152505b610480601b8152601c81602001525060006104605261046061012060006002818352015b6101205160200261048001516102c0511415610c735760018352610c84565b5b8151600101808352811415610c54575b5050506104605160011415610ce257610140516104c0526102c0516000811215610cad57600080fd5b6104e05261028051610500526102a05161052052602060c060806104c060006001610bb8f15060c05160005260005161018051565b6000600052600051610180515650005b600015610db3575b6101605261014052610140517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff806000811215610d3e578060000360020a8204610d45565b8060020a82025b90509050604051811115610d5857600080fd5b61018052700100000000000000000000000000000000610d7757600080fd5b7001000000000000000000000000000000006101405106604051811115610d9d57600080fd5b6101a05261018051600052600051610160515650005b63f17535506000511415610de8573415610dcc57600080fd5b600060043560e05260c052604060c0205460005260206000f350005b63ac2a2e216000511415610e3d573415610e0157600080fd5b6004356020518110610e1257600080fd5b50600460043560e05260c052604060c02060243560e05260c052604060c0205460005260206000f350005b634026b7556000511415610e72573415610e5657600080fd5b600760043560e05260c052604060c0205460005260206000f350005b63f242432a6000511415611135573415610e8b57600080fd5b6004356020518110610e9c57600080fd5b506024356020518110610eae57600080fd5b5061012060843560040161014037610100608435600401351115610ed157600080fd5b600660043560e05260c052604060c0203360e05260c052604060c02054336004351417610efd57600080fd5b6308c379a06102805260206102a05260206102c0527f43616e6e6f74207472616e7366657220746f207a65726f20616464726573732e6102e0526102c050600060243518610f4c57608461029cfd5b6308c379a0610320526020610340526012610360527f4e6f7420656e6f75676820746f6b656e732e00000000000000000000000000006103805261036050606435600360043560e05260c052604060c02060443560e05260c052604060c020541015610fb957608461033cfd5b600360043560e05260c052604060c02060443560e05260c052604060c02060643581541015610fe757600080fd5b606435815403815550600360243560e05260c052604060c02060443560e05260c052604060c0208054606435825401101561102157600080fd5b6064358154018155506044356103c0526064356103e052602435600435337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6260406103c0a460006024353b1115611133576024353b61107f57600080fd5b602435301861108d57600080fd5b60206106406101c460a063f23a6e6161042052336104405260043561046052604435610480526064356104a052806104c052610140808051602001808461044001828460006004600a8704601201f16110e557600080fd5b50508051820160206001820306601f820103905060200191505061043c905060006024355af161111457600080fd5b600050610640516104005263f23a6e61610400511461113257600080fd5b5b005b63cf36e535600051141561163c57341561114e57600080fd5b600435602051811061115f57600080fd5b50602435602051811061117157600080fd5b506000610120525b602061012051016101205261012061012051101561119657611179565b6000610120525b60206101205101610120526101206101205110156111ba5761119d565b6101206102c435600401610140376101006102c4356004013511156111de57600080fd5b600660043560e05260c052604060c0203360e05260c052604060c0205433600435141761120a57600080fd5b6308c379a06102805260206102a05260206102c0527f43616e6e6f74207472616e7366657220746f207a65726f20616464726573732e6102e0526102c05060006024351861125957608461029cfd5b6103206000600a818352015b604461032051600a811061127857600080fd5b60200201356103405261018461032051600a811061129557600080fd5b6020020135600360043560e05260c052604060c0206103405160e05260c052604060c0205410156112c557600080fd5b5b8151600101808352811415611265575b505060443561036052606435610380526084356103a05260a4356103c05260c4356103e05260e435610400526101043561042052610124356104405261014435610460526101643561048052610184356104a0526101a4356104c0526101c4356104e0526101e435610500526102043561052052610224356105405261024435610560526102643561058052610284356105a0526102a4356105c052602435600435337f514c24e4790d7c31a095a1688a73a01f28d936a9a85d806ba95970d8ee88efa8610280610360a46105e06000600a818352015b60446105e051600a81106113c057600080fd5b602002013561060052600360043560e05260c052604060c0206106005160e05260c052604060c0206101846105e051600a81106113fc57600080fd5b60200201358154101561140e57600080fd5b6101846105e051600a811061142257600080fd5b6020020135815403815550600360243560e05260c052604060c0206106005160e05260c052604060c02080546101846105e051600a811061146257600080fd5b6020020135825401101561147557600080fd5b6101846105e051600a811061148957600080fd5b60200201358154018155505b81516001018083528114156113ad575b505060006024353b111561163a576024353b6114c057600080fd5b60243530186114ce57600080fd5b6020610aa06104046102e063a3bfc206610640523361066052600435610680526106a0604480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250506107e061018480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250508061092052610140808051602001808461066001828460006004600a8704601201f16115ec57600080fd5b50508051820160206001820306601f820103905060200191505061065c905060006024355af161161b57600080fd5b600050610aa0516106205263e324a00d610620511461163957600080fd5b5b005b62fdd58e600051141561169057341561165457600080fd5b600435602051811061166557600080fd5b50600360043560e05260c052604060c02060243560e05260c052604060c0205460005260206000f350005b63fbe31aea60005114156117935734156116a957600080fd5b6000610120525b610120516004013560205181106116c657600080fd5b5060206101205101610120526101206101205110156116e4576116b0565b6000610120525b6020610120510161012052610120610120511015611708576116eb565b6102806000600a818352015b6003600461028051600a811061172957600080fd5b602002013560e05260c052604060c02061014461028051600a811061174d57600080fd5b602002013560e05260c052604060c0205461014061028051600a811061177257600080fd5b60200201525b8151600101808352811415611714575b5050610140610140f3005b63a22cb46560005114156118235734156117ac57600080fd5b60043560205181106117bd57600080fd5b50602435600281106117ce57600080fd5b5060243560063360e05260c052604060c02060043560e05260c052604060c0205560243561014052600435337f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c316020610140a3005b63e985e9c5600051141561188a57341561183c57600080fd5b600435602051811061184d57600080fd5b50602435602051811061185f57600080fd5b50600660043560e05260c052604060c02060243560e05260c052604060c0205460005260206000f350005b63a70b070f6000511415611af85734156118a357600080fd5b60043560205181106118b457600080fd5b50610120604435600401610140376101006044356004013511156118d757600080fd5b6000600435186118e657600080fd5b6308c379a06102805260206102a052601b6102c0527f4f776e6572206f6e6c792063616e20637265617465206974656d2e00000000006102e0526102c050336002541461193457608461029cfd5b6000600360043560e05260c052604060c02060243560e05260c052604060c02055600180546001825401101561196957600080fd5b60018154018155506001600760243560e05260c052604060c0205561014080600560243560e05260c052604060c02060c052602060c020602082510161012060006009818352015b826101205160200211156119c4576119e6565b61012051602002850151610120518501555b81516001018083528114156119b1575b50505050505060206103405261034051610380526101408051602001806103405161038001828460006004600a8704601201f1611a2257600080fd5b5050610320610340516103800151610440818352015b610440610320511115611a4a57611a6b565b600061032051610340516103a00101535b8151600101808352811415611a38575b5050602061034051610380015160206001820306601f8201039050610340510101610340526024357f6bb7ff708619ba0610cba295a58592e0451dee2622938c8755667688daf3529b61034051610380a26024356103a05260006103c0526004356000337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6260406103a0a4005b6319a35d7c6000511415611d43573415611b1157600080fd5b6004356020518110611b2257600080fd5b506000610120525b6020610120510161012052610120610120511015611b4757611b2a565b600060043518611b5657600080fd5b6308c379a061014052602061016052601c610180527f4f776e6572206f6e6c792063616e20637265617465206974656d732e000000006101a052610180503360025414611ba457608461015cfd5b6101e06000600a818352015b60246101e051600a8110611bc357600080fd5b6020020135610200526000600360043560e05260c052604060c0206102005160e05260c052604060c020556001805460018254011015611c0257600080fd5b6001815401815550600160076102005160e05260c052604060c020555b8151600101808352811415611bb0575b5050610220600081526000816020015260008160400152600081606001526000816080015260008160a0015260008160c0015260008160e00152600081610100015260008161012001525060243561036052604435610380526064356103a0526084356103c05260a4356103e05260c4356104005260e43561042052610104356104405261012435610460526101443561048052610220516104a052610240516104c052610260516104e05261028051610500526102a051610520526102c051610540526102e051610560526103005161058052610320516105a052610340516105c0526004356000337f514c24e4790d7c31a095a1688a73a01f28d936a9a85d806ba95970d8ee88efa8610280610360a4005b63156e29f66000511415611d8157600061028052610280805160200180610140828460006004600a8704601201f1611d7a57600080fd5b5050611dce565b63731133e96000511415611dc65761012060643560040161014037610100606435600401351115611db157600080fd5b61014060643560040161014037600050611dce565b60001561208a575b3415611dd957600080fd5b6004356020518110611dea57600080fd5b50600060043518611dfa57600080fd5b6308c379a06102c05260206102e052601a610300527f4f776e6572206f6e6c792063616e206d696e74206974656d732e00000000000061032052610300503360025414611e485760846102dcfd5b610140610380525b61038051516020610380510161038052610380610380511015611e7257611e50565b6320171bef6103a0526024356103c0526103c05160065801610cfa565b61042052610360610380525b6103805152602061038051036103805261014061038051101515611ebe57611e9b565b6104205161036052600261036051146001610360511417611ede57600080fd5b6001610360511415611f5f576308c379a0610440526020610460526028610480527f43616e6e6f74206d696e74204e46542077697468205f737570706c79206d6f726104a0527f65207468616e20310000000000000000000000000000000000000000000000006104c05261048050600160443514611f5e5760a461045cfd5b5b604435600360043560e05260c052604060c02060243560e05260c052604060c0205560243561050052604435610520526004356000337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f626040610500a460006004353b1115612088576004353b611fd557600080fd5b6004353018611fe357600080fd5b60206107806101c460a063f23a6e6161056052336105805260006105a0526024356105c0526044356105e0528061060052610140808051602001808461058001828460006004600a8704601201f161203a57600080fd5b50508051820160206001820306601f820103905060200191505061057c905060006004355af161206957600080fd5b600050610780516105405263f23a6e61610540511461208757600080fd5b5b005b63c671854d60005114156120c857600061028052610280805160200180610140828460006004600a8704601201f16120c157600080fd5b5050612118565b63b07e58756000511415612110576101206102a435600401610140376101006102a4356004013511156120fa57600080fd5b6101406102a43560040161014037600050612118565b6000156124f6575b341561212357600080fd5b600435602051811061213457600080fd5b506000610120525b60206101205101610120526101206101205110156121595761213c565b6000610120525b602061012051016101205261012061012051101561217d57612160565b60006004351861218c57600080fd5b6308c379a06102c05260206102e052601a610300527f4f776e6572206f6e6c792063616e206d696e74206974656d732e000000000000610320526103005033600254146121da5760846102dcfd5b6103606000600a818352015b602461036051600a81106121f957600080fd5b6020020135610380526101406103c0525b6103c0515160206103c051016103c0526103c06103c051101561222c5761220a565b6320171bef6103e05261038051610400526104005160065801610cfa565b610460526103a06103c0525b6103c0515260206103c051036103c0526101406103c05110151561227957612256565b610460516103a05260026103a0511460016103a051141761229957600080fd5b60016103a05114156122cb57600161016461036051600a81106122bb57600080fd5b6020020135146122ca57600080fd5b5b61016461036051600a81106122df57600080fd5b6020020135600360043560e05260c052604060c0206103805160e05260c052604060c020555b81516001018083528114156121e6575b5050602435610480526044356104a0526064356104c0526084356104e05260a4356105005260c4356105205260e4356105405261010435610560526101243561058052610144356105a052610164356105c052610184356105e0526101a435610600526101c435610620526101e4356106405261020435610660526102243561068052610244356106a052610264356106c052610284356106e0526004356000337f514c24e4790d7c31a095a1688a73a01f28d936a9a85d806ba95970d8ee88efa8610280610480a46107006000600a818352015b60006004353b11156124e1576004353b61240357600080fd5b600435301861241157600080fd5b60206109606101c460a063f23a6e61610740523361076052600061078052602461070051600a811061244257600080fd5b60200201356107a05261016461070051600a811061245f57600080fd5b60200201356107c052806107e052610140808051602001808461076001828460006004600a8704601201f161249357600080fd5b50508051820160206001820306601f820103905060200191505061075c905060006004355af16124c257600080fd5b600050610960516107205263f23a6e6161072051146124e057600080fd5b5b5b81516001018083528114156123ea575b5050005b63b390c0ab60005114156125ea57341561250f57600080fd5b6308c379a061014052602061016052601a610180527f4e6f7420656e6f75676820746f6b656e7320746f206275726e2e0000000000006101a0526101805060243560033360e05260c052604060c02060043560e05260c052604060c02054101561257a57608461015cfd5b60033360e05260c052604060c02060043560e05260c052604060c020602435815410156125a657600080fd5b6024358154038155506004356101e05260243561020052600033337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6260406101e0a4005b63b59afe52600051141561282b57341561260357600080fd5b6000610120525b60206101205101610120526101206101205110156126275761260a565b6000610120525b602061012051016101205261012061012051101561264b5761262e565b6101406000600a818352015b600461014051600a811061266a57600080fd5b60200201356101605261014461014051600a811061268757600080fd5b602002013560033360e05260c052604060c0206101605160e05260c052604060c0205410156126b557600080fd5b5b8151600101808352811415612657575b50506101806000600a818352015b600461018051600a81106126e757600080fd5b60200201356101a05260033360e05260c052604060c0206101a05160e05260c052604060c02061014461018051600a811061272157600080fd5b60200201358154101561273357600080fd5b61014461018051600a811061274757600080fd5b60200201358154038155505b81516001018083528114156126d4575b50506004356101c0526024356101e05260443561020052606435610220526084356102405260a4356102605260c4356102805260e4356102a052610104356102c052610124356102e0526101443561030052610164356103205261018435610340526101a435610360526101c435610380526101e4356103a052610204356103c052610224356103e05261024435610400526102643561042052600033337f514c24e4790d7c31a095a1688a73a01f28d936a9a85d806ba95970d8ee88efa86102806101c0a4005b63f2526ada6000511415612869576000610320526103208051602001806101e0828460006004600a8704601201f161286257600080fd5b50506128b9565b63a835c36960005114156128b157610120610464356004016101e0376101006104643560040135111561289b57600080fd5b610140610464356004016101e0376000506128b9565b600015613725575b60043560205181106128ca57600080fd5b5060243560205181106128dc57600080fd5b506000610120525b6020610120510161012052610120610120511015612901576128e4565b6000610120525b602061012051016101205261012061012051101561292557612908565b6000610120525b60206101205101610120526101206101205110156129495761292c565b6061610444356004016101403760416104443560040135111561296b57600080fd5b6308c379a061036052602061038052602c6103a0527f5f66726f6d206d757374206265207468652073656e646572206f7220617070726103c0527f6f766564206164647265737300000000000000000000000000000000000000006103e0526103a050600660043560e05260c052604060c0203360e05260c052604060c020543360043514176129fc5760a461037cfd5b6308c379a0610420526020610440526025610460527f44657374696e6174696f6e2061646472657373206d757374206265206e6f6e2d610480527f7a65726f2e0000000000000000000000000000000000000000000000000000006104a05261046050600060243518612a705760a461043cfd5b6308c379a06104e0526020610500526015610520527f4e6f6e6365206d75737420626520756e757365642e00000000000000000000006105405261052050600460043560e05260c052604060c0206104243560e05260c052604060c0205415612ada5760846104fcfd5b6308c379a06105805260206105a05260256105c0527f53656e64657220686173206e6f742070726f766964656420656e6f75676820656105e0527f746865722e000000000000000000000000000000000000000000000000000000610600526105c050346104043514612b4e5760a461059cfd5b6106406000600a818352015b604461064051600a8110612b6d57600080fd5b602002013561066052600061018461064051600a8110612b8c57600080fd5b60200201351115612c03576102c461064051600a8110612bab57600080fd5b602002013515612bba57600080fd5b61018461064051600a8110612bce57600080fd5b6020020135600360043560e05260c052604060c0206106605160e05260c052604060c020541015612bfe57600080fd5b612c6b565b61018461064051600a8110612c1757600080fd5b602002013515612c2657600080fd5b6102c461064051600a8110612c3a57600080fd5b6020020135600360243560e05260c052604060c0206106605160e05260c052604060c020541015612c6a57600080fd5b5b5b8151600101808352811415612b5a575b50506101406106a0525b6106a0515160206106a051016106a0526106a06106a0511015612ca857612c86565b6373ad25716106c0526004356106e05260243561070052610720604480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e00152806101000135826101000152806101200135826101200152505061086061018480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250506109a06102c480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e00152806101000135826101000152806101200135826101200152505061040435610ae05261042435610b0052610b0051610ae051610ac051610aa051610a8051610a6051610a4051610a2051610a00516109e0516109c0516109a05161098051610960516109405161092051610900516108e0516108c0516108a05161088051610860516108405161082051610800516107e0516107c0516107a05161078051610760516107405161072051610700516106e051600658016100dc565b610b60526106806106a0525b6106a0515260206106a051036106a0526101406106a051101515612ecc57612ea9565b610b605161068052610140610ba0525b610ba051516020610ba05101610ba052610ba0610ba0511015612efe57612edc565b6040636f868168610bc05261068051610be05280610c00526101408080516020018084610be001828460006004600a8704601201f1612f3c57600080fd5b50508051820160206001820306601f820103905060200191505050610c005180610be00180518060206001820306601f82010390508201610ce0525050505b610c20610ce0511015612f8d57612fa2565b610ce051516020610ce05103610ce052612f7b565b610c0051610be05160065801610a98565b610d0052610b80610ba0525b610ba051526020610ba05103610ba052610140610ba051101515612fe257612fbf565b610d0051610b80526308c379a0610d20526020610d40526020610d60527f5369676e657220646f6573206e6f74206d61746368207369676e61747572652e610d8052610d6050602435610b80511461303b576084610d3cfd5b600160043360e05260c052604060c0206104243560e05260c052604060c02055610dc06000600a818352015b6044610dc051600a811061307a57600080fd5b6020020135610de0526000610184610dc051600a811061309957600080fd5b6020020135111561317457600360043560e05260c052604060c020610de05160e05260c052604060c020610184610dc051600a81106130d757600080fd5b6020020135815410156130e957600080fd5b610184610dc051600a81106130fd57600080fd5b6020020135815403815550600360243560e05260c052604060c020610de05160e05260c052604060c0208054610184610dc051600a811061313d57600080fd5b6020020135825401101561315057600080fd5b610184610dc051600a811061316457600080fd5b6020020135815401815550613240565b600360043560e05260c052604060c020610de05160e05260c052604060c02080546102c4610dc051600a81106131a957600080fd5b602002013582540110156131bc57600080fd5b6102c4610dc051600a81106131d057600080fd5b6020020135815401815550600360243560e05260c052604060c020610de05160e05260c052604060c0206102c4610dc051600a811061320e57600080fd5b60200201358154101561322057600080fd5b6102c4610dc051600a811061323457600080fd5b60200201358154038155505b5b8151600101808352811415613067575b50506000600060006000346024356000f161326b57600080fd5b604435610e0052606435610e2052608435610e405260a435610e605260c435610e805260e435610ea05261010435610ec05261012435610ee05261014435610f005261016435610f205261018435610f40526101a435610f60526101c435610f80526101e435610fa05261020435610fc05261022435610fe0526102443561100052610264356110205261028435611040526102a43561106052602435600435337f514c24e4790d7c31a095a1688a73a01f28d936a9a85d806ba95970d8ee88efa8610280610e00a4604435611080526064356110a0526084356110c05260a4356110e05260c4356111005260e43561112052610104356111405261012435611160526101443561118052610164356111a0526102c4356111c0526102e4356111e052610304356112005261032435611220526103443561124052610364356112605261038435611280526103a4356112a0526103c4356112c0526103e4356112e052600435602435337f514c24e4790d7c31a095a1688a73a01f28d936a9a85d806ba95970d8ee88efa8610280611080a460006024353b1115613590576024353b61341657600080fd5b602435301861342457600080fd5b60206117806104046102e063a3bfc20661132052336113405260243561136052611380604480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250506114c061018480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e00152806101000135826101000152806101200135826101200152505080611600526101e0808051602001808461134001828460006004600a8704601201f161354257600080fd5b50508051820160206001820306601f820103905060200191505061133c905060006024355af161357157600080fd5b6000506117805161130052630c97e564611300511461358f57600080fd5b5b60006004353b1115613723576004353b6135a957600080fd5b60043530186135b757600080fd5b6020611c206104046102e063a3bfc2066117c052336117e05260043561180052611820604480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250506119606102c480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e00152806101000135826101000152806101200135826101200152505080611aa0526101e080805160200180846117e001828460006004600a8704601201f16136d557600080fd5b50508051820160206001820306601f82010390506020019150506117dc905060006004355af161370457600080fd5b600050611c20516117a052630c97e5646117a0511461372257600080fd5b5b005b636e8205b26000511415613763576000610320526103208051602001806101e0828460006004600a8704601201f161375c57600080fd5b50506137b3565b63183f5ec560005114156137ab57610120610104356004016101e0376101006101043560040135111561379557600080fd5b610140610104356004016101e0376000506137b3565b600015613f5d575b60043560205181106137c457600080fd5b5060243560205181106137d657600080fd5b50606160e43560040161014037604160e4356004013511156137f757600080fd5b600660043560e05260c052604060c0203360e05260c052604060c0205433600435141761382357600080fd5b6308c379a06103605260206103805260256103a0527f44657374696e6174696f6e2061646472657373206d757374206265206e6f6e2d6103c0527f7a65726f2e0000000000000000000000000000000000000000000000000000006103e0526103a0506000602435186138975760a461037cfd5b6308c379a0610420526020610440526015610460527f4e6f6e6365206d75737420626520756e757365642e00000000000000000000006104805261046050600460043560e05260c052604060c02060c43560e05260c052604060c020541561390057608461043cfd5b6308c379a06104c05260206104e0526025610500527f53656e64657220686173206e6f742070726f766964656420656e6f7567682065610520527f746865722e00000000000000000000000000000000000000000000000000000061054052610500503460a435146139735760a46104dcfd5b600060643511156139bd576084351561398b57600080fd5b606435600360043560e05260c052604060c02060443560e05260c052604060c0205410156139b857600080fd5b6139f8565b606435156139ca57600080fd5b608435600360243560e05260c052604060c02060443560e05260c052604060c0205410156139f757600080fd5b5b6101406105a0525b6105a0515160206105a051016105a0526105a06105a0511015613a2257613a00565b63155960636105c0526004356105e0526024356106005260443561062052606435610640526084356106605260a4356106805260c4356106a0526106a05161068051610660516106405161062051610600516105e05160065801610911565b610700526105806105a0525b6105a0515260206105a051036105a0526101406105a051101515613ab057613a8d565b6107005161058052610140610740525b61074051516020610740510161074052610740610740511015613ae257613ac0565b6040636f868168610760526105805161078052806107a052610140808051602001808461078001828460006004600a8704601201f1613b2057600080fd5b50508051820160206001820306601f8201039050602001915050506107a051806107800180518060206001820306601f82010390508201610880525050505b6107c0610880511015613b7157613b86565b61088051516020610880510361088052613b5f565b6107a0516107805160065801610a98565b6108a052610720610740525b6107405152602061074051036107405261014061074051101515613bc657613ba3565b6108a051610720526308c379a06108c05260206108e0526020610900527f5369676e657220646f6573206e6f74206d61746368207369676e61747572652e61092052610900506024356107205114613c1f5760846108dcfd5b600160043360e05260c052604060c02060c43560e05260c052604060c0205560006064351115613cbf57600360043560e05260c052604060c02060443560e05260c052604060c02060643581541015613c7757600080fd5b606435815403815550600360243560e05260c052604060c02060443560e05260c052604060c02080546064358254011015613cb157600080fd5b606435815401815550613d31565b600360043560e05260c052604060c02060443560e05260c052604060c02080546084358254011015613cf057600080fd5b608435815401815550600360243560e05260c052604060c02060443560e05260c052604060c02060843581541015613d2757600080fd5b6084358154038155505b6000600060006000346024356000f1613d4957600080fd5b6044356109605260643561098052602435600435337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f626040610960a46044356109a0526084356109c052600435602435337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6260406109a0a460006024353b1115613e8e576024353b613dda57600080fd5b6024353018613de857600080fd5b6020610c206101c460a063f23a6e61610a005233610a2052602435610a4052604435610a6052606435610a805280610aa0526101e08080516020018084610a2001828460006004600a8704601201f1613e4057600080fd5b50508051820160206001820306601f8201039050602001915050610a1c905060006024355af1613e6f57600080fd5b600050610c20516109e052630c97e5646109e05114613e8d57600080fd5b5b60006004353b1115613f5b576004353b613ea757600080fd5b6004353018613eb557600080fd5b6020610e806101c460a063f23a6e61610c605233610c8052600435610ca052604435610cc052608435610ce05280610d00526101e08080516020018084610c8001828460006004600a8704601201f1613f0d57600080fd5b50508051820160206001820306601f8201039050602001915050610c7c905060006004355af1613f3c57600080fd5b600050610e8051610c4052630c97e564610c405114613f5a57600080fd5b5b005b638da5cb5b6000511415613f84573415613f7657600080fd5b60025460005260206000f350005b60006000fd5b6100d061405a036100d06000396100d061405a036000f3\",\n  \"deployedBytecode\": \"0x600035601c52740100000000000000000000000000000000000000006020526f7fffffffffffffffffffffffffffffff6040527fffffffffffffffffffffffffffffffff8000000000000000000000000000000060605274012a05f1fffffffffffffffffffffffffdabf41c006080527ffffffffffffffffffffffffed5fa0e000000000000000000000000000000000060a05263ae22c57d60005114156100d45734156100ac57600080fd5b60043560205181106100bd57600080fd5b50600435610140526101405160005260206000f350005b600015610313575b610580526101405261016052610180526101a0526101c0526101e05261020052610220526102405261026052610280526102a0526102c0526102e05261030052610320526103405261036052610380526103a0526103c0526103e05261040052610420526104405261046052610480526104a0526104c0526104e052610500526105205261054052610560526000610180516020826105c00101526020810190506102c0516020826105c0010152602081019050610400516020826105c0010152602081019050806105c0526105c090508051602082012090506105a0526106606000600a818352015b610660511515156102765760006105a05160208261068001015260208101905061018061066051600a81106101fa57600080fd5b60200201516020826106800101526020810190506102c061066051600a811061022257600080fd5b602002015160208261068001015260208101905061040061066051600a811061024a57600080fd5b6020020151602082610680010152602081019050806106805261068090508051602082012090506105a0525b5b81516001018083528114156101c6575b5050600061014051602082610760010152602081019050610160516020826107600101526020810190506105a0516020826107600101526020810190506105405160208261076001015260208101905061056051602082610760010152602081019050806107605261076090508051602082012090506107405261074051600052600051610580515650005b634a6f823360005114156105c457341561032c57600080fd5b600435602051811061033d57600080fd5b50602435602051811061034f57600080fd5b506000610120525b602061012051016101205261012061012051101561037457610357565b6000610120525b60206101205101610120526101206101205110156103985761037b565b6000610120525b60206101205101610120526101206101205110156103bc5761039f565b6373ad25716101405260043561016052602435610180526101a0604480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250506102e061018480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250506104206102c480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250506104043561056052610424356105805261058051610560516105405161052051610500516104e0516104c0516104a05161048051610460516104405161042051610400516103e0516103c0516103a05161038051610360516103405161032051610300516102e0516102c0516102a05161028051610260516102405161022051610200516101e0516101c0516101a0516101805161016051600658016100dc565b6105e0526105e05160005260206000f350005b600015610909575b610580526101405261016052610180526101a0526101c0526101e05261020052610220526102405261026052610280526102a0526102c0526102e05261030052610320526103405261036052610380526103a0526103c0526103e05261040052610420526104405261046052610480526104a0526104c0526104e052610500526105205261054052610560526000610140516020826105c0010152602081019050610160516020826105c0010152602081019050610180516020826105c00101526020810190506101a0516020826105c00101526020810190506101c0516020826105c00101526020810190506101e0516020826105c0010152602081019050610200516020826105c0010152602081019050610220516020826105c0010152602081019050610240516020826105c0010152602081019050610260516020826105c0010152602081019050610280516020826105c00101526020810190506102a0516020826105c00101526020810190506102c0516020826105c00101526020810190506102e0516020826105c0010152602081019050610300516020826105c0010152602081019050610320516020826105c0010152602081019050610340516020826105c0010152602081019050610360516020826105c0010152602081019050610380516020826105c00101526020810190506103a0516020826105c00101526020810190506103c0516020826105c00101526020810190506103e0516020826105c0010152602081019050610400516020826105c0010152602081019050610420516020826105c0010152602081019050610440516020826105c0010152602081019050610460516020826105c0010152602081019050610480516020826105c00101526020810190506104a0516020826105c00101526020810190506104c0516020826105c00101526020810190506104e0516020826105c0010152602081019050610500516020826105c0010152602081019050610520516020826105c0010152602081019050610540516020826105c0010152602081019050610560516020826105c0010152602081019050806105c0526105c090508051602082012090506105a0526105a051600052600051610580515650005b6000156109e1575b610220526101405261016052610180526101a0526101c0526101e0526102005260006101405160208261026001015260208101905061016051602082610260010152602081019050610180516020826102600101526020810190506101a0516020826102600101526020810190506101c0516020826102600101526020810190506101e05160208261026001015260208101905061020051602082610260010152602081019050806102605261026090508051602082012090506102405261024051600052600051610220515650005b6310660e866000511415610a905734156109fa57600080fd5b6004356020518110610a0b57600080fd5b506024356020518110610a1d57600080fd5b5063155960636101405260043561016052602435610180526044356101a0526064356101c0526084356101e05260a4356102005260c4356102205261022051610200516101e0516101c0516101a051610180516101605160065801610911565b610280526102805160005260206000f350005b600015610cf2575b6101805261014052610160526101a0526000610240525b6101a05160206001820306601f820103905061024051101515610ad157610aea565b610240516101c001526102405160200161024052610aaf565b60005060416101a0511815610b0757600060005260005161018051565b6101a0602060006020835103811315610b1f57600080fd5b046020026020018101519050610280526101a0602060206020835103811315610b4757600080fd5b0460200260200181015190506102a05260406001602082066103a0016101a0518284011115610b7557600080fd5b6041806103c0826020602088068803016101a001600060046018f1505081815280905090509050806020015160008251806020901315610bb457600080fd5b8091901215610bc257600080fd5b606051816020036101000a830480604051901315610bdf57600080fd5b8091901215610bed57600080fd5b9050905090506102c052601b6102c0511215610c30576102c0606051601b82510180604051901315610c1e57600080fd5b8091901215610c2c57600080fd5b8152505b610480601b8152601c81602001525060006104605261046061012060006002818352015b6101205160200261048001516102c0511415610c735760018352610c84565b5b8151600101808352811415610c54575b5050506104605160011415610ce257610140516104c0526102c0516000811215610cad57600080fd5b6104e05261028051610500526102a05161052052602060c060806104c060006001610bb8f15060c05160005260005161018051565b6000600052600051610180515650005b600015610db3575b6101605261014052610140517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff806000811215610d3e578060000360020a8204610d45565b8060020a82025b90509050604051811115610d5857600080fd5b61018052700100000000000000000000000000000000610d7757600080fd5b7001000000000000000000000000000000006101405106604051811115610d9d57600080fd5b6101a05261018051600052600051610160515650005b63f17535506000511415610de8573415610dcc57600080fd5b600060043560e05260c052604060c0205460005260206000f350005b63ac2a2e216000511415610e3d573415610e0157600080fd5b6004356020518110610e1257600080fd5b50600460043560e05260c052604060c02060243560e05260c052604060c0205460005260206000f350005b634026b7556000511415610e72573415610e5657600080fd5b600760043560e05260c052604060c0205460005260206000f350005b63f242432a6000511415611135573415610e8b57600080fd5b6004356020518110610e9c57600080fd5b506024356020518110610eae57600080fd5b5061012060843560040161014037610100608435600401351115610ed157600080fd5b600660043560e05260c052604060c0203360e05260c052604060c02054336004351417610efd57600080fd5b6308c379a06102805260206102a05260206102c0527f43616e6e6f74207472616e7366657220746f207a65726f20616464726573732e6102e0526102c050600060243518610f4c57608461029cfd5b6308c379a0610320526020610340526012610360527f4e6f7420656e6f75676820746f6b656e732e00000000000000000000000000006103805261036050606435600360043560e05260c052604060c02060443560e05260c052604060c020541015610fb957608461033cfd5b600360043560e05260c052604060c02060443560e05260c052604060c02060643581541015610fe757600080fd5b606435815403815550600360243560e05260c052604060c02060443560e05260c052604060c0208054606435825401101561102157600080fd5b6064358154018155506044356103c0526064356103e052602435600435337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6260406103c0a460006024353b1115611133576024353b61107f57600080fd5b602435301861108d57600080fd5b60206106406101c460a063f23a6e6161042052336104405260043561046052604435610480526064356104a052806104c052610140808051602001808461044001828460006004600a8704601201f16110e557600080fd5b50508051820160206001820306601f820103905060200191505061043c905060006024355af161111457600080fd5b600050610640516104005263f23a6e61610400511461113257600080fd5b5b005b63cf36e535600051141561163c57341561114e57600080fd5b600435602051811061115f57600080fd5b50602435602051811061117157600080fd5b506000610120525b602061012051016101205261012061012051101561119657611179565b6000610120525b60206101205101610120526101206101205110156111ba5761119d565b6101206102c435600401610140376101006102c4356004013511156111de57600080fd5b600660043560e05260c052604060c0203360e05260c052604060c0205433600435141761120a57600080fd5b6308c379a06102805260206102a05260206102c0527f43616e6e6f74207472616e7366657220746f207a65726f20616464726573732e6102e0526102c05060006024351861125957608461029cfd5b6103206000600a818352015b604461032051600a811061127857600080fd5b60200201356103405261018461032051600a811061129557600080fd5b6020020135600360043560e05260c052604060c0206103405160e05260c052604060c0205410156112c557600080fd5b5b8151600101808352811415611265575b505060443561036052606435610380526084356103a05260a4356103c05260c4356103e05260e435610400526101043561042052610124356104405261014435610460526101643561048052610184356104a0526101a4356104c0526101c4356104e0526101e435610500526102043561052052610224356105405261024435610560526102643561058052610284356105a0526102a4356105c052602435600435337f514c24e4790d7c31a095a1688a73a01f28d936a9a85d806ba95970d8ee88efa8610280610360a46105e06000600a818352015b60446105e051600a81106113c057600080fd5b602002013561060052600360043560e05260c052604060c0206106005160e05260c052604060c0206101846105e051600a81106113fc57600080fd5b60200201358154101561140e57600080fd5b6101846105e051600a811061142257600080fd5b6020020135815403815550600360243560e05260c052604060c0206106005160e05260c052604060c02080546101846105e051600a811061146257600080fd5b6020020135825401101561147557600080fd5b6101846105e051600a811061148957600080fd5b60200201358154018155505b81516001018083528114156113ad575b505060006024353b111561163a576024353b6114c057600080fd5b60243530186114ce57600080fd5b6020610aa06104046102e063a3bfc206610640523361066052600435610680526106a0604480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250506107e061018480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250508061092052610140808051602001808461066001828460006004600a8704601201f16115ec57600080fd5b50508051820160206001820306601f820103905060200191505061065c905060006024355af161161b57600080fd5b600050610aa0516106205263e324a00d610620511461163957600080fd5b5b005b62fdd58e600051141561169057341561165457600080fd5b600435602051811061166557600080fd5b50600360043560e05260c052604060c02060243560e05260c052604060c0205460005260206000f350005b63fbe31aea60005114156117935734156116a957600080fd5b6000610120525b610120516004013560205181106116c657600080fd5b5060206101205101610120526101206101205110156116e4576116b0565b6000610120525b6020610120510161012052610120610120511015611708576116eb565b6102806000600a818352015b6003600461028051600a811061172957600080fd5b602002013560e05260c052604060c02061014461028051600a811061174d57600080fd5b602002013560e05260c052604060c0205461014061028051600a811061177257600080fd5b60200201525b8151600101808352811415611714575b5050610140610140f3005b63a22cb46560005114156118235734156117ac57600080fd5b60043560205181106117bd57600080fd5b50602435600281106117ce57600080fd5b5060243560063360e05260c052604060c02060043560e05260c052604060c0205560243561014052600435337f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c316020610140a3005b63e985e9c5600051141561188a57341561183c57600080fd5b600435602051811061184d57600080fd5b50602435602051811061185f57600080fd5b50600660043560e05260c052604060c02060243560e05260c052604060c0205460005260206000f350005b63a70b070f6000511415611af85734156118a357600080fd5b60043560205181106118b457600080fd5b50610120604435600401610140376101006044356004013511156118d757600080fd5b6000600435186118e657600080fd5b6308c379a06102805260206102a052601b6102c0527f4f776e6572206f6e6c792063616e20637265617465206974656d2e00000000006102e0526102c050336002541461193457608461029cfd5b6000600360043560e05260c052604060c02060243560e05260c052604060c02055600180546001825401101561196957600080fd5b60018154018155506001600760243560e05260c052604060c0205561014080600560243560e05260c052604060c02060c052602060c020602082510161012060006009818352015b826101205160200211156119c4576119e6565b61012051602002850151610120518501555b81516001018083528114156119b1575b50505050505060206103405261034051610380526101408051602001806103405161038001828460006004600a8704601201f1611a2257600080fd5b5050610320610340516103800151610440818352015b610440610320511115611a4a57611a6b565b600061032051610340516103a00101535b8151600101808352811415611a38575b5050602061034051610380015160206001820306601f8201039050610340510101610340526024357f6bb7ff708619ba0610cba295a58592e0451dee2622938c8755667688daf3529b61034051610380a26024356103a05260006103c0526004356000337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6260406103a0a4005b6319a35d7c6000511415611d43573415611b1157600080fd5b6004356020518110611b2257600080fd5b506000610120525b6020610120510161012052610120610120511015611b4757611b2a565b600060043518611b5657600080fd5b6308c379a061014052602061016052601c610180527f4f776e6572206f6e6c792063616e20637265617465206974656d732e000000006101a052610180503360025414611ba457608461015cfd5b6101e06000600a818352015b60246101e051600a8110611bc357600080fd5b6020020135610200526000600360043560e05260c052604060c0206102005160e05260c052604060c020556001805460018254011015611c0257600080fd5b6001815401815550600160076102005160e05260c052604060c020555b8151600101808352811415611bb0575b5050610220600081526000816020015260008160400152600081606001526000816080015260008160a0015260008160c0015260008160e00152600081610100015260008161012001525060243561036052604435610380526064356103a0526084356103c05260a4356103e05260c4356104005260e43561042052610104356104405261012435610460526101443561048052610220516104a052610240516104c052610260516104e05261028051610500526102a051610520526102c051610540526102e051610560526103005161058052610320516105a052610340516105c0526004356000337f514c24e4790d7c31a095a1688a73a01f28d936a9a85d806ba95970d8ee88efa8610280610360a4005b63156e29f66000511415611d8157600061028052610280805160200180610140828460006004600a8704601201f1611d7a57600080fd5b5050611dce565b63731133e96000511415611dc65761012060643560040161014037610100606435600401351115611db157600080fd5b61014060643560040161014037600050611dce565b60001561208a575b3415611dd957600080fd5b6004356020518110611dea57600080fd5b50600060043518611dfa57600080fd5b6308c379a06102c05260206102e052601a610300527f4f776e6572206f6e6c792063616e206d696e74206974656d732e00000000000061032052610300503360025414611e485760846102dcfd5b610140610380525b61038051516020610380510161038052610380610380511015611e7257611e50565b6320171bef6103a0526024356103c0526103c05160065801610cfa565b61042052610360610380525b6103805152602061038051036103805261014061038051101515611ebe57611e9b565b6104205161036052600261036051146001610360511417611ede57600080fd5b6001610360511415611f5f576308c379a0610440526020610460526028610480527f43616e6e6f74206d696e74204e46542077697468205f737570706c79206d6f726104a0527f65207468616e20310000000000000000000000000000000000000000000000006104c05261048050600160443514611f5e5760a461045cfd5b5b604435600360043560e05260c052604060c02060243560e05260c052604060c0205560243561050052604435610520526004356000337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f626040610500a460006004353b1115612088576004353b611fd557600080fd5b6004353018611fe357600080fd5b60206107806101c460a063f23a6e6161056052336105805260006105a0526024356105c0526044356105e0528061060052610140808051602001808461058001828460006004600a8704601201f161203a57600080fd5b50508051820160206001820306601f820103905060200191505061057c905060006004355af161206957600080fd5b600050610780516105405263f23a6e61610540511461208757600080fd5b5b005b63c671854d60005114156120c857600061028052610280805160200180610140828460006004600a8704601201f16120c157600080fd5b5050612118565b63b07e58756000511415612110576101206102a435600401610140376101006102a4356004013511156120fa57600080fd5b6101406102a43560040161014037600050612118565b6000156124f6575b341561212357600080fd5b600435602051811061213457600080fd5b506000610120525b60206101205101610120526101206101205110156121595761213c565b6000610120525b602061012051016101205261012061012051101561217d57612160565b60006004351861218c57600080fd5b6308c379a06102c05260206102e052601a610300527f4f776e6572206f6e6c792063616e206d696e74206974656d732e000000000000610320526103005033600254146121da5760846102dcfd5b6103606000600a818352015b602461036051600a81106121f957600080fd5b6020020135610380526101406103c0525b6103c0515160206103c051016103c0526103c06103c051101561222c5761220a565b6320171bef6103e05261038051610400526104005160065801610cfa565b610460526103a06103c0525b6103c0515260206103c051036103c0526101406103c05110151561227957612256565b610460516103a05260026103a0511460016103a051141761229957600080fd5b60016103a05114156122cb57600161016461036051600a81106122bb57600080fd5b6020020135146122ca57600080fd5b5b61016461036051600a81106122df57600080fd5b6020020135600360043560e05260c052604060c0206103805160e05260c052604060c020555b81516001018083528114156121e6575b5050602435610480526044356104a0526064356104c0526084356104e05260a4356105005260c4356105205260e4356105405261010435610560526101243561058052610144356105a052610164356105c052610184356105e0526101a435610600526101c435610620526101e4356106405261020435610660526102243561068052610244356106a052610264356106c052610284356106e0526004356000337f514c24e4790d7c31a095a1688a73a01f28d936a9a85d806ba95970d8ee88efa8610280610480a46107006000600a818352015b60006004353b11156124e1576004353b61240357600080fd5b600435301861241157600080fd5b60206109606101c460a063f23a6e61610740523361076052600061078052602461070051600a811061244257600080fd5b60200201356107a05261016461070051600a811061245f57600080fd5b60200201356107c052806107e052610140808051602001808461076001828460006004600a8704601201f161249357600080fd5b50508051820160206001820306601f820103905060200191505061075c905060006004355af16124c257600080fd5b600050610960516107205263f23a6e6161072051146124e057600080fd5b5b5b81516001018083528114156123ea575b5050005b63b390c0ab60005114156125ea57341561250f57600080fd5b6308c379a061014052602061016052601a610180527f4e6f7420656e6f75676820746f6b656e7320746f206275726e2e0000000000006101a0526101805060243560033360e05260c052604060c02060043560e05260c052604060c02054101561257a57608461015cfd5b60033360e05260c052604060c02060043560e05260c052604060c020602435815410156125a657600080fd5b6024358154038155506004356101e05260243561020052600033337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6260406101e0a4005b63b59afe52600051141561282b57341561260357600080fd5b6000610120525b60206101205101610120526101206101205110156126275761260a565b6000610120525b602061012051016101205261012061012051101561264b5761262e565b6101406000600a818352015b600461014051600a811061266a57600080fd5b60200201356101605261014461014051600a811061268757600080fd5b602002013560033360e05260c052604060c0206101605160e05260c052604060c0205410156126b557600080fd5b5b8151600101808352811415612657575b50506101806000600a818352015b600461018051600a81106126e757600080fd5b60200201356101a05260033360e05260c052604060c0206101a05160e05260c052604060c02061014461018051600a811061272157600080fd5b60200201358154101561273357600080fd5b61014461018051600a811061274757600080fd5b60200201358154038155505b81516001018083528114156126d4575b50506004356101c0526024356101e05260443561020052606435610220526084356102405260a4356102605260c4356102805260e4356102a052610104356102c052610124356102e0526101443561030052610164356103205261018435610340526101a435610360526101c435610380526101e4356103a052610204356103c052610224356103e05261024435610400526102643561042052600033337f514c24e4790d7c31a095a1688a73a01f28d936a9a85d806ba95970d8ee88efa86102806101c0a4005b63f2526ada6000511415612869576000610320526103208051602001806101e0828460006004600a8704601201f161286257600080fd5b50506128b9565b63a835c36960005114156128b157610120610464356004016101e0376101006104643560040135111561289b57600080fd5b610140610464356004016101e0376000506128b9565b600015613725575b60043560205181106128ca57600080fd5b5060243560205181106128dc57600080fd5b506000610120525b6020610120510161012052610120610120511015612901576128e4565b6000610120525b602061012051016101205261012061012051101561292557612908565b6000610120525b60206101205101610120526101206101205110156129495761292c565b6061610444356004016101403760416104443560040135111561296b57600080fd5b6308c379a061036052602061038052602c6103a0527f5f66726f6d206d757374206265207468652073656e646572206f7220617070726103c0527f6f766564206164647265737300000000000000000000000000000000000000006103e0526103a050600660043560e05260c052604060c0203360e05260c052604060c020543360043514176129fc5760a461037cfd5b6308c379a0610420526020610440526025610460527f44657374696e6174696f6e2061646472657373206d757374206265206e6f6e2d610480527f7a65726f2e0000000000000000000000000000000000000000000000000000006104a05261046050600060243518612a705760a461043cfd5b6308c379a06104e0526020610500526015610520527f4e6f6e6365206d75737420626520756e757365642e00000000000000000000006105405261052050600460043560e05260c052604060c0206104243560e05260c052604060c0205415612ada5760846104fcfd5b6308c379a06105805260206105a05260256105c0527f53656e64657220686173206e6f742070726f766964656420656e6f75676820656105e0527f746865722e000000000000000000000000000000000000000000000000000000610600526105c050346104043514612b4e5760a461059cfd5b6106406000600a818352015b604461064051600a8110612b6d57600080fd5b602002013561066052600061018461064051600a8110612b8c57600080fd5b60200201351115612c03576102c461064051600a8110612bab57600080fd5b602002013515612bba57600080fd5b61018461064051600a8110612bce57600080fd5b6020020135600360043560e05260c052604060c0206106605160e05260c052604060c020541015612bfe57600080fd5b612c6b565b61018461064051600a8110612c1757600080fd5b602002013515612c2657600080fd5b6102c461064051600a8110612c3a57600080fd5b6020020135600360243560e05260c052604060c0206106605160e05260c052604060c020541015612c6a57600080fd5b5b5b8151600101808352811415612b5a575b50506101406106a0525b6106a0515160206106a051016106a0526106a06106a0511015612ca857612c86565b6373ad25716106c0526004356106e05260243561070052610720604480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e00152806101000135826101000152806101200135826101200152505061086061018480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250506109a06102c480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e00152806101000135826101000152806101200135826101200152505061040435610ae05261042435610b0052610b0051610ae051610ac051610aa051610a8051610a6051610a4051610a2051610a00516109e0516109c0516109a05161098051610960516109405161092051610900516108e0516108c0516108a05161088051610860516108405161082051610800516107e0516107c0516107a05161078051610760516107405161072051610700516106e051600658016100dc565b610b60526106806106a0525b6106a0515260206106a051036106a0526101406106a051101515612ecc57612ea9565b610b605161068052610140610ba0525b610ba051516020610ba05101610ba052610ba0610ba0511015612efe57612edc565b6040636f868168610bc05261068051610be05280610c00526101408080516020018084610be001828460006004600a8704601201f1612f3c57600080fd5b50508051820160206001820306601f820103905060200191505050610c005180610be00180518060206001820306601f82010390508201610ce0525050505b610c20610ce0511015612f8d57612fa2565b610ce051516020610ce05103610ce052612f7b565b610c0051610be05160065801610a98565b610d0052610b80610ba0525b610ba051526020610ba05103610ba052610140610ba051101515612fe257612fbf565b610d0051610b80526308c379a0610d20526020610d40526020610d60527f5369676e657220646f6573206e6f74206d61746368207369676e61747572652e610d8052610d6050602435610b80511461303b576084610d3cfd5b600160043360e05260c052604060c0206104243560e05260c052604060c02055610dc06000600a818352015b6044610dc051600a811061307a57600080fd5b6020020135610de0526000610184610dc051600a811061309957600080fd5b6020020135111561317457600360043560e05260c052604060c020610de05160e05260c052604060c020610184610dc051600a81106130d757600080fd5b6020020135815410156130e957600080fd5b610184610dc051600a81106130fd57600080fd5b6020020135815403815550600360243560e05260c052604060c020610de05160e05260c052604060c0208054610184610dc051600a811061313d57600080fd5b6020020135825401101561315057600080fd5b610184610dc051600a811061316457600080fd5b6020020135815401815550613240565b600360043560e05260c052604060c020610de05160e05260c052604060c02080546102c4610dc051600a81106131a957600080fd5b602002013582540110156131bc57600080fd5b6102c4610dc051600a81106131d057600080fd5b6020020135815401815550600360243560e05260c052604060c020610de05160e05260c052604060c0206102c4610dc051600a811061320e57600080fd5b60200201358154101561322057600080fd5b6102c4610dc051600a811061323457600080fd5b60200201358154038155505b5b8151600101808352811415613067575b50506000600060006000346024356000f161326b57600080fd5b604435610e0052606435610e2052608435610e405260a435610e605260c435610e805260e435610ea05261010435610ec05261012435610ee05261014435610f005261016435610f205261018435610f40526101a435610f60526101c435610f80526101e435610fa05261020435610fc05261022435610fe0526102443561100052610264356110205261028435611040526102a43561106052602435600435337f514c24e4790d7c31a095a1688a73a01f28d936a9a85d806ba95970d8ee88efa8610280610e00a4604435611080526064356110a0526084356110c05260a4356110e05260c4356111005260e43561112052610104356111405261012435611160526101443561118052610164356111a0526102c4356111c0526102e4356111e052610304356112005261032435611220526103443561124052610364356112605261038435611280526103a4356112a0526103c4356112c0526103e4356112e052600435602435337f514c24e4790d7c31a095a1688a73a01f28d936a9a85d806ba95970d8ee88efa8610280611080a460006024353b1115613590576024353b61341657600080fd5b602435301861342457600080fd5b60206117806104046102e063a3bfc20661132052336113405260243561136052611380604480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250506114c061018480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e00152806101000135826101000152806101200135826101200152505080611600526101e0808051602001808461134001828460006004600a8704601201f161354257600080fd5b50508051820160206001820306601f820103905060200191505061133c905060006024355af161357157600080fd5b6000506117805161130052630c97e564611300511461358f57600080fd5b5b60006004353b1115613723576004353b6135a957600080fd5b60043530186135b757600080fd5b6020611c206104046102e063a3bfc2066117c052336117e05260043561180052611820604480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250506119606102c480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e00152806101000135826101000152806101200135826101200152505080611aa0526101e080805160200180846117e001828460006004600a8704601201f16136d557600080fd5b50508051820160206001820306601f82010390506020019150506117dc905060006004355af161370457600080fd5b600050611c20516117a052630c97e5646117a0511461372257600080fd5b5b005b636e8205b26000511415613763576000610320526103208051602001806101e0828460006004600a8704601201f161375c57600080fd5b50506137b3565b63183f5ec560005114156137ab57610120610104356004016101e0376101006101043560040135111561379557600080fd5b610140610104356004016101e0376000506137b3565b600015613f5d575b60043560205181106137c457600080fd5b5060243560205181106137d657600080fd5b50606160e43560040161014037604160e4356004013511156137f757600080fd5b600660043560e05260c052604060c0203360e05260c052604060c0205433600435141761382357600080fd5b6308c379a06103605260206103805260256103a0527f44657374696e6174696f6e2061646472657373206d757374206265206e6f6e2d6103c0527f7a65726f2e0000000000000000000000000000000000000000000000000000006103e0526103a0506000602435186138975760a461037cfd5b6308c379a0610420526020610440526015610460527f4e6f6e6365206d75737420626520756e757365642e00000000000000000000006104805261046050600460043560e05260c052604060c02060c43560e05260c052604060c020541561390057608461043cfd5b6308c379a06104c05260206104e0526025610500527f53656e64657220686173206e6f742070726f766964656420656e6f7567682065610520527f746865722e00000000000000000000000000000000000000000000000000000061054052610500503460a435146139735760a46104dcfd5b600060643511156139bd576084351561398b57600080fd5b606435600360043560e05260c052604060c02060443560e05260c052604060c0205410156139b857600080fd5b6139f8565b606435156139ca57600080fd5b608435600360243560e05260c052604060c02060443560e05260c052604060c0205410156139f757600080fd5b5b6101406105a0525b6105a0515160206105a051016105a0526105a06105a0511015613a2257613a00565b63155960636105c0526004356105e0526024356106005260443561062052606435610640526084356106605260a4356106805260c4356106a0526106a05161068051610660516106405161062051610600516105e05160065801610911565b610700526105806105a0525b6105a0515260206105a051036105a0526101406105a051101515613ab057613a8d565b6107005161058052610140610740525b61074051516020610740510161074052610740610740511015613ae257613ac0565b6040636f868168610760526105805161078052806107a052610140808051602001808461078001828460006004600a8704601201f1613b2057600080fd5b50508051820160206001820306601f8201039050602001915050506107a051806107800180518060206001820306601f82010390508201610880525050505b6107c0610880511015613b7157613b86565b61088051516020610880510361088052613b5f565b6107a0516107805160065801610a98565b6108a052610720610740525b6107405152602061074051036107405261014061074051101515613bc657613ba3565b6108a051610720526308c379a06108c05260206108e0526020610900527f5369676e657220646f6573206e6f74206d61746368207369676e61747572652e61092052610900506024356107205114613c1f5760846108dcfd5b600160043360e05260c052604060c02060c43560e05260c052604060c0205560006064351115613cbf57600360043560e05260c052604060c02060443560e05260c052604060c02060643581541015613c7757600080fd5b606435815403815550600360243560e05260c052604060c02060443560e05260c052604060c02080546064358254011015613cb157600080fd5b606435815401815550613d31565b600360043560e05260c052604060c02060443560e05260c052604060c02080546084358254011015613cf057600080fd5b608435815401815550600360243560e05260c052604060c02060443560e05260c052604060c02060843581541015613d2757600080fd5b6084358154038155505b6000600060006000346024356000f1613d4957600080fd5b6044356109605260643561098052602435600435337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f626040610960a46044356109a0526084356109c052600435602435337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6260406109a0a460006024353b1115613e8e576024353b613dda57600080fd5b6024353018613de857600080fd5b6020610c206101c460a063f23a6e61610a005233610a2052602435610a4052604435610a6052606435610a805280610aa0526101e08080516020018084610a2001828460006004600a8704601201f1613e4057600080fd5b50508051820160206001820306601f8201039050602001915050610a1c905060006024355af1613e6f57600080fd5b600050610c20516109e052630c97e5646109e05114613e8d57600080fd5b5b60006004353b1115613f5b576004353b613ea757600080fd5b6004353018613eb557600080fd5b6020610e806101c460a063f23a6e61610c605233610c8052600435610ca052604435610cc052608435610ce05280610d00526101e08080516020018084610c8001828460006004600a8704601201f1613f0d57600080fd5b50508051820160206001820306601f8201039050602001915050610c7c905060006004355af1613f3c57600080fd5b600050610e8051610c4052630c97e564610c405114613f5a57600080fd5b5b005b638da5cb5b6000511415613f84573415613f7657600080fd5b60025460005260206000f350005b60006000fd\",\n  \"source\": \"# Author: Sören Steiger, github.com/ssteiger\\n# Author: Fetch.ai, github.com/fetchai\\n# License: MIT\\n\\n# ERC1155 Token Standard\\n# https://eips.ethereum.org/EIPS/eip-1155\\n\\n########################EXTERNAL-CONTRACTS####################################\\n\\ncontract ERC1155TokenReceiver:\\n    # Note: The ERC-165 identifier for this interface is 0x4e2312e0.\\n\\n    def onERC1155Received(_operator: address, _from: address, _id: uint256, _value: uint256,\\n                          _data: bytes[256]) -> bytes32: modifying  # TODO: should return bytes4\\n    #        \\\"\\\"\\\"\\n    #       @notice Handle the receipt of a single ERC1155 token type.\\n    #       @dev An ERC1155-compliant smart contract MUST call this function on the token recipient contract, at the end of a `safeTransferFrom` after the balance has been updated.        \\n    #       This function MUST return `bytes4(keccak256(\\\"onERC1155Received(address,address,uint256,uint256,bytes)\\\"))` (i.e. 0xf23a6e61) if it accepts the transfer.\\n    #       This function MUST revert if it rejects the transfer.\\n    #       Return of any other value than the prescribed keccak256 generated value MUST result in the transaction being reverted by the caller.\\n    #       @param _operator  The address which initiated the transfer (i.e. msg.sender)\\n    #       @param _from      The address which previously owned the token\\n    #       @param _id        The ID of the token being transferred\\n    #       @param _value     The amount of tokens being transferred\\n    #       @param _data      Additional data with no specified format\\n    #       @return           `bytes4(keccak256(\\\"onERC1155Received(address,address,uint256,uint256,bytes)\\\"))`\\n    #       \\\"\\\"\\\"\\n\\n    def onERC1155BatchReceived(_operator: address, _from: address, _ids: uint256[BATCH_SIZE], _values: uint256[BATCH_SIZE],\\n                               _data: bytes[256]) -> bytes32: modifying  # TODO: should return bytes4\\n    #       \\\"\\\"\\\"\\n    #       @notice Handle the receipt of multiple ERC1155 token types.\\n    #       @dev An ERC1155-compliant smart contract MUST call this function on the token recipient contract, at the end of a `safeBatchTransferFrom` after the balances have been updated.        \\n    #       This function MUST return `bytes4(keccak256(\\\"onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)\\\"))` (i.e. 0xbc197c81) if it accepts the transfer(s).\\n    #       This function MUST revert if it rejects the transfer(s).\\n    #       Return of any other value than the prescribed keccak256 generated value MUST result in the transaction being reverted by the caller.\\n    #       @param _operator  The address which initiated the batch transfer (i.e. msg.sender)\\n    #       @param _from      The address which previously owned the token\\n    #       @param _ids       An array containing ids of each token being transferred (order and length must match _values array)\\n    #       @param _values    An array containing amounts of each token being transferred (order and length must match _ids array)\\n    #       @param _data      Additional data with no specified format\\n    #       @return           `bytes4(keccak256(\\\"onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)\\\"))`\\n    #       \\\"\\\"\\\"\\n\\n########################END-EXTERNAL-CONTRACTS####################################\\n########################EVENTS####################################\\n\\nMAX_URI_SIZE: constant(uint256) = 1024\\n\\nTransferSingle: event({_operator: indexed(address), _from: indexed(address), _to: indexed(address), _id: uint256,\\n                       _value: uint256})\\n#   @dev Either `TransferSingle` or `TransferBatch` MUST emit when tokens are transferred, including zero value transfers as well as minting or burning (see \\\"Safe Transfer Rules\\\" section of the standard).\\n#        The `_operator` argument MUST be the address of an account/contract that is approved to make the transfer (SHOULD be msg.sender).\\n#        The `_from` argument MUST be the address of the holder whose balance is decreased.\\n#        The `_to` argument MUST be the address of the recipient whose balance is increased.\\n#        The `_id` argument MUST be the token type being transferred.\\n#        The `_value` argument MUST be the number of tokens the holder balance is decreased by and match what the recipient balance is increased by.\\n#        When minting/creating tokens, the `_from` argument MUST be set to `0x0` (i.e. zero address).\\n#        When burning/destroying tokens, the `_to` argument MUST be set to `0x0` (i.e. zero address).\\n\\n\\nTransferBatch: event({_operator: indexed(address), _from: indexed(address), _to: indexed(address),\\n                      _ids: uint256[BATCH_SIZE], _values: uint256[BATCH_SIZE]})\\n#   @dev Either `TransferSingle` or `TransferBatch` MUST emit when tokens are transferred, including zero value transfers as well as minting or burning (see \\\"Safe Transfer Rules\\\" section of the standard).\\n#        The `_operator` argument MUST be the address of an account/contract that is approved to make the transfer (SHOULD be msg.sender).\\n#        The `_from` argument MUST be the address of the holder whose balance is decreased.\\n#        The `_to` argument MUST be the address of the recipient whose balance is increased.\\n#        The `_ids` argument MUST be the list of tokens being transferred.\\n#        The `_values` argument MUST be the list of number of tokens (matching the list and order of tokens specified in _ids) the holder balance is decreased by and match what the recipient balance is increased by.\\n#        When minting/creating tokens, the `_from` argument MUST be set to `0x0` (i.e. zero address).\\n#        When burning/destroying tokens, the `_to` argument MUST be set to `0x0` (i.e. zero address).\\n\\n\\nApprovalForAll: event({_owner: indexed(address), _operator: indexed(address), _approved: bool})\\n#   @dev MUST emit when approval for a second party/operator address to manage all tokens for an owner address is enabled or disabled (absence of an event assumes disabled).\\n\\n\\nURI: event({_value: string[MAX_URI_SIZE], _id: indexed(uint256)})\\n#   @dev MUST emit when the URI is updated for a token ID.\\n#        URIs are defined in RFC 3986.\\n#        The URI MUST point to a JSON file that conforms to the \\\"ERC-1155 Metadata URI JSON Schema\\\".\\n\\n########################END-EVENTS####################################\\n########################INITIALIZATION####################################\\n\\nsupportedInterfaces: map(bytes32, bool)\\n# https://eips.ethereum.org/EIPS/eip-165\\nERC165_INTERFACE_ID: constant(bytes32)  = 0x0000000000000000000000000000000000000000000000000000000001ffc9a7\\nERC1155_INTERFACE_ID: constant(bytes32) = 0x00000000000000000000000000000000000000000000000000000000d9b67a26\\ntokensIdCount: uint256\\nowner: public(address)\\n\\nbalancesOf: map(address, map(uint256, uint256))\\nnoncesOf: map(address, map(uint256, bool))\\nuri: map(uint256, string[256])\\noperators: map(address, map(address, bool))\\ntoken_ids: map(uint256, bool)\\n\\n# This is to be set before contract migration!\\nBATCH_SIZE: constant(uint256) = 10\\n\\n\\n@public\\ndef __init__():\\n    \\\"\\\"\\\"\\n    @notice Called once and only upon contract deployment.\\n    \\\"\\\"\\\"\\n    self.tokensIdCount = convert(0, uint256)\\n    self.supportedInterfaces[ERC165_INTERFACE_ID] = True\\n    self.supportedInterfaces[ERC1155_INTERFACE_ID] = True\\n    self.owner = msg.sender\\n\\n########################END-INITIALIZATION####################################\\n########################PRIVATE-FUNCTIONS####################################\\n\\n\\n######### THIS IS A TEMPORARY SOLUTION #################\\n@public\\n@constant\\ndef getAddress(_addr: address) -> bytes32:\\n    hash: bytes32 = convert(_addr, bytes32)\\n    return hash\\n##################### END ##############################\\n\\n@private\\n@constant\\ndef _getHash(_from: address, _to: address, _ids: uint256[BATCH_SIZE], _from_supplies: uint256[BATCH_SIZE], _to_supplies: uint256[BATCH_SIZE], _value_eth: uint256, _nonce: uint256) -> bytes32:\\n    \\\"\\\"\\\"\\n    @notice Get the hash from the tx values.\\n    @param _from          The address of the sender.\\n    @param _to            The address of the receiver.\\n    @param _ids           The ids of the tokens.\\n    @param _from_supplies The supply of token values that will send the _from.\\n    @param _to_supplies   The supply of token values that will send the _from.\\n    @param _value_eth     The value of the ether.\\n    @param _nonce         The nonce.\\n    @return the hash\\n    \\\"\\\"\\\"\\n    aggregate_hash: bytes32 = keccak256(concat(convert(_ids[0], bytes32), convert(_from_supplies[0], bytes32), convert(_to_supplies[0], bytes32)))\\n    for i in range(BATCH_SIZE):\\n      if not i == 0:\\n        aggregate_hash = keccak256(concat(aggregate_hash, convert(_ids[i], bytes32), convert(_from_supplies[i], bytes32), convert(_to_supplies[i], bytes32)))\\n    hash: bytes32 = keccak256(concat(convert(_from, bytes32),\\n                              convert(_to, bytes32),\\n                              aggregate_hash,\\n                              convert(_value_eth, bytes32),\\n                              convert(_nonce, bytes32)))\\n    return hash\\n\\n\\n@public\\n@constant\\ndef getHash(_from: address, _to: address, _ids: uint256[BATCH_SIZE], _from_supplies: uint256[BATCH_SIZE], _to_supplies: uint256[BATCH_SIZE], _value_eth: uint256, _nonce: uint256) -> bytes32:\\n    \\\"\\\"\\\"\\n    @notice Get the hash from the tx values.\\n    @param _from          The address of the sender.\\n    @param _to            The address of the receiver.\\n    @param _ids           The ids of the tokens.\\n    @param _from_supplies The supply of token values that will send the _from.\\n    @param _to_supplies   The supply of token values that will send the _from.\\n    @param _value_eth     The value of the ether.\\n    @param _nonce         The nonce.\\n    @return the hash\\n    \\\"\\\"\\\"\\n    return self._getHash(_from, _to, _ids, _from_supplies, _to_supplies, _value_eth, _nonce)\\n\\n\\n@private\\n@constant\\ndef getHashOld(_from: address, _to: address, _ids: uint256[BATCH_SIZE], _from_supplies: uint256[BATCH_SIZE], _to_supplies: uint256[BATCH_SIZE], _value_eth: uint256, _nonce: uint256) -> bytes32:\\n    \\\"\\\"\\\"\\n    @notice Get the hash from the tx values.\\n    @param _from          The address of the sender.\\n    @param _to            The address of the receiver.\\n    @param _ids           The ids of the tokens.\\n    @param _from_supplies The supply of token values that will send the _from.\\n    @param _to_supplies   The supply of token values that will send the _from.\\n    @param _value_eth     The value of the ether.\\n    @param _nonce         The nonce.\\n    @return the hash\\n    \\\"\\\"\\\"\\n    hash: bytes32 = keccak256(concat(convert(_from, bytes32),\\n                              convert(_to, bytes32),\\n                              convert(_ids[0], bytes32),\\n                              convert(_ids[1], bytes32),\\n                              convert(_ids[2], bytes32),\\n                              convert(_ids[3], bytes32),\\n                              convert(_ids[4], bytes32),\\n                              convert(_ids[5], bytes32),\\n                              convert(_ids[6], bytes32),\\n                              convert(_ids[7], bytes32),\\n                              convert(_ids[8], bytes32),\\n                              convert(_ids[9], bytes32),\\n                              convert(_from_supplies[0], bytes32),\\n                              convert(_from_supplies[1], bytes32),\\n                              convert(_from_supplies[2], bytes32),\\n                              convert(_from_supplies[3], bytes32),\\n                              convert(_from_supplies[4], bytes32),\\n                              convert(_from_supplies[5], bytes32),\\n                              convert(_from_supplies[6], bytes32),\\n                              convert(_from_supplies[7], bytes32),\\n                              convert(_from_supplies[8], bytes32),\\n                              convert(_from_supplies[9], bytes32),\\n                              convert(_to_supplies[0], bytes32),\\n                              convert(_to_supplies[1], bytes32),\\n                              convert(_to_supplies[2], bytes32),\\n                              convert(_to_supplies[3], bytes32),\\n                              convert(_to_supplies[4], bytes32),\\n                              convert(_to_supplies[5], bytes32),\\n                              convert(_to_supplies[6], bytes32),\\n                              convert(_to_supplies[7], bytes32),\\n                              convert(_to_supplies[8], bytes32),\\n                              convert(_to_supplies[9], bytes32),\\n                              convert(_value_eth, bytes32),\\n                              convert(_nonce, bytes32)))\\n    return hash\\n\\n\\n@private\\n@constant\\ndef _getSingleHash(_from: address, _to: address, _id: uint256, _from_supply: uint256, _to_supply: uint256, _value_eth: uint256, _nonce: uint256) -> bytes32:\\n    \\\"\\\"\\\"\\n    @notice Get the hash from the tx values.\\n    @param _from            The address of the sender.\\n    @param _to              The address of the receiver.\\n    @param _id              The id of the tokens.\\n    @param _from_supply     The from token value. (_from sends)\\n    @param _to_supply       The to token value (_to sends).\\n    @param _value_eth       The value of the ether.\\n    @param _nonce           The nonce.\\n    @return the hash\\n    \\\"\\\"\\\"\\n    hash: bytes32 = keccak256(concat(convert(_from, bytes32),\\n                              convert(_to, bytes32),\\n                              convert(_id, bytes32),\\n                              convert(_from_supply, bytes32),\\n                              convert(_to_supply, bytes32),\\n                              convert(_value_eth, bytes32),\\n                              convert(_nonce, bytes32)))\\n    return hash\\n\\n\\n@public\\n@constant\\ndef getSingleHash(_from: address, _to: address, _id: uint256, _from_supply: uint256, _to_supply: uint256, _value_eth: uint256, _nonce: uint256) -> bytes32:\\n    \\\"\\\"\\\"\\n    @notice Get the hash from the tx values.\\n    @param _from            The address of the sender.\\n    @param _to              The address of the receiver.\\n    @param _id              The id of the tokens.\\n    @param _from_supply     The from token value. (_from sends)\\n    @param _to_supply       The to token value (_to sends).\\n    @param _value_eth       The value of the ether.\\n    @param _nonce           The nonce.\\n    @return the hash\\n    \\\"\\\"\\\"\\n    return self._getSingleHash(_from, _to, _id, _from_supply, _to_supply, _value_eth, _nonce)\\n\\n\\n@private\\n@constant\\ndef ecrecoverSig(_hash: bytes32, _sig: bytes[65]) -> address:\\n    \\\"\\\"\\\"\\n    @notice Check whether the the signature matches the hash.\\n    @param _hash The hash to be checked.\\n    @param _sig  The signature which is meant to match the hash.\\n    @return the address which signed the signature or the zero address\\n    \\\"\\\"\\\"\\n    if len(_sig) != 65:\\n        return ZERO_ADDRESS\\n    # ref. https://gist.github.com/axic/5b33912c6f61ae6fd96d6c4a47afde6d\\n    # The signature format is a compact form of:\\n    # {bytes32 r}{bytes32 s}{uint8 v}\\n    r: bytes32 = extract32(_sig, 0, type=bytes32)\\n    s: bytes32 = extract32(_sig, 32, type=bytes32)\\n    v: int128 = convert(slice(_sig, start=64, len=1), int128)\\n    # Version of signature should be 27 or 28, but 0 and 1 are also possible versions.\\n    # geth uses [0, 1] and some clients have followed. This might change, see:\\n    # https://github.com/ethereum/go-ethereum/issues/2053\\n    if v < 27:\\n        v += 27\\n    if v in [27, 28]:\\n        return ecrecover(_hash, convert(v, uint256), convert(r, uint256), convert(s, uint256))\\n    return ZERO_ADDRESS\\n\\n\\n@private\\n@constant\\ndef decode_id(id: uint256) -> int128:\\n    \\\"\\\"\\\"\\n    @notice Decodes the id of the token inorder to find out if it NFT or FT.\\n    @param id: uint256\\n    @return token_id : int128 (Specified id for FT and NFT.)\\n    @dev shift(x, -y): returns x with the bits shifted to the right by y places, which is equivalent to dividing x by 2**y.\\n    \\\"\\\"\\\"\\n    decoded_token_id: int128 = convert(shift(id, -128), int128)\\n    decoded_index: int128 = convert(id % 2 ** 128, int128)\\n    return decoded_token_id\\n\\n########################END-PRIVATE-FUNCTIONS################################\\n########################PUBLIC-FUNCTIONS#####################################\\n\\n@public\\n@constant\\ndef supportsInterface(_interfaceID: bytes32) -> bool:\\n    \\\"\\\"\\\"\\n    @notice Check whether the interface id is supported.\\n    @param _interfaceID The interface id\\n    @return True if the interface id is supported.\\n    \\\"\\\"\\\"\\n    return self.supportedInterfaces[_interfaceID]\\n\\n@public\\n@constant\\ndef is_nonce_used(addr: address, nonce: uint256) -> bool:\\n    \\\"\\\"\\\"\\n    @notice Checks if the given nonce for the give address is unused.\\n    @param nonce: uint256 the counter of the transaction\\n    @param address: the address that want to transact.\\n    \\\"\\\"\\\"\\n    return self.noncesOf[addr][nonce]\\n\\n@public\\n@constant\\ndef is_token_id_exists(token_id: uint256) -> bool:\\n    \\\"\\\"\\\"\\n    @notice Checks if the given token_id is already created.\\n    @param token_id: uint256 the id of the token.\\n    \\\"\\\"\\\"\\n    return self.token_ids[token_id]\\n\\n@public\\ndef safeTransferFrom(_from: address, _to: address, _id: uint256, _value: uint256, _data: bytes[256]):\\n    \\\"\\\"\\\"\\n    @notice Transfers `_value` amount of an `_id` from the `_from` address to the `_to` address specified (with safety call).\\n    @dev Caller must be approved to manage the tokens being transferred out of the `_from` account (see \\\"Approval\\\" section of the standard).\\n         MUST revert if `_to` is the zero address.\\n         MUST revert if balance of holder for token `_id` is lower than the `_value` sent.\\n         MUST revert on any other error.\\n         MUST emit the `TransferSingle` event to reflect the balance change (see \\\"Safe Transfer Rules\\\" section of the standard).\\n         After the above conditions are met, this function MUST check if `_to` is a smart contract (e.g. code size > 0). If so, it MUST call `onERC1155Received` on `_to` and act appropriately (see \\\"Safe Transfer Rules\\\" section of the standard).\\n    @param _from    Source address\\n    @param _to      Target address\\n    @param _id      ID of the token type\\n    @param _value   Transfer amount\\n    @param _data    Additional data with no specified format, MUST be sent unaltered in call to `onERC1155Received` on `_to`\\n    @return None\\n    \\\"\\\"\\\"\\n    assert _from == msg.sender or (self.operators[_from])[msg.sender]\\n    assert _to != ZERO_ADDRESS, \\\"Cannot transfer to zero address.\\\"\\n    assert self.balancesOf[_from][_id] >= _value, \\\"Not enough tokens.\\\"\\n\\n    self.balancesOf[_from][_id] -= _value\\n    self.balancesOf[_to][_id] += _value\\n\\n    log.TransferSingle(msg.sender, _from, _to, _id, _value)\\n\\n    if _to.is_contract:\\n        returnValue: bytes32 = ERC1155TokenReceiver(_to).onERC1155Received(msg.sender, _from, _id, _value, _data)\\n        assert returnValue == method_id(\\\"onERC1155Received(address,address,uint256,uint256,bytes)\\\", bytes32)\\n\\n\\n@public\\ndef safeBatchTransferFrom(_from: address, _to: address, _ids: uint256[BATCH_SIZE], _values: uint256[BATCH_SIZE], _data: bytes[256]):\\n    \\\"\\\"\\\"\\n    @notice Transfers `_values` amount(s) of `_ids` from the `_from` address to the `_to` address specified (with safety call).\\n    @dev Caller must be approved to manage the tokens being transferred out of the `_from` account (see \\\"Approval\\\" section of the standard).\\n        MUST revert if `_to` is the zero address.\\n        MUST revert if length of `_ids` is not the same as length of `_values`.\\n        MUST revert if any of the balance(s) of the holder(s) for token(s) in `_ids` is lower than the respective amount(s) in `_values` sent to the recipient.\\n        MUST revert on any other error.\\n        MUST emit `TransferSingle` or `TransferBatch` event(s) such that all the balance changes are reflected (see \\\"Safe Transfer Rules\\\" section of the standard).\\n        Balance changes and events MUST follow the ordering of the arrays (_ids[0]/_values[0] before _ids[1]/_values[1], etc).\\n        After the above conditions for the transfer(s) in the batch are met, this function MUST check if `_to` is a smart contract (e.g. code size > 0). If so, it MUST call the relevant `ERC1155TokenReceiver` hook(s) on `_to` and act appropriately (see \\\"Safe Transfer Rules\\\" section of the standard).\\n    @param _from    Source address\\n    @param _to      Target address\\n    @param _ids     IDs of each token type (order and length must match _values array)\\n    @param _values  Transfer amounts per token type (order and length must match _ids array)\\n    @param _data    Additional data with no specified format, MUST be sent unaltered in call to the `ERC1155TokenReceiver` hook(s) on `_to`\\n    @return None\\n    \\\"\\\"\\\"\\n    assert _from == msg.sender or (self.operators[_from])[msg.sender]\\n    assert _to != ZERO_ADDRESS, \\\"Cannot transfer to zero address.\\\"\\n    for i in range(BATCH_SIZE):\\n        id: uint256 = _ids[i]\\n        assert self.balancesOf[_from][id] >= _values[i]\\n\\n    log.TransferBatch(msg.sender, _from, _to, _ids, _values)\\n\\n    for i in range(BATCH_SIZE):\\n        id: uint256 = _ids[i]\\n        self.balancesOf[_from][id] -= _values[i]\\n        self.balancesOf[_to][id] += _values[i]\\n\\n    if _to.is_contract:\\n        returnValue: bytes32 = ERC1155TokenReceiver(_to).onERC1155BatchReceived(msg.sender, _from, _ids, _values, _data)\\n        assert returnValue == method_id(\\\"onERC1155BatchReceived(address,address,uint256[BATCH_SIZE],uint256[BATCH_SIZE],bytes)\\\", bytes32)\\n\\n\\n@public\\n@constant\\ndef balanceOf(_owner: address, _id: uint256) -> uint256:\\n    \\\"\\\"\\\"\\n    @notice Get the balance of an account's tokens.\\n    @param  _owner The address of the token holder\\n    @param  _id    ID of the token\\n    @return The _owner's balance of the token type requested\\n    \\\"\\\"\\\"\\n    return self.balancesOf[_owner][_id]\\n\\n\\n@public\\n@constant\\ndef balanceOfBatch( _owner: address[BATCH_SIZE], _ids: uint256[BATCH_SIZE]) -> uint256[BATCH_SIZE]:\\n    \\\"\\\"\\\"\\n    @notice Get the balance of multiple account/token pairs\\n    @param _owners The addresses of the token holders\\n    @param _ids    ID of the tokens\\n    @return The _owner's balance of the token types requested (i.e. balance for each (owner, id) pair)\\n    \\\"\\\"\\\"\\n    returnBalances: uint256[BATCH_SIZE]\\n    for i in range(BATCH_SIZE):\\n        returnBalances[i] = self.balancesOf[_owner[i]][_ids[i]]\\n    return returnBalances\\n\\n\\n@public\\ndef setApprovalForAll(_operator: address, _approved: bool):\\n    \\\"\\\"\\\"\\n    @notice Enable or disable approval for a third party (\\\"operator\\\") to manage all of the caller's tokens.\\n    @dev MUST emit the ApprovalForAll event on success.\\n    @param _operator  Address to add to the set of authorized operators\\n    @param _approved  True if the operator is approved, false to revoke approval\\n    @return None\\n    \\\"\\\"\\\"\\n    (self.operators[msg.sender])[_operator] = _approved\\n    log.ApprovalForAll(msg.sender, _operator, _approved)\\n\\n\\n@public\\n@constant\\ndef isApprovedForAll(_owner: address, _operator: address) -> bool:\\n    \\\"\\\"\\\"\\n    @notice Queries the approval status of an operator for a given owner.\\n    @param _owner     The owner of the tokens.\\n    @param _operator  Address of authorized operator.\\n    @return True if the operator is approved, false if not\\n    \\\"\\\"\\\"\\n    return (self.operators[_owner])[_operator]\\n\\n\\n@public\\ndef createSingle(_item_owner: address, _id: uint256, _path: string[256]):\\n    \\\"\\\"\\\"\\n    @notice Create a new token type that we can mint later.\\n    @param _item_owner The owner of the item.\\n    @param _id         The id of the token.\\n    @param _path       The path to the token data.\\n    @return None\\n    \\\"\\\"\\\"\\n    assert _item_owner != ZERO_ADDRESS\\n    assert self.owner == msg.sender, \\\"Owner only can create item.\\\"\\n    self.balancesOf[_item_owner][_id] = 0\\n    self.tokensIdCount += 1\\n    self.token_ids[_id] = True\\n    self.uri[_id] = _path\\n    log.URI(_path, _id)\\n    log.TransferSingle(msg.sender, ZERO_ADDRESS, _item_owner, _id, 0)\\n\\n\\n@public\\ndef createBatch(_items_owner: address, _ids: uint256[BATCH_SIZE]):\\n    \\\"\\\"\\\"\\n    @notice Create new token types that we can mint later.\\n    @param _items_owner The owner of the items.\\n    @param _ids         The ids of the tokens.\\n    @return None\\n    \\\"\\\"\\\"\\n    assert _items_owner != ZERO_ADDRESS\\n    assert self.owner == msg.sender, \\\"Owner only can create items.\\\"\\n    for i in range(BATCH_SIZE):\\n        id: uint256 = _ids[i]\\n        self.balancesOf[_items_owner][id] = 0\\n        self.tokensIdCount += 1\\n        self.token_ids[id] = True\\n    zero_supply: uint256[BATCH_SIZE] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]\\n    log.TransferBatch(msg.sender, ZERO_ADDRESS, _items_owner, _ids, zero_supply)\\n\\n\\n@public\\ndef mint(_to: address, _id: uint256, _supply: uint256, _data: bytes[256]=\\\"\\\"):\\n    \\\"\\\"\\\"\\n    @notice Mint a token.\\n    @dev This is not part of the standard.\\n    @param _to      The address of the receiver.\\n    @param _id      The id of the token.\\n    @param _supply  The supply to be minted for the token.\\n    @param _data    The data.\\n    @return None\\n    \\\"\\\"\\\"\\n    assert _to != ZERO_ADDRESS\\n    assert self.owner == msg.sender, \\\"Owner only can mint items.\\\"\\n    decoded_id: int128 = self.decode_id(_id)\\n    assert decoded_id == 1 or decoded_id == 2\\n    if decoded_id == 1 :\\n        assert _supply == 1, \\\"Cannot mint NFT with _supply more than 1\\\"\\n    self.balancesOf[_to][_id] = _supply\\n\\n    log.TransferSingle(msg.sender, ZERO_ADDRESS, _to, _id, _supply)\\n\\n    if _to.is_contract:\\n        returnValue: bytes32 = ERC1155TokenReceiver(_to).onERC1155Received(msg.sender, ZERO_ADDRESS, _id, _supply, _data)\\n        assert returnValue == method_id(\\\"onERC1155Received(address,address,uint256,uint256,bytes)\\\", bytes32)\\n\\n\\n@public\\ndef mintBatch(_to: address, _ids: uint256[BATCH_SIZE], _supplies: uint256[BATCH_SIZE], _data: bytes[256]=\\\"\\\"):\\n    \\\"\\\"\\\"\\n    @notice Mint a batch of tokens.\\n    @dev This is not part of the standard.\\n    @param _to      The address of the receiver.\\n    @param _ids     The ids of the tokens.\\n    @param _supplies The supply to be minted for each token.\\n    @param _data    The data.\\n    @return None\\n    \\\"\\\"\\\"\\n    assert _to != ZERO_ADDRESS\\n    assert self.owner == msg.sender, \\\"Owner only can mint items.\\\"\\n\\n    for i in range(BATCH_SIZE):\\n        id: uint256 = _ids[i]\\n        decoded_id: int128 = self.decode_id(id)\\n        assert decoded_id == 1 or decoded_id == 2\\n\\n        if decoded_id == 1 :\\n            assert _supplies[i] == 1\\n\\n        self.balancesOf[_to][id] = _supplies[i]\\n\\n    log.TransferBatch(msg.sender, ZERO_ADDRESS, _to, _ids, _supplies)\\n\\n    for i in range(BATCH_SIZE):\\n        if _to.is_contract:\\n            returnValue: bytes32 = ERC1155TokenReceiver(_to).onERC1155Received(msg.sender, ZERO_ADDRESS, _ids[i], _supplies[i], _data)\\n            assert returnValue == method_id(\\\"onERC1155Received(address,address,uint256,uint256,bytes)\\\", bytes32)\\n\\n\\n@public\\ndef burn(_id: uint256, _supply: uint256):\\n    \\\"\\\"\\\"\\n    @notice Burns the supply of the specified token.\\n    @param _id        The id of the token\\n    @param _supply    Supply to be burned\\n    @return None\\n    \\\"\\\"\\\"\\n    assert self.balancesOf[msg.sender][_id] >= _supply, \\\"Not enough tokens to burn.\\\"\\n    self.balancesOf[msg.sender][_id] -= _supply\\n    log.TransferSingle(msg.sender, msg.sender, ZERO_ADDRESS, _id, _supply)\\n\\n\\n@public\\ndef burnBatch(_ids: uint256[BATCH_SIZE], _supplies: uint256[BATCH_SIZE]):\\n    \\\"\\\"\\\"\\n    @notice Burns the supply of the specified tokens.\\n    @dev At this point anyone can burn items if they own it.\\n    @param _ids        The ids of the token\\n    @param _supplies   Supplies to be burned\\n    @return None\\n    \\\"\\\"\\\"\\n    for i in range(BATCH_SIZE):\\n        id: uint256 = _ids[i]\\n        assert self.balancesOf[msg.sender][id] >= _supplies[i]\\n\\n    for i in range(BATCH_SIZE):\\n        id: uint256 = _ids[i]\\n        self.balancesOf[msg.sender][id] -= _supplies[i]\\n    log.TransferBatch(msg.sender, msg.sender, ZERO_ADDRESS, _ids, _supplies)\\n\\n\\n@public\\n@payable\\ndef tradeBatch(_from: address, _to: address, _ids: uint256[BATCH_SIZE], _from_supplies: uint256[BATCH_SIZE], _to_supplies: uint256[BATCH_SIZE], _value_eth: uint256, _nonce: uint256, _signature: bytes[65], _data: bytes[256]=\\\"\\\"):\\n    \\\"\\\"\\\"\\n    @notice Trade (atomically swap) tokens with tokens or eth.\\n    @dev Caller must be approved to manage the tokens being transferred out of the `_from` account (see \\\"Approval\\\" section of the standard).\\n        MUST revert if `_to` is the zero address.\\n        MUST revert if _from_supplies[i] > 0 and _to_supplies[i] > 0\\n        MUST revert if len(_ids) != len(_from_supplies) != len(_to_supplies)\\n        MUST revert if _value_eth != msg.value\\n        MUST revert if any of the balance(s) of the holder(s) for token(s) in `_ids` is lower than the respective amount(s) in `positive and negative values` sent to the recipient.\\n        MUST revert on any other error.\\n        MUST emit `TransferSingle` or `TransferBatch` event(s) such that all the balance changes are reflected (see \\\"Safe Transfer Rules\\\" section of the standard).\\n        Balance changes and events MUST follow the ordering of the arrays (_ids[0]/_values[0] before _ids[1]/_values[1], etc).\\n        After the above conditions for the transfer(s) in the batch are met, this function MUST check if `_to` is a smart contract (e.g. code size > 0). If so, it MUST call the relevant `ERC1155TokenReceiver` hook(s) on `_to` and act appropriately (see \\\"Safe Transfer Rules\\\" section of the standard).\\n    @param _from          The address of the sender.\\n    @param _to            The address of the receiver.\\n    @param _ids           The ids of the tokens.\\n    @param _from_supplies The supply of token values that will send the _from.\\n    @param _to_supplies   The supply of token values that will send the _from.\\n    @param _value_eth     The value of the ether.\\n    @param _nonce         The nonce.\\n    @param _signature    The signature of the _to address.\\n    @param _data    The data.\\n    @return None\\n    \\\"\\\"\\\"\\n    # Assert the value of the transaction is less than the balance of A.\\n\\n    assert _from == msg.sender or (self.operators[_from])[msg.sender], \\\"_from must be the sender or approved address\\\"\\n    assert _to != ZERO_ADDRESS, \\\"Destination address must be non-zero.\\\"\\n    assert self.noncesOf[_from][_nonce] == False, \\\"Nonce must be unused.\\\"\\n    assert _value_eth == msg.value, \\\"Sender has not provided enough ether.\\\"\\n\\n    for i in range(BATCH_SIZE):\\n       id: uint256 = _ids[i]\\n       if _from_supplies[i] > 0:\\n           assert _to_supplies[i] == 0\\n           assert self.balancesOf[_from][id] >= _from_supplies[i]\\n       else:\\n           assert _from_supplies[i] == 0\\n           assert self.balancesOf[_to][id] >= _to_supplies[i]\\n\\n    # Create hash from variables.\\n    hash: bytes32 = self._getHash(_from, _to, _ids, _from_supplies, _to_supplies, _value_eth, _nonce)\\n\\n    # Assert that the ecrecover(address,signature) returns true.\\n    recovered_to: address = self.ecrecoverSig(hash, _signature)\\n    assert recovered_to == _to, \\\"Signer does not match signature.\\\"\\n\\n    # Store the nonce\\n    self.noncesOf[msg.sender][_nonce] = True\\n\\n    # Update the balances\\n    for i in range(BATCH_SIZE):\\n        id: uint256 = _ids[i]\\n        if _from_supplies[i] > 0:\\n            self.balancesOf[_from][id] -= _from_supplies[i]\\n            self.balancesOf[_to][id] += _from_supplies[i]\\n        else:\\n            self.balancesOf[_from][id] += _to_supplies[i]\\n            self.balancesOf[_to][id] -= _to_supplies[i]\\n\\n    send(_to, msg.value)\\n\\n    log.TransferBatch(msg.sender, _from, _to, _ids, _from_supplies)\\n    log.TransferBatch(msg.sender, _to, _from, _ids, _to_supplies)\\n\\n\\n    if _to.is_contract:\\n        returnValue: bytes32 = ERC1155TokenReceiver(_to).onERC1155BatchReceived(msg.sender, _to, _ids, _from_supplies, _data)\\n        assert returnValue == method_id(\\\"onERC1155BatchReceived(address,address,uint256,uint256,bytes)\\\", bytes32)\\n    if _from.is_contract:\\n        returnValue: bytes32 = ERC1155TokenReceiver(_from).onERC1155BatchReceived(msg.sender, _from, _ids, _to_supplies, _data)\\n        assert returnValue == method_id(\\\"onERC1155BatchReceived(address,address,uint256,uint256,bytes)\\\", bytes32)\\n\\n\\n\\n@public\\n@payable\\ndef trade(_from: address, _to: address, _id: uint256, _from_supply: uint256, _to_supply: uint256, _value_eth: uint256, _nonce: uint256, _signature: bytes[65], _data: bytes[256]=\\\"\\\"):\\n    \\\"\\\"\\\"\\n    @notice Trade (atomically swap) tokens with tokens or eth.\\n    @dev Caller must be approved to manage the tokens being transferred out of the `_from` account (see \\\"Approval\\\" section of the standard).\\n        MUST revert if `_to` is the zero address.\\n        MUST revert if _from_supply > 0 and _to_supply > 0\\n        MUST revert if _value_eth != msg.value\\n        MUST revert if any of the balance(s) of the holder(s) for token(s) in `_id` is lower than the respective amount in `positive or negative value` sent to the recipient.\\n        MUST revert on any other error.\\n        MUST emit `TransferSingle` or `TransferBatch` event(s) such that all the balance changes are reflected (see \\\"Safe Transfer Rules\\\" section of the standard).\\n        Balance changes and events MUST follow the ordering of the arrays (_ids[0]/_values[0] before _ids[1]/_values[1], etc).\\n        After the above conditions for the transfer(s) in the batch are met, this function MUST check if `_to` is a smart contract (e.g. code size > 0). If so, it MUST call the relevant `ERC1155TokenReceiver` hook(s) on `_to` and act appropriately (see \\\"Safe Transfer Rules\\\" section of the standard).\\n    @param _from            The from address (seller of eth, potential receiver of tokens).\\n    @param _to              The receiver address (receiver of tokens).\\n    @param _id              The id of the token\\n    @param _from_supply     The change in value of token (for _from)\\n    @param _to_supply       The change in value of token (for _to)\\n    @param _value_eth       The value of the ETH sent to the _from address.\\n    @param _nonce           The nonce.\\n    @param _signature       The signature of the _to address.\\n    @param _data    The data.\\n    @return None\\n    \\\"\\\"\\\"\\n    # Assert the value of the transaction is less than the balance of A.\\n    assert _from == msg.sender or (self.operators[_from])[msg.sender]\\n    assert _to != ZERO_ADDRESS, \\\"Destination address must be non-zero.\\\"\\n    assert self.noncesOf[_from][_nonce] == False, \\\"Nonce must be unused.\\\"\\n    assert _value_eth == msg.value, \\\"Sender has not provided enough ether.\\\"\\n    if _from_supply > 0:\\n        assert _to_supply == 0\\n        assert self.balancesOf[_from][_id] >= _from_supply\\n    else:\\n        assert _from_supply == 0\\n        assert self.balancesOf[_to][_id] >= _to_supply\\n\\n    # Create hash from variables.\\n    hash: bytes32 = self._getSingleHash(_from, _to, _id, _from_supply, _to_supply, _value_eth, _nonce)\\n\\n    # Assert that the ecrecover(address,signature) returns true.\\n    recovered_to: address = self.ecrecoverSig(hash, _signature)\\n    assert recovered_to == _to, \\\"Signer does not match signature.\\\"\\n\\n    # Store the nonce\\n    self.noncesOf[msg.sender][_nonce] = True\\n\\n    # Update the balances\\n    if _from_supply > 0:\\n        self.balancesOf[_from][_id] -= _from_supply\\n        self.balancesOf[_to][_id] += _from_supply\\n    else:\\n        self.balancesOf[_from][_id] += _to_supply\\n        self.balancesOf[_to][_id] -= _to_supply\\n\\n    send(_to, msg.value)\\n\\n    log.TransferSingle(msg.sender, _from, _to, _id, _from_supply)\\n    log.TransferSingle(msg.sender, _to, _from, _id, _to_supply)\\n\\n    if _to.is_contract:\\n        returnValue: bytes32 = ERC1155TokenReceiver(_to).onERC1155Received(msg.sender, _to, _id, _from_supply, _data)\\n        assert returnValue == method_id(\\\"onERC1155BatchReceived(address,address,uint256,uint256,bytes)\\\", bytes32)\\n    if _from.is_contract:\\n        returnValue: bytes32 = ERC1155TokenReceiver(_from).onERC1155Received(msg.sender, _from, _id, _to_supply, _data)\\n        assert returnValue == method_id(\\\"onERC1155BatchReceived(address,address,uint256,uint256,bytes)\\\", bytes32)\\n\",\n  \"sourcePath\": \"/Users/aristotelistriantafyllidis/Documents/agents-research/erc1155/contracts/erc1155.vy\",\n  \"compiler\": {\n    \"name\": \"vyper\",\n    \"version\": \"0.1.0b12+commit.a01cdc8\"\n  },\n  \"networks\": {\n    \"1583918911727\": {\n      \"events\": {\n        \"0xc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62\": {\n          \"name\": \"TransferSingle\",\n          \"inputs\": [\n            {\n              \"type\": \"address\",\n              \"name\": \"_operator\",\n              \"indexed\": true\n            },\n            {\n              \"type\": \"address\",\n              \"name\": \"_from\",\n              \"indexed\": true\n            },\n            {\n              \"type\": \"address\",\n              \"name\": \"_to\",\n              \"indexed\": true\n            },\n            {\n              \"type\": \"uint256\",\n              \"name\": \"_id\",\n              \"indexed\": false\n            },\n            {\n              \"type\": \"uint256\",\n              \"name\": \"_value\",\n              \"indexed\": false\n            }\n          ],\n          \"anonymous\": false,\n          \"type\": \"event\",\n          \"signature\": \"0xc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62\"\n        },\n        \"0x514c24e4790d7c31a095a1688a73a01f28d936a9a85d806ba95970d8ee88efa8\": {\n          \"name\": \"TransferBatch\",\n          \"inputs\": [\n            {\n              \"type\": \"address\",\n              \"name\": \"_operator\",\n              \"indexed\": true\n            },\n            {\n              \"type\": \"address\",\n              \"name\": \"_from\",\n              \"indexed\": true\n            },\n            {\n              \"type\": \"address\",\n              \"name\": \"_to\",\n              \"indexed\": true\n            },\n            {\n              \"type\": \"uint256[10]\",\n              \"name\": \"_ids\",\n              \"indexed\": false\n            },\n            {\n              \"type\": \"uint256[10]\",\n              \"name\": \"_values\",\n              \"indexed\": false\n            }\n          ],\n          \"anonymous\": false,\n          \"type\": \"event\",\n          \"signature\": \"0x514c24e4790d7c31a095a1688a73a01f28d936a9a85d806ba95970d8ee88efa8\"\n        },\n        \"0x17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31\": {\n          \"name\": \"ApprovalForAll\",\n          \"inputs\": [\n            {\n              \"type\": \"address\",\n              \"name\": \"_owner\",\n              \"indexed\": true\n            },\n            {\n              \"type\": \"address\",\n              \"name\": \"_operator\",\n              \"indexed\": true\n            },\n            {\n              \"type\": \"bool\",\n              \"name\": \"_approved\",\n              \"indexed\": false\n            }\n          ],\n          \"anonymous\": false,\n          \"type\": \"event\",\n          \"signature\": \"0x17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31\"\n        },\n        \"0x6bb7ff708619ba0610cba295a58592e0451dee2622938c8755667688daf3529b\": {\n          \"name\": \"URI\",\n          \"inputs\": [\n            {\n              \"type\": \"string\",\n              \"name\": \"_value\",\n              \"indexed\": false\n            },\n            {\n              \"type\": \"uint256\",\n              \"name\": \"_id\",\n              \"indexed\": true\n            }\n          ],\n          \"anonymous\": false,\n          \"type\": \"event\",\n          \"signature\": \"0x6bb7ff708619ba0610cba295a58592e0451dee2622938c8755667688daf3529b\"\n        }\n      },\n      \"links\": {},\n      \"address\": \"0x9561C133DD8580860B6b7E504bC5Aa500f0f06a7\",\n      \"transactionHash\": \"0x816b272ebd644b189a3addfbd429b0ea0fa7b2403cca3aa038bcd59f09d9c116\"\n    }\n  },\n  \"schemaVersion\": \"3.0.19\",\n  \"updatedAt\": \"2020-03-11T13:47:51.885Z\",\n  \"networkType\": \"ethereum\"\n}"
  },
  {
    "path": "plugins/aea-ledger-fetchai/tests/data/dummy_contract/contract.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains a dummy contract for an AEA.\"\"\"\n\nfrom aea.contracts.base import Contract\nfrom aea.crypto.base import LedgerApi\n\n\nclass DummyContract(Contract):\n    \"\"\"The some contract class.\"\"\"\n\n    @classmethod\n    def some_method(cls, ledger_api: LedgerApi, contract_address: str) -> None:\n        \"\"\"Some method.\"\"\"\n        pass\n"
  },
  {
    "path": "plugins/aea-ledger-fetchai/tests/data/dummy_contract/contract.yaml",
    "content": "name: dummy\nauthor: fetchai\nversion: 0.1.0\ntype: contract\ndescription: A test contract\nlicense: Apache-2.0\naea_version: '>=0.9.0, <0.10.0'\nfingerprint:\n  __init__.py: QmWbNjFh6E5V4n2qBwyZyXZdmmHvcZSVnwKrcM34MAE56S\n  build/some.json: Qma5n7au2NDCg1nLwYfYnmFNwWChFuXtu65w5DV7wAZRvw\n  build/some.wasm: Qmc9gthbdwRSywinTHKjRVQdFzrKTxUuLDx2ryNfQp1xqf\n  contract.py: QmYfn2V3tXv7MCyhT5Kz5ArtX2FZWHC1jfeRmqCNsRxDL5\nfingerprint_ignore_patterns: []\nbuild_entrypoint: path/to/script.py\nclass_name: DummyContract\ncontract_interface_paths:\n  cosmos: build/some.wasm\n  ethereum: build/some.json\n  fetchai: build/some.wasm\ndependencies: {}\n"
  },
  {
    "path": "plugins/aea-ledger-fetchai/tests/test_fetchai.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the fetchai module.\"\"\"\nimport base64\nimport json\nimport logging\nimport shutil\nimport tempfile\nimport time\nfrom collections import OrderedDict\nfrom pathlib import Path\nfrom typing import List\nfrom unittest import mock\nfrom unittest.mock import MagicMock, call, patch\nfrom uuid import uuid4\n\nimport pytest\nfrom aea_ledger_fetchai import FetchAIApi, FetchAICrypto, FetchAIFaucetApi\nfrom aea_ledger_fetchai._cosmos import MAXIMUM_GAS_AMOUNT\nfrom cosmpy.protos.cosmos.bank.v1beta1.tx_pb2 import MsgSend\nfrom cosmpy.protos.cosmos.base.v1beta1.coin_pb2 import Coin\nfrom google.protobuf.any_pb2 import Any as ProtoAny\n\nfrom aea.crypto.helpers import KeyIsIncorrect\n\nfrom tests.conftest import FETCHAI_TESTNET_CONFIG, MAX_FLAKY_RERUNS, ROOT_DIR\n\n\n@pytest.fixture\ndef fetchai_private_key_file():\n    \"\"\"Pytest fixture to create a temporary FetchAI private key file.\"\"\"\n    crypto = FetchAICrypto()\n    temp_dir = Path(tempfile.mkdtemp())\n    try:\n        temp_file = temp_dir / \"private.key\"\n        temp_file.write_text(crypto.private_key)\n        yield str(temp_file)\n    finally:\n        shutil.rmtree(temp_dir)\n\n\nclass MockRequestsResponse:\n    \"\"\"Mock of request response.\"\"\"\n\n    def __init__(self, data, status_code=None):\n        \"\"\"Initialize mock of request response.\"\"\"\n        self._data = data\n        self._status_code = status_code or 200\n\n    @property\n    def status_code(self):\n        \"\"\"Get status code.\"\"\"\n        return 200\n\n    def json(self):\n        \"\"\"Get json.\"\"\"\n        return self._data\n\n\ndef test_creation(fetchai_private_key_file):\n    \"\"\"Test the creation of the crypto_objects.\"\"\"\n    assert FetchAICrypto(), \"Did not manage to initialise the crypto module\"\n    assert FetchAICrypto(\n        fetchai_private_key_file\n    ), \"Did not manage to load the cosmos private key\"\n\n\ndef test_key_file_encryption_decryption(fetchai_private_key_file):\n    \"\"\"Test fetchai private key encrypted and decrypted correctly.\"\"\"\n    fetchai = FetchAICrypto(fetchai_private_key_file)\n    pk_data = Path(fetchai_private_key_file).read_text()\n    password = uuid4().hex\n    encrypted_data = fetchai.encrypt(password)\n    decrypted_data = fetchai.decrypt(encrypted_data, password)\n    assert encrypted_data != pk_data\n    assert pk_data == decrypted_data\n\n    with pytest.raises(ValueError, match=\"Decrypt error! Bad password?\"):\n        fetchai.decrypt(encrypted_data, \"BaD_PassWord\")\n\n    with pytest.raises(ValueError, match=\"Bad encrypted key format!\"):\n        fetchai.decrypt(\"some_data\" * 16, \"BaD_PassWord\")\n\n\ndef test_initialization():\n    \"\"\"Test the initialisation of the variables.\"\"\"\n    account = FetchAICrypto()\n    assert account.entity is not None, \"The property must return the account.\"\n    assert (\n        account.address is not None\n    ), \"After creation the display address must not be None\"\n    assert account.address.startswith(\"fetch\")\n    assert (\n        account.public_key is not None\n    ), \"After creation the public key must no be None\"\n\n\ndef test_sign_and_recover_message(fetchai_private_key_file):\n    \"\"\"Test the signing and the recovery of a message.\"\"\"\n    account = FetchAICrypto(fetchai_private_key_file)\n    sign_bytes = account.sign_message(message=b\"hello\")\n    assert len(sign_bytes) > 0, \"The len(signature) must not be 0\"\n    recovered_addresses = FetchAIApi.recover_message(\n        message=b\"hello\", signature=sign_bytes\n    )\n    assert (\n        account.address in recovered_addresses\n    ), \"Failed to recover the correct address.\"\n\n\ndef test_get_hash():\n    \"\"\"Test the get hash functionality.\"\"\"\n    expected_hash = \"2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824\"\n    hash_ = FetchAIApi.get_hash(message=b\"hello\")\n    assert expected_hash == hash_\n\n\ndef test_dump_positive(fetchai_private_key_file):\n    \"\"\"Test dump.\"\"\"\n    account = FetchAICrypto(fetchai_private_key_file)\n    account.dump(MagicMock())\n\n\ndef test_api_creation():\n    \"\"\"Test api instantiation.\"\"\"\n    assert FetchAIApi(**FETCHAI_TESTNET_CONFIG), \"Failed to initialise the api\"\n\n\ndef test_api_none():\n    \"\"\"Test the \"api\" of the cryptoApi is none.\"\"\"\n    fetchai_api = FetchAIApi(**FETCHAI_TESTNET_CONFIG)\n    assert fetchai_api.api is None, \"The api property is not None.\"\n\n\ndef test_generate_nonce():\n    \"\"\"Test generate nonce.\"\"\"\n    nonce = FetchAIApi.generate_tx_nonce(\n        seller=\"some_seller_addr\", client=\"some_buyer_addr\"\n    )\n    assert len(nonce) > 0 and int(\n        nonce, 16\n    ), \"The len(nonce) must not be 0 and must be hex\"\n\n\ndef test_get_address_from_public_key():\n    \"\"\"Test the address from public key.\"\"\"\n    fet_crypto = FetchAICrypto()\n    address = FetchAIApi.get_address_from_public_key(fet_crypto.public_key)\n    assert address == fet_crypto.address, \"The address must be the same.\"\n\n\ndef test_validate_address():\n    \"\"\"Test the is_valid_address functionality.\"\"\"\n    account = FetchAICrypto()\n    assert FetchAIApi.is_valid_address(account.address)\n    assert not FetchAIApi.is_valid_address(account.address + \"wrong\")\n\n\n# @pytest.mark.flaky(reruns=MAX_FLAKY_RERUNS)\n@pytest.mark.integration\n@pytest.mark.ledger\ndef test_construct_sign_and_submit_transfer_transaction():\n    \"\"\"Test the construction, signing and submitting of a transfer transaction.\"\"\"\n    account = FetchAICrypto()\n    balance = get_wealth(account.address)\n    assert balance > 0, \"Failed to fund account.\"\n    fc2 = FetchAICrypto()\n    fetchai_api = FetchAIApi(**FETCHAI_TESTNET_CONFIG)\n\n    amount = 10000\n    assert amount < balance, \"Not enough funds.\"\n    transfer_transaction = fetchai_api.get_transfer_transaction(\n        sender_address=account.address,\n        destination_address=fc2.address,\n        amount=amount,\n        tx_fee=7750000000000000,\n        tx_nonce=\"something\",\n    )\n    assert (\n        isinstance(transfer_transaction, dict) and len(transfer_transaction) == 2\n    ), \"Incorrect transfer_transaction constructed.\"\n\n    signed_transaction = account.sign_transaction(transfer_transaction)\n    assert (\n        isinstance(signed_transaction, dict)\n        and len(signed_transaction[\"tx\"]) == 3\n        and isinstance(signed_transaction[\"tx\"][\"signatures\"], list)\n    ), \"Incorrect signed_transaction constructed.\"\n\n    transaction_digest = fetchai_api.send_signed_transaction(signed_transaction)\n    assert transaction_digest is not None, \"Failed to submit transfer transaction!\"\n\n    not_settled = True\n    elapsed_time = 0\n    while not_settled and elapsed_time < 20:\n        elapsed_time += 1\n        time.sleep(2)\n        transaction_receipt = fetchai_api.get_transaction_receipt(transaction_digest)\n        if transaction_receipt is None:\n            continue\n        is_settled = fetchai_api.is_transaction_settled(transaction_receipt)\n        not_settled = not is_settled\n    assert transaction_receipt is not None, \"Failed to retrieve transaction receipt.\"\n    assert is_settled, \"Failed to verify tx!\"\n\n    tx = fetchai_api.get_transaction(transaction_digest)\n    is_valid = fetchai_api.is_transaction_valid(\n        tx, fc2.address, account.address, \"\", amount\n    )\n    assert is_valid, \"Failed to settle tx correctly!\"\n\n\n# @pytest.mark.flaky(reruns=MAX_FLAKY_RERUNS)\n@pytest.mark.integration\n@pytest.mark.ledger\ndef test_get_balance():\n    \"\"\"Test the balance is zero for a new account.\"\"\"\n    fetchai_api = FetchAIApi(**FETCHAI_TESTNET_CONFIG)\n    fc = FetchAICrypto()\n    balance = fetchai_api.get_balance(fc.address)\n    assert balance == 0, \"New account has a positive balance.\"\n    balance = get_wealth(fc.address)\n    assert balance > 0, \"Existing account has no balance.\"\n\n\n# @pytest.mark.flaky(reruns=MAX_FLAKY_RERUNS)\n@pytest.mark.integration\n@pytest.mark.ledger\ndef test_get_state():\n    \"\"\"Test that get_state() with 'blocks' function returns something containing the block height.\"\"\"\n    fetchai_api = FetchAIApi(**FETCHAI_TESTNET_CONFIG)\n    callable_name = \"blocks\"\n    args = (\"latest\",)\n    block = fetchai_api.get_state(callable_name, *args)\n    assert block is not None, \"No response to 'blocks/latest' query.\"\n    assert (\n        block[\"block\"][\"header\"][\"height\"] is not None\n    ), \"Block height not found in response.\"\n\n\ndef get_wealth(address: str):\n    \"\"\"Get wealth for test.\"\"\"\n    fetchai_api = FetchAIApi(**FETCHAI_TESTNET_CONFIG)\n    FetchAIFaucetApi().get_wealth(address)\n    balance = 0\n    timeout = 0\n    while timeout < 40 and balance == 0:\n        time.sleep(1)\n        timeout += 1\n        _balance = fetchai_api.get_balance(address)\n        balance = _balance if _balance is not None else 0\n    return balance\n\n\n# @pytest.mark.flaky(reruns=MAX_FLAKY_RERUNS)\n@pytest.mark.integration\n@pytest.mark.ledger\ndef test_get_wealth_positive(caplog):\n    \"\"\"Test the balance is zero for a new account.\"\"\"\n    with caplog.at_level(logging.DEBUG, logger=\"aea.crypto.fetchai._default_logger\"):\n        fetchai_faucet_api = FetchAIFaucetApi()\n        fc = FetchAICrypto()\n        fetchai_faucet_api.get_wealth(fc.address)\n\n\n@pytest.mark.ledger\n@mock.patch(\"aea_ledger_fetchai._cosmos.requests.get\")\n@mock.patch(\"aea_ledger_fetchai._cosmos.requests.post\")\ndef test_successful_faucet_operation(mock_post, mock_get):\n    \"\"\"Test successful faucet operation.\"\"\"\n    address = \"a normal cosmos address would be here\"\n    mock_post.return_value = MockRequestsResponse({\"uuid\": \"a-uuid-v4-would-be-here\"})\n\n    mock_get.return_value = MockRequestsResponse(\n        {\n            \"status\": \"ok\",\n            \"claim\": {\n                \"createdAt\": \"2021-08-13T15:18:50.420Z\",\n                \"updatedAt\": \"2021-08-13T15:18:58.249Z\",\n                \"status\": FetchAIFaucetApi.FAUCET_STATUS_COMPLETED,\n                \"txStatus\": {\n                    \"hash\": \"0x transaction hash would be here\",\n                    \"height\": 123456,\n                },\n            },\n        }\n    )\n\n    faucet = FetchAIFaucetApi()\n    faucet.get_wealth(address)\n\n    mock_post.assert_has_calls(\n        [\n            call(\n                url=f\"{FetchAIFaucetApi.testnet_faucet_url}/api/v3/claims\",\n                json={\"address\": address},\n            )\n        ]\n    )\n    mock_get.assert_has_calls(\n        [\n            call(\n                f\"{FetchAIFaucetApi.testnet_faucet_url}/api/v3/claims/a-uuid-v4-would-be-here\"\n            )\n        ]\n    )\n\n\n@pytest.mark.ledger\n@mock.patch(\"aea_ledger_fetchai._cosmos.requests.get\")\n@mock.patch(\"aea_ledger_fetchai._cosmos.requests.post\")\ndef test_successful_realistic_faucet_operation(mock_post, mock_get):\n    \"\"\"Test successful realistic faucet operation.\"\"\"\n    address = \"a normal cosmos address would be here\"\n    mock_post.return_value = MockRequestsResponse({\"uuid\": \"a-uuid-v4-would-be-here\"})\n\n    mock_get.side_effect = [\n        MockRequestsResponse(\n            {\n                \"status\": \"ok\",\n                \"claim\": {\n                    \"createdAt\": \"2021-08-13T15:18:50.420Z\",\n                    \"updatedAt\": \"2021-08-13T15:18:58.249Z\",\n                    \"status\": FetchAIFaucetApi.FAUCET_STATUS_PENDING,\n                },\n            }\n        ),\n        MockRequestsResponse(\n            {\n                \"status\": \"ok\",\n                \"claim\": {\n                    \"createdAt\": \"2021-08-13T15:18:50.420Z\",\n                    \"updatedAt\": \"2021-08-13T15:18:58.249Z\",\n                    \"status\": FetchAIFaucetApi.FAUCET_STATUS_PENDING,\n                },\n            }\n        ),\n        MockRequestsResponse(\n            {\n                \"status\": \"ok\",\n                \"claim\": {\n                    \"createdAt\": \"2021-08-13T15:18:50.420Z\",\n                    \"updatedAt\": \"2021-08-13T15:18:58.249Z\",\n                    \"status\": FetchAIFaucetApi.FAUCET_STATUS_COMPLETED,\n                    \"txStatus\": {\n                        \"hash\": \"0x transaction hash would be here\",\n                        \"height\": 123456,\n                    },\n                },\n            }\n        ),\n    ]\n\n    faucet = FetchAIFaucetApi(poll_interval=0)\n    faucet.get_wealth(address)\n\n    mock_post.assert_has_calls(\n        [\n            call(\n                url=f\"{FetchAIFaucetApi.testnet_faucet_url}/api/v3/claims\",\n                json={\"address\": address},\n            )\n        ]\n    )\n    mock_get.assert_has_calls(\n        [\n            call(\n                f\"{FetchAIFaucetApi.testnet_faucet_url}/api/v3/claims/a-uuid-v4-would-be-here\"\n            ),\n            call(\n                f\"{FetchAIFaucetApi.testnet_faucet_url}/api/v3/claims/a-uuid-v4-would-be-here\"\n            ),\n            call(\n                f\"{FetchAIFaucetApi.testnet_faucet_url}/api/v3/claims/a-uuid-v4-would-be-here\"\n            ),\n        ]\n    )\n\n\n@pytest.mark.flaky(reruns=MAX_FLAKY_RERUNS)\n@pytest.mark.integration\n@pytest.mark.ledger\ndef test_format_default():\n    \"\"\"Test if default CosmosSDK transaction is correctly formatted.\"\"\"\n    account = FetchAICrypto()\n    cc2 = FetchAICrypto()\n    cosmos_api = FetchAIApi(**FETCHAI_TESTNET_CONFIG)\n\n    amount = 10000\n\n    transfer_transaction = cosmos_api.get_transfer_transaction(\n        sender_address=account.address,\n        destination_address=cc2.address,\n        amount=amount,\n        tx_fee=1000,\n        tx_nonce=\"something\",\n        account_number=1,\n        sequence=0,\n    )\n\n    signed_transaction = account.sign_transaction(transfer_transaction)\n\n    assert \"tx\" in signed_transaction\n    assert \"signatures\" in signed_transaction[\"tx\"]\n    assert len(signed_transaction[\"tx\"][\"signatures\"]) == 1\n\n    assert \"publicKey\" in signed_transaction[\"tx\"][\"authInfo\"][\"signerInfos\"][0]\n    assert \"key\" in signed_transaction[\"tx\"][\"authInfo\"][\"signerInfos\"][0][\"publicKey\"]\n    base64_pbk = signed_transaction[\"tx\"][\"authInfo\"][\"signerInfos\"][0][\"publicKey\"][\n        \"key\"\n    ]\n\n    pbk = base64.b64decode(base64_pbk)\n    assert pbk == bytes.fromhex(account.public_key)\n    assert len(signed_transaction[\"tx\"][\"signatures\"][0]) == 88\n    signature = base64.b64decode(signed_transaction[\"tx\"][\"signatures\"][0])\n    assert len(signature) == 64\n\n\n@pytest.mark.flaky(reruns=MAX_FLAKY_RERUNS)\n@pytest.mark.integration\n@pytest.mark.ledger\ndef test_get_storage_transaction_cosmwasm():\n    \"\"\"Test the get storage transaction method.\"\"\"\n    cc2 = FetchAICrypto()\n    cosmos_api = FetchAIApi(**FETCHAI_TESTNET_CONFIG)\n\n    contract_interface = {\"wasm_byte_code\": \"1234\"}\n    deployer_address = cc2.address\n    deploy_transaction = cosmos_api.get_deploy_transaction(\n        contract_interface,\n        deployer_address,\n        account_number=1,\n        sequence=0,\n    )\n    with patch.object(\n        cosmos_api, \"_try_get_account_number_and_sequence\", return_value=(1, 0)\n    ):\n        deploy_transaction = cosmos_api.get_deploy_transaction(\n            contract_interface, deployer_address\n        )\n\n    assert type(deploy_transaction) == dict and len(deploy_transaction) == 2\n    # Check sign_data\n    assert \"account_number\" in deploy_transaction[\"sign_data\"][cc2.address]\n    assert \"chain_id\" in deploy_transaction[\"sign_data\"][cc2.address]\n\n    # Check msg\n    assert len(deploy_transaction[\"tx\"][\"body\"][\"messages\"]) == 1\n    msg = deploy_transaction[\"tx\"][\"body\"][\"messages\"][0]\n    assert \"@type\" in msg and msg[\"@type\"] == \"/cosmwasm.wasm.v1.MsgStoreCode\"\n\n    assert msg[\"sender\"] == deployer_address\n    assert msg[\"wasmByteCode\"] == contract_interface[\"wasm_byte_code\"]\n\n\n@pytest.mark.integration\n@pytest.mark.ledger\ndef test_get_init_transaction_cosmwasm():\n    \"\"\"Test the get deploy transaction method.\"\"\"\n    cc2 = FetchAICrypto()\n    cosmos_api = FetchAIApi(**FETCHAI_TESTNET_CONFIG)\n    init_msg = \"init_msg\"\n    code_id = 1\n    deployer_address = cc2.address\n    tx_fee = 1\n    amount = 10\n    gas_limit = 1234\n    contract_interface = {}\n    init_transaction = cosmos_api.get_deploy_transaction(\n        contract_interface,\n        deployer_address,\n        code_id=code_id,\n        init_msg=init_msg,\n        amount=amount,\n        tx_fee=tx_fee,\n        label=\"\",\n        account_number=1,\n        sequence=0,\n        gas=gas_limit,\n        denom=\"abc\",\n        tx_fee_denom=\"def\",\n    )\n\n    assert type(init_transaction) == dict and len(init_transaction) == 2\n\n    # Check sign_data\n    assert \"account_number\" in init_transaction[\"sign_data\"][cc2.address]\n    assert \"chain_id\" in init_transaction[\"sign_data\"][cc2.address]\n\n    # Check tx\n    assert init_transaction[\"tx\"][\"authInfo\"][\"fee\"][\"amount\"] == [\n        {\"denom\": \"def\", \"amount\": str(tx_fee)}\n    ]\n\n    # Check msg\n    assert len(init_transaction[\"tx\"][\"body\"][\"messages\"]) == 1\n    msg = init_transaction[\"tx\"][\"body\"][\"messages\"][0]\n    assert \"@type\" in msg and msg[\"@type\"] == \"/cosmwasm.wasm.v1.MsgInstantiateContract\"\n    assert msg[\"sender\"] == deployer_address\n    assert msg[\"codeId\"] == str(code_id)\n    assert base64.b64decode(msg[\"msg\"]).decode() == f'\"{init_msg}\"'\n    assert msg[\"funds\"] == [{\"denom\": \"abc\", \"amount\": str(amount)}]\n\n\n@pytest.mark.flaky(reruns=MAX_FLAKY_RERUNS)\n@pytest.mark.integration\n@pytest.mark.ledger\ndef test_get_handle_transaction_cosmwasm():\n    \"\"\"Test the get deploy transaction method.\"\"\"\n    cc2 = FetchAICrypto()\n\n    cosmos_api = FetchAIApi(**FETCHAI_TESTNET_CONFIG)\n    handle_msg = \"handle_msg\"\n    sender_address = cc2.address\n    contract_address = \"contract_address\"\n    tx_fee = 1\n    amount = 10\n    gas_limit = 1234\n    with patch.object(\n        cosmos_api, \"_try_get_account_number_and_sequence\", return_value=(1, 0)\n    ):\n        handle_transaction = cosmos_api.get_handle_transaction(\n            sender_address,\n            contract_address,\n            handle_msg,\n            amount,\n            tx_fee,\n            gas=gas_limit,\n            memo=\"memo\",\n            denom=\"abc\",\n            tx_fee_denom=\"def\",\n        )\n\n    assert type(handle_transaction) == dict and len(handle_transaction) == 2\n\n    # Check sign_data\n    assert \"account_number\" in handle_transaction[\"sign_data\"][cc2.address]\n    assert \"chain_id\" in handle_transaction[\"sign_data\"][cc2.address]\n\n    # Check tx\n    assert handle_transaction[\"tx\"][\"authInfo\"][\"fee\"] == {\n        \"amount\": [{\"denom\": \"def\", \"amount\": str(tx_fee)}],\n        \"gasLimit\": str(gas_limit),\n    }\n\n    assert \"memo\" in handle_transaction[\"tx\"][\"body\"]\n\n    # Check msg\n    assert len(handle_transaction[\"tx\"][\"body\"][\"messages\"]) == 1\n    msg = handle_transaction[\"tx\"][\"body\"][\"messages\"][0]\n    assert \"@type\" in msg and msg[\"@type\"] == \"/cosmwasm.wasm.v1.MsgExecuteContract\"\n    assert msg[\"sender\"] == sender_address\n    assert msg[\"contract\"] == contract_address\n    assert base64.b64decode(msg[\"msg\"]).decode() == f'\"{handle_msg}\"'\n    assert msg[\"funds\"] == [{\"denom\": \"abc\", \"amount\": str(amount)}]\n\n\n@pytest.mark.flaky(reruns=MAX_FLAKY_RERUNS)\n@pytest.mark.integration\n@pytest.mark.ledger\ndef test_try_execute_wasm_query():\n    \"\"\"Test the execute wasm query method.\"\"\"\n    cosmos_api = FetchAIApi(**FETCHAI_TESTNET_CONFIG)\n    client_mock = mock.Mock()\n\n    output_raw_mock = mock.Mock()\n    output_raw_mock.data = '{\"output\": 1}'\n\n    attrs = {\"SmartContractState.return_value\": output_raw_mock}\n    client_mock.configure_mock(**attrs)\n    cosmos_api.wasm_client = client_mock\n    result = cosmos_api.execute_contract_query(\n        contract_address=\"contract_address\", query_msg={}\n    )\n    assert result == json.loads(output_raw_mock.data)\n\n\n@pytest.mark.flaky(reruns=MAX_FLAKY_RERUNS)\n@pytest.mark.integration\n@pytest.mark.ledger\ndef test_send_signed_transaction():\n    \"\"\"Test the send_signed_transaction method\"\"\"\n    cosmos_api = FetchAIApi(**FETCHAI_TESTNET_CONFIG)\n    tx_signed = cosmos_api.get_transfer_transaction(\n        sender_address=\"addr1\",\n        destination_address=\"addr2\",\n        amount=123,\n        tx_fee=1000,\n        tx_nonce=\"something\",\n        account_number=1,\n        sequence=0,\n    )\n\n    # Mock version of protobuf Tx response\n    mock_return_value = mock.Mock()\n    mock_tx_response = mock.Mock()\n    mock_tx_response.code = 0\n    mock_tx_response.txhash = \"digest\"\n    mock_return_value.tx_response = mock_tx_response\n\n    with mock.patch.object(\n        cosmos_api.tx_client, \"BroadcastTx\", return_value=mock_return_value\n    ):\n        result = cosmos_api.send_signed_transaction(tx_signed=tx_signed)\n    assert result == \"digest\"\n\n\n@pytest.mark.flaky(reruns=MAX_FLAKY_RERUNS)\n@pytest.mark.integration\n@pytest.mark.ledger\ndef test_get_contract_instance():\n    \"\"\"Test the get contract instance method.\"\"\"\n    cosmos_api = FetchAIApi(**FETCHAI_TESTNET_CONFIG)\n    assert cosmos_api.get_contract_instance(\"interface\") is None\n\n\ndef test_helper_get_code_id():\n    \"\"\"Test CosmosHelper.is_transaction_settled.\"\"\"\n    assert (\n        FetchAIApi.get_code_id(\n            {\n                \"logs\": [\n                    {\n                        \"msg_index\": 0,\n                        \"log\": \"\",\n                        \"events\": [\n                            {\n                                \"type\": \"message\",\n                                \"attributes\": [\n                                    {\"key\": \"action\", \"value\": \"store-code\"},\n                                    {\"key\": \"module\", \"value\": \"wasm\"},\n                                    {\n                                        \"key\": \"signer\",\n                                        \"value\": \"fetch1pa7q6urt98dfe2rsvfaefj8zhh792sdfuzym2t\",\n                                    },\n                                    {\"key\": \"code_id\", \"value\": \"631\"},\n                                ],\n                            }\n                        ],\n                    }\n                ]\n            }\n        )\n        == 631\n    )\n\n\ndef test_helper_get_contract_address():\n    \"\"\"Test CosmosHelper.is_transaction_settled.\"\"\"\n    assert (\n        FetchAIApi.get_contract_address(\n            {\n                \"logs\": [\n                    {\n                        \"msg_index\": 0,\n                        \"log\": \"\",\n                        \"events\": [\n                            {\n                                \"type\": \"message\",\n                                \"attributes\": [\n                                    {\"key\": \"action\", \"value\": \"instantiate\"},\n                                    {\"key\": \"module\", \"value\": \"wasm\"},\n                                    {\n                                        \"key\": \"signer\",\n                                        \"value\": \"fetch1pa7q6urt98dfe2rsvfaefj8zhh792sdfuzym2t\",\n                                    },\n                                    {\"key\": \"code_id\", \"value\": \"631\"},\n                                    {\n                                        \"key\": \"_contract_address\",\n                                        \"value\": \"fetch1lhd5t8jdjn0n4q27hsah6c0907nxrswcp5l4nw\",\n                                    },\n                                ],\n                            }\n                        ],\n                    }\n                ]\n            }\n        )\n        == \"fetch1lhd5t8jdjn0n4q27hsah6c0907nxrswcp5l4nw\"\n    )\n\n\ndef test_load_contract_interface():\n    \"\"\"Test the load_contract_interface method.\"\"\"\n    path = Path(ROOT_DIR, \"tests\", \"data\", \"dummy_contract\", \"build\", \"some.wasm\")\n    result = FetchAIApi.load_contract_interface(path)\n    assert \"wasm_byte_code\" in result\n\n\n@pytest.mark.integration\n@pytest.mark.ledger\ndef test_construct_init_transaction():\n    \"\"\"Test the construction of a contract instantiate transaction\"\"\"\n    account = FetchAICrypto()\n    fetchai_api = FetchAIApi(**FETCHAI_TESTNET_CONFIG)\n\n    init_transaction = fetchai_api._get_init_transaction(\n        deployer_address=account.address,\n        denom=\"atestfet\",\n        chain_id=\"cosmoshub-3\",\n        account_number=1,\n        sequence=1,\n        amount=0,\n        code_id=200,\n        init_msg={},\n        label=\"something\",\n        tx_fee_denom=\"stake\",\n    )\n    assert (\n        isinstance(init_transaction, dict) and len(init_transaction) == 2\n    ), \"Incorrect transfer_transaction constructed.\"\n    assert (\n        init_transaction[\"tx\"][\"body\"][\"messages\"][0][\"@type\"]\n        == \"/cosmwasm.wasm.v1.MsgInstantiateContract\"\n    )\n\n\n@pytest.mark.integration\n@pytest.mark.ledger\ndef test_construct_handle_transaction():\n    \"\"\"Test the construction of a transfer transaction.\"\"\"\n    account = FetchAICrypto()\n    account2 = FetchAICrypto()\n    fetchai_api = FetchAIApi(**FETCHAI_TESTNET_CONFIG)\n\n    transaction = fetchai_api.get_handle_transaction(\n        sender_address=account.address,\n        contract_address=account2.address,\n        handle_msg={},\n        amount=0,\n        tx_fee=100,\n        denom=\"atestfet\",\n        account_number=1,\n        sequence=0,\n    )\n    assert (\n        isinstance(transaction, dict) and len(transaction) == 2\n    ), \"Incorrect transfer_transaction constructed.\"\n    assert (\n        transaction[\"tx\"][\"body\"][\"messages\"][0][\"@type\"]\n        == \"/cosmwasm.wasm.v1.MsgExecuteContract\"\n    )\n\n\ndef test_load_errors():\n    \"\"\"Test load errors: bad password, no password specified.\"\"\"\n    ec = FetchAICrypto()\n    with patch.object(FetchAICrypto, \"load\", return_value=\"bad sTring\"):\n        with pytest.raises(KeyIsIncorrect, match=\"Try to specify `password`\"):\n            ec.load_private_key_from_path(\"any path\")\n\n        with pytest.raises(KeyIsIncorrect, match=\"Wrong password?\"):\n            ec.load_private_key_from_path(\"any path\", password=\"some\")\n\n\ndef test_decrypt_error():\n    \"\"\"Test bad password error on decrypt.\"\"\"\n    ec = FetchAICrypto()\n    ec._pritvate_key = FetchAICrypto.generate_private_key()\n    password = \"test\"\n    encrypted_data = ec.encrypt(password=password)\n    with patch(\n        \"aea_ledger_fetchai._cosmos.DataEncrypt.decrypt\",\n        side_effect=UnicodeDecodeError(\"expected\", b\"\", 2, 3, \"\"),\n    ):\n        with pytest.raises(ValueError, match=\"bad password?\"):\n            ec.decrypt(encrypted_data, password + \"some\")\n\n\n@pytest.mark.integration\n@pytest.mark.ledger\ndef test_multiple_signatures_transaction():\n    \"\"\"Test generating message with multiple signers\"\"\"\n    fetchai_api = FetchAIApi(**FETCHAI_TESTNET_CONFIG)\n\n    coins = [Coin(denom=\"DENOM\", amount=\"1234\")]\n\n    msg_send = MsgSend(\n        from_address=str(\"from\"),\n        to_address=str(\"to\"),\n        amount=coins,\n    )\n    send_msg_packed = ProtoAny()\n    send_msg_packed.Pack(msg_send, type_url_prefix=\"/\")\n\n    tx = fetchai_api._get_transaction(\n        account_numbers=[1, 2],\n        from_addresses=[\"adr1\", \"adr2\"],\n        pub_keys=[b\"1\", b\"2\"],\n        chain_id=\"chain_id\",\n        tx_fee=coins,\n        gas=1234,\n        memo=\"MEMO\",\n        sequences=[1, 2],\n        msgs=[send_msg_packed, send_msg_packed],\n    )\n    assert (\n        isinstance(tx, dict) and len(tx) == 2\n    ), \"Incorrect transfer_transaction constructed.\"\n    assert tx[\"tx\"][\"body\"][\"messages\"][0][\"@type\"] == \"/cosmos.bank.v1beta1.MsgSend\"\n    assert tx[\"tx\"][\"body\"][\"messages\"][1][\"@type\"] == \"/cosmos.bank.v1beta1.MsgSend\"\n\n\n@pytest.mark.integration\n@pytest.mark.ledger\ndef test_multiple_signatures_transaction_missing_pubkeys():\n    \"\"\"Test if generating message with multiple signers without pubkeys fails\"\"\"\n    fetchai_api = FetchAIApi(**FETCHAI_TESTNET_CONFIG)\n\n    coins = [Coin(denom=\"DENOM\", amount=\"1234\")]\n\n    msg_send = MsgSend(\n        from_address=str(\"from\"),\n        to_address=str(\"to\"),\n        amount=coins,\n    )\n    send_msg_packed = ProtoAny()\n    send_msg_packed.Pack(msg_send, type_url_prefix=\"/\")\n\n    with pytest.raises(\n        RuntimeError,\n        match=\"Only transaction with one signer can be generated without pubkeys\",\n    ):\n        fetchai_api._get_transaction(\n            account_numbers=[1, 2],\n            from_addresses=[\"adr1\", \"adr2\"],\n            chain_id=\"chain_id\",\n            tx_fee=coins,\n            gas=1234,\n            memo=\"MEMO\",\n            sequences=[1, 2],\n            msgs=[send_msg_packed, send_msg_packed],\n        )\n\n\n@pytest.mark.integration\n@pytest.mark.ledger\ndef test_multiple_signatures_transaction_wrong_number_of_params():\n    \"\"\"Test if generating message with wrong number of params fails\"\"\"\n    fetchai_api = FetchAIApi(**FETCHAI_TESTNET_CONFIG)\n\n    coins = [Coin(denom=\"DENOM\", amount=\"1234\")]\n\n    msg_send = MsgSend(\n        from_address=str(\"from\"),\n        to_address=str(\"to\"),\n        amount=coins,\n    )\n    send_msg_packed = ProtoAny()\n    send_msg_packed.Pack(msg_send, type_url_prefix=\"/\")\n\n    with pytest.raises(\n        RuntimeError,\n        match=\"Amount of provided from_addresses, sequences and account_numbers is not equal\",\n    ):\n        fetchai_api._get_transaction(\n            account_numbers=[1, 2],\n            from_addresses=[\"adr1\", \"adr2\"],\n            chain_id=\"chain_id\",\n            tx_fee=coins,\n            gas=1234,\n            memo=\"MEMO\",\n            sequences=[1, 2, 3],\n            pub_keys=[b\"123\"],\n            msgs=[send_msg_packed],\n        )\n\n\n@pytest.mark.ledger\ndef test_fail_sign_multisig():\n    \"\"\"Test sign_transaction failed.\"\"\"\n    tx = {\n        \"tx\": {\n            \"body\": {\n                \"messages\": [\n                    OrderedDict(\n                        [\n                            (\"@type\", \"/cosmos.bank.v1beta1.MsgSend\"),\n                            (\n                                \"fromAddress\",\n                                \"fetch17yh6gwf48ac8m2rdmze0sy55l369x6t75972jf\",\n                            ),\n                            (\n                                \"toAddress\",\n                                \"fetch1sf6xalwvvgafcn5lg80358dt8gn7sf4dt0d9vj\",\n                            ),\n                            (\"amount\", [{\"denom\": \"atestfet\", \"amount\": \"10000\"}]),\n                        ]\n                    )\n                ]\n            },\n            \"authInfo\": {\n                \"signerInfos\": [\n                    {\n                        \"publicKey\": OrderedDict(\n                            [(\"@type\", \"/cosmos.crypto.secp256k1.PubKey\")]\n                        ),\n                        \"modeInfo\": {\"single\": {\"mode\": \"SIGN_MODE_DIRECT\"}},\n                    },\n                    {\n                        \"publicKey\": OrderedDict(\n                            [(\"@type\", \"/cosmos.crypto.secp256k1.PubKey\")]\n                        ),\n                        \"modeInfo\": {\"single\": {\"mode\": \"SIGN_MODE_DIRECT\"}},\n                    },\n                ],\n                \"fee\": {\n                    \"amount\": [{\"denom\": \"atestfet\", \"amount\": \"7750000000000000\"}],\n                    \"gasLimit\": \"1550000\",\n                },\n            },\n        },\n        \"sign_data\": {\n            \"fetch17yh6gwf48ac8m2rdmze0sy55l369x6t75972jf\": {\n                \"account_number\": 16964,\n                \"chain_id\": \"dorado-1\",\n            },\n            \"fetch17yh6gwf48ac8m2rdmze0sy55l369x6t75972j1\": {\n                \"account_number\": 16964,\n                \"chain_id\": \"dorado-1\",\n            },\n        },\n    }\n    ec = FetchAICrypto()\n    ec._pritvate_key = FetchAICrypto.generate_private_key()\n    with pytest.raises(\n        RuntimeError,\n        match=r\"Public key can be added during singing only for single message transactions.\",\n    ):\n        ec.sign_transaction(tx)\n\n\n@pytest.mark.ledger\ndef test_send_signed_tx_failed():\n    \"\"\"Test send signed tx failed.\"\"\"\n    tx_signed = {\n        \"tx\": {\n            \"body\": {\n                \"messages\": [\n                    OrderedDict(\n                        [\n                            (\"@type\", \"/cosmos.bank.v1beta1.MsgSend\"),\n                            (\n                                \"fromAddress\",\n                                \"fetch14a92pzm55djc80xhztkz5ccemnm2kem2g5dzvh\",\n                            ),\n                            (\n                                \"toAddress\",\n                                \"fetch127emdsu23u7u8zy7dpjn25ng7f8v5fkmecae0s\",\n                            ),\n                            (\"amount\", [{\"denom\": \"atestfet\", \"amount\": \"10000\"}]),\n                        ]\n                    )\n                ]\n            },\n            \"authInfo\": {\n                \"signerInfos\": [\n                    {\n                        \"publicKey\": OrderedDict(\n                            [\n                                (\"@type\", \"/cosmos.crypto.secp256k1.PubKey\"),\n                                (\"key\", \"A+SP+gGzrTSNwZ3ntRInSVVhRrslSBRMCh3B7OI6oc75\"),\n                            ]\n                        ),\n                        \"modeInfo\": {\"single\": {\"mode\": \"SIGN_MODE_DIRECT\"}},\n                    }\n                ],\n                \"fee\": {\n                    \"amount\": [{\"denom\": \"atestfet\", \"amount\": \"7750000000000000\"}],\n                    \"gasLimit\": \"1550000\",\n                },\n            },\n            \"signatures\": [\n                \"GUy8kL26D3EbK6K4sY4OBbkXpP4PFKXXtO+IqunPoKBUOYV/+iI4sRShJS3uGAejNRGNP/fgM9AwJIwl8z4z+Q==\"\n            ],\n        },\n        \"sign_data\": {\n            \"fetch14a92pzm55djc80xhztkz5ccemnm2kem2g5dzvh\": {\n                \"account_number\": 16991,\n                \"chain_id\": \"dorado-1\",\n            }\n        },\n    }\n    fetchai_api = FetchAIApi(**FETCHAI_TESTNET_CONFIG)\n    resp_mock = MagicMock()\n    resp_mock.tx_response.code = 10\n    with patch.object(fetchai_api.tx_client, \"BroadcastTx\", return_value=resp_mock):\n        assert fetchai_api.send_signed_transaction(tx_signed) is None\n\n\n@pytest.mark.ledger\ndef test_max_gas():\n    \"\"\"Test max gas limit set.\"\"\"\n    coins = [Coin(denom=\"DENOM\", amount=\"1234\")]\n    msg_send = MsgSend(\n        from_address=str(\"from\"),\n        to_address=str(\"to\"),\n        amount=coins,\n    )\n    send_msg_packed = ProtoAny()\n    send_msg_packed.Pack(msg_send, type_url_prefix=\"/\")\n\n    fetchai_api = FetchAIApi(**FETCHAI_TESTNET_CONFIG)\n    tx = fetchai_api._get_transaction(\n        account_numbers=[1, 2],\n        from_addresses=[\"adr1\", \"adr2\"],\n        pub_keys=[b\"1\", b\"2\"],\n        chain_id=\"chain_id\",\n        tx_fee=coins,\n        gas=MAXIMUM_GAS_AMOUNT * 1.5,\n        memo=\"MEMO\",\n        sequences=[1, 2],\n        msgs=[send_msg_packed, send_msg_packed],\n    )\n    assert tx[\"tx\"][\"authInfo\"][\"fee\"][\"gasLimit\"] == str(MAXIMUM_GAS_AMOUNT)\n\n\n@pytest.mark.ledger\ndef test_get_multi_transaction():\n    \"\"\"Test get_multi_transaction.\"\"\"\n    fetchai_api = FetchAIApi(**FETCHAI_TESTNET_CONFIG)\n    msgs: List[ProtoAny] = []\n    gas = 100\n    from_address = \"123123\"\n    to_address = \"23423434\"\n    token_id = \"sdfsf\"\n    from_supply = \"23423443\"\n    contract_address = \"some addr\"\n    to_pubkey = \"\"\n    tx_fee = 123123\n\n    contract_msg = {\n        \"transfer_single\": {\n            \"operator\": str(from_address),\n            \"from_address\": str(from_address),\n            \"to_address\": str(to_address),\n            \"id\": str(token_id),\n            \"value\": str(from_supply),\n        }\n    }\n    msgs.append(\n        fetchai_api.get_packed_exec_msg(\n            sender_address=from_address,\n            contract_address=contract_address,\n            msg=contract_msg,\n            funds=10,\n            denom=\"test\",\n        )\n    )\n    msgs.append(\n        fetchai_api.get_packed_exec_msg(\n            sender_address=from_address,\n            contract_address=contract_address,\n            msg=contract_msg,\n        )\n    )\n    msgs.append(\n        fetchai_api.get_packed_send_msg(\n            from_address=from_address, to_address=contract_address, amount=10\n        )\n    )\n    with patch.object(\n        fetchai_api, \"_try_get_account_number_and_sequence\", return_value=(1, 0)\n    ):\n        tx = fetchai_api.get_multi_transaction(\n            from_addresses=[to_address],\n            pub_keys=[bytes.fromhex(to_pubkey)],\n            msgs=msgs,\n            gas=gas,\n            tx_fee=tx_fee,\n        )\n    assert tx\n"
  },
  {
    "path": "protolint.yaml",
    "content": "lint:\n  rules:\n    remove:\n      - MESSAGE_NAMES_UPPER_CAMEL_CASE\n      - ENUM_FIELD_NAMES_ZERO_VALUE_END_WITH\n      - PACKAGE_NAME_LOWER_CASE\n      - REPEATED_FIELD_NAMES_PLURALIZED\n      - FIELD_NAMES_LOWER_SNAKE_CASE\n      - ENUM_FIELD_NAMES_PREFIX"
  },
  {
    "path": "pyproject.toml",
    "content": "[build-system]\nrequires = [\"poetry-core>=1.1.0\"]\nbuild-backend = \"poetry.core.masonry.api\"\n\n\n[tool.poetry]\nname = \"aea\"\nversion = \"1.2.5\"\ndescription = \"Autonomous Economic Agent framework\"\nauthors = [\"Fetch.AI Limited\"]\nreadme = \"README.md\"\nlicense = \"Apache-2.0\"\nhomepage = \"https://github.com/fetchai/agents-aea\"\nrepository = \"https://github.com/fetchai/agents-aea\"\ndocumentation = \"https://docs.fetch.ai/aea/\"\nkeywords = [\"agent\", \"aea\", \"autonomous\", \"economic\", \"autonomous economic agent\"]\nclassifiers = [\n    \"Environment :: Console\",\n    \"Development Status :: 4 - Beta\",\n    \"Intended Audience :: Developers\",\n    \"Intended Audience :: Education\",\n    \"Intended Audience :: End Users/Desktop\",\n    \"Intended Audience :: Information Technology\",\n    \"Intended Audience :: Science/Research\",\n    \"License :: OSI Approved :: Apache Software License\",\n    \"Natural Language :: English\",\n    \"Operating System :: MacOS\",\n    \"Operating System :: Microsoft :: Windows\",\n    \"Operating System :: Unix\",\n    \"Programming Language :: Python :: 3.8\",\n    \"Programming Language :: Python :: 3.9\",\n    \"Programming Language :: Python :: 3.10\",\n    \"Topic :: Communications\",\n    \"Topic :: Internet\",\n    \"Topic :: Scientific/Engineering\",\n    \"Topic :: Scientific/Engineering :: Artificial Intelligence\",\n    \"Topic :: Software Development\",\n    \"Topic :: System\",\n]\n\n[tool.poetry.scripts]\naea = 'aea.cli:cli'\n\n[tool.poetry.dependencies]\npython = \">=3.8,<3.11\"\nbase58 = \">=1.0.3,<3.0.0\"\njsonschema = \">=3.2.0,<5\"\npackaging = \"^21.0\"\nsemver = \">=2.9.1,<3.0.0\"\nprotobuf = \">=3.19.4,<4\"\npymultihash = \"==0.8.2\"\npyyaml = \">=4.2b1,<6.0\"\nrequests = \">=2.22.0,<3.0.0\"\npython-dotenv = \">=0.14.0,<0.18.0\"\necdsa = \">=0.15,<0.17.0\"\nimportlib-metadata = \">4,<5\"\n\npywin32 = { version = \"==303\", markers = \"sys_platform == 'win32' or platform_system == 'Windows'\" }\n\n# cli, test_tools extras\nclick = { version = \"^8.0.0\", optional = true }\n\n[tool.poetry.extras]\ncli = [\"click\"]\nall = [\"click\"]\n\n[tool.poetry.group.dev]\noptional = true\n\n[tool.poetry.group.dev.dependencies]\ntox = \"^3.26\"\npy-sr25519-bindings = \">=0.1.5,<0.2\"\npylint = \"==2.15.5\"\ncosmpy = \">=0.6.2,<0.7.0\"\nbandit = \"==1.7.4\"\nvulture = \"==2.6\"\nisort = \"==5.10.1\"\nsafety = \"==2.3.5\"\nmypy = \"==0.982\"\ndarglint = \"==1.8.1\"\nflake8 = \"==5.0.4\"\nflake8-bugbear = \"==22.10.25\"\nflake8-docstrings = \"==1.6.0\"\nflake8-eradicate = \"==1.4.0\"\nflake8-isort = \"==5.0\"\nliccheck = \"==0.7.2\"\nblack = \"^22.10\"\n\n[tool.poetry.group.testing]\noptional = true\n\n[tool.poetry.group.testing.dependencies]\npytest = \"^7.2.0\"\npytest-asyncio = \"^0.20.0\"\npytest-cov = \"^4.0.0\"\npytest-custom-exit-code = \"^0.3.0\"\npytest-randomly = \"^3.12.0\"\npytest-rerunfailures = \"^10.2\"\ndocker = \"^4.2.2\"\npexpect = \"^4.8.0\"\nsqlalchemy = \">=1.4.41\"            # used in one test\nmistune = \"^2.0.4\"\nrequests = \"^2.28.0\"\nweb3 = \"==5.31.1\"\n\n[tool.poetry.group.docs]\noptional = true\n\n[tool.poetry.group.docs.dependencies]\nmkdocs-material = \"^9.0.3\"\nmkdocs-mermaid-plugin = { git = \"https://github.com/pugong/mkdocs-mermaid-plugin.git\" }\npydoc-markdown = \"^4.6.3\"\npydocstyle = \"^6.1.1\"\npymdown-extensions = \"^9.7\"\npygments = \">=2.7.4\"\n\n[tool.poetry.group.packages]\noptional = true\n\n[tool.poetry.group.packages.dependencies]\ntensorflow = [\n    { version = \">=2.9,<2.11.0\"},\n]\n# openapi-core = \"==0.13.2\"  # problematic package for poetry. requirede by http server connection\nopenapi-spec-validator = \"==0.2.8\" # required by openapi core and best to pin it here\ngym = \"==0.15.6\"\naiohttp = \"^3.8\"\naioprometheus = \">=20.0.0,<21.0.0\"\nnumpy = \">=1.18.1\"\noef = \">=0.8.1\"\ndefusedxml = \">=0.7.1\"\nscikit-image = \">=0.17.2\"\ncolorlog = \">=4.1.0\"\ntemper-py = \"==0.0.3\"\n\n\n[tool.poetry.group.tools]\noptional = true\n\n[tool.poetry.group.tools.dependencies]\n#benchmark\nmatplotlib = \">=3.3.0,<3.4\"\npsutil = \"^5.9.3\"\nmemory-profiler = \">=0.57.0\"\n# scripts\ngitpython = \"==3.1.14\"\nipfshttpclient = \"==0.8.0a2\"\n\n\n[tool.poetry.group.types]\noptional = true\n\n[tool.poetry.group.types.dependencies]\n# types defenitions for mypy\ntypes-certifi = \"*\"\ntypes-requests = \"*\"\ntypes-setuptools = \"*\"\ntypes-urllib3 = \"*\"\ntypes-click = \"*\"\ntypes-PyYAML = \"*\"\n\n\n[tool.mypy]\npython_version = 3.8\nstrict_optional = true\n\n[[tool.mypy.overrides]]\nmodule = [\n    \"aea/mail/base_pb2\",\n    \"aea/helpers/multiaddr/crypto_pb2\",\n    \"aea/helpers/search/models_pb2\",\n    \"aea/helpers/ipfs/pb/unixfs_pb2\",\n    \"aea/helpers/ipfs/pb/merkledag_pb2\",\n    \"tests/data/generator/t_protocol/*\",\n    \"tests/data/generator/t_protocol_no_ct/*\",\n    \"tests/data/dummy_aea/vendor/*\",\n    \"packages/fetchai/protocols/acn/acn_pb2\",\n    \"packages/fetchai/protocols/aggregation/aggregation_pb2\",\n    \"packages/fetchai/protocols/contract_api/contract_api_pb2\",\n    \"packages/fetchai/protocols/cosm_trade/cosm_trade_pb2\",\n    \"packages/fetchai/protocols/default/default_pb2\",\n    \"packages/fetchai/protocols/fipa/fipa_pb2\",\n    \"packages/fetchai/protocols/gym/gym_pb2\",\n    \"packages/fetchai/protocols/http/http_pb2\",\n    \"packages/fetchai/protocols/ledger_api/ledger_api_pb2\",\n    \"packages/fetchai/protocols/ml_trade/ml_trade_pb2\",\n    \"packages/fetchai/protocols/prometheus/prometheus_pb2\",\n    \"packages/fetchai/protocols/oef_search/oef_search_pb2\",\n    \"packages/fetchai/protocols/signing/signing_pb2\",\n    \"packages/fetchai/protocols/state_update/state_update_pb2\",\n    \"packages/fetchai/protocols/tac/tac_pb2\",\n    \"packages/fetchai/protocols/register/register_pb2\",\n    \"packages/fetchai/protocols/yoti/yoti_pb2\",\n]\nignore_errors = true\n\n[[tool.mypy.overrides]]\nmodule = [\n    \"oef.*\",\n    \"semver.*\",\n    \"werkzeug.*\",\n    \"eth_keys.*\",\n    \"jsonschema.*\",\n    \"dotenv\",\n    \"connexion\",\n    \"eth_account.*\",\n    \"ipfshttpclient.*\",\n    \"win32con.*\",\n    \"win32file.*\",\n    \"pywintypes.*\",\n    \"ecdsa.*\",\n    \"urllib3.*\",\n    \"aea_ledger_fetchai.*\",\n    \"aea_ledger_ethereum.*\",\n    \"aea_ledger_cosmos.*\",\n    \"numpy\",\n    \"gym.*\",\n    \"pytest\",\n    \"docker.*\",\n    \"mistune\",\n    \"git.*\",\n    \"tensorflow.*\",\n    \"temper.*\",\n    \"openapi_core.*\",\n    \"openapi_spec_validator.*\",\n    \"sqlalchemy\",\n    \"defusedxml.*\",\n    \"cosmpy.*\",\n    \"google.*\",\n]\nignore_missing_imports = true\n\n[[tool.mypy.overrides]]\nmodule = [\n    \"packages/fetchai/connections/p2p_libp2p_mailbox/connection\",\n    \"packages/fetchai/connections/p2p_libp2p_client/connection\",\n]\ndisable_error_code = \"attr-defined\"\n\n[tool.isort]\n# for black compatibility\nmulti_line_output = 3\ninclude_trailing_comma = true\nforce_grid_wrap = 0\nuse_parentheses = true\nensure_newline_before_comments = true\nline_length = 88\n# custom configurations\norder_by_type = false\ncase_sensitive = true\nlines_after_imports = 2\nskip = [\n    \"tests/data/dummy_aea/vendor/\",\n    \"tests/data/dummy_aea/skills/dummy\"\n    ]\nskip_glob = \"**/*_pb2.py\"\nknown_first_party = \"aea\"\nknown_packages = \"packages\"\nknown_local_folder = \"tests\"\nsections = [\"FUTURE\",'STDLIB',\"THIRDPARTY\",\"FIRSTPARTY\",\"PACKAGES\",\"LOCALFOLDER\"]\n\n[tool.pylint.'MASTER']\nignore-patterns = [\"__main__.py\",\".*_pb2.py\",\"tac.sh\",\"tac_local.sh\"]\n\n[tool.pylint.'MESSAGES CONTROL']\ndisable = [\"C0103\",\"C0201\",\"C0301\",\"C0302\",\"W0105\",\"W0707\",\"W1202\",\"W1203\",\"R0801\",\"C0209\",\"R1735\"]\n\n# See here for more options: https://www.codeac.io/documentation/pylint-configuration.html\n## Eventually resolve these:\n# W0707: raise-missing-from\n\n## Eventually decide on a logging policy:\n# W1202: logging-format-interpolation\n# W1203: logging-fstring-interpolation\n\n## Keep the following:\n# C0103: invalid-name, # kept as no harm\n# C0201: consider-iterating-dictionary, # kept as no harm\n# C0301: http://pylint-messages.wikidot.com/messages:c0301 > Line too long (%s/%s), # kept as no harm\n# C0302: http://pylint-messages.wikidot.com/messages:c0302 > Too many lines in module (%s) , # kept as no harm\n# W0105: pointless-string-statement, # kept as no harm\n# R0801: similar lines, # too granular\n# C0209: Formatting a regular string which could be a f-string (consider-using-f-string)  # to many usage atm\n# R1735: Consider using {} instead of dict() (use-dict-literal)\n\n[tool.pylint.'IMPORTS']\nignored-modules = [\"bech32\", \"ecdsa\", \"lru\", \"eth_typing\", \"eth_keys\", \"eth_account\", \"ipfshttpclient\", \"werkzeug\", \"openapi_spec_validator\", \"aiohttp\", \"multidict\", \"yoti_python_sdk\", \"defusedxml\", \"gym\", \"fetch\", \"matplotlib\", \"memory_profiler\", \"numpy\", \"oef\", \"openapi_core\", \"psutil\", \"tensorflow\", \"temper\", \"skimage\", \"web3\", \"aioprometheus\", \"pyaes\", \"Crypto\", \"asn1crypto\", \"cosmpy\", \"google\", \"google.protobuf.any_pb2\", \"google.protobuf.struct_pb2\"]\n\n[tool.pylint.'DESIGN']\nmin-public-methods = 1\nmax-public-methods = 36\nmax-returns = 10\nmax-bool-expr = 7\nmax-args = 27\nmax-locals = 31\nmax-statements = 80\nmax-parents = 11\nmax-branches = 24\nmax-attributes = 38\n\n[tool.pylint.'REFACTORING']\nmax-nested-blocks = 6\n\n[tool.pylint.'SPELLING']\n# uncomment to enable\n# spelling-dict=en_US\n\n# List of comma separated words that should not be checked.\nspelling-ignore-words = [\"nocover\", \"pragma\", \"params\", \"multiaddress\", \"multihash\", \"OEF\", \"wrt\", \"Protobuf\", \"protobuf\", \"backend\", \"coroutine\", \"noqa\", \"ascii\", \"asyncio\", \"awaitable\", \"kwargs\", \"multihashing\", \"interoperable\", \"inlining\", \"datamodel\", \"str\", \"sqlite\", \"sql\", \"async\", \"json\", \"boolean\", \"config\", \"pytest\", \"counterparty\", \"Unregister\", \"unregister\", \"behaviours\", \"crypto\", \"cryptos\", \"args\", \"url\", \"tx\", \"testnet\", \"decrypt\", \"validator\", \"env\", \"jsonschema\", \"URI\", \"uri\", \"entrypoint\", \"initialise\", \"ethereum\", \"traceback\", \"fetchai\", \"apis\", \"api\", \"TCPSocketProtocol\", \"instantiation\", \"ip\", \"Haversine\", \"instantiation\", \"enum\", \"nosec\", \"Init\", \"init\", \"Behaviour\", \"className\", \"AEA\", \"aea\", \"schemas\", \"vendorized\", \"subcommand\", \"filesystem\", \"workdir\", \"ctx\", \"yaml\", \"representer\", \"multiprocess\", \"Struct\", \"struct\", \"Serializers\", \"ValueType\", \"serializer\", \"filepath\", \"subprocesses\", \"Teardown\", \"namespace\", \"LF\", \"maddr\", \"profiler\", \"cpu\", \"myfunction\", \"prepend\", \"mydecorator\", \"CLI\", \"subprocess\", \"ComponentId\", \"bool\", \"satisfiable\", \"unsatisfiable\", \"dicts\", \"utils\", \"entrypoints\", \"prepended\", \"coroutines\", \"functools\", \"ctrl\", \"posix\", \"stdin\", \"Posix\", \"tcp\", \"AbstractServer\", \"StreamReaderProtocol\", \"StreamReader\", \"cli\", \"reraise\", \"SafeLoader\", \"SafeDumper\", \"pathlib\", \"coro\", \"runnable\", \"Runnable\", \"PublicId\", \"stdout\", \"netloc\", \"dest\", \"subgraph\", \"subdict\", \"behaviour\", \"Popen\", \"Interprocess\", \"datetime\", \"isort\", \"runtime\", \"toplevel\", \"callables\", \"Enqueue\", \"Kahn's\", \"myagent\", \"fn\", \"cwd\", \"disjunction\", \"cancelled\", \"Pythonic\", \"pythonic\", \"prepends\", \"subclasses\", \"protolint\", \"Protolint\", \"performatives\", \"programmatically\", \"behaviour's\", \"AsyncResult\", \"sys\", \"enqueued\", \"multithread\", \"teardown\", \"satisfiability\", \"dep\", \"overridables\", \"arg\", \"stderr\", \"multithreading\", \"configs\", \"getters\", \"getter\", \"classmethods\", \"enqueue\", \"interprocess\", \"exc\", \"pydocstyle\", \"linter\", \"programme\", \"compositional\", \"formatter\", \"counterparty's\", \"endstates\", \"EndState\", \"AgentContext\", \"disambiguated\", \"prepending\", \"dir\", \"tarfiles\", \"docstyle\", \"msg\", \"func\", \"ComponentType\", \"PosixNamedPipeProtocol\", \"ungrouped\", \"reformats\", \"protoc\", \"DialogueLabel\", \"Metaclass\", \"responder\", \"UtilityParams\", \"ExchangeParams\", \"GoodHoldings\", \"CurrencyHoldings\", \"rb\", \"auth\", \"dirs\", \"symlink\", \"BadParameter\", \"metavar\", \"readme\", \"multithreads\", \"upgrader\", \"src\", \"pid\", \"mypy\", \"outstream\", \"CliRunner\", \"semver\", \"VersionInfo\", \"reinstantiate\", \"pre\", \"ItemId\", \"serializable\", \"repo\", \"upgraders\", \"addr\", \"endstate\", \"performative's\", \"proto\", \"uncomment\", \"Deserialize\", \"fnctl\", \"Sym\", \"cd\", \"ACN\", \"os\", \"ok\", \"SDK\", \"subtypes\", \"JS\", \"fifos\", \"preprocess\", \"dst\", \"overridable\", \"Mixin\", \"unregistration\", \"multithreaded\", \"iterable\", \"txt\", \"ln\", \"py\", \"Util\", \"ClickException\", \"ai\", \"ABI\", \"approver\", \"deployer\", \"trustless\", \"wei\", \"AppRunner\", \"TCPSite\", \"webhook\", \"Webhook\", \"Webhooks\", \"hostname\", \"http\", \"ClientResponse\", \"TLS\", \"soef\", \"xml\", \"unregisters\", \"FET\", \"eth\", \"nft\", \"AbstractEventLoop\", \"aiohttp\", \"uris\", \"StreamWriter\", \"msgs\", \"oef\", \"watchdogging\", \"webhooks\", \"RequestValidator\", \"ACA\", \"alice\", \"faber\", \"RegisterDialogue\", \"fipa\", \"prometheus\", \"TAC\", \"fet\", \"tac\", \"CFP\", \"GymDialogue\", \"RL\", \"LedgerApiDialogue\", \"faber's\", \"AWx\", \"parametrized\", \"FipaDialogue\", \"MlTradeDialogue\", \"carpark\", \"blockchain\", \"counterparties\", \"dec\", \"mins\", \"Calc\", \"vyper\", \"SigningDialogue\", \"modelling\", \"ContractApiDialogue\", \"alice's\", \"quickfix\", \"StateUpdateDialogue\", \"hacky\", \"aea's\", \"dataset\", \"MessageId\", \"cfp\", \"rl\", \"TacDialogue\", \"BaseFipaDialogue\", \"von\", \"maths\", \"Deque\", \"unregistering\", \"yoti\", \"copyable\", \"deepcopy\", \"multiaddresses\", \"logfile\", \"Vous\", \"ipaddress\", \"clargs\", \"IPCChannel\", \"MultiAddr\", \"Rendez\", \"gcc\", \"aioprometheus\", \"getattr\", \"noop\", \"Noop\", \"multiagent\", \"ttfb\", \"rtt\", \"mem\", \"xaxis\", \"superclass\", \"docstring\", \"execreport\", \"benchmarked\", \"ReportPrinter\", \"plt\", \"kb\", \"num\", \"initialised\", \"bytecode\", \"wasm\", \"denom\", \"mainnet\", \"fp\", \"uid\", \"cosmwasm\", \"Conftest\", \"decrypted\", \"initialisation\", \"hmac\", \"plaintext\", \"aes\", \"ipfs\", \"unlinked\", \"ipfshttpclient\", \"gasstation\", \"Ganache\", \"hexbytes\", \"txs\", \"LRU\"]\n\n[tool.coverage.run]\nomit = [\n    \"*/.tox/*\"\n]\n"
  },
  {
    "path": "pytest.ini",
    "content": "[pytest]\nlog_cli = 1\nlog_cli_level = DEBUG\nlog_cli_format = %(asctime)s [%(levelname)8s] %(message)s (%(filename)s:%(lineno)s)\nlog_cli_date_format=%Y-%m-%d %H:%M:%S\n\nmarkers =\n    integration: marks end-to-end tests which require the oef, soef, ledger or other network services\n    unstable: marks test as unstable (won't be run in CI)\n    ledger: marks tests which require ledger test networks (ethereum, cosmos, fetchai); these tests should also be marked 'integration'\n    flaky: marks tests which are flaky and worth re-running\n    sync: marks test for run in sync mode\n\nfilterwarnings =\n    ignore:the imp module is deprecated in favour of importlib:DeprecationWarning\n\tignore:Call to deprecated create function\n    ignore:Couldn't parse \n"
  },
  {
    "path": "scripts/NOTES.md",
    "content": "# Notes for Development\n\n## Threading\n\n- always join the thread. Setting no timeout means the calling thread's execution will block until the thread is terminated (<https://docs.python.org/3/library/threading.html>)\n"
  },
  {
    "path": "scripts/RELEASE_PROCESS.md",
    "content": "\n# Release Process from develop to main\n\n1. Make sure all tests pass, coverage is at 100% and the local branch is in a clean state (nothing to commit). Make sure you have a clean develop virtual environment.\n\n2. Determine the next AEA version (we use [semantic versioning v 2.0.0][semver]). Create a new release branch named \"feature/release-<NEW-VERSION>\" (e.g. feature/release-1.0.0). Switch to this branch. Run `python scripts/bump_aea_version.py --new-version <NEW_VERSION>`. Commit if satisfied.\n\n3. Bump plugin versions if necessary by running `python scripts/update_plugin_versions.py --update \"<PLUGIN_NAME>,<NEW_VERSION>\"`. Commit if satisfied.\n\n4. Check the protocols are up-to-date by running `python scripts/generate_all_protocols.py`. Commit if changes occurred.\n\n5. Bump all the packages to their latest versions by running `python scripts/update_package_versions.py`.\n\n6. Check the package upgrades are correct by running `python scripts/check_packages.py` and `python scripts/check_package_versions_in_docs.py`. Commit if satisfied.\n\n7. Check the docs are up-to-date by running `python scripts/generate_api_docs.py` and `python scripts/check_doc_links.py`. Ensure all API pages are added into `mkdocs.yaml`. Ensure documentation can be built: `make docs`. Commit if satisfied.\n\n8. Write release notes and place them in `HISTORY.md`. Add upgrading tips in `upgrading.md`. If necessary, adjust version references in `SECURITY.md`. Commit if satisfied.\n\n9. Run spell checker `./scripts/spell-check.sh`. Run `pylint --disable all --enable spelling ...`. Commit if required.\n\n10. Open a PR from feature/release-<NEW-VERSION> and merge into develop. \n\n11. Switch to the develop branch, open a PR from develop to main. If there are failures, fix them in a branch off of develop and merge into develop. Repeat until no failure in the develop to main PR.\n\n12. Release packages into registry: `python scripts/deploy_to_registry.py`. You might have to run the script a few times until all packages are updated due to a specific dependency structure.\n\n13. Merge the develop to main PR.\n\n14. Tag version on main.\n\n15. Pull main, make a clean environment (`make new-env` and `poetry shell`).\n\n16. Create a distribution: `make dist`.\n\n17. Publish to PyPI with twine: `twine upload dist/*`. Optionally, publish to Test-PyPI with twine:\n`twine upload --repository-url https://test.pypi.org/legacy/ dist/*`.\n\n18. For each plugin: create a distribution (`python3 setup.py bdist_wheel sdist`) then perform step 17.\n\n> Note, the AEA develop docker image is automatically created as part of the CI process in the develop to main PR.\n\n> If something goes wrong and only needs a small fix, do `LAST_VERSION.post1` as version, apply fixes, push again to PyPI.\n\n[semver]: https://semver.org/spec/v2.0.0.html"
  },
  {
    "path": "scripts/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Scripts for the AEA framework development and deployment.\"\"\"\n"
  },
  {
    "path": "scripts/acn/Dockerfile",
    "content": "FROM ubuntu:20.04\n\nUSER root\n\nRUN apt-get update && apt-get upgrade -y\n\nRUN apt install -y python3 python3-pip\n\n# utils\nRUN apt install -y wget subversion\n\n# golang\nRUN wget https://dl.google.com/go/go1.13.8.linux-amd64.tar.gz && \\\n  tar -xzvf go1.13.8.linux-amd64.tar.gz -C /usr/local && \\\n  export PATH=$PATH:/usr/local/go/bin && echo 'export PATH=$PATH:/usr/local/go/bin' >> ~/.bashrc && \\\n  mkdir $HOME/go\n\nENV PATH=\"${PATH}:/usr/local/go/bin\"\n\n# deployment scripts deps: needed only if configuration checks are enabled\nRUN python3 -m pip install pymultihash ecdsa base58\n\nWORKDIR /acn/\n\n# get node source code\nRUN svn export https://github.com/fetchai/agents-aea/trunk/packages/fetchai/connections/p2p_libp2p/libp2p_node/ /acn/node\n\n# get deployment script\nRUN svn export https://github.com/fetchai/agents-aea/trunk/scripts/acn/run_acn_node_standalone.py /acn/\n\n# build node\nRUN cd /acn/node && go build\n\nEXPOSE 9000\nEXPOSE 11000\nEXPOSE 8080\n\nENTRYPOINT [ \"python3\", \"-u\", \"/acn/run_acn_node_standalone.py\", \"/acn/node/libp2p_node\"]\n\n"
  },
  {
    "path": "scripts/acn/Dockerfile.dev",
    "content": "FROM ubuntu:20.04\n\nUSER root\n\nRUN apt-get update && apt-get upgrade -y\n\nRUN apt install -y python3 python3-pip\n\n# utils\nRUN apt install -y wget\n\n# golang\nRUN wget https://dl.google.com/go/go1.13.8.linux-amd64.tar.gz && \\\n  tar -xzvf go1.13.8.linux-amd64.tar.gz -C /usr/local && \\\n  export PATH=$PATH:/usr/local/go/bin && echo 'export PATH=$PATH:/usr/local/go/bin' >> ~/.bashrc && \\\n  mkdir $HOME/go\n\nENV PATH=\"${PATH}:/usr/local/go/bin\"\n\n# deployment scripts deps: needed only if configuration checks are enabled\nRUN python3 -m pip install pymultihash ecdsa base58\n\nWORKDIR /acn/\n\n# get node source code\nCOPY ./packages/fetchai/connections/p2p_libp2p/libp2p_node /acn/node\n\n# get deployment script\nCOPY ./scripts/acn/run_acn_node_standalone.py /acn/\n\n# build node\nRUN cd /acn/node && go build\n\nEXPOSE 9000\nEXPOSE 11000\nEXPOSE 8080\n\nENTRYPOINT [ \"python3\", \"-u\", \"/acn/run_acn_node_standalone.py\", \"/acn/node/libp2p_node\"]\n\n"
  },
  {
    "path": "scripts/acn/README.md",
    "content": "# Agent Communication Network (ACN)\n\n## Installing the agent communication network (ACN) in Kubernetes using helm\n\n**Requirements:** `helm` needs to be installed.\n\n`helm` provides a quick way of installing and updating existing ACN deployments.\n\n**NOTE:** Please use the provided `values.yaml` file only for deploying test networks as it includes private keys.\n\nTo deploy a test network do the following steps:\n\n1. Build and upload the ACN node image by running `./build_upload_img.sh`. You have to execute this from this folder.\n2. update the image tag (two instances) in the `helm-chart/values.yaml`\n3. `cd helm-chart`\n   **NOTE: Make sure to be in the `agents-p2p-dht-testnet` namespace before proceeding**\n4. If:\n   1. this is the first time deploying: run `helm install agents-dht-test .`\n   2. you are upgrading an existing installation (see if there is one by `helm ls`): run `helm upgrade agents-dht-test .`\n\n### Simple image update\n\nRun `./build_upload_img.sh` and take note of the image tag.\n\nReplace below `IMAGE_TAG_HERE` with the image tag.\n\n``` bash\nkubens agents-p2p-dht-testnet\nkubectl set image sts/acn-node-9005 acn-node=gcr.io/fetch-ai-colearn/acn_node:{IMAGE_TAG_HERE}\nkubectl set image sts/acn-node-9003 acn-node=gcr.io/fetch-ai-colearn/acn_node:{IMAGE_TAG_HERE}\nkubectl set image sts/acn-node-9004 acn-node=gcr.io/fetch-ai-colearn/acn_node:{IMAGE_TAG_HERE}\n\nkubens agents-p2p-dht\nkubectl set image sts/acn-node-9002 acn-node=gcr.io/fetch-ai-colearn/acn_node:{IMAGE_TAG_HERE}\nkubectl set image sts/acn-node-9000 acn-node=gcr.io/fetch-ai-colearn/acn_node:{IMAGE_TAG_HERE}\nkubectl set image sts/acn-node-9001 acn-node=gcr.io/fetch-ai-colearn/acn_node:{IMAGE_TAG_HERE}\n```\n\n## The agent communication network (ACN) Kubernetes deployment script\n\nThe `k8s_deploy_acn_node.py` script provides a configurable, reproducible, and verifiable deployment of the ACN node to a Kubernetes cluster.\nConfiguration of the ACN node, docker image, and Kubernetes is passed through command-line interface. The script will then verify it, generate the\ncorresponding YAML deployment file and finally deploy it.\nThe script can also delete a deployment by appending `--delete` to the CLI arguments used to create the deployment.\n\nThe generated YAML deployment file includes:\n\n- a `statefulSet` to persist ACN node log file across runs\n- a service for restarting the node (pod) in case of failure\n- a `DNSEndpoint` to expose public port\n- a secret to safely upload the node's private key\n\nThe generated YAML deployment file can be saved for future re-deployments by using CLI option `--from-file`.\nOptions `--from-file` and `--delete` can be combined as quick way to delete a previous deployment from Kubernetes cluster.\nOption `--generate-only` can be used to generate the deployment file without submitting it to the cluster.\n\nTo reduce the number of CLI arguments to pass, the script offers defaults for docker and Kubernetes configuration\nthat can be used by setting `--k8s-fetchai-defaults`, `--docker-fetchai-defaults` or `--docker-fetchai-defaults-dev`.\n\n### Usage examples\n\n- deploy a node using CLI options\n\n  ```bash\n  python3 scripts/acn/k8s_deploy_acn_node.py --acn-key-file fet_key_test_1.txt --acn-port 9009 --acn-port-delegate 11009 --k8s-fetchai-defaults --docker-fetchai-defaults-dev\n  ```\n\n- delete deployment using CLI options\n\n  ```bash\n  python3 scripts/acn/k8s_deploy_acn_node.py --acn-key-file fet_key_test_1.txt --acn-port 9009 --acn-port-delegate 11009 --k8s-fetchai-defaults --docker-fetchai-defaults-dev --delete\n  ```\n\n- redeploy using the generated deployment file\n\n  ```bash\n  python3 scripts/acn/k8s_deploy_acn_node.py --from-file .acn_deployment.yaml\n  ```\n\n- delete deployment using the generated deployment file\n\n  ```bash\n  python3 scripts/acn/k8s_deploy_acn_node.py  --from-file .acn_deployment.yaml --delete\n  ```\n"
  },
  {
    "path": "scripts/acn/build_upload_img.sh",
    "content": "#!/usr/bin/env bash\nset -e\n\nVERSION=$(git rev-parse --short HEAD)\n\n# read -p 'Where to upload the image (prod, or sandbox)?: ' envvar\nenvvar=${1:-\"sandbox\"}\nshopt -s nocasematch\ncase \"$envvar\" in\n \"prod\" ) \n   echo \"Production config selected\"\n   REGISTRY=\"gcr.io/fetch-ai-images\"\n   DOCKERFILE=\"Dockerfile.dev\"\n   echo \"Registry to upload is $REGISTRY\"\n   ;;\n \"sandbox\" ) \n   echo \"sandbox config selected\"\n   REGISTRY=\"gcr.io/fetch-ai-sandbox\"\n   DOCKERFILE=\"Dockerfile.dev\"\n   echo \"Registry to upload is $REGISTRY\"\n   ;;\n *) \n   echo \"Wrong env selected. Try again\" \n   echo \"Exiting with exit code 1\"\n   exit 1\n   ;;\nesac\n\nsleep 2\n\ndocker build -t ${REGISTRY}/acn_node:${VERSION} -f ./scripts/acn/${DOCKERFILE} ./\ndocker push ${REGISTRY}/acn_node:${VERSION}\n"
  },
  {
    "path": "scripts/acn/helm-chart/Chart.yaml",
    "content": "apiVersion: v1\ndescription: The agents p2p DHT network\nname: agents-dht\nversion: 0.0.1\nappVersion: 0.0.1\nkeywords:\n- fetch\n- agents\nhome: https://fetch.ai\nsources:\n- https://github.com/fetchai\nicon: https://avatars3.githubusercontent.com/u/40889903"
  },
  {
    "path": "scripts/acn/helm-chart/templates/acnnode.yaml",
    "content": "{{- range $key, $spec := .Values }}\n{{- if eq $key \"acnnodes\" }}\n{{- if $spec.enabled }}\n{{- range $spec.config }}\n---\napiVersion: apps/v1\nkind: StatefulSet\nmetadata:\n  name: acn-node-{{ .p2pport }}\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: acn-node-{{ .p2pport }}\n  serviceName: acn-node-{{ .p2pport }}\n  template:\n    metadata:\n      labels:\n        app: acn-node-{{ .p2pport }}\n      annotations:\n        prometheus.io/scrape: 'true'\n        prometheus.io/port: '8080'\n        prometheus.io/path: '/metrics'\n    spec:\n      initContainers:\n      - name: check-entry-peer\n        image: subfuzion/netcat\n        imagePullPolicy: IfNotPresent\n        command:\n        - sh\n        - -c\n        - if [ -z \"${LATEST_ENTRY_PEER_HOST}\" ]; then exit 0; fi; until nc -w 2 -zv\n          ${LATEST_ENTRY_PEER_HOST} ${LATEST_ENTRY_PEER_PORT}; do echo waiting for\n          ${LATEST_ENTRY_PEER_HOST}:${LATEST_ENTRY_PEER_PORT} ; sleep 2; done;\n        env:\n        - name: LATEST_ENTRY_PEER_HOST\n          value: {{ $.Values.dns.publicdnsname }}\n        - name: LATEST_ENTRY_PEER_PORT\n          value: \"{{ $.Values.acnnodes.bootstrap.p2pport }}\"\n      containers:\n      - name: acn-node \n        image: {{ $.Values.acnnodes.image }}\n        imagePullPolicy: IfNotPresent\n        args: [\"--config-from-env\"]\n        env:\n          - name: AEA_P2P_ID\n            valueFrom:\n              secretKeyRef:\n                key: priv-key\n                name: node-priv-key-{{ .p2pport }}\n          - name: AEA_P2P_URI_PUBLIC\n            value: {{ $.Values.dns.publicdnsname }}:{{ .p2pport }}\n          - name: AEA_P2P_URI\n            value: 127.0.0.1:9000\n          - name: AEA_P2P_DELEGATE_URI\n            value: 127.0.0.1:11000\n          - name: AEA_P2P_URI_MONITORING\n            value: 127.0.0.1:8080\n          - name: AEA_P2P_ENTRY_URIS\n            value: /dns4/{{ $.Values.dns.publicdnsname }}/tcp/{{ $.Values.acnnodes.bootstrap.p2pport }}/p2p/{{ $.Values.acnnodes.bootstrap.peerid }}\n          - name: ACN_LOG_FILE\n            value: /acn_data/libp2p_node_{{ .p2pport }}.log\n          - name: AEA_P2P_CFG_REGISTRATION_DELAY\n            value: \"3.0\"\n          - name: AEA_P2P_CFG_STORAGE_PATH\n            value: /acn_data/agents_record_store_{{ .peerid }}\n\n        {{- if $.Values.acnnodes.resources }}\n        resources: {{- toYaml $.Values.acnnodes.resources | nindent 10 }}\n        {{- end }}\n        ports:\n        - containerPort: 9000\n        - containerPort: 11000\n        - containerPort: 8080\n        volumeMounts:\n        - mountPath: /acn_data\n          name: acn-data\n\n  volumeClaimTemplates:\n  - kind: PersistentVolumeClaim\n    apiVersion: v1 \n    metadata:\n      name: acn-data\n    spec:\n      accessModes:\n      - ReadWriteOnce\n      resources:\n        requests:\n          storage: 20Gi\n---\napiVersion: v1\nkind: Service\nmetadata:\n  name: acn-node-{{ .p2pport }}\nspec:\n  selector:\n    app: acn-node-{{ .p2pport }}\n  ports:\n    - name: tcp-libp2p\n      protocol: TCP\n      port: {{ .p2pport }}\n      targetPort: 9000\n    - name: tcp-delegate\n      protocol: TCP\n      port: {{ .delegateport }}\n      targetPort: 11000\n    - name: tcp-monitoring\n      protocol: TCP\n      port: 8080\n      targetPort: 8080\n{{- end }}\n{{- end }}\n{{- end }}\n{{- end }}\n"
  },
  {
    "path": "scripts/acn/helm-chart/templates/boostrapistio.yaml",
    "content": "{{- range $key, $spec := .Values }}\n{{- if eq $key \"bootstrap\" }}\n{{- if $spec.enabled }}\n---\napiVersion: networking.istio.io/v1alpha3\nkind: Gateway\nmetadata:\n  name: agents-bootstrap-dht-net\nspec:\n  selector:\n    app: {{ $.Values.dns.ingressgw }}\n    istio: ingressgateway\n  servers:\n  {{- range $spec.config }}\n  - hosts:\n    - {{ $.Values.dns.dnsname }}\n    {{- if $.Values.dns.publicdnsname }}\n    - {{ $.Values.dns.publicdnsname }}\n    {{- end }}\n    port:\n      name: tcp-p2pport-{{ .p2pport }}\n      number: {{ .p2pport }}\n      protocol: TCP\n  - hosts:\n    - {{ $.Values.dns.dnsname }}\n    {{- if $.Values.dns.publicdnsname }}\n    - {{ $.Values.dns.publicdnsname }}\n    {{- end }}\n    port:\n      name: tcp-delegateport-{{ .delegateport }}\n      number: {{ .delegateport }}\n      protocol: TCP\n  {{- end }}\n---\napiVersion: networking.istio.io/v1alpha3\nkind: VirtualService\nmetadata:\n  name: agents-bootstrap-dht-net\nspec:\n  gateways:\n  - agents-bootstrap-dht-net\n  hosts:\n  - {{ $.Values.dns.dnsname }}\n  {{- if $.Values.dns.publicdnsname }}\n  - {{ $.Values.dns.publicdnsname }}\n  {{- end }}\n  tcp:\n  {{- range $spec.config }}\n  - match:\n    - port: {{ .p2pport }}\n    route:\n    - destination:\n        host: acn-node-{{ .p2pport }}\n        port:\n          number: {{ .p2pport }}\n  - match:\n    - port: {{ .delegateport }}\n    route:\n    - destination:\n        host: acn-node-{{ .p2pport }}\n        port:\n          number: {{ .delegateport }}\n  {{- end }}\n{{- end }}\n{{- end }}\n{{- end }}"
  },
  {
    "path": "scripts/acn/helm-chart/templates/bootstrapnode.yaml",
    "content": "{{- range $key, $spec := .Values }}\n{{- if eq $key \"bootstrap\" }}\n{{- if $spec.enabled }}\n{{- range $spec.config }}\n---\napiVersion: apps/v1\nkind: StatefulSet\nmetadata:\n  name: acn-node-{{ .p2pport }}\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: acn-node-{{ .p2pport }}\n  serviceName: acn-node-{{ .p2pport }}\n  template:\n    metadata:\n      labels:\n        app: acn-node-{{ .p2pport }}\n      annotations:\n        prometheus.io/scrape: 'true'\n        prometheus.io/port: '8080'\n        prometheus.io/path: '/metrics'\n    spec:\n      containers:\n      - name: acn-node \n        image: {{ $.Values.bootstrap.image }}\n        imagePullPolicy: IfNotPresent\n        args: [\"--config-from-env\"]\n        env:\n          - name: AEA_P2P_ID\n            valueFrom:\n              secretKeyRef:\n                key: priv-key\n                name: node-priv-key-{{ .p2pport }}\n          - name: AEA_P2P_URI_PUBLIC\n            value: {{ $.Values.dns.publicdnsname }}:{{ .p2pport }}\n          - name: AEA_P2P_URI\n            value: 127.0.0.1:9000\n          - name: AEA_P2P_DELEGATE_URI\n            value: 127.0.0.1:11000\n          - name: AEA_P2P_URI_MONITORING\n            value: 127.0.0.1:8080\n          - name: ACN_LOG_FILE\n            value: /acn_data/libp2p_node_{{ .p2pport }}.log\n\n        {{- if $.Values.bootstrap.resources }}\n        resources: {{- toYaml $.Values.bootstrap.resources | nindent 10 }}\n        {{- end }}\n        ports:\n        - containerPort: 9000\n        - containerPort: 11000\n        - containerPort: 8080\n        volumeMounts:\n        - mountPath: /acn_data\n          name: acn-data\n\n  volumeClaimTemplates:\n  - kind: PersistentVolumeClaim\n    apiVersion: v1 \n    metadata:\n      name: acn-data\n    spec:\n      accessModes:\n      - ReadWriteOnce\n      resources:\n        requests:\n          storage: 2Gi\n---\napiVersion: v1\nkind: Service\nmetadata:\n  name: acn-node-{{ .p2pport }}\nspec:\n  selector:\n    app: acn-node-{{ .p2pport }}\n  ports:\n    - name: tcp-libp2p\n      protocol: TCP\n      port: {{ .p2pport }}\n      targetPort: 9000\n    - name: tcp-delegate\n      protocol: TCP\n      port: {{ .delegateport }}\n      targetPort: 11000\n    - name: tcp-monitoring\n      protocol: TCP\n      port: 8080\n      targetPort: 8080\n{{- end }}\n{{- end }}\n{{- end }}\n{{- end }}\n"
  },
  {
    "path": "scripts/acn/helm-chart/templates/bootstrapsecret.yaml",
    "content": "{{- range $key, $spec := .Values }}\n{{- if eq $key \"bootstrap\" }}\n{{- if $spec.enabled }}\n{{- range $spec.config }}\n---\napiVersion: v1\nkind: Secret\nmetadata:\n  name: node-priv-key-{{ .p2pport }}\ntype: Opaque\ndata:\n  priv-key: {{ .privkey }}\n{{- end }}\n{{- end }}\n{{- end }}\n{{- end }}\n"
  },
  {
    "path": "scripts/acn/helm-chart/templates/dns.yaml",
    "content": "{{- range $key, $spec := .Values }}\n{{- if eq $key \"dns\" }}\n{{- if $spec.enabled }}\n---\napiVersion: externaldns.k8s.io/v1alpha1\nkind: DNSEndpoint\nmetadata:\n  name: agents-dht-net\nspec:\n  endpoints:\n  - dnsName:  {{ $.Values.dns.dnsname}}\n    recordTTL: 180\n    recordType: CNAME\n    targets:\n    - {{ $.Values.dns.targetgw }}\n{{- end }}\n{{- end }}\n{{- end }}\n"
  },
  {
    "path": "scripts/acn/helm-chart/templates/istio.yaml",
    "content": "{{- range $key, $spec := .Values }}\n{{- if eq $key \"acnnodes\" }}\n{{- if $spec.enabled }}\n---\napiVersion: networking.istio.io/v1alpha3\nkind: Gateway\nmetadata:\n  name: agents-dht-net\nspec:\n  selector:\n    app: {{ $.Values.dns.ingressgw }}\n    istio: ingressgateway\n  servers:\n  {{- range $spec.config }}\n  - hosts:\n    - {{ $.Values.dns.dnsname }}\n    {{- if $.Values.dns.publicdnsname }}\n    - {{ $.Values.dns.publicdnsname }}\n    {{- end }}\n    port:\n      name: tcp-p2pport-{{ .p2pport }}\n      number: {{ .p2pport }}\n      protocol: TCP\n  - hosts:\n    - {{ $.Values.dns.dnsname }}\n    {{- if $.Values.dns.publicdnsname }}\n    - {{ $.Values.dns.publicdnsname }}\n    {{- end }}\n    port:\n      name: tcp-delegateport-{{ .delegateport }}\n      number: {{ .delegateport }}\n      protocol: TCP\n  {{- end }}\n---\napiVersion: networking.istio.io/v1alpha3\nkind: VirtualService\nmetadata:\n  name: agents-dht-net\nspec:\n  gateways:\n  - agents-dht-net\n  hosts:\n  - {{ $.Values.dns.dnsname }}\n  {{- if $.Values.dns.publicdnsname }}\n  - {{ $.Values.dns.publicdnsname }}\n  {{- end }}\n  tcp:\n  {{- range $spec.config }}\n  - match:\n    - port: {{ .p2pport }}\n    route:\n    - destination:\n        host: acn-node-{{ .p2pport }}\n        port:\n          number: {{ .p2pport }}\n  - match:\n    - port: {{ .delegateport }}\n    route:\n    - destination:\n        host: acn-node-{{ .p2pport }}\n        port:\n          number: {{ .delegateport }}\n  {{- end }}\n{{- end }}\n{{- end }}\n{{- end }}"
  },
  {
    "path": "scripts/acn/helm-chart/templates/secret.yaml",
    "content": "{{- range $key, $spec := .Values }}\n{{- if eq $key \"acnnodes\" }}\n{{- if $spec.enabled }}\n{{- range $spec.config }}\n---\napiVersion: v1\nkind: Secret\nmetadata:\n  name: node-priv-key-{{ .p2pport }}\ntype: Opaque\ndata:\n  priv-key: {{ .privkey }}\n{{- end }}\n{{- end }}\n{{- end }}\n{{- end }}\n"
  },
  {
    "path": "scripts/acn/helm-chart/values.yaml",
    "content": "# The values here are only for testing. These are not deployed in the production environment\n# DON'T add enything secret here and upload to the git repo\ndns:\n  enabled: true\n  dnsname: agents-dht-testnet.colearn.fetch-ai.com\n  publicdnsname: acn.fetch-ai.com\n  ingressgw: istio-agentsig\n  targetgw: agentsig.colearn.fetch-ai.com\n\nacnnodes:\n  enabled: true\n  image: gcr.io/fetch-ai-colearn/acn_node:003d81c00\n  resources:\n    limits:\n      cpu: 500m\n      memory: 512Mi\n    requests:\n      cpu: 150m\n      memory: 64Mi\n  config:\n    - p2pport: 9003\n      delegateport: 11003\n      privkey: ODE5MzM0MWZhYTFiMjZmZWNmNGJlM2E3ZTdmYzJkZTc0MGE0MzA5OWIxNWMyZjQwNWI2OTBmOWM4NmJjMjAwNA==\n      peerid: 16Uiu2HAkwRr8R4riKhxiCy2a5E4J6t4Cvxnkxasu9uRRyjJ9NGfS\n    - p2pport: 9004\n      delegateport: 11004\n      privkey: ZDg5MWU4ZjAyMjAzYzk3YWE5YjlmODg4Nzk0MjM3NDU4YzRhODA3M2ViYTFlYzI1MzEzOGIxNDRjNDMyZGFkNg==\n      peerid: 16Uiu2HAm1nE7eM1c3GJrbzKZCtBHkuTyoYU4vZo5i1Xo7HzziBYx\n  bootstrap:\n    p2pport: 9005\n    peerid: 16Uiu2HAm5TasPqYqLSBwKw6MKUHLZUmSsnXrbisSGNcXNEqVTpqH\n\nbootstrap:\n  enabled: true\n  image: gcr.io/fetch-ai-colearn/acn_node:003d81c00\n  resources:\n    limits:\n      cpu: 500m\n      memory: 512Mi\n    requests:\n      cpu: 150m\n      memory: 64Mi\n  config:\n    - p2pport: 9005\n      delegateport: 11005\n      privkey: MmM0MjE1MWRmNzQzNzFkZTJmZDQ1MzUyMGY4NzIzYzI1OWFiMTlhZjUxMTkxNDRiNmVhYjcwZjhmYTQzYTE1Zg==\n      peerid: 16Uiu2HAm5TasPqYqLSBwKw6MKUHLZUmSsnXrbisSGNcXNEqVTpqH\n"
  },
  {
    "path": "scripts/acn/k8s/deployment.yaml",
    "content": "apiVersion: v1\nkind: Service\nmetadata:\n  name: ph-deployment-name-here\n  namespace: ph-deployment-namespace-here\nspec:\n  selector:\n    app: ph-deployment-name-here\n  ports:\n    - name: tcp-libp2p\n      protocol: TCP\n      port: ph-node-port-number-here\n      targetPort: 9000\n    - name: tcp-delegate\n      protocol: TCP\n      port: ph-node-delegate-port-number-here\n      targetPort: 11000\n    - name: tcp-monitoring\n      protocol: TCP\n      port: 8080\n      targetPort: 8080\n---\napiVersion: apps/v1\nkind: StatefulSet\nmetadata:\n  name: ph-deployment-name-here\n  namespace: ph-deployment-namespace-here\n  labels:\n    app: ph-deployment-name-here\nspec:\n  serviceName: ph-deployment-name-here\n  replicas: number-of-replicas\n  selector:\n    matchLabels:\n      app: ph-deployment-name-here \n  template:\n    metadata:\n      labels:\n        app: ph-deployment-name-here\n\n    spec:\n      terminationGracePeriodSeconds: 10\n      initContainers:\n      - name: check-entry-peer\n        image: subfuzion/netcat\n        command: ['sh', '-c', \n          'if [ -z \"${LATEST_ENTRY_PEER_HOST}\" ]; then exit 0; fi; until nc -w 2 -zv ${LATEST_ENTRY_PEER_HOST} ${LATEST_ENTRY_PEER_PORT}; do echo waiting for ${LATEST_ENTRY_PEER_HOST}:${LATEST_ENTRY_PEER_PORT} ; sleep 2; done;']\n        env:\n          - name: LATEST_ENTRY_PEER_HOST\n            value: ph-latest-entry-peer-host-here\n          - name: LATEST_ENTRY_PEER_PORT\n            value: ph-latest-entry-peer-port-here\n     \n      containers:\n      - image: ph-gcr-image-with-tag-here\n        name: acn-node\n        args: [\"--config-from-env\"]\n        ports:\n        - containerPort: ph-node-port-number-here\n        - containerPort: ph-node-delegate-port-number-here\n\n        resources:\n          requests:\n            memory: \"64Mi\"\n            cpu: \"150m\"\n          limits:\n            memory: \"4000Mi\"\n            cpu: \"2000m\"\n        volumeMounts:\n        - name: acn-data\n          mountPath: /acn_data\n        \n        env:\n          - name: AEA_P2P_ID \n            valueFrom:\n              secretKeyRef:\n                name: ph-node-priv-key-name-here\n                key: priv-key\n          - name: AEA_P2P_URI_PUBLIC\n            value: ph-node-external-uri-here\n          - name: AEA_P2P_URI\n            value: ph-node-local-uri-here\n          - name: AEA_P2P_DELEGATE_URI\n            value: ph-node-delegate-uri-here\n          - name: AEA_P2P_URI_MONITORING\n            value: ph-node-monitoring-uri-here\n          - name: AEA_P2P_ENTRY_URIS\n            value: ph-node-entry-peers-list-here\n          - name: ACN_LOG_FILE\n            value: ph-node-log-file-path-here\n\n      restartPolicy: Always\n\n  volumeClaimTemplates:\n  - metadata:\n      name: acn-data\n    spec:\n      accessModes: [ \"ReadWriteOnce\" ]\n      resources:\n        requests:\n          storage: 2Gi"
  },
  {
    "path": "scripts/acn/k8s/dns.yaml",
    "content": "---\napiVersion: externaldns.k8s.io/v1alpha1\nkind: DNSEndpoint\nmetadata:\n  name: ph-deployment-name-here \n  namespace: ph-deployment-namespace-here\nspec:\n  endpoints:\n  - dnsName:  ph-deployment-dns-here\n    recordTTL: 180\n    recordType: CNAME\n    targets:\n    - fetchpub.sandbox.fetch-ai.com\n"
  },
  {
    "path": "scripts/acn/k8s/istio.yaml",
    "content": "---\napiVersion: networking.istio.io/v1alpha3\nkind: Gateway\nmetadata:\n  name: ph-deployment-name-here\n  namespace: ph-deployment-namespace-here\nspec:\n  selector:\n    app: istio-fetchpubig\n    istio: ingressgateway\n  servers:\n  - port:\n      name: libp2p\n      number: ph-node-port-number-here\n      protocol: TCP\n    hosts:\n    - ph-deployment-dns-here\n  - port:\n      name: tcp\n      number: ph-node-delegate-port-number-here\n      protocol: TCP\n    hosts:\n    - ph-deployment-dns-here\n---\napiVersion: networking.istio.io/v1alpha3\nkind: VirtualService\nmetadata:\n  name: ph-deployment-name-here\n  namespace: ph-deployment-namespace-here\nspec:\n  gateways:\n  - ph-deployment-name-here\n  hosts:\n  - ph-deployment-dns-here\n  tcp:\n  - match:\n    - port: ph-node-port-number-here\n    route:\n    - destination:\n        host: ph-deployment-name-here\n        port:\n          number: ph-node-port-number-here\n  - match:\n    - port: ph-node-delegate-port-number-here\n    route:\n    - destination:\n        host: ph-deployment-name-here\n        port:\n          number: ph-node-delegate-port-number-here\n"
  },
  {
    "path": "scripts/acn/k8s/secret.yaml",
    "content": "apiVersion: v1\nkind: Secret\nmetadata:\n  name: ph-node-priv-key-name-here\ntype: Opaque\ndata:\n  priv-key: ph-base64-encoded-private-key-here"
  },
  {
    "path": "scripts/acn/k8s_deploy_acn_node.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Deploy an ACN libp2p node to a kubernetes cluster\"\"\"\n\nimport argparse\nimport base64\nimport os\nimport subprocess  # nosec\nimport sys\nfrom datetime import datetime\nfrom pathlib import Path\nfrom typing import Any, Dict, List, Optional, Tuple, Type\n\n\nSCRIPT_DIR = os.path.abspath(os.path.dirname(os.path.realpath(__file__)))\n\nsys.path.append(SCRIPT_DIR)\nfrom run_acn_node_standalone import (  # noqa # pylint: disable=wrong-import-position # isort:skip\n    AcnNodeConfig,\n)\n\n# docker defaults\nDOCKER_FETCHAI_DEFAULT_FILE = os.path.join(SCRIPT_DIR, \"Dockerfile\")\nDOCKER_FETCHAI_DEFAULT_FILE_DEV = os.path.join(SCRIPT_DIR, \"Dockerfile.dev\")\nDOCKER_FETCHAI_DEFAULT_CTX = SCRIPT_DIR\nDOCKER_FETCHAI_DEFAULT_CTX_DEV = os.path.join(SCRIPT_DIR, \"../../\")\nDOCKER_FETCHAI_DEFAULT_IMG = \"acn_node\"\nDOCKER_FETCHAI_DEFAULT_REGISTRY = \"gcr.io/fetch-ai-sandbox\"\n\n# k8s defaults\nK8S_FETCHAI_DEFAULT_PUBLIC_HOST = \"acn.fetch.ai\"\nK8S_FETCHAI_DEFAULT_PUBLIC_TEMPLATE_DIR = os.path.join(SCRIPT_DIR, \"k8s\")\nK8S_FETCHAI_DEFAULT_NAMESPACE = \"agents-p2p-dht\"\n\n\ndef _execute_cmd(cmd: List[str]) -> Tuple[str, bool]:\n    \"\"\"\n    Run command as subprocess and wait for its termination\n\n    :param cmd: command with arguments to execute\n    :return: output of the command execution and execution success\n    \"\"\"\n\n    print(\"-> Running: {}\".format(cmd))\n    proc = subprocess.Popen(cmd, shell=False, stdout=subprocess.PIPE)  # nosec\n    out, _ = proc.communicate()\n    success = False\n    try:\n        if proc.wait() == 0:\n            success = True\n    except (\n        subprocess.CalledProcessError,  # pylint: disable=broad-except\n        Exception,\n    ) as e:\n        print(\"_excute_cmd caught exception: {}\".format(str(e)))\n    print(\"-| Output :\\n{}\".format(out.decode(\"ascii\")))\n    return out.decode(\"ascii\"), success\n\n\nclass DockerDeployment:\n    \"\"\"Build and Publish a Dockerfile\"\"\"\n\n    def __init__(\n        self, dockerfile: str, context: str, image: str, tag: str, registry: str\n    ):\n        \"\"\"\n        Initialize a DockerDeployment object\n\n        :param dockerfile: path to the Dockerfile\n        :param context: path to docker image context\n        :param image: built image name\n        :param tag: built image tag\n        :param registry: registry to publish the image to\n        \"\"\"\n\n        self.dockerfile = dockerfile\n        self.context = context\n        self.image = image\n        self.tag = tag\n        self.registry = registry\n\n    def build_and_publish(self) -> bool:\n        \"\"\"\n        Build the image and publich it to registry\n\n        :return: success of the operation\n        \"\"\"\n\n        cmds: List[List[str]] = []\n\n        cmds.append(\n            [\n                \"docker\",\n                \"build\",\n                \"-t\",\n                \"{}:{}\".format(self.image, self.tag),\n                \"-f\",\n                self.dockerfile,\n                self.context,\n            ]\n        )\n        cmds.append(\n            [\n                \"docker\",\n                \"tag\",\n                \"{}:{}\".format(self.image, self.tag),\n                \"{}/{}:{}\".format(self.registry, self.image, self.tag),\n            ]\n        )\n        cmds.append(\n            [\"docker\", \"push\", \"{}/{}:{}\".format(self.registry, self.image, self.tag)]\n        )\n\n        for cmd in cmds:\n            _, ok = _execute_cmd(cmd)\n            if not ok:\n                return False\n\n        return True\n\n\nclass K8sPodDeployment:\n    \"\"\"An application-agnostic deployment object\"\"\"\n\n    def __init__(\n        self,\n        deployments_files: List[Path],\n        docker_deployment: Optional[DockerDeployment],\n    ):\n        \"\"\"\n        Initialize a K8sPodDeployment object\n\n        :param deployments_files: list of kubernetes yaml files to deploy\n        :param docker_deployment: optional DockerDeployment to build and publish\n        \"\"\"\n        self.deployment_files = deployments_files\n        self.docker_deployment = docker_deployment\n\n    def deploy(self) -> bool:\n        \"\"\"\n        Deploy to k8s cluster\n\n        :return: success of the operation\n        \"\"\"\n\n        ok = True\n        if self.docker_deployment:\n            ok = self.docker_deployment.build_and_publish()\n            if not ok:\n                return ok\n        for yaml in self.deployment_files:\n            cmd = [\"kubectl\", \"apply\", \"-f\", str(yaml)]\n            _, ok = _execute_cmd(cmd)\n            if not ok:\n                break\n        return ok\n\n    def delete(self) -> bool:\n        \"\"\"\n        Delete deployment from k8s cluster\n\n        :return: success of the operation\n        \"\"\"\n        ok = True\n        for yaml in self.deployment_files:\n            cmd = [\"kubectl\", \"delete\", \"-f\", str(yaml)]\n            _, ok = _execute_cmd(cmd)\n            if not ok:\n                break\n        return ok\n\n\nclass AcnK8sPodConfig:\n    \"\"\"Store, parse, and generate kubernetes deployment for an ACN node\"\"\"\n\n    K8S_DEPLOYMENT_NAME = \"ph-deployment-name-here\"\n    K8S_NUMBER_OF_REPLICAS = \"number-of-replicas\"\n    DEFAULT_K8S_NUMBER_OF_REPLICAS = 2\n    K8S_NAMESPACE = \"ph-deployment-namespace-here\"\n    K8S_PUBLIC_DNS = \"ph-deployment-dns-here\"\n\n    DOCKER_IMAGE_REMOTE_WITH_TAG = \"ph-gcr-image-with-tag-here\"\n\n    NODE_PORT = \"ph-node-port-number-here\"\n    NODE_PORT_DELEGATE = \"ph-node-delegate-port-number-here\"\n    NODE_PORT_MONITORING = \"ph-node-monitoring-port-number-here\"\n    NODE_URI_EXTERNAL = \"ph-node-external-uri-here\"\n    NODE_URI = \"ph-node-local-uri-here\"\n    NODE_URI_DELEGATE = \"ph-node-delegate-uri-here\"\n    NODE_URI_MONITORING = \"ph-node-monitoring-uri-here\"\n    NODE_ENTRY_PEERS = \"ph-node-entry-peers-list-here\"\n    NODE_KEY_NAME = \"ph-node-priv-key-name-here\"\n    NODE_KEY_ENCODED = \"ph-base64-encoded-private-key-here\"\n    NODE_LAST_ENTRY_PEER_HOST = \"ph-latest-entry-peer-host-here\"\n    NODE_LAST_ENTRY_PEER_PORT = \"ph-latest-entry-peer-port-here\"\n    NODE_LOG_FILE = \"ph-node-log-file-path-here\"\n    # class defaults\n    Defaults: Dict[str, str] = {\n        K8S_DEPLOYMENT_NAME: \"acn-node\",\n        NODE_LOG_FILE: \"/acn_data/libp2p_node\",\n    }\n\n    def __init__(\n        self,\n        acn_key_file: str,\n        acn_port: int,\n        acn_delegate_port: int,\n        acn_monitoring_port: int,\n        acn_entry_peers: Optional[List[str]],\n        docker_file: str,\n        docker_context: str,\n        docker_image: str,\n        docker_registry: str,\n        k8s_public_hostname: str,\n        k8s_namespace: str,\n        k8s_template_files_dir: str,\n        k8s_number_of_replicas: Optional[int],\n        enable_checks: bool = True,\n    ):\n        \"\"\"\n        Initialize a AcnK8sPodConfig, populate the config dictionary\n\n        :param acn_key_file: path to the acn node private key\n        :param acn_port: acn node port number\n        :param acn_delegate_port: acn node delegate service port number\n        :param acn_monitoring_port: acn node monitoring service port number\n        :param acn_entry_peers: optional list of acn node entry peers multiaddresses\n        :param docker_file: path to Dockerfile\n        :param docker_context: path to Dockerfile context\n        :param docker_image: docker image name\n        :param docker_registry: url of remote docker registry to push image to\n        :param k8s_public_hostname: public dns for acn node's external uri\n        :param k8s_namespace: k8s namespace to deploy node to\n        :param k8s_template_files_dir: path to directory containing k8s yaml deployment templates\n        :param enable_checks: enable configuration checks\n        :param k8s_number_of_replicas: number of replica pods to run\n        \"\"\"\n\n        config: Dict[str, str] = {}\n        cls: Type[AcnK8sPodConfig] = AcnK8sPodConfig\n\n        k8s_number_of_replicas = (\n            k8s_number_of_replicas or self.DEFAULT_K8S_NUMBER_OF_REPLICAS\n        )\n\n        # acn node configuration\n        config[cls.NODE_KEY_NAME] = \"node-priv-key-{}\".format(acn_port)\n        config[cls.NODE_PORT] = str(acn_port)\n        config[cls.NODE_PORT_DELEGATE] = str(acn_delegate_port)\n        config[cls.NODE_PORT_MONITORING] = str(acn_monitoring_port)\n        config[cls.NODE_ENTRY_PEERS] = (\n            \",\".join(acn_entry_peers) if acn_entry_peers is not None else \"\"\n        )\n        config[cls.NODE_ENTRY_PEERS] = '\"{}\"'.format(config[cls.NODE_ENTRY_PEERS])\n        peer_host, peer_port = cls._uri_from_multiaddr(\n            acn_entry_peers[-1]\n            if acn_entry_peers is not None and len(acn_entry_peers) > 0\n            else \"\"\n        )\n        config[cls.NODE_LAST_ENTRY_PEER_HOST] = '\"{}\"'.format(peer_host)\n        config[cls.NODE_LAST_ENTRY_PEER_PORT] = '\"{}\"'.format(peer_port)\n\n        config[cls.NODE_URI] = \"127.0.0.1:9000\"\n        config[cls.NODE_URI_DELEGATE] = \"127.0.0.1:11000\"\n        config[cls.NODE_URI_MONITORING] = \"127.0.0.1:8080\"\n        config[cls.NODE_URI_EXTERNAL] = \"{}:{}\".format(k8s_public_hostname, acn_port)\n        config[cls.NODE_LOG_FILE] = '\"{}_{}.log\"'.format(\n            cls.Defaults[cls.NODE_LOG_FILE], str(acn_port)\n        )\n\n        with open(acn_key_file, \"r\") as f:\n            key = f.read().strip()\n            config[cls.NODE_KEY_ENCODED] = base64.b64encode(key.encode(\"ascii\")).decode(\n                \"ascii\"\n            )\n\n        # k8s configuration\n        config[cls.K8S_NUMBER_OF_REPLICAS] = str(k8s_number_of_replicas)\n        config[cls.K8S_DEPLOYMENT_NAME] = \"{}-{}\".format(\n            cls.Defaults[cls.K8S_DEPLOYMENT_NAME], str(acn_port)\n        )\n        config[cls.K8S_NAMESPACE] = k8s_namespace\n        config[cls.K8S_PUBLIC_DNS] = k8s_public_hostname\n\n        files: List[Path] = []\n        for path in [\n            Path(os.path.join(k8s_template_files_dir, p))\n            for p in os.listdir(k8s_template_files_dir)\n        ]:\n            if path.is_file() and path.suffix == \".yaml\":\n                files.append(path)\n        assert (\n            len(files) > 0\n        ), f\"Couldn't find any template deployment file at {k8s_template_files_dir}\"\n\n        # docker configuration\n        cmd = [\"git\", \"describe\", \"--no-match\", \"--always\", \"--dirty\"]\n        docker_tag, ok = _execute_cmd(cmd)\n        if not ok:\n            docker_tag = datetime.now().strftime(\"%d-%m-%Y_%H-%M-%S\")\n        else:\n            docker_tag = docker_tag.strip()\n        config[cls.DOCKER_IMAGE_REMOTE_WITH_TAG] = \"{}/{}:{}\".format(\n            docker_registry, docker_image, docker_tag.strip()\n        )\n\n        self.config = config\n        self.template_files = files\n        self.docker_deployment = DockerDeployment(\n            docker_file, docker_context, docker_image, docker_tag, docker_registry\n        )\n\n        if enable_checks:\n            cls.check_config(self.config)\n\n    @staticmethod\n    def _uri_from_multiaddr(maddr: str) -> Tuple[str, str]:\n        if maddr != \"\":\n            parts = maddr.split(\"/\")\n            if len(parts) == 7:\n                return parts[2], parts[4]\n        return \"\", \"\"\n\n    @staticmethod\n    def check_config(config: Dict[str, str]) -> None:\n        \"\"\"\n        Check an AcnK8sPodConfig deployment for correct configuration\n\n        :param config: dictionary of configuration to check\n        \"\"\"\n        AcnNodeConfig(\n            base64.b64decode(\n                config[AcnK8sPodConfig.NODE_KEY_ENCODED].encode(\"ascii\")\n            ).decode(\"ascii\"),\n            config[AcnK8sPodConfig.NODE_URI],\n            config[AcnK8sPodConfig.NODE_URI_EXTERNAL],\n            config[AcnK8sPodConfig.NODE_URI_DELEGATE],\n            config[AcnK8sPodConfig.NODE_URI_MONITORING],\n            config[AcnK8sPodConfig.NODE_ENTRY_PEERS].strip('\"').split(\",\"),\n            \"\",\n            True,\n        )\n\n    def generate_deployment(self) -> K8sPodDeployment:\n        \"\"\"\n        Generate deployment for the current configuration\n\n        :return: deployment object\n        \"\"\"\n\n        deployment_file = \".acn_deployment.yaml\"\n        out = open(deployment_file, \"w\")\n\n        for path in self.template_files:\n            with open(path, \"r\") as f:\n                content = f.read()\n\n            for placeholder, value in self.config.items():\n                content = content.replace(placeholder, value)\n\n            out.write(content)\n            out.write(\"\\n---\\n\")\n\n        out.close()\n\n        return K8sPodDeployment([Path(deployment_file)], self.docker_deployment)\n\n\ndef parse_commandline():\n    \"\"\"Parse script cl arguments\"\"\"\n\n    parser = argparse.ArgumentParser()\n    parser.add_argument(\n        \"--from-file\",\n        action=\"store\",\n        type=str,\n        dest=\"from_file\",\n        required=False,\n        help=\"Use previously generated deployment\",\n    )\n    parser.add_argument(\n        \"--delete\",\n        action=\"store_true\",\n        dest=\"delete_deployment\",\n        required=False,\n        help=\"Delete an already deployed node with the same configuration\",\n    )\n    parser.add_argument(\n        \"--generate-only\",\n        action=\"store_true\",\n        dest=\"generate_only\",\n        required=False,\n        help=\"Don't deploy the generated yaml file\",\n    )\n    parser.add_argument(\n        \"--acn-key-file\",\n        action=\"store\",\n        type=str,\n        dest=\"key\",\n        required=False,\n        help=\"acn node's private key file\",\n    )\n    parser.add_argument(\n        \"--acn-port\",\n        action=\"store\",\n        type=int,\n        dest=\"port\",\n        required=False,\n        help=\"acn node's external port number. Internal is 9000\",\n    )\n    parser.add_argument(\n        \"--acn-port-delegate\",\n        action=\"store\",\n        type=int,\n        dest=\"delegate_port\",\n        required=False,\n        help=\"acn node's delegate external service port number. Internal is 11000\",\n    )\n    parser.add_argument(\n        \"--acn-port-monitoring\",\n        action=\"store\",\n        type=int,\n        dest=\"monitoring_port\",\n        required=False,\n        default=8080,\n        help=\"acn node's monitoring service port number (local only)\",\n    )\n    parser.add_argument(\n        \"--acn-entry-peers-maddrs\",\n        action=\"store\",\n        nargs=\"*\",\n        dest=\"entry_peers_maddrs\",\n        help=\"acn node's entry peers in libp2p multiaddress format\",\n    )\n    parser.add_argument(\n        \"--k8s-fetchai-defaults\",\n        action=\"store_true\",\n        dest=\"k8s_fetchai_defaults\",\n        required=False,\n        help=\"Use FetchAI defaults for k8s configuration\",\n    )\n    parser.add_argument(\n        \"--k8s-public-hostname\",\n        action=\"store\",\n        type=str,\n        dest=\"k8s_public_hostname\",\n        required=False,\n        help=\"K8s public hostname to use for acn node's external uri\",\n    )\n    parser.add_argument(\n        \"--k8s-namespace\",\n        action=\"store\",\n        type=str,\n        dest=\"k8s_namespace\",\n        required=False,\n        help=\"K8s deployment namespace\",\n    )\n    parser.add_argument(\n        \"--k8s-template-files-dir\",\n        action=\"store\",\n        type=str,\n        dest=\"k8s_template_files_dir\",\n        required=False,\n        help=\"Directory containing k8s template yaml deployment files\",\n    )\n\n    parser.add_argument(\n        \"--docker-fetchai-defaults\",\n        action=\"store_true\",\n        dest=\"docker_fetchai_defaults\",\n        required=False,\n        help=\"Use FetchAI defaults for docker configuration\",\n    )\n    parser.add_argument(\n        \"--docker-fetchai-defaults-dev\",\n        action=\"store_true\",\n        dest=\"docker_fetchai_defaults_dev\",\n        required=False,\n        help=\"Use FetchAI Dev defaults for docker configuration\",\n    )\n    parser.add_argument(\n        \"--docker-file\",\n        action=\"store\",\n        type=str,\n        dest=\"docker_file\",\n        required=False,\n        help=\"Path to Dockerfile to build\",\n    )\n    parser.add_argument(\n        \"--docker-ctx\",\n        action=\"store\",\n        type=str,\n        dest=\"docker_ctx\",\n        required=False,\n        help=\"Path to Dockerfile context\",\n    )\n    parser.add_argument(\n        \"--docker-image\",\n        action=\"store\",\n        type=str,\n        dest=\"docker_image\",\n        required=False,\n        help=\"Docker image name\",\n    )\n    parser.add_argument(\n        \"--docker-registry\",\n        action=\"store\",\n        type=str,\n        dest=\"docker_registry\",\n        required=False,\n        help=\"Docker remote registry\",\n    )\n\n    parser.add_argument(\n        \"--number-of-replicas\",\n        action=\"store\",\n        type=int,\n        dest=\"number_of_replicas\",\n        required=False,\n        help=\"Number of replicas\",\n    )\n\n    args = parser.parse_args()\n\n    # checks\n    if args.from_file is None and (\n        args.key is None\n        or args.port is None\n        or args.delegate_port is None\n        or args.monitoring_port is None\n    ):\n        parser.error(\n            \"--acn-key-file, --acn-port, --acn-port-delegate, --acn-port-monitoring are required when --from-file is not used\"\n        )\n\n    if (\n        not args.from_file\n        and not args.k8s_fetchai_defaults\n        and (\n            args.k8s_public_hostname is None\n            or args.k8s_namespace is None\n            or args.k8s_template_files_dir is None\n        )\n    ):\n        parser.error(\n            \"--k8s-public-hostname, --k8s-namespace, --k8s-template-files-dir are required when --k8s-fetchai-defaults is not set\"\n        )\n\n    if (\n        not args.from_file\n        and not args.docker_fetchai_defaults\n        and not args.docker_fetchai_defaults_dev\n        and (\n            args.docker_file is None\n            or args.docker_ctx is None\n            or args.docker_image is None\n            or args.docker_registry is None\n        )\n    ):\n        parser.error(\n            \"--docker-file, --docker-ctx, --docker-image, --docker-registry are required when --docker-fetchai-defaults[-dev] is not set\"\n        )\n\n    if args.docker_fetchai_defaults and args.docker_fetchai_defaults_dev:\n        parser.error(\n            \"--docker-fetchai-defaults and --docker-fetchai-defaults-dev are mutually exclusive\"\n        )\n\n    if args.generate_only and (args.delete_deployment or args.from_file):\n        parser.error(\"--generate-only can not be used with --delete or --from-file\")\n\n    return args\n\n\ndef main():\n    \"\"\"K8s deploy acn node\"\"\"\n\n    args = parse_commandline()\n\n    pod_deployment: Optional[K8sPodDeployment] = None\n\n    if args.from_file:\n        pod_deployment = K8sPodDeployment([Path(args.from_file)], None)\n    else:\n        dargs: List[Any] = [\n            args.key,\n            args.port,\n            args.delegate_port,\n            args.monitoring_port,\n        ]\n\n        dargs.append(\n            args.entry_peers_maddrs if args.entry_peers_maddrs is not None else \"\"\n        )\n\n        docker_config: List[str] = []\n        if args.docker_fetchai_defaults_dev:\n            docker_config = [\n                DOCKER_FETCHAI_DEFAULT_FILE_DEV,\n                DOCKER_FETCHAI_DEFAULT_CTX_DEV,\n                DOCKER_FETCHAI_DEFAULT_IMG,\n                DOCKER_FETCHAI_DEFAULT_REGISTRY,\n            ]\n        elif args.docker_fetchai_defaults:\n            docker_config = [\n                DOCKER_FETCHAI_DEFAULT_FILE,\n                DOCKER_FETCHAI_DEFAULT_CTX,\n                DOCKER_FETCHAI_DEFAULT_IMG,\n                DOCKER_FETCHAI_DEFAULT_REGISTRY,\n            ]\n        if args.docker_file is not None:\n            docker_config[0] = args.docker_file\n        if args.docker_ctx is not None:\n            docker_config[1] = args.docker_ctx\n        if args.docker_image is not None:\n            docker_config[2] = args.docker_image\n        if args.docker_registry is not None:\n            docker_config[3] = args.docker_registry\n\n        dargs.extend(docker_config)\n\n        k8s_config: List[str] = []\n        if args.k8s_fetchai_defaults:\n            k8s_config = [\n                K8S_FETCHAI_DEFAULT_PUBLIC_HOST,\n                K8S_FETCHAI_DEFAULT_NAMESPACE,\n                K8S_FETCHAI_DEFAULT_PUBLIC_TEMPLATE_DIR,\n            ]\n        if args.k8s_public_hostname is not None:\n            k8s_config[0] = args.k8s_public_hostname\n        if args.k8s_namespace is not None:\n            k8s_config[1] = args.k8s_namespace\n        if args.k8s_template_files_dir is not None:\n            k8s_config[2] = args.k8s_template_files_dir\n\n        dargs.extend(k8s_config)\n\n        pod_deployment = AcnK8sPodConfig(\n            dargs[0],\n            dargs[1],\n            dargs[2],\n            dargs[3],\n            dargs[4],\n            dargs[5],\n            dargs[6],\n            dargs[7],\n            dargs[8],\n            dargs[9],\n            dargs[10],\n            dargs[11],\n            k8s_number_of_replicas=args.number_of_replicas,\n        ).generate_deployment()\n\n    if args.generate_only:\n        return\n\n    try:\n        if args.delete_deployment:\n            pod_deployment.delete()\n        else:\n            pod_deployment.deploy()\n    except Exception as e:\n        raise e\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "scripts/acn/run_acn_node_standalone.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Run an ACN libp2p node without requiring the agents framework.\"\"\"\n\nimport argparse\nimport os\nimport subprocess  # nosec\nimport sys\nfrom binascii import unhexlify\nfrom typing import Dict, List, Optional\n\n# following imports needed only if checks are enabled  # isort:skip\nfrom base58 import b58decode\nfrom ecdsa import SigningKey, curves\nfrom multihash import decode as multihashdecode  # type: ignore\n\n\nclass AcnNodeConfig:\n    \"\"\"Store the configuration of an acn node as a dictionary.\"\"\"\n\n    KEY = \"AEA_P2P_ID\"\n    URI = \"AEA_P2P_URI\"\n    EXTERNAL_URI = \"AEA_P2P_URI_PUBLIC\"\n    DELEGATE_URI = \"AEA_P2P_DELEGATE_URI\"\n    MONITORING_URI = \"AEA_P2P_URI_MONITORING\"\n    ENTRY_PEERS_MADDRS = \"AEA_P2P_ENTRY_URIS\"\n    IPC_IN = \"AEA_TO_NODE\"\n    IPC_OUT = \"NODE_TO_AEA\"\n    AEA_ADDRESS = \"AEA_AGENT_ADDR\"\n    ACN_LOG_FILE = \"ACN_LOG_FILE\"\n    LIST_SEPARATOR = \",\"\n\n    def __init__(\n        self,\n        key: str,\n        uri: str,\n        external_uri: Optional[str] = None,\n        delegate_uri: Optional[str] = None,\n        monitoring_uri: Optional[str] = None,\n        entry_peers_maddrs: Optional[List[str]] = None,\n        log_file: Optional[str] = None,\n        enable_checks: bool = True,\n    ):\n        \"\"\"\n        Initialize a new ACN configuration from arguments\n\n        :param key: node private key to use as identity\n        :param uri: node local uri to bind to\n        :param external_uri: node external uri, needed to be reached by others\n        :param delegate_uri: node local uri for delegate service\n        :param monitoring_uri: node monitoring uri\n        :param entry_peers_maddrs: multiaddresses of peers to join their network\n        :param log_file: path to log file, opened in append mode\n        :param enable_checks: to check if provided configuration is valid\n        \"\"\"\n        self.config: Dict[str, str] = {}\n\n        self.config[AcnNodeConfig.KEY] = key\n        self.config[AcnNodeConfig.URI] = uri\n        self.config[AcnNodeConfig.EXTERNAL_URI] = (\n            external_uri if external_uri is not None else \"\"\n        )\n        self.config[AcnNodeConfig.DELEGATE_URI] = (\n            delegate_uri if delegate_uri is not None else \"\"\n        )\n        self.config[AcnNodeConfig.MONITORING_URI] = (\n            monitoring_uri if monitoring_uri is not None else \"\"\n        )\n\n        entry_peers_maddrs_list = (\n            AcnNodeConfig.LIST_SEPARATOR.join(entry_peers_maddrs)\n            if entry_peers_maddrs is not None\n            else \"\"\n        )\n        self.config[AcnNodeConfig.ENTRY_PEERS_MADDRS] = entry_peers_maddrs_list\n\n        self.config[AcnNodeConfig.ACN_LOG_FILE] = (\n            log_file if log_file is not None else \"\"\n        )\n        self.config[AcnNodeConfig.AEA_ADDRESS] = \"\"\n        self.config[AcnNodeConfig.IPC_IN] = \"\"\n        self.config[AcnNodeConfig.IPC_OUT] = \"\"\n\n        if enable_checks:\n            AcnNodeConfig.check_config(self.config)\n\n    def dump(self, file_path: str) -> None:\n        \"\"\"Write current configuration to file.\"\"\"\n        with open(file_path, \"w\") as f:\n            for key, value in self.config.items():\n                f.write(\"{}={}\\n\".format(key, value))\n\n    @classmethod\n    def from_file(cls, file_path: str, enable_checks: bool = True) -> \"AcnNodeConfig\":\n        \"\"\"\n        Create a new AcnNodeConfig objet from file.\n\n        :param file_path: path to the file containing the configuration\n        :param enable_checks: whether or not to enable checks\n        :return: newly created AcnNodeConfig object, if successful\n        \"\"\"\n\n        lines: List[str] = []\n        with open(file_path, \"r\") as f:\n            lines = f.readlines()\n\n        config = {}\n        for nbr, line in enumerate(lines):\n            parts = line.strip().split(\"=\")\n            if len(parts) != 2:\n                raise ValueError(\n                    \"Malformed configuration line {}: {}\".format(nbr + 1, line)\n                )\n            config[parts[0]] = parts[1]\n\n        key = config[AcnNodeConfig.KEY]\n        uri = config[AcnNodeConfig.URI]\n        external_uri = config.get(AcnNodeConfig.EXTERNAL_URI, None)\n        delegate_uri = config.get(AcnNodeConfig.DELEGATE_URI, None)\n        monitoring_uri = config.get(AcnNodeConfig.MONITORING_URI, None)\n        entry_peers = config.get(AcnNodeConfig.ENTRY_PEERS_MADDRS, \"\")\n        log_file = config.get(AcnNodeConfig.ACN_LOG_FILE, \"\")\n\n        return cls(\n            key,\n            uri,\n            external_uri,\n            delegate_uri,\n            monitoring_uri,\n            entry_peers.split(\",\"),\n            log_file,\n            enable_checks,\n        )\n\n    @staticmethod\n    def check_config(config: Dict[str, str]) -> None:\n        \"\"\"\n        Validate an ACN node configuration.\n\n        :param config: dictionary containing the configuration to check\n        \"\"\"\n\n        SigningKey.from_string(\n            unhexlify(config[AcnNodeConfig.KEY]), curve=curves.SECP256k1\n        )\n\n        AcnNodeConfig._check_uri(config[AcnNodeConfig.URI])\n        if config[AcnNodeConfig.EXTERNAL_URI] != \"\":\n            AcnNodeConfig._check_uri(config[AcnNodeConfig.EXTERNAL_URI])\n        if config[AcnNodeConfig.DELEGATE_URI] != \"\":\n            AcnNodeConfig._check_uri(config[AcnNodeConfig.DELEGATE_URI])\n        if config[AcnNodeConfig.MONITORING_URI] != \"\":\n            AcnNodeConfig._check_uri(config[AcnNodeConfig.MONITORING_URI])\n\n        maddrs = config[AcnNodeConfig.ENTRY_PEERS_MADDRS].split(\n            AcnNodeConfig.LIST_SEPARATOR\n        )\n        for maddr in maddrs:\n            AcnNodeConfig._check_maddr(maddr)\n\n    @staticmethod\n    def _check_uri(uri: str) -> None:\n        \"\"\"Check uri.\"\"\"\n        if uri == \"\":\n            return\n        parts = uri.split(\":\")\n        if len(parts) != 2:\n            raise ValueError(\"Malformed uri '{}'\".format(uri))\n        int(parts[1])\n\n    @staticmethod\n    def _check_maddr(maddr: str) -> None:\n        \"\"\"Check multiaddress.\"\"\"\n        if maddr == \"\":\n            return\n        parts = maddr.split(\"/\")\n        if len(parts) != 7:\n            raise ValueError(\"Malformed multiaddress '{}'\".format(maddr))\n        multihashdecode(b58decode(parts[-1]))\n\n\nclass AcnNodeStandalone:\n    \"\"\"Deploy an acn node in standalone mode.\"\"\"\n\n    def __init__(self, config: AcnNodeConfig, libp2p_node_binary: str):\n        \"\"\"\n        Initialize a new AcnNodeStandalone object.\n\n        :param config: node's configuration\n        :param libp2p_node_binary: path to libp2p node binary\n        \"\"\"\n\n        self.config = config\n        self.binary = libp2p_node_binary\n        self._proc = None  # type: Optional[subprocess.Popen]\n\n    def run(self):\n        \"\"\"Run the node.\"\"\"\n        config_file = \".acn_config\"\n        self.config.dump(config_file)\n\n        cmd = [self.binary, config_file]\n\n        if self.config.config[AcnNodeConfig.ACN_LOG_FILE] != \"\":\n            self._proc = subprocess.Popen(  # nosec\n                cmd,\n                shell=False,\n                stdout=subprocess.PIPE,\n                stderr=subprocess.STDOUT,\n                bufsize=1,\n            )\n            with open(\n                self.config.config[AcnNodeConfig.ACN_LOG_FILE], \"ab\", 1\n            ) as log_file:\n                for line in self._proc.stdout:\n                    sys.stdout.buffer.write(line)\n                    log_file.write(line)\n                    log_file.flush()\n        else:\n            self._proc = subprocess.Popen(  # nosec\n                cmd,\n                shell=False,\n            )\n\n        try:\n            self._proc.wait()\n        except KeyboardInterrupt:\n            pass\n\n    def stop(self):\n        \"\"\"Stop the node.\"\"\"\n        if self._proc is not None:\n            self._proc.terminate()\n            self._proc.wait()\n\n\ndef parse_commandline():\n    \"\"\"Parse script cl arguments.\"\"\"\n\n    parser = argparse.ArgumentParser()\n    parser.add_argument(\"libp2p_node\")\n    config = parser.add_mutually_exclusive_group(required=False)\n    config.add_argument(\n        \"--config-from-env\",\n        action=\"store_true\",\n        dest=\"config_from_env\",\n        help=\"get node configuration from environment variables\",\n    )\n    config.add_argument(\n        \"--config-from-file\",\n        action=\"store\",\n        type=str,\n        dest=\"config_from_file\",\n        help=\"node configuration file\",\n    )\n\n    parser.add_argument(\n        \"--key-file\",\n        action=\"store\",\n        type=str,\n        dest=\"key\",\n        help=\"node's private key file\",\n    )\n    parser.add_argument(\n        \"--uri\",\n        action=\"store\",\n        type=str,\n        dest=\"uri\",\n        help=\"node's local uri in format {ip_address:port}\",\n    )\n    parser.add_argument(\n        \"--uri-external\",\n        action=\"store\",\n        type=str,\n        dest=\"external_uri\",\n        required=False,\n        help=\"node's external uri in format {ip_address:port}\",\n    )\n    parser.add_argument(\n        \"--uri-delegate\",\n        action=\"store\",\n        type=str,\n        dest=\"delegate_uri\",\n        required=False,\n        help=\"node's delegate service uri in format {ip_address:port}\",\n    )\n    parser.add_argument(\n        \"--uri-monitoring\",\n        action=\"store\",\n        type=str,\n        dest=\"monitoring_uri\",\n        required=False,\n        help=\"node's monitoring service uri in format {ip_address:port}\",\n    )\n    parser.add_argument(\n        \"--entry-peers-maddrs\",\n        action=\"store\",\n        nargs=\"*\",\n        dest=\"entry_peers_maddrs\",\n        help=\"node's entry peer uri in libp2p multiaddress fromat\",\n    )\n    parser.add_argument(\n        \"--log-file\",\n        action=\"store\",\n        type=str,\n        dest=\"log_file\",\n        required=False,\n        help=\"path to node logging file\",\n    )\n\n    args = parser.parse_args()\n\n    if (\n        args.config_from_env is False\n        and args.config_from_file is None\n        and (args.key is None or args.uri is None or args.external_uri is None)\n    ):\n        parser.error(\n            \"--key-file, --uri, and --uri-external are required when configuration is not passed through env or file\"\n        )\n\n    return args\n\n\nif __name__ == \"__main__\":\n\n    args = parse_commandline()\n\n    node_config: Optional[AcnNodeConfig] = None\n\n    if args.config_from_env:\n        key = os.environ[AcnNodeConfig.KEY]\n        uri = os.environ[AcnNodeConfig.URI]\n        external_uri = os.environ.get(AcnNodeConfig.EXTERNAL_URI)\n        delegate_uri = os.environ.get(AcnNodeConfig.DELEGATE_URI)\n        monitoring_uri = os.environ.get(AcnNodeConfig.MONITORING_URI)\n        entry_peers = os.environ.get(AcnNodeConfig.ENTRY_PEERS_MADDRS)\n        entry_peers_list = entry_peers.split(\",\") if entry_peers is not None else []\n        log_file = os.environ.get(AcnNodeConfig.ACN_LOG_FILE, \"\")\n        node_config = AcnNodeConfig(\n            key,\n            uri,\n            external_uri,\n            delegate_uri,\n            monitoring_uri,\n            entry_peers_list,\n            log_file,\n        )\n\n    elif args.config_from_file is not None:\n        node_config = AcnNodeConfig.from_file(args.config_from_file)\n\n    else:\n        with open(args.key, \"r\") as f:\n            key = f.read().strip()\n        node_config = AcnNodeConfig(\n            key,\n            args.uri,\n            args.external_uri,\n            args.delegate_uri,\n            args.monitoring_uri,\n            args.entry_peers_maddrs,\n            args.log_file,\n        )\n\n    node = AcnNodeStandalone(node_config, args.libp2p_node)\n    try:\n        node.run()\n    except Exception:\n        node.stop()\n        raise\n"
  },
  {
    "path": "scripts/bump_aea_version.py",
    "content": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nBump the AEA version throughout the code base.\n\nusage: bump_aea_version [-h] [--new-version NEW_VERSION]\n                        [-p KEY=VALUE [KEY=VALUE ...]] [--no-fingerprints]\n                        [--only-check]\n\noptional arguments:\n  -h, --help            show this help message and exit\n  --new-version NEW_VERSION\n                        The new AEA version.\n  -p KEY=VALUE [KEY=VALUE ...], --plugin-new-version KEY=VALUE [KEY=VALUE ...]\n                        Set a number of key-value pairs plugin-name=new-\n                        plugin-version\n  --no-fingerprints     Skip the computation of fingerprints.\n  --only-check          Only check the need of upgrade.\n\n\nExample of usage:\n\npython scripts/bump_aea_version.py --new-version 1.1.0 -p aea-ledger-fetchai=2.0.0 -p aea-ledger-ethereum=3.0.0\npython scripts/bump_aea_version.py --only-check\n\"\"\"\n\nimport argparse\nimport inspect\nimport logging\nimport operator\nimport os\nimport re\nimport sys\nfrom functools import wraps\nfrom pathlib import Path\nfrom typing import Any, Callable, Dict, List, Optional, Sequence, cast\n\nfrom git import Repo\nfrom packaging.specifiers import SpecifierSet\nfrom packaging.version import Version\n\nfrom aea.helpers.base import compute_specifier_from_version\nfrom scripts.generate_ipfs_hashes import update_hashes\n\n\nlogging.basicConfig(\n    level=logging.INFO, format=\"[%(asctime)s][%(name)s][%(levelname)s] %(message)s\"\n)\n\n# if the key is a file, just process it\n# if the key is a directory, process all files below it\nPatternByPath = Dict[Path, str]\n\nAEA_DIR = Path(\"aea\")\nCUR_PATH = os.path.dirname(inspect.getfile(inspect.currentframe()))  # type: ignore\nROOT_DIR = Path(os.path.join(CUR_PATH, \"..\"))\nPYPROJECT_TOML = ROOT_DIR / \"pyproject.toml\"\n\nPLUGINS_DIR = Path(\"plugins\")\nALL_PLUGINS = tuple(PLUGINS_DIR.iterdir())\n\n\"\"\"\nThis pattern captures a specifier set in the dependencies section\nof an AEA package configuration file, e.g.:\n\ndependencies:\n    ...\n    aea-ledger-fetchai:\n        version: >=1.0.0,<2.0.0\n\"\"\"\nYAML_DEPENDENCY_SPECIFIER_SET_PATTERN = (\n    \"(?<={package_name}:\\n    version: )({specifier_set})\"\n)\n\n\"\"\"\nThis pattern captures a specifier set for PyPI dependencies\nin JSON format.\n\ne.g.:\n\"aea-ledger-fetchai\": {\"version\": \">=2.0.0, <3.0.0\"}\n\"\"\"\nJSON_DEPENDENCY_SPECIFIER_SET_PATTERN = (\n    '(?<=\"{package_name}\": .\"version\": \")({specifier_set})(?=\".)'\n)\n\n\n_AEA_ALL_PATTERN = r\"(?<={package_name}\\[all\\]==){version}\"\nAEA_PATHS: PatternByPath = {\n    Path(\"deploy-image\", \"Dockerfile\"): _AEA_ALL_PATTERN,\n    Path(\"develop-image\", \"docker-env.sh\"): \"(?<=aea-develop:){version}\",\n    Path(\"docs\", \"quickstart.md\"): \"(?<=v){version}\",\n    Path(\"examples\", \"tac_deploy\", \"Dockerfile\"): _AEA_ALL_PATTERN,\n    Path(\"scripts\", \"install.ps1\"): _AEA_ALL_PATTERN,\n    Path(\"scripts\", \"install.sh\"): _AEA_ALL_PATTERN,\n    Path(\n        \"tests\", \"test_docs\", \"test_bash_yaml\", \"md_files\", \"bash-quickstart.md\"\n    ): \"(?<=v){version}\",\n    Path(\"user-image\", \"docker-env.sh\"): \"(?<=aea-user:){version}\",\n}\n\n\ndef check_executed(func: Callable) -> Callable:\n    \"\"\"Check a functor has been already executed; if yes, raise error.\"\"\"\n\n    @wraps(func)\n    def wrapper(self: Any, *args: Any, **kwargs: Any) -> None:\n        if self.is_executed:\n            raise ValueError(\"already executed\")\n        self._executed = True  # pylint: disable=protected-access\n        self._result = func(self, *args, **kwargs)  # pylint: disable=protected-access\n\n    return wrapper\n\n\ndef compute_specifier_from_version_custom(version: Version) -> str:\n    \"\"\"\n    Post-process aea.helpers.compute_specifier_from_version\n\n    The output is post-process in the following way:\n    - remove spaces between specifier sets\n    - put upper bound before lower bound\n\n    :param version: the version\n    :return: the specifier set according to the version and semantic versioning.\n    \"\"\"\n    specifier_set_str = compute_specifier_from_version(version)\n    specifiers = SpecifierSet(specifier_set_str)\n    upper, lower = sorted(specifiers, key=str)\n    return f\"{upper},{lower}\"\n\n\ndef get_regex_from_specifier_set(specifier_set: str) -> str:\n    \"\"\"\n    Get the regex for specifier sets.\n\n    This function accepts input of the form:\n\n        \">={lower_bound_version}, <{upper_bound_version}\"\n\n    And computes a regex pattern:\n\n        \">={lower_bound_version}, *<{upper_bound_version}|<{upper_bound_version}, *>={lower_bound_version}\"\n\n    i.e. not considering the order of the specifiers.\n\n    :param specifier_set: The string representation of the specifier set\n    :return: a regex pattern\n    \"\"\"\n    specifiers = SpecifierSet(specifier_set)\n    upper, lower = sorted(specifiers, key=str)\n    alternatives = []\n    alternatives.append(f\"{upper} *, *{lower}\")\n    alternatives.append(f\"{lower} *, *{upper}\")\n    return \"|\".join(alternatives)\n\n\nclass PythonPackageVersionBumper:\n    \"\"\"Utility class to bump Python package versions.\"\"\"\n\n    IGNORE_DIRS = (Path(\".git\"),)\n\n    def __init__(\n        self,\n        root_dir: Path,\n        python_pkg_dir: Path,\n        new_version: Version,\n        files_to_pattern: PatternByPath,\n        specifier_set_patterns: Sequence[str],\n        package_name: Optional[str] = None,\n        ignore_dirs: Sequence[Path] = (),\n    ):\n        \"\"\"\n        Initialize the utility class.\n\n        :param root_dir: the root directory from which to look for files.\n        :param python_pkg_dir: the path to the Python package to upgrade.\n        :param new_version: the new version.\n        :param files_to_pattern: a list of pairs.\n        :param specifier_set_patterns: a list of patterns for specifier sets.\n        :param package_name: the Python package name aliases (defaults to dirname of python_pkg_dir).\n        :param ignore_dirs: a list of paths to ignore during the substitution.\n        \"\"\"\n        self.root_dir = root_dir\n        self.python_pkg_dir = python_pkg_dir\n        self.new_version = new_version\n        self.files_to_pattern = files_to_pattern\n        self.specifier_set_patterns = specifier_set_patterns\n        self.package_name = package_name or self.python_pkg_dir.name\n        self.ignore_dirs = ignore_dirs or self.IGNORE_DIRS\n\n        self.repo = Repo(self.root_dir)\n        self._current_version: Optional[str] = None\n\n        # functor pattern\n        self._executed: bool = False\n        self._result: Optional[bool] = None\n\n    @property\n    def is_executed(self) -> bool:\n        \"\"\"\n        Return true if the functor has been executed; false otherwise.\n\n        :return: True if it has been executed, False otherwise.\n        \"\"\"\n        return self._executed\n\n    @property\n    def result(self) -> bool:\n        \"\"\"Get the result.\"\"\"\n        if not self.is_executed:\n            raise ValueError(\"not executed yet\")\n        return cast(bool, self._result)\n\n    @check_executed\n    def run(self) -> bool:\n        \"\"\"Main entrypoint.\"\"\"\n        if not self.is_different_from_latest_tag():\n            logging.info(\n                f\"The package {self.python_pkg_dir} has no changes since last tag.\"\n            )\n            return False\n        new_version_string = str(self.new_version)\n        current_version_str = self.update_version_for_package(new_version_string)\n\n        # validate current version\n        current_version: Version = Version(current_version_str)\n        current_version_str = str(current_version)\n        self._current_version = current_version_str\n        self.update_version_for_files()\n\n        return self.update_version_specifiers(current_version, self.new_version)\n\n    def update_version_for_files(self) -> None:\n        \"\"\"Update the version.\"\"\"\n        for filepath, regex_template in self.files_to_pattern.items():\n            self.update_version_for_file(\n                filepath,\n                cast(str, self._current_version),\n                str(self.new_version),\n                version_regex_template=regex_template,\n            )\n\n    def update_version_for_package(self, new_version: str) -> str:\n        \"\"\"\n        Update version for file.\n\n        If __version__.py is available, parse it and check for __version__ variable.\n        Otherwise, try to parse pyproject.py.\n        Otherwise, raise error.\n\n        :param new_version: the new version\n        :return: the current version\n        \"\"\"\n        version_path = self.python_pkg_dir / Path(\"__version__.py\")\n        path_regexp = []\n        if version_path.exists():\n            regex_template = '(?<=__version__ = [\\'\"])({version})(?=\")'\n            path = version_path\n            path_regexp.append((path, regex_template))\n        if PYPROJECT_TOML.exists():\n            regex_template = r\"(?<=\\nversion = \\\")(?P<version>{version})(?=\\\"\\n)\"\n            path = PYPROJECT_TOML\n            path_regexp.append((path, regex_template))\n\n        for path, regex_template in path_regexp:\n            content = path.read_text()\n            pattern = regex_template.format(version=\".*\")\n            current_version_candidates = re.findall(pattern, content)\n            more_than_one_match = len(current_version_candidates) > 1\n            if more_than_one_match:\n                raise ValueError(\n                    f\"find more than one match for current version in {path}: {current_version_candidates}\"\n                )\n            current_version = current_version_candidates[0]\n            self.update_version_for_file(\n                path,\n                current_version,\n                new_version,\n                version_regex_template=regex_template,\n            )\n        return current_version\n\n    def update_version_for_file(\n        self,\n        path: Path,\n        current_version: str,\n        new_version: str,\n        version_regex_template: Optional[str] = None,\n    ) -> None:\n        \"\"\"\n        Update version for file.\n\n        :param path: the file path\n        :param current_version: the regex for the current version\n        :param new_version: the new version\n        :param version_regex_template: the regex template to replace with the current version. Defaults to exactly the current version.\n        \"\"\"\n        if version_regex_template is not None:\n            regex_str = version_regex_template.format(\n                package_name=self.package_name, version=current_version\n            )\n        else:\n            regex_str = current_version\n        pattern = re.compile(regex_str)\n        content = path.read_text()\n        content = pattern.sub(new_version, content)\n        path.write_text(content)\n\n    def update_version_specifiers(\n        self, old_version: Version, new_version: Version\n    ) -> bool:\n        \"\"\"\n        Update specifier set.\n\n        :param old_version: the old version.\n        :param new_version: the new version.\n        :return: True if the update has been done, False otherwise.\n        \"\"\"\n        old_specifier_set = compute_specifier_from_version_custom(old_version)\n        new_specifier_set = compute_specifier_from_version_custom(new_version)\n        logging.info(f\"Old version specifier: {old_specifier_set}\")\n        logging.info(f\"New version specifier: {new_specifier_set}\")\n        if old_specifier_set == new_specifier_set:\n            logging.info(\"Not updating version specifier - they haven't changed.\")\n            return False\n        for file in filter(lambda p: not p.is_dir(), self.root_dir.rglob(\"*\")):\n            dir_root = Path(file.parts[0])\n            if dir_root in self.ignore_dirs:\n                logging.info(f\"Skipping '{file}'...\")\n                continue\n            logging.info(\n                f\"Replacing '{old_specifier_set}' with '{new_specifier_set}' in '{file}'... \",\n            )\n            try:\n                content = file.read_text()\n            except UnicodeDecodeError as e:\n                logging.info(f\"Cannot read {file}: {str(e)}. Continue...\")\n            else:\n                content = self._replace_specifier_sets(\n                    old_specifier_set, new_specifier_set, content\n                )\n                file.write_text(content)\n        return True\n\n    def _replace_specifier_sets(\n        self, old_specifier_set: str, new_specifier_set: str, content: str\n    ) -> str:\n        old_specifier_set_regex = get_regex_from_specifier_set(old_specifier_set)\n        for pattern_template in self.specifier_set_patterns:\n            regex = pattern_template.format(\n                package_name=self.package_name,\n                specifier_set=old_specifier_set_regex,\n            )\n            pattern = re.compile(regex)\n            if pattern.search(content) is not None:\n                content = pattern.sub(new_specifier_set, content)\n        return content\n\n    def is_different_from_latest_tag(self) -> bool:\n        \"\"\"Check whether the package has changes since the latest tag.\"\"\"\n        assert len(self.repo.tags) > 0, \"no git tags found\"\n        latest_tag_str = str(self.repo.tags[-1])\n        args = latest_tag_str, \"--\", str(self.python_pkg_dir)\n        logging.info(f\"Running 'git diff {' '.join(args)}'\")\n        diff = self.repo.git.diff(*args)\n        return diff != \"\"\n\n\ndef parse_args() -> argparse.Namespace:\n    \"\"\"Parse arguments.\"\"\"\n\n    parser = argparse.ArgumentParser(\"bump_aea_version\")\n    parser.add_argument(\n        \"--new-version\", type=str, required=False, help=\"The new AEA version.\"\n    )\n    parser.add_argument(\n        \"-p\",\n        \"--plugin-new-version\",\n        metavar=\"KEY=VALUE\",\n        nargs=\"+\",\n        help=\"Set a number of key-value pairs plugin-name=new-plugin-version\",\n        default={},\n    )\n    parser.add_argument(\n        \"--no-fingerprints\",\n        action=\"store_true\",\n        help=\"Skip the computation of fingerprints.\",\n    )\n    parser.add_argument(\n        \"--only-check\", action=\"store_true\", help=\"Only check the need of upgrade.\"\n    )\n    arguments_ = parser.parse_args()\n    return arguments_\n\n\ndef make_aea_bumper(new_aea_version: Version) -> PythonPackageVersionBumper:\n    \"\"\"Build the AEA Python package version bumper.\"\"\"\n    aea_version_bumper = PythonPackageVersionBumper(\n        ROOT_DIR,\n        AEA_DIR,\n        new_aea_version,\n        specifier_set_patterns=[\n            \"(?<=aea_version:) *({specifier_set})\",\n            \"(?<={package_name})({specifier_set})\",\n        ],\n        files_to_pattern=AEA_PATHS,\n    )\n    return aea_version_bumper\n\n\ndef make_plugin_bumper(\n    plugin_dir: Path, new_version: Version\n) -> PythonPackageVersionBumper:\n    \"\"\"Build the plugin Python package version bumper.\"\"\"\n    plugin_package_dir = plugin_dir / plugin_dir.name.replace(\"-\", \"_\")\n    plugin_version_bumper = PythonPackageVersionBumper(\n        ROOT_DIR,\n        plugin_package_dir,\n        new_version,\n        files_to_pattern={},\n        specifier_set_patterns=[\n            YAML_DEPENDENCY_SPECIFIER_SET_PATTERN,\n            JSON_DEPENDENCY_SPECIFIER_SET_PATTERN,\n        ],\n        package_name=plugin_dir.name,\n    )\n    return plugin_version_bumper\n\n\ndef process_plugins(new_versions: Dict[str, Version]) -> bool:\n    \"\"\"Process plugins.\"\"\"\n    result = False\n    for plugin_dir in ALL_PLUGINS:\n        plugin_dir_name = plugin_dir.name\n        if plugin_dir_name not in new_versions:\n            logging.info(\n                f\"Skipping {plugin_dir_name} as it is not specified in input {new_versions}\"\n            )\n            continue\n        new_version = new_versions[plugin_dir_name]\n        logging.info(\n            f\"Processing {plugin_dir_name}: upgrading to version {new_version}\"\n        )\n        plugin_bumper = make_plugin_bumper(plugin_dir, new_version)\n        plugin_bumper.run()\n        result |= plugin_bumper.result\n    return result\n\n\ndef parse_plugin_versions(key_value_strings: List[str]) -> Dict[str, Version]:\n    \"\"\"Parse plugin versions.\"\"\"\n    return {\n        plugin_name: Version(version)\n        for plugin_name, version in map(\n            operator.methodcaller(\"split\", \"=\"), key_value_strings\n        )\n    }\n\n\ndef only_check_bump_needed() -> int:\n    \"\"\"\n    Check whether a version bump is needed for AEA and plugins.\n\n    :return: the return code\n    \"\"\"\n    bumpers: List[PythonPackageVersionBumper] = []\n    to_upgrade: List[Path] = []\n    bumpers.append(make_aea_bumper(None))  # type: ignore\n    for plugin_dir in ALL_PLUGINS:\n        bumpers.append(make_plugin_bumper(plugin_dir, None))  # type: ignore\n\n    latest_tag = str(bumpers[0].repo.tags[-1])\n    logging.info(\n        f\"Checking packages that have changes from tag {latest_tag} and that require a new release...\"\n    )\n    for bumper in bumpers:\n        if bumper.is_different_from_latest_tag():\n            logging.info(\n                f\"Package {bumper.python_pkg_dir} is different from latest tag {latest_tag}.\"\n            )\n            to_upgrade.append(bumper.python_pkg_dir)\n\n    if len(to_upgrade) > 0:\n        logging.info(\"Packages to upgrade:\")\n        for path in to_upgrade:\n            logging.info(path)\n    else:\n        logging.info(\"No packages to upgrade.\")\n    return 0\n\n\ndef bump(arguments: argparse.Namespace) -> int:\n    \"\"\"\n    Bump versions.\n\n    :param arguments: arguments from argparse\n    :return: the return code\n    \"\"\"\n    new_plugin_versions = parse_plugin_versions(arguments.plugin_new_version)\n    logging.info(f\"Parsed arguments: {arguments}\")\n    logging.info(f\"Parsed plugin versions: {new_plugin_versions}\")\n\n    have_updated_specifier_set = False\n    if arguments.new_version is not None:\n        new_aea_version = Version(arguments.new_version)\n        aea_version_bumper = make_aea_bumper(new_aea_version)\n        aea_version_bumper.run()\n        have_updated_specifier_set = aea_version_bumper.result\n        logging.info(\"AEA package processed.\")\n    else:\n        logging.info(\"AEA package not processed - no version provided.\")\n\n    logging.info(\"Processing plugins:\")\n    have_updated_specifier_set |= process_plugins(new_plugin_versions)\n\n    logging.info(\"OK\")\n    return_code = 0\n    if arguments.no_fingerprints:\n        logging.info(\n            \"Not updating fingerprints, since --no-fingerprints was specified.\"\n        )\n    elif have_updated_specifier_set is False:\n        logging.info(\n            \"Not updating fingerprints, since no specifier set has been updated.\"\n        )\n    else:\n        logging.info(\"Updating hashes and fingerprints.\")\n        return_code = update_hashes()\n    return return_code\n\n\ndef main() -> None:\n    \"\"\"Run the script.\"\"\"\n    repo = Repo(str(ROOT_DIR))\n    if repo.is_dirty():\n        logging.info(\n            \"Repository is dirty. Please clean it up before running this script.\"\n        )\n        sys.exit(1)\n\n    arguments = parse_args()\n    if arguments.only_check:\n        sys.exit(only_check_bump_needed())\n\n    return_code = bump(arguments)\n    sys.exit(return_code)\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "scripts/bump_year.sh",
    "content": "#!/bin/sh\n\nif [ -z \"$1\" ];\nthen\n\techo Please specify year as argument\n\texit 1\nfi\n\nif [ -z `echo $1|grep -E \"^[0-9]{4}$\"` ];\nthen\n\techo Please specify year as 4 digits\n\texit 1\nfi\n\nYEAR=$1\n\nSEARCH_RE=\"Copyright 2018-[0-9]{4} Fetch.AI Limited\"\nUPDATE_STR=\"Copyright 2018-${YEAR} Fetch.AI Limited\"\n\necho $UPDATE_STR\n\n\nfor i in `grep -l -E -R \"${SEARCH_RE}\" --include \"*.py\" ../`;\ndo\n\tsed -E -e \"s/${SEARCH_RE}/${UPDATE_STR}/\" -i $i\n\techo Updated: $i\ndone "
  },
  {
    "path": "scripts/check_copyright_notice.py",
    "content": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nThis script checks that all the Python files of the repository have:\n\n- (optional) the Python shebang\n- the encoding header;\n- the copyright notice;\n\nIt is assumed the script is run from the repository root.\n\"\"\"\n\nimport datetime\nimport itertools\nimport re\nimport sys\nfrom pathlib import Path\n\n\nSUPPORTED_YEARS = [str(i) for i in range(2018, datetime.datetime.now().year + 1)]\n\n\nHEADER_REGEX = rf\"\"\"(#!/usr/bin/env python3\n)?# -\\*- coding: utf-8 -\\*-\n# ------------------------------------------------------------------------------\n#\n#   (Copyright 2018-({\"|\".join(SUPPORTED_YEARS)}) Fetch.AI Limited|Copyright [0-9]{{4}}(-[0-9]{{4}})? [a-zA-Z_]+)\n#\n#   Licensed under the Apache License, Version 2\\.0 \\(the \\\"License\\\"\\);\n#   you may not use this file except in compliance with the License\\.\n#   You may obtain a copy of the License at\n#\n#       http://www\\.apache\\.org/licenses/LICENSE-2\\.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \\\"AS IS\\\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied\\.\n#   See the License for the specific language governing permissions and\n#   limitations under the License\\.\n#\n# ------------------------------------------------------------------------------\n\"\"\"\n\n\ndef check_copyright(file: Path) -> bool:\n    \"\"\"\n    Given a file, check if the header stuff is in place.\n\n    Return True if the files has the encoding header and the copyright notice,\n    optionally prefixed by the shebang. Return False otherwise.\n\n    :param file: the file to check.\n    :return: True if the file is compliant with the checks, False otherwise.\n    \"\"\"\n    content = file.read_text()\n    header_regex = re.compile(HEADER_REGEX, re.MULTILINE)\n    return re.match(header_regex, content) is not None\n\n\nif __name__ == \"__main__\":\n    python_files = itertools.chain(\n        Path(\"aea\").glob(\"**/*.py\"),\n        Path(\"packages\").glob(\"**/*.py\"),\n        Path(\"tests\").glob(\"**/*.py\"),\n        Path(\"plugins\").glob(\"**/*.py\"),\n        Path(\"scripts\").glob(\"**/*.py\"),\n        Path(\"examples\", \"gym_ex\").glob(\"**/*.py\"),\n        Path(\"examples\", \"ml_ex\").glob(\"**/*.py\"),\n    )\n\n    # filter out protobuf files (*_pb2.py)\n    python_files_filtered = filter(\n        lambda x: not str(x).endswith(\"_pb2.py\")\n        and \"data/reference_protocols/\" not in str(x),\n        python_files,\n    )\n\n    bad_files = [\n        filepath for filepath in python_files_filtered if not check_copyright(filepath)\n    ]\n\n    if len(bad_files) > 0:\n        print(\"The following files are not well formatted:\")\n        print(\"\\n\".join(map(str, bad_files)))\n        sys.exit(1)\n    else:\n        print(\"OK\")\n        sys.exit(0)\n"
  },
  {
    "path": "scripts/check_doc_links.py",
    "content": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Script to check that all internal doc links are valid.\"\"\"\nimport re\nimport sys\nimport xml.etree.ElementTree as ET  # nosec\nfrom pathlib import Path\nfrom typing import Pattern, Set\n\nfrom aea.helpers import http_requests as requests\n\n\nLINK_PATTERN_MD = re.compile(r\"\\[([^]]+)]\\(\\s*([^]]+)\\s*\\)\")\nLINK_PATTERN = re.compile(r'(?<=<a href=\")[^\"]*')\nIMAGE_PATTERN = re.compile(r'<img[^>]+src=\"([^\">]+)\"')\nRELATIVE_PATH_STR = \"../\"\nRELATIVE_PATH_STR_LEN = len(RELATIVE_PATH_STR)\nINDEX_FILE_PATH = Path(\"docs/index.md\")\n\nWHITELIST_URL_TO_CODE = {\n    \"https://dl.acm.org/doi/10.1145/3212734.3212736\": 302,\n    \"https://s-oef.fetch.ai:443\": 405,\n    \"https://golang.org/dl/\": 403,\n    \"https://www.wiley.com/en-gb/An+Introduction+to+MultiAgent+Systems%2C+2nd+Edition-p-9781119959519\": 403,\n    \"https://colab.research.google.com\": 403,\n    \"https://github.com/fetchai/networks-capricorn\": 404,\n}\n\nIGNORE: Set[str] = {\"https://faucet.metamask.io/\"}\n\n\ndef is_url_reachable(url: str) -> bool:\n    \"\"\"\n    Check if a url is reachable.\n\n    :param url: the url to check\n    :return: bool\n    \"\"\"\n    if url.startswith(\"http://localhost\") or url.startswith(\"http://127.0.0.1\"):\n        return True\n    if url in IGNORE:\n        return True\n    try:\n        response = requests.head(url, timeout=20)\n        if response.status_code == 200:\n            return True\n        if response.status_code in [403, 405, 302, 404]:\n            return WHITELIST_URL_TO_CODE.get(url, 404) in [403, 405, 302, 404]\n        return False\n    except Exception as e:  # pylint: disable=broad-except,redefined-outer-name\n        print(e)\n        return False\n\n\ndef check_header_in_file(header: str, file: Path) -> None:\n    \"\"\"\n    Check if the string is present in the file.\n\n    :param header: the header\n    :param file: the file path\n    \"\"\"\n    with open(file, encoding=\"utf-8\") as f:\n        s = f.read()\n        if header not in s:\n            raise ValueError(\n                \"Header={} not found in file={}!\".format(header, str(file))\n            )\n\n\ndef validate_internal_url(file: Path, url: str, all_files: Set[Path]) -> None:\n    \"\"\"\n    Validate whether the url is a valid path to a file in docs.\n\n    :param file: the file path\n    :param url: the url to check\n    :param all_files: all the docs files.\n    \"\"\"\n    is_index_file = file == INDEX_FILE_PATH\n\n    if not url.startswith(RELATIVE_PATH_STR) and not is_index_file:\n        raise ValueError(\"Invalid relative path={} in file={}!\".format(url, str(file)))\n\n    md_index = url.find(\".md\")\n    if md_index != -1:\n        raise ValueError(\n            \"Path={} contains invalid `.md` in file={}!\".format(url, str(file))\n        )\n\n    hash_index = url.find(\"#\")\n    if hash_index == -1:\n        n_url = url[RELATIVE_PATH_STR_LEN:] if not is_index_file else url\n        n_url = n_url[:-1] if n_url[-1] == \"/\" else n_url\n        path = Path(\"docs/{}.md\".format(n_url))\n        header = \"\"\n    else:\n        n_url = url[RELATIVE_PATH_STR_LEN:hash_index] if not is_index_file else url\n        n_url = n_url[:-1] if n_url[-1] == \"/\" else n_url\n        path = Path(\"docs/{}.md\".format(n_url))\n        header = url[hash_index:]\n\n    if path not in all_files:\n        raise ValueError(\n            \"Path={} found in file={} does not exist!\".format(str(path), str(file))\n        )\n\n    if header != \"\":\n        check_header_in_file(header, file)\n\n\ndef _checks_all_html(file: Path, regex: Pattern = LINK_PATTERN_MD) -> None:\n    \"\"\"\n    Checks a file for matches to a pattern.\n\n    :param file: the file path\n    :param regex: the regex to check for in the file.\n    \"\"\"\n    matches = regex.finditer(file.read_text())\n    for _ in matches:\n        raise ValueError(\"Markdown link found in file={}!\".format(str(file)))\n\n\ndef is_external_url(url: str) -> bool:\n    \"\"\"\n    Check if an URL is an external URL.\n\n    :param url: the URL\n    :return: true if it is external, false otherwise.\n    \"\"\"\n    return url.startswith(\"https://\") or url.startswith(\"http://\")\n\n\ndef validate_external_url(url: str, file: Path) -> None:\n    \"\"\"\n    Validate external URL.\n\n    :param url: the URL.\n    :param file: the file where the URL is found.\n    \"\"\"\n    if not is_url_reachable(url):\n        raise ValueError(\"Could not reach url={} in file={}!\".format(url, str(file)))\n\n\ndef _checks_link(\n    file: Path, all_files: Set[Path], regex: Pattern = LINK_PATTERN\n) -> None:\n    \"\"\"\n    Checks a file for matches to a pattern.\n\n    :param file: the file path\n    :param all_files: all the doc file paths\n    :param regex: the regex to check for in the file.\n    \"\"\"\n    matches = regex.finditer(file.read_text())\n    for match in matches:\n        result = match.group()\n        if is_external_url(result):\n            validate_external_url(result, file)\n        else:\n            validate_internal_url(file, result, all_files)\n\n\ndef _checks_image(file: Path, regex: Pattern = IMAGE_PATTERN) -> None:\n    \"\"\"\n    Checks a file for matches to a pattern.\n\n    :param file: the file path\n    :param regex: the regex to check for in the file.\n    \"\"\"\n    if file in [Path(\"docs/version.md\"), Path(\"docs/install.md\")]:\n        return\n    matches = regex.finditer(file.read_text())\n    for match in matches:\n        result = match.group(1)\n\n        png_index = result.find(\".png\")\n        jpg_index = result.find(\".jpg\")\n        if png_index != -1 or jpg_index != -1:\n            img_path = Path(\"docs/{}\".format(result[RELATIVE_PATH_STR_LEN:]))\n            if not img_path.exists():\n                raise ValueError(\n                    \"Image path={} in file={} not found!\".format(img_path, str(file))\n                )\n            return\n        if result.startswith(\"https\") or result.startswith(\"http\"):\n            if not is_url_reachable(result):\n                raise ValueError(\n                    \"Could not reach url={} in file={}!\".format(result, str(file))\n                )\n        raise ValueError(\"Image path={} in file={} not `.png` or `.jpg`!\")\n\n\ndef _checks_target_blank(file: Path) -> None:\n    \"\"\"\n    Check target blank.\n\n    :param file: the file.\n    \"\"\"\n    matches = re.finditer(\"<a.*?>(.+?)</a>\", file.read_text())\n    for match in matches:\n        tag = ET.fromstring(match.group())  # nosec\n        href = tag.attrib.get(\"href\")\n        target = tag.attrib.get(\"target\")\n        if href is not None and is_external_url(href) and target != \"_blank\":\n            raise ValueError(\n                f\"Anchor tag with href={href} and target={target} in file {str(file)} is not valid.\"\n            )\n\n\ndef check_file(file: Path, all_files: Set[Path]) -> None:\n    \"\"\"\n    Check the links in the file.\n\n    :param file: the file path\n    :param all_files: all the doc file paths\n    \"\"\"\n    _checks_all_html(file)\n    _checks_link(file, all_files)\n    _checks_target_blank(file)\n    _checks_image(file)\n\n\ndef get_all_docs_files() -> Set[Path]:\n    \"\"\"\n    Get all file paths to docs or api docs.\n\n    :return: list of all paths\n    \"\"\"\n    all_files = Path(\"docs\").glob(\"**/*.md\")\n    return set(all_files)\n\n\nif __name__ == \"__main__\":\n    all_docs_files = get_all_docs_files()\n    docs_files = Path(\"docs\").glob(\"*.md\")\n\n    try:\n        for file_ in docs_files:\n            print(\"Processing \" + str(file_))\n            check_file(file_, all_docs_files)\n    except Exception as e:  # pylint: disable=broad-except\n        print(e)\n        sys.exit(1)\n\n    print(\"Done!\")\n    sys.exit(0)\n"
  },
  {
    "path": "scripts/check_imports_and_dependencies.py",
    "content": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Check aea dependencies.\"\"\"\nimport copy\nimport dis\nimport importlib\nimport re\nimport sys\nfrom collections import defaultdict\nfrom functools import wraps\nfrom pathlib import Path\nfrom typing import Any, Callable, Dict, Generator, List, Optional, Set, Tuple, Union\n\n\nAEA_ROOT_DIR = Path(__file__).parent.parent\n\nsys.path.append(str(AEA_ROOT_DIR))\n\nfrom aea.crypto.registries import (  # noqa # pylint: disable=wrong-import-position\n    crypto_registry,\n)\n\n\nIGNORE: Set[str] = {\"pkg_resources\", \"distutils.dir_util\"}\nDEP_NAME_RE = re.compile(r\"(^[^=><\\[]+)\", re.I)  # type: ignore\n\n\ndef list_decorator(fn: Callable) -> Callable:\n    \"\"\"Wraps generator to return list.\"\"\"\n\n    @wraps(fn)\n    def wrapper(*args: Any, **kwargs: Any) -> List[Any]:\n        return list(fn(*args, **kwargs))\n\n    return wrapper\n\n\nclass DependenciesTool:\n    \"\"\"Tool to work with setup.py dependencies.\"\"\"\n\n    @staticmethod\n    def get_package_files(package_name: str) -> List[Path]:\n        \"\"\"Get package files list.\"\"\"\n        from pip._internal.commands.show import (  # type: ignore  # noqa  # pylint: disable=import-outside-toplevel\n            search_packages_info,\n        )\n\n        packages_info = list(search_packages_info([package_name]))\n        if len(packages_info) == 0:\n            raise Exception(f\"package {package_name} not found\")\n        if isinstance(packages_info[0], dict):\n            files = packages_info[0][\"files\"]\n            location = packages_info[0][\"location\"]\n        else:\n            files = packages_info[0].files  # type: ignore\n            location = packages_info[0].location  # type: ignore\n        return [Path(location) / i for i in files]  # type: ignore\n\n    @staticmethod\n    def clean_dependency_name(dependecy_specification: str) -> str:\n        \"\"\"Get dependency name from dependency specification.\"\"\"\n        match = DEP_NAME_RE.match(dependecy_specification)\n        if not match:\n            raise ValueError(f\"Bad dependency specification: {dependecy_specification}\")\n        return match.groups()[0]\n\n\nclass ImportsTool:\n    \"\"\"Tool to work with 3rd part imports in source code.\"\"\"\n\n    @staticmethod\n    def get_imports_for_file(pyfile: Union[str, Path]) -> List[str]:\n        \"\"\"Get all imported modules for python source file.\"\"\"\n        with open(pyfile, \"r\", encoding=\"utf-8\") as f:\n            statements = f.read()\n        instructions = dis.get_instructions(statements)  # type: ignore\n        imports = [i for i in instructions if \"IMPORT\" in i.opname]\n\n        grouped: Dict[str, List[str]] = defaultdict(list)\n        for instr in imports:\n            grouped[instr.opname].append(instr.argval)\n\n        return grouped[\"IMPORT_NAME\"]\n\n    @staticmethod\n    def get_module_file(module_name: str) -> str:\n        \"\"\"Get module source file name.\"\"\"\n        try:\n            mod = importlib.import_module(module_name)\n            return getattr(mod, \"__file__\", \"\")\n        except (AttributeError, ModuleNotFoundError):\n            return \"\"\n\n    @staticmethod\n    @list_decorator\n    def list_all_pyfiles(\n        root_path: Union[Path, str], pattern: str = \"**/*.py\"\n    ) -> Generator:\n        \"\"\"List all python files in directory.\"\"\"\n        root_path = Path(root_path)\n        for path in root_path.glob(pattern):\n            yield path.relative_to(root_path)\n\n    @classmethod\n    @list_decorator\n    def get_third_part_imports_for_file(cls, pyfile: str) -> Generator:\n        \"\"\"Get list of third part modules imported for source file.\"\"\"\n        imports = cls.get_imports_for_file(pyfile)\n        for module_name in imports:\n            pyfile = cls.get_module_file(module_name)\n            if not pyfile:\n                continue\n            if \"site-packages\" not in Path(pyfile).parts:\n                continue\n            yield module_name, Path(pyfile)\n\n    @classmethod\n    @list_decorator\n    def list_all_pyfiles_with_3rdpart_imports(\n        cls, root_path: Union[str, Path], pattern: str = \"**/*.py\"\n    ) -> Generator:\n        \"\"\"Get list of all python sources with 3rd party modules imported.\"\"\"\n        for pyfile in cls.list_all_pyfiles(root_path, pattern=pattern):\n            mods = list(cls.get_third_part_imports_for_file(root_path / pyfile))\n            if not mods:\n                continue\n            yield Path(pyfile), list(set(mods))\n\n\nclass CheckTool:\n    \"\"\"Tool to check imports in sources match dependencies in setup.py.\"\"\"\n\n    @classmethod\n    def get_section_dependencies_from_setup(cls) -> Dict[str, Dict[str, List[Path]]]:\n        \"\"\"Get sections with dependencies with files lists.\"\"\"\n        spec = importlib.util.spec_from_file_location(\n            \"setup\", str(AEA_ROOT_DIR / \"setup.py\")\n        )\n        assert spec\n        setup = importlib.util.module_from_spec(spec)\n        sys.modules[spec.name] = setup\n        spec.loader.exec_module(setup)  # type: ignore\n\n        sections_dependencies = copy.deepcopy(setup.all_extras)  # type: ignore\n        sections_dependencies.pop(\"all\")\n        base = setup.base_deps  # type: ignore\n\n        for crypto_id in crypto_registry.supported_ids:  # type: ignore\n            if crypto_id == \"fetchai\":\n                crypto_id = \"fetch\"\n            if crypto_id in sections_dependencies:\n                sections_dependencies.pop(crypto_id)\n        sections_dependencies[\"base\"] = base\n\n        return cls.sections_dependencies_add_files(sections_dependencies)\n\n    @staticmethod\n    def sections_dependencies_add_files(\n        sections_dependencies: Dict[str, List[str]]\n    ) -> Dict[str, Dict[str, List[Path]]]:\n        \"\"\"Add packages file lists to dependencies in sections.\"\"\"\n        result: Dict[str, Dict[str, List[Path]]] = defaultdict(\n            lambda: defaultdict(list)\n        )\n        for section, deps in sections_dependencies.items():\n            for dep in deps:\n                dep = DependenciesTool.clean_dependency_name(dep)\n                result[section][dep] = DependenciesTool.get_package_files(dep)\n        return result\n\n    @classmethod\n    def run(cls) -> None:\n        \"\"\"Run dependency check.\"\"\"\n        print(\"Dependencies check report:\")\n        print(\"==========================\")\n        files_and_modules = ImportsTool.list_all_pyfiles_with_3rdpart_imports(\n            AEA_ROOT_DIR, pattern=\"aea/**/*.py\"\n        )\n\n        sections_dependencies = cls.get_section_dependencies_from_setup()\n        sections_imports = cls.make_sections_with_3rdpart_imports(\n            files_and_modules, set(sections_dependencies.keys())\n        )\n        missed_deps_for_imports, deps_not_imported_directly = cls.check_imports(\n            sections_imports, sections_dependencies  # type: ignore\n        )\n\n        for section, unresolved_imports in missed_deps_for_imports.items():\n            print(\n                f\"Section `{section}` unresolved imports: {', '.join(unresolved_imports)}\"\n            )\n\n        if deps_not_imported_directly:\n            if missed_deps_for_imports:\n                print()\n            print(\n                f\"Dependencies not imported in code directly: {', '.join(deps_not_imported_directly)}\"\n            )\n\n        if missed_deps_for_imports or deps_not_imported_directly:\n            sys.exit(1)\n        else:\n            print(\"All good!\")\n\n    @staticmethod\n    def make_sections_with_3rdpart_imports(\n        files_and_modules: List[Tuple[str, List[Tuple[str, Path]]]],\n        section_names: Set[str],\n    ) -> Dict[str, Set[Tuple[str, Path]]]:\n        \"\"\"Make sections with list of 3r part imports.\"\"\"\n        sections_imports: Dict[str, Set[Tuple[str, Path]]] = defaultdict(set)\n        for pyfile, imports in files_and_modules:\n            section_name = Path(pyfile).parts[1]\n\n            if section_name not in section_names:\n                section_name = \"base\"\n\n            sections_imports[section_name].update(imports)\n\n        return sections_imports\n\n    @staticmethod\n    def check_imports(\n        sections_imports: Dict[str, Set[Tuple[str, Path]]],\n        sections_dependencies: Dict[str, Dict[str, List[str]]],\n    ) -> Tuple[Dict[str, List[str]], List[str]]:\n        \"\"\"Find missing dependencies for imports and not imported dependencies.\"\"\"\n\n        def _find_dependency_for_module(\n            dependencies: Dict[str, List[str]], pyfile: str\n        ) -> Optional[str]:\n            for package, files in dependencies.items():\n                if pyfile in files:\n                    return package\n            return None\n\n        sections_imports_packages: Dict[str, Dict[str, Optional[str]]] = defaultdict(\n            dict\n        )\n        for section, modules in sections_imports.items():\n            for module, pyfile in modules:\n                package = _find_dependency_for_module(\n                    sections_dependencies.get(section, {}), pyfile  # type: ignore\n                )\n                if module not in IGNORE:\n                    sections_imports_packages[section][module] = package\n\n        all_dependencies_set = set(\n            sum((list(i.keys()) for _, i in sections_dependencies.items()), [])\n        )\n        used_dependencies_set = set(\n            sum(\n                [\n                    list(section.values())\n                    for section in sections_imports_packages.values()\n                ],\n                [],\n            )\n        )\n        deps_not_imported_directly: List[str] = list(\n            all_dependencies_set - used_dependencies_set\n        )\n        missed_deps_for_imports: Dict[str, List[str]] = {\n            section: [k for k, v in modules.items() if v is None]\n            for section, modules in sections_imports_packages.items()\n            if None in modules.values()\n        }\n        return missed_deps_for_imports, deps_not_imported_directly\n\n\nif __name__ == \"__main__\":\n    CheckTool.run()\n"
  },
  {
    "path": "scripts/check_package_versions_in_docs.py",
    "content": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"\nCheck that package ids are in sync with the current packages.\n\nRun this script from the root of the project directory:\n\n    python scripts/check_package_versions_in_docs.py\n\n\"\"\"\nimport re\nimport sys\nfrom itertools import chain\nfrom pathlib import Path\nfrom typing import Any, Callable, Dict, Generator, List, Match, Pattern, Set\n\nimport yaml\n\nfrom aea.configurations.base import ComponentType, PackageId, PackageType, PublicId\nfrom aea.configurations.constants import (\n    AGENTS,\n    DEFAULT_AEA_CONFIG_FILE,\n    DEFAULT_CONNECTION_CONFIG_FILE,\n    DEFAULT_CONTRACT_CONFIG_FILE,\n    DEFAULT_PROTOCOL_CONFIG_FILE,\n    DEFAULT_SKILL_CONFIG_FILE,\n)\n\n\nPUBLIC_ID_REGEX = PublicId.PUBLIC_ID_REGEX[1:-1]\n\"\"\"This regex removes the '^' and '$' respectively, at the beginning and at the end.\"\"\"\n\nADD_COMMAND_IN_DOCS = re.compile(\n    \"aea +add +({}) +({})\".format(\"|\".join(map(str, ComponentType)), PUBLIC_ID_REGEX)\n)\n\"\"\"\nThis regex matches strings of the form:\n\n  aea add (protocol|connection|contract|skill) some_author/some_package:some_version_number\n\n\"\"\"\n\n\nFETCH_COMMAND_IN_DOCS = re.compile(\"aea +fetch +({})\".format(PUBLIC_ID_REGEX))\n\"\"\"\nThis regex matches strings of the form:\n\n  aea fetch some_author/some_package:some_version_number\n\n\"\"\"\n\n\nclass PackageIdNotFound(Exception):\n    \"\"\"Custom exception for package id not found.\"\"\"\n\n    def __init__(\n        self, file: Path, package_id: PackageId, match_obj: Any, *args: Any\n    ) -> None:\n        \"\"\"\n        Initialize PackageIdNotFound exception.\n\n        :param file: path to the file checked.\n        :param package_id: package id not found.\n        :param match_obj: re.Match object.\n        :param args: super class args.\n        \"\"\"\n        super().__init__(*args)\n        self.file = file\n        self.package_id = package_id\n        self.match_obj = match_obj\n\n\nDEFAULT_CONFIG_FILE_PATHS = []  # type: List[Path]\n\n\nCONFIG_FILE_NAMES = [\n    DEFAULT_AEA_CONFIG_FILE,\n    DEFAULT_SKILL_CONFIG_FILE,\n    DEFAULT_CONNECTION_CONFIG_FILE,\n    DEFAULT_CONTRACT_CONFIG_FILE,\n    DEFAULT_PROTOCOL_CONFIG_FILE,\n]  # type: List[str]\n\n\ndef default_config_file_paths() -> Generator:\n    \"\"\"Get (generator) the default config file paths.\"\"\"\n    for item in DEFAULT_CONFIG_FILE_PATHS:\n        yield item\n\n\ndef unified_yaml_load(configuration_file: Path) -> Dict:\n    \"\"\"\n    Load YAML file, unified (both single- and multi-paged).\n\n    :param configuration_file: the configuration file path.\n    :return: the data.\n    \"\"\"\n    package_type = configuration_file.parent.parent.name\n    with configuration_file.open() as fp:\n        if package_type != AGENTS:\n            return yaml.safe_load(fp)\n        # when it is an agent configuration file,\n        # we are interested only in the first page of the YAML,\n        # because the dependencies are contained only there.\n        data = yaml.safe_load_all(fp)\n        return list(data)[0]\n\n\ndef get_public_id_from_yaml(configuration_file: Path) -> PublicId:\n    \"\"\"\n    Get the public id from yaml.\n\n    :param configuration_file: the path to the config yaml\n    :return: public id\n    \"\"\"\n    data = unified_yaml_load(configuration_file)\n    author = data.get(\"author\", None)\n    if not author:\n        raise KeyError(f\"No author field in {str(configuration_file)}\")\n    # handle the case when it's a package or agent config file.\n    try:\n        name = data[\"name\"] if \"name\" in data else data[\"agent_name\"]\n    except KeyError:\n        print(f\"No name or agent_name field in {str(configuration_file)}\")\n        raise\n    version = data.get(\"version\", None)\n    if not version:\n        raise KeyError(f\"No version field in {str(configuration_file)}\")\n    return PublicId(author, name, version)\n\n\ndef find_all_packages_ids() -> Set[PackageId]:\n    \"\"\"Find all packages ids.\"\"\"\n    package_ids: Set[PackageId] = set()\n    packages_dir = Path(\"packages\")\n    config_files = [\n        path\n        for path in packages_dir.glob(\"*/*/*/*.yaml\")\n        if any(file in str(path) for file in CONFIG_FILE_NAMES)\n    ]\n    for configuration_file in chain(config_files, default_config_file_paths()):\n        package_type = PackageType(configuration_file.parts[-3][:-1])\n        package_public_id = get_public_id_from_yaml(configuration_file)\n        package_id = PackageId(package_type, package_public_id)\n        package_ids.add(package_id)\n\n    return package_ids\n\n\nALL_PACKAGE_IDS: Set[PackageId] = find_all_packages_ids()\n\n\ndef _checks(\n    file: Path,\n    regex: Pattern,\n    extract_package_id_from_match: Callable[[\"re.Match\"], PackageId],\n) -> None:\n    matches = regex.finditer(file.read_text())\n    for match in matches:\n        package_id = extract_package_id_from_match(match)\n        if package_id not in ALL_PACKAGE_IDS:\n            raise PackageIdNotFound(\n                file, package_id, match, \"Package {} not found.\".format(package_id)\n            )\n        print(str(package_id), \"OK!\")\n\n\ndef check_add_commands(file: Path) -> None:\n    \"\"\"\n    Check that 'aea add' commands of the documentation file contains known package ids.\n\n    :param file: path to the file.\n    \"\"\"\n\n    def extract_package_id(match: Match) -> PackageId:\n        package_type, package = match.group(1), match.group(2)\n        package_id = PackageId(PackageType(package_type), PublicId.from_str(package))\n        return package_id\n\n    _checks(file, ADD_COMMAND_IN_DOCS, extract_package_id)\n\n\ndef check_fetch_commands(file: Path) -> None:\n    \"\"\"\n    Check that 'aea fetch' commands of the documentation file contains known package ids.\n\n    :param file: path to the file.\n    \"\"\"\n\n    def extract_package_id(match: Match) -> PackageId:\n        package_public_id = match.group(1)\n        package_id = PackageId(PackageType.AGENT, PublicId.from_str(package_public_id))\n        return package_id\n\n    _checks(file, FETCH_COMMAND_IN_DOCS, extract_package_id)\n\n\ndef check_file(file: Path) -> None:\n    \"\"\"\n    Check documentation file.\n\n    :param file: path to the file to check.\n    \"\"\"\n    check_add_commands(file)\n    check_fetch_commands(file)\n\n\ndef handle_package_not_found(e: PackageIdNotFound) -> None:\n    \"\"\"Handle PackageIdNotFound errors.\"\"\"\n    print(\"=\" * 50)\n    print(\"Package {} not found.\".format(e.package_id))\n    print(\"Path to file: \", e.file)\n    print(\"Span: \", e.match_obj.span(0))\n    print(\"Full Match: \", e.match_obj.group(0))\n    sys.exit(1)\n\n\nif __name__ == \"__main__\":\n    docs_files = Path(\"docs\").glob(\"**/*.md\")\n\n    try:\n        for file_ in docs_files:\n            print(\"Processing \" + str(file_))\n            check_file(file_)\n    except PackageIdNotFound as e_:\n        handle_package_not_found(e_)\n        sys.exit(1)\n\n    print(\"Done!\")\n    sys.exit(0)\n"
  },
  {
    "path": "scripts/check_packages.py",
    "content": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"\nRun different checks on AEA packages.\n\nNamely:\n- Check that every package has existing dependencies\n- Check that every package has non-empty description\n\nRun this script from the root of the project directory:\n\n    python scripts/check_packages.py\n\n\"\"\"\nimport pprint\nimport sys\nfrom functools import partial\nfrom itertools import chain\nfrom pathlib import Path\nfrom typing import Any, Dict, Generator, List, Set\n\nimport yaml\n\nfrom aea.configurations.base import PackageId, PackageType, PublicId\nfrom aea.configurations.constants import (\n    AGENTS,\n    DEFAULT_AEA_CONFIG_FILE,\n    DEFAULT_CONNECTION_CONFIG_FILE,\n    DEFAULT_CONTRACT_CONFIG_FILE,\n    DEFAULT_PROTOCOL_CONFIG_FILE,\n    DEFAULT_SKILL_CONFIG_FILE,\n)\n\n\nDEFAULT_CONFIG_FILE_PATHS = []  # type: List[Path]\n\nCONFIG_FILE_NAMES = [\n    DEFAULT_AEA_CONFIG_FILE,\n    DEFAULT_SKILL_CONFIG_FILE,\n    DEFAULT_CONNECTION_CONFIG_FILE,\n    DEFAULT_CONTRACT_CONFIG_FILE,\n    DEFAULT_PROTOCOL_CONFIG_FILE,\n]  # type: List[str]\n\n\nclass DependencyNotFound(Exception):\n    \"\"\"Custom exception for dependencies not found.\"\"\"\n\n    def __init__(\n        self,\n        configuration_file: Path,\n        expected_deps: Set[PackageId],\n        missing_dependencies: Set[PackageId],\n        *args: Any,\n    ) -> None:\n        \"\"\"\n        Initialize DependencyNotFound exception.\n\n        :param configuration_file: path to the checked file.\n        :param expected_deps: expected dependencies.\n        :param missing_dependencies: missing dependencies.\n        :param args: super class args.\n        \"\"\"\n        super().__init__(*args)\n        self.configuration_file = configuration_file\n        self.expected_dependencies = expected_deps\n        self.missing_dependencies = missing_dependencies\n\n\nclass EmptyPackageDescription(Exception):\n    \"\"\"Custom exception for empty description field.\"\"\"\n\n    def __init__(\n        self,\n        configuration_file: Path,\n        *args: Any,\n    ) -> None:\n        \"\"\"\n        Initialize EmptyPackageDescription exception.\n\n        :param configuration_file: path to the checked file.\n        :param args: super class args.\n        \"\"\"\n        super().__init__(*args)\n        self.configuration_file = configuration_file\n\n\ndef find_all_configuration_files() -> List:\n    \"\"\"Find all configuration files.\"\"\"\n    packages_dir = Path(\"packages\")\n    config_files = [\n        path\n        for path in packages_dir.glob(\"*/*/*/*.yaml\")\n        if any(file in str(path) for file in CONFIG_FILE_NAMES)\n    ]\n    return list(chain(config_files, default_config_file_paths()))\n\n\ndef default_config_file_paths() -> Generator:\n    \"\"\"Get (generator) the default config file paths.\"\"\"\n    for item in DEFAULT_CONFIG_FILE_PATHS:\n        yield item\n\n\ndef get_public_id_from_yaml(configuration_file: Path) -> PublicId:\n    \"\"\"\n    Get the public id from yaml.\n\n    :param configuration_file: the path to the config yaml\n    :return: public id\n    \"\"\"\n    data = unified_yaml_load(configuration_file)\n    author = data.get(\"author\", None)\n    if not author:\n        raise KeyError(f\"No author field in {str(configuration_file)}\")\n    # handle the case when it's a package or agent config file.\n    try:\n        name = data[\"name\"] if \"name\" in data else data[\"agent_name\"]\n    except KeyError:\n        print(f\"No name or agent_name field in {str(configuration_file)}\")\n        raise\n    version = data.get(\"version\", None)\n    if not version:\n        raise KeyError(f\"No version field in {str(configuration_file)}\")\n    return PublicId(author, name, version)\n\n\ndef find_all_packages_ids() -> Set[PackageId]:\n    \"\"\"Find all packages ids.\"\"\"\n    package_ids: Set[PackageId] = set()\n    for configuration_file in find_all_configuration_files():\n        package_type = PackageType(configuration_file.parts[-3][:-1])\n        package_public_id = get_public_id_from_yaml(configuration_file)\n        package_id = PackageId(package_type, package_public_id)\n        package_ids.add(package_id)\n\n    return package_ids\n\n\ndef handle_dependency_not_found(e: DependencyNotFound) -> None:\n    \"\"\"Handle PackageIdNotFound errors.\"\"\"\n    sorted_expected = list(map(str, sorted(e.expected_dependencies)))\n    sorted_missing = list(map(str, sorted(e.missing_dependencies)))\n    print(\"=\" * 50)\n    print(f\"Package {e.configuration_file}:\")\n    print(f\"Expected: {pprint.pformat(sorted_expected)}\")\n    print(f\"Missing: {pprint.pformat(sorted_missing)}\")\n    print(\"=\" * 50)\n\n\ndef handle_empty_package_description(e: EmptyPackageDescription) -> None:\n    \"\"\"Handle EmptyPackageDescription errors.\"\"\"\n    print(\"=\" * 50)\n    print(f\"Package '{e.configuration_file}' has empty description field.\")\n    print(\"=\" * 50)\n\n\ndef unified_yaml_load(configuration_file: Path) -> Dict:\n    \"\"\"\n    Load YAML file, unified (both single- and multi-paged).\n\n    :param configuration_file: the configuration file path.\n    :return: the data.\n    \"\"\"\n    package_type = configuration_file.parent.parent.name\n    with configuration_file.open() as fp:\n        if package_type != AGENTS:\n            return yaml.safe_load(fp)\n        # when it is an agent configuration file,\n        # we are interested only in the first page of the YAML,\n        # because the dependencies are contained only there.\n        data = yaml.safe_load_all(fp)\n        return list(data)[0]\n\n\ndef check_dependencies(\n    configuration_file: Path, all_packages_ids: Set[PackageId]\n) -> None:\n    \"\"\"\n    Check dependencies of configuration file.\n\n    :param configuration_file: path to a package configuration file.\n    :param all_packages_ids: all the package ids.\n    \"\"\"\n    data = unified_yaml_load(configuration_file)\n\n    def _add_package_type(package_type: PackageType, public_id_str: str) -> PackageId:\n        return PackageId(package_type, PublicId.from_str(public_id_str))\n\n    def _get_package_ids(\n        package_type: PackageType, public_ids: Set[PublicId]\n    ) -> Set[PackageId]:\n        return set(map(partial(_add_package_type, package_type), public_ids))\n\n    dependencies: Set[PackageId] = set.union(\n        *[\n            _get_package_ids(package_type, data.get(package_type.to_plural(), set()))\n            for package_type in list(PackageType)\n        ]\n    )\n\n    diff = dependencies.difference(all_packages_ids)\n    if len(diff) > 0:\n        raise DependencyNotFound(configuration_file, dependencies, diff)\n\n\ndef check_description(configuration_file: Path) -> None:\n    \"\"\"Check description field of a package is non-empty.\"\"\"\n    yaml_object = unified_yaml_load(configuration_file)\n    description = yaml_object.get(\"description\")\n    if description == \"\":\n        raise EmptyPackageDescription(configuration_file)\n\n\nif __name__ == \"__main__\":\n    all_packages_ids_ = find_all_packages_ids()\n    failed: bool = False\n    for file in find_all_configuration_files():\n        try:\n            print(\"Processing \" + str(file))\n            check_dependencies(file, all_packages_ids_)\n            check_description(file)\n        except DependencyNotFound as e_:\n            handle_dependency_not_found(e_)\n            failed = True\n        except EmptyPackageDescription as e_:\n            handle_empty_package_description(e_)\n            failed = True\n\n    if failed:\n        print(\"Failed!\")\n        sys.exit(1)\n    else:\n        print(\"OK!\")\n        sys.exit(0)\n"
  },
  {
    "path": "scripts/check_pipfile_and_toxini.py",
    "content": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This script checks that dependencies in tox.ini and Pipfile match.\"\"\"\nimport re\nimport sys\nfrom typing import Dict\n\n\n# specified in setup.py\nWHITELIST = {\"base58\": \">=1.0.3\"}\n# fix for python 3.6 and tox\nEXCLUSIONS_LIST = [(\"tensorflow\", \"==2.4.0\")]\n\nDEP_NAME_RE = re.compile(r\"(^[^=><\\[]+)\", re.I)  # type: ignore\n\n\ndef get_deps_in_pipfile(file: str = \"Pipfile\") -> Dict[str, str]:\n    \"\"\"\n    Get the dependencies of the Pipfile.\n\n    :param file: the file to check.\n    :return: dictionary with dependencies and their versions\n    \"\"\"\n    result: Dict[str, str] = WHITELIST\n    with open(file, \"r\", encoding=\"utf-8\") as f:\n        is_dev_dependency = False\n        for line in f:\n            if line == \"[dev-packages]\\n\":\n                is_dev_dependency = True\n                continue\n            if line == \"[packages]\\n\":\n                is_dev_dependency = True\n                continue\n            if not is_dev_dependency:\n                continue\n            try:\n                package, version = line.split(\" = \")\n                result[package] = version.strip(\"\\n\").strip('\"')\n            except Exception:  # nosec # pylint: disable=broad-except\n                pass\n\n    return result\n\n\ndef check_versions_in_tox_correct(file: str = \"tox.ini\") -> None:\n    \"\"\"\n    Check the versions in tox are matching the ones in Pipfile.\n\n    :param file: the file to check.\n    \"\"\"\n    dependencies = get_deps_in_pipfile()\n\n    with open(file, \"r\", encoding=\"utf-8\") as f:\n        for line in f:\n            line = line.strip()\n            looks_like_deps = False\n            for match_type in [\"==\", \">=\", \"<\"]:\n                if match_type in line:\n                    looks_like_deps = True\n                    break\n            if not looks_like_deps:\n                continue\n            m = DEP_NAME_RE.match(line)\n            if not m:\n                continue\n            name_part = m.groups()[0]\n            version_part = line.replace(name_part, \"\").strip()\n            check_match(\n                name_part.strip(\" \"),\n                version_part.strip(\"\\n\"),\n                dependencies,\n            )\n\n\ndef check_match(\n    name_part: str, version_part: str, dependencies: Dict[str, str]\n) -> None:\n    \"\"\"Check for a match independencies.\"\"\"\n    if (name_part, version_part) in EXCLUSIONS_LIST:\n        return\n    result = False\n    for package, version_and_match_type in dependencies.items():\n        if package == name_part:\n            if version_and_match_type == f\"{version_part}\":\n                result = True\n                break\n            print(\n                f\"Non-matching versions for package={package}, {name_part}. Expected='{version_and_match_type}', found='{version_part}'.\"\n            )\n            sys.exit(1)\n\n    if not result:\n        print(f\"Package not found for: {name_part}\")\n        sys.exit(1)\n\n\nif __name__ == \"__main__\":\n    check_versions_in_tox_correct()\n    print(\"OK\")\n    sys.exit(0)\n"
  },
  {
    "path": "scripts/common.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Common utils for scripts.\"\"\"\nimport logging\nimport re\nimport subprocess  # nosec\nimport sys\nfrom io import StringIO\nfrom pathlib import Path\nfrom typing import Match, cast\n\nfrom aea.configurations.base import ProtocolSpecification\nfrom aea.configurations.loader import ConfigLoader\n\n\nSPECIFICATION_REGEX = re.compile(r\"(---\\nname.*\\.\\.\\.)\", re.DOTALL)\nPROTOCOL_SPECIFICATION_ID_IN_SPECIFICATION_REGEX = re.compile(\n    \"^protocol_specification_id: (.*)$\", re.MULTILINE\n)\nPACKAGES_DIR = Path(\"packages\")\n\n\ndef setup_logger(name: str) -> logging.Logger:\n    \"\"\"Set up the logger.\"\"\"\n    FORMAT = \"[%(asctime)s][%(levelname)s] %(message)s\"\n    logging.basicConfig(format=FORMAT)\n    logger_ = logging.getLogger(name)\n    logger_.setLevel(logging.INFO)\n    return logger_\n\n\nlogger = setup_logger(__name__)\n\n\ndef enforce(condition: bool, message: str = \"\") -> None:\n    \"\"\"Custom assertion.\"\"\"\n    if not condition:\n        raise AssertionError(message)\n\n\ndef check_working_tree_is_dirty() -> None:\n    \"\"\"Check if the current Git working tree is dirty.\"\"\"\n    print(\"Checking whether the Git working tree is dirty...\")\n    result = subprocess.check_output([\"git\", \"diff\", \"--stat\"])  # nosec\n    if len(result) > 0:\n        print(\"Git working tree is dirty:\")\n        print(result.decode(\"utf-8\"))\n        sys.exit(1)\n    else:\n        print(\"All good!\")\n\n\ndef load_protocol_specification_from_string(\n    specification_content: str,\n) -> ProtocolSpecification:\n    \"\"\"Load a protocol specification from string.\"\"\"\n    file = StringIO(initial_value=specification_content)\n    config_loader = ConfigLoader(\n        \"protocol-specification_schema.json\", ProtocolSpecification\n    )\n    protocol_spec = config_loader.load_protocol_specification(file)\n    return protocol_spec\n\n\ndef get_protocol_specification_from_readme(package_path: Path) -> str:\n    \"\"\"Get the protocol specification from the package README.\"\"\"\n    logger.info(f\"Get protocol specification from README {package_path}\")\n    readme = package_path / \"README.md\"\n    readme_content = readme.read_text()\n    enforce(\n        \"## Specification\" in readme_content,\n        f\"Cannot find specification section in {package_path}\",\n    )\n\n    search_result = SPECIFICATION_REGEX.search(readme_content)\n    enforce(\n        search_result is not None,\n        f\"Cannot find specification section in README of {package_path}\",\n    )\n    specification_content = cast(Match, search_result).group(0)\n    # just for validation of the parsed string\n    load_protocol_specification_from_string(specification_content)\n    return specification_content\n\n\ndef get_protocol_specification_id_from_specification(specification: str) -> str:\n    \"\"\"Get the protocol specification id from the protocol specification.\"\"\"\n    matches = PROTOCOL_SPECIFICATION_ID_IN_SPECIFICATION_REGEX.findall(specification)\n    enforce(\n        len(matches) == 1,\n        f\"Expected exactly one protocol specification id, found: {matches}\",\n    )\n    spec_id = matches[0]\n    return spec_id\n"
  },
  {
    "path": "scripts/deploy_to_registry.py",
    "content": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This script deploys all new packages to registry.\"\"\"\n\nimport os\nimport shutil\nimport sys\nimport time\nfrom itertools import chain\nfrom pathlib import Path\nfrom typing import Dict, Generator, List, Set\n\nimport yaml\nfrom click.testing import CliRunner\n\nfrom aea.cli import cli\nfrom aea.configurations.base import PackageId, PackageType, PublicId\nfrom aea.configurations.constants import (\n    AGENTS,\n    DEFAULT_AEA_CONFIG_FILE,\n    DEFAULT_CONNECTION_CONFIG_FILE,\n    DEFAULT_CONTRACT_CONFIG_FILE,\n    DEFAULT_PROTOCOL_CONFIG_FILE,\n    DEFAULT_SKILL_CONFIG_FILE,\n)\n\n\nCONFIG_FILE_NAMES = [\n    DEFAULT_AEA_CONFIG_FILE,\n    DEFAULT_SKILL_CONFIG_FILE,\n    DEFAULT_CONNECTION_CONFIG_FILE,\n    DEFAULT_CONTRACT_CONFIG_FILE,\n    DEFAULT_PROTOCOL_CONFIG_FILE,\n]  # type: List[str]\n\nCLI_LOG_OPTION = [\"-v\", \"OFF\"]\n\nDEFAULT_CONFIG_FILE_PATHS = []  # type: List[Path]\n\n\ndef default_config_file_paths() -> Generator:\n    \"\"\"Get (generator) the default config file paths.\"\"\"\n    for item in DEFAULT_CONFIG_FILE_PATHS:\n        yield item\n\n\ndef unified_yaml_load(configuration_file: Path) -> Dict:\n    \"\"\"\n    Load YAML file, unified (both single- and multi-paged).\n\n    :param configuration_file: the configuration file path.\n    :return: the data.\n    \"\"\"\n    package_type = configuration_file.parent.parent.name\n    with configuration_file.open() as fp:\n        if package_type != AGENTS:\n            return yaml.safe_load(fp)\n        # when it is an agent configuration file,\n        # we are interested only in the first page of the YAML,\n        # because the dependencies are contained only there.\n        data = yaml.safe_load_all(fp)\n        return list(data)[0]\n\n\ndef get_public_id_from_yaml(configuration_file: Path) -> PublicId:\n    \"\"\"\n    Get the public id from yaml.\n\n    :param configuration_file: the path to the config yaml\n    :return: public id\n    \"\"\"\n    data = unified_yaml_load(configuration_file)\n    author = data[\"author\"]\n    # handle the case when it's a package or agent config file.\n    name = data[\"name\"] if \"name\" in data else data[\"agent_name\"]\n    version = data[\"version\"]\n    return PublicId(author, name, version)\n\n\ndef find_all_packages_ids() -> Set[PackageId]:\n    \"\"\"Find all packages ids.\"\"\"\n    package_ids: Set[PackageId] = set()\n    packages_dir = Path(\"packages\")\n    config_files = [\n        path\n        for path in packages_dir.glob(\"*/*/*/*.yaml\")\n        if any(file in str(path) for file in CONFIG_FILE_NAMES)\n    ]\n    for configuration_file in chain(config_files, default_config_file_paths()):\n        package_type = PackageType(configuration_file.parts[-3][:-1])\n        package_public_id = get_public_id_from_yaml(configuration_file)\n        package_id = PackageId(package_type, package_public_id)\n        package_ids.add(package_id)\n\n    return package_ids\n\n\nALL_PACKAGE_IDS: Set[PackageId] = find_all_packages_ids()\n\n\ndef check_correct_author(runner: CliRunner) -> None:\n    \"\"\"\n    Check whether the correct author is locally configured.\n\n    :param runner: the cli runner\n    \"\"\"\n    result = runner.invoke(\n        cli,\n        [*CLI_LOG_OPTION, \"init\"],\n        standalone_mode=False,\n    )\n    if \"{'author': 'fetchai'}\" not in result.output:\n        print(\"Log in with fetchai credentials. Stopping...\")\n        sys.exit(0)\n    else:\n        print(\"Logged in with fetchai credentials. Continuing...\")\n\n\ndef push_package(package_id: PackageId, runner: CliRunner) -> None:\n    \"\"\"\n    Pushes a package (protocol/contract/connection/skill) to registry.\n\n    Specifically:\n    - creates an empty agent project\n    - adds the relevant package from local 'packages' dir (and its dependencies)\n    - moves the relevant package out of vendor dir\n    - pushes the relevant package to registry\n\n    :param package_id: the package id\n    :param runner: the cli runner\n    \"\"\"\n    print(\n        \"Trying to push {}: {}\".format(\n            package_id.package_type.value, str(package_id.public_id)\n        )\n    )\n    cwd = os.getcwd()\n    try:\n        agent_name = \"some_agent\"\n        result = runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", \"--empty\", agent_name],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n        os.chdir(agent_name)\n        result = runner.invoke(\n            cli,\n            [\n                *CLI_LOG_OPTION,\n                \"add\",\n                \"--local\",\n                package_id.package_type.value,\n                str(package_id.public_id),\n            ],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n        src = os.path.join(\n            \"vendor\",\n            package_id.public_id.author,\n            package_id.package_type.value + \"s\",\n            package_id.public_id.name,\n        )\n        dest = os.path.join(\n            package_id.package_type.value + \"s\", package_id.public_id.name\n        )\n        shutil.copytree(src, dest)\n        result = runner.invoke(\n            cli,\n            [\n                *CLI_LOG_OPTION,\n                \"push\",\n                package_id.package_type.value,\n                str(package_id.public_id),\n            ],\n            standalone_mode=False,\n        )\n        assert (\n            result.exit_code == 0\n        ), \"Publishing {} with public_id '{}' failed with: {}\".format(\n            package_id.package_type, package_id.public_id, result.output\n        )\n    except Exception as e:  # pylint: disable=broad-except\n        print(\"\\n\\nAn exception occured: {}\\n\\n\".format(e))\n    finally:\n        os.chdir(cwd)\n        result = runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"delete\", agent_name],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n    print(\n        \"Successfully pushed {}: {}\".format(\n            package_id.package_type.value, str(package_id.public_id)\n        )\n    )\n\n\ndef publish_agent(package_id: PackageId, runner: CliRunner) -> None:\n    \"\"\"\n    Publishes an agent to registry.\n\n    Specifically:\n    - fetches an agent project from local 'packages' dir (and its dependencies)\n    - publishes the agent project to registry\n\n    :param package_id: the package id\n    :param runner: the cli runner\n    :return: None\n    \"\"\"\n    if os.path.isdir(package_id.public_id.name):\n        print(\n            f\"\\n\\nFolder with name '{package_id.public_id.name}' already exists. Skipping publication of {str(package_id.public_id)}\\n\\n\"\n        )\n        return\n    print(\n        \"Trying to push {}: {}\".format(\n            package_id.package_type.value, str(package_id.public_id)\n        )\n    )\n    cwd = os.getcwd()\n    try:\n        result = runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"fetch\", \"--local\", str(package_id.public_id)],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0, \"Local fetch failed.\"\n        os.chdir(str(package_id.public_id.name))\n        result = runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"publish\", \"--remote\"],\n            standalone_mode=False,\n        )\n        assert (\n            result.exit_code == 0\n        ), \"Pushing {} with public_id '{}' failed with: {}\".format(\n            package_id.package_type, package_id.public_id, str(result.exception)\n        )\n        print(\n            \"Successfully pushed {}: {}\".format(\n                package_id.package_type.value, str(package_id.public_id)\n            )\n        )\n    except Exception as e:  # pylint: disable=broad-except\n        print(\"\\n\\nAn exception occured: {}\\n\\n\".format(e))\n    finally:\n        os.chdir(cwd)\n        result = runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"delete\", str(package_id.public_id.name)],\n            standalone_mode=False,\n        )\n        if result.exit_code != 0:\n            print(\"Unsuccessful delete code: {}\".format(str(result.exception)))\n    time.sleep(1.0)\n\n\ndef check_and_upload(package_id: PackageId, runner: CliRunner) -> None:\n    \"\"\"\n    Check and upload.\n\n    Checks whether a package is missing from registry. If it is missing, uploads it.\n\n    :param package_id: the package id\n    :param runner: the cli runner\n    \"\"\"\n    result = runner.invoke(\n        cli,\n        [\n            *CLI_LOG_OPTION,\n            \"search\",\n            package_id.package_type.value + \"s\",\n            \"--query\",\n            package_id.public_id.name,\n        ],\n        standalone_mode=False,\n    )\n    if not str(package_id.public_id) in result.output:\n        if package_id.package_type == PackageType.AGENT:\n            publish_agent(package_id, runner)\n        else:\n            push_package(package_id, runner)\n    else:\n        print(\n            \"The {} '{}' is already in the registry\".format(\n                package_id.package_type.value, str(package_id.public_id)\n            )\n        )\n\n\ndef upload_new_packages(runner: CliRunner) -> None:\n    \"\"\"\n    Upload new packages.\n\n    Checks whether packages are missing from registry in the dependency order.\n\n    :param runner: the cli runner\n    \"\"\"\n    print(\"\\nPushing protocols:\")\n    for package_id in ALL_PACKAGE_IDS:\n        if package_id.package_type != PackageType.PROTOCOL:\n            continue\n        check_and_upload(package_id, runner)\n    print(\"\\nPushing connections and contracts:\")\n    for package_id in ALL_PACKAGE_IDS:\n        if package_id.package_type not in {\n            PackageType.CONNECTION,\n            PackageType.CONTRACT,\n        }:\n            continue\n        check_and_upload(package_id, runner)\n    print(\"\\nPushing skills:\")\n    for package_id in ALL_PACKAGE_IDS:\n        if package_id.package_type != PackageType.SKILL:\n            continue\n        check_and_upload(package_id, runner)\n    print(\"\\nPublishing agents:\")\n    for package_id in ALL_PACKAGE_IDS:\n        if package_id.package_type != PackageType.AGENT:\n            continue\n        check_and_upload(package_id, runner)\n\n\nif __name__ == \"__main__\":\n    runner_ = CliRunner()\n    check_correct_author(runner_)\n    upload_new_packages(runner_)\n    print(\"Done!\")\n    sys.exit(0)\n"
  },
  {
    "path": "scripts/freeze_dependencies.py",
    "content": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This CLI tool freezes the dependencies.\"\"\"\nimport argparse\nimport re\nimport subprocess  # nosec\n\n\ndef parse_args() -> argparse.Namespace:\n    \"\"\"Parse CLI arguments.\"\"\"\n    parser = argparse.ArgumentParser(\"freeze_dependencies\")\n    parser.add_argument(\"-o\", \"--output\", type=argparse.FileType(\"w\"), default=None)\n    return parser.parse_args()\n\n\nif __name__ == \"__main__\":\n    arguments = parse_args()\n\n    with subprocess.Popen(  # nosec\n        [\"pip\", \"freeze\"], stdout=subprocess.PIPE\n    ) as pip_freeze_call:\n        (stdout, stderr) = pip_freeze_call.communicate()\n        requirements = stdout.decode(\"utf-8\")\n\n        # remove 'aea' itself\n        regex = re.compile(\"^aea(==.*| .*)?$\", re.MULTILINE)\n        requirements = re.sub(regex, \"\", requirements)\n        if arguments.output is None:\n            print(requirements)\n        else:\n            arguments.output.write(requirements)\n"
  },
  {
    "path": "scripts/generate_all_protocols.py",
    "content": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"\nGenerate all the protocols from their specifications.\n\nThis script takes all the protocol specification (scraped from the protocol README)\nand calls the `aea generate protocol` command.\n\nCurrently, it does a lot of assumptions, and might not be useful for\nall use cases. However, with not much work, can be customized to achieve\nthe desired outcomes.\n\nIt requires the `aea` package, `black` and `isort` tools.\n\"\"\"\nimport argparse\nimport datetime\nimport logging\nimport os\nimport pprint\nimport re\nimport shutil\nimport subprocess  # nosec\nimport sys\nimport tempfile\nfrom itertools import chain\nfrom operator import methodcaller\nfrom pathlib import Path\nfrom typing import Any, Iterator, List, Optional, Tuple, cast\n\nimport click\nimport semver\n\nfrom aea.cli.registry.utils import download_file, extract, request_api\nfrom aea.common import JSONLike\nfrom aea.configurations.base import ComponentType, ProtocolConfig\nfrom aea.configurations.constants import DEFAULT_PROTOCOL_CONFIG_FILE\nfrom aea.configurations.data_types import PackageId, PublicId\nfrom aea.configurations.loader import ConfigLoaders, load_component_configuration\nfrom aea.protocols.generator.base import copy_right_str\nfrom scripts.common import (\n    check_working_tree_is_dirty,\n    enforce,\n    get_protocol_specification_from_readme,\n    setup_logger,\n)\n\n\nLIBPROTOC_VERSION = \"libprotoc 3.19.4\"\nCUSTOM_TYPE_MODULE_NAME = \"custom_types.py\"\nREADME_FILENAME = \"README.md\"\nPACKAGES_DIR = Path(\"packages\")\nTEST_DATA = Path(\"tests\", \"data\").absolute()\nPROTOCOLS_PLURALS = \"protocols\"\nROOT_DIR = Path(\".\").absolute()\nPROTOCOL_GENERATOR_DOCSTRING_REGEX = \"It was created with protocol buffer compiler version `libprotoc .*` and aea version `.*`.\"\n\n\ndef subdirs(path: Path) -> Iterator[Path]:\n    \"\"\"Get subdirectories of a path.\"\"\"\n    return filter(methodcaller(\"is_dir\"), path.iterdir())\n\n\ndef find_protocols_in_local_registry() -> Iterator[Path]:\n    \"\"\"Find all protocols in local registry.\"\"\"\n    authors = subdirs(PACKAGES_DIR)\n    component_parents = chain(*map(subdirs, authors))\n    protocols_parent = filter(lambda p: p.name == PROTOCOLS_PLURALS, component_parents)\n    protocols = chain(*map(subdirs, protocols_parent))\n    return map(methodcaller(\"absolute\"), protocols)\n\n\ndef log(message: str, level: int = logging.INFO) -> None:\n    \"\"\"Produce a logging message.\"\"\"\n    logger.log(level, message)\n\n\nlogger = setup_logger(\"generate_all_protocols\")\n\n\ndef run_cli(*args: Any, **kwargs: Any) -> None:\n    \"\"\"Run a CLI command.\"\"\"\n    log(f\"Calling command {args} with kwargs {kwargs}\")\n    return_code = subprocess.check_call(args, **kwargs)  # nosec\n    enforce(\n        return_code == 0,\n        f\"Return code of {pprint.pformat(args)} is {return_code} != 0.\",\n    )\n\n\ndef run_aea(*args: Any, **kwargs: Any) -> None:\n    \"\"\"\n    Run an AEA command.\n\n    :param args: the AEA command\n    :param kwargs: keyword arguments to subprocess function\n    \"\"\"\n    run_cli(sys.executable, \"-m\", \"aea.cli\", *args, **kwargs)\n\n\nclass AEAProject:\n    \"\"\"A context manager class to create and delete an AEA project.\"\"\"\n\n    old_cwd: str\n    temp_dir: str\n\n    def __init__(self, name: str = \"my_aea\", parent_dir: Optional[str] = None):\n        \"\"\"\n        Initialize an AEA project.\n\n        :param name: the name of the AEA project.\n        :param parent_dir: the parent directory.\n        \"\"\"\n        self.name = name\n        self.parent_dir = parent_dir\n\n    def __enter__(self) -> None:\n        \"\"\"Create and enter into the project.\"\"\"\n        self.old_cwd = os.getcwd()\n        self.temp_dir = tempfile.mkdtemp(dir=self.parent_dir)\n        os.chdir(self.temp_dir)\n\n        run_aea(\"create\", \"--local\", \"--empty\", self.name, \"--author\", \"fetchai\")\n        os.chdir(self.name)\n\n    def __exit__(self, exc_type, exc_val, exc_tb) -> None:  # type: ignore\n        \"\"\"Exit the context manager.\"\"\"\n        os.chdir(self.old_cwd)\n        shutil.rmtree(self.temp_dir)\n\n\ndef _save_specification_in_temporary_file(\n    name: str, specification_content: str\n) -> None:\n    \"\"\"\n    Save the specification in a temporary file.\n\n    :param name: the name of the package.\n    :param specification_content: the specification content.\n    \"\"\"\n    # here, the cwd is the temporary AEA project\n    # hence, we are writing in a temporary directory\n    spec_path = Path(\"..\", name + \".yaml\")\n    log(f\"Save specification '{name}' in temporary file {spec_path}\")\n    spec_path.write_text(specification_content)  # pylint: disable=unspecified-encoding\n\n\ndef _generate_protocol(package_path: Path) -> None:\n    \"\"\"\n    Generate the protocol.\n\n    :param package_path: package to the path.\n    \"\"\"\n    cmd = [\"generate\", \"protocol\", os.path.join(\"..\", package_path.name) + \".yaml\"]\n    log(f\"Generate the protocol. Command: {pprint.pformat(cmd)}\")\n    run_aea(*cmd)\n\n\ndef run_isort_and_black(directory: Path, **kwargs: Any) -> None:\n    \"\"\"Run black and isort against a directory.\"\"\"\n    run_cli(\n        sys.executable,\n        \"-m\",\n        \"black\",\n        \"--verbose\",\n        str(directory.absolute()),\n        **kwargs,\n    )\n    run_cli(\n        sys.executable,\n        \"-m\",\n        \"isort\",\n        \"--settings-path\",\n        \"pyproject.toml\",\n        \"--verbose\",\n        str(directory.absolute()),\n        **kwargs,\n    )\n\n\ndef replace_in_directory(name: str, replacement_pairs: List[Tuple[str, str]]) -> None:\n    \"\"\"\n    Replace text in directory.\n\n    :param name: the protocol name.\n    :param replacement_pairs: a list of pairs of strings (to_replace, replacement).\n    \"\"\"\n    log(f\"Replace prefix of import statements in directory '{name}'\")\n    package_dir = Path(PROTOCOLS_PLURALS, name)\n    for submodule in package_dir.rglob(\"*.py\"):\n        log(f\"Process submodule {submodule.relative_to(package_dir)}\")\n        for to_replace, replacement in replacement_pairs:\n            if to_replace not in submodule.read_text():\n                continue\n            submodule.write_text(submodule.read_text().replace(to_replace, replacement))\n\n\ndef _fix_generated_protocol(package_path: Path) -> None:\n    \"\"\"\n    Fix the generated protocol.\n\n    That means:\n    - replacing the prefix of import statements for default protocols;\n    - restore the original custom types, if any.\n    - copy the README, if any.\n\n    :param package_path: path to the protocol package. Used also to recover the protocol name.\n    \"\"\"\n    log(f\"Restore original custom types in {package_path}\")\n    custom_types_module = package_path / CUSTOM_TYPE_MODULE_NAME\n    if custom_types_module.exists():\n        file_to_replace = Path(\n            PROTOCOLS_PLURALS, package_path.name, CUSTOM_TYPE_MODULE_NAME\n        )\n        file_to_replace.write_text(  # pylint: disable=unspecified-encoding\n            custom_types_module.read_text()  # pylint: disable=unspecified-encoding\n        )\n\n    package_readme_file = package_path / README_FILENAME\n    if package_readme_file.exists():\n        log(f\"Copy the README {package_readme_file} into the new generated protocol.\")\n        shutil.copyfile(\n            package_readme_file,\n            Path(PROTOCOLS_PLURALS, package_path.name, README_FILENAME),\n        )\n\n\nCOPYRIGHT_STR = f\"\"\"# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-{datetime.datetime.now().year} Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"\n\n\ndef _set_copyright_header(package_path: Path) -> None:\n    \"\"\"Set copyright header for every python file in the package path.\"\"\"\n\n    for filename in package_path.absolute().glob(\"**/*.py\"):\n        if str(filename).endswith(\"_pb2.py\"):\n            continue\n        filepath: Path = package_path.absolute() / filename\n        content = filepath.read_text()\n        if re.search(r\"\\#\\s+Copyright\", content):\n            # header already here\n            continue\n        new_content = content.replace(copy_right_str, COPYRIGHT_STR)\n        assert \"Copyright 2018-\" in new_content\n        filepath.write_text(new_content)\n        print(filepath, \"copyright set\")\n\n\ndef _update_original_protocol(package_path: Path) -> None:\n    \"\"\"\n    Update the original protocol.\n\n    :param package_path: the path to the original package. Used to recover the protocol name.\n    \"\"\"\n    log(f\"Copy the new protocol into the original directory {package_path}\")\n    shutil.rmtree(package_path)\n    shutil.copytree(Path(PROTOCOLS_PLURALS, package_path.name), package_path)\n\n\ndef _fingerprint_protocol(name: str) -> None:\n    \"\"\"Fingerprint the generated (and modified) protocol.\"\"\"\n    log(f\"Fingerprint the generated (and modified) protocol '{name}'\")\n    protocol_config = load_component_configuration(\n        ComponentType.PROTOCOL,\n        Path(PROTOCOLS_PLURALS, name),\n        skip_consistency_check=True,\n    )\n    run_aea(\"fingerprint\", \"protocol\", str(protocol_config.public_id))\n\n\ndef _parse_generator_docstring(package_path: Path) -> str:\n    \"\"\"\n    Parse protocol generator docstring.\n\n    The docstring this function searches is in the __init__.py module\n    and it is of the form:\n\n        It was created with protocol buffer compiler version `libprotoc ...` and aea version `...`.\n\n\n    :param package_path: path to the protocol package\n    :return: the docstring\n    \"\"\"\n    content = (package_path / \"__init__.py\").read_text()\n    regex = re.compile(PROTOCOL_GENERATOR_DOCSTRING_REGEX)\n    match = regex.search(content)\n    if match is None:\n        raise ValueError(\"protocol generator docstring not found\")\n    return match.group(0)\n\n\ndef _replace_generator_docstring(package_path: Path, replacement: str) -> None:\n    \"\"\"\n    Replace the generator docstring in the __init__.py module.\n\n    (see _parse_generator_docstring for more details).\n\n    :param package_path: path to the\n    :param replacement: the replacement to use.\n    \"\"\"\n    protocol_name = package_path.name\n    init_module = Path(PROTOCOLS_PLURALS) / protocol_name / \"__init__.py\"\n    content = init_module.read_text()\n    content = re.sub(PROTOCOL_GENERATOR_DOCSTRING_REGEX, replacement, content)\n    init_module.write_text(content)\n\n\ndef _process_packages_protocol(\n    package_path: Path, preserve_generator_docstring: bool = False\n) -> None:\n    \"\"\"\n    Process protocol package from local registry.\n\n    If the flag '--no-bump' is specified, it means the protocol generator\n    string that records the AEA and the protoc version used, i.e.:\n\n        It was created with protocol buffer compiler version `libprotoc ...` and aea version `...`.\n\n    must not be updated, as the 'AEA' version could have been changed.\n\n    It means:\n    - extract protocol specification from README\n    - generate the protocol in the current AEA project\n    - fix the generated protocol (e.g. import prefixed, custom types, ...)\n    - update the original protocol with the newly generated one.\n\n    It assumes the working directory is an AEA project.\n\n    :param package_path: path to the package.\n    :param preserve_generator_docstring: if True, the protocol generator docstring is preserved (see above).\n    \"\"\"\n    if preserve_generator_docstring:\n        # save the old protocol generator docstring\n        old_protocol_generator_docstring = _parse_generator_docstring(package_path)\n    specification_content = get_protocol_specification_from_readme(package_path)\n    _save_specification_in_temporary_file(package_path.name, specification_content)\n    _generate_protocol(package_path)\n    _fix_generated_protocol(package_path)\n    if preserve_generator_docstring:\n        _replace_generator_docstring(package_path, old_protocol_generator_docstring)\n    _set_copyright_header(Path(PROTOCOLS_PLURALS, package_path.name))\n    run_isort_and_black(Path(PROTOCOLS_PLURALS, package_path.name), cwd=str(ROOT_DIR))\n    _fingerprint_protocol(package_path.name)\n    _update_original_protocol(package_path)\n\n\ndef _check_preliminaries() -> None:\n    \"\"\"Check that the required packages are installed.\"\"\"\n    try:\n        import aea  # noqa: F401  # pylint: disable=import-outside-toplevel,unused-import\n    except ModuleNotFoundError:\n        enforce(False, \"'aea' package not installed.\")\n    enforce(shutil.which(\"black\") is not None, \"black command line tool not found.\")\n    enforce(shutil.which(\"isort\") is not None, \"isort command line tool not found.\")\n    enforce(shutil.which(\"protoc\") is not None, \"protoc command line tool not found.\")\n    result = subprocess.run(  # nosec\n        [\"protoc\", \"--version\"], stdout=subprocess.PIPE, check=True\n    )\n    result_str = result.stdout.decode(\"utf-8\")\n    enforce(\n        LIBPROTOC_VERSION in result_str,\n        f\"Invalid version for protoc. Found: {result_str}. Required: {LIBPROTOC_VERSION}.\",\n    )\n\n\ndef _process_test_protocol(specification: Path, package_path: Path) -> None:\n    \"\"\"\n    Process a test protocol.\n\n    :param specification: path to specification.\n    :param package_path: the output directory.\n    \"\"\"\n    specification_content = specification.read_text()\n    _save_specification_in_temporary_file(package_path.name, specification_content)\n    _generate_protocol(package_path)\n    _fix_generated_protocol(package_path)\n    replacements = [\n        (\n            f\"from packages.fetchai.protocols.{package_path.name}\",\n            f\"from tests.data.generator.{package_path.name}\",\n        )\n    ]\n    replace_in_directory(package_path.name, replacements)\n    _set_copyright_header(Path(PROTOCOLS_PLURALS, package_path.name))\n    run_isort_and_black(Path(PROTOCOLS_PLURALS, package_path.name), cwd=str(ROOT_DIR))\n    _fingerprint_protocol(package_path.name)\n    _update_original_protocol(package_path)\n\n\ndef download_package(package_id: PackageId, destination_path: str) -> None:\n    \"\"\"Download a package into a directory.\"\"\"\n    api_path = f\"/{package_id.package_type.to_plural()}/{package_id.author}/{package_id.name}/{package_id.public_id.LATEST_VERSION}\"\n    resp = cast(JSONLike, request_api(\"GET\", api_path))\n    file_url = cast(str, resp[\"file\"])\n    filepath = download_file(file_url, destination_path)\n    extract(filepath, destination_path)\n\n\ndef _bump_protocol_specification_id(\n    package_path: Path, configuration: ProtocolConfig\n) -> None:\n    \"\"\"Bump spec id version.\"\"\"\n    spec_id: PublicId = configuration.protocol_specification_id  # type: ignore\n    old_version = semver.VersionInfo.parse(spec_id.version)\n    new_version = str(old_version.bump_minor())\n    new_spec_id = PublicId(spec_id.author, spec_id.name, new_version)\n    configuration.protocol_specification_id = new_spec_id\n    with (package_path / DEFAULT_PROTOCOL_CONFIG_FILE).open(\"w\") as file_output:\n        ConfigLoaders.from_package_type(configuration.package_type).dump(\n            configuration, file_output\n        )\n\n\ndef _bump_protocol_specification_id_if_needed(package_path: Path) -> None:\n    \"\"\"\n    Check if protocol specification id needs to be bumped.\n\n    Workflow:\n    - extract protocol specification file from README\n    - download latest protocol id and extract its protocol specification as above\n    - if different, bump protocol specification version, else don't.\n\n    :param package_path: path to the protocol package.\n    \"\"\"\n    # extract protocol specification file from README\n    current_specification_content = get_protocol_specification_from_readme(package_path)\n\n    # download latest protocol id and extract its protocol specification as above\n    configuration: ProtocolConfig = cast(\n        ProtocolConfig,\n        load_component_configuration(ComponentType.PROTOCOL, package_path),\n    )\n    temp_directory = Path(tempfile.mkdtemp())\n    try:\n        download_package(configuration.package_id, str(temp_directory))\n    except click.ClickException:\n        log(\"Protocol specification id not bumped - new protocol.\")\n        return\n    downloaded_package_directory = temp_directory / configuration.name\n    old_specification_content = get_protocol_specification_from_readme(\n        downloaded_package_directory\n    )\n    old_configuration: ProtocolConfig = cast(\n        ProtocolConfig,\n        load_component_configuration(\n            ComponentType.PROTOCOL,\n            downloaded_package_directory,\n            skip_consistency_check=True,\n        ),\n    )\n\n    # if different, bump protocol specification version, else don't.\n    public_id_version_is_newer = (\n        old_configuration.public_id.package_version  # type: ignore\n        <= configuration.public_id.package_version\n    )\n    content_is_different = current_specification_content != old_specification_content\n    if public_id_version_is_newer and content_is_different:\n        log(\n            f\"Bumping protocol specification id from '{old_configuration.protocol_specification_id}' to '{configuration.protocol_specification_id}'\"\n        )\n        _bump_protocol_specification_id(package_path, configuration)\n        return\n    log(\n        \"Protocol specification id not bumped - content is not different, or version is not newer.\"\n    )\n\n\ndef main(no_bump: bool = False) -> None:\n    \"\"\"\n    Run the script.\n\n    :param no_bump: if True, the (default: False)\n    \"\"\"\n    _check_preliminaries()\n\n    all_protocols = list(find_protocols_in_local_registry())\n\n    with AEAProject():\n        log(\"=\" * 100)\n        _process_test_protocol(\n            TEST_DATA / \"sample_specification.yaml\",\n            TEST_DATA / \"generator\" / \"t_protocol\",\n        )\n        log(\"=\" * 100)\n        _process_test_protocol(\n            TEST_DATA / \"sample_specification_no_custom_types.yaml\",\n            TEST_DATA / \"generator\" / \"t_protocol_no_ct\",\n        )\n        for package_path in all_protocols:\n            log(\"=\" * 100)\n            log(f\"Processing protocol at path {package_path}\")\n            if not no_bump:\n                _bump_protocol_specification_id_if_needed(package_path)\n            # no_bump implies to ignore the docstring:\n            #  'It was created with protocol buffer compiler ... and aea version ...'\n            _process_packages_protocol(package_path, no_bump)\n\n\nif __name__ == \"__main__\":\n    parser = argparse.ArgumentParser(\"generate_all_protocols\")\n    parser.add_argument(\n        \"--check-clean\", action=\"store_true\", help=\"Check if the working tree is clean.\"\n    )\n    parser.add_argument(\"--no-bump\", action=\"store_true\", help=\"Prevent version bump.\")\n    arguments = parser.parse_args()\n\n    main(arguments.no_bump)\n\n    if arguments.check_clean:\n        check_working_tree_is_dirty()\n"
  },
  {
    "path": "scripts/generate_api_docs.py",
    "content": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This tool generates the API docs.\"\"\"\nimport argparse\nimport re\nimport shutil\nimport subprocess  # nosec\nimport sys\nfrom pathlib import Path\n\nfrom aea.configurations.base import ComponentType, PublicId\nfrom aea.configurations.constants import (\n    DEFAULT_PROTOCOL,\n    PACKAGES,\n    SIGNING_PROTOCOL,\n    STATE_UPDATE_PROTOCOL,\n    _FETCHAI_IDENTIFIER,\n)\nfrom scripts.common import check_working_tree_is_dirty\n\n\nDOCS_DIR = Path(\"docs/\")\nAPI_DIR = DOCS_DIR / \"api/\"\nAEA_DIR = Path(\"aea\")\nPACKAGES_DIR = Path(PACKAGES)\nPLUGIN_DIR = Path(\"plugins\")\nFETCHAI_PACKAGES = PACKAGES_DIR / _FETCHAI_IDENTIFIER\nDEFAULT_PACKAGES = {\n    (ComponentType.PROTOCOL, DEFAULT_PROTOCOL),\n    (ComponentType.PROTOCOL, SIGNING_PROTOCOL),\n    (ComponentType.PROTOCOL, STATE_UPDATE_PROTOCOL),\n}\n\nIGNORE_NAMES = {r\"^__init__\\.py$\", r\"^__version__\\.py$\", r\"^py\\.typed$\", r\"^.*_pb2.py$\"}\nIGNORE_PREFIXES = {\n    Path(\"aea\", \"cli\"),\n    Path(\"aea\", \"connections\", \"scaffold\"),\n    Path(\"aea\", \"contracts\", \"scaffold\"),\n    Path(\"aea\", \"protocols\", \"scaffold\"),\n    Path(\"aea\", \"skills\", \"scaffold\"),\n    Path(\"aea\", \"decision_maker\", \"scaffold.py\"),\n    Path(\"aea\", \"error_handler\", \"scaffold.py\"),\n    Path(\"aea\", \"test_tools\", \"click_testing.py\"),\n}\n\n\ndef create_subdir(path: str) -> None:\n    \"\"\"\n    Create a subdirectory.\n\n    :param path: the directory path\n    \"\"\"\n    directory = \"/\".join(path.split(\"/\")[:-1])\n    Path(directory).mkdir(parents=True, exist_ok=True)\n\n\ndef replace_underscores(text: str) -> str:\n    \"\"\"\n    Replace escaped underscores in a text.\n\n    :param text: the text to replace underscores in\n    :return: the processed text\n    \"\"\"\n    text_a = text.replace(\"\\\\_\\\\_\", \"`__`\")\n    text_b = text_a.replace(\"\\\\_\", \"`_`\")\n    return text_b\n\n\ndef is_relative_to(p1: Path, p2: Path) -> bool:\n    \"\"\"Check if a path is relative to another path.\"\"\"\n    return str(p1).startswith(str(p2))\n\n\ndef is_not_dir(p: Path) -> bool:\n    \"\"\"Call p.is_dir() method and negate the result.\"\"\"\n    return not p.is_dir()\n\n\ndef should_skip(module_path: Path) -> bool:\n    \"\"\"Return true if the file should be skipped.\"\"\"\n    if any(re.search(pattern, module_path.name) for pattern in IGNORE_NAMES):\n        print(\"Skipping, it's in ignore patterns\")\n        return True\n    if module_path.suffix != \".py\":\n        print(\"Skipping, it's not a Python module.\")\n        return True\n    if any(is_relative_to(module_path, prefix) for prefix in IGNORE_PREFIXES):\n        print(f\"Ignoring prefix {module_path}\")\n        return True\n    return False\n\n\ndef _generate_apidocs_aea_modules() -> None:\n    \"\"\"Generate API docs for aea.* modules.\"\"\"\n    for module_path in filter(is_not_dir, Path(AEA_DIR).rglob(\"*\")):\n        print(f\"Processing {module_path}... \", end=\"\")\n        if should_skip(module_path):\n            continue\n        parents = module_path.parts[:-1]\n        parents_without_root = module_path.parts[1:-1]\n        last = module_path.stem\n        doc_file = API_DIR / Path(*parents_without_root) / f\"{last}.md\"\n        dotted_path = \".\".join(parents) + \".\" + last\n        make_pydoc(dotted_path, doc_file)\n\n\ndef _generate_apidocs_default_packages() -> None:\n    \"\"\"Generate API docs for Fetch.AI default packages.\"\"\"\n    for component_type, default_package in DEFAULT_PACKAGES:\n        public_id = PublicId.from_str(default_package)\n        author = public_id.author\n        name = public_id.name\n        type_plural = component_type.to_plural()\n        package_dir = PACKAGES_DIR / author / type_plural / name\n        for module_path in package_dir.rglob(\"*.py\"):\n            print(f\"Processing {module_path}...\", end=\"\")\n            if should_skip(module_path):\n                continue\n            suffix = Path(str(module_path.relative_to(package_dir))[:-3] + \".md\")\n            dotted_path = \".\".join(module_path.parts)[:-3]\n            doc_file = API_DIR / type_plural / name / suffix\n            make_pydoc(dotted_path, doc_file)\n\n\ndef _generate_apidocs_plugins() -> None:\n    \"\"\"Generate API docs for cyrpto plugins.\"\"\"\n    for plugin in PLUGIN_DIR.iterdir():\n        plugin_name = plugin.name\n        plugin_module_name = plugin_name.replace(\"-\", \"_\")\n        python_package_root = plugin / plugin_module_name\n        for module_path in python_package_root.rglob(\"*.py\"):\n            print(f\"Processing {module_path}...\", end=\"\")\n            if should_skip(module_path):\n                continue\n            # remove \".py\"\n            relative_module_path = module_path.relative_to(python_package_root)\n            suffix = Path(str(relative_module_path)[:-3] + \".md\")\n            dotted_path = \".\".join(module_path.parts)[:-3]\n            doc_file = API_DIR / \"plugins\" / plugin_module_name / suffix\n            make_pydoc(dotted_path, doc_file)\n\n\ndef make_pydoc(dotted_path: str, dest_file: Path) -> None:\n    \"\"\"Make a PyDoc file.\"\"\"\n    print(\n        f\"Running with dotted path={dotted_path} and dest_file={dest_file}... \", end=\"\"\n    )\n    try:\n        api_doc_content = run_pydoc_markdown(dotted_path)\n        dest_file.parent.mkdir(parents=True, exist_ok=True)\n        dest_file.write_text(api_doc_content)\n    except Exception as e:  # pylint: disable=broad-except\n        print(f\"Error: {str(e)}\")\n        return\n    print(\"Done!\")\n\n\ndef run_pydoc_markdown(module: str) -> str:\n    \"\"\"\n    Run pydoc-markdown.\n\n    :param module: the dotted path.\n    :return: the PyDoc content (pre-processed).\n    \"\"\"\n    with subprocess.Popen(  # nosec\n        [\"pydoc-markdown\", \"-m\", module, \"-I\", \".\"], stdout=subprocess.PIPE\n    ) as pydoc:\n        stdout, _ = pydoc.communicate()\n        pydoc.wait()\n        stdout_text = stdout.decode(\"utf-8\")\n        text = replace_underscores(stdout_text)\n        return text\n\n\ndef generate_api_docs() -> None:\n    \"\"\"Generate the api docs.\"\"\"\n    shutil.rmtree(API_DIR, ignore_errors=True)\n    API_DIR.mkdir()\n    _generate_apidocs_default_packages()\n    _generate_apidocs_aea_modules()\n    _generate_apidocs_plugins()\n\n\ndef install(package: str) -> int:\n    \"\"\"\n    Install a PyPI package by calling pip.\n\n    :param package: the package name and version specifier.\n    :return: the return code.\n    \"\"\"\n    return subprocess.check_call(  # nosec\n        [sys.executable, \"-m\", \"pip\", \"install\", package]\n    )\n\n\nif __name__ == \"__main__\":\n    parser = argparse.ArgumentParser(\"generate_api_docs\")\n    parser.add_argument(\n        \"--check-clean\", action=\"store_true\", help=\"Check if the working tree is clean.\"\n    )\n    arguments = parser.parse_args()\n\n    res = shutil.which(\"pydoc-markdown\")\n    if res is None:\n        install(\"pydoc-markdown==3.3.0\")\n        sys.exit(1)\n\n    generate_api_docs()\n\n    if arguments.check_clean:\n        check_working_tree_is_dirty()\n"
  },
  {
    "path": "scripts/generate_ipfs_hashes.py",
    "content": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"\nThis script generates the IPFS hashes for all packages.\n\nThis script requires that you have IPFS installed:\n- https://docs.ipfs.io/guides/guides/install/\n\"\"\"\nimport argparse\nimport collections\nimport csv\nimport operator\nimport os\nimport pprint\nimport re\nimport shutil\nimport signal\nimport socket\nimport subprocess  # nosec\nimport sys\nimport time\nimport traceback\nfrom contextlib import suppress\nfrom pathlib import Path\nfrom subprocess import TimeoutExpired  # nosec\nfrom typing import Collection, Dict, List, Optional, Tuple, Type, cast\n\nimport ipfshttpclient\n\nfrom aea.configurations.base import (\n    AgentConfig,\n    ConnectionConfig,\n    ContractConfig,\n    PackageConfiguration,\n    PackageType,\n    ProtocolConfig,\n    SkillConfig,\n    _compute_fingerprint,\n)\nfrom aea.configurations.loader import ConfigLoaders\nfrom aea.helpers.yaml_utils import yaml_dump, yaml_dump_all\n\n\nAUTHOR = \"fetchai\"\nCORE_PATH = Path(\"aea\")\nTEST_PATH = Path(\"tests\") / \"data\"\nPACKAGE_HASHES_PATH = \"packages/hashes.csv\"\nTEST_PACKAGE_HASHES_PATH = \"tests/data/hashes.csv\"\n\ntype_to_class_config = {\n    PackageType.AGENT: AgentConfig,\n    PackageType.PROTOCOL: ProtocolConfig,\n    PackageType.CONNECTION: ConnectionConfig,\n    PackageType.SKILL: SkillConfig,\n    PackageType.CONTRACT: ContractConfig,\n}  # type: Dict[PackageType, Type[PackageConfiguration]]\n\n\ndef _get_all_packages() -> List[Tuple[PackageType, Path]]:\n    \"\"\"\n    Get all the hashable package of the repository.\n\n    In particular, get them from:\n    - aea/*\n    - packages/*\n    - tests/data/*\n\n    :return: pairs of (package-type, path-to-the-package)\n    \"\"\"\n\n    def package_type_and_path(package_path: Path) -> Tuple[PackageType, Path]:\n        \"\"\"Extract the package type from the path.\"\"\"\n        item_type_plural = package_path.parent.name\n        item_type_singular = item_type_plural[:-1]\n        return PackageType(item_type_singular), package_path\n\n    CORE_PACKAGES = list(\n        map(\n            package_type_and_path,\n            [\n                CORE_PATH / \"protocols\" / \"scaffold\",\n                CORE_PATH / \"connections\" / \"scaffold\",\n                CORE_PATH / \"contracts\" / \"scaffold\",\n                CORE_PATH / \"skills\" / \"scaffold\",\n            ],\n        )\n    )\n\n    PACKAGES = list(\n        map(\n            package_type_and_path,\n            filter(operator.methodcaller(\"is_dir\"), Path(\"packages\").glob(\"*/*/*/\")),\n        )\n    )\n\n    TEST_PACKAGES = [\n        (PackageType.AGENT, TEST_PATH / \"dummy_aea\"),\n        (PackageType.CONNECTION, TEST_PATH / \"dummy_connection\"),\n        (PackageType.CONTRACT, TEST_PATH / \"dummy_contract\"),\n        (PackageType.PROTOCOL, TEST_PATH / \"generator\" / \"t_protocol\"),\n        (PackageType.PROTOCOL, TEST_PATH / \"generator\" / \"t_protocol_no_ct\"),\n        (PackageType.SKILL, TEST_PATH / \"dependencies_skill\"),\n        (PackageType.SKILL, TEST_PATH / \"exception_skill\"),\n        (PackageType.SKILL, TEST_PATH / \"dummy_skill\"),\n    ]\n\n    ALL_PACKAGES = CORE_PACKAGES + PACKAGES + TEST_PACKAGES\n    return ALL_PACKAGES\n\n\ndef sort_configuration_file(config: PackageConfiguration) -> None:\n    \"\"\"Sort the order of the fields in the configuration files.\"\"\"\n    # load config file to get ignore patterns, dump again immediately to impose ordering\n    assert config.directory is not None\n    configuration_filepath = config.directory / config.default_configuration_filename\n    if config.package_type == PackageType.AGENT:\n        json_data = config.ordered_json\n        component_configurations = json_data.pop(\"component_configurations\")\n        yaml_dump_all(\n            [json_data] + component_configurations,\n            configuration_filepath.open(\"w\", encoding=\"utf-8\"),\n        )\n    else:\n        yaml_dump(\n            config.ordered_json, configuration_filepath.open(\"w\", encoding=\"utf-8\")\n        )\n\n\ndef ipfs_hashing(\n    client: ipfshttpclient.Client,\n    configuration: PackageConfiguration,\n    package_type: PackageType,\n) -> Tuple[str, str, List[Dict]]:\n    \"\"\"\n    Hashes a package and its components.\n\n    :param client: a connected IPFS client.\n    :param configuration: the package configuration.\n    :param package_type: the package type.\n    :return: the identifier of the hash (e.g. 'fetchai/protocols/default')\n           | and the hash of the whole package.\n    \"\"\"\n    # hash again to get outer hash (this time all files)\n    # we still need to ignore some files\n    #      use ignore patterns somehow\n    # ignore_patterns = configuration.fingerprint_ignore_patterns # noqa: E800\n    assert configuration.directory is not None\n    result_list = client.add(\n        configuration.directory,\n        recursive=True,\n        period_special=False,\n        follow_symlinks=False,\n    )\n    key = os.path.join(\n        configuration.author,\n        package_type.to_plural(),\n        configuration.directory.name,\n    )\n    # check that the last result of the list is for the whole package directory\n    assert result_list[-1][\"Name\"] == configuration.directory.name\n    directory_hash = result_list[-1][\"Hash\"]\n    return key, directory_hash, result_list\n\n\ndef to_csv(package_hashes: Dict[str, str], path: str) -> None:\n    \"\"\"Outputs a dictionary to CSV.\"\"\"\n    try:\n        ordered = collections.OrderedDict(sorted(package_hashes.items()))\n        with open(path, \"w\", encoding=\"utf-8\") as csv_file:\n            writer = csv.writer(csv_file)\n            writer.writerows(ordered.items())\n    except IOError:\n        print(\"I/O error\")\n\n\ndef from_csv(path: str) -> Dict[str, str]:\n    \"\"\"Load a CSV into a dictionary.\"\"\"\n    result = collections.OrderedDict({})  # type: Dict[str, str]\n    with open(path, \"r\", encoding=\"utf-8\") as csv_file:\n        reader = csv.reader(csv_file)\n        for row in reader:\n            assert len(row) == 2\n            key, value = row\n            result[key] = value\n    return result\n\n\ndef is_port_open(host: str, port: int) -> bool:\n    \"\"\"Check is port open or not.\"\"\"\n    try:\n        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\n        result = sock.connect_ex((host, port))\n    finally:\n        sock.close()\n    return result == 0\n\n\nclass IPFSDaemon:\n    \"\"\"\n    Set up the IPFS daemon.\n\n    :raises Exception: if IPFS is not installed.\n    \"\"\"\n\n    def __init__(self, timeout: float = 15.0, port: int = 5001):\n        \"\"\"Initialise IPFS daemon.\"\"\"\n        # check we have ipfs\n        self.timeout = timeout\n        self.port = port\n        res = shutil.which(\"ipfs\")\n        if res is None:\n            raise Exception(\"Please install IPFS first!\")\n\n        with subprocess.Popen(  # nosec\n            [\"ipfs\", \"--version\"],\n            stdout=subprocess.PIPE,\n            env=os.environ.copy(),\n        ) as process:\n            output, _ = process.communicate()\n            if b\"0.6.0\" not in output:\n                raise Exception(\n                    \"Please ensure you have version 0.6.0 of IPFS daemon installed.\"\n                )\n        self.process = None  # type: Optional[subprocess.Popen]\n\n    def __enter__(self) -> None:\n        \"\"\"Run the ipfs daemon.\"\"\"\n        self.process = subprocess.Popen(  # nosec  # pylint: disable=consider-using-with\n            [\"ipfs\", \"daemon\"],\n            stdout=subprocess.PIPE,\n            env=os.environ.copy(),\n        )\n        print(\"Waiting for {} seconds the IPFS daemon to be up.\".format(self.timeout))\n\n        t = time.time()\n        while time.time() - t < self.timeout:\n            if is_port_open(host=\"localhost\", port=self.port):\n                return\n            time.sleep(1)\n        raise ValueError(\"failed to connect\")\n\n    def __exit__(self, exc_type, exc_val, exc_tb) -> None:  # type: ignore\n        \"\"\"Terminate the ipfs daemon.\"\"\"\n        if self.process is None:\n            return\n        self.process.send_signal(signal.SIGTERM)\n        with suppress(TimeoutExpired):\n            self.process.wait(timeout=30)\n        poll = self.process.poll()\n        if poll is None:\n            self.process.terminate()\n            self.process.wait(2)\n\n\ndef load_configuration(\n    package_type: PackageType, package_path: Path\n) -> PackageConfiguration:\n    \"\"\"\n    Load a configuration, knowing the type and the path to the package root.\n\n    :param package_type: the package type.\n    :param package_path: the path to the package root.\n    :return: the configuration object.\n    \"\"\"\n    configuration_class = type_to_class_config[package_type]\n    configuration_filepath = (\n        package_path / configuration_class.default_configuration_filename\n    )\n\n    loader = ConfigLoaders.from_package_type(package_type)\n    with configuration_filepath.open() as fp:\n        configuration_obj = loader.load(fp)\n    configuration_obj._directory = package_path  # pylint: disable=protected-access\n    return cast(PackageConfiguration, configuration_obj)\n\n\ndef assert_hash_consistency(\n    fingerprint: Dict[str, str], path_prefix: Path, client: ipfshttpclient.Client\n) -> None:\n    \"\"\"\n    Check that our implementation of IPFS hashing for a package is correct against the true IPFS.\n\n    :param fingerprint: the fingerprint dictionary.\n    :param path_prefix: the path prefix to prepend.\n    :param client: the client.\n    \"\"\"\n    # confirm ipfs only generates same hash:\n    for file_name, ipfs_hash in fingerprint.items():\n        path = path_prefix / file_name\n        expected_ipfs_hash = client.add(path)[\"Hash\"]\n        assert (\n            expected_ipfs_hash == ipfs_hash\n        ), \"WARNING, hashes don't match for: {}\".format(path)\n\n\ndef _replace_fingerprint_non_invasive(\n    fingerprint_dict: Dict[str, str], text: str\n) -> str:\n    \"\"\"\n    Replace the fingerprint in a configuration file (not invasive).\n\n    We need this function because libraries like `yaml` may modify the\n    content of the .yaml file when loading/dumping. Instead,\n    working with the content of the file gives us finer granularity.\n\n    :param fingerprint_dict: the fingerprint dictionary.\n    :param text: the content of a configuration file.\n    :return: the updated content of the configuration file.\n    \"\"\"\n\n    def to_row(x: Tuple[str, str]) -> str:\n        return x[0] + \": \" + x[1]\n\n    replacement = \"\\nfingerprint:\\n  {}\\n\".format(\n        \"\\n  \".join(map(to_row, sorted(fingerprint_dict.items())))\n    )\n    return re.sub(r\"\\nfingerprint:\\W*\\n(?:\\W+.*\\n)*\", replacement, text)\n\n\ndef compute_fingerprint(  # pylint: disable=unsubscriptable-object\n    package_path: Path,\n    fingerprint_ignore_patterns: Optional[Collection[str]],\n    client: ipfshttpclient.Client,\n) -> Dict[str, str]:\n    \"\"\"\n    Compute the fingerprint of a package.\n\n    :param package_path: path to the package.\n    :param fingerprint_ignore_patterns: filename patterns whose matches will be ignored.\n    :param client: the IPFS Client. It is used to compare our implementation with the true implementation of IPFS hashing.\n    :return: the fingerprint\n    \"\"\"\n    fingerprint = _compute_fingerprint(\n        package_path,\n        ignore_patterns=fingerprint_ignore_patterns,\n    )\n    assert_hash_consistency(fingerprint, package_path, client)\n    return fingerprint\n\n\ndef update_fingerprint(\n    configuration: PackageConfiguration, client: ipfshttpclient.Client\n) -> None:\n    \"\"\"\n    Update the fingerprint of a package.\n\n    :param configuration: the configuration object.\n    :param client: the IPFS Client. It is used to compare our implementation with the true implementation of IPFS hashing.\n    :return: None\n    \"\"\"\n    # we don't process agent configurations\n    if isinstance(configuration, AgentConfig):\n        return\n    assert configuration.directory is not None\n    fingerprint = compute_fingerprint(\n        configuration.directory, configuration.fingerprint_ignore_patterns, client\n    )\n    config_filepath = (\n        configuration.directory / configuration.default_configuration_filename\n    )\n    old_content = config_filepath.read_text()\n    new_content = _replace_fingerprint_non_invasive(fingerprint, old_content)\n    config_filepath.write_text(new_content)\n\n\ndef check_fingerprint(\n    configuration: PackageConfiguration, client: ipfshttpclient.Client\n) -> bool:\n    \"\"\"\n    Check the fingerprint of a package, given the loaded configuration file.\n\n    :param configuration: the configuration object.\n    :param client: the IPFS Client. It is used to compare our implementation with the true implementation of IPFS hashing.\n    :return: True if the fingerprint match, False otherwise.\n    \"\"\"\n    # we don't process agent configurations\n    if isinstance(configuration, AgentConfig):\n        return True\n    assert configuration.directory is not None\n    expected_fingerprint = compute_fingerprint(\n        configuration.directory, configuration.fingerprint_ignore_patterns, client\n    )\n    actual_fingerprint = configuration.fingerprint\n    result = expected_fingerprint == actual_fingerprint\n    if not result:\n        print(\n            \"Fingerprints do not match for {} in {}\".format(\n                configuration.name, configuration.directory\n            )\n        )\n    return result\n\n\ndef parse_arguments() -> argparse.Namespace:\n    \"\"\"Parse arguments.\"\"\"\n    script_name = Path(__file__).name\n    parser = argparse.ArgumentParser(\n        script_name, description=\"Generate/check hashes of packages.\"\n    )\n    parser.add_argument(\n        \"--check\",\n        action=\"store_true\",\n        default=False,\n        help=\"Only check if the hashes are up-to-date.\",\n    )\n    parser.add_argument(\n        \"--timeout\",\n        type=float,\n        default=15.0,\n        help=\"Time to wait before IPFS daemon is up and running.\",\n    )\n\n    arguments_ = parser.parse_args()\n    return arguments_\n\n\ndef update_hashes(timeout: float = 15.0) -> int:\n    \"\"\"\n    Process all AEA packages, update fingerprint, and update hashes.csv files.\n\n    :param timeout: timeout to the update.\n    :return: exit code. 0 for success, 1 if an exception occurred.\n    \"\"\"\n    return_code_ = 0\n    package_hashes = {}  # type: Dict[str, str]\n    test_package_hashes = {}  # type: Dict[str, str]\n    # run the ipfs daemon\n    with IPFSDaemon(timeout=timeout):\n        try:\n            # connect ipfs client\n            client = ipfshttpclient.connect(\n                \"/ip4/127.0.0.1/tcp/5001/http\"\n            )  # type: ipfshttpclient.Client\n\n            # ipfs hash the packages\n            for package_type, package_path in _get_all_packages():\n                print(\n                    \"Processing package {} of type {}\".format(\n                        package_path.name, package_type\n                    )\n                )\n                configuration_obj = load_configuration(package_type, package_path)\n                sort_configuration_file(configuration_obj)\n                update_fingerprint(configuration_obj, client)\n                key, package_hash, _ = ipfs_hashing(\n                    client, configuration_obj, package_type\n                )\n                if TEST_PATH in package_path.parents:\n                    test_package_hashes[key] = package_hash\n                else:\n                    package_hashes[key] = package_hash\n\n            # output the package hashes\n            to_csv(package_hashes, PACKAGE_HASHES_PATH)\n            to_csv(test_package_hashes, TEST_PACKAGE_HASHES_PATH)\n\n            print(\"Done!\")\n        except Exception:  # pylint: disable=broad-except\n            traceback.print_exc()\n            return_code_ = 1\n\n    return return_code_\n\n\ndef check_same_ipfs_hash(\n    client: ipfshttpclient,\n    configuration: PackageConfiguration,\n    package_type: PackageType,\n    all_expected_hashes: Dict[str, str],\n) -> bool:\n    \"\"\"\n    Compute actual package hash and compare with expected hash.\n\n    :param client: the IPFS client.\n    :param configuration: the configuration object of the package.\n    :param package_type: the type of package.\n    :param all_expected_hashes: the dictionary of all the expected hashes.\n    :return: True if the IPFS hash match, False otherwise.\n    \"\"\"\n    # if configuration.name in [\n    #     \"erc1155\",\n    #     \"carpark_detection\",\n    #     \"p2p_libp2p\",\n    #     \"Agent0\",\n    #     \"dummy\",\n    # ]: # noqa: E800\n    #     return True  # packages with nested dirs or symlinks, kept for reference # noqa: E800\n    key, actual_hash, result_list = ipfs_hashing(client, configuration, package_type)\n    expected_hash = all_expected_hashes[key]\n    result = actual_hash == expected_hash\n    if not result:\n        print(\n            f\"IPFS Hashes do not match for {configuration.name} in {configuration.directory}\"\n        )\n        print(f\"Expected: {expected_hash}\")\n        print(f\"Actual:   {actual_hash}\")\n        print(\"All the hashes: \", pprint.pformat(result_list))\n    return result\n\n\ndef check_hashes(timeout: float = 15.0) -> int:\n    \"\"\"\n    Check fingerprints and outer hash of all AEA packages.\n\n    :param timeout: timeout to the check.\n    :return: exit code. 1 if some fingerprint/hash don't match or if an exception occurs, 0 in case of success.\n    \"\"\"\n    return_code_ = 0\n    failed = False\n    expected_package_hashes = from_csv(PACKAGE_HASHES_PATH)  # type: Dict[str, str]\n    expected_test_package_hashes = from_csv(\n        TEST_PACKAGE_HASHES_PATH\n    )  # type: Dict[str, str]\n    all_expected_hashes = {**expected_package_hashes, **expected_test_package_hashes}\n    with IPFSDaemon(timeout=timeout):\n        try:\n            # connect ipfs client\n            client = ipfshttpclient.connect(\n                \"/ip4/127.0.0.1/tcp/5001/http\"\n            )  # type: ipfshttpclient.Client\n\n            for package_type, package_path in _get_all_packages():\n                configuration_obj = load_configuration(package_type, package_path)\n                failed = failed or not check_fingerprint(configuration_obj, client)\n                failed = failed or not check_same_ipfs_hash(\n                    client, configuration_obj, package_type, all_expected_hashes\n                )\n        except Exception:  # pylint: disable=broad-except\n            traceback.print_exc()\n            failed = True\n\n    if failed:\n        return_code_ = 1\n    else:\n        print(\"OK!\")\n\n    return return_code_\n\n\ndef clean_directory() -> None:\n    \"\"\"Clean the directory.\"\"\"\n    clean_command = [\"make\", \"clean\"]\n    with subprocess.Popen(clean_command, stdout=subprocess.PIPE) as process:  # nosec\n        _, _ = process.communicate()\n\n\nif __name__ == \"__main__\":\n    arguments = parse_arguments()\n    if arguments.check:\n        return_code = check_hashes(arguments.timeout)\n    else:\n        clean_directory()\n        return_code = update_hashes(arguments.timeout)\n\n    sys.exit(return_code)\n"
  },
  {
    "path": "scripts/install.ps1",
    "content": "# usage\n# from cmd: @\"%SystemRoot%\\System32\\WindowsPowerShell\\v1.0\\powershell.exe\" -NoProfile -InputFormat None -ExecutionPolicy Bypass -Command \"iex ((New-Object System.Net.WebClient).DownloadString('https://raw.githubusercontent.com/fetchai/agents-aea/main/scripts/install.ps1'))\"\n# from powershell: iex ((New-Object System.Net.WebClient).DownloadString('https://raw.githubusercontent.com/fetchai/agents-aea/main/scripts/install.ps1'))\n\nfunction install_python {\n\techo \"Installing python\"\n    Invoke-WebRequest https://www.python.org/ftp/python/3.8.6/python-3.8.6-amd64-webinstall.exe -OutFile python-3.8.6-amd64-webinstall.exe\n    ./python-3.8.6-amd64-webinstall.exe /install /passive PrependPath=1 Include_test=0 Include_tcltk=0| Out-Null\n    rm ./python-3.8.6-amd64-webinstall.exe\n\n}\n\nfunction install_build_tools {\n\t$output=pip install wheel --force --no-cache-dir 2>&1 |out-string;\n\t$output=pip wheel cytoolz --no-cache-dir 2>&1 |out-string;\n    if ($LastExitCode -ne 0) {\n    \techo \"Installing visual studio build tools\"\n\t    Invoke-WebRequest https://download.microsoft.com/download/5/f/7/5f7acaeb-8363-451f-9425-68a90f98b238/visualcppbuildtools_full.exe -OutFile visualcppbuildtools_full.exe\n\t    ./visualcppbuildtools_full.exe /NoRestart /Passive | Out-Null\n\t    rm ./visualcppbuildtools_full.exe\n\t} else{\n\t\techo \"Visual studio build tools are already installed\"\n\n\t}\n\n}\n\n\nfunction instal_choco_golang_gcc {\n   echo \"Choco, golang and gcc will be installed\"\n   echo \"You'll be asked for admin shell\"\n   sleep 5\n   Start-Process powershell -Verb runAs -ArgumentList \"Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1')); choco install -y golang mingw\"\n}\nfunction install_aea {\n\techo \"Install aea\"\n    $output=pip install aea[all]==1.1.1 --force --no-cache-dir 2>&1 |out-string;\n    if ($LastExitCode -ne 0) {\n        echo $output\n        echo \"AEA install failed!\"\n        exit 1\n\t}\n\n    aea --help 2>&1 |out-null;\n    if ($LastExitCode -eq 0) {\n        echo \"AEA successfully installed\"\n    }else{\n        echo \"AEA installed but can not be runned!\"\n    }\n}\n\nfunction refresh-path {\n    $env:Path = [System.Environment]::GetEnvironmentVariable(\"Path\",\"Machine\") +\n        \";\" +\n    [System.Environment]::GetEnvironmentVariable(\"Path\",\"User\")\n}\n\nfunction check_python {\n\ttry{\n\t    if (((python -V)|Out-String) -match \"Python 3\\.[678]\\.\") {\n\t        echo \"Python installed and supported!\"\n\t    }else{\n\t        install_python\n\t    }\n\t}catch{\n\t    install_python\n\t}\n}\n\nfunction main{\n    refresh-path\n    check_python\n    install_build_tools\n    refresh-path\n    install_aea\n    instal_choco_golang_gcc\n    pause\n}\n\nmain\n"
  },
  {
    "path": "scripts/install.sh",
    "content": "#!/bin/bash\n### usage\n# mac/linux: /bin/bash -c \"$(curl -fsSL https://raw.githubusercontent.com/fetchai/agents-aea/main/scripts/install.sh)\"\n\nfunction bad_os_type() {\n\techo \"OS $OSTYPE is not supported!\"\n\texit 1\n}\n\nfunction check_linux() {\n\t# check any deb distribution!\n\tis_ubuntu=`cat /etc/issue|grep -i Ubuntu`\n\tif  [[ -z $is_ubuntu ]];\n\tthen\n\t\techo \"Only ubuntu, macos are supported at the moment with this script. please use install.ps1 for windows 10\"\n\t\texit 1\n\tfi\n\tinstall_on_ubuntu\n}\n\n\nfunction is_python3(){\n\treturn `which python3`\n}\n\nfunction is_python_version_ok() {\n\tif which python3 2>&1 >/dev/null;\n\tthen\n\t\tversion=`python3 -V 2>/dev/null`\n\t\tif [[ -z `echo $version|grep -E 'Python 3\\.([(89]|10)\\.[0-9]+'` ]];\n\t\tthen\n\t\t\techo \"Python3 version: ${version} is not supported. Supported versions are 3.8, 3.9, and 3.10.\"\n\t\t\treturn 1\n\t\tfi\n\t\treturn 0\n\telse\n\t\techo \"Python is not installed\"\n\t\treturn 1\n\tfi\n}\n\n\nfunction install_aea (){\n\techo \"Install AEA\"\n\toutput=$(pip3 install --user aea[all]==1.2.5 --force --no-cache-dir)\n\tif [[  $? -ne 0 ]];\n\tthen\n\t\techo \"$output\"\n\t\techo 'Failed to install aea'\n\t\texit 1\n\tfi\n\ttouch ~/.profile\n\tpy_user_base=`python3 -m site --user-base`\n\techo  >>~/.bashrc\n\techo 'export PATH=$PATH'\":${py_user_base}/bin\" >>~/.bashrc \n\techo  >>~/.zshrc\n\techo 'export PATH=$PATH'\":${py_user_base}/bin\" >>~/.zshrc\n\tsource ~/.bashrc  # sometimes ~/.local/bin is not in PATH\n\toutput=`aea --help 2>&1`\n\tif [[  $? -ne 0 ]];\n\tthen\n\t\techo \"$output\"\n\t\techo 'Test run of aea failed!'\n\t\texit 1\n\tfi\n\techo \"AEA successfully installed!\"\n\techo \"It's recommended to open a new shell to work with AEA.\"\n}\n\nfunction install_ubuntu_deps(){\n\t# always install it cause python3-dev can be missing! also it's not consuming much time.\n\techo \"Install python3 and dependencies\"\n\toutput=$(sudo bash -c \"apt update && apt install python3 python3-pip python3-dev -y\" 2>&1)\n\tif [[  $? -ne 0 ]];\n\tthen\n\t\techo \"$output\"\n\t\techo -n '\\n\\nFailed to install required packages!'\n\t\texit 1\n\tfi\n\n}\n\nfunction check_python_version(){\n\toutput=$(is_python_version_ok)\n\tif [[ $? -eq 1 ]];\n\tthen\n\t\techo \"$output\"\n\t\techo \"Can not install supported python version. probably distribution is too old. Exit.\"\n\t\texit 1\n\tfi\n}\n\nfunction install_on_ubuntu(){\n\tinstall_ubuntu_deps\n\tcheck_python_version\n\tinstall_aea\n}\n\nfunction ensure_brew(){\n\toutput=`which brew`\n\tif [[ $? -ne 0 ]];\n\tthen\n\t\techo \"Installing homebrew. Please pay attention, it can ask for the password and agree to install xcode tools.\"\n\t\t/bin/bash -c \"$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)\"\n\t\tif [[ $? -eq 0 ]];\n\t\tthen\n\t\t\techo \"Homebrew was installed!\"\n\t\telse\n\t\t\techo \"Homebrew failed to install!\"\n\t\tfi\n\tfi\n}\n\nfunction mac_install_python(){\n\toutput=`is_python_version_ok`\n\tif [[ $? -eq 0 ]];\n\tthen\n\t\techo \"Python supported version already installed!\"\n\t\treturn 0\n\tfi\n\n\tensure_brew\n\techo \"Install python3.8. It takes long time.\"\n\toutput=$(brew install python@3.8 2>&1)\n\tif [[ $? -eq 0 ]];\n\tthen\n\t\techo \"Python was successfully installed!\"\n\t\treturn 0\n\telse\n\t\techo \"$output\"\n\t\techo \"Python failed to install!\"\n\t\texit 1\n\tfi\n}\n\nfunction install_on_mac(){\n\tmac_install_python\n\tcheck_python_version\n\tinstall_aea\n}\n\nfunction main(){\n\techo \"Welcome to AEA installer!\"\n\tcase \"$OSTYPE\" in\n\t  darwin*)  install_on_mac ;;\n\t  linux*)   check_linux ;;\n\t  *)        bad_os_type ;;\n\tesac\n}\n\nmain\n"
  },
  {
    "path": "scripts/ledger_network_update.py",
    "content": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Setup script to update ledger network.\"\"\"\nimport re\nfrom pathlib import Path\nfrom typing import Optional\n\nimport click  # type: ignore\n\n\nROOT_DIR = Path(__file__).parent / \"../\"\n\nAEA_LEDGER_MODULE_FILE = ROOT_DIR / \"aea/crypto/ledger_apis.py\"\nFETCHAI_LEDGER_FILE = (\n    ROOT_DIR / \"plugins/aea-ledger-fetchai/aea_ledger_fetchai/fetchai.py\"\n)\nLEDGER_INTEGRATION_MD = ROOT_DIR / \"docs/ledger-integration.md\"\n\n\nclass NetworkConfig:\n    \"\"\"Ledger network configuration data class.\"\"\"\n\n    net_name: str\n    chain_id: str\n    denom: str\n    rest_api_address: str\n    rpc_api_address: str\n    faucet_url: Optional[str]\n    explorer_url: Optional[str]\n\n    def __init__(\n        self,\n        net_name: str,\n        chain_id: str,\n        denom: str,\n        rest_api_address: str,\n        rpc_api_address: str,\n        faucet_url: Optional[str] = None,\n        explorer_url: Optional[str] = None,\n    ):\n        \"\"\"\n        Set network config.\n\n        :param net_name: str\n        :param chain_id: str\n        :param denom: str\n        :param rest_api_address: str\n        :param rpc_api_address: str\n        :param faucet_url: optional str\n        :param explorer_url: optional str\n        \"\"\"\n        self.net_name = net_name\n        self.chain_id = chain_id\n        self.denom = denom\n        self.rest_api_address = rest_api_address\n        self.rpc_api_address = rpc_api_address\n        self.faucet_url = faucet_url or self.make_faucet_url(net_name)\n        self.explorer_url = explorer_url or self.make_explorer_url(net_name)\n\n    @staticmethod\n    def make_faucet_url(net_name) -> str:\n        \"\"\"Make default faucet url based on net name.\"\"\"\n        return f\"https://faucet-{net_name}.t-v2-london-c.fetch-ai.com\"\n\n    @staticmethod\n    def make_explorer_url(net_name) -> str:\n        \"\"\"Make default explorer url based on net name.\"\"\"\n        return f\"https://explore-{net_name}.fetch.ai\"\n\n    def __str__(self) -> str:\n        \"\"\"Return lines of network configration to be printed.\"\"\"\n        return (\n            f\"Net name: {self.net_name}\\n\"\n            f\"Chain id: {self.chain_id}\\n\"\n            f\"Denom: {self.denom}\\n\"\n            f\"REST API address: {self.rest_api_address}\\n\"\n            f\"RPC address: {self.rpc_api_address}\\n\"\n            f\"Testnet faucet address: {self.faucet_url}\\n\"\n            f\"Block explorer address: {self.explorer_url}\\n\"\n        )\n\n\ndef _get_value(variable_name: str, text: str) -> str:\n    m = re.search(rf'{variable_name} = \"(.*)\"', text, re.MULTILINE)\n    if m:\n        return m.groups()[0]\n    raise ValueError(\"Value not found\")\n\n\nclass NetworkUpdate:\n    \"\"\"Ledger network update tool.\"\"\"\n\n    cur_config: NetworkConfig\n    new_config: NetworkConfig\n    cosmpy_version: str\n\n    @staticmethod\n    def get_current_config() -> NetworkConfig:\n        \"\"\"\n        Get current ledger network configuration.\n\n        :return: NetworkConfig instance\n        \"\"\"\n        code_text = FETCHAI_LEDGER_FILE.read_text()\n\n        rest_api_addr = _get_value(\"DEFAULT_ADDRESS\", code_text)\n        chain_id = _get_value(\"DEFAULT_CHAIN_ID\", code_text)\n        denom = _get_value(\"DEFAULT_CURRENCY_DENOM\", code_text)\n        faucet_url = _get_value(\"FETCHAI_TESTNET_FAUCET_URL\", code_text)\n\n        m = re.match(r\"https://rest-(\\w+).fetch.ai:443\", rest_api_addr)\n        if not m:\n            raise ValueError(\n                f\"can not determine network name from address: {rest_api_addr}\"\n            )\n        net_name = m.groups()[0]\n\n        rpc_api_addr = f\"https://rpc-{net_name}.fetch.ai:443\"\n\n        m = re.search(\n            r'\\| Block Explorer \\| <a href=\"(.*)\" target=',\n            LEDGER_INTEGRATION_MD.read_text(),\n            re.MULTILINE,\n        )\n        if not m:\n            raise ValueError(f\"REGEX search failed for {LEDGER_INTEGRATION_MD}\")\n        explorer_url = m.groups()[0]\n\n        return NetworkConfig(\n            net_name=net_name,\n            chain_id=chain_id,\n            denom=denom,\n            rest_api_address=rest_api_addr,\n            rpc_api_address=rpc_api_addr,\n            faucet_url=faucet_url,\n            explorer_url=explorer_url,\n        )\n\n    def get_new_config(self) -> NetworkConfig:\n        \"\"\"\n        Get new ledger network configuration.\n\n        :return: NetworkConfig instance\n        \"\"\"\n        net_name = click.prompt(\n            \"Enter the new network name\", default=self.cur_config.net_name\n        )\n        chain_id = f\"{net_name}-1\"\n        chain_id = click.prompt(\"Enter the new chain id\", default=chain_id)\n        denom = \"atestfet\"\n        denom = click.prompt(\"Enter the new denomination\", default=denom)\n        rpc_api_addr = f\"https://rpc-{net_name}.fetch.ai:443\"\n        rpc_api_addr = click.prompt(\"Enter the new rpc address\", default=rpc_api_addr)\n        rest_api_addr = f\"https://rest-{net_name}.fetch.ai:443\"\n        rest_api_addr = click.prompt(\n            \"Enter the new rest api address\", default=rest_api_addr\n        )\n        explorer_url = NetworkConfig.make_explorer_url(net_name)\n        explorer_url = click.prompt(\n            \"Enter the new explorer address\", default=explorer_url\n        )\n        faucet_url = NetworkConfig.make_faucet_url(net_name)\n        faucet_url = click.prompt(\n            \"Enter the new testnet faucet address\", default=faucet_url\n        )\n\n        return NetworkConfig(\n            net_name=net_name,\n            chain_id=chain_id,\n            denom=denom,\n            rest_api_address=rest_api_addr,\n            rpc_api_address=rpc_api_addr,\n            faucet_url=faucet_url,\n            explorer_url=explorer_url,\n        )\n\n    @staticmethod\n    def get_current_cosmpy_version() -> str:\n        \"\"\"\n        Get currect cosmpy version from fetch ledger plugin.\n\n        :return: str\n        \"\"\"\n        plugin_setup_py = ROOT_DIR / \"plugins/aea-ledger-fetchai/setup.py\"\n\n        for i in plugin_setup_py.read_text().splitlines():\n            m = re.search('\"cosmpy(.*)\"', i)\n            if m:\n                return m.groups()[0]\n        raise ValueError(\"Can not determine current cosmpy version\")\n\n    def get_cosmpy_version(self):\n        \"\"\"\n        Get new cosmpy version to apply.\n\n        :return: str\n        \"\"\"\n\n        cur_version = self.get_current_cosmpy_version()\n        return click.prompt(\n            \"Enter cosmpy version (pip style, >=0.2.0)\", default=cur_version\n        )\n\n    def run(self):\n        \"\"\"Do update.\"\"\"\n        self.cur_config = self.get_current_config()\n        click.echo(\"Current network config:\")\n        click.echo(self.cur_config)\n\n        self.cosmpy_version = self.get_cosmpy_version()\n        click.echo(\"\")\n        self.new_config = self.get_new_config()\n\n        click.echo(\"\\n\\n------------\")\n        click.echo(\"New network config:\")\n        click.echo(self.new_config)\n        click.echo(f\"cosmpy version is cosmpy{self.cosmpy_version}\")\n        click.echo()\n        if not click.confirm(\"Do you want to continue?\"):\n            click.echo(\"Exit\")\n            return\n        click.echo(\"Do the update\")\n        self.update_protobuf()\n        self.update_spelling()\n        self.update_cosmpy_version()\n\n        self.update_docs()\n        self.update_conftest()\n        self.update_packages()\n        self.update_plugins()\n        self.update_aea_ledger_crypto()\n\n        self.print_footer()\n\n    @staticmethod\n    def update_protobuf():\n        \"\"\"Update protobuf dependency.\"\"\"\n        click.echo(\"protobuf is not updating at the moment\")\n\n    def update_spelling(self):\n        \"\"\"Add network name to spelling file.\"\"\"\n        click.echo(\"Add network name to spelling\")\n        spelling = ROOT_DIR / \".spelling\"\n        spelling.write_text(\n            spelling.read_text()\n            + f\"\\n{self.new_config.net_name}\\n{self.new_config.chain_id}\"\n        )\n\n    def update_cosmpy_version(self):\n        \"\"\"Set new cosmpy version.\"\"\"\n        click.echo(\"Update cosmpy version\")\n        # pipenv\n        pipenv = ROOT_DIR / \"Pipfile\"\n        pipenv.write_text(\n            re.sub(\n                'cosmpy = \".*\"', f'cosmpy = \"{self.cosmpy_version}\"', pipenv.read_text()\n            )\n        )\n        # aea ledger fetchai plugin\n        plugin_setup_py = ROOT_DIR / \"plugins/aea-ledger-fetchai/setup.py\"\n        plugin_setup_py.write_text(\n            re.sub(\n                '\"cosmpy.*\"',\n                f'\"cosmpy{self.cosmpy_version}\"',\n                plugin_setup_py.read_text(),\n            )\n        )\n\n        # aea ledger cosmos plugin\n        plugin_setup_py = ROOT_DIR / \"plugins/aea-ledger-cosmos/setup.py\"\n        plugin_setup_py.write_text(\n            re.sub(\n                '\"cosmpy.*\"',\n                f'\"cosmpy{self.cosmpy_version}\"',\n                plugin_setup_py.read_text(),\n            )\n        )\n\n        # tox\n        tox_file = ROOT_DIR / \"tox.ini\"\n        tox_file.write_text(\n            re.sub(\"cosmpy.*\", f\"cosmpy{self.cosmpy_version}\", tox_file.read_text())\n        )\n\n    def update_aea_ledger_crypto(self):\n        \"\"\"Update aea/ledger/crypto.py with new defaults.\"\"\"\n        click.echo(\"Update aea/ledger/crypto.py\")\n        content = AEA_LEDGER_MODULE_FILE.read_text()\n\n        content = content.replace(\n            f'FETCHAI_DEFAULT_ADDRESS = \"{self.cur_config.rest_api_address}\"',\n            f'FETCHAI_DEFAULT_ADDRESS = \"{self.new_config.rest_api_address}\"',\n        )\n        content = content.replace(\n            f'FETCHAI_DEFAULT_CURRENCY_DENOM = \"{self.cur_config.denom}\"',\n            f'FETCHAI_DEFAULT_CURRENCY_DENOM = \"{self.new_config.denom}\"',\n        )\n        content = content.replace(\n            f'FETCHAI_DEFAULT_CHAIN_ID = \"{self.cur_config.chain_id}\"',\n            f'FETCHAI_DEFAULT_CHAIN_ID = \"{self.new_config.chain_id}\"',\n        )\n\n        AEA_LEDGER_MODULE_FILE.write_text(content)\n\n    def update_docs(self):\n        \"\"\"Update documentation.\"\"\"\n        click.echo(\"Update docs\")\n        docs_files = (ROOT_DIR / \"docs\").glob(\"**/*.md\")\n        for f in docs_files:\n            content = f.read_text()\n            content = content.replace(\n                self.cur_config.explorer_url,\n                self.new_config.explorer_url,\n            )\n            content = content.replace(\n                f\"Fetch.ai `{self.cur_config.net_name.capitalize()}`\",\n                f\"Fetch.ai `{self.new_config.net_name.capitalize()}`\",\n            )\n            content = content.replace(\n                f\"Fetchai {self.cur_config.net_name.capitalize()} or a local Ganache \",\n                f\"Fetchai {self.new_config.net_name.capitalize()} or a local Ganache \",\n            )\n\n            content = content.replace(\n                f\"{self.cur_config.net_name.capitalize()} block explorer\",\n                f\"{self.new_config.net_name.capitalize()} block explorer\",\n            )\n\n            content = content.replace(\n                f\"{self.cur_config.net_name.capitalize()} block explorer\",\n                f\"{self.new_config.net_name.capitalize()} block explorer\",\n            )\n\n            content = content.replace(\n                f\"{self.cur_config.net_name.capitalize()} testnet\",\n                f\"{self.new_config.net_name.capitalize()} testnet\",\n            )\n\n            content = content.replace(\n                f\"| Chain ID       | {self.cur_config.chain_id}\",\n                f\"| Chain ID       | {self.new_config.chain_id}\",\n            )\n            content = content.replace(\n                f\"| RPC Endpoint   | {self.cur_config.rpc_api_address}\",\n                f\"| RPC Endpoint   | {self.new_config.rpc_api_address}\",\n            )\n\n            content = content.replace(\n                f\"| REST Endpoint  | {self.cur_config.rest_api_address}\",\n                f\"| REST Endpoint  | {self.new_config.rest_api_address}\",\n            )\n            f.write_text(content)\n\n    def update_conftest(self):\n        \"\"\"Update tests/conftest.py.\"\"\"\n        click.echo(\"Update tests/conftest.py\")\n        f = ROOT_DIR / \"tests/conftest.py\"\n        content = f.read_text()\n        content = content.replace(\n            f'DEFAULT_FETCH_ADDR_REMOTE = \"{self.cur_config.rest_api_address}\"',\n            f'DEFAULT_FETCH_ADDR_REMOTE = \"{self.new_config.rest_api_address}\"',\n        )\n        content = content.replace(\n            f'DEFAULT_FETCH_CHAIN_ID = \"{self.cur_config.chain_id}\"',\n            f'DEFAULT_FETCH_CHAIN_ID = \"{self.new_config.chain_id}\"',\n        )\n        f.write_text(content)\n\n    def update_packages(self):\n        \"\"\"Update packages.\"\"\"\n        click.echo(\"Update packages\")\n        configs_files = (ROOT_DIR / \"packages\").glob(\"**/*.yaml\")\n        for f in configs_files:\n            content = f.read_text()\n            content = content.replace(\n                f\"address: {self.cur_config.rest_api_address}\",\n                f\"address: {self.new_config.rest_api_address}\",\n            )\n            content = content.replace(\n                f\"chain_id: {self.cur_config.chain_id}\",\n                f\"chain_id: {self.new_config.chain_id}\",\n            )\n            f.write_text(content)\n\n    def update_plugins(self):\n        \"\"\"Update plugins.\"\"\"\n        click.echo(\"Update plugins\")\n        files = (ROOT_DIR / \"plugins\").glob(\"**/*.py\")\n        for f in files:\n            content = f.read_text()\n            content = content.replace(\n                f'DEFAULT_CHAIN_ID = \"{self.cur_config.chain_id}\"',\n                f'DEFAULT_CHAIN_ID = \"{self.new_config.chain_id}\"',\n            )\n\n            content = content.replace(\n                f'DEFAULT_ADDRESS = \"{self.cur_config.rest_api_address}\"',\n                f'DEFAULT_ADDRESS = \"{self.new_config.rest_api_address}\"',\n            )\n            content = content.replace(\n                f'FETCHAI_DEFAULT_CHAIN_ID = \"{self.cur_config.chain_id}\"',\n                f'FETCHAI_DEFAULT_CHAIN_ID = \"{self.new_config.chain_id}\"',\n            )\n\n            content = content.replace(\n                f'FETCHAI_DEFAULT_ADDRESS = \"{self.cur_config.rest_api_address}\"',\n                f'FETCHAI_DEFAULT_ADDRESS = \"{self.new_config.rest_api_address}\"',\n            )\n\n            content = content.replace(\n                f'FETCHAI_TESTNET_FAUCET_URL = \"{self.cur_config.faucet_url}\"',\n                f'FETCHAI_TESTNET_FAUCET_URL = \"{self.new_config.faucet_url}\"',\n            )\n\n            content = content.replace(\n                f'\"chain_id\": \"{self.cur_config.chain_id}\"',\n                f'\"chain_id\": \"{self.new_config.chain_id}\"',\n            )\n\n            f.write_text(content)\n\n    @staticmethod\n    def print_footer():\n        \"\"\"Print footer after everything was done.\"\"\"\n        click.echo(\"Update completed!\")\n        click.echo(\"Please check wasm files are correct\")\n\n\nif __name__ == \"__main__\":\n    NetworkUpdate().run()\n"
  },
  {
    "path": "scripts/oef/launch.py",
    "content": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\nfrom __future__ import print_function\n\nimport argparse\nimport json\nimport os\nimport subprocess  # nosec\nimport sys\n\n\ndef run(cmd):\n    print(\" \".join(cmd))\n    c = subprocess.Popen(cmd)  # nosec\n    try:\n        c.wait()\n    except KeyboardInterrupt:\n        pass\n    finally:\n        poll = c.poll()\n        if poll is None:\n            c.terminate()\n            c.wait(2)\n    return c.returncode\n\n\ndef error(*x):\n    print(\"\".join([str(xx) for xx in x]), file=sys.stderr)\n\n\ndef fail(*x):\n    error(x)\n    exit(1)\n\n\ndef pull_image(run_sudo, img):\n    c = []\n\n    if run_sudo:\n        c += [\"sudo\"]\n    c += [\n        \"docker\",\n        \"pull\",\n        img,\n    ]\n    r = run(c)\n    if r != 0:\n        error(\"can't pull \" + img)\n\n\ndef parse_command(j):\n    cmd = []\n    used_keys = [\"positional_args\"]\n    for key in j[\"positional_args\"]:\n        cmd.append(str(j[key]))\n        used_keys.append(key)\n    for key in j:\n        if key in used_keys:\n            continue\n        cmd.extend([\"--\" + key, str(j[key])])\n    return cmd\n\n\ndef launch_job(args, j):\n    img = j[\"image\"]\n    if \"/\" in img:\n        pull_image(args.sudo, img)\n\n    c = []\n    if args.sudo:\n        c += [\"sudo\"]\n    c += [\"docker\", \"run\"]\n    if args.background:\n        c += [\"-d\"]\n    elif not args.disable_stdin:\n        c += [\"-it\"]\n    else:\n        c += [\"-t\"]\n\n    if args.name:\n        c += [\"--name\"]\n        c += [args.name]\n\n    work_dir = os.path.abspath(os.path.dirname(__file__))\n    project_dir = os.path.abspath(os.path.join(work_dir, \"..\", \"..\"))\n    print(\"Work dir: \", work_dir)\n    c += [\"-v\", work_dir + \":/config\", \"-v\", project_dir + \"/data/oef-logs:/logs\"]\n\n    for arg in j[\"params\"]:\n        c += map(lambda x: x.replace(\"$PWD\", project_dir), arg)\n\n    c += [img]\n\n    cmd_config = j[\"cmd\"].get(args.cmd, None)\n    if not cmd_config:\n        fail(\"Selected command {} not configured in config file!\".format(args.cmd))\n\n    c.extend(parse_command(cmd_config))\n    extra_args = [a for a in args.rest if a != \"--\"]\n    print(\"Extra arguments to search: \", extra_args)\n    c += extra_args\n    r = run(c)\n    if r != 0:\n        fail(\"can't launch \" + img)\n\n\ndef main(args):\n    with open(args.config, \"r\") as f:\n        config = json.load(f)\n    launch_job(args, config)\n\n\nif __name__ == \"__main__\":\n    parser = argparse.ArgumentParser()\n    parser.add_argument(\n        \"-c\", \"--config\", required=True, type=str, help=\"Publish the image to GCR\"\n    )\n    parser.add_argument(\n        \"--sudo\", required=False, action=\"store_true\", help=\"Run docker as root\"\n    )\n    parser.add_argument(\n        \"--background\",\n        required=False,\n        action=\"store_true\",\n        help=\"Run image in background.\",\n    )\n    parser.add_argument(\n        \"--disable_stdin\",\n        required=False,\n        action=\"store_true\",\n        help=\"Disable disable_stdin.\",\n    )\n    parser.add_argument(\n        \"-n\", \"--name\", required=False, type=str, help=\"give thre container a name\"\n    )\n    parser.add_argument(\n        \"--cmd\",\n        required=False,\n        type=str,\n        default=\"oef-search\",\n        help=\"The available commands are defined\"\n        \" in the config file \"\n        \"('cmd' dictionary) \",\n    )\n    parser.add_argument(\"rest\", nargs=argparse.REMAINDER)\n    main(parser.parse_args())\n"
  },
  {
    "path": "scripts/oef/launch_config.json",
    "content": "{\n  \"image\": \"fetchai/oef-search:0.7\",\n  \"params\": [\n    [\n      \"--rm\",\n      \"--cap-add\",\n      \"sys_ptrace\",\n      \"-p\",\n      \"20000:20000\",\n      \"-p\",\n      \"10000:10000\",\n      \"-p\",\n      \"40000:40000\",\n      \"-p\",\n      \"7500:7500\"\n    ]\n  ],\n  \"cmd\": {\n    \"oef-search\": {\n      \"positional_args\": [\"config_file\"],\n      \"config_file\": \"/config/node_config.json\"\n    }\n  }\n}"
  },
  {
    "path": "scripts/oef/node_config.json",
    "content": "{\n  \"host\": \"127.0.0.1\",\n  \"search_key\": \"London-search\",\n  \"search_port\": 20000,\n  \"search_broadcast_cache_lifetime_sec\": 6,\n  \"director_port\": 40000,\n  \"html_dir\": \"api/src/resources/website\",\n  \"prometheus_api_path\": \"/metrics\",\n  \"prometheus_log_file\": \"./fetch-logs/core-vars.txt\",\n  \"search_prometheus_log_file\": \"./fetch-logs/search-vars.txt\",\n  \"http_port\": 7500,\n  \"log_dir\": \"./fetch-logs/\",\n  \"search_log\": \"/logs/search.log\",\n  \"core_log\": \"/logs/core.log\",\n  \"ssl_certificate\": \"\",\n  \"core\": {\n    \"core_binary\": \"/oef-mt-core/bazel-bin/mt-core/main/src/cpp/app\",\n     \"config\": {\n      \"core_key\": \"CoreKey\",\n      \"core_uri\": \"tcp://127.0.0.1:10000\",\n      \"ws_uri\": \"\",\n      \"ssl_uri\": \"ssl://127.0.0.1:15000\",\n      \"white_list_file\":\"\",\n      \"core_cert_pk_file\": \"/app/ssl/core.pem\",\n      \"core_pubkey_file\": \"/app/ssl/core_pub.pem\",\n      \"tmp_dh_file\": \"/app/ssl/dh2048.pem\",\n      \"search_uri\": \"tcp://127.0.0.1:20000\",\n      \"tasks_thread_count\": 10,\n      \"comms_thread_count\": 10,\n      \"karma_policy\": {\n      },\n      \"prometheus_log_interval\": 3,\n      \"prometheus_log_file\": \"/logs/core-vars.txt\"\n    }\n  },\n  \"search_peers\": [\"KEY:HOST:PORT\"],\n   \"bootstrap\": {\n    \"bootstrap-url\": \"\",\n    \"network-name\": \"oeftestnet\",\n    \"client-name\": \"oef-node\",\n    \"client-version\": \"0.1.0\",\n    \"remote-host\": \"$EXTERNAL_HOSTNAME\",\n    \"remote-port\": -1,\n    \"private-key\": \"\",\n    \"user-token\": \"\",\n    \"notify-period-in-sec\": 180\n  },\n  \"state\": {\n    \"file\": \"/storage/state.json\",\n    \"fields\": [\"bootstrap:private-key\"]\n  },\n  \"search_config\": {\n    \"search_prometheus_log_file\": \"/logs/search-vars.txt\",\n    \"daps\": {\n      \"network_search\": {\n        \"class\": \"DapERNetwork\",\n        \"config\": {\n          \"module\": \"dap_e_r_network.src.python.DapERNetwork\",\n          \"structure\": {\n            \"locations\": {\n            }\n          }\n        }\n      },\n      \"geo_search\": {\n        \"class\": \"DapGeo\",\n        \"config\": {\n          \"module\": \"dap_2d_geo.src.python.DapGeo\",\n          \"structure\": {\n            \"location\": {\n              \"location.location\": {\n                \"type\": \"location\",\n                \"options\": [\n                  \"plane\",\n                  \"os-grid\"\n                ]\n              },\n              \"latlon\": {\n                \"latlon.location\": {\n                  \"type\": \"location\",\n                  \"options\": [\n                  ]\n                }\n              }\n            }\n          }\n        }\n      },\n      \"address_registry\": {\n        \"class\": \"AddressRegistry\",\n        \"config\": {\n          \"module\": \"dap_in_memory.src.python.AddressRegistry\",\n          \"structure\": {\n            \"address_registry_table\": {\n              \"address_field\": \"address\"\n            }\n          }\n        }\n      },\n      \"in_memory_dap\": {\n        \"class\": \"exe.InMemoryDap\",\n        \"config\": {\n          \"binary\": \"cpp_dap_in_memory/src/cpp/cpp_dap_in_memory_server\",\n          \"host\": \"127.0.0.1\",\n          \"port\": 30000,\n          \"structure\": {\n            \"value_table\": {\n              \"field\": \"string\"\n            }\n          }\n        }\n      },\n      \"attrs\": {\n        \"class\": \"DapAttributeStore\",\n        \"config\": {\n          \"module\": \"dap_attribute_store.src.python.DapAttributeStore\",\n          \"structure\": {\n          },\n          \"options\": [\n            \"lazy\"\n          ]\n        }\n      },\n      \"uniquer\": {\n        \"class\": \"DapUniquer\",\n        \"config\": {\n          \"module\": \"uniqer.src.python.DapUniquer\",\n          \"structure\": {\n          }\n        }\n      },\n      \"data_model_searcher\": {\n        \"class\": \"SearchEngine\",\n        \"config\": {\n          \"module\": \"ai_search_engine.src.python.SearchEngine\",\n          \"structure\": {\n            \"data_model_table\": {\n              \"data_model\": \"embedding\"\n            }\n          }\n        }\n      }\n    },\n    \"attribute_tbfld_map\": {\n      \"latlon\": [\"latlon\", \"latlon\"],\n      \"NETWORK_ADDRESS\": [\"address_registry_table\", \"address_field\"]\n    }\n  }\n}"
  },
  {
    "path": "scripts/parse_main_dependencies_from_lock.py",
    "content": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This CLI tool takes the main dependencies of the Pipfile.lock and prints it to stdout in requirements.txt format.\"\"\"\nimport argparse\nimport json\n\n\ndef parse_args() -> argparse.Namespace:\n    \"\"\"Parse CLI arguments.\"\"\"\n    parser = argparse.ArgumentParser(\"parse_main_dependencies_from_lock\")\n    parser.add_argument(\n        \"pipfile_lock_path\", type=argparse.FileType(\"r\"), help=\"Path to Pipfile.lock.\"\n    )\n    parser.add_argument(\"-o\", \"--output\", type=argparse.FileType(\"w\"), default=None)\n    return parser.parse_args()\n\n\nif __name__ == \"__main__\":\n    arguments = parse_args()\n\n    pipfile_lock_content = json.load(arguments.pipfile_lock_path)\n    requirements = sorted(\n        map(\n            lambda x: x[0] + x[1][\"version\"],\n            pipfile_lock_content.get(\"default\").items(),\n        )\n    )\n\n    requirements_content = \"\\n\".join(requirements)\n    if arguments.output is None:\n        print(requirements_content)\n    else:\n        arguments.output.write(requirements_content)\n"
  },
  {
    "path": "scripts/spell-check.sh",
    "content": "#!/bin/bash\n# This script requires `mdspell`:\n#\n#    https://www.npmjs.com/package/markdown-spellcheck\n#\n# Run this script from the root directory.\n# Usage:\n#   ./scripts/spell-check.sh\n#\n\nMDSPELL_PATH=\"$(which mdspell)\"\nif [ -z \"${MDSPELL_PATH}\" ]; then\n  echo \"Cannot find executable 'mdspell'. Please install it to run this script: npm i markdown-spellcheck -g\"\n  exit 127\nelse\n  echo \"Found 'mdspell' executable at ${MDSPELL_PATH}\"\n  mdspell -n -a --en-gb '**/*.md' '!docker-images/*.md' '!docs/api/**/*.md'\nfi\n"
  },
  {
    "path": "scripts/update_package_versions.py",
    "content": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"\nUpdates package versions relative to last release.\n\nRun this script from the root of the project directory:\n\n    python scripts/update_package_versions.py\n\n\"\"\"\n\nimport argparse\nimport operator\nimport os\nimport re\nimport subprocess  # nosec\nimport sys\nfrom collections import Counter\nfrom pathlib import Path\nfrom typing import Any, Dict, List, Optional, Pattern, Set\n\nimport click\nimport requests\nimport semver\nimport yaml\nfrom click.testing import CliRunner\n\nfrom aea.cli import cli\nfrom aea.configurations.base import PackageId, PackageType, PublicId\nfrom aea.configurations.loader import ConfigLoader\nfrom scripts.common import (\n    PACKAGES_DIR,\n    get_protocol_specification_from_readme,\n    get_protocol_specification_id_from_specification,\n)\nfrom scripts.generate_ipfs_hashes import update_hashes\n\n\nDIRECTORIES = [\"packages\", \"aea\", \"docs\", \"benchmark\", \"examples\", \"tests\"]\nCLI_LOG_OPTION = [\"-v\", \"OFF\"]\nTYPES = set(map(lambda x: x.to_plural(), PackageType))\nHASHES_CSV = \"hashes.csv\"\nTYPE_TO_CONFIG_FILE = {\n    \"connections\": \"connection.yaml\",\n    \"protocols\": \"protocol.yaml\",\n    \"contracts\": \"contract.yaml\",\n    \"skills\": \"skill.yaml\",\n    \"agents\": \"aea-config.yaml\",\n}\nPUBLIC_ID_REGEX = PublicId.PUBLIC_ID_REGEX[1:-1]\nTEST_PROTOCOLS = [\"t_protocol\", \"t_protocol_no_ct\"]\nFILE_DOWNLOAD_TIMEOUT = 180\n\n\ndef get_protocol_specification_header_regex(public_id: PublicId) -> Pattern:\n    \"\"\"Get the regex to match.\"\"\"\n    return re.compile(\n        rf\"(name: {public_id.name}\\n\"\n        + rf\"author: {public_id.author}\\n)\"\n        + rf\"version: {public_id.version}\\n\"\n        + r\"(description:)\",\n        re.MULTILINE,\n    )\n\n\ndef check_positive(value: Any) -> int:\n    \"\"\"Check value is an int.\"\"\"\n    try:\n        ivalue = int(value)\n        assert ivalue <= 0\n    except (AssertionError, ValueError):\n        raise argparse.ArgumentTypeError(f\"{value} is an invalid positive int value\")\n    return ivalue\n\n\ndef parse_arguments() -> argparse.Namespace:\n    \"\"\"Parse command-line arguments.\"\"\"\n    parser = argparse.ArgumentParser()\n    parser.add_argument(\n        \"-n\",\n        \"--no-interactive\",\n        action=\"store_true\",\n        default=False,\n        help=\"Don't ask user confirmation for replacement.\",\n    )\n    parser.add_argument(\n        \"-C\",\n        \"--context\",\n        type=check_positive,\n        default=3,\n        help=\"The number of above/below rows to display\",\n    )\n\n    parser.add_argument(\n        \"-r\",\n        \"--replace-by-default\",\n        action=\"store_true\",\n        default=False,\n        help=\"If --no-interactive is set, apply the replacement (default: False).\",\n    )\n    return parser.parse_args()\n\n\narguments: argparse.Namespace = None  # type: ignore\n\n\ndef get_hashes_from_last_release() -> Dict[str, str]:\n    \"\"\"Get hashes from last release.\"\"\"\n    hashes = {}  # Dict[str, str]\n    resp = requests.get(\n        url=\"https://raw.githubusercontent.com/fetchai/agents-aea/main/packages/hashes.csv\",\n        timeout=FILE_DOWNLOAD_TIMEOUT,\n    )\n    hashes_raw = resp.text\n    for line in hashes_raw.splitlines():\n        split = line.split(\",\")\n        hashes[split[0]] = split[1].rstrip()\n    return hashes\n\n\ndef get_hashes_from_current_release() -> Dict[str, str]:\n    \"\"\"Get hashes from last release.\"\"\"\n    hashes = {}  # Dict[str, str]\n    with open(os.path.join(\"packages\", HASHES_CSV), encoding=\"utf-8\") as f:\n        for line in f:\n            split = line.split(\",\")\n            hashes[split[0]] = split[1].rstrip()\n    return hashes\n\n\ndef split_hashes_by_type(all_hashes: Dict[str, str]) -> Dict[str, Dict[str, str]]:\n    \"\"\"Split hashes by type.\"\"\"\n    result = {\n        \"agents\": {},\n        \"protocols\": {},\n        \"contracts\": {},\n        \"connections\": {},\n        \"skills\": {},\n    }  # type: Dict[str, Dict[str, str]]\n    for key, value in all_hashes.items():\n        if \"fetchai\" not in key:\n            print(\"Non-fetchai packages not allowed!\")\n            sys.exit(1)\n        _, type_, name = key.split(\"/\")\n        result[type_][name] = value\n    return result\n\n\ndef get_configuration_file_path(type_: str, name: str) -> Path:\n    \"\"\"Get the configuration file path.\"\"\"\n    fp = os.path.join(\"packages\", \"fetchai\", type_, name, TYPE_TO_CONFIG_FILE[type_])\n    if os.path.isfile(fp):\n        return Path(fp)\n    fp = os.path.join(\"aea\", type_, name, TYPE_TO_CONFIG_FILE[type_])\n    if os.path.isfile(fp):\n        return Path(fp)\n    print(\"Cannot find folder for package `{}` of type `{}`\".format(name, type_))\n    sys.exit(1)\n\n\ndef unified_yaml_load(configuration_file: Path) -> Dict:\n    \"\"\"\n    Load YAML file, unified (both single- and multi-paged).\n\n    :param configuration_file: the configuration file path.\n    :return: the data.\n    \"\"\"\n    package_type = configuration_file.parent.parent.name\n    with configuration_file.open(encoding=\"utf-8\") as fp:\n        if package_type != \"agents\":\n            return yaml.safe_load(fp)\n        # when it is an agent configuration file,\n        # we are interested only in the first page of the YAML,\n        # because the dependencies are contained only there.\n        data = yaml.safe_load_all(fp)\n        return list(data)[0]\n\n\ndef get_public_id_from_yaml(configuration_file_path: Path) -> PublicId:\n    \"\"\"\n    Get the public id from yaml.\n\n    :param configuration_file_path: the path to the config yaml\n    :return: public id\n    \"\"\"\n    data = unified_yaml_load(configuration_file_path)\n    author = data[\"author\"]\n    # handle the case when it's a package or agent config file.\n    name = data[\"name\"] if \"name\" in data else data[\"agent_name\"]\n    version = data[\"version\"]\n    return PublicId(author, name, version)\n\n\ndef public_id_in_registry(type_: str, name: str) -> PublicId:\n    \"\"\"\n    Check if a package id is in the registry.\n\n    :param type_: the package type\n    :param name: the name of the package\n    :return: public id\n    \"\"\"\n    runner = CliRunner()\n    result = runner.invoke(\n        cli,\n        [*CLI_LOG_OPTION, \"search\", type_, \"--query\", name],\n        standalone_mode=False,\n    )\n    reg = r\"({}/{}:{})\".format(\"fetchai\", name, PublicId.VERSION_REGEX)\n    ids = re.findall(\n        reg,\n        result.output,\n    )\n    p_ids = []\n    highest = PublicId.from_str(\"fetchai/{}:0.1.0\".format(name))\n    for id_ in ids:\n        p_id = PublicId.from_str(id_[0])\n        p_ids.append(p_id)\n        if p_id > highest:\n            highest = p_id\n    return highest\n\n\ndef get_all_protocol_spec_ids() -> Set[PublicId]:\n    \"\"\"\n    Get all protocol specification ids.\n\n    We return package ids with type \"protocol\" even though\n    they are not exactly protocol. The reason is that\n    they are only used to find clashes with protocol ids.\n\n    :return: a set of package ids.\n    \"\"\"\n    result: Set[PublicId] = set()\n    protocol_packages = set(PACKAGES_DIR.rglob(\"**/**/protocols/**\")) - set(\n        PACKAGES_DIR.rglob(\"**/**/protocols\")\n    )\n    for protocol_package_path in protocol_packages:\n        if \"connections\" in str(protocol_package_path):\n            continue\n        content = get_protocol_specification_from_readme(protocol_package_path)\n        spec_id = get_protocol_specification_id_from_specification(content)\n        result.add(PublicId.from_str(spec_id))\n    return result\n\n\ndef get_all_package_ids() -> Set[PackageId]:\n    \"\"\"Get all the package ids in the local repository.\"\"\"\n    result: Set[PackageId] = set()\n    now = get_hashes_from_current_release()\n    now_by_type = split_hashes_by_type(now)\n    for type_, name_to_hashes in now_by_type.items():\n        for name, _ in name_to_hashes.items():\n            if name in TEST_PROTOCOLS:\n                continue\n            configuration_file_path = get_configuration_file_path(type_, name)\n            public_id = get_public_id_from_yaml(configuration_file_path)\n            package_id = PackageId(PackageType(type_[:-1]), public_id)\n            result.add(package_id)\n    return result\n\n\ndef get_public_ids_to_update() -> Set[PackageId]:\n    \"\"\"\n    Get all the public ids to be updated.\n\n    In particular, a package DOES NOT NEED a version bump if:\n    - the package is a \"scaffold\" package;\n    - the package is no longer present\n    - the package hasn't change since the last release;\n    - the public ids of the local package and the package in the registry\n      are already the same.\n\n    :return: set of package ids to update\n    \"\"\"\n    result: Set[PackageId] = set()\n    last = get_hashes_from_last_release()\n    now = get_hashes_from_current_release()\n    last_by_type = split_hashes_by_type(last)\n    now_by_type = split_hashes_by_type(now)\n    for type_ in TYPES:\n        for key, value in last_by_type[type_].items():\n            # if the package is a \"scaffold\" package, skip;\n            if key == \"scaffold\":\n                print(\"Package `{}` of type `{}` is never bumped!\".format(key, type_))\n                continue\n            # if the package is no longer present, skip;\n            if key not in now_by_type[type_]:\n                print(\"Package `{}` of type `{}` no longer present!\".format(key, type_))\n                continue\n            # if the package hasn't change since the last release, skip;\n            if now_by_type[type_][key] == value:\n                print(\n                    \"Package `{}` of type `{}` has not changed since last release!\".format(\n                        key, type_\n                    )\n                )\n                continue\n            # load public id in the registry if any\n            name = key\n            configuration_file_path = get_configuration_file_path(type_, name)\n            current_public_id = get_public_id_from_yaml(configuration_file_path)\n            deployed_public_id = public_id_in_registry(type_, name)\n            difference = minor_version_difference(current_public_id, deployed_public_id)\n            # check if the public ids of the local package and the package in the registry are already the same.\n            package_info = f\"Package `{name}` of type `{type_}`\"\n            public_id_info = f\"current id `{current_public_id}` and deployed id `{deployed_public_id}`\"\n            if difference == 0:\n                print(f\"{package_info} needs to be bumped!\")\n                result.add(PackageId(type_[:-1], current_public_id))\n            elif difference == 1:\n                print(f\"{package_info} already at correct version!\")\n                continue\n            else:\n                print(f\"{package_info} has {public_id_info}. Error!\")\n                sys.exit(1)\n    return result\n\n\ndef _get_ambiguous_public_ids() -> Set[PublicId]:\n    \"\"\"Get the public ids that are the public ids of more than one package id.\"\"\"\n    all_package_ids = get_all_package_ids()\n    result: Set[PublicId] = set(\n        map(\n            operator.itemgetter(0),\n            filter(\n                lambda x: x[0].name != \"scaffold\" and x[1] > 1,\n                Counter(id_.public_id for id_ in all_package_ids).items(),\n            ),\n        )\n    )\n    return result\n\n\ndef _sort_in_update_order(package_ids: Set[PackageId]) -> List[PackageId]:\n    \"\"\"\n    Sort the set of package id in the order of update.\n\n    In particular, they are sorted from the greatest version number to the lowest.\n\n    The reason is to avoid that consecutive package ids (i.e. whose minors difference is 1)\n    gets updated in ascending order, resulting in all the updates collapsing to the greatest version.\n    For example, consider two package ids with prefix 'author/package' and with versions\n    0.1.0 and 0.2.0, respectively. If we bump first the former and then the latter,\n    the new replacements associated to the first updated are taken into account in\n    the second update.\n\n    :param package_ids: set of package ids\n    :return: sorted list of package ids\n    \"\"\"\n    return sorted(\n        package_ids,\n        key=lambda x: (\n            semver.VersionInfo.parse(x.public_id.version),\n            x.public_id.author,\n            x.public_id.name,\n            x.package_type.value,\n        ),\n        reverse=True,\n    )\n\n\ndef minor_version_difference(\n    current_public_id: PublicId, deployed_public_id: PublicId\n) -> int:\n    \"\"\"Check the minor version difference.\"\"\"\n    diff = semver.compare(current_public_id.version, deployed_public_id.version)\n    return diff\n\n\ndef _can_disambiguate_from_context(\n    line: str, old_string: str, type_: str\n) -> Optional[bool]:\n    \"\"\"\n    Check whether we can disambiguate the public id given contextual information.\n\n    For example:\n    - whether the public id appears in a line of the form 'aea fetch ...' (we know it's an agent)\n    - whether the public id appears in a line of the form 'aea add ...' (we know the component type)\n    - whether the type appears in the same line where the public id occurs.\n\n    :param line: the line\n    :param old_string: the old string\n    :param type_: the type of package\n    :return: if True/False, the old string can/cannot be replaced. If None, we don't know.\n    \"\"\"\n    match = re.search(\n        rf\"aea +add +(skill|protocol|connection|contract) +{old_string}\", line\n    )\n    if match is not None:\n        return match.group(1) == type_[:-1]\n    if re.search(rf\"aea +fetch +{old_string}\", line) is not None:\n        return type_ == \"agents\"\n    match = re.search(\n        \"(skill|SKILL|\"\n        + \"protocol|PROTOCOL|\"\n        + \"connection|CONNECTION|\"\n        + \"contract|CONTRACT|\"\n        + \"agent|AGENT\"\n        + f\")s?.*{old_string}\",\n        line,\n    )\n    if match is not None:\n        return (match.group(1) + \"s\") == type_\n\n    # for protocol specification id only:\n    # - if the line contains 'protocol_specification_id: {old_public_id}' or\n    # - if the line contains 'protocol_specification_id = PublicId.from_str(\"{old_public_id}\")'\n    # then DON'T replace it (we only bump protocol ids here).\n    # otherwise, we don't know -> return None and ask to user.\n    case_1 = f\"protocol_specification_id: {old_string}\"\n    case_2 = rf'protocol_specification_id = PublicId.from_str([\\'\"]{old_string}[\\'\"])'\n    if re.search(case_1, line) or re.search(case_2, line):\n        return True\n    return None\n\n\ndef _ask_user(\n    lines: List[str], line: str, idx: int, old_string: str, type_: str, lines_num: int\n) -> str:\n    print(\"=\" * 50)\n    above_rows = lines[idx - lines_num : idx]\n    below_rows = lines[idx + 1 : idx + lines_num]\n    print(\"\".join(above_rows))\n    print(line.rstrip().replace(old_string, \"\\033[91m\" + old_string + \"\\033[0m\"))\n    print(\"\".join(below_rows))\n    answer = input(\n        f\"Replace for component ({type_}, {old_string})? [y/N]: \",\n    )  # nosec\n    return answer\n\n\ndef replace_aea_fetch_statements(\n    content: str, old_string: str, new_string: str, type_: str\n) -> str:\n    \"\"\"Replace statements of the type: 'aea fetch <old_string>'.\"\"\"\n    if type_ == \"agents\":\n        content = re.sub(\n            rf\"aea +fetch +{old_string}\", f\"aea fetch {new_string}\", content\n        )\n    return content\n\n\ndef replace_aea_add_statements(\n    content: str, old_string: str, new_string: str, type_: str\n) -> str:\n    \"\"\"Replace statements of the type: 'aea add <type> <old_string>'.\"\"\"\n    if type_ != \"agents\":\n        content = re.sub(\n            rf\"aea +add +{type_} +{old_string}\",\n            f\"aea add {type_} {new_string}\",\n            content,\n        )\n    return content\n\n\ndef replace_type_and_public_id_occurrences(\n    line: str, old_string: str, new_string: str, type_: str\n) -> str:\n    \"\"\"Replace the public id whenever the type and the id occur in the same row, and NOT when other type names occur.\"\"\"\n    if re.match(f\"{type_}.*{old_string}\", line) and all(\n        _type not in line for _type in TYPES.difference({type_})\n    ):\n        line = line.replace(old_string, new_string)\n    return line\n\n\ndef replace_in_yamls(\n    content: str, old_public_id: PublicId, new_public_id: PublicId, type_: str\n) -> str:\n    \"\"\"\n    Replace the public id in configuration files (also nested in .md files).\n\n    1) replace package dependencies:\n        |protocols:\n        |- author/name:version\n        |...\n        |- old_string\n    2) replace in configuration headers:\n        |name: package_name\n        |author: package_author\n        |version: package_version -> bump up\n        |type: package_type\n\n    :param content: the content\n    :param old_public_id: the old public id\n    :param new_public_id: the new public id\n    :param type_: the type of the package\n    :return: replaced content\n    \"\"\"\n    # case 1:\n    regex = re.compile(f\"({type_}:\\n(-.*\\n)*)(- *{str(old_public_id)})\", re.MULTILINE)\n    content = regex.sub(rf\"\\g<1>- {str(new_public_id)}\", content)\n\n    # case 2:\n    regex = re.compile(\n        rf\"(name: {old_public_id.name}\\nauthor: {old_public_id.author}\\n)version: {old_public_id.version}\\n(type: {type_[:-1]})\",\n        re.MULTILINE,\n    )\n    content = regex.sub(rf\"\\g<1>version: {new_public_id.version}\\n\\g<2>\", content)\n    return content\n\n\ndef replace_in_protocol_readme(\n    fp: Path, content: str, old_public_id: PublicId, new_public_id: PublicId, type_: str\n) -> str:\n    \"\"\"\n    Replace the version id in the protocol specification in the protcol's README.\n\n    That is, bump the version in cases like:\n\n        |name: package_name\n        |author: package_author\n        |version: package_version -> bump up\n        ...\n\n    :param fp: path to the file being edited.\n    :param content: the content of the file.\n    :param old_public_id: the old public id.\n    :param new_public_id: the new public id.\n    :param type_: the type of the package.\n    :return: the new content.\n    \"\"\"\n    if (\n        type_ == fp.parent.parent.name == \"protocols\"\n        and fp.name == \"README.md\"\n        and fp.parent.name == old_public_id.name\n    ):\n        regex = get_protocol_specification_header_regex(old_public_id)\n        content = regex.sub(rf\"\\g<1>version: {new_public_id.version}\\n\\g<2>\", content)\n    return content\n\n\ndef file_should_be_processed(content: str, old_public_id: PublicId) -> bool:\n    \"\"\"Check if the file should be processed.\"\"\"\n    old_string = str(old_public_id)\n    return (\n        old_string in content\n        or get_protocol_specification_header_regex(old_public_id).search(content)\n        is not None\n    )\n\n\ndef bump_version_in_yaml(\n    configuration_file_path: Path, type_: str, version: str\n) -> None:\n    \"\"\"Bump the package version in the package yaml.\"\"\"\n    loader = ConfigLoader.from_configuration_type(type_[:-1])\n    with configuration_file_path.open(encoding=\"utf-8\") as f:\n        config = loader.load(f)\n    config.version = version\n\n    with open(configuration_file_path, \"w\", encoding=\"utf-8\") as f:\n        loader.dump(config, f)\n\n\nclass Updater:\n    \"\"\"Package versions updter tool.\"\"\"\n\n    def __init__(\n        self, new_version: str, replace_by_default: bool, context: int\n    ) -> None:\n        \"\"\"Init updater.\"\"\"\n        self.option_new_version = new_version\n        self.option_replace_by_default = replace_by_default\n        self.option_context = context\n\n    @staticmethod\n    def run_hashing() -> None:\n        \"\"\"Run hashes update.\"\"\"\n        hashing_call = update_hashes()\n        if hashing_call == 1:\n            raise Exception(\"Problem when running IPFS script!\")\n\n    @staticmethod\n    def check_if_running_allowed() -> None:\n        \"\"\"\n        Check if we can run the script.\n\n        Script should only be run on a clean branch.\n        \"\"\"\n        with subprocess.Popen(  # nosec\n            [\"git\", \"diff\"], stdout=subprocess.PIPE\n        ) as git_call:\n            (stdout, _) = git_call.communicate()\n            git_call.wait()\n            if len(stdout) > 0:\n                raise Exception(\"Cannot run script in unclean git state.\")\n\n    def _checks(self) -> None:\n        self.run_hashing()\n        self.check_if_running_allowed()\n\n    def run(self) -> None:\n        \"\"\"Run package versions update process.\"\"\"\n        self._checks()\n        self._run_hashing()\n\n    def _run_once(self) -> bool:\n        \"\"\"Run the upgrade logic once.\"\"\"\n        all_package_ids_to_update = get_public_ids_to_update()\n        if len(all_package_ids_to_update) == 0:\n            print(\"No packages to update. Done!\")\n            return False\n        ambiguous_public_ids = _get_ambiguous_public_ids()\n        self.process_packages(all_package_ids_to_update, ambiguous_public_ids)\n        return True\n\n    def process_packages(\n        self,\n        all_package_ids_to_update: Set[PackageId],\n        ambiguous_public_ids: Set[PublicId],\n    ) -> None:\n        \"\"\"Process the package versions.\"\"\"\n        print(\"*\" * 100)\n\n        conflicts = {p.public_id for p in all_package_ids_to_update}.intersection(\n            ambiguous_public_ids\n        )\n        print(f\"Ambiguous public ids: {ambiguous_public_ids}\")\n        print(\n            f\"Conflicts with public ids to update: {conflicts}\",\n        )\n\n        print(\"*\" * 100)\n        print(\"Start processing.\")\n        # we need to include this in case some protocol id == spec id of that protocol.\n        spec_protocol_ids = get_all_protocol_spec_ids()\n        sorted_package_ids_list = _sort_in_update_order(all_package_ids_to_update)\n        for package_id in sorted_package_ids_list:\n            print(\"#\" * 50)\n            print(f\"Processing {package_id}\")\n            is_ambiguous = package_id.public_id in ambiguous_public_ids.union(\n                spec_protocol_ids\n            )\n            self.process_package(package_id, is_ambiguous)\n\n    def process_package(self, package_id: PackageId, is_ambiguous: bool) -> None:\n        \"\"\"\n        Process a package.\n\n        - check version in registry\n        - make sure, version is exactly one above the one in registry\n        - change all occurrences in packages/tests/aea/examples/benchmark/docs to new reference\n        - change yaml version number\n\n        :param package_id: the id of the package\n        :param is_ambiguous: whether the public id is ambiguous.\n        \"\"\"\n        type_plural = package_id.package_type.to_plural()\n        configuration_file_path = get_configuration_file_path(\n            type_plural, package_id.name\n        )\n        current_public_id = get_public_id_from_yaml(configuration_file_path)\n\n        self.bump_package_version(\n            current_public_id, configuration_file_path, type_plural, is_ambiguous\n        )\n\n    def get_new_package_version(self, current_public_id: PublicId) -> str:\n        \"\"\"Get new package version according to command line options provided.\"\"\"\n\n        ver = semver.VersionInfo.parse(current_public_id.version)\n\n        if self.option_new_version == ASK_VERSION:\n            while True:\n                new_version = click.prompt(\n                    f\"Please enter a new version for {current_public_id}\", type=str\n                )\n\n                try:\n                    new_ver = semver.VersionInfo.parse(new_version)\n                    if new_ver <= ver:\n                        print(\"Version is lower or the same. Enter a new one.\")\n                        continue\n                    break\n                except Exception as e:  # pylint: disable=broad-except\n                    print(f\"Version parse error: {e}. Please enter a new version.\")\n                    continue\n        elif self.option_new_version == UPDATE_MINOR:\n            new_version = ver.bump_minor()\n        elif self.option_new_version == UPDATE_PATCH:\n            new_version = ver.bump_patch()\n        else:\n            raise Exception(\"unknown version update mode\")\n\n        return str(new_version)\n\n    def bump_package_version(\n        self,\n        current_public_id: PublicId,\n        configuration_file_path: Path,\n        type_: str,\n        is_ambiguous: bool = False,\n    ) -> None:\n        \"\"\"\n        Bump the version references of the package in the repo.\n\n        Includes, bumping the package itself.\n\n        :param current_public_id: the current public id\n        :param configuration_file_path: the path to the configuration file\n        :param type_: the type of package\n        :param is_ambiguous: whether or not the package id is ambiguous\n        \"\"\"\n        new_version = self.get_new_package_version(current_public_id)\n\n        new_public_id = PublicId(\n            current_public_id.author, current_public_id.name, new_version\n        )\n        for rootdir in DIRECTORIES:\n            for path in Path(rootdir).glob(\"**/*\"):\n                if path.is_file() and str(path).endswith(\n                    (\".py\", \".yaml\", \".md\", \".sh\")\n                ):\n                    self.inplace_change(\n                        path,\n                        current_public_id,\n                        new_public_id,\n                        type_,\n                        is_ambiguous,\n                    )\n\n        bump_version_in_yaml(configuration_file_path, type_, new_public_id.version)\n\n    def _run_hashing(self) -> None:\n        while self._run_once():\n            self._run_hashing()\n\n    def inplace_change(\n        self,\n        fp: Path,\n        old_public_id: PublicId,\n        new_public_id: PublicId,\n        type_: str,\n        is_ambiguous: bool,\n    ) -> None:\n        \"\"\"Replace the occurrence of a string with a new one in the provided file.\"\"\"\n\n        content = fp.read_text()\n        if not file_should_be_processed(content, old_public_id):\n            return\n\n        old_string = str(old_public_id)\n        new_string = str(new_public_id)\n        print(\n            f\"Processing file {fp} for replacing {old_string} with {new_string} (is_ambiguous: {is_ambiguous})\"\n        )\n\n        content = replace_in_yamls(content, old_public_id, new_public_id, type_)\n        content = replace_in_protocol_readme(\n            fp, content, old_public_id, new_public_id, type_\n        )\n        if not is_ambiguous:\n            content = content.replace(old_string, new_string)\n        else:\n            content = self._ask_user_and_replace_if_allowed(\n                content, old_string, new_string, type_\n            )\n\n        with fp.open(mode=\"w\") as f:\n            f.write(content)\n\n    def _ask_user_and_replace_if_allowed(\n        self, content: str, old_string: str, new_string: str, type_: str\n    ) -> str:\n        \"\"\"\n        Ask user if the line should be replaced or not, if the script arguments allow that.\n\n        :param content: the content.\n        :param old_string: the old string.\n        :param new_string: the new string.\n        :param type_: the type of the package.\n        :return: the updated content.\n        \"\"\"\n        if self.option_replace_by_default:\n            content = content.replace(old_string, new_string)\n            return content\n\n        lines = content.splitlines(keepends=True)\n        for idx, line in enumerate(lines[:]):\n            if old_string not in line:\n                continue\n\n            can_replace = _can_disambiguate_from_context(line, old_string, type_)\n            # if we managed to replace all the occurrences, then save this line and continue\n            if can_replace is not None:\n                lines[idx] = (\n                    line.replace(old_string, new_string) if can_replace else line\n                )\n                continue\n\n            # otherwise, forget the attempts and ask the user.\n            answer = _ask_user(lines, line, idx, old_string, type_, self.option_context)\n            if answer == \"y\":\n                lines[idx] = line.replace(old_string, new_string)\n        return \"\".join(lines)\n\n\nUPDATE_PATCH = \"bump_patch\"\nUPDATE_MINOR = \"bump_minor\"\nASK_VERSION = \"ask\"\n\nNEW_VERSION_OPTIONS = [ASK_VERSION, UPDATE_PATCH, UPDATE_MINOR]\n\n\n@click.command()\n@click.option(\n    \"--new-version\",\n    \"-n\",\n    type=click.Choice(NEW_VERSION_OPTIONS),\n    help=f\"Mode to determine a new package version: {', '.join(NEW_VERSION_OPTIONS)}\",\n    default=ASK_VERSION,\n)\n@click.option(\n    \"--context\",\n    \"-C\",\n    type=click.IntRange(0, 5),\n    help=\"Number of lines above and below the reference to display.\",\n    default=1,\n)\n@click.option(\n    \"--replace-by-default\",\n    \"-r\",\n    is_flag=True,\n    help=\"Automatically replace package reference (default: False).\",\n)\ndef command(new_version, replace_by_default, context):\n    \"\"\"Run cli command.\"\"\"\n    Updater(new_version, replace_by_default, context).run()\n\n\nif __name__ == \"__main__\":\n    command()  # pylint: disable=no-value-for-parameter\n"
  },
  {
    "path": "scripts/update_plugin_versions.py",
    "content": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nBump the versions of AEA plugins throughout the code base.\n\n    python scripts/update_plugin_versions.py --update \"plugin-name,version\" [--update ...]\n\nExample of usage:\n\n    python scripts/update_plugin_versions.py --update \"aea-ledger-fetchai,0.2.0\" --update \"aea-ledger-ethereum,0.3.0\"\n\n\"\"\"\n\nimport argparse\nimport pprint\nimport re\nimport sys\nfrom pathlib import Path\nfrom typing import Dict, List, Tuple\n\nfrom packaging.specifiers import SpecifierSet\nfrom packaging.version import Version\n\nfrom aea.helpers.base import compute_specifier_from_version\nfrom scripts.generate_ipfs_hashes import update_hashes\n\n\nPLUGINS_DIR = Path(\"plugins\")\nSETUP_PY_NAME_REGEX = re.compile(r\"\\Wname=\\\"(.*)\\\",\")\nSETUP_PY_VERSION_REGEX = re.compile(r\"\\Wversion=\\\"(.*)\\\",\")\n\n\nIGNORE_DIRS = [Path(\".git\")]\n\n\ndef update_plugin_setup(\n    plugin_name: str, old_version: Version, new_version: Version\n) -> bool:\n    \"\"\"Update plugin setup.py script with new version.\n\n    :param plugin_name: the plugin name.\n    :param old_version: the old version.\n    :param new_version: the new version.\n    :return: True if an update has been done, False otherwise.\n    \"\"\"\n    setup_file = PLUGINS_DIR / plugin_name / \"setup.py\"\n    content = setup_file.read_text()\n    new_content = re.sub(\n        rf\"version=['\\\"]{old_version}['\\\"],\", f'version=\"{new_version}\",', content\n    )\n    setup_file.write_text(new_content)\n    return content != new_content\n\n\ndef process_plugin(\n    plugin_name: str, old_version: Version, new_version: Version\n) -> bool:\n    \"\"\"\n    Process the plugin version.\n\n    :param plugin_name: the plugin name.\n    :param old_version: the old version.\n    :param new_version: the new version.\n    :return: True if an update has been done, False otherwise.\n    \"\"\"\n    result = False\n    result = update_plugin_setup(plugin_name, old_version, new_version) or result\n    result = (\n        update_plugin_version_specifiers(plugin_name, old_version, new_version)\n        or result\n    )\n    return result\n\n\ndef update_plugin_version_specifiers(\n    plugin_name: str, old_version: Version, new_version: Version\n) -> bool:\n    \"\"\"\n    Update aea_version specifier set in docs.\n\n    :param plugin_name: the plugin name.\n    :param old_version: the old version.\n    :param new_version: the new version.\n    :return: True if the update has been done, False otherwise.\n    \"\"\"\n    old_specifier_set = compute_specifier_from_version(old_version)\n    new_specifier_set = compute_specifier_from_version(new_version)\n    print(f\"Old version specifier: {old_specifier_set}\")\n    print(f\"New version specifier: {new_specifier_set}\")\n    if old_specifier_set == new_specifier_set:\n        print(\"Not updating version specifier - they haven't changed.\")\n        return False\n    has_changed = False\n    new_specifier_set = str(SpecifierSet(new_specifier_set))\n    old_specifier_set = str(SpecifierSet(old_specifier_set))\n    old_specifier_set_regex = re.compile(str(old_specifier_set).replace(\" \", \" *\"))\n    for file in filter(lambda p: not p.is_dir(), Path(\".\").rglob(\"*\")):\n        dir_root = Path(file.parts[0])\n        if dir_root in IGNORE_DIRS:\n            print(f\"Skipping '{file}'...\")\n            continue\n        print(\n            f\"Replacing '{old_specifier_set}' with '{new_specifier_set}' in '{file}'... \",\n            end=\"\",\n        )\n        try:\n            content = file.read_text()\n        except UnicodeDecodeError as e:\n            print(f\"Cannot read {file}: {str(e)}. Continue...\")\n        else:\n            if old_specifier_set_regex.search(content) is None:\n                print(\"No version to update found.\")\n                continue\n            new_content = _replace_patterns(\n                content, plugin_name, old_specifier_set, new_specifier_set\n            )\n            has_changed = has_changed or content != new_content\n            file.write_text(new_content)\n            print(\"Done!\")\n    return has_changed\n\n\ndef _replace_patterns(\n    content: str, plugin_name: str, old_specifier: str, new_specifier: str\n) -> str:\n    \"\"\"\n    Replace specific patterns.\n\n    It identifies three patterns:\n\n    1) strings of the form:\n    <plugin-name><old_specifier_set>\n    2) YAML strings of the form:\n    plugin-name:\n      version: <old_specifier_set>\n    3) strings of the form\n    \"<plugin-name>\": {\"version\": \"<old_specifier_set>\"}\n\n    :param content: the file content\n    :param plugin_name: the plugin name\n    :param old_specifier: the old specifier\n    :param new_specifier: the new specifier\n    :return: the new content.\n    \"\"\"\n    # check pattern (1)\n    content = re.sub(\n        f\"{plugin_name}{old_specifier}\", f\"{plugin_name}{new_specifier}\", content\n    )\n    # check pattern (2)\n    content = re.sub(\n        f\"({plugin_name}:\\n *version: ){old_specifier}\",\n        rf\"\\g<1>{new_specifier}\",\n        content,\n    )\n    # check pattern (3)\n    content = re.sub(\n        f'\"{plugin_name}\": {{\"version\": \"{old_specifier}\"}}',\n        f'\"{plugin_name}\": {{\"version\": \"{new_specifier}\"}}',\n        content,\n    )\n    return content\n\n\ndef exit_with_message(message: str, exit_code: int = 1) -> None:\n    \"\"\"Exit the program with a message and an exit code.\"\"\"\n    print(message)\n    sys.exit(exit_code)\n\n\ndef get_plugin_names_and_versions() -> Dict[str, Version]:\n    \"\"\"Get all the plugins names and versions.\"\"\"\n    result: Dict[str, Version] = {}\n    for plugin_setup_script in PLUGINS_DIR.glob(\"*/setup.py\"):\n        content = plugin_setup_script.read_text()\n        name_matches: List[str] = SETUP_PY_NAME_REGEX.findall(content)\n        version_matches: List[str] = SETUP_PY_VERSION_REGEX.findall(content)\n        if len(name_matches) != 1 or len(version_matches) != 1:\n            exit_with_message(\n                f\"Unexpected result: in {result}, found plugin names: {name_matches} and versions: {version_matches}\"\n            )\n        name, version = name_matches[0], version_matches[0]\n        if name in result:\n            print(f\"Warning, duplicate plugin name: '{name}'.\")\n        result[name] = Version(version)\n    return result\n\n\ndef name_version_pair(s: str) -> Tuple[str, str]:\n    \"\"\"\n    Parse a name-version pair.\n\n    :param s: the parameter string.\n    :return: a pair of string (name, new_version)\n    \"\"\"\n    try:\n        name, version = [part.strip() for part in s.split(\",\")]\n        return name, version\n    except Exception:\n        raise argparse.ArgumentTypeError(f\"Name-version pair not correct: '{s}'\")\n\n\ndef parse_args() -> argparse.Namespace:\n    \"\"\"Parse arguments.\"\"\"\n    parser = argparse.ArgumentParser(\"bump_aea_version\")\n    parser.add_argument(\n        \"--update\",\n        type=name_version_pair,\n        metavar=\"'NAME,VERSION'\",\n        required=True,\n        action=\"append\",\n        help=\"A comma-separated pair: 'plugin-name, new-version'.\",\n    )\n    parser.add_argument(\"--no-fingerprint\", action=\"store_true\")\n    arguments_ = parser.parse_args()\n    return arguments_\n\n\ndef main() -> None:\n    \"\"\"Run the script.\"\"\"\n    arguments = parse_args()\n    current_versions_by_name: Dict[str, Version] = get_plugin_names_and_versions()\n    new_versions_by_name: Dict[str, Version] = dict(\n        (name, Version(version)) for name, version in arguments.update\n    )\n\n    print(\n        f\"Found plugin names and versions:\\n{pprint.pformat(current_versions_by_name)}\"\n    )\n    print(f\"Plugins to update:\\n{pprint.pformat(new_versions_by_name)}\")\n\n    not_found_plugins = set(new_versions_by_name.keys()).difference(\n        current_versions_by_name.keys()\n    )\n    if len(not_found_plugins) > 0:\n        exit_with_message(\n            f\"Error: These plugins have not been found:\\n{pprint.pformat(not_found_plugins)}\"\n        )\n\n    have_updated_specifier_set = False\n\n    for current_plugin_name, new_version in new_versions_by_name.items():\n        old_version = current_versions_by_name[current_plugin_name]\n        print(\n            f\"Processing {current_plugin_name}, old_version={old_version}, new_version={new_version}\"\n        )\n        if new_version == old_version:\n            print(\"Skipping, as old and new versions are equal.\")\n            continue\n\n        have_updated_specifier_set = (\n            process_plugin(current_plugin_name, old_version, new_version)\n            or have_updated_specifier_set\n        )\n\n    return_code = 0\n    if arguments.no_fingerprint:\n        print(\"Not updating fingerprints, since --no-fingerprint was specified.\")\n    elif not have_updated_specifier_set:\n        print(\"Not updating fingerprints, since no specifier set has been updated.\")\n    else:\n        print(\"Updating hashes and fingerprints.\")\n        return_code = update_hashes()\n    exit_with_message(\"Done!\", exit_code=return_code)\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "scripts/update_symlinks_cross_platform.py",
    "content": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n# pylint: disable=cyclic-import\n\n\"\"\"This script will update the symlinks of the project, cross-platform compatible.\"\"\"\n\nimport contextlib\nimport inspect\nimport os\nimport sys\nimport traceback\nfrom functools import reduce\nfrom pathlib import Path\nfrom typing import Generator, List, Tuple, Union\n\n\nSCRIPTS_PATH = Path(os.path.dirname(inspect.getfile(inspect.currentframe())))  # type: ignore\nROOT_PATH = SCRIPTS_PATH.parent.absolute()\nTEST_DATA = ROOT_PATH / \"tests\" / \"data\"\nTEST_DUMMY_AEA_DIR = TEST_DATA / \"dummy_aea\"\nFETCHAI_PACKAGES = ROOT_PATH / \"packages\" / \"fetchai\"\n\nSYMLINKS = [\n    (TEST_DUMMY_AEA_DIR / \"skills\" / \"dummy\", TEST_DATA / \"dummy_skill\"),\n    (\n        TEST_DUMMY_AEA_DIR / \"vendor\" / \"fetchai\" / \"protocols\" / \"default\",\n        FETCHAI_PACKAGES / \"protocols\" / \"default\",\n    ),\n    (\n        TEST_DUMMY_AEA_DIR / \"vendor\" / \"fetchai\" / \"protocols\" / \"signing\",\n        FETCHAI_PACKAGES / \"protocols\" / \"signing\",\n    ),\n    (\n        TEST_DUMMY_AEA_DIR / \"vendor\" / \"fetchai\" / \"protocols\" / \"state_update\",\n        FETCHAI_PACKAGES / \"protocols\" / \"state_update\",\n    ),\n    (\n        TEST_DUMMY_AEA_DIR / \"vendor\" / \"fetchai\" / \"protocols\" / \"fipa\",\n        FETCHAI_PACKAGES / \"protocols\" / \"fipa\",\n    ),\n    (\n        TEST_DUMMY_AEA_DIR / \"vendor\" / \"fetchai\" / \"protocols\" / \"oef_search\",\n        FETCHAI_PACKAGES / \"protocols\" / \"oef_search\",\n    ),\n    (\n        TEST_DUMMY_AEA_DIR / \"vendor\" / \"fetchai\" / \"connections\" / \"local\",\n        FETCHAI_PACKAGES / \"connections\" / \"local\",\n    ),\n    (\n        TEST_DUMMY_AEA_DIR / \"vendor\" / \"fetchai\" / \"connections\" / \"p2p_libp2p\",\n        FETCHAI_PACKAGES / \"connections\" / \"p2p_libp2p\",\n    ),\n    (\n        TEST_DUMMY_AEA_DIR / \"vendor\" / \"fetchai\" / \"contracts\" / \"erc1155\",\n        FETCHAI_PACKAGES / \"contracts\" / \"erc1155\",\n    ),\n    (\n        TEST_DUMMY_AEA_DIR / \"vendor\" / \"fetchai\" / \"skills\" / \"error\",\n        FETCHAI_PACKAGES / \"skills\" / \"error\",\n    ),\n]  # type: List[Tuple[Path, Path]]\n\"\"\"A list of pairs: (link_path, target_path)\"\"\"\n\n\ndef make_symlink(link_name: str, target: str) -> None:\n    \"\"\"\n    Make a symbolic link, cross platform.\n\n    :param link_name: the link name.\n    :param target: the target.\n    \"\"\"\n    try:\n        Path(link_name).unlink()\n    except FileNotFoundError:\n        pass\n    Path(link_name).symlink_to(target, target_is_directory=True)\n\n\n@contextlib.contextmanager\ndef cd(path: Union[Path, str]) -> Generator:\n    \"\"\"Change directory with context manager.\"\"\"\n    old_cwd = os.getcwd()\n    try:\n        os.chdir(path)\n        yield\n        os.chdir(old_cwd)\n    except Exception as e:  # pylint: disable=broad-except\n        os.chdir(old_cwd)\n        raise e from e\n\n\ndef create_symlink(link_path: Path, target_path: Path, root_path: Path) -> int:\n    \"\"\"\n    Change directory and call the cross-platform script.\n\n    The working directory must be the parent of the symbolic link name\n    when executing 'create_symlink_crossplatform.sh'. Hence, we\n    need to translate target_path into the relatve path from the\n    symbolic link directory to the target directory.\n\n    So:\n    1) from link_path, extract the number of jumps to the parent directory\n      in order to reach the repository root directory, and chain many \"../\" paths.\n    2) from target_path, compute the relative path to the root\n    3) relative_target_path is just the concatenation of the results from step (1) and (2).\n\n\n    For instance, given\n    - link_path: './directory_1//symbolic_link\n    - target_path: './directory_2/target_path\n\n    we want to compute:\n    - link_path: 'symbolic_link' (just the last bit)\n    - relative_target_path: '../../directory_1/target_path'\n\n    The resulting command on UNIX systems will be:\n\n        cd directory_1 && ln -s ../../directory_1/target_path symbolic_link\n\n    :param link_path: the link path\n    :param target_path: the target path\n    :param root_path: the root path\n    :return: exit code\n    \"\"\"\n    working_directory = link_path.parent\n    target_relative_to_root = target_path.relative_to(root_path)\n    cwd_relative_to_root = working_directory.relative_to(root_path)\n    nb_parents = len(cwd_relative_to_root.parents)\n    root_relative_to_cwd = reduce(\n        lambda x, y: x / y, [Path(\"../\")] * nb_parents, Path(\".\")\n    )\n    link_name = link_path.name\n    target = root_relative_to_cwd / target_relative_to_root\n    with cd(working_directory.absolute()):\n        make_symlink(str(link_name), str(target))\n    return 0\n\n\ndef main() -> None:\n    \"\"\"Run main script.\"\"\"\n    failed = False\n    for link_name, target in SYMLINKS:\n        print(\"Linking {} to {}\".format(link_name, target))\n        try:\n            link_name.unlink()\n        except FileNotFoundError:\n            pass\n        try:\n            return_code = create_symlink(link_name, target, ROOT_PATH)\n        except Exception as e:  # pylint: disable=broad-except\n            exception = e\n            return_code = 1\n            traceback.print_exc()\n            print(\n                \"Last command failed with return code {} and exception {}\".format(\n                    return_code, exception\n                )\n            )\n            failed = True\n\n    sys.exit(1 if failed else 0)\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "scripts/whitelist.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n# flake8: noqa\n# type: ignore\n# pylint: skip-file\n# To update; run: vulture aea --exclude \"*_pb2.py\" --make-whitelist > tests/whitelist.py\n_.dependencies_highest_version  # unused property (aea/aea_builder.py:116)\n_.set_search_service_address  # unused method (aea/aea_builder.py:484)\n_.set_required_ledgers  # unused method (aea/aea_builder.py:850)\n_.remove_private_key  # unused method (aea/aea_builder.py:580)\n_.add_component_instance  # unused method (aea/aea_builder.py:643)\n_.set_context_namespace  # unused method (aea/aea_builder.py:663)\n_.remove_protocol  # unused method (aea/aea_builder.py:694)\n_.remove_connection  # unused method (aea/aea_builder.py:714)\n_.remove_skill  # unused method (aea/aea_builder.py:734)\n_.remove_contract  # unused method (aea/aea_builder.py:754)\n_.tick  # unused property (aea/agent.py:186)\nAgentLoopException  # unused class (aea/agent_loop.py:134)\nset_command  # unused function (aea/cli/config.py:53)\nall_command  # unused function (aea/cli/list.py:47)\n_.type_cast_value  # unused method (aea/cli/utils/click_utils.py:37)\n_.get_metavar  # unused method (aea/cli/utils/click_utils.py:79)\n_.convert  # unused method (aea/cli/utils/click_utils.py:83)\n_.get_metavar  # unused method (aea/cli/utils/click_utils.py:100)\n_.convert  # unused method (aea/cli/utils/click_utils.py:104)\n_.convert  # unused method (aea/cli/utils/click_utils.py:129)\n_.formatter  # unused attribute (aea/cli/utils/loggers.py:92)\nis_item_present_unified  # unused function (aea/cli/utils/package_utils:394)\n_.latest  # unused property (aea/configurations/base.py:384)\n_.to_any  # unused property (aea/configurations/base.py:442)\n_.to_latest  # unused property (aea/configurations/base.py:442)\n_.to_uri_path  # unused property (aea/configurations/base.py:445)\n_.to_uri_path  # unused property (aea/configurations/base.py:605)\n_._ensure_connected  # unused method (aea/connections/base.py:104)\n_._ensure_valid_envelope_for_external_comms  # unused method (aea/connections/base.py:109)\n_._connect_context  # unused method (aea/connections/base.py:125)\n_.has_crypto_store  # unused property (aea/connections/base.py:138)\n_.from_dir  # unused method (aea/connections/base.py:200)\nMyScaffoldAsyncConnection  # unused class (aea/connections/scaffold/connection.py:31)\n_.get_instance  # unused method (aea/contracts/base.py:64)\n_.from_dir  # unused method (aea/contracts/base.py:81)\n_.get_raw_transaction  # unused method (aea/contracts/base.py:147)\n_.get_raw_message  # unused method (aea/contracts/base.py:163)\nMyScaffoldContract  # unused class (aea/contracts/scaffold/contract.py:25)\n_.is_valid_address  # aea/crypto/cosmos.py:170: unused method 'is_valid_address' (60% confidence)\n_.get_handle_transaction  # unused method (aea/crypto/cosmos.py:491)\n_.execute_contract_query  # unused method (aea/crypto/cosmos.py:571)\n_.get_code_id  # unused method (aea/crypto/cosmos.py:837)\n_.get_contract_address  # unused method (aea/crypto/cosmos.py:849)\nCosmosFaucetApi  # unused class (aea/crypto/cosmos.py:867)\ntestnet_name  # unused variable (aea/crypto/cosmos.py:871)\nEthereumFaucetApi  # unused class (aea/crypto/ethereum.py:507)\ntestnet_name  # unused variable (aea/crypto/ethereum.py:511)\nFetchAIFaucetApi  # unused class (aea/crypto/fetchai.py:404)\ntestnet_name  # unused variable (aea/crypto/fetchai.py:408)\n_.has_ledger  # unused method (aea/crypto/ledger_apis.py:55)\n_.get_api  # unused method (aea/crypto/ledger_apis.py:60)\n_.has_spec  # unused method (aea/crypto/registries/base.py:236)\n_.main_cryptos  # unused property (aea/crypto/wallet.py:130)\nlocate  # unused function (aea/helpers/base.py:139)\nsigint_crossplatform  # unused function (aea/helpers/base.py:236)\n_.dwFlags  # unused attribute (aea/helpers/base.py:269)\nretry_decorator  # unused function (aea/helpers/base.py:386)\n_.is_empty  # unused property (aea/helpers/dialogue/base.py:431)\n_.self_initiated  # unused property (aea/helpers/dialogue/base.py:687)\n_.other_initiated  # unused property (aea/helpers/dialogue/base.py:692)\n_.add_dialogue_endstate  # unused method (aea/helpers/dialogue/base.py:697)\n_.dialogue_stats  # unused property (aea/helpers/dialogue/base.py:767)\n_.is_cancelled_by_timeout  # unused method (aea/helpers/exec_timeout.py:51)\nexc_tb  # unused variable (aea/helpers/exec_timeout.py:102)\nexc_type  # unused variable (aea/helpers/exec_timeout.py:102)\nExecTimeoutSigAlarm  # unused class (aea/helpers/exec_timeout.py:138)\nenvelope_from_bytes  # unused function (aea/helpers/file_lock.py:112)\nLOCK_SH  # unused variable (aea/helpers/file_lock.py:32)\nLOCK_NB  # unused variable (aea/helpers/file_lock.py:33)\n_.filesize  # unused attribute (aea/helpers/ipfs/base.py:92)\nMultiAddr  # unused class (aea/helpers/multiaddr/base.py:82)\n_.in_path  # unused property (aea/helpers/pipe.py:70)\n_.out_path  # unused property (aea/helpers/pipe.py:77)\n_.in_path  # unused property (aea/helpers/pipe.py:171)\n_.out_path  # unused property (aea/helpers/pipe.py:175)\n_.in_path  # unused property (aea/helpers/pipe.py:305)\n_.out_path  # unused property (aea/helpers/pipe.py:309)\nmake_ipc_channel  # unused function (aea/helpers/pipe.py:647)\nmake_ipc_channel_client  # unused function (aea/helpers/pipe.py:663)\nto_set_specifier  # unused function (aea/helpers/pypi.py:199)\nGenericDataModel  # unused class (aea/helpers/search/generic.py:29)\nAGENT_LOCATION_MODEL  # unused variable (aea/helpers/search/generic.py:54)\nAGENT_PERSONALITY_MODEL  # unused variable (aea/helpers/search/generic.py:61)\nAGENT_SET_SERVICE_MODEL  # unused variable (aea/helpers/search/generic.py:71)\nSIMPLE_SERVICE_MODEL  # unused variable (aea/helpers/search/generic.py:81)\nSIMPLE_DATA_MODEL  # unused variable (aea/helpers/search/generic.py:88)\nAGENT_REMOVE_SERVICE_MODEL  # unused variable (aea/helpers/search/generic.py:95)\n_.counterparty_hash  # unused property (aea/helpers/transaction/base.py:529)\n_.sender_payable_amount_incl_fee  # unused property (aea/helpers/transaction/base.py:598)\n_.counterparty_payable_amount_incl_fee  # unused property (aea/helpers/transaction/base.py:623)\n_.sender_fee  # unused property (aea/helpers/transaction/base.py:673)\n_.counterparty_fee  # unused property (aea/helpers/transaction/base.py:679)\n_.is_connecting  # unused attribute (aea/multiplexer.py:53)\n_.put_message  # unused method (aea/multiplexer.py:821)\n_.has_to  # unused property (aea/protocols/base.py:100)\nProtobufSerializer  # unused class (aea/protocols/base.py:278)\nJSONSerializer  # unused class (aea/protocols/base.py:304)\n_.from_dir  # unused method (aea/protocols/base.py:359)\nINVALID_MESSAGE  # unused variable (aea/protocols/default/custom_types.py:30)\nINVALID_DIALOGUE  # unused variable (aea/protocols/default/custom_types.py:32)\n_.get_all_protocols  # unused method (aea/registries/resources.py:124)\n_.remove_protocol  # unused method (aea/registries/resources.py:133)\n_.get_contract  # unused method (aea/registries/resources.py:153)\n_.get_all_contracts  # unused method (aea/registries/resources.py:165)\n_.remove_contract  # unused method (aea/registries/resources.py:174)\n_.get_connection  # unused method (aea/registries/resources.py:194)\n_.remove_connection  # unused method (aea/registries/resources.py:215)\n_.get_skill  # unused method (aea/registries/resources.py:248)\n_.remove_skill  # unused method (aea/registries/resources.py:269)\n_.get_all_handlers  # unused method (aea/registries/resources.py:309)\n_.get_behaviour  # unused method (aea/registries/resources.py:318)\n_.get_behaviours  # unused method (aea/registries/resources.py:331)\nPUBLIC_ID  # unused variable (aea/skills/__init__.py:25)\n_.agent_addresses  # unused property (aea/skills/base.py:154)\n_.from_dir  # unused method (aea/skills/base.py:683)\nCyclicBehaviour  # unused class (aea/skills/behaviours.py:57)\n_.number_of_executions  # unused property (aea/skills/behaviours.py:66)\nOneShotBehaviour  # unused class (aea/skills/behaviours.py:80)\nTickerBehaviour  # unused class (aea/skills/behaviours.py:99)\n_.last_act_time  # unused property (aea/skills/behaviours.py:135)\nSequenceBehaviour  # unused class (aea/skills/behaviours.py:159)\nFSMBehaviour  # unused class (aea/skills/behaviours.py:243)\n_.is_started  # unused property (aea/skills/behaviours.py:258)\n_.register_state  # unused method (aea/skills/behaviours.py:263)\n_.register_final_state  # unused method (aea/skills/behaviours.py:280)\n_.unregister_state  # unused method (aea/skills/behaviours.py:294)\n_.final_states  # unused property (aea/skills/behaviours.py:331)\n_.register_transition  # unused method (aea/skills/behaviours.py:364)\n_.unregister_transition  # unused method (aea/skills/behaviours.py:383)\nMyScaffoldBehaviour  # unused class (aea/skills/scaffold/behaviours.py:25)\nMyScaffoldHandler  # unused class (aea/skills/scaffold/handlers.py:29)\nMyModel  # unused class (aea/skills/scaffold/my_model.py:25)\n_.is_executed  # unused property (aea/skills/tasks.py:68)\n_.is_started  # unused property (aea/skills/tasks.py:146)\n_.disable_aea_logging  # unused method (aea/test_tools/test_cases.py:134)\n_.start_subprocess  # unused method (aea/test_tools/test_cases.py:198)\n_.difference_to_fetched_agent  # unused method (aea/test_tools/test_cases.py:256)\n_.delete_agents  # unused method (aea/test_tools/test_cases.py:328)\n_.run_agent  # unused method (aea/test_tools/test_cases.py:341)\n_.run_interaction  # unused method (aea/test_tools/test_cases.py:354)\n_.is_successfully_terminated  # unused method (aea/test_tools/test_cases.py:407)\n_.fingerprint_item  # unused method (aea/test_tools/test_cases.py:457)\n_.eject_item  # unused method (aea/test_tools/test_cases.py:473)\n_.run_install  # unused method (aea/test_tools/test_cases.py:488)\n_.replace_private_key_in_file  # unused method (aea/test_tools/test_cases.py:549)\n_.replace_file_content  # unused method (aea/test_tools/test_cases.py:596)\n_.send_envelope_to_agent  # unused method (aea/test_tools/test_cases.py:685)\n_.read_envelope_from_agent  # unused method (aea/test_tools/test_cases.py:694)\n_._is_teardown_class_called  # unused attribute (aea/test_tools/test_cases.py:801)\n_._start_oef_node  # unused method (aea/test_tools/test_cases.py:808)\nnetwork_node  # unused variable (aea/test_tools/test_cases.py:809)\n_.get_dialogues_with_counterparty  # unused method (aea/protocols/dialogue/base.py:999)\nreceiver_address  # unused variable (aea/decision_maker/default.py:70)\nreceiver_address  # unused variable (aea/decision_maker/default.py:99)\ncreate_with_message  # unused method (aea/helpers/dialogue/base.py:1054)\n_.is_disconnecting  # unused property (aea/multiplexer.py:67)\n_.get_quantity_in_outbox  # unused method (aea/test_tools/test_skills.py:52)\n_.get_message_from_outbox  # unused method (aea/test_tools/test_skills.py:56)\n_.drop_messages_from_outbox  # unused method (aea/test_tools/test_skills.py:70)\n_.drop_messages_from_decision_maker_inbox  # unused method (aea/test_tools/test_skills.py:86)\n_.get_quantity_in_decision_maker_inbox  # unused method (aea/test_tools/test_skills.py:69)\n_.get_message_from_decision_maker_inbox  # unused method (aea/test_tools/test_skills.py:73)\n_.assert_quantity_in_outbox  # unused method (aea/test_tools/test_skills.py:79)\n_.assert_quantity_in_decision_making_queue  # unused method (aea/test_tools/test_skills.py:86)\n_.message_has_attributes  # unused method (aea/test_tools/test_skills.py:69)\n_.build_incoming_message_for_skill_dialogue  # unused method (aea/test_tools/test_skills.py:155)\n_.prepare_skill_dialogue  # unused method (aea/test_tools/test_skills.py:290)\n_.__defaults__  # unused attribute (aea/protocols/dialogue/base.py:49)\n_.build_incoming_message_for_dialogue  # unused method (aea/test_tools/test_skills.py:155)\n_._has_message  # unused method (aea/protocols/dialogue/base.py:491)\nMultiAgentManager  # unused class (aea/manager.py:127)\n_.add_error_callback  # unused method (aea/manager.py:202)\n_.start_manager  # unused method (aea/manager.py:208)\n_.stop_manager  # unused method (aea/manager.py:221)\n_.projects  # unused property (aea/manager.py:228)\n_.add_project  # unused method (aea/manager.py:263)\n_.list_projects  # unused method (aea/manager.py:283)\n_.list_agents_info  # unused method (aea/manager.py:283)\n_.add_agent  # unused method (aea/manager.py:291)\n_.start_all_agents  # unused method (aea/manager.py:396)\n_.get_agent_alias  # unused method (aea/manager.py:486)\n_.DEFAULT_PYPI_INDEX_URL  # unused variable (aea/configurations/base.py:85)\nAEARunner  # unused class (aea/runner.py:84)\n_.join_thread  # unused method (aea/helpers/multiple_executor.py:430)\n_.valid_performatives  # unused property (aea/protocols/base.py:90)\n_.has_dialogue_info  # unused property (aea/protocols/base.py:244)\nget_state  # aea/crypto/base.py:251: unused method 'get_state' (60% confidence)\n_.load_agent_config  # unused method (aea/test_tools/test_cases.py:801)\n_.UseGanache  # unused class (aea/test_tools/test_cases.py:871)\n_._start_ganache  # unused method (aea/test_tools/test_cases.py:875)\n_.ganache  # unused variable (aea/test_tools/test_cases.py:876:)\n_.unsupported_protocol_count\n_.unsupported_skill_count\n_.decoding_error_count\n_.ErrorHandler  # unused class (aea/error_handler/scaffold.py:27)\nensure_dir  # unused function (aea/helpers/base.py:561)\n_.get_agent_overridables  # unused method (aea/manager/manager.py:419)\n_.set_agent_overrides  # unused method (aea/manager/manager.py:432)\nby_path  # unused function (aea/cli/fingerprint.py:94)\nAgentRecord  # unused class (aea/helpers/acn/agent_record.py:49)\ncheck_validity  # unused method (aea/helpers/acn/agent_record.py:96)\nsignature_from_cert_request  # unused function (aea/helpers/acn/agent_record.py:51)\nUri  # unused class (aea/helpers/acn/uri.py:26)\nnot_before_string  # unused property (aea/helpers/base.py:724)\nnot_after_string  # unused property (aea/helpers/base.py:729)\nfrom_cert_request  # unused method (aea/helpers/acn/agent_record.py:136)\nFetchAICrypto  # unused class (aea/crypto/fetchai.py:40)\nentity  # unused property (aea/crypto/base.py:77)\ncallable_name  # unused variable (aea/crypto/base.py:277)\nupdate_with_gas_estimate  # unused method (aea/crypto/base.py:362)\ntry_decorator  # unused function (aea/helpers/base.py:284)\nfrom_string  # unused method (aea/helpers/multiaddr/base.py:163)\nBaseSyncConnection  # unused class (aea/connections/sync_connection.py:33)\n_.put_envelope  # unused method (aea/connections/sync_connection.py:84)\nMyScaffoldSyncConnection  # unused class (aea/connections/scaffold/connection.py:89)\nrun_count  # unused variable (aea/test_tools/test_cases.py:998)\n_.get_addresses  # unused method (aea/manager/project.py:284)\n_.get_connections_addresses  # unused method (aea/manager/project.py:289)\n_.check_protobuf_using_protoc  # unused function (aea/protocols/generator/common.py:420)\n_.last_start_status  # unused property (aea/manager/manager.py:296)\nfrom_uri_path  # unused method (aea/configurations/data_types.py:339)\nfrom_uri_path  # unused method (aea/configurations/data_types.py:497)\nno_active_handler_count  # unused attribute (aea/error_handler/default.py:76)\nparse_module  # unused method (aea/skills/base.py:359)\nparse_module  # unused method (aea/skills/base.py:419)\nparse_module  # unused method (aea/skills/base.py:463)\nparse_module  # unused method (aea/skills/base.py:520)\n_.__path__  # unused attribute (aea/components/base.py:137)\n_.__path__  # unused attribute (aea/components/base.py:140)\n_.__path__  # unused attribute (aea/components/base.py:143)\nshort_help  # unused method (aea/cli/plugin.py:83)\nparse_args  # unused method (aea/cli/plugin.py:99)\nencrypt  # unused method (aea/crypto/base.py:148)\ndecrypt  # unused method (aea/crypto/base.py:158)\nkeyfile_json  # unused variable (aea/crypto/base.py:159)\nDecryptError  # unused class (aea/crypto/helpers.py:195)\nhex_to_bytes_for_key  # unused function (aea/crypto/helpers.py:209)\nitem_owner_crypto  # unused attribute 'item_owner_crypto' (aea/test_tools/test_contract.py:70)\nTCPSocketChannelClientTLS  # unused class (/home/solarw/MyData/work/fetchai/agents-aea/aea/helpers/pipe.py:597)\n_.check_hostname  # unused attribute (/home/solarw/MyData/work/fetchai/agents-aea/aea/helpers/pipe.py:603)\n_.verify_mode  # unused attribute (/home/solarw/MyData/work/fetchai/agents-aea/aea/helpers/pipe.py:604)\n_.last_exception  # unused attribute (/home/solarw/MyData/work/fetchai/agents-aea/aea/helpers/pipe.py:539)\n_.last_exception  # unused attribute (/home/solarw/MyData/work/fetchai/agents-aea/aea/helpers/pipe.py:567)\n_.last_exception  # unused attribute (/home/solarw/MyData/work/fetchai/agents-aea/aea/helpers/pipe.py:630)\n_.last_exception  # unused attribute (/home/solarw/MyData/work/fetchai/agents-aea/aea/helpers/pipe.py:649)\nrun_install_subprocess  # unused function (/home/solarw/MyData/work/fetchai/agents-aea/aea/helpers/install_dependency.py:75)\n_.deployment_tx_receipt  # unused attribute (agents-aea/aea/test_tools/test_contract.py:105)\n_.Hash  # unused attribute (/home/solarw/MyData/work/fetchai/agents-aea/aea/helpers/ipfs/base.py:124)\n_.Tsize  # unused attribute (/home/solarw/MyData/work/fetchai/agents-aea/aea/helpers/ipfs/base.py:125)\n_.Name  # unused attribute (/home/solarw/MyData/work/fetchai/agents-aea/aea/helpers/ipfs/base.py:126)\ninit_worker  # unused function (/home/solarw/MyData/work/fetchai/agents-aea/aea/skills/tasks.py:108)\n_._generate_hash  # unused method (/home/solarw/MyData/work/fetchai/agents-aea/aea/helpers/ipfs/base.py:161)\n"
  },
  {
    "path": "setup.cfg",
    "content": "[flake8]\npaths=aea,examples,packages,scripts,tests\nexclude=.md,\n    *_pb2.py,\n    aea/__init__.py,\n    aea/cli/__init__.py,\n    tests/common/oef_search_pluto_scripts,\n    tests/common/click_testing.py,\n    scripts/oef/launch.py\nmax-line-length = 88\nselect = B,C,D,E,F,I,W,\nignore = B014,D202,D400,D401,E501,E203,W503,DAR002,DAR003,DAR101,DAR102,DAR201,DAR202,DAR301,DAR401,DAR402\napplication-import-names = aea,packages,tests,scripts\ndocstring_style=sphinx\nstrictness=short\n\n# ignore as too restrictive for our needs:\n# B014: redundant exception\n# D202: blank lines\n# D400: First line should end with a period\n# D401: First line should be in imperative mood\n# E501: https://www.flake8rules.com/rules/E501.html (Line too long)\n# E203: https://www.flake8rules.com/rules/E203.html (Whitespace)\n# W503: https://www.flake8rules.com/rules/W503.html (Line break)\n# DAR002 Empty description: e\n# DAR003: Incorrect indentation: ~<\n# DAR101: Missing parameter(s) in Docstring: - **kwargs\n# DAR102 Excess parameter(s) in Docstring: + component\n# DAR201: Missing \"Returns\" in Docstring: - return\n# DAR202: Excess \"Returns\" in Docstring: + return\n# DAR301: Missing \"Yields\" in Docstring: - yield\n# DAR401 Missing exception(s) in Raises section: -r Exception\n# DAR402 Excess exception(s) in Raises section: +r ValueError"
  },
  {
    "path": "strategy.ini",
    "content": "; some useful links:\n; - https://janelia-flyem.github.io/licenses.html\n; - https://dwheeler.com/essays/floss-license-slide.html\n\n; Authorized and unauthorized licenses in LOWER CASE\n[Licenses]\nauthorized_licenses:\n\t; aliases for MIT License\n\tMIT\n\tMIT license\n\thttps://opensource.org/licenses/MIT\n\tLicense :: OSI Approved :: MIT\n\n\t; aliases for BSD License (and variants)\n\tBSD\n\tBSD license\n\tnew BSD\n\t(new) BSD\n\tnew BDS license\n\tsimplified BSD\n\t3-Clause BSD\n\tBSD-3-Clause\n\tBSD 3-Clause\n\tBSD-2-Clause\n\tBSD-like\n\tBSD-2-Clause or Apache-2.0\n\tBSD, Public Domain\n\n\t; aliases for Apache License version 2.0\n\tApache 2.0\n\tApache-2.0\n\tApache License 2.0\n\tApache License, Version 2.0\n\tApache License Version 2.0\n\tApache2\n\tASL 2\n;\tsome packages use 'Apache Software' as license string,\n;\twhich is ambiguous. However, 'Apache Software'\n;\twill likely match with 'Apache 2.0'\n\tApache Software\n\tBSD, Public Domain, Apache\n\thttp://www.apache.org/licenses/LICENSE-2.0\n\n;\tPSF (BSD-style)\n\tPython Software Foundation\n\tPSF\n\n\t; other permissive licenses\n\tHistorical Permission Notice and Disclaimer (HPND)\n\tHPND\n\tISC\n\tISCL\n\tISC License (ISCL)\n\tBSD or Apache License, Version 2.0\n\tModified BSD\n\tExpat\n\nunauthorized_licenses:\n;\taliases for MPL 2.0\n\tMPL-2.0\n\tMPL 2.0\n\tMozilla Public License 2.0 (MPL 2.0)\n\n;    Section 8 of https://www.mozilla.org/en-US/MPL/2.0/Revision-FAQ/\n\tMPL 1.1\n\tMPL-1.1\n\n;\thttp://www.gnu.org/licenses/license-list.en.html#apache2\n\tGPLv2\n\tGPLv2+\n\tGNU General Public License v2 or later (GPLv2+)\n\n;\tLGPL\n\tLGPL\n\tGNU Library or Lesser General Public License (LGPL)\n\n;\tLGPLv2.1\n\tLGPLv2.1\n\tLGPLv2.1+\n\n;\tLGPLv3\n\tGNU Lesser General Public License v3 (LGPLv3)\n\tLGPLv3\n\n;\tGPL v3\n\tGPL v3\n\tGPLv3+\n\n[Authorized Packages]\ngym: >=0.15\n;filelock is public domain\nfilelock: >=3.0.12\nfetchai-ledger-api: >=0.0.1\nchardet: >=3.0.4\ncertifi: >=2019.11.28\npathable: *\n"
  },
  {
    "path": "tests/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"The tests module contains the tests of the AEA package.\"\"\"\n"
  },
  {
    "path": "tests/common/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This test module contains the common modules.\"\"\"\n"
  },
  {
    "path": "tests/common/docker_image.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains testing utilities.\"\"\"\nimport asyncio\nimport logging\nimport os\nimport re\nimport shutil\nimport subprocess  # nosec\nimport sys\nimport tempfile\nimport time\nfrom abc import ABC, abstractmethod\nfrom threading import Timer\nfrom typing import Dict, List, Optional\n\nimport docker\nimport pytest\nfrom docker import DockerClient\nfrom docker.models.containers import Container\nfrom oef.agents import OEFAgent\nfrom oef.core import AsyncioCore\n\nfrom aea.exceptions import enforce\nfrom aea.helpers import http_requests as requests\n\n\nlogger = logging.getLogger(__name__)\n\n\nclass DockerImage(ABC):\n    \"\"\"A class to wrap interatction with a Docker image.\"\"\"\n\n    MINIMUM_DOCKER_VERSION = (19, 0, 0)\n\n    def __init__(self, client: docker.DockerClient):\n        \"\"\"Initialize.\"\"\"\n        self._client = client\n\n    def check_skip(self):\n        \"\"\"\n        Check whether the test should be skipped.\n\n        By default, nothing happens.\n        \"\"\"\n        self._check_docker_binary_available()\n\n    def _check_docker_binary_available(self):\n        \"\"\"Check the 'Docker' CLI tool is in the OS PATH.\"\"\"\n        result = shutil.which(\"docker\")\n        if result is None:\n            pytest.skip(\"Docker not in the OS Path; skipping the test\")\n\n        result = subprocess.run(  # nosec\n            [\"docker\", \"--version\"], stdout=subprocess.PIPE, stderr=subprocess.PIPE\n        )\n        if result.returncode != 0:\n            pytest.skip(f\"'docker --version' failed with exit code {result.returncode}\")\n\n        match = re.search(\n            r\"Docker version ([0-9]+)\\.([0-9]+)\\.([0-9]+)\",\n            result.stdout.decode(\"utf-8\"),\n        )\n        if match is None:\n            pytest.skip(\"cannot read version from the output of 'docker --version'\")\n        version = (int(match.group(1)), int(match.group(2)), int(match.group(3)))\n        if version < self.MINIMUM_DOCKER_VERSION:\n            pytest.skip(\n                f\"expected Docker version to be at least {'.'.join(self.MINIMUM_DOCKER_VERSION)}, found {'.'.join(version)}\"\n            )\n\n    @property\n    @abstractmethod\n    def tag(self) -> str:\n        \"\"\"Return the tag of the image.\"\"\"\n\n    def pull_image(self, retries=3) -> None:\n        \"\"\"Pull image from remote repo.\"\"\"\n        for _ in range(retries):\n            try:\n                self._client.images.pull(self.tag)\n                return\n            except Exception as e:  # nosec\n                print(\"failed to pull image\", e)\n\n    def stop_if_already_running(self):\n        \"\"\"Stop the running images with the same tag, if any.\"\"\"\n        client = docker.from_env()\n        for container in client.containers.list():\n            if self.tag in container.image.tags:\n                logger.info(f\"Stopping image {self.tag}...\")\n                container.stop()\n                container.wait()\n\n    @abstractmethod\n    def create(self) -> Container:\n        \"\"\"Instantiate the image in a container.\"\"\"\n\n    @abstractmethod\n    def wait(self, max_attempts: int = 15, sleep_rate: float = 1.0) -> bool:\n        \"\"\"\n        Wait until the image is running.\n\n        :param max_attempts: max number of attempts.\n        :param sleep_rate: the amount of time to sleep between different requests.\n        :return: True if the wait was successful, False otherwise.\n        \"\"\"\n        return True\n\n\nclass OEFHealthCheck(object):\n    \"\"\"A health check class.\"\"\"\n\n    def __init__(\n        self,\n        oef_addr: str,\n        oef_port: int,\n        loop: Optional[asyncio.AbstractEventLoop] = None,\n    ):\n        \"\"\"\n        Initialize.\n\n        :param oef_addr: IP address of the OEF node.\n        :param oef_port: Port of the OEF node.\n        \"\"\"\n        self.oef_addr = oef_addr\n        self.oef_port = oef_port\n\n        self._result = False\n        self._stop = False\n        self._core = AsyncioCore()\n        self.agent = OEFAgent(\n            \"check\", core=self._core, oef_addr=self.oef_addr, oef_port=self.oef_port\n        )\n        self.agent.on_connect_success = self.on_connect_ok\n        self.agent.on_connection_terminated = self.on_connect_terminated\n        self.agent.on_connect_failed = self.exception_handler\n\n    def exception_handler(self, url=None, ex=None):\n        \"\"\"Handle exception during a connection attempt.\"\"\"\n        print(\"An error occurred. Exception: {}\".format(ex))\n        self._stop = True\n\n    def on_connect_ok(self, url=None):\n        \"\"\"Handle a successful connection.\"\"\"\n        print(\"Connection OK!\")\n        self._result = True\n        self._stop = True\n\n    def on_connect_terminated(self, url=None):\n        \"\"\"Handle a connection failure.\"\"\"\n        print(\"Connection terminated.\")\n        self._stop = True\n\n    def run(self) -> bool:\n        \"\"\"\n        Run the check, asynchronously.\n\n        :return: True if the check is successful, False otherwise.\n        \"\"\"\n        self._result = False\n        self._stop = False\n\n        def stop_connection_attempt(self):\n            if self.agent.state == \"connecting\":\n                self.agent.state = \"failed\"\n\n        t = Timer(1.5, stop_connection_attempt, args=(self,))\n\n        try:\n            print(\"Connecting to {}:{}...\".format(self.oef_addr, self.oef_port))\n            self._core.run_threaded()\n\n            t.start()\n            self._result = self.agent.connect()\n            self._stop = True\n\n            if self._result:\n                print(\"Connection established. Tearing down connection...\")\n                self.agent.disconnect()\n                t.cancel()\n            else:\n                print(\"A problem occurred. Exiting...\")\n            return self._result\n\n        except Exception as e:\n            print(str(e))\n            return self._result\n        finally:\n            t.join()\n            self.agent.stop()\n            self.agent.disconnect()\n            self._core.stop()\n\n\nclass OEFSearchDockerImage(DockerImage):\n    \"\"\"Wrapper to OEF Search Docker image.\"\"\"\n\n    def __init__(self, client: DockerClient, oef_addr: str, oef_port: int):\n        \"\"\"Initialize the OEF Search Docker image.\"\"\"\n        super().__init__(client)\n        self._oef_addr = oef_addr\n        self._oef_port = oef_port\n\n    @property\n    def tag(self) -> str:\n        \"\"\"Get the image tag.\"\"\"\n        return \"fetchai/oef-search:0.7\"\n\n    def check_skip(self):\n        \"\"\"Check if the test should be skipped.\"\"\"\n        super().check_skip()\n        if sys.version_info < (3, 7):\n            pytest.skip(\"Python version < 3.7 not supported by the OEF.\")\n            return\n\n    def create(self) -> Container:\n        \"\"\"Create an instance of the OEF Search image.\"\"\"\n        from tests.conftest import ROOT_DIR  # pylint: disable\n\n        self.pull_image()\n\n        logger.info(ROOT_DIR + \"/tests/common/oef_search_pluto_scripts\")\n        ports = {\n            \"20000/tcp\": (\"0.0.0.0\", 20000),  # nosec\n            \"30000/tcp\": (\"0.0.0.0\", 30000),  # nosec\n            \"{}/tcp\".format(self._oef_port): (\"0.0.0.0\", self._oef_port),  # nosec\n        }\n        volumes = {\n            ROOT_DIR\n            + \"/tests/common/oef_search_pluto_scripts\": {\n                \"bind\": \"/config\",\n                \"mode\": \"rw\",\n            },\n            ROOT_DIR + \"/data/oef-logs\": {\"bind\": \"/logs\", \"mode\": \"rw\"},\n        }\n        c = self._client.containers.run(\n            self.tag,\n            \"/config/node_config.json\",\n            detach=True,\n            ports=ports,\n            volumes=volumes,\n        )\n        return c\n\n    def wait(self, max_attempts: int = 15, sleep_rate: float = 1.0) -> bool:\n        \"\"\"Wait until the image is up.\"\"\"\n        success = False\n        attempt = 0\n        while not success and attempt < max_attempts:\n            attempt += 1\n            logger.info(\"Attempt {}...\".format(attempt))\n            oef_healthcheck = OEFHealthCheck(\"127.0.0.1\", 10000)\n            result = oef_healthcheck.run()\n            if result:\n                success = True\n            else:\n                logger.info(\n                    \"OEF not available yet - sleeping for {} second...\".format(\n                        sleep_rate\n                    )\n                )\n                time.sleep(sleep_rate)\n\n        return success\n\n\nclass GanacheDockerImage(DockerImage):\n    \"\"\"Wrapper to Ganache Docker image.\"\"\"\n\n    def __init__(\n        self,\n        client: DockerClient,\n        addr: str,\n        port: int,\n        config: Optional[Dict] = None,\n        gas_limit: int = 10000000000000,\n    ):\n        \"\"\"\n        Initialize the Ganache Docker image.\n\n        :param client: the Docker client.\n        :param addr: the address.\n        :param port: the port.\n        :param config: optional configuration to command line.\n        \"\"\"\n        super().__init__(client)\n        self._addr = addr\n        self._port = port\n        self._config = config or {}\n        self._gas_limit = gas_limit\n\n    @property\n    def tag(self) -> str:\n        \"\"\"Get the image tag.\"\"\"\n        return \"trufflesuite/ganache-cli:latest\"\n\n    def _make_ports(self) -> Dict:\n        \"\"\"Make ports dictionary for Docker.\"\"\"\n        return {f\"{self._port}/tcp\": (\"0.0.0.0\", self._port)}  # nosec\n\n    def _build_command(self) -> List[str]:\n        \"\"\"Build command.\"\"\"\n        cmd = [\"ganache-cli\"]\n        cmd += [\"--gasLimit=\" + str(self._gas_limit)]\n        accounts_balances = self._config.get(\"accounts_balances\", [])\n        for account, balance in accounts_balances:\n            cmd += [f\"--account='{account},{balance}'\"]\n        return cmd\n\n    def create(self) -> Container:\n        \"\"\"Create the container.\"\"\"\n        cmd = self._build_command()\n        container = self._client.containers.run(\n            self.tag, command=cmd, detach=True, ports=self._make_ports()\n        )\n        return container\n\n    def wait(self, max_attempts: int = 15, sleep_rate: float = 1.0) -> bool:\n        \"\"\"Wait until the image is up.\"\"\"\n        request = dict(jsonrpc=2.0, method=\"web3_clientVersion\", params=[], id=1)\n        for i in range(max_attempts):\n            try:\n                response = requests.post(f\"{self._addr}:{self._port}\", json=request)\n                enforce(response.status_code == 200, \"\")\n                return True\n            except Exception:\n                logger.info(\n                    \"Attempt %s failed. Retrying in %s seconds...\", i, sleep_rate\n                )\n                time.sleep(sleep_rate)\n        return False\n\n\nclass SOEFDockerImage(DockerImage):\n    \"\"\"Wrapper to SOEF Docker image.\"\"\"\n\n    PORT = 12002\n    SOEF_MOUNT_PATH = os.path.abspath(os.path.join(os.sep, \"etc\", \"soef\"))\n    SOEF_CONFIG_FILE_NAME = \"soef.conf\"\n\n    def __init__(\n        self,\n        client: DockerClient,\n        addr: str,\n        port: int = PORT,\n    ):\n        \"\"\"\n        Initialize the SOEF Docker image.\n\n        :param client: the Docker client.\n        :param addr: the address.\n        :param port: the port.\n        \"\"\"\n        super().__init__(client)\n        self._addr = addr\n        self._port = port\n\n    @property\n    def tag(self) -> str:\n        \"\"\"Get the image tag.\"\"\"\n        return \"gcr.io/fetch-ai-images/soef:9e78611\"\n\n    def _make_soef_config_file(self, tmpdirname) -> None:\n        \"\"\"Make a temporary soef_config file to setup and run the an soef instance.\"\"\"\n        soef_config_lines = [\n            \"# SIMPLE OEF CONFIGURATION FILE\",\n            \"# Save as /etc/soef/soef.conf\",\n            \"#\",\n            \"# 27th May 2020\",\n            \"# (Author Toby Simpson)\",\n            \"#\",\n            \"# Port we're listening on\",\n            \"port 9000\",\n            \"#\",\n            \"# Our declared location\",\n            \"latitude 52.205278\",\n            \"longitude 0.119167\",\n            \"#\",\n            \"# Various API keys\",\n            \"agent_registration_api_key TwiCIriSl0mLahw17pyqoA\",\n            \"get_log_api_key TwigsriSl0mLahw48pyqoA\",\n            \"get_agent_partial_list_api_key SnakesiSl0mLahw48pyqoA\",\n            \"#\",\n            \"# Start cold being 1 means 'do not load agents'\",\n            \"start_cold 0\",\n            \"#\",\n            \"# End.\",\n        ]\n        soef_config_file = os.path.join(tmpdirname, self.SOEF_CONFIG_FILE_NAME)\n        with open(soef_config_file, \"w\") as file:\n            file.writelines(line + \"\\n\" for line in soef_config_lines)\n        os.chmod(soef_config_file, 400)  # nosec\n\n    def _make_ports(self) -> Dict:\n        \"\"\"Make ports dictionary for Docker.\"\"\"\n        return {\"9000/tcp\": (\"0.0.0.0\", self._port)}  # nosec\n\n    def create(self) -> Container:\n        \"\"\"Create the container.\"\"\"\n        self.pull_image()\n        with tempfile.TemporaryDirectory() as tmpdirname:\n            self._make_soef_config_file(tmpdirname)\n            volumes = {tmpdirname: {\"bind\": self.SOEF_MOUNT_PATH, \"mode\": \"ro\"}}\n            container = self._client.containers.run(\n                self.tag, detach=True, volumes=volumes, ports=self._make_ports()\n            )\n        return container\n\n    def wait(self, max_attempts: int = 15, sleep_rate: float = 1.0) -> bool:\n        \"\"\"Wait until the image is up.\"\"\"\n        for i in range(max_attempts):\n            try:\n                response = requests.get(f\"{self._addr}:{self._port}\")\n                enforce(response.status_code == 200, \"\")\n                return True\n            except Exception as e:\n                logger.info(\n                    f\"Attempt {i} failed. Retrying in {sleep_rate} seconds... exception {e}\"\n                )\n                time.sleep(sleep_rate)\n        return False\n\n\nclass FetchLedgerDockerImage(DockerImage):\n    \"\"\"Wrapper to Fetch ledger Docker image.\"\"\"\n\n    PORTS = {1317: 1317, 26657: 26657}\n\n    def __init__(\n        self,\n        client: DockerClient,\n        addr: str,\n        port: int,\n        tag: str,\n        config: Optional[Dict] = None,\n    ):\n        \"\"\"\n        Initialize the Fetch ledger Docker image.\n\n        :param client: the Docker client.\n        :param addr: the address.\n        :param port: the port.\n        :param config: optional configuration to command line.\n        \"\"\"\n        super().__init__(client)\n        self._addr = addr\n        self._port = port\n        self._image_tag = tag\n        self._config = config or {}\n\n    @property\n    def tag(self) -> str:\n        \"\"\"Get the image tag.\"\"\"\n        return self._image_tag\n\n    def _make_entrypoint_file(self, tmpdirname) -> None:\n        \"\"\"Make a temporary entrypoint file to setup and run the test ledger node\"\"\"\n        run_node_lines = (\n            \"#!/usr/bin/env bash\",\n            # variables\n            f'export VALIDATOR_KEY_NAME={self._config[\"genesis_account\"]}',\n            f'export VALIDATOR_MNEMONIC=\"{self._config[\"mnemonic\"]}\"',\n            'export PASSWORD=\"12345678\"',\n            f'export CHAIN_ID={self._config[\"chain_id\"]}',\n            f'export MONIKER={self._config[\"moniker\"]}',\n            f'export DENOM={self._config[\"denom\"]}',\n            # Add key\n            '( echo \"$VALIDATOR_MNEMONIC\"; echo \"$PASSWORD\"; echo \"$PASSWORD\"; ) |fetchd keys add $VALIDATOR_KEY_NAME --recover',\n            # Configure node\n            \"fetchd init --chain-id=$CHAIN_ID $MONIKER\",\n            'echo \"$PASSWORD\" |fetchd add-genesis-account $(fetchd keys show $VALIDATOR_KEY_NAME -a) 100000000000000000000000$DENOM',\n            'echo \"$PASSWORD\" |fetchd gentx $VALIDATOR_KEY_NAME 10000000000000000000000$DENOM --chain-id $CHAIN_ID',\n            \"fetchd collect-gentxs\",\n            # Enable rest-api\n            'sed -i \"s/stake/atestfet/\" ~/.fetchd/config/genesis.json',\n            'sed -i \"s/enable = false/enable = true/\" ~/.fetchd/config/app.toml',\n            'sed -i \"s/swagger = false/swagger = true/\" ~/.fetchd/config/app.toml',\n            \"fetchd start\",\n        )\n\n        entrypoint_file = os.path.join(tmpdirname, \"run-node.sh\")\n        with open(entrypoint_file, \"w\") as file:\n            file.writelines(line + \"\\n\" for line in run_node_lines)\n        os.chmod(entrypoint_file, 300)  # nosec\n\n    def create(self) -> Container:\n        \"\"\"Create the container.\"\"\"\n        self.pull_image()\n        with tempfile.TemporaryDirectory() as tmpdirname:\n            self._make_entrypoint_file(tmpdirname)\n            mount_path = \"/mnt\"\n            volumes = {tmpdirname: {\"bind\": mount_path, \"mode\": \"rw\"}}\n            entrypoint = os.path.join(mount_path, \"run-node.sh\")\n            container = self._client.containers.run(\n                self.tag,\n                detach=True,\n                network=\"host\",\n                volumes=volumes,\n                entrypoint=str(entrypoint),\n                ports=self.PORTS,\n            )\n        return container\n\n    def wait(self, max_attempts: int = 15, sleep_rate: float = 1.0) -> bool:\n        \"\"\"Wait until the image is up.\"\"\"\n        for i in range(max_attempts):\n            try:\n                url = f\"{self._addr}:{self._port}/net_info?\"\n                response = requests.get(url)\n                enforce(response.status_code == 200, \"\")\n                return True\n            except Exception:\n                logger.info(\n                    \"Attempt %s failed. Retrying in %s seconds...\", i, sleep_rate\n                )\n                time.sleep(sleep_rate)\n        return False\n"
  },
  {
    "path": "tests/common/mocks.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains mocking utils testing purposes.\"\"\"\nimport re\nimport unittest\nfrom contextlib import contextmanager\nfrom typing import Any, Generator\nfrom unittest.mock import MagicMock\n\n\nclass AnyStringWith(str):\n    \"\"\"\n    Helper class to assert calls of mocked method with string arguments.\n\n    It will use string inclusion as equality comparator.\n    \"\"\"\n\n    def __eq__(self, other):\n        \"\"\"Check equality.\"\"\"\n        return self in other\n\n\nclass RegexComparator(str):\n    \"\"\"\n    Helper class to assert calls of mocked method with string arguments.\n\n    It will use regex matching as equality comparator.\n    \"\"\"\n\n    def __eq__(self, other):\n        \"\"\"Check equality.\"\"\"\n        regex = re.compile(str(self), re.MULTILINE | re.DOTALL)\n        s = str(other)\n        return bool(regex.search(s))\n\n\n@contextmanager\ndef ctx_mock_Popen() -> Generator[Any, Any, Any]:\n    \"\"\"\n    Mock subprocess.Popen.\n\n    Act as context manager.\n\n    :return: mock object.\n    \"\"\"\n    return_value = MagicMock()\n    return_value.communicate.return_value = (MagicMock(), MagicMock())\n\n    with unittest.mock.patch(\"subprocess.Popen\", return_value=return_value) as mocked:\n        yield mocked\n"
  },
  {
    "path": "tests/common/oef_search_pluto_scripts/launch.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This test module contains the launch script for the oef.\"\"\"\n\nfrom __future__ import print_function\n\nimport argparse\nimport json\nimport os\nimport subprocess  # nosec\nimport sys\n\n\ndef run(cmd):\n    \"\"\"Run.\"\"\"\n    print(\" \".join(cmd))\n    c = subprocess.Popen(cmd)  # nosec\n    c.wait()\n    return c.returncode\n\n\ndef error(*x):\n    \"\"\"Error.\"\"\"\n    print(\"\".join([str(xx) for xx in x]), file=sys.stderr)\n\n\ndef fail(*x):\n    \"\"\"Fail.\"\"\"\n    error(x)\n    exit(1)\n\n\ndef pull_image(run_sudo, img):\n    \"\"\"Pull the image.\"\"\"\n    c = []\n\n    if run_sudo:\n        c += [\"sudo\"]\n    c += [\n        \"docker\",\n        \"pull\",\n        img,\n    ]\n    r = run(c)\n    if r != 0:\n        error(\"can't pull \" + img)\n\n\ndef parse_command(j):\n    \"\"\"Parse the command.\"\"\"\n    cmd = []\n    used_keys = [\"positional_args\"]\n    for key in j[\"positional_args\"]:\n        cmd.append(str(j[key]))\n        used_keys.append(key)\n    for key in j:\n        if key in used_keys:\n            continue\n        cmd.extend([\"--\" + key, str(j[key])])\n    return cmd\n\n\ndef launch_job(args, j):\n    \"\"\"Launch the job.\"\"\"\n    img = j[\"image\"]\n    if \"/\" in img:\n        pull_image(args.sudo, img)\n\n    c = []\n    if args.sudo:\n        c += [\"sudo\"]\n    c += [\"docker\", \"run\"]\n    if args.background:\n        c += [\"-d\"]\n    else:\n        c += [\"-it\"]\n    work_dir = os.path.abspath(os.path.dirname(__file__))\n    project_dir = os.path.abspath(os.path.join(work_dir, \"..\"))\n    print(\"Work dir: \", work_dir)\n    c += [\"-v\", work_dir + \":/config\", \"-v\", project_dir + \"/data/oef-logs:/logs\"]\n\n    for arg in j[\"params\"]:\n        c += map(lambda x: x.replace(\"$PWD\", project_dir), arg)\n\n    c += [img]\n\n    cmd_config = j[\"cmd\"].get(args.cmd, None)\n    if not cmd_config:\n        fail(\"Selected command {} not configured in config file!\".format(args.cmd))\n\n    c.extend(parse_command(cmd_config))\n    extra_args = [a for a in args.rest if a != \"--\"]\n    print(\"Extra arguments to search: \", extra_args)\n    c += extra_args\n    r = run(c)\n    if r != 0:\n        fail(\"can't launch \" + img)\n\n\ndef main(args):\n    \"\"\"Run the script.\"\"\"\n    with open(args.config, \"r\") as f:\n        config = json.load(f)\n    launch_job(args, config)\n\n\nif __name__ == \"__main__\":\n    parser = argparse.ArgumentParser()\n    parser.add_argument(\n        \"-c\", \"--config\", required=True, type=str, help=\"Publish the image to GCR\"\n    )\n    parser.add_argument(\n        \"--sudo\", required=False, action=\"store_true\", help=\"Run docker as root\"\n    )\n    parser.add_argument(\n        \"--background\",\n        required=False,\n        action=\"store_true\",\n        help=\"Run image in background.\",\n    )\n    parser.add_argument(\n        \"--cmd\",\n        required=False,\n        type=str,\n        default=\"oef-search\",\n        help=\"The available commands are defined in the config file ('cmd' dictionary) \",\n    )\n    parser.add_argument(\"rest\", nargs=argparse.REMAINDER)\n    main(parser.parse_args())\n"
  },
  {
    "path": "tests/common/oef_search_pluto_scripts/launch_config.json",
    "content": "{\n  \"image\": \"fetchai/oef-search:0.7\",\n  \"params\": [\n    [\n      \"--rm\",\n      \"--cap-add\",\n      \"sys_ptrace\",\n      \"-p\",\n      \"20000:20000\",\n      \"-p\",\n      \"10000:10000\",\n      \"-p\",\n      \"40000:40000\",\n      \"-p\",\n      \"7500:7500\"\n    ]\n  ],\n  \"cmd\": {\n    \"oef-search\": {\n      \"positional_args\": [\"config_file\"],\n      \"config_file\": \"/config/node_config.json\"\n    }\n  }\n}"
  },
  {
    "path": "tests/common/oef_search_pluto_scripts/node_config.json",
    "content": "{\n  \"host\": \"127.0.0.1\",\n  \"search_key\": \"London-search\",\n  \"search_port\": 20000,\n  \"search_broadcast_cache_lifetime_sec\": 6,\n  \"director_port\": 40000,\n  \"html_dir\": \"api/src/resources/website\",\n  \"prometheus_api_path\": \"/metrics\",\n  \"prometheus_log_file\": \"./fetch-logs/core-vars.txt\",\n  \"search_prometheus_log_file\": \"./fetch-logs/search-vars.txt\",\n  \"http_port\": 7500,\n  \"log_dir\": \"./fetch-logs/\",\n  \"search_log\": \"/logs/search.log\",\n  \"core_log\": \"/logs/core.log\",\n  \"ssl_certificate\": \"\",\n  \"core\": {\n    \"core_binary\": \"/oef-mt-core/bazel-bin/mt-core/main/src/cpp/app\",\n     \"config\": {\n      \"core_key\": \"CoreKey\",\n      \"core_uri\": \"tcp://127.0.0.1:10000\",\n      \"ws_uri\": \"\",\n      \"ssl_uri\": \"ssl://127.0.0.1:15000\",\n      \"white_list_file\":\"\",\n      \"core_cert_pk_file\": \"/app/ssl/core.pem\",\n      \"core_pubkey_file\": \"/app/ssl/core_pub.pem\",\n      \"tmp_dh_file\": \"/app/ssl/dh2048.pem\",\n      \"search_uri\": \"tcp://127.0.0.1:20000\",\n      \"tasks_thread_count\": 10,\n      \"comms_thread_count\": 10,\n      \"karma_policy\": {\n      },\n      \"prometheus_log_interval\": 3,\n      \"prometheus_log_file\": \"/logs/core-vars.txt\"\n    }\n  },\n  \"search_peers\": [\"KEY:HOST:PORT\"],\n   \"bootstrap\": {\n    \"bootstrap-url\": \"\",\n    \"network-name\": \"oeftestnet\",\n    \"client-name\": \"oef-node\",\n    \"client-version\": \"0.1.0\",\n    \"remote-host\": \"$EXTERNAL_HOSTNAME\",\n    \"remote-port\": -1,\n    \"private-key\": \"\",\n    \"user-token\": \"\",\n    \"notify-period-in-sec\": 180\n  },\n  \"state\": {\n    \"file\": \"/storage/state.json\",\n    \"fields\": [\"bootstrap:private-key\"]\n  },\n  \"search_config\": {\n    \"search_prometheus_log_file\": \"/logs/search-vars.txt\",\n    \"daps\": {\n      \"network_search\": {\n        \"class\": \"DapERNetwork\",\n        \"config\": {\n          \"module\": \"dap_e_r_network.src.python.DapERNetwork\",\n          \"structure\": {\n            \"locations\": {\n            }\n          }\n        }\n      },\n      \"geo_search\": {\n        \"class\": \"DapGeo\",\n        \"config\": {\n          \"module\": \"dap_2d_geo.src.python.DapGeo\",\n          \"structure\": {\n            \"location\": {\n              \"location.location\": {\n                \"type\": \"location\",\n                \"options\": [\n                  \"plane\",\n                  \"os-grid\"\n                ]\n              },\n              \"latlon\": {\n                \"latlon.location\": {\n                  \"type\": \"location\",\n                  \"options\": [\n                  ]\n                }\n              }\n            }\n          }\n        }\n      },\n      \"address_registry\": {\n        \"class\": \"AddressRegistry\",\n        \"config\": {\n          \"module\": \"dap_in_memory.src.python.AddressRegistry\",\n          \"structure\": {\n            \"address_registry_table\": {\n              \"address_field\": \"address\"\n            }\n          }\n        }\n      },\n      \"in_memory_dap\": {\n        \"class\": \"exe.InMemoryDap\",\n        \"config\": {\n          \"binary\": \"cpp_dap_in_memory/src/cpp/cpp_dap_in_memory_server\",\n          \"host\": \"127.0.0.1\",\n          \"port\": 30000,\n          \"structure\": {\n            \"value_table\": {\n              \"field\": \"string\"\n            }\n          }\n        }\n      },\n      \"attrs\": {\n        \"class\": \"DapAttributeStore\",\n        \"config\": {\n          \"module\": \"dap_attribute_store.src.python.DapAttributeStore\",\n          \"structure\": {\n          },\n          \"options\": [\n            \"lazy\"\n          ]\n        }\n      },\n      \"uniquer\": {\n        \"class\": \"DapUniquer\",\n        \"config\": {\n          \"module\": \"uniqer.src.python.DapUniquer\",\n          \"structure\": {\n          }\n        }\n      },\n      \"data_model_searcher\": {\n        \"class\": \"SearchEngine\",\n        \"config\": {\n          \"module\": \"ai_search_engine.src.python.SearchEngine\",\n          \"structure\": {\n            \"data_model_table\": {\n              \"data_model\": \"embedding\"\n            }\n          }\n        }\n      }\n    },\n    \"attribute_tbfld_map\": {\n      \"latlon\": [\"latlon\", \"latlon\"],\n      \"NETWORK_ADDRESS\": [\"address_registry_table\", \"address_field\"]\n    }\n  }\n}"
  },
  {
    "path": "tests/common/pexpect_popen.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Wrapper for Pexpect to use in tests.\"\"\"\nimport os\nimport platform\nimport signal\nimport sys\nimport time\nfrom typing import List, Optional, Union\n\nfrom pexpect.exceptions import EOF, TIMEOUT  # type: ignore\nfrom pexpect.popen_spawn import PopenSpawn  # type: ignore\n\nfrom aea.helpers.base import send_control_c\n\n\nclass PexpectWrapper(PopenSpawn):\n    \"\"\"Utility class to make aea cli test easier.\"\"\"\n\n    def __init__(self, *args, **kwargs):\n        \"\"\"Init pexpect.spawn.\"\"\"\n        if platform.system() != \"Windows\":\n            kwargs[\"preexec_fn\"] = os.setsid\n\n        super().__init__(*args, **kwargs)\n\n    def control_c(self) -> None:\n        \"\"\"Send control c to process started.\"\"\"\n        time.sleep(0.1)  # sometimes it's better to wait a bit\n        send_control_c(self.proc, True)\n\n    @property\n    def returncode(self) -> Optional[Union[int, str]]:\n        \"\"\"Get return code of finished process.\"\"\"\n        return self.proc.poll()  # type: ignore\n\n    def wait_to_complete(self, timeout: float = 5) -> None:\n        \"\"\"Wait process to complete.\n\n        Terminate automatically after timeout.\n        Set returncode to terminated if terminated.\n\n        :param timeout: how many seconds wait process to finish before kill.\n        \"\"\"\n        if self.proc.poll() is not None:  # type: ignore\n            return\n\n        start_time = time.time()\n\n        while start_time + timeout > time.time() and self.proc.poll() is None:  # type: ignore\n            time.sleep(0.001)\n\n        if self.proc.poll() is None:  # type: ignore\n            self.terminate(force=True)\n            self.wait()\n            self.exitstatus = \"Terminated!\"  # type: ignore\n\n    @classmethod\n    def aea_cli(cls, args, **kwargs) -> \"PexpectWrapper\":\n        \"\"\"Start aea.cli.\n\n        :param args: list of arguments for aea.cli.\n\n        :return: PexpectWrapper\n        \"\"\"\n        return cls(\n            [sys.executable, \"-m\", \"aea.cli\", \"-v\", \"DEBUG\", *args],\n            env=os.environ.copy(),\n            encoding=\"utf-8\",\n            logfile=sys.stdout,\n            **kwargs,\n        )\n\n    def expect_all(\n        self, pattern_list: List[str], timeout: float = 10, strict: bool = True\n    ) -> None:\n        \"\"\"\n        Wait for all patterns appear in process output.\n\n        :param pattern_list: list of string to expect\n        :param timeout: timeout in seconds\n        :param strict: if non strict, it allows regular expression\n\n        :return: None\n        \"\"\"\n        pattern_list = list(pattern_list)\n\n        start_time = time.time()\n        while pattern_list:\n            time_spent = time.time() - start_time\n            if time_spent > timeout:\n                raise TIMEOUT(timeout)\n            if strict:\n                idx = self.expect_exact(pattern_list, timeout - time_spent)\n            else:\n                idx = self.expect(pattern_list, timeout - time_spent)\n            pattern_list.pop(idx)\n\n    def wait_eof(self, timeout: float = 10) -> None:\n        \"\"\"\n        Wait for EOF of the process.\n\n        :param timeout: timeout in seconds\n\n        :return: None\n        \"\"\"\n        self.expect(EOF, timeout=timeout)\n\n    def terminate(self, *args, **kwargs) -> None:\n        \"\"\"Terminate process.\"\"\"\n        if self.proc.poll() is None:\n            self.kill(signal.SIGTERM)\n"
  },
  {
    "path": "tests/common/utils.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains some utils for testing purposes.\"\"\"\nimport asyncio\nimport filecmp\nimport os\nimport subprocess  # nosec\nimport sys\nimport time\nfrom contextlib import contextmanager\nfrom functools import wraps\nfrom threading import Thread\nfrom typing import Any, Callable, List, Optional, Set, Tuple, Type, Union\n\nimport pytest\n\nfrom aea.aea import AEA\nfrom aea.configurations.base import PublicId\nfrom aea.mail.base import Envelope\nfrom aea.protocols.base import Message\nfrom aea.skills.base import Behaviour, Handler\n\nfrom packages.fetchai.protocols.default.message import DefaultMessage\n\nfrom tests.conftest import ROOT_DIR\n\n\nDEFAULT_SLEEP = 0.0001\nDEFAULT_TIMEOUT = 3\n\n\nclass TimeItResult:\n    \"\"\"Class to store execution time for timeit_context.\"\"\"\n\n    def __init__(self):\n        \"\"\"Init with time passed = -1.\"\"\"\n        self.time_passed = -1\n\n\n@contextmanager\ndef timeit_context():\n    \"\"\"\n    Context manager to measure execution time of code in context.\n\n    :return TimeItResult\n\n    example:\n    with timeit_context() as result:\n        do_long_code()\n    print(\"Long code takes \", result.time_passed)\n    \"\"\"\n    result = TimeItResult()\n    started_time = time.time()\n    try:\n        yield result\n    finally:\n        result.time_passed = time.time() - started_time\n\n\nclass AeaTool:\n    \"\"\"\n    AEA test wrapper tool.\n\n    To make testing AEA instances easier\n    \"\"\"\n\n    def __init__(self, aea: AEA):\n        \"\"\"\n        Instantiate AeaTool.\n\n        :param aea: AEA instance to wrap for tests.\n        \"\"\"\n        self.aea = aea\n\n    def setup(self) -> \"AeaTool\":\n        \"\"\"Call AEA._start_setup.\"\"\"\n        self.aea.setup()\n        return self\n\n    def teardown(self) -> \"AeaTool\":\n        \"\"\"Call AEA.teardown.\"\"\"\n        self.aea.teardown()\n        return self\n\n    def wait_outbox_empty(\n        self, sleep: float = DEFAULT_SLEEP, timeout: float = DEFAULT_TIMEOUT\n    ) -> \"AeaTool\":\n        \"\"\"\n        Wait till agent's outbox consumed completely.\n\n        :return: AeaTool\n        \"\"\"\n        start_time = time.time()\n        while not self.aea.outbox.empty():\n            time.sleep(sleep)\n            if time.time() - start_time > timeout:\n                raise Exception(\"timeout\")\n        return self\n\n    def wait_inbox(\n        self, sleep: float = DEFAULT_SLEEP, timeout: float = DEFAULT_TIMEOUT\n    ) -> \"AeaTool\":\n        \"\"\"\n        Wait till something appears on agents inbox and spin loop.\n\n        :return: AeaTool\n        \"\"\"\n        start_time = time.time()\n        while self.aea.inbox.empty():\n            time.sleep(sleep)\n            if time.time() - start_time > timeout:\n                raise Exception(\"timeout\")\n        return self\n\n    def handle_envelope(self, envelope) -> \"AeaTool\":\n        \"\"\"\n        Run AEA.react once to process inbox messages.\n\n        :return: AeaTool\n        \"\"\"\n        self.aea.handle_envelope(envelope)\n        return self\n\n    def act_one(self) -> \"AeaTool\":\n        \"\"\"\n        Run AEA.act once to process behaviours act.\n\n        :return: AeaTool\n        \"\"\"\n        self.aea.act()\n        return self\n\n    @classmethod\n    def dummy_default_message(\n        cls,\n        dialogue_reference: Tuple[str, str] = (\"\", \"\"),\n        message_id: int = 1,\n        target: int = 0,\n        performative: DefaultMessage.Performative = DefaultMessage.Performative.BYTES,\n        content: Union[str, bytes] = \"hello world!\",\n    ) -> Message:\n        \"\"\"\n        Construct simple message, all arguments are optional.\n\n        :return: Message\n        \"\"\"\n        if isinstance(content, str):\n            content = content.encode(\"utf-8\")\n\n        return DefaultMessage(\n            dialogue_reference=dialogue_reference,\n            message_id=message_id,\n            target=target,\n            performative=performative,\n            content=content,\n        )\n\n    @classmethod\n    def dummy_envelope(\n        cls,\n        to: str = \"test\",\n        sender: str = \"test\",\n        protocol_specification_id: PublicId = DefaultMessage.protocol_specification_id,\n        message: Message = None,\n    ) -> Envelope:\n        \"\"\"\n        Create envelope, if message is not passed use .dummy_message method.\n\n        :return: Envelope\n        \"\"\"\n        message = message or cls.dummy_default_message()\n        message.sender = sender\n        message.to = to\n        return Envelope(\n            to=to,\n            sender=sender,\n            protocol_specification_id=protocol_specification_id,\n            message=message,\n        )\n\n    def put_inbox(self, envelope: Envelope) -> None:\n        \"\"\"Add an envelope to agent's inbox.\"\"\"\n        self.aea.runtime.multiplexer.in_queue.put(envelope)\n\n    def is_inbox_empty(self) -> bool:\n        \"\"\"Check there is no messages in inbox.\"\"\"\n        return self.aea.runtime.multiplexer.in_queue.empty()\n\n    def set_execution_timeout(self, timeout: float) -> None:\n        \"\"\"Set act/handle exeution timeout for AEE.\n\n        :param timeout: amount of time to limit single act/handle to execute.\n        \"\"\"\n        self.aea._execution_timeout = timeout\n\n    def stop(self) -> None:\n        \"\"\"Stop AEA instance.\"\"\"\n        self.aea.stop()\n\n\ndef make_handler_cls_from_funcion(func: Callable) -> Type[Handler]:\n    \"\"\"Make Handler class with handler function call `func`.\n\n    :param func: function or callable to be called from Handler.handle method\n    :return: Handler class\n    \"\"\"\n    # pydocstyle: ignore # case conflicts with black # noqa: E800\n    class TestHandler(Handler):\n        SUPPORTED_PROTOCOL = DefaultMessage.protocol_id\n\n        def setup(self):\n            pass\n\n        def teardown(self):\n            pass\n\n        def handle(self, msg):\n            func(self)\n\n    return TestHandler\n\n\ndef make_behaviour_cls_from_funcion(func: Callable) -> Type[Behaviour]:\n    \"\"\"Make Behaviour class with act function call `func`.\n\n    :param func: function or callable to be called from Behaviour.act method\n    :return: Behaviour class\n    \"\"\"\n    # pydocstyle: ignore # case conflicts with black # noqa: E800\n    class TestBehaviour(Behaviour):\n        def act(self) -> None:\n            func(self)\n\n        def setup(self):\n            self._completed = False\n\n        def teardown(self):\n            pass\n\n    return TestBehaviour\n\n\ndef run_in_root_dir(fn) -> Callable:\n    \"\"\"\n    Chdir to ROOT DIR and return back during tests.\n\n    Decorator.\n\n    :param fn: function to decorate\n\n    :return: wrapped function\n    \"\"\"\n    # pydocstyle: ignore # case conflicts with black # noqa: E800\n    @wraps(fn)\n    def wrap(*args, **kwargs) -> Any:\n        \"\"\"Do a chdir.\"\"\"\n        cwd = os.getcwd()\n        os.chdir(ROOT_DIR)\n        try:\n            return fn(*args, **kwargs)\n        finally:\n            os.chdir(cwd)\n\n    return wrap\n\n\n@contextmanager\ndef run_in_thread(fn, timeout=10, on_exit=None, **kwargs):\n    \"\"\"Run a function in contextmanager and test and awaits it completed.\"\"\"\n    thread = Thread(target=fn, **kwargs)\n    thread.daemon = True\n    thread.start()\n    try:\n        yield\n    finally:\n        if on_exit:\n            on_exit()\n        thread.join(timeout)\n        if thread.is_alive():\n            raise Exception(\"Thread was not stopped!\")\n\n\ndef wait_for_condition(condition_checker, timeout=2, error_msg=\"Timeout\", period=0.001):\n    \"\"\"Wait for condition occures in selected timeout.\"\"\"\n    start_time = time.time()\n\n    while not condition_checker():\n        time.sleep(period)\n        if time.time() > start_time + timeout:\n            raise TimeoutError(error_msg)\n\n\nasync def wait_for_condition_async(\n    condition_checker, timeout=2, error_msg=\"Timeout\", period=0.001\n):  # pragma: nocover\n    \"\"\"Wait for condition occures in selected timeout.\"\"\"\n    start_time = time.time()\n\n    while not condition_checker():\n        await asyncio.sleep(period)\n        if time.time() > start_time + timeout:\n            raise TimeoutError(error_msg)\n\n\ndef are_dirs_equal(\n    dir1: Union[str, os.PathLike],\n    dir2: Union[str, os.PathLike],\n    ignore: Optional[List[str]] = None,\n) -> bool:\n    \"\"\"\n    Compare the content of two directories, recursively.\n\n    :param dir1: the left operand.\n    :param dir2: the right operand.\n    :param ignore: is a list of names to ignore (see dircmp docs regarding 'ignore').\n    :return: True if the directories are equal, False otherwise.\n    \"\"\"\n    ignore = ignore or None\n    left_only, right_only, diff = dircmp_recursive(\n        filecmp.dircmp(dir1, dir2, ignore=ignore)\n    )\n    return left_only == right_only == diff == set()\n\n\ndef dircmp_recursive(dircmp_obj: filecmp.dircmp) -> Tuple[Set[str], Set[str], Set[str]]:\n    \"\"\"\n    Compare the content of two directories, recursively.\n\n    :param dircmp_obj: the filecmp.dircmp object.\n    :return: three sets:\n     - the set of files that are only in the left operand\n     - the set of files that are only in the right operand\n     - the set of files in both operands, but that differ.\n    \"\"\"\n\n    def _dircmp_recursive(\n        dircmp_obj: filecmp.dircmp, prefix: str = \"\"\n    ) -> Tuple[Set[str], Set[str], Set[str]]:\n        \"\"\"\n        Helper private function that also accepts the 'prefix' parameter.\n\n        It is used to keep track of the path prefix during the recursive calls.\n        \"\"\"\n\n        def join_with_prefix(suffix: str) -> str:\n            return os.path.join(prefix, suffix)\n\n        left_only: Set[str] = set(map(join_with_prefix, dircmp_obj.left_only))\n        right_only: Set[str] = set(map(join_with_prefix, dircmp_obj.right_only))\n        diff_files: Set[str] = set(map(join_with_prefix, dircmp_obj.diff_files))\n        for name, sub_dircmp_obj in dircmp_obj.subdirs.items():\n            subprefix = join_with_prefix(name)\n            subleft, subright, subdiff = _dircmp_recursive(\n                sub_dircmp_obj, prefix=subprefix\n            )\n            left_only.update(subleft)\n            right_only.update(subright)\n            diff_files.update(subdiff)\n        return left_only, right_only, diff_files\n\n    return _dircmp_recursive(dircmp_obj, \"\")\n\n\ndef run_aea_subprocess(*args, cwd: str = \".\") -> Tuple[subprocess.Popen, str, str]:\n    \"\"\"\n    Run subprocess, bypassing ClickRunner.invoke.\n\n    The reason is that for some reason ClickRunner.invoke doesn't capture\n    well the stdout/stderr of nephew processes - children processes of children processes.\n    \"\"\"\n    result = subprocess.Popen(  # type: ignore  # nosec\n        [sys.executable, \"-m\", \"aea.cli\", *args],\n        stdout=subprocess.PIPE,\n        stderr=subprocess.PIPE,\n        cwd=cwd,\n    )\n    result.wait()\n    stdout, stderr = result.communicate()\n    return result, stdout.decode(\"utf-8\"), stderr.decode(\"utf-8\")\n\n\n@pytest.mark.integration\nclass UseOef:  # pylint: disable=too-few-public-methods\n    \"\"\"Inherit from this class to launch an OEF node.\"\"\"\n\n    @pytest.fixture(autouse=True)\n    def _start_oef_node(self, network_node: Callable) -> None:\n        \"\"\"Start an oef node.\"\"\"\n"
  },
  {
    "path": "tests/conftest.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Conftest module for Pytest.\"\"\"\nimport difflib\nimport inspect\nimport logging\nimport os\nimport platform\nimport random\nimport shutil\nimport socket\nimport string\nimport sys\nimport tempfile\nimport threading\nimport time\nfrom contextlib import contextmanager\nfrom functools import WRAPPER_ASSIGNMENTS, wraps\nfrom pathlib import Path\nfrom types import FunctionType, MethodType\nfrom typing import (\n    Callable,\n    Dict,\n    Generator,\n    List,\n    Optional,\n    Sequence,\n    Tuple,\n    Union,\n    cast,\n)\nfrom unittest.mock import MagicMock, patch\n\nimport docker as docker\nimport gym\nimport pytest\nimport pytest_asyncio\nfrom _pytest.monkeypatch import MonkeyPatch  # type: ignore\nfrom aea_ledger_cosmos import CosmosCrypto\nfrom aea_ledger_ethereum import EthereumCrypto\nfrom aea_ledger_fetchai import FetchAIApi, FetchAICrypto, FetchAIFaucetApi\nfrom cosmpy.aerial.client import LedgerClient, NetworkConfig\nfrom cosmpy.aerial.wallet import LocalWallet\nfrom cosmpy.crypto.address import Address as CosmpyAddress\nfrom cosmpy.crypto.keypairs import PrivateKey\n\nfrom aea import AEA_DIR\nfrom aea.aea import AEA\nfrom aea.aea_builder import AEABuilder\nfrom aea.cli.utils.config import _init_cli_config\nfrom aea.common import Address\nfrom aea.configurations.base import ComponentType, ConnectionConfig, ContractConfig\nfrom aea.configurations.base import DEFAULT_AEA_CONFIG_FILE as AGENT_YAML\nfrom aea.configurations.base import DEFAULT_CONNECTION_CONFIG_FILE as CONNECTION_YAML\nfrom aea.configurations.base import DEFAULT_CONTRACT_CONFIG_FILE as CONTRACT_YAML\nfrom aea.configurations.base import DEFAULT_PROTOCOL_CONFIG_FILE as PROTOCOL_YAML\nfrom aea.configurations.base import DEFAULT_SKILL_CONFIG_FILE as SKILL_YAML\nfrom aea.configurations.base import PublicId\nfrom aea.configurations.constants import DEFAULT_LEDGER, PRIVATE_KEY_PATH_SCHEMA\nfrom aea.configurations.loader import load_component_configuration\nfrom aea.connections.base import Connection\nfrom aea.contracts.base import Contract, contract_registry\nfrom aea.crypto.base import Crypto\nfrom aea.crypto.ledger_apis import (\n    COSMOS_DEFAULT_ADDRESS,\n    DEFAULT_LEDGER_CONFIGS,\n    ETHEREUM_DEFAULT_ADDRESS,\n    ETHEREUM_DEFAULT_CHAIN_ID,\n    ETHEREUM_DEFAULT_CURRENCY_DENOM,\n    FETCHAI_DEFAULT_ADDRESS,\n)\nfrom aea.crypto.registries import ledger_apis_registry, make_crypto, make_ledger_api\nfrom aea.crypto.wallet import CryptoStore\nfrom aea.exceptions import enforce\nfrom aea.helpers.base import CertRequest, SimpleId, cd\nfrom aea.identity.base import Identity\nfrom aea.test_tools.click_testing import CliRunner as ImportedCliRunner\nfrom aea.test_tools.constants import DEFAULT_AUTHOR\nfrom aea.test_tools.test_cases import BaseAEATestCase\n\nfrom packages.fetchai.connections.local.connection import LocalNode, OEFLocalConnection\nfrom packages.fetchai.connections.oef.connection import OEFConnection\nfrom packages.fetchai.connections.p2p_libp2p.check_dependencies import build_node\nfrom packages.fetchai.connections.p2p_libp2p.connection import (\n    LIBP2P_NODE_MODULE_NAME,\n    MultiAddr,\n    P2PLibp2pConnection,\n    POR_DEFAULT_SERVICE_ID,\n)\nfrom packages.fetchai.connections.p2p_libp2p_client.connection import (\n    P2PLibp2pClientConnection,\n)\nfrom packages.fetchai.connections.p2p_libp2p_mailbox.connection import (\n    P2PLibp2pMailboxConnection,\n)\nfrom packages.fetchai.connections.stub.connection import StubConnection\nfrom packages.fetchai.connections.tcp.tcp_client import TCPClientConnection\nfrom packages.fetchai.connections.tcp.tcp_server import TCPServerConnection\n\nfrom tests.common.docker_image import (\n    DockerImage,\n    FetchLedgerDockerImage,\n    GanacheDockerImage,\n    OEFSearchDockerImage,\n    SOEFDockerImage,\n)\nfrom tests.data.dummy_connection.connection import DummyConnection  # type: ignore\n\n\nlogger = logging.getLogger(__name__)\n\nCliRunner = ImportedCliRunner\n\nCUR_PATH = os.path.dirname(inspect.getfile(inspect.currentframe()))  # type: ignore\nROOT_DIR = os.path.join(CUR_PATH, \"..\")\nCLI_LOG_OPTION = [\"-v\", \"OFF\"]\n\nAUTHOR = DEFAULT_AUTHOR\nCONFIGURATION_SCHEMA_DIR = os.path.join(AEA_DIR, \"configurations\", \"schemas\")\nAGENT_CONFIGURATION_SCHEMA = os.path.join(\n    CONFIGURATION_SCHEMA_DIR, \"aea-config_schema.json\"\n)\nSKILL_CONFIGURATION_SCHEMA = os.path.join(\n    CONFIGURATION_SCHEMA_DIR, \"skill-config_schema.json\"\n)\nCONNECTION_CONFIGURATION_SCHEMA = os.path.join(\n    CONFIGURATION_SCHEMA_DIR, \"connection-config_schema.json\"\n)\nPROTOCOL_CONFIGURATION_SCHEMA = os.path.join(\n    CONFIGURATION_SCHEMA_DIR, \"protocol-config_schema.json\"\n)\nCONTRACT_CONFIGURATION_SCHEMA = os.path.join(\n    CONFIGURATION_SCHEMA_DIR, \"contract-config_schema.json\"\n)\nPROTOCOL_SPEC_CONFIGURATION_SCHEMA = os.path.join(\n    CONFIGURATION_SCHEMA_DIR, \"protocol-specification_schema.json\"\n)\n\nDUMMY_ENV = gym.GoalEnv  # type: ignore\n\n# URL to local Ganache instance\nDEFAULT_GANACHE_ADDR = \"http://127.0.0.1\"\nDEFAULT_GANACHE_PORT = 8545\nDEFAULT_GANACHE_CHAIN_ID = 1337\n\n# URL to local Fetch ledger instance\nDEFAULT_FETCH_DOCKER_IMAGE_TAG = \"fetchai/fetchd:0.10.2\"\nDEFAULT_FETCH_LEDGER_ADDR = \"http://127.0.0.1\"\nDEFAULT_FETCH_LEDGER_RPC_PORT = 26657\nDEFAULT_FETCH_LEDGER_REST_PORT = 1317\nDEFAULT_FETCH_ADDR_REMOTE = \"https://rest-dorado.fetch.ai:443\"\nDEFAULT_FETCH_MNEMONIC = \"gap bomb bulk border original scare assault pelican resemble found laptop skin gesture height inflict clinic reject giggle hurdle bubble soldier hurt moon hint\"\nDEFAULT_MONIKER = \"test-node\"\nDEFAULT_FETCH_CHAIN_ID = \"dorado-1\"\nDEFAULT_GENESIS_ACCOUNT = \"validator\"\nDEFAULT_DENOMINATION = \"atestfet\"\nFETCHD_INITIAL_TX_SLEEP = 6\n\nCOSMOS_PRIVATE_KEY_FILE_CONNECTION = \"cosmos_connection_private_key.txt\"\nFETCHAI_PRIVATE_KEY_FILE_CONNECTION = \"fetchai_connection_private_key.txt\"\n\nCOSMOS_PRIVATE_KEY_FILE = PRIVATE_KEY_PATH_SCHEMA.format(CosmosCrypto.identifier)\nETHEREUM_PRIVATE_KEY_FILE = PRIVATE_KEY_PATH_SCHEMA.format(EthereumCrypto.identifier)\nFETCHAI_PRIVATE_KEY_FILE = PRIVATE_KEY_PATH_SCHEMA.format(FetchAICrypto.identifier)\n\nETHEREUM_PRIVATE_KEY_TWO_FILE = \"ethereum_private_key_two.txt\"\n\nDEFAULT_AMOUNT = 1000000000000000000000\nGAS_PRICE_API_KEY = \"\"\n\n# private keys with value on testnet\nCOSMOS_PRIVATE_KEY_PATH = os.path.join(\n    ROOT_DIR, \"tests\", \"data\", COSMOS_PRIVATE_KEY_FILE\n)\nETHEREUM_PRIVATE_KEY_PATH = os.path.join(\n    ROOT_DIR, \"tests\", \"data\", ETHEREUM_PRIVATE_KEY_FILE\n)\nETHEREUM_PRIVATE_KEY_TWO_PATH = os.path.join(\n    ROOT_DIR, \"tests\", \"data\", ETHEREUM_PRIVATE_KEY_TWO_FILE\n)\nFETCHAI_PRIVATE_KEY_PATH = os.path.join(\n    ROOT_DIR, \"tests\", \"data\", FETCHAI_PRIVATE_KEY_FILE\n)\nDEFAULT_PRIVATE_KEY_PATH = COSMOS_PRIVATE_KEY_PATH\nFUNDED_ETH_PRIVATE_KEY_1 = (\n    \"0xa337a9149b4e1eafd6c21c421254cf7f98130233595db25f0f6f0a545fb08883\"\n)\nFUNDED_ETH_PRIVATE_KEY_2 = (\n    \"0x04b4cecf78288f2ab09d1b4c60219556928f86220f0fb2dcfc05e6a1c1149dbf\"\n)\nFUNDED_ETH_PRIVATE_KEY_3 = (\n    \"0x6F611408F7EF304947621C51A4B7D84A13A2B9786E9F984DA790A096E8260C64\"\n)\nNON_FUNDED_COSMOS_PRIVATE_KEY_1 = (\n    \"81b0352f99a08a754b56e529dda965c4ce974edb6db7e90035e01ed193e1b7bc\"\n)\nNON_FUNDED_FETCHAI_PRIVATE_KEY_1 = (\n    \"b6ef49c3078f300efe2d4480e179362bd39f20cbb2087e970c8f345473661aa5\"\n)\nFUNDED_FETCHAI_PRIVATE_KEY_1 = (\n    \"bbaef7511f275dc15f47436d14d6d3c92d4d01befea073d23d0c2750a46f6cb3\"\n)\nFUNDED_FETCHAI_PRIVATE_KEY_2 = (\n    \"9d6459d1f93dd153335291af940f6b5224a34a9a1e1062e2158a45fa4901ed3f\"\n)\n\n# addresses with no value on testnet\nCOSMOS_ADDRESS_ONE = \"cosmos1z4ftvuae5pe09jy2r7udmk6ftnmx504alwd5qf\"\nCOSMOS_ADDRESS_TWO = \"cosmos1gssy8pmjdx8v4reg7lswvfktsaucp0w95nk78m\"\nETHEREUM_ADDRESS_ONE = \"0x46F415F7BF30f4227F98def9d2B22ff62738fD68\"\nETHEREUM_ADDRESS_TWO = \"0x7A1236d5195e31f1F573AD618b2b6FEFC85C5Ce6\"\nFETCHAI_ADDRESS_ONE = \"fetch1paqxtqnfh7da7z9c05l3y3lahe8rhd0nm0jk98\"\nFETCHAI_ADDRESS_TWO = \"fetch19j4dc3e6fgle98pj06l5ehhj6zdejcddx7teac\"\nFUNDED_FETCHAI_ADDRESS_ONE = \"fetch1k9dns2fd74644g0q9mfpsmfeqg0h2ym2cm6wdh\"\nFUNDED_FETCHAI_ADDRESS_TWO = \"fetch1x2vfp8ec2yk8nnlzn52agflpmpwtucm6yj2hw4\"\n\n# P2P addresses\nCOSMOS_P2P_ADDRESS = \"/dns4/127.0.0.1/tcp/9000/p2p/16Uiu2HAmAzvu5uNbcnD2qaqrkSULhJsc6GJUg3iikWerJkoD72pr\"  # relates to NON_FUNDED_COSMOS_PRIVATE_KEY_1\nFETCHAI_P2P_ADDRESS = \"/dns4/127.0.0.1/tcp/9000/p2p/16Uiu2HAmLBCAqHL8SuFosyDhAKYsLKXBZBWXBsB9oFw2qU4Kckun\"  # relates to NON_FUNDED_FETCHAI_PRIVATE_KEY_1\nNON_GENESIS_CONFIG = {\n    \"delegate_uri\": \"127.0.0.1:11001\",\n    \"entry_peers\": [FETCHAI_P2P_ADDRESS],\n    \"local_uri\": \"127.0.0.1:9001\",\n    \"log_file\": \"libp2p_node.log\",\n    \"public_uri\": \"127.0.0.1:9001\",\n    \"ledger_id\": \"fetchai\",\n}\nNON_GENESIS_CONFIG_TWO = {\n    \"delegate_uri\": \"127.0.0.1:11002\",\n    \"entry_peers\": [FETCHAI_P2P_ADDRESS],\n    \"local_uri\": \"127.0.0.1:9002\",\n    \"log_file\": \"libp2p_node.log\",\n    \"public_uri\": \"127.0.0.1:9002\",\n    \"ledger_id\": \"fetchai\",\n}\nPUBLIC_DHT_P2P_MADDR_1 = \"/dns4/acn.fetch.ai/tcp/9000/p2p/16Uiu2HAkw1ypeQYQbRFV5hKUxGRHocwU5ohmVmCnyJNg36tnPFdx\"\nPUBLIC_DHT_P2P_MADDR_2 = \"/dns4/acn.fetch.ai/tcp/9001/p2p/16Uiu2HAmVWnopQAqq4pniYLw44VRvYxBUoRHqjz1Hh2SoCyjbyRW\"\nPUBLIC_DHT_DELEGATE_URI_1 = \"acn.fetch.ai:11000\"\nPUBLIC_DHT_DELEGATE_URI_2 = \"acn.fetch.ai:11001\"\nPUBLIC_DHT_P2P_PUBLIC_KEY_1 = (\n    \"0217a59bd805c310aca4febe0e99ce22ee3712ae085dc1e5630430b1e15a584bb7\"\n)\nPUBLIC_DHT_P2P_PUBLIC_KEY_2 = (\n    \"03fa7cfae1037cba5218f0f5743802eced8de3247c55ecebaae46c7d3679e3f91d\"\n)\nPUBLIC_STAGING_DHT_P2P_MADDR_1 = \"/dns4/acn.fetch-ai.com/tcp/9003/p2p/16Uiu2HAmQo6EHbmwhkMJkyhjz1DCxE8Ahsy5zFZtw97tWCFckLUp\"\nPUBLIC_STAGING_DHT_P2P_MADDR_2 = \"/dns4/acn.fetch-ai.com/tcp/9004/p2p/16Uiu2HAmEvey5siPHzdEb5QcTYCkh16squbeFHYHvRCWP9Jzp4bV\"\nPUBLIC_STAGING_DHT_DELEGATE_URI_1 = \"acn.fetch-ai.com:11003\"\nPUBLIC_STAGING_DHT_DELEGATE_URI_2 = \"acn.fetch-ai.com:11004\"\nPUBLIC_STAGING_DHT_P2P_PUBLIC_KEY_1 = (\n    \"03b45f898bde437ace4728b3ba097988306930b1600b7991d384e6d08452e340e1\"\n)\nPUBLIC_STAGING_DHT_P2P_PUBLIC_KEY_2 = (\n    \"0321bac023b7f7cf655cf5e0f988a4c1cf758f7b530528362c4ba8d563f7b090c4\"\n)\n\n# testnets\nCOSMOS_TESTNET_CONFIG = {\"address\": COSMOS_DEFAULT_ADDRESS}\nETHEREUM_TESTNET_CONFIG = {\n    \"address\": ETHEREUM_DEFAULT_ADDRESS,\n    \"chain_id\": ETHEREUM_DEFAULT_CHAIN_ID,\n    \"gas_price\": 50,\n}\nFETCHAI_TESTNET_CONFIG = {\"address\": FETCHAI_DEFAULT_ADDRESS}\n\n# common public ids used in the tests\nUNKNOWN_PROTOCOL_PUBLIC_ID = PublicId(\"unknown_author\", \"unknown_protocol\", \"0.1.0\")\nUNKNOWN_CONNECTION_PUBLIC_ID = PublicId(\"unknown_author\", \"unknown_connection\", \"0.1.0\")\nMY_FIRST_AEA_PUBLIC_ID = PublicId.from_str(\"fetchai/my_first_aea:0.28.5\")\n\nDUMMY_SKILL_PATH = os.path.join(CUR_PATH, \"data\", \"dummy_skill\", SKILL_YAML)\n\nMAX_FLAKY_RERUNS = 3\nMAX_FLAKY_RERUNS_ETH = 1\nMAX_FLAKY_RERUNS_INTEGRATION = 1\n\nPACKAGES_DIR = os.path.join(ROOT_DIR, \"packages\")\nFETCHAI_PREF = os.path.join(ROOT_DIR, \"packages\", \"fetchai\")\nPROTOCOL_SPECS_PREF_1 = os.path.join(ROOT_DIR, \"examples\", \"protocol_specification_ex\")\nPROTOCOL_SPECS_PREF_2 = os.path.join(ROOT_DIR, \"tests\", \"data\")\n\ncontract_config_files = [\n    os.path.join(FETCHAI_PREF, \"contracts\", \"erc1155\", CONTRACT_YAML),\n    os.path.join(FETCHAI_PREF, \"contracts\", \"staking_erc20\", CONTRACT_YAML),\n    os.path.join(ROOT_DIR, \"tests\", \"data\", \"dummy_contract\", CONTRACT_YAML),\n]\n\nprotocol_config_files = [\n    os.path.join(ROOT_DIR, \"aea\", \"protocols\", \"scaffold\", PROTOCOL_YAML),\n    os.path.join(FETCHAI_PREF, \"protocols\", \"contract_api\", PROTOCOL_YAML),\n    os.path.join(FETCHAI_PREF, \"protocols\", \"default\", PROTOCOL_YAML),\n    os.path.join(FETCHAI_PREF, \"protocols\", \"fipa\", PROTOCOL_YAML),\n    os.path.join(FETCHAI_PREF, \"protocols\", \"gym\", PROTOCOL_YAML),\n    os.path.join(FETCHAI_PREF, \"protocols\", \"http\", PROTOCOL_YAML),\n    os.path.join(FETCHAI_PREF, \"protocols\", \"ledger_api\", PROTOCOL_YAML),\n    os.path.join(FETCHAI_PREF, \"protocols\", \"ml_trade\", PROTOCOL_YAML),\n    os.path.join(FETCHAI_PREF, \"protocols\", \"oef_search\", PROTOCOL_YAML),\n    os.path.join(FETCHAI_PREF, \"protocols\", \"register\", PROTOCOL_YAML),\n    os.path.join(FETCHAI_PREF, \"protocols\", \"signing\", PROTOCOL_YAML),\n    os.path.join(FETCHAI_PREF, \"protocols\", \"state_update\", PROTOCOL_YAML),\n    os.path.join(FETCHAI_PREF, \"protocols\", \"tac\", PROTOCOL_YAML),\n    os.path.join(CUR_PATH, \"data\", \"dummy_protocol\", PROTOCOL_YAML),\n]\n\nconnection_config_files = [\n    os.path.join(ROOT_DIR, \"aea\", \"connections\", \"scaffold\", CONNECTION_YAML),\n    os.path.join(FETCHAI_PREF, \"connections\", \"gym\", CONNECTION_YAML),\n    os.path.join(FETCHAI_PREF, \"connections\", \"http_client\", CONNECTION_YAML),\n    os.path.join(FETCHAI_PREF, \"connections\", \"http_server\", CONNECTION_YAML),\n    os.path.join(FETCHAI_PREF, \"connections\", \"ledger\", CONNECTION_YAML),\n    os.path.join(FETCHAI_PREF, \"connections\", \"local\", CONNECTION_YAML),\n    os.path.join(FETCHAI_PREF, \"connections\", \"oef\", CONNECTION_YAML),\n    os.path.join(FETCHAI_PREF, \"connections\", \"p2p_libp2p\", CONNECTION_YAML),\n    os.path.join(FETCHAI_PREF, \"connections\", \"p2p_libp2p_client\", CONNECTION_YAML),\n    os.path.join(FETCHAI_PREF, \"connections\", \"p2p_stub\", CONNECTION_YAML),\n    os.path.join(FETCHAI_PREF, \"connections\", \"soef\", CONNECTION_YAML),\n    os.path.join(FETCHAI_PREF, \"connections\", \"stub\", CONNECTION_YAML),\n    os.path.join(FETCHAI_PREF, \"connections\", \"tcp\", CONNECTION_YAML),\n    os.path.join(FETCHAI_PREF, \"connections\", \"webhook\", CONNECTION_YAML),\n    os.path.join(CUR_PATH, \"data\", \"dummy_connection\", CONNECTION_YAML),\n    os.path.join(CUR_PATH, \"data\", \"gym-connection.yaml\"),\n]\n\nskill_config_files = [\n    os.path.join(ROOT_DIR, \"aea\", \"skills\", \"scaffold\", SKILL_YAML),\n    os.path.join(FETCHAI_PREF, \"skills\", \"aries_alice\", SKILL_YAML),\n    os.path.join(FETCHAI_PREF, \"skills\", \"aries_faber\", SKILL_YAML),\n    os.path.join(FETCHAI_PREF, \"skills\", \"carpark_client\", SKILL_YAML),\n    os.path.join(FETCHAI_PREF, \"skills\", \"carpark_detection\", SKILL_YAML),\n    os.path.join(FETCHAI_PREF, \"skills\", \"confirmation_aw1\", SKILL_YAML),\n    os.path.join(FETCHAI_PREF, \"skills\", \"echo\", SKILL_YAML),\n    os.path.join(FETCHAI_PREF, \"skills\", \"erc1155_client\", SKILL_YAML),\n    os.path.join(FETCHAI_PREF, \"skills\", \"erc1155_deploy\", SKILL_YAML),\n    os.path.join(FETCHAI_PREF, \"skills\", \"error\", SKILL_YAML),\n    os.path.join(FETCHAI_PREF, \"skills\", \"generic_buyer\", SKILL_YAML),\n    os.path.join(FETCHAI_PREF, \"skills\", \"generic_seller\", SKILL_YAML),\n    os.path.join(FETCHAI_PREF, \"skills\", \"gym\", SKILL_YAML),\n    os.path.join(FETCHAI_PREF, \"skills\", \"http_echo\", SKILL_YAML),\n    os.path.join(FETCHAI_PREF, \"skills\", \"ml_data_provider\", SKILL_YAML),\n    os.path.join(FETCHAI_PREF, \"skills\", \"ml_train\", SKILL_YAML),\n    os.path.join(FETCHAI_PREF, \"skills\", \"registration_aw1\", SKILL_YAML),\n    os.path.join(FETCHAI_PREF, \"skills\", \"simple_service_registration\", SKILL_YAML),\n    os.path.join(FETCHAI_PREF, \"skills\", \"simple_service_search\", SKILL_YAML),\n    os.path.join(FETCHAI_PREF, \"skills\", \"tac_control\", SKILL_YAML),\n    os.path.join(FETCHAI_PREF, \"skills\", \"tac_control_contract\", SKILL_YAML),\n    os.path.join(FETCHAI_PREF, \"skills\", \"tac_negotiation\", SKILL_YAML),\n    os.path.join(FETCHAI_PREF, \"skills\", \"tac_participation\", SKILL_YAML),\n    os.path.join(FETCHAI_PREF, \"skills\", \"thermometer\", SKILL_YAML),\n    os.path.join(FETCHAI_PREF, \"skills\", \"thermometer_client\", SKILL_YAML),\n    os.path.join(FETCHAI_PREF, \"skills\", \"weather_client\", SKILL_YAML),\n    os.path.join(FETCHAI_PREF, \"skills\", \"weather_station\", SKILL_YAML),\n    DUMMY_SKILL_PATH,\n    os.path.join(CUR_PATH, \"data\", \"dummy_aea\", \"skills\", \"dummy\", SKILL_YAML),\n    os.path.join(CUR_PATH, \"data\", \"dependencies_skill\", SKILL_YAML),\n    os.path.join(CUR_PATH, \"data\", \"exception_skill\", SKILL_YAML),\n]\n\nagent_config_files = [\n    os.path.join(CUR_PATH, \"data\", \"dummy_aea\", AGENT_YAML),\n    os.path.join(CUR_PATH, \"data\", \"aea-config.example.yaml\"),\n    os.path.join(CUR_PATH, \"data\", \"aea-config.example_w_keys.yaml\"),\n    os.path.join(CUR_PATH, \"data\", \"aea-config.example_multipage.yaml\"),\n    os.path.join(FETCHAI_PREF, \"agents\", \"aries_alice\", AGENT_YAML),\n    os.path.join(FETCHAI_PREF, \"agents\", \"aries_faber\", AGENT_YAML),\n    os.path.join(FETCHAI_PREF, \"agents\", \"car_data_buyer\", AGENT_YAML),\n    os.path.join(FETCHAI_PREF, \"agents\", \"car_detector\", AGENT_YAML),\n    os.path.join(FETCHAI_PREF, \"agents\", \"confirmation_aea_aw1\", AGENT_YAML),\n    os.path.join(FETCHAI_PREF, \"agents\", \"erc1155_client\", AGENT_YAML),\n    os.path.join(FETCHAI_PREF, \"agents\", \"erc1155_deployer\", AGENT_YAML),\n    os.path.join(FETCHAI_PREF, \"agents\", \"generic_buyer\", AGENT_YAML),\n    os.path.join(FETCHAI_PREF, \"agents\", \"generic_seller\", AGENT_YAML),\n    os.path.join(FETCHAI_PREF, \"agents\", \"gym_aea\", AGENT_YAML),\n    os.path.join(FETCHAI_PREF, \"agents\", \"ml_data_provider\", AGENT_YAML),\n    os.path.join(FETCHAI_PREF, \"agents\", \"ml_model_trainer\", AGENT_YAML),\n    os.path.join(FETCHAI_PREF, \"agents\", \"my_first_aea\", AGENT_YAML),\n    os.path.join(FETCHAI_PREF, \"agents\", \"registration_aea_aw1\", AGENT_YAML),\n    os.path.join(FETCHAI_PREF, \"agents\", \"simple_service_registration\", AGENT_YAML),\n    os.path.join(FETCHAI_PREF, \"agents\", \"tac_controller\", AGENT_YAML),\n    os.path.join(FETCHAI_PREF, \"agents\", \"tac_controller_contract\", AGENT_YAML),\n    os.path.join(FETCHAI_PREF, \"agents\", \"tac_participant\", AGENT_YAML),\n    os.path.join(FETCHAI_PREF, \"agents\", \"tac_participant_contract\", AGENT_YAML),\n    os.path.join(FETCHAI_PREF, \"agents\", \"thermometer_aea\", AGENT_YAML),\n    os.path.join(FETCHAI_PREF, \"agents\", \"thermometer_client\", AGENT_YAML),\n    os.path.join(FETCHAI_PREF, \"agents\", \"weather_client\", AGENT_YAML),\n    os.path.join(FETCHAI_PREF, \"agents\", \"weather_station\", AGENT_YAML),\n]\n\nprotocol_specification_files = [\n    os.path.join(\n        PROTOCOL_SPECS_PREF_1,\n        \"sample.yaml\",\n    ),\n    os.path.join(\n        PROTOCOL_SPECS_PREF_2,\n        \"sample_specification.yaml\",\n    ),\n    os.path.join(\n        PROTOCOL_SPECS_PREF_2,\n        \"sample_specification_no_custom_types.yaml\",\n    ),\n]\n\n\n@contextmanager\ndef project_root_pythonpath():\n    \"\"\"Set pythonpath to project root.\"\"\"\n    old_python_path = os.environ.get(\"PYTHONPATH\", None)\n    os.environ[\"PYTHONPATH\"] = \":\".join(\n        filter(None, [os.path.abspath(ROOT_DIR), old_python_path])\n    )\n    yield\n    if old_python_path is None:\n        os.environ.pop(\"PYTHONPATH\")\n    else:\n        os.environ[\"PYTHONPATH\"] = old_python_path\n\n\ndef match_files(fname1: str, fname2: str) -> Tuple[bool, str]:\n    \"\"\"\n    Find out whether two text files match.\n\n    :param fname1: string path to file 1\n    :param fname2: string path to file 2\n\n    :return: whether files match (True) or not (False) and a string of their difference (\"\" if they match)\n    \"\"\"\n    with open(fname1, \"r\") as f1, open(fname2, \"r\") as f2:\n        difference = set(f1).difference(f2)\n    are_identical = difference == set()\n\n    diff = \"\"\n    if not are_identical:\n        diff = find_difference(fname1, fname2)\n    return are_identical, diff\n\n\ndef find_difference(fname1: str, fname2: str) -> str:\n    \"\"\"Find the difference between two text files.\"\"\"\n    diff = \"\"\n    with open(fname1) as f1, open(fname2) as f2:\n        differ = difflib.Differ()\n\n        for line in differ.compare(f1.readlines(), f2.readlines()):\n            if not (line.startswith(\" \") or line.startswith(\"? \")):\n                line = line[2:].lstrip()\n                diff += line\n    return diff\n\n\ndef number_of_diff_lines(diff: str) -> int:\n    \"\"\"Give number of lines in a diff string.\"\"\"\n    return diff.count(\"\\n\") if diff != \"\" else 0\n\n\ndef only_windows(fn: Callable) -> Callable:\n    \"\"\"\n    Decorate a pytest method to run a test only in a case we are on Windows.\n\n    :return: decorated method.\n    \"\"\"\n    return action_for_platform(\"Windows\", skip=False)(fn)\n\n\ndef skip_test_windows(fn: Callable) -> Callable:\n    \"\"\"\n    Decorate a pytest method to skip a test in a case we are on Windows.\n\n    :return: decorated method.\n    \"\"\"\n    return action_for_platform(\"Windows\", skip=True)(fn)\n\n\ndef skip_test_macos(fn: Callable) -> Callable:\n    \"\"\"\n    Decorate a pytest method to skip a test in a case we are on MacOS.\n\n    :return: decorated method.\n    \"\"\"\n    return action_for_platform(\"Darwin\", skip=True)(fn)\n\n\ndef action_for_platform(platform_name: str, skip: bool = True) -> Callable:\n    \"\"\"\n    Decorate a pytest class or method to skip on certain platform.\n\n    :param platform_name: check `platform.system()` for available platforms.\n    :param skip: if True, the test will be skipped;\n      if False, the test will be run ONLY on the chosen platform.\n\n    :return: decorated object\n    \"\"\"\n\n    # for docstyle.\n    def decorator(pytest_func):\n        \"\"\"\n        For the sake of clarity, assume the chosen platform for the action is \"Windows\".\n\n        If the following condition is true:\n          - the current system is not Windows (is_different) AND we want to skip it (skip)\n         OR\n          - the current system is Windows (not is_different) AND we want to run only on it (not skip)\n        we run the test, else we skip the test.\n\n        logically, the condition is a boolean equivalence\n        between the variables \"is_different\" and \"skip\"\n        Hence, the condition becomes:\n        \"\"\"\n        is_different = platform.system() != platform_name\n        if is_different is skip:\n            return pytest_func\n\n        def action(*args, **kwargs):\n            if skip:\n                pytest.skip(\n                    f\"Skipping the test since it doesn't work on {platform_name}.\"\n                )\n            else:\n                pytest.skip(\n                    f\"Skipping the test since it works only on {platform_name}.\"\n                )\n\n        if isinstance(pytest_func, type):\n            return type(\n                pytest_func.__name__,\n                (pytest_func,),\n                {\n                    \"setup_class\": action,\n                    \"setup\": action,\n                    \"setUp\": action,\n                    \"_skipped\": True,\n                },\n            )\n\n        @wraps(pytest_func)\n        def wrapper(*args, **kwargs):  # type: ignore\n            action(*args, **kwargs)\n\n        return wrapper\n\n    return decorator\n\n\n@pytest.fixture(scope=\"session\")\ndef oef_addr() -> str:\n    \"\"\"IP address pointing to the OEF Node to use during the tests.\"\"\"\n    return \"127.0.0.1\"\n\n\n@pytest.fixture(scope=\"session\")\ndef oef_port() -> int:\n    \"\"\"Port of the connection to the OEF Node to use during the tests.\"\"\"\n    return 10000\n\n\n@pytest.fixture(scope=\"session\")\ndef ganache_addr() -> str:\n    \"\"\"HTTP address to the Ganache node.\"\"\"\n    return DEFAULT_GANACHE_ADDR\n\n\n@pytest.fixture(scope=\"session\")\ndef ganache_port() -> int:\n    \"\"\"Port of the connection to the Ganache Node to use during the tests.\"\"\"\n    return DEFAULT_GANACHE_PORT\n\n\ndef tcpping(ip, port, log_exception: bool = True) -> bool:\n    \"\"\"Ping TCP port.\"\"\"\n    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\n    try:\n        s.connect((ip, int(port)))\n        s.shutdown(2)\n        return True\n    except Exception as e:\n        if log_exception:\n            logger.exception(e)\n        return False\n\n\ndef wait_for_localhost_ports_to_close(\n    ports: List[int], timeout: int = 120, sleep_time: int = 2\n) -> None:\n    \"\"\"Wait for ports to close with timeout.\"\"\"\n    open_ports = ports\n    elapsed = 0\n    while len(open_ports) > 0 and elapsed < timeout:\n        closed = []\n        for port in open_ports:\n            if not tcpping(\"127.0.0.1\", port, log_exception=False):\n                closed.append(port)\n        open_ports = [port for port in open_ports if port not in closed]\n        if len(open_ports) > 0:\n            time.sleep(sleep_time)\n            elapsed += sleep_time\n    if open_ports != []:\n        raise ValueError(\"Some ports are open: {}!\".format(open_ports))\n\n\ndef pytest_addoption(parser) -> None:\n    \"\"\"Add --aea-loop option.\"\"\"\n    parser.addoption(\n        \"--aea-loop\",\n        action=\"store\",\n        default=\"async\",\n        help=\"aea loop to use: async[default] or sync\",\n    )\n    # disable inernet connection\n    parser.addoption(\n        \"--no-inet\",\n        action=\"store_true\",\n        default=False,\n        help=\"block socket connect outside of 127.x.x.x\",\n    )\n\n    parser.addoption(\n        \"--check-threads\",\n        action=\"store_true\",\n        default=False,\n        help=\"check non closed threads i started during test\",\n    )\n\n\n@pytest.fixture(scope=\"session\", autouse=True)\ndef inet_disable(request) -> None:\n    \"\"\"Disable internet access via socket.\"\"\"\n    if not request.config.getoption(\"--no-inet\"):\n        return\n\n    orig_connect = socket.socket.connect\n\n    def socket_connect(*args):\n        host = args[1][0]\n        if host == \"localhost\" or host.startswith(\"127.\"):\n            return orig_connect(*args)\n        raise socket.error(\"Internet disabled by pytest option --no-inet\")\n\n    p = patch.object(socket.socket, \"connect\", new=socket_connect)\n    p.start()\n\n\n@pytest.fixture(scope=\"session\", autouse=True)\ndef increase_aea_builder_build_timeout(request) -> Generator:\n    \"\"\"Increase build timeout for aea builder.\"\"\"\n    old_timeout = AEABuilder.BUILD_TIMEOUT\n    AEABuilder.BUILD_TIMEOUT = 420\n    try:\n        yield\n    finally:\n        AEABuilder.BUILD_TIMEOUT = old_timeout\n\n\n@pytest.fixture(scope=\"session\", autouse=True)\ndef apply_aea_loop(request) -> None:\n    \"\"\"Patch AEA.DEFAULT_RUN_LOOP using pytest option `--aea-loop`.\"\"\"\n    loop = request.config.getoption(\"--aea-loop\")\n    assert loop in AEA.RUN_LOOPS\n    AEA.DEFAULT_RUN_LOOP = loop\n\n\n@pytest.fixture(scope=\"session\")\ndef network_node(\n    oef_addr, oef_port, pytestconfig, timeout: float = 2.0, max_attempts: int = 10\n):\n    \"\"\"Network node initialization.\"\"\"\n    client = docker.from_env()\n    image = OEFSearchDockerImage(client, oef_addr, oef_port)\n    yield from _launch_image(image, timeout, max_attempts)\n\n\n@pytest.fixture(scope=\"session\")\ndef ganache_configuration():\n    \"\"\"Get the Ganache configuration for testing purposes.\"\"\"\n    return dict(\n        accounts_balances=[\n            (FUNDED_ETH_PRIVATE_KEY_1, DEFAULT_AMOUNT),\n            (FUNDED_ETH_PRIVATE_KEY_2, DEFAULT_AMOUNT),\n            (FUNDED_ETH_PRIVATE_KEY_3, DEFAULT_AMOUNT),\n            (Path(ETHEREUM_PRIVATE_KEY_PATH).read_text().strip(), DEFAULT_AMOUNT),\n        ],\n    )\n\n\n@pytest.fixture(scope=\"session\")\ndef fetchd_configuration():\n    \"\"\"Get the Fetch ledger configuration for testing purposes.\"\"\"\n    return dict(\n        mnemonic=DEFAULT_FETCH_MNEMONIC,\n        moniker=DEFAULT_MONIKER,\n        chain_id=DEFAULT_FETCH_CHAIN_ID,\n        genesis_account=DEFAULT_GENESIS_ACCOUNT,\n        denom=DEFAULT_DENOMINATION,\n    )\n\n\n@pytest.fixture(scope=\"session\")\ndef ethereum_testnet_config(ganache_addr, ganache_port):\n    \"\"\"Get Ethereum ledger api configurations using Ganache.\"\"\"\n    new_uri = f\"{ganache_addr}:{ganache_port}\"\n    new_config = {\n        \"address\": new_uri,\n        \"chain_id\": DEFAULT_GANACHE_CHAIN_ID,\n        \"denom\": ETHEREUM_DEFAULT_CURRENCY_DENOM,\n        \"gas_price_api_key\": GAS_PRICE_API_KEY,\n    }\n    return new_config\n\n\n@pytest.fixture(scope=\"function\")\ndef update_default_ethereum_ledger_api(ethereum_testnet_config):\n    \"\"\"Change temporarily default Ethereum ledger api configurations to interact with local Ganache.\"\"\"\n    old_config = DEFAULT_LEDGER_CONFIGS.pop(EthereumCrypto.identifier, None)\n    DEFAULT_LEDGER_CONFIGS[EthereumCrypto.identifier] = ethereum_testnet_config\n    yield\n    DEFAULT_LEDGER_CONFIGS.pop(EthereumCrypto.identifier)\n    DEFAULT_LEDGER_CONFIGS[EthereumCrypto.identifier] = old_config\n\n\n@pytest.mark.integration\n@pytest.mark.ledger\n@pytest.fixture(scope=\"class\")\ndef ganache(\n    ganache_configuration,\n    ganache_addr,\n    ganache_port,\n    timeout: float = 2.0,\n    max_attempts: int = 10,\n):\n    \"\"\"Launch the Ganache image.\"\"\"\n    client = docker.from_env()\n    image = GanacheDockerImage(\n        client, \"http://127.0.0.1\", 8545, config=ganache_configuration\n    )\n    yield from _launch_image(image, timeout=timeout, max_attempts=max_attempts)\n\n\n@pytest.mark.integration\n@pytest.fixture(scope=\"class\")\ndef soef(\n    soef_addr: str = \"http://127.0.0.1\",\n    soef_port: int = 12002,\n    timeout: float = 2.0,\n    max_attempts: int = 50,\n):\n    \"\"\"Launch the soef image.\"\"\"\n    client = docker.from_env()\n    image = SOEFDockerImage(client, soef_addr, soef_port)\n    yield from _launch_image(image, timeout=timeout, max_attempts=max_attempts)\n\n\n@pytest.mark.integration\n@pytest.mark.ledger\n@pytest.fixture(scope=\"class\")\n@action_for_platform(\"Linux\", skip=False)\ndef fetchd(\n    fetchd_configuration,\n    timeout: float = 2.0,\n    max_attempts: int = 20,\n):\n    \"\"\"Launch the Fetch ledger image.\"\"\"\n    client = docker.from_env()\n    image = FetchLedgerDockerImage(\n        client,\n        DEFAULT_FETCH_LEDGER_ADDR,\n        DEFAULT_FETCH_LEDGER_RPC_PORT,\n        DEFAULT_FETCH_DOCKER_IMAGE_TAG,\n        config=fetchd_configuration,\n    )\n    yield from _launch_image(image, timeout=timeout, max_attempts=max_attempts)\n\n\ndef _launch_image(image: DockerImage, timeout: float = 2.0, max_attempts: int = 10):\n    \"\"\"\n    Launch image.\n\n    :param image: an instance of Docker image.\n    :return: None\n    \"\"\"\n    image.check_skip()\n    image.pull_image(30)\n\n    for _ in range(10):\n        image.stop_if_already_running()\n        # sleep after stop called\n        time.sleep(1)\n        container = image.create()\n\n        logger.info(f\"Setting up image {image.tag}...\")\n        try:\n            container.start()\n        except Exception:\n            logger.exception(\"Error on container start\")\n            continue\n        time.sleep(1)\n\n        container.reload()\n        if container.status == \"running\":\n            break\n\n        logger.info(\"Retry to start the container\")\n    else:\n        logger.info(\"Failed to start the container\")\n        logger.info(container.logs())\n        raise Exception(\"Failed to start container\")\n\n    success = image.wait(max_attempts, timeout)\n\n    if not success:\n        logger.info(\n            \"containers list: {}\".format(\n                [f\"{i.image}:{i.status}\" for i in image._client.containers.list()],\n            )\n        )\n        logger.info(container.logs())\n        container.stop()\n        container.remove()\n        pytest.fail(f\"{image.tag} doesn't work. Exiting...\")\n    else:\n        try:\n            logger.info(\"Done!\")\n            time.sleep(timeout)\n            yield\n        finally:\n            logger.info(f\"Stopping the image {image.tag}...\")\n            container.stop()\n            container.remove()\n\n\n@pytest.fixture(scope=\"session\", autouse=True)\ndef reset_aea_cli_config() -> None:\n    \"\"\"Reset the cli config for each test.\"\"\"\n    _init_cli_config()\n\n\ndef get_unused_tcp_port():\n    \"\"\"Get an unused TCP port.\"\"\"\n    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\n    s.bind((\"127.0.0.1\", 0))\n    s.listen(1)\n    port = s.getsockname()[1]\n    s.close()\n    return port\n\n\ndef get_host():\n    \"\"\"Get the host.\"\"\"\n    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)\n    try:\n        # doesn't even have to be reachable\n        s.connect((\"10.255.255.255\", 1))\n        IP = s.getsockname()[0]\n    except Exception:\n        IP = \"127.0.0.1\"\n    finally:\n        s.close()\n    return IP\n\n\ndef double_escape_windows_path_separator(path):\n    r\"\"\"Doubleescape Windows path separator '\\'.\"\"\"\n    return path.replace(\"\\\\\", \"\\\\\\\\\")\n\n\ndef _make_dummy_connection() -> Connection:\n    configuration = ConnectionConfig(\n        connection_id=DummyConnection.connection_id,\n    )\n    dummy_connection = DummyConnection(\n        configuration=configuration,\n        data_dir=MagicMock(),\n        identity=Identity(\"name\", \"address\", \"public_key\"),\n    )\n    return dummy_connection\n\n\ndef _make_local_connection(\n    address: Address,\n    public_key: str,\n    node: LocalNode,\n    restricted_to_protocols=None,\n    excluded_protocols=None,\n) -> Connection:\n    configuration = ConnectionConfig(\n        restricted_to_protocols=restricted_to_protocols,\n        excluded_protocols=excluded_protocols,\n        connection_id=OEFLocalConnection.connection_id,\n    )\n    oef_local_connection = OEFLocalConnection(\n        configuration=configuration,\n        data_dir=MagicMock(),\n        identity=Identity(\"name\", address, public_key),\n        local_node=node,\n    )\n    return oef_local_connection\n\n\ndef _make_oef_connection(\n    address: Address, public_key: str, oef_addr: str, oef_port: int\n):\n    configuration = ConnectionConfig(\n        addr=oef_addr, port=oef_port, connection_id=OEFConnection.connection_id\n    )\n    oef_connection = OEFConnection(\n        configuration=configuration,\n        data_dir=MagicMock(),\n        identity=Identity(\"name\", address, public_key),\n    )\n    oef_connection._default_logger_name = \"aea.packages.fetchai.connections.oef\"\n    return oef_connection\n\n\ndef _make_tcp_server_connection(address: str, public_key: str, host: str, port: int):\n    configuration = ConnectionConfig(\n        address=host, port=port, connection_id=TCPServerConnection.connection_id\n    )\n    tcp_connection = TCPServerConnection(\n        configuration=configuration,\n        data_dir=MagicMock(),\n        identity=Identity(\"name\", address, public_key),\n    )\n    tcp_connection._default_logger_name = (\n        \"aea.packages.fetchai.connections.tcp.tcp_server\"\n    )\n    return tcp_connection\n\n\ndef _make_tcp_client_connection(address: str, public_key: str, host: str, port: int):\n    configuration = ConnectionConfig(\n        address=host, port=port, connection_id=TCPClientConnection.connection_id\n    )\n    tcp_connection = TCPClientConnection(\n        configuration=configuration,\n        data_dir=MagicMock(),\n        identity=Identity(\"name\", address, public_key),\n    )\n    tcp_connection._default_logger_name = (\n        \"aea.packages.fetchai.connections.tcp.tcp_client\"\n    )\n    return tcp_connection\n\n\ndef _make_stub_connection(input_file_path: str, output_file_path: str):\n    configuration = ConnectionConfig(\n        input_file=input_file_path,\n        output_file=output_file_path,\n        connection_id=StubConnection.connection_id,\n    )\n    connection = StubConnection(configuration=configuration, data_dir=MagicMock())\n    return connection\n\n\ndef _process_cert(key: Crypto, cert: CertRequest, path_prefix: str):\n    # must match aea/cli/issue_certificates.py:_process_certificate\n    assert cert.public_key is not None\n    message = cert.get_message(cert.public_key)\n    signature = key.sign_message(message).encode(\"ascii\").hex()\n    Path(cert.get_absolute_save_path(path_prefix)).write_bytes(\n        signature.encode(\"ascii\")\n    )\n\n\ndef _make_libp2p_connection(\n    data_dir: str,\n    port: int = 10234,\n    host: str = \"127.0.0.1\",\n    relay: bool = True,\n    delegate: bool = False,\n    mailbox: bool = False,\n    entry_peers: Optional[Sequence[MultiAddr]] = None,\n    delegate_port: int = 11234,\n    delegate_host: str = \"127.0.0.1\",\n    mailbox_port: int = 8888,\n    mailbox_host: str = \"127.0.0.1\",\n    node_key_file: Optional[str] = None,\n    agent_key: Optional[Crypto] = None,\n    build_directory: Optional[str] = None,\n    peer_registration_delay: str = \"0.0\",\n) -> P2PLibp2pConnection:\n    if not os.path.isdir(data_dir) or not os.path.exists(data_dir):\n        raise ValueError(\"Data dir must be directory and exist!\")\n    log_file = os.path.join(data_dir, \"libp2p_node_{}.log\".format(port))\n    if os.path.exists(log_file):\n        os.remove(log_file)\n    key = agent_key\n    if key is None:\n        key = make_crypto(DEFAULT_LEDGER)\n    identity = Identity(\"identity\", address=key.address, public_key=key.public_key)\n    conn_crypto_store = None\n    if node_key_file is not None:\n        conn_crypto_store = CryptoStore({DEFAULT_LEDGER: node_key_file})\n    else:\n        node_key = make_crypto(DEFAULT_LEDGER)\n        node_key_path = os.path.join(data_dir, f\"{node_key.public_key}.txt\")\n        node_key.dump(node_key_path)\n        conn_crypto_store = CryptoStore({DEFAULT_LEDGER: node_key_path})\n    cert_request = CertRequest(\n        conn_crypto_store.public_keys[DEFAULT_LEDGER],\n        POR_DEFAULT_SERVICE_ID,\n        key.identifier,\n        \"2021-01-01\",\n        \"2021-01-02\",\n        \"{public_key}\",\n        f\"./{key.address}_cert.txt\",\n    )\n    _process_cert(key, cert_request, path_prefix=data_dir)\n    if not build_directory:\n        build_directory = os.getcwd()\n    if relay and delegate:\n        configuration = ConnectionConfig(\n            node_key_file=node_key_file,\n            local_uri=\"{}:{}\".format(host, port),\n            public_uri=\"{}:{}\".format(host, port),\n            entry_peers=entry_peers,\n            log_file=log_file,\n            delegate_uri=\"{}:{}\".format(delegate_host, delegate_port),\n            peer_registration_delay=peer_registration_delay,\n            connection_id=P2PLibp2pConnection.connection_id,\n            build_directory=build_directory,\n            cert_requests=[cert_request],\n        )\n    elif relay and not delegate:\n        configuration = ConnectionConfig(\n            node_key_file=node_key_file,\n            local_uri=\"{}:{}\".format(host, port),\n            public_uri=\"{}:{}\".format(host, port),\n            entry_peers=entry_peers,\n            log_file=log_file,\n            peer_registration_delay=peer_registration_delay,\n            connection_id=P2PLibp2pConnection.connection_id,\n            build_directory=build_directory,\n            cert_requests=[cert_request],\n        )\n    else:\n        configuration = ConnectionConfig(\n            node_key_file=node_key_file,\n            local_uri=\"{}:{}\".format(host, port),\n            entry_peers=entry_peers,\n            log_file=log_file,\n            peer_registration_delay=peer_registration_delay,\n            connection_id=P2PLibp2pConnection.connection_id,\n            build_directory=build_directory,\n            cert_requests=[cert_request],\n        )\n\n    if mailbox:\n        configuration.config[\"mailbox_uri\"] = f\"{mailbox_host}:{mailbox_port}\"\n    else:\n        configuration.config[\"mailbox_uri\"] = \"\"\n\n    if not os.path.exists(os.path.join(build_directory, LIBP2P_NODE_MODULE_NAME)):\n        build_node(build_directory)\n    connection = P2PLibp2pConnection(\n        configuration=configuration,\n        data_dir=data_dir,\n        identity=identity,\n        crypto_store=conn_crypto_store,\n    )\n    return connection\n\n\ndef _make_libp2p_client_connection(\n    peer_public_key: str,\n    data_dir: str,\n    node_port: int = 11234,\n    node_host: str = \"127.0.0.1\",\n    uri: Optional[str] = None,\n    ledger_api_id: Union[SimpleId, str] = DEFAULT_LEDGER,\n) -> P2PLibp2pClientConnection:\n    if not os.path.isdir(data_dir) or not os.path.exists(data_dir):\n        raise ValueError(\"Data dir must be directory and exist!\")\n    crypto = make_crypto(ledger_api_id)\n    identity = Identity(\n        \"identity\", address=crypto.address, public_key=crypto.public_key\n    )\n    cert_request = CertRequest(\n        peer_public_key,\n        POR_DEFAULT_SERVICE_ID,\n        ledger_api_id,\n        \"2021-01-01\",\n        \"2021-01-02\",\n        \"{public_key}\",\n        f\"./{crypto.address}_cert.txt\",\n    )\n    _process_cert(crypto, cert_request, path_prefix=data_dir)\n    configuration = ConnectionConfig(\n        tcp_key_file=None,\n        nodes=[\n            {\n                \"uri\": str(uri)\n                if uri is not None\n                else \"{}:{}\".format(node_host, node_port),\n                \"public_key\": peer_public_key,\n            },\n        ],\n        connection_id=P2PLibp2pClientConnection.connection_id,\n        cert_requests=[cert_request],\n    )\n    return P2PLibp2pClientConnection(\n        configuration=configuration, data_dir=data_dir, identity=identity\n    )\n\n\ndef _make_libp2p_mailbox_connection(\n    peer_public_key: str,\n    data_dir: str,\n    node_port: int = 8888,\n    node_host: str = \"127.0.0.1\",\n    uri: Optional[str] = None,\n    ledger_api_id: Union[SimpleId, str] = DEFAULT_LEDGER,\n) -> P2PLibp2pMailboxConnection:\n    if not os.path.isdir(data_dir) or not os.path.exists(data_dir):\n        raise ValueError(\"Data dir must be directory and exist!\")\n    crypto = make_crypto(ledger_api_id)\n    identity = Identity(\n        \"identity\", address=crypto.address, public_key=crypto.public_key\n    )\n    cert_request = CertRequest(\n        peer_public_key,\n        POR_DEFAULT_SERVICE_ID,\n        ledger_api_id,\n        \"2021-01-01\",\n        \"2021-01-02\",\n        \"{public_key}\",\n        f\"./{crypto.address}_cert.txt\",\n    )\n    _process_cert(crypto, cert_request, path_prefix=data_dir)\n    configuration = ConnectionConfig(\n        tcp_key_file=None,\n        nodes=[\n            {\n                \"uri\": str(uri)\n                if uri is not None\n                else \"{}:{}\".format(node_host, node_port),\n                \"public_key\": peer_public_key,\n            },\n        ],\n        connection_id=P2PLibp2pMailboxConnection.connection_id,\n        cert_requests=[cert_request],\n    )\n    return P2PLibp2pMailboxConnection(\n        configuration=configuration, data_dir=data_dir, identity=identity\n    )\n\n\ndef libp2p_log_on_failure(fn: Callable) -> Callable:\n    \"\"\"\n    Decorate a pytest method running a libp2p node to print its logs in case test fails.\n\n    :return: decorated method.\n    \"\"\"\n\n    # for pydcostyle\n    @wraps(fn)\n    def wrapper(self, *args, **kwargs):\n        try:\n            return fn(self, *args, **kwargs)\n        except Exception:\n            for log_file in self.log_files:\n                print(\"libp2p log file ======================= {}\".format(log_file))\n                try:\n                    with open(log_file, \"r\") as f:\n                        print(f.read())\n                except FileNotFoundError:\n                    pass\n                print(\"=======================================\")\n            raise\n\n    return wrapper\n\n\ndef libp2p_log_on_failure_all(cls):\n    \"\"\"\n    Decorate every method of a class with `libp2p_log_on_failure`.\n\n    :return: class with decorated methods.\n    \"\"\"\n    for name, fn in inspect.getmembers(cls):\n        if isinstance(fn, FunctionType):\n            setattr(cls, name, libp2p_log_on_failure(fn))\n        continue\n        if isinstance(fn, MethodType):\n            if fn.im_self is None:\n                wrapped_fn = libp2p_log_on_failure(fn.im_func)\n                method = MethodType(wrapped_fn, None, cls)\n                setattr(cls, name, method)\n            else:\n                wrapped_fn = libp2p_log_on_failure(fn.im_func)\n                clsmethod = MethodType(wrapped_fn, cls, type)\n                setattr(cls, name, clsmethod)\n    return cls\n\n\ndef _do_for_all(method_decorator):\n    def class_decorator(cls):\n        class GetAttributeMetaClass(type):\n            def __getattribute__(cls, name):\n                attr = super().__getattribute__(name)\n                return method_decorator(attr)\n\n        class DecoratedClass(cls, metaclass=GetAttributeMetaClass):\n            def __getattribute__(self, name):\n                attr = super().__getattribute__(name)\n                return method_decorator(attr)\n\n        for attr in WRAPPER_ASSIGNMENTS:\n            if not hasattr(cls, attr):\n                continue\n            setattr(DecoratedClass, attr, getattr(cls, attr))\n        DecoratedClass.__wrapped__ = cls\n        return DecoratedClass\n\n    return class_decorator\n\n\nclass CwdException(Exception):\n    \"\"\"Exception to raise if cwd was not restored by test.\"\"\"\n\n    def __init__(self):\n        \"\"\"Init expcetion with default message.\"\"\"\n        super().__init__(\"CWD was not restored\")\n\n\n@pytest.fixture(scope=\"class\", autouse=True)\ndef aea_testcase_teardown_check(request):\n    \"\"\"Check BaseAEATestCase.teardown_class for BaseAEATestCase based test cases.\"\"\"\n    from aea.test_tools.test_cases import BaseAEATestCase  # cause circular import\n\n    yield\n    if (\n        request.cls\n        and issubclass(request.cls, BaseAEATestCase)\n        and getattr(request.cls, \"_skipped\", False) is False\n    ):\n        assert getattr(\n            request.cls, \"_is_teardown_class_called\", None\n        ), \"No BaseAEATestCase.teardown_class was called!\"\n\n\n@pytest.fixture(scope=\"class\", autouse=True)\ndef check_test_class_cwd():\n    \"\"\"Check test case class restore CWD.\"\"\"\n    os.chdir(ROOT_DIR)\n    old_cwd = os.getcwd()\n    yield\n    if old_cwd != os.getcwd():\n        raise CwdException()\n\n\n@pytest.fixture(autouse=True)\ndef check_test_cwd(request):\n    \"\"\"Check particular test restore CWD.\"\"\"\n    if request.cls:\n        yield\n        return\n    os.chdir(ROOT_DIR)\n    old_cwd = os.getcwd()\n    yield\n    if old_cwd != os.getcwd():\n        os.chdir(ROOT_DIR)\n        raise CwdException()\n\n\n@pytest.fixture(autouse=True)\ndef set_logging_to_debug(request):\n    \"\"\"Set aea logger to debug.\"\"\"\n    aea_logger = logging.getLogger(\"aea\")\n    aea_logger.setLevel(logging.DEBUG)\n\n\n@pytest.fixture(autouse=True)\ndef check_test_threads(request):\n    \"\"\"Check particular test close all spawned threads.\"\"\"\n    if not request.config.getoption(\"--check-threads\"):\n        yield\n        return\n    if request.cls:\n        yield\n        return\n    num_threads = threading.activeCount()\n    yield\n    new_num_threads = threading.activeCount()\n    assert num_threads >= new_num_threads, \"Non closed threads!\"\n\n\n@pytest_asyncio.fixture\nasync def ledger_apis_connection(request, ethereum_testnet_config):\n    \"\"\"Make a connection.\"\"\"\n    crypto = make_crypto(DEFAULT_LEDGER)\n    identity = Identity(\"name\", crypto.address, crypto.public_key)\n    crypto_store = CryptoStore()\n    directory = Path(ROOT_DIR, \"packages\", \"fetchai\", \"connections\", \"ledger\")\n    connection = Connection.from_dir(\n        directory, data_dir=MagicMock(), identity=identity, crypto_store=crypto_store\n    )\n    connection = cast(Connection, connection)\n    connection._logger = logging.getLogger(\"aea.packages.fetchai.connections.ledger\")\n\n    # use testnet config\n    connection.configuration.config.get(\"ledger_apis\", {})[\n        \"ethereum\"\n    ] = ethereum_testnet_config\n\n    await connection.connect()\n    yield connection\n    await connection.disconnect()\n\n\n@pytest.fixture()\ndef ledger_api(ethereum_testnet_config, ganache):\n    \"\"\"Ledger api fixture.\"\"\"\n    ledger_id, config = EthereumCrypto.identifier, ethereum_testnet_config\n    api = ledger_apis_registry.make(ledger_id, **config)\n    yield api\n\n\ndef get_register_erc1155() -> Contract:\n    \"\"\"Get and register the erc1155 contract package.\"\"\"\n    directory = Path(ROOT_DIR, \"packages\", \"fetchai\", \"contracts\", \"erc1155\")\n    configuration = load_component_configuration(ComponentType.CONTRACT, directory)\n    configuration._directory = directory\n    configuration = cast(ContractConfig, configuration)\n\n    if str(configuration.public_id) not in contract_registry.specs:\n        # load contract into sys modules\n        Contract.from_config(configuration)\n\n    contract = contract_registry.make(str(configuration.public_id))\n    return contract\n\n\n@pytest.fixture()\ndef erc1155_contract(ledger_api, ganache, ganache_addr, ganache_port):\n    \"\"\"\n    Instantiate an ERC1155 contract instance.\n\n    As a side effect, register it to the registry, if not already registered.\n    \"\"\"\n    contract = get_register_erc1155()\n    # deploy contract\n    crypto = make_crypto(\n        EthereumCrypto.identifier, private_key_path=ETHEREUM_PRIVATE_KEY_PATH\n    )\n\n    tx = contract.get_deploy_transaction(\n        ledger_api=ledger_api, deployer_address=crypto.address, gas=5000000\n    )\n    gas = ledger_api.api.eth.estimateGas(transaction=tx)\n    tx[\"gas\"] = gas\n    tx_signed = crypto.sign_transaction(tx)\n    tx_receipt = ledger_api.send_signed_transaction(tx_signed)\n    receipt = ledger_api.get_transaction_receipt(tx_receipt)\n    contract_address = cast(Dict, receipt)[\"contractAddress\"]\n    yield contract, contract_address\n\n\n@pytest.fixture()\ndef erc20_contract(ledger_api, ganache, ganache_addr, ganache_port):\n    \"\"\"Instantiate an ERC20 contract.\"\"\"\n    directory = Path(ROOT_DIR, \"packages\", \"fetchai\", \"contracts\", \"fet_erc20\")\n    configuration = load_component_configuration(ComponentType.CONTRACT, directory)\n    configuration._directory = directory\n    configuration = cast(ContractConfig, configuration)\n\n    if str(configuration.public_id) not in contract_registry.specs:\n        # load contract into sys modules\n        Contract.from_config(configuration)\n\n    contract = contract_registry.make(str(configuration.public_id))\n\n    # get two accounts\n    account1 = make_crypto(\n        EthereumCrypto.identifier, private_key_path=ETHEREUM_PRIVATE_KEY_PATH\n    )\n    account2 = make_crypto(\n        EthereumCrypto.identifier, private_key_path=ETHEREUM_PRIVATE_KEY_TWO_PATH\n    )\n\n    tx = contract.get_deploy_transaction(\n        ledger_api=ledger_api,\n        deployer_address=account1.address,\n        gas=5000000,\n        name=\"FetERC20Mock\",\n        symbol=\"MFET\",\n        initialSupply=int(1e23),\n        decimals_=18,\n    )\n    gas = ledger_api.api.eth.estimateGas(transaction=tx)\n    tx[\"gas\"] = gas\n    tx_signed = account1.sign_transaction(tx)\n    tx_receipt = ledger_api.send_signed_transaction(tx_signed)\n    receipt = ledger_api.get_transaction_receipt(tx_receipt)\n    contract_address = cast(Dict, receipt)[\"contractAddress\"]\n\n    # Transfer some MFET to another default account\n    tx = contract.get_transfer_transaction(\n        ledger_api=ledger_api,\n        contract_address=contract_address,\n        from_address=account1.address,\n        gas=200000,\n        receiver=account2.address,\n        amount=int(1e20),\n    )\n    tx_signed = account1.sign_transaction(tx)\n    ledger_api.send_signed_transaction(tx_signed)\n\n    yield contract, contract_address\n\n\n@pytest.fixture()\ndef oracle_contract(ledger_api, ganache, ganache_addr, ganache_port, erc20_contract):\n    \"\"\"Instantiate a Fetch Oracle contract.\"\"\"\n    directory = Path(ROOT_DIR, \"packages\", \"fetchai\", \"contracts\", \"oracle\")\n    configuration = load_component_configuration(ComponentType.CONTRACT, directory)\n    configuration._directory = directory\n    configuration = cast(ContractConfig, configuration)\n\n    if str(configuration.public_id) not in contract_registry.specs:\n        # load contract into sys modules\n        Contract.from_config(configuration)\n\n    contract = contract_registry.make(str(configuration.public_id))\n\n    _, erc20_address = erc20_contract\n\n    # deploy contract\n    crypto = make_crypto(\n        EthereumCrypto.identifier, private_key_path=ETHEREUM_PRIVATE_KEY_PATH\n    )\n\n    tx = contract.get_deploy_transaction(\n        ledger_api=ledger_api,\n        deployer_address=crypto.address,\n        gas=5000000,\n        ERC20Address=erc20_address,\n        initialFee=10000000000,\n    )\n    tx_signed = crypto.sign_transaction(tx)\n    tx_receipt = ledger_api.send_signed_transaction(tx_signed)\n    receipt = ledger_api.get_transaction_receipt(tx_receipt)\n    contract_address = cast(Dict, receipt)[\"contractAddress\"]\n    yield contract, contract_address\n\n\ndef docker_exec_cmd(image_tag: str, cmd: str, **kwargs):\n    \"\"\"Execute a command in running docker containers matching image tag.\"\"\"\n    client = docker.from_env()\n    for container in client.containers.list():\n        if image_tag in container.image.tags:\n            logger.info(f\"Running command '{cmd}' in docker container {image_tag}\")\n            resp = container.exec_run(cmd, **kwargs)\n            logger.info(resp)\n\n\ndef fund_accounts_from_local_validator(\n    addresses: List[str], amount: int, denom: str = DEFAULT_DENOMINATION\n):\n    \"\"\"Send funds to local accounts from the local genesis validator.\"\"\"\n    pk = PrivateKey(bytes.fromhex(FUNDED_FETCHAI_PRIVATE_KEY_1))\n    wallet = LocalWallet(pk)\n\n    ledger = LedgerClient(\n        NetworkConfig(\n            chain_id=DEFAULT_FETCH_CHAIN_ID,\n            url=f\"rest+{DEFAULT_FETCH_LEDGER_ADDR}:{DEFAULT_FETCH_LEDGER_REST_PORT}\",\n            fee_minimum_gas_price=5000000000,\n            fee_denomination=DEFAULT_DENOMINATION,\n            staking_denomination=DEFAULT_DENOMINATION,\n        )\n    )\n\n    for address in addresses:\n        tx = ledger.send_tokens(CosmpyAddress(address), amount, denom, wallet)\n        tx.wait_to_complete()\n\n\n@pytest.fixture()\ndef fund_fetchai_accounts(fetchd):\n    \"\"\"Fund test accounts from local validator.\"\"\"\n    for _ in range(5):\n        try:\n            # retry, cause possible race condition with fetchd docker image init\n            fund_accounts_from_local_validator(\n                [FUNDED_FETCHAI_ADDRESS_ONE, FUNDED_FETCHAI_ADDRESS_TWO],\n                10000000000000000000,\n            )\n            return\n        except Exception:  # pylint: disable=broad-except\n            time.sleep(3)\n\n\ndef env_path_separator() -> str:\n    \"\"\"\n    Get the separator between path items in PATH variables, cross platform.\n\n    E.g. on Linux and MacOS, it returns ':', whereas on Windows ';'.\n    \"\"\"\n    if sys.platform == \"win32\":\n        return \";\"\n    else:\n        return \":\"\n\n\ndef random_string(length: int = 8) -> str:\n    \"\"\"Generate a random string.\n\n    :param length: how long random string should be\n\n    :return: random chars str\n    \"\"\"\n    return \"\".join(\n        random.choice(string.ascii_lowercase) for _ in range(length)  # nosec\n    )\n\n\ndef make_uri(addr: str, port: int):\n    \"\"\"Make uri from address and port.\"\"\"\n    return f\"{addr}:{port}\"\n\n\n@pytest.mark.integration\nclass UseGanache:\n    \"\"\"Inherit from this class to use Ganache.\"\"\"\n\n    @pytest.fixture(autouse=True)\n    def _start_ganache(self, ganache):\n        \"\"\"Start a Ganache image.\"\"\"\n\n\n@pytest.mark.integration\nclass UseSOEF:\n    \"\"\"Inherit from this class to use SOEF.\"\"\"\n\n    @pytest.fixture(autouse=True)\n    def _start_soef(self, soef):\n        \"\"\"Start an SOEF image.\"\"\"\n\n\n@pytest.mark.integration\nclass UseLocalFetchNode:\n    \"\"\"Inherit from this class to use a local Fetch ledger node.\"\"\"\n\n    @pytest.fixture(autouse=True)\n    def _start_fetchd(self, fetchd):\n        \"\"\"Start a Fetch ledger image.\"\"\"\n\n\n@pytest.fixture()\ndef change_directory():\n    \"\"\"Change directory and execute the test.\"\"\"\n    temporary_directory = tempfile.mkdtemp()\n    try:\n        with cd(temporary_directory):\n            yield temporary_directory\n    finally:\n        shutil.rmtree(temporary_directory)\n\n\n@pytest.fixture(params=[None, \"fake-password\"])\ndef password_or_none(request) -> Optional[str]:\n    \"\"\"\n    Return a password for testing purposes, including None.\n\n    Note that this is a parametrized fixture.\n    \"\"\"\n    return request.param\n\n\ndef method_scope(cls):\n    \"\"\"\n    Class decorator to make the setup/teardown to have the 'method' scope.\n\n    :param cls: the class. It must be a subclass of\n    :return:\n    \"\"\"\n    enforce(\n        issubclass(cls, BaseAEATestCase),\n        \"cannot use decorator if class is not instance of BaseAEATestCase\",\n    )\n    old_setup_class = cls.setup_class\n    old_teardown_class = cls.teardown_class\n    cls.setup_class = classmethod(lambda _cls: None)\n    cls.teardown_class = classmethod(lambda _cls: None)\n    cls.setup = lambda self: old_setup_class()\n    cls.teardown = lambda self: old_teardown_class()\n    return cls\n\n\ndef get_wealth_if_needed(address: Address, fetchai_api: FetchAIApi = None):\n    \"\"\"\n     Get wealth from fetch.ai faucet to specific address\n\n    :param: address: Addresse to be funded from faucet\n    \"\"\"\n    if fetchai_api is None:\n        fetchai_api = make_ledger_api(\n            FetchAICrypto.identifier, **FETCHAI_TESTNET_CONFIG\n        )\n\n    balance = fetchai_api.get_balance(address)\n    if balance == 0:\n        FetchAIFaucetApi().get_wealth(address)\n\n        timeout = 0\n        while timeout < 40 and balance == 0:\n            time.sleep(1)\n            timeout += 1\n            _balance = fetchai_api.get_balance(address)\n            balance = _balance if _balance is not None else 0\n\n\n@pytest.fixture(scope=\"session\", autouse=True)\ndef disable_logging_handlers_cleanup(request) -> Generator:\n    \"\"\"\n    Fix for pytest flaky crash, disable handlers cleanup.\n\n    Check https://github.com/fetchai/agents-aea/issues/2431\n    \"\"\"\n\n    def do_nothing(*args):\n        pass\n\n    with MonkeyPatch().context() as mp:\n        mp.setattr(logging.config, \"_clearExistingHandlers\", do_nothing)\n        yield\n"
  },
  {
    "path": "tests/data/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This test module contains the test data.\"\"\"\n"
  },
  {
    "path": "tests/data/aea-config.example.yaml",
    "content": "agent_name: myagent\nauthor: fetchai\nversion: 0.2.0\ndescription: An example of agent configuration file for testing purposes.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint: {}\nfingerprint_ignore_patterns: []\nconnections:\n- fetchai/oef:0.22.6\ncontracts: []\nprotocols:\n- fetchai/oef_search:1.1.7\n- fetchai/default:1.1.7\n- fetchai/tac:1.1.7\n- fetchai/fipa:1.1.7\nskills:\n- fetchai/echo:0.20.6\ndefault_connection: fetchai/oef:0.22.6\ndefault_ledger: cosmos\nrequired_ledgers:\n- cosmos\nlogging_config:\n  disable_existing_loggers: false\n  version: 1\nprivate_key_paths: {}\ndata_dir: .\ndependencies: {}"
  },
  {
    "path": "tests/data/aea-config.example_multipage.yaml",
    "content": "agent_name: myagent\nauthor: fetchai\nversion: 0.2.0\ndescription: An example of agent configuration file for testing purposes.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint: {}\nfingerprint_ignore_patterns: []\nconnections:\n- fetchai/oef:0.7.0\ncontracts: []\nprotocols:\n- fetchai/oef_search:0.4.0\n- fetchai/default:0.4.0\n- fetchai/tac:0.5.0\n- fetchai/fipa:0.5.0\nskills:\n- fetchai/echo:0.5.0\n- dummy_author/dummy:0.1.0\ndefault_connection: fetchai/oef:0.7.0\ndefault_ledger: cosmos\nrequired_ledgers:\n- cosmos\nlogging_config:\n  disable_existing_loggers: false\n  version: 1\nprivate_key_paths:\n   cosmos: cosmos_private_key.txt\n   ethereum: ethereum_private_key.txt\nconnection_private_key_paths:\n   cosmos: cosmos_private_key.txt\n   ethereum: ethereum_private_key.txt\ndependencies: {}\n---\npublic_id: dummy_author/dummy:0.1.0\ntype: skill\nbehaviours:\n  dummy:\n    args:\n      behaviour_arg_1: 1\n      behaviour_arg_2: '2'\nhandlers:\n  dummy:\n    args:\n      handler_arg_1: 1\n      handler_arg_2: '2'\n  dummy_internal:\n    args:\n      handler_arg_1: 1\n      handler_arg_2: '2'\nmodels:\n  dummy:\n    args:\n      model_arg_1: 1\n      model_arg_2: '2'\n...\n"
  },
  {
    "path": "tests/data/aea-config.example_w_keys.yaml",
    "content": "agent_name: myagent\nauthor: fetchai\nversion: 0.2.0\ndescription: An example of agent configuration file for testing purposes.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint: {}\nfingerprint_ignore_patterns: []\nconnections:\n- fetchai/oef:0.22.6\ncontracts: []\nprotocols:\n- fetchai/oef_search:1.1.7\n- fetchai/default:1.1.7\n- fetchai/tac:1.1.7\n- fetchai/fipa:1.1.7\nskills:\n- fetchai/echo:0.20.6\ndefault_connection: fetchai/oef:0.22.6\ndefault_ledger: cosmos\nrequired_ledgers:\n- cosmos\nlogging_config:\n  disable_existing_loggers: false\n  version: 1\nprivate_key_paths:\n   cosmos: cosmos_private_key.txt\n   ethereum: ethereum_private_key.txt\nconnection_private_key_paths:\n   cosmos: cosmos_private_key.txt\n   ethereum: ethereum_private_key.txt\ndependencies: {}"
  },
  {
    "path": "tests/data/certs/server.crt",
    "content": "-----BEGIN CERTIFICATE-----\nMIICsTCCAZkCFGqNcoSHEADDJ5wZBtczunKoFWBVMA0GCSqGSIb3DQEBCwUAMBQx\nEjAQBgNVBAMMCWxvY2FsaG9zdDAgFw0yMTA5MDYwOTU2MTVaGA8yMTIxMDgxMzA5\nNTYxNVowFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOC\nAQ8AMIIBCgKCAQEAxX8TpWN5cE9oGotbTlEDVst1at0ZgYlgKwCVconrOQ77AhD4\nMyJZ++Poy2i9N1JKYclT9ZrSRtqh+djILaCVeHHgwqFgwpGJuupunv/5o8fX9k1/\nYUs3MQou9STiOLS+B/MK25Fi/LUvr1ZYJzAViekgV1yv7Sn/n2mpQe66ByyNZt3D\nTzid9f3d7FHY6HBkxaoaUxkSIJeHcHy6qUXdiEeoPWBbkp6JjFqKW6mynwnDP4Wc\nzGerRtLo69rxtaaES0aboOjA6bk1Ab+4XmSH+Kv6r7CzArLFHJO+ZUU6Pqxd2ehR\nL9qicTzOQyN7ygVlBwZWpioOSRzGROgrNhQniQIDAQABMA0GCSqGSIb3DQEBCwUA\nA4IBAQBxSEAWtXQUq8qW8XHRcw1loBoxIus1+ajkMX9/pN0SFuNBq8P61TLtMjM1\nG0czcgyXVqjMFtudY+CJa6yn+WWnp6oqDkjcu8Z5SdFfM677pQwF4R1nylb1aLP+\nX+7NxVIs2pHNzYvxRm/OQ1Q6rVWVq3omludCcxHd3+y5kW5enG1Dp2yLXsdatNjj\n2DzLF2WNMVXuXmFC9GVZpSsP5qCYD8rfqNvLaV6oxZ+woJ+UX8Q5YlEB1/2LtRBf\nx+XiiKXY2h4ZTHGjCO+Pu6FKOxf4JxWoBirCe7WOjfOJUdQYLOk6nT+qSP8iLFaS\n/DBRpBw/kJjec5xedh2CZOEC8NLw\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "tests/data/certs/server.csr",
    "content": "-----BEGIN CERTIFICATE REQUEST-----\nMIICWTCCAUECAQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0B\nAQEFAAOCAQ8AMIIBCgKCAQEAxX8TpWN5cE9oGotbTlEDVst1at0ZgYlgKwCVconr\nOQ77AhD4MyJZ++Poy2i9N1JKYclT9ZrSRtqh+djILaCVeHHgwqFgwpGJuupunv/5\no8fX9k1/YUs3MQou9STiOLS+B/MK25Fi/LUvr1ZYJzAViekgV1yv7Sn/n2mpQe66\nByyNZt3DTzid9f3d7FHY6HBkxaoaUxkSIJeHcHy6qUXdiEeoPWBbkp6JjFqKW6my\nnwnDP4WczGerRtLo69rxtaaES0aboOjA6bk1Ab+4XmSH+Kv6r7CzArLFHJO+ZUU6\nPqxd2ehRL9qicTzOQyN7ygVlBwZWpioOSRzGROgrNhQniQIDAQABoAAwDQYJKoZI\nhvcNAQELBQADggEBAH9MeBQNrb081LoPDk3C/C4zH6BoVtxkQXoPXGv6+wijNju5\nwAUZc26VGdawW3Scqj9kboObi5NwI7o8ZMsOx2V8MT5FjSl79DoAszwww19J48J4\n6qGRPuph3c48Gz1eZCCQscaEG4pYqdL3aS6Jt/HmKkZGIAZvNGwzaBOGTIJTZHSU\n9W9gV3RAL1unLgZKYAmKVStFtCOjARbn0wlBOeT2nkqRsckACgxxDNAjDPmKVmUK\nx6BSPttFWIVc/FXvkIBpwbxKAlwK9amtko0VGgw3WC7kBq13/ijNeQV/PaqFbSWF\nMshUv0YLv0aKVwFN1oRYiDYuwSXyRK5PYW4VNhQ=\n-----END CERTIFICATE REQUEST-----\n"
  },
  {
    "path": "tests/data/certs/server.key",
    "content": "-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEAxX8TpWN5cE9oGotbTlEDVst1at0ZgYlgKwCVconrOQ77AhD4\nMyJZ++Poy2i9N1JKYclT9ZrSRtqh+djILaCVeHHgwqFgwpGJuupunv/5o8fX9k1/\nYUs3MQou9STiOLS+B/MK25Fi/LUvr1ZYJzAViekgV1yv7Sn/n2mpQe66ByyNZt3D\nTzid9f3d7FHY6HBkxaoaUxkSIJeHcHy6qUXdiEeoPWBbkp6JjFqKW6mynwnDP4Wc\nzGerRtLo69rxtaaES0aboOjA6bk1Ab+4XmSH+Kv6r7CzArLFHJO+ZUU6Pqxd2ehR\nL9qicTzOQyN7ygVlBwZWpioOSRzGROgrNhQniQIDAQABAoIBAHao81Tbf4tLKnFI\naYOUiT0M4W9jiH+b2nv7zc8TrpCJv6ZuK7INYaNGPAh61bT3bFl0bU2Tx+NqWQeU\niDFh2myTf0dxToGYj/gOAojlo0gUOl1yEqaSWobMZ4pCrukDL2n3TP6/S4oqEox2\nhGCHM2m4+AWFWu5T3ZIaGefTV1IXEqghj7L+53UI4qksnJDEQ9GT34KnlJhQKZmw\nE6St5F2xfXTKq6EWBIC23RNo4kAgDHBTE8MVRZdUEPmipf564NEVtxLFTKUi+tue\nGbiagtCWeGeEGZ2uFyr+HWIQUz4qLcMR6hp+hxh2VP3U52/0I5PKngSO0G6IemMD\nHxj6DEECgYEA/A7Vjy9Or7DEIWZcsm44kyl79qUbzAlqDtG2RmOc6DDiWM3jQ/OR\nbOW4wNCFxv/KOsoeB7FxP7kKTupwj2u1Y9krAsHifXyFtHilZy9yTo4h8wHy40ae\n4B8sP4+xEhppfjoFg5ySdF1BF1prwh34YSlFEkD+Q3Uu4Hr3+Ph8Pk8CgYEAyJXL\nTKT3zUUD6BhtJ74jtmwSW7SZx+lgbgzEtAHTwcZZllaTCdBY6H3im5pJ9LettymT\nPtSVn2EYVULtJJiT0qm3rqkqDQ8QImdx+T2V/GL9Oo8T1LdYud2J+f7+pEAn9Ud3\n/XL6kZUXm/CpwIGIx3tB09kSsLxCGRnyrdhR3qcCgYEA3TCLWg5yp5ygUIsKV45/\n2SxzWzsCzKeKSZzgrp5lqCCV0MZEZHIOsRhaa+HRM5NuPO73MVsWfYv9Lsluo30q\nfYeqxc2s2t/2WSvyQj2RurvhsOWJ5sYnT5grdU+8XJ2O67Uw95DjuHfJUhwIKh2w\nxFq6AU3Fkx73VwiyKOqt5OMCgYBiIh7/VWpCy/QYVfL5UaXpNsBYi2f9DSl3Tdni\nc05lbCQiUCLJ11vYCtaV6Asspbxgcv+t6pV1Dyy3cfHRSLBxjUTnN63yC5+KJW/2\nT3IUs11Oi/dYx4aqED/TxjRQqW6jKp8CqYD7PqT5TunN29HOPng7K+VgAAqaez5m\nXQHY2wKBgErzDsGHH+0XktR7HCZJMmuc/1HnDzfENnfpRIjjlwJF8xn/HymS0OP+\n3AsfN0g60Qutng62wthkzeUheD3UM2nwpmatuP4UXUFGkGcwmCdvzMf/SvyKIjmQ\nMxiu8flSlCWlvP5e+Rrmd3RitOXeCqZLKbywMnlWHHfL33d1LWlf\n-----END RSA PRIVATE KEY-----\n"
  },
  {
    "path": "tests/data/cosmos_private_key.txt",
    "content": "81b0352f99a08a754b56e529dda965c4ce974edb6db7e90035e01ed193e1b7bc"
  },
  {
    "path": "tests/data/custom_crypto.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains a custom crypto class for testing purposes.\"\"\"\nfrom typing import Any, Optional, Tuple\n\nfrom aea.common import Address\nfrom aea.crypto.base import Crypto, EntityClass\n\n\nclass CustomCrypto(Crypto[EntityClass]):\n    \"\"\"This is a custom crypto class for testing purposes..\"\"\"\n\n    @classmethod\n    def generate_private_key(cls) -> EntityClass:\n        \"\"\"Generare private key.\"\"\"\n        pass\n\n    @classmethod\n    def load_private_key_from_path(\n        cls, file_name: str, password: Optional[str] = None\n    ) -> Any:\n        \"\"\"\n        Load a private key in hex format from a file.\n\n        :param file_name: the path to the hex file.\n        :param password: the password to encrypt/decrypt the private key.\n        :return: the Entity.\n        \"\"\"\n        pass\n\n    @property\n    def public_key(self) -> str:\n        \"\"\"Get public key.\"\"\"\n        pass\n\n    @property\n    def address(self) -> str:\n        \"\"\"Get address.\"\"\"\n        pass\n\n    @property\n    def private_key(self) -> str:\n        \"\"\"Get private key.\"\"\"\n        pass\n\n    @classmethod\n    def get_address_from_public_key(cls, public_key: str) -> str:\n        \"\"\"\n        Get address from public key.\n\n        :param public_key: the public key.\n        :return: the address\n        \"\"\"\n        pass\n\n    def sign_message(self, message: bytes, is_deprecated_mode: bool = False) -> str:\n        \"\"\"\n        Sign message.\n\n        :param message: the message\n        :param is_deprecated_mode: whether or not deprecated signing mode is used.\n        :return: signed message string\n        \"\"\"\n        pass\n\n    def sign_transaction(self, transaction: Any) -> Any:\n        \"\"\"\n        Sign transaction.\n\n        :param transaction: the transaction to be signed\n        :return: the signed transaction\n        \"\"\"\n        pass\n\n    def recover_message(\n        self, message: bytes, signature: str, is_deprecated_mode: bool = False\n    ) -> Tuple[Address, ...]:\n        \"\"\"\n        Recover message.\n\n        :param message: the message\n        :param signature: the signature\n        :param is_deprecated_mode: whether or not it is deprecated\n        \"\"\"\n        pass\n\n    def encrypt(self, password: str) -> str:\n        \"\"\"\n        Encrypt the private key and return in json.\n\n        :param private_key: the raw private key.\n        :param password: the password to decrypt.\n        :return: json string containing encrypted private key.\n        \"\"\"\n\n    @classmethod\n    def decrypt(cls, keyfile_json: str, password: str) -> str:\n        \"\"\"\n        Decrypt the private key and return in raw form.\n\n        :param keyfile_json: json string containing encrypted private key.\n        :param password: the password to decrypt.\n        :return: the raw private key.\n        \"\"\"\n"
  },
  {
    "path": "tests/data/dependencies_skill/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains a skill to test dependencies format.\"\"\"\n"
  },
  {
    "path": "tests/data/dependencies_skill/skill.yaml",
    "content": "name: dummy\nauthor: fetchai\nversion: 0.1.0\ntype: skill\ndescription: a skill for testing purposes.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  __init__.py: QmVLEKUHaEdU1fcEvwiPYogLC8FjoKaZDzmq8UXr1rf9zM\nfingerprint_ignore_patterns: []\ncontracts: []\nprotocols:\n- fetchai/default:1.1.7\nskills: []\nbehaviours: {}\nhandlers: {}\nmodels: {}\ndependencies:\n  dep1:\n    version: ==1.0.0\n  dep2:\n    version: ~=1.1.2\n  dep3:\n    version: '>=1.10.11a1'\n  dep4:\n    version: ==1.11.12b2\n  dep5:\n    version: '>=1.4.5.0'\n  dep6:\n    index: https://test.pypi.org/simple\n  dep7:\n    git: https://github.com/a-random-username/a-repository.git\n    ref: master\n  dep8:\n    git: https://github.com/a-random-username/a-repository.git\n    index: https://test.pypi.org/simple\n    ref: master\nis_abstract: false\nconnections: []\n"
  },
  {
    "path": "tests/data/dot_env_file",
    "content": "TEST=yes\n"
  },
  {
    "path": "tests/data/dummy_aea/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2020 fetchai\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains a dummy aea.\"\"\"\n"
  },
  {
    "path": "tests/data/dummy_aea/aea-config.yaml",
    "content": "agent_name: Agent0\nauthor: dummy_author\nversion: 1.0.0\ndescription: dummy_aea agent description\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint: {}\nfingerprint_ignore_patterns: []\nconnections:\n- fetchai/local:0.21.6\n- fetchai/p2p_libp2p:0.27.5\ncontracts:\n- fetchai/erc1155:0.23.3\nprotocols:\n- fetchai/acn:1.1.7\n- fetchai/default:1.1.7\n- fetchai/fipa:1.1.7\n- fetchai/oef_search:1.1.7\n- fetchai/signing:1.1.7\n- fetchai/state_update:1.1.7\nskills:\n- dummy_author/dummy:0.1.0\n- fetchai/error:0.18.6\ndefault_connection: fetchai/local:0.21.6\ndefault_ledger: fetchai\nrequired_ledgers:\n- fetchai\nlogging_config:\n  disable_existing_loggers: false\n  version: 1\nprivate_key_paths:\n  cosmos: cosmos_private_key.txt\n  ethereum: ethereum_private_key.txt\n  fetchai: fetchai_private_key.txt\nconnection_private_key_paths:\n  cosmos: cosmos_private_key.txt\n  ethereum: ethereum_private_key.txt\n  fetchai: fetchai_private_key.txt\ndefault_routing: {}\ndependencies: {}\n"
  },
  {
    "path": "tests/data/dummy_aea/bad_requirements.txt",
    "content": "@#%$^&*^\n"
  },
  {
    "path": "tests/data/dummy_aea/connections/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the implementation of the connections.\"\"\"\n"
  },
  {
    "path": "tests/data/dummy_aea/contracts/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the implementation of the contracts.\"\"\"\n"
  },
  {
    "path": "tests/data/dummy_aea/cosmos_private_key.txt",
    "content": "0988d2460bea9d156aea4bb0664183291a0ba959fe3ca59780faa0e4d1f15686"
  },
  {
    "path": "tests/data/dummy_aea/default_private_key.pem",
    "content": "-----BEGIN EC PRIVATE KEY-----\nMIGkAgEBBDBPDMr3mGOklmP20XAcuJWXyi7MrqEpXnIpLMSrlxRfCt+xToUULRuc\n13ZfEf6/h+ygBwYFK4EEACKhZANiAASCAxxhmfAN7IU/7TBnmadwFJzNYuIcBCZW\n0vyazEyxuZCR0PeSJELVNNr0XCjV65ph+2g48rv/RvrBLC60fglCOVBkZcccWSLD\nS6yukJFBG+z27TE3+O4M0HwC83mLKFc=\n-----END EC PRIVATE KEY-----\n"
  },
  {
    "path": "tests/data/dummy_aea/ethereum_private_key.txt",
    "content": "0x6F611408F7EF304947621C51A4B7D84A13A2B9786E9F984DA790A096E8260C64"
  },
  {
    "path": "tests/data/dummy_aea/fetchai_private_key.txt",
    "content": "66cec3f67a5fa81b6eb1c3c678dd60bb6959e3930c452397196bd63b45af5f00"
  },
  {
    "path": "tests/data/dummy_aea/protocols/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the implementation of the protocols.\"\"\"\n"
  },
  {
    "path": "tests/data/dummy_aea/requirements.txt",
    "content": "protobuf\n"
  },
  {
    "path": "tests/data/dummy_aea/skills/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the implementation of the skills.\"\"\"\n"
  },
  {
    "path": "tests/data/dummy_aea/vendor/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Vendor dependencies.\"\"\"\n"
  },
  {
    "path": "tests/data/dummy_aea/vendor/fetchai/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Vendor dependencies from 'fetchai'.\"\"\"\n"
  },
  {
    "path": "tests/data/dummy_aea/vendor/fetchai/connections/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the implementation of the connections.\"\"\"\n"
  },
  {
    "path": "tests/data/dummy_aea/vendor/fetchai/contracts/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the implementation of the contracts.\"\"\"\n"
  },
  {
    "path": "tests/data/dummy_aea/vendor/fetchai/protocols/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the implementation of the protocols.\"\"\"\n"
  },
  {
    "path": "tests/data/dummy_aea/vendor/fetchai/skills/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the implementation of the skills.\"\"\"\n"
  },
  {
    "path": "tests/data/dummy_connection/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains a dummy connection for an AEA.\"\"\"\n"
  },
  {
    "path": "tests/data/dummy_connection/connection.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the implementation of a 'dummy' connection useful for testing.\"\"\"\n\nimport asyncio\nfrom concurrent.futures._base import CancelledError\nfrom typing import Optional\n\nfrom aea.configurations.base import PublicId\nfrom aea.connections.base import Connection, ConnectionStates\nfrom aea.mail.base import Envelope\n\n\nclass DummyConnection(Connection):\n    \"\"\"A dummy connection that just stores the messages.\"\"\"\n\n    connection_id = PublicId.from_str(\"fetchai/dummy:0.1.0\")\n\n    def __init__(self, **kwargs):\n        \"\"\"Initialize.\"\"\"\n        super().__init__(**kwargs)\n        self.state = ConnectionStates.disconnected\n        self._queue = None\n\n    async def connect(self, *args, **kwargs):\n        \"\"\"Connect.\"\"\"\n        self._queue = asyncio.Queue()\n        self.state = ConnectionStates.connected\n\n    async def disconnect(self, *args, **kwargs):\n        \"\"\"Disconnect.\"\"\"\n        assert self._queue is not None\n        await self._queue.put(None)\n        self.state = ConnectionStates.disconnected\n\n    async def send(self, envelope: \"Envelope\"):\n        \"\"\"Send an envelope.\"\"\"\n        assert self._queue is not None\n        self._queue.put_nowait(envelope)\n\n    async def receive(self, *args, **kwargs) -> Optional[\"Envelope\"]:\n        \"\"\"Receive an envelope.\"\"\"\n        try:\n            assert self._queue is not None\n            envelope = await self._queue.get()\n            if envelope is None:\n                return None\n            return envelope\n        except CancelledError:\n            return None\n        except Exception as e:\n            print(str(e))\n            return None\n\n    def put(self, envelope: Envelope):\n        \"\"\"Put an envelope in the queue.\"\"\"\n        assert self._queue is not None\n        self._queue.put_nowait(envelope)\n"
  },
  {
    "path": "tests/data/dummy_connection/connection.yaml",
    "content": "name: dummy\nauthor: fetchai\nversion: 0.1.0\ntype: connection\ndescription: dummy_connection connection description.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  __init__.py: QmVLvYQsVuMRPvU3w9UzZzEGjGa5iP5SWwDwTKCuRMzRrQ\n  connection.py: QmergefLxWSmAPqn4DZiKEa8xS4u6F8Wp46QqsCv6UMnKq\nfingerprint_ignore_patterns: []\nbuild_entrypoint: path/to/script.py\nconnections: []\nprotocols: []\nclass_name: DummyConnection\nconfig: {}\nexcluded_protocols: []\nrestricted_to_protocols:\n- fetchai/default:1.1.7\ndependencies:\n  dep1:\n    version: ==1.0.0\n  dep2:\n    version: ~=1.1.2\n  dep3:\n    version: '>=1.10.11a1'\n  dep4:\n    version: <=1.11.12b2\nis_abstract: false\ncert_requests:\n- identifier: cert_id_1\n  ledger_id: some_ledger_id\n  message_format: '{public_key}'\n  not_after: '2020-01-02'\n  not_before: '2020-01-01'\n  public_key: key_id\n  save_path: /source/some/path_1\n- identifier: cert_id_2\n  ledger_id: some_ledger_id\n  message_format: '{public_key}'\n  not_after: '2020-01-02'\n  not_before: '2020-01-01'\n  public_key: '0xABCDEF123456'\n  save_path: /source/some/path_2\n"
  },
  {
    "path": "tests/data/dummy_contract/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains a dummy contract for an AEA.\"\"\"\n"
  },
  {
    "path": "tests/data/dummy_contract/build/some.json",
    "content": "{\n  \"contractName\": \"erc1155\",\n  \"abi\": [\n    {\n      \"name\": \"TransferSingle\",\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_operator\",\n          \"indexed\": true\n        },\n        {\n          \"type\": \"address\",\n          \"name\": \"_from\",\n          \"indexed\": true\n        },\n        {\n          \"type\": \"address\",\n          \"name\": \"_to\",\n          \"indexed\": true\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_id\",\n          \"indexed\": false\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_value\",\n          \"indexed\": false\n        }\n      ],\n      \"anonymous\": false,\n      \"type\": \"event\"\n    },\n    {\n      \"name\": \"TransferBatch\",\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_operator\",\n          \"indexed\": true\n        },\n        {\n          \"type\": \"address\",\n          \"name\": \"_from\",\n          \"indexed\": true\n        },\n        {\n          \"type\": \"address\",\n          \"name\": \"_to\",\n          \"indexed\": true\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_ids\",\n          \"indexed\": false\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_values\",\n          \"indexed\": false\n        }\n      ],\n      \"anonymous\": false,\n      \"type\": \"event\"\n    },\n    {\n      \"name\": \"ApprovalForAll\",\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_owner\",\n          \"indexed\": true\n        },\n        {\n          \"type\": \"address\",\n          \"name\": \"_operator\",\n          \"indexed\": true\n        },\n        {\n          \"type\": \"bool\",\n          \"name\": \"_approved\",\n          \"indexed\": false\n        }\n      ],\n      \"anonymous\": false,\n      \"type\": \"event\"\n    },\n    {\n      \"name\": \"URI\",\n      \"inputs\": [\n        {\n          \"type\": \"string\",\n          \"name\": \"_value\",\n          \"indexed\": false\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_id\",\n          \"indexed\": true\n        }\n      ],\n      \"anonymous\": false,\n      \"type\": \"event\"\n    },\n    {\n      \"outputs\": [],\n      \"inputs\": [],\n      \"constant\": false,\n      \"payable\": false,\n      \"type\": \"constructor\"\n    },\n    {\n      \"name\": \"getAddress\",\n      \"outputs\": [\n        {\n          \"type\": \"bytes32\",\n          \"name\": \"out\"\n        }\n      ],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_addr\"\n        }\n      ],\n      \"constant\": true,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 370\n    },\n    {\n      \"name\": \"getHash\",\n      \"outputs\": [\n        {\n          \"type\": \"bytes32\",\n          \"name\": \"out\"\n        }\n      ],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_from\"\n        },\n        {\n          \"type\": \"address\",\n          \"name\": \"_to\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_ids\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_from_supplies\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_to_supplies\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_value_eth\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_nonce\"\n        }\n      ],\n      \"constant\": true,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 11446\n    },\n    {\n      \"name\": \"getSingleHash\",\n      \"outputs\": [\n        {\n          \"type\": \"bytes32\",\n          \"name\": \"out\"\n        }\n      ],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_from\"\n        },\n        {\n          \"type\": \"address\",\n          \"name\": \"_to\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_id\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_from_supply\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_to_supply\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_value_eth\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_nonce\"\n        }\n      ],\n      \"constant\": true,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 2041\n    },\n    {\n      \"name\": \"supportsInterface\",\n      \"outputs\": [\n        {\n          \"type\": \"bool\",\n          \"name\": \"out\"\n        }\n      ],\n      \"inputs\": [\n        {\n          \"type\": \"bytes32\",\n          \"name\": \"_interfaceID\"\n        }\n      ],\n      \"constant\": true,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 868\n    },\n    {\n      \"name\": \"is_nonce_used\",\n      \"outputs\": [\n        {\n          \"type\": \"bool\",\n          \"name\": \"out\"\n        }\n      ],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"addr\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"nonce\"\n        }\n      ],\n      \"constant\": true,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 1052\n    },\n    {\n      \"name\": \"is_token_id_exists\",\n      \"outputs\": [\n        {\n          \"type\": \"bool\",\n          \"name\": \"out\"\n        }\n      ],\n      \"inputs\": [\n        {\n          \"type\": \"uint256\",\n          \"name\": \"token_id\"\n        }\n      ],\n      \"constant\": true,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 928\n    },\n    {\n      \"name\": \"safeTransferFrom\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_from\"\n        },\n        {\n          \"type\": \"address\",\n          \"name\": \"_to\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_id\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_value\"\n        },\n        {\n          \"type\": \"bytes\",\n          \"name\": \"_data\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 80803\n    },\n    {\n      \"name\": \"safeBatchTransferFrom\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_from\"\n        },\n        {\n          \"type\": \"address\",\n          \"name\": \"_to\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_ids\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_values\"\n        },\n        {\n          \"type\": \"bytes\",\n          \"name\": \"_data\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 748184\n    },\n    {\n      \"name\": \"balanceOf\",\n      \"outputs\": [\n        {\n          \"type\": \"uint256\",\n          \"name\": \"out\"\n        }\n      ],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_owner\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_id\"\n        }\n      ],\n      \"constant\": true,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 1172\n    },\n    {\n      \"name\": \"balanceOfBatch\",\n      \"outputs\": [\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"out\"\n        }\n      ],\n      \"inputs\": [\n        {\n          \"type\": \"address[10]\",\n          \"name\": \"_owner\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_ids\"\n        }\n      ],\n      \"constant\": true,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 7524\n    },\n    {\n      \"name\": \"setApprovalForAll\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_operator\"\n        },\n        {\n          \"type\": \"bool\",\n          \"name\": \"_approved\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 38136\n    },\n    {\n      \"name\": \"isApprovedForAll\",\n      \"outputs\": [\n        {\n          \"type\": \"bool\",\n          \"name\": \"out\"\n        }\n      ],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_owner\"\n        },\n        {\n          \"type\": \"address\",\n          \"name\": \"_operator\"\n        }\n      ],\n      \"constant\": true,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 1301\n    },\n    {\n      \"name\": \"createSingle\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_item_owner\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_id\"\n        },\n        {\n          \"type\": \"string\",\n          \"name\": \"_path\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 597461\n    },\n    {\n      \"name\": \"createBatch\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_items_owner\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_ids\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 927926\n    },\n    {\n      \"name\": \"mint\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_to\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_id\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_supply\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": false,\n      \"type\": \"function\"\n    },\n    {\n      \"name\": \"mint\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_to\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_id\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_supply\"\n        },\n        {\n          \"type\": \"bytes\",\n          \"name\": \"_data\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": false,\n      \"type\": \"function\"\n    },\n    {\n      \"name\": \"mintBatch\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_to\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_ids\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_supplies\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": false,\n      \"type\": \"function\"\n    },\n    {\n      \"name\": \"mintBatch\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_to\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_ids\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_supplies\"\n        },\n        {\n          \"type\": \"bytes\",\n          \"name\": \"_data\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": false,\n      \"type\": \"function\"\n    },\n    {\n      \"name\": \"burn\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_id\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_supply\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 40353\n    },\n    {\n      \"name\": \"burnBatch\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_ids\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_supplies\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 382149\n    },\n    {\n      \"name\": \"tradeBatch\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_from\"\n        },\n        {\n          \"type\": \"address\",\n          \"name\": \"_to\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_ids\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_from_supplies\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_to_supplies\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_value_eth\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_nonce\"\n        },\n        {\n          \"type\": \"bytes\",\n          \"name\": \"_signature\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": true,\n      \"type\": \"function\"\n    },\n    {\n      \"name\": \"tradeBatch\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_from\"\n        },\n        {\n          \"type\": \"address\",\n          \"name\": \"_to\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_ids\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_from_supplies\"\n        },\n        {\n          \"type\": \"uint256[10]\",\n          \"name\": \"_to_supplies\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_value_eth\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_nonce\"\n        },\n        {\n          \"type\": \"bytes\",\n          \"name\": \"_signature\"\n        },\n        {\n          \"type\": \"bytes\",\n          \"name\": \"_data\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": true,\n      \"type\": \"function\"\n    },\n    {\n      \"name\": \"trade\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_from\"\n        },\n        {\n          \"type\": \"address\",\n          \"name\": \"_to\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_id\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_from_supply\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_to_supply\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_value_eth\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_nonce\"\n        },\n        {\n          \"type\": \"bytes\",\n          \"name\": \"_signature\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": true,\n      \"type\": \"function\"\n    },\n    {\n      \"name\": \"trade\",\n      \"outputs\": [],\n      \"inputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"_from\"\n        },\n        {\n          \"type\": \"address\",\n          \"name\": \"_to\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_id\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_from_supply\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_to_supply\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_value_eth\"\n        },\n        {\n          \"type\": \"uint256\",\n          \"name\": \"_nonce\"\n        },\n        {\n          \"type\": \"bytes\",\n          \"name\": \"_signature\"\n        },\n        {\n          \"type\": \"bytes\",\n          \"name\": \"_data\"\n        }\n      ],\n      \"constant\": false,\n      \"payable\": true,\n      \"type\": \"function\"\n    },\n    {\n      \"name\": \"owner\",\n      \"outputs\": [\n        {\n          \"type\": \"address\",\n          \"name\": \"out\"\n        }\n      ],\n      \"inputs\": [],\n      \"constant\": true,\n      \"payable\": false,\n      \"type\": \"function\",\n      \"gas\": 1263\n    }\n  ],\n  \"bytecode\": \"0x740100000000000000000000000000000000000000006020526f7fffffffffffffffffffffffffffffff6040527fffffffffffffffffffffffffffffffff8000000000000000000000000000000060605274012a05f1fffffffffffffffffffffffffdabf41c006080527ffffffffffffffffffffffffed5fa0e000000000000000000000000000000000060a052341561009857600080fd5b6000600155600160006301ffc9a760e05260c052604060c020556001600063d9b67a2660e05260c052604060c020553360025561405a56600035601c52740100000000000000000000000000000000000000006020526f7fffffffffffffffffffffffffffffff6040527fffffffffffffffffffffffffffffffff8000000000000000000000000000000060605274012a05f1fffffffffffffffffffffffffdabf41c006080527ffffffffffffffffffffffffed5fa0e000000000000000000000000000000000060a05263ae22c57d60005114156100d45734156100ac57600080fd5b60043560205181106100bd57600080fd5b50600435610140526101405160005260206000f350005b600015610313575b610580526101405261016052610180526101a0526101c0526101e05261020052610220526102405261026052610280526102a0526102c0526102e05261030052610320526103405261036052610380526103a0526103c0526103e05261040052610420526104405261046052610480526104a0526104c0526104e052610500526105205261054052610560526000610180516020826105c00101526020810190506102c0516020826105c0010152602081019050610400516020826105c0010152602081019050806105c0526105c090508051602082012090506105a0526106606000600a818352015b610660511515156102765760006105a05160208261068001015260208101905061018061066051600a81106101fa57600080fd5b60200201516020826106800101526020810190506102c061066051600a811061022257600080fd5b602002015160208261068001015260208101905061040061066051600a811061024a57600080fd5b6020020151602082610680010152602081019050806106805261068090508051602082012090506105a0525b5b81516001018083528114156101c6575b5050600061014051602082610760010152602081019050610160516020826107600101526020810190506105a0516020826107600101526020810190506105405160208261076001015260208101905061056051602082610760010152602081019050806107605261076090508051602082012090506107405261074051600052600051610580515650005b634a6f823360005114156105c457341561032c57600080fd5b600435602051811061033d57600080fd5b50602435602051811061034f57600080fd5b506000610120525b602061012051016101205261012061012051101561037457610357565b6000610120525b60206101205101610120526101206101205110156103985761037b565b6000610120525b60206101205101610120526101206101205110156103bc5761039f565b6373ad25716101405260043561016052602435610180526101a0604480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250506102e061018480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250506104206102c480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250506104043561056052610424356105805261058051610560516105405161052051610500516104e0516104c0516104a05161048051610460516104405161042051610400516103e0516103c0516103a05161038051610360516103405161032051610300516102e0516102c0516102a05161028051610260516102405161022051610200516101e0516101c0516101a0516101805161016051600658016100dc565b6105e0526105e05160005260206000f350005b600015610909575b610580526101405261016052610180526101a0526101c0526101e05261020052610220526102405261026052610280526102a0526102c0526102e05261030052610320526103405261036052610380526103a0526103c0526103e05261040052610420526104405261046052610480526104a0526104c0526104e052610500526105205261054052610560526000610140516020826105c0010152602081019050610160516020826105c0010152602081019050610180516020826105c00101526020810190506101a0516020826105c00101526020810190506101c0516020826105c00101526020810190506101e0516020826105c0010152602081019050610200516020826105c0010152602081019050610220516020826105c0010152602081019050610240516020826105c0010152602081019050610260516020826105c0010152602081019050610280516020826105c00101526020810190506102a0516020826105c00101526020810190506102c0516020826105c00101526020810190506102e0516020826105c0010152602081019050610300516020826105c0010152602081019050610320516020826105c0010152602081019050610340516020826105c0010152602081019050610360516020826105c0010152602081019050610380516020826105c00101526020810190506103a0516020826105c00101526020810190506103c0516020826105c00101526020810190506103e0516020826105c0010152602081019050610400516020826105c0010152602081019050610420516020826105c0010152602081019050610440516020826105c0010152602081019050610460516020826105c0010152602081019050610480516020826105c00101526020810190506104a0516020826105c00101526020810190506104c0516020826105c00101526020810190506104e0516020826105c0010152602081019050610500516020826105c0010152602081019050610520516020826105c0010152602081019050610540516020826105c0010152602081019050610560516020826105c0010152602081019050806105c0526105c090508051602082012090506105a0526105a051600052600051610580515650005b6000156109e1575b610220526101405261016052610180526101a0526101c0526101e0526102005260006101405160208261026001015260208101905061016051602082610260010152602081019050610180516020826102600101526020810190506101a0516020826102600101526020810190506101c0516020826102600101526020810190506101e05160208261026001015260208101905061020051602082610260010152602081019050806102605261026090508051602082012090506102405261024051600052600051610220515650005b6310660e866000511415610a905734156109fa57600080fd5b6004356020518110610a0b57600080fd5b506024356020518110610a1d57600080fd5b5063155960636101405260043561016052602435610180526044356101a0526064356101c0526084356101e05260a4356102005260c4356102205261022051610200516101e0516101c0516101a051610180516101605160065801610911565b610280526102805160005260206000f350005b600015610cf2575b6101805261014052610160526101a0526000610240525b6101a05160206001820306601f820103905061024051101515610ad157610aea565b610240516101c001526102405160200161024052610aaf565b60005060416101a0511815610b0757600060005260005161018051565b6101a0602060006020835103811315610b1f57600080fd5b046020026020018101519050610280526101a0602060206020835103811315610b4757600080fd5b0460200260200181015190506102a05260406001602082066103a0016101a0518284011115610b7557600080fd5b6041806103c0826020602088068803016101a001600060046018f1505081815280905090509050806020015160008251806020901315610bb457600080fd5b8091901215610bc257600080fd5b606051816020036101000a830480604051901315610bdf57600080fd5b8091901215610bed57600080fd5b9050905090506102c052601b6102c0511215610c30576102c0606051601b82510180604051901315610c1e57600080fd5b8091901215610c2c57600080fd5b8152505b610480601b8152601c81602001525060006104605261046061012060006002818352015b6101205160200261048001516102c0511415610c735760018352610c84565b5b8151600101808352811415610c54575b5050506104605160011415610ce257610140516104c0526102c0516000811215610cad57600080fd5b6104e05261028051610500526102a05161052052602060c060806104c060006001610bb8f15060c05160005260005161018051565b6000600052600051610180515650005b600015610db3575b6101605261014052610140517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff806000811215610d3e578060000360020a8204610d45565b8060020a82025b90509050604051811115610d5857600080fd5b61018052700100000000000000000000000000000000610d7757600080fd5b7001000000000000000000000000000000006101405106604051811115610d9d57600080fd5b6101a05261018051600052600051610160515650005b63f17535506000511415610de8573415610dcc57600080fd5b600060043560e05260c052604060c0205460005260206000f350005b63ac2a2e216000511415610e3d573415610e0157600080fd5b6004356020518110610e1257600080fd5b50600460043560e05260c052604060c02060243560e05260c052604060c0205460005260206000f350005b634026b7556000511415610e72573415610e5657600080fd5b600760043560e05260c052604060c0205460005260206000f350005b63f242432a6000511415611135573415610e8b57600080fd5b6004356020518110610e9c57600080fd5b506024356020518110610eae57600080fd5b5061012060843560040161014037610100608435600401351115610ed157600080fd5b600660043560e05260c052604060c0203360e05260c052604060c02054336004351417610efd57600080fd5b6308c379a06102805260206102a05260206102c0527f43616e6e6f74207472616e7366657220746f207a65726f20616464726573732e6102e0526102c050600060243518610f4c57608461029cfd5b6308c379a0610320526020610340526012610360527f4e6f7420656e6f75676820746f6b656e732e00000000000000000000000000006103805261036050606435600360043560e05260c052604060c02060443560e05260c052604060c020541015610fb957608461033cfd5b600360043560e05260c052604060c02060443560e05260c052604060c02060643581541015610fe757600080fd5b606435815403815550600360243560e05260c052604060c02060443560e05260c052604060c0208054606435825401101561102157600080fd5b6064358154018155506044356103c0526064356103e052602435600435337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6260406103c0a460006024353b1115611133576024353b61107f57600080fd5b602435301861108d57600080fd5b60206106406101c460a063f23a6e6161042052336104405260043561046052604435610480526064356104a052806104c052610140808051602001808461044001828460006004600a8704601201f16110e557600080fd5b50508051820160206001820306601f820103905060200191505061043c905060006024355af161111457600080fd5b600050610640516104005263f23a6e61610400511461113257600080fd5b5b005b63cf36e535600051141561163c57341561114e57600080fd5b600435602051811061115f57600080fd5b50602435602051811061117157600080fd5b506000610120525b602061012051016101205261012061012051101561119657611179565b6000610120525b60206101205101610120526101206101205110156111ba5761119d565b6101206102c435600401610140376101006102c4356004013511156111de57600080fd5b600660043560e05260c052604060c0203360e05260c052604060c0205433600435141761120a57600080fd5b6308c379a06102805260206102a05260206102c0527f43616e6e6f74207472616e7366657220746f207a65726f20616464726573732e6102e0526102c05060006024351861125957608461029cfd5b6103206000600a818352015b604461032051600a811061127857600080fd5b60200201356103405261018461032051600a811061129557600080fd5b6020020135600360043560e05260c052604060c0206103405160e05260c052604060c0205410156112c557600080fd5b5b8151600101808352811415611265575b505060443561036052606435610380526084356103a05260a4356103c05260c4356103e05260e435610400526101043561042052610124356104405261014435610460526101643561048052610184356104a0526101a4356104c0526101c4356104e0526101e435610500526102043561052052610224356105405261024435610560526102643561058052610284356105a0526102a4356105c052602435600435337f514c24e4790d7c31a095a1688a73a01f28d936a9a85d806ba95970d8ee88efa8610280610360a46105e06000600a818352015b60446105e051600a81106113c057600080fd5b602002013561060052600360043560e05260c052604060c0206106005160e05260c052604060c0206101846105e051600a81106113fc57600080fd5b60200201358154101561140e57600080fd5b6101846105e051600a811061142257600080fd5b6020020135815403815550600360243560e05260c052604060c0206106005160e05260c052604060c02080546101846105e051600a811061146257600080fd5b6020020135825401101561147557600080fd5b6101846105e051600a811061148957600080fd5b60200201358154018155505b81516001018083528114156113ad575b505060006024353b111561163a576024353b6114c057600080fd5b60243530186114ce57600080fd5b6020610aa06104046102e063a3bfc206610640523361066052600435610680526106a0604480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250506107e061018480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250508061092052610140808051602001808461066001828460006004600a8704601201f16115ec57600080fd5b50508051820160206001820306601f820103905060200191505061065c905060006024355af161161b57600080fd5b600050610aa0516106205263e324a00d610620511461163957600080fd5b5b005b62fdd58e600051141561169057341561165457600080fd5b600435602051811061166557600080fd5b50600360043560e05260c052604060c02060243560e05260c052604060c0205460005260206000f350005b63fbe31aea60005114156117935734156116a957600080fd5b6000610120525b610120516004013560205181106116c657600080fd5b5060206101205101610120526101206101205110156116e4576116b0565b6000610120525b6020610120510161012052610120610120511015611708576116eb565b6102806000600a818352015b6003600461028051600a811061172957600080fd5b602002013560e05260c052604060c02061014461028051600a811061174d57600080fd5b602002013560e05260c052604060c0205461014061028051600a811061177257600080fd5b60200201525b8151600101808352811415611714575b5050610140610140f3005b63a22cb46560005114156118235734156117ac57600080fd5b60043560205181106117bd57600080fd5b50602435600281106117ce57600080fd5b5060243560063360e05260c052604060c02060043560e05260c052604060c0205560243561014052600435337f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c316020610140a3005b63e985e9c5600051141561188a57341561183c57600080fd5b600435602051811061184d57600080fd5b50602435602051811061185f57600080fd5b50600660043560e05260c052604060c02060243560e05260c052604060c0205460005260206000f350005b63a70b070f6000511415611af85734156118a357600080fd5b60043560205181106118b457600080fd5b50610120604435600401610140376101006044356004013511156118d757600080fd5b6000600435186118e657600080fd5b6308c379a06102805260206102a052601b6102c0527f4f776e6572206f6e6c792063616e20637265617465206974656d2e00000000006102e0526102c050336002541461193457608461029cfd5b6000600360043560e05260c052604060c02060243560e05260c052604060c02055600180546001825401101561196957600080fd5b60018154018155506001600760243560e05260c052604060c0205561014080600560243560e05260c052604060c02060c052602060c020602082510161012060006009818352015b826101205160200211156119c4576119e6565b61012051602002850151610120518501555b81516001018083528114156119b1575b50505050505060206103405261034051610380526101408051602001806103405161038001828460006004600a8704601201f1611a2257600080fd5b5050610320610340516103800151610440818352015b610440610320511115611a4a57611a6b565b600061032051610340516103a00101535b8151600101808352811415611a38575b5050602061034051610380015160206001820306601f8201039050610340510101610340526024357f6bb7ff708619ba0610cba295a58592e0451dee2622938c8755667688daf3529b61034051610380a26024356103a05260006103c0526004356000337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6260406103a0a4005b6319a35d7c6000511415611d43573415611b1157600080fd5b6004356020518110611b2257600080fd5b506000610120525b6020610120510161012052610120610120511015611b4757611b2a565b600060043518611b5657600080fd5b6308c379a061014052602061016052601c610180527f4f776e6572206f6e6c792063616e20637265617465206974656d732e000000006101a052610180503360025414611ba457608461015cfd5b6101e06000600a818352015b60246101e051600a8110611bc357600080fd5b6020020135610200526000600360043560e05260c052604060c0206102005160e05260c052604060c020556001805460018254011015611c0257600080fd5b6001815401815550600160076102005160e05260c052604060c020555b8151600101808352811415611bb0575b5050610220600081526000816020015260008160400152600081606001526000816080015260008160a0015260008160c0015260008160e00152600081610100015260008161012001525060243561036052604435610380526064356103a0526084356103c05260a4356103e05260c4356104005260e43561042052610104356104405261012435610460526101443561048052610220516104a052610240516104c052610260516104e05261028051610500526102a051610520526102c051610540526102e051610560526103005161058052610320516105a052610340516105c0526004356000337f514c24e4790d7c31a095a1688a73a01f28d936a9a85d806ba95970d8ee88efa8610280610360a4005b63156e29f66000511415611d8157600061028052610280805160200180610140828460006004600a8704601201f1611d7a57600080fd5b5050611dce565b63731133e96000511415611dc65761012060643560040161014037610100606435600401351115611db157600080fd5b61014060643560040161014037600050611dce565b60001561208a575b3415611dd957600080fd5b6004356020518110611dea57600080fd5b50600060043518611dfa57600080fd5b6308c379a06102c05260206102e052601a610300527f4f776e6572206f6e6c792063616e206d696e74206974656d732e00000000000061032052610300503360025414611e485760846102dcfd5b610140610380525b61038051516020610380510161038052610380610380511015611e7257611e50565b6320171bef6103a0526024356103c0526103c05160065801610cfa565b61042052610360610380525b6103805152602061038051036103805261014061038051101515611ebe57611e9b565b6104205161036052600261036051146001610360511417611ede57600080fd5b6001610360511415611f5f576308c379a0610440526020610460526028610480527f43616e6e6f74206d696e74204e46542077697468205f737570706c79206d6f726104a0527f65207468616e20310000000000000000000000000000000000000000000000006104c05261048050600160443514611f5e5760a461045cfd5b5b604435600360043560e05260c052604060c02060243560e05260c052604060c0205560243561050052604435610520526004356000337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f626040610500a460006004353b1115612088576004353b611fd557600080fd5b6004353018611fe357600080fd5b60206107806101c460a063f23a6e6161056052336105805260006105a0526024356105c0526044356105e0528061060052610140808051602001808461058001828460006004600a8704601201f161203a57600080fd5b50508051820160206001820306601f820103905060200191505061057c905060006004355af161206957600080fd5b600050610780516105405263f23a6e61610540511461208757600080fd5b5b005b63c671854d60005114156120c857600061028052610280805160200180610140828460006004600a8704601201f16120c157600080fd5b5050612118565b63b07e58756000511415612110576101206102a435600401610140376101006102a4356004013511156120fa57600080fd5b6101406102a43560040161014037600050612118565b6000156124f6575b341561212357600080fd5b600435602051811061213457600080fd5b506000610120525b60206101205101610120526101206101205110156121595761213c565b6000610120525b602061012051016101205261012061012051101561217d57612160565b60006004351861218c57600080fd5b6308c379a06102c05260206102e052601a610300527f4f776e6572206f6e6c792063616e206d696e74206974656d732e000000000000610320526103005033600254146121da5760846102dcfd5b6103606000600a818352015b602461036051600a81106121f957600080fd5b6020020135610380526101406103c0525b6103c0515160206103c051016103c0526103c06103c051101561222c5761220a565b6320171bef6103e05261038051610400526104005160065801610cfa565b610460526103a06103c0525b6103c0515260206103c051036103c0526101406103c05110151561227957612256565b610460516103a05260026103a0511460016103a051141761229957600080fd5b60016103a05114156122cb57600161016461036051600a81106122bb57600080fd5b6020020135146122ca57600080fd5b5b61016461036051600a81106122df57600080fd5b6020020135600360043560e05260c052604060c0206103805160e05260c052604060c020555b81516001018083528114156121e6575b5050602435610480526044356104a0526064356104c0526084356104e05260a4356105005260c4356105205260e4356105405261010435610560526101243561058052610144356105a052610164356105c052610184356105e0526101a435610600526101c435610620526101e4356106405261020435610660526102243561068052610244356106a052610264356106c052610284356106e0526004356000337f514c24e4790d7c31a095a1688a73a01f28d936a9a85d806ba95970d8ee88efa8610280610480a46107006000600a818352015b60006004353b11156124e1576004353b61240357600080fd5b600435301861241157600080fd5b60206109606101c460a063f23a6e61610740523361076052600061078052602461070051600a811061244257600080fd5b60200201356107a05261016461070051600a811061245f57600080fd5b60200201356107c052806107e052610140808051602001808461076001828460006004600a8704601201f161249357600080fd5b50508051820160206001820306601f820103905060200191505061075c905060006004355af16124c257600080fd5b600050610960516107205263f23a6e6161072051146124e057600080fd5b5b5b81516001018083528114156123ea575b5050005b63b390c0ab60005114156125ea57341561250f57600080fd5b6308c379a061014052602061016052601a610180527f4e6f7420656e6f75676820746f6b656e7320746f206275726e2e0000000000006101a0526101805060243560033360e05260c052604060c02060043560e05260c052604060c02054101561257a57608461015cfd5b60033360e05260c052604060c02060043560e05260c052604060c020602435815410156125a657600080fd5b6024358154038155506004356101e05260243561020052600033337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6260406101e0a4005b63b59afe52600051141561282b57341561260357600080fd5b6000610120525b60206101205101610120526101206101205110156126275761260a565b6000610120525b602061012051016101205261012061012051101561264b5761262e565b6101406000600a818352015b600461014051600a811061266a57600080fd5b60200201356101605261014461014051600a811061268757600080fd5b602002013560033360e05260c052604060c0206101605160e05260c052604060c0205410156126b557600080fd5b5b8151600101808352811415612657575b50506101806000600a818352015b600461018051600a81106126e757600080fd5b60200201356101a05260033360e05260c052604060c0206101a05160e05260c052604060c02061014461018051600a811061272157600080fd5b60200201358154101561273357600080fd5b61014461018051600a811061274757600080fd5b60200201358154038155505b81516001018083528114156126d4575b50506004356101c0526024356101e05260443561020052606435610220526084356102405260a4356102605260c4356102805260e4356102a052610104356102c052610124356102e0526101443561030052610164356103205261018435610340526101a435610360526101c435610380526101e4356103a052610204356103c052610224356103e05261024435610400526102643561042052600033337f514c24e4790d7c31a095a1688a73a01f28d936a9a85d806ba95970d8ee88efa86102806101c0a4005b63f2526ada6000511415612869576000610320526103208051602001806101e0828460006004600a8704601201f161286257600080fd5b50506128b9565b63a835c36960005114156128b157610120610464356004016101e0376101006104643560040135111561289b57600080fd5b610140610464356004016101e0376000506128b9565b600015613725575b60043560205181106128ca57600080fd5b5060243560205181106128dc57600080fd5b506000610120525b6020610120510161012052610120610120511015612901576128e4565b6000610120525b602061012051016101205261012061012051101561292557612908565b6000610120525b60206101205101610120526101206101205110156129495761292c565b6061610444356004016101403760416104443560040135111561296b57600080fd5b6308c379a061036052602061038052602c6103a0527f5f66726f6d206d757374206265207468652073656e646572206f7220617070726103c0527f6f766564206164647265737300000000000000000000000000000000000000006103e0526103a050600660043560e05260c052604060c0203360e05260c052604060c020543360043514176129fc5760a461037cfd5b6308c379a0610420526020610440526025610460527f44657374696e6174696f6e2061646472657373206d757374206265206e6f6e2d610480527f7a65726f2e0000000000000000000000000000000000000000000000000000006104a05261046050600060243518612a705760a461043cfd5b6308c379a06104e0526020610500526015610520527f4e6f6e6365206d75737420626520756e757365642e00000000000000000000006105405261052050600460043560e05260c052604060c0206104243560e05260c052604060c0205415612ada5760846104fcfd5b6308c379a06105805260206105a05260256105c0527f53656e64657220686173206e6f742070726f766964656420656e6f75676820656105e0527f746865722e000000000000000000000000000000000000000000000000000000610600526105c050346104043514612b4e5760a461059cfd5b6106406000600a818352015b604461064051600a8110612b6d57600080fd5b602002013561066052600061018461064051600a8110612b8c57600080fd5b60200201351115612c03576102c461064051600a8110612bab57600080fd5b602002013515612bba57600080fd5b61018461064051600a8110612bce57600080fd5b6020020135600360043560e05260c052604060c0206106605160e05260c052604060c020541015612bfe57600080fd5b612c6b565b61018461064051600a8110612c1757600080fd5b602002013515612c2657600080fd5b6102c461064051600a8110612c3a57600080fd5b6020020135600360243560e05260c052604060c0206106605160e05260c052604060c020541015612c6a57600080fd5b5b5b8151600101808352811415612b5a575b50506101406106a0525b6106a0515160206106a051016106a0526106a06106a0511015612ca857612c86565b6373ad25716106c0526004356106e05260243561070052610720604480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e00152806101000135826101000152806101200135826101200152505061086061018480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250506109a06102c480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e00152806101000135826101000152806101200135826101200152505061040435610ae05261042435610b0052610b0051610ae051610ac051610aa051610a8051610a6051610a4051610a2051610a00516109e0516109c0516109a05161098051610960516109405161092051610900516108e0516108c0516108a05161088051610860516108405161082051610800516107e0516107c0516107a05161078051610760516107405161072051610700516106e051600658016100dc565b610b60526106806106a0525b6106a0515260206106a051036106a0526101406106a051101515612ecc57612ea9565b610b605161068052610140610ba0525b610ba051516020610ba05101610ba052610ba0610ba0511015612efe57612edc565b6040636f868168610bc05261068051610be05280610c00526101408080516020018084610be001828460006004600a8704601201f1612f3c57600080fd5b50508051820160206001820306601f820103905060200191505050610c005180610be00180518060206001820306601f82010390508201610ce0525050505b610c20610ce0511015612f8d57612fa2565b610ce051516020610ce05103610ce052612f7b565b610c0051610be05160065801610a98565b610d0052610b80610ba0525b610ba051526020610ba05103610ba052610140610ba051101515612fe257612fbf565b610d0051610b80526308c379a0610d20526020610d40526020610d60527f5369676e657220646f6573206e6f74206d61746368207369676e61747572652e610d8052610d6050602435610b80511461303b576084610d3cfd5b600160043360e05260c052604060c0206104243560e05260c052604060c02055610dc06000600a818352015b6044610dc051600a811061307a57600080fd5b6020020135610de0526000610184610dc051600a811061309957600080fd5b6020020135111561317457600360043560e05260c052604060c020610de05160e05260c052604060c020610184610dc051600a81106130d757600080fd5b6020020135815410156130e957600080fd5b610184610dc051600a81106130fd57600080fd5b6020020135815403815550600360243560e05260c052604060c020610de05160e05260c052604060c0208054610184610dc051600a811061313d57600080fd5b6020020135825401101561315057600080fd5b610184610dc051600a811061316457600080fd5b6020020135815401815550613240565b600360043560e05260c052604060c020610de05160e05260c052604060c02080546102c4610dc051600a81106131a957600080fd5b602002013582540110156131bc57600080fd5b6102c4610dc051600a81106131d057600080fd5b6020020135815401815550600360243560e05260c052604060c020610de05160e05260c052604060c0206102c4610dc051600a811061320e57600080fd5b60200201358154101561322057600080fd5b6102c4610dc051600a811061323457600080fd5b60200201358154038155505b5b8151600101808352811415613067575b50506000600060006000346024356000f161326b57600080fd5b604435610e0052606435610e2052608435610e405260a435610e605260c435610e805260e435610ea05261010435610ec05261012435610ee05261014435610f005261016435610f205261018435610f40526101a435610f60526101c435610f80526101e435610fa05261020435610fc05261022435610fe0526102443561100052610264356110205261028435611040526102a43561106052602435600435337f514c24e4790d7c31a095a1688a73a01f28d936a9a85d806ba95970d8ee88efa8610280610e00a4604435611080526064356110a0526084356110c05260a4356110e05260c4356111005260e43561112052610104356111405261012435611160526101443561118052610164356111a0526102c4356111c0526102e4356111e052610304356112005261032435611220526103443561124052610364356112605261038435611280526103a4356112a0526103c4356112c0526103e4356112e052600435602435337f514c24e4790d7c31a095a1688a73a01f28d936a9a85d806ba95970d8ee88efa8610280611080a460006024353b1115613590576024353b61341657600080fd5b602435301861342457600080fd5b60206117806104046102e063a3bfc20661132052336113405260243561136052611380604480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250506114c061018480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e00152806101000135826101000152806101200135826101200152505080611600526101e0808051602001808461134001828460006004600a8704601201f161354257600080fd5b50508051820160206001820306601f820103905060200191505061133c905060006024355af161357157600080fd5b6000506117805161130052630c97e564611300511461358f57600080fd5b5b60006004353b1115613723576004353b6135a957600080fd5b60043530186135b757600080fd5b6020611c206104046102e063a3bfc2066117c052336117e05260043561180052611820604480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250506119606102c480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e00152806101000135826101000152806101200135826101200152505080611aa0526101e080805160200180846117e001828460006004600a8704601201f16136d557600080fd5b50508051820160206001820306601f82010390506020019150506117dc905060006004355af161370457600080fd5b600050611c20516117a052630c97e5646117a0511461372257600080fd5b5b005b636e8205b26000511415613763576000610320526103208051602001806101e0828460006004600a8704601201f161375c57600080fd5b50506137b3565b63183f5ec560005114156137ab57610120610104356004016101e0376101006101043560040135111561379557600080fd5b610140610104356004016101e0376000506137b3565b600015613f5d575b60043560205181106137c457600080fd5b5060243560205181106137d657600080fd5b50606160e43560040161014037604160e4356004013511156137f757600080fd5b600660043560e05260c052604060c0203360e05260c052604060c0205433600435141761382357600080fd5b6308c379a06103605260206103805260256103a0527f44657374696e6174696f6e2061646472657373206d757374206265206e6f6e2d6103c0527f7a65726f2e0000000000000000000000000000000000000000000000000000006103e0526103a0506000602435186138975760a461037cfd5b6308c379a0610420526020610440526015610460527f4e6f6e6365206d75737420626520756e757365642e00000000000000000000006104805261046050600460043560e05260c052604060c02060c43560e05260c052604060c020541561390057608461043cfd5b6308c379a06104c05260206104e0526025610500527f53656e64657220686173206e6f742070726f766964656420656e6f7567682065610520527f746865722e00000000000000000000000000000000000000000000000000000061054052610500503460a435146139735760a46104dcfd5b600060643511156139bd576084351561398b57600080fd5b606435600360043560e05260c052604060c02060443560e05260c052604060c0205410156139b857600080fd5b6139f8565b606435156139ca57600080fd5b608435600360243560e05260c052604060c02060443560e05260c052604060c0205410156139f757600080fd5b5b6101406105a0525b6105a0515160206105a051016105a0526105a06105a0511015613a2257613a00565b63155960636105c0526004356105e0526024356106005260443561062052606435610640526084356106605260a4356106805260c4356106a0526106a05161068051610660516106405161062051610600516105e05160065801610911565b610700526105806105a0525b6105a0515260206105a051036105a0526101406105a051101515613ab057613a8d565b6107005161058052610140610740525b61074051516020610740510161074052610740610740511015613ae257613ac0565b6040636f868168610760526105805161078052806107a052610140808051602001808461078001828460006004600a8704601201f1613b2057600080fd5b50508051820160206001820306601f8201039050602001915050506107a051806107800180518060206001820306601f82010390508201610880525050505b6107c0610880511015613b7157613b86565b61088051516020610880510361088052613b5f565b6107a0516107805160065801610a98565b6108a052610720610740525b6107405152602061074051036107405261014061074051101515613bc657613ba3565b6108a051610720526308c379a06108c05260206108e0526020610900527f5369676e657220646f6573206e6f74206d61746368207369676e61747572652e61092052610900506024356107205114613c1f5760846108dcfd5b600160043360e05260c052604060c02060c43560e05260c052604060c0205560006064351115613cbf57600360043560e05260c052604060c02060443560e05260c052604060c02060643581541015613c7757600080fd5b606435815403815550600360243560e05260c052604060c02060443560e05260c052604060c02080546064358254011015613cb157600080fd5b606435815401815550613d31565b600360043560e05260c052604060c02060443560e05260c052604060c02080546084358254011015613cf057600080fd5b608435815401815550600360243560e05260c052604060c02060443560e05260c052604060c02060843581541015613d2757600080fd5b6084358154038155505b6000600060006000346024356000f1613d4957600080fd5b6044356109605260643561098052602435600435337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f626040610960a46044356109a0526084356109c052600435602435337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6260406109a0a460006024353b1115613e8e576024353b613dda57600080fd5b6024353018613de857600080fd5b6020610c206101c460a063f23a6e61610a005233610a2052602435610a4052604435610a6052606435610a805280610aa0526101e08080516020018084610a2001828460006004600a8704601201f1613e4057600080fd5b50508051820160206001820306601f8201039050602001915050610a1c905060006024355af1613e6f57600080fd5b600050610c20516109e052630c97e5646109e05114613e8d57600080fd5b5b60006004353b1115613f5b576004353b613ea757600080fd5b6004353018613eb557600080fd5b6020610e806101c460a063f23a6e61610c605233610c8052600435610ca052604435610cc052608435610ce05280610d00526101e08080516020018084610c8001828460006004600a8704601201f1613f0d57600080fd5b50508051820160206001820306601f8201039050602001915050610c7c905060006004355af1613f3c57600080fd5b600050610e8051610c4052630c97e564610c405114613f5a57600080fd5b5b005b638da5cb5b6000511415613f84573415613f7657600080fd5b60025460005260206000f350005b60006000fd5b6100d061405a036100d06000396100d061405a036000f3\",\n  \"deployedBytecode\": \"0x600035601c52740100000000000000000000000000000000000000006020526f7fffffffffffffffffffffffffffffff6040527fffffffffffffffffffffffffffffffff8000000000000000000000000000000060605274012a05f1fffffffffffffffffffffffffdabf41c006080527ffffffffffffffffffffffffed5fa0e000000000000000000000000000000000060a05263ae22c57d60005114156100d45734156100ac57600080fd5b60043560205181106100bd57600080fd5b50600435610140526101405160005260206000f350005b600015610313575b610580526101405261016052610180526101a0526101c0526101e05261020052610220526102405261026052610280526102a0526102c0526102e05261030052610320526103405261036052610380526103a0526103c0526103e05261040052610420526104405261046052610480526104a0526104c0526104e052610500526105205261054052610560526000610180516020826105c00101526020810190506102c0516020826105c0010152602081019050610400516020826105c0010152602081019050806105c0526105c090508051602082012090506105a0526106606000600a818352015b610660511515156102765760006105a05160208261068001015260208101905061018061066051600a81106101fa57600080fd5b60200201516020826106800101526020810190506102c061066051600a811061022257600080fd5b602002015160208261068001015260208101905061040061066051600a811061024a57600080fd5b6020020151602082610680010152602081019050806106805261068090508051602082012090506105a0525b5b81516001018083528114156101c6575b5050600061014051602082610760010152602081019050610160516020826107600101526020810190506105a0516020826107600101526020810190506105405160208261076001015260208101905061056051602082610760010152602081019050806107605261076090508051602082012090506107405261074051600052600051610580515650005b634a6f823360005114156105c457341561032c57600080fd5b600435602051811061033d57600080fd5b50602435602051811061034f57600080fd5b506000610120525b602061012051016101205261012061012051101561037457610357565b6000610120525b60206101205101610120526101206101205110156103985761037b565b6000610120525b60206101205101610120526101206101205110156103bc5761039f565b6373ad25716101405260043561016052602435610180526101a0604480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250506102e061018480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250506104206102c480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250506104043561056052610424356105805261058051610560516105405161052051610500516104e0516104c0516104a05161048051610460516104405161042051610400516103e0516103c0516103a05161038051610360516103405161032051610300516102e0516102c0516102a05161028051610260516102405161022051610200516101e0516101c0516101a0516101805161016051600658016100dc565b6105e0526105e05160005260206000f350005b600015610909575b610580526101405261016052610180526101a0526101c0526101e05261020052610220526102405261026052610280526102a0526102c0526102e05261030052610320526103405261036052610380526103a0526103c0526103e05261040052610420526104405261046052610480526104a0526104c0526104e052610500526105205261054052610560526000610140516020826105c0010152602081019050610160516020826105c0010152602081019050610180516020826105c00101526020810190506101a0516020826105c00101526020810190506101c0516020826105c00101526020810190506101e0516020826105c0010152602081019050610200516020826105c0010152602081019050610220516020826105c0010152602081019050610240516020826105c0010152602081019050610260516020826105c0010152602081019050610280516020826105c00101526020810190506102a0516020826105c00101526020810190506102c0516020826105c00101526020810190506102e0516020826105c0010152602081019050610300516020826105c0010152602081019050610320516020826105c0010152602081019050610340516020826105c0010152602081019050610360516020826105c0010152602081019050610380516020826105c00101526020810190506103a0516020826105c00101526020810190506103c0516020826105c00101526020810190506103e0516020826105c0010152602081019050610400516020826105c0010152602081019050610420516020826105c0010152602081019050610440516020826105c0010152602081019050610460516020826105c0010152602081019050610480516020826105c00101526020810190506104a0516020826105c00101526020810190506104c0516020826105c00101526020810190506104e0516020826105c0010152602081019050610500516020826105c0010152602081019050610520516020826105c0010152602081019050610540516020826105c0010152602081019050610560516020826105c0010152602081019050806105c0526105c090508051602082012090506105a0526105a051600052600051610580515650005b6000156109e1575b610220526101405261016052610180526101a0526101c0526101e0526102005260006101405160208261026001015260208101905061016051602082610260010152602081019050610180516020826102600101526020810190506101a0516020826102600101526020810190506101c0516020826102600101526020810190506101e05160208261026001015260208101905061020051602082610260010152602081019050806102605261026090508051602082012090506102405261024051600052600051610220515650005b6310660e866000511415610a905734156109fa57600080fd5b6004356020518110610a0b57600080fd5b506024356020518110610a1d57600080fd5b5063155960636101405260043561016052602435610180526044356101a0526064356101c0526084356101e05260a4356102005260c4356102205261022051610200516101e0516101c0516101a051610180516101605160065801610911565b610280526102805160005260206000f350005b600015610cf2575b6101805261014052610160526101a0526000610240525b6101a05160206001820306601f820103905061024051101515610ad157610aea565b610240516101c001526102405160200161024052610aaf565b60005060416101a0511815610b0757600060005260005161018051565b6101a0602060006020835103811315610b1f57600080fd5b046020026020018101519050610280526101a0602060206020835103811315610b4757600080fd5b0460200260200181015190506102a05260406001602082066103a0016101a0518284011115610b7557600080fd5b6041806103c0826020602088068803016101a001600060046018f1505081815280905090509050806020015160008251806020901315610bb457600080fd5b8091901215610bc257600080fd5b606051816020036101000a830480604051901315610bdf57600080fd5b8091901215610bed57600080fd5b9050905090506102c052601b6102c0511215610c30576102c0606051601b82510180604051901315610c1e57600080fd5b8091901215610c2c57600080fd5b8152505b610480601b8152601c81602001525060006104605261046061012060006002818352015b6101205160200261048001516102c0511415610c735760018352610c84565b5b8151600101808352811415610c54575b5050506104605160011415610ce257610140516104c0526102c0516000811215610cad57600080fd5b6104e05261028051610500526102a05161052052602060c060806104c060006001610bb8f15060c05160005260005161018051565b6000600052600051610180515650005b600015610db3575b6101605261014052610140517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff806000811215610d3e578060000360020a8204610d45565b8060020a82025b90509050604051811115610d5857600080fd5b61018052700100000000000000000000000000000000610d7757600080fd5b7001000000000000000000000000000000006101405106604051811115610d9d57600080fd5b6101a05261018051600052600051610160515650005b63f17535506000511415610de8573415610dcc57600080fd5b600060043560e05260c052604060c0205460005260206000f350005b63ac2a2e216000511415610e3d573415610e0157600080fd5b6004356020518110610e1257600080fd5b50600460043560e05260c052604060c02060243560e05260c052604060c0205460005260206000f350005b634026b7556000511415610e72573415610e5657600080fd5b600760043560e05260c052604060c0205460005260206000f350005b63f242432a6000511415611135573415610e8b57600080fd5b6004356020518110610e9c57600080fd5b506024356020518110610eae57600080fd5b5061012060843560040161014037610100608435600401351115610ed157600080fd5b600660043560e05260c052604060c0203360e05260c052604060c02054336004351417610efd57600080fd5b6308c379a06102805260206102a05260206102c0527f43616e6e6f74207472616e7366657220746f207a65726f20616464726573732e6102e0526102c050600060243518610f4c57608461029cfd5b6308c379a0610320526020610340526012610360527f4e6f7420656e6f75676820746f6b656e732e00000000000000000000000000006103805261036050606435600360043560e05260c052604060c02060443560e05260c052604060c020541015610fb957608461033cfd5b600360043560e05260c052604060c02060443560e05260c052604060c02060643581541015610fe757600080fd5b606435815403815550600360243560e05260c052604060c02060443560e05260c052604060c0208054606435825401101561102157600080fd5b6064358154018155506044356103c0526064356103e052602435600435337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6260406103c0a460006024353b1115611133576024353b61107f57600080fd5b602435301861108d57600080fd5b60206106406101c460a063f23a6e6161042052336104405260043561046052604435610480526064356104a052806104c052610140808051602001808461044001828460006004600a8704601201f16110e557600080fd5b50508051820160206001820306601f820103905060200191505061043c905060006024355af161111457600080fd5b600050610640516104005263f23a6e61610400511461113257600080fd5b5b005b63cf36e535600051141561163c57341561114e57600080fd5b600435602051811061115f57600080fd5b50602435602051811061117157600080fd5b506000610120525b602061012051016101205261012061012051101561119657611179565b6000610120525b60206101205101610120526101206101205110156111ba5761119d565b6101206102c435600401610140376101006102c4356004013511156111de57600080fd5b600660043560e05260c052604060c0203360e05260c052604060c0205433600435141761120a57600080fd5b6308c379a06102805260206102a05260206102c0527f43616e6e6f74207472616e7366657220746f207a65726f20616464726573732e6102e0526102c05060006024351861125957608461029cfd5b6103206000600a818352015b604461032051600a811061127857600080fd5b60200201356103405261018461032051600a811061129557600080fd5b6020020135600360043560e05260c052604060c0206103405160e05260c052604060c0205410156112c557600080fd5b5b8151600101808352811415611265575b505060443561036052606435610380526084356103a05260a4356103c05260c4356103e05260e435610400526101043561042052610124356104405261014435610460526101643561048052610184356104a0526101a4356104c0526101c4356104e0526101e435610500526102043561052052610224356105405261024435610560526102643561058052610284356105a0526102a4356105c052602435600435337f514c24e4790d7c31a095a1688a73a01f28d936a9a85d806ba95970d8ee88efa8610280610360a46105e06000600a818352015b60446105e051600a81106113c057600080fd5b602002013561060052600360043560e05260c052604060c0206106005160e05260c052604060c0206101846105e051600a81106113fc57600080fd5b60200201358154101561140e57600080fd5b6101846105e051600a811061142257600080fd5b6020020135815403815550600360243560e05260c052604060c0206106005160e05260c052604060c02080546101846105e051600a811061146257600080fd5b6020020135825401101561147557600080fd5b6101846105e051600a811061148957600080fd5b60200201358154018155505b81516001018083528114156113ad575b505060006024353b111561163a576024353b6114c057600080fd5b60243530186114ce57600080fd5b6020610aa06104046102e063a3bfc206610640523361066052600435610680526106a0604480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250506107e061018480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250508061092052610140808051602001808461066001828460006004600a8704601201f16115ec57600080fd5b50508051820160206001820306601f820103905060200191505061065c905060006024355af161161b57600080fd5b600050610aa0516106205263e324a00d610620511461163957600080fd5b5b005b62fdd58e600051141561169057341561165457600080fd5b600435602051811061166557600080fd5b50600360043560e05260c052604060c02060243560e05260c052604060c0205460005260206000f350005b63fbe31aea60005114156117935734156116a957600080fd5b6000610120525b610120516004013560205181106116c657600080fd5b5060206101205101610120526101206101205110156116e4576116b0565b6000610120525b6020610120510161012052610120610120511015611708576116eb565b6102806000600a818352015b6003600461028051600a811061172957600080fd5b602002013560e05260c052604060c02061014461028051600a811061174d57600080fd5b602002013560e05260c052604060c0205461014061028051600a811061177257600080fd5b60200201525b8151600101808352811415611714575b5050610140610140f3005b63a22cb46560005114156118235734156117ac57600080fd5b60043560205181106117bd57600080fd5b50602435600281106117ce57600080fd5b5060243560063360e05260c052604060c02060043560e05260c052604060c0205560243561014052600435337f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c316020610140a3005b63e985e9c5600051141561188a57341561183c57600080fd5b600435602051811061184d57600080fd5b50602435602051811061185f57600080fd5b50600660043560e05260c052604060c02060243560e05260c052604060c0205460005260206000f350005b63a70b070f6000511415611af85734156118a357600080fd5b60043560205181106118b457600080fd5b50610120604435600401610140376101006044356004013511156118d757600080fd5b6000600435186118e657600080fd5b6308c379a06102805260206102a052601b6102c0527f4f776e6572206f6e6c792063616e20637265617465206974656d2e00000000006102e0526102c050336002541461193457608461029cfd5b6000600360043560e05260c052604060c02060243560e05260c052604060c02055600180546001825401101561196957600080fd5b60018154018155506001600760243560e05260c052604060c0205561014080600560243560e05260c052604060c02060c052602060c020602082510161012060006009818352015b826101205160200211156119c4576119e6565b61012051602002850151610120518501555b81516001018083528114156119b1575b50505050505060206103405261034051610380526101408051602001806103405161038001828460006004600a8704601201f1611a2257600080fd5b5050610320610340516103800151610440818352015b610440610320511115611a4a57611a6b565b600061032051610340516103a00101535b8151600101808352811415611a38575b5050602061034051610380015160206001820306601f8201039050610340510101610340526024357f6bb7ff708619ba0610cba295a58592e0451dee2622938c8755667688daf3529b61034051610380a26024356103a05260006103c0526004356000337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6260406103a0a4005b6319a35d7c6000511415611d43573415611b1157600080fd5b6004356020518110611b2257600080fd5b506000610120525b6020610120510161012052610120610120511015611b4757611b2a565b600060043518611b5657600080fd5b6308c379a061014052602061016052601c610180527f4f776e6572206f6e6c792063616e20637265617465206974656d732e000000006101a052610180503360025414611ba457608461015cfd5b6101e06000600a818352015b60246101e051600a8110611bc357600080fd5b6020020135610200526000600360043560e05260c052604060c0206102005160e05260c052604060c020556001805460018254011015611c0257600080fd5b6001815401815550600160076102005160e05260c052604060c020555b8151600101808352811415611bb0575b5050610220600081526000816020015260008160400152600081606001526000816080015260008160a0015260008160c0015260008160e00152600081610100015260008161012001525060243561036052604435610380526064356103a0526084356103c05260a4356103e05260c4356104005260e43561042052610104356104405261012435610460526101443561048052610220516104a052610240516104c052610260516104e05261028051610500526102a051610520526102c051610540526102e051610560526103005161058052610320516105a052610340516105c0526004356000337f514c24e4790d7c31a095a1688a73a01f28d936a9a85d806ba95970d8ee88efa8610280610360a4005b63156e29f66000511415611d8157600061028052610280805160200180610140828460006004600a8704601201f1611d7a57600080fd5b5050611dce565b63731133e96000511415611dc65761012060643560040161014037610100606435600401351115611db157600080fd5b61014060643560040161014037600050611dce565b60001561208a575b3415611dd957600080fd5b6004356020518110611dea57600080fd5b50600060043518611dfa57600080fd5b6308c379a06102c05260206102e052601a610300527f4f776e6572206f6e6c792063616e206d696e74206974656d732e00000000000061032052610300503360025414611e485760846102dcfd5b610140610380525b61038051516020610380510161038052610380610380511015611e7257611e50565b6320171bef6103a0526024356103c0526103c05160065801610cfa565b61042052610360610380525b6103805152602061038051036103805261014061038051101515611ebe57611e9b565b6104205161036052600261036051146001610360511417611ede57600080fd5b6001610360511415611f5f576308c379a0610440526020610460526028610480527f43616e6e6f74206d696e74204e46542077697468205f737570706c79206d6f726104a0527f65207468616e20310000000000000000000000000000000000000000000000006104c05261048050600160443514611f5e5760a461045cfd5b5b604435600360043560e05260c052604060c02060243560e05260c052604060c0205560243561050052604435610520526004356000337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f626040610500a460006004353b1115612088576004353b611fd557600080fd5b6004353018611fe357600080fd5b60206107806101c460a063f23a6e6161056052336105805260006105a0526024356105c0526044356105e0528061060052610140808051602001808461058001828460006004600a8704601201f161203a57600080fd5b50508051820160206001820306601f820103905060200191505061057c905060006004355af161206957600080fd5b600050610780516105405263f23a6e61610540511461208757600080fd5b5b005b63c671854d60005114156120c857600061028052610280805160200180610140828460006004600a8704601201f16120c157600080fd5b5050612118565b63b07e58756000511415612110576101206102a435600401610140376101006102a4356004013511156120fa57600080fd5b6101406102a43560040161014037600050612118565b6000156124f6575b341561212357600080fd5b600435602051811061213457600080fd5b506000610120525b60206101205101610120526101206101205110156121595761213c565b6000610120525b602061012051016101205261012061012051101561217d57612160565b60006004351861218c57600080fd5b6308c379a06102c05260206102e052601a610300527f4f776e6572206f6e6c792063616e206d696e74206974656d732e000000000000610320526103005033600254146121da5760846102dcfd5b6103606000600a818352015b602461036051600a81106121f957600080fd5b6020020135610380526101406103c0525b6103c0515160206103c051016103c0526103c06103c051101561222c5761220a565b6320171bef6103e05261038051610400526104005160065801610cfa565b610460526103a06103c0525b6103c0515260206103c051036103c0526101406103c05110151561227957612256565b610460516103a05260026103a0511460016103a051141761229957600080fd5b60016103a05114156122cb57600161016461036051600a81106122bb57600080fd5b6020020135146122ca57600080fd5b5b61016461036051600a81106122df57600080fd5b6020020135600360043560e05260c052604060c0206103805160e05260c052604060c020555b81516001018083528114156121e6575b5050602435610480526044356104a0526064356104c0526084356104e05260a4356105005260c4356105205260e4356105405261010435610560526101243561058052610144356105a052610164356105c052610184356105e0526101a435610600526101c435610620526101e4356106405261020435610660526102243561068052610244356106a052610264356106c052610284356106e0526004356000337f514c24e4790d7c31a095a1688a73a01f28d936a9a85d806ba95970d8ee88efa8610280610480a46107006000600a818352015b60006004353b11156124e1576004353b61240357600080fd5b600435301861241157600080fd5b60206109606101c460a063f23a6e61610740523361076052600061078052602461070051600a811061244257600080fd5b60200201356107a05261016461070051600a811061245f57600080fd5b60200201356107c052806107e052610140808051602001808461076001828460006004600a8704601201f161249357600080fd5b50508051820160206001820306601f820103905060200191505061075c905060006004355af16124c257600080fd5b600050610960516107205263f23a6e6161072051146124e057600080fd5b5b5b81516001018083528114156123ea575b5050005b63b390c0ab60005114156125ea57341561250f57600080fd5b6308c379a061014052602061016052601a610180527f4e6f7420656e6f75676820746f6b656e7320746f206275726e2e0000000000006101a0526101805060243560033360e05260c052604060c02060043560e05260c052604060c02054101561257a57608461015cfd5b60033360e05260c052604060c02060043560e05260c052604060c020602435815410156125a657600080fd5b6024358154038155506004356101e05260243561020052600033337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6260406101e0a4005b63b59afe52600051141561282b57341561260357600080fd5b6000610120525b60206101205101610120526101206101205110156126275761260a565b6000610120525b602061012051016101205261012061012051101561264b5761262e565b6101406000600a818352015b600461014051600a811061266a57600080fd5b60200201356101605261014461014051600a811061268757600080fd5b602002013560033360e05260c052604060c0206101605160e05260c052604060c0205410156126b557600080fd5b5b8151600101808352811415612657575b50506101806000600a818352015b600461018051600a81106126e757600080fd5b60200201356101a05260033360e05260c052604060c0206101a05160e05260c052604060c02061014461018051600a811061272157600080fd5b60200201358154101561273357600080fd5b61014461018051600a811061274757600080fd5b60200201358154038155505b81516001018083528114156126d4575b50506004356101c0526024356101e05260443561020052606435610220526084356102405260a4356102605260c4356102805260e4356102a052610104356102c052610124356102e0526101443561030052610164356103205261018435610340526101a435610360526101c435610380526101e4356103a052610204356103c052610224356103e05261024435610400526102643561042052600033337f514c24e4790d7c31a095a1688a73a01f28d936a9a85d806ba95970d8ee88efa86102806101c0a4005b63f2526ada6000511415612869576000610320526103208051602001806101e0828460006004600a8704601201f161286257600080fd5b50506128b9565b63a835c36960005114156128b157610120610464356004016101e0376101006104643560040135111561289b57600080fd5b610140610464356004016101e0376000506128b9565b600015613725575b60043560205181106128ca57600080fd5b5060243560205181106128dc57600080fd5b506000610120525b6020610120510161012052610120610120511015612901576128e4565b6000610120525b602061012051016101205261012061012051101561292557612908565b6000610120525b60206101205101610120526101206101205110156129495761292c565b6061610444356004016101403760416104443560040135111561296b57600080fd5b6308c379a061036052602061038052602c6103a0527f5f66726f6d206d757374206265207468652073656e646572206f7220617070726103c0527f6f766564206164647265737300000000000000000000000000000000000000006103e0526103a050600660043560e05260c052604060c0203360e05260c052604060c020543360043514176129fc5760a461037cfd5b6308c379a0610420526020610440526025610460527f44657374696e6174696f6e2061646472657373206d757374206265206e6f6e2d610480527f7a65726f2e0000000000000000000000000000000000000000000000000000006104a05261046050600060243518612a705760a461043cfd5b6308c379a06104e0526020610500526015610520527f4e6f6e6365206d75737420626520756e757365642e00000000000000000000006105405261052050600460043560e05260c052604060c0206104243560e05260c052604060c0205415612ada5760846104fcfd5b6308c379a06105805260206105a05260256105c0527f53656e64657220686173206e6f742070726f766964656420656e6f75676820656105e0527f746865722e000000000000000000000000000000000000000000000000000000610600526105c050346104043514612b4e5760a461059cfd5b6106406000600a818352015b604461064051600a8110612b6d57600080fd5b602002013561066052600061018461064051600a8110612b8c57600080fd5b60200201351115612c03576102c461064051600a8110612bab57600080fd5b602002013515612bba57600080fd5b61018461064051600a8110612bce57600080fd5b6020020135600360043560e05260c052604060c0206106605160e05260c052604060c020541015612bfe57600080fd5b612c6b565b61018461064051600a8110612c1757600080fd5b602002013515612c2657600080fd5b6102c461064051600a8110612c3a57600080fd5b6020020135600360243560e05260c052604060c0206106605160e05260c052604060c020541015612c6a57600080fd5b5b5b8151600101808352811415612b5a575b50506101406106a0525b6106a0515160206106a051016106a0526106a06106a0511015612ca857612c86565b6373ad25716106c0526004356106e05260243561070052610720604480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e00152806101000135826101000152806101200135826101200152505061086061018480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250506109a06102c480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e00152806101000135826101000152806101200135826101200152505061040435610ae05261042435610b0052610b0051610ae051610ac051610aa051610a8051610a6051610a4051610a2051610a00516109e0516109c0516109a05161098051610960516109405161092051610900516108e0516108c0516108a05161088051610860516108405161082051610800516107e0516107c0516107a05161078051610760516107405161072051610700516106e051600658016100dc565b610b60526106806106a0525b6106a0515260206106a051036106a0526101406106a051101515612ecc57612ea9565b610b605161068052610140610ba0525b610ba051516020610ba05101610ba052610ba0610ba0511015612efe57612edc565b6040636f868168610bc05261068051610be05280610c00526101408080516020018084610be001828460006004600a8704601201f1612f3c57600080fd5b50508051820160206001820306601f820103905060200191505050610c005180610be00180518060206001820306601f82010390508201610ce0525050505b610c20610ce0511015612f8d57612fa2565b610ce051516020610ce05103610ce052612f7b565b610c0051610be05160065801610a98565b610d0052610b80610ba0525b610ba051526020610ba05103610ba052610140610ba051101515612fe257612fbf565b610d0051610b80526308c379a0610d20526020610d40526020610d60527f5369676e657220646f6573206e6f74206d61746368207369676e61747572652e610d8052610d6050602435610b80511461303b576084610d3cfd5b600160043360e05260c052604060c0206104243560e05260c052604060c02055610dc06000600a818352015b6044610dc051600a811061307a57600080fd5b6020020135610de0526000610184610dc051600a811061309957600080fd5b6020020135111561317457600360043560e05260c052604060c020610de05160e05260c052604060c020610184610dc051600a81106130d757600080fd5b6020020135815410156130e957600080fd5b610184610dc051600a81106130fd57600080fd5b6020020135815403815550600360243560e05260c052604060c020610de05160e05260c052604060c0208054610184610dc051600a811061313d57600080fd5b6020020135825401101561315057600080fd5b610184610dc051600a811061316457600080fd5b6020020135815401815550613240565b600360043560e05260c052604060c020610de05160e05260c052604060c02080546102c4610dc051600a81106131a957600080fd5b602002013582540110156131bc57600080fd5b6102c4610dc051600a81106131d057600080fd5b6020020135815401815550600360243560e05260c052604060c020610de05160e05260c052604060c0206102c4610dc051600a811061320e57600080fd5b60200201358154101561322057600080fd5b6102c4610dc051600a811061323457600080fd5b60200201358154038155505b5b8151600101808352811415613067575b50506000600060006000346024356000f161326b57600080fd5b604435610e0052606435610e2052608435610e405260a435610e605260c435610e805260e435610ea05261010435610ec05261012435610ee05261014435610f005261016435610f205261018435610f40526101a435610f60526101c435610f80526101e435610fa05261020435610fc05261022435610fe0526102443561100052610264356110205261028435611040526102a43561106052602435600435337f514c24e4790d7c31a095a1688a73a01f28d936a9a85d806ba95970d8ee88efa8610280610e00a4604435611080526064356110a0526084356110c05260a4356110e05260c4356111005260e43561112052610104356111405261012435611160526101443561118052610164356111a0526102c4356111c0526102e4356111e052610304356112005261032435611220526103443561124052610364356112605261038435611280526103a4356112a0526103c4356112c0526103e4356112e052600435602435337f514c24e4790d7c31a095a1688a73a01f28d936a9a85d806ba95970d8ee88efa8610280611080a460006024353b1115613590576024353b61341657600080fd5b602435301861342457600080fd5b60206117806104046102e063a3bfc20661132052336113405260243561136052611380604480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250506114c061018480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e00152806101000135826101000152806101200135826101200152505080611600526101e0808051602001808461134001828460006004600a8704601201f161354257600080fd5b50508051820160206001820306601f820103905060200191505061133c905060006024355af161357157600080fd5b6000506117805161130052630c97e564611300511461358f57600080fd5b5b60006004353b1115613723576004353b6135a957600080fd5b60043530186135b757600080fd5b6020611c206104046102e063a3bfc2066117c052336117e05260043561180052611820604480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e0015280610100013582610100015280610120013582610120015250506119606102c480358252806020013582602001528060400135826040015280606001358260600152806080013582608001528060a001358260a001528060c001358260c001528060e001358260e00152806101000135826101000152806101200135826101200152505080611aa0526101e080805160200180846117e001828460006004600a8704601201f16136d557600080fd5b50508051820160206001820306601f82010390506020019150506117dc905060006004355af161370457600080fd5b600050611c20516117a052630c97e5646117a0511461372257600080fd5b5b005b636e8205b26000511415613763576000610320526103208051602001806101e0828460006004600a8704601201f161375c57600080fd5b50506137b3565b63183f5ec560005114156137ab57610120610104356004016101e0376101006101043560040135111561379557600080fd5b610140610104356004016101e0376000506137b3565b600015613f5d575b60043560205181106137c457600080fd5b5060243560205181106137d657600080fd5b50606160e43560040161014037604160e4356004013511156137f757600080fd5b600660043560e05260c052604060c0203360e05260c052604060c0205433600435141761382357600080fd5b6308c379a06103605260206103805260256103a0527f44657374696e6174696f6e2061646472657373206d757374206265206e6f6e2d6103c0527f7a65726f2e0000000000000000000000000000000000000000000000000000006103e0526103a0506000602435186138975760a461037cfd5b6308c379a0610420526020610440526015610460527f4e6f6e6365206d75737420626520756e757365642e00000000000000000000006104805261046050600460043560e05260c052604060c02060c43560e05260c052604060c020541561390057608461043cfd5b6308c379a06104c05260206104e0526025610500527f53656e64657220686173206e6f742070726f766964656420656e6f7567682065610520527f746865722e00000000000000000000000000000000000000000000000000000061054052610500503460a435146139735760a46104dcfd5b600060643511156139bd576084351561398b57600080fd5b606435600360043560e05260c052604060c02060443560e05260c052604060c0205410156139b857600080fd5b6139f8565b606435156139ca57600080fd5b608435600360243560e05260c052604060c02060443560e05260c052604060c0205410156139f757600080fd5b5b6101406105a0525b6105a0515160206105a051016105a0526105a06105a0511015613a2257613a00565b63155960636105c0526004356105e0526024356106005260443561062052606435610640526084356106605260a4356106805260c4356106a0526106a05161068051610660516106405161062051610600516105e05160065801610911565b610700526105806105a0525b6105a0515260206105a051036105a0526101406105a051101515613ab057613a8d565b6107005161058052610140610740525b61074051516020610740510161074052610740610740511015613ae257613ac0565b6040636f868168610760526105805161078052806107a052610140808051602001808461078001828460006004600a8704601201f1613b2057600080fd5b50508051820160206001820306601f8201039050602001915050506107a051806107800180518060206001820306601f82010390508201610880525050505b6107c0610880511015613b7157613b86565b61088051516020610880510361088052613b5f565b6107a0516107805160065801610a98565b6108a052610720610740525b6107405152602061074051036107405261014061074051101515613bc657613ba3565b6108a051610720526308c379a06108c05260206108e0526020610900527f5369676e657220646f6573206e6f74206d61746368207369676e61747572652e61092052610900506024356107205114613c1f5760846108dcfd5b600160043360e05260c052604060c02060c43560e05260c052604060c0205560006064351115613cbf57600360043560e05260c052604060c02060443560e05260c052604060c02060643581541015613c7757600080fd5b606435815403815550600360243560e05260c052604060c02060443560e05260c052604060c02080546064358254011015613cb157600080fd5b606435815401815550613d31565b600360043560e05260c052604060c02060443560e05260c052604060c02080546084358254011015613cf057600080fd5b608435815401815550600360243560e05260c052604060c02060443560e05260c052604060c02060843581541015613d2757600080fd5b6084358154038155505b6000600060006000346024356000f1613d4957600080fd5b6044356109605260643561098052602435600435337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f626040610960a46044356109a0526084356109c052600435602435337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6260406109a0a460006024353b1115613e8e576024353b613dda57600080fd5b6024353018613de857600080fd5b6020610c206101c460a063f23a6e61610a005233610a2052602435610a4052604435610a6052606435610a805280610aa0526101e08080516020018084610a2001828460006004600a8704601201f1613e4057600080fd5b50508051820160206001820306601f8201039050602001915050610a1c905060006024355af1613e6f57600080fd5b600050610c20516109e052630c97e5646109e05114613e8d57600080fd5b5b60006004353b1115613f5b576004353b613ea757600080fd5b6004353018613eb557600080fd5b6020610e806101c460a063f23a6e61610c605233610c8052600435610ca052604435610cc052608435610ce05280610d00526101e08080516020018084610c8001828460006004600a8704601201f1613f0d57600080fd5b50508051820160206001820306601f8201039050602001915050610c7c905060006004355af1613f3c57600080fd5b600050610e8051610c4052630c97e564610c405114613f5a57600080fd5b5b005b638da5cb5b6000511415613f84573415613f7657600080fd5b60025460005260206000f350005b60006000fd\",\n  \"source\": \"# Author: Sören Steiger, github.com/ssteiger\\n# Author: Fetch.ai, github.com/fetchai\\n# License: MIT\\n\\n# ERC1155 Token Standard\\n# https://eips.ethereum.org/EIPS/eip-1155\\n\\n########################EXTERNAL-CONTRACTS####################################\\n\\ncontract ERC1155TokenReceiver:\\n    # Note: The ERC-165 identifier for this interface is 0x4e2312e0.\\n\\n    def onERC1155Received(_operator: address, _from: address, _id: uint256, _value: uint256,\\n                          _data: bytes[256]) -> bytes32: modifying  # TODO: should return bytes4\\n    #        \\\"\\\"\\\"\\n    #       @notice Handle the receipt of a single ERC1155 token type.\\n    #       @dev An ERC1155-compliant smart contract MUST call this function on the token recipient contract, at the end of a `safeTransferFrom` after the balance has been updated.        \\n    #       This function MUST return `bytes4(keccak256(\\\"onERC1155Received(address,address,uint256,uint256,bytes)\\\"))` (i.e. 0xf23a6e61) if it accepts the transfer.\\n    #       This function MUST revert if it rejects the transfer.\\n    #       Return of any other value than the prescribed keccak256 generated value MUST result in the transaction being reverted by the caller.\\n    #       @param _operator  The address which initiated the transfer (i.e. msg.sender)\\n    #       @param _from      The address which previously owned the token\\n    #       @param _id        The ID of the token being transferred\\n    #       @param _value     The amount of tokens being transferred\\n    #       @param _data      Additional data with no specified format\\n    #       @return           `bytes4(keccak256(\\\"onERC1155Received(address,address,uint256,uint256,bytes)\\\"))`\\n    #       \\\"\\\"\\\"\\n\\n    def onERC1155BatchReceived(_operator: address, _from: address, _ids: uint256[BATCH_SIZE], _values: uint256[BATCH_SIZE],\\n                               _data: bytes[256]) -> bytes32: modifying  # TODO: should return bytes4\\n    #       \\\"\\\"\\\"\\n    #       @notice Handle the receipt of multiple ERC1155 token types.\\n    #       @dev An ERC1155-compliant smart contract MUST call this function on the token recipient contract, at the end of a `safeBatchTransferFrom` after the balances have been updated.        \\n    #       This function MUST return `bytes4(keccak256(\\\"onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)\\\"))` (i.e. 0xbc197c81) if it accepts the transfer(s).\\n    #       This function MUST revert if it rejects the transfer(s).\\n    #       Return of any other value than the prescribed keccak256 generated value MUST result in the transaction being reverted by the caller.\\n    #       @param _operator  The address which initiated the batch transfer (i.e. msg.sender)\\n    #       @param _from      The address which previously owned the token\\n    #       @param _ids       An array containing ids of each token being transferred (order and length must match _values array)\\n    #       @param _values    An array containing amounts of each token being transferred (order and length must match _ids array)\\n    #       @param _data      Additional data with no specified format\\n    #       @return           `bytes4(keccak256(\\\"onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)\\\"))`\\n    #       \\\"\\\"\\\"\\n\\n########################END-EXTERNAL-CONTRACTS####################################\\n########################EVENTS####################################\\n\\nMAX_URI_SIZE: constant(uint256) = 1024\\n\\nTransferSingle: event({_operator: indexed(address), _from: indexed(address), _to: indexed(address), _id: uint256,\\n                       _value: uint256})\\n#   @dev Either `TransferSingle` or `TransferBatch` MUST emit when tokens are transferred, including zero value transfers as well as minting or burning (see \\\"Safe Transfer Rules\\\" section of the standard).\\n#        The `_operator` argument MUST be the address of an account/contract that is approved to make the transfer (SHOULD be msg.sender).\\n#        The `_from` argument MUST be the address of the holder whose balance is decreased.\\n#        The `_to` argument MUST be the address of the recipient whose balance is increased.\\n#        The `_id` argument MUST be the token type being transferred.\\n#        The `_value` argument MUST be the number of tokens the holder balance is decreased by and match what the recipient balance is increased by.\\n#        When minting/creating tokens, the `_from` argument MUST be set to `0x0` (i.e. zero address).\\n#        When burning/destroying tokens, the `_to` argument MUST be set to `0x0` (i.e. zero address).\\n\\n\\nTransferBatch: event({_operator: indexed(address), _from: indexed(address), _to: indexed(address),\\n                      _ids: uint256[BATCH_SIZE], _values: uint256[BATCH_SIZE]})\\n#   @dev Either `TransferSingle` or `TransferBatch` MUST emit when tokens are transferred, including zero value transfers as well as minting or burning (see \\\"Safe Transfer Rules\\\" section of the standard).\\n#        The `_operator` argument MUST be the address of an account/contract that is approved to make the transfer (SHOULD be msg.sender).\\n#        The `_from` argument MUST be the address of the holder whose balance is decreased.\\n#        The `_to` argument MUST be the address of the recipient whose balance is increased.\\n#        The `_ids` argument MUST be the list of tokens being transferred.\\n#        The `_values` argument MUST be the list of number of tokens (matching the list and order of tokens specified in _ids) the holder balance is decreased by and match what the recipient balance is increased by.\\n#        When minting/creating tokens, the `_from` argument MUST be set to `0x0` (i.e. zero address).\\n#        When burning/destroying tokens, the `_to` argument MUST be set to `0x0` (i.e. zero address).\\n\\n\\nApprovalForAll: event({_owner: indexed(address), _operator: indexed(address), _approved: bool})\\n#   @dev MUST emit when approval for a second party/operator address to manage all tokens for an owner address is enabled or disabled (absence of an event assumes disabled).\\n\\n\\nURI: event({_value: string[MAX_URI_SIZE], _id: indexed(uint256)})\\n#   @dev MUST emit when the URI is updated for a token ID.\\n#        URIs are defined in RFC 3986.\\n#        The URI MUST point to a JSON file that conforms to the \\\"ERC-1155 Metadata URI JSON Schema\\\".\\n\\n########################END-EVENTS####################################\\n########################INITIALIZATION####################################\\n\\nsupportedInterfaces: map(bytes32, bool)\\n# https://eips.ethereum.org/EIPS/eip-165\\nERC165_INTERFACE_ID: constant(bytes32)  = 0x0000000000000000000000000000000000000000000000000000000001ffc9a7\\nERC1155_INTERFACE_ID: constant(bytes32) = 0x00000000000000000000000000000000000000000000000000000000d9b67a26\\ntokensIdCount: uint256\\nowner: public(address)\\n\\nbalancesOf: map(address, map(uint256, uint256))\\nnoncesOf: map(address, map(uint256, bool))\\nuri: map(uint256, string[256])\\noperators: map(address, map(address, bool))\\ntoken_ids: map(uint256, bool)\\n\\n# This is to be set before contract migration!\\nBATCH_SIZE: constant(uint256) = 10\\n\\n\\n@public\\ndef __init__():\\n    \\\"\\\"\\\"\\n    @notice Called once and only upon contract deployment.\\n    \\\"\\\"\\\"\\n    self.tokensIdCount = convert(0, uint256)\\n    self.supportedInterfaces[ERC165_INTERFACE_ID] = True\\n    self.supportedInterfaces[ERC1155_INTERFACE_ID] = True\\n    self.owner = msg.sender\\n\\n########################END-INITIALIZATION####################################\\n########################PRIVATE-FUNCTIONS####################################\\n\\n\\n######### THIS IS A TEMPORARY SOLUTION #################\\n@public\\n@constant\\ndef getAddress(_addr: address) -> bytes32:\\n    hash: bytes32 = convert(_addr, bytes32)\\n    return hash\\n##################### END ##############################\\n\\n@private\\n@constant\\ndef _getHash(_from: address, _to: address, _ids: uint256[BATCH_SIZE], _from_supplies: uint256[BATCH_SIZE], _to_supplies: uint256[BATCH_SIZE], _value_eth: uint256, _nonce: uint256) -> bytes32:\\n    \\\"\\\"\\\"\\n    @notice Get the hash from the tx values.\\n    @param _from          The address of the sender.\\n    @param _to            The address of the receiver.\\n    @param _ids           The ids of the tokens.\\n    @param _from_supplies The supply of token values that will send the _from.\\n    @param _to_supplies   The supply of token values that will send the _from.\\n    @param _value_eth     The value of the ether.\\n    @param _nonce         The nonce.\\n    @return the hash\\n    \\\"\\\"\\\"\\n    aggregate_hash: bytes32 = keccak256(concat(convert(_ids[0], bytes32), convert(_from_supplies[0], bytes32), convert(_to_supplies[0], bytes32)))\\n    for i in range(BATCH_SIZE):\\n      if not i == 0:\\n        aggregate_hash = keccak256(concat(aggregate_hash, convert(_ids[i], bytes32), convert(_from_supplies[i], bytes32), convert(_to_supplies[i], bytes32)))\\n    hash: bytes32 = keccak256(concat(convert(_from, bytes32),\\n                              convert(_to, bytes32),\\n                              aggregate_hash,\\n                              convert(_value_eth, bytes32),\\n                              convert(_nonce, bytes32)))\\n    return hash\\n\\n\\n@public\\n@constant\\ndef getHash(_from: address, _to: address, _ids: uint256[BATCH_SIZE], _from_supplies: uint256[BATCH_SIZE], _to_supplies: uint256[BATCH_SIZE], _value_eth: uint256, _nonce: uint256) -> bytes32:\\n    \\\"\\\"\\\"\\n    @notice Get the hash from the tx values.\\n    @param _from          The address of the sender.\\n    @param _to            The address of the receiver.\\n    @param _ids           The ids of the tokens.\\n    @param _from_supplies The supply of token values that will send the _from.\\n    @param _to_supplies   The supply of token values that will send the _from.\\n    @param _value_eth     The value of the ether.\\n    @param _nonce         The nonce.\\n    @return the hash\\n    \\\"\\\"\\\"\\n    return self._getHash(_from, _to, _ids, _from_supplies, _to_supplies, _value_eth, _nonce)\\n\\n\\n@private\\n@constant\\ndef getHashOld(_from: address, _to: address, _ids: uint256[BATCH_SIZE], _from_supplies: uint256[BATCH_SIZE], _to_supplies: uint256[BATCH_SIZE], _value_eth: uint256, _nonce: uint256) -> bytes32:\\n    \\\"\\\"\\\"\\n    @notice Get the hash from the tx values.\\n    @param _from          The address of the sender.\\n    @param _to            The address of the receiver.\\n    @param _ids           The ids of the tokens.\\n    @param _from_supplies The supply of token values that will send the _from.\\n    @param _to_supplies   The supply of token values that will send the _from.\\n    @param _value_eth     The value of the ether.\\n    @param _nonce         The nonce.\\n    @return the hash\\n    \\\"\\\"\\\"\\n    hash: bytes32 = keccak256(concat(convert(_from, bytes32),\\n                              convert(_to, bytes32),\\n                              convert(_ids[0], bytes32),\\n                              convert(_ids[1], bytes32),\\n                              convert(_ids[2], bytes32),\\n                              convert(_ids[3], bytes32),\\n                              convert(_ids[4], bytes32),\\n                              convert(_ids[5], bytes32),\\n                              convert(_ids[6], bytes32),\\n                              convert(_ids[7], bytes32),\\n                              convert(_ids[8], bytes32),\\n                              convert(_ids[9], bytes32),\\n                              convert(_from_supplies[0], bytes32),\\n                              convert(_from_supplies[1], bytes32),\\n                              convert(_from_supplies[2], bytes32),\\n                              convert(_from_supplies[3], bytes32),\\n                              convert(_from_supplies[4], bytes32),\\n                              convert(_from_supplies[5], bytes32),\\n                              convert(_from_supplies[6], bytes32),\\n                              convert(_from_supplies[7], bytes32),\\n                              convert(_from_supplies[8], bytes32),\\n                              convert(_from_supplies[9], bytes32),\\n                              convert(_to_supplies[0], bytes32),\\n                              convert(_to_supplies[1], bytes32),\\n                              convert(_to_supplies[2], bytes32),\\n                              convert(_to_supplies[3], bytes32),\\n                              convert(_to_supplies[4], bytes32),\\n                              convert(_to_supplies[5], bytes32),\\n                              convert(_to_supplies[6], bytes32),\\n                              convert(_to_supplies[7], bytes32),\\n                              convert(_to_supplies[8], bytes32),\\n                              convert(_to_supplies[9], bytes32),\\n                              convert(_value_eth, bytes32),\\n                              convert(_nonce, bytes32)))\\n    return hash\\n\\n\\n@private\\n@constant\\ndef _getSingleHash(_from: address, _to: address, _id: uint256, _from_supply: uint256, _to_supply: uint256, _value_eth: uint256, _nonce: uint256) -> bytes32:\\n    \\\"\\\"\\\"\\n    @notice Get the hash from the tx values.\\n    @param _from            The address of the sender.\\n    @param _to              The address of the receiver.\\n    @param _id              The id of the tokens.\\n    @param _from_supply     The from token value. (_from sends)\\n    @param _to_supply       The to token value (_to sends).\\n    @param _value_eth       The value of the ether.\\n    @param _nonce           The nonce.\\n    @return the hash\\n    \\\"\\\"\\\"\\n    hash: bytes32 = keccak256(concat(convert(_from, bytes32),\\n                              convert(_to, bytes32),\\n                              convert(_id, bytes32),\\n                              convert(_from_supply, bytes32),\\n                              convert(_to_supply, bytes32),\\n                              convert(_value_eth, bytes32),\\n                              convert(_nonce, bytes32)))\\n    return hash\\n\\n\\n@public\\n@constant\\ndef getSingleHash(_from: address, _to: address, _id: uint256, _from_supply: uint256, _to_supply: uint256, _value_eth: uint256, _nonce: uint256) -> bytes32:\\n    \\\"\\\"\\\"\\n    @notice Get the hash from the tx values.\\n    @param _from            The address of the sender.\\n    @param _to              The address of the receiver.\\n    @param _id              The id of the tokens.\\n    @param _from_supply     The from token value. (_from sends)\\n    @param _to_supply       The to token value (_to sends).\\n    @param _value_eth       The value of the ether.\\n    @param _nonce           The nonce.\\n    @return the hash\\n    \\\"\\\"\\\"\\n    return self._getSingleHash(_from, _to, _id, _from_supply, _to_supply, _value_eth, _nonce)\\n\\n\\n@private\\n@constant\\ndef ecrecoverSig(_hash: bytes32, _sig: bytes[65]) -> address:\\n    \\\"\\\"\\\"\\n    @notice Check whether the the signature matches the hash.\\n    @param _hash The hash to be checked.\\n    @param _sig  The signature which is meant to match the hash.\\n    @return the address which signed the signature or the zero address\\n    \\\"\\\"\\\"\\n    if len(_sig) != 65:\\n        return ZERO_ADDRESS\\n    # ref. https://gist.github.com/axic/5b33912c6f61ae6fd96d6c4a47afde6d\\n    # The signature format is a compact form of:\\n    # {bytes32 r}{bytes32 s}{uint8 v}\\n    r: bytes32 = extract32(_sig, 0, type=bytes32)\\n    s: bytes32 = extract32(_sig, 32, type=bytes32)\\n    v: int128 = convert(slice(_sig, start=64, len=1), int128)\\n    # Version of signature should be 27 or 28, but 0 and 1 are also possible versions.\\n    # geth uses [0, 1] and some clients have followed. This might change, see:\\n    # https://github.com/ethereum/go-ethereum/issues/2053\\n    if v < 27:\\n        v += 27\\n    if v in [27, 28]:\\n        return ecrecover(_hash, convert(v, uint256), convert(r, uint256), convert(s, uint256))\\n    return ZERO_ADDRESS\\n\\n\\n@private\\n@constant\\ndef decode_id(id: uint256) -> int128:\\n    \\\"\\\"\\\"\\n    @notice Decodes the id of the token inorder to find out if it NFT or FT.\\n    @param id: uint256\\n    @return token_id : int128 (Specified id for FT and NFT.)\\n    @dev shift(x, -y): returns x with the bits shifted to the right by y places, which is equivalent to dividing x by 2**y.\\n    \\\"\\\"\\\"\\n    decoded_token_id: int128 = convert(shift(id, -128), int128)\\n    decoded_index: int128 = convert(id % 2 ** 128, int128)\\n    return decoded_token_id\\n\\n########################END-PRIVATE-FUNCTIONS################################\\n########################PUBLIC-FUNCTIONS#####################################\\n\\n@public\\n@constant\\ndef supportsInterface(_interfaceID: bytes32) -> bool:\\n    \\\"\\\"\\\"\\n    @notice Check whether the interface id is supported.\\n    @param _interfaceID The interface id\\n    @return True if the interface id is supported.\\n    \\\"\\\"\\\"\\n    return self.supportedInterfaces[_interfaceID]\\n\\n@public\\n@constant\\ndef is_nonce_used(addr: address, nonce: uint256) -> bool:\\n    \\\"\\\"\\\"\\n    @notice Checks if the given nonce for the give address is unused.\\n    @param nonce: uint256 the counter of the transaction\\n    @param address: the address that want to transact.\\n    \\\"\\\"\\\"\\n    return self.noncesOf[addr][nonce]\\n\\n@public\\n@constant\\ndef is_token_id_exists(token_id: uint256) -> bool:\\n    \\\"\\\"\\\"\\n    @notice Checks if the given token_id is already created.\\n    @param token_id: uint256 the id of the token.\\n    \\\"\\\"\\\"\\n    return self.token_ids[token_id]\\n\\n@public\\ndef safeTransferFrom(_from: address, _to: address, _id: uint256, _value: uint256, _data: bytes[256]):\\n    \\\"\\\"\\\"\\n    @notice Transfers `_value` amount of an `_id` from the `_from` address to the `_to` address specified (with safety call).\\n    @dev Caller must be approved to manage the tokens being transferred out of the `_from` account (see \\\"Approval\\\" section of the standard).\\n         MUST revert if `_to` is the zero address.\\n         MUST revert if balance of holder for token `_id` is lower than the `_value` sent.\\n         MUST revert on any other error.\\n         MUST emit the `TransferSingle` event to reflect the balance change (see \\\"Safe Transfer Rules\\\" section of the standard).\\n         After the above conditions are met, this function MUST check if `_to` is a smart contract (e.g. code size > 0). If so, it MUST call `onERC1155Received` on `_to` and act appropriately (see \\\"Safe Transfer Rules\\\" section of the standard).\\n    @param _from    Source address\\n    @param _to      Target address\\n    @param _id      ID of the token type\\n    @param _value   Transfer amount\\n    @param _data    Additional data with no specified format, MUST be sent unaltered in call to `onERC1155Received` on `_to`\\n    @return None\\n    \\\"\\\"\\\"\\n    assert _from == msg.sender or (self.operators[_from])[msg.sender]\\n    assert _to != ZERO_ADDRESS, \\\"Cannot transfer to zero address.\\\"\\n    assert self.balancesOf[_from][_id] >= _value, \\\"Not enough tokens.\\\"\\n\\n    self.balancesOf[_from][_id] -= _value\\n    self.balancesOf[_to][_id] += _value\\n\\n    log.TransferSingle(msg.sender, _from, _to, _id, _value)\\n\\n    if _to.is_contract:\\n        returnValue: bytes32 = ERC1155TokenReceiver(_to).onERC1155Received(msg.sender, _from, _id, _value, _data)\\n        assert returnValue == method_id(\\\"onERC1155Received(address,address,uint256,uint256,bytes)\\\", bytes32)\\n\\n\\n@public\\ndef safeBatchTransferFrom(_from: address, _to: address, _ids: uint256[BATCH_SIZE], _values: uint256[BATCH_SIZE], _data: bytes[256]):\\n    \\\"\\\"\\\"\\n    @notice Transfers `_values` amount(s) of `_ids` from the `_from` address to the `_to` address specified (with safety call).\\n    @dev Caller must be approved to manage the tokens being transferred out of the `_from` account (see \\\"Approval\\\" section of the standard).\\n        MUST revert if `_to` is the zero address.\\n        MUST revert if length of `_ids` is not the same as length of `_values`.\\n        MUST revert if any of the balance(s) of the holder(s) for token(s) in `_ids` is lower than the respective amount(s) in `_values` sent to the recipient.\\n        MUST revert on any other error.\\n        MUST emit `TransferSingle` or `TransferBatch` event(s) such that all the balance changes are reflected (see \\\"Safe Transfer Rules\\\" section of the standard).\\n        Balance changes and events MUST follow the ordering of the arrays (_ids[0]/_values[0] before _ids[1]/_values[1], etc).\\n        After the above conditions for the transfer(s) in the batch are met, this function MUST check if `_to` is a smart contract (e.g. code size > 0). If so, it MUST call the relevant `ERC1155TokenReceiver` hook(s) on `_to` and act appropriately (see \\\"Safe Transfer Rules\\\" section of the standard).\\n    @param _from    Source address\\n    @param _to      Target address\\n    @param _ids     IDs of each token type (order and length must match _values array)\\n    @param _values  Transfer amounts per token type (order and length must match _ids array)\\n    @param _data    Additional data with no specified format, MUST be sent unaltered in call to the `ERC1155TokenReceiver` hook(s) on `_to`\\n    @return None\\n    \\\"\\\"\\\"\\n    assert _from == msg.sender or (self.operators[_from])[msg.sender]\\n    assert _to != ZERO_ADDRESS, \\\"Cannot transfer to zero address.\\\"\\n    for i in range(BATCH_SIZE):\\n        id: uint256 = _ids[i]\\n        assert self.balancesOf[_from][id] >= _values[i]\\n\\n    log.TransferBatch(msg.sender, _from, _to, _ids, _values)\\n\\n    for i in range(BATCH_SIZE):\\n        id: uint256 = _ids[i]\\n        self.balancesOf[_from][id] -= _values[i]\\n        self.balancesOf[_to][id] += _values[i]\\n\\n    if _to.is_contract:\\n        returnValue: bytes32 = ERC1155TokenReceiver(_to).onERC1155BatchReceived(msg.sender, _from, _ids, _values, _data)\\n        assert returnValue == method_id(\\\"onERC1155BatchReceived(address,address,uint256[BATCH_SIZE],uint256[BATCH_SIZE],bytes)\\\", bytes32)\\n\\n\\n@public\\n@constant\\ndef balanceOf(_owner: address, _id: uint256) -> uint256:\\n    \\\"\\\"\\\"\\n    @notice Get the balance of an account's tokens.\\n    @param  _owner The address of the token holder\\n    @param  _id    ID of the token\\n    @return The _owner's balance of the token type requested\\n    \\\"\\\"\\\"\\n    return self.balancesOf[_owner][_id]\\n\\n\\n@public\\n@constant\\ndef balanceOfBatch( _owner: address[BATCH_SIZE], _ids: uint256[BATCH_SIZE]) -> uint256[BATCH_SIZE]:\\n    \\\"\\\"\\\"\\n    @notice Get the balance of multiple account/token pairs\\n    @param _owners The addresses of the token holders\\n    @param _ids    ID of the tokens\\n    @return The _owner's balance of the token types requested (i.e. balance for each (owner, id) pair)\\n    \\\"\\\"\\\"\\n    returnBalances: uint256[BATCH_SIZE]\\n    for i in range(BATCH_SIZE):\\n        returnBalances[i] = self.balancesOf[_owner[i]][_ids[i]]\\n    return returnBalances\\n\\n\\n@public\\ndef setApprovalForAll(_operator: address, _approved: bool):\\n    \\\"\\\"\\\"\\n    @notice Enable or disable approval for a third party (\\\"operator\\\") to manage all of the caller's tokens.\\n    @dev MUST emit the ApprovalForAll event on success.\\n    @param _operator  Address to add to the set of authorized operators\\n    @param _approved  True if the operator is approved, false to revoke approval\\n    @return None\\n    \\\"\\\"\\\"\\n    (self.operators[msg.sender])[_operator] = _approved\\n    log.ApprovalForAll(msg.sender, _operator, _approved)\\n\\n\\n@public\\n@constant\\ndef isApprovedForAll(_owner: address, _operator: address) -> bool:\\n    \\\"\\\"\\\"\\n    @notice Queries the approval status of an operator for a given owner.\\n    @param _owner     The owner of the tokens.\\n    @param _operator  Address of authorized operator.\\n    @return True if the operator is approved, false if not\\n    \\\"\\\"\\\"\\n    return (self.operators[_owner])[_operator]\\n\\n\\n@public\\ndef createSingle(_item_owner: address, _id: uint256, _path: string[256]):\\n    \\\"\\\"\\\"\\n    @notice Create a new token type that we can mint later.\\n    @param _item_owner The owner of the item.\\n    @param _id         The id of the token.\\n    @param _path       The path to the token data.\\n    @return None\\n    \\\"\\\"\\\"\\n    assert _item_owner != ZERO_ADDRESS\\n    assert self.owner == msg.sender, \\\"Owner only can create item.\\\"\\n    self.balancesOf[_item_owner][_id] = 0\\n    self.tokensIdCount += 1\\n    self.token_ids[_id] = True\\n    self.uri[_id] = _path\\n    log.URI(_path, _id)\\n    log.TransferSingle(msg.sender, ZERO_ADDRESS, _item_owner, _id, 0)\\n\\n\\n@public\\ndef createBatch(_items_owner: address, _ids: uint256[BATCH_SIZE]):\\n    \\\"\\\"\\\"\\n    @notice Create new token types that we can mint later.\\n    @param _items_owner The owner of the items.\\n    @param _ids         The ids of the tokens.\\n    @return None\\n    \\\"\\\"\\\"\\n    assert _items_owner != ZERO_ADDRESS\\n    assert self.owner == msg.sender, \\\"Owner only can create items.\\\"\\n    for i in range(BATCH_SIZE):\\n        id: uint256 = _ids[i]\\n        self.balancesOf[_items_owner][id] = 0\\n        self.tokensIdCount += 1\\n        self.token_ids[id] = True\\n    zero_supply: uint256[BATCH_SIZE] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]\\n    log.TransferBatch(msg.sender, ZERO_ADDRESS, _items_owner, _ids, zero_supply)\\n\\n\\n@public\\ndef mint(_to: address, _id: uint256, _supply: uint256, _data: bytes[256]=\\\"\\\"):\\n    \\\"\\\"\\\"\\n    @notice Mint a token.\\n    @dev This is not part of the standard.\\n    @param _to      The address of the receiver.\\n    @param _id      The id of the token.\\n    @param _supply  The supply to be minted for the token.\\n    @param _data    The data.\\n    @return None\\n    \\\"\\\"\\\"\\n    assert _to != ZERO_ADDRESS\\n    assert self.owner == msg.sender, \\\"Owner only can mint items.\\\"\\n    decoded_id: int128 = self.decode_id(_id)\\n    assert decoded_id == 1 or decoded_id == 2\\n    if decoded_id == 1 :\\n        assert _supply == 1, \\\"Cannot mint NFT with _supply more than 1\\\"\\n    self.balancesOf[_to][_id] = _supply\\n\\n    log.TransferSingle(msg.sender, ZERO_ADDRESS, _to, _id, _supply)\\n\\n    if _to.is_contract:\\n        returnValue: bytes32 = ERC1155TokenReceiver(_to).onERC1155Received(msg.sender, ZERO_ADDRESS, _id, _supply, _data)\\n        assert returnValue == method_id(\\\"onERC1155Received(address,address,uint256,uint256,bytes)\\\", bytes32)\\n\\n\\n@public\\ndef mintBatch(_to: address, _ids: uint256[BATCH_SIZE], _supplies: uint256[BATCH_SIZE], _data: bytes[256]=\\\"\\\"):\\n    \\\"\\\"\\\"\\n    @notice Mint a batch of tokens.\\n    @dev This is not part of the standard.\\n    @param _to      The address of the receiver.\\n    @param _ids     The ids of the tokens.\\n    @param _supplies The supply to be minted for each token.\\n    @param _data    The data.\\n    @return None\\n    \\\"\\\"\\\"\\n    assert _to != ZERO_ADDRESS\\n    assert self.owner == msg.sender, \\\"Owner only can mint items.\\\"\\n\\n    for i in range(BATCH_SIZE):\\n        id: uint256 = _ids[i]\\n        decoded_id: int128 = self.decode_id(id)\\n        assert decoded_id == 1 or decoded_id == 2\\n\\n        if decoded_id == 1 :\\n            assert _supplies[i] == 1\\n\\n        self.balancesOf[_to][id] = _supplies[i]\\n\\n    log.TransferBatch(msg.sender, ZERO_ADDRESS, _to, _ids, _supplies)\\n\\n    for i in range(BATCH_SIZE):\\n        if _to.is_contract:\\n            returnValue: bytes32 = ERC1155TokenReceiver(_to).onERC1155Received(msg.sender, ZERO_ADDRESS, _ids[i], _supplies[i], _data)\\n            assert returnValue == method_id(\\\"onERC1155Received(address,address,uint256,uint256,bytes)\\\", bytes32)\\n\\n\\n@public\\ndef burn(_id: uint256, _supply: uint256):\\n    \\\"\\\"\\\"\\n    @notice Burns the supply of the specified token.\\n    @param _id        The id of the token\\n    @param _supply    Supply to be burned\\n    @return None\\n    \\\"\\\"\\\"\\n    assert self.balancesOf[msg.sender][_id] >= _supply, \\\"Not enough tokens to burn.\\\"\\n    self.balancesOf[msg.sender][_id] -= _supply\\n    log.TransferSingle(msg.sender, msg.sender, ZERO_ADDRESS, _id, _supply)\\n\\n\\n@public\\ndef burnBatch(_ids: uint256[BATCH_SIZE], _supplies: uint256[BATCH_SIZE]):\\n    \\\"\\\"\\\"\\n    @notice Burns the supply of the specified tokens.\\n    @dev At this point anyone can burn items if they own it.\\n    @param _ids        The ids of the token\\n    @param _supplies   Supplies to be burned\\n    @return None\\n    \\\"\\\"\\\"\\n    for i in range(BATCH_SIZE):\\n        id: uint256 = _ids[i]\\n        assert self.balancesOf[msg.sender][id] >= _supplies[i]\\n\\n    for i in range(BATCH_SIZE):\\n        id: uint256 = _ids[i]\\n        self.balancesOf[msg.sender][id] -= _supplies[i]\\n    log.TransferBatch(msg.sender, msg.sender, ZERO_ADDRESS, _ids, _supplies)\\n\\n\\n@public\\n@payable\\ndef tradeBatch(_from: address, _to: address, _ids: uint256[BATCH_SIZE], _from_supplies: uint256[BATCH_SIZE], _to_supplies: uint256[BATCH_SIZE], _value_eth: uint256, _nonce: uint256, _signature: bytes[65], _data: bytes[256]=\\\"\\\"):\\n    \\\"\\\"\\\"\\n    @notice Trade (atomically swap) tokens with tokens or eth.\\n    @dev Caller must be approved to manage the tokens being transferred out of the `_from` account (see \\\"Approval\\\" section of the standard).\\n        MUST revert if `_to` is the zero address.\\n        MUST revert if _from_supplies[i] > 0 and _to_supplies[i] > 0\\n        MUST revert if len(_ids) != len(_from_supplies) != len(_to_supplies)\\n        MUST revert if _value_eth != msg.value\\n        MUST revert if any of the balance(s) of the holder(s) for token(s) in `_ids` is lower than the respective amount(s) in `positive and negative values` sent to the recipient.\\n        MUST revert on any other error.\\n        MUST emit `TransferSingle` or `TransferBatch` event(s) such that all the balance changes are reflected (see \\\"Safe Transfer Rules\\\" section of the standard).\\n        Balance changes and events MUST follow the ordering of the arrays (_ids[0]/_values[0] before _ids[1]/_values[1], etc).\\n        After the above conditions for the transfer(s) in the batch are met, this function MUST check if `_to` is a smart contract (e.g. code size > 0). If so, it MUST call the relevant `ERC1155TokenReceiver` hook(s) on `_to` and act appropriately (see \\\"Safe Transfer Rules\\\" section of the standard).\\n    @param _from          The address of the sender.\\n    @param _to            The address of the receiver.\\n    @param _ids           The ids of the tokens.\\n    @param _from_supplies The supply of token values that will send the _from.\\n    @param _to_supplies   The supply of token values that will send the _from.\\n    @param _value_eth     The value of the ether.\\n    @param _nonce         The nonce.\\n    @param _signature    The signature of the _to address.\\n    @param _data    The data.\\n    @return None\\n    \\\"\\\"\\\"\\n    # Assert the value of the transaction is less than the balance of A.\\n\\n    assert _from == msg.sender or (self.operators[_from])[msg.sender], \\\"_from must be the sender or approved address\\\"\\n    assert _to != ZERO_ADDRESS, \\\"Destination address must be non-zero.\\\"\\n    assert self.noncesOf[_from][_nonce] == False, \\\"Nonce must be unused.\\\"\\n    assert _value_eth == msg.value, \\\"Sender has not provided enough ether.\\\"\\n\\n    for i in range(BATCH_SIZE):\\n       id: uint256 = _ids[i]\\n       if _from_supplies[i] > 0:\\n           assert _to_supplies[i] == 0\\n           assert self.balancesOf[_from][id] >= _from_supplies[i]\\n       else:\\n           assert _from_supplies[i] == 0\\n           assert self.balancesOf[_to][id] >= _to_supplies[i]\\n\\n    # Create hash from variables.\\n    hash: bytes32 = self._getHash(_from, _to, _ids, _from_supplies, _to_supplies, _value_eth, _nonce)\\n\\n    # Assert that the ecrecover(address,signature) returns true.\\n    recovered_to: address = self.ecrecoverSig(hash, _signature)\\n    assert recovered_to == _to, \\\"Signer does not match signature.\\\"\\n\\n    # Store the nonce\\n    self.noncesOf[msg.sender][_nonce] = True\\n\\n    # Update the balances\\n    for i in range(BATCH_SIZE):\\n        id: uint256 = _ids[i]\\n        if _from_supplies[i] > 0:\\n            self.balancesOf[_from][id] -= _from_supplies[i]\\n            self.balancesOf[_to][id] += _from_supplies[i]\\n        else:\\n            self.balancesOf[_from][id] += _to_supplies[i]\\n            self.balancesOf[_to][id] -= _to_supplies[i]\\n\\n    send(_to, msg.value)\\n\\n    log.TransferBatch(msg.sender, _from, _to, _ids, _from_supplies)\\n    log.TransferBatch(msg.sender, _to, _from, _ids, _to_supplies)\\n\\n\\n    if _to.is_contract:\\n        returnValue: bytes32 = ERC1155TokenReceiver(_to).onERC1155BatchReceived(msg.sender, _to, _ids, _from_supplies, _data)\\n        assert returnValue == method_id(\\\"onERC1155BatchReceived(address,address,uint256,uint256,bytes)\\\", bytes32)\\n    if _from.is_contract:\\n        returnValue: bytes32 = ERC1155TokenReceiver(_from).onERC1155BatchReceived(msg.sender, _from, _ids, _to_supplies, _data)\\n        assert returnValue == method_id(\\\"onERC1155BatchReceived(address,address,uint256,uint256,bytes)\\\", bytes32)\\n\\n\\n\\n@public\\n@payable\\ndef trade(_from: address, _to: address, _id: uint256, _from_supply: uint256, _to_supply: uint256, _value_eth: uint256, _nonce: uint256, _signature: bytes[65], _data: bytes[256]=\\\"\\\"):\\n    \\\"\\\"\\\"\\n    @notice Trade (atomically swap) tokens with tokens or eth.\\n    @dev Caller must be approved to manage the tokens being transferred out of the `_from` account (see \\\"Approval\\\" section of the standard).\\n        MUST revert if `_to` is the zero address.\\n        MUST revert if _from_supply > 0 and _to_supply > 0\\n        MUST revert if _value_eth != msg.value\\n        MUST revert if any of the balance(s) of the holder(s) for token(s) in `_id` is lower than the respective amount in `positive or negative value` sent to the recipient.\\n        MUST revert on any other error.\\n        MUST emit `TransferSingle` or `TransferBatch` event(s) such that all the balance changes are reflected (see \\\"Safe Transfer Rules\\\" section of the standard).\\n        Balance changes and events MUST follow the ordering of the arrays (_ids[0]/_values[0] before _ids[1]/_values[1], etc).\\n        After the above conditions for the transfer(s) in the batch are met, this function MUST check if `_to` is a smart contract (e.g. code size > 0). If so, it MUST call the relevant `ERC1155TokenReceiver` hook(s) on `_to` and act appropriately (see \\\"Safe Transfer Rules\\\" section of the standard).\\n    @param _from            The from address (seller of eth, potential receiver of tokens).\\n    @param _to              The receiver address (receiver of tokens).\\n    @param _id              The id of the token\\n    @param _from_supply     The change in value of token (for _from)\\n    @param _to_supply       The change in value of token (for _to)\\n    @param _value_eth       The value of the ETH sent to the _from address.\\n    @param _nonce           The nonce.\\n    @param _signature       The signature of the _to address.\\n    @param _data    The data.\\n    @return None\\n    \\\"\\\"\\\"\\n    # Assert the value of the transaction is less than the balance of A.\\n    assert _from == msg.sender or (self.operators[_from])[msg.sender]\\n    assert _to != ZERO_ADDRESS, \\\"Destination address must be non-zero.\\\"\\n    assert self.noncesOf[_from][_nonce] == False, \\\"Nonce must be unused.\\\"\\n    assert _value_eth == msg.value, \\\"Sender has not provided enough ether.\\\"\\n    if _from_supply > 0:\\n        assert _to_supply == 0\\n        assert self.balancesOf[_from][_id] >= _from_supply\\n    else:\\n        assert _from_supply == 0\\n        assert self.balancesOf[_to][_id] >= _to_supply\\n\\n    # Create hash from variables.\\n    hash: bytes32 = self._getSingleHash(_from, _to, _id, _from_supply, _to_supply, _value_eth, _nonce)\\n\\n    # Assert that the ecrecover(address,signature) returns true.\\n    recovered_to: address = self.ecrecoverSig(hash, _signature)\\n    assert recovered_to == _to, \\\"Signer does not match signature.\\\"\\n\\n    # Store the nonce\\n    self.noncesOf[msg.sender][_nonce] = True\\n\\n    # Update the balances\\n    if _from_supply > 0:\\n        self.balancesOf[_from][_id] -= _from_supply\\n        self.balancesOf[_to][_id] += _from_supply\\n    else:\\n        self.balancesOf[_from][_id] += _to_supply\\n        self.balancesOf[_to][_id] -= _to_supply\\n\\n    send(_to, msg.value)\\n\\n    log.TransferSingle(msg.sender, _from, _to, _id, _from_supply)\\n    log.TransferSingle(msg.sender, _to, _from, _id, _to_supply)\\n\\n    if _to.is_contract:\\n        returnValue: bytes32 = ERC1155TokenReceiver(_to).onERC1155Received(msg.sender, _to, _id, _from_supply, _data)\\n        assert returnValue == method_id(\\\"onERC1155BatchReceived(address,address,uint256,uint256,bytes)\\\", bytes32)\\n    if _from.is_contract:\\n        returnValue: bytes32 = ERC1155TokenReceiver(_from).onERC1155Received(msg.sender, _from, _id, _to_supply, _data)\\n        assert returnValue == method_id(\\\"onERC1155BatchReceived(address,address,uint256,uint256,bytes)\\\", bytes32)\\n\",\n  \"sourcePath\": \"/Users/aristotelistriantafyllidis/Documents/agents-research/erc1155/contracts/erc1155.vy\",\n  \"compiler\": {\n    \"name\": \"vyper\",\n    \"version\": \"0.1.0b12+commit.a01cdc8\"\n  },\n  \"networks\": {\n    \"1583918911727\": {\n      \"events\": {\n        \"0xc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62\": {\n          \"name\": \"TransferSingle\",\n          \"inputs\": [\n            {\n              \"type\": \"address\",\n              \"name\": \"_operator\",\n              \"indexed\": true\n            },\n            {\n              \"type\": \"address\",\n              \"name\": \"_from\",\n              \"indexed\": true\n            },\n            {\n              \"type\": \"address\",\n              \"name\": \"_to\",\n              \"indexed\": true\n            },\n            {\n              \"type\": \"uint256\",\n              \"name\": \"_id\",\n              \"indexed\": false\n            },\n            {\n              \"type\": \"uint256\",\n              \"name\": \"_value\",\n              \"indexed\": false\n            }\n          ],\n          \"anonymous\": false,\n          \"type\": \"event\",\n          \"signature\": \"0xc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62\"\n        },\n        \"0x514c24e4790d7c31a095a1688a73a01f28d936a9a85d806ba95970d8ee88efa8\": {\n          \"name\": \"TransferBatch\",\n          \"inputs\": [\n            {\n              \"type\": \"address\",\n              \"name\": \"_operator\",\n              \"indexed\": true\n            },\n            {\n              \"type\": \"address\",\n              \"name\": \"_from\",\n              \"indexed\": true\n            },\n            {\n              \"type\": \"address\",\n              \"name\": \"_to\",\n              \"indexed\": true\n            },\n            {\n              \"type\": \"uint256[10]\",\n              \"name\": \"_ids\",\n              \"indexed\": false\n            },\n            {\n              \"type\": \"uint256[10]\",\n              \"name\": \"_values\",\n              \"indexed\": false\n            }\n          ],\n          \"anonymous\": false,\n          \"type\": \"event\",\n          \"signature\": \"0x514c24e4790d7c31a095a1688a73a01f28d936a9a85d806ba95970d8ee88efa8\"\n        },\n        \"0x17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31\": {\n          \"name\": \"ApprovalForAll\",\n          \"inputs\": [\n            {\n              \"type\": \"address\",\n              \"name\": \"_owner\",\n              \"indexed\": true\n            },\n            {\n              \"type\": \"address\",\n              \"name\": \"_operator\",\n              \"indexed\": true\n            },\n            {\n              \"type\": \"bool\",\n              \"name\": \"_approved\",\n              \"indexed\": false\n            }\n          ],\n          \"anonymous\": false,\n          \"type\": \"event\",\n          \"signature\": \"0x17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31\"\n        },\n        \"0x6bb7ff708619ba0610cba295a58592e0451dee2622938c8755667688daf3529b\": {\n          \"name\": \"URI\",\n          \"inputs\": [\n            {\n              \"type\": \"string\",\n              \"name\": \"_value\",\n              \"indexed\": false\n            },\n            {\n              \"type\": \"uint256\",\n              \"name\": \"_id\",\n              \"indexed\": true\n            }\n          ],\n          \"anonymous\": false,\n          \"type\": \"event\",\n          \"signature\": \"0x6bb7ff708619ba0610cba295a58592e0451dee2622938c8755667688daf3529b\"\n        }\n      },\n      \"links\": {},\n      \"address\": \"0x9561C133DD8580860B6b7E504bC5Aa500f0f06a7\",\n      \"transactionHash\": \"0x816b272ebd644b189a3addfbd429b0ea0fa7b2403cca3aa038bcd59f09d9c116\"\n    }\n  },\n  \"schemaVersion\": \"3.0.19\",\n  \"updatedAt\": \"2020-03-11T13:47:51.885Z\",\n  \"networkType\": \"ethereum\"\n}"
  },
  {
    "path": "tests/data/dummy_contract/contract.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains a dummy contract for an AEA.\"\"\"\n\nfrom aea.contracts.base import Contract\nfrom aea.crypto.base import LedgerApi\n\n\nclass DummyContract(Contract):\n    \"\"\"The some contract class.\"\"\"\n\n    @classmethod\n    def some_method(cls, ledger_api: LedgerApi, contract_address: str) -> None:\n        \"\"\"Some method.\"\"\"\n        pass\n"
  },
  {
    "path": "tests/data/dummy_contract/contract.yaml",
    "content": "name: dummy\nauthor: fetchai\nversion: 0.1.0\ntype: contract\ndescription: A test contract\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  __init__.py: QmURXWttkpyyuCk7YfhmvWyRx9xNXzZUmrXaZDJeucajzn\n  build/some.json: Qma5n7au2NDCg1nLwYfYnmFNwWChFuXtu65w5DV7wAZRvw\n  build/some.wasm: Qmc9gthbdwRSywinTHKjRVQdFzrKTxUuLDx2ryNfQp1xqf\n  contract.py: QmUw1VRch2sJGAzS5nb8JMFN2xYL5ovsm3SpnZMw9nV8zg\nfingerprint_ignore_patterns: []\nbuild_entrypoint: path/to/script.py\nclass_name: DummyContract\ncontract_interface_paths:\n  cosmos: build/some.wasm\n  ethereum: build/some.json\n  fetchai: build/some.wasm\ndependencies: {}\n"
  },
  {
    "path": "tests/data/dummy_protocol/protocol.yaml",
    "content": "name: dummy_protocol\nauthor: default_author\nversion: 0.1.0\nprotocol_specification_id: some_author/some_protocol_name:1.0.0\ntype: protocol\ndescription: The scaffold protocol scaffolds a protocol to be implemented by the developer.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  __init__.py: Qmc9Ln8THrWmwou4nr3Acag7vcZ1fv8v5oRSkCWtv1aH6t\n  message.py: QmWPrVTSHeKANCaVA4VaQyMGLix7yiMALbytsKZppAG2VU\n  serialization.py: QmaAf5fppirUWe8JaeBbsqfbeofTHe8DDGHJooe2X389qo\nfingerprint_ignore_patterns: []\nbuild_entrypoint: path/to/script.py\ndependencies: {}\n\n"
  },
  {
    "path": "tests/data/dummy_skill/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains a dummy skill for an AEA.\"\"\"\n\nfrom aea.configurations.base import PublicId\n\n\nPUBLIC_ID = PublicId.from_str(\"dummy_author/dummy:0.1.0\")\n"
  },
  {
    "path": "tests/data/dummy_skill/behaviours.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the behaviours for the 'dummy' skill.\"\"\"\n\nfrom aea.skills.base import Behaviour\n\n\nclass DummyBehaviour(Behaviour):\n    \"\"\"Dummy behaviour.\"\"\"\n\n    def __init__(self, **kwargs):\n        \"\"\"Initialize the echo behaviour.\"\"\"\n        super().__init__(**kwargs)\n        self.kwargs = kwargs\n        self.nb_act_called = 0\n        self.nb_teardown_called = 0\n\n    def setup(self) -> None:\n        \"\"\"\n        Implement the setup.\n\n        :return: None\n        \"\"\"\n        pass\n\n    def act(self) -> None:\n        \"\"\"Act according to the behaviour.\"\"\"\n        self.nb_act_called += 1\n\n    def teardown(self) -> None:\n        \"\"\"Teardown the behaviour.\"\"\"\n        self.nb_teardown_called += 1\n"
  },
  {
    "path": "tests/data/dummy_skill/dummy.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains a dummy model.\"\"\"\n\nfrom aea.skills.base import Model\n\n\nclass DummyModel(Model):\n    \"\"\"This class is a dummy model.\"\"\"\n"
  },
  {
    "path": "tests/data/dummy_skill/dummy_subpackage/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This is a skill subpackage (for testing purposes).\"\"\"\n"
  },
  {
    "path": "tests/data/dummy_skill/dummy_subpackage/foo.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module is in a skill sub-package (for testing purposes).\"\"\"\nfrom aea.protocols.base import Message\nfrom aea.skills.base import Behaviour, Handler\n\nfrom packages.fetchai.protocols.state_update import StateUpdateMessage\n\n\ndef bar():\n    \"\"\"A bar function.\"\"\"\n    return 42\n\n\nclass DummyBehaviour(Behaviour):\n    \"\"\"Dummy behaviour.\"\"\"\n\n    def __init__(self, **kwargs):\n        \"\"\"Initialize the dummy behaviour.\"\"\"\n        super().__init__(**kwargs)\n        self.kwargs = kwargs\n\n    def setup(self) -> None:\n        \"\"\"\n        Implement the setup.\n\n        :return: None\n        \"\"\"\n        pass\n\n    def act(self) -> None:\n        \"\"\"Act according to the behaviour.\"\"\"\n\n    def teardown(self) -> None:\n        \"\"\"Teardown the behaviour.\"\"\"\n\n\nclass DummyStateUpdateHandler(Handler):\n    \"\"\"Dummy handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = StateUpdateMessage.protocol_id\n\n    def __init__(self, **kwargs):\n        \"\"\"Initialize the handler.\"\"\"\n        super().__init__(**kwargs)\n        self.kwargs = kwargs\n\n    def setup(self) -> None:\n        \"\"\"\n        Implement the setup.\n\n        :return: None\n        \"\"\"\n        pass\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Handle message.\n\n        :param message: the message\n        :return: None\n        \"\"\"\n\n    def teardown(self) -> None:\n        \"\"\"\n        Teardown the handler.\n\n        :return: None\n        \"\"\"\n"
  },
  {
    "path": "tests/data/dummy_skill/handlers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the handler for the 'dummy' skill.\"\"\"\n\nfrom aea.protocols.base import Message\nfrom aea.skills.base import Handler\n\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.protocols.signing.message import SigningMessage\n\n\nclass DummyHandler(Handler):\n    \"\"\"Dummy handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = DefaultMessage.protocol_id\n\n    def __init__(self, **kwargs):\n        \"\"\"Initialize the handler.\"\"\"\n        super().__init__(**kwargs)\n        self.kwargs = kwargs\n        self.handled_messages = []\n        self.nb_teardown_called = 0\n\n    def setup(self) -> None:\n        \"\"\"\n        Implement the setup.\n\n        :return: None\n        \"\"\"\n        pass\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Handle message.\n\n        :param message: the message\n        :return: None\n        \"\"\"\n        self.handled_messages.append(message)\n\n    def teardown(self) -> None:\n        \"\"\"\n        Teardown the handler.\n\n        :return: None\n        \"\"\"\n        self.nb_teardown_called += 1\n\n\nclass DummyInternalHandler(Handler):\n    \"\"\"Dummy internal handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = SigningMessage.protocol_id\n\n    def __init__(self, **kwargs):\n        \"\"\"Initialize the handler.\"\"\"\n        super().__init__(**kwargs)\n        self.kwargs = kwargs\n        self.handled_internal_messages = []\n        self.nb_teardown_called = 0\n\n    def setup(self) -> None:\n        \"\"\"\n        Implement the setup.\n\n        :return: None\n        \"\"\"\n        pass\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Handle message.\n\n        :param message: the message\n        :return: None\n        \"\"\"\n        self.handled_internal_messages.append(message)\n\n    def teardown(self) -> None:\n        \"\"\"\n        Teardown the handler.\n\n        :return: None\n        \"\"\"\n        self.nb_teardown_called += 1\n"
  },
  {
    "path": "tests/data/dummy_skill/skill.yaml",
    "content": "name: dummy\nauthor: dummy_author\nversion: 0.1.0\ntype: skill\ndescription: a dummy_skill for testing purposes.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  __init__.py: QmbTjuDJuSgXvD6guu4GJEyZC3BwwtTaSN7HkqgzkCTypX\n  behaviours.py: QmdN12JcAxikGXueDjuwyuGuvbcpihcznG2SLoRr24MDL4\n  dummy.py: QmW6RFSAACA7dy9N6ux22LRpsyCMWtFUXrgjy8YwoPf1XS\n  dummy_subpackage/__init__.py: QmUgN7JbokfWGK6NHxYKN7oSkqcpwupM2FQRVMANwkzjoA\n  dummy_subpackage/foo.py: QmXTMpmhi4qd7VH7rBFaSzDEFnYyj2r7EvALQzcwpK9PcN\n  handlers.py: QmTpiZ1B5RoAKGF1t6TYuhdPemAZ75YuveQpZNETqjphVS\n  tasks.py: QmeEex6NZvzHDSkQakPRTjymAYvyxd4t65mU6RiYAn8DVv\nfingerprint_ignore_patterns: []\ncontracts: []\nprotocols:\n- fetchai/default:1.1.7\n- fetchai/signing:1.1.7\n- fetchai/state_update:1.1.7\nskills: []\nbehaviours:\n  dummy:\n    args:\n      behaviour_arg_1: 1\n      behaviour_arg_2: '2'\n    class_name: DummyBehaviour\n  dummy_behaviour_same_classname:\n    args:\n      behaviour_arg_1: 1\n      behaviour_arg_2: '2'\n    class_name: DummyBehaviour\n    file_path: dummy_subpackage/foo.py\nhandlers:\n  another_dummy_handler:\n    args:\n      handler_arg_1: 1\n      handler_arg_2: '2'\n    class_name: DummyStateUpdateHandler\n  dummy:\n    args:\n      handler_arg_1: 1\n      handler_arg_2: '2'\n    class_name: DummyHandler\n  dummy_internal:\n    args:\n      handler_arg_1: 1\n      handler_arg_2: '2'\n    class_name: DummyInternalHandler\nmodels:\n  dummy:\n    args:\n      model_arg_1: 1\n      model_arg_2: '2'\n    class_name: DummyModel\ndependencies: {}\nis_abstract: false\nconnections: []\n"
  },
  {
    "path": "tests/data/dummy_skill/tasks.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tasks for the 'dummy' skill.\"\"\"\nfrom aea.skills.tasks import Task\n\n\nclass DummyTask(Task):\n    \"\"\"Dummy task.\"\"\"\n\n    def __init__(self, **kwargs):\n        \"\"\"Initialize the task.\"\"\"\n        super().__init__(**kwargs)\n        self.kwargs = kwargs\n        self.nb_execute_called = 0\n        self.nb_teardown_called = 0\n\n    def setup(self) -> None:\n        \"\"\"\n        Implement the setup.\n\n        :return: None\n        \"\"\"\n        pass\n\n    def execute(self, *args, **kwargs) -> int:\n        \"\"\"Execute the task.\"\"\"\n        self.nb_execute_called += 1\n        return self.nb_execute_called\n\n    def teardown(self) -> None:\n        \"\"\"Teardown the task.\"\"\"\n        self.nb_teardown_called += 1\n"
  },
  {
    "path": "tests/data/ethereum_private_key.txt",
    "content": "0x6F611408F7EF304947621C51A4B7D84A13A2B9786E9F984DA790A096E8260C64"
  },
  {
    "path": "tests/data/ethereum_private_key_two.txt",
    "content": "0x04b4cecf78288f2ab09d1b4c60219556928f86220f0fb2dcfc05e6a1c1149dbf"
  },
  {
    "path": "tests/data/exception_skill/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains a dummy 'exception' skill for an AEA.\"\"\"\n"
  },
  {
    "path": "tests/data/exception_skill/behaviours.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the behaviours for the 'exception' skill.\"\"\"\nfrom aea.skills.base import Behaviour\n\n\nclass ExceptionBehaviour(Behaviour):\n    \"\"\"A behaviour that raises an exception..\"\"\"\n\n    def setup(self) -> None:\n        \"\"\"\n        Implement the setup.\n\n        :return: None\n        \"\"\"\n\n    def act(self) -> None:\n        \"\"\"Act.\"\"\"\n        raise Exception(\"Expected exception!\")\n\n    def teardown(self) -> None:\n        \"\"\"Teardown the task.\"\"\"\n"
  },
  {
    "path": "tests/data/exception_skill/handlers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the handler for the 'exception' skill.\"\"\"\n"
  },
  {
    "path": "tests/data/exception_skill/skill.yaml",
    "content": "name: exception\nauthor: fetchai\nversion: 0.1.0\ntype: skill\ndescription: Raise an exception, at some point.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  __init__.py: QmRLyScuC6bY5DANwG1Mk9zNCfiD6arrP2uoSd3ruz7hXQ\n  behaviours.py: QmYnyEnHA73V488mTg5j1i9drtbnd2JBbQa71ypU1uaYuo\n  handlers.py: QmZnd7QMHo9pmwouLcfRFdy3daT4xMP1Cn1FfxYYbzmcXx\n  tasks.py: QmcXkhi79S4AJynSPQtFMqHr7NPT3NDb6EMDSMM3UqAVZZ\nfingerprint_ignore_patterns: []\nbuild_entrypoint: path/to/script.py\ncontracts: []\nprotocols: []\nskills: []\nbehaviours:\n  exception:\n    args: {}\n    class_name: ExceptionBehaviour\nhandlers: {}\nmodels: {}\ndependencies: {}\nis_abstract: false\nconnections: []\n"
  },
  {
    "path": "tests/data/exception_skill/tasks.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tasks for the 'exception' skill.\"\"\"\n"
  },
  {
    "path": "tests/data/fetchai_private_key.txt",
    "content": "6d56fd47e98465824aa85dfe620ad3dbf092b772abc6c6a182e458b5c56ad13b"
  },
  {
    "path": "tests/data/fetchai_private_key_wrong.txt",
    "content": "WRONG!!!!!\n6d56fd47e98465824aa85dfe620ad3dbf092b772abc6c6a182e458b5c56ad13b"
  },
  {
    "path": "tests/data/generator/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This test module contains the generator test data.\"\"\"\n"
  },
  {
    "path": "tests/data/generator/t_protocol/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nThis module contains the support resources for the t_protocol protocol.\n\nIt was created with protocol buffer compiler version `libprotoc 3.19.4` and aea version `1.2.5`.\n\"\"\"\n\nfrom tests.data.generator.t_protocol.message import TProtocolMessage\nfrom tests.data.generator.t_protocol.serialization import TProtocolSerializer\n\n\nTProtocolMessage.serializer = TProtocolSerializer\n"
  },
  {
    "path": "tests/data/generator/t_protocol/custom_types.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains class representations corresponding to every custom type in the protocol specification.\"\"\"\n\nfrom typing import Dict, List, Set\n\n\nclass DataModel:\n    \"\"\"This class represents an instance of DataModel.\"\"\"\n\n    def __init__(\n        self,\n        bytes_field: bytes,\n        int_field: int,\n        float_field: float,\n        bool_field: bool,\n        str_field: str,\n        set_field: Set[int],\n        list_field: List[str],\n        dict_field: Dict[int, bool],\n    ):\n        \"\"\"Initialise an instance of DataModel.\"\"\"\n        self.bytes_field = bytes_field\n        self.int_field = int_field\n        self.float_field = float_field\n        self.bool_field = bool_field\n        self.str_field = str_field\n        self.set_field = set_field\n        self.list_field = list_field\n        self.dict_field = dict_field\n\n    @staticmethod\n    def encode(data_model_protobuf_object, data_model_object: \"DataModel\") -> None:\n        \"\"\"\n        Encode an instance of this class into the protocol buffer object.\n\n        The protocol buffer object in the data_model_protobuf_object argument is matched with the instance of this class in the 'data_model_object' argument.\n\n        :param data_model_protobuf_object: the protocol buffer object whose type corresponds with this class.\n        :param data_model_object: an instance of this class to be encoded in the protocol buffer object.\n        :return: None\n        \"\"\"\n        data_model_protobuf_object.bytes_field = data_model_object.bytes_field\n        data_model_protobuf_object.int_field = data_model_object.int_field\n        data_model_protobuf_object.float_field = data_model_object.float_field\n        data_model_protobuf_object.bool_field = data_model_object.bool_field\n        data_model_protobuf_object.str_field = data_model_object.str_field\n\n        data_model_protobuf_object.set_field.extend(data_model_object.set_field)\n        data_model_protobuf_object.list_field.extend(data_model_object.list_field)\n        data_model_protobuf_object.dict_field.update(data_model_object.dict_field)\n\n    @classmethod\n    def decode(cls, data_model_protobuf_object) -> \"DataModel\":\n        \"\"\"\n        Decode a protocol buffer object that corresponds with this class into an instance of this class.\n\n        A new instance of this class is created that matches the protocol buffer object in the 'data_model_protobuf_object' argument.\n\n        :param data_model_protobuf_object: the protocol buffer object whose type corresponds with this class.\n        :return: A new instance of this class that matches the protocol buffer object in the 'data_model_protobuf_object' argument.\n        \"\"\"\n        return cls(\n            bytes_field=data_model_protobuf_object.bytes_field,\n            int_field=data_model_protobuf_object.int_field,\n            float_field=data_model_protobuf_object.float_field,\n            bool_field=data_model_protobuf_object.bool_field,\n            str_field=data_model_protobuf_object.str_field,\n            set_field=set(data_model_protobuf_object.set_field),\n            list_field=data_model_protobuf_object.list_field,\n            dict_field=data_model_protobuf_object.dict_field,\n        )\n\n    def __eq__(self, other):\n        \"\"\"Overrides the default implementation\"\"\"\n        if not isinstance(other, self.__class__):\n            return False\n        return (\n            self.bytes_field == other.bytes_field\n            and self.int_field == other.int_field\n            # floats seem to lose some precision when serialised then deserialised using protobuf\n            # and self.float_field == other.float_field\n            and self.bool_field == other.bool_field\n            and self.str_field == other.str_field\n            and self.set_field == other.set_field\n            and self.list_field == other.list_field\n            and self.dict_field == other.dict_field\n        )\n\n\nclass DataModel1(DataModel):\n    \"\"\"This class represents an instance of DataModel1.\"\"\"\n\n\nclass DataModel2(DataModel):\n    \"\"\"This class represents an instance of DataModel2.\"\"\"\n\n\nclass DataModel3(DataModel):\n    \"\"\"This class represents an instance of DataModel3.\"\"\"\n\n\nclass DataModel4(DataModel):\n    \"\"\"This class represents an instance of DataModel3.\"\"\"\n"
  },
  {
    "path": "tests/data/generator/t_protocol/dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nThis module contains the classes required for t_protocol dialogue management.\n\n- TProtocolDialogue: The dialogue class maintains state of a dialogue and manages it.\n- TProtocolDialogues: The dialogues class keeps track of all dialogues.\n\"\"\"\n\nfrom abc import ABC\nfrom typing import Callable, Dict, FrozenSet, Type, cast\n\nfrom aea.common import Address\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue, DialogueLabel, Dialogues\n\nfrom tests.data.generator.t_protocol.message import TProtocolMessage\n\n\nclass TProtocolDialogue(Dialogue):\n    \"\"\"The t_protocol dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    INITIAL_PERFORMATIVES: FrozenSet[Message.Performative] = frozenset(\n        {\n            TProtocolMessage.Performative.PERFORMATIVE_CT,\n            TProtocolMessage.Performative.PERFORMATIVE_PT,\n        }\n    )\n    TERMINAL_PERFORMATIVES: FrozenSet[Message.Performative] = frozenset(\n        {\n            TProtocolMessage.Performative.PERFORMATIVE_MT,\n            TProtocolMessage.Performative.PERFORMATIVE_O,\n        }\n    )\n    VALID_REPLIES: Dict[Message.Performative, FrozenSet[Message.Performative]] = {\n        TProtocolMessage.Performative.PERFORMATIVE_CT: frozenset(\n            {TProtocolMessage.Performative.PERFORMATIVE_PCT}\n        ),\n        TProtocolMessage.Performative.PERFORMATIVE_EMPTY_CONTENTS: frozenset(\n            {TProtocolMessage.Performative.PERFORMATIVE_EMPTY_CONTENTS}\n        ),\n        TProtocolMessage.Performative.PERFORMATIVE_MT: frozenset(),\n        TProtocolMessage.Performative.PERFORMATIVE_O: frozenset(),\n        TProtocolMessage.Performative.PERFORMATIVE_PCT: frozenset(\n            {\n                TProtocolMessage.Performative.PERFORMATIVE_MT,\n                TProtocolMessage.Performative.PERFORMATIVE_O,\n            }\n        ),\n        TProtocolMessage.Performative.PERFORMATIVE_PMT: frozenset(\n            {\n                TProtocolMessage.Performative.PERFORMATIVE_MT,\n                TProtocolMessage.Performative.PERFORMATIVE_O,\n            }\n        ),\n        TProtocolMessage.Performative.PERFORMATIVE_PT: frozenset(\n            {\n                TProtocolMessage.Performative.PERFORMATIVE_PT,\n                TProtocolMessage.Performative.PERFORMATIVE_PMT,\n            }\n        ),\n    }\n\n    class Role(Dialogue.Role):\n        \"\"\"This class defines the agent's role in a t_protocol dialogue.\"\"\"\n\n        ROLE_1 = \"role_1\"\n        ROLE_2 = \"role_2\"\n\n    class EndState(Dialogue.EndState):\n        \"\"\"This class defines the end states of a t_protocol dialogue.\"\"\"\n\n        END_STATE_1 = 0\n        END_STATE_2 = 1\n        END_STATE_3 = 2\n\n    def __init__(\n        self,\n        dialogue_label: DialogueLabel,\n        self_address: Address,\n        role: Dialogue.Role,\n        message_class: Type[TProtocolMessage] = TProtocolMessage,\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n        :param message_class: the message class used\n        \"\"\"\n        Dialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            message_class=message_class,\n            self_address=self_address,\n            role=role,\n        )\n\n\nclass TProtocolDialogues(Dialogues, ABC):\n    \"\"\"This class keeps track of all t_protocol dialogues.\"\"\"\n\n    END_STATES = frozenset(\n        {\n            TProtocolDialogue.EndState.END_STATE_1,\n            TProtocolDialogue.EndState.END_STATE_2,\n            TProtocolDialogue.EndState.END_STATE_3,\n        }\n    )\n\n    _keep_terminal_state_dialogues = True\n\n    def __init__(\n        self,\n        self_address: Address,\n        role_from_first_message: Callable[[Message, Address], Dialogue.Role],\n        dialogue_class: Type[TProtocolDialogue] = TProtocolDialogue,\n    ) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param self_address: the address of the entity for whom dialogues are maintained\n        :param dialogue_class: the dialogue class used\n        :param role_from_first_message: the callable determining role from first message\n        \"\"\"\n        Dialogues.__init__(\n            self,\n            self_address=self_address,\n            end_states=cast(FrozenSet[Dialogue.EndState], self.END_STATES),\n            message_class=TProtocolMessage,\n            dialogue_class=dialogue_class,\n            role_from_first_message=role_from_first_message,\n        )\n"
  },
  {
    "path": "tests/data/generator/t_protocol/message.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains t_protocol's message definition.\"\"\"\n\n# pylint: disable=too-many-statements,too-many-locals,no-member,too-few-public-methods,too-many-branches,not-an-iterable,unidiomatic-typecheck,unsubscriptable-object\nimport logging\nfrom typing import Any, Dict, FrozenSet, Optional, Set, Tuple, Union, cast\n\nfrom aea.configurations.base import PublicId\nfrom aea.exceptions import AEAEnforceError, enforce\nfrom aea.protocols.base import Message\n\nfrom tests.data.generator.t_protocol.custom_types import DataModel as CustomDataModel\nfrom tests.data.generator.t_protocol.custom_types import DataModel1 as CustomDataModel1\nfrom tests.data.generator.t_protocol.custom_types import DataModel2 as CustomDataModel2\nfrom tests.data.generator.t_protocol.custom_types import DataModel3 as CustomDataModel3\nfrom tests.data.generator.t_protocol.custom_types import DataModel4 as CustomDataModel4\n\n\n_default_logger = logging.getLogger(\"aea.packages.fetchai.protocols.t_protocol.message\")\n\nDEFAULT_BODY_SIZE = 4\n\n\nclass TProtocolMessage(Message):\n    \"\"\"A protocol for testing purposes.\"\"\"\n\n    protocol_id = PublicId.from_str(\"fetchai/t_protocol:0.1.0\")\n    protocol_specification_id = PublicId.from_str(\n        \"some_author/some_protocol_name:1.0.0\"\n    )\n\n    DataModel = CustomDataModel\n\n    DataModel1 = CustomDataModel1\n\n    DataModel2 = CustomDataModel2\n\n    DataModel3 = CustomDataModel3\n\n    DataModel4 = CustomDataModel4\n\n    class Performative(Message.Performative):\n        \"\"\"Performatives for the t_protocol protocol.\"\"\"\n\n        PERFORMATIVE_CT = \"performative_ct\"\n        PERFORMATIVE_EMPTY_CONTENTS = \"performative_empty_contents\"\n        PERFORMATIVE_MT = \"performative_mt\"\n        PERFORMATIVE_O = \"performative_o\"\n        PERFORMATIVE_PCT = \"performative_pct\"\n        PERFORMATIVE_PMT = \"performative_pmt\"\n        PERFORMATIVE_PT = \"performative_pt\"\n\n        def __str__(self) -> str:\n            \"\"\"Get the string representation.\"\"\"\n            return str(self.value)\n\n    _performatives = {\n        \"performative_ct\",\n        \"performative_empty_contents\",\n        \"performative_mt\",\n        \"performative_o\",\n        \"performative_pct\",\n        \"performative_pmt\",\n        \"performative_pt\",\n    }\n    __slots__: Tuple[str, ...] = tuple()\n\n    class _SlotsCls:\n        __slots__ = (\n            \"content_bool\",\n            \"content_bytes\",\n            \"content_ct\",\n            \"content_dict_bool_bool\",\n            \"content_dict_bool_bytes\",\n            \"content_dict_bool_float\",\n            \"content_dict_bool_int\",\n            \"content_dict_bool_str\",\n            \"content_dict_int_bool\",\n            \"content_dict_int_bytes\",\n            \"content_dict_int_float\",\n            \"content_dict_int_int\",\n            \"content_dict_int_str\",\n            \"content_dict_str_bool\",\n            \"content_dict_str_bytes\",\n            \"content_dict_str_float\",\n            \"content_dict_str_int\",\n            \"content_dict_str_str\",\n            \"content_float\",\n            \"content_int\",\n            \"content_list_bool\",\n            \"content_list_bytes\",\n            \"content_list_float\",\n            \"content_list_int\",\n            \"content_list_str\",\n            \"content_o_bool\",\n            \"content_o_ct\",\n            \"content_o_dict_str_int\",\n            \"content_o_list_bytes\",\n            \"content_o_set_int\",\n            \"content_set_bool\",\n            \"content_set_bytes\",\n            \"content_set_float\",\n            \"content_set_int\",\n            \"content_set_str\",\n            \"content_str\",\n            \"content_union_1\",\n            \"content_union_2\",\n            \"content_union_3\",\n            \"dialogue_reference\",\n            \"message_id\",\n            \"performative\",\n            \"target\",\n        )\n\n    def __init__(\n        self,\n        performative: Performative,\n        dialogue_reference: Tuple[str, str] = (\"\", \"\"),\n        message_id: int = 1,\n        target: int = 0,\n        **kwargs: Any,\n    ):\n        \"\"\"\n        Initialise an instance of TProtocolMessage.\n\n        :param message_id: the message id.\n        :param dialogue_reference: the dialogue reference.\n        :param target: the message target.\n        :param performative: the message performative.\n        :param **kwargs: extra options.\n        \"\"\"\n        super().__init__(\n            dialogue_reference=dialogue_reference,\n            message_id=message_id,\n            target=target,\n            performative=TProtocolMessage.Performative(performative),\n            **kwargs,\n        )\n\n    @property\n    def valid_performatives(self) -> Set[str]:\n        \"\"\"Get valid performatives.\"\"\"\n        return self._performatives\n\n    @property\n    def dialogue_reference(self) -> Tuple[str, str]:\n        \"\"\"Get the dialogue_reference of the message.\"\"\"\n        enforce(self.is_set(\"dialogue_reference\"), \"dialogue_reference is not set.\")\n        return cast(Tuple[str, str], self.get(\"dialogue_reference\"))\n\n    @property\n    def message_id(self) -> int:\n        \"\"\"Get the message_id of the message.\"\"\"\n        enforce(self.is_set(\"message_id\"), \"message_id is not set.\")\n        return cast(int, self.get(\"message_id\"))\n\n    @property\n    def performative(self) -> Performative:  # type: ignore # noqa: F821\n        \"\"\"Get the performative of the message.\"\"\"\n        enforce(self.is_set(\"performative\"), \"performative is not set.\")\n        return cast(TProtocolMessage.Performative, self.get(\"performative\"))\n\n    @property\n    def target(self) -> int:\n        \"\"\"Get the target of the message.\"\"\"\n        enforce(self.is_set(\"target\"), \"target is not set.\")\n        return cast(int, self.get(\"target\"))\n\n    @property\n    def content_bool(self) -> bool:\n        \"\"\"Get the 'content_bool' content from the message.\"\"\"\n        enforce(self.is_set(\"content_bool\"), \"'content_bool' content is not set.\")\n        return cast(bool, self.get(\"content_bool\"))\n\n    @property\n    def content_bytes(self) -> bytes:\n        \"\"\"Get the 'content_bytes' content from the message.\"\"\"\n        enforce(self.is_set(\"content_bytes\"), \"'content_bytes' content is not set.\")\n        return cast(bytes, self.get(\"content_bytes\"))\n\n    @property\n    def content_ct(self) -> CustomDataModel:\n        \"\"\"Get the 'content_ct' content from the message.\"\"\"\n        enforce(self.is_set(\"content_ct\"), \"'content_ct' content is not set.\")\n        return cast(CustomDataModel, self.get(\"content_ct\"))\n\n    @property\n    def content_dict_bool_bool(self) -> Dict[bool, bool]:\n        \"\"\"Get the 'content_dict_bool_bool' content from the message.\"\"\"\n        enforce(\n            self.is_set(\"content_dict_bool_bool\"),\n            \"'content_dict_bool_bool' content is not set.\",\n        )\n        return cast(Dict[bool, bool], self.get(\"content_dict_bool_bool\"))\n\n    @property\n    def content_dict_bool_bytes(self) -> Dict[bool, bytes]:\n        \"\"\"Get the 'content_dict_bool_bytes' content from the message.\"\"\"\n        enforce(\n            self.is_set(\"content_dict_bool_bytes\"),\n            \"'content_dict_bool_bytes' content is not set.\",\n        )\n        return cast(Dict[bool, bytes], self.get(\"content_dict_bool_bytes\"))\n\n    @property\n    def content_dict_bool_float(self) -> Dict[bool, float]:\n        \"\"\"Get the 'content_dict_bool_float' content from the message.\"\"\"\n        enforce(\n            self.is_set(\"content_dict_bool_float\"),\n            \"'content_dict_bool_float' content is not set.\",\n        )\n        return cast(Dict[bool, float], self.get(\"content_dict_bool_float\"))\n\n    @property\n    def content_dict_bool_int(self) -> Dict[bool, int]:\n        \"\"\"Get the 'content_dict_bool_int' content from the message.\"\"\"\n        enforce(\n            self.is_set(\"content_dict_bool_int\"),\n            \"'content_dict_bool_int' content is not set.\",\n        )\n        return cast(Dict[bool, int], self.get(\"content_dict_bool_int\"))\n\n    @property\n    def content_dict_bool_str(self) -> Dict[bool, str]:\n        \"\"\"Get the 'content_dict_bool_str' content from the message.\"\"\"\n        enforce(\n            self.is_set(\"content_dict_bool_str\"),\n            \"'content_dict_bool_str' content is not set.\",\n        )\n        return cast(Dict[bool, str], self.get(\"content_dict_bool_str\"))\n\n    @property\n    def content_dict_int_bool(self) -> Dict[int, bool]:\n        \"\"\"Get the 'content_dict_int_bool' content from the message.\"\"\"\n        enforce(\n            self.is_set(\"content_dict_int_bool\"),\n            \"'content_dict_int_bool' content is not set.\",\n        )\n        return cast(Dict[int, bool], self.get(\"content_dict_int_bool\"))\n\n    @property\n    def content_dict_int_bytes(self) -> Dict[int, bytes]:\n        \"\"\"Get the 'content_dict_int_bytes' content from the message.\"\"\"\n        enforce(\n            self.is_set(\"content_dict_int_bytes\"),\n            \"'content_dict_int_bytes' content is not set.\",\n        )\n        return cast(Dict[int, bytes], self.get(\"content_dict_int_bytes\"))\n\n    @property\n    def content_dict_int_float(self) -> Dict[int, float]:\n        \"\"\"Get the 'content_dict_int_float' content from the message.\"\"\"\n        enforce(\n            self.is_set(\"content_dict_int_float\"),\n            \"'content_dict_int_float' content is not set.\",\n        )\n        return cast(Dict[int, float], self.get(\"content_dict_int_float\"))\n\n    @property\n    def content_dict_int_int(self) -> Dict[int, int]:\n        \"\"\"Get the 'content_dict_int_int' content from the message.\"\"\"\n        enforce(\n            self.is_set(\"content_dict_int_int\"),\n            \"'content_dict_int_int' content is not set.\",\n        )\n        return cast(Dict[int, int], self.get(\"content_dict_int_int\"))\n\n    @property\n    def content_dict_int_str(self) -> Dict[int, str]:\n        \"\"\"Get the 'content_dict_int_str' content from the message.\"\"\"\n        enforce(\n            self.is_set(\"content_dict_int_str\"),\n            \"'content_dict_int_str' content is not set.\",\n        )\n        return cast(Dict[int, str], self.get(\"content_dict_int_str\"))\n\n    @property\n    def content_dict_str_bool(self) -> Dict[str, bool]:\n        \"\"\"Get the 'content_dict_str_bool' content from the message.\"\"\"\n        enforce(\n            self.is_set(\"content_dict_str_bool\"),\n            \"'content_dict_str_bool' content is not set.\",\n        )\n        return cast(Dict[str, bool], self.get(\"content_dict_str_bool\"))\n\n    @property\n    def content_dict_str_bytes(self) -> Dict[str, bytes]:\n        \"\"\"Get the 'content_dict_str_bytes' content from the message.\"\"\"\n        enforce(\n            self.is_set(\"content_dict_str_bytes\"),\n            \"'content_dict_str_bytes' content is not set.\",\n        )\n        return cast(Dict[str, bytes], self.get(\"content_dict_str_bytes\"))\n\n    @property\n    def content_dict_str_float(self) -> Dict[str, float]:\n        \"\"\"Get the 'content_dict_str_float' content from the message.\"\"\"\n        enforce(\n            self.is_set(\"content_dict_str_float\"),\n            \"'content_dict_str_float' content is not set.\",\n        )\n        return cast(Dict[str, float], self.get(\"content_dict_str_float\"))\n\n    @property\n    def content_dict_str_int(self) -> Dict[str, int]:\n        \"\"\"Get the 'content_dict_str_int' content from the message.\"\"\"\n        enforce(\n            self.is_set(\"content_dict_str_int\"),\n            \"'content_dict_str_int' content is not set.\",\n        )\n        return cast(Dict[str, int], self.get(\"content_dict_str_int\"))\n\n    @property\n    def content_dict_str_str(self) -> Dict[str, str]:\n        \"\"\"Get the 'content_dict_str_str' content from the message.\"\"\"\n        enforce(\n            self.is_set(\"content_dict_str_str\"),\n            \"'content_dict_str_str' content is not set.\",\n        )\n        return cast(Dict[str, str], self.get(\"content_dict_str_str\"))\n\n    @property\n    def content_float(self) -> float:\n        \"\"\"Get the 'content_float' content from the message.\"\"\"\n        enforce(self.is_set(\"content_float\"), \"'content_float' content is not set.\")\n        return cast(float, self.get(\"content_float\"))\n\n    @property\n    def content_int(self) -> int:\n        \"\"\"Get the 'content_int' content from the message.\"\"\"\n        enforce(self.is_set(\"content_int\"), \"'content_int' content is not set.\")\n        return cast(int, self.get(\"content_int\"))\n\n    @property\n    def content_list_bool(self) -> Tuple[bool, ...]:\n        \"\"\"Get the 'content_list_bool' content from the message.\"\"\"\n        enforce(\n            self.is_set(\"content_list_bool\"), \"'content_list_bool' content is not set.\"\n        )\n        return cast(Tuple[bool, ...], self.get(\"content_list_bool\"))\n\n    @property\n    def content_list_bytes(self) -> Tuple[bytes, ...]:\n        \"\"\"Get the 'content_list_bytes' content from the message.\"\"\"\n        enforce(\n            self.is_set(\"content_list_bytes\"),\n            \"'content_list_bytes' content is not set.\",\n        )\n        return cast(Tuple[bytes, ...], self.get(\"content_list_bytes\"))\n\n    @property\n    def content_list_float(self) -> Tuple[float, ...]:\n        \"\"\"Get the 'content_list_float' content from the message.\"\"\"\n        enforce(\n            self.is_set(\"content_list_float\"),\n            \"'content_list_float' content is not set.\",\n        )\n        return cast(Tuple[float, ...], self.get(\"content_list_float\"))\n\n    @property\n    def content_list_int(self) -> Tuple[int, ...]:\n        \"\"\"Get the 'content_list_int' content from the message.\"\"\"\n        enforce(\n            self.is_set(\"content_list_int\"), \"'content_list_int' content is not set.\"\n        )\n        return cast(Tuple[int, ...], self.get(\"content_list_int\"))\n\n    @property\n    def content_list_str(self) -> Tuple[str, ...]:\n        \"\"\"Get the 'content_list_str' content from the message.\"\"\"\n        enforce(\n            self.is_set(\"content_list_str\"), \"'content_list_str' content is not set.\"\n        )\n        return cast(Tuple[str, ...], self.get(\"content_list_str\"))\n\n    @property\n    def content_o_bool(self) -> Optional[bool]:\n        \"\"\"Get the 'content_o_bool' content from the message.\"\"\"\n        return cast(Optional[bool], self.get(\"content_o_bool\"))\n\n    @property\n    def content_o_ct(self) -> Optional[CustomDataModel4]:\n        \"\"\"Get the 'content_o_ct' content from the message.\"\"\"\n        return cast(Optional[CustomDataModel4], self.get(\"content_o_ct\"))\n\n    @property\n    def content_o_dict_str_int(self) -> Optional[Dict[str, int]]:\n        \"\"\"Get the 'content_o_dict_str_int' content from the message.\"\"\"\n        return cast(Optional[Dict[str, int]], self.get(\"content_o_dict_str_int\"))\n\n    @property\n    def content_o_list_bytes(self) -> Optional[Tuple[bytes, ...]]:\n        \"\"\"Get the 'content_o_list_bytes' content from the message.\"\"\"\n        return cast(Optional[Tuple[bytes, ...]], self.get(\"content_o_list_bytes\"))\n\n    @property\n    def content_o_set_int(self) -> Optional[FrozenSet[int]]:\n        \"\"\"Get the 'content_o_set_int' content from the message.\"\"\"\n        return cast(Optional[FrozenSet[int]], self.get(\"content_o_set_int\"))\n\n    @property\n    def content_set_bool(self) -> FrozenSet[bool]:\n        \"\"\"Get the 'content_set_bool' content from the message.\"\"\"\n        enforce(\n            self.is_set(\"content_set_bool\"), \"'content_set_bool' content is not set.\"\n        )\n        return cast(FrozenSet[bool], self.get(\"content_set_bool\"))\n\n    @property\n    def content_set_bytes(self) -> FrozenSet[bytes]:\n        \"\"\"Get the 'content_set_bytes' content from the message.\"\"\"\n        enforce(\n            self.is_set(\"content_set_bytes\"), \"'content_set_bytes' content is not set.\"\n        )\n        return cast(FrozenSet[bytes], self.get(\"content_set_bytes\"))\n\n    @property\n    def content_set_float(self) -> FrozenSet[float]:\n        \"\"\"Get the 'content_set_float' content from the message.\"\"\"\n        enforce(\n            self.is_set(\"content_set_float\"), \"'content_set_float' content is not set.\"\n        )\n        return cast(FrozenSet[float], self.get(\"content_set_float\"))\n\n    @property\n    def content_set_int(self) -> FrozenSet[int]:\n        \"\"\"Get the 'content_set_int' content from the message.\"\"\"\n        enforce(self.is_set(\"content_set_int\"), \"'content_set_int' content is not set.\")\n        return cast(FrozenSet[int], self.get(\"content_set_int\"))\n\n    @property\n    def content_set_str(self) -> FrozenSet[str]:\n        \"\"\"Get the 'content_set_str' content from the message.\"\"\"\n        enforce(self.is_set(\"content_set_str\"), \"'content_set_str' content is not set.\")\n        return cast(FrozenSet[str], self.get(\"content_set_str\"))\n\n    @property\n    def content_str(self) -> str:\n        \"\"\"Get the 'content_str' content from the message.\"\"\"\n        enforce(self.is_set(\"content_str\"), \"'content_str' content is not set.\")\n        return cast(str, self.get(\"content_str\"))\n\n    @property\n    def content_union_1(\n        self,\n    ) -> Union[\n        CustomDataModel1,\n        bytes,\n        int,\n        float,\n        bool,\n        str,\n        FrozenSet[int],\n        Tuple[bool, ...],\n        Dict[str, int],\n    ]:\n        \"\"\"Get the 'content_union_1' content from the message.\"\"\"\n        enforce(self.is_set(\"content_union_1\"), \"'content_union_1' content is not set.\")\n        return cast(\n            Union[\n                CustomDataModel1,\n                bytes,\n                int,\n                float,\n                bool,\n                str,\n                FrozenSet[int],\n                Tuple[bool, ...],\n                Dict[str, int],\n            ],\n            self.get(\"content_union_1\"),\n        )\n\n    @property\n    def content_union_2(\n        self,\n    ) -> Union[\n        FrozenSet[bytes],\n        FrozenSet[int],\n        FrozenSet[str],\n        Tuple[float, ...],\n        Tuple[bool, ...],\n        Tuple[bytes, ...],\n        Dict[str, int],\n        Dict[int, float],\n        Dict[bool, bytes],\n        int,\n    ]:\n        \"\"\"Get the 'content_union_2' content from the message.\"\"\"\n        enforce(self.is_set(\"content_union_2\"), \"'content_union_2' content is not set.\")\n        return cast(\n            Union[\n                FrozenSet[bytes],\n                FrozenSet[int],\n                FrozenSet[str],\n                Tuple[float, ...],\n                Tuple[bool, ...],\n                Tuple[bytes, ...],\n                Dict[str, int],\n                Dict[int, float],\n                Dict[bool, bytes],\n                int,\n            ],\n            self.get(\"content_union_2\"),\n        )\n\n    @property\n    def content_union_3(self) -> Union[CustomDataModel2, CustomDataModel3]:\n        \"\"\"Get the 'content_union_3' content from the message.\"\"\"\n        enforce(self.is_set(\"content_union_3\"), \"'content_union_3' content is not set.\")\n        return cast(\n            Union[CustomDataModel2, CustomDataModel3], self.get(\"content_union_3\")\n        )\n\n    def _is_consistent(self) -> bool:\n        \"\"\"Check that the message follows the t_protocol protocol.\"\"\"\n        try:\n            enforce(\n                isinstance(self.dialogue_reference, tuple),\n                \"Invalid type for 'dialogue_reference'. Expected 'tuple'. Found '{}'.\".format(\n                    type(self.dialogue_reference)\n                ),\n            )\n            enforce(\n                isinstance(self.dialogue_reference[0], str),\n                \"Invalid type for 'dialogue_reference[0]'. Expected 'str'. Found '{}'.\".format(\n                    type(self.dialogue_reference[0])\n                ),\n            )\n            enforce(\n                isinstance(self.dialogue_reference[1], str),\n                \"Invalid type for 'dialogue_reference[1]'. Expected 'str'. Found '{}'.\".format(\n                    type(self.dialogue_reference[1])\n                ),\n            )\n            enforce(\n                type(self.message_id) is int,\n                \"Invalid type for 'message_id'. Expected 'int'. Found '{}'.\".format(\n                    type(self.message_id)\n                ),\n            )\n            enforce(\n                type(self.target) is int,\n                \"Invalid type for 'target'. Expected 'int'. Found '{}'.\".format(\n                    type(self.target)\n                ),\n            )\n\n            # Light Protocol Rule 2\n            # Check correct performative\n            enforce(\n                isinstance(self.performative, TProtocolMessage.Performative),\n                \"Invalid 'performative'. Expected either of '{}'. Found '{}'.\".format(\n                    self.valid_performatives, self.performative\n                ),\n            )\n\n            # Check correct contents\n            actual_nb_of_contents = len(self._body) - DEFAULT_BODY_SIZE\n            expected_nb_of_contents = 0\n            if self.performative == TProtocolMessage.Performative.PERFORMATIVE_CT:\n                expected_nb_of_contents = 1\n                enforce(\n                    isinstance(self.content_ct, CustomDataModel),\n                    \"Invalid type for content 'content_ct'. Expected 'DataModel'. Found '{}'.\".format(\n                        type(self.content_ct)\n                    ),\n                )\n            elif self.performative == TProtocolMessage.Performative.PERFORMATIVE_PT:\n                expected_nb_of_contents = 5\n                enforce(\n                    isinstance(self.content_bytes, bytes),\n                    \"Invalid type for content 'content_bytes'. Expected 'bytes'. Found '{}'.\".format(\n                        type(self.content_bytes)\n                    ),\n                )\n                enforce(\n                    type(self.content_int) is int,\n                    \"Invalid type for content 'content_int'. Expected 'int'. Found '{}'.\".format(\n                        type(self.content_int)\n                    ),\n                )\n                enforce(\n                    isinstance(self.content_float, float),\n                    \"Invalid type for content 'content_float'. Expected 'float'. Found '{}'.\".format(\n                        type(self.content_float)\n                    ),\n                )\n                enforce(\n                    isinstance(self.content_bool, bool),\n                    \"Invalid type for content 'content_bool'. Expected 'bool'. Found '{}'.\".format(\n                        type(self.content_bool)\n                    ),\n                )\n                enforce(\n                    isinstance(self.content_str, str),\n                    \"Invalid type for content 'content_str'. Expected 'str'. Found '{}'.\".format(\n                        type(self.content_str)\n                    ),\n                )\n            elif self.performative == TProtocolMessage.Performative.PERFORMATIVE_PCT:\n                expected_nb_of_contents = 10\n                enforce(\n                    isinstance(self.content_set_bytes, frozenset),\n                    \"Invalid type for content 'content_set_bytes'. Expected 'frozenset'. Found '{}'.\".format(\n                        type(self.content_set_bytes)\n                    ),\n                )\n                enforce(\n                    all(\n                        isinstance(element, bytes) for element in self.content_set_bytes\n                    ),\n                    \"Invalid type for frozenset elements in content 'content_set_bytes'. Expected 'bytes'.\",\n                )\n                enforce(\n                    isinstance(self.content_set_int, frozenset),\n                    \"Invalid type for content 'content_set_int'. Expected 'frozenset'. Found '{}'.\".format(\n                        type(self.content_set_int)\n                    ),\n                )\n                enforce(\n                    all(type(element) is int for element in self.content_set_int),\n                    \"Invalid type for frozenset elements in content 'content_set_int'. Expected 'int'.\",\n                )\n                enforce(\n                    isinstance(self.content_set_float, frozenset),\n                    \"Invalid type for content 'content_set_float'. Expected 'frozenset'. Found '{}'.\".format(\n                        type(self.content_set_float)\n                    ),\n                )\n                enforce(\n                    all(\n                        isinstance(element, float) for element in self.content_set_float\n                    ),\n                    \"Invalid type for frozenset elements in content 'content_set_float'. Expected 'float'.\",\n                )\n                enforce(\n                    isinstance(self.content_set_bool, frozenset),\n                    \"Invalid type for content 'content_set_bool'. Expected 'frozenset'. Found '{}'.\".format(\n                        type(self.content_set_bool)\n                    ),\n                )\n                enforce(\n                    all(isinstance(element, bool) for element in self.content_set_bool),\n                    \"Invalid type for frozenset elements in content 'content_set_bool'. Expected 'bool'.\",\n                )\n                enforce(\n                    isinstance(self.content_set_str, frozenset),\n                    \"Invalid type for content 'content_set_str'. Expected 'frozenset'. Found '{}'.\".format(\n                        type(self.content_set_str)\n                    ),\n                )\n                enforce(\n                    all(isinstance(element, str) for element in self.content_set_str),\n                    \"Invalid type for frozenset elements in content 'content_set_str'. Expected 'str'.\",\n                )\n                enforce(\n                    isinstance(self.content_list_bytes, tuple),\n                    \"Invalid type for content 'content_list_bytes'. Expected 'tuple'. Found '{}'.\".format(\n                        type(self.content_list_bytes)\n                    ),\n                )\n                enforce(\n                    all(\n                        isinstance(element, bytes)\n                        for element in self.content_list_bytes\n                    ),\n                    \"Invalid type for tuple elements in content 'content_list_bytes'. Expected 'bytes'.\",\n                )\n                enforce(\n                    isinstance(self.content_list_int, tuple),\n                    \"Invalid type for content 'content_list_int'. Expected 'tuple'. Found '{}'.\".format(\n                        type(self.content_list_int)\n                    ),\n                )\n                enforce(\n                    all(type(element) is int for element in self.content_list_int),\n                    \"Invalid type for tuple elements in content 'content_list_int'. Expected 'int'.\",\n                )\n                enforce(\n                    isinstance(self.content_list_float, tuple),\n                    \"Invalid type for content 'content_list_float'. Expected 'tuple'. Found '{}'.\".format(\n                        type(self.content_list_float)\n                    ),\n                )\n                enforce(\n                    all(\n                        isinstance(element, float)\n                        for element in self.content_list_float\n                    ),\n                    \"Invalid type for tuple elements in content 'content_list_float'. Expected 'float'.\",\n                )\n                enforce(\n                    isinstance(self.content_list_bool, tuple),\n                    \"Invalid type for content 'content_list_bool'. Expected 'tuple'. Found '{}'.\".format(\n                        type(self.content_list_bool)\n                    ),\n                )\n                enforce(\n                    all(\n                        isinstance(element, bool) for element in self.content_list_bool\n                    ),\n                    \"Invalid type for tuple elements in content 'content_list_bool'. Expected 'bool'.\",\n                )\n                enforce(\n                    isinstance(self.content_list_str, tuple),\n                    \"Invalid type for content 'content_list_str'. Expected 'tuple'. Found '{}'.\".format(\n                        type(self.content_list_str)\n                    ),\n                )\n                enforce(\n                    all(isinstance(element, str) for element in self.content_list_str),\n                    \"Invalid type for tuple elements in content 'content_list_str'. Expected 'str'.\",\n                )\n            elif self.performative == TProtocolMessage.Performative.PERFORMATIVE_PMT:\n                expected_nb_of_contents = 15\n                enforce(\n                    isinstance(self.content_dict_int_bytes, dict),\n                    \"Invalid type for content 'content_dict_int_bytes'. Expected 'dict'. Found '{}'.\".format(\n                        type(self.content_dict_int_bytes)\n                    ),\n                )\n                for (\n                    key_of_content_dict_int_bytes,\n                    value_of_content_dict_int_bytes,\n                ) in self.content_dict_int_bytes.items():\n                    enforce(\n                        type(key_of_content_dict_int_bytes) is int,\n                        \"Invalid type for dictionary keys in content 'content_dict_int_bytes'. Expected 'int'. Found '{}'.\".format(\n                            type(key_of_content_dict_int_bytes)\n                        ),\n                    )\n                    enforce(\n                        isinstance(value_of_content_dict_int_bytes, bytes),\n                        \"Invalid type for dictionary values in content 'content_dict_int_bytes'. Expected 'bytes'. Found '{}'.\".format(\n                            type(value_of_content_dict_int_bytes)\n                        ),\n                    )\n                enforce(\n                    isinstance(self.content_dict_int_int, dict),\n                    \"Invalid type for content 'content_dict_int_int'. Expected 'dict'. Found '{}'.\".format(\n                        type(self.content_dict_int_int)\n                    ),\n                )\n                for (\n                    key_of_content_dict_int_int,\n                    value_of_content_dict_int_int,\n                ) in self.content_dict_int_int.items():\n                    enforce(\n                        type(key_of_content_dict_int_int) is int,\n                        \"Invalid type for dictionary keys in content 'content_dict_int_int'. Expected 'int'. Found '{}'.\".format(\n                            type(key_of_content_dict_int_int)\n                        ),\n                    )\n                    enforce(\n                        type(value_of_content_dict_int_int) is int,\n                        \"Invalid type for dictionary values in content 'content_dict_int_int'. Expected 'int'. Found '{}'.\".format(\n                            type(value_of_content_dict_int_int)\n                        ),\n                    )\n                enforce(\n                    isinstance(self.content_dict_int_float, dict),\n                    \"Invalid type for content 'content_dict_int_float'. Expected 'dict'. Found '{}'.\".format(\n                        type(self.content_dict_int_float)\n                    ),\n                )\n                for (\n                    key_of_content_dict_int_float,\n                    value_of_content_dict_int_float,\n                ) in self.content_dict_int_float.items():\n                    enforce(\n                        type(key_of_content_dict_int_float) is int,\n                        \"Invalid type for dictionary keys in content 'content_dict_int_float'. Expected 'int'. Found '{}'.\".format(\n                            type(key_of_content_dict_int_float)\n                        ),\n                    )\n                    enforce(\n                        isinstance(value_of_content_dict_int_float, float),\n                        \"Invalid type for dictionary values in content 'content_dict_int_float'. Expected 'float'. Found '{}'.\".format(\n                            type(value_of_content_dict_int_float)\n                        ),\n                    )\n                enforce(\n                    isinstance(self.content_dict_int_bool, dict),\n                    \"Invalid type for content 'content_dict_int_bool'. Expected 'dict'. Found '{}'.\".format(\n                        type(self.content_dict_int_bool)\n                    ),\n                )\n                for (\n                    key_of_content_dict_int_bool,\n                    value_of_content_dict_int_bool,\n                ) in self.content_dict_int_bool.items():\n                    enforce(\n                        type(key_of_content_dict_int_bool) is int,\n                        \"Invalid type for dictionary keys in content 'content_dict_int_bool'. Expected 'int'. Found '{}'.\".format(\n                            type(key_of_content_dict_int_bool)\n                        ),\n                    )\n                    enforce(\n                        isinstance(value_of_content_dict_int_bool, bool),\n                        \"Invalid type for dictionary values in content 'content_dict_int_bool'. Expected 'bool'. Found '{}'.\".format(\n                            type(value_of_content_dict_int_bool)\n                        ),\n                    )\n                enforce(\n                    isinstance(self.content_dict_int_str, dict),\n                    \"Invalid type for content 'content_dict_int_str'. Expected 'dict'. Found '{}'.\".format(\n                        type(self.content_dict_int_str)\n                    ),\n                )\n                for (\n                    key_of_content_dict_int_str,\n                    value_of_content_dict_int_str,\n                ) in self.content_dict_int_str.items():\n                    enforce(\n                        type(key_of_content_dict_int_str) is int,\n                        \"Invalid type for dictionary keys in content 'content_dict_int_str'. Expected 'int'. Found '{}'.\".format(\n                            type(key_of_content_dict_int_str)\n                        ),\n                    )\n                    enforce(\n                        isinstance(value_of_content_dict_int_str, str),\n                        \"Invalid type for dictionary values in content 'content_dict_int_str'. Expected 'str'. Found '{}'.\".format(\n                            type(value_of_content_dict_int_str)\n                        ),\n                    )\n                enforce(\n                    isinstance(self.content_dict_bool_bytes, dict),\n                    \"Invalid type for content 'content_dict_bool_bytes'. Expected 'dict'. Found '{}'.\".format(\n                        type(self.content_dict_bool_bytes)\n                    ),\n                )\n                for (\n                    key_of_content_dict_bool_bytes,\n                    value_of_content_dict_bool_bytes,\n                ) in self.content_dict_bool_bytes.items():\n                    enforce(\n                        isinstance(key_of_content_dict_bool_bytes, bool),\n                        \"Invalid type for dictionary keys in content 'content_dict_bool_bytes'. Expected 'bool'. Found '{}'.\".format(\n                            type(key_of_content_dict_bool_bytes)\n                        ),\n                    )\n                    enforce(\n                        isinstance(value_of_content_dict_bool_bytes, bytes),\n                        \"Invalid type for dictionary values in content 'content_dict_bool_bytes'. Expected 'bytes'. Found '{}'.\".format(\n                            type(value_of_content_dict_bool_bytes)\n                        ),\n                    )\n                enforce(\n                    isinstance(self.content_dict_bool_int, dict),\n                    \"Invalid type for content 'content_dict_bool_int'. Expected 'dict'. Found '{}'.\".format(\n                        type(self.content_dict_bool_int)\n                    ),\n                )\n                for (\n                    key_of_content_dict_bool_int,\n                    value_of_content_dict_bool_int,\n                ) in self.content_dict_bool_int.items():\n                    enforce(\n                        isinstance(key_of_content_dict_bool_int, bool),\n                        \"Invalid type for dictionary keys in content 'content_dict_bool_int'. Expected 'bool'. Found '{}'.\".format(\n                            type(key_of_content_dict_bool_int)\n                        ),\n                    )\n                    enforce(\n                        type(value_of_content_dict_bool_int) is int,\n                        \"Invalid type for dictionary values in content 'content_dict_bool_int'. Expected 'int'. Found '{}'.\".format(\n                            type(value_of_content_dict_bool_int)\n                        ),\n                    )\n                enforce(\n                    isinstance(self.content_dict_bool_float, dict),\n                    \"Invalid type for content 'content_dict_bool_float'. Expected 'dict'. Found '{}'.\".format(\n                        type(self.content_dict_bool_float)\n                    ),\n                )\n                for (\n                    key_of_content_dict_bool_float,\n                    value_of_content_dict_bool_float,\n                ) in self.content_dict_bool_float.items():\n                    enforce(\n                        isinstance(key_of_content_dict_bool_float, bool),\n                        \"Invalid type for dictionary keys in content 'content_dict_bool_float'. Expected 'bool'. Found '{}'.\".format(\n                            type(key_of_content_dict_bool_float)\n                        ),\n                    )\n                    enforce(\n                        isinstance(value_of_content_dict_bool_float, float),\n                        \"Invalid type for dictionary values in content 'content_dict_bool_float'. Expected 'float'. Found '{}'.\".format(\n                            type(value_of_content_dict_bool_float)\n                        ),\n                    )\n                enforce(\n                    isinstance(self.content_dict_bool_bool, dict),\n                    \"Invalid type for content 'content_dict_bool_bool'. Expected 'dict'. Found '{}'.\".format(\n                        type(self.content_dict_bool_bool)\n                    ),\n                )\n                for (\n                    key_of_content_dict_bool_bool,\n                    value_of_content_dict_bool_bool,\n                ) in self.content_dict_bool_bool.items():\n                    enforce(\n                        isinstance(key_of_content_dict_bool_bool, bool),\n                        \"Invalid type for dictionary keys in content 'content_dict_bool_bool'. Expected 'bool'. Found '{}'.\".format(\n                            type(key_of_content_dict_bool_bool)\n                        ),\n                    )\n                    enforce(\n                        isinstance(value_of_content_dict_bool_bool, bool),\n                        \"Invalid type for dictionary values in content 'content_dict_bool_bool'. Expected 'bool'. Found '{}'.\".format(\n                            type(value_of_content_dict_bool_bool)\n                        ),\n                    )\n                enforce(\n                    isinstance(self.content_dict_bool_str, dict),\n                    \"Invalid type for content 'content_dict_bool_str'. Expected 'dict'. Found '{}'.\".format(\n                        type(self.content_dict_bool_str)\n                    ),\n                )\n                for (\n                    key_of_content_dict_bool_str,\n                    value_of_content_dict_bool_str,\n                ) in self.content_dict_bool_str.items():\n                    enforce(\n                        isinstance(key_of_content_dict_bool_str, bool),\n                        \"Invalid type for dictionary keys in content 'content_dict_bool_str'. Expected 'bool'. Found '{}'.\".format(\n                            type(key_of_content_dict_bool_str)\n                        ),\n                    )\n                    enforce(\n                        isinstance(value_of_content_dict_bool_str, str),\n                        \"Invalid type for dictionary values in content 'content_dict_bool_str'. Expected 'str'. Found '{}'.\".format(\n                            type(value_of_content_dict_bool_str)\n                        ),\n                    )\n                enforce(\n                    isinstance(self.content_dict_str_bytes, dict),\n                    \"Invalid type for content 'content_dict_str_bytes'. Expected 'dict'. Found '{}'.\".format(\n                        type(self.content_dict_str_bytes)\n                    ),\n                )\n                for (\n                    key_of_content_dict_str_bytes,\n                    value_of_content_dict_str_bytes,\n                ) in self.content_dict_str_bytes.items():\n                    enforce(\n                        isinstance(key_of_content_dict_str_bytes, str),\n                        \"Invalid type for dictionary keys in content 'content_dict_str_bytes'. Expected 'str'. Found '{}'.\".format(\n                            type(key_of_content_dict_str_bytes)\n                        ),\n                    )\n                    enforce(\n                        isinstance(value_of_content_dict_str_bytes, bytes),\n                        \"Invalid type for dictionary values in content 'content_dict_str_bytes'. Expected 'bytes'. Found '{}'.\".format(\n                            type(value_of_content_dict_str_bytes)\n                        ),\n                    )\n                enforce(\n                    isinstance(self.content_dict_str_int, dict),\n                    \"Invalid type for content 'content_dict_str_int'. Expected 'dict'. Found '{}'.\".format(\n                        type(self.content_dict_str_int)\n                    ),\n                )\n                for (\n                    key_of_content_dict_str_int,\n                    value_of_content_dict_str_int,\n                ) in self.content_dict_str_int.items():\n                    enforce(\n                        isinstance(key_of_content_dict_str_int, str),\n                        \"Invalid type for dictionary keys in content 'content_dict_str_int'. Expected 'str'. Found '{}'.\".format(\n                            type(key_of_content_dict_str_int)\n                        ),\n                    )\n                    enforce(\n                        type(value_of_content_dict_str_int) is int,\n                        \"Invalid type for dictionary values in content 'content_dict_str_int'. Expected 'int'. Found '{}'.\".format(\n                            type(value_of_content_dict_str_int)\n                        ),\n                    )\n                enforce(\n                    isinstance(self.content_dict_str_float, dict),\n                    \"Invalid type for content 'content_dict_str_float'. Expected 'dict'. Found '{}'.\".format(\n                        type(self.content_dict_str_float)\n                    ),\n                )\n                for (\n                    key_of_content_dict_str_float,\n                    value_of_content_dict_str_float,\n                ) in self.content_dict_str_float.items():\n                    enforce(\n                        isinstance(key_of_content_dict_str_float, str),\n                        \"Invalid type for dictionary keys in content 'content_dict_str_float'. Expected 'str'. Found '{}'.\".format(\n                            type(key_of_content_dict_str_float)\n                        ),\n                    )\n                    enforce(\n                        isinstance(value_of_content_dict_str_float, float),\n                        \"Invalid type for dictionary values in content 'content_dict_str_float'. Expected 'float'. Found '{}'.\".format(\n                            type(value_of_content_dict_str_float)\n                        ),\n                    )\n                enforce(\n                    isinstance(self.content_dict_str_bool, dict),\n                    \"Invalid type for content 'content_dict_str_bool'. Expected 'dict'. Found '{}'.\".format(\n                        type(self.content_dict_str_bool)\n                    ),\n                )\n                for (\n                    key_of_content_dict_str_bool,\n                    value_of_content_dict_str_bool,\n                ) in self.content_dict_str_bool.items():\n                    enforce(\n                        isinstance(key_of_content_dict_str_bool, str),\n                        \"Invalid type for dictionary keys in content 'content_dict_str_bool'. Expected 'str'. Found '{}'.\".format(\n                            type(key_of_content_dict_str_bool)\n                        ),\n                    )\n                    enforce(\n                        isinstance(value_of_content_dict_str_bool, bool),\n                        \"Invalid type for dictionary values in content 'content_dict_str_bool'. Expected 'bool'. Found '{}'.\".format(\n                            type(value_of_content_dict_str_bool)\n                        ),\n                    )\n                enforce(\n                    isinstance(self.content_dict_str_str, dict),\n                    \"Invalid type for content 'content_dict_str_str'. Expected 'dict'. Found '{}'.\".format(\n                        type(self.content_dict_str_str)\n                    ),\n                )\n                for (\n                    key_of_content_dict_str_str,\n                    value_of_content_dict_str_str,\n                ) in self.content_dict_str_str.items():\n                    enforce(\n                        isinstance(key_of_content_dict_str_str, str),\n                        \"Invalid type for dictionary keys in content 'content_dict_str_str'. Expected 'str'. Found '{}'.\".format(\n                            type(key_of_content_dict_str_str)\n                        ),\n                    )\n                    enforce(\n                        isinstance(value_of_content_dict_str_str, str),\n                        \"Invalid type for dictionary values in content 'content_dict_str_str'. Expected 'str'. Found '{}'.\".format(\n                            type(value_of_content_dict_str_str)\n                        ),\n                    )\n            elif self.performative == TProtocolMessage.Performative.PERFORMATIVE_MT:\n                expected_nb_of_contents = 3\n                enforce(\n                    isinstance(self.content_union_1, CustomDataModel1)\n                    or isinstance(self.content_union_1, bool)\n                    or isinstance(self.content_union_1, bytes)\n                    or isinstance(self.content_union_1, dict)\n                    or isinstance(self.content_union_1, float)\n                    or isinstance(self.content_union_1, frozenset)\n                    or type(self.content_union_1) is int\n                    or isinstance(self.content_union_1, str)\n                    or isinstance(self.content_union_1, tuple),\n                    \"Invalid type for content 'content_union_1'. Expected either of '['DataModel1', 'bool', 'bytes', 'dict', 'float', 'frozenset', 'int', 'str', 'tuple']'. Found '{}'.\".format(\n                        type(self.content_union_1)\n                    ),\n                )\n                if isinstance(self.content_union_1, frozenset):\n                    enforce(\n                        all(type(element) is int for element in self.content_union_1),\n                        \"Invalid type for elements of content 'content_union_1'. Expected 'int'.\",\n                    )\n                if isinstance(self.content_union_1, tuple):\n                    enforce(\n                        all(\n                            isinstance(element, bool)\n                            for element in self.content_union_1\n                        ),\n                        \"Invalid type for tuple elements in content 'content_union_1'. Expected 'bool'.\",\n                    )\n                if isinstance(self.content_union_1, dict):\n                    for (\n                        key_of_content_union_1,\n                        value_of_content_union_1,\n                    ) in self.content_union_1.items():\n                        enforce(\n                            (\n                                isinstance(key_of_content_union_1, str)\n                                and type(value_of_content_union_1) is int\n                            ),\n                            \"Invalid type for dictionary key, value in content 'content_union_1'. Expected 'str', 'int'.\",\n                        )\n                enforce(\n                    isinstance(self.content_union_2, dict)\n                    or isinstance(self.content_union_2, frozenset)\n                    or type(self.content_union_2) is int\n                    or isinstance(self.content_union_2, tuple),\n                    \"Invalid type for content 'content_union_2'. Expected either of '['dict', 'frozenset', 'int', 'tuple']'. Found '{}'.\".format(\n                        type(self.content_union_2)\n                    ),\n                )\n                if isinstance(self.content_union_2, frozenset):\n                    enforce(\n                        all(\n                            isinstance(element, bytes)\n                            for element in self.content_union_2\n                        )\n                        or all(type(element) is int for element in self.content_union_2)\n                        or all(\n                            isinstance(element, str) for element in self.content_union_2\n                        ),\n                        \"Invalid type for frozenset elements in content 'content_union_2'. Expected either 'bytes' or 'int' or 'str'.\",\n                    )\n                if isinstance(self.content_union_2, tuple):\n                    enforce(\n                        all(\n                            isinstance(element, bool)\n                            for element in self.content_union_2\n                        )\n                        or all(\n                            isinstance(element, bytes)\n                            for element in self.content_union_2\n                        )\n                        or all(\n                            isinstance(element, float)\n                            for element in self.content_union_2\n                        ),\n                        \"Invalid type for tuple elements in content 'content_union_2'. Expected either 'bool' or 'bytes' or 'float'.\",\n                    )\n                if isinstance(self.content_union_2, dict):\n                    for (\n                        key_of_content_union_2,\n                        value_of_content_union_2,\n                    ) in self.content_union_2.items():\n                        enforce(\n                            (\n                                isinstance(key_of_content_union_2, bool)\n                                and isinstance(value_of_content_union_2, bytes)\n                            )\n                            or (\n                                type(key_of_content_union_2) is int\n                                and isinstance(value_of_content_union_2, float)\n                            )\n                            or (\n                                isinstance(key_of_content_union_2, str)\n                                and type(value_of_content_union_2) is int\n                            ),\n                            \"Invalid type for dictionary key, value in content 'content_union_2'. Expected 'bool','bytes' or 'int','float' or 'str','int'.\",\n                        )\n                enforce(\n                    isinstance(self.content_union_3, CustomDataModel2)\n                    or isinstance(self.content_union_3, CustomDataModel3),\n                    \"Invalid type for content 'content_union_3'. Expected either of '['DataModel2', 'DataModel3']'. Found '{}'.\".format(\n                        type(self.content_union_3)\n                    ),\n                )\n            elif self.performative == TProtocolMessage.Performative.PERFORMATIVE_O:\n                expected_nb_of_contents = 0\n                if self.is_set(\"content_o_ct\"):\n                    expected_nb_of_contents += 1\n                    content_o_ct = cast(CustomDataModel4, self.content_o_ct)\n                    enforce(\n                        isinstance(content_o_ct, CustomDataModel4),\n                        \"Invalid type for content 'content_o_ct'. Expected 'DataModel4'. Found '{}'.\".format(\n                            type(content_o_ct)\n                        ),\n                    )\n                if self.is_set(\"content_o_bool\"):\n                    expected_nb_of_contents += 1\n                    content_o_bool = cast(bool, self.content_o_bool)\n                    enforce(\n                        isinstance(content_o_bool, bool),\n                        \"Invalid type for content 'content_o_bool'. Expected 'bool'. Found '{}'.\".format(\n                            type(content_o_bool)\n                        ),\n                    )\n                if self.is_set(\"content_o_set_int\"):\n                    expected_nb_of_contents += 1\n                    content_o_set_int = cast(FrozenSet[int], self.content_o_set_int)\n                    enforce(\n                        isinstance(content_o_set_int, frozenset),\n                        \"Invalid type for content 'content_o_set_int'. Expected 'frozenset'. Found '{}'.\".format(\n                            type(content_o_set_int)\n                        ),\n                    )\n                    enforce(\n                        all(type(element) is int for element in content_o_set_int),\n                        \"Invalid type for frozenset elements in content 'content_o_set_int'. Expected 'int'.\",\n                    )\n                if self.is_set(\"content_o_list_bytes\"):\n                    expected_nb_of_contents += 1\n                    content_o_list_bytes = cast(\n                        Tuple[bytes, ...], self.content_o_list_bytes\n                    )\n                    enforce(\n                        isinstance(content_o_list_bytes, tuple),\n                        \"Invalid type for content 'content_o_list_bytes'. Expected 'tuple'. Found '{}'.\".format(\n                            type(content_o_list_bytes)\n                        ),\n                    )\n                    enforce(\n                        all(\n                            isinstance(element, bytes)\n                            for element in content_o_list_bytes\n                        ),\n                        \"Invalid type for tuple elements in content 'content_o_list_bytes'. Expected 'bytes'.\",\n                    )\n                if self.is_set(\"content_o_dict_str_int\"):\n                    expected_nb_of_contents += 1\n                    content_o_dict_str_int = cast(\n                        Dict[str, int], self.content_o_dict_str_int\n                    )\n                    enforce(\n                        isinstance(content_o_dict_str_int, dict),\n                        \"Invalid type for content 'content_o_dict_str_int'. Expected 'dict'. Found '{}'.\".format(\n                            type(content_o_dict_str_int)\n                        ),\n                    )\n                    for (\n                        key_of_content_o_dict_str_int,\n                        value_of_content_o_dict_str_int,\n                    ) in content_o_dict_str_int.items():\n                        enforce(\n                            isinstance(key_of_content_o_dict_str_int, str),\n                            \"Invalid type for dictionary keys in content 'content_o_dict_str_int'. Expected 'str'. Found '{}'.\".format(\n                                type(key_of_content_o_dict_str_int)\n                            ),\n                        )\n                        enforce(\n                            type(value_of_content_o_dict_str_int) is int,\n                            \"Invalid type for dictionary values in content 'content_o_dict_str_int'. Expected 'int'. Found '{}'.\".format(\n                                type(value_of_content_o_dict_str_int)\n                            ),\n                        )\n            elif (\n                self.performative\n                == TProtocolMessage.Performative.PERFORMATIVE_EMPTY_CONTENTS\n            ):\n                expected_nb_of_contents = 0\n\n            # Check correct content count\n            enforce(\n                expected_nb_of_contents == actual_nb_of_contents,\n                \"Incorrect number of contents. Expected {}. Found {}\".format(\n                    expected_nb_of_contents, actual_nb_of_contents\n                ),\n            )\n\n            # Light Protocol Rule 3\n            if self.message_id == 1:\n                enforce(\n                    self.target == 0,\n                    \"Invalid 'target'. Expected 0 (because 'message_id' is 1). Found {}.\".format(\n                        self.target\n                    ),\n                )\n        except (AEAEnforceError, ValueError, KeyError) as e:\n            _default_logger.error(str(e))\n            return False\n\n        return True\n"
  },
  {
    "path": "tests/data/generator/t_protocol/protocol.yaml",
    "content": "name: t_protocol\nauthor: fetchai\nversion: 0.1.0\nprotocol_specification_id: some_author/some_protocol_name:1.0.0\ntype: protocol\ndescription: A protocol for testing purposes.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  __init__.py: QmNg4u2z7LVfhFYWiGjvabHoNQ26pyE1a3Z8df8nMVYjKu\n  custom_types.py: QmYe8yi1PB7aGqEJ3z6LqTVUhQyf57Q6U1nCPsEfnEfTVQ\n  dialogues.py: QmerAFMZq4g5fwTdC4CZ3hAG3XA7egXkPeYz95vBSLYHCZ\n  message.py: QmZDVSvvrwrN6tNfipxPUjr6q4N9cqDTMQpenZPZMTtxEg\n  serialization.py: QmXcTuZAbSDXFaCfajXPfFofT2koguvCLriJDx9wAHtSXT\n  t_protocol.proto: QmY6Gw3Y7iKY2zR4kK6cx8cR1jjJivhLsSnP6HDk8843si\n  t_protocol_pb2.py: QmWW1wUqN4X5VCQCmPP1TiHgpNpcNM1z59TnDPZuQ4L8aR\nfingerprint_ignore_patterns: []\ndependencies:\n  protobuf: {}\n"
  },
  {
    "path": "tests/data/generator/t_protocol/serialization.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Serialization module for t_protocol protocol.\"\"\"\n\n# pylint: disable=too-many-statements,too-many-locals,no-member,too-few-public-methods,redefined-builtin\nfrom typing import Any, Dict, cast\n\nfrom aea.mail.base_pb2 import DialogueMessage\nfrom aea.mail.base_pb2 import Message as ProtobufMessage\nfrom aea.protocols.base import Message, Serializer\n\nfrom tests.data.generator.t_protocol import t_protocol_pb2\nfrom tests.data.generator.t_protocol.custom_types import (\n    DataModel,\n    DataModel1,\n    DataModel2,\n    DataModel3,\n    DataModel4,\n)\nfrom tests.data.generator.t_protocol.message import TProtocolMessage\n\n\nclass TProtocolSerializer(Serializer):\n    \"\"\"Serialization for the 't_protocol' protocol.\"\"\"\n\n    @staticmethod\n    def encode(msg: Message) -> bytes:\n        \"\"\"\n        Encode a 'TProtocol' message into bytes.\n\n        :param msg: the message object.\n        :return: the bytes.\n        \"\"\"\n        msg = cast(TProtocolMessage, msg)\n        message_pb = ProtobufMessage()\n        dialogue_message_pb = DialogueMessage()\n        t_protocol_msg = t_protocol_pb2.TProtocolMessage()\n\n        dialogue_message_pb.message_id = msg.message_id\n        dialogue_reference = msg.dialogue_reference\n        dialogue_message_pb.dialogue_starter_reference = dialogue_reference[0]\n        dialogue_message_pb.dialogue_responder_reference = dialogue_reference[1]\n        dialogue_message_pb.target = msg.target\n\n        performative_id = msg.performative\n        if performative_id == TProtocolMessage.Performative.PERFORMATIVE_CT:\n            performative = t_protocol_pb2.TProtocolMessage.Performative_Ct_Performative()  # type: ignore\n            content_ct = msg.content_ct\n            DataModel.encode(performative.content_ct, content_ct)\n            t_protocol_msg.performative_ct.CopyFrom(performative)\n        elif performative_id == TProtocolMessage.Performative.PERFORMATIVE_PT:\n            performative = t_protocol_pb2.TProtocolMessage.Performative_Pt_Performative()  # type: ignore\n            content_bytes = msg.content_bytes\n            performative.content_bytes = content_bytes\n            content_int = msg.content_int\n            performative.content_int = content_int\n            content_float = msg.content_float\n            performative.content_float = content_float\n            content_bool = msg.content_bool\n            performative.content_bool = content_bool\n            content_str = msg.content_str\n            performative.content_str = content_str\n            t_protocol_msg.performative_pt.CopyFrom(performative)\n        elif performative_id == TProtocolMessage.Performative.PERFORMATIVE_PCT:\n            performative = t_protocol_pb2.TProtocolMessage.Performative_Pct_Performative()  # type: ignore\n            content_set_bytes = msg.content_set_bytes\n            performative.content_set_bytes.extend(content_set_bytes)\n            content_set_int = msg.content_set_int\n            performative.content_set_int.extend(content_set_int)\n            content_set_float = msg.content_set_float\n            performative.content_set_float.extend(content_set_float)\n            content_set_bool = msg.content_set_bool\n            performative.content_set_bool.extend(content_set_bool)\n            content_set_str = msg.content_set_str\n            performative.content_set_str.extend(content_set_str)\n            content_list_bytes = msg.content_list_bytes\n            performative.content_list_bytes.extend(content_list_bytes)\n            content_list_int = msg.content_list_int\n            performative.content_list_int.extend(content_list_int)\n            content_list_float = msg.content_list_float\n            performative.content_list_float.extend(content_list_float)\n            content_list_bool = msg.content_list_bool\n            performative.content_list_bool.extend(content_list_bool)\n            content_list_str = msg.content_list_str\n            performative.content_list_str.extend(content_list_str)\n            t_protocol_msg.performative_pct.CopyFrom(performative)\n        elif performative_id == TProtocolMessage.Performative.PERFORMATIVE_PMT:\n            performative = t_protocol_pb2.TProtocolMessage.Performative_Pmt_Performative()  # type: ignore\n            content_dict_int_bytes = msg.content_dict_int_bytes\n            performative.content_dict_int_bytes.update(content_dict_int_bytes)\n            content_dict_int_int = msg.content_dict_int_int\n            performative.content_dict_int_int.update(content_dict_int_int)\n            content_dict_int_float = msg.content_dict_int_float\n            performative.content_dict_int_float.update(content_dict_int_float)\n            content_dict_int_bool = msg.content_dict_int_bool\n            performative.content_dict_int_bool.update(content_dict_int_bool)\n            content_dict_int_str = msg.content_dict_int_str\n            performative.content_dict_int_str.update(content_dict_int_str)\n            content_dict_bool_bytes = msg.content_dict_bool_bytes\n            performative.content_dict_bool_bytes.update(content_dict_bool_bytes)\n            content_dict_bool_int = msg.content_dict_bool_int\n            performative.content_dict_bool_int.update(content_dict_bool_int)\n            content_dict_bool_float = msg.content_dict_bool_float\n            performative.content_dict_bool_float.update(content_dict_bool_float)\n            content_dict_bool_bool = msg.content_dict_bool_bool\n            performative.content_dict_bool_bool.update(content_dict_bool_bool)\n            content_dict_bool_str = msg.content_dict_bool_str\n            performative.content_dict_bool_str.update(content_dict_bool_str)\n            content_dict_str_bytes = msg.content_dict_str_bytes\n            performative.content_dict_str_bytes.update(content_dict_str_bytes)\n            content_dict_str_int = msg.content_dict_str_int\n            performative.content_dict_str_int.update(content_dict_str_int)\n            content_dict_str_float = msg.content_dict_str_float\n            performative.content_dict_str_float.update(content_dict_str_float)\n            content_dict_str_bool = msg.content_dict_str_bool\n            performative.content_dict_str_bool.update(content_dict_str_bool)\n            content_dict_str_str = msg.content_dict_str_str\n            performative.content_dict_str_str.update(content_dict_str_str)\n            t_protocol_msg.performative_pmt.CopyFrom(performative)\n        elif performative_id == TProtocolMessage.Performative.PERFORMATIVE_MT:\n            performative = t_protocol_pb2.TProtocolMessage.Performative_Mt_Performative()  # type: ignore\n            if msg.is_set(\"content_union_1\"):\n                if isinstance(msg.content_union_1, DataModel1):\n                    performative.content_union_1_type_DataModel1_is_set = True\n                    content_union_1_type_DataModel1 = msg.content_union_1\n                    DataModel1.encode(\n                        performative.content_union_1_type_DataModel1,\n                        content_union_1_type_DataModel1,\n                    )\n                elif isinstance(msg.content_union_1, bytes):\n                    performative.content_union_1_type_bytes_is_set = True\n                    content_union_1_type_bytes = msg.content_union_1\n                    performative.content_union_1_type_bytes = content_union_1_type_bytes\n                elif isinstance(msg.content_union_1, int):\n                    performative.content_union_1_type_int_is_set = True\n                    content_union_1_type_int = msg.content_union_1\n                    performative.content_union_1_type_int = content_union_1_type_int\n                elif isinstance(msg.content_union_1, float):\n                    performative.content_union_1_type_float_is_set = True\n                    content_union_1_type_float = msg.content_union_1\n                    performative.content_union_1_type_float = content_union_1_type_float\n                elif isinstance(msg.content_union_1, bool):\n                    performative.content_union_1_type_bool_is_set = True\n                    content_union_1_type_bool = msg.content_union_1\n                    performative.content_union_1_type_bool = content_union_1_type_bool\n                elif isinstance(msg.content_union_1, str):\n                    performative.content_union_1_type_str_is_set = True\n                    content_union_1_type_str = msg.content_union_1\n                    performative.content_union_1_type_str = content_union_1_type_str\n                elif isinstance(msg.content_union_1, (set, frozenset)) and all(\n                    map(lambda x: isinstance(x, int), msg.content_union_1)\n                ):\n                    performative.content_union_1_type_set_of_int_is_set = True\n                    content_union_1 = msg.content_union_1\n                    performative.content_union_1_type_set_of_int.extend(content_union_1)\n                elif isinstance(msg.content_union_1, (list, tuple)) and all(\n                    map(lambda x: isinstance(x, bool), msg.content_union_1)\n                ):\n                    performative.content_union_1_type_list_of_bool_is_set = True\n                    content_union_1 = msg.content_union_1\n                    performative.content_union_1_type_list_of_bool.extend(\n                        content_union_1\n                    )\n                elif isinstance(msg.content_union_1, dict) and all(\n                    map(\n                        lambda x: isinstance(x[0], str) and isinstance(x[1], int),\n                        msg.content_union_1.items(),\n                    )\n                ):\n                    performative.content_union_1_type_dict_of_str_int_is_set = True\n                    content_union_1 = msg.content_union_1\n                    performative.content_union_1_type_dict_of_str_int.update(\n                        content_union_1\n                    )\n                elif msg.content_union_1 is None:\n                    pass\n                else:\n                    raise ValueError(\n                        f\"Bad value set to `content_union_1` {msg.content_union_1 }\"\n                    )\n            if msg.is_set(\"content_union_2\"):\n                if isinstance(msg.content_union_2, (set, frozenset)) and all(\n                    map(lambda x: isinstance(x, bytes), msg.content_union_2)\n                ):\n                    performative.content_union_2_type_set_of_bytes_is_set = True\n                    content_union_2 = msg.content_union_2\n                    performative.content_union_2_type_set_of_bytes.extend(\n                        content_union_2\n                    )\n                elif isinstance(msg.content_union_2, (set, frozenset)) and all(\n                    map(lambda x: isinstance(x, int), msg.content_union_2)\n                ):\n                    performative.content_union_2_type_set_of_int_is_set = True\n                    content_union_2 = msg.content_union_2\n                    performative.content_union_2_type_set_of_int.extend(content_union_2)\n                elif isinstance(msg.content_union_2, (set, frozenset)) and all(\n                    map(lambda x: isinstance(x, str), msg.content_union_2)\n                ):\n                    performative.content_union_2_type_set_of_str_is_set = True\n                    content_union_2 = msg.content_union_2\n                    performative.content_union_2_type_set_of_str.extend(content_union_2)\n                elif isinstance(msg.content_union_2, (list, tuple)) and all(\n                    map(lambda x: isinstance(x, float), msg.content_union_2)\n                ):\n                    performative.content_union_2_type_list_of_float_is_set = True\n                    content_union_2 = msg.content_union_2\n                    performative.content_union_2_type_list_of_float.extend(\n                        content_union_2\n                    )\n                elif isinstance(msg.content_union_2, (list, tuple)) and all(\n                    map(lambda x: isinstance(x, bool), msg.content_union_2)\n                ):\n                    performative.content_union_2_type_list_of_bool_is_set = True\n                    content_union_2 = msg.content_union_2\n                    performative.content_union_2_type_list_of_bool.extend(\n                        content_union_2\n                    )\n                elif isinstance(msg.content_union_2, (list, tuple)) and all(\n                    map(lambda x: isinstance(x, bytes), msg.content_union_2)\n                ):\n                    performative.content_union_2_type_list_of_bytes_is_set = True\n                    content_union_2 = msg.content_union_2\n                    performative.content_union_2_type_list_of_bytes.extend(\n                        content_union_2\n                    )\n                elif isinstance(msg.content_union_2, dict) and all(\n                    map(\n                        lambda x: isinstance(x[0], str) and isinstance(x[1], int),\n                        msg.content_union_2.items(),\n                    )\n                ):\n                    performative.content_union_2_type_dict_of_str_int_is_set = True\n                    content_union_2 = msg.content_union_2\n                    performative.content_union_2_type_dict_of_str_int.update(\n                        content_union_2\n                    )\n                elif isinstance(msg.content_union_2, dict) and all(\n                    map(\n                        lambda x: isinstance(x[0], int) and isinstance(x[1], float),\n                        msg.content_union_2.items(),\n                    )\n                ):\n                    performative.content_union_2_type_dict_of_int_float_is_set = True\n                    content_union_2 = msg.content_union_2\n                    performative.content_union_2_type_dict_of_int_float.update(\n                        content_union_2\n                    )\n                elif isinstance(msg.content_union_2, dict) and all(\n                    map(\n                        lambda x: isinstance(x[0], bool) and isinstance(x[1], bytes),\n                        msg.content_union_2.items(),\n                    )\n                ):\n                    performative.content_union_2_type_dict_of_bool_bytes_is_set = True\n                    content_union_2 = msg.content_union_2\n                    performative.content_union_2_type_dict_of_bool_bytes.update(\n                        content_union_2\n                    )\n                elif isinstance(msg.content_union_2, int):\n                    performative.content_union_2_type_int_is_set = True\n                    content_union_2_type_int = msg.content_union_2\n                    performative.content_union_2_type_int = content_union_2_type_int\n                elif msg.content_union_2 is None:\n                    pass\n                else:\n                    raise ValueError(\n                        f\"Bad value set to `content_union_2` {msg.content_union_2 }\"\n                    )\n            if msg.is_set(\"content_union_3\"):\n                if isinstance(msg.content_union_3, DataModel2):\n                    performative.content_union_3_type_DataModel2_is_set = True\n                    content_union_3_type_DataModel2 = msg.content_union_3\n                    DataModel2.encode(\n                        performative.content_union_3_type_DataModel2,\n                        content_union_3_type_DataModel2,\n                    )\n                elif isinstance(msg.content_union_3, DataModel3):\n                    performative.content_union_3_type_DataModel3_is_set = True\n                    content_union_3_type_DataModel3 = msg.content_union_3\n                    DataModel3.encode(\n                        performative.content_union_3_type_DataModel3,\n                        content_union_3_type_DataModel3,\n                    )\n                elif msg.content_union_3 is None:\n                    pass\n                else:\n                    raise ValueError(\n                        f\"Bad value set to `content_union_3` {msg.content_union_3 }\"\n                    )\n            t_protocol_msg.performative_mt.CopyFrom(performative)\n        elif performative_id == TProtocolMessage.Performative.PERFORMATIVE_O:\n            performative = t_protocol_pb2.TProtocolMessage.Performative_O_Performative()  # type: ignore\n            if msg.is_set(\"content_o_ct\"):\n                performative.content_o_ct_is_set = True\n                content_o_ct = msg.content_o_ct\n                DataModel4.encode(performative.content_o_ct, content_o_ct)\n            if msg.is_set(\"content_o_bool\"):\n                performative.content_o_bool_is_set = True\n                content_o_bool = msg.content_o_bool\n                performative.content_o_bool = content_o_bool\n            if msg.is_set(\"content_o_set_int\"):\n                performative.content_o_set_int_is_set = True\n                content_o_set_int = msg.content_o_set_int\n                performative.content_o_set_int.extend(content_o_set_int)\n            if msg.is_set(\"content_o_list_bytes\"):\n                performative.content_o_list_bytes_is_set = True\n                content_o_list_bytes = msg.content_o_list_bytes\n                performative.content_o_list_bytes.extend(content_o_list_bytes)\n            if msg.is_set(\"content_o_dict_str_int\"):\n                performative.content_o_dict_str_int_is_set = True\n                content_o_dict_str_int = msg.content_o_dict_str_int\n                performative.content_o_dict_str_int.update(content_o_dict_str_int)\n            t_protocol_msg.performative_o.CopyFrom(performative)\n        elif (\n            performative_id == TProtocolMessage.Performative.PERFORMATIVE_EMPTY_CONTENTS\n        ):\n            performative = t_protocol_pb2.TProtocolMessage.Performative_Empty_Contents_Performative()  # type: ignore\n            t_protocol_msg.performative_empty_contents.CopyFrom(performative)\n        else:\n            raise ValueError(\"Performative not valid: {}\".format(performative_id))\n\n        dialogue_message_pb.content = t_protocol_msg.SerializeToString()\n\n        message_pb.dialogue_message.CopyFrom(dialogue_message_pb)\n        message_bytes = message_pb.SerializeToString()\n        return message_bytes\n\n    @staticmethod\n    def decode(obj: bytes) -> Message:\n        \"\"\"\n        Decode bytes into a 'TProtocol' message.\n\n        :param obj: the bytes object.\n        :return: the 'TProtocol' message.\n        \"\"\"\n        message_pb = ProtobufMessage()\n        t_protocol_pb = t_protocol_pb2.TProtocolMessage()\n        message_pb.ParseFromString(obj)\n        message_id = message_pb.dialogue_message.message_id\n        dialogue_reference = (\n            message_pb.dialogue_message.dialogue_starter_reference,\n            message_pb.dialogue_message.dialogue_responder_reference,\n        )\n        target = message_pb.dialogue_message.target\n\n        t_protocol_pb.ParseFromString(message_pb.dialogue_message.content)\n        performative = t_protocol_pb.WhichOneof(\"performative\")\n        performative_id = TProtocolMessage.Performative(str(performative))\n        performative_content = {}  # type: Dict[str, Any]\n        if performative_id == TProtocolMessage.Performative.PERFORMATIVE_CT:\n            pb2_content_ct = t_protocol_pb.performative_ct.content_ct\n            content_ct = DataModel.decode(pb2_content_ct)\n            performative_content[\"content_ct\"] = content_ct\n        elif performative_id == TProtocolMessage.Performative.PERFORMATIVE_PT:\n            content_bytes = t_protocol_pb.performative_pt.content_bytes\n            performative_content[\"content_bytes\"] = content_bytes\n            content_int = t_protocol_pb.performative_pt.content_int\n            performative_content[\"content_int\"] = content_int\n            content_float = t_protocol_pb.performative_pt.content_float\n            performative_content[\"content_float\"] = content_float\n            content_bool = t_protocol_pb.performative_pt.content_bool\n            performative_content[\"content_bool\"] = content_bool\n            content_str = t_protocol_pb.performative_pt.content_str\n            performative_content[\"content_str\"] = content_str\n        elif performative_id == TProtocolMessage.Performative.PERFORMATIVE_PCT:\n            content_set_bytes = t_protocol_pb.performative_pct.content_set_bytes\n            content_set_bytes_frozenset = frozenset(content_set_bytes)\n            performative_content[\"content_set_bytes\"] = content_set_bytes_frozenset\n            content_set_int = t_protocol_pb.performative_pct.content_set_int\n            content_set_int_frozenset = frozenset(content_set_int)\n            performative_content[\"content_set_int\"] = content_set_int_frozenset\n            content_set_float = t_protocol_pb.performative_pct.content_set_float\n            content_set_float_frozenset = frozenset(content_set_float)\n            performative_content[\"content_set_float\"] = content_set_float_frozenset\n            content_set_bool = t_protocol_pb.performative_pct.content_set_bool\n            content_set_bool_frozenset = frozenset(content_set_bool)\n            performative_content[\"content_set_bool\"] = content_set_bool_frozenset\n            content_set_str = t_protocol_pb.performative_pct.content_set_str\n            content_set_str_frozenset = frozenset(content_set_str)\n            performative_content[\"content_set_str\"] = content_set_str_frozenset\n            content_list_bytes = t_protocol_pb.performative_pct.content_list_bytes\n            content_list_bytes_tuple = tuple(content_list_bytes)\n            performative_content[\"content_list_bytes\"] = content_list_bytes_tuple\n            content_list_int = t_protocol_pb.performative_pct.content_list_int\n            content_list_int_tuple = tuple(content_list_int)\n            performative_content[\"content_list_int\"] = content_list_int_tuple\n            content_list_float = t_protocol_pb.performative_pct.content_list_float\n            content_list_float_tuple = tuple(content_list_float)\n            performative_content[\"content_list_float\"] = content_list_float_tuple\n            content_list_bool = t_protocol_pb.performative_pct.content_list_bool\n            content_list_bool_tuple = tuple(content_list_bool)\n            performative_content[\"content_list_bool\"] = content_list_bool_tuple\n            content_list_str = t_protocol_pb.performative_pct.content_list_str\n            content_list_str_tuple = tuple(content_list_str)\n            performative_content[\"content_list_str\"] = content_list_str_tuple\n        elif performative_id == TProtocolMessage.Performative.PERFORMATIVE_PMT:\n            content_dict_int_bytes = (\n                t_protocol_pb.performative_pmt.content_dict_int_bytes\n            )\n            content_dict_int_bytes_dict = dict(content_dict_int_bytes)\n            performative_content[\"content_dict_int_bytes\"] = content_dict_int_bytes_dict\n            content_dict_int_int = t_protocol_pb.performative_pmt.content_dict_int_int\n            content_dict_int_int_dict = dict(content_dict_int_int)\n            performative_content[\"content_dict_int_int\"] = content_dict_int_int_dict\n            content_dict_int_float = (\n                t_protocol_pb.performative_pmt.content_dict_int_float\n            )\n            content_dict_int_float_dict = dict(content_dict_int_float)\n            performative_content[\"content_dict_int_float\"] = content_dict_int_float_dict\n            content_dict_int_bool = t_protocol_pb.performative_pmt.content_dict_int_bool\n            content_dict_int_bool_dict = dict(content_dict_int_bool)\n            performative_content[\"content_dict_int_bool\"] = content_dict_int_bool_dict\n            content_dict_int_str = t_protocol_pb.performative_pmt.content_dict_int_str\n            content_dict_int_str_dict = dict(content_dict_int_str)\n            performative_content[\"content_dict_int_str\"] = content_dict_int_str_dict\n            content_dict_bool_bytes = (\n                t_protocol_pb.performative_pmt.content_dict_bool_bytes\n            )\n            content_dict_bool_bytes_dict = dict(content_dict_bool_bytes)\n            performative_content[\n                \"content_dict_bool_bytes\"\n            ] = content_dict_bool_bytes_dict\n            content_dict_bool_int = t_protocol_pb.performative_pmt.content_dict_bool_int\n            content_dict_bool_int_dict = dict(content_dict_bool_int)\n            performative_content[\"content_dict_bool_int\"] = content_dict_bool_int_dict\n            content_dict_bool_float = (\n                t_protocol_pb.performative_pmt.content_dict_bool_float\n            )\n            content_dict_bool_float_dict = dict(content_dict_bool_float)\n            performative_content[\n                \"content_dict_bool_float\"\n            ] = content_dict_bool_float_dict\n            content_dict_bool_bool = (\n                t_protocol_pb.performative_pmt.content_dict_bool_bool\n            )\n            content_dict_bool_bool_dict = dict(content_dict_bool_bool)\n            performative_content[\"content_dict_bool_bool\"] = content_dict_bool_bool_dict\n            content_dict_bool_str = t_protocol_pb.performative_pmt.content_dict_bool_str\n            content_dict_bool_str_dict = dict(content_dict_bool_str)\n            performative_content[\"content_dict_bool_str\"] = content_dict_bool_str_dict\n            content_dict_str_bytes = (\n                t_protocol_pb.performative_pmt.content_dict_str_bytes\n            )\n            content_dict_str_bytes_dict = dict(content_dict_str_bytes)\n            performative_content[\"content_dict_str_bytes\"] = content_dict_str_bytes_dict\n            content_dict_str_int = t_protocol_pb.performative_pmt.content_dict_str_int\n            content_dict_str_int_dict = dict(content_dict_str_int)\n            performative_content[\"content_dict_str_int\"] = content_dict_str_int_dict\n            content_dict_str_float = (\n                t_protocol_pb.performative_pmt.content_dict_str_float\n            )\n            content_dict_str_float_dict = dict(content_dict_str_float)\n            performative_content[\"content_dict_str_float\"] = content_dict_str_float_dict\n            content_dict_str_bool = t_protocol_pb.performative_pmt.content_dict_str_bool\n            content_dict_str_bool_dict = dict(content_dict_str_bool)\n            performative_content[\"content_dict_str_bool\"] = content_dict_str_bool_dict\n            content_dict_str_str = t_protocol_pb.performative_pmt.content_dict_str_str\n            content_dict_str_str_dict = dict(content_dict_str_str)\n            performative_content[\"content_dict_str_str\"] = content_dict_str_str_dict\n        elif performative_id == TProtocolMessage.Performative.PERFORMATIVE_MT:\n            if t_protocol_pb.performative_mt.content_union_1_type_DataModel1_is_set:\n                pb2_content_union_1_type_DataModel1 = (\n                    t_protocol_pb.performative_mt.content_union_1_type_DataModel1\n                )\n                content_union_1 = DataModel1.decode(pb2_content_union_1_type_DataModel1)\n                performative_content[\"content_union_1\"] = content_union_1\n            if t_protocol_pb.performative_mt.content_union_1_type_bytes_is_set:\n                content_union_1 = (\n                    t_protocol_pb.performative_mt.content_union_1_type_bytes\n                )\n                performative_content[\"content_union_1\"] = content_union_1\n            if t_protocol_pb.performative_mt.content_union_1_type_int_is_set:\n                content_union_1 = t_protocol_pb.performative_mt.content_union_1_type_int\n                performative_content[\"content_union_1\"] = content_union_1\n            if t_protocol_pb.performative_mt.content_union_1_type_float_is_set:\n                content_union_1 = (\n                    t_protocol_pb.performative_mt.content_union_1_type_float\n                )\n                performative_content[\"content_union_1\"] = content_union_1\n            if t_protocol_pb.performative_mt.content_union_1_type_bool_is_set:\n                content_union_1 = (\n                    t_protocol_pb.performative_mt.content_union_1_type_bool\n                )\n                performative_content[\"content_union_1\"] = content_union_1\n            if t_protocol_pb.performative_mt.content_union_1_type_str_is_set:\n                content_union_1 = t_protocol_pb.performative_mt.content_union_1_type_str\n                performative_content[\"content_union_1\"] = content_union_1\n            if t_protocol_pb.performative_mt.content_union_1_type_set_of_int_is_set:\n                content_union_1 = (\n                    t_protocol_pb.performative_mt.content_union_1_type_set_of_int\n                )\n                content_union_1_frozenset = frozenset(content_union_1)\n                performative_content[\"content_union_1\"] = content_union_1_frozenset\n            if t_protocol_pb.performative_mt.content_union_1_type_list_of_bool_is_set:\n                content_union_1 = (\n                    t_protocol_pb.performative_mt.content_union_1_type_list_of_bool\n                )\n                content_union_1_tuple = tuple(content_union_1)\n                performative_content[\"content_union_1\"] = content_union_1_tuple\n            if (\n                t_protocol_pb.performative_mt.content_union_1_type_dict_of_str_int_is_set\n            ):\n                content_union_1 = (\n                    t_protocol_pb.performative_mt.content_union_1_type_dict_of_str_int\n                )\n                content_union_1_dict = dict(content_union_1)\n                performative_content[\"content_union_1\"] = content_union_1_dict\n            if t_protocol_pb.performative_mt.content_union_2_type_set_of_bytes_is_set:\n                content_union_2 = (\n                    t_protocol_pb.performative_mt.content_union_2_type_set_of_bytes\n                )\n                content_union_2_frozenset = frozenset(content_union_2)\n                performative_content[\"content_union_2\"] = content_union_2_frozenset\n            if t_protocol_pb.performative_mt.content_union_2_type_set_of_int_is_set:\n                content_union_2 = (\n                    t_protocol_pb.performative_mt.content_union_2_type_set_of_int\n                )\n                content_union_2_frozenset = frozenset(content_union_2)\n                performative_content[\"content_union_2\"] = content_union_2_frozenset\n            if t_protocol_pb.performative_mt.content_union_2_type_set_of_str_is_set:\n                content_union_2 = (\n                    t_protocol_pb.performative_mt.content_union_2_type_set_of_str\n                )\n                content_union_2_frozenset = frozenset(content_union_2)\n                performative_content[\"content_union_2\"] = content_union_2_frozenset\n            if t_protocol_pb.performative_mt.content_union_2_type_list_of_float_is_set:\n                content_union_2 = (\n                    t_protocol_pb.performative_mt.content_union_2_type_list_of_float\n                )\n                content_union_2_tuple = tuple(content_union_2)\n                performative_content[\"content_union_2\"] = content_union_2_tuple\n            if t_protocol_pb.performative_mt.content_union_2_type_list_of_bool_is_set:\n                content_union_2 = (\n                    t_protocol_pb.performative_mt.content_union_2_type_list_of_bool\n                )\n                content_union_2_tuple = tuple(content_union_2)\n                performative_content[\"content_union_2\"] = content_union_2_tuple\n            if t_protocol_pb.performative_mt.content_union_2_type_list_of_bytes_is_set:\n                content_union_2 = (\n                    t_protocol_pb.performative_mt.content_union_2_type_list_of_bytes\n                )\n                content_union_2_tuple = tuple(content_union_2)\n                performative_content[\"content_union_2\"] = content_union_2_tuple\n            if (\n                t_protocol_pb.performative_mt.content_union_2_type_dict_of_str_int_is_set\n            ):\n                content_union_2 = (\n                    t_protocol_pb.performative_mt.content_union_2_type_dict_of_str_int\n                )\n                content_union_2_dict = dict(content_union_2)\n                performative_content[\"content_union_2\"] = content_union_2_dict\n            if (\n                t_protocol_pb.performative_mt.content_union_2_type_dict_of_int_float_is_set\n            ):\n                content_union_2 = (\n                    t_protocol_pb.performative_mt.content_union_2_type_dict_of_int_float\n                )\n                content_union_2_dict = dict(content_union_2)\n                performative_content[\"content_union_2\"] = content_union_2_dict\n            if (\n                t_protocol_pb.performative_mt.content_union_2_type_dict_of_bool_bytes_is_set\n            ):\n                content_union_2 = (\n                    t_protocol_pb.performative_mt.content_union_2_type_dict_of_bool_bytes\n                )\n                content_union_2_dict = dict(content_union_2)\n                performative_content[\"content_union_2\"] = content_union_2_dict\n            if t_protocol_pb.performative_mt.content_union_2_type_int_is_set:\n                content_union_2 = t_protocol_pb.performative_mt.content_union_2_type_int\n                performative_content[\"content_union_2\"] = content_union_2\n            if t_protocol_pb.performative_mt.content_union_3_type_DataModel2_is_set:\n                pb2_content_union_3_type_DataModel2 = (\n                    t_protocol_pb.performative_mt.content_union_3_type_DataModel2\n                )\n                content_union_3 = DataModel2.decode(pb2_content_union_3_type_DataModel2)\n                performative_content[\"content_union_3\"] = content_union_3\n            if t_protocol_pb.performative_mt.content_union_3_type_DataModel3_is_set:\n                pb2_content_union_3_type_DataModel3 = (\n                    t_protocol_pb.performative_mt.content_union_3_type_DataModel3\n                )\n                content_union_3 = DataModel3.decode(pb2_content_union_3_type_DataModel3)\n                performative_content[\"content_union_3\"] = content_union_3\n        elif performative_id == TProtocolMessage.Performative.PERFORMATIVE_O:\n            if t_protocol_pb.performative_o.content_o_ct_is_set:\n                pb2_content_o_ct = t_protocol_pb.performative_o.content_o_ct\n                content_o_ct = DataModel4.decode(pb2_content_o_ct)\n                performative_content[\"content_o_ct\"] = content_o_ct\n            if t_protocol_pb.performative_o.content_o_bool_is_set:\n                content_o_bool = t_protocol_pb.performative_o.content_o_bool\n                performative_content[\"content_o_bool\"] = content_o_bool\n            if t_protocol_pb.performative_o.content_o_set_int_is_set:\n                content_o_set_int = t_protocol_pb.performative_o.content_o_set_int\n                content_o_set_int_frozenset = frozenset(content_o_set_int)\n                performative_content[\"content_o_set_int\"] = content_o_set_int_frozenset\n            if t_protocol_pb.performative_o.content_o_list_bytes_is_set:\n                content_o_list_bytes = t_protocol_pb.performative_o.content_o_list_bytes\n                content_o_list_bytes_tuple = tuple(content_o_list_bytes)\n                performative_content[\n                    \"content_o_list_bytes\"\n                ] = content_o_list_bytes_tuple\n            if t_protocol_pb.performative_o.content_o_dict_str_int_is_set:\n                content_o_dict_str_int = (\n                    t_protocol_pb.performative_o.content_o_dict_str_int\n                )\n                content_o_dict_str_int_dict = dict(content_o_dict_str_int)\n                performative_content[\n                    \"content_o_dict_str_int\"\n                ] = content_o_dict_str_int_dict\n        elif (\n            performative_id == TProtocolMessage.Performative.PERFORMATIVE_EMPTY_CONTENTS\n        ):\n            pass\n        else:\n            raise ValueError(\"Performative not valid: {}.\".format(performative_id))\n\n        return TProtocolMessage(\n            message_id=message_id,\n            dialogue_reference=dialogue_reference,\n            target=target,\n            performative=performative,\n            **performative_content,\n        )\n"
  },
  {
    "path": "tests/data/generator/t_protocol/t_protocol.proto",
    "content": "syntax = \"proto3\";\n\npackage aea.some_author.some_protocol_name.v1_0_0;\n\nmessage TProtocolMessage{\n\n  // Custom Types\n  message DataModel{\n    bytes bytes_field = 1;\n    int64 int_field = 2;\n    float float_field = 3;\n    bool bool_field = 4;\n    string str_field = 5;\n    repeated int64 set_field = 6;\n    repeated string list_field = 7;\n    map<int64, bool> dict_field = 8;\n  }\n\n  message DataModel1{\n    bytes bytes_field = 1;\n    int64 int_field = 2;\n    float float_field = 3;\n    bool bool_field = 4;\n    string str_field = 5;\n    repeated int64 set_field = 6;\n    repeated string list_field = 7;\n    map<int64, bool> dict_field = 8;\n  }\n\n  message DataModel2{\n    bytes bytes_field = 1;\n    int64 int_field = 2;\n    float float_field = 3;\n    bool bool_field = 4;\n    string str_field = 5;\n    repeated int64 set_field = 6;\n    repeated string list_field = 7;\n    map<int64, bool> dict_field = 8;\n  }\n\n  message DataModel3{\n    bytes bytes_field = 1;\n    int64 int_field = 2;\n    float float_field = 3;\n    bool bool_field = 4;\n    string str_field = 5;\n    repeated int64 set_field = 6;\n    repeated string list_field = 7;\n    map<int64, bool> dict_field = 8;\n  }\n\n  message DataModel4{\n    bytes bytes_field = 1;\n    int64 int_field = 2;\n    float float_field = 3;\n    bool bool_field = 4;\n    string str_field = 5;\n    repeated int64 set_field = 6;\n    repeated string list_field = 7;\n    map<int64, bool> dict_field = 8;\n  }\n\n\n  // Performatives and contents\n  message Performative_Ct_Performative{\n    DataModel content_ct = 1;\n  }\n\n  message Performative_Pt_Performative{\n    bytes content_bytes = 1;\n    int64 content_int = 2;\n    float content_float = 3;\n    bool content_bool = 4;\n    string content_str = 5;\n  }\n\n  message Performative_Pct_Performative{\n    repeated bytes content_set_bytes = 1;\n    repeated int64 content_set_int = 2;\n    repeated float content_set_float = 3;\n    repeated bool content_set_bool = 4;\n    repeated string content_set_str = 5;\n    repeated bytes content_list_bytes = 6;\n    repeated int64 content_list_int = 7;\n    repeated float content_list_float = 8;\n    repeated bool content_list_bool = 9;\n    repeated string content_list_str = 10;\n  }\n\n  message Performative_Pmt_Performative{\n    map<int64, bytes> content_dict_int_bytes = 1;\n    map<int64, int64> content_dict_int_int = 2;\n    map<int64, float> content_dict_int_float = 3;\n    map<int64, bool> content_dict_int_bool = 4;\n    map<int64, string> content_dict_int_str = 5;\n    map<bool, bytes> content_dict_bool_bytes = 6;\n    map<bool, int64> content_dict_bool_int = 7;\n    map<bool, float> content_dict_bool_float = 8;\n    map<bool, bool> content_dict_bool_bool = 9;\n    map<bool, string> content_dict_bool_str = 10;\n    map<string, bytes> content_dict_str_bytes = 11;\n    map<string, int64> content_dict_str_int = 12;\n    map<string, float> content_dict_str_float = 13;\n    map<string, bool> content_dict_str_bool = 14;\n    map<string, string> content_dict_str_str = 15;\n  }\n\n  message Performative_Mt_Performative{\n    DataModel1 content_union_1_type_DataModel1 = 1;\n    bool content_union_1_type_DataModel1_is_set = 2;\n    bytes content_union_1_type_bytes = 3;\n    bool content_union_1_type_bytes_is_set = 4;\n    int64 content_union_1_type_int = 5;\n    bool content_union_1_type_int_is_set = 6;\n    float content_union_1_type_float = 7;\n    bool content_union_1_type_float_is_set = 8;\n    bool content_union_1_type_bool = 9;\n    bool content_union_1_type_bool_is_set = 10;\n    string content_union_1_type_str = 11;\n    bool content_union_1_type_str_is_set = 12;\n    repeated int64 content_union_1_type_set_of_int = 13;\n    bool content_union_1_type_set_of_int_is_set = 14;\n    repeated bool content_union_1_type_list_of_bool = 15;\n    bool content_union_1_type_list_of_bool_is_set = 16;\n    map<string, int64> content_union_1_type_dict_of_str_int = 17;\n    bool content_union_1_type_dict_of_str_int_is_set = 18;\n    repeated bytes content_union_2_type_set_of_bytes = 19;\n    bool content_union_2_type_set_of_bytes_is_set = 20;\n    repeated int64 content_union_2_type_set_of_int = 21;\n    bool content_union_2_type_set_of_int_is_set = 22;\n    repeated string content_union_2_type_set_of_str = 23;\n    bool content_union_2_type_set_of_str_is_set = 24;\n    repeated float content_union_2_type_list_of_float = 25;\n    bool content_union_2_type_list_of_float_is_set = 26;\n    repeated bool content_union_2_type_list_of_bool = 27;\n    bool content_union_2_type_list_of_bool_is_set = 28;\n    repeated bytes content_union_2_type_list_of_bytes = 29;\n    bool content_union_2_type_list_of_bytes_is_set = 30;\n    map<string, int64> content_union_2_type_dict_of_str_int = 31;\n    bool content_union_2_type_dict_of_str_int_is_set = 32;\n    map<int64, float> content_union_2_type_dict_of_int_float = 33;\n    bool content_union_2_type_dict_of_int_float_is_set = 34;\n    map<bool, bytes> content_union_2_type_dict_of_bool_bytes = 35;\n    bool content_union_2_type_dict_of_bool_bytes_is_set = 36;\n    int64 content_union_2_type_int = 37;\n    bool content_union_2_type_int_is_set = 38;\n    DataModel2 content_union_3_type_DataModel2 = 39;\n    bool content_union_3_type_DataModel2_is_set = 40;\n    DataModel3 content_union_3_type_DataModel3 = 41;\n    bool content_union_3_type_DataModel3_is_set = 42;\n  }\n\n  message Performative_O_Performative{\n    DataModel4 content_o_ct = 1;\n    bool content_o_ct_is_set = 2;\n    bool content_o_bool = 3;\n    bool content_o_bool_is_set = 4;\n    repeated int64 content_o_set_int = 5;\n    bool content_o_set_int_is_set = 6;\n    repeated bytes content_o_list_bytes = 7;\n    bool content_o_list_bytes_is_set = 8;\n    map<string, int64> content_o_dict_str_int = 9;\n    bool content_o_dict_str_int_is_set = 10;\n  }\n\n  message Performative_Empty_Contents_Performative{\n  }\n\n\n  oneof performative{\n    Performative_Ct_Performative performative_ct = 5;\n    Performative_Empty_Contents_Performative performative_empty_contents = 6;\n    Performative_Mt_Performative performative_mt = 7;\n    Performative_O_Performative performative_o = 8;\n    Performative_Pct_Performative performative_pct = 9;\n    Performative_Pmt_Performative performative_pmt = 10;\n    Performative_Pt_Performative performative_pt = 11;\n  }\n}\n"
  },
  {
    "path": "tests/data/generator/t_protocol/t_protocol_pb2.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by the protocol buffer compiler.  DO NOT EDIT!\n# source: t_protocol.proto\n\"\"\"Generated protocol buffer code.\"\"\"\nfrom google.protobuf import descriptor as _descriptor\nfrom google.protobuf import descriptor_pool as _descriptor_pool\nfrom google.protobuf import message as _message\nfrom google.protobuf import reflection as _reflection\nfrom google.protobuf import symbol_database as _symbol_database\n\n# @@protoc_insertion_point(imports)\n\n_sym_db = _symbol_database.Default()\n\n\nDESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(\n    b\"\\n\\x10t_protocol.proto\\x12)aea.some_author.some_protocol_name.v1_0_0\\\"\\xcbK\\n\\x10TProtocolMessage\\x12s\\n\\x0fperformative_ct\\x18\\x05 \\x01(\\x0b\\x32X.aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.Performative_Ct_PerformativeH\\x00\\x12\\x8b\\x01\\n\\x1bperformative_empty_contents\\x18\\x06 \\x01(\\x0b\\x32\\x64.aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.Performative_Empty_Contents_PerformativeH\\x00\\x12s\\n\\x0fperformative_mt\\x18\\x07 \\x01(\\x0b\\x32X.aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.Performative_Mt_PerformativeH\\x00\\x12q\\n\\x0eperformative_o\\x18\\x08 \\x01(\\x0b\\x32W.aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.Performative_O_PerformativeH\\x00\\x12u\\n\\x10performative_pct\\x18\\t \\x01(\\x0b\\x32Y.aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.Performative_Pct_PerformativeH\\x00\\x12u\\n\\x10performative_pmt\\x18\\n \\x01(\\x0b\\x32Y.aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.Performative_Pmt_PerformativeH\\x00\\x12s\\n\\x0fperformative_pt\\x18\\x0b \\x01(\\x0b\\x32X.aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.Performative_Pt_PerformativeH\\x00\\x1a\\xb2\\x02\\n\\tDataModel\\x12\\x13\\n\\x0b\\x62ytes_field\\x18\\x01 \\x01(\\x0c\\x12\\x11\\n\\tint_field\\x18\\x02 \\x01(\\x03\\x12\\x13\\n\\x0b\\x66loat_field\\x18\\x03 \\x01(\\x02\\x12\\x12\\n\\nbool_field\\x18\\x04 \\x01(\\x08\\x12\\x11\\n\\tstr_field\\x18\\x05 \\x01(\\t\\x12\\x11\\n\\tset_field\\x18\\x06 \\x03(\\x03\\x12\\x12\\n\\nlist_field\\x18\\x07 \\x03(\\t\\x12h\\n\\ndict_field\\x18\\x08 \\x03(\\x0b\\x32T.aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.DataModel.DictFieldEntry\\x1a\\x30\\n\\x0e\\x44ictFieldEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\x03\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\x08:\\x02\\x38\\x01\\x1a\\xb4\\x02\\n\\nDataModel1\\x12\\x13\\n\\x0b\\x62ytes_field\\x18\\x01 \\x01(\\x0c\\x12\\x11\\n\\tint_field\\x18\\x02 \\x01(\\x03\\x12\\x13\\n\\x0b\\x66loat_field\\x18\\x03 \\x01(\\x02\\x12\\x12\\n\\nbool_field\\x18\\x04 \\x01(\\x08\\x12\\x11\\n\\tstr_field\\x18\\x05 \\x01(\\t\\x12\\x11\\n\\tset_field\\x18\\x06 \\x03(\\x03\\x12\\x12\\n\\nlist_field\\x18\\x07 \\x03(\\t\\x12i\\n\\ndict_field\\x18\\x08 \\x03(\\x0b\\x32U.aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.DataModel1.DictFieldEntry\\x1a\\x30\\n\\x0e\\x44ictFieldEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\x03\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\x08:\\x02\\x38\\x01\\x1a\\xb4\\x02\\n\\nDataModel2\\x12\\x13\\n\\x0b\\x62ytes_field\\x18\\x01 \\x01(\\x0c\\x12\\x11\\n\\tint_field\\x18\\x02 \\x01(\\x03\\x12\\x13\\n\\x0b\\x66loat_field\\x18\\x03 \\x01(\\x02\\x12\\x12\\n\\nbool_field\\x18\\x04 \\x01(\\x08\\x12\\x11\\n\\tstr_field\\x18\\x05 \\x01(\\t\\x12\\x11\\n\\tset_field\\x18\\x06 \\x03(\\x03\\x12\\x12\\n\\nlist_field\\x18\\x07 \\x03(\\t\\x12i\\n\\ndict_field\\x18\\x08 \\x03(\\x0b\\x32U.aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.DataModel2.DictFieldEntry\\x1a\\x30\\n\\x0e\\x44ictFieldEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\x03\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\x08:\\x02\\x38\\x01\\x1a\\xb4\\x02\\n\\nDataModel3\\x12\\x13\\n\\x0b\\x62ytes_field\\x18\\x01 \\x01(\\x0c\\x12\\x11\\n\\tint_field\\x18\\x02 \\x01(\\x03\\x12\\x13\\n\\x0b\\x66loat_field\\x18\\x03 \\x01(\\x02\\x12\\x12\\n\\nbool_field\\x18\\x04 \\x01(\\x08\\x12\\x11\\n\\tstr_field\\x18\\x05 \\x01(\\t\\x12\\x11\\n\\tset_field\\x18\\x06 \\x03(\\x03\\x12\\x12\\n\\nlist_field\\x18\\x07 \\x03(\\t\\x12i\\n\\ndict_field\\x18\\x08 \\x03(\\x0b\\x32U.aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.DataModel3.DictFieldEntry\\x1a\\x30\\n\\x0e\\x44ictFieldEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\x03\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\x08:\\x02\\x38\\x01\\x1a\\xb4\\x02\\n\\nDataModel4\\x12\\x13\\n\\x0b\\x62ytes_field\\x18\\x01 \\x01(\\x0c\\x12\\x11\\n\\tint_field\\x18\\x02 \\x01(\\x03\\x12\\x13\\n\\x0b\\x66loat_field\\x18\\x03 \\x01(\\x02\\x12\\x12\\n\\nbool_field\\x18\\x04 \\x01(\\x08\\x12\\x11\\n\\tstr_field\\x18\\x05 \\x01(\\t\\x12\\x11\\n\\tset_field\\x18\\x06 \\x03(\\x03\\x12\\x12\\n\\nlist_field\\x18\\x07 \\x03(\\t\\x12i\\n\\ndict_field\\x18\\x08 \\x03(\\x0b\\x32U.aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.DataModel4.DictFieldEntry\\x1a\\x30\\n\\x0e\\x44ictFieldEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\x03\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\x08:\\x02\\x38\\x01\\x1ay\\n\\x1cPerformative_Ct_Performative\\x12Y\\n\\ncontent_ct\\x18\\x01 \\x01(\\x0b\\x32\\x45.aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.DataModel\\x1a\\x8c\\x01\\n\\x1cPerformative_Pt_Performative\\x12\\x15\\n\\rcontent_bytes\\x18\\x01 \\x01(\\x0c\\x12\\x13\\n\\x0b\\x63ontent_int\\x18\\x02 \\x01(\\x03\\x12\\x15\\n\\rcontent_float\\x18\\x03 \\x01(\\x02\\x12\\x14\\n\\x0c\\x63ontent_bool\\x18\\x04 \\x01(\\x08\\x12\\x13\\n\\x0b\\x63ontent_str\\x18\\x05 \\x01(\\t\\x1a\\xa8\\x02\\n\\x1dPerformative_Pct_Performative\\x12\\x19\\n\\x11\\x63ontent_set_bytes\\x18\\x01 \\x03(\\x0c\\x12\\x17\\n\\x0f\\x63ontent_set_int\\x18\\x02 \\x03(\\x03\\x12\\x19\\n\\x11\\x63ontent_set_float\\x18\\x03 \\x03(\\x02\\x12\\x18\\n\\x10\\x63ontent_set_bool\\x18\\x04 \\x03(\\x08\\x12\\x17\\n\\x0f\\x63ontent_set_str\\x18\\x05 \\x03(\\t\\x12\\x1a\\n\\x12\\x63ontent_list_bytes\\x18\\x06 \\x03(\\x0c\\x12\\x18\\n\\x10\\x63ontent_list_int\\x18\\x07 \\x03(\\x03\\x12\\x1a\\n\\x12\\x63ontent_list_float\\x18\\x08 \\x03(\\x02\\x12\\x19\\n\\x11\\x63ontent_list_bool\\x18\\t \\x03(\\x08\\x12\\x18\\n\\x10\\x63ontent_list_str\\x18\\n \\x03(\\t\\x1a\\xc0\\x18\\n\\x1dPerformative_Pmt_Performative\\x12\\x92\\x01\\n\\x16\\x63ontent_dict_int_bytes\\x18\\x01 \\x03(\\x0b\\x32r.aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.Performative_Pmt_Performative.ContentDictIntBytesEntry\\x12\\x8e\\x01\\n\\x14\\x63ontent_dict_int_int\\x18\\x02 \\x03(\\x0b\\x32p.aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.Performative_Pmt_Performative.ContentDictIntIntEntry\\x12\\x92\\x01\\n\\x16\\x63ontent_dict_int_float\\x18\\x03 \\x03(\\x0b\\x32r.aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.Performative_Pmt_Performative.ContentDictIntFloatEntry\\x12\\x90\\x01\\n\\x15\\x63ontent_dict_int_bool\\x18\\x04 \\x03(\\x0b\\x32q.aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.Performative_Pmt_Performative.ContentDictIntBoolEntry\\x12\\x8e\\x01\\n\\x14\\x63ontent_dict_int_str\\x18\\x05 \\x03(\\x0b\\x32p.aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.Performative_Pmt_Performative.ContentDictIntStrEntry\\x12\\x94\\x01\\n\\x17\\x63ontent_dict_bool_bytes\\x18\\x06 \\x03(\\x0b\\x32s.aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.Performative_Pmt_Performative.ContentDictBoolBytesEntry\\x12\\x90\\x01\\n\\x15\\x63ontent_dict_bool_int\\x18\\x07 \\x03(\\x0b\\x32q.aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.Performative_Pmt_Performative.ContentDictBoolIntEntry\\x12\\x94\\x01\\n\\x17\\x63ontent_dict_bool_float\\x18\\x08 \\x03(\\x0b\\x32s.aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.Performative_Pmt_Performative.ContentDictBoolFloatEntry\\x12\\x92\\x01\\n\\x16\\x63ontent_dict_bool_bool\\x18\\t \\x03(\\x0b\\x32r.aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.Performative_Pmt_Performative.ContentDictBoolBoolEntry\\x12\\x90\\x01\\n\\x15\\x63ontent_dict_bool_str\\x18\\n \\x03(\\x0b\\x32q.aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.Performative_Pmt_Performative.ContentDictBoolStrEntry\\x12\\x92\\x01\\n\\x16\\x63ontent_dict_str_bytes\\x18\\x0b \\x03(\\x0b\\x32r.aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.Performative_Pmt_Performative.ContentDictStrBytesEntry\\x12\\x8e\\x01\\n\\x14\\x63ontent_dict_str_int\\x18\\x0c \\x03(\\x0b\\x32p.aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.Performative_Pmt_Performative.ContentDictStrIntEntry\\x12\\x92\\x01\\n\\x16\\x63ontent_dict_str_float\\x18\\r \\x03(\\x0b\\x32r.aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.Performative_Pmt_Performative.ContentDictStrFloatEntry\\x12\\x90\\x01\\n\\x15\\x63ontent_dict_str_bool\\x18\\x0e \\x03(\\x0b\\x32q.aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.Performative_Pmt_Performative.ContentDictStrBoolEntry\\x12\\x8e\\x01\\n\\x14\\x63ontent_dict_str_str\\x18\\x0f \\x03(\\x0b\\x32p.aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.Performative_Pmt_Performative.ContentDictStrStrEntry\\x1a:\\n\\x18\\x43ontentDictIntBytesEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\x03\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\x0c:\\x02\\x38\\x01\\x1a\\x38\\n\\x16\\x43ontentDictIntIntEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\x03\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\x03:\\x02\\x38\\x01\\x1a:\\n\\x18\\x43ontentDictIntFloatEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\x03\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\x02:\\x02\\x38\\x01\\x1a\\x39\\n\\x17\\x43ontentDictIntBoolEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\x03\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\x08:\\x02\\x38\\x01\\x1a\\x38\\n\\x16\\x43ontentDictIntStrEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\x03\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\t:\\x02\\x38\\x01\\x1a;\\n\\x19\\x43ontentDictBoolBytesEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\x08\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\x0c:\\x02\\x38\\x01\\x1a\\x39\\n\\x17\\x43ontentDictBoolIntEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\x08\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\x03:\\x02\\x38\\x01\\x1a;\\n\\x19\\x43ontentDictBoolFloatEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\x08\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\x02:\\x02\\x38\\x01\\x1a:\\n\\x18\\x43ontentDictBoolBoolEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\x08\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\x08:\\x02\\x38\\x01\\x1a\\x39\\n\\x17\\x43ontentDictBoolStrEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\x08\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\t:\\x02\\x38\\x01\\x1a:\\n\\x18\\x43ontentDictStrBytesEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\t\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\x0c:\\x02\\x38\\x01\\x1a\\x38\\n\\x16\\x43ontentDictStrIntEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\t\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\x03:\\x02\\x38\\x01\\x1a:\\n\\x18\\x43ontentDictStrFloatEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\t\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\x02:\\x02\\x38\\x01\\x1a\\x39\\n\\x17\\x43ontentDictStrBoolEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\t\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\x08:\\x02\\x38\\x01\\x1a\\x38\\n\\x16\\x43ontentDictStrStrEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\t\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\t:\\x02\\x38\\x01\\x1a\\xdd\\x16\\n\\x1cPerformative_Mt_Performative\\x12o\\n\\x1f\\x63ontent_union_1_type_DataModel1\\x18\\x01 \\x01(\\x0b\\x32\\x46.aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.DataModel1\\x12.\\n&content_union_1_type_DataModel1_is_set\\x18\\x02 \\x01(\\x08\\x12\\\"\\n\\x1a\\x63ontent_union_1_type_bytes\\x18\\x03 \\x01(\\x0c\\x12)\\n!content_union_1_type_bytes_is_set\\x18\\x04 \\x01(\\x08\\x12 \\n\\x18\\x63ontent_union_1_type_int\\x18\\x05 \\x01(\\x03\\x12'\\n\\x1f\\x63ontent_union_1_type_int_is_set\\x18\\x06 \\x01(\\x08\\x12\\\"\\n\\x1a\\x63ontent_union_1_type_float\\x18\\x07 \\x01(\\x02\\x12)\\n!content_union_1_type_float_is_set\\x18\\x08 \\x01(\\x08\\x12!\\n\\x19\\x63ontent_union_1_type_bool\\x18\\t \\x01(\\x08\\x12(\\n content_union_1_type_bool_is_set\\x18\\n \\x01(\\x08\\x12 \\n\\x18\\x63ontent_union_1_type_str\\x18\\x0b \\x01(\\t\\x12'\\n\\x1f\\x63ontent_union_1_type_str_is_set\\x18\\x0c \\x01(\\x08\\x12'\\n\\x1f\\x63ontent_union_1_type_set_of_int\\x18\\r \\x03(\\x03\\x12.\\n&content_union_1_type_set_of_int_is_set\\x18\\x0e \\x01(\\x08\\x12)\\n!content_union_1_type_list_of_bool\\x18\\x0f \\x03(\\x08\\x12\\x30\\n(content_union_1_type_list_of_bool_is_set\\x18\\x10 \\x01(\\x08\\x12\\xa9\\x01\\n$content_union_1_type_dict_of_str_int\\x18\\x11 \\x03(\\x0b\\x32{.aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.Performative_Mt_Performative.ContentUnion1TypeDictOfStrIntEntry\\x12\\x33\\n+content_union_1_type_dict_of_str_int_is_set\\x18\\x12 \\x01(\\x08\\x12)\\n!content_union_2_type_set_of_bytes\\x18\\x13 \\x03(\\x0c\\x12\\x30\\n(content_union_2_type_set_of_bytes_is_set\\x18\\x14 \\x01(\\x08\\x12'\\n\\x1f\\x63ontent_union_2_type_set_of_int\\x18\\x15 \\x03(\\x03\\x12.\\n&content_union_2_type_set_of_int_is_set\\x18\\x16 \\x01(\\x08\\x12'\\n\\x1f\\x63ontent_union_2_type_set_of_str\\x18\\x17 \\x03(\\t\\x12.\\n&content_union_2_type_set_of_str_is_set\\x18\\x18 \\x01(\\x08\\x12*\\n\\\"content_union_2_type_list_of_float\\x18\\x19 \\x03(\\x02\\x12\\x31\\n)content_union_2_type_list_of_float_is_set\\x18\\x1a \\x01(\\x08\\x12)\\n!content_union_2_type_list_of_bool\\x18\\x1b \\x03(\\x08\\x12\\x30\\n(content_union_2_type_list_of_bool_is_set\\x18\\x1c \\x01(\\x08\\x12*\\n\\\"content_union_2_type_list_of_bytes\\x18\\x1d \\x03(\\x0c\\x12\\x31\\n)content_union_2_type_list_of_bytes_is_set\\x18\\x1e \\x01(\\x08\\x12\\xa9\\x01\\n$content_union_2_type_dict_of_str_int\\x18\\x1f \\x03(\\x0b\\x32{.aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.Performative_Mt_Performative.ContentUnion2TypeDictOfStrIntEntry\\x12\\x33\\n+content_union_2_type_dict_of_str_int_is_set\\x18  \\x01(\\x08\\x12\\xad\\x01\\n&content_union_2_type_dict_of_int_float\\x18! \\x03(\\x0b\\x32}.aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.Performative_Mt_Performative.ContentUnion2TypeDictOfIntFloatEntry\\x12\\x35\\n-content_union_2_type_dict_of_int_float_is_set\\x18\\\" \\x01(\\x08\\x12\\xaf\\x01\\n'content_union_2_type_dict_of_bool_bytes\\x18# \\x03(\\x0b\\x32~.aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.Performative_Mt_Performative.ContentUnion2TypeDictOfBoolBytesEntry\\x12\\x36\\n.content_union_2_type_dict_of_bool_bytes_is_set\\x18$ \\x01(\\x08\\x12 \\n\\x18\\x63ontent_union_2_type_int\\x18% \\x01(\\x03\\x12'\\n\\x1f\\x63ontent_union_2_type_int_is_set\\x18& \\x01(\\x08\\x12o\\n\\x1f\\x63ontent_union_3_type_DataModel2\\x18' \\x01(\\x0b\\x32\\x46.aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.DataModel2\\x12.\\n&content_union_3_type_DataModel2_is_set\\x18( \\x01(\\x08\\x12o\\n\\x1f\\x63ontent_union_3_type_DataModel3\\x18) \\x01(\\x0b\\x32\\x46.aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.DataModel3\\x12.\\n&content_union_3_type_DataModel3_is_set\\x18* \\x01(\\x08\\x1a\\x44\\n\\\"ContentUnion1TypeDictOfStrIntEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\t\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\x03:\\x02\\x38\\x01\\x1a\\x44\\n\\\"ContentUnion2TypeDictOfStrIntEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\t\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\x03:\\x02\\x38\\x01\\x1a\\x46\\n$ContentUnion2TypeDictOfIntFloatEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\x03\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\x02:\\x02\\x38\\x01\\x1aG\\n%ContentUnion2TypeDictOfBoolBytesEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\x08\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\x0c:\\x02\\x38\\x01\\x1a\\xc3\\x04\\n\\x1bPerformative_O_Performative\\x12\\\\\\n\\x0c\\x63ontent_o_ct\\x18\\x01 \\x01(\\x0b\\x32\\x46.aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.DataModel4\\x12\\x1b\\n\\x13\\x63ontent_o_ct_is_set\\x18\\x02 \\x01(\\x08\\x12\\x16\\n\\x0e\\x63ontent_o_bool\\x18\\x03 \\x01(\\x08\\x12\\x1d\\n\\x15\\x63ontent_o_bool_is_set\\x18\\x04 \\x01(\\x08\\x12\\x19\\n\\x11\\x63ontent_o_set_int\\x18\\x05 \\x03(\\x03\\x12 \\n\\x18\\x63ontent_o_set_int_is_set\\x18\\x06 \\x01(\\x08\\x12\\x1c\\n\\x14\\x63ontent_o_list_bytes\\x18\\x07 \\x03(\\x0c\\x12#\\n\\x1b\\x63ontent_o_list_bytes_is_set\\x18\\x08 \\x01(\\x08\\x12\\x8f\\x01\\n\\x16\\x63ontent_o_dict_str_int\\x18\\t \\x03(\\x0b\\x32o.aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.Performative_O_Performative.ContentODictStrIntEntry\\x12%\\n\\x1d\\x63ontent_o_dict_str_int_is_set\\x18\\n \\x01(\\x08\\x1a\\x39\\n\\x17\\x43ontentODictStrIntEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\t\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\x03:\\x02\\x38\\x01\\x1a*\\n(Performative_Empty_Contents_PerformativeB\\x0e\\n\\x0cperformativeb\\x06proto3\"\n)\n\n\n_TPROTOCOLMESSAGE = DESCRIPTOR.message_types_by_name[\"TProtocolMessage\"]\n_TPROTOCOLMESSAGE_DATAMODEL = _TPROTOCOLMESSAGE.nested_types_by_name[\"DataModel\"]\n_TPROTOCOLMESSAGE_DATAMODEL_DICTFIELDENTRY = (\n    _TPROTOCOLMESSAGE_DATAMODEL.nested_types_by_name[\"DictFieldEntry\"]\n)\n_TPROTOCOLMESSAGE_DATAMODEL1 = _TPROTOCOLMESSAGE.nested_types_by_name[\"DataModel1\"]\n_TPROTOCOLMESSAGE_DATAMODEL1_DICTFIELDENTRY = (\n    _TPROTOCOLMESSAGE_DATAMODEL1.nested_types_by_name[\"DictFieldEntry\"]\n)\n_TPROTOCOLMESSAGE_DATAMODEL2 = _TPROTOCOLMESSAGE.nested_types_by_name[\"DataModel2\"]\n_TPROTOCOLMESSAGE_DATAMODEL2_DICTFIELDENTRY = (\n    _TPROTOCOLMESSAGE_DATAMODEL2.nested_types_by_name[\"DictFieldEntry\"]\n)\n_TPROTOCOLMESSAGE_DATAMODEL3 = _TPROTOCOLMESSAGE.nested_types_by_name[\"DataModel3\"]\n_TPROTOCOLMESSAGE_DATAMODEL3_DICTFIELDENTRY = (\n    _TPROTOCOLMESSAGE_DATAMODEL3.nested_types_by_name[\"DictFieldEntry\"]\n)\n_TPROTOCOLMESSAGE_DATAMODEL4 = _TPROTOCOLMESSAGE.nested_types_by_name[\"DataModel4\"]\n_TPROTOCOLMESSAGE_DATAMODEL4_DICTFIELDENTRY = (\n    _TPROTOCOLMESSAGE_DATAMODEL4.nested_types_by_name[\"DictFieldEntry\"]\n)\n_TPROTOCOLMESSAGE_PERFORMATIVE_CT_PERFORMATIVE = _TPROTOCOLMESSAGE.nested_types_by_name[\n    \"Performative_Ct_Performative\"\n]\n_TPROTOCOLMESSAGE_PERFORMATIVE_PT_PERFORMATIVE = _TPROTOCOLMESSAGE.nested_types_by_name[\n    \"Performative_Pt_Performative\"\n]\n_TPROTOCOLMESSAGE_PERFORMATIVE_PCT_PERFORMATIVE = (\n    _TPROTOCOLMESSAGE.nested_types_by_name[\"Performative_Pct_Performative\"]\n)\n_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE = (\n    _TPROTOCOLMESSAGE.nested_types_by_name[\"Performative_Pmt_Performative\"]\n)\n_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTBYTESENTRY = (\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE.nested_types_by_name[\n        \"ContentDictIntBytesEntry\"\n    ]\n)\n_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTINTENTRY = (\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE.nested_types_by_name[\n        \"ContentDictIntIntEntry\"\n    ]\n)\n_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTFLOATENTRY = (\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE.nested_types_by_name[\n        \"ContentDictIntFloatEntry\"\n    ]\n)\n_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTBOOLENTRY = (\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE.nested_types_by_name[\n        \"ContentDictIntBoolEntry\"\n    ]\n)\n_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTSTRENTRY = (\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE.nested_types_by_name[\n        \"ContentDictIntStrEntry\"\n    ]\n)\n_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLBYTESENTRY = (\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE.nested_types_by_name[\n        \"ContentDictBoolBytesEntry\"\n    ]\n)\n_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLINTENTRY = (\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE.nested_types_by_name[\n        \"ContentDictBoolIntEntry\"\n    ]\n)\n_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLFLOATENTRY = (\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE.nested_types_by_name[\n        \"ContentDictBoolFloatEntry\"\n    ]\n)\n_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLBOOLENTRY = (\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE.nested_types_by_name[\n        \"ContentDictBoolBoolEntry\"\n    ]\n)\n_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLSTRENTRY = (\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE.nested_types_by_name[\n        \"ContentDictBoolStrEntry\"\n    ]\n)\n_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRBYTESENTRY = (\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE.nested_types_by_name[\n        \"ContentDictStrBytesEntry\"\n    ]\n)\n_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRINTENTRY = (\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE.nested_types_by_name[\n        \"ContentDictStrIntEntry\"\n    ]\n)\n_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRFLOATENTRY = (\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE.nested_types_by_name[\n        \"ContentDictStrFloatEntry\"\n    ]\n)\n_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRBOOLENTRY = (\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE.nested_types_by_name[\n        \"ContentDictStrBoolEntry\"\n    ]\n)\n_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRSTRENTRY = (\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE.nested_types_by_name[\n        \"ContentDictStrStrEntry\"\n    ]\n)\n_TPROTOCOLMESSAGE_PERFORMATIVE_MT_PERFORMATIVE = _TPROTOCOLMESSAGE.nested_types_by_name[\n    \"Performative_Mt_Performative\"\n]\n_TPROTOCOLMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION1TYPEDICTOFSTRINTENTRY = (\n    _TPROTOCOLMESSAGE_PERFORMATIVE_MT_PERFORMATIVE.nested_types_by_name[\n        \"ContentUnion1TypeDictOfStrIntEntry\"\n    ]\n)\n_TPROTOCOLMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFSTRINTENTRY = (\n    _TPROTOCOLMESSAGE_PERFORMATIVE_MT_PERFORMATIVE.nested_types_by_name[\n        \"ContentUnion2TypeDictOfStrIntEntry\"\n    ]\n)\n_TPROTOCOLMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFINTFLOATENTRY = (\n    _TPROTOCOLMESSAGE_PERFORMATIVE_MT_PERFORMATIVE.nested_types_by_name[\n        \"ContentUnion2TypeDictOfIntFloatEntry\"\n    ]\n)\n_TPROTOCOLMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFBOOLBYTESENTRY = (\n    _TPROTOCOLMESSAGE_PERFORMATIVE_MT_PERFORMATIVE.nested_types_by_name[\n        \"ContentUnion2TypeDictOfBoolBytesEntry\"\n    ]\n)\n_TPROTOCOLMESSAGE_PERFORMATIVE_O_PERFORMATIVE = _TPROTOCOLMESSAGE.nested_types_by_name[\n    \"Performative_O_Performative\"\n]\n_TPROTOCOLMESSAGE_PERFORMATIVE_O_PERFORMATIVE_CONTENTODICTSTRINTENTRY = (\n    _TPROTOCOLMESSAGE_PERFORMATIVE_O_PERFORMATIVE.nested_types_by_name[\n        \"ContentODictStrIntEntry\"\n    ]\n)\n_TPROTOCOLMESSAGE_PERFORMATIVE_EMPTY_CONTENTS_PERFORMATIVE = (\n    _TPROTOCOLMESSAGE.nested_types_by_name[\"Performative_Empty_Contents_Performative\"]\n)\nTProtocolMessage = _reflection.GeneratedProtocolMessageType(\n    \"TProtocolMessage\",\n    (_message.Message,),\n    {\n        \"DataModel\": _reflection.GeneratedProtocolMessageType(\n            \"DataModel\",\n            (_message.Message,),\n            {\n                \"DictFieldEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"DictFieldEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _TPROTOCOLMESSAGE_DATAMODEL_DICTFIELDENTRY,\n                        \"__module__\": \"t_protocol_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.DataModel.DictFieldEntry)\n                    },\n                ),\n                \"DESCRIPTOR\": _TPROTOCOLMESSAGE_DATAMODEL,\n                \"__module__\": \"t_protocol_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.DataModel)\n            },\n        ),\n        \"DataModel1\": _reflection.GeneratedProtocolMessageType(\n            \"DataModel1\",\n            (_message.Message,),\n            {\n                \"DictFieldEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"DictFieldEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _TPROTOCOLMESSAGE_DATAMODEL1_DICTFIELDENTRY,\n                        \"__module__\": \"t_protocol_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.DataModel1.DictFieldEntry)\n                    },\n                ),\n                \"DESCRIPTOR\": _TPROTOCOLMESSAGE_DATAMODEL1,\n                \"__module__\": \"t_protocol_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.DataModel1)\n            },\n        ),\n        \"DataModel2\": _reflection.GeneratedProtocolMessageType(\n            \"DataModel2\",\n            (_message.Message,),\n            {\n                \"DictFieldEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"DictFieldEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _TPROTOCOLMESSAGE_DATAMODEL2_DICTFIELDENTRY,\n                        \"__module__\": \"t_protocol_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.DataModel2.DictFieldEntry)\n                    },\n                ),\n                \"DESCRIPTOR\": _TPROTOCOLMESSAGE_DATAMODEL2,\n                \"__module__\": \"t_protocol_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.DataModel2)\n            },\n        ),\n        \"DataModel3\": _reflection.GeneratedProtocolMessageType(\n            \"DataModel3\",\n            (_message.Message,),\n            {\n                \"DictFieldEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"DictFieldEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _TPROTOCOLMESSAGE_DATAMODEL3_DICTFIELDENTRY,\n                        \"__module__\": \"t_protocol_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.DataModel3.DictFieldEntry)\n                    },\n                ),\n                \"DESCRIPTOR\": _TPROTOCOLMESSAGE_DATAMODEL3,\n                \"__module__\": \"t_protocol_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.DataModel3)\n            },\n        ),\n        \"DataModel4\": _reflection.GeneratedProtocolMessageType(\n            \"DataModel4\",\n            (_message.Message,),\n            {\n                \"DictFieldEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"DictFieldEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _TPROTOCOLMESSAGE_DATAMODEL4_DICTFIELDENTRY,\n                        \"__module__\": \"t_protocol_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.DataModel4.DictFieldEntry)\n                    },\n                ),\n                \"DESCRIPTOR\": _TPROTOCOLMESSAGE_DATAMODEL4,\n                \"__module__\": \"t_protocol_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.DataModel4)\n            },\n        ),\n        \"Performative_Ct_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Performative_Ct_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _TPROTOCOLMESSAGE_PERFORMATIVE_CT_PERFORMATIVE,\n                \"__module__\": \"t_protocol_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.Performative_Ct_Performative)\n            },\n        ),\n        \"Performative_Pt_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Performative_Pt_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _TPROTOCOLMESSAGE_PERFORMATIVE_PT_PERFORMATIVE,\n                \"__module__\": \"t_protocol_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.Performative_Pt_Performative)\n            },\n        ),\n        \"Performative_Pct_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Performative_Pct_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _TPROTOCOLMESSAGE_PERFORMATIVE_PCT_PERFORMATIVE,\n                \"__module__\": \"t_protocol_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.Performative_Pct_Performative)\n            },\n        ),\n        \"Performative_Pmt_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Performative_Pmt_Performative\",\n            (_message.Message,),\n            {\n                \"ContentDictIntBytesEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"ContentDictIntBytesEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTBYTESENTRY,\n                        \"__module__\": \"t_protocol_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.Performative_Pmt_Performative.ContentDictIntBytesEntry)\n                    },\n                ),\n                \"ContentDictIntIntEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"ContentDictIntIntEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTINTENTRY,\n                        \"__module__\": \"t_protocol_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.Performative_Pmt_Performative.ContentDictIntIntEntry)\n                    },\n                ),\n                \"ContentDictIntFloatEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"ContentDictIntFloatEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTFLOATENTRY,\n                        \"__module__\": \"t_protocol_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.Performative_Pmt_Performative.ContentDictIntFloatEntry)\n                    },\n                ),\n                \"ContentDictIntBoolEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"ContentDictIntBoolEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTBOOLENTRY,\n                        \"__module__\": \"t_protocol_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.Performative_Pmt_Performative.ContentDictIntBoolEntry)\n                    },\n                ),\n                \"ContentDictIntStrEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"ContentDictIntStrEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTSTRENTRY,\n                        \"__module__\": \"t_protocol_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.Performative_Pmt_Performative.ContentDictIntStrEntry)\n                    },\n                ),\n                \"ContentDictBoolBytesEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"ContentDictBoolBytesEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLBYTESENTRY,\n                        \"__module__\": \"t_protocol_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.Performative_Pmt_Performative.ContentDictBoolBytesEntry)\n                    },\n                ),\n                \"ContentDictBoolIntEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"ContentDictBoolIntEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLINTENTRY,\n                        \"__module__\": \"t_protocol_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.Performative_Pmt_Performative.ContentDictBoolIntEntry)\n                    },\n                ),\n                \"ContentDictBoolFloatEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"ContentDictBoolFloatEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLFLOATENTRY,\n                        \"__module__\": \"t_protocol_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.Performative_Pmt_Performative.ContentDictBoolFloatEntry)\n                    },\n                ),\n                \"ContentDictBoolBoolEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"ContentDictBoolBoolEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLBOOLENTRY,\n                        \"__module__\": \"t_protocol_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.Performative_Pmt_Performative.ContentDictBoolBoolEntry)\n                    },\n                ),\n                \"ContentDictBoolStrEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"ContentDictBoolStrEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLSTRENTRY,\n                        \"__module__\": \"t_protocol_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.Performative_Pmt_Performative.ContentDictBoolStrEntry)\n                    },\n                ),\n                \"ContentDictStrBytesEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"ContentDictStrBytesEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRBYTESENTRY,\n                        \"__module__\": \"t_protocol_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.Performative_Pmt_Performative.ContentDictStrBytesEntry)\n                    },\n                ),\n                \"ContentDictStrIntEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"ContentDictStrIntEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRINTENTRY,\n                        \"__module__\": \"t_protocol_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.Performative_Pmt_Performative.ContentDictStrIntEntry)\n                    },\n                ),\n                \"ContentDictStrFloatEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"ContentDictStrFloatEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRFLOATENTRY,\n                        \"__module__\": \"t_protocol_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.Performative_Pmt_Performative.ContentDictStrFloatEntry)\n                    },\n                ),\n                \"ContentDictStrBoolEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"ContentDictStrBoolEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRBOOLENTRY,\n                        \"__module__\": \"t_protocol_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.Performative_Pmt_Performative.ContentDictStrBoolEntry)\n                    },\n                ),\n                \"ContentDictStrStrEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"ContentDictStrStrEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRSTRENTRY,\n                        \"__module__\": \"t_protocol_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.Performative_Pmt_Performative.ContentDictStrStrEntry)\n                    },\n                ),\n                \"DESCRIPTOR\": _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE,\n                \"__module__\": \"t_protocol_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.Performative_Pmt_Performative)\n            },\n        ),\n        \"Performative_Mt_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Performative_Mt_Performative\",\n            (_message.Message,),\n            {\n                \"ContentUnion1TypeDictOfStrIntEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"ContentUnion1TypeDictOfStrIntEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _TPROTOCOLMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION1TYPEDICTOFSTRINTENTRY,\n                        \"__module__\": \"t_protocol_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.Performative_Mt_Performative.ContentUnion1TypeDictOfStrIntEntry)\n                    },\n                ),\n                \"ContentUnion2TypeDictOfStrIntEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"ContentUnion2TypeDictOfStrIntEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _TPROTOCOLMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFSTRINTENTRY,\n                        \"__module__\": \"t_protocol_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.Performative_Mt_Performative.ContentUnion2TypeDictOfStrIntEntry)\n                    },\n                ),\n                \"ContentUnion2TypeDictOfIntFloatEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"ContentUnion2TypeDictOfIntFloatEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _TPROTOCOLMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFINTFLOATENTRY,\n                        \"__module__\": \"t_protocol_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.Performative_Mt_Performative.ContentUnion2TypeDictOfIntFloatEntry)\n                    },\n                ),\n                \"ContentUnion2TypeDictOfBoolBytesEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"ContentUnion2TypeDictOfBoolBytesEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _TPROTOCOLMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFBOOLBYTESENTRY,\n                        \"__module__\": \"t_protocol_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.Performative_Mt_Performative.ContentUnion2TypeDictOfBoolBytesEntry)\n                    },\n                ),\n                \"DESCRIPTOR\": _TPROTOCOLMESSAGE_PERFORMATIVE_MT_PERFORMATIVE,\n                \"__module__\": \"t_protocol_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.Performative_Mt_Performative)\n            },\n        ),\n        \"Performative_O_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Performative_O_Performative\",\n            (_message.Message,),\n            {\n                \"ContentODictStrIntEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"ContentODictStrIntEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _TPROTOCOLMESSAGE_PERFORMATIVE_O_PERFORMATIVE_CONTENTODICTSTRINTENTRY,\n                        \"__module__\": \"t_protocol_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.Performative_O_Performative.ContentODictStrIntEntry)\n                    },\n                ),\n                \"DESCRIPTOR\": _TPROTOCOLMESSAGE_PERFORMATIVE_O_PERFORMATIVE,\n                \"__module__\": \"t_protocol_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.Performative_O_Performative)\n            },\n        ),\n        \"Performative_Empty_Contents_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Performative_Empty_Contents_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _TPROTOCOLMESSAGE_PERFORMATIVE_EMPTY_CONTENTS_PERFORMATIVE,\n                \"__module__\": \"t_protocol_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage.Performative_Empty_Contents_Performative)\n            },\n        ),\n        \"DESCRIPTOR\": _TPROTOCOLMESSAGE,\n        \"__module__\": \"t_protocol_pb2\"\n        # @@protoc_insertion_point(class_scope:aea.some_author.some_protocol_name.v1_0_0.TProtocolMessage)\n    },\n)\n_sym_db.RegisterMessage(TProtocolMessage)\n_sym_db.RegisterMessage(TProtocolMessage.DataModel)\n_sym_db.RegisterMessage(TProtocolMessage.DataModel.DictFieldEntry)\n_sym_db.RegisterMessage(TProtocolMessage.DataModel1)\n_sym_db.RegisterMessage(TProtocolMessage.DataModel1.DictFieldEntry)\n_sym_db.RegisterMessage(TProtocolMessage.DataModel2)\n_sym_db.RegisterMessage(TProtocolMessage.DataModel2.DictFieldEntry)\n_sym_db.RegisterMessage(TProtocolMessage.DataModel3)\n_sym_db.RegisterMessage(TProtocolMessage.DataModel3.DictFieldEntry)\n_sym_db.RegisterMessage(TProtocolMessage.DataModel4)\n_sym_db.RegisterMessage(TProtocolMessage.DataModel4.DictFieldEntry)\n_sym_db.RegisterMessage(TProtocolMessage.Performative_Ct_Performative)\n_sym_db.RegisterMessage(TProtocolMessage.Performative_Pt_Performative)\n_sym_db.RegisterMessage(TProtocolMessage.Performative_Pct_Performative)\n_sym_db.RegisterMessage(TProtocolMessage.Performative_Pmt_Performative)\n_sym_db.RegisterMessage(\n    TProtocolMessage.Performative_Pmt_Performative.ContentDictIntBytesEntry\n)\n_sym_db.RegisterMessage(\n    TProtocolMessage.Performative_Pmt_Performative.ContentDictIntIntEntry\n)\n_sym_db.RegisterMessage(\n    TProtocolMessage.Performative_Pmt_Performative.ContentDictIntFloatEntry\n)\n_sym_db.RegisterMessage(\n    TProtocolMessage.Performative_Pmt_Performative.ContentDictIntBoolEntry\n)\n_sym_db.RegisterMessage(\n    TProtocolMessage.Performative_Pmt_Performative.ContentDictIntStrEntry\n)\n_sym_db.RegisterMessage(\n    TProtocolMessage.Performative_Pmt_Performative.ContentDictBoolBytesEntry\n)\n_sym_db.RegisterMessage(\n    TProtocolMessage.Performative_Pmt_Performative.ContentDictBoolIntEntry\n)\n_sym_db.RegisterMessage(\n    TProtocolMessage.Performative_Pmt_Performative.ContentDictBoolFloatEntry\n)\n_sym_db.RegisterMessage(\n    TProtocolMessage.Performative_Pmt_Performative.ContentDictBoolBoolEntry\n)\n_sym_db.RegisterMessage(\n    TProtocolMessage.Performative_Pmt_Performative.ContentDictBoolStrEntry\n)\n_sym_db.RegisterMessage(\n    TProtocolMessage.Performative_Pmt_Performative.ContentDictStrBytesEntry\n)\n_sym_db.RegisterMessage(\n    TProtocolMessage.Performative_Pmt_Performative.ContentDictStrIntEntry\n)\n_sym_db.RegisterMessage(\n    TProtocolMessage.Performative_Pmt_Performative.ContentDictStrFloatEntry\n)\n_sym_db.RegisterMessage(\n    TProtocolMessage.Performative_Pmt_Performative.ContentDictStrBoolEntry\n)\n_sym_db.RegisterMessage(\n    TProtocolMessage.Performative_Pmt_Performative.ContentDictStrStrEntry\n)\n_sym_db.RegisterMessage(TProtocolMessage.Performative_Mt_Performative)\n_sym_db.RegisterMessage(\n    TProtocolMessage.Performative_Mt_Performative.ContentUnion1TypeDictOfStrIntEntry\n)\n_sym_db.RegisterMessage(\n    TProtocolMessage.Performative_Mt_Performative.ContentUnion2TypeDictOfStrIntEntry\n)\n_sym_db.RegisterMessage(\n    TProtocolMessage.Performative_Mt_Performative.ContentUnion2TypeDictOfIntFloatEntry\n)\n_sym_db.RegisterMessage(\n    TProtocolMessage.Performative_Mt_Performative.ContentUnion2TypeDictOfBoolBytesEntry\n)\n_sym_db.RegisterMessage(TProtocolMessage.Performative_O_Performative)\n_sym_db.RegisterMessage(\n    TProtocolMessage.Performative_O_Performative.ContentODictStrIntEntry\n)\n_sym_db.RegisterMessage(TProtocolMessage.Performative_Empty_Contents_Performative)\n\nif _descriptor._USE_C_DESCRIPTORS == False:\n\n    DESCRIPTOR._options = None\n    _TPROTOCOLMESSAGE_DATAMODEL_DICTFIELDENTRY._options = None\n    _TPROTOCOLMESSAGE_DATAMODEL_DICTFIELDENTRY._serialized_options = b\"8\\001\"\n    _TPROTOCOLMESSAGE_DATAMODEL1_DICTFIELDENTRY._options = None\n    _TPROTOCOLMESSAGE_DATAMODEL1_DICTFIELDENTRY._serialized_options = b\"8\\001\"\n    _TPROTOCOLMESSAGE_DATAMODEL2_DICTFIELDENTRY._options = None\n    _TPROTOCOLMESSAGE_DATAMODEL2_DICTFIELDENTRY._serialized_options = b\"8\\001\"\n    _TPROTOCOLMESSAGE_DATAMODEL3_DICTFIELDENTRY._options = None\n    _TPROTOCOLMESSAGE_DATAMODEL3_DICTFIELDENTRY._serialized_options = b\"8\\001\"\n    _TPROTOCOLMESSAGE_DATAMODEL4_DICTFIELDENTRY._options = None\n    _TPROTOCOLMESSAGE_DATAMODEL4_DICTFIELDENTRY._serialized_options = b\"8\\001\"\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTBYTESENTRY._options = (\n        None\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTBYTESENTRY._serialized_options = (\n        b\"8\\001\"\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTINTENTRY._options = (\n        None\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTINTENTRY._serialized_options = (\n        b\"8\\001\"\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTFLOATENTRY._options = (\n        None\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTFLOATENTRY._serialized_options = (\n        b\"8\\001\"\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTBOOLENTRY._options = (\n        None\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTBOOLENTRY._serialized_options = (\n        b\"8\\001\"\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTSTRENTRY._options = (\n        None\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTSTRENTRY._serialized_options = (\n        b\"8\\001\"\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLBYTESENTRY._options = (\n        None\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLBYTESENTRY._serialized_options = (\n        b\"8\\001\"\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLINTENTRY._options = (\n        None\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLINTENTRY._serialized_options = (\n        b\"8\\001\"\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLFLOATENTRY._options = (\n        None\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLFLOATENTRY._serialized_options = (\n        b\"8\\001\"\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLBOOLENTRY._options = (\n        None\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLBOOLENTRY._serialized_options = (\n        b\"8\\001\"\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLSTRENTRY._options = (\n        None\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLSTRENTRY._serialized_options = (\n        b\"8\\001\"\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRBYTESENTRY._options = (\n        None\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRBYTESENTRY._serialized_options = (\n        b\"8\\001\"\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRINTENTRY._options = (\n        None\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRINTENTRY._serialized_options = (\n        b\"8\\001\"\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRFLOATENTRY._options = (\n        None\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRFLOATENTRY._serialized_options = (\n        b\"8\\001\"\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRBOOLENTRY._options = (\n        None\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRBOOLENTRY._serialized_options = (\n        b\"8\\001\"\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRSTRENTRY._options = (\n        None\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRSTRENTRY._serialized_options = (\n        b\"8\\001\"\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION1TYPEDICTOFSTRINTENTRY._options = (\n        None\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION1TYPEDICTOFSTRINTENTRY._serialized_options = (\n        b\"8\\001\"\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFSTRINTENTRY._options = (\n        None\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFSTRINTENTRY._serialized_options = (\n        b\"8\\001\"\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFINTFLOATENTRY._options = (\n        None\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFINTFLOATENTRY._serialized_options = (\n        b\"8\\001\"\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFBOOLBYTESENTRY._options = (\n        None\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFBOOLBYTESENTRY._serialized_options = (\n        b\"8\\001\"\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_O_PERFORMATIVE_CONTENTODICTSTRINTENTRY._options = (\n        None\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_O_PERFORMATIVE_CONTENTODICTSTRINTENTRY._serialized_options = (\n        b\"8\\001\"\n    )\n    _TPROTOCOLMESSAGE._serialized_start = 64\n    _TPROTOCOLMESSAGE._serialized_end = 9739\n    _TPROTOCOLMESSAGE_DATAMODEL._serialized_start = 931\n    _TPROTOCOLMESSAGE_DATAMODEL._serialized_end = 1237\n    _TPROTOCOLMESSAGE_DATAMODEL_DICTFIELDENTRY._serialized_start = 1189\n    _TPROTOCOLMESSAGE_DATAMODEL_DICTFIELDENTRY._serialized_end = 1237\n    _TPROTOCOLMESSAGE_DATAMODEL1._serialized_start = 1240\n    _TPROTOCOLMESSAGE_DATAMODEL1._serialized_end = 1548\n    _TPROTOCOLMESSAGE_DATAMODEL1_DICTFIELDENTRY._serialized_start = 1189\n    _TPROTOCOLMESSAGE_DATAMODEL1_DICTFIELDENTRY._serialized_end = 1237\n    _TPROTOCOLMESSAGE_DATAMODEL2._serialized_start = 1551\n    _TPROTOCOLMESSAGE_DATAMODEL2._serialized_end = 1859\n    _TPROTOCOLMESSAGE_DATAMODEL2_DICTFIELDENTRY._serialized_start = 1189\n    _TPROTOCOLMESSAGE_DATAMODEL2_DICTFIELDENTRY._serialized_end = 1237\n    _TPROTOCOLMESSAGE_DATAMODEL3._serialized_start = 1862\n    _TPROTOCOLMESSAGE_DATAMODEL3._serialized_end = 2170\n    _TPROTOCOLMESSAGE_DATAMODEL3_DICTFIELDENTRY._serialized_start = 1189\n    _TPROTOCOLMESSAGE_DATAMODEL3_DICTFIELDENTRY._serialized_end = 1237\n    _TPROTOCOLMESSAGE_DATAMODEL4._serialized_start = 2173\n    _TPROTOCOLMESSAGE_DATAMODEL4._serialized_end = 2481\n    _TPROTOCOLMESSAGE_DATAMODEL4_DICTFIELDENTRY._serialized_start = 1189\n    _TPROTOCOLMESSAGE_DATAMODEL4_DICTFIELDENTRY._serialized_end = 1237\n    _TPROTOCOLMESSAGE_PERFORMATIVE_CT_PERFORMATIVE._serialized_start = 2483\n    _TPROTOCOLMESSAGE_PERFORMATIVE_CT_PERFORMATIVE._serialized_end = 2604\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PT_PERFORMATIVE._serialized_start = 2607\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PT_PERFORMATIVE._serialized_end = 2747\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PCT_PERFORMATIVE._serialized_start = 2750\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PCT_PERFORMATIVE._serialized_end = 3046\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE._serialized_start = 3049\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE._serialized_end = 6185\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTBYTESENTRY._serialized_start = (\n        5297\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTBYTESENTRY._serialized_end = (\n        5355\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTINTENTRY._serialized_start = (\n        5357\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTINTENTRY._serialized_end = (\n        5413\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTFLOATENTRY._serialized_start = (\n        5415\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTFLOATENTRY._serialized_end = (\n        5473\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTBOOLENTRY._serialized_start = (\n        5475\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTBOOLENTRY._serialized_end = (\n        5532\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTSTRENTRY._serialized_start = (\n        5534\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTSTRENTRY._serialized_end = (\n        5590\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLBYTESENTRY._serialized_start = (\n        5592\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLBYTESENTRY._serialized_end = (\n        5651\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLINTENTRY._serialized_start = (\n        5653\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLINTENTRY._serialized_end = (\n        5710\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLFLOATENTRY._serialized_start = (\n        5712\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLFLOATENTRY._serialized_end = (\n        5771\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLBOOLENTRY._serialized_start = (\n        5773\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLBOOLENTRY._serialized_end = (\n        5831\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLSTRENTRY._serialized_start = (\n        5833\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLSTRENTRY._serialized_end = (\n        5890\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRBYTESENTRY._serialized_start = (\n        5892\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRBYTESENTRY._serialized_end = (\n        5950\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRINTENTRY._serialized_start = (\n        5952\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRINTENTRY._serialized_end = (\n        6008\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRFLOATENTRY._serialized_start = (\n        6010\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRFLOATENTRY._serialized_end = (\n        6068\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRBOOLENTRY._serialized_start = (\n        6070\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRBOOLENTRY._serialized_end = (\n        6127\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRSTRENTRY._serialized_start = (\n        6129\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRSTRENTRY._serialized_end = (\n        6185\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_MT_PERFORMATIVE._serialized_start = 6188\n    _TPROTOCOLMESSAGE_PERFORMATIVE_MT_PERFORMATIVE._serialized_end = 9097\n    _TPROTOCOLMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION1TYPEDICTOFSTRINTENTRY._serialized_start = (\n        8814\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION1TYPEDICTOFSTRINTENTRY._serialized_end = (\n        8882\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFSTRINTENTRY._serialized_start = (\n        8884\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFSTRINTENTRY._serialized_end = (\n        8952\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFINTFLOATENTRY._serialized_start = (\n        8954\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFINTFLOATENTRY._serialized_end = (\n        9024\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFBOOLBYTESENTRY._serialized_start = (\n        9026\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFBOOLBYTESENTRY._serialized_end = (\n        9097\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_O_PERFORMATIVE._serialized_start = 9100\n    _TPROTOCOLMESSAGE_PERFORMATIVE_O_PERFORMATIVE._serialized_end = 9679\n    _TPROTOCOLMESSAGE_PERFORMATIVE_O_PERFORMATIVE_CONTENTODICTSTRINTENTRY._serialized_start = (\n        9622\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_O_PERFORMATIVE_CONTENTODICTSTRINTENTRY._serialized_end = (\n        9679\n    )\n    _TPROTOCOLMESSAGE_PERFORMATIVE_EMPTY_CONTENTS_PERFORMATIVE._serialized_start = 9681\n    _TPROTOCOLMESSAGE_PERFORMATIVE_EMPTY_CONTENTS_PERFORMATIVE._serialized_end = 9723\n# @@protoc_insertion_point(module_scope)\n"
  },
  {
    "path": "tests/data/generator/t_protocol_no_ct/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nThis module contains the support resources for the t_protocol_no_ct protocol.\n\nIt was created with protocol buffer compiler version `libprotoc 3.19.4` and aea version `1.2.5`.\n\"\"\"\n\nfrom tests.data.generator.t_protocol_no_ct.message import TProtocolNoCtMessage\nfrom tests.data.generator.t_protocol_no_ct.serialization import TProtocolNoCtSerializer\n\n\nTProtocolNoCtMessage.serializer = TProtocolNoCtSerializer\n"
  },
  {
    "path": "tests/data/generator/t_protocol_no_ct/dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nThis module contains the classes required for t_protocol_no_ct dialogue management.\n\n- TProtocolNoCtDialogue: The dialogue class maintains state of a dialogue and manages it.\n- TProtocolNoCtDialogues: The dialogues class keeps track of all dialogues.\n\"\"\"\n\nfrom abc import ABC\nfrom typing import Callable, Dict, FrozenSet, Type, cast\n\nfrom aea.common import Address\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue, DialogueLabel, Dialogues\n\nfrom tests.data.generator.t_protocol_no_ct.message import TProtocolNoCtMessage\n\n\nclass TProtocolNoCtDialogue(Dialogue):\n    \"\"\"The t_protocol_no_ct dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    INITIAL_PERFORMATIVES: FrozenSet[Message.Performative] = frozenset(\n        {TProtocolNoCtMessage.Performative.PERFORMATIVE_PT}\n    )\n    TERMINAL_PERFORMATIVES: FrozenSet[Message.Performative] = frozenset(\n        {\n            TProtocolNoCtMessage.Performative.PERFORMATIVE_MT,\n            TProtocolNoCtMessage.Performative.PERFORMATIVE_O,\n        }\n    )\n    VALID_REPLIES: Dict[Message.Performative, FrozenSet[Message.Performative]] = {\n        TProtocolNoCtMessage.Performative.PERFORMATIVE_EMPTY_CONTENTS: frozenset(\n            {TProtocolNoCtMessage.Performative.PERFORMATIVE_EMPTY_CONTENTS}\n        ),\n        TProtocolNoCtMessage.Performative.PERFORMATIVE_MT: frozenset(),\n        TProtocolNoCtMessage.Performative.PERFORMATIVE_O: frozenset(),\n        TProtocolNoCtMessage.Performative.PERFORMATIVE_PCT: frozenset(\n            {\n                TProtocolNoCtMessage.Performative.PERFORMATIVE_MT,\n                TProtocolNoCtMessage.Performative.PERFORMATIVE_O,\n            }\n        ),\n        TProtocolNoCtMessage.Performative.PERFORMATIVE_PMT: frozenset(\n            {\n                TProtocolNoCtMessage.Performative.PERFORMATIVE_MT,\n                TProtocolNoCtMessage.Performative.PERFORMATIVE_O,\n            }\n        ),\n        TProtocolNoCtMessage.Performative.PERFORMATIVE_PT: frozenset(\n            {\n                TProtocolNoCtMessage.Performative.PERFORMATIVE_PT,\n                TProtocolNoCtMessage.Performative.PERFORMATIVE_PCT,\n                TProtocolNoCtMessage.Performative.PERFORMATIVE_PMT,\n            }\n        ),\n    }\n\n    class Role(Dialogue.Role):\n        \"\"\"This class defines the agent's role in a t_protocol_no_ct dialogue.\"\"\"\n\n        ROLE_1 = \"role_1\"\n        ROLE_2 = \"role_2\"\n\n    class EndState(Dialogue.EndState):\n        \"\"\"This class defines the end states of a t_protocol_no_ct dialogue.\"\"\"\n\n        END_STATE_1 = 0\n        END_STATE_2 = 1\n        END_STATE_3 = 2\n\n    def __init__(\n        self,\n        dialogue_label: DialogueLabel,\n        self_address: Address,\n        role: Dialogue.Role,\n        message_class: Type[TProtocolNoCtMessage] = TProtocolNoCtMessage,\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n        :param message_class: the message class used\n        \"\"\"\n        Dialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            message_class=message_class,\n            self_address=self_address,\n            role=role,\n        )\n\n\nclass TProtocolNoCtDialogues(Dialogues, ABC):\n    \"\"\"This class keeps track of all t_protocol_no_ct dialogues.\"\"\"\n\n    END_STATES = frozenset(\n        {\n            TProtocolNoCtDialogue.EndState.END_STATE_1,\n            TProtocolNoCtDialogue.EndState.END_STATE_2,\n            TProtocolNoCtDialogue.EndState.END_STATE_3,\n        }\n    )\n\n    _keep_terminal_state_dialogues = True\n\n    def __init__(\n        self,\n        self_address: Address,\n        role_from_first_message: Callable[[Message, Address], Dialogue.Role],\n        dialogue_class: Type[TProtocolNoCtDialogue] = TProtocolNoCtDialogue,\n    ) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param self_address: the address of the entity for whom dialogues are maintained\n        :param dialogue_class: the dialogue class used\n        :param role_from_first_message: the callable determining role from first message\n        \"\"\"\n        Dialogues.__init__(\n            self,\n            self_address=self_address,\n            end_states=cast(FrozenSet[Dialogue.EndState], self.END_STATES),\n            message_class=TProtocolNoCtMessage,\n            dialogue_class=dialogue_class,\n            role_from_first_message=role_from_first_message,\n        )\n"
  },
  {
    "path": "tests/data/generator/t_protocol_no_ct/message.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains t_protocol_no_ct's message definition.\"\"\"\n\n# pylint: disable=too-many-statements,too-many-locals,no-member,too-few-public-methods,too-many-branches,not-an-iterable,unidiomatic-typecheck,unsubscriptable-object\nimport logging\nfrom typing import Any, Dict, FrozenSet, Optional, Set, Tuple, Union, cast\n\nfrom aea.configurations.base import PublicId\nfrom aea.exceptions import AEAEnforceError, enforce\nfrom aea.protocols.base import Message\n\n\n_default_logger = logging.getLogger(\n    \"aea.packages.fetchai.protocols.t_protocol_no_ct.message\"\n)\n\nDEFAULT_BODY_SIZE = 4\n\n\nclass TProtocolNoCtMessage(Message):\n    \"\"\"A protocol for testing purposes.\"\"\"\n\n    protocol_id = PublicId.from_str(\"fetchai/t_protocol_no_ct:0.1.0\")\n    protocol_specification_id = PublicId.from_str(\n        \"some_author/some_protocol_name:1.0.0\"\n    )\n\n    class Performative(Message.Performative):\n        \"\"\"Performatives for the t_protocol_no_ct protocol.\"\"\"\n\n        PERFORMATIVE_EMPTY_CONTENTS = \"performative_empty_contents\"\n        PERFORMATIVE_MT = \"performative_mt\"\n        PERFORMATIVE_O = \"performative_o\"\n        PERFORMATIVE_PCT = \"performative_pct\"\n        PERFORMATIVE_PMT = \"performative_pmt\"\n        PERFORMATIVE_PT = \"performative_pt\"\n\n        def __str__(self) -> str:\n            \"\"\"Get the string representation.\"\"\"\n            return str(self.value)\n\n    _performatives = {\n        \"performative_empty_contents\",\n        \"performative_mt\",\n        \"performative_o\",\n        \"performative_pct\",\n        \"performative_pmt\",\n        \"performative_pt\",\n    }\n    __slots__: Tuple[str, ...] = tuple()\n\n    class _SlotsCls:\n        __slots__ = (\n            \"content_bool\",\n            \"content_bytes\",\n            \"content_dict_bool_bool\",\n            \"content_dict_bool_bytes\",\n            \"content_dict_bool_float\",\n            \"content_dict_bool_int\",\n            \"content_dict_bool_str\",\n            \"content_dict_int_bool\",\n            \"content_dict_int_bytes\",\n            \"content_dict_int_float\",\n            \"content_dict_int_int\",\n            \"content_dict_int_str\",\n            \"content_dict_str_bool\",\n            \"content_dict_str_bytes\",\n            \"content_dict_str_float\",\n            \"content_dict_str_int\",\n            \"content_dict_str_str\",\n            \"content_float\",\n            \"content_int\",\n            \"content_list_bool\",\n            \"content_list_bytes\",\n            \"content_list_float\",\n            \"content_list_int\",\n            \"content_list_str\",\n            \"content_o_bool\",\n            \"content_o_dict_str_int\",\n            \"content_o_list_bytes\",\n            \"content_o_set_int\",\n            \"content_set_bool\",\n            \"content_set_bytes\",\n            \"content_set_float\",\n            \"content_set_int\",\n            \"content_set_str\",\n            \"content_str\",\n            \"content_union_1\",\n            \"content_union_2\",\n            \"dialogue_reference\",\n            \"message_id\",\n            \"performative\",\n            \"target\",\n        )\n\n    def __init__(\n        self,\n        performative: Performative,\n        dialogue_reference: Tuple[str, str] = (\"\", \"\"),\n        message_id: int = 1,\n        target: int = 0,\n        **kwargs: Any,\n    ):\n        \"\"\"\n        Initialise an instance of TProtocolNoCtMessage.\n\n        :param message_id: the message id.\n        :param dialogue_reference: the dialogue reference.\n        :param target: the message target.\n        :param performative: the message performative.\n        :param **kwargs: extra options.\n        \"\"\"\n        super().__init__(\n            dialogue_reference=dialogue_reference,\n            message_id=message_id,\n            target=target,\n            performative=TProtocolNoCtMessage.Performative(performative),\n            **kwargs,\n        )\n\n    @property\n    def valid_performatives(self) -> Set[str]:\n        \"\"\"Get valid performatives.\"\"\"\n        return self._performatives\n\n    @property\n    def dialogue_reference(self) -> Tuple[str, str]:\n        \"\"\"Get the dialogue_reference of the message.\"\"\"\n        enforce(self.is_set(\"dialogue_reference\"), \"dialogue_reference is not set.\")\n        return cast(Tuple[str, str], self.get(\"dialogue_reference\"))\n\n    @property\n    def message_id(self) -> int:\n        \"\"\"Get the message_id of the message.\"\"\"\n        enforce(self.is_set(\"message_id\"), \"message_id is not set.\")\n        return cast(int, self.get(\"message_id\"))\n\n    @property\n    def performative(self) -> Performative:  # type: ignore # noqa: F821\n        \"\"\"Get the performative of the message.\"\"\"\n        enforce(self.is_set(\"performative\"), \"performative is not set.\")\n        return cast(TProtocolNoCtMessage.Performative, self.get(\"performative\"))\n\n    @property\n    def target(self) -> int:\n        \"\"\"Get the target of the message.\"\"\"\n        enforce(self.is_set(\"target\"), \"target is not set.\")\n        return cast(int, self.get(\"target\"))\n\n    @property\n    def content_bool(self) -> bool:\n        \"\"\"Get the 'content_bool' content from the message.\"\"\"\n        enforce(self.is_set(\"content_bool\"), \"'content_bool' content is not set.\")\n        return cast(bool, self.get(\"content_bool\"))\n\n    @property\n    def content_bytes(self) -> bytes:\n        \"\"\"Get the 'content_bytes' content from the message.\"\"\"\n        enforce(self.is_set(\"content_bytes\"), \"'content_bytes' content is not set.\")\n        return cast(bytes, self.get(\"content_bytes\"))\n\n    @property\n    def content_dict_bool_bool(self) -> Dict[bool, bool]:\n        \"\"\"Get the 'content_dict_bool_bool' content from the message.\"\"\"\n        enforce(\n            self.is_set(\"content_dict_bool_bool\"),\n            \"'content_dict_bool_bool' content is not set.\",\n        )\n        return cast(Dict[bool, bool], self.get(\"content_dict_bool_bool\"))\n\n    @property\n    def content_dict_bool_bytes(self) -> Dict[bool, bytes]:\n        \"\"\"Get the 'content_dict_bool_bytes' content from the message.\"\"\"\n        enforce(\n            self.is_set(\"content_dict_bool_bytes\"),\n            \"'content_dict_bool_bytes' content is not set.\",\n        )\n        return cast(Dict[bool, bytes], self.get(\"content_dict_bool_bytes\"))\n\n    @property\n    def content_dict_bool_float(self) -> Dict[bool, float]:\n        \"\"\"Get the 'content_dict_bool_float' content from the message.\"\"\"\n        enforce(\n            self.is_set(\"content_dict_bool_float\"),\n            \"'content_dict_bool_float' content is not set.\",\n        )\n        return cast(Dict[bool, float], self.get(\"content_dict_bool_float\"))\n\n    @property\n    def content_dict_bool_int(self) -> Dict[bool, int]:\n        \"\"\"Get the 'content_dict_bool_int' content from the message.\"\"\"\n        enforce(\n            self.is_set(\"content_dict_bool_int\"),\n            \"'content_dict_bool_int' content is not set.\",\n        )\n        return cast(Dict[bool, int], self.get(\"content_dict_bool_int\"))\n\n    @property\n    def content_dict_bool_str(self) -> Dict[bool, str]:\n        \"\"\"Get the 'content_dict_bool_str' content from the message.\"\"\"\n        enforce(\n            self.is_set(\"content_dict_bool_str\"),\n            \"'content_dict_bool_str' content is not set.\",\n        )\n        return cast(Dict[bool, str], self.get(\"content_dict_bool_str\"))\n\n    @property\n    def content_dict_int_bool(self) -> Dict[int, bool]:\n        \"\"\"Get the 'content_dict_int_bool' content from the message.\"\"\"\n        enforce(\n            self.is_set(\"content_dict_int_bool\"),\n            \"'content_dict_int_bool' content is not set.\",\n        )\n        return cast(Dict[int, bool], self.get(\"content_dict_int_bool\"))\n\n    @property\n    def content_dict_int_bytes(self) -> Dict[int, bytes]:\n        \"\"\"Get the 'content_dict_int_bytes' content from the message.\"\"\"\n        enforce(\n            self.is_set(\"content_dict_int_bytes\"),\n            \"'content_dict_int_bytes' content is not set.\",\n        )\n        return cast(Dict[int, bytes], self.get(\"content_dict_int_bytes\"))\n\n    @property\n    def content_dict_int_float(self) -> Dict[int, float]:\n        \"\"\"Get the 'content_dict_int_float' content from the message.\"\"\"\n        enforce(\n            self.is_set(\"content_dict_int_float\"),\n            \"'content_dict_int_float' content is not set.\",\n        )\n        return cast(Dict[int, float], self.get(\"content_dict_int_float\"))\n\n    @property\n    def content_dict_int_int(self) -> Dict[int, int]:\n        \"\"\"Get the 'content_dict_int_int' content from the message.\"\"\"\n        enforce(\n            self.is_set(\"content_dict_int_int\"),\n            \"'content_dict_int_int' content is not set.\",\n        )\n        return cast(Dict[int, int], self.get(\"content_dict_int_int\"))\n\n    @property\n    def content_dict_int_str(self) -> Dict[int, str]:\n        \"\"\"Get the 'content_dict_int_str' content from the message.\"\"\"\n        enforce(\n            self.is_set(\"content_dict_int_str\"),\n            \"'content_dict_int_str' content is not set.\",\n        )\n        return cast(Dict[int, str], self.get(\"content_dict_int_str\"))\n\n    @property\n    def content_dict_str_bool(self) -> Dict[str, bool]:\n        \"\"\"Get the 'content_dict_str_bool' content from the message.\"\"\"\n        enforce(\n            self.is_set(\"content_dict_str_bool\"),\n            \"'content_dict_str_bool' content is not set.\",\n        )\n        return cast(Dict[str, bool], self.get(\"content_dict_str_bool\"))\n\n    @property\n    def content_dict_str_bytes(self) -> Dict[str, bytes]:\n        \"\"\"Get the 'content_dict_str_bytes' content from the message.\"\"\"\n        enforce(\n            self.is_set(\"content_dict_str_bytes\"),\n            \"'content_dict_str_bytes' content is not set.\",\n        )\n        return cast(Dict[str, bytes], self.get(\"content_dict_str_bytes\"))\n\n    @property\n    def content_dict_str_float(self) -> Dict[str, float]:\n        \"\"\"Get the 'content_dict_str_float' content from the message.\"\"\"\n        enforce(\n            self.is_set(\"content_dict_str_float\"),\n            \"'content_dict_str_float' content is not set.\",\n        )\n        return cast(Dict[str, float], self.get(\"content_dict_str_float\"))\n\n    @property\n    def content_dict_str_int(self) -> Dict[str, int]:\n        \"\"\"Get the 'content_dict_str_int' content from the message.\"\"\"\n        enforce(\n            self.is_set(\"content_dict_str_int\"),\n            \"'content_dict_str_int' content is not set.\",\n        )\n        return cast(Dict[str, int], self.get(\"content_dict_str_int\"))\n\n    @property\n    def content_dict_str_str(self) -> Dict[str, str]:\n        \"\"\"Get the 'content_dict_str_str' content from the message.\"\"\"\n        enforce(\n            self.is_set(\"content_dict_str_str\"),\n            \"'content_dict_str_str' content is not set.\",\n        )\n        return cast(Dict[str, str], self.get(\"content_dict_str_str\"))\n\n    @property\n    def content_float(self) -> float:\n        \"\"\"Get the 'content_float' content from the message.\"\"\"\n        enforce(self.is_set(\"content_float\"), \"'content_float' content is not set.\")\n        return cast(float, self.get(\"content_float\"))\n\n    @property\n    def content_int(self) -> int:\n        \"\"\"Get the 'content_int' content from the message.\"\"\"\n        enforce(self.is_set(\"content_int\"), \"'content_int' content is not set.\")\n        return cast(int, self.get(\"content_int\"))\n\n    @property\n    def content_list_bool(self) -> Tuple[bool, ...]:\n        \"\"\"Get the 'content_list_bool' content from the message.\"\"\"\n        enforce(\n            self.is_set(\"content_list_bool\"), \"'content_list_bool' content is not set.\"\n        )\n        return cast(Tuple[bool, ...], self.get(\"content_list_bool\"))\n\n    @property\n    def content_list_bytes(self) -> Tuple[bytes, ...]:\n        \"\"\"Get the 'content_list_bytes' content from the message.\"\"\"\n        enforce(\n            self.is_set(\"content_list_bytes\"),\n            \"'content_list_bytes' content is not set.\",\n        )\n        return cast(Tuple[bytes, ...], self.get(\"content_list_bytes\"))\n\n    @property\n    def content_list_float(self) -> Tuple[float, ...]:\n        \"\"\"Get the 'content_list_float' content from the message.\"\"\"\n        enforce(\n            self.is_set(\"content_list_float\"),\n            \"'content_list_float' content is not set.\",\n        )\n        return cast(Tuple[float, ...], self.get(\"content_list_float\"))\n\n    @property\n    def content_list_int(self) -> Tuple[int, ...]:\n        \"\"\"Get the 'content_list_int' content from the message.\"\"\"\n        enforce(\n            self.is_set(\"content_list_int\"), \"'content_list_int' content is not set.\"\n        )\n        return cast(Tuple[int, ...], self.get(\"content_list_int\"))\n\n    @property\n    def content_list_str(self) -> Tuple[str, ...]:\n        \"\"\"Get the 'content_list_str' content from the message.\"\"\"\n        enforce(\n            self.is_set(\"content_list_str\"), \"'content_list_str' content is not set.\"\n        )\n        return cast(Tuple[str, ...], self.get(\"content_list_str\"))\n\n    @property\n    def content_o_bool(self) -> Optional[bool]:\n        \"\"\"Get the 'content_o_bool' content from the message.\"\"\"\n        return cast(Optional[bool], self.get(\"content_o_bool\"))\n\n    @property\n    def content_o_dict_str_int(self) -> Optional[Dict[str, int]]:\n        \"\"\"Get the 'content_o_dict_str_int' content from the message.\"\"\"\n        return cast(Optional[Dict[str, int]], self.get(\"content_o_dict_str_int\"))\n\n    @property\n    def content_o_list_bytes(self) -> Optional[Tuple[bytes, ...]]:\n        \"\"\"Get the 'content_o_list_bytes' content from the message.\"\"\"\n        return cast(Optional[Tuple[bytes, ...]], self.get(\"content_o_list_bytes\"))\n\n    @property\n    def content_o_set_int(self) -> Optional[FrozenSet[int]]:\n        \"\"\"Get the 'content_o_set_int' content from the message.\"\"\"\n        return cast(Optional[FrozenSet[int]], self.get(\"content_o_set_int\"))\n\n    @property\n    def content_set_bool(self) -> FrozenSet[bool]:\n        \"\"\"Get the 'content_set_bool' content from the message.\"\"\"\n        enforce(\n            self.is_set(\"content_set_bool\"), \"'content_set_bool' content is not set.\"\n        )\n        return cast(FrozenSet[bool], self.get(\"content_set_bool\"))\n\n    @property\n    def content_set_bytes(self) -> FrozenSet[bytes]:\n        \"\"\"Get the 'content_set_bytes' content from the message.\"\"\"\n        enforce(\n            self.is_set(\"content_set_bytes\"), \"'content_set_bytes' content is not set.\"\n        )\n        return cast(FrozenSet[bytes], self.get(\"content_set_bytes\"))\n\n    @property\n    def content_set_float(self) -> FrozenSet[float]:\n        \"\"\"Get the 'content_set_float' content from the message.\"\"\"\n        enforce(\n            self.is_set(\"content_set_float\"), \"'content_set_float' content is not set.\"\n        )\n        return cast(FrozenSet[float], self.get(\"content_set_float\"))\n\n    @property\n    def content_set_int(self) -> FrozenSet[int]:\n        \"\"\"Get the 'content_set_int' content from the message.\"\"\"\n        enforce(self.is_set(\"content_set_int\"), \"'content_set_int' content is not set.\")\n        return cast(FrozenSet[int], self.get(\"content_set_int\"))\n\n    @property\n    def content_set_str(self) -> FrozenSet[str]:\n        \"\"\"Get the 'content_set_str' content from the message.\"\"\"\n        enforce(self.is_set(\"content_set_str\"), \"'content_set_str' content is not set.\")\n        return cast(FrozenSet[str], self.get(\"content_set_str\"))\n\n    @property\n    def content_str(self) -> str:\n        \"\"\"Get the 'content_str' content from the message.\"\"\"\n        enforce(self.is_set(\"content_str\"), \"'content_str' content is not set.\")\n        return cast(str, self.get(\"content_str\"))\n\n    @property\n    def content_union_1(\n        self,\n    ) -> Union[\n        bytes, int, float, bool, str, FrozenSet[int], Tuple[bool, ...], Dict[str, int]\n    ]:\n        \"\"\"Get the 'content_union_1' content from the message.\"\"\"\n        enforce(self.is_set(\"content_union_1\"), \"'content_union_1' content is not set.\")\n        return cast(\n            Union[\n                bytes,\n                int,\n                float,\n                bool,\n                str,\n                FrozenSet[int],\n                Tuple[bool, ...],\n                Dict[str, int],\n            ],\n            self.get(\"content_union_1\"),\n        )\n\n    @property\n    def content_union_2(\n        self,\n    ) -> Union[\n        FrozenSet[bytes],\n        FrozenSet[int],\n        FrozenSet[str],\n        Tuple[float, ...],\n        Tuple[bool, ...],\n        Tuple[bytes, ...],\n        Dict[str, int],\n        Dict[int, float],\n        Dict[bool, bytes],\n    ]:\n        \"\"\"Get the 'content_union_2' content from the message.\"\"\"\n        enforce(self.is_set(\"content_union_2\"), \"'content_union_2' content is not set.\")\n        return cast(\n            Union[\n                FrozenSet[bytes],\n                FrozenSet[int],\n                FrozenSet[str],\n                Tuple[float, ...],\n                Tuple[bool, ...],\n                Tuple[bytes, ...],\n                Dict[str, int],\n                Dict[int, float],\n                Dict[bool, bytes],\n            ],\n            self.get(\"content_union_2\"),\n        )\n\n    def _is_consistent(self) -> bool:\n        \"\"\"Check that the message follows the t_protocol_no_ct protocol.\"\"\"\n        try:\n            enforce(\n                isinstance(self.dialogue_reference, tuple),\n                \"Invalid type for 'dialogue_reference'. Expected 'tuple'. Found '{}'.\".format(\n                    type(self.dialogue_reference)\n                ),\n            )\n            enforce(\n                isinstance(self.dialogue_reference[0], str),\n                \"Invalid type for 'dialogue_reference[0]'. Expected 'str'. Found '{}'.\".format(\n                    type(self.dialogue_reference[0])\n                ),\n            )\n            enforce(\n                isinstance(self.dialogue_reference[1], str),\n                \"Invalid type for 'dialogue_reference[1]'. Expected 'str'. Found '{}'.\".format(\n                    type(self.dialogue_reference[1])\n                ),\n            )\n            enforce(\n                type(self.message_id) is int,\n                \"Invalid type for 'message_id'. Expected 'int'. Found '{}'.\".format(\n                    type(self.message_id)\n                ),\n            )\n            enforce(\n                type(self.target) is int,\n                \"Invalid type for 'target'. Expected 'int'. Found '{}'.\".format(\n                    type(self.target)\n                ),\n            )\n\n            # Light Protocol Rule 2\n            # Check correct performative\n            enforce(\n                isinstance(self.performative, TProtocolNoCtMessage.Performative),\n                \"Invalid 'performative'. Expected either of '{}'. Found '{}'.\".format(\n                    self.valid_performatives, self.performative\n                ),\n            )\n\n            # Check correct contents\n            actual_nb_of_contents = len(self._body) - DEFAULT_BODY_SIZE\n            expected_nb_of_contents = 0\n            if self.performative == TProtocolNoCtMessage.Performative.PERFORMATIVE_PT:\n                expected_nb_of_contents = 5\n                enforce(\n                    isinstance(self.content_bytes, bytes),\n                    \"Invalid type for content 'content_bytes'. Expected 'bytes'. Found '{}'.\".format(\n                        type(self.content_bytes)\n                    ),\n                )\n                enforce(\n                    type(self.content_int) is int,\n                    \"Invalid type for content 'content_int'. Expected 'int'. Found '{}'.\".format(\n                        type(self.content_int)\n                    ),\n                )\n                enforce(\n                    isinstance(self.content_float, float),\n                    \"Invalid type for content 'content_float'. Expected 'float'. Found '{}'.\".format(\n                        type(self.content_float)\n                    ),\n                )\n                enforce(\n                    isinstance(self.content_bool, bool),\n                    \"Invalid type for content 'content_bool'. Expected 'bool'. Found '{}'.\".format(\n                        type(self.content_bool)\n                    ),\n                )\n                enforce(\n                    isinstance(self.content_str, str),\n                    \"Invalid type for content 'content_str'. Expected 'str'. Found '{}'.\".format(\n                        type(self.content_str)\n                    ),\n                )\n            elif (\n                self.performative == TProtocolNoCtMessage.Performative.PERFORMATIVE_PCT\n            ):\n                expected_nb_of_contents = 10\n                enforce(\n                    isinstance(self.content_set_bytes, frozenset),\n                    \"Invalid type for content 'content_set_bytes'. Expected 'frozenset'. Found '{}'.\".format(\n                        type(self.content_set_bytes)\n                    ),\n                )\n                enforce(\n                    all(\n                        isinstance(element, bytes) for element in self.content_set_bytes\n                    ),\n                    \"Invalid type for frozenset elements in content 'content_set_bytes'. Expected 'bytes'.\",\n                )\n                enforce(\n                    isinstance(self.content_set_int, frozenset),\n                    \"Invalid type for content 'content_set_int'. Expected 'frozenset'. Found '{}'.\".format(\n                        type(self.content_set_int)\n                    ),\n                )\n                enforce(\n                    all(type(element) is int for element in self.content_set_int),\n                    \"Invalid type for frozenset elements in content 'content_set_int'. Expected 'int'.\",\n                )\n                enforce(\n                    isinstance(self.content_set_float, frozenset),\n                    \"Invalid type for content 'content_set_float'. Expected 'frozenset'. Found '{}'.\".format(\n                        type(self.content_set_float)\n                    ),\n                )\n                enforce(\n                    all(\n                        isinstance(element, float) for element in self.content_set_float\n                    ),\n                    \"Invalid type for frozenset elements in content 'content_set_float'. Expected 'float'.\",\n                )\n                enforce(\n                    isinstance(self.content_set_bool, frozenset),\n                    \"Invalid type for content 'content_set_bool'. Expected 'frozenset'. Found '{}'.\".format(\n                        type(self.content_set_bool)\n                    ),\n                )\n                enforce(\n                    all(isinstance(element, bool) for element in self.content_set_bool),\n                    \"Invalid type for frozenset elements in content 'content_set_bool'. Expected 'bool'.\",\n                )\n                enforce(\n                    isinstance(self.content_set_str, frozenset),\n                    \"Invalid type for content 'content_set_str'. Expected 'frozenset'. Found '{}'.\".format(\n                        type(self.content_set_str)\n                    ),\n                )\n                enforce(\n                    all(isinstance(element, str) for element in self.content_set_str),\n                    \"Invalid type for frozenset elements in content 'content_set_str'. Expected 'str'.\",\n                )\n                enforce(\n                    isinstance(self.content_list_bytes, tuple),\n                    \"Invalid type for content 'content_list_bytes'. Expected 'tuple'. Found '{}'.\".format(\n                        type(self.content_list_bytes)\n                    ),\n                )\n                enforce(\n                    all(\n                        isinstance(element, bytes)\n                        for element in self.content_list_bytes\n                    ),\n                    \"Invalid type for tuple elements in content 'content_list_bytes'. Expected 'bytes'.\",\n                )\n                enforce(\n                    isinstance(self.content_list_int, tuple),\n                    \"Invalid type for content 'content_list_int'. Expected 'tuple'. Found '{}'.\".format(\n                        type(self.content_list_int)\n                    ),\n                )\n                enforce(\n                    all(type(element) is int for element in self.content_list_int),\n                    \"Invalid type for tuple elements in content 'content_list_int'. Expected 'int'.\",\n                )\n                enforce(\n                    isinstance(self.content_list_float, tuple),\n                    \"Invalid type for content 'content_list_float'. Expected 'tuple'. Found '{}'.\".format(\n                        type(self.content_list_float)\n                    ),\n                )\n                enforce(\n                    all(\n                        isinstance(element, float)\n                        for element in self.content_list_float\n                    ),\n                    \"Invalid type for tuple elements in content 'content_list_float'. Expected 'float'.\",\n                )\n                enforce(\n                    isinstance(self.content_list_bool, tuple),\n                    \"Invalid type for content 'content_list_bool'. Expected 'tuple'. Found '{}'.\".format(\n                        type(self.content_list_bool)\n                    ),\n                )\n                enforce(\n                    all(\n                        isinstance(element, bool) for element in self.content_list_bool\n                    ),\n                    \"Invalid type for tuple elements in content 'content_list_bool'. Expected 'bool'.\",\n                )\n                enforce(\n                    isinstance(self.content_list_str, tuple),\n                    \"Invalid type for content 'content_list_str'. Expected 'tuple'. Found '{}'.\".format(\n                        type(self.content_list_str)\n                    ),\n                )\n                enforce(\n                    all(isinstance(element, str) for element in self.content_list_str),\n                    \"Invalid type for tuple elements in content 'content_list_str'. Expected 'str'.\",\n                )\n            elif (\n                self.performative == TProtocolNoCtMessage.Performative.PERFORMATIVE_PMT\n            ):\n                expected_nb_of_contents = 15\n                enforce(\n                    isinstance(self.content_dict_int_bytes, dict),\n                    \"Invalid type for content 'content_dict_int_bytes'. Expected 'dict'. Found '{}'.\".format(\n                        type(self.content_dict_int_bytes)\n                    ),\n                )\n                for (\n                    key_of_content_dict_int_bytes,\n                    value_of_content_dict_int_bytes,\n                ) in self.content_dict_int_bytes.items():\n                    enforce(\n                        type(key_of_content_dict_int_bytes) is int,\n                        \"Invalid type for dictionary keys in content 'content_dict_int_bytes'. Expected 'int'. Found '{}'.\".format(\n                            type(key_of_content_dict_int_bytes)\n                        ),\n                    )\n                    enforce(\n                        isinstance(value_of_content_dict_int_bytes, bytes),\n                        \"Invalid type for dictionary values in content 'content_dict_int_bytes'. Expected 'bytes'. Found '{}'.\".format(\n                            type(value_of_content_dict_int_bytes)\n                        ),\n                    )\n                enforce(\n                    isinstance(self.content_dict_int_int, dict),\n                    \"Invalid type for content 'content_dict_int_int'. Expected 'dict'. Found '{}'.\".format(\n                        type(self.content_dict_int_int)\n                    ),\n                )\n                for (\n                    key_of_content_dict_int_int,\n                    value_of_content_dict_int_int,\n                ) in self.content_dict_int_int.items():\n                    enforce(\n                        type(key_of_content_dict_int_int) is int,\n                        \"Invalid type for dictionary keys in content 'content_dict_int_int'. Expected 'int'. Found '{}'.\".format(\n                            type(key_of_content_dict_int_int)\n                        ),\n                    )\n                    enforce(\n                        type(value_of_content_dict_int_int) is int,\n                        \"Invalid type for dictionary values in content 'content_dict_int_int'. Expected 'int'. Found '{}'.\".format(\n                            type(value_of_content_dict_int_int)\n                        ),\n                    )\n                enforce(\n                    isinstance(self.content_dict_int_float, dict),\n                    \"Invalid type for content 'content_dict_int_float'. Expected 'dict'. Found '{}'.\".format(\n                        type(self.content_dict_int_float)\n                    ),\n                )\n                for (\n                    key_of_content_dict_int_float,\n                    value_of_content_dict_int_float,\n                ) in self.content_dict_int_float.items():\n                    enforce(\n                        type(key_of_content_dict_int_float) is int,\n                        \"Invalid type for dictionary keys in content 'content_dict_int_float'. Expected 'int'. Found '{}'.\".format(\n                            type(key_of_content_dict_int_float)\n                        ),\n                    )\n                    enforce(\n                        isinstance(value_of_content_dict_int_float, float),\n                        \"Invalid type for dictionary values in content 'content_dict_int_float'. Expected 'float'. Found '{}'.\".format(\n                            type(value_of_content_dict_int_float)\n                        ),\n                    )\n                enforce(\n                    isinstance(self.content_dict_int_bool, dict),\n                    \"Invalid type for content 'content_dict_int_bool'. Expected 'dict'. Found '{}'.\".format(\n                        type(self.content_dict_int_bool)\n                    ),\n                )\n                for (\n                    key_of_content_dict_int_bool,\n                    value_of_content_dict_int_bool,\n                ) in self.content_dict_int_bool.items():\n                    enforce(\n                        type(key_of_content_dict_int_bool) is int,\n                        \"Invalid type for dictionary keys in content 'content_dict_int_bool'. Expected 'int'. Found '{}'.\".format(\n                            type(key_of_content_dict_int_bool)\n                        ),\n                    )\n                    enforce(\n                        isinstance(value_of_content_dict_int_bool, bool),\n                        \"Invalid type for dictionary values in content 'content_dict_int_bool'. Expected 'bool'. Found '{}'.\".format(\n                            type(value_of_content_dict_int_bool)\n                        ),\n                    )\n                enforce(\n                    isinstance(self.content_dict_int_str, dict),\n                    \"Invalid type for content 'content_dict_int_str'. Expected 'dict'. Found '{}'.\".format(\n                        type(self.content_dict_int_str)\n                    ),\n                )\n                for (\n                    key_of_content_dict_int_str,\n                    value_of_content_dict_int_str,\n                ) in self.content_dict_int_str.items():\n                    enforce(\n                        type(key_of_content_dict_int_str) is int,\n                        \"Invalid type for dictionary keys in content 'content_dict_int_str'. Expected 'int'. Found '{}'.\".format(\n                            type(key_of_content_dict_int_str)\n                        ),\n                    )\n                    enforce(\n                        isinstance(value_of_content_dict_int_str, str),\n                        \"Invalid type for dictionary values in content 'content_dict_int_str'. Expected 'str'. Found '{}'.\".format(\n                            type(value_of_content_dict_int_str)\n                        ),\n                    )\n                enforce(\n                    isinstance(self.content_dict_bool_bytes, dict),\n                    \"Invalid type for content 'content_dict_bool_bytes'. Expected 'dict'. Found '{}'.\".format(\n                        type(self.content_dict_bool_bytes)\n                    ),\n                )\n                for (\n                    key_of_content_dict_bool_bytes,\n                    value_of_content_dict_bool_bytes,\n                ) in self.content_dict_bool_bytes.items():\n                    enforce(\n                        isinstance(key_of_content_dict_bool_bytes, bool),\n                        \"Invalid type for dictionary keys in content 'content_dict_bool_bytes'. Expected 'bool'. Found '{}'.\".format(\n                            type(key_of_content_dict_bool_bytes)\n                        ),\n                    )\n                    enforce(\n                        isinstance(value_of_content_dict_bool_bytes, bytes),\n                        \"Invalid type for dictionary values in content 'content_dict_bool_bytes'. Expected 'bytes'. Found '{}'.\".format(\n                            type(value_of_content_dict_bool_bytes)\n                        ),\n                    )\n                enforce(\n                    isinstance(self.content_dict_bool_int, dict),\n                    \"Invalid type for content 'content_dict_bool_int'. Expected 'dict'. Found '{}'.\".format(\n                        type(self.content_dict_bool_int)\n                    ),\n                )\n                for (\n                    key_of_content_dict_bool_int,\n                    value_of_content_dict_bool_int,\n                ) in self.content_dict_bool_int.items():\n                    enforce(\n                        isinstance(key_of_content_dict_bool_int, bool),\n                        \"Invalid type for dictionary keys in content 'content_dict_bool_int'. Expected 'bool'. Found '{}'.\".format(\n                            type(key_of_content_dict_bool_int)\n                        ),\n                    )\n                    enforce(\n                        type(value_of_content_dict_bool_int) is int,\n                        \"Invalid type for dictionary values in content 'content_dict_bool_int'. Expected 'int'. Found '{}'.\".format(\n                            type(value_of_content_dict_bool_int)\n                        ),\n                    )\n                enforce(\n                    isinstance(self.content_dict_bool_float, dict),\n                    \"Invalid type for content 'content_dict_bool_float'. Expected 'dict'. Found '{}'.\".format(\n                        type(self.content_dict_bool_float)\n                    ),\n                )\n                for (\n                    key_of_content_dict_bool_float,\n                    value_of_content_dict_bool_float,\n                ) in self.content_dict_bool_float.items():\n                    enforce(\n                        isinstance(key_of_content_dict_bool_float, bool),\n                        \"Invalid type for dictionary keys in content 'content_dict_bool_float'. Expected 'bool'. Found '{}'.\".format(\n                            type(key_of_content_dict_bool_float)\n                        ),\n                    )\n                    enforce(\n                        isinstance(value_of_content_dict_bool_float, float),\n                        \"Invalid type for dictionary values in content 'content_dict_bool_float'. Expected 'float'. Found '{}'.\".format(\n                            type(value_of_content_dict_bool_float)\n                        ),\n                    )\n                enforce(\n                    isinstance(self.content_dict_bool_bool, dict),\n                    \"Invalid type for content 'content_dict_bool_bool'. Expected 'dict'. Found '{}'.\".format(\n                        type(self.content_dict_bool_bool)\n                    ),\n                )\n                for (\n                    key_of_content_dict_bool_bool,\n                    value_of_content_dict_bool_bool,\n                ) in self.content_dict_bool_bool.items():\n                    enforce(\n                        isinstance(key_of_content_dict_bool_bool, bool),\n                        \"Invalid type for dictionary keys in content 'content_dict_bool_bool'. Expected 'bool'. Found '{}'.\".format(\n                            type(key_of_content_dict_bool_bool)\n                        ),\n                    )\n                    enforce(\n                        isinstance(value_of_content_dict_bool_bool, bool),\n                        \"Invalid type for dictionary values in content 'content_dict_bool_bool'. Expected 'bool'. Found '{}'.\".format(\n                            type(value_of_content_dict_bool_bool)\n                        ),\n                    )\n                enforce(\n                    isinstance(self.content_dict_bool_str, dict),\n                    \"Invalid type for content 'content_dict_bool_str'. Expected 'dict'. Found '{}'.\".format(\n                        type(self.content_dict_bool_str)\n                    ),\n                )\n                for (\n                    key_of_content_dict_bool_str,\n                    value_of_content_dict_bool_str,\n                ) in self.content_dict_bool_str.items():\n                    enforce(\n                        isinstance(key_of_content_dict_bool_str, bool),\n                        \"Invalid type for dictionary keys in content 'content_dict_bool_str'. Expected 'bool'. Found '{}'.\".format(\n                            type(key_of_content_dict_bool_str)\n                        ),\n                    )\n                    enforce(\n                        isinstance(value_of_content_dict_bool_str, str),\n                        \"Invalid type for dictionary values in content 'content_dict_bool_str'. Expected 'str'. Found '{}'.\".format(\n                            type(value_of_content_dict_bool_str)\n                        ),\n                    )\n                enforce(\n                    isinstance(self.content_dict_str_bytes, dict),\n                    \"Invalid type for content 'content_dict_str_bytes'. Expected 'dict'. Found '{}'.\".format(\n                        type(self.content_dict_str_bytes)\n                    ),\n                )\n                for (\n                    key_of_content_dict_str_bytes,\n                    value_of_content_dict_str_bytes,\n                ) in self.content_dict_str_bytes.items():\n                    enforce(\n                        isinstance(key_of_content_dict_str_bytes, str),\n                        \"Invalid type for dictionary keys in content 'content_dict_str_bytes'. Expected 'str'. Found '{}'.\".format(\n                            type(key_of_content_dict_str_bytes)\n                        ),\n                    )\n                    enforce(\n                        isinstance(value_of_content_dict_str_bytes, bytes),\n                        \"Invalid type for dictionary values in content 'content_dict_str_bytes'. Expected 'bytes'. Found '{}'.\".format(\n                            type(value_of_content_dict_str_bytes)\n                        ),\n                    )\n                enforce(\n                    isinstance(self.content_dict_str_int, dict),\n                    \"Invalid type for content 'content_dict_str_int'. Expected 'dict'. Found '{}'.\".format(\n                        type(self.content_dict_str_int)\n                    ),\n                )\n                for (\n                    key_of_content_dict_str_int,\n                    value_of_content_dict_str_int,\n                ) in self.content_dict_str_int.items():\n                    enforce(\n                        isinstance(key_of_content_dict_str_int, str),\n                        \"Invalid type for dictionary keys in content 'content_dict_str_int'. Expected 'str'. Found '{}'.\".format(\n                            type(key_of_content_dict_str_int)\n                        ),\n                    )\n                    enforce(\n                        type(value_of_content_dict_str_int) is int,\n                        \"Invalid type for dictionary values in content 'content_dict_str_int'. Expected 'int'. Found '{}'.\".format(\n                            type(value_of_content_dict_str_int)\n                        ),\n                    )\n                enforce(\n                    isinstance(self.content_dict_str_float, dict),\n                    \"Invalid type for content 'content_dict_str_float'. Expected 'dict'. Found '{}'.\".format(\n                        type(self.content_dict_str_float)\n                    ),\n                )\n                for (\n                    key_of_content_dict_str_float,\n                    value_of_content_dict_str_float,\n                ) in self.content_dict_str_float.items():\n                    enforce(\n                        isinstance(key_of_content_dict_str_float, str),\n                        \"Invalid type for dictionary keys in content 'content_dict_str_float'. Expected 'str'. Found '{}'.\".format(\n                            type(key_of_content_dict_str_float)\n                        ),\n                    )\n                    enforce(\n                        isinstance(value_of_content_dict_str_float, float),\n                        \"Invalid type for dictionary values in content 'content_dict_str_float'. Expected 'float'. Found '{}'.\".format(\n                            type(value_of_content_dict_str_float)\n                        ),\n                    )\n                enforce(\n                    isinstance(self.content_dict_str_bool, dict),\n                    \"Invalid type for content 'content_dict_str_bool'. Expected 'dict'. Found '{}'.\".format(\n                        type(self.content_dict_str_bool)\n                    ),\n                )\n                for (\n                    key_of_content_dict_str_bool,\n                    value_of_content_dict_str_bool,\n                ) in self.content_dict_str_bool.items():\n                    enforce(\n                        isinstance(key_of_content_dict_str_bool, str),\n                        \"Invalid type for dictionary keys in content 'content_dict_str_bool'. Expected 'str'. Found '{}'.\".format(\n                            type(key_of_content_dict_str_bool)\n                        ),\n                    )\n                    enforce(\n                        isinstance(value_of_content_dict_str_bool, bool),\n                        \"Invalid type for dictionary values in content 'content_dict_str_bool'. Expected 'bool'. Found '{}'.\".format(\n                            type(value_of_content_dict_str_bool)\n                        ),\n                    )\n                enforce(\n                    isinstance(self.content_dict_str_str, dict),\n                    \"Invalid type for content 'content_dict_str_str'. Expected 'dict'. Found '{}'.\".format(\n                        type(self.content_dict_str_str)\n                    ),\n                )\n                for (\n                    key_of_content_dict_str_str,\n                    value_of_content_dict_str_str,\n                ) in self.content_dict_str_str.items():\n                    enforce(\n                        isinstance(key_of_content_dict_str_str, str),\n                        \"Invalid type for dictionary keys in content 'content_dict_str_str'. Expected 'str'. Found '{}'.\".format(\n                            type(key_of_content_dict_str_str)\n                        ),\n                    )\n                    enforce(\n                        isinstance(value_of_content_dict_str_str, str),\n                        \"Invalid type for dictionary values in content 'content_dict_str_str'. Expected 'str'. Found '{}'.\".format(\n                            type(value_of_content_dict_str_str)\n                        ),\n                    )\n            elif self.performative == TProtocolNoCtMessage.Performative.PERFORMATIVE_MT:\n                expected_nb_of_contents = 2\n                enforce(\n                    isinstance(self.content_union_1, bool)\n                    or isinstance(self.content_union_1, bytes)\n                    or isinstance(self.content_union_1, dict)\n                    or isinstance(self.content_union_1, float)\n                    or isinstance(self.content_union_1, frozenset)\n                    or type(self.content_union_1) is int\n                    or isinstance(self.content_union_1, str)\n                    or isinstance(self.content_union_1, tuple),\n                    \"Invalid type for content 'content_union_1'. Expected either of '['bool', 'bytes', 'dict', 'float', 'frozenset', 'int', 'str', 'tuple']'. Found '{}'.\".format(\n                        type(self.content_union_1)\n                    ),\n                )\n                if isinstance(self.content_union_1, frozenset):\n                    enforce(\n                        all(type(element) is int for element in self.content_union_1),\n                        \"Invalid type for elements of content 'content_union_1'. Expected 'int'.\",\n                    )\n                if isinstance(self.content_union_1, tuple):\n                    enforce(\n                        all(\n                            isinstance(element, bool)\n                            for element in self.content_union_1\n                        ),\n                        \"Invalid type for tuple elements in content 'content_union_1'. Expected 'bool'.\",\n                    )\n                if isinstance(self.content_union_1, dict):\n                    for (\n                        key_of_content_union_1,\n                        value_of_content_union_1,\n                    ) in self.content_union_1.items():\n                        enforce(\n                            (\n                                isinstance(key_of_content_union_1, str)\n                                and type(value_of_content_union_1) is int\n                            ),\n                            \"Invalid type for dictionary key, value in content 'content_union_1'. Expected 'str', 'int'.\",\n                        )\n                enforce(\n                    isinstance(self.content_union_2, dict)\n                    or isinstance(self.content_union_2, frozenset)\n                    or isinstance(self.content_union_2, tuple),\n                    \"Invalid type for content 'content_union_2'. Expected either of '['dict', 'frozenset', 'tuple']'. Found '{}'.\".format(\n                        type(self.content_union_2)\n                    ),\n                )\n                if isinstance(self.content_union_2, frozenset):\n                    enforce(\n                        all(\n                            isinstance(element, bytes)\n                            for element in self.content_union_2\n                        )\n                        or all(type(element) is int for element in self.content_union_2)\n                        or all(\n                            isinstance(element, str) for element in self.content_union_2\n                        ),\n                        \"Invalid type for frozenset elements in content 'content_union_2'. Expected either 'bytes' or 'int' or 'str'.\",\n                    )\n                if isinstance(self.content_union_2, tuple):\n                    enforce(\n                        all(\n                            isinstance(element, bool)\n                            for element in self.content_union_2\n                        )\n                        or all(\n                            isinstance(element, bytes)\n                            for element in self.content_union_2\n                        )\n                        or all(\n                            isinstance(element, float)\n                            for element in self.content_union_2\n                        ),\n                        \"Invalid type for tuple elements in content 'content_union_2'. Expected either 'bool' or 'bytes' or 'float'.\",\n                    )\n                if isinstance(self.content_union_2, dict):\n                    for (\n                        key_of_content_union_2,\n                        value_of_content_union_2,\n                    ) in self.content_union_2.items():\n                        enforce(\n                            (\n                                isinstance(key_of_content_union_2, bool)\n                                and isinstance(value_of_content_union_2, bytes)\n                            )\n                            or (\n                                type(key_of_content_union_2) is int\n                                and isinstance(value_of_content_union_2, float)\n                            )\n                            or (\n                                isinstance(key_of_content_union_2, str)\n                                and type(value_of_content_union_2) is int\n                            ),\n                            \"Invalid type for dictionary key, value in content 'content_union_2'. Expected 'bool','bytes' or 'int','float' or 'str','int'.\",\n                        )\n            elif self.performative == TProtocolNoCtMessage.Performative.PERFORMATIVE_O:\n                expected_nb_of_contents = 0\n                if self.is_set(\"content_o_bool\"):\n                    expected_nb_of_contents += 1\n                    content_o_bool = cast(bool, self.content_o_bool)\n                    enforce(\n                        isinstance(content_o_bool, bool),\n                        \"Invalid type for content 'content_o_bool'. Expected 'bool'. Found '{}'.\".format(\n                            type(content_o_bool)\n                        ),\n                    )\n                if self.is_set(\"content_o_set_int\"):\n                    expected_nb_of_contents += 1\n                    content_o_set_int = cast(FrozenSet[int], self.content_o_set_int)\n                    enforce(\n                        isinstance(content_o_set_int, frozenset),\n                        \"Invalid type for content 'content_o_set_int'. Expected 'frozenset'. Found '{}'.\".format(\n                            type(content_o_set_int)\n                        ),\n                    )\n                    enforce(\n                        all(type(element) is int for element in content_o_set_int),\n                        \"Invalid type for frozenset elements in content 'content_o_set_int'. Expected 'int'.\",\n                    )\n                if self.is_set(\"content_o_list_bytes\"):\n                    expected_nb_of_contents += 1\n                    content_o_list_bytes = cast(\n                        Tuple[bytes, ...], self.content_o_list_bytes\n                    )\n                    enforce(\n                        isinstance(content_o_list_bytes, tuple),\n                        \"Invalid type for content 'content_o_list_bytes'. Expected 'tuple'. Found '{}'.\".format(\n                            type(content_o_list_bytes)\n                        ),\n                    )\n                    enforce(\n                        all(\n                            isinstance(element, bytes)\n                            for element in content_o_list_bytes\n                        ),\n                        \"Invalid type for tuple elements in content 'content_o_list_bytes'. Expected 'bytes'.\",\n                    )\n                if self.is_set(\"content_o_dict_str_int\"):\n                    expected_nb_of_contents += 1\n                    content_o_dict_str_int = cast(\n                        Dict[str, int], self.content_o_dict_str_int\n                    )\n                    enforce(\n                        isinstance(content_o_dict_str_int, dict),\n                        \"Invalid type for content 'content_o_dict_str_int'. Expected 'dict'. Found '{}'.\".format(\n                            type(content_o_dict_str_int)\n                        ),\n                    )\n                    for (\n                        key_of_content_o_dict_str_int,\n                        value_of_content_o_dict_str_int,\n                    ) in content_o_dict_str_int.items():\n                        enforce(\n                            isinstance(key_of_content_o_dict_str_int, str),\n                            \"Invalid type for dictionary keys in content 'content_o_dict_str_int'. Expected 'str'. Found '{}'.\".format(\n                                type(key_of_content_o_dict_str_int)\n                            ),\n                        )\n                        enforce(\n                            type(value_of_content_o_dict_str_int) is int,\n                            \"Invalid type for dictionary values in content 'content_o_dict_str_int'. Expected 'int'. Found '{}'.\".format(\n                                type(value_of_content_o_dict_str_int)\n                            ),\n                        )\n            elif (\n                self.performative\n                == TProtocolNoCtMessage.Performative.PERFORMATIVE_EMPTY_CONTENTS\n            ):\n                expected_nb_of_contents = 0\n\n            # Check correct content count\n            enforce(\n                expected_nb_of_contents == actual_nb_of_contents,\n                \"Incorrect number of contents. Expected {}. Found {}\".format(\n                    expected_nb_of_contents, actual_nb_of_contents\n                ),\n            )\n\n            # Light Protocol Rule 3\n            if self.message_id == 1:\n                enforce(\n                    self.target == 0,\n                    \"Invalid 'target'. Expected 0 (because 'message_id' is 1). Found {}.\".format(\n                        self.target\n                    ),\n                )\n        except (AEAEnforceError, ValueError, KeyError) as e:\n            _default_logger.error(str(e))\n            return False\n\n        return True\n"
  },
  {
    "path": "tests/data/generator/t_protocol_no_ct/protocol.yaml",
    "content": "name: t_protocol_no_ct\nauthor: fetchai\nversion: 0.1.0\nprotocol_specification_id: some_author/some_protocol_name:1.0.0\ntype: protocol\ndescription: A protocol for testing purposes.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  __init__.py: QmcxVa3xRNtDc5tmaeDiN3KMHC7dENFrrgmnufQ3Ypqk9w\n  dialogues.py: QmRTxDfiHH5CS65g9wtz1mqWDmENDpMvgmmczsn1tWemSr\n  message.py: QmYR1AwBvuVUFdQdLagHastVduKJB3WPUX8hWiyAozsEwG\n  serialization.py: Qmbem38xwYtcGsFfn6vd8xuMeE8FVFrJXGUXNEhY5V3zpR\n  t_protocol_no_ct.proto: QmapyiDZBjF3K8yLZvCBYhjm3dFVwaLBKL8PLWUoYpTLez\n  t_protocol_no_ct_pb2.py: QmUeCxpxg2SYZfB26rjFentsmpFtJLgwU1ueMvPNQA4YbP\nfingerprint_ignore_patterns: []\ndependencies:\n  protobuf: {}\n"
  },
  {
    "path": "tests/data/generator/t_protocol_no_ct/serialization.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Serialization module for t_protocol_no_ct protocol.\"\"\"\n\n# pylint: disable=too-many-statements,too-many-locals,no-member,too-few-public-methods,redefined-builtin\nfrom typing import Any, Dict, cast\n\nfrom aea.mail.base_pb2 import DialogueMessage\nfrom aea.mail.base_pb2 import Message as ProtobufMessage\nfrom aea.protocols.base import Message, Serializer\n\nfrom tests.data.generator.t_protocol_no_ct import t_protocol_no_ct_pb2\nfrom tests.data.generator.t_protocol_no_ct.message import TProtocolNoCtMessage\n\n\nclass TProtocolNoCtSerializer(Serializer):\n    \"\"\"Serialization for the 't_protocol_no_ct' protocol.\"\"\"\n\n    @staticmethod\n    def encode(msg: Message) -> bytes:\n        \"\"\"\n        Encode a 'TProtocolNoCt' message into bytes.\n\n        :param msg: the message object.\n        :return: the bytes.\n        \"\"\"\n        msg = cast(TProtocolNoCtMessage, msg)\n        message_pb = ProtobufMessage()\n        dialogue_message_pb = DialogueMessage()\n        t_protocol_no_ct_msg = t_protocol_no_ct_pb2.TProtocolNoCtMessage()\n\n        dialogue_message_pb.message_id = msg.message_id\n        dialogue_reference = msg.dialogue_reference\n        dialogue_message_pb.dialogue_starter_reference = dialogue_reference[0]\n        dialogue_message_pb.dialogue_responder_reference = dialogue_reference[1]\n        dialogue_message_pb.target = msg.target\n\n        performative_id = msg.performative\n        if performative_id == TProtocolNoCtMessage.Performative.PERFORMATIVE_PT:\n            performative = t_protocol_no_ct_pb2.TProtocolNoCtMessage.Performative_Pt_Performative()  # type: ignore\n            content_bytes = msg.content_bytes\n            performative.content_bytes = content_bytes\n            content_int = msg.content_int\n            performative.content_int = content_int\n            content_float = msg.content_float\n            performative.content_float = content_float\n            content_bool = msg.content_bool\n            performative.content_bool = content_bool\n            content_str = msg.content_str\n            performative.content_str = content_str\n            t_protocol_no_ct_msg.performative_pt.CopyFrom(performative)\n        elif performative_id == TProtocolNoCtMessage.Performative.PERFORMATIVE_PCT:\n            performative = t_protocol_no_ct_pb2.TProtocolNoCtMessage.Performative_Pct_Performative()  # type: ignore\n            content_set_bytes = msg.content_set_bytes\n            performative.content_set_bytes.extend(content_set_bytes)\n            content_set_int = msg.content_set_int\n            performative.content_set_int.extend(content_set_int)\n            content_set_float = msg.content_set_float\n            performative.content_set_float.extend(content_set_float)\n            content_set_bool = msg.content_set_bool\n            performative.content_set_bool.extend(content_set_bool)\n            content_set_str = msg.content_set_str\n            performative.content_set_str.extend(content_set_str)\n            content_list_bytes = msg.content_list_bytes\n            performative.content_list_bytes.extend(content_list_bytes)\n            content_list_int = msg.content_list_int\n            performative.content_list_int.extend(content_list_int)\n            content_list_float = msg.content_list_float\n            performative.content_list_float.extend(content_list_float)\n            content_list_bool = msg.content_list_bool\n            performative.content_list_bool.extend(content_list_bool)\n            content_list_str = msg.content_list_str\n            performative.content_list_str.extend(content_list_str)\n            t_protocol_no_ct_msg.performative_pct.CopyFrom(performative)\n        elif performative_id == TProtocolNoCtMessage.Performative.PERFORMATIVE_PMT:\n            performative = t_protocol_no_ct_pb2.TProtocolNoCtMessage.Performative_Pmt_Performative()  # type: ignore\n            content_dict_int_bytes = msg.content_dict_int_bytes\n            performative.content_dict_int_bytes.update(content_dict_int_bytes)\n            content_dict_int_int = msg.content_dict_int_int\n            performative.content_dict_int_int.update(content_dict_int_int)\n            content_dict_int_float = msg.content_dict_int_float\n            performative.content_dict_int_float.update(content_dict_int_float)\n            content_dict_int_bool = msg.content_dict_int_bool\n            performative.content_dict_int_bool.update(content_dict_int_bool)\n            content_dict_int_str = msg.content_dict_int_str\n            performative.content_dict_int_str.update(content_dict_int_str)\n            content_dict_bool_bytes = msg.content_dict_bool_bytes\n            performative.content_dict_bool_bytes.update(content_dict_bool_bytes)\n            content_dict_bool_int = msg.content_dict_bool_int\n            performative.content_dict_bool_int.update(content_dict_bool_int)\n            content_dict_bool_float = msg.content_dict_bool_float\n            performative.content_dict_bool_float.update(content_dict_bool_float)\n            content_dict_bool_bool = msg.content_dict_bool_bool\n            performative.content_dict_bool_bool.update(content_dict_bool_bool)\n            content_dict_bool_str = msg.content_dict_bool_str\n            performative.content_dict_bool_str.update(content_dict_bool_str)\n            content_dict_str_bytes = msg.content_dict_str_bytes\n            performative.content_dict_str_bytes.update(content_dict_str_bytes)\n            content_dict_str_int = msg.content_dict_str_int\n            performative.content_dict_str_int.update(content_dict_str_int)\n            content_dict_str_float = msg.content_dict_str_float\n            performative.content_dict_str_float.update(content_dict_str_float)\n            content_dict_str_bool = msg.content_dict_str_bool\n            performative.content_dict_str_bool.update(content_dict_str_bool)\n            content_dict_str_str = msg.content_dict_str_str\n            performative.content_dict_str_str.update(content_dict_str_str)\n            t_protocol_no_ct_msg.performative_pmt.CopyFrom(performative)\n        elif performative_id == TProtocolNoCtMessage.Performative.PERFORMATIVE_MT:\n            performative = t_protocol_no_ct_pb2.TProtocolNoCtMessage.Performative_Mt_Performative()  # type: ignore\n            if msg.is_set(\"content_union_1\"):\n                if isinstance(msg.content_union_1, bytes):\n                    performative.content_union_1_type_bytes_is_set = True\n                    content_union_1_type_bytes = msg.content_union_1\n                    performative.content_union_1_type_bytes = content_union_1_type_bytes\n                elif isinstance(msg.content_union_1, int):\n                    performative.content_union_1_type_int_is_set = True\n                    content_union_1_type_int = msg.content_union_1\n                    performative.content_union_1_type_int = content_union_1_type_int\n                elif isinstance(msg.content_union_1, float):\n                    performative.content_union_1_type_float_is_set = True\n                    content_union_1_type_float = msg.content_union_1\n                    performative.content_union_1_type_float = content_union_1_type_float\n                elif isinstance(msg.content_union_1, bool):\n                    performative.content_union_1_type_bool_is_set = True\n                    content_union_1_type_bool = msg.content_union_1\n                    performative.content_union_1_type_bool = content_union_1_type_bool\n                elif isinstance(msg.content_union_1, str):\n                    performative.content_union_1_type_str_is_set = True\n                    content_union_1_type_str = msg.content_union_1\n                    performative.content_union_1_type_str = content_union_1_type_str\n                elif isinstance(msg.content_union_1, (set, frozenset)) and all(\n                    map(lambda x: isinstance(x, int), msg.content_union_1)\n                ):\n                    performative.content_union_1_type_set_of_int_is_set = True\n                    content_union_1 = msg.content_union_1\n                    performative.content_union_1_type_set_of_int.extend(content_union_1)\n                elif isinstance(msg.content_union_1, (list, tuple)) and all(\n                    map(lambda x: isinstance(x, bool), msg.content_union_1)\n                ):\n                    performative.content_union_1_type_list_of_bool_is_set = True\n                    content_union_1 = msg.content_union_1\n                    performative.content_union_1_type_list_of_bool.extend(\n                        content_union_1\n                    )\n                elif isinstance(msg.content_union_1, dict) and all(\n                    map(\n                        lambda x: isinstance(x[0], str) and isinstance(x[1], int),\n                        msg.content_union_1.items(),\n                    )\n                ):\n                    performative.content_union_1_type_dict_of_str_int_is_set = True\n                    content_union_1 = msg.content_union_1\n                    performative.content_union_1_type_dict_of_str_int.update(\n                        content_union_1\n                    )\n                elif msg.content_union_1 is None:\n                    pass\n                else:\n                    raise ValueError(\n                        f\"Bad value set to `content_union_1` {msg.content_union_1 }\"\n                    )\n            if msg.is_set(\"content_union_2\"):\n                if isinstance(msg.content_union_2, (set, frozenset)) and all(\n                    map(lambda x: isinstance(x, bytes), msg.content_union_2)\n                ):\n                    performative.content_union_2_type_set_of_bytes_is_set = True\n                    content_union_2 = msg.content_union_2\n                    performative.content_union_2_type_set_of_bytes.extend(\n                        content_union_2\n                    )\n                elif isinstance(msg.content_union_2, (set, frozenset)) and all(\n                    map(lambda x: isinstance(x, int), msg.content_union_2)\n                ):\n                    performative.content_union_2_type_set_of_int_is_set = True\n                    content_union_2 = msg.content_union_2\n                    performative.content_union_2_type_set_of_int.extend(content_union_2)\n                elif isinstance(msg.content_union_2, (set, frozenset)) and all(\n                    map(lambda x: isinstance(x, str), msg.content_union_2)\n                ):\n                    performative.content_union_2_type_set_of_str_is_set = True\n                    content_union_2 = msg.content_union_2\n                    performative.content_union_2_type_set_of_str.extend(content_union_2)\n                elif isinstance(msg.content_union_2, (list, tuple)) and all(\n                    map(lambda x: isinstance(x, float), msg.content_union_2)\n                ):\n                    performative.content_union_2_type_list_of_float_is_set = True\n                    content_union_2 = msg.content_union_2\n                    performative.content_union_2_type_list_of_float.extend(\n                        content_union_2\n                    )\n                elif isinstance(msg.content_union_2, (list, tuple)) and all(\n                    map(lambda x: isinstance(x, bool), msg.content_union_2)\n                ):\n                    performative.content_union_2_type_list_of_bool_is_set = True\n                    content_union_2 = msg.content_union_2\n                    performative.content_union_2_type_list_of_bool.extend(\n                        content_union_2\n                    )\n                elif isinstance(msg.content_union_2, (list, tuple)) and all(\n                    map(lambda x: isinstance(x, bytes), msg.content_union_2)\n                ):\n                    performative.content_union_2_type_list_of_bytes_is_set = True\n                    content_union_2 = msg.content_union_2\n                    performative.content_union_2_type_list_of_bytes.extend(\n                        content_union_2\n                    )\n                elif isinstance(msg.content_union_2, dict) and all(\n                    map(\n                        lambda x: isinstance(x[0], str) and isinstance(x[1], int),\n                        msg.content_union_2.items(),\n                    )\n                ):\n                    performative.content_union_2_type_dict_of_str_int_is_set = True\n                    content_union_2 = msg.content_union_2\n                    performative.content_union_2_type_dict_of_str_int.update(\n                        content_union_2\n                    )\n                elif isinstance(msg.content_union_2, dict) and all(\n                    map(\n                        lambda x: isinstance(x[0], int) and isinstance(x[1], float),\n                        msg.content_union_2.items(),\n                    )\n                ):\n                    performative.content_union_2_type_dict_of_int_float_is_set = True\n                    content_union_2 = msg.content_union_2\n                    performative.content_union_2_type_dict_of_int_float.update(\n                        content_union_2\n                    )\n                elif isinstance(msg.content_union_2, dict) and all(\n                    map(\n                        lambda x: isinstance(x[0], bool) and isinstance(x[1], bytes),\n                        msg.content_union_2.items(),\n                    )\n                ):\n                    performative.content_union_2_type_dict_of_bool_bytes_is_set = True\n                    content_union_2 = msg.content_union_2\n                    performative.content_union_2_type_dict_of_bool_bytes.update(\n                        content_union_2\n                    )\n                elif msg.content_union_2 is None:\n                    pass\n                else:\n                    raise ValueError(\n                        f\"Bad value set to `content_union_2` {msg.content_union_2 }\"\n                    )\n            t_protocol_no_ct_msg.performative_mt.CopyFrom(performative)\n        elif performative_id == TProtocolNoCtMessage.Performative.PERFORMATIVE_O:\n            performative = t_protocol_no_ct_pb2.TProtocolNoCtMessage.Performative_O_Performative()  # type: ignore\n            if msg.is_set(\"content_o_bool\"):\n                performative.content_o_bool_is_set = True\n                content_o_bool = msg.content_o_bool\n                performative.content_o_bool = content_o_bool\n            if msg.is_set(\"content_o_set_int\"):\n                performative.content_o_set_int_is_set = True\n                content_o_set_int = msg.content_o_set_int\n                performative.content_o_set_int.extend(content_o_set_int)\n            if msg.is_set(\"content_o_list_bytes\"):\n                performative.content_o_list_bytes_is_set = True\n                content_o_list_bytes = msg.content_o_list_bytes\n                performative.content_o_list_bytes.extend(content_o_list_bytes)\n            if msg.is_set(\"content_o_dict_str_int\"):\n                performative.content_o_dict_str_int_is_set = True\n                content_o_dict_str_int = msg.content_o_dict_str_int\n                performative.content_o_dict_str_int.update(content_o_dict_str_int)\n            t_protocol_no_ct_msg.performative_o.CopyFrom(performative)\n        elif (\n            performative_id\n            == TProtocolNoCtMessage.Performative.PERFORMATIVE_EMPTY_CONTENTS\n        ):\n            performative = t_protocol_no_ct_pb2.TProtocolNoCtMessage.Performative_Empty_Contents_Performative()  # type: ignore\n            t_protocol_no_ct_msg.performative_empty_contents.CopyFrom(performative)\n        else:\n            raise ValueError(\"Performative not valid: {}\".format(performative_id))\n\n        dialogue_message_pb.content = t_protocol_no_ct_msg.SerializeToString()\n\n        message_pb.dialogue_message.CopyFrom(dialogue_message_pb)\n        message_bytes = message_pb.SerializeToString()\n        return message_bytes\n\n    @staticmethod\n    def decode(obj: bytes) -> Message:\n        \"\"\"\n        Decode bytes into a 'TProtocolNoCt' message.\n\n        :param obj: the bytes object.\n        :return: the 'TProtocolNoCt' message.\n        \"\"\"\n        message_pb = ProtobufMessage()\n        t_protocol_no_ct_pb = t_protocol_no_ct_pb2.TProtocolNoCtMessage()\n        message_pb.ParseFromString(obj)\n        message_id = message_pb.dialogue_message.message_id\n        dialogue_reference = (\n            message_pb.dialogue_message.dialogue_starter_reference,\n            message_pb.dialogue_message.dialogue_responder_reference,\n        )\n        target = message_pb.dialogue_message.target\n\n        t_protocol_no_ct_pb.ParseFromString(message_pb.dialogue_message.content)\n        performative = t_protocol_no_ct_pb.WhichOneof(\"performative\")\n        performative_id = TProtocolNoCtMessage.Performative(str(performative))\n        performative_content = {}  # type: Dict[str, Any]\n        if performative_id == TProtocolNoCtMessage.Performative.PERFORMATIVE_PT:\n            content_bytes = t_protocol_no_ct_pb.performative_pt.content_bytes\n            performative_content[\"content_bytes\"] = content_bytes\n            content_int = t_protocol_no_ct_pb.performative_pt.content_int\n            performative_content[\"content_int\"] = content_int\n            content_float = t_protocol_no_ct_pb.performative_pt.content_float\n            performative_content[\"content_float\"] = content_float\n            content_bool = t_protocol_no_ct_pb.performative_pt.content_bool\n            performative_content[\"content_bool\"] = content_bool\n            content_str = t_protocol_no_ct_pb.performative_pt.content_str\n            performative_content[\"content_str\"] = content_str\n        elif performative_id == TProtocolNoCtMessage.Performative.PERFORMATIVE_PCT:\n            content_set_bytes = t_protocol_no_ct_pb.performative_pct.content_set_bytes\n            content_set_bytes_frozenset = frozenset(content_set_bytes)\n            performative_content[\"content_set_bytes\"] = content_set_bytes_frozenset\n            content_set_int = t_protocol_no_ct_pb.performative_pct.content_set_int\n            content_set_int_frozenset = frozenset(content_set_int)\n            performative_content[\"content_set_int\"] = content_set_int_frozenset\n            content_set_float = t_protocol_no_ct_pb.performative_pct.content_set_float\n            content_set_float_frozenset = frozenset(content_set_float)\n            performative_content[\"content_set_float\"] = content_set_float_frozenset\n            content_set_bool = t_protocol_no_ct_pb.performative_pct.content_set_bool\n            content_set_bool_frozenset = frozenset(content_set_bool)\n            performative_content[\"content_set_bool\"] = content_set_bool_frozenset\n            content_set_str = t_protocol_no_ct_pb.performative_pct.content_set_str\n            content_set_str_frozenset = frozenset(content_set_str)\n            performative_content[\"content_set_str\"] = content_set_str_frozenset\n            content_list_bytes = t_protocol_no_ct_pb.performative_pct.content_list_bytes\n            content_list_bytes_tuple = tuple(content_list_bytes)\n            performative_content[\"content_list_bytes\"] = content_list_bytes_tuple\n            content_list_int = t_protocol_no_ct_pb.performative_pct.content_list_int\n            content_list_int_tuple = tuple(content_list_int)\n            performative_content[\"content_list_int\"] = content_list_int_tuple\n            content_list_float = t_protocol_no_ct_pb.performative_pct.content_list_float\n            content_list_float_tuple = tuple(content_list_float)\n            performative_content[\"content_list_float\"] = content_list_float_tuple\n            content_list_bool = t_protocol_no_ct_pb.performative_pct.content_list_bool\n            content_list_bool_tuple = tuple(content_list_bool)\n            performative_content[\"content_list_bool\"] = content_list_bool_tuple\n            content_list_str = t_protocol_no_ct_pb.performative_pct.content_list_str\n            content_list_str_tuple = tuple(content_list_str)\n            performative_content[\"content_list_str\"] = content_list_str_tuple\n        elif performative_id == TProtocolNoCtMessage.Performative.PERFORMATIVE_PMT:\n            content_dict_int_bytes = (\n                t_protocol_no_ct_pb.performative_pmt.content_dict_int_bytes\n            )\n            content_dict_int_bytes_dict = dict(content_dict_int_bytes)\n            performative_content[\"content_dict_int_bytes\"] = content_dict_int_bytes_dict\n            content_dict_int_int = (\n                t_protocol_no_ct_pb.performative_pmt.content_dict_int_int\n            )\n            content_dict_int_int_dict = dict(content_dict_int_int)\n            performative_content[\"content_dict_int_int\"] = content_dict_int_int_dict\n            content_dict_int_float = (\n                t_protocol_no_ct_pb.performative_pmt.content_dict_int_float\n            )\n            content_dict_int_float_dict = dict(content_dict_int_float)\n            performative_content[\"content_dict_int_float\"] = content_dict_int_float_dict\n            content_dict_int_bool = (\n                t_protocol_no_ct_pb.performative_pmt.content_dict_int_bool\n            )\n            content_dict_int_bool_dict = dict(content_dict_int_bool)\n            performative_content[\"content_dict_int_bool\"] = content_dict_int_bool_dict\n            content_dict_int_str = (\n                t_protocol_no_ct_pb.performative_pmt.content_dict_int_str\n            )\n            content_dict_int_str_dict = dict(content_dict_int_str)\n            performative_content[\"content_dict_int_str\"] = content_dict_int_str_dict\n            content_dict_bool_bytes = (\n                t_protocol_no_ct_pb.performative_pmt.content_dict_bool_bytes\n            )\n            content_dict_bool_bytes_dict = dict(content_dict_bool_bytes)\n            performative_content[\n                \"content_dict_bool_bytes\"\n            ] = content_dict_bool_bytes_dict\n            content_dict_bool_int = (\n                t_protocol_no_ct_pb.performative_pmt.content_dict_bool_int\n            )\n            content_dict_bool_int_dict = dict(content_dict_bool_int)\n            performative_content[\"content_dict_bool_int\"] = content_dict_bool_int_dict\n            content_dict_bool_float = (\n                t_protocol_no_ct_pb.performative_pmt.content_dict_bool_float\n            )\n            content_dict_bool_float_dict = dict(content_dict_bool_float)\n            performative_content[\n                \"content_dict_bool_float\"\n            ] = content_dict_bool_float_dict\n            content_dict_bool_bool = (\n                t_protocol_no_ct_pb.performative_pmt.content_dict_bool_bool\n            )\n            content_dict_bool_bool_dict = dict(content_dict_bool_bool)\n            performative_content[\"content_dict_bool_bool\"] = content_dict_bool_bool_dict\n            content_dict_bool_str = (\n                t_protocol_no_ct_pb.performative_pmt.content_dict_bool_str\n            )\n            content_dict_bool_str_dict = dict(content_dict_bool_str)\n            performative_content[\"content_dict_bool_str\"] = content_dict_bool_str_dict\n            content_dict_str_bytes = (\n                t_protocol_no_ct_pb.performative_pmt.content_dict_str_bytes\n            )\n            content_dict_str_bytes_dict = dict(content_dict_str_bytes)\n            performative_content[\"content_dict_str_bytes\"] = content_dict_str_bytes_dict\n            content_dict_str_int = (\n                t_protocol_no_ct_pb.performative_pmt.content_dict_str_int\n            )\n            content_dict_str_int_dict = dict(content_dict_str_int)\n            performative_content[\"content_dict_str_int\"] = content_dict_str_int_dict\n            content_dict_str_float = (\n                t_protocol_no_ct_pb.performative_pmt.content_dict_str_float\n            )\n            content_dict_str_float_dict = dict(content_dict_str_float)\n            performative_content[\"content_dict_str_float\"] = content_dict_str_float_dict\n            content_dict_str_bool = (\n                t_protocol_no_ct_pb.performative_pmt.content_dict_str_bool\n            )\n            content_dict_str_bool_dict = dict(content_dict_str_bool)\n            performative_content[\"content_dict_str_bool\"] = content_dict_str_bool_dict\n            content_dict_str_str = (\n                t_protocol_no_ct_pb.performative_pmt.content_dict_str_str\n            )\n            content_dict_str_str_dict = dict(content_dict_str_str)\n            performative_content[\"content_dict_str_str\"] = content_dict_str_str_dict\n        elif performative_id == TProtocolNoCtMessage.Performative.PERFORMATIVE_MT:\n            if t_protocol_no_ct_pb.performative_mt.content_union_1_type_bytes_is_set:\n                content_union_1 = (\n                    t_protocol_no_ct_pb.performative_mt.content_union_1_type_bytes\n                )\n                performative_content[\"content_union_1\"] = content_union_1\n            if t_protocol_no_ct_pb.performative_mt.content_union_1_type_int_is_set:\n                content_union_1 = (\n                    t_protocol_no_ct_pb.performative_mt.content_union_1_type_int\n                )\n                performative_content[\"content_union_1\"] = content_union_1\n            if t_protocol_no_ct_pb.performative_mt.content_union_1_type_float_is_set:\n                content_union_1 = (\n                    t_protocol_no_ct_pb.performative_mt.content_union_1_type_float\n                )\n                performative_content[\"content_union_1\"] = content_union_1\n            if t_protocol_no_ct_pb.performative_mt.content_union_1_type_bool_is_set:\n                content_union_1 = (\n                    t_protocol_no_ct_pb.performative_mt.content_union_1_type_bool\n                )\n                performative_content[\"content_union_1\"] = content_union_1\n            if t_protocol_no_ct_pb.performative_mt.content_union_1_type_str_is_set:\n                content_union_1 = (\n                    t_protocol_no_ct_pb.performative_mt.content_union_1_type_str\n                )\n                performative_content[\"content_union_1\"] = content_union_1\n            if (\n                t_protocol_no_ct_pb.performative_mt.content_union_1_type_set_of_int_is_set\n            ):\n                content_union_1 = (\n                    t_protocol_no_ct_pb.performative_mt.content_union_1_type_set_of_int\n                )\n                content_union_1_frozenset = frozenset(content_union_1)\n                performative_content[\"content_union_1\"] = content_union_1_frozenset\n            if (\n                t_protocol_no_ct_pb.performative_mt.content_union_1_type_list_of_bool_is_set\n            ):\n                content_union_1 = (\n                    t_protocol_no_ct_pb.performative_mt.content_union_1_type_list_of_bool\n                )\n                content_union_1_tuple = tuple(content_union_1)\n                performative_content[\"content_union_1\"] = content_union_1_tuple\n            if (\n                t_protocol_no_ct_pb.performative_mt.content_union_1_type_dict_of_str_int_is_set\n            ):\n                content_union_1 = (\n                    t_protocol_no_ct_pb.performative_mt.content_union_1_type_dict_of_str_int\n                )\n                content_union_1_dict = dict(content_union_1)\n                performative_content[\"content_union_1\"] = content_union_1_dict\n            if (\n                t_protocol_no_ct_pb.performative_mt.content_union_2_type_set_of_bytes_is_set\n            ):\n                content_union_2 = (\n                    t_protocol_no_ct_pb.performative_mt.content_union_2_type_set_of_bytes\n                )\n                content_union_2_frozenset = frozenset(content_union_2)\n                performative_content[\"content_union_2\"] = content_union_2_frozenset\n            if (\n                t_protocol_no_ct_pb.performative_mt.content_union_2_type_set_of_int_is_set\n            ):\n                content_union_2 = (\n                    t_protocol_no_ct_pb.performative_mt.content_union_2_type_set_of_int\n                )\n                content_union_2_frozenset = frozenset(content_union_2)\n                performative_content[\"content_union_2\"] = content_union_2_frozenset\n            if (\n                t_protocol_no_ct_pb.performative_mt.content_union_2_type_set_of_str_is_set\n            ):\n                content_union_2 = (\n                    t_protocol_no_ct_pb.performative_mt.content_union_2_type_set_of_str\n                )\n                content_union_2_frozenset = frozenset(content_union_2)\n                performative_content[\"content_union_2\"] = content_union_2_frozenset\n            if (\n                t_protocol_no_ct_pb.performative_mt.content_union_2_type_list_of_float_is_set\n            ):\n                content_union_2 = (\n                    t_protocol_no_ct_pb.performative_mt.content_union_2_type_list_of_float\n                )\n                content_union_2_tuple = tuple(content_union_2)\n                performative_content[\"content_union_2\"] = content_union_2_tuple\n            if (\n                t_protocol_no_ct_pb.performative_mt.content_union_2_type_list_of_bool_is_set\n            ):\n                content_union_2 = (\n                    t_protocol_no_ct_pb.performative_mt.content_union_2_type_list_of_bool\n                )\n                content_union_2_tuple = tuple(content_union_2)\n                performative_content[\"content_union_2\"] = content_union_2_tuple\n            if (\n                t_protocol_no_ct_pb.performative_mt.content_union_2_type_list_of_bytes_is_set\n            ):\n                content_union_2 = (\n                    t_protocol_no_ct_pb.performative_mt.content_union_2_type_list_of_bytes\n                )\n                content_union_2_tuple = tuple(content_union_2)\n                performative_content[\"content_union_2\"] = content_union_2_tuple\n            if (\n                t_protocol_no_ct_pb.performative_mt.content_union_2_type_dict_of_str_int_is_set\n            ):\n                content_union_2 = (\n                    t_protocol_no_ct_pb.performative_mt.content_union_2_type_dict_of_str_int\n                )\n                content_union_2_dict = dict(content_union_2)\n                performative_content[\"content_union_2\"] = content_union_2_dict\n            if (\n                t_protocol_no_ct_pb.performative_mt.content_union_2_type_dict_of_int_float_is_set\n            ):\n                content_union_2 = (\n                    t_protocol_no_ct_pb.performative_mt.content_union_2_type_dict_of_int_float\n                )\n                content_union_2_dict = dict(content_union_2)\n                performative_content[\"content_union_2\"] = content_union_2_dict\n            if (\n                t_protocol_no_ct_pb.performative_mt.content_union_2_type_dict_of_bool_bytes_is_set\n            ):\n                content_union_2 = (\n                    t_protocol_no_ct_pb.performative_mt.content_union_2_type_dict_of_bool_bytes\n                )\n                content_union_2_dict = dict(content_union_2)\n                performative_content[\"content_union_2\"] = content_union_2_dict\n        elif performative_id == TProtocolNoCtMessage.Performative.PERFORMATIVE_O:\n            if t_protocol_no_ct_pb.performative_o.content_o_bool_is_set:\n                content_o_bool = t_protocol_no_ct_pb.performative_o.content_o_bool\n                performative_content[\"content_o_bool\"] = content_o_bool\n            if t_protocol_no_ct_pb.performative_o.content_o_set_int_is_set:\n                content_o_set_int = t_protocol_no_ct_pb.performative_o.content_o_set_int\n                content_o_set_int_frozenset = frozenset(content_o_set_int)\n                performative_content[\"content_o_set_int\"] = content_o_set_int_frozenset\n            if t_protocol_no_ct_pb.performative_o.content_o_list_bytes_is_set:\n                content_o_list_bytes = (\n                    t_protocol_no_ct_pb.performative_o.content_o_list_bytes\n                )\n                content_o_list_bytes_tuple = tuple(content_o_list_bytes)\n                performative_content[\n                    \"content_o_list_bytes\"\n                ] = content_o_list_bytes_tuple\n            if t_protocol_no_ct_pb.performative_o.content_o_dict_str_int_is_set:\n                content_o_dict_str_int = (\n                    t_protocol_no_ct_pb.performative_o.content_o_dict_str_int\n                )\n                content_o_dict_str_int_dict = dict(content_o_dict_str_int)\n                performative_content[\n                    \"content_o_dict_str_int\"\n                ] = content_o_dict_str_int_dict\n        elif (\n            performative_id\n            == TProtocolNoCtMessage.Performative.PERFORMATIVE_EMPTY_CONTENTS\n        ):\n            pass\n        else:\n            raise ValueError(\"Performative not valid: {}.\".format(performative_id))\n\n        return TProtocolNoCtMessage(\n            message_id=message_id,\n            dialogue_reference=dialogue_reference,\n            target=target,\n            performative=performative,\n            **performative_content,\n        )\n"
  },
  {
    "path": "tests/data/generator/t_protocol_no_ct/t_protocol_no_ct.proto",
    "content": "syntax = \"proto3\";\n\npackage aea.some_author.some_protocol_name.v1_0_0;\n\nmessage TProtocolNoCtMessage{\n\n  // Performatives and contents\n  message Performative_Pt_Performative{\n    bytes content_bytes = 1;\n    int64 content_int = 2;\n    float content_float = 3;\n    bool content_bool = 4;\n    string content_str = 5;\n  }\n\n  message Performative_Pct_Performative{\n    repeated bytes content_set_bytes = 1;\n    repeated int64 content_set_int = 2;\n    repeated float content_set_float = 3;\n    repeated bool content_set_bool = 4;\n    repeated string content_set_str = 5;\n    repeated bytes content_list_bytes = 6;\n    repeated int64 content_list_int = 7;\n    repeated float content_list_float = 8;\n    repeated bool content_list_bool = 9;\n    repeated string content_list_str = 10;\n  }\n\n  message Performative_Pmt_Performative{\n    map<int64, bytes> content_dict_int_bytes = 1;\n    map<int64, int64> content_dict_int_int = 2;\n    map<int64, float> content_dict_int_float = 3;\n    map<int64, bool> content_dict_int_bool = 4;\n    map<int64, string> content_dict_int_str = 5;\n    map<bool, bytes> content_dict_bool_bytes = 6;\n    map<bool, int64> content_dict_bool_int = 7;\n    map<bool, float> content_dict_bool_float = 8;\n    map<bool, bool> content_dict_bool_bool = 9;\n    map<bool, string> content_dict_bool_str = 10;\n    map<string, bytes> content_dict_str_bytes = 11;\n    map<string, int64> content_dict_str_int = 12;\n    map<string, float> content_dict_str_float = 13;\n    map<string, bool> content_dict_str_bool = 14;\n    map<string, string> content_dict_str_str = 15;\n  }\n\n  message Performative_Mt_Performative{\n    bytes content_union_1_type_bytes = 1;\n    bool content_union_1_type_bytes_is_set = 2;\n    int64 content_union_1_type_int = 3;\n    bool content_union_1_type_int_is_set = 4;\n    float content_union_1_type_float = 5;\n    bool content_union_1_type_float_is_set = 6;\n    bool content_union_1_type_bool = 7;\n    bool content_union_1_type_bool_is_set = 8;\n    string content_union_1_type_str = 9;\n    bool content_union_1_type_str_is_set = 10;\n    repeated int64 content_union_1_type_set_of_int = 11;\n    bool content_union_1_type_set_of_int_is_set = 12;\n    repeated bool content_union_1_type_list_of_bool = 13;\n    bool content_union_1_type_list_of_bool_is_set = 14;\n    map<string, int64> content_union_1_type_dict_of_str_int = 15;\n    bool content_union_1_type_dict_of_str_int_is_set = 16;\n    repeated bytes content_union_2_type_set_of_bytes = 17;\n    bool content_union_2_type_set_of_bytes_is_set = 18;\n    repeated int64 content_union_2_type_set_of_int = 19;\n    bool content_union_2_type_set_of_int_is_set = 20;\n    repeated string content_union_2_type_set_of_str = 21;\n    bool content_union_2_type_set_of_str_is_set = 22;\n    repeated float content_union_2_type_list_of_float = 23;\n    bool content_union_2_type_list_of_float_is_set = 24;\n    repeated bool content_union_2_type_list_of_bool = 25;\n    bool content_union_2_type_list_of_bool_is_set = 26;\n    repeated bytes content_union_2_type_list_of_bytes = 27;\n    bool content_union_2_type_list_of_bytes_is_set = 28;\n    map<string, int64> content_union_2_type_dict_of_str_int = 29;\n    bool content_union_2_type_dict_of_str_int_is_set = 30;\n    map<int64, float> content_union_2_type_dict_of_int_float = 31;\n    bool content_union_2_type_dict_of_int_float_is_set = 32;\n    map<bool, bytes> content_union_2_type_dict_of_bool_bytes = 33;\n    bool content_union_2_type_dict_of_bool_bytes_is_set = 34;\n  }\n\n  message Performative_O_Performative{\n    bool content_o_bool = 1;\n    bool content_o_bool_is_set = 2;\n    repeated int64 content_o_set_int = 3;\n    bool content_o_set_int_is_set = 4;\n    repeated bytes content_o_list_bytes = 5;\n    bool content_o_list_bytes_is_set = 6;\n    map<string, int64> content_o_dict_str_int = 7;\n    bool content_o_dict_str_int_is_set = 8;\n  }\n\n  message Performative_Empty_Contents_Performative{\n  }\n\n\n  oneof performative{\n    Performative_Empty_Contents_Performative performative_empty_contents = 5;\n    Performative_Mt_Performative performative_mt = 6;\n    Performative_O_Performative performative_o = 7;\n    Performative_Pct_Performative performative_pct = 8;\n    Performative_Pmt_Performative performative_pmt = 9;\n    Performative_Pt_Performative performative_pt = 10;\n  }\n}\n"
  },
  {
    "path": "tests/data/generator/t_protocol_no_ct/t_protocol_no_ct_pb2.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by the protocol buffer compiler.  DO NOT EDIT!\n# source: t_protocol_no_ct.proto\n\"\"\"Generated protocol buffer code.\"\"\"\nfrom google.protobuf import descriptor as _descriptor\nfrom google.protobuf import descriptor_pool as _descriptor_pool\nfrom google.protobuf import message as _message\nfrom google.protobuf import reflection as _reflection\nfrom google.protobuf import symbol_database as _symbol_database\n\n# @@protoc_insertion_point(imports)\n\n_sym_db = _symbol_database.Default()\n\n\nDESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(\n    b'\\n\\x16t_protocol_no_ct.proto\\x12)aea.some_author.some_protocol_name.v1_0_0\"\\x8f\\x39\\n\\x14TProtocolNoCtMessage\\x12\\x8f\\x01\\n\\x1bperformative_empty_contents\\x18\\x05 \\x01(\\x0b\\x32h.aea.some_author.some_protocol_name.v1_0_0.TProtocolNoCtMessage.Performative_Empty_Contents_PerformativeH\\x00\\x12w\\n\\x0fperformative_mt\\x18\\x06 \\x01(\\x0b\\x32\\\\.aea.some_author.some_protocol_name.v1_0_0.TProtocolNoCtMessage.Performative_Mt_PerformativeH\\x00\\x12u\\n\\x0eperformative_o\\x18\\x07 \\x01(\\x0b\\x32[.aea.some_author.some_protocol_name.v1_0_0.TProtocolNoCtMessage.Performative_O_PerformativeH\\x00\\x12y\\n\\x10performative_pct\\x18\\x08 \\x01(\\x0b\\x32].aea.some_author.some_protocol_name.v1_0_0.TProtocolNoCtMessage.Performative_Pct_PerformativeH\\x00\\x12y\\n\\x10performative_pmt\\x18\\t \\x01(\\x0b\\x32].aea.some_author.some_protocol_name.v1_0_0.TProtocolNoCtMessage.Performative_Pmt_PerformativeH\\x00\\x12w\\n\\x0fperformative_pt\\x18\\n \\x01(\\x0b\\x32\\\\.aea.some_author.some_protocol_name.v1_0_0.TProtocolNoCtMessage.Performative_Pt_PerformativeH\\x00\\x1a\\x8c\\x01\\n\\x1cPerformative_Pt_Performative\\x12\\x15\\n\\rcontent_bytes\\x18\\x01 \\x01(\\x0c\\x12\\x13\\n\\x0b\\x63ontent_int\\x18\\x02 \\x01(\\x03\\x12\\x15\\n\\rcontent_float\\x18\\x03 \\x01(\\x02\\x12\\x14\\n\\x0c\\x63ontent_bool\\x18\\x04 \\x01(\\x08\\x12\\x13\\n\\x0b\\x63ontent_str\\x18\\x05 \\x01(\\t\\x1a\\xa8\\x02\\n\\x1dPerformative_Pct_Performative\\x12\\x19\\n\\x11\\x63ontent_set_bytes\\x18\\x01 \\x03(\\x0c\\x12\\x17\\n\\x0f\\x63ontent_set_int\\x18\\x02 \\x03(\\x03\\x12\\x19\\n\\x11\\x63ontent_set_float\\x18\\x03 \\x03(\\x02\\x12\\x18\\n\\x10\\x63ontent_set_bool\\x18\\x04 \\x03(\\x08\\x12\\x17\\n\\x0f\\x63ontent_set_str\\x18\\x05 \\x03(\\t\\x12\\x1a\\n\\x12\\x63ontent_list_bytes\\x18\\x06 \\x03(\\x0c\\x12\\x18\\n\\x10\\x63ontent_list_int\\x18\\x07 \\x03(\\x03\\x12\\x1a\\n\\x12\\x63ontent_list_float\\x18\\x08 \\x03(\\x02\\x12\\x19\\n\\x11\\x63ontent_list_bool\\x18\\t \\x03(\\x08\\x12\\x18\\n\\x10\\x63ontent_list_str\\x18\\n \\x03(\\t\\x1a\\xfc\\x18\\n\\x1dPerformative_Pmt_Performative\\x12\\x96\\x01\\n\\x16\\x63ontent_dict_int_bytes\\x18\\x01 \\x03(\\x0b\\x32v.aea.some_author.some_protocol_name.v1_0_0.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictIntBytesEntry\\x12\\x92\\x01\\n\\x14\\x63ontent_dict_int_int\\x18\\x02 \\x03(\\x0b\\x32t.aea.some_author.some_protocol_name.v1_0_0.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictIntIntEntry\\x12\\x96\\x01\\n\\x16\\x63ontent_dict_int_float\\x18\\x03 \\x03(\\x0b\\x32v.aea.some_author.some_protocol_name.v1_0_0.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictIntFloatEntry\\x12\\x94\\x01\\n\\x15\\x63ontent_dict_int_bool\\x18\\x04 \\x03(\\x0b\\x32u.aea.some_author.some_protocol_name.v1_0_0.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictIntBoolEntry\\x12\\x92\\x01\\n\\x14\\x63ontent_dict_int_str\\x18\\x05 \\x03(\\x0b\\x32t.aea.some_author.some_protocol_name.v1_0_0.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictIntStrEntry\\x12\\x98\\x01\\n\\x17\\x63ontent_dict_bool_bytes\\x18\\x06 \\x03(\\x0b\\x32w.aea.some_author.some_protocol_name.v1_0_0.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictBoolBytesEntry\\x12\\x94\\x01\\n\\x15\\x63ontent_dict_bool_int\\x18\\x07 \\x03(\\x0b\\x32u.aea.some_author.some_protocol_name.v1_0_0.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictBoolIntEntry\\x12\\x98\\x01\\n\\x17\\x63ontent_dict_bool_float\\x18\\x08 \\x03(\\x0b\\x32w.aea.some_author.some_protocol_name.v1_0_0.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictBoolFloatEntry\\x12\\x96\\x01\\n\\x16\\x63ontent_dict_bool_bool\\x18\\t \\x03(\\x0b\\x32v.aea.some_author.some_protocol_name.v1_0_0.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictBoolBoolEntry\\x12\\x94\\x01\\n\\x15\\x63ontent_dict_bool_str\\x18\\n \\x03(\\x0b\\x32u.aea.some_author.some_protocol_name.v1_0_0.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictBoolStrEntry\\x12\\x96\\x01\\n\\x16\\x63ontent_dict_str_bytes\\x18\\x0b \\x03(\\x0b\\x32v.aea.some_author.some_protocol_name.v1_0_0.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictStrBytesEntry\\x12\\x92\\x01\\n\\x14\\x63ontent_dict_str_int\\x18\\x0c \\x03(\\x0b\\x32t.aea.some_author.some_protocol_name.v1_0_0.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictStrIntEntry\\x12\\x96\\x01\\n\\x16\\x63ontent_dict_str_float\\x18\\r \\x03(\\x0b\\x32v.aea.some_author.some_protocol_name.v1_0_0.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictStrFloatEntry\\x12\\x94\\x01\\n\\x15\\x63ontent_dict_str_bool\\x18\\x0e \\x03(\\x0b\\x32u.aea.some_author.some_protocol_name.v1_0_0.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictStrBoolEntry\\x12\\x92\\x01\\n\\x14\\x63ontent_dict_str_str\\x18\\x0f \\x03(\\x0b\\x32t.aea.some_author.some_protocol_name.v1_0_0.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictStrStrEntry\\x1a:\\n\\x18\\x43ontentDictIntBytesEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\x03\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\x0c:\\x02\\x38\\x01\\x1a\\x38\\n\\x16\\x43ontentDictIntIntEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\x03\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\x03:\\x02\\x38\\x01\\x1a:\\n\\x18\\x43ontentDictIntFloatEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\x03\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\x02:\\x02\\x38\\x01\\x1a\\x39\\n\\x17\\x43ontentDictIntBoolEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\x03\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\x08:\\x02\\x38\\x01\\x1a\\x38\\n\\x16\\x43ontentDictIntStrEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\x03\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\t:\\x02\\x38\\x01\\x1a;\\n\\x19\\x43ontentDictBoolBytesEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\x08\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\x0c:\\x02\\x38\\x01\\x1a\\x39\\n\\x17\\x43ontentDictBoolIntEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\x08\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\x03:\\x02\\x38\\x01\\x1a;\\n\\x19\\x43ontentDictBoolFloatEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\x08\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\x02:\\x02\\x38\\x01\\x1a:\\n\\x18\\x43ontentDictBoolBoolEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\x08\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\x08:\\x02\\x38\\x01\\x1a\\x39\\n\\x17\\x43ontentDictBoolStrEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\x08\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\t:\\x02\\x38\\x01\\x1a:\\n\\x18\\x43ontentDictStrBytesEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\t\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\x0c:\\x02\\x38\\x01\\x1a\\x38\\n\\x16\\x43ontentDictStrIntEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\t\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\x03:\\x02\\x38\\x01\\x1a:\\n\\x18\\x43ontentDictStrFloatEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\t\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\x02:\\x02\\x38\\x01\\x1a\\x39\\n\\x17\\x43ontentDictStrBoolEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\t\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\x08:\\x02\\x38\\x01\\x1a\\x38\\n\\x16\\x43ontentDictStrStrEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\t\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\t:\\x02\\x38\\x01\\x1a\\xc1\\x12\\n\\x1cPerformative_Mt_Performative\\x12\"\\n\\x1a\\x63ontent_union_1_type_bytes\\x18\\x01 \\x01(\\x0c\\x12)\\n!content_union_1_type_bytes_is_set\\x18\\x02 \\x01(\\x08\\x12 \\n\\x18\\x63ontent_union_1_type_int\\x18\\x03 \\x01(\\x03\\x12\\'\\n\\x1f\\x63ontent_union_1_type_int_is_set\\x18\\x04 \\x01(\\x08\\x12\"\\n\\x1a\\x63ontent_union_1_type_float\\x18\\x05 \\x01(\\x02\\x12)\\n!content_union_1_type_float_is_set\\x18\\x06 \\x01(\\x08\\x12!\\n\\x19\\x63ontent_union_1_type_bool\\x18\\x07 \\x01(\\x08\\x12(\\n content_union_1_type_bool_is_set\\x18\\x08 \\x01(\\x08\\x12 \\n\\x18\\x63ontent_union_1_type_str\\x18\\t \\x01(\\t\\x12\\'\\n\\x1f\\x63ontent_union_1_type_str_is_set\\x18\\n \\x01(\\x08\\x12\\'\\n\\x1f\\x63ontent_union_1_type_set_of_int\\x18\\x0b \\x03(\\x03\\x12.\\n&content_union_1_type_set_of_int_is_set\\x18\\x0c \\x01(\\x08\\x12)\\n!content_union_1_type_list_of_bool\\x18\\r \\x03(\\x08\\x12\\x30\\n(content_union_1_type_list_of_bool_is_set\\x18\\x0e \\x01(\\x08\\x12\\xad\\x01\\n$content_union_1_type_dict_of_str_int\\x18\\x0f \\x03(\\x0b\\x32\\x7f.aea.some_author.some_protocol_name.v1_0_0.TProtocolNoCtMessage.Performative_Mt_Performative.ContentUnion1TypeDictOfStrIntEntry\\x12\\x33\\n+content_union_1_type_dict_of_str_int_is_set\\x18\\x10 \\x01(\\x08\\x12)\\n!content_union_2_type_set_of_bytes\\x18\\x11 \\x03(\\x0c\\x12\\x30\\n(content_union_2_type_set_of_bytes_is_set\\x18\\x12 \\x01(\\x08\\x12\\'\\n\\x1f\\x63ontent_union_2_type_set_of_int\\x18\\x13 \\x03(\\x03\\x12.\\n&content_union_2_type_set_of_int_is_set\\x18\\x14 \\x01(\\x08\\x12\\'\\n\\x1f\\x63ontent_union_2_type_set_of_str\\x18\\x15 \\x03(\\t\\x12.\\n&content_union_2_type_set_of_str_is_set\\x18\\x16 \\x01(\\x08\\x12*\\n\"content_union_2_type_list_of_float\\x18\\x17 \\x03(\\x02\\x12\\x31\\n)content_union_2_type_list_of_float_is_set\\x18\\x18 \\x01(\\x08\\x12)\\n!content_union_2_type_list_of_bool\\x18\\x19 \\x03(\\x08\\x12\\x30\\n(content_union_2_type_list_of_bool_is_set\\x18\\x1a \\x01(\\x08\\x12*\\n\"content_union_2_type_list_of_bytes\\x18\\x1b \\x03(\\x0c\\x12\\x31\\n)content_union_2_type_list_of_bytes_is_set\\x18\\x1c \\x01(\\x08\\x12\\xad\\x01\\n$content_union_2_type_dict_of_str_int\\x18\\x1d \\x03(\\x0b\\x32\\x7f.aea.some_author.some_protocol_name.v1_0_0.TProtocolNoCtMessage.Performative_Mt_Performative.ContentUnion2TypeDictOfStrIntEntry\\x12\\x33\\n+content_union_2_type_dict_of_str_int_is_set\\x18\\x1e \\x01(\\x08\\x12\\xb2\\x01\\n&content_union_2_type_dict_of_int_float\\x18\\x1f \\x03(\\x0b\\x32\\x81\\x01.aea.some_author.some_protocol_name.v1_0_0.TProtocolNoCtMessage.Performative_Mt_Performative.ContentUnion2TypeDictOfIntFloatEntry\\x12\\x35\\n-content_union_2_type_dict_of_int_float_is_set\\x18  \\x01(\\x08\\x12\\xb4\\x01\\n\\'content_union_2_type_dict_of_bool_bytes\\x18! \\x03(\\x0b\\x32\\x82\\x01.aea.some_author.some_protocol_name.v1_0_0.TProtocolNoCtMessage.Performative_Mt_Performative.ContentUnion2TypeDictOfBoolBytesEntry\\x12\\x36\\n.content_union_2_type_dict_of_bool_bytes_is_set\\x18\" \\x01(\\x08\\x1a\\x44\\n\"ContentUnion1TypeDictOfStrIntEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\t\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\x03:\\x02\\x38\\x01\\x1a\\x44\\n\"ContentUnion2TypeDictOfStrIntEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\t\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\x03:\\x02\\x38\\x01\\x1a\\x46\\n$ContentUnion2TypeDictOfIntFloatEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\x03\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\x02:\\x02\\x38\\x01\\x1aG\\n%ContentUnion2TypeDictOfBoolBytesEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\x08\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\x0c:\\x02\\x38\\x01\\x1a\\xcc\\x03\\n\\x1bPerformative_O_Performative\\x12\\x16\\n\\x0e\\x63ontent_o_bool\\x18\\x01 \\x01(\\x08\\x12\\x1d\\n\\x15\\x63ontent_o_bool_is_set\\x18\\x02 \\x01(\\x08\\x12\\x19\\n\\x11\\x63ontent_o_set_int\\x18\\x03 \\x03(\\x03\\x12 \\n\\x18\\x63ontent_o_set_int_is_set\\x18\\x04 \\x01(\\x08\\x12\\x1c\\n\\x14\\x63ontent_o_list_bytes\\x18\\x05 \\x03(\\x0c\\x12#\\n\\x1b\\x63ontent_o_list_bytes_is_set\\x18\\x06 \\x01(\\x08\\x12\\x93\\x01\\n\\x16\\x63ontent_o_dict_str_int\\x18\\x07 \\x03(\\x0b\\x32s.aea.some_author.some_protocol_name.v1_0_0.TProtocolNoCtMessage.Performative_O_Performative.ContentODictStrIntEntry\\x12%\\n\\x1d\\x63ontent_o_dict_str_int_is_set\\x18\\x08 \\x01(\\x08\\x1a\\x39\\n\\x17\\x43ontentODictStrIntEntry\\x12\\x0b\\n\\x03key\\x18\\x01 \\x01(\\t\\x12\\r\\n\\x05value\\x18\\x02 \\x01(\\x03:\\x02\\x38\\x01\\x1a*\\n(Performative_Empty_Contents_PerformativeB\\x0e\\n\\x0cperformativeb\\x06proto3'\n)\n\n\n_TPROTOCOLNOCTMESSAGE = DESCRIPTOR.message_types_by_name[\"TProtocolNoCtMessage\"]\n_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PT_PERFORMATIVE = (\n    _TPROTOCOLNOCTMESSAGE.nested_types_by_name[\"Performative_Pt_Performative\"]\n)\n_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PCT_PERFORMATIVE = (\n    _TPROTOCOLNOCTMESSAGE.nested_types_by_name[\"Performative_Pct_Performative\"]\n)\n_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE = (\n    _TPROTOCOLNOCTMESSAGE.nested_types_by_name[\"Performative_Pmt_Performative\"]\n)\n_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTBYTESENTRY = (\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE.nested_types_by_name[\n        \"ContentDictIntBytesEntry\"\n    ]\n)\n_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTINTENTRY = (\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE.nested_types_by_name[\n        \"ContentDictIntIntEntry\"\n    ]\n)\n_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTFLOATENTRY = (\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE.nested_types_by_name[\n        \"ContentDictIntFloatEntry\"\n    ]\n)\n_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTBOOLENTRY = (\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE.nested_types_by_name[\n        \"ContentDictIntBoolEntry\"\n    ]\n)\n_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTSTRENTRY = (\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE.nested_types_by_name[\n        \"ContentDictIntStrEntry\"\n    ]\n)\n_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLBYTESENTRY = (\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE.nested_types_by_name[\n        \"ContentDictBoolBytesEntry\"\n    ]\n)\n_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLINTENTRY = (\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE.nested_types_by_name[\n        \"ContentDictBoolIntEntry\"\n    ]\n)\n_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLFLOATENTRY = (\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE.nested_types_by_name[\n        \"ContentDictBoolFloatEntry\"\n    ]\n)\n_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLBOOLENTRY = (\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE.nested_types_by_name[\n        \"ContentDictBoolBoolEntry\"\n    ]\n)\n_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLSTRENTRY = (\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE.nested_types_by_name[\n        \"ContentDictBoolStrEntry\"\n    ]\n)\n_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRBYTESENTRY = (\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE.nested_types_by_name[\n        \"ContentDictStrBytesEntry\"\n    ]\n)\n_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRINTENTRY = (\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE.nested_types_by_name[\n        \"ContentDictStrIntEntry\"\n    ]\n)\n_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRFLOATENTRY = (\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE.nested_types_by_name[\n        \"ContentDictStrFloatEntry\"\n    ]\n)\n_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRBOOLENTRY = (\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE.nested_types_by_name[\n        \"ContentDictStrBoolEntry\"\n    ]\n)\n_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRSTRENTRY = (\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE.nested_types_by_name[\n        \"ContentDictStrStrEntry\"\n    ]\n)\n_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_MT_PERFORMATIVE = (\n    _TPROTOCOLNOCTMESSAGE.nested_types_by_name[\"Performative_Mt_Performative\"]\n)\n_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION1TYPEDICTOFSTRINTENTRY = _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_MT_PERFORMATIVE.nested_types_by_name[\n    \"ContentUnion1TypeDictOfStrIntEntry\"\n]\n_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFSTRINTENTRY = _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_MT_PERFORMATIVE.nested_types_by_name[\n    \"ContentUnion2TypeDictOfStrIntEntry\"\n]\n_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFINTFLOATENTRY = _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_MT_PERFORMATIVE.nested_types_by_name[\n    \"ContentUnion2TypeDictOfIntFloatEntry\"\n]\n_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFBOOLBYTESENTRY = _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_MT_PERFORMATIVE.nested_types_by_name[\n    \"ContentUnion2TypeDictOfBoolBytesEntry\"\n]\n_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_O_PERFORMATIVE = (\n    _TPROTOCOLNOCTMESSAGE.nested_types_by_name[\"Performative_O_Performative\"]\n)\n_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_O_PERFORMATIVE_CONTENTODICTSTRINTENTRY = (\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_O_PERFORMATIVE.nested_types_by_name[\n        \"ContentODictStrIntEntry\"\n    ]\n)\n_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_EMPTY_CONTENTS_PERFORMATIVE = (\n    _TPROTOCOLNOCTMESSAGE.nested_types_by_name[\n        \"Performative_Empty_Contents_Performative\"\n    ]\n)\nTProtocolNoCtMessage = _reflection.GeneratedProtocolMessageType(\n    \"TProtocolNoCtMessage\",\n    (_message.Message,),\n    {\n        \"Performative_Pt_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Performative_Pt_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PT_PERFORMATIVE,\n                \"__module__\": \"t_protocol_no_ct_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.some_author.some_protocol_name.v1_0_0.TProtocolNoCtMessage.Performative_Pt_Performative)\n            },\n        ),\n        \"Performative_Pct_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Performative_Pct_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PCT_PERFORMATIVE,\n                \"__module__\": \"t_protocol_no_ct_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.some_author.some_protocol_name.v1_0_0.TProtocolNoCtMessage.Performative_Pct_Performative)\n            },\n        ),\n        \"Performative_Pmt_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Performative_Pmt_Performative\",\n            (_message.Message,),\n            {\n                \"ContentDictIntBytesEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"ContentDictIntBytesEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTBYTESENTRY,\n                        \"__module__\": \"t_protocol_no_ct_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.some_author.some_protocol_name.v1_0_0.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictIntBytesEntry)\n                    },\n                ),\n                \"ContentDictIntIntEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"ContentDictIntIntEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTINTENTRY,\n                        \"__module__\": \"t_protocol_no_ct_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.some_author.some_protocol_name.v1_0_0.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictIntIntEntry)\n                    },\n                ),\n                \"ContentDictIntFloatEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"ContentDictIntFloatEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTFLOATENTRY,\n                        \"__module__\": \"t_protocol_no_ct_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.some_author.some_protocol_name.v1_0_0.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictIntFloatEntry)\n                    },\n                ),\n                \"ContentDictIntBoolEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"ContentDictIntBoolEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTBOOLENTRY,\n                        \"__module__\": \"t_protocol_no_ct_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.some_author.some_protocol_name.v1_0_0.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictIntBoolEntry)\n                    },\n                ),\n                \"ContentDictIntStrEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"ContentDictIntStrEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTSTRENTRY,\n                        \"__module__\": \"t_protocol_no_ct_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.some_author.some_protocol_name.v1_0_0.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictIntStrEntry)\n                    },\n                ),\n                \"ContentDictBoolBytesEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"ContentDictBoolBytesEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLBYTESENTRY,\n                        \"__module__\": \"t_protocol_no_ct_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.some_author.some_protocol_name.v1_0_0.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictBoolBytesEntry)\n                    },\n                ),\n                \"ContentDictBoolIntEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"ContentDictBoolIntEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLINTENTRY,\n                        \"__module__\": \"t_protocol_no_ct_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.some_author.some_protocol_name.v1_0_0.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictBoolIntEntry)\n                    },\n                ),\n                \"ContentDictBoolFloatEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"ContentDictBoolFloatEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLFLOATENTRY,\n                        \"__module__\": \"t_protocol_no_ct_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.some_author.some_protocol_name.v1_0_0.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictBoolFloatEntry)\n                    },\n                ),\n                \"ContentDictBoolBoolEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"ContentDictBoolBoolEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLBOOLENTRY,\n                        \"__module__\": \"t_protocol_no_ct_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.some_author.some_protocol_name.v1_0_0.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictBoolBoolEntry)\n                    },\n                ),\n                \"ContentDictBoolStrEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"ContentDictBoolStrEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLSTRENTRY,\n                        \"__module__\": \"t_protocol_no_ct_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.some_author.some_protocol_name.v1_0_0.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictBoolStrEntry)\n                    },\n                ),\n                \"ContentDictStrBytesEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"ContentDictStrBytesEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRBYTESENTRY,\n                        \"__module__\": \"t_protocol_no_ct_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.some_author.some_protocol_name.v1_0_0.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictStrBytesEntry)\n                    },\n                ),\n                \"ContentDictStrIntEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"ContentDictStrIntEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRINTENTRY,\n                        \"__module__\": \"t_protocol_no_ct_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.some_author.some_protocol_name.v1_0_0.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictStrIntEntry)\n                    },\n                ),\n                \"ContentDictStrFloatEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"ContentDictStrFloatEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRFLOATENTRY,\n                        \"__module__\": \"t_protocol_no_ct_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.some_author.some_protocol_name.v1_0_0.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictStrFloatEntry)\n                    },\n                ),\n                \"ContentDictStrBoolEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"ContentDictStrBoolEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRBOOLENTRY,\n                        \"__module__\": \"t_protocol_no_ct_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.some_author.some_protocol_name.v1_0_0.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictStrBoolEntry)\n                    },\n                ),\n                \"ContentDictStrStrEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"ContentDictStrStrEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRSTRENTRY,\n                        \"__module__\": \"t_protocol_no_ct_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.some_author.some_protocol_name.v1_0_0.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictStrStrEntry)\n                    },\n                ),\n                \"DESCRIPTOR\": _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE,\n                \"__module__\": \"t_protocol_no_ct_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.some_author.some_protocol_name.v1_0_0.TProtocolNoCtMessage.Performative_Pmt_Performative)\n            },\n        ),\n        \"Performative_Mt_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Performative_Mt_Performative\",\n            (_message.Message,),\n            {\n                \"ContentUnion1TypeDictOfStrIntEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"ContentUnion1TypeDictOfStrIntEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION1TYPEDICTOFSTRINTENTRY,\n                        \"__module__\": \"t_protocol_no_ct_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.some_author.some_protocol_name.v1_0_0.TProtocolNoCtMessage.Performative_Mt_Performative.ContentUnion1TypeDictOfStrIntEntry)\n                    },\n                ),\n                \"ContentUnion2TypeDictOfStrIntEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"ContentUnion2TypeDictOfStrIntEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFSTRINTENTRY,\n                        \"__module__\": \"t_protocol_no_ct_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.some_author.some_protocol_name.v1_0_0.TProtocolNoCtMessage.Performative_Mt_Performative.ContentUnion2TypeDictOfStrIntEntry)\n                    },\n                ),\n                \"ContentUnion2TypeDictOfIntFloatEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"ContentUnion2TypeDictOfIntFloatEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFINTFLOATENTRY,\n                        \"__module__\": \"t_protocol_no_ct_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.some_author.some_protocol_name.v1_0_0.TProtocolNoCtMessage.Performative_Mt_Performative.ContentUnion2TypeDictOfIntFloatEntry)\n                    },\n                ),\n                \"ContentUnion2TypeDictOfBoolBytesEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"ContentUnion2TypeDictOfBoolBytesEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFBOOLBYTESENTRY,\n                        \"__module__\": \"t_protocol_no_ct_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.some_author.some_protocol_name.v1_0_0.TProtocolNoCtMessage.Performative_Mt_Performative.ContentUnion2TypeDictOfBoolBytesEntry)\n                    },\n                ),\n                \"DESCRIPTOR\": _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_MT_PERFORMATIVE,\n                \"__module__\": \"t_protocol_no_ct_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.some_author.some_protocol_name.v1_0_0.TProtocolNoCtMessage.Performative_Mt_Performative)\n            },\n        ),\n        \"Performative_O_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Performative_O_Performative\",\n            (_message.Message,),\n            {\n                \"ContentODictStrIntEntry\": _reflection.GeneratedProtocolMessageType(\n                    \"ContentODictStrIntEntry\",\n                    (_message.Message,),\n                    {\n                        \"DESCRIPTOR\": _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_O_PERFORMATIVE_CONTENTODICTSTRINTENTRY,\n                        \"__module__\": \"t_protocol_no_ct_pb2\"\n                        # @@protoc_insertion_point(class_scope:aea.some_author.some_protocol_name.v1_0_0.TProtocolNoCtMessage.Performative_O_Performative.ContentODictStrIntEntry)\n                    },\n                ),\n                \"DESCRIPTOR\": _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_O_PERFORMATIVE,\n                \"__module__\": \"t_protocol_no_ct_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.some_author.some_protocol_name.v1_0_0.TProtocolNoCtMessage.Performative_O_Performative)\n            },\n        ),\n        \"Performative_Empty_Contents_Performative\": _reflection.GeneratedProtocolMessageType(\n            \"Performative_Empty_Contents_Performative\",\n            (_message.Message,),\n            {\n                \"DESCRIPTOR\": _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_EMPTY_CONTENTS_PERFORMATIVE,\n                \"__module__\": \"t_protocol_no_ct_pb2\"\n                # @@protoc_insertion_point(class_scope:aea.some_author.some_protocol_name.v1_0_0.TProtocolNoCtMessage.Performative_Empty_Contents_Performative)\n            },\n        ),\n        \"DESCRIPTOR\": _TPROTOCOLNOCTMESSAGE,\n        \"__module__\": \"t_protocol_no_ct_pb2\"\n        # @@protoc_insertion_point(class_scope:aea.some_author.some_protocol_name.v1_0_0.TProtocolNoCtMessage)\n    },\n)\n_sym_db.RegisterMessage(TProtocolNoCtMessage)\n_sym_db.RegisterMessage(TProtocolNoCtMessage.Performative_Pt_Performative)\n_sym_db.RegisterMessage(TProtocolNoCtMessage.Performative_Pct_Performative)\n_sym_db.RegisterMessage(TProtocolNoCtMessage.Performative_Pmt_Performative)\n_sym_db.RegisterMessage(\n    TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictIntBytesEntry\n)\n_sym_db.RegisterMessage(\n    TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictIntIntEntry\n)\n_sym_db.RegisterMessage(\n    TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictIntFloatEntry\n)\n_sym_db.RegisterMessage(\n    TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictIntBoolEntry\n)\n_sym_db.RegisterMessage(\n    TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictIntStrEntry\n)\n_sym_db.RegisterMessage(\n    TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictBoolBytesEntry\n)\n_sym_db.RegisterMessage(\n    TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictBoolIntEntry\n)\n_sym_db.RegisterMessage(\n    TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictBoolFloatEntry\n)\n_sym_db.RegisterMessage(\n    TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictBoolBoolEntry\n)\n_sym_db.RegisterMessage(\n    TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictBoolStrEntry\n)\n_sym_db.RegisterMessage(\n    TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictStrBytesEntry\n)\n_sym_db.RegisterMessage(\n    TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictStrIntEntry\n)\n_sym_db.RegisterMessage(\n    TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictStrFloatEntry\n)\n_sym_db.RegisterMessage(\n    TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictStrBoolEntry\n)\n_sym_db.RegisterMessage(\n    TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictStrStrEntry\n)\n_sym_db.RegisterMessage(TProtocolNoCtMessage.Performative_Mt_Performative)\n_sym_db.RegisterMessage(\n    TProtocolNoCtMessage.Performative_Mt_Performative.ContentUnion1TypeDictOfStrIntEntry\n)\n_sym_db.RegisterMessage(\n    TProtocolNoCtMessage.Performative_Mt_Performative.ContentUnion2TypeDictOfStrIntEntry\n)\n_sym_db.RegisterMessage(\n    TProtocolNoCtMessage.Performative_Mt_Performative.ContentUnion2TypeDictOfIntFloatEntry\n)\n_sym_db.RegisterMessage(\n    TProtocolNoCtMessage.Performative_Mt_Performative.ContentUnion2TypeDictOfBoolBytesEntry\n)\n_sym_db.RegisterMessage(TProtocolNoCtMessage.Performative_O_Performative)\n_sym_db.RegisterMessage(\n    TProtocolNoCtMessage.Performative_O_Performative.ContentODictStrIntEntry\n)\n_sym_db.RegisterMessage(TProtocolNoCtMessage.Performative_Empty_Contents_Performative)\n\nif _descriptor._USE_C_DESCRIPTORS == False:\n\n    DESCRIPTOR._options = None\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTBYTESENTRY._options = (\n        None\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTBYTESENTRY._serialized_options = (\n        b\"8\\001\"\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTINTENTRY._options = (\n        None\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTINTENTRY._serialized_options = (\n        b\"8\\001\"\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTFLOATENTRY._options = (\n        None\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTFLOATENTRY._serialized_options = (\n        b\"8\\001\"\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTBOOLENTRY._options = (\n        None\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTBOOLENTRY._serialized_options = (\n        b\"8\\001\"\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTSTRENTRY._options = (\n        None\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTSTRENTRY._serialized_options = (\n        b\"8\\001\"\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLBYTESENTRY._options = (\n        None\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLBYTESENTRY._serialized_options = (\n        b\"8\\001\"\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLINTENTRY._options = (\n        None\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLINTENTRY._serialized_options = (\n        b\"8\\001\"\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLFLOATENTRY._options = (\n        None\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLFLOATENTRY._serialized_options = (\n        b\"8\\001\"\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLBOOLENTRY._options = (\n        None\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLBOOLENTRY._serialized_options = (\n        b\"8\\001\"\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLSTRENTRY._options = (\n        None\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLSTRENTRY._serialized_options = (\n        b\"8\\001\"\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRBYTESENTRY._options = (\n        None\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRBYTESENTRY._serialized_options = (\n        b\"8\\001\"\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRINTENTRY._options = (\n        None\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRINTENTRY._serialized_options = (\n        b\"8\\001\"\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRFLOATENTRY._options = (\n        None\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRFLOATENTRY._serialized_options = (\n        b\"8\\001\"\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRBOOLENTRY._options = (\n        None\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRBOOLENTRY._serialized_options = (\n        b\"8\\001\"\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRSTRENTRY._options = (\n        None\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRSTRENTRY._serialized_options = (\n        b\"8\\001\"\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION1TYPEDICTOFSTRINTENTRY._options = (\n        None\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION1TYPEDICTOFSTRINTENTRY._serialized_options = (\n        b\"8\\001\"\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFSTRINTENTRY._options = (\n        None\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFSTRINTENTRY._serialized_options = (\n        b\"8\\001\"\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFINTFLOATENTRY._options = (\n        None\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFINTFLOATENTRY._serialized_options = (\n        b\"8\\001\"\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFBOOLBYTESENTRY._options = (\n        None\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFBOOLBYTESENTRY._serialized_options = (\n        b\"8\\001\"\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_O_PERFORMATIVE_CONTENTODICTSTRINTENTRY._options = (\n        None\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_O_PERFORMATIVE_CONTENTODICTSTRINTENTRY._serialized_options = (\n        b\"8\\001\"\n    )\n    _TPROTOCOLNOCTMESSAGE._serialized_start = 70\n    _TPROTOCOLNOCTMESSAGE._serialized_end = 7381\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PT_PERFORMATIVE._serialized_start = 848\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PT_PERFORMATIVE._serialized_end = 988\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PCT_PERFORMATIVE._serialized_start = 991\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PCT_PERFORMATIVE._serialized_end = 1287\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE._serialized_start = 1290\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE._serialized_end = 4486\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTBYTESENTRY._serialized_start = (\n        3598\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTBYTESENTRY._serialized_end = (\n        3656\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTINTENTRY._serialized_start = (\n        3658\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTINTENTRY._serialized_end = (\n        3714\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTFLOATENTRY._serialized_start = (\n        3716\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTFLOATENTRY._serialized_end = (\n        3774\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTBOOLENTRY._serialized_start = (\n        3776\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTBOOLENTRY._serialized_end = (\n        3833\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTSTRENTRY._serialized_start = (\n        3835\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTSTRENTRY._serialized_end = (\n        3891\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLBYTESENTRY._serialized_start = (\n        3893\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLBYTESENTRY._serialized_end = (\n        3952\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLINTENTRY._serialized_start = (\n        3954\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLINTENTRY._serialized_end = (\n        4011\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLFLOATENTRY._serialized_start = (\n        4013\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLFLOATENTRY._serialized_end = (\n        4072\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLBOOLENTRY._serialized_start = (\n        4074\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLBOOLENTRY._serialized_end = (\n        4132\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLSTRENTRY._serialized_start = (\n        4134\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLSTRENTRY._serialized_end = (\n        4191\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRBYTESENTRY._serialized_start = (\n        4193\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRBYTESENTRY._serialized_end = (\n        4251\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRINTENTRY._serialized_start = (\n        4253\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRINTENTRY._serialized_end = (\n        4309\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRFLOATENTRY._serialized_start = (\n        4311\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRFLOATENTRY._serialized_end = (\n        4369\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRBOOLENTRY._serialized_start = (\n        4371\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRBOOLENTRY._serialized_end = (\n        4428\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRSTRENTRY._serialized_start = (\n        4430\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRSTRENTRY._serialized_end = (\n        4486\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_MT_PERFORMATIVE._serialized_start = 4489\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_MT_PERFORMATIVE._serialized_end = 6858\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION1TYPEDICTOFSTRINTENTRY._serialized_start = (\n        6575\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION1TYPEDICTOFSTRINTENTRY._serialized_end = (\n        6643\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFSTRINTENTRY._serialized_start = (\n        6645\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFSTRINTENTRY._serialized_end = (\n        6713\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFINTFLOATENTRY._serialized_start = (\n        6715\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFINTFLOATENTRY._serialized_end = (\n        6785\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFBOOLBYTESENTRY._serialized_start = (\n        6787\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFBOOLBYTESENTRY._serialized_end = (\n        6858\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_O_PERFORMATIVE._serialized_start = 6861\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_O_PERFORMATIVE._serialized_end = 7321\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_O_PERFORMATIVE_CONTENTODICTSTRINTENTRY._serialized_start = (\n        7264\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_O_PERFORMATIVE_CONTENTODICTSTRINTENTRY._serialized_end = (\n        7321\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_EMPTY_CONTENTS_PERFORMATIVE._serialized_start = (\n        7323\n    )\n    _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_EMPTY_CONTENTS_PERFORMATIVE._serialized_end = (\n        7365\n    )\n# @@protoc_insertion_point(module_scope)\n"
  },
  {
    "path": "tests/data/gym-connection.yaml",
    "content": "name: gym\nauthor: fetchai\nversion: 0.1.0\ntype: connection\nlicense: Apache-2.0\nfingerprint:\n  __init__.py: QmWwxj1hGGZNteCvRtZxwtY9PuEKsrWsEmMWCKwiYCdvRR\n  connection.py: QmPgSzbkwRE9CJ6sve7gvS62M3VdcBMfTozHdSgCnb7FPY\nfingerprint_ignore_patterns: []\naea_version: '>=1.0.0, <2.0.0'\ndescription: \"The gym connection wraps an OpenAI gym.\"\nclass_name: GymConnection\nconnections: []\nprotocols:\n- fetchai/gym:1.1.7\nrestricted_to_protocols: [\"fetchai/gym:1.1.7\"]\nexcluded_protocols: []\nconfig:\n  env: 'gyms.env.BanditNArmedRandom'\ndependencies:\n  gym: {}\nis_abstract: false"
  },
  {
    "path": "tests/data/hashes.csv",
    "content": "dummy_author/agents/dummy_aea,Qmdh3dsyHEGYVyXgjbgnMd32D7zPrr6MqNGJ4Ye2gxPsVv\ndummy_author/skills/dummy_skill,QmX4qGcgk6Rs7mXszSWGXknzEabQJ44PAcw8YinWe2nRyB\nfetchai/connections/dummy_connection,QmNwX9YPbjQER5hypZk7P6kmi4Lt3Z3VuATXzNiCtzrTSR\nfetchai/contracts/dummy_contract,QmSMqYSAdM6mfA5beVS8XLjqYoCyzyv8aqq1YQtKZFf6vm\nfetchai/protocols/t_protocol,QmcsHPDZjVL4SfVJhyyJfHgUxqfhDA7JM6rR7DwtRraRdj\nfetchai/protocols/t_protocol_no_ct,QmfS8z6CiTRFUwduco5F5iFKtj5CKDaeKPdrvqbhyE7Qvn\nfetchai/skills/dependencies_skill,QmYmZt4oYbtRod6rjeGyeojCoPDmgzFaWTK322oFS5vf3a\nfetchai/skills/exception_skill,QmX7kNkQkcz23vtFExC9rpBN119atNHF8T8viqo2u9yrp8\n"
  },
  {
    "path": "tests/data/petstore_sim.yaml",
    "content": "openapi: \"3.0.0\"\ninfo:\n  version: 1.0.0\n  title: Swagger Petstore\n  license:\n    name: MIT\nservers:\n  - url: ''\npaths:\n  /pets:\n    get:\n      summary: List all pets\n      operationId: listPets\n      tags:\n        - pets\n      parameters:\n        - name: limit\n          in: query\n          description: How many items to return at one time (max 100)\n          required: false\n          schema:\n            type: integer\n            format: int32\n      responses:\n        '200':\n          description: A paged array of pets\n          headers:\n            x-next:\n              description: A link to the next page of responses\n              schema:\n                type: string\n          content:\n            application/json:\n              schema:\n                $ref: \"#/components/schemas/Pets\"\n        default:\n          description: unexpected error\n          content:\n            application/json:\n              schema:\n                $ref: \"#/components/schemas/Error\"\n    post:\n      summary: Create a pet\n      operationId: createPets\n      tags:\n        - pets\n      responses:\n        '201':\n          description: Null response\n        default:\n          description: unexpected error\n          content:\n            application/json:\n              schema:\n                $ref: \"#/components/schemas/Error\"\n  /pets/{petId}:\n    get:\n      summary: Info for a specific pet\n      operationId: showPetById\n      tags:\n        - pets\n      parameters:\n        - name: petId\n          in: path\n          required: true\n          description: The id of the pet to retrieve\n          schema:\n            type: string\n      responses:\n        '200':\n          description: Expected response to a valid request\n          content:\n            application/json:\n              schema:\n                $ref: \"#/components/schemas/Pet\"\n        default:\n          description: unexpected error\n          content:\n            application/json:\n              schema:\n                $ref: \"#/components/schemas/Error\"\ncomponents:\n  schemas:\n    Pet:\n      type: object\n      required:\n        - id\n        - name\n      properties:\n        id:\n          type: integer\n          format: int64\n        name:\n          type: string\n        tag:\n          type: string\n    Pets:\n      type: array\n      items:\n        $ref: \"#/components/schemas/Pet\"\n    Error:\n      type: object\n      required:\n        - code\n        - message\n      properties:\n        code:\n          type: integer\n          format: int32\n        message:\n          type: string"
  },
  {
    "path": "tests/data/sample_specification.yaml",
    "content": "---\nname: t_protocol\nauthor: fetchai\nversion: 0.1.0\nlicense: Apache-2.0\nprotocol_specification_id: some_author/some_protocol_name:1.0.0\naea_version: '>=1.0.0, <2.0.0'\ndescription: 'A protocol for testing purposes.'\nspeech_acts:\n  performative_ct:\n    content_ct: ct:DataModel\n  performative_pt:\n    content_bytes: pt:bytes\n    content_int: pt:int\n    content_float: pt:float\n    content_bool: pt:bool\n    content_str: pt:str\n  performative_pct:\n#    content_set_ct: pt:set[ct:DataModel] # custom type inside of set, list, and dict isn't allowed.\n    content_set_bytes: pt:set[pt:bytes]\n    content_set_int: pt:set[pt:int]\n    content_set_float: pt:set[pt:float]\n    content_set_bool: pt:set[pt:bool]\n    content_set_str: pt:set[pt:str]\n#    content_list_ct: pt:list[ct:DataModel] # custom type inside of set, list, and dict isn't allowed.\n    content_list_bytes: pt:list[pt:bytes]\n    content_list_int: pt:list[pt:int]\n    content_list_float: pt:list[pt:float]\n    content_list_bool: pt:list[pt:bool]\n    content_list_str: pt:list[pt:str]\n  performative_pmt:\n#    custom type inside of set, list, and dict isn't allowed.\n#    content_dict_int_ct: pt:dict[pt:int, ct:DataModel]\n#    content_dict_ct_ct: pt:dict[ct:DataModel, ct:DataModel]\n#    content_dict_ct_bool: pt:dict[ct:DataModel, pt:bool]\n#    invalid in protobuf (key in map<X, Y> cannot be 'bytes', 'float', 'double', 'message')\n#    content_dict_bytes_bytes: pt:dict[pt:bytes, pt:bytes]\n#    content_dict_bytes_int: pt:dict[pt:bytes, pt:int]\n#    content_dict_bytes_float: pt:dict[pt:bytes, pt:float]\n#    content_dict_bytes_bool: pt:dict[pt:bytes, pt:bool]\n#    content_dict_bytes_str: pt:dict[pt:bytes, pt:str]\n    content_dict_int_bytes: pt:dict[pt:int, pt:bytes]\n    content_dict_int_int: pt:dict[pt:int, pt:int]\n    content_dict_int_float: pt:dict[pt:int, pt:float]\n    content_dict_int_bool: pt:dict[pt:int, pt:bool]\n    content_dict_int_str: pt:dict[pt:int, pt:str]\n#    invalid in protobuf (key in map<X, Y> cannot be 'bytes', 'float', 'double', 'message')\n#    content_dict_float_bytes: pt:dict[pt:float, pt:bytes]\n#    content_dict_float_int: pt:dict[pt:float, pt:int]\n#    content_dict_float_float: pt:dict[pt:float, pt:float]\n#    content_dict_float_bool: pt:dict[pt:float, pt:bool]\n#    content_dict_float_str: pt:dict[pt:float, pt:str]\n    content_dict_bool_bytes: pt:dict[pt:bool, pt:bytes]\n    content_dict_bool_int: pt:dict[pt:bool, pt:int]\n    content_dict_bool_float: pt:dict[pt:bool, pt:float]\n    content_dict_bool_bool: pt:dict[pt:bool, pt:bool]\n    content_dict_bool_str: pt:dict[pt:bool, pt:str]\n    content_dict_str_bytes: pt:dict[pt:str, pt:bytes]\n    content_dict_str_int: pt:dict[pt:str, pt:int]\n    content_dict_str_float: pt:dict[pt:str, pt:float]\n    content_dict_str_bool: pt:dict[pt:str, pt:bool]\n    content_dict_str_str: pt:dict[pt:str, pt:str]\n  performative_mt:\n    content_union_1: pt:union[ct:DataModel1, pt:bytes, pt:int, pt:float, pt:bool, pt:str, pt:set[pt:int], pt:list[pt:bool], pt:dict[pt:str, pt:int]]\n    content_union_2: pt:union[pt:set[pt:bytes], pt:set[pt:int], pt:set[pt:str], pt:list[pt:float], pt:list[pt:bool], pt:list[pt:bytes], pt:dict[pt:str, pt:int], pt:dict[pt:int, pt:float], pt:dict[pt:bool, pt:bytes], pt:int]\n    content_union_3: pt:union[ct:DataModel2, ct:DataModel3]\n  performative_o:\n    content_o_ct: pt:optional[ct:DataModel4]\n    content_o_bool: pt:optional[pt:bool]\n    content_o_set_int: pt:optional[pt:set[pt:int]]\n    content_o_list_bytes: pt:optional[pt:list[pt:bytes]]\n    content_o_dict_str_int: pt:optional[pt:dict[pt:str, pt:int]]\n#    union does not work properly in the generator\n#    content_o_union: pt:optional[pt:union[pt:str, pt:dict[pt:str,pt:int], pt:set[pt:int], pt:set[pt:bytes], pt:list[pt:bool], pt:dict[pt:str, pt:float]]]\n  performative_empty_contents: {}\n...\n---\nct:DataModel: |\n  bytes bytes_field = 1;\n  int64 int_field = 2;\n  float float_field = 3;\n  bool bool_field = 4;\n  string str_field = 5;\n  repeated int64 set_field = 6;\n  repeated string list_field = 7;\n  map<int64, bool> dict_field = 8;\nct:DataModel1: |\n  bytes bytes_field = 1;\n  int64 int_field = 2;\n  float float_field = 3;\n  bool bool_field = 4;\n  string str_field = 5;\n  repeated int64 set_field = 6;\n  repeated string list_field = 7;\n  map<int64, bool> dict_field = 8;\nct:DataModel2: |\n  bytes bytes_field = 1;\n  int64 int_field = 2;\n  float float_field = 3;\n  bool bool_field = 4;\n  string str_field = 5;\n  repeated int64 set_field = 6;\n  repeated string list_field = 7;\n  map<int64, bool> dict_field = 8;\nct:DataModel3: |\n  bytes bytes_field = 1;\n  int64 int_field = 2;\n  float float_field = 3;\n  bool bool_field = 4;\n  string str_field = 5;\n  repeated int64 set_field = 6;\n  repeated string list_field = 7;\n  map<int64, bool> dict_field = 8;\nct:DataModel4: |\n  bytes bytes_field = 1;\n  int64 int_field = 2;\n  float float_field = 3;\n  bool bool_field = 4;\n  string str_field = 5;\n  repeated int64 set_field = 6;\n  repeated string list_field = 7;\n  map<int64, bool> dict_field = 8;\n...\n---\ninitiation: [performative_ct, performative_pt]\nreply:\n  performative_ct: [performative_pct]\n  performative_pt: [performative_pt, performative_pmt]\n  performative_pct: [performative_mt, performative_o]\n  performative_pmt: [performative_mt, performative_o]\n  performative_mt: []\n  performative_o: []\n  performative_empty_contents: [performative_empty_contents]\ntermination: [performative_mt, performative_o]\nroles: {role_1, role_2}\nend_states: [end_state_1, end_state_2, end_state_3]\nkeep_terminal_state_dialogues: true\n...\n"
  },
  {
    "path": "tests/data/sample_specification_no_custom_types.yaml",
    "content": "---\nname: t_protocol_no_ct\nauthor: fetchai\nversion: 0.1.0\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nprotocol_specification_id: some_author/some_protocol_name:1.0.0\ndescription: 'A protocol for testing purposes.'\nspeech_acts:\n  performative_pt:\n    content_bytes: pt:bytes\n    content_int: pt:int\n    content_float: pt:float\n    content_bool: pt:bool\n    content_str: pt:str\n  performative_pct:\n#    content_set_ct: pt:set[ct:DataModel] # custom type inside of set, list, and dict isn't allowed.\n    content_set_bytes: pt:set[pt:bytes]\n    content_set_int: pt:set[pt:int]\n    content_set_float: pt:set[pt:float]\n    content_set_bool: pt:set[pt:bool]\n    content_set_str: pt:set[pt:str]\n#    content_list_ct: pt:list[ct:DataModel] # custom type inside of set, list, and dict isn't allowed.\n    content_list_bytes: pt:list[pt:bytes]\n    content_list_int: pt:list[pt:int]\n    content_list_float: pt:list[pt:float]\n    content_list_bool: pt:list[pt:bool]\n    content_list_str: pt:list[pt:str]\n  performative_pmt:\n#    custom type inside of set, list, and dict isn't allowed.\n#    content_dict_int_ct: pt:dict[pt:int, ct:DataModel]\n#    content_dict_ct_ct: pt:dict[ct:DataModel, ct:DataModel]\n#    content_dict_ct_bool: pt:dict[ct:DataModel, pt:bool]\n#    invalid in protobuf (key in map<X, Y> cannot be 'bytes', 'float', 'double', 'message')\n#    content_dict_bytes_bytes: pt:dict[pt:bytes, pt:bytes]\n#    content_dict_bytes_int: pt:dict[pt:bytes, pt:int]\n#    content_dict_bytes_float: pt:dict[pt:bytes, pt:float]\n#    content_dict_bytes_bool: pt:dict[pt:bytes, pt:bool]\n#    content_dict_bytes_str: pt:dict[pt:bytes, pt:str]\n    content_dict_int_bytes: pt:dict[pt:int, pt:bytes]\n    content_dict_int_int: pt:dict[pt:int, pt:int]\n    content_dict_int_float: pt:dict[pt:int, pt:float]\n    content_dict_int_bool: pt:dict[pt:int, pt:bool]\n    content_dict_int_str: pt:dict[pt:int, pt:str]\n#    invalid in protobuf (key in map<X, Y> cannot be 'bytes', 'float', 'double', 'message')\n#    content_dict_float_bytes: pt:dict[pt:float, pt:bytes]\n#    content_dict_float_int: pt:dict[pt:float, pt:int]\n#    content_dict_float_float: pt:dict[pt:float, pt:float]\n#    content_dict_float_bool: pt:dict[pt:float, pt:bool]\n#    content_dict_float_str: pt:dict[pt:float, pt:str]\n    content_dict_bool_bytes: pt:dict[pt:bool, pt:bytes]\n    content_dict_bool_int: pt:dict[pt:bool, pt:int]\n    content_dict_bool_float: pt:dict[pt:bool, pt:float]\n    content_dict_bool_bool: pt:dict[pt:bool, pt:bool]\n    content_dict_bool_str: pt:dict[pt:bool, pt:str]\n    content_dict_str_bytes: pt:dict[pt:str, pt:bytes]\n    content_dict_str_int: pt:dict[pt:str, pt:int]\n    content_dict_str_float: pt:dict[pt:str, pt:float]\n    content_dict_str_bool: pt:dict[pt:str, pt:bool]\n    content_dict_str_str: pt:dict[pt:str, pt:str]\n  performative_mt:\n    content_union_1: pt:union[pt:bytes, pt:int, pt:float, pt:bool, pt:str, pt:set[pt:int], pt:list[pt:bool], pt:dict[pt:str, pt:int]]\n    content_union_2: pt:union[pt:set[pt:bytes], pt:set[pt:int], pt:set[pt:str], pt:list[pt:float], pt:list[pt:bool], pt:list[pt:bytes], pt:dict[pt:str, pt:int], pt:dict[pt:int, pt:float], pt:dict[pt:bool, pt:bytes]]\n  performative_o:\n    content_o_bool: pt:optional[pt:bool]\n    content_o_set_int: pt:optional[pt:set[pt:int]]\n    content_o_list_bytes: pt:optional[pt:list[pt:bytes]]\n    content_o_dict_str_int: pt:optional[pt:dict[pt:str, pt:int]]\n#    union does not work properly in the generator\n#    content_o_union: pt:optional[pt:union[pt:str, pt:dict[pt:str,pt:int], pt:set[pt:int], pt:set[pt:bytes], pt:list[pt:bool], pt:dict[pt:str, pt:float]]]\n  performative_empty_contents: {}\n...\n---\n...\n---\ninitiation: [performative_pt]\nreply:\n  performative_pt: [performative_pt, performative_pct, performative_pmt]\n  performative_pct: [performative_mt, performative_o]\n  performative_pmt: [performative_mt, performative_o]\n  performative_mt: []\n  performative_o: []\n  performative_empty_contents: [performative_empty_contents]\ntermination: [performative_mt, performative_o]\nroles: {role_1, role_2}\nend_states: [end_state_1, end_state_2, end_state_3]\nkeep_terminal_state_dialogues: true\n...\n"
  },
  {
    "path": "tests/list_of_packages_for_aea_tests.txt",
    "content": "./fetchai/skills/weather_client/skill.yaml\n./fetchai/skills/generic_buyer/skill.yaml\n./fetchai/skills/generic_seller/skill.yaml\n./fetchai/skills/erc1155_client/skill.yaml\n./fetchai/skills/weather_station/skill.yaml\n./fetchai/skills/error_test_skill/skill.yaml\n./fetchai/skills/error/skill.yaml\n./fetchai/skills/gym/skill.yaml\n./fetchai/skills/echo/skill.yaml\n./fetchai/skills/task_test_skill/skill.yaml\n./fetchai/protocols/fipa/protocol.yaml\n./fetchai/protocols/http/protocol.yaml\n./fetchai/protocols/contract_api/protocol.yaml\n./fetchai/protocols/state_update/protocol.yaml\n./fetchai/protocols/tac/protocol.yaml\n./fetchai/protocols/acn/protocol.yaml\n./fetchai/protocols/register/protocol.yaml\n./fetchai/protocols/ledger_api/protocol.yaml\n./fetchai/protocols/oef_search/protocol.yaml\n./fetchai/protocols/signing/protocol.yaml\n./fetchai/protocols/default/protocol.yaml\n./fetchai/protocols/gym/protocol.yaml\n./fetchai/contracts/erc1155/contract.yaml\n./fetchai/agents/weather_client/aea-config.yaml\n./fetchai/agents/generic_buyer/aea-config.yaml\n./fetchai/agents/generic_seller/aea-config.yaml\n./fetchai/agents/error_test/aea-config.yaml\n./fetchai/agents/my_first_aea/aea-config.yaml\n./fetchai/agents/weather_station/aea-config.yaml\n./fetchai/connections/soef/connection.yaml\n./fetchai/connections/oef/connection.yaml\n./fetchai/connections/tcp/connection.yaml\n./fetchai/connections/ledger/connection.yaml\n./fetchai/connections/p2p_libp2p_client/connection.yaml\n./fetchai/connections/p2p_stub/connection.yaml\n./fetchai/connections/p2p_libp2p_mailbox/connection.yaml\n./fetchai/connections/stub/connection.yaml\n./fetchai/connections/http_client/connection.yaml\n./fetchai/connections/local/connection.yaml\n./fetchai/connections/p2p_libp2p/connection.yaml\n./fetchai/connections/p2p_libp2p/libp2p_node/protocols/acn/v1_0_0/acn.yaml\n./fetchai/connections/gym/connection.yaml\n./fetchai/connections/http_server/connection.yaml\n\n"
  },
  {
    "path": "tests/oracle_contract_address.txt",
    "content": "fetch14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9szlkpka"
  },
  {
    "path": "tests/test_aea/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"The tests module contains the tests of the AEA package.\"\"\"\n"
  },
  {
    "path": "tests/test_aea/test_act_storage.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains tests behaviour storage access.\"\"\"\nimport os\nfrom typing import List, Set\n\nimport pytest\n\nfrom aea.aea import AEA\nfrom aea.aea_builder import AEABuilder\nfrom aea.configurations.base import SkillConfig\nfrom aea.configurations.constants import DEFAULT_LEDGER\nfrom aea.mail.base import Envelope\nfrom aea.protocols.base import Address, Message\nfrom aea.protocols.dialogue.base import (\n    BasicDialoguesStorage,\n    Dialogue,\n    DialogueLabel,\n    PersistDialoguesStorage,\n)\nfrom aea.skills.base import Handler, Skill, SkillContext\nfrom aea.skills.behaviours import TickerBehaviour\nfrom aea.test_tools.test_cases import AEATestCaseEmpty\n\nfrom packages.fetchai.protocols.default.dialogues import (\n    DefaultDialogue,\n    DefaultDialogues,\n)\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.skills.echo import PUBLIC_ID\n\nfrom tests.common.utils import wait_for_condition\n\n\nclass TBehaviour(TickerBehaviour):\n    \"\"\"Simple behaviour to count how many acts were called.\"\"\"\n\n    OBJ_ID = \"some\"\n    OBJ_BODY = {\"data\": 12}\n    COL_NAME = \"test\"\n\n    def setup(self) -> None:\n        \"\"\"Set up behaviour.\"\"\"\n        self.counter = 0\n\n    def act(self) -> None:\n        \"\"\"Make an action.\"\"\"\n        if self.context.storage and self.context.storage.is_connected:\n            col = self.context.storage.get_sync_collection(self.COL_NAME)\n            col.put(self.OBJ_ID, self.OBJ_BODY)\n        self.counter += 1\n\n\nclass THandler(Handler):\n    \"\"\"Simple behaviour to count how many acts were called.\"\"\"\n\n    SUPPORTED_PROTOCOL = DefaultMessage.protocol_id\n\n    OBJ_ID = \"some\"\n    OBJ_BODY = {\"data\": 12}\n    COL_NAME = \"test\"\n\n    def setup(self) -> None:\n        \"\"\"Set up behaviour.\"\"\"\n        self.counter = 0\n\n    def teardown(self) -> None:\n        \"\"\"Tear down handler.\"\"\"\n\n    def handle(self, *args, **kwargs) -> None:\n        \"\"\"Handle an evelope.\"\"\"\n        if self.context.storage and self.context.storage.is_connected:\n            col = self.context.storage.get_sync_collection(self.COL_NAME)\n            col.put(self.OBJ_ID, self.OBJ_BODY)\n\n        self.counter += 1\n\n\ndef test_storage_access_from_behaviour():\n    \"\"\"Test storage access from behaviour component.\"\"\"\n    builder = AEABuilder()\n    builder.set_name(\"aea_1\")\n    builder.add_private_key(DEFAULT_LEDGER)\n\n    skill_context = SkillContext()\n    behaviour = TBehaviour(name=\"behaviour\", skill_context=skill_context)\n    test_skill = Skill(\n        SkillConfig(name=\"test_skill\", author=\"fetchai\"),\n        skill_context=skill_context,\n        handlers={},\n        behaviours={\"behaviour\": behaviour},\n    )\n\n    builder.add_component_instance(test_skill)\n    builder.set_storage_uri(\"sqlite://:memory:\")\n    aea = builder.build()\n    skill_context.set_agent_context(aea.context)\n\n    aea.runtime._threaded = True\n    aea.runtime.start()\n\n    try:\n        wait_for_condition(lambda: aea.is_running, timeout=10)\n        wait_for_condition(lambda: behaviour.counter > 0, timeout=10)\n\n        col = skill_context.storage.get_sync_collection(behaviour.COL_NAME)\n        assert col.get(behaviour.OBJ_ID) == behaviour.OBJ_BODY\n    finally:\n        aea.runtime.stop()\n        aea.runtime.wait_completed(sync=True, timeout=10)\n\n\ndef test_storage_access_from_handler():\n    \"\"\"Test storage access from handler component.\"\"\"\n    builder = AEABuilder()\n    builder.set_name(\"aea_1\")\n    builder.add_private_key(DEFAULT_LEDGER)\n\n    skill_context = SkillContext()\n    handler = THandler(name=\"behaviour\", skill_context=skill_context)\n    test_skill = Skill(\n        SkillConfig(name=\"test_skill\", author=\"fetchai\"),\n        skill_context=skill_context,\n        handlers={\"handler\": handler},\n        behaviours={},\n    )\n\n    builder.add_component_instance(test_skill)\n    builder.set_storage_uri(\"sqlite://:memory:\")\n    aea = builder.build()\n    skill_context.set_agent_context(aea.context)\n\n    aea.runtime._threaded = True\n    aea.runtime.start()\n\n    msg = DefaultMessage(\n        dialogue_reference=(\"\", \"\"),\n        message_id=1,\n        target=0,\n        performative=DefaultMessage.Performative.BYTES,\n        content=b\"hello\",\n    )\n    msg.to = aea.identity.address\n    msg.sender = aea.identity.address\n    envelope = Envelope(\n        to=msg.to,\n        sender=msg.sender,\n        message=msg,\n    )\n    try:\n        wait_for_condition(lambda: aea.is_running, timeout=10)\n\n        aea.runtime.multiplexer.in_queue.put(envelope)\n\n        wait_for_condition(lambda: handler.counter > 0, timeout=10)\n\n        col = skill_context.storage.get_sync_collection(handler.COL_NAME)\n        assert col.get(handler.OBJ_ID) == handler.OBJ_BODY\n    finally:\n        aea.runtime.stop()\n        aea.runtime.wait_completed(sync=True, timeout=10)\n\n\ndef _get_labels(dialogues: List[Dialogue]) -> Set[DialogueLabel]:\n    return set([i.dialogue_label for i in dialogues])\n\n\ndef _storage_all_dialogues_labels(storage: BasicDialoguesStorage) -> Set[DialogueLabel]:\n    return _get_labels(\n        storage.dialogues_in_active_state + storage.dialogues_in_terminal_state\n    )\n\n\nclass TestDialogueModelSaveLoad(AEATestCaseEmpty):\n    \"\"\"Test dialogues sved and loaded on agent restart.\"\"\"\n\n    def setup(self):\n        \"\"\"Set up the test case.\"\"\"\n        self.add_item(\"skill\", \"fetchai/echo:latest\", local=True)\n        pkey_file = os.path.join(self._get_cwd(), \"privkey\")\n        self.generate_private_key(\"fetchai\", pkey_file)\n        self.add_private_key(\"fetchai\", pkey_file, False)\n        self.add_private_key(\"fetchai\", pkey_file, True)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> Dialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return DefaultDialogue.Role.AGENT\n\n        self.dialogues = DefaultDialogues(\n            self_address=\"another_agent\",\n            role_from_first_message=role_from_first_message,\n        )\n\n    def _build_aea(self) -> AEA:\n        \"\"\"Build an AEA.\"\"\"\n        builder = AEABuilder.from_aea_project(self._get_cwd())\n        builder.set_storage_uri(\"sqlite://some_file.db\")\n        aea = builder.build()\n        aea.runtime._threaded = True\n        return aea\n\n    def test_dialogues_dumped_and_restored_properly(self):\n        \"\"\"Test dialogues restored during restart of agent.\"\"\"\n        aea = self._build_aea()\n        aea.runtime.start()\n        try:\n            wait_for_condition(lambda: aea.is_running, timeout=10)\n            echo_skill = aea.resources.get_skill(PUBLIC_ID)\n            assert (\n                not echo_skill.skill_context.default_dialogues._dialogues_storage._dialogues_by_dialogue_label\n            )\n            msg, dialogue = self.dialogues.create(\n                aea.name,\n                performative=DefaultMessage.Performative.BYTES,\n                content=b\"hello\",\n            )\n            envelope = Envelope(\n                to=msg.to,\n                sender=msg.sender,\n                message=msg,\n            )\n            aea.runtime.multiplexer.in_queue.put(envelope)\n\n            dialogue_storage: PersistDialoguesStorage = (\n                echo_skill.skill_context.default_dialogues._dialogues_storage\n            )\n            wait_for_condition(\n                lambda: _storage_all_dialogues_labels(dialogue_storage),\n                timeout=3,\n            )\n            dialogues_for_check = _storage_all_dialogues_labels(dialogue_storage)\n        finally:\n            aea.runtime.stop()\n            aea.runtime.wait_completed(sync=True, timeout=10)\n\n        aea = self._build_aea()\n        aea.runtime.start()\n        try:\n            wait_for_condition(lambda: aea.is_running, timeout=10)\n            echo_skill = aea.resources.get_skill(PUBLIC_ID)\n\n            dialogue_storage: PersistDialoguesStorage = (\n                echo_skill.skill_context.default_dialogues._dialogues_storage\n            )\n            wait_for_condition(\n                lambda: _storage_all_dialogues_labels(dialogue_storage),\n                timeout=3,\n            )\n            assert (\n                _storage_all_dialogues_labels(dialogue_storage) == dialogues_for_check\n            )\n        finally:\n            aea.runtime.stop()\n            aea.runtime.wait_completed(sync=True, timeout=10)\n\n\nif __name__ == \"__main__\":\n    pytest.main([os.path.basename(__file__)])\n"
  },
  {
    "path": "tests/test_aea/test_aea.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests for aea/aea.py.\"\"\"\nimport os\nimport tempfile\nimport time\nimport unittest\nfrom pathlib import Path\nfrom threading import Thread\nfrom typing import Callable\nfrom unittest.case import TestCase\nfrom unittest.mock import MagicMock, PropertyMock, patch\n\nimport pytest\n\nimport aea  # noqa: F401\nfrom aea.aea import AEA\nfrom aea.aea_builder import AEABuilder\nfrom aea.configurations.base import SkillConfig\nfrom aea.configurations.constants import DEFAULT_LEDGER, DEFAULT_PRIVATE_KEY_FILE\nfrom aea.crypto.wallet import Wallet\nfrom aea.exceptions import AEAActException, AEAException, AEAHandleException\nfrom aea.helpers.base import cd\nfrom aea.helpers.exception_policy import ExceptionPolicyEnum\nfrom aea.identity.base import Identity\nfrom aea.mail.base import Envelope\nfrom aea.protocols.base import Protocol\nfrom aea.registries.resources import Resources\nfrom aea.runtime import RuntimeStates\nfrom aea.skills.base import Skill, SkillContext\n\nfrom packages.fetchai.connections.local.connection import LocalNode, OEFLocalConnection\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.protocols.default.serialization import DefaultSerializer\nfrom packages.fetchai.protocols.fipa.message import FipaMessage\n\nfrom tests.common.utils import (\n    AeaTool,\n    make_behaviour_cls_from_funcion,\n    make_handler_cls_from_funcion,\n    run_in_thread,\n    timeit_context,\n    wait_for_condition,\n)\nfrom tests.conftest import (\n    CUR_PATH,\n    FETCHAI_PRIVATE_KEY_PATH,\n    ROOT_DIR,\n    UNKNOWN_PROTOCOL_PUBLIC_ID,\n    _make_local_connection,\n)\nfrom tests.data.dummy_aea.skills.dummy.tasks import DummyTask  # type: ignore\nfrom tests.data.dummy_skill import PUBLIC_ID as DUMMY_SKILL_PUBLIC_ID\nfrom tests.data.dummy_skill.behaviours import DummyBehaviour  # type: ignore\n\n\ndef test_setup_aea():\n    \"\"\"Tests the initialisation of the AEA.\"\"\"\n    private_key_path = os.path.join(CUR_PATH, \"data\", DEFAULT_PRIVATE_KEY_FILE)\n    builder = AEABuilder()\n    builder.set_name(\"my_name\").add_private_key(DEFAULT_LEDGER, private_key_path)\n    my_AEA = builder.build()\n    assert my_AEA.context == my_AEA._context, \"Cannot access the Agent's Context\"\n    assert (\n        not my_AEA.context.connection_status.is_connected\n    ), \"AEA should not be connected.\"\n    my_AEA.setup()\n    assert my_AEA.resources is not None, \"Resources must not be None after setup\"\n    my_AEA.resources = Resources()\n    assert my_AEA.resources is not None, \"Resources must not be None after set\"\n    assert (\n        my_AEA.context.shared_state is not None\n    ), \"Shared state must not be None after set\"\n    assert my_AEA.context.task_manager is not None\n    assert my_AEA.context.identity is not None, \"Identity must not be None after set.\"\n    my_AEA.teardown()\n\n\ndef test_act():\n    \"\"\"Tests the act function of the AEA.\"\"\"\n    agent_name = \"MyAgent\"\n    private_key_path = os.path.join(CUR_PATH, \"data\", DEFAULT_PRIVATE_KEY_FILE)\n    builder = AEABuilder()\n    builder.set_name(agent_name)\n    builder.add_private_key(DEFAULT_LEDGER, private_key_path)\n    builder.add_skill(Path(CUR_PATH, \"data\", \"dummy_skill\"))\n    agent = builder.build()\n\n    with run_in_thread(agent.start, timeout=20):\n        wait_for_condition(lambda: agent.is_running, timeout=20)\n        behaviour = agent.resources.get_behaviour(DUMMY_SKILL_PUBLIC_ID, \"dummy\")\n\n        time.sleep(1)\n        wait_for_condition(lambda: behaviour.nb_act_called > 0, timeout=20)\n        agent.stop()\n\n\ndef test_start_stop():\n    \"\"\"Tests the act function of the AEA.\"\"\"\n    agent_name = \"MyAgent\"\n    private_key_path = os.path.join(CUR_PATH, \"data\", DEFAULT_PRIVATE_KEY_FILE)\n    builder = AEABuilder()\n    builder.set_name(agent_name)\n    builder.add_private_key(DEFAULT_LEDGER, private_key_path)\n    builder.add_skill(Path(CUR_PATH, \"data\", \"dummy_skill\"))\n    agent = builder.build()\n\n    with run_in_thread(agent.start, timeout=20):\n        wait_for_condition(lambda: agent.is_running, timeout=20)\n        agent.stop()\n\n\ndef test_double_start():\n    \"\"\"Tests the act function of the AEA.\"\"\"\n    agent_name = \"MyAgent\"\n    private_key_path = os.path.join(CUR_PATH, \"data\", DEFAULT_PRIVATE_KEY_FILE)\n    builder = AEABuilder()\n    builder.set_name(agent_name)\n    builder.add_private_key(DEFAULT_LEDGER, private_key_path)\n    builder.add_skill(Path(CUR_PATH, \"data\", \"dummy_skill\"))\n    agent = builder.build()\n\n    with run_in_thread(agent.start, timeout=20):\n        try:\n            wait_for_condition(lambda: agent.is_running, timeout=20)\n            t = Thread(target=agent.start)\n            t.start()\n            time.sleep(1)\n            assert not t.is_alive()\n        finally:\n            agent.stop()\n            t.join()\n\n\ndef test_react():\n    \"\"\"Tests income messages.\"\"\"\n    with LocalNode() as node:\n        agent_name = \"MyAgent\"\n        private_key_path = os.path.join(CUR_PATH, \"data\", DEFAULT_PRIVATE_KEY_FILE)\n        builder = AEABuilder()\n        builder.set_name(agent_name)\n        builder.add_private_key(DEFAULT_LEDGER, private_key_path)\n        builder.add_protocol(\n            Path(ROOT_DIR, \"packages\", \"fetchai\", \"protocols\", \"oef_search\")\n        )\n        builder.add_connection(\n            Path(ROOT_DIR, \"packages\", \"fetchai\", \"connections\", \"local\")\n        )\n        local_connection_id = OEFLocalConnection.connection_id\n        builder.set_default_connection(local_connection_id)\n        builder.add_skill(Path(CUR_PATH, \"data\", \"dummy_skill\"))\n        agent = builder.build(connection_ids=[local_connection_id])\n        # This is a temporary workaround to feed the local node to the OEF Local connection\n        # TODO remove it.\n        local_connection = agent.resources.get_connection(local_connection_id)\n        local_connection._local_node = node\n\n        msg = DefaultMessage(\n            dialogue_reference=(\"\", \"\"),\n            message_id=1,\n            target=0,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"hello\",\n        )\n        msg.to = agent.identity.address\n        msg.sender = agent.identity.address\n        envelope = Envelope(\n            to=msg.to,\n            sender=msg.sender,\n            message=msg,\n        )\n\n        with run_in_thread(agent.start, timeout=20, on_exit=agent.stop):\n            wait_for_condition(lambda: agent.is_running, timeout=20)\n            agent.outbox.put(envelope)\n            default_protocol_public_id = DefaultMessage.protocol_id\n            dummy_skill_public_id = DUMMY_SKILL_PUBLIC_ID\n            handler = agent.resources.get_handler(\n                default_protocol_public_id, dummy_skill_public_id\n            )\n\n            assert handler is not None, \"Handler is not set.\"\n\n            wait_for_condition(\n                lambda: len(handler.handled_messages) > 0,\n                timeout=20,\n                error_msg=\"The message is not inside the handled_messages.\",\n            )\n\n\ndef test_handle():\n    \"\"\"Tests handle method of an agent.\"\"\"\n    with LocalNode() as node:\n        agent_name = \"MyAgent\"\n        private_key_path = os.path.join(CUR_PATH, \"data\", DEFAULT_PRIVATE_KEY_FILE)\n        builder = AEABuilder()\n        builder.set_name(agent_name)\n        builder.add_private_key(DEFAULT_LEDGER, private_key_path)\n        builder.add_protocol(Path(ROOT_DIR, \"packages\", \"fetchai\", \"protocols\", \"fipa\"))\n        builder.add_protocol(\n            Path(ROOT_DIR, \"packages\", \"fetchai\", \"protocols\", \"oef_search\")\n        )\n        builder.add_connection(\n            Path(ROOT_DIR, \"packages\", \"fetchai\", \"connections\", \"local\")\n        )\n        local_connection_id = OEFLocalConnection.connection_id\n        builder.set_default_connection(local_connection_id)\n        builder.add_skill(Path(CUR_PATH, \"data\", \"dummy_skill\"))\n        an_aea = builder.build(connection_ids=[local_connection_id])\n        # This is a temporary workaround to feed the local node to the OEF Local connection\n        # TODO remove it.\n        local_connection = an_aea.resources.get_connection(local_connection_id)\n        local_connection._local_node = node\n\n        msg = DefaultMessage(\n            dialogue_reference=(\"\", \"\"),\n            message_id=1,\n            target=0,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"hello\",\n        )\n        msg.to = an_aea.identity.address\n        msg.sender = an_aea.identity.address\n\n        encoded_msg = DefaultSerializer.encode(msg)\n\n        error_handler = an_aea._error_handler\n\n        with run_in_thread(an_aea.start, timeout=5):\n            wait_for_condition(lambda: an_aea.is_running, timeout=10)\n            dummy_skill = an_aea.resources.get_skill(DUMMY_SKILL_PUBLIC_ID)\n            dummy_handler = dummy_skill.skill_context.handlers.dummy\n            # UNSUPPORTED PROTOCOL\n            envelope = Envelope(\n                to=msg.to,\n                sender=msg.sender,\n                message=msg,\n            )\n            envelope._protocol_specification_id = UNKNOWN_PROTOCOL_PUBLIC_ID\n            # send envelope via localnode back to agent/bypass `outbox` put consistency checks\n            assert error_handler.unsupported_protocol_count == 0\n            an_aea.outbox.put(envelope)\n            wait_for_condition(\n                lambda: error_handler.unsupported_protocol_count == 1,\n                timeout=2,\n            )\n\n            # DECODING ERROR\n            envelope = Envelope(\n                to=an_aea.identity.address,\n                sender=an_aea.identity.address,\n                protocol_specification_id=DefaultMessage.protocol_specification_id,\n                message=b\"\",\n            )\n            assert error_handler.decoding_error_count == 0\n            an_aea.runtime.multiplexer.put(envelope)\n            wait_for_condition(\n                lambda: error_handler.decoding_error_count == 1,\n                timeout=5,\n            )\n\n            #   UNSUPPORTED SKILL\n            msg = FipaMessage(\n                performative=FipaMessage.Performative.ACCEPT,\n                message_id=1,\n                dialogue_reference=(str(0), \"\"),\n                target=0,\n            )\n            msg.to = an_aea.identity.address\n            msg.sender = an_aea.identity.address\n            envelope = Envelope(\n                to=msg.to,\n                sender=msg.sender,\n                message=msg,\n            )\n            # send envelope via localnode back to agent/bypass `outbox` put consistency checks\n            assert error_handler.no_active_handler_count == 0\n            an_aea.outbox.put(envelope)\n            wait_for_condition(\n                lambda: error_handler.no_active_handler_count == 1,\n                timeout=5,\n            )\n\n            #   DECODING OK\n            envelope = Envelope(\n                to=msg.to,\n                sender=msg.sender,\n                protocol_specification_id=DefaultMessage.protocol_specification_id,\n                message=encoded_msg,\n            )\n            # send envelope via localnode back to agent/bypass `outbox` put consistency checks\n            assert len(dummy_handler.handled_messages) == 0\n            an_aea.runtime.multiplexer.put(envelope)\n            wait_for_condition(\n                lambda: len(dummy_handler.handled_messages) == 1,\n                timeout=5,\n            )\n            an_aea.stop()\n\n\ndef test_initialize_aea_programmatically():\n    \"\"\"Test that we can initialize an AEA programmatically.\"\"\"\n    with LocalNode() as node:\n        agent_name = \"MyAgent\"\n        private_key_path = os.path.join(CUR_PATH, \"data\", DEFAULT_PRIVATE_KEY_FILE)\n        builder = AEABuilder()\n        builder.set_name(agent_name)\n        builder.add_private_key(DEFAULT_LEDGER, private_key_path)\n        builder.add_protocol(\n            Path(ROOT_DIR, \"packages\", \"fetchai\", \"protocols\", \"oef_search\")\n        )\n        builder.add_connection(\n            Path(ROOT_DIR, \"packages\", \"fetchai\", \"connections\", \"local\")\n        )\n        local_connection_id = OEFLocalConnection.connection_id\n        builder.set_default_connection(local_connection_id)\n        builder.add_skill(Path(CUR_PATH, \"data\", \"dummy_skill\"))\n        an_aea = builder.build(connection_ids=[local_connection_id])\n        local_connection = an_aea.resources.get_connection(local_connection_id)\n        local_connection._local_node = node\n\n        expected_message = DefaultMessage(\n            dialogue_reference=(\"\", \"\"),\n            message_id=1,\n            target=0,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"hello\",\n        )\n        expected_message.to = an_aea.identity.address\n        expected_message.sender = an_aea.identity.address\n        envelope = Envelope(\n            to=expected_message.to,\n            sender=expected_message.sender,\n            message=expected_message,\n        )\n\n        with run_in_thread(an_aea.start, timeout=5, on_exit=an_aea.stop):\n            wait_for_condition(lambda: an_aea.is_running, timeout=10)\n            an_aea.outbox.put(envelope)\n\n            dummy_skill_id = DUMMY_SKILL_PUBLIC_ID\n            dummy_behaviour_name = \"dummy\"\n            dummy_behaviour = an_aea.resources.get_behaviour(\n                dummy_skill_id, dummy_behaviour_name\n            )\n            wait_for_condition(lambda: dummy_behaviour is not None, timeout=10)\n            wait_for_condition(lambda: dummy_behaviour.nb_act_called > 0, timeout=10)\n\n            # TODO the previous code caused an error:\n            #      _pickle.PicklingError: Can't pickle <class 'tasks.DummyTask'>: import of module 'tasks' failed\n            dummy_task = DummyTask()\n            task_id = an_aea.enqueue_task(dummy_task)\n            async_result = an_aea.get_task_result(task_id)\n            expected_result = async_result.get(10.0)\n            assert expected_result == 1\n            dummy_handler = an_aea.resources.get_handler(\n                DefaultMessage.protocol_id, dummy_skill_id\n            )\n            dummy_handler_alt = an_aea.resources._handler_registry.fetch(\n                (dummy_skill_id, \"dummy\")\n            )\n            wait_for_condition(lambda: dummy_handler == dummy_handler_alt, timeout=10)\n            wait_for_condition(lambda: dummy_handler is not None, timeout=10)\n            wait_for_condition(\n                lambda: len(dummy_handler.handled_messages) == 1, timeout=10\n            )\n            wait_for_condition(\n                lambda: dummy_handler.handled_messages[0] == expected_message,\n                timeout=10,\n            )\n\n\ndef test_initialize_aea_programmatically_build_resources():\n    \"\"\"Test that we can initialize the agent by building the resource object.\"\"\"\n    try:\n        temp = tempfile.mkdtemp(prefix=\"test_aea_resources\")\n        with LocalNode() as node:\n            agent_name = \"MyAgent\"\n            private_key_path = os.path.join(CUR_PATH, \"data\", DEFAULT_PRIVATE_KEY_FILE)\n            wallet = Wallet({DEFAULT_LEDGER: private_key_path})\n            identity = Identity(\n                agent_name,\n                address=wallet.addresses[DEFAULT_LEDGER],\n                public_key=wallet.public_keys[DEFAULT_LEDGER],\n            )\n            connection = _make_local_connection(\n                agent_name, agent_name + \"_public_key\", node\n            )\n\n            resources = Resources()\n            default_protocol = Protocol.from_dir(\n                str(Path(\"packages\", \"fetchai\", \"protocols\", \"default\"))\n            )\n            resources.add_protocol(default_protocol)\n            resources.add_connection(connection)\n\n            an_aea = AEA(\n                identity,\n                wallet,\n                resources=resources,\n                data_dir=MagicMock(),\n                default_connection=connection.public_id,\n            )\n\n            error_skill = Skill.from_dir(\n                str(Path(\"packages\", \"fetchai\", \"skills\", \"error\")),\n                agent_context=an_aea.context,\n            )\n            dummy_skill = Skill.from_dir(\n                str(Path(CUR_PATH, \"data\", \"dummy_skill\")), agent_context=an_aea.context\n            )\n            resources.add_skill(dummy_skill)\n            resources.add_skill(error_skill)\n\n            expected_message = DefaultMessage(\n                dialogue_reference=(\"\", \"\"),\n                message_id=1,\n                target=0,\n                performative=DefaultMessage.Performative.BYTES,\n                content=b\"hello\",\n            )\n            expected_message.to = agent_name\n            expected_message.sender = agent_name\n\n            with run_in_thread(an_aea.start, timeout=5, on_exit=an_aea.stop):\n                wait_for_condition(lambda: an_aea.is_running, timeout=10)\n                an_aea.outbox.put(\n                    Envelope(\n                        to=agent_name,\n                        sender=agent_name,\n                        message=expected_message,\n                    )\n                )\n\n                dummy_skill_id = DUMMY_SKILL_PUBLIC_ID\n                dummy_behaviour_name = \"dummy\"\n                dummy_behaviour = an_aea.resources.get_behaviour(\n                    dummy_skill_id, dummy_behaviour_name\n                )\n                wait_for_condition(lambda: dummy_behaviour is not None, timeout=10)\n                wait_for_condition(\n                    lambda: dummy_behaviour.nb_act_called > 0, timeout=10\n                )\n\n                dummy_task = DummyTask()\n                task_id = an_aea.enqueue_task(dummy_task)\n                async_result = an_aea.get_task_result(task_id)\n                expected_result = async_result.get(10.0)\n                assert expected_result == 1\n\n                dummy_handler_name = \"dummy\"\n                dummy_handler = an_aea.resources._handler_registry.fetch(\n                    (dummy_skill_id, dummy_handler_name)\n                )\n                dummy_handler_alt = an_aea.resources.get_handler(\n                    DefaultMessage.protocol_id, dummy_skill_id\n                )\n                wait_for_condition(\n                    lambda: dummy_handler == dummy_handler_alt, timeout=10\n                )\n                wait_for_condition(lambda: dummy_handler is not None, timeout=10)\n                wait_for_condition(\n                    lambda: len(dummy_handler.handled_messages) == 1, timeout=10\n                )\n                wait_for_condition(\n                    lambda: dummy_handler.handled_messages[0] == expected_message,\n                    timeout=10,\n                )\n    finally:\n        Path(temp).rmdir()\n\n\ndef test_add_behaviour_dynamically():\n    \"\"\"Test that we can add a behaviour dynamically.\"\"\"\n    agent_name = \"MyAgent\"\n    private_key_path = os.path.join(CUR_PATH, \"data\", DEFAULT_PRIVATE_KEY_FILE)\n    wallet = Wallet({DEFAULT_LEDGER: private_key_path})\n    data_dir = MagicMock()\n    resources = Resources()\n    identity = Identity(\n        agent_name,\n        address=wallet.addresses[DEFAULT_LEDGER],\n        public_key=wallet.public_keys[DEFAULT_LEDGER],\n    )\n    with LocalNode() as local_node:\n        connection = _make_local_connection(\n            identity.address, identity.public_key, local_node\n        )\n        resources.add_connection(connection)\n\n        agent = AEA(\n            identity,\n            wallet,\n            resources,\n            data_dir,\n            default_connection=connection.public_id,\n        )\n        resources.add_component(\n            Skill.from_dir(\n                Path(CUR_PATH, \"data\", \"dummy_skill\"), agent_context=agent.context\n            )\n        )\n        for skill in resources.get_all_skills():\n            skill.skill_context.set_agent_context(agent.context)\n\n        dummy_skill_id = DUMMY_SKILL_PUBLIC_ID\n        old_nb_behaviours = len(agent.resources.get_behaviours(dummy_skill_id))\n        with run_in_thread(agent.start, timeout=5, on_exit=agent.stop):\n            wait_for_condition(lambda: agent.is_running, timeout=10)\n\n            dummy_skill = agent.resources.get_skill(dummy_skill_id)\n\n            wait_for_condition(lambda: dummy_skill is not None, timeout=10)\n\n            new_behaviour = DummyBehaviour(\n                name=\"dummy2\", skill_context=dummy_skill.skill_context\n            )\n            dummy_skill.skill_context.new_behaviours.put(new_behaviour)\n\n            wait_for_condition(lambda: new_behaviour.nb_act_called > 0, timeout=10)\n            wait_for_condition(\n                lambda: len(agent.resources.get_behaviours(dummy_skill_id))\n                == old_nb_behaviours + 1,\n                timeout=10,\n            )\n\n\ndef test_no_handlers_registered():\n    \"\"\"Test no handlers are registered for message processing.\"\"\"\n    agent_name = \"MyAgent\"\n    builder = AEABuilder()\n    private_key_path = os.path.join(CUR_PATH, \"data\", DEFAULT_PRIVATE_KEY_FILE)\n    builder.set_name(agent_name)\n    builder.add_private_key(DEFAULT_LEDGER, private_key_path)\n    an_aea = builder.build()\n\n    with patch.object(an_aea.logger, \"warning\") as mock_logger:\n        msg = DefaultMessage(\n            dialogue_reference=(\"\", \"\"),\n            message_id=1,\n            target=0,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"hello\",\n        )\n        msg.to = an_aea.identity.address\n        envelope = Envelope(\n            to=an_aea.identity.address,\n            sender=an_aea.identity.address,\n            message=msg,\n        )\n        with patch(\n            \"aea.registries.filter.Filter.get_active_handlers\",\n            new_callable=PropertyMock,\n        ):\n            with patch.object(\n                an_aea.runtime.multiplexer,\n                \"put\",\n            ):\n                an_aea.handle_envelope(envelope)\n        mock_logger.assert_any_call(\n            f\"Cannot handle envelope: no active handler for protocol={msg.protocol_id}. Sender={envelope.sender}, to={envelope.sender}.\"\n        )\n\n\nclass TestContextNamespace:\n    \"\"\"Test that the keyword arguments to AEA constructor can be accessible from the skill context.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        agent_name = \"my_agent\"\n        data_dir = MagicMock()\n        private_key_path = os.path.join(CUR_PATH, \"data\", DEFAULT_PRIVATE_KEY_FILE)\n        wallet = Wallet({DEFAULT_LEDGER: private_key_path})\n        identity = Identity(\n            agent_name,\n            address=wallet.addresses[DEFAULT_LEDGER],\n            public_key=wallet.public_keys[DEFAULT_LEDGER],\n        )\n        connection = _make_local_connection(\n            identity.address, identity.public_key, LocalNode()\n        )\n        resources = Resources()\n        resources.add_connection(connection)\n        cls.context_namespace = {\"key1\": 1, \"key2\": 2}\n        cls.agent = AEA(identity, wallet, resources, data_dir, **cls.context_namespace)\n\n        resources.add_component(\n            Skill.from_dir(\n                Path(CUR_PATH, \"data\", \"dummy_skill\"), agent_context=cls.agent.context\n            )\n        )\n        for skill in resources.get_all_skills():\n            skill.skill_context.set_agent_context(cls.agent.context)\n\n    def test_access_context_namespace(self):\n        \"\"\"Test that we can access the context namespace.\"\"\"\n        assert self.agent.context.namespace.key1 == 1\n        assert self.agent.context.namespace.key2 == 2\n\n        for skill in self.agent.resources.get_all_skills():\n            assert skill.skill_context.namespace.key1 == 1\n            assert skill.skill_context.namespace.key2 == 2\n\n\ndef test_start_stop_and_start_stop_again():\n    \"\"\"Tests AEA can be started/stopped twice.\"\"\"\n    agent_name = \"MyAgent\"\n    private_key_path = os.path.join(CUR_PATH, \"data\", DEFAULT_PRIVATE_KEY_FILE)\n    builder = AEABuilder()\n    builder.set_name(agent_name)\n    builder.add_private_key(DEFAULT_LEDGER, private_key_path)\n    builder.add_skill(Path(CUR_PATH, \"data\", \"dummy_skill\"))\n    agent = builder.build()\n\n    with run_in_thread(agent.start, timeout=20):\n        wait_for_condition(lambda: agent.is_running, timeout=10)\n        behaviour = agent.resources.get_behaviour(DUMMY_SKILL_PUBLIC_ID, \"dummy\")\n\n        time.sleep(1)\n        wait_for_condition(lambda: behaviour.nb_act_called > 0, timeout=5)\n        agent.stop()\n        wait_for_condition(lambda: agent.is_stopped, timeout=10)\n\n    behaviour.nb_act_called = 0\n\n    time.sleep(2)\n    assert behaviour.nb_act_called == 0\n\n    with run_in_thread(agent.start, timeout=20):\n        wait_for_condition(lambda: agent.is_running, timeout=10)\n\n        time.sleep(1)\n        wait_for_condition(lambda: behaviour.nb_act_called > 0, timeout=5)\n        agent.stop()\n        wait_for_condition(lambda: agent.is_stopped, timeout=10)\n\n\nclass ExpectedExcepton(Exception):\n    \"\"\"Exception for testing.\"\"\"\n\n\nclass TestAeaExceptionPolicy:\n    \"\"\"Tests for exception policies.\"\"\"\n\n    @staticmethod\n    def raise_exception(*args, **kwargs) -> None:\n        \"\"\"Raise exception for tests.\"\"\"\n        raise ExpectedExcepton(\"we wait it!\")\n\n    def setup(self) -> None:\n        \"\"\"Set test cae instance.\"\"\"\n        agent_name = \"MyAgent\"\n\n        builder = AEABuilder()\n        builder.set_name(agent_name)\n        builder.add_private_key(DEFAULT_LEDGER, FETCHAI_PRIVATE_KEY_PATH)\n\n        self.handler_called = 0\n\n        def handler_func(*args, **kwargs):\n            self.handler_called += 1\n\n        skill_context = SkillContext()\n        handler_cls = make_handler_cls_from_funcion(handler_func)\n        behaviour_cls = make_behaviour_cls_from_funcion(handler_func)\n\n        self.handler = handler_cls(name=\"handler1\", skill_context=skill_context)\n        self.behaviour = behaviour_cls(name=\"behaviour1\", skill_context=skill_context)\n\n        test_skill = Skill(\n            SkillConfig(name=\"test_skill\", author=\"fetchai\"),\n            skill_context=skill_context,\n            handlers={\"handler\": self.handler},\n            behaviours={\"behaviour\": self.behaviour},\n        )\n        skill_context._skill = test_skill  # weird hack\n\n        builder.add_component_instance(test_skill)\n        self.aea = builder.build()\n        self.aea_tool = AeaTool(self.aea)\n\n    def test_no_exceptions(self) -> None:\n        \"\"\"Test act and handle works if no exception raised.\"\"\"\n        t = Thread(target=self.aea.start)\n        t.start()\n\n        self.aea_tool.put_inbox(self.aea_tool.dummy_envelope())\n        time.sleep(1)\n        try:\n            assert self.handler_called >= 2\n        finally:\n            self.aea.stop()\n            t.join()\n\n    def test_handle_propagate(self) -> None:\n        \"\"\"Test propagate policy on message handle.\"\"\"\n        self.aea._skills_exception_policy = ExceptionPolicyEnum.propagate\n        self.handler.handle = self.raise_exception  # type: ignore # cause error: Cannot assign to a method\n        self.aea_tool.put_inbox(self.aea_tool.dummy_envelope())\n\n        with pytest.raises(AEAHandleException):\n            with pytest.raises(ExpectedExcepton):\n                self.aea.start()\n\n        assert not self.aea.is_running\n\n    def test_handle_stop_and_exit(self) -> None:\n        \"\"\"Test stop and exit policy on message handle.\"\"\"\n        self.aea._skills_exception_policy = ExceptionPolicyEnum.stop_and_exit\n        self.handler.handle = self.raise_exception  # type: ignore # cause error: Cannot assign to a method\n        self.aea_tool.put_inbox(self.aea_tool.dummy_envelope())\n\n        with pytest.raises(\n            AEAException, match=r\"AEA was terminated cause exception .*\"\n        ):\n            self.aea.start()\n\n        assert not self.aea.is_running\n\n    def test_handle_just_log(self) -> None:\n        \"\"\"Test just log policy on message handle.\"\"\"\n        self.aea._skills_exception_policy = ExceptionPolicyEnum.just_log\n        self.handler.handle = self.raise_exception  # type: ignore # cause error: Cannot assign to a method\n\n        with patch.object(self.aea._logger, \"exception\") as patched:\n            t = Thread(target=self.aea.start)\n            t.start()\n            self.aea_tool.put_inbox(self.aea_tool.dummy_envelope())\n            self.aea_tool.put_inbox(self.aea_tool.dummy_envelope())\n            time.sleep(1)\n        try:\n            assert self.aea.is_running\n            assert patched.call_count == 2\n        finally:\n            self.aea.stop()\n            t.join()\n\n    def test_act_propagate(self) -> None:\n        \"\"\"Test propagate policy on behaviour act.\"\"\"\n        self.aea._skills_exception_policy = ExceptionPolicyEnum.propagate\n        self.behaviour.act = self.raise_exception  # type: ignore # cause error: Cannot assign to a method\n\n        with pytest.raises(AEAActException):\n            with pytest.raises(ExpectedExcepton):\n                self.aea.start()\n\n        assert self.aea.runtime.state == RuntimeStates.error\n\n    def test_act_stop_and_exit(self) -> None:\n        \"\"\"Test stop and exit policy on behaviour act.\"\"\"\n        self.aea._skills_exception_policy = ExceptionPolicyEnum.stop_and_exit\n        self.behaviour.act = self.raise_exception  # type: ignore # cause error: Cannot assign to a method\n\n        with pytest.raises(\n            AEAException, match=r\"AEA was terminated cause exception .*\"\n        ):\n            self.aea.start()\n\n        assert not self.aea.is_running\n\n    def test_act_just_log(self) -> None:\n        \"\"\"Test just log policy on behaviour act.\"\"\"\n        self.aea._skills_exception_policy = ExceptionPolicyEnum.just_log\n        self.behaviour.act = self.raise_exception  # type: ignore # cause error: Cannot assign to a method\n\n        with patch.object(self.aea.logger, \"exception\") as patched:\n            t = Thread(target=self.aea.start)\n            t.start()\n\n            time.sleep(1)\n        try:\n            assert self.aea.is_running\n            assert patched.call_count > 1\n        finally:\n            self.aea.stop()\n            t.join()\n\n    def test_act_bad_policy(self) -> None:\n        \"\"\"Test propagate policy on behaviour act.\"\"\"\n        self.aea._skills_exception_policy = \"non exists policy\"  # type: ignore\n        self.behaviour.act = self.raise_exception  # type: ignore # cause error: Cannot assign to a method\n\n        with pytest.raises(AEAException, match=r\"Unsupported exception policy.*\"):\n            self.aea.start()\n\n        assert not self.aea.is_running\n\n    def teardown(self) -> None:\n        \"\"\"Stop AEA if not stopped.\"\"\"\n        self.aea.stop()\n\n\ndef sleep_a_bit(sleep_time: float = 0.1, num_of_sleeps: int = 1) -> None:\n    \"\"\"Sleep num_of_sleeps time for sleep_time.\n\n    :param sleep_time: time to sleep.\n    :param  num_of_sleeps: how many time sleep for sleep_time.\n\n    :return: None\n    \"\"\"\n    for _ in range(num_of_sleeps):\n        time.sleep(sleep_time)\n\n\nclass BaseTimeExecutionCase(TestCase):\n    \"\"\"Base Test case for code execute timeout.\"\"\"\n\n    BASE_TIMEOUT = 0.35\n\n    @classmethod\n    def setUpClass(cls) -> None:\n        \"\"\"Set up.\"\"\"\n        if cls is BaseTimeExecutionCase:\n            raise unittest.SkipTest(\"Skip BaseTest tests, it's a base class\")\n\n    def tearDown(self) -> None:\n        \"\"\"Tear down.\"\"\"\n        self.aea_tool.teardown()\n        self.aea_tool.aea.runtime.agent_loop._teardown()\n\n    def prepare(self, function: Callable) -> None:\n        \"\"\"Prepare aea_tool for testing.\n\n        :param function: function be called on react handle or/and Behaviour.act\n        :return: None\n        \"\"\"\n        agent_name = \"MyAgent\"\n\n        builder = AEABuilder()\n        builder.set_name(agent_name)\n        builder.add_private_key(DEFAULT_LEDGER, FETCHAI_PRIVATE_KEY_PATH)\n\n        self.function_finished = False\n\n        def handler_func(*args, **kwargs):\n            function()\n            self.function_finished = True\n\n        skill_context = SkillContext()\n        handler_cls = make_handler_cls_from_funcion(handler_func)\n\n        behaviour_cls = make_behaviour_cls_from_funcion(handler_func)\n        self.behaviour = behaviour_cls(name=\"behaviour1\", skill_context=skill_context)\n        test_skill = Skill(\n            SkillConfig(name=\"test_skill\", author=\"fetchai\"),\n            skill_context=skill_context,\n            handlers={\n                \"handler1\": handler_cls(name=\"handler1\", skill_context=skill_context)\n            },\n            behaviours={\"behaviour1\": self.behaviour},\n        )\n        skill_context._skill = test_skill  # weird hack\n\n        builder.add_component_instance(test_skill)\n        my_aea = builder.build()\n        self.aea_tool = AeaTool(my_aea)\n        self.envelope = AeaTool.dummy_envelope()\n        self.aea_tool.aea.runtime.agent_loop._setup()\n\n    def test_long_handler_cancelled_by_timeout(self):\n        \"\"\"Test long function terminated by timeout.\"\"\"\n        num_sleeps = 10\n        sleep_time = self.BASE_TIMEOUT\n        function_sleep_time = num_sleeps * sleep_time\n        execution_timeout = self.BASE_TIMEOUT * 2\n        assert execution_timeout < function_sleep_time\n\n        self.prepare(lambda: sleep_a_bit(sleep_time, num_sleeps))\n        self.aea_tool.set_execution_timeout(execution_timeout)\n\n        with timeit_context() as timeit:\n            self.aea_action()\n\n        assert execution_timeout <= timeit.time_passed <= function_sleep_time\n        assert not self.function_finished\n\n    def test_short_handler_not_cancelled_by_timeout(self):\n        \"\"\"Test short function NOT terminated by timeout.\"\"\"\n        num_sleeps = 1\n        sleep_time = self.BASE_TIMEOUT\n        function_sleep_time = num_sleeps * sleep_time\n        execution_timeout = self.BASE_TIMEOUT * 2\n\n        assert function_sleep_time <= execution_timeout\n\n        self.prepare(lambda: sleep_a_bit(sleep_time, num_sleeps))\n        self.aea_tool.set_execution_timeout(execution_timeout)\n        self.aea_tool.setup()\n\n        with timeit_context() as timeit:\n            self.aea_action()\n\n        assert function_sleep_time <= timeit.time_passed <= execution_timeout\n        assert self.function_finished\n\n    def test_no_timeout(self):\n        \"\"\"Test function NOT terminated by timeout cause timeout == 0.\"\"\"\n        num_sleeps = 1\n        sleep_time = self.BASE_TIMEOUT\n        function_sleep_time = num_sleeps * sleep_time\n        execution_timeout = 0\n\n        self.prepare(lambda: sleep_a_bit(sleep_time, num_sleeps))\n        self.aea_tool.set_execution_timeout(execution_timeout)\n        self.aea_tool.setup()\n\n        with timeit_context() as timeit:\n            self.aea_action()\n\n        assert function_sleep_time <= timeit.time_passed\n        assert self.function_finished\n\n\nclass HandleTimeoutExecutionCase(BaseTimeExecutionCase):\n    \"\"\"Test handle envelope timeout.\"\"\"\n\n    def aea_action(self):\n        \"\"\"Spin react on AEA.\"\"\"\n        self.aea_tool.aea.runtime.agent_loop._execution_control(\n            self.aea_tool.handle_envelope, [self.envelope]\n        )\n\n\nclass ActTimeoutExecutionCase(BaseTimeExecutionCase):\n    \"\"\"Test act timeout.\"\"\"\n\n    def aea_action(self):\n        \"\"\"Spin act on AEA.\"\"\"\n        self.aea_tool.aea.runtime.agent_loop._execution_control(\n            self.behaviour.act_wrapper\n        )\n\n\ndef test_skill2skill_message():\n    \"\"\"Tests message can be sent directly to any skill.\"\"\"\n    with tempfile.TemporaryDirectory() as dir_name:\n        with cd(dir_name):\n            agent_name = \"MyAgent\"\n            private_key_path = os.path.join(CUR_PATH, \"data\", DEFAULT_PRIVATE_KEY_FILE)\n            builder = AEABuilder(registry_dir=Path(ROOT_DIR, \"packages\"))\n            builder.set_name(agent_name)\n            builder.add_private_key(DEFAULT_LEDGER, private_key_path)\n            builder.add_skill(Path(CUR_PATH, \"data\", \"dummy_skill\"))\n            builder.add_connection(\n                Path(ROOT_DIR, \"packages\", \"fetchai\", \"connections\", \"stub\")\n            )\n            agent = builder.build()\n\n            msg = DefaultMessage(\n                dialogue_reference=(\"\", \"\"),\n                message_id=1,\n                target=0,\n                performative=DefaultMessage.Performative.BYTES,\n                content=b\"hello\",\n            )\n            msg.to = str(DUMMY_SKILL_PUBLIC_ID)\n            msg.sender = \"some_author/some_skill:0.1.0\"\n            envelope = Envelope(\n                to=msg.to,\n                sender=msg.sender,\n                message=msg,\n            )\n\n            with run_in_thread(agent.start, timeout=20, on_exit=agent.stop):\n                wait_for_condition(lambda: agent.is_running, timeout=20)\n                default_protocol_public_id = DefaultMessage.protocol_id\n                handler = agent.resources.get_handler(\n                    default_protocol_public_id, DUMMY_SKILL_PUBLIC_ID\n                )\n\n                assert handler is not None, \"Handler is not set.\"\n\n                # send an envelope to itself\n                handler.context.send_to_skill(envelope)\n\n                wait_for_condition(\n                    lambda: len(handler.handled_messages) == 1,\n                    timeout=5,\n                    error_msg=\"The message is not inside the handled_messages.\",\n                )\n"
  },
  {
    "path": "tests/test_aea/test_aea_builder.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains tests for aea/aea_builder.py.\"\"\"\nimport os\nimport re\nimport sys\nfrom importlib import import_module\nfrom pathlib import Path\nfrom textwrap import dedent, indent\nfrom typing import Collection\nfrom unittest import mock\nfrom unittest.mock import MagicMock, Mock, patch\n\nimport pytest\nimport yaml\n\nfrom aea.aea import AEA\nfrom aea.aea_builder import AEABuilder, _DependenciesManager\nfrom aea.components.base import Component\nfrom aea.configurations.base import (\n    ComponentId,\n    ComponentType,\n    ConnectionConfig,\n    DEFAULT_AEA_CONFIG_FILE,\n    Dependency,\n    ProtocolConfig,\n    SkillConfig,\n)\nfrom aea.configurations.constants import (\n    DEFAULT_LEDGER,\n    DEFAULT_PRIVATE_KEY_FILE,\n    DOTTED_PATH_MODULE_ELEMENT_SEPARATOR,\n)\nfrom aea.configurations.data_types import PublicId\nfrom aea.configurations.loader import load_component_configuration\nfrom aea.contracts.base import Contract\nfrom aea.exceptions import AEAEnforceError, AEAException, AEAWalletNoAddressException\nfrom aea.helpers.base import cd\nfrom aea.helpers.exception_policy import ExceptionPolicyEnum\nfrom aea.helpers.install_dependency import call_pip\nfrom aea.protocols.base import Protocol\nfrom aea.registries.resources import Resources\nfrom aea.skills.base import Skill\nfrom aea.test_tools.test_cases import AEATestCase, AEATestCaseEmpty\n\nfrom packages.fetchai.connections.oef.connection import (\n    PUBLIC_ID as OEF_CONNECTION_PUBLIC_ID,\n)\nfrom packages.fetchai.connections.stub.connection import StubConnection\nfrom packages.fetchai.protocols.default import DefaultMessage\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\n\nfrom tests.common.mocks import RegexComparator\nfrom tests.conftest import (\n    CUR_PATH,\n    DEFAULT_PRIVATE_KEY_PATH,\n    ROOT_DIR,\n    _make_dummy_connection,\n)\nfrom tests.data.dummy_skill import PUBLIC_ID as DUMMY_SKILL_PUBLIC_ID\n\n\ndummy_skill_path = os.path.join(CUR_PATH, \"data\", \"dummy_skill\")\ncontract_path = os.path.join(ROOT_DIR, \"packages\", \"fetchai\", \"contracts\", \"erc1155\")\n\n\ndef test_default_timeout_for_agent():\n    \"\"\"Tests agents loop sleep timeout set by AEABuilder.DEFAULT_AGENT_LOOP_TIMEOUT.\"\"\"\n    agent_name = \"MyAgent\"\n    private_key_path = os.path.join(CUR_PATH, \"data\", DEFAULT_PRIVATE_KEY_FILE)\n    builder = AEABuilder()\n    builder.set_name(agent_name)\n    builder.add_private_key(DEFAULT_LEDGER, private_key_path)\n\n    aea = builder.build()\n    assert aea._period == builder.DEFAULT_AGENT_ACT_PERIOD\n\n    builder = AEABuilder()\n    builder.set_name(agent_name)\n    builder.add_private_key(DEFAULT_LEDGER, private_key_path)\n    builder.set_period(100)\n\n    aea = builder.build()\n    assert aea.period == 100\n\n\ndef test_add_package_already_existing():\n    \"\"\"\n    Test the case when we try to add a package (already added) to the AEA builder.\n\n    It should fail because the package is already present into the builder.\n    \"\"\"\n    builder = AEABuilder()\n    fipa_package_path = Path(ROOT_DIR) / \"packages\" / \"fetchai\" / \"protocols\" / \"fipa\"\n    builder.add_component(ComponentType.PROTOCOL, fipa_package_path)\n\n    expected_message = re.escape(\n        \"Component 'fetchai/fipa:1.1.7' of type 'protocol' already added.\"\n    )\n    with pytest.raises(AEAException, match=expected_message):\n        builder.add_component(ComponentType.PROTOCOL, fipa_package_path)\n\n\ndef test_when_package_has_missing_dependency():\n    \"\"\"Test the case when the builder tries to load the packages, but fails because of a missing dependency.\"\"\"\n    builder = AEABuilder()\n    expected_message = re.escape(\n        f\"Package '{str(OEF_CONNECTION_PUBLIC_ID)}' of type 'connection' cannot be added. \"\n        f\"Missing dependencies: ['(protocol, {str(OefSearchMessage.protocol_id)})']\"\n    )\n    with pytest.raises(AEAException, match=expected_message):\n        # connection \"fetchai/oef\" requires\n        # \"fetchai/oef_search\" and \"fetchai/fipa\" protocols.\n        builder.add_component(\n            ComponentType.CONNECTION,\n            Path(ROOT_DIR) / \"packages\" / \"fetchai\" / \"connections\" / \"oef\",\n        )\n\n\nclass TestReentrancy:\n    \"\"\"\n    Test the reentrancy of the AEABuilder class, when the components are loaded from directories.\n\n    Namely, it means that multiple calls to the AEABuilder class\n    should instantiate different AEAs in all their components.\n\n    For example:\n\n        builder = AEABuilder()\n        ... # add components etc.\n        aea1 = builder.build()\n        aea2 = builder.build()\n\n    Instances of components of aea1 are not shared with the aea2's ones.\n    \"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set up the test.\"\"\"\n        protocol_path = os.path.join(\n            ROOT_DIR, \"packages\", \"fetchai\", \"protocols\", \"oef_search\"\n        )\n        connection_path = os.path.join(\n            ROOT_DIR, \"packages\", \"fetchai\", \"connections\", \"soef\"\n        )\n\n        builder = AEABuilder()\n        builder.set_name(\"aea1\")\n        builder.add_private_key(DEFAULT_LEDGER)\n        builder.add_protocol(protocol_path)\n        builder.add_contract(contract_path)\n        builder.add_connection(connection_path)\n        builder.add_skill(dummy_skill_path)\n\n        cls.aea1 = builder.build()\n\n        builder.set_name(\"aea2\")\n        cls.aea2 = builder.build()\n\n    @staticmethod\n    def are_components_different(\n        components_a: Collection[Component],\n        components_b: Collection[Component],\n        is_including_config: bool = True,\n    ) -> None:\n        \"\"\"\n        Compare collections of component instances.\n\n        It only makes sense if they have the same number of elements and the same component ids.\n        \"\"\"\n        assert len(components_a) == len(\n            components_b\n        ), \"Cannot compare, number of components is different.\"\n        assert {c.component_id for c in components_a} == {\n            c.component_id for c in components_b\n        }, \"Cannot compare, component ids are different.\"\n\n        d1 = {c.component_id: c for c in components_a}\n        d2 = {c.component_id: c for c in components_b}\n        assert all(d1[k] is not d2[k] for k in d1.keys())\n\n        if is_including_config:\n            c1 = {c.component_id: c.configuration for c in components_a}\n            c2 = {c.component_id: c.configuration for c in components_b}\n            assert all(c1[k] is not c2[k] for k in c1.keys())\n\n    def test_skills_instances_are_different(self):\n        \"\"\"Test that skill instances are different.\"\"\"\n        aea1_skills = self.aea1.resources.get_all_skills()\n        aea2_skills = self.aea2.resources.get_all_skills()\n        self.are_components_different(aea1_skills, aea2_skills)\n\n    def test_protocols_instances_are_different(self):\n        \"\"\"Test that protocols instances are different.\"\"\"\n        aea1_protocols = self.aea1.resources.get_all_protocols()\n        aea2_protocols = self.aea2.resources.get_all_protocols()\n        self.are_components_different(aea1_protocols, aea2_protocols)\n\n    def test_contracts_instances_are_different(self):\n        \"\"\"Test that contract instances are different.\"\"\"\n        aea1_contracts = self.aea1.resources.get_all_contracts()\n        aea2_contracts = self.aea2.resources.get_all_contracts()\n        self.are_components_different(\n            aea1_contracts, aea2_contracts, is_including_config=False\n        )\n\n    def test_connections_instances_are_different(self):\n        \"\"\"Test that connection instances are different.\"\"\"\n        aea1_connections = self.aea1.runtime.multiplexer.connections\n        aea2_connections = self.aea2.runtime.multiplexer.connections\n        self.are_components_different(aea1_connections, aea2_connections)\n\n\ndef test_multiple_builds_with_private_keys():\n    \"\"\"Test multiple calls to the 'build()' method when adding custom private keys.\"\"\"\n    builder = AEABuilder()\n    builder.set_name(\"aea_1\")\n    builder.add_private_key(DEFAULT_LEDGER, DEFAULT_PRIVATE_KEY_PATH)\n\n    # the first call works\n    aea_1 = builder.build()\n    assert isinstance(aea_1, AEA)\n\n    # the second call fails\n    with pytest.raises(ValueError, match=\"Cannot build.*\"):\n        builder.build()\n\n    # after reset, it works\n    builder.reset()\n    builder.set_name(\"aea_1\")\n    builder.add_private_key(DEFAULT_LEDGER, DEFAULT_PRIVATE_KEY_PATH)\n    aea_2 = builder.build()\n    assert isinstance(aea_2, AEA)\n\n\ndef test_multiple_builds_with_component_instance():\n    \"\"\"Test multiple calls to the 'build()' method when adding component instances.\"\"\"\n    builder = AEABuilder()\n    builder.set_name(\"aea_1\")\n    builder.add_private_key(DEFAULT_LEDGER)\n\n    a_protocol = Protocol(\n        ProtocolConfig(\n            \"a_protocol\",\n            \"author\",\n            \"0.1.0\",\n            protocol_specification_id=\"some/author:0.1.0\",\n        ),\n        DefaultMessage,\n    )\n    builder.add_component_instance(a_protocol)\n\n    # the first call works\n    aea_1 = builder.build()\n    assert isinstance(aea_1, AEA)\n\n    # the second call fails\n    with pytest.raises(ValueError, match=\"Cannot build.*\"):\n        builder.build()\n\n    # after reset, it works\n    builder.reset()\n    builder.set_name(\"aea_1\")\n    builder.add_private_key(DEFAULT_LEDGER)\n    builder.add_component_instance(a_protocol)\n    aea_2 = builder.build()\n    assert isinstance(aea_2, AEA)\n\n\ndef test_dependency_manager_highest_version():\n    \"\"\"Test dependency version priority.\"\"\"\n    dep_manager = _DependenciesManager()\n    dep_manager.add_component(\n        ProtocolConfig(\n            \"a_protocol\",\n            \"author\",\n            \"0.1.0\",\n            protocol_specification_id=\"some/author:0.1.0\",\n        )\n    )\n    dep_manager.add_component(\n        ProtocolConfig(\n            \"a_protocol\",\n            \"author\",\n            \"0.2.0\",\n            protocol_specification_id=\"some/author:0.1.0\",\n        )\n    )\n\n    assert len(dep_manager.dependencies_highest_version) == 1\n    assert list(dep_manager.dependencies_highest_version)[0].version == \"0.2.0\"\n\n    assert len(dep_manager.protocols) == 2\n\n    assert len(dep_manager.skills) == 0\n    assert len(dep_manager.contracts) == 0\n\n\ndef test_remove_component_not_exists():\n    \"\"\"Test component remove not exists.\"\"\"\n    dep_manager = _DependenciesManager()\n    with pytest.raises(ValueError, match=r\"Component .* of type .* not present.\"):\n        dep_manager.remove_component(\n            ProtocolConfig(\n                \"a_protocol\",\n                \"author\",\n                \"0.1.0\",\n                protocol_specification_id=\"some/author:0.1.0\",\n            ).component_id\n        )\n\n\ndef test_remove_component_depends_on_fail():\n    \"\"\"Test component remove fails cause dependency.\"\"\"\n    dep_manager = _DependenciesManager()\n    protocol = ProtocolConfig(\n        \"a_protocol\", \"author\", \"0.1.0\", protocol_specification_id=\"some/author:0.1.0\"\n    )\n    dep_manager.add_component(protocol)\n    dep_manager.add_component(\n        SkillConfig(\"skill\", \"author\", \"0.1.0\", protocols=[protocol.public_id])\n    )\n\n    with pytest.raises(\n        ValueError,\n        match=r\"Cannot remove component .* of type .*. Other components depends on it: .*\",\n    ):\n        dep_manager.remove_component(protocol.component_id)\n\n\ndef test_remove_component_success():\n    \"\"\"Test remove registered component.\"\"\"\n    dep_manager = _DependenciesManager()\n    protocol = ProtocolConfig(\n        \"a_protocol\", \"author\", \"0.1.0\", protocol_specification_id=\"some/author:0.1.0\"\n    )\n    skill = SkillConfig(\"skill\", \"author\", \"0.1.0\", protocols=[protocol.public_id])\n    dep_manager.add_component(protocol)\n    dep_manager.add_component(skill)\n    dep_manager.remove_component(skill.component_id)\n\n\ndef test_private_keys():\n    \"\"\"Test add/remove private keys.\"\"\"\n    builder = AEABuilder()\n    builder.set_name(\"aea_1\")\n    builder.add_private_key(\"fetchai\")\n\n    builder.add_private_key(\"fetchai\", is_connection=True)\n\n    assert builder._connection_private_key_paths\n    assert builder._private_key_paths\n\n    builder.remove_private_key(\"fetchai\")\n    builder.remove_private_key(\"fetchai\", is_connection=True)\n\n    assert not builder._connection_private_key_paths\n    assert not builder._private_key_paths\n\n\ndef test_can_remove_not_exists_component():\n    \"\"\"Test fail on remove component not registered.\"\"\"\n    builder = AEABuilder()\n    builder.set_name(\"aea_1\")\n    builder.add_private_key(\"fetchai\")\n    protocol = ProtocolConfig(\n        \"a_protocol\", \"author\", \"0.1.0\", protocol_specification_id=\"some/author:0.1.0\"\n    )\n    with pytest.raises(ValueError):\n        builder._check_can_remove(protocol.component_id)\n\n\ndef test_remove_protocol():\n    \"\"\"Test add/remove protocol.\"\"\"\n    builder = AEABuilder()\n    builder.set_name(\"aea_1\")\n    builder.add_private_key(\"fetchai\")\n    a_protocol = Protocol(\n        ProtocolConfig(\n            \"a_protocol\",\n            \"author\",\n            \"0.1.0\",\n            protocol_specification_id=\"some/author:0.1.0\",\n        ),\n        DefaultMessage,\n    )\n    num_deps = len(builder._package_dependency_manager.all_dependencies)\n    builder.add_component_instance(a_protocol)\n    assert len(builder._package_dependency_manager.all_dependencies) == num_deps + 1\n    builder.remove_protocol(a_protocol.public_id)\n    assert len(builder._package_dependency_manager.all_dependencies) == num_deps\n\n\ndef test_remove_connection():\n    \"\"\"Test add/remove connection.\"\"\"\n    builder = AEABuilder()\n    builder.set_name(\"aea_1\")\n    builder.add_private_key(\"fetchai\")\n\n    num_deps = len(builder._package_dependency_manager.all_dependencies)\n    conn = _make_dummy_connection()\n    builder.add_component_instance(conn)\n    assert len(builder._package_dependency_manager.all_dependencies) == num_deps + 1\n    builder.remove_connection(conn.public_id)\n    assert len(builder._package_dependency_manager.all_dependencies) == num_deps\n\n\ndef test_remove_skill():\n    \"\"\"Test add/remove skill.\"\"\"\n    builder = AEABuilder()\n    builder.set_name(\"aea_1\")\n    builder.add_private_key(\"fetchai\")\n\n    skill = Skill.from_dir(dummy_skill_path, Mock(agent_name=\"name\"))\n    num_deps = len(builder._package_dependency_manager.all_dependencies)\n    builder.add_component_instance(skill)\n    assert len(builder._package_dependency_manager.all_dependencies) == num_deps + 1\n    builder.remove_skill(skill.public_id)\n    assert len(builder._package_dependency_manager.all_dependencies) == num_deps\n\n\ndef test_remove_contract():\n    \"\"\"Test add/remove contract.\"\"\"\n    builder = AEABuilder()\n    builder.set_name(\"aea_1\")\n    builder.add_private_key(\"fetchai\")\n\n    contract = Contract.from_dir(contract_path)\n    num_deps = len(builder._package_dependency_manager.all_dependencies)\n    builder.add_component_instance(contract)\n    assert len(builder._package_dependency_manager.all_dependencies) == num_deps + 1\n    builder.remove_contract(contract.public_id)\n    assert len(builder._package_dependency_manager.all_dependencies) == num_deps\n\n\ndef test_process_connection_ids_not_specified():\n    \"\"\"Test process connection fails on no connection specified.\"\"\"\n    builder = AEABuilder()\n    builder.set_name(\"aea_1\")\n    builder.add_private_key(\"fetchai\")\n\n    with pytest.raises(\n        ValueError, match=r\"Connection ids .* not declared in the configuration file.\"\n    ):\n        builder._process_connection_ids(\n            [ConnectionConfig(\"conn\", \"author\", \"0.1.0\").public_id]\n        )\n\n\ndef test_process_connection_ids_bad_default_connection():\n    \"\"\"Test fail on incorrect default connections.\"\"\"\n    builder = AEABuilder()\n    builder.set_name(\"aea_1\")\n    builder.add_private_key(\"fetchai\")\n    connection = _make_dummy_connection()\n    builder.add_component_instance(connection)\n    with pytest.raises(\n        ValueError,\n        match=r\"Default connection not a dependency. Please add it and retry.\",\n    ):\n        builder._default_connection = ConnectionConfig(\n            \"conn\", \"author\", \"0.1.0\"\n        ).public_id\n        builder._process_connection_ids([connection.public_id])\n\n\ndef test_component_add_bad_dep():\n    \"\"\"Test component load failed cause dependency.\"\"\"\n    builder = AEABuilder()\n    builder.set_name(\"aea_1\")\n    builder.add_private_key(\"fetchai\")\n    connection = _make_dummy_connection()\n    connection.configuration.pypi_dependencies = {\n        \"something\": Dependency(\"something\", \"==0.1.0\")\n    }\n    builder.add_component_instance(connection)\n\n    a_protocol = Protocol(\n        ProtocolConfig(\n            \"a_protocol\",\n            \"author\",\n            \"0.1.0\",\n            protocol_specification_id=\"some/author:0.1.0\",\n        ),\n        DefaultMessage,\n    )\n    a_protocol.configuration.pypi_dependencies = {\n        \"something\": Dependency(\"something\", \"==0.2.0\")\n    }\n    with pytest.raises(\n        AEAException, match=r\"Conflict on package something: specifier set .*\"\n    ):\n        builder.add_component_instance(a_protocol)\n\n\ndef test_set_from_config_default():\n    \"\"\"Test set configuration from config loaded.\"\"\"\n    builder = AEABuilder()\n    agent_configuration = Mock()\n    agent_configuration.default_ledger = \"fetchai\"\n    agent_configuration.required_ledgers = [\"fetchai\"]\n    agent_configuration.default_connection = \"test/test:0.1.0\"\n    agent_configuration.default_routing = {}\n    agent_configuration.decision_maker_handler = {}\n    agent_configuration.error_handler = {}\n    agent_configuration.skill_exception_policy = ExceptionPolicyEnum.just_log\n    agent_configuration.connection_exception_policy = ExceptionPolicyEnum.just_log\n    agent_configuration._default_connection = None\n    agent_configuration.connection_private_key_paths_dict = {\"fetchai\": None}\n    agent_configuration.ledger_apis_dict = {\"fetchai\": None}\n    agent_configuration.private_key_paths_dict = {\"fetchai\": None}\n    agent_configuration.protocols = (\n        agent_configuration.connections\n    ) = agent_configuration.contracts = agent_configuration.skills = []\n\n    with patch.object(builder, \"set_default_connection\"):\n        builder.set_from_configuration(agent_configuration, aea_project_path=\"/anydir\")\n    assert builder._decision_maker_handler_class is None\n    assert builder._decision_maker_handler_dotted_path is None\n    assert builder._decision_maker_handler_file_path is None\n    assert builder._load_decision_maker_handler_class() is None\n\n\ndef test_set_from_config_custom():\n    \"\"\"Test set configuration from config loaded.\"\"\"\n    dm_dotted_path = f\"aea.decision_maker.default{DOTTED_PATH_MODULE_ELEMENT_SEPARATOR}DecisionMakerHandler\"\n    dm_file_path = ROOT_DIR + \"/aea/decision_maker/default.py\"\n    builder = AEABuilder()\n    agent_configuration = Mock()\n    agent_configuration.default_ledger = \"fetchai\"\n    agent_configuration.required_ledgers = [\"fetchai\"]\n    agent_configuration.default_connection = \"test/test:0.1.0\"\n    agent_configuration.default_routing = {}\n    agent_configuration.decision_maker_handler = {\n        \"dotted_path\": dm_dotted_path,\n        \"file_path\": dm_file_path,\n        \"config\": {},\n    }\n    error_handler_dotted_path = (\n        f\"aea.error_handler.default{DOTTED_PATH_MODULE_ELEMENT_SEPARATOR}ErrorHandler\"\n    )\n    error_handler_file_path = ROOT_DIR + \"/aea/error_handler/default.py\"\n    agent_configuration.error_handler = {\n        \"dotted_path\": error_handler_dotted_path,\n        \"file_path\": error_handler_file_path,\n        \"config\": {},\n    }\n    agent_configuration.skill_exception_policy = ExceptionPolicyEnum.just_log\n    agent_configuration.connection_exception_policy = ExceptionPolicyEnum.just_log\n    agent_configuration._default_connection = None\n    agent_configuration.connection_private_key_paths_dict = {\"fetchai\": None}\n    agent_configuration.ledger_apis_dict = {\"fetchai\": None}\n    agent_configuration.private_key_paths_dict = {\"fetchai\": None}\n    agent_configuration.protocols = (\n        agent_configuration.connections\n    ) = agent_configuration.contracts = agent_configuration.skills = []\n\n    with patch.object(builder, \"set_default_connection\"):\n        builder.set_from_configuration(agent_configuration, aea_project_path=\"/anydir\")\n        assert builder._decision_maker_handler_class is None\n        assert builder._decision_maker_handler_dotted_path == dm_dotted_path\n        assert builder._decision_maker_handler_file_path == dm_file_path\n        assert builder._load_decision_maker_handler_class() is not None\n        assert builder._load_error_handler_class() is not None\n        builder.reset(is_full_reset=True)\n        agent_configuration.decision_maker_handler = {\n            \"dotted_path\": dm_dotted_path,\n            \"file_path\": None,\n            \"config\": {},\n        }\n        agent_configuration.error_handler = {\n            \"dotted_path\": error_handler_dotted_path,\n            \"file_path\": None,\n            \"config\": {},\n        }\n        builder.set_from_configuration(agent_configuration, aea_project_path=\"/anydir\")\n        assert builder._load_decision_maker_handler_class() is not None\n        assert builder._load_error_handler_class() is not None\n\n\ndef test_load_abstract_component():\n    \"\"\"Test abstract component loading.\"\"\"\n    resources = Resources()\n    builder = AEABuilder()\n    builder.set_name(\"aea_1\")\n    builder.add_private_key(\"fetchai\")\n\n    builder.add_component(ComponentType.SKILL, dummy_skill_path)\n    with mock.patch(\"aea.aea_builder.load_aea_package\"), mock.patch.object(\n        builder,\n        \"_overwrite_custom_configuration\",\n        return_value=Mock(is_abstract_component=True),\n    ), mock.patch.object(builder.logger, \"debug\") as mock_logger:\n        builder._load_and_add_components(\n            ComponentType.SKILL,\n            resources,\n            \"aea_1\",\n            agent_context=Mock(agent_name=\"name\"),\n        )\n\n        mock_logger.assert_called_with(\n            f\"Package {DUMMY_SKILL_PUBLIC_ID} of type skill is abstract, \"\n            f\"therefore only the Python modules have been loaded.\"\n        )\n\n    assert (\n        len(resources.get_all_skills()) == 0\n    ), \"expected 0 skills because the loaded skill is abstract\"\n\n\ndef test_find_import_order():\n    \"\"\"Test find import order works on cycle dependency.\"\"\"\n    builder = AEABuilder()\n    builder.set_name(\"aea_1\")\n    builder.add_private_key(\"fetchai\")\n\n    _old_load = load_component_configuration\n\n    def _new_load(*args, **kwargs):\n        skill_config = _old_load(*args, **kwargs)\n        # add loop\n        skill_config.skills = [skill_config.public_id]\n        return skill_config\n\n    with patch(\"aea.aea_builder.load_component_configuration\", _new_load):\n        with pytest.raises(\n            AEAException, match=r\"Cannot load skills, there is a cyclic dependency.\"\n        ):\n            builder._find_import_order(\n                [ComponentId(ComponentType.SKILL, DUMMY_SKILL_PUBLIC_ID)],\n                Path(os.path.join(CUR_PATH, \"data\", \"dummy_aea\")),\n                True,\n            )\n\n\ndef test__build_identity_from_wallet():\n    \"\"\"Test AEABuilder._build_identity_from_wallet.\"\"\"\n    builder = AEABuilder()\n    builder.set_name(\"aea_1\")\n    builder.add_private_key(\"fetchai\")\n\n    wallet = Mock()\n    wallet.addresses = {}\n    wallet.public_keys = {}\n    with pytest.raises(AEAWalletNoAddressException):\n        builder._build_identity_from_wallet(wallet)\n\n    wallet.addresses = {builder.get_default_ledger(): \"addr1\"}\n    wallet.public_keys = {builder.get_default_ledger(): \"pk1\"}\n    builder._build_identity_from_wallet(wallet)\n\n    wallet.addresses = {builder.get_default_ledger(): \"addr1\", \"some_ledger\": \"addr2\"}\n    wallet.public_keys = {builder.get_default_ledger(): \"pk11\", \"some_ledger\": \"pk2\"}\n    builder._build_identity_from_wallet(wallet)\n\n\nclass TestFromAEAProject(AEATestCaseEmpty):\n    \"\"\"Test builder set from project dir.\"\"\"\n\n    def test_from_project(self):\n        \"\"\"Test builder set from project dir.\"\"\"\n        self.generate_private_key()\n        self.add_private_key()\n        builder = AEABuilder.from_aea_project(Path(self._get_cwd()))\n        with cd(self._get_cwd()):\n            aea = builder.build()\n        assert aea.name == self.agent_name\n\n\nclass TestFromAEAProjectWithCustomConnectionConfig(AEATestCaseEmpty):\n    \"\"\"Test builder set from project dir with custom connection config.\"\"\"\n\n    def _add_stub_connection_config(self):\n        \"\"\"Add custom stub connection config.\"\"\"\n        self.generate_private_key()\n        self.add_private_key()\n        cwd = self._get_cwd()\n        aea_config_file = Path(cwd, DEFAULT_AEA_CONFIG_FILE)\n        configuration = aea_config_file.read_text()\n        connection_name = StubConnection.connection_id.name\n        connection_version = StubConnection.connection_id.version\n        configuration += dedent(\n            f\"\"\"\n        ---\n        public_id: fetchai/{connection_name}:{connection_version}\n        type: connection\n        config:\n            input_file: \"{self.expected_input_file}\"\n            output_file: \"{self.expected_output_file}\"\n        ...\n        \"\"\"\n        )\n        aea_config_file.write_text(configuration)\n\n    def test_from_project(self):\n        \"\"\"Test builder set from project dir.\"\"\"\n        self.add_item(\"connection\", \"fetchai/stub:0.21.3\")\n        self.expected_input_file = \"custom_input_file\"\n        self.expected_output_file = \"custom_output_file\"\n        self._add_stub_connection_config()\n        builder = AEABuilder.from_aea_project(Path(self._get_cwd()))\n        with cd(self._get_cwd()):\n            aea = builder.build()\n        assert aea.name == self.agent_name\n        stub_connection_id = StubConnection.connection_id\n        stub_connection = aea.resources.get_connection(stub_connection_id)\n        assert stub_connection.configuration.config == dict(\n            input_file=self.expected_input_file, output_file=self.expected_output_file\n        )\n\n\nclass TestFromAEAProjectWithCustomSkillConfig(AEATestCase):\n    \"\"\"Test builder set from project dir with custom skill config.\"\"\"\n\n    path_to_aea = Path(CUR_PATH) / \"data\" / \"dummy_aea\"\n\n    def _add_dummy_skill_config(self):\n        \"\"\"Add custom stub connection config.\"\"\"\n        cwd = self._get_cwd()\n        aea_config_file = Path(cwd, DEFAULT_AEA_CONFIG_FILE)\n        configuration = aea_config_file.read_text()\n        # here we change all the dummy skill configurations\n        configuration += dedent(\n            f\"\"\"\n        ---\n        public_id: dummy_author/dummy:0.1.0\n        type: skill\n        behaviours:\n          dummy:\n            args:\n            {indent(yaml.dump(self.new_behaviour_args), \"  \")}\n        handlers:\n          dummy:\n            args:\n            {indent(yaml.dump(self.new_handler_args), \"  \")}\n        models:\n          dummy:\n            args:\n            {indent(yaml.dump(self.new_model_args), \"  \")}\n        ...\n        \"\"\"\n        )\n        aea_config_file.write_text(configuration)\n\n    def test_from_project(self):\n        \"\"\"Test builder set from project dir.\"\"\"\n        self.new_behaviour_args = {\"behaviour_arg_1\": 42}\n        self.new_handler_args = {\"handler_arg_1\": 42}\n        self.new_model_args = {\"model_arg_1\": 42}\n        self._add_dummy_skill_config()\n        self.run_cli_command(\"issue-certificates\", cwd=self._get_cwd())\n        builder = AEABuilder.from_aea_project(Path(self._get_cwd()))\n\n        with cd(self._get_cwd()):\n            builder.call_all_build_entrypoints()\n            aea = builder.build()\n\n        dummy_skill = aea.resources.get_skill(DUMMY_SKILL_PUBLIC_ID)\n        dummy_behaviour = dummy_skill.behaviours[\"dummy\"]\n        assert dummy_behaviour.config == {\"behaviour_arg_1\": 42, \"behaviour_arg_2\": \"2\"}\n        dummy_handler = dummy_skill.handlers[\"dummy\"]\n        assert dummy_handler.config == {\"handler_arg_1\": 42, \"handler_arg_2\": \"2\"}\n        dummy_model = dummy_skill.models[\"dummy\"]\n        assert dummy_model.config == {\"model_arg_1\": 42, \"model_arg_2\": \"2\"}\n\n\nclass TestFromAEAProjectMakeSkillAbstract(AEATestCase):\n    \"\"\"Test builder set from project dir, to make a skill 'abstract'.\"\"\"\n\n    path_to_aea = Path(CUR_PATH) / \"data\" / \"dummy_aea\"\n\n    def _add_dummy_skill_config(self):\n        \"\"\"Add custom stub connection config.\"\"\"\n        cwd = self._get_cwd()\n        aea_config_file = Path(cwd, DEFAULT_AEA_CONFIG_FILE)\n        configuration = aea_config_file.read_text()\n        # here we change all the dummy skill configurations\n        configuration += dedent(\n            \"\"\"\n        ---\n        public_id: dummy_author/dummy:0.1.0\n        type: skill\n        is_abstract: true\n        ...\n        \"\"\"\n        )\n        aea_config_file.write_text(configuration)\n\n    def test_from_project(self):\n        \"\"\"Test builder set from project dir.\"\"\"\n        self._add_dummy_skill_config()\n        self.run_cli_command(\"issue-certificates\", cwd=self._get_cwd())\n        builder = AEABuilder.from_aea_project(Path(self._get_cwd()))\n        with cd(self._get_cwd()):\n            builder.call_all_build_entrypoints()\n            aea = builder.build()\n\n        dummy_skill = aea.resources.get_skill(DUMMY_SKILL_PUBLIC_ID)\n        assert dummy_skill is None, \"Shouldn't have found the skill in Resources.\"\n\n\nclass TestFromAEAProjectCustomConfigFailsWhenComponentNotDeclared(AEATestCaseEmpty):\n    \"\"\"Test builder set from project dir with custom component config fails when the component is not declared in the agent configuration.\"\"\"\n\n    def _add_stub_connection_config(self):\n        \"\"\"Add custom stub connection config.\"\"\"\n        cwd = self._get_cwd()\n        aea_config_file = Path(cwd, DEFAULT_AEA_CONFIG_FILE)\n        configuration = aea_config_file.read_text()\n        configuration += dedent(\n            \"\"\"\n        ---\n        public_id: some_author/non_existing_package:0.1.0\n        type: protocol\n        ...\n        \"\"\"\n        )\n        aea_config_file.write_text(configuration)\n\n    def test_from_project(self):\n        \"\"\"Test builder set from project dir.\"\"\"\n        self.expected_input_file = \"custom_input_file\"\n        self.expected_output_file = \"custom_output_file\"\n        self._add_stub_connection_config()\n        with pytest.raises(\n            AEAEnforceError,\n            match=r\"Component \\(protocol, some_author/non_existing_package:0.1.0\\) not declared in the agent configuration.\",\n        ):\n            with cd(self._get_cwd()):\n                AEABuilder.from_aea_project(Path(self._get_cwd()))\n\n\nclass TestExtraDeps(AEATestCaseEmpty):\n    \"\"\"Test builder set from project dir.\"\"\"\n\n    def test_check_dependencies_correct(self):\n        \"\"\"Test dependencies properly listed.\"\"\"\n        self.run_cli_command(\n            \"add\", \"--local\", \"connection\", \"fetchai/http_client\", cwd=self._get_cwd()\n        )\n        builder = AEABuilder.from_aea_project(Path(self._get_cwd()))\n        assert \"aiohttp\" in builder._package_dependency_manager.pypi_dependencies\n\n    def test_install_dependency(self):\n        \"\"\"Test dependencies installed.\"\"\"\n        package_name = \"async_generator\"\n        dependency = Dependency(package_name, \"==1.10\")\n        sys.modules.pop(package_name, None)\n        call_pip([\"uninstall\", package_name, \"-y\"])\n        try:\n            import_module(package_name)\n\n            raise Exception(\"should not be raised\")\n        except ModuleNotFoundError:\n            pass\n\n        builder = AEABuilder.from_aea_project(Path(self._get_cwd()))\n        with patch(\n            \"aea.aea_builder._DependenciesManager.pypi_dependencies\",\n            {\"package_name\": dependency},\n        ):\n            builder.install_pypi_dependencies()\n\n        import_module(package_name)\n\n        sys.modules.pop(package_name)\n        call_pip([\"uninstall\", package_name, \"-y\"])\n        try:\n            import_module(package_name)\n\n            raise Exception(\"should not be raised\")\n        except ModuleNotFoundError:\n            pass\n\n\nclass TestBuildEntrypoint(AEATestCaseEmpty):\n    \"\"\"Test build entrypoint.\"\"\"\n\n    def setup(self):\n        \"\"\"Set up the test.\"\"\"\n        self.builder = AEABuilder.from_aea_project(Path(self._get_cwd()))\n        self.component_id = \"component_id\"\n        # add project-wide build entrypoint\n        self.script_path = Path(\"script.py\")\n        self.builder._build_entrypoint = str(self.script_path)\n\n    def test_build_positive_aea(self):\n        \"\"\"Test build project-wide entrypoint, positive.\"\"\"\n        with cd(self._get_cwd()):\n            self.script_path.write_text(\"\")\n            with patch.object(self.builder.logger, \"info\") as info_mock:\n                self.builder.call_all_build_entrypoints()\n\n        info_mock.assert_any_call(\"Building AEA package...\")\n        info_mock.assert_any_call(RegexComparator(\"Running command '.*script.py .*'\"))\n\n    def test_build_positive_package(self):\n        \"\"\"Test build package entrypoint, positive.\"\"\"\n        with cd(self._get_cwd()):\n            self.script_path.write_text(\"\")\n            # add mock configuration build entrypoint\n            with patch.object(self.builder, \"_package_dependency_manager\") as _mock_mgr:\n                mock_config = MagicMock(\n                    component_id=self.component_id,\n                    build_entrypoint=str(self.script_path),\n                    directory=\".\",\n                    build_directory=\"test\",\n                )\n                mock_values = MagicMock(return_value=[mock_config])\n                _mock_mgr._dependencies = MagicMock(values=mock_values)\n\n                with patch.object(self.builder.logger, \"info\") as info_mock:\n                    self.builder.call_all_build_entrypoints()\n\n        info_mock.assert_any_call(f\"Building package {self.component_id}...\")\n        info_mock.assert_any_call(RegexComparator(\"Running command '.*script.py .*'\"))\n\n    def test_build_negative_syntax_error(self):\n        \"\"\"Test build, negative due to a syntax error in the script.\"\"\"\n        match = r\"The Python script at 'script.py' has a syntax error: invalid syntax \\(<unknown>, line 1\\): syntax\\+\\.error\\n\"\n        with cd(self._get_cwd()), pytest.raises(AEAException, match=match):\n            self.script_path.write_text(\"syntax+.error\")\n            self.builder.call_all_build_entrypoints()\n\n    @mock.patch(\n        \"aea.aea_builder.AEABuilder._run_in_subprocess\",\n        return_value=(\"\", \"some error.\", 1),\n    )\n    def test_build_negative_subprocess(self, *_mocks):\n        \"\"\"Test build, negative due to script error at runtime.\"\"\"\n        match = \"An error occurred while running command '.*script.py .+':\\nsome error.\"\n        with cd(self._get_cwd()), pytest.raises(AEAException, match=match):\n            self.script_path.write_text(\"\")\n            self.builder.call_all_build_entrypoints()\n\n\ndef test_set_default_connection_and_routing():\n    \"\"\"Test checks on default connection and routing set.\"\"\"\n    builder = AEABuilder()\n    builder._package_dependency_manager = Mock()\n    good_connection = ComponentId(\n        \"connection\", PublicId.from_str(\"good/connection:0.1.0\")\n    )\n    bad_connection = ComponentId(\n        \"connection\", PublicId.from_str(\"bad/connection:0.1.0\")\n    )\n    good_protocol = ComponentId(\"protocol\", PublicId.from_str(\"good/protocol:0.1.0\"))\n    bad_protocol = ComponentId(\"protocol\", PublicId.from_str(\"bad/protocol:0.1.0\"))\n\n    builder._package_dependency_manager.connections = [good_connection]\n    builder._package_dependency_manager.protocols = [good_protocol]\n\n    builder.set_default_connection(public_id=good_connection.public_id)\n    with pytest.raises(\n        ValueError,\n        match=\"Connection bad/connection:0.1.0 specified as `default_connection` is not a project dependency!\",\n    ):\n        builder.set_default_connection(public_id=bad_connection.public_id)\n\n    builder.set_default_routing({good_protocol.public_id: good_connection.public_id})\n\n    with pytest.raises(\n        ValueError,\n        match=\"Connection bad/connection:0.1.0 specified in `default_routing` is not a project dependency!\",\n    ):\n        builder.set_default_routing({good_protocol.public_id: bad_connection.public_id})\n\n    with pytest.raises(\n        ValueError,\n        match=\"Protocol bad/protocol:0.1.0 specified in `default_routing` is not a project dependency!\",\n    ):\n        builder.set_default_routing({bad_protocol.public_id: good_connection.public_id})\n\n\ndef test_builder_pypi_dependencies():\n    \"\"\"Test getter for PyPI dependencies.\"\"\"\n    dummy_aea_path = Path(CUR_PATH, \"data\", \"dummy_aea\")\n    builder = AEABuilder.from_aea_project(dummy_aea_path)\n    dependencies = builder._package_dependency_manager.pypi_dependencies\n    assert set(dependencies.keys()) == {\n        \"protobuf\",\n        \"aea-ledger-fetchai\",\n        \"aea-ledger-ethereum\",\n        \"aea-ledger-cosmos\",\n    }\n"
  },
  {
    "path": "tests/test_aea/test_agent.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the agent module.\"\"\"\nimport asyncio\nfrom threading import Thread\nfrom unittest.mock import Mock\n\nimport pytest\n\nfrom aea.agent import Agent, Identity\nfrom aea.runtime import RuntimeStates\n\nfrom packages.fetchai.connections.local.connection import LocalNode\n\nfrom tests.common.utils import wait_for_condition\nfrom tests.conftest import _make_local_connection\n\n\nclass DummyAgent(Agent):\n    \"\"\"A dummy agent for testing.\"\"\"\n\n    def __init__(self, *args, **kwargs):\n        \"\"\"Initialize the agent.\"\"\"\n        super().__init__(*args, **kwargs)\n\n    def setup(self) -> None:\n        \"\"\"Set up the agent.\"\"\"\n        pass\n\n    def act(self) -> None:\n        \"\"\"Act.\"\"\"\n        pass\n\n    def react(self) -> None:\n        \"\"\"React to events.\"\"\"\n        pass\n\n    def update(self) -> None:\n        \"\"\"Update the state of the agent.\"\"\"\n        pass\n\n    def teardown(self) -> None:\n        \"\"\"Tear down the agent.\"\"\"\n        pass\n\n    @property\n    def resources(self):\n        \"\"\"Get resources.\"\"\"\n        return Mock()\n\n\ndef test_run_agent():\n    \"\"\"Test that we can set up and then run the agent.\"\"\"\n    with LocalNode() as node:\n        agent_name = \"dummyagent\"\n        agent_address = \"some_address\"\n        agent_public_key = \"some_public_key\"\n        identity = Identity(\n            agent_name, address=agent_address, public_key=agent_public_key\n        )\n        oef_local_connection = _make_local_connection(\n            agent_address, agent_public_key, node\n        )\n        oef_local_connection._local_node = node\n\n        agent = DummyAgent(\n            identity, [oef_local_connection], loop=asyncio.new_event_loop()\n        )\n        agent_thread = Thread(target=agent.start)\n        assert agent.state == RuntimeStates.stopped\n        agent_thread.start()\n        try:\n            wait_for_condition(\n                lambda: agent.state == RuntimeStates.running,\n                timeout=10,\n                error_msg=\"Agent state must be 'running'\",\n            )\n        finally:\n            agent.stop()\n            assert agent.state == RuntimeStates.stopped\n            agent_thread.join()\n\n\ndef test_runtime_modes():\n    \"\"\"Test runtime modes are set.\"\"\"\n    agent_name = \"dummyagent\"\n    agent_address = \"some_address\"\n    agent_public_key = \"some_public_key\"\n    identity = Identity(agent_name, address=agent_address, public_key=agent_public_key)\n    agent = DummyAgent(\n        identity,\n        [],\n    )\n\n    assert not agent.is_running\n    assert agent.is_stopped\n\n    agent._runtime_mode = \"not exists\"\n\n    with pytest.raises(ValueError):\n        agent._get_runtime_class()\n\n    with pytest.raises(ValueError):\n        agent.runtime._get_agent_loop_class(\"not exists\")\n\n    assert agent.runtime.loop_mode == agent.runtime.DEFAULT_RUN_LOOP\n"
  },
  {
    "path": "tests/test_aea/test_agent_loop.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains tests of the implementation of an agent loop using asyncio.\"\"\"\nimport asyncio\nimport datetime\nimport logging\nfrom typing import Any, Callable, Dict, List, Optional, Sequence, Tuple, Type\nfrom unittest.mock import MagicMock, Mock, patch\n\nimport pytest\n\nfrom aea.aea import AEA\nfrom aea.agent_loop import AgentLoopStates, AsyncAgentLoop, BaseAgentLoop, SyncAgentLoop\nfrom aea.exceptions import AEAActException\nfrom aea.helpers.async_friendly_queue import AsyncFriendlyQueue\nfrom aea.helpers.exception_policy import ExceptionPolicyEnum\nfrom aea.mail.base import Envelope, EnvelopeContext\nfrom aea.protocols.base import Message\nfrom aea.registries.filter import Filter\nfrom aea.registries.resources import Resources\nfrom aea.skills.base import Behaviour, Handler, SkillContext\nfrom aea.skills.behaviours import TickerBehaviour\n\nfrom packages.fetchai.protocols.default.message import DefaultMessage\n\nfrom tests.common.utils import wait_for_condition, wait_for_condition_async\n\n\nclass CountHandler(Handler):\n    \"\"\"Simple handler to count how many message it gets.\"\"\"\n\n    def setup(self) -> None:\n        \"\"\"Set up handler.\"\"\"\n        self.counter = 0\n\n    def handle(self, message: Message) -> None:\n        \"\"\"Process incoming message.\"\"\"\n        self.counter += 1\n\n    def teardown(self) -> None:\n        \"\"\"Clean up handler.\"\"\"\n        pass\n\n    @classmethod\n    def make(cls) -> \"CountHandler\":\n        \"\"\"Construct handler.\"\"\"\n        return cls(name=\"test\", skill_context=SkillContext())\n\n\nclass CountBehaviour(TickerBehaviour):\n    \"\"\"Simple behaviour to count how many acts were called.\"\"\"\n\n    def setup(self) -> None:\n        \"\"\"Set up behaviour.\"\"\"\n        self.counter = 0\n\n    def act(self) -> None:\n        \"\"\"Make an action.\"\"\"\n        self.counter += 1\n\n    @classmethod\n    def make(cls, tick_interval: int = 1) -> \"CountBehaviour\":\n        \"\"\"Construct behaviour.\"\"\"\n        return cls(\n            name=\"test\", skill_context=SkillContext(), tick_interval=tick_interval\n        )\n\n\nclass FailBehaviour(TickerBehaviour):\n    \"\"\"Simple behaviour to raise an exception.\"\"\"\n\n    def setup(self) -> None:\n        \"\"\"Set up behaviour.\"\"\"\n        pass\n\n    def act(self) -> None:\n        \"\"\"Make an action.\"\"\"\n        raise ValueError(\"expected!\")\n\n    @classmethod\n    def make(cls, tick_interval: int = 1) -> \"FailBehaviour\":\n        \"\"\"Construct behaviour.\"\"\"\n        return cls(name=\"test\", skill_context=Mock(), tick_interval=tick_interval)\n\n\nclass AsyncFakeAgent(AEA):\n    \"\"\"Fake agent form testing.\"\"\"\n\n    name = \"fake_agent\"\n    _skills_exception_policy = ExceptionPolicyEnum.just_log\n\n    def __init__(self, handlers=None, behaviours=None):\n        \"\"\"Init agent.\"\"\"\n        self.handlers = handlers or []\n        self.behaviours = behaviours or []\n        self._runtime = MagicMock()\n        self.runtime.decision_maker.message_out_queue = AsyncFriendlyQueue()\n        self._inbox = AsyncFriendlyQueue()\n        self._runtime.agent_loop.skill2skill_queue = asyncio.Queue()\n        self._filter = Filter(\n            Resources(), self.runtime.decision_maker.message_out_queue\n        )\n        self._logger = logging.getLogger(\"fake agent\")\n        self._period = 0.001\n        self.filter.handle_internal_message = MagicMock()\n        self.filter.handle_new_handlers_and_behaviours = MagicMock()\n\n    def _get_behaviours_tasks(\n        self,\n    ) -> Dict[Callable, Tuple[float, Optional[datetime.datetime]]]:\n        tasks = {}\n        for behaviour in self.active_behaviours:\n            tasks[behaviour.act_wrapper] = (behaviour.tick_interval, behaviour.start_at)\n        return tasks\n\n    @property\n    def active_behaviours(self) -> List[Behaviour]:\n        \"\"\"Return all behaviours.\"\"\"\n        return self.behaviours\n\n    def _handle(self, envelope: Envelope) -> None:\n        \"\"\"\n        Handle an envelope.\n\n        :param envelope: the envelope to handle.\n        :return: None\n        \"\"\"\n        for handler in self.handlers:\n            handler.handle(envelope)\n\n    def put_inbox(self, msg: Any) -> None:\n        \"\"\"Add a message to inbox.\"\"\"\n        self._inbox.put_nowait(msg)  # type: ignore\n\n    def put_internal_message(self, msg: Any) -> None:\n        \"\"\"Add a message to internal queue.\"\"\"\n        self.runtime.decision_maker.message_out_queue.put_nowait(msg)\n\n    def _get_msg_and_handlers_for_envelope(\n        self, envelope: Envelope\n    ) -> Tuple[Optional[Message], List[Handler]]:\n        return envelope, self.handlers  # type: ignore\n\n    def _execution_control(\n        self,\n        fn: Callable,\n        args: Optional[Sequence] = None,\n        kwargs: Optional[Dict] = None,\n    ) -> Any:\n        \"\"\"\n        Execute skill function in exception handling environment.\n\n        Logs error, stop agent or propagate excepion depends on policy defined.\n\n        :param fn: function to call\n        :param component: skill component function belongs to\n        :param args: optional sequence of arguments to pass to function on call\n        :param kwargs: optional dict of keyword arguments to pass to function on call\n\n        :return: same as function\n        \"\"\"\n        return fn(*(args or []), **(kwargs or {}))\n\n    def _handle_envelope(self, envelope: Envelope) -> None:\n        for handler in self.handlers:\n            handler.handle(envelope)\n\n\nclass SyncFakeAgent(AsyncFakeAgent):\n    \"\"\"Fake agent for sync loop.\"\"\"\n\n    def put_inbox(self, msg: Any) -> None:\n        \"\"\"Add a message to inbox.\"\"\"\n        self._inbox.put_nowait(msg)  # type: ignore\n\n    def put_internal_message(self, msg: Any) -> None:\n        \"\"\"Add a message to internal queue.\"\"\"\n        self.runtime.decision_maker.message_out_queue.put_nowait(msg)\n\n\nclass TestAsyncAgentLoop:\n    \"\"\"Tests for asynchronous loop.\"\"\"\n\n    AGENT_LOOP_CLASS: Type[BaseAgentLoop] = AsyncAgentLoop\n    FAKE_AGENT_CLASS = AsyncFakeAgent\n\n    def test_loop_start_stop(self):\n        \"\"\"Test loop start and stopped properly.\"\"\"\n        agent = self.FAKE_AGENT_CLASS()\n        agent_loop = self.AGENT_LOOP_CLASS(agent, threaded=True)\n        agent.runtime.agent_loop = agent_loop\n        agent_loop.start()\n        wait_for_condition(lambda: agent_loop.is_running, timeout=10)\n        agent_loop.stop()\n        agent_loop.wait_completed(sync=True)\n        assert not agent_loop.is_running, agent_loop.state\n\n    def test_set_loop(self):\n        \"\"\"Test set loop.\"\"\"\n        agent_loop = self.AGENT_LOOP_CLASS(self.FAKE_AGENT_CLASS())\n\n        loop = asyncio.new_event_loop()\n        agent_loop.set_loop(loop=loop)\n        assert agent_loop._loop == loop\n\n    @pytest.mark.asyncio\n    async def test_state_property(self):\n        \"\"\"Test state property.\"\"\"\n        agent_loop = self.AGENT_LOOP_CLASS(self.FAKE_AGENT_CLASS())\n\n        assert agent_loop.state == AgentLoopStates.initial\n        await asyncio.wait_for(\n            agent_loop.wait_state(AgentLoopStates.initial), timeout=2\n        )\n\n    def test_handle_envelope(self):\n        \"\"\"Test one envelope handling.\"\"\"\n        handler = CountHandler.make()\n        agent = self.FAKE_AGENT_CLASS(handlers=[handler])\n        agent_loop = self.AGENT_LOOP_CLASS(agent, threaded=True)\n        agent.runtime.agent_loop = agent_loop\n        handler.setup()\n        agent_loop.start()\n        wait_for_condition(lambda: agent_loop.is_running, timeout=10)\n        agent.put_inbox(\"msg\")\n        wait_for_condition(lambda: handler.counter == 1, timeout=2)\n        agent_loop.stop()\n        agent_loop.wait_completed(sync=True)\n\n    def test_behaviour_act(self):\n        \"\"\"Test behaviour act called by schedule.\"\"\"\n        tick_interval = 0.1\n\n        behaviour = CountBehaviour.make(tick_interval=tick_interval)\n        behaviour.setup()\n        agent = self.FAKE_AGENT_CLASS(behaviours=[behaviour])\n        agent_loop = self.AGENT_LOOP_CLASS(agent, threaded=True)\n        agent.runtime.agent_loop = agent_loop\n        agent_loop.start()\n        wait_for_condition(lambda: agent_loop.is_running, timeout=10)\n\n        wait_for_condition(lambda: behaviour.counter >= 1, timeout=tick_interval * 2)\n        agent_loop.stop()\n        agent_loop.wait_completed(sync=True)\n\n    @pytest.mark.asyncio\n    async def test_internal_messages(self):\n        \"\"\"Test internal meesages are processed.\"\"\"\n        agent = self.FAKE_AGENT_CLASS()\n        agent_loop = self.AGENT_LOOP_CLASS(agent)\n        agent.runtime.agent_loop = agent_loop\n        agent_loop.start()\n        await asyncio.wait_for(\n            agent_loop.wait_state(AgentLoopStates.started), timeout=10\n        )\n        agent.put_internal_message(\"msg\")\n        await wait_for_condition_async(\n            lambda: agent.filter.handle_internal_message.called is True,\n            timeout=5,\n        )\n        agent_loop.stop()\n        await agent_loop.wait_completed()\n\n    def test_new_behaviours(self):\n        \"\"\"Test new behaviours are added.\"\"\"\n        agent = self.FAKE_AGENT_CLASS()\n        agent_loop = self.AGENT_LOOP_CLASS(agent, threaded=True)\n        agent_loop.NEW_BEHAVIOURS_PROCESS_SLEEP = 0.5\n        agent.runtime.agent_loop = agent_loop\n\n        agent_loop.start()\n        wait_for_condition(lambda: agent_loop.is_running, timeout=10)\n        wait_for_condition(\n            lambda: agent.filter.handle_new_handlers_and_behaviours.call_count >= 2,\n            timeout=agent_loop.NEW_BEHAVIOURS_PROCESS_SLEEP * 3,\n        )\n        agent_loop.stop()\n        agent_loop.wait_completed(sync=True)\n\n    @pytest.mark.asyncio\n    async def test_behaviour_exception(self):\n        \"\"\"Test behaviour exception reraised properly.\"\"\"\n        tick_interval = 0.1\n        behaviour = FailBehaviour.make(tick_interval)\n        agent = self.FAKE_AGENT_CLASS(behaviours=[behaviour])\n        agent_loop = self.AGENT_LOOP_CLASS(agent, threaded=True)\n        agent.runtime.agent_loop = agent_loop\n        agent._skills_exception_policy = ExceptionPolicyEnum.propagate\n\n        with pytest.raises(AEAActException):\n            with pytest.raises(ValueError, match=\"expected!\"):\n                agent_loop.start()\n                await agent_loop.wait_completed()\n\n        agent_loop.stop()\n        agent_loop.wait_completed(sync=True)\n\n    @pytest.mark.asyncio\n    async def test_stop(self):\n        \"\"\"Test loop stoped.\"\"\"\n        agent = self.FAKE_AGENT_CLASS()\n        agent_loop = self.AGENT_LOOP_CLASS(agent)\n        agent_loop.start()\n        await asyncio.wait_for(\n            agent_loop._state.wait(AgentLoopStates.started), timeout=10\n        )\n        agent_loop.stop()\n        await asyncio.wait_for(\n            agent_loop._state.wait(AgentLoopStates.stopped), timeout=10\n        )\n\n    @pytest.mark.asyncio\n    async def test_send_to_skill(self):\n        \"\"\"Test loop stoped.\"\"\"\n        agent = self.FAKE_AGENT_CLASS()\n        agent_loop = self.AGENT_LOOP_CLASS(agent)\n        agent_loop.start()\n        await asyncio.wait_for(\n            agent_loop._state.wait(AgentLoopStates.started), timeout=10\n        )\n\n        msg = DefaultMessage(performative=DefaultMessage.Performative.BYTES)\n        msg.to = \"to\"\n        msg.sender = \"sender\"\n        envelope = Envelope(\n            to=msg.to,\n            sender=msg.sender,\n            message=msg,\n            context=EnvelopeContext(connection_id=\"some_con\"),\n        )\n        try:\n            with pytest.raises(\n                ValueError, match=\"Unsupported message or envelope type:\"\n            ):\n                agent_loop.send_to_skill(\"something\")\n\n            with patch.object(agent_loop, \"_skill2skill_message_queue\"):\n                agent_loop.send_to_skill(msg)\n                agent_loop.send_to_skill(envelope)\n        finally:\n            agent_loop.stop()\n            await asyncio.wait_for(\n                agent_loop._state.wait(AgentLoopStates.stopped), timeout=10\n            )\n\n\nclass TestSyncAgentLoop:\n    \"\"\"Tests for synchronous loop.\"\"\"\n\n    AGENT_LOOP_CLASS: Type[BaseAgentLoop] = SyncAgentLoop\n    FAKE_AGENT_CLASS = SyncFakeAgent\n"
  },
  {
    "path": "tests/test_aea/test_cli/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This test module contains the tests for the cli tool commands.\"\"\"\n"
  },
  {
    "path": "tests/test_aea/test_cli/constants.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Constants used for CLI testing.\"\"\"\n\nfrom aea.configurations.base import DEFAULT_VERSION\n\n\nFORMAT_ITEMS_SAMPLE_OUTPUT = \"Correct items\"\n\nDEFAULT_TESTING_VERSION = DEFAULT_VERSION\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_add/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This test module contains the tests for the `aea add` sub-command.\"\"\"\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_add/test_connection.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This test module contains the tests for the `aea add connection` sub-command.\"\"\"\nimport os\nimport shutil\nimport tempfile\nimport unittest.mock\nfrom pathlib import Path\nfrom unittest.mock import patch\n\nimport pytest\nimport yaml\nfrom jsonschema import ValidationError\n\nimport aea.configurations.base\nfrom aea.cli import cli\nfrom aea.configurations.base import DEFAULT_CONNECTION_CONFIG_FILE, PublicId\nfrom aea.test_tools.test_cases import AEATestCaseEmpty, AEATestCaseEmptyFlaky\n\nfrom packages.fetchai.connections.http_client.connection import (\n    PUBLIC_ID as HTTP_CLIENT_PUBLIC_ID,\n)\nfrom packages.fetchai.connections.local.connection import (\n    PUBLIC_ID as LOCAL_CONNECTION_PUBLIC_ID,\n)\n\nfrom tests.conftest import (\n    AUTHOR,\n    CLI_LOG_OPTION,\n    CUR_PATH,\n    CliRunner,\n    MAX_FLAKY_RERUNS,\n    double_escape_windows_path_separator,\n)\n\n\nclass TestAddConnectionFailsWhenConnectionAlreadyExists:\n    \"\"\"Test that the command 'aea add connection' fails when the connection already exists.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        cls.connection_name = \"http_client\"\n        cls.connection_author = \"fetchai\"\n        cls.connection_version = \"0.3.0\"\n        cls.connection_id = str(HTTP_CLIENT_PUBLIC_ID)\n        # copy the 'packages' directory in the parent of the agent folder.\n        shutil.copytree(Path(CUR_PATH, \"..\", \"packages\"), Path(cls.t, \"packages\"))\n\n        os.chdir(cls.t)\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR],\n            standalone_mode=False,\n        )\n\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n        os.chdir(cls.agent_name)\n        # add connection first time\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"add\", \"--local\", \"connection\", cls.connection_id],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n        # add connection again\n        cls.result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"add\", \"--local\", \"connection\", cls.connection_id],\n            standalone_mode=False,\n        )\n\n    @unittest.mock.patch(\"aea.cli.add.get_package_path\", return_value=\"dest/path\")\n    @unittest.mock.patch(\"aea.cli.add.fetch_package\")\n    def test_add_connection_from_registry_positive(self, fetch_package_mock, *mocks):\n        \"\"\"Test add from registry positive result.\"\"\"\n        fetch_package_mock.return_value = Path(\n            \"vendor/{}/connections/{}\".format(\n                self.connection_author, self.connection_name\n            )\n        )\n        public_id = \"{}/{}:{}\".format(\n            AUTHOR, self.connection_name, self.connection_version\n        )\n        obj_type = \"connection\"\n        result = self.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"add\", obj_type, public_id],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n        public_id_obj = PublicId.from_str(public_id)\n        fetch_package_mock.assert_called_once_with(\n            obj_type, public_id=public_id_obj, cwd=\".\", dest=\"dest/path\"\n        )\n\n    def test_exit_code_equal_to_1(self):\n        \"\"\"Test that the exit code is equal to 1 (i.e. catchall for general errors).\"\"\"\n        assert self.result.exit_code == 1\n\n    def test_error_message_connection_already_existing(self):\n        \"\"\"Test that the log error message is fixed.\n\n        The expected message is: 'A connection with id '{connection_id}' already exists. Aborting...'\n        \"\"\"\n        s = f\"A connection with id '{self.connection_id}' already exists. Aborting...\"\n        assert self.result.exception.message == s\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestAddConnectionFailsWhenConnectionWithSameAuthorAndNameButDifferentVersion:\n    \"\"\"Test that 'aea add connection' fails when the connection with different version already exists.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        cls.connection_name = \"http_client\"\n        cls.connection_author = \"fetchai\"\n        cls.connection_version = \"0.3.0\"\n        cls.connection_id = str(HTTP_CLIENT_PUBLIC_ID)\n\n        # copy the 'packages' directory in the parent of the agent folder.\n        shutil.copytree(Path(CUR_PATH, \"..\", \"packages\"), Path(cls.t, \"packages\"))\n\n        os.chdir(cls.t)\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR],\n            standalone_mode=False,\n        )\n\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n        os.chdir(cls.agent_name)\n        # add connection first time\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"add\", \"--local\", \"connection\", cls.connection_id],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n\n        # add connection again, but with different version number\n        # first, change version number to package\n        different_version = \"0.1.1\"\n        different_id = (\n            cls.connection_author + \"/\" + cls.connection_name + \":\" + different_version\n        )\n        config_path = Path(\n            cls.t,\n            \"packages\",\n            cls.connection_author,\n            \"connections\",\n            cls.connection_name,\n            DEFAULT_CONNECTION_CONFIG_FILE,\n        )\n        config = yaml.safe_load(config_path.open())\n        config[\"version\"] = different_version\n        yaml.safe_dump(config, config_path.open(mode=\"w\"))\n        cls.result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"add\", \"--local\", \"connection\", different_id],\n            standalone_mode=False,\n        )\n\n    def test_exit_code_equal_to_1(self):\n        \"\"\"Test that the exit code is equal to 1 (i.e. catchall for general errors).\"\"\"\n        assert self.result.exit_code == 1\n\n    def test_error_message_connection_already_existing(self):\n        \"\"\"Test that the log error message is fixed.\n\n        The expected message is: 'A connection with id '{connection_id}' already exists. Aborting...'\n        \"\"\"\n        s = f\"A connection with id '{self.connection_id}' already exists. Aborting...\"\n        assert self.result.exception.message == s\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestAddConnectionFailsWhenConnectionNotInRegistry:\n    \"\"\"Test that the command 'aea add connection' fails when the connection is not in the registry.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        cls.connection_id = \"author/unknown_connection:0.1.0\"\n        cls.connection_name = \"unknown_connection\"\n\n        # copy the 'packages' directory in the parent of the agent folder.\n        shutil.copytree(Path(CUR_PATH, \"..\", \"packages\"), Path(cls.t, \"packages\"))\n\n        os.chdir(cls.t)\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR],\n            standalone_mode=False,\n        )\n\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n        os.chdir(cls.agent_name)\n        cls.result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"add\", \"--local\", \"connection\", cls.connection_id],\n            standalone_mode=False,\n        )\n\n    def test_exit_code_equal_to_1(self):\n        \"\"\"Test that the exit code is equal to 1 (i.e. catchall for general errors).\"\"\"\n        assert self.result.exit_code == 1\n\n    def test_error_message_connection_already_existing(self):\n        \"\"\"Test that the log error message is fixed.\n\n        The expected message is: 'Cannot find connection: '{connection_name}''\n        \"\"\"\n        s = \"Cannot find connection: '{}'.\".format(self.connection_id)\n        assert self.result.exception.message == s\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestAddConnectionFailsWhenDifferentPublicId:\n    \"\"\"Test that the command 'aea add connection' fails when the connection has not the same public id.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        cls.connection_id = \"different_author/local:0.1.0\"\n        cls.connection_name = \"unknown_connection\"\n\n        # copy the 'packages' directory in the parent of the agent folder.\n        shutil.copytree(Path(CUR_PATH, \"..\", \"packages\"), Path(cls.t, \"packages\"))\n\n        os.chdir(cls.t)\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR],\n            standalone_mode=False,\n        )\n\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n        os.chdir(cls.agent_name)\n        cls.result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"add\", \"--local\", \"connection\", cls.connection_id],\n            standalone_mode=False,\n        )\n\n    def test_exit_code_equal_to_1(self):\n        \"\"\"Test that the exit code is equal to 1 (i.e. catchall for general errors).\"\"\"\n        assert self.result.exit_code == 1\n\n    def test_error_message_connection_wrong_public_id(self):\n        \"\"\"Test that the log error message is fixed.\"\"\"\n        s = \"Cannot find connection: '{}'.\".format(self.connection_id)\n        assert self.result.exception.message == s\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestAddConnectionFailsWhenConfigFileIsNotCompliant:\n    \"\"\"Test that the command 'aea add connection' fails when the configuration file is not compliant with the schema.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        cls.connection_id = str(HTTP_CLIENT_PUBLIC_ID)\n        cls.connection_name = \"http_client\"\n\n        # copy the 'packages' directory in the parent of the agent folder.\n        shutil.copytree(Path(CUR_PATH, \"..\", \"packages\"), Path(cls.t, \"packages\"))\n\n        os.chdir(cls.t)\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR],\n            standalone_mode=False,\n        )\n\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n\n        # change the serialization of the AgentConfig class so to make the parsing to fail.\n        cls.patch = unittest.mock.patch.object(\n            aea.configurations.base.ConnectionConfig,\n            \"from_json\",\n            side_effect=ValidationError(\"test error message\"),\n        )\n        cls.patch.start()\n\n        os.chdir(cls.agent_name)\n        cls.result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"add\", \"--local\", \"connection\", cls.connection_id],\n            standalone_mode=False,\n        )\n\n    def test_exit_code_equal_to_1(self):\n        \"\"\"Test that the exit code is equal to 1 (i.e. catchall for general errors).\"\"\"\n        assert self.result.exit_code == 1\n\n    def test_configuration_file_not_valid(self):\n        \"\"\"Test that the log error message is fixed.\n\n        The expected message is: 'Connection configuration file not valid: '{connection_name}''\n        \"\"\"\n        s = \"Connection configuration file not valid: test error message\"\n        assert self.result.exception.message == s\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        cls.patch.stop()\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestAddConnectionFailsWhenDirectoryAlreadyExists:\n    \"\"\"Test that the command 'aea add connection' fails when the destination directory already exists.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        cls.connection_id = str(HTTP_CLIENT_PUBLIC_ID)\n        cls.connection_name = \"http_client\"\n\n        # copy the 'packages' directory in the parent of the agent folder.\n        shutil.copytree(Path(CUR_PATH, \"..\", \"packages\"), Path(cls.t, \"packages\"))\n\n        os.chdir(cls.t)\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR],\n            standalone_mode=False,\n        )\n\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n\n        os.chdir(cls.agent_name)\n        Path(\n            cls.t,\n            cls.agent_name,\n            \"vendor\",\n            \"fetchai\",\n            \"connections\",\n            cls.connection_name,\n        ).mkdir(parents=True, exist_ok=True)\n        cls.result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"add\", \"--local\", \"connection\", cls.connection_id],\n            standalone_mode=False,\n        )\n\n    def test_exit_code_equal_to_1(self):\n        \"\"\"Test that the exit code is equal to 1 (i.e. catchall for general errors).\"\"\"\n        assert self.result.exit_code == 1\n\n    def test_file_exists_error(self):\n        \"\"\"Test that the log error message is fixed.\n\n        The expected message is: 'Cannot find connection: '{connection_name}''\n        \"\"\"\n        missing_path = os.path.join(\n            \"vendor\", \"fetchai\", \"connections\", self.connection_name\n        )\n        missing_path = double_escape_windows_path_separator(missing_path)\n        assert missing_path in self.result.exception.message\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestAddConnectionFromRemoteRegistry(AEATestCaseEmptyFlaky):\n    \"\"\"Test case for add connection from Registry command.\"\"\"\n\n    IS_LOCAL = False\n    IS_EMPTY = True\n\n    @pytest.mark.integration\n    @pytest.mark.flaky(reruns=MAX_FLAKY_RERUNS)\n    def test_add_connection_from_remote_registry_positive(self):\n        \"\"\"Test add connection from Registry positive result.\"\"\"\n        self.add_item(\n            \"connection\",\n            str(LOCAL_CONNECTION_PUBLIC_ID.to_latest()),\n            local=self.IS_LOCAL,\n        )\n\n        items_path = os.path.join(self.agent_name, \"vendor\", \"fetchai\", \"connections\")\n        items_folders = os.listdir(items_path)\n        item_name = \"local\"\n        assert item_name in items_folders\n\n\nclass TestAddConnectionWithLatestVersion(AEATestCaseEmpty):\n    \"\"\"Test case for add connection with latest version.\"\"\"\n\n    def test_add_connection_latest_version(self):\n        \"\"\"Test add connection with latest version.\"\"\"\n        self.add_item(\n            \"connection\", str(LOCAL_CONNECTION_PUBLIC_ID.to_latest()), local=True\n        )\n\n        items_path = os.path.join(self.agent_name, \"vendor\", \"fetchai\", \"connections\")\n        items_folders = os.listdir(items_path)\n        item_name = \"local\"\n        assert item_name in items_folders\n\n\nclass TestAddConnectionMixedWhenNoLocalRegistryExists:\n    \"\"\"Test that the command 'aea add connection' works in mixed mode when the local registry does not exists (it swaps to remote).\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        cls.connection_id = str(HTTP_CLIENT_PUBLIC_ID)\n        cls.connection_name = \"http_client\"\n\n        os.chdir(cls.t)\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR],\n            standalone_mode=False,\n        )\n\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", cls.agent_name],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n\n        os.chdir(cls.agent_name)\n        with patch(\"aea.cli.registry.utils.request_api\"), patch(\n            \"aea.cli.add.fetch_package\"\n        ), patch(\"aea.cli.add.load_item_config\"), patch(\n            \"aea.cli.add.is_fingerprint_correct\"\n        ), patch(\n            \"aea.cli.add.register_item\"\n        ):\n\n            cls.result = cls.runner.invoke(\n                cli,\n                [*CLI_LOG_OPTION, \"add\", \"connection\", cls.connection_id],\n                standalone_mode=False,\n                catch_exceptions=False,\n            )\n\n    def test_exit_code_equal_to_0(self):\n        \"\"\"Test that the exit code is equal to 0.\"\"\"\n        assert self.result.exit_code == 0\n\n    def test_standard_output_mentions_swap_to_remote(self):\n        \"\"\"Test standard output contains information on swap to remote.\"\"\"\n        assert \"Trying remote registry (`--remote`).\" in self.result.stdout\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestAddConnectionLocalWhenNoLocalRegistryExists:\n    \"\"\"Test that the command 'aea add connection' fails in local mode when the local registry does not exists.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        cls.connection_id = str(HTTP_CLIENT_PUBLIC_ID)\n        cls.connection_name = \"http_client\"\n\n        os.chdir(cls.t)\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0, result.stdout\n\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", cls.agent_name],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0, result.stdout\n\n        os.chdir(cls.agent_name)\n        cls.result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"add\", \"--local\", \"connection\", cls.connection_id],\n            standalone_mode=False,\n        )\n\n    def test_exit_code_equal_to_1(self):\n        \"\"\"Test that the exit code is equal to 1.\"\"\"\n        assert self.result.exit_code == 1, self.result.stdout\n\n    def test_standard_output_mentions_failure(self):\n        \"\"\"Test standard output contains information on failure.\"\"\"\n        assert (\n            \"Registry path not provided and local registry `packages` not found in current (.) and parent directory.\"\n            in self.result.exception.message\n        )\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_add/test_contract.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This test module contains the tests for the `aea add contract` sub-command.\"\"\"\n\nimport os\nfrom unittest import TestCase, mock\n\nimport pytest\n\nfrom aea.cli import cli\nfrom aea.test_tools.test_cases import AEATestCaseEmptyFlaky\n\nfrom packages.fetchai.contracts.erc1155.contract import PUBLIC_ID as ERC1155_PUBLIC_ID\n\nfrom tests.conftest import CLI_LOG_OPTION, CliRunner, MAX_FLAKY_RERUNS\n\n\n@mock.patch(\"aea.cli.utils.decorators.try_to_load_agent_config\")\n@mock.patch(\"aea.cli.utils.decorators._validate_config_consistency\")\nclass AddContractCommandTestCase(TestCase):\n    \"\"\"Test that the command 'aea add contract' works as expected.\"\"\"\n\n    def setUp(self):\n        \"\"\"Set the test up.\"\"\"\n        self.runner = CliRunner()\n\n    @mock.patch(\"aea.cli.add.add_item\")\n    def test_add_contract_positive(self, *mocks):\n        \"\"\"Test add contract command positive result.\"\"\"\n        result = self.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"add\", \"contract\", \"author/name:0.1.0\"],\n            standalone_mode=False,\n        )\n        self.assertEqual(result.exit_code, 0)\n        result = self.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"add\", \"--local\", \"contract\", \"author/name:0.1.0\"],\n            standalone_mode=False,\n        )\n        self.assertEqual(result.exit_code, 0)\n\n\nclass TestAddContractFromRemoteRegistry(AEATestCaseEmptyFlaky):\n    \"\"\"Test case for add contract from Registry command.\"\"\"\n\n    IS_LOCAL = False\n    IS_EMPTY = True\n\n    @pytest.mark.integration\n    @pytest.mark.flaky(reruns=MAX_FLAKY_RERUNS)\n    def test_add_contract_from_remote_registry_positive(self):\n        \"\"\"Test add contract from Registry positive result.\"\"\"\n        self.add_item(\n            \"contract\", str(ERC1155_PUBLIC_ID.to_latest()), local=self.IS_LOCAL\n        )\n\n        items_path = os.path.join(self.agent_name, \"vendor\", \"fetchai\", \"contracts\")\n        items_folders = os.listdir(items_path)\n        item_name = \"erc1155\"\n        assert item_name in items_folders\n\n\nclass TestAddContractWithLatestVersion(AEATestCaseEmptyFlaky):\n    \"\"\"Test case for add contract with latest version.\"\"\"\n\n    IS_LOCAL = True\n\n    @pytest.mark.integration\n    @pytest.mark.flaky(reruns=MAX_FLAKY_RERUNS)\n    def test_add_contract_latest_version(self):\n        \"\"\"Test add contract with latest version.\"\"\"\n        self.add_item(\n            \"contract\", str(ERC1155_PUBLIC_ID.to_latest()), local=self.IS_LOCAL\n        )\n\n        items_path = os.path.join(self.agent_name, \"vendor\", \"fetchai\", \"contracts\")\n        items_folders = os.listdir(items_path)\n        item_name = \"erc1155\"\n        assert item_name in items_folders\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_add/test_generic.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This test module contains tests for aea.cli.add generic methods.\"\"\"\n\nfrom unittest import TestCase, mock\n\nfrom aea.cli.add import _add_item_deps\n\nfrom tests.test_aea.test_cli.tools_for_testing import ContextMock\n\n\nclass AddItemDepsTestCase(TestCase):\n    \"\"\"Test case for _add_item_deps method.\"\"\"\n\n    @mock.patch(\"aea.cli.add.add_item\")\n    def test__add_item_deps_missing_skills_positive(self, add_item_mock):\n        \"\"\"Test _add_item_deps for positive result with missing skills.\"\"\"\n        ctx = ContextMock(skills=[])\n        item_config = mock.Mock()\n        item_config.protocols = []\n        item_config.contracts = []\n        item_config.connections = []\n        item_config.skills = [\"skill-1\", \"skill-2\"]\n        _add_item_deps(ctx, \"skill\", item_config)\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_add/test_protocol.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This test module contains the tests for the `aea add protocol` sub-command.\"\"\"\nimport os\nimport re\nimport shutil\nimport tempfile\nimport unittest.mock\nfrom pathlib import Path\n\nimport pytest\nimport yaml\nfrom jsonschema import ValidationError\n\nimport aea.configurations.base\nfrom aea.cli import cli\nfrom aea.configurations.base import DEFAULT_PROTOCOL_CONFIG_FILE, PublicId\nfrom aea.test_tools.test_cases import AEATestCaseEmpty, AEATestCaseEmptyFlaky\n\nfrom packages.fetchai.protocols.fipa.message import FipaMessage\nfrom packages.fetchai.protocols.gym.message import GymMessage\n\nfrom tests.conftest import (\n    AUTHOR,\n    CLI_LOG_OPTION,\n    CUR_PATH,\n    CliRunner,\n    MAX_FLAKY_RERUNS,\n    double_escape_windows_path_separator,\n)\n\n\nclass TestAddProtocolFailsWhenProtocolAlreadyExists:\n    \"\"\"Test that the command 'aea add protocol' fails when the protocol already exists.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        cls.protocol_id = GymMessage.protocol_id\n        cls.protocol_name = cls.protocol_id.name\n        cls.protocol_author = cls.protocol_id.author\n        cls.protocol_version = cls.protocol_id.version\n\n        # copy the 'packages' directory in the parent of the agent folder.\n        shutil.copytree(Path(CUR_PATH, \"..\", \"packages\"), Path(cls.t, \"packages\"))\n\n        os.chdir(cls.t)\n\n        result = cls.runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n        assert result.exit_code == 0\n\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n        os.chdir(cls.agent_name)\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"add\", \"--local\", \"protocol\", str(cls.protocol_id)],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n        cls.result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"add\", \"--local\", \"protocol\", str(cls.protocol_id)],\n            standalone_mode=False,\n        )\n\n    def test_exit_code_equal_to_1(self):\n        \"\"\"Test that the exit code is equal to 1 (i.e. catchall for general errors).\"\"\"\n        assert self.result.exit_code == 1\n\n    def test_error_message_protocol_already_existing(self):\n        \"\"\"Test that the log error message is fixed.\n\n        The expected message is: 'A protocol with id '{protocol_id}' already exists. Aborting...'\n        \"\"\"\n        s = f\"A protocol with id '{self.protocol_id}' already exists. Aborting...\"\n        assert self.result.exception.message == s\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestAddProtocolFailsWhenProtocolWithSameAuthorAndNameButDifferentVersion:\n    \"\"\"Test that the command 'aea add protocol' fails when the protocol already exists.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        cls.protocol_id = GymMessage.protocol_id\n        cls.protocol_name = cls.protocol_id.name\n        cls.protocol_author = cls.protocol_id.author\n        cls.protocol_version = cls.protocol_id.version\n\n        # copy the 'packages' directory in the parent of the agent folder.\n        shutil.copytree(Path(CUR_PATH, \"..\", \"packages\"), Path(cls.t, \"packages\"))\n\n        os.chdir(cls.t)\n        result = cls.runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n        assert result.exit_code == 0\n\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n        os.chdir(cls.agent_name)\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"add\", \"--local\", \"protocol\", str(cls.protocol_id)],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n\n        # add protocol again, but with different version number\n        # first, change version number to package\n        different_version = \"0.1.1\"\n        different_id = (\n            cls.protocol_author + \"/\" + cls.protocol_name + \":\" + different_version\n        )\n        config_path = Path(\n            cls.t,\n            \"packages\",\n            cls.protocol_author,\n            \"protocols\",\n            cls.protocol_name,\n            DEFAULT_PROTOCOL_CONFIG_FILE,\n        )\n        config = yaml.safe_load(config_path.open())\n        config[\"version\"] = different_version\n        yaml.safe_dump(config, config_path.open(mode=\"w\"))\n        cls.result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"add\", \"--local\", \"protocol\", different_id],\n            standalone_mode=False,\n        )\n\n    def test_exit_code_equal_to_1(self):\n        \"\"\"Test that the exit code is equal to 1 (i.e. catchall for general errors).\"\"\"\n        assert self.result.exit_code == 1\n\n    def test_error_message_protocol_already_existing(self):\n        \"\"\"Test that the log error message is fixed.\n\n        The expected message is: 'A protocol with id '{protocol_id}' already exists. Aborting...'\n        \"\"\"\n        s = f\"A protocol with id '{self.protocol_id}' already exists. Aborting...\"\n        assert self.result.exception.message == s\n\n    @unittest.mock.patch(\"aea.cli.add.get_package_path\", return_value=\"dest/path\")\n    @unittest.mock.patch(\"aea.cli.add.fetch_package\")\n    def test_add_protocol_from_registry_positive(self, fetch_package_mock, *mocks):\n        \"\"\"Test add from registry positive result.\"\"\"\n        fetch_package_mock.return_value = Path(\n            \"vendor/{}/protocols/{}\".format(self.protocol_author, self.protocol_name)\n        )\n        public_id = \"{}/{}:{}\".format(AUTHOR, self.protocol_name, self.protocol_version)\n        obj_type = \"protocol\"\n        result = self.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"add\", obj_type, public_id],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n        public_id_obj = PublicId.from_str(public_id)\n        fetch_package_mock.assert_called_once_with(\n            obj_type, public_id=public_id_obj, cwd=\".\", dest=\"dest/path\"\n        )\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestAddProtocolFailsWhenProtocolNotInRegistry:\n    \"\"\"Test that the command 'aea add protocol' fails when the protocol is not in the registry.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        cls.protocol_id = \"user/unknown_protocol:0.1.0\"\n\n        # copy the 'packages' directory in the parent of the agent folder.\n        shutil.copytree(Path(CUR_PATH, \"..\", \"packages\"), Path(cls.t, \"packages\"))\n\n        os.chdir(cls.t)\n        result = cls.runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n        assert result.exit_code == 0\n\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n        os.chdir(cls.agent_name)\n        cls.result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"add\", \"--local\", \"protocol\", cls.protocol_id],\n            standalone_mode=False,\n        )\n\n    def test_exit_code_equal_to_1(self):\n        \"\"\"Test that the exit code is equal to 1 (i.e. catchall for general errors).\"\"\"\n        assert self.result.exit_code == 1\n\n    def test_error_message_protocol_already_existing(self):\n        \"\"\"Test that the log error message is fixed.\n\n        The expected message is: 'Cannot find protocol: '{protocol_name}''\n        \"\"\"\n        s = \"Cannot find protocol: '{}'.\".format(self.protocol_id)\n        assert self.result.exception.message == s\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestAddProtocolFailsWhenDifferentPublicId:\n    \"\"\"Test that the command 'aea add protocol' fails when the protocol has not the same public id.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        cls.protocol_id = \"different_author/default:1.0.0\"\n\n        # copy the 'packages' directory in the parent of the agent folder.\n        shutil.copytree(Path(CUR_PATH, \"..\", \"packages\"), Path(cls.t, \"packages\"))\n\n        os.chdir(cls.t)\n        result = cls.runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n        assert result.exit_code == 0\n\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n        os.chdir(cls.agent_name)\n        cls.result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"add\", \"--local\", \"protocol\", cls.protocol_id],\n            standalone_mode=False,\n        )\n\n    def test_exit_code_equal_to_1(self):\n        \"\"\"Test that the exit code is equal to 1 (i.e. catchall for general errors).\"\"\"\n        assert self.result.exit_code == 1\n\n    def test_error_message_protocol_wrong_public_id(self):\n        \"\"\"Test that the log error message is fixed.\"\"\"\n        s = \"Cannot find protocol: '{}'.\".format(self.protocol_id)\n        assert self.result.exception.message == s\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestAddProtocolFailsWhenConfigFileIsNotCompliant:\n    \"\"\"Test that the command 'aea add protocol' fails when the configuration file is not compliant with the schema.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        cls.protocol_id = str(GymMessage.protocol_id)\n\n        # copy the 'packages' directory in the parent of the agent folder.\n        shutil.copytree(Path(CUR_PATH, \"..\", \"packages\"), Path(cls.t, \"packages\"))\n\n        os.chdir(cls.t)\n        result = cls.runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n        assert result.exit_code == 0\n\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n\n        # change the serialization of the ProtocolConfig class so to make the parsing to fail.\n        cls.patch = unittest.mock.patch.object(\n            aea.configurations.base.ProtocolConfig,\n            \"from_json\",\n            side_effect=ValidationError(\"test error message\"),\n        )\n        cls.patch.start()\n\n        os.chdir(cls.agent_name)\n        cls.result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"add\", \"--local\", \"protocol\", cls.protocol_id],\n            standalone_mode=False,\n        )\n\n    def test_exit_code_equal_to_1(self):\n        \"\"\"Test that the exit code is equal to 1 (i.e. catchall for general errors).\"\"\"\n        assert self.result.exit_code == 1\n\n    def test_configuration_file_not_valid(self):\n        \"\"\"Test that the log error message is fixed.\n\n        The expected message is: 'Protocol configuration file not valid: ...'\n        \"\"\"\n        assert re.match(\n            \"Protocol configuration file '.*' not valid: test error message\",\n            self.result.exception.message,\n        )\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        cls.patch.stop()\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestAddProtocolFailsWhenDirectoryAlreadyExists:\n    \"\"\"Test that the command 'aea add protocol' fails when the destination directory already exists.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        cls.protocol_id = str(GymMessage.protocol_id)\n        cls.protocol_name = \"gym\"\n\n        # copy the 'packages' directory in the parent of the agent folder.\n        shutil.copytree(Path(CUR_PATH, \"..\", \"packages\"), Path(cls.t, \"packages\"))\n\n        os.chdir(cls.t)\n        result = cls.runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n        assert result.exit_code == 0\n\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n\n        os.chdir(cls.agent_name)\n        Path(\n            cls.t, cls.agent_name, \"vendor\", \"fetchai\", \"protocols\", cls.protocol_name\n        ).mkdir(parents=True, exist_ok=True)\n        cls.result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"add\", \"--local\", \"protocol\", cls.protocol_id],\n            standalone_mode=False,\n        )\n\n    def test_exit_code_equal_to_1(self):\n        \"\"\"Test that the exit code is equal to 1 (i.e. catchall for general errors).\"\"\"\n        assert self.result.exit_code == 1\n\n    def test_file_exists_error(self):\n        \"\"\"Test that the log error message is fixed.\n\n        The expected message is: 'Cannot find protocol: '{protocol_name}''\n        \"\"\"\n        missing_path = os.path.join(\n            \"vendor\", \"fetchai\", \"protocols\", self.protocol_name\n        )\n        missing_path = double_escape_windows_path_separator(missing_path)\n        assert missing_path in self.result.exception.message\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestAddProtocolFromRemoteRegistry(AEATestCaseEmptyFlaky):\n    \"\"\"Test case for add protocol from Registry command.\"\"\"\n\n    IS_LOCAL = False\n    IS_EMPTY = True\n\n    @pytest.mark.integration\n    @pytest.mark.flaky(reruns=MAX_FLAKY_RERUNS)\n    def test_add_protocol_from_remote_registry_positive(self):\n        \"\"\"Test add protocol from Registry positive result.\"\"\"\n        self.add_item(\n            \"protocol\", str(FipaMessage.protocol_id.to_latest()), local=self.IS_LOCAL\n        )\n\n        items_path = os.path.join(self.agent_name, \"vendor\", \"fetchai\", \"protocols\")\n        items_folders = os.listdir(items_path)\n        item_name = \"fipa\"\n        assert item_name in items_folders\n\n\nclass TestAddProtocolWithLatestVersion(AEATestCaseEmpty):\n    \"\"\"Test case for add protocol with latest version.\"\"\"\n\n    def test_add_protocol_latest_version(self):\n        \"\"\"Test add protocol with latest version.\"\"\"\n        self.add_item(\"protocol\", str(FipaMessage.protocol_id.to_latest()), local=True)\n\n        items_path = os.path.join(self.agent_name, \"vendor\", \"fetchai\", \"protocols\")\n        items_folders = os.listdir(items_path)\n        item_name = \"fipa\"\n        assert item_name in items_folders\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_add/test_skill.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\n\"\"\"This test module contains the tests for the `aea add skill` sub-command.\"\"\"\n\nimport os\nimport shutil\nimport tempfile\nfrom pathlib import Path\nfrom unittest import mock\n\nimport click\nimport pytest\nimport yaml\nfrom jsonschema import ValidationError\n\nimport aea\nfrom aea.cli import cli\nfrom aea.configurations.base import (\n    AgentConfig,\n    DEFAULT_AEA_CONFIG_FILE,\n    DEFAULT_SKILL_CONFIG_FILE,\n    PublicId,\n)\nfrom aea.test_tools.test_cases import AEATestCaseEmpty, AEATestCaseEmptyFlaky\n\nfrom packages.fetchai.skills.echo import PUBLIC_ID as ECHO_PUBLIC_ID\nfrom packages.fetchai.skills.erc1155_client import PUBLIC_ID as ERC1155_CLIENT_PUBLIC_ID\nfrom packages.fetchai.skills.error import PUBLIC_ID as ERROR_PUBLIC_ID\n\nfrom tests.conftest import (\n    AUTHOR,\n    CLI_LOG_OPTION,\n    CUR_PATH,\n    CliRunner,\n    MAX_FLAKY_RERUNS,\n    ROOT_DIR,\n    double_escape_windows_path_separator,\n)\n\n\nclass TestAddSkillFailsWhenSkillAlreadyExists:\n    \"\"\"Test that the command 'aea add skill' fails when the skill already exists.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        cls.skill_id = ERROR_PUBLIC_ID\n        cls.skill_name = cls.skill_id.name\n        cls.skill_author = cls.skill_id.author\n        cls.skill_version = cls.skill_id.version\n\n        # copy the 'packages' directory in the parent of the agent folder.\n        shutil.copytree(Path(CUR_PATH, \"..\", \"packages\"), Path(cls.t, \"packages\"))\n\n        os.chdir(cls.t)\n        result = cls.runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n        assert result.exit_code == 0\n\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name],\n            standalone_mode=False,\n        )\n        # this also by default adds the stub connection\n        assert result.exit_code == 0\n        os.chdir(cls.agent_name)\n        cls.result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"add\", \"--local\", \"skill\", str(cls.skill_id)],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n\n        # add the error skill again\n        cls.result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"add\", \"--local\", \"skill\", str(cls.skill_id)],\n            standalone_mode=False,\n        )\n\n    def test_exit_code_equal_to_1(self):\n        \"\"\"Test that the exit code is equal to 1 (i.e. catchall for general errors).\"\"\"\n        assert self.result.exit_code == 1\n\n    def test_error_message_skill_already_existing(self):\n        \"\"\"Test that the log error message is fixed.\n\n        The expected message is: 'A skill with id '{skill_id}' already exists. Aborting...'\n        \"\"\"\n        s = f\"A skill with id '{self.skill_id}' already exists. Aborting...\"\n        assert self.result.exception.message == s\n\n    @mock.patch(\"aea.cli.add.get_package_path\", return_value=\"dest/path\")\n    @mock.patch(\"aea.cli.add.fetch_package\")\n    def test_add_skill_from_registry_positive(self, fetch_package_mock, *mocks):\n        \"\"\"Test add from registry positive result.\"\"\"\n        fetch_package_mock.return_value = Path(\n            \"vendor/{}/skills/{}\".format(self.skill_author, self.skill_name)\n        )\n        public_id = \"{}/{}:{}\".format(AUTHOR, self.skill_name, self.skill_version)\n        obj_type = \"skill\"\n        result = self.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"add\", obj_type, public_id],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n        public_id_obj = PublicId.from_str(public_id)\n        fetch_package_mock.assert_called_once_with(\n            obj_type, public_id=public_id_obj, cwd=\".\", dest=\"dest/path\"\n        )\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestAddSkillFailsWhenSkillWithSameAuthorAndNameButDifferentVersion:\n    \"\"\"Test that the command 'aea add skill' fails when the skill already exists.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        cls.skill_id = ECHO_PUBLIC_ID\n        cls.skill_name = cls.skill_id.name\n        cls.skill_author = cls.skill_id.author\n        cls.skill_version = cls.skill_id.version\n\n        # copy the 'packages' directory in the parent of the agent folder.\n        shutil.copytree(Path(CUR_PATH, \"..\", \"packages\"), Path(cls.t, \"packages\"))\n\n        os.chdir(cls.t)\n        result = cls.runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n        assert result.exit_code == 0\n\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name],\n            standalone_mode=False,\n        )\n        # this also by default adds the stub connection\n        assert result.exit_code == 0\n        os.chdir(cls.agent_name)\n        cls.result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"add\", \"--local\", \"skill\", str(cls.skill_id)],\n            standalone_mode=False,\n        )\n        assert cls.result.exit_code == 0\n\n        # add skill again, but with different version number\n        # first, change version number to package\n        different_version = \"0.1.1\"\n        different_id = cls.skill_author + \"/\" + cls.skill_name + \":\" + different_version\n        config_path = Path(\n            cls.t,\n            \"packages\",\n            cls.skill_author,\n            \"skills\",\n            cls.skill_name,\n            DEFAULT_SKILL_CONFIG_FILE,\n        )\n        config = yaml.safe_load(config_path.open())\n        config[\"version\"] = different_version\n        yaml.safe_dump(config, config_path.open(mode=\"w\"))\n        cls.result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"add\", \"--local\", \"skill\", different_id],\n            standalone_mode=False,\n        )\n\n    def test_exit_code_equal_to_1(self):\n        \"\"\"Test that the exit code is equal to 1 (i.e. catchall for general errors).\"\"\"\n        assert self.result.exit_code == 1\n\n    def test_error_message_skill_already_existing(self):\n        \"\"\"Test that the log error message is fixed.\n\n        The expected message is: 'A skill with id '{skill_id}' already exists. Aborting...'\n        \"\"\"\n        s = f\"A skill with id '{self.skill_id}' already exists. Aborting...\"\n        assert self.result.exception.message == s\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestAddSkillFailsWhenSkillNotInRegistry:\n    \"\"\"Test that the command 'aea add skill' fails when the skill is not in the registry.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        cls.skill_id = \"author/unknown_skill:0.1.0\"\n        cls.skill_name = \"unknown_skill\"\n\n        # copy the 'packages' directory in the parent of the agent folder.\n        shutil.copytree(Path(CUR_PATH, \"..\", \"packages\"), Path(cls.t, \"packages\"))\n\n        os.chdir(cls.t)\n        result = cls.runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n        assert result.exit_code == 0\n\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n        os.chdir(cls.agent_name)\n        cls.result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"add\", \"--local\", \"skill\", cls.skill_id],\n            standalone_mode=False,\n        )\n\n    def test_exit_code_equal_to_1(self):\n        \"\"\"Test that the exit code is equal to 1 (i.e. catchall for general errors).\"\"\"\n        assert self.result.exit_code == 1\n\n    def test_error_message_skill_already_existing(self):\n        \"\"\"Test that the log error message is fixed.\n\n        The expected message is: 'Cannot find skill: '{skill_name}''\n        \"\"\"\n        s = \"Cannot find skill: '{}'.\".format(self.skill_id)\n        assert self.result.exception.message == s\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestAddSkillFailsWhenDifferentPublicId:\n    \"\"\"Test that the command 'aea add skill' fails when the skill has not the same public id.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        cls.skill_id = \"different_author/error:0.1.0\"\n        cls.skill_name = \"unknown_skill\"\n\n        # copy the 'packages' directory in the parent of the agent folder.\n        shutil.copytree(Path(CUR_PATH, \"..\", \"packages\"), Path(cls.t, \"packages\"))\n\n        os.chdir(cls.t)\n        result = cls.runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n        assert result.exit_code == 0\n\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n        os.chdir(cls.agent_name)\n        cls.result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"add\", \"--local\", \"skill\", cls.skill_id],\n            standalone_mode=False,\n        )\n\n    def test_exit_code_equal_to_1(self):\n        \"\"\"Test that the exit code is equal to 1 (i.e. catchall for general errors).\"\"\"\n        assert self.result.exit_code == 1\n\n    def test_error_message_skill_wrong_public_id(self):\n        \"\"\"Test that the log error message is fixed.\"\"\"\n        s = \"Cannot find skill: '{}'.\".format(self.skill_id)\n        assert self.result.exception.message == s\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestAddSkillFailsWhenConfigFileIsNotCompliant:\n    \"\"\"Test that the command 'aea add skill' fails when the configuration file is not compliant with the schema.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        cls.skill_id = str(ECHO_PUBLIC_ID)\n        cls.skill_name = \"echo\"\n\n        # copy the 'packages' directory in the parent of the agent folder.\n        shutil.copytree(Path(CUR_PATH, \"..\", \"packages\"), Path(cls.t, \"packages\"))\n\n        os.chdir(cls.t)\n        result = cls.runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n        assert result.exit_code == 0\n\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n        os.chdir(cls.agent_name)\n\n        # change default registry path\n        config = AgentConfig.from_json(yaml.safe_load(open(DEFAULT_AEA_CONFIG_FILE)))\n        config.registry_path = os.path.join(ROOT_DIR, \"packages\")\n        yaml.safe_dump(dict(config.json), open(DEFAULT_AEA_CONFIG_FILE, \"w\"))\n\n        # change the serialization of the AgentConfig class so to make the parsing to fail.\n        cls.patch = mock.patch.object(\n            aea.configurations.base.SkillConfig,\n            \"from_json\",\n            side_effect=ValidationError(\"test error message\"),\n        )\n        cls.patch.start()\n\n        cls.result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"add\", \"--local\", \"skill\", cls.skill_id],\n            standalone_mode=False,\n        )\n\n    def test_exit_code_equal_to_1(self):\n        \"\"\"Test that the exit code is equal to 1 (i.e. catchall for general errors).\"\"\"\n        assert self.result.exit_code == 1\n\n    def test_configuration_file_not_valid(self):\n        \"\"\"Test that the log error message is fixed.\n\n        The expected message is: 'Cannot find skill: '{skill_name}''\n        \"\"\"\n        s = \"Skill configuration file not valid: test error message\"\n        assert self.result.exception.message == s\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        cls.patch.stop()\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestAddSkillFailsWhenDirectoryAlreadyExists:\n    \"\"\"Test that the command 'aea add skill' fails when the destination directory already exists.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        cls.skill_id = str(ECHO_PUBLIC_ID)\n        cls.skill_name = \"echo\"\n\n        # copy the 'packages' directory in the parent of the agent folder.\n        shutil.copytree(Path(CUR_PATH, \"..\", \"packages\"), Path(cls.t, \"packages\"))\n\n        os.chdir(cls.t)\n        result = cls.runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n        assert result.exit_code == 0\n\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n        os.chdir(cls.agent_name)\n\n        # change default registry path\n        config = AgentConfig.from_json(yaml.safe_load(open(DEFAULT_AEA_CONFIG_FILE)))\n        config.registry_path = os.path.join(ROOT_DIR, \"packages\")\n        yaml.safe_dump(dict(config.json), open(DEFAULT_AEA_CONFIG_FILE, \"w\"))\n\n        Path(\n            cls.t, cls.agent_name, \"vendor\", \"fetchai\", \"skills\", cls.skill_name\n        ).mkdir(parents=True, exist_ok=True)\n        cls.result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"add\", \"--local\", \"skill\", cls.skill_id],\n            standalone_mode=False,\n        )\n\n    def test_exit_code_equal_to_1(self):\n        \"\"\"Test that the exit code is equal to 1 (i.e. catchall for general errors).\"\"\"\n        assert self.result.exit_code == 1\n\n    def test_file_exists_error(self):\n        \"\"\"Test that the log error message is fixed.\n\n        The expected message is: 'Cannot find skill: '{skill_name}''\n        \"\"\"\n        missing_path = os.path.join(\"vendor\", \"fetchai\", \"skills\", self.skill_name)\n        missing_path = double_escape_windows_path_separator(missing_path)\n        assert missing_path in self.result.exception.message\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestAddSkillWithContractsDeps(AEATestCaseEmpty):\n    \"\"\"Test add skill with contract dependencies.\"\"\"\n\n    def test_add_skill_with_contracts_positive(self):\n        \"\"\"Test add skill with contract dependencies positive result.\"\"\"\n        self.add_item(\"skill\", str(ERC1155_CLIENT_PUBLIC_ID))\n\n        contracts_path = os.path.join(self.agent_name, \"vendor\", \"fetchai\", \"contracts\")\n        contracts_folders = os.listdir(contracts_path)\n        contract_dependency_name = \"erc1155\"\n        assert contract_dependency_name in contracts_folders\n\n\nclass TestAddSkillFromRemoteRegistry(AEATestCaseEmptyFlaky):\n    \"\"\"Test case for add skill from Registry command.\"\"\"\n\n    IS_LOCAL = False\n    IS_EMPTY = True\n\n    @pytest.mark.integration\n    @pytest.mark.flaky(reruns=MAX_FLAKY_RERUNS)\n    def test_add_skill_from_remote_registry_positive(self):\n        \"\"\"Test add skill from Registry positive result.\"\"\"\n        self.add_item(\"skill\", str(ECHO_PUBLIC_ID.to_latest()), local=self.IS_LOCAL)\n\n        items_path = os.path.join(self.agent_name, \"vendor\", \"fetchai\", \"skills\")\n        items_folders = os.listdir(items_path)\n        item_name = \"echo\"\n        assert item_name in items_folders\n\n\nclass TestAddSkillWithLatestVersion(AEATestCaseEmpty):\n    \"\"\"Test case for add skill with latest version.\"\"\"\n\n    def test_add_skill_latest_version(self):\n        \"\"\"Test add skill with latest version.\"\"\"\n        self.add_item(\"skill\", str(ECHO_PUBLIC_ID.to_latest()), local=True)\n\n        items_path = os.path.join(self.agent_name, \"vendor\", \"fetchai\", \"skills\")\n        items_folders = os.listdir(items_path)\n        item_name = \"echo\"\n        assert item_name in items_folders\n\n\nclass TestAddSkillMixedModeFallsBack(AEATestCaseEmpty):\n    \"\"\"Test add skill in mixed mode that fails with local falls back to remote registry.\"\"\"\n\n    IS_EMPTY = True\n\n    @mock.patch(\n        \"aea.cli.add.find_item_locally_or_distributed\",\n        side_effect=click.ClickException(\"\"),\n    )\n    def test_add_skill_remote_mode_negative_local_positive_remote(self, *_mocks):\n        \"\"\"Test add skill mixed mode.\"\"\"\n        self.run_cli_command(\n            \"add\", \"skill\", str(ECHO_PUBLIC_ID.to_latest()), cwd=self._get_cwd()\n        )\n\n        items_path = os.path.join(self.agent_name, \"vendor\", \"fetchai\", \"skills\")\n        items_folders = os.listdir(items_path)\n        item_name = \"echo\"\n        assert item_name in items_folders\n\n\nclass TestAddSkillRemoteMode(AEATestCaseEmpty):\n    \"\"\"Test case for add skill, --remote mode.\"\"\"\n\n    IS_EMPTY = True\n\n    def test_add_skill_remote_mode(self):\n        \"\"\"Test add skill mixed mode.\"\"\"\n        self.run_cli_command(\n            \"add\",\n            \"--remote\",\n            \"skill\",\n            str(ECHO_PUBLIC_ID.to_latest()),\n            cwd=self._get_cwd(),\n        )\n\n        items_path = os.path.join(self.agent_name, \"vendor\", \"fetchai\", \"skills\")\n        items_folders = os.listdir(items_path)\n        item_name = \"echo\"\n        assert item_name in items_folders\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_add_key.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This test module contains the tests for the `aea add-key` sub-command.\"\"\"\nimport os\nimport shutil\nimport tempfile\nfrom pathlib import Path\nfrom unittest import TestCase, mock\n\nimport pytest\nimport yaml\nfrom aea_ledger_ethereum import EthereumCrypto\nfrom aea_ledger_fetchai import FetchAICrypto\nfrom click.exceptions import BadParameter\n\nimport aea\nfrom aea.cli import cli\nfrom aea.cli.add_key import _try_add_key\nfrom aea.configurations.base import AgentConfig, DEFAULT_AEA_CONFIG_FILE\nfrom aea.test_tools.test_cases import AEATestCaseEmpty\n\nfrom tests.conftest import (\n    AUTHOR,\n    CLI_LOG_OPTION,\n    CUR_PATH,\n    CliRunner,\n    ETHEREUM_PRIVATE_KEY_FILE,\n    FETCHAI_PRIVATE_KEY_FILE,\n    ROOT_DIR,\n)\nfrom tests.test_aea.test_cli.tools_for_testing import ContextMock\n\n\nclass TestAddFetchKey:\n    \"\"\"Test that the command 'aea add-key' works as expected for a 'fetchai' key.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        dir_path = Path(\"packages\")\n        tmp_dir = cls.t / dir_path\n        src_dir = cls.cwd / Path(ROOT_DIR, dir_path)\n        shutil.copytree(str(src_dir), str(tmp_dir))\n        cls.agent_folder = Path(cls.t, cls.agent_name)\n        os.chdir(cls.t)\n\n        result = cls.runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n\n        result = cls.runner.invoke(\n            cli, [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name]\n        )\n        assert result.exit_code == 0\n        os.chdir(Path(cls.t, cls.agent_name))\n\n        shutil.copy(\n            Path(CUR_PATH, \"data\", FETCHAI_PRIVATE_KEY_FILE),\n            cls.agent_folder / FETCHAI_PRIVATE_KEY_FILE,\n        )\n\n        cls.result = cls.runner.invoke(\n            cli,\n            [\n                *CLI_LOG_OPTION,\n                \"add-key\",\n                FetchAICrypto.identifier,\n                FETCHAI_PRIVATE_KEY_FILE,\n            ],\n        )\n\n    def test_return_code(self):\n        \"\"\"Test return code equal to zero.\"\"\"\n        assert self.result.exit_code == 0\n\n    def test_key_added(self):\n        \"\"\"Test that the fetch private key has been added correctly.\"\"\"\n        f = open(Path(self.agent_folder, DEFAULT_AEA_CONFIG_FILE))\n        expected_json = yaml.safe_load(f)\n        config = AgentConfig.from_json(expected_json)\n        private_key_path = config.private_key_paths.read(FetchAICrypto.identifier)\n        assert private_key_path == FETCHAI_PRIVATE_KEY_FILE\n        assert len(config.private_key_paths.read_all()) == 1\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        os.chdir(cls.cwd)\n        shutil.rmtree(cls.t)\n\n\nclass TestAddEthereumhKey:\n    \"\"\"Test that the command 'aea add-key' works as expected for an 'ethereum' key.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        cls.agent_folder = Path(cls.t, cls.agent_name)\n        dir_path = Path(\"packages\")\n        tmp_dir = cls.t / dir_path\n        src_dir = cls.cwd / Path(ROOT_DIR, dir_path)\n        shutil.copytree(str(src_dir), str(tmp_dir))\n        os.chdir(cls.t)\n\n        result = cls.runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n\n        result = cls.runner.invoke(\n            cli, [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name]\n        )\n        assert result.exit_code == 0\n        os.chdir(Path(cls.t, cls.agent_name))\n\n        shutil.copy(\n            Path(CUR_PATH, \"data\", ETHEREUM_PRIVATE_KEY_FILE),\n            cls.agent_folder / ETHEREUM_PRIVATE_KEY_FILE,\n        )\n\n        cls.result = cls.runner.invoke(\n            cli,\n            [\n                *CLI_LOG_OPTION,\n                \"add-key\",\n                EthereumCrypto.identifier,\n                ETHEREUM_PRIVATE_KEY_FILE,\n            ],\n        )\n\n    def test_return_code(self):\n        \"\"\"Test return code equal to zero.\"\"\"\n        assert self.result.exit_code == 0\n\n    def test_key_added(self):\n        \"\"\"Test that the fetch private key has been added correctly.\"\"\"\n        f = open(Path(self.agent_folder, DEFAULT_AEA_CONFIG_FILE))\n        expected_json = yaml.safe_load(f)\n        config = AgentConfig.from_json(expected_json)\n        private_key_path = config.private_key_paths.read(EthereumCrypto.identifier)\n        assert private_key_path == ETHEREUM_PRIVATE_KEY_FILE\n        assert len(config.private_key_paths.read_all()) == 1\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        os.chdir(cls.cwd)\n        shutil.rmtree(cls.t)\n\n\nclass TestAddManyKeys:\n    \"\"\"Test that the command 'aea add-key' works as expected when adding many keys.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        dir_path = Path(\"packages\")\n        tmp_dir = cls.t / dir_path\n        src_dir = cls.cwd / Path(ROOT_DIR, dir_path)\n        shutil.copytree(str(src_dir), str(tmp_dir))\n        cls.agent_folder = Path(cls.t, cls.agent_name)\n        os.chdir(cls.t)\n\n        result = cls.runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n\n        result = cls.runner.invoke(\n            cli, [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name]\n        )\n        assert result.exit_code == 0\n        os.chdir(Path(cls.t, cls.agent_name))\n\n        shutil.copy(\n            Path(CUR_PATH, \"data\", FETCHAI_PRIVATE_KEY_FILE),\n            cls.agent_folder / FETCHAI_PRIVATE_KEY_FILE,\n        )\n        shutil.copy(\n            Path(CUR_PATH, \"data\", ETHEREUM_PRIVATE_KEY_FILE),\n            cls.agent_folder / ETHEREUM_PRIVATE_KEY_FILE,\n        )\n\n    def test_add_many_keys(self, pytestconfig):\n        \"\"\"Test that the keys are added correctly.\"\"\"\n\n        result = self.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"add-key\", FetchAICrypto.identifier],\n        )\n        assert result.exit_code == 0\n        result = self.runner.invoke(\n            cli,\n            [\n                *CLI_LOG_OPTION,\n                \"add-key\",\n                EthereumCrypto.identifier,\n                ETHEREUM_PRIVATE_KEY_FILE,\n            ],\n        )\n        assert result.exit_code == 0\n\n        f = open(Path(self.agent_folder, DEFAULT_AEA_CONFIG_FILE))\n        expected_json = yaml.safe_load(f)\n        config = AgentConfig.from_json(expected_json)\n        private_key_path_ethereum = config.private_key_paths.read(\n            FetchAICrypto.identifier\n        )\n        assert private_key_path_ethereum == FETCHAI_PRIVATE_KEY_FILE\n        private_key_path_ethereum = config.private_key_paths.read(\n            EthereumCrypto.identifier\n        )\n        assert private_key_path_ethereum == ETHEREUM_PRIVATE_KEY_FILE\n        assert len(config.private_key_paths.read_all()) == 2\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except OSError:\n            pass\n\n\ndef test_add_key_fails_bad_key():\n    \"\"\"Test that 'aea add-key' fails because the key is not valid.\"\"\"\n    oldcwd = os.getcwd()\n    runner = CliRunner()\n    agent_name = \"myagent\"\n    tmpdir = tempfile.mkdtemp()\n    dir_path = Path(\"packages\")\n    tmp_dir = tmpdir / dir_path\n    src_dir = oldcwd / Path(ROOT_DIR, dir_path)\n    shutil.copytree(str(src_dir), str(tmp_dir))\n    os.chdir(tmpdir)\n    try:\n        with mock.patch.object(\n            aea.crypto.helpers._default_logger, \"error\"\n        ) as mock_logger_error:\n\n            result = runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n\n            result = runner.invoke(\n                cli, [*CLI_LOG_OPTION, \"create\", \"--local\", agent_name]\n            )\n            assert result.exit_code == 0\n            os.chdir(Path(tmpdir, agent_name))\n\n            # create an empty file - surely not a private key\n            pvk_file = \"this_is_not_a_key.txt\"\n            Path(pvk_file).touch()\n\n            result = runner.invoke(\n                cli, [*CLI_LOG_OPTION, \"add-key\", FetchAICrypto.identifier, pvk_file]\n            )\n            assert result.exit_code == 1\n            error_message = \"Invalid length of private key, received 0, expected 32\"\n            mock_logger_error.assert_called_with(\n                \"This is not a valid private key file: '{}'\\n Exception: '{}'\".format(\n                    pvk_file, error_message\n                ),\n            )\n\n            # check that no key has been added.\n            f = open(Path(DEFAULT_AEA_CONFIG_FILE))\n            expected_json = yaml.safe_load(f)\n            config = AgentConfig.from_json(expected_json)\n            assert len(config.private_key_paths.read_all()) == 0\n    finally:\n        os.chdir(oldcwd)\n\n\ndef test_add_key_fails_bad_ledger_id():\n    \"\"\"Test that 'aea add-key' fails because the ledger id is not valid.\"\"\"\n    oldcwd = os.getcwd()\n    runner = CliRunner()\n    agent_name = \"myagent\"\n    tmpdir = tempfile.mkdtemp()\n    dir_path = Path(\"packages\")\n    tmp_dir = tmpdir / dir_path\n    src_dir = oldcwd / Path(ROOT_DIR, dir_path)\n    shutil.copytree(str(src_dir), str(tmp_dir))\n    os.chdir(tmpdir)\n    try:\n        result = runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n\n        result = runner.invoke(cli, [*CLI_LOG_OPTION, \"create\", \"--local\", agent_name])\n        assert result.exit_code == 0\n        os.chdir(Path(tmpdir, agent_name))\n\n        # generate a private key file\n        result = runner.invoke(\n            cli, [*CLI_LOG_OPTION, \"generate-key\", FetchAICrypto.identifier]\n        )\n        assert result.exit_code == 0\n        assert Path(FETCHAI_PRIVATE_KEY_FILE).exists()\n        bad_ledger_id = \"this_is_a_bad_ledger_id\"\n\n        result = runner.invoke(\n            cli, [*CLI_LOG_OPTION, \"add-key\", bad_ledger_id, FETCHAI_PRIVATE_KEY_FILE]\n        )\n        assert result.exit_code == 2\n\n        # check that no key has been added.\n        f = open(Path(DEFAULT_AEA_CONFIG_FILE))\n        expected_json = yaml.safe_load(f)\n        config = AgentConfig.from_json(expected_json)\n        assert len(config.private_key_paths.read_all()) == 0\n    finally:\n        os.chdir(oldcwd)\n\n\n@mock.patch(\"aea.cli.add_key.open_file\", mock.mock_open())\nclass AddKeyTestCase(TestCase):\n    \"\"\"Test case for _add_key method.\"\"\"\n\n    def test__add_key_positive(self, *mocks):\n        \"\"\"Test for _add_key method positive result.\"\"\"\n        ctx = ContextMock()\n        _try_add_key(ctx, \"type\", \"filepath\")\n\n\n@mock.patch(\"aea.cli.add_key.open_file\", mock.mock_open())\nclass AddKeyConnectionTestCase(TestCase):\n    \"\"\"Test case for _add_key method.\"\"\"\n\n    def test__add_key_positive(self, *mocks):\n        \"\"\"Test for _add_key method positive result.\"\"\"\n        ctx = ContextMock()\n        _try_add_key(ctx, \"type\", \"filepath\", connection=True)\n\n\n@mock.patch(\"aea.cli.utils.decorators.try_to_load_agent_config\")\n@mock.patch(\"aea.cli.add_key.try_validate_private_key_path\")\n@mock.patch(\"aea.cli.add_key._try_add_key\")\nclass AddKeyCommandTestCase(TestCase):\n    \"\"\"Test case for CLI add_key command.\"\"\"\n\n    def setUp(self):\n        \"\"\"Set it up.\"\"\"\n        self.runner = CliRunner()\n\n    def test_run_positive(self, *mocks):\n        \"\"\"Test for CLI add_key positive result.\"\"\"\n        filepath = str(\n            Path(ROOT_DIR, \"pyproject.toml\")\n        )  # some existing filepath to pass CLI argument check\n        result = self.runner.invoke(\n            cli,\n            [\n                *CLI_LOG_OPTION,\n                \"--skip-consistency-check\",\n                \"add-key\",\n                FetchAICrypto.identifier,\n                filepath,\n            ],\n            standalone_mode=False,\n        )\n        self.assertEqual(result.exit_code, 0)\n\n\n@mock.patch(\"aea.cli.utils.decorators.try_to_load_agent_config\")\n@mock.patch(\"aea.cli.add_key.try_validate_private_key_path\")\n@mock.patch(\"aea.cli.add_key._try_add_key\")\nclass CheckFileNotExistsTestCase(TestCase):\n    \"\"\"Test case for CLI add_key command.\"\"\"\n\n    def setUp(self):\n        \"\"\"Set it up.\"\"\"\n        self.runner = CliRunner()\n\n    def test_file_specified_does_not_exist(self, *mocks):\n        \"\"\"Test for CLI add_key fails on file not exists.\"\"\"\n        with pytest.raises(BadParameter, match=r\"File '.*' does not exist.\"):\n            self.runner.invoke(\n                cli,\n                [\n                    *CLI_LOG_OPTION,\n                    \"--skip-consistency-check\",\n                    \"add-key\",\n                    FetchAICrypto.identifier,\n                    \"somefile\",\n                ],\n                standalone_mode=False,\n                catch_exceptions=False,\n            )\n\n    def test_file_not_specified_does_not_exist(self, *mocks):\n        \"\"\"Test for CLI add_key fails on file not exists.\"\"\"\n        with pytest.raises(BadParameter, match=r\"File '.*' does not exist.\"):\n            self.runner.invoke(\n                cli,\n                [\n                    *CLI_LOG_OPTION,\n                    \"--skip-consistency-check\",\n                    \"add-key\",\n                    FetchAICrypto.identifier,\n                ],\n                standalone_mode=False,\n                catch_exceptions=False,\n            )\n\n\nclass TestAddKeyWithPassword(AEATestCaseEmpty):\n    \"\"\"Test the '--password' option to 'add-key' command.\"\"\"\n\n    FAKE_PASSWORD = \"password\"  # nosec\n\n    @classmethod\n    def setup_class(cls) -> None:\n        \"\"\"Set up the class.\"\"\"\n        super().setup_class()\n        cls.run_cli_command(\n            \"generate-key\",\n            FetchAICrypto.identifier,\n            FETCHAI_PRIVATE_KEY_FILE,\n            \"--password\",\n            cls.FAKE_PASSWORD,\n            cwd=cls._get_cwd(),\n        )\n\n    def test_add_key_with_password(self):\n        \"\"\"Test add key with password.\"\"\"\n        self.run_cli_command(\n            \"add-key\",\n            FetchAICrypto.identifier,\n            \"--password\",\n            self.FAKE_PASSWORD,\n            cwd=self._get_cwd(),\n        )\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_build.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\n\"\"\"This test module contains the tests for the `aea build` sub-command.\"\"\"\nimport re\nfrom pathlib import Path\nfrom unittest import mock\n\nimport pytest\nfrom click.exceptions import ClickException\n\nfrom aea.configurations.constants import DEFAULT_VERSION\nfrom aea.test_tools.test_cases import AEATestCaseEmpty\n\nfrom tests.common.utils import run_aea_subprocess\n\n\nclass TestAEABuildEmpty(AEATestCaseEmpty):\n    \"\"\"Test the command 'aea build', empty project.\"\"\"\n\n    def test_build(self):\n        \"\"\"Test build command.\"\"\"\n        result = self.run_cli_command(\"build\", cwd=self._get_cwd())\n        assert result.exit_code == 0\n        assert \"Build completed!\" in result.stdout\n\n\nclass TestAEABuildMainEntrypoint(AEATestCaseEmpty):\n    \"\"\"Test the command 'aea build', only main entrypoint.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set up the test.\"\"\"\n        super().setup_class()\n        cls.entrypoint = \"script.py\"\n        cls.expected_string = \"Hello, world!\"\n        (Path(cls._get_cwd()) / cls.entrypoint).write_text(\n            f\"print('{cls.expected_string}')\"\n        )\n        cls.nested_set_config(\"agent.build_entrypoint\", cls.entrypoint)\n\n    def test_build(self):\n        \"\"\"Test build command.\"\"\"\n        result, stdout, stderr = run_aea_subprocess(\"-s\", \"build\", cwd=self._get_cwd())\n        assert result.returncode == 0\n        assert re.search(r\"Building AEA package\\.\\.\\.\", stdout)\n        assert re.search(r\"Running command '.*script\\.py .+'\", stdout)\n        assert \"Build completed!\" in stdout\n        assert self.expected_string in stdout\n\n\nclass TestAEABuildPackageEntrypoint(AEATestCaseEmpty):\n    \"\"\"Test the command 'aea build', with a package entrypoint.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set up the test.\"\"\"\n        super().setup_class()\n        cls.entrypoint = \"script.py\"\n        cls.expected_string = \"Hello, world!\"\n        cls.scaffold_package_name = \"my_protocol\"\n        cls.scaffold_item(\"protocol\", cls.scaffold_package_name)\n        (\n            Path(cls._get_cwd())\n            / \"protocols\"\n            / cls.scaffold_package_name\n            / cls.entrypoint\n        ).write_text(f\"print('{cls.expected_string}')\")\n        cls.nested_set_config(\n            f\"protocols.{cls.scaffold_package_name}.build_entrypoint\", cls.entrypoint\n        )\n\n    def test_build(self):\n        \"\"\"Test build command.\"\"\"\n        result, stdout, stderr = run_aea_subprocess(\"-s\", \"build\", cwd=self._get_cwd())\n        assert result.returncode == 0\n        assert re.search(\n            rf\"Building package \\(protocol, {self.author}/{self.scaffold_package_name}:{DEFAULT_VERSION}\\)...\",\n            stdout,\n        )\n        assert re.search(r\"Running command '.*script\\.py .+'\", stdout)\n        assert \"Build completed!\" in stdout\n\n\nclass TestAEABuildEntrypointNegative(AEATestCaseEmpty):\n    \"\"\"Test the command 'aea build', in case there is an exception.\"\"\"\n\n    @mock.patch(\n        \"aea.cli.build.AEABuilder.call_all_build_entrypoints\",\n        side_effect=Exception(\"some error.\"),\n    )\n    def test_build_exception(self, *_mock):\n        \"\"\"Test build exception.\"\"\"\n        with pytest.raises(ClickException, match=\"some error.\"):\n            self.run_cli_command(\"build\", cwd=self._get_cwd())\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_config.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This test module contains the tests for the `aea config` sub-command.\"\"\"\nimport json\nimport os\nimport shutil\nimport tempfile\nfrom pathlib import Path\n\nimport pytest\nfrom click.exceptions import ClickException\n\nfrom aea.aea_builder import AEABuilder\nfrom aea.cli import cli\nfrom aea.cli.config import AgentConfigManager\nfrom aea.configurations.base import AgentConfig, DEFAULT_AEA_CONFIG_FILE, PackageType\nfrom aea.configurations.loader import ConfigLoader\nfrom aea.configurations.manager import ALLOWED_PATH_ROOTS\nfrom aea.helpers.yaml_utils import yaml_load\n\nfrom tests.conftest import CLI_LOG_OPTION, CUR_PATH, CliRunner, ROOT_DIR\n\n\nclass TestConfigGet:\n    \"\"\"Test that the command 'aea config get' works as expected.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        dir_path = Path(\"packages\")\n        tmp_dir = cls.t / dir_path\n        src_dir = cls.cwd / Path(ROOT_DIR, dir_path)\n        shutil.copytree(str(src_dir), str(tmp_dir))\n        shutil.copytree(Path(CUR_PATH, \"data\", \"dummy_aea\"), Path(cls.t, \"dummy_aea\"))\n        os.chdir(Path(cls.t, \"dummy_aea\"))\n        cls.runner = CliRunner()\n\n    def test_get_agent_name(self):\n        \"\"\"Test getting the agent name.\"\"\"\n        result = self.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"config\", \"get\", \"agent.agent_name\"],\n            standalone_mode=False,\n            catch_exceptions=False,\n        )\n        assert result.exit_code == 0\n        assert result.output == \"Agent0\\n\"\n\n    def test_get_agent_default_routing(self):\n        \"\"\"Test getting the agent name.\"\"\"\n        result = self.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"config\", \"get\", \"agent.default_routing\"],\n            standalone_mode=False,\n            catch_exceptions=False,\n        )\n        assert result.exit_code == 0\n        assert result.output == \"{}\\n\"\n\n    def test_get_skill_name(self):\n        \"\"\"Test getting the 'dummy' skill name.\"\"\"\n        result = self.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"config\", \"get\", \"skills.dummy.name\"],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n        assert result.output == \"dummy\\n\"\n\n    def test_get_nested_attribute(self):\n        \"\"\"Test getting the 'dummy' skill name.\"\"\"\n        result = self.runner.invoke(\n            cli,\n            [\n                *CLI_LOG_OPTION,\n                \"config\",\n                \"get\",\n                \"skills.dummy.behaviours.dummy.class_name\",\n            ],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n        assert result.output == \"DummyBehaviour\\n\"\n\n    def test_no_recognized_root(self):\n        \"\"\"Test that the 'get' fails because the root is not recognized.\"\"\"\n        result = self.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"config\", \"get\", \"wrong_root.agent_name\"],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 1\n        assert (\n            result.exception.message\n            == \"The root of the dotted path must be one of: {}\".format(\n                ALLOWED_PATH_ROOTS\n            )\n        )\n\n    def test_too_short_path_but_root_correct(self):\n        \"\"\"Test that the 'get' fails because the path is too short but the root is correct.\"\"\"\n        result = self.runner.invoke(\n            cli, [*CLI_LOG_OPTION, \"config\", \"get\", \"agent\"], standalone_mode=False\n        )\n        assert result.exit_code == 1\n        assert (\n            result.exception.message\n            == \"The path is too short. Please specify a path up to an attribute name.\"\n        )\n\n        result = self.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"config\", \"get\", \"skills.dummy\"],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 1\n        assert (\n            result.exception.message\n            == \"The path is too short. Please specify a path up to an attribute name.\"\n        )\n\n    def test_resource_not_existing(self):\n        \"\"\"Test that the 'get' fails because the resource does not exist.\"\"\"\n        result = self.runner.invoke(\n            cli,\n            [\n                *CLI_LOG_OPTION,\n                \"config\",\n                \"get\",\n                \"connections.non_existing_connection.name\",\n            ],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 1\n        assert (\n            result.exception.message\n            == \"Resource connections/non_existing_connection does not exist.\"\n        )\n\n    def test_attribute_not_found(self):\n        \"\"\"Test that the 'get' fails because the attribute is not found.\"\"\"\n        with pytest.raises(\n            ClickException, match=r\"Attribute `.* for .* config does not exist\"\n        ):\n            self.runner.invoke(\n                cli,\n                [\n                    *CLI_LOG_OPTION,\n                    \"config\",\n                    \"get\",\n                    \"skills.dummy.non_existing_attribute\",\n                ],\n                standalone_mode=False,\n                catch_exceptions=False,\n            )\n\n    def test_get_whole_dict(self):\n        \"\"\"Test that getting the 'dummy' skill behaviours works.\"\"\"\n        result = self.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"config\", \"get\", \"skills.dummy.behaviours\"],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n\n        actual_object = json.loads(result.output)\n        expected_object = {\n            \"dummy\": {\n                \"args\": {\"behaviour_arg_1\": 1, \"behaviour_arg_2\": \"2\"},\n                \"class_name\": \"DummyBehaviour\",\n            },\n            \"dummy_behaviour_same_classname\": {\n                \"args\": {\"behaviour_arg_1\": 1, \"behaviour_arg_2\": \"2\"},\n                \"class_name\": \"DummyBehaviour\",\n                \"file_path\": \"dummy_subpackage/foo.py\",\n            },\n        }\n        assert actual_object == expected_object\n\n    def test_get_list(self):\n        \"\"\"Test that getting the 'dummy' skill behaviours works.\"\"\"\n        result = self.runner.invoke(\n            cli,\n            [\n                *CLI_LOG_OPTION,\n                \"config\",\n                \"get\",\n                \"vendor.fetchai.connections.p2p_libp2p.config.entry_peers\",\n            ],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n        assert result.output == \"[]\\n\"\n\n    def test_get_fails_when_getting_nested_object(self):\n        \"\"\"Test that getting a nested object in 'dummy' skill fails because path is not valid.\"\"\"\n        with pytest.raises(\n            ClickException, match=r\"Attribute `.* for .* config does not exist\"\n        ):\n            self.runner.invoke(\n                cli,\n                [\n                    *CLI_LOG_OPTION,\n                    \"config\",\n                    \"get\",\n                    \"skills.dummy.non_existing_attribute.dummy\",\n                ],\n                standalone_mode=False,\n                catch_exceptions=False,\n            )\n\n    def test_get_fails_when_getting_non_dict_attribute(self):\n        \"\"\"Test that the get fails because the path point to a non-dict object.\"\"\"\n        attribute = \"protocols\"\n        result = self.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"config\", \"get\", f\"skills.dummy.{attribute}.protocol\"],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 1\n        s = f\"Attribute '{attribute}' is not a dictionary.\"\n        assert result.exception.message == s\n\n    def test_get_fails_when_getting_non_dict_attribute_in_between(self):\n        \"\"\"Test that the get fails because an object in between is not a dictionary.\"\"\"\n        result = self.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"config\", \"get\", \"agent.skills.some_attribute\"],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 1\n        s = \"Attribute 'skills' is not a dictionary.\"\n        assert result.exception.message == s\n\n    def test_get_fails_when_getting_vendor_dependency_with_wrong_component_type(self):\n        \"\"\"Test that getting a vendor component with wrong component type raises error.\"\"\"\n        result = self.runner.invoke(\n            cli,\n            [\n                *CLI_LOG_OPTION,\n                \"config\",\n                \"get\",\n                \"vendor.fetchai.component_type_not_correct.error.non_existing_attribute\",\n            ],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 1\n        s = \"'component_type_not_correct' is not a valid component type. Please use one of ['protocols', 'connections', 'skills', 'contracts'].\"\n        assert result.exception.message == s\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Teardowm the test.\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestConfigSet:\n    \"\"\"Test that the command 'aea config set' works as expected.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        dir_path = Path(\"packages\")\n        tmp_dir = cls.t / dir_path\n        src_dir = cls.cwd / Path(ROOT_DIR, dir_path)\n        shutil.copytree(str(src_dir), str(tmp_dir))\n        shutil.copytree(Path(CUR_PATH, \"data\", \"dummy_aea\"), Path(cls.t, \"dummy_aea\"))\n        os.chdir(Path(cls.t, \"dummy_aea\"))\n        cls.runner = CliRunner()\n\n    def test_set_agent_logging_options(self):\n        \"\"\"Test setting the agent name.\"\"\"\n        result = self.runner.invoke(\n            cli,\n            [\n                *CLI_LOG_OPTION,\n                \"config\",\n                \"set\",\n                \"agent.logging_config.disable_existing_loggers\",\n                \"True\",\n                \"--type=bool\",\n            ],\n            standalone_mode=False,\n            catch_exceptions=False,\n        )\n        assert result.exit_code == 0\n\n        result = self.runner.invoke(\n            cli,\n            [\n                *CLI_LOG_OPTION,\n                \"config\",\n                \"get\",\n                \"agent.logging_config.disable_existing_loggers\",\n            ],\n            standalone_mode=False,\n            catch_exceptions=False,\n        )\n        assert result.exit_code == 0\n        assert result.output == \"True\\n\"\n\n    def test_set_agent_incorrect_value(self):\n        \"\"\"Test setting the agent name.\"\"\"\n        with pytest.raises(\n            ClickException,\n            match=\"Attribute `not_agent_name` is not allowed to be updated!\",\n        ):\n            self.runner.invoke(\n                cli,\n                [*CLI_LOG_OPTION, \"config\", \"set\", \"agent.not_agent_name\", \"new_name\"],\n                standalone_mode=False,\n                catch_exceptions=False,\n            )\n\n    def test_set_type_bool(self):\n        \"\"\"Test setting the agent name.\"\"\"\n        result = self.runner.invoke(\n            cli,\n            [\n                *CLI_LOG_OPTION,\n                \"config\",\n                \"set\",\n                \"agent.logging_config.disable_existing_loggers\",\n                \"true\",\n                \"--type=bool\",\n            ],\n            standalone_mode=False,\n            catch_exceptions=False,\n        )\n        assert result.exit_code == 0\n\n    def test_set_type_none(self):\n        \"\"\"Test setting the agent name.\"\"\"\n        result = self.runner.invoke(\n            cli,\n            [\n                *CLI_LOG_OPTION,\n                \"config\",\n                \"set\",\n                \"agent.logging_config.some_value\",\n                \"\",\n                \"--type=none\",\n            ],\n            standalone_mode=False,\n            catch_exceptions=False,\n        )\n        assert result.exit_code == 0\n\n    def test_set_type_dict(self):\n        \"\"\"Test setting the default routing.\"\"\"\n        result = self.runner.invoke(\n            cli,\n            [\n                *CLI_LOG_OPTION,\n                \"config\",\n                \"set\",\n                \"agent.default_routing\",\n                '{\"fetchai/contract_api:any\": \"fetchai/ledger:any\"}',\n                \"--type=dict\",\n            ],\n            standalone_mode=False,\n            catch_exceptions=False,\n        )\n        assert result.exit_code == 0\n\n    def test_set_type_list(self):\n        \"\"\"Test setting the default routing.\"\"\"\n        result = self.runner.invoke(\n            cli,\n            [\n                *CLI_LOG_OPTION,\n                \"config\",\n                \"set\",\n                \"vendor.fetchai.connections.p2p_libp2p.config.entry_peers\",\n                '[\"peer1\", \"peer2\"]',\n                \"--type=list\",\n            ],\n            standalone_mode=False,\n            catch_exceptions=False,\n        )\n        assert result.exit_code == 0\n\n    def test_set_invalid_value(self):\n        \"\"\"Test setting the agent name.\"\"\"\n        result = self.runner.invoke(\n            cli,\n            [\n                *CLI_LOG_OPTION,\n                \"config\",\n                \"set\",\n                \"agent.agent_name\",\n                \"true\",\n                \"--type=bool\",\n            ],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 1\n\n    def test_set_skill_name_should_fail(self):\n        \"\"\"Test setting the 'dummy' skill name.\"\"\"\n        result = self.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"config\", \"set\", \"skills.dummy.name\", \"new_dummy_name\"],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 1\n\n    def test_set_nested_attribute(self):\n        \"\"\"Test setting a nested attribute.\"\"\"\n        path = \"skills.dummy.behaviours.dummy.args.behaviour_arg_1\"\n        new_value = \"10\"  # cause old value is int\n        result = self.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"config\", \"set\", path, new_value],\n            standalone_mode=False,\n            catch_exceptions=False,\n        )\n        assert result.exit_code == 0\n        result = self.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"config\", \"get\", path],\n            standalone_mode=False,\n            catch_exceptions=False,\n        )\n        assert result.exit_code == 0\n        assert new_value in result.output\n\n    def test_set_nested_attribute_not_allowed(self):\n        \"\"\"Test setting a nested attribute.\"\"\"\n        path = \"skills.dummy.behaviours.dummy.config.behaviour_arg_1\"\n        new_value = \"new_dummy_name\"\n        result = self.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"config\", \"set\", path, new_value],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 1\n        assert (\n            result.exception.message\n            == \"Attribute `behaviours.dummy.config.behaviour_arg_1` is not allowed to be updated!\"\n        )\n\n    def test_no_recognized_root(self):\n        \"\"\"Test that the 'get' fails because the root is not recognized.\"\"\"\n        result = self.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"config\", \"set\", \"wrong_root.agent_name\", \"value\"],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 1\n        assert (\n            result.exception.message\n            == \"The root of the dotted path must be one of: {}\".format(\n                ALLOWED_PATH_ROOTS\n            )\n        )\n\n    def test_too_short_path_but_root_correct(self):\n        \"\"\"Test that the 'get' fails because the path is too short but the root is correct.\"\"\"\n        result = self.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"config\", \"set\", \"agent\", \"data\"],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 1\n        assert (\n            result.exception.message\n            == \"The path is too short. Please specify a path up to an attribute name.\"\n        )\n\n        result = self.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"config\", \"set\", \"skills.dummy\", \"value\"],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 1\n        assert (\n            result.exception.message\n            == \"The path is too short. Please specify a path up to an attribute name.\"\n        )\n\n    def test_resource_not_existing(self):\n        \"\"\"Test that the 'get' fails because the resource does not exist.\"\"\"\n        result = self.runner.invoke(\n            cli,\n            [\n                *CLI_LOG_OPTION,\n                \"config\",\n                \"set\",\n                \"connections.non_existing_connection.name\",\n                \"value\",\n            ],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 1\n        assert (\n            result.exception.message\n            == \"Resource connections/non_existing_connection does not exist.\"\n        )\n\n    def test_attribute_not_found(self):\n        \"\"\"Test that the 'set' fails because the attribute is not found.\"\"\"\n        with pytest.raises(\n            ClickException,\n            match=\"Attribute `non_existing_attribute` is not allowed to be updated!\",\n        ):\n            self.runner.invoke(\n                cli,\n                [\n                    *CLI_LOG_OPTION,\n                    \"config\",\n                    \"set\",\n                    \"skills.dummy.non_existing_attribute\",\n                    \"value\",\n                ],\n                standalone_mode=False,\n                catch_exceptions=False,\n            )\n\n    def test_set_fails_when_setting_non_primitive_type(self):\n        \"\"\"Test that setting the 'dummy' skill behaviours fails because not a primitive type.\"\"\"\n        with pytest.raises(\n            ClickException, match=\"Attribute `behaviours` is not allowed to be updated!\"\n        ):\n            self.runner.invoke(\n                cli,\n                [*CLI_LOG_OPTION, \"config\", \"set\", \"skills.dummy.behaviours\", \"value\"],\n                standalone_mode=False,\n                catch_exceptions=False,\n            )\n\n    def test_get_fails_when_setting_nested_object(self):\n        \"\"\"Test that setting a nested object in 'dummy' skill fails because path is not valid.\"\"\"\n        with pytest.raises(\n            ClickException,\n            match=r\"Attribute `non_existing_attribute.dummy` is not allowed to be updated!\",\n        ):\n            self.runner.invoke(\n                cli,\n                [\n                    *CLI_LOG_OPTION,\n                    \"config\",\n                    \"set\",\n                    \"skills.dummy.non_existing_attribute.dummy\",\n                    \"new_value\",\n                ],\n                standalone_mode=False,\n                catch_exceptions=False,\n            )\n\n    def test_get_fails_when_setting_non_dict_attribute(self):\n        \"\"\"Test that the set fails because the path point to a non-dict object.\"\"\"\n        behaviour_arg_1 = \"behaviour_arg_1\"\n        path = f\"skills.dummy.behaviours.dummy.args.{behaviour_arg_1}.over_the_string\"\n        result = self.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"config\", \"set\", path, \"new_value\"],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 1\n        s = f\"Attribute '{behaviour_arg_1}' is not a dictionary.\"\n        assert result.exception.message == s\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Teardowm the test.\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestConfigNestedGetSet:\n    \"\"\"Test that the command 'aea config set' works as expected.\"\"\"\n\n    PATH = \"skills.dummy.behaviours.dummy.args.behaviour_arg_1\"\n    INCORRECT_PATH = \"skills.dummy.behaviours.dummy.args.behaviour_arg_100500\"\n    INITIAL_VALUE = 1\n    NEW_VALUE = 100\n\n    def setup(self):\n        \"\"\"Set the test up.\"\"\"\n        self.cwd = os.getcwd()\n        self.t = tempfile.mkdtemp()\n        dir_path = Path(\"packages\")\n        tmp_dir = self.t / dir_path\n        src_dir = self.cwd / Path(ROOT_DIR, dir_path)\n        shutil.copytree(str(src_dir), str(tmp_dir))\n        shutil.copytree(Path(CUR_PATH, \"data\", \"dummy_aea\"), Path(self.t, \"dummy_aea\"))\n        os.chdir(Path(self.t, \"dummy_aea\"))\n        self.runner = CliRunner()\n\n    def teardown(self):\n        \"\"\"Tear dowm the test.\"\"\"\n        os.chdir(self.cwd)\n        try:\n            shutil.rmtree(self.t)\n        except (OSError, IOError):\n            pass\n\n    def test_set_get_incorrect_path(self):\n        \"\"\"Fail on incorrect attribute tryed to be updated.\"\"\"\n        with pytest.raises(\n            ClickException, match=\"Attribute `.*` for .* config does not exist\"\n        ):\n            self.runner.invoke(\n                cli,\n                [*CLI_LOG_OPTION, \"config\", \"get\", self.INCORRECT_PATH],\n                standalone_mode=False,\n                catch_exceptions=False,\n            )\n\n        with pytest.raises(\n            ClickException,\n            match=\"Attribute `behaviours.dummy.args.behaviour_arg_100500` is not allowed to be updated!\",\n        ):\n            self.runner.invoke(\n                cli,\n                [\n                    *CLI_LOG_OPTION,\n                    \"config\",\n                    \"set\",\n                    self.INCORRECT_PATH,\n                    str(self.NEW_VALUE),\n                ],\n                standalone_mode=False,\n                catch_exceptions=False,\n            )\n\n    def load_agent_config(self) -> AgentConfig:\n        \"\"\"Load agent config for current dir.\"\"\"\n        agent_loader = ConfigLoader.from_configuration_type(PackageType.AGENT)\n        with open(DEFAULT_AEA_CONFIG_FILE, \"r\") as fp:\n            agent_config = agent_loader.load(fp)\n        return agent_config\n\n    def get_component_config_value(self) -> dict:\n        \"\"\"Get component variable value.\"\"\"\n        package_type, package_name, *path = self.PATH.split(\".\")\n        file_path = Path(f\"{package_type}\") / package_name / f\"{package_type[:-1]}.yaml\"\n\n        with open(file_path, \"r\") as fp:\n            data = yaml_load(fp)\n\n        value = data\n        for i in path:\n            value = value[i]\n        return value\n\n    def test_set_get_correct_path(self):\n        \"\"\"Test component value updated in agent config not in component config.\"\"\"\n        agent_config = self.load_agent_config()\n        assert not agent_config.component_configurations\n\n        config_value = self.get_component_config_value()\n        assert config_value == self.INITIAL_VALUE\n\n        result = self.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"config\", \"get\", self.PATH],\n            standalone_mode=False,\n            catch_exceptions=False,\n        )\n        assert result.exit_code == 0\n        assert str(self.INITIAL_VALUE) in result.output\n\n        result = self.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"config\", \"set\", self.PATH, str(self.NEW_VALUE)],\n            standalone_mode=False,\n            catch_exceptions=False,\n        )\n        assert result.exit_code == 0\n\n        config_value = self.get_component_config_value()\n        assert config_value == self.INITIAL_VALUE\n\n        result = self.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"config\", \"get\", self.PATH],\n            standalone_mode=False,\n            catch_exceptions=False,\n        )\n        assert result.exit_code == 0\n        assert str(self.NEW_VALUE) in result.output\n\n        agent_config = self.load_agent_config()\n        assert agent_config.component_configurations\n\n\ndef test_AgentConfigManager_get_overridables():\n    \"\"\"Test agent config manager get_overridables.\"\"\"\n    path = Path(CUR_PATH, \"data\", \"dummy_aea\")\n    agent_config = AEABuilder.try_to_load_agent_configuration_file(path)\n    config_manager = AgentConfigManager(agent_config, path)\n    agent_overridables, component_overridables = config_manager.get_overridables()\n    assert \"description\" in agent_overridables\n    assert \"is_abstract\" in list(component_overridables.values())[0]\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_create.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This test module contains the tests for the `aea create` sub-command.\"\"\"\n\nimport filecmp\nimport json\nimport os\nimport shutil\nimport tempfile\nfrom pathlib import Path\nfrom typing import Dict\nfrom unittest import TestCase\nfrom unittest.mock import patch\n\nimport jsonschema\nimport pytest\nimport yaml\nfrom jsonschema import Draft4Validator\nfrom packaging.version import Version\n\nimport aea\nfrom aea.cli import cli\nfrom aea.configurations.constants import DEFAULT_AEA_CONFIG_FILE\nfrom aea.configurations.loader import ConfigLoader, make_jsonschema_base_uri\n\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.protocols.signing.message import SigningMessage\nfrom packages.fetchai.protocols.state_update.message import StateUpdateMessage\n\nfrom tests.conftest import (\n    AGENT_CONFIGURATION_SCHEMA,\n    AUTHOR,\n    CLI_LOG_OPTION,\n    CONFIGURATION_SCHEMA_DIR,\n    CliRunner,\n    ROOT_DIR,\n)\n\n\nclass TestCreate:\n    \"\"\"Test that the command 'aea create <agent_name>' works as expected.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.schema = json.load(open(AGENT_CONFIGURATION_SCHEMA))\n        cls.resolver = jsonschema.RefResolver(\n            make_jsonschema_base_uri(Path(CONFIGURATION_SCHEMA_DIR).absolute()),\n            cls.schema,\n        )\n        cls.validator = Draft4Validator(cls.schema, resolver=cls.resolver)\n\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        dir_path = Path(\"packages\")\n        tmp_dir = cls.t / dir_path\n        src_dir = cls.cwd / Path(ROOT_DIR, dir_path)\n        shutil.copytree(str(src_dir), str(tmp_dir))\n        os.chdir(cls.t)\n        cls.cli_config_file = f\"{cls.t}/cli_config.yaml\"\n        cls.cli_config_patch = patch(\n            \"aea.cli.utils.config.CLI_CONFIG_PATH\", cls.cli_config_file\n        )\n        cls.cli_config_patch.start()\n        result = cls.runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n        assert result.exit_code == 0, result.stdout\n\n        cls.result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name],\n            standalone_mode=False,\n        )\n        cls.agent_config = cls._load_config_file(cls.agent_name)\n\n    @classmethod\n    def _load_config_file(cls, agent_name) -> Dict:\n        \"\"\"Load a config file.\"\"\"\n        agent_config_file = Path(agent_name, DEFAULT_AEA_CONFIG_FILE)  # type: ignore\n        file_pointer = open(agent_config_file, mode=\"r\", encoding=\"utf-8\")\n        agent_config_instance = yaml.safe_load(file_pointer)\n        return agent_config_instance\n\n    def test_exit_code_equal_to_zero(self):\n        \"\"\"Assert that the exit code is equal to zero (i.e. success).\"\"\"\n        assert self.result.exit_code == 0\n\n    def test_agent_directory_path_exists(self):\n        \"\"\"Check that the agent's directory has been created.\"\"\"\n        agent_dir = Path(self.agent_name)\n        assert agent_dir.exists()\n        assert agent_dir.is_dir()\n\n    def test_configuration_file_has_been_created(self):\n        \"\"\"Check that an agent's configuration file has been created.\"\"\"\n        agent_config_file = Path(self.agent_name, DEFAULT_AEA_CONFIG_FILE)\n        assert agent_config_file.exists()\n        assert agent_config_file.is_file()\n\n    def test_configuration_file_is_compliant_to_schema(self):\n        \"\"\"Check that the agent's configuration file is compliant with the schema.\"\"\"\n        try:\n            self.validator.validate(instance=self.agent_config)\n        except jsonschema.exceptions.ValidationError as e:\n            pytest.fail(\n                \"Configuration file is not compliant with the schema. Exception: {}\".format(\n                    str(e)\n                )\n            )\n\n    def test_aea_version_is_correct(self):\n        \"\"\"Check that the aea version in the configuration file is correct, i.e. the same of the installed package.\"\"\"\n        expected_aea_version = Version(aea.__version__)\n        version_no_micro = Version(\n            f\"{expected_aea_version.major}.{expected_aea_version.minor}.0\"\n        )\n        version_no_micro = (\n            version_no_micro\n            if version_no_micro < expected_aea_version\n            else expected_aea_version\n        )\n        version_next_minor = Version(f\"{expected_aea_version.major + 1}.0.0\")\n        version_range = f\">={version_no_micro}, <{version_next_minor}\"\n        assert self.agent_config[\"aea_version\"] == version_range\n\n    def test_agent_name_is_correct(self):\n        \"\"\"Check that the agent name in the configuration file is correct.\"\"\"\n        assert self.agent_config[\"agent_name\"] == self.agent_name\n\n    def test_authors_field_is_empty_string(self):\n        \"\"\"Check that the 'authors' field in the config file is the empty string.\"\"\"\n        assert self.agent_config[\"author\"] == AUTHOR\n\n    def test_connections_contains_nothing(self):\n        \"\"\"Check that the 'connections' list contains only the 'stub' connection.\"\"\"\n        assert self.agent_config[\"connections\"] == []\n\n    def test_default_connection_field_is_empty(self):\n        \"\"\"Check that the 'default_connection' is not specified.\"\"\"\n        assert self.agent_config[\"default_connection\"] is None\n\n    def test_license_field_is_empty_string(self):\n        \"\"\"Check that the 'license' is the empty string.\"\"\"\n        assert (\n            self.agent_config[\"license\"] == aea.configurations.constants.DEFAULT_LICENSE\n        )\n\n    def test_protocols_field_is_not_empty_list(self):\n        \"\"\"Check that the 'protocols' field is a list with the 'default' protocol.\"\"\"\n        assert self.agent_config[\"protocols\"] == [\n            str(DefaultMessage.protocol_id),\n            str(SigningMessage.protocol_id),\n            str(StateUpdateMessage.protocol_id),\n        ]\n\n    def test_skills_field_is_empty_list(self):\n        \"\"\"Check that the 'skills' field is a list with the 'error' skill.\"\"\"\n        assert self.agent_config[\"skills\"] == []\n\n    def test_version_field_is_equal_to_0_1_0(self):\n        \"\"\"Check that the 'version' field is equal to the string '0.1.0'.\"\"\"\n        assert self.agent_config[\"version\"] == \"0.1.0\"\n\n    def test_vendor_content(self):\n        \"\"\"Check the content of vendor directory is as expected.\"\"\"\n        vendor_dir = Path(self.agent_name, \"vendor\")\n        assert vendor_dir.exists()\n        assert set(vendor_dir.iterdir()) == {\n            vendor_dir / \"fetchai\",\n            vendor_dir / \"__init__.py\",\n        }\n\n        # assert that every subdirectory of vendor/fetchai is a Python package\n        # (i.e. that contains __init__.py)\n        for package_dir in (vendor_dir / \"fetchai\").iterdir():\n            assert (package_dir / \"__init__.py\").exists()\n\n    def test_vendor_protocols_contains_default_protocol(self):\n        \"\"\"Check that the vendor protocols directory contains the default protocol.\"\"\"\n        stub_connection_dirpath = Path(\n            self.agent_name, \"vendor\", \"fetchai\", \"protocols\", \"default\"\n        )\n        assert stub_connection_dirpath.exists()\n        assert stub_connection_dirpath.is_dir()\n\n    def test_default_protocol_is_equal_to_library_default_protocol(self):\n        \"\"\"Check that the stub connection directory is equal to the package's one (packages.fetchai.protocols.default).\"\"\"\n        default_protocol_dirpath = Path(\n            self.agent_name, \"vendor\", \"fetchai\", \"protocols\", \"default\"\n        )\n        comparison = filecmp.dircmp(\n            str(default_protocol_dirpath),\n            str(Path(ROOT_DIR, \"packages\", \"fetchai\", \"protocols\", \"default\")),\n        )\n        assert comparison.diff_files == []\n\n    def test_protocols_directory_content(self):\n        \"\"\"Test the content of the 'protocols' directory.\"\"\"\n        dir = Path(self.t, self.agent_name, \"protocols\")\n        assert dir.exists()\n        assert dir.is_dir()\n        assert set(dir.iterdir()) == {dir / \"__init__.py\"}\n\n    def test_connections_directory_content(self):\n        \"\"\"Test the content of the 'connections' directory.\"\"\"\n        dir = Path(self.t, self.agent_name, \"connections\")\n        assert dir.exists()\n        assert dir.is_dir()\n        assert set(dir.iterdir()) == {dir / \"__init__.py\"}\n\n    def test_skills_directory_content(self):\n        \"\"\"Test the content of the 'skills' directory.\"\"\"\n        dir = Path(self.t, self.agent_name, \"skills\")\n        assert dir.exists()\n        assert dir.is_dir()\n        assert set(dir.iterdir()) == {dir / \"__init__.py\"}\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        cls.cli_config_patch.start()\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestCreateFailsWhenDirectoryAlreadyExists:\n    \"\"\"Test that 'aea create' sub-command fails when the directory with the agent name in input already exists.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set up the test class.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        dir_path = Path(\"packages\")\n        tmp_dir = cls.t / dir_path\n        src_dir = cls.cwd / Path(ROOT_DIR, dir_path)\n        shutil.copytree(str(src_dir), str(tmp_dir))\n        os.chdir(cls.t)\n\n        # create a directory with the agent name -> make 'aea create fail.\n        os.mkdir(cls.agent_name)\n        result = cls.runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n        assert result.exit_code == 0\n\n        cls.result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name],\n            standalone_mode=False,\n        )\n\n    def test_exit_code_equal_to_1(self):\n        \"\"\"Test that the error code is equal to 1 (i.e. catchall for general errors).\"\"\"\n        assert self.result.exit_code == 1\n\n    def test_log_error_message(self):\n        \"\"\"Test that the log error message is fixed.\n\n        The expected message is: 'Directory already exist. Aborting...'\n        \"\"\"\n        s = \"Directory already exist. Aborting...\"\n        assert self.result.exception.message == s\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestCreateFailsWhenConfigFileIsNotCompliant:\n    \"\"\"Test that 'aea create' sub-command fails when the generated configuration file is not compliant with the schema.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set up the test class.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n\n        # change the serialization of the AgentConfig class so to make the parsing to fail.\n        cls.patch = patch.object(\n            aea.configurations.base.AgentConfig, \"json\", return_value={\"hello\": \"world\"}\n        )\n        cls.patch.start()\n\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        dir_path = Path(\"packages\")\n        tmp_dir = cls.t / dir_path\n        src_dir = cls.cwd / Path(ROOT_DIR, dir_path)\n        shutil.copytree(str(src_dir), str(tmp_dir))\n        os.chdir(cls.t)\n\n        result = cls.runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n        assert result.exit_code == 0\n\n        cls.result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name],\n            standalone_mode=False,\n        )\n\n    def test_exit_code_equal_to_1(self):\n        \"\"\"Test that the error code is equal to 1 (i.e. catchall for general errors).\"\"\"\n        assert self.result.exit_code == 1\n\n    def test_agent_folder_is_not_created(self):\n        \"\"\"Test that the agent folder is removed.\"\"\"\n        assert not Path(self.agent_name).exists()\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        cls.patch.stop()\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestCreateFailsWhenExceptionOccurs:\n    \"\"\"Test that 'aea create' sub-command fails when the generated configuration file is not compliant with the schema.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set up the test class.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n\n        # change the serialization of the AgentConfig class so to make the parsing to fail.\n        cls.patch = patch.object(ConfigLoader, \"dump\", side_effect=Exception)\n        cls.patch.start()\n\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        dir_path = Path(\"packages\")\n        tmp_dir = cls.t / dir_path\n        src_dir = cls.cwd / Path(ROOT_DIR, dir_path)\n        shutil.copytree(str(src_dir), str(tmp_dir))\n        os.chdir(cls.t)\n        result = cls.runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n        assert result.exit_code == 0\n\n        cls.result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name],\n            standalone_mode=False,\n        )\n\n    def test_exit_code_equal_to_1(self):\n        \"\"\"Test that the error code is equal to 1 (i.e. catchall for general errors).\"\"\"\n        assert self.result.exit_code == 1\n\n    def test_agent_folder_is_not_created(self):\n        \"\"\"Test that the agent folder is removed.\"\"\"\n        assert not Path(self.agent_name).exists()\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        cls.patch.stop()\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestCreateFailsWhenAlreadyInAEAProject:\n    \"\"\"Test that 'aea create' sub-command fails when it is called within an AEA project.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        dir_path = Path(\"packages\")\n        tmp_dir = cls.t / dir_path\n        src_dir = cls.cwd / Path(ROOT_DIR, dir_path)\n        shutil.copytree(str(src_dir), str(tmp_dir))\n        os.chdir(cls.t)\n\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        result = cls.runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n        assert result.exit_code == 0\n\n        cls.result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name],\n            standalone_mode=False,\n        )\n        assert cls.result.exit_code == 0\n\n        # calling 'aea create myagent' again within an AEA project - recursively.\n        os.chdir(cls.agent_name)\n        cls.result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name],\n            standalone_mode=False,\n        )\n\n    def test_exit_code_equal_to_1(self):\n        \"\"\"Test that the error code is equal to 1 (i.e. catchall for general errors).\"\"\"\n        assert self.result.exit_code == 1\n\n    def test_log_error_message(self):\n        \"\"\"Test that the log error message is fixed.\n\n        The expected message is: \"The current folder is already an AEA project. Please move to the parent folder.\".\n        \"\"\"\n        s = \"The current folder is already an AEA project. Please move to the parent folder.\"\n        assert self.result.exception.message == s\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass CreateCommandTestCase(TestCase):\n    \"\"\"Test case for CLI create command.\"\"\"\n\n    def setUp(self):\n        \"\"\"Set it up.\"\"\"\n        self.runner = CliRunner()\n\n    def test_create_no_init(self):\n        \"\"\"Test for CLI create no init result.\"\"\"\n        result = self.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"agent_name\", \"--author=some\"],\n            standalone_mode=False,\n        )\n        self.assertEqual(\n            result.exception.message,\n            \"Author is not set up. Please use 'aea init' to initialize.\",\n        )\n\n    @patch(\"aea.cli.create.get_or_create_cli_config\", return_value={})\n    def test_create_no_author_local(self, *mocks):\n        \"\"\"Test for CLI create no author local result.\"\"\"\n        result = self.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", \"agent_name\"],\n            standalone_mode=False,\n        )\n        expected_message = (\n            \"The AEA configurations are not initialized. \"\n            \"Uses `aea init` before continuing or provide optional argument `--author`.\"\n        )\n        self.assertEqual(result.exception.message, expected_message)\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_delete.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This test module contains the tests for the `aea delete` sub-command.\"\"\"\n\nimport os\nimport shutil\nimport tempfile\nimport unittest.mock\nfrom pathlib import Path\n\nfrom aea.cli import cli\n\nfrom tests.conftest import AUTHOR, CLI_LOG_OPTION, CliRunner, ROOT_DIR\n\n\nclass TestDelete:\n    \"\"\"Test that the command 'aea create <agent_name>' works as expected.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        dir_path = Path(\"packages\")\n        tmp_dir = cls.t / dir_path\n        src_dir = cls.cwd / Path(ROOT_DIR, dir_path)\n        shutil.copytree(str(src_dir), str(tmp_dir))\n        os.chdir(cls.t)\n        cls.runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n\n        cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name],\n            standalone_mode=False,\n        )\n        cls.result = cls.runner.invoke(\n            cli, [*CLI_LOG_OPTION, \"delete\", cls.agent_name], standalone_mode=False\n        )\n\n    def test_exit_code_equal_to_zero(self):\n        \"\"\"Assert that the exit code is equal to zero (i.e. success).\"\"\"\n        assert self.result.exit_code == 0\n\n    def test_agent_directory_path_does_not_exists(self):\n        \"\"\"Check that the agent's directory has been deleted.\"\"\"\n        agent_dir = Path(self.agent_name)\n        assert not agent_dir.exists()\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestDeleteFailsWhenDirectoryDoesNotExist:\n    \"\"\"Test that 'aea delete' sub-command fails when the directory with the agent name in input does not exist.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        os.chdir(cls.t)\n\n        # agent's directory does not exist -> command will fail.\n        cls.result = cls.runner.invoke(\n            cli, [*CLI_LOG_OPTION, \"delete\", cls.agent_name], standalone_mode=False\n        )\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestDeleteFailsWhenDirectoryCannotBeDeleted:\n    \"\"\"Test that 'aea delete' sub-command fails when the directory with the agent name cannot be deleted.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        dir_path = Path(\"packages\")\n        tmp_dir = cls.t / dir_path\n        src_dir = cls.cwd / Path(ROOT_DIR, dir_path)\n        shutil.copytree(str(src_dir), str(tmp_dir))\n        os.chdir(cls.t)\n\n        result = cls.runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n        assert result.exit_code == 0\n\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n\n        # agent's directory does not exist -> command will fail.\n        with unittest.mock.patch.object(shutil, \"rmtree\", side_effect=OSError):\n            cls.result = cls.runner.invoke(\n                cli, [*CLI_LOG_OPTION, \"delete\", cls.agent_name], standalone_mode=False\n            )\n\n    def test_exit_code_equal_to_1(self):\n        \"\"\"Test that the error code is equal to 1 (i.e. catchall for general errors).\"\"\"\n        assert self.result.exit_code == 1\n\n    def test_log_error_message(self):\n        \"\"\"Test that the log error message is fixed.\n\n        The expected message is: 'Directory already exist. Aborting...'\n        \"\"\"\n        s = \"An error occurred while deleting the agent directory. Aborting...\"\n        assert self.result.exception.message == s\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestDeleteFailsWhenDirectoryIsNotAnAEAProject:\n    \"\"\"Test that 'aea delete' sub-command fails when the directory with the agent name in input is not an AEA project.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        os.chdir(cls.t)\n\n        # directory is not AEA project -> command will fail.\n        Path(cls.t, cls.agent_name).mkdir()\n        cls.result = cls.runner.invoke(\n            cli, [*CLI_LOG_OPTION, \"delete\", cls.agent_name], standalone_mode=False\n        )\n\n    def test_exit_code_equal_to_1(self):\n        \"\"\"Test that the error code is equal to 1 (i.e. catchall for general errors).\"\"\"\n        assert self.result.exit_code == 1\n\n    def test_log_error_message(self):\n        \"\"\"Test that the log error message is fixed.\n\n        The expected message is: 'Directory already exist. Aborting...'\n        \"\"\"\n        s = \"The name provided is not a path to an AEA project.\"\n        assert self.result.exception.message == s\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_eject.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This test module contains the tests for commands in aea.cli.eject module.\"\"\"\n\nimport os\nfrom pathlib import Path\nfrom unittest import mock\n\nimport click\nimport pytest\n\nfrom aea.cli.utils.config import get_or_create_cli_config\nfrom aea.configurations.base import ComponentType, DEFAULT_VERSION, PublicId\nfrom aea.configurations.loader import load_component_configuration\nfrom aea.test_tools.test_cases import AEATestCaseEmpty, AEATestCaseMany\n\nfrom packages.fetchai.connections.gym.connection import (\n    PUBLIC_ID as GYM_CONNECTION_PUBLIC_ID,\n)\nfrom packages.fetchai.contracts.erc1155.contract import PUBLIC_ID as ERC1155_PUBLIC_ID\nfrom packages.fetchai.protocols.default import DefaultMessage\nfrom packages.fetchai.protocols.gym.message import GymMessage\nfrom packages.fetchai.skills.error import PUBLIC_ID as ERROR_PUBLIC_ID\nfrom packages.fetchai.skills.gym import PUBLIC_ID as GYM_SKILL_PUBLIC_ID\n\n\nclass TestEjectCommands(AEATestCaseMany):\n    \"\"\"End-to-end test case for CLI eject commands.\"\"\"\n\n    def test_eject_commands_positive(self):\n        \"\"\"Test eject commands for positive result.\"\"\"\n        agent_name = \"test_aea\"\n        self.create_agents(agent_name)\n\n        self.set_agent_context(agent_name)\n        cwd = os.path.join(self.t, agent_name)\n        self.add_item(\"connection\", str(GYM_CONNECTION_PUBLIC_ID))\n        self.add_item(\"skill\", str(GYM_SKILL_PUBLIC_ID))\n        self.add_item(\"contract\", str(ERC1155_PUBLIC_ID))\n\n        # the order must be kept as is, because of recursive ejects\n        self.eject_item(\"skill\", str(GYM_SKILL_PUBLIC_ID))\n        assert \"gym\" not in os.listdir(\n            (os.path.join(cwd, \"vendor\", \"fetchai\", \"skills\"))\n        )\n        assert \"gym\" in os.listdir((os.path.join(cwd, \"skills\")))\n        self.eject_item(\"connection\", str(GYM_CONNECTION_PUBLIC_ID))\n        assert \"gym\" not in os.listdir(\n            (os.path.join(cwd, \"vendor\", \"fetchai\", \"connections\"))\n        )\n        assert \"gym\" in os.listdir((os.path.join(cwd, \"connections\")))\n\n        self.eject_item(\"protocol\", str(GymMessage.protocol_id))\n        assert \"gym\" not in os.listdir(\n            (os.path.join(cwd, \"vendor\", \"fetchai\", \"protocols\"))\n        )\n        assert \"gym\" in os.listdir((os.path.join(cwd, \"protocols\")))\n\n        self.eject_item(\"contract\", str(ERC1155_PUBLIC_ID))\n        assert \"erc1155\" not in os.listdir(\n            (os.path.join(cwd, \"vendor\", \"fetchai\", \"contracts\"))\n        )\n        assert \"erc1155\" in os.listdir((os.path.join(cwd, \"contracts\")))\n\n\nclass TestRecursiveEject(AEATestCaseEmpty):\n    \"\"\"Test that eject is recursive.\"\"\"\n\n    def test_recursive_eject_commands_positive(self):\n        \"\"\"Test eject commands for positive result.\"\"\"\n        agent_name = \"test_aea\"\n        self.create_agents(agent_name)\n\n        self.set_agent_context(agent_name)\n        cwd = os.path.join(self.t, agent_name)\n        self.add_item(\"connection\", str(GYM_CONNECTION_PUBLIC_ID))\n        self.add_item(\"skill\", str(GYM_SKILL_PUBLIC_ID))\n        self.add_item(\"contract\", str(ERC1155_PUBLIC_ID))\n\n        # ejecting the gym protocol will cause the ejection of\n        # all the other packages that depend on it,\n        # that is, gym connection and gym skill.\n        self.eject_item(\"protocol\", str(GymMessage.protocol_id))\n        assert \"gym\" not in os.listdir(\n            (os.path.join(cwd, \"vendor\", \"fetchai\", \"protocols\"))\n        )\n        assert \"gym\" in os.listdir((os.path.join(cwd, \"protocols\")))\n        assert \"gym\" not in os.listdir(\n            (os.path.join(cwd, \"vendor\", \"fetchai\", \"connections\"))\n        )\n        assert \"gym\" in os.listdir((os.path.join(cwd, \"connections\")))\n        assert \"gym\" not in os.listdir(\n            (os.path.join(cwd, \"vendor\", \"fetchai\", \"skills\"))\n        )\n        assert \"gym\" in os.listdir((os.path.join(cwd, \"skills\")))\n\n\nclass TestRecursiveEjectIsAborted(AEATestCaseEmpty):\n    \"\"\"Test that recursive eject is aborted in non-quiet mode.\"\"\"\n\n    @mock.patch(\"click.confirm\", return_value=False)\n    def test_recursive_eject_commands_non_quiet_negative(self, *_mocks):\n        \"\"\"Test eject command for negative result in interactive mode.\"\"\"\n        agent_name = \"test_aea\"\n        self.create_agents(agent_name)\n\n        self.set_agent_context(agent_name)\n        cwd = os.path.join(self.t, agent_name)\n        self.add_item(\"connection\", str(GYM_CONNECTION_PUBLIC_ID))\n        self.add_item(\"skill\", str(GYM_SKILL_PUBLIC_ID))\n        self.add_item(\"contract\", str(ERC1155_PUBLIC_ID))\n\n        self.run_cli_command(\n            \"eject\", \"protocol\", str(GymMessage.protocol_id), cwd=self._get_cwd()\n        )\n        # assert packages not ejected\n        assert \"gym\" in os.listdir(\n            (os.path.join(cwd, \"vendor\", \"fetchai\", \"protocols\"))\n        )\n        assert \"gym\" not in os.listdir((os.path.join(cwd, \"protocols\")))\n        assert \"gym\" in os.listdir(\n            (os.path.join(cwd, \"vendor\", \"fetchai\", \"connections\"))\n        )\n        assert \"gym\" not in os.listdir((os.path.join(cwd, \"connections\")))\n        assert \"gym\" in os.listdir((os.path.join(cwd, \"vendor\", \"fetchai\", \"skills\")))\n        assert \"gym\" not in os.listdir((os.path.join(cwd, \"skills\")))\n\n\nclass BaseTestEjectCommand(AEATestCaseEmpty):\n    \"\"\"Replace CLI author with a known author.\"\"\"\n\n    EXPECTED_AUTHOR = \"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set up the class.\"\"\"\n        super().setup_class()\n        config = get_or_create_cli_config()\n        cls.EXPECTED_AUTHOR = config.get(\"author\", \"\")\n\n\nclass TestEjectCommandCliConfigNotAvailable(AEATestCaseEmpty):\n    \"\"\"Test that 'aea eject' cannot be run if CLI configuration not provided.\"\"\"\n\n    IS_EMPTY = True\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set up the class.\"\"\"\n        super().setup_class()\n        cls.add_item(\"protocol\", str(DefaultMessage.protocol_id))\n\n    @mock.patch(\"aea.cli.utils.config.get_or_create_cli_config\", return_value={})\n    def test_error(self, *_mocks):\n        \"\"\"Test that without CLI configuration, 'aea eject' won't work.\"\"\"\n        with pytest.raises(\n            click.ClickException,\n            match=\"The AEA configurations are not initialized. Use `aea init` before continuing.\",\n        ):\n            self.invoke(\n                \"eject\",\n                \"--quiet\",\n                \"protocol\",\n                str(DefaultMessage.protocol_id),\n            )\n\n\nclass TestEjectCommandReplacesReferences(BaseTestEjectCommand):\n    \"\"\"Test that eject command replaces the right references to the new package.\"\"\"\n\n    IS_EMPTY = True\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set up the class.\"\"\"\n        super().setup_class()\n        cls.add_item(\"protocol\", str(DefaultMessage.protocol_id))\n        cls.eject_item(\"protocol\", str(DefaultMessage.protocol_id))\n\n    def test_username_is_correct(self):\n        \"\"\"Test that the author name in the ejected component configuration is updated correctly.\"\"\"\n        package_path = Path(\n            self.current_agent_context, \"protocols\", DefaultMessage.protocol_id.name\n        )\n        assert (\n            package_path.exists()\n        ), f\"Expected ejected package in '{package_path}', but not found.\"\n        component_configuration = load_component_configuration(\n            ComponentType.PROTOCOL, package_path\n        )\n        assert component_configuration.author == self.EXPECTED_AUTHOR\n        assert component_configuration.name == DefaultMessage.protocol_id.name\n        assert component_configuration.version == DEFAULT_VERSION\n\n    def test_aea_config_references_updated_correctly(self):\n        \"\"\"Test that the references in the AEA configuration is updated correctly.\"\"\"\n        agent_config = self.load_agent_config(self.agent_name)\n        assert agent_config.protocols == {\n            PublicId(\n                self.EXPECTED_AUTHOR, DefaultMessage.protocol_id.name, DEFAULT_VERSION\n            )\n        }\n\n\nclass TestEjectCommandReplacesCustomConfigurationReference(BaseTestEjectCommand):\n    \"\"\"Test that eject command replaces references in AEA configuration.\"\"\"\n\n    IS_EMPTY = True\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set up the class.\"\"\"\n        super().setup_class()\n        cls.add_item(\"skill\", str(ERROR_PUBLIC_ID))\n        # add a custom configuration to the error skill\n        cls.run_cli_command(\n            \"--skip-consistency-check\",\n            \"config\",\n            \"set\",\n            \"vendor.fetchai.skills.error.is_abstract\",\n            \"--type\",\n            \"bool\",\n            \"true\",\n            cwd=cls._get_cwd(),\n        )\n\n        cls.eject_item(\"skill\", str(ERROR_PUBLIC_ID))\n\n    def test_username_is_correct(self):\n        \"\"\"Test that the author name in the ejected component configuration is updated correctly.\"\"\"\n        package_path = Path(self.current_agent_context, \"skills\", ERROR_PUBLIC_ID.name)\n        assert (\n            package_path.exists()\n        ), f\"Expected ejected package in '{package_path}', but not found.\"\n        component_configuration = load_component_configuration(\n            ComponentType.SKILL, package_path\n        )\n        assert component_configuration.author == self.EXPECTED_AUTHOR\n\n    def test_aea_config_references_updated_correctly(self):\n        \"\"\"Test that the references in the AEA configuration is updated correctly.\"\"\"\n        agent_config = self.load_agent_config(self.agent_name)\n        assert agent_config.skills == {\n            PublicId(self.EXPECTED_AUTHOR, ERROR_PUBLIC_ID.name, DEFAULT_VERSION)\n        }\n\n\nclass TestEjectWithLatest(AEATestCaseEmpty):\n    \"\"\"Test the eject command when a public id 'latest' is provided.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Setup class.\"\"\"\n        super(TestEjectWithLatest, cls).setup_class()\n        cls.add_item(\"skill\", str(ERROR_PUBLIC_ID.to_latest()))\n\n    def test_command(self):\n        \"\"\"Run the test.\"\"\"\n        latest_public_id = ERROR_PUBLIC_ID.to_latest()\n        self.eject_item(\"skill\", str(latest_public_id))\n        cwd = os.path.join(self.t, self.agent_name)\n        # assert packages ejected\n        assert \"error\" not in os.listdir(\n            (os.path.join(cwd, \"vendor\", \"fetchai\", \"skills\"))\n        )\n        assert \"error\" in os.listdir((os.path.join(cwd, \"skills\")))\n\n\nclass TestEjectWithSymlink(AEATestCaseEmpty):\n    \"\"\"Test the eject command with symlinks flag.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Setup class.\"\"\"\n        super(TestEjectWithSymlink, cls).setup_class()\n        cls.add_item(\"skill\", str(ERROR_PUBLIC_ID.to_latest()))\n\n    def test_command(self):\n        \"\"\"Run the test.\"\"\"\n        latest_public_id = ERROR_PUBLIC_ID.to_latest()\n        self.run_cli_command(\n            \"eject\",\n            \"--with-symlinks\",\n            \"skill\",\n            str(latest_public_id),\n            cwd=self._get_cwd(),\n        )\n        cwd = os.path.join(self.t, self.agent_name)\n        # assert packages ejected\n        assert \"error\" not in os.listdir(\n            (os.path.join(cwd, \"vendor\", \"fetchai\", \"skills\"))\n        )\n        assert \"error\" in os.listdir((os.path.join(cwd, \"skills\")))\n        assert \"error\" in os.listdir(\n            (os.path.join(cwd, \"vendor\", self.author, \"skills\"))\n        )\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_fetch.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This test module contains the tests for CLI Registry fetch methods.\"\"\"\nimport os\nfrom abc import ABC\nfrom tempfile import TemporaryDirectory\nfrom unittest import TestCase, mock\n\nimport click\nimport pytest\nfrom click import ClickException\n\nimport aea\nfrom aea.cli import cli\nfrom aea.cli.fetch import _is_version_correct, fetch_agent_locally\nfrom aea.cli.utils.context import Context\nfrom aea.configurations.base import PublicId\nfrom aea.helpers.base import cd\nfrom aea.test_tools.test_cases import (\n    AEATestCaseMany,\n    AEATestCaseManyFlaky,\n    BaseAEATestCase,\n)\n\nfrom tests.conftest import (\n    CLI_LOG_OPTION,\n    CliRunner,\n    MAX_FLAKY_RERUNS,\n    MY_FIRST_AEA_PUBLIC_ID,\n    PACKAGES_DIR,\n)\nfrom tests.test_aea.test_cli.tools_for_testing import ContextMock, PublicIdMock\n\n\ndef _raise_click_exception(*args, **kwargs):\n    raise ClickException(\"Message\")\n\n\n@mock.patch(\"builtins.open\", mock.mock_open())\n@mock.patch(\"aea.cli.utils.decorators._cast_ctx\")\n@mock.patch(\"aea.cli.fetch.os.path.join\", return_value=\"joined-path\")\n@mock.patch(\"aea.cli.fetch.try_get_item_source_path\", return_value=\"path\")\n@mock.patch(\"aea.cli.fetch.try_to_load_agent_config\")\nclass FetchAgentLocallyTestCase(TestCase):\n    \"\"\"Test case for fetch_agent_locally method.\"\"\"\n\n    @mock.patch(\"aea.cli.fetch._is_version_correct\", return_value=True)\n    @mock.patch(\"aea.cli.fetch.os.path.exists\", return_value=False)\n    @mock.patch(\"aea.cli.fetch.copy_tree\")\n    def test_fetch_agent_locally_positive(self, copy_tree, *mocks):\n        \"\"\"Test for fetch_agent_locally method positive result.\"\"\"\n        ctx = ContextMock()\n        ctx.config[\"is_local\"] = True\n        fetch_agent_locally(ctx, PublicIdMock(), alias=\"some-alias\")\n        copy_tree.assert_called_once_with(\"path\", \"joined-path\", dirs_exist_ok=True)\n\n    @mock.patch(\"aea.cli.fetch._is_version_correct\", return_value=True)\n    @mock.patch(\"aea.cli.fetch.os.path.exists\", return_value=True)\n    @mock.patch(\"aea.cli.fetch.copy_tree\")\n    def test_fetch_agent_locally_already_exists(self, *mocks):\n        \"\"\"Test for fetch_agent_locally method agent already exists.\"\"\"\n        ctx = ContextMock()\n        ctx.config[\"is_local\"] = True\n        with self.assertRaises(ClickException):\n            fetch_agent_locally(ctx, PublicIdMock())\n\n    @mock.patch(\"aea.cli.fetch._is_version_correct\", return_value=False)\n    @mock.patch(\"aea.cli.fetch.os.path.exists\", return_value=True)\n    @mock.patch(\"aea.cli.fetch.copy_tree\")\n    def test_fetch_agent_locally_incorrect_version(self, *mocks):\n        \"\"\"Test for fetch_agent_locally method incorrect agent version.\"\"\"\n        ctx = ContextMock()\n        ctx.config[\"is_local\"] = True\n        with self.assertRaises(ClickException):\n            fetch_agent_locally(ctx, PublicIdMock())\n\n    @mock.patch(\"aea.cli.fetch._is_version_correct\", return_value=True)\n    @mock.patch(\"aea.cli.fetch.add_item\")\n    @mock.patch(\"aea.cli.fetch.os.path.exists\", return_value=False)\n    @mock.patch(\"aea.cli.fetch.copy_tree\")\n    def test_fetch_agent_locally_with_deps_positive(self, *mocks):\n        \"\"\"Test for fetch_agent_locally method with deps positive result.\"\"\"\n        public_id = PublicIdMock.from_str(\"author/name:0.1.0\")\n        ctx_mock = ContextMock(\n            connections=[public_id],\n            protocols=[public_id],\n            skills=[public_id],\n            contracts=[public_id],\n        )\n        ctx_mock.config[\"is_local\"] = True\n        fetch_agent_locally(ctx_mock, PublicIdMock())\n\n    @mock.patch(\"aea.cli.fetch._is_version_correct\", return_value=True)\n    @mock.patch(\"aea.cli.fetch.os.path.exists\", return_value=False)\n    @mock.patch(\"aea.cli.fetch.copy_tree\")\n    @mock.patch(\"aea.cli.fetch.add_item\", _raise_click_exception)\n    def test_fetch_agent_locally_with_deps_fail(self, *mocks):\n        \"\"\"Test for fetch_agent_locally method with deps ClickException catch.\"\"\"\n        public_id = PublicIdMock.from_str(\"author/name:0.1.0\")\n        ctx_mock = ContextMock(\n            connections=[public_id],\n            protocols=[public_id],\n            skills=[public_id],\n            contracts=[public_id],\n        )\n        ctx_mock.config[\"is_local\"] = True\n        with self.assertRaises(ClickException):\n            fetch_agent_locally(ctx_mock, PublicIdMock())\n\n\n@mock.patch(\"aea.cli.fetch.fetch_agent\")\n@mock.patch(\"aea.cli.fetch.fetch_agent_locally\")\nclass FetchCommandTestCase(TestCase):\n    \"\"\"Test case for CLI fetch command.\"\"\"\n\n    def setUp(self):\n        \"\"\"Set it up.\"\"\"\n        self.runner = CliRunner()\n\n    def test_fetch_positive_mixed(self, *mocks):\n        \"\"\"Test for CLI push connection positive result.\"\"\"\n        self.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"fetch\", \"author/name:0.1.0\"],\n            standalone_mode=False,\n        )\n\n    def test_fetch_positive_local(self, *mocks):\n        \"\"\"Test for CLI push connection positive result.\"\"\"\n        self.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"fetch\", \"--local\", \"author/name:0.1.0\"],\n            standalone_mode=False,\n        )\n\n    def test_fetch_positive_remote(self, *mocks):\n        \"\"\"Test for CLI push connection positive result.\"\"\"\n        self.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"fetch\", \"--remote\", \"author/name:0.1.0\"],\n            standalone_mode=False,\n        )\n\n\nclass IsVersionCorrectTestCase(TestCase):\n    \"\"\"Test case for _is_version_correct method.\"\"\"\n\n    def test__is_version_correct_positive(self):\n        \"\"\"Test for _is_version_correct method positive result.\"\"\"\n        public_id = PublicId(\"author\", \"package\", \"0.1.0\")\n        ctx_mock = ContextMock(version=public_id.version)\n        ctx_mock.agent_config.public_id = public_id\n        result = _is_version_correct(ctx_mock, public_id)\n        self.assertTrue(result)\n\n    def test__is_version_correct_negative(self):\n        \"\"\"Test for _is_version_correct method negative result.\"\"\"\n        public_id_a = PublicId(\"author\", \"package\", \"0.1.0\")\n        public_id_b = PublicId(\"author\", \"package\", \"0.1.1\")\n        ctx_mock = ContextMock(version=public_id_b.version)\n        ctx_mock.agent_config.public_id = public_id_b\n        result = _is_version_correct(ctx_mock, public_id_a)\n        self.assertFalse(result)\n\n\nclass TestFetchFromRemoteRegistry(AEATestCaseManyFlaky):\n    \"\"\"Test case for fetch agent command from Registry.\"\"\"\n\n    @pytest.mark.integration\n    @pytest.mark.flaky(reruns=MAX_FLAKY_RERUNS)\n    def test_fetch_agent_from_remote_registry_positive(self):\n        \"\"\"Test fetch agent from Registry for positive result.\"\"\"\n        self.run_cli_command(\n            \"fetch\", str(MY_FIRST_AEA_PUBLIC_ID.to_latest()), \"--remote\"\n        )\n        assert \"my_first_aea\" in os.listdir(self.t)\n\n\nclass TestFetchMixedModeFallsBackCorrectly(AEATestCaseManyFlaky):\n    \"\"\"Test fetch command when registry fetch fails falls back to local fetch.\"\"\"\n\n    @pytest.mark.integration\n    @pytest.mark.flaky(reruns=MAX_FLAKY_RERUNS)\n    @mock.patch(\"aea.cli.fetch.fetch_agent\", side_effect=ClickException(\"\"))\n    @mock.patch(\"aea.cli.fetch.fetch_agent_locally\", wraps=fetch_agent_locally)\n    def test_fetch_agent_from_remote_registry_falls_back_to_local(\n        self, local_fetch, _remote_fetch\n    ):\n        \"\"\"Test fetch agent from Registry for positive result.\"\"\"\n        self.run_cli_command(\"fetch\", str(MY_FIRST_AEA_PUBLIC_ID))\n        local_fetch.assert_called()\n        assert \"my_first_aea\" in os.listdir(self.t)\n\n\nclass TestFetchLatestVersion(AEATestCaseMany):\n    \"\"\"Test case for fetch agent, latest version.\"\"\"\n\n    def test_fetch_agent_latest(self):\n        \"\"\"Test fetch agent, latest version.\"\"\"\n        self.run_cli_command(\n            \"fetch\", \"--local\", str(MY_FIRST_AEA_PUBLIC_ID.to_latest())\n        )\n        assert \"my_first_aea\" in os.listdir(self.t)\n\n\nclass TestFetchAgentMixed(BaseAEATestCase):\n    \"\"\"Test 'aea fetch' in mixed mode.\"\"\"\n\n    @pytest.mark.integration\n    @mock.patch(\n        \"aea.cli.registry.add.fetch_package\", wraps=aea.cli.registry.add.fetch_package\n    )\n    @mock.patch(\n        \"aea.cli.add.find_item_locally_or_distributed\",\n        side_effect=click.ClickException(\"\"),\n    )\n    @mock.patch(\n        \"aea.cli.fetch.fetch_agent_locally\",\n        side_effect=click.ClickException(\"\"),\n    )\n    def test_fetch_mixed(\n        self, mock_fetch_package, _mock_fetch_locally, _mock_fetch_agent_locally\n    ) -> None:\n        \"\"\"Test fetch in mixed mode.\"\"\"\n        self.run_cli_command(\n            \"-v\", \"DEBUG\", \"fetch\", str(MY_FIRST_AEA_PUBLIC_ID.to_latest())\n        )\n        assert \"my_first_aea\" in os.listdir(self.t)\n        mock_fetch_package.assert_called()\n\n\nclass BaseTestFetchAgentError(BaseAEATestCase, ABC):\n    \"\"\"Test 'aea fetch' in local, remote or mixed mode when it fails.\"\"\"\n\n    ERROR_MESSAGE = \"some error.\"\n    EXPECTED_ERROR_MESSAGE = \"\"\n    MODE = \"\"\n\n    def _mock_raise_click_exception(self, ctx: Context, *args, **kwargs):\n        \"\"\"Mock 'add_item' so to always fail.\"\"\"\n        raise click.ClickException(BaseTestFetchAgentError.ERROR_MESSAGE)\n\n    @pytest.mark.integration\n    @mock.patch(\"aea.cli.fetch.add_item\", side_effect=_mock_raise_click_exception)\n    @mock.patch(\"aea.cli.fetch.fetch_agent\", side_effect=_mock_raise_click_exception)\n    @mock.patch(\n        \"aea.cli.registry.fetch.add_item\", side_effect=_mock_raise_click_exception\n    )\n    def test_fetch_negative(self, *_mocks) -> None:\n        \"\"\"Test fetch in mixed mode.\"\"\"\n        if type(self) == BaseTestFetchAgentError:\n            pytest.skip(\"Base test class.\")\n        with pytest.raises(\n            Exception,\n            match=self.EXPECTED_ERROR_MESSAGE,\n        ):\n            self.run_cli_command(\n                *(\n                    [\"-v\", \"DEBUG\", \"fetch\", str(MY_FIRST_AEA_PUBLIC_ID.to_latest())]\n                    + ([self.MODE] if self.MODE else [])\n                )\n            )\n\n\nclass TestFetchAgentNonMixedErrorLocal(BaseTestFetchAgentError):\n    \"\"\"Test 'aea fetch' in local mode when it fails.\"\"\"\n\n    EXPECTED_ERROR_MESSAGE = f\".*{BaseTestFetchAgentError.ERROR_MESSAGE}\"\n    MODE = \"--local\"\n\n\nclass TestFetchAgentMixedModeError(BaseTestFetchAgentError):\n    \"\"\"Test 'aea fetch' in mixed mode when it fails.\"\"\"\n\n    EXPECTED_ERROR_MESSAGE = f\".*{BaseTestFetchAgentError.ERROR_MESSAGE}\"\n    MODE = \"\"\n\n\nclass TestFetchAgentRemoteModeError(BaseTestFetchAgentError):\n    \"\"\"Test 'aea fetch' in remote mode when it fails.\"\"\"\n\n    EXPECTED_ERROR_MESSAGE = rf\".*{BaseTestFetchAgentError.ERROR_MESSAGE}\"\n    MODE = \"--remote\"\n\n\ndef test_fetch_mixed_no_local_registry():\n    \"\"\"Test that mixed becomes remote when no local registry.\"\"\"\n    with TemporaryDirectory() as tmp_dir:\n        with cd(tmp_dir):\n            name = \"my_first_aea\"\n            runner = CliRunner()\n            result = runner.invoke(\n                cli,\n                [\"fetch\", \"fetchai/my_first_aea\"],\n                catch_exceptions=False,\n            )\n            assert result.exit_code == 0, result.stdout\n            assert os.path.exists(name)\n            assert \"Trying remote registry (`--remote`).\" in result.stdout\n\n\ndef test_fetch_local_no_local_registry():\n    \"\"\"Test that local fetch fails when no local registry.\"\"\"\n    with TemporaryDirectory() as tmp_dir:\n        with cd(tmp_dir):\n            runner = CliRunner()\n            result = runner.invoke(\n                cli,\n                [\"fetch\", \"--local\", \"fetchai/my_first_aea\"],\n                catch_exceptions=False,\n            )\n            assert result.exit_code == 1, result.stdout\n            assert (\n                \"Registry path not provided and local registry `packages` not found in current (.) and parent directory.\"\n                in result.stdout\n            )\n\n\ndef test_fetch_twice_locally():\n    \"\"\"Test fails on fetch if dir exists.\"\"\"\n    with TemporaryDirectory() as tmp_dir:\n        with cd(tmp_dir):\n            name = \"my_first_aea\"\n            runner = CliRunner()\n            result = runner.invoke(\n                cli,\n                [\n                    \"--registry-path\",\n                    PACKAGES_DIR,\n                    \"fetch\",\n                    \"--local\",\n                    \"fetchai/my_first_aea\",\n                ],\n                catch_exceptions=False,\n            )\n            assert result.exit_code == 0, result.stdout\n            assert os.path.exists(name)\n\n            with pytest.raises(\n                ClickException,\n                match='Item \"my_first_aea\" already exists in target folder.',\n            ):\n                result = runner.invoke(\n                    cli,\n                    [\n                        \"--registry-path\",\n                        PACKAGES_DIR,\n                        \"fetch\",\n                        \"--local\",\n                        \"fetchai/my_first_aea\",\n                    ],\n                    standalone_mode=False,\n                    catch_exceptions=False,\n                )\n\n\ndef test_fetch_twice_remote():\n    \"\"\"Test fails on fetch if dir exists.\"\"\"\n    with TemporaryDirectory() as tmp_dir:\n        with cd(tmp_dir):\n            name = \"my_first_aea\"\n            runner = CliRunner()\n            result = runner.invoke(\n                cli,\n                [\n                    \"--registry-path\",\n                    PACKAGES_DIR,\n                    \"fetch\",\n                    \"--local\",\n                    \"fetchai/my_first_aea\",\n                ],\n                catch_exceptions=False,\n            )\n            assert result.exit_code == 0, result.stdout\n            assert os.path.exists(name)\n\n            with pytest.raises(\n                ClickException,\n                match='Item \"my_first_aea\" already exists in target folder.',\n            ):\n                result = runner.invoke(\n                    cli,\n                    [\n                        \"--registry-path\",\n                        PACKAGES_DIR,\n                        \"fetch\",\n                        \"--remote\",\n                        \"fetchai/my_first_aea\",\n                    ],\n                    standalone_mode=False,\n                    catch_exceptions=False,\n                )\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_fingerprint.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This test module contains the tests for CLI fingerprint command.\"\"\"\nfrom pathlib import Path\nfrom unittest import TestCase, mock\nfrom unittest.mock import MagicMock\n\nimport pytest\nfrom click import ClickException\n\nfrom aea.cli import cli\nfrom aea.cli.fingerprint import fingerprint_item\nfrom aea.cli.utils.context import Context\nfrom aea.cli.utils.decorators import _check_aea_project\nfrom aea.configurations.constants import (\n    DEFAULT_CONNECTION_CONFIG_FILE,\n    DEFAULT_SKILL_CONFIG_FILE,\n)\nfrom aea.test_tools.test_cases import AEATestCaseEmpty\n\nfrom tests.conftest import CLI_LOG_OPTION, CliRunner\nfrom tests.test_aea.test_cli.tools_for_testing import (\n    ConfigLoaderMock,\n    ContextMock,\n    PublicIdMock,\n)\n\n\n@mock.patch(\"aea.cli.fingerprint.fingerprint_package\")\nclass FingerprintCommandTestCase(TestCase):\n    \"\"\"Test case for CLI fingerprint command.\"\"\"\n\n    def setUp(self):\n        \"\"\"Set it up.\"\"\"\n        self.runner = CliRunner()\n\n    def test_fingerprint_positive(self, *mocks):\n        \"\"\"Test for CLI fingerprint positive result.\"\"\"\n        public_id = \"author/name:0.1.0\"\n        result = self.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"fingerprint\", \"connection\", public_id],\n            standalone_mode=False,\n        )\n        self.assertEqual(result.exit_code, 0)\n\n        result = self.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"fingerprint\", \"contract\", public_id],\n            standalone_mode=False,\n        )\n        self.assertEqual(result.exit_code, 0)\n\n        result = self.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"fingerprint\", \"protocol\", public_id],\n            standalone_mode=False,\n        )\n        self.assertEqual(result.exit_code, 0)\n\n        result = self.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"fingerprint\", \"skill\", public_id],\n            standalone_mode=False,\n        )\n        self.assertEqual(result.exit_code, 0)\n\n    def _run_fingerprint_by_path(self):\n        \"\"\"Call fingerprint by-path cli command.\"\"\"\n        result = self.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"fingerprint\", \"by-path\", \"some_dir\"],\n            standalone_mode=False,\n            catch_exceptions=False,\n        )\n        self.assertEqual(result.exit_code, 0, result.exception)\n\n    def test_by_path_ok(self, fingerprint_mock):\n        \"\"\"Test fingerprint by_path works ok.\"\"\"\n        with mock.patch(\"os.listdir\", return_value=[DEFAULT_CONNECTION_CONFIG_FILE]):\n            self._run_fingerprint_by_path()\n            fingerprint_mock.assert_called()\n\n    def test_by_path_exceptions(self, *mocks):\n        \"\"\"Test fingerprint by_path works raises exceptions.\"\"\"\n        with pytest.raises(\n            ClickException,\n            match=\"No package config file found in `.*`. Incorrect directory?\",\n        ):\n            with mock.patch(\"os.listdir\", return_value=[]):\n                self._run_fingerprint_by_path()\n\n        with pytest.raises(\n            ClickException,\n            match=\"Too many config files in the directory, only one has to present!\",\n        ):\n            with mock.patch(\n                \"os.listdir\",\n                return_value=[\n                    DEFAULT_CONNECTION_CONFIG_FILE,\n                    DEFAULT_SKILL_CONFIG_FILE,\n                ],\n            ):\n                self._run_fingerprint_by_path()\n\n\ndef _raise_exception(*args, **kwargs):\n    raise Exception()\n\n\n@mock.patch(\"aea.cli.fingerprint.open_file\", mock.mock_open())\nclass FingerprintItemTestCase(TestCase):\n    \"\"\"Test case for fingerprint_item method.\"\"\"\n\n    @mock.patch(\"aea.cli.fingerprint.Path.exists\", return_value=False)\n    @mock.patch(\n        \"aea.cli.fingerprint.ConfigLoader.from_configuration_type\",\n        return_value=ConfigLoaderMock(),\n    )\n    def test_fingerprint_item_package_not_found(self, *mocks):\n        \"\"\"Test for fingerprint_item package not found result.\"\"\"\n        public_id = PublicIdMock()\n        with self.assertRaises(ClickException) as cm:\n            fingerprint_item(ContextMock(), \"skill\", public_id)\n        self.assertIn(\"Package not found at path\", cm.exception.message)\n\n    @mock.patch(\n        \"aea.cli.fingerprint.ConfigLoader.from_configuration_type\", _raise_exception\n    )\n    def test_fingerprint_item_exception(self, *mocks):\n        \"\"\"Test for fingerprint_item exception raised.\"\"\"\n        public_id = PublicIdMock()\n        with self.assertRaises(ClickException):\n            fingerprint_item(ContextMock(), \"skill\", public_id)\n\n\nclass TestFingerprintAgent(AEATestCaseEmpty):\n    \"\"\"Check fingerprint for agent.\"\"\"\n\n    def test_fingerprint(self):\n        \"\"\"Check fingerprint calculated and checked properly.\"\"\"\n        r = self.invoke(\"fingerprint\")\n        assert \"calculated\" in r.stdout\n\n        click_context = MagicMock()\n        click_context.obj = Context(self._get_cwd(), \"\", registry_path=None)\n        click_context.obj.config[\"skip_consistency_check\"] = True\n\n        _check_aea_project([click_context], check_finger_prints=True)\n\n        (Path(self._get_cwd()) / \"some_file.txt\").write_text(\"sdfds\")\n        with pytest.raises(\n            ClickException, match=r\"Fingerprints for package .* do not match\"\n        ):\n            _check_aea_project([click_context], check_finger_prints=True)\n\n        self.invoke(\"fingerprint\")\n        _check_aea_project([click_context], check_finger_prints=True)\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_freeze.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This test module contains the tests for the `aea freeze` sub-command.\"\"\"\n\nimport json\nimport os\nimport shutil\nimport tempfile\nfrom pathlib import Path\n\nimport jsonschema\nimport pytest\nfrom jsonschema import Draft4Validator\n\nfrom aea.cli import cli\nfrom aea.configurations.loader import make_jsonschema_base_uri\n\nfrom tests.conftest import (\n    AGENT_CONFIGURATION_SCHEMA,\n    CLI_LOG_OPTION,\n    CONFIGURATION_SCHEMA_DIR,\n    CUR_PATH,\n    CliRunner,\n    MAX_FLAKY_RERUNS,\n)\n\n\nclass TestFreeze:\n    \"\"\"Test that the command 'aea freeze' works as expected.\"\"\"\n\n    def setup(self):\n        \"\"\"Set the test up.\"\"\"\n        self.schema = json.load(open(AGENT_CONFIGURATION_SCHEMA))\n        self.resolver = jsonschema.RefResolver(\n            make_jsonschema_base_uri(Path(CONFIGURATION_SCHEMA_DIR)), self.schema\n        )\n        self.validator = Draft4Validator(self.schema, resolver=self.resolver)\n\n        self.cwd = os.getcwd()\n        self.t = tempfile.mkdtemp()\n        # copy the 'dummy_aea' directory in the parent of the agent folder.\n        shutil.copytree(Path(CUR_PATH, \"data\", \"dummy_aea\"), Path(self.t, \"dummy_aea\"))\n        self.runner = CliRunner()\n        os.chdir(Path(self.t, \"dummy_aea\"))\n        self.result = self.runner.invoke(\n            cli, [*CLI_LOG_OPTION, \"freeze\"], standalone_mode=False\n        )\n\n    @pytest.mark.flaky(reruns=MAX_FLAKY_RERUNS)\n    def test_exit_code_equal_to_zero_and_correct_output(self):\n        \"\"\"Assert that the exit code is equal to zero (i.e. success).\"\"\"\n        assert self.result.exit_code == 0\n        \"\"\"Test that the command has printed the correct output.\"\"\"\n        assert (\n            self.result.output\n            == \"\"\"aea-ledger-cosmos<2.0.0,>=1.0.0\\naea-ledger-ethereum<2.0.0,>=1.0.0\\naea-ledger-fetchai<2.0.0,>=1.0.0\\nprotobuf\\n\"\"\"\n        )\n\n    def teardown(self):\n        \"\"\"Tear the test down.\"\"\"\n        os.chdir(self.cwd)\n        try:\n            shutil.rmtree(self.t)\n        except (OSError, IOError):\n            pass\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_generate/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This test module contains the tests for the `aea generate` sub-command.\"\"\"\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_generate/test_generate.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This test module contains the tests for the aea.cli.generate sub-module.\"\"\"\nfrom unittest import TestCase, mock\n\nimport yaml\nfrom click import ClickException\n\nfrom aea.cli.generate import _generate_protocol\nfrom aea.configurations.base import (\n    ProtocolSpecification,\n    ProtocolSpecificationParseError,\n)\n\nfrom tests.test_aea.test_cli.tools_for_testing import ContextMock\n\n\ndef _raise_file_exists(*args, **kwargs):\n    raise FileExistsError()\n\n\ndef _which_mock(arg):\n    if arg == \"protoc\":\n        return True\n    else:\n        return None\n\n\ndef _which_mock_isort(arg):\n    if arg == \"isort\":\n        return None\n    else:\n        return True\n\n\ndef _raise_psperror(*args, **kwargs):\n    raise ProtocolSpecificationParseError()\n\n\ndef _raise_yamlerror(*args, **kwargs):\n    raise yaml.YAMLError(\"some yaml error\")\n\n\ndef _raise_fnfError(*args, **kwargs):\n    raise FileNotFoundError(\"some fnf error\")\n\n\n@mock.patch(\"aea.protocols.generator.common.open_file\", mock.mock_open())\n@mock.patch(\"aea.cli.generate.open_file\", mock.mock_open())\n@mock.patch(\n    \"aea.protocols.generator.common.ConfigLoader.load_protocol_specification\",\n    return_value=ProtocolSpecification(\n        name=\"name\",\n        author=\"author\",\n        version=\"1.0.0\",\n        protocol_specification_id=\"author/name:0.1.0\",\n    ),\n)\n@mock.patch(\"aea.cli.utils.decorators._cast_ctx\")\nclass GenerateItemTestCase(TestCase):\n    \"\"\"Test case for fetch_agent_locally method.\"\"\"\n\n    def test__generate_item_file_exists(self, *_mocks):\n        \"\"\"Test for fetch_agent_locally method file exists result.\"\"\"\n        ctx_mock = ContextMock()\n        with self.assertRaises(ClickException):\n            _generate_protocol(ctx_mock, \"path\")\n\n    @mock.patch(\"aea.protocols.generator.base.shutil.which\", _which_mock)\n    def test__generate_item_no_res(self, *_mocks):\n        \"\"\"Test for fetch_agent_locally method no black.\"\"\"\n        ctx_mock = ContextMock()\n        with self.assertRaises(ClickException) as cm:\n            _generate_protocol(ctx_mock, \"path\")\n        expected_msg = (\n            \"Protocol is NOT generated. The following error happened while generating the protocol:\\n\"\n            \"Cannot find black code formatter! To install, please follow this link: \"\n            \"https://black.readthedocs.io/en/stable/installation_and_usage.html\"\n        )\n        self.assertEqual(cm.exception.message, expected_msg)\n\n    @mock.patch(\"aea.protocols.generator.base.shutil.which\", _which_mock_isort)\n    def test__generate_item_no_res_isort_missing(self, *_mocks):\n        \"\"\"Test for fetch_agent_locally method no isort.\"\"\"\n        ctx_mock = ContextMock()\n        with self.assertRaises(ClickException) as cm:\n            _generate_protocol(ctx_mock, \"path\")\n        expected_msg = (\n            \"Protocol is NOT generated. The following error happened while generating the protocol:\\n\"\n            \"Cannot find isort code formatter! To install, please follow this link: \"\n            \"https://pycqa.github.io/isort/#installing-isort\"\n        )\n        self.assertEqual(cm.exception.message, expected_msg)\n\n    @mock.patch(\"aea.cli.generate.os.path.exists\", return_value=False)\n    @mock.patch(\"aea.protocols.generator.base.shutil.which\", return_value=\"some\")\n    @mock.patch(\"aea.cli.generate.ProtocolGenerator.__init__\", _raise_fnfError)\n    def test__generate_item_prerequisite_app_not_installed(self, *mocks):\n        \"\"\"Test for fetch_agent_locally method parsing specs fail.\"\"\"\n        ctx_mock = ContextMock()\n        with self.assertRaises(ClickException) as cm:\n            _generate_protocol(ctx_mock, \"path\")\n        expected_msg = \"Protocol is NOT generated. The following error happened while generating the protocol:\\n\"\n        self.assertIn(expected_msg, cm.exception.message)\n\n    @mock.patch(\"aea.cli.generate.os.path.exists\", return_value=False)\n    @mock.patch(\"aea.protocols.generator.base.shutil.which\", return_value=\"some\")\n    @mock.patch(\"aea.cli.generate.ProtocolGenerator.__init__\", _raise_yamlerror)\n    def test__generate_item_parsing_yaml_fail(self, *mocks):\n        \"\"\"Test for fetch_agent_locally method parsing specs fail.\"\"\"\n        ctx_mock = ContextMock()\n        with self.assertRaises(ClickException) as cm:\n            _generate_protocol(ctx_mock, \"path\")\n        expected_msg = (\n            \"Protocol is NOT generated. The following error happened while generating the protocol:\\n\"\n            \"Yaml error in the protocol specification file:\"\n        )\n        self.assertIn(expected_msg, cm.exception.message)\n\n    @mock.patch(\"aea.cli.generate.os.path.exists\", return_value=False)\n    @mock.patch(\"aea.protocols.generator.base.shutil.which\", return_value=\"some\")\n    @mock.patch(\"aea.cli.generate.ProtocolGenerator.__init__\", _raise_psperror)\n    def test__generate_item_parsing_specs_fail(self, *mocks):\n        \"\"\"Test for fetch_agent_locally method parsing specs fail.\"\"\"\n        ctx_mock = ContextMock()\n        with self.assertRaises(ClickException) as cm:\n            _generate_protocol(ctx_mock, \"path\")\n        expected_msg = (\n            \"Protocol is NOT generated. The following error happened while generating the protocol:\\n\"\n            \"Error while parsing the protocol specification: \"\n        )\n        self.assertIn(expected_msg, cm.exception.message)\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_generate/test_protocols.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This test module contains the tests for the `aea generate protocol` sub-command.\"\"\"\n\nimport json\nimport os\nimport shutil\nimport tempfile\nimport unittest.mock\nfrom pathlib import Path\n\nimport jsonschema\nimport yaml\nfrom jsonschema import Draft4Validator, ValidationError\n\nfrom aea.cli import cli\nfrom aea.configurations.base import DEFAULT_PROTOCOL_CONFIG_FILE\nfrom aea.configurations.loader import make_jsonschema_base_uri\n\nfrom tests.conftest import (\n    AUTHOR,\n    CLI_LOG_OPTION,\n    CONFIGURATION_SCHEMA_DIR,\n    CUR_PATH,\n    CliRunner,\n    PROTOCOL_CONFIGURATION_SCHEMA,\n    ROOT_DIR,\n)\n\n\nclass TestGenerateProtocolFullMode:\n    \"\"\"Test that the command 'aea generate protocol' works correctly in correct preconditions.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        dir_path = Path(\"packages\")\n        tmp_dir = cls.t / dir_path\n        src_dir = cls.cwd / Path(ROOT_DIR, dir_path)\n        shutil.copytree(str(src_dir), str(tmp_dir))\n        shutil.copyfile(\n            Path(CUR_PATH, \"data\", \"sample_specification.yaml\"),\n            Path(cls.t, \"sample_specification.yaml\"),\n        )\n        cls.path_to_specification = str(Path(\"..\", \"sample_specification.yaml\"))\n\n        cls.schema = json.load(open(PROTOCOL_CONFIGURATION_SCHEMA))\n        cls.resolver = jsonschema.RefResolver(\n            make_jsonschema_base_uri(Path(CONFIGURATION_SCHEMA_DIR).absolute()),\n            cls.schema,\n        )\n        cls.validator = Draft4Validator(cls.schema, resolver=cls.resolver)\n\n        # create an agent\n        os.chdir(cls.t)\n        result = cls.runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n        assert result.exit_code == 0\n\n        cls.create_result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name],\n            standalone_mode=False,\n        )\n        os.chdir(cls.agent_name)\n\n        # generate protocol\n        cls.result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"generate\", \"protocol\", cls.path_to_specification],\n            standalone_mode=False,\n        )\n        os.chdir(cls.cwd)\n\n    def test_create_agent_exit_code_equal_to_0(self):\n        \"\"\"Test that the exit code is equal to 0 when creating the agent.\"\"\"\n        assert self.create_result.exit_code == 0\n\n    def test_exit_code_equal_to_0(self):\n        \"\"\"Test that the exit code is equal to 0 when generating a protocol.\"\"\"\n        assert self.result.exit_code == 0, \"Failed with stdout='{}'\".format(\n            self.result.stdout\n        )\n\n    def test_resource_folder_contains_configuration_file(self):\n        \"\"\"Test that the protocol folder contains a structurally valid configuration file.\"\"\"\n        p = Path(\n            self.t,\n            self.agent_name,\n            \"protocols\",\n            \"t_protocol\",\n            DEFAULT_PROTOCOL_CONFIG_FILE,\n        )\n        config_file = yaml.safe_load(open(p))\n        self.validator.validate(instance=config_file)\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestGenerateProtocolProtobufOnlyMode:\n    \"\"\"Test that the command 'aea generate protocol' works correctly in correct preconditions.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        dir_path = Path(\"packages\")\n        tmp_dir = cls.t / dir_path\n        src_dir = cls.cwd / Path(ROOT_DIR, dir_path)\n        shutil.copytree(str(src_dir), str(tmp_dir))\n        shutil.copyfile(\n            Path(CUR_PATH, \"data\", \"sample_specification.yaml\"),\n            Path(cls.t, \"sample_specification.yaml\"),\n        )\n        cls.path_to_specification = str(Path(\"..\", \"sample_specification.yaml\"))\n\n        cls.schema = json.load(open(PROTOCOL_CONFIGURATION_SCHEMA))\n        cls.resolver = jsonschema.RefResolver(\n            make_jsonschema_base_uri(Path(CONFIGURATION_SCHEMA_DIR).absolute()),\n            cls.schema,\n        )\n        cls.validator = Draft4Validator(cls.schema, resolver=cls.resolver)\n\n        # create an agent\n        os.chdir(cls.t)\n        result = cls.runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n        assert result.exit_code == 0\n\n        cls.create_result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name],\n            standalone_mode=False,\n        )\n        os.chdir(cls.agent_name)\n\n        # generate protocol\n        cls.result = cls.runner.invoke(\n            cli,\n            [\n                *CLI_LOG_OPTION,\n                \"generate\",\n                \"protocol\",\n                \"--l\",\n                \"cpp\",\n                cls.path_to_specification,\n            ],\n            standalone_mode=False,\n        )\n        os.chdir(cls.cwd)\n\n    def test_create_agent_exit_code_equal_to_0(self):\n        \"\"\"Test that the exit code is equal to 0 when creating the agent.\"\"\"\n        assert self.create_result.exit_code == 0\n\n    def test_exit_code_equal_to_0(self):\n        \"\"\"Test that the exit code is equal to 0 when generating a protocol.\"\"\"\n        assert self.result.exit_code == 0, \"Failed with stdout='{}'\".format(\n            self.result.stdout\n        )\n\n    def test_resource_folder_contains_protobuf_schema_file(self):\n        \"\"\"Test that the protocol folder contains a structurally valid configuration file.\"\"\"\n        protobuf_schema_file = Path(\n            self.t,\n            self.agent_name,\n            \"protocols\",\n            \"t_protocol\",\n            \"t_protocol.proto\",\n        )\n        cpp_header_file = Path(\n            self.t,\n            self.agent_name,\n            \"protocols\",\n            \"t_protocol\",\n            \"t_protocol.pb.h\",\n        )\n        cpp_implementation_file = Path(\n            self.t,\n            self.agent_name,\n            \"protocols\",\n            \"t_protocol\",\n            \"t_protocol.pb.cc\",\n        )\n\n        assert protobuf_schema_file.exists()\n        assert cpp_header_file.exists()\n        assert cpp_implementation_file.exists()\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestGenerateProtocolFailsWhenDirectoryAlreadyExists:\n    \"\"\"Test that the command 'aea generate protocol' fails when a directory with the same name as the name of the protocol being generated already exists.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.protocol_name = \"t_protocol\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        dir_path = Path(\"packages\")\n        tmp_dir = cls.t / dir_path\n        src_dir = cls.cwd / Path(ROOT_DIR, dir_path)\n        shutil.copytree(str(src_dir), str(tmp_dir))\n        shutil.copyfile(\n            Path(CUR_PATH, \"data\", \"sample_specification.yaml\"),\n            Path(cls.t, \"sample_specification.yaml\"),\n        )\n        cls.path_to_specification = str(Path(\"..\", \"sample_specification.yaml\"))\n\n        # create an agent\n        os.chdir(cls.t)\n        result = cls.runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n        assert result.exit_code == 0\n\n        cls.create_result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name],\n            standalone_mode=False,\n        )\n        os.chdir(cls.agent_name)\n\n        # create a dummy 'myprotocol' folder\n        Path(cls.t, cls.agent_name, \"protocols\", cls.protocol_name).mkdir(\n            exist_ok=False, parents=True\n        )\n\n        # generate protocol\n        cls.result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"generate\", \"protocol\", cls.path_to_specification],\n            standalone_mode=False,\n        )\n        os.chdir(cls.cwd)\n\n    def test_create_agent_exit_code_equal_to_0(self):\n        \"\"\"Test that the exit code is equal to 0 when creating the agent.\"\"\"\n        assert self.create_result.exit_code == 0\n\n    def test_exit_code_equal_to_1(self):\n        \"\"\"Test that the exit code is equal to 1 (i.e. catchall for general errors).\"\"\"\n        assert self.result.exit_code == 1\n\n    def test_error_message_protocol_already_existing(self):\n        \"\"\"Test that the log error message is fixed.\n\n        The expected message is: 'A protocol with name '{protocol_name}' already exists. Aborting...'\n        \"\"\"\n        s = (\n            \"Protocol is NOT generated. The following error happened while generating the protocol:\\n\"\n            + \"A directory with name '{}' already exists. Aborting...\".format(\n                self.protocol_name\n            )\n        )\n        assert self.result.exception.message == s\n\n    def test_resource_directory_exists(self):\n        \"\"\"Test that the resource directory still exists.\n\n        This means that after every failure, we make sure we restore the previous state.\n        \"\"\"\n        assert Path(self.t, self.agent_name, \"protocols\", self.protocol_name).exists()\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestGenerateProtocolFailsWhenProtocolAlreadyExists:\n    \"\"\"Test that the command 'aea add protocol' fails when the protocol already exists.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        dir_path = Path(\"packages\")\n        tmp_dir = cls.t / dir_path\n        src_dir = cls.cwd / Path(ROOT_DIR, dir_path)\n        shutil.copytree(str(src_dir), str(tmp_dir))\n        shutil.copyfile(\n            Path(CUR_PATH, \"data\", \"sample_specification.yaml\"),\n            Path(cls.t, \"sample_specification.yaml\"),\n        )\n        cls.path_to_specification = str(Path(\"..\", \"sample_specification.yaml\"))\n\n        # create an agent\n        os.chdir(cls.t)\n        result = cls.runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n        assert result.exit_code == 0\n\n        cls.create_result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name],\n            standalone_mode=False,\n        )\n        os.chdir(cls.agent_name)\n\n        # generate protocol first time\n        cls.generate_result_1 = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"generate\", \"protocol\", cls.path_to_specification],\n            standalone_mode=False,\n        )\n\n        # generate protocol second time\n        cls.generate_result_2 = cls.runner.invoke(\n            cli,\n            [\n                *CLI_LOG_OPTION,\n                \"--skip-consistency-check\",\n                \"generate\",\n                \"protocol\",\n                cls.path_to_specification,\n            ],\n            standalone_mode=False,\n        )\n        os.chdir(cls.cwd)\n\n    def test_create_agent_exit_code_equal_to_0(self):\n        \"\"\"Test that the exit code is equal to 0 when creating the agent.\"\"\"\n        assert self.create_result.exit_code == 0\n\n    def test_generate_protocol_first_time_exit_code_equal_to_0(self):\n        \"\"\"Test that the exit code is equal to 0 the first time a protocol is generated.\"\"\"\n        assert self.generate_result_1.exit_code == 0\n\n    def test_generate_protocol_second_time_exit_code_equal_to_1(self):\n        \"\"\"Test that the exit code is equal to 1 the second time the protocol is generated (i.e. catchall for general errors).\"\"\"\n        assert self.generate_result_2.exit_code == 1\n\n    def test_error_message_protocol_already_existing(self):\n        \"\"\"Test that the log error message is fixed.\n\n        The expected message is: 'A protocol with name '{protocol_name}' already exists. Aborting...'\n        \"\"\"\n        s = (\n            \"Protocol is NOT generated. The following error happened while generating the protocol:\\n\"\n            + \"A protocol with name 't_protocol' already exists. Aborting...\"\n        )\n        assert self.generate_result_2.exception.message == s\n\n    def test_resource_directory_exists(self):\n        \"\"\"Test that the resource directory still exists.\n\n        This means that after every failure, we make sure we restore the previous state.\n        \"\"\"\n        assert Path(self.t, self.agent_name, \"protocols\", \"t_protocol\").exists()\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestGenerateProtocolFailsWhenConfigFileIsNotCompliant:\n    \"\"\"Test that the command 'aea generate protocol' fails when the configuration file is not compliant with the schema.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        dir_path = Path(\"packages\")\n        tmp_dir = cls.t / dir_path\n        src_dir = cls.cwd / Path(ROOT_DIR, dir_path)\n        shutil.copytree(str(src_dir), str(tmp_dir))\n        shutil.copyfile(\n            Path(CUR_PATH, \"data\", \"sample_specification.yaml\"),\n            Path(cls.t, \"sample_specification.yaml\"),\n        )\n        cls.path_to_specification = str(Path(\"..\", \"sample_specification.yaml\"))\n\n        # create an agent\n        os.chdir(cls.t)\n        result = cls.runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n        assert result.exit_code == 0\n\n        cls.create_result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name],\n            standalone_mode=False,\n        )\n\n        # change the dumping of yaml module to raise an exception.\n        cls.patch = unittest.mock.patch(\n            \"yaml.dump_all\", side_effect=ValidationError(\"test error message\")\n        )\n        cls.patch.start()\n\n        # generate protocol\n        os.chdir(cls.agent_name)\n        cls.result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"generate\", \"protocol\", cls.path_to_specification],\n            standalone_mode=False,\n        )\n        os.chdir(cls.cwd)\n\n    def test_create_agent_exit_code_equal_to_0(self):\n        \"\"\"Test that the exit code is equal to 0 when creating the agent.\"\"\"\n        assert self.create_result.exit_code == 0\n\n    def test_exit_code_equal_to_1(self):\n        \"\"\"Test that the exit code is equal to 1 when config file is non-compliant (i.e. catchall for general errors).\"\"\"\n        assert self.result.exit_code == 1\n\n    def test_resource_directory_does_not_exists(self):\n        \"\"\"Test that the resource directory does not exist.\n\n        This means that after every failure, we make sure we restore the previous state.\n        \"\"\"\n        assert not Path(self.t, self.agent_name, \"protocols\", \"t_protocol\").exists()\n\n    def test_configuration_file_not_valid(self):\n        \"\"\"Test that the log error message is fixed.\n\n        The expected message is: 'Cannot find protocol: '{protocol_name}'\n        \"\"\"\n        s = \"Protocol is NOT generated. The following error happened while generating the protocol:\\ntest error message\"\n        assert self.result.exception.message == s\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        cls.patch.stop()\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestGenerateProtocolFailsWhenExceptionOccurs:\n    \"\"\"Test that the command 'aea generate protocol' fails when the configuration file is not compliant with the schema.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        dir_path = Path(\"packages\")\n        tmp_dir = cls.t / dir_path\n        src_dir = cls.cwd / Path(ROOT_DIR, dir_path)\n        shutil.copytree(str(src_dir), str(tmp_dir))\n        cls.path_to_specification = str(Path(\"..\", \"sample_specification.yaml\"))\n\n        # create an agent\n        os.chdir(cls.t)\n        result = cls.runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n        assert result.exit_code == 0\n\n        cls.create_result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name],\n            standalone_mode=False,\n        )\n\n        # create an exception\n        cls.patch = unittest.mock.patch(\n            \"shutil.copytree\", side_effect=Exception(\"unknwon exception\")\n        )\n        cls.patch.start()\n\n        # generate protocol\n        os.chdir(cls.agent_name)\n        cls.result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"generate\", \"protocol\", cls.path_to_specification],\n            standalone_mode=False,\n        )\n        os.chdir(cls.cwd)\n\n    def test_create_agent_exit_code_equal_to_0(self):\n        \"\"\"Test that the exit code is equal to 0 when creating the agent.\"\"\"\n        assert self.create_result.exit_code == 0\n\n    def test_exit_code_equal_to_1(self):\n        \"\"\"Test that the exit code is equal to 1 when an exception is thrown (i.e. catchall for general errors).\"\"\"\n        assert self.result.exit_code == 1\n\n    def test_resource_directory_does_not_exists(self):\n        \"\"\"Test that the resource directory does not exist.\n\n        This means that after every failure, we make sure we restore the previous state.\n        \"\"\"\n        assert not Path(self.t, self.agent_name, \"protocols\", \"t_protocol\").exists()\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        cls.patch.stop()\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_generate_key.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This test module contains the tests for the `aea generate-key` sub-command.\"\"\"\nimport json\nimport os\nimport shutil\nimport tempfile\nfrom pathlib import Path\n\nfrom aea_ledger_ethereum import EthereumCrypto\nfrom aea_ledger_fetchai import FetchAICrypto\n\nfrom aea.cli import cli\nfrom aea.crypto.registries import make_crypto\nfrom aea.helpers.sym_link import cd\nfrom aea.test_tools.test_cases import AEATestCaseEmpty\n\nfrom tests.conftest import (\n    CLI_LOG_OPTION,\n    CliRunner,\n    ETHEREUM_PRIVATE_KEY_FILE,\n    FETCHAI_PRIVATE_KEY_FILE,\n)\n\n\nclass TestGenerateKey:\n    \"\"\"Test that the command 'aea generate-key' works as expected.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        os.chdir(cls.t)\n\n    def test_fetchai(self, password_or_none):\n        \"\"\"Test that the fetch private key is created correctly.\"\"\"\n        args = [*CLI_LOG_OPTION, \"generate-key\", FetchAICrypto.identifier] + (\n            [\"--password\", password_or_none] if password_or_none is not None else []\n        )\n        result = self.runner.invoke(cli, args)\n        assert result.exit_code == 0\n        assert Path(FETCHAI_PRIVATE_KEY_FILE).exists()\n        make_crypto(\n            FetchAICrypto.identifier,\n            private_key_path=FETCHAI_PRIVATE_KEY_FILE,\n            password=password_or_none,\n        )\n\n        Path(FETCHAI_PRIVATE_KEY_FILE).unlink()\n\n    def test_ethereum(self, password_or_none):\n        \"\"\"Test that the fetch private key is created correctly.\"\"\"\n        args = [*CLI_LOG_OPTION, \"generate-key\", EthereumCrypto.identifier] + (\n            [\"--password\", password_or_none] if password_or_none is not None else []\n        )\n        result = self.runner.invoke(cli, args)\n        assert result.exit_code == 0\n        assert Path(ETHEREUM_PRIVATE_KEY_FILE).exists()\n        make_crypto(\n            EthereumCrypto.identifier,\n            private_key_path=ETHEREUM_PRIVATE_KEY_FILE,\n            password=password_or_none,\n        )\n\n        Path(ETHEREUM_PRIVATE_KEY_FILE).unlink()\n\n    def test_all(self):\n        \"\"\"Test that all the private keys are created correctly when running 'aea generate-key all'.\"\"\"\n        result = self.runner.invoke(cli, [*CLI_LOG_OPTION, \"generate-key\", \"all\"])\n        assert result.exit_code == 0\n\n        assert Path(FETCHAI_PRIVATE_KEY_FILE).exists()\n        assert Path(ETHEREUM_PRIVATE_KEY_FILE).exists()\n        make_crypto(FetchAICrypto.identifier, private_key_path=FETCHAI_PRIVATE_KEY_FILE)\n        make_crypto(\n            EthereumCrypto.identifier, private_key_path=ETHEREUM_PRIVATE_KEY_FILE\n        )\n\n        Path(FETCHAI_PRIVATE_KEY_FILE).unlink()\n        Path(ETHEREUM_PRIVATE_KEY_FILE).unlink()\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        os.chdir(cls.cwd)\n        shutil.rmtree(cls.t)\n\n\nclass TestGenerateKeyWhenAlreadyExists:\n    \"\"\"Test that the command 'aea generate-key' asks for confirmation when a key already exists.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        os.chdir(cls.t)\n\n    def test_fetchai(self):\n        \"\"\"Test that the fetchai private key is overwritten or not dependending on the user input.\"\"\"\n        result = self.runner.invoke(\n            cli, [*CLI_LOG_OPTION, \"generate-key\", FetchAICrypto.identifier]\n        )\n        assert result.exit_code == 0\n        assert Path(FETCHAI_PRIVATE_KEY_FILE).exists()\n\n        # This tests if the file has been created and its content is correct.\n        make_crypto(FetchAICrypto.identifier, private_key_path=FETCHAI_PRIVATE_KEY_FILE)\n        content = Path(FETCHAI_PRIVATE_KEY_FILE).read_bytes()\n\n        # Saying 'no' leave the files as it is.\n        result = self.runner.invoke(\n            cli, [*CLI_LOG_OPTION, \"generate-key\", FetchAICrypto.identifier], input=\"n\"\n        )\n        assert result.exit_code == 0\n        assert Path(FETCHAI_PRIVATE_KEY_FILE).read_bytes() == content\n\n        # Saying 'yes' overwrites the file.\n        result = self.runner.invoke(\n            cli, [*CLI_LOG_OPTION, \"generate-key\", FetchAICrypto.identifier], input=\"y\"\n        )\n        assert result.exit_code == 0\n        assert Path(FETCHAI_PRIVATE_KEY_FILE).read_bytes() != content\n        make_crypto(FetchAICrypto.identifier, private_key_path=FETCHAI_PRIVATE_KEY_FILE)\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        os.chdir(cls.cwd)\n        shutil.rmtree(cls.t)\n\n\nclass TestGenerateKeyWithFile:\n    \"\"\"Test that the command 'aea generate-key' can accept a file path.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        os.chdir(cls.t)\n\n    def test_fetchai(self):\n        \"\"\"Test that the fetchai private key can be deposited in a custom file.\"\"\"\n        test_file = \"test.txt\"\n        result = self.runner.invoke(\n            cli, [*CLI_LOG_OPTION, \"generate-key\", FetchAICrypto.identifier, test_file]\n        )\n        assert result.exit_code == 0\n        assert Path(test_file).exists()\n\n        # This tests if the file has been created and its content is correct.\n        crypto = make_crypto(FetchAICrypto.identifier, private_key_path=test_file)\n        content = Path(test_file).read_bytes()\n        assert content.decode(\"utf-8\") == crypto.private_key\n\n    def test_all(self):\n        \"\"\"Test that the all command does not allow a file to be provided.\"\"\"\n        test_file = \"test.txt\"\n        result = self.runner.invoke(\n            cli, [*CLI_LOG_OPTION, \"generate-key\", \"all\", test_file]\n        )\n        assert result.exit_code == 1\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        os.chdir(cls.cwd)\n        shutil.rmtree(cls.t)\n\n\nclass TestGenerateKeyWithAddKeyWithoutConnection(AEATestCaseEmpty):\n    \"\"\"Test that the command 'aea generate-key --add-key' works as expected.\"\"\"\n\n    keys_config_path = \"agent.private_key_paths\"\n    args = []  # type: ignore\n\n    def test_fetchai(self):\n        \"\"\"Test that the fetch private key is created correctly.\"\"\"\n\n        with cd(self._get_cwd()):\n            result = self.run_cli_command(\n                \"config\", \"get\", self.keys_config_path, cwd=self._get_cwd()\n            )\n            assert result.exit_code == 0\n            assert json.loads(result.stdout_bytes) == {}\n\n            args = [*CLI_LOG_OPTION, \"generate-key\", FetchAICrypto.identifier]\n            result = self.run_cli_command(\n                *args, \"--add-key\", *self.args, cwd=self._get_cwd()\n            )\n            assert result.exit_code == 0\n            assert Path(FETCHAI_PRIVATE_KEY_FILE).exists()\n            make_crypto(\n                FetchAICrypto.identifier,\n                private_key_path=FETCHAI_PRIVATE_KEY_FILE,\n                password=None,\n            )\n\n            Path(FETCHAI_PRIVATE_KEY_FILE).unlink()\n\n            result = self.run_cli_command(\n                \"config\", \"get\", self.keys_config_path, cwd=self._get_cwd()\n            )\n            assert result.exit_code == 0\n            agent_keys = json.loads(result.stdout_bytes)\n            assert agent_keys.get(FetchAICrypto.identifier) == FETCHAI_PRIVATE_KEY_FILE\n\n\nclass TestGenerateKeyWithAddKeyWithConnection(\n    TestGenerateKeyWithAddKeyWithoutConnection\n):\n    \"\"\"Test that the command 'aea generate-key --add-key' works as expected.\"\"\"\n\n    keys_config_path = \"agent.connection_private_key_paths\"\n    args = [\"--connection\"]  # type: ignore\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_generate_wealth.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This test module contains the tests for commands in aea.cli.generate_wealth module.\"\"\"\nfrom unittest import TestCase, mock\nfrom unittest.mock import MagicMock\n\nimport pytest\nfrom aea_ledger_fetchai import FetchAICrypto\n\nfrom aea.cli import cli\nfrom aea.cli.generate_wealth import _try_generate_wealth\nfrom aea.test_tools.test_cases import AEATestCaseMany, AEATestCaseManyFlaky\n\nfrom tests.conftest import (\n    CLI_LOG_OPTION,\n    COSMOS_ADDRESS_ONE,\n    CliRunner,\n    MAX_FLAKY_RERUNS_INTEGRATION,\n)\nfrom tests.test_aea.test_cli.tools_for_testing import ContextMock\n\n\nclass GenerateWealthTestCase(TestCase):\n    \"\"\"Test case for _generate_wealth method.\"\"\"\n\n    @mock.patch(\"aea.cli.utils.package_utils.Wallet\")\n    @mock.patch(\"aea.cli.generate_wealth.click.echo\")\n    @mock.patch(\"aea.cli.generate_wealth.try_generate_testnet_wealth\")\n    @mock.patch(\n        \"aea.cli.generate_wealth.get_wallet_from_context\",\n        return_value=MagicMock(addresses={\"cosmos\": COSMOS_ADDRESS_ONE}),\n    )\n    def test__generate_wealth_positive(self, *mocks):\n        \"\"\"Test for _generate_wealth method positive result.\"\"\"\n        ctx = ContextMock()\n        _try_generate_wealth(ctx, \"cosmos\", None, True)\n\n\n@mock.patch(\"aea.cli.utils.decorators.try_to_load_agent_config\")\n@mock.patch(\"aea.cli.utils.package_utils.verify_private_keys_ctx\")\n@mock.patch(\"aea.cli.generate_wealth._try_generate_wealth\")\nclass GenerateWealthCommandTestCase(TestCase):\n    \"\"\"Test case for CLI generate_wealth command.\"\"\"\n\n    def setUp(self):\n        \"\"\"Set it up.\"\"\"\n        self.runner = CliRunner()\n\n    def test_run_positive(self, *mocks):\n        \"\"\"Test for CLI generate_wealth positive result.\"\"\"\n        result = self.runner.invoke(\n            cli,\n            [\n                *CLI_LOG_OPTION,\n                \"--skip-consistency-check\",\n                \"generate-wealth\",\n                \"--sync\",\n                FetchAICrypto.identifier,\n            ],\n            standalone_mode=False,\n        )\n        self.assertEqual(result.exit_code, 0)\n\n\nclass TestWealthCommandsPositive(AEATestCaseManyFlaky):\n    \"\"\"Test case for CLI wealth commands.\"\"\"\n\n    @pytest.mark.integration\n    @pytest.mark.flaky(reruns=MAX_FLAKY_RERUNS_INTEGRATION)\n    def test_wealth_commands(self, password_or_none):\n        \"\"\"Test wealth commands.\"\"\"\n        agent_name = \"test_aea\"\n        self.create_agents(agent_name)\n\n        self.set_agent_context(agent_name)\n\n        self.generate_private_key(password=password_or_none)\n        self.add_private_key(password=password_or_none)\n\n        self.generate_wealth(password=password_or_none)\n\n\nclass TestWealthCommandsNegative(AEATestCaseMany):\n    \"\"\"Test case for CLI wealth commands, negative case.\"\"\"\n\n    def test_wealth_commands_negative(self):\n        \"\"\"Test wealth commands.\"\"\"\n        agent_name = \"test_aea\"\n        self.create_agents(agent_name)\n\n        self.set_agent_context(agent_name)\n\n        self.generate_private_key()\n        self.add_private_key()\n\n        settings = {\"unsupported_crypto\": \"path\"}\n        self.nested_set_config(\"agent.private_key_paths\", settings)\n        with pytest.raises(\n            Exception, match=\"Unsupported identifier `unsupported_crypto`\"\n        ):\n            self.generate_wealth()\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_get_address.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This test module contains the tests for commands in aea.cli.get_address module.\"\"\"\nfrom unittest import TestCase, mock\nfrom unittest.mock import MagicMock\n\nfrom aea_ledger_fetchai import FetchAICrypto\n\nfrom aea.cli import cli\nfrom aea.cli.get_address import _try_get_address\nfrom aea.configurations.constants import DEFAULT_LEDGER\nfrom aea.test_tools.test_cases import AEATestCaseEmpty\n\nfrom tests.conftest import CLI_LOG_OPTION, COSMOS_ADDRESS_ONE, CliRunner, method_scope\nfrom tests.test_aea.test_cli.tools_for_testing import ContextMock\n\n\nclass GetAddressTestCase(TestCase):\n    \"\"\"Test case for _get_address method.\"\"\"\n\n    @mock.patch(\n        \"aea.cli.get_address.get_wallet_from_context\",\n        return_value=MagicMock(addresses={\"cosmos\": COSMOS_ADDRESS_ONE}),\n    )\n    def test__get_address_positive(self, *mocks):\n        \"\"\"Test for _get_address method positive result.\"\"\"\n        ctx = ContextMock()\n        _try_get_address(ctx, \"cosmos\")\n\n\n@mock.patch(\"aea.cli.utils.decorators.try_to_load_agent_config\")\n@mock.patch(\"aea.cli.utils.package_utils.verify_private_keys_ctx\")\n@mock.patch(\"aea.cli.get_address._try_get_address\")\n@mock.patch(\"aea.cli.get_address.click.echo\")\nclass GetAddressCommandTestCase(TestCase):\n    \"\"\"Test case for CLI get_address command.\"\"\"\n\n    def setUp(self):\n        \"\"\"Set it up.\"\"\"\n        self.runner = CliRunner()\n\n    def test_run_positive(self, *mocks):\n        \"\"\"Test for CLI get_address positive result.\"\"\"\n        result = self.runner.invoke(\n            cli,\n            [\n                *CLI_LOG_OPTION,\n                \"--skip-consistency-check\",\n                \"get-address\",\n                FetchAICrypto.identifier,\n            ],\n            standalone_mode=False,\n        )\n        self.assertEqual(result.exit_code, 0)\n\n\n@method_scope\nclass TestGetAddressCommand(AEATestCaseEmpty):\n    \"\"\"Test 'get-address' command.\"\"\"\n\n    def test_get_address(self, password_or_none):\n        \"\"\"Run the main test.\"\"\"\n        self.generate_private_key(password=password_or_none)\n        self.add_private_key(password=password_or_none)\n\n        password_option = [\"--password\", password_or_none] if password_or_none else []\n        result = self.run_cli_command(\n            \"get-address\", DEFAULT_LEDGER, *password_option, cwd=self._get_cwd()\n        )\n\n        assert result.exit_code == 0\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_get_multiaddress.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This test module contains the tests for commands in aea.cli.get_multiaddress module.\"\"\"\nfrom unittest import mock\n\nimport base58\nimport pytest\nfrom aea_ledger_fetchai import FetchAICrypto\n\nfrom aea.test_tools.test_cases import AEATestCaseEmpty, _get_password_option_args\n\nfrom packages.fetchai.connections.p2p_libp2p.connection import (\n    PUBLIC_ID as P2P_CONNECTION_PUBLIC_ID,\n)\nfrom packages.fetchai.connections.stub.connection import (\n    PUBLIC_ID as STUB_CONNECTION_PUBLIC_ID,\n)\n\nfrom tests.conftest import method_scope\n\n\n@method_scope\nclass TestGetMultiAddressCommandPositive(AEATestCaseEmpty):\n    \"\"\"Test case for CLI get-multiaddress command.\"\"\"\n\n    def test_run(self, password_or_none):\n        \"\"\"Run the test.\"\"\"\n        self.generate_private_key(FetchAICrypto.identifier, password=password_or_none)\n        self.add_private_key(\n            FetchAICrypto.identifier, connection=False, password=password_or_none\n        )\n\n        password_options = _get_password_option_args(password_or_none)\n        result = self.run_cli_command(\n            \"get-multiaddress\",\n            FetchAICrypto.identifier,\n            *password_options,\n            cwd=self.current_agent_context,\n        )\n\n        assert result.exit_code == 0\n        # test we can decode the output\n        base58.b58decode(result.stdout)\n\n\n@method_scope\nclass TestGetMultiAddressCommandConnectionPositive(AEATestCaseEmpty):\n    \"\"\"Test case for CLI get-multiaddress command with --connection flag.\"\"\"\n\n    def test_run(self, password_or_none):\n        \"\"\"Run the test.\"\"\"\n        self.generate_private_key(FetchAICrypto.identifier, password=password_or_none)\n        self.add_private_key(\n            FetchAICrypto.identifier, connection=True, password=password_or_none\n        )\n\n        password_options = _get_password_option_args(password_or_none)\n        result = self.run_cli_command(\n            \"get-multiaddress\",\n            FetchAICrypto.identifier,\n            \"--connection\",\n            *password_options,\n            cwd=self.current_agent_context,\n        )\n\n        assert result.exit_code == 0\n        # test we can decode the output\n\n\n@method_scope\nclass TestGetMultiAddressCommandConnectionIdPositive(AEATestCaseEmpty):\n    \"\"\"Test case for CLI get-multiaddress command with --connection flag.\"\"\"\n\n    def test_run(self, password_or_none):\n        \"\"\"Run the test.\"\"\"\n        self.add_item(\"connection\", str(STUB_CONNECTION_PUBLIC_ID))\n        self.generate_private_key(FetchAICrypto.identifier, password=password_or_none)\n        self.add_private_key(\n            FetchAICrypto.identifier, connection=True, password=password_or_none\n        )\n\n        self.nested_set_config(\n            \"vendor.fetchai.connections.stub.config\",\n            {\"host\": \"127.0.0.1\", \"port\": 10000},\n        )\n\n        password_options = _get_password_option_args(password_or_none)\n        result = self.run_cli_command(\n            \"get-multiaddress\",\n            FetchAICrypto.identifier,\n            \"--connection\",\n            \"--connection-id\",\n            str(STUB_CONNECTION_PUBLIC_ID),\n            \"--host-field\",\n            \"host\",\n            \"--port-field\",\n            \"port\",\n            *password_options,\n            cwd=self.current_agent_context,\n        )\n\n        assert result.exit_code == 0\n        # multiaddr test\n        expected_multiaddr_prefix = \"/dns4/127.0.0.1/tcp/10000/p2p/\"\n        assert expected_multiaddr_prefix in result.stdout\n        base58_addr = str(result.stdout).replace(expected_multiaddr_prefix, \"\")\n        base58.b58decode(base58_addr)\n\n\n@method_scope\nclass TestGetMultiAddressCommandConnectionIdURIPositive(AEATestCaseEmpty):\n    \"\"\"Test case for CLI get-multiaddress command with --connection flag and --uri.\"\"\"\n\n    def test_run(self, password_or_none):\n        \"\"\"Run the test.\"\"\"\n        self.add_item(\"connection\", str(STUB_CONNECTION_PUBLIC_ID))\n        self.generate_private_key(FetchAICrypto.identifier, password=password_or_none)\n        self.add_private_key(\n            FetchAICrypto.identifier, connection=True, password=password_or_none\n        )\n\n        port = 10101\n        host = \"127.0.0.1\"\n        self.nested_set_config(\n            \"vendor.fetchai.connections.stub.config\", {\"public_uri\": f\"{host}:{port}\"}\n        )\n\n        password_options = _get_password_option_args(password_or_none)\n        result = self.run_cli_command(\n            \"get-multiaddress\",\n            FetchAICrypto.identifier,\n            \"--connection\",\n            \"--connection-id\",\n            str(STUB_CONNECTION_PUBLIC_ID),\n            \"--uri-field\",\n            \"public_uri\",\n            *password_options,\n            cwd=self.current_agent_context,\n        )\n\n        assert result.exit_code == 0\n        # multiaddr test\n        expected_multiaddr_prefix = f\"/dns4/{host}/tcp/{port}/p2p/\"\n        assert expected_multiaddr_prefix in result.stdout\n        base58_addr = str(result.stdout).replace(expected_multiaddr_prefix, \"\")\n        base58.b58decode(base58_addr)\n\n\nclass TestGetMultiAddressCommandConnectionIdURIAgentOverridesPositive(AEATestCaseEmpty):\n    \"\"\"Test case for CLI get-multiaddress command with --connection flag and --uri for agent overrides.\"\"\"\n\n    def test_run(self, *mocks):\n        \"\"\"Run the test.\"\"\"\n        self.add_item(\"connection\", str(P2P_CONNECTION_PUBLIC_ID))\n        self.generate_private_key(FetchAICrypto.identifier)\n        self.add_private_key(FetchAICrypto.identifier, connection=True)\n\n        port = 10101\n        host = \"127.0.0.1\"\n        self.run_cli_command(\n            \"config\",\n            \"set\",\n            \"--type\",\n            \"dict\",\n            \"vendor.fetchai.connections.p2p_libp2p.config\",\n            f'{{\"public_uri\": \"{host}:{port}\"}}',\n            cwd=self.current_agent_context,\n        )\n\n        result = self.run_cli_command(\n            \"get-multiaddress\",\n            FetchAICrypto.identifier,\n            \"--connection\",\n            \"--connection-id\",\n            str(P2P_CONNECTION_PUBLIC_ID),\n            \"--uri-field\",\n            \"public_uri\",\n            cwd=self.current_agent_context,\n        )\n\n        assert result.exit_code == 0\n        # multiaddr test\n        expected_multiaddr_prefix = f\"/dns4/{host}/tcp/{port}/p2p/\"\n        assert expected_multiaddr_prefix in result.stdout\n        base58_addr = str(result.stdout).replace(expected_multiaddr_prefix, \"\")\n        base58.b58decode(base58_addr)\n\n\n@method_scope\nclass TestGetMultiAddressCommandConnectionNegative(AEATestCaseEmpty):\n    \"\"\"Test case for CLI get-multiaddress command with --connection flag.\"\"\"\n\n    def test_run(self, password_or_none):\n        \"\"\"Run the test.\"\"\"\n        self.generate_private_key(FetchAICrypto.identifier, password=password_or_none)\n        self.add_private_key(\n            FetchAICrypto.identifier, connection=True, password=password_or_none\n        )\n\n        password_options = _get_password_option_args(password_or_none)\n        result = self.run_cli_command(\n            \"get-multiaddress\",\n            FetchAICrypto.identifier,\n            \"--connection\",\n            *password_options,\n            cwd=self.current_agent_context,\n        )\n\n        assert result.exit_code == 0\n        # test we can decode the output\n        base58.b58decode(result.stdout)\n\n\n@method_scope\nclass TestGetMultiAddressCommandNegativeMissingKey(AEATestCaseEmpty):\n    \"\"\"Test case for CLI get-multiaddress when the key is missing.\"\"\"\n\n    def test_run(self, password_or_none):\n        \"\"\"Run the test.\"\"\"\n        # this will cause exception because no key is added to the AEA project.\n        with pytest.raises(\n            Exception,\n            match=\"Cannot find '{}'. Please check private_key_path.\".format(\n                FetchAICrypto.identifier\n            ),\n        ):\n            password_options = _get_password_option_args(password_or_none)\n            self.run_cli_command(\n                \"get-multiaddress\",\n                FetchAICrypto.identifier,\n                *password_options,\n                cwd=self.current_agent_context,\n            )\n\n\n@method_scope\nclass TestGetMultiAddressCommandNegativePeerId(AEATestCaseEmpty):\n    \"\"\"Test case for CLI get-multiaddress when the peer id computation raises an error.\"\"\"\n\n    @mock.patch(\n        \"aea.cli.get_multiaddress.MultiAddr.__init__\",\n        side_effect=Exception(\"test error\"),\n    )\n    def test_run(self, _mock, password_or_none):\n        \"\"\"Run the test.\"\"\"\n        self.generate_private_key(FetchAICrypto.identifier, password=password_or_none)\n        self.add_private_key(\n            FetchAICrypto.identifier, connection=False, password=password_or_none\n        )\n\n        # this will cause exception because no key is added to the AEA project.\n        password_options = _get_password_option_args(password_or_none)\n        with pytest.raises(Exception, match=\"test error\"):\n            self.run_cli_command(\n                \"get-multiaddress\",\n                FetchAICrypto.identifier,\n                *password_options,\n                cwd=self.current_agent_context,\n            )\n\n\n@method_scope\nclass TestGetMultiAddressCommandNegativeBadHostField(AEATestCaseEmpty):\n    \"\"\"Test case for CLI get-multiaddress when the host field is missing.\"\"\"\n\n    def test_run(self, password_or_none):\n        \"\"\"Run the test.\"\"\"\n        self.add_item(\"connection\", str(STUB_CONNECTION_PUBLIC_ID))\n        self.generate_private_key(FetchAICrypto.identifier, password=password_or_none)\n        self.add_private_key(\n            FetchAICrypto.identifier, connection=True, password=password_or_none\n        )\n\n        # this will cause exception because no host configuration is in stub connection by default.\n        password_options = _get_password_option_args(password_or_none)\n        with pytest.raises(\n            Exception,\n            match=\"Host field 'some_host' not present in connection configuration fetchai/stub:0.21.3\",\n        ):\n            self.run_cli_command(\n                \"get-multiaddress\",\n                FetchAICrypto.identifier,\n                \"--connection\",\n                \"--connection-id\",\n                str(STUB_CONNECTION_PUBLIC_ID),\n                \"--host-field\",\n                \"some_host\",\n                \"--port-field\",\n                \"some_port\",\n                *password_options,\n                cwd=self.current_agent_context,\n            )\n\n\n@method_scope\nclass TestGetMultiAddressCommandNegativeBadPortField(AEATestCaseEmpty):\n    \"\"\"Test case for CLI get-multiaddress when the port field is missing.\"\"\"\n\n    def test_run(self, password_or_none):\n        \"\"\"Run the test.\"\"\"\n        self.add_item(\"connection\", str(STUB_CONNECTION_PUBLIC_ID))\n        self.generate_private_key(FetchAICrypto.identifier, password=password_or_none)\n        self.add_private_key(\n            FetchAICrypto.identifier, connection=True, password=password_or_none\n        )\n\n        self.nested_set_config(\n            \"vendor.fetchai.connections.stub.config\", {\"host\": \"127.0.0.1\"}\n        )\n\n        # this will cause exception because no port configuration is in stub connection by default.\n        password_options = _get_password_option_args(password_or_none)\n        with pytest.raises(\n            Exception,\n            match=\"Port field 'some_port' not present in connection configuration fetchai/stub:0.21.3\",\n        ):\n            self.run_cli_command(\n                \"get-multiaddress\",\n                FetchAICrypto.identifier,\n                \"--connection\",\n                \"--connection-id\",\n                str(STUB_CONNECTION_PUBLIC_ID),\n                \"--host-field\",\n                \"host\",\n                \"--port-field\",\n                \"some_port\",\n                *password_options,\n                cwd=self.current_agent_context,\n            )\n\n\n@method_scope\nclass TestGetMultiAddressCommandNegativeBadConnectionId(AEATestCaseEmpty):\n    \"\"\"Test case for CLI get-multiaddress when the connection id is missing.\"\"\"\n\n    def test_run(self, password_or_none):\n        \"\"\"Run the test.\"\"\"\n        self.generate_private_key(FetchAICrypto.identifier, password=password_or_none)\n        self.add_private_key(\n            FetchAICrypto.identifier, connection=True, password=password_or_none\n        )\n\n        # this will cause exception because a bad public id is provided.\n        password_options = _get_password_option_args(password_or_none)\n        connection_id = \"some_author/some_connection:0.1.0\"\n        with pytest.raises(\n            Exception,\n            match=f\"Cannot find connection with the public id {connection_id}\",\n        ):\n            self.run_cli_command(\n                \"get-multiaddress\",\n                FetchAICrypto.identifier,\n                \"--connection\",\n                \"--connection-id\",\n                connection_id,\n                *password_options,\n                cwd=self.current_agent_context,\n            )\n\n\n@method_scope\nclass TestGetMultiAddressCommandNegativeFullMultiaddrComputation(AEATestCaseEmpty):\n    \"\"\"Test case for CLI get-multiaddress when an error occurs in the computation of the full multiaddr.\"\"\"\n\n    @mock.patch(\n        \"aea.cli.get_multiaddress.MultiAddr.__init__\",\n        side_effect=Exception(\"test error\"),\n    )\n    def test_run(self, _mock, password_or_none):\n        \"\"\"Run the test.\"\"\"\n        self.add_item(\"connection\", str(STUB_CONNECTION_PUBLIC_ID))\n        self.generate_private_key(FetchAICrypto.identifier, password=password_or_none)\n        self.add_private_key(\n            FetchAICrypto.identifier, connection=True, password=password_or_none\n        )\n\n        self.nested_set_config(\n            \"vendor.fetchai.connections.stub.config\",\n            {\"host\": \"127.0.0.1\", \"port\": 10000},\n        )\n\n        # this will cause exception due to the mocking.\n        password_options = _get_password_option_args(password_or_none)\n        with pytest.raises(\n            Exception,\n            match=\"An error occurred while creating the multiaddress: test error\",\n        ):\n            self.run_cli_command(\n                \"get-multiaddress\",\n                FetchAICrypto.identifier,\n                \"--connection\",\n                \"--connection-id\",\n                str(STUB_CONNECTION_PUBLIC_ID),\n                \"--host-field\",\n                \"host\",\n                \"--port-field\",\n                \"port\",\n                *password_options,\n                cwd=self.current_agent_context,\n            )\n\n\n@method_scope\nclass TestGetMultiAddressCommandNegativeOnlyHostSpecified(AEATestCaseEmpty):\n    \"\"\"Test case for CLI get-multiaddress when only the host field is specified.\"\"\"\n\n    def test_run(self, password_or_none):\n        \"\"\"Run the test.\"\"\"\n        self.add_item(\"connection\", str(STUB_CONNECTION_PUBLIC_ID))\n        self.generate_private_key(FetchAICrypto.identifier, password=password_or_none)\n        self.add_private_key(\n            FetchAICrypto.identifier, connection=True, password=password_or_none\n        )\n\n        # this will cause exception because only the host, and not the port, are specified.\n        password_options = _get_password_option_args(password_or_none)\n        with pytest.raises(\n            Exception,\n            match=\"-h/--host-field and -p/--port-field must be specified together.\",\n        ):\n            self.run_cli_command(\n                \"get-multiaddress\",\n                FetchAICrypto.identifier,\n                \"--connection\",\n                \"--connection-id\",\n                str(STUB_CONNECTION_PUBLIC_ID),\n                \"--host-field\",\n                \"some_host\",\n                *password_options,\n                cwd=self.current_agent_context,\n            )\n\n\n@method_scope\nclass TestGetMultiAddressCommandNegativeUriNotExisting(AEATestCaseEmpty):\n    \"\"\"Test case for CLI get-multiaddress when the URI field doesn't exists.\"\"\"\n\n    def test_run(self, password_or_none):\n        \"\"\"Run the test.\"\"\"\n        self.add_item(\"connection\", str(STUB_CONNECTION_PUBLIC_ID))\n        self.generate_private_key(FetchAICrypto.identifier, password=password_or_none)\n        self.add_private_key(\n            FetchAICrypto.identifier, connection=True, password=password_or_none\n        )\n\n        # this will cause exception because only the host, and not the port, are specified.\n        password_options = _get_password_option_args(password_or_none)\n        with pytest.raises(\n            Exception,\n            match=\"URI field 'some_uri' not present in connection configuration fetchai/stub:0.21.3\",\n        ):\n            self.run_cli_command(\n                \"get-multiaddress\",\n                FetchAICrypto.identifier,\n                \"--connection\",\n                \"--connection-id\",\n                str(STUB_CONNECTION_PUBLIC_ID),\n                \"--uri-field\",\n                \"some_uri\",\n                *password_options,\n                cwd=self.current_agent_context,\n            )\n\n\n@method_scope\nclass TestGetMultiAddressCommandNegativeBadUri(AEATestCaseEmpty):\n    \"\"\"Test case for CLI get-multiaddress when we cannot parse the URI field.\"\"\"\n\n    def test_run(self, password_or_none):\n        \"\"\"Run the test.\"\"\"\n        self.add_item(\"connection\", str(STUB_CONNECTION_PUBLIC_ID))\n        self.generate_private_key(FetchAICrypto.identifier, password=password_or_none)\n        self.add_private_key(\n            FetchAICrypto.identifier, connection=True, password=password_or_none\n        )\n\n        self.nested_set_config(\n            \"vendor.fetchai.connections.stub.config\",\n            {\"some_uri\": \"some-unparsable_URI\"},\n        )\n\n        # this will cause exception because only the host, and not the port, are specified.\n        password_options = _get_password_option_args(password_or_none)\n        with pytest.raises(\n            Exception,\n            match=r\"Cannot extract host and port from some_uri: 'some-unparsable_URI'. Reason: URI Doesn't match regex '\",\n        ):\n            self.run_cli_command(\n                \"get-multiaddress\",\n                FetchAICrypto.identifier,\n                \"--connection\",\n                \"--connection-id\",\n                str(STUB_CONNECTION_PUBLIC_ID),\n                \"--uri-field\",\n                \"some_uri\",\n                *password_options,\n                cwd=self.current_agent_context,\n            )\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_get_public_key.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This test module contains the tests for commands in aea.cli.get_public_key module.\"\"\"\n\nfrom unittest import TestCase, mock\nfrom unittest.mock import MagicMock\n\nfrom aea_ledger_fetchai import FetchAICrypto\n\nfrom aea.cli import cli\nfrom aea.cli.get_public_key import _try_get_public_key\n\nfrom tests.conftest import CLI_LOG_OPTION, COSMOS_ADDRESS_ONE, CliRunner\nfrom tests.test_aea.test_cli.tools_for_testing import ContextMock\n\n\nclass GetPublicKeyTestCase(TestCase):\n    \"\"\"Test case for _get_public_key method.\"\"\"\n\n    @mock.patch(\n        \"aea.cli.get_public_key.get_wallet_from_context\",\n        return_value=MagicMock(public_keys={\"cosmos\": COSMOS_ADDRESS_ONE}),\n    )\n    def test__get_address_positive(self, *mocks):\n        \"\"\"Test for _get_public_key method positive result.\"\"\"\n        ctx = ContextMock()\n        _try_get_public_key(ctx, \"cosmos\")\n\n\n@mock.patch(\"aea.cli.utils.decorators.try_to_load_agent_config\")\n@mock.patch(\"aea.cli.utils.package_utils.verify_private_keys_ctx\")\n@mock.patch(\"aea.cli.get_public_key._try_get_public_key\")\n@mock.patch(\"aea.cli.get_public_key.click.echo\")\nclass GetPublicKeyCommandTestCase(TestCase):\n    \"\"\"Test case for CLI get_public_key command.\"\"\"\n\n    def setUp(self):\n        \"\"\"Set it up.\"\"\"\n        self.runner = CliRunner()\n\n    def test_run_positive(self, *mocks):\n        \"\"\"Test for CLI get_public_key positive result.\"\"\"\n        result = self.runner.invoke(\n            cli,\n            [\n                *CLI_LOG_OPTION,\n                \"--skip-consistency-check\",\n                \"get-public-key\",\n                FetchAICrypto.identifier,\n            ],\n            standalone_mode=False,\n        )\n        self.assertEqual(result.exit_code, 0)\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_get_wealth.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This test module contains the tests for commands in aea.cli.generate_wealth module.\"\"\"\n\nfrom unittest import TestCase, mock\n\nfrom aea_ledger_fetchai import FetchAICrypto\n\nfrom aea.cli import cli\nfrom aea.cli.get_wealth import _try_get_wealth\nfrom aea.test_tools.test_cases import AEATestCaseEmpty\n\nfrom tests.conftest import CLI_LOG_OPTION, CliRunner, method_scope\nfrom tests.test_aea.test_cli.tools_for_testing import ContextMock\n\n\nclass GetWealthTestCase(TestCase):\n    \"\"\"Test case for _get_wealth method.\"\"\"\n\n    @mock.patch(\"aea.cli.utils.package_utils.Wallet\")\n    @mock.patch(\"aea.cli.utils.package_utils.verify_private_keys_ctx\")\n    @mock.patch(\"aea.cli.get_wealth.try_get_balance\")\n    def test__get_wealth_positive(self, *mocks):\n        \"\"\"Test for _get_wealth method positive result.\"\"\"\n        ctx = ContextMock()\n        _try_get_wealth(ctx, \"type\")\n\n\n@mock.patch(\"aea.cli.utils.decorators.try_to_load_agent_config\")\n@mock.patch(\"aea.cli.utils.package_utils.verify_private_keys_ctx\")\n@mock.patch(\"aea.cli.get_wealth._try_get_wealth\")\n@mock.patch(\"aea.cli.get_wealth.click.echo\")\nclass GetWealthCommandTestCase(TestCase):\n    \"\"\"Test case for CLI get_wealth command.\"\"\"\n\n    def setUp(self):\n        \"\"\"Set it up.\"\"\"\n        self.runner = CliRunner()\n\n    def test_run_positive(self, *mocks):\n        \"\"\"Test for CLI get_wealth positive result.\"\"\"\n        result = self.runner.invoke(\n            cli,\n            [\n                *CLI_LOG_OPTION,\n                \"--skip-consistency-check\",\n                \"get-wealth\",\n                FetchAICrypto.identifier,\n            ],\n            standalone_mode=False,\n        )\n        self.assertEqual(result.exit_code, 0)\n\n\n@method_scope\nclass TestGetWealth(AEATestCaseEmpty):\n    \"\"\"Test 'get-wealth' command.\"\"\"\n\n    @mock.patch(\"click.echo\")\n    def test_get_wealth(self, _echo_mock, password_or_none):\n        \"\"\"Run the main test.\"\"\"\n        self.generate_private_key(password=password_or_none)\n        self.add_private_key(password=password_or_none)\n        self.get_wealth(password=password_or_none)\n\n        expected_wealth = 0\n        _echo_mock.assert_called_with(expected_wealth)\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_init.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This test module contains the tests for the `aea init` sub-command.\"\"\"\nimport os\nimport shutil\nimport tempfile\nfrom pathlib import Path\nfrom unittest.mock import patch\n\nimport yaml\n\nfrom aea.cli import cli\n\nfrom tests.conftest import CLI_LOG_OPTION, CliRunner, random_string\n\n\nclass TestDoInit:\n    \"\"\"Test that the command 'aea init'.\"\"\"\n\n    def setup(self):\n        \"\"\"Set the test up.\"\"\"\n        self.runner = CliRunner()\n        self.agent_name = \"myagent\"\n        self.cwd = os.getcwd()\n        self.t = tempfile.mkdtemp()\n        self.agent_folder = Path(self.t, self.agent_name)\n        os.chdir(self.t)\n        self.cli_config_file = f\"{self.t}/cli_config.yaml\"\n        self.cli_config_patch = patch(\n            \"aea.cli.utils.config.CLI_CONFIG_PATH\", self.cli_config_file\n        )\n        self.cli_config_patch.start()\n\n    def test_author_local(self):\n        \"\"\"Test author set localy.\"\"\"\n        author = \"test_author\"\n        assert not os.path.exists(self.cli_config_file)\n\n        result = self.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"init\", \"--author\", author],\n        )\n\n        assert result.exit_code == 0\n        assert \"AEA configurations successfully initialized\" in result.output\n        assert self._read_config()[\"author\"] == \"test_author\"\n\n    def _read_config(self) -> dict:\n        \"\"\"Read cli config file.\n\n        :return: dict\n        \"\"\"\n        with open(self.cli_config_file, \"r\") as f:\n            data = yaml.safe_load(f)\n        return data\n\n    def test_already_registered(self):\n        \"\"\"Test author already registered.\"\"\"\n        result = self.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"init\", \"--author\", \"author\"],\n        )\n        assert result.exit_code == 0\n        result = self.runner.invoke(cli, [*CLI_LOG_OPTION, \"init\"])\n        assert \"AEA configurations already initialized\" in result.output\n\n    @patch(\"aea.cli.register.register_new_account\", return_value=\"TOKEN\")\n    def test_non_local(self, mock):\n        \"\"\"Test registration online.\"\"\"\n        email = f\"{random_string()}@{random_string()}.com\"\n        pwd = random_string()\n        author = \"test_author\" + random_string()\n        result = self.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"init\", \"--register\", \"--author\", author],\n            input=f\"n\\n{email}\\n{pwd}\\n{pwd}\\n\\n\",\n        )\n        assert result.exit_code == 0, result.output\n        assert \"Successfully registered\" in result.output\n\n        config = self._read_config()\n        assert config[\"author\"] == author\n        assert config[\"auth_token\"] == \"TOKEN\"\n\n    @patch(\"aea.cli.init.do_login\", return_value=None)\n    def test_registered(self, *mocks):\n        \"\"\"Test author already registered.\"\"\"\n        author = \"test_author\" + random_string()\n        result = self.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"init\", \"--register\", \"--author\", author],\n            input=\"y\\nsome fake password\\n\",\n        )\n\n        assert result.exit_code == 0\n\n    @patch(\"aea.cli.init.is_auth_token_present\", return_value=True)\n    @patch(\"aea.cli.init.check_is_author_logged_in\", return_value=True)\n    def test_already_logged_in(self, *mocks):\n        \"\"\"Registered and logged in (has token).\"\"\"\n        result = self.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"init\", \"--register\", \"--author\", \"test_author\"],\n        )\n        assert result.exit_code == 0\n\n    def teardown(self):\n        \"\"\"Tear the test down.\"\"\"\n        self.cli_config_patch.stop()\n        os.chdir(self.cwd)\n        shutil.rmtree(self.t)\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_install.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This test module contains the tests for the `aea install` sub-command.\"\"\"\n\nfrom pathlib import Path\nfrom typing import Dict\n\nimport pytest\nimport yaml\nfrom click import ClickException\n\nfrom aea.configurations.base import DEFAULT_PROTOCOL_CONFIG_FILE\nfrom aea.configurations.constants import DEFAULT_CONNECTION_CONFIG_FILE\nfrom aea.test_tools.test_cases import AEATestCase, AEATestCaseEmpty\n\nfrom tests.conftest import CUR_PATH\n\n\nclass TestInstall(AEATestCase):\n    \"\"\"Test that the command 'aea install' works as expected.\"\"\"\n\n    path_to_aea: Path = Path(CUR_PATH, \"data\", \"dummy_aea\")\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        super().setup_class()\n        cls.result = cls.run_cli_command(\"install\", cwd=cls._get_cwd())\n\n    def test_exit_code_equal_to_zero(self):\n        \"\"\"Assert that the exit code is equal to zero (i.e. success).\"\"\"\n        assert self.result.exit_code == 0\n\n\nclass TestInstallFromRequirementFile(AEATestCase):\n    \"\"\"Test that the command 'aea install --requirement REQ_FILE' works.\"\"\"\n\n    path_to_aea: Path = Path(CUR_PATH, \"data\", \"dummy_aea\")\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        super().setup_class()\n        cls.result = cls.run_cli_command(\n            \"install\", \"-r\", \"requirements.txt\", cwd=cls._get_cwd()\n        )\n\n    def test_exit_code_equal_to_zero(self):\n        \"\"\"Assert that the exit code is equal to zero (i.e. success).\"\"\"\n        assert self.result.exit_code == 0\n\n\nclass TestInstallFailsWhenDependencyDoesNotExist(AEATestCaseEmpty):\n    \"\"\"Test that the command 'aea install' fails when a dependency is not found.\"\"\"\n\n    capture_log = True\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        super().setup_class()\n        result = cls.run_cli_command(\n            \"scaffold\", \"protocol\", \"-y\", \"my_protocol\", cwd=cls._get_cwd()\n        )\n        assert result.exit_code == 0\n\n        config_path = (\n            Path(cls._get_cwd())\n            / \"protocols\"\n            / \"my_protocol\"\n            / DEFAULT_PROTOCOL_CONFIG_FILE\n        )\n        with config_path.open() as fp:\n            config = yaml.safe_load(fp)\n\n        config.setdefault(\"dependencies\", {}).update(\n            {\n                \"this_is_a_test_dependency\": {\n                    \"version\": \"==0.1.0\",\n                    \"index\": \"https://test.pypi.org/simple\",\n                },\n            }\n        )\n\n        with config_path.open(mode=\"w\") as fp:\n            yaml.safe_dump(config, fp)\n\n    def test_error(self):\n        \"\"\"Assert an error occurs.\"\"\"\n        with pytest.raises(\n            ClickException,\n            match=\"An error occurred while installing.*this_is_a_test_dependency.*\",\n        ):\n            self.run_cli_command(\"install\", cwd=self._get_cwd())\n\n\nclass TestInstallWithRequirementFailsWhenFileIsBad(AEATestCase):\n    \"\"\"Test that the command 'aea install -r REQ_FILE' fails if the requirement file is not good.\"\"\"\n\n    path_to_aea: Path = Path(CUR_PATH, \"data\", \"dummy_aea\")\n\n    def test_error(self):\n        \"\"\"Test that an error occurs.\"\"\"\n        with pytest.raises(\n            ClickException,\n            match=\"An error occurred while installing requirement file bad_requirements.txt. Stopping...\",\n        ):\n            self.run_cli_command(\n                \"install\", \"-r\", \"bad_requirements.txt\", cwd=self._get_cwd()\n            )\n\n\nclass TestInstallFailsWhenDependencyHasUnsatisfiableSpecifier(AEATestCaseEmpty):\n    \"\"\"Test that the command 'aea install' fails when a dependency has an unsatisfiable version specifier.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        super().setup_class()\n        result = cls.run_cli_command(\n            \"scaffold\", \"connection\", \"my_connection_1\", cwd=cls._get_cwd()\n        )\n        assert result.exit_code == 0\n        result = cls.run_cli_command(\n            \"scaffold\", \"connection\", \"my_connection_2\", cwd=cls._get_cwd()\n        )\n        assert result.exit_code == 0\n\n        config_path_1 = (\n            Path(cls._get_cwd())\n            / \"connections\"\n            / \"my_connection_1\"\n            / DEFAULT_CONNECTION_CONFIG_FILE\n        )\n\n        cls._write_dependencies(\n            {\"this_is_a_test_dependency\": {\"version\": \"==0.1.0\"}}, config_path_1\n        )\n\n        config_path_2 = (\n            Path(cls._get_cwd())\n            / \"connections\"\n            / \"my_connection_2\"\n            / DEFAULT_CONNECTION_CONFIG_FILE\n        )\n\n        cls._write_dependencies(\n            {\"this_is_a_test_dependency\": {\"version\": \"==0.2.0\"}}, config_path_2\n        )\n\n    @classmethod\n    def _write_dependencies(cls, dependency_dict: Dict, path_to_config: Path):\n        \"\"\"Write a dependency to a configuration file.\"\"\"\n        with path_to_config.open() as fp:\n            config = yaml.safe_load(fp)\n        config.setdefault(\"dependencies\", {}).update(dependency_dict)\n        with path_to_config.open(mode=\"w\") as fp:\n            yaml.safe_dump(config, fp)\n\n    def test_error(self):\n        \"\"\"Assert an error occurs.\"\"\"\n        with pytest.raises(\n            ClickException,\n            match=\"cannot install the following dependencies as the joint version specifier is unsatisfiable:\\n - this_is_a_test_dependency: ==0.1.0,==0.2.0\",\n        ):\n            self.run_cli_command(\"install\", cwd=self._get_cwd())\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_interact.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This test module contains tests for iteract command.\"\"\"\nfrom unittest import TestCase, mock\n\nimport pytest\n\nfrom aea.cli.interact import (\n    _construct_message,\n    _process_envelopes,\n    _try_construct_envelope,\n)\nfrom aea.helpers.base import send_control_c\nfrom aea.mail.base import Envelope\nfrom aea.test_tools.test_cases import AEATestCaseEmptyFlaky, AEATestCaseManyFlaky\n\nfrom packages.fetchai.connections.stub.connection import PUBLIC_ID as STUB_CONNECTION_ID\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.skills.echo import PUBLIC_ID as ECHO_SKILL_PUBLIC_ID\n\nfrom tests.conftest import MAX_FLAKY_RERUNS\n\n\nclass TestInteractCommand(AEATestCaseManyFlaky):\n    \"\"\"Test that interact command work.\"\"\"\n\n    @pytest.mark.flaky(reruns=MAX_FLAKY_RERUNS)\n    def test_interact_command_positive(self):\n        \"\"\"Run interaction.\"\"\"\n        agent_name = \"test_iteraction_agent\"\n        self.create_agents(agent_name)\n\n        # prepare agent\n        self.set_agent_context(agent_name)\n        self.generate_private_key()\n        self.add_private_key()\n        self.add_item(\"connection\", str(STUB_CONNECTION_ID))\n        self.run_install()\n\n        agent_process = self.run_agent()\n        interaction_process = self.run_interaction()\n\n        check_strings = (\"Starting AEA interaction channel...\",)\n        missing_strings = self.missing_from_output(\n            interaction_process, check_strings, is_terminating=False\n        )\n        assert missing_strings == [], \"Strings {} didn't appear in output.\".format(\n            missing_strings\n        )\n\n        self.terminate_agents(interaction_process)\n        self.terminate_agents(agent_process)\n        assert (\n            self.is_successfully_terminated()\n        ), \"Agent {} wasn't successfully terminated.\".format(agent_name)\n\n\nclass ConstructMessageTestCase(TestCase):\n    \"\"\"Test case for _construct_message method.\"\"\"\n\n    def test__construct_message_positive(self, *mocks):\n        \"\"\"Test _construct_message method for positive result.\"\"\"\n        envelope = mock.Mock()\n        envelope.to = \"receiver\"\n        envelope.sender = \"sender\"\n        envelope.protocol_specification_id = \"protocol-id\"\n\n        envelope.message = \"Message\"\n        message_class = DefaultMessage\n        with mock.patch.object(\n            message_class.serializer, \"decode\", return_value=\"Decoded message\"\n        ):\n            result = _construct_message(\"action\", envelope, message_class)\n            expected_result = (\n                \"\\nAction envelope:\"\n                \"\\nto: receiver\"\n                \"\\nsender: sender\"\n                \"\\nprotocol_specification_id: protocol-id\"\n                \"\\nmessage: Message\\n\"\n            )\n            self.assertEqual(result, expected_result)\n\n            envelope.message = b\"Encoded message\"\n            result = _construct_message(\"action\", envelope, message_class)\n            expected_result = (\n                \"\\nAction envelope:\"\n                \"\\nto: receiver\"\n                \"\\nsender: sender\"\n                \"\\nprotocol_specification_id: protocol-id\"\n                \"\\nmessage: Decoded message\\n\"\n            )\n            self.assertEqual(result, expected_result)\n\n\ndef _raise_keyboard_interrupt():\n    raise KeyboardInterrupt()\n\n\ndef _raise_exception():\n    raise Exception()\n\n\nclass TryConstructEnvelopeTestCase(TestCase):\n    \"\"\"Test case for _try_construct_envelope method.\"\"\"\n\n    @mock.patch(\"builtins.input\", return_value=\"Inputed value\")\n    def test__try_construct_envelope_positive(self, *mocks):\n        \"\"\"Test _try_construct_envelope for positive result.\"\"\"\n        dialogues_mock = mock.Mock()\n        msg_mock = mock.Mock(spec=DefaultMessage)\n        msg_mock.to = \"to\"\n        msg_mock.sender = \"sender\"\n        dialogues_mock.create.return_value = msg_mock, None\n        message_class = mock.Mock()\n        envelope = _try_construct_envelope(\"agent_name\", dialogues_mock, message_class)\n        self.assertIsInstance(envelope, Envelope)\n\n    @mock.patch(\"builtins.input\", return_value=\"\")\n    def test__try_construct_envelope_positive_no_input_message(self, *mocks):\n        \"\"\"Test _try_construct_envelope for no input message result.\"\"\"\n        envelope = _try_construct_envelope(\"agent_name\", \"dialogues\", \"message_class\")\n        self.assertEqual(envelope, None)\n\n    @mock.patch(\"builtins.input\", _raise_keyboard_interrupt)\n    def test__try_construct_envelope_keyboard_interrupt(self, *mocks):\n        \"\"\"Test _try_construct_envelope for keyboard interrupt result.\"\"\"\n        with self.assertRaises(KeyboardInterrupt):\n            _try_construct_envelope(\"agent_name\", \"dialogues\", mock.Mock())\n\n    @mock.patch(\"builtins.input\", _raise_exception)\n    def test__try_construct_envelope_exception_raised(self, *mocks):\n        \"\"\"Test _try_construct_envelope for exception raised result.\"\"\"\n        envelope = _try_construct_envelope(\"agent_name\", \"dialogues\", \"message_class\")\n        self.assertEqual(envelope, None)\n\n\nclass ProcessEnvelopesTestCase(TestCase):\n    \"\"\"Test case for _process_envelopes method.\"\"\"\n\n    @mock.patch(\"aea.cli.interact.click.echo\")\n    @mock.patch(\"aea.cli.interact._construct_message\")\n    @mock.patch(\"aea.cli.interact._try_construct_envelope\")\n    def test__process_envelopes_positive(\n        self, try_construct_envelope_mock, construct_message_mock, click_echo_mock\n    ):\n        \"\"\"Test _process_envelopes method for positive result.\"\"\"\n        agent_name = \"agent_name\"\n        identity_stub = mock.Mock()\n        identity_stub.name = \"identity_stub_name\"\n        inbox = mock.Mock()\n        inbox.empty = lambda: False\n        inbox.get_nowait = lambda: \"Not None\"\n        outbox = mock.Mock()\n        dialogues = mock.Mock()\n        message_class = mock.Mock()\n\n        try_construct_envelope_mock.return_value = None\n        constructed_message = \"Constructed message\"\n        construct_message_mock.return_value = constructed_message\n\n        # no envelope and inbox not empty behaviour\n        _process_envelopes(agent_name, inbox, outbox, dialogues, message_class)\n        click_echo_mock.assert_called_once_with(constructed_message)\n\n        # no envelope and inbox empty behaviour\n        inbox.empty = lambda: True\n        _process_envelopes(agent_name, inbox, outbox, dialogues, message_class)\n        click_echo_mock.assert_called_with(\"Received no new envelope!\")\n\n        # present envelope behaviour\n        try_construct_envelope_mock.return_value = \"Not None envelope\"\n        outbox.put = mock.Mock()\n        _process_envelopes(agent_name, inbox, outbox, dialogues, message_class)\n        outbox.put.assert_called_once_with(\"Not None envelope\")\n        click_echo_mock.assert_called_with(constructed_message)\n\n    @mock.patch(\"aea.cli.interact._try_construct_envelope\", return_value=None)\n    def test__process_envelopes_couldnt_recover(self, *mocks):\n        \"\"\"Test _process_envelopes for couldn't recover envelope result.\"\"\"\n        agent_name = \"agent_name\"\n        identity_stub = mock.Mock()\n        identity_stub.name = \"identity_stub_name\"\n        inbox = mock.Mock()\n        inbox.empty = lambda: False\n        inbox.get_nowait = lambda: None\n        outbox = mock.Mock()\n        dialogues = mock.Mock()\n        message_class = mock.Mock()\n\n        with self.assertRaises(ValueError):\n            _process_envelopes(agent_name, inbox, outbox, dialogues, message_class)\n\n\nclass TestInteractEcho(AEATestCaseEmptyFlaky):\n    \"\"\"Test 'aea interact' with the echo skill.\"\"\"\n\n    @pytest.mark.integration\n    @pytest.mark.flaky(reruns=MAX_FLAKY_RERUNS)  # can be flaky on Windows\n    def test_interact(self):\n        \"\"\"Test the 'aea interact' command with the echo skill.\"\"\"\n        self.generate_private_key()\n        self.add_private_key()\n        self.add_item(\"connection\", str(STUB_CONNECTION_ID))\n        self.add_item(\"skill\", str(ECHO_SKILL_PUBLIC_ID))\n        self.run_agent()\n        process = self.run_interaction()\n\n        assert not self.missing_from_output(\n            process,\n            [\n                \"Starting AEA interaction channel...\",\n                f\"Provide message of protocol '{str(DefaultMessage.protocol_id)}' for performative bytes\",\n            ],\n            timeout=10,\n            is_terminating=False,\n        )\n\n        # send first message\n        process.stdin.write(b\"hello\\n\")\n        process.stdin.flush()\n\n        assert not self.missing_from_output(\n            process,\n            [\n                \"Sending envelope:\",\n                f\"to: {self.agent_name}\",\n                f\"sender: {self.agent_name}_interact\",\n                f\"protocol_specification_id: {str(DefaultMessage.protocol_specification_id)}\",\n                \"message_id=1\",\n                \"target=0\",\n                \"performative=bytes\",\n                \"content=b'hello'\",\n                f\"Provide message of protocol '{str(DefaultMessage.protocol_id)}' for performative bytes:\",\n            ],\n            timeout=10,\n            is_terminating=False,\n        )\n\n        # read incoming messages\n        process.stdin.write(b\"\\n\")\n        process.stdin.flush()\n        assert not self.missing_from_output(\n            process,\n            [\n                \"Interrupting input, checking inbox ...\",\n                \"Received envelope:\",\n                f\"to: {self.agent_name}_interact\",\n                f\"sender: {self.agent_name}\",\n                f\"protocol_specification_id: {str(DefaultMessage.protocol_specification_id)}\",\n                \"message_id=-1\",\n                \"target=1\",\n                \"performative=bytes\",\n                \"content=b'hello'\",\n                f\"Provide message of protocol '{str(DefaultMessage.protocol_id)}' for performative bytes:\",\n            ],\n            timeout=10,\n            is_terminating=False,\n        )\n\n        # read another message - should return nothing\n        process.stdin.write(b\"\\n\")\n        process.stdin.flush()\n        assert not self.missing_from_output(\n            process,\n            [\n                \"Interrupting input, checking inbox ...\",\n                \"Received no new envelope!\",\n                f\"Provide message of protocol '{str(DefaultMessage.protocol_id)}' for performative bytes:\",\n            ],\n            timeout=10,\n            is_terminating=False,\n        )\n\n        send_control_c(process)\n\n        assert not self.missing_from_output(\n            process, [\"Interaction interrupted!\"], timeout=10, is_terminating=False\n        )\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_issue_certificates.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This test module contains tests for 'issue-certificates' command.\"\"\"\nimport json\nimport os\nimport shutil\nfrom pathlib import Path\nfrom typing import List\n\nimport pytest\nfrom aea_ledger_ethereum import EthereumCrypto\nfrom aea_ledger_fetchai import FetchAICrypto\n\nfrom aea.cli.utils.config import dump_item_config\nfrom aea.helpers.base import CertRequest\nfrom aea.test_tools.test_cases import AEATestCaseEmpty, _get_password_option_args\n\nfrom tests.conftest import CUR_PATH, ETHEREUM_PRIVATE_KEY_FILE, FETCHAI_PRIVATE_KEY_FILE\nfrom tests.data.dummy_connection.connection import DummyConnection\n\n\nclass BaseTestIssueCertificates(AEATestCaseEmpty):\n    \"\"\"Base test class for 'aea issue-certificates' tests.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set up the class.\"\"\"\n        super().setup_class()\n\n        # add dummy connection\n        shutil.copytree(\n            os.path.join(CUR_PATH, \"data\", \"dummy_connection\"),\n            os.path.join(cls.current_agent_context, \"connections\", \"dummy\"),\n        )\n        agent_config = cls.load_agent_config(cls.agent_name)\n        agent_config.author = FetchAICrypto.identifier\n        agent_config.connections.add(DummyConnection.connection_id)\n        dump_item_config(agent_config, Path(cls.current_agent_context))\n\n    @classmethod\n    def add_cert_requests(cls, cert_requests: List[CertRequest], connection_name: str):\n        \"\"\"Add certificate requests to a target connection.\"\"\"\n        cls.nested_set_config(\n            f\"connections.{connection_name}.cert_requests\", cert_requests\n        )\n\n\nclass TestIssueCertificatesPositive(BaseTestIssueCertificates):\n    \"\"\"Test 'issue-certificates', positive case.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set up the class.\"\"\"\n        super().setup_class()\n\n        cls.expected_path_1 = os.path.abspath(\"path_1\")\n        cls.expected_path_2 = os.path.abspath(\"path_2\")\n        cls.cert_id_1 = \"cert_id_1\"\n        cls.cert_id_2 = \"cert_id_2\"\n        cls.cert_request_1 = CertRequest(\n            identifier=cls.cert_id_1,\n            ledger_id=FetchAICrypto.identifier,\n            not_after=\"2020-01-02\",\n            not_before=\"2020-01-01\",\n            public_key=FetchAICrypto.identifier,\n            message_format=\"{public_key}\",\n            save_path=cls.expected_path_1,\n        )\n        cls.cert_request_2 = CertRequest(\n            identifier=cls.cert_id_2,\n            ledger_id=FetchAICrypto.identifier,\n            not_after=\"2020-01-02\",\n            not_before=\"2020-01-01\",\n            public_key=\"0xABCDEF123456\",\n            message_format=\"{public_key}\",\n            save_path=cls.expected_path_2,\n        )\n        cls.add_cert_requests(\n            [cls.cert_request_1, cls.cert_request_2], DummyConnection.connection_id.name\n        )\n\n    def test_issue_certificate(self, password_or_none):\n        \"\"\"Test 'aea issue-certificates' in case of success.\"\"\"\n        # setup: add private key with password\n        self.generate_private_key(password=password_or_none)\n        self.add_private_key(password=password_or_none)\n        self.add_private_key(connection=True, password=password_or_none)\n\n        # issue certificates and check\n        password_options = _get_password_option_args(password_or_none)\n        result = self.run_cli_command(\n            \"issue-certificates\", *password_options, cwd=self._get_cwd()\n        )\n        self._check_signature(self.cert_id_1, self.expected_path_1, result.stdout)\n        self._check_signature(self.cert_id_2, self.expected_path_2, result.stdout)\n\n        # teardown: remove private key\n        Path(self._get_cwd(), FETCHAI_PRIVATE_KEY_FILE).unlink()\n        self.remove_private_key()\n        self.remove_private_key(connection=True)\n\n    def _check_signature(self, cert_id, filename, stdout):\n        \"\"\"Check signature has been generated correctly.\"\"\"\n        path = Path(self.current_agent_context, filename)\n        assert path.exists()\n        signature = path.read_text()\n\n        def is_ascii(s):\n            \"\"\"Check isascii method for all Python 3 versions\"\"\"\n            return all(ord(c) < 128 for c in s)\n\n        assert is_ascii(signature)\n        int(signature, 16)  # this will fail if not hexadecimal\n\n        cert_msg_1 = (\n            f\"Issuing certificate '{cert_id}' for connection fetchai/dummy:0.1.0...\"\n        )\n        cert_msg_3 = f\"Generated signature: '{signature}'\"\n        cert_msg_2 = f\"Dumped certificate '{cert_id}' in '{filename}' for connection fetchai/dummy:0.1.0.\"\n        assert cert_msg_1 in stdout\n        assert cert_msg_2 in stdout\n        assert cert_msg_3 in stdout\n\n\nclass TestIssueCertificatesWithOverride(TestIssueCertificatesPositive):\n    \"\"\"Test 'issue-certificates' with override configurations.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set up the class.\"\"\"\n        super().setup_class()\n\n        cls.cert_id_3 = \"cert_id_3\"\n        cls.cert_id_4 = \"cert_id_4\"\n        cls.expected_path_3 = os.path.abspath(\"path_3\")\n        cls.expected_path_4 = os.path.abspath(\"path_4\")\n        cls.cert_request_3 = CertRequest(\n            identifier=cls.cert_id_3,\n            ledger_id=EthereumCrypto.identifier,\n            not_after=\"2020-01-02\",\n            not_before=\"2020-01-01\",\n            public_key=EthereumCrypto.identifier,\n            message_format=\"{public_key}\",\n            save_path=cls.expected_path_3,\n        )\n        cls.cert_request_4 = CertRequest(\n            identifier=cls.cert_id_4,\n            ledger_id=EthereumCrypto.identifier,\n            not_after=\"2020-01-02\",\n            not_before=\"2020-01-01\",\n            public_key=\"0xABCDEF123456\",\n            message_format=\"{public_key}\",\n            save_path=cls.expected_path_4,\n        )\n\n        # Add override configurations\n        dotted_path = f\"connections.{DummyConnection.connection_id.name}.cert_requests\"\n        json_3 = json.dumps(cls.cert_request_3.json).replace(\"'\", '\"')\n        json_4 = json.dumps(cls.cert_request_4.json).replace(\"'\", '\"')\n        new_cert_requests = f\"[{json_3}, {json_4}]\"\n        cls.set_config(dotted_path, new_cert_requests, type_=\"list\")\n\n    def test_issue_certificate(self, password_or_none):\n        \"\"\"Test 'aea issue-certificates' in case of success.\"\"\"\n        # setup: add private key with password\n        ledger_id = EthereumCrypto.identifier\n        self.generate_private_key(\n            ledger_id, ETHEREUM_PRIVATE_KEY_FILE, password=password_or_none\n        )\n        self.add_private_key(\n            ledger_id, ETHEREUM_PRIVATE_KEY_FILE, password=password_or_none\n        )\n        self.add_private_key(\n            ledger_id,\n            ETHEREUM_PRIVATE_KEY_FILE,\n            connection=True,\n            password=password_or_none,\n        )\n\n        password_options = _get_password_option_args(password_or_none)\n        result = self.run_cli_command(\n            \"issue-certificates\", *password_options, cwd=self._get_cwd()\n        )\n        self._check_signature(self.cert_id_3, self.expected_path_3, result.stdout)\n        self._check_signature(self.cert_id_4, self.expected_path_4, result.stdout)\n\n        # teardown: remove private key\n        Path(self._get_cwd(), ETHEREUM_PRIVATE_KEY_FILE).unlink()\n        self.remove_private_key(ledger_id)\n        self.remove_private_key(ledger_id, connection=True)\n\n\nclass TestIssueCertificatesWrongConnectionKey(BaseTestIssueCertificates):\n    \"\"\"Test 'aea issue-certificates' when a bad connection key id is provided.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set up class.\"\"\"\n        super().setup_class()\n        cls.cert_id_1 = \"cert_id_1\"\n        cls.cert_request_1 = CertRequest(\n            identifier=cls.cert_id_1,\n            ledger_id=FetchAICrypto.identifier,\n            not_after=\"2020-01-02\",\n            not_before=\"2020-01-01\",\n            public_key=\"bad_ledger_id\",\n            message_format=\"{public_key}\",\n            save_path=\"path\",\n        )\n        cls.add_cert_requests([cls.cert_request_1], DummyConnection.connection_id.name)\n\n    def test_run(self):\n        \"\"\"Run the test.\"\"\"\n        with pytest.raises(\n            Exception,\n            match=\"Cannot find connection private key with id 'bad_ledger_id'\",\n        ):\n            self.run_cli_command(\"issue-certificates\", cwd=self._get_cwd())\n\n\nclass TestIssueCertificatesWrongCryptoKey(BaseTestIssueCertificates):\n    \"\"\"Test 'aea issue-certificates' when a bad crypto key id is provided.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set up class.\"\"\"\n        super().setup_class()\n        cls.cert_id_1 = \"cert_id_1\"\n        cls.cert_request_1 = CertRequest(\n            identifier=cls.cert_id_1,\n            ledger_id=\"bad_ledger_id\",\n            not_after=\"2020-01-02\",\n            not_before=\"2020-01-01\",\n            public_key=FetchAICrypto.identifier,\n            message_format=\"{public_key}\",\n            save_path=\"path\",\n        )\n        cls.add_cert_requests([cls.cert_request_1], DummyConnection.connection_id.name)\n        # add fetchai key and connection key\n        cls.generate_private_key()\n        cls.add_private_key()\n        cls.add_private_key(connection=True)\n\n    def test_run(self):\n        \"\"\"Run the test.\"\"\"\n        with pytest.raises(\n            Exception,\n            match=\"Cannot find private key with id 'bad_ledger_id'\",\n        ):\n            self.run_cli_command(\"issue-certificates\", cwd=self._get_cwd())\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_launch.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This test module contains the tests for the `aea launch` sub-command.\"\"\"\n\nimport logging\nimport os\nimport shutil\nimport sys\nimport tempfile\nimport unittest\nfrom contextlib import contextmanager\nfrom pathlib import Path\nfrom typing import Generator, List, Optional\n\nimport pytest\nimport yaml\nfrom aea_ledger_fetchai import FetchAICrypto\nfrom pexpect.exceptions import EOF  # type: ignore\n\nfrom aea.cli import cli\nfrom aea.configurations.base import DEFAULT_AEA_CONFIG_FILE\n\nfrom tests.common.pexpect_popen import PexpectWrapper\nfrom tests.conftest import (\n    AUTHOR,\n    CLI_LOG_OPTION,\n    CUR_PATH,\n    CliRunner,\n    MAX_FLAKY_RERUNS,\n    MAX_FLAKY_RERUNS_ETH,\n    ROOT_DIR,\n)\n\n\nlogger = logging.getLogger(__name__)\n\nDEFAULT_EXPECT_TIMEOUT = 40\n\n\nclass BaseLaunchTestCase:\n    \"\"\"Base Test case for launch tests.\"\"\"\n\n    PASSWORD: Optional[str] = None  # nosec\n\n    @contextmanager\n    def _cli_launch(\n        self, agents: List[str], options: Optional[List[str]] = None\n    ) -> Generator:\n        \"\"\"\n        Run aea.cli wrapped with Pexpect.\n\n        :param agents: list of agent names to run\n        :param options: list of string options to pass to aea launch.\n\n        :return: PexpectWrapper\n        \"\"\"\n        password_options = self.get_password_args(self.PASSWORD)\n        proc = PexpectWrapper(  # nosec\n            [\n                sys.executable,\n                \"-m\",\n                \"aea.cli\",\n                \"-v\",\n                \"DEBUG\",\n                \"launch\",\n                *password_options,\n                *(options or []),\n                *(agents or []),\n            ],\n            env=os.environ,\n            maxread=10000,\n            encoding=\"utf-8\",\n            logfile=sys.stdout,\n        )\n        try:\n            yield proc\n        finally:\n            proc.wait_to_complete(10)\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        if cls is BaseLaunchTestCase:\n            raise unittest.SkipTest(\"Skip BaseTest tests, it's a base class\")\n\n        method_list = [\n            func\n            for func in dir(cls)\n            if callable(getattr(cls, func))\n            and not func.startswith(\"__\")\n            and func.startswith(\"test_\")\n        ]\n        if len(method_list) > 1:\n            raise ValueError(f\"{cls.__name__} can only contain one test method!\")\n\n        cls.runner = CliRunner()\n        cls.agent_name_1 = \"myagent_1\"\n        cls.agent_name_2 = \"myagent_2\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        dir_path = Path(\"packages\")\n        tmp_dir = cls.t / dir_path\n        src_dir = cls.cwd / Path(ROOT_DIR, dir_path)\n        shutil.copytree(str(src_dir), str(tmp_dir))\n        os.chdir(cls.t)\n        password_option = cls.get_password_args(cls.PASSWORD)\n        result = cls.runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n        assert result.exit_code == 0\n        result = cls.runner.invoke(\n            cli, [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name_1]\n        )\n        assert result.exit_code == 0\n        os.chdir(cls.agent_name_1)\n        result = cls.runner.invoke(\n            cli,\n            [\n                *CLI_LOG_OPTION,\n                \"generate-key\",\n                FetchAICrypto.identifier,\n                *password_option,\n            ],\n        )\n        assert result.exit_code == 0\n\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"add-key\", FetchAICrypto.identifier, *password_option],\n        )\n        assert result.exit_code == 0\n        os.chdir(cls.t)\n        result = cls.runner.invoke(\n            cli, [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name_2]\n        )\n        assert result.exit_code == 0\n        os.chdir(cls.agent_name_2)\n        result = cls.runner.invoke(\n            cli,\n            [\n                *CLI_LOG_OPTION,\n                \"generate-key\",\n                FetchAICrypto.identifier,\n                *password_option,\n            ],\n        )\n        assert result.exit_code == 0\n\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"add-key\", FetchAICrypto.identifier, *password_option],\n        )\n        assert result.exit_code == 0\n        os.chdir(cls.t)\n\n    @classmethod\n    def get_password_args(cls, password: Optional[str]) -> List[str]:\n        \"\"\"Get password arguments.\"\"\"\n        return [] if password is None else [\"--password\", password]\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestLaunch(BaseLaunchTestCase):\n    \"\"\"Test that the command 'aea launch <agent_name>' works as expected.\"\"\"\n\n    @pytest.mark.flaky(reruns=MAX_FLAKY_RERUNS_ETH)\n    def test_exit_code_equal_to_zero(self):\n        \"\"\"Assert that the exit code is equal to zero (i.e. success).\"\"\"\n        with self._cli_launch([self.agent_name_1, self.agent_name_2]) as process_launch:\n            process_launch.expect_all(\n                [\n                    f\"[{self.agent_name_1}] Start processing messages...\",\n                    f\"[{self.agent_name_2}] Start processing messages...\",\n                ],\n                timeout=DEFAULT_EXPECT_TIMEOUT,\n            )\n            process_launch.control_c()\n            process_launch.expect_all(\n                [\"Exit cli. code: 0\"],\n                timeout=DEFAULT_EXPECT_TIMEOUT,\n            )\n\n\nclass TestLaunchWithPassword(TestLaunch):\n    \"\"\"Test that the command 'aea launch <agent_name> --password <password>' works as expected.\"\"\"\n\n    PASSWORD = \"fake-password\"  # nosec\n\n\nclass TestLaunchWithOneFailingAgent(BaseLaunchTestCase):\n    \"\"\"Test aea launch when there is a failing agent..\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        super().setup_class()\n        # add the exception skill to agent 2\n        os.chdir(cls.agent_name_2)\n        shutil.copytree(\n            Path(CUR_PATH, \"data\", \"exception_skill\"),\n            Path(cls.t, cls.agent_name_2, \"skills\", \"exception\"),\n        )\n        config_path = Path(cls.t, cls.agent_name_2, DEFAULT_AEA_CONFIG_FILE)\n        config = yaml.safe_load(open(config_path))\n        config.setdefault(\"skills\", []).append(\"fetchai/exception:0.1.0\")\n        yaml.safe_dump(config, open(config_path, \"w\"))\n        os.chdir(cls.t)\n\n    @pytest.mark.flaky(reruns=MAX_FLAKY_RERUNS)\n    def test_exit_code_equal_to_one(self):\n        \"\"\"Assert that the exit code is equal to one (i.e. generic failure).\"\"\"\n        with self._cli_launch([self.agent_name_1, self.agent_name_2]) as process_launch:\n            process_launch.expect_all(\n                [\n                    f\"[{self.agent_name_1}] Start processing messages...\",\n                    \"Expected exception!\",\n                    \"Receiving loop terminated\",  # cause race condition in close/interrupt agent 2, so wait it closed by exception before call ctrl+c\n                ],\n                timeout=DEFAULT_EXPECT_TIMEOUT,\n            )\n            process_launch.control_c()\n            process_launch.expect_all(\n                [\n                    f\"Agent {self.agent_name_1} terminated with exit code 0\",\n                    f\"Agent {self.agent_name_2} terminated with exit code \",\n                ],\n                timeout=DEFAULT_EXPECT_TIMEOUT,\n            )\n            process_launch.expect(\n                EOF,\n                timeout=DEFAULT_EXPECT_TIMEOUT,\n            )\n            process_launch.wait_to_complete(10)\n            assert process_launch.returncode == 1\n\n\nclass TestLaunchWithWrongArguments(BaseLaunchTestCase):\n    \"\"\"Test aea launch when some agent directory does not exist.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        super().setup_class()\n        cls.temp_agent = tempfile.mkdtemp()\n        os.chdir(cls.temp_agent)\n\n        cls.result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"launch\", \"this_agent_does_not_exist\"],\n            standalone_mode=True,\n        )\n\n    def test_exit_code_equal_to_one(self):\n        \"\"\"Assert that the exit code is equal to 1.\"\"\"\n        assert self.result.exit_code == 1\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        os.chdir(cls.t)\n        try:\n            shutil.rmtree(cls.temp_agent)\n        except (OSError, IOError):\n            pass\n        super().teardown_class()\n\n\nclass TestLaunchMultithreaded(BaseLaunchTestCase):\n    \"\"\"Test that the command 'aea launch <agent_names> --multithreaded' works as expected.\"\"\"\n\n    def test_exit_code_equal_to_zero(self):\n        \"\"\"Assert that the exit code is equal to zero (i.e. success).\"\"\"\n        with self._cli_launch(\n            [self.agent_name_1, self.agent_name_2], [\"--multithreaded\"]\n        ) as process_launch:\n            process_launch.expect_all(\n                [\n                    f\"[{self.agent_name_1}] Start processing messages\",\n                    f\"[{self.agent_name_2}] Start processing messages\",\n                ],\n                timeout=DEFAULT_EXPECT_TIMEOUT,\n            )\n            process_launch.control_c()\n            process_launch.expect_all(\n                [\"Exit cli. code: 0\"],\n                timeout=DEFAULT_EXPECT_TIMEOUT,\n            )\n\n\nclass TestLaunchOneAgent(BaseLaunchTestCase):\n    \"\"\"Test that the command 'aea launch <agent_name>' works as expected.\"\"\"\n\n    def test_exit_code_equal_to_zero(self):\n        \"\"\"Assert that the exit code is equal to zero (i.e. success).\"\"\"\n        with self._cli_launch([self.agent_name_1]) as process_launch:\n            process_launch.expect_all(\n                [f\"[{self.agent_name_1}] Start processing messages...\"],\n                timeout=DEFAULT_EXPECT_TIMEOUT,\n            )\n            process_launch.control_c()\n            process_launch.expect_all(\n                [f\"Agent {self.agent_name_1} terminated with exit code 0\"],\n                timeout=DEFAULT_EXPECT_TIMEOUT,\n            )\n            process_launch.wait_to_complete(10)\n\n            assert process_launch.returncode == 0\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_launch_end_to_end.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This test module contains the tests for the `aea launch` sub-command.\"\"\"\nimport json\nimport os\nimport sqlite3\nimport sys\nimport uuid\n\nimport pytest\nfrom aea_ledger_fetchai import FetchAICrypto\n\nfrom aea.test_tools.test_cases import AEATestCaseMany\n\nfrom tests.common.pexpect_popen import PexpectWrapper\nfrom tests.conftest import FETCHAI_PRIVATE_KEY_FILE_CONNECTION\n\n\nclass TestLaunchEndToEnd(AEATestCaseMany):\n    \"\"\"Perform aea launch end to end test.\"\"\"\n\n    key = \"seller_service\"\n    value = None\n\n    registration_agent_connection = {\n        \"delegate_uri\": \"127.0.0.1:11011\",\n        \"entry_peers\": [],\n        \"ledger_id\": \"fetchai\",\n        \"local_uri\": \"127.0.0.1:9011\",\n        \"log_file\": \"libp2p_node.log\",\n        \"public_uri\": \"127.0.0.1:9011\",\n    }\n\n    search_agent_connection = {\n        \"delegate_uri\": \"127.0.0.1:11012\",\n        \"entry_peers\": [],\n        \"ledger_id\": \"fetchai\",\n        \"local_uri\": \"127.0.0.1:9012\",\n        \"log_file\": \"libp2p_node.log\",\n        \"public_uri\": \"127.0.0.1:9012\",\n    }\n\n    @pytest.mark.integration\n    def test_end_to_end(self):\n        \"\"\"Perform end to end test with simple register/search agents.\"\"\"\n        registration_agent_name = \"registration_agent\"\n        self.value = uuid.uuid4().hex\n        self.fetch_agent(\n            \"fetchai/simple_service_registration\",\n            agent_name=registration_agent_name,\n            is_local=True,\n        )\n\n        self.run_cli_command(\n            \"config\",\n            \"set\",\n            \"vendor.fetchai.connections.p2p_libp2p.config\",\n            \"--type\",\n            \"dict\",\n            json.dumps(self.registration_agent_connection),\n            cwd=registration_agent_name,\n        )\n        self.run_cli_command(\n            \"config\",\n            \"set\",\n            \"vendor.fetchai.skills.simple_service_registration.models.strategy.args.service_data\",\n            \"--type\",\n            \"dict\",\n            json.dumps({\"key\": self.key, \"value\": self.value}),\n            cwd=registration_agent_name,\n        )\n        self.run_cli_command(\n            \"config\",\n            \"set\",\n            \"vendor.fetchai.connections.soef.config.token_storage_path\",\n            os.path.join(self.t, registration_agent_name, \"soef_key.txt\"),\n            cwd=registration_agent_name,\n        )\n\n        storage_file_name = os.path.abspath(\n            os.path.join(registration_agent_name, \"test.db\")\n        )\n        self.run_cli_command(\n            \"config\",\n            \"set\",\n            \"agent.storage_uri\",\n            f\"sqlite://{storage_file_name}\",\n            cwd=registration_agent_name,\n        )\n\n        search_agent_name = \"search_agent\"\n        self.fetch_agent(\n            \"fetchai/simple_service_search\",\n            agent_name=search_agent_name,\n            is_local=True,\n        )\n        self.run_cli_command(\n            \"config\",\n            \"set\",\n            \"vendor.fetchai.connections.p2p_libp2p.config\",\n            \"--type\",\n            \"dict\",\n            json.dumps(self.search_agent_connection),\n            cwd=search_agent_name,\n        )\n        self.run_cli_command(\n            \"config\",\n            \"set\",\n            \"vendor.fetchai.skills.simple_service_search.models.strategy.args.search_query\",\n            \"--type\",\n            \"dict\",\n            json.dumps(\n                {\n                    \"constraint_type\": \"==\",\n                    \"search_key\": self.key,\n                    \"search_value\": self.value,\n                }\n            ),\n            cwd=search_agent_name,\n        )\n        self.run_cli_command(\n            \"config\",\n            \"set\",\n            \"vendor.fetchai.skills.simple_service_search.behaviours.service_search.args.tick_interval\",\n            \"--type\",\n            \"int\",\n            \"2\",\n            cwd=search_agent_name,\n        )\n        self.run_cli_command(\n            \"config\",\n            \"set\",\n            \"vendor.fetchai.connections.soef.config.token_storage_path\",\n            os.path.join(self.t, search_agent_name, \"soef_key.txt\"),\n            cwd=search_agent_name,\n        )\n        self.run_cli_command(\n            \"build\",\n            cwd=registration_agent_name,\n        )\n        self.run_cli_command(\n            \"build\",\n            cwd=search_agent_name,\n        )\n        self.set_agent_context(registration_agent_name)\n        self.generate_private_key(\n            FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE_CONNECTION\n        )\n        self.add_private_key(\n            FetchAICrypto.identifier,\n            FETCHAI_PRIVATE_KEY_FILE_CONNECTION,\n            connection=True,\n        )\n        self.generate_private_key()\n        self.add_private_key()\n        self.unset_agent_context()\n        self.run_cli_command(\n            \"issue-certificates\",\n            cwd=registration_agent_name,\n        )\n        self.set_agent_context(search_agent_name)\n        self.generate_private_key(\n            FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE_CONNECTION\n        )\n        self.add_private_key(\n            FetchAICrypto.identifier,\n            FETCHAI_PRIVATE_KEY_FILE_CONNECTION,\n            connection=True,\n        )\n        self.generate_private_key()\n        self.add_private_key()\n        self.unset_agent_context()\n        self.run_cli_command(\n            \"issue-certificates\",\n            cwd=search_agent_name,\n        )\n\n        proc = PexpectWrapper(  # nosec\n            [\n                sys.executable,\n                \"-m\",\n                \"aea.cli\",\n                \"-v\",\n                \"DEBUG\",\n                \"launch\",\n                registration_agent_name,\n                search_agent_name,\n            ],\n            env=os.environ,\n            maxread=10000,\n            encoding=\"utf-8\",\n            logfile=sys.stdout,\n        )\n        try:\n            proc.expect_all(\n                [f\"[{search_agent_name}] found number of agents=1, search_response\"],\n                timeout=30,\n            )\n        finally:\n            proc.control_c()\n            proc.expect(\"Exit cli. code: 0\", timeout=30)\n\n        assert os.path.exists(storage_file_name)\n        con = sqlite3.connect(storage_file_name)\n        try:\n            cursor = con.cursor()\n            tables = cursor.execute(\n                \"SELECT name FROM sqlite_master WHERE type='table';\"\n            ).fetchall()\n            assert tables\n            table_name = tables[0][0]\n            num_of_records = cursor.execute(  # nosec\n                f\"SELECT count(*) FROM {table_name};\"\n            ).fetchone()[0]\n            assert num_of_records > 0\n        finally:\n            con.close\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_list.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This test module contains the tests for the `aea list` sub-command.\"\"\"\n\nimport json\nimport os\nimport shutil\nimport tempfile\nfrom pathlib import Path\nfrom unittest import TestCase, mock\n\nimport jsonschema\nimport pytest\nfrom jsonschema import Draft4Validator\n\nfrom aea.cli import cli\n\nfrom tests.conftest import (\n    AGENT_CONFIGURATION_SCHEMA,\n    CLI_LOG_OPTION,\n    CONFIGURATION_SCHEMA_DIR,\n    CUR_PATH,\n    CliRunner,\n    MAX_FLAKY_RERUNS,\n)\nfrom tests.test_aea.test_cli.constants import FORMAT_ITEMS_SAMPLE_OUTPUT\n\n\n@pytest.mark.flaky(reruns=MAX_FLAKY_RERUNS)\nclass TestListProtocols:\n    \"\"\"Test that the command 'aea list protocols' works as expected.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.schema = json.load(open(AGENT_CONFIGURATION_SCHEMA))\n        cls.resolver = jsonschema.RefResolver(\n            \"file://{}/\".format(Path(CONFIGURATION_SCHEMA_DIR).absolute()), cls.schema\n        )\n        cls.validator = Draft4Validator(cls.schema, resolver=cls.resolver)\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        # copy the 'dummy_aea' directory in the parent of the agent folder.\n        shutil.copytree(Path(CUR_PATH, \"data\", \"dummy_aea\"), Path(cls.t, \"dummy_aea\"))\n        cls.runner = CliRunner()\n        os.chdir(Path(cls.t, \"dummy_aea\"))\n\n        with mock.patch(\n            \"aea.cli.list.format_items\", return_value=FORMAT_ITEMS_SAMPLE_OUTPUT\n        ):\n            cls.result = cls.runner.invoke(\n                cli,\n                [*CLI_LOG_OPTION, \"list\", \"protocols\"],\n                standalone_mode=False,\n            )\n\n    def test_exit_code_equal_to_zero(self):\n        \"\"\"Assert that the exit code is equal to zero (i.e. success).\"\"\"\n        assert self.result.exit_code == 0\n\n    def test_correct_output(self):\n        \"\"\"Test that the command has printed the correct output.\"\"\"\n        compare_text = \"{}\\n\".format(FORMAT_ITEMS_SAMPLE_OUTPUT)\n        assert self.result.output == compare_text, self.result.output\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestListConnections:\n    \"\"\"Test that the command 'aea list connections' works as expected.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.schema = json.load(open(AGENT_CONFIGURATION_SCHEMA))\n        cls.resolver = jsonschema.RefResolver(\n            \"file://{}/\".format(Path(CONFIGURATION_SCHEMA_DIR).absolute()), cls.schema\n        )\n        cls.validator = Draft4Validator(cls.schema, resolver=cls.resolver)\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        # copy the 'dummy_aea' directory in the parent of the agent folder.\n        shutil.copytree(Path(CUR_PATH, \"data\", \"dummy_aea\"), Path(cls.t, \"dummy_aea\"))\n        cls.runner = CliRunner()\n        os.chdir(Path(cls.t, \"dummy_aea\"))\n\n        with mock.patch(\n            \"aea.cli.list.format_items\", return_value=FORMAT_ITEMS_SAMPLE_OUTPUT\n        ):\n            cls.result = cls.runner.invoke(\n                cli, [*CLI_LOG_OPTION, \"list\", \"connections\"], standalone_mode=False\n            )\n\n    def test_exit_code_equal_to_zero(self):\n        \"\"\"Assert that the exit code is equal to zero (i.e. success).\"\"\"\n        assert self.result.exit_code == 0\n\n    def test_correct_output(self):\n        \"\"\"Test that the command has printed the correct output.\"\"\"\n        compare_text = \"{}\\n\".format(FORMAT_ITEMS_SAMPLE_OUTPUT)\n        assert self.result.output == compare_text, self.result.output\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestListSkills:\n    \"\"\"Test that the command 'aea list skills' works as expected.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.schema = json.load(open(AGENT_CONFIGURATION_SCHEMA))\n        cls.resolver = jsonschema.RefResolver(\n            \"file://{}/\".format(Path(CONFIGURATION_SCHEMA_DIR).absolute()), cls.schema\n        )\n        cls.validator = Draft4Validator(cls.schema, resolver=cls.resolver)\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        # copy the 'dummy_aea' directory in the parent of the agent folder.\n        shutil.copytree(Path(CUR_PATH, \"data\", \"dummy_aea\"), Path(cls.t, \"dummy_aea\"))\n        cls.runner = CliRunner()\n        os.chdir(Path(cls.t, \"dummy_aea\"))\n\n        with mock.patch(\n            \"aea.cli.list.format_items\", return_value=FORMAT_ITEMS_SAMPLE_OUTPUT\n        ) as format_items_mock:\n            cls.result = cls.runner.invoke(\n                cli, [*CLI_LOG_OPTION, \"list\", \"skills\"], standalone_mode=False\n            )\n        format_items_mock.assert_called()\n\n    def test_exit_code_equal_to_zero(self):\n        \"\"\"Assert that the exit code is equal to zero (i.e. success).\"\"\"\n        assert self.result.exit_code == 0\n\n    def test_correct_output(self):\n        \"\"\"Test that the command has printed the correct output.\"\"\"\n        compare_text = \"{}\\n\".format(FORMAT_ITEMS_SAMPLE_OUTPUT)\n        assert self.result.output == compare_text, self.result.output\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass ListContractsCommandTestCase(TestCase):\n    \"\"\"Test that the command 'aea list contracts' works as expected.\"\"\"\n\n    def setUp(self):\n        \"\"\"Set the test up.\"\"\"\n        self.runner = CliRunner()\n        self.schema = json.load(open(AGENT_CONFIGURATION_SCHEMA))\n        self.resolver = jsonschema.RefResolver(\n            \"file://{}/\".format(Path(CONFIGURATION_SCHEMA_DIR).absolute()), self.schema\n        )\n        self.validator = Draft4Validator(self.schema, resolver=self.resolver)\n        self.cwd = os.getcwd()\n        self.t = tempfile.mkdtemp()\n        # copy the 'dummy_aea' directory in the parent of the agent folder.\n        shutil.copytree(Path(CUR_PATH, \"data\", \"dummy_aea\"), Path(self.t, \"dummy_aea\"))\n        os.chdir(Path(self.t, \"dummy_aea\"))\n\n    @mock.patch(\"aea.cli.list.list_agent_items\")\n    @mock.patch(\"aea.cli.utils.formatting.format_items\")\n    def test_list_contracts_positive(self, *mocks):\n        \"\"\"Test list contracts command positive result.\"\"\"\n        result = self.runner.invoke(\n            cli, [*CLI_LOG_OPTION, \"list\", \"contracts\"], standalone_mode=False\n        )\n        self.assertEqual(result.exit_code, 0)\n\n    def tearDown(self):\n        \"\"\"Tear the test down.\"\"\"\n        os.chdir(self.cwd)\n        try:\n            shutil.rmtree(self.t)\n        except (OSError, IOError):\n            pass\n\n\nclass ListAllCommandTestCase(TestCase):\n    \"\"\"Test case for aea list all command.\"\"\"\n\n    def setUp(self):\n        \"\"\"Set the test up.\"\"\"\n        self.runner = CliRunner()\n\n    @mock.patch(\"aea.cli.list.list_agent_items\", return_value=[])\n    @mock.patch(\"aea.cli.list.format_items\")\n    @mock.patch(\"aea.cli.utils.decorators._check_aea_project\")\n    def test_list_all_no_details_positive(self, *mocks):\n        \"\"\"Test list all command no details positive result.\"\"\"\n        result = self.runner.invoke(\n            cli, [*CLI_LOG_OPTION, \"list\", \"all\"], standalone_mode=False\n        )\n        self.assertEqual(result.exit_code, 0)\n        self.assertEqual(result.output, \"\")\n\n    @mock.patch(\"aea.cli.list.list_agent_items\", return_value=[{\"name\": \"some\"}])\n    @mock.patch(\"aea.cli.list.format_items\", return_value=\"correct\")\n    @mock.patch(\"aea.cli.utils.decorators._check_aea_project\")\n    def test_list_all_positive(self, *mocks):\n        \"\"\"Test list all command positive result.\"\"\"\n        result = self.runner.invoke(\n            cli, [*CLI_LOG_OPTION, \"list\", \"all\"], standalone_mode=False\n        )\n        self.assertEqual(result.exit_code, 0)\n        self.assertEqual(\n            result.output,\n            \"Connections:\\ncorrect\\nContracts:\\ncorrect\\n\"\n            \"Protocols:\\ncorrect\\nSkills:\\ncorrect\\n\",\n        )\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_local_registry_update.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This test module contains the tests for the `aea local-registry-sync\"\"\"\nimport os\nfrom tempfile import TemporaryDirectory\nfrom unittest.mock import patch\n\nfrom aea.cli.core import cli\nfrom aea.cli.local_registry_sync import enlist_packages\nfrom aea.cli.registry.add import fetch_package\nfrom aea.configurations.data_types import PackageId, PackageType, PublicId\nfrom aea.helpers.base import cd\nfrom aea.test_tools.click_testing import CliRunner\n\n\ndef test_local_registry_update():\n    \"\"\"Test local-registry-sync cli command.\"\"\"\n    PACKAGES = [\n        PackageId(PackageType.CONNECTION, PublicId(\"fetchai\", \"local\", \"0.17.0\")),\n        PackageId(PackageType.AGENT, PublicId(\"fetchai\", \"my_first_aea\", \"0.24.0\")),\n    ]\n    with TemporaryDirectory() as tmp_dir:\n        for package_id in PACKAGES:\n            package_dir = os.path.join(\n                tmp_dir,\n                package_id.public_id.author,\n                str(package_id.package_type.to_plural()),\n                package_id.public_id.name,\n            )\n            os.makedirs(package_dir)\n            fetch_package(\n                str(package_id.package_type),\n                public_id=package_id.public_id,\n                cwd=tmp_dir,\n                dest=package_dir,\n            )\n\n        assert set(PACKAGES) == set([i[0] for i in enlist_packages(tmp_dir)])\n\n        runner = CliRunner()\n        with cd(tmp_dir):\n            # check intention to upgrade\n            with patch(\n                \"aea.cli.local_registry_sync.replace_package\"\n            ) as replace_package_mock:\n                result = runner.invoke(\n                    cli, [\"-s\", \"local-registry-sync\"], catch_exceptions=False\n                )\n                assert result.exit_code == 0, result.stdout\n            assert replace_package_mock.call_count == 2\n\n            # do actual upgrade\n            result = runner.invoke(\n                cli, [\"-s\", \"local-registry-sync\"], catch_exceptions=False\n            )\n            assert result.exit_code == 0, result.stdout\n\n            # check next update will do nothing\n            with patch(\n                \"aea.cli.local_registry_sync.replace_package\"\n            ) as replace_package_mock:\n                result = runner.invoke(\n                    cli, [\"-s\", \"local-registry-sync\"], catch_exceptions=False\n                )\n                assert result.exit_code == 0, result.stdout\n            assert replace_package_mock.call_count == 0\n\n        def sort_(packages):\n            return sorted(packages, key=lambda x: str(x))\n\n        new_packages = [i[0] for i in enlist_packages(tmp_dir)]\n\n        for new_package, old_package in zip(sort_(new_packages), sort_(PACKAGES)):\n            assert new_package.public_id != old_package.public_id\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_loggers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This test module contains the tests for commands in aea.cli.utils.loggers module.\"\"\"\n\nfrom unittest import TestCase, mock\n\nfrom aea.cli.utils.loggers import ColorFormatter\n\n\nclass ColorFormatterTestCase(TestCase):\n    \"\"\"Test case for ColorFormatter class.\"\"\"\n\n    def test_format_positive(self):\n        \"\"\"Test for format method positive result.\"\"\"\n        record = mock.Mock()\n        record.exc_info = None\n        record.levelname = \"DEBUG\"\n        record.getMessage = mock.Mock(return_value=\"Message\")\n        color_formatter = ColorFormatter()\n        color_formatter.format(record)\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_login.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This test module contains the tests for CLI login command.\"\"\"\n\nfrom unittest import TestCase, mock\n\nfrom aea.cli import cli\n\nfrom tests.conftest import CLI_LOG_OPTION, CliRunner\n\n\n@mock.patch(\"aea.cli.login.registry_login\", return_value=\"token\")\n@mock.patch(\"aea.cli.login.update_cli_config\")\nclass LoginTestCase(TestCase):\n    \"\"\"Test case for CLI login command.\"\"\"\n\n    def setUp(self):\n        \"\"\"Set it up.\"\"\"\n        self.runner = CliRunner()\n\n    def test_login_positive(self, update_cli_config_mock, registry_login_mock):\n        \"\"\"Test for CLI login positive result.\"\"\"\n        username, password = (\"Username\", \"Password\")\n        result = self.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"login\", username, \"--password={}\".format(password)],\n            standalone_mode=False,\n        )\n        expected_output = (\n            \"Signing in as Username...\\n\" \"Successfully signed in: Username.\\n\"\n        )\n        self.assertEqual(result.output, expected_output)\n        registry_login_mock.assert_called_once_with(username, password)\n        update_cli_config_mock.assert_called_once_with({\"auth_token\": \"token\"})\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_logout.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This test module contains the tests for CLI logout command.\"\"\"\n\nfrom unittest import TestCase, mock\n\nfrom aea.cli import cli\n\nfrom tests.conftest import CLI_LOG_OPTION, CliRunner\n\n\n@mock.patch(\"aea.cli.logout.registry_logout\")\n@mock.patch(\"aea.cli.logout.update_cli_config\")\nclass LogoutTestCase(TestCase):\n    \"\"\"Test case for CLI logout command.\"\"\"\n\n    def setUp(self):\n        \"\"\"Set it up.\"\"\"\n        self.runner = CliRunner()\n\n    def test_logout_positive(self, update_cli_config_mock, registry_logout_mock):\n        \"\"\"Test for CLI logout positive result.\"\"\"\n        result = self.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"logout\"],\n            standalone_mode=False,\n        )\n        self.assertEqual(result.exit_code, 0)\n        registry_logout_mock.assert_called_once()\n        update_cli_config_mock.assert_called_once()\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_misc.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This test module contains the tests for the `aea` sub-commands.\"\"\"\n\nimport aea\nfrom aea.cli import cli\n\nfrom tests.conftest import CliRunner\n\n\ndef test_no_argument():\n    \"\"\"Test that if we run the cli tool without arguments, it exits gracefully.\"\"\"\n    runner = CliRunner()\n    result = runner.invoke(cli, [])\n    assert result.exit_code == 0\n\n\ndef test_flag_version():\n    \"\"\"Test that the flag '--version' works correctly.\"\"\"\n    runner = CliRunner()\n    result = runner.invoke(cli, [\"--version\"])\n    assert result.stdout == \"aea, version {}\\n\".format(aea.__version__)\n\n\ndef test_flag_help():\n    \"\"\"Test that the flag '--help' works correctly.\"\"\"\n    runner = CliRunner()\n    result = runner.invoke(cli, [\"--help\"])\n    assert (\n        result.stdout\n        == \"\"\"Usage: aea [OPTIONS] COMMAND [ARGS]...\n\n  Command-line tool for setting up an Autonomous Economic Agent (AEA).\n\nOptions:\n  --version                     Show the version and exit.\n  -v, --verbosity LVL           One of NOTSET, DEBUG, INFO, WARNING, ERROR,\n                                CRITICAL, OFF\n  -s, --skip-consistency-check  Skip consistency checks of agent during command\n                                execution.\n  --registry-path DIRECTORY     Provide a local registry directory full path.\n  --help                        Show this message and exit.\n\nCommands:\n  add                  Add a package to the agent.\n  add-key              Add a private key to the wallet of the agent.\n  build                Build the agent and its components.\n  config               Read or modify a configuration of the agent.\n  create               Create a new agent.\n  delete               Delete an agent.\n  eject                Eject a vendor package of the agent.\n  fetch                Fetch an agent from the registry.\n  fingerprint          Fingerprint a non-vendor package of the agent.\n  freeze               Get the dependencies of the agent.\n  generate             Generate a package for the agent.\n  generate-key         Generate a private key and place it in a file.\n  generate-wealth      Generate wealth for the agent on a test network.\n  get-address          Get the address associated with a private key of the...\n  get-multiaddress     Get the multiaddress associated with a private key...\n  get-public-key       Get the public key associated with a private key of...\n  get-wealth           Get the wealth associated with the private key of...\n  init                 Initialize your AEA configurations.\n  install              Install the dependencies of the agent.\n  interact             Interact with the running agent via the stub...\n  ipfs                 IPFS Commands\n  issue-certificates   Issue certificates for connections that require them.\n  launch               Launch many agents at the same time.\n  list                 List the installed packages of the agent.\n  local-registry-sync  Upgrade the local package registry.\n  login                Login to the registry account.\n  logout               Logout from the registry account.\n  publish              Publish the agent to the registry.\n  push                 Push a non-vendor package of the agent to the registry.\n  register             Create a new registry account.\n  remove               Remove a package from the agent.\n  remove-key           Remove a private key from the wallet of the agent.\n  reset_password       Reset the password of the registry account.\n  run                  Run the agent.\n  scaffold             Scaffold a package for the agent.\n  search               Search for packages in the registry.\n  transfer             Transfer wealth associated with a private key of the...\n  upgrade              Upgrade the packages of the agent.\n\"\"\"\n    )\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_plugin.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Test the CLI plugin mechanism.\"\"\"\nimport inspect\nfrom pathlib import Path\n\nimport click\nimport pytest\nfrom pkg_resources import Distribution, EntryPoint, iter_entry_points, working_set\n\n# Create a few CLI commands for testing\nfrom aea.cli.plugin import with_plugins\nfrom aea.test_tools.click_testing import CliRunner\n\nfrom tests.conftest import ROOT_DIR\n\n\n# We need to compute the right dotted path w.r.t. the current module location.\n# Instead of hard-coding it, we compute it on-the-fly.\n_PATH_TO_THIS_MODULE = (\n    Path(inspect.getfile(inspect.currentframe()))  # type: ignore\n    .absolute()\n    .relative_to(Path(ROOT_DIR).resolve())\n)\n_DOTTED_PATH = \".\".join(_PATH_TO_THIS_MODULE.with_suffix(\"\").parts)\n\n\n@pytest.fixture(scope=\"function\")\ndef runner(request):\n    \"\"\"Get a click.CliRunner instance.\"\"\"\n    return CliRunner()\n\n\n@click.command()\n@click.argument(\"arg\")\ndef cmd1(arg):\n    \"\"\"Test command 1\"\"\"\n    click.echo(\"passed\")\n\n\n@click.command()\n@click.argument(\"arg\")\ndef cmd2(arg):\n    \"\"\"Test command 2\"\"\"\n    click.echo(\"passed\")\n\n\nclass DistStub(Distribution):\n    \"\"\"\n    Manually register plugins in an entry point and put broken plugins in a different entry point.\n\n    The `DistStub()` class gets around an exception that is raised when\n    `entry_point.load()` is called.  By default `load()` has `requires=True`\n    which calls `dist.requires()` and the `click.group()` decorator\n    doesn't allow us to change this.  Because we are manually registering these\n    plugins the `dist` attribute is `None` so we can just create a stub that\n    always returns an empty list since we don't have any requirements.  A full\n    `pkg_resources.Distribution()` instance is not needed because there isn't\n    a package installed anywhere.\n    \"\"\"\n\n    def requires(self, *args):\n        \"\"\"Implement a dummy 'requires' function.\"\"\"\n        return []\n\n\nworking_set.by_key[\"click\"]._ep_map = {  # type: ignore\n    \"_test_click_plugins.test_plugins\": {\n        \"cmd1\": EntryPoint.parse(f\"cmd1={_DOTTED_PATH}:cmd1\", dist=DistStub()),\n        \"cmd2\": EntryPoint.parse(f\"cmd2={_DOTTED_PATH}:cmd2\", dist=DistStub()),\n    },\n    \"_test_click_plugins.broken_plugins\": {\n        \"before\": EntryPoint.parse(\n            \"before=tests.broken_plugins:before\", dist=DistStub()\n        ),\n        \"after\": EntryPoint.parse(\"after=tests.broken_plugins:after\", dist=DistStub()),\n        \"do_not_exist\": EntryPoint.parse(\n            \"do_not_exist=tests.broken_plugins:do_not_exist\", dist=DistStub()\n        ),\n    },\n}\n\n\n# Main CLI groups - one with good plugins attached and the other broken\n@with_plugins(iter_entry_points(\"_test_click_plugins.test_plugins\"))\n@click.group()\ndef good_cli():\n    \"\"\"Good CLI group.\"\"\"\n    pass\n\n\n@with_plugins(iter_entry_points(\"_test_click_plugins.broken_plugins\"))\n@click.group()\ndef broken_cli():\n    \"\"\"Broken CLI group.\"\"\"\n    pass\n\n\ndef test_registered():\n    \"\"\"\n    Make sure the plugins are properly registered.\n\n    If this test fails it means that some of the for loops in other tests may not be executing.\n    \"\"\"\n    assert len([ep for ep in iter_entry_points(\"_test_click_plugins.test_plugins\")]) > 1\n    assert (\n        len([ep for ep in iter_entry_points(\"_test_click_plugins.broken_plugins\")]) > 1\n    )\n\n\ndef test_register_and_run(runner):\n    \"\"\"Test that registration and run of the command work correctly.\"\"\"\n\n    result = runner.invoke(good_cli)\n    assert result.exit_code == 0\n\n    for ep in iter_entry_points(\"_test_click_plugins.test_plugins\"):\n        cmd_result = runner.invoke(good_cli, [ep.name, \"something\"])\n        assert cmd_result.exit_code == 0\n        assert cmd_result.output.strip() == \"passed\"\n\n\ndef test_broken_register_and_run(runner):\n    \"\"\"Test that the broken plugin doesn't get registered as expected.\"\"\"\n    result = runner.invoke(broken_cli)\n    assert result.exit_code == 0\n\n    for ep in iter_entry_points(\"_test_click_plugins.broken_plugins\"):\n        cmd_result = runner.invoke(broken_cli, [ep.name])\n        assert cmd_result.exit_code != 0\n        assert \"Traceback\" in cmd_result.output\n\n\ndef test_group_chain(runner):\n    \"\"\"Test the plugin with nested CLI command group levels.\"\"\"\n\n    # Attach a sub-group to a CLI and get execute it without arguments to make\n    # sure both the sub-group and all the parent group's commands are present\n    @good_cli.group()\n    def sub_cli():\n        \"\"\"Sub CLI.\"\"\"\n        pass\n\n    result = runner.invoke(good_cli)\n    assert result.exit_code == 0\n    assert sub_cli.name in result.output\n    for ep in iter_entry_points(\"_test_click_plugins.test_plugins\"):\n        assert ep.name in result.output\n\n    # Same as above but the sub-group has plugins\n    @with_plugins(plugins=iter_entry_points(\"_test_click_plugins.test_plugins\"))\n    @good_cli.group(name=\"sub-cli-plugins\")\n    def sub_cli_plugins():\n        \"\"\"Sub CLI with plugins.\"\"\"\n        pass\n\n    result = runner.invoke(good_cli, [\"sub-cli-plugins\"])\n    assert result.exit_code == 0\n    for ep in iter_entry_points(\"_test_click_plugins.test_plugins\"):\n        assert ep.name in result.output\n\n    print(result.output)\n\n    # Execute one of the sub-group's commands\n    result = runner.invoke(good_cli, [\"sub-cli-plugins\", \"cmd1\", \"something\"])\n    assert result.exit_code == 0\n    assert result.output.strip() == \"passed\"\n\n\ndef test_exception():\n    \"\"\"Test the 'with_plugins' decorator when it gets used on a non-click.Group object.\"\"\"\n\n    # Decorating something that isn't a click.Group() should fail\n    with pytest.raises(TypeError):\n\n        @with_plugins([])\n        @click.command()\n        def cli():\n            \"\"\"Whatever\"\"\"\n\n\ndef test_broken_register_and_run_with_help(runner):\n    \"\"\"Test the broken registration of the plugin when the command is run with the '--help' flag.\"\"\"\n    result = runner.invoke(broken_cli)\n    assert result.exit_code == 0\n\n    for ep in iter_entry_points(\"_test_click_plugins.broken_plugins\"):\n        cmd_result = runner.invoke(broken_cli, [ep.name, \"--help\"])\n        assert cmd_result.exit_code != 0\n        assert \"Traceback\" in cmd_result.output\n\n\ndef test_broken_register_and_run_with_args(runner):\n    \"\"\"Test the broken registration of the plugin when the command is run with the '--help' flag.\"\"\"\n    result = runner.invoke(broken_cli)\n    assert result.exit_code == 0\n\n    for ep in iter_entry_points(\"_test_click_plugins.broken_plugins\"):\n        cmd_result = runner.invoke(broken_cli, [ep.name, \"-a\", \"b\"])\n        assert cmd_result.exit_code != 0\n        assert \"Traceback\" in cmd_result.output\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_publish.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Test module for Registry publish methods.\"\"\"\nfrom pathlib import Path\nfrom shutil import rmtree\nfrom unittest import TestCase, mock\n\nimport click\nimport pytest\nfrom click import ClickException\n\nfrom aea.cli import cli\nfrom aea.cli.publish import (\n    LocalRegistry,\n    MixedRegistry,\n    RemoteRegistry,\n    _save_agent_locally,\n    _validate_pkp,\n)\nfrom aea.configurations.base import PublicId\nfrom aea.test_tools.test_cases import AEATestCaseEmpty\n\nfrom packages.fetchai.skills.echo import PUBLIC_ID as ECHO_SKILL_PUBLIC_ID\n\nfrom tests.conftest import CLI_LOG_OPTION, CliRunner\nfrom tests.test_aea.test_cli.tools_for_testing import (\n    ContextMock,\n    PublicIdMock,\n    raise_click_exception,\n)\n\n\n@mock.patch(\"aea.cli.publish.PublicId\", PublicIdMock)\n@mock.patch(\"aea.cli.publish.LocalRegistry.check_item_present\")\n@mock.patch(\"aea.cli.publish.copyfile\")\n@mock.patch(\"aea.cli.publish.os.makedirs\")\n@mock.patch(\"aea.cli.publish.os.path.exists\", return_value=False)\n@mock.patch(\"aea.cli.publish.try_get_item_target_path\", return_value=\"target-dir\")\n@mock.patch(\"aea.cli.publish.os.path.join\", return_value=\"joined-path\")\nclass SaveAgentLocallyTestCase(TestCase):\n    \"\"\"Test case for _save_agent_locally method.\"\"\"\n\n    def test_save_agent_locally_positive(\n        self,\n        path_join_mock,\n        try_get_item_target_path_mock,\n        path_exists_mock,\n        makedirs_mock,\n        copyfile_mock,\n        _check_is_item_in_local_registry_mock,\n    ):\n        \"\"\"Test for save_agent_locally positive result.\"\"\"\n        _save_agent_locally(\n            ContextMock(\n                connections=[\"author/default_connection:version\", \"author/name:version\"]\n            )\n        )\n        makedirs_mock.assert_called_once_with(\"target-dir\", exist_ok=True)\n        copyfile_mock.assert_called_once_with(\"joined-path\", \"joined-path\")\n\n\nclass CheckIsItemInLocalRegistryTestCase(TestCase):\n    \"\"\"Test case for _check_is_item_in_local_registry method.\"\"\"\n\n    @mock.patch(\"aea.cli.publish.try_get_item_source_path\")\n    def test__check_is_item_in_local_registry_positive(self, get_path_mock):\n        \"\"\"Test for _check_is_item_in_local_registry positive result.\"\"\"\n        public_id = PublicIdMock.from_str(\"author/name:version\")\n        item_type_plural = \"items\"\n        ctx = mock.Mock()\n        ctx.registry_path = \"some-registry-path\"\n        LocalRegistry(ctx).check_item_present(item_type_plural, public_id)\n        get_path_mock.assert_called_once_with(\n            ctx.registry_path, public_id.author, item_type_plural, public_id.name\n        )\n\n    @mock.patch(\"aea.cli.publish.try_get_item_source_path\", raise_click_exception)\n    def test__check_is_item_in_local_registry_negative(self):\n        \"\"\"Test for _check_is_item_in_local_registry negative result.\"\"\"\n        public_id = PublicIdMock.from_str(\"author/name:version\")\n        item_type_plural = \"items\"\n        with self.assertRaises(ClickException):\n            ctx = mock.Mock()\n            ctx.registry_path = \"some-registry-path\"\n            LocalRegistry(ctx).check_item_present(item_type_plural, public_id)\n\n\n@mock.patch(\"aea.cli.utils.decorators._check_aea_project\")\n@mock.patch(\"aea.cli.publish._save_agent_locally\")\n@mock.patch(\"aea.cli.publish.publish_agent\")\n@mock.patch(\"aea.cli.publish._validate_pkp\")\n@mock.patch(\"aea.cli.publish._validate_config\")\n@mock.patch(\"aea.cli.publish.cast\", return_value=ContextMock())\nclass PublishCommandTestCase(TestCase):\n    \"\"\"Test case for CLI publish command.\"\"\"\n\n    def setUp(self):\n        \"\"\"Set it up.\"\"\"\n        self.runner = CliRunner()\n\n    def test_publish_positive(self, *mocks):\n        \"\"\"Test for CLI publish positive result.\"\"\"\n        result = self.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"publish\", \"--local\"],\n            standalone_mode=False,\n        )\n        self.assertEqual(result.exit_code, 0)\n        result = self.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"publish\", \"--remote\"],\n            standalone_mode=False,\n        )\n        self.assertEqual(result.exit_code, 0)\n        result = self.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"publish\"],\n            standalone_mode=False,\n        )\n        self.assertEqual(result.exit_code, 0)\n\n\nclass ValidatePkpTestCase(TestCase):\n    \"\"\"Test case for _validate_pkp method.\"\"\"\n\n    def test__validate_pkp_positive(self):\n        \"\"\"Test _validate_pkp for positive result.\"\"\"\n        private_key_paths = mock.Mock()\n        private_key_paths.read_all = mock.Mock(return_value=[])\n        _validate_pkp(private_key_paths)\n        private_key_paths.read_all.assert_called_once()\n\n    def test__validate_pkp_negative(self):\n        \"\"\"Test _validate_pkp for negative result.\"\"\"\n        private_key_paths = mock.Mock()\n        private_key_paths.read_all = mock.Mock(return_value=[1, 2])\n        with self.assertRaises(ClickException):\n            _validate_pkp(private_key_paths)\n        private_key_paths.read_all.assert_called_once()\n\n\n@mock.patch(\"aea.cli.publish.MixedRegistry.check_item_present\")\nclass TestPublishMixedMode(AEATestCaseEmpty):\n    \"\"\"Test the execution branch with in mixed mode.\"\"\"\n\n    def test_publish_positive(self, *mocks):\n        \"\"\"Test for CLI publish positive result.\"\"\"\n        self.set_config(\"agent.description\", \"some-description\")\n        self.run_cli_command(\"publish\", cwd=self._get_cwd())\n\n\ndef test_negative_check_is_item_in_remote_registry():\n    \"\"\"Test the utility function (negative) to check if an item is in the remote registry\"\"\"\n    with pytest.raises(click.ClickException, match=\"Not found in Registry.\"):\n        RemoteRegistry(mock.Mock()).check_item_present(\n            \"protocols\",\n            PublicId(\"nonexisting_package_author\", \"nonexisting_package_name\", \"0.0.0\"),\n        )\n\n\ndef test_negative_check_is_item_in_registry_mixed():\n    \"\"\"Check if item in registry, mixed mode.\"\"\"\n    ctx = mock.Mock()\n    ctx.registry_path = \"some-registry-path\"\n\n    with pytest.raises(\n        click.ClickException,\n        match=\"Can not find dependency locally or remotely: .*. Try to add flag `--push-missing` to push dependency package to the registry.\",\n    ):\n        MixedRegistry(ctx).check_item_present(\n            \"protocols\", PublicId.from_str(\"bad_author/bad_package_name:0.8.0\")\n        )\n\n\ndef test_positive_check_is_item_in_registry_mixed_not_locally_but_remotely():\n    \"\"\"Check if item in registry, mixed mode, when not in local registry but only in remote.\"\"\"\n    ctx = mock.Mock()\n    ctx.registry_path = \"some-registry-path\"\n    MixedRegistry(ctx).check_item_present(\n        \"protocols\", PublicId.from_str(\"fetchai/default:0.8.0\")\n    )\n\n\nclass TestPublishLocallyWithDeps(AEATestCaseEmpty):\n    \"\"\"Test case for cli publish --local --push-missing.\"\"\"\n\n    ITEM_PUBLIC_ID = ECHO_SKILL_PUBLIC_ID\n    ITEM_TYPE = \"skill\"\n\n    NEW_ITEM_TYPE = \"skill\"\n    NEW_ITEM_NAME = \"my_test_skill\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set up test case.\"\"\"\n        super(TestPublishLocallyWithDeps, cls).setup_class()\n        cls.add_item(cls.ITEM_TYPE, str(cls.ITEM_PUBLIC_ID), local=True)\n        cls.scaffold_item(cls.NEW_ITEM_TYPE, cls.NEW_ITEM_NAME)\n\n    def test_publish_ok_with_missing_push(\n        self,\n    ):\n        \"\"\"Test ok for missing push.\"\"\"\n        with pytest.raises(ClickException, match=r\"Dependency is missing\") as e:\n            self.invoke(\"publish\", \"--local\")\n        assert \"use --push-missing\" in str(e)\n\n        self.invoke(\"publish\", \"--local\", \"--push-missing\")\n\n        # remove agents published and publish again\n        packages_dir = self.t / self.packages_dir_path  # type: ignore\n        rmtree(Path(packages_dir) / self.author / \"agents\")\n        self.invoke(\"publish\", \"--local\")\n\n\n@mock.patch(\"aea.cli.publish._push_item_remote\")\n@mock.patch(\"aea.cli.publish.publish_agent\")\nclass TestPublishRemotellyWithDeps(AEATestCaseEmpty):\n    \"\"\"Test case for cli publish --push-missing.\"\"\"\n\n    ITEM_PUBLIC_ID = ECHO_SKILL_PUBLIC_ID\n    ITEM_TYPE = \"skill\"\n\n    NEW_ITEM_TYPE = \"skill\"\n    NEW_ITEM_NAME = \"my_test_skill\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set up test case.\"\"\"\n        super(TestPublishRemotellyWithDeps, cls).setup_class()\n        cls.add_item(cls.ITEM_TYPE, str(cls.ITEM_PUBLIC_ID), local=True)\n        cls.scaffold_item(cls.NEW_ITEM_TYPE, cls.NEW_ITEM_NAME)\n\n    def test_publish_ok_with_missing_push(\n        self, publish_agent_mock, push_item_remote_mock\n    ):\n        \"\"\"Test ok for missing push.\"\"\"\n        with pytest.raises(\n            ClickException, match=r\"Package not found in remote registry\"\n        ) as e, mock.patch(\n            \"aea.cli.publish.get_package_meta\",\n            side_effect=ClickException(\"expected\"),\n        ):\n            self.invoke(\"publish\", \"--remote\")\n        assert \"--push-missing\" in str(e)\n        publish_agent_mock.assert_not_called()\n\n        with mock.patch(\n            \"aea.cli.publish.get_package_meta\",\n            side_effect=[ClickException(\"expected\")] + [mock.DEFAULT] * 100,\n        ):\n            self.invoke(\"publish\", \"--remote\", \"--push-missing\")\n\n        push_item_remote_mock.assert_called()\n        publish_agent_mock.assert_called()\n\n\nclass CheckAndPublishCommandTestCase(TestCase):\n    \"\"\"Test case for Registry.check_item_present_and_push method.\"\"\"\n\n    def test_publish_not_present_positive(self, *mocks):\n        \"\"\"Test for publish positive result.\"\"\"\n        ctx = mock.Mock()\n        registry = LocalRegistry(ctx)\n        with mock.patch(\n            \"aea.cli.publish.LocalRegistry.check_item_present\",\n            side_effect=[ClickException(\"expected\"), None],\n        ), mock.patch(\"aea.cli.publish.LocalRegistry.push_item\") as push_item_mock:\n            registry.check_item_present_and_push(\"connections\", mock.Mock())\n\n        push_item_mock.assert_called_once()\n\n    def test_publish_not_present_failed_to_push(self, *mocks):\n        \"\"\"Test for publish failed.\"\"\"\n        ctx = mock.Mock()\n        registry = LocalRegistry(ctx)\n        with mock.patch(\n            \"aea.cli.publish.LocalRegistry.check_item_present\",\n            side_effect=[ClickException(\"expected\"), None],\n        ), mock.patch(\n            \"aea.cli.publish.LocalRegistry.push_item\", side_effect=Exception(\"expected\")\n        ):\n            with pytest.raises(\n                ClickException, match=\"Failed to push missing item.*expected\"\n            ):\n                registry.check_item_present_and_push(\"connections\", mock.Mock())\n\n    def test_publish_not_present_failed_to_check(self, *mocks):\n        \"\"\"Test for publish failed lookup after push.\"\"\"\n        ctx = mock.Mock()\n        registry = LocalRegistry(ctx)\n        with mock.patch(\n            \"aea.cli.publish.LocalRegistry.check_item_present\",\n            side_effect=ClickException(\"expected\"),\n        ), mock.patch(\"aea.cli.publish.LocalRegistry.push_item\") as push_item_mock:\n            with pytest.raises(\n                ClickException, match=\"Failed to find item after push:.*expected\"\n            ):\n                registry.check_item_present_and_push(\"connections\", mock.Mock())\n\n        push_item_mock.assert_called_once()\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_push.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Test module for Registry push methods.\"\"\"\nimport filecmp\nimport os\nfrom unittest import TestCase, mock\n\nimport pytest\nfrom click import ClickException\n\nfrom aea.cli import cli\nfrom aea.cli.push import _save_item_locally, check_package_public_id\nfrom aea.cli.utils.constants import ITEM_TYPES\nfrom aea.configurations.base import PublicId\nfrom aea.test_tools.constants import DEFAULT_AUTHOR\nfrom aea.test_tools.test_cases import AEATestCaseEmpty\n\nfrom packages.fetchai.skills.echo import PUBLIC_ID\n\nfrom tests.conftest import AUTHOR, CLI_LOG_OPTION, CliRunner\nfrom tests.test_aea.test_cli.tools_for_testing import ContextMock, PublicIdMock\n\n\n@mock.patch(\"aea.cli.push.copytree\")\nclass SaveItemLocallyTestCase(TestCase):\n    \"\"\"Test case for save_item_locally method.\"\"\"\n\n    @mock.patch(\"aea.cli.push.try_get_item_target_path\", return_value=\"target\")\n    @mock.patch(\"aea.cli.push.try_get_item_source_path\", return_value=\"source\")\n    @mock.patch(\"aea.cli.push.check_package_public_id\", return_value=None)\n    def test_save_item_locally_positive(\n        self,\n        _check_package_public_id_mock,\n        try_get_item_source_path_mock,\n        try_get_item_target_path_mock,\n        copy_tree_mock,\n    ):\n        \"\"\"Test for save_item_locally positive result.\"\"\"\n        item_type = \"skill\"\n        item_id = PublicIdMock()\n        ctx_mock = ContextMock()\n        _save_item_locally(ctx_mock, item_type, item_id)\n        try_get_item_source_path_mock.assert_called_once_with(\n            \"cwd\", None, \"skills\", item_id.name\n        )\n        try_get_item_target_path_mock.assert_called_once_with(\n            ctx_mock.registry_path,\n            item_id.author,\n            item_type + \"s\",\n            item_id.name,\n        )\n        _check_package_public_id_mock.assert_called_once_with(\n            \"source\", item_type, item_id\n        )\n        copy_tree_mock.assert_called_once_with(\"source\", \"target\")\n\n\n@mock.patch(\"aea.cli.push.copytree\")\nclass TestPushLocally(AEATestCaseEmpty):\n    \"\"\"Test case for cli push --local.\"\"\"\n\n    ITEM_PUBLIC_ID = PUBLIC_ID\n    ITEM_TYPE = \"skill\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set up test case.\"\"\"\n        super(TestPushLocally, cls).setup_class()\n        cls.add_item(cls.ITEM_TYPE, str(cls.ITEM_PUBLIC_ID), local=True)\n\n    def test_vendor_ok(\n        self,\n        copy_tree_mock,\n    ):\n        \"\"\"Test ok for vendor's item.\"\"\"\n        with mock.patch(\n            \"aea.cli.utils.package_utils.is_path_exist\",\n            side_effect=[False, True, False],\n        ):\n            self.invoke(\"push\", \"--local\", \"skill\", \"fetchai/echo\")\n        copy_tree_mock.assert_called_once()\n        src_path, dst_path = copy_tree_mock.mock_calls[0][1]\n        # check for correct author, type, name\n        assert (\n            os.path.normpath(src_path).split(os.sep)[-3:]\n            == os.path.normpath(dst_path).split(os.sep)[-3:]\n        )\n\n    def test_user_ok(\n        self,\n        copy_tree_mock,\n    ):\n        \"\"\"Test ok for users's item.\"\"\"\n        with mock.patch(\n            \"aea.cli.push.try_get_item_source_path\",\n            return_value=f\"{self.author}/skills/echo\",\n        ), mock.patch(\"aea.cli.push.check_package_public_id\"):\n            self.invoke(\"push\", \"--local\", \"skill\", f\"{self.author}/echo\")\n        copy_tree_mock.assert_called_once()\n        src_path, dst_path = copy_tree_mock.mock_calls[0][1]\n        # check for correct author, type, name\n        assert (\n            os.path.normpath(src_path).split(os.sep)[-3:]\n            == os.path.normpath(dst_path).split(os.sep)[-3:]\n        )\n\n    def test_fail_no_item(\n        self,\n        *mocks,\n    ):\n        \"\"\"Test fail, item_not_exists .\"\"\"\n        expected_path_pattern = \".*\" + \".*\".join(\n            [\"vendor\", \"fetchai\", \"skills\", \"not_exists\"]\n        )\n        with pytest.raises(\n            ClickException,\n            match=rf'Item \"fetchai/not_exists\" not found in source folder \"{expected_path_pattern}\"\\.',\n        ):\n            self.invoke(\"push\", \"--local\", \"skill\", \"fetchai/not_exists\")\n\n\n@mock.patch(\n    \"aea.cli.registry.push.load_yaml\",\n    return_value={\"author\": AUTHOR, \"name\": \"name\", \"version\": \"0.1.0\"},\n)\nclass CheckPackagePublicIdTestCase(TestCase):\n    \"\"\"Test case for _check_package_public_id method.\"\"\"\n\n    def test__check_package_public_id_positive(self, *mocks):\n        \"\"\"Test for _check_package_public_id positive result.\"\"\"\n        check_package_public_id(\n            \"source-path\",\n            \"item-type\",\n            PublicId.from_str(f\"{AUTHOR}/name:0.1.0\"),\n        )\n\n    def test__check_package_public_id_negative(self, *mocks):\n        \"\"\"Test for _check_package_public_id negative result.\"\"\"\n        with self.assertRaises(ClickException):\n            check_package_public_id(\n                \"source-path\",\n                \"item-type\",\n                PublicId.from_str(f\"{AUTHOR}/name:0.1.1\"),\n            )\n\n\nclass TestPushLocalFailsArgumentNotPublicId:\n    \"\"\"Test the case when we try a local push with a non public id.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the tests up.\"\"\"\n        cls.runner = CliRunner()\n        cls.result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"push\", \"--local\", \"connection\", \"oef\"],\n            standalone_mode=False,\n        )\n\n    def test_exit_code_1(self):\n        \"\"\"Test the exit code is 1 (SystemExit).\"\"\"\n        assert self.result.exit_code == 1\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the tests down.\"\"\"\n\n\n@mock.patch(\"aea.cli.utils.config.try_to_load_agent_config\")\n@mock.patch(\"aea.cli.push._save_item_locally\")\n@mock.patch(\"aea.cli.push.push_item\")\n@mock.patch(\"aea.cli.utils.decorators._check_aea_project\")\nclass PushCommandTestCase(TestCase):\n    \"\"\"Test case for CLI push command.\"\"\"\n\n    def setUp(self):\n        \"\"\"Set it up.\"\"\"\n        self.runner = CliRunner()\n\n    def test_push_connection_positive(self, *mocks):\n        \"\"\"Test for CLI push connection positive result.\"\"\"\n        result = self.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"push\", \"connection\", \"author/name:0.1.0\"],\n            standalone_mode=False,\n        )\n        self.assertEqual(result.exit_code, 0)\n        result = self.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"push\", \"--local\", \"connection\", \"author/name:0.1.0\"],\n            standalone_mode=False,\n        )\n        self.assertEqual(result.exit_code, 0)\n\n    def test_push_protocol_positive(self, *mocks):\n        \"\"\"Test for CLI push protocol positive result.\"\"\"\n        result = self.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"push\", \"protocol\", \"author/name:0.1.0\"],\n            standalone_mode=False,\n        )\n        self.assertEqual(result.exit_code, 0)\n        result = self.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"push\", \"--local\", \"protocol\", \"author/name:0.1.0\"],\n            standalone_mode=False,\n        )\n        self.assertEqual(result.exit_code, 0)\n\n    def test_push_skill_positive(self, *mocks):\n        \"\"\"Test for CLI push skill positive result.\"\"\"\n        result = self.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"push\", \"skill\", \"author/name:0.1.0\"],\n            standalone_mode=False,\n        )\n        self.assertEqual(result.exit_code, 0)\n        result = self.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"push\", \"--local\", \"skill\", \"author/name:0.1.0\"],\n            standalone_mode=False,\n        )\n        self.assertEqual(result.exit_code, 0)\n\n\n@mock.patch(\"aea.cli.utils.decorators.try_to_load_agent_config\")\nclass PushContractCommandTestCase(TestCase):\n    \"\"\"Test that the command 'aea push contract' works as expected.\"\"\"\n\n    def setUp(self):\n        \"\"\"Set the test up.\"\"\"\n        self.runner = CliRunner()\n\n    @mock.patch(\"aea.cli.push._save_item_locally\")\n    def test_push_contract_positive(self, *mocks):\n        \"\"\"Test push contract command positive result.\"\"\"\n        result = self.runner.invoke(\n            cli,\n            [\n                *CLI_LOG_OPTION,\n                \"--skip-consistency-check\",\n                \"push\",\n                \"--local\",\n                \"contract\",\n                \"author/name:0.1.0\",\n            ],\n            standalone_mode=False,\n        )\n        self.assertEqual(result.exit_code, 0)\n\n    @mock.patch(\"aea.cli.push.push_item\")\n    def test_push_contract_registry_positive(self, *mocks):\n        \"\"\"Test push contract to registry command positive result.\"\"\"\n        result = self.runner.invoke(\n            cli,\n            [\n                *CLI_LOG_OPTION,\n                \"--skip-consistency-check\",\n                \"push\",\n                \"contract\",\n                \"author/name:0.1.0\",\n            ],\n            standalone_mode=False,\n        )\n        self.assertEqual(result.exit_code, 0)\n\n\nclass TestPushLocallyWithLatest(AEATestCaseEmpty):\n    \"\"\"Test push locally with 'latest' as version.\"\"\"\n\n    @pytest.mark.parametrize(\"component_type\", ITEM_TYPES)\n    def test_command(self, component_type):\n        \"\"\"Run the test.\"\"\"\n        item_name = f\"my_{component_type}\"\n        version = \":latest\"\n        self.scaffold_item(component_type, item_name)\n        self.run_cli_command(\n            \"push\",\n            \"--local\",\n            component_type,\n            f\"{self.author}/{item_name}{version}\",\n            cwd=self._get_cwd(),\n        )\n\n        component_type_plural = component_type + \"s\"\n        path_to_pushed_package = (\n            self.packages_dir_path / DEFAULT_AUTHOR / component_type_plural / item_name\n        )\n        path_to_current_package = (\n            self.t / self.agent_name / component_type_plural / item_name\n        )\n        assert path_to_pushed_package.exists()\n        comparison = filecmp.dircmp(path_to_pushed_package, path_to_current_package)\n        assert comparison.diff_files == []\n\n\n@mock.patch(\"aea.cli.utils.config.try_to_load_agent_config\")\n@mock.patch(\"aea.cli.utils.decorators._check_aea_project\")\n@mock.patch(\"os.path.exists\")\nclass TestPushVersionsMismatch(TestCase):\n    \"\"\"Test that the command 'aea push contract' works as expected.\"\"\"\n\n    def setUp(self):\n        \"\"\"Set the test up.\"\"\"\n        self.runner = CliRunner()\n\n    def test_push_local_version_check_failed(self, *mocks):\n        \"\"\"Test push contract command positive result.\"\"\"\n        with mock.patch(\n            \"aea.cli.registry.push.load_component_public_id\",\n            return_value=PublicId(\"author\", \"name\", \"1000.0.0\"),\n        ):\n            with pytest.raises(\n                ClickException, match=\"Version, name or author does not match.\"\n            ):\n                self.runner.invoke(\n                    cli,\n                    [\n                        *CLI_LOG_OPTION,\n                        \"push\",\n                        \"--local\",\n                        \"contract\",\n                        \"author/name:0.1.0\",\n                    ],\n                    standalone_mode=False,\n                    catch_exceptions=False,\n                )\n\n    def test_push_remote_version_check_failed(self, *mocks):\n        \"\"\"Test push contract command positive result.\"\"\"\n        with mock.patch(\n            \"aea.cli.registry.push.load_component_public_id\",\n            return_value=PublicId(\"author\", \"name\", \"1000.0.0\"),\n        ):\n            with pytest.raises(\n                ClickException, match=\"Version, name or author does not match.\"\n            ):\n                self.runner.invoke(\n                    cli,\n                    [*CLI_LOG_OPTION, \"push\", \"contract\", \"author/name:0.1.0\"],\n                    standalone_mode=False,\n                    catch_exceptions=False,\n                )\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_register.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This test module contains the tests for CLI register command.\"\"\"\n\nfrom unittest import TestCase, mock\n\nfrom aea.cli import cli\nfrom aea.cli.register import do_register\nfrom aea.cli.registry.settings import AUTH_TOKEN_KEY\n\nfrom tests.conftest import CLI_LOG_OPTION, CliRunner\n\n\n@mock.patch(\"aea.cli.register.do_register\")\nclass RegisterTestCase(TestCase):\n    \"\"\"Test case for CLI register command.\"\"\"\n\n    def setUp(self):\n        \"\"\"Set it up.\"\"\"\n        self.runner = CliRunner()\n\n    def test_register_positive(self, do_register_mock):\n        \"\"\"Test for CLI register positive result.\"\"\"\n        username = \"username\"\n        email = \"email@example.com\"\n        fake_pwd = \"fake_pwd\"  # nosec\n\n        result = self.runner.invoke(\n            cli,\n            [\n                *CLI_LOG_OPTION,\n                \"register\",\n                \"--username={}\".format(username),\n                \"--email={}\".format(email),\n                \"--password={}\".format(fake_pwd),\n                \"--confirm_password={}\".format(fake_pwd),\n                \"--no-subscribe\",\n            ],\n            standalone_mode=False,\n        )\n        self.assertEqual(result.exit_code, 0)\n        do_register_mock.assert_called_once_with(\n            username, email, fake_pwd, fake_pwd, True\n        )\n\n\n@mock.patch(\"aea.cli.register.validate_author_name\", lambda x: x)\n@mock.patch(\"aea.cli.register.register_new_account\", return_value=\"token\")\n@mock.patch(\"aea.cli.register.click.echo\")\n@mock.patch(\"aea.cli.register.click.confirm\", return_value=True)\n@mock.patch(\"aea.cli.register.update_cli_config\")\nclass DoRegisterTestCase(TestCase):\n    \"\"\"Test case for do_register method.\"\"\"\n\n    def test_do_register_positive(\n        self, update_cli_config_mock, confirm_mock, echo_mock, *mocks\n    ):\n        \"\"\"Test for do_register method positive result.\"\"\"\n        username = \"username\"\n        email = \"email@example.com\"\n        fake_pwd = \"fake_pwd\"  # nosec\n        no_subscribe = False\n\n        do_register(username, email, fake_pwd, fake_pwd, no_subscribe)\n        update_cli_config_mock.assert_called_once_with({AUTH_TOKEN_KEY: \"token\"})\n        confirm_mock.assert_called_once()\n\n    def test_do_register_no_subscribe_true_positive(\n        self, update_cli_config_mock, confirm_mock, echo_mock, *mocks\n    ):\n        \"\"\"Test for do_register method no_subscribe flag = True positive result.\"\"\"\n        username = \"username\"\n        email = \"email@example.com\"\n        fake_pwd = \"fake_pwd\"  # nosec\n        no_subscribe = True\n\n        do_register(username, email, fake_pwd, fake_pwd, no_subscribe)\n        update_cli_config_mock.assert_called_once_with({AUTH_TOKEN_KEY: \"token\"})\n        confirm_mock.assert_not_called()\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_registry/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This test package contains the tests for Registry operating tools.\"\"\"\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_registry/test_add.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This test module contains tests for CLI Registry add methods.\"\"\"\n\nimport os\nfrom unittest import TestCase, mock\n\nfrom aea.cli.registry.add import fetch_package\nfrom aea.configurations.base import PublicId\n\n\n@mock.patch(\"aea.cli.registry.utils.request_api\", return_value={\"file\": \"url\"})\n@mock.patch(\"aea.cli.registry.add.download_file\", return_value=\"filepath\")\n@mock.patch(\"aea.cli.registry.add.extract\")\nclass FetchPackageTestCase(TestCase):\n    \"\"\"Test case for fetch_package method.\"\"\"\n\n    def test_fetch_package_positive(\n        self, extract_mock, download_file_mock, request_api_mock\n    ):\n        \"\"\"Test for fetch_package method positive result.\"\"\"\n        obj_type = \"connection\"\n        public_id = PublicId.from_str(\"author/name:0.1.0\")\n        cwd = \"cwd\"\n        dest_path = os.path.join(\"dest\", \"path\", \"package_folder_name\")\n\n        fetch_package(obj_type, public_id, cwd, dest_path)\n        request_api_mock.assert_called_with(\n            \"GET\", \"/connections/author/name/0.1.0\", params=None\n        )\n        download_file_mock.assert_called_once_with(\"url\", \"cwd\")\n        extract_mock.assert_called_once_with(\"filepath\", os.path.join(\"dest\", \"path\"))\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_registry/test_fetch.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This test module contains the tests for CLI Registry fetch methods.\"\"\"\n\nimport os\nimport shutil\nimport tempfile\nfrom unittest import TestCase, mock\n\nfrom click import ClickException\n\nfrom aea.cli.registry.fetch import fetch_agent\n\nfrom tests.test_aea.test_cli.tools_for_testing import ContextMock, PublicIdMock\n\n\ndef _raise_exception():\n    raise Exception()\n\n\n@mock.patch(\"aea.cli.registry.fetch.open_file\", mock.mock_open())\n@mock.patch(\"aea.cli.utils.decorators._cast_ctx\")\n@mock.patch(\"aea.cli.registry.fetch.PublicId\", PublicIdMock)\n@mock.patch(\"aea.cli.registry.fetch.os.rename\")\n@mock.patch(\"aea.cli.registry.fetch.os.makedirs\")\n@mock.patch(\"aea.cli.registry.fetch.try_to_load_agent_config\")\n@mock.patch(\"aea.cli.registry.fetch.download_file\", return_value=\"filepath\")\n@mock.patch(\"aea.cli.registry.fetch.extract\")\nclass TestFetchAgent(TestCase):\n    \"\"\"Test case for fetch_package method.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set up the test class.\"\"\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        os.chdir(cls.t)\n\n    @mock.patch(\n        \"aea.cli.registry.fetch.request_api\",\n        return_value={\n            \"file\": \"url\",\n            \"connections\": [],\n            \"contracts\": [],\n            \"protocols\": [],\n            \"skills\": [],\n        },\n    )\n    def test_fetch_agent_positive(\n        self, request_api_mock, extract_mock, download_file_mock, *mocks\n    ):\n        \"\"\"Test for fetch_agent method positive result.\"\"\"\n        public_id_mock = PublicIdMock()\n        fetch_agent(ContextMock(), public_id_mock, alias=\"alias\")\n        request_api_mock.assert_called_with(\n            \"GET\",\n            \"/agents/{}/{}/{}\".format(\n                public_id_mock.author, public_id_mock.name, public_id_mock.version\n            ),\n        )\n        download_file_mock.assert_called_once_with(\"url\", \"cwd\")\n        extract_mock.assert_called_once_with(\"filepath\", \"cwd\")\n\n    @mock.patch(\"aea.cli.registry.fetch.add_item\")\n    @mock.patch(\n        \"aea.cli.registry.fetch.request_api\",\n        return_value={\n            \"file\": \"url\",\n            \"connections\": [\"public/id:{}\".format(PublicIdMock.DEFAULT_VERSION)],\n            \"contracts\": [\"public/id:{}\".format(PublicIdMock.DEFAULT_VERSION)],\n            \"protocols\": [\"public/id:{}\".format(PublicIdMock.DEFAULT_VERSION)],\n            \"skills\": [\"public/id:{}\".format(PublicIdMock.DEFAULT_VERSION)],\n        },\n    )\n    def test_fetch_agent_with_dependencies_positive(\n        self, request_api_mock, add_item_mock, extract_mock, download_file_mock, *mocks\n    ):\n        \"\"\"Test for fetch_agent method with dependencies positive result.\"\"\"\n        public_id_mock = PublicIdMock()\n        ctx_mock = ContextMock(\n            connections=[\"public/id:{}\".format(PublicIdMock.DEFAULT_VERSION)]\n        )\n        fetch_agent(ctx_mock, public_id_mock)\n        request_api_mock.assert_called_with(\n            \"GET\",\n            \"/agents/{}/{}/{}\".format(\n                public_id_mock.author, public_id_mock.name, public_id_mock.version\n            ),\n        )\n        download_file_mock.assert_called_once_with(\"url\", \"cwd\")\n        extract_mock.assert_called_once_with(\"filepath\", \"cwd\")\n        add_item_mock.assert_called()\n\n    @mock.patch(\"aea.cli.registry.fetch.add_item\", _raise_exception)\n    @mock.patch(\n        \"aea.cli.registry.fetch.request_api\",\n        return_value={\n            \"file\": \"url\",\n            \"connections\": [\"public/id:{}\".format(PublicIdMock.DEFAULT_VERSION)],\n            \"contracts\": [],\n            \"protocols\": [],\n            \"skills\": [],\n        },\n    )\n    def test_fetch_agent_with_dependencies_unable_to_fetch(self, *mocks):\n        \"\"\"Test for fetch_agent method unable to fetch.\"\"\"\n        ctx_mock = ContextMock(\n            connections=[\"public/id:{}\".format(PublicIdMock.DEFAULT_VERSION)]\n        )\n        with self.assertRaises(ClickException):\n            fetch_agent(ctx_mock, PublicIdMock())\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Teardowm the test.\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_registry/test_login.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This test module contains tests for CLI Registry login methods.\"\"\"\n\nfrom unittest import TestCase, mock\n\nfrom aea.cli.registry.login import registry_login, registry_reset_password\n\n\n@mock.patch(\"aea.cli.registry.login.request_api\", return_value={\"key\": \"key\"})\nclass RegistryLoginTestCase(TestCase):\n    \"\"\"Test case for registry_login method.\"\"\"\n\n    def test_registry_login_positive(self, request_api_mock):\n        \"\"\"Test for registry_login method positive result.\"\"\"\n        result = registry_login(\"username\", \"password\")\n        expected_result = \"key\"\n        self.assertEqual(result, expected_result)\n        request_api_mock.assert_called_once()\n\n\n@mock.patch(\n    \"aea.cli.registry.login.request_api\", return_value={\"message\": \"Email was sent.\"}\n)\nclass RegistryResetPasswordTestCase(TestCase):\n    \"\"\"Test case for registry_reset_password method.\"\"\"\n\n    def test_registry_reset_password_positive(self, request_api_mock):\n        \"\"\"Test for registry_reset_password method positive result.\"\"\"\n        registry_reset_password(\"email@example.com\")\n        request_api_mock.assert_called_once()\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_registry/test_logout.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This test module contains tests for CLI Registry logout methods.\"\"\"\n\nfrom unittest import TestCase, mock\n\nfrom aea.cli.registry.logout import registry_logout\n\n\n@mock.patch(\"aea.cli.registry.logout.request_api\")\nclass RegistryLogoutTestCase(TestCase):\n    \"\"\"Test case for registry_logout method.\"\"\"\n\n    def test_registry_logout_positive(self, request_api_mock):\n        \"\"\"Test for registry_logout method positive result.\"\"\"\n        registry_logout()\n        request_api_mock.assert_called_once()\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_registry/test_publish.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Test module for Registry publish methods.\"\"\"\nfrom pathlib import Path\nfrom unittest import TestCase, mock\nfrom unittest.mock import mock_open\n\nfrom aea.cli.registry.publish import _compress, publish_agent\nfrom aea.test_tools.test_cases import AEATestCase\n\nfrom tests.conftest import CUR_PATH\nfrom tests.test_aea.test_cli.tools_for_testing import ContextMock\n\n\n@mock.patch(\"builtins.open\", mock_open(read_data=\"test\"))\n@mock.patch(\"aea.cli.registry.publish.shutil.copy\")\n@mock.patch(\"aea.cli.registry.publish.try_to_load_agent_config\")\n@mock.patch(\"aea.cli.registry.publish.check_is_author_logged_in\")\n@mock.patch(\"aea.cli.registry.utils._rm_tarfiles\")\n@mock.patch(\"aea.cli.registry.publish.os.getcwd\", return_value=\"cwd\")\n@mock.patch(\"aea.cli.registry.publish._compress\")\n@mock.patch(\n    \"aea.cli.registry.publish.request_api\", return_value={\"public_id\": \"public-id\"}\n)\nclass PublishAgentTestCase(TestCase):\n    \"\"\"Test case for publish_agent method.\"\"\"\n\n    @mock.patch(\"aea.cli.registry.publish.is_readme_present\", return_value=True)\n    def test_publish_agent_positive(\n        self, is_readme_present_mock, request_api_mock, *mocks\n    ):\n        \"\"\"Test for publish_agent positive result.\"\"\"\n        description = \"Some description.\"\n        version = \"0.1.0\"\n        context_mock = ContextMock(description=description, version=version)\n        publish_agent(context_mock)\n        request_api_mock.assert_called_once_with(\n            \"POST\",\n            \"/agents/create\",\n            data={\n                \"name\": \"agent_name\",\n                \"description\": description,\n                \"version\": version,\n                \"connections\": [],\n                \"contracts\": [],\n                \"protocols\": [],\n                \"skills\": [],\n            },\n            is_auth=True,\n            files={\"file\": mock.ANY, \"readme\": mock.ANY},\n        )\n\n    @mock.patch(\"aea.cli.registry.publish.is_readme_present\", return_value=False)\n    def test_publish_agent_without_readme_positive(\n        self, is_readme_present_mock, request_api_mock, *mocks\n    ):\n        \"\"\"Test for publish_agent without readme positive result.\"\"\"\n        description = \"Some description.\"\n        version = \"0.1.0\"\n        context_mock = ContextMock(description=description, version=version)\n        publish_agent(context_mock)\n        request_api_mock.assert_called_once_with(\n            \"POST\",\n            \"/agents/create\",\n            data={\n                \"name\": \"agent_name\",\n                \"description\": description,\n                \"version\": version,\n                \"connections\": [],\n                \"contracts\": [],\n                \"protocols\": [],\n                \"skills\": [],\n            },\n            is_auth=True,\n            files={\"file\": mock.ANY},\n        )\n\n\n@mock.patch(\"aea.cli.registry.publish.tarfile\")\nclass CompressTestCase(TestCase):\n    \"\"\"Test case for _compress method.\"\"\"\n\n    def test__compress_positive(self, tarfile_mock):\n        \"\"\"Test for _compress positive result.\"\"\"\n        tar_obj_mock = mock.MagicMock()\n        open_mock = mock.MagicMock(return_value=tar_obj_mock)\n        tarfile_mock.open = open_mock\n\n        _compress(\"output_filename\", \"file1\", \"file2\")\n        open_mock.assert_called_once_with(\"output_filename\", \"w:gz\")\n\n\n@mock.patch(\"aea.cli.registry.publish.request_api\", side_effect=ValueError(\"expected\"))\nclass PublishAgentCleanupOnFailTestCase(AEATestCase):\n    \"\"\"Test case for publish_agent method.\"\"\"\n\n    path_to_aea = Path(CUR_PATH) / \"data\" / \"dummy_aea\"\n\n    def test_publish_agent_fails(self, *mocks):\n        \"\"\"Test for publish_agent positive result.\"\"\"\n        description = \"Some description.\"\n        version = \"0.1.0\"\n        context_mock = ContextMock(description=description, version=version)\n        context_mock.cwd = \".\"\n        publish_agent(context_mock)\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_registry/test_push.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Test module for Registry push methods.\"\"\"\nimport os\nfrom unittest import TestCase, mock\nfrom unittest.mock import mock_open, patch\n\nimport pytest\nfrom click import ClickException\n\nfrom aea.cli.registry.push import (\n    _compress_dir,\n    _remove_pycache,\n    check_package_public_id,\n    push_item,\n)\nfrom aea.configurations.base import PublicId\n\nfrom tests.test_aea.test_cli.tools_for_testing import ContextMock, PublicIdMock\n\n\n@mock.patch(\"builtins.open\", mock_open(read_data=\"opened_file\"))\n@mock.patch(\"aea.cli.registry.push.check_is_author_logged_in\")\n@mock.patch(\"aea.cli.registry.push.list_missing_packages\", return_value=[])\n@mock.patch(\"aea.cli.registry.utils._rm_tarfiles\")\n@mock.patch(\"aea.cli.registry.push.os.getcwd\", return_value=\"cwd\")\n@mock.patch(\"aea.cli.registry.push._compress_dir\")\n@mock.patch(\n    \"aea.cli.registry.push.load_yaml\",\n    return_value={\n        \"description\": \"some-description\",\n        \"version\": PublicIdMock.DEFAULT_VERSION,\n        \"author\": \"some_author\",\n        \"name\": \"some_name\",\n        \"protocols\": [\"some/protocol:0.1.2\"],\n    },\n)\n@mock.patch(\n    \"aea.cli.registry.push.request_api\", return_value={\"public_id\": \"public-id\"}\n)\nclass PushItemTestCase(TestCase):\n    \"\"\"Test case for push_item method.\"\"\"\n\n    @mock.patch(\"aea.cli.registry.push.os.path.exists\", return_value=True)\n    @mock.patch(\"aea.cli.registry.push.is_readme_present\", return_value=True)\n    def test_push_item_positive(\n        self,\n        is_readme_present_mock,\n        path_exists_mock,\n        request_api_mock,\n        load_yaml_mock,\n        compress_mock,\n        getcwd_mock,\n        rm_tarfiles_mock,\n        check_is_author_logged_in_mock,\n        *_,\n    ):\n        \"\"\"Test for push_item positive result.\"\"\"\n        public_id = PublicIdMock(\n            name=\"some_name\",\n            author=\"some_author\",\n            version=\"{}\".format(PublicIdMock.DEFAULT_VERSION),\n        )\n        push_item(ContextMock(), \"some-type\", public_id)\n        request_api_mock.assert_called_once_with(\n            \"POST\",\n            \"/some-types/create\",\n            data={\n                \"name\": \"some_name\",\n                \"description\": \"some-description\",\n                \"version\": PublicIdMock.DEFAULT_VERSION,\n                \"protocols\": [\"some/protocol:0.1.2\"],\n            },\n            is_auth=True,\n            files={\"file\": open(\"file.1\"), \"readme\": open(\"file.2\")},\n        )\n\n    @mock.patch(\"aea.cli.registry.push.os.path.exists\", return_value=True)\n    @mock.patch(\"aea.cli.registry.push.is_readme_present\", return_value=True)\n    def test_push_dependency_fail(\n        self,\n        is_readme_present_mock,\n        path_exists_mock,\n        request_api_mock,\n        load_yaml_mock,\n        compress_mock,\n        getcwd_mock,\n        rm_tarfiles_mock,\n        check_is_author_logged_in_mock,\n        *_,\n    ):\n        \"\"\"Test for push_item fails cause dependencies check.\"\"\"\n        public_id = PublicIdMock(\n            name=\"some_name\",\n            author=\"some_author\",\n            version=\"{}\".format(PublicIdMock.DEFAULT_VERSION),\n        )\n\n        with patch(\n            \"aea.cli.registry.push.list_missing_packages\",\n            return_value=[(\"some\", PublicId.from_str(\"some/pack:0.1.0\"))],\n        ):\n            with pytest.raises(\n                ClickException, match=\"Found missing dependencies! Push canceled!\"\n            ):\n                push_item(ContextMock(), \"some-type\", public_id)\n\n    @mock.patch(\"aea.cli.registry.push.os.path.exists\", return_value=True)\n    @mock.patch(\"aea.cli.registry.push.is_readme_present\", return_value=False)\n    def test_push_item_positive_without_readme(\n        self, is_readme_present_mock, path_exists_mock, request_api_mock, *mocks\n    ):\n        \"\"\"Test for push_item without readme positive result.\"\"\"\n        public_id = PublicIdMock(\n            name=\"some_name\",\n            author=\"some_author\",\n            version=\"{}\".format(PublicIdMock.DEFAULT_VERSION),\n        )\n        push_item(ContextMock(), \"some-type\", public_id)\n        request_api_mock.assert_called_once_with(\n            \"POST\",\n            \"/some-types/create\",\n            data={\n                \"name\": \"some_name\",\n                \"description\": \"some-description\",\n                \"version\": PublicIdMock.DEFAULT_VERSION,\n                \"protocols\": [\"some/protocol:0.1.2\"],\n            },\n            is_auth=True,\n            files={\"file\": open(\"opened_file\", \"r\")},\n        )\n\n    @mock.patch(\"aea.cli.registry.push.os.path.exists\", return_value=False)\n    def test_push_item_item_not_found(\n        self,\n        path_exists_mock,\n        request_api_mock,\n        load_yaml_mock,\n        compress_mock,\n        getcwd_mock,\n        rm_tarfiles_mock,\n        check_is_author_logged_in_mock,\n        *_,\n    ):\n        \"\"\"Test for push_item - item not found.\"\"\"\n        with self.assertRaises(ClickException):\n            push_item(ContextMock(), \"some-type\", PublicIdMock())\n\n        request_api_mock.assert_not_called()\n\n\n@mock.patch(\"aea.cli.registry.push.shutil.rmtree\")\nclass RemovePycacheTestCase(TestCase):\n    \"\"\"Test case for _remove_pycache method.\"\"\"\n\n    @mock.patch(\"aea.cli.registry.push.os.path.exists\", return_value=True)\n    def test_remove_pycache_positive(self, path_exists_mock, rmtree_mock):\n        \"\"\"Test for _remove_pycache positive result.\"\"\"\n        source_dir = \"somedir\"\n        pycache_path = os.path.join(source_dir, \"__pycache__\")\n\n        _remove_pycache(source_dir)\n        rmtree_mock.assert_called_once_with(pycache_path)\n\n    @mock.patch(\"aea.cli.registry.push.os.path.exists\", return_value=False)\n    def test_remove_pycache_no_pycache(self, path_exists_mock, rmtree_mock):\n        \"\"\"Test for _remove_pycache if there's no pycache.\"\"\"\n        source_dir = \"somedir\"\n        _remove_pycache(source_dir)\n        rmtree_mock.assert_not_called()\n\n\n@mock.patch(\"aea.cli.registry.push.tarfile\")\n@mock.patch(\"aea.cli.registry.push._remove_pycache\")\nclass CompressDirTestCase(TestCase):\n    \"\"\"Test case for _compress_dir method.\"\"\"\n\n    def test__compress_dir_positive(self, _remove_pycache_mock, tarfile_mock):\n        \"\"\"Test for _compress_dir positive result.\"\"\"\n        tar_obj_mock = mock.MagicMock()\n        open_mock = mock.MagicMock(return_value=tar_obj_mock)\n        tarfile_mock.open = open_mock\n\n        _compress_dir(\"output_filename\", \"source_dir\")\n        _remove_pycache_mock.assert_called_once_with(\"source_dir\")\n        open_mock.assert_called_once_with(\"output_filename\", \"w:gz\")\n\n\ndef test_check_package_public_id():\n    \"\"\"Test check_package_public_id.\"\"\"\n    public_id = PublicId(\"test\", \"test\", \"10.0.1\")\n\n    with mock.patch(\n        \"aea.cli.registry.push.load_component_public_id\", return_value=public_id\n    ):\n        check_package_public_id(mock.Mock(), mock.Mock(), public_id)\n\n    with mock.patch(\n        \"aea.cli.registry.push.load_component_public_id\", return_value=public_id\n    ):\n        with pytest.raises(\n            ClickException, match=\"Version, name or author does not match\"\n        ):\n            check_package_public_id(\n                mock.Mock(), mock.Mock(), PublicId(\"test\", \"test\", \"10.0.2\")\n            )\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_registry/test_registration.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Test module for Registry registration methods.\"\"\"\n\nfrom unittest import TestCase, mock\n\nfrom click import ClickException\n\nfrom aea.cli.registry.registration import register\n\n\nclass RegistrationTestCase(TestCase):\n    \"\"\"Test case for Registry registration methods.\"\"\"\n\n    @mock.patch(\n        \"aea.cli.registry.registration.request_api\",\n        return_value=({\"key\": \"token\"}, 201),\n    )\n    def test_register_positive(self, *mocks):\n        \"\"\"Test register method positive result.\"\"\"\n        username, email, password = (\"username\", \"email\", \"password\")\n        result = register(username, email, password, password)\n        expected_result = \"token\"\n        self.assertEqual(result, expected_result)\n\n    @mock.patch(\n        \"aea.cli.registry.registration.request_api\",\n        return_value=({\"username\": \"Already exists\"}, 400),\n    )\n    def test_register_negative(self, *mocks):\n        \"\"\"Test register method negative result.\"\"\"\n        username, email, password = (\"bad-username\", \"email\", \"password\")\n        with self.assertRaises(ClickException):\n            register(username, email, password, password)\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_registry/test_utils.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This test module contains tests for CLI Registry utils.\"\"\"\n\nimport os\nimport tempfile\nfrom json.decoder import JSONDecodeError\nfrom pathlib import Path\nfrom unittest import TestCase, mock\nfrom unittest.mock import MagicMock, patch\n\nimport pytest\nfrom click import ClickException\nfrom requests.exceptions import ConnectionError\n\nfrom aea.cli.registry.settings import AUTH_TOKEN_KEY, REGISTRY_API_URL\nfrom aea.cli.registry.utils import (\n    FILE_DOWNLOAD_TIMEOUT,\n    _rm_tarfiles,\n    check_is_author_logged_in,\n    clean_tarfiles,\n    download_file,\n    extract,\n    get_latest_public_id_mixed,\n    get_latest_version_available_in_registry,\n    get_package_meta,\n    is_auth_token_present,\n    list_missing_packages,\n    request_api,\n)\nfrom aea.cli.utils.exceptions import AEAConfigException\nfrom aea.configurations.base import PublicId\nfrom aea.helpers.base import cd\n\nfrom packages.fetchai.protocols.default import DefaultMessage\n\n\ndef _raise_connection_error(*args, **kwargs):\n    raise ConnectionError()\n\n\ndef _raise_config_exception(*args):\n    raise AEAConfigException()\n\n\ndef _raise_json_decode_error(*args):\n    raise JSONDecodeError(None, \"None\", 1)  # args requied for JSONDecodeError raising\n\n\n@mock.patch(\"aea.cli.registry.utils.requests.request\")\nclass RequestAPITestCase(TestCase):\n    \"\"\"Test case for request_api method.\"\"\"\n\n    def test_request_api_positive(self, request_mock):\n        \"\"\"Test for request_api method positive result.\"\"\"\n        expected_result = {\"correct\": \"json\"}\n\n        resp_mock = mock.Mock()\n        resp_mock.json = lambda: expected_result\n        resp_mock.status_code = 200\n        request_mock.return_value = resp_mock\n\n        result = request_api(\"GET\", \"/path\")\n        request_mock.assert_called_once_with(\n            method=\"GET\",\n            params=None,\n            data=None,\n            files=None,\n            headers={},\n            url=REGISTRY_API_URL + \"/path\",\n        )\n        self.assertEqual(result, expected_result)\n\n        result = request_api(\"GET\", \"/path\", return_code=True)\n        self.assertEqual(result, (expected_result, 200))\n\n    def test_request_api_404(self, request_mock):\n        \"\"\"Test for request_api method 404 server response.\"\"\"\n        resp_mock = mock.Mock()\n        resp_mock.status_code = 404\n        request_mock.return_value = resp_mock\n        with self.assertRaises(ClickException):\n            request_api(\"GET\", \"/path\")\n\n    def test_request_api_500(self, request_mock):\n        \"\"\"Test for request_api method 500 server response.\"\"\"\n        resp_mock = mock.Mock()\n        resp_mock.status_code = 500\n        resp_mock.json.return_value = {\"detail\": \"test\"}\n        request_mock.return_value = resp_mock\n        with self.assertRaises(ClickException):\n            request_api(\"GET\", \"/path\")\n\n    def test_request_api_201(self, request_mock):\n        \"\"\"Test for request_api method 201 server response.\"\"\"\n        expected_result = {\"correct\": \"json\"}\n\n        resp_mock = mock.Mock()\n        resp_mock.json = lambda: expected_result\n        resp_mock.status_code = 201\n        request_mock.return_value = resp_mock\n        result = request_api(\"GET\", \"/path\")\n        self.assertEqual(result, expected_result)\n\n    def test_request_api_403(self, request_mock):\n        \"\"\"Test for request_api method notauthorized server response.\"\"\"\n        resp_mock = mock.Mock()\n        resp_mock.status_code = 403\n        request_mock.return_value = resp_mock\n        with self.assertRaises(ClickException):\n            request_api(\"GET\", \"/path\")\n\n    def test_request_api_400(self, request_mock):\n        \"\"\"Test for request_api method 400 code server response.\"\"\"\n        resp_mock = mock.Mock()\n        resp_mock.status_code = 400\n        request_mock.return_value = resp_mock\n        with self.assertRaises(ClickException):\n            request_api(\"GET\", \"/path\")\n\n    def test_request_api_409(self, request_mock):\n        \"\"\"Test for request_api method conflict server response.\"\"\"\n        resp_mock = mock.Mock()\n        resp_mock.status_code = 409\n        resp_mock.json = lambda: {\"detail\": \"some\"}\n        request_mock.return_value = resp_mock\n        with self.assertRaises(ClickException):\n            request_api(\"GET\", \"/path\")\n\n    def test_request_api_unexpected_response(self, request_mock):\n        \"\"\"Test for request_api method unexpected server response.\"\"\"\n        resp_mock = mock.Mock()\n        status_code = 501\n        resp_mock.status_code = status_code  # not implemented status\n        resp_mock.json = _raise_json_decode_error\n        request_mock.return_value = resp_mock\n        with self.assertRaises(ClickException):\n            request_api(\"GET\", \"/path\")\n\n        error_msg = \"Error occured.\"\n        resp_mock.json = mock.Mock(return_value={\"detail\": error_msg})\n        with self.assertRaises(ClickException) as execinfo:\n            request_api(\"GET\", \"/path\")\n        expected_exception = f\"Wrong server response. Status code: {status_code}: Error detail: {error_msg}\"\n        self.assertEqual(str(execinfo.exception), expected_exception)\n\n    @mock.patch(\"aea.cli.registry.utils.get_or_create_cli_config\", return_value={})\n    def test_request_api_no_auth_data(\n        self, get_or_create_cli_config_mock, request_mock\n    ):\n        \"\"\"Test for request_api method no auth data.\"\"\"\n        with self.assertRaises(ClickException):\n            request_api(\"GET\", \"/path\", is_auth=True)\n\n    @mock.patch(\n        \"aea.cli.registry.utils.get_or_create_cli_config\",\n        return_value={AUTH_TOKEN_KEY: \"key\"},\n    )\n    def test_request_api_with_auth_positive(\n        self, get_or_create_cli_config_mock, request_mock\n    ):\n        \"\"\"Test for request_api method with auth positive result.\"\"\"\n        expected_result = {\"correct\": \"json\"}\n\n        resp_mock = mock.Mock()\n        resp_mock.json = lambda: expected_result\n        resp_mock.status_code = 200\n        request_mock.return_value = resp_mock\n\n        result = request_api(\"GET\", \"/path\", is_auth=True)\n        self.assertEqual(result, expected_result)\n\n    @mock.patch(\"builtins.open\", mock.mock_open())\n    def test_request_api_with_files_positive(self, request_mock):\n        \"\"\"Test for request_api method with file positive result.\"\"\"\n        expected_result = {\"correct\": \"json\"}\n\n        resp_mock = mock.Mock()\n        resp_mock.json = lambda: expected_result\n        resp_mock.status_code = 200\n        request_mock.return_value = resp_mock\n\n        test_files = {\n            \"file\": open(\"file.tar.gz\", \"rb\"),\n            \"readme\": open(\"file.md\", \"rb\"),\n        }\n        result = request_api(\"GET\", \"/path\", files=test_files)\n        self.assertEqual(result, expected_result)\n\n\n@mock.patch(\"aea.cli.registry.utils.requests.request\", _raise_connection_error)\nclass RequestAPINoResponseTestCase(TestCase):\n    \"\"\"Test case for request_api method no server response.\"\"\"\n\n    def test_request_api_server_not_responding(self):\n        \"\"\"Test for request_api method no server response.\"\"\"\n        with self.assertRaises(ClickException):\n            request_api(\"GET\", \"/path\")\n\n\n@mock.patch(\"aea.cli.registry.utils.requests.get\")\nclass DownloadFileTestCase(TestCase):\n    \"\"\"Test case for download_file method.\"\"\"\n\n    @mock.patch(\"builtins.open\", mock.mock_open())\n    def test_download_file_positive(self, get_mock):\n        \"\"\"Test for download_file method positive result.\"\"\"\n        filename = \"filename.tar.gz\"\n        url = \"url/{}\".format(filename)\n        cwd = \"cwd\"\n        filepath = os.path.join(cwd, filename)\n\n        resp_mock = mock.Mock()\n        raw_mock = mock.Mock()\n        raw_mock.read = lambda: \"file content\"\n\n        resp_mock.raw = raw_mock\n        resp_mock.status_code = 200\n        get_mock.return_value = resp_mock\n\n        result = download_file(url, cwd)\n        expected_result = filepath\n        self.assertEqual(result, expected_result)\n        get_mock.assert_called_once_with(\n            url, stream=True, timeout=FILE_DOWNLOAD_TIMEOUT\n        )\n\n    def test_download_file_wrong_response(self, get_mock):\n        \"\"\"Test for download_file method wrong response from file server.\"\"\"\n        resp_mock = mock.Mock()\n        resp_mock.status_code = 404\n        get_mock.return_value = resp_mock\n\n        with self.assertRaises(ClickException):\n            download_file(\"url\", \"cwd\")\n\n\nclass ExtractTestCase(TestCase):\n    \"\"\"Test case for extract method.\"\"\"\n\n    @mock.patch(\"aea.cli.registry.utils.os.remove\")\n    @mock.patch(\"aea.cli.registry.utils.tarfile.open\")\n    def test_extract_positive(self, tarfile_open_mock, os_remove_mock):\n        \"\"\"Test for extract method positive result.\"\"\"\n        source = \"file.tar.gz\"\n        target = \"target-folder\"\n\n        tar_mock = mock.Mock()\n        tar_mock.extractall = lambda path: None\n        tar_mock.close = lambda: None\n        tarfile_open_mock.return_value = tar_mock\n\n        extract(source, target)\n        tarfile_open_mock.assert_called_once_with(source, \"r:gz\")\n        os_remove_mock.assert_called_once_with(source)\n\n    def test_extract_wrong_file_type(self):\n        \"\"\"Test for extract method wrong file type.\"\"\"\n        source = \"file.wrong\"\n        target = \"target-folder\"\n        with self.assertRaises(ValueError):\n            extract(source, target)\n\n\n@mock.patch(\n    \"aea.cli.registry.utils.request_api\", return_value={\"username\": \"current-user\"}\n)\nclass CheckIsAuthorLoggedInTestCase(TestCase):\n    \"\"\"Test case for check_is_author_logged_in method.\"\"\"\n\n    def test_check_is_author_logged_in_positive(self, request_api_mock):\n        \"\"\"Test for check_is_author_logged_in method positive result.\"\"\"\n        check_is_author_logged_in(\"current-user\")\n\n    def test_check_is_author_logged_in_negative(self, request_api_mock):\n        \"\"\"Test for check_is_author_logged_in method negative result.\"\"\"\n        with self.assertRaises(ClickException):\n            check_is_author_logged_in(\"not-current-user\")\n\n\n@mock.patch(\"aea.cli.registry.utils.os.remove\")\n@mock.patch(\"aea.cli.registry.utils.os.listdir\", return_value=[\"file1.tar.gz\", \"file2\"])\n@mock.patch(\"aea.cli.registry.utils.os.getcwd\", return_value=\"cwd\")\nclass RmTarfilesTestCase(TestCase):\n    \"\"\"Test case for _rm_tarfiles method.\"\"\"\n\n    def test__rm_tarfiles_positive(self, getcwd_mock, listdir_mock, remove_mock):\n        \"\"\"Test for _rm_tarfiles method positive result.\"\"\"\n        _rm_tarfiles()\n        listdir_mock.assert_called_once_with(\"cwd\")\n        remove_mock.assert_called_once()\n\n\n@mock.patch(\"aea.cli.registry.utils.get_auth_token\", return_value=\"token\")\nclass IsAuthTokenPresentTestCase(TestCase):\n    \"\"\"Test case for is_auth_token_present method.\"\"\"\n\n    def test_is_auth_token_present_positive(self, get_auth_token_mock):\n        \"\"\"Test for is_auth_token_present method positive result.\"\"\"\n        result = is_auth_token_present()\n        self.assertTrue(result)\n\n\n@mock.patch(\n    \"aea.cli.registry.utils.find_item_locally\", side_effect=ClickException(\"some error\")\n)\n@mock.patch(\n    \"aea.cli.registry.utils.get_package_meta\",\n    return_value=dict(public_id=\"author/name:0.1.0\"),\n)\ndef test_get_latest_public_id_mixed_negative(*_mocks):\n    \"\"\"Test 'get_latest_public_id_mixed', when local fetch fails.\"\"\"\n    get_latest_public_id_mixed(\n        MagicMock(), \"protocol\", PublicId.from_str(\"author/name:0.1.0\")\n    )\n\n\ndef test_clean_tarfiles():\n    \"\"\"Test clean tarfiles wrapper.\"\"\"\n\n    expected_result = \"result\"\n\n    def func() -> str:\n        \"\"\"The function being wrapped.\"\"\"\n        return expected_result\n\n    wrapped = clean_tarfiles(func)\n    with tempfile.TemporaryDirectory() as tempdir:\n        with cd(tempdir):\n            tarfile_path = Path(tempdir, \"tarfile.tar.gz\")\n            tarfile_path.touch()\n\n            result = wrapped()\n\n            assert not tarfile_path.exists()\n            assert result == expected_result\n\n\ndef test_clean_tarfiles_error():\n    \"\"\"Test clean tarfiles wrapper in case of error.\"\"\"\n\n    expected_message = \"some exception\"\n\n    def func() -> str:\n        \"\"\"The function being wrapped.\"\"\"\n        raise Exception(expected_message)\n\n    wrapped = clean_tarfiles(func)\n    with tempfile.TemporaryDirectory() as tempdir:\n        with cd(tempdir):\n            tarfile_path = Path(tempdir, \"tarfile.tar.gz\")\n            tarfile_path.touch()\n\n            with pytest.raises(Exception, match=expected_message):\n                wrapped()\n\n            assert not tarfile_path.exists()\n\n\n@pytest.mark.integration\ndef test_get_package_meta():\n    \"\"\"Test get package meta.\"\"\"\n    package_meta = get_package_meta(\"protocol\", DefaultMessage.protocol_id.to_latest())\n    assert isinstance(package_meta, dict)\n    assert package_meta[\"name\"] == DefaultMessage.protocol_id.name\n\n\n@mock.patch(\n    \"aea.cli.registry.utils.find_item_locally\",\n    return_value=(None, MagicMock(public_id=DefaultMessage.protocol_id)),\n)\ndef test_get_latest_public_id_mixed(*_mock):\n    \"\"\"Test 'get_latest_public_id_mixed', in case of success.\"\"\"\n    result = get_latest_public_id_mixed(\n        MagicMock(), \"protocol\", DefaultMessage.protocol_id\n    )\n    assert result == DefaultMessage.protocol_id\n\n\n@mock.patch(\n    \"aea.cli.registry.utils.get_package_meta\",\n    return_value=dict(public_id=str(DefaultMessage.protocol_id)),\n)\ndef test_get_latest_version_available_in_registry_remote_mode(*_mocks):\n    \"\"\"Test 'get_latest_version_available_in_registry', remote mode.\"\"\"\n    context_mock = MagicMock(config=dict(is_local=False, is_mixed=False))\n    result = get_latest_version_available_in_registry(\n        context_mock, \"protocol\", DefaultMessage.protocol_id\n    )\n    assert result == DefaultMessage.protocol_id\n\n\ndef test_list_missing_packages():\n    \"\"\"Test 'list_missing_packages'.\"\"\"\n    packages = [(\"connection\", PublicId.from_str(\"test/test:0.1.2\"))]\n\n    resp_ok = MagicMock()\n    resp_ok.status_code = 200\n    with patch(\n        \"aea.cli.registry.utils._perform_registry_request\", return_value=resp_ok\n    ):\n        assert list_missing_packages(packages) == []\n\n    resp_404 = MagicMock()\n    resp_404.status_code = 404\n    with patch(\n        \"aea.cli.registry.utils._perform_registry_request\", return_value=resp_404\n    ):\n        assert list_missing_packages(packages) == packages\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_remove/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This test module contains the tests for the `aea remove` sub-command.\"\"\"\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_remove/test_base.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Test module for aea.cli.remove.remove_item method.\"\"\"\nimport os\nimport shutil\nimport tempfile\nfrom pathlib import Path\nfrom unittest import TestCase, mock\nfrom unittest.mock import patch\n\nimport pytest\nfrom click import ClickException\n\nfrom aea.cli.core import cli\nfrom aea.cli.remove import remove_item\nfrom aea.configurations.base import (\n    AgentConfig,\n    DEFAULT_AEA_CONFIG_FILE,\n    PackageId,\n    PackageType,\n    PublicId,\n)\nfrom aea.configurations.constants import DEFAULT_PROTOCOL\nfrom aea.configurations.loader import ConfigLoader\nfrom aea.helpers.base import cd\nfrom aea.test_tools.click_testing import CliRunner\nfrom aea.test_tools.test_cases import AEATestCaseEmpty\n\nfrom packages.fetchai.connections.http_client.connection import (\n    PUBLIC_ID as HTTP_CLIENT_PUBLIC_ID,\n)\nfrom packages.fetchai.connections.soef.connection import PUBLIC_ID as SOEF_PUBLIC_ID\n\nfrom tests.conftest import AUTHOR, CLI_LOG_OPTION, CUR_PATH\nfrom tests.test_aea.test_cli.tools_for_testing import ContextMock, PublicIdMock\n\n\n@mock.patch(\"aea.cli.remove.shutil.rmtree\")\n@mock.patch(\"aea.cli.remove.Path.exists\", return_value=False)\n@mock.patch(\"aea.cli.remove.try_to_load_agent_config\")\nclass RemoveItemTestCase(TestCase):\n    \"\"\"Test case for remove_item method.\"\"\"\n\n    def test_remove_item_item_folder_not_exists(\n        self, *mocks\n    ):  # pylint: disable=unused-argument\n        \"\"\"Test for save_agent_locally item folder not exists.\"\"\"\n        public_id = PublicIdMock.from_str(\"author/name:0.1.0\")\n        with pytest.raises(ClickException, match=\"Can not find folder for the package\"):\n            remove_item(ContextMock(protocols=[public_id]), \"protocol\", public_id)\n\n\n@mock.patch(\"aea.cli.remove.shutil.rmtree\")\n@mock.patch(\"aea.cli.remove.Path.exists\", return_value=True)\n@mock.patch(\"aea.cli.remove.ItemRemoveHelper.get_component_directory\")\n@mock.patch(\"aea.cli.remove.load_item_config\")\n@mock.patch(\"aea.cli.remove.try_to_load_agent_config\")\nclass RemoveItemBadConfigurationTestCase(TestCase):\n    \"\"\"Test case for remove_item method.\"\"\"\n\n    def test_remove_item_item_folder_not_exists(\n        self, *mocks\n    ):  # pylint: disable=unused-argument\n        \"\"\"Test for component bad configuration load.\"\"\"\n        public_id = PublicIdMock.from_str(\"author/name:0.1.0\")\n        with pytest.raises(\n            ClickException,\n            match=\"Error loading .* configuration, author/name do not match: .*\",\n        ):\n            remove_item(ContextMock(protocols=[public_id]), \"protocol\", public_id)\n\n\nclass TestRemovePackageWithLatestVersion(AEATestCaseEmpty):\n    \"\"\"Test case for remove package with latest version.\"\"\"\n\n    @pytest.mark.parametrize(\n        [\"type_\", \"public_id\"],\n        [\n            (\"protocol\", PublicId.from_str(DEFAULT_PROTOCOL)),\n            (\"connection\", PublicId(\"fetchai\", \"stub\").to_latest()),\n            (\"contract\", PublicId(\"fetchai\", \"erc1155\").to_latest()),\n        ],\n    )\n    def test_remove_pacakge_latest_version(self, type_, public_id):\n        \"\"\"Test remove protocol with latest version.\"\"\"\n        assert public_id.package_version.is_latest\n        # we need this because there isn't a default contract/connection\n        if type_ == \"connection\":\n            self.add_item(\"connection\", str(public_id))\n        if type_ == \"contract\":\n            self.add_item(\"contract\", str(public_id))\n\n        # first, check the package is present\n        items_path = os.path.join(self.agent_name, \"vendor\", \"fetchai\", type_ + \"s\")\n        items_folders = os.listdir(items_path)\n        item_name = public_id.name\n        assert item_name in items_folders\n\n        # remove the package\n        with patch(\"aea.cli.remove.RemoveItem.is_required_by\", False):\n            self.run_cli_command(\n                *[\"remove\", type_, str(public_id)], cwd=self._get_cwd()\n            )\n\n        # check that the 'aea remove' took effect.\n        items_folders = os.listdir(items_path)\n        assert item_name not in items_folders\n\n\nclass TestRemoveConfig(\n    AEATestCaseEmpty\n):  # pylint: disable=attribute-defined-outside-init\n    \"\"\"Test component configuration also removed from agent config.\"\"\"\n\n    ITEM_TYPE = \"connection\"\n    ITEM_PUBLIC_ID = SOEF_PUBLIC_ID\n\n    @staticmethod\n    def loader() -> ConfigLoader:\n        \"\"\"Return Agent config loader.\"\"\"\n        return ConfigLoader.from_configuration_type(PackageType.AGENT)\n\n    def load_config(self) -> AgentConfig:\n        \"\"\"Load AgentConfig from current directory.\"\"\"\n        with cd(self._get_cwd()):\n            agent_loader = self.loader()\n            path = Path(DEFAULT_AEA_CONFIG_FILE)\n            with path.open(mode=\"r\", encoding=\"utf-8\") as fp:\n                agent_config = agent_loader.load(fp)\n            return agent_config\n\n    def test_component_configuration_removed_from_agent_config(self):\n        \"\"\"Test component configuration removed from agent config.\"\"\"\n        with cd(self._get_cwd()):\n            self.run_cli_command(\n                \"add\", \"--local\", self.ITEM_TYPE, str(self.ITEM_PUBLIC_ID)\n            )\n            self.run_cli_command(\"add\", \"--local\", \"connection\", \"fetchai/http_server\")\n\n            self.runner.invoke(\n                cli,\n                [\n                    \"config\",\n                    \"set\",\n                    \"vendor.fetchai.connections.soef.config.api_key\",\n                    \"some_api_key\",\n                ],\n                standalone_mode=False,\n                catch_exceptions=False,\n            )\n            self.runner.invoke(\n                cli,\n                [\n                    \"config\",\n                    \"set\",\n                    \"vendor.fetchai.connections.http_server.config.port\",\n                    \"9000\",\n                ],\n                standalone_mode=False,\n                catch_exceptions=False,\n            )\n            config = self.load_config()\n            assert config.component_configurations\n            assert (\n                PackageId(self.ITEM_TYPE, self.ITEM_PUBLIC_ID)\n                in config.component_configurations\n            )\n\n            self.run_cli_command(\"remove\", self.ITEM_TYPE, str(self.ITEM_PUBLIC_ID))\n\n            config = self.load_config()\n            assert (\n                PackageId(self.ITEM_TYPE, self.ITEM_PUBLIC_ID)\n                not in config.component_configurations\n            )\n            assert config.component_configurations\n\n\nclass TestRemoveWithIncompatibleAEAVersion:\n    \"\"\"Test remove command when agent/package has incompatible aea version.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        # copy the 'packages' directory in the parent of the agent folder.\n        shutil.copytree(Path(CUR_PATH, \"..\", \"packages\"), Path(cls.t, \"packages\"))\n        cls.connection_id = str(HTTP_CLIENT_PUBLIC_ID)\n        cls.connection_name = \"http_client\"\n\n        os.chdir(cls.t)\n        result = cls.runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n        assert result.exit_code == 0\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n        os.chdir(cls.agent_name)\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"add\", \"--local\", \"connection\", cls.connection_id],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n\n    def test_exit_code_equal_to_zero(self):\n        \"\"\"Test that the exit code is equal to 1 (i.e. catchall for general errors).\"\"\"\n\n        with patch(\"aea.configurations.base.__aea_version__\", \"2.0.0\"):\n            result = self.runner.invoke(\n                cli,\n                [*CLI_LOG_OPTION, \"remove\", \"connection\", self.connection_id],\n                standalone_mode=False,\n                catch_exceptions=False,\n            )\n\n            assert result.exit_code == 0\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_remove/test_connection.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This test module contains the tests for the `aea remove connection` sub-command.\"\"\"\n\nimport os\nimport shutil\nimport tempfile\nimport unittest.mock\nfrom pathlib import Path\n\nimport yaml\n\nimport aea\nimport aea.configurations.base\nfrom aea.cli import cli\nfrom aea.configurations.base import DEFAULT_AEA_CONFIG_FILE\n\nfrom packages.fetchai.connections.http_client.connection import (\n    PUBLIC_ID as HTTP_CLIENT_PUBLIC_ID,\n)\nfrom packages.fetchai.connections.local.connection import (\n    PUBLIC_ID as LOCAL_CONNECTION_PUBLIC_ID,\n)\n\nfrom tests.conftest import AUTHOR, CLI_LOG_OPTION, CUR_PATH, CliRunner\n\n\nclass TestRemoveConnectionWithPublicId:\n    \"\"\"Test that the command 'aea remove connection' works correctly when using the public id.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        # copy the 'packages' directory in the parent of the agent folder.\n        shutil.copytree(Path(CUR_PATH, \"..\", \"packages\"), Path(cls.t, \"packages\"))\n        cls.connection_id = str(HTTP_CLIENT_PUBLIC_ID)\n        cls.connection_name = \"http_client\"\n\n        os.chdir(cls.t)\n        result = cls.runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n        assert result.exit_code == 0\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n        os.chdir(cls.agent_name)\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"add\", \"--local\", \"connection\", cls.connection_id],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n        cls.result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"remove\", \"connection\", cls.connection_id],\n            standalone_mode=False,\n        )\n\n    def test_exit_code_equal_to_zero(self):\n        \"\"\"Test that the exit code is equal to 1 (i.e. catchall for general errors).\"\"\"\n        assert self.result.exit_code == 0\n\n    def test_directory_does_not_exist(self):\n        \"\"\"Test that the directory of the removed connection does not exist.\"\"\"\n        assert not Path(\"connections\", self.connection_name).exists()\n\n    def test_connection_not_present_in_agent_config(self):\n        \"\"\"Test that the name of the removed connection is not present in the agent configuration file.\"\"\"\n        agent_config = aea.configurations.base.AgentConfig.from_json(\n            yaml.safe_load(open(DEFAULT_AEA_CONFIG_FILE))\n        )\n        assert self.connection_id not in agent_config.connections\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestRemoveConnectionFailsWhenConnectionDoesNotExist:\n    \"\"\"Test that the command 'aea remove connection' fails when the connection does not exist.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        shutil.copytree(Path(CUR_PATH, \"..\", \"packages\"), Path(cls.t, \"packages\"))\n        cls.connection_id = str(LOCAL_CONNECTION_PUBLIC_ID)\n\n        os.chdir(cls.t)\n        result = cls.runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n        assert result.exit_code == 0\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n        os.chdir(cls.agent_name)\n\n        cls.result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"remove\", \"connection\", cls.connection_id],\n            standalone_mode=False,\n        )\n\n    def test_exit_code_equal_to_1(self):\n        \"\"\"Test that the exit code is equal to 1 (i.e. catchall for general errors).\"\"\"\n        assert self.result.exit_code == 1\n\n    def test_error_message_connection_not_existing(self):\n        \"\"\"Test that the log error message is fixed.\n\n        The expected message is: 'Connection '{connection_name}' not found.'\n        \"\"\"\n        s = \"The connection '{}' is not supported.\".format(self.connection_id)\n        assert self.result.exception.message == s\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestRemoveConnectionFailsWhenExceptionOccurs:\n    \"\"\"Test that the command 'aea remove connection' fails when an exception occurs while removing the directory.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        # copy the 'packages' directory in the parent of the agent folder.\n        shutil.copytree(Path(CUR_PATH, \"..\", \"packages\"), Path(cls.t, \"packages\"))\n        cls.connection_id = str(HTTP_CLIENT_PUBLIC_ID)\n        cls.connection_name = \"http_client\"\n\n        os.chdir(cls.t)\n        result = cls.runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n        assert result.exit_code == 0\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n        os.chdir(cls.agent_name)\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"add\", \"--local\", \"connection\", cls.connection_id],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n\n        cls.patch = unittest.mock.patch(\n            \"shutil.rmtree\", side_effect=BaseException(\"an exception\")\n        )\n        cls.patch.start()\n\n        cls.result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"remove\", \"connection\", cls.connection_id],\n            standalone_mode=False,\n        )\n\n    def test_exit_code_equal_to_1(self):\n        \"\"\"Test that the exit code is equal to 1 (i.e. catchall for general errors).\"\"\"\n        assert self.result.exit_code == 1\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        cls.patch.stop()\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_remove/test_contract.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This test module contains the tests for the `aea remove contract` sub-command.\"\"\"\n\nfrom unittest import TestCase, mock\n\nfrom aea.cli import cli\n\nfrom tests.conftest import CLI_LOG_OPTION, CliRunner\n\n\n@mock.patch(\"aea.cli.utils.decorators.try_to_load_agent_config\")\nclass RemoveContractCommandTestCase(TestCase):\n    \"\"\"Test that the command 'aea remove contract' works as expected.\"\"\"\n\n    def setUp(self):\n        \"\"\"Set the test up.\"\"\"\n        self.runner = CliRunner()\n\n    @mock.patch(\"aea.cli.remove.remove_item\")\n    def test_remove_contract_positive(self, *mocks):\n        \"\"\"Test remove contract command positive result.\"\"\"\n        result = self.runner.invoke(\n            cli,\n            [\n                *CLI_LOG_OPTION,\n                \"--skip-consistency-check\",\n                \"remove\",\n                \"contract\",\n                \"author/name:0.1.0\",\n            ],\n            standalone_mode=False,\n        )\n        self.assertEqual(result.exit_code, 0)\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_remove/test_dependencies.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This test module contains the tests for the `aea add connection` sub-command.\"\"\"\n\nimport os\nimport shutil\nimport tempfile\nfrom pathlib import Path\nfrom unittest.mock import MagicMock\n\nimport pytest\nfrom click.exceptions import ClickException\n\nfrom aea.cli import cli\nfrom aea.cli.upgrade import ItemRemoveHelper\nfrom aea.configurations.base import (\n    AgentConfig,\n    DEFAULT_AEA_CONFIG_FILE,\n    PackageId,\n    PackageType,\n)\nfrom aea.configurations.loader import ConfigLoader\n\nfrom packages.fetchai.connections import oef\nfrom packages.fetchai.connections.soef.connection import PUBLIC_ID as SOEF_PUBLIC_ID\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\n\nfrom tests.conftest import AUTHOR, CLI_LOG_OPTION, CUR_PATH, CliRunner\n\n\nclass TestRemoveAndDependencies:  # pylint: disable=attribute-defined-outside-init\n    \"\"\"Test dependency remove helper and upgrade with dependency removed.\"\"\"\n\n    ITEM_TYPE = \"connection\"\n    ITEM_PUBLIC_ID = SOEF_PUBLIC_ID\n    DEPENDENCY_TYPE = \"protocol\"\n    DEPENDENCY_PUBLIC_ID = OefSearchMessage.protocol_id\n\n    @staticmethod\n    def loader() -> ConfigLoader:\n        \"\"\"Return Agent config loader.\"\"\"\n        return ConfigLoader.from_configuration_type(PackageType.AGENT)\n\n    def load_config(self) -> AgentConfig:\n        \"\"\"Load AgentConfig from current directory.\"\"\"\n        agent_loader = self.loader()\n        path = Path(DEFAULT_AEA_CONFIG_FILE)\n        with path.open(mode=\"r\", encoding=\"utf-8\") as fp:\n            agent_config = agent_loader.load(fp)\n        return agent_config\n\n    def setup(self):\n        \"\"\"Set the test up.\"\"\"\n        self.runner = CliRunner()\n        self.agent_name = \"myagent\"\n        self.cwd = os.getcwd()\n        self.t = tempfile.mkdtemp()\n        # copy the 'packages' directory in the parent of the agent folder.\n        shutil.copytree(Path(CUR_PATH, \"..\", \"packages\"), Path(self.t, \"packages\"))\n\n        os.chdir(self.t)\n        result = self.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n        result = self.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", self.agent_name],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n        os.chdir(self.agent_name)\n\n        # add connection first time\n        self.DEPENDENCY_PACKAGE_ID = PackageId(\n            self.DEPENDENCY_TYPE, self.DEPENDENCY_PUBLIC_ID\n        )\n        result = self.runner.invoke(\n            cli,\n            [\"-v\", \"DEBUG\", \"add\", \"--local\", self.ITEM_TYPE, str(self.ITEM_PUBLIC_ID)],\n            standalone_mode=False,\n            catch_exceptions=False,\n        )\n\n    def teardown(self):\n        \"\"\"Tear the test down.\"\"\"\n        os.chdir(self.cwd)\n        try:\n            shutil.rmtree(self.t)\n        except (OSError, IOError):\n            pass\n\n    def check_remove(self, item_type, public_id):\n        \"\"\"Check remove can be performed with remove helper.\"\"\"\n        context_mock = MagicMock(agent_config=self.load_config())\n        return ItemRemoveHelper(context_mock).check_remove(item_type, public_id)\n\n    def test_package_can_be_removed_with_its_dependency(self):\n        \"\"\"Test package (soef) can be removed with its dependency (oef_search).\"\"\"\n        required_by, can_be_removed, can_not_be_removed = self.check_remove(\n            self.ITEM_TYPE, self.ITEM_PUBLIC_ID\n        )\n\n        assert not required_by, required_by\n        assert self.DEPENDENCY_PACKAGE_ID in can_be_removed\n        assert self.DEPENDENCY_PACKAGE_ID not in can_not_be_removed\n\n    def _install_oef(self):\n        self.runner.invoke(\n            cli,\n            [\n                \"-v\",\n                \"DEBUG\",\n                \"add\",\n                \"--local\",\n                \"connection\",\n                str(oef.connection.PUBLIC_ID),\n            ],\n            standalone_mode=False,\n            catch_exceptions=False,\n        )\n\n    def test_package_can_be_removed_but_not_dependency(self):\n        \"\"\"Test package (soef) can be removed but not its shared dependency (oef_search) with other package (oef).\"\"\"\n        self._install_oef()\n        required_by, can_be_removed, can_not_be_removed = self.check_remove(\n            self.ITEM_TYPE, self.ITEM_PUBLIC_ID\n        )\n\n        assert not required_by, required_by\n        assert self.DEPENDENCY_PACKAGE_ID not in can_be_removed\n        assert self.DEPENDENCY_PACKAGE_ID in can_not_be_removed\n\n    def test_package_can_not_be_removed_cause_required_by_another_package(self):\n        \"\"\"Test package (oef_search) can not be removed cause required by another package (soef).\"\"\"\n        required_by, can_be_removed, can_not_be_removed = self.check_remove(\n            self.DEPENDENCY_TYPE, self.DEPENDENCY_PUBLIC_ID\n        )\n\n        assert PackageId(self.ITEM_TYPE, self.ITEM_PUBLIC_ID) in required_by\n        assert not can_be_removed\n        assert not can_not_be_removed\n\n    def test_removed_with_dependencies(self):\n        \"\"\"\n        Test dependency removed after upgrade.\n\n        Done with mocking _add_item_deps to avoid dependencies installation.\n        \"\"\"\n        assert self.DEPENDENCY_PUBLIC_ID in self.load_config().protocols\n\n        self.runner.invoke(\n            cli,\n            [\n                \"-v\",\n                \"DEBUG\",\n                \"remove\",\n                \"--with-dependencies\",\n                self.ITEM_TYPE,\n                f\"{self.ITEM_PUBLIC_ID.author}/{self.ITEM_PUBLIC_ID.name}\",\n            ],\n            standalone_mode=False,\n            catch_exceptions=False,\n        )\n        assert self.DEPENDENCY_PUBLIC_ID not in self.load_config().protocols\n\n    def test_removed_and_dependency_not_removed_caused_required_by_another_item(self):\n        \"\"\"Test dependency is not removed after upgrade cause required by another item.\"\"\"\n        assert self.DEPENDENCY_PUBLIC_ID in self.load_config().protocols\n        # do not add dependencies for the package\n\n        self._install_oef()\n        self.runner.invoke(\n            cli,\n            [\n                \"-v\",\n                \"DEBUG\",\n                \"remove\",\n                \"--with-dependencies\",\n                self.ITEM_TYPE,\n                f\"{self.ITEM_PUBLIC_ID.author}/{self.ITEM_PUBLIC_ID.name}\",\n            ],\n            standalone_mode=False,\n            catch_exceptions=False,\n        )\n        assert self.DEPENDENCY_PUBLIC_ID in self.load_config().protocols\n\n    def test_not_removed_cause_required(self):\n        \"\"\"Test dependency is not removed after upgrade cause required by another item.\"\"\"\n        assert self.DEPENDENCY_PUBLIC_ID in self.load_config().protocols\n        # do not add dependencies for the package\n        with pytest.raises(\n            ClickException,\n            match=\"Package .* can not be removed because it is required by .*\",\n        ):\n            self.runner.invoke(\n                cli,\n                [\n                    \"-v\",\n                    \"DEBUG\",\n                    \"remove\",\n                    \"--with-dependencies\",\n                    self.DEPENDENCY_TYPE,\n                    f\"{self.DEPENDENCY_PUBLIC_ID.author}/{self.DEPENDENCY_PUBLIC_ID.name}\",\n                ],\n                standalone_mode=False,\n                catch_exceptions=False,\n            )\n        assert self.DEPENDENCY_PUBLIC_ID in self.load_config().protocols\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_remove/test_protocol.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This test module contains the tests for the `aea remove protocol` sub-command.\"\"\"\n\nimport os\nimport shutil\nimport tempfile\nimport unittest.mock\nfrom pathlib import Path\n\nimport yaml\n\nimport aea\nimport aea.configurations.base\nfrom aea.cli import cli\nfrom aea.configurations.base import DEFAULT_AEA_CONFIG_FILE\n\nfrom packages.fetchai.protocols.gym.message import GymMessage\n\nfrom tests.conftest import AUTHOR, CLI_LOG_OPTION, CUR_PATH, CliRunner\n\n\nclass TestRemoveProtocolWithPublicId:\n    \"\"\"Test that the command 'aea remove protocol' works correctly when using the public id.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        # copy the 'packages' directory in the parent of the agent folder.\n        shutil.copytree(Path(CUR_PATH, \"..\", \"packages\"), Path(cls.t, \"packages\"))\n        cls.protocol_id = str(GymMessage.protocol_id)\n        cls.protocol_name = \"gym\"\n\n        os.chdir(cls.t)\n        result = cls.runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n        assert result.exit_code == 0\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n        os.chdir(cls.agent_name)\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"add\", \"--local\", \"protocol\", cls.protocol_id],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n        cls.result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"remove\", \"protocol\", cls.protocol_id],\n            standalone_mode=False,\n        )\n\n    def test_exit_code_equal_to_zero(self):\n        \"\"\"Test that the exit code is equal to 1 (i.e. catchall for general errors).\"\"\"\n        assert self.result.exit_code == 0\n\n    def test_directory_does_not_exist(self):\n        \"\"\"Test that the directory of the removed protocol does not exist.\"\"\"\n        assert not Path(\"protocols\", self.protocol_name).exists()\n\n    def test_protocol_not_present_in_agent_config(self):\n        \"\"\"Test that the name of the removed protocol is not present in the agent configuration file.\"\"\"\n        agent_config = aea.configurations.base.AgentConfig.from_json(\n            yaml.safe_load(open(DEFAULT_AEA_CONFIG_FILE))\n        )\n        assert self.protocol_id not in agent_config.protocols\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestRemoveProtocolFailsWhenProtocolDoesNotExist:\n    \"\"\"Test that the command 'aea remove protocol' fails when the protocol does not exist.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        shutil.copytree(Path(CUR_PATH, \"..\", \"packages\"), Path(cls.t, \"packages\"))\n        cls.protocol_id = str(GymMessage.protocol_id)\n\n        os.chdir(cls.t)\n        result = cls.runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n        assert result.exit_code == 0\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n        os.chdir(cls.agent_name)\n\n        cls.result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"remove\", \"protocol\", cls.protocol_id],\n            standalone_mode=False,\n        )\n\n    def test_exit_code_equal_to_1(self):\n        \"\"\"Test that the exit code is equal to 1 (i.e. catchall for general errors).\"\"\"\n        assert self.result.exit_code == 1\n\n    def test_error_message_protocol_not_existing(self):\n        \"\"\"Test that the log error message is fixed.\n\n        The expected message is: 'Protocol '{protocol_name}' not found.'\n        \"\"\"\n        s = \"The protocol '{}' is not supported.\".format(self.protocol_id)\n        assert self.result.exception.message == s\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestRemoveProtocolFailsWhenExceptionOccurs:\n    \"\"\"Test that the command 'aea remove protocol' fails when an exception occurs while removing the directory.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n\n        # copy the 'packages' directory in the parent of the agent folder.\n        shutil.copytree(Path(CUR_PATH, \"..\", \"packages\"), Path(cls.t, \"packages\"))\n        cls.protocol_id = str(GymMessage.protocol_id)\n\n        os.chdir(cls.t)\n        result = cls.runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n        assert result.exit_code == 0\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n        os.chdir(cls.agent_name)\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"add\", \"--local\", \"protocol\", cls.protocol_id],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n\n        cls.patch = unittest.mock.patch(\n            \"shutil.rmtree\", side_effect=BaseException(\"an exception\")\n        )\n        cls.patch.start()\n\n        cls.result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"remove\", \"protocol\", cls.protocol_id],\n            standalone_mode=False,\n        )\n\n    def test_exit_code_equal_to_1(self):\n        \"\"\"Test that the exit code is equal to 1 (i.e. catchall for general errors).\"\"\"\n        assert self.result.exit_code == 1\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        cls.patch.stop()\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_remove/test_skill.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This test module contains the tests for the `aea remove skill` sub-command.\"\"\"\n\nimport os\nimport shutil\nimport tempfile\nimport unittest.mock\nfrom pathlib import Path\n\nimport yaml\n\nimport aea\nimport aea.configurations.base\nfrom aea.cli import cli\nfrom aea.configurations.base import AgentConfig, DEFAULT_AEA_CONFIG_FILE\n\nfrom packages.fetchai.skills.gym import PUBLIC_ID as GYM_SKILL_PUBLIC_ID\n\nfrom tests.conftest import AUTHOR, CLI_LOG_OPTION, CliRunner, ROOT_DIR\n\n\nclass TestRemoveSkillWithPublicId:\n    \"\"\"Test that the command 'aea remove skill' works correctly when using the public id.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        dir_path = Path(\"packages\")\n        tmp_dir = cls.t / dir_path\n        src_dir = cls.cwd / Path(ROOT_DIR, dir_path)\n        shutil.copytree(str(src_dir), str(tmp_dir))\n        cls.skill_id = str(GYM_SKILL_PUBLIC_ID)\n        cls.skill_name = \"gym\"\n\n        os.chdir(cls.t)\n        result = cls.runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n        assert result.exit_code == 0\n\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n        os.chdir(cls.agent_name)\n\n        # change default registry path\n        config = AgentConfig.from_json(yaml.safe_load(open(DEFAULT_AEA_CONFIG_FILE)))\n        config.registry_path = os.path.join(ROOT_DIR, \"packages\")\n        yaml.safe_dump(dict(config.json), open(DEFAULT_AEA_CONFIG_FILE, \"w\"))\n\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"add\", \"--local\", \"skill\", cls.skill_id],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n        cls.result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"remove\", \"skill\", cls.skill_id],\n            standalone_mode=False,\n        )\n\n    def test_exit_code_equal_to_zero(self):\n        \"\"\"Test that the exit code is equal to 1 (i.e. catchall for general errors).\"\"\"\n        assert self.result.exit_code == 0\n\n    def test_directory_does_not_exist(self):\n        \"\"\"Test that the directory of the removed skill does not exist.\"\"\"\n        assert not Path(\"skills\", self.skill_name).exists()\n\n    def test_skill_not_present_in_agent_config(self):\n        \"\"\"Test that the name of the removed skill is not present in the agent configuration file.\"\"\"\n        agent_config = aea.configurations.base.AgentConfig.from_json(\n            yaml.safe_load(open(DEFAULT_AEA_CONFIG_FILE))\n        )\n        assert self.skill_id not in agent_config.skills\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestRemoveSkillFailsWhenSkillIsNotSupported:\n    \"\"\"Test that the command 'aea remove skill' fails when the skill is not supported.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        dir_path = Path(\"packages\")\n        tmp_dir = cls.t / dir_path\n        src_dir = cls.cwd / Path(ROOT_DIR, dir_path)\n        shutil.copytree(str(src_dir), str(tmp_dir))\n        cls.skill_id = str(GYM_SKILL_PUBLIC_ID)\n\n        os.chdir(cls.t)\n        result = cls.runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n        assert result.exit_code == 0\n\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n        os.chdir(cls.agent_name)\n\n        cls.result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"remove\", \"skill\", cls.skill_id],\n            standalone_mode=False,\n        )\n\n    def test_exit_code_equal_to_1(self):\n        \"\"\"Test that the exit code is equal to 1 (i.e. catchall for general errors).\"\"\"\n        assert self.result.exit_code == 1\n\n    def test_error_message_skill_not_existing(self):\n        \"\"\"Test that the log error message is fixed.\n\n        The expected message is: 'The skill '{skill_name}' is not supported.'\n        \"\"\"\n        s = \"The skill '{}' is not supported.\".format(self.skill_id)\n        assert self.result.exception.message == s\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestRemoveSkillFailsWhenExceptionOccurs:\n    \"\"\"Test that the command 'aea remove skill' fails when an exception occurs while removing the directory.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        dir_path = Path(\"packages\")\n        tmp_dir = cls.t / dir_path\n        src_dir = cls.cwd / Path(ROOT_DIR, dir_path)\n        shutil.copytree(str(src_dir), str(tmp_dir))\n        cls.skill_id = str(GYM_SKILL_PUBLIC_ID)\n        cls.skill_name = \"gym\"\n\n        os.chdir(cls.t)\n        result = cls.runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n        assert result.exit_code == 0\n\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n        os.chdir(cls.agent_name)\n\n        # change default registry path\n        config = AgentConfig.from_json(yaml.safe_load(open(DEFAULT_AEA_CONFIG_FILE)))\n        config.registry_path = os.path.join(ROOT_DIR, \"packages\")\n        yaml.safe_dump(dict(config.json), open(DEFAULT_AEA_CONFIG_FILE, \"w\"))\n\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"add\", \"--local\", \"skill\", cls.skill_id],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n\n        cls.patch = unittest.mock.patch(\n            \"shutil.rmtree\", side_effect=BaseException(\"an exception\")\n        )\n        cls.patch.start()\n\n        cls.result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"remove\", \"skill\", cls.skill_name],\n            standalone_mode=False,\n        )\n\n    def test_exit_code_equal_to_1(self):\n        \"\"\"Test that the exit code is equal to 1 (i.e. catchall for general errors).\"\"\"\n        assert self.result.exit_code == 1\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        cls.patch.stop()\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_remove_key.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This test module contains the tests for the `aea remove-key` sub-command.\"\"\"\nimport pytest\nfrom click.exceptions import ClickException\n\nfrom aea.test_tools.test_cases import AEATestCaseEmpty\n\nfrom tests.conftest import FETCHAI_PRIVATE_KEY_PATH\n\n\nclass BaseTestRemovePrivateKey(AEATestCaseEmpty):\n    \"\"\"Base test class on removing private keys.\"\"\"\n\n    WITH_CONNECTION: bool\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set up class.\"\"\"\n        super().setup_class()\n        cls.add_private_key(\n            private_key_filepath=FETCHAI_PRIVATE_KEY_PATH,\n            connection=cls.WITH_CONNECTION,\n        )\n\n    def test_remove(self):\n        \"\"\"Test remove.\"\"\"\n        result = self.remove_private_key(connection=self.WITH_CONNECTION)\n        assert result.exit_code == 0\n\n\nclass TestRemoveCryptoPrivateKey(BaseTestRemovePrivateKey):\n    \"\"\"Test removing a crypto private key.\"\"\"\n\n    WITH_CONNECTION = False\n\n\nclass TestRemoveConnectionPrivateKey(BaseTestRemovePrivateKey):\n    \"\"\"Test removing a connection private key.\"\"\"\n\n    WITH_CONNECTION = True\n\n\nclass BaseTestRemovePrivateKeyNegative(AEATestCaseEmpty):\n    \"\"\"Base test class on removing private keys, when key is not present\"\"\"\n\n    WITH_CONNECTION: bool\n    EXPECTED_ERROR_MSG: str\n\n    def test_remove(self):\n        \"\"\"Test remove.\"\"\"\n        with pytest.raises(ClickException, match=self.EXPECTED_ERROR_MSG):\n            self.remove_private_key(connection=self.WITH_CONNECTION)\n\n\nclass TestRemoveCryptoPrivateKeyNegative(BaseTestRemovePrivateKeyNegative):\n    \"\"\"Test removing a crypto private key.\"\"\"\n\n    WITH_CONNECTION = False\n    EXPECTED_ERROR_MSG = \"There is no key registered with id fetchai.\"\n\n\nclass TestRemoveConnectionPrivateKeyNegative(BaseTestRemovePrivateKeyNegative):\n    \"\"\"Test removing a connection private key.\"\"\"\n\n    WITH_CONNECTION = True\n    EXPECTED_ERROR_MSG = \"There is no connection key registered with id fetchai.\"\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_reset_password.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This test module contains the tests for CLI reset_password command.\"\"\"\n\nfrom unittest import TestCase, mock\n\nfrom aea.cli import cli\nfrom aea.cli.reset_password import _do_password_reset\n\nfrom tests.conftest import CLI_LOG_OPTION, CliRunner\n\n\n@mock.patch(\"aea.cli.reset_password._do_password_reset\")\nclass ResetPasswordTestCase(TestCase):\n    \"\"\"Test case for CLI reset_password command.\"\"\"\n\n    def setUp(self):\n        \"\"\"Set it up.\"\"\"\n        self.runner = CliRunner()\n\n    def test_reset_password_positive(self, registry_reset_password_mock):\n        \"\"\"Test for CLI reset_password positive result.\"\"\"\n        email = \"email@example.com\"\n        result = self.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"reset_password\", email],\n            standalone_mode=False,\n        )\n        self.assertEqual(result.exit_code, 0)\n        registry_reset_password_mock.assert_called_once_with(email)\n\n\nclass DoPasswordResetTestCase(TestCase):\n    \"\"\"Test case for _do_password_reset method.\"\"\"\n\n    @mock.patch(\"aea.cli.reset_password.registry_reset_password\")\n    @mock.patch(\"aea.cli.reset_password.click.echo\")\n    def test__do_password_reset_positive(self, echo_mock, registry_reset_password_mock):\n        \"\"\"Test _do_password_reset for positive result.\"\"\"\n        email = \"email@example.com\"\n        _do_password_reset(email)\n        registry_reset_password_mock.assert_called_once_with(email)\n        echo_mock.assert_called_once_with(\n            \"An email with a password reset link was sent to {}\".format(email)\n        )\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_run.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This test module contains the tests for the `aea run` sub-command.\"\"\"\nimport os\nimport re\nimport shutil\nimport sys\nimport tempfile\nimport time\nfrom pathlib import Path\nfrom unittest import TestCase, mock\nfrom unittest.mock import patch\n\nimport pytest\nimport yaml\nfrom aea_ledger_fetchai import FetchAICrypto\nfrom click import ClickException\nfrom pexpect.exceptions import EOF  # type: ignore\n\nfrom aea.cli import cli\nfrom aea.cli.run import _build_aea, run_aea\nfrom aea.configurations.base import (\n    DEFAULT_AEA_CONFIG_FILE,\n    DEFAULT_CONNECTION_CONFIG_FILE,\n)\nfrom aea.exceptions import AEAPackageLoadingError\nfrom aea.test_tools.test_cases import AEATestCaseEmpty, _get_password_option_args\n\nfrom packages.fetchai.connections.http_client.connection import (\n    PUBLIC_ID as HTTP_ClIENT_PUBLIC_ID,\n)\nfrom packages.fetchai.connections.stub.connection import (\n    PUBLIC_ID as STUB_CONNECTION_PUBLIC_ID,\n)\nfrom packages.fetchai.protocols.fipa.message import FipaMessage\n\nfrom tests.common.pexpect_popen import PexpectWrapper\nfrom tests.conftest import (\n    AUTHOR,\n    CLI_LOG_OPTION,\n    CliRunner,\n    FETCHAI_PRIVATE_KEY_FILE,\n    MAX_FLAKY_RERUNS,\n    ROOT_DIR,\n)\n\n\n@pytest.mark.flaky(reruns=MAX_FLAKY_RERUNS)\ndef test_run(password_or_none):\n    \"\"\"Test that the command 'aea run' works as expected.\"\"\"\n    runner = CliRunner()\n    agent_name = \"myagent\"\n    cwd = os.getcwd()\n    t = tempfile.mkdtemp()\n    # copy the 'packages' directory in the parent of the agent folder.\n    shutil.copytree(Path(ROOT_DIR, \"packages\"), Path(t, \"packages\"))\n    password_options = _get_password_option_args(password_or_none)\n\n    os.chdir(t)\n    result = runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n    assert result.exit_code == 0\n\n    result = runner.invoke(cli, [*CLI_LOG_OPTION, \"create\", \"--local\", agent_name])\n    assert result.exit_code == 0\n\n    os.chdir(Path(t, agent_name))\n\n    result = runner.invoke(\n        cli,\n        [*CLI_LOG_OPTION, \"generate-key\", FetchAICrypto.identifier, *password_options],\n    )\n    assert result.exit_code == 0\n\n    result = runner.invoke(\n        cli, [*CLI_LOG_OPTION, \"add-key\", FetchAICrypto.identifier, *password_options]\n    )\n    assert result.exit_code == 0\n\n    result = runner.invoke(\n        cli,\n        [*CLI_LOG_OPTION, \"add\", \"--local\", \"connection\", str(HTTP_ClIENT_PUBLIC_ID)],\n    )\n    assert result.exit_code == 0\n\n    result = runner.invoke(\n        cli,\n        [\n            *CLI_LOG_OPTION,\n            \"config\",\n            \"set\",\n            \"agent.default_connection\",\n            str(HTTP_ClIENT_PUBLIC_ID),\n        ],\n    )\n    assert result.exit_code == 0\n\n    try:\n        process = PexpectWrapper(  # nosec\n            [sys.executable, \"-m\", \"aea.cli\", \"run\", *password_options],\n            env=os.environ.copy(),\n            maxread=10000,\n            encoding=\"utf-8\",\n            logfile=sys.stdout,\n        )\n\n        process.expect(\"Start processing messages\", timeout=10)\n        process.control_c()\n        process.wait_to_complete(10)\n\n        assert process.returncode == 0\n\n    finally:\n        process.terminate()\n        process.wait_to_complete(10)\n\n        os.chdir(cwd)\n        try:\n            shutil.rmtree(t)\n        except (OSError, IOError):\n            pass\n\n\n@pytest.mark.flaky(reruns=MAX_FLAKY_RERUNS)  # flaky on Windows\n@pytest.mark.skipif(\n    sys.version_info < (3, 7),\n    reason=\"cannot run on 3.6 as AttributeError: 'functools._lru_list_elem' object has no attribute '__class__'\",\n)\ndef test_run_with_profiling():\n    \"\"\"Test profiling data showed.\"\"\"\n    runner = CliRunner()\n    agent_name = \"myagent\"\n    cwd = os.getcwd()\n    t = tempfile.mkdtemp()\n    # copy the 'packages' directory in the parent of the agent folder.\n    shutil.copytree(Path(ROOT_DIR, \"packages\"), Path(t, \"packages\"))\n\n    os.chdir(t)\n    result = runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n    assert result.exit_code == 0\n\n    result = runner.invoke(cli, [*CLI_LOG_OPTION, \"create\", \"--local\", agent_name])\n    assert result.exit_code == 0\n\n    os.chdir(Path(t, agent_name))\n\n    result = runner.invoke(\n        cli, [*CLI_LOG_OPTION, \"generate-key\", FetchAICrypto.identifier]\n    )\n    assert result.exit_code == 0\n\n    result = runner.invoke(cli, [*CLI_LOG_OPTION, \"add-key\", FetchAICrypto.identifier])\n    assert result.exit_code == 0\n\n    result = runner.invoke(\n        cli,\n        [*CLI_LOG_OPTION, \"add\", \"--local\", \"connection\", str(HTTP_ClIENT_PUBLIC_ID)],\n    )\n    assert result.exit_code == 0\n\n    result = runner.invoke(\n        cli,\n        [\n            *CLI_LOG_OPTION,\n            \"config\",\n            \"set\",\n            \"agent.default_connection\",\n            str(HTTP_ClIENT_PUBLIC_ID),\n        ],\n    )\n    assert result.exit_code == 0\n\n    try:\n        process = PexpectWrapper(  # nosec\n            [sys.executable, \"-m\", \"aea.cli\", \"run\", \"--profiling\", \"1\"],\n            env=os.environ.copy(),\n            maxread=10000,\n            encoding=\"utf-8\",\n            logfile=sys.stdout,\n        )\n\n        process.expect(\"Start processing messages\", timeout=10)\n        process.expect(\"Profiling details\", timeout=10)\n        process.control_c()\n        process.wait_to_complete(10)\n\n        assert process.returncode == 0\n\n    finally:\n        process.terminate()\n        process.wait_to_complete(10)\n\n        os.chdir(cwd)\n        try:\n            shutil.rmtree(t)\n        except (OSError, IOError):\n            pass\n\n\n@pytest.mark.flaky(reruns=MAX_FLAKY_RERUNS)\ndef test_run_with_default_connection():\n    \"\"\"Test that the command 'aea run' works as expected.\"\"\"\n    runner = CliRunner()\n    agent_name = \"myagent\"\n    cwd = os.getcwd()\n    t = tempfile.mkdtemp()\n    # copy the 'packages' directory in the parent of the agent folder.\n    shutil.copytree(Path(ROOT_DIR, \"packages\"), Path(t, \"packages\"))\n\n    os.chdir(t)\n    result = runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n    assert result.exit_code == 0\n\n    result = runner.invoke(cli, [*CLI_LOG_OPTION, \"create\", \"--local\", agent_name])\n    assert result.exit_code == 0\n\n    os.chdir(Path(t, agent_name))\n\n    result = runner.invoke(\n        cli, [*CLI_LOG_OPTION, \"generate-key\", FetchAICrypto.identifier]\n    )\n    assert result.exit_code == 0\n\n    result = runner.invoke(cli, [*CLI_LOG_OPTION, \"add-key\", FetchAICrypto.identifier])\n    assert result.exit_code == 0\n\n    try:\n        process = PexpectWrapper(  # nosec\n            [sys.executable, \"-m\", \"aea.cli\", \"run\"],\n            env=os.environ.copy(),\n            maxread=10000,\n            encoding=\"utf-8\",\n            logfile=sys.stdout,\n        )\n\n        process.expect(\"Start processing messages\", timeout=10)\n        process.control_c()\n        process.wait_to_complete(10)\n\n        assert process.returncode == 0\n\n    finally:\n        process.terminate()\n        process.wait_to_complete(10)\n\n        os.chdir(cwd)\n        try:\n            shutil.rmtree(t)\n        except (OSError, IOError):\n            pass\n\n\n@pytest.mark.parametrize(\n    argnames=[\"connection_ids\"],\n    argvalues=[\n        [f\"{str(HTTP_ClIENT_PUBLIC_ID)},{str(STUB_CONNECTION_PUBLIC_ID)}\"],\n        [f\"'{str(HTTP_ClIENT_PUBLIC_ID)}, {str(STUB_CONNECTION_PUBLIC_ID)}'\"],\n        [f\"{str(HTTP_ClIENT_PUBLIC_ID)},,{str(STUB_CONNECTION_PUBLIC_ID)},\"],\n    ],\n)\ndef test_run_multiple_connections(connection_ids):\n    \"\"\"Test that the command 'aea run' works as expected when specifying multiple connections.\"\"\"\n    runner = CliRunner()\n    agent_name = \"myagent\"\n    cwd = os.getcwd()\n    t = tempfile.mkdtemp()\n    # copy the 'packages' directory in the parent of the agent folder.\n    shutil.copytree(Path(ROOT_DIR, \"packages\"), Path(t, \"packages\"))\n\n    os.chdir(t)\n    result = runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n    assert result.exit_code == 0\n\n    result = runner.invoke(cli, [*CLI_LOG_OPTION, \"create\", \"--local\", agent_name])\n    assert result.exit_code == 0\n\n    os.chdir(Path(t, agent_name))\n\n    result = runner.invoke(\n        cli, [*CLI_LOG_OPTION, \"generate-key\", FetchAICrypto.identifier]\n    )\n    assert result.exit_code == 0\n\n    result = runner.invoke(cli, [*CLI_LOG_OPTION, \"add-key\", FetchAICrypto.identifier])\n    assert result.exit_code == 0\n\n    result = runner.invoke(\n        cli,\n        [\n            *CLI_LOG_OPTION,\n            \"add\",\n            \"--local\",\n            \"connection\",\n            str(STUB_CONNECTION_PUBLIC_ID),\n        ],\n    )\n    assert result.exit_code == 0\n\n    result = runner.invoke(\n        cli,\n        [*CLI_LOG_OPTION, \"add\", \"--local\", \"connection\", str(HTTP_ClIENT_PUBLIC_ID)],\n    )\n    assert result.exit_code == 0\n\n    # stub is the default connection, so it should fail\n    result = runner.invoke(\n        cli,\n        [\n            *CLI_LOG_OPTION,\n            \"add\",\n            \"--local\",\n            \"connection\",\n            str(STUB_CONNECTION_PUBLIC_ID),\n        ],\n    )\n    assert result.exit_code == 1\n    process = PexpectWrapper(  # nosec\n        [sys.executable, \"-m\", \"aea.cli\", \"run\", \"--connections\", connection_ids],\n        env=os.environ,\n        maxread=10000,\n        encoding=\"utf-8\",\n        logfile=sys.stdout,\n    )\n\n    try:\n        process.expect_all([\"Start processing messages\"], timeout=40)\n        process.control_c()\n        process.expect(\n            EOF,\n            timeout=40,\n        )\n        process.wait_to_complete(15)\n        assert process.returncode == 0\n    finally:\n        process.wait_to_complete(15)\n        os.chdir(cwd)\n        try:\n            shutil.rmtree(t)\n        except (OSError, IOError):\n            pass\n\n\ndef test_run_unknown_private_key():\n    \"\"\"Test that the command 'aea run' works as expected.\"\"\"\n    runner = CliRunner()\n    agent_name = \"myagent\"\n    cwd = os.getcwd()\n    t = tempfile.mkdtemp()\n    # copy the 'packages' directory in the parent of the agent folder.\n    shutil.copytree(Path(ROOT_DIR, \"packages\"), Path(t, \"packages\"))\n\n    os.chdir(t)\n    result = runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n    assert result.exit_code == 0\n\n    result = runner.invoke(cli, [*CLI_LOG_OPTION, \"create\", \"--local\", agent_name])\n    assert result.exit_code == 0\n\n    os.chdir(Path(t, agent_name))\n\n    result = runner.invoke(\n        cli,\n        [*CLI_LOG_OPTION, \"add\", \"--local\", \"connection\", str(HTTP_ClIENT_PUBLIC_ID)],\n    )\n    assert result.exit_code == 0\n    result = runner.invoke(\n        cli,\n        [\n            *CLI_LOG_OPTION,\n            \"config\",\n            \"set\",\n            \"agent.default_connection\",\n            str(HTTP_ClIENT_PUBLIC_ID),\n        ],\n    )\n    assert result.exit_code == 0\n\n    # Load the agent yaml file and manually insert the things we need\n    file = open(\"aea-config.yaml\", mode=\"r\")\n\n    # read all lines at once\n    whole_file = file.read()\n\n    find_text = \"private_key_paths: {}\"\n    replace_text = \"\"\"private_key_paths:\n        fetchai_not: fetchai_private_key.txt\"\"\"\n\n    whole_file = whole_file.replace(find_text, replace_text)\n\n    # close the file\n    file.close()\n\n    with open(\"aea-config.yaml\", \"w\") as f:\n        f.write(whole_file)\n\n    # Private key needs to exist otherwise doesn't get to code path we are interested in testing\n    with open(FETCHAI_PRIVATE_KEY_FILE, \"w\") as f:\n        f.write(\"3801d3703a1fcef18f6bf393fba89245f36b175f4989d8d6e026300dad21e05d\")\n\n    result = runner.invoke(\n        cli,\n        [*CLI_LOG_OPTION, \"run\", \"--connections\", str(HTTP_ClIENT_PUBLIC_ID)],\n        standalone_mode=False,\n    )\n\n    s = \"Unsupported identifier `fetchai_not` in private key paths. Supported identifiers: ['cosmos', 'ethereum', 'fetchai'].\"\n    assert result.exception.message == s\n\n    os.chdir(cwd)\n    try:\n        shutil.rmtree(t)\n    except (OSError, IOError):\n        pass\n\n\ndef test_run_fet_private_key_config():\n    \"\"\"Test that the command 'aea run' works as expected.\"\"\"\n    runner = CliRunner()\n    agent_name = \"myagent\"\n    cwd = os.getcwd()\n    t = tempfile.mkdtemp()\n    # copy the 'packages' directory in the parent of the agent folder.\n    shutil.copytree(Path(ROOT_DIR, \"packages\"), Path(t, \"packages\"))\n\n    os.chdir(t)\n    result = runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n    assert result.exit_code == 0\n\n    result = runner.invoke(cli, [*CLI_LOG_OPTION, \"create\", \"--local\", agent_name])\n    assert result.exit_code == 0\n\n    os.chdir(Path(t, agent_name))\n\n    result = runner.invoke(\n        cli,\n        [*CLI_LOG_OPTION, \"add\", \"--local\", \"connection\", str(HTTP_ClIENT_PUBLIC_ID)],\n    )\n    assert result.exit_code == 0\n\n    # Load the agent yaml file and manually insert the things we need\n    file = open(\"aea-config.yaml\", mode=\"r\")\n\n    # read all lines at once\n    whole_file = file.read()\n\n    find_text = \"private_key_paths: {}\"\n    replace_text = \"\"\"private_key_paths:\n    fetchai: default_private_key_not.txt\"\"\"\n\n    whole_file = whole_file.replace(find_text, replace_text)\n\n    # close the file\n    file.close()\n\n    with open(\"aea-config.yaml\", \"w\") as f:\n        f.write(whole_file)\n\n    error_msg = \"\"\n    try:\n        cli.main([*CLI_LOG_OPTION, \"run\", \"--connections\", str(HTTP_ClIENT_PUBLIC_ID)])\n    except SystemExit as e:\n        error_msg = str(e)\n\n    assert error_msg == \"1\"\n\n    os.chdir(cwd)\n    try:\n        shutil.rmtree(t)\n    except (OSError, IOError):\n        pass\n\n\ndef test_run_ethereum_private_key_config():\n    \"\"\"Test that the command 'aea run' works as expected.\"\"\"\n    runner = CliRunner()\n    agent_name = \"myagent\"\n    cwd = os.getcwd()\n    t = tempfile.mkdtemp()\n    # copy the 'packages' directory in the parent of the agent folder.\n    shutil.copytree(Path(ROOT_DIR, \"packages\"), Path(t, \"packages\"))\n\n    os.chdir(t)\n    result = runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n    assert result.exit_code == 0\n\n    result = runner.invoke(cli, [*CLI_LOG_OPTION, \"create\", \"--local\", agent_name])\n    assert result.exit_code == 0\n\n    os.chdir(Path(t, agent_name))\n\n    result = runner.invoke(\n        cli,\n        [*CLI_LOG_OPTION, \"add\", \"--local\", \"connection\", str(HTTP_ClIENT_PUBLIC_ID)],\n    )\n    assert result.exit_code == 0\n\n    # Load the agent yaml file and manually insert the things we need\n    file = open(\"aea-config.yaml\", mode=\"r\")\n\n    # read all lines at once\n    whole_file = file.read()\n\n    find_text = \"private_key_paths: {}\"\n    replace_text = \"\"\"private_key_paths:\n    ethereum: default_private_key_not.txt\"\"\"\n\n    whole_file = whole_file.replace(find_text, replace_text)\n\n    # close the file\n    file.close()\n\n    with open(\"aea-config.yaml\", \"w\") as f:\n        f.write(whole_file)\n\n    error_msg = \"\"\n    try:\n        cli.main([*CLI_LOG_OPTION, \"run\", \"--connections\", str(HTTP_ClIENT_PUBLIC_ID)])\n    except SystemExit as e:\n        error_msg = str(e)\n\n    assert error_msg == \"1\"\n\n    os.chdir(cwd)\n    try:\n        shutil.rmtree(t)\n    except (OSError, IOError):\n        pass\n\n\n@pytest.mark.flaky(reruns=MAX_FLAKY_RERUNS)  # install depends on network\ndef test_run_with_install_deps():\n    \"\"\"Test that the command 'aea run --install-deps' does not crash.\"\"\"\n    runner = CliRunner()\n    agent_name = \"myagent\"\n    cwd = os.getcwd()\n    t = tempfile.mkdtemp()\n    # copy the 'packages' directory in the parent of the agent folder.\n    packages_src = os.path.join(ROOT_DIR, \"packages\")\n    packages_dst = os.path.join(t, \"packages\")\n    shutil.copytree(packages_src, packages_dst)\n\n    os.chdir(t)\n    result = runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n    assert result.exit_code == 0\n\n    result = runner.invoke(cli, [*CLI_LOG_OPTION, \"create\", \"--local\", agent_name])\n    assert result.exit_code == 0\n\n    os.chdir(Path(t, agent_name))\n\n    result = runner.invoke(\n        cli, [*CLI_LOG_OPTION, \"generate-key\", FetchAICrypto.identifier]\n    )\n    assert result.exit_code == 0\n\n    result = runner.invoke(cli, [*CLI_LOG_OPTION, \"add-key\", FetchAICrypto.identifier])\n    assert result.exit_code == 0\n\n    result = runner.invoke(\n        cli,\n        [*CLI_LOG_OPTION, \"add\", \"--local\", \"connection\", str(HTTP_ClIENT_PUBLIC_ID)],\n    )\n    assert result.exit_code == 0\n    result = runner.invoke(\n        cli,\n        [\n            *CLI_LOG_OPTION,\n            \"config\",\n            \"set\",\n            \"agent.default_connection\",\n            str(HTTP_ClIENT_PUBLIC_ID),\n        ],\n    )\n    assert result.exit_code == 0\n\n    try:\n        process = PexpectWrapper(\n            [\n                sys.executable,\n                \"-m\",\n                \"aea.cli\",\n                \"-v\",\n                \"DEBUG\",\n                \"run\",\n                \"--install-deps\",\n                \"--connections\",\n                str(HTTP_ClIENT_PUBLIC_ID),\n            ],\n            env=os.environ,\n            maxread=10000,\n            encoding=\"utf-8\",\n            logfile=sys.stdout,\n        )\n        process.expect_all([\"Start processing messages...\"], timeout=30)\n        time.sleep(1.0)\n        process.control_c()\n        process.wait_to_complete(10)\n        assert process.returncode == 0\n\n    finally:\n        process.terminate()\n        process.wait_to_complete(10)\n        os.chdir(cwd)\n        try:\n            shutil.rmtree(t)\n        except (OSError, IOError):\n            pass\n\n\n@pytest.mark.flaky(reruns=MAX_FLAKY_RERUNS)  # install depends on network\ndef test_run_with_install_deps_and_requirement_file():\n    \"\"\"Test that the command 'aea run --install-deps' with requirement file does not crash.\"\"\"\n    runner = CliRunner()\n    agent_name = \"myagent\"\n    cwd = os.getcwd()\n    t = tempfile.mkdtemp()\n    # copy the 'packages' directory in the parent of the agent folder.\n    shutil.copytree(Path(ROOT_DIR, \"packages\"), Path(t, \"packages\"))\n\n    os.chdir(t)\n    result = runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n    assert result.exit_code == 0\n\n    result = runner.invoke(cli, [*CLI_LOG_OPTION, \"create\", \"--local\", agent_name])\n    assert result.exit_code == 0\n\n    os.chdir(Path(t, agent_name))\n\n    result = runner.invoke(\n        cli, [*CLI_LOG_OPTION, \"generate-key\", FetchAICrypto.identifier]\n    )\n    assert result.exit_code == 0\n\n    result = runner.invoke(cli, [*CLI_LOG_OPTION, \"add-key\", FetchAICrypto.identifier])\n    assert result.exit_code == 0\n\n    result = runner.invoke(\n        cli,\n        [*CLI_LOG_OPTION, \"add\", \"--local\", \"connection\", str(HTTP_ClIENT_PUBLIC_ID)],\n    )\n    assert result.exit_code == 0\n    result = runner.invoke(\n        cli,\n        [\n            *CLI_LOG_OPTION,\n            \"config\",\n            \"set\",\n            \"agent.default_connection\",\n            str(HTTP_ClIENT_PUBLIC_ID),\n        ],\n    )\n    assert result.exit_code == 0\n\n    result = runner.invoke(cli, [*CLI_LOG_OPTION, \"freeze\"])\n    assert result.exit_code == 0\n    Path(t, agent_name, \"requirements.txt\").write_text(result.output)\n\n    try:\n        process = PexpectWrapper(\n            [\n                sys.executable,\n                \"-m\",\n                \"aea.cli\",\n                \"-v\",\n                \"DEBUG\",\n                \"run\",\n                \"--install-deps\",\n                \"--connections\",\n                str(HTTP_ClIENT_PUBLIC_ID),\n            ],\n            env=os.environ,\n            maxread=10000,\n            encoding=\"utf-8\",\n            logfile=sys.stdout,\n        )\n        process.expect_all([\"Start processing messages...\"], timeout=30)\n        time.sleep(1.0)\n        process.control_c()\n        process.wait_to_complete(10)\n        assert process.returncode == 0\n\n    finally:\n        process.terminate()\n        process.wait_to_complete(10)\n        os.chdir(cwd)\n        try:\n            shutil.rmtree(t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestRunFailsWhenExceptionOccursInSkill:\n    \"\"\"Test that the command 'aea run' fails when an exception occurs in any skill.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        # copy the 'packages' directory in the parent of the agent folder.\n        shutil.copytree(Path(ROOT_DIR, \"packages\"), Path(cls.t, \"packages\"))\n\n        os.chdir(cls.t)\n        result = cls.runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n        assert result.exit_code == 0\n\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n\n        os.chdir(Path(cls.t, cls.agent_name))\n\n        result = cls.runner.invoke(\n            cli,\n            [\n                *CLI_LOG_OPTION,\n                \"add\",\n                \"--local\",\n                \"connection\",\n                str(HTTP_ClIENT_PUBLIC_ID),\n            ],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n\n        shutil.copytree(\n            Path(ROOT_DIR, \"tests\", \"data\", \"exception_skill\"),\n            Path(cls.t, cls.agent_name, \"vendor\", \"fetchai\", \"skills\", \"exception\"),\n        )\n        config_path = Path(cls.t, cls.agent_name, DEFAULT_AEA_CONFIG_FILE)\n        config = yaml.safe_load(open(config_path))\n        config.setdefault(\"skills\", []).append(\"fetchai/exception:0.1.0\")\n        yaml.safe_dump(config, open(config_path, \"w\"))\n\n        try:\n            cli.main(\n                [*CLI_LOG_OPTION, \"run\", \"--connections\", str(HTTP_ClIENT_PUBLIC_ID)]\n            )\n        except SystemExit as e:\n            cls.exit_code = e.code\n\n    def test_exit_code_equal_to_1(self):\n        \"\"\"Assert that the exit code is equal to 1 (i.e. catchall for general errors).\"\"\"\n        assert self.exit_code == 1\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestRunFailsWhenConfigurationFileNotFound:\n    \"\"\"Test that the command 'aea run' fails when the agent configuration file is not found in the current directory.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        # copy the 'packages' directory in the parent of the agent folder.\n        shutil.copytree(Path(ROOT_DIR, \"packages\"), Path(cls.t, \"packages\"))\n\n        os.chdir(cls.t)\n        result = cls.runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n        assert result.exit_code == 0\n\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n        Path(cls.t, cls.agent_name, DEFAULT_AEA_CONFIG_FILE).unlink()\n\n        os.chdir(Path(cls.t, cls.agent_name))\n\n        cls.result = cls.runner.invoke(\n            cli,\n            [\"--skip-consistency-check\", *CLI_LOG_OPTION, \"run\"],\n            standalone_mode=False,\n        )\n\n    def test_exit_code_equal_to_1(self):\n        \"\"\"Assert that the exit code is equal to 1 (i.e. catchall for general errors).\"\"\"\n        assert self.result.exit_code == 1\n\n    def test_log_error_message(self):\n        \"\"\"Test that the log error message is fixed.\"\"\"\n        s = \"Agent configuration file '{}' not found in the current directory.\".format(\n            DEFAULT_AEA_CONFIG_FILE\n        )\n        assert self.result.exception.message == s\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestRunFailsWhenConfigurationFileIsEmpty:\n    \"\"\"Test that the command 'aea run' fails when the agent configuration file is empty.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        # copy the 'packages' directory in the parent of the agent folder.\n        shutil.copytree(Path(ROOT_DIR, \"packages\"), Path(cls.t, \"packages\"))\n\n        os.chdir(cls.t)\n        result = cls.runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n        assert result.exit_code == 0\n\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n\n        Path(cls.t, cls.agent_name, DEFAULT_AEA_CONFIG_FILE).write_text(\"\")\n\n        os.chdir(Path(cls.t, cls.agent_name))\n\n        cls.result = cls.runner.invoke(\n            cli, [*CLI_LOG_OPTION, \"run\"], standalone_mode=False\n        )\n\n    def test_exit_code_equal_to_1(self):\n        \"\"\"Assert that the exit code is equal to 1 (i.e. catchall for general errors).\"\"\"\n        assert self.result.exit_code == 1\n\n    def test_log_error_message(self):\n        \"\"\"Test that the log error message is fixed.\"\"\"\n        s = \"Agent configuration file was empty.\"\n        assert self.result.exception.message == s\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestRunFailsWhenConfigurationFileInvalid:\n    \"\"\"Test that the command 'aea run' fails when the agent configuration file is invalid.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        # copy the 'packages' directory in the parent of the agent folder.\n        shutil.copytree(Path(ROOT_DIR, \"packages\"), Path(cls.t, \"packages\"))\n\n        os.chdir(cls.t)\n        result = cls.runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n        assert result.exit_code == 0\n\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n\n        Path(cls.t, cls.agent_name, DEFAULT_AEA_CONFIG_FILE).write_text(\n            \"invalid_attribute: 'foo'\\n\"\n        )\n\n        os.chdir(Path(cls.t, cls.agent_name))\n\n        cls.result = cls.runner.invoke(\n            cli, [*CLI_LOG_OPTION, \"run\"], standalone_mode=False\n        )\n\n    def test_exit_code_equal_to_1(self):\n        \"\"\"Assert that the exit code is equal to 1 (i.e. catchall for general errors).\"\"\"\n        assert self.result.exit_code == 1\n\n    def test_log_error_message(self):\n        \"\"\"Test that the log error message is fixed.\"\"\"\n        s = \"Agent configuration file '{}' is invalid: `ExtraPropertiesError: properties not expected: invalid_attribute`. Please check the documentation.\".format(\n            DEFAULT_AEA_CONFIG_FILE\n        )\n        assert self.result.exception.message == s\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestRunFailsWhenConnectionNotDeclared(AEATestCaseEmpty):\n    \"\"\"Test that the command 'aea run --connections' fails when the connection is not declared.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        super().setup_class()\n        cls.connection_id = \"author/unknown_connection:0.1.0\"\n        cls.connection_name = \"unknown_connection\"\n        cls.generate_private_key(FetchAICrypto.identifier)\n        cls.add_private_key(FetchAICrypto.identifier)\n\n    def test_run(self):\n        \"\"\"Run the test.\"\"\"\n        expected_message = f\"Connection ids ['{self.connection_id}'] not declared in the configuration file.\"\n        with pytest.raises(ClickException, match=re.escape(expected_message)):\n            self.run_cli_command(\n                \"run\", \"--connections\", str(self.connection_id), cwd=self._get_cwd()\n            )\n\n\nclass TestRunFailsWhenConnectionConfigFileNotFound:\n    \"\"\"Test that the command 'aea run --connections' fails when the connection config file is not found.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.connection_id = HTTP_ClIENT_PUBLIC_ID\n        cls.connection_name = cls.connection_id.name\n        cls.connection_author = cls.connection_id.author\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        # copy the 'packages' directory in the parent of the agent folder.\n        shutil.copytree(Path(ROOT_DIR, \"packages\"), Path(cls.t, \"packages\"))\n\n        os.chdir(cls.t)\n        result = cls.runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n        assert result.exit_code == 0\n\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n        os.chdir(Path(cls.t, cls.agent_name))\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"add\", \"--local\", \"connection\", str(cls.connection_id)],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n        result = cls.runner.invoke(\n            cli,\n            [\n                *CLI_LOG_OPTION,\n                \"config\",\n                \"set\",\n                \"agent.default_connection\",\n                str(HTTP_ClIENT_PUBLIC_ID),\n            ],\n        )\n        assert result.exit_code == 0\n        cls.connection_configuration_path = Path(\n            cls.t,\n            cls.agent_name,\n            \"vendor\",\n            cls.connection_author,\n            \"connections\",\n            cls.connection_name,\n            DEFAULT_CONNECTION_CONFIG_FILE,\n        )\n        cls.connection_configuration_path.unlink()\n        cls.relative_connection_configuration_path = (\n            cls.connection_configuration_path.relative_to(Path(cls.t, cls.agent_name))\n        )\n\n        cls.result = cls.runner.invoke(\n            cli,\n            [\n                \"--skip-consistency-check\",\n                *CLI_LOG_OPTION,\n                \"run\",\n                \"--connections\",\n                str(cls.connection_id),\n            ],\n            standalone_mode=False,\n        )\n\n    def test_exit_code_equal_to_1(self):\n        \"\"\"Assert that the exit code is equal to 1 (i.e. catchall for general errors).\"\"\"\n        assert self.result.exit_code == 1\n\n    def test_log_error_message(self):\n        \"\"\"Test that the log error message is fixed.\"\"\"\n        s = \"Connection configuration not found: {}\".format(\n            self.relative_connection_configuration_path\n        )\n        assert self.result.exception.message == s\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestRunFailsWhenConnectionNotComplete(AEATestCaseEmpty):\n    \"\"\"Test that the command 'aea run --connections' fails when the connection.py module is missing.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        super().setup_class()\n        cls.connection_id = HTTP_ClIENT_PUBLIC_ID\n        cls.connection_author = cls.connection_id.author\n        cls.connection_name = cls.connection_id.name\n        cls.generate_private_key(FetchAICrypto.identifier)\n        cls.add_private_key(FetchAICrypto.identifier)\n        cls.add_item(\"connection\", str(cls.connection_id))\n        cls.set_config(\"agent.default_connection\", str(HTTP_ClIENT_PUBLIC_ID))\n        connection_module_path = Path(\n            cls.t,\n            cls.agent_name,\n            \"vendor\",\n            \"fetchai\",\n            \"connections\",\n            cls.connection_name,\n            \"connection.py\",\n        )\n        connection_module_path.unlink()\n        cls.relative_connection_module_path = connection_module_path.relative_to(\n            Path(cls.t, cls.agent_name)\n        )\n\n    def test_run(self):\n        \"\"\"Run the test.\"\"\"\n        expected_message = \"Package loading error: An error occurred while loading connection {}: Connection module '{}' not found.\".format(\n            self.connection_id, self.relative_connection_module_path\n        )\n        with pytest.raises(ClickException, match=re.escape(expected_message)):\n            self.run_cli_command(\n                \"--skip-consistency-check\",\n                \"run\",\n                \"--connections\",\n                str(self.connection_id),\n                cwd=self._get_cwd(),\n            )\n\n\nclass TestRunFailsWhenConnectionClassNotPresent(AEATestCaseEmpty):\n    \"\"\"Test that the command 'aea run --connections' fails when the connection is not declared.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        super().setup_class()\n        cls.connection_id = str(HTTP_ClIENT_PUBLIC_ID)\n        cls.connection_name = \"http_client\"\n        cls.generate_private_key(FetchAICrypto.identifier)\n        cls.add_private_key(FetchAICrypto.identifier)\n        cls.add_item(\"connection\", cls.connection_id)\n        cls.set_config(\"agent.default_connection\", cls.connection_id)\n        Path(\n            cls.t,\n            cls.agent_name,\n            \"vendor\",\n            \"fetchai\",\n            \"connections\",\n            cls.connection_name,\n            \"connection.py\",\n        ).write_text(\"\")\n\n    def test_run(self):\n        \"\"\"Run the test.\"\"\"\n        expected_message = \"Package loading error: An error occurred while loading connection {}: Connection class '{}' not found.\".format(\n            self.connection_id, \"HTTPClientConnection\"\n        )\n        with pytest.raises(ClickException, match=expected_message):\n            self.run_cli_command(\n                \"--skip-consistency-check\",\n                \"run\",\n                \"--connections\",\n                self.connection_id,\n                cwd=self._get_cwd(),\n            )\n\n\nclass TestRunFailsWhenProtocolConfigFileNotFound:\n    \"\"\"Test that the command 'aea run' fails when a protocol configuration file is not found.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.connection_id = str(STUB_CONNECTION_PUBLIC_ID)\n        cls.connection_name = \"stub\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        # copy the 'packages' directory in the parent of the agent folder.\n        shutil.copytree(Path(ROOT_DIR, \"packages\"), Path(cls.t, \"packages\"))\n\n        os.chdir(cls.t)\n        result = cls.runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n        assert result.exit_code == 0\n\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n        os.chdir(Path(cls.t, cls.agent_name))\n\n        configuration_file_path = Path(\n            cls.t,\n            cls.agent_name,\n            \"vendor\",\n            \"fetchai\",\n            \"protocols\",\n            \"default\",\n            \"protocol.yaml\",\n        )\n\n        configuration_file_path.unlink()\n        cls.relative_configuration_file_path = configuration_file_path.relative_to(\n            Path(cls.t, cls.agent_name)\n        )\n\n        cls.result = cls.runner.invoke(\n            cli,\n            [\n                \"--skip-consistency-check\",\n                *CLI_LOG_OPTION,\n                \"run\",\n                \"--connections\",\n                cls.connection_id,\n            ],\n            standalone_mode=False,\n        )\n\n    def test_exit_code_equal_to_1(self):\n        \"\"\"Assert that the exit code is equal to 1 (i.e. catchall for general errors).\"\"\"\n        assert self.result.exit_code == 1\n\n    def test_log_error_message(self):\n        \"\"\"Test that the log error message is fixed.\"\"\"\n        s = \"Protocol configuration not found: {}\".format(\n            self.relative_configuration_file_path\n        )\n        assert self.result.exception.message == s\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestRunFailsWhenProtocolNotComplete:\n    \"\"\"Test that the command 'aea run' fails when a protocol directory is not complete.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        # copy the 'packages' directory in the parent of the agent folder.\n        shutil.copytree(Path(ROOT_DIR, \"packages\"), Path(cls.t, \"packages\"))\n\n        os.chdir(cls.t)\n        result = cls.runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n        assert result.exit_code == 0\n\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n\n        os.chdir(os.path.join(cls.t, cls.agent_name))\n\n        result = cls.runner.invoke(\n            cli,\n            [\n                *CLI_LOG_OPTION,\n                \"add\",\n                \"--local\",\n                \"protocol\",\n                str(FipaMessage.protocol_id),\n            ],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n\n        # remove protocol configuration\n        configuration_path = Path(\n            cls.t,\n            cls.agent_name,\n            \"vendor\",\n            \"fetchai\",\n            \"protocols\",\n            \"fipa\",\n            \"protocol.yaml\",\n        )\n        configuration_path.unlink()\n        cls.relative_configuration_file_path = configuration_path.relative_to(\n            Path(cls.t, cls.agent_name)\n        )\n\n        cls.result = cls.runner.invoke(\n            cli,\n            [\"--skip-consistency-check\", *CLI_LOG_OPTION, \"run\"],\n            standalone_mode=False,\n        )\n\n    def test_exit_code_equal_to_1(self):\n        \"\"\"Assert that the exit code is equal to 1 (i.e. catchall for general errors).\"\"\"\n        assert self.result.exit_code == 1\n\n    def test_log_error_message(self):\n        \"\"\"Test that the log error message is fixed.\"\"\"\n        s = \"Protocol configuration not found: {}\".format(\n            self.relative_configuration_file_path\n        )\n        assert self.result.exception.message == s\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\ndef _raise_click_exception(*args, **kwargs):\n    raise ClickException(\"message\")\n\n\nclass RunAEATestCase(TestCase):\n    \"\"\"Test case for run_aea method.\"\"\"\n\n    def test_run_aea_positive_mock(self):\n        \"\"\"Test run_aea method for positive result (mocked).\"\"\"\n        ctx = mock.Mock()\n        aea = mock.Mock()\n        ctx.config = {\"skip_consistency_check\": True}\n        with mock.patch(\"aea.cli.run._build_aea\", return_value=aea):\n            run_aea(ctx, [\"author/name:0.1.0\"], \"env_file\", False)\n\n    def test_run_aea_positive_install_deps_mock(self):\n        \"\"\"Test run_aea method for positive result (mocked), install deps true.\"\"\"\n        ctx = mock.Mock()\n        aea = mock.Mock()\n        ctx.config = {\"skip_consistency_check\": True}\n        with mock.patch(\"aea.cli.run.do_install\"):\n            with mock.patch(\"aea.cli.run._build_aea\", return_value=aea):\n                run_aea(ctx, [\"author/name:0.1.0\"], \"env_file\", True)\n\n    @mock.patch(\"aea.cli.run._prepare_environment\", _raise_click_exception)\n    def test_run_aea_negative(self, *mocks):\n        \"\"\"Test run_aea method for negative result.\"\"\"\n        ctx = mock.Mock()\n        ctx.config = {\"skip_consistency_check\": True}\n        with self.assertRaises(ClickException):\n            run_aea(ctx, [\"author/name:0.1.0\"], \"env_file\", False)\n\n\ndef _raise_aea_package_loading_error(*args, **kwargs):\n    raise AEAPackageLoadingError()\n\n\n@mock.patch(\"aea.cli.run.AEABuilder.from_aea_project\", _raise_aea_package_loading_error)\nclass BuildAEATestCase(TestCase):\n    \"\"\"Test case for run_aea method.\"\"\"\n\n    def test__build_aea_negative(self, *mocks):\n        \"\"\"Test _build_aea method for negative result.\"\"\"\n        with self.assertRaises(ClickException):\n            _build_aea(connection_ids=[], skip_consistency_check=True)\n\n\nclass TestExcludeConnection(AEATestCaseEmpty):\n    \"\"\"Test that the command 'aea run --connections' fails when the connection is not declared.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        super().setup_class()\n        cls.connection_id = str(HTTP_ClIENT_PUBLIC_ID)\n        cls.connection2_id = str(STUB_CONNECTION_PUBLIC_ID)\n        cls.generate_private_key(FetchAICrypto.identifier)\n        cls.add_private_key(FetchAICrypto.identifier)\n        cls.add_item(\"connection\", cls.connection_id)\n        cls.add_item(\"connection\", cls.connection2_id)\n\n    def test_connection_excluded(self):\n        \"\"\"Test connection excluded.\"\"\"\n\n        def raise_err(*args):\n            raise Exception(args[1])\n\n        with pytest.raises(Exception, match=\"^None$\"):\n            with patch(\"aea.cli.run.run_aea\", raise_err):\n                self.run_cli_command(\n                    \"run\",\n                    cwd=self._get_cwd(),\n                )\n        with pytest.raises(Exception, match=f\"^..{self.connection2_id}..$\"):\n            with patch(\"aea.cli.run.run_aea\", raise_err):\n                self.run_cli_command(\n                    \"run\",\n                    \"--exclude-connections\",\n                    self.connection_id,\n                    cwd=self._get_cwd(),\n                )\n\n    def test_fail_to_exclude_non_existing_connection(self):\n        \"\"\"Test fail to exclude not defined connection.\"\"\"\n        with pytest.raises(\n            Exception,\n            match=\"Connections to exclude: fake/connection:0.1.0 are not defined in agent configuration\",\n        ):\n            self.run_cli_command(\n                \"--skip-consistency-check\",\n                \"run\",\n                \"--exclude-connections\",\n                \"fake/connection:0.1.0\",\n                cwd=self._get_cwd(),\n            )\n\n    def test_fail_to_specify_connections_and_exclude_the_same_time(self):\n        \"\"\"Test connections specification and exclusion not permited.\"\"\"\n\n        with pytest.raises(\n            Exception,\n            match=\"Please use only one of --connections or --exclude-connections, not both!\",\n        ):\n            self.run_cli_command(\n                \"run\",\n                \"--exclude-connections\",\n                self.connection_id,\n                \"--connections\",\n                self.connection_id,\n                cwd=self._get_cwd(),\n            )\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_scaffold/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This test module contains the tests for the `aea scaffold` sub-command.\"\"\"\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_scaffold/test_connection.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This test module contains the tests for the `aea scaffold connection` sub-command.\"\"\"\nimport json\nimport os\nimport shutil\nimport tempfile\nimport unittest.mock\nfrom pathlib import Path\n\nimport jsonschema\nimport yaml\nfrom jsonschema import Draft4Validator, ValidationError\n\nfrom aea.cli import cli\nfrom aea.configurations.base import DEFAULT_CONNECTION_CONFIG_FILE\nfrom aea.configurations.loader import make_jsonschema_base_uri\n\nfrom tests.conftest import (\n    AUTHOR,\n    CLI_LOG_OPTION,\n    CONFIGURATION_SCHEMA_DIR,\n    CONNECTION_CONFIGURATION_SCHEMA,\n    CliRunner,\n    ROOT_DIR,\n)\n\n\nclass TestScaffoldConnection:\n    \"\"\"Test that the command 'aea scaffold connection' works correctly in correct preconditions.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.resource_name = \"myresource\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        dir_path = Path(\"packages\")\n        tmp_dir = cls.t / dir_path\n        src_dir = cls.cwd / Path(ROOT_DIR, dir_path)\n        shutil.copytree(str(src_dir), str(tmp_dir))\n\n        cls.schema = json.load(open(CONNECTION_CONFIGURATION_SCHEMA))\n        cls.resolver = jsonschema.RefResolver(\n            make_jsonschema_base_uri(Path(CONFIGURATION_SCHEMA_DIR).absolute()),\n            cls.schema,\n        )\n        cls.validator = Draft4Validator(cls.schema, resolver=cls.resolver)\n\n        os.chdir(cls.t)\n        result = cls.runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n        assert result.exit_code == 0\n\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n        os.chdir(cls.agent_name)\n        # scaffold connection\n        cls.result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"scaffold\", \"connection\", cls.resource_name],\n            standalone_mode=False,\n        )\n\n    def test_exit_code_equal_to_0(self):\n        \"\"\"Test that the exit code is equal to 0.\"\"\"\n        assert self.result.exit_code == 0\n\n    def test_resource_folder_contains_module_connection(self):\n        \"\"\"Test that the resource folder contains scaffold connection.py module.\"\"\"\n        p = Path(\n            self.t, self.agent_name, \"connections\", self.resource_name, \"connection.py\"\n        )\n        assert p.exists()\n\n    def test_resource_folder_contains_configuration_file(self):\n        \"\"\"Test that the resource folder contains a good configuration file.\"\"\"\n        p = Path(\n            self.t,\n            self.agent_name,\n            \"connections\",\n            self.resource_name,\n            DEFAULT_CONNECTION_CONFIG_FILE,\n        )\n        config_file = yaml.safe_load(open(p))\n        self.validator.validate(instance=config_file)\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestScaffoldConnectionWithSymlinks:\n    \"\"\"Test that the command 'aea scaffold connection' works correctly in correct preconditions with the `--with-symlinks` flag.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.resource_name = \"myresource\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        dir_path = Path(\"packages\")\n        tmp_dir = cls.t / dir_path\n        src_dir = cls.cwd / Path(ROOT_DIR, dir_path)\n        shutil.copytree(str(src_dir), str(tmp_dir))\n\n        cls.schema = json.load(open(CONNECTION_CONFIGURATION_SCHEMA))\n        cls.resolver = jsonschema.RefResolver(\n            make_jsonschema_base_uri(Path(CONFIGURATION_SCHEMA_DIR).absolute()),\n            cls.schema,\n        )\n        cls.validator = Draft4Validator(cls.schema, resolver=cls.resolver)\n\n        os.chdir(cls.t)\n        result = cls.runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n        assert result.exit_code == 0\n\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n        os.chdir(cls.agent_name)\n        # scaffold connection\n        cls.result = cls.runner.invoke(\n            cli,\n            [\n                *CLI_LOG_OPTION,\n                \"scaffold\",\n                \"--with-symlinks\",\n                \"connection\",\n                cls.resource_name,\n            ],\n            standalone_mode=False,\n        )\n\n    def test_exit_code_equal_to_0(self):\n        \"\"\"Test that the exit code is equal to 0.\"\"\"\n        assert self.result.exit_code == 0\n\n    def test_resource_folder_contains_module_connection(self):\n        \"\"\"Test that the resource folder contains scaffold connection.py module.\"\"\"\n        p = Path(\n            self.t, self.agent_name, \"connections\", self.resource_name, \"connection.py\"\n        )\n        assert p.exists()\n\n    def test_resource_folder_contains_configuration_file(self):\n        \"\"\"Test that the resource folder contains a good configuration file.\"\"\"\n        p = Path(\n            self.t,\n            self.agent_name,\n            \"connections\",\n            self.resource_name,\n            DEFAULT_CONNECTION_CONFIG_FILE,\n        )\n        config_file = yaml.safe_load(open(p))\n        self.validator.validate(instance=config_file)\n\n    def test_symlinks_exist(self):\n        \"\"\"Test that the symlinks where created.\"\"\"\n        packages = \"packages\"\n        assert os.path.islink(packages)\n        assert os.readlink(packages) == \"vendor\"\n        vendor_package = Path(\"vendor\", AUTHOR, \"connections\", self.resource_name)\n        non_vendor_package = Path(\"connections\", self.resource_name)\n        assert os.path.islink(vendor_package)\n        assert os.readlink(str(vendor_package)) == os.path.join(\n            \"..\", \"..\", \"..\", non_vendor_package\n        )\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestScaffoldConnectionFailsWhenDirectoryAlreadyExists:\n    \"\"\"Test that the command 'aea scaffold connection' fails when a folder with 'scaffold' name already.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.resource_name = \"myresource\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        dir_path = Path(\"packages\")\n        tmp_dir = cls.t / dir_path\n        src_dir = cls.cwd / Path(ROOT_DIR, dir_path)\n        shutil.copytree(str(src_dir), str(tmp_dir))\n\n        os.chdir(cls.t)\n        result = cls.runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n        assert result.exit_code == 0\n\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n        os.chdir(cls.agent_name)\n        # create a dummy 'myresource' folder\n        Path(cls.t, cls.agent_name, \"connections\", cls.resource_name).mkdir(\n            exist_ok=False, parents=True\n        )\n        cls.result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"scaffold\", \"connection\", cls.resource_name],\n            standalone_mode=False,\n        )\n\n    def test_exit_code_equal_to_1(self):\n        \"\"\"Test that the exit code is equal to 1 (i.e. catchall for general errors).\"\"\"\n        assert self.result.exit_code == 1\n\n    def test_error_message_connection_already_existing(self):\n        \"\"\"Test that the log error message is fixed.\n\n        The expected message is: 'A connection with name '{connection_name}' already exists. Aborting...'\n        \"\"\"\n        s = \"A connection with this name already exists. Please choose a different name and try again.\"\n        assert self.result.exception.message == s\n\n    def test_resource_directory_exists(self):\n        \"\"\"Test that the resource directory still exists.\n\n        This means that after every failure, we make sure we restore the previous state.\n        \"\"\"\n        assert Path(self.t, self.agent_name, \"connections\", self.resource_name).exists()\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestScaffoldConnectionFailsWhenConnectionAlreadyExists:\n    \"\"\"Test that the command 'aea add connection' fails when the connection already exists.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.resource_name = \"myresource\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        dir_path = Path(\"packages\")\n        tmp_dir = cls.t / dir_path\n        src_dir = cls.cwd / Path(ROOT_DIR, dir_path)\n        shutil.copytree(str(src_dir), str(tmp_dir))\n\n        os.chdir(cls.t)\n        result = cls.runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n        assert result.exit_code == 0\n\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n        os.chdir(cls.agent_name)\n        # add connection first time\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"scaffold\", \"connection\", cls.resource_name],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n        # scaffold connection with the same connection name\n        cls.result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"scaffold\", \"connection\", cls.resource_name],\n            standalone_mode=False,\n        )\n\n    def test_exit_code_equal_to_1(self):\n        \"\"\"Test that the exit code is equal to 1 (i.e. catchall for general errors).\"\"\"\n        assert self.result.exit_code == 1\n\n    def test_error_message_connection_already_existing(self):\n        \"\"\"Test that the log error message is fixed.\n\n        The expected message is: 'A connection with name '{connection_name}' already exists. Aborting...'\n        \"\"\"\n        s = \"A connection with name '{}' already exists. Aborting...\".format(\n            self.resource_name\n        )\n        assert self.result.exception.message == s\n\n    def test_resource_directory_exists(self):\n        \"\"\"Test that the resource directory still exists.\n\n        This means that after every failure, we make sure we restore the previous state.\n        \"\"\"\n        assert Path(self.t, self.agent_name, \"connections\", self.resource_name).exists()\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestScaffoldConnectionFailsWhenConfigFileIsNotCompliant:\n    \"\"\"Test that the command 'aea scaffold connection' fails when the configuration file is not compliant with the schema.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.resource_name = \"myresource\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        dir_path = Path(\"packages\")\n        tmp_dir = cls.t / dir_path\n        src_dir = cls.cwd / Path(ROOT_DIR, dir_path)\n        shutil.copytree(str(src_dir), str(tmp_dir))\n\n        os.chdir(cls.t)\n        result = cls.runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n        assert result.exit_code == 0\n\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n\n        # change the dumping of yaml module to raise an exception.\n        cls.patch = unittest.mock.patch(\n            \"yaml.dump\", side_effect=ValidationError(\"test error message\")\n        )\n        cls.patch.start()\n\n        os.chdir(cls.agent_name)\n        cls.result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"scaffold\", \"connection\", cls.resource_name],\n            standalone_mode=False,\n        )\n\n    def test_exit_code_equal_to_1(self):\n        \"\"\"Test that the exit code is equal to 1 (i.e. catchall for general errors).\"\"\"\n        assert self.result.exit_code == 1\n\n    def test_configuration_file_not_valid(self):\n        \"\"\"Test that the log error message is fixed.\n\n        The expected message is: 'Cannot find connection: '{connection_name}''\n        \"\"\"\n        s = \"Error when validating the connection configuration file.\"\n        assert self.result.exception.message == s\n\n    def test_resource_directory_does_not_exists(self):\n        \"\"\"Test that the resource directory does not exist.\n\n        This means that after every failure, we make sure we restore the previous state.\n        \"\"\"\n        assert not Path(\n            self.t, self.agent_name, \"connections\", self.resource_name\n        ).exists()\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        cls.patch.stop()\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestScaffoldConnectionFailsWhenExceptionOccurs:\n    \"\"\"Test that the command 'aea scaffold connection' fails when the configuration file is not compliant with the schema.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.resource_name = \"myresource\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        dir_path = Path(\"packages\")\n        tmp_dir = cls.t / dir_path\n        src_dir = cls.cwd / Path(ROOT_DIR, dir_path)\n        shutil.copytree(str(src_dir), str(tmp_dir))\n\n        os.chdir(cls.t)\n        result = cls.runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n        assert result.exit_code == 0\n\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n\n        cls.patch = unittest.mock.patch(\n            \"shutil.copytree\", side_effect=Exception(\"unknwon exception\")\n        )\n        cls.patch.start()\n\n        os.chdir(cls.agent_name)\n        cls.result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"scaffold\", \"connection\", cls.resource_name],\n            standalone_mode=False,\n        )\n\n    def test_exit_code_equal_to_1(self):\n        \"\"\"Test that the exit code is equal to 1 (i.e. catchall for general errors).\"\"\"\n        assert self.result.exit_code == 1\n\n    def test_resource_directory_does_not_exists(self):\n        \"\"\"Test that the resource directory does not exist.\n\n        This means that after every failure, we make sure we restore the previous state.\n        \"\"\"\n        assert not Path(\n            self.t, self.agent_name, \"connections\", self.resource_name\n        ).exists()\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        cls.patch.stop()\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_scaffold/test_decision_maker_handler.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This test module contains the tests for CLI scaffold generic methods and commands.\"\"\"\n\nfrom unittest import TestCase, mock\n\nfrom click import ClickException\n\nfrom aea.cli import cli\nfrom aea.cli.scaffold import _scaffold_dm_handler\n\nfrom tests.conftest import CLI_LOG_OPTION, CliRunner\nfrom tests.test_aea.test_cli.tools_for_testing import ContextMock\n\n\n@mock.patch(\"aea.cli.scaffold._scaffold_dm_handler\")\n@mock.patch(\"aea.cli.utils.decorators._check_aea_project\")\nclass ScaffoldDecisionMakerHandlerTestCase(TestCase):\n    \"\"\"Test case for CLI scaffold decision maker handler command.\"\"\"\n\n    def setUp(self):\n        \"\"\"Set it up.\"\"\"\n        self.runner = CliRunner()\n\n    def test_scaffold_decision_maker_handler_command_positive(self, *mocks):\n        \"\"\"Test for CLI scaffold decision maker handler command for positive result.\"\"\"\n        result = self.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"scaffold\", \"decision-maker-handler\"],\n            standalone_mode=False,\n        )\n        self.assertEqual(result.exit_code, 0)\n\n\ndef _raise_exception(*args):\n    raise Exception()\n\n\nclass ScaffoldDmHandlerTestCase(TestCase):\n    \"\"\"Test case for _scaffold_dm_handler method.\"\"\"\n\n    def test__scaffold_dm_handler_already_exists(self):\n        \"\"\"Test _scaffold_dm_handler method dm handler already exists result.\"\"\"\n        dm_handler = {\"dm\": \"handler\"}\n        ctx = ContextMock()\n        ctx.agent_config.decision_maker_handler = dm_handler\n        with self.assertRaises(ClickException) as cm:\n            _scaffold_dm_handler(ctx)\n        self.assertEqual(\n            \"A decision maker handler specification already exists. Aborting...\",\n            str(cm.exception),\n        )\n\n    @mock.patch(\"aea.cli.scaffold.shutil.copyfile\", _raise_exception)\n    @mock.patch(\"aea.cli.scaffold.os.remove\")\n    def test__scaffold_dm_handler_exception(self, os_remove_mock, *mocks):\n        \"\"\"Test _scaffold_dm_handler method exception raised result.\"\"\"\n        dm_handler = {}\n        ctx = ContextMock()\n        ctx.agent_config.decision_maker_handler = dm_handler\n        with self.assertRaises(ClickException):\n            _scaffold_dm_handler(ctx)\n        os_remove_mock.assert_called_once()\n\n    @mock.patch(\"aea.cli.scaffold.shutil.copyfile\")\n    @mock.patch(\"aea.cli.scaffold.os.remove\")\n    @mock.patch(\"aea.cli.scaffold.open_file\", mock.mock_open())\n    @mock.patch(\"aea.cli.scaffold.Path\", return_value=\"Path\")\n    def test__scaffold_dm_handler_positive(self, *mocks):\n        \"\"\"Test _scaffold_dm_handler method for positive result.\"\"\"\n        dm_handler = {}\n        ctx = ContextMock()\n        ctx.agent_config.decision_maker_handler = dm_handler\n        ctx.agent_loader.dump = mock.Mock()\n        _scaffold_dm_handler(ctx)\n        ctx.agent_loader.dump.assert_called_once()\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_scaffold/test_error_handler.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This test module contains the tests for CLI scaffold generic methods and commands.\"\"\"\n\nfrom unittest import TestCase, mock\n\nfrom click import ClickException\n\nfrom aea.cli import cli\nfrom aea.cli.scaffold import _scaffold_error_handler\n\nfrom tests.conftest import CLI_LOG_OPTION, CliRunner\nfrom tests.test_aea.test_cli.tools_for_testing import ContextMock\n\n\n@mock.patch(\"aea.cli.scaffold._scaffold_error_handler\")\n@mock.patch(\"aea.cli.utils.decorators._check_aea_project\")\nclass ScaffoldErrorHandlerTestCase(TestCase):\n    \"\"\"Test case for CLI scaffold error handler command.\"\"\"\n\n    def setUp(self):\n        \"\"\"Set it up.\"\"\"\n        self.runner = CliRunner()\n\n    def test_scaffold_error_handler_command_positive(self, *mocks):\n        \"\"\"Test for CLI scaffold error handler command for positive result.\"\"\"\n        result = self.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"scaffold\", \"error-handler\"],\n            standalone_mode=False,\n        )\n        self.assertEqual(result.exit_code, 0)\n\n\ndef _raise_exception(*args):\n    raise Exception()\n\n\nclass ScaffoldErrHandlerTestCase(TestCase):\n    \"\"\"Test case for _scaffold_error_handler method.\"\"\"\n\n    def test__scaffold_error_handler_already_exists(self):\n        \"\"\"Test _scaffold_error_handler method dm handler already exists result.\"\"\"\n        err_handler = {\"err\": \"handler\"}\n        ctx = ContextMock()\n        ctx.agent_config.error_handler = err_handler\n        with self.assertRaises(ClickException) as cm:\n            _scaffold_error_handler(ctx)\n        self.assertEqual(\n            \"A error handler specification already exists. Aborting...\",\n            str(cm.exception),\n        )\n\n    @mock.patch(\"aea.cli.scaffold.shutil.copyfile\", _raise_exception)\n    @mock.patch(\"aea.cli.scaffold.os.remove\")\n    def test__scaffold_error_handler_exception(self, os_remove_mock, *mocks):\n        \"\"\"Test _scaffold_error_handler method exception raised result.\"\"\"\n        err_handler = {}\n        ctx = ContextMock()\n        ctx.agent_config.error_handler = err_handler\n        with self.assertRaises(ClickException):\n            _scaffold_error_handler(ctx)\n        os_remove_mock.assert_called_once()\n\n    @mock.patch(\"aea.cli.scaffold.shutil.copyfile\")\n    @mock.patch(\"aea.cli.scaffold.os.remove\")\n    @mock.patch(\"aea.cli.scaffold.open_file\", mock.mock_open())\n    @mock.patch(\"aea.cli.scaffold.Path\", return_value=\"Path\")\n    def test__scaffold_error_handler_positive(self, *mocks):\n        \"\"\"Test _scaffold_error_handler method for positive result.\"\"\"\n        err_handler = {}\n        ctx = ContextMock()\n        ctx.agent_config.error_handler = err_handler\n        ctx.agent_loader.dump = mock.Mock()\n        _scaffold_error_handler(ctx)\n        ctx.agent_loader.dump.assert_called_once()\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_scaffold/test_generic.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This test module contains the tests for CLI scaffold generic methods and commands.\"\"\"\n\nfrom unittest import TestCase, mock\n\nfrom aea.cli import cli\n\nfrom tests.conftest import CLI_LOG_OPTION, CliRunner\n\n\n@mock.patch(\"aea.cli.scaffold.scaffold_item\")\n@mock.patch(\"aea.cli.utils.decorators._check_aea_project\")\nclass ScaffoldContractCommandTestCase(TestCase):\n    \"\"\"Test case for CLI scaffold contract command.\"\"\"\n\n    def setUp(self):\n        \"\"\"Set it up.\"\"\"\n        self.runner = CliRunner()\n\n    def test_scaffold_contract_command_positive(self, *mocks):\n        \"\"\"Test for CLI scaffold contract command for positive result.\"\"\"\n        result = self.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"scaffold\", \"contract\", \"contract_name\"],\n            standalone_mode=False,\n        )\n        self.assertEqual(result.exit_code, 0)\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_scaffold/test_protocols.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This test module contains the tests for the `aea scaffold protocol` sub-command.\"\"\"\nimport filecmp\nimport json\nimport os\nimport shutil\nimport tempfile\nimport unittest.mock\nfrom pathlib import Path\nfrom unittest.mock import patch\n\nimport jsonschema\nimport yaml\nfrom jsonschema import Draft4Validator, ValidationError\n\nfrom aea import AEA_DIR\nfrom aea.cli import cli\nfrom aea.configurations.base import DEFAULT_PROTOCOL_CONFIG_FILE\nfrom aea.configurations.loader import make_jsonschema_base_uri\n\nfrom tests.conftest import (\n    AUTHOR,\n    CLI_LOG_OPTION,\n    CONFIGURATION_SCHEMA_DIR,\n    CliRunner,\n    PROTOCOL_CONFIGURATION_SCHEMA,\n    ROOT_DIR,\n)\n\n\nclass TestScaffoldProtocol:\n    \"\"\"Test that the command 'aea scaffold protocol' works correctly in correct preconditions.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.resource_name = \"myresource\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        dir_path = Path(\"packages\")\n        tmp_dir = cls.t / dir_path\n        src_dir = cls.cwd / Path(ROOT_DIR, dir_path)\n        shutil.copytree(str(src_dir), str(tmp_dir))\n        cls.schema = json.load(open(PROTOCOL_CONFIGURATION_SCHEMA))\n        cls.resolver = jsonschema.RefResolver(\n            make_jsonschema_base_uri(Path(CONFIGURATION_SCHEMA_DIR).absolute()),\n            cls.schema,\n        )\n        cls.validator = Draft4Validator(cls.schema, resolver=cls.resolver)\n\n        os.chdir(cls.t)\n        result = cls.runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n        assert result.exit_code == 0\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n        os.chdir(cls.agent_name)\n        # scaffold protocol\n        with patch(\"click.confirm\", return_value=True) as confirm_mock:\n            cls.result = cls.runner.invoke(\n                cli,\n                [*CLI_LOG_OPTION, \"scaffold\", \"protocol\", cls.resource_name],\n                standalone_mode=False,\n            )\n            confirm_mock.assert_called_once_with(\n                \"We highly recommend auto-generating protocols with the aea generate command. Do you really want to continue scaffolding?\"\n            )\n\n    def test_exit_code_equal_to_0(self):\n        \"\"\"Test that the exit code is equal to 0.\"\"\"\n        assert self.result.exit_code == 0\n\n    def test_resource_folder_contains_module_message(self):\n        \"\"\"Test that the resource folder contains scaffold message.py module.\"\"\"\n        p = Path(self.t, self.agent_name, \"protocols\", self.resource_name, \"message.py\")\n        original = Path(AEA_DIR, \"protocols\", \"scaffold\", \"message.py\")\n        assert filecmp.cmp(p, original)\n\n    def test_resource_folder_contains_module_protocol(self):\n        \"\"\"Test that the resource folder contains scaffold protocol.py module.\"\"\"\n        p = Path(\n            self.t, self.agent_name, \"protocols\", self.resource_name, \"serialization.py\"\n        )\n        original = Path(AEA_DIR, \"protocols\", \"scaffold\", \"serialization.py\")\n        assert filecmp.cmp(p, original)\n\n    def test_resource_folder_contains_configuration_file(self):\n        \"\"\"Test that the resource folder contains a good configuration file.\"\"\"\n        p = Path(\n            self.t,\n            self.agent_name,\n            \"protocols\",\n            self.resource_name,\n            DEFAULT_PROTOCOL_CONFIG_FILE,\n        )\n        config_file = yaml.safe_load(open(p))\n        self.validator.validate(instance=config_file)\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestScaffoldProtocolFailsWhenDirectoryAlreadyExists:\n    \"\"\"Test that the command 'aea scaffold protocol' fails when a folder with 'scaffold' name already.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.resource_name = \"myresource\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        dir_path = Path(\"packages\")\n        tmp_dir = cls.t / dir_path\n        src_dir = cls.cwd / Path(ROOT_DIR, dir_path)\n        shutil.copytree(str(src_dir), str(tmp_dir))\n\n        os.chdir(cls.t)\n        result = cls.runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n        assert result.exit_code == 0\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n        os.chdir(cls.agent_name)\n        # create a dummy 'myresource' folder\n        Path(cls.t, cls.agent_name, \"protocols\", cls.resource_name).mkdir(\n            exist_ok=False, parents=True\n        )\n        with patch(\"click.confirm\", return_value=True):\n            cls.result = cls.runner.invoke(\n                cli,\n                [*CLI_LOG_OPTION, \"scaffold\", \"protocol\", cls.resource_name],\n                standalone_mode=False,\n            )\n\n    def test_exit_code_equal_to_1(self):\n        \"\"\"Test that the exit code is equal to 1 (i.e. catchall for general errors).\"\"\"\n        assert self.result.exit_code == 1\n\n    def test_error_message_protocol_already_existing(self):\n        \"\"\"Test that the log error message is fixed.\n\n        The expected message is: 'A protocol with name '{protocol_name}' already exists. Aborting...'\n        \"\"\"\n        s = \"A protocol with this name already exists. Please choose a different name and try again.\"\n        assert self.result.exception.message == s\n\n    def test_resource_directory_exists(self):\n        \"\"\"Test that the resource directory still exists.\n\n        This means that after every failure, we make sure we restore the previous state.\n        \"\"\"\n        assert Path(self.t, self.agent_name, \"protocols\", self.resource_name).exists()\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestScaffoldProtocolFailsWhenProtocolAlreadyExists:\n    \"\"\"Test that the command 'aea add protocol' fails when the protocol already exists.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.resource_name = \"myresource\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        dir_path = Path(\"packages\")\n        tmp_dir = cls.t / dir_path\n        src_dir = cls.cwd / Path(ROOT_DIR, dir_path)\n        shutil.copytree(str(src_dir), str(tmp_dir))\n\n        os.chdir(cls.t)\n        result = cls.runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n        assert result.exit_code == 0\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n        os.chdir(cls.agent_name)\n        # add protocol first time\n        with patch(\"click.confirm\", return_value=True):\n            result = cls.runner.invoke(\n                cli,\n                [*CLI_LOG_OPTION, \"scaffold\", \"protocol\", cls.resource_name],\n                standalone_mode=False,\n            )\n            assert result.exit_code == 0\n            # scaffold protocol with the same protocol name\n\n            cls.result = cls.runner.invoke(\n                cli,\n                [*CLI_LOG_OPTION, \"scaffold\", \"protocol\", cls.resource_name],\n                standalone_mode=False,\n            )\n\n    def test_exit_code_equal_to_1(self):\n        \"\"\"Test that the exit code is equal to 1 (i.e. catchall for general errors).\"\"\"\n        assert self.result.exit_code == 1\n\n    def test_error_message_protocol_already_existing(self):\n        \"\"\"Test that the log error message is fixed.\n\n        The expected message is: 'A protocol with name '{protocol_name}' already exists. Aborting...'\n        \"\"\"\n        s = \"A protocol with name '{}' already exists. Aborting...\".format(\n            self.resource_name\n        )\n        assert s in self.result.exception.message\n\n    def test_resource_directory_exists(self):\n        \"\"\"Test that the resource directory still exists.\n\n        This means that after every failure, we make sure we restore the previous state.\n        \"\"\"\n        assert Path(self.t, self.agent_name, \"protocols\", self.resource_name).exists()\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestScaffoldProtocolFailsWhenConfigFileIsNotCompliant:\n    \"\"\"Test that the command 'aea scaffold protocol' fails when the configuration file is not compliant with the schema.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.resource_name = \"myresource\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        dir_path = Path(\"packages\")\n        tmp_dir = cls.t / dir_path\n        src_dir = cls.cwd / Path(ROOT_DIR, dir_path)\n        shutil.copytree(str(src_dir), str(tmp_dir))\n\n        os.chdir(cls.t)\n        result = cls.runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n        assert result.exit_code == 0\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n\n        # change the dumping of yaml module to raise an exception.\n        cls.patch = unittest.mock.patch(\n            \"yaml.dump\", side_effect=ValidationError(\"test error message\")\n        )\n        cls.patch.start()\n\n        os.chdir(cls.agent_name)\n        with patch(\"click.confirm\", return_value=True):\n            cls.result = cls.runner.invoke(\n                cli,\n                [*CLI_LOG_OPTION, \"scaffold\", \"protocol\", cls.resource_name],\n                standalone_mode=False,\n            )\n\n    def test_exit_code_equal_to_1(self):\n        \"\"\"Test that the exit code is equal to 1 (i.e. catchall for general errors).\"\"\"\n        assert self.result.exit_code == 1\n\n    def test_configuration_file_not_valid(self):\n        \"\"\"Test that the log error message is fixed.\n\n        The expected message is: 'Cannot find protocol: '{protocol_name}'\n        \"\"\"\n        s = \"Error when validating the protocol configuration file.\"\n        assert self.result.exception.message == s\n\n    def test_resource_directory_does_not_exists(self):\n        \"\"\"Test that the resource directory does not exist.\n\n        This means that after every failure, we make sure we restore the previous state.\n        \"\"\"\n        assert not Path(\n            self.t, self.agent_name, \"protocols\", self.resource_name\n        ).exists()\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        cls.patch.stop()\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestScaffoldProtocolFailsWhenExceptionOccurs:\n    \"\"\"Test that the command 'aea scaffold protocol' fails when the configuration file is not compliant with the schema.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.resource_name = \"myresource\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        dir_path = Path(\"packages\")\n        tmp_dir = cls.t / dir_path\n        src_dir = cls.cwd / Path(ROOT_DIR, dir_path)\n        shutil.copytree(str(src_dir), str(tmp_dir))\n\n        os.chdir(cls.t)\n        result = cls.runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n        assert result.exit_code == 0\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n\n        cls.patch = unittest.mock.patch(\n            \"shutil.copytree\", side_effect=Exception(\"unknwon exception\")\n        )\n        cls.patch.start()\n\n        os.chdir(cls.agent_name)\n        with patch(\"click.confirm\", return_value=True):\n            cls.result = cls.runner.invoke(\n                cli,\n                [*CLI_LOG_OPTION, \"scaffold\", \"protocol\", cls.resource_name],\n                standalone_mode=False,\n            )\n\n    def test_exit_code_equal_to_1(self):\n        \"\"\"Test that the exit code is equal to 1 (i.e. catchall for general errors).\"\"\"\n        assert self.result.exit_code == 1\n\n    def test_resource_directory_does_not_exists(self):\n        \"\"\"Test that the resource directory does not exist.\n\n        This means that after every failure, we make sure we restore the previous state.\n        \"\"\"\n        assert not Path(\n            self.t, self.agent_name, \"protocols\", self.resource_name\n        ).exists()\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        cls.patch.stop()\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_scaffold/test_skills.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This test module contains the tests for the `aea scaffold skill` sub-command.\"\"\"\n\nimport filecmp\nimport json\nimport os\nimport re\nimport shutil\nimport tempfile\nimport unittest.mock\nfrom pathlib import Path\n\nimport jsonschema\nimport yaml\nfrom jsonschema import Draft4Validator, ValidationError\n\nfrom aea import AEA_DIR\nfrom aea.cli import cli\nfrom aea.configurations.base import DEFAULT_SKILL_CONFIG_FILE, DEFAULT_VERSION\nfrom aea.configurations.loader import make_jsonschema_base_uri\n\nfrom tests.conftest import (\n    AUTHOR,\n    CLI_LOG_OPTION,\n    CONFIGURATION_SCHEMA_DIR,\n    CliRunner,\n    ROOT_DIR,\n    SKILL_CONFIGURATION_SCHEMA,\n)\n\n\nclass TestScaffoldSkill:\n    \"\"\"Test that the command 'aea scaffold skill' works correctly in correct preconditions.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.resource_name = \"myresource\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        dir_path = Path(\"packages\")\n        tmp_dir = cls.t / dir_path\n        src_dir = cls.cwd / Path(ROOT_DIR, dir_path)\n        shutil.copytree(str(src_dir), str(tmp_dir))\n\n        cls.schema = json.load(open(SKILL_CONFIGURATION_SCHEMA))\n        cls.resolver = jsonschema.RefResolver(\n            make_jsonschema_base_uri(Path(CONFIGURATION_SCHEMA_DIR).absolute()),\n            cls.schema,\n        )\n        cls.validator = Draft4Validator(cls.schema, resolver=cls.resolver)\n\n        os.chdir(cls.t)\n        result = cls.runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n        assert result.exit_code == 0\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n        os.chdir(cls.agent_name)\n        # scaffold skill\n        cls.result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"scaffold\", \"skill\", cls.resource_name],\n            standalone_mode=False,\n        )\n\n    def test_exit_code_equal_to_0(self):\n        \"\"\"Test that the exit code is equal to 0.\"\"\"\n        assert self.result.exit_code == 0\n\n    def test_resource_folder_contains_module_handlers(self):\n        \"\"\"Test that the resource folder contains scaffold handlers.py module.\"\"\"\n        p = Path(self.t, self.agent_name, \"skills\", self.resource_name, \"handlers.py\")\n        original = Path(AEA_DIR, \"skills\", \"scaffold\", \"handlers.py\")\n        assert filecmp.cmp(p, original)\n\n    def test_resource_folder_contains_module_behaviours(self):\n        \"\"\"Test that the resource folder contains scaffold behaviours.py module.\"\"\"\n        p = Path(self.t, self.agent_name, \"skills\", self.resource_name, \"behaviours.py\")\n        original = Path(AEA_DIR, \"skills\", \"scaffold\", \"behaviours.py\")\n        assert filecmp.cmp(p, original)\n\n    def test_resource_folder_contains_module_model(self):\n        \"\"\"Test that the resource folder contains scaffold my_model.py module.\"\"\"\n        p = Path(self.t, self.agent_name, \"skills\", self.resource_name, \"my_model.py\")\n        original = Path(AEA_DIR, \"skills\", \"scaffold\", \"my_model.py\")\n        assert filecmp.cmp(p, original)\n\n    def test_resource_folder_contains_configuration_file(self):\n        \"\"\"Test that the resource folder contains a good configuration file.\"\"\"\n        p = Path(\n            self.t,\n            self.agent_name,\n            \"skills\",\n            self.resource_name,\n            DEFAULT_SKILL_CONFIG_FILE,\n        )\n        config_file = yaml.safe_load(open(p))\n        self.validator.validate(instance=config_file)\n\n    def test_init_module_contains_new_public_id(self):\n        \"\"\"Test that the PUBLIC ID variable in the init module is replaced correctly.\"\"\"\n        p = Path(self.t, self.agent_name, \"skills\", self.resource_name, \"__init__.py\")\n        init_module_content = p.read_text()\n        expected_public_id = f\"{AUTHOR}/{self.resource_name}:{DEFAULT_VERSION}\"\n        matches = re.findall(\n            rf'^PUBLIC_ID = PublicId\\.from_str\\(\"{expected_public_id}\"\\)$',\n            init_module_content,\n            re.MULTILINE,\n        )\n        assert len(matches) == 1\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestScaffoldSkillFailsWhenDirectoryAlreadyExists:\n    \"\"\"Test that the command 'aea scaffold skill' fails when a folder with 'scaffold' name already.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.resource_name = \"myresource\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        dir_path = Path(\"packages\")\n        tmp_dir = cls.t / dir_path\n        src_dir = cls.cwd / Path(ROOT_DIR, dir_path)\n        shutil.copytree(str(src_dir), str(tmp_dir))\n\n        os.chdir(cls.t)\n        result = cls.runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n        assert result.exit_code == 0\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n        os.chdir(cls.agent_name)\n        # create a dummy 'myresource' folder\n        Path(cls.t, cls.agent_name, \"skills\", cls.resource_name).mkdir(\n            exist_ok=False, parents=True\n        )\n        cls.result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"scaffold\", \"skill\", cls.resource_name],\n            standalone_mode=False,\n        )\n\n    def test_exit_code_equal_to_1(self):\n        \"\"\"Test that the exit code is equal to 1 (i.e. catchall for general errors).\"\"\"\n        assert self.result.exit_code == 1\n\n    def test_error_message_skill_already_existing(self):\n        \"\"\"Test that the log error message is fixed.\n\n        The expected message is: 'A skill with name '{skill_name}' already exists. Aborting...'\n        \"\"\"\n        s = \"A skill with this name already exists. Please choose a different name and try again.\"\n        assert self.result.exception.message == s\n\n    def test_resource_directory_exists(self):\n        \"\"\"Test that the resource directory still exists.\n\n        This means that after every failure, we make sure we restore the previous state.\n        \"\"\"\n        assert Path(self.t, self.agent_name, \"skills\", self.resource_name).exists()\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestScaffoldSkillFailsWhenSkillAlreadyExists:\n    \"\"\"Test that the command 'aea add skill' fails when the skill already exists.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.resource_name = \"myresource\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        dir_path = Path(\"packages\")\n        tmp_dir = cls.t / dir_path\n        src_dir = cls.cwd / Path(ROOT_DIR, dir_path)\n        shutil.copytree(str(src_dir), str(tmp_dir))\n\n        os.chdir(cls.t)\n        result = cls.runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n        assert result.exit_code == 0\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n        os.chdir(cls.agent_name)\n        # add skill first time\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"scaffold\", \"skill\", cls.resource_name],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n        # scaffold skill with the same skill name\n        cls.result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"scaffold\", \"skill\", cls.resource_name],\n            standalone_mode=False,\n        )\n\n    def test_exit_code_equal_to_1(self):\n        \"\"\"Test that the exit code is equal to 1 (i.e. catchall for general errors).\"\"\"\n        assert self.result.exit_code == 1\n\n    def test_error_message_skill_already_existing(self):\n        \"\"\"Test that the log error message is fixed.\n\n        The expected message is: 'A skill with name '{skill_name}' already exists. Aborting...'\n        \"\"\"\n        s = \"A skill with name '{}' already exists. Aborting...\".format(\n            self.resource_name\n        )\n        assert self.result.exception.message == s\n\n    def test_resource_directory_exists(self):\n        \"\"\"Test that the resource directory still exists.\n\n        This means that after every failure, we make sure we restore the previous state.\n        \"\"\"\n        assert Path(self.t, self.agent_name, \"skills\", self.resource_name).exists()\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestScaffoldSkillFailsWhenConfigFileIsNotCompliant:\n    \"\"\"Test that the command 'aea scaffold skill' fails when the configuration file is not compliant with the schema.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.resource_name = \"myresource\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        dir_path = Path(\"packages\")\n        tmp_dir = cls.t / dir_path\n        src_dir = cls.cwd / Path(ROOT_DIR, dir_path)\n        shutil.copytree(str(src_dir), str(tmp_dir))\n\n        os.chdir(cls.t)\n        result = cls.runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n        assert result.exit_code == 0\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n\n        # change the dumping of yaml module to raise an exception.\n        cls.patch = unittest.mock.patch(\n            \"yaml.dump\",\n            side_effect=ValidationError(\"test error message\"),\n        )\n        cls.patch.start()\n\n        os.chdir(cls.agent_name)\n        cls.result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"scaffold\", \"skill\", cls.resource_name],\n            standalone_mode=False,\n        )\n\n    def test_exit_code_equal_to_1(self):\n        \"\"\"Test that the exit code is equal to 1 (i.e. catchall for general errors).\"\"\"\n        assert self.result.exit_code == 1\n\n    def test_configuration_file_not_valid(self):\n        \"\"\"Test that the log error message is fixed.\n\n        The expected message is: 'Cannot find skill: '{skill_name}'\n        \"\"\"\n        s = \"Error when validating the skill configuration file.\"\n        assert self.result.exception.message == s\n\n    def test_resource_directory_does_not_exists(self):\n        \"\"\"Test that the resource directory does not exist.\n\n        This means that after every failure, we make sure we restore the previous state.\n        \"\"\"\n        assert not Path(self.t, self.agent_name, \"skills\", self.resource_name).exists()\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        cls.patch.stop()\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestScaffoldSkillFailsWhenExceptionOccurs:\n    \"\"\"Test that the command 'aea scaffold skill' fails when the configuration file is not compliant with the schema.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.resource_name = \"myresource\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        dir_path = Path(\"packages\")\n        tmp_dir = cls.t / dir_path\n        src_dir = cls.cwd / Path(ROOT_DIR, dir_path)\n        shutil.copytree(str(src_dir), str(tmp_dir))\n\n        os.chdir(cls.t)\n        result = cls.runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n        assert result.exit_code == 0\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n\n        cls.patch = unittest.mock.patch(\n            \"shutil.copytree\", side_effect=Exception(\"unknwon exception\")\n        )\n        cls.patch.start()\n\n        os.chdir(cls.agent_name)\n        cls.result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"scaffold\", \"skill\", cls.resource_name],\n            standalone_mode=False,\n        )\n\n    def test_exit_code_equal_to_1(self):\n        \"\"\"Test that the exit code is equal to 1 (i.e. catchall for general errors).\"\"\"\n        assert self.result.exit_code == 1\n\n    def test_resource_directory_does_not_exists(self):\n        \"\"\"Test that the resource directory does not exist.\n\n        This means that after every failure, we make sure we restore the previous state.\n        \"\"\"\n        assert not Path(self.t, self.agent_name, \"skills\", self.resource_name).exists()\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        cls.patch.stop()\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_search.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This test module contains the tests for the `aea search` sub-command.\"\"\"\n\nimport json\nimport os\nimport shutil\nimport tempfile\nfrom pathlib import Path\nfrom unittest import TestCase, mock\n\nimport jsonschema\nimport pytest\nfrom jsonschema import Draft4Validator\n\nfrom aea.cli import cli\n\nfrom packages.fetchai.skills.echo import PUBLIC_ID as ECHO_SKILL_PUBLIC_ID\nfrom packages.fetchai.skills.error import PUBLIC_ID as ERROR_SKILL_PUBLIC_ID\n\nfrom tests.conftest import (\n    AGENT_CONFIGURATION_SCHEMA,\n    AUTHOR,\n    CLI_LOG_OPTION,\n    CONFIGURATION_SCHEMA_DIR,\n    CliRunner,\n    MAX_FLAKY_RERUNS,\n    ROOT_DIR,\n)\nfrom tests.test_aea.test_cli.constants import FORMAT_ITEMS_SAMPLE_OUTPUT\n\n\nclass TestSearchProtocolsLocal:\n    \"\"\"Test that the command 'aea search protocols' works as expected.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n\n    @mock.patch(\"aea.cli.search.format_items\", return_value=FORMAT_ITEMS_SAMPLE_OUTPUT)\n    def test_correct_output_default_registry(self, _):\n        \"\"\"Test that the command has printed the correct output when using the default registry.\"\"\"\n        self.result = self.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"search\", \"--local\", \"protocols\"],\n            standalone_mode=False,\n        )\n        assert self.result.output == (\n            'Searching for \"\"...\\n'\n            \"Protocols found:\\n\\n\"\n            \"{}\\n\".format(FORMAT_ITEMS_SAMPLE_OUTPUT)\n        )\n\n\nclass TestSearchContractsLocal(TestCase):\n    \"\"\"Test that the command 'aea search contracts' works as expected.\"\"\"\n\n    def setUp(self):\n        \"\"\"Set the test up.\"\"\"\n        self.runner = CliRunner()\n\n    @mock.patch(\"aea.cli.search.format_items\", return_value=FORMAT_ITEMS_SAMPLE_OUTPUT)\n    @mock.patch(\"aea.cli.search._search_items_locally\", return_value=[\"item1\"])\n    def test_search_contracts_positive(self, *mocks):\n        \"\"\"Test search contracts command positive result.\"\"\"\n        result = self.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"search\", \"--local\", \"contracts\"],\n            standalone_mode=False,\n        )\n        assert result.output == (\n            'Searching for \"\"...\\n'\n            \"Contracts found:\\n\\n\"\n            \"{}\\n\".format(FORMAT_ITEMS_SAMPLE_OUTPUT)\n        )\n\n    @mock.patch(\"aea.cli.search.format_items\", return_value=FORMAT_ITEMS_SAMPLE_OUTPUT)\n    @mock.patch(\n        \"aea.cli.search.request_api\", return_value={\"results\": [\"item1\"], \"count\": 1}\n    )\n    def test_search_contracts_registry_positive(self, *mocks):\n        \"\"\"Test search contracts in registry command positive result.\"\"\"\n        result = self.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"search\", \"contracts\"],\n            standalone_mode=False,\n        )\n        assert result.output == (\n            'Searching for \"\"...\\n'\n            \"Contracts found:\\n\\n\"\n            \"{}\\n\".format(FORMAT_ITEMS_SAMPLE_OUTPUT)\n        )\n\n\nclass TestSearchConnectionsLocal:\n    \"\"\"Test that the command 'aea search connections' works as expected.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n\n    @mock.patch(\"aea.cli.search.format_items\", return_value=FORMAT_ITEMS_SAMPLE_OUTPUT)\n    def test_correct_output_default_registry(self, _):\n        \"\"\"Test that the command has printed the correct output when using the default registry.\"\"\"\n        self.result = self.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"search\", \"--local\", \"connections\"],\n            standalone_mode=False,\n        )\n        assert self.result.output == (\n            'Searching for \"\"...\\n'\n            \"Connections found:\\n\\n\"\n            \"{}\\n\".format(FORMAT_ITEMS_SAMPLE_OUTPUT)\n        )\n\n\n@pytest.mark.flaky(reruns=MAX_FLAKY_RERUNS)\nclass TestSearchSkillsLocal:\n    \"\"\"Test that the command 'aea search skills' works as expected.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n\n    @mock.patch(\"aea.cli.search.format_items\", return_value=FORMAT_ITEMS_SAMPLE_OUTPUT)\n    def test_correct_output_default_registry(self, _):\n        \"\"\"Test that the command has printed the correct output when using the default registry.\"\"\"\n        self.result = self.runner.invoke(\n            cli, [*CLI_LOG_OPTION, \"search\", \"--local\", \"skills\"], standalone_mode=False\n        )\n        assert self.result.output == (\n            'Searching for \"\"...\\n'\n            \"Skills found:\\n\\n\"\n            \"{}\\n\".format(FORMAT_ITEMS_SAMPLE_OUTPUT)\n        )\n\n\nclass TestSearchAgentsLocal:\n    \"\"\"Test that the command 'aea search agents' works as expected.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.schema = json.load(open(AGENT_CONFIGURATION_SCHEMA))\n        cls.resolver = jsonschema.RefResolver(\n            \"file://{}/\".format(Path(CONFIGURATION_SCHEMA_DIR).absolute()), cls.schema\n        )\n        cls.validator = Draft4Validator(cls.schema, resolver=cls.resolver)\n\n        cls.cwd = os.getcwd()\n        cls.runner = CliRunner()\n\n        cls.t = tempfile.mkdtemp()\n        dir_path = Path(\"packages\")\n        tmp_dir = cls.t / dir_path\n        src_dir = cls.cwd / Path(ROOT_DIR, dir_path)\n        shutil.copytree(str(src_dir), str(tmp_dir))\n        os.chdir(cls.t)\n        cls.cli_config_file = f\"{cls.t}/cli_config.yaml\"\n        cls.cli_config_patch = mock.patch(\n            \"aea.cli.utils.config.CLI_CONFIG_PATH\", cls.cli_config_file\n        )\n        cls.cli_config_patch.start()\n        result = cls.runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n        assert result.exit_code == 0\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", \"myagent\"],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n\n        os.chdir(Path(cls.t, \"myagent\"))\n        result = cls.runner.invoke(\n            cli,\n            [\n                *CLI_LOG_OPTION,\n                \"config\",\n                \"set\",\n                \"agent.description\",\n                \"Some description.\",\n            ],\n            standalone_mode=False,\n            catch_exceptions=False,\n        )\n        assert result.exit_code == 0\n        result = cls.runner.invoke(\n            cli, [*CLI_LOG_OPTION, \"publish\", \"--local\"], standalone_mode=False\n        )\n        assert result.exit_code == 0\n        cls.result = cls.runner.invoke(\n            cli, [*CLI_LOG_OPTION, \"search\", \"--local\", \"agents\"], standalone_mode=False\n        )\n\n    def test_correct_output_default_registry(self):\n        \"\"\"Test that the command has printed the correct output when using the default registry.\"\"\"\n        expected = [\n            ('Searching for \"\"...\\n' \"Agents found:\\n\\n\"),\n            (\n                \"------------------------------\\n\"\n                \"Public ID: default_author/myagent:0.1.0\\n\"\n                \"Name: myagent\\n\"\n                \"Description: Some description.\\n\"\n                \"Author: default_author\\n\"\n                \"Version: 0.1.0\\n\"\n                \"------------------------------\\n\\n\"\n            ),\n        ]\n        assert [strings in self.result.output for strings in expected]\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        cls.cli_config_patch.stop()\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\n@mock.patch(\n    \"aea.cli.search.request_api\",\n    return_value={\"results\": [\"correct\", \"results\"], \"count\": 2},\n)\n@mock.patch(\"aea.cli.search.format_items\", return_value=FORMAT_ITEMS_SAMPLE_OUTPUT)\nclass RegistrySearchTestCase(TestCase):\n    \"\"\"Test case for search --registry CLI command.\"\"\"\n\n    def setUp(self):\n        \"\"\"Set it up.\"\"\"\n        self.runner = CliRunner()\n\n    def test_search_connections_positive(self, format_items_mock, request_api_mock):\n        \"\"\"Test for CLI search --registry connections positive result.\"\"\"\n        result = self.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"search\", \"connections\", \"--query=some\"],\n            standalone_mode=False,\n        )\n        expected_output = (\n            'Searching for \"some\"...\\n'\n            \"Connections found:\\n\\n\"\n            \"{}\\n\".format(FORMAT_ITEMS_SAMPLE_OUTPUT)\n        )\n        self.assertEqual(result.output, expected_output)\n        request_api_mock.assert_called_once_with(\n            \"GET\", \"/connections\", params={\"search\": \"some\", \"page\": 1}\n        )\n        format_items_mock.assert_called_once_with([\"correct\", \"results\"])\n\n    def test_search_agents_positive(self, format_items_mock, request_api_mock):\n        \"\"\"Test for CLI search --registry agents positive result.\"\"\"\n        result = self.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"search\", \"agents\", \"--query=some\"],\n            standalone_mode=False,\n        )\n        expected_output = (\n            'Searching for \"some\"...\\n'\n            \"Agents found:\\n\\n\"\n            \"{}\\n\".format(FORMAT_ITEMS_SAMPLE_OUTPUT)\n        )\n        self.assertEqual(result.output, expected_output)\n        request_api_mock.assert_called_once_with(\n            \"GET\", \"/agents\", params={\"search\": \"some\", \"page\": 1}\n        )\n        format_items_mock.assert_called_once_with([\"correct\", \"results\"])\n\n    def test_search_protocols_positive(self, format_items_mock, request_api_mock):\n        \"\"\"Test for CLI search --registry protocols positive result.\"\"\"\n        result = self.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"search\", \"protocols\", \"--query=some\"],\n            standalone_mode=False,\n        )\n        expected_output = (\n            'Searching for \"some\"...\\n'\n            \"Protocols found:\\n\\n\"\n            \"{}\\n\".format(FORMAT_ITEMS_SAMPLE_OUTPUT)\n        )\n        self.assertEqual(result.output, expected_output)\n        request_api_mock.assert_called_once_with(\n            \"GET\", \"/protocols\", params={\"search\": \"some\", \"page\": 1}\n        )\n        format_items_mock.assert_called_once_with([\"correct\", \"results\"])\n\n    def test_search_skills_positive(self, format_items_mock, request_api_mock):\n        \"\"\"Test for CLI search --registry skills positive result.\"\"\"\n        result = self.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"search\", \"skills\", \"--query=some\"],\n            standalone_mode=False,\n        )\n        expected_output = (\n            'Searching for \"some\"...\\n'\n            \"Skills found:\\n\\n\"\n            \"{}\\n\".format(FORMAT_ITEMS_SAMPLE_OUTPUT)\n        )\n        self.assertEqual(result.output, expected_output)\n        request_api_mock.assert_called_once_with(\n            \"GET\", \"/skills\", params={\"search\": \"some\", \"page\": 1}\n        )\n        format_items_mock.assert_called_once_with([\"correct\", \"results\"])\n\n\nclass TestSearchWithRegistryInSubfolderLocal:\n    \"\"\"Test the search when the registry directory is a subfolder of the current path.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.cwd = os.getcwd()\n        cls.runner = CliRunner()\n        cls.t = tempfile.mkdtemp()\n        os.chdir(cls.t)\n\n        # copy the packages directory in the temporary test directory.\n        shutil.copytree(Path(ROOT_DIR, \"packages\"), Path(cls.t, \"packages\"))\n\n        # remove all the skills except the echo and error skill (to make testing easier).\n        for p in Path(cls.t, \"packages\", \"fetchai\", \"skills\").iterdir():\n            if p.name not in [\"echo\", \"error\"] and p.is_dir():\n                shutil.rmtree(p)\n\n        cls.result = cls.runner.invoke(\n            cli, [*CLI_LOG_OPTION, \"search\", \"--local\", \"skills\"], standalone_mode=False\n        )\n\n    def test_exit_code_equal_to_zero(self):\n        \"\"\"Test that the exit code is equal to 0 (i.e. success).\"\"\"\n        assert self.result.exit_code == 0\n\n    def test_correct_output(\n        self,\n    ):\n        \"\"\"Test that the command has printed the correct output..\"\"\"\n        public_id_echo = ECHO_SKILL_PUBLIC_ID\n        public_id_error = ERROR_SKILL_PUBLIC_ID\n        expected = [\n            ('Searching for \"\"...\\n' \"Skills found:\\n\\n\"),\n            (\n                \"------------------------------\\n\"\n                \"Public ID: {}\\n\"\n                \"Name: echo\\n\"\n                \"Description: The echo skill implements simple echo functionality.\\n\"\n                \"Author: fetchai\\n\"\n                \"Version: {}\\n\"\n                \"------------------------------\\n\"\n            ).format(str(public_id_echo), str(public_id_echo.version)),\n            (\n                \"------------------------------\\n\"\n                \"Public ID: {}\\n\"\n                \"Name: error\\n\"\n                \"Description: The error skill implements basic error handling required by all AEAs.\\n\"\n                \"Author: fetchai\\n\"\n                \"Version: {}\\n\"\n                \"------------------------------\\n\\n\"\n            ).format(\n                str(public_id_error),\n                str(public_id_error.version),\n            ),\n        ]\n        assert [strings in self.result.output for strings in expected]\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestSearchInAgentDirectoryLocal:\n    \"\"\"Test the search when we are in the agent directory.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.cwd = os.getcwd()\n        cls.runner = CliRunner()\n        cls.t = tempfile.mkdtemp()\n        os.chdir(cls.t)\n\n        # copy the packages directory in the temporary test directory.\n        shutil.copytree(Path(ROOT_DIR, \"packages\"), Path(cls.t, \"packages\"))\n\n        # remove all the skills except the echo and error skill (to make testing easier).\n        for p in Path(cls.t, \"packages\", \"fetchai\", \"skills\").iterdir():\n            if p.name not in [\"echo\", \"error\"] and p.is_dir():\n                shutil.rmtree(p)\n\n        result = cls.runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n        assert result.exit_code == 0\n\n        # create an AEA proejct and enter into it.\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", \"myagent\"],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n        os.chdir(Path(cls.t, \"myagent\"))\n\n        cls.result = cls.runner.invoke(\n            cli, [*CLI_LOG_OPTION, \"search\", \"--local\", \"skills\"], standalone_mode=False\n        )\n\n    def test_exit_code_equal_to_zero(self):\n        \"\"\"Test that the exit code is equal to 0 (i.e. success).\"\"\"\n        assert self.result.exit_code == 0\n\n    def test_correct_output(\n        self,\n    ):\n        \"\"\"Test that the command has printed the correct output..\"\"\"\n        public_id_echo = ECHO_SKILL_PUBLIC_ID\n        public_id_error = ERROR_SKILL_PUBLIC_ID\n        expected = [\n            ('Searching for \"\"...\\n' \"Skills found:\\n\\n\"),\n            (\n                \"------------------------------\\n\"\n                \"Public ID: {}\\n\"\n                \"Name: echo\\n\"\n                \"Description: The echo skill implements simple echo functionality.\\n\"\n                \"Author: fetchai\\n\"\n                \"Version: {}\\n\"\n                \"------------------------------\\n\"\n            ).format(str(public_id_echo), str(public_id_echo.version)),\n            (\n                \"------------------------------\\n\"\n                \"Public ID: {}\\n\"\n                \"Name: error\\n\"\n                \"Description: The error skill implements basic error handling required by all AEAs.\\n\"\n                \"Author: fetchai\\n\"\n                \"Version: {}\\n\"\n                \"------------------------------\\n\\n\"\n            ).format(\n                str(public_id_error),\n                str(public_id_error.version),\n            ),\n        ]\n        assert [strings in self.result.output for strings in expected]\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_transfer.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This test module contains the tests for commands in aea.cli.transfer module.\"\"\"\nimport random\nimport string\nfrom pathlib import Path\nfrom typing import List, Optional\nfrom unittest.mock import patch\n\nimport pytest\nfrom aea_ledger_cosmos import CosmosCrypto\nfrom aea_ledger_fetchai import FetchAICrypto\nfrom click.exceptions import ClickException\n\nfrom aea.cli.transfer import wait_tx_settled\nfrom aea.cli.utils.package_utils import try_get_balance\nfrom aea.configurations.manager import AgentConfigManager\nfrom aea.crypto.helpers import get_wallet_from_agent_config, private_key_verify\nfrom aea.helpers.base import cd\nfrom aea.test_tools.test_cases import AEATestCaseEmpty\n\nfrom tests.common.utils import wait_for_condition\nfrom tests.conftest import MAX_FLAKY_RERUNS\n\n\nclass TestCliTransferFetchAINetwork(AEATestCaseEmpty):\n    \"\"\"Test cli transfer command.\"\"\"\n\n    LEDGER_ID = FetchAICrypto.identifier\n    ANOTHER_LEDGER_ID = CosmosCrypto.identifier\n    PASSWORD: Optional[str] = None\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set up the test class.\"\"\"\n        super(TestCliTransferFetchAINetwork, cls).setup_class()\n        cls.agent_name2 = \"agent_\" + \"\".join(\n            random.choices(string.ascii_lowercase, k=5)  # nosec\n        )\n        cls.create_agents(cls.agent_name2)\n\n        cls.gen_key(cls.agent_name)\n        cls.gen_key(cls.agent_name2)\n\n    @classmethod\n    def gen_key(cls, agent_name: str) -> None:\n        \"\"\"Generate crypto key.\"\"\"\n        cls.set_agent_context(agent_name)\n        key_file = f\"{cls.LEDGER_ID}.key\"\n        password_options = cls.get_password_args(cls.PASSWORD)\n        assert cls.run_cli_command(\n            \"generate-key\",\n            cls.LEDGER_ID,\n            key_file,\n            *password_options,\n            cwd=cls._get_cwd(),\n        )\n        assert cls.run_cli_command(\n            \"add-key\", cls.LEDGER_ID, key_file, *password_options, cwd=cls._get_cwd()\n        )\n\n    @classmethod\n    def get_password_args(cls, password: Optional[str]) -> List[str]:\n        \"\"\"Get password arguments.\"\"\"\n        return [] if password is None else [\"--password\", password]\n\n    def get_balance(self) -> int:\n        \"\"\"Get balance for current agent.\"\"\"\n        with cd(self._get_cwd()):\n            agent_config = AgentConfigManager.verify_private_keys(\n                Path(\".\"),\n                substitude_env_vars=False,\n                private_key_helper=private_key_verify,\n                password=self.PASSWORD,\n            ).agent_config\n            wallet = get_wallet_from_agent_config(agent_config, password=self.PASSWORD)\n            return int(try_get_balance(agent_config, wallet, self.LEDGER_ID))\n\n    @pytest.mark.flaky(reruns=MAX_FLAKY_RERUNS)\n    def test_integration(self):\n        \"\"\"Perform integration tests of cli transfer command with real transfer.\"\"\"\n        self.set_agent_context(self.agent_name2)\n        password_option = self.get_password_args(self.PASSWORD)\n        agent2_original_balance = self.get_balance()\n        agent2_address = self.get_address(self.LEDGER_ID, self.PASSWORD)\n\n        self.set_agent_context(self.agent_name)\n        agent1_original_balance = self.get_balance()\n        self.generate_wealth(password=self.PASSWORD)\n\n        wait_for_condition(\n            lambda: self.get_balance() > agent1_original_balance, timeout=15, period=0.1\n        )\n\n        agent1_balance = self.get_balance()\n        assert agent1_balance > agent1_original_balance\n\n        amount = round(agent1_balance / 10)\n        fee = round(agent1_balance / 20)\n\n        self.invoke(\n            \"transfer\",\n            self.LEDGER_ID,\n            agent2_address,\n            str(amount),\n            str(fee),\n            \"-y\",\n            *password_option,\n        )\n\n        wait_for_condition(\n            lambda: self.get_balance() == (agent1_balance - amount - fee),\n            timeout=15,\n            period=0.1,\n        )\n\n        self.set_agent_context(self.agent_name2)\n        wait_for_condition(\n            lambda: self.get_balance() == (agent2_original_balance + amount),\n            timeout=15,\n            period=0.1,\n        )\n\n    @patch(\"aea.cli.transfer.do_transfer\", return_value=\"some_digest\")\n    @patch(\"aea.cli.transfer.click.confirm\", return_value=None)\n    @patch(\"aea.cli.transfer.wait_tx_settled\", return_value=None)\n    def test_yes_option_enabled(\n        self, wait_tx_settled_mock, confirm_mock, do_transfer_mock\n    ):\n        \"\"\"Test yes option is enabled.\"\"\"\n        password_option = self.get_password_args(self.PASSWORD)\n        self.invoke(\n            \"transfer\",\n            self.LEDGER_ID,\n            self.get_address(self.LEDGER_ID, self.PASSWORD),\n            \"100000\",\n            \"100\",\n            \"-y\",\n            *password_option,\n        )\n        confirm_mock.assert_not_called()\n\n    @patch(\"aea.cli.transfer.do_transfer\", return_value=\"some_digest\")\n    @patch(\"aea.cli.transfer.click.confirm\", return_value=None)\n    @patch(\"aea.cli.transfer.wait_tx_settled\", return_value=None)\n    def test_yes_option_disabled(\n        self, wait_tx_settled_mock, confirm_mock, do_transfer_mock\n    ):\n        \"\"\"Test yes option is disabled.\"\"\"\n        password_option = self.get_password_args(self.PASSWORD)\n        self.invoke(\n            \"transfer\",\n            self.LEDGER_ID,\n            self.get_address(self.LEDGER_ID, self.PASSWORD),\n            \"100000\",\n            \"100\",\n            *password_option,\n        )\n        confirm_mock.assert_called_once()\n\n    @patch(\"aea.cli.transfer.do_transfer\", return_value=\"some_digest\")\n    @patch(\"aea.cli.transfer.click.confirm\", return_value=None)\n    @patch(\"aea.cli.transfer.wait_tx_settled\", return_value=None)\n    def test_sync_option_enabled(\n        self, wait_tx_settled_mock, confirm_mock, do_transfer_mock\n    ):\n        \"\"\"Test sync option is enabled.\"\"\"\n        password_option = self.get_password_args(self.PASSWORD)\n        self.invoke(\n            \"transfer\",\n            self.LEDGER_ID,\n            self.get_address(self.LEDGER_ID, self.PASSWORD),\n            \"100000\",\n            \"100\",\n            \"-y\",\n            *password_option,\n        )\n        wait_tx_settled_mock.assert_not_called()\n\n    @patch(\"aea.cli.transfer.do_transfer\", return_value=\"some_digest\")\n    @patch(\"aea.cli.transfer.click.confirm\", return_value=None)\n    @patch(\"aea.cli.transfer.wait_tx_settled\", return_value=None)\n    def test_sync_option_disabled(\n        self, wait_tx_settled_mock, confirm_mock, do_transfer_mock\n    ):\n        \"\"\"Test sync option is disabled.\"\"\"\n        password_option = self.get_password_args(self.PASSWORD)\n        self.invoke(\n            \"transfer\",\n            self.LEDGER_ID,\n            self.get_address(self.LEDGER_ID, self.PASSWORD),\n            \"100000\",\n            \"100\",\n            \"-y\",\n            \"--sync\",\n            *password_option,\n        )\n        wait_tx_settled_mock.assert_called_once()\n\n    @patch(\"aea.cli.transfer.do_transfer\", return_value=None)\n    @patch(\"aea.cli.transfer.click.confirm\", return_value=None)\n    @patch(\"aea.cli.transfer.wait_tx_settled\", return_value=None)\n    def test_failed_on_send(self, wait_tx_settled_mock, confirm_mock, do_transfer_mock):\n        \"\"\"Test fail to send a transaction.\"\"\"\n        with pytest.raises(ClickException, match=r\"Failed to send a transaction!\"):\n            password_option = self.get_password_args(self.PASSWORD)\n            self.invoke(\n                \"transfer\",\n                self.LEDGER_ID,\n                self.get_address(self.LEDGER_ID, self.PASSWORD),\n                \"100000\",\n                \"100\",\n                *password_option,\n            )\n\n    @patch(\"aea.cli.transfer.click.confirm\", return_value=None)\n    @patch(\"aea.cli.transfer.wait_tx_settled\", return_value=None)\n    def test_no_wallet_registered(self, wait_tx_settled_mock, confirm_mock):\n        \"\"\"Test no wallet for crypto id registered.\"\"\"\n        password_option = self.get_password_args(self.PASSWORD)\n        with pytest.raises(\n            ClickException, match=r\"No private key registered for `.*` in wallet!\"\n        ):\n            self.invoke(\n                \"transfer\",\n                self.ANOTHER_LEDGER_ID,\n                self.get_address(self.LEDGER_ID, self.PASSWORD),\n                \"100000\",\n                \"100\",\n                *password_option,\n            )\n\n    @patch(\"aea.cli.transfer.try_get_balance\", return_value=10)\n    @patch(\"aea.cli.transfer.click.confirm\", return_value=None)\n    @patch(\"aea.cli.transfer.wait_tx_settled\", return_value=None)\n    def test_balance_too_low(\n        self, wait_tx_settled_mock, confirm_mock, do_transfer_mock\n    ):\n        \"\"\"Test balance too low exception.\"\"\"\n        password_option = self.get_password_args(self.PASSWORD)\n        with pytest.raises(\n            ClickException,\n            match=r\"Balance is not enough! Available=[0-9]+, required=[0-9]+!\",\n        ):\n            self.invoke(\n                \"transfer\",\n                self.LEDGER_ID,\n                self.get_address(self.LEDGER_ID, self.PASSWORD),\n                \"100000\",\n                \"100\",\n                *password_option,\n            )\n\n    @patch(\n        \"aea.cli.transfer.LedgerApis.is_transaction_settled\", side_effects=[False, True]\n    )\n    def test_wait_tx_settled_ok(self, is_transaction_settled_mock):\n        \"\"\"Test wait tx settle is ok.\"\"\"\n        wait_tx_settled(\"some\", \"some\", timeout=4)\n\n    @patch(\"aea.cli.transfer.LedgerApis.is_transaction_settled\", return_value=False)\n    def test_wait_tx_settled_timeout(self, is_transaction_settled_mock):\n        \"\"\"Test wait tx settle fails with timeout error.\"\"\"\n        with pytest.raises(TimeoutError):\n            wait_tx_settled(\"some\", \"some\", timeout=0.5)\n\n\nclass TestCliTransferFetchAINetworkWithPassword(TestCliTransferFetchAINetwork):\n    \"\"\"Test cli transfer command, with '--password' option.\"\"\"\n\n    PASSWORD = \"fake-password\"  # nosec\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_upgrade.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This test module contains the tests for the `aea add connection` sub-command.\"\"\"\nimport filecmp\nimport os\nimport shutil\nimport tempfile\nfrom contextlib import contextmanager\nfrom pathlib import Path\nfrom typing import List, Set, cast\nfrom unittest import mock\nfrom unittest.mock import MagicMock, patch\n\nimport pytest\nfrom click.exceptions import ClickException\nfrom click.testing import Result\nfrom packaging.version import Version\n\nimport aea\nfrom aea import get_current_aea_version\nfrom aea.cli import cli\nfrom aea.cli.registry.utils import get_latest_version_available_in_registry\nfrom aea.cli.upgrade import ItemRemoveHelper\nfrom aea.cli.utils.config import load_item_config\nfrom aea.configurations.base import (\n    AgentConfig,\n    ComponentId,\n    ComponentType,\n    DEFAULT_AEA_CONFIG_FILE,\n    PackageId,\n    PackageType,\n    PublicId,\n)\nfrom aea.configurations.constants import DEFAULT_README_FILE, DEFAULT_VERSION\nfrom aea.configurations.loader import ConfigLoader, load_component_configuration\nfrom aea.helpers.base import cd, compute_specifier_from_version\nfrom aea.test_tools.test_cases import AEATestCaseEmpty, BaseAEATestCase\n\nfrom packages.fetchai.connections import oef\nfrom packages.fetchai.connections.oef.connection import PUBLIC_ID as OEF_PUBLIC_ID\nfrom packages.fetchai.connections.soef.connection import PUBLIC_ID as SOEF_PUBLIC_ID\nfrom packages.fetchai.connections.stub.connection import StubConnection\nfrom packages.fetchai.contracts.erc1155.contract import PUBLIC_ID as ERC1155_PUBLIC_ID\nfrom packages.fetchai.protocols.default import DefaultMessage\nfrom packages.fetchai.protocols.http.message import HttpMessage\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.skills.echo import PUBLIC_ID as ECHO_SKILL_PUBLIC_ID\nfrom packages.fetchai.skills.error import PUBLIC_ID as ERROR_SKILL_PUBLIC_ID\n\nfrom tests.common.mocks import RegexComparator\nfrom tests.common.utils import are_dirs_equal, dircmp_recursive\nfrom tests.conftest import AUTHOR, CLI_LOG_OPTION, CUR_PATH, CliRunner\n\n\nclass BaseTestCase:\n    \"\"\"Base test case class with setup and teardown and some utils.\"\"\"\n\n    ITEM_TYPE = \"connection\"\n    ITEM_PUBLIC_ID = SOEF_PUBLIC_ID\n    LOCAL: List[str] = [\"--local\"]\n    DEPENDENCY_TYPE = \"protocol\"\n    DEPENDENCY_PUBLIC_ID = OefSearchMessage.protocol_id\n\n    @staticmethod\n    def loader() -> ConfigLoader:\n        \"\"\"Return Agent config loader.\"\"\"\n        return ConfigLoader.from_configuration_type(PackageType.AGENT)\n\n    def load_config(self) -> AgentConfig:\n        \"\"\"Load AgentConfig from current directory.\"\"\"\n        agent_loader = self.loader()\n        path = Path(DEFAULT_AEA_CONFIG_FILE)\n        with path.open(mode=\"r\", encoding=\"utf-8\") as fp:\n            agent_config = agent_loader.load(fp)\n        return agent_config\n\n    def load_mock_context(self) -> MagicMock:\n        \"\"\"Load mock context.\"\"\"\n        context_mock = MagicMock(agent_config=self.load_config())\n        return context_mock\n\n    def dump_config(self, agent_config: AgentConfig) -> None:\n        \"\"\"Dump AgentConfig to current directory.\"\"\"\n        agent_loader = self.loader()\n        path = Path(DEFAULT_AEA_CONFIG_FILE)\n\n        with path.open(mode=\"w\", encoding=\"utf-8\") as fp:\n            agent_loader.dump(agent_config, fp)\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.runner = CliRunner()\n        cls.agent_name = \"myagent\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        # copy the 'packages' directory in the parent of the agent folder.\n        shutil.copytree(Path(CUR_PATH, \"..\", \"packages\"), Path(cls.t, \"packages\"))\n\n        os.chdir(cls.t)\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n        result = cls.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"create\", \"--local\", cls.agent_name],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n        os.chdir(cls.agent_name)\n        # add connection first time\n\n    @contextmanager\n    def with_oef_installed(self):\n        \"\"\"Add and remove oef connection.\"\"\"\n        result = self.runner.invoke(\n            cli,\n            [\n                \"-v\",\n                \"DEBUG\",\n                \"add\",\n                \"--local\",\n                \"connection\",\n                str(oef.connection.PUBLIC_ID),\n            ],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n        try:\n            yield\n        finally:\n            result = self.runner.invoke(\n                cli,\n                [\"-v\", \"DEBUG\", \"remove\", \"connection\", str(oef.connection.PUBLIC_ID)],\n                standalone_mode=False,\n            )\n            assert result.exit_code == 0\n\n    @contextmanager\n    def with_config_update(self):\n        \"\"\"Context manager to update item version to 0.0.1.\"\"\"\n        original_config = self.load_config()\n\n        config_data = original_config.json\n        if str(self.ITEM_PUBLIC_ID) in config_data[f\"{self.ITEM_TYPE}s\"]:\n            config_data[f\"{self.ITEM_TYPE}s\"].remove(str(self.ITEM_PUBLIC_ID))\n        config_data[f\"{self.ITEM_TYPE}s\"].append(\n            f\"{self.ITEM_PUBLIC_ID.author}/{self.ITEM_PUBLIC_ID.name}:0.0.1\"\n        )\n        self.dump_config(AgentConfig.from_json(config_data))\n        try:\n            yield\n        finally:\n            self.dump_config(original_config)\n\n    @classmethod\n    def teardown(cls):\n        \"\"\"Tear the test down.\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestRemoveAndDependencies(BaseTestCase):\n    \"\"\"Test dependency remove helper and upgrade with dependency removed.\"\"\"\n\n    ITEM_TYPE = \"connection\"\n    ITEM_PUBLIC_ID = SOEF_PUBLIC_ID\n    LOCAL: List[str] = [\"--local\"]\n    DEPENDENCY_TYPE = \"protocol\"\n    DEPENDENCY_PUBLIC_ID = OefSearchMessage.protocol_id\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Set the test up.\"\"\"\n        super(TestRemoveAndDependencies, cls).setup()\n        cls.DEPENDENCY_PACKAGE_ID = PackageId(\n            cls.DEPENDENCY_TYPE, cls.DEPENDENCY_PUBLIC_ID\n        )\n        result = cls.runner.invoke(\n            cli,\n            [\"-v\", \"DEBUG\", \"add\", \"--local\", cls.ITEM_TYPE, str(cls.ITEM_PUBLIC_ID)],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n\n    def test_upgrade_and_dependency_removed(self):\n        \"\"\"\n        Test dependency removed after upgrade.\n\n        Done with mocking _add_item_deps to avoid dependencies installation.\n\n        Also checks dependency configuration removed with component\n        \"\"\"\n        assert self.DEPENDENCY_PUBLIC_ID in self.load_config().protocols\n\n        # add empty component config to aea-config.py\n        agent_config = self.load_config()\n        component_id = ComponentId(self.DEPENDENCY_TYPE, self.DEPENDENCY_PUBLIC_ID)\n        agent_config.component_configurations[component_id] = {}  # just empty\n        agent_config.component_configurations[\n            ComponentId(self.ITEM_TYPE, self.ITEM_PUBLIC_ID)\n        ] = {}  # just empty\n        self.dump_config(agent_config)\n\n        agent_config = self.load_config()\n        assert component_id in agent_config.component_configurations\n\n        with patch(\n            \"aea.cli.upgrade.ItemUpgrader.check_upgrade_is_required\",\n            return_value=self.ITEM_PUBLIC_ID.version,\n        ), patch(\"aea.cli.add._add_item_deps\"):\n            result = self.runner.invoke(\n                cli,\n                [\n                    \"-v\",\n                    \"DEBUG\",\n                    \"upgrade\",\n                    *self.LOCAL,\n                    self.ITEM_TYPE,\n                    f\"{self.ITEM_PUBLIC_ID.author}/{self.ITEM_PUBLIC_ID.name}:latest\",\n                ],\n                catch_exceptions=True,\n            )\n            try:\n                assert result.exit_code == 0\n\n                assert self.DEPENDENCY_PUBLIC_ID not in self.load_config().protocols\n                agent_config = self.load_config()\n\n                # check configuration was removed too\n                assert component_id not in agent_config.component_configurations\n                assert (\n                    ComponentId(self.ITEM_TYPE, self.ITEM_PUBLIC_ID)\n                    in agent_config.component_configurations\n                )\n            finally:\n                # restore component removed\n                result = self.runner.invoke(\n                    cli,\n                    [\n                        \"-v\",\n                        \"DEBUG\",\n                        \"add\",\n                        *self.LOCAL,\n                        self.DEPENDENCY_TYPE,\n                        f\"{self.DEPENDENCY_PUBLIC_ID.author}/{self.DEPENDENCY_PUBLIC_ID.name}:latest\",\n                    ],\n                    catch_exceptions=True,\n                )\n                assert self.DEPENDENCY_PUBLIC_ID in self.load_config().protocols\n\n    def test_upgrade_and_dependency_not_removed_caused_required_by_another_item(self):\n        \"\"\"Test dependency is not removed after upgrade cause required by another item.\"\"\"\n        assert self.DEPENDENCY_PUBLIC_ID in self.load_config().protocols\n        # do not add dependencies for the package\n\n        with self.with_oef_installed(), self.with_config_update(), patch(\n            \"aea.cli.add._add_item_deps\"\n        ):\n            result = self.runner.invoke(\n                cli,\n                [\n                    \"-v\",\n                    \"DEBUG\",\n                    \"upgrade\",\n                    *self.LOCAL,\n                    self.ITEM_TYPE,\n                    f\"{self.ITEM_PUBLIC_ID.author}/{self.ITEM_PUBLIC_ID.name}:latest\",\n                ],\n                catch_exceptions=True,\n            )\n            assert result.exit_code == 0\n            assert self.DEPENDENCY_PUBLIC_ID in self.load_config().protocols\n\n\nclass TestUpgradeSharedDependencies(AEATestCaseEmpty):\n    \"\"\"\n    Test removal of shared dependency.\n\n    The shared dependency in this test case is 'fetchai/oef_search:0.9.0'.\n    \"\"\"\n\n    IS_EMPTY = True\n    OLD_SOEF_ID = PublicId.from_str(\"fetchai/soef:0.16.0\")\n    OLD_OEF_SEARCH_ID = PublicId.from_str(\"fetchai/oef_search:0.13.0\")\n    OLD_OEF_ID = PublicId.from_str(\"fetchai/oef:0.16.0\")\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"\n        Set the test up.\n\n        Skip consistency checks to avoid aea version compatibility checks.\n        \"\"\"\n        super().setup_class()\n        result = cls.run_cli_command(\n            \"-s\", \"add\", \"connection\", str(cls.OLD_SOEF_ID), cwd=cls._get_cwd()\n        )\n        assert result.exit_code == 0\n        result = cls.run_cli_command(\n            \"-s\", \"add\", \"connection\", str(cls.OLD_OEF_ID), cwd=cls._get_cwd()\n        )\n        assert result.exit_code == 0\n\n    def test_upgrade_shared_dependencies(self):\n        \"\"\"Test upgrade shared dependencies.\"\"\"\n        result = self.run_cli_command(\"-s\", \"upgrade\", cwd=self._get_cwd())\n        assert result.exit_code == 0\n\n        agent_config: AgentConfig = cast(\n            AgentConfig,\n            load_item_config(PackageType.AGENT.value, Path(self.current_agent_context)),\n        )\n        assert OefSearchMessage.protocol_id in agent_config.protocols\n        assert SOEF_PUBLIC_ID in agent_config.connections\n        assert OEF_PUBLIC_ID in agent_config.connections\n\n\nclass TestUpgradeProject(BaseAEATestCase, BaseTestCase):\n    \"\"\"Test that the command 'aea upgrade' works.\"\"\"\n\n    capture_log = True\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Set up test case.\"\"\"\n        super(TestUpgradeProject, cls).setup()\n        cls.change_directory(Path(\"..\"))\n        cls.agent_name = \"generic_buyer\"\n        cls.latest_agent_name = \"generic_buyer_latest\"\n        cls.run_cli_command(\n            \"--skip-consistency-check\",\n            \"fetch\",\n            \"fetchai/generic_buyer:0.30.5\",\n            \"--alias\",\n            cls.agent_name,\n        )\n        cls.run_cli_command(\n            \"--skip-consistency-check\",\n            \"fetch\",\n            \"fetchai/generic_buyer:latest\",\n            \"--alias\",\n            cls.latest_agent_name,\n        )\n        cls.agents.add(cls.agent_name)\n        cls.set_agent_context(cls.agent_name)\n\n    def test_upgrade(self):\n        \"\"\"Test upgrade project old version to latest one and compare with latest project fetched.\"\"\"\n        with cd(self.latest_agent_name):\n            latest_agent_items = set(\n                ItemRemoveHelper(self.load_mock_context())\n                .get_agent_dependencies_with_reverse_dependencies()\n                .keys()\n            )\n\n        with cd(self.agent_name):\n            self.runner.invoke(  # pylint: disable=no-member\n                cli,\n                [\"--skip-consistency-check\", \"upgrade\", \"--local\"],\n                standalone_mode=False,\n                catch_exceptions=False,\n            )\n            agent_items = set(\n                ItemRemoveHelper(self.load_mock_context())\n                .get_agent_dependencies_with_reverse_dependencies()\n                .keys()\n            )\n            assert latest_agent_items == agent_items\n\n        # upgrade again to check it workd with upgraded version\n        with cd(self.agent_name):\n            self.runner.invoke(  # pylint: disable=no-member\n                cli,\n                [\"--skip-consistency-check\", \"upgrade\", \"--local\"],\n                standalone_mode=False,\n                catch_exceptions=False,\n            )\n            agent_items = set(\n                ItemRemoveHelper(self.load_mock_context())\n                .get_agent_dependencies_with_reverse_dependencies()\n                .keys()\n            )\n            assert latest_agent_items == agent_items\n\n        # compare both configuration files, except the agent name and the author\n        upgraded_agent_dir = Path(self.agent_name)\n        latest_agent_dir = Path(self.latest_agent_name)\n        lines_upgraded_agent_config = (\n            (upgraded_agent_dir / DEFAULT_AEA_CONFIG_FILE).read_text().splitlines()\n        )\n        lines_latest_agent_config = (\n            (latest_agent_dir / DEFAULT_AEA_CONFIG_FILE).read_text().splitlines()\n        )\n        # the slice is because we don't compare the agent name and the author name\n        assert lines_upgraded_agent_config[2:] == lines_latest_agent_config[2:]\n\n        # compare vendor folders.\n        assert are_dirs_equal(\n            upgraded_agent_dir / \"vendor\", latest_agent_dir / \"vendor\"\n        )\n\n\nclass TestNonVendorProject(BaseAEATestCase, BaseTestCase):\n    \"\"\"Test that the command 'aea upgrade' works.\"\"\"\n\n    capture_log = True\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Set up test case.\"\"\"\n        super(TestNonVendorProject, cls).setup()\n        cls.change_directory(Path(\"..\"))\n        cls.agent_name = \"generic_buyer\"\n        cls.run_cli_command(\n            \"fetch\", \"fetchai/generic_buyer:0.30.5\", \"--alias\", cls.agent_name\n        )\n        cls.agents.add(cls.agent_name)\n        cls.set_agent_context(cls.agent_name)\n\n    @patch(\"aea.cli.upgrade.ItemUpgrader.is_non_vendor\", True)\n    @patch(\n        \"aea.cli.upgrade.ItemUpgrader.check_upgrade_is_required\", return_value=\"0.99.0\"\n    )\n    @patch(\"aea.cli.upgrade.ItemUpgrader.remove_item\")\n    @patch(\"aea.cli.upgrade.ItemUpgrader.add_item\")\n    def test_non_vendor_nothing_to_upgrade(\n        self, *mocks\n    ):  # pylint: disable=unused-argument\n        \"\"\"Test upgrade project dependencies not removed cause non vendor.\"\"\"\n        with cd(self.agent_name):\n            base_agent_items = set(\n                ItemRemoveHelper(self.load_mock_context())\n                .get_agent_dependencies_with_reverse_dependencies()\n                .keys()\n            )\n\n            self.runner.invoke(  # pylint: disable=no-member\n                cli,\n                [\"--skip-consistency-check\", \"upgrade\"],\n                standalone_mode=False,\n                catch_exceptions=False,\n            )\n            agent_items = set(\n                ItemRemoveHelper(self.load_mock_context())\n                .get_agent_dependencies_with_reverse_dependencies()\n                .keys()\n            )\n            assert base_agent_items == agent_items\n\n\nclass TestUpgradeConnectionLocally(BaseTestCase):\n    \"\"\"Test that the command 'aea upgrade connection' works.\"\"\"\n\n    ITEM_TYPE = \"connection\"\n    ITEM_PUBLIC_ID = SOEF_PUBLIC_ID\n    LOCAL: List[str] = [\"--local\"]\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Set the test up.\"\"\"\n        super(TestUpgradeConnectionLocally, cls).setup()\n\n        result = cls.runner.invoke(\n            cli,\n            [\"-v\", \"DEBUG\", \"add\", \"--local\", cls.ITEM_TYPE, str(cls.ITEM_PUBLIC_ID)],\n            standalone_mode=False,\n        )\n        assert result.exit_code == 0\n\n    def test_upgrade_to_same_version(self):\n        \"\"\"Test do not  upgrade to version already installed.\"\"\"\n        with pytest.raises(\n            ClickException,\n            match=r\"The .* with id '.*' already has version .*. Nothing to upgrade.\",\n        ):\n            self.runner.invoke(\n                cli,\n                [\"upgrade\", *self.LOCAL, self.ITEM_TYPE, str(self.ITEM_PUBLIC_ID)],\n                standalone_mode=False,\n                catch_exceptions=False,\n            )\n\n    @patch(\"aea.cli.upgrade.ItemUpgrader.is_non_vendor\", True)\n    def test_upgrade_non_vendor(self):\n        \"\"\"Test do not upgrade non vendor package.\"\"\"\n        with pytest.raises(\n            ClickException,\n            match=r\"The .* with id '.*' already has version .*. Nothing to upgrade.\",\n        ):\n            self.runner.invoke(\n                cli,\n                [\n                    \"upgrade\",\n                    *self.LOCAL,\n                    self.ITEM_TYPE,\n                    f\"{self.ITEM_PUBLIC_ID.author}/{self.ITEM_PUBLIC_ID.name}:100.0.0\",\n                ],\n                standalone_mode=False,\n                catch_exceptions=False,\n            )\n\n    def test_upgrade_to_latest_but_same_version(self):\n        \"\"\"Test no update to latest if already latest component.\"\"\"\n        with pytest.raises(\n            ClickException,\n            match=r\"The .* with id '.*' already has version .*. Nothing to upgrade.\",\n        ):\n            self.runner.invoke(\n                cli,\n                [\n                    \"upgrade\",\n                    *self.LOCAL,\n                    self.ITEM_TYPE,\n                    f\"{self.ITEM_PUBLIC_ID.author}/{self.ITEM_PUBLIC_ID.name}:latest\",\n                ],\n                standalone_mode=False,\n                catch_exceptions=False,\n            )\n\n    def test_upgrade_to_non_registered(self):\n        \"\"\"Test can not upgrade not registered component.\"\"\"\n        with pytest.raises(\n            ClickException,\n            match=r\".* with id .* is not registered. Please use the `add` command. Aborting...\",\n        ):\n            self.runner.invoke(\n                cli,\n                [\n                    \"-v\",\n                    \"DEBUG\",\n                    \"upgrade\",\n                    *self.LOCAL,\n                    self.ITEM_TYPE,\n                    \"nonexits/dummy:0.0.0\",\n                ],\n                standalone_mode=False,\n                catch_exceptions=False,\n            )\n\n    def test_upgrade_required_mock(self):\n        \"\"\"Test upgrade with mocking upgrade required.\"\"\"\n        with patch(\n            \"aea.cli.upgrade.ItemUpgrader.check_upgrade_is_required\",\n            return_value=\"100.0.0\",\n        ):\n            result = self.runner.invoke(\n                cli,\n                [\n                    \"-v\",\n                    \"DEBUG\",\n                    \"upgrade\",\n                    *self.LOCAL,\n                    self.ITEM_TYPE,\n                    f\"{self.ITEM_PUBLIC_ID.author}/{self.ITEM_PUBLIC_ID.name}:latest\",\n                ],\n                catch_exceptions=False,\n            )\n            assert result.exit_code == 0\n\n    def test_do_upgrade(self):\n        \"\"\"Test real full upgrade.\"\"\"\n        with self.with_config_update():\n            result = self.runner.invoke(\n                cli,\n                [\n                    \"upgrade\",\n                    *self.LOCAL,\n                    self.ITEM_TYPE,\n                    f\"{self.ITEM_PUBLIC_ID.author}/{self.ITEM_PUBLIC_ID.name}:latest\",\n                ],\n                standalone_mode=False,\n            )\n            assert result.exit_code == 0\n\n    def test_package_can_not_be_found_in_registry(self):\n        \"\"\"Test no package in registry.\"\"\"\n        with self.with_config_update():\n            with patch(\n                \"aea.cli.registry.utils.get_package_meta\",\n                side_effects=Exception(\"expected!\"),\n            ), patch(\n                \"aea.cli.registry.utils.find_item_locally\",\n                side_effects=Exception(\"expected!\"),\n            ), pytest.raises(\n                ClickException,\n                match=r\"Package .* details can not be fetched from the registry!\",\n            ):\n                self.runner.invoke(\n                    cli,\n                    [\n                        \"upgrade\",\n                        *self.LOCAL,\n                        self.ITEM_TYPE,\n                        f\"{self.ITEM_PUBLIC_ID.author}/{self.ITEM_PUBLIC_ID.name}:latest\",\n                    ],\n                    standalone_mode=False,\n                    catch_exceptions=False,\n                )\n\n    def test_package_can_not_upgraded_cause_required(self):\n        \"\"\"Test no package in registry.\"\"\"\n        with self.with_config_update():\n            with patch(\n                \"aea.cli.upgrade.ItemRemoveHelper.check_remove\",\n                return_value=(\n                    set([PackageId(\"connection\", PublicId(\"test\", \"test\", \"0.0.1\"))]),\n                    set(),\n                    dict(),\n                ),\n            ), pytest.raises(\n                ClickException,\n                match=r\"Can not upgrade .* because it is required by '.*'\",\n            ):\n                self.runner.invoke(\n                    cli,\n                    [\n                        \"upgrade\",\n                        *self.LOCAL,\n                        self.ITEM_TYPE,\n                        f\"{self.ITEM_PUBLIC_ID.author}/{self.ITEM_PUBLIC_ID.name}:latest\",\n                    ],\n                    standalone_mode=False,\n                    catch_exceptions=False,\n                )\n\n    @classmethod\n    def teardown(cls):\n        \"\"\"Tear the test down.\"\"\"\n        super(TestUpgradeConnectionLocally, cls).teardown()\n\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestUpgradeConnectionRemoteRegistry(TestUpgradeConnectionLocally):\n    \"\"\"Test that the command 'aea upgrade connection' works.\"\"\"\n\n    LOCAL: List[str] = []\n\n    def test_upgrade_to_latest_but_same_version(self):\n        \"\"\"Skip.\"\"\"\n        pass\n\n\nclass TestUpgradeProtocolLocally(TestUpgradeConnectionLocally):\n    \"\"\"Test that the command 'aea upgrade protocol --local' works.\"\"\"\n\n    ITEM_TYPE = \"protocol\"\n    ITEM_PUBLIC_ID = HttpMessage.protocol_id\n\n\nclass TestUpgradeProtocolRemoteRegistry(TestUpgradeProtocolLocally):\n    \"\"\"Test that the command 'aea upgrade protocol' works.\"\"\"\n\n    LOCAL: List[str] = []\n\n    def test_upgrade_to_latest_but_same_version(self):\n        \"\"\"Skip.\"\"\"\n        pass\n\n\nclass TestUpgradeSkillLocally(TestUpgradeConnectionLocally):\n    \"\"\"Test that the command 'aea upgrade skill --local' works.\"\"\"\n\n    ITEM_TYPE = \"skill\"\n    ITEM_PUBLIC_ID = ECHO_SKILL_PUBLIC_ID\n\n\nclass TestUpgradeSkillRemoteRegistry(TestUpgradeSkillLocally):\n    \"\"\"Test that the command 'aea upgrade skill' works.\"\"\"\n\n    LOCAL: List[str] = []\n\n    def test_upgrade_to_latest_but_same_version(self):\n        \"\"\"Skip.\"\"\"\n        pass\n\n    def test_upgrade_required_mock(self):\n        \"\"\"Skip.\"\"\"\n        pass\n\n    def test_do_upgrade(self):\n        \"\"\"Skip.\"\"\"\n        pass\n\n\nclass TestUpgradeContractLocally(TestUpgradeConnectionLocally):\n    \"\"\"Test that the command 'aea upgrade contract' works.\"\"\"\n\n    ITEM_TYPE = \"contract\"\n    ITEM_PUBLIC_ID = ERC1155_PUBLIC_ID\n\n\nclass TestUpgradeContractRemoteRegistry(TestUpgradeContractLocally):\n    \"\"\"Test that the command 'aea upgrade contract --local' works.\"\"\"\n\n    LOCAL: List[str] = []\n\n    def test_upgrade_to_latest_but_same_version(self):\n        \"\"\"Skip.\"\"\"\n        pass\n\n\n@pytest.mark.integration\nclass TestUpgradeNonVendorDependencies(AEATestCaseEmpty):\n    \"\"\"\n    Test that the command 'aea upgrade' correctly updates non-vendor package data.\n\n    In particular, check that 'aea upgrade' updates:\n    - the public ids of the package dependencies and the 'aea_version' field.\n    - the 'aea_version' field in case it is not compatible with the current version.\n\n    The test works as follows:\n    - scaffold a package, one for each possible package type;\n    - add the protocol \"fetchai/default:0.12.0\" as dependency to each of them.\n    - add the skill \"fetchai/error:0.12.0\"; this will also add the default protocol.\n      add it also as dependency of non-vendor skill.\n    - run 'aea upgrade'\n    - check that the reference to \"fetchai/default\" in each scaffolded package\n      has the new version.\n    \"\"\"\n\n    capture_log = True\n    IS_EMPTY = True\n    old_default_protocol_id = PublicId(\n        DefaultMessage.protocol_id.author, DefaultMessage.protocol_id.name, \"0.12.0\"\n    )\n    old_error_skill_id = PublicId(\n        ERROR_SKILL_PUBLIC_ID.author, ERROR_SKILL_PUBLIC_ID.name, \"0.12.0\"\n    )\n    old_aea_version_range = compute_specifier_from_version(Version(\"0.1.0\"))\n\n    @classmethod\n    def scaffold_item(\n        cls, item_type: str, name: str, skip_consistency_check: bool = False\n    ) -> Result:\n        \"\"\"Override default behaviour by adding a custom dependency to the scaffolded item.\"\"\"\n        result = super(TestUpgradeNonVendorDependencies, cls).scaffold_item(\n            item_type, name, skip_consistency_check\n        )\n        # add custom dependency (a protocol) to each package\n        # that supports dependencies (only connections and skills)\n        if item_type in {ComponentType.CONNECTION.value, ComponentType.SKILL.value}:\n            cls.nested_set_config(\n                f\"{ComponentType(item_type).to_plural()}.{name}.protocols\",\n                [str(cls.old_default_protocol_id)],\n            )\n\n        # add the vendor skill as dependency of the non-vendor skill\n        if item_type == ComponentType.SKILL.value:\n            cls.nested_set_config(\n                f\"{ComponentType(item_type).to_plural()}.{name}.skills\",\n                [str(cls.old_error_skill_id)],\n            )\n\n        # update 'aea_version' to an old version range.\n        cls.nested_set_config(\n            f\"{ComponentType(item_type).to_plural()}.{name}.aea_version\",\n            str(cls.old_aea_version_range),\n        )\n        return result\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set up test case.\"\"\"\n        super(TestUpgradeNonVendorDependencies, cls).setup_class()\n        cls.scaffold_item(\"protocol\", \"my_protocol\", skip_consistency_check=True)\n        cls.scaffold_item(\"connection\", \"my_connection\", skip_consistency_check=True)\n        cls.scaffold_item(\"contract\", \"my_contract\", skip_consistency_check=True)\n        cls.scaffold_item(\"skill\", \"my_skill\", skip_consistency_check=True)\n        cls.run_cli_command(\n            \"--skip-consistency-check\",\n            \"add\",\n            \"skill\",\n            str(cls.old_error_skill_id),\n            cwd=cls._get_cwd(),\n        )\n        cls.run_cli_command(\n            \"--skip-consistency-check\", \"upgrade\", \"--local\", cwd=cls._get_cwd()\n        )\n\n    def test_agent_config_updated(self):\n        \"\"\"Test the agent configuration is updated.\"\"\"\n        loader = ConfigLoader.from_configuration_type(PackageType.AGENT)\n        with Path(self._get_cwd(), DEFAULT_AEA_CONFIG_FILE).open() as fp:\n            agent_config = loader.load(fp)\n        assert DefaultMessage.protocol_id in agent_config.protocols\n        assert ERROR_SKILL_PUBLIC_ID in agent_config.skills\n\n    def test_non_vendor_update_references_to_upgraded_packages(\n        self,\n    ):  # pylint: disable=unused-argument\n        \"\"\"Test that dependencies in non-vendor packages are updated correctly after upgrade.\"\"\"\n        self.assert_dependency_updated(\n            ComponentType.CONNECTION,\n            \"my_connection\",\n            \"protocols\",\n            {DefaultMessage.protocol_id},\n        )\n        self.assert_dependency_updated(\n            ComponentType.SKILL, \"my_skill\", \"protocols\", {DefaultMessage.protocol_id}\n        )\n        self.assert_dependency_updated(\n            ComponentType.SKILL, \"my_skill\", \"skills\", {ERROR_SKILL_PUBLIC_ID}\n        )\n\n    def assert_dependency_updated(\n        self,\n        item_type: ComponentType,\n        package_name: str,\n        package_type: str,\n        expected: Set[PublicId],\n    ):\n        \"\"\"Assert dependency is updated.\"\"\"\n        package_path = Path(self._get_cwd(), item_type.to_plural(), package_name)\n        component_config = load_component_configuration(item_type, package_path)\n        assert hasattr(component_config, package_type), \"Test is not well-written.\"\n        assert getattr(component_config, package_type) == expected  # type: ignore\n\n        expected_version_range = compute_specifier_from_version(\n            get_current_aea_version()\n        )\n        assert component_config.aea_version == expected_version_range\n\n\nclass TestUpdateReferences(AEATestCaseEmpty):\n    \"\"\"\n    Test that references are updated correctly after 'aea upgrade'.\n\n    In particular, 'default_routing', 'default_connection' and custom component configurations in AEA configuration.\n\n    How the test works:\n    - add fetchai/error:0.12.0, that requires fetchai/default:0.12.0\n    - add fetchai/stub:0.16.0\n    - add 'fetchai/default:0.12.0: fetchai/stub:0.16.0' to default routing\n    - add custom configuration to stub connection.\n    - run 'aea upgrade'. This will upgrade `stub` connection and `error` skill, and in turn `default` protocol.\n    \"\"\"\n\n    IS_EMPTY = True\n\n    OLD_DEFAULT_PROTOCOL_PUBLIC_ID = PublicId.from_str(\"fetchai/default:0.12.0\")\n    OLD_ERROR_SKILL_PUBLIC_ID = PublicId.from_str(\"fetchai/error:0.12.0\")\n    OLD_STUB_CONNECTION_PUBLIC_ID = PublicId.from_str(\"fetchai/stub:0.16.0\")\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set up the test class.\"\"\"\n        super().setup_class()\n        cls.run_cli_command(\n            \"--skip-consistency-check\",\n            \"add\",\n            \"skill\",\n            str(cls.OLD_ERROR_SKILL_PUBLIC_ID),\n            cwd=cls._get_cwd(),\n        )\n        cls.run_cli_command(\n            \"--skip-consistency-check\",\n            \"add\",\n            \"connection\",\n            str(cls.OLD_STUB_CONNECTION_PUBLIC_ID),\n            cwd=cls._get_cwd(),\n        )\n\n        cls.nested_set_config(\n            \"agent.default_routing\",\n            {cls.OLD_DEFAULT_PROTOCOL_PUBLIC_ID: cls.OLD_STUB_CONNECTION_PUBLIC_ID},\n        )\n        cls.nested_set_config(\n            \"agent.default_connection\",\n            cls.OLD_STUB_CONNECTION_PUBLIC_ID,\n        )\n        cls.run_cli_command(\n            \"--skip-consistency-check\",\n            \"config\",\n            \"set\",\n            \"vendor.fetchai.skills.error.is_abstract\",\n            \"--type\",\n            \"bool\",\n            \"true\",\n            cwd=cls._get_cwd(),\n        )\n\n        cls.run_cli_command(\n            \"--skip-consistency-check\", \"upgrade\", \"--local\", cwd=cls._get_cwd()\n        )\n\n    def test_default_routing_updated_correctly(self):\n        \"\"\"Test default routing has been updated correctly.\"\"\"\n        result = self.run_cli_command(\n            \"--skip-consistency-check\",\n            \"config\",\n            \"get\",\n            \"agent.default_routing\",\n            cwd=self._get_cwd(),\n        )\n        assert (\n            result.stdout\n            == f'{{\"{DefaultMessage.protocol_id}\": \"{StubConnection.connection_id}\"}}\\n'\n        )\n\n    def test_default_connection_updated_correctly(self):\n        \"\"\"Test default routing has been updated correctly.\"\"\"\n        result = self.run_cli_command(\n            \"--skip-consistency-check\",\n            \"config\",\n            \"get\",\n            \"agent.default_connection\",\n            cwd=self._get_cwd(),\n        )\n        assert result.stdout == \"fetchai/stub:0.21.3\\n\"\n\n    def test_custom_configuration_updated_correctly(self):\n        \"\"\"Test default routing has been updated correctly.\"\"\"\n        result = self.run_cli_command(\n            \"--skip-consistency-check\",\n            \"config\",\n            \"get\",\n            \"vendor.fetchai.skills.error.is_abstract\",\n            cwd=self._get_cwd(),\n        )\n        assert result.stdout == \"True\\n\"\n\n\n@mock.patch(\"click.echo\")\nclass TestNothingToUpgrade(AEATestCaseEmpty):\n    \"\"\"Test the upgrade command when there's nothing t upgrade.\"\"\"\n\n    def test_nothing_to_upgrade(self, mock_click_echo):\n        \"\"\"Test nothing to upgrade.\"\"\"\n        agent_config = self.load_agent_config(self.agent_name)\n        result = self.run_cli_command(\"upgrade\", cwd=self._get_cwd())\n        assert result.exit_code == 0\n        mock_click_echo.assert_any_call(\"Starting project upgrade...\")\n        mock_click_echo.assert_any_call(\n            f\"Checking if there is a newer remote version of agent package '{agent_config.public_id}'...\"\n        )\n        mock_click_echo.assert_any_call(\n            \"Package not found, continuing with normal upgrade.\"\n        )\n        mock_click_echo.assert_any_call(\"Everything is already up to date!\")\n\n\n@pytest.mark.integration\n@mock.patch(\"click.echo\")\nclass TestWrongAEAVersion(AEATestCaseEmpty):\n    \"\"\"\n    Test consistency check ignores AEA version fields.\n\n    Use an old version of a package to simulate an upgrade.\n    \"\"\"\n\n    AEA_VERSION_SPECIFIER: str = \"==0.1.0\"\n    IS_EMPTY = True\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set up the test.\"\"\"\n        super().setup_class()\n\n        # this is an old version of the package, just to trigger an upgrade.\n        cls.add_item(\"protocol\", \"fetchai/default:0.12.0\", local=False)\n\n        # change aea version of the AEA project\n        agent_config = cls.load_agent_config(cls.current_agent_context)\n        cls._update_aea_version(agent_config)\n        cls.nested_set_config(\"agent.aea_version\", cls.AEA_VERSION_SPECIFIER)\n        cls.nested_set_config(\"agent.author\", \"wrong_author\")\n\n    @classmethod\n    def _update_aea_version(cls, agent_config: AgentConfig):\n        \"\"\"Update aea version to all items and fingerprint them.\"\"\"\n        for item in agent_config.package_dependencies:\n            type_ = item.component_type.to_plural()\n            dotted_path = f\"vendor.{item.author}.{type_}.{item.name}.aea_version\"\n            path = os.path.join(\"vendor\", item.author, type_, item.name)\n            cls.nested_set_config(dotted_path, cls.AEA_VERSION_SPECIFIER)\n            cls.run_cli_command(\"fingerprint\", \"by-path\", path, cwd=cls._get_cwd())\n\n    def test_nothing_to_upgrade(self, mock_click_echo):\n        \"\"\"Test nothing to upgrade, and additionally, that 'aea_version' is correct.\"\"\"\n        result = self.run_cli_command(\"upgrade\", cwd=self._get_cwd())\n        assert result.exit_code == 0\n        mock_click_echo.assert_any_call(\"Starting project upgrade...\")\n        mock_click_echo.assert_any_call(\n            f\"Updating AEA version specifier from ==0.1.0 to {compute_specifier_from_version(get_current_aea_version())}.\"\n        )\n\n        # test 'aea_version' of agent configuration is upgraded\n        expected_aea_version_specifier = compute_specifier_from_version(\n            get_current_aea_version()\n        )\n        agent_config = self.load_agent_config(self.current_agent_context)\n        assert agent_config.aea_version == expected_aea_version_specifier\n        assert agent_config.author == self.author\n        assert agent_config.version == DEFAULT_VERSION\n\n\n@mock.patch(\"click.echo\")\n@mock.patch(\"click.confirm\")\n@mock.patch(\"aea.cli.upgrade.get_latest_version_available_in_registry\")\nclass BaseTestUpgradeWithEject(AEATestCaseEmpty):\n    \"\"\"\n    Base test class to test 'aea upgrade' with request for ejection.\n\n    We use an old version of 'generic seller' skill to simulate a request from the CLI tool.\n    The utility 'get_latest_version_available_in_registry' is mocked so to\n    hide the new version of that package, hence triggering an ejection.;\n    \"\"\"\n\n    IS_EMPTY = True\n\n    GENERIC_SELLER = ComponentId(\n        ComponentType.SKILL, PublicId.from_str(\"fetchai/generic_seller:0.28.6\")\n    )\n    unmocked = get_latest_version_available_in_registry\n\n    EXPECTED_CLICK_ECHO_CALLS: List[str] = []\n    EXPECTED_CLICK_CONFIRM_CALLS: List[str] = []\n    CONFIRM_OUTPUT = [False, False]\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set up the test.\"\"\"\n        super().setup_class()\n        cls.add_item(\"skill\", str(cls.GENERIC_SELLER.public_id), local=False)\n\n    @classmethod\n    def mock_get_latest_version_available_in_registry(cls, *args, **kwargs):\n        \"\"\"Mock 'get_latest_version_available_in_registry' when called with generic_seller public key.\"\"\"\n        if (\n            args[1] == str(cls.GENERIC_SELLER.package_type)\n            and args[2] == cls.GENERIC_SELLER.public_id.to_latest()\n        ):\n            # return current version\n            return cls.GENERIC_SELLER\n        return cls.unmocked(*args, **kwargs)\n\n    def _get_mock(self):\n        \"\"\"Get the mock of 'get_latest_version_available_in_registry'.\"\"\"\n        return mock.patch(\n            \"aea.cli.upgrade.get_latest_version_available_in_registry\",\n            side_effect=self.mock_get_latest_version_available_in_registry,\n        )\n\n    def test_run(self, mock_get_latest_version, mock_click_confirm, mock_click_echo):\n        \"\"\"Run the test.\"\"\"\n        mock_get_latest_version.side_effect = (\n            self.mock_get_latest_version_available_in_registry\n        )\n        mock_click_confirm.side_effect = self.CONFIRM_OUTPUT\n        result = self.run_cli_command(\"upgrade\", cwd=self._get_cwd())\n        assert result.exit_code == 0\n        self.mock_click_echo = mock_click_echo\n        self.mock_click_confirm = mock_click_confirm\n        self._assert_calls(self.EXPECTED_CLICK_ECHO_CALLS, mock_click_echo)\n        self._assert_calls(self.EXPECTED_CLICK_CONFIRM_CALLS, mock_click_confirm)\n\n    def _assert_calls(self, args: List, stdout_mock: MagicMock):\n        \"\"\"Assert lines are present in stdout.\"\"\"\n        for expected_line in args:\n            stdout_mock.assert_any_call(expected_line)\n\n\n@pytest.mark.integration\nclass TestUpgradeWithEjectAbort(BaseTestUpgradeWithEject):\n    \"\"\"Test 'aea upgrade' command with request for ejection, refused.\"\"\"\n\n    GENERIC_SELLER = ComponentId(\n        ComponentType.SKILL, PublicId.from_str(\"fetchai/generic_seller:0.24.0\")\n    )\n\n    EXPECTED_CLICK_ECHO_CALLS = [\"Abort.\"]\n    EXPECTED_CLICK_CONFIRM_CALLS = [\n        RegexComparator(\n            r\"Skill fetchai/generic_seller:0.24.0 prevents the upgrade of the following vendor packages:.*as there isn't a compatible version available on the AEA registry\\. Would you like to eject it\\?\"\n        )\n    ]\n\n\n@pytest.mark.integration\nclass TestUpgradeWithEjectAccept(BaseTestUpgradeWithEject):\n    \"\"\"Test 'aea upgrade' command with request for ejection, accepted by the user.\"\"\"\n\n    CONFIRM_OUTPUT = [True, True]\n\n    GENERIC_SELLER = ComponentId(\n        ComponentType.SKILL, PublicId.from_str(\"fetchai/generic_seller:0.24.0\")\n    )\n\n    EXPECTED_CLICK_ECHO_CALLS = [\n        \"Ejecting (skill, fetchai/generic_seller:0.24.0)...\",\n        \"Ejecting item skill fetchai/generic_seller:0.24.0\",\n        \"Fingerprinting skill components of 'default_author/generic_seller:0.1.0' ...\",\n        \"Successfully ejected skill fetchai/generic_seller:0.24.0 to ./skills/generic_seller as default_author/generic_seller:0.1.0.\",\n    ]\n    EXPECTED_CLICK_CONFIRM_CALLS = [\n        RegexComparator(\n            \"Skill fetchai/generic_seller:0.24.0 prevents the upgrade of the following vendor packages:\"\n        ),\n        RegexComparator(\n            \"as there isn't a compatible version available on the AEA registry. Would you like to eject it?\"\n        ),\n    ]\n\n    def test_run(self, *mocks):\n        \"\"\"Run the test.\"\"\"\n        super().test_run(*mocks)\n        ejected_package_path = Path(\n            self.t, self.current_agent_context, \"skills\", \"generic_seller\"\n        )\n        assert ejected_package_path.exists()\n        assert ejected_package_path.is_dir()\n\n\n@pytest.mark.integration\nclass BaseTestUpgradeProject(AEATestCaseEmpty):\n    \"\"\"Base test class for testing project upgrader.\"\"\"\n\n    OLD_AGENT_PUBLIC_ID = PublicId.from_str(\"fetchai/weather_station:0.32.0\")\n    EXPECTED_NEW_AGENT_PUBLIC_ID = OLD_AGENT_PUBLIC_ID.to_latest()\n    EXPECTED = \"expected_agent\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set up the test.\"\"\"\n        super().setup_class()\n        cls.run_cli_command(\n            \"--skip-consistency-check\",\n            \"fetch\",\n            \"--remote\",\n            str(cls.EXPECTED_NEW_AGENT_PUBLIC_ID),\n            \"--alias\",\n            cls.EXPECTED,\n        )\n\n    def setup(self):\n        \"\"\"Set up the class.\"\"\"\n        self.run_cli_command(\"fetch\", str(self.OLD_AGENT_PUBLIC_ID))\n        self.set_agent_context(self.OLD_AGENT_PUBLIC_ID.name)\n\n    def teardown(self):\n        \"\"\"Tear down class.\"\"\"\n        shutil.rmtree(self.current_agent_context)\n\n\n@mock.patch(\"click.confirm\")\nclass TestUpgradeProjectWithNewerVersion(BaseTestUpgradeProject):\n    \"\"\"Test upgrade project with newer version available.\"\"\"\n\n    @pytest.mark.parametrize(\"confirm\", [True, False])\n    def test_upgrade(self, mock_confirm, confirm):\n        \"\"\"Test upgrade.\"\"\"\n        mock_confirm.return_value = confirm\n        result = self.run_cli_command(\"upgrade\", \"--remote\", cwd=self._get_cwd())\n        assert result.exit_code == 0\n\n        mock_confirm.assert_any_call(\n            RegexComparator(\n                r\"Found a newer version of this project:.*Would you like to replace this project with it\\?.*Warning: the content in the current directory.*will be removed\"\n            )\n        )\n\n        # compare with latest fetched agent.\n        ignore = [\n            DEFAULT_AEA_CONFIG_FILE,\n            DEFAULT_README_FILE,\n        ] + filecmp.DEFAULT_IGNORES\n        dircmp = filecmp.dircmp(\n            self.current_agent_context, self.EXPECTED, ignore=ignore\n        )\n        _left_only, _right_only, diff = dircmp_recursive(dircmp)\n        assert _right_only == diff == _left_only == set()\n\n\n@mock.patch(\"aea.cli.upgrade.get_latest_version_available_in_registry\")\n@mock.patch(\"click.echo\")\nclass TestUpgradeProjectWithoutNewerVersion(BaseTestUpgradeProject):\n    \"\"\"Test upgrade project without newer version available (but available on registry).\"\"\"\n\n    def test_run(self, mock_click_echo, mock_get_latest_version):\n        \"\"\"Run the test.\"\"\"\n        fake_old_public_id = self.OLD_AGENT_PUBLIC_ID\n        mock_get_latest_version.return_value = fake_old_public_id\n        result = self.run_cli_command(\"upgrade\", \"--remote\", cwd=self._get_cwd())\n        assert result.exit_code == 0\n\n        version_str = str(self.OLD_AGENT_PUBLIC_ID.version)\n        mock_click_echo.assert_any_call(\n            f\"Latest version found is '{version_str}' which is smaller or equal than current version '{version_str}'. Continuing...\"\n        )\n\n        # compare with latest fetched agent.\n        ignore = [\n            DEFAULT_AEA_CONFIG_FILE,\n            DEFAULT_README_FILE,\n        ] + filecmp.DEFAULT_IGNORES\n        dircmp = filecmp.dircmp(\n            self.current_agent_context, self.EXPECTED, ignore=ignore\n        )\n        _left_only, _right_only, diff = dircmp_recursive(dircmp)\n        assert diff == set()\n        # temp: assert diff == _left_only == _right_only == set()\n\n\n@mock.patch.object(aea, \"__version__\", \"0.11.0\")\nclass TestUpgradeAEACompatibility(BaseTestUpgradeProject):\n    \"\"\"\n    Test 'aea upgrade' takes into account the current aea version.\n\n    The test works as follows:\n    \"\"\"\n\n    OLD_AGENT_PUBLIC_ID = PublicId.from_str(\"fetchai/weather_station:0.32.5\")\n    EXPECTED_NEW_AGENT_PUBLIC_ID = PublicId.from_str(\"fetchai/weather_station:latest\")\n\n    def test_upgrade(self):\n        \"\"\"Test upgrade.\"\"\"\n        result = self.run_cli_command(\"upgrade\", \"--remote\", \"-y\", cwd=self._get_cwd())\n        assert result.exit_code == 0\n\n        # compare with latest fetched agent.\n        ignore = [DEFAULT_AEA_CONFIG_FILE] + filecmp.DEFAULT_IGNORES\n        dircmp = filecmp.dircmp(\n            self.current_agent_context, self.EXPECTED, ignore=ignore\n        )\n        _left_only, _right_only, diff = dircmp_recursive(dircmp)\n        assert diff == set()  # temp\n\n        # compare agent configuration files (except the name)\n        expected_content = (\n            Path(self.EXPECTED, DEFAULT_AEA_CONFIG_FILE).read_text().splitlines()[1:]\n        )\n        actual_content = (\n            Path(self.current_agent_context, DEFAULT_AEA_CONFIG_FILE)\n            .read_text()\n            .splitlines()[1:]\n        )\n        assert expected_content != actual_content  # temp\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_utils/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This test module contains the tests for the cli utils.\"\"\"\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_utils/test_config.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This test module contains the tests for aea.cli.utils.config module.\"\"\"\n\n\nfrom unittest import TestCase, mock\n\nfrom aea.cli.utils.config import validate_item_config\nfrom aea.cli.utils.exceptions import AEAConfigException\n\nfrom tests.test_aea.test_cli.tools_for_testing import (\n    AgentConfigMock,\n    ConfigLoaderMock,\n    FaultyAgentConfigMock,\n)\n\n\nclass ValidateItemConfigTestCase(TestCase):\n    \"\"\"Test case for validate_item_config method.\"\"\"\n\n    @mock.patch(\n        \"aea.cli.utils.config.load_item_config\",\n        return_value=AgentConfigMock(description=\"Description\"),\n    )\n    @mock.patch(\n        \"aea.cli.utils.config.ConfigLoaders.from_package_type\",\n        return_value=ConfigLoaderMock(required_fields=[\"description\"]),\n    )\n    def test_validate_item_config_positive(self, *mocks):\n        \"\"\"Test validate_item_config for positive result.\"\"\"\n        validate_item_config(item_type=\"agent\", package_path=\"file/path\")\n\n    @mock.patch(\n        \"aea.cli.utils.config.load_item_config\",\n        return_value=FaultyAgentConfigMock(),\n    )\n    @mock.patch(\n        \"aea.cli.utils.config.ConfigLoaders.from_package_type\",\n        return_value=ConfigLoaderMock(required_fields=[\"description\"]),\n    )\n    def test_validate_item_config_negative(self, *mocks):\n        \"\"\"Test validate_item_config for negative result.\"\"\"\n        with self.assertRaises(AEAConfigException):\n            validate_item_config(item_type=\"agent\", package_path=\"file/path\")\n"
  },
  {
    "path": "tests/test_aea/test_cli/test_utils/test_utils.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This test module contains the tests for aea.cli.utils module.\"\"\"\nfrom builtins import FileNotFoundError\nfrom copy import deepcopy\nfrom tempfile import TemporaryDirectory\nfrom typing import cast\nfrom unittest import TestCase, mock\nfrom unittest.mock import MagicMock, patch\nfrom uuid import uuid4\n\nimport click\nimport pytest\nfrom aea_ledger_fetchai import FetchAICrypto\nfrom click import BadParameter, ClickException, UsageError\nfrom click.testing import CliRunner\nfrom jsonschema import ValidationError\nfrom yaml import YAMLError\n\nfrom aea.cli.utils.click_utils import (\n    MutuallyExclusiveOption,\n    PublicIdParameter,\n    password_option,\n)\nfrom aea.cli.utils.config import (\n    _init_cli_config,\n    get_or_create_cli_config,\n    set_cli_author,\n    update_cli_config,\n)\nfrom aea.cli.utils.context import Context\nfrom aea.cli.utils.decorators import _validate_config_consistency, clean_after\nfrom aea.cli.utils.formatting import format_items\nfrom aea.cli.utils.generic import is_readme_present\nfrom aea.cli.utils.package_utils import (\n    _override_ledger_configurations,\n    find_item_in_distribution,\n    find_item_locally,\n    get_dotted_package_path_unified,\n    get_package_path_unified,\n    get_wallet_from_context,\n    is_distributed_item,\n    is_fingerprint_correct,\n    is_item_present_unified,\n    try_get_balance,\n    try_get_item_source_path,\n    try_get_item_target_path,\n    validate_author_name,\n    validate_package_name,\n)\nfrom aea.configurations.base import ComponentId, ComponentType, PublicId\nfrom aea.configurations.constants import (\n    DEFAULT_LEDGER,\n    DEFAULT_PROTOCOL,\n    LEDGER_CONNECTION,\n)\nfrom aea.crypto.ledger_apis import FETCHAI_DEFAULT_CHAIN_ID, LedgerApis\nfrom aea.crypto.wallet import Wallet\nfrom aea.helpers.base import cd\nfrom aea.test_tools.test_cases import AEATestCaseEmpty\n\nfrom tests.test_aea.test_cli.tools_for_testing import (\n    ConfigLoaderMock,\n    ContextMock,\n    PublicIdMock,\n    StopTest,\n    raise_stoptest,\n)\n\n\nAUTHOR = \"author\"\n\n\nclass FormatItemsTestCase(TestCase):\n    \"\"\"Test case for format_items method.\"\"\"\n\n    def testformat_items_positive(self):\n        \"\"\"Test format_items positive result.\"\"\"\n        items = [\n            {\n                \"public_id\": \"author/name:version\",\n                \"name\": \"obj_name\",\n                \"description\": \"Some description\",\n                \"author\": \"author\",\n                \"version\": \"1.0\",\n            }\n        ]\n        result = format_items(items)\n        expected_result = (\n            \"------------------------------\\n\"\n            \"Public ID: author/name:version\\n\"\n            \"Name: obj_name\\n\"\n            \"Description: Some description\\n\"\n            \"Author: author\\n\"\n            \"Version: 1.0\\n\"\n            \"------------------------------\\n\"\n        )\n        self.assertEqual(result, expected_result)\n\n\n@mock.patch(\"aea.cli.utils.package_utils.os.path.join\", return_value=\"some-path\")\nclass TryGetItemSourcePathTestCase(TestCase):\n    \"\"\"Test case for try_get_item_source_path method.\"\"\"\n\n    @mock.patch(\"aea.cli.utils.package_utils.os.path.exists\", return_value=True)\n    def test_get_item_source_path_positive(self, exists_mock, join_mock):\n        \"\"\"Test for get_item_source_path positive result.\"\"\"\n        result = try_get_item_source_path(\"cwd\", AUTHOR, \"skills\", \"skill_name\")\n        expected_result = \"some-path\"\n        self.assertEqual(result, expected_result)\n        join_mock.assert_called_once_with(\"cwd\", AUTHOR, \"skills\", \"skill_name\")\n        exists_mock.assert_called_once_with(\"some-path\")\n\n        result = try_get_item_source_path(\"cwd\", None, \"skills\", \"skill_name\")\n        self.assertEqual(result, expected_result)\n\n    @mock.patch(\"aea.cli.utils.package_utils.os.path.exists\", return_value=False)\n    def test_get_item_source_path_not_exists(self, exists_mock, join_mock):\n        \"\"\"Test for get_item_source_path item already exists.\"\"\"\n        item_name = \"skill_name\"\n        with pytest.raises(\n            ClickException,\n            match=f'Item \"{AUTHOR}/{item_name}\" not found in source folder \"some-path\"',\n        ):\n            try_get_item_source_path(\"cwd\", AUTHOR, \"skills\", item_name)\n\n\n@mock.patch(\"aea.cli.utils.package_utils.os.path.join\", return_value=\"some-path\")\nclass TryGetItemTargetPathTestCase(TestCase):\n    \"\"\"Test case for try_get_item_target_path method.\"\"\"\n\n    @mock.patch(\"aea.cli.utils.package_utils.os.path.exists\", return_value=False)\n    def test_get_item_target_path_positive(self, exists_mock, join_mock):\n        \"\"\"Test for get_item_source_path positive result.\"\"\"\n        result = try_get_item_target_path(\"packages\", AUTHOR, \"skills\", \"skill_name\")\n        expected_result = \"some-path\"\n        self.assertEqual(result, expected_result)\n        join_mock.assert_called_once_with(\"packages\", AUTHOR, \"skills\", \"skill_name\")\n        exists_mock.assert_called_once_with(\"some-path\")\n\n    @mock.patch(\"aea.cli.utils.package_utils.os.path.exists\", return_value=True)\n    def test_get_item_target_path_already_exists(self, exists_mock, join_mock):\n        \"\"\"Test for get_item_target_path item already exists.\"\"\"\n        with self.assertRaises(ClickException):\n            try_get_item_target_path(\"skills\", AUTHOR, \"skill_name\", \"packages_path\")\n\n\nclass PublicIdParameterTestCase(TestCase):\n    \"\"\"Test case for PublicIdParameter class.\"\"\"\n\n    def test_get_metavar_positive(self):\n        \"\"\"Test for get_metavar positive result.\"\"\"\n        result = PublicIdParameter.get_metavar(\"obj\", \"param\")\n        expected_result = \"PUBLIC_ID\"\n        self.assertEqual(result, expected_result)\n\n\n@mock.patch(\"aea.cli.utils.config.os.path.dirname\", return_value=\"dir-name\")\n@mock.patch(\"aea.cli.utils.config.os.path.exists\", return_value=False)\n@mock.patch(\"aea.cli.utils.config.os.makedirs\")\n@mock.patch(\"aea.cli.utils.click_utils.open_file\")\nclass InitConfigFolderTestCase(TestCase):\n    \"\"\"Test case for _init_cli_config method.\"\"\"\n\n    def test_init_cli_config_positive(\n        self, open_mock, makedirs_mock, exists_mock, dirname_mock\n    ):\n        \"\"\"Test for _init_cli_config method positive result.\"\"\"\n        _init_cli_config()\n        dirname_mock.assert_called_once()\n        exists_mock.assert_called_once_with(\"dir-name\")\n        makedirs_mock.assert_called_once_with(\"dir-name\")\n\n\n@mock.patch(\"aea.cli.utils.config.get_or_create_cli_config\")\n@mock.patch(\"aea.cli.utils.generic.yaml.dump\")\n@mock.patch(\"aea.cli.utils.click_utils.open_file\", mock.mock_open())\nclass UpdateCLIConfigTestCase(TestCase):\n    \"\"\"Test case for update_cli_config method.\"\"\"\n\n    def testupdate_cli_config_positive(self, dump_mock, icf_mock):\n        \"\"\"Test for update_cli_config method positive result.\"\"\"\n        update_cli_config({\"some\": \"config\"})\n        icf_mock.assert_called_once()\n        dump_mock.assert_called_once()\n\n\ndef _raise_yamlerror(*args):\n    raise YAMLError()\n\n\ndef _raise_file_not_found_error(*args):\n    raise FileNotFoundError()\n\n\n@mock.patch(\"aea.cli.utils.click_utils.open_file\", mock.mock_open())\nclass GetOrCreateCLIConfigTestCase(TestCase):\n    \"\"\"Test case for read_cli_config method.\"\"\"\n\n    @mock.patch(\n        \"aea.cli.utils.generic.yaml.safe_load\", return_value={\"correct\": \"output\"}\n    )\n    def testget_or_create_cli_config_positive(self, safe_load_mock):\n        \"\"\"Test for get_or_create_cli_config method positive result.\"\"\"\n        result = get_or_create_cli_config()\n        expected_result = {\"correct\": \"output\"}\n        self.assertEqual(result, expected_result)\n        safe_load_mock.assert_called_once()\n\n    @mock.patch(\"aea.cli.utils.generic.yaml.safe_load\", _raise_yamlerror)\n    def testget_or_create_cli_config_bad_yaml(self):\n        \"\"\"Test for rget_or_create_cli_config method bad yaml behavior.\"\"\"\n        with self.assertRaises(ClickException):\n            get_or_create_cli_config()\n\n\nclass CleanAfterTestCase(TestCase):\n    \"\"\"Test case for clean_after decorator method.\"\"\"\n\n    @mock.patch(\"aea.cli.utils.decorators.os.path.exists\", return_value=True)\n    @mock.patch(\"aea.cli.utils.decorators._cast_ctx\", lambda x: x)\n    @mock.patch(\"aea.cli.utils.decorators.shutil.rmtree\")\n    def test_clean_after_positive(self, rmtree_mock, *mocks):\n        \"\"\"Test clean_after decorator method for positive result.\"\"\"\n\n        @clean_after\n        def func(click_context):\n            ctx = cast(Context, click_context.obj)\n            ctx.clean_paths.append(\"clean/path\")\n            raise ClickException(\"Message\")\n\n        with self.assertRaises(ClickException):\n            func(ContextMock())\n            rmtree_mock.assert_called_once_with(\"clean/path\")\n\n\n@mock.patch(\"aea.cli.utils.package_utils.click.echo\", raise_stoptest)\nclass ValidateAuthorNameTestCase(TestCase):\n    \"\"\"Test case for validate_author_name method.\"\"\"\n\n    @mock.patch(\n        \"aea.cli.utils.package_utils.click.prompt\", return_value=\"correct_author\"\n    )\n    def test_validate_author_name_positive(self, prompt_mock):\n        \"\"\"Test validate_author_name for positive result.\"\"\"\n        author = \"valid_author\"\n        result = validate_author_name(author=author)\n        self.assertEqual(result, author)\n\n        result = validate_author_name()\n        self.assertEqual(result, \"correct_author\")\n        prompt_mock.assert_called_once()\n\n    @mock.patch(\n        \"aea.cli.utils.package_utils.click.prompt\", return_value=\"inv@l1d_@uth&r\"\n    )\n    def test_validate_author_name_negative(self, prompt_mock):\n        \"\"\"Test validate_author_name for negative result.\"\"\"\n        with self.assertRaises(StopTest):\n            validate_author_name()\n\n        prompt_mock.return_value = \"skills\"\n        with self.assertRaises(StopTest):\n            validate_author_name()\n\n\nclass ValidatePackageNameTestCase(TestCase):\n    \"\"\"Test case for validate_package_name method.\"\"\"\n\n    def test_validate_package_name_positive(self):\n        \"\"\"Test validate_package_name for positive result.\"\"\"\n        validate_package_name(\"correct_name\")\n\n    def test_validate_package_name_negative(self):\n        \"\"\"Test validate_package_name for negative result.\"\"\"\n        with self.assertRaises(BadParameter):\n            validate_package_name(\"incorrect-name\")\n\n\ndef _raise_validation_error(*args, **kwargs):\n    raise ValidationError(\"Message.\")\n\n\nclass FindItemLocallyTestCase(TestCase):\n    \"\"\"Test case for find_item_locally method.\"\"\"\n\n    @mock.patch(\"aea.cli.utils.package_utils.Path.exists\", return_value=True)\n    @mock.patch(\n        \"aea.cli.utils.package_utils.ConfigLoader.from_configuration_type\",\n        _raise_validation_error,\n    )\n    def test_find_item_locally_bad_config(self, *mocks):\n        \"\"\"Test find_item_locally for bad config result.\"\"\"\n        public_id = PublicIdMock.from_str(\"fetchai/echo:0.20.6\")\n        with self.assertRaises(ClickException) as cm:\n            find_item_locally(ContextMock(), \"skill\", public_id)\n\n        self.assertIn(\"configuration file not valid\", cm.exception.message)\n\n    @mock.patch(\"aea.cli.utils.package_utils.Path.exists\", return_value=True)\n    @mock.patch(\"aea.cli.utils.package_utils.open_file\", mock.mock_open())\n    @mock.patch(\n        \"aea.cli.utils.package_utils.ConfigLoader.from_configuration_type\",\n        return_value=ConfigLoaderMock(),\n    )\n    def test_find_item_locally_cant_find(self, from_conftype_mock, *mocks):\n        \"\"\"Test find_item_locally for can't find result.\"\"\"\n        public_id = PublicIdMock.from_str(\"fetchai/echo:0.20.6\")\n        with self.assertRaises(ClickException) as cm:\n            find_item_locally(ContextMock(), \"skill\", public_id)\n\n        self.assertEqual(\n            cm.exception.message, \"Cannot find skill with author and version specified.\"\n        )\n\n\nclass FindItemInDistributionTestCase(TestCase):\n    \"\"\"Test case for find_item_in_distribution method.\"\"\"\n\n    @mock.patch(\"aea.cli.utils.package_utils.Path.exists\", return_value=True)\n    @mock.patch(\n        \"aea.cli.utils.package_utils.ConfigLoader.from_configuration_type\",\n        _raise_validation_error,\n    )\n    def testfind_item_in_distribution_bad_config(self, *mocks):\n        \"\"\"Test find_item_in_distribution for bad config result.\"\"\"\n        public_id = PublicIdMock.from_str(\"fetchai/echo:0.20.6\")\n        with self.assertRaises(ClickException) as cm:\n            find_item_in_distribution(ContextMock(), \"skill\", public_id)\n\n        self.assertIn(\"configuration file not valid\", cm.exception.message)\n\n    @mock.patch(\"aea.cli.utils.package_utils.Path.exists\", return_value=False)\n    def testfind_item_in_distribution_not_found(self, *mocks):\n        \"\"\"Test find_item_in_distribution for not found result.\"\"\"\n        public_id = PublicIdMock.from_str(\"fetchai/echo:0.20.6\")\n        with self.assertRaises(ClickException) as cm:\n            find_item_in_distribution(ContextMock(), \"skill\", public_id)\n\n        self.assertIn(\"Cannot find skill\", cm.exception.message)\n\n    @mock.patch(\"aea.cli.utils.package_utils.Path.exists\", return_value=True)\n    @mock.patch(\"aea.cli.utils.package_utils.open_file\", mock.mock_open())\n    @mock.patch(\n        \"aea.cli.utils.package_utils.ConfigLoader.from_configuration_type\",\n        return_value=ConfigLoaderMock(),\n    )\n    def testfind_item_in_distribution_cant_find(self, from_conftype_mock, *mocks):\n        \"\"\"Test find_item_locally for can't find result.\"\"\"\n        public_id = PublicIdMock.from_str(\"fetchai/echo:0.20.6\")\n        with self.assertRaises(ClickException) as cm:\n            find_item_in_distribution(ContextMock(), \"skill\", public_id)\n\n        self.assertEqual(\n            cm.exception.message, \"Cannot find skill with author and version specified.\"\n        )\n\n\nclass ValidateConfigConsistencyTestCase(TestCase):\n    \"\"\"Test case for _validate_config_consistency method.\"\"\"\n\n    @mock.patch(\"aea.cli.utils.config.Path.exists\", _raise_validation_error)\n    def test__validate_config_consistency_cant_find(self, *mocks):\n        \"\"\"Test _validate_config_consistency can't find result\"\"\"\n        with self.assertRaises(ValueError) as cm:\n            _validate_config_consistency(ContextMock(protocols=[\"some\"]))\n\n        self.assertIn(\"Cannot find\", str(cm.exception))\n\n\n@mock.patch(\n    \"aea.cli.utils.package_utils._compute_fingerprint\",\n    return_value={\"correct\": \"fingerprint\"},\n)\nclass IsFingerprintCorrectTestCase(TestCase):\n    \"\"\"Test case for adding skill with invalid fingerprint.\"\"\"\n\n    def test_is_fingerprint_correct_positive(self, *mocks):\n        \"\"\"Test is_fingerprint_correct method for positive result.\"\"\"\n        item_config = mock.Mock()\n        item_config.fingerprint = {\"correct\": \"fingerprint\"}\n        item_config.fingerprint_ignore_patterns = []\n        result = is_fingerprint_correct(\"package_path\", item_config)\n        self.assertTrue(result)\n\n    def test_is_fingerprint_correct_negative(self, *mocks):\n        \"\"\"Test is_fingerprint_correct method for negative result.\"\"\"\n        item_config = mock.Mock()\n        item_config.fingerprint = {\"incorrect\": \"fingerprint\"}\n        item_config.fingerprint_ignore_patterns = []\n        package_path = \"package_dir\"\n        result = is_fingerprint_correct(package_path, item_config)\n        self.assertFalse(result)\n\n\n@mock.patch(\"aea.cli.utils.package_utils.LedgerApis\", mock.MagicMock())\nclass TryGetBalanceTestCase(TestCase):\n    \"\"\"Test case for try_get_balance method.\"\"\"\n\n    def test_try_get_balance_positive(self):\n        \"\"\"Test for try_get_balance method positive result.\"\"\"\n        agent_config = mock.Mock()\n        agent_config.default_ledger_config = FetchAICrypto.identifier\n\n        wallet_mock = mock.Mock()\n        wallet_mock.addresses = {FetchAICrypto.identifier: \"some-adress\"}\n        try_get_balance(agent_config, wallet_mock, FetchAICrypto.identifier)\n\n\n@mock.patch(\"aea.cli.utils.generic.os.path.exists\", return_value=True)\nclass IsReadmePresentTestCase(TestCase):\n    \"\"\"Test case for is_readme_present method.\"\"\"\n\n    def test_is_readme_present_positive(self, *mocks):\n        \"\"\"Test is_readme_present for positive result.\"\"\"\n        self.assertTrue(is_readme_present(\"readme/path\"))\n\n\n@mock.patch(\"aea.cli.utils.package_utils.get_package_path\", return_value=\"some_path\")\n@mock.patch(\"aea.cli.utils.package_utils.is_item_present\")\n@pytest.mark.parametrize(\"vendor\", [True, False])\ndef test_get_package_path_unified(mock_present, mock_path, vendor):\n    \"\"\"Test 'get_package_path_unified'.\"\"\"\n    contex_mock = mock.MagicMock()\n    contex_mock.agent_config.author = \"some_author\" if vendor else \"another_author\"\n    mock_present.return_value = vendor\n    public_id_mock = mock.MagicMock(author=\"some_author\")\n    result = get_package_path_unified(\n        \".\", contex_mock.agent_config, \"some_component_type\", public_id_mock\n    )\n    assert result == \"some_path\"\n\n\n@mock.patch(\"aea.cli.utils.package_utils.get_package_path\", return_value=\"some_path\")\n@mock.patch(\"aea.cli.utils.package_utils.is_item_present\")\n@pytest.mark.parametrize(\"vendor\", [True, False])\ndef test_get_dotted_package_path_unified(mock_present, mock_path, vendor):\n    \"\"\"Test 'get_package_path_unified'.\"\"\"\n    contex_mock = mock.MagicMock()\n    contex_mock.cwd = \".\"\n    contex_mock.agent_config.author = \"some_author\" if vendor else \"another_author\"\n    mock_present.return_value = vendor\n    public_id_mock = mock.MagicMock(author=\"some_author\")\n    result = get_dotted_package_path_unified(\n        \".\", contex_mock.agent_config, \"some_component_type\", public_id_mock\n    )\n    assert result == \"some_path\"\n\n\n@mock.patch(\"aea.cli.utils.package_utils.is_item_present\", return_value=False)\n@pytest.mark.parametrize(\"vendor\", [True, False])\ndef test_is_item_present_unified(mock_, vendor):\n    \"\"\"Test 'is_item_present_unified'.\"\"\"\n    contex_mock = mock.MagicMock()\n    contex_mock.agent_config.author = \"some_author\" if vendor else \"another_author\"\n    public_id_mock = mock.MagicMock(author=\"some_author\")\n    result = is_item_present_unified(contex_mock, \"some_component_type\", public_id_mock)\n    assert not result\n\n\n@pytest.mark.parametrize(\n    [\"public_id\", \"expected_outcome\"],\n    [\n        (PublicId.from_str(\"author/package:0.1.0\"), False),\n        (PublicId.from_str(\"author/package:latest\"), False),\n        (PublicId.from_str(\"fetchai/oef:0.1.0\"), False),\n        (PublicId.from_str(\"fetchai/oef:latest\"), False),\n        (PublicId.from_str(\"fetchai/stub:latest\"), False),\n        (PublicId.from_str(DEFAULT_PROTOCOL), False),\n    ],\n)\ndef test_is_distributed_item(public_id, expected_outcome):\n    \"\"\"Test the 'is_distributed_item' CLI utility function.\"\"\"\n    assert is_distributed_item(public_id) is expected_outcome\n\n\nclass TestGetWalletFromtx(AEATestCaseEmpty):\n    \"\"\"Test get_wallet_from_context.\"\"\"\n\n    def test_get_wallet_from_ctx(self):\n        \"\"\"Test get_wallet_from_context.\"\"\"\n        ctx = mock.Mock()\n        with cd(self._get_cwd()):\n            assert isinstance(get_wallet_from_context(ctx), Wallet)\n\n\ndef test_override_ledger_configurations_negative():\n    \"\"\"Test override ledger configurations function util when nothing to override.\"\"\"\n    agent_config = MagicMock()\n    agent_config.component_configurations = {}\n    expected_configurations = deepcopy(LedgerApis.ledger_api_configs)\n    _override_ledger_configurations(agent_config)\n    actual_configurations = LedgerApis.ledger_api_configs\n    assert expected_configurations == actual_configurations\n\n\ndef test_override_ledger_configurations_positive():\n    \"\"\"Test override ledger configurations function util with fields to override.\"\"\"\n    new_chain_id = \"some_chain\"\n    agent_config = MagicMock()\n    agent_config.component_configurations = {\n        ComponentId(ComponentType.CONNECTION, PublicId.from_str(LEDGER_CONNECTION)): {\n            \"config\": {\"ledger_apis\": {DEFAULT_LEDGER: {\"chain_id\": new_chain_id}}}\n        }\n    }\n    old_configurations = deepcopy(LedgerApis.ledger_api_configs)\n\n    expected_configurations = deepcopy(old_configurations[DEFAULT_LEDGER])\n    expected_configurations[\"chain_id\"] = new_chain_id\n    try:\n        _override_ledger_configurations(agent_config)\n        actual_configurations = LedgerApis.ledger_api_configs.get(\"fetchai\")\n        assert expected_configurations == actual_configurations\n    finally:\n        # this is important - _ovveride_ledger_configurations does\n        # side-effect to LedgerApis.ledger_api_configs\n        LedgerApis.ledger_api_configs = old_configurations\n        assert (\n            LedgerApis.ledger_api_configs[DEFAULT_LEDGER][\"chain_id\"]\n            == FETCHAI_DEFAULT_CHAIN_ID\n        )\n\n\ndef test_mutually_exclusive_usage_error():\n    \"\"\"Test MutuallyExclusiveOption.handle_parse_result.\"\"\"\n    opt = MutuallyExclusiveOption([\"--arg1\"], mutually_exclusive=[\"arg2\"])\n    with pytest.raises(\n        UsageError,\n        match=f\"Illegal usage: `arg1` is mutually exclusive with arguments `{', '.join(['arg2'])}`.\",\n    ):\n        opt.handle_parse_result(MagicMock(), {\"arg1\": None, \"arg2\": None}, [])\n\n\n@mock.patch(\"aea.cli.utils.config.get_or_create_cli_config\", return_value={})\ndef test_set_cli_author_negative(*_mocks):\n    \"\"\"Test set_cli_author, negative case.\"\"\"\n    with pytest.raises(\n        ClickException,\n        match=\"The AEA configurations are not initialized. Use `aea init` before continuing.\",\n    ):\n        set_cli_author(MagicMock())\n\n\n@mock.patch(\n    \"aea.cli.utils.config.get_or_create_cli_config\",\n    return_value=dict(author=\"some_author\"),\n)\ndef test_set_cli_author_positive(*_mocks):\n    \"\"\"Test set_cli_author, positive case.\"\"\"\n    context_mock = MagicMock()\n    set_cli_author(context_mock)\n    context_mock.obj.set_config.assert_called_with(\"cli_author\", \"some_author\")\n\n\ndef test_password_option():\n    \"\"\"Test password option.\"\"\"\n\n    @click.command()\n    @password_option()\n    def cmd(password):\n        raise ValueError(password)\n\n    # no password specified\n    with pytest.raises(ValueError, match=\"None\"):\n        CliRunner().invoke(cmd, [], catch_exceptions=False, standalone_mode=False)\n\n    # --password specified\n    password = uuid4().hex\n    with pytest.raises(ValueError, match=password):\n        CliRunner().invoke(\n            cmd, [\"--password\", password], catch_exceptions=False, standalone_mode=False\n        )\n\n    # -p to ask with click.prompt\n    with pytest.raises(ValueError, match=password):\n        with patch(\"click.prompt\", return_value=password):\n            CliRunner().invoke(\n                cmd, [\"-p\"], catch_exceptions=False, standalone_mode=False\n            )\n    # -p and --password togehter, -p in priority\n    with pytest.raises(ValueError, match=password):\n        with patch(\"click.prompt\", return_value=\"prompted_password\"):\n            CliRunner().invoke(\n                cmd,\n                [\"-p\", \"--password\", password],\n                catch_exceptions=False,\n                standalone_mode=False,\n            )\n\n\ndef test_context_registry_path_does_not_exist():\n    \"\"\"Test context registry path specified but not found.\"\"\"\n    with pytest.raises(\n        ValueError, match=\"Registry path directory provided .* can not be found.\"\n    ):\n        Context(\n            cwd=\".\", verbosity=\"\", registry_path=\"some_path_does_not_exist\"\n        ).registry_path\n\n    with TemporaryDirectory() as tmp_dir:\n        with cd(tmp_dir):\n            with pytest.raises(\n                ValueError,\n                match=\"Registry path not provided and local registry `packages` not found\",\n            ):\n                Context(cwd=\".\", verbosity=\"\", registry_path=None).registry_path\n"
  },
  {
    "path": "tests/test_aea/test_cli/tools_for_testing.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Tools used for CLI registry testing.\"\"\"\nfrom typing import List\nfrom unittest.mock import Mock\n\nfrom aea_ledger_cosmos import CosmosCrypto\nfrom aea_ledger_ethereum import EthereumCrypto\nfrom click import ClickException\nfrom packaging.specifiers import SpecifierSet\n\nimport aea\nfrom aea.configurations.base import PackageVersion\nfrom aea.configurations.constants import DEFAULT_LEDGER\n\nfrom tests.conftest import AUTHOR\nfrom tests.test_aea.test_cli.constants import DEFAULT_TESTING_VERSION\n\n\ndef raise_click_exception(*args, **kwargs):\n    \"\"\"Raise ClickException.\"\"\"\n    raise ClickException(\"Message\")\n\n\nclass AgentConfigMock:\n    \"\"\"A class to mock Agent config.\"\"\"\n\n    def __init__(self, *args, **kwargs):\n        \"\"\"Init the AgentConfigMock object.\"\"\"\n        self.aea_version_specifiers: SpecifierSet = kwargs.get(\n            \"aea_version_specifier\", SpecifierSet(f\"=={aea.__version__}\")\n        )\n        self.connections: List[str] = kwargs.get(\"connections\", [])\n        self.contracts: List[str] = kwargs.get(\"contracts\", [])\n        self.description: str = kwargs.get(\"description\", \"\")\n        self.version: str = kwargs.get(\"version\", \"\")\n        self.protocols: List[str] = kwargs.get(\"protocols\", [])\n        self.skills: List[str] = kwargs.get(\"skills\", [])\n        self.agent_name: str = kwargs.get(\"agent_name\", \"agent_name\")\n        self.author: str = AUTHOR\n        private_key_paths = kwargs.get(\"private_key_paths\", [])\n        self.private_key_paths = Mock()\n        self.private_key_paths.read_all = Mock(return_value=private_key_paths)\n        self.private_key_paths.read = Mock(\n            return_value=private_key_paths[0][1] if private_key_paths else None\n        )\n        connection_private_key_paths = kwargs.get(\"connection_private_key_paths\", [])\n        self.connection_private_key_paths = Mock()\n        self.connection_private_key_paths.read_all = Mock(\n            return_value=connection_private_key_paths\n        )\n        self.get = lambda x, default=None: getattr(self, x, default)\n        self.component_configurations = {}\n        self.package_dependencies = set()\n        self.config: dict = {}\n        self.default_ledger = DEFAULT_LEDGER\n\n    name = \"name\"\n\n\nclass FaultyAgentConfigMock:\n    \"\"\"A Class to mock Agent config with missing attributes.\"\"\"\n\n    def __init__(self, *args, **kwargs):\n        \"\"\"Init faulty agent config.\"\"\"\n\n\nclass ContextMock:\n    \"\"\"A class to mock Context.\"\"\"\n\n    cwd = \"cwd\"\n\n    def __init__(self, *args, **kwargs):\n        \"\"\"Init the ContextMock object.\"\"\"\n        self.invoke = Mock()\n        self.agent_config = AgentConfigMock(*args, **kwargs)\n        self.config: dict = {}\n        self.connection_loader = ConfigLoaderMock()\n        self.agent_loader = ConfigLoaderMock()\n        self.clean_paths: List = []\n        self.obj = self\n        self.registry_path = \"packages\"\n        self.cwd = \"cwd\"\n\n    def set_config(self, key, value):\n        \"\"\"Set config.\"\"\"\n        setattr(self.config, key, value)\n\n\nclass PublicIdMock:\n    \"\"\"A class to mock PublicId.\"\"\"\n\n    DEFAULT_VERSION = DEFAULT_TESTING_VERSION\n\n    def __init__(self, author=AUTHOR, name=\"name\", version=DEFAULT_TESTING_VERSION):\n        \"\"\"Init the Public ID mock object.\"\"\"\n        self.name = name\n        self.author = author\n        self.version = version\n\n    @classmethod\n    def from_str(cls, public_id):\n        \"\"\"Create object from str public_id without validation.\"\"\"\n        author, name, version = public_id.replace(\":\", \"/\").split(\"/\")\n        return cls(author, name, version)\n\n    @property\n    def package_version(self) -> PackageVersion:\n        \"\"\"Get package version.\"\"\"\n        return PackageVersion(self.version)\n\n\nclass AEAConfMock:\n    \"\"\"A class to mock AgentConfig.\"\"\"\n\n    def __init__(self, *args, **kwargs):\n        \"\"\"Init the AEAConf mock object.\"\"\"\n        self.author = AUTHOR\n        self.version = DEFAULT_TESTING_VERSION\n        self.ledger_apis = Mock()\n        ledger_apis = (\n            (CosmosCrypto.identifier, \"value\"),\n            (EthereumCrypto.identifier, \"value\"),\n        )\n        self.ledger_apis.read_all = Mock(return_value=ledger_apis)\n        ledger_api_config = {\"host\": \"host\", \"port\": \"port\", \"address\": \"address\"}\n        self.ledger_apis.read = Mock(return_value=ledger_api_config)\n\n\nclass ConfigLoaderMock:\n    \"\"\"A class to mock ConfigLoader.\"\"\"\n\n    def __init__(self, *args, **kwargs):\n        \"\"\"Init the ConfigLoader mock object.\"\"\"\n        self.required_fields = kwargs.get(\"required_fields\", [])\n\n    def load(self, *args, **kwargs):\n        \"\"\"Mock the load method.\"\"\"\n        return AEAConfMock()\n\n    def dump(self, *args, **kwargs):\n        \"\"\"Mock the dump method.\"\"\"\n        pass\n\n\nclass StopTest(Exception):\n    \"\"\"An exception to stop test.\"\"\"\n\n    pass\n\n\ndef raise_stoptest(*args, **kwargs):\n    \"\"\"Raise StopTest exception.\"\"\"\n    raise StopTest()\n"
  },
  {
    "path": "tests/test_aea/test_components/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains tests for aea/components/*\"\"\"\n"
  },
  {
    "path": "tests/test_aea/test_components/test_base.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains tests for aea/components/base.py\"\"\"\nimport sys\nfrom pathlib import Path\n\nimport pytest\n\nfrom aea.components.base import Component, load_aea_package\nfrom aea.configurations.base import ConnectionConfig, ProtocolConfig\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass TestComponentProperties:\n    \"\"\"Test accessibility of component properties.\"\"\"\n\n    def setup_class(self):\n        \"\"\"Setup test.\"\"\"\n        self.configuration = ProtocolConfig(\n            \"name\", \"author\", \"0.1.0\", protocol_specification_id=\"some/author:0.1.0\"\n        )\n        self.configuration.build_directory = \"test\"\n        self.component = Component(configuration=self.configuration)\n        self.directory = Path()\n        self.component._directory = self.directory\n\n    def test_component_type(self):\n        \"\"\"Test component type attribute.\"\"\"\n        assert self.component.component_type == self.configuration.component_type\n\n    def test_is_vendor(self):\n        \"\"\"Test component type attribute.\"\"\"\n        assert self.component.is_vendor is False\n\n    def test_prefix_import_path(self):\n        \"\"\"Test component type attribute.\"\"\"\n        assert self.component.prefix_import_path == \"packages.author.protocols.name\"\n\n    def test_component_id(self):\n        \"\"\"Test component id.\"\"\"\n        assert self.component.component_id == self.configuration.component_id\n\n    def test_public_id(self):\n        \"\"\"Test public id.\"\"\"\n        assert self.component.public_id == self.configuration.public_id\n\n    def test_directory(self):\n        \"\"\"Test directory.\"\"\"\n        assert self.component.directory == self.directory\n\n    def test_build_directory(self):\n        \"\"\"Test directory.\"\"\"\n        assert self.component.build_directory\n\n\ndef test_directory_setter():\n    \"\"\"Test directory.\"\"\"\n    configuration = ProtocolConfig(\n        \"author\", \"name\", \"0.1.0\", protocol_specification_id=\"some/author:0.1.0\"\n    )\n    component = Component(configuration=configuration)\n\n    with pytest.raises(ValueError):\n        component.directory\n\n    new_path = Path(\"new_path\")\n    component.directory = new_path\n    assert component.directory == new_path\n\n\ndef test_load_aea_package():\n    \"\"\"Test aea package load.\"\"\"\n    config = ConnectionConfig(\"http_client\", \"fetchai\", \"0.5.0\")\n    config.directory = (\n        Path(ROOT_DIR) / \"packages\" / \"fetchai\" / \"connections\" / \"http_client\"\n    )\n    load_aea_package(config)\n\n\ndef test_load_aea_package_twice():\n    \"\"\"Test aea package load twice and ensure python objects stay the same.\"\"\"\n    config = ConnectionConfig(\"http_client\", \"fetchai\", \"0.5.0\")\n    config.directory = (\n        Path(ROOT_DIR) / \"packages\" / \"fetchai\" / \"connections\" / \"http_client\"\n    )\n    sys.modules.pop(\"packages.fetchai.connections.http_client.connection\", None)\n    load_aea_package(config)\n    assert \"packages.fetchai.connections.http_client.connection\" not in sys.modules\n    from packages.fetchai.connections.http_client.connection import HTTPClientConnection\n\n    assert \"packages.fetchai.connections.http_client.connection\" in sys.modules\n    BaseHTTPCLientConnection = HTTPClientConnection\n    load_aea_package(config)\n    from packages.fetchai.connections.http_client.connection import HTTPClientConnection\n\n    assert BaseHTTPCLientConnection is HTTPClientConnection\n"
  },
  {
    "path": "tests/test_aea/test_components/test_loader.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains tests for aea/components/loader.py\"\"\"\nfrom pathlib import Path\nfrom unittest import mock\n\nimport pytest\n\nfrom aea.components.loader import load_component_from_config\nfrom aea.configurations.base import ProtocolConfig\nfrom aea.exceptions import (\n    AEAComponentLoadException,\n    AEAInstantiationException,\n    AEAPackageLoadingError,\n)\nfrom aea.helpers.base import cd\nfrom aea.protocols.base import Protocol\nfrom aea.test_tools.test_cases import AEATestCaseEmpty\n\nfrom tests.common.pexpect_popen import PexpectWrapper\n\n\n@pytest.fixture(scope=\"module\")\ndef component_configuration():\n    \"\"\"Return a component configuration.\"\"\"\n    return ProtocolConfig(\n        \"a_protocol\",\n        \"an_author\",\n        \"0.1.0\",\n        protocol_specification_id=\"some/author:0.1.0\",\n    )\n\n\ndef test_component_loading_generic_exception(component_configuration):\n    \"\"\"Test 'load_component_from_config' method when a generic \"Exception\" occurs.\"\"\"\n\n    with mock.patch.object(\n        Protocol, \"from_config\", side_effect=Exception(\"Generic exception\")\n    ):\n        with pytest.raises(\n            Exception, match=\"Package loading error: An error occurred while loading\"\n        ):\n            load_component_from_config(component_configuration)\n\n\ndef test_component_loading_generic_module_not_found_error(component_configuration):\n    \"\"\"Test 'load_component_from_config' method when a generic \"ModuleNotFoundError\" occurs.\"\"\"\n\n    with mock.patch.object(\n        Protocol,\n        \"from_config\",\n        side_effect=ModuleNotFoundError(\n            \"Package loading error: An error occurred while loading .*: Generic error\"\n        ),\n    ):\n        with pytest.raises(ModuleNotFoundError, match=\"Generic error\"):\n            load_component_from_config(component_configuration)\n\n\ndef test_component_loading_module_not_found_error_non_framework_package(\n    component_configuration,\n):\n    \"\"\"Test 'load_component_from_config' method when a \"ModuleNotFoundError\" occurs for a generic import path (non framework related.\"\"\"\n    with mock.patch.object(\n        Protocol,\n        \"from_config\",\n        side_effect=ModuleNotFoundError(\"No module named 'generic.package'\"),\n    ):\n        with pytest.raises(ModuleNotFoundError):\n            load_component_from_config(component_configuration)\n\n\ndef test_component_loading_module_not_found_error_framework_package(\n    component_configuration,\n):\n    \"\"\"Test 'load_component_from_config' method when a \"ModuleNotFoundError\" occurs for a framework-related import (starts with 'packages') but for some reason it doesn't contain the author name.\"\"\"\n    with mock.patch.object(\n        Protocol,\n        \"from_config\",\n        side_effect=ModuleNotFoundError(\"No module named 'packages'\"),\n    ):\n        with pytest.raises(ModuleNotFoundError, match=\"No module named 'packages'\"):\n            load_component_from_config(component_configuration)\n\n\ndef test_component_loading_module_not_found_error_framework_package_with_wrong_author(\n    component_configuration,\n):\n    \"\"\"Test 'load_component_from_config' method when a \"ModuleNotFoundError\" occurs for a framework-related import (starts with 'packages') with wrong author.\"\"\"\n    with mock.patch.object(\n        Protocol,\n        \"from_config\",\n        side_effect=ModuleNotFoundError(\"No module named 'packages.some_author'\"),\n    ):\n        with pytest.raises(\n            AEAPackageLoadingError,\n            match=\"An error occurred while loading protocol an_author/a_protocol:0.1.0:\",\n        ) as e:\n            load_component_from_config(component_configuration)\n            assert \"some_type\" in str(e)\n\n\ndef test_component_loading_module_not_found_error_framework_package_with_wrong_type(\n    component_configuration,\n):\n    \"\"\"Test 'load_component_from_config' method when a \"ModuleNotFoundError\" occurs for a framework-related import (starts with 'packages') with correct author but wrong type.\"\"\"\n    with mock.patch.object(\n        Protocol,\n        \"from_config\",\n        side_effect=ModuleNotFoundError(\n            \"No module named 'packages.some_author.some_type'\"\n        ),\n    ):\n        with pytest.raises(\n            AEAPackageLoadingError,\n            match=\"An error occurred while loading protocol an_author/a_protocol:0.1.0:\",\n        ) as e:\n            load_component_from_config(component_configuration)\n            assert (\n                \"package 'packages/some_author' of type 'protocols' exists, but cannot find module 'some_type'\"\n                in e.value.args[0]\n            )\n\n\ndef test_component_loading_module_not_found_error_framework_package_with_wrong_name(\n    component_configuration,\n):\n    \"\"\"Test 'load_component_from_config' method when a \"ModuleNotFoundError\" occurs for a framework-related import (starts with 'packages') with correct author and type but wrong name.\"\"\"\n    with mock.patch.object(\n        Protocol,\n        \"from_config\",\n        side_effect=ModuleNotFoundError(\n            \"No module named 'packages.some_author.protocols.some_name'\"\n        ),\n    ):\n        with pytest.raises(\n            AEAPackageLoadingError,\n            match=\"An error occurred while loading protocol an_author/a_protocol:0.1.0:\",\n        ) as e:\n            load_component_from_config(component_configuration)\n        assert (\n            \" No AEA package found with author name 'some_author', type 'protocols', name 'some_name'\"\n            in e.value.args[0]\n        )\n\n\ndef test_component_loading_module_not_found_error_framework_package_with_wrong_suffix(\n    component_configuration,\n):\n    \"\"\"Test 'load_component_from_config' method when a \"ModuleNotFoundError\" occurs for a framework-related import (starts with 'packages') with correct author and type but wrong suffix.\"\"\"\n    with mock.patch.object(\n        Protocol,\n        \"from_config\",\n        side_effect=ModuleNotFoundError(\n            \"No module named 'packages.some_author.protocols.some_name.some_subpackage'\"\n        ),\n    ):\n        with pytest.raises(\n            AEAPackageLoadingError,\n            match=\"An error occurred while loading protocol an_author/a_protocol:0.1.0:\",\n        ) as e:\n            load_component_from_config(component_configuration)\n        assert (\n            \"package 'packages/some_author' of type 'protocols' exists, but cannot find module 'some_subpackage'\"\n            in e.value.args[0]\n        )\n\n\ndef test_component_loading_instantiation_exception(component_configuration):\n    \"\"\"Test 'load_component_from_config' method when a generic \"Exception\" occurs.\"\"\"\n\n    with mock.patch.object(\n        Protocol,\n        \"from_config\",\n        side_effect=AEAInstantiationException(\"Generic exception\"),\n    ):\n        with pytest.raises(AEAInstantiationException):\n            load_component_from_config(component_configuration)\n\n\ndef test_component_loading_component_exception(component_configuration):\n    \"\"\"Test 'load_component_from_config' method when a generic \"Exception\" occurs.\"\"\"\n\n    with mock.patch.object(\n        Protocol,\n        \"from_config\",\n        side_effect=AEAComponentLoadException(\"Generic exception\"),\n    ):\n        with pytest.raises(\n            AEAPackageLoadingError,\n            match=\"Package loading error: An error occurred while loading protocol an_author/a_protocol:0.1.0: Generic exception\",\n        ):\n            load_component_from_config(component_configuration)\n\n\nclass TestLoadFailedCauseImportedPackageNotFound(AEATestCaseEmpty):\n    \"\"\"Test package not found in import.\"\"\"\n\n    def test_load_component_failed_cause_package_not_found(self):\n        \"\"\"Test package not found in import.\"\"\"\n        self.generate_private_key()\n        self.add_private_key()\n        self.add_item(\"skill\", \"fetchai/echo:latest\", local=True)\n\n        with cd(self._get_cwd()):\n            echo_dir = \"./vendor/fetchai/skills/echo\"\n            handlers_file = Path(echo_dir) / \"handlers.py\"\n            assert handlers_file.exists()\n            file_data = handlers_file.read_text()\n            file_data = file_data.replace(\n                \"from packages.fetchai.protocols.default\",\n                \"from packages.fetchai.protocols.not_exist_protocol\",\n            )\n            handlers_file.write_text(file_data)\n            with cd(\"./vendor/fetchai\"):\n                self.run_cli_command(\"fingerprint\", \"skill\", \"fetchai/echo:0.20.6\")\n\n            proc = PexpectWrapper.aea_cli([\"run\"], cwd=self._get_cwd())\n            proc.expect_all(\n                [\"No AEA package found with author name\", \"not_exist_protocol\"]\n            )\n"
  },
  {
    "path": "tests/test_aea/test_components/test_utils.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains tests for aea/components/utils.py\"\"\"\nfrom itertools import chain\nfrom unittest.mock import patch\n\nfrom aea.components.utils import _enlist_component_packages, _populate_packages\n\nfrom tests.test_aea.test_aea import test_act\n\n\ndef test_modules_enlisted_and_loaded():\n    \"\"\"Test modules enlisted and loaded back.\"\"\"\n    # ensure some packages loaded\n    test_act()\n\n    packages = _enlist_component_packages()\n    num_of_packages = len(list(chain(*packages.values())))\n    assert num_of_packages > 0, \"No packages present\"\n\n    with patch(\"aea.components.utils.perform_load_aea_package\") as mock_package_load:\n        _populate_packages(packages)\n        assert mock_package_load.call_count == num_of_packages, packages\n"
  },
  {
    "path": "tests/test_aea/test_configurations/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This test module contains the tests for the aea.configurations module.\"\"\"\n"
  },
  {
    "path": "tests/test_aea/test_configurations/test_aea_config.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests for the aea configurations.\"\"\"\nimport io\nfrom enum import Enum\nfrom pathlib import Path\nfrom textwrap import dedent\nfrom typing import Any, List, Sequence\nfrom unittest import TestCase\n\nimport pytest\nimport yaml\nfrom jsonschema.exceptions import ValidationError  # type: ignore\n\nfrom aea.aea import AEA\nfrom aea.aea_builder import AEABuilder\nfrom aea.configurations.base import (\n    AgentConfig,\n    ComponentId,\n    ComponentType,\n    PackageType,\n    PublicId,\n)\nfrom aea.configurations.loader import ConfigLoader, ConfigLoaders\nfrom aea.exceptions import AEAValidationError\nfrom aea.helpers.exception_policy import ExceptionPolicyEnum\nfrom aea.helpers.yaml_utils import yaml_load_all\n\nfrom tests.conftest import CUR_PATH, ROOT_DIR\n\n\nclass NotSet(type):\n    \"\"\"Definition to use when variable is not set.\"\"\"\n\n\nbase_config = dedent(\n    \"\"\"\nagent_name: my_seller_aea\nauthor: solarw\nversion: 0.1.0\nlicense: Apache-2.0\nfingerprint: {}\nfingerprint_ignore_patterns: []\naea_version: '>=1.0.0, <2.0.0'\ndescription: ''\nconnections: []\ncontracts: []\nprotocols: []\nskills: []\ndefault_connection: null\ndefault_ledger: cosmos\nrequired_ledgers: [cosmos]\nprivate_key_paths:\n    cosmos: tests/data/cosmos_private_key.txt\nconnection_private_key_paths:\n    cosmos: tests/data/cosmos_private_key.txt\ndependencies: {}\n\"\"\"\n)\n\n\nclass BaseConfigTestVariable(TestCase):\n    \"\"\"Base class to test aea config variables.\"\"\"\n\n    OPTION_NAME: str = \"\"\n    CONFIG_ATTR_NAME: str = \"\"\n    GOOD_VALUES: Sequence[Any] = []\n    INCORRECT_VALUES: List[Any] = []\n    BASE_CONFIG: str = base_config\n    REQUIRED: bool = False\n    AEA_ATTR_NAME: str = \"\"\n    AEA_DEFAULT_VALUE: Any = None\n\n    @classmethod\n    def setUpClass(cls) -> None:\n        \"\"\"Skip tests for base class.\"\"\"\n        if cls is BaseConfigTestVariable:\n            pytest.skip(\"base class\")\n        super(BaseConfigTestVariable, cls).setUpClass()\n\n    @property\n    def loader(self) -> ConfigLoader:\n        \"\"\"\n        Create ConfigLoader for Agent config.\n\n        :return: ConfigLoader for AgentConfig\n        \"\"\"\n        return ConfigLoader.from_configuration_type(PackageType.AGENT)\n\n    def _make_configuration_yaml(self, value: Any = NotSet) -> str:\n        \"\"\"Create yaml text configuration file for aea with value for tested parameter.\n\n        :param value: value to set for test config parameter\n\n        :return: string yaml\n        \"\"\"\n        if value is NotSet:\n            return self.BASE_CONFIG\n        value = self._un_enum_value(value)\n        return f\"{self.BASE_CONFIG}\\n\" + yaml.dump({self.OPTION_NAME: value})\n\n    def _make_configuration(self, value: Any = NotSet) -> AgentConfig:\n        \"\"\"Create AgentConfig file using generated yaml file with value set.\n\n        :param value: value to set for test config parameter\n\n        :return: AgentConfig\n        \"\"\"\n        config_data = self._make_configuration_yaml(value)\n        f = io.StringIO(config_data)\n        return self.loader.load(f)\n\n    @staticmethod\n    def _un_enum_value(value: Any) -> Any:\n        \"\"\"Return enum.value if value is enum, otherwise just value.\"\"\"\n        if isinstance(value, Enum):\n            value = value.value\n        return value\n\n    def test_no_variable_passed(self) -> None:\n        \"\"\"Test option not specified in cofig.\"\"\"\n        if self.REQUIRED:\n            with self.assertRaises(ValidationError):\n                self._make_configuration(NotSet)\n            return\n        configuration = self._make_configuration(NotSet)\n        assert getattr(configuration, self.CONFIG_ATTR_NAME) is None\n\n    def test_good_value_passed(self) -> None:\n        \"\"\"Test correct values parsed and set.\"\"\"\n        for good_value in self.GOOD_VALUES:\n            good_value = self._un_enum_value(good_value)\n            configuration = self._make_configuration(good_value)\n            assert getattr(configuration, self.CONFIG_ATTR_NAME) == good_value\n\n    def test_incorrect_value_passed(self) -> None:\n        \"\"\"Test validation error on incorrect values.\"\"\"\n        for incorrect_value in self.INCORRECT_VALUES:\n            with pytest.raises(\n                AEAValidationError,\n                match=\"The following errors occurred during validation:\",\n            ):\n                self._make_configuration(incorrect_value)\n\n    def _get_aea_value(self, aea: AEA) -> Any:\n        \"\"\"Get AEA attribute value.\n\n        :param aea: AEA instance to get attribute value from.\n\n        :return: value of attribute.\n        \"\"\"\n        return getattr(aea, self.AEA_ATTR_NAME)\n\n    def test_builder_applies_default_value_to_aea(self) -> None:\n        \"\"\"Test AEABuilder applies default value to AEA instance when option is not specified in config.\"\"\"\n        configuration = self._make_configuration(NotSet)\n        builder = AEABuilder()\n        builder.set_from_configuration(configuration, aea_project_path=Path(\".\"))\n        aea = builder.build()\n\n        assert self._get_aea_value(aea) == self.AEA_DEFAULT_VALUE\n\n    def test_builder_applies_config_value_to_aea(self) -> None:\n        \"\"\"Test AEABuilder applies value to AEA instance when option is specified in config.\"\"\"\n        for good_value in self.GOOD_VALUES:\n            configuration = self._make_configuration(good_value)\n            builder = AEABuilder()\n            builder.set_from_configuration(\n                configuration, aea_project_path=Path(ROOT_DIR)\n            )\n            aea = builder.build()\n\n            assert self._get_aea_value(aea) == good_value\n\n\nclass TestPeriodConfigVariable(BaseConfigTestVariable):\n    \"\"\"Test `period` aea config option.\"\"\"\n\n    OPTION_NAME = \"period\"\n    CONFIG_ATTR_NAME = \"period\"\n    GOOD_VALUES = [0.1, 1.1]\n    INCORRECT_VALUES = [0, \"sTrING?\", -1]\n    REQUIRED = False\n    AEA_ATTR_NAME = \"_period\"\n    AEA_DEFAULT_VALUE = AEABuilder.DEFAULT_AGENT_ACT_PERIOD\n\n\nclass TestExecutionTimeoutConfigVariable(BaseConfigTestVariable):\n    \"\"\"Test `execution_timeout` aea config option.\"\"\"\n\n    OPTION_NAME = \"execution_timeout\"\n    CONFIG_ATTR_NAME = \"execution_timeout\"\n    GOOD_VALUES = [0, 1.1]\n    INCORRECT_VALUES = [\"sTrING?\", -1]\n    REQUIRED = False\n    AEA_ATTR_NAME = \"_execution_timeout\"\n    AEA_DEFAULT_VALUE = AEABuilder.DEFAULT_EXECUTION_TIMEOUT\n\n\nclass TestMaxReactionsConfigVariable(BaseConfigTestVariable):\n    \"\"\"Test `max_reactions` aea config option.\"\"\"\n\n    OPTION_NAME = \"max_reactions\"\n    CONFIG_ATTR_NAME = \"max_reactions\"\n    GOOD_VALUES = [1, 10]\n    INCORRECT_VALUES = [\"sTrING?\", -1, 0, 1.1]\n    REQUIRED = False\n    AEA_ATTR_NAME = \"max_reactions\"\n    AEA_DEFAULT_VALUE = AEABuilder.DEFAULT_MAX_REACTIONS\n\n\nclass TestLoopModeConfigVariable(BaseConfigTestVariable):\n    \"\"\"Test `loop_mode` aea config option.\"\"\"\n\n    OPTION_NAME = \"loop_mode\"\n    CONFIG_ATTR_NAME = \"loop_mode\"\n    GOOD_VALUES = [\"async\", \"sync\"]\n    INCORRECT_VALUES = [None, \"sTrING?\", -1]\n    REQUIRED = False\n    AEA_ATTR_NAME = \"_loop_mode\"\n    AEA_DEFAULT_VALUE = AEABuilder.DEFAULT_LOOP_MODE\n\n    def _get_aea_value(self, aea: AEA) -> Any:\n        \"\"\"Get AEA attribute value.\n\n        :param aea: AEA isntance to get atribute value from.\n\n        :return: value of attribute.\n        \"\"\"\n        return aea.runtime.loop_mode\n\n\nclass TestSkillExceptionPolicyConfigVariable(BaseConfigTestVariable):\n    \"\"\"Test `skill_exception_policy` aea config option.\"\"\"\n\n    OPTION_NAME = \"skill_exception_policy\"\n    CONFIG_ATTR_NAME = \"skill_exception_policy\"\n    GOOD_VALUES = ExceptionPolicyEnum  # type: ignore\n    INCORRECT_VALUES = [None, \"sTrING?\", -1]\n    REQUIRED = False\n    AEA_ATTR_NAME = \"_skills_exception_policy\"\n    AEA_DEFAULT_VALUE = ExceptionPolicyEnum.propagate\n\n\nclass TestStorageUriConfigVariable(BaseConfigTestVariable):\n    \"\"\"Test `storage_uri` aea config option.\"\"\"\n\n    OPTION_NAME = \"storage_uri\"\n    CONFIG_ATTR_NAME = \"storage_uri\"\n    GOOD_VALUES = [\"sqlite://test\"]  # type: ignore\n    INCORRECT_VALUES = [None, -1]\n    REQUIRED = False\n    AEA_ATTR_NAME = \"_storage_uri\"\n    AEA_DEFAULT_VALUE = None\n\n\nclass TestConnectionExceptionPolicyConfigVariable(BaseConfigTestVariable):\n    \"\"\"Test `skill_exception_policy` aea config option.\"\"\"\n\n    OPTION_NAME = \"connection_exception_policy\"\n    CONFIG_ATTR_NAME = \"connection_exception_policy\"\n    GOOD_VALUES = ExceptionPolicyEnum  # type: ignore\n    INCORRECT_VALUES = [None, \"sTrING?\", -1]\n    REQUIRED = False\n    AEA_ATTR_NAME = \"_connection_exception_policy\"\n    AEA_DEFAULT_VALUE = ExceptionPolicyEnum.propagate\n\n\nclass TestRuntimeModeConfigVariable(BaseConfigTestVariable):\n    \"\"\"Test `runtime_mode` aea config option.\"\"\"\n\n    OPTION_NAME = \"runtime_mode\"\n    CONFIG_ATTR_NAME = \"runtime_mode\"\n    GOOD_VALUES = [\"threaded\", \"async\"]\n    INCORRECT_VALUES = [None, \"sTrING?\", -1]\n    REQUIRED = False\n    AEA_ATTR_NAME = \"_runtime_mode\"\n    AEA_DEFAULT_VALUE = AEABuilder.DEFAULT_RUNTIME_MODE\n\n\ndef test_agent_configuration_loading_multipage():\n    \"\"\"Test agent configuration loading, multi-page case.\"\"\"\n    loader = ConfigLoaders.from_package_type(PackageType.AGENT)\n    agent_config = loader.load(\n        Path(CUR_PATH, \"data\", \"aea-config.example_multipage.yaml\").open()\n    )\n\n    # test main agent configuration loaded correctly\n    assert agent_config.agent_name == \"myagent\"\n    assert agent_config.author == \"fetchai\"\n\n    # test component configurations loaded correctly\n    assert len(agent_config.component_configurations) == 1\n    keys = list(agent_config.component_configurations)\n    dummy_skill_public_id = PublicId.from_str(\"dummy_author/dummy:0.1.0\")\n    expected_component_id = ComponentId(\"skill\", dummy_skill_public_id)\n    assert keys[0] == expected_component_id\n\n\ndef test_agent_configuration_loading_multipage_when_empty_file():\n    \"\"\"Test agent configuration loading, multi-page case, in case of empty file.\"\"\"\n    with pytest.raises(ValueError, match=\"Agent configuration file was empty.\"):\n        loader = ConfigLoaders.from_package_type(PackageType.AGENT)\n        loader.load(io.StringIO())\n\n\ndef test_agent_configuration_loading_multipage_when_type_not_found():\n    \"\"\"Test agent configuration loading, multi-page case, when type not found in some component.\"\"\"\n    # remove type field manually\n    file = Path(CUR_PATH, \"data\", \"aea-config.example_multipage.yaml\").open()\n    jsons = list(yaml.safe_load_all(file))\n    jsons[1].pop(\"type\")\n    modified_file = io.StringIO()\n    yaml.safe_dump_all(jsons, modified_file)\n    modified_file.seek(0)\n\n    with pytest.raises(\n        ValueError, match=\"There are missing fields in component id 1: {'type'}.\"\n    ):\n        loader = ConfigLoaders.from_package_type(PackageType.AGENT)\n        loader.load(modified_file)\n\n\ndef test_agent_configuration_loading_multipage_when_same_id():\n    \"\"\"Test agent configuration loading, multi-page case, when there are two components with the same id.\"\"\"\n    file = Path(CUR_PATH, \"data\", \"aea-config.example_multipage.yaml\").open()\n    jsons = list(yaml.safe_load_all(file))\n    # add twice the last component\n    jsons.append(jsons[-1])\n    modified_file = io.StringIO()\n    yaml.safe_dump_all(jsons, modified_file)\n    modified_file.seek(0)\n\n    with pytest.raises(\n        ValueError,\n        match=r\"Configuration of component \\(skill, dummy_author/dummy:0.1.0\\) occurs more than once.\",\n    ):\n        loader = ConfigLoaders.from_package_type(PackageType.AGENT)\n        loader.load(modified_file)\n\n\ndef test_agent_configuration_loading_multipage_validation_error():\n    \"\"\"Test agent configuration loading, multi-page case, when the configuration is invalid.\"\"\"\n    file = Path(CUR_PATH, \"data\", \"aea-config.example_multipage.yaml\").open()\n    jsons = list(yaml.safe_load_all(file))\n    # make invalid the last component configuration\n    jsons[-1][\"invalid_attribute\"] = \"foo\"\n    modified_file = io.StringIO()\n    yaml.safe_dump_all(jsons, modified_file)\n    modified_file.seek(0)\n\n    with pytest.raises(\n        ValueError,\n        match=r\"Configuration of component \\(skill, dummy_author/dummy:0.1.0\\) is not valid.\",\n    ):\n        loader = ConfigLoaders.from_package_type(PackageType.AGENT)\n        loader.load(modified_file)\n\n\n@pytest.mark.parametrize(\n    \"component_type\",\n    [\n        ComponentType.PROTOCOL,\n        ComponentType.CONNECTION,\n        ComponentType.CONTRACT,\n        ComponentType.SKILL,\n    ],\n)\ndef test_agent_configuration_loading_multipage_positive_case(component_type):\n    \"\"\"Test agent configuration loading, multi-page case, positive case.\"\"\"\n    public_id = PublicId(\"dummy_author\", \"dummy\", \"0.1.0\")\n    file = Path(CUR_PATH, \"data\", \"aea-config.example.yaml\").open()\n    json_data = yaml.safe_load(file)\n    json_data[component_type.to_plural()].append(str(public_id))\n    modified_file = io.StringIO()\n    yaml.safe_dump(json_data, modified_file)\n    modified_file.flush()\n    modified_file.write(\"---\\n\")\n    modified_file.write(f\"public_id: {public_id}\\n\")\n    modified_file.write(f\"type: {component_type.value}\\n\")\n    modified_file.seek(0)\n    expected_component_id = ComponentId(\n        component_type, PublicId(\"dummy_author\", \"dummy\", \"0.1.0\")\n    )\n\n    loader = ConfigLoaders.from_package_type(PackageType.AGENT)\n    agent_config = loader.load(modified_file)\n    assert isinstance(agent_config.component_configurations, dict)\n    assert len(agent_config.component_configurations)\n    assert set(agent_config.component_configurations.keys()) == {expected_component_id}\n\n\ndef test_agent_configuration_dump_multipage():\n    \"\"\"Test agent configuration dump with component configuration.\"\"\"\n    loader = ConfigLoaders.from_package_type(PackageType.AGENT)\n    agent_config = loader.load(\n        Path(CUR_PATH, \"data\", \"aea-config.example_multipage.yaml\").open()\n    )\n\n    # test main agent configuration loaded correctly\n    assert agent_config.agent_name == \"myagent\"\n    assert agent_config.author == \"fetchai\"\n\n    # test component configurations loaded correctly\n    assert len(agent_config.component_configurations) == 1\n    fp = io.StringIO()\n    loader.dump(agent_config, fp)\n    fp.seek(0)\n    agent_config = yaml_load_all(fp)\n    assert agent_config[0][\"agent_name\"] == \"myagent\"\n    assert agent_config[1][\"public_id\"] == \"dummy_author/dummy:0.1.0\"\n    assert agent_config[1][\"type\"] == \"skill\"\n\n\ndef test_agent_configuration_dump_multipage_fails_bad_component_configuration():\n    \"\"\"Test agent configuration dump with INCORRECT component configuration.\"\"\"\n    loader = ConfigLoaders.from_package_type(PackageType.AGENT)\n    agent_config = loader.load(\n        Path(CUR_PATH, \"data\", \"aea-config.example_multipage.yaml\").open()\n    )\n\n    # test main agent configuration loaded correctly\n    assert agent_config.agent_name == \"myagent\"\n    assert agent_config.author == \"fetchai\"\n\n    # test component configurations loaded correctly\n    assert len(agent_config.component_configurations) == 1\n    list(agent_config.component_configurations.values())[0][\n        \"BAD FIELD\"\n    ] = \"not in specs!\"\n    fp = io.StringIO()\n    with pytest.raises(\n        ValueError,\n        match=\"Configuration of component .* is not valid. ExtraPropertiesError: properties not expected: BAD FIELD\",\n    ):\n        loader.dump(agent_config, fp)\n\n\nclass TestTaskManagerModeConfigVariable(BaseConfigTestVariable):\n    \"\"\"Test `task_manager_mode` aea config option.\"\"\"\n\n    OPTION_NAME = \"task_manager_mode\"\n    CONFIG_ATTR_NAME = \"task_manager_mode\"\n    GOOD_VALUES = [\"threaded\", \"multiprocess\"]\n    INCORRECT_VALUES = [None, \"sTrING?\", -1]\n    REQUIRED = False\n    AEA_ATTR_NAME = \"_task_manager_mode\"\n    AEA_DEFAULT_VALUE = AEABuilder.DEFAULT_TASKMANAGER_MODE\n"
  },
  {
    "path": "tests/test_aea/test_configurations/test_base.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests for the aea.configurations.base module.\"\"\"\nimport re\nfrom copy import copy\nfrom pathlib import Path\nfrom unittest import TestCase, mock\nfrom unittest.mock import Mock\n\nimport pytest\nimport semver\nimport yaml\nfrom packaging.specifiers import SpecifierSet\n\nfrom aea.configurations.base import (\n    AgentConfig,\n    CRUDCollection,\n    ComponentId,\n    ComponentType,\n    ConnectionConfig,\n    ContractConfig,\n    Dependency,\n    PackageId,\n    PackageType,\n    PackageVersion,\n    ProtocolConfig,\n    ProtocolSpecification,\n    PublicId,\n    SkillConfig,\n    SpeechActContentConfig,\n    _check_aea_version,\n    _compare_fingerprints,\n    _get_default_configuration_file_name_from_type,\n    dependencies_from_json,\n    dependencies_to_json,\n)\nfrom aea.configurations.constants import (\n    DEFAULT_AEA_CONFIG_FILE,\n    DEFAULT_GIT_REF,\n    DEFAULT_LEDGER,\n    DEFAULT_PYPI_INDEX_URL,\n    DEFAULT_SKILL_CONFIG_FILE,\n)\nfrom aea.configurations.loader import ConfigLoaders, load_component_configuration\n\nfrom tests.conftest import (\n    AUTHOR,\n    CUR_PATH,\n    DUMMY_SKILL_PATH,\n    ROOT_DIR,\n    agent_config_files,\n    connection_config_files,\n    contract_config_files,\n    protocol_config_files,\n    random_string,\n    skill_config_files,\n)\nfrom tests.data.dummy_skill import PUBLIC_ID as DUMMY_SKILL_PUBLIC_ID\n\n\nclass TestCRUDCollection:\n    \"\"\"Test the CRUDCollection data structure.\"\"\"\n\n    def test_create_with_existing_key(self):\n        \"\"\"Test that creating and item with an existing key raises an exception.\"\"\"\n        collection = CRUDCollection()\n        collection.create(\"one\", 1)\n\n        with pytest.raises(ValueError, match=\"Item with name .* already present\"):\n            collection.create(\"one\", 1)\n\n    def test_read_not_empty(self):\n        \"\"\"Test that reading a previously created item gives a non-empty result.\"\"\"\n        collection = CRUDCollection()\n        collection.create(\"one\", 1)\n        item = collection.read(\"one\")\n        assert item == 1\n\n    def test_read_empty(self):\n        \"\"\"Test that reading with a non-existing key returns None.\"\"\"\n        collection = CRUDCollection()\n        item = collection.read(\"one\")\n        assert item is None\n\n    def test_update(self):\n        \"\"\"Test that the update method works correctly.\"\"\"\n        collection = CRUDCollection()\n        collection.create(\"one\", 1)\n\n        assert collection.read(\"one\") == 1\n        collection.update(\"one\", 2)\n        assert collection.read(\"one\") == 2\n\n    def test_delete(self):\n        \"\"\"Test that the delete method works correctly.\"\"\"\n        collection = CRUDCollection()\n        collection.create(\"one\", 1)\n\n        assert collection.read(\"one\") == 1\n        collection.delete(\"one\")\n        assert collection.read(\"one\") is None\n\n    def test_read_all(self):\n        \"\"\"Test that the read_all method works correctly.\"\"\"\n        collection = CRUDCollection()\n        collection.create(\"one\", 1)\n        collection.create(\"two\", 2)\n\n        keyvalue_pairs = collection.read_all()\n        assert {(\"one\", 1), (\"two\", 2)} == set(keyvalue_pairs)\n\n    def test_keys(self):\n        \"\"\"Test the keys method.\"\"\"\n        collection = CRUDCollection()\n        collection.create(\"one\", 1)\n        collection.create(\"two\", 2)\n\n        keyvalue_pairs = collection.keys()\n        assert {\"one\", \"two\"} == set(keyvalue_pairs)\n\n\nclass TestContractConfig:\n    \"\"\"Test the contract configuration class.\"\"\"\n\n    @pytest.mark.parametrize(\"contract_path\", contract_config_files)\n    def test_from_json_and_to_json(self, contract_path):\n        \"\"\"Test the 'from_json' method and 'to_json' work correctly.\"\"\"\n        f = open(contract_path)\n        original_json = yaml.safe_load(f)\n        original_json[\"build_directory\"] = \"some\"\n\n        expected_config = ContractConfig.from_json(original_json)\n        assert isinstance(expected_config, ContractConfig)\n        expected_json = expected_config.json\n        actual_config = ContractConfig.from_json(expected_json)\n        actual_json = actual_config.json\n        assert expected_json == actual_json\n\n\nclass TestConnectionConfig:\n    \"\"\"Test the connection configuration class.\"\"\"\n\n    @pytest.mark.parametrize(\"connection_path\", connection_config_files)\n    def test_from_json_and_to_json(self, connection_path):\n        \"\"\"Test the 'from_json' method and 'to_json' work correctly.\"\"\"\n        f = open(connection_path)\n        original_json = yaml.safe_load(f)\n        original_json[\"build_directory\"] = \"some\"\n\n        expected_config = ConnectionConfig.from_json(original_json)\n        assert isinstance(expected_config, ConnectionConfig)\n        assert isinstance(expected_config.package_dependencies, set)\n        assert not expected_config.is_abstract_component\n        expected_json = expected_config.json\n        actual_config = ConnectionConfig.from_json(expected_json)\n        actual_json = actual_config.json\n        assert expected_json == actual_json\n\n\nclass TestProtocolConfig:\n    \"\"\"Test the protocol configuration class.\"\"\"\n\n    @pytest.mark.parametrize(\"protocol_path\", protocol_config_files)\n    def test_from_json_and_to_json(self, protocol_path):\n        \"\"\"Test the 'from_json' method and 'to_json' work correctly.\"\"\"\n        f = open(protocol_path)\n        original_json = yaml.safe_load(f)\n        original_json[\"build_directory\"] = \"some\"\n\n        expected_config = ProtocolConfig.from_json(original_json)\n        assert isinstance(expected_config, ProtocolConfig)\n        expected_json = expected_config.json\n        actual_config = ProtocolConfig.from_json(expected_json)\n        actual_json = actual_config.json\n        assert expected_json == actual_json\n\n\nclass TestSkillConfig:\n    \"\"\"\n    Test the skill configuration class.\n\n    This suite tests also the handlers/tasks/behaviours/models configuration classes.\n    \"\"\"\n\n    @pytest.mark.parametrize(\"skill_path\", skill_config_files)\n    def test_from_json_and_to_json(self, skill_path):\n        \"\"\"Test the 'from_json' method and 'to_json' work correctly.\"\"\"\n        f = open(skill_path)\n        original_json = yaml.safe_load(f)\n        original_json[\"build_directory\"] = \"some\"\n\n        expected_config = SkillConfig.from_json(original_json)\n        assert isinstance(expected_config, SkillConfig)\n        expected_json = expected_config.json\n        actual_config = SkillConfig.from_json(expected_json)\n        actual_json = actual_config.json\n        assert expected_json == actual_json\n\n    def test_update_method(self):\n        \"\"\"Test the update method.\"\"\"\n        skill_config_path = Path(DUMMY_SKILL_PATH)\n        loader = ConfigLoaders.from_package_type(PackageType.SKILL)\n        skill_config = loader.load(skill_config_path.open())\n\n        dummy_behaviour = skill_config.behaviours.read(\"dummy\")\n        expected_dummy_behaviour_args = copy(dummy_behaviour.args)\n        expected_dummy_behaviour_args[\"behaviour_arg_1\"] = 42\n\n        dummy_handler = skill_config.handlers.read(\"dummy\")\n        expected_dummy_handler_args = copy(dummy_handler.args)\n        expected_dummy_handler_args[\"handler_arg_1\"] = 42\n\n        dummy_model = skill_config.models.read(\"dummy\")\n        expected_dummy_model_args = copy(dummy_model.args)\n        expected_dummy_model_args[\"model_arg_1\"] = 42\n\n        new_configurations = {\n            \"behaviours\": {\"dummy\": {\"args\": dict(behaviour_arg_1=42)}},\n            \"handlers\": {\"dummy\": {\"args\": dict(handler_arg_1=42)}},\n            \"models\": {\"dummy\": {\"args\": dict(model_arg_1=42)}},\n        }\n        directory = \"test_directory\"\n        skill_config.directory = directory\n        skill_config.update(new_configurations)\n\n        assert skill_config.directory == directory\n\n        assert (\n            expected_dummy_behaviour_args == skill_config.behaviours.read(\"dummy\").args\n        )\n        assert expected_dummy_handler_args == skill_config.handlers.read(\"dummy\").args\n        assert expected_dummy_model_args == skill_config.models.read(\"dummy\").args\n        assert len(skill_config.package_dependencies)\n\n    def test_update_method_raises_error_if_skill_component_not_allowed(self):\n        \"\"\"Test that we raise error if the custom configuration contain unexpected skill components.\"\"\"\n        skill_config_path = Path(\n            ROOT_DIR,\n            \"packages\",\n            \"fetchai\",\n            \"skills\",\n            \"error\",\n            DEFAULT_SKILL_CONFIG_FILE,\n        )\n        loader = ConfigLoaders.from_package_type(PackageType.SKILL)\n        skill_config = loader.load(skill_config_path.open())\n        new_configurations = {\n            \"behaviours\": {\"new_behaviour\": {\"args\": {}}},\n            \"handlers\": {\"new_handler\": {\"args\": {}}},\n            \"models\": {\"new_model\": {\"args\": {}}},\n        }\n\n        with pytest.raises(\n            ValueError,\n            match=\"Attribute `behaviours.new_behaviour.args` is not allowed to be updated!\",\n        ):\n            skill_config.update(new_configurations)\n\n    def test_update_method_raises_error_if_we_try_to_change_classname_of_skill_component(\n        self,\n    ):\n        \"\"\"Test that we raise error if we try to change the 'class_name' field of a skill component configuration.\"\"\"\n        skill_config_path = Path(\n            ROOT_DIR,\n            \"packages\",\n            \"fetchai\",\n            \"skills\",\n            \"error\",\n            DEFAULT_SKILL_CONFIG_FILE,\n        )\n        loader = ConfigLoaders.from_package_type(PackageType.SKILL)\n        skill_config = loader.load(skill_config_path.open())\n        new_configurations = {\n            \"handlers\": {\"error_handler\": {\"class_name\": \"SomeClass\", \"args\": {}}},\n        }\n\n        with pytest.raises(\n            ValueError,\n            match=\"Attribute `handlers.error_handler.class_name` is not allowed to be updated!\",\n        ):\n            skill_config.update(new_configurations)\n\n\nclass TestAgentConfig:\n    \"\"\"Test the agent configuration class.\"\"\"\n\n    @pytest.mark.parametrize(\"agent_path\", agent_config_files)\n    def test_from_json_and_to_json(self, agent_path):\n        \"\"\"Test the 'from_json' method and 'to_json' work correctly.\"\"\"\n        f = open(agent_path)\n        original_jsons = list(yaml.safe_load_all(f))\n        components = original_jsons[1:]\n        original_json = original_jsons[0]\n        original_json[\"component_configurations\"] = components\n        original_json[\"build_entrypoint\"] = \"some\"\n\n        expected_config = AgentConfig.from_json(original_json)\n        assert isinstance(expected_config, AgentConfig)\n        expected_json = expected_config.json\n        actual_config = AgentConfig.from_json(expected_json)\n        actual_json = actual_config.json\n        assert expected_json == actual_json\n\n\nclass TestAgentConfigUpdate:\n    \"\"\"Test methods that change the agent configuration.\"\"\"\n\n    def setup(self):\n        \"\"\"Set up the tests.\"\"\"\n        self.aea_config_path = Path(\n            CUR_PATH, \"data\", \"dummy_aea\", DEFAULT_AEA_CONFIG_FILE\n        )\n        self.loader = ConfigLoaders.from_package_type(PackageType.AGENT)\n        self.aea_config: AgentConfig = self.loader.load(self.aea_config_path.open())\n        self.dummy_skill_component_id = ComponentId(\n            ComponentType.SKILL, DUMMY_SKILL_PUBLIC_ID\n        )\n\n        self.new_dummy_skill_config = {\n            \"behaviours\": {\"dummy\": {\"args\": dict(behaviour_arg_1=42)}},\n            \"handlers\": {\"dummy\": {\"args\": dict(handler_arg_1=42)}},\n            \"models\": {\"dummy\": {\"args\": dict(model_arg_1=42)}},\n        }\n\n    def test_all_components_id(self):\n        \"\"\"Test all components id listing.\"\"\"\n        assert self.dummy_skill_component_id in self.aea_config.all_components_id\n\n    def test_component_configurations_setter(self):\n        \"\"\"Test component configuration setter.\"\"\"\n        assert self.aea_config.component_configurations == {}\n        new_component_configurations = {\n            self.dummy_skill_component_id: self.new_dummy_skill_config\n        }\n        self.aea_config.component_configurations = new_component_configurations\n\n    def test_component_configurations_setter_negative(self):\n        \"\"\"Test component configuration setter with wrong configurations.\"\"\"\n        assert self.aea_config.component_configurations == {}\n        new_component_configurations = {\n            self.dummy_skill_component_id: {\n                \"handlers\": {\"dummy\": {\"class_name\": \"SomeClass\"}}\n            }\n        }\n        with pytest.raises(\n            ValueError, match=r\"Configuration of component .* is not valid.*\"\n        ):\n            self.aea_config.component_configurations = new_component_configurations\n\n    def test_aea_version_setter(self):\n        \"\"\"Test 'aea_version' setter.\"\"\"\n        new_version_specifier = \"==0.1.0\"\n        self.aea_config.aea_version = new_version_specifier\n        assert self.aea_config.aea_version == new_version_specifier\n        assert self.aea_config.aea_version_specifiers == SpecifierSet(\n            new_version_specifier\n        )\n\n    def test_update(self):\n        \"\"\"Test the update method.\"\"\"\n        new_private_key_paths = dict(ethereum=\"foo\")\n        expected_private_key_paths = dict(\n            ethereum=\"foo\",\n            cosmos=\"cosmos_private_key.txt\",\n            fetchai=\"fetchai_private_key.txt\",\n        )\n        self.aea_config.update(\n            dict(\n                component_configurations={\n                    self.dummy_skill_component_id: self.new_dummy_skill_config\n                },\n                private_key_paths=new_private_key_paths,\n                connection_private_key_paths=new_private_key_paths,\n            )\n        )\n        assert (\n            self.aea_config.component_configurations[self.dummy_skill_component_id]\n            == self.new_dummy_skill_config\n        )\n        assert (\n            dict(self.aea_config.private_key_paths.read_all())\n            == expected_private_key_paths\n        )\n        assert (\n            dict(self.aea_config.connection_private_key_paths.read_all())\n            == expected_private_key_paths\n        )\n\n        # test idempotence\n        self.aea_config.update(\n            dict(\n                component_configurations={\n                    self.dummy_skill_component_id: self.new_dummy_skill_config\n                }\n            )\n        )\n        assert (\n            self.aea_config.component_configurations[self.dummy_skill_component_id]\n            == self.new_dummy_skill_config\n        )\n\n        # to json\n        self.aea_config.json\n\n\nclass GetDefaultConfigurationFileNameFromStrTestCase(TestCase):\n    \"\"\"Test case for _get_default_configuration_file_name_from_type method.\"\"\"\n\n    def test__get_default_configuration_file_name_from_type_positive(self):\n        \"\"\"Test for _get_default_configuration_file_name_from_type method positive result.\"\"\"\n        _get_default_configuration_file_name_from_type(\"agent\")\n        _get_default_configuration_file_name_from_type(\"connection\")\n        _get_default_configuration_file_name_from_type(\"protocol\")\n        _get_default_configuration_file_name_from_type(\"skill\")\n        _get_default_configuration_file_name_from_type(\"contract\")\n\n\nclass PublicIdTestCase(TestCase):\n    \"\"\"Test case for PublicId class.\"\"\"\n\n    @mock.patch(\"aea.configurations.data_types.re.match\", return_value=None)\n    def test_public_id_from_str_not_matching(self, *mocks):\n        \"\"\"Test case for from_str method regex not matching.\"\"\"\n        with self.assertRaises(ValueError):\n            PublicId.from_str(\"public_id_str\")\n\n    def test_public_id_from_json_positive(self):\n        \"\"\"Test case for from_json method positive result.\"\"\"\n        obj = {\"author\": AUTHOR, \"name\": \"name\", \"version\": \"0.1.0\"}\n        PublicId.from_json(obj)\n\n    def test_public_id_json_positive(self):\n        \"\"\"Test case for json property positive result.\"\"\"\n        obj = PublicId(AUTHOR, \"name\", \"0.1.0\")\n        obj.json\n\n    def test_public_id_eq_positive(self):\n        \"\"\"Test case for json __eq__ method positive result.\"\"\"\n        obj1 = PublicId(AUTHOR, \"name\", \"0.1.0\")\n        obj2 = PublicId(AUTHOR, \"name\", \"0.1.0\")\n        self.assertTrue(obj1 == obj2)\n\n    def test_public_id_lt_positive(self):\n        \"\"\"Test case for json __lt__ method positive result.\"\"\"\n        obj1 = PublicId(AUTHOR, \"name\", \"1.0.0\")\n        obj2 = PublicId(AUTHOR, \"name\", \"2.0.0\")\n        self.assertTrue(obj1 < obj2)\n\n    def test_is_valid_str(self):\n        \"\"\"Test is_valid_str method.\"\"\"\n        assert PublicId.is_valid_str(\"author/name:0.1.0\")\n        assert not PublicId.is_valid_str(\"author!name:0.1.0\")\n\n    def test_try_from_str(self):\n        \"\"\"Test is_valid_str method.\"\"\"\n        assert PublicId.try_from_str(\"author/name:0.1.0\")\n        assert not PublicId.try_from_str(\"author!name:0.1.0\")\n\n\nclass AgentConfigTestCase(TestCase):\n    \"\"\"Test case for AgentConfig class.\"\"\"\n\n    def test_init_logging_config_positive(self):\n        \"\"\"Test case for from_json method positive result.\"\"\"\n        AgentConfig(agent_name=\"my_agent\", author=\"fetchai\", logging_config={})\n\n    def test_default_connection(self):\n        \"\"\"Test case for default_connection setter positive result.\"\"\"\n        agent_config = AgentConfig(agent_name=\"my_agent\", author=\"fetchai\")\n        agent_config.default_connection = None\n        agent_config.default_connection = 1\n        agent_config.public_id\n\n    def test_name_and_author(self):\n        \"\"\"Test case for default_connection setter positive result.\"\"\"\n        agent_config = AgentConfig(agent_name=\"my_agent\", author=\"fetchai\")\n        agent_config.name = \"new_name\"\n        agent_config.author = \"new_author\"\n\n\nclass SpeechActContentConfigTestCase(TestCase):\n    \"\"\"Test case for SpeechActContentConfig class.\"\"\"\n\n    def test_speech_act_content_config_init_positive(self):\n        \"\"\"Test case for __init__ method positive result.\"\"\"\n        SpeechActContentConfig()\n\n    def test_json_positive(self):\n        \"\"\"Test case for json property positive result.\"\"\"\n        config = SpeechActContentConfig()\n        config.json\n\n    def test_from_json_positive(self):\n        \"\"\"Test case for from_json method positive result.\"\"\"\n        SpeechActContentConfig.from_json({})\n\n\nclass ProtocolSpecificationTestCase(TestCase):\n    \"\"\"Test case for ProtocolSpecification class.\"\"\"\n\n    def test_init_positive(self):\n        \"\"\"Test case for __init__ method positive result.\"\"\"\n        ProtocolSpecification(\n            name=\"my_protocol\",\n            author=\"fetchai\",\n            protocol_specification_id=\"some/author:0.1.0\",\n        )\n\n    def test_json_positive(self):\n        \"\"\"Test case for json property positive result.\"\"\"\n        obj = ProtocolSpecification(\n            name=\"my_protocol\",\n            author=\"fetchai\",\n            protocol_specification_id=\"some/author:0.1.0\",\n        )\n        obj.json\n\n    @mock.patch(\"aea.configurations.base.SpeechActContentConfig.from_json\")\n    def test_from_json_positive(self, *mocks):\n        \"\"\"Test case for from_json method positive result.\"\"\"\n        json_disc = {\n            \"name\": \"name\",\n            \"author\": AUTHOR,\n            \"version\": \"0.1.0\",\n            \"license\": \"license\",\n            \"description\": \"description\",\n            \"speech_acts\": {\"arg1\": \"arg1\", \"arg2\": \"arg2\"},\n            \"protocol_specification_id\": \"some/author:0.1.0\",\n        }\n        ProtocolSpecification.from_json(json_disc)\n\n\ndef test_package_type_plural():\n    \"\"\"Test PackageType.to_plural\"\"\"\n    assert PackageType.AGENT.to_plural() == \"agents\"\n    assert PackageType.PROTOCOL.to_plural() == \"protocols\"\n    assert PackageType.CONNECTION.to_plural() == \"connections\"\n    assert PackageType.CONTRACT.to_plural() == \"contracts\"\n    assert PackageType.SKILL.to_plural() == \"skills\"\n\n\ndef test_package_type_str():\n    \"\"\"Test PackageType.__str__\"\"\"\n    assert str(PackageType.AGENT) == \"agent\"\n    assert str(PackageType.PROTOCOL) == \"protocol\"\n    assert str(PackageType.CONNECTION) == \"connection\"\n    assert str(PackageType.CONTRACT) == \"contract\"\n    assert str(PackageType.SKILL) == \"skill\"\n\n\ndef test_component_type_str():\n    \"\"\"Test ComponentType.__str__\"\"\"\n    assert str(ComponentType.PROTOCOL) == \"protocol\"\n    assert str(ComponentType.CONNECTION) == \"connection\"\n    assert str(ComponentType.CONTRACT) == \"contract\"\n    assert str(ComponentType.SKILL) == \"skill\"\n\n\ndef test_configuration_ordered_json():\n    \"\"\"Test configuration ordered json.\"\"\"\n    configuration = ProtocolConfig(\n        \"name\", \"author\", \"0.1.0\", protocol_specification_id=\"some/author:0.1.0\"\n    )\n    configuration._key_order = [\"aea_version\"]\n    configuration.ordered_json\n\n\ndef test_public_id_versions():\n    \"\"\"Test that a public id version can be initialized with different objects.\"\"\"\n    PublicId(\"author\", \"name\", \"0.1.0\")\n    PublicId(\"author\", \"name\", semver.VersionInfo(major=0, minor=1, patch=0))\n\n\ndef test_public_id_invalid_version():\n    \"\"\"Test the case when the version id is of an invalid type.\"\"\"\n    with pytest.raises(ValueError, match=\"Version type not valid.\"):\n        PublicId(\"author\", \"name\", object())\n\n\ndef test_public_id_from_string():\n    \"\"\"Test parsing the public id from string.\"\"\"\n    public_id = PublicId.from_str(\"author/package:0.1.0\")\n    assert public_id.author == \"author\"\n    assert public_id.name == \"package\"\n    assert public_id.version == \"0.1.0\"\n\n\ndef test_public_id_from_string_without_version_string():\n    \"\"\"Test parsing the public id without version string.\"\"\"\n    public_id = PublicId.from_str(\"author/package\")\n    assert public_id.author == \"author\"\n    assert public_id.name == \"package\"\n    assert public_id.version == \"latest\"\n\n\ndef test_public_id_from_string_with_version_string_latest():\n    \"\"\"Test parsing the public id with version string 'latest'.\"\"\"\n    public_id = PublicId.from_str(\"author/package:latest\")\n    assert public_id.author == \"author\"\n    assert public_id.name == \"package\"\n    assert public_id.version == \"latest\"\n\n\ndef test_public_id_from_uri_path():\n    \"\"\"Test PublicId.from_uri_path\"\"\"\n    result = PublicId.from_uri_path(\"author/package_name/0.1.0\")\n    assert result.name == \"package_name\"\n    assert result.author == \"author\"\n    assert result.version == \"0.1.0\"\n\n\ndef test_public_id_from_uri_path_wrong_input():\n    \"\"\"Test that when a bad formatted path is passed in input of PublicId.from_uri_path an exception is raised.\"\"\"\n    with pytest.raises(\n        ValueError, match=\"Input 'bad/formatted:input' is not well formatted.\"\n    ):\n        PublicId.from_uri_path(\"bad/formatted:input\")\n\n\ndef test_public_id_to_uri_path():\n    \"\"\"Test PublicId.to_uri_path\"\"\"\n    public_id = PublicId(\"author\", \"name\", \"0.1.0\")\n    assert public_id.to_uri_path == \"author/name/0.1.0\"\n\n\ndef test_pubic_id_repr():\n    \"\"\"Test PublicId.__repr__\"\"\"\n    public_id = PublicId(\"author\", \"name\", \"0.1.0\")\n    assert repr(public_id) == \"<author/name:0.1.0>\"\n\n\ndef test_pubic_id_to_latest():\n    \"\"\"Test PublicId.to_latest\"\"\"\n    public_id = PublicId(\"author\", \"name\", \"0.1.0\")\n    expected_public_id = PublicId(\"author\", \"name\", \"latest\")\n    actual_public_id = public_id.to_latest()\n    assert expected_public_id == actual_public_id\n\n\ndef test_pubic_id_to_any():\n    \"\"\"Test PublicId.to_any\"\"\"\n    public_id = PublicId(\"author\", \"name\", \"0.1.0\")\n    expected_public_id = PublicId(\"author\", \"name\", \"any\")\n    actual_public_id = public_id.to_any()\n    assert expected_public_id == actual_public_id\n\n\ndef test_pubic_id_same_prefix():\n    \"\"\"Test PublicId.same_prefix\"\"\"\n    same_1 = PublicId(\"author\", \"name\", \"0.1.0\")\n    same_2 = PublicId(\"author\", \"name\", \"0.1.1\")\n    different = PublicId(\"author\", \"different_name\", \"0.1.0\")\n\n    assert same_1.same_prefix(same_2)\n    assert same_2.same_prefix(same_1)\n\n    assert not different.same_prefix(same_1)\n    assert not same_1.same_prefix(different)\n\n    assert not different.same_prefix(same_2)\n    assert not same_2.same_prefix(different)\n\n\ndef test_public_id_comparator_when_author_is_different():\n    \"\"\"Test PublicId.__lt__ when author is different.\"\"\"\n    pid1 = PublicId(\"author_1\", \"name\", \"0.1.0\")\n    pid2 = PublicId(\"author_2\", \"name\", \"0.1.0\")\n    with pytest.raises(\n        ValueError,\n        match=\"The public IDs .* and .* cannot be compared. Their author or name attributes are different.\",\n    ):\n        _ = pid1 < pid2\n\n\ndef test_public_id_comparator_when_name_is_different():\n    \"\"\"Test PublicId.__lt__ when author is different.\"\"\"\n    pid1 = PublicId(\"author\", \"name_1\", \"0.1.0\")\n    pid2 = PublicId(\"author\", \"name_2\", \"0.1.0\")\n    with pytest.raises(\n        ValueError,\n        match=\"The public IDs .* and .* cannot be compared. Their author or name attributes are different.\",\n    ):\n        _ = pid1 < pid2\n\n\ndef test_package_id_version():\n    \"\"\"Test PackageId.version\"\"\"\n    package_id = PackageId(PackageType.PROTOCOL, PublicId(\"author\", \"name\", \"0.1.0\"))\n    assert package_id.version == \"0.1.0\"\n\n\ndef test_package_id_str():\n    \"\"\"Test PackageId.__str__\"\"\"\n    package_id = PackageId(PackageType.PROTOCOL, PublicId(\"author\", \"name\", \"0.1.0\"))\n    assert str(package_id) == \"(protocol, author/name:0.1.0)\"\n\n\ndef test_package_id_repr():\n    \"\"\"Test PackageId.__repr__\"\"\"\n    package_id = PackageId(PackageType.PROTOCOL, PublicId(\"author\", \"name\", \"0.1.0\"))\n    assert repr(package_id) == \"PackageId(protocol, author/name:0.1.0)\"\n\n\ndef test_package_id_lt():\n    \"\"\"Test PackageId.__lt__\"\"\"\n    package_id_1 = PackageId(PackageType.PROTOCOL, PublicId(\"author\", \"name\", \"0.1.0\"))\n    package_id_2 = PackageId(PackageType.PROTOCOL, PublicId(\"author\", \"name\", \"0.2.0\"))\n\n    assert package_id_1 < package_id_2\n\n\ndef test_package_id_from_uri_path():\n    \"\"\"Test PackageId.from_uri_path\"\"\"\n    result = PackageId.from_uri_path(\"skill/author/package_name/0.1.0\")\n    assert str(result.package_type) == \"skill\"\n    assert result.public_id.name == \"package_name\"\n    assert result.public_id.author == \"author\"\n    assert result.public_id.version == \"0.1.0\"\n\n\ndef test_package_id_to_uri_path():\n    \"\"\"Test PackageId.to_uri_path\"\"\"\n    package_id = PackageId(PackageType.PROTOCOL, PublicId(\"author\", \"name\", \"0.1.0\"))\n    assert package_id.to_uri_path == \"protocol/author/name/0.1.0\"\n\n\ndef test_package_id_from_uri_path_negative():\n    \"\"\"Test PackageId.from_uri_path with invalid type\"\"\"\n    with pytest.raises(\n        ValueError,\n        match=\"Input 'not_a_valid_type/author/package_name/0.1.0' is not well formatted.\",\n    ):\n        PackageId.from_uri_path(\"not_a_valid_type/author/package_name/0.1.0\")\n\n\ndef test_component_id_prefix_import_path():\n    \"\"\"Test ComponentId.prefix_import_path\"\"\"\n    component_id = ComponentId(\n        ComponentType.PROTOCOL, PublicId(\"author\", \"name\", \"0.1.0\")\n    )\n    assert component_id.prefix_import_path == \"packages.author.protocols.name\"\n    assert component_id.json\n\n\ndef test_component_id_same_prefix():\n    \"\"\"Test ComponentId.same_prefix\"\"\"\n    component_id_1 = ComponentId(\n        ComponentType.PROTOCOL, PublicId(\"author\", \"name\", \"0.1.0\")\n    )\n    component_id_2 = ComponentId(\n        ComponentType.PROTOCOL, PublicId(\"author\", \"name\", \"0.2.0\")\n    )\n    assert component_id_1.same_prefix(component_id_2)\n\n\ndef test_component_configuration_load_file_not_found():\n    \"\"\"Test Component.load when a file is not found.\"\"\"\n    with mock.patch(\n        \"aea.configurations.loader.open_file\", side_effect=FileNotFoundError\n    ):\n        with pytest.raises(FileNotFoundError):\n            load_component_configuration(\n                ComponentType.PROTOCOL, mock.MagicMock(spec=Path)\n            )\n\n\ndef test_component_configuration_check_fingerprint_bad_directory():\n    \"\"\"Test ComponentConfiguration.check_fingerprint when a bad directory is provided.\"\"\"\n    config = ProtocolConfig(\n        \"name\", \"author\", \"0.1.0\", protocol_specification_id=\"some/author:0.1.0\"\n    )\n    with pytest.raises(ValueError, match=\"Directory .* is not valid.\"):\n        config.check_fingerprint(Path(\"non_existing_directory\"))\n\n\ndef test_component_configuration_check_fingerprint_different_fingerprints_vendor():\n    \"\"\"Test ComponentConfiguration.check_fingerprint when the fingerprints differ for a vendor package.\"\"\"\n    config = ProtocolConfig(\n        \"name\", \"author\", \"0.1.0\", protocol_specification_id=\"some/author:0.1.0\"\n    )\n    package_dir = Path(\"path\", \"to\", \"dir\")\n    error_regex = (\n        f\"Fingerprints for package {re.escape(str(package_dir))} do not match:\\nExpected: {dict()}\\nActual: {dict(foo='bar')}\\n\"\n        + \"Vendorized projects should not be tampered with, please revert any changes to protocol author/name:0.1.0\"\n    )\n\n    with pytest.raises(ValueError, match=error_regex):\n        with mock.patch(\n            \"aea.configurations.base._compute_fingerprint\", return_value={\"foo\": \"bar\"}\n        ):\n            _compare_fingerprints(config, package_dir, True, PackageType.PROTOCOL)\n\n\ndef test_component_configuration_check_fingerprint_different_fingerprints_no_vendor():\n    \"\"\"Test ComponentConfiguration.check_fingerprint when the fingerprints differ for a non-vendor package.\"\"\"\n    config = ProtocolConfig(\n        \"name\", \"author\", \"0.1.0\", protocol_specification_id=\"some/author:0.1.0\"\n    )\n    package_dir = Path(\"path\", \"to\", \"dir\")\n    error_regex = (\n        f\"Fingerprints for package {re.escape(str(package_dir))} do not match:\\nExpected: {dict()}\\nActual: {dict(foo='bar')}\\n\"\n        + \"Please fingerprint the package before continuing: 'aea fingerprint protocol author/name:0.1.0\"\n    )\n\n    with pytest.raises(ValueError, match=error_regex):\n        with mock.patch(\n            \"aea.configurations.base._compute_fingerprint\", return_value={\"foo\": \"bar\"}\n        ):\n            _compare_fingerprints(config, package_dir, False, PackageType.PROTOCOL)\n\n\ndef test_agent_fingerprint_different_fingerprints():\n    \"\"\"Test ComponentConfiguration.check_fingerprint for agent.\"\"\"\n    config = Mock()\n    config.fingerprint = {}\n    package_dir = Path(\"path\", \"to\", \"dir\")\n    error_regex = (\n        f\"Fingerprints for package {re.escape(str(package_dir))} do not match:\\nExpected: {dict()}\\nActual: {dict(foo='bar')}\\n\"\n        + \"Please fingerprint the package before continuing: 'aea fingerprint\"\n    )\n\n    with pytest.raises(ValueError, match=error_regex):\n        with mock.patch(\n            \"aea.configurations.base._compute_fingerprint\", return_value={\"foo\": \"bar\"}\n        ):\n            _compare_fingerprints(config, package_dir, False, PackageType.AGENT)\n\n\ndef test_check_aea_version_when_it_fails():\n    \"\"\"Test the check for the AEA version when it fails.\"\"\"\n    config = ProtocolConfig(\n        \"name\",\n        \"author\",\n        \"0.1.0\",\n        aea_version=\">0.1.0\",\n        protocol_specification_id=\"some/author:0.1.0\",\n    )\n    with mock.patch(\"aea.configurations.base.__aea_version__\", \"0.1.0\"):\n        with pytest.raises(\n            ValueError,\n            match=\"The CLI version is 0.1.0, but package author/name:0.1.0 requires version >0.1.0\",\n        ):\n            _check_aea_version(config)\n\n\ndef test_connection_config_with_connection_id():\n    \"\"\"Test construction of ConnectionConfig with connection id.\"\"\"\n    ConnectionConfig(connection_id=PublicId(\"name\", \"author\", \"0.1.0\"))\n\n\ndef test_agent_config_package_dependencies():\n    \"\"\"Test agent config package dependencies.\"\"\"\n    agent_config = AgentConfig(\"name\", \"author\")\n    assert agent_config.package_dependencies == set()\n\n    pid = PublicId(\"author\", \"name\", \"0.1.0\")\n    agent_config.protocols.add(pid)\n    agent_config.connections.add(pid)\n    agent_config.contracts.add(pid)\n    agent_config.skills.add(pid)\n\n    assert agent_config.package_dependencies == {\n        PackageId(PackageType.PROTOCOL, pid),\n        PackageId(PackageType.CONNECTION, pid),\n        PackageId(PackageType.CONTRACT, pid),\n        PackageId(PackageType.SKILL, pid),\n    }\n\n\ndef test_agent_config_to_json_with_optional_configurations():\n    \"\"\"Test agent config to json with optional configurations.\"\"\"\n    agent_config = AgentConfig(\n        \"name\",\n        \"author\",\n        period=0.1,\n        execution_timeout=1.0,\n        max_reactions=100,\n        decision_maker_handler=dict(dotted_path=\"\", file_path=\"\"),\n        error_handler=dict(dotted_path=\"\", file_path=\"\"),\n        skill_exception_policy=\"propagate\",\n        connection_exception_policy=\"propagate\",\n        default_routing={\"author/name:0.1.0\": \"author/name:0.1.0\"},\n        currency_denominations={\"fetchai\": \"fet\"},\n        loop_mode=\"sync\",\n        runtime_mode=\"async\",\n        storage_uri=\"some_uri_to_storage\",\n        task_manager_mode=\"threaded\",\n    )\n    agent_config.default_connection = \"author/name:0.1.0\"\n    agent_config.default_ledger = DEFAULT_LEDGER\n    agent_config.json\n    assert agent_config.package_id == PackageId.from_uri_path(\"agent/author/name/0.1.0\")\n\n\ndef test_protocol_specification_attributes():\n    \"\"\"Test protocol specification attributes.\"\"\"\n    protocol_specification = ProtocolSpecification(\n        \"name\", \"author\", \"0.1.0\", protocol_specification_id=\"some/author:0.1.0\"\n    )\n\n    # test getter and setter for 'protobuf_snippets'\n    assert protocol_specification.protobuf_snippets == {}\n    protocol_specification.protobuf_snippets = {\"a\": 1}\n    assert protocol_specification.protobuf_snippets == {\"a\": 1}\n\n    # test getter and setter for 'dialogue_config'\n    assert protocol_specification.dialogue_config == {}\n    protocol_specification.dialogue_config = {\"a\": 1}\n    assert protocol_specification.dialogue_config == {\"a\": 1}\n\n\ndef test_contract_config_component_type():\n    \"\"\"Test ContractConfig.component_type\"\"\"\n    config = ContractConfig(\"name\", \"author\", \"0.1.0\")\n    assert config.component_type == ComponentType.CONTRACT\n\n\ndef test_package_version_eq_negative():\n    \"\"\"Test package version __eq__.\"\"\"\n    v1 = PackageVersion(\"0.1.0\")\n    v2 = PackageVersion(\"0.2.0\")\n    assert v1 != v2\n\n\ndef test_package_version_lt():\n    \"\"\"Test package version __lt__.\"\"\"\n    v1 = PackageVersion(\"0.1.0\")\n    v2 = PackageVersion(\"0.2.0\")\n    v3 = PackageVersion(\"latest\")\n    assert v1 < v2 < v3\n\n\nclass TestDependencyGetPipInstallArgs:\n    \"\"\"Test 'get_pip_install_args' of 'Dependency' class.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set up the class.\"\"\"\n        cls.package_name = \"package_name\"\n        cls.version = \"<0.2.0,>=0.1.0\"\n        cls.custom_index = \"https://test.pypi.org\"\n        cls.git_url = \"https://github.com/some-author/some-repository.git\"\n        cls.ref = \"develop\"\n\n    def test_only_name_and_version(self):\n        \"\"\"Test only with name and version.\"\"\"\n        # no index and no git\n        dep = Dependency(self.package_name, self.version)\n        assert dep.get_pip_install_args() == [\n            f\"{self.package_name}{self.version}\",\n        ]\n\n    def test_name_version_index(self):\n        \"\"\"Test the method with name, version and index.\"\"\"\n        dep = Dependency(self.package_name, self.version, self.custom_index)\n        assert dep.get_pip_install_args() == [\n            \"-i\",\n            self.custom_index,\n            f\"{self.package_name}{self.version}\",\n        ]\n\n    def test_name_version_index_git(self):\n        \"\"\"Test the method when name, version, index and git fields are provided.\"\"\"\n        dep = Dependency(\n            self.package_name, self.version, self.custom_index, self.git_url\n        )\n        git_url = f\"git+{self.git_url}@{DEFAULT_GIT_REF}#egg={self.package_name}\"\n        assert dep.get_pip_install_args() == [\"-i\", self.custom_index, git_url]\n\n    def test_name_version_index_git_ref(self):\n        \"\"\"Test the method when name, version, index, git and ref fields are provided.\"\"\"\n        dep = Dependency(\n            self.package_name, self.version, self.custom_index, self.git_url, self.ref\n        )\n        git_url = f\"git+{self.git_url}@{self.ref}#egg={self.package_name}\"\n        assert dep.get_pip_install_args() == [\"-i\", self.custom_index, git_url]\n\n\ndef test_dependencies_from_to_json():\n    \"\"\"Test serialization and deserialization of Dependencies object.\"\"\"\n    version_str = \"==0.1.0\"\n    git_url = \"https://some-git-repo.git\"\n    branch = \"some-branch\"\n    dep1 = Dependency(\"package_1\", version_str, DEFAULT_PYPI_INDEX_URL, git_url, branch)\n    dep2 = Dependency(\"package_2\", version_str)\n    expected_obj = {\"package_1\": dep1, \"package_2\": dep2}\n    expected_obj_json = dependencies_to_json(expected_obj)\n    assert expected_obj_json == {\n        \"package_1\": {\n            \"version\": \"==0.1.0\",\n            \"index\": DEFAULT_PYPI_INDEX_URL,\n            \"git\": git_url,\n            \"ref\": branch,\n        },\n        \"package_2\": {\"version\": version_str},\n    }\n\n    actual_obj = dependencies_from_json(expected_obj_json)\n    assert expected_obj == actual_obj\n\n\ndef test_dependency_from_json_fail_more_than_one_key():\n    \"\"\"Test failure of Dependency.from_json due to more than one key at the top level.\"\"\"\n    bad_obj = {\"field_1\": {}, \"field_2\": {}}\n    keys = set(bad_obj.keys())\n    with pytest.raises(ValueError, match=f\"Only one key allowed, found {keys}\"):\n        Dependency.from_json(bad_obj)\n\n\ndef test_dependency_from_json_fail_not_allowed_keys():\n    \"\"\"Test failure of Dependency.from_json due to unallowed keys\"\"\"\n    bad_obj = {\"field_1\": {\"not-allowed-key\": \"value\"}}\n    with pytest.raises(ValueError, match=\"Not allowed keys: {'not-allowed-key'}\"):\n        Dependency.from_json(bad_obj)\n\n\ndef test_dependency_to_string():\n    \"\"\"Test dependency.__str__ method.\"\"\"\n    dependency = Dependency(\n        \"package_1\", \"==0.1.0\", \"https://index.com\", \"https://some-repo.git\", \"branch\"\n    )\n    assert (\n        str(dependency)\n        == \"Dependency(name='package_1', version='==0.1.0', index='https://index.com', git='https://some-repo.git', ref='branch')\"\n    )\n\n\ndef test_check_public_id_consistency_negative():\n    \"\"\"Test ComponentId.check_public_id_consistency raises error when directory does not exists.\"\"\"\n    random_dir_name = random_string()\n    with pytest.raises(ValueError, match=f\"Directory {random_dir_name} is not valid.\"):\n        component_configuration = ProtocolConfig(\n            \"name\", \"author\", protocol_specification_id=\"some/author:0.1.0\"\n        )\n        component_configuration.check_public_id_consistency(Path(random_dir_name))\n\n\ndef test_check_public_id_consistency_positive():\n    \"\"\"Test ComponentId.check_public_id_consistency works.\"\"\"\n    skill_config_path = Path(DUMMY_SKILL_PATH)\n    loader = ConfigLoaders.from_package_type(PackageType.SKILL)\n    skill_config = loader.load(skill_config_path.open())\n    skill_config.check_public_id_consistency(Path(skill_config_path).parent)\n\n\ndef test_component_id_from_json():\n    \"\"\"Test ComponentId.from_json.\"\"\"\n    json_data = {\n        \"type\": \"connection\",\n        \"author\": \"author\",\n        \"name\": \"name\",\n        \"version\": \"1.0.0\",\n    }\n    assert ComponentId.from_json(json_data).json == json_data\n"
  },
  {
    "path": "tests/test_aea/test_configurations/test_loader.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\n\"\"\"This module contains the tests for the aea.configurations.loader module.\"\"\"\nimport os\nfrom io import StringIO\nfrom pathlib import Path\nfrom unittest import mock\nfrom unittest.mock import MagicMock\n\nimport pytest\nimport yaml\n\nimport aea\nfrom aea.configurations.base import PackageType, ProtocolSpecification\nfrom aea.configurations.loader import ConfigLoader\nfrom aea.configurations.validation import make_jsonschema_base_uri\nfrom aea.exceptions import AEAEnforceError\nfrom aea.protocols.generator.common import load_protocol_specification\n\nfrom tests.conftest import protocol_specification_files\n\n\ndef test_windows_uri_path():\n    \"\"\"Test uri path on running platform.\"\"\"\n    path = Path(\"aea\", \"configurations\").absolute()\n    output = make_jsonschema_base_uri(path)\n\n    if os.name == \"nt\":\n        assert output == f\"file:///{'/'.join(path.parts)}/\"\n    else:\n        assert output == f\"file:/{'/'.join(path.parts)}/\"\n\n\ndef test_config_loader_get_required_fields():\n    \"\"\"Test required fields of ConfigLoader.\"\"\"\n    config_loader = ConfigLoader.from_configuration_type(PackageType.PROTOCOL)\n    config_loader.required_fields\n\n\n@mock.patch.object(aea.configurations.loader, \"yaml_dump\")\n@mock.patch.object(ConfigLoader, \"validate\")\n@mock.patch(\"builtins.open\")\ndef test_config_loader_dump_component(*_mocks):\n    \"\"\"Test ConfigLoader.dump\"\"\"\n    config_loader = ConfigLoader.from_configuration_type(PackageType.PROTOCOL)\n    configuration = MagicMock()\n    config_loader.dump(configuration, open(\"foo\"))\n\n\n@mock.patch.object(aea.configurations.loader, \"yaml_dump_all\")\n@mock.patch.object(ConfigLoader, \"validate\")\n@mock.patch(\"builtins.open\")\ndef test_config_loader_dump_agent_config(*_mocks):\n    \"\"\"Test ConfigLoader.dump\"\"\"\n    config_loader = ConfigLoader.from_configuration_type(PackageType.AGENT)\n    configuration = MagicMock(ordered_json={\"component_configurations\": []})\n    config_loader.dump(configuration, open(\"foo\"))\n\n\n@pytest.mark.parametrize(\"spec_file_path\", protocol_specification_files)\ndef test_load_protocol_specification(spec_file_path):\n    \"\"\"Test for the utility function 'load_protocol_specification'\"\"\"\n    result = load_protocol_specification(spec_file_path)\n    assert type(result) == ProtocolSpecification\n\n\n@mock.patch(\"aea.protocols.generator.common.open_file\")\n@mock.patch.object(ConfigLoader, \"validate\")\ndef test_load_protocol_specification_only_first_part(*_mocks):\n    \"\"\"Test 'load_protocol_specification' with only the first part.\"\"\"\n    valid_protocol_specification = dict(\n        name=\"name\",\n        author=\"author\",\n        version=\"0.1.0\",\n        license=\"\",\n        aea_version=\"0.1.0\",\n        speech_acts={\"example\": {}},\n        protocol_specification_id=\"test/test:0.1.0\",\n        description=\"some\",\n    )\n    with mock.patch.object(\n        yaml, \"safe_load_all\", return_value=[valid_protocol_specification]\n    ):\n        load_protocol_specification(\"foo\")\n\n\n@mock.patch(\"aea.protocols.generator.common.open_file\")\n@mock.patch.object(ConfigLoader, \"validate\")\ndef test_load_protocol_specification_two_parts(*_mocks):\n    \"\"\"Test 'load_protocol_specification' with two parts.\"\"\"\n    valid_protocol_specification = dict(\n        name=\"name\",\n        author=\"author\",\n        version=\"0.1.0\",\n        license=\"\",\n        aea_version=\"0.1.0\",\n        speech_acts={\"example\": {}},\n        protocol_specification_id=\"test/test:0.1.0\",\n        description=\"some\",\n    )\n    with mock.patch.object(\n        yaml,\n        \"safe_load_all\",\n        return_value=[valid_protocol_specification, valid_protocol_specification],\n    ):\n        load_protocol_specification(\"foo\")\n\n\ndef test_load_protocol_specification_too_many_parts():\n    \"\"\"Test 'load_protocol_specification' with more than three parts.\"\"\"\n    with pytest.raises(\n        ValueError,\n        match=\"Incorrect number of Yaml documents in the protocol specification.\",\n    ):\n        with mock.patch.object(\n            yaml, \"safe_load_all\", return_value=[{}] * 4\n        ), mock.patch(\"aea.protocols.generator.common.open_file\"):\n            load_protocol_specification(\"foo\")\n\n\n@mock.patch.object(aea, \"__version__\", \"0.1.0\")\ndef test_load_package_configuration_with_incompatible_aea_version(*_mocks):\n    \"\"\"Test that loading a package configuration with incompatible AEA version raises an error.\"\"\"\n    config_loader = ConfigLoader.from_configuration_type(\n        PackageType.PROTOCOL, skip_aea_validation=False\n    )\n    specifier_set = \"<2.0.0,>=1.0.0\"\n    file = StringIO(f\"name: some_protocol\\naea_version: '{specifier_set}'\")\n    with pytest.raises(\n        AEAEnforceError,\n        match=f\"AEA version in use '0.1.0' is not compatible with the specifier set '{specifier_set}'.\",\n    ):\n        config_loader.load(file)\n"
  },
  {
    "path": "tests/test_aea/test_configurations/test_manager.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This test module contains the tests for the configurations manager module.\"\"\"\nimport os\nfrom copy import deepcopy\nfrom pathlib import Path\nfrom unittest.mock import mock_open, patch\n\nimport pytest\nimport yaml\n\nfrom aea.configurations.constants import CONNECTION\nfrom aea.configurations.data_types import ComponentId, PublicId\nfrom aea.configurations.manager import (\n    AgentConfigManager,\n    find_component_directory_from_component_id,\n    handle_dotted_path,\n)\nfrom aea.configurations.validation import SAME_MARK\nfrom aea.exceptions import AEAException\n\nfrom tests.conftest import ROOT_DIR\n\n\nDUMMY_AEA = Path(ROOT_DIR) / \"tests\" / \"data\" / \"dummy_aea\"\n\nagent_config_data = yaml.safe_load(\n    \"\"\"\nagent_name: Agent0\nauthor: dummy_author\nversion: 1.0.0\ndescription: dummy_aea agent description\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint: {}\nfingerprint_ignore_patterns: []\nconnections:\n- fetchai/local:0.21.6\ncontracts: []\nprotocols:\n- fetchai/default:1.1.7\nskills:\n- dummy_author/dummy:0.1.0\n- fetchai/error:0.18.6\ndefault_connection: fetchai/local:0.21.6\ndefault_ledger: cosmos\nlogging_config:\n  disable_existing_loggers: ${DISABLE_LOGS:bool}\n  version: 1\nprivate_key_paths:\n  cosmos: cosmos_private_key.txt\n  ethereum: ethereum_private_key.txt\nconnection_private_key_paths:\n  cosmos: cosmos_private_key.txt\n  ethereum: ethereum_private_key.txt\ndefault_routing: {}\n\"\"\"\n)\n\n\ndef test_envvars_applied():\n    \"\"\"Test env vars replaced with values.\"\"\"\n    dct = deepcopy(agent_config_data)\n    with patch.object(AgentConfigManager, \"_load_config_data\", return_value=[dct]):\n        os.environ[\"DISABLE_LOGS\"] = \"true\"\n        agent_config_manager = AgentConfigManager.load(\".\", substitude_env_vars=True)\n    assert (\n        agent_config_manager.json[\"logging_config\"][\"disable_existing_loggers\"] is True\n    )\n\n    with patch.object(AgentConfigManager, \"_load_config_data\", return_value=[dct]):\n        os.environ[\"DISABLE_LOGS\"] = \"false\"\n        agent_config_manager = AgentConfigManager.load(\".\", substitude_env_vars=True)\n    assert (\n        agent_config_manager.json[\"logging_config\"][\"disable_existing_loggers\"] is False\n    )\n\n    # no env! no default value\n    os.environ.pop(\"DISABLE_LOGS\")\n    with pytest.raises(\n        ValueError,\n        match=\"`DISABLE_LOGS` not found in env variables and no default value set!\",\n    ):\n        with patch.object(AgentConfigManager, \"_load_config_data\", return_value=[dct]):\n            agent_config_manager = AgentConfigManager.load(\n                \".\", substitude_env_vars=True\n            )\n        assert (\n            agent_config_manager.json[\"logging_config\"][\"disable_existing_loggers\"]\n            is False\n        )\n\n    # check default value specified\n    dct[\"logging_config\"][\"disable_existing_loggers\"] = \"${DISABLE_LOGS:bool:true}\"\n    with patch.object(AgentConfigManager, \"_load_config_data\", return_value=[dct]):\n        agent_config_manager = AgentConfigManager.load(\".\", substitude_env_vars=True)\n        assert (\n            agent_config_manager.json[\"logging_config\"][\"disable_existing_loggers\"]\n            is True\n        )\n\n    # check incorrect data type\n    dct[\"logging_config\"][\"disable_existing_loggers\"] = \"${DISABLE_LOGS:int:true}\"\n    with pytest.raises(ValueError, match=\"Cannot convert string `true` to type `int`\"):\n        with patch.object(AgentConfigManager, \"_load_config_data\", return_value=[dct]):\n            agent_config_manager = AgentConfigManager.load(\n                \".\", substitude_env_vars=True\n            )\n            assert (\n                agent_config_manager.json[\"logging_config\"][\"disable_existing_loggers\"]\n                is True\n            )\n\n    # not applied\n    dct = deepcopy(agent_config_data)\n    with patch.object(AgentConfigManager, \"_load_config_data\", return_value=[dct]):\n        os.environ[\"DISABLE_LOGS\"] = \"true\"\n        agent_config_manager = AgentConfigManager.load(\".\", substitude_env_vars=False)\n    assert (\n        agent_config_manager.json[\"logging_config\"][\"disable_existing_loggers\"]\n        == dct[\"logging_config\"][\"disable_existing_loggers\"]\n    )\n\n\n@patch.object(AgentConfigManager, \"get_overridables\", return_value=[{}, {}])\ndef test_envvars_preserved(*mocks):\n    \"\"\"Test env vars not modified on config update.\"\"\"\n    dct = deepcopy(agent_config_data)\n    new_cosmos_key_value = \"cosmons_key_updated\"\n\n    with patch.object(AgentConfigManager, \"_load_config_data\", return_value=[dct]):\n        os.environ[\"DISABLE_LOGS\"] = \"true\"\n        agent_config_manager = AgentConfigManager.load(\".\", substitude_env_vars=False)\n\n    assert (\n        agent_config_manager.json[\"logging_config\"][\"disable_existing_loggers\"]\n        == dct[\"logging_config\"][\"disable_existing_loggers\"]\n    )\n\n    with patch.object(AgentConfigManager, \"_load_config_data\", return_value=[dct]):\n        os.environ[\"DISABLE_LOGS\"] = \"true\"\n        agent_config_manager = AgentConfigManager.load(\".\", substitude_env_vars=False)\n\n    assert (\n        agent_config_manager.json[\"private_key_paths\"][\"cosmos\"] != new_cosmos_key_value\n    )\n    agent_config_manager.update_config(\n        {\"private_key_paths\": {\"cosmos\": new_cosmos_key_value}}\n    )\n\n    assert (\n        agent_config_manager.json[\"logging_config\"][\"disable_existing_loggers\"]\n        == dct[\"logging_config\"][\"disable_existing_loggers\"]\n    )\n    assert (\n        agent_config_manager.json[\"private_key_paths\"][\"cosmos\"] == new_cosmos_key_value\n    )\n\n\ndef test_agent_attribute_get_set():\n    \"\"\"Test agent config manager  get set variables.\"\"\"\n    dct = deepcopy(agent_config_data)\n    with patch.object(AgentConfigManager, \"_load_config_data\", return_value=[dct]):\n        os.environ[\"DISABLE_LOGS\"] = \"true\"\n        agent_config_manager = AgentConfigManager.load(\n            DUMMY_AEA, substitude_env_vars=False\n        )\n        assert (\n            agent_config_manager.get_variable(\"agent.default_ledger\")\n            == dct[\"default_ledger\"]\n        )\n        assert (\n            agent_config_manager.get_variable(\"vendor.fetchai.skills.error.name\")\n            == \"error\"\n        )\n\n        assert (\n            agent_config_manager.get_variable(\n                \"vendor.fetchai.connections.local.is_abstract\"\n            )\n            is False\n        )\n        agent_config_manager.set_variable(\n            \"vendor.fetchai.connections.local.is_abstract\", True\n        )\n        assert (\n            agent_config_manager.get_variable(\n                \"vendor.fetchai.connections.local.is_abstract\"\n            )\n            is True\n        )\n\n        agent_config_manager.set_variable(\"agent.default_ledger\", \"fetchai\")\n        assert agent_config_manager.get_variable(\"agent.default_ledger\") == \"fetchai\"\n\n        assert (\n            agent_config_manager.json[\"component_configurations\"][0][\"is_abstract\"]\n            is True\n        )\n\n    agent_config_manager = AgentConfigManager.load(DUMMY_AEA, substitude_env_vars=False)\n    agent_config_manager.set_variable(\n        \"vendor.fetchai.connections.p2p_libp2p.config.delegate_uri\", \"some_url\"\n    )\n    assert (\n        agent_config_manager.get_variable(\n            \"vendor.fetchai.connections.p2p_libp2p.config.delegate_uri\"\n        )\n        == \"some_url\"\n    )\n\n    with pytest.raises(\n        ValueError, match=\"Attribute `does_not_exist` for AgentConfig does not exist\"\n    ):\n        agent_config_manager.get_variable(\"agent.does_not_exist\")\n\n    agent_config_manager.validate_current_config()\n    agent_config_manager.verify_private_keys(DUMMY_AEA, lambda x, y, z: None)\n\n\ndef test_agent_attribute_get_overridables():\n    \"\"\"Test AgentConfigManager.get_overridables.\"\"\"\n    agent_config_manager = AgentConfigManager.load(DUMMY_AEA, substitude_env_vars=False)\n    agent_overrides, component_overrides = agent_config_manager.get_overridables()\n    assert \"default_ledger\" in agent_overrides\n    assert \"is_abstract\" in list(component_overrides.values())[0]\n\n\ndef test_dump_config():\n    \"\"\"Test AgentConfigManager.dump_config.\"\"\"\n    agent_config_manager = AgentConfigManager.load(DUMMY_AEA, substitude_env_vars=False)\n    with patch(\"aea.configurations.manager.open_file\", mock_open()), patch(\n        \"aea.configurations.loader.ConfigLoader.dump\"\n    ) as dump_mock:\n        agent_config_manager.dump_config()\n\n    dump_mock.assert_called_once()\n\n\ndef test_handle_dotted_path():\n    \"\"\"Test handle_dotted_path.\"\"\"\n    with pytest.raises(\n        AEAException, match=r\"The root of the dotted path must be one of:\"\n    ):\n        handle_dotted_path(\"something\", author=\"fetchai\")\n\n    with pytest.raises(\n        AEAException,\n        match=r\"The path is too short. Please specify a path up to an attribute name.\",\n    ):\n        handle_dotted_path(\"skills\", author=\"fetchai\")\n\n    with pytest.raises(\n        AEAException, match=r\"is not a valid component type. Please use one of\"\n    ):\n        handle_dotted_path(\"vendor.fetchai.notskills.dummy.name\", author=\"fetchai\")\n\n    with pytest.raises(AEAException, match=r\"Resource .* does not exist.\"):\n        handle_dotted_path(\"skills.notdummy.name\", author=\"fetchai\")\n\n\ndef test_find_component_directory_from_component_id():\n    \"\"\"Test find_component_directory_from_component_id.\"\"\"\n    with pytest.raises(ValueError, match=r\"Package .* not found.\"):\n        find_component_directory_from_component_id(\n            Path(\".\"),\n            ComponentId(\n                component_type=CONNECTION, public_id=PublicId(\"test\", \"test\", \"1.0.1\")\n            ),\n        )\n\n\ndef test_agent_attribute_get_and_apply_overridables():\n    \"\"\"Test AgentConfigManager.get_overridables and apply it.\"\"\"\n    agent_config_manager = AgentConfigManager.load(DUMMY_AEA, substitude_env_vars=False)\n    initial_agent_config_json = agent_config_manager.json\n\n    agent_overrides, component_overrides = agent_config_manager.get_overridables()\n\n    agent_config_manager.update_config(agent_overrides)\n    assert initial_agent_config_json == agent_config_manager.json\n\n    agent_overrides[\"component_configurations\"] = component_overrides\n    agent_config_manager.update_config(agent_overrides)\n\n    assert agent_config_manager._filter_overrides(agent_overrides) == SAME_MARK\n\n    agent_overrides[\"execution_timeout\"] = 12\n    assert agent_config_manager._filter_overrides(agent_overrides) == {\n        \"execution_timeout\": 12\n    }\n"
  },
  {
    "path": "tests/test_aea/test_configurations/test_pypi.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains tests for the aea.helpers.pypi module.\"\"\"\nimport pytest\nfrom packaging.specifiers import SpecifierSet\n\nfrom aea.configurations.base import Dependency\nfrom aea.configurations.pypi import (\n    is_satisfiable,\n    is_simple_dep,\n    merge_dependencies,\n    merge_dependencies_list,\n    to_set_specifier,\n)\n\n\ndef test_is_satisfiable_common_cases():\n    \"\"\"Test the 'is_satisfiable' function with common cases.\"\"\"\n    assert is_satisfiable(SpecifierSet(\"<=1.0,>1.1, >0.9\")) is False\n    assert is_satisfiable(SpecifierSet(\"==1.0,!=1.0\")) is False\n    assert is_satisfiable(SpecifierSet(\"!=0.9,!=1.0\")) is True\n    assert is_satisfiable(SpecifierSet(\"<=1.0,>=1.0\")) is True\n    assert is_satisfiable(SpecifierSet(\"<=1.0,>1.0\")) is False\n    assert is_satisfiable(SpecifierSet(\"<1.0,<=1.0,>1.0\")) is False\n    assert is_satisfiable(SpecifierSet(\">1.0,>=1.0,<1.0\")) is False\n\n\ndef test_is_satisfiable_with_compatibility_constraints():\n    \"\"\"Test the 'is_satisfiable' function with ~= constraints.\"\"\"\n    assert is_satisfiable(SpecifierSet(\"~=1.1,==2.0\")) is False\n    assert is_satisfiable(SpecifierSet(\"~=1.1,==1.0\")) is False\n    assert is_satisfiable(SpecifierSet(\"~=1.1,<=1.1\")) is True\n    assert is_satisfiable(SpecifierSet(\"~=1.1,<1.1\")) is False\n    assert is_satisfiable(SpecifierSet(\"~=1.0,<1.0\")) is False\n    assert is_satisfiable(SpecifierSet(\"~=1.1,==1.2\")) is True\n    assert is_satisfiable(SpecifierSet(\"~=1.1,>1.2\")) is True\n    assert is_satisfiable(SpecifierSet(\"==1.1,==1.2\")) is False\n    assert is_satisfiable(SpecifierSet(\"~= 1.4.5.0\")) is True\n    assert is_satisfiable(SpecifierSet(\"~= 1.4.5.0,>1.4.6\")) is False\n    assert is_satisfiable(SpecifierSet(\"~=2.2.post3,==2.*\")) is True\n    assert is_satisfiable(SpecifierSet(\"~=2.2.post3,>2.3\")) is True\n    assert is_satisfiable(SpecifierSet(\"~=2.2.post3,>3\")) is False\n    assert is_satisfiable(SpecifierSet(\"~=1.4.5a4,>1.4.6\")) is True\n    assert is_satisfiable(SpecifierSet(\"~=1.4.5a4,>1.5\")) is False\n\n\ndef test_is_satisfiable_with_legacy_version():\n    \"\"\"Test the 'is_satisfiable' function with legacy versions.\"\"\"\n    assert is_satisfiable(SpecifierSet(\"==1.0,==1.*\")) is True\n\n\ndef test_merge_dependencies():\n    \"\"\"Test the 'merge_dependencies' function.\"\"\"\n    dependencies_a = {\n        \"package_1\": Dependency(\"package_1\", \"==0.1.0\"),\n        \"package_2\": Dependency(\"package_2\", \"==0.3.0\"),\n        \"package_3\": Dependency(\"package_3\", \"==0.2.0\", \"https://pypi.org\"),\n    }\n    dependencies_b = {\n        \"package_1\": Dependency(\"package_1\", \"==0.1.0\"),\n        \"package_2\": Dependency(\"package_2\", \"==0.2.0\"),\n        \"package_4\": Dependency(\"package_4\", \"==0.1.0\", \"https://pypi.org\"),\n    }\n    expected_merged_dependencies = {\n        \"package_1\": Dependency(\"package_1\", \"==0.1.0\"),\n        \"package_2\": Dependency(\"package_2\", \"==0.2.0,==0.3.0\"),\n        \"package_3\": Dependency(\"package_3\", \"==0.2.0\", \"https://pypi.org\"),\n        \"package_4\": Dependency(\"package_4\", \"==0.1.0\", \"https://pypi.org\"),\n    }\n    assert expected_merged_dependencies == merge_dependencies(\n        dependencies_a, dependencies_b\n    )\n    assert expected_merged_dependencies == merge_dependencies_list(\n        dependencies_a, dependencies_b\n    )\n\n\ndef test_merge_dependencies_fails_not_simple():\n    \"\"\"Test we can't merge dependencies if at least one of the overlapping dependency is not 'simple'.\"\"\"\n    dependencies_a = {\n        \"package_1\": Dependency(\"package_1\", \"==0.1.0\", index=\"https://pypi.org\"),\n    }\n    dependencies_b = {\n        \"package_1\": Dependency(\"package_1\", \"==0.1.0\", index=\"https://test.pypi.org\"),\n    }\n\n    with pytest.raises(\n        ValueError, match=\"cannot trivially merge these two PyPI dependencies:.*\"\n    ):\n        merge_dependencies(dependencies_a, dependencies_b)\n\n\ndef test_merge_dependencies_succeeds_not_simple_but_the_same():\n    \"\"\"Test we can't merge dependencies if conflicting deps are not 'simple' but equal.\"\"\"\n    dependencies_a = {\n        \"package_1\": Dependency(\"package_1\", \"==0.1.0\", index=\"https://pypi.org\"),\n    }\n    dependencies_b = {\n        \"package_1\": Dependency(\"package_1\", \"==0.1.0\", index=\"https://pypi.org\"),\n    }\n\n    expected_merged_dependencies = merge_dependencies(dependencies_a, dependencies_b)\n    assert dependencies_a == dependencies_b == expected_merged_dependencies\n\n\ndef test_is_simple_dep():\n    \"\"\"Test the `is_simple_dep` function.\"\"\"\n    dependency_a = Dependency(\"name\", \"==0.1.0\")\n    assert is_simple_dep(dependency_a), \"Should be a simple dependency.\"\n    dependency_b = Dependency(\"name\")\n    assert is_simple_dep(dependency_b), \"Should be a simple dependency.\"\n    dependency_c = Dependency(\"name\", \"==0.1.0\", \"pypi\")\n    assert not is_simple_dep(dependency_c), \"Should not be a simple dependency.\"\n\n\ndef test_to_set_specifier():\n    \"\"\"Test the 'to_set_specifier' function.\"\"\"\n    dependency_a = Dependency(\"name\", \"==0.1.0\")\n    assert to_set_specifier(dependency_a) == SpecifierSet(\"==0.1.0\")\n"
  },
  {
    "path": "tests/test_aea/test_configurations/test_schema.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This test module contains the tests for the JSON schemas of the configuration files.\"\"\"\nimport itertools\nimport json\nimport os\nfrom itertools import zip_longest\nfrom pathlib import Path\n\nimport jsonschema\nimport pytest\nimport yaml\nfrom jsonschema import Draft4Validator  # type: ignore\n\nfrom aea.configurations.validation import make_jsonschema_base_uri\n\nfrom tests.conftest import (\n    AGENT_CONFIGURATION_SCHEMA,\n    CONFIGURATION_SCHEMA_DIR,\n    CONNECTION_CONFIGURATION_SCHEMA,\n    CONTRACT_CONFIGURATION_SCHEMA,\n    PROTOCOL_CONFIGURATION_SCHEMA,\n    PROTOCOL_SPEC_CONFIGURATION_SCHEMA,\n    ROOT_DIR,\n    SKILL_CONFIGURATION_SCHEMA,\n    agent_config_files,\n    connection_config_files,\n    contract_config_files,\n    protocol_config_files,\n    protocol_specification_files,\n    skill_config_files,\n)\n\n\ndef test_agent_configuration_schema_is_valid_wrt_draft_04():\n    \"\"\"Test that the JSON schema for the agent configuration file is compliant with the specification Draft 04.\"\"\"\n    agent_config_schema = json.load(\n        open(\n            os.path.join(\n                ROOT_DIR, \"aea\", \"configurations\", \"schemas\", \"aea-config_schema.json\"\n            )\n        )\n    )\n    Draft4Validator.check_schema(agent_config_schema)\n\n\ndef test_skill_configuration_schema_is_valid_wrt_draft_04():\n    \"\"\"Test that the JSON schema for the skill configuration file is compliant with the specification Draft 04.\"\"\"\n    skill_config_schema = json.load(\n        open(\n            os.path.join(\n                ROOT_DIR, \"aea\", \"configurations\", \"schemas\", \"skill-config_schema.json\"\n            )\n        )\n    )\n    Draft4Validator.check_schema(skill_config_schema)\n\n\ndef test_connection_configuration_schema_is_valid_wrt_draft_04():\n    \"\"\"Test that the JSON schema for the connection configuration file is compliant with the specification Draft 04.\"\"\"\n    connection_config_schema = json.load(\n        open(\n            os.path.join(\n                ROOT_DIR,\n                \"aea\",\n                \"configurations\",\n                \"schemas\",\n                \"connection-config_schema.json\",\n            )\n        )\n    )\n    Draft4Validator.check_schema(connection_config_schema)\n\n\ndef test_protocol_configuration_schema_is_valid_wrt_draft_04():\n    \"\"\"Test that the JSON schema for the protocol configuration file is compliant with the specification Draft 04.\"\"\"\n    protocol_config_schema = json.load(\n        open(\n            os.path.join(\n                ROOT_DIR,\n                \"aea\",\n                \"configurations\",\n                \"schemas\",\n                \"protocol-config_schema.json\",\n            )\n        )\n    )\n    Draft4Validator.check_schema(protocol_config_schema)\n\n\ndef test_definitions_schema_is_valid_wrt_draft_04():\n    \"\"\"Test that the JSON schema for the definitions is compliant with the specification Draft 04.\"\"\"\n    definitions_config_schema = json.load(\n        open(\n            os.path.join(\n                ROOT_DIR, \"aea\", \"configurations\", \"schemas\", \"definitions.json\"\n            )\n        )\n    )\n    Draft4Validator.check_schema(definitions_config_schema)\n\n\n@pytest.mark.parametrize(\n    \"schema_file_path, config_file_path\",\n    itertools.chain.from_iterable(\n        [\n            zip_longest([], files, fillvalue=schema)\n            for files, schema in [\n                (agent_config_files, AGENT_CONFIGURATION_SCHEMA),\n                (protocol_config_files, PROTOCOL_CONFIGURATION_SCHEMA),\n                (contract_config_files, CONTRACT_CONFIGURATION_SCHEMA),\n                (connection_config_files, CONNECTION_CONFIGURATION_SCHEMA),\n                (skill_config_files, SKILL_CONFIGURATION_SCHEMA),\n                (protocol_specification_files, PROTOCOL_SPEC_CONFIGURATION_SCHEMA),\n            ]\n        ]\n    ),\n)\ndef test_config_validation(schema_file_path, config_file_path):\n    \"\"\"Test configuration validation.\"\"\"\n    # TODO a bit inefficient to load each schema everytime; consider making the validators as fixtures.\n    schema = json.load(open(schema_file_path))\n    resolver = jsonschema.RefResolver(\n        make_jsonschema_base_uri(Path(CONFIGURATION_SCHEMA_DIR).absolute()),\n        schema,\n    )\n    validator = Draft4Validator(schema, resolver=resolver)\n    config_data = list(yaml.safe_load_all(open(config_file_path)))\n    validator.validate(instance=config_data[0])\n"
  },
  {
    "path": "tests/test_aea/test_configurations/test_utils.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This test module contains the tests configuration utils.\"\"\"\nfrom unittest.mock import MagicMock\n\nfrom aea.configurations.base import (\n    AgentConfig,\n    ComponentId,\n    ComponentType,\n    ConnectionConfig,\n    PublicId,\n    SkillConfig,\n)\nfrom aea.configurations.utils import (\n    get_latest_component_id_from_prefix,\n    replace_component_ids,\n)\n\n\ndef test_get_latest_component_id_from_prefix():\n    \"\"\"Test the utility to get the latest concrete version id.\"\"\"\n    agent_config = MagicMock()\n    expected_component_id = ComponentId(\n        ComponentType.PROTOCOL, PublicId(\"author\", \"name\", \"0.1.0\")\n    )\n    agent_config.package_dependencies = {expected_component_id}\n\n    result = get_latest_component_id_from_prefix(\n        agent_config, expected_component_id.component_prefix\n    )\n    assert result == expected_component_id\n\n\ndef test_get_latest_component_id_from_prefix_negative():\n    \"\"\"Test the utility to get the latest concrete version id, negative case.\"\"\"\n    agent_config = MagicMock()\n    agent_config.package_dependencies = {}\n\n    result = get_latest_component_id_from_prefix(\n        agent_config, (ComponentType.PROTOCOL, \"author\", \"name\")\n    )\n    assert result is None\n\n\nclass BaseTestReplaceComponentIds:\n    \"\"\"Base test class for 'replace_component_ids' utility function.\"\"\"\n\n    old_protocol_id = PublicId(\"author\", \"old_protocol\", \"0.1.0\")\n    old_contract_id = PublicId(\"author\", \"old_contract\", \"0.1.0\")\n    old_connection_id = PublicId(\"author\", \"old_connection\", \"0.1.0\")\n    old_skill_id = PublicId(\"author\", \"old_skill\", \"0.1.0\")\n\n    new_protocol_id = PublicId(\"author\", \"new_protocol\", \"0.1.0\")\n    new_contract_id = PublicId(\"author\", \"new_contract\", \"0.1.0\")\n    new_connection_id = PublicId(\"author\", \"new_connection\", \"0.1.0\")\n    new_skill_id = PublicId(\"author\", \"new_skill\", \"0.1.0\")\n\n    new_public_ids = {\n        new_protocol_id,\n        new_contract_id,\n        new_connection_id,\n        new_skill_id,\n    }\n\n    replacements = {\n        ComponentType.PROTOCOL: {old_protocol_id: new_protocol_id},\n        ComponentType.CONTRACT: {old_contract_id: new_contract_id},\n        ComponentType.CONNECTION: {old_connection_id: new_connection_id},\n        ComponentType.SKILL: {old_skill_id: new_skill_id},\n    }\n\n\nclass TestReplaceComponentIdsInAgentConfig(BaseTestReplaceComponentIds):\n    \"\"\"Test replace component ids in agent configuration.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set up the test.\"\"\"\n        cls.expected_custom_component_configuration = dict(foo=\"bar\")\n\n        cls.agent_config = AgentConfig(\n            agent_name=\"agent_name\",\n            author=\"author\",\n            version=\"0.1.0\",\n            default_routing={str(cls.old_protocol_id): str(cls.old_connection_id)},\n            default_connection=str(cls.old_connection_id),\n        )\n\n        cls.agent_config.protocols = {cls.old_protocol_id}\n        cls.agent_config.contracts = {cls.old_contract_id}\n        cls.agent_config.connections = {cls.old_connection_id}\n        cls.agent_config.skills = {cls.old_skill_id}\n        cls.agent_config.component_configurations[\n            ComponentId(ComponentType.PROTOCOL, cls.old_protocol_id)\n        ] = cls.expected_custom_component_configuration\n        cls.agent_config.component_configurations[\n            ComponentId(ComponentType.CONTRACT, cls.old_contract_id)\n        ] = cls.expected_custom_component_configuration\n        cls.agent_config.component_configurations[\n            ComponentId(ComponentType.CONNECTION, cls.old_connection_id)\n        ] = cls.expected_custom_component_configuration\n        cls.agent_config.component_configurations[\n            ComponentId(ComponentType.SKILL, cls.old_skill_id)\n        ] = cls.expected_custom_component_configuration\n\n        replace_component_ids(cls.agent_config, cls.replacements)\n\n    def test_protocols_updated(self):\n        \"\"\"Test set of protocol ids updated.\"\"\"\n        assert self.agent_config.protocols == {self.new_protocol_id}\n\n    def test_contracts_updated(self):\n        \"\"\"Test set of contract ids updated.\"\"\"\n        assert self.agent_config.contracts == {self.new_contract_id}\n\n    def test_connections_updated(self):\n        \"\"\"Test set of connection ids updated.\"\"\"\n        assert self.agent_config.connections == {self.new_connection_id}\n\n    def test_skills_updated(self):\n        \"\"\"Test set of skill ids updated.\"\"\"\n        assert self.agent_config.skills == {self.new_skill_id}\n\n    def test_default_connection_updated(self):\n        \"\"\"Test default connection updated.\"\"\"\n        assert self.agent_config.default_connection == self.new_connection_id\n\n    def test_default_routing_updated(self):\n        \"\"\"Test default routing updated.\"\"\"\n        assert self.agent_config.default_routing == {\n            self.new_protocol_id: self.new_connection_id\n        }\n\n    def test_custom_configuration_updated(self):\n        \"\"\"Test default routing updated.\"\"\"\n        component_protocol_id = ComponentId(\n            ComponentType.PROTOCOL, self.new_protocol_id\n        )\n        component_contract_id = ComponentId(\n            ComponentType.CONTRACT, self.new_contract_id\n        )\n        component_connection_id = ComponentId(\n            ComponentType.CONNECTION, self.new_connection_id\n        )\n        component_skill_id = ComponentId(ComponentType.SKILL, self.new_skill_id)\n\n        assert (\n            self.agent_config.component_configurations[component_protocol_id]\n            == self.expected_custom_component_configuration\n        )\n        assert (\n            self.agent_config.component_configurations[component_contract_id]\n            == self.expected_custom_component_configuration\n        )\n        assert (\n            self.agent_config.component_configurations[component_connection_id]\n            == self.expected_custom_component_configuration\n        )\n        assert (\n            self.agent_config.component_configurations[component_skill_id]\n            == self.expected_custom_component_configuration\n        )\n\n\nclass TestReplaceComponentIdsInConnectionConfig(BaseTestReplaceComponentIds):\n    \"\"\"Test replace component ids utility with connection configuration.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set up the test.\"\"\"\n        cls.connection_config = ConnectionConfig(\n            name=\"connection_name\",\n            author=\"author\",\n            version=\"0.1.0\",\n            connections={cls.old_connection_id},\n            protocols={cls.old_protocol_id},\n            restricted_to_protocols={cls.old_protocol_id},\n            excluded_protocols={cls.old_protocol_id},\n        )\n        replace_component_ids(cls.connection_config, cls.replacements)\n\n    def test_protocols_updated(self):\n        \"\"\"Test set of protocol ids updated.\"\"\"\n        assert self.connection_config.protocols == {self.new_protocol_id}\n\n    def test_connections_updated(self):\n        \"\"\"Test set of connection ids updated.\"\"\"\n        assert self.connection_config.connections == {self.new_connection_id}\n\n    def test_restricted_to_protocols_updated(self):\n        \"\"\"Test restricted to protocols updated.\"\"\"\n        assert self.connection_config.restricted_to_protocols == {self.new_protocol_id}\n\n    def test_excluded_protocols_updated(self):\n        \"\"\"Test excluded protocols updated.\"\"\"\n        assert self.connection_config.excluded_protocols == {self.new_protocol_id}\n\n\nclass TestReplaceComponentIdsInSkillConfig(BaseTestReplaceComponentIds):\n    \"\"\"Test replace component ids in skill configuration.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set up the test class.\"\"\"\n        cls.expected_custom_component_configuration = dict(foo=\"bar\")\n\n        cls.skill_config = SkillConfig(\n            name=\"skill_name\",\n            author=\"author\",\n            version=\"0.1.0\",\n        )\n\n        cls.skill_config.protocols = {cls.old_protocol_id}\n        cls.skill_config.contracts = {cls.old_contract_id}\n        cls.skill_config.connections = {cls.old_connection_id}\n        cls.skill_config.skills = {cls.old_skill_id}\n\n        replace_component_ids(cls.skill_config, cls.replacements)\n\n    def test_protocols_updated(self):\n        \"\"\"Test set of protocol ids updated.\"\"\"\n        assert self.skill_config.protocols == {self.new_protocol_id}\n\n    def test_contracts_updated(self):\n        \"\"\"Test set of contract ids updated.\"\"\"\n        assert self.skill_config.contracts == {self.new_contract_id}\n\n    def test_connections_updated(self):\n        \"\"\"Test set of connection ids updated.\"\"\"\n        assert self.skill_config.connections == {self.new_connection_id}\n\n    def test_skills_updated(self):\n        \"\"\"Test set of skill ids updated.\"\"\"\n        assert self.skill_config.skills == {self.new_skill_id}\n"
  },
  {
    "path": "tests/test_aea/test_configurations/test_validation.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests for the aea.configurations.validation module.\"\"\"\nfrom aea.configurations.validation import (\n    SAME_MARK,\n    filter_data,\n    validate_data_with_pattern,\n)\n\n\ndef test_compare_data_pattern():\n    \"\"\"Test validate_data_with_pattern.\"\"\"\n    errors = validate_data_with_pattern({\"a\": 12}, {\"a\": 13})\n    assert not errors\n\n    errors = validate_data_with_pattern({\"a\": 12}, {\"a\": \"string\"})\n    assert errors\n    assert (\n        errors[0]\n        == \"For attribute `a` `str` data type is expected, but `int` was provided!\"\n    )\n\n    errors = validate_data_with_pattern({\"a\": None}, {\"a\": int})\n    assert not errors\n\n    assert not validate_data_with_pattern(\n        {\"a\": 12}, {\"a\": \"${var}\"}, skip_env_vars=True\n    )\n    assert not validate_data_with_pattern(\n        {\"a\": \"${var}\"}, {\"a\": \"string\"}, skip_env_vars=True\n    )\n\n    errors = validate_data_with_pattern({\"a\": 12}, {\"b\": 12})\n    assert errors\n    assert errors[0] == \"Attribute `a` is not allowed to be updated!\"\n\n    errors = validate_data_with_pattern({\"a\": {}}, {\"a\": {\"b\": 12}})\n    assert errors\n    assert errors[0] == \"Attribute `a` is not allowed to be updated!\"\n\n\ndef test_filter_data():\n    \"\"\"Test filter_data function.\"\"\"\n    assert filter_data(1, 1) == SAME_MARK\n    assert filter_data(1, 2) == 2\n    assert filter_data(2, 1) == 1\n\n    assert filter_data({}, {}) == SAME_MARK\n    assert filter_data({1: 2}, {1: 2}) == SAME_MARK\n    assert filter_data({1: 2}, {1: 3}) == {1: 3}\n\n    assert filter_data([1, 2, 3], [1, 2, 3]) == SAME_MARK\n    assert filter_data([1, 2, 3], [1, 2]) == [1, 2]\n\n    assert filter_data({1: {2: 3}, 3: {2: 1}}, {1: {2: 3}, 3: {2: 3}, 0: 0}) == {\n        3: {2: 3},\n        0: 0,\n    }\n"
  },
  {
    "path": "tests/test_aea/test_connections/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This test module contains the tests for the channels.\"\"\"\n"
  },
  {
    "path": "tests/test_aea/test_connections/test_base.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests for the base module.\"\"\"\nimport asyncio\nimport os\nimport unittest\nfrom pathlib import Path\nfrom typing import cast\nfrom unittest.mock import MagicMock\n\nimport pytest\n\nimport aea\nfrom aea.configurations.base import (\n    ComponentId,\n    ComponentType,\n    ConnectionConfig,\n    PublicId,\n)\nfrom aea.configurations.loader import load_component_configuration\nfrom aea.connections.base import Connection, ConnectionStates\nfrom aea.exceptions import AEAComponentLoadException, AEAEnforceError\nfrom aea.mail.base import Envelope\n\nfrom tests.conftest import CUR_PATH\n\n\nclass TConnection(Connection):\n    \"\"\"Test class for Connection.\"\"\"\n\n    connection_id = PublicId.from_str(\"fetchai/some_connection:0.1.0\")\n\n    def connect(self, *args, **kwargs):\n        \"\"\"Connect.\"\"\"\n        pass\n\n    def disconnect(self, *args, **kwargs):\n        \"\"\"Disconnect.\"\"\"\n        pass\n\n    def from_config(self, *args, **kwargs):\n        \"\"\"From config.\"\"\"\n        pass\n\n    def receive(self, *args, **kwargs):\n        \"\"\"Receive.\"\"\"\n        pass\n\n    def send(self, *args, **kwargs):\n        \"\"\"Send.\"\"\"\n        pass\n\n\nclass TestConnectionTestCase:\n    \"\"\"Test case for Connection abstract class.\"\"\"\n\n    TConnection = TConnection\n\n    @pytest.mark.asyncio\n    async def test_loop_only_in_running_loop(self):\n        \"\"\"Test loop property positive result.\"\"\"\n        obj = self.TConnection(\n            ConnectionConfig(\"some_connection\", \"fetchai\", \"0.1.0\"), MagicMock()\n        )\n        obj.loop\n\n    def test_loop_fails_on_non_running_loop(self):\n        \"\"\"Test loop property positive result.\"\"\"\n        obj = self.TConnection(\n            ConnectionConfig(\"some_connection\", \"fetchai\", \"0.1.0\"), MagicMock()\n        )\n        with pytest.raises(AEAEnforceError):\n            obj.loop\n\n    def test_excluded_protocols_positive(self):\n        \"\"\"Test excluded_protocols property positive result.\"\"\"\n        obj = self.TConnection(\n            ConnectionConfig(\"some_connection\", \"fetchai\", \"0.1.0\"), MagicMock()\n        )\n        obj._excluded_protocols = \"excluded_protocols\"\n        obj.excluded_protocols\n\n\ndef test_loop_property():\n    \"\"\"Test connection's loop property.\"\"\"\n    connection = TConnection(\n        MagicMock(public_id=TConnection.connection_id), MagicMock()\n    )\n    with unittest.mock.patch.object(aea.connections.base, \"enforce\"):\n        loop = connection.loop\n        assert isinstance(loop, asyncio.AbstractEventLoop)\n\n\ndef test_ensure_valid_envelope_for_external_comms_negative_cases():\n    \"\"\"Test the staticmethod '_ensure_valid_envelope_for_external_comms', negative cases.\"\"\"\n    protocol_specification_id = PublicId(\"author\", \"name\", \"0.1.0\")\n    wrong_sender = wrong_to = \"author/name:0.1.0\"\n    envelope_wrong_sender = Envelope(\n        to=wrong_to,\n        sender=wrong_sender,\n        protocol_specification_id=protocol_specification_id,\n        message=b\"\",\n    )\n    with pytest.raises(\n        AEAEnforceError,\n        match=f\"Sender and to field of envelope is public id, needs to be address. Found: sender={wrong_sender}, to={wrong_to}\",\n    ):\n        Connection._ensure_valid_envelope_for_external_comms(envelope_wrong_sender)\n\n\ndef test_state():\n    \"\"\"Test connect context of a connection.\"\"\"\n    connection = TConnection(\n        MagicMock(public_id=TConnection.connection_id), MagicMock()\n    )\n    assert connection.state == ConnectionStates.disconnected\n\n    with connection._connect_context():\n        assert connection.state == ConnectionStates.connecting\n\n    assert connection.state == ConnectionStates.connected\n\n\ndef test_ensure_connected():\n    \"\"\"Test ensure_connected method.\"\"\"\n    connection = TConnection(\n        MagicMock(public_id=TConnection.connection_id), MagicMock()\n    )\n    assert not connection.is_connected\n    with pytest.raises(\n        ConnectionError, match=\"Connection is not connected! Connect first!\"\n    ):\n        connection._ensure_connected()\n\n    connection._state.set(ConnectionStates.connected)\n    connection._ensure_connected()\n\n\ndef test_from_dir():\n    \"\"\"Test Connection.from_dir\"\"\"\n    dummy_connection_dir = os.path.join(CUR_PATH, \"data\", \"dummy_connection\")\n    identity = MagicMock()\n    identity.name = \"agent_name\"\n    crypto_store = MagicMock()\n\n    data_dir = MagicMock()\n    connection = Connection.from_dir(\n        dummy_connection_dir, identity, crypto_store, data_dir\n    )\n    assert isinstance(connection, Connection)\n    assert connection.component_id == ComponentId(\n        ComponentType.CONNECTION, PublicId(\"fetchai\", \"dummy\", \"0.1.0\")\n    )\n\n\ndef test_from_config_exception_path():\n    \"\"\"Test Connection.from_config with exception\"\"\"\n    dummy_connection_dir = os.path.join(CUR_PATH, \"data\", \"dummy_connection\")\n    configuration = cast(\n        ConnectionConfig,\n        load_component_configuration(\n            ComponentType.CONNECTION, Path(dummy_connection_dir)\n        ),\n    )\n    wrong_dir = os.path.join(CUR_PATH, \"data\", \"wrong_connection\")\n    configuration.directory = Path(wrong_dir)\n    identity = MagicMock()\n    identity.name = \"agent_name\"\n    crypto_store = MagicMock()\n    data_dir = MagicMock()\n    with pytest.raises(AEAComponentLoadException, match=\"Connection module\"):\n        Connection.from_config(configuration, identity, crypto_store, data_dir)\n\n\ndef test_from_config_exception_class():\n    \"\"\"Test Connection.from_config with exception\"\"\"\n    dummy_connection_dir = os.path.join(CUR_PATH, \"data\", \"dummy_connection\")\n    configuration = cast(\n        ConnectionConfig,\n        load_component_configuration(\n            ComponentType.CONNECTION, Path(dummy_connection_dir)\n        ),\n    )\n    configuration.directory = Path(dummy_connection_dir)\n    configuration.class_name = \"WrongName\"\n    identity = MagicMock()\n    identity.name = \"agent_name\"\n    crypto_store = MagicMock()\n    data_dir = MagicMock()\n    with pytest.raises(AEAComponentLoadException, match=\"Connection class\"):\n        Connection.from_config(configuration, identity, crypto_store, data_dir)\n\n\ndef test_set_base_state():\n    \"\"\"Check error raised on bad state set.\"\"\"\n    con = TConnection(\n        configuration=ConnectionConfig(\"some_connection\", \"fetchai\", \"0.1.0\"),\n        data_dir=MagicMock(),\n    )\n    with pytest.raises(ValueError, match=\"Incorrect state.*\"):\n        con.state = \"some bad state\"\n"
  },
  {
    "path": "tests/test_aea/test_connections/test_scaffold.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This test module contains the tests for the scaffold connection.\"\"\"\nimport os\nimport sys\nfrom unittest.mock import MagicMock\n\nimport pytest\n\nfrom aea.configurations.base import ConnectionConfig\nfrom aea.connections.scaffold.connection import MyScaffoldAsyncConnection\nfrom aea.helpers.base import cd\nfrom aea.test_tools.test_cases import AEATestCaseEmpty\n\nfrom tests.common.pexpect_popen import PexpectWrapper\nfrom tests.conftest import ROOT_DIR\n\n\nclass TestScaffoldConnectionReception:\n    \"\"\"Test that the stub connection is implemented correctly.\"\"\"\n\n    def setup(self):\n        \"\"\"Set case up.\"\"\"\n        configuration = ConnectionConfig(\n            connection_id=MyScaffoldAsyncConnection.connection_id,\n        )\n        self.connection = MyScaffoldAsyncConnection(\n            configuration=configuration, data_dir=MagicMock()\n        )\n\n    @pytest.mark.asyncio\n    async def test_methods_not_implemented(self):\n        \"\"\"Test methods not implemented.\"\"\"\n        with pytest.raises(NotImplementedError):\n            await self.connection.connect()\n\n        with pytest.raises(NotImplementedError):\n            await self.connection.disconnect()\n\n        with pytest.raises(NotImplementedError):\n            await self.connection.send(None)\n\n        with pytest.raises(NotImplementedError):\n            await self.connection.receive()\n\n\nclass TestScaffoldConnectionAndRun(AEATestCaseEmpty):\n    \"\"\"Test that the scaffold connection created.\"\"\"\n\n    def setup(self):\n        \"\"\"Set case up.\"\"\"\n        result = self.invoke(\"scaffold\", \"connection\", \"my_con\")\n        assert result.exit_code == 0\n\n    def test_run_and_not_implemented_error(self):\n        \"\"\"Test aea run crashes with connect not implemented for scaffolded connection.\"\"\"\n        self.generate_private_key()\n        self.add_private_key()\n        with cd(self._get_cwd()):\n            proc = PexpectWrapper(  # nosec\n                [sys.executable, \"-m\", \"aea.cli\", \"-v\", \"DEBUG\", \"run\"],\n                env={\n                    **os.environ,\n                    \"PYTHONPATH\": ROOT_DIR + \":\" + os.environ.get(\"PYTHONPATH\", \"\"),\n                },\n                maxread=10000,\n                encoding=\"utf-8\",\n                logfile=sys.stdout,\n            )\n            try:\n                proc.expect_all(\n                    [\n                        \"Error while connecting <class 'connection_module.MyScaffoldAsyncConnection'>: NotImplementedError()\"\n                    ],\n                    timeout=50,\n                )\n            finally:\n                proc.terminate()\n                proc.wait_to_complete(timeout=50)\n"
  },
  {
    "path": "tests/test_aea/test_connections/test_sync_connection.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests for the sync connection module.\"\"\"\nimport asyncio\nimport time\nfrom unittest.mock import MagicMock, Mock, patch\n\nimport pytest\n\nfrom aea.configurations.data_types import PublicId\nfrom aea.connections.base import BaseSyncConnection\nfrom aea.mail.base import Envelope\n\n\nclass SampleConnection(BaseSyncConnection):\n    \"\"\"Sample connection for testing.\"\"\"\n\n    MAX_WORKER_THREADS = 3\n\n    connection_id = PublicId(\"test\", \"test\", \"0.1.0\")\n    PAUSE = 0.5\n\n    def __init__(self, *args, **kwargs):\n        \"\"\"Init connection.\"\"\"\n        super().__init__(*args, **kwargs)\n        self.main_called = False\n        self.send_counter = 0\n        self.on_connect_called = False\n        self.on_disconnect_called = False\n\n    def main(self):\n        \"\"\"Run main.\"\"\"\n        self.main_called = True\n        envelope = Mock()\n        envelope.message = \"main\"\n        self.put_envelope(envelope)\n\n    def on_send(self, envelope: Envelope) -> None:\n        \"\"\"Run on send.\"\"\"\n        time.sleep(self.PAUSE)\n        resp_envelope = Mock()\n        resp_envelope.message = f\"resp for {str(envelope.message)}\"\n        self.put_envelope(resp_envelope)\n        self.send_counter += 1\n\n    def on_connect(self):\n        \"\"\"Run on connect.\"\"\"\n        self.on_connect_called = True\n\n    def on_disconnect(self):\n        \"\"\"Run on disconnect.\"\"\"\n        self.on_disconnect_called = True\n\n\n@pytest.mark.asyncio\nasync def test_sync_connection():\n    \"\"\"Test sync connection example.\"\"\"\n    conf = Mock()\n    conf.public_id = SampleConnection.connection_id\n    conf.config = {}\n    con = SampleConnection(conf, MagicMock())\n    await asyncio.wait_for(con.connect(), timeout=10)\n    assert con.is_connected\n    envelope = Mock()\n\n    for i in range(10):\n        envelope.message = str(i)\n        await asyncio.wait_for(con.send(envelope), timeout=10)\n\n    await asyncio.sleep(con.PAUSE * 1.5)\n    assert con.send_counter == con.MAX_WORKER_THREADS\n\n    await asyncio.wait_for(con.disconnect(), timeout=10)\n    assert con.is_disconnected\n\n    assert con.on_connect_called\n    assert con.on_disconnect_called\n    assert con.main_called\n\n    with patch.object(con, \"_ensure_connected\"):\n        envelope = await con.receive()\n        assert envelope.message == \"main\"\n"
  },
  {
    "path": "tests/test_aea/test_context/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains a test for aea.context.\"\"\"\n"
  },
  {
    "path": "tests/test_aea/test_context/test_base.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains a test for aea.context.\"\"\"\nimport os\nfrom unittest.mock import Mock\n\nfrom aea_ledger_fetchai import FetchAICrypto\n\nfrom aea.context.base import AgentContext\nfrom aea.identity.base import Identity\n\n\ndef test_agent_context():\n    \"\"\"Test the agent context.\"\"\"\n    agent_name = \"name\"\n    address = \"address\"\n    addresses = {FetchAICrypto.identifier: address}\n    public_key = \"public_key\"\n    public_keys = {FetchAICrypto.identifier: public_key}\n    identity = Identity(agent_name, addresses=addresses, public_keys=public_keys)\n    connection_status = \"connection_status_stub\"\n    outbox = \"outbox_stub\"\n    decision_maker_message_queue = \"decision_maker_message_queue_stub\"\n    decision_maker_handler_context = \"decision_maker_handler_context_stub\"\n    task_manager = \"task_manager_stub\"\n    default_connection = \"default_connection_stub\"\n    default_routing = \"default_routing_stub\"\n    search_service_address = \"search_service_address_stub\"\n    decision_maker_address = \"decision_maker_address_stub\"\n    value = \"some_value\"\n    kwargs = {\"some_key\": value}\n    default_ledger_id = \"fetchai\"\n    currency_denominations = {}\n    data_dir = os.getcwd()\n\n    send_to_skill = Mock()\n\n    def storage_callable_():\n        pass\n\n    ac = AgentContext(\n        identity=identity,\n        connection_status=connection_status,\n        outbox=outbox,\n        decision_maker_message_queue=decision_maker_message_queue,\n        decision_maker_handler_context=decision_maker_handler_context,\n        task_manager=task_manager,\n        default_ledger_id=default_ledger_id,\n        currency_denominations=currency_denominations,\n        default_connection=default_connection,\n        default_routing=default_routing,\n        search_service_address=search_service_address,\n        decision_maker_address=decision_maker_address,\n        storage_callable=storage_callable_,\n        data_dir=data_dir,\n        send_to_skill=send_to_skill,\n        **kwargs,\n    )\n\n    assert ac.data_dir == data_dir\n    assert ac.shared_state == {}\n    assert ac.identity == identity\n    assert ac.agent_name == identity.name\n    assert ac.address == identity.address\n    assert ac.addresses == identity.addresses\n    assert ac.public_key == identity.public_key\n    assert ac.public_keys == identity.public_keys\n    assert ac.connection_status == connection_status\n    assert ac.outbox == outbox\n    assert ac.decision_maker_message_queue == decision_maker_message_queue\n    assert ac.decision_maker_handler_context == decision_maker_handler_context\n    assert ac.task_manager == task_manager\n    assert ac.default_ledger_id == default_ledger_id\n    assert ac.currency_denominations == currency_denominations\n    assert ac.default_connection == default_connection\n    assert ac.default_routing == default_routing\n    assert ac.search_service_address == search_service_address\n    assert ac.namespace.some_key == value\n    assert ac.decision_maker_address == decision_maker_address\n    assert ac.storage == storage_callable_()\n\n    ac.send_to_skill(\"test\")\n    send_to_skill.assert_called()\n"
  },
  {
    "path": "tests/test_aea/test_contracts/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains tests for aea.contracts.\"\"\"\n"
  },
  {
    "path": "tests/test_aea/test_contracts/test_base.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains tests for aea.contracts.base.\"\"\"\n\nimport logging\nimport os\nfrom pathlib import Path\nfrom typing import cast\nfrom unittest.mock import patch\n\nimport pytest\nimport web3\nfrom aea_ledger_ethereum import EthereumCrypto\nfrom aea_ledger_fetchai import FetchAICrypto\n\nfrom aea.configurations.base import ComponentType, ContractConfig\nfrom aea.configurations.loader import load_component_configuration\nfrom aea.contracts import contract_registry\nfrom aea.contracts.base import Contract\nfrom aea.contracts.scaffold.contract import MyScaffoldContract\nfrom aea.crypto.ledger_apis import ETHEREUM_DEFAULT_ADDRESS, FETCHAI_DEFAULT_ADDRESS\nfrom aea.crypto.registries import crypto_registry, ledger_apis_registry\nfrom aea.exceptions import AEAComponentLoadException\n\nfrom tests.conftest import ROOT_DIR, make_uri\n\n\nlogger = logging.getLogger(__name__)\n\n\ndef test_from_dir():\n    \"\"\"Tests the from dir and from config methods.\"\"\"\n    contract = Contract.from_dir(\n        os.path.join(ROOT_DIR, \"tests\", \"data\", \"dummy_contract\")\n    )\n    assert contract is not None\n    assert contract.contract_interface is not None\n    assert isinstance(contract.contract_interface, dict)\n\n\ndef test_from_config_and_registration():\n    \"\"\"Tests the from config method and contract registry registration.\"\"\"\n\n    directory = Path(ROOT_DIR, \"tests\", \"data\", \"dummy_contract\")\n    configuration = load_component_configuration(ComponentType.CONTRACT, directory)\n    configuration._directory = directory\n    configuration = cast(ContractConfig, configuration)\n\n    if str(configuration.public_id) in contract_registry.specs:\n        contract_registry.specs.pop(str(configuration.public_id))\n\n    contract = Contract.from_config(configuration)\n    assert contract is not None\n    assert contract.contract_interface is not None\n    assert isinstance(contract.contract_interface, dict)\n    assert contract.configuration == configuration\n    assert contract.id == configuration.public_id\n\n    # the contract is registered as side-effect\n    assert str(contract.public_id) in contract_registry.specs\n\n    try:\n        contract_registry.specs.pop(str(configuration.public_id))\n    except Exception as e:\n        logger.exception(e)\n\n\ndef test_from_config_negative():\n    \"\"\"Tests the from config method raises.\"\"\"\n\n    directory = Path(ROOT_DIR, \"tests\", \"data\", \"dummy_contract\")\n    configuration = load_component_configuration(ComponentType.CONTRACT, directory)\n    configuration._directory = directory\n    configuration = cast(ContractConfig, configuration)\n\n    if str(configuration.public_id) in contract_registry.specs:\n        contract_registry.specs.pop(str(configuration.public_id))\n\n    configuration.class_name = \"WrongName\"\n    with pytest.raises(AEAComponentLoadException):\n        _ = Contract.from_config(configuration)\n\n    try:\n        contract_registry.specs.pop(str(configuration.public_id))\n    except Exception as e:\n        logger.exception(e)\n\n\ndef test_non_implemented_class_methods():\n    \"\"\"Tests the non implemented class methods.\"\"\"\n    with pytest.raises(NotImplementedError):\n        Contract.get_raw_transaction(\"ledger_api\", \"contract_address\")\n\n    with pytest.raises(NotImplementedError):\n        Contract.get_raw_message(\"ledger_api\", \"contract_address\")\n\n    with pytest.raises(NotImplementedError):\n        Contract.get_state(\"ledger_api\", \"contract_address\")\n\n\n@pytest.fixture()\ndef dummy_contract(request):\n    \"\"\"Dummy contract fixture.\"\"\"\n    directory = Path(ROOT_DIR, \"tests\", \"data\", \"dummy_contract\")\n    configuration = load_component_configuration(ComponentType.CONTRACT, directory)\n    configuration._directory = directory\n    configuration = cast(ContractConfig, configuration)\n\n    if str(configuration.public_id) in contract_registry.specs:\n        contract_registry.specs.pop(str(configuration.public_id))\n\n    # load into sys modules and register into contract registry\n    contract = Contract.from_config(configuration)\n    yield contract\n    contract_registry.specs.pop(str(configuration.public_id))\n\n\ndef test_get_instance_no_address_ethereum(dummy_contract):\n    \"\"\"Tests get instance method with no address for ethereum.\"\"\"\n    ledger_api = ledger_apis_registry.make(\n        EthereumCrypto.identifier,\n        address=ETHEREUM_DEFAULT_ADDRESS,\n    )\n    instance = dummy_contract.get_instance(ledger_api)\n    assert type(instance) == web3._utils.datatypes.PropertyCheckingFactory\n\n\n@pytest.mark.integration\n@pytest.mark.ledger\ndef test_get_deploy_transaction_ethereum(\n    dummy_contract, ganache_addr, ganache_port, ganache\n):\n    \"\"\"Tests the deploy transaction classmethod for ethereum.\"\"\"\n    aea_ledger_ethereum = crypto_registry.make(EthereumCrypto.identifier)\n    ledger_api = ledger_apis_registry.make(\n        EthereumCrypto.identifier, address=make_uri(ganache_addr, ganache_port)\n    )\n    with patch(\n        \"web3.contract.ContractConstructor.buildTransaction\",\n        return_value={\"data\": \"0xstub\"},\n    ):\n        deploy_tx = dummy_contract.get_deploy_transaction(\n            ledger_api, aea_ledger_ethereum.address\n        )\n    assert deploy_tx is not None and len(deploy_tx) == 6\n    assert all(\n        key in [\"from\", \"value\", \"gas\", \"gasPrice\", \"nonce\", \"data\"]\n        for key in deploy_tx.keys()\n    )\n\n\ndef test_get_instance_no_address_cosmwasm(dummy_contract):\n    \"\"\"Tests get instance method with no address for fetchai.\"\"\"\n    ledger_api = ledger_apis_registry.make(\n        FetchAICrypto.identifier,\n        address=FETCHAI_DEFAULT_ADDRESS,\n    )\n    instance = dummy_contract.get_instance(ledger_api)\n    assert instance is None\n\n\ndef test_get_deploy_transaction_cosmwasm(dummy_contract):\n    \"\"\"Tests the deploy transaction classmethod for fetchai.\"\"\"\n    aea_ledger_fetchai = crypto_registry.make(FetchAICrypto.identifier)\n    ledger_api = ledger_apis_registry.make(\n        FetchAICrypto.identifier,\n        address=FETCHAI_DEFAULT_ADDRESS,\n    )\n    deploy_tx = dummy_contract.get_deploy_transaction(\n        ledger_api, aea_ledger_fetchai.address, account_number=1, sequence=0\n    )\n    assert deploy_tx is not None and len(deploy_tx) == 2\n    assert all(key in [\"tx\", \"sign_data\"] for key in deploy_tx.keys())\n\n\ndef test_scaffold():\n    \"\"\"Test the scaffold contract can be loaded/instantiated.\"\"\"\n    scaffold = MyScaffoldContract(\"config\")\n    kwargs = {\"key\": \"value\"}\n    with pytest.raises(NotImplementedError):\n        scaffold.get_raw_transaction(\"ledger_api\", \"contract_address\", **kwargs)\n    with pytest.raises(NotImplementedError):\n        scaffold.get_raw_message(\"ledger_api\", \"contract_address\", **kwargs)\n    with pytest.raises(NotImplementedError):\n        scaffold.get_state(\"ledger_api\", \"contract_address\", **kwargs)\n"
  },
  {
    "path": "tests/test_aea/test_crypto/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains a test for aea.crypto.\"\"\"\n"
  },
  {
    "path": "tests/test_aea/test_crypto/test_helpers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests for the crypto/helpers module.\"\"\"\nimport logging\nimport os\nfrom pathlib import Path\nfrom tempfile import TemporaryDirectory\nfrom unittest.mock import mock_open, patch\n\nimport pytest\nfrom aea_ledger_cosmos import CosmosCrypto\nfrom aea_ledger_ethereum import EthereumCrypto\nfrom aea_ledger_fetchai import FetchAICrypto\n\nfrom aea.crypto.helpers import (\n    create_private_key,\n    get_wallet_from_agent_config,\n    make_certificate,\n    private_key_verify,\n    try_generate_testnet_wealth,\n    try_validate_private_key_path,\n)\nfrom aea.crypto.wallet import Wallet\n\nfrom tests.conftest import (\n    COSMOS_PRIVATE_KEY_FILE,\n    CUR_PATH,\n    ETHEREUM_PRIVATE_KEY_FILE,\n    ETHEREUM_PRIVATE_KEY_PATH,\n    FETCHAI_PRIVATE_KEY_PATH,\n)\nfrom tests.test_aea.test_cli.tools_for_testing import AgentConfigMock\n\n\nlogger = logging.getLogger(__name__)\n\n\nclass ResponseMock:\n    \"\"\"Mock for response class.\"\"\"\n\n    text = \"some text\"\n\n    def __init__(self, status_code=200):\n        \"\"\"Initialise response mock.\"\"\"\n        self.status_code = status_code\n\n\nclass TestHelperFile:\n    \"\"\"Test helper module in aea/crypto.\"\"\"\n\n    def tests_private_keys(self):\n        \"\"\"Test the private keys.\"\"\"\n        try_validate_private_key_path(\n            FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_PATH\n        )\n        with pytest.raises(Exception):\n            private_key_path = os.path.join(\n                CUR_PATH, \"data\", \"fet_private_key_wrong.txt\"\n            )\n            try_validate_private_key_path(FetchAICrypto.identifier, private_key_path)\n\n        try_validate_private_key_path(\n            EthereumCrypto.identifier, ETHEREUM_PRIVATE_KEY_PATH\n        )\n        with pytest.raises(Exception):\n            private_key_path = os.path.join(\n                CUR_PATH, \"data\", \"fet_private_key_wrong.txt\"\n            )\n            try_validate_private_key_path(EthereumCrypto.identifier, private_key_path)\n\n    def tests_generate_wealth_ethereum_fail_no_url(self, caplog):\n        \"\"\"Test generate wealth for ethereum.\"\"\"\n        address = \"my_address\"\n        with caplog.at_level(\n            logging.DEBUG, logger=\"aea_ledger_ethereum._default_logger\"\n        ):\n            try_generate_testnet_wealth(\n                identifier=EthereumCrypto.identifier, address=address\n            )\n            assert (\n                \"Url is none, no default url provided. Please provide a faucet url.\"\n                in caplog.text\n            )\n\n    def tests_generate_wealth_ethereum_fail_invalid_url(self, caplog):\n        \"\"\"Test generate wealth for ethereum.\"\"\"\n        address = \"my_address\"\n        result = ResponseMock(status_code=500)\n        with patch(\"aea_ledger_ethereum.requests.get\", return_value=result):\n            with caplog.at_level(\n                logging.DEBUG, logger=\"aea_ledger_ethereum._default_logger\"\n            ):\n                try_generate_testnet_wealth(\n                    identifier=EthereumCrypto.identifier,\n                    address=address,\n                    url=\"wrong_url\",\n                )\n                assert \"Response: 500\" in caplog.text\n\n    def tests_generate_wealth_ethereum_fail_valid_url(self, caplog):\n        \"\"\"Test generate wealth for ethereum.\"\"\"\n        address = \"my_address\"\n        result = ResponseMock(status_code=200)\n        with patch(\"aea_ledger_ethereum.requests.get\", return_value=result):\n            with caplog.at_level(\n                logging.DEBUG, logger=\"aea_ledger_ethereum._default_logger\"\n            ):\n                try_generate_testnet_wealth(\n                    identifier=EthereumCrypto.identifier,\n                    address=address,\n                    url=\"correct_url\",\n                )\n\n    @patch(\"aea_ledger_ethereum.requests.post\", return_value=ResponseMock())\n    @patch(\"aea_ledger_ethereum.json.loads\", return_value={\"error_message\": \"\"})\n    def test_try_generate_testnet_wealth_error_resp_ethereum(self, *mocks):\n        \"\"\"Test try_generate_testnet_wealth error_resp.\"\"\"\n        try_generate_testnet_wealth(EthereumCrypto.identifier, \"address\")\n\n    def test_try_validate_private_key_path_positive(self):\n        \"\"\"Test _validate_private_key_path positive result.\"\"\"\n        try_validate_private_key_path(\n            FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_PATH\n        )\n        try_validate_private_key_path(\n            EthereumCrypto.identifier, ETHEREUM_PRIVATE_KEY_PATH\n        )\n\n    @patch(\"builtins.open\", mock_open())\n    def test__create_ethereum_private_key_positive(self, *mocks):\n        \"\"\"Test _create_ethereum_private_key positive result.\"\"\"\n        create_private_key(EthereumCrypto.identifier, ETHEREUM_PRIVATE_KEY_FILE)\n\n    @patch(\"builtins.open\", mock_open())\n    def test__create_cosmos_private_key_positive(self, *mocks):\n        \"\"\"Test _create_cosmos_private_key positive result.\"\"\"\n        create_private_key(CosmosCrypto.identifier, COSMOS_PRIVATE_KEY_FILE)\n\n\ndef test_private_key_verify():\n    \"\"\"Test private_key_verify.\"\"\"\n    agent_conf = AgentConfigMock(private_key_paths=[(\"fetchai\", \"test\")])\n    with patch(\"aea.crypto.helpers.try_validate_private_key_path\") as mock_validate:\n        private_key_verify(agent_conf, Path(\".\"))\n    mock_validate.assert_called()\n\n    agent_conf = AgentConfigMock(private_key_paths=[(\"fetchai\", \"${var}\")])\n    with patch(\"aea.crypto.helpers.try_validate_private_key_path\") as mock_validate:\n        with patch(\"aea.crypto.helpers.create_private_key\") as mock_create:\n            private_key_verify(agent_conf, Path(\".\"))\n    mock_validate.assert_not_called()\n    mock_create.assert_not_called()\n\n\ndef test_make_certificate():\n    \"\"\"Test make_certificate.\"\"\"\n    with TemporaryDirectory() as tmp_dir:\n        make_certificate(\n            \"fetchai\",\n            os.path.join(CUR_PATH, \"data\", \"fetchai_private_key.txt\"),\n            b\"message\",\n            os.path.join(tmp_dir, \"test.txt\"),\n        )\n\n\ndef test_get_wallet_from_agent_config():\n    \"\"\"Test get_wallet_from_agent_config.\"\"\"\n    agent_conf = AgentConfigMock()\n    wallet = get_wallet_from_agent_config(agent_conf)\n    assert isinstance(wallet, Wallet)\n"
  },
  {
    "path": "tests/test_aea/test_crypto/test_ledger_apis.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests for the crypto/helpers module.\"\"\"\n\nimport logging\nfrom unittest import mock\n\nimport pytest\nfrom aea_ledger_cosmos import CosmosCrypto\nfrom aea_ledger_ethereum import EthereumCrypto\nfrom aea_ledger_fetchai import FetchAICrypto\n\nfrom aea.configurations.constants import DEFAULT_LEDGER\nfrom aea.crypto.ledger_apis import LedgerApis\nfrom aea.exceptions import AEAEnforceError\n\nfrom tests.conftest import COSMOS_ADDRESS_ONE, ETHEREUM_ADDRESS_ONE, FETCHAI_ADDRESS_ONE\n\n\nlogger = logging.getLogger(__name__)\n\n\ndef _raise_exception(*args, **kwargs):\n    raise Exception(\"Message\")\n\n\ndef test_initialisation():\n    \"\"\"Test the initialisation of the ledger APIs.\"\"\"\n    ledger_apis = LedgerApis\n    assert ledger_apis.has_ledger(FetchAICrypto.identifier)\n    assert type(LedgerApis.get_api(FetchAICrypto.identifier)).__name__ == \"FetchAIApi\"\n    assert LedgerApis.has_ledger(EthereumCrypto.identifier)\n    assert type(LedgerApis.get_api(EthereumCrypto.identifier)).__name__ == \"EthereumApi\"\n    assert LedgerApis.has_ledger(CosmosCrypto.identifier)\n    assert type(LedgerApis.get_api(CosmosCrypto.identifier)).__name__ == \"CosmosApi\"\n    with pytest.raises(AEAEnforceError):\n        ledger_apis.get_api(\"UNKNOWN\")\n\n\nclass TestLedgerApis:\n    \"\"\"Test the ledger_apis module.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Setup the test case.\"\"\"\n        cls.ledger_apis = LedgerApis\n\n    def test_get_balance(self):\n        \"\"\"Test the get_balance.\"\"\"\n        with mock.patch(\"aea_ledger_ethereum.EthereumApi.get_balance\", return_value=10):\n            balance = self.ledger_apis.get_balance(\n                EthereumCrypto.identifier, ETHEREUM_ADDRESS_ONE\n            )\n            assert balance == 10\n\n    def test_get_transfer_transaction(self):\n        \"\"\"Test the get_transfer_transaction.\"\"\"\n        with mock.patch(\n            \"aea_ledger_cosmos.CosmosApi.get_transfer_transaction\",\n            return_value=\"mock_transaction\",\n        ):\n            tx = self.ledger_apis.get_transfer_transaction(\n                identifier=CosmosCrypto.identifier,\n                sender_address=\"sender_address\",\n                destination_address=COSMOS_ADDRESS_ONE,\n                amount=10,\n                tx_fee=10,\n                tx_nonce=\"transaction nonce\",\n            )\n            assert tx == \"mock_transaction\"\n\n    def test_send_signed_transaction(self):\n        \"\"\"Test the send_signed_transaction.\"\"\"\n        with mock.patch(\n            \"aea_ledger_cosmos.CosmosApi.send_signed_transaction\",\n            return_value=\"mock_transaction_digest\",\n        ):\n            tx_digest = self.ledger_apis.send_signed_transaction(\n                identifier=CosmosCrypto.identifier,\n                tx_signed=\"signed_transaction\",\n            )\n            assert tx_digest == \"mock_transaction_digest\"\n\n    def test_get_transaction_receipt(self):\n        \"\"\"Test the get_transaction_receipt.\"\"\"\n        with mock.patch(\n            \"aea_ledger_cosmos.CosmosApi.get_transaction_receipt\",\n            return_value=\"mock_transaction_receipt\",\n        ):\n            tx_receipt = self.ledger_apis.get_transaction_receipt(\n                identifier=CosmosCrypto.identifier,\n                tx_digest=\"tx_digest\",\n            )\n            assert tx_receipt == \"mock_transaction_receipt\"\n\n    def test_get_transaction(self):\n        \"\"\"Test the get_transaction.\"\"\"\n        with mock.patch(\n            \"aea_ledger_cosmos.CosmosApi.get_transaction\",\n            return_value=\"mock_transaction\",\n        ):\n            tx = self.ledger_apis.get_transaction(\n                identifier=CosmosCrypto.identifier,\n                tx_digest=\"tx_digest\",\n            )\n            assert tx == \"mock_transaction\"\n\n    def test_is_transaction_settled(self):\n        \"\"\"Test the is_transaction_settled.\"\"\"\n        with mock.patch(\n            \"aea_ledger_cosmos.CosmosApi.is_transaction_settled\",\n            return_value=True,\n        ):\n            is_settled = self.ledger_apis.is_transaction_settled(\n                identifier=CosmosCrypto.identifier,\n                tx_receipt=\"tx_receipt\",\n            )\n            assert is_settled\n\n    def test_is_transaction_valid(self):\n        \"\"\"Test the is_transaction_valid.\"\"\"\n        with mock.patch(\n            \"aea_ledger_cosmos.CosmosApi.is_transaction_valid\",\n            return_value=True,\n        ):\n            is_valid = self.ledger_apis.is_transaction_valid(\n                identifier=CosmosCrypto.identifier,\n                tx=\"tx\",\n                seller=\"seller\",\n                client=\"client\",\n                tx_nonce=\"tx_nonce\",\n                amount=10,\n            )\n            assert is_valid\n\n    def test_recover_message(self):\n        \"\"\"Test the is_transaction_valid.\"\"\"\n        expected_addresses = (\"address_1\", \"address_2\")\n        with mock.patch(\n            \"aea_ledger_cosmos.CosmosApi.recover_message\",\n            return_value=expected_addresses,\n        ):\n            addresses = self.ledger_apis.recover_message(\n                identifier=CosmosCrypto.identifier,\n                message=\"message\",\n                signature=\"signature\",\n            )\n            assert addresses == expected_addresses\n\n    def test_get_hash(self):\n        \"\"\"Test the get_hash.\"\"\"\n        expected_hash = \"hash\"\n        with mock.patch(\n            \"aea_ledger_cosmos.CosmosApi.get_hash\",\n            return_value=expected_hash,\n        ):\n            hash_ = self.ledger_apis.get_hash(\n                identifier=CosmosCrypto.identifier,\n                message=b\"message\",\n            )\n            assert hash_ == expected_hash\n\n    def test_get_contract_address(self):\n        \"\"\"Test the get_contract_address.\"\"\"\n        expected_address = \"address\"\n        with mock.patch(\n            \"aea_ledger_cosmos.CosmosApi.get_contract_address\",\n            return_value=expected_address,\n        ):\n            address_ = self.ledger_apis.get_contract_address(\n                identifier=CosmosCrypto.identifier,\n                tx_receipt={},\n            )\n            assert address_ == expected_address\n\n    def test_generate_tx_nonce_positive(self):\n        \"\"\"Test generate_tx_nonce positive result.\"\"\"\n        result = LedgerApis.generate_tx_nonce(\n            CosmosCrypto.identifier, \"seller\", \"client\"\n        )\n        assert int(result, 16)\n\n\ndef test_is_valid_address():\n    \"\"\"Test LedgerApis.is_valid_address.\"\"\"\n    assert LedgerApis.is_valid_address(DEFAULT_LEDGER, FETCHAI_ADDRESS_ONE)\n    assert LedgerApis.is_valid_address(EthereumCrypto.identifier, ETHEREUM_ADDRESS_ONE)\n    assert LedgerApis.is_valid_address(CosmosCrypto.identifier, COSMOS_ADDRESS_ONE)\n"
  },
  {
    "path": "tests/test_aea/test_crypto/test_password_end2end.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This test module contains the tests for the private key password support.\"\"\"\nfrom pathlib import Path\n\nimport pytest\nfrom click.exceptions import ClickException\n\nfrom aea.helpers.base import cd\nfrom aea.test_tools.test_cases import AEATestCaseEmpty\n\n\nclass TestKeyEncryption(AEATestCaseEmpty):\n    \"\"\"Test that the command 'aea generate-key' works as expected.\"\"\"\n\n    @pytest.mark.parametrize(\"ledger_name\", [\"fetchai\", \"ethereum\", \"cosmos\"])\n    def test_crypto_plugin(self, ledger_name):\n        \"\"\"Test that the fetch private key is created correctly.\"\"\"\n        with cd(self._get_cwd()):\n            plain_file_name = Path(f\"{ledger_name}_key\")\n            encrypted_file_name = Path(f\"{ledger_name}_key_encrypted\")\n            password = \"somePwd\"  # nosec\n            self.invoke(\"generate-key\", ledger_name, str(plain_file_name))\n            assert plain_file_name.exists()\n\n            self.invoke(\n                \"generate-key\",\n                ledger_name,\n                str(encrypted_file_name),\n                \"--password\",\n                password,\n            )\n            assert encrypted_file_name.exists()\n            assert len(encrypted_file_name.read_bytes()) != len(\n                plain_file_name.read_bytes()\n            )\n\n            with pytest.raises(ClickException, match=\"Error on key.*load.*password\"):\n                self.invoke(\"add-key\", ledger_name, str(encrypted_file_name))\n\n            with pytest.raises(ClickException, match=\"Decrypt error! Bad password?\"):\n                self.invoke(\n                    \"add-key\",\n                    ledger_name,\n                    str(encrypted_file_name),\n                    \"--password\",\n                    \"incorrectpassword\",\n                )\n            r = self.invoke(\n                \"add-key\",\n                ledger_name,\n                str(encrypted_file_name),\n                \"--password\",\n                password,\n            )\n            assert r.exit_code == 0\n\n            r = self.invoke(\n                \"get-address\",\n                ledger_name,\n                \"--password\",\n                password,\n            )\n            assert r.exit_code == 0\n"
  },
  {
    "path": "tests/test_aea/test_crypto/test_registries.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains tests for aea.crypto.registries\"\"\"\n\nfrom typing import Optional\n\nfrom aea_ledger_cosmos import CosmosApi, CosmosCrypto\n\nfrom aea.crypto.base import Crypto\nfrom aea.crypto.registries import make_crypto, make_ledger_api\nfrom aea.crypto.registries.base import ItemId, Registry\n\n\nCOSMOS = CosmosCrypto.identifier\n\n\ndef test_make_crypto_cosmos_positive():\n    \"\"\"Test make_crypto for fetchai.\"\"\"\n    crypto = make_crypto(COSMOS)\n    assert isinstance(crypto, CosmosCrypto)\n\n\ndef test_make_ledger_api_cosmos_positive():\n    \"\"\"Test make_crypto for fetchai.\"\"\"\n    ledger_api = make_ledger_api(COSMOS, **{\"network\": \"testnet\"})\n    assert isinstance(ledger_api, CosmosApi)\n\n\nclass Something:\n    \"\"\"Some class.\"\"\"\n\n    class_key = None  # type: Optional[str]\n\n    def __init__(self, **kwargs):\n        \"\"\"Initialize something.\"\"\"\n        self.kwargs = kwargs\n\n\ndef test_register_make_with_class_kwargs():\n    \"\"\"Test registry make with class kwargs.\"\"\"\n    reg = Registry()\n    id_ = \"id\"\n    kwargs = {\"key\": \"value\"}\n    class_kwargs = {\"class_key\": \"class_value\"}\n    reg.register(\n        id_=id_,\n        entry_point=\"tests.test_aea.test_crypto.test_registries:Something\",\n        class_kwargs=class_kwargs,\n        **kwargs,\n    )\n    assert Something.class_key is None\n    item = reg.make(id_)\n    assert item is not None\n    assert type(item) == Something\n    assert item.kwargs == kwargs\n    assert item.class_key == \"class_value\"\n\n\ndef test_itemid():\n    \"\"\"Test the idemid object.\"\"\"\n    item_id = ItemId(COSMOS)\n    assert item_id.name == COSMOS\n\n\ndef test_registry():\n    \"\"\"Test the registry object.\"\"\"\n    registry = Registry[Crypto]()\n    item_id = ItemId(COSMOS)\n    assert not registry.has_spec(item_id), \"Registry should be empty\"\n"
  },
  {
    "path": "tests/test_aea/test_crypto/test_registry/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests for the crypto and ledger registries.\"\"\"\n"
  },
  {
    "path": "tests/test_aea/test_crypto/test_registry/test_crypto_registry.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests for the crypto registry.\"\"\"\n\nimport logging\nimport string\nfrom unittest import mock\n\nimport pytest\nfrom aea_ledger_cosmos import CosmosCrypto\nfrom aea_ledger_ethereum import EthereumCrypto\nfrom aea_ledger_fetchai import FetchAICrypto\n\nimport aea.crypto\nfrom aea.crypto.registries.base import EntryPoint\nfrom aea.exceptions import AEAException\n\nfrom tests.data.custom_crypto import CustomCrypto\n\n\nlogger = logging.getLogger(__name__)\n\nforbidden_special_characters = \"\".join(\n    filter(lambda c: c not in \"_:/.\", string.punctuation)\n)\n\n\ndef test_make_fetchai():\n    \"\"\"Test the 'make' method for 'fetchai' crypto.\"\"\"\n    aea_ledger_fetchai = aea.crypto.registries.make_crypto(FetchAICrypto.identifier)\n\n    # calling 'make' again will give a different object.\n    aea_ledger_fetchai_1 = aea.crypto.registries.make_crypto(FetchAICrypto.identifier)\n    assert type(aea_ledger_fetchai) == type(aea_ledger_fetchai_1)\n    assert aea_ledger_fetchai.address != aea_ledger_fetchai_1\n\n\ndef test_make_ethereum():\n    \"\"\"Test the 'make' method for 'ethereum' crypto.\"\"\"\n    aea_ledger_ethereum = aea.crypto.registries.make_crypto(EthereumCrypto.identifier)\n\n    # calling 'make' again will give a different object.\n    aea_ledger_ethereum_1 = aea.crypto.registries.make_crypto(EthereumCrypto.identifier)\n    assert type(aea_ledger_ethereum) == type(aea_ledger_ethereum_1)\n    assert aea_ledger_ethereum.address != aea_ledger_ethereum_1.address\n\n\ndef test_make_cosmos():\n    \"\"\"Test the 'make' method for 'cosmos' crypto.\"\"\"\n    aea_ledger_cosmos = aea.crypto.registries.make_crypto(CosmosCrypto.identifier)\n\n    # calling 'make' again will give a different object.\n    aea_ledger_cosmos_1 = aea.crypto.registries.make_crypto(CosmosCrypto.identifier)\n    assert type(aea_ledger_cosmos) == type(aea_ledger_cosmos_1)\n    assert aea_ledger_cosmos.address != aea_ledger_cosmos_1.address\n\n\ndef test_register_custom_crypto():\n    \"\"\"Test the 'register' method with a custom crypto object.\"\"\"\n\n    aea.crypto.registries.register_crypto(\n        \"my_custom_crypto\", entry_point=\"tests.data.custom_crypto:CustomCrypto\"\n    )\n\n    assert (\n        aea.crypto.registries.crypto_registry.specs.get(\"my_custom_crypto\") is not None\n    )\n    actual_spec = aea.crypto.registries.crypto_registry.specs[\"my_custom_crypto\"]\n\n    expected_id = \"my_custom_crypto\"\n    expected_entry_point = EntryPoint(\"tests.data.custom_crypto:CustomCrypto\")\n    assert actual_spec.id == expected_id\n    assert actual_spec.entry_point == expected_entry_point\n    assert actual_spec.entry_point.import_path == expected_entry_point.import_path\n    assert actual_spec.entry_point.class_name == expected_entry_point.class_name\n\n    my_crypto = aea.crypto.registries.make_crypto(\"my_custom_crypto\")\n    assert type(my_crypto) == CustomCrypto\n\n    # calling 'make' again will give a different object.\n    my_crypto_1 = aea.crypto.registries.make_crypto(\"my_custom_crypto\")\n    assert type(my_crypto) == type(my_crypto_1)\n    assert my_crypto != my_crypto_1\n\n    aea.crypto.registries.crypto_registry.specs.pop(\"my_custom_crypto\")\n\n\ndef test_cannot_register_crypto_twice():\n    \"\"\"Test we cannot register a crypto twice.\"\"\"\n    aea.crypto.registries.register_crypto(\n        \"my_custom_crypto\", entry_point=\"tests.data.custom_crypto:CustomCrypto\"\n    )\n\n    with pytest.raises(AEAException, match=\"Cannot re-register id: 'my_custom_crypto'\"):\n        aea.crypto.registries.register_crypto(\n            \"my_custom_crypto\", entry_point=\"tests.data.custom_crypto:CustomCrypto\"\n        )\n\n    aea.crypto.registries.crypto_registry.specs.pop(\"my_custom_crypto\")\n\n\n@mock.patch(\"importlib.import_module\", side_effect=ImportError)\ndef test_import_error(*mocks):\n    \"\"\"Test import errors.\"\"\"\n    aea.crypto.registries.register_crypto(\n        \"some_crypto\", entry_point=\"path.to.module:SomeCrypto\"\n    )\n    with pytest.raises(\n        AEAException,\n        match=\"A module (.*) was specified for the item but was not found\",\n    ):\n        aea.crypto.registries.make_crypto(\"some_crypto\", module=\"some.module\")\n    aea.crypto.registries.crypto_registry.specs.pop(\"some_crypto\")\n\n\nclass TestRegisterWithMalformedId:\n    \"\"\"Test the error message when we try to register a crypto whose identifier is malformed.\"\"\"\n\n    MESSAGE_REGEX = \"Malformed .*: '.*'. It must be of the form '.*'.\"\n\n    def test_wrong_spaces(self):\n        \"\"\"Spaces not allowed in a Crypto ID.\"\"\"\n        # beginning space\n        with pytest.raises(AEAException, match=self.MESSAGE_REGEX):\n            aea.crypto.registries.register_crypto(\n                \" malformed_id\", \"path.to.module:CryptoClass\"\n            )\n\n        # trailing space\n        with pytest.raises(AEAException, match=self.MESSAGE_REGEX):\n            aea.crypto.registries.register_crypto(\n                \"malformed_id \", \"path.to.module:CryptoClass\"\n            )\n\n        # in between\n        with pytest.raises(AEAException, match=self.MESSAGE_REGEX):\n            aea.crypto.registries.register_crypto(\n                \"malformed id\", \"path.to.module:CryptoClass\"\n            )\n\n    @pytest.mark.parametrize(\"special_character\", forbidden_special_characters)\n    def test_special_characters(self, special_character):\n        \"\"\"Special characters are not allowed (only underscore).\"\"\"\n        with pytest.raises(AEAException, match=self.MESSAGE_REGEX):\n            aea.crypto.registries.register_crypto(\n                \"malformed_id\" + special_character, \"path.to.module:CryptoClass\"\n            )\n\n\nclass TestRegisterWithMalformedEntryPoint:\n    \"\"\"Test the error message when we try to register a crypto with a wrong entry point.\"\"\"\n\n    MESSAGE_REGEX = \"Malformed .*: '.*'. It must be of the form '.*'.\"\n\n    def test_wrong_spaces(self):\n        \"\"\"Spaces not allowed in a Crypto ID.\"\"\"\n        # beginning space\n        with pytest.raises(AEAException, match=self.MESSAGE_REGEX):\n            aea.crypto.registries.register_crypto(\n                \"crypto_id\", \" path.to.module:CryptoClass\"\n            )\n\n        # trailing space\n        with pytest.raises(AEAException, match=self.MESSAGE_REGEX):\n            aea.crypto.registries.register_crypto(\n                \"crypto_id\", \"path.to.module :CryptoClass\"\n            )\n\n        # in between\n        with pytest.raises(AEAException, match=self.MESSAGE_REGEX):\n            aea.crypto.registries.register_crypto(\n                \"crypto_id\", \"path.to .module:CryptoClass\"\n            )\n\n    @pytest.mark.parametrize(\"special_character\", forbidden_special_characters)\n    def test_special_characters(self, special_character):\n        \"\"\"Special characters are not allowed (only underscore).\"\"\"\n        with pytest.raises(AEAException, match=self.MESSAGE_REGEX):\n            aea.crypto.registries.register_crypto(\n                \"crypto_id\", \"path\" + special_character + \".to.module:CryptoClass\"\n            )\n"
  },
  {
    "path": "tests/test_aea/test_crypto/test_registry/test_ledger_api_registry.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests for the ledger api registry.\"\"\"\n\nimport logging\n\nimport pytest\nfrom aea_ledger_ethereum import EthereumCrypto\nfrom aea_ledger_fetchai import FetchAICrypto\n\nimport aea.crypto\n\nfrom tests.conftest import (\n    ETHEREUM_ADDRESS_ONE,\n    ETHEREUM_TESTNET_CONFIG,\n    FETCHAI_ADDRESS_ONE,\n    FETCHAI_TESTNET_CONFIG,\n)\n\n\nlogger = logging.getLogger(__name__)\n\n\n@pytest.mark.parametrize(\n    \"identifier,address,config\",\n    [\n        (FetchAICrypto.identifier, FETCHAI_ADDRESS_ONE, FETCHAI_TESTNET_CONFIG),\n        (EthereumCrypto.identifier, ETHEREUM_ADDRESS_ONE, ETHEREUM_TESTNET_CONFIG),\n    ],\n)\ndef test_make_ledger_apis(identifier, address, config):\n    \"\"\"Test the 'make' method for ledger api.\"\"\"\n    api = aea.crypto.registries.make_ledger_api(identifier, **config)\n\n    # minimal functional test - comprehensive tests on ledger APIs are located in another module\n    balance_1 = api.get_balance(address)\n    balance_2 = api.get_balance(address)\n    assert balance_1 == balance_2\n"
  },
  {
    "path": "tests/test_aea/test_crypto/test_registry/test_misc.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains misc tests for the registry (crypto/ledger_api/contract).\"\"\"\n\nimport logging\n\nimport pytest\n\nfrom aea.crypto.registries.base import Registry\nfrom aea.exceptions import AEAException\n\n\nlogger = logging.getLogger(__name__)\n\n\n@pytest.mark.parametrize(\n    \"current_id,is_valid\",\n    [\n        (\"a\", True),\n        (\"_\", True),\n        (\"0\", False),\n        (\"_0\", True),\n        (\"-\", False),\n        (\"ABCDE\", True),\n        (\"author/package:0.1.0\", True),\n        (\"author/package:0.1.\", False),\n        (\"0author/package:0.1.0\", False),\n    ],\n)\ndef test_validation_item_id(current_id, is_valid):\n    \"\"\"Test validation of item id id.\"\"\"\n    registry = Registry()\n    entrypoint = \"some_entrypoint:SomeEntrypoint\"\n    if is_valid:\n        registry.register(current_id, entry_point=entrypoint)\n    else:\n        with pytest.raises(\n            AEAException,\n            match=rf\"Malformed ItemId: '{current_id}'\\. It must be of the form .*\\.\",\n        ):\n            registry.register(current_id, entry_point=entrypoint)\n"
  },
  {
    "path": "tests/test_aea/test_crypto/test_wallet.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests of the wallet module.\"\"\"\n\nfrom unittest import TestCase\n\nimport pytest\nfrom aea_ledger_cosmos import CosmosCrypto\nfrom aea_ledger_ethereum import EthereumCrypto\nfrom aea_ledger_fetchai import FetchAICrypto\n\nfrom aea.crypto.wallet import Wallet\nfrom aea.exceptions import AEAException\n\nfrom tests.conftest import (\n    COSMOS_PRIVATE_KEY_PATH,\n    ETHEREUM_PRIVATE_KEY_PATH,\n    FETCHAI_PRIVATE_KEY_PATH,\n)\n\n\ndef test_wallet_initialisation_error():\n    \"\"\"Test the value error when we initialise the wallet.\"\"\"\n    with pytest.raises(AEAException):\n        Wallet({\"Test\": \"test\"})\n\n\nclass WalletTestCase(TestCase):\n    \"\"\"Test case for Wallet class.\"\"\"\n\n    def test_wallet_init_positive(self):\n        \"\"\"Test Wallet init positive result.\"\"\"\n        private_key_paths = {\n            EthereumCrypto.identifier: ETHEREUM_PRIVATE_KEY_PATH,\n            FetchAICrypto.identifier: FETCHAI_PRIVATE_KEY_PATH,\n            CosmosCrypto.identifier: COSMOS_PRIVATE_KEY_PATH,\n        }\n        Wallet(private_key_paths)\n\n    def test_wallet_init_bad_id(self):\n        \"\"\"Test Wallet init unsupported private key paths identifier.\"\"\"\n        private_key_paths = {\"unknown_id\": \"path1\"}\n        with self.assertRaises(AEAException):\n            Wallet(private_key_paths)\n\n    def test_wallet_init_bad_paths(self):\n        \"\"\"Test Wallet init with bad paths to private keys\"\"\"\n        private_key_paths = {FetchAICrypto.identifier: \"this_path_does_not_exists\"}\n        with self.assertRaises(FileNotFoundError):\n            Wallet(private_key_paths)\n\n    def test_wallet_crypto_objects_positive(self):\n        \"\"\"Test Wallet.crypto_objects init positive result.\"\"\"\n        private_key_paths = {\n            EthereumCrypto.identifier: ETHEREUM_PRIVATE_KEY_PATH,\n            FetchAICrypto.identifier: FETCHAI_PRIVATE_KEY_PATH,\n        }\n        wallet = Wallet(private_key_paths)\n        crypto_objects = wallet.crypto_objects\n        self.assertTupleEqual(\n            tuple(crypto_objects), (EthereumCrypto.identifier, FetchAICrypto.identifier)\n        )\n\n    def test_wallet_public_keys_positive(self):\n        \"\"\"Test Wallet.public_keys init positive result.\"\"\"\n        private_key_paths = {\n            EthereumCrypto.identifier: ETHEREUM_PRIVATE_KEY_PATH,\n            FetchAICrypto.identifier: FETCHAI_PRIVATE_KEY_PATH,\n        }\n        wallet = Wallet(private_key_paths)\n        public_keys = wallet.public_keys\n        self.assertTupleEqual(\n            tuple(public_keys), (EthereumCrypto.identifier, FetchAICrypto.identifier)\n        )\n\n    def test_wallet_addresses_positive(self):\n        \"\"\"Test Wallet.addresses init positive result.\"\"\"\n        private_key_paths = {\n            EthereumCrypto.identifier: ETHEREUM_PRIVATE_KEY_PATH,\n            FetchAICrypto.identifier: FETCHAI_PRIVATE_KEY_PATH,\n        }\n        wallet = Wallet(private_key_paths)\n        addresses = wallet.addresses\n        self.assertTupleEqual(\n            tuple(addresses), (EthereumCrypto.identifier, FetchAICrypto.identifier)\n        )\n\n    def test_wallet_private_keys_positive(self):\n        \"\"\"Test Wallet.private_keys init positive result.\"\"\"\n        private_key_paths = {\n            EthereumCrypto.identifier: ETHEREUM_PRIVATE_KEY_PATH,\n            FetchAICrypto.identifier: FETCHAI_PRIVATE_KEY_PATH,\n        }\n        wallet = Wallet(private_key_paths)\n        private_keys = wallet.private_keys\n        self.assertTupleEqual(\n            tuple(private_keys), (EthereumCrypto.identifier, FetchAICrypto.identifier)\n        )\n\n    def test_wallet_cryptos_positive(self):\n        \"\"\"Test Wallet.main_cryptos and connection cryptos init positive result.\"\"\"\n        private_key_paths = {\n            EthereumCrypto.identifier: ETHEREUM_PRIVATE_KEY_PATH,\n            FetchAICrypto.identifier: FETCHAI_PRIVATE_KEY_PATH,\n        }\n        connection_private_key_paths = {\n            EthereumCrypto.identifier: ETHEREUM_PRIVATE_KEY_PATH,\n            FetchAICrypto.identifier: FETCHAI_PRIVATE_KEY_PATH,\n        }\n        wallet = Wallet(private_key_paths, connection_private_key_paths)\n        assert len(wallet.main_cryptos.crypto_objects) == len(\n            wallet.connection_cryptos.crypto_objects\n        ), \"Incorrect amount of cryptos\"\n\n    def test_wallet_sign_message_positive(self):\n        \"\"\"Test Wallet.sign_message positive result.\"\"\"\n        private_key_paths = {\n            EthereumCrypto.identifier: ETHEREUM_PRIVATE_KEY_PATH,\n            FetchAICrypto.identifier: FETCHAI_PRIVATE_KEY_PATH,\n        }\n        wallet = Wallet(private_key_paths)\n        signature = wallet.sign_message(\n            EthereumCrypto.identifier, message=b\"some message\"\n        )\n        assert type(signature) == str and int(\n            signature, 16\n        ), \"No signature present or not hexadecimal\"\n\n    def test_wallet_sign_message_negative(self):\n        \"\"\"Test Wallet.sign_message negative result.\"\"\"\n        private_key_paths = {\n            EthereumCrypto.identifier: ETHEREUM_PRIVATE_KEY_PATH,\n            FetchAICrypto.identifier: FETCHAI_PRIVATE_KEY_PATH,\n        }\n        wallet = Wallet(private_key_paths)\n        signature = wallet.sign_message(\"unknown id\", message=b\"some message\")\n        assert signature is None, \"Signature should be none\"\n\n    def test_wallet_sign_transaction_positive(self):\n        \"\"\"Test Wallet.sign_transaction positive result.\"\"\"\n        private_key_paths = {\n            EthereumCrypto.identifier: ETHEREUM_PRIVATE_KEY_PATH,\n            FetchAICrypto.identifier: FETCHAI_PRIVATE_KEY_PATH,\n        }\n        wallet = Wallet(private_key_paths)\n        signed_transaction = wallet.sign_transaction(\n            EthereumCrypto.identifier,\n            transaction={\"gasPrice\": 50, \"nonce\": 10, \"gas\": 10},\n        )\n        assert type(signed_transaction) == dict, \"No signed transaction returned\"\n\n    def test_wallet_sign_transaction_negative(self):\n        \"\"\"Test Wallet.sign_transaction negative result.\"\"\"\n        private_key_paths = {\n            EthereumCrypto.identifier: ETHEREUM_PRIVATE_KEY_PATH,\n            FetchAICrypto.identifier: FETCHAI_PRIVATE_KEY_PATH,\n        }\n        wallet = Wallet(private_key_paths)\n        signed_transaction = wallet.sign_transaction(\n            \"unknown id\", transaction={\"this is my tx\": \"here\"}\n        )\n        assert signed_transaction is None, \"Signed transaction should be none\"\n"
  },
  {
    "path": "tests/test_aea/test_decision_maker/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains tests for decision_maker.\"\"\"\n"
  },
  {
    "path": "tests/test_aea/test_decision_maker/test_default.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains tests for decision_maker.\"\"\"\n\nimport pytest\nfrom aea_ledger_cosmos import CosmosCrypto\nfrom aea_ledger_ethereum import EthereumCrypto\nfrom aea_ledger_fetchai import FetchAICrypto\n\nfrom aea.configurations.base import PublicId\nfrom aea.crypto.registries import make_crypto, make_ledger_api\nfrom aea.crypto.wallet import Wallet\nfrom aea.decision_maker.base import DecisionMaker\nfrom aea.decision_maker.default import DecisionMakerHandler\nfrom aea.helpers.transaction.base import (\n    RawMessage,\n    RawTransaction,\n    SignedMessage,\n    Terms,\n)\nfrom aea.identity.base import Identity\nfrom aea.protocols.base import Address, Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\n\nfrom packages.fetchai.protocols.signing.dialogues import SigningDialogue\nfrom packages.fetchai.protocols.signing.dialogues import (\n    SigningDialogues as BaseSigningDialogues,\n)\nfrom packages.fetchai.protocols.signing.message import SigningMessage\n\nfrom tests.conftest import (\n    COSMOS_PRIVATE_KEY_PATH,\n    ETHEREUM_PRIVATE_KEY_PATH,\n    FETCHAI_PRIVATE_KEY_PATH,\n    FETCHAI_TESTNET_CONFIG,\n    MAX_FLAKY_RERUNS,\n    get_wealth_if_needed,\n)\n\n\nclass SigningDialogues(BaseSigningDialogues):\n    \"\"\"This class keeps track of all oef_search dialogues.\"\"\"\n\n    def __init__(self, self_address: Address) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param self_address: the address of the entity for whom dialogues are maintained\n        :return: None\n        \"\"\"\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return SigningDialogue.Role.SKILL\n\n        BaseSigningDialogues.__init__(\n            self,\n            self_address=self_address,\n            role_from_first_message=role_from_first_message,\n            dialogue_class=SigningDialogue,\n        )\n\n\nclass BaseTestDecisionMaker:\n    \"\"\"Test the decision maker.\"\"\"\n\n    decision_maker_handler_cls = DecisionMakerHandler\n    decision_maker_cls = DecisionMaker\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Initialise the decision maker.\"\"\"\n        cls.wallet = Wallet(\n            {\n                CosmosCrypto.identifier: COSMOS_PRIVATE_KEY_PATH,\n                EthereumCrypto.identifier: ETHEREUM_PRIVATE_KEY_PATH,\n                FetchAICrypto.identifier: FETCHAI_PRIVATE_KEY_PATH,\n            }\n        )\n        cls.agent_name = \"test\"\n        cls.identity = Identity(\n            cls.agent_name,\n            addresses=cls.wallet.addresses,\n            public_keys=cls.wallet.public_keys,\n            default_address_key=FetchAICrypto.identifier,\n        )\n        cls.config = {}\n        cls.decision_maker_handler = cls.decision_maker_handler_cls(\n            identity=cls.identity, wallet=cls.wallet, config=cls.config\n        )\n        cls.decision_maker = cls.decision_maker_cls(cls.decision_maker_handler)\n\n        cls.tx_sender_addr = \"agent_1\"\n        cls.tx_counterparty_addr = \"pk\"\n        cls.info = {\"some_info_key\": \"some_info_value\"}\n        cls.ledger_id = FetchAICrypto.identifier\n\n        cls.decision_maker.start()\n\n    def test_decision_maker_config(self):\n        \"\"\"Test config property.\"\"\"\n        assert self.decision_maker_handler.config == self.config\n\n    def test_decision_maker_execute_w_wrong_input(self):\n        \"\"\"Test the execute method with wrong input.\"\"\"\n        with pytest.raises(ValueError):\n            self.decision_maker.message_in_queue.put_nowait(\"wrong input\")\n        with pytest.raises(ValueError):\n            self.decision_maker.message_in_queue.put(\"wrong input\")\n\n    def test_decision_maker_queue_access_not_permitted(self):\n        \"\"\"Test the in queue of the decision maker can not be accessed.\"\"\"\n        with pytest.raises(ValueError):\n            self.decision_maker.message_in_queue.get()\n        with pytest.raises(ValueError):\n            self.decision_maker.message_in_queue.get_nowait()\n        with pytest.raises(ValueError):\n            self.decision_maker.message_in_queue.protected_get(\n                access_code=\"some_invalid_code\"\n            )\n\n    @pytest.mark.flaky(reruns=MAX_FLAKY_RERUNS)\n    def test_handle_tx_signing_fetchai(self):\n        \"\"\"Test tx signing for fetchai.\"\"\"\n        fetchai_api = make_ledger_api(\n            FetchAICrypto.identifier, **FETCHAI_TESTNET_CONFIG\n        )\n        sender_address = self.wallet.addresses[\"fetchai\"]\n        fc2 = make_crypto(FetchAICrypto.identifier)\n\n        get_wealth_if_needed(sender_address, fetchai_api)\n\n        amount = 10000\n        transfer_transaction = fetchai_api.get_transfer_transaction(\n            sender_address=sender_address,\n            destination_address=fc2.address,\n            amount=amount,\n            tx_fee=1000,\n            tx_nonce=\"something\",\n        )\n        signing_dialogues = SigningDialogues(\n            str(PublicId(\"author\", \"a_skill\", \"0.1.0\"))\n        )\n        signing_msg = SigningMessage(\n            performative=SigningMessage.Performative.SIGN_TRANSACTION,\n            dialogue_reference=signing_dialogues.new_self_initiated_dialogue_reference(),\n            terms=Terms(\n                ledger_id=FetchAICrypto.identifier,\n                sender_address=\"pk1\",\n                counterparty_address=\"pk2\",\n                amount_by_currency_id={\"FET\": -1},\n                is_sender_payable_tx_fee=True,\n                quantities_by_good_id={\"good_id\": 10},\n                nonce=\"transaction nonce\",\n            ),\n            raw_transaction=RawTransaction(\n                FetchAICrypto.identifier, transfer_transaction\n            ),\n        )\n        signing_dialogue = signing_dialogues.create_with_message(\n            \"decision_maker\", signing_msg\n        )\n        assert signing_dialogue is not None\n        self.decision_maker.message_in_queue.put_nowait(signing_msg)\n        signing_msg_response = self.decision_maker.message_out_queue.get(timeout=2)\n        recovered_dialogue = signing_dialogues.update(signing_msg_response)\n        assert recovered_dialogue is not None and recovered_dialogue == signing_dialogue\n        assert (\n            signing_msg_response.performative\n            == SigningMessage.Performative.SIGNED_TRANSACTION\n        )\n        assert type(signing_msg_response.signed_transaction.body) == dict\n\n    def test_handle_tx_signing_ethereum(self):\n        \"\"\"Test tx signing for ethereum.\"\"\"\n        tx = {\"gasPrice\": 30, \"nonce\": 1, \"gas\": 20000}\n        signing_dialogues = SigningDialogues(\n            str(PublicId(\"author\", \"a_skill\", \"0.1.0\"))\n        )\n        signing_msg = SigningMessage(\n            performative=SigningMessage.Performative.SIGN_TRANSACTION,\n            dialogue_reference=signing_dialogues.new_self_initiated_dialogue_reference(),\n            terms=Terms(\n                ledger_id=EthereumCrypto.identifier,\n                sender_address=\"pk1\",\n                counterparty_address=\"pk2\",\n                amount_by_currency_id={\"FET\": -1},\n                is_sender_payable_tx_fee=True,\n                quantities_by_good_id={\"good_id\": 10},\n                nonce=\"transaction nonce\",\n            ),\n            raw_transaction=RawTransaction(EthereumCrypto.identifier, tx),\n        )\n        signing_dialogue = signing_dialogues.create_with_message(\n            \"decision_maker\", signing_msg\n        )\n        assert signing_dialogue is not None\n        self.decision_maker.message_in_queue.put_nowait(signing_msg)\n        signing_msg_response = self.decision_maker.message_out_queue.get(timeout=2)\n        recovered_dialogue = signing_dialogues.update(signing_msg_response)\n        assert recovered_dialogue is not None and recovered_dialogue == signing_dialogue\n        assert (\n            signing_msg_response.performative\n            == SigningMessage.Performative.SIGNED_TRANSACTION\n        )\n        assert type(signing_msg_response.signed_transaction.body) == dict\n\n    def test_handle_tx_signing_unknown(self):\n        \"\"\"Test tx signing for unknown.\"\"\"\n        tx = {}\n        signing_dialogues = SigningDialogues(\n            str(PublicId(\"author\", \"a_skill\", \"0.1.0\"))\n        )\n        signing_msg = SigningMessage(\n            performative=SigningMessage.Performative.SIGN_TRANSACTION,\n            dialogue_reference=signing_dialogues.new_self_initiated_dialogue_reference(),\n            terms=Terms(\n                ledger_id=\"unknown\",\n                sender_address=\"pk1\",\n                counterparty_address=\"pk2\",\n                amount_by_currency_id={\"FET\": -1},\n                is_sender_payable_tx_fee=True,\n                quantities_by_good_id={\"good_id\": 10},\n                nonce=\"transaction nonce\",\n            ),\n            raw_transaction=RawTransaction(\"unknown\", tx),\n        )\n        signing_dialogue = signing_dialogues.create_with_message(\n            \"decision_maker\", signing_msg\n        )\n        assert signing_dialogue is not None\n        self.decision_maker.message_in_queue.put_nowait(signing_msg)\n        signing_msg_response = self.decision_maker.message_out_queue.get(timeout=2)\n        recovered_dialogue = signing_dialogues.update(signing_msg_response)\n        assert recovered_dialogue is not None and recovered_dialogue == signing_dialogue\n        assert signing_msg_response.performative == SigningMessage.Performative.ERROR\n        assert (\n            signing_msg_response.error_code\n            == SigningMessage.ErrorCode.UNSUCCESSFUL_TRANSACTION_SIGNING\n        )\n\n    def test_handle_message_signing_fetchai(self):\n        \"\"\"Test message signing for fetchai.\"\"\"\n        message = b\"0x11f3f9487724404e3a1fb7252a322656b90ba0455a2ca5fcdcbe6eeee5f8126d\"\n        signing_dialogues = SigningDialogues(\n            str(PublicId(\"author\", \"a_skill\", \"0.1.0\"))\n        )\n        signing_msg = SigningMessage(\n            performative=SigningMessage.Performative.SIGN_MESSAGE,\n            dialogue_reference=signing_dialogues.new_self_initiated_dialogue_reference(),\n            terms=Terms(\n                ledger_id=FetchAICrypto.identifier,\n                sender_address=\"pk1\",\n                counterparty_address=\"pk2\",\n                amount_by_currency_id={\"FET\": -1},\n                is_sender_payable_tx_fee=True,\n                quantities_by_good_id={\"good_id\": 10},\n                nonce=\"transaction nonce\",\n            ),\n            raw_message=RawMessage(FetchAICrypto.identifier, message),\n        )\n        signing_dialogue = signing_dialogues.create_with_message(\n            \"decision_maker\", signing_msg\n        )\n        assert signing_dialogue is not None\n        self.decision_maker.message_in_queue.put_nowait(signing_msg)\n        signing_msg_response = self.decision_maker.message_out_queue.get(timeout=2)\n        recovered_dialogue = signing_dialogues.update(signing_msg_response)\n        assert recovered_dialogue is not None and recovered_dialogue == signing_dialogue\n        assert (\n            signing_msg_response.performative\n            == SigningMessage.Performative.SIGNED_MESSAGE\n        )\n        assert type(signing_msg_response.signed_message) == SignedMessage\n\n    def test_handle_message_signing_ethereum(self):\n        \"\"\"Test message signing for ethereum.\"\"\"\n        message = b\"0x11f3f9487724404e3a1fb7252a322656b90ba0455a2ca5fcdcbe6eeee5f8126d\"\n        signing_dialogues = SigningDialogues(\n            str(PublicId(\"author\", \"a_skill\", \"0.1.0\"))\n        )\n        signing_msg = SigningMessage(\n            performative=SigningMessage.Performative.SIGN_MESSAGE,\n            dialogue_reference=signing_dialogues.new_self_initiated_dialogue_reference(),\n            terms=Terms(\n                ledger_id=EthereumCrypto.identifier,\n                sender_address=\"pk1\",\n                counterparty_address=\"pk2\",\n                amount_by_currency_id={\"FET\": -1},\n                is_sender_payable_tx_fee=True,\n                quantities_by_good_id={\"good_id\": 10},\n                nonce=\"transaction nonce\",\n            ),\n            raw_message=RawMessage(EthereumCrypto.identifier, message),\n        )\n        signing_dialogue = signing_dialogues.create_with_message(\n            \"decision_maker\", signing_msg\n        )\n        assert signing_dialogue is not None\n        self.decision_maker.message_in_queue.put_nowait(signing_msg)\n        signing_msg_response = self.decision_maker.message_out_queue.get(timeout=2)\n        recovered_dialogue = signing_dialogues.update(signing_msg_response)\n        assert recovered_dialogue is not None and recovered_dialogue == signing_dialogue\n        assert (\n            signing_msg_response.performative\n            == SigningMessage.Performative.SIGNED_MESSAGE\n        )\n        assert type(signing_msg_response.signed_message) == SignedMessage\n\n    def test_handle_message_signing_ethereum_deprecated(self):\n        \"\"\"Test message signing for ethereum deprecated.\"\"\"\n        message = b\"0x11f3f9487724404e3a1fb7252a3226\"\n        signing_dialogues = SigningDialogues(\n            str(PublicId(\"author\", \"a_skill\", \"0.1.0\"))\n        )\n        signing_msg = SigningMessage(\n            performative=SigningMessage.Performative.SIGN_MESSAGE,\n            dialogue_reference=signing_dialogues.new_self_initiated_dialogue_reference(),\n            terms=Terms(\n                ledger_id=EthereumCrypto.identifier,\n                sender_address=\"pk1\",\n                counterparty_address=\"pk2\",\n                amount_by_currency_id={\"FET\": -1},\n                is_sender_payable_tx_fee=True,\n                quantities_by_good_id={\"good_id\": 10},\n                nonce=\"transaction nonce\",\n            ),\n            raw_message=RawMessage(\n                EthereumCrypto.identifier, message, is_deprecated_mode=True\n            ),\n        )\n        signing_dialogue = signing_dialogues.create_with_message(\n            \"decision_maker\", signing_msg\n        )\n        assert signing_dialogue is not None\n        self.decision_maker.message_in_queue.put_nowait(signing_msg)\n        signing_msg_response = self.decision_maker.message_out_queue.get(timeout=2)\n        recovered_dialogue = signing_dialogues.update(signing_msg_response)\n        assert recovered_dialogue is not None and recovered_dialogue == signing_dialogue\n        assert (\n            signing_msg_response.performative\n            == SigningMessage.Performative.SIGNED_MESSAGE\n        )\n        assert type(signing_msg_response.signed_message) == SignedMessage\n        assert signing_msg_response.signed_message.is_deprecated_mode\n\n    def test_handle_message_signing_unknown_and_two_dialogues(self):\n        \"\"\"Test message signing for unknown.\"\"\"\n        message = b\"0x11f3f9487724404e3a1fb7252a322656b90ba0455a2ca5fcdcbe6eeee5f8126d\"\n        signing_dialogues = SigningDialogues(\n            str(PublicId(\"author\", \"a_skill\", \"0.1.0\"))\n        )\n        signing_msg = SigningMessage(\n            performative=SigningMessage.Performative.SIGN_MESSAGE,\n            dialogue_reference=signing_dialogues.new_self_initiated_dialogue_reference(),\n            terms=Terms(\n                ledger_id=\"unknown\",\n                sender_address=\"pk1\",\n                counterparty_address=\"pk2\",\n                amount_by_currency_id={\"FET\": -1},\n                is_sender_payable_tx_fee=True,\n                quantities_by_good_id={\"good_id\": 10},\n                nonce=\"transaction nonce\",\n            ),\n            raw_message=RawMessage(\"unknown\", message),\n        )\n        signing_dialogue = signing_dialogues.create_with_message(\n            \"decision_maker\", signing_msg\n        )\n        assert signing_dialogue is not None\n        self.decision_maker.message_in_queue.put_nowait(signing_msg)\n        signing_msg_response = self.decision_maker.message_out_queue.get(timeout=2)\n        recovered_dialogue = signing_dialogues.update(signing_msg_response)\n        assert recovered_dialogue is not None and recovered_dialogue == signing_dialogue\n        assert signing_msg_response.performative == SigningMessage.Performative.ERROR\n        assert (\n            signing_msg_response.error_code\n            == SigningMessage.ErrorCode.UNSUCCESSFUL_MESSAGE_SIGNING\n        )\n\n    def test_handle_messages_from_two_dialogues_same_agent(self):\n        \"\"\"Test message signing for unknown.\"\"\"\n        message = b\"0x11f3f9487724404e3a1fb7252a322656b90ba0455a2ca5fcdcbe6eeee5f8126d\"\n        signing_dialogues = SigningDialogues(\n            str(PublicId(\"author\", \"a_skill\", \"0.1.0\"))\n        )\n        dialogue_reference = signing_dialogues.new_self_initiated_dialogue_reference()\n        signing_msg = SigningMessage(\n            performative=SigningMessage.Performative.SIGN_MESSAGE,\n            dialogue_reference=dialogue_reference,\n            terms=Terms(\n                ledger_id=\"unknown\",\n                sender_address=\"pk1\",\n                counterparty_address=\"pk2\",\n                amount_by_currency_id={\"FET\": -1},\n                is_sender_payable_tx_fee=True,\n                quantities_by_good_id={\"good_id\": 10},\n                nonce=\"transaction nonce\",\n            ),\n            raw_message=RawMessage(\"unknown\", message),\n        )\n        signing_dialogue = signing_dialogues.create_with_message(\n            \"decision_maker\", signing_msg\n        )\n        assert signing_dialogue is not None\n        self.decision_maker.message_in_queue.put_nowait(signing_msg)\n        signing_msg_response = self.decision_maker.message_out_queue.get(timeout=2)\n        assert signing_msg_response is not None\n        signing_dialogues = SigningDialogues(\n            str(PublicId(\"author\", \"a_skill\", \"0.1.0\"))\n        )\n        signing_msg = SigningMessage(\n            performative=SigningMessage.Performative.SIGN_MESSAGE,\n            dialogue_reference=dialogue_reference,\n            terms=Terms(\n                ledger_id=\"unknown\",\n                sender_address=\"pk1\",\n                counterparty_address=\"pk2\",\n                amount_by_currency_id={\"FET\": -1},\n                is_sender_payable_tx_fee=True,\n                quantities_by_good_id={\"good_id\": 10},\n                nonce=\"transaction nonce\",\n            ),\n            raw_message=RawMessage(\"unknown\", message),\n        )\n        signing_dialogue = signing_dialogues.create_with_message(\n            \"decision_maker\", signing_msg\n        )\n        assert signing_dialogue is not None\n        with pytest.raises(Exception):\n            # Exception occurs because the same counterparty sends two identical dialogue references\n            self.decision_maker.message_out_queue.get(timeout=1)\n        # test twice; should work again even from same agent\n        signing_dialogues = SigningDialogues(\n            str(PublicId(\"author\", \"a_skill\", \"0.1.0\"))\n        )\n        signing_msg = SigningMessage(\n            performative=SigningMessage.Performative.SIGN_MESSAGE,\n            dialogue_reference=signing_dialogues.new_self_initiated_dialogue_reference(),\n            terms=Terms(\n                ledger_id=\"unknown\",\n                sender_address=\"pk1\",\n                counterparty_address=\"pk2\",\n                amount_by_currency_id={\"FET\": -1},\n                is_sender_payable_tx_fee=True,\n                quantities_by_good_id={\"good_id\": 10},\n                nonce=\"transaction nonce\",\n            ),\n            raw_message=RawMessage(\"unknown\", message),\n        )\n        signing_dialogue = signing_dialogues.create_with_message(\n            \"decision_maker\", signing_msg\n        )\n        assert signing_dialogue is not None\n        self.decision_maker.message_in_queue.put_nowait(signing_msg)\n        signing_msg_response = self.decision_maker.message_out_queue.get(timeout=2)\n        assert signing_msg_response is not None\n\n    @classmethod\n    def teardown(cls):\n        \"\"\"Tear the tests down.\"\"\"\n        cls.decision_maker.stop()\n\n\nclass TestDecisionMaker(BaseTestDecisionMaker):\n    \"\"\"Run test for default decision maker.\"\"\"\n"
  },
  {
    "path": "tests/test_aea/test_decision_maker/test_gop.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains tests for decision_maker.\"\"\"\n\nfrom queue import Queue\nfrom typing import Optional, cast\nfrom unittest import mock\n\nfrom aea_ledger_cosmos import CosmosCrypto\nfrom aea_ledger_ethereum import EthereumCrypto\nfrom aea_ledger_fetchai import FetchAICrypto\n\nimport aea\nimport aea.decision_maker.gop\nfrom aea.crypto.wallet import Wallet\nfrom aea.decision_maker.base import DecisionMaker\nfrom aea.decision_maker.gop import DecisionMakerHandler\nfrom aea.identity.base import Identity\nfrom aea.protocols.base import Address, Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\n\nfrom packages.fetchai.protocols.signing.dialogues import SigningDialogue\nfrom packages.fetchai.protocols.signing.dialogues import (\n    SigningDialogues as BaseSigningDialogues,\n)\nfrom packages.fetchai.protocols.state_update.dialogues import StateUpdateDialogue\nfrom packages.fetchai.protocols.state_update.dialogues import (\n    StateUpdateDialogues as BaseStateUpdateDialogues,\n)\nfrom packages.fetchai.protocols.state_update.message import StateUpdateMessage\n\nfrom tests.conftest import (\n    COSMOS_PRIVATE_KEY_PATH,\n    ETHEREUM_PRIVATE_KEY_PATH,\n    FETCHAI_PRIVATE_KEY_PATH,\n)\nfrom tests.test_aea.test_decision_maker.test_default import (\n    BaseTestDecisionMaker as BaseTestDecisionMakerDefault,\n)\n\n\nclass SigningDialogues(BaseSigningDialogues):\n    \"\"\"This class keeps track of all oef_search dialogues.\"\"\"\n\n    def __init__(self, self_address: Address) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param self_address: the address of the entity for whom dialogues are maintained\n        :return: None\n        \"\"\"\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return SigningDialogue.Role.SKILL\n\n        BaseSigningDialogues.__init__(\n            self,\n            self_address=self_address,\n            role_from_first_message=role_from_first_message,\n            dialogue_class=SigningDialogue,\n        )\n\n\nclass StateUpdateDialogues(BaseStateUpdateDialogues):\n    \"\"\"This class keeps track of all oef_search dialogues.\"\"\"\n\n    def __init__(self, self_address: Address) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param self_address: the address of the entity for whom dialogues are maintained\n        :return: None\n        \"\"\"\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return StateUpdateDialogue.Role.DECISION_MAKER\n\n        BaseStateUpdateDialogues.__init__(\n            self,\n            self_address=self_address,\n            role_from_first_message=role_from_first_message,\n        )\n\n\nclass TestDecisionMaker:\n    \"\"\"Test the decision maker.\"\"\"\n\n    @classmethod\n    def _patch_logger(cls):\n        cls.patch_logger_warning = mock.patch.object(\n            aea.decision_maker.gop._default_logger, \"warning\"\n        )\n        cls.mocked_logger_warning = cls.patch_logger_warning.__enter__()\n\n    @classmethod\n    def _unpatch_logger(cls):\n        cls.mocked_logger_warning.__exit__()\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Initialise the decision maker.\"\"\"\n        cls._patch_logger()\n        cls.wallet = Wallet(\n            {\n                CosmosCrypto.identifier: COSMOS_PRIVATE_KEY_PATH,\n                EthereumCrypto.identifier: ETHEREUM_PRIVATE_KEY_PATH,\n                FetchAICrypto.identifier: FETCHAI_PRIVATE_KEY_PATH,\n            }\n        )\n        cls.agent_name = \"test\"\n        cls.identity = Identity(\n            cls.agent_name,\n            addresses=cls.wallet.addresses,\n            public_keys=cls.wallet.public_keys,\n            default_address_key=FetchAICrypto.identifier,\n        )\n        cls.decision_maker_handler = DecisionMakerHandler(\n            identity=cls.identity, wallet=cls.wallet, config={}\n        )\n        cls.decision_maker = DecisionMaker(cls.decision_maker_handler)\n\n        cls.tx_sender_addr = \"agent_1\"\n        cls.tx_counterparty_addr = \"pk\"\n        cls.info = {\"some_info_key\": \"some_info_value\"}\n        cls.ledger_id = FetchAICrypto.identifier\n\n        cls.decision_maker.start()\n\n    def test_properties(self):\n        \"\"\"Test the properties of the decision maker.\"\"\"\n        assert isinstance(self.decision_maker.message_in_queue, Queue)\n        assert isinstance(self.decision_maker.message_out_queue, Queue)\n\n    def test_decision_maker_handle_state_update_initialize_and_apply(self):\n        \"\"\"Test the handle method for a stateUpdate message with Initialize and Apply performative.\"\"\"\n        good_holdings = {\"good_id\": 2}\n        currency_holdings = {\"FET\": 100}\n        utility_params = {\"good_id\": 20.0}\n        exchange_params = {\"FET\": 10.0}\n        currency_deltas = {\"FET\": -10}\n        good_deltas = {\"good_id\": 1}\n\n        state_update_dialogues = StateUpdateDialogues(\"agent\")\n        state_update_message_1 = StateUpdateMessage(\n            performative=StateUpdateMessage.Performative.INITIALIZE,\n            dialogue_reference=state_update_dialogues.new_self_initiated_dialogue_reference(),\n            amount_by_currency_id=currency_holdings,\n            quantities_by_good_id=good_holdings,\n            exchange_params_by_currency_id=exchange_params,\n            utility_params_by_good_id=utility_params,\n        )\n        state_update_dialogue = cast(\n            Optional[StateUpdateDialogue],\n            state_update_dialogues.create_with_message(\n                \"decision_maker\", state_update_message_1\n            ),\n        )\n        assert state_update_dialogue is not None, \"StateUpdateDialogue not created\"\n        self.decision_maker.handle(state_update_message_1)\n        assert (\n            self.decision_maker_handler.context.ownership_state.amount_by_currency_id\n            is not None\n        )\n        assert (\n            self.decision_maker_handler.context.ownership_state.quantities_by_good_id\n            is not None\n        )\n        assert (\n            self.decision_maker_handler.context.preferences.exchange_params_by_currency_id\n            is not None\n        )\n        assert (\n            self.decision_maker_handler.context.preferences.utility_params_by_good_id\n            is not None\n        )\n\n        state_update_message_2 = state_update_dialogue.reply(\n            performative=StateUpdateMessage.Performative.APPLY,\n            amount_by_currency_id=currency_deltas,\n            quantities_by_good_id=good_deltas,\n        )\n        self.decision_maker.handle(state_update_message_2)\n        expected_amount_by_currency_id = {\n            key: currency_holdings.get(key, 0) + currency_deltas.get(key, 0)\n            for key in set(currency_holdings) | set(currency_deltas)\n        }\n        expected_quantities_by_good_id = {\n            key: good_holdings.get(key, 0) + good_deltas.get(key, 0)\n            for key in set(good_holdings) | set(good_deltas)\n        }\n        assert (\n            self.decision_maker_handler.context.ownership_state.amount_by_currency_id\n            == expected_amount_by_currency_id\n        ), \"The amount_by_currency_id must be equal with the expected amount.\"\n        assert (\n            self.decision_maker_handler.context.ownership_state.quantities_by_good_id\n            == expected_quantities_by_good_id\n        )\n\n    @classmethod\n    def teardown(cls):\n        \"\"\"Tear the tests down.\"\"\"\n        cls._unpatch_logger()\n        cls.decision_maker.stop()\n\n\nclass TestDecisionMaker2(BaseTestDecisionMakerDefault):\n    \"\"\"Test the decision maker.\"\"\"\n\n    decision_maker_handler_cls = DecisionMakerHandler  # type: ignore\n    decision_maker_cls = DecisionMaker  # type: ignore\n\n    @classmethod\n    def _patch_logger(cls):\n        cls.patch_logger_warning = mock.patch.object(\n            aea.decision_maker.gop._default_logger, \"warning\"\n        )\n        cls.mocked_logger_warning = cls.patch_logger_warning.__enter__()\n\n    @classmethod\n    def _unpatch_logger(cls):\n        cls.mocked_logger_warning.__exit__()\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Initialise the decision maker.\"\"\"\n        super().setup()\n        cls._patch_logger()\n\n    @classmethod\n    def teardown(cls):\n        \"\"\"Tear the tests down.\"\"\"\n        cls._unpatch_logger()\n        super().teardown()\n"
  },
  {
    "path": "tests/test_aea/test_decision_maker/test_ownership_state.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains tests for decision_maker.\"\"\"\n\nimport pytest\nfrom aea_ledger_ethereum import EthereumCrypto\n\nfrom aea.decision_maker.gop import OwnershipState\nfrom aea.helpers.transaction.base import Terms\n\n\ndef test_non_initialized_ownership_state_raises_exception():\n    \"\"\"Test that non-initialized ownership state raises exception.\"\"\"\n    ownership_state = OwnershipState()\n\n    with pytest.raises(ValueError):\n        ownership_state.amount_by_currency_id\n\n    with pytest.raises(ValueError):\n        ownership_state.quantities_by_good_id\n\n\ndef test_initialisation():\n    \"\"\"Test the initialisation of the ownership_state.\"\"\"\n    currency_endowment = {\"FET\": 100}\n    good_endowment = {\"good_id\": 2}\n    ownership_state = OwnershipState()\n    ownership_state.set(\n        amount_by_currency_id=currency_endowment,\n        quantities_by_good_id=good_endowment,\n    )\n    assert ownership_state.amount_by_currency_id is not None\n    assert ownership_state.quantities_by_good_id is not None\n    assert ownership_state.is_initialized\n\n\ndef test_is_affordable_for_uninitialized():\n    \"\"\"Test the initialisation of the ownership_state.\"\"\"\n    ownership_state = OwnershipState()\n    buyer_terms = Terms(\n        ledger_id=EthereumCrypto.identifier,\n        sender_address=\"pk1\",\n        counterparty_address=\"pk2\",\n        amount_by_currency_id={\"FET\": -1},\n        is_sender_payable_tx_fee=True,\n        quantities_by_good_id={\"good_id\": 10},\n        nonce=\"transaction nonce\",\n    )\n    assert ownership_state.is_affordable(\n        terms=buyer_terms\n    ), \"Any transaction should be classed as affordable.\"\n\n\nclass TestOwnershipState:\n    \"\"\"Test the OwnershipState module.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Setup class for test case.\"\"\"\n        cls.buyer_terms = Terms(\n            ledger_id=EthereumCrypto.identifier,\n            sender_address=\"pk1\",\n            counterparty_address=\"pk2\",\n            amount_by_currency_id={\"FET\": -1},\n            is_sender_payable_tx_fee=True,\n            quantities_by_good_id={\"good_id\": 10},\n            nonce=\"transaction nonce\",\n        )\n        cls.neutral_terms = Terms(\n            ledger_id=EthereumCrypto.identifier,\n            sender_address=\"pk1\",\n            counterparty_address=\"pk2\",\n            amount_by_currency_id={\"FET\": 0},\n            is_sender_payable_tx_fee=True,\n            quantities_by_good_id={\"good_id\": 0},\n            nonce=\"transaction nonce\",\n        )\n        cls.malformed_terms = Terms(\n            ledger_id=EthereumCrypto.identifier,\n            sender_address=\"pk1\",\n            counterparty_address=\"pk2\",\n            amount_by_currency_id={\"FET\": -10},\n            is_sender_payable_tx_fee=True,\n            quantities_by_good_id={\"good_id\": 10},\n            nonce=\"transaction nonce\",\n        )\n        cls.malformed_terms._amount_by_currency_id = {\"FET\": 10}\n        cls.seller_terms = Terms(\n            ledger_id=EthereumCrypto.identifier,\n            sender_address=\"pk1\",\n            counterparty_address=\"pk2\",\n            amount_by_currency_id={\"FET\": 1},\n            is_sender_payable_tx_fee=True,\n            quantities_by_good_id={\"good_id\": -10},\n            nonce=\"transaction nonce\",\n        )\n\n    def test_transaction_is_affordable_agent_is_buyer(self):\n        \"\"\"Check if the agent has the money to cover the sender_amount (the agent=sender is the buyer).\"\"\"\n        currency_endowment = {\"FET\": 100}\n        good_endowment = {\"good_id\": 20}\n        ownership_state = OwnershipState()\n        ownership_state.set(\n            amount_by_currency_id=currency_endowment,\n            quantities_by_good_id=good_endowment,\n        )\n        assert ownership_state.is_affordable(\n            terms=self.buyer_terms\n        ), \"We should have the money for the transaction!\"\n\n    def test_transaction_is_affordable_there_is_no_wealth(self):\n        \"\"\"Reject the transaction when there is no wealth exchange.\"\"\"\n        currency_endowment = {\"FET\": 0}\n        good_endowment = {\"good_id\": 0}\n        ownership_state = OwnershipState()\n        ownership_state.set(\n            amount_by_currency_id=currency_endowment,\n            quantities_by_good_id=good_endowment,\n        )\n        assert not ownership_state.is_affordable_transaction(\n            terms=self.buyer_terms\n        ), \"We must reject the transaction.\"\n\n    def test_transaction_is_affordable_neutral(self):\n        \"\"\"Reject the transaction when there is no wealth exchange.\"\"\"\n        currency_endowment = {\"FET\": 100}\n        good_endowment = {\"good_id\": 20}\n        ownership_state = OwnershipState()\n        ownership_state.set(\n            amount_by_currency_id=currency_endowment,\n            quantities_by_good_id=good_endowment,\n        )\n        assert not ownership_state.is_affordable_transaction(\n            terms=self.neutral_terms\n        ), \"We must reject the transaction.\"\n\n    def test_transaction_is_affordable_malformed(self):\n        \"\"\"Reject the transaction when there is no wealth exchange.\"\"\"\n        currency_endowment = {\"FET\": 100}\n        good_endowment = {\"good_id\": 20}\n        ownership_state = OwnershipState()\n        ownership_state.set(\n            amount_by_currency_id=currency_endowment,\n            quantities_by_good_id=good_endowment,\n        )\n        assert not ownership_state.is_affordable_transaction(\n            terms=self.malformed_terms\n        ), \"We must reject the transaction.\"\n\n    def test_transaction_is_affordable_agent_is_seller(self):\n        \"\"\"Check if the agent has the goods (the agent=sender is the seller).\"\"\"\n        currency_endowment = {\"FET\": 100}\n        good_endowment = {\"good_id\": 20}\n        ownership_state = OwnershipState()\n        ownership_state.set(\n            amount_by_currency_id=currency_endowment,\n            quantities_by_good_id=good_endowment,\n        )\n        assert ownership_state.is_affordable_transaction(\n            terms=self.seller_terms\n        ), \"We must reject the transaction.\"\n\n    def test_apply(self):\n        \"\"\"Test the apply function.\"\"\"\n        currency_endowment = {\"FET\": 100}\n        good_endowment = {\"good_id\": 2}\n        ownership_state = OwnershipState()\n        ownership_state.set(\n            amount_by_currency_id=currency_endowment,\n            quantities_by_good_id=good_endowment,\n        )\n        list_of_terms = [self.buyer_terms]\n        state = ownership_state\n        new_state = ownership_state.apply_transactions(list_of_terms=list_of_terms)\n        assert (\n            state != new_state\n        ), \"after applying a list_of_terms must have a different state!\"\n\n    def test_transaction_update(self):\n        \"\"\"Test the transaction update when sending tokens.\"\"\"\n        currency_endowment = {\"FET\": 100}\n        good_endowment = {\"good_id\": 20}\n        ownership_state = OwnershipState()\n        ownership_state.set(\n            amount_by_currency_id=currency_endowment,\n            quantities_by_good_id=good_endowment,\n        )\n        assert ownership_state.amount_by_currency_id == currency_endowment\n        assert ownership_state.quantities_by_good_id == good_endowment\n        ownership_state.update(terms=self.buyer_terms)\n        expected_amount_by_currency_id = {\"FET\": 99}\n        expected_quantities_by_good_id = {\"good_id\": 30}\n        assert ownership_state.amount_by_currency_id == expected_amount_by_currency_id\n        assert ownership_state.quantities_by_good_id == expected_quantities_by_good_id\n\n    def test_transaction_update_receive(self):\n        \"\"\"Test the transaction update when receiving tokens.\"\"\"\n        currency_endowment = {\"FET\": 100}\n        good_endowment = {\"good_id\": 20}\n        ownership_state = OwnershipState()\n        ownership_state.set(\n            amount_by_currency_id=currency_endowment,\n            quantities_by_good_id=good_endowment,\n        )\n        assert ownership_state.amount_by_currency_id == currency_endowment\n        assert ownership_state.quantities_by_good_id == good_endowment\n        ownership_state.update(terms=self.seller_terms)\n        expected_amount_by_currency_id = {\"FET\": 101}\n        expected_quantities_by_good_id = {\"good_id\": 10}\n        assert ownership_state.amount_by_currency_id == expected_amount_by_currency_id\n        assert ownership_state.quantities_by_good_id == expected_quantities_by_good_id\n"
  },
  {
    "path": "tests/test_aea/test_decision_maker/test_preferences.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains tests for decision_maker.\"\"\"\n\nimport copy\n\nimport pytest\nfrom aea_ledger_ethereum import EthereumCrypto\n\nfrom aea.decision_maker.gop import OwnershipState, Preferences\nfrom aea.helpers.transaction.base import Terms\n\n\ndef test_preferences_properties():\n    \"\"\"Test the properties of the preferences class.\"\"\"\n    preferences = Preferences()\n    with pytest.raises(ValueError):\n        preferences.exchange_params_by_currency_id\n    with pytest.raises(ValueError):\n        preferences.utility_params_by_good_id\n\n\ndef test_preferences_init():\n    \"\"\"Test the preferences init().\"\"\"\n    utility_params = {\"good_id\": 20.0}\n    exchange_params = {\"FET\": 10.0}\n    preferences = Preferences()\n    preferences.set(\n        exchange_params_by_currency_id=exchange_params,\n        utility_params_by_good_id=utility_params,\n    )\n    assert preferences.utility_params_by_good_id is not None\n    assert preferences.exchange_params_by_currency_id is not None\n    assert preferences.is_initialized\n    copied_preferences = copy.copy(preferences)\n    assert (\n        preferences.exchange_params_by_currency_id\n        == copied_preferences.exchange_params_by_currency_id\n    )\n    assert (\n        preferences.utility_params_by_good_id\n        == copied_preferences.utility_params_by_good_id\n    )\n\n\ndef test_logarithmic_utility():\n    \"\"\"Calculate the logarithmic utility and checks that it is not none..\"\"\"\n    utility_params = {\"good_id\": 20.0}\n    exchange_params = {\"FET\": 10.0}\n    good_holdings = {\"good_id\": 2}\n    preferences = Preferences()\n    preferences.set(\n        utility_params_by_good_id=utility_params,\n        exchange_params_by_currency_id=exchange_params,\n    )\n    log_utility = preferences.logarithmic_utility(quantities_by_good_id=good_holdings)\n    assert log_utility is not None, \"Log_utility must not be none.\"\n\n\ndef test_linear_utility():\n    \"\"\"Calculate the linear_utility and checks that it is not none.\"\"\"\n    currency_holdings = {\"FET\": 100}\n    utility_params = {\"good_id\": 20.0}\n    exchange_params = {\"FET\": 10.0}\n    preferences = Preferences()\n    preferences.set(\n        utility_params_by_good_id=utility_params,\n        exchange_params_by_currency_id=exchange_params,\n    )\n    linear_utility = preferences.linear_utility(amount_by_currency_id=currency_holdings)\n    assert linear_utility is not None, \"Linear utility must not be none.\"\n\n\ndef test_utility():\n    \"\"\"Calculate the score.\"\"\"\n    utility_params = {\"good_id\": 20.0}\n    exchange_params = {\"FET\": 10.0}\n    currency_holdings = {\"FET\": 100}\n    good_holdings = {\"good_id\": 2}\n    preferences = Preferences()\n    preferences.set(\n        utility_params_by_good_id=utility_params,\n        exchange_params_by_currency_id=exchange_params,\n    )\n    score = preferences.utility(\n        quantities_by_good_id=good_holdings,\n        amount_by_currency_id=currency_holdings,\n    )\n    linear_utility = preferences.linear_utility(amount_by_currency_id=currency_holdings)\n    log_utility = preferences.logarithmic_utility(quantities_by_good_id=good_holdings)\n    assert (\n        score == log_utility + linear_utility\n    ), \"The score must be equal to the sum of log_utility and linear_utility.\"\n\n\ndef test_marginal_utility():\n    \"\"\"Test the marginal utility.\"\"\"\n    currency_holdings = {\"FET\": 100}\n    utility_params = {\"good_id\": 20.0}\n    exchange_params = {\"FET\": 10.0}\n    good_holdings = {\"good_id\": 2}\n    preferences = Preferences()\n    preferences.set(\n        utility_params_by_good_id=utility_params,\n        exchange_params_by_currency_id=exchange_params,\n    )\n    delta_good_holdings = {\"good_id\": 1}\n    delta_currency_holdings = {\"FET\": -5}\n    ownership_state = OwnershipState()\n    ownership_state.set(\n        amount_by_currency_id=currency_holdings,\n        quantities_by_good_id=good_holdings,\n    )\n    marginal_utility = preferences.marginal_utility(\n        ownership_state=ownership_state,\n        delta_quantities_by_good_id=delta_good_holdings,\n        delta_amount_by_currency_id=delta_currency_holdings,\n    )\n    assert marginal_utility is not None, \"Marginal utility must not be none.\"\n\n\ndef test_score_diff_from_transaction():\n    \"\"\"Test the difference between the scores.\"\"\"\n    good_holdings = {\"good_id\": 2}\n    currency_holdings = {\"FET\": 100}\n    utility_params = {\"good_id\": 20.0}\n    exchange_params = {\"FET\": 10.0}\n    ownership_state = OwnershipState()\n    ownership_state.set(\n        amount_by_currency_id=currency_holdings, quantities_by_good_id=good_holdings\n    )\n    preferences = Preferences()\n    preferences.set(\n        utility_params_by_good_id=utility_params,\n        exchange_params_by_currency_id=exchange_params,\n    )\n    terms = Terms(\n        ledger_id=EthereumCrypto.identifier,\n        sender_address=\"agent_1\",\n        counterparty_address=\"pk\",\n        amount_by_currency_id={\"FET\": -20},\n        is_sender_payable_tx_fee=True,\n        quantities_by_good_id={\"good_id\": 10},\n        nonce=\"transaction nonce\",\n    )\n    cur_score = preferences.utility(\n        quantities_by_good_id=good_holdings, amount_by_currency_id=currency_holdings\n    )\n    new_state = ownership_state.apply_transactions([terms])\n    new_score = preferences.utility(\n        quantities_by_good_id=new_state.quantities_by_good_id,\n        amount_by_currency_id=new_state.amount_by_currency_id,\n    )\n    diff_scores = new_score - cur_score\n    score_difference = preferences.utility_diff_from_transaction(\n        ownership_state=ownership_state, terms=terms\n    )\n    assert (\n        score_difference == diff_scores\n    ), \"The calculated difference must be equal to the return difference from the function.\"\n    assert not preferences.is_utility_enhancing(\n        ownership_state=ownership_state, terms=terms\n    ), \"Should not enhance utility.\"\n\n\ndef test_is_utility_enhancing_uninitialized():\n    \"\"\"Test is_utility_enhancing when the states are uninitialized.\"\"\"\n    ownership_state = OwnershipState()\n    preferences = Preferences()\n    terms = Terms(\n        ledger_id=EthereumCrypto.identifier,\n        sender_address=\"agent_1\",\n        counterparty_address=\"pk\",\n        amount_by_currency_id={\"FET\": -20},\n        is_sender_payable_tx_fee=True,\n        quantities_by_good_id={\"good_id\": 10},\n        nonce=\"transaction nonce\",\n    )\n    assert preferences.is_utility_enhancing(\n        ownership_state=ownership_state, terms=terms\n    ), \"Should enhance utility.\"\n"
  },
  {
    "path": "tests/test_aea/test_decision_maker/test_scaffold.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains tests for decision_maker.\"\"\"\n\nimport pytest\n\nfrom aea.decision_maker.scaffold import DecisionMakerHandler\nfrom aea.identity.base import Identity\n\n\ndef test_init_and_not_implemented():\n    \"\"\"Initialise the decision maker handler.\"\"\"\n    decision_maker_handler = DecisionMakerHandler(\n        identity=Identity(\"name\", \"address\", \"public_key\"), wallet=\"wallet\", config={}\n    )\n    with pytest.raises(NotImplementedError):\n        decision_maker_handler.handle(\"message\")\n"
  },
  {
    "path": "tests/test_aea/test_error_handler/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Test modules for the error handler.\"\"\"\n"
  },
  {
    "path": "tests/test_aea/test_error_handler/test_base.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests for the sym link module.\"\"\"\n\nimport logging\nfrom unittest.mock import Mock, patch\n\nfrom aea.error_handler.default import ErrorHandler\n\n\n_default_logger = logging.getLogger(__name__)\n\n\ndef test_config():\n    \"\"\"Test the config property.\"\"\"\n    config = {\"some\": \"config\"}\n    handler = ErrorHandler(**config)\n    assert handler.config == config\n\n\ndef test_send_unsupported_protocol():\n    \"\"\"Test the send_unsupported_protocol method.\"\"\"\n    handler = ErrorHandler()\n    envelope_mock = Mock()\n    envelope_mock.protocol_specification_id = \"1\"\n    envelope_mock.sender = \"2\"\n    envelope_mock.to = \"3\"\n    count = handler.unsupported_protocol_count\n    with patch.object(_default_logger, \"warning\") as mock_logger:\n        handler.send_unsupported_protocol(envelope_mock, _default_logger)\n        mock_logger.assert_any_call(\n            f\"Unsupported protocol: protocol_specification_id={envelope_mock.protocol_specification_id}. You might want to add a handler for a protocol implementing this specification. Sender={envelope_mock.sender}, to={envelope_mock.sender}.\"\n        )\n    assert count + 1 == handler.unsupported_protocol_count\n\n\ndef test_send_decoding_error():\n    \"\"\"Test the send_decoding_error method.\"\"\"\n    handler = ErrorHandler()\n    envelope_mock = Mock()\n    envelope_mock.protocol_specification_id = \"1\"\n    envelope_mock.sender = \"2\"\n    envelope_mock.to = \"3\"\n    count = handler.decoding_error_count\n    e = Exception(\"some\")\n    with patch.object(_default_logger, \"warning\") as mock_logger:\n        handler.send_decoding_error(envelope_mock, e, _default_logger)\n        mock_logger.assert_any_call(\n            f\"Decoding error for envelope: {envelope_mock}. Protocol_specification_id='{envelope_mock.protocol_specification_id}' and message are inconsistent. Sender={envelope_mock.sender}, to={envelope_mock.sender}. Exception={e}.\"\n        )\n    assert count + 1 == handler.decoding_error_count\n\n\ndef test_send_no_active_handler_1():\n    \"\"\"Test the send_no_active_handler method.\"\"\"\n    handler = ErrorHandler()\n    envelope_mock = Mock()\n    envelope_mock.protocol_specification_id = \"1\"\n    envelope_mock.sender = \"2\"\n    envelope_mock.to = \"3\"\n    envelope_mock.skill_id = None\n    count = handler.no_active_handler_count\n    reason = \"reason\"\n    with patch.object(_default_logger, \"warning\") as mock_logger:\n        handler.send_no_active_handler(envelope_mock, reason, _default_logger)\n        mock_logger.assert_any_call(\n            f\"Cannot handle envelope: {reason}. Sender={envelope_mock.sender}, to={envelope_mock.sender}.\"\n        )\n    assert count + 1 == handler.no_active_handler_count\n\n\ndef test_send_no_active_handler_2():\n    \"\"\"Test the send_no_active_handler method.\"\"\"\n    handler = ErrorHandler()\n    envelope_mock = Mock()\n    envelope_mock.protocol_id = \"1\"\n    envelope_mock.sender = \"2\"\n    envelope_mock.to = \"3\"\n    envelope_mock.skill_id = \"4\"\n    count = handler.no_active_handler_count\n    reason = \"reason\"\n    with patch.object(_default_logger, \"warning\") as mock_logger:\n        handler.send_no_active_handler(envelope_mock, reason, _default_logger)\n        mock_logger.assert_any_call(\n            f\"Cannot handle envelope: {reason}. Sender={envelope_mock.sender}, to={envelope_mock.sender}.\"\n        )\n    assert count + 1 == handler.no_active_handler_count\n"
  },
  {
    "path": "tests/test_aea/test_error_handler/test_scaffold.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains tests for decision_maker.\"\"\"\n\nimport pytest\n\nfrom aea.error_handler.scaffold import ErrorHandler\n\n\ndef test_scaffold_send_unsupported_protocol_raises_not_implemented_error():\n    \"\"\"Test 'send_unsupported_protocol' raises not implemented error.\"\"\"\n    with pytest.raises(NotImplementedError):\n        ErrorHandler().send_unsupported_protocol(None, None)\n\n\ndef test_scaffold_send_decoding_error_raises_not_implemented_error():\n    \"\"\"Test 'send_decoding_error' raises not implemented error.\"\"\"\n    with pytest.raises(NotImplementedError):\n        ErrorHandler().send_decoding_error(None, None, None)\n\n\ndef test_scaffold_send_no_active_handler_raises_not_implemented_error():\n    \"\"\"Test 'send_no_active_handler' raises not implemented error.\"\"\"\n    with pytest.raises(NotImplementedError):\n        ErrorHandler().send_no_active_handler(None, None, None)\n"
  },
  {
    "path": "tests/test_aea/test_exceptions.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains tests for aea exceptions.\"\"\"\n\nimport pytest\n\nfrom aea.exceptions import AEAEnforceError, _StopRuntime, enforce, parse_exception\n\n\ndef test_enforce_no_exception():\n    \"\"\"Test enforce does not throw exception if condition is True.\"\"\"\n    enforce(True, \"Error message\")\n\n\ndef test_enforce_exception():\n    \"\"\"Test enforce does throw exception if condition is False.\"\"\"\n    error_msg = \"Error message\"\n    with pytest.raises(AEAEnforceError, match=error_msg):\n        enforce(False, error_msg)\n\n\ndef test_stop_runtime():\n    \"\"\"Test thes stop runtime exception.\"\"\"\n    test = \"test string\"\n    e = _StopRuntime(test)\n    assert e.reraise == test\n\n\ndef test_parse_exception_i():\n    \"\"\"Test parse exception.\"\"\"\n\n    def exception_raise():\n        \"\"\"A function that raises an exception.\"\"\"\n        raise ValueError(\"expected\")\n\n    try:\n        exception_raise()\n    except Exception as e:\n        out = parse_exception(e)\n\n    expected = [\n        \"Traceback (most recent call last):\\n\\n\",\n        'test_exceptions.py\", line ',\n        \"in exception_raise\\n\",\n        'raise ValueError(\"expected\")\\n\\nValueError: expected\\n',\n    ]\n    assert all([string in out for string in expected])\n\n\ndef test_parse_exception_ii():\n    \"\"\"Test parse exception.\"\"\"\n\n    def exception_raise():\n        \"\"\"A function that raises an exception.\"\"\"\n        raise AEAEnforceError(\"expected\")\n\n    try:\n        exception_raise()\n    except Exception as e:\n        out = parse_exception(e)\n\n    expected = [\n        \"Traceback (most recent call last):\\n\\n\",\n        'test_exceptions.py\", line ',\n        \"in test_parse_exception_ii\\n\",\n        \"exception_raise()\\n\\n\",\n        \", line\",\n        \"in exception_raise\\n\",\n        'raise AEAEnforceError(\"expected\")\\n\\naea.exceptions.AEAEnforceError: expected\\n',\n    ]\n    assert all([string in out for string in expected])\n"
  },
  {
    "path": "tests/test_aea/test_helpers/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests for the helper module.\"\"\"\n"
  },
  {
    "path": "tests/test_aea/test_helpers/test_acn/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests for the helper.acn module.\"\"\"\n"
  },
  {
    "path": "tests/test_aea/test_helpers/test_acn/test_agent_record.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests for acn helper module.\"\"\"\n\nimport pytest\n\nfrom aea.configurations.constants import DEFAULT_LEDGER\nfrom aea.crypto.registries import make_crypto\nfrom aea.helpers.acn.agent_record import AgentRecord\nfrom aea.helpers.base import CertRequest\n\nfrom tests.conftest import _process_cert\n\n\ndef test_agent_record(change_directory):\n    \"\"\"Test signature and public key proper retrieval from a CertRequest\"\"\"\n    agent_key_1 = make_crypto(DEFAULT_LEDGER)\n    agent_key_2 = make_crypto(DEFAULT_LEDGER)\n\n    peer_public_key_1 = make_crypto(DEFAULT_LEDGER).public_key\n    peer_public_key_2 = make_crypto(DEFAULT_LEDGER).public_key\n\n    cert_path = \"test_acn_cert.txt\"\n\n    cert = CertRequest(\n        peer_public_key_1,\n        \"test_service\",\n        DEFAULT_LEDGER,\n        \"2021-01-01\",\n        \"2022-01-01\",\n        \"{public_key}\",\n        cert_path,\n    )\n    _process_cert(agent_key_1, cert, change_directory)\n\n    # success\n    agent_record = AgentRecord.from_cert_request(\n        cert, agent_key_1.address, peer_public_key_1\n    )\n    assert (\n        agent_record.address == agent_key_1.address\n        and agent_record.public_key == agent_key_1.public_key\n        and agent_record.representative_public_key == peer_public_key_1\n        and agent_record.signature == cert.get_signature()\n        and agent_record.message == cert.get_message(peer_public_key_1)\n    )\n\n    # success\n    agent_record = AgentRecord(\n        agent_key_1.address,\n        peer_public_key_1,\n        cert.identifier,\n        cert.ledger_id,\n        cert.not_before,\n        cert.not_after,\n        cert.message_format,\n        cert.get_signature(),\n    )\n    assert (\n        agent_record.address == agent_key_1.address\n        and agent_record.public_key == agent_key_1.public_key\n        and agent_record.representative_public_key == peer_public_key_1\n        and agent_record.signature == cert.get_signature()\n        and agent_record.message == cert.get_message(peer_public_key_1)\n    )\n\n    # error: wrong signer\n    with pytest.raises(\n        ValueError,\n        match=\"Invalid signature for provided representative_public_key and agent address!\",\n    ):\n        AgentRecord.from_cert_request(cert, agent_key_2.address, peer_public_key_1)\n\n    # error: wrong signer\n    with pytest.raises(\n        ValueError,\n        match=\"Invalid signature for provided representative_public_key and agent address!\",\n    ):\n        AgentRecord.from_cert_request(cert, agent_key_1.address, peer_public_key_2)\n"
  },
  {
    "path": "tests/test_aea/test_helpers/test_acn/test_uri.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests for acn helper module.\"\"\"\n\nfrom aea.helpers.acn.uri import Uri\n\n\ndef test_uri():\n    \"\"\"Test URI class\"\"\"\n    Uri(uri=\"localhost:9000\")\n    uri = Uri(host=\"localhost\", port=9000)\n    assert str(uri) == \"localhost:9000\"\n    assert uri.host == \"localhost\"\n    assert uri.port == 9000\n    Uri()\n"
  },
  {
    "path": "tests/test_aea/test_helpers/test_async_friendly_queue.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests for AsyncFriendlyQueue.\"\"\"\n\nimport asyncio\nimport time\nfrom queue import Empty\nfrom threading import Thread\n\nimport pytest\n\nfrom aea.helpers.async_friendly_queue import AsyncFriendlyQueue\n\n\ndef test_same_thread() -> None:\n    \"\"\"Test AsyncFriendlyQueue in one thread environment.\"\"\"\n    sq = AsyncFriendlyQueue()\n\n    with pytest.raises(Empty):\n        sq.get_nowait()\n\n    item = \"item\"\n    sq.put_nowait(item)\n    assert sq.get_nowait() == item\n\n\n@pytest.mark.asyncio\nasync def test_asyncio_loop() -> None:\n    \"\"\"Test AsyncFriendlyQueue inside one event loop.\"\"\"\n    sq = AsyncFriendlyQueue()\n    item = \"item\"\n    sq.put(item)\n    assert await sq.async_get() == item\n\n\ndef test_many_threads_with_asyncio() -> None:\n    \"\"\"Test AsyncFriendlyQueue wuth multiple asyncio event loop consumers in different threads.\"\"\"\n    sq = AsyncFriendlyQueue()\n    num_threads = 10\n    threads = []\n    results = []  # type: ignore\n\n    def test(sq, timeout, results):\n        loop = asyncio.new_event_loop()\n        asyncio.set_event_loop(loop)\n\n        async def wait_msg(sq, timeout, results):\n            await asyncio.wait_for(sq.async_get(), timeout)\n            results.append(\"done\")\n\n        loop.run_until_complete(wait_msg(sq, timeout, results))\n        loop.close()\n\n    for _ in range(num_threads):\n        t = Thread(target=test, args=(sq, 5, results))\n        t.daemon = True\n        t.start()\n        threads.append(t)\n\n    time.sleep(0.03)\n    for _ in range(num_threads):\n        sq.put(\"item\")\n\n    for t in threads:\n        t.join()\n\n    assert len(results) == num_threads\n"
  },
  {
    "path": "tests/test_aea/test_helpers/test_async_utils.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests for AsyncFriendlyQueue.\"\"\"\nimport asyncio\nimport time\nfrom concurrent.futures._base import CancelledError\nfrom contextlib import suppress\nfrom threading import Thread\n\nimport pytest\n\nfrom aea.helpers.async_utils import (\n    AsyncState,\n    PeriodicCaller,\n    Runnable,\n    ThreadedAsyncRunner,\n    ensure_list,\n)\n\nfrom tests.common.utils import wait_for_condition, wait_for_condition_async\n\n\ndef test_enusre_list() -> None:\n    \"\"\"Test AsyncFriendlyQueue in one thread environment.\"\"\"\n    list1 = [1, 2, 3]\n    assert ensure_list(list1) is list1\n\n    assert ensure_list(1) == [1]\n    assert ensure_list(map(lambda x: x, list1)) == list1\n\n\n@pytest.mark.asyncio\nasync def test_async_state():\n    \"\"\"Test various cases for AsyncState.\"\"\"\n    loop = asyncio.get_event_loop()\n    state = AsyncState()\n\n    # check set/get\n    value = 1\n    state.set(value)\n    assert state.get() == value\n\n    # check set/get with state property\n    value = 3\n    state.state = 3\n    assert state.state == value\n\n    # check wait/set\n    loop.call_soon(state.set, 2)\n    await state.wait(2)\n\n    # state is already set\n    await state.wait(2)\n\n\n@pytest.mark.asyncio\nasync def test_async_state_transit():\n    \"\"\"Test async state transit contextmanager.\"\"\"\n    state = AsyncState()\n    state.set(None)\n\n    with state.transit(initial=1, success=2, fail=3):\n        assert state.get() == 1\n    assert state.get() == 2\n\n    state.set(None)\n\n    with suppress(ValueError):\n        with state.transit(initial=1, success=2, fail=3):\n            assert state.get() == 1\n            raise ValueError()\n\n    assert state.get() == 3\n\n\n@pytest.mark.asyncio\nasync def test_asyncstate_with_list_of_valid_states():\n    \"\"\"Test various cases for AsyncState.\"\"\"\n    states = [1, 2, 3]\n    state = AsyncState(1, states)\n\n    state.set(2)\n    assert state.get() == 2\n\n    with pytest.raises(ValueError):\n        state.set(\"anything\")\n\n    assert state.get() == 2\n\n\n@pytest.mark.asyncio\nasync def test_asyncstate_callback():\n    \"\"\"Test various cases for AsyncState.callback.\"\"\"\n    state = AsyncState()\n\n    called = False\n\n    def callback_err(state):\n        raise Exception(\"expected\")\n\n    def callback(state):\n        nonlocal called\n        called = True\n\n    state.add_callback(callback_err)\n    state.add_callback(callback)\n\n    state.set(2)\n    assert state.get() == 2\n    assert called\n\n\n@pytest.mark.asyncio\nasync def test_periodic_caller_start_stop():\n    \"\"\"Test start stop calls for PeriodicCaller.\"\"\"\n    called = 0\n\n    def callback():\n        nonlocal called\n        called += 1\n\n    periodic_caller = PeriodicCaller(callback, period=0.1)\n    periodic_caller.start()\n\n    await asyncio.sleep(0.15)\n    assert called >= 1\n\n    periodic_caller.stop()\n    old_called = called\n    await asyncio.sleep(0.15)\n    assert old_called == called\n\n\n@pytest.mark.asyncio\nasync def test_periodic_caller_exception():\n    \"\"\"Test exception raises for PeriodicCaller.\"\"\"\n    exception_called = False\n\n    def exception_callback(*args, **kwargs):\n        nonlocal exception_called\n        exception_called = True\n\n    def callback():\n        raise Exception(\"expected\")\n\n    periodic_caller = PeriodicCaller(\n        callback, period=0.1, exception_callback=exception_callback\n    )\n    periodic_caller.start()\n\n    await asyncio.sleep(0.15)\n    assert exception_called\n    periodic_caller.stop()\n\n\n@pytest.mark.asyncio\nasync def test_threaded_async_run():\n    \"\"\"Test threaded async runner.\"\"\"\n    runner = ThreadedAsyncRunner()\n    runner.start()\n\n    async def fn():\n        return \"ok\"\n\n    assert runner.call(fn()).result() == \"ok\"\n    runner.stop()\n\n\n@pytest.mark.asyncio\nasync def test_threaded_async_run_cancel_task():\n    \"\"\"Test threaded async runner tasks cancelled.\"\"\"\n    runner = ThreadedAsyncRunner()\n    runner.start()\n\n    async def fn():\n        await asyncio.sleep(1)\n\n    task = runner.call(fn())\n    await asyncio.sleep(0.1)\n    task.cancel()\n    await asyncio.sleep(0.1)\n    with pytest.raises(CancelledError):\n        task.result()\n\n    assert task.done()\n\n    # cancel before start\n    task = runner.call(fn())\n    task.cancel()\n    with pytest.raises(CancelledError):\n        task.result()\n    assert task.done()\n\n\nclass RunAndExit(Runnable):\n    \"\"\"Test class.\"\"\"\n\n    async def run(self):\n        \"\"\"Test method.\"\"\"\n        await asyncio.sleep(0.2)\n\n\nclass TestRunnable:\n    \"\"\"Tests for Runnable object.\"\"\"\n\n    def test_no_loop_and_threded(self):\n        \"\"\"Test runnable fails on threaded mode and loop provided..\"\"\"\n        with pytest.raises(\n            ValueError,\n        ):\n            RunAndExit(loop=asyncio.get_event_loop(), threaded=True)\n\n    def test_task_cancel_not_set(self):\n        \"\"\"Test task cancel.\"\"\"\n\n        class TestRun(Runnable):\n            async def run(self):\n                while True:\n                    await asyncio.sleep(1)\n\n        run = TestRun()\n        run._task_cancel()\n\n    @pytest.mark.asyncio\n    async def test_runnable_async(self):\n        \"\"\"Test runnable async methods.\"\"\"\n        # for pydocstyle\n        class TestRun(Runnable):\n            async def run(self):\n                while True:\n                    await asyncio.sleep(1)\n\n        run = TestRun()\n        run.start()\n        run.stop()\n        await run.wait_completed()\n\n        run = TestRun(threaded=True)\n        run.start()\n        run.stop()\n        run.wait_completed(sync=True)\n\n        run = RunAndExit()\n        await run.start_and_wait_completed()\n\n    def test_runnable_sync(self):\n        \"\"\"Test runnable sync methods.\"\"\"\n        run = RunAndExit()\n        run.start_and_wait_completed(sync=True)\n\n    @pytest.mark.asyncio\n    async def test_double_start(self):\n        \"\"\"Test runnable async methods.\"\"\"\n        # for pydocstyle\n        class TestRun(Runnable):\n            async def run(self):\n                while True:\n                    await asyncio.sleep(1)\n\n        run = TestRun()\n        await run.wait_completed()\n        assert run.start()\n        assert not run.start()\n        run.stop()\n        await run.wait_completed()\n        await run.wait_completed()\n\n    @pytest.mark.asyncio\n    async def test_run_in_thread(self):\n        \"\"\"Test runnable in thread mode.\"\"\"\n        # for pydocstyle\n        class TestRun(Runnable):\n            async def run(self):\n                while True:\n                    await asyncio.sleep(1)\n\n        run = TestRun()\n        t = Thread(target=run.start_and_wait_completed, kwargs=dict(sync=True))\n        t.start()\n        while not run.is_running:\n            pass\n        run.stop()\n        t.join()\n\n    @pytest.mark.asyncio\n    async def test_timeout(self):\n        \"\"\"Test runnable async methods.\"\"\"\n        # for pydocstyle\n        class TestRun(Runnable):\n            def __init__(\n                self, loop: asyncio.AbstractEventLoop = None, threaded: bool = False\n            ) -> None:\n                Runnable.__init__(self, loop=loop, threaded=threaded)\n                self.started = False\n\n            async def run(self):\n                while True:\n                    await asyncio.sleep(0.1)\n                    self.started = True\n\n        run = TestRun(threaded=True)\n        run.start()\n        wait_for_condition(lambda: run.started, timeout=5)\n        with pytest.raises(asyncio.TimeoutError):\n            run.wait_completed(sync=True, timeout=1)\n\n        run.stop()\n        run.wait_completed(sync=True)\n\n        run = TestRun()\n        run.start()\n        await wait_for_condition_async(lambda: run.started, timeout=5)\n        with pytest.raises(asyncio.TimeoutError):\n            await run.wait_completed(timeout=1)\n        run.stop()\n        await run.wait_completed()\n\n    @pytest.mark.asyncio\n    async def test_exception(self):\n        \"\"\"Test runnable async methods.\"\"\"\n        # for pydocstyle\n        import time\n\n        class TestRun(Runnable):\n            async def run(self):\n                raise Exception(\"awaited\")\n\n        run = TestRun(threaded=True)\n        run.start()\n        time.sleep(0.1)\n        with pytest.raises(Exception, match=\"awaited\"):\n            run.wait_completed(sync=True, timeout=1)\n\n        run.stop()\n        run.wait_completed(sync=True)\n\n        run = TestRun()\n        run.start()\n        with pytest.raises(Exception, match=\"awaited\"):\n            await run.wait_completed(timeout=1)\n\n        run.stop()\n        await run.wait_completed()\n\n    @pytest.mark.asyncio\n    async def test_wait_async_threaded(self):\n        \"\"\"Test runnable async methods.\"\"\"\n        # for pydocstyle\n        class TestRun(Runnable):\n            async def run(self):\n                raise Exception(\"awaited\")\n\n        run = TestRun(threaded=True)\n        run.start()\n        await asyncio.sleep(0.4)\n\n        with pytest.raises(Exception, match=\"awaited\"):\n            await run.wait_completed(timeout=1)\n\n        run.stop()\n        await run.wait_completed()\n\n    @pytest.mark.asyncio\n    async def test_wait_async_threaded_no_exception(self):\n        \"\"\"Test runnable threaded wait completed.\"\"\"\n        # for pydocstyle\n        class TestRun(Runnable):\n            async def run(self):\n                await asyncio.sleep(0.1)\n\n        run = TestRun(threaded=True)\n        run.start()\n        await run.wait_completed()\n\n    @pytest.mark.asyncio\n    async def test_double_stop(self):\n        \"\"\"Test runnable double stop.\"\"\"\n        # for pydocstyle\n        class TestRun(Runnable):\n            async def run(self):\n                await asyncio.sleep(0.1)\n\n        run = TestRun()\n        run.start()\n        run.stop()\n        run.stop()\n        await run.wait_completed()\n\n    def test_stop_before_run(self):\n        \"\"\"Test stop before run.\"\"\"\n        # for pydocstyle\n        class TestRun(Runnable):\n            async def run(self):\n                await asyncio.sleep(0.1)\n\n        run = TestRun()\n        run.stop()\n        run.start()\n        time.sleep(1)\n        assert not run.is_running\n"
  },
  {
    "path": "tests/test_aea/test_helpers/test_base.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests for the helper module.\"\"\"\nimport datetime\nimport os\nimport platform\nimport re\nimport shutil\nimport signal\nimport tempfile\nimport time\nfrom copy import copy\nfrom functools import wraps\nfrom pathlib import Path\nfrom subprocess import Popen  # nosec\nfrom tempfile import TemporaryDirectory\nfrom typing import Dict, Optional, Set\nfrom unittest.mock import patch\n\nimport pytest\nfrom packaging.version import Version\n\nfrom aea.exceptions import AEAEnforceError\nfrom aea.helpers.base import (\n    CertRequest,\n    MaxRetriesError,\n    RegexConstrainedString,\n    compute_specifier_from_version,\n    decorator_with_optional_params,\n    delete_directory_contents,\n    dict_to_path_value,\n    ensure_dir,\n    exception_log_and_reraise,\n    find_topological_order,\n    load_env_file,\n    load_module,\n    locate,\n    prepend_if_not_absolute,\n    reachable_nodes,\n    recursive_update,\n    retry_decorator,\n    send_control_c,\n    try_decorator,\n    win_popen_kwargs,\n)\n\nfrom packages.fetchai.connections.oef.connection import OEFConnection\n\nfrom tests.conftest import CUR_PATH, ROOT_DIR, skip_test_windows\n\n\nclass TestHelpersBase:\n    \"\"\"Test the helper functions.\"\"\"\n\n    def test_locate(self):\n        \"\"\"Test the locate function to locate modules.\"\"\"\n        cwd = os.getcwd()\n        os.chdir(os.path.join(CUR_PATH, \"..\"))\n        gym_package = locate(\n            \"packages.fetchai.connections.gym.connection.GymConnection\"\n        )\n        non_existing_package = locate(\n            \"packages.fetchai.connections.non_existing_connection\"\n        )\n        os.chdir(cwd)\n        assert gym_package is not None\n        assert non_existing_package is None\n\n    def test_locate_class(self):\n        \"\"\"Test the locate function to locate classes.\"\"\"\n        cwd = os.getcwd()\n        os.chdir(os.path.join(CUR_PATH, \"..\"))\n        expected_class = OEFConnection\n        actual_class = locate(\n            \"packages.fetchai.connections.oef.connection.OEFConnection\"\n        )\n        os.chdir(cwd)\n        # although they are the same class, they are different instances in memory\n        # and the build-in default \"__eq__\" method does not compare the attributes.\n        # so compare the names\n        assert actual_class is not None\n        assert expected_class.__name__ == actual_class.__name__\n\n    def test_locate_with_builtins(self):\n        \"\"\"Test that locate function returns the built-in.\"\"\"\n        result = locate(\"int.bit_length\")\n        assert int.bit_length == result\n\n    def test_locate_when_path_does_not_exist(self):\n        \"\"\"Test that locate function returns None when the dotted path does not exist.\"\"\"\n        result = locate(\"aea.not.existing.path\")\n        assert result is None\n\n        result = locate(\"ThisClassDoesNotExist\")\n        assert result is None\n\n\ndef test_regex_constrained_string_initialization():\n    \"\"\"Test we can initialize a regex constrained with the default regex.\"\"\"\n    RegexConstrainedString(\"\")\n    RegexConstrainedString(\"abcde\")\n    RegexConstrainedString(b\"\")\n    RegexConstrainedString(b\"abcde\")\n    RegexConstrainedString(RegexConstrainedString(\"\"))\n    RegexConstrainedString(RegexConstrainedString(\"abcde\"))\n\n\ndef test_load_module():\n    \"\"\"Test load module from filepath and dotted notation.\"\"\"\n    load_module(\n        \"packages.fetchai.connections.gym.connection\",\n        Path(ROOT_DIR)\n        / \"packages\"\n        / \"fetchai\"\n        / \"connections\"\n        / \"gym\"\n        / \"connection.py\",\n    )\n\n\ndef test_load_env_file():\n    \"\"\"Test load env file updates process environment variables.\"\"\"\n    load_env_file(Path(ROOT_DIR) / \"tests\" / \"data\" / \"dot_env_file\")\n    assert os.getenv(\"TEST\") == \"yes\"\n\n\ndef test_reg_exp_not_match():\n    \"\"\"Test regexp checks.\"\"\"\n    # for pydocstyle\n    class MyReString(RegexConstrainedString):\n        REGEX = re.compile(r\"[0-9]+\")\n\n    with pytest.raises(ValueError):\n        MyReString(\"anystring\")\n\n\ndef test_try_decorator():\n    \"\"\"Test try and log decorator.\"\"\"\n    # for pydocstyle\n    @try_decorator(\"oops\", default_return=\"failed\")\n    def fn():\n        raise Exception(\"expected\")\n\n    assert fn() == \"failed\"\n\n\ndef test_retry_decorator():\n    \"\"\"Test auto retry decorator.\"\"\"\n    num_calls = 0\n    retries = 3\n\n    @retry_decorator(retries, \"oops. expected\")\n    def fn():\n        nonlocal num_calls\n        num_calls += 1\n        raise Exception(\"expected\")\n\n    with pytest.raises(MaxRetriesError):\n        fn()\n    assert num_calls == retries\n\n\ndef test_log_and_reraise():\n    \"\"\"Test log and reraise context manager.\"\"\"\n    log_msg = None\n\n    def fn(msg):\n        nonlocal log_msg\n        log_msg = msg\n\n    with pytest.raises(ValueError):\n        with exception_log_and_reraise(fn, \"oops\"):\n            raise ValueError()\n\n    assert log_msg == \"oops\"\n\n\n@skip_test_windows\ndef test_send_control_c_group():\n    \"\"\"Test send control c to process group.\"\"\"\n    # Can't test process group id kill directly,\n    # because o/w pytest would be stopped.\n    process = Popen([\"sleep\", \"1\"])  # nosec\n    pgid = os.getpgid(process.pid)\n    time.sleep(0.1)\n    with patch(\"os.killpg\") as mock_killpg:\n        send_control_c(process, kill_group=True)\n        process.communicate(timeout=3)\n        mock_killpg.assert_called_with(pgid, signal.SIGINT)\n\n\ndef test_send_control_c():\n    \"\"\"Test send control c to process.\"\"\"\n    # Can't test process group id kill directly,\n    # because o/w pytest would be stopped.\n    process = Popen(  # nosec\n        [\"timeout\" if platform.system() == \"Windows\" else \"sleep\", \"5\"],\n        **win_popen_kwargs(),\n    )\n    time.sleep(0.001)\n    send_control_c(process)\n    process.communicate(timeout=3)\n    assert process.returncode != 0\n\n\n@skip_test_windows\ndef test_send_control_c_windows():\n    \"\"\"Test send control c on Windows.\"\"\"\n    process = Popen(  # nosec\n        [\"timeout\" if platform.system() == \"Windows\" else \"sleep\", \"5\"]\n    )\n    time.sleep(0.001)\n    pid = process.pid\n    with patch(\"aea.helpers.base.signal\") as mock_signal:\n        mock_signal.CTRL_C_EVENT = \"mock\"\n        with patch(\"platform.system\", return_value=\"Windows\"):\n            with patch(\"os.kill\") as mock_kill:\n                send_control_c(process)\n                mock_kill.assert_called_with(pid, mock_signal.CTRL_C_EVENT)\n\n\ndef test_recursive_update_no_recursion():\n    \"\"\"Test the 'recursive update' utility, in the case there's no recursion.\"\"\"\n    to_update = dict(not_updated=0, an_integer=1, a_list=[1, 2, 3], a_tuple=(1, 2, 3))\n\n    new_integer, new_list, new_tuple = 2, [3], (3,)\n    new_values = dict(an_integer=new_integer, a_list=new_list, a_tuple=new_tuple)\n    recursive_update(to_update, new_values)\n    assert to_update == dict(\n        not_updated=0, an_integer=new_integer, a_list=new_list, a_tuple=new_tuple\n    )\n\n\ndef test_recursive_update_with_recursion():\n    \"\"\"Test the 'recursive update' utility with recursion.\"\"\"\n    # here we try to update an integer and add a new value\n    to_update = dict(subdict=dict(to_update=1))\n    new_values = dict(subdict=dict(to_update=2))\n\n    recursive_update(to_update, new_values)\n    assert to_update == dict(subdict=dict(to_update=2))\n\n\ndef test_recursive_update_negative_different_type():\n    \"\"\"Test the 'recursive update' utility, when the types are different.\"\"\"\n    # here we try to update an integer with a boolean - it raises error.\n    to_update = dict(subdict=dict(to_update=1))\n    new_values = dict(subdict=dict(to_update=False))\n\n    with pytest.raises(\n        ValueError,\n        match=\"Trying to replace value '1' with value 'False' which is of different type.\",\n    ):\n        recursive_update(to_update, new_values)\n\n\ndef test_recursive_update_new_fields():\n    \"\"\"Test the 'recursive update' utility, with new fields.\"\"\"\n    # here we try to update an integer with a boolean - it raises error.\n    to_update = dict(subdict=dict(to_update=1))\n    new_values = dict(subdict=dict(to_update2=False))\n\n    with pytest.raises(\n        ValueError,\n        match=\"Key 'to_update2' is not contained in the dictionary to update.\",\n    ):\n        recursive_update(to_update, new_values)\n    assert \"to_update2\" not in to_update[\"subdict\"]\n\n    recursive_update(to_update, new_values, allow_new_values=True)\n    assert \"to_update2\" in to_update[\"subdict\"]\n\n\ndef test_recursive_update_negative_unknown_field():\n    \"\"\"Test the 'recursive update' utility, when there are unknown fields.\"\"\"\n    # here we try to update an integer with a boolean - it raises error.\n    to_update = dict(subdict=dict(field=1))\n    new_values = dict(subdict=dict(new_field=False))\n\n    with pytest.raises(\n        ValueError,\n        match=\"Key 'new_field' is not contained in the dictionary to update.\",\n    ):\n        recursive_update(to_update, new_values)\n\n\nclass TestTopologicalOrder:\n    \"\"\"Test the computation of topological order.\"\"\"\n\n    def test_empty_graph(self):\n        \"\"\"Test the function with empty input.\"\"\"\n        order = find_topological_order({})\n        assert order == []\n\n    def test_one_node(self):\n        \"\"\"Test the function with only one node.\"\"\"\n        order = find_topological_order({0: set()})\n        assert order == [0]\n\n    def test_one_node_with_cycle(self):\n        \"\"\"Test the function with only one node and a loop.\"\"\"\n        with pytest.raises(ValueError, match=\"Graph has at least one cycle.\"):\n            find_topological_order({0: {0}})\n\n    def test_two_nodes_no_edges(self):\n        \"\"\"Test the function with two nodes, but no edges.\"\"\"\n        order = find_topological_order({0: set(), 1: set()})\n        assert order == [0, 1]\n\n    def test_two_nodes_no_cycle(self):\n        \"\"\"Test the function with two nodes, but no cycles.\"\"\"\n        order = find_topological_order({0: {1}})\n        assert order == [0, 1]\n\n    def test_two_nodes_with_cycle(self):\n        \"\"\"Test the function with two nodes and a cycle between them.\"\"\"\n        with pytest.raises(ValueError, match=\"Graph has at least one cycle.\"):\n            find_topological_order({0: {1}, 1: {0}})\n\n    def test_two_nodes_clique(self):\n        \"\"\"Test the function with a clique of two nodes.\"\"\"\n        with pytest.raises(ValueError, match=\"Graph has at least one cycle.\"):\n            find_topological_order({0: {1, 0}, 1: {0, 1}})\n\n    @pytest.mark.parametrize(\"chain_length\", [3, 5, 10, 100])\n    def test_chain(self, chain_length):\n        \"\"\"Test the function with a chain.\"\"\"\n        adj_list: Dict[int, Set[int]] = {}\n        for i in range(chain_length - 1):\n            adj_list[i] = {i + 1}\n        adj_list[chain_length - 1] = set()\n\n        order = find_topological_order(adj_list)\n        assert order == list(range(chain_length))\n\n\nclass TestReachableNodes:\n    \"\"\"Test reachable_nodes utility.\"\"\"\n\n    def test_empty_graph(self):\n        \"\"\"Test empty graph.\"\"\"\n        result = reachable_nodes({}, set())\n        assert result == {}\n\n    def test_starting_node_not_in_the_graph(self):\n        \"\"\"Test error when starting node not in the graph.\"\"\"\n        with pytest.raises(\n            AEAEnforceError,\n            match=\"These starting nodes are not in the set of nodes: {1}\",\n        ):\n            reachable_nodes({}, {1})\n\n    def test_one_node(self):\n        \"\"\"Test one node.\"\"\"\n        result = reachable_nodes({1: set()}, {1})\n        assert result == {1: set()}\n\n    def test_one_node_loop(self):\n        \"\"\"Test one node, loop.\"\"\"\n        g = {1: {1}}\n        result = reachable_nodes(g, {1})\n        assert result == g\n\n    def test_two_nodes(self):\n        \"\"\"Test two nodes.\"\"\"\n        g = {1: {2}}\n        result = reachable_nodes(g, {1})\n        assert result == g\n\n        result = reachable_nodes(g, {2})\n        assert result == {2: set()}\n\n    def test_two_nodes_cycle(self):\n        \"\"\"Test two nodes in a cycle\"\"\"\n        g = {1: {2}, 2: {1}}\n        result = reachable_nodes(g, {1})\n        assert result == g\n\n        result = reachable_nodes(g, {2})\n        assert result == g\n\n    def test_chain(self):\n        \"\"\"Test chain\"\"\"\n        g = {1: {2}, 2: {3}, 3: set()}\n        result = reachable_nodes(g, {1})\n        assert result == g\n\n        result = reachable_nodes(g, {2})\n        expected = copy(g)\n        expected.pop(1)\n        assert result == expected\n\n        result = reachable_nodes(g, {3})\n        assert result == {3: set()}\n\n\ndef test_ensure_dir():\n    \"\"\"Test ensure_dir.\"\"\"\n    dir_name = \"test\"\n    with TemporaryDirectory() as tmpdirname:\n        full_path = os.path.join(tmpdirname, dir_name)\n        assert not os.path.exists(full_path)\n        ensure_dir(full_path)\n        assert os.path.exists(full_path)\n        file_path = os.path.join(full_path, \"file_name\")\n        with open(file_path, \"w\"):\n            pass\n\n        with pytest.raises(AEAEnforceError):\n            ensure_dir(file_path)\n\n\nclass BaseTestCertRequestError:\n    \"\"\"Test errors when instantiating a CertRequest object.\"\"\"\n\n    PUBLIC_KEY = \"a_public_key\"\n    IDENTIFIER = \"an_identifier\"\n    LEDGER_ID = \"a_ledger_id\"\n    NOT_BEFORE = \"2020-01-01\"\n    NOT_AFTER = \"2020-01-02\"\n    MESSAGE_FORMAT = \"{public_key}\"\n    PATH = \"some/path\"\n    ERROR_MESSAGE_PATTERN = \"\"\n\n    def test_error(self):\n        \"\"\"Test error during instantiation..\"\"\"\n        with pytest.raises(ValueError, match=self.ERROR_MESSAGE_PATTERN):\n            CertRequest(\n                self.PUBLIC_KEY,\n                self.IDENTIFIER,\n                self.LEDGER_ID,\n                self.NOT_BEFORE,\n                self.NOT_AFTER,\n                self.MESSAGE_FORMAT,\n                self.PATH,\n            )\n\n\nclass TestCertRequestBadPublicKey(BaseTestCertRequestError):\n    \"\"\"Test instantiation of CertRequest class with bad public key.\"\"\"\n\n    PUBLIC_KEY = \"0a_bad_identifier\"\n    ERROR_MESSAGE_PATTERN = \"Public key field '0a_bad_identifier' is neither a valid identifier nor an address.\"\n\n\nclass TestCertRequestBadIdentifier(BaseTestCertRequestError):\n    \"\"\"Test instantiation of CertRequest class with bad identifier.\"\"\"\n\n    IDENTIFIER = \"0bad_identifier\"\n    ERROR_MESSAGE_PATTERN = (\n        \"Value 0bad_identifier does not match the regular expression.*\"\n    )\n\n\nclass TestCertRequestBadLedgerId(BaseTestCertRequestError):\n    \"\"\"Test instantiation of CertRequest class with bad ledger id.\"\"\"\n\n    LEDGER_ID = \"0bad_identifier\"\n    ERROR_MESSAGE_PATTERN = (\n        \"Value 0bad_identifier does not match the regular expression.*\"\n    )\n\n\nclass TestCertRequestBadNotBefore(BaseTestCertRequestError):\n    \"\"\"Test instantiation of CertRequest class with bad not_before date.\"\"\"\n\n    NOT_BEFORE = \"bad-formatted-date\"\n    ERROR_MESSAGE_PATTERN = (\n        \"time data 'bad-formatted-date' does not match format '%Y-%m-%d'\"\n    )\n\n\nclass TestCertRequestBadNotAfter(BaseTestCertRequestError):\n    \"\"\"Test instantiation of CertRequest class with bad not_after date.\"\"\"\n\n    NOT_AFTER = \"bad-formatted-date\"\n    ERROR_MESSAGE_PATTERN = (\n        \"time data 'bad-formatted-date' does not match format '%Y-%m-%d'\"\n    )\n\n\nclass TestCertRequestInconsistentDates(BaseTestCertRequestError):\n    \"\"\"Test instantiation of CertRequest class when not_before >= not_after\"\"\"\n\n    NOT_BEFORE = \"1954-06-07\"\n    NOT_AFTER = \"1900-01-01\"\n    ERROR_MESSAGE_PATTERN = r\"Inconsistent certificate validity period: 'not_before' field '1954-06-07' is not before than 'not_after' field '1900-01-01'\"\n\n\nclass BaseTestCertRequestInstantiation:\n    \"\"\"Test (successful) instantiation of CertRequest class.\"\"\"\n\n    PUBLIC_KEY: Optional[str] = \"\"\n    EXPECTED_PUBLIC_KEY: Optional[str] = \"\"\n    EXPECTED_KEY_IDENTIFIER: Optional[str] = \"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set up class.\"\"\"\n        cls.expected_public_key = cls.PUBLIC_KEY\n        cls.expected_identifier = \"identifier\"\n        cls.expected_ledger_id = \"ledger_id\"\n        cls.not_before = \"2020-01-01\"\n        cls.not_after = \"2020-01-02\"\n        cls.message_format = \"{public_key}\"\n        cls.expected_path = os.path.abspath(\"some/path\")\n        cls.cert_request = CertRequest(\n            cls.expected_public_key,\n            cls.expected_identifier,\n            cls.expected_ledger_id,\n            cls.not_before,\n            cls.not_after,\n            cls.message_format,\n            cls.expected_path,\n        )\n\n    def test_instantiation(self):\n        \"\"\"Test instantiation.\"\"\"\n        assert self.cert_request.public_key == self.EXPECTED_PUBLIC_KEY\n        assert self.cert_request.key_identifier == self.EXPECTED_KEY_IDENTIFIER\n        assert self.cert_request.identifier == self.expected_identifier\n        assert self.cert_request.ledger_id == self.expected_ledger_id\n\n        expected_not_before = datetime.datetime(\n            2020, 1, 1, 0, 0, 0, 0, datetime.timezone.utc\n        )\n        assert self.cert_request.not_before == expected_not_before\n\n        expected_not_after = datetime.datetime(\n            2020, 1, 2, 0, 0, 0, 0, datetime.timezone.utc\n        )\n        assert self.cert_request.not_after == expected_not_after\n\n        assert self.cert_request.not_before_string == expected_not_before.strftime(\n            \"%Y-%m-%d\"\n        )\n        assert self.cert_request.not_after_string == expected_not_after.strftime(\n            \"%Y-%m-%d\"\n        )\n        some_key = \"some_key\"\n        assert self.cert_request.get_message(some_key) == \"some_key\".encode(\"ascii\")\n\n        assert self.cert_request.save_path == Path(self.expected_path)\n\n    def test_from_to_json(self):\n        \"\"\"Test from-to json methods.\"\"\"\n        assert self.cert_request == self.cert_request.from_json(self.cert_request.json)\n\n\nclass TestCertRequestInstantiationWithKeyIdentifier(BaseTestCertRequestInstantiation):\n    \"\"\"Test (successful) instantiation of CertRequest class.\"\"\"\n\n    PUBLIC_KEY = \"public_key\"\n    EXPECTED_PUBLIC_KEY = None\n    EXPECTED_KEY_IDENTIFIER = PUBLIC_KEY\n\n\nclass TestCertRequestInstantiationWithKeyHex(BaseTestCertRequestInstantiation):\n    \"\"\"Test (successful) instantiation of CertRequest class.\"\"\"\n\n    PUBLIC_KEY = \"0xABCDEF12345\"\n    EXPECTED_PUBLIC_KEY = \"0xABCDEF12345\"\n    EXPECTED_KEY_IDENTIFIER = None\n\n\ndef test_compute_specifier_from_version():\n    \"\"\"Test function 'compute_specifier_from_version'.\"\"\"\n\n    version = \"0.1.5\"\n    expected_range = \">=0.1.0, <0.2.0\"\n    assert expected_range == compute_specifier_from_version(Version(version))\n\n    version = \"1.0.0rc1\"\n    expected_range = \">=1.0.0rc1, <2.0.0\"\n    assert expected_range == compute_specifier_from_version(Version(version))\n\n    version = \"1.0.0.post1\"\n    expected_range = \">=1.0.0, <2.0.0\"\n    assert expected_range == compute_specifier_from_version(Version(version))\n\n    version = \"1.1.0rc1\"\n    expected_range = \">=1.1.0rc1, <2.0.0\"\n    assert expected_range == compute_specifier_from_version(Version(version))\n\n\ndef test_dict_to_path_value():\n    \"\"\"Test dict_to_path_value.\"\"\"\n    path_values = {\n        tuple(path): value\n        for path, value in dict_to_path_value({\"a\": 12, \"b\": {\"c\": 1}})\n    }\n    assert path_values.get((\"a\",)) == 12\n    assert path_values.get((\"b\", \"c\")) == 1\n\n\ndef test_decorator_with_optional_params():\n    \"\"\"Test the utility 'decorator_with_optional_params'.\"\"\"\n\n    def hello(name: str):\n        \"\"\"Say hello to 'name'.\"\"\"\n        return f\"Hello, {name}!\"\n\n    @decorator_with_optional_params\n    def add_preamble(f, computer_name: str = \"\"):\n        \"\"\"\n        This function adds a preamble to the 'hello' function.\n\n        It prepends: 'Computer says: ' if the computer name is not specified,\n        else 'Computer {computer_name} says: '.\n        \"\"\"\n\n        @wraps(f)\n        def wrapper(*args, **kwargs):\n            computer_name_or_space = f\" {computer_name} \" if computer_name else \" \"\n            preamble = f\"Computer{computer_name_or_space}says: \"\n            result = f(*args, **kwargs)\n            return preamble + result\n\n        return wrapper\n\n    # we can use the 'add_preamble' wrapper either as:\n    #    @add_preamble\n    # or:\n    #    @add_preamble()\n\n    @add_preamble\n    def hello_with_preamble(*args, **kwargs):\n        return hello(*args, **kwargs)\n\n    @add_preamble(computer_name=\"Commodore 64\")\n    def hello_from_commodore(*args, **kwargs):\n        return hello(*args, **kwargs)\n\n    # we test that the name is updated correctly\n    with pytest.raises(\n        TypeError,\n        match=re.escape(\"hello() missing 1 required positional argument: 'name'\"),\n    ):\n        hello_with_preamble()\n\n    assert hello_with_preamble(\"User\") == \"Computer says: Hello, User!\"\n    assert hello_from_commodore(\"User\") == \"Computer Commodore 64 says: Hello, User!\"\n\n\nclass TestDeleteDirectoryContents:\n    \"\"\"Test utility 'delete_directory_contents'.\"\"\"\n\n    def setup(self):\n        \"\"\"Set up the test.\"\"\"\n        self.root = Path(tempfile.mkdtemp())\n        # create a file\n        file_1 = self.root / \"file_1\"\n        file_1.touch()\n\n        # create a symlink\n        (self.root / \"symlink_1\").symlink_to(file_1)\n\n        # create a subdirectory\n        subdir = self.root / \"directory\"\n        subdir.mkdir()\n\n        # create a file in the directory\n        (subdir / \"file\").touch()\n\n    def test_main(self):\n        \"\"\"Run the test.\"\"\"\n        delete_directory_contents(self.root)\n\n        assert self.root.exists()\n        assert len(list(self.root.iterdir())) == 0\n\n    def teardown(self):\n        \"\"\"Tear down the test.\"\"\"\n        shutil.rmtree(str(self.root), ignore_errors=True)\n\n\ndef test_prepend_if_not_absolute():\n    \"\"\"Test the prepend_if_not_absolute method.\"\"\"\n    path = \"path\"\n    prefix = \"prefix\"\n    res = prepend_if_not_absolute(path, prefix)\n    assert res == Path(prefix, path)\n    abs_path = os.path.abspath(path)\n    res = prepend_if_not_absolute(abs_path, prefix)\n    assert res == abs_path\n"
  },
  {
    "path": "tests/test_aea/test_helpers/test_env_vars.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests for the helper module.\"\"\"\nimport pytest\n\nfrom aea.helpers.env_vars import (\n    apply_env_variables,\n    convert_value_str_to_type,\n    is_env_variable,\n    replace_with_env_var,\n)\n\n\ndef test_is_env_variable():\n    \"\"\"Test is_env_variable.\"\"\"\n    assert is_env_variable(\"${test}\")\n    assert is_env_variable(\"${test:int}\")\n    assert is_env_variable(\"${test:int:12}\")\n\n    assert not is_env_variable(\"sdfsdf\")\n\n\ndef test_apply_env_variables():\n    \"\"\"Test apply_env_variables\"\"\"\n    assert apply_env_variables(\"${var}\", {\"var\": \"test\"}) == \"test\"\n    assert apply_env_variables(\"var\", {\"var\": \"test\"}) == \"var\"\n    assert apply_env_variables([\"${var}\"], {\"var\": \"test\"}) == [\"test\"]\n    assert apply_env_variables({\"${var}\": \"${var}\"}, {\"var\": \"test\"}) == {\n        \"test\": \"test\"\n    }\n\n\ndef test_replace_with_env_var():\n    \"\"\"Test replace_with_env_var.\"\"\"\n    assert replace_with_env_var(\"${var:int:12}\", {\"var\": \"10\"}) == 10\n    assert replace_with_env_var(\"${var:int:12}\", {}) == 12\n    assert replace_with_env_var(\"var\", {}) == \"var\"\n    assert replace_with_env_var(\"${var}\", {}, default_value=100) == 100\n\n    with pytest.raises(\n        ValueError,\n        match=r\"`var` not found in env variables and no default value set!\",\n    ):\n        replace_with_env_var(\"${var}\", {})\n\n\ndef test_convert_value_str_to_type():\n    \"\"\"Test convert_value_str_to_type.\"\"\"\n    assert convert_value_str_to_type(\"false\", \"bool\") is False\n    assert convert_value_str_to_type(\"True\", \"bool\") is True\n    assert convert_value_str_to_type(\"12\", \"int\") == 12\n    assert convert_value_str_to_type(\"1.1\", \"float\") == 1.1\n    assert convert_value_str_to_type(\"1sdfsdf2\", \"none\") is None\n    assert convert_value_str_to_type('{\"a\": 12}', \"dict\") == {\"a\": 12}\n"
  },
  {
    "path": "tests/test_aea/test_helpers/test_exec_timeout.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests for the helpers.exec_timout.\"\"\"\nimport os\nimport time\nimport unittest\nfrom functools import partial\nfrom threading import Thread\nfrom unittest.case import TestCase\n\nimport pytest\n\nfrom aea.helpers.exec_timeout import (\n    BaseExecTimeout,\n    ExecTimeoutSigAlarm,\n    ExecTimeoutThreadGuard,\n    TimeoutException,\n)\n\nfrom tests.common.utils import timeit_context\nfrom tests.conftest import MAX_FLAKY_RERUNS\n\n\nif os.name == \"nt\":\n    pytest.skip(\"signal.settimer non available on Windows.\", allow_module_level=True)\n\n\nclass BaseTestExecTimeout(TestCase):\n    \"\"\"Base test case for code execution timeout.\"\"\"\n\n    EXEC_TIMEOUT_CLASS = BaseExecTimeout\n\n    @classmethod\n    def setUpClass(cls):\n        \"\"\"Set up.\"\"\"\n        if cls is BaseTestExecTimeout:\n            raise unittest.SkipTest(\"Skip BaseTest tests, it's a base class\")\n\n    def test_cancel_by_timeout(self):\n        \"\"\"Test function interrupted by timeout.\"\"\"\n        slow_function_time = 0.4\n        timeout = 0.1\n\n        assert timeout < slow_function_time\n\n        with timeit_context() as timeit_result:\n            with pytest.raises(TimeoutException):\n                with self.EXEC_TIMEOUT_CLASS(timeout) as exec_timeout:\n                    self.slow_function(slow_function_time)\n\n            assert exec_timeout.is_cancelled_by_timeout()\n\n        assert (\n            timeit_result.time_passed >= timeout\n            and timeit_result.time_passed < slow_function_time\n        )\n\n    def test_limit_is_0_do_not_limit_execution(self):\n        \"\"\"Test function will not be interrupted cause timeout is 0 or None.\"\"\"\n        slow_function_time = 0.1\n        timeout = 0\n        assert timeout < slow_function_time\n\n        with timeit_context() as timeit_result:\n            with self.EXEC_TIMEOUT_CLASS(timeout) as exec_timeout:\n                self.slow_function(slow_function_time)\n\n            assert not exec_timeout.is_cancelled_by_timeout()\n\n        assert timeit_result.time_passed >= slow_function_time\n\n    def test_timeout_bigger_than_execution_time(self):\n        \"\"\"Test function interrupted by timeout.\"\"\"\n        slow_function_time = 0.1\n        timeout = 1\n\n        assert timeout > slow_function_time\n\n        with timeit_context() as timeit_result:\n            with self.EXEC_TIMEOUT_CLASS(timeout) as exec_timeout:\n                self.slow_function(slow_function_time)\n\n            assert not exec_timeout.is_cancelled_by_timeout()\n\n        assert (\n            timeit_result.time_passed <= timeout\n            and timeit_result.time_passed >= slow_function_time\n        )\n\n    @classmethod\n    def slow_function(cls, sleep):\n        \"\"\"Sleep some time to test timeout applied.\"\"\"\n        time.sleep(sleep)\n\n\nclass TestSigAlarm(BaseTestExecTimeout):\n    \"\"\"Test code execution timeout using unix signals.\"\"\"\n\n    EXEC_TIMEOUT_CLASS = ExecTimeoutSigAlarm\n\n\nclass TestThreadGuard(BaseTestExecTimeout):\n    \"\"\"Test code execution timeout using. thread set execption.\"\"\"\n\n    EXEC_TIMEOUT_CLASS = ExecTimeoutThreadGuard\n\n    def setUp(self):\n        \"\"\"Set up.\"\"\"\n        self.EXEC_TIMEOUT_CLASS.start()\n\n    def tearDown(self):\n        \"\"\"Tear down.\"\"\"\n        self.EXEC_TIMEOUT_CLASS.stop(force=True)\n\n    @classmethod\n    def slow_function(cls, sleep):\n        \"\"\"Sleep in cycle to be perfect interrupted.\"\"\"\n        fractions = 10\n        for _ in range(fractions):\n            time.sleep(sleep / fractions)\n\n    @pytest.mark.flaky(reruns=MAX_FLAKY_RERUNS)\n    def test_execution_limit_in_threads(self):\n        \"\"\"Test two threads with different timeouts same time.\"\"\"\n        # pydocstyle: ignore # conflict with black # noqa: E800\n        def make_test_function(slow_function_time, timeout):\n            assert timeout < slow_function_time\n\n            with timeit_context() as timeit_result:\n                with pytest.raises(TimeoutException):\n                    with self.EXEC_TIMEOUT_CLASS(timeout) as exec_limit:\n                        self.slow_function(slow_function_time)\n\n            assert exec_limit.is_cancelled_by_timeout()\n            assert (\n                timeit_result.time_passed >= timeout\n                and timeit_result.time_passed < slow_function_time\n            )\n\n        t1_sleep, t1_timeout = 1, 0.6\n        t2_sleep, t2_timeout = 0.45, 0.1\n\n        t1 = Thread(target=partial(make_test_function, t1_sleep, t1_timeout))\n        t2 = Thread(target=partial(make_test_function, t2_sleep, t2_timeout))\n\n        with timeit_context() as time_t1:\n            t1.start()\n            with timeit_context() as time_t2:\n                t2.start()\n                t2.join()\n            t1.join()\n\n        assert t2_timeout <= time_t2.time_passed <= t2_sleep\n        assert t1_timeout <= time_t1.time_passed < t1_sleep\n\n\ndef test_supervisor_not_started():\n    \"\"\"Test that TestThreadGuard supervisor thread not started.\"\"\"\n    timeout = 0.1\n    sleep_time = 0.5\n\n    exec_limiter = ExecTimeoutThreadGuard(timeout)\n\n    with exec_limiter as exec_limit:\n        assert not exec_limiter._future_guard_task\n        TestThreadGuard.slow_function(sleep_time)\n\n    assert not exec_limit.is_cancelled_by_timeout()\n"
  },
  {
    "path": "tests/test_aea/test_helpers/test_file_io.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests for the 'helpers/file_io' module.\"\"\"\nimport os\nimport tempfile\nfrom pathlib import Path\nfrom unittest.mock import patch\n\nimport pytest\n\nimport aea\nfrom aea.configurations.base import PublicId\nfrom aea.helpers.file_io import _decode, envelope_from_bytes, lock_file, write_envelope\nfrom aea.mail.base import Envelope\n\n\nclass TestFileLock:\n    \"\"\"Test for filelocks.\"\"\"\n\n    def test_lock_file_ok(self):\n        \"\"\"Work ok ok for random file.\"\"\"\n        with tempfile.TemporaryFile() as fp:\n            with lock_file(fp):\n                pass\n\n    def test_lock_file_error(self):\n        \"\"\"Fail on closed file.\"\"\"\n        with tempfile.TemporaryFile() as fp:\n            fp.close()\n            with pytest.raises(ValueError):\n                with lock_file(fp):\n                    pass\n\n\ndef test_envelope_serialization():\n    \"\"\"Test envelope serialization/deserialization with files.\"\"\"\n    envelope = Envelope(\n        to=\"to\",\n        sender=\"sender\",\n        protocol_specification_id=PublicId(\"author\", \"name\", \"0.1.0\"),\n        message=b\"\",\n    )\n    with tempfile.TemporaryDirectory() as temp_dir:\n        output_file = Path(os.path.join(temp_dir, \"output_file\"))\n        with output_file.open(mode=\"wb\") as fout:\n            write_envelope(envelope, fout)\n\n        actual_envelope = envelope_from_bytes(output_file.read_bytes())\n\n    assert envelope == actual_envelope\n\n\ndef test_decode_fails():\n    \"\"\"Test decode fails.\"\"\"\n    with pytest.raises(\n        ValueError,\n        match=\"Expected at least 5 values separated by commas and last value being empty or new line, got 1\",\n    ):\n        _decode(b\"\")\n\n\ndef test_envelope_from_bytes_bad_format():\n    \"\"\"Test envelope_from_bytes, when the input has a bad format we raise ValueError.\"\"\"\n    test_error_message = \"Something bad happened.\"\n    _bytes = b\"\"\n    with patch(\n        \"aea.helpers.file_io._decode\", side_effect=ValueError(test_error_message)\n    ):\n        with patch.object(aea.helpers.file_io._default_logger, \"error\") as mock_error:\n            envelope_from_bytes(_bytes)\n            mock_error.assert_called_with(\n                f\"Bad formatted input: {_bytes}. {test_error_message}\"\n            )\n"
  },
  {
    "path": "tests/test_aea/test_helpers/test_install_dependency.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Test helper to install python dependecies.\"\"\"\nfrom unittest import mock\nfrom unittest.case import TestCase\n\nimport pytest\n\nfrom aea.configurations.base import Dependency\nfrom aea.exceptions import AEAException\nfrom aea.helpers.install_dependency import install_dependencies, install_dependency\n\n\nclass InstallDependencyTestCase(TestCase):\n    \"\"\"Test case for _install_dependency method.\"\"\"\n\n    def test__install_dependency_fails(self, *mocks):\n        \"\"\"Test for install_dependency method fails.\"\"\"\n        result = mock.Mock()\n        result.returncode = 1\n        with mock.patch(\"subprocess.run\", return_value=result):\n            with self.assertRaises(AEAException):\n                install_dependency(\"test\", Dependency(\"test\", \"==10.0.0\"), mock.Mock())\n\n    def test__install_dependency_ok(self, *mocks):\n        \"\"\"Test for install_dependency method ok.\"\"\"\n        result = mock.Mock()\n        result.returncode = 0\n        with mock.patch(\"subprocess.run\", return_value=result):\n            install_dependency(\"test\", Dependency(\"test\", \"==10.0.0\"), mock.Mock())\n\n    def test__install_dependency_fails_real_pip_call(self):\n        \"\"\"Test for install_dependency method fails.\"\"\"\n        with pytest.raises(AEAException, match=r\"No matching distribution found\"):\n            install_dependency(\n                \"testnotexists\", Dependency(\"testnotexists\", \"==10.0.0\"), mock.Mock()\n            )\n\n\nclass InstallDependenciesTestCase(TestCase):\n    \"\"\"Test case for _install_dependencies method.\"\"\"\n\n    def test_fails(self, *mocks):\n        \"\"\"Test for install_dependency method fails.\"\"\"\n        result = mock.Mock()\n        result.returncode = 1\n        with mock.patch(\"subprocess.run\", return_value=result):\n            with self.assertRaises(AEAException):\n                install_dependencies([Dependency(\"test\", \"==10.0.0\")], mock.Mock())\n\n    def test_ok(self, *mocks):\n        \"\"\"Test for install_dependency method ok.\"\"\"\n        result = mock.Mock()\n        result.returncode = 0\n        with mock.patch(\"subprocess.run\", return_value=result):\n            install_dependencies([Dependency(\"test\", \"==10.0.0\")], mock.Mock())\n\n    def test_fails_real_pip_call(self):\n        \"\"\"Test for install_dependency method fails.\"\"\"\n        with pytest.raises(AEAException, match=r\"No matching distribution found\"):\n            install_dependencies([Dependency(\"testnotexists\", \"==10.0.0\")], mock.Mock())\n\n        \"\"\"Test for install_dependency method fails.\"\"\"\n        with pytest.raises(AEAException, match=r\"No matching distribution found\"):\n            install_dependency(\n                \"testnotexists\", Dependency(\"testnotexists\", \"==10.0.0\"), mock.Mock()\n            )\n"
  },
  {
    "path": "tests/test_aea/test_helpers/test_io.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests for the 'aea.helpers.io' module.\"\"\"\nimport os\nfrom pathlib import Path\nfrom unittest.mock import MagicMock\n\nimport pytest\n\nfrom aea.helpers.io import open_file\n\n\n@pytest.mark.parametrize(argnames=\"path_builder\", argvalues=[os.path.join, Path])\ndef test_open_file(change_directory, path_builder):\n    \"\"\"Test 'open_file' for the built-in open.\"\"\"\n    expected_string = \"hello\\nworld\"\n    path = path_builder(change_directory, \"temporary-file\")\n    with open_file(path, \"w\") as file_out:\n        file_out.write(expected_string)\n\n    with open_file(path, \"r\") as file_in:\n        assert file_in.read() == expected_string\n\n    with open(path, \"rb\") as bytes_in:\n        assert bytes_in.read() == bytes(expected_string, encoding=\"utf-8\")\n\n\ndef test_raise_if_binary_mode():\n    \"\"\"Raise if mode is binary mode.\"\"\"\n    with pytest.raises(ValueError, match=\"This function can only work in text mode.\"):\n        open_file(MagicMock(), mode=\"rb\")\n"
  },
  {
    "path": "tests/test_aea/test_helpers/test_ipfs/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests for the ipfs helper module.\"\"\"\n"
  },
  {
    "path": "tests/test_aea/test_helpers/test_ipfs/test_base.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests for the ipfs helper module.\"\"\"\n\nimport os\nfrom unittest.mock import patch\n\nfrom aea.helpers.ipfs.base import IPFSHashOnly, _is_text\n\nfrom tests.conftest import CUR_PATH\n\n\nFILE_PATH = \"__init__.py\"\n\n\ndef test_get_hash():\n    \"\"\"Test get hash IPFSHashOnly.\"\"\"\n    ipfs_hash = IPFSHashOnly().get(file_path=os.path.join(CUR_PATH, FILE_PATH))\n    assert ipfs_hash == \"QmVyhvd64oCVNqs4Vg2zn8WE6UsK1tk1jTW4GEopcUVyuH\"\n\n\ndef test_is_text_negative():\n    \"\"\"Test the helper method 'is_text' negative case.\"\"\"\n    # https://gehrcke.de/2015/12/how-to-raise-unicodedecodeerror-in-python-3/\n    with patch(\n        \"aea.helpers.ipfs.base.open_file\",\n        side_effect=UnicodeDecodeError(\"foo\", b\"bytes\", 1, 2, \"Fake reason\"),\n    ):\n        assert not _is_text(\"path\")\n\n\ndef test_hash_for_big_file():\n    \"\"\"Check hash is ok for big amount of data with chunks support.\"\"\"\n    VALID_HASH = \"QmWt5fanMr2JbiaUAUpyLUL8FegGn95t5tHA6kgobXgWX3\"  # from ipfs daemon\n    data = b\"1\" * int(IPFSHashOnly.DEFAULT_CHUNK_SIZE * 1.5)\n    my_hash = IPFSHashOnly._generate_hash(data)\n    assert my_hash == VALID_HASH\n"
  },
  {
    "path": "tests/test_aea/test_helpers/test_logging.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests for the helpers/logging module.\"\"\"\nimport logging\nfrom unittest.mock import patch\n\nfrom aea.helpers.logging import AgentLoggerAdapter, WithLogger, get_logger\n\n\ndef test_get_logger():\n    \"\"\"Test the get_logger function.\"\"\"\n    module_path = \"some.dotted.module.path\"\n    agent_name = \"agent_name\"\n    expected_name = \"some.agent_name.dotted.module.path\"\n    logger = get_logger(module_path, agent_name)\n    assert logger.name == expected_name\n\n\ndef test_agent_logger_adapter():\n    \"\"\"Test the agent logger adapter.\"\"\"\n    logger = logging.getLogger(\"some.logger\")\n    logger = AgentLoggerAdapter(logger, agent_name=\"some_agent\")\n    logger.setLevel(\"DEBUG\")\n    with patch.object(logger.logger, \"log\") as mock_logger:\n        logger.debug(\"Some log message.\")\n        mock_logger.assert_any_call(logging.DEBUG, \"[some_agent] Some log message.\")\n\n\ndef test_with_logger_default_logger_name():\n    \"\"\"Test the WithLogger interface, default logger name.\"\"\"\n\n    class SomeClass(WithLogger):\n        pass\n\n    x = SomeClass()\n    assert isinstance(x.logger, logging.Logger)\n    with patch.object(x.logger, \"debug\") as mock_logger:\n        x.logger.debug(\"Some log message.\")\n        mock_logger.assert_any_call(\"Some log message.\")\n\n\ndef test_with_logger_custom_logger_name():\n    \"\"\"Test the WithLogger interface, custom logger name.\"\"\"\n\n    class SomeClass(WithLogger):\n        pass\n\n    x = SomeClass(default_logger_name=\"some.logger\")\n    assert isinstance(x.logger, logging.Logger)\n\n    with patch.object(x.logger, \"debug\") as mock_logger:\n        x.logger.debug(\"Some log message.\")\n        mock_logger.assert_any_call(\"Some log message.\")\n\n\ndef test_with_logger_custom_logger():\n    \"\"\"Test the WithLogger interface, custom logger.\"\"\"\n\n    class SomeClass(WithLogger):\n        pass\n\n    logger = logging.getLogger(\"some.logger\")\n    x = SomeClass(logger=logger)\n    assert isinstance(x.logger, logging.Logger)\n\n    with patch.object(x.logger, \"debug\") as mock_logger:\n        x.logger.debug(\"Some log message.\")\n        mock_logger.assert_any_call(\"Some log message.\")\n\n\ndef test_with_logger_setter():\n    \"\"\"Test the WithLogger interface, logger setter.\"\"\"\n\n    class SomeClass(WithLogger):\n        pass\n\n    logger_1 = logging.getLogger(\"some.logger\")\n    x = SomeClass(logger=logger_1)\n    assert isinstance(x.logger, logging.Logger)\n    assert x.logger.name == \"some.logger\"\n    logger_2 = logging.getLogger(\"another.logger\")\n    x.logger = logger_2\n    assert x.logger.name == \"another.logger\"\n"
  },
  {
    "path": "tests/test_aea/test_helpers/test_multiaddr.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests for MultiAddr helper class.\"\"\"\n\n\nimport tempfile\nfrom shutil import rmtree\n\nimport pytest\n\nfrom aea.configurations.constants import DEFAULT_LEDGER\nfrom aea.crypto.registries import make_crypto\nfrom aea.helpers.multiaddr.base import MultiAddr\n\n\nHOST = \"127.0.0.1\"\nPORT = 13000\n\nPRIV_KEY = \"b6dbe68a5b9bc135a3736a9b59892b6c806bf7594092de441f43e6d8609ea5fd\"\nPEER_ID = \"16Uiu2HAkw1VyY3RkiuMy38XKjb6w9EhbtXfwHkRpbQzNvXYVkG1T\"\n\n\ndef test_multiaddr_consistency():\n    \"\"\"Test multiaddress consistency.\"\"\"\n    key = make_crypto(DEFAULT_LEDGER)\n    maddr1 = MultiAddr(HOST, PORT, key.public_key)\n\n    tmpdir = tempfile.mkdtemp()\n    key_file = tmpdir + \"/key\"\n    key.dump(key_file)\n\n    key2 = make_crypto(DEFAULT_LEDGER, private_key_path=key_file)\n    maddr2 = MultiAddr(HOST, PORT, key2.public_key)\n\n    rmtree(tmpdir)\n\n    assert str(maddr1) == str(maddr2)\n    assert maddr1.public_key == maddr2.public_key\n    assert maddr1.peer_id == maddr2.peer_id\n\n\ndef test_multiaddr_correctness():\n    \"\"\"Test multiaddress correctness.\"\"\"\n    tmpdir = tempfile.mkdtemp()\n    key_file = tmpdir + \"/key\"\n    with open(key_file, \"w+\") as k:\n        k.write(PRIV_KEY)\n\n    key = make_crypto(DEFAULT_LEDGER, private_key_path=key_file)\n    maddr = MultiAddr(HOST, PORT, key.public_key)\n\n    rmtree(tmpdir)\n\n    assert maddr._peerid == PEER_ID\n\n\ndef test_multiaddr_from_string():\n    \"\"\"Test multiaddress from string\"\"\"\n    maddr_str = \"/dns4/\" + HOST + \"/tcp/\" + str(PORT) + \"/p2p/\"\n    maddr = MultiAddr.from_string(maddr_str + PEER_ID)\n    assert maddr.host == HOST and maddr.port == PORT and maddr.peer_id == PEER_ID\n\n    with pytest.raises(ValueError):\n        MultiAddr.from_string(\"\")\n\n    with pytest.raises(ValueError):\n        MultiAddr.from_string(maddr_str + \"wrong-peer-id\")\n"
  },
  {
    "path": "tests/test_aea/test_helpers/test_multiple_executor.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests for the helpers.multiple_executor.\"\"\"\n\nimport asyncio\nfrom asyncio.events import AbstractEventLoop\n\nfrom aea.helpers.multiple_executor import AbstractExecutorTask, TaskAwaitable\n\n\nclass Task(AbstractExecutorTask):\n    \"\"\"Simple Executor Task for testing.\"\"\"\n\n    def start(self):\n        \"\"\"Implement start task function here.\"\"\"\n        pass\n\n    def stop(self) -> None:\n        \"\"\"Implement stop task function here.\"\"\"\n        pass\n\n    def create_async_task(self, loop: AbstractEventLoop) -> TaskAwaitable:\n        \"\"\"\n        Create asyncio task for task run in asyncio loop.\n\n        :param loop: the event loop\n        :return: task to run in asyncio loop.\n        \"\"\"\n        pass\n\n\ndef test_task_failed():\n    \"\"\"Test task failed.\"\"\"\n    task = Task()\n    assert not task.failed\n\n    task.future = asyncio.Future()\n    assert not task.failed\n\n    task.future.set_result(None)\n\n    assert not task.failed\n\n    task.future = asyncio.Future()\n    task.future.set_exception(KeyboardInterrupt())\n\n    assert not task.failed\n\n    task.future = asyncio.Future()\n    task.future.set_exception(ValueError())\n\n    assert task.failed\n"
  },
  {
    "path": "tests/test_aea/test_helpers/test_pipe/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests for portable IPC pipe module.\"\"\"\n"
  },
  {
    "path": "tests/test_aea/test_helpers/test_pipe/test_pipe.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Tests for the pipe module.\"\"\"\nimport asyncio\nfrom threading import Thread\n\nimport pytest\n\nfrom aea.helpers.pipe import (\n    IPCChannelClient,\n    PosixNamedPipeChannel,\n    PosixNamedPipeChannelClient,\n    TCPSocketChannel,\n    TCPSocketChannelClient,\n    make_ipc_channel,\n    make_ipc_channel_client,\n)\n\nfrom tests.conftest import skip_test_windows\n\n\ndef _run_echo_service(client: IPCChannelClient):\n    async def echo_service(client: IPCChannelClient):\n        try:\n            await client.connect()\n            while True:\n                data = await client.read()\n                if not data:\n                    break\n                await client.write(data)\n        except (asyncio.IncompleteReadError, asyncio.CancelledError, OSError):\n            pass\n        finally:\n            await client.close()\n\n    loop = asyncio.new_event_loop()\n    loop.run_until_complete(echo_service(client))\n\n\n@pytest.mark.asyncio\nclass TestAEAHelperMakePipe:\n    \"\"\"Test that make_ipc_channel utility and abstract class IPCChannel work properly\"\"\"\n\n    @pytest.mark.asyncio\n    async def test_connection_communication(self):\n        \"\"\"Test connection communication.\"\"\"\n        pipe = make_ipc_channel()\n        assert (\n            pipe.in_path is not None and pipe.out_path is not None\n        ), \"Pipe not properly setup\"\n\n        connected = asyncio.ensure_future(pipe.connect())\n\n        client_pipe = make_ipc_channel_client(pipe.out_path, pipe.in_path)\n\n        client = Thread(target=_run_echo_service, args=[client_pipe])\n        client.start()\n\n        try:\n            assert await connected, \"Failed to connect pipe\"\n\n            message = b\"hello\"\n            await pipe.write(message)\n            received = await pipe.read()\n\n            assert received == message, \"Echoed message differs\"\n\n        except Exception:\n            raise\n        finally:\n            await pipe.close()\n            client.join()\n\n\n@pytest.mark.asyncio\nclass TestAEAHelperTCPSocketChannel:\n    \"\"\"Test that TCPSocketChannel work properly\"\"\"\n\n    @pytest.mark.asyncio\n    async def test_connection_communication(self):\n        \"\"\"Test connection communication.\"\"\"\n        pipe = TCPSocketChannel()\n        assert (\n            pipe.in_path is not None and pipe.out_path is not None\n        ), \"TCPSocketChannel not properly setup\"\n\n        connected = asyncio.ensure_future(pipe.connect())\n\n        client_pipe = TCPSocketChannelClient(pipe.out_path, pipe.in_path)\n\n        client = Thread(target=_run_echo_service, args=[client_pipe])\n        client.start()\n\n        try:\n            assert await connected, \"Failed to connect pipe\"\n\n            message = b\"hello\"\n            await pipe.write(message)\n            received = await pipe.read()\n\n            assert received == message, \"Echoed message differs\"\n\n        except Exception:\n            raise\n        finally:\n            await pipe.close()\n            client.join()\n\n    @pytest.mark.asyncio\n    async def test_connection_refused(self):\n        \"\"\"Test connection refused.\"\"\"\n        pipe = TCPSocketChannel()\n        assert (\n            pipe.in_path is not None and pipe.out_path is not None\n        ), \"TCPSocketChannel not properly setup\"\n\n        client_pipe = TCPSocketChannelClient(pipe.out_path, pipe.in_path)\n\n        connected = await client_pipe.connect()\n        assert connected is False\n\n\ndef make_future(result) -> asyncio.Future:\n    \"\"\"Make future for value.\"\"\"\n    f = asyncio.Future()  # type: ignore\n    f.set_result(result)\n    return f\n\n\n@skip_test_windows\n@pytest.mark.asyncio\nclass TestAEAHelperPosixNamedPipeChannel:\n    \"\"\"Test that TCPSocketChannel work properly\"\"\"\n\n    @pytest.mark.asyncio\n    async def test_connection_communication(self):\n        \"\"\"Test connection communication.\"\"\"\n        pipe = PosixNamedPipeChannel()\n        assert (\n            pipe.in_path is not None and pipe.out_path is not None\n        ), \"PosixNamedPipeChannel not properly setup\"\n\n        connected = asyncio.ensure_future(pipe.connect())\n\n        client_pipe = PosixNamedPipeChannelClient(pipe.out_path, pipe.in_path)\n\n        client = Thread(target=_run_echo_service, args=[client_pipe])\n        client.start()\n\n        try:\n            assert await connected, \"Failed to connect pipe\"\n\n            message = b\"hello\"\n            await pipe.write(message)\n            received = await pipe.read()\n\n            assert received == message, \"Echoed message differs\"\n\n        except Exception:\n            raise\n        finally:\n            await pipe.close()\n            client.join()\n"
  },
  {
    "path": "tests/test_aea/test_helpers/test_preference_representations/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests for the preference representations helper module.\"\"\"\n"
  },
  {
    "path": "tests/test_aea/test_helpers/test_preference_representations/test_base.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests for the preference representations helper module.\"\"\"\n\nfrom aea.helpers.preference_representations.base import (\n    linear_utility,\n    logarithmic_utility,\n)\n\n\ndef test_logarithmic_utility():\n    \"\"\"Test logarithmic utlity.\"\"\"\n    assert (\n        logarithmic_utility(\n            utility_params_by_good_id={\"good_1\": 0.2, \"good_2\": 0.8},\n            quantities_by_good_id={\"good_1\": 2, \"good_2\": 1},\n        )\n        > 0\n    ), \"Utility should be positive.\"\n\n\ndef test_linear_utility():\n    \"\"\"Test logarithmic utlity.\"\"\"\n    assert (\n        linear_utility(\n            exchange_params_by_currency_id={\"cur_1\": 0.2, \"cur_2\": 0.8},\n            balance_by_currency_id={\"cur_1\": 20, \"cur_2\": 100},\n        )\n        > 0\n    ), \"Utility should be positive.\"\n"
  },
  {
    "path": "tests/test_aea/test_helpers/test_profiling.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests for the helpers/profiling module.\"\"\"\nfrom aea.helpers.profiling import Profiling\nfrom aea.protocols.base import Message\n\nfrom tests.common.utils import wait_for_condition\n\n\ndef test_profiling():\n    \"\"\"Test profiling tool.\"\"\"\n    result = \"\"\n\n    def output_function(report):\n        nonlocal result\n        result = report\n\n    p = Profiling(1, [Message], [Message], output_function=output_function)\n    p.start()\n\n    wait_for_condition(lambda: p.is_running, timeout=20)\n    m = Message()\n    try:\n        wait_for_condition(lambda: result, timeout=20)\n\n        assert \"Profiling details\" in result\n    finally:\n        p.stop()\n        p.wait_completed(sync=True, timeout=20)\n    del m\n"
  },
  {
    "path": "tests/test_aea/test_helpers/test_search/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests for the search helper module.\"\"\"\n"
  },
  {
    "path": "tests/test_aea/test_helpers/test_search/base.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests for the search helper module.\"\"\"\n\nfrom aea.helpers.search.models import Location\n\n\ndef test_location_init():\n    \"\"\"Test the initialization of the location model\"\"\"\n    latitude = 51.507351\n    longitude = -0.127758\n    loc = Location(latitude, longitude)\n    latitude_2 = 48.856613\n    longitude_2 = 2.352222\n    loc2 = Location(latitude_2, longitude_2)\n    assert loc != loc2, \"Locations should not be the same.\"\n    assert loc.distance(loc2) > 0.0, \"Locations should be positive.\"\n"
  },
  {
    "path": "tests/test_aea/test_helpers/test_search/test_generic.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests for the helpers.search.generic.\"\"\"\n\nimport pytest\n\nfrom aea.exceptions import AEAEnforceError\nfrom aea.helpers.search.generic import GenericDataModel\n\n\ndef test_generic_data_model():\n    \"\"\"Test generic data model creation.\"\"\"\n    # ok\n    GenericDataModel(\n        \"test\", {\"attr1\": {\"name\": \"attr1\", \"type\": \"str\", \"is_required\": True}}\n    )\n\n    # bad type\n    with pytest.raises(AEAEnforceError):\n        GenericDataModel(\n            \"test\",\n            {\"attr1\": {\"name\": \"attr1\", \"type\": \"bad type\", \"is_required\": True}},\n        )\n\n    # bad name\n    with pytest.raises(AEAEnforceError):\n        GenericDataModel(\n            \"test\", {\"attr1\": {\"name\": 1231, \"type\": \"str\", \"is_required\": True}}\n        )\n\n    # bad is required\n    with pytest.raises(AEAEnforceError):\n        GenericDataModel(\n            \"test\", {\"attr1\": {\"name\": \"attr1\", \"type\": \"str\", \"is_required\": \"True\"}}\n        )\n"
  },
  {
    "path": "tests/test_aea/test_helpers/test_search/test_models.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests for the helpers.search.models.\"\"\"\nimport re\nfrom unittest.mock import MagicMock\n\nimport pytest\n\nfrom aea.exceptions import AEAEnforceError\nfrom aea.helpers.search.models import (\n    And,\n    Attribute,\n    AttributeInconsistencyException,\n    Constraint,\n    ConstraintExpr,\n    ConstraintType,\n    ConstraintTypes,\n    DataModel,\n    Description,\n    Location,\n    Not,\n    Or,\n    Query,\n    generate_data_model,\n)\n\n\ndef test_location():\n    \"\"\"Test Location type.\"\"\"\n    location = Location(latitude=1.1, longitude=2.2)\n    assert location is not None\n\n    assert location.tuple == (location.latitude, location.longitude)\n    assert location.distance(Location(1.1, 2.2)) == 0\n    assert location == Location(1.1, 2.2)\n    assert str(location) == \"Location(latitude=1.1,longitude=2.2)\"\n\n    location_pb = location.encode()\n    actual_location = Location.decode(location_pb)\n    assert actual_location == location\n    assert location.latitude == actual_location.latitude\n    assert location.longitude == actual_location.longitude\n\n\ndef test_attribute():\n    \"\"\"Test data model Attribute.\"\"\"\n    params = dict(name=\"test\", type_=str, is_required=True)\n    attribute = Attribute(**params)\n    assert attribute is not None\n\n    assert attribute == Attribute(**params)\n    assert attribute != Attribute(name=\"another\", type_=int, is_required=True)\n\n    assert str(attribute) == \"Attribute(name=test,type=<class 'str'>,is_required=True)\"\n\n    attribute_pb = attribute.encode()\n    actual_attribute = Attribute.decode(attribute_pb)\n    assert actual_attribute == attribute\n\n\ndef test_data_model():\n    \"\"\"Test data model definitions.\"\"\"\n    params = dict(name=\"test\", type_=str, is_required=True)\n    data_model = DataModel(\"test\", [Attribute(**params)])\n\n    data_model._check_validity()\n    with pytest.raises(\n        ValueError,\n        match=\"Invalid input value for type 'DataModel': duplicated attribute name.\",\n    ):\n        data_model = DataModel(\"test\", [Attribute(**params), Attribute(**params)])\n        data_model._check_validity()\n\n    assert data_model == DataModel(\"test\", [Attribute(**params)])\n    assert data_model != DataModel(\"not test\", [Attribute(**params)])\n\n    assert (\n        str(data_model)\n        == \"DataModel(name=test,attributes={'test': \\\"Attribute(name=test,type=<class 'str'>,is_required=True)\\\"},description=)\"\n    )\n\n    data_model_pb = data_model.encode()\n    actual_data_model = DataModel.decode(data_model_pb)\n    assert actual_data_model == data_model\n\n\ndef test_generate_data_model():\n    \"\"\"Test model generated from description.\"\"\"\n    params = dict(name=\"test\", type_=str, is_required=True)\n\n    data_model = DataModel(\"test\", [Attribute(**params)])\n\n    assert generate_data_model(\"test\", {\"test\": \"str\"}) == data_model\n\n\ndef test_description():\n    \"\"\"Test model description.\"\"\"\n    values = {\n        \"test\": \"test_value\",\n        \"bool\": True,\n        \"float\": 1.1,\n        \"int\": int(1),\n        \"loc\": Location(1, 1),\n    }\n    description = Description(\n        values=values, data_model=generate_data_model(\"test\", values)\n    )\n\n    assert description.values == values\n    assert description == Description(\n        values=values, data_model=generate_data_model(\"test\", values)\n    )\n    assert list(description.values.values()) == list(values.values())\n    assert list(description) == list(values)\n\n    with pytest.raises(\n        AttributeInconsistencyException, match=r\"Missing required attribute.\"\n    ):\n        Description(\n            values=values, data_model=generate_data_model(\"test\", {\"extra_key\": \"key\"})\n        )\n    with pytest.raises(\n        AttributeInconsistencyException,\n        match=r\"Have extra attribute not in data model.\",\n    ):\n        Description(values=values, data_model=generate_data_model(\"test\", {}))\n    with pytest.raises(\n        AttributeInconsistencyException, match=r\".* has incorrect type:.*\"\n    ):\n        Description(\n            values=values,\n            data_model=generate_data_model(\"test\", {**values, \"test\": 12}),\n        )\n\n    with pytest.raises(\n        AttributeInconsistencyException, match=r\".* has unallowed type:.*\"\n    ):\n        Description(\n            values={\"test\": object()},\n            data_model=generate_data_model(\"test\", {\"test\": object()}),\n        )\n\n    assert re.match(r\"Description\\(values=.*data_model=.*\", str(description))\n\n    description_pb = description._encode()\n    actual_description = Description._decode(description_pb)\n    assert actual_description == description\n\n    mock = MagicMock()\n    mock.description_bytes = None\n    Description.encode(mock, description)\n    assert mock.description_bytes is not None\n    description = Description.decode(mock)\n    assert \"test\" in description.values\n\n\ndef test_constraint_type():\n    \"\"\"Test ConstraintType.\"\"\"\n    constraint_type_values = {\n        \"int\": 12,\n        \"bool\": True,\n        \"float\": 10.4,\n        \"str\": \"some_string\",\n        \"location\": Location(1.1, 2.2),\n    }\n    constraint_type_types = {\n        \"int\": int,\n        \"bool\": bool,\n        \"float\": float,\n        \"str\": str,\n        \"location\": Location,\n    }\n    to_check = {\n        \"int\": 13,\n        \"bool\": False,\n        \"float\": 9.3,\n        \"str\": \"some_other_string\",\n        \"location\": Location(1.2, 2.3),\n    }\n\n    # = and !=\n    for constraint_types_type in [ConstraintTypes.EQUAL, ConstraintTypes.NOT_EQUAL]:\n        for allowed_type in [\"int\", \"bool\", \"float\", \"str\"]:\n            constraint_type = ConstraintType(\n                constraint_types_type, constraint_type_values[allowed_type]\n            )\n            constraint_type.is_valid(\n                Attribute(\"test\", constraint_type_types[allowed_type], True)\n            )\n            constraint_type.check(to_check[allowed_type])\n            assert constraint_type == ConstraintType(\n                constraint_types_type, constraint_type_values[allowed_type]\n            )\n            assert (\n                str(constraint_type)\n                == f\"ConstraintType(value={constraint_type_values[allowed_type]},type={constraint_types_type})\"\n            )\n\n            constraint_type_pb = constraint_type.encode()\n            actual_constraint_type = ConstraintType.decode(\n                constraint_type_pb, \"relation\"\n            )\n            assert actual_constraint_type == constraint_type\n\n    # < and <= and > and >=\n    for constraint_types_type in [\n        ConstraintTypes.LESS_THAN,\n        ConstraintTypes.LESS_THAN_EQ,\n        ConstraintTypes.GREATER_THAN,\n        ConstraintTypes.GREATER_THAN_EQ,\n    ]:\n        for allowed_type in [\"int\", \"float\", \"str\"]:\n            constraint_type = ConstraintType(\n                constraint_types_type, constraint_type_values[allowed_type]\n            )\n            constraint_type.is_valid(\n                Attribute(\"test\", constraint_type_types[allowed_type], True)\n            )\n            constraint_type.check(to_check[allowed_type])\n            assert constraint_type == ConstraintType(\n                constraint_types_type, constraint_type_values[allowed_type]\n            )\n            assert (\n                str(constraint_type)\n                == f\"ConstraintType(value={constraint_type_values[allowed_type]},type={constraint_types_type})\"\n            )\n\n            constraint_type_pb = constraint_type.encode()\n            actual_constraint_type = ConstraintType.decode(\n                constraint_type_pb, \"relation\"\n            )\n            assert actual_constraint_type == constraint_type\n\n    # within\n    constraint_type_values = {\n        \"int\": (1, 2),\n        \"float\": (2.4, 5.4),\n        \"str\": (\"str_1\", \"str_2\"),\n        \"location\": (Location(1.1, 2.2), Location(1.2, 5.2)),\n    }\n    constraint_type_types = {\n        \"int\": int,\n        \"float\": float,\n        \"str\": str,\n        \"location\": Location,\n    }\n    to_check = {\n        \"int\": 13,\n        \"float\": 9.3,\n        \"str\": \"some_other_string\",\n        \"location\": Location(1.2, 2.3),\n    }\n\n    for range_constraint_type in [\"int\", \"float\", \"str\"]:  # location is not working\n        constraint_type = ConstraintType(\n            ConstraintTypes.WITHIN, constraint_type_values[range_constraint_type]\n        )\n        constraint_type.is_valid(\n            Attribute(\"test\", constraint_type_types[range_constraint_type], True)\n        )\n        constraint_type.check(to_check[range_constraint_type])\n        assert constraint_type == ConstraintType(\n            ConstraintTypes.WITHIN, constraint_type_values[range_constraint_type]\n        )\n        assert (\n            str(constraint_type)\n            == f\"ConstraintType(value={constraint_type_values[range_constraint_type]},type=within)\"\n        )\n        constraint_type_pb = constraint_type.encode()\n        actual_constraint_type = ConstraintType.decode(constraint_type_pb, \"range\")\n        assert actual_constraint_type == constraint_type\n\n    # in and not_in\n    constraint_type_values = {\n        \"int\": (1, 2),\n        \"bool\": (True, False),\n        \"float\": (2.4, 5.4),\n        \"str\": (\"str_1\", \"str_2\"),\n        \"location\": (Location(1.1, 2.2), Location(1.2, 5.2)),\n    }\n    constraint_type_types = {\n        \"int\": int,\n        \"bool\": bool,\n        \"float\": float,\n        \"str\": str,\n        \"location\": Location,\n    }\n    to_check = {\n        \"int\": 13,\n        \"bool\": False,\n        \"float\": 9.3,\n        \"str\": \"some_other_string\",\n        \"location\": Location(1.2, 2.3),\n    }\n\n    for constraint_types_type in [ConstraintTypes.IN, ConstraintTypes.NOT_IN]:\n        for constraint_set in [\"int\", \"bool\", \"float\", \"str\", \"location\"]:\n            constraint_type = ConstraintType(\n                constraint_types_type, constraint_type_values[constraint_set]\n            )\n            constraint_type.is_valid(\n                Attribute(\"test\", constraint_type_types[constraint_set], True)\n            )\n            constraint_type.check(to_check[constraint_set])\n            assert constraint_type == ConstraintType(\n                constraint_types_type, constraint_type_values[constraint_set]\n            )\n            assert (\n                str(constraint_type)\n                == f\"ConstraintType(value={constraint_type_values[constraint_set]},type={constraint_types_type})\"\n            )\n            constraint_type_pb = constraint_type.encode()\n            actual_constraint_type = ConstraintType.decode(constraint_type_pb, \"set\")\n            assert actual_constraint_type == constraint_type\n\n    # distance\n    constraint_location = (Location(1.1, 2.2), 2.2)\n    constraint_type_distance = ConstraintType(\n        ConstraintTypes.DISTANCE, constraint_location\n    )\n    constraint_type_distance.is_valid(Attribute(\"test\", int, True))\n    constraint_type_distance.check(Location(1.1, 2.2))\n    assert constraint_type_distance == ConstraintType(\n        ConstraintTypes.DISTANCE, constraint_location\n    )\n    constraint_type_distance_pb = constraint_type_distance.encode()\n    actual_constraint_type_distance = ConstraintType.decode(\n        constraint_type_distance_pb, \"distance\"\n    )\n    assert actual_constraint_type_distance == constraint_type_distance\n\n    # failures\n    with pytest.raises(ValueError):\n        ConstraintType(\"something\", [Location(1.1, 2.2), 2.2]).is_valid(\n            Attribute(\"test\", int, True)\n        )\n\n    with pytest.raises(AEAEnforceError, match=\"\"):\n        ConstraintType(ConstraintTypes.GREATER_THAN, str)\n\n    list_value = [1, 2]\n    set_value = {1, 2}\n    list_location = [Location(1.1, 2.2), 2.2]\n\n    with pytest.raises(\n        AEAEnforceError, match=f\"Expected tuple, got {type(list_value)}\"\n    ):\n        ConstraintType(ConstraintTypes.WITHIN, list_value)\n\n    with pytest.raises(\n        AEAEnforceError, match=f\"Expected tuple, got {type(list_value)}\"\n    ):\n        ConstraintType(ConstraintTypes.IN, list_value)\n\n    with pytest.raises(AEAEnforceError, match=f\"Expected tuple, got {type(set_value)}\"):\n        ConstraintType(ConstraintTypes.IN, set_value)\n\n    with pytest.raises(\n        AEAEnforceError, match=f\"Expected tuple, got {type(list_value)}\"\n    ):\n        ConstraintType(ConstraintTypes.NOT_IN, list_value)\n\n    with pytest.raises(AEAEnforceError, match=f\"Expected tuple, got {type(set_value)}\"):\n        ConstraintType(ConstraintTypes.NOT_IN, set_value)\n\n    with pytest.raises(\n        AEAEnforceError, match=f\"Expected tuple, got {type(list_location)}\"\n    ):\n        ConstraintType(ConstraintTypes.DISTANCE, list_location)\n\n    incorrect_category = \"some_incorrect_category\"\n    with pytest.raises(\n        ValueError,\n        match=r\"Incorrect category. Expected either of .* Found some_incorrect_category.\",\n    ):\n        constraint_type_distance_pb = constraint_type_distance.encode()\n        ConstraintType.decode(constraint_type_distance_pb, incorrect_category)\n\n\ndef test_constraints_expression():\n    \"\"\"Test constraint expressions: And, Or, Not, Constraint.\"\"\"\n    and_expression = And(\n        [\n            Constraint(\"number\", ConstraintType(ConstraintTypes.LESS_THAN, 15)),\n            Constraint(\"number\", ConstraintType(ConstraintTypes.GREATER_THAN, 10)),\n        ]\n    )\n    and_expression.check_validity()\n    assert and_expression.check(Description({\"number\": 12}))\n    assert and_expression.is_valid(\n        DataModel(\"some_name\", [Attribute(\"number\", int, True)])\n    )\n    and_expression_pb = ConstraintExpr._encode(and_expression)\n    actual_and_expression = ConstraintExpr._decode(and_expression_pb)\n    assert actual_and_expression == and_expression\n\n    or_expression = Or(\n        [\n            Constraint(\"number\", ConstraintType(ConstraintTypes.EQUAL, 12)),\n            Constraint(\"number\", ConstraintType(ConstraintTypes.EQUAL, 13)),\n        ]\n    )\n    or_expression.check_validity()\n    assert or_expression.check(Description({\"number\": 12}))\n    assert or_expression.is_valid(\n        DataModel(\"some_name\", [Attribute(\"number\", int, True)])\n    )\n    or_expression_pb = ConstraintExpr._encode(or_expression)\n    actual_or_expression = ConstraintExpr._decode(or_expression_pb)\n    assert actual_or_expression == or_expression\n\n    not_expression = Not(\n        And(\n            [\n                Constraint(\"number\", ConstraintType(ConstraintTypes.EQUAL, 12)),\n                Constraint(\"number\", ConstraintType(ConstraintTypes.EQUAL, 12)),\n            ]\n        )\n    )\n    not_expression.check_validity()\n    assert not_expression.check(Description({\"number\": 13}))\n    assert not_expression.is_valid(\n        DataModel(\"some_name\", [Attribute(\"number\", int, True)])\n    )\n    not_expression_pb = ConstraintExpr._encode(not_expression)\n    actual_not_expression = ConstraintExpr._decode(not_expression_pb)\n    assert actual_not_expression == not_expression\n\n    # constraint\n    constraint_expression = Constraint(\"author\", ConstraintType(\"==\", \"Stephen King\"))\n    constraint_expression.check_validity()\n    assert constraint_expression.check(Description({\"author\": \"Stephen King\"}))\n    assert constraint_expression.is_valid(\n        DataModel(\"some_name\", [Attribute(\"author\", str, True)])\n    )\n    constraint_expression_pb = ConstraintExpr._encode(constraint_expression)\n    actual_constraint_expression = ConstraintExpr._decode(constraint_expression_pb)\n    assert actual_constraint_expression == constraint_expression\n\n    incorrect_expression = Location(1.1, 2.2)\n    with pytest.raises(\n        ValueError,\n        match=f\"Invalid expression type. Expected either of 'And', 'Or', 'Not', 'Constraint'. Found {type(incorrect_expression)}.\",\n    ):\n        ConstraintExpr._encode(incorrect_expression)\n\n\ndef test_constraints_and():\n    \"\"\"Test And.\"\"\"\n    and_expression = And(\n        [\n            Constraint(\"number\", ConstraintType(ConstraintTypes.LESS_THAN, 15)),\n            Constraint(\"number\", ConstraintType(ConstraintTypes.GREATER_THAN, 10)),\n        ]\n    )\n    and_expression.check_validity()\n    assert and_expression.check(Description({\"number\": 12}))\n    assert and_expression.is_valid(\n        DataModel(\"some_name\", [Attribute(\"number\", int, True)])\n    )\n    and_expression_pb = and_expression.encode()\n    actual_and_expression = And.decode(and_expression_pb)\n    assert actual_and_expression == and_expression\n\n\ndef test_constraints_or():\n    \"\"\"Test Or.\"\"\"\n    or_expression = Or(\n        [\n            Constraint(\"number\", ConstraintType(ConstraintTypes.EQUAL, 12)),\n            Constraint(\"number\", ConstraintType(ConstraintTypes.EQUAL, 13)),\n        ]\n    )\n    or_expression.check_validity()\n    assert or_expression.check(Description({\"number\": 12}))\n    assert or_expression.is_valid(\n        DataModel(\"some_name\", [Attribute(\"number\", int, True)])\n    )\n    or_expression_pb = or_expression.encode()\n    actual_or_expression = Or.decode(or_expression_pb)\n    assert actual_or_expression == or_expression\n\n\ndef test_constraints_not():\n    \"\"\"Test Not.\"\"\"\n    not_expression = Not(\n        And(\n            [\n                Constraint(\"number\", ConstraintType(ConstraintTypes.EQUAL, 12)),\n                Constraint(\"number\", ConstraintType(ConstraintTypes.EQUAL, 12)),\n            ]\n        )\n    )\n    not_expression.check_validity()\n    assert not_expression.check(Description({\"number\": 13}))\n    assert not_expression.is_valid(\n        DataModel(\"some_name\", [Attribute(\"number\", int, True)])\n    )\n    not_expression_pb = not_expression.encode()\n    actual_not_expression = Not.decode(not_expression_pb)\n    assert actual_not_expression == not_expression\n\n\ndef test_constraint():\n    \"\"\"Test Constraint.\"\"\"\n    c1 = Constraint(\"author\", ConstraintType(\"==\", \"Stephen King\"))\n    c2 = Constraint(\"year\", ConstraintType(\"within\", (2000, 2010)))\n    c3 = Constraint(\"author\", ConstraintType(\"in\", (\"Stephen King\", \"J. K. Rowling\")))\n    c4 = Constraint(\n        \"author\", ConstraintType(\"not_in\", (\"Stephen King\", \"J. K. Rowling\"))\n    )\n    c5 = Constraint(\"address\", ConstraintType(\"distance\", (Location(1.1, 2.2), 2.2)))\n\n    book_1 = Description(\n        {\"author\": \"Stephen King\", \"year\": 2005, \"address\": Location(1.1, 2.2)}\n    )\n    book_2 = Description(\n        {\"author\": \"George Orwell\", \"year\": 1948, \"address\": Location(1.1, 2.2)}\n    )\n\n    assert c1.check(book_1)\n    assert not c1.check(book_2)\n    # empty description\n    assert not c1.check(Description({}))\n    # bad type\n    assert not c1.check(Description({\"author\": 12}))\n    # bad type\n    assert not c2.check(Description({\"author\": 12}))\n\n    assert c1.is_valid(generate_data_model(\"test\", {\"author\": \"some author\"}))\n    assert not c1.is_valid(generate_data_model(\"test\", {\"not_author\": \"some author\"}))\n\n    assert c1 == c1\n    assert c1 != c2\n\n    assert (\n        str(c1)\n        == f\"Constraint(attribute_name=author,constraint_type={c1.constraint_type})\"\n    )\n    assert (\n        str(c2)\n        == f\"Constraint(attribute_name=year,constraint_type={c2.constraint_type})\"\n    )\n\n    c1_pb = c1.encode()\n    actual_c1 = Constraint.decode(c1_pb)\n    assert actual_c1 == c1\n\n    c2_pb = c2.encode()\n    actual_c2 = Constraint.decode(c2_pb)\n    assert actual_c2 == c2\n\n    c3_pb = c3.encode()\n    actual_c3 = Constraint.decode(c3_pb)\n    assert actual_c3 == c3\n\n    c4_pb = c4.encode()\n    actual_c4 = Constraint.decode(c4_pb)\n    assert actual_c4 == c4\n\n    c5_pb = c5.encode()\n    actual_c5 = Constraint.decode(c5_pb)\n    assert actual_c5 == c5\n\n\ndef test_query():\n    \"\"\"Test Query.\"\"\"\n    c1 = Constraint(\"author\", ConstraintType(\"==\", \"Stephen King\"))\n    model = generate_data_model(\"book_author\", {\"author\": \"author of the book\"})\n    query = Query([c1], model=model)\n\n    assert query.check(\n        Description({\"author\": \"Stephen King\", \"year\": 1991, \"genre\": \"horror\"})\n    )\n    assert query.is_valid(generate_data_model(\"test\", {\"author\": \"some author\"}))\n\n    query.check_validity()\n    with pytest.raises(ValueError, match=r\"Constraints must be a list .*\"):\n        query = Query(c1)\n    Query([]).check_validity()\n    with pytest.raises(\n        ValueError,\n        match=r\"Invalid input value for type 'Query': the query is not valid for the given data model.\",\n    ):\n        Query(\n            [c1], generate_data_model(\"test\", {\"notauthor\": \"not some author\"})\n        ).check_validity()\n\n    assert query == Query(\n        [c1], model=generate_data_model(\"book_author\", {\"author\": \"author of the book\"})\n    )\n\n    assert (\n        str(query)\n        == f\"Query(constraints=['Constraint(attribute_name=author,constraint_type=ConstraintType(value=Stephen King,type===))'],model={model})\"\n    )\n\n    query_pb = query._encode()\n    actual_query = Query._decode(query_pb)\n    assert actual_query == query\n\n    query_pb = MagicMock()\n    query_pb.query_bytes = None\n    Query.encode(query_pb, query)\n    assert query_pb.query_bytes is not None\n    query = Query.decode(query_pb)\n    assert \"author\" in query.model.attributes_by_name\n"
  },
  {
    "path": "tests/test_aea/test_helpers/test_serializers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests for the helpers/serializers module.\"\"\"\nimport pytest\n\nfrom aea.helpers.serializers import DictProtobufStructSerializer\n\n\ndef test_encode_decode_i():\n    \"\"\"Test encode decode logic.\"\"\"\n    case = {\n        \"bool_true\": True,\n        \"bool_False\": False,\n        \"none\": None,\n        \"float\": 0.12,\n        \"int\": 100,\n        \"str\": \"some string\",\n        \"bytes\": b\"some bytes string\",\n        \"empty dict\": {},\n        \"list_of_bytes\": [b\"1234\", b\"234234\"],\n        \"list_of_ints\": [1, 2, 3],\n        \"list_of_str\": [\"1234\", \"234234\"],\n        \"list_of_floats\": [1.1, 2.2, 3.0],\n        \"nested_dict\": {\n            \"bool_true\": True,\n            \"bool_False\": False,\n            \"none\": None,\n            \"float\": 0.12,\n            \"int\": 100,\n            \"str\": \"some string\",\n            \"bytes\": b\"some bytes string\",\n            \"empty dict\": {},\n            \"list_of_bytes\": [b\"1234\", b\"234234\"],\n            \"list_of_ints\": [1, 2, 3],\n            \"list_of_str\": [\"1234\", \"234234\"],\n            \"list_of_floats\": [1.1, 2.2, 3.0],\n            \"list\": [{\"a\": 1, \"b\": {\"c\": 12}}, {\"b\": b\"234\", \"x\": [1, 2, 3]}],\n        },\n        \"list_of_dict\": {\n            \"list\": [{\"a\": 1, \"b\": {\"c\": 12}}, {\"b\": b\"234\", \"x\": [1, 2, 3]}]\n        },\n    }\n    encoded = DictProtobufStructSerializer.encode(case)\n    assert isinstance(encoded, bytes)\n    decoded = DictProtobufStructSerializer.decode(encoded)\n    assert case == decoded\n\n\ndef test_error_type_not_supported():\n    \"\"\"Test type not supported.\"\"\"\n    case = {\n        \"obj\": object(),\n    }\n    with pytest.raises(Exception, match=r\".*doesn't support dict value type.*\"):\n        DictProtobufStructSerializer.encode(case)\n\n\ndef test_list_mixed_type_not_supported():\n    \"\"\"Test list mixed type not supported.\"\"\"\n    case = {\"list\": [1, 1.0, \"test\", {\"a\": False}]}\n    with pytest.raises(Exception, match=r\"Mixed data types in list are not allowed\"):\n        DictProtobufStructSerializer.encode(case)\n\n\ndef test_encode_dict_is_deterministic():\n    \"\"\"Check DictProtobufStructSerializer.encode result is the same for the same input data.\"\"\"\n    data = dict(c=3, b=2, a=1)\n    assert DictProtobufStructSerializer.encode(\n        data\n    ) == DictProtobufStructSerializer.encode(data)\n"
  },
  {
    "path": "tests/test_aea/test_helpers/test_storage.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests for aea helpers storage code.\"\"\"\nimport os\nimport time\n\nimport pytest\n\nfrom aea.helpers.storage.generic_storage import Storage\n\n\nclass TestAsyncCollection:\n    \"\"\"Test async storage collection.\"\"\"\n\n    @pytest.mark.asyncio\n    async def test_collection(self):\n        \"\"\"Test collecton methods.\"\"\"\n        s = Storage(\"sqlite://:memory:\")\n        s.start()\n\n        await s.wait_connected()\n\n        col = await s.get_collection(\"test_col\")\n        col2 = await s.get_collection(\"another_collection\")\n        obj_id = \"1\"\n        obj_body = {\"a\": 12}\n        await col.put(obj_id, {\"x\": 13})\n        await col.put(obj_id, obj_body)\n        assert await col.find(\"a\", 12) == [(obj_id, obj_body)]\n        assert await col.get(obj_id) == obj_body\n        assert await col2.get(obj_id) is None\n        assert await col.get(\"not exists\") is None\n\n        assert await col.list() == [(obj_id, obj_body)]\n\n        await col.remove(obj_id)\n        assert await col.get(obj_id) is None\n\n        s.stop()\n        await s.wait_completed()\n\n\nclass TestSyncCollection:\n    \"\"\"Test sync storage collection.\"\"\"\n\n    def test_collection(self):\n        \"\"\"Test collecton methods.\"\"\"\n        s = Storage(\"sqlite://:memory:\", threaded=True)\n        s.start()\n\n        while not s.is_connected:\n            time.sleep(0.01)\n\n        obj_id = \"1\"\n        obj_body = {\"a\": 12}\n\n        col = s.get_sync_collection(\"test_col\")\n        col2 = s.get_sync_collection(\"another_collection\")\n        col.put(obj_id, {\"x\": 13})\n        col.put(obj_id, obj_body)\n        assert col.find(\"a\", 12) == [(obj_id, obj_body)]\n        assert col.get(obj_id) == obj_body\n        assert col2.get(obj_id) is None\n        assert col.get(\"not exists\") is None\n        assert col.list() == [(obj_id, obj_body)]\n\n        col.remove(obj_id)\n        assert col.get(obj_id) is None\n\n        s.stop()\n        s.wait_completed(sync=True, timeout=5)\n\n\nclass TestMisc:\n    \"\"\"Various tests.\"\"\"\n\n    def test_invalid_col_name(self):\n        \"\"\"Test bad collection name raises exception.\"\"\"\n        s = Storage(\"sqlite://:memory:\", threaded=True)\n        s.start()\n        try:\n            with pytest.raises(ValueError, match=\"Invalid collection name:\"):\n                s.get_sync_collection(\"invalid%2345346?^$$$  /// : collection name\")\n        finally:\n            s.stop()\n            s.wait_completed(sync=True, timeout=10)\n\n    def test_unsupoported_backend(self):\n        \"\"\"Test unsupported backed raises exception.\"\"\"\n        with pytest.raises(\n            ValueError, match=\"Backend .* is not supported. Supported are\"\n        ):\n            Storage._get_backend_instance(\"bad_back://test\")\n\n\nif __name__ == \"__main__\":\n    pytest.main([os.path.basename(__file__)])\n"
  },
  {
    "path": "tests/test_aea/test_helpers/test_sym_link.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests for the sym link module.\"\"\"\n\nimport os\nimport shutil\nimport tempfile\nfrom pathlib import Path\n\nfrom aea.helpers.sym_link import create_symlink\n\n\ndef test_create_symlink():\n    \"\"\"Test create_symlink method.\"\"\"\n    t = Path(tempfile.mkdtemp())\n    cwd = os.getcwd()\n    os.chdir(t)\n    try:\n        link = Path(os.path.join(t, \"here\"))\n        target = Path(os.path.join(t, \"test\", \"nested\"))\n        os.makedirs(target)\n        create_symlink(link, target, t)\n        assert os.path.islink(link)\n        assert os.readlink(\"here\") == os.path.join(\"test\", \"nested\")\n    finally:\n        os.chdir(cwd)\n        shutil.rmtree(t)\n"
  },
  {
    "path": "tests/test_aea/test_helpers/test_transaction/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests for the transaction helper module.\"\"\"\n"
  },
  {
    "path": "tests/test_aea/test_helpers/test_transaction/test_base.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests for the base module.\"\"\"\n\nimport pytest\n\nfrom aea.configurations.constants import DEFAULT_LEDGER\nfrom aea.exceptions import AEAEnforceError\nfrom aea.helpers.transaction.base import (\n    RawMessage,\n    RawTransaction,\n    SignedMessage,\n    SignedTransaction,\n    State,\n    Terms,\n    TransactionDigest,\n    TransactionReceipt,\n)\n\n\ndef test_init_terms():\n    \"\"\"Test the terms object initialization.\"\"\"\n    ledger_id = DEFAULT_LEDGER\n    sender_addr = \"SenderAddress\"\n    counterparty_addr = \"CounterpartyAddress\"\n    amount_by_currency_id = {\"FET\": -10}\n    quantities_by_good_id = {\"good_1\": 20}\n    is_sender_payable_tx_fee = True\n    nonce = \"somestring\"\n    kwargs = {\"key\": \"value\"}\n    fee_by_currency_id = {}\n    terms = Terms(\n        ledger_id=ledger_id,\n        sender_address=sender_addr,\n        counterparty_address=counterparty_addr,\n        amount_by_currency_id=amount_by_currency_id,\n        quantities_by_good_id=quantities_by_good_id,\n        is_sender_payable_tx_fee=is_sender_payable_tx_fee,\n        nonce=nonce,\n        **kwargs,\n    )\n    sender_hash = \"9af02c24bdb18b73aad129291dc9eee008f9bcf62f5a6e91b5cb7427f146ca3b\"\n    counterparty_hash = (\n        \"174c1321c0eb4a49bf99d783b56f4fc30d0ee558106454c56d1c0fad295ccc79\"\n    )\n    assert terms.ledger_id == ledger_id\n    assert terms.sender_address == sender_addr\n    assert terms.counterparty_address == counterparty_addr\n    assert terms.amount_by_currency_id == amount_by_currency_id\n    assert terms.quantities_by_good_id == quantities_by_good_id\n    assert terms.is_sender_payable_tx_fee == is_sender_payable_tx_fee\n    assert terms.nonce == nonce\n    assert terms.kwargs == kwargs\n    assert terms.fee_by_currency_id == fee_by_currency_id\n    assert terms.id == sender_hash\n    assert terms.sender_hash == sender_hash\n    assert terms.counterparty_hash == counterparty_hash\n    assert terms.currency_id == next(iter(amount_by_currency_id.keys()))\n    assert str(\n        terms\n    ) == \"Terms: ledger_id={}, sender_address={}, counterparty_address={}, amount_by_currency_id={}, quantities_by_good_id={}, is_sender_payable_tx_fee={}, nonce={}, fee_by_currency_id={}, kwargs={}\".format(\n        ledger_id,\n        sender_addr,\n        counterparty_addr,\n        amount_by_currency_id,\n        quantities_by_good_id,\n        is_sender_payable_tx_fee,\n        nonce,\n        fee_by_currency_id,\n        kwargs,\n    )\n    assert terms == terms\n    with pytest.raises(AEAEnforceError):\n        terms.fee\n\n\ndef test_init_terms_w_fee():\n    \"\"\"Test the terms object initialization with fee.\"\"\"\n    ledger_id = DEFAULT_LEDGER\n    sender_addr = \"SenderAddress\"\n    counterparty_addr = \"CounterpartyAddress\"\n    amount_by_currency_id = {\"FET\": -10}\n    quantities_by_good_id = {\"good_1\": 20}\n    is_sender_payable_tx_fee = True\n    nonce = \"somestring\"\n    fee_by_currency_id = {\"FET\": 1}\n    terms = Terms(\n        ledger_id=ledger_id,\n        sender_address=sender_addr,\n        counterparty_address=counterparty_addr,\n        amount_by_currency_id=amount_by_currency_id,\n        quantities_by_good_id=quantities_by_good_id,\n        is_sender_payable_tx_fee=is_sender_payable_tx_fee,\n        nonce=nonce,\n        fee_by_currency_id=fee_by_currency_id,\n    )\n    new_counterparty_address = \"CounterpartyAddressNew\"\n    terms.counterparty_address = new_counterparty_address\n    assert terms.counterparty_address == new_counterparty_address\n    assert terms.fee == next(iter(fee_by_currency_id.values()))\n    assert terms.fee_by_currency_id == fee_by_currency_id\n    assert terms.counterparty_payable_amount == 0\n    assert terms.sender_payable_amount == -next(iter(amount_by_currency_id.values()))\n    assert terms.sender_payable_amount_incl_fee == -next(\n        iter(amount_by_currency_id.values())\n    ) + next(iter(fee_by_currency_id.values()))\n    assert terms.sender_fee == next(iter(fee_by_currency_id.values()))\n    assert terms.counterparty_fee == 0\n\n\ndef test_init_terms_w_fee_counterparty():\n    \"\"\"Test the terms object initialization with fee.\"\"\"\n    ledger_id = DEFAULT_LEDGER\n    sender_addr = \"SenderAddress\"\n    counterparty_addr = \"CounterpartyAddress\"\n    amount_by_currency_id = {\"FET\": 10}\n    quantities_by_good_id = {\"good_1\": -20}\n    is_sender_payable_tx_fee = False\n    nonce = \"somestring\"\n    fee_by_currency_id = {\"FET\": 1}\n    terms = Terms(\n        ledger_id=ledger_id,\n        sender_address=sender_addr,\n        counterparty_address=counterparty_addr,\n        amount_by_currency_id=amount_by_currency_id,\n        quantities_by_good_id=quantities_by_good_id,\n        is_sender_payable_tx_fee=is_sender_payable_tx_fee,\n        nonce=nonce,\n        fee_by_currency_id=fee_by_currency_id,\n    )\n    new_counterparty_address = \"CounterpartyAddressNew\"\n    terms.counterparty_address = new_counterparty_address\n    assert terms.counterparty_address == new_counterparty_address\n    assert terms.fee == next(iter(fee_by_currency_id.values()))\n    assert terms.fee_by_currency_id == fee_by_currency_id\n    assert terms.counterparty_payable_amount == next(\n        iter(amount_by_currency_id.values())\n    )\n    assert terms.counterparty_payable_amount_incl_fee == next(\n        iter(amount_by_currency_id.values())\n    ) + next(iter(fee_by_currency_id.values()))\n    assert terms.sender_payable_amount == 0\n    assert terms.sender_fee == 0\n    assert terms.counterparty_fee == next(iter(fee_by_currency_id.values()))\n\n\ndef test_init_terms_strict_positive():\n    \"\"\"Test the terms object initialization in strict mode.\"\"\"\n    ledger_id = DEFAULT_LEDGER\n    sender_addr = \"SenderAddress\"\n    counterparty_addr = \"CounterpartyAddress\"\n    amount_by_currency_id = {\"FET\": -10}\n    quantities_by_good_id = {\"good_1\": 20}\n    is_sender_payable_tx_fee = True\n    nonce = \"somestring\"\n    assert Terms(\n        ledger_id=ledger_id,\n        sender_address=sender_addr,\n        counterparty_address=counterparty_addr,\n        amount_by_currency_id=amount_by_currency_id,\n        quantities_by_good_id=quantities_by_good_id,\n        is_sender_payable_tx_fee=is_sender_payable_tx_fee,\n        nonce=nonce,\n        is_strict=True,\n    )\n\n\ndef test_init_terms_strict_negative():\n    \"\"\"Test the terms object initialization in strict mode.\"\"\"\n    ledger_id = DEFAULT_LEDGER\n    sender_addr = \"SenderAddress\"\n    counterparty_addr = \"CounterpartyAddress\"\n    amount_by_currency_id = {\"FET\": 10}\n    quantities_by_good_id = {\"good_1\": 20}\n    is_sender_payable_tx_fee = True\n    nonce = \"somestring\"\n    with pytest.raises(AEAEnforceError):\n        Terms(\n            ledger_id=ledger_id,\n            sender_address=sender_addr,\n            counterparty_address=counterparty_addr,\n            amount_by_currency_id=amount_by_currency_id,\n            quantities_by_good_id=quantities_by_good_id,\n            is_sender_payable_tx_fee=is_sender_payable_tx_fee,\n            nonce=nonce,\n            is_strict=True,\n        )\n\n\ndef test_init_terms_multiple_goods():\n    \"\"\"Test the terms object initialization with multiple goods.\"\"\"\n    ledger_id = DEFAULT_LEDGER\n    sender_addr = \"SenderAddress\"\n    counterparty_addr = \"CounterpartyAddress\"\n    amount_by_currency_id = {\"FET\": -10}\n    quantities_by_good_id = {\"good_1\": 20, \"good_2\": -10}\n    is_sender_payable_tx_fee = True\n    nonce = \"somestring\"\n    terms = Terms(\n        ledger_id=ledger_id,\n        sender_address=sender_addr,\n        counterparty_address=counterparty_addr,\n        amount_by_currency_id=amount_by_currency_id,\n        quantities_by_good_id=quantities_by_good_id,\n        is_sender_payable_tx_fee=is_sender_payable_tx_fee,\n        nonce=nonce,\n    )\n    assert (\n        terms.id == \"f81812773f5242d0cb52cfa82bc08bdba8d17b1e56e2cf02b3056749184e198c\"\n    )\n\n\ndef test_init_terms_no_amount_and_quantity():\n    \"\"\"Test the terms object initialization with no amount.\"\"\"\n    ledger_id = DEFAULT_LEDGER\n    sender_addr = \"SenderAddress\"\n    counterparty_addr = \"CounterpartyAddress\"\n    amount_by_currency_id = {}\n    quantities_by_good_id = {}\n    nonce = \"somestring\"\n    terms = Terms(\n        ledger_id=ledger_id,\n        sender_address=sender_addr,\n        counterparty_address=counterparty_addr,\n        amount_by_currency_id=amount_by_currency_id,\n        quantities_by_good_id=quantities_by_good_id,\n        nonce=nonce,\n    )\n    new_counterparty_address = \"CounterpartyAddressNew\"\n    terms.counterparty_address = new_counterparty_address\n    assert terms.counterparty_address == new_counterparty_address\n    assert not terms.has_fee\n    assert terms.counterparty_payable_amount == 0\n    assert terms.counterparty_payable_amount_incl_fee == 0\n    assert terms.sender_payable_amount == 0\n    assert terms.sender_payable_amount_incl_fee == 0\n\n\ndef test_terms_encode_decode():\n    \"\"\"Test encoding and decoding of terms.\"\"\"\n\n    class TermsProtobufObject:\n        terms_bytes = b\"\"\n\n    ledger_id = DEFAULT_LEDGER\n    sender_addr = \"SenderAddress\"\n    counterparty_addr = \"CounterpartyAddress\"\n    amount_by_currency_id = {\"FET\": -10}\n    quantities_by_good_id = {\"good_1\": 20}\n    is_sender_payable_tx_fee = True\n    nonce = \"somestring\"\n    terms = Terms(\n        ledger_id=ledger_id,\n        sender_address=sender_addr,\n        counterparty_address=counterparty_addr,\n        amount_by_currency_id=amount_by_currency_id,\n        quantities_by_good_id=quantities_by_good_id,\n        is_sender_payable_tx_fee=is_sender_payable_tx_fee,\n        nonce=nonce,\n        is_strict=True,\n    )\n    Terms.encode(TermsProtobufObject, terms)\n    recovered_terms = Terms.decode(TermsProtobufObject)\n    assert terms == recovered_terms\n\n\ndef test_init_raw_transaction():\n    \"\"\"Test the raw_transaction object initialization.\"\"\"\n    ledger_id = \"some_ledger\"\n    body = {\"body\": \"value\"}\n    rt = RawTransaction(ledger_id, body)\n    assert rt.ledger_id == ledger_id\n    assert rt.body == body\n    assert str(rt) == \"RawTransaction: ledger_id=some_ledger, body={'body': 'value'}\"\n    assert rt == rt\n\n\ndef test_raw_transaction_encode_decode():\n    \"\"\"Test encoding and decoding of terms.\"\"\"\n\n    class RawTransactionProtobufObject:\n        raw_transaction_bytes = b\"\"\n\n    ledger_id = \"some_ledger\"\n    body = {\"body\": \"value\"}\n    rt = RawTransaction(ledger_id, body)\n    RawTransaction.encode(RawTransactionProtobufObject, rt)\n    recovered_rt = RawTransaction.decode(RawTransactionProtobufObject)\n    assert rt == recovered_rt\n\n\ndef test_init_raw_message():\n    \"\"\"Test the raw_message object initialization.\"\"\"\n    ledger_id = \"some_ledger\"\n    body = b\"body\"\n    rm = RawMessage(ledger_id, body)\n    assert rm.ledger_id == ledger_id\n    assert rm.body == body\n    assert not rm.is_deprecated_mode\n    assert (\n        str(rm)\n        == f\"RawMessage: ledger_id=some_ledger, body={body}, is_deprecated_mode=False\"\n    )\n    assert rm == rm\n\n\ndef test_raw_message_encode_decode():\n    \"\"\"Test encoding and decoding of raw_message.\"\"\"\n\n    class RawMessageProtobufObject:\n        raw_message_bytes = b\"\"\n\n    ledger_id = \"some_ledger\"\n    body = b\"body\"\n    rm = RawMessage(ledger_id, body)\n    RawMessage.encode(RawMessageProtobufObject, rm)\n    recovered_rm = RawMessage.decode(RawMessageProtobufObject)\n    assert rm == recovered_rm\n\n\ndef test_init_signed_transaction():\n    \"\"\"Test the signed_transaction object initialization.\"\"\"\n    ledger_id = \"some_ledger\"\n    body = {\"key\": \"value\"}\n    st = SignedTransaction(ledger_id, body)\n    assert st.ledger_id == ledger_id\n    assert st.body == body\n    assert str(st) == \"SignedTransaction: ledger_id=some_ledger, body={'key': 'value'}\"\n    assert st == st\n\n\ndef test_signed_transaction_encode_decode():\n    \"\"\"Test encoding and decoding of signed_transaction.\"\"\"\n\n    class SignedTransactionProtobufObject:\n        signed_transaction_bytes = b\"\"\n\n    ledger_id = \"some_ledger\"\n    body = {\"key\": \"value\"}\n    st = SignedTransaction(ledger_id, body)\n    SignedTransaction.encode(SignedTransactionProtobufObject, st)\n    recovered_st = SignedTransaction.decode(SignedTransactionProtobufObject)\n    assert st == recovered_st\n\n\ndef test_init_signed_message():\n    \"\"\"Test the signed_message object initialization.\"\"\"\n    ledger_id = \"some_ledger\"\n    body = \"body\"\n    sm = SignedMessage(ledger_id, body)\n    assert sm.ledger_id == ledger_id\n    assert sm.body == body\n    assert not sm.is_deprecated_mode\n    assert (\n        str(sm)\n        == \"SignedMessage: ledger_id=some_ledger, body=body, is_deprecated_mode=False\"\n    )\n    assert sm == sm\n\n\ndef test_signed_message_encode_decode():\n    \"\"\"Test encoding and decoding of signed_message.\"\"\"\n\n    class SignedMessageProtobufObject:\n        signed_message_bytes = b\"\"\n\n    ledger_id = \"some_ledger\"\n    body = \"body\"\n    sm = SignedMessage(ledger_id, body)\n    SignedMessage.encode(SignedMessageProtobufObject, sm)\n    recovered_sm = SignedMessage.decode(SignedMessageProtobufObject)\n    assert sm == recovered_sm\n\n\ndef test_init_transaction_receipt():\n    \"\"\"Test the transaction_receipt object initialization.\"\"\"\n    ledger_id = \"some_ledger\"\n    receipt = {\"receipt\": \"v\"}\n    transaction = {\"transaction\": \"v\"}\n    tr = TransactionReceipt(ledger_id, receipt, transaction)\n    assert tr.ledger_id == ledger_id\n    assert tr.receipt == receipt\n    assert tr.transaction == transaction\n    assert (\n        str(tr)\n        == f\"TransactionReceipt: ledger_id={ledger_id}, receipt={receipt}, transaction={transaction}\"\n    )\n    assert tr == tr\n\n\ndef test_transaction_receipt_encode_decode():\n    \"\"\"Test encoding and decoding of transaction_receipt.\"\"\"\n\n    class TransactionReceiptProtobufObject:\n        transaction_receipt_bytes = b\"\"\n\n    ledger_id = \"some_ledger\"\n    receipt = {\"receipt\": \"v\"}\n    transaction = {\"transaction\": \"v\"}\n    tr = TransactionReceipt(ledger_id, receipt, transaction)\n    TransactionReceipt.encode(TransactionReceiptProtobufObject, tr)\n    recovered_tr = TransactionReceipt.decode(TransactionReceiptProtobufObject)\n    assert tr == recovered_tr\n\n\ndef test_init_state():\n    \"\"\"Test the state object initialization.\"\"\"\n    ledger_id = \"some_ledger\"\n    body = {\"state\": \"v\"}\n    state = State(ledger_id, body)\n    assert state.ledger_id == ledger_id\n    assert state.body == body\n    assert str(state) == f\"State: ledger_id={ledger_id}, body={body}\"\n    assert state == state\n\n\ndef test_state_encode_decode():\n    \"\"\"Test encoding and decoding of state.\"\"\"\n\n    class StateProtobufObject:\n        state_bytes = b\"\"\n\n    ledger_id = \"some_ledger\"\n    body = {\"state\": \"v\"}\n    state = State(ledger_id, body)\n    State.encode(StateProtobufObject, state)\n    recovered_state = State.decode(StateProtobufObject)\n    assert state == recovered_state\n\n\ndef test_init_transaction_digest():\n    \"\"\"Test the transaction_digest object initialization.\"\"\"\n    ledger_id = \"some_ledger\"\n    body = \"digest\"\n    td = TransactionDigest(ledger_id, body)\n    assert td.ledger_id == ledger_id\n    assert td.body == body\n    assert str(td) == \"TransactionDigest: ledger_id={}, body={}\".format(ledger_id, body)\n    assert td == td\n\n\ndef test_transaction_digest_encode_decode():\n    \"\"\"Test encoding and decoding of transaction_digest.\"\"\"\n\n    class TransactionDigestProtobufObject:\n        transaction_digest_bytes = b\"\"\n\n    ledger_id = \"some_ledger\"\n    body = \"digest\"\n    td = TransactionDigest(ledger_id, body)\n    TransactionDigest.encode(TransactionDigestProtobufObject, td)\n    recovered_td = TransactionDigest.decode(TransactionDigestProtobufObject)\n    assert td == recovered_td\n"
  },
  {
    "path": "tests/test_aea/test_helpers/test_yaml_utils.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests for the yaml utils module.\"\"\"\nimport io\nimport random\nimport string\nfrom collections import OrderedDict\n\nfrom aea.helpers.yaml_utils import (\n    _AEAYamlLoader,\n    yaml_dump,\n    yaml_dump_all,\n    yaml_load,\n    yaml_load_all,\n)\n\n\ndef test_yaml_dump_load():\n    \"\"\"Test yaml dump/load works.\"\"\"\n    data = OrderedDict({\"a\": 12, \"b\": None})\n    stream = io.StringIO()\n    yaml_dump(data, stream)\n    stream.seek(0)\n    loaded_data = yaml_load(stream)\n    assert loaded_data == data\n\n\ndef test_yaml_dump_all_load_all():\n    \"\"\"Test yaml_dump_all and yaml_load_all.\"\"\"\n    f = io.StringIO()\n    data = [{\"a\": \"12\"}, {\"b\": \"13\"}]\n    yaml_dump_all(data, f)\n\n    f.seek(0)\n    assert yaml_load_all(f) == data\n\n\ndef test_instantiate_loader_twice():\n    \"\"\"Test that instantiating the AEA YAML loader twice doesn't add twice implicit resolvers.\"\"\"\n    loader = _AEAYamlLoader(io.StringIO())\n    old_length = len(loader.yaml_implicit_resolvers)\n    loader = _AEAYamlLoader(io.StringIO())\n    assert len(loader.yaml_implicit_resolvers) == old_length\n\n\ndef _generate_random_string(n: int = 100):\n    return \"\".join(\n        random.choice(string.ascii_uppercase + string.digits) for _ in range(n)  # nosec\n    )\n"
  },
  {
    "path": "tests/test_aea/test_identity/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests for the identity module.\"\"\"\n"
  },
  {
    "path": "tests/test_aea/test_identity/test_base.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests for the identity module.\"\"\"\n\nimport pytest\nfrom aea_ledger_fetchai import FetchAICrypto\n\nfrom aea.configurations.constants import DEFAULT_LEDGER\nfrom aea.exceptions import AEAEnforceError\nfrom aea.identity.base import Identity\n\n\ndef test_init_identity_positive():\n    \"\"\"Test initialization of the identity object.\"\"\"\n    assert Identity(\"some_name\", address=\"some_address\", public_key=\"some_public_key\")\n    assert Identity(\n        \"some_name\",\n        address=\"some_address\",\n        public_key=\"some_public_key\",\n        default_address_key=DEFAULT_LEDGER,\n    )\n    assert Identity(\n        \"some_name\",\n        addresses={\n            DEFAULT_LEDGER: \"some_address\",\n            FetchAICrypto.identifier: \"some_address\",\n        },\n        public_keys={\n            DEFAULT_LEDGER: \"some_public_key\",\n            FetchAICrypto.identifier: \"some_public_key\",\n        },\n    )\n    assert Identity(\n        \"some_name\",\n        addresses={\n            DEFAULT_LEDGER: \"some_address\",\n            FetchAICrypto.identifier: \"some_address\",\n        },\n        public_keys={\n            DEFAULT_LEDGER: \"some_public_key\",\n            FetchAICrypto.identifier: \"some_public_key\",\n        },\n        default_address_key=DEFAULT_LEDGER,\n    )\n\n\ndef test_init_identity_negative():\n    \"\"\"Test initialization of the identity object.\"\"\"\n    name = \"some_name\"\n    address_1 = \"some_address\"\n    addresses_1 = {\"some_ledger_id\": \"some_address\"}\n    addresses_2 = {}\n    public_key_1 = \"some_public_key\"\n    public_keys_1 = {\"some_ledger_id\": \"some_public_key\"}\n    public_keys_2 = {}\n    with pytest.raises(ValueError, match=\"Provide a key for the default address.\"):\n        Identity(name, default_address_key=None)\n    with pytest.raises(\n        ValueError,\n        match=\"Either provide a single address or a dictionary of addresses, and not both.\",\n    ):\n        Identity(name)\n    with pytest.raises(\n        ValueError,\n        match=\"Either provide a single address or a dictionary of addresses, and not both.\",\n    ):\n        Identity(name, address=address_1, addresses=addresses_1)\n    with pytest.raises(ValueError, match=\"Provide at least one pair of addresses.\"):\n        Identity(name, addresses=addresses_2)\n    with pytest.raises(\n        ValueError,\n        match=\"If you provide a dictionary of addresses, you must provide its corresponding dictionary of public keys.\",\n    ):\n        Identity(name, addresses=addresses_1)\n    with pytest.raises(\n        ValueError,\n        match=\"If you provide a dictionary of addresses, you must not provide a single public key.\",\n    ):\n        Identity(name, addresses=addresses_1, public_key=public_key_1)\n    with pytest.raises(\n        AEAEnforceError,\n        match=\"Keys in public keys and addresses dictionaries do not match. They must be identical.\",\n    ):\n        Identity(name, addresses=addresses_1, public_keys=public_keys_2)\n    with pytest.raises(\n        AEAEnforceError,\n        match=\"The default address key must exist in both addresses and public keys dictionaries.\",\n    ):\n        Identity(\n            name,\n            addresses=addresses_1,\n            public_keys=public_keys_1,\n            default_address_key=\"some_other_ledger\",\n        )\n    with pytest.raises(\n        ValueError,\n        match=\"If you provide a single address, you must not provide a dictionary of public keys.\",\n    ):\n        Identity(name, address=address_1, public_keys=public_keys_1)\n    with pytest.raises(\n        ValueError,\n        match=\"If you provide a single address, you must provide its corresponding public key.\",\n    ):\n        Identity(name, address=address_1)\n\n\ndef test_accessors():\n    \"\"\"Test the properties of the identity object.\"\"\"\n    name = \"some_name\"\n    address = \"some_address\"\n    public_key = \"some_public_key\"\n    identity = Identity(name, address=address, public_key=public_key)\n    assert identity.name == name\n    assert identity.address == address\n    assert identity.addresses == {DEFAULT_LEDGER: address}\n    assert identity.public_key == public_key\n    assert identity.public_keys == {DEFAULT_LEDGER: public_key}\n    assert identity.default_address_key == DEFAULT_LEDGER\n"
  },
  {
    "path": "tests/test_aea/test_launcher.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains tests for aea launcher.\"\"\"\nimport shutil\nimport time\nfrom multiprocessing import Event\nfrom pathlib import Path\nfrom threading import Thread\nfrom unittest.mock import patch\n\nimport pytest\nimport yaml\n\nfrom aea.configurations.base import DEFAULT_AEA_CONFIG_FILE\nfrom aea.launcher import AEADirMultiprocessTask, AEALauncher, _run_agent\nfrom aea.test_tools.test_cases import AEATestCaseMany\n\nfrom tests.common.utils import wait_for_condition\nfrom tests.conftest import CUR_PATH\n\n\nclass TestThreadLauncherMode(AEATestCaseMany):\n    \"\"\"Test launcher in threaded mode.\"\"\"\n\n    RUNNER_MODE = \"threaded\"\n    agent_name_1 = \"myagent_1\"\n    agent_name_2 = \"myagent_2\"\n    failing_agent = \"failing_agent\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        super(AEATestCaseMany, cls).setup_class()\n        cls.create_agents(cls.agent_name_1, cls.agent_name_2, cls.failing_agent)\n        cls.set_agent_context(cls.failing_agent)\n        shutil.copytree(\n            Path(CUR_PATH, \"data\", \"exception_skill\"),\n            Path(cls.t, cls.failing_agent, \"skills\", \"exception\"),\n        )\n        config_path = Path(cls.t, cls.failing_agent, DEFAULT_AEA_CONFIG_FILE)\n        with open(config_path) as fp:\n            config = yaml.safe_load(fp)\n        config.setdefault(\"skills\", []).append(\"fetchai/exception:0.1.0\")\n        yaml.safe_dump(config, open(config_path, \"w\"))\n        cls.unset_agent_context()\n\n        for agent_name in (cls.agent_name_1, cls.agent_name_2, cls.failing_agent):\n            cls.set_agent_context(agent_name)\n            cls.generate_private_key()\n            cls.add_private_key()\n            cls.set_runtime_mode_to_async(agent_name)\n            cls.unset_agent_context()\n\n    @classmethod\n    def set_runtime_mode_to_async(cls, agent_name: str) -> None:\n        \"\"\"Set runtime mode of the agent to async.\"\"\"\n        config_path = Path(cls.t, agent_name, DEFAULT_AEA_CONFIG_FILE)\n        with open(config_path) as fp:\n            config = yaml.safe_load(fp)\n        config.setdefault(\"runtime_mode\", \"async\")\n        with open(config_path, \"w\") as fp:\n            yaml.safe_dump(config, fp)\n\n    def test_start_stop(self, capfd, caplog) -> None:\n        \"\"\"Test agents started stopped.\"\"\"\n        try:\n            runner = AEALauncher(\n                [self.agent_name_1, self.agent_name_2],\n                self.RUNNER_MODE,\n                log_level=\"DEBUG\",\n            )\n            runner.start(True)\n            wait_for_condition(lambda: runner.is_running, timeout=10)\n\n            capfd_out = \"\"\n\n            def _check():\n                nonlocal capfd_out  # to accumulate logs from capfd to chgck all the logs captured.\n                capfd_out += capfd.readouterr().out\n                log_text = capfd_out + \"\\n\".join(caplog.messages)\n                return (\n                    f\"[{self.agent_name_1}]: Runtime state changed to RuntimeStates.running.\"\n                    in log_text\n                    and f\"[{self.agent_name_2}]: Runtime state changed to RuntimeStates.running.\"\n                    in log_text\n                )\n\n            wait_for_condition(_check, timeout=10, period=0.1)\n            assert runner.num_failed == 0\n        finally:\n            runner.stop()\n            assert not runner.is_running\n            assert runner.num_failed == 0\n\n    def test_one_fails(self) -> None:\n        \"\"\"Test agents started, one agent failed, exception is raised.\"\"\"\n        try:\n            runner = AEALauncher(\n                [self.agent_name_1, self.agent_name_2, self.failing_agent],\n                self.RUNNER_MODE,\n            )\n\n            with pytest.raises(Exception, match=\"Expected exception!\"):\n                runner.start()\n        finally:\n            runner.stop()\n\n    def test_run_agent_in_thread(self):\n        \"\"\"Test agent started and stopped in thread.\"\"\"\n        stop_event = Event()\n        t = Thread(target=_run_agent, args=(self.agent_name_1, stop_event))\n        t.start()\n        time.sleep(1)\n        stop_event.set()\n        t.join()\n\n\nclass TestAsyncLauncherMode(TestThreadLauncherMode):\n    \"\"\"Test launcher in async mode.\"\"\"\n\n    RUNNER_MODE = \"async\"\n\n\nclass TestProcessLauncherMode(TestThreadLauncherMode):\n    \"\"\"Test launcher in process mode.\"\"\"\n\n    RUNNER_MODE = \"multiprocess\"\n\n\ndef test_task_stop():\n    \"\"\"Test AEADirMultiprocessTask.stop when not started.\"\"\"\n    task = AEADirMultiprocessTask(\"some\")\n    assert not task.failed\n    with patch.object(task._stop_event, \"set\") as set_mock:\n        task.stop()\n        set_mock.assert_not_called()\n"
  },
  {
    "path": "tests/test_aea/test_mail/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains a test for aea.mail.\"\"\"\n"
  },
  {
    "path": "tests/test_aea/test_mail/test_base.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests for Envelope of mail.base.py.\"\"\"\nimport unittest.mock\n\nimport pytest\n\nimport aea\nfrom aea.configurations.base import PublicId\nfrom aea.exceptions import AEAEnforceError\nfrom aea.mail import base_pb2\nfrom aea.mail.base import Envelope, EnvelopeContext, ProtobufEnvelopeSerializer, URI\nfrom aea.multiplexer import InBox, Multiplexer, OutBox\nfrom aea.protocols.base import Message\n\nfrom packages.fetchai.connections.local.connection import LocalNode\nfrom packages.fetchai.protocols.default.message import DefaultMessage\n\nfrom tests.common.utils import wait_for_condition\nfrom tests.conftest import _make_dummy_connection, _make_local_connection\n\n\ndef test_uri():\n    \"\"\"Testing the uri initialisation.\"\"\"\n    uri_raw = \"http://user:pwd@NetLoc:80/path;param?query=arg#frag\"\n    uri = URI(uri_raw=uri_raw)\n    assert uri_raw == str(uri)\n    assert uri.scheme == \"http\"\n    assert uri.netloc == \"user:pwd@NetLoc:80\"\n    assert uri.path == \"/path\"\n    assert uri.params == \"param\"\n    assert uri.query == \"query=arg\"\n    assert uri.fragment == \"frag\"\n    assert uri.host == \"netloc\"\n    assert uri.port == 80\n    assert uri.username == \"user\"\n    assert uri.password == \"pwd\"  # nosec\n\n\ndef test_uri_eq():\n    \"\"\"Testing the uri __eq__ function.\"\"\"\n    uri_raw = \"http://user:pwd@NetLoc:80/path;param?query=arg#frag\"\n    uri = URI(uri_raw=uri_raw)\n    assert uri == uri\n\n\ndef test_envelope_initialisation():\n    \"\"\"Testing the envelope initialisation.\"\"\"\n    agent_address = \"Agent0\"\n    receiver_address = \"Agent1\"\n    msg = DefaultMessage(\n        performative=DefaultMessage.Performative.BYTES, content=\"hello\"\n    )\n    msg.to = receiver_address\n\n    envelope = Envelope(\n        to=receiver_address,\n        sender=agent_address,\n        message=msg,\n    )\n\n    assert envelope, \"Cannot generate a new envelope\"\n\n    envelope.to = \"ChangedAgent\"\n    envelope.sender = \"ChangedSender\"\n    envelope.message = b\"HelloWorld\"\n\n    assert envelope.to == \"ChangedAgent\", \"Cannot set to value on Envelope\"\n    assert envelope.sender == \"ChangedSender\", \"Cannot set sender value on Envelope\"\n    assert envelope.message == b\"HelloWorld\", \"Cannot set message on Envelope\"\n    assert envelope.context is None\n    assert not envelope.is_sender_public_id\n    assert not envelope.is_to_public_id\n\n\ndef test_inbox_empty():\n    \"\"\"Tests if the inbox is empty.\"\"\"\n    multiplexer = Multiplexer([_make_dummy_connection()])\n    _inbox = InBox(multiplexer)\n    assert _inbox.empty(), \"Inbox is not empty\"\n\n\ndef test_inbox_nowait():\n    \"\"\"Tests the inbox without waiting.\"\"\"\n    agent_address = \"Agent0\"\n    receiver_address = \"Agent1\"\n    msg = DefaultMessage(\n        performative=DefaultMessage.Performative.BYTES, content=\"hello\"\n    )\n    msg.to = receiver_address\n    multiplexer = Multiplexer([_make_dummy_connection()])\n    envelope = Envelope(\n        to=receiver_address,\n        sender=agent_address,\n        message=msg,\n    )\n    multiplexer.in_queue.put(envelope)\n    inbox = InBox(multiplexer)\n    assert (\n        inbox.get_nowait() == envelope\n    ), \"Check for a message on the in queue and wait for no time.\"\n\n\ndef test_inbox_get():\n    \"\"\"Tests for a envelope on the in queue.\"\"\"\n    agent_address = \"Agent0\"\n    receiver_address = \"Agent1\"\n    msg = DefaultMessage(\n        performative=DefaultMessage.Performative.BYTES, content=\"hello\"\n    )\n    msg.to = receiver_address\n    multiplexer = Multiplexer([_make_dummy_connection()])\n    envelope = Envelope(\n        to=receiver_address,\n        sender=agent_address,\n        message=msg,\n    )\n    multiplexer.in_queue.put(envelope)\n    inbox = InBox(multiplexer)\n\n    assert (\n        inbox.get() == envelope\n    ), \"Checks if the returned envelope is the same with the queued envelope.\"\n\n\ndef test_inbox_get_raises_exception_when_empty():\n    \"\"\"Test that getting an envelope from an empty inbox raises an exception.\"\"\"\n    multiplexer = Multiplexer([_make_dummy_connection()])\n    inbox = InBox(multiplexer)\n\n    with pytest.raises(aea.mail.base.Empty):\n        with unittest.mock.patch.object(multiplexer, \"get\", return_value=None):\n            inbox.get()\n\n\ndef test_inbox_get_nowait_returns_none():\n    \"\"\"Test that getting an envelope from an empty inbox returns None.\"\"\"\n    # TODO get_nowait in this case should raise an exception, like it's done in queue.Queue\n    multiplexer = Multiplexer([_make_dummy_connection()])\n    inbox = InBox(multiplexer)\n    assert inbox.get_nowait() is None\n\n\ndef test_outbox_put():\n    \"\"\"Tests that an envelope is putted into the queue.\"\"\"\n    agent_address = \"Agent0\"\n    receiver_address = \"Agent1\"\n    msg = DefaultMessage(\n        dialogue_reference=(\"\", \"\"),\n        message_id=1,\n        target=0,\n        performative=DefaultMessage.Performative.BYTES,\n        content=b\"hello\",\n    )\n    msg.to = receiver_address\n    msg.sender = agent_address\n    dummy_connection = _make_dummy_connection()\n    multiplexer = Multiplexer([dummy_connection])\n    outbox = OutBox(multiplexer)\n    inbox = InBox(multiplexer)\n    multiplexer.connect()\n    wait_for_condition(\n        lambda: dummy_connection.is_connected, 15, \"Connection is not connected\"\n    )\n    envelope = Envelope(\n        to=receiver_address,\n        sender=agent_address,\n        message=msg,\n    )\n    outbox.put(envelope)\n    wait_for_condition(\n        lambda: inbox.empty(), 15, \"Inbox must not be empty after putting an envelope\"\n    )\n    multiplexer.disconnect()\n\n\ndef test_outbox_put_message():\n    \"\"\"Tests that an envelope is created from the message is in the queue.\"\"\"\n    agent_address = \"Agent0\"\n    receiver_address = \"Agent1\"\n    msg = DefaultMessage(\n        dialogue_reference=(\"\", \"\"),\n        message_id=1,\n        target=0,\n        performative=DefaultMessage.Performative.BYTES,\n        content=b\"hello\",\n    )\n    msg.to = receiver_address\n    msg.sender = agent_address\n    dummy_connection = _make_dummy_connection()\n    multiplexer = Multiplexer([dummy_connection])\n    outbox = OutBox(multiplexer)\n    inbox = InBox(multiplexer)\n    multiplexer.connect()\n    wait_for_condition(\n        lambda: multiplexer.is_connected, 15, \"Multiplexer is not connected\"\n    )\n    outbox.put_message(msg)\n    wait_for_condition(\n        lambda: inbox.empty(), 15, \"Inbox must not be empty after putting a message\"\n    )\n    multiplexer.disconnect()\n\n\ndef test_outbox_empty():\n    \"\"\"Test thet the outbox queue is empty.\"\"\"\n    dummy_connection = _make_dummy_connection()\n    multiplexer = Multiplexer([dummy_connection])\n    multiplexer.connect()\n    outbox = OutBox(multiplexer)\n    assert outbox.empty(), \"The outbox is not empty\"\n    multiplexer.disconnect()\n\n\ndef test_multiplexer():\n    \"\"\"Tests if the multiplexer is connected.\"\"\"\n    with LocalNode() as node:\n        address_1 = \"address_1\"\n        public_key_1 = \"public_key_1\"\n        oef_local_connection = _make_local_connection(address_1, public_key_1, node)\n        multiplexer = Multiplexer([oef_local_connection])\n        multiplexer.connect()\n        assert (\n            multiplexer.is_connected\n        ), \"Mailbox cannot connect to the specific Connection(OEFLocalConnection)\"\n        multiplexer.disconnect()\n\n\ndef test_envelope_fails_on_message_empty_protocol_specification_id():\n    \"\"\"Check message.protocol_specification_id.\"\"\"\n\n    class BadMessage(Message):\n        protocol_id = \"some/some:0.1.0\"\n\n    message = BadMessage()\n\n    with pytest.raises(ValueError):\n        Envelope(message=message, to=\"1\", sender=\"1\")\n\n\ndef test_protobuf_envelope_serializer():\n    \"\"\"Test Protobuf envelope serializer.\"\"\"\n    serializer = ProtobufEnvelopeSerializer()\n    # connection id is None because it is not included in the encoded envelope\n    envelope_context = EnvelopeContext(connection_id=None, uri=URI(\"/uri\"))\n    expected_envelope = Envelope(\n        to=\"to\",\n        sender=\"sender\",\n        protocol_specification_id=PublicId(\"author\", \"name\", \"0.1.0\"),\n        message=b\"message\",\n        context=envelope_context,\n    )\n    encoded_envelope = serializer.encode(expected_envelope)\n    actual_envelope = serializer.decode(encoded_envelope)\n\n    assert actual_envelope == expected_envelope\n\n\ndef test_envelope_serialization():\n    \"\"\"Test Envelope.encode and Envelope.decode methods.\"\"\"\n    expected_envelope = Envelope(\n        to=\"to\",\n        sender=\"sender\",\n        protocol_specification_id=PublicId(\"author\", \"name\", \"0.1.0\"),\n        message=b\"message\",\n    )\n    encoded_envelope = expected_envelope.encode()\n    actual_envelope = Envelope.decode(encoded_envelope)\n\n    assert actual_envelope == expected_envelope\n\n\ndef test_envelope_message_bytes():\n    \"\"\"Test the property Envelope.message_bytes.\"\"\"\n    message = DefaultMessage(DefaultMessage.Performative.BYTES, content=b\"message\")\n    envelope = Envelope(\n        to=\"to\",\n        sender=\"sender\",\n        message=message,\n    )\n\n    expected_message_bytes = message.encode()\n    actual_message_bytes = envelope.message_bytes\n    assert expected_message_bytes == actual_message_bytes\n\n\ndef test_envelope_context_connection_id():\n    \"\"\"Test the property EnvelopeContext.connection_id.\"\"\"\n    connection_id = PublicId(\"author\", \"skill_name\", \"0.1.0\")\n    envelope_context = EnvelopeContext()\n    envelope_context.connection_id = connection_id\n    assert envelope_context.connection_id == connection_id\n\n\ndef test_envelope_context_is_None_for_c2c():\n    \"\"\"Test the Envelope context is None for c2c.\"\"\"\n    envelope_context = EnvelopeContext(\n        connection_id=PublicId.from_str(\"author/connection_name:0.1.0\")\n    )\n    message = DefaultMessage(DefaultMessage.Performative.BYTES, content=b\"message\")\n    with pytest.raises(\n        AEAEnforceError,\n        match=\"EnvelopeContext must be None for component to component messages.\",\n    ):\n        Envelope(\n            to=\"some_author/some_name:0.1.0\",\n            sender=\"some_author/some_name:0.1.0\",\n            protocol_specification_id=PublicId(\"author\", \"name\", \"0.1.0\"),\n            message=message,\n            context=envelope_context,\n        )\n\n\ndef test_envelope_to_as_public_id():\n    \"\"\"Test the Envelope to_as_public_id method.\"\"\"\n    env = Envelope(\n        to=\"some_author/some_name:0.1.0\",\n        sender=\"some_author/some_name:0.1.0\",\n        protocol_specification_id=PublicId(\"author\", \"name\", \"0.1.0\"),\n        message=b\"message\",\n    )\n    assert env.to_as_public_id is not None\n\n\ndef test_envelope_constructor():\n    \"\"\"Test Envelope constructor checks.\"\"\"\n    Envelope(\n        to=\"to\",\n        sender=\"sender\",\n        message=DefaultMessage(performative=DefaultMessage.Performative.BYTES),\n    )\n    Envelope(\n        to=\"to\",\n        sender=\"sender\",\n        message=b\"\",\n        protocol_specification_id=DefaultMessage.protocol_specification_id,\n    )\n\n    with pytest.raises(\n        AEAEnforceError, match=\"message should be a type of Message or bytes!\"\n    ):\n        Envelope(to=\"to\", sender=\"sender\", message=123)\n\n    with pytest.raises(\n        Exception,\n        match=r\"Message is bytes object, protocol_specification_id must be provided!\",\n    ):\n        Envelope(to=\"asd\", sender=\"asdasd\", message=b\"sdfdf\")\n\n\ndef test_envelope_context_repr():\n    \"\"\"Check repr for EnvelopeContext.\"\"\"\n    assert str(EnvelopeContext(1, 2)) == \"EnvelopeContext(connection_id=1, uri=2)\"\n\n\ndef test_envelope_specification_id_translated():\n    \"\"\"Test protocol id to protocol specification id translation and back.\"\"\"\n    protocol_specification_id = PublicId(\"author\", \"specification\", \"0.1.0\")\n\n    envelope = Envelope(\n        to=\"to\",\n        sender=\"sender\",\n        protocol_specification_id=protocol_specification_id,\n        message=b\"\",\n    )\n\n    assert envelope.protocol_specification_id == protocol_specification_id\n\n    envelope_bytes = envelope.encode()\n    envelope_pb = base_pb2.Envelope()\n    envelope_pb.ParseFromString(envelope_bytes)\n\n    new_envelope = Envelope.decode(envelope_bytes)\n    assert new_envelope.protocol_specification_id == envelope.protocol_specification_id\n"
  },
  {
    "path": "tests/test_aea/test_multiplexer.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests for the Multiplexer.\"\"\"\nimport asyncio\nimport logging\nimport os\nimport shutil\nimport sys\nimport tempfile\nimport time\nimport unittest.mock\nfrom pathlib import Path\nfrom threading import Thread\nfrom unittest import mock\nfrom unittest.mock import MagicMock, Mock, call, patch\n\nimport pytest\nfrom pexpect.exceptions import EOF  # type: ignore\n\nimport aea\nfrom aea.cli.core import cli\nfrom aea.configurations.constants import DEFAULT_LEDGER\nfrom aea.connections.base import ConnectionStates\nfrom aea.helpers.exception_policy import ExceptionPolicyEnum\nfrom aea.identity.base import Identity\nfrom aea.mail.base import AEAConnectionError, Envelope, EnvelopeContext\nfrom aea.multiplexer import AsyncMultiplexer, InBox, Multiplexer, OutBox\nfrom aea.test_tools.click_testing import CliRunner\n\nfrom packages.fetchai.connections.local.connection import LocalNode\nfrom packages.fetchai.connections.p2p_libp2p.connection import (\n    PUBLIC_ID as P2P_PUBLIC_ID,\n)\nfrom packages.fetchai.connections.stub.connection import PUBLIC_ID as STUB_CONNECTION_ID\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.protocols.fipa.message import FipaMessage\n\nfrom ..conftest import (\n    AUTHOR,\n    CLI_LOG_OPTION,\n    ROOT_DIR,\n    UNKNOWN_CONNECTION_PUBLIC_ID,\n    UNKNOWN_PROTOCOL_PUBLIC_ID,\n    _make_dummy_connection,\n    _make_local_connection,\n    _make_stub_connection,\n    logger,\n)\nfrom tests.common.pexpect_popen import PexpectWrapper\nfrom tests.common.utils import wait_for_condition\n\n\nUnknownProtocolMock = Mock()\nUnknownProtocolMock.protocol_id = UNKNOWN_PROTOCOL_PUBLIC_ID\nUnknownProtocolMock.protocol_specification_id = UNKNOWN_PROTOCOL_PUBLIC_ID\n\n\n@pytest.mark.asyncio\nasync def test_receiving_loop_terminated():\n    \"\"\"Test that connecting twice the multiplexer behaves correctly.\"\"\"\n    multiplexer = Multiplexer([_make_dummy_connection()])\n    multiplexer.connect()\n\n    with unittest.mock.patch.object(multiplexer.logger, \"debug\") as mock_logger_debug:\n        multiplexer.connection_status.set(ConnectionStates.disconnected)\n        await multiplexer._receiving_loop()\n        mock_logger_debug.assert_called_with(\"Receiving loop terminated.\")\n        multiplexer.connection_status.set(ConnectionStates.connected)\n        multiplexer.disconnect()\n\n\ndef test_connect_twice():\n    \"\"\"Test that connecting twice the multiplexer behaves correctly.\"\"\"\n    multiplexer = Multiplexer([_make_dummy_connection()])\n\n    assert not multiplexer.connection_status.is_connected\n    multiplexer.connect()\n    assert multiplexer.connection_status.is_connected\n    multiplexer.connect()\n    assert multiplexer.connection_status.is_connected\n\n    multiplexer.disconnect()\n\n\ndef test_disconnect_twice():\n    \"\"\"Test that connecting twice the multiplexer behaves correctly.\"\"\"\n    multiplexer = Multiplexer([_make_dummy_connection()])\n\n    assert not multiplexer.connection_status.is_connected\n    multiplexer.connect()\n    assert multiplexer.connection_status.is_connected\n    multiplexer.disconnect()\n    multiplexer.disconnect()\n\n\ndef test_connect_twice_with_loop():\n    \"\"\"Test that connecting twice the multiplexer behaves correctly.\"\"\"\n    running_loop = asyncio.new_event_loop()\n    thread_loop = Thread(target=running_loop.run_forever)\n    thread_loop.start()\n\n    try:\n        multiplexer = Multiplexer([_make_dummy_connection()], loop=running_loop)\n\n        with unittest.mock.patch.object(\n            multiplexer.logger, \"debug\"\n        ) as mock_logger_debug:\n            assert not multiplexer.connection_status.is_connected\n            multiplexer.connect()\n            assert multiplexer.connection_status.is_connected\n            multiplexer.connect()\n            assert multiplexer.connection_status.is_connected\n\n            mock_logger_debug.assert_called_with(\"Multiplexer already connected.\")\n\n            multiplexer.disconnect()\n            running_loop.call_soon_threadsafe(running_loop.stop)\n    finally:\n        thread_loop.join()\n\n\n@pytest.mark.asyncio\nasync def test_connect_twice_a_single_connection():\n    \"\"\"Test that connecting twice a single connection behaves correctly.\"\"\"\n    connection = _make_dummy_connection()\n    multiplexer = Multiplexer([connection])\n\n    assert not multiplexer.connection_status.is_connected\n    await multiplexer._connect_one(connection.connection_id)\n    with unittest.mock.patch.object(multiplexer.logger, \"debug\") as mock_logger_debug:\n        await multiplexer._connect_one(connection.connection_id)\n        mock_logger_debug.assert_called_with(\n            \"Connection fetchai/dummy:0.1.0 already established.\"\n        )\n        await multiplexer._disconnect_one(connection.connection_id)\n\n\n@pytest.mark.asyncio\nasync def test_run_bad_conneect():\n    \"\"\"Test that connecting twice a single connection behaves correctly.\"\"\"\n    connection = _make_dummy_connection()\n    multiplexer = AsyncMultiplexer([connection])\n    f = asyncio.Future()\n    f.set_result(None)\n    with unittest.mock.patch.object(multiplexer, \"connect\", return_value=f):\n        with pytest.raises(ValueError, match=\"Multiplexer is not connected properly.\"):\n            await multiplexer.run()\n\n\ndef test_multiplexer_connect_all_raises_error():\n    \"\"\"Test the case when the multiplexer raises an exception while connecting.\"\"\"\n    multiplexer = Multiplexer([_make_dummy_connection()])\n\n    with unittest.mock.patch.object(multiplexer, \"_connect_all\", side_effect=Exception):\n        with pytest.raises(\n            AEAConnectionError, match=\"Failed to connect the multiplexer.\"\n        ):\n            multiplexer.connect()\n    multiplexer.disconnect()\n\n\ndef test_multiplexer_connect_one_raises_error_many_connections():\n    \"\"\"Test the case when the multiplexer raises an exception while attempting the connection of one connection.\"\"\"\n    node = LocalNode()\n    tmpdir = Path(tempfile.mkdtemp())\n    d = tmpdir / \"test_stub\"\n    d.mkdir(parents=True)\n    input_file_path = d / \"input_file.csv\"\n    output_file_path = d / \"input_file.csv\"\n\n    connection_1 = _make_local_connection(\"my_addr\", \"my_public_key\", node)\n    connection_2 = _make_stub_connection(input_file_path, output_file_path)\n    connection_3 = _make_dummy_connection()\n    multiplexer = Multiplexer([connection_1, connection_2, connection_3])\n\n    assert not connection_1.is_connected\n    assert not connection_2.is_connected\n    assert not connection_3.is_connected\n\n    with unittest.mock.patch.object(connection_3, \"connect\", side_effect=Exception):\n        with pytest.raises(\n            AEAConnectionError, match=\"Failed to connect the multiplexer.\"\n        ):\n            multiplexer.connect()\n\n    assert not connection_1.is_connected\n    assert not connection_2.is_connected\n    assert not connection_3.is_connected\n\n    multiplexer.disconnect()\n    try:\n        shutil.rmtree(tmpdir)\n    except OSError as e:\n        logger.warning(\"Couldn't delete {}\".format(tmpdir))\n        logger.exception(e)\n\n\n@pytest.mark.asyncio\nasync def test_disconnect_twice_a_single_connection():\n    \"\"\"Test that connecting twice a single connection behaves correctly.\"\"\"\n    connection = _make_dummy_connection()\n    multiplexer = Multiplexer([_make_dummy_connection()])\n\n    assert not multiplexer.connection_status.is_connected\n    with unittest.mock.patch.object(multiplexer.logger, \"debug\") as mock_logger_debug:\n        await multiplexer._disconnect_one(connection.connection_id)\n        mock_logger_debug.assert_called_with(\n            \"Connection fetchai/dummy:0.1.0 already disconnected.\"\n        )\n\n\ndef test_multiplexer_disconnect_all_raises_error():\n    \"\"\"Test the case when the multiplexer raises an exception while disconnecting.\"\"\"\n    multiplexer = Multiplexer([_make_dummy_connection()])\n    multiplexer.connect()\n\n    assert multiplexer.connection_status.is_connected\n\n    with unittest.mock.patch.object(\n        multiplexer, \"_disconnect_all\", side_effect=Exception\n    ):\n        with pytest.raises(\n            AEAConnectionError, match=\"Failed to disconnect the multiplexer.\"\n        ):\n            multiplexer.disconnect()\n\n    # # do the true disconnection - for clean the test up\n    assert multiplexer.connection_status.is_disconnecting\n    multiplexer.disconnect()\n    assert multiplexer.connection_status.is_disconnected\n\n\n@pytest.mark.asyncio\nasync def test_multiplexer_disconnect_one_raises_error_many_connections():\n    \"\"\"Test the case when the multiplexer raises an exception while attempting the disconnection of one connection.\"\"\"\n    with LocalNode() as node:\n        tmpdir = Path(tempfile.mkdtemp())\n        d = tmpdir / \"test_stub\"\n        d.mkdir(parents=True)\n        input_file_path = d / \"input_file.csv\"\n        output_file_path = d / \"input_file.csv\"\n\n        connection_1 = _make_local_connection(\"my_addr\", \"my_public_key\", node)\n        connection_2 = _make_stub_connection(input_file_path, output_file_path)\n        connection_3 = _make_dummy_connection()\n        multiplexer = Multiplexer([connection_1, connection_2, connection_3])\n\n        assert not connection_1.is_connected\n        assert not connection_2.is_connected\n        assert not connection_3.is_connected\n\n        multiplexer.connect()\n\n        assert connection_1.is_connected\n        assert connection_2.is_connected\n        assert connection_3.is_connected\n\n        with unittest.mock.patch.object(\n            connection_3, \"disconnect\", side_effect=Exception\n        ):\n            with pytest.raises(\n                AEAConnectionError, match=\"Failed to disconnect the multiplexer.\"\n            ):\n                multiplexer.disconnect()\n\n        assert not connection_1.is_connected\n        assert not connection_2.is_connected\n        assert connection_3.is_connected\n\n        # clean the test up.\n        await connection_3.disconnect()\n        multiplexer.disconnect()\n        try:\n            shutil.rmtree(tmpdir)\n        except OSError as e:\n            logger.warning(\"Couldn't delete {}\".format(tmpdir))\n            logger.exception(e)\n\n\n@pytest.mark.asyncio\nasync def test_sending_loop_does_not_start_if_multiplexer_not_connected():\n    \"\"\"Test that the sending loop is stopped does not start if the multiplexer is not connected.\"\"\"\n    multiplexer = Multiplexer([_make_dummy_connection()])\n\n    with unittest.mock.patch.object(multiplexer.logger, \"debug\") as mock_logger_debug:\n        await multiplexer._send_loop()\n        mock_logger_debug.assert_called_with(\n            \"Sending loop not started. The multiplexer is not connected.\"\n        )\n\n\n@pytest.mark.asyncio\nasync def test_sending_loop_cancelled():\n    \"\"\"Test the case when the sending loop is cancelled.\"\"\"\n    multiplexer = Multiplexer([_make_dummy_connection()])\n\n    multiplexer.connect()\n    await asyncio.sleep(0.1)\n    with unittest.mock.patch.object(multiplexer.logger, \"debug\") as mock_logger_debug:\n        multiplexer.disconnect()\n        mock_logger_debug.assert_any_call(\"Sending loop cancelled.\")\n\n\n@pytest.mark.asyncio\nasync def test_receiving_loop_raises_exception():\n    \"\"\"Test the case when an error occurs when a receive is started.\"\"\"\n    connection = _make_dummy_connection()\n    multiplexer = Multiplexer([connection])\n\n    with unittest.mock.patch(\"asyncio.wait\", side_effect=Exception(\"a weird error.\")):\n        with unittest.mock.patch.object(\n            multiplexer.logger, \"error\"\n        ) as mock_logger_error:\n            multiplexer.connect()\n            time.sleep(0.1)\n            mock_logger_error.assert_called_with(\n                \"Error in the receiving loop: a weird error.\", exc_info=True\n            )\n\n    multiplexer.disconnect()\n\n\n@pytest.mark.asyncio\nasync def test_send_envelope_with_non_registered_connection():\n    \"\"\"Test that sending an envelope with an unregistered connection raises an exception.\"\"\"\n    connection = _make_dummy_connection()\n    multiplexer = Multiplexer([connection], protocols=[DefaultProtocolMock])\n    multiplexer.connect()\n\n    envelope = Envelope(\n        to=\"\",\n        sender=\"\",\n        protocol_specification_id=DefaultMessage.protocol_specification_id,\n        message=b\"\",\n        context=EnvelopeContext(connection_id=UNKNOWN_CONNECTION_PUBLIC_ID),\n    )\n\n    with unittest.mock.patch.object(\n        multiplexer.logger, \"warning\"\n    ) as mock_logger_warning:\n        await multiplexer._send(envelope)\n        mock_logger_warning.assert_called_with(\n            f\"Dropping envelope, no connection available for sending: {envelope}\"\n        )\n\n    multiplexer.disconnect()\n\n\n@pytest.mark.asyncio\nasync def test_send_envelope_when_no_connection():\n    \"\"\"Test that sending an envelope with no connection logs a warning.\"\"\"\n    multiplexer = Multiplexer([], protocols=[DefaultProtocolMock])\n    multiplexer.connect()\n\n    envelope = Envelope(\n        to=\"\",\n        sender=\"\",\n        protocol_specification_id=DefaultMessage.protocol_specification_id,\n        message=b\"\",\n    )\n\n    with unittest.mock.patch.object(\n        multiplexer.logger, \"warning\"\n    ) as mock_logger_warning:\n        await multiplexer._send(envelope)\n        mock_logger_warning.assert_called_with(\n            f\"Dropping envelope, no connection available for sending: {envelope}\"\n        )\n\n    multiplexer.disconnect()\n\n\ndef test_send_envelope_error_is_logged_by_send_loop():\n    \"\"\"Test that the AEAConnectionError in the '_send' method is logged by the '_send_loop'.\"\"\"\n    connection = _make_dummy_connection()\n    multiplexer = Multiplexer([connection], protocols=[DefaultProtocolMock])\n    multiplexer.connect()\n    fake_connection_id = UNKNOWN_CONNECTION_PUBLIC_ID\n\n    envelope = Envelope(\n        to=\"\",\n        sender=\"\",\n        protocol_specification_id=DefaultMessage.protocol_specification_id,\n        message=b\"\",\n        context=EnvelopeContext(connection_id=fake_connection_id),\n    )\n\n    with unittest.mock.patch.object(multiplexer.logger, \"error\") as mock_logger_error:\n        multiplexer.put(envelope)\n        time.sleep(0.1)\n        mock_logger_error.assert_called_with(\n            \"No connection registered with id: {}\".format(fake_connection_id)\n        )\n\n    multiplexer.disconnect()\n\n\ndef test_get_from_multiplexer_when_empty():\n    \"\"\"Test that getting an envelope from the multiplexer when the input queue is empty raises an exception.\"\"\"\n    connection = _make_dummy_connection()\n    multiplexer = Multiplexer([connection])\n\n    with pytest.raises(aea.mail.base.Empty):\n        multiplexer.get()\n\n\ndef test_send_message_no_supported_protocol():\n    \"\"\"Test the case when we send an envelope with a specific connection that does not support the protocol.\"\"\"\n    with LocalNode() as node:\n        identity_1 = Identity(\n            \"identity\", address=\"address_1\", public_key=\"public_key_1\"\n        )\n        connection_1 = _make_local_connection(\n            identity_1.address,\n            identity_1.public_key,\n            node,\n            restricted_to_protocols={DefaultMessage.protocol_id},\n            excluded_protocols={FipaMessage.protocol_id},\n        )\n        multiplexer = Multiplexer(\n            [connection_1], protocols=[DefaultMessage, FipaMessage, UnknownProtocolMock]\n        )\n\n        multiplexer.connect()\n\n        with mock.patch.object(multiplexer.logger, \"warning\") as mock_logger_warning:\n            envelope = Envelope(\n                to=identity_1.address,\n                sender=identity_1.address,\n                protocol_specification_id=FipaMessage.protocol_specification_id,\n                message=b\"some bytes\",\n            )\n            multiplexer.put(envelope)\n            time.sleep(0.5)\n            mock_logger_warning.assert_called_with(\n                \"Connection {} does not support protocol {}. It is explicitly excluded.\".format(\n                    connection_1.connection_id, FipaMessage.protocol_id\n                )\n            )\n\n        with mock.patch.object(multiplexer.logger, \"warning\") as mock_logger_warning:\n            envelope = Envelope(\n                to=identity_1.address,\n                sender=identity_1.address,\n                protocol_specification_id=UnknownProtocolMock.protocol_specification_id,\n                message=b\"some bytes\",\n            )\n            multiplexer.put(envelope)\n            time.sleep(0.5)\n            mock_logger_warning.assert_called_with(\n                \"Connection {} does not support protocol {}. The connection is restricted to protocols in {}.\".format(\n                    connection_1.connection_id,\n                    UnknownProtocolMock.protocol_id,\n                    connection_1.restricted_to_protocols,\n                )\n            )\n\n        multiplexer.disconnect()\n\n\ndef test_protocol_not_resolved():\n    \"\"\"Test multiplexer raises ValueError on protocol not resolved.\"\"\"\n    multiplexer = Multiplexer([Mock()])\n\n    envelope = Envelope(\n        to=\"1\",\n        sender=\"2\",\n        protocol_specification_id=FipaMessage.protocol_specification_id,\n        message=b\"some bytes\",\n    )\n    with pytest.raises(ValueError):\n        multiplexer._get_protocol_id_for_envelope(envelope)\n\n\ndef test_autoset_default_connection():\n    \"\"\"Set default connection automatically.\"\"\"\n    connection_1 = _make_dummy_connection()\n    connection_2 = _make_dummy_connection()\n    connections = [connection_1, connection_2]\n    multiplexer = Multiplexer(connections)\n\n    multiplexer._default_connection = None\n    multiplexer._set_default_connection_if_none()\n    assert multiplexer._default_connection == connections[0]\n\n\ndef test__get_connection():\n    \"\"\"Test the method _get_connection.\"\"\"\n    connection_1 = _make_dummy_connection()\n    connections = [connection_1]\n    multiplexer = Multiplexer(connections)\n    conn_ = multiplexer._get_connection(connection_1.connection_id.to_any())\n    assert conn_ == connection_1\n\n\n@pytest.mark.asyncio\nasync def test_disconnect_when_not_connected():\n    \"\"\"Test disconnect when not connected.\"\"\"\n    connection_1 = _make_dummy_connection()\n    connections = [connection_1]\n    multiplexer = AsyncMultiplexer(connections)\n    with patch.object(multiplexer, \"_disconnect_all\") as disconnect_all_mocked:\n        await multiplexer.disconnect()\n\n    disconnect_all_mocked.assert_not_called()\n\n\n@pytest.mark.asyncio\nasync def test_exit_on_none_envelope():\n    \"\"\"Test sending task exit on None envelope.\"\"\"\n    connection_1 = _make_dummy_connection()\n    connections = [connection_1]\n    multiplexer = AsyncMultiplexer(connections, loop=asyncio.get_event_loop())\n    try:\n        await multiplexer.connect()\n        assert multiplexer.is_connected\n        multiplexer.put(None)\n\n        await asyncio.sleep(0.5)\n        assert multiplexer._send_loop_task.done()\n    finally:\n        await multiplexer.disconnect()\n\n\n@pytest.mark.asyncio\nasync def test_inbox_outbox():\n    \"\"\"Test InBox OutBox objects.\"\"\"\n    connection_1 = _make_dummy_connection()\n    connections = [connection_1]\n    multiplexer = AsyncMultiplexer(connections, loop=asyncio.get_event_loop())\n    msg = DefaultMessage(\n        performative=DefaultMessage.Performative.BYTES,\n        content=b\"\",\n    )\n    msg.to = \"to\"\n    msg.sender = \"sender\"\n    envelope = Envelope(\n        to=\"to\",\n        sender=\"sender\",\n        message=msg,\n    )\n    try:\n        await multiplexer.connect()\n        inbox = InBox(multiplexer)\n        outbox = OutBox(multiplexer)\n\n        assert inbox.empty()\n        assert outbox.empty()\n\n        outbox.put(envelope)\n        received = await inbox.async_get()\n        assert received == envelope\n\n        assert inbox.empty()\n        assert outbox.empty()\n\n        outbox.put_message(msg)\n        await inbox.async_wait()\n        received = inbox.get_nowait()\n        assert received == envelope\n\n    finally:\n        await multiplexer.disconnect()\n\n\n@pytest.mark.asyncio\nasync def test_threaded_mode():\n    \"\"\"Test InBox OutBox objects in threaded mode.\"\"\"\n    connection_1 = _make_dummy_connection()\n    connections = [connection_1]\n    multiplexer = AsyncMultiplexer(connections, threaded=True)\n    msg = DefaultMessage(\n        performative=DefaultMessage.Performative.BYTES,\n        content=b\"\",\n    )\n    msg.to = \"to\"\n    msg.sender = \"sender\"\n    envelope = Envelope(to=\"to\", sender=\"sender\", message=msg)\n    try:\n        await multiplexer.connect()\n        await asyncio.sleep(0.5)\n        inbox = InBox(multiplexer)\n        outbox = OutBox(multiplexer)\n\n        assert inbox.empty()\n        assert outbox.empty()\n\n        outbox.put(envelope)\n        received = await inbox.async_get()\n        assert received == envelope\n\n        assert inbox.empty()\n        assert outbox.empty()\n\n        outbox.put_message(msg)\n        await inbox.async_wait()\n        received = inbox.get_nowait()\n        assert received == envelope\n\n    finally:\n        await multiplexer.disconnect()\n\n\n@pytest.mark.asyncio\nasync def test_outbox_negative():\n    \"\"\"Test InBox OutBox objects.\"\"\"\n    connection_1 = _make_dummy_connection()\n    connections = [connection_1]\n    multiplexer = AsyncMultiplexer(connections, loop=asyncio.get_event_loop())\n    msg = DefaultMessage(\n        performative=DefaultMessage.Performative.BYTES,\n        content=b\"\",\n    )\n    context = EnvelopeContext(connection_id=connection_1.connection_id)\n    envelope = Envelope(\n        to=\"to\",\n        sender=\"sender\",\n        protocol_specification_id=msg.protocol_specification_id,\n        message=b\"\",\n        context=context,\n    )\n\n    try:\n        await multiplexer.connect()\n        outbox = OutBox(multiplexer)\n\n        assert outbox.empty()\n\n        with pytest.raises(ValueError) as execinfo:\n            outbox.put(envelope)\n        assert (\n            str(execinfo.value)\n            == \"Only Message type allowed in envelope message field when putting into outbox.\"\n        )\n\n        assert outbox.empty()\n\n        with pytest.raises(ValueError) as execinfo:\n            outbox.put_message(\"\")\n        assert str(execinfo.value) == \"Provided message not of type Message.\"\n\n        assert outbox.empty()\n\n        with pytest.raises(ValueError) as execinfo:\n            outbox.put_message(msg)\n        assert str(execinfo.value) == \"Provided message has message.to not set.\"\n\n        assert outbox.empty()\n        msg.to = \"to\"\n\n        with pytest.raises(ValueError) as execinfo:\n            outbox.put_message(msg)\n        assert str(execinfo.value) == \"Provided message has message.sender not set.\"\n\n    finally:\n        await multiplexer.disconnect()\n\n\nDefaultProtocolMock = Mock()\nDefaultProtocolMock.protocol_id = DefaultMessage.protocol_id\nDefaultProtocolMock.protocol_specification_id = DefaultMessage.protocol_specification_id\n\n\n@pytest.mark.asyncio\nasync def test_default_route_applied(caplog):\n    \"\"\"Test default route is selected automatically.\"\"\"\n    logger = logging.getLogger(\"aea.multiplexer\")\n    with caplog.at_level(logging.DEBUG, logger=\"aea.multiplexer\"):\n        connection_1 = _make_dummy_connection()\n        connections = [connection_1]\n        multiplexer = AsyncMultiplexer(\n            connections, loop=asyncio.get_event_loop(), protocols=[DefaultProtocolMock]\n        )\n        multiplexer.logger = logger\n        envelope = Envelope(\n            to=\"\",\n            sender=\"\",\n            protocol_specification_id=DefaultMessage.protocol_specification_id,\n            message=b\"\",\n            context=EnvelopeContext(),\n        )\n        multiplexer.default_routing = {\n            DefaultMessage.protocol_id: connection_1.connection_id\n        }\n        try:\n            await multiplexer.connect()\n            inbox = InBox(multiplexer)\n            outbox = InBox(multiplexer)\n\n            assert inbox.empty()\n            assert outbox.empty()\n            multiplexer.put(envelope)\n            await outbox.async_get()\n        finally:\n            await multiplexer.disconnect()\n\n            assert \"Using default routing:\" in caplog.text\n\n\n@pytest.mark.asyncio\nasync def test_connection_id_in_to_field_detected(caplog):\n    \"\"\"Test to field is parsed correctly and used for routing.\"\"\"\n    logger = logging.getLogger(\"aea.multiplexer\")\n    with caplog.at_level(logging.DEBUG, logger=\"aea.multiplexer\"):\n        connection_1 = _make_dummy_connection()\n        connections = [connection_1]\n        multiplexer = AsyncMultiplexer(\n            connections, loop=asyncio.get_event_loop(), protocols=[DefaultProtocolMock]\n        )\n        multiplexer.logger = logger\n        envelope = Envelope(\n            to=str(connection_1.connection_id),\n            sender=\"some_author/some_skill:0.1.0\",\n            protocol_specification_id=DefaultMessage.protocol_specification_id,\n            message=b\"\",\n        )\n        try:\n            await multiplexer.connect()\n            inbox = InBox(multiplexer)\n            outbox = InBox(multiplexer)\n\n            assert inbox.empty()\n            assert outbox.empty()\n            multiplexer.put(envelope)\n            await outbox.async_get()\n        finally:\n            await multiplexer.disconnect()\n\n            assert \"Using envelope `to` field as connection_id:\" in caplog.text\n\n\n@pytest.mark.asyncio\nasync def test_routing_helper_applied(caplog):\n    \"\"\"Test the routing helper is used for routing.\"\"\"\n    logger = logging.getLogger(\"aea.multiplexer\")\n    with caplog.at_level(logging.DEBUG, logger=\"aea.multiplexer\"):\n        connection_1 = _make_dummy_connection()\n        connections = [connection_1]\n        multiplexer = AsyncMultiplexer(\n            connections, loop=asyncio.get_event_loop(), protocols=[DefaultProtocolMock]\n        )\n        multiplexer.logger = logger\n        envelope = Envelope(\n            to=\"test\",\n            sender=\"\",\n            protocol_specification_id=DefaultMessage.protocol_specification_id,\n            message=b\"\",\n        )\n        multiplexer._routing_helper[envelope.to] = connection_1.connection_id\n        try:\n            await multiplexer.connect()\n            inbox = InBox(multiplexer)\n            outbox = InBox(multiplexer)\n\n            assert inbox.empty()\n            assert outbox.empty()\n            multiplexer.put(envelope)\n            await outbox.async_get()\n        finally:\n            await multiplexer.disconnect()\n\n            assert (\n                f\"Using routing helper with connection_id: {connection_1.connection_id}\"\n                in caplog.text\n            )\n\n\ndef test_multiplexer_setup():\n    \"\"\"Test multiplexer setup to set connections.\"\"\"\n    node = LocalNode()\n    tmpdir = Path(tempfile.mkdtemp())\n    d = tmpdir / \"test_stub\"\n    d.mkdir(parents=True)\n    input_file_path = d / \"input_file.csv\"\n    output_file_path = d / \"input_file.csv\"\n\n    connection_1 = _make_local_connection(\"my_addr\", \"my_public_key\", node)\n    connection_2 = _make_stub_connection(input_file_path, output_file_path)\n    connection_3 = _make_dummy_connection()\n    connections = [connection_1, connection_2, connection_3]\n    multiplexer = Multiplexer([])\n    with unittest.mock.patch.object(multiplexer.logger, \"debug\") as mock_logger_debug:\n        multiplexer._connection_consistency_checks()\n        mock_logger_debug.assert_called_with(\"List of connections is empty.\")\n    multiplexer._setup(connections, default_routing=None)\n    multiplexer._connection_consistency_checks()\n\n\nclass TestExceptionHandlingOnConnectionSend:\n    \"\"\"Test exception handling policy on connection.send.\"\"\"\n\n    def setup(self):\n        \"\"\"Set up test case.\"\"\"\n        self.connection = _make_dummy_connection()\n        self.multiplexer = Multiplexer(\n            [self.connection], protocols=[DefaultProtocolMock]\n        )\n        self.multiplexer.connect()\n\n        self.envelope = Envelope(\n            to=\"\",\n            sender=\"\",\n            protocol_specification_id=DefaultMessage.protocol_specification_id,\n            message=b\"\",\n            context=EnvelopeContext(connection_id=self.connection.connection_id),\n        )\n        self.exception = ValueError(\"expected\")\n\n    def teardown(self):\n        \"\"\"Tear down test case.\"\"\"\n        self.multiplexer.disconnect()\n\n    def test_log_policy(self):\n        \"\"\"Test just log exception.\"\"\"\n        with patch.object(self.connection, \"send\", side_effect=self.exception):\n            self.multiplexer._exception_policy = ExceptionPolicyEnum.just_log\n            self.multiplexer.put(self.envelope)\n            time.sleep(1)\n            assert not self.multiplexer._send_loop_task.done()\n\n    def test_propagate_policy(self):\n        \"\"\"Test propagate exception.\"\"\"\n        assert self.multiplexer._exception_policy == ExceptionPolicyEnum.propagate\n\n        with patch.object(self.connection, \"send\", side_effect=self.exception):\n            self.multiplexer.put(self.envelope)\n            time.sleep(1)\n            wait_for_condition(\n                lambda: self.multiplexer._send_loop_task.done(), timeout=5\n            )\n            assert self.multiplexer._send_loop_task.exception() == self.exception\n\n    def test_stop_policy(self):\n        \"\"\"Test stop multiplexer on exception.\"\"\"\n        with patch.object(self.connection, \"send\", side_effect=self.exception):\n            self.multiplexer._exception_policy = ExceptionPolicyEnum.stop_and_exit\n            self.multiplexer.put(self.envelope)\n            time.sleep(1)\n            wait_for_condition(\n                lambda: self.multiplexer.connection_status.is_disconnected, timeout=5\n            )\n\n    def test_disconnect_order(self):\n        \"\"\"Test disconnect order: tasks first, disconnect_all next.\"\"\"\n        parent = MagicMock()\n\n        async def fn():\n            return\n\n        with patch.object(\n            self.multiplexer, \"_stop_receive_send_loops\", return_value=fn()\n        ) as stop_loops, patch.object(\n            self.multiplexer, \"_disconnect_all\", return_value=fn()\n        ) as disconnect_all, patch.object(\n            self.multiplexer, \"_check_and_set_disconnected_state\"\n        ) as check_and_set_disconnected_state:\n            parent.attach_mock(stop_loops, \"stop_loops\")\n            parent.attach_mock(disconnect_all, \"disconnect_all\")\n            parent.attach_mock(\n                check_and_set_disconnected_state, \"check_and_set_disconnected_state\"\n            )\n            self.multiplexer.disconnect()\n            assert parent.mock_calls == [\n                call.stop_loops(),\n                call.disconnect_all(),\n                call.check_and_set_disconnected_state(),\n            ]\n\n\nclass TestMultiplexerDisconnectsOnTermination:  # pylint: disable=attribute-defined-outside-init\n    \"\"\"Test multiplexer disconnects on  agent process keyboard interrupted.\"\"\"\n\n    def setup(self):\n        \"\"\"Set the test up.\"\"\"\n        self.proc = None\n        self.runner = CliRunner()\n        self.agent_name = \"myagent\"\n        self.cwd = os.getcwd()\n        self.t = tempfile.mkdtemp()\n        shutil.copytree(Path(ROOT_DIR, \"packages\"), Path(self.t, \"packages\"))\n        os.chdir(self.t)\n        self.key_path = os.path.join(self.t, \"fetchai_private_key.txt\")\n        self.conn_key_path = os.path.join(self.t, \"conn_private_key.txt\")\n\n        result = self.runner.invoke(cli, [*CLI_LOG_OPTION, \"init\", \"--author\", AUTHOR])\n        assert result.exit_code == 0\n\n        result = self.runner.invoke(\n            cli, [*CLI_LOG_OPTION, \"create\", \"--local\", self.agent_name]\n        )\n        assert result.exit_code == 0\n\n        os.chdir(Path(self.t, self.agent_name))\n\n        result = self.runner.invoke(\n            cli, [*CLI_LOG_OPTION, \"generate-key\", DEFAULT_LEDGER, self.key_path]\n        )\n        assert result.exit_code == 0, result.stdout_bytes\n\n        result = self.runner.invoke(\n            cli, [*CLI_LOG_OPTION, \"add-key\", DEFAULT_LEDGER, self.key_path]\n        )\n        assert result.exit_code == 0, result.stdout_bytes\n\n    def test_multiplexer_disconnected_on_early_interruption(self):\n        \"\"\"Test multiplexer disconnected properly on termination before connected.\"\"\"\n        result = self.runner.invoke(\n            cli, [*CLI_LOG_OPTION, \"add\", \"--local\", \"connection\", str(P2P_PUBLIC_ID)]\n        )\n        assert result.exit_code == 0, result.stdout_bytes\n\n        result = self.runner.invoke(cli, [*CLI_LOG_OPTION, \"build\"])\n        assert result.exit_code == 0, result.stdout_bytes\n\n        result = self.runner.invoke(\n            cli, [*CLI_LOG_OPTION, \"generate-key\", DEFAULT_LEDGER, self.conn_key_path]\n        )\n        assert result.exit_code == 0, result.stdout_bytes\n\n        result = self.runner.invoke(\n            cli,\n            [\n                *CLI_LOG_OPTION,\n                \"add-key\",\n                DEFAULT_LEDGER,\n                self.conn_key_path,\n                \"--connection\",\n            ],\n        )\n        assert result.exit_code == 0, result.stdout_bytes\n\n        result = self.runner.invoke(cli, [*CLI_LOG_OPTION, \"issue-certificates\"])\n        assert result.exit_code == 0, result.stdout_bytes\n\n        self.proc = PexpectWrapper(  # nosec\n            [sys.executable, \"-m\", \"aea.cli\", \"-v\", \"DEBUG\", \"run\"],\n            env=os.environ,\n            maxread=10000,\n            encoding=\"utf-8\",\n            logfile=sys.stdout,\n        )\n\n        self.proc.expect_all(\n            [\"Starting libp2p node...\"],\n            timeout=50,\n        )\n        self.proc.control_c()\n        self.proc.expect_all(\n            [\"Multiplexer .*disconnected.\"],\n            timeout=20,\n            strict=False,\n        )\n\n        self.proc.expect_all(\n            [EOF],\n            timeout=20,\n        )\n\n    def test_multiplexer_disconnected_on_termination_after_connected_no_connection(\n        self,\n    ):\n        \"\"\"Test multiplexer disconnected properly on termination after connected.\"\"\"\n        self.proc = PexpectWrapper(  # nosec\n            [sys.executable, \"-m\", \"aea.cli\", \"-v\", \"DEBUG\", \"run\"],\n            env=os.environ,\n            maxread=10000,\n            encoding=\"utf-8\",\n            logfile=sys.stdout,\n        )\n\n        self.proc.expect_all(\n            [\"Start processing messages...\"],\n            timeout=20,\n        )\n        self.proc.control_c()\n        self.proc.expect_all(\n            [\"Multiplexer disconnecting...\", \"Multiplexer disconnected.\", EOF],\n            timeout=20,\n        )\n\n    def test_multiplexer_disconnected_on_termination_after_connected_one_connection(\n        self,\n    ):\n        \"\"\"Test multiplexer disconnected properly on termination after connected.\"\"\"\n\n        result = self.runner.invoke(\n            cli,\n            [*CLI_LOG_OPTION, \"add\", \"--local\", \"connection\", str(STUB_CONNECTION_ID)],\n        )\n        assert result.exit_code == 0, result.stdout_bytes\n\n        self.proc = PexpectWrapper(  # nosec\n            [sys.executable, \"-m\", \"aea.cli\", \"-v\", \"DEBUG\", \"run\"],\n            env=os.environ,\n            maxread=10000,\n            encoding=\"utf-8\",\n            logfile=sys.stdout,\n        )\n\n        self.proc.expect_all(\n            [\"Start processing messages...\"],\n            timeout=20,\n        )\n        self.proc.control_c()\n        self.proc.expect_all(\n            [\"Multiplexer disconnecting...\", \"Multiplexer disconnected.\", EOF],\n            timeout=20,\n        )\n\n    def teardown(self):\n        \"\"\"Tear the test down.\"\"\"\n        if self.proc:\n            self.proc.wait_to_complete(10)\n        os.chdir(self.cwd)\n        try:\n            shutil.rmtree(self.t)\n        except (OSError, IOError):\n            pass\n\n\ndef test_multiplexer_setup_replaces_connections():\n    \"\"\"Test proper connections reset on setup call.\"\"\"\n    m = AsyncMultiplexer([MagicMock(), MagicMock(), MagicMock()])\n    assert len(m._id_to_connection) == 3\n    assert len(m._connections) == 3\n\n    m._setup([MagicMock()], MagicMock())\n    assert len(m._id_to_connection) == 1\n    assert len(m._connections) == 1\n\n\ndef test_connect_after_disconnect_sync():\n    \"\"\"Test connect-disconnect-connect again for threaded multiplexer.\"\"\"\n    multiplexer = Multiplexer([_make_dummy_connection()])\n\n    assert not multiplexer.connection_status.is_connected\n    multiplexer.connect()\n    assert multiplexer.connection_status.is_connected\n    multiplexer.disconnect()\n    assert not multiplexer.connection_status.is_connected\n\n    multiplexer.connect()\n    assert multiplexer.connection_status.is_connected\n    multiplexer.disconnect()\n    assert not multiplexer.connection_status.is_connected\n\n\n@pytest.mark.asyncio\nasync def test_connect_after_disconnect_async():\n    \"\"\"Test connect-disconnect-connect again for async multiplexer.\"\"\"\n    multiplexer = AsyncMultiplexer([_make_dummy_connection()])\n\n    assert not multiplexer.connection_status.is_connected\n    await multiplexer.connect()\n    assert multiplexer.connection_status.is_connected\n    await multiplexer.disconnect()\n    assert not multiplexer.connection_status.is_connected\n\n    await multiplexer.connect()\n    assert multiplexer.connection_status.is_connected\n    await multiplexer.disconnect()\n    assert not multiplexer.connection_status.is_connected\n\n\n@pytest.mark.asyncio\nasync def test_connection_timeouts():\n    \"\"\"Test connect,send, disconnect timeouts for connections.\"\"\"\n\n    async def slow_fn(*asrgs, **kwargs):\n        await asyncio.sleep(100)\n\n    connection = _make_dummy_connection()\n    envelope = Envelope(\n        to=\"\",\n        sender=\"\",\n        message=DefaultMessage(performative=DefaultMessage.Performative.BYTES),\n        context=EnvelopeContext(connection_id=connection.connection_id),\n    )\n\n    connection = _make_dummy_connection()\n    connection.connect = slow_fn\n    multiplexer = AsyncMultiplexer([connection])\n\n    multiplexer.CONNECT_TIMEOUT = 0.1\n    with pytest.raises(AEAConnectionError, match=r\"TimeoutError\"):\n        await multiplexer.connect()\n\n    connection = _make_dummy_connection()\n    connection.send = slow_fn\n    multiplexer = AsyncMultiplexer([connection])\n\n    multiplexer.SEND_TIMEOUT = 0.1\n    await multiplexer.connect()\n    with pytest.raises(asyncio.TimeoutError):\n        await multiplexer._send(envelope)\n    await multiplexer.disconnect()\n\n    connection = _make_dummy_connection()\n    connection.disconnect = slow_fn\n    multiplexer = AsyncMultiplexer([connection])\n\n    multiplexer.DISCONNECT_TIMEOUT = 0.1\n    await multiplexer.connect()\n    with pytest.raises(\n        AEAConnectionError,\n        match=f\"Failed to disconnect multiplexer, some connections are not disconnected.*{str(connection.connection_id)}\",\n    ):\n        await multiplexer.disconnect()\n\n\n@pytest.mark.asyncio\nasync def test_stops_on_connectionerror_during_connect():\n    \"\"\"Test multiplexer stopped and reraise exception on connect fails on conection.connect with AEAConnectionError.\"\"\"\n\n    connection = _make_dummy_connection()\n\n    multiplexer = AsyncMultiplexer([connection])\n\n    with patch.object(\n        connection, \"connect\", side_effect=AEAConnectionError(\"expected\")\n    ):\n        with pytest.raises(AEAConnectionError, match=r\"expected\"):\n            await multiplexer.connect()\n\n    assert multiplexer.connection_status.is_disconnected\n"
  },
  {
    "path": "tests/test_aea/test_package_loading.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains tests for AEA package loading.\"\"\"\nimport os\nimport sys\nfrom unittest.mock import Mock\n\nimport pytest\n\nfrom aea.skills.base import Skill\n\nfrom tests.conftest import CUR_PATH\n\n\ndef test_loading():\n    \"\"\"Test that we correctly load AEA package modules.\"\"\"\n    agent_context_mock = Mock(agent_name=\"name\")\n    skill_directory = os.path.join(CUR_PATH, \"data\", \"dummy_skill\")\n\n    prefixes = [\n        \"packages\",\n        \"packages.dummy_author\",\n        \"packages.dummy_author.skills\",\n        \"packages.dummy_author.skills.dummy\",\n        \"packages.dummy_author.skills.dummy.dummy_subpackage\",\n    ]\n    Skill.from_dir(skill_directory, agent_context_mock)\n    assert all(\n        prefix in sys.modules for prefix in prefixes\n    ), \"Not all the subpackages are importable.\"\n\n    # try to import a function from a skill submodule.\n    from packages.dummy_author.skills.dummy.dummy_subpackage.foo import (  # type: ignore\n        bar,\n    )\n\n    assert bar() == 42\n\n    import packages  # type: ignore\n    import packages.dummy_author  # type: ignore\n    import packages.dummy_author.skills  # type: ignore\n    import packages.dummy_author.skills.dummy  # type: ignore\n\n    with pytest.raises(\n        ModuleNotFoundError, match=\"No module named 'packages.dummy_author.connections'\"\n    ):\n        import packages.dummy_author.connections  # type: ignore\n\n    with pytest.raises(\n        ModuleNotFoundError,\n        match=\"No module named 'packages.dummy_author.skills.not_exists_skill'\",\n    ):\n        import packages.dummy_author.skills.not_exists_skill  # type: ignore # noqa # flake8: noqa\n"
  },
  {
    "path": "tests/test_aea/test_protocols/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"The test protocols module contains the tests of the AEA protocols.\"\"\"\n"
  },
  {
    "path": "tests/test_aea/test_protocols/test_base.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests of the protocols base module.\"\"\"\n\nimport os\nimport shutil\nimport tempfile\nfrom copy import copy\nfrom enum import Enum\nfrom pathlib import Path\nfrom typing import Callable, List, Tuple, Type\nfrom unittest.mock import Mock\n\nimport pytest\nfrom google.protobuf.struct_pb2 import Struct\n\nfrom aea.exceptions import AEAEnforceError\nfrom aea.mail.base import Envelope\nfrom aea.mail.base_pb2 import DialogueMessage as Pb2DialogueMessage\nfrom aea.mail.base_pb2 import Message as ProtobufMessage\nfrom aea.protocols.base import Message, Protocol, Serializer\nfrom aea.protocols.dialogue.base import Dialogue, DialogueLabel\n\nfrom packages.fetchai.protocols.default.dialogues import (\n    DefaultDialogue,\n    DefaultDialogues,\n)\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.protocols.signing.dialogues import (\n    SigningDialogue,\n    SigningDialogues,\n)\nfrom packages.fetchai.protocols.state_update.dialogues import (\n    StateUpdateDialogue,\n    StateUpdateDialogues,\n)\n\nfrom tests.conftest import ROOT_DIR, UNKNOWN_PROTOCOL_PUBLIC_ID\n\n\ndef role_from_first_message_dd(\n    message: Message, receiver_address: str\n) -> Dialogue.Role:\n    \"\"\"Role from first message.\"\"\"\n    return DefaultDialogue.Role.AGENT\n\n\ndef role_from_first_message_sd(\n    message: Message, receiver_address: str\n) -> Dialogue.Role:\n    \"\"\"Role from first message.\"\"\"\n    return SigningDialogue.Role.SKILL\n\n\ndef role_from_first_message_sud(\n    message: Message, receiver_address: str\n) -> Dialogue.Role:\n    \"\"\"Role from first message.\"\"\"\n    return StateUpdateDialogue.Role.SKILL\n\n\nDIALOGUE_CLASSES: List[Tuple[Type, Type, Enum, Callable]] = [\n    (\n        DefaultDialogue,\n        DefaultDialogues,\n        DefaultDialogue.Role.AGENT,\n        role_from_first_message_dd,\n    ),\n    (\n        SigningDialogue,\n        SigningDialogues,\n        SigningDialogue.Role.SKILL,\n        role_from_first_message_sd,\n    ),\n    (\n        StateUpdateDialogue,\n        StateUpdateDialogues,\n        StateUpdateDialogue.Role.SKILL,\n        role_from_first_message_sud,\n    ),\n]\n\n\nclass TMessage(Message):\n    \"\"\"Message class for tests.\"\"\"\n\n    class _SlotsCls:\n        __slots__ = (\n            \"body_1\",\n            \"body_2\",\n            \"kwarg\",\n            \"content\",\n            \"performative\",\n            \"dialogue_reference\",\n            \"message_id\",\n            \"target\",\n        )\n\n\nclass TestMessageProperties:\n    \"\"\"Test that the base serializations work.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Setup test.\"\"\"\n        cls.body = {\"body_1\": \"1\", \"body_2\": \"2\"}\n        cls.kwarg = 1\n        cls.message = TMessage(cls.body, kwarg=cls.kwarg)\n\n    def test_message_properties(self):\n        \"\"\"Test message properties.\"\"\"\n        for key, value in self.body.items():\n            assert self.message.get(key) == value\n        assert self.message.get(\"kwarg\") == self.kwarg\n        assert not self.message.has_sender\n        assert not self.message.has_to\n        to = \"to\"\n        sender = \"sender\"\n        self.message.to = to\n        self.message.sender = sender\n        assert self.message.sender == sender\n        assert self.message.to == to\n        assert (\n            str(self.message)\n            == \"Message(sender=sender,to=to,body_1=1,body_2=2,kwarg=1)\"\n        )\n        assert (\n            repr(self.message)\n            == \"Message(sender=sender,to=to,body_1=1,body_2=2,kwarg=1)\"\n        )\n        assert self.message.valid_performatives == set()\n\n\nclass ExampleProtobufSerializer(Serializer):\n    \"\"\"\n    Example Protobuf serializer.\n\n    It assumes that the Message contains a JSON-serializable body.\n    \"\"\"\n\n    @staticmethod\n    def encode(msg: Message) -> bytes:\n        \"\"\"\n        Encode a message into bytes using Protobuf.\n\n        - if one of message_id, target and dialogue_reference are not defined,\n          serialize only the message body/\n        - otherwise, extract those fields from the body and instantiate\n          a Message struct.\n        \"\"\"\n        message_pb = ProtobufMessage()\n        if msg.has_dialogue_info:\n            dialogue_message_pb = Pb2DialogueMessage()\n            dialogue_message_pb.message_id = msg.message_id\n            dialogue_message_pb.dialogue_starter_reference = msg.dialogue_reference[0]\n            dialogue_message_pb.dialogue_responder_reference = msg.dialogue_reference[1]\n            dialogue_message_pb.target = msg.target\n\n            new_body = copy(msg._body)  # pylint: disable=protected-access\n            new_body.pop(\"message_id\")\n            new_body.pop(\"dialogue_reference\")\n            new_body.pop(\"target\")\n\n            body_json = Struct()\n            body_json.update(new_body)  # pylint: disable=no-member\n\n            dialogue_message_pb.content = (  # pylint: disable=no-member\n                body_json.SerializeToString()\n            )\n            message_pb.dialogue_message.CopyFrom(  # pylint: disable=no-member\n                dialogue_message_pb\n            )\n        else:\n            body_json = Struct()\n            body_json.update(msg._body)  # pylint: disable=no-member,protected-access\n            message_pb.body.CopyFrom(body_json)  # pylint: disable=no-member\n\n        return message_pb.SerializeToString()\n\n    @staticmethod\n    def decode(obj: bytes) -> Message:\n        \"\"\"\n        Decode bytes into a message using Protobuf.\n\n        First, try to parse the input as a Protobuf 'Message';\n        if it fails, parse the bytes as struct.\n        \"\"\"\n        message_pb = ProtobufMessage()\n        message_pb.ParseFromString(obj)\n        message_type = message_pb.WhichOneof(\"message\")\n        if message_type == \"body\":\n            body = dict(message_pb.body)  # pylint: disable=no-member\n            msg = TMessage(_body=body)\n            return msg\n        if message_type == \"dialogue_message\":\n            dialogue_message_pb = (\n                message_pb.dialogue_message  # pylint: disable=no-member\n            )\n            message_id = dialogue_message_pb.message_id\n            target = dialogue_message_pb.target\n            dialogue_starter_reference = dialogue_message_pb.dialogue_starter_reference\n            dialogue_responder_reference = (\n                dialogue_message_pb.dialogue_responder_reference\n            )\n            body_json = Struct()\n            body_json.ParseFromString(dialogue_message_pb.content)\n            body = dict(body_json)\n            body[\"message_id\"] = message_id\n            body[\"target\"] = target\n            body[\"dialogue_reference\"] = (\n                dialogue_starter_reference,\n                dialogue_responder_reference,\n            )\n            return TMessage(_body=body)\n        raise ValueError(\"Message type not recognized.\")  # pragma: nocover\n\n\nclass TestBaseSerializations:\n    \"\"\"Test that the base serializations work.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set up the use case.\"\"\"\n        cls.message = TMessage(content=\"hello\")\n        cls.message2 = TMessage(_body={\"content\": \"hello\"})\n        cls.message3 = TMessage(\n            message_id=1,\n            target=0,\n            dialogue_reference=(\"\", \"\"),\n            _body={\"content\": \"hello\"},\n        )\n\n    def test_default_protobuf_serialization(self):\n        \"\"\"Test that the default Protobuf serialization works.\"\"\"\n        message_bytes = ExampleProtobufSerializer().encode(self.message)\n        envelope = Envelope(\n            to=\"receiver\",\n            sender=\"sender\",\n            protocol_specification_id=UNKNOWN_PROTOCOL_PUBLIC_ID,\n            message=message_bytes,\n        )\n        envelope_bytes = envelope.encode()\n\n        expected_envelope = Envelope.decode(envelope_bytes)\n        actual_envelope = envelope\n        assert expected_envelope == actual_envelope\n\n        expected_msg = ExampleProtobufSerializer().decode(expected_envelope.message)\n        actual_msg = self.message\n        assert expected_msg == actual_msg\n\n    def test_default_protobuf_serialization_with_dialogue_info(self):\n        \"\"\"Test that the default Protobuf serialization with dialogue info works.\"\"\"\n        message_bytes = ExampleProtobufSerializer().encode(self.message3)\n        envelope = Envelope(\n            to=\"receiver\",\n            sender=\"sender\",\n            protocol_specification_id=UNKNOWN_PROTOCOL_PUBLIC_ID,\n            message=message_bytes,\n        )\n        envelope_bytes = envelope.encode()\n\n        expected_envelope = Envelope.decode(envelope_bytes)\n        actual_envelope = envelope\n        assert expected_envelope == actual_envelope\n\n        expected_msg = ExampleProtobufSerializer().decode(expected_envelope.message)\n        actual_msg = self.message3\n        assert expected_msg == actual_msg\n\n    def test_set(self):\n        \"\"\"Test that the set method works.\"\"\"\n        self.message._body = {}  # clean values\n        key, value = \"content\", \"temporary_value\"\n        assert self.message.get(key) is None\n        self.message.set(key, value)\n        assert self.message.get(key) == value\n\n    def test_body_setter(self):\n        \"\"\"Test the body setter.\"\"\"\n        m_dict = {\"content\": \"data\"}\n        self.message2._body = m_dict\n        assert self.message2._body == m_dict\n\n\nclass TestMessageEncode:\n    \"\"\"Test the 'Protocol.from_dir' method.\"\"\"\n\n    def test_encode(self):\n        \"\"\"Test encode on message.\"\"\"\n\n        class TTMessage(TMessage):\n            \"\"\"Test class extended.\"\"\"\n\n            serializer = ExampleProtobufSerializer\n\n        msg = TTMessage({\"body_1\": \"1\", \"body_2\": \"2\"})\n        msg.encode()\n\n\nclass TestProtocolFromDir:\n    \"\"\"Test the 'Protocol.from_dir' method.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the tests up.\"\"\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        shutil.copytree(Path(ROOT_DIR, \"packages\"), Path(cls.t, \"packages\"))\n        os.chdir(cls.t)\n\n    def test_protocol_load_positive(self):\n        \"\"\"Test protocol loaded correctly.\"\"\"\n        default_protocol = Protocol.from_dir(\n            Path(\"packages\", \"fetchai\", \"protocols\", \"default\")\n        )\n        assert str(default_protocol.public_id) == str(\n            DefaultMessage.protocol_id\n        ), \"Protocol not loaded correctly.\"\n        assert str(default_protocol.protocol_specification_id) == str(\n            DefaultMessage.protocol_specification_id\n        ), \"Protocol not loaded correctly.\"\n        assert default_protocol.serializer is not None\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the tests down.\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestMessageAttributes:\n    \"\"\"Test some message attributes.\"\"\"\n\n    def test_performative(self):\n        \"\"\"Test message performative.\"\"\"\n\n        class SomePerformative(Message.Performative):\n            value = \"value\"\n\n        message = Message(performative=SomePerformative.value)\n        assert message.performative == SomePerformative.value\n        assert str(message.performative) == \"value\"\n\n    def test_to(self):\n        \"\"\"Test the 'to' attribute getter and setter.\"\"\"\n        message = Message()\n        with pytest.raises(ValueError, match=\"Message's 'To' field must be set.\"):\n            message.to\n\n        message.to = \"to\"\n        assert message.to == \"to\"\n\n        with pytest.raises(AEAEnforceError, match=\"To already set.\"):\n            message.to = \"to\"\n\n    def test_dialogue_reference(self):\n        \"\"\"Test the 'dialogue_reference' attribute.\"\"\"\n        message = Message(dialogue_reference=(\"x\", \"y\"))\n        assert message.dialogue_reference == (\"x\", \"y\")\n\n    def test_message_id(self):\n        \"\"\"Test the 'message_id' attribute.\"\"\"\n        message = Message(message_id=1)\n        assert message.message_id == 1\n\n    def test_target(self):\n        \"\"\"Test the 'target' attribute.\"\"\"\n        message = Message(target=1)\n        assert message.target == 1\n\n\n@pytest.mark.parametrize(\"dialogue_classes\", DIALOGUE_CLASSES)\ndef test_dialogue(dialogue_classes):\n    \"\"\"Test dialogue initialization.\"\"\"\n    dialogue_class, _, role, _ = dialogue_classes\n    dialogue_class(\n        DialogueLabel((\"x\", \"y\"), \"opponent_addr\", \"starer_addr\"), \"agent_address\", role\n    )\n\n\n@pytest.mark.parametrize(\"dialogues_classes\", DIALOGUE_CLASSES)\ndef test_dialogues(dialogues_classes):\n    \"\"\"Test dialogues initialization.\"\"\"\n    dialogue_class, dialogues_class, _, role_from_first_message = dialogues_classes\n    dialogues_class(\"agent_address\", role_from_first_message, dialogue_class)\n\n\ndef test_protocol_repr():\n    \"\"\"Test protocol repr.\"\"\"\n    config_mock = Mock()\n    config_mock.public_id = UNKNOWN_PROTOCOL_PUBLIC_ID\n    protocol = Protocol(config_mock, message_class=Message)\n    assert repr(protocol) == f\"Protocol({UNKNOWN_PROTOCOL_PUBLIC_ID})\"\n"
  },
  {
    "path": "tests/test_aea/test_protocols/test_dialogue/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests for the dialogue helper module.\"\"\"\n"
  },
  {
    "path": "tests/test_aea/test_protocols/test_dialogue/test_base.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests for the dialogue/base.py module.\"\"\"\nimport re\nimport sys\nfrom typing import FrozenSet, Tuple, Type, cast\nfrom unittest import mock\nfrom unittest.mock import Mock, patch\n\nimport pytest\n\nimport aea\nfrom aea.common import Address\nfrom aea.configurations.base import PublicId\nfrom aea.exceptions import AEAEnforceError\nfrom aea.helpers.storage.generic_storage import Storage\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import BasicDialoguesStorage\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\nfrom aea.protocols.dialogue.base import DialogueLabel, DialogueMessage, DialogueStats\nfrom aea.protocols.dialogue.base import Dialogues as BaseDialogues\nfrom aea.protocols.dialogue.base import (\n    InvalidDialogueMessage,\n    PersistDialoguesStorage,\n    PersistDialoguesStorageWithOffloading,\n    find_caller_object,\n)\nfrom aea.skills.base import SkillComponent\n\nfrom packages.fetchai.protocols.default.custom_types import ErrorCode\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.protocols.state_update.message import StateUpdateMessage\n\nfrom tests.common.utils import wait_for_condition\n\n\nclass Dialogue(BaseDialogue):\n    \"\"\"This concrete class defines a dialogue.\"\"\"\n\n    INITIAL_PERFORMATIVES = frozenset({DefaultMessage.Performative.BYTES})\n    TERMINAL_PERFORMATIVES = frozenset({DefaultMessage.Performative.ERROR})\n    VALID_REPLIES = {\n        DefaultMessage.Performative.BYTES: frozenset(\n            {DefaultMessage.Performative.BYTES, DefaultMessage.Performative.ERROR}\n        ),\n        DefaultMessage.Performative.ERROR: frozenset(),\n    }\n\n    class Role(BaseDialogue.Role):\n        \"\"\"This class defines the agent's role in this dialogue.\"\"\"\n\n        ROLE1 = \"role1\"\n        ROLE2 = \"role2\"\n\n    class EndState(BaseDialogue.EndState):\n        \"\"\"This class defines the end states of this dialogue.\"\"\"\n\n        SUCCESSFUL = 0\n        FAILED = 1\n\n    def __init__(\n        self,\n        dialogue_label: DialogueLabel,\n        message_class: Type[Message] = DefaultMessage,\n        self_address: Address = \"agent 1\",\n        role: BaseDialogue.Role = Role.ROLE1,\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n        :return: None\n        \"\"\"\n        BaseDialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            self_address=self_address,\n            role=role,\n            message_class=message_class,\n        )\n\n\nclass Dialogues(BaseDialogues):\n    \"\"\"This class gives a concrete definition of dialogues.\"\"\"\n\n    END_STATES = frozenset(\n        {Dialogue.EndState.SUCCESSFUL, Dialogue.EndState.FAILED}\n    )  # type: FrozenSet[BaseDialogue.EndState]\n\n    def __init__(\n        self,\n        self_address: Address,\n        message_class=DefaultMessage,\n        dialogue_class=Dialogue,\n        keep_terminal_state_dialogues=None,\n    ) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param self_address: the address of the entity for whom dialogues are maintained\n        :return: None\n        \"\"\"\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return Dialogue.Role.ROLE1\n\n        BaseDialogues.__init__(\n            self,\n            self_address=self_address,\n            end_states=cast(FrozenSet[BaseDialogue.EndState], self.END_STATES),\n            message_class=message_class,\n            dialogue_class=dialogue_class,\n            role_from_first_message=role_from_first_message,\n            keep_terminal_state_dialogues=keep_terminal_state_dialogues,\n        )\n\n\n@pytest.mark.skipif(\n    sys.version_info < (3, 7),\n    reason=\"This part of code is only defined for python version >= 3.7\",\n)\ndef test_dialogue_message_python_3_7():\n    \"\"\"Test DiallogueMessage if python is 3.7\"\"\"\n    dialogue_message = DialogueMessage(DefaultMessage.Performative.BYTES)\n    assert isinstance(dialogue_message.performative, Message.Performative)\n\n    assert dialogue_message.performative == DefaultMessage.Performative.BYTES\n    assert dialogue_message.contents == {}\n    assert dialogue_message.is_incoming is None\n    assert dialogue_message.target is None\n\n\n@pytest.mark.skipif(\n    sys.version_info >= (3, 7),\n    reason=\"This part of code is only defined for python version < 3.7\",\n)\ndef test_dialogue_message_python_3_6():\n    \"\"\"Test DiallogueMessage if python is 3.6\"\"\"\n    with mock.patch.object(\n        aea.protocols.dialogue.base.sys, \"version_info\", return_value=(3, 6)\n    ):\n        dialogue_message = DialogueMessage(DefaultMessage.Performative.BYTES)\n        assert isinstance(dialogue_message.performative, Message.Performative)\n\n        assert dialogue_message.performative == DefaultMessage.Performative.BYTES\n        assert dialogue_message.contents == {}\n        assert dialogue_message.is_incoming is None\n        assert dialogue_message.target is None\n\n\nclass TestDialogueLabel:\n    \"\"\"Test for DialogueLabel.\"\"\"\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Initialise the environment to test DialogueLabel.\"\"\"\n        cls.agent_address = \"agent 1\"\n        cls.opponent_address = \"agent 2\"\n        cls.dialogue_label = DialogueLabel(\n            dialogue_reference=(str(1), \"\"),\n            dialogue_opponent_addr=cls.opponent_address,\n            dialogue_starter_addr=cls.agent_address,\n        )\n\n    def test_all_methods(self):\n        \"\"\"Test the DialogueLabel.\"\"\"\n        assert self.dialogue_label.dialogue_reference == (str(1), \"\")\n        assert self.dialogue_label.dialogue_starter_reference == str(1)\n        assert self.dialogue_label.dialogue_responder_reference == \"\"\n        assert self.dialogue_label.dialogue_opponent_addr == self.opponent_address\n        assert self.dialogue_label.dialogue_starter_addr == self.agent_address\n        assert str(self.dialogue_label) == \"{}_{}_{}_{}\".format(\n            self.dialogue_label.dialogue_starter_reference,\n            self.dialogue_label.dialogue_responder_reference,\n            self.dialogue_label.dialogue_opponent_addr,\n            self.dialogue_label.dialogue_starter_addr,\n        )\n\n        dialogue_label_eq = DialogueLabel(\n            dialogue_reference=(str(1), \"\"),\n            dialogue_opponent_addr=self.opponent_address,\n            dialogue_starter_addr=self.agent_address,\n        )\n\n        assert dialogue_label_eq == self.dialogue_label\n\n        dialogue_label_not_eq = \"This is a test\"\n\n        assert not dialogue_label_not_eq == self.dialogue_label\n\n        assert hash(dialogue_label_eq) == hash(self.dialogue_label)\n\n        assert self.dialogue_label.json == dict(\n            dialogue_starter_reference=str(1),\n            dialogue_responder_reference=\"\",\n            dialogue_opponent_addr=self.opponent_address,\n            dialogue_starter_addr=self.agent_address,\n        )\n        assert DialogueLabel.from_json(self.dialogue_label.json) == self.dialogue_label\n        assert DialogueLabel.from_str(str(self.dialogue_label)) == self.dialogue_label\n\n\nclass TestDialogueBase:\n    \"\"\"Test for Dialogue.\"\"\"\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Initialise the environment to test Dialogue.\"\"\"\n        cls.incomplete_reference = (str(1), \"\")\n        cls.complete_reference = (str(1), str(1))\n        cls.opponent_address = \"agent 2\"\n        cls.agent_address = \"agent 1\"\n\n        cls.dialogue_label = DialogueLabel(\n            dialogue_reference=cls.incomplete_reference,\n            dialogue_opponent_addr=cls.opponent_address,\n            dialogue_starter_addr=cls.agent_address,\n        )\n        cls.dialogue = Dialogue(dialogue_label=cls.dialogue_label)\n\n        cls.dialogue_label_opponent_started = DialogueLabel(\n            dialogue_reference=cls.complete_reference,\n            dialogue_opponent_addr=cls.opponent_address,\n            dialogue_starter_addr=cls.opponent_address,\n        )\n        cls.dialogue_opponent_started = Dialogue(\n            dialogue_label=cls.dialogue_label_opponent_started\n        )\n\n        # convenient messages to reuse across tests\n        cls.valid_message_1_by_self = DefaultMessage(\n            dialogue_reference=(str(1), \"\"),\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"Hello\",\n        )\n        cls.valid_message_1_by_self.sender = cls.agent_address\n        cls.valid_message_1_by_self.to = cls.opponent_address\n\n        cls.valid_message_2_by_other = DefaultMessage(\n            dialogue_reference=(str(1), str(1)),\n            message_id=-1,\n            target=1,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"Hello back\",\n        )\n        cls.valid_message_2_by_other.sender = cls.opponent_address\n        cls.valid_message_2_by_other.to = cls.agent_address\n\n        cls.valid_message_3_by_self = DefaultMessage(\n            dialogue_reference=(str(1), str(1)),\n            message_id=2,\n            target=-1,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"Hello back 2\",\n        )\n        cls.valid_message_3_by_self.sender = cls.agent_address\n        cls.valid_message_3_by_self.to = cls.opponent_address\n\n    def test_inner_classes(self):\n        \"\"\"Test the inner classes: Role and EndStates.\"\"\"\n        assert str(Dialogue.Role.ROLE1) == \"role1\"\n        assert str(Dialogue.Role.ROLE2) == \"role2\"\n        assert str(Dialogue.EndState.SUCCESSFUL) == \"0\"\n        assert str(Dialogue.EndState.FAILED) == \"1\"\n\n    def test_dialogue_properties(self):\n        \"\"\"Test dialogue properties.\"\"\"\n        assert self.dialogue.dialogue_label == self.dialogue_label\n        assert self.dialogue.incomplete_dialogue_label == self.dialogue_label\n        assert self.dialogue.dialogue_labels == {self.dialogue_label}\n        assert self.dialogue.self_address == self.agent_address\n\n        assert self.dialogue.role == Dialogue.Role.ROLE1\n        assert str(self.dialogue.role) == \"role1\"\n\n        assert self.dialogue.rules.initial_performatives == frozenset(\n            {DefaultMessage.Performative.BYTES}\n        )\n        assert self.dialogue.rules.terminal_performatives == frozenset(\n            {DefaultMessage.Performative.ERROR}\n        )\n        assert self.dialogue.rules.valid_replies == {\n            DefaultMessage.Performative.BYTES: frozenset(\n                {DefaultMessage.Performative.BYTES, DefaultMessage.Performative.ERROR}\n            ),\n            DefaultMessage.Performative.ERROR: frozenset(),\n        }\n        assert self.dialogue.rules.get_valid_replies(\n            DefaultMessage.Performative.BYTES\n        ) == frozenset(\n            {DefaultMessage.Performative.BYTES, DefaultMessage.Performative.ERROR}\n        )\n        assert self.dialogue.rules.get_valid_replies(\n            DefaultMessage.Performative.ERROR\n        ) == frozenset({})\n        assert self.dialogue.message_class == DefaultMessage\n\n        assert self.dialogue.is_self_initiated\n\n        assert self.dialogue.last_incoming_message is None\n        assert self.dialogue.last_outgoing_message is None\n        assert self.dialogue.last_message is None\n\n        assert self.dialogue.is_empty\n\n    def test_counterparty_from_message(self):\n        \"\"\"Test the 'counterparty_from_message' method.\"\"\"\n        assert (\n            self.dialogue._counterparty_from_message(self.valid_message_1_by_self)\n            == self.opponent_address\n        )\n        assert (\n            self.dialogue._counterparty_from_message(self.valid_message_2_by_other)\n            == self.opponent_address\n        )\n\n    def test_is_message_by_self(self):\n        \"\"\"Test the 'is_message_by_self' method.\"\"\"\n        assert self.dialogue._is_message_by_self(self.valid_message_1_by_self)\n        assert not self.dialogue._is_message_by_self(self.valid_message_2_by_other)\n\n    def test_is_message_by_other(self):\n        \"\"\"Test the 'is_message_by_other' method.\"\"\"\n        assert not self.dialogue._is_message_by_other(self.valid_message_1_by_self)\n        assert self.dialogue._is_message_by_other(self.valid_message_2_by_other)\n\n    def test_try_get_message(self):\n        \"\"\"Test the 'try_get_message' method.\"\"\"\n        assert (\n            self.dialogue.get_message_by_id(self.valid_message_1_by_self.message_id)\n            is None\n        )\n        self.dialogue._update(self.valid_message_1_by_self)\n        assert (\n            self.dialogue.get_message_by_id(self.valid_message_1_by_self.message_id)\n            == self.valid_message_1_by_self\n        )\n\n        assert (\n            self.dialogue.get_message_by_id(self.valid_message_2_by_other.message_id)\n            is None\n        )\n        self.dialogue._update(self.valid_message_2_by_other)\n        assert (\n            self.dialogue.get_message_by_id(self.valid_message_2_by_other.message_id)\n            == self.valid_message_2_by_other\n        )\n\n    def test_has_message_id(self):\n        \"\"\"Test the 'has_message_id' method.\"\"\"\n        assert self.dialogue._has_message_id(1) is False\n\n        self.dialogue._update(self.valid_message_1_by_self)\n        assert self.dialogue._has_message_id(1) is True\n\n        assert self.dialogue._has_message_id(2) is False\n\n    def test_update_positive(self):\n        \"\"\"Positive test for the 'update' method.\"\"\"\n        self.dialogue._update(self.valid_message_1_by_self)\n        assert self.dialogue.last_outgoing_message == self.valid_message_1_by_self\n\n    def test_update_positive_multiple_messages_by_self(self):\n        \"\"\"Positive test for the 'update' method: multiple messages by self is sent to the dialogue.\"\"\"\n        self.dialogue._update(self.valid_message_1_by_self)\n\n        valid_message_2_by_self = DefaultMessage(\n            dialogue_reference=(str(1), \"\"),\n            message_id=2,\n            target=1,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"Hello back\",\n        )\n        valid_message_2_by_self.sender = self.agent_address\n        valid_message_2_by_self.to = self.opponent_address\n\n        self.dialogue._update(valid_message_2_by_self)\n\n        assert self.dialogue.last_message.message_id == 2\n\n    def test_terminal_state_callback(self):\n        \"\"\"Test dialogue terminal state callback works.\"\"\"\n        called = False\n\n        def callback(dialogue):\n            nonlocal called\n            called = True\n\n        self.dialogue.add_terminal_state_callback(callback)\n        self.dialogue._update(self.valid_message_1_by_self)\n\n        self.dialogue.reply(\n            target_message=self.valid_message_1_by_self,\n            performative=DefaultMessage.Performative.ERROR,\n            error_code=ErrorCode.UNSUPPORTED_PROTOCOL,\n            error_msg=\"oops\",\n            error_data={},\n        )\n\n        assert called\n\n    def test_update_negative_is_valid_next_message_fails(self):\n        \"\"\"Negative test for the 'update' method: input message is invalid with respect to the dialogue.\"\"\"\n        invalid_message_1_by_self = DefaultMessage(\n            dialogue_reference=(str(1), \"\"),\n            message_id=200,\n            target=1,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"Hello\",\n        )\n        invalid_message_1_by_self.sender = self.agent_address\n        invalid_message_1_by_self.to = self.opponent_address\n\n        with pytest.raises(\n            InvalidDialogueMessage,\n            match=r\"Message .* is invalid with respect to this dialogue. Error: Invalid message_id. Expected .*. Found 200.\",\n        ):\n            self.dialogue._update(invalid_message_1_by_self)\n\n        assert self.dialogue.last_outgoing_message is None\n\n    def test_update_dialogue_negative_message_does_not_belong_to_dialogue(self):\n        \"\"\"Negative test for the 'update' method in dialogue with wrong message not belonging to dialogue.\"\"\"\n        invalid_message_1_by_self = DefaultMessage(\n            dialogue_reference=(str(2), \"\"),\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"Hello\",\n        )\n        invalid_message_1_by_self.sender = self.agent_address\n        invalid_message_1_by_self.to = self.opponent_address\n\n        with pytest.raises(InvalidDialogueMessage) as cm:\n            self.dialogue._update(invalid_message_1_by_self)\n        assert str(cm.value) == (\n            \"The message 1 does not belong to this dialogue.\"\n            \"The dialogue reference of the message is {}, while the dialogue reference of the dialogue is {}\".format(\n                invalid_message_1_by_self.dialogue_reference,\n                self.dialogue.dialogue_label.dialogue_reference,\n            )\n        )\n        assert self.dialogue.is_empty\n\n    def test_is_belonging_to_dialogue(self):\n        \"\"\"Test for the '_is_belonging_to_dialogue' method\"\"\"\n        valid_message_2_by_self = DefaultMessage(\n            dialogue_reference=(str(2), \"\"),\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"Hello\",\n        )\n        valid_message_2_by_self.sender = self.agent_address\n        valid_message_2_by_self.to = self.opponent_address\n\n        assert self.dialogue._is_belonging_to_dialogue(self.valid_message_1_by_self)\n        assert not self.dialogue._is_belonging_to_dialogue(valid_message_2_by_self)\n\n    def test_reply_positive(self):\n        \"\"\"Positive test for the 'reply' method.\"\"\"\n        self.dialogue._update(self.valid_message_1_by_self)\n\n        self.dialogue.reply(\n            target_message=self.valid_message_1_by_self,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"Hello Back\",\n        )\n\n        assert self.dialogue.last_message.message_id == 2\n\n    def test_reply_negative_empty_dialogue(self):\n        \"\"\"Negative test for the 'reply' method: target message is not in the dialogue.\"\"\"\n        with pytest.raises(ValueError) as cm:\n            self.dialogue.reply(\n                target_message=self.valid_message_1_by_self,\n                performative=DefaultMessage.Performative.BYTES,\n                content=b\"Hello Back\",\n            )\n        assert str(cm.value) == \"Cannot reply in an empty dialogue!\"\n        assert self.dialogue.is_empty\n\n    def test_reply_negative_target_does_not_exist(self):\n        \"\"\"Negative test for the 'reply' method: target is not in the dialogue.\"\"\"\n        self.dialogue._update(self.valid_message_1_by_self)\n        with pytest.raises(ValueError) as cm:\n            self.dialogue.reply(\n                target=10,\n                performative=DefaultMessage.Performative.BYTES,\n                content=b\"Hello Back\",\n            )\n        assert str(cm.value) == \"No target message found!\"\n\n    def test_reply_negative_target_message_target_mismatch(self):\n        \"\"\"Negative test for the 'reply' method: target message and target provided but do not match.\"\"\"\n        self.dialogue._update(self.valid_message_1_by_self)\n        assert self.dialogue.last_message.message_id == 1\n\n        with pytest.raises(AEAEnforceError) as cm:\n            self.dialogue.reply(\n                target_message=self.valid_message_1_by_self,\n                target=2,\n                performative=DefaultMessage.Performative.BYTES,\n                content=b\"Hello Back\",\n            )\n        assert str(cm.value) == \"The provided target and target_message do not match.\"\n        assert self.dialogue.last_message.message_id == 1\n\n    def test_reply_negative_invalid_target(self):\n        \"\"\"Negative test for the 'reply' method: target message is not in the dialogue.\"\"\"\n        self.dialogue._update(self.valid_message_1_by_self)\n        assert self.dialogue.last_message.message_id == 1\n\n        invalid_message_1_by_self = DefaultMessage(\n            dialogue_reference=(str(1), \"\"),\n            message_id=2,\n            target=1,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"Hello There\",\n        )\n        invalid_message_1_by_self.sender = self.agent_address\n        invalid_message_1_by_self.to = self.opponent_address\n\n        with pytest.raises(AEAEnforceError) as cm:\n            self.dialogue.reply(\n                target_message=invalid_message_1_by_self,\n                performative=DefaultMessage.Performative.BYTES,\n                content=b\"Hello Back\",\n            )\n        assert str(cm.value) == \"The target message does not exist in this dialogue.\"\n        assert self.dialogue.last_message.message_id == 1\n\n    def test_is_valid_next_message_positive(self):\n        \"\"\"Positive test for the 'validate_next_message' method\"\"\"\n        self.dialogue._update(self.valid_message_1_by_self)\n        self.dialogue._update(self.valid_message_2_by_other)\n\n        result, msg = self.dialogue._validate_next_message(self.valid_message_3_by_self)\n        assert result is True\n        assert msg == \"Message is valid with respect to this dialogue.\"\n\n    def test_is_valid_next_message_negative_basic_validation_fails(self):\n        \"\"\"Negative test for the 'validate_next_message' method: basic_validation method fails\"\"\"\n        invalid_message_1_by_self = DefaultMessage(\n            dialogue_reference=(str(1), \"\"),\n            message_id=2,\n            target=0,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"Hello\",\n        )\n        invalid_message_1_by_self.sender = self.agent_address\n        invalid_message_1_by_self.to = self.opponent_address\n\n        result, msg = self.dialogue._validate_next_message(invalid_message_1_by_self)\n        assert result is False\n        assert msg == \"Invalid message_id. Expected 1. Found 2.\"\n\n    def test_is_valid_next_message_negative_additional_validation_fails(self):\n        \"\"\"Negative test for the 'validate_next_message' method: additional_validation method fails\"\"\"\n        self.dialogue._update(self.valid_message_1_by_self)\n        self.dialogue._update(self.valid_message_2_by_other)\n\n        invalid_message_3_by_self = DefaultMessage(\n            dialogue_reference=(str(1), str(1)),\n            message_id=2,\n            target=3,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"Hello back 2\",\n        )\n        invalid_message_3_by_self.sender = self.agent_address\n        invalid_message_3_by_self.to = self.opponent_address\n\n        result, msg = self.dialogue._validate_next_message(invalid_message_3_by_self)\n        assert result is False\n        assert \"Invalid target\" in msg\n\n    def test_is_valid_next_message_negative_is_valid_fails(self):\n        \"\"\"Negative test for the 'validate_next_message' method: is_valid method fails\"\"\"\n\n        def failing_custom_validation(self, message: Message) -> Tuple[bool, str]:\n            return False, \"some reason\"\n\n        with patch.object(\n            self.dialogue.__class__, \"_custom_validation\", failing_custom_validation\n        ):\n            result, msg = self.dialogue._validate_next_message(\n                self.valid_message_1_by_self\n            )\n\n        assert result is False\n        assert msg == \"some reason\"\n\n    def test_basic_validation_positive(self):\n        \"\"\"Positive test for the '_basic_validation' method.\"\"\"\n        result, msg = self.dialogue._basic_validation(self.valid_message_1_by_self)\n        assert result is True\n        assert msg == \"The initial message passes basic validation.\"\n\n        self.dialogue._update(self.valid_message_1_by_self)\n\n        result, msg = self.dialogue._basic_validation(self.valid_message_2_by_other)\n        assert result is True\n        assert msg == \"The non-initial message passes basic validation.\"\n\n    def test_basic_validation_negative_initial_message_invalid(self):\n        \"\"\"Negative test for the '_basic_validation' method: initial message is invalid.\"\"\"\n        invalid_message_1_by_self = DefaultMessage(\n            dialogue_reference=(str(1), \"\"),\n            message_id=2,\n            target=1,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"Hello\",\n        )\n        invalid_message_1_by_self.sender = self.agent_address\n        invalid_message_1_by_self.to = self.opponent_address\n\n        assert self.dialogue.is_empty\n        result, msg = self.dialogue._basic_validation(invalid_message_1_by_self)\n        assert result is False\n        assert msg == \"Invalid message_id. Expected 1. Found 2.\"\n\n    @patch.object(BaseDialogue, \"_validate_message_id\", return_value=None)\n    def test_basic_validation_negative_non_initial_message_invalid(self, *mocks):\n        \"\"\"Negative test for the '_basic_validation' method: non-initial message is invalid.\"\"\"\n        self.dialogue._update(self.valid_message_1_by_self)\n\n        invalid_message_2_by_other = DefaultMessage(\n            dialogue_reference=(str(1), str(1)),\n            message_id=-1,\n            target=0,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"Hello back\",\n        )\n        invalid_message_2_by_other.sender = self.opponent_address\n        invalid_message_2_by_other.to = self.agent_address\n\n        result, msg = self.dialogue._basic_validation(invalid_message_2_by_other)\n        assert result is False\n        assert msg == \"Invalid target. Expected a non-zero integer. Found 0.\"\n\n    def test_basic_validation_initial_message_positive(self):\n        \"\"\"Positive test for the '_basic_validation_initial_message' method.\"\"\"\n        result, msg = self.dialogue._basic_validation_initial_message(\n            self.valid_message_1_by_self\n        )\n        assert result is True\n        assert msg == \"The initial message passes basic validation.\"\n\n    def test_basic_validation_initial_message_negative_invalid_dialogue_reference(self):\n        \"\"\"Negative test for the '_basic_validation' method: input message has invalid dialogue reference.\"\"\"\n        invalid_message_1_by_self = DefaultMessage(\n            dialogue_reference=(str(2), \"\"),\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"Hello\",\n        )\n        invalid_message_1_by_self.sender = self.agent_address\n        invalid_message_1_by_self.to = self.opponent_address\n\n        result, msg = self.dialogue._basic_validation_initial_message(\n            invalid_message_1_by_self\n        )\n        assert result is False\n        assert msg == \"Invalid dialogue_reference[0]. Expected 1. Found 2.\"\n\n    def test_basic_validation_initial_message_negative_invalid_message_id(self):\n        \"\"\"Negative test for the '_basic_validation' method: input message has invalid message id.\"\"\"\n        invalid_message_1_by_self = DefaultMessage(\n            dialogue_reference=(str(1), \"\"),\n            message_id=200,\n            target=1,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"Hello\",\n        )\n        invalid_message_1_by_self.sender = self.agent_address\n        invalid_message_1_by_self.to = self.opponent_address\n\n        result, msg = self.dialogue._basic_validation_initial_message(\n            invalid_message_1_by_self\n        )\n        assert result is False\n        assert re.match(\"Invalid message_id. Expected .*. Found 200.\", msg)\n\n    def test_basic_validation_initial_message_negative_invalid_target(self):\n        \"\"\"Negative test for the '_basic_validation_initial_message' method: input message has invalid target.\"\"\"\n        invalid_message_1_by_self = DefaultMessage(\n            dialogue_reference=(str(1), \"\"),\n            message_id=1,\n            target=1,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"Hello\",\n        )\n        invalid_message_1_by_self.sender = self.agent_address\n        invalid_message_1_by_self.to = self.opponent_address\n\n        result, msg = self.dialogue._basic_validation_initial_message(\n            invalid_message_1_by_self\n        )\n        assert result is False\n        assert msg == \"Invalid target. Expected 0. Found 1.\"\n\n    def test_basic_validation_initial_message_negative_invalid_performative(self):\n        \"\"\"Negative test for the '_basic_validation_initial_message' method: input message has invalid performative.\"\"\"\n        invalid_initial_msg = DefaultMessage(\n            dialogue_reference=(str(1), \"\"),\n            performative=DefaultMessage.Performative.ERROR,\n            error_code=DefaultMessage.ErrorCode.INVALID_MESSAGE,\n            error_msg=\"some_error_message\",\n            error_data={\"some_data\": b\"some_bytes\"},\n        )\n        invalid_initial_msg.sender = self.agent_address\n        invalid_initial_msg.to = self.opponent_address\n\n        result, msg = self.dialogue._basic_validation_initial_message(\n            invalid_initial_msg\n        )\n        assert result is False\n        assert (\n            msg\n            == \"Invalid initial performative. Expected one of {}. Found error.\".format(\n                self.dialogue.rules.initial_performatives\n            )\n        )\n\n    def test_basic_validation_non_initial_message_positive(self):\n        \"\"\"Positive test for the '_basic_validation_non_initial_message' method.\"\"\"\n        self.dialogue._update(self.valid_message_1_by_self)\n\n        result, msg = self.dialogue._basic_validation_non_initial_message(\n            self.valid_message_2_by_other\n        )\n        assert result is True\n        assert msg == \"The non-initial message passes basic validation.\"\n\n    def test_basic_validation_non_initial_message_negative_invalid_dialogue_reference(\n        self,\n    ):\n        \"\"\"Negative test for the '_basic_validation_non_initial_message' method: input message has invalid dialogue reference.\"\"\"\n        self.dialogue._update(self.valid_message_1_by_self)\n\n        invalid_message_2_by_other = DefaultMessage(\n            dialogue_reference=(str(2), str(1)),\n            message_id=2,\n            target=1,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"Hello back\",\n        )\n        invalid_message_2_by_other.sender = self.opponent_address\n        invalid_message_2_by_other.to = self.agent_address\n\n        result, msg = self.dialogue._basic_validation_non_initial_message(\n            invalid_message_2_by_other\n        )\n        assert result is False\n        assert msg == \"Invalid dialogue_reference[0]. Expected 1. Found 2.\"\n\n    def test_basic_validation_non_initial_message_negative_invalid_message_id(self):\n        \"\"\"Negative test for the '_basic_validation_non_initial_message' method: input message has invalid message id.\"\"\"\n        self.dialogue._update(self.valid_message_1_by_self)\n\n        invalid_message_2_by_other = DefaultMessage(\n            dialogue_reference=(str(1), str(1)),\n            message_id=1000500000,\n            target=1,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"Hello back\",\n        )\n        invalid_message_2_by_other.sender = self.opponent_address\n        invalid_message_2_by_other.to = self.agent_address\n\n        result, msg = self.dialogue._basic_validation_non_initial_message(\n            invalid_message_2_by_other\n        )\n        assert result is False\n        assert re.match(\"Invalid message_id. Expected .*. Found 1000500000\", msg)\n\n    @patch.object(BaseDialogue, \"_validate_message_id\", return_value=None)\n    def test_basic_validation_non_initial_message_negative_invalid_target_1(\n        self, *mocks\n    ):\n        \"\"\"Negative test for the '_basic_validation_non_initial_message' method: input message has target less than 1.\"\"\"\n        self.dialogue._update(self.valid_message_1_by_self)\n\n        invalid_message_2_by_other = DefaultMessage(\n            dialogue_reference=(str(1), str(1)),\n            message_id=2,\n            target=0,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"Hello back\",\n        )\n        invalid_message_2_by_other.sender = self.opponent_address\n        invalid_message_2_by_other.to = self.agent_address\n\n        result, msg = self.dialogue._basic_validation_non_initial_message(\n            invalid_message_2_by_other\n        )\n        assert result is False\n        assert msg == \"Invalid target. Expected a non-zero integer. Found 0.\"\n\n    def test_basic_validation_non_initial_message_negative_invalid_target_2(self):\n        \"\"\"Negative test for the '_basic_validation_non_initial_message' method: input message has target greater than the id of the last existing message.\"\"\"\n        self.dialogue._update(self.valid_message_1_by_self)\n\n        invalid_message_2_by_other = DefaultMessage(\n            dialogue_reference=(str(1), str(1)),\n            message_id=-1,\n            target=2,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"Hello back\",\n        )\n        invalid_message_2_by_other.sender = self.opponent_address\n        invalid_message_2_by_other.to = self.agent_address\n\n        result, msg = self.dialogue._basic_validation_non_initial_message(\n            invalid_message_2_by_other\n        )\n        assert result is False\n        assert \"Invalid target. Expected a value less than \" in msg\n\n    @patch.object(BaseDialogue, \"_validate_message_id\", return_value=None)\n    def test_basic_validation_non_initial_message_negative_invalid_performative(\n        self, *mocks\n    ):\n        \"\"\"Negative test for the '_basic_validation_non_initial_message' method: input message has invalid performative.\"\"\"\n        self.dialogue._update(self.valid_message_1_by_self)\n\n        invalid_message_2_by_other = StateUpdateMessage(\n            dialogue_reference=(str(1), str(1)),\n            message_id=Mock(),\n            target=1,\n            performative=StateUpdateMessage.Performative.APPLY,\n            amount_by_currency_id={},\n            quantities_by_good_id={},\n        )\n        invalid_message_2_by_other.sender = self.opponent_address\n        invalid_message_2_by_other.to = self.agent_address\n\n        result, msg = self.dialogue._basic_validation_non_initial_message(\n            invalid_message_2_by_other\n        )\n        assert result is False\n        assert msg == \"Invalid performative. Expected one of {}. Found {}.\".format(\n            self.dialogue.rules.get_valid_replies(\n                self.valid_message_1_by_self.performative\n            ),\n            invalid_message_2_by_other.performative,\n        )\n\n    def test_update_dialogue_label_positive(self):\n        \"\"\"Positive test for the 'update_dialogue_label' method.\"\"\"\n        self.dialogue._update(self.valid_message_1_by_self)\n\n        new_label = DialogueLabel(\n            (str(1), str(1)), self.valid_message_1_by_self.to, self.agent_address\n        )\n        self.dialogue._update_dialogue_label(new_label)\n\n        assert self.dialogue.dialogue_label == new_label\n\n    def test_update_dialogue_label_negative_invalid_existing_label(self):\n        \"\"\"Negative test for the 'update_dialogue_label' method: existing dialogue reference is invalid.\"\"\"\n        self.dialogue._update(self.valid_message_1_by_self)\n        self.dialogue._update(self.valid_message_2_by_other)\n\n        new_label = DialogueLabel(\n            (str(1), str(1)), self.valid_message_1_by_self.to, self.agent_address\n        )\n        self.dialogue._update_dialogue_label(new_label)\n        assert self.dialogue.dialogue_label == new_label\n\n        new_label = DialogueLabel(\n            (str(1), str(2)), self.valid_message_1_by_self.to, self.agent_address\n        )\n        with pytest.raises(AEAEnforceError) as cm:\n            self.dialogue._update_dialogue_label(new_label)\n        assert str(cm.value) == \"Dialogue label cannot be updated.\"\n\n        assert self.dialogue.dialogue_label != new_label\n\n    def test_update_dialogue_label_negative_invalid_input_label(self):\n        \"\"\"Negative test for the 'update_dialogue_label' method: input dialogue label's dialogue reference is invalid.\"\"\"\n        self.dialogue._update(self.valid_message_1_by_self)\n\n        new_label = DialogueLabel(\n            (str(2), \"\"), self.valid_message_1_by_self.to, self.agent_address\n        )\n        with pytest.raises(AEAEnforceError) as cm:\n            self.dialogue._update_dialogue_label(new_label)\n        assert str(cm.value) == \"Dialogue label cannot be updated.\"\n        assert self.dialogue.dialogue_label != new_label\n\n    def test___str__1(self):\n        \"\"\"Test the '__str__' method: dialogue is self initiated\"\"\"\n        self.dialogue._update(self.valid_message_1_by_self)\n        self.dialogue._update(self.valid_message_2_by_other)\n\n        self.dialogue._update(self.valid_message_3_by_self)\n\n        dialogue_str = \"Dialogue Label:\\n1__agent 2_agent 1\\nMessages:\\nmessage_id=1, target=0, performative=bytes\\nmessage_id=-1, target=1, performative=bytes\\nmessage_id=2, target=-1, performative=bytes\\n\"\n\n        assert str(self.dialogue) == dialogue_str\n\n    def test___str__2(self):\n        \"\"\"Test the '__str__' method: dialogue is other initiated\"\"\"\n        valid_message_1_by_other = DefaultMessage(\n            dialogue_reference=(str(1), \"\"),\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"Hello\",\n        )\n        valid_message_1_by_other.sender = self.opponent_address\n        valid_message_1_by_other.to = self.agent_address\n\n        self.dialogue_opponent_started._update(valid_message_1_by_other)\n\n        valid_message_2_by_self = DefaultMessage(\n            dialogue_reference=(str(1), str(1)),\n            message_id=-1,\n            target=1,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"Hello back\",\n        )\n        valid_message_2_by_self.sender = self.agent_address\n        valid_message_2_by_self.to = self.opponent_address\n\n        self.dialogue_opponent_started._update(valid_message_2_by_self)\n\n        valid_message_3_by_other = DefaultMessage(\n            dialogue_reference=(str(1), str(1)),\n            message_id=2,\n            target=-1,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"Hello back 2\",\n        )\n        valid_message_3_by_other.sender = self.opponent_address\n        valid_message_3_by_other.to = self.agent_address\n\n        self.dialogue_opponent_started._update(valid_message_3_by_other)\n\n        dialogue_str = \"Dialogue Label:\\n1_1_agent 2_agent 2\\nMessages:\\nmessage_id=1, target=0, performative=bytes\\nmessage_id=-1, target=1, performative=bytes\\nmessage_id=2, target=-1, performative=bytes\\n\"\n\n        assert str(self.dialogue_opponent_started) == dialogue_str\n\n\nclass TestDialogueStats:\n    \"\"\"Test for DialogueStats.\"\"\"\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Initialise the environment to test DialogueStats.\"\"\"\n        cls.agent_address = \"agent 1\"\n        cls.opponent_address = \"agent 2\"\n        cls.dialogue_label = DialogueLabel(\n            dialogue_reference=(str(1), \"\"),\n            dialogue_opponent_addr=cls.opponent_address,\n            dialogue_starter_addr=cls.agent_address,\n        )\n        cls.dialogue = Dialogue(dialogue_label=cls.dialogue_label)\n        end_states = frozenset(\n            {Dialogue.EndState.SUCCESSFUL, Dialogue.EndState.FAILED}\n        )  # type: FrozenSet[BaseDialogue.EndState]\n        cls.dialogue_stats = DialogueStats(end_states)\n\n    def test_properties(self):\n        \"\"\"Test dialogue properties.\"\"\"\n        assert isinstance(self.dialogue_stats.self_initiated, dict)\n        assert self.dialogue_stats.self_initiated == {\n            Dialogue.EndState.SUCCESSFUL: 0,\n            Dialogue.EndState.FAILED: 0,\n        }\n        assert self.dialogue_stats.other_initiated == {\n            Dialogue.EndState.SUCCESSFUL: 0,\n            Dialogue.EndState.FAILED: 0,\n        }\n\n    def test_add_dialogue_endstate(self):\n        \"\"\"Test for the 'add_dialogue_endstate' method.\"\"\"\n        assert self.dialogue_stats.self_initiated == {\n            Dialogue.EndState.SUCCESSFUL: 0,\n            Dialogue.EndState.FAILED: 0,\n        }\n        assert self.dialogue_stats.other_initiated == {\n            Dialogue.EndState.SUCCESSFUL: 0,\n            Dialogue.EndState.FAILED: 0,\n        }\n\n        self.dialogue_stats.add_dialogue_endstate(Dialogue.EndState.SUCCESSFUL, True)\n        assert self.dialogue_stats.self_initiated == {\n            Dialogue.EndState.SUCCESSFUL: 1,\n            Dialogue.EndState.FAILED: 0,\n        }\n        assert self.dialogue_stats.other_initiated == {\n            Dialogue.EndState.SUCCESSFUL: 0,\n            Dialogue.EndState.FAILED: 0,\n        }\n\n        self.dialogue_stats.add_dialogue_endstate(Dialogue.EndState.FAILED, False)\n        assert self.dialogue_stats.self_initiated == {\n            Dialogue.EndState.SUCCESSFUL: 1,\n            Dialogue.EndState.FAILED: 0,\n        }\n        assert self.dialogue_stats.other_initiated == {\n            Dialogue.EndState.SUCCESSFUL: 0,\n            Dialogue.EndState.FAILED: 1,\n        }\n\n\nclass TestDialoguesBase:\n    \"\"\"Test for Dialogues.\"\"\"\n\n    def setup(self):\n        \"\"\"Initialise the environment to test Dialogue.\"\"\"\n        self.agent_address = \"agent 1\"\n        self.opponent_address = \"agent 2\"\n        self.dialogue_label = DialogueLabel(\n            dialogue_reference=(str(1), \"\"),\n            dialogue_opponent_addr=self.opponent_address,\n            dialogue_starter_addr=self.agent_address,\n        )\n        self.dialogue = Dialogue(dialogue_label=self.dialogue_label)\n        self.own_dialogues = Dialogues(self.agent_address)\n        self.opponent_dialogues = Dialogues(self.opponent_address)\n\n        # convenient messages to reuse across tests\n        self.valid_message_1_by_self = DefaultMessage(\n            dialogue_reference=(str(1), \"\"),\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"Hello\",\n        )\n        self.valid_message_1_by_self.sender = self.agent_address\n        self.valid_message_1_by_self.to = self.opponent_address\n\n        self.valid_message_2_by_other = DefaultMessage(\n            dialogue_reference=(str(1), str(1)),\n            message_id=2,\n            target=1,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"Hello back\",\n        )\n        self.valid_message_2_by_other.sender = self.opponent_address\n        self.valid_message_2_by_other.to = self.agent_address\n\n    def test_dialogues_properties(self):\n        \"\"\"Test dialogue properties.\"\"\"\n        assert self.own_dialogues._dialogues_storage._dialogues_by_dialogue_label == {}\n        assert self.own_dialogues.self_address == self.agent_address\n        assert self.own_dialogues.dialogue_stats.other_initiated == {\n            Dialogue.EndState.SUCCESSFUL: 0,\n            Dialogue.EndState.FAILED: 0,\n        }\n        assert self.own_dialogues.dialogue_stats.self_initiated == {\n            Dialogue.EndState.SUCCESSFUL: 0,\n            Dialogue.EndState.FAILED: 0,\n        }\n        assert self.own_dialogues.message_class == DefaultMessage\n        assert self.own_dialogues.dialogue_class == Dialogue\n\n    def test_counterparty_from_message(self):\n        \"\"\"Test the 'counterparty_from_message' method.\"\"\"\n        assert (\n            self.own_dialogues._counterparty_from_message(self.valid_message_1_by_self)\n            == self.opponent_address\n        )\n        assert (\n            self.own_dialogues._counterparty_from_message(self.valid_message_2_by_other)\n            == self.opponent_address\n        )\n\n    def test_is_message_by_self(self):\n        \"\"\"Test the 'is_message_by_self' method.\"\"\"\n        assert self.own_dialogues._is_message_by_self(self.valid_message_1_by_self)\n        assert not self.own_dialogues._is_message_by_self(self.valid_message_2_by_other)\n\n    def test_is_message_by_other(self):\n        \"\"\"Test the 'is_message_by_other' method.\"\"\"\n        assert not self.own_dialogues._is_message_by_other(self.valid_message_1_by_self)\n        assert self.own_dialogues._is_message_by_other(self.valid_message_2_by_other)\n\n    def test_new_self_initiated_dialogue_reference(self):\n        \"\"\"Test the 'new_self_initiated_dialogue_reference' method.\"\"\"\n        self_initiated_ref = self.own_dialogues.new_self_initiated_dialogue_reference()\n        assert (\n            isinstance(self_initiated_ref[0], str)\n            and self_initiated_ref[0] != \"\"\n            and len(self_initiated_ref[0]) == DialogueLabel.NONCE_BYTES_NB * 2\n        )\n        assert self_initiated_ref[1] == \"\"\n        self_initiated_ref_2 = (\n            self.own_dialogues.new_self_initiated_dialogue_reference()\n        )\n        assert self_initiated_ref_2 != self_initiated_ref\n\n    def test_create_positive(self):\n        \"\"\"Positive test for the 'create' method.\"\"\"\n        assert (\n            len(self.own_dialogues._dialogues_storage._dialogues_by_dialogue_label) == 0\n        )\n        self.own_dialogues.create(\n            self.opponent_address, DefaultMessage.Performative.BYTES, content=b\"Hello\"\n        )\n        assert (\n            len(self.own_dialogues._dialogues_storage._dialogues_by_dialogue_label) == 1\n        )\n\n    def test_create_negative_incorrect_performative_content_combination(self):\n        \"\"\"Negative test for the 'create' method: invalid performative and content combination (i.e. invalid message).\"\"\"\n        assert (\n            len(self.own_dialogues._dialogues_storage._dialogues_by_dialogue_label) == 0\n        )\n        with pytest.raises(\n            ValueError, match=\"Invalid initial performative. Expected one of\"\n        ):\n            self.own_dialogues.create(\n                self.opponent_address,\n                DefaultMessage.Performative.ERROR,\n                content=b\"Hello\",\n            )\n        assert (\n            len(self.own_dialogues._dialogues_storage._dialogues_by_dialogue_label) == 0\n        )\n\n    def test_update_positive_new_dialogue_by_other(self):\n        \"\"\"Positive test for the 'update' method: the input message is for a new dialogue dialogue by other.\"\"\"\n        valid_message_1_by_other = DefaultMessage(\n            dialogue_reference=(str(1), \"\"),\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"Hello\",\n        )\n        valid_message_1_by_other.sender = self.opponent_address\n        valid_message_1_by_other.to = self.agent_address\n\n        assert (\n            len(self.own_dialogues._dialogues_storage._dialogues_by_dialogue_label) == 0\n        )\n\n        dialogue = self.own_dialogues.update(valid_message_1_by_other)\n\n        assert (\n            len(self.own_dialogues._dialogues_storage._dialogues_by_dialogue_label) == 1\n        )\n        assert dialogue is not None\n        assert dialogue.last_message.dialogue_reference == (str(1), \"\")\n        assert dialogue.last_message.message_id == 1\n        assert dialogue.last_message.target == 0\n        assert dialogue.last_message.performative == DefaultMessage.Performative.BYTES\n        assert dialogue.last_message.content == b\"Hello\"\n\n    def test_update_positive_existing_dialogue(self):\n        \"\"\"Positive test for the 'update' method: the input message is for an existing dialogue.\"\"\"\n        msg, dialogue = self.own_dialogues.create(\n            self.opponent_address, DefaultMessage.Performative.BYTES, content=b\"Hello\"\n        )\n\n        dialogue_reference = (\n            msg.dialogue_reference[0],\n            self.opponent_dialogues._generate_dialogue_nonce(),\n        )\n        valid_message_2_by_other = DefaultMessage(\n            dialogue_reference=dialogue_reference,\n            message_id=dialogue.get_incoming_next_message_id(),\n            target=msg.message_id,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"Hello back\",\n        )\n        valid_message_2_by_other.sender = self.opponent_address\n        valid_message_2_by_other.to = self.agent_address\n\n        assert (\n            len(self.own_dialogues._dialogues_storage._dialogues_by_dialogue_label) == 1\n        )\n\n        dialogue = self.own_dialogues.update(valid_message_2_by_other)\n\n        assert (\n            len(self.own_dialogues._dialogues_storage._dialogues_by_dialogue_label) == 1\n        )\n        assert dialogue is not None\n        assert dialogue.last_message.dialogue_reference == dialogue_reference\n        assert dialogue.last_message.message_id == valid_message_2_by_other.message_id\n        assert dialogue.last_message.target == valid_message_2_by_other.target\n        assert dialogue.last_message.performative == DefaultMessage.Performative.BYTES\n        assert dialogue.last_message.content == b\"Hello back\"\n\n    def test_update_positive_existing_dialogue_2(self):\n        \"\"\"Positive test for the 'update' method: the input message is for an existing dialogue from the original sender.\"\"\"\n        msg_1, dialogue = self.own_dialogues.create(\n            self.opponent_address, DefaultMessage.Performative.BYTES, content=b\"Hello\"\n        )\n\n        opponent_dialogue_1 = self.opponent_dialogues.update(msg_1)\n\n        msg_2 = dialogue.reply(\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"Hello again\",\n        )\n\n        opponent_dialogue_2 = self.opponent_dialogues.update(msg_2)\n\n        assert opponent_dialogue_1 == opponent_dialogue_2\n\n    def test_update_negative_invalid_label(self):\n        \"\"\"Negative test for the 'update' method: dialogue is not extendable with the input message.\"\"\"\n        invalid_message_1_by_other = DefaultMessage(\n            dialogue_reference=(\"\", \"\"),\n            message_id=0,\n            target=0,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"Hello\",\n        )\n        invalid_message_1_by_other.sender = self.opponent_address\n        invalid_message_1_by_other.to = self.agent_address\n\n        assert not self.own_dialogues.update(invalid_message_1_by_other)\n\n    def test_update_negative_new_dialogue_by_self(self):\n        \"\"\"Negative test for the 'update' method: the message is not by the counterparty.\"\"\"\n        assert (\n            len(self.own_dialogues._dialogues_storage._dialogues_by_dialogue_label) == 0\n        )\n\n        with pytest.raises(AEAEnforceError) as cm:\n            self.own_dialogues.update(self.valid_message_1_by_self)\n        assert (\n            str(cm.value)\n            == \"Invalid 'update' usage. Update must only be used with a message by another agent.\"\n        )\n\n        assert (\n            len(self.own_dialogues._dialogues_storage._dialogues_by_dialogue_label) == 0\n        )\n\n    def test_update_negative_no_to(self):\n        \"\"\"Negative test for the 'update' method: the 'to' field of the input message is not set.\"\"\"\n        invalid_message_1_by_other = DefaultMessage(\n            dialogue_reference=(str(1), \"\"),\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"Hello\",\n        )\n        invalid_message_1_by_other.sender = self.opponent_address\n\n        assert (\n            len(self.own_dialogues._dialogues_storage._dialogues_by_dialogue_label) == 0\n        )\n\n        with pytest.raises(AEAEnforceError) as cm:\n            self.own_dialogues.update(invalid_message_1_by_other)\n        assert str(cm.value) == \"The message's 'to' field is not set {}\".format(\n            invalid_message_1_by_other\n        )\n\n        assert (\n            len(self.own_dialogues._dialogues_storage._dialogues_by_dialogue_label) == 0\n        )\n\n    def test_update_negative_no_sender(self):\n        \"\"\"Negative test for the 'update' method: the 'sender' field of the input message is not set.\"\"\"\n        invalid_message_1_by_other = DefaultMessage(\n            dialogue_reference=(str(1), \"\"),\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"Hello\",\n        )\n        invalid_message_1_by_other.to = self.agent_address\n\n        assert (\n            len(self.own_dialogues._dialogues_storage._dialogues_by_dialogue_label) == 0\n        )\n\n        with pytest.raises(AEAEnforceError) as cm:\n            self.own_dialogues.update(invalid_message_1_by_other)\n        assert (\n            str(cm.value)\n            == \"Invalid 'update' usage. Update must only be used with a message by another agent.\"\n        )\n\n        assert (\n            len(self.own_dialogues._dialogues_storage._dialogues_by_dialogue_label) == 0\n        )\n\n    def test_update_negative_no_matching_to(self):\n        \"\"\"Negative test for the 'update' method: the 'to' field of the input message does not match self address.\"\"\"\n        invalid_message_1_by_other = DefaultMessage(\n            dialogue_reference=(str(1), \"\"),\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"Hello\",\n        )\n        invalid_message_1_by_other.to = self.agent_address + \"wrong_stuff\"\n        invalid_message_1_by_other.sender = self.opponent_address\n\n        assert (\n            len(self.own_dialogues._dialogues_storage._dialogues_by_dialogue_label) == 0\n        )\n\n        with pytest.raises(AEAEnforceError) as cm:\n            self.own_dialogues.update(invalid_message_1_by_other)\n        assert (\n            str(cm.value)\n            == \"Message to and dialogue self address do not match. Got 'to=agent 1wrong_stuff' expected 'to=agent 1'.\"\n        )\n\n        assert (\n            len(self.own_dialogues._dialogues_storage._dialogues_by_dialogue_label) == 0\n        )\n\n    def test_update_negative_invalid_message(self):\n        \"\"\"Negative test for the 'update' method: the message is invalid.\"\"\"\n        invalid_message_1_by_other = DefaultMessage(\n            dialogue_reference=(str(1), \"\"),\n            performative=DefaultMessage.Performative.ERROR,\n            error_code=DefaultMessage.ErrorCode.INVALID_MESSAGE,\n            error_msg=\"some_error_message\",\n            error_data={\"some_data\": b\"some_bytes\"},\n        )\n        invalid_message_1_by_other.sender = self.opponent_address\n        invalid_message_1_by_other.to = self.agent_address\n\n        assert (\n            len(self.own_dialogues._dialogues_storage._dialogues_by_dialogue_label) == 0\n        )\n\n        dialogue = self.own_dialogues.update(invalid_message_1_by_other)\n\n        assert dialogue is None\n\n        assert (\n            len(self.own_dialogues._dialogues_storage._dialogues_by_dialogue_label) == 0\n        )\n\n    def test_update_negative_existing_dialogue_non_nonexistent(self):\n        \"\"\"Negative test for the 'update' method: the dialogue referred by the input message does not exist.\"\"\"\n        _, dialogue = self.own_dialogues.create(\n            self.opponent_address, DefaultMessage.Performative.BYTES, content=b\"Hello\"\n        )\n\n        invalid_message_2_by_other = DefaultMessage(\n            dialogue_reference=(str(2), str(1)),\n            message_id=2,\n            target=1,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"Hello back\",\n        )\n        invalid_message_2_by_other.sender = self.opponent_address\n        invalid_message_2_by_other.to = self.agent_address\n\n        updated_dialogue = self.own_dialogues.update(invalid_message_2_by_other)\n\n        assert updated_dialogue is None\n        last_message = self.own_dialogues._dialogues_storage.get(\n            dialogue.dialogue_label\n        ).last_message\n        assert (\n            last_message.dialogue_reference[0] != \"\"\n            and last_message.dialogue_reference[1] == \"\"\n        )\n        assert (\n            self.own_dialogues._dialogues_storage.get(\n                dialogue.dialogue_label\n            ).last_message.message_id\n            == 1\n        )\n        assert (\n            self.own_dialogues._dialogues_storage.get(\n                dialogue.dialogue_label\n            ).last_message.target\n            == 0\n        )\n        assert (\n            self.own_dialogues._dialogues_storage.get(\n                dialogue.dialogue_label\n            ).last_message.performative\n            == DefaultMessage.Performative.BYTES\n        )\n        assert (\n            self.own_dialogues._dialogues_storage.get(\n                dialogue.dialogue_label\n            ).last_message.content\n            == b\"Hello\"\n        )\n\n    def test_complete_dialogue_reference_positive(\n        self,\n    ):\n        \"\"\"Positive test for the '_complete_dialogue_reference' method.\"\"\"\n        msg, dialogue = self.own_dialogues.create(\n            self.opponent_address, DefaultMessage.Performative.BYTES, content=b\"Hello\"\n        )\n\n        valid_message_2_by_other = DefaultMessage(\n            dialogue_reference=(\n                msg.dialogue_reference[0],\n                self.opponent_dialogues._generate_dialogue_nonce(),\n            ),\n            message_id=2,\n            target=1,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"Hello back\",\n        )\n        valid_message_2_by_other.sender = self.opponent_address\n        valid_message_2_by_other.to = self.agent_address\n\n        self.own_dialogues._complete_dialogue_reference(valid_message_2_by_other)\n\n        assert (\n            self.own_dialogues._dialogues_storage.get(\n                dialogue.dialogue_label\n            ).dialogue_label.dialogue_reference\n            == valid_message_2_by_other.dialogue_reference\n        )\n\n    def test_complete_dialogue_reference_negative_incorrect_reference(\n        self,\n    ):\n        \"\"\"Negative test for the '_complete_dialogue_reference' method: the input message has invalid dialogue reference.\"\"\"\n        msg, dialogue = self.own_dialogues.create(\n            self.opponent_address, DefaultMessage.Performative.BYTES, content=b\"Hello\"\n        )\n\n        wrong_own_ref = (\n            \"wrong reference\"  # if correct, would be  msg.dialogue_reference[0]\n        )\n        valid_message_2_by_other = DefaultMessage(\n            dialogue_reference=(\n                wrong_own_ref,\n                self.opponent_dialogues._generate_dialogue_nonce(),\n            ),\n            message_id=msg.message_id + 1,\n            target=msg.message_id,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"Hello back\",\n        )\n        valid_message_2_by_other.sender = self.opponent_address\n        valid_message_2_by_other.to = self.agent_address\n\n        self.own_dialogues._complete_dialogue_reference(valid_message_2_by_other)\n        assert (\n            self.own_dialogues._dialogues_storage.get(\n                dialogue.dialogue_label\n            ).dialogue_label.dialogue_reference\n            == msg.dialogue_reference\n        )\n\n    def test_get_dialogue_positive_1(self):\n        \"\"\"Positive test for the 'get_dialogue' method: the dialogue is self initiated and the second message is by the other agent.\"\"\"\n        msg, dialogue = self.own_dialogues.create(\n            self.opponent_address, DefaultMessage.Performative.BYTES, content=b\"Hello\"\n        )\n\n        valid_message_2_by_other = DefaultMessage(\n            dialogue_reference=(\n                msg.dialogue_reference[0],\n                self.opponent_dialogues._generate_dialogue_nonce(),\n            ),\n            message_id=msg.message_id + 1,\n            target=msg.message_id,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"Hello back\",\n        )\n        valid_message_2_by_other.sender = self.opponent_address\n        valid_message_2_by_other.to = self.agent_address\n\n        self.own_dialogues._complete_dialogue_reference(valid_message_2_by_other)\n\n        assert (\n            self.own_dialogues._dialogues_storage.get(\n                dialogue.dialogue_label\n            ).dialogue_label.dialogue_reference\n            == valid_message_2_by_other.dialogue_reference\n        )\n\n        retrieved_dialogue = self.own_dialogues.get_dialogue(valid_message_2_by_other)\n\n        assert retrieved_dialogue.dialogue_label == dialogue.dialogue_label\n\n    def test_get_dialogue_positive_2(self):\n        \"\"\"Positive test for the 'get_dialogue' method: the dialogue is other initiated and the second message is by this agent.\"\"\"\n        valid_message_1_by_other = DefaultMessage(\n            dialogue_reference=(str(1), \"\"),\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"Hello\",\n        )\n        valid_message_1_by_other.sender = self.opponent_address\n        valid_message_1_by_other.to = self.agent_address\n\n        dialogue = self.own_dialogues.update(valid_message_1_by_other)\n\n        valid_message_2_by_other = DefaultMessage(\n            dialogue_reference=dialogue.dialogue_label.dialogue_reference,\n            message_id=valid_message_1_by_other.message_id + 1,\n            target=valid_message_1_by_other.message_id,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"Hello back\",\n        )\n        valid_message_2_by_other.sender = self.agent_address\n        valid_message_2_by_other.to = self.opponent_address\n\n        retrieved_dialogue = self.own_dialogues.get_dialogue(valid_message_2_by_other)\n\n        assert retrieved_dialogue is not None\n        assert retrieved_dialogue.dialogue_label == dialogue.dialogue_label\n\n    @patch.object(BaseDialogue, \"_validate_message_id\", return_value=None)\n    def test_get_dialogue_negative_invalid_reference(self, *mocks):\n        \"\"\"Negative test for the 'get_dialogue' method: the input message has invalid dialogue reference.\"\"\"\n        msg, dialogue = self.own_dialogues.create(\n            self.opponent_address, DefaultMessage.Performative.BYTES, content=b\"Hello\"\n        )\n\n        valid_message_2_by_other = DefaultMessage(\n            dialogue_reference=(\n                msg.dialogue_reference[0],\n                self.opponent_dialogues._generate_dialogue_nonce(),\n            ),\n            message_id=msg.message_id + 1,\n            target=msg.message_id,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"Hello back\",\n        )\n        valid_message_2_by_other.sender = self.opponent_address\n        valid_message_2_by_other.to = self.agent_address\n\n        dialogue = self.own_dialogues.update(valid_message_2_by_other)\n        assert dialogue is not None\n\n        invalid_message_3_by_self = DefaultMessage(\n            dialogue_reference=(str(2), str(1)),\n            message_id=2,\n            target=1,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"Hello back\",\n        )\n        invalid_message_3_by_self.sender = self.agent_address\n        invalid_message_3_by_self.to = self.opponent_address\n\n        retrieved_dialogue = self.own_dialogues.get_dialogue(invalid_message_3_by_self)\n\n        assert retrieved_dialogue is None\n\n    def test_get_latest_label(self):\n        \"\"\"Positive test for the 'get_latest_label' method.\"\"\"\n        pass\n\n    def test_get_dialogue_from_label_positive(self):\n        \"\"\"Positive test for the 'get_dialogue_from_label' method.\"\"\"\n        _, dialogue = self.own_dialogues.create(\n            self.opponent_address, DefaultMessage.Performative.BYTES, content=b\"Hello\"\n        )\n\n        retrieved_dialogue = self.own_dialogues.get_dialogue_from_label(\n            dialogue.dialogue_label\n        )\n        assert retrieved_dialogue.dialogue_label == dialogue.dialogue_label\n\n    def test_get_dialogue_from_label_negative_incorrect_input_label(self):\n        \"\"\"Negative test for the 'get_dialogue_from_label' method: the input dialogue label does not exist.\"\"\"\n        _, dialogue = self.own_dialogues.create(\n            self.opponent_address, DefaultMessage.Performative.BYTES, content=b\"Hello\"\n        )\n\n        incorrect_label = DialogueLabel(\n            (str(1), \"error\"), self.opponent_address, self.agent_address\n        )\n\n        retrieved_dialogue = self.own_dialogues.get_dialogue_from_label(incorrect_label)\n        assert retrieved_dialogue is None\n\n    def test_create_self_initiated_positive(self):\n        \"\"\"Positive test for the '_create_self_initiated' method.\"\"\"\n        assert (\n            len(self.own_dialogues._dialogues_storage._dialogues_by_dialogue_label) == 0\n        )\n\n        self.own_dialogues._create_self_initiated(\n            self.opponent_address, (str(1), \"\"), Dialogue.Role.ROLE1\n        )\n        assert (\n            len(self.own_dialogues._dialogues_storage._dialogues_by_dialogue_label) == 1\n        )\n\n    def test_create_self_initiated_negative_invalid_dialogue_reference(self):\n        \"\"\"Negative test for the '_create_self_initiated' method: invalid dialogue reference\"\"\"\n        pass\n\n    def test_create_opponent_initiated_positive(self):\n        \"\"\"Positive test for the '_create_opponent_initiated' method.\"\"\"\n        assert (\n            len(self.own_dialogues._dialogues_storage._dialogues_by_dialogue_label) == 0\n        )\n\n        self.own_dialogues._create_opponent_initiated(\n            self.opponent_address, (str(1), \"\"), Dialogue.Role.ROLE2\n        )\n        assert (\n            len(self.own_dialogues._dialogues_storage._dialogues_by_dialogue_label) == 1\n        )\n\n    def test_create_opponent_initiated_negative_invalid_input_dialogue_reference(self):\n        \"\"\"Negative test for the '_create_opponent_initiated' method: input dialogue label has invalid dialogue reference.\"\"\"\n        assert (\n            len(self.own_dialogues._dialogues_storage._dialogues_by_dialogue_label) == 0\n        )\n\n        try:\n            self.own_dialogues._create_opponent_initiated(\n                self.opponent_address, (\"\", str(1)), Dialogue.Role.ROLE2\n            )\n            result = True\n        except AEAEnforceError:\n            result = False\n\n        assert not result\n        assert (\n            len(self.own_dialogues._dialogues_storage._dialogues_by_dialogue_label) == 0\n        )\n\n    def test_create_with_message(self):\n        \"\"\"Positive test for create with message.\"\"\"\n        msg = DefaultMessage(\n            dialogue_reference=self.own_dialogues.new_self_initiated_dialogue_reference(),\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"Hello\",\n        )\n        self.own_dialogues.create_with_message(\"opponent\", msg)\n\n    def test__create_positive(self):\n        \"\"\"Positive test for the '_create' method.\"\"\"\n        pass\n\n    def test__create_negative_incomplete_dialogue_label_present(self):\n        \"\"\"Negative test for the '_create' method: incomplete dialogue label already present.\"\"\"\n        pass\n\n    def test__create_negative_dialogue_label_present(self):\n        \"\"\"Negative test for the '_create' method: dialogue label already present.\"\"\"\n        pass\n\n    def test_generate_dialogue_nonce(self):\n        \"\"\"Test the '_generate_dialogue_nonce' method.\"\"\"\n        nonce = self.own_dialogues._generate_dialogue_nonce()\n        assert (\n            isinstance(nonce, str)\n            and nonce != \"\"\n            and len(nonce) == DialogueLabel.NONCE_BYTES_NB * 2\n        )\n        second_nonce = self.own_dialogues._generate_dialogue_nonce()\n        assert nonce != second_nonce\n\n    def test_get_dialogues_with_counterparty(self):\n        \"\"\"Test get dialogues with counterparty.\"\"\"\n        assert (\n            self.own_dialogues.get_dialogues_with_counterparty(self.opponent_address)\n            == []\n        )\n        _, dialogue = self.own_dialogues.create(\n            self.opponent_address, DefaultMessage.Performative.BYTES, content=b\"Hello\"\n        )\n        assert self.own_dialogues.get_dialogues_with_counterparty(\n            self.opponent_address\n        ) == [dialogue]\n\n    def test_setup(self):\n        \"\"\"Test dialogues.setup().\"\"\"\n        self.own_dialogues.setup()\n\n    def test_teardown(self):\n        \"\"\"Test dialogues.teardown().\"\"\"\n        self.own_dialogues.teardown()\n\n\nclass TestPersistDialoguesStorage:\n    \"\"\"Test PersistDialoguesStorage.\"\"\"\n\n    def setup(self):\n        \"\"\"Initialise the environment to test PersistDialogueStorage.\"\"\"\n        self.agent_address = \"agent 1\"\n        self.opponent_address = \"agent 2\"\n        self.dialogues = Dialogues(\n            self.agent_address, keep_terminal_state_dialogues=True\n        )\n        self.dialogues._dialogues_storage = PersistDialoguesStorage(self.dialogues)\n        self.skill_component = Mock()\n        self.skill_component.name = \"test_component\"\n        self.skill_component.skill_id = PublicId(\"test\", \"test\", \"0.1.0\")\n\n        self.dialogue_label = DialogueLabel(\n            dialogue_reference=(str(1), \"\"),\n            dialogue_opponent_addr=self.opponent_address,\n            dialogue_starter_addr=self.agent_address,\n        )\n        self.generic_storage = Storage(\"sqlite://:memory:\", threaded=True)\n        self.generic_storage.start()\n        wait_for_condition(lambda: self.generic_storage.is_connected, timeout=10)\n        self.skill_component.context.storage = self.generic_storage\n\n    def teardown(self):\n        \"\"\"Tear down the environment to test PersistDialogueStorage.\"\"\"\n        self.generic_storage.stop()\n        self.generic_storage.wait_completed(sync=True, timeout=10)\n\n    def test_dialogue_serialize_deserialize(self):\n        \"\"\"Test dialogue dumped and restored.\"\"\"\n        msg = DefaultMessage(\n            dialogue_reference=self.dialogues.new_self_initiated_dialogue_reference(),\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"Hello\",\n        )\n        dialogue = self.dialogues.create_with_message(\"opponent\", msg)\n        data = dialogue.json()\n        dialogue_restored = dialogue.__class__.from_json(dialogue.message_class, data)\n        assert dialogue == dialogue_restored\n\n    def test_dump_restore(self):\n        \"\"\"Test dump and load methods of the persists storage.\"\"\"\n        dialogues_storage = PersistDialoguesStorage(self.dialogues)\n        dialogues_storage._skill_component = self.skill_component\n        self.dialogues._dialogues_storage = dialogues_storage\n        dialogues_storage._incomplete_to_complete_dialogue_labels[\n            self.dialogue_label\n        ] = self.dialogue_label\n        self.dialogues.create(\n            self.opponent_address, DefaultMessage.Performative.BYTES, content=b\"Hello\"\n        )\n        msg, dialogue = self.dialogues.create(\n            self.opponent_address, DefaultMessage.Performative.BYTES, content=b\"Hello2\"\n        )\n        dialogue.reply(\n            target_message=msg,\n            performative=DefaultMessage.Performative.ERROR,\n            error_code=ErrorCode.UNSUPPORTED_PROTOCOL,\n            error_msg=\"oops\",\n            error_data={},\n        )\n        assert dialogues_storage.dialogues_in_terminal_state\n        assert dialogues_storage.dialogues_in_active_state\n        assert dialogues_storage._dialogue_by_address\n        assert dialogues_storage._incomplete_to_complete_dialogue_labels\n        dialogues_storage.teardown()\n\n        dialogues_storage_restored = PersistDialoguesStorage(self.dialogues)\n        dialogues_storage_restored._skill_component = self.skill_component\n        dialogues_storage_restored.setup()\n\n        assert len(dialogues_storage._dialogue_by_address) == len(\n            dialogues_storage_restored._dialogue_by_address\n        )\n\n        assert len(dialogues_storage._dialogue_by_address) == len(\n            dialogues_storage_restored._dialogue_by_address\n        )\n\n        assert (\n            dialogues_storage._incomplete_to_complete_dialogue_labels\n            == dialogues_storage_restored._incomplete_to_complete_dialogue_labels\n        )\n        assert set(\n            [str(i.dialogue_label) for i in dialogues_storage.dialogues_in_active_state]\n        ) == set(\n            [\n                str(i.dialogue_label)\n                for i in dialogues_storage_restored.dialogues_in_active_state\n            ]\n        )\n        assert set(\n            [\n                str(i.dialogue_label)\n                for i in dialogues_storage.dialogues_in_terminal_state\n            ]\n        ) == set(\n            [\n                str(i.dialogue_label)\n                for i in dialogues_storage_restored.dialogues_in_terminal_state\n            ]\n        )\n\n        # test remove from storage on storeage.remove\n        assert dialogues_storage_restored._terminal_dialogues_collection\n        dialogue_label = dialogues_storage.dialogues_in_terminal_state[0].dialogue_label\n        assert dialogues_storage_restored._terminal_dialogues_collection.get(\n            str(dialogue_label)\n        )\n        dialogues_storage_restored.remove(dialogue_label)\n        assert (\n            dialogues_storage_restored._terminal_dialogues_collection.get(\n                str(dialogue_label)\n            )\n            is None\n        )\n\n\nclass TestPersistDialoguesStorageOffloading:\n    \"\"\"Test PersistDialoguesStorage.\"\"\"\n\n    def setup(self):\n        \"\"\"Initialise the environment to test PersistDialogueStorage.\"\"\"\n        self.agent_address = \"agent 1\"\n        self.opponent_address = \"agent 2\"\n        self.dialogues = Dialogues(\n            self.agent_address, keep_terminal_state_dialogues=True\n        )\n        self.skill_component = Mock()\n        self.skill_component.name = \"test_component\"\n        self.skill_component.skill_id = PublicId(\"test\", \"test\", \"0.1.0\")\n\n        self.dialogue_label = DialogueLabel(\n            dialogue_reference=(str(1), \"\"),\n            dialogue_opponent_addr=self.opponent_address,\n            dialogue_starter_addr=self.agent_address,\n        )\n        self.generic_storage = Storage(\"sqlite://:memory:\", threaded=True)\n        self.generic_storage.start()\n        wait_for_condition(lambda: self.generic_storage.is_connected, timeout=10)\n        self.skill_component.context.storage = self.generic_storage\n\n    def teardown(self):\n        \"\"\"Tear down the environment to test PersistDialogueStorage.\"\"\"\n        self.generic_storage.stop()\n        self.generic_storage.wait_completed(sync=True, timeout=10)\n\n    def test_dump_restore(self):\n        \"\"\"Test dump and load methods of the persists storage.\"\"\"\n        dialogues_storage = PersistDialoguesStorageWithOffloading(self.dialogues)\n        dialogues_storage._skill_component = self.skill_component\n        self.dialogues._dialogues_storage = dialogues_storage\n        dialogues_storage._incomplete_to_complete_dialogue_labels[\n            self.dialogue_label\n        ] = self.dialogue_label\n        self.dialogues.create(\n            self.opponent_address, DefaultMessage.Performative.BYTES, content=b\"Hello\"\n        )\n        msg, dialogue = self.dialogues.create(\n            self.opponent_address, DefaultMessage.Performative.BYTES, content=b\"Hello2\"\n        )\n        dialogue.reply(\n            target_message=msg,\n            performative=DefaultMessage.Performative.ERROR,\n            error_code=ErrorCode.UNSUPPORTED_PROTOCOL,\n            error_msg=\"oops\",\n            error_data={},\n        )\n        assert dialogues_storage.dialogues_in_terminal_state\n        assert dialogues_storage.dialogues_in_active_state\n        assert dialogues_storage._dialogue_by_address\n        assert dialogues_storage._incomplete_to_complete_dialogue_labels\n        dialogues_by_addr = dialogues_storage.get_dialogues_with_counterparty(\n            dialogue.dialogue_label.dialogue_opponent_addr\n        )\n        dialogues_storage.teardown()\n\n        dialogues_storage_restored = PersistDialoguesStorageWithOffloading(\n            self.dialogues\n        )\n        dialogues_storage_restored._skill_component = self.skill_component\n        dialogues_storage_restored.setup()\n\n        assert len(dialogues_storage._dialogue_by_address) == len(\n            dialogues_storage_restored._dialogue_by_address\n        )\n\n        assert (\n            dialogues_storage._incomplete_to_complete_dialogue_labels\n            == dialogues_storage_restored._incomplete_to_complete_dialogue_labels\n        )\n        assert set(\n            [str(i.dialogue_label) for i in dialogues_storage.dialogues_in_active_state]\n        ) == set(\n            [\n                str(i.dialogue_label)\n                for i in dialogues_storage_restored.dialogues_in_active_state\n            ]\n        )\n        assert set(\n            [\n                str(i.dialogue_label)\n                for i in dialogues_storage.dialogues_in_terminal_state\n            ]\n        ) == set(\n            [\n                str(i.dialogue_label)\n                for i in dialogues_storage_restored.dialogues_in_terminal_state\n            ]\n        )\n\n        dialogue_label = dialogues_storage.dialogues_in_terminal_state[0].dialogue_label\n\n        assert len(dialogues_by_addr) == len(\n            dialogues_storage_restored.get_dialogues_with_counterparty(\n                dialogue.dialogue_label.dialogue_opponent_addr\n            )\n        )\n        # check get and cache\n        assert not dialogues_storage_restored._terminal_state_dialogues_labels\n        assert dialogues_storage_restored.get(dialogue_label) is not None\n        assert dialogues_storage_restored._terminal_state_dialogues_labels\n\n        # test remove from storage on storeage.remove\n        assert dialogues_storage_restored._terminal_dialogues_collection\n        assert (\n            dialogues_storage_restored._terminal_dialogues_collection.get(\n                str(dialogue_label)\n            )\n            is not None\n        )\n        dialogues_storage_restored.remove(dialogue_label)\n        assert (\n            dialogues_storage_restored._terminal_dialogues_collection.get(\n                str(dialogue_label)\n            )\n            is None\n        )\n        assert dialogues_storage_restored.get(dialogue_label) is None\n\n\nclass TestBaseDialoguesStorage:\n    \"\"\"Test PersistDialoguesStorage.\"\"\"\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Initialise the environment to test Dialogue.\"\"\"\n        cls.incomplete_reference = (str(1), \"\")\n        cls.complete_reference = (str(1), str(1))\n        cls.opponent_address = \"agent 2\"\n        cls.agent_address = \"agent 1\"\n\n        cls.dialogue_label = DialogueLabel(\n            dialogue_reference=cls.incomplete_reference,\n            dialogue_opponent_addr=cls.opponent_address,\n            dialogue_starter_addr=cls.agent_address,\n        )\n        cls.dialogue = Dialogue(dialogue_label=cls.dialogue_label)\n\n        cls.dialogue_label_opponent_started = DialogueLabel(\n            dialogue_reference=cls.complete_reference,\n            dialogue_opponent_addr=cls.opponent_address,\n            dialogue_starter_addr=cls.opponent_address,\n        )\n        cls.dialogue_opponent_started = Dialogue(\n            dialogue_label=cls.dialogue_label_opponent_started\n        )\n\n        # convenient messages to reuse across tests\n        cls.valid_message_1_by_self = DefaultMessage(\n            dialogue_reference=(str(1), \"\"),\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"Hello\",\n        )\n        cls.valid_message_1_by_self.sender = cls.agent_address\n        cls.valid_message_1_by_self.to = cls.opponent_address\n\n        cls.storage = BasicDialoguesStorage(Mock())\n\n    def test_dialogues_in_terminal_state_kept(self):\n        \"\"\"Test dialogues in terminal state handled properly.\"\"\"\n        self.storage.add(self.dialogue)\n        assert self.storage.dialogues_in_active_state\n        assert not self.storage.dialogues_in_terminal_state\n\n        self.dialogue._update(self.valid_message_1_by_self)\n        self.dialogue.reply(\n            target_message=self.valid_message_1_by_self,\n            performative=DefaultMessage.Performative.ERROR,\n            error_code=ErrorCode.UNSUPPORTED_PROTOCOL,\n            error_msg=\"oops\",\n            error_data={},\n        )\n\n        assert not self.storage.dialogues_in_active_state\n        assert self.storage.dialogues_in_terminal_state\n\n        self.storage.remove(self.dialogue.dialogue_label)\n        assert not self.storage.dialogues_in_active_state\n        assert not self.storage.dialogues_in_terminal_state\n\n    def test_dialogues_in_terminal_state_removed(self):\n        \"\"\"Test dialogues in terminal state handled properly.\"\"\"\n        self.storage._dialogues.is_keep_dialogues_in_terminal_state = False\n        self.storage.add(self.dialogue)\n        assert self.storage.dialogues_in_active_state\n        assert not self.storage.dialogues_in_terminal_state\n\n        self.dialogue._update(self.valid_message_1_by_self)\n        self.dialogue.reply(\n            target_message=self.valid_message_1_by_self,\n            performative=DefaultMessage.Performative.ERROR,\n            error_code=ErrorCode.UNSUPPORTED_PROTOCOL,\n            error_msg=\"oops\",\n            error_data={},\n        )\n\n        assert not self.storage.dialogues_in_active_state\n        assert not self.storage.dialogues_in_terminal_state\n\n    def teardown(self):\n        \"\"\"Tear down the environment to test BaseDialogueStorage.\"\"\"\n\n\ndef test_find_caller_object():\n    \"\"\"Test find_caller_object.\"\"\"\n\n    class CustomSkillComponent(SkillComponent):\n        def __init__(self, *args, **kwargs):\n            super().__init__(*args, **kwargs)\n            self.storage = PersistDialoguesStorage(self)\n\n        def setup(self):\n            pass\n\n        def teardown(self):\n            pass\n\n        @classmethod\n        def parse_module(cls, *args, **kwargs):\n            pass\n\n    skill_component = CustomSkillComponent(Mock(), Mock(), Mock())\n    assert skill_component.storage._skill_component == skill_component\n\n    class CustomObject:\n        def __init__(self, *args, **kwargs):\n            self.component = find_caller_object(SkillComponent)\n\n    custom_object = CustomObject()\n    assert custom_object.component is None\n\n\ndef test_dialogues_keep_terminal_state_dialogues():\n    \"\"\"Test Dialogues keep_terminal_state_dialogues option.\"\"\"\n    initial = Dialogues._keep_terminal_state_dialogues\n    dialogues = Dialogues(Mock(), keep_terminal_state_dialogues=True)\n    assert dialogues.is_keep_dialogues_in_terminal_state is True\n    assert Dialogues._keep_terminal_state_dialogues == initial\n\n    dialogues = Dialogues(Mock(), keep_terminal_state_dialogues=False)\n    assert dialogues.is_keep_dialogues_in_terminal_state is False\n    assert Dialogues._keep_terminal_state_dialogues == initial\n"
  },
  {
    "path": "tests/test_aea/test_protocols/test_dialogue/test_msg_resolve.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"\nThis module contains the tests for the dialogue messages resolution.\n\nissue: https://github.com/fetchai/agents-aea/issues/2128\n\"\"\"\n\nfrom aea.common import Address\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\n\nfrom packages.fetchai.protocols.tac.dialogues import TacDialogue, TacDialogues\nfrom packages.fetchai.protocols.tac.message import TacMessage\n\n\ndef role_participant(  # pylint: disable=unused-argument\n    message: Message, receiver_address: Address\n) -> BaseDialogue.Role:\n    \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n    :param message: an incoming/outgoing first message\n    :param receiver_address: the address of the receiving agent\n    :return: The role of the agent\n    \"\"\"\n    return TacDialogue.Role.PARTICIPANT\n\n\ndef role_controller(  # pylint: disable=unused-argument\n    message: Message, receiver_address: Address\n) -> BaseDialogue.Role:\n    \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n    :param message: an incoming/outgoing first message\n    :param receiver_address: the address of the receiving agent\n    :return: The role of the agent\n    \"\"\"\n    return TacDialogue.Role.PARTICIPANT\n\n\ndef test_dialogues_message_resolved_properly():\n    \"\"\"\n    Test for the issue in parallel messages sends in the dialogues system.\n\n    issue: https://github.com/fetchai/agents-aea/issues/2128\n    \"\"\"\n    addr1 = \"addr1\"\n    addr2 = \"addr2\"\n    part1 = TacDialogues(addr1, role_from_first_message=role_participant)\n    part2 = TacDialogues(addr2, role_from_first_message=role_participant)\n\n    msg, _ = part1.create(\n        addr2, performative=TacMessage.Performative.REGISTER, agent_name=addr1\n    )\n\n    dialogue = part2.update(msg)\n    assert dialogue\n    game_data_msg = dialogue.reply(performative=TacMessage.Performative.GAME_DATA)\n\n    dialogue = part1.update(game_data_msg)\n    assert dialogue\n    transaction1_msg = dialogue.reply(performative=TacMessage.Performative.TRANSACTION)\n    transaction2_msg = dialogue.reply(performative=TacMessage.Performative.TRANSACTION)\n\n    dialogue = part2.update(transaction1_msg)\n    assert dialogue\n    comfirmation1_msg = dialogue.reply(\n        performative=TacMessage.Performative.TRANSACTION_CONFIRMATION\n    )\n\n    dialogue = part1.update(comfirmation1_msg)\n    assert dialogue\n    transaction3_msg = dialogue.reply(performative=TacMessage.Performative.TRANSACTION)\n\n    dialogue = part2.update(transaction2_msg)\n    assert dialogue\n    comfirmation2_msg = dialogue.reply(\n        performative=TacMessage.Performative.TRANSACTION_CONFIRMATION\n    )\n    assert comfirmation2_msg.target == transaction2_msg.message_id\n\n    dialogue = part1.update(comfirmation2_msg)\n    assert dialogue\n\n    dialogue = part2.update(transaction3_msg)\n    assert dialogue\n    msg1 = dialogue.reply(performative=TacMessage.Performative.TRANSACTION_CONFIRMATION)\n\n    # self reply\n    msg2 = dialogue.reply(performative=TacMessage.Performative.TRANSACTION_CONFIRMATION)\n    assert abs(msg2.message_id) - abs(msg1.message_id) == 1\n    assert msg2.target == msg1.message_id\n"
  },
  {
    "path": "tests/test_aea/test_protocols/test_generator/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"The test generator module contains the tests of the AEA protocol generator.\"\"\"\n"
  },
  {
    "path": "tests/test_aea/test_protocols/test_generator/common.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains utility code for the test_generator modules.\"\"\"\nimport os\n\nfrom tests.conftest import ROOT_DIR\n\n\nT_PROTOCOL_NAME = \"t_protocol\"\nT_PROTOCOL_NO_CT_NAME = \"t_protocol_no_ct\"\nPATH_TO_T_PROTOCOL_SPECIFICATION = os.path.join(\n    ROOT_DIR, \"tests\", \"data\", \"sample_specification.yaml\"\n)\nPATH_TO_T_PROTOCOL_NO_CT_SPECIFICATION = os.path.join(\n    ROOT_DIR, \"tests\", \"data\", \"sample_specification_no_custom_types.yaml\"\n)\nPATH_TO_T_PROTOCOL = os.path.join(\n    ROOT_DIR, \"tests\", \"data\", \"generator\", T_PROTOCOL_NAME\n)\nPATH_TO_T_PROTOCOL_NO_CT = os.path.join(\n    ROOT_DIR, \"tests\", \"data\", \"generator\", T_PROTOCOL_NO_CT_NAME\n)\n\n\ndef black_is_not_installed(*args, **kwargs):\n    \"\"\"Check black is not installed.\"\"\"\n    return not args[0] == \"black\"\n"
  },
  {
    "path": "tests/test_aea/test_protocols/test_generator/test_common.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests for generator/common.py module.\"\"\"\nimport logging\nimport os\nimport shutil\nimport tempfile\nfrom pathlib import Path\nfrom subprocess import CalledProcessError  # nosec\nfrom unittest import TestCase, mock\n\nfrom aea.protocols.generator.common import (\n    _camel_case_to_snake_case,\n    _create_protocol_file,\n    _get_sub_types_of_compositional_types,\n    _has_matched_brackets,\n    _includes_custom_type,\n    _match_brackets,\n    _python_pt_or_ct_type_to_proto_type,\n    _to_camel_case,\n    _union_sub_type_to_protobuf_variable_name,\n    apply_protolint,\n    base_protolint_command,\n    check_prerequisites,\n    check_protobuf_using_protoc,\n    compile_protobuf_using_protoc,\n    is_installed,\n    load_protocol_specification,\n    try_run_black_formatting,\n    try_run_isort_formatting,\n    try_run_protoc,\n)\n\nfrom tests.test_aea.test_protocols.test_generator.common import (\n    PATH_TO_T_PROTOCOL_SPECIFICATION,\n    T_PROTOCOL_NAME,\n)\n\n\nlogger = logging.getLogger(\"aea\")\nlogging.basicConfig(level=logging.INFO)\n\n\ndef isort_is_not_installed_side_effect(*args, **kwargs):\n    \"\"\"Isort not installed.\"\"\"\n    return not args[0] == \"isort\"\n\n\ndef protolint_is_not_installed_side_effect(*args, **kwargs):\n    \"\"\"Protolint not installed.\"\"\"\n    return not args[0] == \"protolint\"\n\n\ndef black_is_not_installed_side_effect(*args, **kwargs):\n    \"\"\"Black not installed.\"\"\"\n    return not args[0] == \"black\"\n\n\ndef protoc_is_not_installed_side_effect(*args, **kwargs):\n    \"\"\"Protoco not installed.\"\"\"\n    return not args[0] == \"protoc\"\n\n\nclass TestCommon(TestCase):\n    \"\"\"Test for generator/common.py.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Setup test.\"\"\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        os.chdir(cls.t)\n\n    def test_to_camel_case(self):\n        \"\"\"Test the '_to_camel_case' method.\"\"\"\n        input_text_1 = \"this_is_a_snake_case_text\"\n        expected_1 = \"ThisIsASnakeCaseText\"\n        output_1 = _to_camel_case(input_text_1)\n        assert output_1 == expected_1\n\n        input_text_2 = \"This_is_a_Snake_Case_text\"\n        expected_2 = \"ThisIsASnakeCaseText\"\n        output_2 = _to_camel_case(input_text_2)\n        assert output_2 == expected_2\n\n    def test_camel_case_to_snake_case(self):\n        \"\"\"Test the '_camel_case_to_snake_case' method.\"\"\"\n        input_text_1 = \"ThisIsASnakeCaseText\"\n        expected_1 = \"this_is_a_snake_case_text\"\n        output_1 = _camel_case_to_snake_case(input_text_1)\n        assert output_1 == expected_1\n\n    def test_match_brackets(\n        self,\n    ):\n        \"\"\"Positive test the '_match_brackets' method.\"\"\"\n        text_1 = \"[so[met[hi]]ng]\"\n        assert _match_brackets(text_1, 0) == 14\n        assert _match_brackets(text_1, 3) == 11\n        assert _match_brackets(text_1, 7) == 10\n\n        text_2 = \"[]]som[]et[hi[ng][sf]\"\n        index_2 = 4\n        with self.assertRaises(SyntaxError) as cm:\n            _match_brackets(text_2, index_2)\n        self.assertEqual(\n            str(cm.exception),\n            \"Index {} in 'text' is not an open bracket '['. It is {}\".format(\n                index_2,\n                text_2[index_2],\n            ),\n        )\n\n        index_3 = 2\n        with self.assertRaises(SyntaxError) as cm:\n            _match_brackets(text_2, index_3)\n        self.assertEqual(\n            str(cm.exception),\n            \"Index {} in 'text' is not an open bracket '['. It is {}\".format(\n                index_3,\n                text_2[index_3],\n            ),\n        )\n\n        index_4 = 10\n        with self.assertRaises(SyntaxError) as cm:\n            _match_brackets(text_2, index_4)\n        self.assertEqual(\n            str(cm.exception),\n            \"No matching closing bracket ']' for the opening bracket '[' at {} \"\n            + str(index_4),\n        )\n\n    def test_has_matched_brackets(\n        self,\n    ):\n        \"\"\"Positive test the '_has_matched_brackets' method.\"\"\"\n        valid_text_1 = \"[so[met[hi]]ng]\"\n        assert _has_matched_brackets(valid_text_1) is True\n\n        valid_text_2 = \"[[][[]]]\"\n        assert _has_matched_brackets(valid_text_2) is True\n\n        valid_text_3 = \"[[[[[[[]]]]]]]\"\n        assert _has_matched_brackets(valid_text_3) is True\n\n        invalid_text_1 = \"[]]som[]et[hi[ng][sf]\"\n        assert _has_matched_brackets(invalid_text_1) is False\n\n        invalid_text_2 = \"[]][][[][]\"\n        assert _has_matched_brackets(invalid_text_2) is False\n\n        invalid_text_3 = \"[]]\"\n        assert _has_matched_brackets(invalid_text_3) is False\n\n        invalid_text_4 = \"[[]\"\n        assert _has_matched_brackets(invalid_text_4) is False\n\n    def test_get_sub_types_of_compositional_types_positive(\n        self,\n    ):\n        \"\"\"Positive test the '_get_sub_types_of_compositional_types' method.\"\"\"\n        composition_type_1 = \"pt:set[pt:int, integer, bool]\"\n        expected_1 = (\"pt:int\", \"integer\", \"bool\")\n        assert _get_sub_types_of_compositional_types(composition_type_1) == expected_1\n\n        composition_type_2 = \"FrozenSet[something, anotherthing]\"\n        expected_2 = (\"something\", \"anotherthing\")\n        assert _get_sub_types_of_compositional_types(composition_type_2) == expected_2\n\n        composition_type_3 = \"pt:list[pt:str]\"\n        expected_3 = (\"pt:str\",)\n        assert _get_sub_types_of_compositional_types(composition_type_3) == expected_3\n\n        composition_type_4 = \"Tuple[bytes, ...]\"\n        expected_4 = (\"bytes\",)\n        assert _get_sub_types_of_compositional_types(composition_type_4) == expected_4\n\n        composition_type_5 = \"pt:dict[pt:int, pt:int]\"\n        expected_5 = (\"pt:int\", \"pt:int\")\n        assert _get_sub_types_of_compositional_types(composition_type_5) == expected_5\n\n        composition_type_6 = \"Dict[bool, float]\"\n        expected_6 = (\"bool\", \"float\")\n        assert _get_sub_types_of_compositional_types(composition_type_6) == expected_6\n\n        composition_type_7 = \"pt:union[ct:DataModel, pt:bytes, pt:int, pt:bool, pt:float, pt:str, pt:set[pt:int], pt:list[pt:bool], pt:dict[pt:str,pt:str]]\"\n        expected_7 = (\n            \"ct:DataModel\",\n            \"pt:bytes\",\n            \"pt:int\",\n            \"pt:bool\",\n            \"pt:float\",\n            \"pt:str\",\n            \"pt:set[pt:int]\",\n            \"pt:list[pt:bool]\",\n            \"pt:dict[pt:str,pt:str]\",\n        )\n        assert _get_sub_types_of_compositional_types(composition_type_7) == expected_7\n\n        composition_type_8 = \"Union[int, Tuple[bool, ...]]\"\n        expected_8 = (\"int\", \"Tuple[bool, ...]\")\n        assert _get_sub_types_of_compositional_types(composition_type_8) == expected_8\n\n        composition_type_9 = (\n            \"Union[DataModel, FrozenSet[int], Tuple[bool, ...], bytes, Dict[bool,float], int, \"\n            \"FrozenSet[bool], Dict[int, str], Tuple[str, ...], bool, float, str, Dict[str, str]]\"\n        )\n        expected_9 = (\n            \"DataModel\",\n            \"FrozenSet[int]\",\n            \"Tuple[bool, ...]\",\n            \"bytes\",\n            \"Dict[bool,float]\",\n            \"int\",\n            \"FrozenSet[bool]\",\n            \"Dict[int, str]\",\n            \"Tuple[str, ...]\",\n            \"bool\",\n            \"float\",\n            \"str\",\n            \"Dict[str, str]\",\n        )\n        assert _get_sub_types_of_compositional_types(composition_type_9) == expected_9\n\n        composition_type_10 = \"pt:optional[pt:union[ct:DataModel, pt:bytes, pt:int, pt:bool, pt:float, pt:str, pt:set[pt:int], pt:list[pt:bool], pt:dict[pt:str,pt:str]]]\"\n        expected_10 = (\n            \"pt:union[ct:DataModel, pt:bytes, pt:int, pt:bool, pt:float, pt:str, pt:set[pt:int], pt:list[pt:bool], pt:dict[pt:str,pt:str]]\",\n        )\n        assert _get_sub_types_of_compositional_types(composition_type_10) == expected_10\n\n        composition_type_11 = \"Optional[Union[DataModel, bytes, int, bool, float, str, FrozenSet[int], Tuple[bool, ...], Dict[str,str]]]\"\n        expected_11 = (\n            \"Union[DataModel, bytes, int, bool, float, str, FrozenSet[int], Tuple[bool, ...], Dict[str,str]]\",\n        )\n        assert _get_sub_types_of_compositional_types(composition_type_11) == expected_11\n\n    def test_get_sub_types_of_compositional_types_negative(\n        self,\n    ):\n        \"\"\"Negative test the '_get_sub_types_of_compositional_types' method\"\"\"\n        composition_type_1 = \"pt:int\"\n        with self.assertRaises(SyntaxError) as cm:\n            _get_sub_types_of_compositional_types(composition_type_1)\n        self.assertEqual(\n            str(cm.exception),\n            \"{} is not a valid compositional type.\".format(composition_type_1),\n        )\n\n        composition_type_2 = \"pt:int[pt:DataModel]\"\n        with self.assertRaises(SyntaxError) as cm:\n            _get_sub_types_of_compositional_types(composition_type_2)\n        self.assertEqual(\n            str(cm.exception),\n            \"{} is not a valid compositional type.\".format(composition_type_2),\n        )\n\n        composition_type_3 = \"pt:dict[pt:set[int, pt:list[pt:bool]]\"\n        with self.assertRaises(SyntaxError) as cm:\n            _get_sub_types_of_compositional_types(composition_type_3)\n        self.assertEqual(\n            str(cm.exception),\n            \"Bad formatting. No matching close bracket ']' for the open bracket at pt:set[\",\n        )\n\n    def test_union_sub_type_to_protobuf_variable_name(\n        self,\n    ):\n        \"\"\"Test the '_union_sub_type_to_protobuf_variable_name' method\"\"\"\n        content_name = \"proposal\"\n\n        content_type_1 = \"FrozenSet[int]\"\n        assert (\n            _union_sub_type_to_protobuf_variable_name(content_name, content_type_1)\n            == \"proposal_type_set_of_int\"\n        )\n\n        content_type_2 = \"Tuple[str, ...]\"\n        assert (\n            _union_sub_type_to_protobuf_variable_name(content_name, content_type_2)\n            == \"proposal_type_list_of_str\"\n        )\n\n        content_type_3 = \"Dict[bool, float]\"\n        assert (\n            _union_sub_type_to_protobuf_variable_name(content_name, content_type_3)\n            == \"proposal_type_dict_of_bool_float\"\n        )\n\n        content_type_4 = \"int\"\n        assert (\n            _union_sub_type_to_protobuf_variable_name(content_name, content_type_4)\n            == \"proposal_type_int\"\n        )\n\n        content_type_5 = \"DataModel\"\n        assert (\n            _union_sub_type_to_protobuf_variable_name(content_name, content_type_5)\n            == \"proposal_type_DataModel\"\n        )\n\n    def test_python_pt_or_ct_type_to_proto_type(\n        self,\n    ):\n        \"\"\"Test the '_python_pt_or_ct_type_to_proto_type' method\"\"\"\n        content_type_bytes = \"bytes\"\n        assert _python_pt_or_ct_type_to_proto_type(content_type_bytes) == \"bytes\"\n\n        content_type_int = \"int\"\n        assert _python_pt_or_ct_type_to_proto_type(content_type_int) == \"int64\"\n\n        content_type_float = \"float\"\n        assert _python_pt_or_ct_type_to_proto_type(content_type_float) == \"float\"\n\n        content_type_bool = \"bool\"\n        assert _python_pt_or_ct_type_to_proto_type(content_type_bool) == \"bool\"\n\n        content_type_str = \"str\"\n        assert _python_pt_or_ct_type_to_proto_type(content_type_str) == \"string\"\n\n        content_type_ct = \"Query\"\n        assert _python_pt_or_ct_type_to_proto_type(content_type_ct) == \"Query\"\n\n    def test_includes_custom_type(\n        self,\n    ):\n        \"\"\"Test the '_includes_custom_type' method\"\"\"\n        content_type_includes_1 = \"Optional[DataModel]\"\n        assert _includes_custom_type(content_type_includes_1) is True\n\n        content_type_includes_2 = \"Union[int, DataModel]\"\n        assert _includes_custom_type(content_type_includes_2) is True\n\n        content_type_includes_3 = \"Optional[Union[int, float, DataModel, Query, float]]\"\n        assert _includes_custom_type(content_type_includes_3) is True\n\n        content_type_not_includes_1 = \"Optional[int]\"\n        assert _includes_custom_type(content_type_not_includes_1) is False\n\n        content_type_not_includes_2 = \"Union[int, float, str]\"\n        assert _includes_custom_type(content_type_not_includes_2) is False\n\n        content_type_not_includes_3 = (\n            \"Optional[Union[int, float, FrozenSet[int], Tuple[bool, ...], float]]\"\n        )\n        assert _includes_custom_type(content_type_not_includes_3) is False\n\n    @mock.patch(\"shutil.which\", return_value=\"some string\")\n    def test_is_installed_positive(self, mocked_shutil_which):\n        \"\"\"Positive test for the 'is_installed' method\"\"\"\n        assert is_installed(\"some_programme\") is True\n\n    @mock.patch(\"shutil.which\", return_value=None)\n    def test_is_installed_negative(self, mocked_shutil_which):\n        \"\"\"Negative test for the 'is_installed' method: programme is not installed\"\"\"\n        assert is_installed(\"some_programme\") is False\n\n    def test_base_protolint_command(self):\n        \"\"\"Tests the 'base_protolint_command' method\"\"\"\n        assert (\n            base_protolint_command() == \"protolint\"\n            or \"PATH=${PATH}:${GOPATH}/bin/:~/go/bin protolint\"\n        )\n\n    @mock.patch(\"aea.protocols.generator.common.is_installed\", return_value=True)\n    def test_check_prerequisites_positive(self, mocked_is_installed):\n        \"\"\"Positive test for the 'check_prerequisites' method\"\"\"\n        try:\n            check_prerequisites()\n        except FileNotFoundError:\n            self.assertTrue(False)\n\n    @mock.patch(\n        \"aea.protocols.generator.common.is_installed\",\n        side_effect=black_is_not_installed_side_effect,\n    )\n    def test_check_prerequisites_negative_black_is_not_installed(\n        self, mocked_is_installed\n    ):\n        \"\"\"Negative test for the 'check_prerequisites' method: black isn't installed\"\"\"\n        with self.assertRaises(FileNotFoundError):\n            check_prerequisites()\n\n    @mock.patch(\n        \"aea.protocols.generator.common.is_installed\",\n        side_effect=isort_is_not_installed_side_effect,\n    )\n    def test_check_prerequisites_negative_isort_is_not_installed(\n        self, mocked_is_installed\n    ):\n        \"\"\"Negative test for the 'check_prerequisites' method: isort isn't installed\"\"\"\n        with self.assertRaises(FileNotFoundError):\n            check_prerequisites()\n\n    @mock.patch(\n        \"aea.protocols.generator.common.subprocess.call\",\n        return_value=1,\n    )\n    def test_check_prerequisites_negative_protolint_is_not_installed(\n        self, mocked_is_installed\n    ):\n        \"\"\"Negative test for the 'check_prerequisites' method: protolint isn't installed\"\"\"\n        with self.assertRaises(FileNotFoundError):\n            check_prerequisites()\n\n    @mock.patch(\n        \"aea.protocols.generator.common.is_installed\",\n        side_effect=protoc_is_not_installed_side_effect,\n    )\n    def test_check_prerequisites_negative_protoc_is_not_installed(\n        self, mocked_is_installed\n    ):\n        \"\"\"Negative test for the 'check_prerequisites' method: protoc isn't installed\"\"\"\n        with self.assertRaises(FileNotFoundError):\n            check_prerequisites()\n\n    def test_load_protocol_specification(\n        self,\n    ):\n        \"\"\"Test the 'load_protocol_specification' method\"\"\"\n        spec = load_protocol_specification(PATH_TO_T_PROTOCOL_SPECIFICATION)\n        assert spec.name == T_PROTOCOL_NAME\n        assert spec.version == \"0.1.0\"\n        assert spec.author == \"fetchai\"\n        assert spec.license == \"Apache-2.0\"\n        assert spec.aea_version == \">=1.0.0, <2.0.0\"\n        assert spec.description == \"A protocol for testing purposes.\"\n        assert spec.speech_acts is not None\n        assert spec.protobuf_snippets is not None and spec.protobuf_snippets != \"\"\n\n    def test_create_protocol_file(\n        self,\n    ):\n        \"\"\"Test the '_create_protocol_file' method\"\"\"\n        file_name = \"temp_file\"\n        file_content = \"this is a temporary file\"\n\n        _create_protocol_file(self.t, file_name, file_content)\n        path_to_the_file = os.path.join(self.t, file_name)\n\n        assert Path(path_to_the_file).exists()\n        assert Path(path_to_the_file).read_text() == file_content\n\n    @mock.patch(\"subprocess.run\")\n    def test_try_run_black_formatting(self, mocked_subprocess):\n        \"\"\"Test the 'try_run_black_formatting' method\"\"\"\n        try_run_black_formatting(\"some_path\")\n        mocked_subprocess.assert_called_once()\n\n    @mock.patch(\"subprocess.run\")\n    def test_try_run_isort_formatting(self, mocked_subprocess):\n        \"\"\"Test the 'try_run_isort_formatting' method\"\"\"\n        try_run_isort_formatting(\"some_path\")\n        mocked_subprocess.assert_called_once()\n\n    @mock.patch(\"subprocess.run\")\n    def test_try_run_protoc(self, mocked_subprocess):\n        \"\"\"Test the 'try_run_protoc' method\"\"\"\n        try_run_protoc(\"some_path\", \"some_name\")\n        mocked_subprocess.assert_called_once()\n\n    @mock.patch(\"subprocess.run\")\n    def test_try_run_protolint(self, mocked_subprocess):\n        \"\"\"Test the 'try_run_protolint' method\"\"\"\n        try_run_protoc(\"some_path\", \"some_name\")\n        mocked_subprocess.assert_called_once()\n\n    @mock.patch(\"aea.protocols.generator.common.try_run_protoc\")\n    def test_check_protobuf_using_protoc_positive(self, mocked_try_run_protoc):\n        \"\"\"Positive test for the 'check_protobuf_using_protoc' method\"\"\"\n        protocol_name = \"protocol_name\"\n        file_name = protocol_name + \"_pb2.py\"\n\n        new_file = open(os.path.join(self.t, file_name), \"w+\")\n        new_file.close()\n        result, msg = check_protobuf_using_protoc(self.t, protocol_name)\n\n        assert not Path(self.t, file_name).exists()\n        assert result is True\n        assert msg == \"protobuf file is valid\"\n\n    @mock.patch(\n        \"subprocess.run\",\n        side_effect=CalledProcessError(\n            1, \"some_command\", stderr=\"name.proto:12:45: some_protoc_error\\n\"\n        ),\n    )\n    def test_check_protobuf_using_protoc_nagative(self, mocked_subprocess):\n        \"\"\"Negative test for the 'check_protobuf_using_protoc' method: protoc has some errors\"\"\"\n        result, msg = check_protobuf_using_protoc(\"some_path\", \"name\")\n        assert result is False\n        assert msg == \"some_protoc_error\"\n\n    @mock.patch(\"aea.protocols.generator.common.try_run_protoc\")\n    def test_compile_protobuf_using_protoc_positive(self, mocked_try_run_protoc):\n        \"\"\"Positive test for the 'compile_protobuf_using_protoc' method\"\"\"\n        protocol_name = \"protocol_name\"\n\n        result, msg = compile_protobuf_using_protoc(self.t, protocol_name, \"python\")\n\n        mocked_try_run_protoc.assert_called_once()\n        assert result is True\n        assert msg == \"protobuf schema successfully compiled\"\n\n    @mock.patch(\n        \"subprocess.run\",\n        side_effect=CalledProcessError(\n            1, \"some_command\", stderr=\"protocol_name.proto:12:45: some_protoc_error\\n\"\n        ),\n    )\n    def test_compile_protobuf_using_protoc_nagative(self, mocked_subprocess):\n        \"\"\"Negative test for the 'check_protobuf_using_protoc' method: protoc has some errors\"\"\"\n        protocol_name = \"protocol_name\"\n        result, msg = compile_protobuf_using_protoc(self.t, protocol_name, \"python\")\n        assert result is False\n        assert msg == \"some_protoc_error\"\n\n    @mock.patch(\"aea.protocols.generator.common.try_run_protolint\")\n    def test_apply_protolint_positive(self, mocked_try_run_protoc):\n        \"\"\"Positive test for the 'apply_protolint' method\"\"\"\n        protocol_name = \"protocol_name\"\n\n        result, msg = apply_protolint(self.t, protocol_name)\n\n        mocked_try_run_protoc.assert_called_once()\n        assert result is True\n        assert msg == \"protolint has no output\"\n\n    @mock.patch(\n        \"subprocess.run\",\n        side_effect=CalledProcessError(\n            1,\n            \"some_command\",\n            stderr=\"protocol_name.proto:12:45: some_protoc_error\\nprotocol_name.proto:12:45: incorrect indentation style ...\",\n        ),\n    )\n    def test_apply_protolint_nagative(self, mocked_subprocess):\n        \"\"\"Negative test for the 'apply_protolint' method: protoc has some errors\"\"\"\n        protocol_name = \"protocol_name\"\n        result, msg = apply_protolint(self.t, protocol_name)\n        assert result is False\n        assert msg == \"protocol_name.proto:12:45: some_protoc_error\"\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n"
  },
  {
    "path": "tests/test_aea/test_protocols/test_generator/test_end_to_end.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains end to end tests for the protocol generator.\"\"\"\nimport logging\nimport os\nimport shutil\nimport tempfile\nimport time\nfrom pathlib import Path\nfrom threading import Thread\nfrom typing import Optional, cast\n\nfrom aea.aea_builder import AEABuilder\nfrom aea.configurations.base import ComponentType, PublicId, SkillConfig\nfrom aea.configurations.constants import DEFAULT_LEDGER, DEFAULT_PRIVATE_KEY_FILE\nfrom aea.crypto.helpers import create_private_key\nfrom aea.protocols.base import Address, Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\nfrom aea.skills.base import Handler, Skill, SkillContext\n\nfrom packages.fetchai.connections.oef.connection import (\n    PUBLIC_ID as OEF_CONNECTION_PUBLIC_ID,\n)\n\nfrom tests.common.utils import UseOef\nfrom tests.conftest import ROOT_DIR\nfrom tests.data.generator.t_protocol.dialogues import (\n    TProtocolDialogue,\n    TProtocolDialogues,\n)\nfrom tests.data.generator.t_protocol.message import TProtocolMessage  # type: ignore\nfrom tests.test_aea.test_protocols.test_generator.common import PATH_TO_T_PROTOCOL\n\n\nlogger = logging.getLogger(\"aea\")\nlogging.basicConfig(level=logging.INFO)\n\n\nclass TestEndToEndGenerator(UseOef):\n    \"\"\"\n    Test that the generating a protocol works correctly in correct preconditions.\n\n    Note: Types involving Floats seem to lose some precision when serialised then deserialised using protobuf.\n    So tests for these types are commented out throughout for now.\n    \"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        shutil.copytree(Path(ROOT_DIR, \"packages\"), Path(cls.t, \"packages\"))\n        os.chdir(cls.t)\n        cls.private_key_path_1 = os.path.join(cls.t, DEFAULT_PRIVATE_KEY_FILE + \"_1\")\n        cls.private_key_path_2 = os.path.join(cls.t, DEFAULT_PRIVATE_KEY_FILE + \"_2\")\n        create_private_key(DEFAULT_LEDGER, cls.private_key_path_1)\n        create_private_key(DEFAULT_LEDGER, cls.private_key_path_2)\n\n    def test_generated_protocol_end_to_end(self):\n        \"\"\"Test that a generated protocol could be used in exchanging messages between two agents.\"\"\"\n        agent_name_1 = \"my_aea_1\"\n        agent_name_2 = \"my_aea_2\"\n        builder_1 = AEABuilder()\n        builder_1.set_name(agent_name_1)\n        builder_1.add_private_key(DEFAULT_LEDGER, self.private_key_path_1)\n        builder_1.set_default_ledger(DEFAULT_LEDGER)\n        builder_1.add_protocol(\n            Path(ROOT_DIR, \"packages\", \"fetchai\", \"protocols\", \"fipa\")\n        )\n        builder_1.add_protocol(\n            Path(ROOT_DIR, \"packages\", \"fetchai\", \"protocols\", \"oef_search\")\n        )\n        builder_1.add_component(\n            ComponentType.PROTOCOL,\n            Path(PATH_TO_T_PROTOCOL),\n            skip_consistency_check=True,\n        )\n        builder_1.add_connection(\n            Path(ROOT_DIR, \"packages\", \"fetchai\", \"connections\", \"oef\")\n        )\n\n        builder_1.set_default_connection(OEF_CONNECTION_PUBLIC_ID)\n\n        builder_2 = AEABuilder()\n        builder_2.set_name(agent_name_2)\n        builder_2.add_private_key(DEFAULT_LEDGER, self.private_key_path_2)\n        builder_2.set_default_ledger(DEFAULT_LEDGER)\n        builder_2.add_protocol(\n            Path(ROOT_DIR, \"packages\", \"fetchai\", \"protocols\", \"fipa\")\n        )\n        builder_2.add_protocol(\n            Path(ROOT_DIR, \"packages\", \"fetchai\", \"protocols\", \"oef_search\")\n        )\n        builder_2.add_component(\n            ComponentType.PROTOCOL,\n            Path(PATH_TO_T_PROTOCOL),\n            skip_consistency_check=True,\n        )\n        builder_2.add_connection(\n            Path(ROOT_DIR, \"packages\", \"fetchai\", \"connections\", \"oef\")\n        )\n        builder_2.set_default_connection(OEF_CONNECTION_PUBLIC_ID)\n\n        # create AEAs\n        aea_1 = builder_1.build(connection_ids=[OEF_CONNECTION_PUBLIC_ID])\n        aea_2 = builder_2.build(connection_ids=[OEF_CONNECTION_PUBLIC_ID])\n\n        # dialogues\n        def role_from_first_message_1(\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return TProtocolDialogue.Role.ROLE_1\n\n        agent_1_dialogues = TProtocolDialogues(\n            self_address=aea_1.identity.address,\n            role_from_first_message=role_from_first_message_1,\n        )\n\n        def role_from_first_message_1(\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return TProtocolDialogue.Role.ROLE_2\n\n        agent_2_dialogues = TProtocolDialogues(\n            self_address=aea_2.identity.address,\n            role_from_first_message=role_from_first_message_1,\n        )\n\n        # messages\n        message_1, aea_1_dialogue = agent_1_dialogues.create(\n            counterparty=aea_2.identity.address,\n            performative=TProtocolMessage.Performative.PERFORMATIVE_PT,\n            content_bytes=b\"some bytes\",\n            content_int=42,\n            content_float=42.7,\n            content_bool=True,\n            content_str=\"some string\",\n        )\n        message_1 = cast(TProtocolMessage, message_1)\n\n        message_2, aea_2_dialogue = agent_2_dialogues.create(\n            counterparty=aea_1.identity.address,\n            performative=TProtocolMessage.Performative.PERFORMATIVE_PT,\n            content_bytes=b\"some other bytes\",\n            content_int=43,\n            content_float=43.7,\n            content_bool=False,\n            content_str=\"some other string\",\n        )\n        message_2 = cast(TProtocolMessage, message_2)\n\n        # add handlers to AEA resources\n        skill_context_1 = SkillContext(aea_1.context)\n        skill_1 = Skill(SkillConfig(\"fake_skill\", \"fetchai\", \"0.1.0\"), skill_context_1)\n        skill_context_1._skill = skill_1\n\n        agent_1_handler = Agent1Handler(\n            skill_context=skill_context_1,\n            name=\"fake_handler_1\",\n            dialogues=agent_1_dialogues,\n        )\n        aea_1.resources._handler_registry.register(\n            (\n                PublicId.from_str(\"fetchai/fake_skill:0.1.0\"),\n                TProtocolMessage.protocol_id,\n            ),\n            agent_1_handler,\n        )\n        skill_context_2 = SkillContext(aea_2.context)\n        skill_2 = Skill(SkillConfig(\"fake_skill\", \"fetchai\", \"0.1.0\"), skill_context_2)\n        skill_context_2._skill = skill_2\n\n        agent_2_handler = Agent2Handler(\n            message=message_2,\n            dialogues=agent_2_dialogues,\n            skill_context=skill_context_2,\n            name=\"fake_handler_2\",\n        )\n        aea_2.resources._handler_registry.register(\n            (\n                PublicId.from_str(\"fetchai/fake_skill:0.1.0\"),\n                TProtocolMessage.protocol_id,\n            ),\n            agent_2_handler,\n        )\n\n        # Start threads\n        t_1 = Thread(target=aea_1.start)\n        t_2 = Thread(target=aea_2.start)\n        try:\n            t_1.start()\n            t_2.start()\n            time.sleep(1.0)\n            aea_1.outbox.put_message(message_1)\n            time.sleep(5.0)\n            assert (\n                agent_2_handler.handled_message.message_id == message_1.message_id\n            ), \"Message from Agent 1 to 2: message ids do not match\"\n            assert (\n                agent_2_handler.handled_message.dialogue_reference\n                == message_1.dialogue_reference\n            ), \"Message from Agent 1 to 2: dialogue references do not match\"\n            assert (\n                agent_2_handler.handled_message.dialogue_reference[0]\n                == message_1.dialogue_reference[0]\n            ), \"Message from Agent 1 to 2: dialogue reference[0]s do not match\"\n            assert (\n                agent_2_handler.handled_message.dialogue_reference[1]\n                == message_1.dialogue_reference[1]\n            ), \"Message from Agent 1 to 2: dialogue reference[1]s do not match\"\n            assert (\n                agent_2_handler.handled_message.target == message_1.target\n            ), \"Message from Agent 1 to 2: targets do not match\"\n            assert (\n                agent_2_handler.handled_message.performative == message_1.performative\n            ), \"Message from Agent 1 to 2: performatives do not match\"\n            assert (\n                agent_2_handler.handled_message.content_bytes == message_1.content_bytes\n            ), \"Message from Agent 1 to 2: content_bytes do not match\"\n            assert (\n                agent_2_handler.handled_message.content_int == message_1.content_int\n            ), \"Message from Agent 1 to 2: content_int do not match\"\n            # assert (\n            #     agent_2_handler.handled_message.content_float == message_1.content_float # noqa: E800\n            # ), \"Message from Agent 1 to 2: content_float do not match\"\n            assert (\n                agent_2_handler.handled_message.content_bool == message_1.content_bool\n            ), \"Message from Agent 1 to 2: content_bool do not match\"\n            assert (\n                agent_2_handler.handled_message.content_str == message_1.content_str\n            ), \"Message from Agent 1 to 2: content_str do not match\"\n\n            assert (\n                agent_1_handler.handled_message.message_id == message_2.message_id\n            ), \"Message from Agent 1 to 2: dialogue references do not match\"\n            assert (\n                agent_1_handler.handled_message.dialogue_reference\n                == message_2.dialogue_reference\n            ), \"Message from Agent 2 to 1: dialogue references do not match\"\n            assert (\n                agent_1_handler.handled_message.dialogue_reference[0]\n                == message_2.dialogue_reference[0]\n            ), \"Message from Agent 2 to 1: dialogue reference[0]s do not match\"\n            assert (\n                agent_1_handler.handled_message.dialogue_reference[1]\n                == message_2.dialogue_reference[1]\n            ), \"Message from Agent 2 to 1: dialogue reference[1]s do not match\"\n            assert (\n                agent_1_handler.handled_message.target == message_2.target\n            ), \"Message from Agent 2 to 1: targets do not match\"\n            assert (\n                agent_1_handler.handled_message.performative == message_2.performative\n            ), \"Message from Agent 2 to 1: performatives do not match\"\n            assert (\n                agent_1_handler.handled_message.content_bytes == message_2.content_bytes\n            ), \"Message from Agent 2 to 1: content_bytes do not match\"\n            assert (\n                agent_1_handler.handled_message.content_int == message_2.content_int\n            ), \"Message from Agent 2 to 1: content_int do not match\"\n            # assert (\n            #     agent_1_handler.handled_message.content_float == message_2.content_float # noqa: E800\n            # ), \"Message from Agent 2 to 1: content_float do not match\"\n            assert (\n                agent_1_handler.handled_message.content_bool == message_2.content_bool\n            ), \"Message from Agent 2 to 1: content_bool do not match\"\n            assert (\n                agent_1_handler.handled_message.content_str == message_2.content_str\n            ), \"Message from Agent 2 to 1: content_str do not match\"\n            time.sleep(2.0)\n        finally:\n            aea_1.stop()\n            aea_2.stop()\n            t_1.join()\n            t_2.join()\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass Agent1Handler(Handler):\n    \"\"\"The handler for agent 1.\"\"\"\n\n    SUPPORTED_PROTOCOL = TProtocolMessage.protocol_id  # type: Optional[PublicId]\n\n    def __init__(self, dialogues: TProtocolDialogues, **kwargs):\n        \"\"\"Initialize the handler.\"\"\"\n        super().__init__(**kwargs)\n        self.kwargs = kwargs\n        self.handled_message = None  # type: Optional[TProtocolMessage]\n        self.dialogues = dialogues\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup for the handler.\"\"\"\n        pass\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to a message.\n\n        :param message: the message\n        :return: None\n        \"\"\"\n        message = cast(TProtocolMessage, message)\n        self.dialogues.update(message)\n        self.handled_message = message\n\n    def teardown(self) -> None:\n        \"\"\"\n        Implement the handler teardown.\n\n        :return: None\n        \"\"\"\n\n\nclass Agent2Handler(Handler):\n    \"\"\"The handler for agent 2.\"\"\"\n\n    SUPPORTED_PROTOCOL = TProtocolMessage.protocol_id  # type: Optional[PublicId]\n\n    def __init__(\n        self, message: TProtocolMessage, dialogues: TProtocolDialogues, **kwargs\n    ):\n        \"\"\"Initialize the handler.\"\"\"\n        print(\"inside handler's initialisation method for agent 2\")\n        super().__init__(**kwargs)\n        self.kwargs = kwargs\n        self.handled_message = None  # type: Optional[TProtocolMessage]\n        self.message_2 = message\n        self.dialogues = dialogues\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup for the handler.\"\"\"\n        pass\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to a message.\n\n        :param message: the message\n        :return: None\n        \"\"\"\n        message = cast(TProtocolMessage, message)\n        dialogue = self.dialogues.update(message)\n        self.handled_message = message\n        assert (\n            dialogue is not None\n        ), \"Agent 2 didn't update dialogue with incoming message {}\".format(\n            str(message)\n        )\n        dialogue.reply(\n            target_message=message,\n            performative=self.message_2.performative,\n            content_bytes=self.message_2.content_bytes,\n            content_int=self.message_2.content_int,\n            content_float=self.message_2.content_float,\n            content_bool=self.message_2.content_bool,\n            content_str=self.message_2.content_str,\n        )\n        self.context.outbox.put_message(self.message_2)\n\n    def teardown(self) -> None:\n        \"\"\"\n        Implement the handler teardown.\n\n        :return: None\n        \"\"\"\n"
  },
  {
    "path": "tests/test_aea/test_protocols/test_generator/test_extract_specification.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests for generator/extract_specification.py module.\"\"\"\nimport logging\nimport os\nimport shutil\nimport tempfile\nfrom unittest import TestCase\n\nfrom aea.configurations.base import ProtocolSpecificationParseError\nfrom aea.protocols.generator.common import load_protocol_specification\nfrom aea.protocols.generator.extract_specification import (\n    PythonicProtocolSpecification,\n    _ct_specification_type_to_python_type,\n    _mt_specification_type_to_python_type,\n    _optional_specification_type_to_python_type,\n    _pct_specification_type_to_python_type,\n    _pmt_specification_type_to_python_type,\n    _pt_specification_type_to_python_type,\n    _specification_type_to_python_type,\n    extract,\n)\n\nfrom tests.test_aea.test_protocols.test_generator.common import (\n    PATH_TO_T_PROTOCOL_SPECIFICATION,\n)\n\n\nlogger = logging.getLogger(\"aea\")\nlogging.basicConfig(level=logging.INFO)\n\n\nclass TestExtractSpecification(TestCase):\n    \"\"\"Test for generator/extract_specification.py.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Setup class.\"\"\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        os.chdir(cls.t)\n\n    def test_ct_specification_type_to_python_type(self):\n        \"\"\"Test the '_ct_specification_type_to_python_type' method.\"\"\"\n        specification_type_1 = \"ct:DataModel\"\n        expected_1 = \"DataModel\"\n        assert _ct_specification_type_to_python_type(specification_type_1) == expected_1\n\n        specification_type_2 = \"ct:Query\"\n        expected_2 = \"Query\"\n        assert _ct_specification_type_to_python_type(specification_type_2) == expected_2\n\n    def test_pt_specification_type_to_python_type(self):\n        \"\"\"Test the '_pt_specification_type_to_python_type' method.\"\"\"\n        specification_type_1 = \"pt:bytes\"\n        expected_1 = \"bytes\"\n        assert _pt_specification_type_to_python_type(specification_type_1) == expected_1\n\n        specification_type_2 = \"pt:int\"\n        expected_2 = \"int\"\n        assert _pt_specification_type_to_python_type(specification_type_2) == expected_2\n\n        specification_type_3 = \"pt:float\"\n        expected_3 = \"float\"\n        assert _pt_specification_type_to_python_type(specification_type_3) == expected_3\n\n        specification_type_4 = \"pt:bool\"\n        expected_4 = \"bool\"\n        assert _pt_specification_type_to_python_type(specification_type_4) == expected_4\n\n        specification_type_5 = \"pt:str\"\n        expected_5 = \"str\"\n        assert _pt_specification_type_to_python_type(specification_type_5) == expected_5\n\n    def test_pct_specification_type_to_python_type(self):\n        \"\"\"Test the '_pct_specification_type_to_python_type' method.\"\"\"\n        specification_type_1 = \"pt:set[pt:bytes]\"\n        expected_1 = \"FrozenSet[bytes]\"\n        assert (\n            _pct_specification_type_to_python_type(specification_type_1) == expected_1\n        )\n\n        specification_type_2 = \"pt:set[pt:int]\"\n        expected_2 = \"FrozenSet[int]\"\n        assert (\n            _pct_specification_type_to_python_type(specification_type_2) == expected_2\n        )\n\n        specification_type_3 = \"pt:set[pt:float]\"\n        expected_3 = \"FrozenSet[float]\"\n        assert (\n            _pct_specification_type_to_python_type(specification_type_3) == expected_3\n        )\n\n        specification_type_4 = \"pt:set[pt:bool]\"\n        expected_4 = \"FrozenSet[bool]\"\n        assert (\n            _pct_specification_type_to_python_type(specification_type_4) == expected_4\n        )\n\n        specification_type_5 = \"pt:set[pt:str]\"\n        expected_5 = \"FrozenSet[str]\"\n        assert (\n            _pct_specification_type_to_python_type(specification_type_5) == expected_5\n        )\n\n        specification_type_6 = \"pt:list[pt:bytes]\"\n        expected_6 = \"Tuple[bytes, ...]\"\n        assert (\n            _pct_specification_type_to_python_type(specification_type_6) == expected_6\n        )\n\n        specification_type_7 = \"pt:list[pt:int]\"\n        expected_7 = \"Tuple[int, ...]\"\n        assert (\n            _pct_specification_type_to_python_type(specification_type_7) == expected_7\n        )\n\n        specification_type_8 = \"pt:list[pt:float]\"\n        expected_8 = \"Tuple[float, ...]\"\n        assert (\n            _pct_specification_type_to_python_type(specification_type_8) == expected_8\n        )\n\n        specification_type_9 = \"pt:list[pt:bool]\"\n        expected_9 = \"Tuple[bool, ...]\"\n        assert (\n            _pct_specification_type_to_python_type(specification_type_9) == expected_9\n        )\n\n        specification_type_10 = \"pt:list[pt:str]\"\n        expected_10 = \"Tuple[str, ...]\"\n        assert (\n            _pct_specification_type_to_python_type(specification_type_10) == expected_10\n        )\n\n    def test_pmt_specification_type_to_python_type(self):\n        \"\"\"Test the '_pmt_specification_type_to_python_type' method.\"\"\"\n        specification_type_1 = \"pt:dict[pt:int, pt:bytes]\"\n        expected_1 = \"Dict[int, bytes]\"\n        assert (\n            _pmt_specification_type_to_python_type(specification_type_1) == expected_1\n        )\n\n        specification_type_2 = \"pt:dict[pt:int, pt:int]\"\n        expected_2 = \"Dict[int, int]\"\n        assert (\n            _pmt_specification_type_to_python_type(specification_type_2) == expected_2\n        )\n\n        specification_type_3 = \"pt:dict[pt:int, pt:float]\"\n        expected_3 = \"Dict[int, float]\"\n        assert (\n            _pmt_specification_type_to_python_type(specification_type_3) == expected_3\n        )\n\n        specification_type_4 = \"pt:dict[pt:int, pt:bool]\"\n        expected_4 = \"Dict[int, bool]\"\n        assert (\n            _pmt_specification_type_to_python_type(specification_type_4) == expected_4\n        )\n\n        specification_type_5 = \"pt:dict[pt:int, pt:str]\"\n        expected_5 = \"Dict[int, str]\"\n        assert (\n            _pmt_specification_type_to_python_type(specification_type_5) == expected_5\n        )\n\n        specification_type_6 = \"pt:dict[pt:bool, pt:bytes]\"\n        expected_6 = \"Dict[bool, bytes]\"\n        assert (\n            _pmt_specification_type_to_python_type(specification_type_6) == expected_6\n        )\n\n        specification_type_7 = \"pt:dict[pt:bool, pt:int]\"\n        expected_7 = \"Dict[bool, int]\"\n        assert (\n            _pmt_specification_type_to_python_type(specification_type_7) == expected_7\n        )\n\n        specification_type_8 = \"pt:dict[pt:bool, pt:float]\"\n        expected_8 = \"Dict[bool, float]\"\n        assert (\n            _pmt_specification_type_to_python_type(specification_type_8) == expected_8\n        )\n\n        specification_type_9 = \"pt:dict[pt:bool, pt:bool]\"\n        expected_9 = \"Dict[bool, bool]\"\n        assert (\n            _pmt_specification_type_to_python_type(specification_type_9) == expected_9\n        )\n\n        specification_type_10 = \"pt:dict[pt:bool, pt:str]\"\n        expected_10 = \"Dict[bool, str]\"\n        assert (\n            _pmt_specification_type_to_python_type(specification_type_10) == expected_10\n        )\n\n        specification_type_11 = \"pt:dict[pt:str, pt:bytes]\"\n        expected_11 = \"Dict[str, bytes]\"\n        assert (\n            _pmt_specification_type_to_python_type(specification_type_11) == expected_11\n        )\n\n        specification_type_12 = \"pt:dict[pt:str, pt:int]\"\n        expected_12 = \"Dict[str, int]\"\n        assert (\n            _pmt_specification_type_to_python_type(specification_type_12) == expected_12\n        )\n\n        specification_type_13 = \"pt:dict[pt:str, pt:float]\"\n        expected_13 = \"Dict[str, float]\"\n        assert (\n            _pmt_specification_type_to_python_type(specification_type_13) == expected_13\n        )\n\n        specification_type_14 = \"pt:dict[pt:str, pt:bool]\"\n        expected_14 = \"Dict[str, bool]\"\n        assert (\n            _pmt_specification_type_to_python_type(specification_type_14) == expected_14\n        )\n\n        specification_type_15 = \"pt:dict[pt:str, pt:str]\"\n        expected_15 = \"Dict[str, str]\"\n        assert (\n            _pmt_specification_type_to_python_type(specification_type_15) == expected_15\n        )\n\n    def test_mt_specification_type_to_python_type(self):\n        \"\"\"Test the '_mt_specification_type_to_python_type' method.\"\"\"\n        specification_type_1 = \"pt:union[pt:int, pt:bytes]\"\n        expected_1 = \"Union[int, bytes]\"\n        assert _mt_specification_type_to_python_type(specification_type_1) == expected_1\n\n        specification_type_2 = \"pt:union[ct:DataModel, pt:bytes, pt:int, pt:bool, pt:float, pt:str, pt:set[pt:int], pt:list[pt:bool], pt:dict[pt:str,pt:str]]\"\n        expected_2 = \"Union[DataModel, bytes, int, bool, float, str, FrozenSet[int], Tuple[bool, ...], Dict[str, str]]\"\n        assert _mt_specification_type_to_python_type(specification_type_2) == expected_2\n\n        specification_type_3 = (\n            \"pt:union[ct:DataModel, pt:set[pt:int], pt:list[pt:bool], pt:bytes, pt:dict[pt:bool,pt:float], pt:int, \"\n            \"pt:set[pt:bool], pt:dict[pt:int, pt:str], pt:list[pt:str], pt:bool, pt:float, pt:str, pt:dict[pt:str, pt:str]]\"\n        )\n        expected_3 = (\n            \"Union[DataModel, FrozenSet[int], Tuple[bool, ...], bytes, Dict[bool, float], int, \"\n            \"FrozenSet[bool], Dict[int, str], Tuple[str, ...], bool, float, str, Dict[str, str]]\"\n        )\n        assert _mt_specification_type_to_python_type(specification_type_3) == expected_3\n\n    def test_optional_specification_type_to_python_type(self):\n        \"\"\"Test the '_optional_specification_type_to_python_type' method.\"\"\"\n        specification_type_1 = (\n            \"pt:optional[pt:union[ct:DataModel, pt:bytes, pt:int, pt:bool, pt:float, pt:str, pt:set[pt:int], \"\n            \"pt:list[pt:bool], pt:dict[pt:str, pt:str]]]\"\n        )\n        expected_1 = \"Optional[Union[DataModel, bytes, int, bool, float, str, FrozenSet[int], Tuple[bool, ...], Dict[str, str]]]\"\n        assert (\n            _optional_specification_type_to_python_type(specification_type_1)\n            == expected_1\n        )\n\n        specification_type_2 = (\n            \"pt:optional[pt:union[ct:DataModel, pt:bytes, pt:int, pt:bool, pt:float, pt:str, pt:set[pt:int], \"\n            \"pt:list[pt:bool], pt:dict[pt:str,pt:str]]]\"\n        )\n        expected_2 = \"Optional[Union[DataModel, bytes, int, bool, float, str, FrozenSet[int], Tuple[bool, ...], Dict[str, str]]]\"\n        assert (\n            _optional_specification_type_to_python_type(specification_type_2)\n            == expected_2\n        )\n\n        specification_type_3 = \"pt:optional[ct:DataModel]\"\n        expected_3 = \"Optional[DataModel]\"\n        assert (\n            _optional_specification_type_to_python_type(specification_type_3)\n            == expected_3\n        )\n\n    def test_specification_type_to_python_type(self):\n        \"\"\"Test the '_specification_type_to_python_type' method.\"\"\"\n        specification_type_1 = \"ct:DataModel\"\n        expected_1 = \"DataModel\"\n        assert _specification_type_to_python_type(specification_type_1) == expected_1\n\n        specification_type_2 = \"pt:bytes\"\n        expected_2 = \"bytes\"\n        assert _specification_type_to_python_type(specification_type_2) == expected_2\n\n        specification_type_3 = \"pt:set[pt:int]\"\n        expected_3 = \"FrozenSet[int]\"\n        assert _specification_type_to_python_type(specification_type_3) == expected_3\n\n        specification_type_4 = \"pt:list[pt:float]\"\n        expected_4 = \"Tuple[float, ...]\"\n        assert _specification_type_to_python_type(specification_type_4) == expected_4\n\n        specification_type_5 = \"pt:dict[pt:bool, pt:str]\"\n        expected_5 = \"Dict[bool, str]\"\n        assert _specification_type_to_python_type(specification_type_5) == expected_5\n\n        specification_type_6 = \"pt:union[pt:int, pt:bytes]\"\n        expected_6 = \"Union[int, bytes]\"\n        assert _specification_type_to_python_type(specification_type_6) == expected_6\n\n        specification_type_7 = (\n            \"pt:optional[pt:union[ct:DataModel, pt:bytes, pt:int, pt:bool, pt:float, pt:str, pt:set[pt:int], \"\n            \"pt:list[pt:bool], pt:dict[pt:str,pt:str]]]\"\n        )\n        expected_7 = \"Optional[Union[DataModel, bytes, int, bool, float, str, FrozenSet[int], Tuple[bool, ...], Dict[str, str]]]\"\n        assert _specification_type_to_python_type(specification_type_7) == expected_7\n\n        specification_type_8 = \"wrong_type\"\n        with self.assertRaises(ProtocolSpecificationParseError) as cm:\n            _specification_type_to_python_type(specification_type_8)\n        self.assertEqual(\n            str(cm.exception), \"Unsupported type: '{}'\".format(specification_type_8)\n        )\n\n        specification_type_9 = \"pt:integer\"\n        with self.assertRaises(ProtocolSpecificationParseError) as cm:\n            _specification_type_to_python_type(specification_type_9)\n        self.assertEqual(\n            str(cm.exception), \"Unsupported type: '{}'\".format(specification_type_9)\n        )\n\n        specification_type_10 = \"pt: list\"\n        with self.assertRaises(ProtocolSpecificationParseError) as cm:\n            _specification_type_to_python_type(specification_type_10)\n        self.assertEqual(\n            str(cm.exception), \"Unsupported type: '{}'\".format(specification_type_10)\n        )\n\n        specification_type_11 = \"pt:list[wrong_sub_type]\"\n        with self.assertRaises(ProtocolSpecificationParseError) as cm:\n            _specification_type_to_python_type(specification_type_11)\n        self.assertEqual(str(cm.exception), \"Unsupported type: 'wrong_sub_type'\")\n\n    def test_pythonic_protocol_specification_class(self):\n        \"\"\"Test the 'PythonicProtocolSpecification' class.\"\"\"\n        spec = PythonicProtocolSpecification()\n        assert spec.speech_acts == {}\n        assert spec.all_performatives == []\n        assert spec.all_unique_contents == {}\n        assert spec.all_custom_types == []\n        assert spec.custom_custom_types == {}\n        assert spec.initial_performatives == []\n        assert spec.reply == {}\n        assert spec.terminal_performatives == []\n        assert spec.roles == []\n        assert spec.end_states == []\n        assert spec.typing_imports == {\n            \"Set\": True,\n            \"Tuple\": True,\n            \"cast\": True,\n            \"FrozenSet\": False,\n            \"Dict\": False,\n            \"Union\": False,\n            \"Optional\": False,\n        }\n\n    def test_extract_positive(self):\n        \"\"\"Positive test the 'extract' method.\"\"\"\n        protocol_specification = load_protocol_specification(\n            PATH_TO_T_PROTOCOL_SPECIFICATION\n        )\n        spec = extract(protocol_specification)\n\n        assert spec.speech_acts == {\n            \"performative_ct\": {\"content_ct\": \"DataModel\"},\n            \"performative_pt\": {\n                \"content_bytes\": \"bytes\",\n                \"content_int\": \"int\",\n                \"content_float\": \"float\",\n                \"content_bool\": \"bool\",\n                \"content_str\": \"str\",\n            },\n            \"performative_pct\": {\n                \"content_set_bytes\": \"FrozenSet[bytes]\",\n                \"content_set_int\": \"FrozenSet[int]\",\n                \"content_set_float\": \"FrozenSet[float]\",\n                \"content_set_bool\": \"FrozenSet[bool]\",\n                \"content_set_str\": \"FrozenSet[str]\",\n                \"content_list_bytes\": \"Tuple[bytes, ...]\",\n                \"content_list_int\": \"Tuple[int, ...]\",\n                \"content_list_float\": \"Tuple[float, ...]\",\n                \"content_list_bool\": \"Tuple[bool, ...]\",\n                \"content_list_str\": \"Tuple[str, ...]\",\n            },\n            \"performative_pmt\": {\n                \"content_dict_int_bytes\": \"Dict[int, bytes]\",\n                \"content_dict_int_int\": \"Dict[int, int]\",\n                \"content_dict_int_float\": \"Dict[int, float]\",\n                \"content_dict_int_bool\": \"Dict[int, bool]\",\n                \"content_dict_int_str\": \"Dict[int, str]\",\n                \"content_dict_bool_bytes\": \"Dict[bool, bytes]\",\n                \"content_dict_bool_int\": \"Dict[bool, int]\",\n                \"content_dict_bool_float\": \"Dict[bool, float]\",\n                \"content_dict_bool_bool\": \"Dict[bool, bool]\",\n                \"content_dict_bool_str\": \"Dict[bool, str]\",\n                \"content_dict_str_bytes\": \"Dict[str, bytes]\",\n                \"content_dict_str_int\": \"Dict[str, int]\",\n                \"content_dict_str_float\": \"Dict[str, float]\",\n                \"content_dict_str_bool\": \"Dict[str, bool]\",\n                \"content_dict_str_str\": \"Dict[str, str]\",\n            },\n            \"performative_mt\": {\n                \"content_union_1\": \"Union[DataModel1, bytes, int, float, bool, str, FrozenSet[int], Tuple[bool, ...], Dict[str, int]]\",\n                \"content_union_2\": \"Union[FrozenSet[bytes], FrozenSet[int], FrozenSet[str], Tuple[float, ...], Tuple[bool, ...], Tuple[bytes, ...], Dict[str, int], Dict[int, float], Dict[bool, bytes], int]\",\n                \"content_union_3\": \"Union[DataModel2, DataModel3]\",\n            },\n            \"performative_o\": {\n                \"content_o_ct\": \"Optional[DataModel4]\",\n                \"content_o_bool\": \"Optional[bool]\",\n                \"content_o_set_int\": \"Optional[FrozenSet[int]]\",\n                \"content_o_list_bytes\": \"Optional[Tuple[bytes, ...]]\",\n                \"content_o_dict_str_int\": \"Optional[Dict[str, int]]\",\n            },\n            \"performative_empty_contents\": {},\n        }\n        assert spec.all_performatives == [\n            \"performative_ct\",\n            \"performative_empty_contents\",\n            \"performative_mt\",\n            \"performative_o\",\n            \"performative_pct\",\n            \"performative_pmt\",\n            \"performative_pt\",\n        ]\n        assert spec.all_unique_contents == {\n            \"content_ct\": \"DataModel\",\n            \"content_bytes\": \"bytes\",\n            \"content_int\": \"int\",\n            \"content_float\": \"float\",\n            \"content_bool\": \"bool\",\n            \"content_str\": \"str\",\n            \"content_set_bytes\": \"FrozenSet[bytes]\",\n            \"content_set_int\": \"FrozenSet[int]\",\n            \"content_set_float\": \"FrozenSet[float]\",\n            \"content_set_bool\": \"FrozenSet[bool]\",\n            \"content_set_str\": \"FrozenSet[str]\",\n            \"content_list_bytes\": \"Tuple[bytes, ...]\",\n            \"content_list_int\": \"Tuple[int, ...]\",\n            \"content_list_float\": \"Tuple[float, ...]\",\n            \"content_list_bool\": \"Tuple[bool, ...]\",\n            \"content_list_str\": \"Tuple[str, ...]\",\n            \"content_dict_int_bytes\": \"Dict[int, bytes]\",\n            \"content_dict_int_int\": \"Dict[int, int]\",\n            \"content_dict_int_float\": \"Dict[int, float]\",\n            \"content_dict_int_bool\": \"Dict[int, bool]\",\n            \"content_dict_int_str\": \"Dict[int, str]\",\n            \"content_dict_bool_bytes\": \"Dict[bool, bytes]\",\n            \"content_dict_bool_int\": \"Dict[bool, int]\",\n            \"content_dict_bool_float\": \"Dict[bool, float]\",\n            \"content_dict_bool_bool\": \"Dict[bool, bool]\",\n            \"content_dict_bool_str\": \"Dict[bool, str]\",\n            \"content_dict_str_bytes\": \"Dict[str, bytes]\",\n            \"content_dict_str_int\": \"Dict[str, int]\",\n            \"content_dict_str_float\": \"Dict[str, float]\",\n            \"content_dict_str_bool\": \"Dict[str, bool]\",\n            \"content_dict_str_str\": \"Dict[str, str]\",\n            \"content_union_1\": \"Union[DataModel1, bytes, int, float, bool, str, FrozenSet[int], Tuple[bool, ...], Dict[str, int]]\",\n            \"content_union_2\": \"Union[FrozenSet[bytes], FrozenSet[int], FrozenSet[str], Tuple[float, ...], Tuple[bool, ...], Tuple[bytes, ...], Dict[str, int], Dict[int, float], Dict[bool, bytes], int]\",\n            \"content_union_3\": \"Union[DataModel2, DataModel3]\",\n            \"content_o_ct\": \"Optional[DataModel4]\",\n            \"content_o_bool\": \"Optional[bool]\",\n            \"content_o_set_int\": \"Optional[FrozenSet[int]]\",\n            \"content_o_list_bytes\": \"Optional[Tuple[bytes, ...]]\",\n            \"content_o_dict_str_int\": \"Optional[Dict[str, int]]\",\n        }\n        assert spec.all_custom_types == [\n            \"DataModel\",\n            \"DataModel1\",\n            \"DataModel2\",\n            \"DataModel3\",\n            \"DataModel4\",\n        ]\n        assert spec.custom_custom_types == {\n            \"DataModel\": \"CustomDataModel\",\n            \"DataModel1\": \"CustomDataModel1\",\n            \"DataModel2\": \"CustomDataModel2\",\n            \"DataModel3\": \"CustomDataModel3\",\n            \"DataModel4\": \"CustomDataModel4\",\n        }\n\n        assert spec.initial_performatives == [\"PERFORMATIVE_CT\", \"PERFORMATIVE_PT\"]\n        assert spec.reply == {\n            \"performative_ct\": [\"performative_pct\"],\n            \"performative_pt\": [\"performative_pt\", \"performative_pmt\"],\n            \"performative_pct\": [\"performative_mt\", \"performative_o\"],\n            \"performative_pmt\": [\"performative_mt\", \"performative_o\"],\n            \"performative_mt\": [],\n            \"performative_o\": [],\n            \"performative_empty_contents\": [\"performative_empty_contents\"],\n        }\n        assert spec.terminal_performatives == [\n            \"PERFORMATIVE_MT\",\n            \"PERFORMATIVE_O\",\n        ]\n        assert spec.roles == [\"role_1\", \"role_2\"]\n        assert spec.end_states == [\"end_state_1\", \"end_state_2\", \"end_state_3\"]\n        assert spec.typing_imports == {\n            \"Set\": True,\n            \"Tuple\": True,\n            \"cast\": True,\n            \"FrozenSet\": True,\n            \"Dict\": True,\n            \"Union\": True,\n            \"Optional\": True,\n        }\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n"
  },
  {
    "path": "tests/test_aea/test_protocols/test_generator/test_generator.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains miscellaneous tests for the protocol generator.\"\"\"\nimport logging\nimport os\nimport shutil\nimport tempfile\nfrom pathlib import Path\nfrom typing import cast\nfrom unittest import TestCase, mock\n\nimport pytest\n\nfrom aea.configurations.base import (\n    ProtocolSpecification,\n    ProtocolSpecificationParseError,\n)\nfrom aea.configurations.constants import SUPPORTED_PROTOCOL_LANGUAGES\nfrom aea.configurations.data_types import PublicId\nfrom aea.protocols.generator.base import (\n    CUSTOM_TYPES_DOT_PY_FILE_NAME,\n    ProtocolGenerator,\n)\nfrom aea.protocols.generator.common import _to_camel_case\n\nfrom tests.conftest import match_files\nfrom tests.data.generator.t_protocol.message import TProtocolMessage  # type: ignore\nfrom tests.test_aea.test_protocols.test_generator.common import (\n    PATH_TO_T_PROTOCOL,\n    PATH_TO_T_PROTOCOL_NO_CT,\n    PATH_TO_T_PROTOCOL_NO_CT_SPECIFICATION,\n    PATH_TO_T_PROTOCOL_SPECIFICATION,\n    T_PROTOCOL_NAME,\n    T_PROTOCOL_NO_CT_NAME,\n)\n\n\nlogger = logging.getLogger(\"aea\")\nlogging.basicConfig(level=logging.INFO)\n\n\nclass TestCompareLatestGeneratorOutputWithTestProtocol:\n    \"\"\"Test that the \"t_protocol\" test protocol matches with the latest generator output based on its specification.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        os.chdir(cls.t)\n\n    def test_compare_latest_generator_output_with_test_protocol(self):\n        \"\"\"\n        Test that the \"t_protocol\" test protocol matches with the latest generator output based on its specification.\n\n        Note:\n            - custom_types.py files are not compared as the generated one is only a template.\n            - protocol.yaml files are consequently not compared either because the different\n              custom_types.py files makes their IPFS hashes different.\n        \"\"\"\n        path_to_generated_protocol = self.t\n        dotted_path_to_package_for_imports = \"tests.data.generator.\"\n\n        # Generate the protocol\n        try:\n            protocol_generator = ProtocolGenerator(\n                path_to_protocol_specification=PATH_TO_T_PROTOCOL_SPECIFICATION,\n                output_path=path_to_generated_protocol,\n                dotted_path_to_protocol_package=dotted_path_to_package_for_imports,\n            )\n            protocol_generator.generate()\n        except Exception as e:\n            pytest.skip(\n                \"Something went wrong when generating the protocol. The exception:\"\n                + str(e)\n            )\n\n        # compare __init__.py\n        init_file_generated = Path(self.t, T_PROTOCOL_NAME, \"__init__.py\")\n        init_file_original = Path(\n            PATH_TO_T_PROTOCOL,\n            \"__init__.py\",\n        )\n        is_matched, diff = match_files(init_file_generated, init_file_original)\n        assert (\n            is_matched or len(diff) == 194\n        ), f\"Difference Found between __init__.py files:\\n{diff}\"\n\n        # compare message.py\n        message_file_generated = Path(self.t, T_PROTOCOL_NAME, \"message.py\")\n        message_file_original = Path(\n            PATH_TO_T_PROTOCOL,\n            \"message.py\",\n        )\n        is_matched, diff = match_files(message_file_generated, message_file_original)\n        assert is_matched, f\"Difference Found between message.py files:\\n{diff}\"\n\n        # compare serialization.py\n        serialization_file_generated = Path(self.t, T_PROTOCOL_NAME, \"serialization.py\")\n        serialization_file_original = Path(\n            PATH_TO_T_PROTOCOL,\n            \"serialization.py\",\n        )\n        is_matched, diff = match_files(\n            serialization_file_generated, serialization_file_original\n        )\n        assert is_matched, f\"Difference Found between serialization.py files:\\n{diff}\"\n\n        # compare dialogues.py\n        dialogue_file_generated = Path(self.t, T_PROTOCOL_NAME, \"dialogues.py\")\n        dialogue_file_original = Path(\n            PATH_TO_T_PROTOCOL,\n            \"dialogues.py\",\n        )\n        is_matched, diff = match_files(dialogue_file_generated, dialogue_file_original)\n        assert is_matched, f\"Difference Found between dialogues.py files:\\n{diff}\"\n\n        # compare .proto\n        proto_file_generated = Path(\n            self.t, T_PROTOCOL_NAME, \"{}.proto\".format(T_PROTOCOL_NAME)\n        )\n        proto_file_original = Path(\n            PATH_TO_T_PROTOCOL,\n            \"{}.proto\".format(T_PROTOCOL_NAME),\n        )\n        is_matched, diff = match_files(proto_file_generated, proto_file_original)\n        assert is_matched, f\"Difference Found between .proto files:\\n{diff}\"\n\n        # compare _pb2.py # noqa: E800\n        # ToDo this part fails in CI. Investigate why?\n        # pb2_file_generated = Path( # noqa: E800\n        #     self.t, T_PROTOCOL_NAME, \"{}_pb2.py\".format(T_PROTOCOL_NAME) # noqa: E800\n        # ) # noqa: E800\n        # pb2_file_original = Path( # noqa: E800\n        #     PATH_TO_T_PROTOCOL, \"{}_pb2.py\".format(T_PROTOCOL_NAME), # noqa: E800\n        # ) # noqa: E800\n        # is_matched, diff = match_files(pb2_file_generated, pb2_file_original) # noqa: E800\n        # assert is_matched, f\"Difference Found between _pb2.py files:\\n{diff}\" # noqa: E800\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestCompareLatestGeneratorOutputWithTestProtocolWithNoCustomTypes:\n    \"\"\"Test that the \"t_protocol\" test protocol matches with the latest generator output based on its specification.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        os.chdir(cls.t)\n\n    def test_compare_latest_generator_output_with_test_protocol(self):\n        \"\"\"\n        Test that the \"t_protocol\" test protocol matches with the latest generator output based on its specification.\n\n        Note:\n            - custom_types.py files are not compared as the generated one is only a template.\n            - protocol.yaml files are consequently not compared either because the different\n              custom_types.py files makes their IPFS hashes different.\n        \"\"\"\n\n        path_to_generated_protocol = self.t\n        dotted_path_to_package_for_imports = \"tests.data.generator.\"\n\n        # Generate the protocol\n        try:\n            protocol_generator = ProtocolGenerator(\n                path_to_protocol_specification=PATH_TO_T_PROTOCOL_NO_CT_SPECIFICATION,\n                output_path=path_to_generated_protocol,\n                dotted_path_to_protocol_package=dotted_path_to_package_for_imports,\n            )\n            protocol_generator.generate()\n        except Exception as e:\n            pytest.skip(\n                \"Something went wrong when generating the protocol. The exception:\"\n                + str(e)\n            )\n\n        # compare __init__.py\n        init_file_generated = Path(self.t, T_PROTOCOL_NO_CT_NAME, \"__init__.py\")\n        init_file_original = Path(\n            PATH_TO_T_PROTOCOL_NO_CT,\n            \"__init__.py\",\n        )\n        is_matched, diff = match_files(init_file_generated, init_file_original)\n        assert (\n            is_matched or len(diff) == 194\n        ), f\"Difference Found between __init__.py files:\\n{diff}\"\n\n        # compare message.py\n        message_file_generated = Path(self.t, T_PROTOCOL_NO_CT_NAME, \"message.py\")\n        message_file_original = Path(\n            PATH_TO_T_PROTOCOL_NO_CT,\n            \"message.py\",\n        )\n        is_matched, diff = match_files(message_file_generated, message_file_original)\n        assert is_matched, f\"Difference Found between message.py files:\\n{diff}\"\n\n        # compare serialization.py\n        serialization_file_generated = Path(\n            self.t, T_PROTOCOL_NO_CT_NAME, \"serialization.py\"\n        )\n        serialization_file_original = Path(\n            PATH_TO_T_PROTOCOL_NO_CT,\n            \"serialization.py\",\n        )\n        is_matched, diff = match_files(\n            serialization_file_generated, serialization_file_original\n        )\n        assert is_matched, f\"Difference Found between serialization.py files:\\n{diff}\"\n\n        # compare dialogues.py\n        dialogue_file_generated = Path(self.t, T_PROTOCOL_NO_CT_NAME, \"dialogues.py\")\n        dialogue_file_original = Path(\n            PATH_TO_T_PROTOCOL_NO_CT,\n            \"dialogues.py\",\n        )\n        is_matched, diff = match_files(dialogue_file_generated, dialogue_file_original)\n        assert is_matched, f\"Difference Found between dialogues.py files:\\n{diff}\"\n\n        # compare .proto\n        proto_file_generated = Path(\n            self.t, T_PROTOCOL_NO_CT_NAME, \"{}.proto\".format(T_PROTOCOL_NO_CT_NAME)\n        )\n        proto_file_original = Path(\n            PATH_TO_T_PROTOCOL_NO_CT,\n            \"{}.proto\".format(T_PROTOCOL_NO_CT_NAME),\n        )\n        is_matched, diff = match_files(proto_file_generated, proto_file_original)\n        assert is_matched, f\"Difference Found between .proto files:\\n{diff}\"\n\n        # compare _pb2.py # noqa: E800\n        # ToDo this part fails in CI. Investigate why? # noqa: E800\n        # pb2_file_generated = Path( # noqa: E800\n        #     self.t, protocol_name, \"{}_pb2.py\".format(protocol_name) # noqa: E800\n        # ) # noqa: E800\n        # pb2_file_original = Path(path_to_protocol, \"{}_pb2.py\".format(protocol_name),) # noqa: E800\n        # is_matched, diff = match_files(pb2_file_generated, pb2_file_original) # noqa: E800\n        # assert is_matched, f\"Difference Found between _pb2.py files:\\n{diff}\" # noqa: E800\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestSerialisations:\n    \"\"\"\n    Test that the generating a protocol works correctly in correct preconditions.\n\n    Note: Types involving Floats seem to lose some precision when serialised then deserialised using protobuf.\n    So tests for these types are commented out throughout for now.\n    \"\"\"\n\n    def test_generated_protocol_serialisation_ct(self):\n        \"\"\"Test serialisation and deserialisation of a message involving a ct type.\"\"\"\n        some_dict = {1: True, 2: False, 3: True, 4: False}\n        data_model = TProtocolMessage.DataModel(\n            bytes_field=b\"some bytes\",\n            int_field=42,\n            float_field=42.7,\n            bool_field=True,\n            str_field=\"some string\",\n            set_field={1, 2, 3, 4, 5},\n            list_field=[\"some string 1\", \"some string 2\"],\n            dict_field=some_dict,\n        )\n        message = TProtocolMessage(\n            message_id=1,\n            dialogue_reference=(str(0), \"\"),\n            target=0,\n            performative=TProtocolMessage.Performative.PERFORMATIVE_CT,\n            content_ct=data_model,\n        )\n\n        encoded_message_in_bytes = TProtocolMessage.serializer.encode(message)\n        decoded_message = cast(\n            TProtocolMessage,\n            TProtocolMessage.serializer.decode(encoded_message_in_bytes),\n        )\n\n        assert decoded_message.message_id == message.message_id\n        assert decoded_message.dialogue_reference == message.dialogue_reference\n        assert decoded_message.dialogue_reference[0] == message.dialogue_reference[0]\n        assert decoded_message.dialogue_reference[1] == message.dialogue_reference[1]\n        assert decoded_message.target == message.target\n        assert decoded_message.performative == message.performative\n        assert decoded_message.content_ct == message.content_ct\n\n    def test_generated_protocol_serialisation_pt(self):\n        \"\"\"Test serialisation and deserialisation of a message involving a pt type.\"\"\"\n        message = TProtocolMessage(\n            message_id=1,\n            dialogue_reference=(str(0), \"\"),\n            target=0,\n            performative=TProtocolMessage.Performative.PERFORMATIVE_PT,\n            content_bytes=b\"some bytes\",\n            content_int=42,\n            content_float=42.7,\n            content_bool=True,\n            content_str=\"some string\",\n        )\n\n        encoded_message_in_bytes = TProtocolMessage.serializer.encode(message)\n        decoded_message = cast(\n            TProtocolMessage,\n            TProtocolMessage.serializer.decode(encoded_message_in_bytes),\n        )\n\n        assert decoded_message.message_id == message.message_id\n        assert decoded_message.dialogue_reference == message.dialogue_reference\n        assert decoded_message.dialogue_reference[0] == message.dialogue_reference[0]\n        assert decoded_message.dialogue_reference[1] == message.dialogue_reference[1]\n        assert decoded_message.target == message.target\n        assert decoded_message.performative == message.performative\n        assert decoded_message.content_bytes == message.content_bytes\n        assert decoded_message.content_int == message.content_int\n        # assert decoded_message.content_float == message.content_float # noqa: E800\n        assert decoded_message.content_bool == message.content_bool\n        assert decoded_message.content_str == message.content_str\n\n    def test_generated_protocol_serialisation_pct(self):\n        \"\"\"Test serialisation and deserialisation of a message involving a pct type.\"\"\"\n        message = TProtocolMessage(\n            message_id=1,\n            dialogue_reference=(str(0), \"\"),\n            target=0,\n            performative=TProtocolMessage.Performative.PERFORMATIVE_PCT,\n            content_set_bytes=frozenset([b\"byte 1\", b\"byte 2\", b\"byte 3\"]),\n            content_set_int=frozenset([1, 2, 3]),\n            content_set_float=frozenset([1.2, 2.3, 3.4]),\n            content_set_bool=frozenset([True, False, False, True]),\n            content_set_str=frozenset([\"string1\", \"string2\", \"string3\"]),\n            content_list_bytes=(b\"byte 4\", b\"byte 5\", b\"byte 6\"),\n            content_list_int=(4, 5, 6),\n            content_list_float=(4.5, 5.6, 6.7),\n            content_list_bool=(False, True, False, False),\n            content_list_str=(\"string4\", \"string5\", \"string6\"),\n        )\n\n        encoded_message_in_bytes = TProtocolMessage.serializer.encode(message)\n        decoded_message = cast(\n            TProtocolMessage,\n            TProtocolMessage.serializer.decode(encoded_message_in_bytes),\n        )\n\n        assert decoded_message.message_id == message.message_id\n        assert decoded_message.dialogue_reference == message.dialogue_reference\n        assert decoded_message.dialogue_reference[0] == message.dialogue_reference[0]\n        assert decoded_message.dialogue_reference[1] == message.dialogue_reference[1]\n        assert decoded_message.target == message.target\n        assert decoded_message.performative == message.performative\n        assert decoded_message.content_set_bytes == message.content_set_bytes\n        assert decoded_message.content_set_int == message.content_set_int\n        # assert decoded_message.content_set_float == message.content_set_float # noqa: E800\n        assert decoded_message.content_set_bool == message.content_set_bool\n        assert decoded_message.content_set_str == message.content_set_str\n        assert decoded_message.content_list_bytes == message.content_list_bytes\n        assert decoded_message.content_list_int == message.content_list_int\n        # assert decoded_message.content_list_float == message.content_list_float # noqa: E800\n        assert decoded_message.content_list_bool == message.content_list_bool\n        assert decoded_message.content_list_str == message.content_list_str\n\n    def test_generated_protocol_serialisation_pmt(self):\n        \"\"\"Test serialisation and deserialisation of a message involving a pmt type.\"\"\"\n        message = TProtocolMessage(\n            message_id=1,\n            dialogue_reference=(str(0), \"\"),\n            target=0,\n            performative=TProtocolMessage.Performative.PERFORMATIVE_PMT,\n            content_dict_int_bytes={1: b\"bytes1\", 2: b\"bytes2\", 3: b\"bytes3\"},\n            content_dict_int_int={1: 2, 2: 3, 3: 4},\n            content_dict_int_float={1: 3.4, 2: 4.7, 3: 4.6},\n            content_dict_int_bool={1: True, 2: True, 3: False},\n            content_dict_int_str={1: \"string1\", 2: \"string2\", 3: \"string3\"},\n            content_dict_bool_bytes={True: b\"bytes1\", False: b\"bytes2\"},\n            content_dict_bool_int={True: 5, False: 7},\n            content_dict_bool_float={True: 5.4, False: 4.6},\n            content_dict_bool_bool={True: False, False: False},\n            content_dict_bool_str={True: \"string1\", False: \"string2\"},\n            content_dict_str_bytes={\n                \"string1\": b\"bytes1\",\n                \"string2\": b\"bytes2\",\n                \"string3\": b\"bytes3\",\n            },\n            content_dict_str_int={\"string1\": 2, \"string2\": 3, \"string3\": 4},\n            content_dict_str_float={\"string1\": 3.4, \"string2\": 4.7, \"string3\": 4.6},\n            content_dict_str_bool={\"string1\": True, \"string2\": True, \"string3\": False},\n            content_dict_str_str={\n                \"string1\": \"string4\",\n                \"string2\": \"string5\",\n                \"string3\": \"string6\",\n            },\n        )\n\n        encoded_message_in_bytes = TProtocolMessage.serializer.encode(message)\n        decoded_message = cast(\n            TProtocolMessage,\n            TProtocolMessage.serializer.decode(encoded_message_in_bytes),\n        )\n\n        assert decoded_message.message_id == message.message_id\n        assert decoded_message.dialogue_reference == message.dialogue_reference\n        assert decoded_message.dialogue_reference[0] == message.dialogue_reference[0]\n        assert decoded_message.dialogue_reference[1] == message.dialogue_reference[1]\n        assert decoded_message.target == message.target\n        assert decoded_message.performative == message.performative\n        assert decoded_message.content_dict_int_bytes == message.content_dict_int_bytes\n        assert decoded_message.content_dict_int_int == message.content_dict_int_int\n        # assert decoded_message.content_dict_int_float == message.content_dict_int_float # noqa: E800\n        assert decoded_message.content_dict_int_bool == message.content_dict_int_bool\n        assert decoded_message.content_dict_int_str == message.content_dict_int_str\n        assert (\n            decoded_message.content_dict_bool_bytes == message.content_dict_bool_bytes\n        )\n        assert decoded_message.content_dict_bool_int == message.content_dict_bool_int\n        # assert decoded_message.content_dict_bool_float == message.content_dict_bool_float # noqa: E800\n        assert decoded_message.content_dict_bool_bool == message.content_dict_bool_bool\n        assert decoded_message.content_dict_bool_str == message.content_dict_bool_str\n        assert decoded_message.content_dict_str_bytes == message.content_dict_str_bytes\n        assert decoded_message.content_dict_str_int == message.content_dict_str_int\n        # assert decoded_message.content_dict_str_float == message.content_dict_str_float # noqa: E800\n        assert decoded_message.content_dict_str_bool == message.content_dict_str_bool\n        assert decoded_message.content_dict_str_str == message.content_dict_str_str\n\n    def test_generated_protocol_serialisation_mt(self):\n        \"\"\"Test serialisation and deserialisation of a message involving an mt type.\"\"\"\n        some_dict = {1: True, 2: False, 3: True, 4: False}\n\n        def make_data_model(type_):\n            return type_(\n                bytes_field=b\"some bytes\",\n                int_field=42,\n                float_field=42.7,\n                bool_field=True,\n                str_field=\"some string\",\n                set_field={1, 2, 3, 4, 5},\n                list_field=[\"some string 1\", \"some string 2\"],\n                dict_field=some_dict,\n            )\n\n        data_model1 = make_data_model(TProtocolMessage.DataModel1)\n        data_model2 = make_data_model(TProtocolMessage.DataModel2)\n        message_ct = TProtocolMessage(\n            message_id=1,\n            dialogue_reference=(str(0), \"\"),\n            target=0,\n            performative=TProtocolMessage.Performative.PERFORMATIVE_MT,\n            content_union_1=data_model1,\n            content_union_2=frozenset([1, 2, 3]),\n            content_union_3=data_model2,\n        )\n\n        encoded_message_in_bytes = TProtocolMessage.serializer.encode(message_ct)\n        decoded_message = cast(\n            TProtocolMessage,\n            TProtocolMessage.serializer.decode(encoded_message_in_bytes),\n        )\n\n        assert decoded_message.message_id == message_ct.message_id\n        assert decoded_message.dialogue_reference == message_ct.dialogue_reference\n        assert decoded_message.dialogue_reference[0] == message_ct.dialogue_reference[0]\n        assert decoded_message.dialogue_reference[1] == message_ct.dialogue_reference[1]\n        assert decoded_message.target == message_ct.target\n        assert decoded_message.performative == message_ct.performative\n        assert decoded_message.content_union_1 == message_ct.content_union_1\n        assert decoded_message.content_union_2 == message_ct.content_union_2\n\n        #####################\n\n        message_pt_bytes = TProtocolMessage(\n            message_id=1,\n            dialogue_reference=(str(0), \"\"),\n            target=0,\n            performative=TProtocolMessage.Performative.PERFORMATIVE_MT,\n            content_union_1=b\"some bytes\",\n            content_union_2=2,\n        )\n\n        encoded_message_in_bytes = TProtocolMessage.serializer.encode(message_pt_bytes)\n        decoded_message = cast(\n            TProtocolMessage,\n            TProtocolMessage.serializer.decode(encoded_message_in_bytes),\n        )\n\n        assert decoded_message.message_id == message_pt_bytes.message_id\n        assert decoded_message.dialogue_reference == message_pt_bytes.dialogue_reference\n        assert (\n            decoded_message.dialogue_reference[0]\n            == message_pt_bytes.dialogue_reference[0]\n        )\n        assert (\n            decoded_message.dialogue_reference[1]\n            == message_pt_bytes.dialogue_reference[1]\n        )\n        assert decoded_message.target == message_pt_bytes.target\n        assert decoded_message.performative == message_pt_bytes.performative\n        assert decoded_message.content_union_1 == message_pt_bytes.content_union_1\n        assert decoded_message.content_union_2 == message_pt_bytes.content_union_2\n\n        #####################\n\n        message_pt_int = TProtocolMessage(\n            message_id=1,\n            dialogue_reference=(str(0), \"\"),\n            target=0,\n            performative=TProtocolMessage.Performative.PERFORMATIVE_MT,\n            content_union_1=3453,\n            content_union_2=tuple([b\"1\", b\"2\", b\"3\"]),\n        )\n\n        encoded_message_in_bytes = TProtocolMessage.serializer.encode(message_pt_int)\n        decoded_message = cast(\n            TProtocolMessage,\n            TProtocolMessage.serializer.decode(encoded_message_in_bytes),\n        )\n\n        assert decoded_message.message_id == message_pt_int.message_id\n        assert decoded_message.dialogue_reference == message_pt_int.dialogue_reference\n        assert (\n            decoded_message.dialogue_reference[0]\n            == message_pt_int.dialogue_reference[0]\n        )\n        assert (\n            decoded_message.dialogue_reference[1]\n            == message_pt_int.dialogue_reference[1]\n        )\n        assert decoded_message.target == message_pt_int.target\n        assert decoded_message.performative == message_pt_int.performative\n        assert decoded_message.content_union_1 == message_pt_int.content_union_1\n        assert decoded_message.content_union_2 == message_pt_int.content_union_2\n\n        #####################\n        # float does not decoded properly\n        \"\"\"\n        message_pt_float = TProtocolMessage(\n            message_id=1,\n            dialogue_reference=(str(0), \"\"),\n            target=0,\n            performative=TProtocolMessage.Performative.PERFORMATIVE_MT,\n            content_union_1=34.4,\n        )\n\n        encoded_message_in_bytes = TProtocolMessage.serializer.encode(message_pt_float)\n        decoded_message = cast(\n            TProtocolMessage,\n            TProtocolMessage.serializer.decode(encoded_message_in_bytes),\n        )\n\n        assert decoded_message.message_id == message_pt_float.message_id\n        assert decoded_message.dialogue_reference == message_pt_float.dialogue_reference\n        assert (\n            decoded_message.dialogue_reference[0]\n            == message_pt_float.dialogue_reference[0]\n        )\n        assert (\n            decoded_message.dialogue_reference[1]\n            == message_pt_float.dialogue_reference[1]\n        )\n        assert decoded_message.target == message_pt_float.target\n        assert decoded_message.performative == message_pt_float.performative\n        assert decoded_message.content_union_1 == message_pt_float.content_union_1\n        \"\"\"\n        #####################\n\n        message_pt_bool = TProtocolMessage(\n            message_id=1,\n            dialogue_reference=(str(0), \"\"),\n            target=0,\n            performative=TProtocolMessage.Performative.PERFORMATIVE_MT,\n            content_union_1=True,\n        )\n\n        encoded_message_in_bytes = TProtocolMessage.serializer.encode(message_pt_bool)\n        decoded_message = cast(\n            TProtocolMessage,\n            TProtocolMessage.serializer.decode(encoded_message_in_bytes),\n        )\n\n        assert decoded_message.message_id == message_pt_bool.message_id\n        assert decoded_message.dialogue_reference == message_pt_bool.dialogue_reference\n        assert (\n            decoded_message.dialogue_reference[0]\n            == message_pt_bool.dialogue_reference[0]\n        )\n        assert (\n            decoded_message.dialogue_reference[1]\n            == message_pt_bool.dialogue_reference[1]\n        )\n        assert decoded_message.target == message_pt_bool.target\n        assert decoded_message.performative == message_pt_bool.performative\n        assert decoded_message.content_union_1 == message_pt_bool.content_union_1\n\n        #####################\n\n        message_pt_str = TProtocolMessage(\n            message_id=1,\n            dialogue_reference=(str(0), \"\"),\n            target=0,\n            performative=TProtocolMessage.Performative.PERFORMATIVE_MT,\n            content_union_1=\"some string\",\n        )\n\n        encoded_message_in_bytes = TProtocolMessage.serializer.encode(message_pt_str)\n        decoded_message = cast(\n            TProtocolMessage,\n            TProtocolMessage.serializer.decode(encoded_message_in_bytes),\n        )\n\n        assert decoded_message.message_id == message_pt_str.message_id\n        assert decoded_message.dialogue_reference == message_pt_str.dialogue_reference\n        assert (\n            decoded_message.dialogue_reference[0]\n            == message_pt_str.dialogue_reference[0]\n        )\n        assert (\n            decoded_message.dialogue_reference[1]\n            == message_pt_str.dialogue_reference[1]\n        )\n        assert decoded_message.target == message_pt_str.target\n        assert decoded_message.performative == message_pt_str.performative\n        assert decoded_message.content_union_1 == message_pt_str.content_union_1\n\n        #####################\n        \"\"\"\n        NESTED TYPES AR NOT SUPPORTED\n\n        message_set_int = TProtocolMessage(\n            message_id=1,\n            dialogue_reference=(str(0), \"\"),\n            target=0,\n            performative=TProtocolMessage.Performative.PERFORMATIVE_MT,\n            content_union_1=frozenset([1, 2, 3]),\n        )\n\n        encoded_message_in_bytes = TProtocolMessage.serializer.encode(message_set_int)\n        decoded_message = cast(\n            TProtocolMessage,\n            TProtocolMessage.serializer.decode(encoded_message_in_bytes),\n        )\n\n        assert decoded_message.message_id == message_set_int.message_id\n        assert decoded_message.dialogue_reference == message_set_int.dialogue_reference\n        assert (\n            decoded_message.dialogue_reference[0]\n            == message_set_int.dialogue_reference[0]\n        )\n        assert (\n            decoded_message.dialogue_reference[1]\n            == message_set_int.dialogue_reference[1]\n        )\n        assert decoded_message.target == message_set_int.target\n        assert decoded_message.performative == message_set_int.performative\n        assert decoded_message.content_union_1 == message_set_int.content_union_1\n\n        #####################\n\n        message_list_bool = TProtocolMessage(\n            message_id=1,\n            dialogue_reference=(str(0), \"\"),\n            target=0,\n            performative=TProtocolMessage.Performative.PERFORMATIVE_MT,\n            content_union_1=(True, False, False, True, True),\n        )\n\n        encoded_message_in_bytes = TProtocolMessage.serializer.encode(message_list_bool)\n        decoded_message = cast(\n            TProtocolMessage,\n            TProtocolMessage.serializer.decode(encoded_message_in_bytes),\n        )\n\n        assert decoded_message.message_id == message_list_bool.message_id\n        assert (\n            decoded_message.dialogue_reference == message_list_bool.dialogue_reference\n        )\n        assert (\n            decoded_message.dialogue_reference[0]\n            == message_list_bool.dialogue_reference[0]\n        )\n        assert (\n            decoded_message.dialogue_reference[1]\n            == message_list_bool.dialogue_reference[1]\n        )\n        assert decoded_message.target == message_list_bool.target\n        assert decoded_message.performative == message_list_bool.performative\n        assert decoded_message.content_union_1 == message_list_bool.content_union_1\n\n        #####################\n\n        message_dict_str_int = TProtocolMessage(\n            message_id=1,\n            dialogue_reference=(str(0), \"\"),\n            target=0,\n            performative=TProtocolMessage.Performative.PERFORMATIVE_MT,\n            content_union_1={\"string1\": 2, \"string2\": 3, \"string3\": 4},\n        )\n\n        encoded_message_in_bytes = TProtocolMessage.serializer.encode(\n            message_dict_str_int\n        )\n        decoded_message = cast(\n            TProtocolMessage,\n            TProtocolMessage.serializer.decode(encoded_message_in_bytes),\n        )\n\n        assert decoded_message.message_id == message_dict_str_int.message_id\n        assert (\n            decoded_message.dialogue_reference\n            == message_dict_str_int.dialogue_reference\n        )\n        assert (\n            decoded_message.dialogue_reference[0]\n            == message_dict_str_int.dialogue_reference[0]\n        )\n        assert (\n            decoded_message.dialogue_reference[1]\n            == message_dict_str_int.dialogue_reference[1]\n        )\n        assert decoded_message.target == message_dict_str_int.target\n        assert decoded_message.performative == message_dict_str_int.performative\n        assert decoded_message.content_union_1 == message_dict_str_int.content_union_1\n        \"\"\"\n\n    def test_generated_protocol_serialisation_o(self):\n        \"\"\"Test serialisation and deserialisation of a message involving an optional type.\"\"\"\n        some_dict = {1: True, 2: False, 3: True, 4: False}\n        data_model = TProtocolMessage.DataModel4(\n            bytes_field=b\"some bytes\",\n            int_field=42,\n            float_field=42.7,\n            bool_field=True,\n            str_field=\"some string\",\n            set_field={1, 2, 3, 4, 5},\n            list_field=[\"some string 1\", \"some string 2\"],\n            dict_field=some_dict,\n        )\n        message_o_ct_set = TProtocolMessage(\n            message_id=1,\n            dialogue_reference=(str(0), \"\"),\n            target=0,\n            performative=TProtocolMessage.Performative.PERFORMATIVE_O,\n            content_o_ct=data_model,\n        )\n\n        encoded_message_in_bytes = TProtocolMessage.serializer.encode(message_o_ct_set)\n        decoded_message = cast(\n            TProtocolMessage,\n            TProtocolMessage.serializer.decode(encoded_message_in_bytes),\n        )\n\n        assert decoded_message.message_id == message_o_ct_set.message_id\n        assert decoded_message.dialogue_reference == message_o_ct_set.dialogue_reference\n        assert (\n            decoded_message.dialogue_reference[0]\n            == message_o_ct_set.dialogue_reference[0]\n        )\n        assert (\n            decoded_message.dialogue_reference[1]\n            == message_o_ct_set.dialogue_reference[1]\n        )\n        assert decoded_message.target == message_o_ct_set.target\n        assert decoded_message.performative == message_o_ct_set.performative\n        assert decoded_message.content_o_ct == message_o_ct_set.content_o_ct\n\n        #####################\n\n        message_o_ct_not_set = TProtocolMessage(\n            message_id=1,\n            dialogue_reference=(str(0), \"\"),\n            target=0,\n            performative=TProtocolMessage.Performative.PERFORMATIVE_O,\n        )\n\n        encoded_message_in_bytes = TProtocolMessage.serializer.encode(\n            message_o_ct_not_set\n        )\n        decoded_message = cast(\n            TProtocolMessage,\n            TProtocolMessage.serializer.decode(encoded_message_in_bytes),\n        )\n\n        assert decoded_message.message_id == message_o_ct_not_set.message_id\n        assert (\n            decoded_message.dialogue_reference\n            == message_o_ct_not_set.dialogue_reference\n        )\n        assert (\n            decoded_message.dialogue_reference[0]\n            == message_o_ct_not_set.dialogue_reference[0]\n        )\n        assert (\n            decoded_message.dialogue_reference[1]\n            == message_o_ct_not_set.dialogue_reference[1]\n        )\n        assert decoded_message.target == message_o_ct_not_set.target\n        assert decoded_message.performative == message_o_ct_not_set.performative\n        assert decoded_message.content_o_ct == message_o_ct_not_set.content_o_ct\n\n        #####################\n\n        message_o_bool_set = TProtocolMessage(\n            message_id=1,\n            dialogue_reference=(str(0), \"\"),\n            target=0,\n            performative=TProtocolMessage.Performative.PERFORMATIVE_O,\n            content_o_bool=True,\n        )\n\n        encoded_message_in_bytes = TProtocolMessage.serializer.encode(\n            message_o_bool_set\n        )\n        decoded_message = cast(\n            TProtocolMessage,\n            TProtocolMessage.serializer.decode(encoded_message_in_bytes),\n        )\n\n        assert decoded_message.message_id == message_o_bool_set.message_id\n        assert (\n            decoded_message.dialogue_reference == message_o_bool_set.dialogue_reference\n        )\n        assert (\n            decoded_message.dialogue_reference[0]\n            == message_o_bool_set.dialogue_reference[0]\n        )\n        assert (\n            decoded_message.dialogue_reference[1]\n            == message_o_bool_set.dialogue_reference[1]\n        )\n        assert decoded_message.target == message_o_bool_set.target\n        assert decoded_message.performative == message_o_bool_set.performative\n        assert decoded_message.content_o_ct == message_o_bool_set.content_o_ct\n\n        #####################\n\n        message_o_bool_not_set = TProtocolMessage(\n            message_id=1,\n            dialogue_reference=(str(0), \"\"),\n            target=0,\n            performative=TProtocolMessage.Performative.PERFORMATIVE_O,\n        )\n\n        encoded_message_in_bytes = TProtocolMessage.serializer.encode(\n            message_o_bool_not_set\n        )\n        decoded_message = cast(\n            TProtocolMessage,\n            TProtocolMessage.serializer.decode(encoded_message_in_bytes),\n        )\n\n        assert decoded_message.message_id == message_o_bool_not_set.message_id\n        assert (\n            decoded_message.dialogue_reference\n            == message_o_bool_not_set.dialogue_reference\n        )\n        assert (\n            decoded_message.dialogue_reference[0]\n            == message_o_bool_not_set.dialogue_reference[0]\n        )\n        assert (\n            decoded_message.dialogue_reference[1]\n            == message_o_bool_not_set.dialogue_reference[1]\n        )\n        assert decoded_message.target == message_o_bool_not_set.target\n        assert decoded_message.performative == message_o_bool_not_set.performative\n        assert decoded_message.content_o_bool == message_o_bool_not_set.content_o_bool\n\n        #####################\n\n        message_o_set_int_set = TProtocolMessage(\n            message_id=1,\n            dialogue_reference=(str(0), \"\"),\n            target=0,\n            performative=TProtocolMessage.Performative.PERFORMATIVE_O,\n            content_o_set_int=frozenset([1, 2, 3]),\n        )\n\n        encoded_message_in_bytes = TProtocolMessage.serializer.encode(\n            message_o_set_int_set\n        )\n        decoded_message = cast(\n            TProtocolMessage,\n            TProtocolMessage.serializer.decode(encoded_message_in_bytes),\n        )\n\n        assert decoded_message.message_id == message_o_set_int_set.message_id\n        assert (\n            decoded_message.dialogue_reference\n            == message_o_set_int_set.dialogue_reference\n        )\n        assert (\n            decoded_message.dialogue_reference[0]\n            == message_o_set_int_set.dialogue_reference[0]\n        )\n        assert (\n            decoded_message.dialogue_reference[1]\n            == message_o_set_int_set.dialogue_reference[1]\n        )\n        assert decoded_message.target == message_o_set_int_set.target\n        assert decoded_message.performative == message_o_set_int_set.performative\n        assert (\n            decoded_message.content_o_set_int == message_o_set_int_set.content_o_set_int\n        )\n\n        #####################\n\n        message_o_set_int_not_set = TProtocolMessage(\n            message_id=1,\n            dialogue_reference=(str(0), \"\"),\n            target=0,\n            performative=TProtocolMessage.Performative.PERFORMATIVE_O,\n        )\n\n        encoded_message_in_bytes = TProtocolMessage.serializer.encode(\n            message_o_set_int_not_set\n        )\n        decoded_message = cast(\n            TProtocolMessage,\n            TProtocolMessage.serializer.decode(encoded_message_in_bytes),\n        )\n\n        assert decoded_message.message_id == message_o_set_int_not_set.message_id\n        assert (\n            decoded_message.dialogue_reference\n            == message_o_set_int_not_set.dialogue_reference\n        )\n        assert (\n            decoded_message.dialogue_reference[0]\n            == message_o_set_int_not_set.dialogue_reference[0]\n        )\n        assert (\n            decoded_message.dialogue_reference[1]\n            == message_o_set_int_not_set.dialogue_reference[1]\n        )\n        assert decoded_message.target == message_o_set_int_not_set.target\n        assert decoded_message.performative == message_o_set_int_not_set.performative\n        assert (\n            decoded_message.content_o_set_int\n            == message_o_set_int_not_set.content_o_set_int\n        )\n\n        #####################\n\n        message_o_list_bytes_set = TProtocolMessage(\n            message_id=1,\n            dialogue_reference=(str(0), \"\"),\n            target=0,\n            performative=TProtocolMessage.Performative.PERFORMATIVE_O,\n            content_o_list_bytes=(b\"bytes1\", b\"bytes2\", b\"bytes3\"),\n        )\n\n        encoded_message_in_bytes = TProtocolMessage.serializer.encode(\n            message_o_list_bytes_set\n        )\n        decoded_message = cast(\n            TProtocolMessage,\n            TProtocolMessage.serializer.decode(encoded_message_in_bytes),\n        )\n\n        assert decoded_message.message_id == message_o_list_bytes_set.message_id\n        assert (\n            decoded_message.dialogue_reference\n            == message_o_list_bytes_set.dialogue_reference\n        )\n        assert (\n            decoded_message.dialogue_reference[0]\n            == message_o_list_bytes_set.dialogue_reference[0]\n        )\n        assert (\n            decoded_message.dialogue_reference[1]\n            == message_o_list_bytes_set.dialogue_reference[1]\n        )\n        assert decoded_message.target == message_o_list_bytes_set.target\n        assert decoded_message.performative == message_o_list_bytes_set.performative\n        assert (\n            decoded_message.content_o_list_bytes\n            == message_o_list_bytes_set.content_o_list_bytes\n        )\n\n        #####################\n\n        message_o_list_bytes_not_set = TProtocolMessage(\n            message_id=1,\n            dialogue_reference=(str(0), \"\"),\n            target=0,\n            performative=TProtocolMessage.Performative.PERFORMATIVE_O,\n        )\n\n        encoded_message_in_bytes = TProtocolMessage.serializer.encode(\n            message_o_list_bytes_not_set\n        )\n        decoded_message = cast(\n            TProtocolMessage,\n            TProtocolMessage.serializer.decode(encoded_message_in_bytes),\n        )\n\n        assert decoded_message.message_id == message_o_list_bytes_not_set.message_id\n        assert (\n            decoded_message.dialogue_reference\n            == message_o_list_bytes_not_set.dialogue_reference\n        )\n        assert (\n            decoded_message.dialogue_reference[0]\n            == message_o_list_bytes_not_set.dialogue_reference[0]\n        )\n        assert (\n            decoded_message.dialogue_reference[1]\n            == message_o_list_bytes_not_set.dialogue_reference[1]\n        )\n        assert decoded_message.target == message_o_list_bytes_not_set.target\n        assert decoded_message.performative == message_o_list_bytes_not_set.performative\n        assert (\n            decoded_message.content_o_list_bytes\n            == message_o_list_bytes_not_set.content_o_list_bytes\n        )\n\n        #####################\n\n        message_o_dict_str_int_set = TProtocolMessage(\n            message_id=1,\n            dialogue_reference=(str(0), \"\"),\n            target=0,\n            performative=TProtocolMessage.Performative.PERFORMATIVE_O,\n            content_o_dict_str_int={\"string1\": 2, \"string2\": 3, \"string3\": 4},\n        )\n\n        encoded_message_in_bytes = TProtocolMessage.serializer.encode(\n            message_o_dict_str_int_set\n        )\n        decoded_message = cast(\n            TProtocolMessage,\n            TProtocolMessage.serializer.decode(encoded_message_in_bytes),\n        )\n\n        assert decoded_message.message_id == message_o_dict_str_int_set.message_id\n        assert (\n            decoded_message.dialogue_reference\n            == message_o_dict_str_int_set.dialogue_reference\n        )\n        assert (\n            decoded_message.dialogue_reference[0]\n            == message_o_dict_str_int_set.dialogue_reference[0]\n        )\n        assert (\n            decoded_message.dialogue_reference[1]\n            == message_o_dict_str_int_set.dialogue_reference[1]\n        )\n        assert decoded_message.target == message_o_dict_str_int_set.target\n        assert decoded_message.performative == message_o_dict_str_int_set.performative\n        assert (\n            decoded_message.content_o_list_bytes\n            == message_o_dict_str_int_set.content_o_list_bytes\n        )\n\n        #####################\n\n        message_o_dict_str_int_not_set = TProtocolMessage(\n            message_id=1,\n            dialogue_reference=(str(0), \"\"),\n            target=0,\n            performative=TProtocolMessage.Performative.PERFORMATIVE_O,\n        )\n\n        encoded_message_in_bytes = TProtocolMessage.serializer.encode(\n            message_o_dict_str_int_not_set\n        )\n        decoded_message = cast(\n            TProtocolMessage,\n            TProtocolMessage.serializer.decode(encoded_message_in_bytes),\n        )\n\n        assert decoded_message.message_id == message_o_dict_str_int_not_set.message_id\n        assert (\n            decoded_message.dialogue_reference\n            == message_o_dict_str_int_not_set.dialogue_reference\n        )\n        assert (\n            decoded_message.dialogue_reference[0]\n            == message_o_dict_str_int_not_set.dialogue_reference[0]\n        )\n        assert (\n            decoded_message.dialogue_reference[1]\n            == message_o_dict_str_int_not_set.dialogue_reference[1]\n        )\n        assert decoded_message.target == message_o_dict_str_int_not_set.target\n        assert (\n            decoded_message.performative == message_o_dict_str_int_not_set.performative\n        )\n        assert (\n            decoded_message.content_o_list_bytes\n            == message_o_dict_str_int_not_set.content_o_list_bytes\n        )\n\n\nclass ProtocolGeneratorTestCase(TestCase):\n    \"\"\"Test for generator/base.py.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Setup class.\"\"\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        os.chdir(cls.t)\n\n    def _mock_config(self):\n        return \"\"\"lint:\n          rules:\n            remove:\n              - MESSAGE_NAMES_UPPER_CAMEL_CASE\n              - ENUM_FIELD_NAMES_ZERO_VALUE_END_WITH\n              - PACKAGE_NAME_LOWER_CASE\n              - REPEATED_FIELD_NAMES_PLURALIZED\n              - FIELD_NAMES_LOWER_SNAKE_CASE\"\"\"\n\n    @mock.patch(\n        \"aea.protocols.generator.base.check_prerequisites\",\n        side_effect=FileNotFoundError(\"Some error!\"),\n    )\n    def test_init_negative_no_prerequisits(self, mocked_check_prerequisites):\n        \"\"\"Negative test for the '__init__' method: check_prerequisites fails.\"\"\"\n        with self.assertRaises(FileNotFoundError) as cm:\n            ProtocolGenerator(PATH_TO_T_PROTOCOL, self.t)\n            expected_msg = \"Some error!\"\n            assert str(cm.exception) == expected_msg\n\n    @mock.patch(\n        \"aea.protocols.generator.base.load_protocol_specification\",\n        side_effect=ValueError(\"Some error!\"),\n    )\n    def test_init_negative_loading_specification_fails(self, mocked_load):\n        \"\"\"Negative test for the '__init__' method: loading the specification fails.\"\"\"\n        with mock.patch(\"aea.protocols.generator.base.check_prerequisites\"):\n            with self.assertRaises(ValueError) as cm:\n                ProtocolGenerator(PATH_TO_T_PROTOCOL, self.t)\n                expected_msg = \"Some error!\"\n                assert str(cm.exception) == expected_msg\n\n    @mock.patch(\n        \"aea.protocols.generator.base.extract\",\n        side_effect=ProtocolSpecificationParseError(\"Some error!\"),\n    )\n    def test_init_negative_extracting_specification_fails(self, mocked_extract):\n        \"\"\"Negative test for the '__init__' method: extracting the specification fails.\"\"\"\n        with mock.patch(\"aea.protocols.generator.base.check_prerequisites\"):\n            p_spec_mock = mock.MagicMock(ProtocolSpecification)\n            p_spec_mock.name = \"some_name\"\n            p_spec_mock.author = \"some_author\"\n            with mock.patch(\n                \"aea.protocols.generator.base.load_protocol_specification\",\n                return_value=p_spec_mock,\n            ):\n                with mock.patch(\n                    \"aea.protocols.generator.base.validate\",\n                    return_value=(True, \"valid!\"),\n                ):\n                    with self.assertRaises(ProtocolSpecificationParseError) as cm:\n                        ProtocolGenerator(\n                            \"some_path_to_protocol_specification\", \"some_path_to_output\"\n                        )\n                        expected_msg = \"Some error!\"\n                        assert str(cm.exception) == expected_msg\n\n    @mock.patch(\n        \"aea.protocols.generator.base.validate\",\n        return_value=(False, \"Some error!\"),\n    )\n    def test_extract_negative_invalid_specification(self, mocked_validate):\n        \"\"\"Negative test the 'extract' method: invalid protocol specification\"\"\"\n        with mock.patch(\"aea.protocols.generator.base.check_prerequisites\"):\n            p_spec_mock = mock.MagicMock(ProtocolSpecification)\n            p_spec_mock.name = \"some_name\"\n            p_spec_mock.author = \"some_author\"\n            with mock.patch(\n                \"aea.protocols.generator.base.load_protocol_specification\",\n                return_value=p_spec_mock,\n            ):\n                with self.assertRaises(ProtocolSpecificationParseError) as cm:\n                    ProtocolGenerator(\n                        \"some_path_to_protocol_specification\", \"some_path_to_output\"\n                    )\n                    expected_msg = \"Some error!\"\n                    assert str(cm.exception) == expected_msg\n\n    def test_change_indent_negative_set_indent_to_negative_value(self):\n        \"\"\"Negative test for the '_change_indent' method: setting indent level to negative value.\"\"\"\n        with mock.patch(\"aea.protocols.generator.base.check_prerequisites\"):\n            p_spec_mock = mock.MagicMock(ProtocolSpecification)\n            p_spec_mock.name = \"some_name\"\n            p_spec_mock.author = \"some_author\"\n            with mock.patch(\n                \"aea.protocols.generator.base.load_protocol_specification\",\n                return_value=p_spec_mock,\n            ):\n                with mock.patch(\n                    \"aea.protocols.generator.base.validate\",\n                    return_value=(True, \"valid!\"),\n                ):\n                    with mock.patch(\"aea.protocols.generator.base.extract\"):\n                        protocol_generator = ProtocolGenerator(\n                            \"some_path_to_protocol_specification\", \"some_path_to_output\"\n                        )\n                        with self.assertRaises(ValueError) as cm:\n                            protocol_generator._change_indent(-1, \"s\")\n                            expected_msg = (\n                                \"Error: setting indent to be a negative number.\"\n                            )\n                            assert str(cm.exception) == expected_msg\n\n    def test_change_indent_negative_decreasing_more_spaces_than_available(self):\n        \"\"\"Negative test for the '_change_indent' method: decreasing more spaces than available.\"\"\"\n        with mock.patch(\"aea.protocols.generator.base.check_prerequisites\"):\n            p_spec_mock = mock.MagicMock(ProtocolSpecification)\n            p_spec_mock.name = \"some_name\"\n            p_spec_mock.author = \"some_author\"\n            with mock.patch(\n                \"aea.protocols.generator.base.load_protocol_specification\",\n                return_value=p_spec_mock,\n            ):\n                with mock.patch(\n                    \"aea.protocols.generator.base.validate\",\n                    return_value=(True, \"valid!\"),\n                ):\n                    with mock.patch(\"aea.protocols.generator.base.extract\"):\n                        protocol_generator = ProtocolGenerator(\n                            \"some_path_to_protocol_specification\", \"some_path_to_output\"\n                        )\n                        protocol_generator.indent = \"    \"\n                        with self.assertRaises(ValueError) as cm:\n                            protocol_generator._change_indent(-2)\n                            expected_msg = (\n                                \"Not enough spaces in the 'indent' variable to remove.\"\n                            )\n                            assert str(cm.exception) == expected_msg\n\n    def test_import_from_custom_types_module_no_custom_types(self):\n        \"\"\"Test the '_import_from_custom_types_module' method: no custom types.\"\"\"\n        with mock.patch(\"aea.protocols.generator.base.check_prerequisites\"):\n            p_spec_mock = mock.MagicMock(ProtocolSpecification)\n            p_spec_mock.name = \"some_name\"\n            p_spec_mock.author = \"some_author\"\n            with mock.patch(\n                \"aea.protocols.generator.base.load_protocol_specification\",\n                return_value=p_spec_mock,\n            ):\n                with mock.patch(\n                    \"aea.protocols.generator.base.validate\",\n                    return_value=(True, \"valid!\"),\n                ):\n                    with mock.patch(\"aea.protocols.generator.base.extract\"):\n                        protocol_generator = ProtocolGenerator(\n                            \"some_path_to_protocol_specification\", \"some_path_to_output\"\n                        )\n                        protocol_generator.spec.all_custom_types = []\n                        assert (\n                            protocol_generator._import_from_custom_types_module() == \"\"\n                        )\n\n    def test_protocol_buffer_schema_str(self):\n        \"\"\"Negative test for the '_protocol_buffer_schema_str' method: 1 line protobuf snippet.\"\"\"\n        with mock.patch(\"aea.protocols.generator.base.check_prerequisites\"):\n            p_spec_mock = mock.MagicMock(ProtocolSpecification)\n            p_spec_mock.name = \"some_name\"\n            p_spec_mock.author = \"some_author\"\n            p_spec_mock.protocol_specification_id = PublicId(\n                \"some_author\", \"some_protocol_name\", \"0.1.0\"\n            )\n\n            with mock.patch(\n                \"aea.protocols.generator.base.load_protocol_specification\",\n                return_value=p_spec_mock,\n            ):\n                with mock.patch(\n                    \"aea.protocols.generator.base.validate\",\n                    return_value=(True, \"valid!\"),\n                ):\n                    with mock.patch(\"aea.protocols.generator.base.extract\"):\n                        protocol_generator = ProtocolGenerator(\n                            \"some_path_to_protocol_specification\", \"some_path_to_output\"\n                        )\n                        protocol_generator.spec.all_custom_types = [\"SomeCustomType\"]\n                        protocol_generator.protocol_specification.protobuf_snippets = {\n                            \"ct:SomeCustomType\": \"bytes description = 1;\"\n                        }\n                        proto_buff_schema_str = (\n                            protocol_generator._protocol_buffer_schema_str()\n                        )\n                        print(proto_buff_schema_str)\n                        expected = (\n                            'syntax = \"proto3\";\\n\\n'\n                            \"package aea.some_author.some_protocol_name.v0_1_0;\\n\\n\"\n                            \"message SomeNameMessage{\\n\\n\"\n                            \"    // Custom Types\\n\"\n                            \"    message SomeCustomType{\\n\"\n                            \"        bytes description = 1;    }\\n\\n\\n\"\n                            \"    // Performatives and contents\\n\\n\"\n                            \"    oneof performative{\\n\"\n                            \"    }\\n\"\n                            \"}\\n\"\n                        )\n                        assert proto_buff_schema_str == expected\n\n    def test_generate_protobuf_only_mode_positive_python(self):\n        \"\"\"Positive test for the 'generate_protobuf_only_mode' where language is Python.\"\"\"\n        protocol_generator = ProtocolGenerator(PATH_TO_T_PROTOCOL_SPECIFICATION, self.t)\n        protocol_generator.generate_protobuf_only_mode()\n        path_to_protobuf_schema_file = os.path.join(\n            self.t, T_PROTOCOL_NAME, T_PROTOCOL_NAME + \".proto\"\n        )\n        path_to_protobuf_python_implementation = os.path.join(\n            self.t, T_PROTOCOL_NAME, T_PROTOCOL_NAME + \"_pb2.py\"\n        )\n        assert Path(path_to_protobuf_schema_file).exists()\n        assert Path(path_to_protobuf_python_implementation).exists()\n\n    def test_generate_protobuf_only_mode_positive_cpp(self):\n        \"\"\"Positive test for the 'generate_protobuf_only_mode' where language is C++.\"\"\"\n        protocol_generator = ProtocolGenerator(PATH_TO_T_PROTOCOL_SPECIFICATION, self.t)\n        protocol_generator.generate_protobuf_only_mode(language=\"cpp\")\n        path_to_protobuf_schema_file = os.path.join(\n            self.t, T_PROTOCOL_NAME, T_PROTOCOL_NAME + \".proto\"\n        )\n        path_to_protobuf_cpp_headers = os.path.join(\n            self.t, T_PROTOCOL_NAME, T_PROTOCOL_NAME + \".pb.h\"\n        )\n        path_to_protobuf_cpp_implementation = os.path.join(\n            self.t, T_PROTOCOL_NAME, T_PROTOCOL_NAME + \".pb.cc\"\n        )\n        assert Path(path_to_protobuf_schema_file).exists()\n        assert Path(path_to_protobuf_cpp_headers).exists()\n        assert Path(path_to_protobuf_cpp_implementation).exists()\n\n    def test_generate_protobuf_only_mode_positive_java(self):\n        \"\"\"Positive test for the 'generate_protobuf_only_mode' where language is Java.\"\"\"\n        protocol_generator = ProtocolGenerator(PATH_TO_T_PROTOCOL_SPECIFICATION, self.t)\n        protocol_generator.generate_protobuf_only_mode(language=\"java\")\n        path_to_protobuf_schema_file = os.path.join(\n            self.t, T_PROTOCOL_NAME, T_PROTOCOL_NAME + \".proto\"\n        )\n        assert Path(path_to_protobuf_schema_file).exists()\n\n        java_implementation_exists = False\n        for _, _, files in os.walk(os.path.join(self.t, T_PROTOCOL_NAME)):\n            for file in files:  # loops through directories and files\n                if file == _to_camel_case(T_PROTOCOL_NAME) + \".java\":\n                    java_implementation_exists = True\n                    break\n\n        assert java_implementation_exists\n\n    def test_generate_protobuf_only_mode_positive_csharp(self):\n        \"\"\"Positive test for the 'generate_protobuf_only_mode' where language is C#.\"\"\"\n        protocol_generator = ProtocolGenerator(PATH_TO_T_PROTOCOL_SPECIFICATION, self.t)\n        protocol_generator.generate_protobuf_only_mode(language=\"csharp\")\n        path_to_protobuf_schema_file = os.path.join(\n            self.t, T_PROTOCOL_NAME, T_PROTOCOL_NAME + \".proto\"\n        )\n        path_to_protobuf_csharp_implementation = os.path.join(\n            self.t, T_PROTOCOL_NAME, _to_camel_case(T_PROTOCOL_NAME) + \".cs\"\n        )\n        assert Path(path_to_protobuf_schema_file).exists()\n        assert Path(path_to_protobuf_csharp_implementation).exists()\n\n    def test_generate_protobuf_only_mode_positive_ruby(self):\n        \"\"\"Positive test for the 'generate_protobuf_only_mode' where language is Ruby.\"\"\"\n        protocol_generator = ProtocolGenerator(PATH_TO_T_PROTOCOL_SPECIFICATION, self.t)\n        protocol_generator.generate_protobuf_only_mode(language=\"ruby\")\n        path_to_protobuf_schema_file = os.path.join(\n            self.t, T_PROTOCOL_NAME, T_PROTOCOL_NAME + \".proto\"\n        )\n        path_to_protobuf_ruby_implementation = os.path.join(\n            self.t, T_PROTOCOL_NAME, T_PROTOCOL_NAME + \"_pb.rb\"\n        )\n        assert Path(path_to_protobuf_schema_file).exists()\n        assert Path(path_to_protobuf_ruby_implementation).exists()\n\n    def test_generate_protobuf_only_mode_positive_objc(self):\n        \"\"\"Positive test for the 'generate_protobuf_only_mode' where language is objective-c.\"\"\"\n        protocol_generator = ProtocolGenerator(PATH_TO_T_PROTOCOL_SPECIFICATION, self.t)\n        protocol_generator.generate_protobuf_only_mode(language=\"objc\")\n        path_to_protobuf_schema_file = os.path.join(\n            self.t, T_PROTOCOL_NAME, T_PROTOCOL_NAME + \".proto\"\n        )\n        path_to_protobuf_objc_headers = os.path.join(\n            self.t, T_PROTOCOL_NAME, _to_camel_case(T_PROTOCOL_NAME) + \".pbobjc.h\"\n        )\n        path_to_protobuf_objc_implementation = os.path.join(\n            self.t, T_PROTOCOL_NAME, _to_camel_case(T_PROTOCOL_NAME) + \".pbobjc.m\"\n        )\n        assert Path(path_to_protobuf_schema_file).exists()\n        assert Path(path_to_protobuf_objc_headers).exists()\n        assert Path(path_to_protobuf_objc_implementation).exists()\n\n    def test_generate_protobuf_only_mode_positive_js(self):\n        \"\"\"Positive test for the 'generate_protobuf_only_mode' where language is JS.\"\"\"\n        protocol_generator = ProtocolGenerator(PATH_TO_T_PROTOCOL_SPECIFICATION, self.t)\n        protocol_generator.generate_protobuf_only_mode(language=\"js\")\n        path_to_protobuf_schema_file = os.path.join(\n            self.t, T_PROTOCOL_NAME, T_PROTOCOL_NAME + \".proto\"\n        )\n        path_to_protobuf_js_implementation = os.path.join(\n            self.t, T_PROTOCOL_NAME, T_PROTOCOL_NAME + \"_pb.js\"\n        )\n        assert Path(path_to_protobuf_schema_file).exists()\n        assert Path(path_to_protobuf_js_implementation).exists()\n\n    def test_generate_protobuf_only_mode_negative_incorrect_language(self):\n        \"\"\"Negative test for the 'generate_protobuf_only_mode' method: invalid language.\"\"\"\n        invalid_language = \"wrong_language\"\n        protocol_generator = ProtocolGenerator(PATH_TO_T_PROTOCOL_SPECIFICATION, self.t)\n        with self.assertRaises(ValueError) as cm:\n            protocol_generator.generate_protobuf_only_mode(language=invalid_language)\n            expected_msg = f\"Unsupported language. Expected one of {SUPPORTED_PROTOCOL_LANGUAGES}. Found {invalid_language}.\"\n            assert str(cm.exception) == expected_msg\n\n    @mock.patch(\n        \"aea.protocols.generator.base.compile_protobuf_using_protoc\",\n        return_value=(False, \"Some error!\"),\n    )\n    def test_generate_protobuf_only_mode_negative_compile_fails(\n        self, mocked_compile_protobuf\n    ):\n        \"\"\"Negative test for the 'generate_protobuf_only_mode' method: compiling protobuf schema file fails\"\"\"\n        protocol_generator = ProtocolGenerator(PATH_TO_T_PROTOCOL_SPECIFICATION, self.t)\n        with self.assertRaises(SyntaxError) as cm:\n            protocol_generator.generate_protobuf_only_mode()\n            expected_msg = (\n                \"Error when trying to compile the protocol buffer schema file:\\n\"\n                + \"Some error!\"\n            )\n            assert str(cm.exception) == expected_msg\n\n        path_to_protobuf_file = os.path.join(\n            self.t, T_PROTOCOL_NAME, T_PROTOCOL_NAME + \".proto\"\n        )\n        assert not Path(path_to_protobuf_file).exists()\n\n    @mock.patch(\n        \"aea.protocols.generator.base.apply_protolint\",\n        return_value=(False, \"error line 1\\nerror line 2\"),\n    )\n    def test_generate_protobuf_only_mode_protolint_error(self, mocked_apply_protolint):\n        \"\"\"Positive test for the 'generate_protobuf_only_mode' where protolint has some error.\"\"\"\n        protocol_generator = ProtocolGenerator(PATH_TO_T_PROTOCOL_SPECIFICATION, self.t)\n        output = protocol_generator.generate_protobuf_only_mode()\n        expected_output = \"Protolint warnings:\\n\" + \"error line 1\\nerror line 2\"\n        assert output == expected_output\n\n    def test_generate_full_mode_negative_incorrect_language(self):\n        \"\"\"Negative test for the 'generate_protobuf_only_mode' method: invalid language.\"\"\"\n        invalid_language = \"wrong_language\"\n        protocol_generator = ProtocolGenerator(PATH_TO_T_PROTOCOL_SPECIFICATION, self.t)\n        with self.assertRaises(ValueError) as cm:\n            protocol_generator.generate_full_mode(language=invalid_language)\n            expected_msg = f\"Unsupported language. Expected 'python' because currently the framework supports full generation of protocols only in Python. Found {invalid_language}.\"\n            assert str(cm.exception) == expected_msg\n\n    @mock.patch(\n        \"aea.protocols.generator.base.apply_protolint\",\n        return_value=(False, \"error line 1\\nerror line 2\"),\n    )\n    def test_generate_full_mode_protolint_error(self, mocked_apply_protolint):\n        \"\"\"Positive test for the 'generate_full_mode' where protolint has some error.\"\"\"\n        protocol_generator = ProtocolGenerator(PATH_TO_T_PROTOCOL_SPECIFICATION, self.t)\n        output = protocol_generator.generate_full_mode(\"python\")\n        expected_output = (\n            \"Protolint warnings:\\n\"\n            + \"error line 1\\nerror line 2\"\n            + \"The generated protocol is incomplete, because the protocol specification contains the following custom types: \"\n            + \"{}. Update the generated '{}' file with the appropriate implementations of these custom types.\".format(\n                protocol_generator.spec.all_custom_types, CUSTOM_TYPES_DOT_PY_FILE_NAME\n            )\n        )\n        assert output == expected_output\n\n    @mock.patch(\n        \"aea.protocols.generator.base.ProtocolGenerator.generate_protobuf_only_mode\"\n    )\n    @mock.patch(\"aea.protocols.generator.base.ProtocolGenerator.generate_full_mode\")\n    def test_generate_1(self, mocked_full_mode, mocked_protobuf_mode):\n        \"\"\"Test the 'generate' method: protobuf_only mode\"\"\"\n        protocol_generator = ProtocolGenerator(PATH_TO_T_PROTOCOL_SPECIFICATION, self.t)\n        protocol_generator.generate(protobuf_only=True)\n        mocked_protobuf_mode.assert_called_once()\n        mocked_full_mode.assert_not_called()\n\n    @mock.patch(\n        \"aea.protocols.generator.base.ProtocolGenerator.generate_protobuf_only_mode\"\n    )\n    @mock.patch(\"aea.protocols.generator.base.ProtocolGenerator.generate_full_mode\")\n    def test_generate_2(self, mocked_full_mode, mocked_protobuf_mode):\n        \"\"\"Test the 'generate' method: full mode\"\"\"\n        protocol_generator = ProtocolGenerator(PATH_TO_T_PROTOCOL_SPECIFICATION, self.t)\n        protocol_generator.generate(protobuf_only=False)\n        mocked_protobuf_mode.assert_not_called()\n        mocked_full_mode.assert_called_once()\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n"
  },
  {
    "path": "tests/test_aea/test_protocols/test_generator/test_validate.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests for generator/validate.py module.\"\"\"\nimport logging\nfrom unittest import TestCase, mock\n\nfrom aea.configurations.base import CRUDCollection, SpeechActContentConfig\nfrom aea.protocols.generator.validate import (\n    CONTENT_NAME_REGEX_PATTERN,\n    END_STATE_REGEX_PATTERN,\n    PERFORMATIVE_REGEX_PATTERN,\n    ROLE_REGEX_PATTERN,\n    _has_brackets,\n    _is_reserved_name,\n    _is_valid_content_type_format,\n    _is_valid_ct,\n    _is_valid_dict,\n    _is_valid_list,\n    _is_valid_optional,\n    _is_valid_pt,\n    _is_valid_regex,\n    _is_valid_set,\n    _is_valid_union,\n    _validate_content_name,\n    _validate_content_type,\n    _validate_dialogue_section,\n    _validate_end_states,\n    _validate_field_existence,\n    _validate_initiation,\n    _validate_keep_terminal,\n    _validate_performatives,\n    _validate_protocol_buffer_schema_code_snippets,\n    _validate_reply,\n    _validate_roles,\n    _validate_speech_acts_section,\n    _validate_termination,\n    validate,\n)\n\n\nlogger = logging.getLogger(\"aea\")\nlogging.basicConfig(level=logging.INFO)\n\n\nclass TestValidate(TestCase):\n    \"\"\"Test for generator/validate.py.\"\"\"\n\n    def test_is_reserved_name(self):\n        \"\"\"Test for the '_is_reserved_name' method.\"\"\"\n        invalid_content_name_1 = \"_body\"\n        assert _is_reserved_name(invalid_content_name_1) is True\n\n        invalid_content_name_2 = \"message_id\"\n        assert _is_reserved_name(invalid_content_name_2) is True\n\n        invalid_content_name_3 = \"dialogue_reference\"\n        assert _is_reserved_name(invalid_content_name_3) is True\n\n        invalid_content_name_4 = \"target\"\n        assert _is_reserved_name(invalid_content_name_4) is True\n\n        invalid_content_name_5 = \"performative\"\n        assert _is_reserved_name(invalid_content_name_5) is True\n\n        valid_content_nam_1 = \"content_name\"\n        assert _is_reserved_name(valid_content_nam_1) is False\n\n        valid_content_name_2 = \"query\"\n        assert _is_reserved_name(valid_content_name_2) is False\n\n        valid_content_name_3 = \"ThiSiSAConTEnT234\"\n        assert _is_reserved_name(valid_content_name_3) is False\n\n    def test_is_valid_regex(self):\n        \"\"\"Test for the '_is_valid_regex' method.\"\"\"\n        regex_1 = \"^[0-9][a-zA-Z0-9]*[A-Z]$\"\n\n        valid_text_1 = \"53453hKb35nDkG\"\n        assert _is_valid_regex(regex_1, valid_text_1) is True\n\n        invalid_text_1 = \"hKbnDkG\"\n        assert _is_valid_regex(regex_1, invalid_text_1) is False\n\n        invalid_text_2 = \"4f nkG\"\n        assert _is_valid_regex(regex_1, invalid_text_2) is False\n\n    def test_has_brackets(self):\n        \"\"\"Test for the '_has_brackets' method.\"\"\"\n        valid_content_type_1 = \"pt:set[pt:int]\"\n        assert _has_brackets(valid_content_type_1) is True\n\n        valid_content_type_2 = \"pt:union[hskdjf-8768&^${]hsdkjhfk]\"\n        assert _has_brackets(valid_content_type_2) is True\n\n        valid_content_type_3 = \"pt:optional[[]]\"\n        assert _has_brackets(valid_content_type_3) is True\n\n        ###################################################\n\n        invalid_content_type_1 = \"ct:set[pt:int]\"\n        with self.assertRaises(SyntaxError) as cm:\n            _has_brackets(invalid_content_type_1)\n        self.assertEqual(\n            str(cm.exception), \"Content type must be a compositional type!\"\n        )\n\n        invalid_content_type_2 = \"pt:tuple[pt:float]\"\n        with self.assertRaises(SyntaxError) as cm:\n            _has_brackets(invalid_content_type_2)\n        self.assertEqual(\n            str(cm.exception), \"Content type must be a compositional type!\"\n        )\n\n        invalid_content_type_3 = \"pt:optinal[pt:bool]\"\n        with self.assertRaises(SyntaxError) as cm:\n            _has_brackets(invalid_content_type_3)\n        self.assertEqual(\n            str(cm.exception), \"Content type must be a compositional type!\"\n        )\n\n        ###################################################\n\n        invalid_content_type_4 = \"pt:optional{}\"\n        assert _has_brackets(invalid_content_type_4) is False\n\n        invalid_content_type_5 = \"pt:set[]7657\"\n        assert _has_brackets(invalid_content_type_5) is False\n\n        invalid_content_type_6 = \"pt:union [pt:int, pt:bool]\"\n        assert _has_brackets(invalid_content_type_6) is False\n\n        invalid_content_type_7 = \"pt:dict[pt:int, pt:bool] \"\n        assert _has_brackets(invalid_content_type_7) is False\n\n    def test_is_valid_ct(self):\n        \"\"\"Test for the '_is_valid_ct' method.\"\"\"\n        valid_content_type_1 = \"ct:DataModel\"\n        assert _is_valid_ct(valid_content_type_1) is True\n\n        valid_content_type_2 = \"ct:ThisIsACustomContent\"\n        assert _is_valid_ct(valid_content_type_2) is True\n\n        valid_content_type_3 = \"ct:Query\"\n        assert _is_valid_ct(valid_content_type_3) is True\n\n        valid_content_type_4 = \"   ct:Proposal \"\n        assert _is_valid_ct(valid_content_type_4) is True\n\n        valid_content_type_5 = \"ct:DSA\"\n        assert _is_valid_ct(valid_content_type_5) is True\n\n        valid_content_type_6 = \"ct:DataF\"\n        assert _is_valid_ct(valid_content_type_6) is True\n\n        valid_content_type_7 = \"ct:DataModel2\"\n        assert _is_valid_ct(valid_content_type_7) is True\n\n        ###################################################\n\n        invalid_content_type_1 = \"ct:data\"\n        assert _is_valid_ct(invalid_content_type_1) is False\n\n        invalid_content_type_2 = \"Model\"\n        assert _is_valid_ct(invalid_content_type_2) is False\n\n        invalid_content_type_3 = \"ct: DataModel\"\n        assert _is_valid_ct(invalid_content_type_3) is False\n\n    def test_is_valid_pt(self):\n        \"\"\"Test for the '_is_valid_pt' method.\"\"\"\n        valid_content_type_1 = \"pt:bytes\"\n        assert _is_valid_pt(valid_content_type_1) is True\n\n        valid_content_type_2 = \"pt:int\"\n        assert _is_valid_pt(valid_content_type_2) is True\n\n        valid_content_type_3 = \"pt:float\"\n        assert _is_valid_pt(valid_content_type_3) is True\n\n        valid_content_type_4 = \"pt:bool\"\n        assert _is_valid_pt(valid_content_type_4) is True\n\n        valid_content_type_5 = \"pt:str\"\n        assert _is_valid_pt(valid_content_type_5) is True\n\n        valid_content_type_6 = \"  pt:int  \"\n        assert _is_valid_pt(valid_content_type_6) is True\n\n        ###################################################\n\n        invalid_content_type_1 = \"pt:integer\"\n        assert _is_valid_pt(invalid_content_type_1) is False\n\n        invalid_content_type_2 = \"bool\"\n        assert _is_valid_pt(invalid_content_type_2) is False\n\n        invalid_content_type_3 = \"pt: str\"\n        assert _is_valid_pt(invalid_content_type_3) is False\n\n        invalid_content_type_4 = \"pt;float\"\n        assert _is_valid_pt(invalid_content_type_4) is False\n\n    def test_is_valid_set(self):\n        \"\"\"Test for the '_is_valid_set' method.\"\"\"\n        valid_content_type_1 = \"pt:set[pt:bytes]\"\n        assert _is_valid_set(valid_content_type_1) is True\n\n        valid_content_type_2 = \"pt:set[pt:int]\"\n        assert _is_valid_set(valid_content_type_2) is True\n\n        valid_content_type_3 = \"pt:set[pt:float]\"\n        assert _is_valid_set(valid_content_type_3) is True\n\n        valid_content_type_4 = \"pt:set[pt:bool]\"\n        assert _is_valid_set(valid_content_type_4) is True\n\n        valid_content_type_5 = \"pt:set[pt:str]\"\n        assert _is_valid_set(valid_content_type_5) is True\n\n        valid_content_type_6 = \" pt:set[   pt:int ]   \"\n        assert _is_valid_set(valid_content_type_6) is True\n\n        ###################################################\n\n        invalid_content_type_1 = \"pt:frozenset[pt:int]\"\n        assert _is_valid_set(invalid_content_type_1) is False\n\n        invalid_content_type_2 = \"set[pt:int]\"\n        assert _is_valid_set(invalid_content_type_2) is False\n\n        invalid_content_type_3 = \"pt: set[pt:int]\"\n        assert _is_valid_set(invalid_content_type_3) is False\n\n        invalid_content_type_4 = \"pt:set[integer]\"\n        assert _is_valid_set(invalid_content_type_4) is False\n\n        invalid_content_type_5 = \"pt:set[int]\"\n        assert _is_valid_set(invalid_content_type_5) is False\n\n        invalid_content_type_6 = \"pt:set{int]\"\n        assert _is_valid_set(invalid_content_type_6) is False\n\n        invalid_content_type_7 = \"pt:set[pt:int, pt:str]\"\n        assert _is_valid_set(invalid_content_type_7) is False\n\n        invalid_content_type_8 = \"pt:set[]\"\n        assert _is_valid_set(invalid_content_type_8) is False\n\n        invalid_content_type_9 = \"pt:set[pt:list[pt:int, pt:list[pt:bool]]\"\n        assert _is_valid_set(invalid_content_type_9) is False\n\n        invalid_content_type_10 = \"pt:set\"\n        assert _is_valid_set(invalid_content_type_10) is False\n\n    def test_is_valid_list(self):\n        \"\"\"Test for the '_is_valid_list' method.\"\"\"\n        valid_content_type_1 = \"pt:list[pt:bytes]\"\n        assert _is_valid_list(valid_content_type_1) is True\n\n        valid_content_type_2 = \"pt:list[pt:int]\"\n        assert _is_valid_list(valid_content_type_2) is True\n\n        valid_content_type_3 = \"pt:list[pt:float]\"\n        assert _is_valid_list(valid_content_type_3) is True\n\n        valid_content_type_4 = \"pt:list[pt:bool]\"\n        assert _is_valid_list(valid_content_type_4) is True\n\n        valid_content_type_5 = \"pt:list[pt:str]\"\n        assert _is_valid_list(valid_content_type_5) is True\n\n        valid_content_type_6 = \" pt:list[   pt:bool ]   \"\n        assert _is_valid_list(valid_content_type_6) is True\n\n        ###################################################\n\n        invalid_content_type_1 = \"pt:tuple[pt:bytes]\"\n        assert _is_valid_list(invalid_content_type_1) is False\n\n        invalid_content_type_2 = \"list[pt:bool]\"\n        assert _is_valid_list(invalid_content_type_2) is False\n\n        invalid_content_type_3 = \"pt: list[pt:float]\"\n        assert _is_valid_list(invalid_content_type_3) is False\n\n        invalid_content_type_4 = \"pt:list[string]\"\n        assert _is_valid_list(invalid_content_type_4) is False\n\n        invalid_content_type_5 = \"pt:list[bool]\"\n        assert _is_valid_list(invalid_content_type_5) is False\n\n        invalid_content_type_6 = \"pt:list[bytes\"\n        assert _is_valid_list(invalid_content_type_6) is False\n\n        invalid_content_type_7 = \"pt:list[pt:float, pt:bool]\"\n        assert _is_valid_list(invalid_content_type_7) is False\n\n        invalid_content_type_8 = \"pt:list[]\"\n        assert _is_valid_list(invalid_content_type_8) is False\n\n        invalid_content_type_9 = \"pt:list[pt:set[pt:bool, pt:set[pt:str]]\"\n        assert _is_valid_list(invalid_content_type_9) is False\n\n        invalid_content_type_10 = \"pt:list\"\n        assert _is_valid_list(invalid_content_type_10) is False\n\n    def test_is_valid_dict(self):\n        \"\"\"Test for the '_is_valid_dict' method.\"\"\"\n        valid_content_type_1 = \"pt:dict[pt:bytes, pt:int]\"\n        assert _is_valid_dict(valid_content_type_1) is True\n\n        valid_content_type_2 = \"pt:dict[pt:int, pt:int]\"\n        assert _is_valid_dict(valid_content_type_2) is True\n\n        valid_content_type_3 = \"pt:dict[pt:float, pt:str]\"\n        assert _is_valid_dict(valid_content_type_3) is True\n\n        valid_content_type_4 = \"pt:dict[pt:bool, pt:str]\"\n        assert _is_valid_dict(valid_content_type_4) is True\n\n        valid_content_type_5 = \"pt:dict[pt:bool,pt:float]\"\n        assert _is_valid_dict(valid_content_type_5) is True\n\n        valid_content_type_6 = \"   pt:dict[  pt:bytes  ,   pt:int   ] \"\n        assert _is_valid_dict(valid_content_type_6) is True\n\n        ###################################################\n\n        invalid_content_type_1 = \"pt:map[pt:bool, pt:str]\"\n        assert _is_valid_dict(invalid_content_type_1) is False\n\n        invalid_content_type_2 = \"dict[pt:int, pt:float]\"\n        assert _is_valid_dict(invalid_content_type_2) is False\n\n        invalid_content_type_3 = \"pt: dict[pt:bytes, pt:bool]\"\n        assert _is_valid_dict(invalid_content_type_3) is False\n\n        invalid_content_type_4 = \"pt:dict[float, pt:str]\"\n        assert _is_valid_dict(invalid_content_type_4) is False\n\n        invalid_content_type_5 = \"pt:dict[pt:bool, pt:integer]\"\n        assert _is_valid_dict(invalid_content_type_5) is False\n\n        invalid_content_type_6 = \"pt:dict(pt:boolean, pt:int\"\n        assert _is_valid_dict(invalid_content_type_6) is False\n\n        invalid_content_type_7 = \"pt:dict[pt:boolean]\"\n        assert _is_valid_dict(invalid_content_type_7) is False\n\n        invalid_content_type_8 = \"pt:dict[]\"\n        assert _is_valid_dict(invalid_content_type_8) is False\n\n        invalid_content_type_9 = \"pt:dict[pt:str, pt:float, pt:int, pt:bytes]\"\n        assert _is_valid_dict(invalid_content_type_9) is False\n\n        invalid_content_type_10 = \"pt:dict[pt:set[pt:bool, pt:str]\"\n        assert _is_valid_dict(invalid_content_type_10) is False\n\n        invalid_content_type_11 = \"pt:dict\"\n        assert _is_valid_dict(invalid_content_type_11) is False\n\n    def test_is_valid_union(self):\n        \"\"\"Test for the '_is_valid_union' method.\"\"\"\n        valid_content_type_1 = \"pt:union[pt:bytes, pt:int, pt:float, pt:bool, pt:str]\"\n        assert _is_valid_union(valid_content_type_1) is True\n\n        valid_content_type_3 = \"pt:union[pt:float, pt:bool]\"\n        assert _is_valid_union(valid_content_type_3) is True\n\n        valid_content_type_3 = \"pt:union[ct:DataModel, pt:bool]\"\n        assert _is_valid_union(valid_content_type_3) is True\n\n        valid_content_type_3 = \"pt:union[ct:DataModel, ct:DataModel2]\"\n        assert _is_valid_union(valid_content_type_3) is True\n\n        valid_content_type_5 = \"pt:union[pt:bool,pt:bytes]\"\n        assert _is_valid_union(valid_content_type_5) is True\n\n        valid_content_type_4 = \"pt:union[pt:set[pt:int], pt:set[pt:float]]\"\n        assert _is_valid_union(valid_content_type_4) is True\n\n        valid_content_type_6 = \"   pt:union[  pt:bytes  ,   pt:set[  pt:int  ]   ] \"\n        assert _is_valid_union(valid_content_type_6) is True\n\n        valid_content_type_13 = \"pt:union[pt:bytes, pt:set[pt:int]]\"\n        assert _is_valid_union(valid_content_type_13) is True\n\n        ###################################################\n\n        invalid_content_type_1 = \"pt:onion[pt:bool, pt:str]\"\n        assert _is_valid_union(invalid_content_type_1) is False\n\n        invalid_content_type_2 = \"union[pt:int, pt:float]\"\n        assert _is_valid_union(invalid_content_type_2) is False\n\n        invalid_content_type_3 = \"pt: union[pt:set[pt:int], pt:bool]\"\n        assert _is_valid_union(invalid_content_type_3) is False\n\n        invalid_content_type_4 = \"pt:union[float, pt:str\"\n        assert _is_valid_union(invalid_content_type_4) is False\n\n        invalid_content_type_5 = \"pt:union[pt:int, pt:dict[pt:str, pt:bool]\"\n        assert _is_valid_union(invalid_content_type_5) is False\n\n        invalid_content_type_6 = \"pt:union{pt:boolean, pt:int]\"\n        assert _is_valid_union(invalid_content_type_6) is False\n\n        invalid_content_type_7 = \"pt:union[pt:boolean]\"\n        assert _is_valid_union(invalid_content_type_7) is False\n\n        invalid_content_type_8 = \"pt:union[]\"\n        assert _is_valid_union(invalid_content_type_8) is False\n\n        invalid_content_type_9 = \"pt:union[pt:str, pt:int, pt:str]\"\n        assert _is_valid_union(invalid_content_type_9) is False\n\n        invalid_content_type_10 = \"pt:union[pt:set[pt:integer], pt:float]\"\n        assert _is_valid_union(invalid_content_type_10) is False\n\n        invalid_content_type_11 = (\n            \"pt:union[pt:dict[pt:set[pt:bool]], pt:list[pt:set[pt:str]]]\"\n        )\n        assert _is_valid_union(invalid_content_type_11) is False\n\n        invalid_content_type_12 = \"pt:union\"\n        assert _is_valid_union(invalid_content_type_12) is False\n\n    def test_is_valid_optional(self):\n        \"\"\"Test for the '_is_valid_optional' method.\"\"\"\n        valid_content_type_1 = (\n            \"pt:optional[pt:union[pt:bytes, pt:int, pt:float, pt:bool, pt:str]]\"\n        )\n        assert _is_valid_optional(valid_content_type_1) is True\n\n        valid_content_type_2 = \"pt:optional[pt:union[pt:bytes, pt:str]]\"\n        assert _is_valid_optional(valid_content_type_2) is True\n\n        valid_content_type_3 = \"pt:optional[pt:bytes]\"\n        assert _is_valid_optional(valid_content_type_3) is True\n\n        valid_content_type_4 = \"pt:optional[pt:int]\"\n        assert _is_valid_optional(valid_content_type_4) is True\n\n        valid_content_type_5 = \"pt:optional[pt:float]\"\n        assert _is_valid_optional(valid_content_type_5) is True\n\n        valid_content_type_6 = \"pt:optional[pt:bool]\"\n        assert _is_valid_optional(valid_content_type_6) is True\n\n        valid_content_type_7 = \"pt:optional[pt:str]\"\n        assert _is_valid_optional(valid_content_type_7) is True\n\n        valid_content_type_8 = \"pt:optional[pt:set[pt:bytes]]\"\n        assert _is_valid_optional(valid_content_type_8) is True\n\n        valid_content_type_9 = \"pt:optional[pt:list[pt:int]]\"\n        assert _is_valid_optional(valid_content_type_9) is True\n\n        valid_content_type_10 = (\n            \"     pt:optional[  pt:dict[   pt:float   ,  pt:bool ]   ] \"\n        )\n        assert _is_valid_optional(valid_content_type_10) is True\n\n        ###################################################\n\n        invalid_content_type_1 = \"pt:optinal[pt:bytes]\"\n        assert _is_valid_optional(invalid_content_type_1) is False\n\n        invalid_content_type_2 = \"optional[pt:int]\"\n        assert _is_valid_optional(invalid_content_type_2) is False\n\n        invalid_content_type_3 = \"pt: optional[pt:float]\"\n        assert _is_valid_optional(invalid_content_type_3) is False\n\n        invalid_content_type_4 = \"pt:optional[bool]\"\n        assert _is_valid_optional(invalid_content_type_4) is False\n\n        invalid_content_type_5 = \"pt:optional[pt:str\"\n        assert _is_valid_optional(invalid_content_type_5) is False\n\n        invalid_content_type_6 = \"pt:optional{pt:set[pt:int]]\"\n        assert _is_valid_optional(invalid_content_type_6) is False\n\n        invalid_content_type_7 = \"pt:optional[pt:string]\"\n        assert _is_valid_optional(invalid_content_type_7) is False\n\n        invalid_content_type_8 = \"pt:optional[]\"\n        assert _is_valid_optional(invalid_content_type_8) is False\n\n        invalid_content_type_9 = \"pt:optional[pt:str, pt:int, pt:list[pt:bool]]\"\n        assert _is_valid_optional(invalid_content_type_9) is False\n\n        invalid_content_type_10 = \"pt:optional[pt:list[pt:boolean]]\"\n        assert _is_valid_optional(invalid_content_type_10) is False\n\n        invalid_content_type_11 = \"pt:optional[pt:dict[pt:set[pt:int]]]\"\n        assert _is_valid_optional(invalid_content_type_11) is False\n\n        invalid_content_type_12 = \"pt:optional\"\n        assert _is_valid_optional(invalid_content_type_12) is False\n\n    def test_is_valid_content_type_format(self):\n        \"\"\"Test for the '_is_valid_content_type_format' method.\"\"\"\n        valid_content_type_1 = \"ct:DataModel\"\n        assert _is_valid_content_type_format(valid_content_type_1) is True\n\n        valid_content_type_2 = \"pt:int\"\n        assert _is_valid_content_type_format(valid_content_type_2) is True\n\n        valid_content_type_3 = \"pt:set[pt:float]\"\n        assert _is_valid_content_type_format(valid_content_type_3) is True\n\n        valid_content_type_4 = \"pt:list[pt:bool]\"\n        assert _is_valid_content_type_format(valid_content_type_4) is True\n\n        valid_content_type_5 = \"pt:dict[pt:bool,pt:float]\"\n        assert _is_valid_content_type_format(valid_content_type_5) is True\n\n        valid_content_type_6 = (\n            \"pt:optional[pt:union[pt:bytes, pt:int, pt:float, pt:bool, pt:str]]\"\n        )\n        assert _is_valid_content_type_format(valid_content_type_6) is True\n\n        valid_content_type_7 = (\n            \"     pt:optional[  pt:dict[   pt:float   ,  pt:bool ]   ] \"\n        )\n        assert _is_valid_content_type_format(valid_content_type_7) is True\n\n        ###################################################\n\n        invalid_content_type_1 = \"ct:data\"\n        assert _is_valid_content_type_format(invalid_content_type_1) is False\n\n        invalid_content_type_2 = \"bool\"\n        assert _is_valid_content_type_format(invalid_content_type_2) is False\n\n        invalid_content_type_3 = \"pt: set[pt:int]\"\n        assert _is_valid_content_type_format(invalid_content_type_3) is False\n\n        invalid_content_type_4 = \"pt:list[string]\"\n        assert _is_valid_content_type_format(invalid_content_type_4) is False\n\n        invalid_content_type_5 = \"pt:dict[pt:bool, pt:integer]\"\n        assert _is_valid_content_type_format(invalid_content_type_5) is False\n\n        invalid_content_type_6 = \"pt:union{pt:boolean, pt:int]\"\n        assert _is_valid_content_type_format(invalid_content_type_6) is False\n\n        invalid_content_type_7 = \"pt:optional[pt:str, pt:int, pt:list[pt:bool]]\"\n        assert _is_valid_content_type_format(invalid_content_type_7) is False\n\n    def test_validate_performatives(self):\n        \"\"\"Test for the '_validate_performatives' method.\"\"\"\n        valid_content_type_1 = \"offer\"\n        valid_result_1, valid_msg_1 = _validate_performatives(valid_content_type_1)\n        assert valid_result_1 is True\n        assert valid_msg_1 == \"Performative '{}' is valid.\".format(valid_content_type_1)\n\n        valid_content_type_2 = \"send_HTTP_message\"\n        valid_result_2, valid_msg_2 = _validate_performatives(valid_content_type_2)\n        assert valid_result_2 is True\n        assert valid_msg_2 == \"Performative '{}' is valid.\".format(valid_content_type_2)\n\n        valid_content_type_3 = \"request_2PL\"\n        valid_result_3, valid_msg_3 = _validate_performatives(valid_content_type_3)\n        assert valid_result_3 is True\n        assert valid_msg_3 == \"Performative '{}' is valid.\".format(valid_content_type_3)\n\n        valid_content_type_4 = \"argue\"\n        valid_result_4, valid_msg_4 = _validate_performatives(valid_content_type_4)\n        assert valid_result_4 is True\n        assert valid_msg_4 == \"Performative '{}' is valid.\".format(valid_content_type_4)\n\n        ###################################################\n\n        invalid_content_type_1 = \"_offer\"\n        invalid_result_1, invalid_msg_1 = _validate_performatives(\n            invalid_content_type_1\n        )\n        assert invalid_result_1 is False\n        assert (\n            invalid_msg_1\n            == \"Invalid name for performative '{}'. Performative names must match the following regular expression: {} \".format(\n                invalid_content_type_1, PERFORMATIVE_REGEX_PATTERN\n            )\n        )\n\n        invalid_content_type_2 = \"request_\"\n        invalid_result_2, invalid_msg_2 = _validate_performatives(\n            invalid_content_type_2\n        )\n        assert invalid_result_2 is False\n        assert (\n            invalid_msg_2\n            == \"Invalid name for performative '{}'. Performative names must match the following regular expression: {} \".format(\n                invalid_content_type_2, PERFORMATIVE_REGEX_PATTERN\n            )\n        )\n\n        invalid_content_type_3 = \"_query_\"\n        invalid_result_3, invalid_msg_3 = _validate_performatives(\n            invalid_content_type_3\n        )\n        assert invalid_result_3 is False\n        assert (\n            invalid_msg_3\n            == \"Invalid name for performative '{}'. Performative names must match the following regular expression: {} \".format(\n                invalid_content_type_3, PERFORMATIVE_REGEX_PATTERN\n            )\n        )\n\n        invalid_content_type_4 = \"$end\"\n        invalid_result_4, invalid_msg_4 = _validate_performatives(\n            invalid_content_type_4\n        )\n        assert invalid_result_4 is False\n        assert (\n            invalid_msg_4\n            == \"Invalid name for performative '{}'. Performative names must match the following regular expression: {} \".format(\n                invalid_content_type_4, PERFORMATIVE_REGEX_PATTERN\n            )\n        )\n\n        invalid_content_type_5 = \"create()\"\n        invalid_result_5, invalid_msg_5 = _validate_performatives(\n            invalid_content_type_5\n        )\n        assert invalid_result_5 is False\n        assert (\n            invalid_msg_5\n            == \"Invalid name for performative '{}'. Performative names must match the following regular expression: {} \".format(\n                invalid_content_type_5, PERFORMATIVE_REGEX_PATTERN\n            )\n        )\n\n        invalid_content_type_6 = \"_body\"\n        invalid_result_6, invalid_msg_6 = _validate_performatives(\n            invalid_content_type_6\n        )\n        assert invalid_result_6 is False\n        assert (\n            invalid_msg_6\n            == \"Invalid name for performative '{}'. This name is reserved.\".format(\n                invalid_content_type_6,\n            )\n        )\n\n        invalid_content_type_7 = \"message_id\"\n        invalid_result_7, invalid_msg_7 = _validate_performatives(\n            invalid_content_type_7\n        )\n        assert invalid_result_7 is False\n        assert (\n            invalid_msg_6\n            == \"Invalid name for performative '{}'. This name is reserved.\".format(\n                invalid_content_type_6,\n            )\n        )\n\n    def test_validate_content_name(self):\n        \"\"\"Test for the '_validate_content_name' method.\"\"\"\n        performative = \"some_performative\"\n\n        valid_content_type_1 = \"content\"\n        valid_result_1, valid_msg_1 = _validate_content_name(\n            valid_content_type_1, performative\n        )\n        assert valid_result_1 is True\n        assert valid_msg_1 == \"Content name '{}' of performative '{}' is valid.\".format(\n            valid_content_type_1, performative\n        )\n\n        valid_content_type_2 = \"HTTP_msg_name\"\n        valid_result_2, valid_msg_2 = _validate_content_name(\n            valid_content_type_2, performative\n        )\n        assert valid_result_2 is True\n        assert valid_msg_2 == \"Content name '{}' of performative '{}' is valid.\".format(\n            valid_content_type_2, performative\n        )\n\n        valid_content_type_3 = \"number_of_3PLs\"\n        valid_result_3, valid_msg_3 = _validate_content_name(\n            valid_content_type_3, performative\n        )\n        assert valid_result_3 is True\n        assert valid_msg_3 == \"Content name '{}' of performative '{}' is valid.\".format(\n            valid_content_type_3, performative\n        )\n\n        valid_content_type_4 = \"model\"\n        valid_result_4, valid_msg_4 = _validate_content_name(\n            valid_content_type_4, performative\n        )\n        assert valid_result_4 is True\n        assert valid_msg_4 == \"Content name '{}' of performative '{}' is valid.\".format(\n            valid_content_type_4, performative\n        )\n\n        ###################################################\n\n        invalid_content_type_1 = \"_content\"\n        invalid_result_1, invalid_msg_1 = _validate_content_name(\n            invalid_content_type_1, performative\n        )\n        assert invalid_result_1 is False\n        assert (\n            invalid_msg_1\n            == \"Invalid name for content '{}' of performative '{}'. Content names must match the following regular expression: {} \".format(\n                invalid_content_type_1, performative, CONTENT_NAME_REGEX_PATTERN\n            )\n        )\n\n        invalid_content_type_2 = \"content_\"\n        invalid_result_2, invalid_msg_2 = _validate_content_name(\n            invalid_content_type_2, performative\n        )\n        assert invalid_result_2 is False\n        assert (\n            invalid_msg_2\n            == \"Invalid name for content '{}' of performative '{}'. Content names must match the following regular expression: {} \".format(\n                invalid_content_type_2, performative, CONTENT_NAME_REGEX_PATTERN\n            )\n        )\n\n        invalid_content_type_3 = \"_content_\"\n        invalid_result_3, invalid_msg_3 = _validate_content_name(\n            invalid_content_type_3, performative\n        )\n        assert invalid_result_3 is False\n        assert (\n            invalid_msg_3\n            == \"Invalid name for content '{}' of performative '{}'. Content names must match the following regular expression: {} \".format(\n                invalid_content_type_3, performative, CONTENT_NAME_REGEX_PATTERN\n            )\n        )\n\n        invalid_content_type_4 = \"con^en^\"\n        invalid_result_4, invalid_msg_4 = _validate_content_name(\n            invalid_content_type_4, performative\n        )\n        assert invalid_result_4 is False\n        assert (\n            invalid_msg_4\n            == \"Invalid name for content '{}' of performative '{}'. Content names must match the following regular expression: {} \".format(\n                invalid_content_type_4, performative, CONTENT_NAME_REGEX_PATTERN\n            )\n        )\n\n        invalid_content_type_5 = \"some_content()\"\n        invalid_result_5, invalid_msg_5 = _validate_content_name(\n            invalid_content_type_5, performative\n        )\n        assert invalid_result_5 is False\n        assert (\n            invalid_msg_5\n            == \"Invalid name for content '{}' of performative '{}'. Content names must match the following regular expression: {} \".format(\n                invalid_content_type_5, performative, CONTENT_NAME_REGEX_PATTERN\n            )\n        )\n\n        invalid_content_type_6 = \"target\"\n        invalid_result_6, invalid_msg_6 = _validate_content_name(\n            invalid_content_type_6, performative\n        )\n        assert invalid_result_6 is False\n        assert (\n            invalid_msg_6\n            == \"Invalid name for content '{}' of performative '{}'. This name is reserved.\".format(\n                invalid_content_type_6,\n                performative,\n            )\n        )\n\n        invalid_content_type_7 = \"performative\"\n        invalid_result_7, invalid_msg_7 = _validate_content_name(\n            invalid_content_type_7, performative\n        )\n        assert invalid_result_7 is False\n        assert (\n            invalid_msg_7\n            == \"Invalid name for content '{}' of performative '{}'. This name is reserved.\".format(\n                invalid_content_type_7,\n                performative,\n            )\n        )\n\n    def test_validate_content_type(self):\n        \"\"\"Test for the '_validate_content_type' method.\"\"\"\n        performative = \"some_performative\"\n        content_name = \"some_content_name\"\n\n        valid_content_type_1 = \"ct:DataModel\"\n        valid_result_1, valid_msg_1 = _validate_content_type(\n            valid_content_type_1, content_name, performative\n        )\n        assert valid_result_1 is True\n        assert (\n            valid_msg_1\n            == \"Type of content '{}' of performative '{}' is valid.\".format(\n                content_name, performative\n            )\n        )\n\n        valid_content_type_2 = \"pt:int\"\n        valid_result_2, valid_msg_2 = _validate_content_type(\n            valid_content_type_2, content_name, performative\n        )\n        assert valid_result_2 is True\n        assert (\n            valid_msg_2\n            == \"Type of content '{}' of performative '{}' is valid.\".format(\n                content_name, performative\n            )\n        )\n\n        valid_content_type_3 = \"pt:set[pt:float]\"\n        valid_result_3, valid_msg_3 = _validate_content_type(\n            valid_content_type_3, content_name, performative\n        )\n        assert valid_result_3 is True\n        assert (\n            valid_msg_3\n            == \"Type of content '{}' of performative '{}' is valid.\".format(\n                content_name, performative\n            )\n        )\n\n        valid_content_type_4 = \"pt:list[pt:bool]\"\n        valid_result_4, valid_msg_4 = _validate_content_type(\n            valid_content_type_4, content_name, performative\n        )\n        assert valid_result_4 is True\n        assert (\n            valid_msg_4\n            == \"Type of content '{}' of performative '{}' is valid.\".format(\n                content_name, performative\n            )\n        )\n\n        valid_content_type_5 = \"pt:dict[pt:bool,pt:float]\"\n        valid_result_5, valid_msg_5 = _validate_content_type(\n            valid_content_type_5, content_name, performative\n        )\n        assert valid_result_5 is True\n        assert (\n            valid_msg_5\n            == \"Type of content '{}' of performative '{}' is valid.\".format(\n                content_name, performative\n            )\n        )\n\n        valid_content_type_6 = (\n            \"pt:optional[pt:union[pt:bytes, pt:int, pt:float, pt:bool, pt:str]]\"\n        )\n        valid_result_6, valid_msg_6 = _validate_content_type(\n            valid_content_type_6, content_name, performative\n        )\n        assert valid_result_6 is True\n        assert (\n            valid_msg_6\n            == \"Type of content '{}' of performative '{}' is valid.\".format(\n                content_name, performative\n            )\n        )\n\n        valid_content_type_7 = (\n            \"     pt:optional[  pt:dict[   pt:float   ,  pt:bool ]   ] \"\n        )\n        valid_result_7, valid_msg_7 = _validate_content_type(\n            valid_content_type_7, content_name, performative\n        )\n        assert valid_result_7 is True\n        assert (\n            valid_msg_7\n            == \"Type of content '{}' of performative '{}' is valid.\".format(\n                content_name, performative\n            )\n        )\n\n        ###################################################\n\n        invalid_content_type_1 = \"ct:data\"\n        invalid_result_1, invalid_msg_1 = _validate_content_type(\n            invalid_content_type_1, content_name, performative\n        )\n        assert invalid_result_1 is False\n        assert (\n            invalid_msg_1\n            == \"Invalid type for content '{}' of performative '{}'. See documentation for the correct format of specification types.\".format(\n                content_name,\n                performative,\n            )\n        )\n\n        invalid_content_type_2 = \"bool\"\n        invalid_result_2, invalid_msg_2 = _validate_content_type(\n            invalid_content_type_2, content_name, performative\n        )\n        assert invalid_result_2 is False\n        assert (\n            invalid_msg_2\n            == \"Invalid type for content '{}' of performative '{}'. See documentation for the correct format of specification types.\".format(\n                content_name,\n                performative,\n            )\n        )\n\n        invalid_content_type_3 = \"pt: set[pt:int]\"\n        invalid_result_3, invalid_msg_3 = _validate_content_type(\n            invalid_content_type_3, content_name, performative\n        )\n        assert invalid_result_3 is False\n        assert (\n            invalid_msg_3\n            == \"Invalid type for content '{}' of performative '{}'. See documentation for the correct format of specification types.\".format(\n                content_name,\n                performative,\n            )\n        )\n\n        invalid_content_type_4 = \"pt:list[string]\"\n        invalid_result_4, invalid_msg_4 = _validate_content_type(\n            invalid_content_type_4, content_name, performative\n        )\n        assert invalid_result_4 is False\n        assert (\n            invalid_msg_4\n            == \"Invalid type for content '{}' of performative '{}'. See documentation for the correct format of specification types.\".format(\n                content_name,\n                performative,\n            )\n        )\n\n        invalid_content_type_5 = \"pt:dict[pt:bool, pt:integer]\"\n        invalid_result_5, invalid_msg_5 = _validate_content_type(\n            invalid_content_type_5, content_name, performative\n        )\n        assert invalid_result_5 is False\n        assert (\n            invalid_msg_5\n            == \"Invalid type for content '{}' of performative '{}'. See documentation for the correct format of specification types.\".format(\n                content_name,\n                performative,\n            )\n        )\n\n        invalid_content_type_6 = \"pt:union{pt:boolean, pt:int]\"\n        invalid_result_6, invalid_msg_6 = _validate_content_type(\n            invalid_content_type_6, content_name, performative\n        )\n        assert invalid_result_6 is False\n        assert (\n            invalid_msg_6\n            == \"Invalid type for content '{}' of performative '{}'. See documentation for the correct format of specification types.\".format(\n                content_name,\n                performative,\n            )\n        )\n\n        invalid_content_type_7 = \"pt:optional[pt:str, pt:int, pt:list[pt:bool]]\"\n        invalid_result_7, invalid_msg_7 = _validate_content_type(\n            invalid_content_type_7, content_name, performative\n        )\n        assert invalid_result_7 is False\n        assert (\n            invalid_msg_7\n            == \"Invalid type for content '{}' of performative '{}'. See documentation for the correct format of specification types.\".format(\n                content_name,\n                performative,\n            )\n        )\n\n    @mock.patch(\n        \"aea.configurations.base.ProtocolSpecification\",\n    )\n    def test_validate_speech_acts_section(self, mocked_spec):\n        \"\"\"Test for the '_validate_speech_acts_section' method.\"\"\"\n        valid_speech_act_content_config_1 = SpeechActContentConfig(\n            content_1=\"ct:CustomType\", content_2=\"pt:int\"\n        )\n        valid_speech_act_content_config_2 = SpeechActContentConfig(\n            content_3=\"ct:DataModel\"\n        )\n        valid_speech_act_content_config_3 = SpeechActContentConfig()\n\n        speech_act_1 = CRUDCollection()\n        speech_act_1.create(\"perm_1\", valid_speech_act_content_config_1)\n        speech_act_1.create(\"perm_2\", valid_speech_act_content_config_2)\n        speech_act_1.create(\"perm_3\", valid_speech_act_content_config_3)\n\n        mocked_spec.speech_acts = speech_act_1\n\n        (\n            valid_result_1,\n            valid_msg_1,\n            valid_all_per_1,\n            valid_all_content_1,\n        ) = _validate_speech_acts_section(mocked_spec)\n        assert valid_result_1 is True\n        assert valid_msg_1 == \"Speech-acts are valid.\"\n        assert valid_all_per_1 == {\"perm_1\", \"perm_2\", \"perm_3\"}\n        assert valid_all_content_1 == {\"ct:CustomType\", \"ct:DataModel\"}\n\n        ###################################################\n\n        speech_act_3 = CRUDCollection()\n        invalid_perm = \"_query_\"\n        speech_act_3.create(invalid_perm, valid_speech_act_content_config_1)\n\n        mocked_spec.speech_acts = speech_act_3\n\n        (\n            invalid_result_1,\n            invalid_msg_1,\n            invalid_all_per_1,\n            invalid_all_content_1,\n        ) = _validate_speech_acts_section(mocked_spec)\n        assert invalid_result_1 is False\n        assert (\n            invalid_msg_1\n            == \"Invalid name for performative '{}'. Performative names must match the following regular expression: {} \".format(\n                invalid_perm, PERFORMATIVE_REGEX_PATTERN\n            )\n        )\n        assert invalid_all_per_1 is None\n        assert invalid_all_content_1 is None\n\n        invalid_speech_act_content_config_1 = SpeechActContentConfig(target=\"pt:int\")\n        speech_act_4 = CRUDCollection()\n        valid_perm = \"perm_1\"\n        speech_act_4.create(valid_perm, invalid_speech_act_content_config_1)\n\n        mocked_spec.speech_acts = speech_act_4\n\n        (\n            invalid_result_2,\n            invalid_msg_2,\n            invalid_all_per_2,\n            invalid_all_content_2,\n        ) = _validate_speech_acts_section(mocked_spec)\n        assert invalid_result_2 is False\n        assert (\n            invalid_msg_2\n            == \"Invalid name for content '{}' of performative '{}'. This name is reserved.\".format(\n                \"target\",\n                valid_perm,\n            )\n        )\n        assert invalid_all_per_2 is None\n        assert invalid_all_content_2 is None\n\n        invalid_speech_act_content_config_2 = SpeechActContentConfig(\n            content_name_1=\"pt: set[pt:int]\"\n        )\n        speech_act_5 = CRUDCollection()\n        speech_act_5.create(valid_perm, invalid_speech_act_content_config_2)\n\n        mocked_spec.speech_acts = speech_act_5\n\n        (\n            invalid_result_3,\n            invalid_msg_3,\n            invalid_all_per_3,\n            invalid_all_content_3,\n        ) = _validate_speech_acts_section(mocked_spec)\n        assert invalid_result_3 is False\n        assert (\n            invalid_msg_3\n            == \"Invalid type for content 'content_name_1' of performative '{}'. See documentation for the correct format of specification types.\".format(\n                valid_perm,\n            )\n        )\n        assert invalid_all_per_3 is None\n        assert invalid_all_content_3 is None\n\n        speech_act_6 = CRUDCollection()\n        mocked_spec.speech_acts = speech_act_6\n\n        (\n            invalid_result_4,\n            invalid_msg_4,\n            invalid_all_per_4,\n            invalid_all_content_4,\n        ) = _validate_speech_acts_section(mocked_spec)\n        assert invalid_result_4 is False\n        assert invalid_msg_4 == \"Speech-acts cannot be empty!\"\n        assert invalid_all_per_4 is None\n        assert invalid_all_content_4 is None\n\n        invalid_speech_act_content_config_3 = SpeechActContentConfig(content_name_1=123)\n        speech_act_7 = CRUDCollection()\n        speech_act_7.create(valid_perm, invalid_speech_act_content_config_3)\n\n        mocked_spec.speech_acts = speech_act_7\n\n        (\n            invalid_result_5,\n            invalid_msg_5,\n            invalid_all_per_5,\n            invalid_all_content_5,\n        ) = _validate_speech_acts_section(mocked_spec)\n        assert invalid_result_5 is False\n        assert (\n            invalid_msg_5\n            == f\"Invalid type for '{'content_name_1'}'. Expected str. Found {type(123)}.\"\n        )\n        assert invalid_all_per_5 is None\n        assert invalid_all_content_5 is None\n\n        invalid_speech_act_content_config_4 = SpeechActContentConfig(\n            content_name_1=\"pt:int\"\n        )\n        invalid_speech_act_content_config_5 = SpeechActContentConfig(\n            content_name_1=\"pt:float\"\n        )\n        speech_act_8 = CRUDCollection()\n        speech_act_8.create(\"perm_1\", invalid_speech_act_content_config_4)\n        speech_act_8.create(\"perm_2\", invalid_speech_act_content_config_5)\n\n        mocked_spec.speech_acts = speech_act_8\n\n        (\n            invalid_result_6,\n            invalid_msg_6,\n            invalid_all_per_6,\n            invalid_all_content_6,\n        ) = _validate_speech_acts_section(mocked_spec)\n        assert invalid_result_6 is False\n        assert (\n            invalid_msg_6\n            == \"Content 'content_name_1' with type 'pt:float' under performative 'perm_2' is already defined under performative 'perm_1' with a different type ('pt:int').\"\n        )\n        assert invalid_all_per_6 is None\n        assert invalid_all_content_6 is None\n\n    @mock.patch(\n        \"aea.configurations.base.ProtocolSpecification\",\n    )\n    def test_validate_protocol_buffer_schema_code_snippets(self, mocked_spec):\n        \"\"\"Test for the '_validate_protocol_buffer_schema_code_snippets' method.\"\"\"\n        valid_protobuf_snippet_1 = {\n            \"ct:DataModel\": \"bytes bytes_field = 1;\\nint32 int_field = 2;\\nfloat float_field = 3;\\nbool bool_field = 4;\\nstring str_field = 5;\\nrepeated int32 set_field = 6;\\nrepeated string list_field = 7;\\nmap<int32, bool> dict_field = 8;\\n\"\n        }\n        valid_all_content_1 = {\"ct:DataModel\"}\n        mocked_spec.protobuf_snippets = valid_protobuf_snippet_1\n\n        valid_result_1, valid_msg_1, = _validate_protocol_buffer_schema_code_snippets(\n            mocked_spec, valid_all_content_1\n        )\n        assert valid_result_1 is True\n        assert valid_msg_1 == \"Protobuf code snippet section is valid.\"\n\n        valid_protobuf_snippet_2 = {}\n        valid_all_content_2 = set()\n        mocked_spec.protobuf_snippets = valid_protobuf_snippet_2\n\n        valid_result_2, valid_msg_2, = _validate_protocol_buffer_schema_code_snippets(\n            mocked_spec, valid_all_content_2\n        )\n        assert valid_result_2 is True\n        assert valid_msg_2 == \"Protobuf code snippet section is valid.\"\n\n        ###################################################\n\n        invalid_protobuf_snippet_1 = {\n            \"ct:DataModel\": \"bytes bytes_field = 1;\\nint32 int_field = 2;\\nfloat float_field = 3;\\nbool bool_field = 4;\\nstring str_field = 5;\",\n            \"ct:Query\": \"bytes bytes_field = 1;\",\n        }\n        invalid_all_content_1 = {\"ct:DataModel\"}\n        mocked_spec.protobuf_snippets = invalid_protobuf_snippet_1\n\n        (\n            invalid_result_1,\n            invalid_msg_1,\n        ) = _validate_protocol_buffer_schema_code_snippets(\n            mocked_spec, invalid_all_content_1\n        )\n        assert invalid_result_1 is False\n        assert (\n            invalid_msg_1\n            == \"Extra protobuf code snippet provided. Type 'ct:Query' is not used anywhere in your protocol definition.\"\n        )\n\n        invalid_protobuf_snippet_2 = {\n            \"ct:DataModel\": \"bytes bytes_field = 1;\\nint32 int_field = 2;\\nfloat float_field = 3;\",\n        }\n        invalid_all_content_2 = {\"ct:DataModel\", \"ct:Frame\"}\n        mocked_spec.protobuf_snippets = invalid_protobuf_snippet_2\n\n        (\n            invalid_result_2,\n            invalid_msg_2,\n        ) = _validate_protocol_buffer_schema_code_snippets(\n            mocked_spec, invalid_all_content_2\n        )\n        assert invalid_result_2 is False\n        assert (\n            invalid_msg_2\n            == \"No protobuf code snippet is provided for the following custom types: {}\".format(\n                {\"ct:Frame\"},\n            )\n        )\n\n    def test_validate_field_existence(self):\n        \"\"\"Test for the '_validate_field_existence' method.\"\"\"\n        valid_dialogue_config_1 = {\n            \"initiation\": [\"performative_ct\", \"performative_pt\"],\n            \"reply\": {\n                \"performative_ct\": [\"performative_pct\"],\n                \"performative_pt\": [\"performative_pmt\"],\n                \"performative_pct\": [\"performative_mt\", \"performative_o\"],\n                \"performative_pmt\": [\"performative_mt\", \"performative_o\"],\n                \"performative_mt\": [],\n                \"performative_o\": [],\n                \"performative_empty_contents\": [\"performative_empty_contents\"],\n            },\n            \"termination\": [\n                \"performative_mt\",\n                \"performative_o\",\n                \"performative_empty_contents\",\n            ],\n            \"roles\": {\"role_1\": None, \"role_2\": None},\n            \"end_states\": [\"end_state_1\", \"end_state_2\", \"end_state_3\"],\n            \"keep_terminal_state_dialogues\": True,\n        }\n\n        (\n            valid_result_1,\n            valid_msg_1,\n        ) = _validate_field_existence(valid_dialogue_config_1)\n        assert valid_result_1 is True\n        assert valid_msg_1 == \"Dialogue section has all the required fields.\"\n\n        ###################################################\n\n        invalid_dialogue_config_1 = valid_dialogue_config_1.copy()\n        invalid_dialogue_config_1.pop(\"initiation\")\n\n        (\n            invalid_result_1,\n            invalid_msg_1,\n        ) = _validate_field_existence(invalid_dialogue_config_1)\n        assert invalid_result_1 is False\n        assert (\n            invalid_msg_1\n            == \"Missing required field 'initiation' in the dialogue section of the protocol specification.\"\n        )\n\n        invalid_dialogue_config_2 = valid_dialogue_config_1.copy()\n        invalid_dialogue_config_2.pop(\"reply\")\n\n        (\n            invalid_result_2,\n            invalid_msg_2,\n        ) = _validate_field_existence(invalid_dialogue_config_2)\n        assert invalid_result_2 is False\n        assert (\n            invalid_msg_2\n            == \"Missing required field 'reply' in the dialogue section of the protocol specification.\"\n        )\n\n    def test_validate_initiation(self):\n        \"\"\"Test for the '_validate_initiation' method.\"\"\"\n        valid_initiation_1 = [\"perm_1\", \"perm_2\"]\n        valid_performatives_set = {\"perm_1\", \"perm_2\", \"perm_3\", \"perm_4\"}\n        valid_result_1, valid_msg_1 = _validate_initiation(\n            valid_initiation_1, valid_performatives_set\n        )\n        assert valid_result_1 is True\n        assert valid_msg_1 == \"Initial messages are valid.\"\n\n        ###################################################\n\n        invalid_initiation_1 = []\n        invalid_result_1, invalid_msg_1 = _validate_initiation(\n            invalid_initiation_1, valid_performatives_set\n        )\n        assert invalid_result_1 is False\n        assert (\n            invalid_msg_1\n            == \"At least one initial performative for this dialogue must be specified.\"\n        )\n\n        invalid_initiation_2 = [\"perm_5\"]\n        invalid_result_2, invalid_msg_2 = _validate_initiation(\n            invalid_initiation_2, valid_performatives_set\n        )\n        assert invalid_result_2 is False\n        assert (\n            invalid_msg_2\n            == \"Performative 'perm_5' specified in \\\"initiation\\\" is not defined in the protocol's speech-acts.\"\n        )\n\n        invalid_initiation_3 = \"perm_1\"\n        invalid_result_3, invalid_msg_3 = _validate_initiation(\n            invalid_initiation_3, valid_performatives_set\n        )\n        assert invalid_result_3 is False\n        assert (\n            invalid_msg_3\n            == f\"Invalid type for initiation. Expected list. Found '{type(invalid_initiation_3)}'.\"\n        )\n\n    def test_validate_reply(self):\n        \"\"\"Test for the '_validate_reply' method.\"\"\"\n        valid_reply_1 = {\n            \"performative_ct\": [\"performative_pct\"],\n            \"performative_pt\": [\"performative_pmt\"],\n            \"performative_pct\": [\"performative_mt\", \"performative_o\"],\n            \"performative_pmt\": [\"performative_mt\", \"performative_o\"],\n            \"performative_mt\": [],\n            \"performative_o\": [],\n            \"performative_empty_contents\": [\"performative_empty_contents\"],\n        }\n        valid_performatives_set_1 = {\n            \"performative_ct\",\n            \"performative_pt\",\n            \"performative_pct\",\n            \"performative_pmt\",\n            \"performative_mt\",\n            \"performative_o\",\n            \"performative_empty_contents\",\n        }\n\n        (\n            valid_result_1,\n            valid_msg_1,\n            terminal_performatives_from_reply_1,\n        ) = _validate_reply(valid_reply_1, valid_performatives_set_1)\n        assert valid_result_1 is True\n        assert valid_msg_1 == \"Reply structure is valid.\"\n        assert terminal_performatives_from_reply_1 == {\n            \"performative_mt\",\n            \"performative_o\",\n        }\n\n        ###################################################\n\n        invalid_reply_1 = {\n            \"perm_1\": [\"perm_2\"],\n            \"perm_2\": [\"perm_3\"],\n            \"perm_3\": [\"perm_4\"],\n            \"perm_4\": [],\n        }\n        invalid_performatives_set_1 = {\"perm_1\", \"perm_2\", \"perm_3\", \"perm_4\", \"perm_5\"}\n\n        (\n            invalid_result_1,\n            invalid_msg_1,\n            invalid_terminal_performatives_from_reply_1,\n        ) = _validate_reply(invalid_reply_1, invalid_performatives_set_1)\n        assert invalid_result_1 is False\n        assert (\n            invalid_msg_1\n            == \"No reply is provided for the following performatives: {}\".format(\n                {\"perm_5\"},\n            )\n        )\n        assert invalid_terminal_performatives_from_reply_1 is None\n\n        invalid_reply_2 = {\n            \"perm_1\": [\"perm_2\"],\n            \"perm_2\": [\"perm_3\"],\n            \"perm_3\": [\"perm_4\"],\n            \"perm_4\": [\"perm_5\"],\n            \"perm_5\": [],\n        }\n        invalid_performatives_set_2 = {\"perm_1\", \"perm_2\", \"perm_3\", \"perm_4\"}\n        (\n            invalid_result_2,\n            invalid_msg_2,\n            invalid_terminal_performatives_from_reply_2,\n        ) = _validate_reply(invalid_reply_2, invalid_performatives_set_2)\n        assert invalid_result_2 is False\n        assert (\n            invalid_msg_2\n            == \"Performative 'perm_5' in the list of replies for 'perm_4' is not defined in speech-acts.\"\n        )\n        assert invalid_terminal_performatives_from_reply_2 is None\n\n        invalid_reply_3 = [\"perm_1\", \"perm_2\", \"perm_3\", \"perm_4\", \"perm_5\"]\n        (\n            invalid_result_3,\n            invalid_msg_3,\n            invalid_terminal_performatives_from_reply_3,\n        ) = _validate_reply(invalid_reply_3, invalid_performatives_set_1)\n        assert invalid_result_3 is False\n        assert (\n            invalid_msg_3\n            == f\"Invalid type for the reply definition. Expected dict. Found '{type(invalid_reply_3)}'.\"\n        )\n        assert invalid_terminal_performatives_from_reply_3 is None\n\n        invalid_reply_4 = {\n            \"perm_1\": {\"perm_2\"},\n            \"perm_2\": {\"perm_3\"},\n            \"perm_3\": {\"perm_4\"},\n            \"perm_4\": {\"perm_5\"},\n            \"perm_5\": set(),\n        }\n        (\n            invalid_result_4,\n            invalid_msg_4,\n            invalid_terminal_performatives_from_reply_4,\n        ) = _validate_reply(invalid_reply_4, invalid_performatives_set_1)\n        assert invalid_result_4 is False\n        assert (\n            invalid_msg_4\n            == f\"Invalid type for replies of performative perm_1. Expected list. Found '{type({'perm_2'})}'.\"\n        )\n        assert invalid_terminal_performatives_from_reply_4 is None\n\n        invalid_reply_5 = {\n            \"perm_1\": [\"perm_2\"],\n            \"perm_2\": [\"perm_3\"],\n            \"perm_3\": [\"perm_4\"],\n            \"perm_4\": [\"perm_1\"],\n            \"perm_5\": [],\n        }\n        (\n            invalid_result_5,\n            invalid_msg_5,\n            invalid_terminal_performatives_from_reply_5,\n        ) = _validate_reply(invalid_reply_5, invalid_performatives_set_2)\n        assert invalid_result_5 is False\n        assert (\n            invalid_msg_5\n            == \"Performative 'perm_5' specified in \\\"reply\\\" is not defined in the protocol's speech-acts.\"\n        )\n        assert invalid_terminal_performatives_from_reply_5 is None\n\n    def test_validate_termination(self):\n        \"\"\"Test for the '_validate_termination' method.\"\"\"\n        valid_termination_1 = [\"perm_4\", \"perm_3\"]\n        valid_performatives_set = {\"perm_1\", \"perm_2\", \"perm_3\", \"perm_4\"}\n        valid_terminal_performatives_from_reply_1 = {\"perm_4\", \"perm_3\"}\n        valid_result_1, valid_msg_1 = _validate_termination(\n            valid_termination_1,\n            valid_performatives_set,\n            valid_terminal_performatives_from_reply_1,\n        )\n        assert valid_result_1 is True\n        assert valid_msg_1 == \"Terminal messages are valid.\"\n\n        ###################################################\n\n        invalid_termination_1 = []\n        invalid_terminal_performatives_from_reply_1 = set()\n        invalid_result_1, invalid_msg_1 = _validate_termination(\n            invalid_termination_1,\n            valid_performatives_set,\n            invalid_terminal_performatives_from_reply_1,\n        )\n        assert invalid_result_1 is False\n        assert (\n            invalid_msg_1\n            == \"At least one terminal performative for this dialogue must be specified.\"\n        )\n\n        invalid_termination_2 = [\"perm_5\"]\n        invalid_terminal_performatives_from_reply_2 = {\"perm_5\"}\n        invalid_result_2, invalid_msg_2 = _validate_termination(\n            invalid_termination_2,\n            valid_performatives_set,\n            invalid_terminal_performatives_from_reply_2,\n        )\n        assert invalid_result_2 is False\n        assert (\n            invalid_msg_2\n            == \"Performative 'perm_5' specified in \\\"termination\\\" is not defined in the protocol's speech-acts.\"\n        )\n\n        invalid_termination_3 = {\"perm_5\"}\n        invalid_terminal_performatives_from_reply_3 = {\"perm_5\"}\n        invalid_result_3, invalid_msg_3 = _validate_termination(\n            invalid_termination_3,\n            valid_performatives_set,\n            invalid_terminal_performatives_from_reply_3,\n        )\n        assert invalid_result_3 is False\n        assert (\n            invalid_msg_3\n            == f\"Invalid type for termination. Expected list. Found '{type(invalid_termination_3)}'.\"\n        )\n\n        invalid_termination_4 = [\"perm_4\", \"perm_3\", \"perm_4\", \"perm_3\", \"perm_1\"]\n        invalid_terminal_performatives_from_reply_4 = {\"perm_4\", \"perm_3\", \"perm_1\"}\n        invalid_result_4, invalid_msg_4 = _validate_termination(\n            invalid_termination_4,\n            valid_performatives_set,\n            invalid_terminal_performatives_from_reply_4,\n        )\n        assert invalid_result_4 is False\n        assert (\n            invalid_msg_4 == f'There are {2} duplicate performatives in \"termination\".'\n        )\n\n        invalid_termination_5 = [\"perm_4\", \"perm_3\"]\n        invalid_terminal_performatives_from_reply_5 = {\"perm_4\"}\n        invalid_result_5, invalid_msg_5 = _validate_termination(\n            invalid_termination_5,\n            valid_performatives_set,\n            invalid_terminal_performatives_from_reply_5,\n        )\n        assert invalid_result_5 is False\n        assert (\n            invalid_msg_5\n            == 'The terminal performative \\'perm_3\\' specified in \"termination\" is assigned replies in \"reply\".'\n        )\n\n        invalid_termination_6 = [\"perm_4\"]\n        invalid_terminal_performatives_from_reply_6 = {\"perm_4\", \"perm_3\"}\n        invalid_result_6, invalid_msg_6 = _validate_termination(\n            invalid_termination_6,\n            valid_performatives_set,\n            invalid_terminal_performatives_from_reply_6,\n        )\n        assert invalid_result_6 is False\n        assert (\n            invalid_msg_6\n            == \"The performative 'perm_3' has no replies but is not listed as a terminal performative in \\\"termination\\\".\"\n        )\n\n    def test_validate_roles(self):\n        \"\"\"Test for the '_validate_roles' method.\"\"\"\n        valid_roles_1 = {\"role_1\": None, \"role_2\": None}\n        valid_result_1, valid_msg_1 = _validate_roles(valid_roles_1)\n        assert valid_result_1 is True\n        assert valid_msg_1 == \"Dialogue roles are valid.\"\n\n        valid_roles_2 = {\"role_1\": None}\n        valid_result_2, valid_msg_2 = _validate_roles(valid_roles_2)\n        assert valid_result_2 is True\n        assert valid_msg_2 == \"Dialogue roles are valid.\"\n\n        ###################################################\n\n        invalid_roles_1 = {}\n        invalid_result_1, invalid_msg_1 = _validate_roles(invalid_roles_1)\n        assert invalid_result_1 is False\n        assert (\n            invalid_msg_1\n            == \"There must be either 1 or 2 roles defined in this dialogue. Found 0\"\n        )\n\n        invalid_roles_2 = {\"role_1\": None, \"role_2\": None, \"role_3\": None}\n        invalid_result_2, invalid_msg_2 = _validate_roles(invalid_roles_2)\n        assert invalid_result_2 is False\n        assert (\n            invalid_msg_2\n            == \"There must be either 1 or 2 roles defined in this dialogue. Found 3\"\n        )\n\n        invalid_roles_3 = {\"_agent_\": None}\n        invalid_result_3, invalid_msg_3 = _validate_roles(invalid_roles_3)\n        assert invalid_result_3 is False\n        assert (\n            invalid_msg_3\n            == \"Invalid name for role '_agent_'. Role names must match the following regular expression: {} \".format(\n                ROLE_REGEX_PATTERN\n            )\n        )\n\n        invalid_roles_4 = {\"client\"}\n        invalid_result_4, invalid_msg_4 = _validate_roles(invalid_roles_4)\n        assert invalid_result_4 is False\n        assert (\n            invalid_msg_4\n            == f\"Invalid type for roles. Expected dict. Found '{type(invalid_roles_4)}'.\"\n        )\n\n    def test_validate_end_states(self):\n        \"\"\"Test for the '_validate_end_states' method.\"\"\"\n        valid_end_states_1 = [\"end_state_1\", \"end_state_2\"]\n        valid_result_1, valid_msg_1 = _validate_end_states(valid_end_states_1)\n        assert valid_result_1 is True\n        assert valid_msg_1 == \"Dialogue end_states are valid.\"\n\n        valid_end_states_2 = []\n        valid_result_2, valid_msg_2 = _validate_end_states(valid_end_states_2)\n        assert valid_result_2 is True\n        assert valid_msg_2 == \"Dialogue end_states are valid.\"\n\n        ###################################################\n\n        invalid_end_states_1 = [\"_end_state_1\"]\n        invalid_result_1, invalid_msg_1 = _validate_end_states(invalid_end_states_1)\n        assert invalid_result_1 is False\n        assert (\n            invalid_msg_1\n            == \"Invalid name for end_state '_end_state_1'. End_state names must match the following regular expression: {} \".format(\n                END_STATE_REGEX_PATTERN\n            )\n        )\n\n        invalid_end_states_2 = [\"end_$tate_1\"]\n        invalid_result_2, invalid_msg_2 = _validate_end_states(invalid_end_states_2)\n        assert invalid_result_2 is False\n        assert (\n            invalid_msg_2\n            == \"Invalid name for end_state 'end_$tate_1'. End_state names must match the following regular expression: {} \".format(\n                END_STATE_REGEX_PATTERN\n            )\n        )\n\n        invalid_end_states_3 = {\"end_state_1\"}\n        invalid_result_3, invalid_msg_3 = _validate_end_states(invalid_end_states_3)\n        assert invalid_result_3 is False\n        assert (\n            invalid_msg_3\n            == f\"Invalid type for roles. Expected list. Found '{type(invalid_end_states_3)}'.\"\n        )\n\n    def test_validate_keep_terminal(self):\n        \"\"\"Test for the '_validate_keep_terminal' method.\"\"\"\n        valid_keep_terminal_state_dialogues_1 = True\n        valid_result_1, valid_msg_1 = _validate_keep_terminal(\n            valid_keep_terminal_state_dialogues_1\n        )\n        assert valid_result_1 is True\n        assert valid_msg_1 == \"Dialogue keep_terminal_state_dialogues is valid.\"\n\n        valid_keep_terminal_state_dialogues_2 = False\n        valid_result_2, valid_msg_2 = _validate_keep_terminal(\n            valid_keep_terminal_state_dialogues_2\n        )\n        assert valid_result_2 is True\n        assert valid_msg_2 == \"Dialogue keep_terminal_state_dialogues is valid.\"\n\n        ###################################################\n\n        invalid_keep_terminal_state_dialogues_1 = \"some_non_boolean_value\"\n        invalid_result_1, invalid_msg_1 = _validate_keep_terminal(\n            invalid_keep_terminal_state_dialogues_1\n        )\n        assert invalid_result_1 is False\n        assert (\n            invalid_msg_1\n            == f\"Invalid type for keep_terminal_state_dialogues. Expected bool. Found {type(invalid_keep_terminal_state_dialogues_1)}.\"\n        )\n\n    @mock.patch(\n        \"aea.configurations.base.ProtocolSpecification\",\n    )\n    def test_validate_dialogue_section(self, mocked_spec):\n        \"\"\"Test for the '_validate_dialogue_section' method.\"\"\"\n        valid_dialogue_config_1 = {\n            \"initiation\": [\"performative_ct\", \"performative_pt\"],\n            \"reply\": {\n                \"performative_ct\": [\"performative_pct\"],\n                \"performative_pt\": [\"performative_pmt\"],\n                \"performative_pct\": [\"performative_mt\", \"performative_o\"],\n                \"performative_pmt\": [\"performative_mt\", \"performative_o\"],\n                \"performative_mt\": [],\n                \"performative_o\": [],\n                \"performative_empty_contents\": [\"performative_empty_contents\"],\n            },\n            \"termination\": [\"performative_mt\", \"performative_o\"],\n            \"roles\": {\"role_1\": None, \"role_2\": None},\n            \"end_states\": [\"end_state_1\", \"end_state_2\", \"end_state_3\"],\n            \"keep_terminal_state_dialogues\": True,\n        }\n        valid_performatives_set_1 = {\n            \"performative_ct\",\n            \"performative_pt\",\n            \"performative_pct\",\n            \"performative_pmt\",\n            \"performative_mt\",\n            \"performative_o\",\n            \"performative_empty_contents\",\n        }\n        mocked_spec.dialogue_config = valid_dialogue_config_1\n\n        (\n            valid_result_1,\n            valid_msg_1,\n        ) = _validate_dialogue_section(mocked_spec, valid_performatives_set_1)\n        assert valid_result_1 is True\n        assert valid_msg_1 == \"Dialogue section of the protocol specification is valid.\"\n\n        ###################################################\n\n        invalid_dialogue_config_1 = valid_dialogue_config_1.copy()\n        invalid_dialogue_config_1[\"initiation\"] = [\"new_performative\"]\n\n        mocked_spec.dialogue_config = invalid_dialogue_config_1\n\n        (\n            invalid_result_1,\n            invalid_msg_1,\n        ) = _validate_dialogue_section(mocked_spec, valid_performatives_set_1)\n        assert invalid_result_1 is False\n        assert (\n            invalid_msg_1\n            == \"Performative 'new_performative' specified in \\\"initiation\\\" is not defined in the protocol's speech-acts.\"\n        )\n\n        invalid_dialogue_config_2 = valid_dialogue_config_1.copy()\n        invalid_dialogue_config_2[\"reply\"] = {\n            \"performative_ct\": [\"performative_pct\"],\n            \"performative_pt\": [\"performative_pmt\"],\n            \"performative_pct\": [\"performative_mt\", \"performative_o\"],\n            \"performative_pmt\": [\"performative_mt\", \"performative_o\"],\n            \"performative_mt\": [],\n            \"performative_o\": [],\n        }\n\n        mocked_spec.dialogue_config = invalid_dialogue_config_2\n\n        (\n            invalid_result_2,\n            invalid_msg_2,\n        ) = _validate_dialogue_section(mocked_spec, valid_performatives_set_1)\n        assert invalid_result_2 is False\n        assert (\n            invalid_msg_2\n            == \"No reply is provided for the following performatives: {}\".format(\n                {\"performative_empty_contents\"},\n            )\n        )\n\n        invalid_dialogue_config_3 = valid_dialogue_config_1.copy()\n        invalid_dialogue_config_3[\"termination\"] = [\"new_performative\"]\n\n        mocked_spec.dialogue_config = invalid_dialogue_config_3\n\n        (\n            invalid_result_3,\n            invalid_msg_3,\n        ) = _validate_dialogue_section(mocked_spec, valid_performatives_set_1)\n        assert invalid_result_3 is False\n        assert (\n            invalid_msg_3\n            == \"Performative 'new_performative' specified in \\\"termination\\\" is not defined in the protocol's speech-acts.\"\n        )\n\n        invalid_dialogue_config_4 = valid_dialogue_config_1.copy()\n        invalid_dialogue_config_4[\"roles\"] = {\n            \"role_1\": None,\n            \"role_2\": None,\n            \"role_3\": None,\n        }\n\n        mocked_spec.dialogue_config = invalid_dialogue_config_4\n\n        (\n            invalid_result_4,\n            invalid_msg_4,\n        ) = _validate_dialogue_section(mocked_spec, valid_performatives_set_1)\n        assert invalid_result_4 is False\n        assert (\n            invalid_msg_4\n            == \"There must be either 1 or 2 roles defined in this dialogue. Found 3\"\n        )\n\n        invalid_dialogue_config_5 = valid_dialogue_config_1.copy()\n        invalid_dialogue_config_5[\"end_states\"] = [\"end_$tate_1\"]\n\n        mocked_spec.dialogue_config = invalid_dialogue_config_5\n\n        (\n            invalid_result_5,\n            invalid_msg_5,\n        ) = _validate_dialogue_section(mocked_spec, valid_performatives_set_1)\n        assert invalid_result_5 is False\n        assert (\n            invalid_msg_5\n            == \"Invalid name for end_state 'end_$tate_1'. End_state names must match the following regular expression: {} \".format(\n                END_STATE_REGEX_PATTERN\n            )\n        )\n\n        invalid_dialogue_config_6 = valid_dialogue_config_1.copy()\n        invalid_dialogue_config_6.pop(\"termination\")\n        mocked_spec.dialogue_config = invalid_dialogue_config_6\n\n        (\n            invalid_result_6,\n            invalid_msg_6,\n        ) = _validate_dialogue_section(mocked_spec, valid_performatives_set_1)\n        assert invalid_result_6 is False\n        assert (\n            invalid_msg_6\n            == \"Missing required field 'termination' in the dialogue section of the protocol specification.\"\n        )\n\n        invalid_value = 521\n        invalid_dialogue_config_7 = valid_dialogue_config_1.copy()\n        invalid_dialogue_config_7[\"keep_terminal_state_dialogues\"] = invalid_value\n        mocked_spec.dialogue_config = invalid_dialogue_config_7\n\n        (\n            invalid_result_7,\n            invalid_msg_7,\n        ) = _validate_dialogue_section(mocked_spec, valid_performatives_set_1)\n        assert invalid_result_7 is False\n        assert (\n            invalid_msg_7\n            == f\"Invalid type for keep_terminal_state_dialogues. Expected bool. Found {type(invalid_value)}.\"\n        )\n\n    @mock.patch(\"aea.configurations.base.ProtocolSpecification\")\n    @mock.patch(\n        \"aea.protocols.generator.validate._validate_speech_acts_section\",\n        return_value=tuple([True, \"Speech_acts are correct!\", set(), set()]),\n    )\n    @mock.patch(\n        \"aea.protocols.generator.validate._validate_protocol_buffer_schema_code_snippets\",\n        return_value=tuple([True, \"Protobuf snippets are correct!\"]),\n    )\n    @mock.patch(\n        \"aea.protocols.generator.validate._validate_dialogue_section\",\n        return_value=tuple([True, \"Dialogue section is correct!\"]),\n    )\n    def test_validate_positive(\n        self,\n        mocked_spec,\n        macked_validate_speech_acts,\n        macked_validate_protobuf,\n        macked_validate_dialogue,\n    ):\n        \"\"\"Positive test for the 'validate' method: invalid dialogue section.\"\"\"\n        (\n            valid_result_1,\n            valid_msg_1,\n        ) = validate(mocked_spec)\n        assert valid_result_1 is True\n        assert valid_msg_1 == \"Protocol specification is valid.\"\n\n    @mock.patch(\"aea.configurations.base.ProtocolSpecification\")\n    @mock.patch(\n        \"aea.protocols.generator.validate._validate_speech_acts_section\",\n        return_value=tuple([False, \"Some error on speech_acts.\", None, None]),\n    )\n    def test_validate_negative_invalid_speech_acts(\n        self, mocked_spec, macked_validate_speech_acts\n    ):\n        \"\"\"Negative test for the 'validate' method: invalid speech_acts.\"\"\"\n        (\n            invalid_result_1,\n            invalid_msg_1,\n        ) = validate(mocked_spec)\n        assert invalid_result_1 is False\n        assert invalid_msg_1 == \"Some error on speech_acts.\"\n\n    @mock.patch(\"aea.configurations.base.ProtocolSpecification\")\n    @mock.patch(\n        \"aea.protocols.generator.validate._validate_speech_acts_section\",\n        return_value=tuple([True, \"Speech_acts are correct!\", set(), set()]),\n    )\n    @mock.patch(\n        \"aea.protocols.generator.validate._validate_protocol_buffer_schema_code_snippets\",\n        return_value=tuple([False, \"Some error on protobuf snippets.\"]),\n    )\n    def test_validate_negative_invalid_protobuf_snippets(\n        self, mocked_spec, macked_validate_speech_acts, macked_validate_protobuf\n    ):\n        \"\"\"Negative test for the 'validate' method: invalid protobuf snippets.\"\"\"\n        (\n            invalid_result_1,\n            invalid_msg_1,\n        ) = validate(mocked_spec)\n        assert invalid_result_1 is False\n        assert invalid_msg_1 == \"Some error on protobuf snippets.\"\n\n    @mock.patch(\"aea.configurations.base.ProtocolSpecification\")\n    @mock.patch(\n        \"aea.protocols.generator.validate._validate_speech_acts_section\",\n        return_value=tuple([True, \"Speech_acts are correct!\", set(), set()]),\n    )\n    @mock.patch(\n        \"aea.protocols.generator.validate._validate_protocol_buffer_schema_code_snippets\",\n        return_value=tuple([True, \"Protobuf snippets are correct!\"]),\n    )\n    @mock.patch(\n        \"aea.protocols.generator.validate._validate_dialogue_section\",\n        return_value=tuple([False, \"Some error on dialogue section.\"]),\n    )\n    def test_validate_negative_invalid_dialogue_section(\n        self,\n        mocked_spec,\n        macked_validate_speech_acts,\n        macked_validate_protobuf,\n        macked_validate_dialogue,\n    ):\n        \"\"\"Negative test for the 'validate' method: invalid dialogue section.\"\"\"\n        (\n            invalid_result_1,\n            invalid_msg_1,\n        ) = validate(mocked_spec)\n        assert invalid_result_1 is False\n        assert invalid_msg_1 == \"Some error on dialogue section.\"\n"
  },
  {
    "path": "tests/test_aea/test_protocols/test_scaffold.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests for the Scaffold protocol.\"\"\"\n\nimport pytest\n\nfrom aea.protocols.scaffold.message import MyScaffoldMessage\n\n\ndef test_scaffold_message():\n    \"\"\"Testing the creation of a scaffold message.\"\"\"\n    with pytest.raises(NotImplementedError):\n        msg = MyScaffoldMessage(performative=\"\")\n        assert not msg._check_consistency(), \"Not Implemented Error\"\n"
  },
  {
    "path": "tests/test_aea/test_registries/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains a test for aea.registries.\"\"\"\n"
  },
  {
    "path": "tests/test_aea/test_registries/test_base.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests for aea/registries/base.py.\"\"\"\nimport os\nimport random\nimport shutil\nimport tempfile\nimport unittest.mock\nfrom pathlib import Path\nfrom typing import cast\nfrom unittest.mock import MagicMock\n\nimport pytest\n\nimport aea\nimport aea.registries.base\nfrom aea.aea import AEA\nfrom aea.configurations.base import ComponentId, ComponentType, PublicId\nfrom aea.configurations.constants import DEFAULT_LEDGER, DEFAULT_PRIVATE_KEY_FILE\nfrom aea.connections.base import Connection\nfrom aea.contracts.base import Contract\nfrom aea.crypto.wallet import Wallet\nfrom aea.helpers.transaction.base import SignedTransaction\nfrom aea.identity.base import Identity\nfrom aea.protocols.base import Protocol\nfrom aea.registries.base import (\n    AgentComponentRegistry,\n    ComponentRegistry,\n    HandlerRegistry,\n    PublicIdRegistry,\n)\nfrom aea.registries.resources import Resources\nfrom aea.skills.base import Skill\n\nfrom packages.fetchai.contracts.erc1155.contract import PUBLIC_ID as ERC1155_PUBLIC_ID\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.protocols.fipa.message import FipaMessage\nfrom packages.fetchai.protocols.signing.message import SigningMessage\nfrom packages.fetchai.protocols.state_update import StateUpdateMessage\nfrom packages.fetchai.skills.error import PUBLIC_ID as ERROR_SKILL_PUBLIC_ID\n\nfrom tests.conftest import CUR_PATH, ROOT_DIR, _make_dummy_connection\n\n\nclass TestContractRegistry:\n    \"\"\"Test the contract registry.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the tests up.\"\"\"\n\n        cls.oldcwd = os.getcwd()\n        cls.agent_name = \"agent_dir_test\"\n        cls.t = tempfile.mkdtemp()\n        cls.agent_folder = os.path.join(cls.t, cls.agent_name)\n        shutil.copytree(os.path.join(CUR_PATH, \"data\", \"dummy_aea\"), cls.agent_folder)\n        os.chdir(cls.agent_folder)\n\n        contract = Contract.from_dir(\n            str(Path(ROOT_DIR, \"packages\", \"fetchai\", \"contracts\", \"erc1155\"))\n        )\n\n        cls.registry = AgentComponentRegistry()\n        cls.patch = unittest.mock.patch.object(cls.registry.logger, \"exception\")\n        cls.mocked_logger = cls.patch.start()\n        cls.registry.register(contract.component_id, cast(Contract, contract))\n        cls.expected_contract_ids = {ERC1155_PUBLIC_ID}\n\n    def test_fetch_all(self):\n        \"\"\"Test that the 'fetch_all' method works as expected.\"\"\"\n        contracts = self.registry.fetch_by_type(ComponentType.CONTRACT)\n        assert all(isinstance(c, Contract) for c in contracts)\n        assert set(c.public_id for c in contracts) == self.expected_contract_ids\n\n    def test_fetch(self):\n        \"\"\"Test that the `fetch` method works as expected.\"\"\"\n        contract_id = ERC1155_PUBLIC_ID\n        contract = self.registry.fetch(ComponentId(ComponentType.CONTRACT, contract_id))\n        assert isinstance(contract, Contract)\n        assert contract.id == contract_id\n\n    def test_unregister(self):\n        \"\"\"Test that the 'unregister' method works as expected.\"\"\"\n        contract_id_removed = ERC1155_PUBLIC_ID\n        component_id = ComponentId(ComponentType.CONTRACT, contract_id_removed)\n        contract_removed = self.registry.fetch(component_id)\n        self.registry.unregister(contract_removed.component_id)\n        expected_contract_ids = set(self.expected_contract_ids)\n        expected_contract_ids.remove(contract_id_removed)\n\n        assert (\n            set(\n                c.public_id for c in self.registry.fetch_by_type(ComponentType.CONTRACT)\n            )\n            == expected_contract_ids\n        )\n\n        # restore the contract\n        self.registry.register(component_id, contract_removed)\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear down the tests.\"\"\"\n        cls.mocked_logger.__exit__()\n        os.chdir(cls.oldcwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestProtocolRegistry:\n    \"\"\"Test the protocol registry.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the tests up.\"\"\"\n\n        cls.oldcwd = os.getcwd()\n        cls.agent_name = \"agent_dir_test\"\n        cls.t = tempfile.mkdtemp()\n        cls.agent_folder = os.path.join(cls.t, cls.agent_name)\n        shutil.copytree(os.path.join(CUR_PATH, \"data\", \"dummy_aea\"), cls.agent_folder)\n        os.chdir(cls.agent_folder)\n\n        cls.registry = AgentComponentRegistry()\n        cls.patch = unittest.mock.patch.object(cls.registry.logger, \"exception\")\n        cls.mocked_logger = cls.patch.start()\n\n        protocol_1 = Protocol.from_dir(\n            Path(ROOT_DIR, \"packages\", \"fetchai\", \"protocols\", \"default\")\n        )\n        protocol_2 = Protocol.from_dir(\n            Path(ROOT_DIR, \"packages\", \"fetchai\", \"protocols\", \"fipa\"),\n        )\n        cls.registry.register(protocol_1.component_id, protocol_1)\n        cls.registry.register(protocol_2.component_id, protocol_2)\n\n        cls.expected_protocol_ids = {\n            DefaultMessage.protocol_id,\n            FipaMessage.protocol_id,\n        }\n\n    def test_fetch_all(self):\n        \"\"\"Test that the 'fetch_all' method works as expected.\"\"\"\n        protocols = self.registry.fetch_by_type(ComponentType.PROTOCOL)\n        assert all(isinstance(p, Protocol) for p in protocols)\n        assert set(p.public_id for p in protocols) == self.expected_protocol_ids\n\n    def test_unregister(self):\n        \"\"\"Test that the 'unregister' method works as expected.\"\"\"\n        protocol_id_removed = DefaultMessage.protocol_id\n        component_id = ComponentId(ComponentType.PROTOCOL, protocol_id_removed)\n        protocol_removed = self.registry.fetch(component_id)\n        self.registry.unregister(component_id)\n        expected_protocols_ids = set(self.expected_protocol_ids)\n        expected_protocols_ids.remove(protocol_id_removed)\n\n        assert (\n            set(\n                p.public_id for p in self.registry.fetch_by_type(ComponentType.PROTOCOL)\n            )\n            == expected_protocols_ids\n        )\n\n        # restore the protocol\n        self.registry.register(component_id, protocol_removed)\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear down the tests.\"\"\"\n        cls.mocked_logger.__exit__()\n        os.chdir(cls.oldcwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestResources:\n    \"\"\"Test the resources class.\"\"\"\n\n    @classmethod\n    def _patch_logger(cls):\n        cls.patch_logger_exception = unittest.mock.patch.object(\n            aea.registries.base._default_logger, \"exception\"\n        )\n        cls.mocked_logger_exception = cls.patch_logger_exception.__enter__()\n        cls.patch_logger_warning = unittest.mock.patch.object(\n            aea.registries.base._default_logger, \"warning\"\n        )\n        cls.mocked_logger_warning = cls.patch_logger_warning.__enter__()\n\n    @classmethod\n    def _unpatch_logger(cls):\n        cls.mocked_logger_exception.__exit__()\n        cls.mocked_logger_warning.__exit__()\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the tests up.\"\"\"\n        # cls._patch_logger() # noqa: E800\n\n        # create temp agent folder\n        cls.oldcwd = os.getcwd()\n        cls.agent_name = \"agent_test\" + str(random.randint(0, 1000))  # nosec\n        cls.t = tempfile.mkdtemp()\n        cls.agent_folder = os.path.join(cls.t, cls.agent_name)\n        shutil.copytree(os.path.join(CUR_PATH, \"data\", \"dummy_aea\"), cls.agent_folder)\n        os.chdir(cls.agent_folder)\n\n        cls.resources = Resources()\n\n        cls.resources.add_component(\n            Protocol.from_dir(\n                Path(ROOT_DIR, \"packages\", \"fetchai\", \"protocols\", \"default\")\n            )\n        )\n        cls.resources.add_component(\n            Protocol.from_dir(\n                Path(ROOT_DIR, \"packages\", \"fetchai\", \"protocols\", \"signing\")\n            )\n        )\n        cls.resources.add_component(\n            Protocol.from_dir(\n                Path(ROOT_DIR, \"packages\", \"fetchai\", \"protocols\", \"state_update\")\n            )\n        )\n        cls.resources.add_component(\n            Skill.from_dir(\n                Path(CUR_PATH, \"data\", \"dummy_skill\"),\n                agent_context=MagicMock(agent_name=\"name\"),\n            )\n        )\n        cls.resources.add_component(\n            Skill.from_dir(\n                Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"error\"),\n                agent_context=MagicMock(agent_name=\"name\"),\n            )\n        )\n\n        cls.error_skill_public_id = ERROR_SKILL_PUBLIC_ID\n        cls.dummy_skill_public_id = PublicId.from_str(\"dummy_author/dummy:0.1.0\")\n\n        cls.contract_public_id = ERC1155_PUBLIC_ID\n\n    def test_unregister_handler(self):\n        \"\"\"Test that the unregister of handlers work correctly.\"\"\"\n        assert len(self.resources.get_all_handlers()) == 4\n\n        # unregister the error handler and test that it has been actually unregistered.\n        # TODO shouldn't we prevent the unregistration of this?\n        error_handler = self.resources._handler_registry.fetch(\n            (self.error_skill_public_id, \"error_handler\")\n        )\n        assert error_handler is not None\n        self.resources._handler_registry.unregister(\n            (self.error_skill_public_id, \"error_handler\")\n        )\n        assert (\n            self.resources._handler_registry.fetch(\n                (self.error_skill_public_id, \"error_handler\")\n            )\n            is None\n        )\n\n        # unregister the dummy handler and test that it has been actually unregistered.\n        dummy_handler = self.resources._handler_registry.fetch(\n            (self.dummy_skill_public_id, \"dummy\")\n        )\n        assert dummy_handler is not None\n        self.resources._handler_registry.unregister(\n            (self.dummy_skill_public_id, \"dummy\")\n        )\n        assert (\n            self.resources._handler_registry.fetch(\n                (self.dummy_skill_public_id, \"dummy\")\n            )\n            is None\n        )\n\n        # restore the handlers\n        self.resources._handler_registry.register(\n            (self.error_skill_public_id, \"error\"), error_handler\n        )\n        self.resources._handler_registry.register(\n            (self.dummy_skill_public_id, \"dummy\"), dummy_handler\n        )\n        assert len(self.resources.get_all_handlers()) == 4\n\n    def test_add_and_remove_protocol(self):\n        \"\"\"Test that the 'add protocol' and 'remove protocol' method work correctly.\"\"\"\n        a_protocol = Protocol.from_dir(\n            Path(ROOT_DIR, \"packages\", \"fetchai\", \"protocols\", \"oef_search\"),\n        )\n        self.resources.add_component(cast(Protocol, a_protocol))\n        assert self.resources.get_protocol(a_protocol.public_id) == a_protocol\n        assert (\n            self.resources.get_protocol_by_specification_id(\n                a_protocol.protocol_specification_id\n            )\n            == a_protocol\n        )\n        # restore state\n        self.resources.remove_protocol(a_protocol.public_id)\n        assert self.resources.get_protocol(a_protocol.public_id) is None\n        assert (\n            self.resources.get_protocol_by_specification_id(\n                a_protocol.protocol_specification_id\n            )\n            is None\n        )\n\n    def test_get_all_protocols(self):\n        \"\"\"Test get all protocols.\"\"\"\n        all_protocols = self.resources.get_all_protocols()\n        assert len(all_protocols) == 3\n\n        expected_pids = {\n            DefaultMessage.protocol_id,\n            SigningMessage.protocol_id,\n            StateUpdateMessage.protocol_id,\n        }\n        actual_pids = {p.public_id for p in all_protocols}\n        assert expected_pids == actual_pids\n\n    def test_add_remove_contract(self):\n        \"\"\"Test that the 'add contract' and 'remove contract' method work correctly.\"\"\"\n        a_contract = Contract.from_dir(\n            Path(ROOT_DIR, \"packages\", \"fetchai\", \"contracts\", \"erc1155\"),\n        )\n        self.resources.add_component(a_contract)\n        assert self.resources.get_contract(a_contract.public_id) == a_contract\n        # restore state\n        self.resources.remove_contract(a_contract.public_id)\n        assert self.resources.get_contract(a_contract.public_id) is None\n\n    def test_get_all_contracts(self):\n        \"\"\"Test get all contracts.\"\"\"\n        a_contract = Contract.from_dir(\n            Path(ROOT_DIR, \"packages\", \"fetchai\", \"contracts\", \"erc1155\"),\n        )\n        self.resources.add_component(a_contract)\n        all_contracts = self.resources.get_all_contracts()\n        assert len(all_contracts) == 1\n        # restore state\n        self.resources.remove_contract(a_contract.public_id)\n\n    def test_add_remove_connection(self):\n        \"\"\"Test that the 'add connection' and 'remove connection' methods work correctly.\"\"\"\n        a_connection = Connection.from_dir(\n            Path(ROOT_DIR, \"packages\", \"fetchai\", \"connections\", \"oef\"),\n            data_dir=MagicMock(),\n            identity=Identity(\"name\", \"address\", \"public_key\"),\n            crypto_store=MagicMock(),\n        )\n        self.resources.add_component(a_connection)\n        assert self.resources.get_connection(a_connection.public_id) is not None\n        # restore state\n        self.resources.remove_connection(a_connection.public_id)\n\n    def test_get_all_connections(self):\n        \"\"\"Test get all connections.\"\"\"\n        a_connection = Connection.from_dir(\n            Path(ROOT_DIR, \"packages\", \"fetchai\", \"connections\", \"oef\"),\n            data_dir=MagicMock(),\n            identity=Identity(\"name\", \"address\", \"public_key\"),\n            crypto_store=MagicMock(),\n        )\n        self.resources.add_component(a_connection)\n        all_connections = self.resources.get_all_connections()\n        assert len(all_connections) == 1\n        assert all_connections[0] == a_connection\n        # restore state\n        self.resources.remove_connection(a_connection.public_id)\n\n    def test_add_remove_skill(self):\n        \"\"\"Test that the 'remove skill' and 'add skill' method work correctly.\"\"\"\n        a_skill = self.resources.get_skill(self.dummy_skill_public_id)\n        self.resources.remove_skill(self.dummy_skill_public_id)\n        assert self.resources.get_skill(self.dummy_skill_public_id) is None\n        self.resources.add_skill(a_skill)\n        assert self.resources.get_skill(self.dummy_skill_public_id) == a_skill\n\n    def test_get_handler(self):\n        \"\"\"Test get handler.\"\"\"\n        handler = self.resources.get_handler(\n            DefaultMessage.protocol_id, self.dummy_skill_public_id\n        )\n        assert handler is not None\n\n    def test_get_handlers(self):\n        \"\"\"Test get handlers.\"\"\"\n        default_handlers = self.resources.get_handlers(DefaultMessage.protocol_id)\n        assert len(default_handlers) == 2\n\n    def test_get_behaviours(self):\n        \"\"\"Test get handlers.\"\"\"\n        dummy_behaviours = self.resources.get_behaviours(self.dummy_skill_public_id)\n        assert len(dummy_behaviours) == 2\n\n    def test_add_component_raises_error(self):\n        \"\"\"Test add component with unknown component type.\"\"\"\n        a_component = MagicMock()\n        a_component.component_type = unittest.mock.PropertyMock(return_value=None)\n        with pytest.raises(ValueError):\n            self.resources.add_component(a_component)\n\n    def test_register_behaviour_with_already_existing_skill_id(self):\n        \"\"\"Test that registering a behaviour with an already existing skill id behaves as expected.\"\"\"\n        # this should raise an error, since the 'dummy\" skill already has a behaviour named \"dummy\"\n        with pytest.raises(\n            ValueError,\n            match=\"Item already registered with skill id '{}' and name '{}'\".format(\n                self.dummy_skill_public_id, \"dummy\"\n            ),\n        ):\n            self.resources._behaviour_registry.register(\n                (self.dummy_skill_public_id, \"dummy\"), None\n            )\n\n    def test_behaviour_registry(self):\n        \"\"\"Test that the behaviour registry behaves as expected.\"\"\"\n        dummy_behaviour = self.resources.get_behaviour(\n            self.dummy_skill_public_id, \"dummy\"\n        )\n        assert len(self.resources.get_all_behaviours()) == 2\n        assert dummy_behaviour is not None\n\n        self.resources._behaviour_registry.unregister(\n            (self.dummy_skill_public_id, \"dummy\")\n        )\n        assert self.resources.get_behaviour(self.dummy_skill_public_id, \"dummy\") is None\n        assert len(self.resources.get_all_behaviours()) == 1\n\n        self.resources._behaviour_registry.register(\n            (self.dummy_skill_public_id, \"dummy\"), dummy_behaviour\n        )\n\n    def test_skill_loading(self):\n        \"\"\"Test that the skills have been loaded correctly.\"\"\"\n        dummy_skill = self.resources.get_skill(self.dummy_skill_public_id)\n        skill_context = dummy_skill.skill_context\n\n        handlers = dummy_skill.handlers\n        behaviours = dummy_skill.behaviours\n        models = dummy_skill.models\n\n        assert len(handlers) == len(skill_context.handlers.__dict__)\n        assert len(behaviours) == len(skill_context.behaviours.__dict__)\n\n        assert handlers[\"dummy\"] == skill_context.handlers.dummy\n        assert behaviours[\"dummy\"] == skill_context.behaviours.dummy\n        assert models[\"dummy\"] == skill_context.dummy\n\n        assert handlers[\"dummy\"].context == dummy_skill.skill_context\n        assert behaviours[\"dummy\"].context == dummy_skill.skill_context\n        assert models[\"dummy\"].context == dummy_skill.skill_context\n\n    def test_handler_configuration_loading(self):\n        \"\"\"Test that the handler configurations are loaded correctly.\"\"\"\n        default_handlers = self.resources.get_handlers(DefaultMessage.protocol_id)\n        assert len(default_handlers) == 2\n        handler1, handler2 = default_handlers[0], default_handlers[1]\n        dummy_handler = (\n            handler1 if handler1.__class__.__name__ == \"DummyHandler\" else handler2\n        )\n\n        assert dummy_handler.config == {\"handler_arg_1\": 1, \"handler_arg_2\": \"2\"}\n\n    def test_behaviour_configuration_loading(self):\n        \"\"\"Test that the behaviour configurations are loaded correctly.\"\"\"\n        dummy_behaviour = self.resources.get_behaviour(\n            self.dummy_skill_public_id, \"dummy\"\n        )\n        assert dummy_behaviour.config == {\"behaviour_arg_1\": 1, \"behaviour_arg_2\": \"2\"}\n\n    def test_model_configuration_loading(self):\n        \"\"\"Test that the model configurations are loaded correctly.\"\"\"\n        dummy_skill = self.resources.get_skill(self.dummy_skill_public_id)\n        assert dummy_skill is not None\n        assert len(dummy_skill.models) == 1\n        dummy_model = dummy_skill.models[\"dummy\"]\n\n        assert dummy_model.config == {\n            \"model_arg_1\": 1,\n            \"model_arg_2\": \"2\",\n        }\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the tests down.\"\"\"\n        # cls._unpatch_logger() # noqa: E800\n        os.chdir(cls.oldcwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestFilter:\n    \"\"\"Test the resources class.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the tests up.\"\"\"\n        # create temp agent folder\n        cls.oldcwd = os.getcwd()\n        cls.agent_name = \"agent_test\" + str(random.randint(0, 1000))  # nosec\n        cls.t = tempfile.mkdtemp()\n        cls.agent_folder = os.path.join(cls.t, cls.agent_name)\n        shutil.copytree(os.path.join(CUR_PATH, \"data\", \"dummy_aea\"), cls.agent_folder)\n        os.chdir(cls.agent_folder)\n\n        connection = _make_dummy_connection()\n        private_key_path = os.path.join(CUR_PATH, \"data\", DEFAULT_PRIVATE_KEY_FILE)\n        wallet = Wallet({DEFAULT_LEDGER: private_key_path})\n        identity = Identity(\n            cls.agent_name,\n            address=wallet.addresses[DEFAULT_LEDGER],\n            public_key=wallet.public_keys[DEFAULT_LEDGER],\n        )\n        resources = Resources()\n\n        resources.add_component(\n            Skill.from_dir(\n                Path(CUR_PATH, \"data\", \"dummy_skill\"),\n                agent_context=MagicMock(agent_name=\"name\"),\n            )\n        )\n\n        resources.add_connection(connection)\n\n        cls.aea = AEA(identity, wallet, resources=resources, data_dir=MagicMock())\n        cls.aea.setup()\n\n    def test_handle_internal_messages(self):\n        \"\"\"Test that the internal messages are handled.\"\"\"\n        t = SigningMessage(\n            performative=SigningMessage.Performative.SIGNED_TRANSACTION,\n            signed_transaction=SignedTransaction(\"ledger_id\", {\"tx\": \"v\"}),\n        )\n        t.to = str(PublicId(\"dummy_author\", \"dummy\", \"0.1.0\"))\n        t.sender = \"decision_maker\"\n        self.aea._filter.handle_internal_message(t)\n\n        internal_handlers_list = self.aea.resources.get_handlers(t.protocol_id)\n        assert len(internal_handlers_list) == 1\n        internal_handler = internal_handlers_list[0]\n        assert len(internal_handler.handled_internal_messages) == 1\n        self.aea.teardown()\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the tests down.\"\"\"\n        os.chdir(cls.oldcwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestAgentComponentRegistry:\n    \"\"\"Test agent component registry.\"\"\"\n\n    def setup_class(self):\n        \"\"\"Set up the test.\"\"\"\n        self.registry = AgentComponentRegistry()\n\n    def test_ids(self):\n        \"\"\"Test all ids getter.\"\"\"\n        assert self.registry.ids() == set()\n\n    def test_register_when_component_is_already_registered(self):\n        \"\"\"Test AgentComponentRegistry.register when the component is already registered.\"\"\"\n        component_id = ComponentId(\n            ComponentType.PROTOCOL, PublicId(\"author\", \"name\", \"0.1.0\")\n        )\n        component_mock = MagicMock(component_id=component_id)\n        self.registry._registered_keys.add(component_id)\n        with pytest.raises(\n            ValueError, match=r\"Component already registered with item id\"\n        ):\n            self.registry.register(component_id, component_mock)\n        self.registry._registered_keys = set()\n\n    def test_register_when_component_id_mismatch(self):\n        \"\"\"Test AgentComponentRegistry.register when the component ids mismatch.\"\"\"\n        component_id_1 = ComponentId(\n            ComponentType.PROTOCOL, PublicId(\"author\", \"name\", \"0.1.0\")\n        )\n        component_id_2 = ComponentId(\n            ComponentType.PROTOCOL, PublicId(\"author\", \"name\", \"0.2.0\")\n        )\n        component_mock = MagicMock(component_id=component_id_1)\n        with pytest.raises(\n            ValueError, match=\"Component id '.*' is different to the id '.*' specified.\"\n        ):\n            self.registry.register(component_id_2, component_mock)\n        self.registry._registered_keys = set()\n\n    def test_unregister_when_no_item_registered(self):\n        \"\"\"Test AgentComponentRegistry.register when the item was not registered.\"\"\"\n        component_id = ComponentId(\n            ComponentType.PROTOCOL, PublicId(\"author\", \"name\", \"0.1.0\")\n        )\n        component_mock = MagicMock(component_id=component_id)\n        self.registry.register(component_id, component_mock)\n        self.registry._registered_keys.remove(component_id)\n        with pytest.raises(ValueError, match=\"No item registered with item id '.*'\"):\n            self.registry.unregister(component_id)\n        self.registry._registered_keys.add(component_id)\n        self.registry.unregister(component_id)\n\n    def test_fetch_all(self):\n        \"\"\"Test fetch all.\"\"\"\n        all_components = self.registry.fetch_all()\n        assert len(all_components) == 0\n        component_id = ComponentId(\n            ComponentType.PROTOCOL, PublicId(\"author\", \"name\", \"0.1.0\")\n        )\n        component_mock = MagicMock(component_id=component_id)\n        self.registry.register(component_id, component_mock)\n        all_components = self.registry.fetch_all()\n        assert len(all_components) == 1\n\n        # restore state\n        self.registry.unregister(component_id)\n\n\nclass TestComponentRegistry:\n    \"\"\"Tests for the component registry.\"\"\"\n\n    def setup_class(self):\n        \"\"\"Set up the tests.\"\"\"\n        self.registry = ComponentRegistry()\n\n    def test_ids(self):\n        \"\"\"Test the getter of all ids.\"\"\"\n        assert self.registry.ids() == set()\n\n    def test_ids_non_empty(self):\n        \"\"\"Test ids, non-empty case.\"\"\"\n        dummy_skill = Skill.from_dir(\n            Path(CUR_PATH, \"data\", \"dummy_skill\"),\n            agent_context=MagicMock(agent_name=\"name\"),\n        )\n        behaviour = next(iter(dummy_skill.behaviours.values()))\n        skill_component_id = (dummy_skill.public_id, behaviour.name)\n        self.registry.register(skill_component_id, behaviour)\n\n        assert self.registry.ids() == {skill_component_id}\n\n        self.registry.unregister(skill_component_id)\n\n    def test_unregister_when_item_not_registered(self):\n        \"\"\"Test 'unregister' in case the item is not registered.\"\"\"\n        with pytest.raises(ValueError):\n            self.registry.unregister(\n                (PublicId.from_str(\"author/name:0.1.0\"), \"component_name\")\n            )\n\n    def test_unregister_by_skill_when_item_not_registered(self):\n        \"\"\"Test 'unregister_by_skill' in case the item is not registered.\"\"\"\n        with pytest.raises(\n            ValueError, match=\"No component of skill .* present in the registry.\"\n        ):\n            self.registry.unregister_by_skill(PublicId.from_str(\"author/skill:0.1.0\"))\n\n    def test_setup_with_inactive_skill(self):\n        \"\"\"Test setup with inactive skill.\"\"\"\n        mock_item = MagicMock(\n            name=\"name\", skill_id=\"skill\", context=MagicMock(is_active=False)\n        )\n        with unittest.mock.patch.object(\n            self.registry, \"fetch_all\", return_value=[mock_item]\n        ):\n            with unittest.mock.patch.object(\n                self.registry.logger, \"debug\"\n            ) as mock_debug:\n                self.registry.setup()\n                mock_debug.assert_called_with(\n                    f\"Ignoring setup() of component {mock_item.name} of skill {mock_item.skill_id}, because the skill is not active.\"\n                )\n\n    def test_fetch_with_latest_version(self):\n        \"\"\"Test fetch with public id :latest version.\"\"\"\n        item_id_1 = PublicId(\"author\", \"package\", \"0.1.0\")\n        item_id_2 = PublicId(\"author\", \"package\", \"0.2.0\")\n        item_id_3 = PublicId(\"author\", \"package\", \"0.3.0\")\n        item_id_latest = PublicId(\"author\", \"package\")\n        name = \"name\"\n        self.registry.register((item_id_1, name), MagicMock(id=1))\n        self.registry.register((item_id_3, name), MagicMock(id=3))\n        self.registry.register((item_id_2, name), MagicMock(id=2))\n\n        latest = self.registry.fetch((item_id_latest, name))\n        assert latest is not None\n        assert latest.id == 3\n\n        # restore previous state\n        self.registry.unregister((item_id_1, name))\n        self.registry.unregister((item_id_2, name))\n        self.registry.unregister((item_id_3, name))\n\n\nclass TestHandlerRegistry:\n    \"\"\"Test handler registry.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set up the tests.\"\"\"\n        cls.registry = HandlerRegistry()\n\n    def test_fetch_skill_id_not_present(self):\n        \"\"\"Test fetch, negative case for skill id..\"\"\"\n        # register an item\n        protocol_id = MagicMock()\n        protocol_id.package_version.is_latest = False\n        skill_id = MagicMock()\n        skill_id.package_version.is_latest = False\n        handler_name = \"handler\"\n        handler_mock = MagicMock(name=handler_name, SUPPORTED_PROTOCOL=protocol_id)\n        self.registry.register((skill_id, handler_name), handler_mock)\n\n        # fetch an item with right protocol but unknown skill id\n        result = self.registry.fetch_by_protocol_and_skill(protocol_id, MagicMock())\n        assert result is None\n\n        self.registry.unregister((skill_id, handler_name))\n\n    def test_register_and_unregister_dynamically(self):\n        \"\"\"Test register when protocol id is None.\"\"\"\n        assert len(self.registry._dynamically_added) == 0\n        self.registry.register(\n            (PublicId.from_str(\"author/name:0.1.0\"), \"name\"),\n            MagicMock(SUPPORTED_PROTOCOL=PublicId.from_str(\"author/protocol:0.1.0\")),\n            is_dynamically_added=True,\n        )\n        assert len(self.registry._dynamically_added) == 1\n        self.registry.unregister(\n            (PublicId.from_str(\"author/name:0.1.0\"), \"name\"),\n        )\n        assert len(self.registry._dynamically_added) == 0\n\n    def test_register_and_teardown_dynamically(self):\n        \"\"\"Test register when protocol id is None.\"\"\"\n        assert len(self.registry._dynamically_added) == 0\n        self.registry.register(\n            (PublicId.from_str(\"author/name:0.1.0\"), \"name\"),\n            MagicMock(SUPPORTED_PROTOCOL=PublicId.from_str(\"author/protocol:0.1.0\")),\n            is_dynamically_added=True,\n        )\n        assert len(self.registry._dynamically_added) == 1\n        self.registry.teardown()\n        assert len(self.registry._dynamically_added) == 0\n\n    def test_register_when_protocol_id_is_none(self):\n        \"\"\"Test register when protocol id is None.\"\"\"\n        with pytest.raises(\n            ValueError, match=\"Please specify a supported protocol for handler class\"\n        ):\n            self.registry.register(\n                (PublicId.from_str(\"author/name:0.1.0\"), \"name\"),\n                MagicMock(SUPPORTED_PROTOCOL=None),\n            )\n\n    def test_register_when_skill_protocol_id_exist(self):\n        \"\"\"Test register when protocol id is None.\"\"\"\n        skill_id = PublicId.from_str(\"author/name:0.1.0\")\n        protocol_id = PublicId.from_str(\"author/name:0.1.0\")\n        self.registry.register(\n            (skill_id, \"name\"), MagicMock(SUPPORTED_PROTOCOL=protocol_id)\n        )\n        with pytest.raises(\n            ValueError,\n            match=\"A handler already registered with pair of protocol id .* and skill id .*\",\n        ):\n            self.registry.register(\n                (skill_id, \"name\"), MagicMock(SUPPORTED_PROTOCOL=protocol_id)\n            )\n        self.registry.unregister((skill_id, \"name\"))\n\n    def test_unregister_when_no_item_is_registered(self):\n        \"\"\"Test unregister when there is no item with that item id.\"\"\"\n        item_id = (PublicId.from_str(\"author/name:0.1.0\"), \"name\")\n        with pytest.raises(\n            ValueError, match=\"No item registered with component id '.*'\"\n        ):\n            self.registry.unregister(item_id)\n\n    def test_unregister_by_skill(self):\n        \"\"\"Test unregister by skill.\"\"\"\n        skill_id = PublicId.from_str(\"author/name:0.1.0\")\n        with pytest.raises(\n            ValueError, match=\"No component of skill .* present in the registry.\"\n        ):\n            self.registry.unregister_by_skill(skill_id)\n\n\nclass TestPublicIdRegistry:\n    \"\"\"Tests for the public id registry class.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set up the class.\"\"\"\n        cls.registry = PublicIdRegistry()\n\n    def test_register_fails_when_version_latest(self):\n        \"\"\"Test that version 'latest' are not allowed for registration.\"\"\"\n        public_id = PublicId(\"author\", \"package\", \"latest\")\n        with pytest.raises(\n            ValueError,\n            match=f\"Cannot register item with public id 'latest': {public_id}\",\n        ):\n            self.registry.register(public_id, MagicMock())\n\n    def test_register_fails_when_already_registered(self):\n        \"\"\"Test that register fails when the same public id is already registered.\"\"\"\n        public_id = PublicId(\"author\", \"package\", \"0.1.0\")\n        self.registry._public_id_to_item[public_id] = MagicMock()\n        with pytest.raises(\n            ValueError, match=f\"Item already registered with item id '{public_id}'\"\n        ):\n            self.registry.register(public_id, MagicMock())\n        self.registry._public_id_to_item.pop(public_id)\n\n    def test_unregister_fails_when_item_not_registered(self):\n        \"\"\"Test that unregister fails when the item is not registered..\"\"\"\n        public_id = PublicId(\"author\", \"package\", \"0.1.0\")\n        with pytest.raises(\n            ValueError, match=f\"No item registered with item id '{public_id}'\"\n        ):\n            self.registry.unregister(public_id)\n\n    def test_fetch_none(self):\n        \"\"\"Test fetch, negative case.\"\"\"\n        assert self.registry.fetch(MagicMock()) is None\n"
  },
  {
    "path": "tests/test_aea/test_registries/test_filter.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests for aea/registries/filter.py.\"\"\"\nimport unittest.mock\nfrom unittest.mock import MagicMock\n\nimport pytest\n\nfrom aea.configurations.base import PublicId, SkillConfig\nfrom aea.helpers.async_friendly_queue import AsyncFriendlyQueue\nfrom aea.registries.filter import Filter\nfrom aea.registries.resources import Resources\nfrom aea.skills.base import Skill\n\nfrom packages.fetchai.protocols.signing import SigningMessage\n\nfrom tests.data.dummy_skill.behaviours import DummyBehaviour\nfrom tests.data.dummy_skill.handlers import DummyHandler\n\n\nclass TestFilter:\n    \"\"\"Test class for filter.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the tests up.\"\"\"\n        cls.resources = Resources()\n        cls.decision_make_queue = AsyncFriendlyQueue()\n        cls.filter = Filter(cls.resources, cls.decision_make_queue)\n\n    @pytest.mark.asyncio\n    async def test_get_internal_message(self):\n        \"\"\"Test get internal message.\"\"\"\n        msg = MagicMock()\n        self.decision_make_queue.put(msg)\n        _msg = await self.filter.get_internal_message()\n        assert msg == _msg, \"Should get message\"\n\n    def test_get_active_handlers_skill_id_none(self):\n        \"\"\"Test get active handlers with skill id None.\"\"\"\n        protocol_id = PublicId.from_str(\"author/name:0.1.0\")\n        active_handlers = self.filter.get_active_handlers(protocol_id, skill_id=None)\n        assert len(active_handlers) == 0\n\n    def test_get_active_handlers_skill_id_not_none(self):\n        \"\"\"Test get active handlers with skill id not None.\"\"\"\n        protocol_id = PublicId.from_str(\"author/name:0.1.0\")\n        skill_id = PublicId.from_str(\"author/skill:0.1.0\")\n        active_handlers = self.filter.get_active_handlers(\n            protocol_id, skill_id=skill_id\n        )\n        assert len(active_handlers) == 0\n\n    def test_get_active_behaviours(self):\n        \"\"\"Test get active behaviours.\"\"\"\n        active_behaviours = self.filter.get_active_behaviours()\n        assert len(active_behaviours) == 0\n\n    def test_handle_internal_message_when_none(self):\n        \"\"\"Test handle internal message when the received message is None.\"\"\"\n        with unittest.mock.patch.object(\n            self.filter.logger, \"warning\"\n        ) as mock_logger_warning:\n            self.filter.handle_internal_message(None)\n            mock_logger_warning.assert_called_with(\n                \"Got 'None' while processing internal messages.\"\n            )\n\n    def test_handle_internal_message_when_no_handler(self):\n        \"\"\"Test handle internal message when the message has no matching handler.\"\"\"\n        msg = MagicMock()\n        msg.to = \"author/name:0.1.0\"\n        with unittest.mock.patch.object(\n            self.filter.logger, \"warning\"\n        ) as mock_logger_warning:\n            self.filter.handle_internal_message(msg)\n            mock_logger_warning.assert_called_with(\n                \"No internal handler fetched for skill_id={}\".format(msg.to)\n            )\n        assert self.decision_make_queue.empty()\n\n    def test_handle_internal_message_when_invalid_to(self):\n        \"\"\"Test handle internal message when the message has an invalid to.\"\"\"\n        msg = MagicMock()\n        msg.to = \"author!name\"\n        with unittest.mock.patch.object(\n            self.filter.logger, \"warning\"\n        ) as mock_logger_warning:\n            self.filter.handle_internal_message(msg)\n            mock_logger_warning.assert_called_with(\n                \"Invalid public id as destination={}\".format(msg.to)\n            )\n        assert self.decision_make_queue.empty()\n\n    def test_handle_internal_message_new_behaviours(self):\n        \"\"\"Test handle internal message when there are new behaviours to register.\"\"\"\n        skill = Skill(\n            SkillConfig(\"name\", \"author\", \"0.1.0\"),\n            handlers={},\n            behaviours={},\n            models={},\n        )\n        self.resources.add_skill(skill)\n        new_behaviour = DummyBehaviour(name=\"dummy2\", skill_context=skill.skill_context)\n        skill.skill_context.new_behaviours.put(new_behaviour)\n        self.filter.handle_new_handlers_and_behaviours()\n\n        assert self.decision_make_queue.empty()\n        assert len(self.resources.behaviour_registry.fetch_all()) == 1\n        # restore previous state\n        self.resources.remove_skill(skill.public_id)\n        assert len(self.resources.behaviour_registry.fetch_all()) == 0\n\n    def test_handle_internal_message_new_behaviours_with_error(self):\n        \"\"\"Test handle internal message when an error happens while registering a new behaviour.\"\"\"\n        skill = Skill(\n            SkillConfig(\"name\", \"author\", \"0.1.0\"),\n            handlers={},\n            behaviours={},\n            models={},\n        )\n        self.resources.add_skill(skill)\n        new_behaviour = DummyBehaviour(name=\"dummy2\", skill_context=skill.skill_context)\n        with unittest.mock.patch.object(\n            self.resources.behaviour_registry, \"register\", side_effect=ValueError\n        ):\n            with unittest.mock.patch.object(\n                self.filter.logger, \"warning\"\n            ) as mock_logger_warning:\n                skill.skill_context.new_behaviours.put(new_behaviour)\n                self.filter.handle_new_handlers_and_behaviours()\n\n        mock_logger_warning.assert_called_with(\n            \"Error when trying to add a new behaviour: \"\n        )\n        assert self.decision_make_queue.empty()\n        assert len(self.resources.behaviour_registry.fetch_all()) == 0\n        # restore previous state\n        self.resources.component_registry.unregister(skill.component_id)\n\n    def test_handle_internal_message_new_handlers(self):\n        \"\"\"Test handle internal message when there are new handlers to register.\"\"\"\n        skill = Skill(\n            SkillConfig(\"name\", \"author\", \"0.1.0\"),\n            handlers={},\n            behaviours={},\n            models={},\n        )\n        self.resources.add_skill(skill)\n        new_handler = DummyHandler(name=\"dummy2\", skill_context=skill.skill_context)\n        skill.skill_context.new_handlers.put(new_handler)\n        self.filter.handle_new_handlers_and_behaviours()\n\n        assert self.decision_make_queue.empty()\n        assert len(self.resources.handler_registry.fetch_all()) == 1\n        # restore previous state\n        self.resources.remove_skill(skill.public_id)\n        assert len(self.resources.handler_registry.fetch_all()) == 0\n\n    def test_handle_internal_message_new_handlers_with_error(self):\n        \"\"\"Test handle internal message when an error happens while registering a new handler.\"\"\"\n        skill = Skill(\n            SkillConfig(\"name\", \"author\", \"0.1.0\"),\n            handlers={},\n            behaviours={},\n            models={},\n        )\n        self.resources.add_skill(skill)\n        new_handler = DummyHandler(name=\"dummy2\", skill_context=skill.skill_context)\n        with unittest.mock.patch.object(\n            self.resources.handler_registry, \"register\", side_effect=ValueError\n        ):\n            with unittest.mock.patch.object(\n                self.filter.logger, \"warning\"\n            ) as mock_logger_warning:\n                skill.skill_context.new_handlers.put(new_handler)\n                self.filter.handle_new_handlers_and_behaviours()\n\n        mock_logger_warning.assert_called_with(\n            \"Error when trying to add a new handler: \"\n        )\n        assert self.decision_make_queue.empty()\n        assert len(self.resources.handler_registry.fetch_all()) == 0\n        # restore previous state\n        self.resources.component_registry.unregister(skill.component_id)\n\n    def test_handle_signing_message(self):\n        \"\"\"Test the handling of a signing message.\"\"\"\n        public_id = \"author/non_existing_skill:0.1.0\"\n        message = SigningMessage(\n            SigningMessage.Performative.ERROR,\n            error_code=SigningMessage.ErrorCode.UNSUCCESSFUL_MESSAGE_SIGNING,\n        )\n        message.to = public_id\n        with unittest.mock.patch.object(\n            self.filter.logger, \"warning\"\n        ) as mock_logger_warning:\n            self.filter.handle_internal_message(message)\n            mock_logger_warning.assert_called_with(\n                f\"No internal handler fetched for skill_id={public_id}\"\n            )\n\n        assert self.decision_make_queue.empty()\n"
  },
  {
    "path": "tests/test_aea/test_runner.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains tests for aea runner.\"\"\"\nimport time\nfrom unittest.mock import call, patch\n\nimport pytest\n\nfrom aea.aea_builder import AEABuilder\nfrom aea.configurations.base import SkillConfig\nfrom aea.configurations.constants import DEFAULT_LEDGER\nfrom aea.helpers.multiple_executor import ExecutorExceptionPolicies\nfrom aea.helpers.multiple_executor import _default_logger as executor_logger\nfrom aea.runner import AEARunner\nfrom aea.skills.base import Skill, SkillContext\n\nfrom tests.common.utils import make_behaviour_cls_from_funcion, wait_for_condition\nfrom tests.conftest import FETCHAI_PRIVATE_KEY_PATH\n\n\nclass TestThreadedRunner:\n    \"\"\"Test runner in threaded mode.\"\"\"\n\n    RUNNER_MODE = \"threaded\"\n\n    def _builder(self, agent_name=\"agent1\", act_func=None) -> AEABuilder:\n        \"\"\"Build an aea instance.\"\"\"\n        builder = AEABuilder()\n        builder.set_name(agent_name)\n        builder.add_private_key(DEFAULT_LEDGER, FETCHAI_PRIVATE_KEY_PATH)\n\n        skill_context = SkillContext()\n        act_func = act_func or (lambda self: self)\n        behaviour_cls = make_behaviour_cls_from_funcion(act_func)\n\n        behaviour = behaviour_cls(name=\"behaviour\", skill_context=skill_context)\n        test_skill = Skill(\n            SkillConfig(name=\"test_skill\", author=\"fetchai\"),\n            skill_context=skill_context,\n            behaviours={\"behaviour\": behaviour},\n        )\n        skill_context._skill = test_skill  # weird hack\n        builder.add_component_instance(test_skill)\n        builder.set_runtime_mode(\"async\")\n        return builder\n\n    def setup(self):\n        \"\"\"Set up aea instances.\"\"\"\n        self.aea1 = self._builder(\"agent1\").build()\n        self.aea2 = self._builder(\"agent2\").build()\n        self.failing_aea = self._builder(\n            \"failing_agent\", act_func=self.raise_exception\n        ).build()\n        self.agents = [self.aea1, self.aea2]\n\n    def raise_exception(self, *args, **kwargs):\n        \"\"\"Raise a test exception.\"\"\"\n        raise Exception(\"expected!\")\n\n    def test_start_stop(self):\n        \"\"\"Test agents started stopped.\"\"\"\n        runner = AEARunner([self.aea1, self.aea2], self.RUNNER_MODE)\n        runner.start(True)\n        wait_for_condition(lambda: runner.is_running, timeout=5)\n        time.sleep(1)\n        runner.stop()\n        assert not runner.is_running\n\n    def test_one_fails_propagate_policy(self) -> None:\n        \"\"\"Test agents started, one agent failed, exception is raised.\"\"\"\n        runner = AEARunner(\n            [self.aea1, self.aea2, self.failing_aea],\n            self.RUNNER_MODE,\n            fail_policy=ExecutorExceptionPolicies.propagate,\n        )\n\n        with pytest.raises(Exception, match=\"expected!\"):\n            runner.start()\n        runner.stop()\n\n    def test_one_fails_log_only_policy(self) -> None:\n        \"\"\"Test agents started, one agent failed, exception is raised.\"\"\"\n        runner = AEARunner(\n            [self.aea1, self.aea2, self.failing_aea],\n            self.RUNNER_MODE,\n            fail_policy=ExecutorExceptionPolicies.log_only,\n        )\n        with patch.object(executor_logger, \"exception\") as mock:\n            runner.start(threaded=True)\n            time.sleep(1)\n        mock.assert_called_with(\n            f\"Exception raised during {self.failing_aea.name} running.\"\n        )\n        assert runner.is_running\n        runner.stop()\n\n    def test_one_fails_stop_policy(self) -> None:\n        \"\"\"Test agents started, one agent failed, exception is raised.\"\"\"\n        runner = AEARunner(\n            [self.aea1, self.aea2, self.failing_aea],\n            self.RUNNER_MODE,\n            fail_policy=ExecutorExceptionPolicies.stop_all,\n        )\n        with patch.object(executor_logger, \"exception\") as mock:\n            runner.start(threaded=True)\n            time.sleep(1)\n        mock.assert_has_calls(\n            [call(f\"Exception raised during {self.failing_aea.name} running.\")]\n        )\n        assert not runner.is_running\n        runner.stop()\n\n\nclass TestAsyncRunner(TestThreadedRunner):\n    \"\"\"Test runner in async mode.\"\"\"\n\n    RUNNER_MODE = \"async\"\n"
  },
  {
    "path": "tests/test_aea/test_runtime.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains tests for aea runtime.\"\"\"\nimport asyncio\nimport os\nfrom pathlib import Path\nfrom typing import Type\nfrom unittest.mock import patch\n\nimport pytest\n\nfrom aea.aea_builder import AEABuilder\nfrom aea.configurations.constants import DEFAULT_LEDGER, DEFAULT_PRIVATE_KEY_FILE\nfrom aea.exceptions import _StopRuntime\nfrom aea.runtime import AsyncRuntime, BaseRuntime, RuntimeStates, ThreadedRuntime\n\nfrom tests.common.utils import wait_for_condition\nfrom tests.conftest import CUR_PATH, MAX_FLAKY_RERUNS\nfrom tests.data.dummy_skill import PUBLIC_ID as DUMMY_SKILL_PUBLIC_ID\n\n\nclass TestAsyncRuntime:\n    \"\"\"Test async runtime.\"\"\"\n\n    RUNTIME: Type[BaseRuntime] = AsyncRuntime\n\n    def setup(self):\n        \"\"\"Set up case.\"\"\"\n        agent_name = \"MyAgent\"\n        private_key_path = os.path.join(CUR_PATH, \"data\", DEFAULT_PRIVATE_KEY_FILE)\n        builder = AEABuilder()\n        builder.set_name(agent_name)\n        builder.add_private_key(DEFAULT_LEDGER, private_key_path)\n        builder.add_skill(Path(CUR_PATH, \"data\", \"dummy_skill\"))\n        builder.set_storage_uri(\"sqlite://:memory:\")\n        self.agent = builder.build()\n\n        self.runtime = self.RUNTIME(\n            self.agent,\n            threaded=True,\n            multiplexer_options={\n                \"connections\": self.agent.runtime.multiplexer.connections\n            },\n        )\n        self.agent._runtime = self.runtime\n\n    def teardown(self):\n        \"\"\"Tear down.\"\"\"\n        self.runtime.stop()\n        self.runtime.wait_completed(sync=True)\n\n    def test_start_stop(self):\n        \"\"\"Test runtime tart/stop.\"\"\"\n        self.runtime.start()\n        wait_for_condition(lambda: self.runtime.is_running, timeout=20)\n        self.runtime.stop()\n        self.runtime.wait_completed(sync=True)\n\n    @pytest.mark.flaky(reruns=MAX_FLAKY_RERUNS)\n    @pytest.mark.asyncio\n    async def test_stop_with_stopped_exception(self):\n        \"\"\"Test runtime stopped by stopruntime exception.\"\"\"\n        behaviour = self.agent.resources.get_behaviour(DUMMY_SKILL_PUBLIC_ID, \"dummy\")\n        with patch.object(\n            behaviour, \"act\", side_effect=_StopRuntime(reraise=ValueError(\"expected\"))\n        ):\n            self.runtime.start()\n            with pytest.raises(ValueError, match=\"expected\"):\n                self.runtime.wait_completed(timeout=20, sync=True)\n\n    def test_double_start(self):\n        \"\"\"Test runtime double start do nothing.\"\"\"\n        assert self.runtime.start()\n        assert not self.runtime.start()\n        wait_for_condition(lambda: self.runtime.is_running, timeout=20)\n\n    def test_set_loop(self):\n        \"\"\"Test set loop method.\"\"\"\n        loop = asyncio.new_event_loop()\n        self.runtime.set_loop(loop)\n        assert self.runtime.loop is loop\n\n    def test_double_stop(self):\n        \"\"\"Test runtime double stop do nothing.\"\"\"\n        self.runtime.start()\n        wait_for_condition(lambda: self.runtime.is_running, timeout=20)\n        self.runtime.stop()\n        self.runtime.wait_completed(sync=True)\n        assert self.runtime.is_stopped\n\n        self.runtime.stop()\n        self.runtime.wait_completed(sync=True)\n        assert self.runtime.is_stopped\n\n    def test_error_state(self):\n        \"\"\"Test runtime fails on start.\"\"\"\n\n        async def error(*args, **kwargs):\n            raise ValueError(\"oops\")\n\n        with patch.object(self.runtime, \"_start_agent_loop\", error):\n            with pytest.raises(ValueError, match=\"oops\"):\n                self.runtime.start_and_wait_completed(sync=True)\n\n        assert self.runtime.state == RuntimeStates.error, self.runtime.state\n\n\nclass TestThreadedRuntime(TestAsyncRuntime):\n    \"\"\"Test threaded runtime.\"\"\"\n\n    RUNTIME = ThreadedRuntime\n\n    def test_error_state(self):\n        \"\"\"Test runtime fails on start.\"\"\"\n        with patch.object(\n            self.runtime.agent_loop, \"start\", side_effect=ValueError(\"oops\")\n        ):\n            with pytest.raises(ValueError, match=\"oops\"):\n                self.runtime.start_and_wait_completed(sync=True)\n\n        assert self.runtime.state == RuntimeStates.error, self.runtime.state\n"
  },
  {
    "path": "tests/test_aea/test_skills/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"The tests for the skills module contains the tests for the skills.\"\"\"\n"
  },
  {
    "path": "tests/test_aea/test_skills/test_base.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests for the base classes for the skills.\"\"\"\nimport shutil\nimport unittest.mock\nfrom pathlib import Path\nfrom queue import Queue\nfrom textwrap import dedent\nfrom types import SimpleNamespace\nfrom unittest import TestCase, mock\nfrom unittest.mock import MagicMock, Mock, patch\n\nimport pytest\nfrom aea_ledger_ethereum import EthereumCrypto\nfrom aea_ledger_fetchai import FetchAICrypto\n\nimport aea\nfrom aea.aea import AEA\nfrom aea.common import Address\nfrom aea.configurations.base import PublicId, SkillComponentConfiguration, SkillConfig\nfrom aea.configurations.data_types import ComponentType\nfrom aea.configurations.loader import load_component_configuration\nfrom aea.crypto.wallet import Wallet\nfrom aea.decision_maker.gop import DecisionMakerHandler as GOPDecisionMakerHandler\nfrom aea.decision_maker.gop import GoalPursuitReadiness, OwnershipState, Preferences\nfrom aea.exceptions import AEAHandleException, _StopRuntime\nfrom aea.identity.base import Identity\nfrom aea.multiplexer import MultiplexerStatus\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue, Dialogues\nfrom aea.registries.resources import Resources\nfrom aea.skills.base import (\n    Behaviour,\n    Handler,\n    Model,\n    Skill,\n    SkillComponent,\n    SkillContext,\n    _SkillComponentLoader,\n    _print_warning_message_for_non_declared_skill_components,\n)\nfrom aea.test_tools.test_cases import BaseAEATestCase\n\nfrom tests.conftest import (\n    CUR_PATH,\n    ETHEREUM_PRIVATE_KEY_PATH,\n    FETCHAI_PRIVATE_KEY_PATH,\n    ROOT_DIR,\n    _make_dummy_connection,\n)\n\n\nclass BaseTestSkillContext:\n    \"\"\"Test the skill context.\"\"\"\n\n    @classmethod\n    def setup_class(cls, decision_maker_handler_class=None):\n        \"\"\"Test the initialisation of the AEA.\"\"\"\n        cls.wallet = Wallet(\n            {\n                FetchAICrypto.identifier: FETCHAI_PRIVATE_KEY_PATH,\n                EthereumCrypto.identifier: ETHEREUM_PRIVATE_KEY_PATH,\n            }\n        )\n        cls.connection = _make_dummy_connection()\n        resources = Resources()\n        resources.add_connection(cls.connection)\n        cls.identity = Identity(\n            \"name\",\n            addresses=cls.wallet.addresses,\n            public_keys=cls.wallet.public_keys,\n            default_address_key=FetchAICrypto.identifier,\n        )\n        cls.my_aea = AEA(\n            cls.identity,\n            cls.wallet,\n            data_dir=MagicMock(),\n            resources=resources,\n            decision_maker_handler_class=decision_maker_handler_class,\n        )\n\n        cls.skill_context = SkillContext(\n            cls.my_aea.context, skill=MagicMock(contracts={})\n        )\n\n    def test_agent_name(self):\n        \"\"\"Test the agent's name.\"\"\"\n        assert self.skill_context.agent_name == self.my_aea.name\n\n    def test_agent_addresses(self):\n        \"\"\"Test the agent's addresses.\"\"\"\n        assert self.skill_context.agent_addresses == self.my_aea.identity.addresses\n\n    def test_agent_public_keys(self):\n        \"\"\"Test the agent's public_keys.\"\"\"\n        assert self.skill_context.public_keys == self.my_aea.identity.public_keys\n\n    def test_agent_address(self):\n        \"\"\"Test the default agent's address.\"\"\"\n        assert self.skill_context.agent_address == self.my_aea.identity.address\n\n    def test_agent_public_key(self):\n        \"\"\"Test the default agent's public_key.\"\"\"\n        assert self.skill_context.public_key == self.my_aea.identity.public_key\n\n    def test_connection_status(self):\n        \"\"\"Test the default agent's connection status.\"\"\"\n        assert isinstance(self.skill_context.connection_status, MultiplexerStatus)\n\n    def test_decision_maker_message_queue(self):\n        \"\"\"Test the decision maker's queue.\"\"\"\n        assert isinstance(self.skill_context.decision_maker_message_queue, Queue)\n\n    def test_decision_maker_handler_context(self):\n        \"\"\"Test the decision_maker_handler_context.\"\"\"\n        assert isinstance(\n            self.skill_context.decision_maker_handler_context,\n            SimpleNamespace,\n        )\n\n    def test_storage(self):\n        \"\"\"Test the agent's storage.\"\"\"\n        assert self.skill_context.storage is None\n\n    def test_message_in_queue(self):\n        \"\"\"Test the 'message_in_queue' property.\"\"\"\n        assert isinstance(self.skill_context.message_in_queue, Queue)\n\n    def test_logger_setter(self):\n        \"\"\"Test the logger setter.\"\"\"\n        logger = self.skill_context.logger\n        self.skill_context._logger = None\n        self.skill_context.logger = logger\n        assert self.skill_context.logger == logger\n\n    def test_agent_context_setter(self):\n        \"\"\"Test the agent context setter.\"\"\"\n        agent_context = self.skill_context._agent_context\n        self.skill_context.set_agent_context(agent_context)\n        assert self.skill_context.agent_name == agent_context.agent_name\n        assert self.skill_context.agent_address == agent_context.address\n        assert self.skill_context.agent_addresses == agent_context.addresses\n\n    def test_is_active_property(self):\n        \"\"\"Test is_active property getter.\"\"\"\n        assert self.skill_context.is_active is True\n\n    def test_new_behaviours_queue(self):\n        \"\"\"Test 'new_behaviours_queue' property getter.\"\"\"\n        assert isinstance(self.skill_context.new_behaviours, Queue)\n\n    def test_new_handlers_queue(self):\n        \"\"\"Test 'new_behaviours_queue' property getter.\"\"\"\n        assert isinstance(self.skill_context.new_handlers, Queue)\n\n    def test_search_service_address(self):\n        \"\"\"Test 'search_service_address' property getter.\"\"\"\n        assert (\n            self.skill_context.search_service_address\n            == self.my_aea.context.search_service_address\n        )\n\n    def test_decision_maker_address(self):\n        \"\"\"Test 'decision_maker_address' property getter.\"\"\"\n        assert (\n            self.skill_context.decision_maker_address\n            == self.my_aea.context.decision_maker_address\n        )\n\n    def test_default_ledger_id(self):\n        \"\"\"Test 'default_ledger_id' property getter.\"\"\"\n        assert (\n            self.skill_context.default_ledger_id\n            == self.my_aea.context.default_ledger_id\n        )\n\n    def test_currency_denominations(self):\n        \"\"\"Test 'currency_denominations' property getter.\"\"\"\n        assert (\n            self.skill_context.currency_denominations\n            == self.my_aea.context.currency_denominations\n        )\n\n    def test_namespace(self):\n        \"\"\"Test the 'namespace' property getter.\"\"\"\n        assert isinstance(self.skill_context.namespace, SimpleNamespace)\n\n    def test_send_to_skill(self):\n        \"\"\"Test the send_to_skill method.\"\"\"\n        with unittest.mock.patch.object(\n            self.my_aea.context, \"_send_to_skill\", return_value=None\n        ):\n            self.skill_context.send_to_skill(\"envelope\", \"context\")\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Test teardown.\"\"\"\n        pass\n\n\nclass TestSkillContextDefault(BaseTestSkillContext):\n    \"\"\"Test skill context with default dm.\"\"\"\n\n\nclass TestSkillContextGOP(BaseTestSkillContext):\n    \"\"\"Test skill context with GOP dm.\"\"\"\n\n    @classmethod\n    def setup_class(cls, decision_maker_handler_class=GOPDecisionMakerHandler):\n        \"\"\"Setup test class.\"\"\"\n        super().setup_class(decision_maker_handler_class)\n\n    def test_agent_ownership_state(self):\n        \"\"\"Test the ownership state.\"\"\"\n        assert isinstance(\n            self.skill_context.decision_maker_handler_context.ownership_state,\n            OwnershipState,\n        )\n\n    def test_agent_preferences(self):\n        \"\"\"Test the agents_preferences.\"\"\"\n        assert isinstance(\n            self.skill_context.decision_maker_handler_context.preferences, Preferences\n        )\n\n    def test_agent_is_ready_to_pursuit_goals(self):\n        \"\"\"Test if the agent is ready to pursuit his goals.\"\"\"\n        assert isinstance(\n            self.skill_context.decision_maker_handler_context.goal_pursuit_readiness,\n            GoalPursuitReadiness,\n        )\n\n\nclass SkillContextTestCase(TestCase):\n    \"\"\"Test case for SkillContext class.\"\"\"\n\n    def test_shared_state_positive(self):\n        \"\"\"Test shared_state property positive result\"\"\"\n        agent_context = mock.Mock()\n        agent_context.shared_state = \"shared_state\"\n        obj = SkillContext(agent_context)\n        obj.shared_state\n\n    def test_skill_id_positive(self):\n        \"\"\"Test skill_id property positive result\"\"\"\n        obj = SkillContext(\"agent_context\")\n        obj._skill = mock.Mock()\n        obj._skill.config = mock.Mock()\n        obj._skill.config.public_id = \"public_id\"\n        obj.skill_id\n\n    @mock.patch(\"aea.skills.base._default_logger.debug\")\n    @mock.patch(\"aea.skills.base.SkillContext.skill_id\")\n    def test_is_active_positive(self, skill_id_mock, debug_mock):\n        \"\"\"Test is_active setter positive result\"\"\"\n        obj = SkillContext(\"agent_context\")\n        obj.is_active = \"value\"\n        debug_mock.assert_called_once()\n\n    def test_task_manager_positive(self):\n        \"\"\"Test task_manager property positive result\"\"\"\n        agent_context = mock.Mock()\n        agent_context.task_manager = \"task_manager\"\n        obj = SkillContext(agent_context)\n        with self.assertRaises(ValueError):\n            obj.task_manager\n        obj._skill = mock.Mock()\n        obj.task_manager\n\n    @mock.patch(\"aea.skills.base.SimpleNamespace\")\n    def test_handlers_positive(self, *mocks):\n        \"\"\"Test handlers property positive result\"\"\"\n        obj = SkillContext(\"agent_context\")\n        with self.assertRaises(ValueError):\n            obj.handlers\n        obj._skill = mock.Mock()\n        obj._skill.handlers = {}\n        obj.handlers\n\n    @mock.patch(\"aea.skills.base.SimpleNamespace\")\n    def test_behaviours_positive(self, *mocks):\n        \"\"\"Test behaviours property positive result\"\"\"\n        obj = SkillContext(\"agent_context\")\n        with self.assertRaises(ValueError):\n            obj.behaviours\n        obj._skill = mock.Mock()\n        obj._skill.behaviours = {}\n        obj.behaviours\n\n    def test_logger_positive(self):\n        \"\"\"Test logger property positive result\"\"\"\n        obj = SkillContext(\"agent_context\")\n        obj.logger\n        obj._logger = mock.Mock()\n        obj.logger\n\n\nclass SkillComponentTestCase(TestCase):\n    \"\"\"Test case for SkillComponent class.\"\"\"\n\n    def setUp(self):\n        \"\"\"Set the test up.\"\"\"\n\n        class TestComponent(SkillComponent):\n            \"\"\"Test class for SkillComponent\"\"\"\n\n            def parse_module(self, *args):\n                \"\"\"Parse module.\"\"\"\n                pass\n\n            def setup(self, *args):\n                \"\"\"Set up.\"\"\"\n                pass\n\n            def teardown(self, *args):\n                \"\"\"Tear down.\"\"\"\n                pass\n\n        self.TestComponent = TestComponent\n\n    def test_init_no_ctx(self):\n        \"\"\"Test init method no context provided.\"\"\"\n\n        with self.assertRaises(ValueError):\n            self.TestComponent(name=\"some_name\", skill_context=None)\n        with self.assertRaises(ValueError):\n            self.TestComponent(name=None, skill_context=\"skill_context\")\n\n    def test_skill_id_positive(self):\n        \"\"\"Test skill_id property positive.\"\"\"\n        ctx = mock.Mock()\n        ctx.skill_id = \"skill_id\"\n        component = self.TestComponent(\n            name=\"name\", skill_context=ctx, configuration=Mock()\n        )\n        component.skill_id\n\n    def test_config_positive(self):\n        \"\"\"Test config property positive.\"\"\"\n        component = self.TestComponent(\n            configuration=Mock(args={}), skill_context=\"ctx\", name=\"name\"\n        )\n        component.config\n\n    def test_kwargs_not_empty(self):\n        \"\"\"Test the case when there are some kwargs not-empty\"\"\"\n        kwargs = dict(foo=\"bar\")\n        component_name = \"component_name\"\n        skill_context = SkillContext()\n        with mock.patch.object(skill_context.logger, \"warning\") as mock_logger:\n            self.TestComponent(component_name, skill_context, **kwargs)\n            mock_logger.assert_any_call(\n                f\"The kwargs={kwargs} passed to {component_name} have not been set!\"\n            )\n\n\ndef test_load_skill():\n    \"\"\"Test the loading of a skill.\"\"\"\n    agent_context = MagicMock(agent_name=\"name\")\n    skill = Skill.from_dir(\n        Path(ROOT_DIR, \"tests\", \"data\", \"dummy_skill\"), agent_context=agent_context\n    )\n    assert isinstance(skill, Skill)\n\n\ndef test_behaviour():\n    \"\"\"Test behaviour initialization.\"\"\"\n\n    class CustomBehaviour(Behaviour):\n        def setup(self) -> None:\n            pass\n\n        def teardown(self) -> None:\n            pass\n\n        def act(self) -> None:\n            pass\n\n    behaviour = CustomBehaviour(\"behaviour\", skill_context=MagicMock())\n\n    # test getters (default values)\n    assert behaviour.tick_interval == 0.001\n    assert behaviour.start_at is None\n    assert behaviour.is_done() is False\n\n\ndef test_behaviour_parse_module_without_configs():\n    \"\"\"Call Behaviour.parse_module without configurations.\"\"\"\n    assert Behaviour.parse_module(MagicMock(), {}, MagicMock()) == {}\n\n\ndef test_behaviour_parse_module_missing_class():\n    \"\"\"Test Behaviour.parse_module when a class is missing.\"\"\"\n    skill_context = SkillContext(\n        skill=MagicMock(skill_id=PublicId.from_str(\"author/name:0.1.0\"))\n    )\n    dummy_behaviours_path = Path(\n        ROOT_DIR, \"tests\", \"data\", \"dummy_skill\", \"behaviours.py\"\n    )\n    with unittest.mock.patch.object(\n        aea.skills.base._default_logger, \"warning\"\n    ) as mock_logger_warning:\n        behaviours_by_id = Behaviour.parse_module(\n            dummy_behaviours_path,\n            {\n                \"dummy_behaviour\": SkillComponentConfiguration(\"DummyBehaviour\"),\n                \"unknown_behaviour\": SkillComponentConfiguration(\"UnknownBehaviour\"),\n            },\n            skill_context,\n        )\n        mock_logger_warning.assert_called_with(\n            \"Behaviour 'UnknownBehaviour' cannot be found.\"\n        )\n        assert \"dummy_behaviour\" in behaviours_by_id\n\n\ndef test_handler_parse_module_without_configs():\n    \"\"\"Call Handler.parse_module without configurations.\"\"\"\n    assert Handler.parse_module(MagicMock(), {}, MagicMock()) == {}\n\n\ndef test_handler_parse_module_missing_class():\n    \"\"\"Test Handler.parse_module when a class is missing.\"\"\"\n    skill_context = SkillContext(\n        skill=MagicMock(skill_id=PublicId.from_str(\"author/name:0.1.0\"))\n    )\n    dummy_handlers_path = Path(ROOT_DIR, \"tests\", \"data\", \"dummy_skill\", \"handlers.py\")\n    with unittest.mock.patch.object(\n        aea.skills.base._default_logger, \"warning\"\n    ) as mock_logger_warning:\n        behaviours_by_id = Handler.parse_module(\n            dummy_handlers_path,\n            {\n                \"dummy_handler\": SkillComponentConfiguration(\"DummyHandler\"),\n                \"unknown_handelr\": SkillComponentConfiguration(\"UnknownHandler\"),\n            },\n            skill_context,\n        )\n        mock_logger_warning.assert_called_with(\n            \"Handler 'UnknownHandler' cannot be found.\"\n        )\n        assert \"dummy_handler\" in behaviours_by_id\n\n\ndef test_model_parse_module_without_configs():\n    \"\"\"Call Model.parse_module without configurations.\"\"\"\n    assert Model.parse_module(MagicMock(), {}, MagicMock()) == {}\n\n\ndef test_model_parse_module_missing_class():\n    \"\"\"Test Model.parse_module when a class is missing.\"\"\"\n    skill_context = SkillContext(\n        skill=MagicMock(skill_id=PublicId.from_str(\"author/name:0.1.0\"))\n    )\n    dummy_models_path = Path(ROOT_DIR, \"tests\", \"data\", \"dummy_skill\", \"dummy.py\")\n    with unittest.mock.patch.object(\n        aea.skills.base._default_logger, \"warning\"\n    ) as mock_logger_warning:\n        models_by_id = Model.parse_module(\n            dummy_models_path,\n            {\n                \"dummy_model\": SkillComponentConfiguration(\"DummyModel\"),\n                \"unknown_model\": SkillComponentConfiguration(\"UnknownModel\"),\n            },\n            skill_context,\n        )\n        mock_logger_warning.assert_called_with(\"Model 'UnknownModel' cannot be found.\")\n        assert \"dummy_model\" in models_by_id\n\n\ndef test_print_warning_message_for_non_declared_skill_components():\n    \"\"\"Test the helper function '_print_warning_message_for_non_declared_skill_components'.\"\"\"\n    with unittest.mock.patch.object(\n        aea.skills.base._default_logger, \"warning\"\n    ) as mock_logger_warning:\n        _print_warning_message_for_non_declared_skill_components(\n            SkillContext(),\n            {\"unknown_class_1\", \"unknown_class_2\"},\n            set(),\n            \"type\",\n            \"path\",\n        )\n        mock_logger_warning.assert_any_call(\n            \"Class unknown_class_1 of type type found in skill module path but not declared in the configuration file.\"\n        )\n        mock_logger_warning.assert_any_call(\n            \"Class unknown_class_2 of type type found in skill module path but not declared in the configuration file.\"\n        )\n\n\nclass TestSkill:\n    \"\"\"Test skill attributes.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the tests up.\"\"\"\n        cls.skill = Skill.from_dir(\n            Path(ROOT_DIR, \"tests\", \"data\", \"dummy_skill\"),\n            MagicMock(agent_name=\"agent_name\"),\n        )\n\n    def test_logger(self):\n        \"\"\"Test the logger getter.\"\"\"\n        self.skill.logger\n\n    def test_logger_setter_raises_error(self):\n        \"\"\"Test that the logger setter raises error.\"\"\"\n        with pytest.raises(ValueError, match=\"Cannot set logger to a skill component.\"):\n            logger = self.skill.logger\n            self.skill.logger = logger\n\n    def test_skill_context(self):\n        \"\"\"Test the skill context getter.\"\"\"\n        context = self.skill.skill_context\n        assert isinstance(context, SkillContext)\n\n\nclass TestSkillProgrammatic:\n    \"\"\"Test skill attributes.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the tests up.\"\"\"\n        skill_context = SkillContext()\n        skill_config = SkillConfig(\n            name=\"simple_skill\", author=\"fetchai\", version=\"0.1.0\"\n        )\n\n        class MyHandler(Handler):\n            def setup(self):\n                pass\n\n            def handle(self, message: Message):\n                pass\n\n            def teardown(self):\n                pass\n\n        class MyBehaviour(Behaviour):\n            def setup(self):\n                pass\n\n            def act(self):\n                pass\n\n            def teardown(self):\n                pass\n\n        cls.handler_name = \"some_handler\"\n        cls.handler = MyHandler(skill_context=skill_context, name=cls.handler_name)\n        cls.model_name = \"some_model\"\n        cls.model = Model(skill_context=skill_context, name=cls.model_name)\n        cls.behaviour_name = \"some_behaviour\"\n        cls.behaviour = MyBehaviour(\n            skill_context=skill_context, name=cls.behaviour_name\n        )\n        cls.skill = Skill(\n            skill_config,\n            skill_context,\n            handlers={cls.handler.name: cls.handler},\n            models={cls.model.name: cls.model},\n            behaviours={cls.behaviour.name: cls.behaviour},\n        )\n\n    def test_behaviours(self):\n        \"\"\"Test the behaviours getter on skill context.\"\"\"\n        assert (\n            getattr(self.skill.skill_context.behaviours, self.behaviour_name, None)\n            == self.behaviour\n        )\n\n    def test_handlers(self):\n        \"\"\"Test the handlers getter on skill context.\"\"\"\n        assert (\n            getattr(self.skill.skill_context.handlers, self.handler_name, None)\n            == self.handler\n        )\n\n    def test_models(self):\n        \"\"\"Test the handlers getter on skill context.\"\"\"\n        assert getattr(self.skill.skill_context, self.model_name, None) == self.model\n\n\nclass TestHandlerHandleExceptions:\n    \"\"\"Test exceptions in the handle wrapper.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Setup test class.\"\"\"\n\n        class StandardExceptionHandler(Handler):\n            def setup(self):\n                pass\n\n            def handle(self, message: Message):\n                raise ValueError(\"expected\")\n\n            def teardown(self):\n                pass\n\n        cls.handler = StandardExceptionHandler(skill_context=mock.Mock(), name=\"name\")\n\n    def test_handler_standard_exception(self):\n        \"\"\"Test the handler exception.\"\"\"\n        with pytest.raises(AEAHandleException):\n            with pytest.raises(ValueError):\n                self.handler.handle_wrapper(\"msg\")\n\n    def test_handler_stop_exception(self):\n        \"\"\"Test the handler exception.\"\"\"\n        with pytest.raises(_StopRuntime):\n            with mock.patch.object(self.handler, \"handle\", side_effect=_StopRuntime()):\n                self.handler.handle_wrapper(\"msg\")\n\n\nclass DefaultDialogues(Model, Dialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, **kwargs) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :return: None\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> Dialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return 1  # type: ignore\n\n        Dialogues.__init__(\n            self,\n            self_address=self.context.agent_name,\n            end_states=[Mock()],  # type: ignore\n            message_class=Message,\n            dialogue_class=Dialogue,\n            role_from_first_message=role_from_first_message,\n        )\n\n\ndef test_model_dialogues_keep_terminal_dialogues_option():\n    \"\"\"Test Model Dialogues class.\"\"\"\n    dialogues = DefaultDialogues(name=\"test\", skill_context=Mock())\n    assert (\n        DefaultDialogues._keep_terminal_state_dialogues\n        == dialogues.is_keep_dialogues_in_terminal_state\n    )\n\n    dialogues = DefaultDialogues(\n        name=\"test\", skill_context=Mock(), keep_terminal_state_dialogues=True\n    )\n    assert dialogues.is_keep_dialogues_in_terminal_state is True\n    assert (\n        DefaultDialogues._keep_terminal_state_dialogues\n        == Dialogues._keep_terminal_state_dialogues\n    )\n\n    dialogues = DefaultDialogues(\n        name=\"test\", skill_context=Mock(), keep_terminal_state_dialogues=False\n    )\n    assert dialogues.is_keep_dialogues_in_terminal_state is False\n    assert (\n        DefaultDialogues._keep_terminal_state_dialogues\n        == Dialogues._keep_terminal_state_dialogues\n    )\n\n\ndef test_setup_teardown_methods():\n    \"\"\"Test skill etup/teardown methods with proper super() calls.\"\"\"\n\n    def role_from_first_message(  # pylint: disable=unused-argument\n        message: Message, receiver_address: Address\n    ) -> Dialogue.Role:\n        return None  # type: ignore\n\n    class Test(Model, Dialogues):\n        def __init__(self, name, skill_context):\n            Model.__init__(self, name, skill_context)\n            Dialogues.__init__(\n                self, \"addr\", MagicMock(), Message, Dialogue, role_from_first_message\n            )\n\n        def setup(self) -> None:\n            super().setup()\n\n        def teardown(self) -> None:\n            super().teardown()\n\n    skill_context = MagicMock()\n    skill_context.skill_id = PublicId(\"test\", \"test\", \"1.0.1\")\n    t = Test(name=\"test\", skill_context=skill_context)\n\n    with patch.object(t._dialogues_storage, \"setup\") as mock_setup, patch.object(\n        t._dialogues_storage, \"teardown\"\n    ) as mock_teardown:\n        t.setup()\n        t.teardown()\n\n    mock_setup.assert_called_once()\n    mock_teardown.assert_called_once()\n\n\nclass TestSkillLoadingWarningMessages(BaseAEATestCase):\n    \"\"\"\n    Test warning message in case undeclared skill are found.\n\n    That is:\n    - copy dummy_aea in a temporary directory\n    - add a skill module with two skill components\n      - one that has 'is_programmatically_defined' set to False\n      - one that has 'is_programmatically_defined' set to True\n    - test that we have a warning message only from the first.\n    \"\"\"\n\n    agent_name = \"dummy_aea\"\n\n    cli_log_options = [\"-v\", \"DEBUG\"]\n    _TEST_HANDLER_CLASS_NAME = \"TestHandler\"\n    _TEST_BEHAVIOUR_CLASS_NAME = \"TestBehaviour\"\n\n    _test_skill_module_path = \"skill_module_for_testing.py\"\n    _test_skill_module_content = dedent(\n        f\"\"\"\n    from aea.skills.base import Behaviour, Handler\n\n    class {_TEST_HANDLER_CLASS_NAME}(Handler):\n\n        is_programmatically_defined = False\n\n        def setup(self):\n            pass\n        def handle(self, message):\n            pass\n        def teardown(self):\n            pass\n\n    class {_TEST_BEHAVIOUR_CLASS_NAME}(Behaviour):\n\n        is_programmatically_defined = True\n\n        def setup(self):\n            pass\n        def act(self):\n            pass\n        def teardown(self):\n            pass\n    \"\"\"\n    )\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set up the test.\"\"\"\n        super().setup_class()\n        path_to_aea = Path(CUR_PATH, \"data\", \"dummy_aea\")\n        shutil.copytree(path_to_aea, cls.t / cls.agent_name)\n\n        # add a module in 'dummy' skill with a Handler and a Behaviour\n        dummy_skill_path = cls.t / cls.agent_name / \"skills\" / \"dummy\"\n        (dummy_skill_path / cls._test_skill_module_path).write_text(\n            cls._test_skill_module_content\n        )\n        skill_config = load_component_configuration(\n            ComponentType.SKILL, dummy_skill_path, skip_consistency_check=True\n        )\n        skill_config._directory = dummy_skill_path\n\n        cls.skill_context_mock = MagicMock()\n        cls.skill_component_loader = _SkillComponentLoader(\n            skill_config, cls.skill_context_mock\n        )\n\n        # load the skill - it will trigger the warning messages.\n        cls.skill_component_loader.load_skill()\n\n    def test_warning_message_when_component_not_declared_and_flag_is_false(self):\n        \"\"\"\n        Test warning message.\n\n        Test that the warning message is printed when component not declared\n         and when the flag 'is_programmatically_defined' is false.\n        \"\"\"\n        expected_message = f\"Class {self._TEST_HANDLER_CLASS_NAME} of type handler found in skill module {self._test_skill_module_path} but not declared in the configuration file.\"\n        self.skill_context_mock.logger.warning.assert_any_call(expected_message)\n\n    def test_no_warning_message_when_component_not_declared_but_flag_is_true(self):\n        \"\"\"\n        Test warning message.\n\n        Test that the warning message is NOT printed when component not declared\n         AND the flag 'is_programmatically_defined' is true.\n        \"\"\"\n        not_expected_message = f\"Class {self._TEST_BEHAVIOUR_CLASS_NAME} of type behaviour found in skill module {self._test_skill_module_path} but not declared in the configuration file.\"\n        # note: we do want the mock assert to fail\n        with pytest.raises(AssertionError):\n            self.skill_context_mock.logger.warning.assert_any_call(not_expected_message)\n"
  },
  {
    "path": "tests/test_aea/test_skills/test_behaviours.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests for the behaviours.\"\"\"\nfrom collections import Counter\nfrom unittest import TestCase, mock\n\nimport pytest\n\nfrom aea.exceptions import AEAActException, _StopRuntime\nfrom aea.skills.behaviours import (\n    CyclicBehaviour,\n    FSMBehaviour,\n    OneShotBehaviour,\n    SequenceBehaviour,\n    State,\n    TickerBehaviour,\n)\n\n\ndef test_sequence_behaviour():\n    \"\"\"Test the sequence behaviour.\"\"\"\n    outputs = []\n\n    class MySequenceBehaviour(SequenceBehaviour):\n        \"\"\"Custom sequence behaviour.\"\"\"\n\n        def setup(self) -> None:\n            \"\"\"Setup behaviour.\"\"\"\n            pass\n\n        def teardown(self) -> None:\n            \"\"\"Teardown behaviour.\"\"\"\n            pass\n\n    class SimpleOneShotBehaviour(OneShotBehaviour):\n        \"\"\"Custom simple behaviour.\"\"\"\n\n        def __init__(self, name, **kwargs):\n            super().__init__(name=name, **kwargs)\n\n        def setup(self) -> None:\n            \"\"\"Setup behaviour.\"\"\"\n            pass\n\n        def teardown(self) -> None:\n            \"\"\"Teardown behaviour.\"\"\"\n            pass\n\n        def act(self) -> None:\n            \"\"\"Act implementation.\"\"\"\n            outputs.append(self.name)\n\n    # TODO let the initialization of a behaviour action from constructor\n    a = SimpleOneShotBehaviour(\"a\", skill_context=object())\n    b = SimpleOneShotBehaviour(\"b\", skill_context=object())\n    c = SimpleOneShotBehaviour(\"c\", skill_context=object())\n    sequence = MySequenceBehaviour([a, b, c], name=\"abc\", skill_context=object())\n\n    max_iterations = 10\n    i = 0\n    while not sequence.is_done() and i < max_iterations:\n        sequence.act()\n        i += 1\n\n    assert outputs == [\"a\", \"b\", \"c\"]\n\n\ndef test_act_parameter():\n    \"\"\"Test the 'act' parameter.\"\"\"\n    counter = Counter(i=0)\n\n    def increment_counter(counter=counter):\n        counter += Counter(i=1)\n\n    assert counter[\"i\"] == 0\n\n    one_shot_behaviour = OneShotBehaviour(\n        act=lambda: increment_counter(), skill_context=object(), name=\"my_behaviour\"\n    )\n    one_shot_behaviour.act()\n    assert counter[\"i\"] == 1\n\n\nclass SimpleFSMBehaviour(FSMBehaviour):\n    \"\"\"A Finite-State Machine behaviour for testing purposes.\"\"\"\n\n    def setup(self) -> None:\n        \"\"\"Setup behaviour.\"\"\"\n        pass\n\n    def teardown(self) -> None:\n        \"\"\"Teardown behaviour.\"\"\"\n        pass\n\n\nclass SimpleStateBehaviour(State):\n    \"\"\"A simple state behaviour to be added in a FSMBehaviour.\"\"\"\n\n    def __init__(self, shared_list, event_to_trigger=None, **kwargs):\n        \"\"\"Initialise simple behaviour.\"\"\"\n        super().__init__(**kwargs)\n        self.shared_list = shared_list\n        self.event_to_trigger = event_to_trigger\n        self.executed = False\n\n    def setup(self) -> None:\n        \"\"\"Setup behaviour.\"\"\"\n        pass\n\n    def teardown(self) -> None:\n        \"\"\"Teardown behaviour.\"\"\"\n        pass\n\n    def act(self) -> None:\n        \"\"\"Act implementation.\"\"\"\n        self.shared_list.append(self.name)\n        self.executed = True\n        self._event = self.event_to_trigger\n\n    def is_done(self) -> bool:\n        \"\"\"Get is done.\"\"\"\n        return self.executed\n\n\ndef test_fms_behaviour():\n    \"\"\"Test the finite-state machine behaviour.\"\"\"\n    outputs = []\n\n    a = SimpleStateBehaviour(\n        outputs, name=\"a\", event_to_trigger=\"move_to_b\", skill_context=object()\n    )\n    b = SimpleStateBehaviour(\n        outputs, name=\"b\", event_to_trigger=\"move_to_c\", skill_context=object()\n    )\n    c = SimpleStateBehaviour(outputs, name=\"c\", skill_context=object())\n    fsm = SimpleFSMBehaviour(name=\"abc\", skill_context=object())\n    fsm.register_state(str(a.name), a, initial=True)\n    fsm.register_state(str(b.name), b)\n    fsm.register_final_state(str(c.name), c)\n    fsm.register_transition(\"a\", \"b\", \"move_to_b\")\n    fsm.register_transition(\"b\", \"c\", \"move_to_c\")\n\n    max_iterations = 10\n    i = 0\n    while not fsm.is_done() and i < max_iterations:\n        fsm.act()\n        i += 1\n\n    assert outputs == [\"a\", \"b\", \"c\"]\n\n\nclass TestFSMBehaviourCreation:\n    \"\"\"Test FSMBehaviour creation.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.fsm_behaviour = SimpleFSMBehaviour(name=\"fsm\", skill_context=object())\n        cls.outputs = []\n        cls.a = SimpleStateBehaviour(cls.outputs, name=\"a\", skill_context=object())\n        cls.b = SimpleStateBehaviour(cls.outputs, name=\"b\", skill_context=object())\n        cls.c = SimpleStateBehaviour(cls.outputs, name=\"c\", skill_context=object())\n\n    def test_initial_state_is_none(self):\n        \"\"\"Test that the initial state is None.\"\"\"\n        assert self.fsm_behaviour.initial_state is None\n\n    def test_states_is_empty(self):\n        \"\"\"Test that the states is an empty set.\"\"\"\n        assert self.fsm_behaviour.states == set()\n\n    def test_final_states_is_empty(self):\n        \"\"\"Test that the final states is an empty set.\"\"\"\n        assert self.fsm_behaviour.final_states == set()\n\n    def test_add_and_remove_state(self):\n        \"\"\"Test that adding and removing a state works correctly.\"\"\"\n        assert self.fsm_behaviour.states == set()\n        self.fsm_behaviour.register_state(\"a\", self.a)\n        assert self.fsm_behaviour.states == {\"a\"}\n        self.fsm_behaviour.unregister_state(\"a\")\n        assert self.fsm_behaviour.states == set()\n\n    def test_add_and_remove_initial_state(self):\n        \"\"\"Test that adding and removing an initial state works correctly.\"\"\"\n        assert self.fsm_behaviour.states == set()\n        self.fsm_behaviour.register_state(\"a\", self.a, initial=True)\n        assert self.fsm_behaviour.states == {\"a\"}\n        assert self.fsm_behaviour.initial_state == \"a\"\n        assert self.fsm_behaviour.final_states == set()\n        self.fsm_behaviour.unregister_state(\"a\")\n        assert self.fsm_behaviour.states == set()\n        assert self.fsm_behaviour.initial_state is None\n        assert self.fsm_behaviour.final_states == set()\n\n    def test_add_and_remove_final_state(self):\n        \"\"\"Test that adding and removing final states works correctly.\"\"\"\n        assert self.fsm_behaviour.states == set()\n        self.fsm_behaviour.register_final_state(\"a\", self.a)\n        assert self.fsm_behaviour.states == {\"a\"}\n        assert self.fsm_behaviour.initial_state is None\n        assert self.fsm_behaviour.final_states == {\"a\"}\n        self.fsm_behaviour.unregister_state(\"a\")\n        assert self.fsm_behaviour.states == set()\n        assert self.fsm_behaviour.initial_state is None\n        assert self.fsm_behaviour.final_states == set()\n\n    def test_register_initial_state_twice(self):\n        \"\"\"Test that the register state with initial=True works correctly when called twice.\"\"\"\n        assert self.fsm_behaviour.initial_state is None\n        self.fsm_behaviour.register_state(\"a\", self.a, initial=True)\n        assert self.fsm_behaviour.initial_state == \"a\"\n        self.fsm_behaviour.register_state(\"b\", self.b, initial=True)\n        assert self.fsm_behaviour.initial_state == \"b\"\n        self.fsm_behaviour.unregister_state(\"a\")\n        self.fsm_behaviour.unregister_state(\"b\")\n        assert self.fsm_behaviour.initial_state is None\n\n    def test_register_twice_same_state(self):\n        \"\"\"Test that registering twice a state with the same name raises an error.\"\"\"\n        self.fsm_behaviour.register_state(\"a\", self.a)\n        with pytest.raises(ValueError, match=\"State name already existing.\"):\n            self.fsm_behaviour.register_state(\"a\", self.a)\n        self.fsm_behaviour.unregister_state(\"a\")\n\n    def test_register_transition(self):\n        \"\"\"Test register transition.\"\"\"\n        self.fsm_behaviour.register_transition(\"state_1\", \"state_2\")\n        self.fsm_behaviour.register_transition(\"state_1\", \"state_2\", \"an_event\")\n        assert self.fsm_behaviour.transitions == {\n            \"state_1\": {None: \"state_2\", \"an_event\": \"state_2\"}\n        }\n        self.fsm_behaviour.unregister_transition(\"state_1\", \"state_2\", None)\n        self.fsm_behaviour.unregister_transition(\"state_1\", \"state_2\", \"an_event\")\n        assert self.fsm_behaviour.transitions == {}\n\n    def test_register_same_transition_twice(self):\n        \"\"\"Test that when we try to register twice the same transition we raise an error.\"\"\"\n        self.fsm_behaviour.register_transition(\"state_1\", \"state_2\")\n        with pytest.raises(ValueError, match=\"Transition already registered.\"):\n            self.fsm_behaviour.register_transition(\"state_1\", \"state_2\")\n        self.fsm_behaviour.unregister_transition(\"state_1\", \"state_2\")\n\n        self.fsm_behaviour.register_transition(\"state_1\", \"state_2\", \"an_event\")\n        with pytest.raises(ValueError, match=\"Transition already registered.\"):\n            self.fsm_behaviour.register_transition(\"state_1\", \"state_2\", \"an_event\")\n        self.fsm_behaviour.unregister_transition(\"state_1\", \"state_2\", \"an_event\")\n\n\nclass CyclicBehaviourTestCase(TestCase):\n    \"\"\"Test case for CyclicBehaviour class.\"\"\"\n\n    def setUp(self):\n        \"\"\"Set the test up.\"\"\"\n\n        class TestCyclicBehaviour(CyclicBehaviour):\n            \"\"\"Class for testing CyclicBehaviour abstract class.\"\"\"\n\n            def setup(self, *args):\n                \"\"\"Set up.\"\"\"\n                pass\n\n            def teardown(self, *args):\n                \"\"\"Tear down.\"\"\"\n                pass\n\n        self.TestCyclicBehaviour = TestCyclicBehaviour\n\n    def test_init_positive(self):\n        \"\"\"Test for init positive result.\"\"\"\n        self.TestCyclicBehaviour(skill_context=\"skill_context\", name=\"name\")\n\n    def test_act_wrapper_positive(self):\n        \"\"\"Test for act_wrapper positive result.\"\"\"\n        obj = self.TestCyclicBehaviour(skill_context=\"skill_context\", name=\"name\")\n        obj.act = mock.Mock()\n        assert obj.number_of_executions == 0\n        obj.act_wrapper()\n        obj.act.assert_called_once()\n        assert obj.number_of_executions == 1\n\n    def test_act_wrapper_negative_standard_exception(self):\n        \"\"\"Test for act_wrapper negative result.\"\"\"\n\n        def exception_act():\n            \"\"\"Act method with exception.\"\"\"\n            raise ValueError(\"expected\")\n\n        with pytest.raises(AEAActException):\n            with pytest.raises(ValueError):\n                obj = self.TestCyclicBehaviour(skill_context=mock.Mock(), name=\"name\")\n                obj.act = exception_act\n                assert obj.number_of_executions == 0\n                obj.act_wrapper()\n                obj.act.assert_called_once()\n                assert obj.number_of_executions == 1\n\n    def test_act_wrapper_negative_stop_runtime(self):\n        \"\"\"Test for act_wrapper negative result.\"\"\"\n        obj = self.TestCyclicBehaviour(skill_context=\"skill_context\", name=\"name\")\n        obj.act = mock.Mock()\n\n        with pytest.raises(_StopRuntime):\n            with mock.patch.object(obj, \"act\", side_effect=_StopRuntime()):\n                assert obj.number_of_executions == 0\n                obj.act_wrapper()\n                obj.act.assert_called_once()\n                assert obj.number_of_executions == 1\n\n\nclass TickerBehaviourTestCase(TestCase):\n    \"\"\"Test case for TickerBehaviour class.\"\"\"\n\n    def setUp(self):\n        \"\"\"Set the test up.\"\"\"\n\n        class TestTickerBehaviour(TickerBehaviour):\n            \"\"\"Class for testing TickerBehaviour abstract class.\"\"\"\n\n            def setup(self, *args):\n                \"\"\"Set up.\"\"\"\n                pass\n\n            def teardown(self, *args):\n                \"\"\"Tear down.\"\"\"\n                pass\n\n        self.TestTickerBehaviour = TestTickerBehaviour\n\n    def test_init_positive(self):\n        \"\"\"Test for init positive result.\"\"\"\n        self.TestTickerBehaviour(skill_context=\"skill_context\", name=\"name\")\n\n    def test_tick_interval_positive(self):\n        \"\"\"Test for tick_interval property positive result.\"\"\"\n        obj = self.TestTickerBehaviour(skill_context=\"skill_context\", name=\"name\")\n        obj.tick_interval\n\n    def test_start_at_positive(self):\n        \"\"\"Test for start_at property positive result.\"\"\"\n        obj = self.TestTickerBehaviour(skill_context=\"skill_context\", name=\"name\")\n        obj.start_at\n\n    def test_last_act_time_positive(self):\n        \"\"\"Test for last_act_time property positive result.\"\"\"\n        obj = self.TestTickerBehaviour(skill_context=\"skill_context\", name=\"name\")\n        obj.last_act_time\n\n    def test_act_wrapper_positive(self):\n        \"\"\"Test for act_wrapper positive result.\"\"\"\n        obj = self.TestTickerBehaviour(skill_context=\"skill_context\", name=\"name\")\n        obj.is_done = mock.Mock(return_value=False)\n        obj.is_time_to_act = mock.Mock(return_value=True)\n        obj.act = mock.Mock()\n        obj.act_wrapper()\n        obj.act.assert_called_once()\n\n    def test_is_time_to_act_positive(self):\n        \"\"\"Test for is_time_to_act positive result.\"\"\"\n        obj = self.TestTickerBehaviour(skill_context=\"skill_context\", name=\"name\")\n        obj.is_time_to_act()\n\n\nclass FSMBehaviourTestCase(TestCase):\n    \"\"\"Test case for FSMBehaviour class.\"\"\"\n\n    def setUp(self):\n        \"\"\"Set the test up.\"\"\"\n\n        class TestFSMBehaviour(FSMBehaviour):\n            \"\"\"Class for testing FSMBehaviour abstract class.\"\"\"\n\n            def setup(self, *args):\n                \"\"\"Set up.\"\"\"\n                pass\n\n            def teardown(self, *args):\n                \"\"\"Tear down.\"\"\"\n                pass\n\n        self.TestFSMBehaviour = TestFSMBehaviour\n\n    def test_is_started_positive(self):\n        \"\"\"Test for is_started property positive result.\"\"\"\n        obj = self.TestFSMBehaviour(skill_context=\"skill_context\", name=\"name\")\n        obj.is_started\n\n    def test_register_final_state_already_exists(self):\n        \"\"\"Test for register_final_state already exists.\"\"\"\n        obj = self.TestFSMBehaviour(skill_context=\"skill_context\", name=\"name\")\n        obj._name_to_state = [\"name\"]\n        with self.assertRaises(ValueError):\n            obj.register_final_state(\"name\", \"state\")\n\n    def test_unregister_state_not_exists(self):\n        \"\"\"Test for unregister_state not exists.\"\"\"\n        obj = self.TestFSMBehaviour(skill_context=\"skill_context\", name=\"name\")\n        obj._name_to_state = []\n        with self.assertRaises(ValueError):\n            obj.unregister_state(\"name\")\n\n    def test_initial_state_not_state(self):\n        \"\"\"Test for initial_state not a state.\"\"\"\n        obj = self.TestFSMBehaviour(skill_context=\"skill_context\", name=\"name\")\n        obj._name_to_state = []\n        with self.assertRaises(ValueError):\n            obj.initial_state = \"name\"\n\n    def test_initial_state_positive(self):\n        \"\"\"Test for initial_state positive result.\"\"\"\n        obj = self.TestFSMBehaviour(skill_context=\"skill_context\", name=\"name\")\n        obj._name_to_state = [\"name\"]\n        obj.initial_state = \"name\"\n\n    def test_act_no_current(self):\n        \"\"\"Test for act method no current state.\"\"\"\n        obj = self.TestFSMBehaviour(skill_context=\"skill_context\", name=\"name\")\n        obj.current = None\n        obj.act()\n\n    def test_act_no_current_got(self):\n        \"\"\"Test for act method no current state got.\"\"\"\n        obj = self.TestFSMBehaviour(skill_context=\"skill_context\", name=\"name\")\n        obj.get_state = mock.Mock(return_value=None)\n        obj.current = \"current\"\n        obj.act()\n        obj.get_state.assert_called_once()\n\n    def test_act_current_in_final_states(self):\n        \"\"\"Test for act method current in final_states.\"\"\"\n        obj = self.TestFSMBehaviour(skill_context=\"skill_context\", name=\"name\")\n        current_state = mock.Mock()\n        current_state.act_wrapper = mock.Mock()\n        current_state.is_done = mock.Mock(return_value=True)\n\n        obj.final_states.add(current_state)\n        obj.get_state = mock.Mock(return_value=current_state)\n        obj.current = \"current\"\n        obj.act()\n\n        obj.get_state.assert_called_once()\n        current_state.act_wrapper.assert_called_once()\n        current_state.is_done.assert_called_once()\n\n    def test_unregister_transition_value_error(self):\n        \"\"\"Test for unregister_transition method ValueError raises.\"\"\"\n        obj = self.TestFSMBehaviour(skill_context=\"skill_context\", name=\"name\")\n        obj.transitions = {}\n        with self.assertRaises(ValueError):\n            obj.unregister_transition(\"source\", \"destination\")\n"
  },
  {
    "path": "tests/test_aea/test_skills/test_error.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"The test error skill module contains the tests of the error skill.\"\"\"\n\nimport logging\nimport os\nimport unittest.mock\nfrom threading import Thread\nfrom unittest.mock import MagicMock\n\nfrom aea.aea import AEA\nfrom aea.configurations.base import PublicId\nfrom aea.configurations.constants import DEFAULT_LEDGER, DEFAULT_PRIVATE_KEY_FILE\nfrom aea.crypto.wallet import Wallet\nfrom aea.identity.base import Identity\nfrom aea.mail.base import Envelope\nfrom aea.multiplexer import InBox, Multiplexer\nfrom aea.registries.resources import Resources\nfrom aea.skills.base import SkillContext\n\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.protocols.fipa.message import FipaMessage\nfrom packages.fetchai.skills.error.handlers import ErrorHandler\n\nfrom tests.common.utils import wait_for_condition\nfrom tests.conftest import CUR_PATH, _make_dummy_connection\n\n\nlogger = logging.getLogger(__file__)\n\n\nclass InboxWithHistory(InBox):\n    \"\"\"Inbox with history of all messages every fetched.\"\"\"\n\n    def __init__(self, multiplexer: Multiplexer):\n        \"\"\"Inin inbox.\"\"\"\n        super().__init__(multiplexer)\n        self._history = []  # type: ignore\n\n    def get(self, *args, **kwargs) -> Envelope:\n        \"\"\"Get envelope.\"\"\"\n        item = super().get(*args, **kwargs)\n        self._history.append(item)\n        return item\n\n    async def async_get(self, *args, **kwargs) -> Envelope:\n        \"\"\"Get envelope.\"\"\"\n        item = await super().async_get()\n        self._history.append(item)\n        return item\n\n\nclass TestSkillError:\n    \"\"\"Test the skill: Error.\"\"\"\n\n    def setup(self):\n        \"\"\"Test the initialisation of the AEA.\"\"\"\n        private_key_path = os.path.join(CUR_PATH, \"data\", DEFAULT_PRIVATE_KEY_FILE)\n        self.wallet = Wallet({DEFAULT_LEDGER: private_key_path})\n        self.agent_name = \"Agent0\"\n        self.data_dir = MagicMock()\n\n        self.connection = _make_dummy_connection()\n        self.identity = Identity(\n            self.agent_name,\n            address=self.wallet.addresses[DEFAULT_LEDGER],\n            public_key=self.wallet.public_keys[DEFAULT_LEDGER],\n        )\n        self.address = self.identity.address\n        resources = Resources()\n        resources.add_connection(self.connection)\n        self.my_aea = AEA(\n            self.identity,\n            self.wallet,\n            resources=resources,\n            data_dir=self.data_dir,\n            period=0.1,\n            default_connection=self.connection.public_id,\n        )\n\n        self.my_aea._inbox = InboxWithHistory(self.my_aea.runtime.multiplexer)\n        self.skill_context = SkillContext(self.my_aea._context)\n        logger_name = \"aea.{}.skills.{}.{}\".format(\n            self.my_aea._context.agent_name, \"fetchai\", \"error\"\n        )\n        self.skill_context._logger = logging.getLogger(logger_name)\n        self.my_error_handler = ErrorHandler(\n            name=\"error\", skill_context=self.skill_context\n        )\n        self.t = Thread(target=self.my_aea.start)\n        self.t.start()\n        wait_for_condition(\n            lambda: self.my_aea.runtime and self.my_aea.runtime.is_running, 10\n        )\n\n    def test_error_handler_handle(self):\n        \"\"\"Test the handle function.\"\"\"\n        msg = FipaMessage(\n            message_id=1,\n            dialogue_reference=(str(0), \"\"),\n            target=0,\n            performative=FipaMessage.Performative.ACCEPT,\n        )\n        msg.to = \"a_counterparty\"\n        self.my_error_handler.handle(message=msg)\n\n    def test_error_skill_unsupported_protocol(self):\n        \"\"\"Test the unsupported error message.\"\"\"\n        self.my_aea._inbox._history = []\n        msg = FipaMessage(\n            message_id=1,\n            dialogue_reference=(str(0), \"\"),\n            target=0,\n            performative=FipaMessage.Performative.ACCEPT,\n        )\n        msg.to = self.address\n        envelope = Envelope(\n            to=msg.to,\n            sender=self.address,\n            message=msg,\n        )\n\n        self.my_error_handler.send_unsupported_protocol(envelope)\n\n        wait_for_condition(lambda: len(self.my_aea._inbox._history) >= 1, timeout=5)\n        envelope = self.my_aea._inbox._history[-1]\n        msg = envelope.message\n        assert msg.performative == DefaultMessage.Performative.ERROR\n        assert msg.error_code == DefaultMessage.ErrorCode.UNSUPPORTED_PROTOCOL\n\n    def test_error_decoding_error(self):\n        \"\"\"Test the decoding error.\"\"\"\n        self.my_aea._inbox._history = []\n        msg = FipaMessage(\n            message_id=1,\n            dialogue_reference=(str(0), \"\"),\n            target=0,\n            performative=FipaMessage.Performative.ACCEPT,\n        )\n        msg.to = self.address\n        envelope = Envelope(\n            to=msg.to,\n            sender=self.address,\n            message=msg,\n        )\n\n        self.my_error_handler.send_decoding_error(envelope)\n        wait_for_condition(lambda: len(self.my_aea._inbox._history) >= 1, timeout=5)\n        envelope = self.my_aea._inbox._history[-1]\n\n        msg = envelope.message\n        assert msg.performative == DefaultMessage.Performative.ERROR\n        assert msg.error_code == DefaultMessage.ErrorCode.DECODING_ERROR\n\n    def test_error_unsupported_skill(self):\n        \"\"\"Test the unsupported skill.\"\"\"\n        msg = FipaMessage(\n            message_id=1,\n            dialogue_reference=(str(0), \"\"),\n            target=0,\n            performative=FipaMessage.Performative.ACCEPT,\n        )\n        msg.to = self.address\n        msg.sender = self.address\n        envelope = Envelope(\n            to=msg.to,\n            sender=msg.sender,\n            message=msg,\n        )\n\n        self.my_error_handler.send_unsupported_skill(envelope=envelope)\n\n        wait_for_condition(lambda: len(self.my_aea._inbox._history) >= 1, timeout=5)\n        envelope = self.my_aea._inbox._history[-1]\n\n        msg = envelope.message\n        assert msg.performative == DefaultMessage.Performative.ERROR\n        assert msg.error_code == DefaultMessage.ErrorCode.UNSUPPORTED_SKILL\n\n    def test_error_unsupported_skill_when_skill_id_is_none(self):\n        \"\"\"Test the 'send_unsupported_skill' when the skill id in the envelope is None.\"\"\"\n        protocol_id = PublicId.from_str(\"author/name:0.1.0\")\n        envelope = Envelope(\n            to=\"\",\n            sender=\"\",\n            protocol_specification_id=protocol_id,\n            message=b\"\",\n        )\n        with unittest.mock.patch.object(self.skill_context.outbox, \"put_message\"):\n            with unittest.mock.patch.object(\n                self.skill_context._logger, \"warning\"\n            ) as mock_logger_warning:\n                self.my_error_handler.send_unsupported_skill(envelope)\n                mock_logger_warning.assert_called_with(\n                    f\"Cannot handle envelope: no active handler registered for the protocol_specification_id='{protocol_id}'.\"\n                )\n\n    def teardown(self):\n        \"\"\"Teardown method.\"\"\"\n        self.my_aea.stop()\n        self.t.join()\n"
  },
  {
    "path": "tests/test_aea/test_skills/test_scaffold.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains tests for the scaffold skill.\"\"\"\nfrom unittest.mock import MagicMock\n\nimport pytest\n\nfrom aea.skills.base import SkillContext\nfrom aea.skills.scaffold.behaviours import MyScaffoldBehaviour\nfrom aea.skills.scaffold.handlers import MyScaffoldHandler\nfrom aea.skills.scaffold.my_model import MyModel\n\n\nclass TestScaffoldHandler:\n    \"\"\"Tests for the scaffold handler.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set up the tests.\"\"\"\n        cls.handler = MyScaffoldHandler(\"handler\", SkillContext())\n\n    def test_supported_protocol(self):\n        \"\"\"Test that the supported protocol is None.\"\"\"\n        assert self.handler.SUPPORTED_PROTOCOL is None\n\n    def test_setup(self):\n        \"\"\"Test that the setup method raises 'NotImplementedError'.\"\"\"\n        with pytest.raises(NotImplementedError):\n            self.handler.setup()\n\n    def test_handle(self):\n        \"\"\"Test that the handle method raises 'NotImplementedError'.\"\"\"\n        with pytest.raises(NotImplementedError):\n            self.handler.handle(MagicMock())\n\n    def test_teardown(self):\n        \"\"\"Test that the teardown method raises 'NotImplementedError'.\"\"\"\n        with pytest.raises(NotImplementedError):\n            self.handler.teardown()\n\n\nclass TestScaffoldBehaviour:\n    \"\"\"Tests for the scaffold behaviour.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set up the tests.\"\"\"\n        cls.behaviour = MyScaffoldBehaviour(\"behaviour\", SkillContext())\n\n    def test_setup(self):\n        \"\"\"Test that the setup method raises 'NotImplementedError'.\"\"\"\n        with pytest.raises(NotImplementedError):\n            self.behaviour.setup()\n\n    def test_handle(self):\n        \"\"\"Test that the handle method raises 'NotImplementedError'.\"\"\"\n        with pytest.raises(NotImplementedError):\n            self.behaviour.act()\n\n    def test_teardown(self):\n        \"\"\"Test that the teardown method raises 'NotImplementedError'.\"\"\"\n        with pytest.raises(NotImplementedError):\n            self.behaviour.teardown()\n\n\ndef test_model_initialization():\n    \"\"\"Test scaffold model initialization.\"\"\"\n    MyModel(\"model\", SkillContext())\n"
  },
  {
    "path": "tests/test_aea/test_skills/test_task_subprocess.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests for subprocess task manager/tasl_test_skill.\"\"\"\nfrom aea.test_tools.test_cases import AEATestCaseEmpty\n\n\nclass TestTaskTestSkill(AEATestCaseEmpty):\n    \"\"\"Test task manager subprocess run a simple task.\"\"\"\n\n    capture_log = True\n\n    @classmethod\n    def setup_class(cls) -> None:\n        \"\"\"Init the test case.\"\"\"\n        super(TestTaskTestSkill, cls).setup_class()\n        cls.add_item(\"skill\", \"fetchai/task_test_skill:0.1.2\", local=True)\n        cls.generate_private_key()\n        cls.add_private_key()\n        cls.set_config(\"agent.task_manager_mode\", \"multiprocess\", \"str\")\n\n    def test_task_run_in_a_subprocess(self):\n        \"\"\"Test task run in a subporocess.\"\"\"\n        process = self.run_agent()\n        try:\n            is_running = self.is_running(process)\n            assert is_running, \"AEA not running within timeout!\"\n            assert not self.missing_from_output(\n                process, [\"Task id is\"], 10, is_terminating=False\n            )\n            assert not self.missing_from_output(\n                process, [\"result is\"], 10, is_terminating=False\n            )\n        finally:\n            process.terminate()\n            process.wait(10)\n            print(self.stdout[process.pid])\n            print(self.stderr[process.pid])\n"
  },
  {
    "path": "tests/test_aea/test_skills/test_tasks.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests for the tasks module.\"\"\"\n\nfrom unittest import TestCase, mock\nfrom unittest.mock import Mock, patch\n\nfrom aea.skills.tasks import Task, TaskManager\n\n\ndef _raise_exception(self, *args, **kwargs):\n    raise Exception()\n\n\nclass TaskTestCase(TestCase):\n    \"\"\"Test case for Task class.\"\"\"\n\n    def test_call_positive(self):\n        \"\"\"Test call obj positive result.\"\"\"\n        obj = Task()\n        obj.setup = mock.Mock()\n        obj.execute = mock.Mock()\n        obj.teardown = mock.Mock()\n        obj()\n\n    def test_call_already_executed(self):\n        \"\"\"Test call obj already executed.\"\"\"\n        obj = Task()\n        obj._is_executed = True\n        with self.assertRaises(ValueError):\n            obj()\n\n    def test_call_exception_while_executing(self):\n        \"\"\"Test call obj exception raised while executing.\"\"\"\n        obj = Task()\n        with mock.patch.object(obj.logger, \"debug\") as debug_mock:\n            obj.setup = mock.Mock()\n            obj.execute = _raise_exception\n            obj.teardown = mock.Mock()\n            obj()\n            debug_mock.assert_called_once()\n\n    def test_is_executed_positive(self):\n        \"\"\"Test is_executed property positive result.\"\"\"\n        obj = Task()\n        obj.is_executed\n\n    def test_result_positive(self):\n        \"\"\"Test result property positive result.\"\"\"\n        obj = Task()\n        obj._is_executed = True\n        obj.result\n\n    def test_result_not_executed(self):\n        \"\"\"Test result property task not executed.\"\"\"\n        obj = Task()\n        with self.assertRaises(ValueError):\n            obj.result\n\n\nclass InitWorkerTestCase(TestCase):\n    \"\"\"Test case for init_worker method.\"\"\"\n\n    @mock.patch(\"aea.skills.tasks._init_worker\")\n    def test_init_worker_positive(self, init_worker_mock):\n        \"\"\"Test init_worker method positive result.\"\"\"\n        task_manager = TaskManager(is_lazy_pool_start=False)\n        task_manager.start()\n        try:\n            init_worker_mock.assert_called()\n        finally:\n            task_manager.stop()\n\n\nclass TaskManagerTestCase(TestCase):\n    \"\"\"Test case for TaskManager class.\"\"\"\n\n    def test_nb_workers_positive(self):\n        \"\"\"Test nb_workers property positive result.\"\"\"\n        obj = TaskManager()\n        obj.nb_workers\n\n    def test_stop_already_stopped(self):\n        \"\"\"Test stop method already stopped.\"\"\"\n        obj = TaskManager()\n        with mock.patch.object(obj.logger, \"debug\") as debug_mock:\n            obj.stop()\n            debug_mock.assert_called_once()\n\n    def test_start_already_started(self):\n        \"\"\"Test start method already started.\"\"\"\n        obj = TaskManager()\n        with mock.patch.object(obj.logger, \"debug\") as debug_mock:\n            obj._stopped = False\n            obj.start()\n            debug_mock.assert_called_once()\n            obj.stop()\n\n    def test_start_lazy_pool_start(self):\n        \"\"\"Test start method with lazy pool start.\"\"\"\n        obj = TaskManager(is_lazy_pool_start=False)\n        with mock.patch.object(obj.logger, \"debug\") as debug_mock:\n            obj.start()\n            obj._stopped = True\n            obj.start()\n            debug_mock.assert_called_with(\"Pool was already started!\")\n            obj.start()\n\n    def test_enqueue_task_stopped(self):\n        \"\"\"Test enqueue_task method manager stopped.\"\"\"\n        obj = TaskManager()\n        func = mock.Mock()\n        with self.assertRaises(ValueError):\n            obj.enqueue_task(func)\n            func.assert_not_called()\n\n    def test_enqueue_task_positive(self):\n        \"\"\"Test enqueue_task method positive result.\"\"\"\n        obj = TaskManager()\n        func = mock.Mock()\n        obj._stopped = False\n        obj._pool = mock.Mock()\n        obj._pool.apply_async = mock.Mock(return_value=\"async_result\")\n        obj.enqueue_task(func)\n        obj._pool.apply_async.assert_called_once()\n\n    def test_get_task_result_id_not_present(self):\n        \"\"\"Test get_task_result method id not present.\"\"\"\n        obj = TaskManager()\n        with self.assertRaises(ValueError):\n            obj.get_task_result(\"task_id\")\n\n    def test_get_task_result_positive(self):\n        \"\"\"Test get_task_result method positive result.\"\"\"\n        obj = TaskManager()\n        obj._results_by_task_id = {\"task_id\": \"result\"}\n        obj.get_task_result(\"task_id\")\n\n\nclass TestTaskPoolManagementManager(TestCase):\n    \"\"\"Tests for pool management by task manager. Lazy and non lazy.\"\"\"\n\n    def tearDown(self):\n        \"\"\"Stop task manager. assumed it's created on each test.\"\"\"\n        self.task_manager.stop()\n\n    def test_start_stop_reflected_by_is_started(self) -> None:\n        \"\"\"Test is_started property of task manaher.\"\"\"\n        self.task_manager = TaskManager()\n        assert not self.task_manager.is_started\n        self.task_manager.start()\n        assert self.task_manager.is_started\n\n        self.task_manager.stop()\n        assert not self.task_manager.is_started\n\n    def test_lazy_pool_not_started(self) -> None:\n        \"\"\"Lazy pool creation assumes pool create on first task enqueue.\"\"\"\n        self.task_manager = TaskManager(is_lazy_pool_start=True)\n        self.task_manager.start()\n        assert not self.task_manager._pool\n\n    def test_not_lazy_pool_is_started(self) -> None:\n        \"\"\"Lazy pool creation assumes pool create on first task enqueue.\"\"\"\n        self.task_manager = TaskManager(is_lazy_pool_start=False)\n        self.task_manager.start()\n        assert self.task_manager._pool\n\n    @patch(\"aea.skills.tasks.Pool.apply_async\")\n    def test_lazy_pool_start_on_enqueue(self, apply_async_mock: Mock) -> None:\n        \"\"\"\n        Test lazy pool created on enqueue once.\n\n        :param apply_async_mock: is mock for aea.skills.tasks.Pool.apply_async\n        \"\"\"\n        self.task_manager = TaskManager(is_lazy_pool_start=True)\n        self.task_manager.start()\n        assert not self.task_manager._pool\n\n        self.task_manager.enqueue_task(print)\n\n        apply_async_mock.assert_called_once()\n        assert self.task_manager._pool\n\n        \"\"\"Check pool created once on several enqueues\"\"\"\n        pool = self.task_manager._pool\n\n        self.task_manager.enqueue_task(print)\n\n        assert self.task_manager._pool is pool\n"
  },
  {
    "path": "tests/test_aea/test_task.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests for the task manager.\"\"\"\nfrom multiprocessing.pool import AsyncResult\n\nimport pytest\n\nfrom aea.skills.tasks import Task, TaskManager\n\n\nclass MyTask(Task):\n    \"\"\"Test class for a task.\"\"\"\n\n    def __init__(self, return_value):\n        \"\"\"Initialise test task.\"\"\"\n        super().__init__()\n        self.setup_called = False\n        self.teardown_called = False\n        self.execute_called = False\n        self.execute_args = None\n        self.execute_kwargs = None\n        self.return_value = return_value\n\n    def setup(self) -> None:\n        \"\"\"Setup task.\"\"\"\n        self.setup_called = True\n\n    def execute(self, *args, **kwargs) -> None:\n        \"\"\"Execute task.\"\"\"\n        self.execute_called = True\n        self.execute_args = args\n        self.execute_kwargs = kwargs\n        return self.return_value\n\n    def teardown(self) -> None:\n        \"\"\"Teardown task.\"\"\"\n        self.teardown_called = True\n\n\nclass TestTaskManager:\n    \"\"\"Test the features of the task manager.\"\"\"\n\n    WAIT_TIMEOUT = 20.0\n\n    def _return_a_constant(self, a: int, b: int = 10):\n        return a + b\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the tests up.\"\"\"\n        cls.task_manager = TaskManager(nb_workers=5)\n        cls.task_manager.start()\n\n    def test_task_manager_function_with_default_arguments(self):\n        \"\"\"Test a function submitted to the task manager with default arguments.\"\"\"\n        task_id = self.task_manager.enqueue_task(self._return_a_constant, args=(32,))\n        task_result = self.task_manager.get_task_result(task_id)\n        assert isinstance(task_result, AsyncResult)\n        result = task_result.get(self.WAIT_TIMEOUT)\n        assert result == 42\n\n    def test_task_manager_function_with_keyword_arguments(self):\n        \"\"\"Test a function submitted to the task manager with keyword arguments.\"\"\"\n        task_id = self.task_manager.enqueue_task(\n            self._return_a_constant, args=(32,), kwargs={\"b\": 10}\n        )\n        task_result = self.task_manager.get_task_result(task_id)\n        assert isinstance(task_result, AsyncResult)\n        result = task_result.get(self.WAIT_TIMEOUT)\n        assert result == 42\n\n    def test_task_manager_function_with_wrong_argument_number(self):\n        \"\"\"Test wrong number of arguments.\"\"\"\n        task_id = self.task_manager.enqueue_task(\n            self._return_a_constant, args=(), kwargs={\"b\": 10}\n        )\n        task_result = self.task_manager.get_task_result(task_id)\n        assert isinstance(task_result, AsyncResult)\n        with pytest.raises(TypeError, match=\"missing .+ required positional argument:\"):\n            task_result.get(self.WAIT_TIMEOUT)\n\n    def test_task_manager_task_object(self):\n        \"\"\"Test task manager with task object.\"\"\"\n        expected_args = (0, 1)\n        expected_kwargs = {\"a\": 0, \"b\": 2}\n        expected_return_value = 42\n        my_task = MyTask(return_value=expected_return_value)\n        task_id = self.task_manager.enqueue_task(\n            my_task, args=expected_args, kwargs=expected_kwargs\n        )\n        task_result = self.task_manager.get_task_result(task_id)\n        assert isinstance(task_result, AsyncResult)\n\n        result = task_result.get(self.WAIT_TIMEOUT)\n        assert result == expected_return_value\n\n    @pytest.mark.skip\n    def test_task_manager_task_object_fails_when_not_pickable(self):\n        \"\"\"Test task manager with task object fails when the task is not pickable.\"\"\"\n        expected_args = [lambda x: x]\n        my_task = MyTask(return_value=None)\n        task_id = self.task_manager.enqueue_task(my_task, args=expected_args)\n        task_result = self.task_manager.get_task_result(task_id)\n        assert isinstance(task_result, AsyncResult)\n\n        with pytest.raises(AttributeError, match=\"Can't pickle local object\"):\n            task_result.get(self.WAIT_TIMEOUT)  # noqaexpected_task.result\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear the test down.\"\"\"\n        cls.task_manager.stop()\n"
  },
  {
    "path": "tests/test_aea/test_test_tools/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains a test for aea.test_tools.\"\"\"\n"
  },
  {
    "path": "tests/test_aea/test_test_tools/test_click_testing.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains a test for aea.test_tools.\"\"\"\nfrom unittest.mock import patch\n\nimport pytest\n\nfrom aea.cli.core import cli\nfrom aea.test_tools.click_testing import CliRunner\n\n\ndef test_invoke():\n    \"\"\"Test runner invoke method.\"\"\"\n    cli_runner = CliRunner()\n\n    result = cli_runner.invoke(cli, [\"--help\"])\n    assert (\n        \"Command-line tool for setting up an Autonomous Economic Agent\" in result.output\n    )\n\n    result = cli_runner.invoke(cli, \"--help\")\n    assert (\n        \"Command-line tool for setting up an Autonomous Economic Agent\" in result.output\n    )\n\n\ndef test_invoke_error():\n    \"\"\"Test runner invoke method raises an error.\"\"\"\n    cli_runner = CliRunner()\n\n    with patch.object(cli, \"main\", side_effect=SystemExit(1)):\n        result = cli_runner.invoke(cli, [\"--help\"])\n        assert result.exit_code == 1\n\n    with patch.object(cli, \"main\", side_effect=SystemExit(object())):\n        result = cli_runner.invoke(cli, [\"--help\"])\n        assert result.exit_code == 1\n\n\ndef test_catch_exception():\n    \"\"\"Test runner invoke method raises an exception and its propogated.\"\"\"\n    cli_runner = CliRunner()\n\n    # True\n    with patch.object(cli, \"main\", side_effect=ValueError(\"expected\")):\n        result = cli_runner.invoke(cli, [\"--help\"])\n        assert result.exit_code == 1\n\n    # False\n\n    with pytest.raises(ValueError, match=\"expected\"):\n        with patch.object(cli, \"main\", side_effect=ValueError(\"expected\")):\n            result = cli_runner.invoke(cli, [\"--help\"], catch_exceptions=False)\n\n\ndef test_mix_std_err_False():\n    \"\"\"Test stderr and stdout not mixed.\"\"\"\n    cli_runner = CliRunner(mix_stderr=False)\n\n    result = cli_runner.invoke(cli, \"-v DEBUG run\")\n    assert result.exit_code == 1\n    # check for access, no exception should be raised\n    result.stderr\n\n\ndef test_mix_std_err_True():\n    \"\"\"Test stderr and stdout are mixed.\"\"\"\n    cli_runner = CliRunner(mix_stderr=True)\n\n    result = cli_runner.invoke(cli, \"-v DEBUG run\")\n    assert result.exit_code == 1\n\n    with pytest.raises(ValueError):\n        result.stderr\n"
  },
  {
    "path": "tests/test_aea/test_test_tools/test_test_cases.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains a test for aea.test_tools.test_cases.\"\"\"\n\nimport os\nimport time\nfrom pathlib import Path\nfrom unittest import mock\n\nimport pytest\nimport yaml\nfrom aea_ledger_fetchai import FetchAICrypto\n\nimport aea\nfrom aea.configurations.base import AgentConfig\nfrom aea.configurations.constants import DEFAULT_AEA_CONFIG_FILE\nfrom aea.mail.base import Envelope\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue\nfrom aea.test_tools.exceptions import AEATestingException\nfrom aea.test_tools.test_cases import (\n    AEATestCase,\n    AEATestCaseEmpty,\n    AEATestCaseEmptyFlaky,\n    AEATestCaseManyFlaky,\n    BaseAEATestCase,\n)\n\nfrom packages.fetchai.connections.stub.connection import PUBLIC_ID as STUB_CONNECTION_ID\nfrom packages.fetchai.protocols.default.dialogues import (\n    DefaultDialogue,\n    DefaultDialogues,\n)\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.skills.echo import PUBLIC_ID as ECHO_SKILL_PUBLIC_ID\nfrom packages.fetchai.skills.error import PUBLIC_ID as ERROR_SKILL_PUBLIC_ID\n\nfrom tests.conftest import MAX_FLAKY_RERUNS, MY_FIRST_AEA_PUBLIC_ID\nfrom tests.test_aea.test_cli import test_generate_wealth, test_interact\n\n\nTestWealthCommandsPositive = test_generate_wealth.TestWealthCommandsPositive\nTestInteractCommand = test_interact.TestInteractCommand\n\n\nclass TestConfigCases(AEATestCaseEmpty):\n    \"\"\"Test config set/get.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Setup class.\"\"\"\n        super(TestConfigCases, cls).setup_class()\n        cls.add_item(\"connection\", str(STUB_CONNECTION_ID))\n        cls.add_item(\"skill\", str(ERROR_SKILL_PUBLIC_ID))\n\n    def test_agent_nested_set_agent_crudcollection(self):\n        \"\"\"Test agent test nested set from path.\"\"\"\n        key_name = \"agent.private_key_paths.cosmos\"\n        self.nested_set_config(key_name, \"testdata2000\")\n        result = self.run_cli_command(\"config\", \"get\", key_name, cwd=self._get_cwd())\n        assert b\"testdata2000\" in result.stdout_bytes\n\n    def test_agent_nested_set_agent_crudcollection_all(self):\n        \"\"\"Test agent test nested set from path.\"\"\"\n        key_name = \"agent.private_key_paths\"\n        self.nested_set_config(key_name, {\"cosmos\": \"testdata2000\"})\n        result = self.run_cli_command(\n            \"config\", \"get\", f\"{key_name}.cosmos\", cwd=self._get_cwd()\n        )\n        assert b\"testdata2000\" in result.stdout_bytes\n\n    def test_agent_nested_set_agent_simple(self):\n        \"\"\"Test agent test nested set from path.\"\"\"\n        key_name = \"agent.default_ledger\"\n        self.nested_set_config(key_name, \"some_ledger\")\n        result = self.run_cli_command(\"config\", \"get\", key_name, cwd=self._get_cwd())\n        assert b\"some_ledger\" in result.stdout_bytes\n\n    def test_agent_nested_set_skill_simple(self):\n        \"\"\"Test agent test nested set from path.\"\"\"\n        key_name = \"vendor.fetchai.skills.error.handlers.error_handler.args.some_key\"\n        self.nested_set_config(key_name, \"some_value\")\n        result = self.run_cli_command(\"config\", \"get\", key_name, cwd=self._get_cwd())\n        assert b\"some_value\" in result.stdout_bytes\n\n    def test_agent_nested_set_skill_simple_nested(self):\n        \"\"\"Test agent test nested set from path.\"\"\"\n        key_name = \"vendor.fetchai.skills.error.handlers.error_handler.args.some_key\"\n        self.nested_set_config(f\"{key_name}.some_nested_key\", \"some_value\")\n\n    def test_agent_nested_set_skill_all(self):\n        \"\"\"Test agent test nested set from path.\"\"\"\n        key_name = \"vendor.fetchai.skills.error.handlers.error_handler.args\"\n        self.nested_set_config(key_name, {\"some_key\": \"some_value\"})\n        result = self.run_cli_command(\n            \"config\", \"get\", f\"{key_name}.some_key\", cwd=self._get_cwd()\n        )\n        assert b\"some_value\" in result.stdout_bytes\n\n    def test_agent_nested_set_skill_all_nested(self):\n        \"\"\"Test agent test nested set from path.\"\"\"\n        key_name = \"vendor.fetchai.skills.error.handlers.error_handler.args\"\n        self.nested_set_config(\n            key_name, {\"some_key\": {\"some_nested_key\": \"some_value\"}}\n        )\n\n    def test_agent_nested_set_connection_simple(self):\n        \"\"\"Test agent test nested set from path.\"\"\"\n        key_name = \"vendor.fetchai.connections.stub.config.input_file\"\n        self.nested_set_config(key_name, \"some_value\")\n        result = self.run_cli_command(\"config\", \"get\", key_name, cwd=self._get_cwd())\n        assert b\"some_value\" in result.stdout_bytes\n\n    def test_agent_nested_set_connection_dependency(self):\n        \"\"\"Test agent test nested set from path.\"\"\"\n        key_name = \"vendor.fetchai.connections.stub.dependencies\"\n        self.nested_set_config(key_name, {\"dep\": {\"version\": \"==1.0.0\"}})\n\n    def test_agent_set(self):\n        \"\"\"Test agent test set from path.\"\"\"\n        value = True\n        key_name = \"agent.logging_config.disable_existing_loggers\"\n        self.set_config(key_name, value)\n        result = self.run_cli_command(\"config\", \"get\", key_name, cwd=self._get_cwd())\n        assert str(value) in str(result.stdout_bytes)\n\n    def test_agent_get_exception(self):\n        \"\"\"Test agent test get non exists key.\"\"\"\n        with pytest.raises(Exception, match=\".*bad_key.*\"):\n            self.run_cli_command(\"config\", \"get\", \"agent.bad_key\", cwd=self._get_cwd())\n\n\nclass TestRunAgent(AEATestCaseEmpty):\n    \"\"\"Tests test for generic cases of AEATestCases.\"\"\"\n\n    def test_run_agent(self):\n        \"\"\"Run agent and test it's launched.\"\"\"\n        self.generate_private_key()\n        self.add_private_key()\n        process = self.run_agent()\n        assert self.is_running(process, timeout=30)\n\n\nclass TestGenericCases(AEATestCaseEmpty):\n    \"\"\"Tests test for generic cases of AEATestCases.\"\"\"\n\n    def test_disable_aea_logging(self):\n        \"\"\"Call logging disable.\"\"\"\n        self.disable_aea_logging()\n\n    def test_start_subprocess(self):\n        \"\"\"Start a python subprocess and check output.\"\"\"\n        proc = self.start_subprocess(\"-c\", \"print('hi')\")\n        proc.wait(10)\n\n        assert \"hi\" in self.stdout[proc.pid]\n\n    def test_start_thread(self):\n        \"\"\"Start and join thread for python code.\"\"\"\n        called = False\n\n        def fn():\n            nonlocal called\n            called = True\n\n        thread = self.start_thread(fn)\n        thread.join()\n        assert called\n\n    def test_fetch_and_delete(self):\n        \"\"\"Fetch and delete agent from repo.\"\"\"\n        agent_name = \"some_agent_for_tests\"\n        self.fetch_agent(str(MY_FIRST_AEA_PUBLIC_ID), agent_name)\n        assert os.path.exists(agent_name)\n        self.delete_agents(agent_name)\n        assert not os.path.exists(agent_name)\n\n    def test_diff(self):\n        \"\"\"Test difference_to_fetched_agent.\"\"\"\n        agent_name = \"some_agent_for_tests2\"\n        self.fetch_agent(str(MY_FIRST_AEA_PUBLIC_ID), agent_name)\n        self.run_cli_command(\n            \"config\", \"set\", \"agent.default_ledger\", \"test_ledger\", cwd=agent_name\n        )\n        result = self.run_cli_command(\n            \"config\", \"get\", \"agent.default_ledger\", cwd=agent_name\n        )\n        assert b\"test_ledger\" in result.stdout_bytes\n        diff = self.difference_to_fetched_agent(str(MY_FIRST_AEA_PUBLIC_ID), agent_name)\n        assert diff\n        assert \"test_ledger\" in diff[1]\n\n    def test_no_diff(self):\n        \"\"\"Test no difference for two aea configs.\"\"\"\n        agent_name = \"some_agent_for_tests3\"\n        self.fetch_agent(str(MY_FIRST_AEA_PUBLIC_ID), agent_name)\n        diff = self.difference_to_fetched_agent(str(MY_FIRST_AEA_PUBLIC_ID), agent_name)\n        assert not diff\n\n    def test_diff_different_overrides(self):\n        \"\"\"Test difference due to overrides.\"\"\"\n        agent_name = \"some_agent_for_tests4\"\n        self.fetch_agent(str(MY_FIRST_AEA_PUBLIC_ID), agent_name)\n        self.set_agent_context(agent_name)\n        self.run_cli_command(\n            \"config\",\n            \"set\",\n            \"vendor.fetchai.skills.echo.behaviours.echo.args.tick_interval\",\n            \"2.0\",\n            cwd=self._get_cwd(),\n        )\n        diff = self.difference_to_fetched_agent(str(MY_FIRST_AEA_PUBLIC_ID), agent_name)\n        assert diff\n        assert diff[0] == DEFAULT_AEA_CONFIG_FILE\n\n    def test_terminate_subprocesses(self):\n        \"\"\"Start and terminate long running python subprocess.\"\"\"\n        proc = self.start_subprocess(\"-c\", \"import time; time.sleep(10)\")\n        assert proc.returncode is None\n        self._terminate_subprocesses()\n        assert proc.returncode is not None\n\n    def test_miss_from_output(self):\n        \"\"\"Test subprocess output missing output.\"\"\"\n        proc = self.start_subprocess(\"-c\", \"print('hi')\")\n        assert len(self.missing_from_output(proc, [\"hi\"], timeout=5)) == 0\n        assert \"HI\" in self.missing_from_output(proc, [\"HI\"], timeout=5)\n\n    def test_replace_file_content(self):\n        \"\"\"Replace content of the file with another one.\"\"\"\n        file1 = \"file1.txt\"\n        file2 = \"file2.txt\"\n\n        with open(file1, \"w\") as f:\n            f.write(\"hi\")\n\n        with open(file2, \"w\") as f:\n            f.write(\"world\")\n\n        self.replace_file_content(Path(file1), Path(file2))\n\n        with open(file2, \"r\") as f:\n            assert f.read() == \"hi\"\n\n\nclass TestDifferenceToFetchedAgent(BaseAEATestCase):\n    \"\"\"Test 'different_to_fetched_agent' in case of component overrides.\"\"\"\n\n    _mock_called = False\n    original_function = yaml.safe_load_all\n    test_agent_name: str\n\n    @classmethod\n    def setup_class(cls) -> None:\n        \"\"\"Set up the class.\"\"\"\n        super().setup_class()\n\n        # build aea, and override the tick interval\n        cls.test_agent_name = \"test_agent\"\n        cls.fetch_agent(str(MY_FIRST_AEA_PUBLIC_ID), cls.test_agent_name)\n        cls.set_agent_context(cls.test_agent_name)\n        cls.run_cli_command(\n            \"config\",\n            \"set\",\n            \"vendor.fetchai.skills.echo.behaviours.echo.args.tick_interval\",\n            \"2.0\",\n            cwd=cls._get_cwd(),\n        )\n\n    @classmethod\n    def _safe_load_all_side_effect(cls, file):\n        \"\"\"Implement yaml.safe_load_all side-effect for testing.\"\"\"\n        result = list(cls.original_function(file))\n        if not cls._mock_called:\n            cls._mock_called = True\n            fake_override = {}\n            result.append(fake_override)\n        return iter(result)\n\n    def test_difference_to_fetched_agent(self, *_mocks):\n        \"\"\"Test difference to fetched agent.\"\"\"\n        with mock.patch(\n            \"yaml.safe_load_all\", side_effect=self._safe_load_all_side_effect\n        ):\n            file_diff = self.difference_to_fetched_agent(\n                str(MY_FIRST_AEA_PUBLIC_ID), self.test_agent_name\n            )\n            assert file_diff\n\n\nclass TestLoadAgentConfig(AEATestCaseEmpty):\n    \"\"\"Test function 'load_agent_config'.\"\"\"\n\n    def test_load_agent_config(self):\n        \"\"\"Test load_agent_config.\"\"\"\n        agent_config = self.load_agent_config(self.agent_name)\n        assert isinstance(agent_config, AgentConfig)\n\n    def test_load_agent_config_when_agent_name_not_exists(self):\n        \"\"\"Test load_agent_config with a wrong agent name.\"\"\"\n        wrong_agent_name = \"non-existing-agent-name\"\n        with pytest.raises(\n            AEATestingException,\n            match=f\"Cannot find agent '{wrong_agent_name}' in the current test case.\",\n        ):\n            self.load_agent_config(wrong_agent_name)\n\n\nclass TestAddAndEjectComponent(AEATestCaseEmpty):\n    \"\"\"Test add/reject components.\"\"\"\n\n    def test_add_and_eject(self):\n        \"\"\"Test add/reject components.\"\"\"\n        result = self.add_item(\"skill\", str(ECHO_SKILL_PUBLIC_ID), local=True)\n        assert result.exit_code == 0\n\n        result = self.eject_item(\"skill\", str(ECHO_SKILL_PUBLIC_ID))\n        assert result.exit_code == 0\n\n\nclass TestAddAndRemoveComponent(AEATestCaseEmpty):\n    \"\"\"Test add/remove components.\"\"\"\n\n    def test_add_and_eject(self):\n        \"\"\"Test add/reject components.\"\"\"\n        result = self.add_item(\"skill\", str(ECHO_SKILL_PUBLIC_ID), local=True)\n        assert result.exit_code == 0\n\n        result = self.remove_item(\"skill\", str(ECHO_SKILL_PUBLIC_ID))\n        assert result.exit_code == 0\n\n\nclass TestGenerateAndAddKey(AEATestCaseEmpty):\n    \"\"\"Test generate and add private key.\"\"\"\n\n    def test_generate_and_add_key(self):\n        \"\"\"Test generate and add private key.\"\"\"\n        result = self.generate_private_key(\"cosmos\")\n        assert result.exit_code == 0\n        result = self.add_private_key(\n            \"cosmos\", \"cosmos_private_key.txt\", connection=True\n        )\n        assert result.exit_code == 0\n        result = self.add_private_key(\"cosmos\", \"cosmos_private_key.txt\")\n        assert result.exit_code == 0\n\n        result = self.remove_private_key(\"cosmos\")\n        assert result.exit_code == 0\n\n\nclass TestGetWealth(AEATestCaseEmpty):\n    \"\"\"Test get_wealth.\"\"\"\n\n    @pytest.mark.flaky(reruns=MAX_FLAKY_RERUNS)\n    def test_get_wealth(self):\n        \"\"\"Test get_wealth.\"\"\"\n        # just call it, network related and quite unstable\n        self.generate_private_key()\n        self.add_private_key()\n        self.get_wealth(FetchAICrypto.identifier)\n\n\nclass TestGetAddress(AEATestCaseEmpty):\n    \"\"\"Test get_address.\"\"\"\n\n    def test_get_address(self):\n        \"\"\"Test get_address.\"\"\"\n        # just call it, network related and quite unstable\n        self.generate_private_key()\n        self.add_private_key()\n        result = self.get_address(FetchAICrypto.identifier)\n        assert len(result) == 44\n        assert result.startswith(\"fetch\")\n\n\nclass TestAEA(AEATestCase):\n    \"\"\"Test agent test set from path.\"\"\"\n\n    path_to_aea = Path(\"tests\") / \"data\" / \"dummy_aea\"\n\n    def test_scaffold_and_fingerprint(self):\n        \"\"\"Test component scaffold and fingerprint.\"\"\"\n        result = self.scaffold_item(\"skill\", \"skill1\")\n        assert result.exit_code == 0\n\n        result = self.fingerprint_item(\"skill\", \"fetchai/skill1:0.1.0\")\n        assert result.exit_code == 0\n\n    def test_scaffold_and_fingerprint_protocol(self):\n        \"\"\"Test component scaffold and fingerprint protocol.\"\"\"\n        result = self.scaffold_item(\"protocol\", \"protocol1\")\n        assert result.exit_code == 0\n\n        result = self.fingerprint_item(\"protocol\", \"fetchai/protocol1:0.1.0\")\n        assert result.exit_code == 0\n\n\nclass TestSendReceiveEnvelopesSkill(AEATestCaseEmpty):\n    \"\"\"Test that we can communicate with agent via stub connection.\"\"\"\n\n    def test_send_receive_envelope(self):\n        \"\"\"Run the echo skill sequence.\"\"\"\n        self.generate_private_key()\n        self.add_private_key()\n        self.add_item(\"connection\", str(STUB_CONNECTION_ID))\n        self.add_item(\"skill\", str(ECHO_SKILL_PUBLIC_ID))\n\n        process = self.run_agent()\n        is_running = self.is_running(process)\n        assert is_running, \"AEA not running within timeout!\"\n\n        # add sending and receiving envelope from input/output files\n        sender = \"sender\"\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: str\n        ) -> Dialogue.Role:\n            return DefaultDialogue.Role.AGENT\n\n        default_dialogues = DefaultDialogues(sender, role_from_first_message)\n        message_content = b\"hello\"\n        message = DefaultMessage(\n            performative=DefaultMessage.Performative.BYTES,\n            dialogue_reference=default_dialogues.new_self_initiated_dialogue_reference(),\n            content=message_content,\n        )\n        sent_envelope = Envelope(\n            to=self.agent_name,\n            sender=sender,\n            protocol_specification_id=message.protocol_specification_id,\n            message=message,\n        )\n\n        self.send_envelope_to_agent(sent_envelope, self.agent_name)\n\n        time.sleep(2.0)\n        received_envelope = self.read_envelope_from_agent(self.agent_name)\n        received_message = DefaultMessage.serializer.decode(received_envelope.message)\n        assert sent_envelope.message.content == received_message.content\n\n\nclass TestInvoke(AEATestCaseEmpty):\n    \"\"\"Test invoke method.\"\"\"\n\n    def test_invoke(self):\n        \"\"\"Test invoke method.\"\"\"\n        result = self.invoke(\"--version\")\n        assert result.exit_code == 0\n        assert f\"aea, version {aea.__version__}\" in result.stdout\n\n\nclass TestFlakyMany(AEATestCaseManyFlaky):\n    \"\"\"Test that flaky tests are properly rerun.\"\"\"\n\n    @pytest.mark.flaky(reruns=1)\n    def test_fail_on_first_run(self):\n        \"\"\"Test failure on first run leads to second run.\"\"\"\n        file = os.path.join(self.t, \"test_file\")\n        if self.run_count == 1:\n            open(file, \"a\").close()\n            raise AssertionError(\"Expected error to trigger rerun!\")\n        assert self.run_count == 2, \"Should only be rerun once!\"\n        assert not os.path.isfile(file), \"File should not exist\"\n\n\nclass TestFlakyEmpty(AEATestCaseEmptyFlaky):\n    \"\"\"Test that flaky tests are properly rerun.\"\"\"\n\n    @pytest.mark.flaky(reruns=1)\n    def test_fail_on_first_run(self):\n        \"\"\"Test failure on first run leads to second run.\"\"\"\n        file = os.path.join(self.t, \"test_file\")\n        if self.run_count == 1:\n            open(file, \"a\").close()\n            raise AssertionError(\"Expected error to trigger rerun!\")\n        assert self.run_count == 2, \"Should only be rerun once!\"\n        assert not os.path.isfile(file), \"File should not exist\"\n"
  },
  {
    "path": "tests/test_aea/test_test_tools/test_test_contract.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains tests for aea.test_tools.test_contract.BaseContractTestCase.\"\"\"\n\n\nfrom pathlib import Path\nfrom unittest import mock\n\nimport pytest\nfrom aea_ledger_fetchai import CosmosCrypto, FetchAIApi, FetchAICrypto, FetchAIFaucetApi\n\nfrom aea.test_tools.test_contract import BaseContractTestCase\n\nfrom tests.conftest import ROOT_DIR\n\n\nLEDGER_ID = \"fetchai\"\nCONTRACT_ADDRESS = \"contract_address\"\n\nTX_RECEIPT_EXAMPLE = {\"json\": \"like\", \"raw_log\": \"log\"}\n\n\nclass TestContractTestCase(BaseContractTestCase):\n    \"\"\"Test case for BaseContractTestCase.\"\"\"\n\n    path_to_contract = Path(ROOT_DIR, \"tests\", \"data\", \"dummy_contract\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        cls.ledger_identifier = LEDGER_ID\n        cls.fund_from_faucet = True\n\n        with mock.patch.object(\n            BaseContractTestCase,\n            \"sign_send_confirm_receipt_multisig_transaction\",\n            return_value=TX_RECEIPT_EXAMPLE,\n        ):\n            with mock.patch.object(\n                BaseContractTestCase, \"refill_from_faucet\"\n            ) as refill_from_faucet_mock:\n                with mock.patch.object(CosmosCrypto, \"sign_transaction\"):\n                    with mock.patch.object(FetchAIApi, \"get_deploy_transaction\"):\n                        super().setup()\n\n                        refill_from_faucet_mock.assert_called_with(\n                            cls.ledger_api,\n                            cls.faucet_api,\n                            cls.item_owner_crypto.address,\n                        )\n\n    @classmethod\n    def finish_contract_deployment(cls):\n        \"\"\"Finish contract deployment method.\"\"\"\n        return CONTRACT_ADDRESS\n\n    def test_setup(self):\n        \"\"\"Test the setup class method.\"\"\"\n        assert self.ledger_identifier == LEDGER_ID\n        assert type(self.ledger_api) is FetchAIApi\n        assert self.ledger_api.identifier == LEDGER_ID\n\n        assert type(self.deployer_crypto) is FetchAICrypto\n        assert self.deployer_crypto.identifier == LEDGER_ID\n        assert type(self.item_owner_crypto) is FetchAICrypto\n        assert self.item_owner_crypto.identifier == LEDGER_ID\n\n        assert type(self.faucet_api) is FetchAIFaucetApi\n        assert self.faucet_api.identifier == LEDGER_ID\n\n        assert self._contract.__class__.__name__ == \"DummyContract\"\n\n        assert self.contract_address == CONTRACT_ADDRESS\n        assert self.fund_from_faucet is True\n        assert self.deployment_tx_receipt == TX_RECEIPT_EXAMPLE\n\n    def test_contract_property(self):\n        \"\"\"Test contract property.\"\"\"\n        assert self.contract is self._contract\n        delattr(self.__class__, \"_contract\")\n        with pytest.raises(\n            ValueError, match=\"Ensure the contract is set during setup.\"\n        ):\n            self.contract\n\n    @mock.patch.object(FetchAIFaucetApi, \"get_wealth\")\n    def test_refill_from_faucet(self, get_wealth_mock):\n        \"\"\"Test the refill_from_faucet static method.\"\"\"\n        with pytest.raises(ValueError) as e:\n            self.refill_from_faucet(\n                self.ledger_api, self.faucet_api, self.contract_address\n            )\n            assert str(e) == \"Balance not increased!\"\n        get_wealth_mock.assert_called_once_with(CONTRACT_ADDRESS)\n\n    @mock.patch(\"aea.contracts.base.Contract.get_deploy_transaction\", return_value=\"tx\")\n    @mock.patch.object(\n        BaseContractTestCase,\n        \"sign_send_confirm_receipt_multisig_transaction\",\n        return_value=TX_RECEIPT_EXAMPLE,\n    )\n    def test__deploy_contract(\n        self,\n        sign_send_confirm_receipt_multisig_transaction_mock,\n        get_deploy_transaction_mock,\n    ):\n        \"\"\"Test the _deploy_contract class method.\"\"\"\n        gas = 1\n        result = self._deploy_contract(\n            self.contract, self.ledger_api, self.deployer_crypto, gas\n        )\n        assert result == TX_RECEIPT_EXAMPLE\n        sign_send_confirm_receipt_multisig_transaction_mock.assert_called_once_with(\n            \"tx\", self.ledger_api, [self.deployer_crypto]\n        )\n        get_deploy_transaction_mock.assert_called_once_with(\n            ledger_api=self.ledger_api,\n            deployer_address=self.deployer_crypto.address,\n            gas=gas,\n        )\n\n    @mock.patch(\"aea.contracts.base.Contract.get_deploy_transaction\", return_value=None)\n    @mock.patch.object(\n        BaseContractTestCase,\n        \"sign_send_confirm_receipt_multisig_transaction\",\n        return_value=TX_RECEIPT_EXAMPLE,\n    )\n    def test__deploy_contract_tx_not_found(\n        self,\n        sign_send_confirm_receipt_multisig_transaction_mock,\n        get_deploy_transaction_mock,\n    ):\n        \"\"\"Test the _deploy_contract class method.\"\"\"\n        gas = 1\n        with pytest.raises(ValueError) as e:\n            self._deploy_contract(\n                self.contract, self.ledger_api, self.deployer_crypto, gas\n            )\n            assert str(e) == \"Deploy transaction not found!\"\n        sign_send_confirm_receipt_multisig_transaction_mock.assert_not_called()\n        get_deploy_transaction_mock.assert_called_once_with(\n            ledger_api=self.ledger_api,\n            deployer_address=self.deployer_crypto.address,\n            gas=gas,\n        )\n\n    @mock.patch.object(FetchAICrypto, \"sign_transaction\", return_value=\"tx\")\n    @mock.patch.object(FetchAIApi, \"send_signed_transaction\", return_value=\"tx_digest\")\n    @mock.patch.object(\n        FetchAIApi, \"get_transaction_receipt\", return_value=TX_RECEIPT_EXAMPLE\n    )\n    @mock.patch.object(FetchAIApi, \"is_transaction_settled\", return_value=True)\n    def test_sign_send_confirm_receipt_multisig_transaction(\n        self,\n        is_transaction_settled_mock,\n        get_transaction_receipt_mock,\n        send_signed_transaction_mock,\n        sign_transaction_mock,\n    ):\n        \"\"\"Test the sign_send_confirm_receipt_multisig_transaction static method.\"\"\"\n        sleep_time = 0\n        tx = \"tx\"\n        result = self.sign_send_confirm_receipt_multisig_transaction(\n            tx, self.ledger_api, [self.deployer_crypto], sleep_time=sleep_time\n        )\n        assert result == TX_RECEIPT_EXAMPLE\n        is_transaction_settled_mock.assert_called_once_with(TX_RECEIPT_EXAMPLE)\n        get_transaction_receipt_mock.assert_called_with(\"tx_digest\")\n        send_signed_transaction_mock.assert_called_once_with(tx)\n        sign_transaction_mock.assert_called_once_with(tx)\n\n    @mock.patch.object(FetchAICrypto, \"sign_transaction\", return_value=\"tx\")\n    @mock.patch.object(FetchAIApi, \"send_signed_transaction\", return_value=None)\n    @mock.patch.object(FetchAIApi, \"get_transaction_receipt\")\n    @mock.patch.object(FetchAIApi, \"is_transaction_settled\")\n    def test_sign_send_confirm_receipt_multisig_transaction_digest_not_found(\n        self,\n        is_transaction_settled_mock,\n        get_transaction_receipt_mock,\n        send_signed_transaction_mock,\n        sign_transaction_mock,\n    ):\n        \"\"\"Test the sign_send_confirm_receipt_multisig_transaction static method: digest not found.\"\"\"\n        tx = \"tx\"\n        with pytest.raises(ValueError, match=\"Transaction digest not found!\"):\n            self.sign_send_confirm_receipt_multisig_transaction(\n                tx,\n                self.ledger_api,\n                [self.deployer_crypto],\n            )\n        is_transaction_settled_mock.assert_not_called()\n        get_transaction_receipt_mock.assert_not_called()\n        send_signed_transaction_mock.assert_called_once_with(tx)\n        sign_transaction_mock.assert_called_once_with(tx)\n\n    @mock.patch.object(FetchAICrypto, \"sign_transaction\", return_value=\"tx\")\n    @mock.patch.object(FetchAIApi, \"send_signed_transaction\", return_value=\"tx_digest\")\n    @mock.patch.object(FetchAIApi, \"get_transaction_receipt\", return_value=None)\n    @mock.patch.object(FetchAIApi, \"is_transaction_settled\")\n    def test_sign_send_confirm_receipt_multisig_transaction_receipt_not_found(\n        self,\n        is_transaction_settled_mock,\n        get_transaction_receipt_mock,\n        send_signed_transaction_mock,\n        sign_transaction_mock,\n    ):\n        \"\"\"Test the sign_send_confirm_receipt_multisig_transaction static method: receipt not found.\"\"\"\n        tx = \"tx\"\n        sleep_time = 0\n        with pytest.raises(ValueError, match=\"Transaction receipt not found!\"):\n            self.sign_send_confirm_receipt_multisig_transaction(\n                tx, self.ledger_api, [self.deployer_crypto], sleep_time=sleep_time\n            )\n        is_transaction_settled_mock.assert_not_called()\n        get_transaction_receipt_mock.assert_called_with(\"tx_digest\")\n        send_signed_transaction_mock.assert_called_once_with(tx)\n        sign_transaction_mock.assert_called_once_with(tx)\n\n    @mock.patch.object(FetchAICrypto, \"sign_transaction\", return_value=\"tx\")\n    @mock.patch.object(FetchAIApi, \"send_signed_transaction\", return_value=\"tx_digest\")\n    @mock.patch.object(\n        FetchAIApi, \"get_transaction_receipt\", return_value=TX_RECEIPT_EXAMPLE\n    )\n    @mock.patch.object(FetchAIApi, \"is_transaction_settled\", return_value=False)\n    def test_sign_send_confirm_receipt_multisig_transaction_receipt_not_valid(\n        self,\n        is_transaction_settled_mock,\n        get_transaction_receipt_mock,\n        send_signed_transaction_mock,\n        sign_transaction_mock,\n    ):\n        \"\"\"Test the sign_send_confirm_receipt_multisig_transaction static method: receipt not valid.\"\"\"\n        tx = \"tx\"\n        sleep_time = 0\n        with pytest.raises(ValueError) as e:\n            self.sign_send_confirm_receipt_multisig_transaction(\n                tx, self.ledger_api, [self.deployer_crypto], sleep_time=sleep_time\n            )\n            assert str(e) == \"Transaction receipt not valid!\\nlog\"\n        is_transaction_settled_mock.assert_called_with(TX_RECEIPT_EXAMPLE)\n        get_transaction_receipt_mock.assert_called_with(\"tx_digest\")\n        send_signed_transaction_mock.assert_called_once_with(tx)\n        sign_transaction_mock.assert_called_once_with(tx)\n\n    @mock.patch.object(\n        BaseContractTestCase,\n        \"sign_send_confirm_receipt_multisig_transaction\",\n        return_value=TX_RECEIPT_EXAMPLE,\n    )\n    def test_sign_send_confirm_receipt_transaction_positive(\n        self, sign_send_confirm_receipt_multisig_transaction_mock\n    ):\n        \"\"\"Test sign_send_confirm_receipt_transaction method for positive result.\"\"\"\n        tx = \"tx\"\n        sleep_time = 0.2\n        ledger_api, crypto = self.ledger_api, self.deployer_crypto\n        self.sign_send_confirm_receipt_transaction(tx, ledger_api, crypto, sleep_time)\n        sign_send_confirm_receipt_multisig_transaction_mock.assert_called_once_with(\n            tx, ledger_api, [crypto], sleep_time\n        )\n"
  },
  {
    "path": "tests/test_aea/test_test_tools/test_test_skill.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains a test for aea.test_tools.test_cases.\"\"\"\n\nfrom pathlib import Path\nfrom typing import cast\n\nimport pytest\n\nfrom aea.decision_maker.gop import GoalPursuitReadiness, OwnershipState, Preferences\nfrom aea.exceptions import AEAEnforceError\nfrom aea.mail.base import Address\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue, DialogueLabel, DialogueMessage\nfrom aea.skills.base import Skill\nfrom aea.test_tools.test_skill import BaseSkillTestCase\n\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.protocols.fipa.dialogues import FipaDialogue\nfrom packages.fetchai.protocols.fipa.dialogues import FipaDialogues as BaseFipaDialogues\nfrom packages.fetchai.protocols.fipa.message import FipaMessage\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass TestSkillTestCase(BaseSkillTestCase):\n    \"\"\"Test case for BaseSkillTestCase.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"tests\", \"data\", \"dummy_skill\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        cls.behaviour_arg_1 = 2\n        cls.behaviour_arg_2 = \"3\"\n\n        config_overrides = {\n            \"behaviours\": {\n                \"dummy\": {\n                    \"args\": {\n                        \"behaviour_arg_1\": cls.behaviour_arg_1,\n                        \"behaviour_arg_2\": cls.behaviour_arg_2,\n                    }\n                }\n            },\n        }\n        cls.shared_state_key = \"some_shared_state_key\"\n        cls.shared_state_value = \"some_shared_state_value\"\n        cls.shared_state = {cls.shared_state_key: cls.shared_state_value}\n\n        tac_dm_context_kwargs = {\n            \"goal_pursuit_readiness\": GoalPursuitReadiness(),\n            \"ownership_state\": OwnershipState(),\n            \"preferences\": Preferences(),\n        }\n\n        super().setup(\n            config_overrides=config_overrides,\n            shared_state=cls.shared_state,\n            dm_context_kwargs=tac_dm_context_kwargs,\n        )\n\n    def test_setup(self):\n        \"\"\"Test the setup() class method.\"\"\"\n        assert self.skill.skill_context.agent_address == \"test_agent_address\"\n        assert self.skill.skill_context.agent_name == \"test_agent_name\"\n        assert (\n            self.skill.skill_context.search_service_address\n            == \"dummy_author/dummy_search_skill:0.1.0\"\n        )\n        assert (\n            self.skill.skill_context.decision_maker_address\n            == \"dummy_decision_maker_address\"\n        )\n        assert \"dummy\" in self.skill.behaviours.keys()\n        assert \"dummy\" in self.skill.handlers.keys()\n        assert \"dummy_internal\" in self.skill.handlers.keys()\n        assert \"dummy\" in self.skill.models.keys()\n\n        assert (\n            self.skill.skill_context._agent_context.shared_state[self.shared_state_key]\n            == self.shared_state_value\n        )\n\n        assert (\n            self.skill.skill_context.behaviours.dummy.kwargs[\"behaviour_arg_1\"]\n            == self.behaviour_arg_1\n        )\n        assert (\n            self.skill.skill_context.behaviours.dummy.kwargs[\"behaviour_arg_2\"]\n            == self.behaviour_arg_2\n        )\n\n        assert (\n            type(\n                self.skill.skill_context.decision_maker_handler_context.goal_pursuit_readiness\n            )\n            == GoalPursuitReadiness\n        )\n        assert (\n            type(\n                self.skill.skill_context.decision_maker_handler_context.ownership_state\n            )\n            == OwnershipState\n        )\n        assert (\n            type(self.skill.skill_context.decision_maker_handler_context.preferences)\n            == Preferences\n        )\n\n    def test_properties(self):\n        \"\"\"Test the properties.\"\"\"\n        assert isinstance(self.skill, Skill)\n        assert self.skill.behaviours.get(\"dummy\") is not None\n\n    def test_get_quantity_in_outbox(self):\n        \"\"\"Test the get_quantity_in_outbox method.\"\"\"\n        assert self.get_quantity_in_outbox() == 0\n\n        dummy_message = DefaultMessage(\n            performative=DefaultMessage.Performative.BYTES, content=\"dummy\"\n        )\n        dummy_message.to = \"some_to\"\n        dummy_message.sender = \"some_sender\"\n        self.skill.skill_context.outbox.put_message(dummy_message)\n\n        assert self.get_quantity_in_outbox() == 1\n\n    def test_get_message_from_outbox(self):\n        \"\"\"Test the get_message_from_outbox method.\"\"\"\n        assert self.get_message_from_outbox() is None\n\n        dummy_message_1 = DefaultMessage(\n            performative=DefaultMessage.Performative.BYTES, content=\"dummy_1\"\n        )\n        dummy_message_1.to = \"some_to_1\"\n        dummy_message_1.sender = \"some_sender_1\"\n        self.skill.skill_context.outbox.put_message(dummy_message_1)\n\n        dummy_message_2 = DefaultMessage(\n            performative=DefaultMessage.Performative.BYTES, content=\"dummy_2\"\n        )\n        dummy_message_2.to = \"some_to_2\"\n        dummy_message_2.sender = \"some_sender_2\"\n        self.skill.skill_context.outbox.put_message(dummy_message_2)\n\n        assert self.get_message_from_outbox() == dummy_message_1\n        assert self.get_message_from_outbox() == dummy_message_2\n\n    def test_drop_messages_from_outbox(self):\n        \"\"\"Test the drop_messages_from_outbox method.\"\"\"\n        assert self.get_quantity_in_outbox() == 0\n        self.drop_messages_from_outbox(5)\n        assert self.get_quantity_in_outbox() == 0\n\n        dummy_message_1 = DefaultMessage(\n            performative=DefaultMessage.Performative.BYTES, content=\"dummy_2\"\n        )\n        dummy_message_1.to = \"some_to_1\"\n        dummy_message_1.sender = \"some_sender_1\"\n        self.skill.skill_context.outbox.put_message(dummy_message_1)\n\n        dummy_message_2 = DefaultMessage(\n            performative=DefaultMessage.Performative.BYTES, content=\"dummy_2\"\n        )\n        dummy_message_2.to = \"some_to_2\"\n        dummy_message_2.sender = \"some_sender_2\"\n        self.skill.skill_context.outbox.put_message(dummy_message_2)\n\n        dummy_message_3 = DefaultMessage(\n            performative=DefaultMessage.Performative.BYTES, content=\"dummy_2\"\n        )\n        dummy_message_3.to = \"some_to_3\"\n        dummy_message_3.sender = \"some_sender_3\"\n        self.skill.skill_context.outbox.put_message(dummy_message_3)\n\n        assert self.get_quantity_in_outbox() == 3\n\n        self.drop_messages_from_outbox(2)\n\n        assert self.get_quantity_in_outbox() == 1\n        assert self.get_message_from_outbox() == dummy_message_3\n\n    def test_get_quantity_in_decision_maker_inbox(self):\n        \"\"\"Test the get_quantity_in_decision_maker_inbox method.\"\"\"\n        assert self.get_quantity_in_decision_maker_inbox() == 0\n\n        dummy_message = DefaultMessage(\n            performative=DefaultMessage.Performative.BYTES, content=\"dummy\"\n        )\n        dummy_message.to = \"some_to\"\n        dummy_message.sender = \"some_sender\"\n        self.skill.skill_context.decision_maker_message_queue.put(dummy_message)\n\n        assert self.get_quantity_in_decision_maker_inbox() == 1\n\n    def test_get_message_from_decision_maker_inbox(self):\n        \"\"\"Test the get_message_from_decision_maker_inbox method.\"\"\"\n        assert self.get_message_from_decision_maker_inbox() is None\n\n        dummy_message_1 = DefaultMessage(\n            performative=DefaultMessage.Performative.BYTES, content=\"dummy_1\"\n        )\n        dummy_message_1.to = \"some_to_1\"\n        dummy_message_1.sender = \"some_sender_1\"\n        self.skill.skill_context.decision_maker_message_queue.put(dummy_message_1)\n\n        dummy_message_2 = DefaultMessage(\n            performative=DefaultMessage.Performative.BYTES, content=\"dummy_2\"\n        )\n        dummy_message_2.to = \"some_to_2\"\n        dummy_message_2.sender = \"some_sender_2\"\n        self.skill.skill_context.decision_maker_message_queue.put(dummy_message_2)\n\n        assert self.get_message_from_decision_maker_inbox() == dummy_message_1\n        assert self.get_message_from_decision_maker_inbox() == dummy_message_2\n\n    def test_drop_messages_from_decision_maker_inbox(self):\n        \"\"\"Test the drop_messages_from_decision_maker_inbox method.\"\"\"\n        assert self.get_quantity_in_decision_maker_inbox() == 0\n        self.drop_messages_from_decision_maker_inbox(5)\n        assert self.get_quantity_in_decision_maker_inbox() == 0\n\n        dummy_message_1 = Message()\n        dummy_message_1.to = \"some_to_1\"\n        dummy_message_1.sender = \"some_sender_1\"\n        self.skill.skill_context.decision_maker_message_queue.put(dummy_message_1)\n\n        dummy_message_2 = Message()\n        dummy_message_2.to = \"some_to_2\"\n        dummy_message_2.sender = \"some_sender_2\"\n        self.skill.skill_context.decision_maker_message_queue.put(dummy_message_2)\n\n        dummy_message_3 = Message()\n        dummy_message_3.to = \"some_to_3\"\n        dummy_message_3.sender = \"some_sender_3\"\n        self.skill.skill_context.decision_maker_message_queue.put(dummy_message_3)\n\n        assert self.get_quantity_in_decision_maker_inbox() == 3\n\n        self.drop_messages_from_decision_maker_inbox(2)\n\n        assert self.get_quantity_in_decision_maker_inbox() == 1\n        assert self.get_message_from_decision_maker_inbox() == dummy_message_3\n\n    def test_assert_quantity_in_outbox(self):\n        \"\"\"Test the assert_quantity_in_outbox method.\"\"\"\n        with pytest.raises(\n            AssertionError,\n            match=f\"Invalid number of messages in outbox. Expected {1}. Found {0}.\",\n        ):\n            self.assert_quantity_in_outbox(1)\n\n        dummy_message = DefaultMessage(\n            performative=DefaultMessage.Performative.BYTES, content=\"dummy\"\n        )\n        dummy_message.to = \"some_to\"\n        dummy_message.sender = \"some_sender\"\n        self.skill.skill_context.outbox.put_message(dummy_message)\n\n        self.assert_quantity_in_outbox(1)\n\n    def test_assert_quantity_in_decision_making_queue(self):\n        \"\"\"Test the assert_quantity_in_decision_making_queue method.\"\"\"\n        with pytest.raises(\n            AssertionError,\n            match=f\"Invalid number of messages in decision maker queue. Expected {1}. Found {0}.\",\n        ):\n            self.assert_quantity_in_decision_making_queue(1)\n\n        dummy_message = DefaultMessage(\n            performative=DefaultMessage.Performative.BYTES, content=\"dummy_1\"\n        )\n        dummy_message.to = \"some_to_1\"\n        dummy_message.sender = \"some_sender_1\"\n        self.skill.skill_context.decision_maker_message_queue.put(dummy_message)\n\n        self.assert_quantity_in_decision_making_queue(1)\n\n    def test_positive_message_has_attributes_valid_type(self):\n        \"\"\"Test the message_has_attributes method where the message is of the specified type.\"\"\"\n        dummy_message = FipaMessage(\n            dialogue_reference=(\"0\", \"0\"),\n            message_id=1,\n            performative=FipaMessage.Performative.CFP,\n            target=0,\n            query=\"some_query\",\n        )\n        dummy_message.to = \"some_to\"\n        dummy_message.sender = \"some_sender\"\n\n        valid_has_attribute, valid_has_attribute_msg = self.message_has_attributes(\n            actual_message=dummy_message,\n            message_type=FipaMessage,\n            message_id=1,\n            performative=FipaMessage.Performative.CFP,\n            target=0,\n            query=\"some_query\",\n            to=\"some_to\",\n            sender=\"some_sender\",\n        )\n        assert valid_has_attribute\n        assert (\n            valid_has_attribute_msg\n            == \"The message has the provided expected attributes.\"\n        )\n\n    def test_negative_message_has_attributes_invalid_message_id(self):\n        \"\"\"Negative test for message_has_attributes method where the message id does NOT match.\"\"\"\n        dummy_message = FipaMessage(\n            dialogue_reference=(\"0\", \"0\"),\n            message_id=1,\n            performative=FipaMessage.Performative.CFP,\n            target=0,\n            query=\"some_query\",\n        )\n        dummy_message.to = \"some_to\"\n        dummy_message.sender = \"some_sender\"\n\n        invalid_has_attribute, invalid_has_attribute_msg = self.message_has_attributes(\n            actual_message=dummy_message,\n            message_type=FipaMessage,\n            message_id=2,\n            performative=FipaMessage.Performative.CFP,\n            target=0,\n            query=\"some_query\",\n            to=\"some_to\",\n            sender=\"some_sender\",\n        )\n        assert not invalid_has_attribute\n        assert (\n            invalid_has_attribute_msg\n            == \"The 'message_id' fields do not match. Actual 'message_id': 1. Expected 'message_id': 2\"\n        )\n\n    def test_negative_message_has_attributes_invalid_type(self):\n        \"\"\"Test the message_has_attributes method where the message is NOT of the specified type.\"\"\"\n        dummy_message = FipaMessage(\n            dialogue_reference=(\"0\", \"0\"),\n            message_id=1,\n            performative=FipaMessage.Performative.CFP,\n            target=0,\n            query=\"some_query\",\n        )\n        dummy_message.to = \"some_to\"\n        dummy_message.sender = \"some_sender\"\n\n        valid_has_attribute, valid_has_attribute_msg = self.message_has_attributes(\n            actual_message=dummy_message,\n            message_type=DefaultMessage,\n            message_id=1,\n            performative=FipaMessage.Performative.CFP,\n            target=0,\n            query=\"some_query\",\n            to=\"some_to\",\n            sender=\"some_sender\",\n        )\n        assert not valid_has_attribute\n        assert (\n            valid_has_attribute_msg\n            == f\"The message types do not match. Actual type: {FipaMessage}. Expected type: {DefaultMessage}\"\n        )\n\n        invalid_has_attribute, invalid_has_attribute_msg = self.message_has_attributes(\n            actual_message=dummy_message,\n            message_type=FipaMessage,\n            message_id=2,\n            performative=FipaMessage.Performative.CFP,\n            target=0,\n            query=\"some_query\",\n            to=\"some_to\",\n            sender=\"some_sender\",\n        )\n        assert not invalid_has_attribute\n        assert (\n            invalid_has_attribute_msg\n            == \"The 'message_id' fields do not match. Actual 'message_id': 1. Expected 'message_id': 2\"\n        )\n\n    def test_build_incoming_message(self):\n        \"\"\"Test the build_incoming_message method.\"\"\"\n        message_type = FipaMessage\n        performative = FipaMessage.Performative.CFP\n        dialogue_reference = (\"1\", \"1\")\n        to = \"some_to\"\n        query = \"some_query\"\n        incoming_message = self.build_incoming_message(\n            message_type=message_type,\n            performative=performative,\n            dialogue_reference=dialogue_reference,\n            to=to,\n            query=query,\n        )\n\n        assert type(incoming_message) == message_type\n        incoming_message = cast(FipaMessage, incoming_message)\n        assert incoming_message.dialogue_reference == dialogue_reference\n        assert incoming_message.message_id == 1\n        assert incoming_message.target == 0\n        assert incoming_message.performative == performative\n        assert incoming_message.query == query\n        assert incoming_message.sender == \"counterparty\"\n        assert incoming_message.to == to\n\n    def test_positive_build_incoming_message_for_skill_dialogue(self):\n        \"\"\"Positive test for build_incoming_message_for_skill_dialogue method.\"\"\"\n        fipa_dialogues = FipaDialogues(\n            self_address=self.skill.skill_context.agent_address\n        )\n        base_msg, dialogue = fipa_dialogues.create(\n            counterparty=\"some_counterparty\",\n            performative=FipaMessage.Performative.CFP,\n            query=\"some_query\",\n        )\n\n        performative = FipaMessage.Performative.PROPOSE\n        proposal = \"some_proposal\"\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=dialogue,\n            performative=performative,\n            proposal=proposal,\n        )\n\n        assert type(incoming_message) == FipaMessage\n        incoming_message = cast(FipaMessage, incoming_message)\n        assert (\n            incoming_message.dialogue_reference\n            == dialogue.dialogue_label.dialogue_reference\n        )\n        assert incoming_message.message_id != base_msg.message_id\n        assert incoming_message.target == base_msg.message_id\n        assert incoming_message.performative == performative\n        assert incoming_message.proposal == proposal\n        assert incoming_message.sender == dialogue.dialogue_label.dialogue_opponent_addr\n        assert incoming_message.to == dialogue.self_address\n\n    def test_negative_build_incoming_message_for_skill_dialogue_dialogue_is_none(self):\n        \"\"\"Negative test for build_incoming_message_for_skill_dialogue method where the provided dialogue is None.\"\"\"\n        performative = FipaMessage.Performative.PROPOSE\n        proposal = \"some_proposal\"\n\n        with pytest.raises(AEAEnforceError, match=\"dialogue cannot be None.\"):\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=None,\n                performative=performative,\n                proposal=proposal,\n            )\n\n    def test_negative_build_incoming_message_for_skill_dialogue_dialogue_is_empty(self):\n        \"\"\"Negative test for build_incoming_message_for_skill_dialogue method where the provided dialogue is empty.\"\"\"\n        performative = FipaMessage.Performative.PROPOSE\n        proposal = \"some_proposal\"\n\n        fipa_dialogues = FipaDialogues(\n            self_address=self.skill.skill_context.agent_address\n        )\n        dialogue = fipa_dialogues._create_self_initiated(\n            dialogue_opponent_addr=\"some_counterparty\",\n            dialogue_reference=(\"0\", \"\"),\n            role=FipaDialogue.Role.BUYER,\n        )\n\n        with pytest.raises(AEAEnforceError, match=\"dialogue cannot be empty.\"):\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=dialogue,\n                performative=performative,\n                proposal=proposal,\n            )\n\n    def test_provide_unspecified_fields(self):\n        \"\"\"Test the _provide_unspecified_fields method.\"\"\"\n        dialogue_message_unspecified = DialogueMessage(\n            FipaMessage.Performative.ACCEPT, {}\n        )\n\n        is_incoming, target = self._provide_unspecified_fields(\n            dialogue_message_unspecified, last_is_incoming=False\n        )\n        assert is_incoming is True\n        assert target is None\n\n        dialogue_message_specified = DialogueMessage(\n            FipaMessage.Performative.ACCEPT, {}, False, 4\n        )\n\n        is_incoming, target = self._provide_unspecified_fields(\n            dialogue_message_specified, last_is_incoming=True\n        )\n        assert is_incoming is False\n        assert target == 4\n\n    def test_non_initial_incoming_message_dialogue_reference(self):\n        \"\"\"Test the _non_initial_incoming_message_dialogue_reference method.\"\"\"\n        dialogue_incomplete_ref = FipaDialogue(\n            DialogueLabel((\"2\", \"\"), \"opponent\", \"self_address\"),\n            \"self_address\",\n            FipaDialogue.Role.BUYER,\n        )\n        reference_incomplete = self._non_initial_incoming_message_dialogue_reference(\n            dialogue_incomplete_ref\n        )\n        assert reference_incomplete[1] != \"\"\n\n        dialogue_complete_ref = FipaDialogue(\n            DialogueLabel((\"2\", \"7\"), \"opponent\", \"self_address\"),\n            \"self_address\",\n            FipaDialogue.Role.BUYER,\n        )\n        reference_complete = self._non_initial_incoming_message_dialogue_reference(\n            dialogue_complete_ref\n        )\n        assert reference_complete[1] == \"7\"\n\n    def test_extract_message_fields(self):\n        \"\"\"Test the _extract_message_fields method.\"\"\"\n        expected_performative = FipaMessage.Performative.ACCEPT\n        expected_contents = {}\n        expected_is_incoming = False\n        expected_target = 4\n        dialogue_message = DialogueMessage(\n            expected_performative,\n            expected_contents,\n            expected_is_incoming,\n            expected_target,\n        )\n\n        (\n            actual_performative,\n            actual_contents,\n            actual_message_id,\n            actual_is_incoming,\n            actual_target,\n        ) = self._extract_message_fields(\n            message=dialogue_message, index=3, last_is_incoming=True\n        )\n\n        assert actual_message_id == 4\n        assert actual_target == expected_target\n        assert actual_performative == expected_performative\n        assert actual_contents == expected_contents\n        assert actual_is_incoming == expected_is_incoming\n\n    def test_prepare_skill_dialogue_valid_self_initiated(self):\n        \"\"\"Positive test for prepare_skill_dialogue method with a valid dialogue initiated by self.\"\"\"\n        fipa_dialogues = FipaDialogues(\n            self_address=self.skill.skill_context.agent_address\n        )\n        dialogue_messages = (\n            DialogueMessage(FipaMessage.Performative.CFP, {\"query\": \"some_query\"}),\n            DialogueMessage(\n                FipaMessage.Performative.PROPOSE, {\"proposal\": \"some_proposal\"}\n            ),\n            DialogueMessage(\n                FipaMessage.Performative.PROPOSE,\n                {\"proposal\": \"some_counter_proposal_1\"},\n            ),\n            DialogueMessage(\n                FipaMessage.Performative.PROPOSE,\n                {\"proposal\": \"some_counter_proposal_2\"},\n            ),\n            DialogueMessage(\n                FipaMessage.Performative.PROPOSE,\n                {\"proposal\": \"some_counter_proposal_3\"},\n            ),\n            DialogueMessage(\n                FipaMessage.Performative.PROPOSE,\n                {\"proposal\": \"some_counter_proposal_4\"},\n            ),\n            DialogueMessage(FipaMessage.Performative.ACCEPT, {}),\n            DialogueMessage(\n                FipaMessage.Performative.MATCH_ACCEPT_W_INFORM, {\"info\": \"some_info\"}\n            ),\n        )\n        dialogue = self.prepare_skill_dialogue(\n            fipa_dialogues,\n            dialogue_messages,\n            \"counterparty\",\n        )\n\n        assert type(dialogue) == FipaDialogue\n        assert dialogue.is_self_initiated\n        assert len(dialogue._outgoing_messages) == 4\n        assert len(dialogue._incoming_messages) == 4\n        assert dialogue._incoming_messages[1].proposal == \"some_counter_proposal_2\"\n        assert dialogue._incoming_messages[3].info == \"some_info\"\n\n    def test_prepare_skill_dialogue_valid_opponent_initiated(self):\n        \"\"\"Positive test for prepare_skill_dialogue method with a valid dialogue initiated by the opponent.\"\"\"\n        fipa_dialogues = FipaDialogues(\n            self_address=self.skill.skill_context.agent_address\n        )\n        dialogue_messages = (\n            DialogueMessage(\n                FipaMessage.Performative.CFP, {\"query\": \"some_query\"}, True\n            ),\n            DialogueMessage(\n                FipaMessage.Performative.PROPOSE, {\"proposal\": \"some_proposal\"}\n            ),\n            DialogueMessage(\n                FipaMessage.Performative.PROPOSE,\n                {\"proposal\": \"some_counter_proposal_1\"},\n            ),\n            DialogueMessage(\n                FipaMessage.Performative.PROPOSE,\n                {\"proposal\": \"some_counter_proposal_2\"},\n            ),\n            DialogueMessage(\n                FipaMessage.Performative.PROPOSE,\n                {\"proposal\": \"some_counter_proposal_3\"},\n            ),\n            DialogueMessage(\n                FipaMessage.Performative.PROPOSE,\n                {\"proposal\": \"some_counter_proposal_4\"},\n            ),\n            DialogueMessage(FipaMessage.Performative.ACCEPT, {}),\n            DialogueMessage(\n                FipaMessage.Performative.MATCH_ACCEPT_W_INFORM, {\"info\": \"some_info\"}\n            ),\n        )\n        dialogue = self.prepare_skill_dialogue(\n            fipa_dialogues,\n            dialogue_messages,\n            \"counterparty\",\n        )\n\n        assert type(dialogue) == FipaDialogue\n        assert not dialogue.is_self_initiated\n        assert len(dialogue._outgoing_messages) == 4\n        assert len(dialogue._incoming_messages) == 4\n        assert dialogue._outgoing_messages[1].proposal == \"some_counter_proposal_2\"\n        assert dialogue._outgoing_messages[-1].info == \"some_info\"\n\n    def test_negative_prepare_skill_dialogue_invalid_opponent_initiated(self):\n        \"\"\"Negative test for prepare_skill_dialogue method with an invalid dialogue initiated by the opponent.\"\"\"\n        fipa_dialogues = FipaDialogues(\n            self_address=self.skill.skill_context.agent_address\n        )\n        dialogue_messages = (\n            DialogueMessage(\n                FipaMessage.Performative.PROPOSE, {\"proposal\": \"some_proposal\"}, True\n            ),\n            DialogueMessage(\n                FipaMessage.Performative.PROPOSE,\n                {\"proposal\": \"some_counter_proposal_1\"},\n            ),\n            DialogueMessage(\n                FipaMessage.Performative.PROPOSE,\n                {\"proposal\": \"some_counter_proposal_2\"},\n            ),\n            DialogueMessage(\n                FipaMessage.Performative.PROPOSE,\n                {\"proposal\": \"some_counter_proposal_3\"},\n            ),\n            DialogueMessage(\n                FipaMessage.Performative.PROPOSE,\n                {\"proposal\": \"some_counter_proposal_4\"},\n            ),\n            DialogueMessage(FipaMessage.Performative.ACCEPT, {}),\n            DialogueMessage(\n                FipaMessage.Performative.MATCH_ACCEPT_W_INFORM, {\"info\": \"some_info\"}\n            ),\n        )\n        with pytest.raises(\n            AEAEnforceError, match=\"Cannot update the dialogue with message number 1\"\n        ):\n            self.prepare_skill_dialogue(\n                fipa_dialogues,\n                dialogue_messages,\n                \"counterparty\",\n            )\n\n    def test_negative_prepare_skill_dialogue_empty_messages(self):\n        \"\"\"Negative test for prepare_skill_dialogue method where the list of DialogueMessages is emoty.\"\"\"\n        fipa_dialogues = FipaDialogues(\n            self_address=self.skill.skill_context.agent_address\n        )\n        dialogue_messages = tuple()\n\n        with pytest.raises(\n            AEAEnforceError, match=\"the list of messages must be positive.\"\n        ):\n            self.prepare_skill_dialogue(\n                fipa_dialogues,\n                dialogue_messages,\n                \"counterparty\",\n            )\n\n    def test_negative_prepare_skill_dialogue_invalid(self):\n        \"\"\"Negative test for prepare_skill_dialogue method with an invalid dialogue (a message has invalid target).\"\"\"\n        fipa_dialogues = FipaDialogues(\n            self_address=self.skill.skill_context.agent_address\n        )\n        dialogue_messages = (\n            DialogueMessage(FipaMessage.Performative.CFP, {\"query\": \"some_query\"}),\n            DialogueMessage(\n                FipaMessage.Performative.PROPOSE,\n                {\"proposal\": \"some_proposal\"},\n                target=2,\n            ),\n        )\n\n        with pytest.raises(\n            AEAEnforceError, match=\"Cannot update the dialogue with message number .*\"\n        ):\n            self.prepare_skill_dialogue(\n                fipa_dialogues,\n                dialogue_messages,\n                \"counterparty\",\n            )\n\n\nclass FipaDialogues(BaseFipaDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, self_address: Address, **kwargs) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :return: None\n        \"\"\"\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> Dialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return FipaDialogue.Role.BUYER\n\n        BaseFipaDialogues.__init__(\n            self,\n            self_address=self_address,\n            role_from_first_message=role_from_first_message,\n            dialogue_class=FipaDialogue,\n        )\n"
  },
  {
    "path": "tests/test_aea_core_packages/test_connections/test_http_client/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests of the HTTP client connection implementation.\"\"\"\n"
  },
  {
    "path": "tests/test_aea_core_packages/test_connections/test_http_client/test_http_client.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Tests for the HTTP Client connection and channel.\"\"\"\nimport asyncio\nimport logging\nfrom asyncio import CancelledError\nfrom typing import Any, cast\nfrom unittest.mock import MagicMock, Mock, patch\n\nimport aiohttp\nimport pytest\n\nfrom aea.common import Address\nfrom aea.configurations.base import ConnectionConfig\nfrom aea.identity.base import Identity\nfrom aea.mail.base import Envelope, Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\n\nfrom packages.fetchai.connections.http_client.connection import HTTPClientConnection\nfrom packages.fetchai.protocols.http.dialogues import HttpDialogue\nfrom packages.fetchai.protocols.http.dialogues import HttpDialogues as BaseHttpDialogues\nfrom packages.fetchai.protocols.http.message import HttpMessage\n\nfrom tests.common.mocks import AnyStringWith\nfrom tests.conftest import UNKNOWN_PROTOCOL_PUBLIC_ID, get_host, get_unused_tcp_port\n\n\nlogger = logging.getLogger(__name__)\n\n\nclass _MockRequest:\n    \"\"\"Fake request for aiohttp client session.\"\"\"\n\n    def __init__(self, response: Mock) -> None:\n        \"\"\"Init with mock response.\"\"\"\n        self.response = response\n\n    async def __aenter__(self) -> Any:\n        \"\"\"Enter async context.\"\"\"\n        return self.response\n\n    async def __aexit__(self, *args, **kwargs) -> None:\n        \"\"\"Exit async context.\"\"\"\n        return None\n\n\nclass HttpDialogues(BaseHttpDialogues):\n    \"\"\"The dialogues class keeps track of all http dialogues.\"\"\"\n\n    def __init__(self, self_address: Address, **kwargs) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :return: None\n        \"\"\"\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return HttpDialogue.Role.CLIENT\n\n        BaseHttpDialogues.__init__(\n            self,\n            self_address=self_address,\n            role_from_first_message=role_from_first_message,\n        )\n\n\n@pytest.mark.asyncio\nclass TestHTTPClientConnect:\n    \"\"\"Tests the http client connection's 'connect' functionality.\"\"\"\n\n    def setup(self):\n        \"\"\"Initialise the class.\"\"\"\n        self.address = get_host()\n        self.port = get_unused_tcp_port()\n        self.agent_identity = Identity(\n            \"name\", address=\"some string\", public_key=\"some public_key\"\n        )\n        self.client_skill_id = \"some/skill:0.1.0\"\n        configuration = ConnectionConfig(\n            host=self.address,\n            port=self.port,\n            connection_id=HTTPClientConnection.connection_id,\n        )\n        self.http_client_connection = HTTPClientConnection(\n            configuration=configuration,\n            data_dir=MagicMock(),\n            identity=self.agent_identity,\n        )\n        self.connection_address = str(HTTPClientConnection.connection_id)\n        self.http_dialogs = HttpDialogues(self.client_skill_id)\n\n    @pytest.mark.asyncio\n    async def test_initialization(self):\n        \"\"\"Test the initialisation of the class.\"\"\"\n        assert self.http_client_connection.address == self.agent_identity.address\n\n    @pytest.mark.asyncio\n    async def test_connection(self):\n        \"\"\"Test the connect functionality of the http client connection.\"\"\"\n        await self.http_client_connection.connect()\n        assert self.http_client_connection.is_connected is True\n\n    @pytest.mark.asyncio\n    async def test_disconnect(self):\n        \"\"\"Test the disconnect functionality of the http client connection.\"\"\"\n        await self.http_client_connection.connect()\n        assert self.http_client_connection.is_connected is True\n\n        await self.http_client_connection.disconnect()\n        assert self.http_client_connection.is_connected is False\n\n    @pytest.mark.asyncio\n    async def test_http_send_error(self):\n        \"\"\"Test request fails and send back result with code 600.\"\"\"\n        await self.http_client_connection.connect()\n        request_http_message, _ = self.http_dialogs.create(\n            counterparty=self.connection_address,\n            performative=HttpMessage.Performative.REQUEST,\n            method=\"get\",\n            url=\"bad url\",\n            headers=\"\",\n            version=\"\",\n            body=b\"\",\n        )\n        request_envelope = Envelope(\n            to=self.connection_address,\n            sender=self.client_skill_id,\n            protocol_specification_id=UNKNOWN_PROTOCOL_PUBLIC_ID,\n            message=request_http_message,\n        )\n\n        connection_response_mock = Mock()\n        connection_response_mock.status_code = 200\n\n        await self.http_client_connection.send(envelope=request_envelope)\n        # TODO: Consider returning the response from the server in order to be able to assert that the message send!\n        envelope = await asyncio.wait_for(\n            self.http_client_connection.receive(), timeout=10\n        )\n        assert envelope\n        assert envelope.message.status_code == 600\n\n        await self.http_client_connection.disconnect()\n\n    @pytest.mark.asyncio\n    async def test_http_client_send_not_connected_error(self):\n        \"\"\"Test connection.send error if not conencted.\"\"\"\n        with pytest.raises(ConnectionError):\n            await self.http_client_connection.send(Mock())\n\n    @pytest.mark.asyncio\n    async def test_http_channel_send_not_connected_error(self):\n        \"\"\"Test channel.send error if not conencted.\"\"\"\n        with pytest.raises(ValueError):\n            self.http_client_connection.channel.send(Mock())\n\n    @pytest.mark.asyncio\n    async def test_send_empty_envelope_skip(self):\n        \"\"\"Test skip on empty envelope request sent.\"\"\"\n        await self.http_client_connection.connect()\n        with patch.object(\n            self.http_client_connection.channel, \"_http_request_task\"\n        ) as mock:\n            await self.http_client_connection.send(None)\n        mock.assert_not_called()\n\n    @pytest.mark.asyncio\n    async def test_channel_get_message_not_connected(self):\n        \"\"\"Test errro on message get if not connected.\"\"\"\n        with pytest.raises(ValueError):\n            await self.http_client_connection.channel.get_message()\n\n    @pytest.mark.asyncio\n    async def test_channel_cancel_tasks_on_disconnect(self):\n        \"\"\"Test requests tasks cancelled on disconnect.\"\"\"\n        await self.http_client_connection.connect()\n        request_http_message, _ = self.http_dialogs.create(\n            counterparty=self.connection_address,\n            performative=HttpMessage.Performative.REQUEST,\n            method=\"get\",\n            url=\"https://not-a-google.com\",\n            headers=\"\",\n            version=\"\",\n            body=b\"\",\n        )\n        request_envelope = Envelope(\n            to=self.connection_address,\n            sender=self.client_skill_id,\n            protocol_specification_id=UNKNOWN_PROTOCOL_PUBLIC_ID,\n            message=request_http_message,\n        )\n\n        connection_response_mock = Mock()\n        connection_response_mock.status_code = 200\n\n        response_mock = Mock()\n        response_mock.status = 200\n        response_mock.headers = {\"headers\": \"some header\"}\n        response_mock.reason = \"OK\"\n        response_mock._body = b\"Some content\"\n        response_mock.read.return_value = asyncio.Future()\n\n        with patch.object(\n            aiohttp.ClientSession,\n            \"request\",\n            return_value=_MockRequest(response_mock),\n        ):\n            await self.http_client_connection.send(envelope=request_envelope)\n\n            assert self.http_client_connection.channel._tasks\n            task = list(self.http_client_connection.channel._tasks)[0]\n            assert not task.done()\n        await self.http_client_connection.disconnect()\n\n        assert not self.http_client_connection.channel._tasks\n        assert task.done()\n        with pytest.raises(CancelledError):\n            await task\n\n    @pytest.mark.asyncio\n    async def test_http_send_ok(self):\n        \"\"\"Test request is ok cause mocked.\"\"\"\n        await self.http_client_connection.connect()\n        request_http_message, sending_dialogue = self.http_dialogs.create(\n            counterparty=self.connection_address,\n            performative=HttpMessage.Performative.REQUEST,\n            method=\"get\",\n            url=\"https://not-a-google.com\",\n            headers=\"\",\n            version=\"\",\n            body=b\"\",\n        )\n        request_envelope = Envelope(\n            to=self.connection_address,\n            sender=self.client_skill_id,\n            message=request_http_message,\n        )\n\n        connection_response_mock = Mock()\n        connection_response_mock.status_code = 200\n\n        response_mock = Mock()\n        response_mock.status = 200\n        response_mock.headers = {\"headers\": \"some header\"}\n        response_mock.reason = \"OK\"\n        response_mock._body = b\"Some content\"\n        response_mock.read.return_value = asyncio.Future()\n        response_mock.read.return_value.set_result(\"\")\n\n        with patch.object(\n            aiohttp.ClientSession,\n            \"request\",\n            return_value=_MockRequest(response_mock),\n        ):\n            await self.http_client_connection.send(envelope=request_envelope)\n            # TODO: Consider returning the response from the server in order to be able to assert that the message send!\n            envelope = await asyncio.wait_for(\n                self.http_client_connection.receive(), timeout=10\n            )\n\n        assert envelope is not None and envelope.message is not None\n        message = envelope.message\n        response_dialogue = self.http_dialogs.update(message)\n        assert message.status_code == response_mock.status, message.body.decode(\"utf-8\")\n        assert sending_dialogue == response_dialogue\n        await self.http_client_connection.disconnect()\n\n    @pytest.mark.asyncio\n    async def test_http_dialogue_construct_fail(self):\n        \"\"\"Test dialogue not properly constructed.\"\"\"\n        await self.http_client_connection.connect()\n\n        incorrect_http_message = HttpMessage(\n            dialogue_reference=self.http_dialogs.new_self_initiated_dialogue_reference(),\n            performative=HttpMessage.Performative.RESPONSE,\n            status_code=500,\n            headers=\"\",\n            status_text=\"\",\n            body=b\"\",\n            version=\"\",\n        )\n        incorrect_http_message.to = self.connection_address\n        incorrect_http_message.sender = self.client_skill_id\n\n        # the incorrect message cannot be sent into a dialogue, so this is omitted.\n\n        envelope = Envelope(\n            to=incorrect_http_message.to,\n            sender=incorrect_http_message.sender,\n            message=incorrect_http_message,\n        )\n        with patch.object(\n            self.http_client_connection.channel.logger, \"warning\"\n        ) as mock_logger:\n            await self.http_client_connection.channel._http_request_task(envelope)\n            mock_logger.assert_any_call(\n                AnyStringWith(\"Could not create dialogue for message=\")\n            )\n\n    @pytest.mark.asyncio\n    async def test_http_send_exception(self):\n        \"\"\"Test request is ok cause mocked.\"\"\"\n        await self.http_client_connection.connect()\n        request_http_message, sending_dialogue = self.http_dialogs.create(\n            counterparty=self.connection_address,\n            performative=HttpMessage.Performative.REQUEST,\n            method=\"get\",\n            url=\"https://not-a-google.com\",\n            headers=\"\",\n            version=\"\",\n            body=b\"\",\n        )\n        request_envelope = Envelope(\n            to=self.connection_address,\n            sender=self.client_skill_id,\n            message=request_http_message,\n        )\n\n        with patch.object(\n            aiohttp.ClientSession,\n            \"request\",\n            side_effect=asyncio.TimeoutError(\"expected exception\"),\n        ):\n            await self.http_client_connection.send(envelope=request_envelope)\n            envelope = await asyncio.wait_for(\n                self.http_client_connection.receive(), timeout=10\n            )\n\n        assert envelope\n        message = cast(HttpMessage, envelope.message)\n        assert message.performative == HttpMessage.Performative.RESPONSE\n        assert b\"expected exception\" in message.body\n"
  },
  {
    "path": "tests/test_aea_core_packages/test_connections/test_http_server/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the HTTP Server connection implementation.\"\"\"\n"
  },
  {
    "path": "tests/test_aea_core_packages/test_connections/test_http_server/test_http_server.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the HTTP Server connection module.\"\"\"\nimport asyncio\nimport logging\nimport os\nimport ssl\nfrom traceback import print_exc\nfrom typing import Tuple, cast\nfrom unittest.mock import MagicMock, Mock, patch\n\nimport aiohttp\nimport pytest\nfrom aiohttp.client_reqrep import ClientResponse\n\nfrom aea.common import Address\nfrom aea.configurations.base import ConnectionConfig\nfrom aea.identity.base import Identity\nfrom aea.mail.base import Envelope, Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\n\nfrom packages.fetchai.connections.http_server.connection import (\n    APISpec,\n    HTTPServerConnection,\n    Response,\n)\nfrom packages.fetchai.protocols.http.dialogues import HttpDialogue\nfrom packages.fetchai.protocols.http.dialogues import HttpDialogues as BaseHttpDialogues\nfrom packages.fetchai.protocols.http.message import HttpMessage\n\nfrom tests.common.mocks import RegexComparator\nfrom tests.conftest import ROOT_DIR, get_host, get_unused_tcp_port\n\n\nlogger = logging.getLogger(__name__)\n\n\nclass HttpDialogues(BaseHttpDialogues):\n    \"\"\"The dialogues class keeps track of all http dialogues.\"\"\"\n\n    def __init__(self, self_address: Address, **kwargs) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :return: None\n        \"\"\"\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return HttpDialogue.Role.SERVER\n\n        BaseHttpDialogues.__init__(\n            self,\n            self_address=self_address,\n            role_from_first_message=role_from_first_message,\n        )\n\n\n@pytest.mark.asyncio\nclass TestHTTPServer:\n    \"\"\"Tests for HTTPServer connection.\"\"\"\n\n    async def request(self, method: str, path: str, **kwargs) -> ClientResponse:\n        \"\"\"\n        Make a http request.\n\n        :param method: HTTP method: GET, POST etc\n        :param path: path to request on server. full url constructed automatically\n\n        :return: http response\n        \"\"\"\n        try:\n            url = f\"http://{self.host}:{self.port}{path}\"\n            async with aiohttp.ClientSession() as session:\n                async with session.request(method, url, **kwargs) as resp:\n                    await resp.read()\n                    return resp\n        except Exception:\n            print_exc()\n            raise\n\n    def setup(self):\n        \"\"\"Initialise the test case.\"\"\"\n        self.identity = Identity(\"name\", address=\"my_key\", public_key=\"my_public_key\")\n        self.agent_address = self.identity.address\n        self.host = get_host()\n        self.port = get_unused_tcp_port()\n        self.api_spec_path = os.path.join(\n            ROOT_DIR, \"tests\", \"data\", \"petstore_sim.yaml\"\n        )\n        self.connection_id = HTTPServerConnection.connection_id\n        self.protocol_id = HttpMessage.protocol_id\n        self.target_skill_id = \"some_author/some_skill:0.1.0\"\n\n        self.configuration = ConnectionConfig(\n            host=self.host,\n            port=self.port,\n            target_skill_id=self.target_skill_id,\n            api_spec_path=self.api_spec_path,\n            connection_id=HTTPServerConnection.connection_id,\n            restricted_to_protocols={HttpMessage.protocol_id},\n        )\n        self.http_connection = HTTPServerConnection(\n            configuration=self.configuration,\n            data_dir=MagicMock(),\n            identity=self.identity,\n        )\n        self.loop = asyncio.get_event_loop()\n        self.loop.run_until_complete(self.http_connection.connect())\n        self.connection_address = str(HTTPServerConnection.connection_id)\n        self._dialogues = HttpDialogues(self.target_skill_id)\n        self.original_timeout = self.http_connection.channel.timeout_window\n\n    @pytest.mark.asyncio\n    async def test_http_connection_disconnect_channel(self):\n        \"\"\"Test the disconnect.\"\"\"\n        await self.http_connection.channel.disconnect()\n        assert self.http_connection.channel.is_stopped\n\n    def _get_message_and_dialogue(\n        self, envelope: Envelope\n    ) -> Tuple[HttpMessage, HttpDialogue]:\n        message = cast(HttpMessage, envelope.message)\n        dialogue = cast(HttpDialogue, self._dialogues.update(message))\n        assert dialogue is not None\n        return message, dialogue\n\n    @pytest.mark.asyncio\n    async def test_get_200(self):\n        \"\"\"Test send get request w/ 200 response.\"\"\"\n        request_task = self.loop.create_task(self.request(\"get\", \"/pets\"))\n        envelope = await asyncio.wait_for(self.http_connection.receive(), timeout=20)\n        assert envelope\n        incoming_message, dialogue = self._get_message_and_dialogue(envelope)\n        message = dialogue.reply(\n            target_message=incoming_message,\n            performative=HttpMessage.Performative.RESPONSE,\n            version=incoming_message.version,\n            status_code=200,\n            status_text=\"Success\",\n            body=b\"Response body\",\n        )\n        response_envelope = Envelope(\n            to=envelope.sender,\n            sender=envelope.to,\n            context=envelope.context,\n            message=message,\n        )\n        await self.http_connection.send(response_envelope)\n\n        response = await asyncio.wait_for(\n            request_task,\n            timeout=20,\n        )\n\n        assert (\n            response.status == 200\n            and response.reason == \"Success\"\n            and await response.text() == \"Response body\"\n        )\n\n    @pytest.mark.asyncio\n    async def test_header_content_type(self):\n        \"\"\"Test send get request w/ 200 response.\"\"\"\n        content_type = \"something/unique\"\n        request_task = self.loop.create_task(self.request(\"get\", \"/pets\"))\n        envelope = await asyncio.wait_for(self.http_connection.receive(), timeout=20)\n        assert envelope\n        incoming_message, dialogue = self._get_message_and_dialogue(envelope)\n        message = dialogue.reply(\n            target_message=incoming_message,\n            performative=HttpMessage.Performative.RESPONSE,\n            version=incoming_message.version,\n            headers=f\"Content-Type: {content_type}\",\n            status_code=200,\n            status_text=\"Success\",\n            body=b\"Response body\",\n        )\n        response_envelope = Envelope(\n            to=envelope.sender,\n            sender=envelope.to,\n            context=envelope.context,\n            message=message,\n        )\n        await self.http_connection.send(response_envelope)\n\n        response = await asyncio.wait_for(\n            request_task,\n            timeout=20,\n        )\n        assert (\n            response.status == 200\n            and response.reason == \"Success\"\n            and await response.text() == \"Response body\"\n        )\n        assert response.headers[\"Content-Type\"] == content_type\n\n    @pytest.mark.asyncio\n    async def test_bad_performative_get_timeout_error(self):\n        \"\"\"Test send get request w/ 200 response.\"\"\"\n        self.http_connection.channel.timeout_window = 3\n        request_task = self.loop.create_task(self.request(\"get\", \"/pets\"))\n        envelope = await asyncio.wait_for(self.http_connection.receive(), timeout=10)\n        assert envelope\n        incoming_message, dialogue = self._get_message_and_dialogue(envelope)\n        incorrect_message = HttpMessage(\n            performative=HttpMessage.Performative.REQUEST,\n            dialogue_reference=dialogue.dialogue_label.dialogue_reference,\n            target=incoming_message.message_id,\n            message_id=incoming_message.message_id + 1,\n            method=\"post\",\n            url=\"/pets\",\n            version=incoming_message.version,\n            headers=incoming_message.headers,\n            body=b\"Request body\",\n        )\n        incorrect_message.to = incoming_message.sender\n\n        # the incorrect message cannot be sent into a dialogue, so this is omitted.\n\n        response_envelope = Envelope(\n            to=incorrect_message.to,\n            sender=envelope.to,\n            context=envelope.context,\n            message=incorrect_message,\n        )\n        with patch.object(self.http_connection.logger, \"warning\") as mock_logger:\n            await self.http_connection.send(response_envelope)\n            mock_logger.assert_any_call(\n                f\"Could not create dialogue for message={incorrect_message}\"\n            )\n\n        response = await asyncio.wait_for(request_task, timeout=10)\n\n        assert (\n            response.status == 408\n            and response.reason == \"Request Timeout\"\n            and await response.text() == \"\"\n        )\n\n    @pytest.mark.asyncio\n    async def test_late_message_get_timeout_error(self):\n        \"\"\"Test send get request w/ 200 response.\"\"\"\n        self.http_connection.channel.timeout_window = 1\n        request_task = self.loop.create_task(self.request(\"get\", \"/pets\"))\n        envelope = await asyncio.wait_for(self.http_connection.receive(), timeout=10)\n        assert envelope\n        incoming_message, dialogue = self._get_message_and_dialogue(envelope)\n        message = dialogue.reply(\n            target_message=incoming_message,\n            performative=HttpMessage.Performative.RESPONSE,\n            version=incoming_message.version,\n            headers=incoming_message.headers,\n            status_code=200,\n            status_text=\"Success\",\n            body=b\"Response body\",\n        )\n        response_envelope = Envelope(\n            to=message.to,\n            sender=envelope.to,\n            context=envelope.context,\n            message=message,\n        )\n        await asyncio.sleep(1.5)\n        with patch.object(self.http_connection.logger, \"warning\") as mock_logger:\n            await self.http_connection.send(response_envelope)\n            mock_logger.assert_any_call(\n                RegexComparator(\n                    \"Dropping message=.* for incomplete_dialogue_label=.* which has timed out.\"\n                )\n            )\n\n        response = await asyncio.wait_for(request_task, timeout=10)\n\n        assert (\n            response.status == 408\n            and response.reason == \"Request Timeout\"\n            and await response.text() == \"\"\n        )\n\n    @pytest.mark.asyncio\n    async def test_post_201(self):\n        \"\"\"Test send get request w/ 200 response.\"\"\"\n        request_task = self.loop.create_task(\n            self.request(\n                \"post\",\n                \"/pets\",\n            )\n        )\n        envelope = await asyncio.wait_for(self.http_connection.receive(), timeout=20)\n        assert envelope\n        incoming_message, dialogue = self._get_message_and_dialogue(envelope)\n        message = dialogue.reply(\n            target_message=incoming_message,\n            performative=HttpMessage.Performative.RESPONSE,\n            version=incoming_message.version,\n            status_code=201,\n            status_text=\"Created\",\n            body=b\"Response body\",\n        )\n        response_envelope = Envelope(\n            to=message.to,\n            sender=envelope.to,\n            context=envelope.context,\n            message=message,\n        )\n\n        await self.http_connection.send(response_envelope)\n\n        response = await asyncio.wait_for(\n            request_task,\n            timeout=20,\n        )\n        assert (\n            response.status == 201\n            and response.reason == \"Created\"\n            and await response.text() == \"Response body\"\n        )\n\n    @pytest.mark.asyncio\n    async def test_get_404(self):\n        \"\"\"Test send post request w/ 404 response.\"\"\"\n        response = await self.request(\"get\", \"/url-non-exists\")\n\n        assert (\n            response.status == 404\n            and response.reason == \"Request Not Found\"\n            and await response.text() == \"\"\n        )\n\n    @pytest.mark.asyncio\n    async def test_post_404(self):\n        \"\"\"Test send post request w/ 404 response.\"\"\"\n        response = await self.request(\"get\", \"/url-non-exists\", data=\"some data\")\n\n        assert (\n            response.status == 404\n            and response.reason == \"Request Not Found\"\n            and await response.text() == \"\"\n        )\n\n    @pytest.mark.asyncio\n    async def test_get_408(self):\n        \"\"\"Test send post request w/ 404 response.\"\"\"\n        await self.http_connection.connect()\n        self.http_connection.channel.timeout_window = 0.1\n        with patch.object(\n            self.http_connection.channel.logger, \"warning\"\n        ) as mock_logger:\n            response = await self.request(\"get\", \"/pets\")\n            mock_logger.assert_any_call(\n                RegexComparator(\"Request timed out! Request=.*\")\n            )\n\n        assert (\n            response.status == 408\n            and response.reason == \"Request Timeout\"\n            and await response.text() == \"\"\n        )\n\n    @pytest.mark.asyncio\n    async def test_post_408(self):\n        \"\"\"Test send post request w/ 404 response.\"\"\"\n        self.http_connection.channel.timeout_window = 0.1\n        response = await self.request(\"post\", \"/pets\", data=\"somedata\")\n\n        assert (\n            response.status == 408\n            and response.reason == \"Request Timeout\"\n            and await response.text() == \"\"\n        )\n\n    @pytest.mark.asyncio\n    async def test_send_connection_drop(self):\n        \"\"\"Test unexpected response.\"\"\"\n        message = HttpMessage(\n            performative=HttpMessage.Performative.RESPONSE,\n            dialogue_reference=(\"\", \"\"),\n            target=1,\n            message_id=2,\n            headers=\"\",\n            version=\"\",\n            status_code=200,\n            status_text=\"Success\",\n            body=b\"\",\n        )\n        message.to = str(HTTPServerConnection.connection_id)\n        message.sender = self.target_skill_id\n        envelope = Envelope(\n            to=message.to,\n            sender=message.sender,\n            message=message,\n        )\n        await self.http_connection.send(envelope)\n\n    @pytest.mark.asyncio\n    async def test_get_message_channel_not_connected(self):\n        \"\"\"Test error on channel get message if not connected.\"\"\"\n        await self.http_connection.disconnect()\n        with pytest.raises(ValueError):\n            await self.http_connection.channel.get_message()\n\n    @pytest.mark.asyncio\n    async def test_fail_connect(self):\n        \"\"\"Test error on server connection.\"\"\"\n        await self.http_connection.disconnect()\n\n        with patch.object(\n            self.http_connection.channel,\n            \"_start_http_server\",\n            side_effect=Exception(\"expected\"),\n        ):\n            await self.http_connection.connect()\n        assert not self.http_connection.is_connected\n\n    @pytest.mark.asyncio\n    async def test_server_error_on_send_response(self):\n        \"\"\"Test exception raised on response sending to the client.\"\"\"\n        request_task = self.loop.create_task(\n            self.request(\n                \"post\",\n                \"/pets\",\n            )\n        )\n        envelope = await asyncio.wait_for(self.http_connection.receive(), timeout=20)\n        assert envelope\n        incoming_message, dialogue = self._get_message_and_dialogue(envelope)\n        message = dialogue.reply(\n            target_message=incoming_message,\n            performative=HttpMessage.Performative.RESPONSE,\n            version=incoming_message.version,\n            headers=incoming_message.headers,\n            status_code=201,\n            status_text=\"Created\",\n            body=b\"Response body\",\n        )\n        response_envelope = Envelope(\n            to=message.to,\n            sender=envelope.to,\n            context=envelope.context,\n            message=message,\n        )\n\n        with patch.object(Response, \"from_message\", side_effect=Exception(\"expected\")):\n            await self.http_connection.send(response_envelope)\n            response = await asyncio.wait_for(\n                request_task,\n                timeout=20,\n            )\n\n        assert response and response.status == 500 and response.reason == \"Server Error\"\n\n    def teardown(self):\n        \"\"\"Teardown the test case.\"\"\"\n        self.loop.run_until_complete(self.http_connection.disconnect())\n        self.http_connection.channel.timeout_window = self.original_timeout\n\n\ndef test_bad_api_spec():\n    \"\"\"Test error on apispec file is invalid.\"\"\"\n    with pytest.raises(FileNotFoundError):\n        APISpec(\"not_exist_file\")\n\n\ndef test_apispec_verify_if_no_validator_set():\n    \"\"\"Test api spec ok if no spec file provided.\"\"\"\n    assert APISpec().verify(Mock())\n\n\n@pytest.mark.asyncio\nclass TestHTTPSServer:\n    \"\"\"Tests for HTTPServer connection.\"\"\"\n\n    async def request(self, method: str, path: str, **kwargs) -> ClientResponse:\n        \"\"\"\n        Make a http request.\n\n        :param method: HTTP method: GET, POST etc\n        :param path: path to request on server. full url constructed automatically\n\n        :return: http response\n        \"\"\"\n        try:\n            url = f\"https://{self.host}:{self.port}{path}\"\n            sslcontext = ssl.create_default_context(cafile=self.ssl_cert)\n            async with aiohttp.ClientSession() as session:\n                async with session.request(\n                    method, url, **kwargs, ssl=sslcontext\n                ) as resp:\n                    await resp.read()\n                    return resp\n        except Exception:\n            print_exc()\n            raise\n\n    def setup(self):\n        \"\"\"Initialise the test case.\"\"\"\n        self.identity = Identity(\"name\", address=\"my_key\", public_key=\"my_public_key\")\n        self.agent_address = self.identity.address\n        self.host = \"localhost\"\n        self.port = get_unused_tcp_port()\n        self.api_spec_path = os.path.join(\n            ROOT_DIR, \"tests\", \"data\", \"petstore_sim.yaml\"\n        )\n        self.connection_id = HTTPServerConnection.connection_id\n        self.protocol_id = HttpMessage.protocol_id\n        self.target_skill_id = \"some_author/some_skill:0.1.0\"\n        self.ssl_cert = os.path.join(ROOT_DIR, \"tests\", \"data\", \"certs\", \"server.crt\")\n        self.ssl_key = os.path.join(ROOT_DIR, \"tests\", \"data\", \"certs\", \"server.key\")\n        self.configuration = ConnectionConfig(\n            host=self.host,\n            port=self.port,\n            target_skill_id=self.target_skill_id,\n            api_spec_path=self.api_spec_path,\n            connection_id=HTTPServerConnection.connection_id,\n            restricted_to_protocols={HttpMessage.protocol_id},\n            ssl_cert=self.ssl_cert,\n            ssl_key=self.ssl_key,\n        )\n        self.http_connection = HTTPServerConnection(\n            configuration=self.configuration,\n            data_dir=MagicMock(),\n            identity=self.identity,\n        )\n        self.loop = asyncio.get_event_loop()\n        self.loop.run_until_complete(self.http_connection.connect())\n        self.connection_address = str(HTTPServerConnection.connection_id)\n        self._dialogues = HttpDialogues(self.target_skill_id)\n        self.original_timeout = self.http_connection.channel.timeout_window\n\n    @pytest.mark.asyncio\n    async def test_get_200(self):\n        \"\"\"Test send get request w/ 200 response.\"\"\"\n        request_task = self.loop.create_task(self.request(\"get\", \"/pets\"))\n        envelope = await asyncio.wait_for(self.http_connection.receive(), timeout=20)\n        assert envelope\n        incoming_message, dialogue = self._get_message_and_dialogue(envelope)\n        message = dialogue.reply(\n            target_message=incoming_message,\n            performative=HttpMessage.Performative.RESPONSE,\n            version=incoming_message.version,\n            status_code=200,\n            status_text=\"Success\",\n            body=b\"Response body\",\n        )\n        response_envelope = Envelope(\n            to=envelope.sender,\n            sender=envelope.to,\n            context=envelope.context,\n            message=message,\n        )\n        await self.http_connection.send(response_envelope)\n\n        response = await asyncio.wait_for(\n            request_task,\n            timeout=20,\n        )\n\n        assert (\n            response.status == 200\n            and response.reason == \"Success\"\n            and await response.text() == \"Response body\"\n        )\n\n    def _get_message_and_dialogue(\n        self, envelope: Envelope\n    ) -> Tuple[HttpMessage, HttpDialogue]:\n        message = cast(HttpMessage, envelope.message)\n        dialogue = cast(HttpDialogue, self._dialogues.update(message))\n        assert dialogue is not None\n        return message, dialogue\n"
  },
  {
    "path": "tests/test_aea_core_packages/test_connections/test_http_server/test_http_server_and_client.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Tests for the HTTP Client and Server connections together.\"\"\"\nimport asyncio\nimport email\nimport logging\nimport urllib\nfrom typing import Dict, Optional, cast\nfrom unittest.mock import MagicMock\n\nimport pytest\n\nfrom aea.common import Address\nfrom aea.configurations.base import ConnectionConfig\nfrom aea.identity.base import Identity\nfrom aea.mail.base import Envelope, Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\n\nfrom packages.fetchai.connections.http_client.connection import HTTPClientConnection\nfrom packages.fetchai.connections.http_server.connection import (\n    HTTPServerConnection,\n    headers_to_string,\n)\nfrom packages.fetchai.protocols.http.dialogues import HttpDialogue, HttpDialogues\nfrom packages.fetchai.protocols.http.message import HttpMessage\n\nfrom tests.conftest import get_host, get_unused_tcp_port\n\n\nlogger = logging.getLogger(__name__)\n\nSKILL_ID_STR = \"some_author/some_skill:0.1.0\"\n\n\nclass TestClientServer:\n    \"\"\"Client-Server end-to-end test.\"\"\"\n\n    def setup_server(self):\n        \"\"\"Set up server connection.\"\"\"\n        self.server_agent_address = \"server_agent_address\"\n        self.server_agent_public_key = \"server_agent_public_key\"\n        self.server_agent_identity = Identity(\n            \"agent_running_server\",\n            address=self.server_agent_address,\n            public_key=self.server_agent_public_key,\n        )\n        self.host = get_host()\n        self.port = get_unused_tcp_port()\n        self.connection_id = HTTPServerConnection.connection_id\n        self.protocol_id = HttpMessage.protocol_id\n        self.target_skill_id = SKILL_ID_STR\n\n        self.configuration = ConnectionConfig(\n            host=self.host,\n            port=self.port,\n            target_skill_id=self.target_skill_id,\n            api_spec_path=None,  # do not filter on API spec\n            connection_id=HTTPServerConnection.connection_id,\n        )\n        self.server = HTTPServerConnection(\n            configuration=self.configuration,\n            data_dir=MagicMock(),\n            identity=self.server_agent_identity,\n        )\n        self.loop = asyncio.get_event_loop()\n        self.loop.run_until_complete(self.server.connect())\n\n        # skill side dialogues\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return HttpDialogue.Role.SERVER\n\n        self._skill_dialogues = HttpDialogues(\n            SKILL_ID_STR, role_from_first_message=role_from_first_message\n        )\n\n    def setup_client(self):\n        \"\"\"Set up client connection.\"\"\"\n        self.client_agent_address = \"client_agent_address\"\n        self.client_agent_public_key = \"client_agent_public_key\"\n        self.client_agent_skill_id = \"some/skill:0.1.0\"\n        self.client_agent_identity = Identity(\n            \"agent_running_client\",\n            address=self.client_agent_address,\n            public_key=self.client_agent_public_key,\n        )\n        configuration = ConnectionConfig(\n            host=\"localhost\",\n            port=\"8888\",  # TODO: remove host/port for client?\n            connection_id=HTTPClientConnection.connection_id,\n        )\n        self.client = HTTPClientConnection(\n            configuration=configuration,\n            data_dir=MagicMock(),\n            identity=self.client_agent_identity,\n        )\n        self.loop.run_until_complete(self.client.connect())\n\n        # skill side dialogues\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return HttpDialogue.Role.CLIENT\n\n        self._client_dialogues = HttpDialogues(\n            self.client_agent_skill_id, role_from_first_message=role_from_first_message\n        )\n\n    def setup(self):\n        \"\"\"Set up test case.\"\"\"\n        self.setup_server()\n        self.setup_client()\n\n    def _make_request(\n        self,\n        path: str,\n        method: str = \"get\",\n        headers: Optional[Dict] = None,\n        body: bytes = b\"\",\n    ) -> Envelope:\n        \"\"\"Make request envelope.\"\"\"\n        request_http_message, _ = self._client_dialogues.create(\n            counterparty=str(HTTPClientConnection.connection_id),\n            performative=HttpMessage.Performative.REQUEST,\n            method=method,\n            url=f\"http://{self.host}:{self.port}{path}\",\n            headers=headers_to_string(headers) if headers else \"\",\n            version=\"\",\n            body=b\"\",\n        )\n        request_envelope = Envelope(\n            to=request_http_message.to,\n            sender=request_http_message.sender,\n            message=request_http_message,\n        )\n        return request_envelope\n\n    def _make_response(\n        self, request_envelope: Envelope, status_code: int = 200, status_text: str = \"\"\n    ) -> Envelope:\n        \"\"\"Make response envelope.\"\"\"\n        incoming_message = cast(HttpMessage, request_envelope.message)\n        dialogue = self._skill_dialogues.update(incoming_message)\n        assert dialogue is not None\n        message = dialogue.reply(\n            target_message=incoming_message,\n            performative=HttpMessage.Performative.RESPONSE,\n            version=incoming_message.version,\n            headers=incoming_message.headers,\n            status_code=status_code,\n            status_text=status_text,\n            body=incoming_message.body,\n        )\n        response_envelope = Envelope(\n            to=message.to,\n            sender=message.sender,\n            context=request_envelope.context,\n            message=message,\n        )\n        return response_envelope\n\n    @pytest.mark.asyncio\n    async def test_post_with_payload(self):\n        \"\"\"Test client and server with post request.\"\"\"\n        initial_request = self._make_request(\"/test\", \"POST\", body=b\"1234567890\")\n        await self.client.send(initial_request)\n        request = await asyncio.wait_for(self.server.receive(), timeout=5)\n        # this is \"inside\" the server agent\n        initial_response = self._make_response(request)\n        await self.server.send(initial_response)\n        response = await asyncio.wait_for(self.client.receive(), timeout=5)\n        assert (\n            cast(HttpMessage, initial_request.message).body\n            == cast(HttpMessage, response.message).body\n        )\n        assert (\n            initial_request.message.dialogue_reference[0]\n            == response.message.dialogue_reference[0]\n        )\n\n    @pytest.mark.asyncio\n    async def test_get_with_query(self):\n        \"\"\"Test client and server with url query.\"\"\"\n        query = {\"key\": \"value\"}\n        path = \"/test?{}\".format(urllib.parse.urlencode(query))\n        initial_request = self._make_request(path, \"GET\")\n        await self.client.send(initial_request)\n        request = await asyncio.wait_for(self.server.receive(), timeout=5)\n        # this is \"inside\" the server agent\n\n        parsed_query = dict(\n            urllib.parse.parse_qsl(\n                urllib.parse.urlparse(cast(HttpMessage, request.message).url).query\n            )\n        )\n        assert parsed_query == query\n        initial_response = self._make_response(request)\n        await self.server.send(initial_response)\n        response = await asyncio.wait_for(self.client.receive(), timeout=5)\n\n        assert (\n            initial_request.message.dialogue_reference[0]\n            == response.message.dialogue_reference[0]\n        )\n\n    @pytest.mark.asyncio\n    async def test_headers(self):\n        \"\"\"Test client and server with url query.\"\"\"\n        headers = {\"key1\": \"value1\", \"key2\": \"value2\"}\n        path = \"/test\"\n        initial_request = self._make_request(path, \"GET\", headers=headers)\n        await self.client.send(initial_request)\n\n        request = await asyncio.wait_for(self.server.receive(), timeout=5)\n        parsed_headers = dict(\n            email.message_from_string(\n                cast(HttpMessage, request.message).headers\n            ).items()\n        )\n        assert parsed_headers.items() >= headers.items()\n\n        initial_response = self._make_response(request)\n        await self.server.send(initial_response)\n\n        response = await asyncio.wait_for(self.client.receive(), timeout=5)\n        parsed_headers = dict(\n            email.message_from_string(\n                cast(HttpMessage, response.message).headers\n            ).items()\n        )\n        assert parsed_headers.items() >= headers.items()\n        assert (\n            initial_request.message.dialogue_reference[0]\n            == response.message.dialogue_reference[0]\n        )\n\n    def teardown(self):\n        \"\"\"Tear down testcase.\"\"\"\n        self.loop.run_until_complete(self.client.disconnect())\n        self.loop.run_until_complete(self.server.disconnect())\n"
  },
  {
    "path": "tests/test_aea_core_packages/test_connections/test_ledger/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains tests for the ledger API connection module, plus some utils.\"\"\"\n"
  },
  {
    "path": "tests/test_aea_core_packages/test_connections/test_ledger/test_contract_api.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the ledger API connection for the contract APIs.\"\"\"\nimport asyncio\nimport logging\nimport unittest.mock\nfrom typing import cast\nfrom unittest.mock import MagicMock, patch\n\nimport pytest\nfrom aea_ledger_ethereum import EthereumCrypto\n\nfrom aea.common import Address\nfrom aea.helpers.transaction.base import RawMessage, RawTransaction, State\nfrom aea.mail.base import Envelope\nfrom aea.multiplexer import MultiplexerStatus\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue\n\nfrom packages.fetchai.connections.ledger.contract_dispatcher import (\n    ContractApiRequestDispatcher,\n)\nfrom packages.fetchai.contracts.erc1155.contract import PUBLIC_ID as ERC1155_PUBLIC_ID\nfrom packages.fetchai.protocols.contract_api.dialogues import ContractApiDialogue\nfrom packages.fetchai.protocols.contract_api.dialogues import (\n    ContractApiDialogues as BaseContractApiDialogues,\n)\nfrom packages.fetchai.protocols.contract_api.message import ContractApiMessage\n\nfrom tests.conftest import ETHEREUM_ADDRESS_ONE\n\n\nSOME_SKILL_ID = \"some/skill:0.1.0\"\n\n\nclass ContractApiDialogues(BaseContractApiDialogues):\n    \"\"\"This class keeps track of all contract_api dialogues.\"\"\"\n\n    def __init__(self, self_address: str) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param self_address: the address of the entity for whom dialogues are maintained\n        :return: None\n        \"\"\"\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> Dialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return ContractApiDialogue.Role.AGENT\n\n        BaseContractApiDialogues.__init__(\n            self,\n            self_address=self_address,\n            role_from_first_message=role_from_first_message,\n        )\n\n\n@pytest.mark.integration\n@pytest.mark.ledger\n@pytest.mark.asyncio\nasync def test_erc1155_get_deploy_transaction(erc1155_contract, ledger_apis_connection):\n    \"\"\"Test get state with contract erc1155.\"\"\"\n    contract_api_dialogues = ContractApiDialogues(SOME_SKILL_ID)\n    request, contract_api_dialogue = contract_api_dialogues.create(\n        counterparty=str(ledger_apis_connection.connection_id),\n        performative=ContractApiMessage.Performative.GET_DEPLOY_TRANSACTION,\n        ledger_id=EthereumCrypto.identifier,\n        contract_id=str(ERC1155_PUBLIC_ID),\n        callable=\"get_deploy_transaction\",\n        kwargs=ContractApiMessage.Kwargs({\"deployer_address\": ETHEREUM_ADDRESS_ONE}),\n    )\n    envelope = Envelope(\n        to=request.to,\n        sender=request.sender,\n        message=request,\n    )\n\n    await ledger_apis_connection.send(envelope)\n    await asyncio.sleep(0.01)\n    response = await ledger_apis_connection.receive()\n\n    assert response is not None\n    assert type(response.message) == ContractApiMessage\n    response_message = cast(ContractApiMessage, response.message)\n    assert (\n        response_message.performative == ContractApiMessage.Performative.RAW_TRANSACTION\n    ), \"Error: {}\".format(response_message.message)\n    response_dialogue = contract_api_dialogues.update(response_message)\n    assert response_dialogue == contract_api_dialogue\n    assert type(response_message.raw_transaction) == RawTransaction\n    assert response_message.raw_transaction.ledger_id == EthereumCrypto.identifier\n    assert len(response.message.raw_transaction.body) == 6\n    assert len(response.message.raw_transaction.body[\"data\"]) > 0\n\n\n@pytest.mark.integration\n@pytest.mark.ledger\n@pytest.mark.asyncio\nasync def test_erc1155_get_raw_transaction(\n    erc1155_contract,\n    ledger_apis_connection,\n    update_default_ethereum_ledger_api,\n    ganache,\n):\n    \"\"\"Test get state with contract erc1155.\"\"\"\n    contract, contract_address = erc1155_contract\n    contract_api_dialogues = ContractApiDialogues(SOME_SKILL_ID)\n    request, contract_api_dialogue = contract_api_dialogues.create(\n        counterparty=str(ledger_apis_connection.connection_id),\n        performative=ContractApiMessage.Performative.GET_RAW_TRANSACTION,\n        ledger_id=EthereumCrypto.identifier,\n        contract_id=str(ERC1155_PUBLIC_ID),\n        contract_address=contract_address,\n        callable=\"get_create_batch_transaction\",\n        kwargs=ContractApiMessage.Kwargs(\n            {\n                \"deployer_address\": ETHEREUM_ADDRESS_ONE,\n                \"token_ids\": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],\n            }\n        ),\n    )\n    envelope = Envelope(\n        to=request.to,\n        sender=request.sender,\n        message=request,\n    )\n\n    await ledger_apis_connection.send(envelope)\n    await asyncio.sleep(0.01)\n    response = await ledger_apis_connection.receive()\n\n    assert response is not None\n    assert type(response.message) == ContractApiMessage\n    response_message = cast(ContractApiMessage, response.message)\n    assert (\n        response_message.performative == ContractApiMessage.Performative.RAW_TRANSACTION\n    ), \"Error: {}\".format(response_message.message)\n\n    response_dialogue = contract_api_dialogues.update(response_message)\n    assert response_dialogue == contract_api_dialogue\n    assert type(response_message.raw_transaction) == RawTransaction\n    assert response_message.raw_transaction.ledger_id == EthereumCrypto.identifier\n    assert len(response.message.raw_transaction.body) == 7\n    assert len(response.message.raw_transaction.body[\"data\"]) > 0\n\n\n@pytest.mark.integration\n@pytest.mark.ledger\n@pytest.mark.asyncio\nasync def test_erc1155_get_raw_message(erc1155_contract, ledger_apis_connection):\n    \"\"\"Test get state with contract erc1155.\"\"\"\n    contract, contract_address = erc1155_contract\n    contract_api_dialogues = ContractApiDialogues(SOME_SKILL_ID)\n    request, contract_api_dialogue = contract_api_dialogues.create(\n        counterparty=str(ledger_apis_connection.connection_id),\n        performative=ContractApiMessage.Performative.GET_RAW_MESSAGE,\n        ledger_id=EthereumCrypto.identifier,\n        contract_id=str(ERC1155_PUBLIC_ID),\n        contract_address=contract_address,\n        callable=\"get_hash_single\",\n        kwargs=ContractApiMessage.Kwargs(\n            {\n                \"from_address\": ETHEREUM_ADDRESS_ONE,\n                \"to_address\": ETHEREUM_ADDRESS_ONE,\n                \"token_id\": 1,\n                \"from_supply\": 10,\n                \"to_supply\": 0,\n                \"value\": 0,\n                \"trade_nonce\": 1,\n            }\n        ),\n    )\n    envelope = Envelope(\n        to=request.to,\n        sender=request.sender,\n        message=request,\n    )\n\n    await ledger_apis_connection.send(envelope)\n    await asyncio.sleep(0.01)\n    response = await ledger_apis_connection.receive()\n\n    assert response is not None\n    assert type(response.message) == ContractApiMessage\n    response_message = cast(ContractApiMessage, response.message)\n    assert (\n        response_message.performative == ContractApiMessage.Performative.RAW_MESSAGE\n    ), \"Error: {}\".format(response_message.message)\n    response_dialogue = contract_api_dialogues.update(response_message)\n    assert response_dialogue == contract_api_dialogue\n    assert type(response_message.raw_message) == RawMessage\n    assert response_message.raw_message.ledger_id == EthereumCrypto.identifier\n    assert type(response.message.raw_message.body) == bytes\n\n\n@pytest.mark.integration\n@pytest.mark.ledger\n@pytest.mark.asyncio\nasync def test_erc1155_get_state(erc1155_contract, ledger_apis_connection):\n    \"\"\"Test get state with contract erc1155.\"\"\"\n    contract, contract_address = erc1155_contract\n    contract_api_dialogues = ContractApiDialogues(SOME_SKILL_ID)\n    token_id = 1\n    request, contract_api_dialogue = contract_api_dialogues.create(\n        counterparty=str(ledger_apis_connection.connection_id),\n        performative=ContractApiMessage.Performative.GET_STATE,\n        ledger_id=EthereumCrypto.identifier,\n        contract_id=str(ERC1155_PUBLIC_ID),\n        contract_address=contract_address,\n        callable=\"get_balance\",\n        kwargs=ContractApiMessage.Kwargs(\n            {\"agent_address\": ETHEREUM_ADDRESS_ONE, \"token_id\": token_id}\n        ),\n    )\n    envelope = Envelope(\n        to=request.to,\n        sender=request.sender,\n        message=request,\n    )\n\n    await ledger_apis_connection.send(envelope)\n    await asyncio.sleep(0.01)\n    response = await ledger_apis_connection.receive()\n\n    assert response is not None\n    assert type(response.message) == ContractApiMessage\n    response_message = cast(ContractApiMessage, response.message)\n    assert (\n        response_message.performative == ContractApiMessage.Performative.STATE\n    ), \"Error: {}\".format(response_message.message)\n    response_dialogue = contract_api_dialogues.update(response_message)\n    assert response_dialogue == contract_api_dialogue\n    assert type(response_message.state) == State\n    assert response_message.state.ledger_id == EthereumCrypto.identifier\n    result = response_message.state.body.get(\"balance\", None)\n    expected_result = {token_id: 0}\n    assert result is not None and result == expected_result\n\n\n@pytest.mark.asyncio\nasync def test_run_async():\n    \"\"\"Test run async error handled.\"\"\"\n    # for pydocstyle\n    def _raise():\n        raise Exception(\"Expected\")\n\n    contract_api_dialogues = ContractApiDialogues(SOME_SKILL_ID)\n    request, dialogue = contract_api_dialogues.create(\n        counterparty=\"str(ledger_apis_connection.connection_id)\",\n        performative=ContractApiMessage.Performative.GET_RAW_TRANSACTION,\n        ledger_id=EthereumCrypto.identifier,\n        contract_id=str(ERC1155_PUBLIC_ID),\n        contract_address=\"test addr\",\n        callable=\"get_create_batch_transaction\",\n        kwargs=ContractApiMessage.Kwargs(\n            {\n                \"deployer_address\": \"test_addr\",\n                \"token_ids\": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],\n            }\n        ),\n    )\n    api = None\n    msg = await ContractApiRequestDispatcher(MultiplexerStatus()).run_async(\n        _raise, api, request, dialogue\n    )\n    assert msg.performative == ContractApiMessage.Performative.ERROR\n\n\n@pytest.mark.asyncio\nasync def test_get_handler():\n    \"\"\"Test failed to get handler.\"\"\"\n    with pytest.raises(Exception, match=\"Performative not recognized.\"):\n        ContractApiRequestDispatcher(MultiplexerStatus()).get_handler(\n            ContractApiMessage.Performative.ERROR\n        )\n\n\n@pytest.mark.integration\n@pytest.mark.ledger\n@pytest.mark.asyncio\nasync def test_callable_wrong_number_of_arguments_api_and_contract_address(\n    erc1155_contract, ledger_apis_connection\n):\n    \"\"\"\n    Test a contract callable with wrong number of arguments.\n\n    Test the case of either GET_STATE, GET_RAW_MESSAGE or GET_RAW_TRANSACTION.\n    \"\"\"\n    contract, contract_address = erc1155_contract\n    contract_api_dialogues = ContractApiDialogues(SOME_SKILL_ID)\n    token_id = 1\n    request, _ = contract_api_dialogues.create(\n        counterparty=str(ledger_apis_connection.connection_id),\n        performative=ContractApiMessage.Performative.GET_STATE,\n        ledger_id=EthereumCrypto.identifier,\n        contract_id=str(ERC1155_PUBLIC_ID),\n        contract_address=contract_address,\n        callable=\"get_balance\",\n        kwargs=ContractApiMessage.Kwargs(\n            {\"agent_address\": ETHEREUM_ADDRESS_ONE, \"token_id\": token_id}\n        ),\n    )\n    envelope = Envelope(\n        to=request.to,\n        sender=request.sender,\n        message=request,\n    )\n\n    with unittest.mock.patch(\n        \"inspect.getfullargspec\", return_value=unittest.mock.MagicMock(args=[None])\n    ):\n        with unittest.mock.patch.object(\n            ledger_apis_connection._logger, \"error\"\n        ) as mock_logger:\n            await ledger_apis_connection.send(envelope)\n            await asyncio.sleep(0.01)\n            response = await ledger_apis_connection.receive()\n            mock_logger.assert_any_call(\n                \"Exception during contract request: Expected two or more positional arguments, got 1\"\n            )\n            assert (\n                response.message.performative == ContractApiMessage.Performative.ERROR\n            )\n            assert (\n                response.message.message\n                == \"Expected two or more positional arguments, got 1\"\n            )\n\n\n@pytest.mark.integration\n@pytest.mark.ledger\n@pytest.mark.asyncio\nasync def test_callable_wrong_number_of_arguments_apis(\n    erc1155_contract, ledger_apis_connection\n):\n    \"\"\"\n    Test a contract callable with wrong number of arguments.\n\n    Test the case of either GET_DEPLOY_TRANSACTION.\n    \"\"\"\n    contract, contract_address = erc1155_contract\n    contract_api_dialogues = ContractApiDialogues(SOME_SKILL_ID)\n    request, _ = contract_api_dialogues.create(\n        counterparty=str(ledger_apis_connection.connection_id),\n        performative=ContractApiMessage.Performative.GET_DEPLOY_TRANSACTION,\n        ledger_id=EthereumCrypto.identifier,\n        contract_id=str(ERC1155_PUBLIC_ID),\n        callable=\"get_deploy_transaction\",\n        kwargs=ContractApiMessage.Kwargs({}),\n    )\n    envelope = Envelope(\n        to=request.to,\n        sender=request.sender,\n        message=request,\n    )\n\n    with unittest.mock.patch(\n        \"inspect.getfullargspec\", return_value=unittest.mock.MagicMock(args=[])\n    ):\n        with unittest.mock.patch.object(\n            ledger_apis_connection._contract_dispatcher, \"_call_stub\", return_value=None\n        ):\n            with unittest.mock.patch.object(\n                ledger_apis_connection._contract_dispatcher.logger, \"error\"\n            ) as mock_logger:\n                await ledger_apis_connection.send(envelope)\n                await asyncio.sleep(0.01)\n                response = await ledger_apis_connection.receive()\n                mock_logger.assert_any_call(\n                    \"Exception during contract request: Expected one or more positional arguments, got 0\"\n                )\n                assert (\n                    response.message.performative\n                    == ContractApiMessage.Performative.ERROR\n                )\n                assert (\n                    response.message.message\n                    == \"Expected one or more positional arguments, got 0\"\n                )\n\n\n@pytest.mark.integration\n@pytest.mark.ledger\n@pytest.mark.asyncio\nasync def test_callable_wrong_number_of_arguments_apis_method_call(\n    erc1155_contract, ledger_apis_connection, caplog\n):\n    \"\"\"\n    Test a contract callable with wrong number of arguments.\n\n    Test the case of either GET_DEPLOY_TRANSACTION.\n    \"\"\"\n    contract, contract_address = erc1155_contract\n    contract_api_dialogues = ContractApiDialogues(SOME_SKILL_ID)\n    request, _ = contract_api_dialogues.create(\n        counterparty=str(ledger_apis_connection.connection_id),\n        performative=ContractApiMessage.Performative.GET_DEPLOY_TRANSACTION,\n        ledger_id=EthereumCrypto.identifier,\n        contract_id=str(ERC1155_PUBLIC_ID),\n        callable=\"get_deploy_transaction\",\n        kwargs=ContractApiMessage.Kwargs({}),\n    )\n    envelope = Envelope(\n        to=request.to,\n        sender=request.sender,\n        message=request,\n    )\n\n    with unittest.mock.patch.object(\n        ledger_apis_connection._contract_dispatcher, \"_call_stub\", return_value=None\n    ):\n        with caplog.at_level(logging.DEBUG, \"aea.packages.fetchai.connections.ledger\"):\n            await ledger_apis_connection.send(envelope)\n            await asyncio.sleep(0.01)\n            assert (\n                \"An error occurred while processing the contract api request:\"\n                in caplog.text\n            )\n            assert (\n                \"get_deploy_transaction() missing 1 required positional argument: 'deployer_address\"\n                in caplog.text\n            )\n\n\n@pytest.mark.integration\n@pytest.mark.ledger\n@pytest.mark.asyncio\nasync def test_callable_generic_error(erc1155_contract, ledger_apis_connection):\n    \"\"\"Test error messages when an exception is raised while processing the request.\"\"\"\n    contract, contract_address = erc1155_contract\n    contract_api_dialogues = ContractApiDialogues(SOME_SKILL_ID)\n    token_id = 1\n    request, _ = contract_api_dialogues.create(\n        counterparty=str(ledger_apis_connection.connection_id),\n        performative=ContractApiMessage.Performative.GET_STATE,\n        ledger_id=EthereumCrypto.identifier,\n        contract_id=str(ERC1155_PUBLIC_ID),\n        contract_address=contract_address,\n        callable=\"get_balance\",\n        kwargs=ContractApiMessage.Kwargs(\n            {\"agent_address\": ETHEREUM_ADDRESS_ONE, \"token_id\": token_id}\n        ),\n    )\n    envelope = Envelope(\n        to=request.to,\n        sender=request.sender,\n        message=request,\n    )\n\n    with unittest.mock.patch(\n        \"inspect.getfullargspec\", side_effect=Exception(\"Generic error\")\n    ):\n        with unittest.mock.patch.object(\n            ledger_apis_connection._logger, \"error\"\n        ) as mock_logger:\n            await ledger_apis_connection.send(envelope)\n            await asyncio.sleep(0.01)\n            response = await ledger_apis_connection.receive()\n            mock_logger.assert_any_call(\n                \"An error occurred while processing the contract api request: 'Generic error'.\"\n            )\n            assert (\n                response.message.performative == ContractApiMessage.Performative.ERROR\n            )\n            assert response.message.message == \"Generic error\"\n\n\n@pytest.mark.integration\n@pytest.mark.ledger\n@pytest.mark.asyncio\nasync def test_callable_cannot_find(erc1155_contract, ledger_apis_connection, caplog):\n    \"\"\"Test error messages when an exception is raised while processing the request.\"\"\"\n    contract, contract_address = erc1155_contract\n    contract_api_dialogues = ContractApiDialogues(SOME_SKILL_ID)\n    token_id = 1\n    request, _ = contract_api_dialogues.create(\n        counterparty=str(ledger_apis_connection.connection_id),\n        performative=ContractApiMessage.Performative.GET_STATE,\n        ledger_id=EthereumCrypto.identifier,\n        contract_id=str(ERC1155_PUBLIC_ID),\n        contract_address=contract_address,\n        callable=\"unknown_callable\",\n        kwargs=ContractApiMessage.Kwargs(\n            {\"agent_address\": ETHEREUM_ADDRESS_ONE, \"token_id\": token_id}\n        ),\n    )\n    envelope = Envelope(\n        to=request.to,\n        sender=request.sender,\n        message=request,\n    )\n\n    with caplog.at_level(logging.DEBUG, \"aea.packages.fetchai.connections.ledger\"):\n        await ledger_apis_connection.send(envelope)\n        await asyncio.sleep(0.01)\n        assert f\"Cannot find {request.callable} in contract\" in caplog.text\n\n\ndef test_build_response_fails_on_bad_data_type():\n    \"\"\"Test internal build_response functions for data type check.\"\"\"\n    dispatcher = ContractApiRequestDispatcher(MagicMock())\n    with patch.object(\n        dispatcher,\n        \"dispatch_request\",\n        lambda x, x1, x2, fn: fn(data=b\"some_data\", dialogue=MagicMock()),\n    ), pytest.raises(\n        ValueError, match=r\"Invalid state type, got=<class '.+'>, expected=typing.Dict\"\n    ):\n        dispatcher.get_state(MagicMock(), MagicMock(), MagicMock())\n\n    with patch.object(\n        dispatcher,\n        \"dispatch_request\",\n        lambda x, x1, x2, fn: fn(rm=12, dialogue=MagicMock()),\n    ), pytest.raises(ValueError, match=r\"Invalid message type\"):\n        dispatcher.get_raw_message(MagicMock(), MagicMock(), MagicMock())\n\n    with patch.object(\n        dispatcher,\n        \"dispatch_request\",\n        lambda x, x1, x2, fn: fn(tx=b\"some_data\", dialogue=MagicMock()),\n    ):\n        with pytest.raises(\n            ValueError,\n            match=r\"Invalid transaction type, got=<class '.+'>, expected=typing.Dict\",\n        ):\n            dispatcher.get_deploy_transaction(MagicMock(), MagicMock(), MagicMock())\n        with pytest.raises(\n            ValueError,\n            match=r\"Invalid transaction type, got=<class '.+'>, expected=typing.Dict\",\n        ):\n            dispatcher.get_raw_transaction(MagicMock(), MagicMock(), MagicMock())\n"
  },
  {
    "path": "tests/test_aea_core_packages/test_connections/test_ledger/test_ledger_api.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\n\"\"\"This module contains the tests of the ledger API connection module.\"\"\"\nimport asyncio\nimport logging\nfrom typing import cast\nfrom unittest.mock import Mock, patch\n\nimport pytest\nfrom aea_ledger_ethereum import EthereumCrypto\nfrom aea_ledger_fetchai import FetchAICrypto\n\nfrom aea.common import Address\nfrom aea.configurations.base import PublicId\nfrom aea.connections.base import Connection, ConnectionStates\nfrom aea.crypto.ledger_apis import LedgerApis\nfrom aea.crypto.registries import make_crypto, make_ledger_api\nfrom aea.helpers.async_utils import AsyncState\nfrom aea.helpers.transaction.base import (\n    RawTransaction,\n    SignedTransaction,\n    Terms,\n    TransactionDigest,\n    TransactionReceipt,\n)\nfrom aea.mail.base import Envelope, Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\n\nfrom packages.fetchai.connections.ledger.connection import LedgerConnection\nfrom packages.fetchai.connections.ledger.ledger_dispatcher import (\n    LedgerApiRequestDispatcher,\n)\nfrom packages.fetchai.protocols.ledger_api.custom_types import Kwargs\nfrom packages.fetchai.protocols.ledger_api.dialogues import LedgerApiDialogue\nfrom packages.fetchai.protocols.ledger_api.dialogues import (\n    LedgerApiDialogues as BaseLedgerApiDialogues,\n)\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\n\nfrom tests.conftest import (\n    ETHEREUM_PRIVATE_KEY_PATH,\n    FETCHAI_ADDRESS_ONE,\n    FETCHAI_TESTNET_CONFIG,\n)\n\n\nlogger = logging.getLogger(__name__)\n\n\nledger_ids = pytest.mark.parametrize(\n    \"ledger_id,address\",\n    [\n        (FetchAICrypto.identifier, FETCHAI_ADDRESS_ONE),\n        (EthereumCrypto.identifier, EthereumCrypto(ETHEREUM_PRIVATE_KEY_PATH).address),\n    ],\n)\ngas_price_strategies = pytest.mark.parametrize(\n    \"gas_price_strategy\",\n    [None, \"average\"],\n)\n\nSOME_SKILL_ID = \"some/skill:0.1.0\"\n\n\nclass LedgerApiDialogues(BaseLedgerApiDialogues):\n    \"\"\"The dialogues class keeps track of all ledger_api dialogues.\"\"\"\n\n    def __init__(self, self_address: Address, **kwargs) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :return: None\n        \"\"\"\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return LedgerApiDialogue.Role.AGENT\n\n        BaseLedgerApiDialogues.__init__(\n            self,\n            self_address=self_address,\n            role_from_first_message=role_from_first_message,\n        )\n\n\n@pytest.mark.integration\n@pytest.mark.ledger\n@pytest.mark.asyncio\n@ledger_ids\nasync def test_get_balance(\n    ledger_id,\n    address,\n    ledger_apis_connection: Connection,\n    update_default_ethereum_ledger_api,\n    ethereum_testnet_config,\n    ganache,\n):\n    \"\"\"Test get balance.\"\"\"\n    import aea  # noqa # to load registries\n\n    if ledger_id == FetchAICrypto.identifier:\n        config = FETCHAI_TESTNET_CONFIG\n    else:\n        config = ethereum_testnet_config\n\n    ledger_api_dialogues = LedgerApiDialogues(SOME_SKILL_ID)\n    request, ledger_api_dialogue = ledger_api_dialogues.create(\n        counterparty=str(ledger_apis_connection.connection_id),\n        performative=LedgerApiMessage.Performative.GET_BALANCE,\n        ledger_id=ledger_id,\n        address=address,\n    )\n    envelope = Envelope(\n        to=request.to,\n        sender=request.sender,\n        message=request,\n    )\n\n    await ledger_apis_connection.send(envelope)\n    await asyncio.sleep(0.01)\n    response = await ledger_apis_connection.receive()\n\n    assert response is not None\n    assert type(response.message) == LedgerApiMessage\n    response_msg = cast(LedgerApiMessage, response.message)\n    response_dialogue = ledger_api_dialogues.update(response_msg)\n    assert response_dialogue == ledger_api_dialogue\n    assert response_msg.performative == LedgerApiMessage.Performative.BALANCE\n    actual_balance_amount = response_msg.balance\n    expected_balance_amount = make_ledger_api(ledger_id, **config).get_balance(address)\n    assert actual_balance_amount == expected_balance_amount\n\n\n@pytest.mark.integration\n@pytest.mark.ledger\n@pytest.mark.asyncio\n@ledger_ids\nasync def test_get_state(\n    ledger_id,\n    address,\n    ledger_apis_connection: Connection,\n    update_default_ethereum_ledger_api,\n    ethereum_testnet_config,\n    ganache,\n):\n    \"\"\"Test get state.\"\"\"\n    import aea  # noqa # to load registries\n\n    if ledger_id == FetchAICrypto.identifier:\n        config = FETCHAI_TESTNET_CONFIG\n    else:\n        config = ethereum_testnet_config\n\n    if \"ethereum\" in ledger_id:\n        callable_name = \"getBlock\"\n    else:\n        callable_name = \"blocks\"\n    args = (\"latest\",)\n    kwargs = Kwargs({})\n\n    ledger_api_dialogues = LedgerApiDialogues(SOME_SKILL_ID)\n    request, ledger_api_dialogue = ledger_api_dialogues.create(\n        counterparty=str(ledger_apis_connection.connection_id),\n        performative=LedgerApiMessage.Performative.GET_STATE,\n        ledger_id=ledger_id,\n        callable=callable_name,\n        args=args,\n        kwargs=kwargs,\n    )\n    envelope = Envelope(\n        to=request.to,\n        sender=request.sender,\n        message=request,\n    )\n\n    await ledger_apis_connection.send(envelope)\n    await asyncio.sleep(0.01)\n    response = await ledger_apis_connection.receive()\n\n    assert response is not None\n    assert type(response.message) == LedgerApiMessage\n    response_msg = cast(LedgerApiMessage, response.message)\n    response_dialogue = ledger_api_dialogues.update(response_msg)\n    assert response_dialogue == ledger_api_dialogue\n\n    assert (\n        response_msg.performative == LedgerApiMessage.Performative.STATE\n    ), response_msg\n    actual_block = response_msg.state.body\n    expected_block = make_ledger_api(ledger_id, **config).get_state(\n        callable_name, *args\n    )\n    assert actual_block == expected_block\n\n\n@pytest.mark.integration\n@pytest.mark.ledger\n@pytest.mark.asyncio\n@gas_price_strategies\nasync def test_send_signed_transaction_ethereum(\n    gas_price_strategy,\n    ledger_apis_connection: Connection,\n    update_default_ethereum_ledger_api,\n    ganache,\n):\n    \"\"\"Test send signed transaction with Ethereum APIs.\"\"\"\n    import aea  # noqa # to load registries\n\n    crypto1 = make_crypto(\n        EthereumCrypto.identifier, private_key_path=ETHEREUM_PRIVATE_KEY_PATH\n    )\n    crypto2 = make_crypto(EthereumCrypto.identifier)\n    ledger_api_dialogues = LedgerApiDialogues(SOME_SKILL_ID)\n\n    amount = 40000\n    fee = 30000\n\n    request, ledger_api_dialogue = ledger_api_dialogues.create(\n        counterparty=str(ledger_apis_connection.connection_id),\n        performative=LedgerApiMessage.Performative.GET_RAW_TRANSACTION,\n        terms=Terms(\n            ledger_id=EthereumCrypto.identifier,\n            sender_address=crypto1.address,\n            counterparty_address=crypto2.address,\n            amount_by_currency_id={\"ETH\": -amount},\n            quantities_by_good_id={\"some_service_id\": 1},\n            is_sender_payable_tx_fee=True,\n            nonce=\"\",\n            fee_by_currency_id={\"ETH\": fee},\n            chain_id=3,\n            gas_price_strategy=gas_price_strategy,\n        ),\n    )\n    request = cast(LedgerApiMessage, request)\n    envelope = Envelope(\n        to=request.to,\n        sender=request.sender,\n        message=request,\n    )\n    await ledger_apis_connection.send(envelope)\n    await asyncio.sleep(0.01)\n    response = await ledger_apis_connection.receive()\n\n    assert response is not None\n    assert type(response.message) == LedgerApiMessage\n    response_message = cast(LedgerApiMessage, response.message)\n    assert (\n        response_message.performative == LedgerApiMessage.Performative.RAW_TRANSACTION\n    )\n    response_dialogue = ledger_api_dialogues.update(response_message)\n    assert response_dialogue == ledger_api_dialogue\n    assert type(response_message.raw_transaction) == RawTransaction\n    assert response_message.raw_transaction.ledger_id == request.terms.ledger_id\n\n    signed_transaction = crypto1.sign_transaction(response_message.raw_transaction.body)\n    request = cast(\n        LedgerApiMessage,\n        ledger_api_dialogue.reply(\n            performative=LedgerApiMessage.Performative.SEND_SIGNED_TRANSACTION,\n            target_message=response_message,\n            signed_transaction=SignedTransaction(\n                EthereumCrypto.identifier, signed_transaction\n            ),\n        ),\n    )\n    envelope = Envelope(\n        to=request.to,\n        sender=request.sender,\n        message=request,\n    )\n    await ledger_apis_connection.send(envelope)\n    await asyncio.sleep(0.01)\n    response = await ledger_apis_connection.receive()\n\n    assert response is not None\n    assert type(response.message) == LedgerApiMessage\n    response_message = cast(LedgerApiMessage, response.message)\n    assert (\n        response_message.performative != LedgerApiMessage.Performative.ERROR\n    ), f\"Received error: {response_message.message}\"\n    assert (\n        response_message.performative\n        == LedgerApiMessage.Performative.TRANSACTION_DIGEST\n    )\n    response_dialogue = ledger_api_dialogues.update(response_message)\n    assert response_dialogue == ledger_api_dialogue\n    assert type(response_message.transaction_digest) == TransactionDigest\n    assert type(response_message.transaction_digest.body) == str\n    assert (\n        response_message.transaction_digest.ledger_id\n        == request.signed_transaction.ledger_id\n    )\n    assert type(response_message.transaction_digest.body.startswith(\"0x\"))\n\n    request = cast(\n        LedgerApiMessage,\n        ledger_api_dialogue.reply(\n            performative=LedgerApiMessage.Performative.GET_TRANSACTION_RECEIPT,\n            target_message=response_message,\n            transaction_digest=response_message.transaction_digest,\n        ),\n    )\n    envelope = Envelope(\n        to=request.to,\n        sender=request.sender,\n        message=request,\n    )\n    await ledger_apis_connection.send(envelope)\n    await asyncio.sleep(0.01)\n    response = await ledger_apis_connection.receive()\n\n    assert response is not None\n    assert type(response.message) == LedgerApiMessage\n    response_message = cast(LedgerApiMessage, response.message)\n    assert (\n        response_message.performative\n        == LedgerApiMessage.Performative.TRANSACTION_RECEIPT\n    )\n    response_dialogue = ledger_api_dialogues.update(response_message)\n    assert response_dialogue == ledger_api_dialogue\n    assert type(response_message.transaction_receipt) == TransactionReceipt\n    assert response_message.transaction_receipt.receipt is not None\n    assert response_message.transaction_receipt.transaction is not None\n    assert (\n        response_message.transaction_receipt.ledger_id\n        == request.transaction_digest.ledger_id\n    )\n    assert LedgerApis.is_transaction_settled(\n        response_message.transaction_receipt.ledger_id,\n        response_message.transaction_receipt.receipt,\n    ), \"Transaction not settled.\"\n\n\n@pytest.mark.asyncio\nasync def test_unsupported_protocol(ledger_apis_connection: LedgerConnection):\n    \"\"\"Test fail on protocol not supported.\"\"\"\n    envelope = Envelope(\n        to=str(ledger_apis_connection.connection_id),\n        sender=\"test/skill:0.1.0\",\n        protocol_specification_id=PublicId.from_str(\"author/package_name:0.1.0\"),\n        message=b\"message\",\n    )\n    with pytest.raises(ValueError):\n        ledger_apis_connection._schedule_request(envelope)\n\n\n@pytest.mark.asyncio\nasync def test_new_message_wait_flag(ledger_apis_connection: LedgerConnection):\n    \"\"\"Test wait for new message.\"\"\"\n    task = asyncio.ensure_future(ledger_apis_connection.receive())\n    await asyncio.sleep(0.1)\n    assert not task.done()\n    task.cancel()\n\n\n@pytest.mark.asyncio\nasync def test_no_balance():\n    \"\"\"Test no balance.\"\"\"\n    dispatcher = LedgerApiRequestDispatcher(AsyncState())\n    mock_api = Mock()\n    message = LedgerApiMessage(\n        performative=LedgerApiMessage.Performative.GET_BALANCE,\n        dialogue_reference=dispatcher.dialogues.new_self_initiated_dialogue_reference(),\n        ledger_id=EthereumCrypto.identifier,\n        address=\"test\",\n    )\n    message.to = dispatcher.dialogues.self_address\n    message.sender = \"test\"\n    dialogue = dispatcher.dialogues.update(message)\n    assert dialogue is not None\n    mock_api.get_balance.return_value = None\n    msg = dispatcher.get_balance(mock_api, message, dialogue)\n\n    assert msg.performative == LedgerApiMessage.Performative.ERROR\n\n\n@pytest.mark.asyncio\nasync def test_no_raw_tx():\n    \"\"\"Test no raw tx returned.\"\"\"\n    dispatcher = LedgerApiRequestDispatcher(AsyncState())\n    mock_api = Mock()\n    message = LedgerApiMessage(\n        performative=LedgerApiMessage.Performative.GET_RAW_TRANSACTION,\n        dialogue_reference=dispatcher.dialogues.new_self_initiated_dialogue_reference(),\n        terms=Terms(\n            ledger_id=EthereumCrypto.identifier,\n            sender_address=\"1111\",\n            counterparty_address=\"22222\",\n            amount_by_currency_id={\"ETH\": -1},\n            quantities_by_good_id={\"some_service_id\": 1},\n            is_sender_payable_tx_fee=True,\n            nonce=\"\",\n            fee_by_currency_id={\"ETH\": 10},\n            chain_id=3,\n        ),\n    )\n    message.to = dispatcher.dialogues.self_address\n    message.sender = \"test\"\n    dialogue = dispatcher.dialogues.update(message)\n    assert dialogue is not None\n    mock_api.get_transfer_transaction.return_value = None\n    msg = dispatcher.get_raw_transaction(mock_api, message, dialogue)\n\n    assert msg.performative == LedgerApiMessage.Performative.ERROR\n\n\n@pytest.mark.asyncio\nasync def test_attempts_get_transaction_receipt():\n    \"\"\"Test retry and sleep.\"\"\"\n    dispatcher = LedgerApiRequestDispatcher(AsyncState(ConnectionStates.connected))\n    mock_api = Mock()\n    message = LedgerApiMessage(\n        performative=LedgerApiMessage.Performative.GET_TRANSACTION_RECEIPT,\n        dialogue_reference=dispatcher.dialogues.new_self_initiated_dialogue_reference(),\n        transaction_digest=TransactionDigest(\"asdad\", \"sdfdsf\"),\n    )\n    message.to = dispatcher.dialogues.self_address\n    message.sender = \"test\"\n    dialogue = dispatcher.dialogues.update(message)\n    assert dialogue is not None\n    mock_api.get_transaction.return_value = None\n    mock_api.is_transaction_settled.return_value = True\n    with patch.object(dispatcher, \"MAX_ATTEMPTS\", 2):\n        with patch.object(dispatcher, \"TIMEOUT\", 0.001):\n            msg = dispatcher.get_transaction_receipt(mock_api, message, dialogue)\n\n    assert msg.performative == LedgerApiMessage.Performative.ERROR\n"
  },
  {
    "path": "tests/test_aea_core_packages/test_contracts/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"The tests module contains the tests of the packages/contracts dir.\"\"\"\n"
  },
  {
    "path": "tests/test_aea_core_packages/test_contracts/test_erc1155/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"The tests module contains the tests of the packages/contracts/erc1155 dir.\"\"\"\n"
  },
  {
    "path": "tests/test_aea_core_packages/test_contracts/test_erc1155/test_contract.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"The tests module contains the tests of the packages/contracts/erc1155 dir.\"\"\"\nimport re\nimport time\nfrom pathlib import Path\nfrom typing import cast\nfrom unittest import mock\n\nimport pytest\nfrom aea_ledger_ethereum import EthereumCrypto\nfrom aea_ledger_fetchai import FetchAIApi, FetchAICrypto\n\nfrom aea.common import JSONLike\nfrom aea.configurations.loader import (\n    ComponentType,\n    ContractConfig,\n    load_component_configuration,\n)\nfrom aea.contracts.base import Contract, contract_registry\nfrom aea.crypto.base import Crypto, LedgerApi\nfrom aea.test_tools.test_contract import BaseContractTestCase\n\nfrom tests.conftest import (\n    ETHEREUM_ADDRESS_ONE,\n    ETHEREUM_ADDRESS_TWO,\n    ETHEREUM_PRIVATE_KEY_PATH,\n    ETHEREUM_PRIVATE_KEY_TWO_PATH,\n    ETHEREUM_TESTNET_CONFIG,\n    FETCHAI_TESTNET_CONFIG,\n    MAX_FLAKY_RERUNS,\n    ROOT_DIR,\n    UseGanache,\n)\n\n\n@pytest.mark.ledger\nclass TestERC1155ContractEthereum(BaseContractTestCase, UseGanache):\n    \"\"\"Test the ERC1155 contract on Ethereum.\"\"\"\n\n    ledger_identifier = EthereumCrypto.identifier\n    path_to_contract = Path(ROOT_DIR, \"packages\", \"fetchai\", \"contracts\", \"erc1155\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup.\"\"\"\n        super().setup(\n            ledger_config=ETHEREUM_TESTNET_CONFIG,\n            deployer_private_key_path=ETHEREUM_PRIVATE_KEY_PATH,\n            item_owner_private_key_path=ETHEREUM_PRIVATE_KEY_TWO_PATH,\n        )\n\n        cls.token_ids_a = [\n            340282366920938463463374607431768211456,\n            340282366920938463463374607431768211457,\n            340282366920938463463374607431768211458,\n            340282366920938463463374607431768211459,\n            340282366920938463463374607431768211460,\n            340282366920938463463374607431768211461,\n            340282366920938463463374607431768211462,\n            340282366920938463463374607431768211463,\n            340282366920938463463374607431768211464,\n            340282366920938463463374607431768211465,\n        ]\n\n        cls.token_id_b = 680564733841876926926749214863536422912\n\n    @classmethod\n    def finish_contract_deployment(cls) -> str:\n        \"\"\"\n        Finish deploying contract.\n\n        :return: contract address\n        \"\"\"\n        contract_address = cls.ledger_api.get_contract_address(\n            cls.deployment_tx_receipt\n        )\n\n        if contract_address is None:\n            raise ValueError(\"Contract address not found!\")  # pragma: nocover\n\n        return contract_address\n\n    def test_generate_token_ids(self):\n        \"\"\"Test the generate_token_ids method of the ERC1155 contract.\"\"\"\n        # setup\n        nft_token_type = 1\n        nb_tokens = 2\n        expected_toke_ids = [\n            340282366920938463463374607431768211456,\n            340282366920938463463374607431768211457,\n        ]\n\n        # operation\n        actual_toke_ids = self.contract.generate_token_ids(nft_token_type, nb_tokens)\n\n        # after\n        assert actual_toke_ids == expected_toke_ids\n\n    def test_generate_id(self):\n        \"\"\"Test the _generate_id method of the ERC1155 contract.\"\"\"\n        # setup\n        ft_token_type = 2\n        index = 0\n        expected_toke_id = 680564733841876926926749214863536422912\n\n        # operation\n        actual_toke_id = self.contract._generate_id(index, ft_token_type)\n\n        # after\n        assert actual_toke_id == expected_toke_id\n\n    def test_get_create_batch_transaction(self):\n        \"\"\"Test the get_create_batch_transaction method of the ERC1155 contract.\"\"\"\n        # operation\n        tx = self.contract.get_create_batch_transaction(\n            ledger_api=self.ledger_api,\n            contract_address=self.contract_address,\n            deployer_address=self.deployer_crypto.address,\n            token_ids=self.token_ids_a,\n        )\n\n        # after\n        assert len(tx) == 7\n        assert all(\n            key in tx\n            for key in [\"value\", \"chainId\", \"gas\", \"gasPrice\", \"nonce\", \"to\", \"data\"]\n        )\n        self.sign_send_confirm_receipt_multisig_transaction(\n            tx, self.ledger_api, [self.deployer_crypto]\n        )\n\n    def test_get_create_single_transaction(self):\n        \"\"\"Test the get_create_single_transaction method of the ERC1155 contract.\"\"\"\n        # operation\n        tx = self.contract.get_create_single_transaction(\n            ledger_api=self.ledger_api,\n            contract_address=self.contract_address,\n            deployer_address=self.deployer_crypto.address,\n            token_id=self.token_id_b,\n        )\n\n        # after\n        assert len(tx) == 7\n        assert all(\n            key in tx\n            for key in [\"value\", \"chainId\", \"gas\", \"gasPrice\", \"nonce\", \"to\", \"data\"]\n        )\n        self.sign_send_confirm_receipt_multisig_transaction(\n            tx, self.ledger_api, [self.deployer_crypto]\n        )\n\n    def test_get_mint_batch_transaction(self):\n        \"\"\"Test the get_mint_batch_transaction method of the ERC1155 contract.\"\"\"\n        # operation\n        tx = self.contract.get_mint_batch_transaction(\n            ledger_api=self.ledger_api,\n            contract_address=self.contract_address,\n            deployer_address=self.deployer_crypto.address,\n            recipient_address=self.item_owner_crypto.address,\n            token_ids=self.token_ids_a,\n            mint_quantities=[1] * len(self.token_ids_a),\n        )\n\n        # after\n        assert len(tx) == 7\n        assert all(\n            key in tx\n            for key in [\"value\", \"chainId\", \"gas\", \"gasPrice\", \"nonce\", \"to\", \"data\"]\n        )\n        self.sign_send_confirm_receipt_multisig_transaction(\n            tx, self.ledger_api, [self.deployer_crypto]\n        )\n\n    def test_validate_mint_quantities(self):\n        \"\"\"Test the validate_mint_quantities method of the ERC1155 contract.\"\"\"\n        # Valid NFTs\n        self.contract.validate_mint_quantities(\n            token_ids=self.token_ids_a,\n            mint_quantities=[1] * len(self.token_ids_a),\n        )\n\n        # Valid FTs\n        token_id = 680564733841876926926749214863536422912\n        mint_quantity = 1\n        self.contract.validate_mint_quantities(\n            token_ids=[token_id],\n            mint_quantities=[mint_quantity],\n        )\n\n        # Invalid NFTs\n        token_id = self.token_ids_a[0]\n        mint_quantity = 2\n        with pytest.raises(\n            ValueError,\n            match=re.escape(\n                f\"Cannot mint NFT (token_id={token_id}) with mint_quantity more than 1 (found={mint_quantity})\"\n            ),\n        ):\n            self.contract.validate_mint_quantities(\n                token_ids=[token_id],\n                mint_quantities=[mint_quantity],\n            )\n\n        # Invalid: neither NFT nor FT\n        token_id = 1020847100762815390390123822295304634368\n        mint_quantity = 1\n        with pytest.raises(\n            ValueError,\n            match=re.escape(\n                f\"The token type must be 1 or 2. Found type=3 for token_id={token_id}\"\n            ),\n        ):\n            self.contract.validate_mint_quantities(\n                token_ids=[token_id],\n                mint_quantities=[mint_quantity],\n            )\n\n    def test_decode_id(self):\n        \"\"\"Test the decode_id method of the ERC1155 contract.\"\"\"\n        # FT\n        expected_token_type = 2\n        token_id = 680564733841876926926749214863536422912\n        actual_token_type = self.contract.decode_id(token_id)\n        assert actual_token_type == expected_token_type\n\n        # NFT\n        expected_token_type = 1\n        token_id = 340282366920938463463374607431768211456\n        actual_token_type = self.contract.decode_id(token_id)\n        assert actual_token_type == expected_token_type\n\n    def test_get_mint_single_transaction(self):\n        \"\"\"Test the get_mint_single_transaction method of the ERC1155 contract.\"\"\"\n        # operation\n        tx = self.contract.get_mint_single_transaction(\n            ledger_api=self.ledger_api,\n            contract_address=self.contract_address,\n            deployer_address=self.deployer_crypto.address,\n            recipient_address=self.item_owner_crypto.address,\n            token_id=self.token_id_b,\n            mint_quantity=1,\n        )\n\n        # after\n        assert len(tx) == 7\n        assert all(\n            key in tx\n            for key in [\"value\", \"chainId\", \"gas\", \"gasPrice\", \"nonce\", \"to\", \"data\"]\n        )\n        self.sign_send_confirm_receipt_multisig_transaction(\n            tx, self.ledger_api, [self.deployer_crypto]\n        )\n\n    def test_get_balance(self):\n        \"\"\"Test the get_balance method of the ERC1155 contract.\"\"\"\n        # operation\n        result = self.contract.get_balance(\n            ledger_api=self.ledger_api,\n            contract_address=self.contract_address,\n            agent_address=self.item_owner_crypto.address,\n            token_id=self.token_id_b,\n        )\n\n        # after\n        assert \"balance\" in result\n        assert result[\"balance\"][self.token_id_b] == 0\n\n    def test_get_balances(self):\n        \"\"\"Test the get_balances method of the ERC1155 contract.\"\"\"\n        # operation\n        result = self.contract.get_balances(\n            ledger_api=self.ledger_api,\n            contract_address=self.contract_address,\n            agent_address=self.item_owner_crypto.address,\n            token_ids=self.token_ids_a,\n        )\n\n        # after\n        assert \"balances\" in result\n        assert all(result[\"balances\"][token_id] == 0 for token_id in self.token_ids_a)\n\n    def test_get_hash_single(self):\n        \"\"\"Test the get_hash_single method of the ERC1155 contract.\"\"\"\n        # operation\n        result = self.contract.get_hash_single(\n            ledger_api=self.ledger_api,\n            contract_address=self.contract_address,\n            from_address=self.deployer_crypto.address,\n            to_address=self.item_owner_crypto.address,\n            token_id=self.token_id_b,\n            from_supply=0,\n            to_supply=10,\n            value=1,\n            trade_nonce=1,\n        )\n\n        # after\n        assert isinstance(result, bytes)\n\n    def test_get_hash_batch(self):\n        \"\"\"Test the get_hash_batch method of the ERC1155 contract.\"\"\"\n        # operation\n        result = self.contract.get_hash_batch(\n            ledger_api=self.ledger_api,\n            contract_address=self.contract_address,\n            from_address=self.deployer_crypto.address,\n            to_address=self.item_owner_crypto.address,\n            token_ids=self.token_ids_a,\n            from_supplies=[0, 1, 0, 0, 1, 0, 0, 0, 0, 1],\n            to_supplies=[0, 0, 0, 0, 0, 1, 0, 0, 0, 0],\n            value=1,\n            trade_nonce=1,\n        )\n\n        # after\n        assert isinstance(result, bytes)\n\n    def test_generate_trade_nonce(self):\n        \"\"\"Test the generate_trade_nonce method of the ERC1155 contract.\"\"\"\n        # operation\n        result = self.contract.generate_trade_nonce(\n            ledger_api=self.ledger_api,\n            contract_address=self.contract_address,\n            agent_address=self.item_owner_crypto.address,\n        )\n\n        # after\n        assert \"trade_nonce\" in result\n        assert isinstance(result[\"trade_nonce\"], int)\n\n    @pytest.mark.integration\n    def test_helper_methods_and_get_transactions(self):\n        \"\"\"Test helper methods and get transactions.\"\"\"\n        expected_a = [\n            340282366920938463463374607431768211456,\n            340282366920938463463374607431768211457,\n            340282366920938463463374607431768211458,\n            340282366920938463463374607431768211459,\n            340282366920938463463374607431768211460,\n            340282366920938463463374607431768211461,\n            340282366920938463463374607431768211462,\n            340282366920938463463374607431768211463,\n            340282366920938463463374607431768211464,\n            340282366920938463463374607431768211465,\n        ]\n        actual = self.contract.generate_token_ids(token_type=1, nb_tokens=10)\n        assert expected_a == actual\n        expected_b = [\n            680564733841876926926749214863536422912,\n            680564733841876926926749214863536422913,\n        ]\n        actual = self.contract.generate_token_ids(token_type=2, nb_tokens=2)\n        assert expected_b == actual\n        tx = self.contract.get_deploy_transaction(\n            ledger_api=self.ledger_api, deployer_address=ETHEREUM_ADDRESS_ONE\n        )\n        assert len(tx) == 6\n        data = tx.pop(\"data\")\n        assert len(data) > 0 and data.startswith(\"0x\")\n        assert all(\n            [key in tx for key in [\"value\", \"from\", \"gas\", \"gasPrice\", \"nonce\"]]\n        ), \"Error, found: {}\".format(tx)\n        tx = self.contract.get_create_batch_transaction(\n            ledger_api=self.ledger_api,\n            contract_address=ETHEREUM_ADDRESS_ONE,\n            deployer_address=ETHEREUM_ADDRESS_ONE,\n            token_ids=expected_a,\n        )\n        assert len(tx) == 7\n        data = tx.pop(\"data\")\n        assert len(data) > 0 and data.startswith(\"0x\")\n        assert all(\n            [\n                key in tx\n                for key in [\"value\", \"chainId\", \"gas\", \"gasPrice\", \"nonce\", \"to\"]\n            ]\n        ), \"Error, found: {}\".format(tx)\n        tx = self.contract.get_create_single_transaction(\n            ledger_api=self.ledger_api,\n            contract_address=ETHEREUM_ADDRESS_ONE,\n            deployer_address=ETHEREUM_ADDRESS_ONE,\n            token_id=expected_b[0],\n        )\n        assert len(tx) == 7\n        data = tx.pop(\"data\")\n        assert len(data) > 0 and data.startswith(\"0x\")\n        assert all(\n            [\n                key in tx\n                for key in [\"value\", \"chainId\", \"gas\", \"gasPrice\", \"nonce\", \"to\"]\n            ]\n        ), \"Error, found: {}\".format(tx)\n        mint_quantities = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]\n        tx = self.contract.get_mint_batch_transaction(\n            ledger_api=self.ledger_api,\n            contract_address=ETHEREUM_ADDRESS_ONE,\n            deployer_address=ETHEREUM_ADDRESS_ONE,\n            recipient_address=ETHEREUM_ADDRESS_ONE,\n            token_ids=expected_a,\n            mint_quantities=mint_quantities,\n        )\n        assert len(tx) == 7\n        data = tx.pop(\"data\")\n        assert len(data) > 0 and data.startswith(\"0x\")\n        assert all(\n            [\n                key in tx\n                for key in [\"value\", \"chainId\", \"gas\", \"gasPrice\", \"nonce\", \"to\"]\n            ]\n        ), \"Error, found: {}\".format(tx)\n        mint_quantity = 1\n        tx = self.contract.get_mint_single_transaction(\n            ledger_api=self.ledger_api,\n            contract_address=ETHEREUM_ADDRESS_ONE,\n            deployer_address=ETHEREUM_ADDRESS_ONE,\n            recipient_address=ETHEREUM_ADDRESS_ONE,\n            token_id=expected_b[1],\n            mint_quantity=mint_quantity,\n        )\n        assert len(tx) == 7\n        data = tx.pop(\"data\")\n        assert len(data) > 0 and data.startswith(\"0x\")\n        assert all(\n            [\n                key in tx\n                for key in [\"value\", \"chainId\", \"gas\", \"gasPrice\", \"nonce\", \"to\"]\n            ]\n        ), \"Error, found: {}\".format(tx)\n\n    @pytest.mark.integration\n    def test_get_single_atomic_swap(self):\n        \"\"\"Test get single atomic swap.\"\"\"\n        from_address = ETHEREUM_ADDRESS_ONE\n        to_address = ETHEREUM_ADDRESS_TWO\n        token_id = self.contract.generate_token_ids(token_type=2, nb_tokens=1)[0]\n        from_supply = 0\n        to_supply = 10\n        value = 1\n        trade_nonce = 1\n        tx_hash = self.contract.get_hash_single(\n            self.ledger_api,\n            self.contract_address,\n            from_address,\n            to_address,\n            token_id,\n            from_supply,\n            to_supply,\n            value,\n            trade_nonce,\n        )\n        assert isinstance(tx_hash, bytes)\n        signature = self.deployer_crypto.sign_message(tx_hash)\n        tx = self.contract.get_atomic_swap_single_transaction(\n            ledger_api=self.ledger_api,\n            contract_address=self.contract_address,\n            from_address=from_address,\n            to_address=to_address,\n            token_id=token_id,\n            from_supply=from_supply,\n            to_supply=to_supply,\n            value=value,\n            trade_nonce=trade_nonce,\n            signature=signature,\n        )\n        assert len(tx) == 8\n        data = tx.pop(\"data\")\n        assert len(data) > 0 and data.startswith(\"0x\")\n        assert all(\n            [\n                key in tx\n                for key in [\n                    \"value\",\n                    \"chainId\",\n                    \"gas\",\n                    \"gasPrice\",\n                    \"nonce\",\n                    \"to\",\n                    \"from\",\n                ]\n            ]\n        ), \"Error, found: {}\".format(tx)\n\n    @pytest.mark.integration\n    def test_get_batch_atomic_swap(self):\n        \"\"\"Test get batch atomic swap.\"\"\"\n        from_address = ETHEREUM_ADDRESS_ONE\n        to_address = ETHEREUM_ADDRESS_TWO\n        token_ids = self.contract.generate_token_ids(token_type=2, nb_tokens=10)\n        from_supplies = [0, 1, 0, 0, 1, 0, 0, 0, 0, 1]\n        to_supplies = [0, 0, 0, 0, 0, 1, 0, 0, 0, 0]\n        value = 1\n        trade_nonce = 1\n        tx_hash = self.contract.get_hash_batch(\n            self.ledger_api,\n            self.contract_address,\n            from_address,\n            to_address,\n            token_ids,\n            from_supplies,\n            to_supplies,\n            value,\n            trade_nonce,\n        )\n        assert isinstance(tx_hash, bytes)\n        signature = self.deployer_crypto.sign_message(tx_hash)\n        tx = self.contract.get_atomic_swap_batch_transaction(\n            ledger_api=self.ledger_api,\n            contract_address=self.contract_address,\n            from_address=from_address,\n            to_address=to_address,\n            token_ids=token_ids,\n            from_supplies=from_supplies,\n            to_supplies=to_supplies,\n            value=value,\n            trade_nonce=trade_nonce,\n            signature=signature,\n        )\n        assert len(tx) == 8\n        data = tx.pop(\"data\")\n        assert len(data) > 0 and data.startswith(\"0x\")\n        assert all(\n            [\n                key in tx\n                for key in [\n                    \"value\",\n                    \"chainId\",\n                    \"gas\",\n                    \"gasPrice\",\n                    \"nonce\",\n                    \"to\",\n                    \"from\",\n                ]\n            ]\n        ), \"Error, found: {}\".format(tx)\n\n    @pytest.mark.integration\n    def test_full(self):\n        \"\"\"Setup.\"\"\"\n        # Test tokens IDs\n        token_ids = self.contract.generate_token_ids(token_type=2, nb_tokens=10)\n\n        # create\n        tx = self.contract.get_create_batch_transaction(\n            ledger_api=self.ledger_api,\n            contract_address=self.contract_address,\n            deployer_address=self.deployer_crypto.address,\n            token_ids=token_ids,\n        )\n        tx_signed = self.deployer_crypto.sign_transaction(tx)\n        tx_receipt = self.ledger_api.send_signed_transaction(tx_signed)\n        time.sleep(1)\n        receipt = self.ledger_api.get_transaction_receipt(tx_receipt)\n        assert self.ledger_api.is_transaction_settled(receipt)\n\n        mint_quantities = [10] * len(token_ids)\n        # mint\n        tx = self.contract.get_mint_batch_transaction(\n            ledger_api=self.ledger_api,\n            contract_address=self.contract_address,\n            deployer_address=self.deployer_crypto.address,\n            recipient_address=self.deployer_crypto.address,\n            token_ids=token_ids,\n            mint_quantities=mint_quantities,\n        )\n        tx_signed = self.deployer_crypto.sign_transaction(tx)\n        tx_receipt = self.ledger_api.send_signed_transaction(tx_signed)\n        time.sleep(1)\n        receipt = self.ledger_api.get_transaction_receipt(tx_receipt)\n        assert self.ledger_api.is_transaction_settled(receipt)\n\n        tx = self.contract.get_mint_batch_transaction(\n            ledger_api=self.ledger_api,\n            contract_address=self.contract_address,\n            deployer_address=self.deployer_crypto.address,\n            recipient_address=self.item_owner_crypto.address,\n            token_ids=token_ids,\n            mint_quantities=mint_quantities,\n        )\n        tx_signed = self.deployer_crypto.sign_transaction(tx)\n        tx_receipt = self.ledger_api.send_signed_transaction(tx_signed)\n        time.sleep(1)\n        receipt = self.ledger_api.get_transaction_receipt(tx_receipt)\n        assert self.ledger_api.is_transaction_settled(receipt)\n\n        #  batch trade\n        from_address = self.deployer_crypto.address\n        to_address = self.item_owner_crypto.address\n        from_supplies = [0, 1, 0, 0, 1, 0, 0, 0, 0, 1]\n        to_supplies = [0, 0, 0, 0, 0, 1, 0, 0, 0, 0]\n        value = 0\n        trade_nonce = 1\n        tx_hash = self.contract.get_hash_batch(\n            self.ledger_api,\n            self.contract_address,\n            from_address,\n            to_address,\n            token_ids,\n            from_supplies,\n            to_supplies,\n            value,\n            trade_nonce,\n        )\n        signature = self.item_owner_crypto.sign_message(\n            tx_hash, is_deprecated_mode=True\n        )\n        tx = self.contract.get_atomic_swap_batch_transaction(\n            ledger_api=self.ledger_api,\n            contract_address=self.contract_address,\n            from_address=from_address,\n            to_address=to_address,\n            token_ids=token_ids,\n            from_supplies=from_supplies,\n            to_supplies=to_supplies,\n            value=value,\n            trade_nonce=trade_nonce,\n            signature=signature,\n        )\n        tx_signed = self.deployer_crypto.sign_transaction(tx)\n        tx_receipt = self.ledger_api.send_signed_transaction(tx_signed)\n        time.sleep(1)\n        receipt = self.ledger_api.get_transaction_receipt(tx_receipt)\n        assert self.ledger_api.is_transaction_settled(receipt)\n\n\nclass TestCosmWasmContract(BaseContractTestCase):\n    \"\"\"Test the cosmwasm contract.\"\"\"\n\n    ledger_identifier = FetchAICrypto.identifier\n    path_to_contract = Path(ROOT_DIR, \"packages\", \"fetchai\", \"contracts\", \"erc1155\")\n    fund_from_faucet = True\n    deploy_tx_fee = 10000000000000000\n\n    @classmethod\n    def _deploy_contract(\n        cls,\n        contract: Contract,\n        ledger_api: LedgerApi,\n        deployer_crypto: Crypto,\n        gas: int,\n    ) -> JSONLike:\n        \"\"\"\n        Deploy contract on network.\n\n        :param contract: the contract\n        :param ledger_api: the ledger api\n        :param deployer_crypto: the contract deployer crypto\n        :param gas: the gas amount\n\n        :return: the transaction receipt for initial transaction deployment\n        \"\"\"\n        tx = contract.get_deploy_transaction(\n            ledger_api=ledger_api,\n            deployer_address=deployer_crypto.address,\n            gas=gas,\n            tx_fee=cls.deploy_tx_fee,\n        )\n\n        if tx is None:\n            raise ValueError(\"Deploy transaction not found!\")  # pragma: nocover\n\n        tx_receipt = cls.sign_send_confirm_receipt_multisig_transaction(\n            tx, ledger_api, [deployer_crypto]\n        )\n\n        return tx_receipt\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup.\"\"\"\n        # Test tokens IDs\n        super().setup(ledger_config=FETCHAI_TESTNET_CONFIG, tx_fee=10000000000000000)\n        cls.token_ids_a = [\n            340282366920938463463374607431768211456,\n            340282366920938463463374607431768211457,\n            340282366920938463463374607431768211458,\n            340282366920938463463374607431768211459,\n            340282366920938463463374607431768211460,\n            340282366920938463463374607431768211461,\n            340282366920938463463374607431768211462,\n            340282366920938463463374607431768211463,\n            340282366920938463463374607431768211464,\n            340282366920938463463374607431768211465,\n        ]\n\n        cls.token_id_b = 680564733841876926926749214863536422912\n\n    @classmethod\n    def finish_contract_deployment(cls) -> str:\n        \"\"\"\n        Finish deploying contract.\n\n        :return: contract address\n        \"\"\"\n        code_id = cast(FetchAIApi, cls.ledger_api).get_code_id(\n            cls.deployment_tx_receipt\n        )\n\n        assert code_id is not None\n\n        # Init contract\n        tx = cls._contract.get_deploy_transaction(\n            ledger_api=cls.ledger_api,\n            deployer_address=cls.deployer_crypto.address,\n            code_id=code_id,\n            init_msg={},\n            amount=0,\n            label=\"ERC1155\",\n            gas=1000000,\n            tx_fee=5000000000000000,\n        )\n\n        if tx is None:\n            raise ValueError(\"Deploy transaction not found!\")  # pragma: nocover\n\n        tx_receipt = cls.sign_send_confirm_receipt_multisig_transaction(\n            tx, cls.ledger_api, [cls.deployer_crypto]\n        )\n\n        contract_address = cls.ledger_api.get_contract_address(tx_receipt)\n\n        if contract_address is None:\n            raise ValueError(\"Contract address not found!\")  # pragma: nocover\n\n        return contract_address\n\n    @pytest.mark.integration\n    @pytest.mark.ledger\n    @pytest.mark.flaky(reruns=MAX_FLAKY_RERUNS)\n    def test_create_and_mint_and_balances(self):\n        \"\"\"Test cosmwasm contract create, mint and balances functionalities.\"\"\"\n        # Create single token\n        tx = self.contract.get_create_single_transaction(\n            ledger_api=self.ledger_api,\n            contract_address=self.contract_address,\n            deployer_address=self.deployer_crypto.address,\n            token_id=self.token_id_b,\n            tx_fee=1500000000000000,\n        )\n        assert len(tx) == 2\n        self.sign_send_confirm_receipt_multisig_transaction(\n            tx, self.ledger_api, [self.deployer_crypto]\n        )\n\n        # Create batch of tokens\n        tx = self.contract.get_create_batch_transaction(\n            ledger_api=self.ledger_api,\n            contract_address=self.contract_address,\n            deployer_address=self.deployer_crypto.address,\n            token_ids=self.token_ids_a,\n            tx_fee=2500000000000000,\n        )\n        assert len(tx) == 2\n        self.sign_send_confirm_receipt_multisig_transaction(\n            tx, self.ledger_api, [self.deployer_crypto]\n        )\n\n        # Mint single token\n        tx = self.contract.get_mint_single_transaction(\n            ledger_api=self.ledger_api,\n            contract_address=self.contract_address,\n            deployer_address=self.deployer_crypto.address,\n            recipient_address=self.item_owner_crypto.address,\n            token_id=self.token_id_b,\n            mint_quantity=1,\n            tx_fee=2500000000000000,\n        )\n        assert len(tx) == 2\n        self.sign_send_confirm_receipt_multisig_transaction(\n            tx, self.ledger_api, [self.deployer_crypto]\n        )\n\n        # Get balance of single token\n        res = self.contract.get_balance(\n            ledger_api=self.ledger_api,\n            contract_address=self.contract_address,\n            agent_address=self.item_owner_crypto.address,\n            token_id=self.token_id_b,\n        )\n        assert \"balance\" in res\n        assert res[\"balance\"][self.token_id_b] == 1\n\n        # Mint batch of tokens\n        tx = self.contract.get_mint_batch_transaction(\n            ledger_api=self.ledger_api,\n            contract_address=self.contract_address,\n            deployer_address=self.deployer_crypto.address,\n            recipient_address=self.item_owner_crypto.address,\n            token_ids=self.token_ids_a,\n            mint_quantities=[1] * len(self.token_ids_a),\n            tx_fee=2500000000000000,\n        )\n        assert len(tx) == 2\n        self.sign_send_confirm_receipt_multisig_transaction(\n            tx, self.ledger_api, [self.deployer_crypto]\n        )\n\n        # Get balances of multiple tokens\n        res = self.contract.get_balances(\n            ledger_api=self.ledger_api,\n            contract_address=self.contract_address,\n            agent_address=self.item_owner_crypto.address,\n            token_ids=self.token_ids_a,\n        )\n        assert \"balances\" in res\n        assert res[\"balances\"] == {token_id: 1 for token_id in self.token_ids_a}\n\n    @pytest.mark.integration\n    @pytest.mark.ledger\n    @pytest.mark.flaky(reruns=MAX_FLAKY_RERUNS)\n    def test_cosmwasm_single_atomic_swap(self):\n        \"\"\"Test single atomic swap.\"\"\"\n        # Create batch of tokens\n        tx = self.contract.get_create_batch_transaction(\n            ledger_api=self.ledger_api,\n            contract_address=self.contract_address,\n            deployer_address=self.deployer_crypto.address,\n            token_ids=self.token_ids_a,\n            tx_fee=2500000000000000,\n        )\n        assert len(tx) == 2\n        self.sign_send_confirm_receipt_multisig_transaction(\n            tx, self.ledger_api, [self.deployer_crypto]\n        )\n\n        # Mint single ERC1155 token a[0] to Deployer\n        tx = self.contract.get_mint_single_transaction(\n            ledger_api=self.ledger_api,\n            contract_address=self.contract_address,\n            deployer_address=self.deployer_crypto.address,\n            recipient_address=self.deployer_crypto.address,\n            token_id=self.token_ids_a[0],\n            mint_quantity=1,\n            tx_fee=2500000000000000,\n        )\n        assert len(tx) == 2\n        self.sign_send_confirm_receipt_multisig_transaction(\n            tx, self.ledger_api, [self.deployer_crypto]\n        )\n\n        # Store balance of Deployer's native tokens before atomic swap\n        original_deployer_balance = self.ledger_api.get_balance(\n            self.deployer_crypto.address\n        )\n\n        # Atomic swap\n        # Send 1 ERC1155 token a[0] from Deployer to Item owner\n        # Send 1 native token from Item owner to Deployer\n        tx_fee = 7500000000000000\n        tx = self.contract.get_atomic_swap_single_transaction(\n            self.ledger_api,\n            contract_address=self.contract_address,\n            from_address=self.deployer_crypto.address,\n            to_address=self.item_owner_crypto.address,\n            token_id=self.token_ids_a[0],\n            from_supply=1,\n            to_supply=0,\n            value=1,\n            trade_nonce=0,\n            from_pubkey=self.deployer_crypto.public_key,\n            to_pubkey=self.item_owner_crypto.public_key,\n            tx_fee=tx_fee,\n        )\n        assert len(tx) == 2\n        self.sign_send_confirm_receipt_multisig_transaction(\n            tx, self.ledger_api, [self.deployer_crypto, self.item_owner_crypto]\n        )\n\n        # Check Item owner's ERC1155 token balance\n        result = self.contract.get_balance(\n            ledger_api=self.ledger_api,\n            contract_address=self.contract_address,\n            agent_address=self.item_owner_crypto.address,\n            token_id=self.token_ids_a[0],\n        )\n\n        assert \"balance\" in result\n        assert result[\"balance\"][self.token_ids_a[0]] == 1\n\n        # Check deployer's native token balance\n        deployer_balance = self.ledger_api.get_balance(self.deployer_crypto.address)\n        assert deployer_balance == original_deployer_balance + 1 - tx_fee\n\n        # Other direction of atomic swap\n        # Send 1 ERC1155 token a[0] from Item owner to Deployer\n        # Send 1 native token from Item owner to Deployer\n        tx = self.contract.get_atomic_swap_single_transaction(\n            self.ledger_api,\n            contract_address=self.contract_address,\n            from_address=self.deployer_crypto.address,\n            to_address=self.item_owner_crypto.address,\n            token_id=self.token_ids_a[0],\n            from_supply=0,\n            to_supply=1,\n            value=1,\n            trade_nonce=0,\n            from_pubkey=self.deployer_crypto.public_key,\n            to_pubkey=self.item_owner_crypto.public_key,\n            tx_fee=tx_fee,\n        )\n        assert len(tx) == 2\n        self.sign_send_confirm_receipt_multisig_transaction(\n            tx, self.ledger_api, [self.item_owner_crypto]\n        )\n\n        # Check Item owner's ERC1155 token balance\n        result = self.contract.get_balance(\n            ledger_api=self.ledger_api,\n            contract_address=self.contract_address,\n            agent_address=self.deployer_crypto.address,\n            token_id=self.token_ids_a[0],\n        )\n\n        assert \"balance\" in result\n        assert result[\"balance\"][self.token_ids_a[0]] == 1\n\n        # Check deployer's native token balance\n        deployer_balance = self.ledger_api.get_balance(self.deployer_crypto.address)\n        assert deployer_balance == original_deployer_balance + 2 - tx_fee\n\n        # Check invalid case with from_supply > 0 and to_supply > 0\n        with pytest.raises(RuntimeError):\n            self.contract.get_atomic_swap_single_transaction(\n                self.ledger_api,\n                contract_address=self.contract_address,\n                from_address=self.deployer_crypto.address,\n                to_address=self.item_owner_crypto.address,\n                token_id=self.token_ids_a[0],\n                from_supply=1,\n                to_supply=1,\n                value=1,\n                trade_nonce=0,\n                from_pubkey=self.deployer_crypto.public_key,\n                to_pubkey=self.item_owner_crypto.public_key,\n            )\n\n    @pytest.mark.integration\n    @pytest.mark.ledger\n    @pytest.mark.flaky(reruns=MAX_FLAKY_RERUNS)\n    def test_cosmwasm_batch_atomic_swap(self):\n        \"\"\"Test batch atomic swap.\"\"\"\n\n        # Create batch of tokens\n        tx = self.contract.get_create_batch_transaction(\n            ledger_api=self.ledger_api,\n            contract_address=self.contract_address,\n            deployer_address=self.deployer_crypto.address,\n            token_ids=self.token_ids_a,\n            tx_fee=2500000000000000,\n        )\n        assert len(tx) == 2\n        self.sign_send_confirm_receipt_multisig_transaction(\n            tx, self.ledger_api, [self.deployer_crypto]\n        )\n\n        # Mint single token a[0] to Deployer\n        tx = self.contract.get_mint_single_transaction(\n            ledger_api=self.ledger_api,\n            contract_address=self.contract_address,\n            deployer_address=self.deployer_crypto.address,\n            recipient_address=self.deployer_crypto.address,\n            token_id=self.token_ids_a[0],\n            mint_quantity=1,\n            tx_fee=2500000000000000,\n        )\n        assert len(tx) == 2\n        self.sign_send_confirm_receipt_multisig_transaction(\n            tx, self.ledger_api, [self.deployer_crypto]\n        )\n\n        # Mint single token a[1] to Item owner\n        tx = self.contract.get_mint_single_transaction(\n            ledger_api=self.ledger_api,\n            contract_address=self.contract_address,\n            deployer_address=self.deployer_crypto.address,\n            recipient_address=self.item_owner_crypto.address,\n            token_id=self.token_ids_a[1],\n            mint_quantity=1,\n            tx_fee=2500000000000000,\n        )\n        assert len(tx) == 2\n        self.sign_send_confirm_receipt_multisig_transaction(\n            tx, self.ledger_api, [self.deployer_crypto]\n        )\n\n        # Store balance of Deployer's native tokens before atomic swap\n        original_deployer_balance = self.ledger_api.get_balance(\n            self.deployer_crypto.address\n        )\n\n        # Atomic swap\n        # Send 1 ERC1155 token a[0] from Deployer to Item owner\n        # Send 1 ERC1155 token a[1] from Item owner to Deployer\n        # Send 1 native token from Item owner to Deployer\n        tx_fee = 7500000000000000\n        tx = self.contract.get_atomic_swap_batch_transaction(\n            self.ledger_api,\n            contract_address=self.contract_address,\n            from_address=self.deployer_crypto.address,\n            to_address=self.item_owner_crypto.address,\n            token_ids=[self.token_ids_a[0], self.token_ids_a[1]],\n            from_supplies=[1, 0],\n            to_supplies=[0, 1],\n            value=1,\n            trade_nonce=0,\n            from_pubkey=self.deployer_crypto.public_key,\n            to_pubkey=self.item_owner_crypto.public_key,\n            tx_fee=tx_fee,\n        )\n        assert len(tx) == 2\n        self.sign_send_confirm_receipt_multisig_transaction(\n            tx, self.ledger_api, [self.deployer_crypto, self.item_owner_crypto]\n        )\n\n        # Check Item owner's ERC1155 token balance\n        result = self.contract.get_balance(\n            ledger_api=self.ledger_api,\n            contract_address=self.contract_address,\n            agent_address=self.item_owner_crypto.address,\n            token_id=self.token_ids_a[0],\n        )\n\n        assert \"balance\" in result\n        assert result[\"balance\"][self.token_ids_a[0]] == 1\n\n        # Check Deployer's ERC1155 token balance\n        result = self.contract.get_balance(\n            ledger_api=self.ledger_api,\n            contract_address=self.contract_address,\n            agent_address=self.deployer_crypto.address,\n            token_id=self.token_ids_a[1],\n        )\n\n        assert \"balance\" in result\n        assert result[\"balance\"][self.token_ids_a[1]] == 1\n\n        # Check deployer's native token balance\n        deployer_balance = self.ledger_api.get_balance(self.deployer_crypto.address)\n        assert deployer_balance == original_deployer_balance + 1 - tx_fee\n\n\nclass TestContractCommon:\n    \"\"\"Other tests for the contract.\"\"\"\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup.\"\"\"\n\n        # Register smart contract used for testing\n        cls.path_to_contract = Path(\n            ROOT_DIR, \"packages\", \"fetchai\", \"contracts\", \"erc1155\"\n        )\n\n        # register contract\n        configuration = cast(\n            ContractConfig,\n            load_component_configuration(ComponentType.CONTRACT, cls.path_to_contract),\n        )\n        configuration._directory = (  # pylint: disable=protected-access\n            cls.path_to_contract\n        )\n        if str(configuration.public_id) not in contract_registry.specs:\n            # load contract into sys modules\n            Contract.from_config(configuration)\n        cls.contract = contract_registry.make(str(configuration.public_id))\n\n        cls.token_ids_a = [\n            340282366920938463463374607431768211456,\n        ]\n\n        # Create mock ledger with unknown identifier\n        cls.ledger_api = mock.Mock()\n        attrs = {\"identifier\": \"dummy\"}\n        cls.ledger_api.configure_mock(**attrs)\n\n    @pytest.mark.ledger\n    def test_get_create_batch_transaction_wrong_identifier(self):\n        \"\"\"Test if get_create_batch_transaction with wrong api identifier fails.\"\"\"\n\n        # Test if function is not implemented for unknown ledger\n        with pytest.raises(NotImplementedError):\n            self.contract.get_create_batch_transaction(\n                ledger_api=self.ledger_api,\n                contract_address=\"contract_address\",\n                deployer_address=\"address\",\n                token_ids=self.token_ids_a,\n            )\n\n    @pytest.mark.ledger\n    def test_get_create_single_transaction_wrong_identifier(self):\n        \"\"\"Test if get_create_single_transaction with wrong api identifier fails.\"\"\"\n\n        # Test if function is not implemented for unknown ledger\n        with pytest.raises(NotImplementedError):\n            self.contract.get_create_single_transaction(\n                ledger_api=self.ledger_api,\n                contract_address=\"contract_address\",\n                deployer_address=\"address\",\n                token_id=self.token_ids_a[0],\n            )\n\n    @pytest.mark.ledger\n    def test_get_mint_batch_transaction_wrong_identifier(self):\n        \"\"\"Test if get_mint_batch_transaction with wrong api identifier fails.\"\"\"\n\n        # Test if function is not implemented for unknown ledger\n        with pytest.raises(NotImplementedError):\n            self.contract.get_mint_batch_transaction(\n                ledger_api=self.ledger_api,\n                contract_address=\"contract_address\",\n                deployer_address=\"address\",\n                recipient_address=\"address\",\n                token_ids=self.token_ids_a,\n                mint_quantities=[1],\n            )\n\n    @pytest.mark.ledger\n    def test_get_mint_single_transaction_wrong_identifier(self):\n        \"\"\"Test if get_mint_single_transaction with wrong api identifier fails.\"\"\"\n\n        # Test if function is not implemented for unknown ledger\n        with pytest.raises(NotImplementedError):\n            self.contract.get_mint_single_transaction(\n                ledger_api=self.ledger_api,\n                contract_address=\"contract_address\",\n                deployer_address=\"address\",\n                recipient_address=\"address\",\n                token_id=self.token_ids_a[0],\n                mint_quantity=1,\n            )\n\n    @pytest.mark.ledger\n    def test_get_balance_wrong_identifier(self):\n        \"\"\"Test if get_balance with wrong api identifier fails.\"\"\"\n\n        # Test if function is not implemented for unknown ledger\n        with pytest.raises(NotImplementedError):\n            self.contract.get_balance(\n                ledger_api=self.ledger_api,\n                contract_address=\"contract_address\",\n                agent_address=\"address\",\n                token_id=self.token_ids_a[0],\n            )\n\n    @pytest.mark.ledger\n    def test_get_balance_wrong_query_res(self):\n        \"\"\"Test if get_balance with wrong api identifier fails.\"\"\"\n\n        # Create mock fetchai ledger that returns None on execute_contract_query\n        attrs = {\"identifier\": \"fetchai\", \"execute_contract_query.return_value\": None}\n        self.ledger_api.configure_mock(**attrs)\n\n        # Test if get balance returns ValueError when querying contract returns None\n        with pytest.raises(ValueError):\n            self.contract.get_balance(\n                ledger_api=self.ledger_api,\n                contract_address=\"contract_address\",\n                agent_address=\"address\",\n                token_id=self.token_ids_a[0],\n            )\n\n    @pytest.mark.ledger\n    def test_get_balances_wrong_query_res(self):\n        \"\"\"Test if get_balances with wrong api identifier fails.\"\"\"\n\n        # Create mock fetchai ledger that returns None on execute_contract_query\n        attrs = {\"identifier\": \"fetchai\", \"execute_contract_query.return_value\": None}\n        self.ledger_api.configure_mock(**attrs)\n\n        # Test if get balance returns ValueError when querying contract returns None\n        with pytest.raises(ValueError):\n            self.contract.get_balances(\n                ledger_api=self.ledger_api,\n                contract_address=\"contract_address\",\n                agent_address=\"address\",\n                token_ids=self.token_ids_a,\n            )\n\n    @pytest.mark.ledger\n    def test_get_hash_batch_not_same(self):\n        \"\"\"Test if get_hash_batch returns ValueError when on-chain hash is not same as computed hash.\"\"\"\n\n        self.ledger_api.identifier = \"ethereum\"\n\n        # Test if get hash returns ValueError when on chain hash is not same as computed hash\n        with mock.patch.object(type(self.contract), \"_get_hash_batch\", new=mock.Mock()):\n            with pytest.raises(ValueError):\n                self.contract.get_hash_batch(\n                    ledger_api=self.ledger_api,\n                    contract_address=\"contract_address\",\n                    from_address=\"address\",\n                    to_address=\"address\",\n                    token_ids=self.token_ids_a,\n                    from_supplies=[1],\n                    to_supplies=[0],\n                    value=123,\n                    trade_nonce=123,\n                )\n\n    @pytest.mark.ledger\n    def test_generate_trade_nonce_if_exist(self):\n        \"\"\"Test if generate_trade_nonce retries when nonce already exist.\"\"\"\n\n        # Etherem ledger api mock\n        self.ledger_api.identifier = \"ethereum\"\n\n        # instance.functions.is_nonce_used(agent_address, trade_nonce).call() -> True, False\n        is_nonce_used_mock = mock.Mock()\n        is_nonce_used_mock.configure_mock(**{\"call.side_effect\": [True, False]})\n\n        # instance.functions.is_nonce_used(agent_address, trade_nonce) -> is_nonce_used_mock with call method\n        instance_mock = mock.Mock()\n        instance_mock.configure_mock(\n            **{\"functions.is_nonce_used.return_value\": is_nonce_used_mock}\n        )\n\n        # cls.get_instance(ledger_api, contract_address) -> instance_mock\n        get_instance_mock = mock.Mock()\n        get_instance_mock.configure_mock(**{\"return_value\": instance_mock})\n\n        # Patch get_instance method to return get_instance_mock which returns instance of instance_mock when called\n        with mock.patch.object(\n            type(self.contract), \"get_instance\", new=get_instance_mock\n        ):\n            self.contract.generate_trade_nonce(\n                ledger_api=self.ledger_api,\n                contract_address=\"contract_address\",\n                agent_address=\"address\",\n            )\n\n        # Check if is_nonce_used was called twice\n        assert is_nonce_used_mock.call.call_count == 2\n\n    @pytest.mark.ledger\n    def test_get_atomic_swap_single_transaction_eth_no_signature(self):\n        \"\"\"Test if get_atomic_swap_single_transaction returns RuntimeError if signature not present on Ethereum case.\"\"\"\n\n        self.ledger_api.identifier = \"ethereum\"\n\n        # Test if get_atomic_swap_single_transaction returns RuntimeError when signature is missing\n        with pytest.raises(RuntimeError):\n            self.contract.get_atomic_swap_single_transaction(\n                self.ledger_api,\n                contract_address=\"address\",\n                from_address=\"address\",\n                to_address=\"address\",\n                token_id=self.token_ids_a[0],\n                from_supply=1,\n                to_supply=0,\n                value=1,\n                trade_nonce=0,\n            )\n\n    @pytest.mark.ledger\n    def test_get_atomic_swap_single_transaction_eth_pubkeys(self):\n        \"\"\"Test if get_atomic_swap_single_transaction returns RuntimeError if pubkeys are present on Ethereum case.\"\"\"\n\n        self.ledger_api.identifier = \"ethereum\"\n\n        # Test if get_atomic_swap_single_transaction returns RuntimeError when pubkey is present\n        with pytest.raises(RuntimeError):\n            self.contract.get_atomic_swap_single_transaction(\n                self.ledger_api,\n                contract_address=\"address\",\n                from_address=\"address\",\n                to_address=\"address\",\n                token_id=self.token_ids_a[0],\n                from_supply=1,\n                to_supply=0,\n                value=1,\n                trade_nonce=0,\n                signature=\"signature\",\n                from_pubkey=\"deadbeef\",\n                to_pubkey=\"deadbeef\",\n            )\n\n    @pytest.mark.ledger\n    def test_get_atomic_swap_single_transaction_cosmos_signature(self):\n        \"\"\"Test if get_atomic_swap_single_transaction returns RuntimeError if signature is present on Cosmos/Fetch case.\"\"\"\n\n        self.ledger_api.identifier = \"fetchai\"\n\n        # Test if get_atomic_swap_single_transaction returns RuntimeError when signature is present\n        with pytest.raises(RuntimeError):\n            self.contract.get_atomic_swap_single_transaction(\n                self.ledger_api,\n                contract_address=\"address\",\n                from_address=\"address\",\n                to_address=\"address\",\n                token_id=self.token_ids_a[0],\n                from_supply=1,\n                to_supply=0,\n                value=1,\n                trade_nonce=0,\n                signature=\"signature\",\n                from_pubkey=\"deadbeef\",\n                to_pubkey=\"deadbeef\",\n            )\n\n    @pytest.mark.ledger\n    def test_get_atomic_swap_single_transaction_cosmos_one_pubkey_valid(self):\n        \"\"\"Test if get_atomic_swap_single_transaction allows one pubkey in case of only one direction of transfers.\"\"\"\n\n        self.ledger_api.identifier = \"fetchai\"\n\n        # Test if get_atomic_swap_single_transaction works with only to_pubkey\n        tx = self.contract.get_atomic_swap_single_transaction(\n            self.ledger_api,\n            contract_address=\"address\",\n            from_address=\"address\",\n            to_address=\"address\",\n            token_id=self.token_ids_a[0],\n            from_supply=0,\n            to_supply=1,\n            value=1,\n            trade_nonce=0,\n            to_pubkey=\"deadbeef\",\n        )\n        assert tx is not None\n\n    @pytest.mark.ledger\n    def test_get_atomic_swap_single_transaction_cosmos_one_pubkey_invalid(self):\n        \"\"\"Test if get_atomic_swap_single_transaction returns RuntimeError with missing from_pubkey.\"\"\"\n\n        self.ledger_api.identifier = \"fetchai\"\n\n        # Test if get_atomic_swap_single_transaction fails with missing from_key\n        with pytest.raises(RuntimeError):\n            self.contract.get_atomic_swap_single_transaction(\n                self.ledger_api,\n                contract_address=\"address\",\n                from_address=\"address\",\n                to_address=\"address\",\n                token_id=self.token_ids_a[0],\n                from_supply=1,\n                to_supply=0,\n                value=1,\n                trade_nonce=0,\n                to_pubkey=\"deadbeef\",\n            )\n\n    @pytest.mark.ledger\n    def test_get_atomic_swap_single_transaction_cosmos_to_pubkey_missing(self):\n        \"\"\"Test if get_atomic_swap_single_transaction returns RuntimeError with missing to_pubkey.\"\"\"\n\n        self.ledger_api.identifier = \"fetchai\"\n\n        # Test if get_atomic_swap_single_transaction fails with missing from_key\n        with pytest.raises(RuntimeError):\n            self.contract.get_atomic_swap_single_transaction(\n                self.ledger_api,\n                contract_address=\"address\",\n                from_address=\"address\",\n                to_address=\"address\",\n                token_id=self.token_ids_a[0],\n                from_supply=1,\n                to_supply=0,\n                value=1,\n                trade_nonce=0,\n                from_pubkey=\"deadbeef\",\n            )\n\n    @pytest.mark.ledger\n    def test_get_atomic_swap_batch_transaction_eth_pubkeys(self):\n        \"\"\"Test if get_atomic_swap_batch_transaction returns RuntimeError if pubkeys are present on Ethereum case.\"\"\"\n\n        self.ledger_api.identifier = \"ethereum\"\n\n        # Test if get_atomic_swap_batch_transaction returns RuntimeError when pubkey is present\n        with pytest.raises(RuntimeError):\n            self.contract.get_atomic_swap_batch_transaction(\n                self.ledger_api,\n                contract_address=\"address\",\n                from_address=\"address\",\n                to_address=\"address\",\n                token_ids=[self.token_ids_a[0]],\n                from_supplies=[1],\n                to_supplies=[0],\n                value=1,\n                trade_nonce=0,\n                signature=\"signature\",\n                from_pubkey=\"deadbeef\",\n            )\n\n    @pytest.mark.ledger\n    def test_get_atomic_swap_batch_transaction_cosmos_signature(self):\n        \"\"\"Test if get_atomic_swap_batch_transaction returns RuntimeError if signature is present on Cosmos/Fetch case.\"\"\"\n\n        self.ledger_api.identifier = \"fetchai\"\n\n        # Test if get_atomic_swap_batch_transaction returns RuntimeError when signature is present\n        with pytest.raises(RuntimeError):\n            self.contract.get_atomic_swap_batch_transaction(\n                self.ledger_api,\n                contract_address=\"address\",\n                from_address=\"address\",\n                to_address=\"address\",\n                token_ids=[self.token_ids_a[0]],\n                from_supplies=[1],\n                to_supplies=[0],\n                value=1,\n                trade_nonce=0,\n                signature=\"signature\",\n                from_pubkey=\"deadbeef\",\n                to_pubkey=\"deadbeef\",\n            )\n\n    @pytest.mark.ledger\n    def test_get_atomic_swap_batch_transaction_cosmos_one_pubkey_valid(self):\n        \"\"\"Test if get_atomic_swap_batch_transaction allows one pubkey in case of only one direction of transfers.\"\"\"\n\n        self.ledger_api.identifier = \"fetchai\"\n\n        # Test if get_atomic_swap_batch_transaction works with only to_pubkey\n        tx = self.contract.get_atomic_swap_batch_transaction(\n            self.ledger_api,\n            contract_address=\"address\",\n            from_address=\"address\",\n            to_address=\"address\",\n            token_ids=[self.token_ids_a[0]],\n            from_supplies=[0],\n            to_supplies=[1],\n            value=1,\n            trade_nonce=0,\n            to_pubkey=\"deadbeef\",\n        )\n        assert tx is not None\n\n    @pytest.mark.ledger\n    def test_get_atomic_swap_batch_transaction_cosmos_one_pubkey_invalid(self):\n        \"\"\"Test if get_atomic_swap_batch_transaction returns RuntimeError with missing from_pubkey.\"\"\"\n\n        self.ledger_api.identifier = \"fetchai\"\n\n        # Test if get_atomic_swap_batch_transaction fails with missing from_key\n        with pytest.raises(RuntimeError):\n            self.contract.get_atomic_swap_batch_transaction(\n                self.ledger_api,\n                contract_address=\"address\",\n                from_address=\"address\",\n                to_address=\"address\",\n                token_ids=[self.token_ids_a[0]],\n                from_supplies=[1],\n                to_supplies=[0],\n                value=1,\n                trade_nonce=0,\n                to_pubkey=\"deadbeef\",\n            )\n\n    @pytest.mark.ledger\n    def test_get_atomic_swap_ba_transaction_eth_no_signature(self):\n        \"\"\"Test if get_atomic_swap_single_transaction returns RuntimeError if signature not present on Ethereum case.\"\"\"\n\n        self.ledger_api.identifier = \"ethereum\"\n\n        # Test if get_atomic_swap_single_transaction returns RuntimeError when signature is missing\n        with pytest.raises(RuntimeError):\n            self.contract.get_atomic_swap_batch_transaction(\n                self.ledger_api,\n                contract_address=\"address\",\n                from_address=\"address\",\n                to_address=\"address\",\n                token_ids=[self.token_ids_a[0]],\n                from_supplies=[1],\n                to_supplies=[0],\n                value=1,\n                trade_nonce=0,\n            )\n\n    @pytest.mark.ledger\n    def test_get_atomic_swap_batch_transaction_cosmos_to_pubkey_missing(self):\n        \"\"\"Test if get_atomic_swap_batch_transaction returns RuntimeError with missing to_pubkey.\"\"\"\n\n        self.ledger_api.identifier = \"fetchai\"\n\n        # Test if get_atomic_swap_single_transaction fails with all amounts to be zero\n        with pytest.raises(RuntimeError):\n            self.contract.get_atomic_swap_batch_transaction(\n                self.ledger_api,\n                contract_address=\"address\",\n                from_address=\"address\",\n                to_address=\"address\",\n                token_ids=[self.token_ids_a[0]],\n                from_supplies=[1],\n                to_supplies=[0],\n                value=1,\n                trade_nonce=0,\n                from_pubkey=\"deadbeef\",\n            )\n\n    @pytest.mark.ledger\n    def test_get_atomic_swap_batch_transaction_cosmos_to_pubkey_missing_no_from_pubkey_required(\n        self,\n    ):\n        \"\"\"Test if get_atomic_swap_batch_transaction returns RuntimeError with missing to_pubkey and from_pubkey not required.\"\"\"\n\n        self.ledger_api.identifier = \"fetchai\"\n\n        # Test if get_atomic_swap_single_transaction fails with missing to_pubkey\n        with pytest.raises(RuntimeError):\n            self.contract.get_atomic_swap_batch_transaction(\n                self.ledger_api,\n                contract_address=\"address\",\n                from_address=\"address\",\n                to_address=\"address\",\n                token_ids=[self.token_ids_a[0]],\n                from_supplies=[0],\n                to_supplies=[1],\n                value=1,\n                trade_nonce=0,\n            )\n\n    @pytest.mark.ledger\n    def test_get_atomic_swap_batch_transaction_cosmos_from_pubkey_missing_no_to_pubkey_required(\n        self,\n    ):\n        \"\"\"Test if get_atomic_swap_batch_transaction returns RuntimeError with missing from_pubkey and to_pubkey not required.\"\"\"\n\n        self.ledger_api.identifier = \"fetchai\"\n\n        # Test if get_atomic_swap_single_transaction fails with missing from_pubkey\n        with pytest.raises(RuntimeError):\n            self.contract.get_atomic_swap_batch_transaction(\n                self.ledger_api,\n                contract_address=\"address\",\n                from_address=\"address\",\n                to_address=\"address\",\n                token_ids=[self.token_ids_a[0]],\n                from_supplies=[1],\n                to_supplies=[0],\n                value=0,\n                trade_nonce=0,\n            )\n\n    @pytest.mark.ledger\n    def test_get_atomic_swap_batch_transaction_cosmos_from_pubkey_only(self):\n        \"\"\"Test if get_atomic_swap_batch_transaction returns Tx in case with only from_pubkey.\"\"\"\n\n        self.ledger_api.identifier = \"fetchai\"\n\n        # Test if get_atomic_swap_single_transaction works with only from_pubkey\n        res = self.contract.get_atomic_swap_batch_transaction(\n            self.ledger_api,\n            contract_address=\"address\",\n            from_address=\"address\",\n            to_address=\"address\",\n            token_ids=[self.token_ids_a[0]],\n            from_supplies=[1],\n            to_supplies=[0],\n            value=0,\n            trade_nonce=0,\n            from_pubkey=\"deadbeef\",\n        )\n        assert res is not None\n\n    @pytest.mark.ledger\n    def test_get_atomic_swap_single_transaction_amounts_missing(self):\n        \"\"\"Test if get_atomic_swap_single_transaction returns RuntimeError with missing amounts.\"\"\"\n\n        self.ledger_api.identifier = \"fetchai\"\n\n        # Test if get_atomic_swap_single_transaction fails with all amounts to be zero\n        with pytest.raises(RuntimeError):\n            self.contract.get_atomic_swap_single_transaction(\n                self.ledger_api,\n                contract_address=\"address\",\n                from_address=\"address\",\n                to_address=\"address\",\n                token_id=self.token_ids_a[0],\n                from_supply=0,\n                to_supply=0,\n                value=0,\n                trade_nonce=0,\n                from_pubkey=\"deadbeef\",\n            )\n\n    @pytest.mark.ledger\n    def test_get_atomic_swap_batch_transaction_amounts_missing(self):\n        \"\"\"Test if get_atomic_swap_batch_transaction returns RuntimeError with missing amounts.\"\"\"\n\n        self.ledger_api.identifier = \"fetchai\"\n\n        # Test if get_atomic_swap_single_transaction fails with all amounts to be zero\n        with pytest.raises(RuntimeError):\n            self.contract.get_atomic_swap_batch_transaction(\n                self.ledger_api,\n                contract_address=\"address\",\n                from_address=\"address\",\n                to_address=\"address\",\n                token_ids=[self.token_ids_a[0]],\n                from_supplies=[0],\n                to_supplies=[0],\n                value=0,\n                trade_nonce=0,\n                from_pubkey=\"deadbeef\",\n            )\n\n    @pytest.mark.ledger\n    def test_get_atomic_swap_single_transaction_cosmos_to_pubkey_missing_no_from_pubkey_required(\n        self,\n    ):\n        \"\"\"Test if get_atomic_swap_single_transaction returns RuntimeError with missing to_pubkey and from_pubkey not required.\"\"\"\n\n        self.ledger_api.identifier = \"fetchai\"\n\n        # Test if get_atomic_swap_single_transaction fails with missing to_pubkey\n        with pytest.raises(RuntimeError):\n            self.contract.get_atomic_swap_single_transaction(\n                self.ledger_api,\n                contract_address=\"address\",\n                from_address=\"address\",\n                to_address=\"address\",\n                token_id=self.token_ids_a[0],\n                from_supply=0,\n                to_supply=1,\n                value=1,\n                trade_nonce=0,\n            )\n\n    @pytest.mark.ledger\n    def test_get_atomic_swap_single_transaction_cosmos_from_pubkey_missing_no_to_pubkey_required(\n        self,\n    ):\n        \"\"\"Test if get_atomic_swap_single_transaction returns RuntimeError with missing from_pubkey and to_pubkey not required.\"\"\"\n\n        self.ledger_api.identifier = \"fetchai\"\n\n        # Test if get_atomic_swap_single_transaction fails with missing from_pubkey\n        with pytest.raises(RuntimeError):\n            self.contract.get_atomic_swap_single_transaction(\n                self.ledger_api,\n                contract_address=\"address\",\n                from_address=\"address\",\n                to_address=\"address\",\n                token_id=self.token_ids_a[0],\n                from_supply=1,\n                to_supply=0,\n                value=0,\n                trade_nonce=0,\n            )\n\n    @pytest.mark.ledger\n    def test_get_atomic_swap_single_transaction_cosmos_from_pubkey_only(self):\n        \"\"\"Test if get_atomic_swap_single_transaction returns Tx in case with only from_pubkey.\"\"\"\n\n        self.ledger_api.identifier = \"fetchai\"\n\n        # Test if get_atomic_swap_single_transaction works with only from_pubkey\n        res = self.contract.get_atomic_swap_single_transaction(\n            self.ledger_api,\n            contract_address=\"address\",\n            from_address=\"address\",\n            to_address=\"address\",\n            token_id=self.token_ids_a[0],\n            from_supply=1,\n            to_supply=0,\n            value=0,\n            trade_nonce=0,\n            from_pubkey=\"deadbeef\",\n        )\n        assert res is not None\n"
  },
  {
    "path": "tests/test_aea_core_packages/test_skills_integration/test_echo.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This test module contains the integration test for the echo skill.\"\"\"\nimport time\n\nfrom aea.common import Address\nfrom aea.mail.base import Envelope\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue\nfrom aea.test_tools.test_cases import AEATestCaseEmpty\n\nfrom packages.fetchai.protocols.default.dialogues import DefaultDialogue\nfrom packages.fetchai.protocols.default.dialogues import (\n    DefaultDialogues as BaseDefaultDialogues,\n)\nfrom packages.fetchai.protocols.default.message import DefaultMessage\n\n\nclass DefaultDialogues(BaseDefaultDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, self_address: Address) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :return: None\n        \"\"\"\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> Dialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return DefaultDialogue.Role.AGENT\n\n        BaseDefaultDialogues.__init__(\n            self,\n            self_address=self_address,\n            role_from_first_message=role_from_first_message,\n        )\n\n\nclass TestEchoSkill(AEATestCaseEmpty):\n    \"\"\"Test that echo skill works.\"\"\"\n\n    capture_log = True\n\n    def test_echo(self):\n        \"\"\"Run the echo skill sequence.\"\"\"\n        self.generate_private_key()\n        self.add_private_key()\n        self.add_item(\"connection\", \"fetchai/stub:0.21.3\")\n        self.add_item(\"skill\", \"fetchai/echo:0.20.6\")\n\n        process = self.run_agent()\n        is_running = self.is_running(process)\n        assert is_running, \"AEA not running within timeout!\"\n\n        # add sending and receiving envelope from input/output files\n        sender = \"sender\"\n        default_dialogues = DefaultDialogues(sender)\n        message_content = b\"hello\"\n        message = DefaultMessage(\n            performative=DefaultMessage.Performative.BYTES,\n            dialogue_reference=default_dialogues.new_self_initiated_dialogue_reference(),\n            content=message_content,\n        )\n        sent_envelope = Envelope(\n            to=self.agent_name,\n            sender=sender,\n            message=message,\n        )\n\n        self.send_envelope_to_agent(sent_envelope, self.agent_name)\n\n        time.sleep(2.0)\n        received_envelope = self.read_envelope_from_agent(self.agent_name)\n\n        assert sent_envelope.sender == received_envelope.to\n        assert (\n            sent_envelope.protocol_specification_id\n            == received_envelope.protocol_specification_id\n        )\n        msg = DefaultMessage.serializer.decode(received_envelope.message)\n        assert sent_envelope.message.content == msg.content\n\n        check_strings = (\n            \"Echo Handler: setup method called.\",\n            \"Echo Behaviour: setup method called.\",\n            \"Echo Behaviour: act method called.\",\n            \"content={}\".format(message_content),\n        )\n        missing_strings = self.missing_from_output(process, check_strings)\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in agent output.\".format(missing_strings)\n\n        assert (\n            self.is_successfully_terminated()\n        ), \"Echo agent wasn't successfully terminated.\"\n"
  },
  {
    "path": "tests/test_aea_core_packages/test_skills_integration/test_generic.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This test module contains the integration test for the generic buyer and seller skills.\"\"\"\n\nfrom random import uniform\n\nimport pytest\nfrom aea_ledger_fetchai import FetchAICrypto\n\nfrom aea.test_tools.test_cases import AEATestCaseManyFlaky\n\nfrom packages.fetchai.connections.p2p_libp2p.connection import LIBP2P_SUCCESS_MESSAGE\n\nfrom tests.conftest import (\n    FETCHAI_PRIVATE_KEY_FILE,\n    FETCHAI_PRIVATE_KEY_FILE_CONNECTION,\n    MAX_FLAKY_RERUNS_INTEGRATION,\n    NON_FUNDED_FETCHAI_PRIVATE_KEY_1,\n    NON_GENESIS_CONFIG,\n    wait_for_localhost_ports_to_close,\n)\n\n\n@pytest.mark.integration\nclass TestGenericSkills(AEATestCaseManyFlaky):\n    \"\"\"Test that generic skills work.\"\"\"\n\n    capture_log = True\n\n    @pytest.mark.flaky(\n        reruns=MAX_FLAKY_RERUNS_INTEGRATION\n    )  # cause possible network issues\n    def test_generic(self, pytestconfig):\n        \"\"\"Run the generic skills sequence.\"\"\"\n        seller_aea_name = \"my_generic_seller\"\n        buyer_aea_name = \"my_generic_buyer\"\n        self.create_agents(seller_aea_name, buyer_aea_name)\n\n        default_routing = {\n            \"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n            \"fetchai/oef_search:1.1.7\": \"fetchai/soef:0.27.6\",\n        }\n\n        # generate random location\n        location = {\n            \"latitude\": round(uniform(-90, 90), 2),  # nosec\n            \"longitude\": round(uniform(-180, 180), 2),  # nosec\n        }\n\n        # prepare seller agent\n        self.set_agent_context(seller_aea_name)\n        self.add_item(\"connection\", \"fetchai/p2p_libp2p:0.27.5\")\n        self.add_item(\"connection\", \"fetchai/soef:0.27.6\")\n        self.set_config(\"agent.default_connection\", \"fetchai/p2p_libp2p:0.27.5\")\n        self.add_item(\"connection\", \"fetchai/ledger:0.21.5\")\n        self.add_item(\"skill\", \"fetchai/generic_seller:0.28.6\")\n        setting_path = (\n            \"vendor.fetchai.skills.generic_seller.models.strategy.args.is_ledger_tx\"\n        )\n        self.set_config(setting_path, False, \"bool\")\n        setting_path = \"agent.default_routing\"\n        self.nested_set_config(setting_path, default_routing)\n        self.run_install()\n\n        # add keys\n        self.generate_private_key(FetchAICrypto.identifier)\n        self.generate_private_key(\n            FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE_CONNECTION\n        )\n        self.add_private_key(FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE)\n        self.add_private_key(\n            FetchAICrypto.identifier,\n            FETCHAI_PRIVATE_KEY_FILE_CONNECTION,\n            connection=True,\n        )\n        self.replace_private_key_in_file(\n            NON_FUNDED_FETCHAI_PRIVATE_KEY_1, FETCHAI_PRIVATE_KEY_FILE_CONNECTION\n        )\n\n        # make runable:\n        setting_path = \"vendor.fetchai.skills.generic_seller.is_abstract\"\n        self.set_config(setting_path, False, \"bool\")\n\n        # replace location\n        setting_path = (\n            \"vendor.fetchai.skills.generic_seller.models.strategy.args.location\"\n        )\n        self.nested_set_config(setting_path, location)\n        self.run_cli_command(\"build\", cwd=self._get_cwd())\n        self.run_cli_command(\"issue-certificates\", cwd=self._get_cwd())\n\n        # prepare buyer agent\n        self.set_agent_context(buyer_aea_name)\n        self.add_item(\"connection\", \"fetchai/p2p_libp2p:0.27.5\")\n        self.add_item(\"connection\", \"fetchai/soef:0.27.6\")\n        self.set_config(\"agent.default_connection\", \"fetchai/p2p_libp2p:0.27.5\")\n        self.add_item(\"connection\", \"fetchai/ledger:0.21.5\")\n        self.add_item(\"skill\", \"fetchai/generic_buyer:0.27.6\")\n        setting_path = (\n            \"vendor.fetchai.skills.generic_buyer.models.strategy.args.is_ledger_tx\"\n        )\n        self.set_config(setting_path, False, \"bool\")\n        setting_path = \"agent.default_routing\"\n        self.nested_set_config(setting_path, default_routing)\n\n        self.run_install()\n\n        # add keys\n        self.generate_private_key(FetchAICrypto.identifier)\n        self.generate_private_key(\n            FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE_CONNECTION\n        )\n        self.add_private_key(FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE)\n        self.add_private_key(\n            FetchAICrypto.identifier,\n            FETCHAI_PRIVATE_KEY_FILE_CONNECTION,\n            connection=True,\n        )\n\n        # set p2p configs\n        setting_path = \"vendor.fetchai.connections.p2p_libp2p.config\"\n        self.nested_set_config(setting_path, NON_GENESIS_CONFIG)\n\n        # make runable:\n        setting_path = \"vendor.fetchai.skills.generic_buyer.is_abstract\"\n        self.set_config(setting_path, False, \"bool\")\n\n        # replace location\n        setting_path = (\n            \"vendor.fetchai.skills.generic_buyer.models.strategy.args.location\"\n        )\n        self.nested_set_config(setting_path, location)\n        self.run_cli_command(\"build\", cwd=self._get_cwd())\n        self.run_cli_command(\"issue-certificates\", cwd=self._get_cwd())\n\n        # run AEAs\n        self.set_agent_context(seller_aea_name)\n        seller_aea_process = self.run_agent()\n\n        check_strings = (\n            \"Starting libp2p node...\",\n            \"Connecting to libp2p node...\",\n            \"Successfully connected to libp2p node!\",\n            LIBP2P_SUCCESS_MESSAGE,\n        )\n        missing_strings = self.missing_from_output(\n            seller_aea_process, check_strings, timeout=30, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in seller_aea output.\".format(missing_strings)\n\n        self.set_agent_context(buyer_aea_name)\n        buyer_aea_process = self.run_agent()\n\n        check_strings = (\n            \"Starting libp2p node...\",\n            \"Connecting to libp2p node...\",\n            \"Successfully connected to libp2p node!\",\n            LIBP2P_SUCCESS_MESSAGE,\n        )\n        missing_strings = self.missing_from_output(\n            buyer_aea_process, check_strings, timeout=30, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in buyer_aea output.\".format(missing_strings)\n\n        check_strings = (\n            \"registering agent on SOEF.\",\n            \"registering agent's service on the SOEF.\",\n            \"registering agent's personality genus on the SOEF.\",\n            \"registering agent's personality classification on the SOEF.\",\n            \"received CFP from sender=\",\n            \"sending a PROPOSE with proposal=\",\n            \"received ACCEPT from sender=\",\n            \"sending MATCH_ACCEPT_W_INFORM to sender=\",\n            \"received INFORM from sender=\",\n            \"transaction confirmed, sending data=\",\n        )\n        missing_strings = self.missing_from_output(\n            seller_aea_process, check_strings, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in seller_aea output.\".format(missing_strings)\n\n        check_strings = (\n            \"found agents=\",\n            \"sending CFP to agent=\",\n            \"received proposal=\",\n            \"accepting the proposal from sender=\",\n            \"received MATCH_ACCEPT_W_INFORM from sender=\",\n            \"informing counterparty=\",\n            \"received INFORM from sender=\",\n            \"received the following data=\",\n        )\n        missing_strings = self.missing_from_output(\n            buyer_aea_process, check_strings, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in buyer_aea output.\".format(missing_strings)\n\n        self.terminate_agents(seller_aea_process, buyer_aea_process)\n        assert (\n            self.is_successfully_terminated()\n        ), \"Agents weren't successfully terminated.\"\n        wait_for_localhost_ports_to_close([9000, 9001])\n\n\n@pytest.mark.sync\n@pytest.mark.integration\nclass TestGenericSkillsFetchaiLedger(AEATestCaseManyFlaky):\n    \"\"\"Test that generic skills work.\"\"\"\n\n    capture_log = True\n\n    @pytest.mark.flaky(\n        reruns=MAX_FLAKY_RERUNS_INTEGRATION\n    )  # cause possible network issues\n    def test_generic(self, pytestconfig):\n        \"\"\"Run the generic skills sequence.\"\"\"\n        seller_aea_name = \"my_generic_seller\"\n        buyer_aea_name = \"my_generic_buyer\"\n        self.create_agents(seller_aea_name, buyer_aea_name)\n\n        default_routing = {\n            \"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n            \"fetchai/oef_search:1.1.7\": \"fetchai/soef:0.27.6\",\n        }\n\n        # generate random location\n        location = {\n            \"latitude\": round(uniform(-90, 90), 2),  # nosec\n            \"longitude\": round(uniform(-180, 180), 2),  # nosec\n        }\n\n        # prepare seller agent\n        self.set_agent_context(seller_aea_name)\n        self.add_item(\"connection\", \"fetchai/p2p_libp2p:0.27.5\")\n        self.add_item(\"connection\", \"fetchai/soef:0.27.6\")\n        self.set_config(\"agent.default_connection\", \"fetchai/p2p_libp2p:0.27.5\")\n        self.add_item(\"connection\", \"fetchai/ledger:0.21.5\")\n        self.add_item(\"skill\", \"fetchai/generic_seller:0.28.6\")\n        setting_path = \"agent.default_routing\"\n        self.nested_set_config(setting_path, default_routing)\n        self.run_install()\n\n        diff = self.difference_to_fetched_agent(\n            \"fetchai/generic_seller:0.29.5\", seller_aea_name\n        )\n        assert (\n            diff == []\n        ), \"Difference between created and fetched project for files={}\".format(diff)\n\n        # add keys\n        self.generate_private_key(FetchAICrypto.identifier)\n        self.generate_private_key(\n            FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE_CONNECTION\n        )\n        self.add_private_key(FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE)\n        self.add_private_key(\n            FetchAICrypto.identifier,\n            FETCHAI_PRIVATE_KEY_FILE_CONNECTION,\n            connection=True,\n        )\n        self.replace_private_key_in_file(\n            NON_FUNDED_FETCHAI_PRIVATE_KEY_1, FETCHAI_PRIVATE_KEY_FILE_CONNECTION\n        )\n\n        # make runable:\n        setting_path = \"vendor.fetchai.skills.generic_seller.is_abstract\"\n        self.set_config(setting_path, False, \"bool\")\n\n        # replace location\n        setting_path = (\n            \"vendor.fetchai.skills.generic_seller.models.strategy.args.location\"\n        )\n        self.nested_set_config(setting_path, location)\n        self.run_cli_command(\"build\", cwd=self._get_cwd())\n        self.run_cli_command(\"issue-certificates\", cwd=self._get_cwd())\n\n        # prepare buyer agent\n        self.set_agent_context(buyer_aea_name)\n        self.add_item(\"connection\", \"fetchai/p2p_libp2p:0.27.5\")\n        self.add_item(\"connection\", \"fetchai/soef:0.27.6\")\n        self.set_config(\"agent.default_connection\", \"fetchai/p2p_libp2p:0.27.5\")\n        self.add_item(\"connection\", \"fetchai/ledger:0.21.5\")\n        self.add_item(\"skill\", \"fetchai/generic_buyer:0.27.6\")\n        setting_path = \"agent.default_routing\"\n        self.nested_set_config(setting_path, default_routing)\n\n        self.run_install()\n\n        diff = self.difference_to_fetched_agent(\n            \"fetchai/generic_buyer:0.30.5\", buyer_aea_name\n        )\n        assert (\n            diff == []\n        ), \"Difference between created and fetched project for files={}\".format(diff)\n\n        setting_path = \"vendor.fetchai.skills.generic_buyer.is_abstract\"\n        self.set_config(setting_path, False, \"bool\")\n        self.set_config(\n            \"vendor.fetchai.skills.generic_buyer.models.strategy.args.max_tx_fee\",\n            7750000000000000,\n        )\n\n        # add keys\n        self.generate_private_key(FetchAICrypto.identifier)\n        self.generate_private_key(\n            FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE_CONNECTION\n        )\n        self.add_private_key(FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE)\n        self.add_private_key(\n            FetchAICrypto.identifier,\n            FETCHAI_PRIVATE_KEY_FILE_CONNECTION,\n            connection=True,\n        )\n\n        # fund key\n        self.generate_wealth(FetchAICrypto.identifier)\n\n        # set p2p configs\n        setting_path = \"vendor.fetchai.connections.p2p_libp2p.config\"\n        self.nested_set_config(setting_path, NON_GENESIS_CONFIG)\n\n        # replace location\n        setting_path = (\n            \"vendor.fetchai.skills.generic_buyer.models.strategy.args.location\"\n        )\n        self.nested_set_config(setting_path, location)\n        self.run_cli_command(\"build\", cwd=self._get_cwd())\n        self.run_cli_command(\"issue-certificates\", cwd=self._get_cwd())\n\n        # run AEAs\n        self.set_agent_context(seller_aea_name)\n        seller_aea_process = self.run_agent()\n\n        check_strings = (\n            \"Starting libp2p node...\",\n            \"Connecting to libp2p node...\",\n            \"Successfully connected to libp2p node!\",\n            LIBP2P_SUCCESS_MESSAGE,\n        )\n        missing_strings = self.missing_from_output(\n            seller_aea_process, check_strings, timeout=30, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in seller_aea output.\".format(missing_strings)\n\n        self.set_agent_context(buyer_aea_name)\n        buyer_aea_process = self.run_agent()\n\n        check_strings = (\n            \"Starting libp2p node...\",\n            \"Connecting to libp2p node...\",\n            \"Successfully connected to libp2p node!\",\n            LIBP2P_SUCCESS_MESSAGE,\n        )\n        missing_strings = self.missing_from_output(\n            buyer_aea_process, check_strings, timeout=30, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in buyer_aea output.\".format(missing_strings)\n\n        check_strings = (\n            \"registering agent on SOEF.\",\n            \"registering agent's service on the SOEF.\",\n            \"registering agent's personality genus on the SOEF.\",\n            \"registering agent's personality classification on the SOEF.\",\n            \"received CFP from sender=\",\n            \"sending a PROPOSE with proposal=\",\n            \"received ACCEPT from sender=\",\n            \"sending MATCH_ACCEPT_W_INFORM to sender=\",\n            \"received INFORM from sender=\",\n            \"checking whether transaction=\",\n            \"transaction confirmed, sending data=\",\n        )\n        missing_strings = self.missing_from_output(\n            seller_aea_process, check_strings, timeout=120, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in seller_aea output.\".format(missing_strings)\n\n        check_strings = (\n            \"found agents=\",\n            \"sending CFP to agent=\",\n            \"received proposal=\",\n            \"accepting the proposal from sender=\",\n            \"received MATCH_ACCEPT_W_INFORM from sender=\",\n            \"requesting transfer transaction from ledger api for message=\",\n            \"received raw transaction=\",\n            \"proposing the transaction to the decision maker. Waiting for confirmation ...\",\n            \"transaction signing was successful.\",\n            \"sending transaction to ledger.\",\n            \"transaction was successfully submitted. Transaction digest=\",\n            \"transaction confirmed, informing counterparty=\",\n            \"received INFORM from sender=\",\n            \"received the following data=\",\n        )\n        missing_strings = self.missing_from_output(\n            buyer_aea_process, check_strings, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in buyer_aea output.\".format(missing_strings)\n\n        self.terminate_agents(seller_aea_process, buyer_aea_process)\n        assert (\n            self.is_successfully_terminated()\n        ), \"Agents weren't successfully terminated.\"\n        wait_for_localhost_ports_to_close([9000, 9001])\n"
  },
  {
    "path": "tests/test_aea_core_packages/test_skills_integration/test_hello_world.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This test module contains the integration test for the hello_world skill.\"\"\"\nfrom aea.test_tools.test_cases import AEATestCaseEmpty\n\n\nclass TestHelloWorldSkill(AEATestCaseEmpty):\n    \"\"\"Test that hello_world skill works.\"\"\"\n\n    capture_log = True\n\n    def test_hello_world(self):\n        \"\"\"Run the hello_world skill sequence.\"\"\"\n        self.generate_private_key()\n        self.add_private_key()\n        self.add_item(\"skill\", \"fetchai/hello_world:0.1.5\")\n\n        process = self.run_agent()\n        is_running = self.is_running(process)\n        assert is_running, \"AEA not running within timeout!\"\n\n        check_strings = (\"Hello World!\",)\n        missing_strings = self.missing_from_output(process, check_strings)\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in agent output.\".format(missing_strings)\n"
  },
  {
    "path": "tests/test_aea_core_packages/test_skills_integration/test_http_echo.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This test module contains the integration test for the echo skill.\"\"\"\n\nfrom pathlib import Path\n\nfrom aea.helpers import http_requests as requests\nfrom aea.test_tools.test_cases import AEATestCaseEmpty\n\nfrom tests.conftest import ROOT_DIR\n\n\nAPI_SPEC_PATH = str(Path(ROOT_DIR, \"examples\", \"http_ex\", \"petstore.yaml\").absolute())\n\n\nclass TestHttpEchoSkill(AEATestCaseEmpty):\n    \"\"\"Test that http echo skill works.\"\"\"\n\n    capture_log = True\n\n    def test_echo(self):\n        \"\"\"Run the echo skill sequence.\"\"\"\n        self.generate_private_key()\n        self.add_private_key()\n        self.add_item(\"connection\", \"fetchai/http_server:0.23.6\")\n        self.add_item(\"skill\", \"fetchai/http_echo:0.21.6\")\n        self.set_config(\"agent.default_connection\", \"fetchai/http_server:0.23.6\")\n        self.set_config(\n            \"vendor.fetchai.connections.http_server.config.target_skill_id\",\n            \"fetchai/http_echo:0.21.6\",\n        )\n        self.set_config(\n            \"vendor.fetchai.connections.http_server.config.api_spec_path\", API_SPEC_PATH\n        )\n        self.run_install()\n\n        process = self.run_agent()\n        is_running = self.is_running(process)\n        assert is_running, \"AEA not running within timeout!\"\n\n        # add sending and receiving envelope from input/output files\n\n        response = requests.get(\"http://127.0.0.1:8000\")\n        assert response.status_code == 404, \"Failed to receive not found\"\n        # we receive a not found since the path is not available in the api spec\n\n        response = requests.get(\"http://127.0.0.1:8000/pets\")\n        assert response.status_code == 200, \"Failed to receive ok\"\n        assert (\n            response.content == b'{\"tom\": {\"type\": \"cat\", \"age\": 10}}'\n        ), \"Wrong body on get\"\n\n        response = requests.post(\"http://127.0.0.1:8000/pets\")\n        assert response.status_code == 200\n        assert response.content == b\"\", \"Wrong body on post\"\n\n        check_strings = (\n            \"received http request with method=get, url=http://127.0.0.1:8000/pets and body=b''\",\n            \"received http request with method=post, url=http://127.0.0.1:8000/pets and body=b''\",\n        )\n        missing_strings = self.missing_from_output(process, check_strings)\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in agent output.\".format(missing_strings)\n\n        assert (\n            self.is_successfully_terminated()\n        ), \"Http echo agent wasn't successfully terminated.\"\n"
  },
  {
    "path": "tests/test_aea_extra/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"The tests module contains the extra tests for the AEA core.\"\"\"\n"
  },
  {
    "path": "tests/test_aea_extra/test_manager/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains a test for aea.manager.\"\"\"\n"
  },
  {
    "path": "tests/test_aea_extra/test_manager/test_manager.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains tests for aea manager.\"\"\"\nimport contextlib\nimport logging\nimport os\nimport pickle  # nosec\nimport re\nimport time\nfrom contextlib import suppress\nfrom copy import copy\nfrom pathlib import Path\nfrom shutil import rmtree\nfrom tempfile import TemporaryDirectory\nfrom textwrap import dedent\nfrom typing import Optional\nfrom unittest.case import TestCase\nfrom unittest.mock import Mock, patch\n\nimport pytest\n\nfrom aea.configurations.base import PublicId\nfrom aea.crypto.helpers import create_private_key\nfrom aea.crypto.plugin import load_all_plugins\nfrom aea.crypto.registries import crypto_registry\nfrom aea.helpers.install_dependency import call_pip\nfrom aea.manager import MultiAgentManager\nfrom aea.manager.manager import AgentRunProcessTask, ProjectPackageConsistencyCheckError\n\nfrom packages.fetchai.connections.stub.connection import StubConnection\nfrom packages.fetchai.skills.echo import PUBLIC_ID as ECHO_SKILL_PUBLIC_ID\n\nfrom tests.common.utils import wait_for_condition\nfrom tests.conftest import MY_FIRST_AEA_PUBLIC_ID, PACKAGES_DIR, ROOT_DIR\n\n\nDEFAULT_TIMEOUT = 60\n\n\n@patch(\"aea.aea_builder.AEABuilder.install_pypi_dependencies\")\nclass BaseCase(TestCase):\n    \"\"\"Base case setup/teardown.\"\"\"\n\n    MODE = \"async\"\n    PASSWORD: Optional[str] = None\n\n    echo_skill_id = ECHO_SKILL_PUBLIC_ID\n\n    def setUp(self):\n        \"\"\"Set test case.\"\"\"\n        self.agent_name = \"test_what_ever12\"\n        self.project_public_id = MY_FIRST_AEA_PUBLIC_ID\n        self.tmp_dir = TemporaryDirectory()\n        self.working_dir = os.path.join(self.tmp_dir.name, \"MultiAgentManager_dir\")\n        self.project_path = os.path.join(\n            self.working_dir, self.project_public_id.author, self.project_public_id.name\n        )\n        assert not os.path.exists(self.working_dir)\n        self.manager = MultiAgentManager(\n            self.working_dir, mode=self.MODE, password=self.PASSWORD\n        )\n        self._log_handlers = copy(logging.root.getChild(\"aea\").handlers)\n\n    def tearDown(self):\n        \"\"\"Tear down test case.\"\"\"\n        try:\n            self.manager.stop_manager()\n\n            for task in self.manager._agents_tasks.values():\n                if isinstance(task, AgentRunProcessTask):\n                    task.process.terminate()\n                    task.process.join(5)\n\n            time.sleep(1)\n            logging.shutdown(\n                [\n                    handler\n                    for handler in logging._handlerList\n                    if getattr(handler, \"baseFilename\", None)\n                ]\n            )\n            logging.root.getChild(\"aea\").handlers = [\n                handler\n                for handler in self._log_handlers\n                if not getattr(handler, \"baseFilename\", None)\n            ]\n            time.sleep(1)\n            if os.path.exists(self.working_dir):\n                rmtree(self.working_dir)\n        finally:\n            self.tmp_dir.cleanup()\n\n\n@patch(\"aea.aea_builder.AEABuilder.install_pypi_dependencies\")\nclass TestMultiAgentManagerDependencies(BaseCase):\n    \"\"\"Test plugin installed and loaded as a depencndecy.\"\"\"\n\n    def test_plugin_dependencies(self, *args):\n        \"\"\"Test plugin installed and loaded as a depencndecy.\"\"\"\n        plugin_path = str(Path(ROOT_DIR) / \"plugins\" / \"aea-ledger-fetchai\")\n        install_cmd = f\"install --no-deps {plugin_path}\".split(\" \")\n        try:\n            self.manager.start_manager()\n            call_pip(\"uninstall aea-ledger-fetchai -y\".split(\" \"))\n            from aea.crypto.registries import ledger_apis_registry\n\n            ledger_apis_registry.specs.pop(\"fetchai\", None)\n            load_all_plugins(is_raising_exception=False)\n            assert \"fetchai\" not in ledger_apis_registry.specs\n\n            self.manager.add_project(self.project_public_id, local=True)\n            assert \"fetchai\" not in ledger_apis_registry.specs\n\n            self.manager.remove_project(self.project_public_id)\n\n            def install_deps(*_):\n                call_pip(install_cmd)\n\n            with patch(\n                \"aea.aea_builder.AEABuilder.install_pypi_dependencies\", install_deps\n            ):\n                self.manager.add_project(self.project_public_id, local=True)\n\n            assert \"fetchai\" in ledger_apis_registry.specs\n        finally:\n            call_pip(\"uninstall aea-ledger-fetchai -y\".split(\" \"))\n            call_pip(install_cmd)\n\n\n@patch(\"aea.aea_builder.AEABuilder.install_pypi_dependencies\")\nclass BaseTestMultiAgentManager(BaseCase):\n    \"\"\"Base test class for multi-agent manager\"\"\"\n\n    def test_workdir_created_removed(self, *args):\n        \"\"\"Check work dit created removed on MultiAgentManager start and stop.\"\"\"\n        assert not os.path.exists(self.working_dir)\n        self.manager.start_manager()\n        assert os.path.exists(self.working_dir)\n        self.manager.stop_manager()\n        assert not os.path.exists(self.working_dir)\n        assert not os.path.exists(self.working_dir)\n\n    def test_projects_property(self, *args):\n        \"\"\"Test projects property.\"\"\"\n        self.assertEqual(self.manager.projects, self.manager._projects)\n\n    def test_data_dir_presents(self, *args):\n        \"\"\"Check not fails on exists data dir.\"\"\"\n        try:\n            os.makedirs(self.working_dir)\n            os.makedirs(self.manager._data_dir)\n            self.manager.start_manager()\n            self.manager.stop_manager()\n        finally:\n            with suppress(Exception):\n                rmtree(self.working_dir)\n\n    def test_MultiAgentManager_is_running(self, *args):\n        \"\"\"Check MultiAgentManager is running property reflects state.\"\"\"\n        assert not self.manager.is_running\n        self.manager.start_manager()\n        assert self.manager.is_running\n        self.manager.stop_manager()\n        assert not self.manager.is_running\n\n    def test_add_remove_project(self, *args):\n        \"\"\"Test add and remove project.\"\"\"\n        self.manager.start_manager()\n\n        self.manager.add_project(self.project_public_id, local=True)\n\n        assert self.project_public_id in self.manager.list_projects()\n        assert os.path.exists(self.project_path)\n\n        with pytest.raises(ValueError, match=r\".*was already added.*\"):\n            self.manager.add_project(self.project_public_id, local=True)\n\n        self.manager.remove_project(self.project_public_id)\n        assert self.project_public_id not in self.manager.list_projects()\n\n        with pytest.raises(ValueError, match=r\"is not present\"):\n            self.manager.remove_project(self.project_public_id)\n\n        self.manager.add_project(self.project_public_id, local=True)\n        assert self.project_public_id in self.manager.list_projects()\n        assert os.path.exists(self.project_path)\n\n    def log_file(self, agent_name: str) -> str:\n        \"\"\"Get agent's log gile path.\"\"\"\n        return f\"{self.tmp_dir.name}/{agent_name}.log\"\n\n    def test_add_agent(self, *args):\n        \"\"\"Test add agent alias.\"\"\"\n        self.manager.start_manager()\n\n        self.manager.add_project(self.project_public_id, local=True)\n\n        new_tick_interval = 0.2111\n\n        component_overrides = [\n            {\n                **self.echo_skill_id.json,\n                \"type\": \"skill\",\n                \"behaviours\": {\"echo\": {\"args\": {\"tick_interval\": new_tick_interval}}},\n            }\n        ]\n        agent_overrides = {\n            \"logging_config\": {\n                \"version\": 1,\n                \"formatters\": {\"standard\": {\"format\": \"\"}},\n                \"handlers\": {\n                    \"console\": {\n                        \"class\": \"logging.StreamHandler\",\n                        \"formatter\": \"standard\",\n                        \"level\": \"DEBUG\",\n                    },\n                    \"file\": {\n                        \"class\": \"logging.FileHandler\",\n                        \"filename\": self.log_file(self.agent_name),\n                        \"mode\": \"w\",\n                        \"level\": \"DEBUG\",\n                        \"formatter\": \"standard\",\n                    },\n                },\n                \"loggers\": {\"aea\": {\"level\": \"DEBUG\", \"handlers\": [\"file\", \"console\"]}},\n            }\n        }\n        self.manager.add_agent(\n            self.project_public_id,\n            self.agent_name,\n            component_overrides=component_overrides,\n            agent_overrides=agent_overrides,\n        )\n\n        agent_alias = self.manager.get_agent_alias(self.agent_name)\n        assert agent_alias.agent_name == self.agent_name\n        assert (\n            agent_alias.get_aea_instance()\n            .resources.get_behaviour(self.echo_skill_id, \"echo\")\n            .tick_interval\n            == new_tick_interval\n        )\n\n        with pytest.raises(ValueError, match=\"already exists\"):\n            self.manager.add_agent(\n                self.project_public_id,\n                self.agent_name,\n            )\n\n    def test_set_overrides(self, *args):\n        \"\"\"Test agent set overrides.\"\"\"\n        self.test_add_agent()\n        new_tick_interval = 1000.0\n        component_overrides = [\n            {\n                **self.echo_skill_id.json,\n                \"type\": \"skill\",\n                \"behaviours\": {\"echo\": {\"args\": {\"tick_interval\": new_tick_interval}}},\n            }\n        ]\n        self.manager.set_agent_overrides(\n            self.agent_name,\n            agent_overides=None,\n            components_overrides=component_overrides,\n        )\n        agent_alias = self.manager.get_agent_alias(self.agent_name)\n        assert agent_alias.agent_name == self.agent_name\n        assert (\n            agent_alias.get_aea_instance()\n            .resources.get_behaviour(self.echo_skill_id, \"echo\")\n            .tick_interval\n            == new_tick_interval\n        )\n\n    def test_remove_agent(self, *args):\n        \"\"\"Test remove agent alias.\"\"\"\n        self.test_add_agent()\n        assert self.agent_name in self.manager.list_agents()\n        self.manager.remove_agent(self.agent_name)\n        assert self.agent_name not in self.manager.list_agents()\n\n        with pytest.raises(ValueError, match=\"does not exist!\"):\n            self.manager.remove_agent(self.agent_name)\n\n    def test_remove_project_with_alias(self, *args):\n        \"\"\"Test remove project with alias presents.\"\"\"\n        self.test_add_agent()\n\n        with pytest.raises(\n            ValueError, match=\"Can not remove projects with aliases exists\"\n        ):\n            self.manager.remove_project(self.project_public_id)\n\n    def test_add_agent_for_non_exist_project(self, *args):\n        \"\"\"Test add agent when no project added.\"\"\"\n        with pytest.raises(ValueError, match=\" project is not added\"):\n            self.manager.add_agent(PublicId(\"test\", \"test\", \"0.1.0\"), \"another_agent\")\n\n    def test_agent_actually_running(self, *args):\n        \"\"\"Test MultiAgentManager starts agent correctly and agent perform acts.\"\"\"\n        self.test_add_agent()\n\n        self.manager.start_all_agents()\n\n        wait_for_condition(\n            lambda: \"Echo Behaviour: act method called.\"\n            in open(self.log_file(self.agent_name), \"r\").read(),\n            timeout=DEFAULT_TIMEOUT,\n        )\n\n        with contextlib.suppress(Exception):\n            self.manager.stop_agent(self.agent_name)\n\n    def test_exception_handling(self, *args):\n        \"\"\"Test error callback works.\"\"\"\n        self.add_agent(\"test_agent\", PublicId.from_str(\"fetchai/error_test:0.1.1\"))\n        self.manager.start_all_agents()\n\n        callback_mock = Mock()\n\n        self.manager.add_error_callback(callback_mock)\n\n        self.manager.start_all_agents()\n        wait_for_condition(\n            lambda: callback_mock.call_count > 0, timeout=DEFAULT_TIMEOUT\n        )\n\n    def add_agent(self, agent_name: str, project_id: PublicId) -> None:\n        \"\"\"Add agent and start manager.\"\"\"\n        self.manager.start_manager()\n\n        self.manager.add_project(project_id, local=True)\n\n        self.manager.add_agent(\n            project_id,\n            agent_name,\n        )\n\n        agent_alias = self.manager.get_agent_alias(agent_name)\n        assert agent_alias\n\n    def test_default_exception_handling(self, *args):\n        \"\"\"Test that the default error callback works.\"\"\"\n        self.add_agent(\"test_agent\", PublicId.from_str(\"fetchai/error_test:0.1.1\"))\n\n        with patch.object(\n            self.manager,\n            \"_print_exception_occurred_but_no_error_callback\",\n            side_effect=self.manager._print_exception_occurred_but_no_error_callback,\n        ) as callback_mock:\n            self.manager.start_all_agents()\n            wait_for_condition(\n                lambda: callback_mock.call_count > 0, timeout=DEFAULT_TIMEOUT\n            )\n            callback_mock.assert_called_once()\n\n    def test_stop_from_exception_handling(self, *args):\n        \"\"\"Test stop MultiAgentManager from error callback.\"\"\"\n        self.add_agent(\"test_agent\", PublicId.from_str(\"fetchai/error_test:0.1.1\"))\n\n        def handler(*args, **kwargs):\n            self.manager.stop_manager()\n\n        self.manager.add_error_callback(handler)\n\n        self.manager.start_all_agents()\n        wait_for_condition(lambda: not self.manager.is_running, timeout=DEFAULT_TIMEOUT)\n\n    def test_start_all(self, *args):\n        \"\"\"Test MultiAgentManager start all agents.\"\"\"\n        self.test_add_agent()\n        assert self.agent_name in self.manager.list_agents()\n        assert self.agent_name not in self.manager.list_agents(running_only=True)\n        self.manager.start_all_agents()\n        assert self.agent_name in self.manager.list_agents(running_only=True)\n\n        self.manager.start_all_agents()\n\n        # check every agent started\n        wait_for_condition(\n            lambda: len(self.manager.list_agents())\n            == len(self.manager.list_agents(running_only=True)),\n            timeout=DEFAULT_TIMEOUT,\n            period=0.1,\n        )\n\n        wait_for_condition(\n            lambda: \"Start processing messages\"\n            in open(self.log_file(self.agent_name), \"r\").read(),\n            timeout=DEFAULT_TIMEOUT,\n        )\n\n        with pytest.raises(ValueError, match=\"is already started!\"):\n            self.manager.start_agents(self.manager.list_agents())\n\n        with pytest.raises(ValueError, match=\"is already started!\"):\n            self.manager.start_agent(self.agent_name)\n\n        with pytest.raises(ValueError, match=\"is not registered!\"):\n            self.manager.start_agent(\"non_exists_agent\")\n\n    def test_stop_agent(self, *args):\n        \"\"\"Test stop agent.\"\"\"\n        self.test_start_all()\n        wait_for_condition(\n            lambda: self.manager.list_agents(running_only=True), timeout=DEFAULT_TIMEOUT\n        )\n\n        wait_for_condition(\n            lambda: \"Start processing messages\"\n            in open(self.log_file(self.agent_name), \"r\").read(),\n            timeout=DEFAULT_TIMEOUT,\n        )\n\n        self.manager.stop_all_agents()\n\n        wait_for_condition(\n            lambda: len(self.manager.list_agents(running_only=True)) == 0,\n            timeout=DEFAULT_TIMEOUT,\n        )\n\n        assert not self.manager.list_agents(running_only=True)\n\n        with pytest.raises(ValueError, match=\" is not running!\"):\n            self.manager.stop_agent(self.agent_name)\n\n        with pytest.raises(ValueError, match=\" is not running!\"):\n            self.manager.stop_agents([self.agent_name])\n\n        wait_for_condition(\n            lambda: \"Runtime loop stopped!\"\n            in open(self.log_file(self.agent_name), \"r\").read(),\n            timeout=DEFAULT_TIMEOUT,\n        )\n\n    def test_do_no_allow_override_some_fields(self, *args):\n        \"\"\"Do not allo to override some values in agent config.\"\"\"\n        self.manager.start_manager()\n\n        self.manager.add_project(self.project_public_id, local=True)\n\n        BAD_OVERRIDES = [\n            \"skills\",\n            \"connections\",\n            \"contracts\",\n            \"protocols\",\n            \"some_field?\",\n        ]\n\n        for bad_override in BAD_OVERRIDES:\n            with pytest.raises(\n                ValueError, match=r\"Attribute `.*` is not allowed to be updated!\"\n            ):\n                self.manager.add_agent(\n                    self.project_public_id,\n                    self.agent_name,\n                    agent_overrides={bad_override: \"some value\"},\n                )\n\n    @staticmethod\n    def test_invalid_mode(*args):\n        \"\"\"Test MultiAgentManager fails on invalid mode.\"\"\"\n        with pytest.raises(ValueError, match=\"Invalid mode\"):\n            MultiAgentManager(\"test_dir\", mode=\"invalid_mode\")\n\n    def test_double_start(self, *args):\n        \"\"\"Test double MultiAgentManager start.\"\"\"\n        self.manager.start_manager()\n        assert self.manager.is_running\n        self.manager.start_manager()\n        assert self.manager.is_running\n\n    def test_double_stop(self, *args):\n        \"\"\"Test double MultiAgentManager stop.\"\"\"\n        self.manager.start_manager()\n        assert self.manager.is_running\n        self.manager.stop_manager()\n        assert not self.manager.is_running\n        self.manager.stop_manager()\n        assert not self.manager.is_running\n\n    def test_remove_running_agent(self, *args):\n        \"\"\"Test fail on remove running agent.\"\"\"\n        self.test_start_all()\n\n        wait_for_condition(\n            lambda: \"Start processing messages\"\n            in open(self.log_file(self.agent_name), \"r\").read(),\n            timeout=DEFAULT_TIMEOUT,\n        )\n        with pytest.raises(ValueError, match=\"Agent is running. stop it first!\"):\n            self.manager.remove_agent(self.agent_name)\n\n        self.manager.stop_all_agents()\n\n        # wait all stopped\n        wait_for_condition(\n            lambda: len(self.manager.list_agents(running_only=True)) == 0,\n            timeout=DEFAULT_TIMEOUT,\n            period=0.1,\n        )\n        assert self.agent_name not in self.manager.list_agents(running_only=True)\n\n        self.manager.remove_agent(self.agent_name)\n        assert self.agent_name not in self.manager.list_agents()\n\n    def test_save_load_positive(self, *args):\n        \"\"\"Test save-load func of MultiAgentManager for positive result.\"\"\"\n        self.manager.start_manager()\n        self.manager.add_project(self.project_public_id, local=True)\n\n        self.manager.add_agent(self.project_public_id, self.agent_name)\n        self.manager.stop_manager(save=True)\n        assert os.path.exists(self.manager._save_path)\n\n        self.manager.start_manager()\n        assert self.project_public_id in self.manager._projects.keys()\n        assert self.agent_name in self.manager._agents.keys()\n\n    def test_list_agents_info_positive(self, *args):\n        \"\"\"Test list_agents_info method for positive result.\"\"\"\n        self.manager.start_manager()\n        self.manager.add_project(self.project_public_id, local=True)\n\n        self.manager.add_agent(self.project_public_id, self.agent_name)\n        result = self.manager.list_agents_info()\n        expected_result = [\n            {\n                \"agent_name\": self.agent_name,\n                \"public_id\": str(self.project_public_id),\n                \"addresses\": self.manager.get_agent_alias(\n                    self.agent_name\n                ).get_addresses(),\n                \"is_running\": False,\n            }\n        ]\n        assert result == expected_result\n\n    def test_add_same_project_versions(self, *args):\n        \"\"\"Test add the same project twice.\"\"\"\n        self.manager.start_manager()\n\n        self.manager.add_project(self.project_public_id, local=True)\n        with pytest.raises(\n            ValueError, match=r\"The project \\(fetchai/my_first_aea\\) was already added!\"\n        ):\n            self.manager.add_project(\n                PublicId.from_str(\"fetchai/my_first_aea:0.15.0\"), local=False\n            )\n\n    def test_get_overridables(self, *args):\n        \"\"\"Test get overridables.\"\"\"\n        self.manager.start_manager()\n        self.manager.add_project(self.project_public_id, local=True)\n        self.manager.add_agent(self.project_public_id, self.agent_name)\n\n        (\n            agent_overridables,\n            components_overridables,\n        ) = self.manager.get_agent_overridables(self.agent_name)\n        assert \"default_ledger\" in agent_overridables\n        assert \"timeout\" in agent_overridables\n        assert \"description\" in agent_overridables\n        assert len(components_overridables) == 2\n        assert \"is_abstract\" in components_overridables[0]\n\n    def test_issue_certificates(self, *args):\n        \"\"\"Test agent alias issue certificates.\"\"\"\n        self.manager.start_manager()\n        self.manager.add_project(self.project_public_id, local=True)\n\n        cert_filename = \"cert.txt\"\n        cert_path = os.path.join(self.manager.data_dir, self.agent_name, cert_filename)\n        assert not os.path.exists(cert_filename)\n\n        priv_key_path = os.path.abspath(os.path.join(self.working_dir, \"priv_key.txt\"))\n        create_private_key(\"fetchai\", priv_key_path, password=self.PASSWORD)\n        assert os.path.exists(priv_key_path)\n\n        component_overrides = [\n            {\n                **StubConnection.connection_id.json,\n                \"type\": \"connection\",\n                \"cert_requests\": [\n                    {\n                        \"identifier\": \"acn\",\n                        \"ledger_id\": \"fetchai\",\n                        \"not_after\": \"2023-01-01\",\n                        \"not_before\": \"2022-01-01\",\n                        \"public_key\": \"fetchai\",\n                        \"message_format\": \"{public_key}\",\n                        \"save_path\": cert_filename,\n                    }\n                ],\n            }\n        ]\n\n        agent_overrides = {\n            \"private_key_paths\": {\"fetchai\": priv_key_path},\n            \"connection_private_key_paths\": {\"fetchai\": priv_key_path},\n        }\n        self.manager.add_agent(\n            self.project_public_id,\n            self.agent_name,\n            agent_overrides=agent_overrides,\n            component_overrides=component_overrides,\n        )\n        agent_alias = self.manager.get_agent_alias(self.agent_name)\n\n        agent_alias.issue_certificates()\n\n        assert os.path.exists(cert_path)\n\n    def test_get_addresses(self, *args) -> None:\n        \"\"\"Test get addresses for agent alias.\"\"\"\n        self.test_add_agent()\n        agent_alias = self.manager.get_agent_alias(self.agent_name)\n        keys = {\n            name: agent_alias._create_private_key(\n                ledger=name, replace=True, is_connection=False\n            )\n            for name in crypto_registry.supported_ids\n        }\n\n        connection_keys = {\n            name: agent_alias._create_private_key(\n                ledger=name, replace=True, is_connection=True\n            )\n            for name in crypto_registry.supported_ids\n        }\n        agent_alias.set_overrides(\n            {\"private_key_paths\": keys, \"connection_private_key_paths\": connection_keys}\n        )\n\n        assert len(agent_alias.get_addresses()) == len(crypto_registry.supported_ids)\n        assert len(agent_alias.get_connections_addresses()) == len(\n            crypto_registry.supported_ids\n        )\n\n    def test_addresses_autoadded(self, *args) -> None:\n        \"\"\"Test addresses automatically added on creation.\"\"\"\n        self.test_add_agent()\n        agent_alias = self.manager.get_agent_alias(self.agent_name)\n        assert len(agent_alias.get_addresses()) == 1\n        assert len(agent_alias.get_connections_addresses()) == 1\n\n\n@patch(\"aea.aea_builder.AEABuilder.install_pypi_dependencies\")\nclass TestMultiAgentManagerAsyncMode(\n    BaseTestMultiAgentManager\n):  # pylint: disable=unused-argument,protected-access,attribute-defined-outside-init\n    \"\"\"Tests for MultiAgentManager in async mode.\"\"\"\n\n    PASSWORD = \"password\"  # nosec\n\n\n@patch(\"aea.aea_builder.AEABuilder.install_pypi_dependencies\")\nclass TestMultiAgentManagerThreadedMode(BaseTestMultiAgentManager):\n    \"\"\"Tests for MultiAgentManager in threaded mode.\"\"\"\n\n    MODE = \"threaded\"\n\n\n@patch(\"aea.aea_builder.AEABuilder.install_pypi_dependencies\")\nclass TestMultiAgentManagerMultiprocessMode(BaseTestMultiAgentManager):\n    \"\"\"Tests for MultiAgentManager in multiprocess mode.\"\"\"\n\n    MODE = \"multiprocess\"\n\n    def test_plugin_dependencies(self, *args):\n        \"\"\"Skip test cause multiprocess works another way.\"\"\"\n\n\n@patch(\"aea.aea_builder.AEABuilder.install_pypi_dependencies\")\nclass TestMultiAgentManagerPackageConsistencyError:\n    \"\"\"\n    Test that the MultiAgentManager (MAM) raises an error on package version inconsistency.\n\n    In particular, an invariant to keep for the MAM state is that\n    there are no two AEA package dependencies across all the projects\n    that have different versions. This is due to a known limitation\n    in the package loading system.\n\n    This test checks that when the invariant is violated when\n    the method \"add_project\" is called, the framework raises an\n    exception with a descriptive error message.\n    \"\"\"\n\n    EXPECTED_ERROR_MESSAGE = dedent(\n        \"\"\"    cannot add project 'fetchai/weather_client:0.27.0': the following AEA dependencies have conflicts with previously added projects:\n    - 'fetchai/ledger' of type connection: the new version '0.17.0' conflicts with existing version '0.18.0' of the same package required by agents: [<fetchai/weather_station:0.27.0>]\n    - 'fetchai/p2p_libp2p' of type connection: the new version '0.20.0' conflicts with existing version '0.21.0' of the same package required by agents: [<fetchai/weather_station:0.27.0>]\n    - 'fetchai/soef' of type connection: the new version '0.21.0' conflicts with existing version '0.22.0' of the same package required by agents: [<fetchai/weather_station:0.27.0>]\n    - 'fetchai/contract_api' of type protocol: the new version '0.14.0' conflicts with existing version '1.0.0' of the same package required by agents: [<fetchai/weather_station:0.27.0>]\n    - 'fetchai/default' of type protocol: the new version '0.15.0' conflicts with existing version '1.0.0' of the same package required by agents: [<fetchai/weather_station:0.27.0>]\n    - 'fetchai/fipa' of type protocol: the new version '0.16.0' conflicts with existing version '1.0.0' of the same package required by agents: [<fetchai/weather_station:0.27.0>]\n    - 'fetchai/ledger_api' of type protocol: the new version '0.13.0' conflicts with existing version '1.0.0' of the same package required by agents: [<fetchai/weather_station:0.27.0>]\n    - 'fetchai/oef_search' of type protocol: the new version '0.16.0' conflicts with existing version '1.0.0' of the same package required by agents: [<fetchai/weather_station:0.27.0>]\n    - 'fetchai/signing' of type protocol: the new version '0.13.0' conflicts with existing version '1.0.0' of the same package required by agents: [<fetchai/weather_station:0.27.0>]\n    - 'fetchai/state_update' of type protocol: the new version '0.13.0' conflicts with existing version '1.0.0' of the same package required by agents: [<fetchai/weather_station:0.27.0>]\n    \"\"\"\n    )\n\n    def setup(self):\n        \"\"\"Set up the test case.\"\"\"\n        self.project_public_id = MY_FIRST_AEA_PUBLIC_ID\n        self.tmp_dir = TemporaryDirectory()\n        self.working_dir = os.path.join(self.tmp_dir.name, \"MultiAgentManager_dir\")\n        self.project_path = os.path.join(\n            self.working_dir, self.project_public_id.author, self.project_public_id.name\n        )\n        assert not os.path.exists(self.working_dir)\n        self.manager = MultiAgentManager(self.working_dir)\n\n    def test_run(self, *args):\n        \"\"\"\n        Run the test.\n\n        First add agent project \"fetchai/weather_station:0.27.0\",\n        and then add \"fetchai/weather_client:0.27.0\".\n        The second addition will fail because the projects\n        contain conflicting AEA package versions.\n        \"\"\"\n        self.manager.start_manager()\n        weather_station_id = PublicId.from_str(\"fetchai/weather_station:0.27.0\")\n        self.manager.add_project(weather_station_id)\n        weather_client_id = PublicId.from_str(\"fetchai/weather_client:0.27.0\")\n        with pytest.raises(\n            ProjectPackageConsistencyCheckError,\n            match=re.escape(self.EXPECTED_ERROR_MESSAGE),\n        ):\n            self.manager.add_project(weather_client_id)\n\n    def teardown(self):\n        \"\"\"Tear down test case.\"\"\"\n        try:\n            self.manager.stop_manager()\n            if os.path.exists(self.working_dir):\n                rmtree(self.working_dir)\n        finally:\n            self.tmp_dir.cleanup()\n\n\nclass TestMultiAgentManagerWithPotentiallyConflictingPackages:\n    \"\"\"\n    Test that the MultiAgentManager (MAM) handles correctly potentially conflicting packages.\n\n    \"Potentially conflicting packages\" are packages that have the same\n    package id prefix. The reason why they are \"potentially conflicting\"\n    is that their version may be different, i.e. conflicting,\n    and therefore are incompatible within the same MAM.\n\n    This test checks that, when adding a new project,\n    in case there are potentially conflicting packages but that\n    are not in fact conflicting, the operation is completed successfully.\n    \"\"\"\n\n    def setup(self):\n        \"\"\"Set up the test case.\"\"\"\n        self.project_public_id = MY_FIRST_AEA_PUBLIC_ID\n        self.tmp_dir = TemporaryDirectory()\n        self.working_dir = os.path.join(self.tmp_dir.name, \"MultiAgentManager_dir\")\n        self.project_path = os.path.join(\n            self.working_dir, self.project_public_id.author, self.project_public_id.name\n        )\n        assert not os.path.exists(self.working_dir)\n        self.manager = MultiAgentManager(self.working_dir)\n\n    def test_run(self):\n        \"\"\"\n        Run the test.\n\n        First add agent project \"fetchai/weather_station:0.27.0\",\n        and then add \"fetchai/weather_client:0.27.0\".\n        The second addition will fail because the projects\n        contain conflicting AEA package versions.\n        \"\"\"\n        self.manager.start_manager()\n        weather_station_id = PublicId.from_str(\"fetchai/weather_station:0.27.0\")\n        self.manager.add_project(weather_station_id)\n        weather_client_id = PublicId.from_str(\"fetchai/weather_client:0.28.0\")\n        self.manager.add_project(weather_client_id)\n\n    def teardown(self):\n        \"\"\"Tear down test case.\"\"\"\n        try:\n            self.manager.stop_manager()\n            if os.path.exists(self.working_dir):\n                rmtree(self.working_dir)\n        finally:\n            self.tmp_dir.cleanup()\n\n\ndef test_project_auto_added_removed():\n    \"\"\"Check project auto added and auto removed on agent added/removed.\"\"\"\n    agent_name = \"test_agent\"\n    with TemporaryDirectory() as tmp_dir, patch(\n        \"aea.manager.project.Project.build\"\n    ), patch(\"aea.manager.project.Project.install_pypi_dependencies\"):\n        manager = MultiAgentManager(\n            tmp_dir,\n            mode=\"async\",\n            registry_path=PACKAGES_DIR,\n            auto_add_remove_project=True,\n        )\n        try:\n            manager.start_manager()\n            assert not manager.list_projects()\n            manager.add_agent(\n                PublicId(\"fetchai\", \"my_first_aea\"), agent_name, local=True\n            )\n            assert manager.list_projects()\n            assert manager.list_agents()\n            manager.remove_agent(agent_name)\n            assert not manager.list_agents()\n            assert not manager.list_projects()\n        finally:\n            manager.stop_manager()\n\n\ndef test_dump():\n    \"\"\"Check project auto added and auto removed on agent added/removed.\"\"\"\n    agent_name = \"test_agent\"\n    with TemporaryDirectory() as tmp_dir, patch(\n        \"aea.manager.project.Project.build\"\n    ), patch(\"aea.manager.project.Project.install_pypi_dependencies\"):\n        manager = MultiAgentManager(\n            tmp_dir,\n            mode=\"async\",\n            registry_path=PACKAGES_DIR,\n            auto_add_remove_project=True,\n        )\n        try:\n            manager.start_manager()\n            assert not manager.list_projects()\n            manager.add_agent(\n                PublicId(\"fetchai\", \"my_first_aea\"), agent_name, local=True\n            )\n            alias = manager.get_agent_alias(agent_name)\n            data = pickle.dumps(alias)\n            alias2 = pickle.loads(data)  # nosec\n            assert alias.dict == alias2.dict\n            assert alias.project.public_id == alias2.project.public_id\n\n            assert manager.list_projects()\n            assert manager.list_agents()\n            manager.remove_agent(agent_name)\n            assert not manager.list_agents()\n            assert not manager.list_projects()\n        finally:\n            manager.stop_manager()\n\n\ndef test_handle_error_on_load_state():\n    \"\"\"Check project auto added and auto removed on agent added/removed.\"\"\"\n    agent_name = \"test_agent\"\n    with TemporaryDirectory() as tmp_dir:\n        manager = MultiAgentManager(\n            tmp_dir,\n            mode=\"async\",\n            registry_path=PACKAGES_DIR,\n            auto_add_remove_project=True,\n        )\n\n        with pytest.raises(ValueError, match=\"Manager was not started\"):\n            manager.last_start_status\n\n        try:\n            manager.start_manager()\n            state_loaded, *_ = manager.last_start_status\n            assert not state_loaded\n            assert not manager.list_projects()\n            manager.add_agent(\n                PublicId(\"fetchai\", \"my_first_aea\"), agent_name, local=True\n            )\n            assert manager.list_projects()\n            manager._save_state()\n        finally:\n            manager.stop_manager(cleanup=False)\n\n        # check loaded well\n        manager = MultiAgentManager(\n            tmp_dir,\n            mode=\"async\",\n            registry_path=PACKAGES_DIR,\n            auto_add_remove_project=False,\n        )\n        try:\n            manager.start_manager()\n            state_loaded, loaded_ok, *_ = manager.last_start_status\n            assert state_loaded\n            assert len(loaded_ok) == 1\n            assert manager.list_projects()\n            assert manager.list_agents()\n        finally:\n            manager.stop_manager(cleanup=False)\n\n        config_file = (\n            Path(tmp_dir) / \"fetchai/my_first_aea/vendor/fetchai/skills/echo/skill.yaml\"\n        )\n        config_yaml = config_file.read_text()\n        new_version = \"'>=0.0.1, <0.0.2'\"\n        new_config = re.sub(\n            r\"'>=[0-9]+.[0-9]+.[0-9]+, <[0-9]+.[0-9]+.[0-9]+'\",\n            new_version,\n            config_yaml,\n        )\n        assert new_version in new_config\n        config_file.write_text(new_config)\n        # check load fails\n        manager = MultiAgentManager(\n            tmp_dir,\n            mode=\"async\",\n            registry_path=PACKAGES_DIR,\n            auto_add_remove_project=False,\n        )\n        try:\n            manager.start_manager()\n            state_loaded, loaded_ok, load_failed = manager.last_start_status\n            assert state_loaded\n            assert len(loaded_ok) == 0\n            assert len(load_failed) == 1\n            assert isinstance(load_failed[0][0], PublicId)\n            assert isinstance(load_failed[0][1], list)\n            assert len(load_failed[0][1]) == 1\n            assert isinstance(load_failed[0][1][0], dict)\n            assert isinstance(load_failed[0][2], Exception)\n            assert re.match(\n                \"Failed to load project: fetchai/my_first_aea:latest Error: The CLI version is .*, but package fetchai/echo:0.20.6 requires version <0.0.2,>=0.0.1\",\n                str(load_failed[0][2]),\n            )\n            assert not manager.list_projects()\n            assert not manager.list_agents()\n        finally:\n            manager.stop_manager()\n"
  },
  {
    "path": "tests/test_aea_extra/test_manager/test_utils.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains tests for aea manager utils.\"\"\"\nimport time\nfrom random import randint\nfrom tempfile import TemporaryDirectory\n\nimport pytest\n\nfrom aea.manager.utils import run_in_venv\n\n\nRETURN_VALUE = randint(0, 2000)  # nosec\n\nDEFAULT_TIMEOUT = 20\n\n\ndef _process_long():\n    time.sleep(70)\n\n\ndef _process_exception():\n    raise ValueError(\"Expected\")\n\n\ndef _process_return_value(value_to_return):\n    return value_to_return\n\n\ndef test_process_run_in_venv_timeout_error():\n    \"\"\"Test timeout error raised for process running too long.\"\"\"\n    with TemporaryDirectory() as tmp_dir:\n        with pytest.raises(TimeoutError):\n            run_in_venv(tmp_dir, _process_long, timeout=DEFAULT_TIMEOUT)\n\n\ndef test_process_run_in_venv_raise_custom_exception():\n    \"\"\"Test process returns expcetion.\"\"\"\n    with TemporaryDirectory() as tmp_dir:\n        with pytest.raises(Exception, match=\"Expected\"):\n            run_in_venv(tmp_dir, _process_exception, timeout=DEFAULT_TIMEOUT)\n\n\ndef test_process_run_in_venv_return_value():\n    \"\"\"Test process return value.\"\"\"\n    with TemporaryDirectory() as tmp_dir:\n        ret_value = run_in_venv(\n            tmp_dir, _process_return_value, DEFAULT_TIMEOUT, RETURN_VALUE\n        )\n        assert ret_value == RETURN_VALUE\n"
  },
  {
    "path": "tests/test_docs/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests for docs modules.\"\"\"\n"
  },
  {
    "path": "tests/test_docs/helper.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains helper function to extract code from the .md files.\"\"\"\nimport re\nimport traceback\nfrom functools import partial\nfrom pathlib import Path\nfrom typing import Dict, List, Optional, cast\n\nimport mistune\nimport pytest\n\n\nMISTUNE_BLOCK_CODE_ID = \"block_code\"\n\n\ndef block_code_filter(b: Dict) -> bool:\n    \"\"\"Check Mistune block is a code block.\"\"\"\n    return b[\"type\"] == MISTUNE_BLOCK_CODE_ID\n\n\ndef type_filter(type_: Optional[str], b: Dict) -> bool:\n    \"\"\"\n    Check Mistune code block is of a certain type.\n\n    If the field \"info\" is None, return False.\n    If type_ is None, this function always return true.\n\n    :param type_: the expected type of block (optional)\n    :param b: the block dicionary.\n    :return: True if the block should be accepted, false otherwise.\n    \"\"\"\n    if type_ is None:\n        return True\n    return b[\"info\"].strip() == type_ if b[\"info\"] is not None else False\n\n\ndef extract_dicts(dictionary: Dict, collection_dict: List[Dict]) -> List[Dict]:\n    \"\"\"Extract code blocks from .md files.\"\"\"\n    if all(not isinstance(v, list) for v in dictionary.values()):\n        collection_dict.append(dictionary)\n    else:\n        for dict_el in dictionary.values():\n            if isinstance(dict_el, list):\n                for list_el in dict_el:\n                    if isinstance(list_el, dict):\n                        extract_dicts(list_el, collection_dict)\n    return collection_dict\n\n\ndef flatten_blocks(blocks: List[Dict]) -> List[Dict]:\n    \"\"\"Convert a list of dicts with nested dicts, into a list containing all dicts.\"\"\"\n    new_blocks: List[Dict] = []\n    if isinstance(blocks, list):\n        for el in blocks:\n            if isinstance(el, dict):\n                extract_dicts(el, new_blocks)\n    return new_blocks\n\n\ndef correct_spacing(string: str) -> str:\n    \"\"\"Convert a list of dicts with nested dicts, into a list containing all dicts.\"\"\"\n    new_string = \"\"\n    string_no_back_quote = string[:-3]\n    last_new_line = string.rfind(\"\\n\")\n    last_none_space = len(string_no_back_quote.strip(\" \")) - 1\n\n    if last_new_line != -1 and last_new_line == last_none_space:\n        number_of_trailing_spaces = (len(string_no_back_quote) - 1) - last_none_space\n        for line in string.splitlines():\n            number_of_leading_spaces = len(line) - len(line.lstrip(\" \"))\n            if number_of_leading_spaces >= number_of_trailing_spaces:\n                new_line = line[number_of_trailing_spaces:]\n                new_string += new_line\n            else:\n                new_string += line\n            new_string += \"\\n\"\n        return new_string\n    return string\n\n\ndef extract_inner_code_blocks(block: Dict, code_blocks: List[Dict]) -> None:\n    \"\"\"Replace code_block with any sub code_blocks it may have\"\"\"\n    text = cast(str, block[\"text\"])\n    indexes = [m.start() for m in re.finditer(\"```\", text)]\n    if indexes:\n        if len(indexes) % 2 != 0:\n            raise SyntaxError(f\"un-matching ``` found in the block: {text}\")\n        while indexes:\n            starting_index = indexes.pop(0)\n            ending_index = indexes.pop(0) + 3\n            sub_string = text[starting_index:ending_index]\n            new_substring = correct_spacing(sub_string)\n            new_dict = {\n                \"type\": block[\"type\"],\n                \"text\": new_substring,\n                \"info\": block[\"info\"],\n            }\n            code_blocks.insert(code_blocks.index(block), new_dict)\n        code_blocks.remove(block)\n\n\ndef extract_code_blocks(filepath, filter_=None):\n    \"\"\"Extract code blocks from .md files.\"\"\"\n    content = Path(filepath).read_text(encoding=\"utf-8\")\n    markdown_parser = mistune.create_markdown(renderer=mistune.AstRenderer())\n    blocks = markdown_parser(content)\n    flat_blocks = flatten_blocks(blocks)\n    actual_type_filter = partial(type_filter, filter_)\n    code_blocks = list(filter(block_code_filter, flat_blocks))\n\n    for code_block in code_blocks:\n        extract_inner_code_blocks(code_block, code_blocks)\n\n    for block in code_blocks:\n        if block[\"text\"].startswith(\"``` \"):\n            type_ = block[\"text\"][4 : block[\"text\"].find(\"\\n\")]\n            block[\"text\"] = block[\"text\"].strip()[block[\"text\"].find(\"\\n\") + 1 :]\n            if block[\"text\"].endswith(\"```\"):\n                block[\"text\"] = block[\"text\"].strip()[:-3]\n            block[\"info\"] = f\"{type_}\"\n\n    bash_code_blocks = filter(actual_type_filter, code_blocks)\n    return list(b[\"text\"] for b in bash_code_blocks)\n\n\ndef extract_python_code(filepath):\n    \"\"\"Removes the license part from the scripts\"\"\"\n    python_str = \"\"\n    with open(filepath, \"r\") as python_file:\n        read_python_file = python_file.readlines()\n    for i in range(21, len(read_python_file)):\n        python_str += read_python_file[i]\n\n    return python_str\n\n\ndef compile_and_exec(code: str, locals_dict: Dict = None) -> Dict:\n    \"\"\"\n    Compile and exec the code.\n\n    :param code: the code to execute.\n    :param locals_dict: the dictionary of local variables.\n    :return: the dictionary of locals.\n    \"\"\"\n    locals_dict = {} if locals_dict is None else locals_dict\n    try:\n        code_obj = compile(code, \"fakemodule\", \"exec\")\n        exec(code_obj, locals_dict)  # nosec\n    except Exception:\n        pytest.fail(\n            \"The execution of the following code:\\n{}\\nfailed with error:\\n{}\".format(\n                code, traceback.format_exc()\n            )\n        )\n    return locals_dict\n\n\ndef compare_enum_classes(expected_enum_class, actual_enum_class):\n    \"\"\"Compare enum classes.\"\"\"\n    try:\n        # do some pre-processing\n        expected_pairs = sorted(map(lambda x: (x.name, x.value), expected_enum_class))\n        actual_pairs = sorted(map(lambda x: (x.name, x.value), actual_enum_class))\n        assert expected_pairs == actual_pairs, \"{} != {}\".format(\n            expected_pairs, actual_pairs\n        )\n    except AssertionError:\n        pytest.fail(\n            \"Actual enum {} is different from the actual one {}\".format(\n                expected_enum_class, actual_enum_class\n            )\n        )\n\n\nclass BaseTestMarkdownDocs:\n    \"\"\"Base test class for testing Markdown documents.\"\"\"\n\n    DOC_PATH: Path\n    blocks: List[Dict]\n    flat_blocks: List[Dict]\n    python_blocks: List[Dict]\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set up the test.\"\"\"\n        markdown_parser = mistune.create_markdown(renderer=mistune.AstRenderer())\n        cls.doc_path = cls.DOC_PATH\n        cls.doc_content = cls.doc_path.read_text()\n        cls.blocks = markdown_parser(cls.doc_content)\n        cls.flat_blocks = flatten_blocks(cls.blocks)\n        cls.code_blocks = list(filter(block_code_filter, cls.flat_blocks))\n        cls.python_blocks = list(filter(cls._python_selector, cls.flat_blocks))\n\n    @classmethod\n    def _python_selector(cls, block: Dict) -> bool:\n        return block[\"type\"] == MISTUNE_BLOCK_CODE_ID and (\n            block[\"info\"].strip() == \"python\" if block[\"info\"] else False\n        )\n\n\nclass BasePythonMarkdownDocs(BaseTestMarkdownDocs):\n    \"\"\"Test Markdown documentation by running Python snippets in sequence.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"\n        Set up class.\n\n        It sets the initial value of locals and globals.\n        \"\"\"\n        super().setup_class()\n        cls.locals = {}\n        cls.globals = {}\n\n    def _assert(self, locals_, *mocks):\n        \"\"\"Do assertions after Python code execution.\"\"\"\n\n    def test_python_blocks(self, *mocks):\n        \"\"\"Run Python code block in sequence.\"\"\"\n        python_blocks = self.python_blocks\n\n        globals_, locals_ = self.globals, self.locals\n        for python_block in python_blocks:\n            python_code = python_block[\"text\"]\n            exec(python_code, globals_, locals_)  # nosec\n        self._assert(locals_, *mocks)\n"
  },
  {
    "path": "tests/test_docs/test_agent_vs_aea/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the agent-vs-aea modules.\"\"\"\n"
  },
  {
    "path": "tests/test_docs/test_agent_vs_aea/agent_code_block.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This scripts contains code from agent-vs-aea.md file.\"\"\"\n\nimport os\nimport time\nfrom threading import Thread\nfrom typing import List\n\nfrom aea.agent import Agent\nfrom aea.configurations.base import ConnectionConfig\nfrom aea.connections.base import Connection\nfrom aea.helpers.file_io import write_with_lock\nfrom aea.identity.base import Identity\nfrom aea.mail.base import Envelope\n\nfrom packages.fetchai.connections.stub.connection import StubConnection\nfrom packages.fetchai.protocols.default.message import DefaultMessage\n\n\nINPUT_FILE = \"input_file\"\nOUTPUT_FILE = \"output_file\"\n\n\nclass MyAgent(Agent):\n    \"\"\"A simple agent.\"\"\"\n\n    def __init__(self, identity: Identity, connections: List[Connection]):\n        \"\"\"Initialise the agent.\"\"\"\n        super().__init__(identity, connections)\n\n    def setup(self):\n        \"\"\"Setup the agent.\"\"\"\n\n    def act(self):\n        \"\"\"Act implementation.\"\"\"\n        print(\"Act called for tick {}\".format(self.tick))\n\n    def handle_envelope(self, envelope: Envelope) -> None:\n        \"\"\"\n        Handle envelope.\n\n        :param envelope: the envelope received\n        :return: None\n        \"\"\"\n        print(\"React called for tick {}\".format(self.tick))\n        if (\n            envelope is not None\n            and envelope.protocol_specification_id\n            == DefaultMessage.protocol_specification_id\n        ):\n            sender = envelope.sender\n            receiver = envelope.to\n            envelope.to = sender\n            envelope.sender = receiver\n            envelope.message = DefaultMessage.serializer.decode(envelope.message_bytes)\n            envelope.message.sender = receiver\n            envelope.message.to = sender\n            print(\n                \"Received envelope from {} with protocol_specification_id={}\".format(\n                    sender, envelope.protocol_specification_id\n                )\n            )\n            self.outbox.put(envelope)\n\n    def teardown(self):\n        \"\"\"Teardown the agent.\"\"\"\n\n\ndef run():\n    \"\"\"Run demo.\"\"\"\n\n    # Ensure the input and output files do not exist initially\n    if os.path.isfile(INPUT_FILE):\n        os.remove(INPUT_FILE)\n    if os.path.isfile(OUTPUT_FILE):\n        os.remove(OUTPUT_FILE)\n\n    # Create an addresses identity:\n    identity = Identity(\n        name=\"my_agent\", address=\"some_address\", public_key=\"public_key\"\n    )\n\n    # Set up the stub connection\n    configuration = ConnectionConfig(\n        input_file_path=INPUT_FILE,\n        output_file_path=OUTPUT_FILE,\n        connection_id=StubConnection.connection_id,\n    )\n    stub_connection = StubConnection(\n        configuration=configuration, data_dir=\".\", identity=identity\n    )\n\n    # Create our Agent\n    my_agent = MyAgent(identity, [stub_connection])\n\n    # Set the agent running in a different thread\n    try:\n        t = Thread(target=my_agent.start)\n        t.start()\n\n        # Wait for everything to start up\n        time.sleep(3)\n\n        # Create a message inside an envelope and get the stub connection to pass it into the agent\n        message_text = b\"my_agent,other_agent,fetchai/default:1.0.0,\\x12\\r\\x08\\x01*\\t*\\x07\\n\\x05hello,\"\n\n        with open(INPUT_FILE, \"wb\") as f:\n            write_with_lock(f, message_text)\n\n        # Wait for the envelope to get processed\n        time.sleep(2)\n\n        # Read the output envelope generated by the agent\n        with open(OUTPUT_FILE, \"rb\") as f:\n            print(\"output message: \" + f.readline().decode(\"utf-8\"))\n    finally:\n        # Shut down the agent\n        my_agent.stop()\n        t.join()\n\n\nif __name__ == \"__main__\":\n    run()\n"
  },
  {
    "path": "tests/test_docs/test_agent_vs_aea/test_agent_vs_aea.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests for the code-blocks in the agent-vs-aea.md file.\"\"\"\n\nimport os\nfrom pathlib import Path\n\nimport pytest\n\nfrom aea.test_tools.test_cases import AEATestCaseManyFlaky\n\nfrom tests.conftest import CUR_PATH, MAX_FLAKY_RERUNS, ROOT_DIR\nfrom tests.test_docs.helper import extract_code_blocks, extract_python_code\nfrom tests.test_docs.test_agent_vs_aea.agent_code_block import run\n\n\nMD_FILE = \"docs/agent-vs-aea.md\"\nPY_FILE = \"test_docs/test_agent_vs_aea/agent_code_block.py\"\n\n\nclass TestFiles:\n    \"\"\"Test consistency of the files.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Setup the test class.\"\"\"\n        doc_path = os.path.join(ROOT_DIR, MD_FILE)\n        cls.code_blocks = extract_code_blocks(filepath=doc_path, filter_=\"python\")\n        test_code_path = os.path.join(CUR_PATH, PY_FILE)\n        cls.python_file = extract_python_code(test_code_path)\n\n    def test_read_md_file(self):\n        \"\"\"Test the last code block, that is the full listing of the demo from the Markdown.\"\"\"\n        assert (\n            self.code_blocks[-1] == self.python_file\n        ), \"Files must be exactly the same.\"\n\n    def test_code_blocks_exist(self):\n        \"\"\"Test that all the code-blocks exist in the python file.\"\"\"\n        for blocks in self.code_blocks:\n            assert (\n                blocks in self.python_file\n            ), \"Code-block doesn't exist in the python file.\"\n\n\nclass TestAgentVsAEA(AEATestCaseManyFlaky):\n    \"\"\"This class contains the tests for the code-blocks in the agent-vs-aea.md file.\"\"\"\n\n    @pytest.mark.flaky(\n        reruns=MAX_FLAKY_RERUNS\n    )  # TODO: check why test_run_agent raises permission error on file on windows platform!\n    def test_run_agent(self):\n        \"\"\"Run the agent from the file.\"\"\"\n        run()\n        assert os.path.exists(Path(self.t, \"input_file\"))\n\n        message_text = b\"other_agent,my_agent,fetchai/default:1.0.0,\\x12\\r\\x08\\x01*\\t*\\x07\\n\\x05hello,\"\n        path = os.path.join(self.t, \"output_file\")\n        with open(path, \"rb\") as file:\n            msg = file.read()\n        assert msg == message_text, \"The messages must be identical.\"\n"
  },
  {
    "path": "tests/test_docs/test_bash_yaml/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests for the code-blocks in the demos folder.\"\"\"\n"
  },
  {
    "path": "tests/test_docs/test_bash_yaml/md_files/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests for the bash code-blocks in the demos.\"\"\"\n"
  },
  {
    "path": "tests/test_docs/test_bash_yaml/md_files/bash-aggregation-demo.md",
    "content": "``` bash\nagent_name=\"agg$i\"\naea fetch fetchai/simple_aggregator:0.5.5 --alias $agent_name\ncd $agent_name\naea install\naea build\n```\n\n``` bash\nagent_name=\"agg$i\"\naea create agent_name\ncd agent_name\naea add connection fetchai/http_client:0.24.6\naea add connection fetchai/http_server:0.23.6\naea add connection fetchai/p2p_libp2p:0.27.5\naea add connection fetchai/soef:0.27.6\naea add connection fetchai/prometheus:0.9.6\naea add skill fetchai/advanced_data_request:0.7.6\naea add skill fetchai/simple_aggregation:0.3.6\n\naea config set agent.default_connection fetchai/p2p_libp2p:0.27.5\naea install\naea build\n```\n\n``` bash\naea config set --type int vendor.fetchai.skills.advanced_data_request.models.advanced_data_request_model.args.decimals 0\n```\n\n``` bash\naea config set --type bool vendor.fetchai.skills.advanced_data_request.models.advanced_data_request_model.args.use_http_server false\n```\n\n``` bash\naea config set --type list vendor.fetchai.connections.p2p_libp2p.cert_requests \\\n'[{\"identifier\": \"acn\", \"ledger_id\": \"fetchai\", \"not_after\": \"2023-01-01\", \"not_before\": \"2022-01-01\", \"public_key\": \"fetchai\", \"message_format\": \"{public_key}\", \"save_path\": \".certs/conn_cert.txt\"}]'\n```\n\n``` bash\naea config set vendor.fetchai.skills.advanced_data_request.models.advanced_data_request_model.args.url $COIN_URL\naea config set vendor.fetchai.skills.advanced_data_request.models.advanced_data_request_model.args.outputs '[{\"name\": \"price\", \"json_path\": '\"\\\"$JSON_PATH\\\"\"'}]'\n```\n\n``` bash\naea config set vendor.fetchai.skills.simple_aggregation.models.strategy.args.quantity_name price\naea config set vendor.fetchai.skills.simple_aggregation.models.strategy.args.aggregation_function mean\n```\n\n``` bash\nSERVICE_ID=my_btc_aggregation_service\naea config set vendor.fetchai.skills.simple_aggregation.models.strategy.args.service_id $SERVICE_ID\naea config set vendor.fetchai.skills.simple_aggregation.models.strategy.args.search_query.search_value $SERVICE_ID\n```\n\n``` bash\naea generate-key fetchai\naea add-key fetchai\naea generate-key fetchai fetchai_connection_private_key.txt\naea add-key fetchai fetchai_connection_private_key.txt --connection\n```\n\n``` bash\naea issue-certificates\n```\n\n``` bash\nMULTIADDR=$(cd ../agg0 && aea get-multiaddress fetchai --connection)\naea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \\\n'{\n\"delegate_uri\": \"127.0.0.1:'$((11000+i))'\",\n\"entry_peers\": [\"/dns4/127.0.0.1/tcp/9000/p2p/'\"$MULTIADDR\\\"\"'],\n\"local_uri\": \"127.0.0.1:'$((9000+i))'\",\n\"log_file\": \"libp2p_node.log\",\n\"public_uri\": \"127.0.0.1:'$((9000+i))'\"\n}'\naea config set vendor.fetchai.connections.prometheus.config.port $((20000+i))\naea config set vendor.fetchai.connections.http_server.config.port $((8000+i))\n```\n\n``` bash\naea add connection fetchai/ledger:0.21.5\naea add skill fetchai/simple_oracle:0.16.5\n```\n\n``` bash\naea config set vendor.fetchai.skills.simple_oracle.models.strategy.args.ledger_id fetchai\naea config set vendor.fetchai.skills.simple_oracle.models.strategy.args.update_function update_oracle_value\n```\n\n``` bash\naea generate-wealth fetchai\n```\n\n``` bash\naea config set vendor.fetchai.skills.simple_oracle.models.strategy.args.oracle_value_name price_mean\n```\n\n``` bash\naea run\n```\n\n``` bash\ninfo: [agg_i] found agents...\n...\ninfo: [agg_i] Fetching data from...\n...\ninfo: [agg_i] Observation: {'price': {'value':...\n...\ninfo: [agg_i] sending observation to peer...\n...\ninfo: [agg_i] received observation from sender...\n...\ninfo: [agg_i] Observations:...\n...\ninfo: [agg_i] Aggregation (mean):...\n```\n"
  },
  {
    "path": "tests/test_docs/test_bash_yaml/md_files/bash-aries-cloud-agent-demo.md",
    "content": "``` bash\npip install aries-cloudagent\n```\n\n``` bash\n./manage build\n./manage start --logs\n```\n\n``` bash\naca-py start --help\n```\n\n``` bash\naca-py start --admin 127.0.0.1 8021 --admin-insecure-mode --inbound-transport http 0.0.0.0 8020 --outbound-transport http --webhook-url http://127.0.0.1:8022/webhooks\n```\n\n``` bash\naca-py start --admin 127.0.0.1 8031 --admin-insecure-mode --inbound-transport http 0.0.0.0 8030 --outbound-transp http --webhook-url http://127.0.0.1:8032/webhooks\n```\n\n``` bash\naea fetch fetchai/aries_alice:0.32.5\ncd aries_alice\n```\n\n``` bash\naea create aries_alice\ncd aries_alice\naea add connection fetchai/p2p_libp2p:0.27.5\naea add connection fetchai/soef:0.27.6\naea add connection fetchai/http_client:0.24.6\naea add connection fetchai/webhook:0.20.6\naea add skill fetchai/aries_alice:0.26.6\n```\n\n``` bash\naea config set vendor.fetchai.skills.aries_alice.models.strategy.args.admin_host 127.0.0.1\n```\n\n``` bash\naea config set --type int vendor.fetchai.skills.aries_alice.models.strategy.args.admin_port 8031\n```\n\n``` bash\naea config set --type int vendor.fetchai.connections.webhook.config.webhook_port 8032\n```\n\n``` bash\naea config set vendor.fetchai.connections.webhook.config.webhook_url_path /webhooks/topic/{topic}/\n```\n\n``` bash\naea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \\\n'{\n  \"delegate_uri\": \"127.0.0.1:11000\",\n  \"entry_peers\": [],\n  \"local_uri\": \"127.0.0.1:7000\",\n  \"log_file\": \"libp2p_node.log\",\n  \"public_uri\": \"127.0.0.1:7000\"\n}'\n```\n\n``` bash\naea install\naea build\n```\n\n``` bash\naea run\n```\n\n``` bash\naea fetch fetchai/aries_faber:0.32.5\ncd aries_faber\n```\n\n``` bash\naea create aries_faber\ncd aries_faber\naea add connection fetchai/p2p_libp2p:0.27.5\naea add connection fetchai/soef:0.27.6\naea add connection fetchai/http_client:0.24.6\naea add connection fetchai/webhook:0.20.6\naea add skill fetchai/aries_faber:0.24.5\n```\n\n``` bash\naea config set vendor.fetchai.skills.aries_faber.models.strategy.args.admin_host 127.0.0.1\n```\n\n``` bash\naea config set --type int vendor.fetchai.skills.aries_faber.models.strategy.args.admin_port 8021\n```\n\n``` bash\naea config set --type int vendor.fetchai.connections.webhook.config.webhook_port 8022\n```\n\n``` bash\naea config set vendor.fetchai.connections.webhook.config.webhook_url_path /webhooks/topic/{topic}/\n```\n\n``` bash\naea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \\\n'{\n  \"delegate_uri\": \"127.0.0.1:11001\",\n  \"entry_peers\": [\"SOME_ADDRESS\"],\n  \"local_uri\": \"127.0.0.1:7001\",\n  \"log_file\": \"libp2p_node.log\",\n  \"public_uri\": \"127.0.0.1:7001\"\n}'\n```\n\n``` bash\naea install\naea build\n```\n\n``` bash\naea run\n```\n\n``` bash\naea delete aries_faber\naea delete aries_alice\n```\n"
  },
  {
    "path": "tests/test_docs/test_bash_yaml/md_files/bash-car-park-skills.md",
    "content": "``` bash\n{\n  \"delegate_uri\": \"127.0.0.1:11001\",\n  \"entry_peers\": [\"REPLACE_WITH_MULTI_ADDRESS_HERE\"],\n  \"local_uri\": \"127.0.0.1:9001\",\n  \"log_file\": \"libp2p_node.log\",\n  \"public_uri\": \"127.0.0.1:9001\"\n}\n```\n\n``` bash\naea fetch fetchai/car_detector:0.32.5\ncd car_detector\naea install\naea build\n```\n\n``` bash\naea create car_detector\ncd car_detector\naea add connection fetchai/p2p_libp2p:0.27.5\naea add connection fetchai/soef:0.27.6\naea add connection fetchai/ledger:0.21.5\naea add skill fetchai/carpark_detection:0.27.6\naea config set --type dict agent.dependencies \\\n'{\n  \"aea-ledger-fetchai\": {\"version\": \"<2.0.0,>=1.0.0\"}\n}'\naea config set agent.default_connection fetchai/p2p_libp2p:0.27.5\naea config set --type dict agent.default_routing \\\n'{\n  \"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n  \"fetchai/oef_search:1.1.7\": \"fetchai/soef:0.27.6\"\n}'\naea install\naea build\n```\n\n``` bash\naea fetch fetchai/car_data_buyer:0.33.5\ncd car_data_buyer\naea install\naea build\n```\n\n``` bash\naea create car_data_buyer\ncd car_data_buyer\naea add connection fetchai/p2p_libp2p:0.27.5\naea add connection fetchai/soef:0.27.6\naea add connection fetchai/ledger:0.21.5\naea add skill fetchai/carpark_client:0.27.6\naea config set --type dict agent.dependencies \\\n'{\n  \"aea-ledger-fetchai\": {\"version\": \"<2.0.0,>=1.0.0\"}\n}'\naea config set agent.default_connection fetchai/p2p_libp2p:0.27.5\naea config set --type dict agent.default_routing \\\n'{\n  \"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n  \"fetchai/oef_search:1.1.7\": \"fetchai/soef:0.27.6\"\n}'\naea install\naea build\n```\n\n``` bash\naea generate-key fetchai\naea add-key fetchai fetchai_private_key.txt\n```\n\n``` bash\naea generate-key fetchai fetchai_connection_private_key.txt\naea add-key fetchai fetchai_connection_private_key.txt --connection\n```\n\n``` bash\naea issue-certificates\n```\n\n``` bash\naea generate-key fetchai\naea add-key fetchai fetchai_private_key.txt\naea add-key fetchai fetchai_private_key.txt --connection\n```\n\n``` bash\naea generate-wealth fetchai\n```\n\n``` bash\naea generate-key fetchai fetchai_connection_private_key.txt\naea add-key fetchai fetchai_connection_private_key.txt --connection\n```\n\n``` bash\naea issue-certificates\n```\n\n``` bash\naea run\n```\n\n``` bash\naea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \\\n'{\n  \"delegate_uri\": \"127.0.0.1:11001\",\n  \"entry_peers\": [\"SOME_ADDRESS\"],\n  \"local_uri\": \"127.0.0.1:9001\",\n  \"log_file\": \"libp2p_node.log\",\n  \"public_uri\": \"127.0.0.1:9001\"\n}'\n```\n\n``` bash\naea run\n```\n\n``` bash\ncd ..\naea delete car_detector\naea delete car_data_buyer\n```\n\n``` yaml\n---\npublic_id: fetchai/p2p_libp2p:0.27.5\ntype: connection\nconfig:\n  delegate_uri: 127.0.0.1:11001\n  entry_peers:\n  - SOME_ADDRESS\n  local_uri: 127.0.0.1:9001\n  log_file: libp2p_node.log\n  public_uri: 127.0.0.1:9001\n```\n"
  },
  {
    "path": "tests/test_docs/test_bash_yaml/md_files/bash-cli-vs-programmatic-aeas.md",
    "content": "``` bash\nsvn export https://github.com/fetchai/agents-aea.git/trunk/packages\n```\n\n```bash\npip install aea-ledger-fetchai\n```\n\n``` bash\naea fetch fetchai/weather_station:0.32.5\ncd weather_station\naea install\naea build\n```\n\n``` bash\naea config set vendor.fetchai.skills.weather_station.models.strategy.args.is_ledger_tx False --type bool\n```\n\n``` bash\naea generate-key fetchai\naea add-key fetchai fetchai_private_key.txt\n```\n\n``` bash\naea generate-key fetchai fetchai_connection_private_key.txt\naea add-key fetchai fetchai_connection_private_key.txt --connection\n```\n\n``` bash\naea issue-certificates\n```\n\n``` bash\naea run\n```\n\n``` bash\npython weather_client.py\n```\n"
  },
  {
    "path": "tests/test_docs/test_bash_yaml/md_files/bash-config.md",
    "content": "``` yaml\nPACKAGE_REGEX: \"[a-zA-Z_][a-zA-Z0-9_]*\"\nAUTHOR_REGEX: \"[a-zA-Z_][a-zA-Z0-9_]*\"\nPUBLIC_ID_REGEX: \"^[a-zA-Z0-9_]*/[a-zA-Z_][a-zA-Z0-9_]*:(0|[1-9]\\\\d*)\\\\.(0|[1-9]\\\\d*)\\\\.(0|[1-9]\\\\d*)(?:-((?:0|[1-9]\\\\d*|\\\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\\\.(?:0|[1-9]\\\\d*|\\\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\\\+([0-9a-zA-Z-]+(?:\\\\.[0-9a-zA-Z-]+)*))?$\"\nLEDGER_ID_REGEX: \"^[^\\\\d\\\\W]\\\\w*\\\\Z\"\n```\n\n``` yaml\nagent_name: my_agent                            # Name of the AEA project (must satisfy PACKAGE_REGEX)\nauthor: fetchai                                 # Author handle of the project's author (must satisfy AUTHOR_REGEX)\nversion: 0.1.0                                  # Version of the AEA project (a semantic version number, see https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string\")\ndescription: A demo project                     # Description of the AEA project\nlicense: Apache-2.0                             # License of the AEA project\naea_version: '>=1.0.0, <2.0.0'               # AEA framework version(s) compatible with the AEA project (a version number that matches PEP 440 version schemes, or a comma-separated list of PEP 440 version specifiers, see https://www.python.org/dev/peps/pep-0440/#version-specifiers)\nfingerprint: {}                                 # Fingerprint of AEA project components.\nfingerprint_ignore_patterns: []                 # Ignore pattern for the fingerprinting tool.\nconnections:                                    # The list of connection public ids the AEA project depends on (each public id must satisfy PUBLIC_ID_REGEX)\n- fetchai/stub:0.21.3\ncontracts: []                                   # The list of contract public ids the AEA project depends on (each public id must satisfy PUBLIC_ID_REGEX).\nprotocols:                                      # The list of protocol public ids the AEA project depends on (each public id must satisfy PUBLIC_ID_REGEX).\n- fetchai/default:1.1.7\nskills:                                         # The list of skill public ids the AEA project depends on (each public id must satisfy PUBLIC_ID_REGEX).\n- fetchai/error:0.18.6\ndefault_connection: fetchai/p2p_libp2p:0.27.5   # The default connection used for envelopes sent by the AEA (must satisfy PUBLIC_ID_REGEX).\ndefault_ledger: fetchai                         # The default ledger identifier the AEA project uses (must satisfy LEDGER_ID_REGEX)\nrequired_ledgers: [fetchai]                            # the list of identifiers of ledgers that the AEA project requires key pairs for (each item must satisfy LEDGER_ID_REGEX)\ndefault_routing: {}                             # The default routing scheme applied to envelopes sent by the AEA, it maps from protocol public ids to connection public ids (both keys and values must satisfy PUBLIC_ID_REGEX)\nconnection_private_key_paths:                   # The private key paths the AEA project uses for its connections (keys must satisfy LEDGER_ID_REGEX, values must be file paths)\n  fetchai: fetchai_private_key.txt\nprivate_key_paths:                              # The private key paths the AEA project uses (keys must satisfy LEDGER_ID_REGEX, values must be file paths)\n  fetchai: fetchai_private_key.txt\nlogging_config:                                 # The logging configurations the AEA project uses\n  disable_existing_loggers: false\n  version: 1\ndependencies: {}                                # The python dependencies the AEA relies on (e.g. plugins). They will be installed when `aea install` is run.\n```\n\n``` yaml\nperiod: 0.05                                    # The period to call agent's act\nexecution_timeout: 0                            # The execution time limit on each call to `react` and `act` (0 disables the feature)\ntimeout: 0.05                                   # The sleep time on each AEA loop spin (only relevant for the `sync` mode)\nmax_reactions: 20                               # The maximum number of envelopes processed per call to `react` (only relevant for the `sync` mode)\nskill_exception_policy: propagate               # The exception policy applied to skills (must be one of \"propagate\", \"just_log\", or \"stop_and_exit\")\nconnection_exception_policy: propagate          # The exception policy applied to connections (must be one of \"propagate\", \"just_log\", or \"stop_and_exit\")\nloop_mode: async                                # The agent loop mode (must be one of \"sync\" or \"async\")\nruntime_mode: threaded                          # The runtime mode (must be one of \"threaded\" or \"async\") and determines how agent loop and multiplexer are run\nerror_handler: None                             # The error handler to be used.\ndecision_maker_handler: None                    # The decision maker handler to be used.\nstorage_uri: None                               # The URI to the storage.\ndata_dir: None                                  # The path to the directory for local files. Defaults to current working directory.\n```\n\n``` yaml\npublic_id: some_author/some_package:0.1.0       # The public id of the connection (must satisfy PUBLIC_ID_REGEX).\ntype: connection                                # for connections, this must be \"connection\".\nconfig: ...                                     # a dictionary to overwrite the `config` field (see below)\n```\n\n``` yaml\npublic_id: some_author/some_package:0.1.0       # The public id of the connection (must satisfy PUBLIC_ID_REGEX).\ntype: skill                                     # for skills, this must be \"skill\".\nbehaviours:                                     # override configurations for behaviours\n  behaviour_1:                                  # override configurations for \"behaviour_1\"\n    args:                                       # arguments for a specific behaviour (see below)\n      foo: bar\nhandlers:                                       # override configurations for handlers\n  handler_1:                                    # override configurations for \"handler_1\"\n    args:                                       # arguments for a specific handler (see below)\n      foo: bar\nmodels:                                         # override configurations for models\n  model_1:                                      # override configurations for \"model_1\"\n    args:                                       # arguments for a specific model (see below)\n      foo: bar\n```\n\n``` yaml\nname: scaffold                                  # Name of the package (must satisfy PACKAGE_REGEX)\nauthor: fetchai                                 # Author handle of the package's author (must satisfy AUTHOR_REGEX)\nversion: 0.1.0                                  # Version of the package (a semantic version number, see https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string\")\ntype: connection                                # The type of the package; for connections, it must be \"connection\"\ndescription: A scaffold connection              # Description of the package\nlicense: Apache-2.0                             # License of the package\naea_version: '>=1.0.0, <2.0.0'               # AEA framework version(s) compatible with the AEA project (a version number that matches PEP 440 version schemes, or a comma-separated list of PEP 440 version specifiers, see https://www.python.org/dev/peps/pep-0440/#version-specifiers)\nfingerprint:                                    # Fingerprint of package components.\n  __init__.py: QmZvYZ5ECcWwqiNGh8qNTg735wu51HqaLxTSifUxkQ4KGj\n  connection.py: QmagwVgaPgfeXqVTgcpFESA4DYsteSbojz94SLtmnHNAze\nfingerprint_ignore_patterns: []                 # Ignore pattern for the fingerprinting tool.\nconnections: []                                 # The list of connection public ids the package depends on (each public id must satisfy PUBLIC_ID_REGEX).\nprotocols: []                                   # The list of protocol public ids the package depends on (each public id must satisfy PUBLIC_ID_REGEX).\nclass_name: MyScaffoldConnection                # The class name of the class implementing the connection interface.\nconfig:                                         # A dictionary containing the kwargs for the connection instantiation.\n  foo: bar\nexcluded_protocols: []                          # The list of protocol public ids the package does not permit (each public id must satisfy PUBLIC_ID_REGEX).\nrestricted_to_protocols: []                     # The list of protocol public ids the package is limited to (each public id must satisfy PUBLIC_ID_REGEX).\ndependencies: {}                                # The python dependencies the package relies on. They will be installed when `aea install` is run.\nis_abstract: false                              # An optional boolean that if `true` makes the connection\n```\n\n``` yaml\nname: scaffold                                  # Name of the package (must satisfy PACKAGE_REGEX)\nauthor: fetchai                                 # Author handle of the package's author (must satisfy AUTHOR_REGEX)\nversion: 0.1.0                                  # Version of the package (a semantic version number, see https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string\")\ntype: contract                                  # The type of the package; for contracts, it must be \"contract\"\ndescription: A scaffold contract                # Description of the package\nlicense: Apache-2.0                             # License of the package\naea_version: '>=1.0.0, <2.0.0'               # AEA framework version(s) compatible with the AEA project (a version number that matches PEP 440 version schemes, or a comma-separated list of PEP 440 version specifiers, see https://www.python.org/dev/peps/pep-0440/#version-specifiers)\nfingerprint:                                    # Fingerprint of package components.\n  __init__.py: QmPBwWhEg3wcH1q9612srZYAYdANVdWLDFWKs7TviZmVj6\n  contract.py: QmXvjkD7ZVEJDJspEz5YApe5bRUxvZHNi8vfyeVHPyQD5G\nfingerprint_ignore_patterns: []                 # Ignore pattern for the fingerprinting tool.\nclass_name: MyScaffoldContract                  # The class name of the class implementing the contract interface.\ncontract_interface_paths: {}                    # The paths to the contract interfaces (one for each ledger identifier).\nconfig:                                         # A dictionary containing the kwargs for the contract instantiation.\n  foo: bar\ndependencies: {}                                # The python dependencies the package relies on. They will be installed when `aea install` is run.\n```\n\n``` yaml\nname: scaffold                                  # Name of the package (must satisfy PACKAGE_REGEX)\nauthor: fetchai                                 # Author handle of the package's author (must satisfy AUTHOR_REGEX)\nversion: 0.1.0                                  # Version of the package (a semantic version number, see https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string\")\ntype: protocol                                  # The type of the package; for protocols, it must be \"protocol\" \ndescription: A scaffold protocol                # Description of the package\nlicense: Apache-2.0                             # License of the package\naea_version: '>=1.0.0, <2.0.0'               # AEA framework version(s) compatible with the AEA project (a version number that matches PEP 440 version schemes, or a comma-separated list of PEP 440 version specifiers, see https://www.python.org/dev/peps/pep-0440/#version-specifiers)\nfingerprint:                                    # Fingerprint of package components.\n  __init__.py: Qmay9PmfeHqqVa3rdgiJYJnzZzTStboQEfpwXDpcgJMHTJ\n  message.py: QmdvAdYSHNdZyUMrK3ue7quHAuSNwgZZSHqxYXyvh8Nie4\n  serialization.py: QmVUzwaSMErJgNFYQZkzsDhuuT2Ht4EdbGJ443usHmPxVv\nfingerprint_ignore_patterns: []                 # Ignore pattern for the fingerprinting tool.\ndependencies: {}                                # The python dependencies the package relies on. They will be installed when `aea install` is run.\n```\n\n``` yaml\nname: scaffold                                  # Name of the package (must satisfy PACKAGE_REGEX)\nauthor: fetchai                                 # Author handle of the package's author (must satisfy AUTHOR_REGEX)\nversion: 0.1.0                                  # Version of the package (a semantic version number, see https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string\")\ntype: skill                                     # The type of the package; for skills, it must be \"skill\"\ndescription: A scaffold skill                   # Description of the package\nlicense: Apache-2.0                             # License of the package\naea_version: '>=1.0.0, <2.0.0'               # AEA framework version(s) compatible with the AEA project (a version number that matches PEP 440 version schemes, or a comma-separated list of PEP 440 version specifiers, see https://www.python.org/dev/peps/pep-0440/#version-specifiers)\nfingerprint:                                    # Fingerprint of package components.\n  __init__.py: QmNkZAetyctaZCUf6ACxP5onGWsSxu2hjSNoFmJ3ta6Lta\n  behaviours.py: QmYa1rczhGTtMJBgCd1QR9uZhhkf45orm7TnGTE5Eizjpy\n  handlers.py: QmZYyTENRr6ecnxx1FeBdgjLiBhFLVn9mqarzUtFQmNUFn\n  my_model.py: QmPaZ6G37Juk63mJj88nParaEp71XyURts8AmmX1axs24V\nfingerprint_ignore_patterns: []                 # Ignore pattern for the fingerprinting tool.\ncontracts: []                                   # The list of contract public ids the package depends on (each public id must satisfy PUBLIC_ID_REGEX).\nprotocols: []                                   # The list of protocol public ids the package depends on (each public id must satisfy PUBLIC_ID_REGEX).\nskills: []                                      # The list of skill public ids the package depends on (each public id must satisfy PUBLIC_ID_REGEX).\nis_abstract: false                              # An optional boolean that if `true` makes the skill abstract, i.e. not instantiated by the framework but importable from other skills. Defaults to `false`. \nbehaviours:                                     # The dictionary describing the behaviours immplemented in the package (including their configuration)\n  scaffold:                                     # Name of the behaviour under which it is made available on the skill context.\n    args:                                       # Keyword arguments provided to the skill component on instantiation.\n      foo: bar\n    class_name: MyScaffoldBehaviour             # The class name of the class implementing the behaviour interface.\nhandlers:                                       # The dictionary describing the handlers immplemented in the package (including their configuration)\n  scaffold:                                     # Name of the handler under which it is made available on the skill\n    args:                                       # Keyword arguments provided to the skill component on instantiation.\n      foo: bar\n    class_name: MyScaffoldHandler               # The class name of the class implementing the handler interface.\nmodels:                                         # The dictionary describing the models immplemented in the package (including their configuration)\n  scaffold:                                     # Name of the model under which it is made available on the skill\n    args:                                       # Keyword arguments provided to the skill component on instantiation.\n      foo: bar\n    class_name: MyModel                         # The class name of the class implementing the model interface.\ndependencies: {}                                # The python dependencies the package relies on. They will be installed when `aea install` is run.\n```\n"
  },
  {
    "path": "tests/test_docs/test_bash_yaml/md_files/bash-connection.md",
    "content": "``` bash\naea scaffold connection my_new_connection\n```\n\n``` yaml\nconnections: []\nprotocols: []\nclass_name: MyScaffoldConnection\nconfig:\n  foo: bar\nexcluded_protocols: []\nrestricted_to_protocols: []\ndependencies: {}\nis_abstract: false\ncert_requests: []\n```\n"
  },
  {
    "path": "tests/test_docs/test_bash_yaml/md_files/bash-contract.md",
    "content": "``` bash\naea scaffold contract my_new_contract\n```\n\n``` yaml\ncontract_interface_paths:\n    ethereum: build/my_contract.json\n```\n"
  },
  {
    "path": "tests/test_docs/test_bash_yaml/md_files/bash-decision-maker.md",
    "content": "``` yaml\ndecision_maker_handler:\n  config: {}\n  dotted_path: \"aea.decision_maker.gop:DecisionMakerHandler\"\n  file_path: null\n```\n\n``` bash\naea scaffold decision-maker-handler\n```\n"
  },
  {
    "path": "tests/test_docs/test_bash_yaml/md_files/bash-deployment.md",
    "content": "``` bash\nsvn export https://github.com/fetchai/agents-aea/branches/main/deploy-image\ncd deploy-image\n```\n"
  },
  {
    "path": "tests/test_docs/test_bash_yaml/md_files/bash-erc1155-skills.md",
    "content": "``` bash\naea fetch fetchai/erc1155_deployer:0.34.5\ncd erc1155_deployer\naea install\naea build\n```\n\n``` bash\naea create erc1155_deployer\ncd erc1155_deployer\naea add connection fetchai/p2p_libp2p:0.27.5\naea add connection fetchai/soef:0.27.6\naea add connection fetchai/ledger:0.21.5\naea add skill fetchai/erc1155_deploy:0.31.6\naea config set --type dict agent.dependencies \\\n'{\n  \"aea-ledger-fetchai\": {\"version\": \"<2.0.0,>=1.0.0\"},\n  \"aea-ledger-ethereum\": {\"version\": \"<2.0.0,>=1.0.0\"},\n  \"aea-ledger-cosmos\": {\"version\": \"<2.0.0,>=1.0.0\"}\n}'\naea config set agent.default_connection fetchai/p2p_libp2p:0.27.5\naea config set --type dict agent.default_routing \\\n'{\n  \"fetchai/contract_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n  \"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n  \"fetchai/oef_search:1.1.7\": \"fetchai/soef:0.27.6\"\n}'\naea config set --type list vendor.fetchai.connections.p2p_libp2p.cert_requests \\\n'[{\"identifier\": \"acn\", \"ledger_id\": \"ethereum\", \"not_after\": \"2023-01-01\", \"not_before\": \"2022-01-01\", \"public_key\": \"fetchai\", \"save_path\": \".certs/conn_cert.txt\"}]'\naea install\naea build\n```\n\n``` bash\naea config set agent.default_ledger ethereum\n```\n\n``` bash\naea generate-key ethereum\naea add-key ethereum ethereum_private_key.txt\n```\n\n``` bash\naea generate-key fetchai fetchai_connection_private_key.txt\naea add-key fetchai fetchai_connection_private_key.txt --connection\n```\n\n``` bash\naea issue-certificates\n```\n\n``` bash\naea fetch fetchai/erc1155_client:0.34.5\ncd erc1155_client\naea install\naea build\n```\n\n``` bash\naea create erc1155_client\ncd erc1155_client\naea add connection fetchai/p2p_libp2p:0.27.5\naea add connection fetchai/soef:0.27.6\naea add connection fetchai/ledger:0.21.5\naea add skill fetchai/erc1155_client:0.29.6\naea config set --type dict agent.dependencies \\\n'{\n  \"aea-ledger-fetchai\": {\"version\": \"<2.0.0,>=1.0.0\"},\n  \"aea-ledger-ethereum\": {\"version\": \"<2.0.0,>=1.0.0\"},\n  \"aea-ledger-cosmos\": {\"version\": \"<2.0.0,>=1.0.0\"}\n}'\naea config set agent.default_connection fetchai/p2p_libp2p:0.27.5\naea config set --type dict agent.default_routing \\\n'{\n  \"fetchai/contract_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n  \"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n  \"fetchai/oef_search:1.1.7\": \"fetchai/soef:0.27.6\"\n}'\naea config set --type list vendor.fetchai.connections.p2p_libp2p.cert_requests \\\n'[{\"identifier\": \"acn\", \"ledger_id\": \"ethereum\", \"not_after\": \"2023-01-01\", \"not_before\": \"2022-01-01\", \"public_key\": \"fetchai\", \"save_path\": \".certs/conn_cert.txt\"}]'\naea install\naea build\n```\n\n``` bash\naea config set agent.default_ledger ethereum\n```\n\n``` bash\naea generate-key ethereum\naea add-key ethereum ethereum_private_key.txt\n```\n\n``` bash\naea generate-key fetchai fetchai_connection_private_key.txt\naea add-key fetchai fetchai_connection_private_key.txt --connection\n```\n\n``` bash\naea issue-certificates\n```\n\n``` bash\ndocker run -p 8545:8545 trufflesuite/ganache-cli:latest --verbose --gasPrice=0 --gasLimit=0x1fffffffffffff --account=\"$(cat erc1155_deployer/ethereum_private_key.txt),1000000000000000000000\" --account=\"$(cat erc1155_client/ethereum_private_key.txt),1000000000000000000000\"\n```\n\n``` bash\naea get-wealth ethereum\n```\n\n``` bash\naea config set vendor.fetchai.connections.soef.config.chain_identifier ethereum\n```\n\n``` bash\naea run\n```\n\n``` bash\nregistering service on SOEF.\n```\n\n``` bash\naea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \\\n'{\n  \"delegate_uri\": \"127.0.0.1:11001\",\n  \"entry_peers\": [\"SOME_ADDRESS\"],\n  \"local_uri\": \"127.0.0.1:9001\",\n  \"log_file\": \"libp2p_node.log\",\n  \"public_uri\": \"127.0.0.1:9001\"\n}'\n```\n\n``` bash\naea run\n```\n\n``` bash\ncd ..\naea delete erc1155_deployer\naea delete erc1155_client\n```\n\n``` yaml\ndefault_routing:\n  fetchai/contract_api:1.1.7: fetchai/ledger:0.21.5\n  fetchai/ledger_api:1.1.7: fetchai/ledger:0.21.5\n  fetchai/oef_search:1.1.7: fetchai/soef:0.27.6\n```\n\n``` yaml\ndefault_routing:\n  fetchai/contract_api:1.1.7: fetchai/ledger:0.21.5\n  fetchai/ledger_api:1.1.7: fetchai/ledger:0.21.5\n  fetchai/oef_search:1.1.7: fetchai/soef:0.27.6\n```\n\n``` yaml\n---\npublic_id: fetchai/p2p_libp2p:0.27.5\ntype: connection\nconfig:\n  delegate_uri: 127.0.0.1:11001\n  entry_peers:\n  - SOME_ADDRESS\n  local_uri: 127.0.0.1:9001\n  log_file: libp2p_node.log\n  public_uri: 127.0.0.1:9001\n```\n"
  },
  {
    "path": "tests/test_docs/test_bash_yaml/md_files/bash-generic-skills-step-by-step.md",
    "content": "``` bash\nsudo nano 99-hidraw-permissions.rules\n```\n\n``` bash\nKERNEL==\"hidraw*\", SUBSYSTEM==\"hidraw\", MODE=\"0664\", GROUP=\"plugdev\"\n```\n\n``` bash\naea fetch fetchai/generic_seller:0.29.5\ncd generic_seller\naea eject skill fetchai/generic_seller:0.28.6\ncd ..\n```\n\n``` bash\naea fetch fetchai/generic_buyer:0.30.5\ncd generic_buyer\naea eject skill fetchai/generic_buyer:0.27.6\ncd ..\n```\n\n``` bash\naea init --reset --author fetchai\n```\n\n``` bash\naea create my_generic_seller\ncd my_generic_seller\naea install\n```\n\n``` bash\naea scaffold skill generic_seller\n```\n\n``` bash\naea fingerprint skill fetchai/generic_seller:0.1.0\n```\n\n``` bash\naea create my_generic_buyer\ncd my_generic_buyer\naea install\n```\n\n``` bash\naea scaffold skill generic_buyer\n```\n\n``` bash\naea fingerprint skill fetchai/generic_buyer:0.1.0\n```\n\n``` bash\naea generate-key fetchai\naea add-key fetchai fetchai_private_key.txt\n```\n\n``` bash\naea generate-key fetchai fetchai_connection_private_key.txt\naea add-key fetchai fetchai_connection_private_key.txt --connection\n```\n\n``` bash\naea issue-certificates\n```\n\n``` bash\naea config set --type dict agent.default_routing \\\n'{\n  \"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n  \"fetchai/oef_search:1.1.7\": \"fetchai/soef:0.27.6\"\n}'\n```\n\n``` bash\naea generate-wealth fetchai --sync\n```\n\n``` bash\naea add connection fetchai/p2p_libp2p:0.27.5\naea add connection fetchai/soef:0.27.6\naea add connection fetchai/ledger:0.21.5\naea add protocol fetchai/fipa:1.1.7\naea install\naea build\naea config set agent.default_connection fetchai/p2p_libp2p:0.27.5\naea run\n```\n\n``` bash\naea add connection fetchai/p2p_libp2p:0.27.5\naea add connection fetchai/soef:0.27.6\naea add connection fetchai/ledger:0.21.5\naea add protocol fetchai/fipa:1.1.7\naea add protocol fetchai/signing:1.1.7\naea install\naea build\naea config set agent.default_connection fetchai/p2p_libp2p:0.27.5\n```\n\n``` bash\naea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \\\n'{\n  \"delegate_uri\": \"127.0.0.1:11001\",\n  \"entry_peers\": [\"SOME_ADDRESS\"],\n  \"local_uri\": \"127.0.0.1:9001\",\n  \"log_file\": \"libp2p_node.log\",\n  \"public_uri\": \"127.0.0.1:9001\"\n}'\n```\n\n``` bash\naea run\n```\n\n``` bash\ncd ..\naea delete my_generic_seller\naea delete my_generic_buyer\n```\n\n``` yaml\nname: generic_seller\nauthor: fetchai\nversion: 0.1.0\ntype: skill\ndescription: The weather station skill implements the functionality to sell weather\n  data.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: QmPb5kHYZyhUN87EKmuahyGqDGgqVdGPyfC1KpGC3xfmcP\n  __init__.py: QmTSEedzQySy2nzRCY3F66CBSX52f8s3pWHZTejX4hKC9h\n  behaviours.py: QmS9sPCv2yBnhWsmHeaCptpApMtYZipbR39TXixeGK64Ks\n  dialogues.py: QmdTW8q1xQ7ajFVsWmuV62ypoT5J2b6Hkyz52LFaWuMEtd\n  handlers.py: QmQnQhSaHPUYaJut8bMe2LHEqiZqokMSVfCthVaqrvPbdi\n  strategy.py: QmYTUsfv64eRQDevCfMUDQPx2GCtiMLFdacN4sS1E4Fdfx\nfingerprint_ignore_patterns: []\nconnections:\n- fetchai/ledger:0.21.5\ncontracts: []\nprotocols:\n- fetchai/default:1.1.7\n- fetchai/fipa:1.1.7\n- fetchai/ledger_api:1.1.7\n- fetchai/oef_search:1.1.7\nskills: []\nbehaviours:\n  service_registration:\n    args:\n      services_interval: 20\n    class_name: GenericServiceRegistrationBehaviour\nhandlers:\n  fipa:\n    args: {}\n    class_name: GenericFipaHandler\n  ledger_api:\n    args: {}\n    class_name: GenericLedgerApiHandler\n  oef_search:\n    args: {}\n    class_name: GenericOefSearchHandler\nmodels:\n  default_dialogues:\n    args: {}\n    class_name: DefaultDialogues\n  fipa_dialogues:\n    args: {}\n    class_name: FipaDialogues\n  ledger_api_dialogues:\n    args: {}\n    class_name: LedgerApiDialogues\n  oef_search_dialogues:\n    args: {}\n    class_name: OefSearchDialogues\n  strategy:\n    args:\n      data_for_sale:\n        generic: data\n      has_data_source: false\n      is_ledger_tx: true\n      location:\n        latitude: 51.5194\n        longitude: 0.127\n      service_data:\n        key: seller_service\n        value: generic_service\n      service_id: generic_service\n      unit_price: 10\n    class_name: GenericStrategy\nis_abstract: false\ndependencies: {}\n```\n\n``` yaml\nname: generic_buyer\nauthor: fetchai\nversion: 0.1.0\ntype: skill\ndescription: The weather client skill implements the skill to purchase weather data.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: QmTR91jm7WfJpmabisy74NR5mc35YXjDU1zQAUKZeHRw8L\n  __init__.py: QmU5vrC8FipyjfS5biNa6qDWdp4aeH5h4YTtbFDmCg8Chj\n  behaviours.py: QmNwvSjEz4kzM3gWtnKbZVFJc2Z85Nb748CWAK4C4Sa4nT\n  dialogues.py: QmNen91qQDWy4bNBKrB3LabAP5iRf29B8iwYss4NB13iNU\n  handlers.py: QmZfudXXbdiREiViuwPZDXoQQyXT2ySQHdF7psQsohZXQy\n  strategy.py: QmcrwaEWvKHDCNti8QjRhB4utJBJn5L8GpD27Uy9zHwKhY\nfingerprint_ignore_patterns: []\nconnections:\n- fetchai/ledger:0.21.5\ncontracts: []\nprotocols:\n- fetchai/default:1.1.7\n- fetchai/fipa:1.1.7\n- fetchai/ledger_api:1.1.7\n- fetchai/oef_search:1.1.7\n- fetchai/signing:1.1.7\nskills: []\nbehaviours:\n  search:\n    args:\n      search_interval: 5\n    class_name: GenericSearchBehaviour\n  transaction:\n    args:\n      max_processing: 420\n      transaction_interval: 2\n    class_name: GenericTransactionBehaviour\nhandlers:\n  fipa:\n    args: {}\n    class_name: GenericFipaHandler\n  ledger_api:\n    args: {}\n    class_name: GenericLedgerApiHandler\n  oef_search:\n    args: {}\n    class_name: GenericOefSearchHandler\n  signing:\n    args: {}\n    class_name: GenericSigningHandler\nmodels:\n  default_dialogues:\n    args: {}\n    class_name: DefaultDialogues\n  fipa_dialogues:\n    args: {}\n    class_name: FipaDialogues\n  ledger_api_dialogues:\n    args: {}\n    class_name: LedgerApiDialogues\n  oef_search_dialogues:\n    args: {}\n    class_name: OefSearchDialogues\n  signing_dialogues:\n    args: {}\n    class_name: SigningDialogues\n  strategy:\n    args:\n      is_ledger_tx: true\n      location:\n        latitude: 51.5194\n        longitude: 0.127\n      max_negotiations: 1\n      max_tx_fee: 3550000000000000\n      max_unit_price: 20\n      min_quantity: 1\n      search_query:\n        constraint_type: ==\n        search_key: seller_service\n        search_value: generic_service\n      search_radius: 5.0\n      service_id: generic_service\n      stop_searching_on_result: true\n    class_name: GenericStrategy\nis_abstract: false\ndependencies: {}\n```\n\n``` yaml\nconfig:\n  delegate_uri: 127.0.0.1:11001\n  entry_peers: ['SOME_ADDRESS']\n  local_uri: 127.0.0.1:9001\n  log_file: libp2p_node.log\n  public_uri: 127.0.0.1:9001\n```\n"
  },
  {
    "path": "tests/test_docs/test_bash_yaml/md_files/bash-generic-skills.md",
    "content": "``` bash\naea fetch fetchai/generic_seller:0.29.5 --alias my_seller_aea\ncd my_seller_aea\naea install\naea build\n```\n\n``` bash\naea create my_seller_aea\ncd my_seller_aea\naea add connection fetchai/p2p_libp2p:0.27.5\naea add connection fetchai/soef:0.27.6\naea add connection fetchai/ledger:0.21.5\naea add skill fetchai/generic_seller:0.28.6\naea config set --type dict agent.dependencies \\\n'{\n  \"aea-ledger-fetchai\": {\"version\": \"<2.0.0,>=1.0.0\"}\n}'\naea config set agent.default_connection fetchai/p2p_libp2p:0.27.5\naea config set --type dict agent.default_routing \\\n'{\n  \"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n  \"fetchai/oef_search:1.1.7\": \"fetchai/soef:0.27.6\"\n}'\naea install\naea build\n```\n\n``` bash\naea fetch fetchai/generic_buyer:0.30.5 --alias my_buyer_aea\ncd my_buyer_aea\naea install\naea build\n```\n\n``` bash\naea create my_buyer_aea\ncd my_buyer_aea\naea add connection fetchai/p2p_libp2p:0.27.5\naea add connection fetchai/soef:0.27.6\naea add connection fetchai/ledger:0.21.5\naea add skill fetchai/generic_buyer:0.27.6\naea config set --type dict agent.dependencies \\\n'{\n  \"aea-ledger-fetchai\": {\"version\": \"<2.0.0,>=1.0.0\"}\n}'\naea config set agent.default_connection fetchai/p2p_libp2p:0.27.5\naea config set --type dict agent.default_routing \\\n'{\n  \"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n  \"fetchai/oef_search:1.1.7\": \"fetchai/soef:0.27.6\"\n}'\naea install\naea build\n```\n\n``` bash\naea generate-key fetchai\naea add-key fetchai fetchai_private_key.txt\n```\n\n``` bash\naea generate-key fetchai fetchai_connection_private_key.txt\naea add-key fetchai fetchai_connection_private_key.txt --connection\n```\n\n``` bash\naea issue-certificates\n```\n\n``` bash\naea generate-key fetchai\naea add-key fetchai fetchai_private_key.txt\naea add-key fetchai fetchai_private_key.txt --connection\n```\n\n``` bash\naea generate-wealth fetchai\n```\n\n``` bash\naea generate-key fetchai fetchai_connection_private_key.txt\naea add-key fetchai fetchai_connection_private_key.txt --connection\n```\n\n``` bash\naea issue-certificates\n```\n\n``` bash\ncd my_seller_aea\naea config set vendor.fetchai.skills.generic_seller.is_abstract false --type bool\n```\n\n``` bash\ncd my_buyer_aea\naea config set vendor.fetchai.skills.generic_buyer.is_abstract false --type bool\n```\n\n``` bash\naea run\n```\n\n``` bash\naea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \\\n'{\n  \"delegate_uri\": \"127.0.0.1:11001\",\n  \"entry_peers\": [\"SOME_ADDRESS\"],\n  \"local_uri\": \"127.0.0.1:9001\",\n  \"log_file\": \"libp2p_node.log\",\n  \"public_uri\": \"127.0.0.1:9001\"\n}'\n```\n\n``` bash\naea run\n```\n\n``` bash\ncd ..\naea delete my_seller_aea\naea delete my_buyer_aea\n```\n\n``` yaml\nmodels:\n  ...\n  strategy:\n    args:\n      currency_id: FET\n      data_for_sale:\n        generic: data\n      has_data_source: false\n      is_ledger_tx: true\n      ledger_id: fetchai\n      location:\n        latitude: 51.5194\n        longitude: 0.127\n      service_data:\n        key: seller_service\n        value: generic_service\n      service_id: generic_service\n      unit_price: 10\n    class_name: GenericStrategy\n```\n\n``` yaml\nmodels:\n  ...\n  strategy:\n    args:\n      currency_id: FET\n      is_ledger_tx: true\n      ledger_id: fetchai\n      location:\n        latitude: 51.5194\n        longitude: 0.127\n      max_negotiations: 1\n      max_tx_fee: 3550000000000000\n      max_unit_price: 20\n      search_query:\n        constraint_type: ==\n        search_key: seller_service\n        search_value: generic_service\n      search_radius: 5.0\n      service_id: generic_service\n    class_name: GenericStrategy\n```\n\n``` yaml\n---\npublic_id: fetchai/p2p_libp2p:0.27.5\ntype: connection\nconfig:\n  delegate_uri: 127.0.0.1:11001\n  entry_peers:\n  - SOME_ADDRESS\n  local_uri: 127.0.0.1:9001\n  log_file: libp2p_node.log\n  public_uri: 127.0.0.1:9001\n```\n"
  },
  {
    "path": "tests/test_docs/test_bash_yaml/md_files/bash-gym-example.md",
    "content": "``` bash\nsvn export https://github.com/fetchai/agents-aea.git/trunk/examples\nsvn export https://github.com/fetchai/agents-aea.git/trunk/packages\n```\n\n``` bash\npip install numpy gym\n```\n\n``` bash\npython examples/gym_ex/train.py\n```\n"
  },
  {
    "path": "tests/test_docs/test_bash_yaml/md_files/bash-gym-skill.md",
    "content": "``` bash\nmkdir gym_skill_agent\nsvn export https://github.com/fetchai/agents-aea.git/trunk/examples\n```\n\n``` bash\npip install numpy gym\n```\n\n``` bash\naea fetch fetchai/gym_aea:0.26.5 --alias my_gym_aea\ncd my_gym_aea\naea install\n```\n\n``` bash\naea create my_gym_aea\ncd my_gym_aea\n```\n\n``` bash\naea add skill fetchai/gym:0.21.6\n```\n\n``` bash\naea config set agent.default_connection fetchai/gym:0.20.6\n```\n\n``` bash\naea install\n```\n\n``` bash\nmkdir gyms\ncp -a ../examples/gym_ex/gyms/. gyms/\n```\n\n``` bash\naea config set vendor.fetchai.connections.gym.config.env 'gyms.env.BanditNArmedRandom'\n```\n\n``` bash\naea generate-key fetchai\naea add-key fetchai\n```\n\n``` bash\naea run\n```\n\n``` bash\ncd ..\naea delete my_gym_aea\n```\n"
  },
  {
    "path": "tests/test_docs/test_bash_yaml/md_files/bash-http-connection-and-skill.md",
    "content": "``` bash\naea create my_aea\ncd my_aea\n```\n\n``` bash\naea add connection fetchai/http_server:0.23.6\n```\n\n``` bash\naea config set agent.default_connection fetchai/http_server:0.23.6\n```\n\n``` bash\naea config set vendor.fetchai.connections.http_server.config.api_spec_path \"../examples/http_ex/petstore.yaml\"\n```\n\n``` bash\naea generate-key fetchai\naea add-key fetchai\n```\n\n``` bash\naea install\n```\n\n``` bash\naea scaffold skill http_echo\n```\n\n``` bash\naea fingerprint skill fetchai/http_echo:0.21.6\n```\n\n``` bash\naea config set vendor.fetchai.connections.http_server.config.target_skill_id \"$(aea config get agent.author)/http_echo:0.1.0\" \n```\n\n``` bash\naea run\n```\n\n``` yaml\nhandlers:\n  http_handler:\n    args: {}\n    class_name: HttpHandler\nmodels:\n  default_dialogues:\n    args: {}\n    class_name: DefaultDialogues\n  http_dialogues:\n    args: {}\n    class_name: HttpDialogues\n```\n"
  },
  {
    "path": "tests/test_docs/test_bash_yaml/md_files/bash-language-agnostic-definition.md",
    "content": "``` proto\nsyntax = \"proto3\";\n\npackage aea;\n\nmessage Envelope{\n    string to = 1;\n    string sender = 2;\n    string protocol_id = 3;\n    bytes message = 4;\n    string uri = 5;\n}\n```\n\n``` proto\nimport \"google/protobuf/struct.proto\";\n\nmessage DialogueMessage {\n    int32 message_id = 1;\n    string dialogue_starter_reference = 2;\n    string dialogue_responder_reference = 3;\n    int32 target = 4;\n    bytes content = 5;\n}\n\nmessage Message {\n    oneof message {\n        google.protobuf.Struct body = 1;\n        DialogueMessage dialogue_message = 2;\n    }\n}\n```\n\n``` proto\nsyntax = \"proto3\";\n\npackage aea.fetchai.default;\n\nmessage DefaultMessage{\n\n    // Custom Types\n    message ErrorCode{\n        enum ErrorCodeEnum {\n            UNSUPPORTED_PROTOCOL = 0;\n            DECODING_ERROR = 1;\n            INVALID_MESSAGE = 2;\n            UNSUPPORTED_SKILL = 3;\n            INVALID_DIALOGUE = 4;\n          }\n        ErrorCodeEnum error_code = 1;\n    }\n\n\n    // Performatives and contents\n    message Bytes_Performative{\n        bytes content = 1;\n    }\n\n    message Error_Performative{\n        ErrorCode error_code = 1;\n        string error_msg = 2;\n        map<string, bytes> error_data = 3;\n    }\n\n    message End_Performative{}\n\n\n    oneof performative{\n        Bytes_Performative bytes = 5;\n        End_Performative end = 6;\n        Error_Performative error = 7;\n    }\n}\n```\n"
  },
  {
    "path": "tests/test_docs/test_bash_yaml/md_files/bash-ledger-integration.md",
    "content": "``` bash\ngit clone https://github.com/fetchai/fetchd.git\ncd fetchd\ngit checkout release/v0.8.4\nmake install\n```\n"
  },
  {
    "path": "tests/test_docs/test_bash_yaml/md_files/bash-logging.md",
    "content": "``` bash\naea create my_aea\ncd my_aea\n```\n\n``` yaml\nagent_name: my_aea\nauthor: fetchai\nversion: 0.1.0\ndescription: ''\nlicense: Apache-2.0\naea_version: 0.6.0\nfingerprint: {}\nfingerprint_ignore_patterns: []\nconnections:\n- fetchai/stub:0.21.3\ncontracts: []\nprotocols:\n- fetchai/default:1.1.7\nskills:\n- fetchai/error:0.18.6\ndefault_connection: fetchai/stub:0.21.3\ndefault_ledger: fetchai\nrequired_ledgers:\n- fetchai\nlogging_config:\n  disable_existing_loggers: false\n  version: 1\nprivate_key_paths: {}\n```\n\n``` yaml\nlogging_config:\n  version: 1\n  disable_existing_loggers: False\n  formatters:\n    standard:\n      format: '%(asctime)s [%(levelname)s] %(name)s: %(message)s'\n  handlers:\n    logfile:\n      class: logging.FileHandler\n      formatter: standard\n      level: DEBUG\n      filename: logconfig.log\n    console:\n      class: logging.StreamHandler\n      formatter: standard\n      level: DEBUG\n  loggers:\n    aea:\n      handlers:\n      - logfile\n      - console\n      level: DEBUG\n      propagate: False\n```\n\n``` yaml\nlogging_config:\n  version: 1\n  disable_existing_loggers: false\n  formatters:\n    standard:\n      format: '%(asctime)s [%(levelname)s] %(name)s: %(message)s'\n  handlers:\n    http:\n      class: logging.handlers.HTTPHandler\n      formatter: standard\n      level: INFO\n      host: localhost:5000\n      url: /stream\n      method: POST\n  loggers:\n    aea:\n      handlers:\n      - http\n      level: INFO\n      propagate: false\n```\n"
  },
  {
    "path": "tests/test_docs/test_bash_yaml/md_files/bash-ml-skills.md",
    "content": "``` bash\n{\n  \"delegate_uri\": \"127.0.0.1:11001\",\n  \"entry_peers\": [\"REPLACE_WITH_MULTI_ADDRESS_HERE\"],\n  \"local_uri\": \"127.0.0.1:9001\",\n  \"log_file\": \"libp2p_node.log\",\n  \"public_uri\": \"127.0.0.1:9001\"\n}\n```\n\n``` bash\naea fetch fetchai/ml_data_provider:0.32.5\ncd ml_data_provider\naea install\naea build\n```\n\n``` bash\naea create ml_data_provider\ncd ml_data_provider\naea add connection fetchai/p2p_libp2p:0.27.5\naea add connection fetchai/soef:0.27.6\naea add connection fetchai/ledger:0.21.5\naea add skill fetchai/ml_data_provider:0.27.6\naea config set --type dict agent.dependencies \\\n'{\n  \"aea-ledger-fetchai\": {\"version\": \"<2.0.0,>=1.0.0\"}\n}'\naea config set agent.default_connection fetchai/p2p_libp2p:0.27.5\naea config set --type dict agent.default_routing \\\n'{\n  \"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n  \"fetchai/oef_search:1.1.7\": \"fetchai/soef:0.27.6\"\n}'\naea install\naea build\n```\n\n``` bash\naea fetch fetchai/ml_model_trainer:0.33.5\ncd ml_model_trainer\naea install\naea build\n```\n\n``` bash\naea create ml_model_trainer\ncd ml_model_trainer\naea add connection fetchai/p2p_libp2p:0.27.5\naea add connection fetchai/soef:0.27.6\naea add connection fetchai/ledger:0.21.5\naea add skill fetchai/ml_train:0.29.6\naea config set --type dict agent.dependencies \\\n'{\n  \"aea-ledger-fetchai\": {\"version\": \"<2.0.0,>=1.0.0\"}\n}'\naea config set agent.default_connection fetchai/p2p_libp2p:0.27.5\naea config set --type dict agent.default_routing \\\n'{\n  \"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n  \"fetchai/oef_search:1.1.7\": \"fetchai/soef:0.27.6\"\n}'\naea install\naea build\n```\n\n``` bash\naea generate-key fetchai\naea add-key fetchai fetchai_private_key.txt\n```\n\n``` bash\naea generate-key fetchai fetchai_connection_private_key.txt\naea add-key fetchai fetchai_connection_private_key.txt --connection\n```\n\n``` bash\naea issue-certificates\n```\n\n``` bash\naea generate-key fetchai\naea add-key fetchai fetchai_private_key.txt\naea add-key fetchai fetchai_private_key.txt --connection\n```\n\n``` bash\naea generate-wealth fetchai\n```\n\n``` bash\naea generate-key fetchai fetchai_connection_private_key.txt\naea add-key fetchai fetchai_connection_private_key.txt --connection\n```\n\n``` bash\naea issue-certificates\n```\n\n``` bash\naea run\n```\n\n``` bash\naea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \\\n'{\n  \"delegate_uri\": \"127.0.0.1:11001\",\n  \"entry_peers\": [\"SOME_ADDRESS\"],\n  \"local_uri\": \"127.0.0.1:9001\",\n  \"log_file\": \"libp2p_node.log\",\n  \"public_uri\": \"127.0.0.1:9001\"\n}'\n```\n\n``` bash\naea run\n```\n\n``` bash\ncd ..\naea delete ml_data_provider\naea delete ml_model_trainer\n```\n\n``` yaml\n---\npublic_id: fetchai/p2p_libp2p:0.27.5\ntype: connection\nconfig:\n  delegate_uri: 127.0.0.1:11001\n  entry_peers:\n  - SOME_ADDRESS\n  local_uri: 127.0.0.1:9001\n  log_file: libp2p_node.log\n  public_uri: 127.0.0.1:9001\n```\n"
  },
  {
    "path": "tests/test_docs/test_bash_yaml/md_files/bash-oracle-demo.md",
    "content": "``` bash\naea fetch fetchai/coin_price_oracle:0.17.6\ncd coin_price_oracle\naea install\n```\n\n``` bash\naea create coin_price_oracle\ncd coin_price_oracle\naea add connection fetchai/http_client:0.24.6\naea add connection fetchai/ledger:0.21.5\naea add connection fetchai/prometheus:0.9.6\naea add skill fetchai/advanced_data_request:0.7.6\naea add skill fetchai/simple_oracle:0.16.5\naea config set --type dict agent.dependencies \\\n'{\n  \"aea-ledger-fetchai\": {\"version\": \"<2.0.0,>=1.0.0\"},\n  \"aea-ledger-ethereum\": {\"version\": \"<2.0.0,>=1.0.0\"}\n}'\naea config set agent.default_connection fetchai/ledger:0.21.5\naea install\n```\n\n``` bash\naea config set --type str vendor.fetchai.skills.advanced_data_request.models.advanced_data_request_model.args.url \"https://api.coingecko.com/api/v3/simple/price?ids=fetch-ai&vs_currencies=usd\"\n```\n\n``` bash\naea config set --type list vendor.fetchai.skills.advanced_data_request.models.advanced_data_request_model.args.outputs '[{\"name\": \"price\", \"json_path\": \"fetch-ai.usd\"}]'\n```\n\n``` bash\naea config set vendor.fetchai.skills.simple_oracle.models.strategy.args.oracle_value_name price\n```\n\n``` bash\naea config set --type dict agent.default_routing \\\n'{\n\"fetchai/contract_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n\"fetchai/http:1.1.7\": \"fetchai/http_client:0.24.6\",\n\"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\"\n}'\n```\n\n``` bash\naea config set agent.default_ledger fetchai\n```\n\n``` bash\naea config set vendor.fetchai.skills.simple_oracle.models.strategy.args.ledger_id fetchai\naea config set vendor.fetchai.skills.simple_oracle.models.strategy.args.update_function update_oracle_value\n```\n\n``` bash\nLEDGER_ID=fetchai\n```\n\n``` bash\nLEDGER_ID=ethereum\n```\n\n``` bash\naea config set agent.default_ledger ethereum\n```\n\n``` bash\naea config set vendor.fetchai.skills.simple_oracle.models.strategy.args.ledger_id ethereum\naea config set vendor.fetchai.skills.simple_oracle.models.strategy.args.update_function updateOracleValue\n```\n\n``` bash\naea generate-key $LEDGER_ID --add-key\n```\n\n``` bash\naea generate-wealth $LEDGER_ID\n```\n\n``` bash\naea fetch fetchai/coin_price_oracle_client:0.12.6\ncd coin_price_oracle_client\naea install\n```\n\n``` bash\naea create coin_price_oracle_client\ncd coin_price_oracle_client\naea add connection fetchai/http_client:0.24.6\naea add connection fetchai/ledger:0.21.5\naea add skill fetchai/simple_oracle_client:0.13.5\naea config set --type dict agent.dependencies \\\n'{\n  \"aea-ledger-fetchai\": {\"version\": \"<2.0.0,>=1.0.0\"},\n  \"aea-ledger-ethereum\": {\"version\": \"<2.0.0,>=1.0.0\"}\n}'\naea config set agent.default_connection fetchai/ledger:0.21.5\naea install\n```\n\n``` bash\naea config set --type dict agent.default_routing \\\n'{\n\"fetchai/contract_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n\"fetchai/http:1.1.7\": \"fetchai/http_client:0.24.6\",\n\"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\"\n}'\n```\n\n``` bash\naea config set agent.default_ledger fetchai\n```\n\n``` bash\naea config set vendor.fetchai.skills.simple_oracle_client.models.strategy.args.ledger_id fetchai\naea config set vendor.fetchai.skills.simple_oracle_client.models.strategy.args.query_function query_oracle_value\n```\n\n``` bash\naea config set agent.default_ledger ethereum\n```\n\n``` bash\naea config set vendor.fetchai.skills.simple_oracle_client.models.strategy.args.ledger_id ethereum\naea config set vendor.fetchai.skills.simple_oracle_client.models.strategy.args.query_function queryOracleValue\n```\n\n``` bash\naea generate-key $LEDGER_ID --add-key\n```\n\n``` bash\naea generate-wealth $LEDGER_ID\n```\n\n``` bash\ndocker run -p 8545:8545 trufflesuite/ganache-cli:latest --verbose --gasPrice=0 --gasLimit=0x1fffffffffffff --account=\"$(cat coin_price_oracle/ethereum_private_key.txt),1000000000000000000000\" --account=\"$(cat coin_price_oracle_client/ethereum_private_key.txt),1000000000000000000000\"\n```\n\n``` bash\naea config set vendor.fetchai.skills.simple_oracle.models.strategy.args.erc20_address $ERC20_ADDRESS\n```\n\n``` bash\naea config set vendor.fetchai.skills.simple_oracle_client.models.strategy.args.erc20_address $ERC20_ADDRESS\n```\n\n``` bash\naea run\n```\n\n``` bash\ninfo: [coin_price_oracle] Oracle contract successfully deployed at address: ...\n...\ninfo: [coin_price_oracle] Oracle role successfully granted!\n...\ninfo: [coin_price_oracle] Oracle value successfully updated!\n```\n\n``` bash\naea config set vendor.fetchai.skills.simple_oracle_client.models.strategy.args.oracle_contract_address $ORACLE_ADDRESS\n```\n\n``` bash\nOracle contract successfully deployed at address: ORACLE_ADDRESS\n```\n\n``` bash\naea run\n```\n\n``` bash\ninfo: [coin_price_oracle_client] Oracle client contract successfully deployed at address: ...\n...\ninfo: [coin_price_oracle_client] Oracle value successfully requested!\n```\n"
  },
  {
    "path": "tests/test_docs/test_bash_yaml/md_files/bash-orm-integration.md",
    "content": "``` bash\naea fetch fetchai/thermometer_aea:0.30.5 --alias my_thermometer_aea\ncd my_thermometer_aea\naea install\naea build\n```\n\n``` bash\naea create my_thermometer_aea\ncd my_thermometer_aea\naea add connection fetchai/p2p_libp2p:0.27.5\naea add connection fetchai/soef:0.27.6\naea add connection fetchai/ledger:0.21.5\naea add skill fetchai/thermometer:0.27.6\naea config set --type dict agent.dependencies \\\n'{\n  \"aea-ledger-fetchai\": {\"version\": \"<2.0.0,>=1.0.0\"}\n}'\naea config set agent.default_connection fetchai/p2p_libp2p:0.27.5\naea config set --type dict agent.default_routing \\\n'{\n  \"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n  \"fetchai/oef_search:1.1.7\": \"fetchai/soef:0.27.6\"\n}'\naea install\naea build\n```\n\n``` bash\naea fetch fetchai/thermometer_client:0.32.5 --alias my_thermometer_client\ncd my_thermometer_client\naea install\naea build\n```\n\n``` bash\naea create my_thermometer_client\ncd my_thermometer_client\naea add connection fetchai/p2p_libp2p:0.27.5\naea add connection fetchai/soef:0.27.6\naea add connection fetchai/ledger:0.21.5\naea add skill fetchai/thermometer_client:0.26.6\naea config set --type dict agent.dependencies \\\n'{\n  \"aea-ledger-fetchai\": {\"version\": \"<2.0.0,>=1.0.0\"}\n}'\naea config set agent.default_connection fetchai/p2p_libp2p:0.27.5\naea config set --type dict agent.default_routing \\\n'{\n  \"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n  \"fetchai/oef_search:1.1.7\": \"fetchai/soef:0.27.6\"\n}'\naea install\naea build\n```\n\n``` bash\naea generate-key fetchai\naea add-key fetchai fetchai_private_key.txt\n```\n\n``` bash\naea generate-key fetchai fetchai_connection_private_key.txt\naea add-key fetchai fetchai_connection_private_key.txt --connection\n```\n\n``` bash\naea issue-certificates\n```\n\n``` bash\naea generate-key fetchai\naea add-key fetchai fetchai_private_key.txt\n```\n\n``` bash\naea generate-key fetchai fetchai_connection_private_key.txt\naea add-key fetchai fetchai_connection_private_key.txt --connection\n```\n\n``` bash\naea issue-certificates\n```\n\n``` bash\naea generate-wealth fetchai\n```\n\n``` bash\naea install\naea build\n```\n\n``` bash\naea eject skill fetchai/thermometer:0.27.6\n```\n\n``` bash\naea fingerprint skill {YOUR_AUTHOR_HANDLE}/thermometer:0.1.0\n```\n\n``` bash\naea run\n```\n\n``` bash\naea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \\\n'{\n  \"delegate_uri\": \"127.0.0.1:11001\",\n  \"entry_peers\": [\"SOME_ADDRESS\"],\n  \"local_uri\": \"127.0.0.1:9001\",\n  \"log_file\": \"libp2p_node.log\",\n  \"public_uri\": \"127.0.0.1:9001\"\n}'\n```\n\n``` bash\naea run\n```\n\n``` bash\ncd ..\naea delete my_thermometer_aea\naea delete my_thermometer_client\n```\n\n``` yaml\nmodels:\n  ...\n  strategy:\n    args:\n      currency_id: FET\n      data_for_sale:\n        temperature: 26\n      has_data_source: false\n      is_ledger_tx: true\n      ledger_id: fetchai\n      location:\n        latitude: 51.5194\n        longitude: 0.127\n      service_data:\n        key: seller_service\n        value: thermometer_data\n      service_id: thermometer_data\n      unit_price: 10\n    class_name: Strategy\ndependencies:\n  SQLAlchemy: {}\n```\n\n``` yaml\nmodels:\n  ...\n  strategy:\n    args:\n      currency_id: FET\n      is_ledger_tx: true\n      ledger_id: fetchai\n      location:\n        latitude: 51.5194\n        longitude: 0.127\n      max_negotiations: 1\n      max_tx_fee: 3550000000000000\n      max_unit_price: 20\n      search_query:\n        constraint_type: ==\n        search_key: seller_service\n        search_value: thermometer_data\n      search_radius: 5.0\n      service_id: thermometer_data\n    class_name: Strategy\n```\n\n``` yaml\n---\npublic_id: fetchai/p2p_libp2p:0.27.5\ntype: connection\nconfig:\n  delegate_uri: 127.0.0.1:11001\n  entry_peers:\n  - SOME_ADDRESS\n  local_uri: 127.0.0.1:9001\n  log_file: libp2p_node.log\n  public_uri: 127.0.0.1:9001\n```\n"
  },
  {
    "path": "tests/test_docs/test_bash_yaml/md_files/bash-p2p-connection.md",
    "content": "``` bash\npip install aea-ledger-fetchai\n```\n\n``` bash\naea create my_genesis_aea\ncd my_genesis_aea\naea add connection fetchai/p2p_libp2p:0.27.5\naea config set agent.default_connection fetchai/p2p_libp2p:0.27.5\naea install\naea build\n```\n\n``` bash\naea generate-key fetchai\naea add-key fetchai fetchai_private_key.txt\naea generate-key fetchai fetchai_connection_private_key.txt\naea add-key fetchai fetchai_connection_private_key.txt --connection\naea issue-certificates\n```\n\n``` bash\naea run --connections fetchai/p2p_libp2p:0.27.5\n```\n\n``` bash\naea create my_other_aea\ncd my_other_aea\naea add connection fetchai/p2p_libp2p:0.27.5\naea config set agent.default_connection fetchai/p2p_libp2p:0.27.5\naea install\naea build\n```\n\n``` bash\naea generate-key fetchai\naea add-key fetchai fetchai_private_key.txt\naea generate-key fetchai fetchai_connection_private_key.txt\naea add-key fetchai fetchai_connection_private_key.txt --connection\naea issue-certificates\n```\n\n``` bash\naea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \\\n'{\n  \"delegate_uri\": \"127.0.0.1:11001\",\n  \"entry_peers\": [\"SOME_ADDRESS\"],\n  \"local_uri\": \"127.0.0.1:9001\",\n  \"log_file\": \"libp2p_node.log\",\n  \"public_uri\": \"127.0.0.1:9001\"\n}'\n```\n\n``` bash\naea run --connections fetchai/p2p_libp2p:0.27.5\n```\n\n``` bash\nsvn export https://github.com/fetchai/agents-aea.git/trunk/packages/fetchai/connections/p2p_libp2p\ncd p2p_libp2p\ngo build\nchmod +x libp2p_node\n```\n\n``` bash\ndocker build -t acn_node_standalone -f scripts/acn/Dockerfile .\n```\n\n``` bash\npython3 run_acn_node_standalone.py libp2p_node --config-from-env\n```\n\n``` bash\npython3 run_acn_node_standalone.py libp2p_node --config-from-file <env-file-path>\n```\n\n``` bash\ndocker run -v <acn_config_file>:/acn/acn_config -it acn_node_standalone --config-from-file /acn/acn_config\n```\n\n``` bash\npython3 run_acn_node_standalone.py libp2p_node --key-file <node_private_key.txt> \\\n  --uri <AEA_P2P_URI> --uri-external <AEA_P2P_URI_PUBLIC>  \\\n  --uri-delegate <AEA_P2P_DELEGATE_URI> \\\n  --entry-peers-maddrs <AEA_P2P_ENTRY_URI_1> <AEA_P2P_ENTRY_URI_2> ...\n```\n\n``` bash\ndocker run -v <node_private_key.txt>:/acn/key.txt -it acn_node_standalone --key-file /acn/key.txt \\\n  --uri <AEA_P2P_URI> --uri-external <AEA_P2P_URI_PUBLIC>  \\\n  --uri-delegate <AEA_P2P_DELEGATE_URI> \\\n  --entry-peers-maddrs <AEA_P2P_ENTRY_URI_1> <AEA_P2P_ENTRY_URI_2> ...\n```\n\n``` yaml\n/dns4/acn.fetch.ai/tcp/9000/p2p/16Uiu2HAkw1ypeQYQbRFV5hKUxGRHocwU5ohmVmCnyJNg36tnPFdx\n/dns4/acn.fetch.ai/tcp/9001/p2p/16Uiu2HAmVWnopQAqq4pniYLw44VRvYxBUoRHqjz1Hh2SoCyjbyRW\n```\n\n``` yaml\n---\npublic_id: fetchai/p2p_libp2p:0.27.5\ntype: connection\nconfig:\n  delegate_uri: null\n  entry_peers: [/dns4/acn.fetch.ai/tcp/9000/p2p/16Uiu2HAkw1ypeQYQbRFV5hKUxGRHocwU5ohmVmCnyJNg36tnPFdx,/dns4/acn.fetch.ai/tcp/9001/p2p/16Uiu2HAmVWnopQAqq4pniYLw44VRvYxBUoRHqjz1Hh2SoCyjbyRW]\n  public_uri: null\n  local_uri: 127.0.0.1:9001\n```\n"
  },
  {
    "path": "tests/test_docs/test_bash_yaml/md_files/bash-package-imports.md",
    "content": "``` bash\naea_name/\n  aea-config.yaml       YAML configuration of the AEA\n  fetchai_private_key.txt   The private key file\n  connections/          Directory containing all the connections developed as part of the given project.\n    connection_1/       First connection\n    ...                 ...\n    connection_n/       nth connection\n  contracts/            Directory containing all the contracts developed as part of the given project.\n    connection_1/       First connection\n    ...                 ...\n    connection_n/       nth connection\n  protocols/            Directory containing all the protocols developed as part of the given project.\n    protocol_1/         First protocol\n    ...                 ...\n    protocol_m/         mth protocol\n  skills/               Directory containing all the skills developed as part of the given project.\n    skill_1/            First skill\n    ...                 ...\n    skill_k/            kth skill\n  vendor/               Directory containing all the added resources from the registry, sorted by author.\n    author_1/           Directory containing all the resources added from author_1\n      connections/      Directory containing all the added connections from author_1\n        ...             ...\n      protocols/        Directory containing all the added protocols from author_1\n        ...             ...\n      skills/           Directory containing all the added skills from author_1\n        ...             ...\n```\n\n``` yaml\nconnections:\n- fetchai/stub:0.21.3\n```\n"
  },
  {
    "path": "tests/test_docs/test_bash_yaml/md_files/bash-performance-benchmark.md",
    "content": "``` bash\nUsage: cpu_burn.py [OPTIONS] [ARGS]...\n\n       Do nothing, just burn cpu to check cpu load changed on sleep.\n\n  :param benchmark: benchmark special parameter to communicate with executor\n  :param run_time: time limit to run this function :param sleep: time to sleep in loop\n\n  :return: None\n\n      ARGS is function arguments in format: `run_time,sleep`\n\n      default ARGS is `10,0.0001`\n\nOptions:\n  --timeout FLOAT               Executor timeout in seconds  [default: 10.0]\n  --period FLOAT                Period for measurement  [default: 0.1]\n  -N, --num-executions INTEGER  Number of runs for each case  [default: 1]\n  -P, --plot INTEGER            X axis parameter idx\n  --help                        Show this message and exit.\n```\n\n``` bash\nTest execution timeout: 10.0\nTest execution measure period: 0.1\nTested function name: cpu_burn\nTested function description:\n    Do nothing, just burn cpu to check cpu load changed on sleep.\n\n    :param benchmark: benchmark special parameter to communicate with executor\n    :param run_time: time limit to run this function\n    :param sleep: time to sleep in loop\n\n    :return: None\n\nTested function argument names: ['run_time', 'sleep']\nTested function argument default values: [10, 0.0001]\n\n== Report created 2020-04-27 15:14:56.076549 ==\nArguments are `[10, 0.0001]`\nNumber of runs: 1\nNumber of time terminated: 0\nTime passed (seconds): 10.031443119049072 ± 0\ncpu min (%): 0.0 ± 0\ncpu max (%): 10.0 ± 0\ncpu mean (%): 3.4 ± 0\nmem min (kb): 53.98828125 ± 0\nmem max (kb): 53.98828125 ± 0\nmem mean (kb): 53.98828125 ± 0\n```\n\n``` bash\nTest execution timeout: 10.0\nTest execution measure period: 0.1\nTested function name: cpu_burn\nTested function description:\n    Do nothing, just burn cpu to check cpu load changed on sleep.\n\n    :param benchmark: benchmark special parameter to communicate with executor\n    :param run_time: time limit to run this function\n    :param sleep: time to sleep in loop\n\n    :return: None\n\nTested function argument names: ['run_time', 'sleep']\nTested function argument default values: [10, 0.0001]\n\n== Report created 2020-04-27 15:38:17.849535 ==\nArguments are `(3, 1e-05)`\nNumber of runs: 5\nNumber of time terminated: 0\nTime passed (seconds): 3.0087939262390138 ± 0.0001147521277690166\ncpu min (%): 0.0 ± 0.0\ncpu max (%): 11.0 ± 2.23606797749979\ncpu mean (%): 6.2 ± 0.18257418583505522\nmem min (kb): 54.0265625 ± 0.11180339887498948\nmem max (kb): 54.0265625 ± 0.11180339887498948\nmem mean (kb): 54.0265625 ± 0.11180339887498948\n== Report created 2020-04-27 15:38:32.947308 ==\nArguments are `(3, 0.001)`\nNumber of runs: 5\nNumber of time terminated: 0\nTime passed (seconds): 3.014109659194946 ± 0.0004416575764579524\ncpu min (%): 0.0 ± 0.0\ncpu max (%): 8.0 ± 2.7386127875258306\ncpu mean (%): 1.9986666666666666 ± 0.002981423969999689\nmem min (kb): 53.9890625 ± 0.10431954926750306\nmem max (kb): 53.9890625 ± 0.10431954926750306\nmem mean (kb): 53.9890625 ± 0.10431954926750306\n== Report created 2020-04-27 15:38:48.067511 ==\nArguments are `(3, 0.01)`\nNumber of runs: 5\nNumber of time terminated: 0\nTime passed (seconds): 3.0181806087493896 ± 0.0022409499756841883\ncpu min (%): 0.0 ± 0.0\ncpu max (%): 1.0 ± 2.23606797749979\ncpu mean (%): 0.06666666666666667 ± 0.14907119849998599\nmem min (kb): 53.9078125 ± 0.11487297672320501\nmem max (kb): 53.9078125 ± 0.11487297672320501\nmem mean (kb): 53.9078125 ± 0.11487297672320501\n```\n"
  },
  {
    "path": "tests/test_docs/test_bash_yaml/md_files/bash-por.md",
    "content": "``` yaml\ncert_requests:\n- identifier: acn\n  ledger_id: fetchai\n  not_after: '2023-01-01'\n  not_before: '2022-01-01'\n  public_key: fetchai\n  message_format: '{public_key}'\n  save_path: .certs/conn_cert.txt\n```\n"
  },
  {
    "path": "tests/test_docs/test_bash_yaml/md_files/bash-protocol-generator.md",
    "content": "``` bash\naea generate protocol <path-to-protocol-specification>\n```\n\n``` bash\naea generate protocol --l <language> <path-to-protocol-specification>\n```\n\n``` bash\naea create my_aea\ncd my_aea\n```\n\n``` bash\naea generate protocol ../examples/protocol_specification_ex/sample.yaml\n```\n\n``` yaml\n---\nname: two_party_negotiation\nauthor: fetchai\nversion: 0.1.0\ndescription: An example of a protocol specification that describes a protocol for bilateral negotiation.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nspeech_acts:\n  cfp:\n    query: ct:Query\n  propose:\n    price: pt:float\n    proposal: pt:dict[pt:str, pt:str]\n    conditions: pt:optional[pt:union[pt:str, pt:dict[pt:str,pt:str], pt:set[pt:str]]]\n    resources: pt:list[pt:bytes]\n  accept: {}\n  decline: {}\n...\n---\nct:Query: |\n  bytes query_bytes = 1;\n...\n---\ninitiation: [cfp]\nreply:\n  cfp: [propose, decline]\n  propose: [propose, accept, decline]\n  accept: []\n  decline: []\ntermination: [accept, decline]\nroles: {buyer, seller}\nend_states: [agreement_reached, agreement_unreached]\nkeep_terminal_state_dialogues: true\n...\n```\n"
  },
  {
    "path": "tests/test_docs/test_bash_yaml/md_files/bash-quickstart.md",
    "content": "``` bash\npython3 --version\n```\n\n``` bash\nsudo apt-get install python3.7-dev\n```\n\n``` bash\ncurl https://raw.githubusercontent.com/fetchai/agents-aea/main/scripts/install.sh --output install.sh\nchmod +x install.sh\n./install.sh\n```\n\n```bash\ndocker pull fetchai/aea-user:latest\n```\n\n```bash\ndocker run -it -v $(pwd):/agents --workdir=/agents fetchai/aea-user:latest \n```\n\n```bash\ndocker run -it -v %cd%:/agents --workdir=/agents fetchai/aea-user:latest \n```\n\n``` bash\nmkdir my_aea_projects/\ncd my_aea_projects/\n```\n\n``` bash\nwhich pipenv\n```\n\n``` bash\ntouch Pipfile && pipenv --python 3.7 && pipenv shell\n```\n\n``` bash\nsvn export https://github.com/fetchai/agents-aea.git/trunk/examples\nsvn export https://github.com/fetchai/agents-aea.git/trunk/scripts\nsvn export https://github.com/fetchai/agents-aea.git/trunk/packages\n```\n\n``` bash\npip install aea[all]\n```\n\n``` bash\nsudo apt-get install python3.7-dev\n```\n\n``` bash\naea init\n```\n\n``` bash\naea register\n```\n\n``` bash\nDo you have a Registry account? [y/N]: n\nCreate a new account on the Registry now:\nUsername: fetchai\nEmail: hello@fetch.ai\nPassword:\nPlease make sure that passwords are equal.\nConfirm password:\n    _     _____     _\n   / \\   | ____|   / \\\n  / _ \\  |  _|    / _ \\\n / ___ \\ | |___  / ___ \\\n/_/   \\_\\|_____|/_/   \\_\\\n\nv1.2.5\n\nAEA configurations successfully initialized: {'author': 'fetchai'}\n```\n\n``` bash\naea fetch fetchai/my_first_aea:0.28.5\ncd my_first_aea\n```\n\n``` bash\naea create my_first_aea\ncd my_first_aea\n```\n\n``` bash\naea add connection fetchai/stub:0.21.3\n```\n\n``` bash\naea add skill fetchai/echo:0.20.6\n```\n\n``` bash\nTO,SENDER,PROTOCOL_ID,ENCODED_MESSAGE,\n```\n\n``` bash\nrecipient_aea,sender_aea,fetchai/default:1.0.0,\\x08\\x01\\x12\\x011*\\x07\\n\\x05hello,\n```\n\n``` bash\naea install\n```\n\n``` bash\naea generate-key fetchai\naea add-key fetchai\n```\n\n``` bash\naea run\n```\n\n``` bash\n    _     _____     _\n   / \\   | ____|   / \\\n  / _ \\  |  _|    / _ \\\n / ___ \\ | |___  / ___ \\\n/_/   \\_\\|_____|/_/   \\_\\\n\nv1.1.1\n\nStarting AEA 'my_first_aea' in 'async' mode ...\ninfo: Echo Handler: setup method called.\ninfo: Echo Behaviour: setup method called.\ninfo: [my_first_aea]: Start processing messages...\ninfo: Echo Behaviour: act method called.\ninfo: Echo Behaviour: act method called.\ninfo: Echo Behaviour: act method called.\n...\n```\n\n``` bash\ncd my_first_aea\naea interact\n```\n\n``` bash\ninfo: Echo Behaviour: act method called.\ninfo: Echo Handler: message=Message(dialogue_reference=('1', '') message_id=1 target=0 performative=bytes content=b'hello'), sender=my_first_aea_interact\ninfo: Echo Behaviour: act method called.\ninfo: Echo Behaviour: act method called.\n```\n\n``` bash\necho 'my_first_aea,sender_aea,fetchai/default:1.0.0,\\x12\\x10\\x08\\x01\\x12\\x011*\\t*\\x07\\n\\x05hello,' >> input_file\n```\n\n``` bash\ninfo: Echo Behaviour: act method called.\nEcho Handler: message=Message(sender=sender_aea,to=my_first_aea,content=b'hello',dialogue_reference=('1', ''),message_id=1,performative=bytes,target=0), sender=sender_aea\ninfo: Echo Behaviour: act method called.\ninfo: Echo Behaviour: act method called.\n```\n\n``` bash\ninfo: Echo Behaviour: act method called.\ninfo: Echo Behaviour: act method called.\n^C my_first_aea interrupted!\nmy_first_aea stopping ...\ninfo: Echo Handler: teardown method called.\ninfo: Echo Behaviour: teardown method called.\n```\n\n``` bash\naea interact\n```\n\n``` bash\npytest test.py\n```\n\n``` bash\naea delete my_first_aea\n```\n"
  },
  {
    "path": "tests/test_docs/test_bash_yaml/md_files/bash-raspberry-set-up.md",
    "content": "``` bash\nsudo apt update -y \nsudo apt-get update\nsudo apt-get dist-upgrade \n```\n\n``` bash\nsudo apt install cmake golang -y\n```\n\n``` bash\nsudo apt install gfortran libatlas-base-dev libopenblas-dev -y\n```\n\n``` bash\nsudo /bin/dd if=/dev/zero of=/var/swap.1 bs=1M count=1024\nsudo /sbin/mkswap /var/swap.1\nsudo chmod 600 /var/swap.1\nsudo /sbin/swapon /var/swap.1\n```\n\n``` bash\npip install numpy --upgrade\npip install scikit-image\n```\n\n``` bash\nsudo swapoff /var/swap.1\nsudo rm /var/swap.1\n```\n\n``` bash\nexport PATH=\"$HOME/.local/bin:$PATH\"\n```\n\n``` bash\npip install aea[all]\n```\n\n``` bash\naea --version\n```\n"
  },
  {
    "path": "tests/test_docs/test_bash_yaml/md_files/bash-scaffolding.md",
    "content": "``` bash\naea create my_aea --author \"fetchai\"\ncd my_aea\n```\n\n``` bash\naea scaffold skill my_skill\n```\n\n``` bash\naea scaffold protocol my_protocol\n```\n\n``` bash\naea scaffold contract my_contract\n```\n\n``` bash\naea scaffold connection my_connection\n```\n\n``` bash\naea fingerprint [package_name] [public_id]\n```\n"
  },
  {
    "path": "tests/test_docs/test_bash_yaml/md_files/bash-skill-guide.md",
    "content": "``` bash\naea create my_aea && cd my_aea\naea scaffold skill my_search\n```\n\n``` bash\naea fingerprint skill fetchai/my_search:0.1.0\n```\n\n``` bash\naea add protocol fetchai/oef_search:1.1.7\n```\n\n``` bash\naea add connection fetchai/soef:0.27.6\naea add connection fetchai/p2p_libp2p:0.27.5\naea install\naea build\naea config set agent.default_connection fetchai/p2p_libp2p:0.27.5\naea config set --type dict agent.default_routing \\\n'{\n  \"fetchai/oef_search:1.1.7\": \"fetchai/soef:0.27.6\"\n}'\n```\n\n``` bash\naea fetch fetchai/simple_service_registration:0.32.5 && cd simple_service_registration && aea install && aea build\n```\n\n``` bash\naea generate-key fetchai\naea add-key fetchai fetchai_private_key.txt\n```\n\n``` bash\naea generate-key fetchai fetchai_connection_private_key.txt\naea add-key fetchai fetchai_connection_private_key.txt --connection\n```\n\n``` bash\naea issue-certificates\n```\n\n``` bash\naea run\n```\n\n``` bash\naea generate-key fetchai\naea add-key fetchai fetchai_private_key.txt\n```\n\n``` bash\naea generate-key fetchai fetchai_connection_private_key.txt\naea add-key fetchai fetchai_connection_private_key.txt --connection\n```\n\n``` bash\naea issue-certificates\n```\n\n``` bash\naea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \\\n'{\n  \"delegate_uri\": \"127.0.0.1:11001\",\n  \"entry_peers\": [\"/dns4/127.0.0.1/tcp/9000/p2p/16Uiu2HAm1uJpFsqSgHStJdtTBPpDme1fo8uFEvvY182D2y89jQuj\"],\n  \"local_uri\": \"127.0.0.1:9001\",\n  \"log_file\": \"libp2p_node.log\",\n  \"public_uri\": \"127.0.0.1:9001\"\n}'\n```\n\n``` bash\naea run\n```\n\n``` yaml\nname: my_search\nauthor: fetchai\nversion: 0.1.0\ntype: skill\ndescription: A simple search skill utilising the SOEF search node.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint: {}\nfingerprint_ignore_patterns: []\nconnections: []\ncontracts: []\nprotocols:\n- fetchai/oef_search:1.1.7\nskills: []\nbehaviours:\n  my_search_behaviour:\n    args:\n      location:\n        latitude: 51.5194\n        longitude: 0.127\n      search_query:\n        constraint_type: ==\n        search_key: seller_service\n        search_value: generic_service\n      search_radius: 5.0\n      tick_interval: 5\n    class_name: MySearchBehaviour\nhandlers:\n  my_search_handler:\n    args: {}\n    class_name: MySearchHandler\nmodels:\n  oef_search_dialogues:\n    args: {}\n    class_name: OefSearchDialogues\ndependencies:\n  aea-ledger-fetchai:\n    version: <2.0.0,>=1.0.0\nis_abstract: false\n```\n\n``` yaml\nname: simple_service_registration\nauthor: fetchai\nversion: 0.20.0\ntype: skill\ndescription: The simple service registration skills is a skill to register a service.\nlicense: Apache-2.0\naea_version: '>=1.0.0, <2.0.0'\nfingerprint:\n  README.md: QmUgCcR7sDBQeeCBRKwDT7tPBTi3t4zSibyEqR3xdQUKmh\n  __init__.py: QmZd48HmYDr7FMxNaVeGfWRvVtieEdEV78hd7h7roTceP2\n  behaviours.py: QmQHf6QL5aBtLJ34D2tdcbjJLbzom9gaA3HWgRn3rWyigM\n  dialogues.py: QmTT9dvFhWt6qvxjwBfMFDTrgEtgWbvgANYafyRg2BXwcR\n  handlers.py: QmZqPt8toGbJgTT6NZBLxjkusrQCZ8GmUEwcmqZ1sd7DpG\n  strategy.py: QmVXfQpk4cjDw576H2ELE12tEiN5brPkwvffvcTeMbsugA\nfingerprint_ignore_patterns: []\nconnections: []\ncontracts: []\nprotocols:\n- fetchai/oef_search:1.1.7\nskills: []\nbehaviours:\n  service:\n    args:\n      max_soef_registration_retries: 5\n      services_interval: 30\n    class_name: ServiceRegistrationBehaviour\nhandlers:\n  oef_search:\n    args: {}\n    class_name: OefSearchHandler\nmodels:\n  oef_search_dialogues:\n    args: {}\n    class_name: OefSearchDialogues\n  strategy:\n    args:\n      classification:\n        piece: classification\n        value: seller\n      location:\n        latitude: 51.5194\n        longitude: 0.127\n      personality_data:\n        piece: genus\n        value: data\n      service_data:\n        key: seller_service\n        value: generic_service\n    class_name: Strategy\ndependencies: {}\nis_abstract: false\n```\n"
  },
  {
    "path": "tests/test_docs/test_bash_yaml/md_files/bash-skill.md",
    "content": "``` yaml\nname: echo\nauthors: fetchai\nversion: 0.1.0\nlicense: Apache-2.0\nbehaviours:\n  echo:\n    class_name: EchoBehaviour\n    args:\n      tick_interval: 1.0\nhandlers:\n  echo:\n    class_name: EchoHandler\n    args:\n      foo: bar\nmodels: {}\ndependencies: {}\nprotocols:\n- fetchai/default:1.1.7\n```\n\n``` bash\naea scaffold error-handler\n```\n"
  },
  {
    "path": "tests/test_docs/test_bash_yaml/md_files/bash-tac-skills-contract.md",
    "content": "``` bash\naea fetch fetchai/tac_controller_contract:0.32.5\ncd tac_controller_contract\naea install\naea build\n```\n\n``` bash\naea create tac_controller_contract\ncd tac_controller_contract\naea add connection fetchai/p2p_libp2p:0.27.5\naea add connection fetchai/soef:0.27.6\naea add connection fetchai/ledger:0.21.5\naea add skill fetchai/tac_control_contract:0.27.6\naea config set --type dict agent.dependencies \\\n'{\n  \"aea-ledger-fetchai\": {\"version\": \"<2.0.0,>=1.0.0\"},\n  \"aea-ledger-ethereum\": {\"version\": \"<2.0.0,>=1.0.0\"}\n}'\naea config set agent.default_connection fetchai/p2p_libp2p:0.27.5\naea config set agent.default_ledger fetchai\naea config set vendor.fetchai.connections.soef.config.chain_identifier fetchai_v2_misc\naea config set --type bool vendor.fetchai.skills.tac_control.is_abstract true\naea config set --type dict agent.default_routing \\\n'{\n  \"fetchai/contract_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n  \"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n  \"fetchai/oef_search:1.1.7\": \"fetchai/soef:0.27.6\"\n}'\naea config set --type list vendor.fetchai.connections.p2p_libp2p.cert_requests \\\n'[{\"identifier\": \"acn\", \"ledger_id\": \"fetchai\", \"not_after\": \"2023-01-01\", \"not_before\": \"2022-01-01\", \"public_key\": \"fetchai\", \"save_path\": \".certs/conn_cert.txt\"}]'\naea install\naea build\n```\n\n``` bash\naea fetch fetchai/tac_participant_contract:0.22.5 --alias tac_participant_one\ncd tac_participant_one\naea install\naea build\ncd ..\naea fetch fetchai/tac_participant_contract:0.22.5 --alias tac_participant_two\ncd tac_participant_two\naea install\naea build\n```\n\n``` bash\naea create tac_participant_one\naea create tac_participant_two\n```\n\n``` bash\ncd tac_participant_one\naea add connection fetchai/p2p_libp2p:0.27.5\naea add connection fetchai/soef:0.27.6\naea add connection fetchai/ledger:0.21.5\naea add skill fetchai/tac_participation:0.25.6\naea add skill fetchai/tac_negotiation:0.29.6\naea config set --type dict agent.dependencies \\\n'{\n  \"aea-ledger-fetchai\": {\"version\": \"<2.0.0,>=1.0.0\"},\n  \"aea-ledger-ethereum\": {\"version\": \"<2.0.0,>=1.0.0\"}\n}'\naea config set agent.default_connection fetchai/p2p_libp2p:0.27.5\naea config set agent.default_ledger fetchai\naea config set vendor.fetchai.connections.soef.config.chain_identifier fetchai_v2_misc\naea config set vendor.fetchai.skills.tac_participation.models.game.args.is_using_contract 'True' --type bool\naea config set vendor.fetchai.skills.tac_negotiation.models.strategy.args.is_contract_tx 'True' --type bool\naea config set --type dict agent.default_routing \\\n'{\n  \"fetchai/contract_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n  \"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n  \"fetchai/oef_search:1.1.7\": \"fetchai/soef:0.27.6\"\n}'\naea config set --type dict agent.decision_maker_handler \\\n'{\n  \"dotted_path\": \"aea.decision_maker.gop:DecisionMakerHandler\",\n  \"file_path\": null\n}'\naea config set --type list vendor.fetchai.connections.p2p_libp2p.cert_requests \\\n'''[{\"identifier\": \"acn\", \"ledger_id\": \"fetchai\", \"message_format\": \"'{public_key}'\", \"not_after\": \"2023-01-01\", \"not_before\": \"2022-01-01\", \"public_key\": \"fetchai\", \"save_path\": \".certs/conn_cert.txt\"}]'''\naea install\naea build\n```\n\n``` bash\ncd tac_participant_two\naea add connection fetchai/p2p_libp2p:0.27.5\naea add connection fetchai/soef:0.27.6\naea add connection fetchai/ledger:0.21.5\naea add skill fetchai/tac_participation:0.25.6\naea add skill fetchai/tac_negotiation:0.29.6\naea config set --type dict agent.dependencies \\\n'{\n  \"aea-ledger-fetchai\": {\"version\": \"<2.0.0,>=1.0.0\"},\n  \"aea-ledger-ethereum\": {\"version\": \"<2.0.0,>=1.0.0\"}\n}'\naea config set agent.default_connection fetchai/p2p_libp2p:0.27.5\naea config set agent.default_ledger fetchai\naea config set vendor.fetchai.connections.soef.config.chain_identifier fetchai_v2_misc\naea config set vendor.fetchai.skills.tac_participation.models.game.args.is_using_contract 'True' --type bool\naea config set vendor.fetchai.skills.tac_negotiation.models.strategy.args.is_contract_tx 'True' --type bool\naea config set --type dict agent.default_routing \\\n'{\n  \"fetchai/contract_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n  \"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n  \"fetchai/oef_search:1.1.7\": \"fetchai/soef:0.27.6\"\n}'\naea config set --type dict agent.decision_maker_handler \\\n'{\n  \"dotted_path\": \"aea.decision_maker.gop:DecisionMakerHandler\",\n  \"file_path\": null\n}'\naea config set --type list vendor.fetchai.connections.p2p_libp2p.cert_requests \\\n'''[{\"identifier\": \"acn\", \"ledger_id\": \"fetchai\", \"message_format\": \"'{public_key}'\", \"not_after\": \"2023-01-01\", \"not_before\": \"2022-01-01\", \"public_key\": \"fetchai\", \"save_path\": \".certs/conn_cert.txt\"}]'''\naea install\naea build\n```\n\n``` bash\naea generate-key fetchai\naea add-key fetchai fetchai_private_key.txt\n```\n\n``` bash\naea generate-key fetchai fetchai_connection_private_key.txt\naea add-key fetchai fetchai_connection_private_key.txt --connection\n```\n\n``` bash\naea issue-certificates\n```\n\n``` bash\naea config get vendor.fetchai.skills.tac_control_contract.models.parameters.args.registration_start_time\naea config set vendor.fetchai.skills.tac_control_contract.models.parameters.args.registration_start_time '01 01 2020  00:01'\n```\n\n``` bash\naea config set vendor.fetchai.skills.tac_control_contract.models.parameters.args.registration_start_time \"$(date -d \"5 minutes\" +'%d %m %Y %H:%M')\"\n```\n\n``` bash\naea get-multiaddress fetchai -c -i fetchai/p2p_libp2p:0.27.5 -u public_uri\n```\n\n``` bash\naea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \\\n'{\n  \"delegate_uri\": \"127.0.0.1:11001\",\n  \"entry_peers\": [\"SOME_ADDRESS\"],\n  \"local_uri\": \"127.0.0.1:9001\",\n  \"log_file\": \"libp2p_node.log\",\n  \"public_uri\": \"127.0.0.1:9001\"\n}'\n```\n\n``` bash\naea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \\\n'{\n  \"delegate_uri\": \"127.0.0.1:11002\",\n  \"entry_peers\": [\"SOME_ADDRESS\"],\n  \"local_uri\": \"127.0.0.1:9002\",\n  \"log_file\": \"libp2p_node.log\",\n  \"public_uri\": \"127.0.0.1:9002\"\n}'\n```\n\n``` bash\naea get-address fetchai\n```\n\n``` bash\naea get-wealth fetchai\n```\n\n``` bash\naea run\n```\n\n``` bash\naea launch tac_participant_one tac_participant_two\n```\n\n``` bash\naea delete tac_controller_contract\naea delete tac_participant_one\naea delete tac_participant_two\n```\n\n``` bash\naea fetch fetchai/tac_controller_contract:0.32.5\ncd tac_controller_contract\naea install\naea build\n```\n\n``` bash\naea create tac_controller_contract\ncd tac_controller_contract\naea add connection fetchai/p2p_libp2p:0.27.5\naea add connection fetchai/soef:0.27.6\naea add connection fetchai/ledger:0.21.5\naea add skill fetchai/tac_control_contract:0.27.6\naea config set --type dict agent.dependencies \\\n'{\n  \"aea-ledger-fetchai\": {\"version\": \"<2.0.0,>=1.0.0\"},\n  \"aea-ledger-ethereum\": {\"version\": \"<2.0.0,>=1.0.0\"}\n}'\naea config set agent.default_connection fetchai/p2p_libp2p:0.27.5\naea config set agent.default_ledger ethereum\naea config set vendor.fetchai.connections.soef.config.chain_identifier ethereum\naea config set --type bool vendor.fetchai.skills.tac_control.is_abstract true\naea config set --type dict agent.default_routing \\\n'{\n  \"fetchai/contract_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n  \"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n  \"fetchai/oef_search:1.1.7\": \"fetchai/soef:0.27.6\"\n}'\naea config set --type list vendor.fetchai.connections.p2p_libp2p.cert_requests \\\n'[{\"identifier\": \"acn\", \"ledger_id\": \"ethereum\", \"not_after\": \"2023-01-01\", \"not_before\": \"2022-01-01\", \"public_key\": \"fetchai\", \"save_path\": \".certs/conn_cert.txt\"}]'\naea install\naea build\n```\n\n``` bash\naea fetch fetchai/tac_participant_contract:0.22.5 --alias tac_participant_one\ncd tac_participant_one\naea install\naea build\ncd ..\naea fetch fetchai/tac_participant_contract:0.22.5 --alias tac_participant_two\ncd tac_participant_two\naea install\naea build\n```\n\n``` bash\naea create tac_participant_one\naea create tac_participant_two\n```\n\n``` bash\ncd tac_participant_one\naea add connection fetchai/p2p_libp2p:0.27.5\naea add connection fetchai/soef:0.27.6\naea add connection fetchai/ledger:0.21.5\naea add skill fetchai/tac_participation:0.25.6\naea add skill fetchai/tac_negotiation:0.29.6\naea config set --type dict agent.dependencies \\\n'{\n  \"aea-ledger-fetchai\": {\"version\": \"<2.0.0,>=1.0.0\"},\n  \"aea-ledger-ethereum\": {\"version\": \"<2.0.0,>=1.0.0\"}\n}'\naea config set agent.default_connection fetchai/p2p_libp2p:0.27.5\naea config set agent.default_ledger ethereum\naea config set vendor.fetchai.connections.soef.config.chain_identifier ethereum\naea config set vendor.fetchai.skills.tac_participation.models.game.args.is_using_contract 'True' --type bool\naea config set vendor.fetchai.skills.tac_negotiation.models.strategy.args.is_contract_tx 'True' --type bool\naea config set --type dict agent.default_routing \\\n'{\n  \"fetchai/contract_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n  \"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n  \"fetchai/oef_search:1.1.7\": \"fetchai/soef:0.27.6\"\n}'\naea config set --type dict agent.decision_maker_handler \\\n'{\n  \"dotted_path\": \"aea.decision_maker.gop:DecisionMakerHandler\",\n  \"file_path\": null\n}'\naea config set --type list vendor.fetchai.connections.p2p_libp2p.cert_requests \\\n'''[{\"identifier\": \"acn\", \"ledger_id\": \"ethereum\", \"message_format\": \"'{public_key}'\", \"not_after\": \"2023-01-01\", \"not_before\": \"2022-01-01\", \"public_key\": \"fetchai\", \"save_path\": \".certs/conn_cert.txt\"}]'''\naea install\naea build\n```\n\n``` bash\ncd tac_participant_two\naea add connection fetchai/p2p_libp2p:0.27.5\naea add connection fetchai/soef:0.27.6\naea add connection fetchai/ledger:0.21.5\naea add skill fetchai/tac_participation:0.25.6\naea add skill fetchai/tac_negotiation:0.29.6\naea config set --type dict agent.dependencies \\\n'{\n  \"aea-ledger-fetchai\": {\"version\": \"<2.0.0,>=1.0.0\"},\n  \"aea-ledger-ethereum\": {\"version\": \"<2.0.0,>=1.0.0\"}\n}'\naea config set agent.default_connection fetchai/p2p_libp2p:0.27.5\naea config set agent.default_ledger ethereum\naea config set vendor.fetchai.connections.soef.config.chain_identifier ethereum\naea config set vendor.fetchai.skills.tac_participation.models.game.args.is_using_contract 'True' --type bool\naea config set vendor.fetchai.skills.tac_negotiation.models.strategy.args.is_contract_tx 'True' --type bool\naea config set --type dict agent.default_routing \\\n'{\n  \"fetchai/contract_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n  \"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n  \"fetchai/oef_search:1.1.7\": \"fetchai/soef:0.27.6\"\n}'\naea config set --type dict agent.decision_maker_handler \\\n'{\n  \"dotted_path\": \"aea.decision_maker.gop:DecisionMakerHandler\",\n  \"file_path\": null\n}'\naea config set --type list vendor.fetchai.connections.p2p_libp2p.cert_requests \\\n'''[{\"identifier\": \"acn\", \"ledger_id\": \"ethereum\", \"message_format\": \"'{public_key}'\", \"not_after\": \"2023-01-01\", \"not_before\": \"2022-01-01\", \"public_key\": \"fetchai\", \"save_path\": \".certs/conn_cert.txt\"}]'''\naea install\naea build\n```\n\n```bash\naea config set agent.default_ledger ethereum\njson=$(printf '[{\"identifier\": \"acn\", \"ledger_id\": \"ethereum\", \"not_after\": \"2023-01-01\", \"not_before\": \"2022-01-01\", \"public_key\": \"fetchai\", \"message_format\": \"{public_key}\", \"save_path\": \".certs/conn_cert.txt\"}]')\naea config set --type list vendor.fetchai.connections.p2p_libp2p.cert_requests \"$json\"\naea config set vendor.fetchai.connections.soef.config.chain_identifier ethereum\n```\n\n``` bash\naea generate-key ethereum\naea add-key ethereum ethereum_private_key.txt\n```\n\n``` bash\naea generate-key fetchai fetchai_connection_private_key.txt\naea add-key fetchai fetchai_connection_private_key.txt --connection\n```\n\n``` bash\naea issue-certificates\n```\n\n``` bash\naea config get vendor.fetchai.skills.tac_control_contract.models.parameters.args.registration_start_time\naea config set vendor.fetchai.skills.tac_control_contract.models.parameters.args.registration_start_time '01 01 2020  00:01'\n```\n\n``` bash\naea config set vendor.fetchai.skills.tac_control_contract.models.parameters.args.registration_start_time \"$(date -d \"5 minutes\" +'%d %m %Y %H:%M')\"\n```\n\n```bash\naea get-multiaddress fetchai -c -i fetchai/p2p_libp2p:0.27.5 -u public_uri\n```\n\n``` bash\naea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \\\n'{\n  \"delegate_uri\": \"127.0.0.1:11001\",\n  \"entry_peers\": [\"SOME_ADDRESS\"],\n  \"local_uri\": \"127.0.0.1:9001\",\n  \"log_file\": \"libp2p_node.log\",\n  \"public_uri\": \"127.0.0.1:9001\"\n}'\n```\n\n``` bash\naea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \\\n'{\n  \"delegate_uri\": \"127.0.0.1:11002\",\n  \"entry_peers\": [\"SOME_ADDRESS\"],\n  \"local_uri\": \"127.0.0.1:9002\",\n  \"log_file\": \"libp2p_node.log\",\n  \"public_uri\": \"127.0.0.1:9002\"\n}'\n```\n\n``` bash\ndocker run -p 8545:8545 trufflesuite/ganache-cli:latest --verbose --gasPrice=0 --gasLimit=0x1fffffffffffff --account=\"$(cat tac_controller_contract/ethereum_private_key.txt),1000000000000000000000\" --account=\"$(cat tac_participant_one/ethereum_private_key.txt),1000000000000000000000\" --account=\"$(cat tac_participant_two/ethereum_private_key.txt),1000000000000000000000\"\n```\n\n``` bash\naea get-wealth ethereum\n```\n\n``` bash\naea run\n```\n\n``` bash\naea launch tac_participant_one tac_participant_two\n```\n\n``` bash\naea delete tac_controller_contract\naea delete tac_participant_one\naea delete tac_participant_two\n```\n"
  },
  {
    "path": "tests/test_docs/test_bash_yaml/md_files/bash-tac-skills.md",
    "content": "``` bash\n{\n  \"delegate_uri\": \"127.0.0.1:11001\",\n  \"entry_peers\": [\"REPLACE_WITH_MULTI_ADDRESS_HERE\"],\n  \"local_uri\": \"127.0.0.1:9001\",\n  \"log_file\": \"libp2p_node.log\",\n  \"public_uri\": \"127.0.0.1:9001\"\n}\n```\n\n``` bash\n{\n  \"delegate_uri\": \"127.0.0.1:11002\",\n  \"entry_peers\": [\"REPLACE_WITH_MULTI_ADDRESS_HERE\"],\n  \"local_uri\": \"127.0.0.1:9002\",\n  \"log_file\": \"libp2p_node.log\",\n  \"public_uri\": \"127.0.0.1:9002\"\n}\n```\n\n``` bash\naea fetch fetchai/tac_controller:0.30.5\ncd tac_controller\naea install\naea build\n```\n\n``` bash\naea create tac_controller\ncd tac_controller\naea add connection fetchai/p2p_libp2p:0.27.5\naea add connection fetchai/soef:0.27.6\naea add connection fetchai/ledger:0.21.5\naea add skill fetchai/tac_control:0.25.6\naea config set --type dict agent.dependencies \\\n'{\n  \"aea-ledger-fetchai\": {\"version\": \"<2.0.0,>=1.0.0\"}\n}'\naea config set agent.default_connection fetchai/p2p_libp2p:0.27.5\naea config set agent.default_ledger fetchai\naea config set --type dict agent.default_routing \\\n'{\n  \"fetchai/oef_search:1.1.7\": \"fetchai/soef:0.27.6\"\n}'\naea install\naea build\n```\n\n``` bash\naea fetch fetchai/tac_participant:0.32.5 --alias tac_participant_one\ncd tac_participant_one\naea install\naea build\ncd ..\naea fetch fetchai/tac_participant:0.32.5 --alias tac_participant_two\ncd tac_participant_two\naea build\n```\n\n``` bash\naea create tac_participant_one\naea create tac_participant_two\n```\n\n``` bash\ncd tac_participant_one\naea add connection fetchai/p2p_libp2p:0.27.5\naea add connection fetchai/soef:0.27.6\naea add connection fetchai/ledger:0.21.5\naea add skill fetchai/tac_participation:0.25.6\naea add skill fetchai/tac_negotiation:0.29.6\naea config set --type dict agent.dependencies \\\n'{\n  \"aea-ledger-fetchai\": {\"version\": \"<2.0.0,>=1.0.0\"}\n}'\naea config set agent.default_connection fetchai/p2p_libp2p:0.27.5\naea config set agent.default_ledger fetchai\naea config set --type dict agent.default_routing \\\n'{\n  \"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n  \"fetchai/oef_search:1.1.7\": \"fetchai/soef:0.27.6\"\n}'\naea config set --type dict agent.decision_maker_handler \\\n'{\n  \"dotted_path\": \"aea.decision_maker.gop:DecisionMakerHandler\",\n  \"file_path\": null\n}'\naea install\naea build\n```\n\n``` bash\ncd tac_participant_two\naea add connection fetchai/p2p_libp2p:0.27.5\naea add connection fetchai/soef:0.27.6\naea add connection fetchai/ledger:0.21.5\naea add skill fetchai/tac_participation:0.25.6\naea add skill fetchai/tac_negotiation:0.29.6\naea config set --type dict agent.dependencies \\\n'{\n  \"aea-ledger-fetchai\": {\"version\": \"<2.0.0,>=1.0.0\"}\n}'\naea config set agent.default_connection fetchai/p2p_libp2p:0.27.5\naea config set agent.default_ledger fetchai\naea config set --type dict agent.default_routing \\\n'{\n  \"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n  \"fetchai/oef_search:1.1.7\": \"fetchai/soef:0.27.6\"\n}'\naea config set --type dict agent.decision_maker_handler \\\n'{\n  \"dotted_path\": \"aea.decision_maker.gop:DecisionMakerHandler\",\n  \"file_path\": null\n}'\naea install\naea build\n```\n\n``` bash\naea generate-key fetchai\naea add-key fetchai fetchai_private_key.txt\n```\n\n``` bash\naea generate-key fetchai fetchai_connection_private_key.txt\naea add-key fetchai fetchai_connection_private_key.txt --connection\n```\n\n``` bash\naea issue-certificates\n```\n\n``` bash\naea config get vendor.fetchai.skills.tac_control.models.parameters.args.registration_start_time\naea config set vendor.fetchai.skills.tac_control.models.parameters.args.registration_start_time '01 01 2020  00:01'\n```\n\n``` bash\naea config set vendor.fetchai.skills.tac_control.models.parameters.args.registration_start_time \"$(date -d \"2 minutes\" +'%d %m %Y %H:%M')\"\n```\n\n``` bash\naea run\n```\n\n``` bash\naea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \\\n'{\n  \"delegate_uri\": \"127.0.0.1:11001\",\n  \"entry_peers\": [\"SOME_ADDRESS\"],\n  \"local_uri\": \"127.0.0.1:9001\",\n  \"log_file\": \"libp2p_node.log\",\n  \"public_uri\": \"127.0.0.1:9001\"\n}'\n```\n\n``` bash\naea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \\\n'{\n  \"delegate_uri\": \"127.0.0.1:11002\",\n  \"entry_peers\": [\"SOME_ADDRESS\"],\n  \"local_uri\": \"127.0.0.1:9002\",\n  \"log_file\": \"libp2p_node.log\",\n  \"public_uri\": \"127.0.0.1:9002\"\n}'\n```\n\n``` bash\naea run\n```\n\n``` bash\naea launch tac_participant_one tac_participant_two\n```\n\n``` bash\naea delete tac_controller\naea delete tac_participant_one\naea delete tac_participant_two\n```\n\n``` yaml\n---\npublic_id: fetchai/p2p_libp2p:0.27.5\ntype: connection\nconfig:\n  delegate_uri: 127.0.0.1:11001\n  entry_peers: ['SOME_ADDRESS']\n  local_uri: 127.0.0.1:9001\n  log_file: libp2p_node.log\n  public_uri: 127.0.0.1:9001\n```\n\n``` yaml\n---\npublic_id: fetchai/p2p_libp2p:0.27.5\ntype: connection\nconfig:\n  delegate_uri: 127.0.0.1:11002\n  entry_peers: ['SOME_ADDRESS']\n  local_uri: 127.0.0.1:9002\n  log_file: libp2p_node.log\n  public_uri: 127.0.0.1:9002\n```\n"
  },
  {
    "path": "tests/test_docs/test_bash_yaml/md_files/bash-tac.md",
    "content": "``` bash\ngit clone git@github.com:fetchai/agents-tac.git --recursive && cd agents-tac\n```\n\n``` bash\nwhich pipenv\n```\n\n``` bash\npipenv --python 3.7 && pipenv shell\n```\n\n``` bash\npipenv install\n```\n\n``` bash\npython setup.py install\n```\n\n``` bash\npython scripts/launch.py\n```\n\n``` bash\ngit clone git@github.com:fetchai/agents-tac.git --recursive && cd agents-tac\npipenv --python 3.7 && pipenv shell\npython setup.py install\ncd sandbox && docker-compose build\ndocker-compose up\n```\n\n``` bash\npipenv shell\npython templates/v1/basic.py --name my_agent --dashboard\n```\n\n``` bash\ndocker stop $(docker ps -q)\n```\n\n``` bash\n# mac\ndocker ps -q | xargs docker stop ; docker system prune -a\n```\n"
  },
  {
    "path": "tests/test_docs/test_bash_yaml/md_files/bash-thermometer-skills.md",
    "content": "``` bash\n{\n  \"delegate_uri\": \"127.0.0.1:11001\",\n  \"entry_peers\": [\"REPLACE_WITH_MULTI_ADDRESS_HERE\"],\n  \"local_uri\": \"127.0.0.1:9001\",\n  \"log_file\": \"libp2p_node.log\",\n  \"public_uri\": \"127.0.0.1:9001\"\n}\n```\n\n``` bash\naea fetch fetchai/thermometer_aea:0.30.5 --alias my_thermometer_aea\ncd my_thermometer_aea\naea install\naea build\n```\n\n``` bash\naea create my_thermometer_aea\ncd my_thermometer_aea\naea add connection fetchai/p2p_libp2p:0.27.5\naea add connection fetchai/soef:0.27.6\naea add connection fetchai/ledger:0.21.5\naea add skill fetchai/thermometer:0.27.6\naea install\naea build\naea config set agent.default_connection fetchai/p2p_libp2p:0.27.5\naea config set --type dict agent.default_routing \\\n'{\n  \"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n  \"fetchai/oef_search:1.1.7\": \"fetchai/soef:0.27.6\"\n}'\n```\n\n``` bash\naea fetch fetchai/thermometer_client:0.32.5 --alias my_thermometer_client\ncd my_thermometer_client\naea install\naea build\n```\n\n``` bash\naea create my_thermometer_client\ncd my_thermometer_client\naea add connection fetchai/p2p_libp2p:0.27.5\naea add connection fetchai/soef:0.27.6\naea add connection fetchai/ledger:0.21.5\naea add skill fetchai/thermometer_client:0.26.6\naea install\naea build\naea config set agent.default_connection fetchai/p2p_libp2p:0.27.5\naea config set --type dict agent.default_routing \\\n'{\n  \"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n  \"fetchai/oef_search:1.1.7\": \"fetchai/soef:0.27.6\"\n}'\n```\n\n``` bash\naea generate-key fetchai\naea add-key fetchai fetchai_private_key.txt\n```\n\n``` bash\naea generate-key fetchai fetchai_connection_private_key.txt\naea add-key fetchai fetchai_connection_private_key.txt --connection\n```\n\n``` bash\naea issue-certificates\n```\n\n``` bash\naea generate-key fetchai\naea add-key fetchai fetchai_private_key.txt\naea add-key fetchai fetchai_private_key.txt --connection\n```\n\n``` bash\naea generate-wealth fetchai\n```\n\n``` bash\naea generate-key fetchai fetchai_connection_private_key.txt\naea add-key fetchai fetchai_connection_private_key.txt --connection\n```\n\n``` bash\naea issue-certificates\n```\n\n``` bash\naea run\n```\n\n``` bash\naea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \\\n'{\n  \"delegate_uri\": \"127.0.0.1:11001\",\n  \"entry_peers\": [\"SOME_ADDRESS\"],\n  \"local_uri\": \"127.0.0.1:9001\",\n  \"log_file\": \"libp2p_node.log\",\n  \"public_uri\": \"127.0.0.1:9001\"\n}'\n```\n\n``` bash\naea run\n```\n\n``` bash\ncd ..\naea delete my_thermometer_aea\naea delete my_thermometer_client\n```\n\n``` yaml\n---\npublic_id: fetchai/p2p_libp2p:0.27.5\ntype: connection\nconfig:\n  delegate_uri: 127.0.0.1:11001\n  entry_peers:\n  - SOME_ADDRESS\n  local_uri: 127.0.0.1:9001\n  log_file: libp2p_node.log\n  public_uri: 127.0.0.1:9001\n```\n"
  },
  {
    "path": "tests/test_docs/test_bash_yaml/md_files/bash-wealth.md",
    "content": "``` bash\npip install aea-ledger-fetchai\n```\n\n``` bash\npip install aea-ledger-ethereum\n```\n\n``` bash\naea generate-key fetchai\naea add-key fetchai fetchai_private_key.txt\n```\n\n``` bash\naea generate-key ethereum\naea add-key ethereum ethereum_private_key.txt\n```\n\n``` bash\naea get-address fetchai\n```\n\n``` bash\naea get-address ethereum\n```\n\n``` bash\naea get-wealth fetchai\n```\n\n``` bash\naea get-wealth ethereum\n```\n\n``` bash\naea generate-wealth fetchai\n```\n\n``` bash\naea generate-wealth ethereum\n```\n"
  },
  {
    "path": "tests/test_docs/test_bash_yaml/md_files/bash-weather-skills.md",
    "content": "``` bash\n{\n  \"delegate_uri\": \"127.0.0.1:11001\",\n  \"entry_peers\": [\"REPLACE_WITH_MULTI_ADDRESS_HERE\"],\n  \"local_uri\": \"127.0.0.1:9001\",\n  \"log_file\": \"libp2p_node.log\",\n  \"public_uri\": \"127.0.0.1:9001\"\n}\n```\n\n``` bash\naea fetch fetchai/weather_station:0.32.5 --alias my_weather_station\ncd my_weather_station\naea install\naea build\n```\n\n``` bash\naea create my_weather_station\ncd my_weather_station\naea add connection fetchai/p2p_libp2p:0.27.5\naea add connection fetchai/soef:0.27.6\naea add connection fetchai/ledger:0.21.5\naea add skill fetchai/weather_station:0.27.6\naea config set --type dict agent.dependencies \\\n'{\n  \"aea-ledger-fetchai\": {\"version\": \"<2.0.0,>=1.0.0\"}\n}'\naea config set agent.default_connection fetchai/p2p_libp2p:0.27.5\naea config set --type dict agent.default_routing \\\n'{\n  \"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n  \"fetchai/oef_search:1.1.7\": \"fetchai/soef:0.27.6\"\n}'\naea install\naea build\n```\n\n``` bash\naea fetch fetchai/weather_client:0.33.5 --alias my_weather_client\ncd my_weather_client\naea install\naea build\n```\n\n``` bash\naea create my_weather_client\ncd my_weather_client\naea add connection fetchai/p2p_libp2p:0.27.5\naea add connection fetchai/soef:0.27.6\naea add connection fetchai/ledger:0.21.5\naea add skill fetchai/weather_client:0.26.6\naea config set --type dict agent.dependencies \\\n'{\n  \"aea-ledger-fetchai\": {\"version\": \"<2.0.0,>=1.0.0\"}\n}'\naea config set agent.default_connection fetchai/p2p_libp2p:0.27.5\naea config set --type dict agent.default_routing \\\n'{\n  \"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n  \"fetchai/oef_search:1.1.7\": \"fetchai/soef:0.27.6\"\n}'\naea install\naea build\n```\n\n``` bash\naea generate-key fetchai\naea add-key fetchai fetchai_private_key.txt\n```\n\n``` bash\naea generate-key fetchai fetchai_connection_private_key.txt\naea add-key fetchai fetchai_connection_private_key.txt --connection\n```\n\n``` bash\naea issue-certificates\n```\n\n``` bash\naea generate-key fetchai\naea add-key fetchai fetchai_private_key.txt\naea add-key fetchai fetchai_private_key.txt --connection\n```\n\n``` bash\naea generate-wealth fetchai\n```\n\n``` bash\naea generate-key fetchai fetchai_connection_private_key.txt\naea add-key fetchai fetchai_connection_private_key.txt --connection\n```\n\n``` bash\naea issue-certificates\n```\n\n``` bash\naea run\n```\n\n``` bash\naea config set --type dict vendor.fetchai.connections.p2p_libp2p.config \\\n'{\n  \"delegate_uri\": \"127.0.0.1:11001\",\n  \"entry_peers\": [\"SOME_ADDRESS\"],\n  \"local_uri\": \"127.0.0.1:9001\",\n  \"log_file\": \"libp2p_node.log\",\n  \"public_uri\": \"127.0.0.1:9001\"\n}'\n```\n\n``` bash\naea run\n```\n\n``` bash\ncd ..\naea delete my_weather_station\naea delete my_weather_client\n```\n\n``` yaml\n---\npublic_id: fetchai/p2p_libp2p:0.27.5\ntype: connection\nconfig:\n  delegate_uri: 127.0.0.1:11001\n  entry_peers:\n  - SOME_ADDRESS\n  local_uri: 127.0.0.1:9001\n  log_file: libp2p_node.log\n  public_uri: 127.0.0.1:9001\n```\n"
  },
  {
    "path": "tests/test_docs/test_bash_yaml/test_demo_docs.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests for the code-blocks in the multiplexer-standalone.md file.\"\"\"\n\nimport logging\nimport os\nfrom pathlib import Path\n\nfrom tests.conftest import ROOT_DIR\nfrom tests.test_docs.helper import extract_code_blocks\n\n\nlogger = logging.getLogger(__name__)\n\n\nclass TestDemoDocs:\n    \"\"\"This class contains the tests for the bash/yaml-blocks in *.md file.\"\"\"\n\n    BASH_DIR_PATH = Path(ROOT_DIR, \"tests\", \"test_docs\", \"test_bash_yaml\", \"md_files\")\n\n    def _test_blocks(self, filename: str, filter_: str):\n        \"\"\"Test code blocks of a certain type determined by 'filter_' param.\"\"\"\n        bash_file = Path(self.BASH_DIR_PATH, filename).read_text(encoding=\"utf-8\")\n        md_path = os.path.join(ROOT_DIR, \"docs\", filename.replace(\"bash-\", \"\"))\n\n        bash_code_blocks = extract_code_blocks(filepath=md_path, filter_=filter_)\n        for blocks in bash_code_blocks:\n            assert blocks in bash_file, \"[{}]: FAILED. Code must be identical\".format(\n                filename\n            )\n        logger.info(\n            f\"[{filename}]: PASSED. Tested {len(bash_code_blocks)} '{filter_}' blocks.\"\n        )\n\n    def test_code_blocks_exist(self):\n        \"\"\"Test that all the code-blocks exist in the python file.\"\"\"\n        logger.info(os.listdir(self.BASH_DIR_PATH))\n        for file in os.listdir(self.BASH_DIR_PATH):\n            if not file.endswith(\".md\"):\n                continue\n            # in the future, we might add other filters like \"python\"\n            self._test_blocks(file, \"bash\")\n            self._test_blocks(file, \"yaml\")\n"
  },
  {
    "path": "tests/test_docs/test_build_aea_programmatically/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the 'build-aea-programmatically' modules.\"\"\"\n"
  },
  {
    "path": "tests/test_docs/test_build_aea_programmatically/programmatic_aea.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This scripts contains code from agent-vs-aea.md file.\"\"\"\n\nimport os\nimport time\nfrom threading import Thread\n\nfrom aea_ledger_fetchai import FetchAICrypto\n\nfrom aea.aea_builder import AEABuilder\nfrom aea.configurations.base import SkillConfig\nfrom aea.crypto.helpers import PRIVATE_KEY_PATH_SCHEMA, create_private_key\nfrom aea.helpers.file_io import write_with_lock\nfrom aea.skills.base import Skill\n\n\nROOT_DIR = \"./\"\nINPUT_FILE = \"input_file\"\nOUTPUT_FILE = \"output_file\"\nFETCHAI_PRIVATE_KEY_FILE = PRIVATE_KEY_PATH_SCHEMA.format(FetchAICrypto.identifier)\n\n\ndef run():\n    \"\"\"Run demo.\"\"\"\n\n    # Create a private key\n    create_private_key(FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE)\n\n    # Ensure the input and output files do not exist initially\n    if os.path.isfile(INPUT_FILE):\n        os.remove(INPUT_FILE)\n    if os.path.isfile(OUTPUT_FILE):\n        os.remove(OUTPUT_FILE)\n\n    # Instantiate the builder and build the AEA\n    # By default, the default protocol, error skill and stub connection are added\n    builder = AEABuilder()\n\n    builder.set_name(\"my_aea\")\n\n    builder.add_private_key(FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE)\n\n    # Add the stub connection (assuming it is present in the local directory 'packages')\n    builder.add_connection(\"./packages/fetchai/connections/stub\")\n\n    # Add the echo skill (assuming it is present in the local directory 'packages')\n    builder.add_skill(\"./packages/fetchai/skills/echo\")\n\n    # create skill and handler manually\n    from aea.protocols.base import Message\n    from aea.skills.base import Handler\n\n    from packages.fetchai.protocols.default.message import DefaultMessage\n\n    class DummyHandler(Handler):\n        \"\"\"Dummy handler to handle messages.\"\"\"\n\n        SUPPORTED_PROTOCOL = DefaultMessage.protocol_id\n\n        def setup(self) -> None:\n            \"\"\"Noop setup.\"\"\"\n\n        def teardown(self) -> None:\n            \"\"\"Noop teardown.\"\"\"\n\n        def handle(self, message: Message) -> None:\n            \"\"\"Handle incoming message.\"\"\"\n            self.context.logger.info(\"You got a message: {}\".format(str(message)))\n\n    config = SkillConfig(name=\"test_skill\", author=\"fetchai\")\n    skill = Skill(configuration=config)\n    dummy_handler = DummyHandler(\n        name=\"dummy_handler\", skill_context=skill.skill_context\n    )\n    skill.handlers.update({dummy_handler.name: dummy_handler})\n    builder.add_component_instance(skill)\n\n    # Create our AEA\n    my_aea = builder.build()\n\n    # Set the AEA running in a different thread\n    try:\n        t = Thread(target=my_aea.start)\n        t.start()\n\n        # Wait for everything to start up\n        time.sleep(4)\n\n        # Create a message inside an envelope and get the stub connection to pass it on to the echo skill\n        message_text = b\"my_aea,other_agent,fetchai/default:1.0.0,\\x12\\x10\\x08\\x01\\x12\\x011*\\t*\\x07\\n\\x05hello,\"\n        with open(INPUT_FILE, \"wb\") as f:\n            write_with_lock(f, message_text)\n            print(b\"input message: \" + message_text)\n\n        # Wait for the envelope to get processed\n        time.sleep(4)\n\n        # Read the output envelope generated by the echo skill\n        with open(OUTPUT_FILE, \"rb\") as f:\n            print(b\"output message: \" + f.readline())\n    finally:\n        # Shut down the AEA\n        my_aea.stop()\n        t.join()\n        t = None\n\n\nif __name__ == \"__main__\":\n    run()\n"
  },
  {
    "path": "tests/test_docs/test_build_aea_programmatically/test_programmatic_aea.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests for the code-blocks in the build-aea-programmatically.md file.\"\"\"\n\nimport os\nfrom pathlib import Path\n\nfrom aea.configurations.constants import DEFAULT_PRIVATE_KEY_FILE\nfrom aea.test_tools.test_cases import BaseAEATestCase\n\nfrom tests.conftest import CUR_PATH, ROOT_DIR\nfrom tests.test_docs.helper import extract_code_blocks, extract_python_code\nfrom tests.test_docs.test_build_aea_programmatically.programmatic_aea import run\n\n\nMD_FILE = \"docs/build-aea-programmatically.md\"\nPY_FILE = \"test_docs/test_build_aea_programmatically/programmatic_aea.py\"\n\n\nclass TestProgrammaticAEA(BaseAEATestCase):\n    \"\"\"This class contains the tests for the code-blocks in the build-aea-programmatically.md file.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup_class()\n        doc_path = os.path.join(ROOT_DIR, MD_FILE)\n        cls.code_blocks = extract_code_blocks(filepath=doc_path, filter_=\"python\")\n        test_code_path = os.path.join(CUR_PATH, PY_FILE)\n        cls.python_file = extract_python_code(test_code_path)\n\n    def test_read_md_file(self):\n        \"\"\"Read the code blocks. Last block should be the whole code.\"\"\"\n        assert (\n            self.code_blocks[-1] == self.python_file\n        ), \"Files must be exactly the same.\"\n\n    def test_run_agent(self):\n        \"\"\"Run the agent from the file.\"\"\"\n        run()\n        assert os.path.exists(Path(self.t, \"input_file\"))\n        assert os.path.exists(Path(self.t, \"output_file\"))\n        assert os.path.exists(Path(self.t, DEFAULT_PRIVATE_KEY_FILE))\n\n        message_text_1 = b\"other_agent,my_aea,fetchai/default:1.0.0,\"\n        message_text_2 = b\"hello,\"\n        path = os.path.join(self.t, \"output_file\")\n        msg = Path(path).read_bytes()\n        assert message_text_1 in msg\n        assert message_text_2 in msg\n\n    def test_code_blocks_exist(self):\n        \"\"\"Test that all the code-blocks exist in the python file.\"\"\"\n        for block in self.code_blocks:\n            assert (\n                block in self.python_file\n            ), \"Code-block doesn't exist in the python file.\"\n"
  },
  {
    "path": "tests/test_docs/test_cli_commands.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests for the content of cli-commands.md file.\"\"\"\nimport pprint\nimport re\nfrom pathlib import Path\n\nfrom aea.cli import cli\n\nfrom tests.conftest import ROOT_DIR\nfrom tests.test_docs.helper import BaseTestMarkdownDocs\n\n\nIGNORE_MATCHES = [\"`-v DEBUG run`\", \"`config set [path] [--type TYPE]`\"]\n\n\nclass TestCliCommands(BaseTestMarkdownDocs):\n    \"\"\"Test cli-commands.md documentation.\"\"\"\n\n    DOC_PATH = Path(ROOT_DIR, \"docs\", \"cli-commands.md\")\n\n    def test_cli_commands(self):\n        \"\"\"Test CLI commands.\"\"\"\n        commands_raw = re.compile(r\"\\| `.*` +\\|\").findall(self.doc_content)\n        commands_raw = [\n            re.compile(r\"`([A-Za-z0-9\\-_]+) ?.*`\").search(s) for s in commands_raw\n        ]\n        commands_raw = list(\n            filter(lambda x: x.group(0) not in IGNORE_MATCHES, commands_raw)\n        )\n        actual_commands = list(map(lambda match: match.group(1), commands_raw))\n\n        actual_commands_set = set(actual_commands)\n        expected_commands = set(cli.commands.keys())\n\n        # test no duplicates\n        assert len(actual_commands) == len(\n            actual_commands_set\n        ), \"Found duplicate commands in the documentation.\"\n\n        # test that there is no missing command\n        missing = expected_commands.difference(actual_commands)\n        assert (\n            len(missing) == 0\n        ), f\"Missing the following commands: {pprint.pformat(missing)}\"\n\n        # test that there are no more commands\n        more = actual_commands_set.difference(expected_commands)\n        assert len(more) == 0, f\"There are unknown commands: {pprint.pformat(missing)}\"\n\n        # test that they are in the same order.\n        actual = actual_commands\n        expected = sorted(expected_commands)\n        assert actual == expected, \"Commands are not in alphabetical order.\"\n"
  },
  {
    "path": "tests/test_docs/test_cli_vs_programmatic_aeas/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the 'clis-vs-programmatic-aeas' modules.\"\"\"\n"
  },
  {
    "path": "tests/test_docs/test_cli_vs_programmatic_aeas/programmatic_aea.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This scripts contains code from cli-vs-programmatic-aeas.md file.\"\"\"\n\nimport logging\nimport os\nimport sys\nfrom typing import cast\n\nfrom aea_ledger_fetchai import FetchAICrypto\n\nfrom aea.aea import AEA\nfrom aea.aea_builder import AEABuilder\nfrom aea.configurations.base import ConnectionConfig\nfrom aea.crypto.helpers import (\n    PRIVATE_KEY_PATH_SCHEMA,\n    create_private_key,\n    make_certificate,\n)\nfrom aea.crypto.wallet import Wallet\nfrom aea.helpers.base import CertRequest\nfrom aea.identity.base import Identity\nfrom aea.protocols.base import Protocol\nfrom aea.registries.resources import Resources\nfrom aea.skills.base import Skill\n\nimport packages.fetchai.connections.p2p_libp2p.connection\nfrom packages.fetchai.connections.ledger.connection import LedgerConnection\nfrom packages.fetchai.connections.p2p_libp2p.connection import P2PLibp2pConnection\nfrom packages.fetchai.connections.soef.connection import SOEFConnection\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.skills.weather_client.strategy import Strategy\n\n\nAPI_KEY = \"TwiCIriSl0mLahw17pyqoA\"\nSOEF_ADDR = \"s-oef.fetch.ai\"\nSOEF_PORT = 443\nENTRY_PEER_ADDRESS = (\n    \"/dns4/127.0.0.1/tcp/9000/p2p/16Uiu2HAmLBCAqHL8SuFosyDhAKYsLKXBZBWXBsB9oFw2qU4Kckun\"\n)\nFETCHAI_PRIVATE_KEY_FILE = PRIVATE_KEY_PATH_SCHEMA.format(FetchAICrypto.identifier)\nFETCHAI_PRIVATE_KEY_FILE_CONNECTION = PRIVATE_KEY_PATH_SCHEMA.format(\n    \"fetchai_connection\"\n)\nROOT_DIR = os.getcwd()\n\nlogger = logging.getLogger(\"aea\")\nlogging.basicConfig(stream=sys.stdout, level=logging.INFO)\n\n\ndef run():\n    \"\"\"Run demo.\"\"\"\n\n    # Create a private key\n    create_private_key(FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE)\n    create_private_key(FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE_CONNECTION)\n\n    # Set up the wallet, identity and (empty) resources\n    wallet = Wallet(\n        private_key_paths={FetchAICrypto.identifier: FETCHAI_PRIVATE_KEY_FILE},\n        connection_private_key_paths={\n            FetchAICrypto.identifier: FETCHAI_PRIVATE_KEY_FILE_CONNECTION\n        },\n    )\n    identity = Identity(\n        \"my_aea\",\n        address=wallet.addresses.get(FetchAICrypto.identifier),\n        public_key=wallet.public_keys.get(FetchAICrypto.identifier),\n    )\n    resources = Resources()\n    data_dir = os.getcwd()\n\n    # specify the default routing for some protocols\n    default_routing = {\n        LedgerApiMessage.protocol_id: LedgerConnection.connection_id,\n        OefSearchMessage.protocol_id: SOEFConnection.connection_id,\n    }\n    default_connection = P2PLibp2pConnection.connection_id\n\n    state_update_protocol = Protocol.from_dir(\n        os.path.join(os.getcwd(), \"packages\", \"fetchai\", \"protocols\", \"state_update\")\n    )\n    resources.add_protocol(state_update_protocol)\n\n    # Add the default protocol (which is part of the AEA distribution)\n    default_protocol = Protocol.from_dir(\n        os.path.join(os.getcwd(), \"packages\", \"fetchai\", \"protocols\", \"default\")\n    )\n    resources.add_protocol(default_protocol)\n\n    # Add the signing protocol (which is part of the AEA distribution)\n    signing_protocol = Protocol.from_dir(\n        os.path.join(os.getcwd(), \"packages\", \"fetchai\", \"protocols\", \"signing\")\n    )\n    resources.add_protocol(signing_protocol)\n\n    # Add the ledger_api protocol\n    ledger_api_protocol = Protocol.from_dir(\n        os.path.join(\n            os.getcwd(),\n            \"packages\",\n            \"fetchai\",\n            \"protocols\",\n            \"ledger_api\",\n        )\n    )\n    resources.add_protocol(ledger_api_protocol)\n\n    # Add the oef_search protocol\n    oef_protocol = Protocol.from_dir(\n        os.path.join(\n            os.getcwd(),\n            \"packages\",\n            \"fetchai\",\n            \"protocols\",\n            \"oef_search\",\n        )\n    )\n    resources.add_protocol(oef_protocol)\n\n    # Add the fipa protocol\n    fipa_protocol = Protocol.from_dir(\n        os.path.join(\n            os.getcwd(),\n            \"packages\",\n            \"fetchai\",\n            \"protocols\",\n            \"fipa\",\n        )\n    )\n    resources.add_protocol(fipa_protocol)\n\n    # Add the LedgerAPI connection\n    configuration = ConnectionConfig(connection_id=LedgerConnection.connection_id)\n    ledger_api_connection = LedgerConnection(\n        configuration=configuration, data_dir=data_dir, identity=identity\n    )\n    resources.add_connection(ledger_api_connection)\n\n    # Add the P2P connection\n    cert_path = \".certs/conn_cert.txt\"\n    cert_request = CertRequest(\n        identifier=\"acn\",\n        ledger_id=FetchAICrypto.identifier,\n        not_after=\"2022-01-01\",\n        not_before=\"2021-01-01\",\n        public_key=\"fetchai\",\n        message_format=\"{public_key}\",\n        save_path=cert_path,\n    )\n    public_key = wallet.connection_cryptos.public_keys.get(FetchAICrypto.identifier)\n    message = cert_request.get_message(public_key)\n    make_certificate(\n        FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE, message, cert_path\n    )\n    configuration = ConnectionConfig(\n        connection_id=P2PLibp2pConnection.connection_id,\n        delegate_uri=\"127.0.0.1:11001\",\n        entry_peers=[ENTRY_PEER_ADDRESS],\n        local_uri=\"127.0.0.1:9001\",\n        log_file=\"libp2p_node.log\",\n        public_uri=\"127.0.0.1:9001\",\n        build_directory=os.getcwd(),\n        build_entrypoint=\"check_dependencies.py\",\n        cert_requests=[cert_request],\n    )\n    configuration.directory = os.path.dirname(\n        packages.fetchai.connections.p2p_libp2p.connection.__file__\n    )\n\n    AEABuilder.run_build_for_component_configuration(configuration)\n\n    p2p_connection = P2PLibp2pConnection(\n        configuration=configuration,\n        data_dir=data_dir,\n        identity=identity,\n        crypto_store=wallet.connection_cryptos,\n    )\n    resources.add_connection(p2p_connection)\n\n    # Add the SOEF connection\n    configuration = ConnectionConfig(\n        api_key=API_KEY,\n        soef_addr=SOEF_ADDR,\n        soef_port=SOEF_PORT,\n        restricted_to_protocols={OefSearchMessage.protocol_id},\n        connection_id=SOEFConnection.connection_id,\n    )\n    soef_connection = SOEFConnection(\n        configuration=configuration, data_dir=data_dir, identity=identity\n    )\n    resources.add_connection(soef_connection)\n\n    # create the AEA\n    my_aea = AEA(\n        identity,\n        wallet,\n        resources,\n        data_dir,\n        default_connection=default_connection,\n        default_routing=default_routing,\n    )\n    # Add the error and weather_client skills\n    error_skill = Skill.from_dir(\n        os.path.join(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"error\"),\n        agent_context=my_aea.context,\n    )\n    weather_skill = Skill.from_dir(\n        os.path.join(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"weather_client\"),\n        agent_context=my_aea.context,\n    )\n\n    strategy = cast(Strategy, weather_skill.models.get(\"strategy\"))\n    strategy._is_ledger_tx = False\n\n    for skill in [error_skill, weather_skill]:\n        resources.add_skill(skill)\n\n    # Run the AEA\n    try:\n        logger.info(\"STARTING AEA NOW!\")\n        my_aea.start()\n    except KeyboardInterrupt:\n        logger.info(\"STOPPING AEA NOW!\")\n        my_aea.stop()\n\n\nif __name__ == \"__main__\":\n    run()\n"
  },
  {
    "path": "tests/test_docs/test_cli_vs_programmatic_aeas/test_cli_vs_programmatic_aea.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests for the code-blocks in the build-aea-programmatically.md file.\"\"\"\n\nimport os\nimport shutil\nfrom pathlib import Path\nfrom random import uniform\n\nimport pytest\nfrom aea_ledger_fetchai import FetchAICrypto\n\nfrom aea.test_tools.test_cases import AEATestCaseManyFlaky\n\nfrom packages.fetchai.connections.p2p_libp2p.connection import LIBP2P_SUCCESS_MESSAGE\n\nfrom tests.conftest import (\n    CUR_PATH,\n    FETCHAI_PRIVATE_KEY_FILE,\n    FETCHAI_PRIVATE_KEY_FILE_CONNECTION,\n    MAX_FLAKY_RERUNS_INTEGRATION,\n    NON_FUNDED_FETCHAI_PRIVATE_KEY_1,\n    ROOT_DIR,\n    wait_for_localhost_ports_to_close,\n)\nfrom tests.test_docs.helper import extract_code_blocks, extract_python_code\n\n\nMD_FILE = \"docs/cli-vs-programmatic-aeas.md\"\nPY_FILE = \"test_docs/test_cli_vs_programmatic_aeas/programmatic_aea.py\"\nDEST = \"programmatic_aea.py\"\n\n\ndef test_read_md_file():\n    \"\"\"Compare the extracted code with the python file.\"\"\"\n    doc_path = os.path.join(ROOT_DIR, MD_FILE)\n    code_blocks = extract_code_blocks(filepath=doc_path, filter_=\"python\")\n    test_code_path = os.path.join(CUR_PATH, PY_FILE)\n    python_file = extract_python_code(test_code_path)\n    assert code_blocks[-1] == python_file, \"Files must be exactly the same.\"\n\n\nclass TestCliVsProgrammaticAEA(AEATestCaseManyFlaky):\n    \"\"\"This class contains the tests for the code-blocks in the build-aea-programmatically.md file.\"\"\"\n\n    capture_log: bool = True\n\n    @pytest.mark.flaky(reruns=MAX_FLAKY_RERUNS_INTEGRATION)\n    @pytest.mark.integration\n    def test_cli_programmatic_communication(self):\n        \"\"\"Test the communication of the two agents.\"\"\"\n\n        weather_station = \"weather_station\"\n        self.fetch_agent(\"fetchai/weather_station:0.32.5\", weather_station)\n        self.set_agent_context(weather_station)\n        self.set_config(\n            \"vendor.fetchai.skills.weather_station.models.strategy.args.is_ledger_tx\",\n            False,\n            \"bool\",\n        )\n        self.run_install()\n\n        # add non-funded key\n        self.generate_private_key(FetchAICrypto.identifier)\n        self.generate_private_key(\n            FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE_CONNECTION\n        )\n        self.add_private_key(FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE)\n        self.add_private_key(\n            FetchAICrypto.identifier,\n            FETCHAI_PRIVATE_KEY_FILE_CONNECTION,\n            connection=True,\n        )\n        self.replace_private_key_in_file(\n            NON_FUNDED_FETCHAI_PRIVATE_KEY_1, FETCHAI_PRIVATE_KEY_FILE_CONNECTION\n        )\n        # generate random location\n        location = {\n            \"latitude\": round(uniform(-90, 90), 2),  # nosec\n            \"longitude\": round(uniform(-180, 180), 2),  # nosec\n        }\n        setting_path = (\n            \"vendor.fetchai.skills.weather_station.models.strategy.args.location\"\n        )\n        self.nested_set_config(setting_path, location)\n\n        self.run_cli_command(\"build\", cwd=self._get_cwd())\n        self.run_cli_command(\"issue-certificates\", cwd=self._get_cwd())\n        weather_station_process = self.run_agent()\n\n        check_strings = (\n            \"Starting libp2p node...\",\n            \"Connecting to libp2p node...\",\n            \"Successfully connected to libp2p node!\",\n            LIBP2P_SUCCESS_MESSAGE,\n        )\n        missing_strings = self.missing_from_output(\n            weather_station_process, check_strings, timeout=30, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in weather_station output.\".format(missing_strings)\n\n        src_file_path = os.path.join(ROOT_DIR, \"tests\", PY_FILE)\n        dst_file_path = os.path.join(ROOT_DIR, self.t, DEST)\n        shutil.copyfile(src_file_path, dst_file_path)\n        self._inject_location(location, dst_file_path)\n        weather_client_process = self.start_subprocess(DEST, cwd=self.t)\n\n        check_strings = (\n            \"Starting libp2p node...\",\n            \"Connecting to libp2p node...\",\n            \"Successfully connected to libp2p node!\",\n            LIBP2P_SUCCESS_MESSAGE,\n        )\n        missing_strings = self.missing_from_output(\n            weather_client_process,\n            check_strings,\n            timeout=30,\n            is_terminating=False,\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in weather_client output.\".format(missing_strings)\n\n        check_strings = (\n            \"registering agent on SOEF.\",\n            \"registering agent's service on the SOEF.\",\n            \"registering agent's personality genus on the SOEF.\",\n            \"registering agent's personality classification on the SOEF.\",\n            \"received CFP from sender=\",\n            \"sending a PROPOSE with proposal=\",\n            \"received ACCEPT from sender=\",\n            \"sending MATCH_ACCEPT_W_INFORM to sender=\",\n            \"received INFORM from sender=\",\n            \"transaction confirmed, sending data=\",\n        )\n        missing_strings = self.missing_from_output(\n            weather_station_process, check_strings, timeout=120, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in weather_station output.\".format(missing_strings)\n\n        check_strings = (\n            \"found agents=\",\n            \"sending CFP to agent=\",\n            \"received proposal=\",\n            \"accepting the proposal from sender=\",\n            \"informing counterparty=\",\n            \"received INFORM from sender=\",\n            \"received the following data=\",\n        )\n        missing_strings = self.missing_from_output(\n            weather_client_process, check_strings, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in weather_client output.\".format(missing_strings)\n\n        self.terminate_agents(weather_client_process, weather_station_process)\n        assert (\n            self.is_successfully_terminated()\n        ), \"Agents weren't successfully terminated.\"\n        wait_for_localhost_ports_to_close([9000, 9001])\n\n    def _inject_location(self, location, dst_file_path):\n        \"\"\"Inject location into the weather client strategy.\"\"\"\n        file = Path(dst_file_path)\n        lines = file.read_text().splitlines()\n        target_line = \"    strategy._is_ledger_tx = False\"\n        line_insertion_position = lines.index(target_line) + 1\n        lines.insert(\n            line_insertion_position,\n            \"    from packages.fetchai.skills.generic_buyer.strategy import Location\",\n        )\n        lines.insert(\n            line_insertion_position + 1,\n            f\"    strategy._agent_location = Location(latitude={location['latitude']}, longitude={location['longitude']})\",\n        )\n        file.write_text(\"\\n\".join(lines))\n"
  },
  {
    "path": "tests/test_docs/test_data_models.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests for the content of data-models.md file.\"\"\"\nfrom pathlib import Path\n\nfrom aea.helpers.search.models import Attribute, DataModel, Description\n\nfrom tests.conftest import ROOT_DIR\nfrom tests.test_docs.helper import BasePythonMarkdownDocs\n\n\nclass TestDataModel(BasePythonMarkdownDocs):\n    \"\"\"Test the data models code snippets.\"\"\"\n\n    DOC_PATH = Path(ROOT_DIR, \"docs\", \"defining-data-models.md\")\n\n    def _assert(self, locals_, *_mocks):\n        attribute = locals_[\"attr_title\"]\n        assert isinstance(attribute, Attribute)\n\n        data_model = locals_[\"book_model\"]\n        assert isinstance(data_model, DataModel)\n\n        description = locals_[\"It\"]\n        assert isinstance(description, Description)\n"
  },
  {
    "path": "tests/test_docs/test_decision_maker_transaction/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests for the code-blocks in the decision-maker-transaction.md file.\"\"\"\n"
  },
  {
    "path": "tests/test_docs/test_decision_maker_transaction/decision_maker_transaction.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests for the code-blocks in the decision-maker-transaction.md file.\"\"\"\n\nimport logging\nimport time\nfrom threading import Thread\nfrom typing import Optional, cast\n\nfrom aea_ledger_fetchai import FetchAICrypto\n\nfrom aea.aea_builder import AEABuilder\nfrom aea.configurations.base import PublicId, SkillConfig\nfrom aea.crypto.helpers import create_private_key\nfrom aea.crypto.ledger_apis import LedgerApis\nfrom aea.crypto.wallet import Wallet\nfrom aea.helpers.transaction.base import RawTransaction, Terms\nfrom aea.identity.base import Identity\nfrom aea.protocols.base import Address, Message\nfrom aea.protocols.dialogue.base import Dialogue\nfrom aea.skills.base import Handler, Model, Skill, SkillContext\n\nfrom packages.fetchai.protocols.signing.dialogues import SigningDialogue\nfrom packages.fetchai.protocols.signing.dialogues import (\n    SigningDialogues as BaseSigningDialogues,\n)\nfrom packages.fetchai.protocols.signing.message import SigningMessage\n\nfrom tests.conftest import get_wealth_if_needed\n\n\nlogger = logging.getLogger(\"aea\")\nlogging.basicConfig(level=logging.INFO)\n\nFETCHAI_PRIVATE_KEY_FILE_1 = \"fetchai_private_key_1.txt\"\nFETCHAI_PRIVATE_KEY_FILE_2 = \"fetchai_private_key_2.txt\"\n\n\ndef run():\n    \"\"\"Run demo.\"\"\"\n\n    # Create a private key\n    create_private_key(\n        FetchAICrypto.identifier, private_key_file=FETCHAI_PRIVATE_KEY_FILE_1\n    )\n\n    # Instantiate the builder and build the AEA\n    # By default, the default protocol, error skill and stub connection are added\n    builder = AEABuilder()\n\n    builder.set_name(\"my_aea\")\n\n    builder.add_private_key(FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE_1)\n\n    # Create our AEA\n    my_aea = builder.build()\n\n    # add a simple skill with handler\n    skill_context = SkillContext(my_aea.context)\n    skill_config = SkillConfig(name=\"simple_skill\", author=\"fetchai\", version=\"0.1.0\")\n    signing_handler = SigningHandler(\n        skill_context=skill_context, name=\"signing_handler\"\n    )\n    signing_dialogues_model = SigningDialogues(\n        skill_context=skill_context,\n        name=\"signing_dialogues\",\n        self_address=str(skill_config.public_id),\n    )\n\n    simple_skill = Skill(\n        skill_config,\n        skill_context,\n        handlers={signing_handler.name: signing_handler},\n        models={signing_dialogues_model.name: signing_dialogues_model},\n    )\n    my_aea.resources.add_skill(simple_skill)\n\n    # create a second identity\n    create_private_key(\n        FetchAICrypto.identifier, private_key_file=FETCHAI_PRIVATE_KEY_FILE_2\n    )\n\n    counterparty_wallet = Wallet({FetchAICrypto.identifier: FETCHAI_PRIVATE_KEY_FILE_2})\n    get_wealth_if_needed(counterparty_wallet.addresses[\"fetchai\"])\n\n    counterparty_identity = Identity(\n        name=\"counterparty_aea\",\n        addresses=counterparty_wallet.addresses,\n        public_keys=counterparty_wallet.public_keys,\n        default_address_key=FetchAICrypto.identifier,\n    )\n\n    # create signing message for decision maker to sign\n    terms = Terms(\n        ledger_id=FetchAICrypto.identifier,\n        sender_address=my_aea.identity.address,\n        counterparty_address=counterparty_identity.address,\n        amount_by_currency_id={\"FET\": -1},\n        quantities_by_good_id={\"some_service\": 1},\n        nonce=\"some_nonce\",\n        fee_by_currency_id={\"FET\": 0},\n    )\n    get_wealth_if_needed(terms.sender_address)\n\n    signing_dialogues = cast(SigningDialogues, skill_context.signing_dialogues)\n    stub_transaction = LedgerApis.get_transfer_transaction(\n        terms.ledger_id,\n        terms.sender_address,\n        terms.counterparty_address,\n        terms.sender_payable_amount,\n        terms.sender_fee,\n        terms.nonce,\n    )\n    signing_msg = SigningMessage(\n        performative=SigningMessage.Performative.SIGN_TRANSACTION,\n        dialogue_reference=signing_dialogues.new_self_initiated_dialogue_reference(),\n        raw_transaction=RawTransaction(FetchAICrypto.identifier, stub_transaction),\n        terms=terms,\n    )\n    signing_dialogue = cast(\n        Optional[SigningDialogue],\n        signing_dialogues.create_with_message(\"decision_maker\", signing_msg),\n    )\n    assert signing_dialogue is not None\n    my_aea.context.decision_maker_message_queue.put_nowait(signing_msg)\n\n    # Set the AEA running in a different thread\n    try:\n        logger.info(\"STARTING AEA NOW!\")\n        t = Thread(target=my_aea.start)\n        t.start()\n\n        # Let it run long enough to interact with the decision maker\n        time.sleep(1)\n    finally:\n        # Shut down the AEA\n        logger.info(\"STOPPING AEA NOW!\")\n        my_aea.stop()\n        t.join()\n\n\nclass SigningDialogues(Model, BaseSigningDialogues):\n    \"\"\"Signing dialogues model.\"\"\"\n\n    def __init__(self, self_address: Address, **kwargs) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :return: None\n        \"\"\"\n        Model.__init__(self, **kwargs)\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> Dialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return SigningDialogue.Role.SKILL\n\n        BaseSigningDialogues.__init__(\n            self,\n            self_address=self_address,\n            role_from_first_message=role_from_first_message,\n        )\n\n\nclass SigningHandler(Handler):\n    \"\"\"Implement the signing handler.\"\"\"\n\n    SUPPORTED_PROTOCOL = SigningMessage.protocol_id  # type: Optional[PublicId]\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup for the handler.\"\"\"\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to a message.\n\n        :param message: the message\n        :return: None\n        \"\"\"\n        signing_msg = cast(SigningMessage, message)\n\n        # recover dialogue\n        signing_dialogues = cast(SigningDialogues, self.context.signing_dialogues)\n        signing_dialogue = cast(\n            Optional[SigningDialogue], signing_dialogues.update(signing_msg)\n        )\n        if signing_dialogue is None:\n            self._handle_unidentified_dialogue(signing_msg)\n            return\n\n        # handle message\n        if signing_msg.performative is SigningMessage.Performative.SIGNED_TRANSACTION:\n            self._handle_signed_transaction(signing_msg, signing_dialogue)\n        elif signing_msg.performative is SigningMessage.Performative.ERROR:\n            self._handle_error(signing_msg, signing_dialogue)\n        else:\n            self._handle_invalid(signing_msg, signing_dialogue)\n\n    def teardown(self) -> None:\n        \"\"\"\n        Implement the handler teardown.\n\n        :return: None\n        \"\"\"\n\n    def _handle_unidentified_dialogue(self, signing_msg: SigningMessage) -> None:\n        \"\"\"\n        Handle an unidentified dialogue.\n\n        :param msg: the message\n        \"\"\"\n        self.context.logger.info(\n            \"received invalid signing message={}, unidentified dialogue.\".format(\n                signing_msg\n            )\n        )\n\n    def _handle_signed_transaction(\n        self, signing_msg: SigningMessage, signing_dialogue: SigningDialogue\n    ) -> None:\n        \"\"\"\n        Handle a signing message.\n\n        :param signing_msg: the signing message\n        :param signing_dialogue: the dialogue\n        :return: None\n        \"\"\"\n        self.context.logger.info(\"transaction signing was successful.\")\n        logger.info(signing_msg.signed_transaction)\n\n    def _handle_error(\n        self, signing_msg: SigningMessage, signing_dialogue: SigningDialogue\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param signing_msg: the signing message\n        :param signing_dialogue: the dialogue\n        :return: None\n        \"\"\"\n        self.context.logger.info(\n            \"transaction signing was not successful. Error_code={} in dialogue={}\".format(\n                signing_msg.error_code, signing_dialogue\n            )\n        )\n\n    def _handle_invalid(\n        self, signing_msg: SigningMessage, signing_dialogue: SigningDialogue\n    ) -> None:\n        \"\"\"\n        Handle an oef search message.\n\n        :param signing_msg: the signing message\n        :param signing_dialogue: the dialogue\n        :return: None\n        \"\"\"\n        self.context.logger.warning(\n            \"cannot handle signing message of performative={} in dialogue={}.\".format(\n                signing_msg.performative, signing_dialogue\n            )\n        )\n\n\nif __name__ == \"__main__\":\n    run()\n"
  },
  {
    "path": "tests/test_docs/test_decision_maker_transaction/test_decision_maker_transaction.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests for the code-blocks in the standalone-transaction.md file.\"\"\"\nimport logging\nimport os\nfrom unittest.mock import patch\n\nimport pytest\n\nfrom aea.test_tools.test_cases import BaseAEATestCase\n\nfrom ..helper import extract_code_blocks, extract_python_code\nfrom .decision_maker_transaction import logger, run\nfrom tests.conftest import CUR_PATH, MAX_FLAKY_RERUNS, ROOT_DIR\n\n\nMD_FILE = \"docs/decision-maker-transaction.md\"\nPY_FILE = \"test_docs/test_decision_maker_transaction/decision_maker_transaction.py\"\n\ntest_logger = logging.getLogger(__name__)\n\n\nclass TestDecisionMakerTransaction(BaseAEATestCase):\n    \"\"\"This class contains the tests for the code-blocks in the agent-vs-aea.md file.\"\"\"\n\n    @classmethod\n    def _patch_logger(cls):\n        cls.patch_logger_info = patch.object(logger, \"info\")\n        cls.mocked_logger_info = cls.patch_logger_info.__enter__()\n\n    @classmethod\n    def _unpatch_logger(cls):\n        cls.mocked_logger_info.__exit__()\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup_class()\n        cls._patch_logger()\n        doc_path = os.path.join(ROOT_DIR, MD_FILE)\n        cls.code_blocks = extract_code_blocks(filepath=doc_path, filter_=\"python\")\n        test_code_path = os.path.join(CUR_PATH, PY_FILE)\n        cls.python_file = extract_python_code(test_code_path)\n\n    def test_read_md_file(self):\n        \"\"\"Test the last code block, that is the full listing of the demo from the Markdown.\"\"\"\n        assert (\n            self.code_blocks[-1] == self.python_file\n        ), \"Files must be exactly the same.\"\n\n    def test_code_blocks_exist(self):\n        \"\"\"Test that all the code-blocks exist in the python file.\"\"\"\n        for blocks in self.code_blocks:\n            assert (\n                blocks in self.python_file\n            ), \"Code-block doesn't exist in the python file.\"\n\n    @pytest.mark.flaky(reruns=MAX_FLAKY_RERUNS)\n    def test_run_end_to_end(self):\n        \"\"\"Run the transaction from the file.\"\"\"\n        try:\n            run()\n        except RuntimeError:\n            test_logger.info(\"RuntimeError: Some transactions have failed\")\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Teardown test.\"\"\"\n        super().teardown_class()\n        cls._unpatch_logger()\n"
  },
  {
    "path": "tests/test_docs/test_docs_http_connection_and_skill.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"\nThis module contain the test for the HTTP connection and skill documentation page.\n\nThe testing strategy is to just check that the Python code reported in\nthe documentation is contained in the http_echo skill.\n\nMoreover, test that the code is compilable/executable.\n\"\"\"\nfrom pathlib import Path\nfrom unittest import mock\n\nfrom tests.conftest import ROOT_DIR\nfrom tests.test_docs.helper import BaseTestMarkdownDocs\n\n\nclass TestHttpConnectionAndSkill(BaseTestMarkdownDocs):\n    \"\"\"Test the skill testing code snippets.\"\"\"\n\n    DOC_PATH = Path(ROOT_DIR, \"docs\", \"http-connection-and-skill.md\")\n    HTTP_ECHO_PATH = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"http_echo\")\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set up the test.\"\"\"\n        super().setup_class()\n\n        assert (\n            len(cls.python_blocks) == 3\n        ), \"this test expected exactly 3 Python blocks.\"\n\n        # read the content of 'handlers.py' and 'dialogues.py' of skill\n        cls.http_echo_handlers_module = (cls.HTTP_ECHO_PATH / \"handlers.py\").read_text()\n        cls.http_echo_dialogues = (cls.HTTP_ECHO_PATH / \"dialogues.py\").read_text()\n\n    def test_handlers_code_snippet(self):\n        \"\"\"Test the 'handlers.py' code snippet.\"\"\"\n        handlers_code_snippet = self.python_blocks[0][\"text\"]\n\n        # the handlers code snippet contains the YOUR_USERNAME placeholder\n        # to be replaced by the user. We need to replace it with 'fetchai'\n        # in order to compare it with the skill 'fetchai/http_echo'.\n        replacement = \"from packages.YOUR_USERNAME.skills.http_echo.dialogues import\"\n        to_be_replaced = \"from packages.fetchai.skills.http_echo.dialogues import\"\n        expected_handlers_code = self.http_echo_handlers_module.replace(\n            to_be_replaced, replacement\n        )\n\n        assert handlers_code_snippet in expected_handlers_code\n\n    def test_dialogues_code_snippet(self):\n        \"\"\"Test the 'dialogues.py' code snippet.\"\"\"\n        dialogues_code_snippet = self.python_blocks[1][\"text\"]\n        expected_dialogues_code = self.http_echo_dialogues\n        assert dialogues_code_snippet in expected_dialogues_code\n\n    @mock.patch(\"requests.get\")\n    @mock.patch(\"requests.post\")\n    def test_requests_code_snippet(self, *_mocks):\n        \"\"\"Test the 'requests' code snippet.\"\"\"\n        _globals, locals_ = {}, {}\n        requests_code_snippet = self.python_blocks[2][\"text\"]\n        exec(requests_code_snippet, _globals, locals_)  # nosec\n\n        assert \"requests\" in locals_\n        assert \"response\" in locals_\n"
  },
  {
    "path": "tests/test_docs/test_docs_protocol.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests for the code-blocks in the protocol.md file.\"\"\"\nfrom enum import Enum\nfrom pathlib import Path\n\nimport mistune\n\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.protocols.fipa.message import FipaMessage\nfrom packages.fetchai.protocols.oef_search.custom_types import OefErrorOperation\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\n\nfrom tests.conftest import ROOT_DIR\nfrom tests.test_docs.helper import compare_enum_classes, compile_and_exec\n\n\nclass TestProtocolDocs:\n    \"\"\"Test the integrity of the code-blocks in skill.md\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Test skill.md\"\"\"\n        markdown_parser = mistune.create_markdown(renderer=mistune.AstRenderer())\n\n        skill_doc_file = Path(ROOT_DIR, \"docs\", \"protocol.md\")\n        doc = markdown_parser(skill_doc_file.read_text())\n        # get only code blocks\n        cls.code_blocks = list(filter(lambda x: x[\"type\"] == \"block_code\", doc))\n\n    def test_custom_protocol(self):\n        \"\"\"Test the code in the 'Custom protocol' section.\"\"\"\n        # this is the offset of code blocks for the section under testing\n        offset = 0\n        locals_dict = {}\n        compile_and_exec(self.code_blocks[offset][\"text\"], locals_dict=locals_dict)\n        ActualPerformative = locals_dict[\"Performative\"]\n        compare_enum_classes(ActualPerformative, DefaultMessage.Performative)\n\n        # load the example of default message of type BYTES\n        compile_and_exec(self.code_blocks[offset + 1][\"text\"], locals_dict=locals_dict)\n\n        # load the definition of the ErrorCode enumeration\n        compile_and_exec(self.code_blocks[offset + 2][\"text\"], locals_dict=locals_dict)\n        ExpectedErrorCode = locals_dict[\"ErrorCode\"]\n        compare_enum_classes(ExpectedErrorCode, DefaultMessage.ErrorCode)\n\n        # load the example of default message of type ERROR\n        _ = compile_and_exec(\n            self.code_blocks[offset + 3][\"text\"], locals_dict=locals_dict\n        )\n\n    def test_oef_search_protocol(self):\n        \"\"\"Test the fetchai/oef_search:1.1.7 protocol documentation.\"\"\"\n        # this is the offset of code blocks for the section under testing\n        offset = 5\n\n        # define a data model and a description\n        locals_dict = {\"Enum\": Enum}\n        compile_and_exec(self.code_blocks[offset][\"text\"], locals_dict=locals_dict)\n        ActualPerformative = locals_dict[\"Performative\"]\n        compare_enum_classes(OefSearchMessage.Performative, ActualPerformative)\n\n        compile_and_exec(self.code_blocks[offset + 1][\"text\"], locals_dict=locals_dict)\n        # mind the indexes: +3 before +2\n        compile_and_exec(self.code_blocks[offset + 3][\"text\"], locals_dict=locals_dict)\n        compile_and_exec(self.code_blocks[offset + 2][\"text\"], locals_dict=locals_dict)\n\n        # test the construction of OEF Search Messages does not contain trivial errors.\n        locals_dict[\"OefSearchMessage\"] = OefSearchMessage\n        compile_and_exec(self.code_blocks[offset + 4][\"text\"], locals_dict=locals_dict)\n        compile_and_exec(self.code_blocks[offset + 5][\"text\"], locals_dict=locals_dict)\n        compile_and_exec(self.code_blocks[offset + 6][\"text\"], locals_dict=locals_dict)\n        compile_and_exec(self.code_blocks[offset + 7][\"text\"], locals_dict=locals_dict)\n        compile_and_exec(self.code_blocks[offset + 8][\"text\"], locals_dict=locals_dict)\n        compile_and_exec(self.code_blocks[offset + 9][\"text\"], locals_dict=locals_dict)\n        # this is just to test that something has actually run\n        assert locals_dict[\"query_data\"] == {\n            \"search_term\": \"country\",\n            \"search_value\": \"UK\",\n            \"constraint_type\": \"==\",\n        }\n\n        # test the definition of OefErrorOperation\n        compile_and_exec(self.code_blocks[offset + 10][\"text\"], locals_dict=locals_dict)\n        ActualOefErrorOperation = locals_dict[\"OefErrorOperation\"]\n        ExpectedOefErrorOperation = OefErrorOperation\n        compare_enum_classes(ExpectedOefErrorOperation, ActualOefErrorOperation)\n\n    def test_fipa_protocol(self):\n        \"\"\"Test the fetchai/fipa:1.1.7 documentation.\"\"\"\n        offset = 15\n        locals_dict = {\"Enum\": Enum}\n        compile_and_exec(self.code_blocks[offset][\"text\"], locals_dict=locals_dict)\n        ActualFipaPerformative = locals_dict[\"Performative\"]\n        ExpectedFipaPerformative = FipaMessage.Performative\n        compare_enum_classes(ExpectedFipaPerformative, ActualFipaPerformative)\n"
  },
  {
    "path": "tests/test_docs/test_docs_skill.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests for the code-blocks in the skill.md file.\"\"\"\nfrom pathlib import Path\n\nimport mistune\n\nfrom aea.skills.behaviours import OneShotBehaviour\nfrom aea.skills.tasks import Task\n\nfrom tests.conftest import ROOT_DIR\nfrom tests.test_docs.helper import compile_and_exec\n\n\nclass TestSkillDocs:\n    \"\"\"Test the integrity of the code-blocks in skill.md\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Test skill.md\"\"\"\n        markdown_parser = mistune.create_markdown(renderer=mistune.AstRenderer())\n\n        skill_doc_file = Path(ROOT_DIR, \"docs\", \"skill.md\")\n        doc = markdown_parser(skill_doc_file.read_text())\n        # get only code blocks\n        cls.code_blocks = list(filter(lambda x: x[\"type\"] == \"block_code\", doc))\n\n    def test_context(self):\n        \"\"\"Test the code in context.\"\"\"\n        block = self.code_blocks[0]\n        expected = \"self.context.outbox.put_message(message=reply)\"\n        assert block[\"text\"].strip() == expected\n        assert block[\"info\"].strip() == \"python\"\n\n    # TODO add tests for new_handlers queue\n\n    def test_hello_world_behaviour(self):\n        \"\"\"Test the code in the 'behaviours.py' section.\"\"\"\n        # here, we test the definition of a custom class\n        offset = 2\n        block = self.code_blocks[offset]\n        text = block[\"text\"]\n\n        # check that the code can be executed\n        code_obj = compile(text, \"fakemodule\", \"exec\")\n        locals_dict = {}\n        exec(code_obj, globals(), locals_dict)  # nosec\n\n        # some consistency check on the behaviour class.\n        HelloWorldBehaviour = locals_dict[\"HelloWorldBehaviour\"]\n        assert issubclass(HelloWorldBehaviour, OneShotBehaviour)\n\n        # here, we test the code example for adding the new custom behaviour to the list\n        # of new behaviours\n        block = self.code_blocks[offset + 1]\n        text = block[\"text\"]\n        assert (\n            text.strip()\n            == 'self.context.new_behaviours.put(HelloWorldBehaviour(name=\"hello_world\", skill_context=self.context))'\n        )\n\n        block = self.code_blocks[offset + 2]\n        assert (\n            block[\"text\"] == \"def hello():\\n\"\n            '    print(\"Hello, World!\")\\n'\n            \"\\n\"\n            'self.context.new_behaviours.put(OneShotBehaviour(act=hello, name=\"hello_world\", skill_context=self.context))\\n'\n        )\n\n    def test_task(self):\n        \"\"\"Test the code blocks of the 'tasks.py' section.\"\"\"\n        # test code of task definition\n        offset = 5\n        block = self.code_blocks[offset]\n        locals_dict = compile_and_exec(block[\"text\"])\n\n        nth_prime_number = locals_dict[\"nth_prime_number\"]\n        assert nth_prime_number(1) == 2\n        assert nth_prime_number(2) == 3\n        assert nth_prime_number(3) == 5\n        assert nth_prime_number(4) == 7\n        LongTask = locals_dict[\"LongTask\"]\n        assert issubclass(LongTask, Task)\n        LongTask()\n"
  },
  {
    "path": "tests/test_docs/test_generic_step_by_step_guide/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests for the code-blocks in thermometer-skills-step-by-step.md file.\"\"\"\n"
  },
  {
    "path": "tests/test_docs/test_generic_step_by_step_guide/test_generic_step_by_step_guide.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests for the code-blocks in thermometer-skills-step-by-step.md file.\"\"\"\n\nimport logging\nimport os\nfrom pathlib import Path\n\nfrom tests.conftest import ROOT_DIR\nfrom tests.test_docs.helper import extract_code_blocks\n\n\nlogger = logging.getLogger(__name__)\n\n\nclass TestDemoDocs:\n    \"\"\"This class contains the tests for the python-blocks in thermometer-skills-step-by-step.md file.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Setup the test class.\"\"\"\n        md_path = os.path.join(ROOT_DIR, \"docs\", \"generic-skills-step-by-step.md\")\n        code_blocks = extract_code_blocks(filepath=md_path, filter_=\"python\")\n        cls.generic_seller = code_blocks[0:11]\n        cls.generic_buyer = code_blocks[11 : len(code_blocks)]\n\n    def test_generic_seller_skill_behaviour(self):\n        \"\"\"Test behaviours.py of generic_seller skill.\"\"\"\n        path = Path(\n            ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"generic_seller\", \"behaviours.py\"\n        )\n        with open(path, \"r\") as file:\n            python_code = file.read()\n            assert self.generic_seller[0] in python_code, \"Code is not identical.\"\n\n    def test_generic_seller_skill_handler(self):\n        \"\"\"Test handlers.py of generic_seller skill.\"\"\"\n        path = Path(\n            ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"generic_seller\", \"handlers.py\"\n        )\n\n        with open(path, \"r\") as file:\n            python_code = file.read()\n        for code_block in self.generic_seller[1:8]:\n            assert code_block in python_code, \"Code is not identical.\"\n\n    def test_generic_seller_skill_strategy(self):\n        \"\"\"Test strategy.py of generic_seller skill.\"\"\"\n        path = Path(\n            ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"generic_seller\", \"strategy.py\"\n        )\n        with open(path, \"r\") as file:\n            python_code = file.read()\n\n        for code_block in self.generic_seller[8:10]:\n            assert code_block in python_code, \"Code is not identical.\"\n\n    def test_generic_seller_skill_dialogues(self):\n        \"\"\"Test dialogues.py of generic_seller skill.\"\"\"\n        path = Path(\n            ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"generic_seller\", \"dialogues.py\"\n        )\n        with open(path, \"r\") as file:\n            python_code = file.read()\n        assert self.generic_seller[10] in python_code, \"Code is not identical.\"\n\n    def test_generic_buyer_skill_behaviour(self):\n        \"\"\"Test that the code blocks exist in the generic_buyer skill.\"\"\"\n        path = Path(\n            ROOT_DIR,\n            \"packages\",\n            \"fetchai\",\n            \"skills\",\n            \"generic_buyer\",\n            \"behaviours.py\",\n        )\n        with open(path, \"r\") as file:\n            python_code = file.read()\n            assert self.generic_buyer[0] in python_code, \"Code is not identical.\"\n\n    def test_generic_buyer_skill_handler(self):\n        \"\"\"Test handlers.py of generic_buyer skill.\"\"\"\n        path = Path(\n            ROOT_DIR,\n            \"packages\",\n            \"fetchai\",\n            \"skills\",\n            \"generic_buyer\",\n            \"handlers.py\",\n        )\n\n        with open(path, \"r\") as file:\n            python_code = file.read()\n        for code_block in self.generic_buyer[1:9]:\n            assert code_block in python_code, \"Code is not identical.\"\n\n    def test_generic_buyer_skill_strategy(self):\n        \"\"\"Test strategy.py correctness of generic_buyer skill.\"\"\"\n        path = Path(\n            ROOT_DIR,\n            \"packages\",\n            \"fetchai\",\n            \"skills\",\n            \"generic_buyer\",\n            \"strategy.py\",\n        )\n\n        with open(path, \"r\") as file:\n            python_code = file.read()\n        for code_block in self.generic_buyer[9:13]:\n            assert code_block in python_code, \"Code is not identical.\"\n\n    def test_generic_buyer_skill_dialogues(self):\n        \"\"\"Test dialogues.py of generic_buyer skill.\"\"\"\n        path = Path(\n            ROOT_DIR,\n            \"packages\",\n            \"fetchai\",\n            \"skills\",\n            \"generic_buyer\",\n            \"dialogues.py\",\n        )\n        with open(path, \"r\") as file:\n            python_code = file.read()\n            assert self.generic_buyer[13] in python_code, \"Code is not identical.\"\n"
  },
  {
    "path": "tests/test_docs/test_generic_storage.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests for the content of generic-storage.md file.\"\"\"\nimport inspect\nimport re\nfrom pathlib import Path\n\nfrom aea.helpers.storage.generic_storage import SyncCollection\nfrom aea.skills.behaviours import TickerBehaviour\n\nfrom tests.conftest import ROOT_DIR\nfrom tests.test_docs.helper import BaseTestMarkdownDocs\n\n\nclass TestGenericStorage(BaseTestMarkdownDocs):\n    \"\"\"Test generic-storage.md documentation.\"\"\"\n\n    DOC_PATH = Path(ROOT_DIR, \"docs\", \"generic-storage.md\")\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"\n        Set up test.\n\n        We test only the signatures and the\n        docstrings of 'SyncCollection' methods. Hence,\n        we need to remove the return statement.\n        \"\"\"\n        super().setup_class()\n        cls.content = inspect.getsource(SyncCollection)\n        cls.content = re.sub(\"\\n +return.*\", \"\", cls.content)\n\n    def test_storage_abstract_methods(self):\n        \"\"\"\n        Test storage abstract methods.\n\n        Note: the block index of the abstract methods is 0.\n        Please check generic-storage.md\n        \"\"\"\n        block_index = 1\n        assert self.code_blocks[block_index][\"text\"] in self.content\n\n    def test_test_behaviour(self):\n        \"\"\"Test that the 'TestBehaviour' code is compilable.\"\"\"\n        block_index = 2\n        code = self.code_blocks[block_index][\"text\"]\n        exec(code, {}, dict(TickerBehaviour=TickerBehaviour))  # nosec\n"
  },
  {
    "path": "tests/test_docs/test_language_agnostic_definition.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests for the content of language-agnostic-definition.md file.\"\"\"\nfrom pathlib import Path\nfrom typing import Dict\n\nfrom aea import AEA_DIR\nfrom aea.configurations.data_types import PublicId\n\nfrom tests.conftest import ROOT_DIR\nfrom tests.test_docs.helper import BaseTestMarkdownDocs\n\n\nMAIL_BASE_PROTO = Path(AEA_DIR) / \"mail\" / \"base.proto\"\nDEFAULT_MESSAGE_PROTO = (\n    Path(ROOT_DIR) / \"packages\" / \"fetchai\" / \"protocols\" / \"default\" / \"default.proto\"\n)\n\n\nclass TestLanguageAgnosticDocs(BaseTestMarkdownDocs):\n    \"\"\"Test the integrity of the language agnostic definitions in docs.\"\"\"\n\n    DOC_PATH = Path(ROOT_DIR, \"docs\", \"language-agnostic-definition.md\")\n\n    @classmethod\n    def _proto_snippet_selector(cls, block: Dict) -> bool:\n        return block[\"type\"] == \"block_code\" and block[\"info\"].strip() == \"proto\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set up the test.\"\"\"\n        super().setup_class()\n        cls.code_blocks = list(filter(cls._proto_snippet_selector, cls.flat_blocks))\n        cls.actual_mail_base_file_content = MAIL_BASE_PROTO.read_text()\n        cls.actual_default_message_file_content = DEFAULT_MESSAGE_PROTO.read_text()\n\n    def test_envelope_code_snippet(self):\n        \"\"\"\n        Test the Envelope protobuf code snippet.\n\n        It requires treating the preamble lines separately,\n        because aea/mail/base.proto doesn't follow\n        the same order of language-agnostic-definition.md file.\n        \"\"\"\n        block = self.code_blocks[0]\n        assert block[\"info\"].strip() == \"proto\"\n\n        lines = block[\"text\"].splitlines()\n        first_part, second_part = \"\\n\".join(lines[:3]), \"\\n\".join(lines[3:])\n\n        assert first_part in self.actual_mail_base_file_content\n        assert second_part in self.actual_mail_base_file_content\n\n    def test_dialogue_message_code_snippet(self):\n        \"\"\"\n        Test the DialogueMessage protobuf code snippet.\n\n        It requires treating the preamble lines separately,\n        because aea/mail/base.proto doesn't follow\n        the same order of language-agnostic-definition.md file.\n        \"\"\"\n        block = self.code_blocks[1]\n        assert block[\"info\"].strip() == \"proto\"\n        assert block[\"text\"] in self.actual_mail_base_file_content\n\n    def test_public_id_regular_expression(self):\n        \"\"\"Test public id regular expression is the same.\"\"\"\n        expected_regex = PublicId.PUBLIC_ID_REGEX\n        assert expected_regex in self.doc_content\n\n    def test_default_message_code_snippet(self):\n        \"\"\"Test DefaultMessage protobuf code snippet.\"\"\"\n        block = self.code_blocks[2]\n        assert block[\"info\"].strip() == \"proto\"\n        assert block[\"text\"] in self.actual_default_message_file_content, Exception(\n            [block[\"text\"], self.actual_default_message_file_content]\n        )\n"
  },
  {
    "path": "tests/test_docs/test_ledger_integration.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests for the content of ledger-integration.md file.\"\"\"\nfrom importlib import import_module\nfrom pathlib import Path\nfrom unittest import mock\nfrom unittest.mock import MagicMock\n\nfrom aea.crypto.registries import (\n    crypto_registry,\n    faucet_apis_registry,\n    ledger_apis_registry,\n)\n\nfrom tests.conftest import ROOT_DIR\nfrom tests.test_docs.helper import BasePythonMarkdownDocs\n\n\ndef _import_module_mock(arg):\n    \"\"\"\n    Mock importlib.import_module only if argument is a dummy one: 'some.dotted.path'.\n\n    This choice is tight to the code examples in 'ledger-integration.md'.\n    It helps to tests the cases in which the import path is not a fake one.\n    \"\"\"\n    if arg.startswith(\"some.dotted.path\"):\n        return MagicMock()\n    return import_module(arg)\n\n\n# we mock only if the import is from dummy import path like \"some.dotted.path\".\n@mock.patch(\"importlib.import_module\", side_effect=_import_module_mock)\n@mock.patch(\"setuptools.setup\")\nclass TestLedgerIntegration(BasePythonMarkdownDocs):\n    \"\"\"Test the ledger integration code snippets.\"\"\"\n\n    DOC_PATH = Path(ROOT_DIR, \"docs\", \"ledger-integration.md\")\n\n    def _assert_isinstance(self, locals_key, cls_or_str, locals_):\n        \"\"\"Assert that the member of 'locals' is an instance of a class.\"\"\"\n        assert locals_key in locals_\n        obj = locals_[locals_key]\n\n        if type(cls_or_str) == type:\n            assert isinstance(obj, cls_or_str)\n        else:\n            assert obj.__class__.__name__ == cls_or_str\n\n    def _assert(self, locals_, *mocks):\n        \"\"\"Assert code outputs.\"\"\"\n        self._assert_isinstance(\"fetchai_crypto\", \"FetchAICrypto\", locals_)\n        self._assert_isinstance(\"fetchai_ledger_api\", \"FetchAIApi\", locals_)\n        self._assert_isinstance(\"fetchai_faucet_api\", \"FetchAIFaucetApi\", locals_)\n        self._assert_isinstance(\"my_ledger_crypto\", MagicMock, locals_)\n        self._assert_isinstance(\"my_ledger_api\", MagicMock, locals_)\n        self._assert_isinstance(\"my_faucet_api\", MagicMock, locals_)\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear down the test.\"\"\"\n        crypto_registry.specs.pop(\"my_ledger_id\")\n        ledger_apis_registry.specs.pop(\"my_ledger_id\")\n        faucet_apis_registry.specs.pop(\"my_ledger_id\")\n"
  },
  {
    "path": "tests/test_docs/test_multiagent_manager.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests for the content of multi-agent-manager.md file.\"\"\"\nimport os\nimport shutil\nimport tempfile\nfrom importlib import import_module\nfrom pathlib import Path\nfrom unittest.mock import MagicMock\n\nimport pytest\n\nfrom tests.conftest import MAX_FLAKY_RERUNS, PACKAGES_DIR, ROOT_DIR\nfrom tests.test_docs.helper import BasePythonMarkdownDocs\n\n\ndef _import_module_mock(arg):\n    \"\"\"\n    Mock importlib.import_module only if argument is a dummy one: 'some.dotted.path'.\n\n    This choice is tight to the code examples in 'ledger-integration.md'.\n    It helps to tests the cases in which the import path is not a fake one.\n    \"\"\"\n    if arg.startswith(\"some.dotted.path\"):\n        return MagicMock()\n    return import_module(arg)\n\n\n@pytest.mark.flaky(reruns=MAX_FLAKY_RERUNS)  # flaky on Windows\nclass TestMultiAgentManager(BasePythonMarkdownDocs):\n    \"\"\"Test the ledger integration code snippets.\"\"\"\n\n    DOC_PATH = Path(ROOT_DIR, \"docs\", \"multi-agent-manager.md\")\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set up the class.\"\"\"\n        super().setup_class()\n        cls.old_cwd = os.getcwd()\n        cls.temp_dir = tempfile.mkdtemp()\n        shutil.copytree(PACKAGES_DIR, Path(cls.temp_dir, \"packages\"))\n        os.chdir(cls.temp_dir)\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Teardown class.\"\"\"\n        os.chdir(cls.old_cwd)\n        shutil.rmtree(cls.temp_dir)\n"
  },
  {
    "path": "tests/test_docs/test_multiplexer_standalone/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests for the code-blocks in the multiplexer-standalone.md file.\"\"\"\n"
  },
  {
    "path": "tests/test_docs/test_multiplexer_standalone/multiplexer_standalone.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the full script from the multiplexer-standalone.md file.\"\"\"\n\nimport os\nimport time\nfrom copy import copy\nfrom threading import Thread\nfrom typing import Optional\n\nfrom aea.configurations.base import ConnectionConfig\nfrom aea.helpers.file_io import write_with_lock\nfrom aea.identity.base import Identity\nfrom aea.mail.base import Envelope\nfrom aea.multiplexer import Multiplexer\n\nfrom packages.fetchai.connections.stub.connection import StubConnection\nfrom packages.fetchai.protocols.default.message import DefaultMessage\n\n\nINPUT_FILE = \"input.txt\"\nOUTPUT_FILE = \"output.txt\"\n\n\ndef run():\n    \"\"\"Run demo.\"\"\"\n\n    # Ensure the input and output files do not exist initially\n    if os.path.isfile(INPUT_FILE):\n        os.remove(INPUT_FILE)\n    if os.path.isfile(OUTPUT_FILE):\n        os.remove(OUTPUT_FILE)\n\n    # create the connection and multiplexer objects\n    configuration = ConnectionConfig(\n        input_file=INPUT_FILE,\n        output_file=OUTPUT_FILE,\n        connection_id=StubConnection.connection_id,\n    )\n    stub_connection = StubConnection(\n        configuration=configuration,\n        data_dir=\".\",\n        identity=Identity(\"some_agent\", \"some_address\", \"some_public_key\"),\n    )\n    multiplexer = Multiplexer([stub_connection], protocols=[DefaultMessage])\n    try:\n        # Set the multiplexer running in a different thread\n        t = Thread(target=multiplexer.connect)\n        t.start()\n\n        # Wait for everything to start up\n        for _ in range(20):\n            if multiplexer.is_connected:\n                break\n            time.sleep(1)\n        else:\n            raise Exception(\"Not connected\")\n\n        # Create a message inside an envelope and get the stub connection to pass it into the multiplexer\n        message_text = (\n            \"multiplexer,some_agent,fetchai/default:1.0.0,\\x08\\x01*\\x07\\n\\x05hello,\"\n        )\n        with open(INPUT_FILE, \"w\") as f:\n            write_with_lock(f, message_text)\n\n        # Wait for the envelope to get processed\n        for _ in range(20):\n            if not multiplexer.in_queue.empty():\n                break\n            time.sleep(1)\n        else:\n            raise Exception(\"No message!\")\n\n        # get the envelope\n        envelope = multiplexer.get()  # type: Optional[Envelope]\n        assert envelope is not None\n\n        # Inspect its contents\n        print(\n            \"Envelope received by Multiplexer: sender={}, to={}, protocol_specification_id={}, message={}\".format(\n                envelope.sender,\n                envelope.to,\n                envelope.protocol_specification_id,\n                envelope.message,\n            )\n        )\n\n        # Create a mirrored response envelope\n        response_envelope = copy(envelope)\n        response_envelope.to = envelope.sender\n        response_envelope.sender = envelope.to\n\n        # Send the envelope back\n        multiplexer.put(response_envelope)\n\n        # Read the output envelope generated by the multiplexer\n        with open(OUTPUT_FILE, \"r\") as f:\n            print(\"Envelope received from Multiplexer: \" + f.readline())\n    finally:\n        # Shut down the multiplexer\n        multiplexer.disconnect()\n        t.join()\n\n\nif __name__ == \"__main__\":\n    run()\n"
  },
  {
    "path": "tests/test_docs/test_multiplexer_standalone/test_multiplexer_standalone.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests for the code-blocks in the multiplexer-standalone.md file.\"\"\"\nimport os\nfrom pathlib import Path\n\nfrom aea.test_tools.test_cases import BaseAEATestCase\n\nfrom tests.conftest import CUR_PATH, ROOT_DIR\nfrom tests.test_docs.helper import extract_code_blocks, extract_python_code\nfrom tests.test_docs.test_multiplexer_standalone.multiplexer_standalone import run\n\n\nMD_FILE = \"docs/multiplexer-standalone.md\"\nPY_FILE = \"test_docs/test_multiplexer_standalone/multiplexer_standalone.py\"\n\n\nclass TestMultiplexerStandAlone(BaseAEATestCase):\n    \"\"\"This class contains the tests for the code-blocks in the build-aea-programmatically.md file.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup_class()\n        doc_path = os.path.join(ROOT_DIR, MD_FILE)\n        cls.code_blocks = extract_code_blocks(filepath=doc_path, filter_=\"python\")\n        test_code_path = os.path.join(CUR_PATH, PY_FILE)\n        cls.python_file = extract_python_code(test_code_path)\n\n    def test_read_md_file(self):\n        \"\"\"Read the code blocks. Last block should be the whole code.\"\"\"\n        assert (\n            self.code_blocks[-1] == self.python_file\n        ), \"Files must be exactly the same.\"\n\n    def test_run_agent(self):\n        \"\"\"Run the agent from the file.\"\"\"\n        run()\n        assert os.path.exists(Path(self.t, \"input.txt\"))\n        assert os.path.exists(Path(self.t, \"output.txt\"))\n\n        message_text = (\n            \"some_agent,multiplexer,fetchai/default:1.0.0,\\x08\\x01*\\x07\\n\\x05hello,\"\n        )\n        path = os.path.join(str(self.t), \"output.txt\")\n        with open(path, \"r\", encoding=\"utf-8\") as file:\n            msg = file.read()\n\n        assert msg == message_text, \"The messages must be identical.\"\n\n    def test_code_blocks_exist(self):\n        \"\"\"Test that all the code-blocks exist in the python file.\"\"\"\n        for blocks in self.code_blocks:\n            assert (\n                blocks in self.python_file\n            ), \"Code-block doesn't exist in the python file.\"\n"
  },
  {
    "path": "tests/test_docs/test_orm_integration/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This package contains the tests for the orm-integration.md guide.\"\"\"\n"
  },
  {
    "path": "tests/test_docs/test_orm_integration/orm_seller_strategy.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the strategy class.\"\"\"\n\nimport json\nimport random  # nosec\nimport time\nfrom typing import Dict\n\nimport sqlalchemy as db\n\nfrom packages.fetchai.skills.generic_seller.strategy import GenericStrategy\n\n\nclass Strategy(GenericStrategy):\n    \"\"\"This class defines a strategy for the agent.\"\"\"\n\n    def __init__(self, **kwargs) -> None:\n        \"\"\"\n        Initialize the strategy of the agent.\n\n        :param register_as: determines whether the agent registers as seller, buyer or both\n        :param search_for: determines whether the agent searches for sellers, buyers or both\n\n        :return: None\n        \"\"\"\n        self._db_engine = db.create_engine(\"sqlite:///genericdb.db\")\n        self._tbl = self.create_database_and_table()\n        self.insert_data()\n        super().__init__(**kwargs)\n\n    def collect_from_data_source(self) -> Dict[str, str]:\n        \"\"\"Implement the logic to collect data.\"\"\"\n        connection = self._db_engine.connect()\n        query = db.select([self._tbl])\n        result_proxy = connection.execute(query)\n        data_points = result_proxy.fetchall()\n        return {\"data\": json.dumps(list(map(tuple, data_points)))}\n\n    def create_database_and_table(self):\n        \"\"\"Creates a database and a table to store the data if not exists.\"\"\"\n        metadata = db.MetaData()\n\n        tbl = db.Table(\n            \"data\",\n            metadata,\n            db.Column(\"timestamp\", db.Integer()),\n            db.Column(\"temprature\", db.String(255), nullable=False),\n        )\n        metadata.create_all(self._db_engine)\n        return tbl\n\n    def insert_data(self):\n        \"\"\"Insert data in the database.\"\"\"\n        connection = self._db_engine.connect()\n        for _ in range(10):\n            query = db.insert(self._tbl).values(  # nosec\n                timestamp=time.time(), temprature=str(random.randrange(10, 25))\n            )\n            connection.execute(query)\n"
  },
  {
    "path": "tests/test_docs/test_orm_integration/test_orm_integration.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests for the orm-integration.md guide.\"\"\"\nfrom pathlib import Path\nfrom random import uniform\n\nimport mistune\nimport pytest\nimport yaml\nfrom aea_ledger_fetchai import FetchAICrypto\n\nfrom aea.test_tools.test_cases import AEATestCaseManyFlaky\n\nfrom packages.fetchai.connections.p2p_libp2p.connection import LIBP2P_SUCCESS_MESSAGE\n\nfrom tests.conftest import (\n    FETCHAI_PRIVATE_KEY_FILE,\n    FETCHAI_PRIVATE_KEY_FILE_CONNECTION,\n    MAX_FLAKY_RERUNS_INTEGRATION,\n    NON_FUNDED_FETCHAI_PRIVATE_KEY_1,\n    NON_GENESIS_CONFIG,\n    ROOT_DIR,\n    wait_for_localhost_ports_to_close,\n)\n\n\nseller_strategy_replacement = \"\"\"models:\n  default_dialogues:\n    args: {}\n    class_name: DefaultDialogues\n  fipa_dialogues:\n    args: {}\n    class_name: FipaDialogues\n  ledger_api_dialogues:\n    args: {}\n    class_name: LedgerApiDialogues\n  oef_search_dialogues:\n    args: {}\n    class_name: OefSearchDialogues\n  strategy:\n    args:\n      currency_id: FET\n      data_for_sale:\n        temperature: 26\n      has_data_source: false\n      is_ledger_tx: true\n      ledger_id: fetchai\n      location:\n        latitude: 51.5194\n        longitude: 0.127\n      service_data:\n        key: seller_service\n        value: thermometer_data\n      service_id: thermometer_data\n      unit_price: 10\n    class_name: Strategy\ndependencies:\n  SQLAlchemy: {}\"\"\"\n\nbuyer_strategy_replacement = \"\"\"models:\n  default_dialogues:\n    args: {}\n    class_name: DefaultDialogues\n  fipa_dialogues:\n    args: {}\n    class_name: FipaDialogues\n  ledger_api_dialogues:\n    args: {}\n    class_name: LedgerApiDialogues\n  oef_search_dialogues:\n    args: {}\n    class_name: OefSearchDialogues\n  signing_dialogues:\n    args: {}\n    class_name: SigningDialogues\n  strategy:\n    args:\n      currency_id: FET\n      is_ledger_tx: true\n      ledger_id: fetchai\n      location:\n        latitude: 51.5194\n        longitude: 0.127\n      max_negotiations: 1\n      max_tx_fee: 3550000000000000\n      max_unit_price: 20\n      search_query:\n        constraint_type: ==\n        search_key: seller_service\n        search_value: thermometer_data\n      search_radius: 5.0\n      service_id: thermometer_data\n    class_name: Strategy\"\"\"\n\n\nORM_SELLER_STRATEGY_PATH = Path(\n    ROOT_DIR, \"tests\", \"test_docs\", \"test_orm_integration\", \"orm_seller_strategy.py\"\n)\n\n\n@pytest.mark.integration\nclass TestOrmIntegrationDocs(AEATestCaseManyFlaky):\n    \"\"\"This class contains the tests for the orm-integration.md guide.\"\"\"\n\n    @pytest.mark.flaky(reruns=MAX_FLAKY_RERUNS_INTEGRATION)\n    def test_orm_integration_docs_example(self):\n        \"\"\"Run the weather skills sequence.\"\"\"\n        seller_aea_name = \"my_thermometer_aea\"\n        buyer_aea_name = \"my_thermometer_client\"\n        self.create_agents(seller_aea_name, buyer_aea_name)\n\n        default_routing = {\n            \"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n            \"fetchai/oef_search:1.1.7\": \"fetchai/soef:0.27.6\",\n        }\n\n        # generate random location\n        location = {\n            \"latitude\": round(uniform(-90, 90), 2),  # nosec\n            \"longitude\": round(uniform(-180, 180), 2),  # nosec\n        }\n\n        # Setup seller\n        self.set_agent_context(seller_aea_name)\n        self.add_item(\"connection\", \"fetchai/p2p_libp2p:0.27.5\")\n        self.add_item(\"connection\", \"fetchai/soef:0.27.6\")\n        self.set_config(\"agent.default_connection\", \"fetchai/p2p_libp2p:0.27.5\")\n        self.add_item(\"connection\", \"fetchai/ledger:0.21.5\")\n        self.add_item(\"skill\", \"fetchai/thermometer:0.27.6\")\n        setting_path = \"agent.default_routing\"\n        self.nested_set_config(setting_path, default_routing)\n        # ejecting changes author and version!\n        self.eject_item(\"skill\", \"fetchai/thermometer:0.27.6\")\n        seller_skill_config_replacement = yaml.safe_load(seller_strategy_replacement)\n        self.nested_set_config(\n            \"skills.thermometer.models.strategy.args\",\n            seller_skill_config_replacement[\"models\"][\"strategy\"][\"args\"],\n        )\n        self.nested_set_config(\n            \"skills.thermometer.dependencies\",\n            seller_skill_config_replacement[\"dependencies\"],\n        )\n        # Replace the seller strategy\n        seller_stategy_path = Path(\n            seller_aea_name,\n            \"skills\",\n            \"thermometer\",\n            \"strategy.py\",\n        )\n        self.replace_file_content(ORM_SELLER_STRATEGY_PATH, seller_stategy_path)\n        self.fingerprint_item(\n            \"skill\",\n            \"{}/thermometer:0.1.0\".format(self.author),\n        )\n        self.run_install()\n\n        # add keys\n        self.generate_private_key(FetchAICrypto.identifier)\n        self.generate_private_key(\n            FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE_CONNECTION\n        )\n        self.add_private_key(FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE)\n        self.add_private_key(\n            FetchAICrypto.identifier,\n            FETCHAI_PRIVATE_KEY_FILE_CONNECTION,\n            connection=True,\n        )\n        self.replace_private_key_in_file(\n            NON_FUNDED_FETCHAI_PRIVATE_KEY_1, FETCHAI_PRIVATE_KEY_FILE_CONNECTION\n        )\n        setting_path = \"vendor.fetchai.connections.p2p_libp2p.config.ledger_id\"\n        self.set_config(setting_path, FetchAICrypto.identifier)\n\n        # replace location\n        setting_path = \"skills.thermometer.models.strategy.args.location\"\n        self.nested_set_config(setting_path, location)\n\n        # Setup Buyer\n        self.set_agent_context(buyer_aea_name)\n        self.add_item(\"connection\", \"fetchai/p2p_libp2p:0.27.5\")\n        self.add_item(\"connection\", \"fetchai/soef:0.27.6\")\n        self.set_config(\"agent.default_connection\", \"fetchai/p2p_libp2p:0.27.5\")\n        self.add_item(\"connection\", \"fetchai/ledger:0.21.5\")\n        self.add_item(\"skill\", \"fetchai/thermometer_client:0.26.6\")\n        setting_path = \"agent.default_routing\"\n        self.nested_set_config(setting_path, default_routing)\n        buyer_skill_config_replacement = yaml.safe_load(buyer_strategy_replacement)\n        self.nested_set_config(\n            \"vendor.fetchai.skills.thermometer_client.models.strategy.args\",\n            buyer_skill_config_replacement[\"models\"][\"strategy\"][\"args\"],\n        )\n        self.run_install()\n\n        # add keys\n        self.generate_private_key(FetchAICrypto.identifier)\n        self.generate_private_key(\n            FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE_CONNECTION\n        )\n        self.add_private_key(FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE)\n        self.add_private_key(\n            FetchAICrypto.identifier,\n            FETCHAI_PRIVATE_KEY_FILE_CONNECTION,\n            connection=True,\n        )\n\n        # fund key\n        self.generate_wealth(FetchAICrypto.identifier)\n\n        # set p2p configs\n        setting_path = \"vendor.fetchai.connections.p2p_libp2p.config\"\n        self.nested_set_config(setting_path, NON_GENESIS_CONFIG)\n\n        # replace location\n        setting_path = (\n            \"vendor.fetchai.skills.thermometer_client.models.strategy.args.location\"\n        )\n        self.nested_set_config(setting_path, location)\n\n        # Fire the sub-processes and the threads.\n        self.set_agent_context(seller_aea_name)\n        self.run_cli_command(\"build\", cwd=self._get_cwd())\n        self.run_cli_command(\"issue-certificates\", cwd=self._get_cwd())\n        seller_aea_process = self.run_agent()\n\n        check_strings = (\n            \"Starting libp2p node...\",\n            \"Connecting to libp2p node...\",\n            \"Successfully connected to libp2p node!\",\n            LIBP2P_SUCCESS_MESSAGE,\n        )\n        missing_strings = self.missing_from_output(\n            seller_aea_process, check_strings, timeout=30, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in thermometer_aea output.\".format(missing_strings)\n\n        self.set_agent_context(buyer_aea_name)\n        self.run_cli_command(\"build\", cwd=self._get_cwd())\n        self.run_cli_command(\"issue-certificates\", cwd=self._get_cwd())\n        buyer_aea_process = self.run_agent()\n\n        check_strings = (\n            \"Starting libp2p node...\",\n            \"Connecting to libp2p node...\",\n            \"Successfully connected to libp2p node!\",\n            LIBP2P_SUCCESS_MESSAGE,\n        )\n        missing_strings = self.missing_from_output(\n            buyer_aea_process,\n            check_strings,\n            timeout=30,\n            is_terminating=False,\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in thermometer_client_aea output.\".format(\n            missing_strings\n        )\n\n        check_strings = (\n            \"registering agent on SOEF.\",\n            \"registering agent's service on the SOEF.\",\n            \"registering agent's personality genus on the SOEF.\",\n            \"registering agent's personality classification on the SOEF.\",\n            \"received CFP from sender=\",\n            \"sending a PROPOSE with proposal=\",\n            \"received ACCEPT from sender=\",\n            \"sending MATCH_ACCEPT_W_INFORM to sender=\",\n            \"received INFORM from sender=\",\n            \"checking whether transaction=\",\n            \"transaction confirmed, sending data=\",\n        )\n        missing_strings = self.missing_from_output(\n            seller_aea_process, check_strings, timeout=120, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in seller_aea output.\".format(missing_strings)\n\n        check_strings = (\n            \"found agents=\",\n            \"sending CFP to agent=\",\n            \"received proposal=\",\n            \"accepting the proposal from sender=\",\n            \"received MATCH_ACCEPT_W_INFORM from sender=\",\n            \"requesting transfer transaction from ledger api for message=\",\n            \"received raw transaction=\",\n            \"proposing the transaction to the decision maker. Waiting for confirmation ...\",\n            \"transaction signing was successful.\",\n            \"sending transaction to ledger.\",\n            \"transaction was successfully submitted. Transaction digest=\",\n            \"informing counterparty=\",\n            \"received INFORM from sender=\",\n            \"received the following data=\",\n        )\n        missing_strings = self.missing_from_output(\n            buyer_aea_process, check_strings, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in buyer_aea output.\".format(missing_strings)\n\n        self.terminate_agents(seller_aea_process, buyer_aea_process)\n        assert (\n            self.is_successfully_terminated()\n        ), \"Agents weren't successfully terminated.\"\n        wait_for_localhost_ports_to_close([9000, 9001])\n\n\ndef test_strategy_consistency():\n    \"\"\"Test that the seller strategy specified in the documentation is the same we use in the tests.\"\"\"\n    markdown_parser = mistune.create_markdown(renderer=mistune.AstRenderer())\n\n    skill_doc_file = Path(ROOT_DIR, \"docs\", \"orm-integration.md\")\n    doc = markdown_parser(skill_doc_file.read_text())\n    # get only code blocks\n    code_blocks = list(filter(lambda x: x[\"type\"] == \"block_code\", doc))\n    python_code_blocks = list(\n        filter(\n            lambda x: x[\"info\"] is not None and x[\"info\"].strip() == \"python\",\n            code_blocks,\n        )\n    )\n\n    strategy_file_content = ORM_SELLER_STRATEGY_PATH.read_text()\n    for python_code_block in python_code_blocks:\n        if not python_code_block[\"text\"] in strategy_file_content:\n            pytest.fail(\n                \"Code block not present in strategy file:\\n{}\".format(\n                    python_code_block[\"text\"]\n                )\n            )\n"
  },
  {
    "path": "tests/test_docs/test_query_language.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests for the content of query-language.md file.\"\"\"\nfrom pathlib import Path\nfrom unittest import mock\nfrom unittest.mock import MagicMock\n\nfrom tests.conftest import ROOT_DIR\nfrom tests.test_docs.helper import BasePythonMarkdownDocs\n\n\n@mock.patch(\"aea.helpers.search.models.Query.check_validity\")\nclass TestQueryLanguage(BasePythonMarkdownDocs):\n    \"\"\"Test the data models code snippets.\"\"\"\n\n    DOC_PATH = Path(ROOT_DIR, \"docs\", \"query-language.md\")\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set up the test.\"\"\"\n        super().setup_class()\n        cls.locals[\"book_model\"] = MagicMock()\n"
  },
  {
    "path": "tests/test_docs/test_quickstart.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests for the content of quickstart.md file.\"\"\"\nfrom pathlib import Path\n\nimport pytest\n\nfrom packages.fetchai.protocols.default.message import DefaultMessage\n\nfrom tests.conftest import ROOT_DIR\nfrom tests.test_docs.helper import BasePythonMarkdownDocs, extract_code_blocks\n\n\nclass TestQuickstartTest(BasePythonMarkdownDocs):\n    \"\"\"Test the quickstart test.\"\"\"\n\n    DOC_PATH = Path(ROOT_DIR, \"docs\", \"quickstart.md\")\n\n\n@pytest.mark.skip\ndef test_correct_echo_string():\n    \"\"\"Test the echo string in the quickstart is using the correct protocol specification id.\"\"\"\n    file_path = Path(ROOT_DIR, \"docs\", \"quickstart.md\")\n    bash_code_blocks = extract_code_blocks(filepath=file_path, filter_=\"bash\")\n    echo_bloc = bash_code_blocks[24]\n    default_protocol_spec_id = echo_bloc.split(\",\")[2]\n    assert (\n        str(DefaultMessage.protocol_specification_id) == default_protocol_spec_id\n    ), \"Spec ids not matching!\"\n"
  },
  {
    "path": "tests/test_docs/test_simple_oef_usage.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests for the content of simple-oef-usage.md file.\"\"\"\nfrom pathlib import Path\n\nfrom aea.helpers.search.models import Description\n\nfrom packages.fetchai.protocols.oef_search import OefSearchMessage\n\nfrom tests.conftest import ROOT_DIR\nfrom tests.test_docs.helper import BasePythonMarkdownDocs\n\n\nclass TestSimpleOefUsage(BasePythonMarkdownDocs):\n    \"\"\"Test the simple OEF usage code snippets.\"\"\"\n\n    DOC_PATH = Path(ROOT_DIR, \"docs\", \"simple-oef-usage.md\")\n\n    def _assert(self, locals_, *mocks):\n        \"\"\"Assert executed code.\"\"\"\n        assert isinstance(locals_[\"message\"], OefSearchMessage)\n        assert isinstance(locals_[\"service_description\"], Description)\n"
  },
  {
    "path": "tests/test_docs/test_skill_guide/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests for the code-blocks in the skill-guide.md file.\"\"\"\n"
  },
  {
    "path": "tests/test_docs/test_skill_guide/test_skill_guide.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests for the code-blocks in the skill-guide.md file.\"\"\"\n\nimport filecmp\nimport os\nfrom pathlib import Path\nfrom random import uniform\n\nimport pytest\nfrom aea_ledger_fetchai import FetchAICrypto\n\nfrom aea import AEA_DIR\nfrom aea.configurations.base import DEFAULT_VERSION\nfrom aea.test_tools.test_cases import AEATestCaseManyFlaky\n\nfrom packages.fetchai.connections.p2p_libp2p.connection import LIBP2P_SUCCESS_MESSAGE\n\nfrom tests.conftest import (\n    AUTHOR,\n    FETCHAI_PRIVATE_KEY_FILE,\n    FETCHAI_PRIVATE_KEY_FILE_CONNECTION,\n    MAX_FLAKY_RERUNS_INTEGRATION,\n    NON_FUNDED_FETCHAI_PRIVATE_KEY_1,\n    NON_GENESIS_CONFIG,\n    ROOT_DIR,\n    wait_for_localhost_ports_to_close,\n)\nfrom tests.test_docs.helper import extract_code_blocks\n\n\nMD_FILE = \"docs/skill-guide.md\"\n\n\n@pytest.mark.integration\nclass TestBuildSkill(AEATestCaseManyFlaky):\n    \"\"\"This class contains the tests for the code-blocks in the skill-guide.md file.\"\"\"\n\n    capture_log = True\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup_class()\n        cls.doc_path = os.path.join(ROOT_DIR, MD_FILE)\n        cls.code_blocks = extract_code_blocks(filepath=cls.doc_path, filter_=\"python\")\n\n    @pytest.mark.flaky(reruns=MAX_FLAKY_RERUNS_INTEGRATION)\n    def test_update_skill_and_run(self):\n        \"\"\"Test that the resource folder contains scaffold handlers.py module.\"\"\"\n        assert self.code_blocks != [], \"File must not be empty.\"\n\n        self.initialize_aea(AUTHOR)\n\n        # generate random location\n        location = {\n            \"latitude\": round(uniform(-90, 90), 2),  # nosec\n            \"longitude\": round(uniform(-180, 180), 2),  # nosec\n        }\n\n        simple_service_registration_aea = \"simple_service_registration\"\n        self.fetch_agent(\n            \"fetchai/simple_service_registration:0.32.5\",\n            simple_service_registration_aea,\n        )\n        self.set_agent_context(simple_service_registration_aea)\n        # add non-funded key\n        self.generate_private_key(FetchAICrypto.identifier)\n        self.generate_private_key(\n            FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE_CONNECTION\n        )\n        self.add_private_key(FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE)\n        self.add_private_key(\n            FetchAICrypto.identifier,\n            FETCHAI_PRIVATE_KEY_FILE_CONNECTION,\n            connection=True,\n        )\n        self.replace_private_key_in_file(\n            NON_FUNDED_FETCHAI_PRIVATE_KEY_1, FETCHAI_PRIVATE_KEY_FILE_CONNECTION\n        )\n        setting_path = \"vendor.fetchai.connections.p2p_libp2p.config.ledger_id\"\n        self.set_config(setting_path, FetchAICrypto.identifier)\n\n        default_routing = {\n            \"fetchai/oef_search:1.1.7\": \"fetchai/soef:0.27.6\",\n        }\n\n        # replace location\n        setting_path = \"vendor.fetchai.skills.simple_service_registration.models.strategy.args.location\"\n        self.nested_set_config(setting_path, location)\n\n        search_aea = \"search_aea\"\n        self.create_agents(search_aea)\n        self.set_agent_context(search_aea)\n        skill_name = \"my_search\"\n        skill_id = AUTHOR + \"/\" + skill_name + \":\" + DEFAULT_VERSION\n        self.scaffold_item(\"skill\", skill_name)\n        self.add_item(\"connection\", \"fetchai/p2p_libp2p:0.27.5\")\n        self.add_item(\"connection\", \"fetchai/soef:0.27.6\")\n        self.set_config(\"agent.default_connection\", \"fetchai/p2p_libp2p:0.27.5\")\n        setting_path = \"agent.default_routing\"\n        self.nested_set_config(setting_path, default_routing)\n\n        # manually change the files:\n        path = Path(self.t, search_aea, \"skills\", skill_name, \"behaviours.py\")\n        original = Path(AEA_DIR, \"skills\", \"scaffold\", \"behaviours.py\")\n        assert filecmp.cmp(path, original)\n        with open(path, \"w\") as file:\n            file.write(self.code_blocks[0])  # block one is behaviour\n\n        path = Path(self.t, search_aea, \"skills\", skill_name, \"handlers.py\")\n        original = Path(AEA_DIR, \"skills\", \"scaffold\", \"handlers.py\")\n        assert filecmp.cmp(path, original)\n        with open(path, \"w\") as file:\n            file.write(self.code_blocks[1])  # block two is handler\n\n        path = Path(self.t, search_aea, \"skills\", skill_name, \"my_model.py\")\n        original = Path(AEA_DIR, \"skills\", \"scaffold\", \"my_model.py\")\n        assert filecmp.cmp(path, original)\n        with open(path, \"w\") as file:\n            file.write(self.code_blocks[2])  # block three is dialogues\n\n        path_new = Path(self.t, search_aea, \"skills\", skill_name, \"dialogues.py\")\n        os.rename(path, path_new)\n\n        path = Path(self.t, search_aea, \"skills\", skill_name, \"skill.yaml\")\n        yaml_code_block = extract_code_blocks(self.doc_path, filter_=\"yaml\")\n        with open(path, \"w\") as file:\n            file.write(yaml_code_block[0])  # block one is yaml\n\n        path = Path(self.t, search_aea, \"skills\", skill_name, \"__init__.py\")\n        original = Path(AEA_DIR, \"skills\", \"scaffold\", \"__init__.py\")\n        assert not filecmp.cmp(path, original)  # the public id gets updated\n        with open(path, \"w\") as file:\n            file.write(self.code_blocks[3])  # block four is init\n\n        # update fingerprint\n        self.fingerprint_item(\"skill\", skill_id)\n\n        # add keys\n        self.generate_private_key(FetchAICrypto.identifier)\n        self.generate_private_key(\n            FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE_CONNECTION\n        )\n        self.add_private_key(FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE)\n        self.add_private_key(\n            FetchAICrypto.identifier,\n            FETCHAI_PRIVATE_KEY_FILE_CONNECTION,\n            connection=True,\n        )\n\n        # fund key\n        self.generate_wealth(FetchAICrypto.identifier)\n\n        # set p2p configs\n        setting_path = \"vendor.fetchai.connections.p2p_libp2p.config\"\n        self.nested_set_config(setting_path, NON_GENESIS_CONFIG)\n\n        # replace location\n        setting_path = \"skills.{}.behaviours.my_search_behaviour.args.location\".format(\n            skill_name\n        )\n        self.nested_set_config(setting_path, location)\n\n        # run agents\n        self.set_agent_context(simple_service_registration_aea)\n        self.run_cli_command(\"build\", cwd=self._get_cwd())\n        self.run_cli_command(\"issue-certificates\", cwd=self._get_cwd())\n        simple_service_registration_aea_process = self.run_agent()\n\n        check_strings = (\n            \"Starting libp2p node...\",\n            \"Connecting to libp2p node...\",\n            \"Successfully connected to libp2p node!\",\n            LIBP2P_SUCCESS_MESSAGE,\n        )\n        missing_strings = self.missing_from_output(\n            simple_service_registration_aea_process,\n            check_strings,\n            timeout=30,\n            is_terminating=False,\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in simple_service_registration_aea output.\".format(\n            missing_strings\n        )\n\n        self.set_agent_context(search_aea)\n        self.run_cli_command(\"build\", cwd=self._get_cwd())\n        self.run_cli_command(\"issue-certificates\", cwd=self._get_cwd())\n        search_aea_process = self.run_agent()\n\n        check_strings = (\n            \"Starting libp2p node...\",\n            \"Connecting to libp2p node...\",\n            \"Successfully connected to libp2p node!\",\n            LIBP2P_SUCCESS_MESSAGE,\n        )\n        missing_strings = self.missing_from_output(\n            search_aea_process, check_strings, timeout=30, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in search_aea output.\".format(missing_strings)\n\n        check_strings = (\n            \"registering agent on SOEF.\",\n            \"registering agent's service on the SOEF.\",\n            \"registering agent's personality genus on the SOEF.\",\n            \"registering agent's personality classification on the SOEF.\",\n        )\n        missing_strings = self.missing_from_output(\n            simple_service_registration_aea_process,\n            check_strings,\n            is_terminating=False,\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in simple_service_registration_aea output.\".format(\n            missing_strings\n        )\n\n        check_strings = (\n            \"sending search request to OEF search node, search_count=\",\n            \"number of search requests sent=\",\n            \"found number of agents=1, received search count=\",\n        )\n        missing_strings = self.missing_from_output(\n            search_aea_process, check_strings, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in search_aea output.\".format(missing_strings)\n\n        self.terminate_agents(\n            simple_service_registration_aea_process, search_aea_process\n        )\n        assert (\n            self.is_successfully_terminated()\n        ), \"Agents weren't successfully terminated.\"\n        wait_for_localhost_ports_to_close([9000, 9001])\n"
  },
  {
    "path": "tests/test_docs/test_skill_testing.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests for the content of skill-testing.md file.\"\"\"\nfrom pathlib import Path\nfrom unittest import mock\nfrom unittest.mock import MagicMock\n\nfrom tests.conftest import ROOT_DIR\nfrom tests.test_docs.helper import BasePythonMarkdownDocs\n\n\n@mock.patch(\"unittest.mock.MagicMock.assert_any_call\")\nclass TestSkillTesting(BasePythonMarkdownDocs):\n    \"\"\"Test the skill testing code snippets.\"\"\"\n\n    DOC_PATH = Path(ROOT_DIR, \"docs\", \"skill-testing.md\")\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set up the test.\"\"\"\n        super().setup_class()\n        # without this, it fails at the first block\n        # with: \"NameError: name 'Path' is not defined\"\n        cls.globals.update(globals())\n\n        cls.locals.update(dict(cls=MagicMock(), self=MagicMock()))\n"
  },
  {
    "path": "tests/test_docs/test_standalone_transaction/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests for the code-blocks in the standalone-transaction.md file.\"\"\"\n"
  },
  {
    "path": "tests/test_docs/test_standalone_transaction/standalone_transaction.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the last code-block from the standalone-transaction.md file.\"\"\"\n\nimport logging\n\nfrom aea_ledger_fetchai import FetchAICrypto\n\nfrom aea.crypto.helpers import create_private_key, try_generate_testnet_wealth\nfrom aea.crypto.ledger_apis import LedgerApis\nfrom aea.crypto.wallet import Wallet\n\n\nlogger = logging.getLogger(\"aea\")\nlogging.basicConfig(level=logging.INFO)\n\nFETCHAI_PRIVATE_KEY_FILE_1 = \"fetchai_private_key_1.txt\"\nFETCHAI_PRIVATE_KEY_FILE_2 = \"fetchai_private_key_2.txt\"\n\n\ndef run():\n    \"\"\"Run demo.\"\"\"\n\n    # Create a private keys\n    create_private_key(\n        FetchAICrypto.identifier, private_key_file=FETCHAI_PRIVATE_KEY_FILE_1\n    )\n    create_private_key(\n        FetchAICrypto.identifier, private_key_file=FETCHAI_PRIVATE_KEY_FILE_2\n    )\n\n    # Set up the wallets\n    wallet_1 = Wallet({FetchAICrypto.identifier: FETCHAI_PRIVATE_KEY_FILE_1})\n    wallet_2 = Wallet({FetchAICrypto.identifier: FETCHAI_PRIVATE_KEY_FILE_2})\n\n    # Generate some wealth\n    try_generate_testnet_wealth(\n        FetchAICrypto.identifier, wallet_1.addresses[FetchAICrypto.identifier]\n    )\n\n    logger.info(\n        \"Sending amount to {}\".format(wallet_2.addresses.get(FetchAICrypto.identifier))\n    )\n\n    # Create the transaction and send it to the ledger.\n    tx_nonce = LedgerApis.generate_tx_nonce(\n        FetchAICrypto.identifier,\n        wallet_2.addresses.get(FetchAICrypto.identifier),\n        wallet_1.addresses.get(FetchAICrypto.identifier),\n    )\n    transaction = LedgerApis.get_transfer_transaction(\n        identifier=FetchAICrypto.identifier,\n        sender_address=wallet_1.addresses.get(FetchAICrypto.identifier),\n        destination_address=wallet_2.addresses.get(FetchAICrypto.identifier),\n        amount=1,\n        tx_fee=1,\n        tx_nonce=tx_nonce,\n    )\n    signed_transaction = wallet_1.sign_transaction(\n        FetchAICrypto.identifier, transaction\n    )\n    transaction_digest = LedgerApis.send_signed_transaction(\n        FetchAICrypto.identifier, signed_transaction\n    )\n\n    logger.info(\"Transaction complete.\")\n    logger.info(\"The transaction digest is {}\".format(transaction_digest))\n\n\nif __name__ == \"__main__\":\n    run()\n"
  },
  {
    "path": "tests/test_docs/test_standalone_transaction/test_standalone_transaction.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests for the code-blocks in the standalone-transaction.md file.\"\"\"\n\nimport logging\nimport os\nfrom unittest.mock import patch\n\nimport pytest\n\nfrom aea.test_tools.test_cases import BaseAEATestCase\n\nfrom tests.conftest import CUR_PATH, MAX_FLAKY_RERUNS_INTEGRATION, ROOT_DIR\nfrom tests.test_docs.helper import extract_code_blocks, extract_python_code\nfrom tests.test_docs.test_standalone_transaction.standalone_transaction import (\n    logger,\n    run,\n)\n\n\nMD_FILE = \"docs/standalone-transaction.md\"\nPY_FILE = \"test_docs/test_standalone_transaction/standalone_transaction.py\"\n\ntest_logger = logging.getLogger(__name__)\n\n\nclass TestStandaloneTransaction(BaseAEATestCase):\n    \"\"\"This class contains the tests for the code-blocks in the agent-vs-aea.md file.\"\"\"\n\n    @classmethod\n    def _patch_logger(cls):\n\n        cls.patch_logger_info = patch.object(logger, \"info\")\n        cls.mocked_logger_info = cls.patch_logger_info.__enter__()\n\n    @classmethod\n    def _unpatch_logger(cls):\n        cls.mocked_logger_info.__exit__()\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup_class()\n        cls._patch_logger()\n        doc_path = os.path.join(ROOT_DIR, MD_FILE)\n        cls.code_blocks = extract_code_blocks(filepath=doc_path, filter_=\"python\")\n        test_code_path = os.path.join(CUR_PATH, PY_FILE)\n        cls.python_file = extract_python_code(test_code_path)\n\n    def test_read_md_file(self):\n        \"\"\"Test the last code block, that is the full listing of the demo from the Markdown.\"\"\"\n        assert (\n            self.code_blocks[-1] == self.python_file\n        ), \"Files must be exactly the same.\"\n\n    @pytest.mark.integration(reruns=MAX_FLAKY_RERUNS_INTEGRATION)\n    def test_run_end_to_end(self):\n        \"\"\"Run the transaction from the file.\"\"\"\n        try:\n            run()\n            self.mocked_logger_info.assert_any_call(\"Transaction complete.\")\n        except RuntimeError:\n            test_logger.info(\"RuntimeError: Some transactions have failed\")\n\n    def test_code_blocks_exist(self):\n        \"\"\"Test that all the code-blocks exist in the python file.\"\"\"\n        for blocks in self.code_blocks:\n            assert (\n                blocks in self.python_file\n            ), \"Code-block doesn't exist in the python file.\"\n"
  },
  {
    "path": "tests/test_examples/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"The tests module contains the tests of the examples dir.\"\"\"\n"
  },
  {
    "path": "tests/test_examples/test_gym_ex.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"The tests module contains the tests of the gym example.\"\"\"\n\nimport os\nimport shutil\nimport sys\nimport tempfile\nfrom pathlib import Path\n\nfrom tests.common.pexpect_popen import PexpectWrapper\nfrom tests.conftest import ROOT_DIR, env_path_separator\n\n\nDIRECTORIES = [\"packages\", \"examples\"]\n\n\nclass TestGymExt:\n    \"\"\"Test the gym example.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set up the test class.\"\"\"\n        cls.old_cwd = Path(os.getcwd())\n        cls.t = Path(tempfile.mkdtemp())\n        for directory in DIRECTORIES:\n            dir_path = Path(directory)\n            tmp_dir = cls.t / dir_path\n            src_dir = cls.old_cwd / Path(ROOT_DIR, directory)\n            shutil.copytree(str(src_dir), str(tmp_dir))\n        os.chdir(Path(cls.t))\n\n    def test_gym_ex(self):\n        \"\"\"Run the gym ex sequence.\"\"\"\n        try:\n            env = os.environ.copy()\n            env[\n                \"PYTHONPATH\"\n            ] = f\"{self.t}{env_path_separator()}{env.get('PYTHONPATH', '')}\"\n            process = PexpectWrapper(  # nosec\n                [\n                    sys.executable,\n                    str(Path(\"examples/gym_ex/train.py\").resolve()),\n                    \"--nb-steps\",\n                    \"50\",\n                ],\n                env=env,\n                maxread=1,\n                encoding=\"utf-8\",\n                logfile=sys.stdout,\n            )\n\n            process.expect([\"Step 50/50\"], timeout=10)\n            process.wait_to_complete(5)\n            assert process.returncode == 0, \"Test failed\"\n        finally:\n            process.terminate()\n            process.wait_to_complete(5)\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Teardown the test.\"\"\"\n        try:\n            os.chdir(Path(cls.old_cwd))\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n"
  },
  {
    "path": "tests/test_examples/test_http_client_connection_to_aries_cloud_agent.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"End-to-end test for AEA connecting using HTTP Client connection, to an Aries Cloud Agent.\"\"\"\n\nimport asyncio\nimport logging\nimport os\nimport shutil\nimport subprocess  # nosec\nimport time\nfrom threading import Thread\nfrom typing import Optional\nfrom unittest.mock import MagicMock\n\nimport pytest\nimport yaml\n\nfrom aea import AEA_DIR\nfrom aea.aea import AEA\nfrom aea.configurations.base import (\n    ConnectionConfig,\n    ProtocolConfig,\n    PublicId,\n    SkillConfig,\n)\nfrom aea.configurations.constants import DEFAULT_LEDGER, DEFAULT_PRIVATE_KEY_FILE\nfrom aea.crypto.wallet import Wallet\nfrom aea.identity.base import Identity\nfrom aea.mail.base import Envelope\nfrom aea.protocols.base import Message, Protocol\nfrom aea.registries.resources import Resources\nfrom aea.skills.base import Handler, Skill, SkillContext\n\nfrom packages.fetchai.connections.http_client.connection import HTTPClientConnection\nfrom packages.fetchai.protocols.http.message import HttpMessage\n\n\nlogger = logging.getLogger(__name__)\n\n\n@pytest.mark.asyncio\nclass TestAEAToACA:\n    \"\"\"End-to-end test for an AEA connecting to an ACA via the http client connection.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Initialise the class.\"\"\"\n        cls.aca_admin_address = \"127.0.0.1\"\n        cls.aca_admin_port = 8020\n\n        cls.aea_address = \"some string\"\n        cls.aea_public_key = \"some public_key\"\n        cls.aea_identity = Identity(\n            \"identity\", address=cls.aea_address, public_key=cls.aea_public_key\n        )\n\n        cls.cwd = os.getcwd()\n\n        # check Aries Cloud Agents (ACA) is installed\n        res = shutil.which(\"aca-py\")\n        if res is None:\n            pytest.skip(\n                \"Please install Aries Cloud Agents first! See the following link: https://github.com/hyperledger/aries-cloudagent-python\"\n            )\n\n        # run an ACA\n        # command: aca-py start --admin 127.0.0.1 8020 --admin-insecure-mode --inbound-transport http 0.0.0.0 8000 --outbound-transport http\n        cls.process = subprocess.Popen(  # nosec\n            [\n                \"aca-py\",\n                \"start\",\n                \"--admin\",\n                cls.aca_admin_address,\n                str(cls.aca_admin_port),\n                \"--admin-insecure-mode\",\n                \"--inbound-transport\",\n                \"http\",\n                \"0.0.0.0\",\n                \"8000\",\n                \"--outbound-transport\",\n                \"http\",\n            ]\n        )\n        time.sleep(4.0)\n\n    @pytest.mark.asyncio\n    async def test_connecting_to_aca(self):\n        \"\"\"Test connecting to aca.\"\"\"\n        configuration = ConnectionConfig(\n            host=self.aca_admin_address,\n            port=self.aca_admin_port,\n            connection_id=HTTPClientConnection.connection_id,\n        )\n        http_client_connection = HTTPClientConnection(\n            configuration=configuration,\n            data_dir=MagicMock(),\n            identity=self.aea_identity,\n        )\n        http_client_connection.loop = asyncio.get_event_loop()\n\n        # Request messages\n        request_http_message = HttpMessage(\n            dialogue_reference=(\"1\", \"\"),\n            target=0,\n            message_id=1,\n            performative=HttpMessage.Performative.REQUEST,\n            method=\"GET\",\n            url=\"http://{}:{}/status\".format(\n                self.aca_admin_address, self.aca_admin_port\n            ),\n            headers=\"\",\n            version=\"\",\n            body=b\"\",\n        )\n        request_http_message.to = \"ACA\"\n        request_envelope = Envelope(\n            to=\"ACA\",\n            sender=\"AEA\",\n            message=request_http_message,\n        )\n\n        try:\n            # connect to ACA\n            await http_client_connection.connect()\n            assert http_client_connection.is_connected is True\n\n            # send request to ACA\n            await http_client_connection.send(envelope=request_envelope)\n\n            # receive response from ACA\n            response_envelop = await http_client_connection.receive()\n\n            # check the response\n            assert response_envelop.to == self.aea_address\n            assert response_envelop.sender == \"HTTP Server\"\n            assert response_envelop.protocol_id == HttpMessage.protocol_id\n            decoded_response_message = response_envelop.message\n            assert (\n                decoded_response_message.performative\n                == HttpMessage.Performative.RESPONSE\n            )\n            assert decoded_response_message.version == \"\"\n            assert decoded_response_message.status_code == 200\n            assert decoded_response_message.status_text == \"OK\"\n            assert decoded_response_message.headers is not None\n            assert decoded_response_message.version is not None\n\n        finally:\n            # disconnect from ACA\n            await http_client_connection.disconnect()\n            assert http_client_connection.is_connected is False\n\n    @pytest.mark.asyncio\n    async def test_end_to_end_aea_aca(self):\n        \"\"\"Test the end to end aea aca interaction.\"\"\"\n        # AEA components\n        wallet = Wallet({DEFAULT_LEDGER: DEFAULT_PRIVATE_KEY_FILE})\n        identity = Identity(\n            name=\"my_aea_1\",\n            address=wallet.addresses.get(DEFAULT_LEDGER),\n            public_key=wallet.public_keys.get(DEFAULT_LEDGER),\n            default_address_key=DEFAULT_LEDGER,\n        )\n        data_dir = MagicMock()\n        configuration = ConnectionConfig(\n            host=self.aca_admin_address,\n            port=self.aca_admin_port,\n            connection_id=HTTPClientConnection.connection_id,\n        )\n        http_client_connection = HTTPClientConnection(\n            configuration=configuration,\n            data_dir=MagicMock(),\n            identity=identity,\n        )\n        resources = Resources()\n        resources.add_connection(http_client_connection)\n\n        # create AEA\n        aea = AEA(identity, wallet, resources, data_dir)\n\n        # Add http protocol to AEA resources\n        http_protocol_configuration = ProtocolConfig.from_json(\n            yaml.safe_load(\n                open(\n                    os.path.join(\n                        self.cwd,\n                        \"packages\",\n                        \"fetchai\",\n                        \"protocols\",\n                        \"http\",\n                        \"protocol.yaml\",\n                    )\n                )\n            )\n        )\n        http_protocol = Protocol(http_protocol_configuration, HttpMessage.serializer())\n        resources.add_protocol(http_protocol)\n\n        # Request message & envelope\n        request_http_message = HttpMessage(\n            dialogue_reference=(\"\", \"\"),\n            target=0,\n            message_id=1,\n            performative=HttpMessage.Performative.REQUEST,\n            method=\"GET\",\n            url=\"http://{}:{}/status\".format(\n                self.aca_admin_address, self.aca_admin_port\n            ),\n            headers=\"\",\n            version=\"\",\n            body=b\"\",\n        )\n        request_http_message.to = \"ACA\"\n        request_envelope = Envelope(\n            to=\"ACA\",\n            sender=\"AEA\",\n            message=request_http_message,\n        )\n\n        # add a simple skill with handler\n        skill_context = SkillContext(aea.context)\n        skill_config = SkillConfig(\n            name=\"simple_skill\", author=\"fetchai\", version=\"0.1.0\"\n        )\n        aea_handler = AEAHandler(skill_context=skill_context, name=\"aea_handler\")\n        simple_skill = Skill(\n            skill_config, skill_context, handlers={aea_handler.name: aea_handler}\n        )\n        resources.add_skill(simple_skill)\n\n        # add error skill to AEA\n        error_skill = Skill.from_dir(\n            os.path.join(AEA_DIR, \"skills\", \"error\"), agent_context=aea.context\n        )\n        resources.add_skill(error_skill)\n\n        # start AEA thread\n        t_aea = Thread(target=aea.start)\n        try:\n            t_aea.start()\n            time.sleep(1.0)\n            aea.outbox.put(request_envelope)\n            time.sleep(5.0)\n            assert (\n                aea_handler.handled_message.performative\n                == HttpMessage.Performative.RESPONSE\n            )\n            assert aea_handler.handled_message.version == \"\"\n            assert aea_handler.handled_message.status_code == 200\n            assert aea_handler.handled_message.status_text == \"OK\"\n            assert aea_handler.handled_message.headers is not None\n            assert aea_handler.handled_message.version is not None\n        finally:\n            aea.stop()\n            t_aea.join()\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Teardown the aca.\"\"\"\n        # terminate the ACA\n        cls.process.terminate()\n\n\nclass AEAHandler(Handler):\n    \"\"\"The handler for the AEA.\"\"\"\n\n    SUPPORTED_PROTOCOL = HttpMessage.protocol_id  # type: Optional[PublicId]\n\n    def __init__(self, **kwargs):\n        \"\"\"Initialize the handler.\"\"\"\n        super().__init__(**kwargs)\n        self.kwargs = kwargs\n        self.handled_message = None\n\n    def setup(self) -> None:\n        \"\"\"Implement the setup for the handler.\"\"\"\n        pass\n\n    def handle(self, message: Message) -> None:\n        \"\"\"\n        Implement the reaction to a message.\n\n        :param message: the message\n        :return: None\n        \"\"\"\n        self.handled_message = message\n\n    def teardown(self) -> None:\n        \"\"\"\n        Implement the handler teardown.\n\n        :return: None\n        \"\"\"\n"
  },
  {
    "path": "tests/test_packages/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"The tests module contains the tests of the packages dir.\"\"\"\n"
  },
  {
    "path": "tests/test_packages/test_connections/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"The tests module contains the tests of the packages/connections dir.\"\"\"\n"
  },
  {
    "path": "tests/test_packages/test_connections/test_p2p_libp2p/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests of the Libp2p-based DHT connection.\"\"\"\n"
  },
  {
    "path": "tests/test_packages/test_connections/test_p2p_libp2p/test_aea_cli.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This test module contains AEA cli tests for P2PLibp2p connection.\"\"\"\n\nimport json\nimport os\n\nfrom aea_ledger_ethereum.ethereum import EthereumCrypto as Ethereum\nfrom aea_ledger_fetchai import FetchAICrypto as FetchAI\n\nfrom aea.test_tools.test_cases import AEATestCaseEmpty\n\nfrom packages.fetchai.connections.p2p_libp2p.connection import (\n    PUBLIC_ID as P2P_CONNECTION_PUBLIC_ID,\n)\n\nfrom tests.conftest import libp2p_log_on_failure\n\n\nDEFAULT_PORT = 10234\nDEFAULT_DELEGATE_PORT = 11234\nDEFAULT_NET_SIZE = 4\n\nLIBP2P_LAUNCH_TIMEOUT = 20  # may downloads up to ~66Mb\n\n\nclass TestP2PLibp2pConnectionAEARunningDefaultConfigNode(AEATestCaseEmpty):\n    \"\"\"Test AEA with p2p_libp2p connection is correctly run\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up\"\"\"\n        super(TestP2PLibp2pConnectionAEARunningDefaultConfigNode, cls).setup_class()\n        cls.conn_key_file = os.path.join(os.path.abspath(os.getcwd()), \"./conn_key.txt\")\n        cls.log_files = []\n\n    @libp2p_log_on_failure\n    def test_agent(self):\n        \"\"\"Test with aea.\"\"\"\n        self.generate_private_key()\n        self.add_private_key()\n        self.generate_private_key(private_key_file=self.conn_key_file)\n        self.add_private_key(private_key_filepath=self.conn_key_file, connection=True)\n        self.add_item(\"connection\", str(P2P_CONNECTION_PUBLIC_ID))\n        self.run_cli_command(\"build\", cwd=self._get_cwd())\n        self.set_config(\"agent.default_connection\", str(P2P_CONNECTION_PUBLIC_ID))\n\n        # for logging\n        config_path = \"vendor.fetchai.connections.p2p_libp2p.config\"\n        log_file = \"libp2p_node_{}.log\".format(self.agent_name)\n        log_file = os.path.join(os.path.abspath(os.getcwd()), log_file)\n        self.set_config(\"{}.log_file\".format(config_path), log_file)\n        TestP2PLibp2pConnectionAEARunningDefaultConfigNode.log_files.append(log_file)\n\n        self.run_cli_command(\"issue-certificates\", cwd=self._get_cwd())\n\n        process = self.run_agent()\n        is_running = self.is_running(process, timeout=LIBP2P_LAUNCH_TIMEOUT)\n        assert is_running, \"AEA not running within timeout!\"\n\n        check_strings = \"Peer running in \"\n        missing_strings = self.missing_from_output(process, check_strings)\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in agent output.\".format(missing_strings)\n\n        self.terminate_agents(process)\n        assert self.is_successfully_terminated(\n            process\n        ), \"AEA wasn't successfully terminated.\"\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear down the test\"\"\"\n        cls.terminate_agents()\n\n        super(TestP2PLibp2pConnectionAEARunningDefaultConfigNode, cls).teardown_class()\n\n\nclass TestP2PLibp2pConnectionAEARunningEthereumConfigNode(AEATestCaseEmpty):\n    \"\"\"Test AEA with p2p_libp2p connection is correctly run\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up\"\"\"\n        super(TestP2PLibp2pConnectionAEARunningEthereumConfigNode, cls).setup_class()\n        cls.conn_key_file = os.path.join(os.path.abspath(os.getcwd()), \"./conn_key.txt\")\n        cls.log_files = []\n\n    @libp2p_log_on_failure\n    def test_agent(self):\n        \"\"\"Test with aea.\"\"\"\n        key_path = \"ethereum_private_key.txt\"\n        self.generate_private_key(\n            ledger_api_id=Ethereum.identifier, private_key_file=key_path\n        )\n        self.add_private_key(\n            ledger_api_id=Ethereum.identifier, private_key_filepath=key_path\n        )\n        self.generate_private_key(private_key_file=self.conn_key_file)\n        self.add_private_key(private_key_filepath=self.conn_key_file, connection=True)\n        self.add_item(\"connection\", str(P2P_CONNECTION_PUBLIC_ID))\n        self.run_cli_command(\"build\", cwd=self._get_cwd())\n        self.set_config(\"agent.default_ledger\", Ethereum.identifier)\n        self.nested_set_config(\n            \"agent.required_ledgers\", [FetchAI.identifier, Ethereum.identifier]\n        )\n        self.set_config(\"agent.default_connection\", str(P2P_CONNECTION_PUBLIC_ID))\n\n        # for logging\n        config_path = \"vendor.fetchai.connections.p2p_libp2p.config\"\n        log_file = \"libp2p_node_{}.log\".format(self.agent_name)\n        log_file = os.path.join(os.path.abspath(os.getcwd()), log_file)\n        self.set_config(\"{}.log_file\".format(config_path), log_file)\n        self.log_files.append(log_file)\n        setting_path = \"vendor.fetchai.connections.p2p_libp2p.cert_requests\"\n        settings = json.dumps(\n            [\n                {\n                    \"identifier\": \"acn\",\n                    \"ledger_id\": Ethereum.identifier,\n                    \"not_after\": \"2023-01-01\",\n                    \"not_before\": \"2022-01-01\",\n                    \"public_key\": \"fetchai\",\n                    \"message_format\": \"{public_key}\",\n                    \"save_path\": \".certs/conn_cert.txt\",\n                }\n            ]\n        )\n        self.set_config(setting_path, settings, type_=\"list\")\n        self.run_cli_command(\"issue-certificates\", cwd=self._get_cwd())\n\n        process = self.run_agent()\n        is_running = self.is_running(process, timeout=LIBP2P_LAUNCH_TIMEOUT)\n        assert is_running, \"AEA not running within timeout!\"\n\n        check_strings = \"Peer running in \"\n        missing_strings = self.missing_from_output(process, check_strings)\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in agent output.\".format(missing_strings)\n\n        self.terminate_agents(process)\n        assert self.is_successfully_terminated(\n            process\n        ), \"AEA wasn't successfully terminated.\"\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear down the test\"\"\"\n        cls.terminate_agents()\n\n        super(TestP2PLibp2pConnectionAEARunningEthereumConfigNode, cls).teardown_class()\n\n\nclass TestP2PLibp2pConnectionAEARunningFullNode(AEATestCaseEmpty):\n    \"\"\"Test AEA with p2p_libp2p connection is correctly run\"\"\"\n\n    capture_log = True\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up\"\"\"\n        super(TestP2PLibp2pConnectionAEARunningFullNode, cls).setup_class()\n        cls.conn_key_file = os.path.join(os.path.abspath(os.getcwd()), \"./conn_key.txt\")\n        cls.log_files = []\n\n    @libp2p_log_on_failure\n    def test_agent(self):\n        \"\"\"Test with aea.\"\"\"\n        self.generate_private_key()\n        self.add_private_key()\n        self.generate_private_key(private_key_file=self.conn_key_file)\n        self.add_private_key(private_key_filepath=self.conn_key_file, connection=True)\n        self.add_item(\"connection\", str(P2P_CONNECTION_PUBLIC_ID))\n        self.run_cli_command(\"build\", cwd=self._get_cwd())\n\n        # setup a full node: with public uri, relay service, and delegate service\n        config_path = \"vendor.fetchai.connections.p2p_libp2p.config\"\n        self.set_config(\n            \"{}.local_uri\".format(config_path), \"127.0.0.1:{}\".format(DEFAULT_PORT)\n        )\n        self.set_config(\n            \"{}.public_uri\".format(config_path), \"127.0.0.1:{}\".format(DEFAULT_PORT)\n        )\n        self.set_config(\n            \"{}.delegate_uri\".format(config_path),\n            \"127.0.0.1:{}\".format(DEFAULT_DELEGATE_PORT),\n        )\n\n        # for logging\n        log_file = \"libp2p_node_{}.log\".format(self.agent_name)\n        log_file = os.path.join(os.path.abspath(os.getcwd()), log_file)\n        self.set_config(\"{}.log_file\".format(config_path), log_file)\n        TestP2PLibp2pConnectionAEARunningFullNode.log_files.append(log_file)\n\n        self.run_cli_command(\"issue-certificates\", cwd=self._get_cwd())\n\n        process = self.run_agent()\n\n        is_running = self.is_running(process, timeout=LIBP2P_LAUNCH_TIMEOUT)\n        assert is_running, \"AEA not running within timeout!\"\n\n        check_strings = \"Peer running in \"\n        missing_strings = self.missing_from_output(process, check_strings, timeout=30)\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in agent output.\".format(missing_strings)\n\n        self.terminate_agents(process)\n        assert self.is_successfully_terminated(\n            process\n        ), \"AEA wasn't successfully terminated.\"\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear down the test\"\"\"\n        cls.terminate_agents()\n        super(TestP2PLibp2pConnectionAEARunningFullNode, cls).teardown_class()\n"
  },
  {
    "path": "tests/test_packages/test_connections/test_p2p_libp2p/test_build.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Test P2PLibp2p connection build.\"\"\"\nimport os\nimport tempfile\nfrom io import StringIO\nfrom unittest import mock\n\nimport pytest\n\nfrom aea.exceptions import AEAException\n\nfrom packages.fetchai.connections.p2p_libp2p import check_dependencies\nfrom packages.fetchai.connections.p2p_libp2p.check_dependencies import (\n    MINIMUM_GCC_VERSION,\n    MINIMUM_GO_VERSION,\n    build_node,\n    check_versions,\n    version_to_string,\n)\nfrom packages.fetchai.connections.p2p_libp2p.connection import LIBP2P_NODE_MODULE_NAME\n\n\ndef test_check_versions():\n    \"\"\"Test check_versions - positive case.\"\"\"\n    with mock.patch(\"sys.stdout\", new_callable=StringIO) as mock_stdout:\n        check_versions()\n        stdout = mock_stdout.getvalue()\n    assert f\"check 'go'>={version_to_string(MINIMUM_GO_VERSION)}, found \" in stdout\n    assert f\"check 'gcc'>={version_to_string(MINIMUM_GCC_VERSION)}, found \" in stdout\n\n\ndef test_check_versions_negative_binary_not_found():\n    \"\"\"Test check_versions - negative case, binary not found.\"\"\"\n    with mock.patch(\"shutil.which\", return_value=None):\n        with pytest.raises(\n            AEAException,\n            match=\"'go' is required by the libp2p connection, but it is not installed, or it is not accessible from the system path.\",\n        ):\n            check_versions()\n\n\ndef test_check_versions_negative_version_too_low():\n    \"\"\"Test check_versions - negative case, version too low.\"\"\"\n    with mock.patch.object(\n        check_dependencies,\n        \"get_version\",\n        return_value=(0, 0, 0),\n    ):\n        with pytest.raises(\n            AEAException,\n            match=f\"The installed version of 'go' is too low: expected at least {version_to_string(MINIMUM_GO_VERSION)}; found 0.0.0.\",\n        ):\n            check_versions()\n\n\ndef test_check_versions_negative_cannot_parse_version():\n    \"\"\"Test the check_versions - negative case, cannot parse version.\"\"\"\n    with mock.patch(\"sys.stdout\", new_callable=StringIO) as mock_stdout:\n        with mock.patch(\"subprocess.check_output\", return_value=b\"\"):\n            check_versions()\n        stdout = mock_stdout.getvalue()\n    assert (\n        \"Warning: cannot parse 'go' version from command: ['go', 'version'].\" in stdout\n    )\n    assert (\n        \"Warning: cannot parse 'gcc' version from command: ['gcc', '--version'].\"\n        in stdout\n    )\n\n\ndef test_build_node():\n    \"\"\"Test build node function.\"\"\"\n    with tempfile.TemporaryDirectory() as build_dir:\n        build_node(build_dir)\n        assert os.path.exists(os.path.join(build_dir, LIBP2P_NODE_MODULE_NAME))\n"
  },
  {
    "path": "tests/test_packages/test_connections/test_p2p_libp2p/test_communication.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This test module contains tests for P2PLibp2p connection.\"\"\"\nimport asyncio\nimport os\nimport shutil\nimport tempfile\nfrom unittest import mock\nfrom unittest.mock import Mock, call\n\nimport pytest\nfrom aea_ledger_ethereum import EthereumCrypto\nfrom aea_ledger_fetchai import FetchAICrypto\n\nfrom aea.crypto.registries import make_crypto\nfrom aea.mail.base import Empty, Envelope\nfrom aea.multiplexer import Multiplexer\n\nfrom packages.fetchai.connections.p2p_libp2p.connection import NodeClient, Uri\nfrom packages.fetchai.protocols.default import DefaultSerializer\nfrom packages.fetchai.protocols.default.message import DefaultMessage\n\nfrom tests.conftest import (\n    _make_libp2p_connection,\n    libp2p_log_on_failure,\n    libp2p_log_on_failure_all,\n)\n\n\nDEFAULT_PORT = 10234\nDEFAULT_NET_SIZE = 4\n\nMockDefaultMessageProtocol = Mock()\nMockDefaultMessageProtocol.protocol_id = DefaultMessage.protocol_id\nMockDefaultMessageProtocol.protocol_specification_id = (\n    DefaultMessage.protocol_specification_id\n)\n\n\n@pytest.mark.asyncio\nclass TestP2PLibp2pConnectionConnectDisconnect:\n    \"\"\"Test that connection is established and torn down correctly\"\"\"\n\n    def setup(self):\n        \"\"\"Set the test up\"\"\"\n        self.cwd = os.getcwd()\n        self.t = tempfile.mkdtemp()\n        os.chdir(self.t)\n\n    @pytest.mark.asyncio\n    async def test_p2plibp2pconnection_connect_disconnect_default(self):\n        \"\"\"Test connect then disconnect.\"\"\"\n        temp_dir = os.path.join(self.t, \"temp_dir\")\n        os.mkdir(temp_dir)\n        connection = _make_libp2p_connection(data_dir=temp_dir)\n\n        assert connection.is_connected is False\n        try:\n            await connection.connect()\n            assert connection.is_connected is True\n        except Exception as e:\n            await connection.disconnect()\n            raise e\n\n        await connection.disconnect()\n        assert connection.is_connected is False\n\n    @pytest.mark.asyncio\n    async def test_p2plibp2pconnection_connect_disconnect_ethereum(self):\n        \"\"\"Test connect then disconnect.\"\"\"\n        temp_dir = os.path.join(self.t, \"temp_dir\")\n        os.mkdir(temp_dir)\n        crypto = make_crypto(EthereumCrypto.identifier)\n        connection = _make_libp2p_connection(data_dir=temp_dir, agent_key=crypto)\n\n        assert connection.is_connected is False\n        try:\n            await connection.connect()\n            assert connection.is_connected is True\n        except Exception as e:\n            await connection.disconnect()\n            raise e\n\n        await connection.disconnect()\n        assert connection.is_connected is False\n\n    def teardown(self):\n        \"\"\"Tear down the test\"\"\"\n        os.chdir(self.cwd)\n        try:\n            shutil.rmtree(self.t)\n        except (OSError, IOError):\n            pass\n\n\n@libp2p_log_on_failure_all\nclass TestP2PLibp2pConnectionEchoEnvelope:\n    \"\"\"Test that connection will route envelope to destination\"\"\"\n\n    @classmethod\n    @libp2p_log_on_failure\n    def setup_class(cls):\n        \"\"\"Set the test up\"\"\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        os.chdir(cls.t)\n\n        cls.log_files = []\n        cls.multiplexers = []\n\n        aea_ledger_fetchai = make_crypto(FetchAICrypto.identifier)\n        aea_ledger_ethereum = make_crypto(EthereumCrypto.identifier)\n\n        try:\n            temp_dir_1 = os.path.join(cls.t, \"temp_dir_1\")\n            os.mkdir(temp_dir_1)\n            cls.connection1 = _make_libp2p_connection(\n                data_dir=temp_dir_1, agent_key=aea_ledger_fetchai, port=DEFAULT_PORT + 1\n            )\n            cls.multiplexer1 = Multiplexer(\n                [cls.connection1], protocols=[MockDefaultMessageProtocol]\n            )\n            cls.log_files.append(cls.connection1.node.log_file)\n            cls.multiplexer1.connect()\n            cls.multiplexers.append(cls.multiplexer1)\n\n            genesis_peer = cls.connection1.node.multiaddrs[0]\n\n            temp_dir_2 = os.path.join(cls.t, \"temp_dir_2\")\n            os.mkdir(temp_dir_2)\n            cls.connection2 = _make_libp2p_connection(\n                data_dir=temp_dir_2,\n                port=DEFAULT_PORT + 2,\n                entry_peers=[genesis_peer],\n                agent_key=aea_ledger_ethereum,\n            )\n            cls.multiplexer2 = Multiplexer(\n                [cls.connection2], protocols=[MockDefaultMessageProtocol]\n            )\n            cls.log_files.append(cls.connection2.node.log_file)\n            cls.multiplexer2.connect()\n            cls.multiplexers.append(cls.multiplexer2)\n        except Exception as e:\n            cls.teardown_class()\n            raise e\n\n    def test_connection_is_established(self):\n        \"\"\"Test connection established.\"\"\"\n        assert self.connection1.is_connected is True\n        assert self.connection2.is_connected is True\n\n    def test_envelope_routed(self):\n        \"\"\"Test envelope routed.\"\"\"\n        addr_1 = self.connection1.node.address\n        addr_2 = self.connection2.node.address\n\n        msg = DefaultMessage(\n            dialogue_reference=(\"\", \"\"),\n            message_id=1,\n            target=0,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"hello\",\n        )\n        envelope = Envelope(\n            to=addr_2,\n            sender=addr_1,\n            message=msg,\n        )\n        self.multiplexer1.put(envelope)\n        delivered_envelope = self.multiplexer2.get(block=True, timeout=20)\n\n        assert delivered_envelope is not None\n        assert delivered_envelope.to == envelope.to\n        assert delivered_envelope.sender == envelope.sender\n        assert (\n            delivered_envelope.protocol_specification_id\n            == envelope.protocol_specification_id\n        )\n        assert delivered_envelope.message != envelope.message\n        msg = DefaultMessage.serializer.decode(delivered_envelope.message)\n        msg.to = delivered_envelope.to\n        msg.sender = delivered_envelope.sender\n        assert envelope.message == msg\n\n    def test_envelope_echoed_back(self):\n        \"\"\"Test envelope echoed back.\"\"\"\n        addr_1 = self.connection1.node.address\n        addr_2 = self.connection2.node.address\n\n        msg = DefaultMessage(\n            dialogue_reference=(\"\", \"\"),\n            message_id=1,\n            target=0,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"hello\",\n        )\n        original_envelope = Envelope(\n            to=addr_2,\n            sender=addr_1,\n            message=msg,\n        )\n\n        self.multiplexer1.put(original_envelope)\n        delivered_envelope = self.multiplexer2.get(block=True, timeout=10)\n        assert delivered_envelope is not None\n\n        delivered_envelope.to = addr_1\n        delivered_envelope.sender = addr_2\n\n        self.multiplexer2.put(delivered_envelope)\n        echoed_envelope = self.multiplexer1.get(block=True, timeout=5)\n\n        assert echoed_envelope is not None\n        assert echoed_envelope.to == original_envelope.sender\n        assert delivered_envelope.sender == original_envelope.to\n        assert (\n            delivered_envelope.protocol_specification_id\n            == original_envelope.protocol_specification_id\n        )\n        assert delivered_envelope.message != original_envelope.message\n        assert original_envelope.message_bytes == delivered_envelope.message_bytes\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear down the test\"\"\"\n        for mux in cls.multiplexers:\n            mux.disconnect()\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\n@libp2p_log_on_failure_all\nclass TestP2PLibp2pConnectionRouting:\n    \"\"\"Test that libp2p node will reliably route envelopes in a local network\"\"\"\n\n    @classmethod\n    @libp2p_log_on_failure\n    def setup_class(cls):\n        \"\"\"Set the test up\"\"\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        os.chdir(cls.t)\n\n        cls.log_files = []\n        cls.multiplexers = []\n\n        try:\n            port_genesis = DEFAULT_PORT + 10\n            temp_dir_gen = os.path.join(cls.t, \"temp_dir_gen\")\n            os.mkdir(temp_dir_gen)\n            cls.connection_genesis = _make_libp2p_connection(\n                data_dir=temp_dir_gen, port=port_genesis\n            )\n            cls.multiplexer_genesis = Multiplexer(\n                [cls.connection_genesis], protocols=[MockDefaultMessageProtocol]\n            )\n            cls.log_files.append(cls.connection_genesis.node.log_file)\n            cls.multiplexer_genesis.connect()\n            cls.multiplexers.append(cls.multiplexer_genesis)\n\n            genesis_peer = cls.connection_genesis.node.multiaddrs[0]\n\n            cls.connections = [cls.connection_genesis]\n\n            port = port_genesis\n            for i in range(DEFAULT_NET_SIZE):\n                port += 1\n                temp_dir = os.path.join(cls.t, f\"temp_dir_{i}\")\n                os.mkdir(temp_dir)\n                conn = _make_libp2p_connection(\n                    data_dir=temp_dir, port=port, entry_peers=[genesis_peer]\n                )\n                mux = Multiplexer([conn], protocols=[MockDefaultMessageProtocol])\n\n                cls.connections.append(conn)\n\n                cls.log_files.append(conn.node.log_file)\n                mux.connect()\n                cls.multiplexers.append(mux)\n        except Exception as e:\n            cls.teardown_class()\n            raise e\n\n    def test_connection_is_established(self):\n        \"\"\"Test connection established.\"\"\"\n        assert self.connection_genesis.is_connected is True\n        for conn in self.connections:\n            assert conn.is_connected is True\n\n    def test_star_routing_connectivity(self):\n        \"\"\"Test star routing connectivity.\"\"\"\n        addrs = [conn.node.address for conn in self.connections]\n\n        for source in range(len(self.multiplexers)):\n            for destination in range(len(self.multiplexers)):\n                if destination == source:\n                    continue\n                msg = DefaultMessage(\n                    dialogue_reference=(\"\", \"\"),\n                    message_id=1,\n                    target=0,\n                    performative=DefaultMessage.Performative.BYTES,\n                    content=b\"hello\",\n                )\n                envelope = Envelope(\n                    to=addrs[destination],\n                    sender=addrs[source],\n                    message=msg,\n                )\n\n                self.multiplexers[source].put(envelope)\n                delivered_envelope = self.multiplexers[destination].get(\n                    block=True, timeout=10\n                )\n\n                assert delivered_envelope is not None\n                assert delivered_envelope.to == envelope.to\n                assert delivered_envelope.sender == envelope.sender\n                assert (\n                    delivered_envelope.protocol_specification_id\n                    == envelope.protocol_specification_id\n                )\n                assert delivered_envelope.message != envelope.message\n                msg = DefaultMessage.serializer.decode(delivered_envelope.message)\n                msg.to = delivered_envelope.to\n                msg.sender = delivered_envelope.sender\n                assert envelope.message == msg\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear down the test\"\"\"\n        for mux in cls.multiplexers:\n            mux.disconnect()\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\n@libp2p_log_on_failure_all\nclass TestP2PLibp2pConnectionEchoEnvelopeRelayOneDHTNode:\n    \"\"\"Test that connection will route envelope to destination using the same relay node\"\"\"\n\n    @classmethod\n    @libp2p_log_on_failure\n    def setup_class(cls):\n        \"\"\"Set the test up\"\"\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        os.chdir(cls.t)\n\n        cls.log_files = []\n        cls.multiplexers = []\n\n        try:\n            temp_dir_rel = os.path.join(cls.t, \"temp_dir_rel\")\n            os.mkdir(temp_dir_rel)\n            cls.relay = _make_libp2p_connection(\n                data_dir=temp_dir_rel, port=DEFAULT_PORT + 1\n            )\n            cls.multiplexer = Multiplexer([cls.relay])\n            cls.log_files.append(cls.relay.node.log_file)\n            cls.multiplexer.connect()\n            cls.multiplexers.append(cls.multiplexer)\n\n            relay_peer = cls.relay.node.multiaddrs[0]\n\n            temp_dir_1 = os.path.join(cls.t, \"temp_dir_1\")\n            os.mkdir(temp_dir_1)\n            cls.connection1 = _make_libp2p_connection(\n                data_dir=temp_dir_1,\n                port=DEFAULT_PORT + 2,\n                relay=False,\n                entry_peers=[relay_peer],\n            )\n            cls.multiplexer1 = Multiplexer(\n                [cls.connection1], protocols=[MockDefaultMessageProtocol]\n            )\n            cls.log_files.append(cls.connection1.node.log_file)\n            cls.multiplexer1.connect()\n            cls.multiplexers.append(cls.multiplexer1)\n\n            temp_dir_2 = os.path.join(cls.t, \"temp_dir_2\")\n            os.mkdir(temp_dir_2)\n            cls.connection2 = _make_libp2p_connection(\n                data_dir=temp_dir_2, port=DEFAULT_PORT + 3, entry_peers=[relay_peer]\n            )\n            cls.multiplexer2 = Multiplexer(\n                [cls.connection2], protocols=[MockDefaultMessageProtocol]\n            )\n            cls.log_files.append(cls.connection2.node.log_file)\n            cls.multiplexer2.connect()\n            cls.multiplexers.append(cls.multiplexer2)\n        except Exception as e:\n            cls.teardown_class()\n            raise e\n\n    def test_connection_is_established(self):\n        \"\"\"Test connection established.\"\"\"\n        assert self.relay.is_connected is True\n        assert self.connection1.is_connected is True\n        assert self.connection2.is_connected is True\n\n    def test_envelope_routed(self):\n        \"\"\"Test envelope routed.\"\"\"\n        addr_1 = self.connection1.node.address\n        addr_2 = self.connection2.node.address\n\n        msg = DefaultMessage(\n            dialogue_reference=(\"\", \"\"),\n            message_id=1,\n            target=0,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"hello\",\n        )\n        envelope = Envelope(\n            to=addr_2,\n            sender=addr_1,\n            message=msg,\n        )\n\n        self.multiplexer1.put(envelope)\n        delivered_envelope = self.multiplexer2.get(block=True, timeout=20)\n\n        assert delivered_envelope is not None\n        assert delivered_envelope.to == envelope.to\n        assert delivered_envelope.sender == envelope.sender\n        assert (\n            delivered_envelope.protocol_specification_id\n            == envelope.protocol_specification_id\n        )\n        assert delivered_envelope.message != envelope.message\n        msg = DefaultMessage.serializer.decode(delivered_envelope.message)\n        msg.to = delivered_envelope.to\n        msg.sender = delivered_envelope.sender\n        assert envelope.message == msg\n\n    def test_envelope_echoed_back(self):\n        \"\"\"Test envelope echoed back.\"\"\"\n        addr_1 = self.connection1.node.address\n        addr_2 = self.connection2.node.address\n\n        msg = DefaultMessage(\n            dialogue_reference=(\"\", \"\"),\n            message_id=1,\n            target=0,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"hello\",\n        )\n        original_envelope = Envelope(\n            to=addr_2,\n            sender=addr_1,\n            message=msg,\n        )\n\n        self.multiplexer1.put(original_envelope)\n        delivered_envelope = self.multiplexer2.get(block=True, timeout=10)\n        assert delivered_envelope is not None\n\n        delivered_envelope.to = addr_1\n        delivered_envelope.sender = addr_2\n\n        self.multiplexer2.put(delivered_envelope)\n        echoed_envelope = self.multiplexer1.get(block=True, timeout=5)\n\n        assert echoed_envelope is not None\n        assert echoed_envelope.to == original_envelope.sender\n        assert delivered_envelope.sender == original_envelope.to\n        assert (\n            delivered_envelope.protocol_specification_id\n            == original_envelope.protocol_specification_id\n        )\n        assert delivered_envelope.message != original_envelope.message\n        assert original_envelope.message_bytes == delivered_envelope.message_bytes\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear down the test\"\"\"\n        for mux in cls.multiplexers:\n            mux.disconnect()\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\n@libp2p_log_on_failure_all\nclass TestP2PLibp2pConnectionRoutingRelayTwoDHTNodes:\n    \"\"\"Test that libp2p DHT network will reliably route envelopes from relay/non-relay to relay/non-relay nodes\"\"\"\n\n    @classmethod\n    @libp2p_log_on_failure\n    def setup_class(cls):\n        \"\"\"Set the test up\"\"\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        os.chdir(cls.t)\n\n        cls.log_files = []\n        cls.multiplexers = []\n\n        try:\n            temp_dir_rel_1 = os.path.join(cls.t, \"temp_dir_rel_1\")\n            os.mkdir(temp_dir_rel_1)\n            port_relay_1 = DEFAULT_PORT + 10\n            cls.connection_relay_1 = _make_libp2p_connection(\n                data_dir=temp_dir_rel_1, port=port_relay_1\n            )\n            cls.multiplexer_relay_1 = Multiplexer(\n                [cls.connection_relay_1], protocols=[MockDefaultMessageProtocol]\n            )\n            cls.log_files.append(cls.connection_relay_1.node.log_file)\n            cls.multiplexer_relay_1.connect()\n            cls.multiplexers.append(cls.multiplexer_relay_1)\n\n            relay_peer_1 = cls.connection_relay_1.node.multiaddrs[0]\n\n            temp_dir_rel_2 = os.path.join(cls.t, \"temp_dir_rel_2\")\n            os.mkdir(temp_dir_rel_2)\n            port_relay_2 = DEFAULT_PORT + 100\n            cls.connection_relay_2 = _make_libp2p_connection(\n                data_dir=temp_dir_rel_2, port=port_relay_2, entry_peers=[relay_peer_1]\n            )\n            cls.multiplexer_relay_2 = Multiplexer(\n                [cls.connection_relay_2], protocols=[MockDefaultMessageProtocol]\n            )\n            cls.log_files.append(cls.connection_relay_2.node.log_file)\n            cls.multiplexer_relay_2.connect()\n            cls.multiplexers.append(cls.multiplexer_relay_2)\n\n            relay_peer_2 = cls.connection_relay_2.node.multiaddrs[0]\n\n            cls.connections = [cls.connection_relay_1, cls.connection_relay_2]\n\n            port = port_relay_1\n            for i in range(int(DEFAULT_NET_SIZE / 2) + 1):\n                temp_dir = os.path.join(cls.t, f\"temp_dir_conn_{i}_1\")\n                os.mkdir(temp_dir)\n                port += 1\n                conn = _make_libp2p_connection(\n                    data_dir=temp_dir,\n                    port=port,\n                    relay=False,\n                    entry_peers=[relay_peer_1],\n                )\n                mux = Multiplexer([conn])\n                cls.connections.append(conn)\n                cls.log_files.append(conn.node.log_file)\n                mux.connect()\n                cls.multiplexers.append(mux)\n\n            port = port_relay_2\n            for i in range(int(DEFAULT_NET_SIZE / 2) + 1):\n                temp_dir = os.path.join(cls.t, f\"temp_dir_conn_{i}_2\")\n                os.mkdir(temp_dir)\n                port += 1\n                conn = _make_libp2p_connection(\n                    data_dir=temp_dir,\n                    port=port,\n                    relay=False,\n                    entry_peers=[relay_peer_2],\n                )\n                mux = Multiplexer([conn])\n                cls.connections.append(conn)\n                cls.log_files.append(conn.node.log_file)\n                mux.connect()\n                cls.multiplexers.append(mux)\n        except Exception as e:\n            cls.teardown_class()\n            raise e\n\n    def test_connection_is_established(self):\n        \"\"\"Test connection established.\"\"\"\n        assert self.connection_relay_1.is_connected is True\n        assert self.connection_relay_2.is_connected is True\n        for conn in self.connections:\n            assert conn.is_connected is True\n\n    def test_star_routing_connectivity(self):\n        \"\"\"Test star routing connectivity.\"\"\"\n        addrs = [conn.node.address for conn in self.connections]\n\n        for source in range(len(self.multiplexers)):\n            for destination in range(len(self.multiplexers)):\n                if destination == source:\n                    continue\n                msg = DefaultMessage(\n                    dialogue_reference=(\"\", \"\"),\n                    message_id=1,\n                    target=0,\n                    performative=DefaultMessage.Performative.BYTES,\n                    content=b\"hello\",\n                )\n                envelope = Envelope(\n                    to=addrs[destination],\n                    sender=addrs[source],\n                    message=msg,\n                )\n\n                self.multiplexers[source].put(envelope)\n                delivered_envelope = self.multiplexers[destination].get(\n                    block=True, timeout=10\n                )\n\n                assert delivered_envelope is not None\n                assert delivered_envelope.to == envelope.to\n                assert delivered_envelope.sender == envelope.sender\n                assert (\n                    delivered_envelope.protocol_specification_id\n                    == envelope.protocol_specification_id\n                )\n                assert delivered_envelope.message != envelope.message\n                msg = DefaultMessage.serializer.decode(delivered_envelope.message)\n                msg.sender = delivered_envelope.sender\n                msg.to = delivered_envelope.to\n                assert envelope.message == msg\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear down the test\"\"\"\n        for mux in cls.multiplexers:\n            mux.disconnect()\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\ndef test_libp2pconnection_uri():\n    \"\"\"Test uri.\"\"\"\n    uri = Uri(host=\"127.0.0.1\")\n    uri = Uri(host=\"127.0.0.1\", port=10000)\n    assert uri.host == \"127.0.0.1\" and uri.port == 10000\n\n\n@pytest.mark.asyncio\nclass TestP2PLibp2pNodeRestart:\n    \"\"\"Test node restart.\"\"\"\n\n    def setup(self):\n        \"\"\"Set the test up\"\"\"\n        self.cwd = os.getcwd()\n        self.t = tempfile.mkdtemp()\n        os.chdir(self.t)\n\n    @pytest.mark.asyncio\n    async def test_node_restart(self):\n        \"\"\"Test node restart works.\"\"\"\n        temp_dir = os.path.join(self.t, \"temp_dir\")\n        os.mkdir(temp_dir)\n        connection = _make_libp2p_connection(data_dir=temp_dir)\n        try:\n            await connection.node.start()\n            pipe = connection.node.pipe\n            assert pipe is not None\n            await connection.node.restart()\n            new_pipe = connection.node.pipe\n            assert new_pipe is not None\n            assert new_pipe is not pipe\n        finally:\n            await connection.node.stop()\n\n    def teardown(self):\n        \"\"\"Tear down the test\"\"\"\n        os.chdir(self.cwd)\n        try:\n            shutil.rmtree(self.t)\n        except (OSError, IOError):\n            pass\n\n\n@libp2p_log_on_failure_all\nclass BaseTestP2PLibp2p:\n    \"\"\"Base test class for p2p libp2p tests with two peers.\"\"\"\n\n    def _make_envelope(\n        self,\n        sender_address: str,\n        receiver_address: str,\n        message_id: int = 1,\n        target: int = 0,\n    ):\n        \"\"\"Make an envelope for testing purposes.\"\"\"\n        msg = DefaultMessage(\n            dialogue_reference=(\"\", \"\"),\n            message_id=message_id,\n            target=target,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"hello\",\n        )\n        envelope = Envelope(\n            to=receiver_address,\n            sender=sender_address,\n            protocol_specification_id=DefaultMessage.protocol_specification_id,\n            message=DefaultSerializer().encode(msg),\n        )\n        return envelope\n\n    @classmethod\n    @libp2p_log_on_failure\n    def setup_class(cls):\n        \"\"\"Set the test up\"\"\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        os.chdir(cls.t)\n\n        cls.log_files = []\n        cls.multiplexers = []\n\n        aea_ledger_fetchai = make_crypto(FetchAICrypto.identifier)\n        aea_ledger_ethereum = make_crypto(EthereumCrypto.identifier)\n\n        try:\n            temp_dir_1 = os.path.join(cls.t, \"temp_dir_1\")\n            os.mkdir(temp_dir_1)\n            cls.connection1 = _make_libp2p_connection(\n                data_dir=temp_dir_1, agent_key=aea_ledger_fetchai, port=DEFAULT_PORT + 1\n            )\n            cls.multiplexer1 = Multiplexer(\n                [cls.connection1], protocols=[MockDefaultMessageProtocol]\n            )\n            cls.log_files.append(cls.connection1.node.log_file)\n            cls.multiplexer1.connect()\n            cls.multiplexers.append(cls.multiplexer1)\n\n            genesis_peer = cls.connection1.node.multiaddrs[0]\n\n            temp_dir_2 = os.path.join(cls.t, \"temp_dir_2\")\n            os.mkdir(temp_dir_2)\n            cls.connection2 = _make_libp2p_connection(\n                data_dir=temp_dir_2,\n                port=DEFAULT_PORT + 2,\n                entry_peers=[genesis_peer],\n                agent_key=aea_ledger_ethereum,\n            )\n            cls.multiplexer2 = Multiplexer(\n                [cls.connection2], protocols=[MockDefaultMessageProtocol]\n            )\n            cls.log_files.append(cls.connection2.node.log_file)\n            cls.multiplexer2.connect()\n            cls.multiplexers.append(cls.multiplexer2)\n        except Exception as e:\n            cls.teardown_class()\n            raise e\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear down the test\"\"\"\n        for mux in cls.multiplexers:\n            mux.disconnect()\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\n@libp2p_log_on_failure_all\nclass TestP2PLibp2PSendEnvelope(BaseTestP2PLibp2p):\n    \"\"\"Test that connection will send envelope with error, and that reconnection fixes it.\"\"\"\n\n    def test_connection_is_established(self):\n        \"\"\"Test connection established.\"\"\"\n        assert self.connection1.is_connected is True\n        assert self.connection2.is_connected is True\n\n    def test_envelope_routed(self):\n        \"\"\"Test envelope routed.\"\"\"\n        addr_1 = self.connection2.node.address\n        addr_2 = self.connection1.node.address\n\n        msg = DefaultMessage(\n            dialogue_reference=(\"\", \"\"),\n            message_id=1,\n            target=0,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"hello\",\n        )\n        envelope = Envelope(\n            to=addr_2,\n            sender=addr_1,\n            message=msg,\n        )\n\n        # make the send to fail\n        # note: we don't mock the genesis peer.\n        with mock.patch.object(\n            self.connection2.logger, \"exception\"\n        ) as _mock_logger, mock.patch.object(\n            self.connection2.node.pipe, \"write\", side_effect=Exception(\"some error\")\n        ):\n            self.multiplexer2.put(envelope)\n            delivered_envelope = self.multiplexer1.get(block=True, timeout=20)\n            _mock_logger.assert_called_with(\n                \"Failed to send after pipe reconnect. Exception: some error. Try recover connection to node and send again.\"\n            )\n\n        assert delivered_envelope is not None\n        assert delivered_envelope.to == envelope.to\n        assert delivered_envelope.sender == envelope.sender\n        assert (\n            delivered_envelope.protocol_specification_id\n            == envelope.protocol_specification_id\n        )\n        assert delivered_envelope.message != envelope.message\n        msg = DefaultMessage.serializer.decode(delivered_envelope.message)\n        msg.to = delivered_envelope.to\n        msg.sender = delivered_envelope.sender\n        assert envelope.message == msg\n\n\n@libp2p_log_on_failure_all\nclass TestP2PLibp2PReceiveEnvelope(BaseTestP2PLibp2p):\n    \"\"\"Test that connection will receive envelope with error, and that reconnection fixes it.\"\"\"\n\n    def test_envelope_routed(self):\n        \"\"\"Test envelope routed.\"\"\"\n        addr_1 = self.connection1.node.address\n        addr_2 = self.connection2.node.address\n\n        msg = DefaultMessage(\n            dialogue_reference=(\"\", \"\"),\n            message_id=1,\n            target=0,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"hello\",\n        )\n        envelope = Envelope(\n            to=addr_2,\n            sender=addr_1,\n            message=msg,\n        )\n\n        # make the receive to fail\n        with mock.patch.object(\n            self.connection2.logger, \"exception\"\n        ) as _mock_logger, mock.patch.object(\n            self.connection2.node.pipe, \"read\", side_effect=Exception(\"some error\")\n        ):\n            self.multiplexer1.put(envelope)\n            delivered_envelope = self.multiplexer2.get(block=True, timeout=20)\n            _mock_logger.assert_has_calls(\n                [\n                    call(\n                        \"Failed to read. Exception: some error. Try reconnect to node and read again.\"\n                    )\n                ]\n            )\n\n        assert delivered_envelope is not None\n        assert delivered_envelope.to == envelope.to\n        assert delivered_envelope.sender == envelope.sender\n        assert (\n            delivered_envelope.protocol_specification_id\n            == envelope.protocol_specification_id\n        )\n        assert delivered_envelope.message != envelope.message\n        msg = DefaultMessage.serializer.decode(delivered_envelope.message)\n        msg.to = delivered_envelope.to\n        msg.sender = delivered_envelope.sender\n        assert envelope.message == msg\n\n\n@libp2p_log_on_failure_all\nclass TestLibp2pEnvelopeOrder(BaseTestP2PLibp2p):\n    \"\"\"\n    Test message ordering.\n\n    Test that the order of envelope is the guaranteed to be the same\n    when communicating between two peers.\n    \"\"\"\n\n    NB_ENVELOPES = 1000\n\n    def test_burst_order(self):\n        \"\"\"Test order of envelope burst is guaranteed on receiving end.\"\"\"\n        addr_1 = self.connection1.address\n        addr_2 = self.connection2.address\n\n        sent_envelopes = [\n            self._make_envelope(addr_1, addr_2, i, i - 1)\n            for i in range(1, self.NB_ENVELOPES + 1)\n        ]\n        for envelope in sent_envelopes:\n            self.multiplexer1.put(envelope)\n\n        received_envelopes = []\n        for _ in range(1, self.NB_ENVELOPES + 1):\n            envelope = self.multiplexer2.get(block=True, timeout=20)\n            received_envelopes.append(envelope)\n\n        # test no new message is \"created\"\n        with pytest.raises(Empty):\n            self.multiplexer2.get(block=True, timeout=1)\n\n        assert len(sent_envelopes) == len(\n            received_envelopes\n        ), f\"expected number of envelopes {len(sent_envelopes)}, got {len(received_envelopes)}\"\n        for expected, actual in zip(sent_envelopes, received_envelopes):\n            assert expected.message == actual.message, (\n                \"message content differ; probably a wrong message \"\n                \"ordering on the receiving end\"\n            )\n\n\n@pytest.mark.asyncio\nasync def test_nodeclient_pipe_connect():\n    \"\"\"Test pipe.connect called on NodeClient.connect.\"\"\"\n    f = asyncio.Future()\n    f.set_result(None)\n    pipe = Mock()\n    pipe.connect.return_value = f\n    node_client = NodeClient(pipe, Mock())\n    await node_client.connect()\n    pipe.connect.assert_called_once()\n"
  },
  {
    "path": "tests/test_packages/test_connections/test_p2p_libp2p/test_errors.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This test module contains Negative tests for Libp2p connection.\"\"\"\nimport asyncio\nimport os\nimport platform\nimport shutil\nimport subprocess  # nosec\nimport sys\nimport tempfile\nfrom asyncio.futures import Future\nfrom unittest.mock import Mock, patch\n\nimport pytest\n\nfrom aea.configurations.base import ConnectionConfig\nfrom aea.crypto.registries import make_crypto\nfrom aea.identity.base import Identity\nfrom aea.multiplexer import Multiplexer\n\nfrom packages.fetchai.connections.p2p_libp2p.connection import (\n    LIBP2P_NODE_MODULE_NAME,\n    Libp2pNode,\n    P2PLibp2pConnection,\n    _golang_module_run,\n    _ip_all_private_or_all_public,\n)\nfrom packages.fetchai.protocols.acn.message import AcnMessage\n\nfrom tests.conftest import DEFAULT_LEDGER, _make_libp2p_connection\n\n\nDEFAULT_PORT = 10234\nDEFAULT_NET_SIZE = 4\n\n\nclass TestP2PLibp2pConnectionFailureGolangRun:\n    \"\"\"Test that golang run fails if wrong path or timeout\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up\"\"\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        os.chdir(cls.t)\n\n        temp_dir = os.path.join(cls.t, \"temp_dir\")\n        os.mkdir(temp_dir)\n        cls.connection = _make_libp2p_connection(data_dir=temp_dir)\n        cls.wrong_path = tempfile.mkdtemp()\n\n    def test_wrong_path(self):\n        \"\"\"Test the wrong path.\"\"\"\n        log_file_desc = open(\"log\", \"a\", 1)\n        with pytest.raises(Exception):\n            _golang_module_run(\n                self.wrong_path, LIBP2P_NODE_MODULE_NAME, [], log_file_desc\n            )\n\n    def test_timeout(self):\n        \"\"\"Test the timeout.\"\"\"\n        self.connection.node._connection_timeout = 0\n        muxer = Multiplexer([self.connection])\n        with pytest.raises(Exception):\n            muxer.connect()\n        muxer.disconnect()\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear down the test\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n            shutil.rmtree(cls.wrong_path)\n        except (OSError, IOError):\n            pass\n\n\nclass TestP2PLibp2pConnectionFailureNodeDisconnect:\n    \"\"\"Test that connection handles node disconnecting properly\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up\"\"\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        os.chdir(cls.t)\n\n        temp_dir = os.path.join(cls.t, \"temp_dir\")\n        os.mkdir(temp_dir)\n        cls.connection = _make_libp2p_connection(data_dir=temp_dir)\n\n    def test_node_disconnect(self):\n        \"\"\"Test node disconnect.\"\"\"\n        muxer = Multiplexer([self.connection])\n        muxer.connect()\n        self.connection.node.proc.terminate()\n        self.connection.node.proc.wait()\n        muxer.disconnect()\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear down the test\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestP2PLibp2pConnectionFailureSetupNewConnection:\n    \"\"\"Test that connection constructor ensures proper configuration\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up\"\"\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        os.chdir(cls.t)\n        crypto = make_crypto(DEFAULT_LEDGER)\n        cls.identity = Identity(\n            \"identity\", address=crypto.address, public_key=crypto.public_key\n        )\n        cls.host = \"localhost\"\n        cls.port = \"10000\"\n\n        cls.key_file = os.path.join(cls.t, \"keyfile\")\n        crypto.dump(cls.key_file)\n\n    def test_entry_peers_when_no_public_uri_provided(self):\n        \"\"\"Test entry peers when no public uri provided.\"\"\"\n        configuration = ConnectionConfig(\n            libp2p_key_file=None,\n            local_uri=\"{}:{}\".format(self.host, self.port),\n            delegate_uri=\"{}:{}\".format(self.host, self.port),\n            entry_peers=None,\n            log_file=None,\n            connection_id=P2PLibp2pConnection.connection_id,\n            build_directory=self.t,\n        )\n        with pytest.raises(ValueError):\n            P2PLibp2pConnection(\n                configuration=configuration, data_dir=self.t, identity=self.identity\n            )\n\n    def test_local_uri_provided_when_public_uri_provided(self):\n        \"\"\"Test local uri provided when public uri provided.\"\"\"\n        configuration = ConnectionConfig(\n            node_key_file=self.key_file,\n            public_uri=\"{}:{}\".format(self.host, self.port),\n            entry_peers=None,\n            log_file=None,\n            connection_id=P2PLibp2pConnection.connection_id,\n            build_directory=self.t,\n        )\n        with pytest.raises(ValueError):\n            P2PLibp2pConnection(\n                configuration=configuration, data_dir=self.t, identity=self.identity\n            )\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear down the test\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\ndef test_libp2pconnection_mixed_ip_address():\n    \"\"\"Test correct public uri ip and entry peers ips configuration.\"\"\"\n    assert _ip_all_private_or_all_public([]) is True\n    assert _ip_all_private_or_all_public([\"127.0.0.1\", \"127.0.0.1\"]) is True\n    assert _ip_all_private_or_all_public([\"localhost\", \"127.0.0.1\"]) is True\n    assert _ip_all_private_or_all_public([\"10.0.0.1\", \"127.0.0.1\"]) is False\n    assert _ip_all_private_or_all_public([\"fetch.ai\", \"127.0.0.1\"]) is False\n    assert _ip_all_private_or_all_public([\"104.26.2.97\", \"127.0.0.1\"]) is False\n    assert _ip_all_private_or_all_public([\"fetch.ai\", \"acn.fetch.ai\"]) is True\n\n\ndef test_libp2pconnection_node_config_registration_delay():\n    \"\"\"Test node registration delay configuration\"\"\"\n    host = \"localhost\"\n    port = \"10000\"\n\n    with tempfile.TemporaryDirectory() as data_dir:\n        _make_libp2p_connection(\n            port=port, host=host, data_dir=data_dir, build_directory=data_dir\n        )\n    with tempfile.TemporaryDirectory() as data_dir:\n        with pytest.raises(ValueError):\n            _make_libp2p_connection(\n                port=port,\n                host=host,\n                data_dir=data_dir,\n                peer_registration_delay=\"must_be_float\",\n                build_directory=data_dir,\n            )\n\n\ndef test_build_dir_not_set():\n    \"\"\"Test build dir not set.\"\"\"\n    host = \"localhost\"\n    port = \"10000\"\n    with tempfile.TemporaryDirectory() as data_dir:\n        con = _make_libp2p_connection(\n            port=port, host=host, data_dir=data_dir, build_directory=data_dir\n        )\n        con.configuration.build_directory = None\n        with pytest.raises(\n            ValueError, match=\"Connection Configuration build directory is not set!\"\n        ):\n            P2PLibp2pConnection(\n                configuration=con.configuration,\n                data_dir=data_dir,\n                identity=con._identity,\n                crypto_store=con.crypto_store,\n            )\n\n\n@pytest.mark.asyncio\nasync def test_reconnect_on_write_failed():\n    \"\"\"Test node restart on write fail.\"\"\"\n    host = \"localhost\"\n    port = \"10000\"\n    with patch(\n        \"packages.fetchai.connections.p2p_libp2p.connection.P2PLibp2pConnection._check_node_built\",\n        return_value=\"./\",\n    ), patch(\"tests.conftest.build_node\"), tempfile.TemporaryDirectory() as data_dir:\n        con = _make_libp2p_connection(\n            port=port, host=host, data_dir=data_dir, build_directory=data_dir\n        )\n    node = Libp2pNode(Mock(), Mock(), \"tmp\", \"tmp\")\n    con.node = node\n    node.pipe = Mock()\n    node.pipe.write = Mock(side_effect=Exception(\"expected\"))\n    con._node_client = node.get_client()\n    f = Future()\n    f.set_result(None)\n    with patch.object(\n        con, \"_restart_node\", return_value=f\n    ) as restart_mock, patch.object(\n        con, \"_ensure_valid_envelope_for_external_comms\"\n    ), patch.object(\n        con._node_client, \"make_acn_envelope_message\", return_value=b\"some_data\"\n    ), pytest.raises(\n        Exception, match=\"expected\"\n    ):\n        await con._send_envelope_with_node_client(Mock())\n\n    assert node.pipe.write.call_count == 2\n    restart_mock.assert_called_once()\n\n\n@pytest.mark.asyncio\nasync def test_reconnect_on_write_failed_reconnect_pipe():\n    \"\"\"Test node restart on write fail.\"\"\"\n    host = \"localhost\"\n    port = \"10000\"\n    with patch(\n        \"packages.fetchai.connections.p2p_libp2p.connection.P2PLibp2pConnection._check_node_built\",\n        return_value=\"./\",\n    ), patch(\"tests.conftest.build_node\"), tempfile.TemporaryDirectory() as data_dir:\n        con = _make_libp2p_connection(\n            port=port, host=host, data_dir=data_dir, build_directory=data_dir\n        )\n\n    node = Libp2pNode(Mock(), Mock(), \"tmp\", \"tmp\")\n    f = Future()\n    f.set_result(None)\n    con.node = node\n    node.pipe = Mock()\n    node.pipe.connect = Mock(return_value=f)\n    node.pipe.write = Mock(side_effect=[Exception(\"expected\"), f])\n    node.pipe.close = Mock(return_value=f)\n\n    con._node_client = node.get_client()\n    status_ok = Mock()\n    status_ok.code = int(AcnMessage.StatusBody.StatusCode.SUCCESS)\n    status_ok_future = Future()\n    status_ok_future.set_result(status_ok)\n    with patch.object(con, \"_ensure_valid_envelope_for_external_comms\"), patch.object(\n        node, \"is_proccess_running\", return_value=True\n    ), patch.object(\n        con._node_client, \"make_acn_envelope_message\", return_value=b\"some_data\"\n    ), patch.object(\n        con._node_client, \"wait_for_status\", lambda: status_ok_future\n    ):\n        await con._send_envelope_with_node_client(Mock())\n\n    assert node.pipe.write.call_count == 2\n    assert node.pipe.connect.call_count == 1\n\n\n@pytest.mark.asyncio\nasync def test_reconnect_on_read_failed():\n    \"\"\"Test node restart on read fail.\"\"\"\n    host = \"localhost\"\n    port = \"10000\"\n    with patch(\n        \"packages.fetchai.connections.p2p_libp2p.connection.P2PLibp2pConnection._check_node_built\",\n        return_value=\"./\",\n    ), patch(\"tests.conftest.build_node\"), tempfile.TemporaryDirectory() as data_dir:\n        con = _make_libp2p_connection(\n            port=port, host=host, data_dir=data_dir, build_directory=data_dir\n        )\n    node = Libp2pNode(Mock(), Mock(), \"tmp\", \"tmp\")\n    con.node = node\n    node.pipe = Mock()\n    node.pipe.read = Mock(side_effect=Exception(\"expected\"))\n    con._node_client = node.get_client()\n    f = Future()\n    f.set_result(None)\n    with patch.object(\n        con, \"_restart_node\", return_value=f\n    ) as restart_mock, pytest.raises(Exception, match=\"expected\"):\n        await con._read_envelope_from_node()\n\n    assert node.pipe.read.call_count == 2\n    restart_mock.assert_called_once()\n\n    assert node.pipe.read.call_count == 2\n    restart_mock.assert_called_once()\n\n\n@pytest.mark.asyncio\nasync def test_max_restarts():\n    \"\"\"Test node max restarts exception.\"\"\"\n    node = Libp2pNode(Mock(), Mock(), \"tmp\", \"tmp\", max_restarts=0)\n    with pytest.raises(ValueError, match=\"Max restarts attempts reached:\"):\n        await node.restart()\n\n\n@pytest.mark.asyncio\nasync def test_node_stopped_callback():\n    \"\"\"Test node stopped callback called.\"\"\"\n    if not (\n        platform.system() != \"Windows\"\n        and sys.version_info.major == 3\n        and sys.version_info.minor >= 8\n    ):\n        pytest.skip(\n            \"Not supported on this platform. Unix and python >= 3.8 supported only\"\n        )\n    host = \"127.0.0.1\"\n    port = \"10000\"\n\n    with tempfile.TemporaryDirectory() as data_dir:\n        con = _make_libp2p_connection(\n            port=port, host=host, data_dir=data_dir, build_directory=data_dir\n        )\n        con.node.logger.error = Mock()\n        await con.node.start()\n        subprocess.Popen.terminate(con.node.proc)\n        await asyncio.sleep(2)\n        con.node.logger.error.assert_called_once()\n        await con.node.stop()\n\n    with tempfile.TemporaryDirectory() as data_dir:\n        con = _make_libp2p_connection(\n            port=port, host=host, data_dir=data_dir, build_directory=data_dir\n        )\n        con.node.logger.error = Mock()\n        await con.node.start()\n        await con.node.stop()\n        await asyncio.sleep(2)\n        con.node.logger.error.assert_not_called()\n\n\n@pytest.mark.asyncio\nasync def test_send_acn_confirm_failed():\n    \"\"\"Test nodeclient send fails on confirmation from other point .\"\"\"\n    node = Libp2pNode(Mock(), Mock(), \"tmp\", \"tmp\")\n    f = Future()\n    f.set_result(None)\n    node.pipe = Mock()\n    node.pipe.connect = Mock(return_value=f)\n    node.pipe.write = Mock(return_value=f)\n\n    node_client = node.get_client()\n    status = Mock()\n    status.code = int(AcnMessage.StatusBody.StatusCode.ERROR_GENERIC)\n    status_future = Future()\n    status_future.set_result(status)\n    with patch.object(\n        node_client, \"make_acn_envelope_message\", return_value=b\"some_data\"\n    ), patch.object(\n        node_client, \"wait_for_status\", lambda: status_future\n    ), pytest.raises(\n        Exception, match=r\"failed to send envelope. got error confirmation\"\n    ):\n        await node_client.send_envelope(Mock())\n\n\n@pytest.mark.asyncio\nasync def test_send_acn_confirm_timeout():\n    \"\"\"Test nodeclient send fails on timeout.\"\"\"\n    node = Libp2pNode(Mock(), Mock(), \"tmp\", \"tmp\")\n    f = Future()\n    f.set_result(None)\n    node.pipe = Mock()\n    node.pipe.connect = Mock(return_value=f)\n    node.pipe.write = Mock(return_value=f)\n\n    node_client = node.get_client()\n    node_client.ACN_ACK_TIMEOUT = 0.5\n    with patch.object(\n        node_client, \"make_acn_envelope_message\", return_value=b\"some_data\"\n    ), patch(\"asyncio.wait_for\", side_effect=asyncio.TimeoutError()), pytest.raises(\n        Exception, match=r\"acn status await timeout!\"\n    ):\n        await node_client.send_envelope(Mock())\n\n\n@pytest.mark.asyncio\nasync def test_acn_decode_error_on_read():\n    \"\"\"Test nodeclient send fails on read.\"\"\"\n    node = Libp2pNode(Mock(), Mock(), \"tmp\", \"tmp\")\n    f = Future()\n    f.set_result(b\"some_data\")\n    node.pipe = Mock()\n    node.pipe.connect = Mock(return_value=f)\n\n    node_client = node.get_client()\n    node_client.ACN_ACK_TIMEOUT = 0.5\n\n    with patch.object(node_client, \"_read\", lambda: f), patch.object(\n        node_client, \"write_acn_status_error\", return_value=f\n    ) as mocked_write_acn_status_error, pytest.raises(\n        Exception, match=r\"Error parsing acn message:\"\n    ):\n        await node_client.read_envelope()\n\n    mocked_write_acn_status_error.assert_called_once()\n\n\n@pytest.mark.asyncio\nasync def test_write_acn_error():\n    \"\"\"Test nodeclient write acn error.\"\"\"\n    node = Libp2pNode(Mock(), Mock(), \"tmp\", \"tmp\")\n    f = Future()\n    f.set_result(b\"some_data\")\n    node.pipe = Mock()\n    node.pipe.connect = Mock(return_value=f)\n\n    node_client = node.get_client()\n\n    with patch.object(node_client, \"_write\", return_value=f) as write_mock:\n        await node_client.write_acn_status_error(\"some error\")\n\n    write_mock.assert_called_once()\n"
  },
  {
    "path": "tests/test_packages/test_connections/test_p2p_libp2p/test_fault_tolerance.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This test module contains resilience and fault tolerance tests for P2PLibp2p connection.\"\"\"\nimport os\nimport shutil\nimport tempfile\nimport time\n\nimport pytest\n\nfrom aea.configurations.constants import DEFAULT_LEDGER\nfrom aea.crypto.registries import make_crypto\nfrom aea.mail.base import Envelope\nfrom aea.multiplexer import Multiplexer\n\nfrom packages.fetchai.connections.p2p_libp2p.check_dependencies import build_node\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.protocols.default.serialization import DefaultSerializer\n\nfrom tests.common.utils import wait_for_condition\nfrom tests.conftest import (\n    MAX_FLAKY_RERUNS_INTEGRATION,\n    _make_libp2p_connection,\n    libp2p_log_on_failure,\n    libp2p_log_on_failure_all,\n)\n\n\nDEFAULT_PORT = 10234\n\n\n@pytest.mark.flaky(reruns=MAX_FLAKY_RERUNS_INTEGRATION)\nclass BaseTestLibp2pRelay:\n    \"\"\"Base test class for libp2p connection relay.\"\"\"\n\n    @libp2p_log_on_failure\n    def setup(self):\n        \"\"\"Set the test up\"\"\"\n        self.cwd = os.getcwd()\n        self.t = tempfile.mkdtemp()\n        os.chdir(self.t)\n        build_node(self.t)\n        self.log_files = []\n        self.multiplexers = []\n\n    def change_state_and_wait(\n        self,\n        multiplexer: Multiplexer,\n        expected_is_connected: bool = False,\n        timeout: int = 10,\n    ) -> None:\n        \"\"\"\n        Change state of a multiplexer (either connect or disconnect) and wait.\n\n        :param multiplexer: the multiplexer to connect/disconnect.\n        :param expected_is_connected: whether it should be connected or disconnected.\n        :param timeout: the maximum number seconds to wait.\n        :return: None\n        \"\"\"\n        wait_for_condition(\n            lambda: multiplexer.is_connected == expected_is_connected, timeout=timeout\n        )\n\n    def teardown(self):\n        \"\"\"Tear down the test\"\"\"\n        for mux in self.multiplexers:\n            mux.disconnect()\n        os.chdir(self.cwd)\n        try:\n            shutil.rmtree(self.t)\n        except (OSError, IOError):\n            pass\n\n\n@libp2p_log_on_failure_all\nclass TestLibp2pConnectionRelayNodeRestartIncomingEnvelopes(BaseTestLibp2pRelay):\n    \"\"\"Test that connection will reliably receive envelopes after its relay node restarted\"\"\"\n\n    @libp2p_log_on_failure\n    def setup(self):\n        \"\"\"Set the test up\"\"\"\n        super().setup()\n        temp_dir_gen = os.path.join(self.t, \"temp_dir_gen\")\n        os.mkdir(temp_dir_gen)\n        self.genesis = _make_libp2p_connection(\n            data_dir=temp_dir_gen, port=DEFAULT_PORT + 1, build_directory=self.t\n        )\n\n        self.multiplexer_genesis = Multiplexer(\n            [self.genesis], protocols=[DefaultMessage]\n        )\n        self.multiplexer_genesis.connect()\n        self.log_files.append(self.genesis.node.log_file)\n        self.multiplexers.append(self.multiplexer_genesis)\n\n        genesis_peer = self.genesis.node.multiaddrs[0]\n\n        file = \"node_key\"\n        make_crypto(DEFAULT_LEDGER).dump(file)\n        self.relay_key_path = file\n\n        temp_dir_rel = os.path.join(self.t, \"temp_dir_rel\")\n        os.mkdir(temp_dir_rel)\n        self.relay = _make_libp2p_connection(\n            data_dir=temp_dir_rel,\n            port=DEFAULT_PORT + 2,\n            entry_peers=[genesis_peer],\n            node_key_file=self.relay_key_path,\n            build_directory=self.t,\n        )\n        self.multiplexer_relay = Multiplexer([self.relay], protocols=[DefaultMessage])\n        self.multiplexer_relay.connect()\n        self.log_files.append(self.relay.node.log_file)\n        self.multiplexers.append(self.multiplexer_relay)\n\n        relay_peer = self.relay.node.multiaddrs[0]\n\n        temp_dir_1 = os.path.join(self.t, \"temp_dir_1\")\n        os.mkdir(temp_dir_1)\n        self.connection = _make_libp2p_connection(\n            data_dir=temp_dir_1,\n            port=DEFAULT_PORT + 3,\n            relay=False,\n            entry_peers=[relay_peer],\n            build_directory=self.t,\n        )\n        self.multiplexer = Multiplexer([self.connection], protocols=[DefaultMessage])\n        self.multiplexer.connect()\n        self.log_files.append(self.connection.node.log_file)\n        self.multiplexers.append(self.multiplexer)\n\n        temp_dir_2 = os.path.join(self.t, \"temp_dir_2\")\n        os.mkdir(temp_dir_2)\n        self.connection2 = _make_libp2p_connection(\n            data_dir=temp_dir_2,\n            port=DEFAULT_PORT + 4,\n            relay=False,\n            entry_peers=[relay_peer],\n            build_directory=self.t,\n        )\n        self.multiplexer2 = Multiplexer([self.connection2], protocols=[DefaultMessage])\n        self.multiplexer2.connect()\n        self.log_files.append(self.connection2.node.log_file)\n        self.multiplexers.append(self.multiplexer2)\n\n    def test_connection_is_established(self):\n        \"\"\"Test connection established.\"\"\"\n        assert self.relay.is_connected is True\n        assert self.connection.is_connected is True\n        assert self.connection2.is_connected is True\n\n    def test_envelope_routed_from_peer_after_relay_restart(self):\n        \"\"\"Test envelope routed from third peer after relay restart.\"\"\"\n        addr_1 = self.genesis.address\n        addr_2 = self.connection.address\n\n        msg = DefaultMessage(\n            dialogue_reference=(\"\", \"\"),\n            message_id=1,\n            target=0,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"hello\",\n        )\n        envelope = Envelope(\n            to=addr_2,\n            sender=addr_1,\n            protocol_specification_id=DefaultMessage.protocol_specification_id,\n            message=DefaultSerializer().encode(msg),\n        )\n\n        self.multiplexer_genesis.put(envelope)\n        delivered_envelope = self.multiplexer.get(block=True, timeout=20)\n\n        assert delivered_envelope is not None\n        assert delivered_envelope.to == envelope.to\n        assert delivered_envelope.sender == envelope.sender\n        assert (\n            delivered_envelope.protocol_specification_id\n            == envelope.protocol_specification_id\n        )\n        assert delivered_envelope.message_bytes == envelope.message_bytes\n\n        self.multiplexer_relay.disconnect()\n        self.change_state_and_wait(self.multiplexer_relay, expected_is_connected=False)\n\n        # currently, multiplexer cannot be restarted\n        self.multiplexer_relay = Multiplexer([self.relay], protocols=[DefaultMessage])\n        self.multiplexer_relay.connect()\n        self.change_state_and_wait(self.multiplexer_relay, expected_is_connected=True)\n        self.multiplexers.append(self.multiplexer_relay)\n\n        msg = DefaultMessage(\n            dialogue_reference=(\"\", \"\"),\n            message_id=1,\n            target=0,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"helloAfterRestart\",\n        )\n        envelope = Envelope(\n            to=addr_2,\n            sender=addr_1,\n            protocol_specification_id=DefaultMessage.protocol_specification_id,\n            message=DefaultSerializer().encode(msg),\n        )\n\n        time.sleep(10)\n        self.multiplexer_genesis.put(envelope)\n\n        delivered_envelope = self.multiplexer.get(block=True, timeout=20)\n\n        assert delivered_envelope is not None\n        assert delivered_envelope.to == envelope.to\n        assert delivered_envelope.sender == envelope.sender\n        assert (\n            delivered_envelope.protocol_specification_id\n            == envelope.protocol_specification_id\n        )\n        assert delivered_envelope.message_bytes == envelope.message_bytes\n\n    def test_envelope_routed_from_client_after_relay_restart(self):\n        \"\"\"Test envelope routed from third relay client after relay restart.\"\"\"\n        addr_1 = self.connection.address\n        addr_2 = self.connection2.address\n\n        msg = DefaultMessage(\n            dialogue_reference=(\"\", \"\"),\n            message_id=1,\n            target=0,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"hello\",\n        )\n        envelope = Envelope(\n            to=addr_1,\n            sender=addr_2,\n            protocol_specification_id=DefaultMessage.protocol_specification_id,\n            message=DefaultSerializer().encode(msg),\n        )\n\n        self.multiplexer2.put(envelope)\n        delivered_envelope = self.multiplexer.get(block=True, timeout=20)\n\n        assert delivered_envelope is not None\n        assert delivered_envelope.to == envelope.to\n        assert delivered_envelope.sender == envelope.sender\n        assert (\n            delivered_envelope.protocol_specification_id\n            == envelope.protocol_specification_id\n        )\n        assert delivered_envelope.message_bytes == envelope.message_bytes\n\n        self.multiplexer_relay.disconnect()\n        self.change_state_and_wait(self.multiplexer_relay, expected_is_connected=False)\n\n        # currently, multiplexer cannot be restarted\n        self.multiplexer_relay = Multiplexer([self.relay], protocols=[DefaultMessage])\n        self.multiplexer_relay.connect()\n        self.change_state_and_wait(self.multiplexer_relay, expected_is_connected=True)\n        self.multiplexers.append(self.multiplexer_relay)\n\n        msg = DefaultMessage(\n            dialogue_reference=(\"\", \"\"),\n            message_id=1,\n            target=0,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"helloAfterRestart\",\n        )\n\n        envelope = Envelope(\n            to=addr_1,\n            sender=addr_2,\n            protocol_specification_id=DefaultMessage.protocol_specification_id,\n            message=DefaultSerializer().encode(msg),\n        )\n\n        time.sleep(10)\n        self.multiplexer2.put(envelope)\n        delivered_envelope = self.multiplexer.get(block=True, timeout=20)\n\n        assert delivered_envelope is not None\n        assert delivered_envelope.to == envelope.to\n        assert delivered_envelope.sender == envelope.sender\n        assert (\n            delivered_envelope.protocol_specification_id\n            == envelope.protocol_specification_id\n        )\n        assert delivered_envelope.message_bytes == envelope.message_bytes\n\n\n@libp2p_log_on_failure_all\nclass TestLibp2pConnectionRelayNodeRestartOutgoingEnvelopes(BaseTestLibp2pRelay):\n    \"\"\"Test that connection will reliably route envelope to destination in case of relay node restart within timeout\"\"\"\n\n    @libp2p_log_on_failure\n    def setup(self):\n        \"\"\"Set the test up\"\"\"\n        super().setup()\n        temp_dir_gen = os.path.join(self.t, \"temp_dir_gen\")\n        os.mkdir(temp_dir_gen)\n        self.genesis = _make_libp2p_connection(\n            data_dir=temp_dir_gen, port=DEFAULT_PORT + 1, build_directory=self.t\n        )\n\n        self.multiplexer_genesis = Multiplexer(\n            [self.genesis], protocols=[DefaultMessage]\n        )\n        self.multiplexer_genesis.connect()\n        self.log_files.append(self.genesis.node.log_file)\n        self.multiplexers.append(self.multiplexer_genesis)\n\n        genesis_peer = self.genesis.node.multiaddrs[0]\n\n        file = \"node_key\"\n        make_crypto(DEFAULT_LEDGER).dump(file)\n        self.relay_key_path = file\n\n        temp_dir_rel = os.path.join(self.t, \"temp_dir_rel\")\n        os.mkdir(temp_dir_rel)\n        self.relay = _make_libp2p_connection(\n            data_dir=temp_dir_rel,\n            port=DEFAULT_PORT + 2,\n            entry_peers=[genesis_peer],\n            node_key_file=self.relay_key_path,\n            build_directory=self.t,\n        )\n        self.multiplexer_relay = Multiplexer([self.relay], protocols=[DefaultMessage])\n        self.multiplexer_relay.connect()\n        self.log_files.append(self.relay.node.log_file)\n        self.multiplexers.append(self.multiplexer_relay)\n\n        relay_peer = self.relay.node.multiaddrs[0]\n\n        temp_dir_1 = os.path.join(self.t, \"temp_dir_1\")\n        os.mkdir(temp_dir_1)\n        self.connection = _make_libp2p_connection(\n            data_dir=temp_dir_1,\n            port=DEFAULT_PORT + 3,\n            relay=False,\n            entry_peers=[relay_peer],\n            build_directory=self.t,\n        )\n        self.multiplexer = Multiplexer([self.connection], protocols=[DefaultMessage])\n        self.multiplexer.connect()\n        self.log_files.append(self.connection.node.log_file)\n        self.multiplexers.append(self.multiplexer)\n\n    def test_connection_is_established(self):\n        \"\"\"Test connection established.\"\"\"\n        assert self.relay.is_connected is True\n        assert self.connection.is_connected is True\n\n    def test_envelope_routed_after_relay_restart(self):\n        \"\"\"Test envelope routed after relay restart.\"\"\"\n        addr_1 = self.connection.address\n        addr_2 = self.genesis.address\n\n        msg = DefaultMessage(\n            dialogue_reference=(\"\", \"\"),\n            message_id=1,\n            target=0,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"hello\",\n        )\n        envelope = Envelope(\n            to=addr_2,\n            sender=addr_1,\n            protocol_specification_id=DefaultMessage.protocol_specification_id,\n            message=DefaultSerializer().encode(msg),\n        )\n\n        self.multiplexer.put(envelope)\n        delivered_envelope = self.multiplexer_genesis.get(block=True, timeout=20)\n\n        assert delivered_envelope is not None\n        assert delivered_envelope.to == envelope.to\n        assert delivered_envelope.sender == envelope.sender\n        assert (\n            delivered_envelope.protocol_specification_id\n            == envelope.protocol_specification_id\n        )\n        assert delivered_envelope.message_bytes == envelope.message_bytes\n\n        self.multiplexer_relay.disconnect()\n        self.change_state_and_wait(self.multiplexer_relay, expected_is_connected=False)\n\n        msg = DefaultMessage(\n            dialogue_reference=(\"\", \"\"),\n            message_id=1,\n            target=0,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"helloAfterRestart\",\n        )\n        envelope = Envelope(\n            to=addr_2,\n            sender=addr_1,\n            protocol_specification_id=DefaultMessage.protocol_specification_id,\n            message=DefaultSerializer().encode(msg),\n        )\n\n        time.sleep(10)\n        self.multiplexer.put(envelope)\n\n        # currently, multiplexer cannot be restarted\n        self.multiplexer_relay = Multiplexer([self.relay], protocols=[DefaultMessage])\n        self.multiplexer_relay.connect()\n        self.change_state_and_wait(self.multiplexer_relay, expected_is_connected=True)\n        self.multiplexers.append(self.multiplexer_relay)\n\n        delivered_envelope = self.multiplexer_genesis.get(block=True, timeout=20)\n\n        assert delivered_envelope is not None\n        assert delivered_envelope.to == envelope.to\n        assert delivered_envelope.sender == envelope.sender\n        assert (\n            delivered_envelope.protocol_specification_id\n            == envelope.protocol_specification_id\n        )\n        assert delivered_envelope.message_bytes == envelope.message_bytes\n\n\n@libp2p_log_on_failure_all\nclass TestLibp2pConnectionAgentMobility(BaseTestLibp2pRelay):\n    \"\"\"Test that connection will correctly route envelope to destination that changed its peer\"\"\"\n\n    @libp2p_log_on_failure\n    def setup(self):\n        \"\"\"Set the test up\"\"\"\n        super().setup()\n        temp_dir_gen = os.path.join(self.t, \"temp_dir_gen\")\n        os.mkdir(temp_dir_gen)\n        self.genesis = _make_libp2p_connection(data_dir=temp_dir_gen, port=DEFAULT_PORT)\n\n        self.multiplexer_genesis = Multiplexer(\n            [self.genesis], protocols=[DefaultMessage]\n        )\n        self.log_files.append(self.genesis.node.log_file)\n        self.multiplexer_genesis.connect()\n        self.multiplexers.append(self.multiplexer_genesis)\n\n        genesis_peer = self.genesis.node.multiaddrs[0]\n\n        temp_dir_1 = os.path.join(self.t, \"temp_dir_1\")\n        os.mkdir(temp_dir_1)\n        self.connection1 = _make_libp2p_connection(\n            data_dir=temp_dir_1, port=DEFAULT_PORT + 1, entry_peers=[genesis_peer]\n        )\n        self.multiplexer1 = Multiplexer([self.connection1], protocols=[DefaultMessage])\n        self.log_files.append(self.connection1.node.log_file)\n        self.multiplexer1.connect()\n        self.multiplexers.append(self.multiplexer1)\n\n        self.connection_key = make_crypto(DEFAULT_LEDGER)\n        temp_dir_2 = os.path.join(self.t, \"temp_dir_2\")\n        os.mkdir(temp_dir_2)\n        self.connection2 = _make_libp2p_connection(\n            data_dir=temp_dir_2,\n            port=DEFAULT_PORT + 2,\n            entry_peers=[genesis_peer],\n            agent_key=self.connection_key,\n        )\n        self.multiplexer2 = Multiplexer([self.connection2], protocols=[DefaultMessage])\n        self.log_files.append(self.connection2.node.log_file)\n        self.multiplexer2.connect()\n        self.multiplexers.append(self.multiplexer2)\n\n    def test_connection_is_established(self):\n        \"\"\"Test connection established.\"\"\"\n        assert self.connection1.is_connected is True\n        assert self.connection2.is_connected is True\n\n    def test_envelope_routed_after_peer_changed(self):\n        \"\"\"Test envelope routed after peer changed.\"\"\"\n        addr_1 = self.connection1.address\n        addr_2 = self.connection2.address\n\n        msg = DefaultMessage(\n            dialogue_reference=(\"\", \"\"),\n            message_id=1,\n            target=0,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"hello\",\n        )\n        envelope = Envelope(\n            to=addr_2,\n            sender=addr_1,\n            protocol_specification_id=DefaultMessage.protocol_specification_id,\n            message=DefaultSerializer().encode(msg),\n        )\n\n        self.multiplexer1.put(envelope)\n        delivered_envelope = self.multiplexer2.get(block=True, timeout=20)\n\n        assert delivered_envelope is not None\n        assert delivered_envelope.to == envelope.to\n        assert delivered_envelope.sender == envelope.sender\n        assert (\n            delivered_envelope.protocol_specification_id\n            == envelope.protocol_specification_id\n        )\n        assert delivered_envelope.message_bytes == envelope.message_bytes\n\n        self.multiplexer2.disconnect()\n        self.change_state_and_wait(self.multiplexer2, expected_is_connected=False)\n\n        # currently, multiplexer cannot be restarted\n        self.multiplexer2 = Multiplexer([self.connection2], protocols=[DefaultMessage])\n        self.multiplexer2.connect()\n        self.change_state_and_wait(self.multiplexer2, expected_is_connected=True)\n        self.multiplexers.append(self.multiplexer2)\n\n        msg = DefaultMessage(\n            dialogue_reference=(\"\", \"\"),\n            message_id=1,\n            target=0,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"helloAfterChangingPeer\",\n        )\n        envelope = Envelope(\n            to=addr_2,\n            sender=addr_1,\n            protocol_specification_id=msg.protocol_specification_id,\n            message=msg.encode(),\n        )\n\n        time.sleep(10)\n        self.multiplexer1.put(envelope)\n\n        delivered_envelope = self.multiplexer2.get(block=True, timeout=20)\n\n        assert delivered_envelope is not None\n        assert delivered_envelope.to == envelope.to\n        assert delivered_envelope.sender == envelope.sender\n        assert (\n            delivered_envelope.protocol_specification_id\n            == envelope.protocol_specification_id\n        )\n        assert delivered_envelope.message_bytes == envelope.message_bytes\n"
  },
  {
    "path": "tests/test_packages/test_connections/test_p2p_libp2p/test_integration.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This test module contains tests for P2PLibp2p connection.\"\"\"\nimport itertools\nimport os\nimport shutil\nimport tempfile\nfrom copy import copy\nfrom unittest.mock import Mock\n\nfrom aea.helpers.acn.uri import Uri\nfrom aea.mail.base import Envelope\nfrom aea.multiplexer import Multiplexer\n\nfrom packages.fetchai.protocols.default.message import DefaultMessage\n\nfrom tests.conftest import (\n    _make_libp2p_client_connection,\n    _make_libp2p_connection,\n    _make_libp2p_mailbox_connection,\n    libp2p_log_on_failure,\n    libp2p_log_on_failure_all,\n)\n\n\nDEFAULT_PORT = 10234\nDEFAULT_NET_SIZE = 4\n\nMockDefaultMessageProtocol = Mock()\nMockDefaultMessageProtocol.protocol_id = DefaultMessage.protocol_id\nMockDefaultMessageProtocol.protocol_specification_id = (\n    DefaultMessage.protocol_specification_id\n)\n\n\n@libp2p_log_on_failure_all\nclass TestP2PLibp2pConnectionIntegrationTest:\n    \"\"\"Test mix of relay/delegate agents and client connections work together\"\"\"\n\n    BASE_PORT_NUM: int = DEFAULT_PORT\n\n    @classmethod\n    def get_port(cls) -> int:\n        \"\"\"Get next port to use for libp2p.\"\"\"\n        cls.BASE_PORT_NUM += 1\n        return cls.BASE_PORT_NUM\n\n    @classmethod\n    def make_connection(cls, name, **kwargs):\n        \"\"\"Make a p2p connection.\"\"\"\n        if name in cls.multiplexers_dict:\n            raise ValueError(f\"Connection with name `{name}` already added\")\n        temp_dir = os.path.join(cls.t, name)\n        os.mkdir(temp_dir)\n        conn_options = copy(kwargs)\n        conn_options[\"port\"] = conn_options.get(\"port\", cls.get_port())\n        conn_options[\"data_dir\"] = conn_options.get(\"data_dir\", temp_dir)\n        conn = _make_libp2p_connection(**conn_options)\n        multiplexer = Multiplexer([conn], protocols=[MockDefaultMessageProtocol])\n        cls.log_files.append(conn.node.log_file)\n        multiplexer.connect()\n        cls.multiplexers_dict[name] = multiplexer\n        cls.connections_dict[name] = conn\n        return conn\n\n    @classmethod\n    def make_client_connection(cls, name, **kwargs):\n        \"\"\"Make a p2p client connection.\"\"\"\n        if name in cls.multiplexers_dict:\n            raise ValueError(f\"Connection with name `{name}` already added\")\n        temp_dir = os.path.join(cls.t, name)\n        os.mkdir(temp_dir)\n        conn_options = copy(kwargs)\n\n        conn_options[\"data_dir\"] = conn_options.get(\"data_dir\", temp_dir)\n        conn = _make_libp2p_client_connection(**conn_options)\n        multiplexer = Multiplexer([conn], protocols=[MockDefaultMessageProtocol])\n        multiplexer.connect()\n        cls.multiplexers_dict[name] = multiplexer\n        cls.connections_dict[name] = conn\n        return conn\n\n    @classmethod\n    def make_mailbox_connection(cls, name, **kwargs):\n        \"\"\"Make a p2p mailbox connection.\"\"\"\n        if name in cls.multiplexers_dict:\n            raise ValueError(f\"Connection with name `{name}` already added\")\n        temp_dir = os.path.join(cls.t, name)\n        os.mkdir(temp_dir)\n        conn_options = copy(kwargs)\n\n        conn_options[\"data_dir\"] = conn_options.get(\"data_dir\", temp_dir)\n        conn = _make_libp2p_mailbox_connection(**conn_options)\n        multiplexer = Multiplexer([conn], protocols=[MockDefaultMessageProtocol])\n        multiplexer.connect()\n        cls.multiplexers_dict[name] = multiplexer\n        cls.connections_dict[name] = conn\n        return conn\n\n    @classmethod\n    @libp2p_log_on_failure\n    def setup_class(cls):\n        \"\"\"Set the test up\"\"\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        os.chdir(cls.t)\n\n        cls.log_files = []\n        cls.multiplexers_dict = {}\n        cls.connections_dict = {}\n        cls.multiplexers = []\n\n        try:\n            cls.main_relay = cls.make_connection(\"main_relay\", relay=True)\n            main_relay = cls.main_relay.node.multiaddrs[0]\n            cls.relay_2 = cls.make_connection(\n                \"relay_2\", entry_peers=[main_relay], relay=True\n            )\n            relay_peer_2 = cls.relay_2.node.multiaddrs[0]\n\n            cls.delegate_1 = cls.make_connection(\n                \"delegate_1\",\n                entry_peers=[main_relay],\n                relay=True,\n                delegate=True,\n                delegate_port=cls.get_port(),\n                mailbox_port=cls.get_port(),\n                mailbox=True,\n            )\n\n            cls.delegate_2 = cls.make_connection(\n                \"delegate_2\",\n                entry_peers=[relay_peer_2],\n                relay=True,\n                delegate=True,\n                delegate_port=cls.get_port(),\n                mailbox_port=cls.get_port(),\n                mailbox=True,\n            )\n\n            cls.agent_connection_1 = cls.make_connection(\n                \"agent_connection_1\",\n                entry_peers=[main_relay],\n                relay=False,\n                delegate=False,\n            )\n\n            cls.agent_connection_2 = cls.make_connection(\n                \"agent_connection_2\",\n                entry_peers=[relay_peer_2],\n                relay=False,\n                delegate=False,\n            )\n            cls.client_connection_1 = cls.make_client_connection(\n                \"client_1\",\n                peer_public_key=cls.delegate_1.node.pub,\n                **cls.get_delegate_host_port(cls.delegate_1.node.delegate_uri),\n            )\n\n            cls.client_connection_2 = cls.make_client_connection(\n                \"client_2\",\n                peer_public_key=cls.delegate_2.node.pub,\n                **cls.get_delegate_host_port(cls.delegate_2.node.delegate_uri),\n            )\n            cls.mailbox_connection_1 = cls.make_mailbox_connection(\n                \"mailbox_1\",\n                peer_public_key=cls.delegate_1.node.pub,\n                **cls.get_delegate_host_port(Uri(cls.delegate_1.node.mailbox_uri)),\n            )\n\n            cls.mailbox_connection_2 = cls.make_mailbox_connection(\n                \"mailbox_2\",\n                peer_public_key=cls.delegate_2.node.pub,\n                **cls.get_delegate_host_port(Uri(cls.delegate_2.node.mailbox_uri)),\n            )\n        except Exception:\n            cls.teardown_class()\n            raise\n\n    @classmethod\n    def get_delegate_host_port(cls, delegate_uri: Uri) -> dict:\n        \"\"\"Get delegate/mailbox server config dict.\"\"\"\n        return {\"node_port\": delegate_uri.port, \"node_host\": delegate_uri.host}\n\n    def test_connection_is_established(self):\n        \"\"\"Test connection established.\"\"\"\n        for conn in self.connections_dict.values():\n            assert conn.is_connected is True\n\n    def send_message(self, from_name: str, to_name: str) -> None:\n        \"\"\"Send message from one connection to another and check it's delivered.\"\"\"\n        from_addr = self.connections_dict[from_name].address  # type: ignore\n        to_addr = self.connections_dict[to_name].address  # type: ignore\n\n        from_multiplexer = self.multiplexers_dict[from_name]  # type: ignore\n        to_multiplexer = self.multiplexers_dict[to_name]  # type: ignore\n\n        msg = DefaultMessage(\n            dialogue_reference=(\"\", \"\"),\n            message_id=1,\n            target=0,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"hello\",\n        )\n        envelope = Envelope(\n            to=to_addr,\n            sender=from_addr,\n            message=msg,\n        )\n\n        from_multiplexer.put(envelope)\n\n        delivered_envelope = to_multiplexer.get(block=True, timeout=10)\n\n        assert delivered_envelope is not None\n        assert delivered_envelope.to == envelope.to\n        assert delivered_envelope.sender == envelope.sender\n        assert (\n            delivered_envelope.protocol_specification_id\n            == envelope.protocol_specification_id\n        )\n        assert delivered_envelope.message != envelope.message\n        msg = DefaultMessage.serializer.decode(delivered_envelope.message)  # type: ignore\n        msg.sender = delivered_envelope.sender\n        msg.to = delivered_envelope.to\n        assert envelope.message == msg\n\n    def test_send_and_receive(self):\n        \"\"\"Test envelope send/received by every pair of connection.\"\"\"\n        for from_name, to_name in itertools.permutations(\n            [\n                \"client_1\",\n                \"client_2\",\n                \"agent_connection_1\",\n                \"agent_connection_2\",\n                \"mailbox_1\",\n                \"mailbox_2\",\n            ],\n            2,\n        ):\n            self.send_message(from_name, to_name)\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear down the test\"\"\"\n        for mux in cls.multiplexers:\n            mux.disconnect()\n\n        for mux in cls.multiplexers_dict.values():\n            mux.disconnect()\n\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n"
  },
  {
    "path": "tests/test_packages/test_connections/test_p2p_libp2p/test_public_dht.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This test module contains integration tests for P2PLibp2p connection.\"\"\"\n\nimport os\nimport shutil\nimport tempfile\n\nimport pytest\n\nfrom aea.helpers.base import CertRequest\nfrom aea.mail.base import Envelope\nfrom aea.multiplexer import Multiplexer\nfrom aea.test_tools.test_cases import AEATestCaseMany\n\nfrom packages.fetchai.connections.p2p_libp2p.connection import (\n    PUBLIC_ID as P2P_CONNECTION_PUBLIC_ID,\n)\nfrom packages.fetchai.connections.p2p_libp2p_client.connection import (\n    PUBLIC_ID as P2P_CLIENT_CONNECTION_PUBLIC_ID,\n)\nfrom packages.fetchai.protocols.default.message import DefaultMessage\n\nfrom tests.conftest import (\n    PUBLIC_DHT_DELEGATE_URI_1,\n    PUBLIC_DHT_DELEGATE_URI_2,\n    PUBLIC_DHT_P2P_MADDR_1,\n    PUBLIC_DHT_P2P_MADDR_2,\n    PUBLIC_DHT_P2P_PUBLIC_KEY_1,\n    PUBLIC_DHT_P2P_PUBLIC_KEY_2,\n    PUBLIC_STAGING_DHT_DELEGATE_URI_1,\n    PUBLIC_STAGING_DHT_DELEGATE_URI_2,\n    PUBLIC_STAGING_DHT_P2P_MADDR_1,\n    PUBLIC_STAGING_DHT_P2P_MADDR_2,\n    PUBLIC_STAGING_DHT_P2P_PUBLIC_KEY_1,\n    PUBLIC_STAGING_DHT_P2P_PUBLIC_KEY_2,\n    _make_libp2p_client_connection,\n    _make_libp2p_connection,\n    libp2p_log_on_failure,\n    libp2p_log_on_failure_all,\n)\n\n\nDEFAULT_PORT = 10234\nPUBLIC_DHT_MADDRS = [PUBLIC_DHT_P2P_MADDR_1, PUBLIC_DHT_P2P_MADDR_2]\nPUBLIC_DHT_DELEGATE_URIS = [PUBLIC_DHT_DELEGATE_URI_1, PUBLIC_DHT_DELEGATE_URI_2]\nPUBLIC_DHT_PUBLIC_KEYS = [PUBLIC_DHT_P2P_PUBLIC_KEY_1, PUBLIC_DHT_P2P_PUBLIC_KEY_2]\nPUBLIC_STAGING_DHT_MADDRS = [\n    PUBLIC_STAGING_DHT_P2P_MADDR_1,\n    PUBLIC_STAGING_DHT_P2P_MADDR_2,\n]\nPUBLIC_STAGING_DHT_DELEGATE_URIS = [\n    PUBLIC_STAGING_DHT_DELEGATE_URI_1,\n    PUBLIC_STAGING_DHT_DELEGATE_URI_2,\n]\nPUBLIC_STAGING_DHT_PUBLIC_KEYS = [\n    PUBLIC_STAGING_DHT_P2P_PUBLIC_KEY_1,\n    PUBLIC_STAGING_DHT_P2P_PUBLIC_KEY_2,\n]\nAEA_DEFAULT_LAUNCH_TIMEOUT = 20\nAEA_LIBP2P_LAUNCH_TIMEOUT = 20\n\n\n@pytest.fixture\ndef maddrs(request):\n    \"\"\"Fixture for multi addresses.\"\"\"\n    return request.param\n\n\n@pytest.fixture\ndef delegate_uris_public_keys(request):\n    \"\"\"Fixture for delegate uris and public keys.\"\"\"\n    return request.param\n\n\n@pytest.mark.integration\n@libp2p_log_on_failure_all\nclass TestLibp2pConnectionPublicDHTRelay:\n    \"\"\"Test that public DHT's relay service is working properly\"\"\"\n\n    def setup(self):\n        \"\"\"Set the test up\"\"\"\n        self.cwd = os.getcwd()\n        self.t = tempfile.mkdtemp()\n        os.chdir(self.t)\n\n        self.log_files = []\n\n    @pytest.mark.parametrize(\n        \"maddrs\", [PUBLIC_DHT_MADDRS, PUBLIC_STAGING_DHT_MADDRS], indirect=True\n    )\n    def test_connectivity(self, maddrs):\n        \"\"\"Test connectivity.\"\"\"\n        for i, maddr in enumerate(maddrs):\n            temp_dir = os.path.join(self.t, f\"dir_{i}\")\n            os.mkdir(temp_dir)\n            connection = _make_libp2p_connection(\n                port=DEFAULT_PORT + 1,\n                relay=False,\n                entry_peers=[maddr],\n                data_dir=temp_dir,\n            )\n            multiplexer = Multiplexer([connection])\n            self.log_files.append(connection.node.log_file)\n            multiplexer.connect()\n\n            try:\n                assert (\n                    connection.is_connected is True\n                ), \"Couldn't connect to public node {}\".format(maddr)\n            except Exception:\n                raise\n            finally:\n                multiplexer.disconnect()\n\n    @pytest.mark.parametrize(\n        \"maddrs\", [PUBLIC_DHT_MADDRS, PUBLIC_STAGING_DHT_MADDRS], indirect=True\n    )\n    def test_communication_direct(self, maddrs):\n        \"\"\"Test communication direct.\"\"\"\n        for i, maddr in enumerate(maddrs):\n            multiplexers = []\n            try:\n                temp_dir_1 = os.path.join(self.t, f\"dir_{i}_1\")\n                os.mkdir(temp_dir_1)\n                connection1 = _make_libp2p_connection(\n                    port=DEFAULT_PORT + 1,\n                    relay=False,\n                    entry_peers=[maddr],\n                    data_dir=temp_dir_1,\n                )\n                multiplexer1 = Multiplexer([connection1])\n                self.log_files.append(connection1.node.log_file)\n                multiplexer1.connect()\n                multiplexers.append(multiplexer1)\n\n                temp_dir_2 = os.path.join(self.t, f\"dir_{i}_2\")\n                os.mkdir(temp_dir_2)\n                connection2 = _make_libp2p_connection(\n                    port=DEFAULT_PORT + 2,\n                    relay=False,\n                    entry_peers=[maddr],\n                    data_dir=temp_dir_2,\n                )\n                multiplexer2 = Multiplexer([connection2])\n                self.log_files.append(connection2.node.log_file)\n                multiplexer2.connect()\n                multiplexers.append(multiplexer2)\n\n                addr_1 = connection1.node.address\n                addr_2 = connection2.node.address\n\n                msg = DefaultMessage(\n                    dialogue_reference=(\"\", \"\"),\n                    message_id=1,\n                    target=0,\n                    performative=DefaultMessage.Performative.BYTES,\n                    content=b\"hello\",\n                )\n                envelope = Envelope(\n                    to=addr_2,\n                    sender=addr_1,\n                    message=msg,\n                )\n\n                multiplexer1.put(envelope)\n                delivered_envelope = multiplexer2.get(block=True, timeout=20)\n\n                assert delivered_envelope is not None\n                assert delivered_envelope.to == envelope.to\n                assert delivered_envelope.sender == envelope.sender\n                assert (\n                    delivered_envelope.protocol_specification_id\n                    == envelope.protocol_specification_id\n                )\n                assert delivered_envelope.message != envelope.message\n                msg = DefaultMessage.serializer.decode(delivered_envelope.message)\n                msg.to = delivered_envelope.to\n                msg.sender = delivered_envelope.sender\n                assert envelope.message == msg\n            except Exception:\n                raise\n            finally:\n                for mux in multiplexers:\n                    mux.disconnect()\n\n    @pytest.mark.parametrize(\n        \"maddrs\", [PUBLIC_DHT_MADDRS, PUBLIC_STAGING_DHT_MADDRS], indirect=True\n    )\n    def test_communication_indirect(self, maddrs):\n        \"\"\"Test communication indirect.\"\"\"\n        assert len(maddrs) > 1, \"Test requires at least 2 public dht node\"\n\n        for i in range(len(maddrs)):\n            multiplexers = []\n            try:\n                temp_dir_1 = os.path.join(self.t, f\"dir_{i}__\")\n                os.mkdir(temp_dir_1)\n                connection1 = _make_libp2p_connection(\n                    port=DEFAULT_PORT + 1,\n                    relay=False,\n                    entry_peers=[maddrs[i]],\n                    data_dir=temp_dir_1,\n                )\n                multiplexer1 = Multiplexer([connection1])\n                self.log_files.append(connection1.node.log_file)\n                multiplexer1.connect()\n                multiplexers.append(multiplexer1)\n                addr_1 = connection1.node.address\n\n                for j in range(len(maddrs)):\n                    if j == i:\n                        continue\n\n                    temp_dir_2 = os.path.join(self.t, f\"dir_{i}_{j}\")\n                    os.mkdir(temp_dir_2)\n                    connection2 = _make_libp2p_connection(\n                        port=DEFAULT_PORT + 2,\n                        relay=False,\n                        entry_peers=[maddrs[j]],\n                        data_dir=temp_dir_2,\n                    )\n                    multiplexer2 = Multiplexer([connection2])\n                    self.log_files.append(connection2.node.log_file)\n                    multiplexer2.connect()\n                    multiplexers.append(multiplexer2)\n\n                    addr_2 = connection2.node.address\n\n                    msg = DefaultMessage(\n                        dialogue_reference=(\"\", \"\"),\n                        message_id=1,\n                        target=0,\n                        performative=DefaultMessage.Performative.BYTES,\n                        content=b\"hello\",\n                    )\n                    envelope = Envelope(\n                        to=addr_2,\n                        sender=addr_1,\n                        message=msg,\n                    )\n\n                    multiplexer1.put(envelope)\n                    delivered_envelope = multiplexer2.get(block=True, timeout=20)\n\n                    assert delivered_envelope is not None\n                    assert delivered_envelope.to == envelope.to\n                    assert delivered_envelope.sender == envelope.sender\n                    assert (\n                        delivered_envelope.protocol_specification_id\n                        == envelope.protocol_specification_id\n                    )\n                    assert delivered_envelope.message != envelope.message\n                    msg = DefaultMessage.serializer.decode(delivered_envelope.message)\n                    msg.to = delivered_envelope.to\n                    msg.sender = delivered_envelope.sender\n                    assert envelope.message == msg\n                    multiplexer2.disconnect()\n                    del multiplexers[-1]\n            except Exception:\n                raise\n            finally:\n                for mux in multiplexers:\n                    mux.disconnect()\n\n    def teardown(self):\n        \"\"\"Tear down the test\"\"\"\n        os.chdir(self.cwd)\n        try:\n            shutil.rmtree(self.t)\n        except (OSError, IOError):\n            pass\n\n\n@pytest.mark.integration\nclass TestLibp2pConnectionPublicDHTDelegate:\n    \"\"\"Test that public DHT's delegate service is working properly\"\"\"\n\n    def setup(self):\n        \"\"\"Set the test up\"\"\"\n        self.cwd = os.getcwd()\n        self.t = tempfile.mkdtemp()\n        os.chdir(self.t)\n\n    @pytest.mark.parametrize(\n        \"delegate_uris_public_keys\",\n        [\n            (PUBLIC_DHT_DELEGATE_URIS, PUBLIC_DHT_PUBLIC_KEYS),\n            (PUBLIC_STAGING_DHT_DELEGATE_URIS, PUBLIC_STAGING_DHT_PUBLIC_KEYS),\n        ],\n        indirect=True,\n    )\n    def test_connectivity(self, delegate_uris_public_keys):\n        \"\"\"Test connectivity.\"\"\"\n        delegate_uris, public_keys = delegate_uris_public_keys\n        for i in range(len(delegate_uris)):\n            uri = delegate_uris[i]\n            peer_public_key = public_keys[i]\n            temp_dir = os.path.join(self.t, f\"dir_{i}\")\n            os.mkdir(temp_dir)\n            connection = _make_libp2p_client_connection(\n                peer_public_key=peer_public_key, uri=uri, data_dir=temp_dir\n            )\n            multiplexer = Multiplexer([connection])\n\n            try:\n                multiplexer.connect()\n                assert (\n                    connection.is_connected is True\n                ), \"Couldn't connect to public node {}\".format(uri)\n            except Exception:\n                raise\n            finally:\n                multiplexer.disconnect()\n\n    @pytest.mark.parametrize(\n        \"delegate_uris_public_keys\",\n        [\n            (PUBLIC_DHT_DELEGATE_URIS, PUBLIC_DHT_PUBLIC_KEYS),\n            (PUBLIC_STAGING_DHT_DELEGATE_URIS, PUBLIC_STAGING_DHT_PUBLIC_KEYS),\n        ],\n        indirect=True,\n    )\n    def test_communication_direct(self, delegate_uris_public_keys):\n        \"\"\"Test communication direct (i.e. both clients registered to same peer).\"\"\"\n        delegate_uris, public_keys = delegate_uris_public_keys\n        for i in range(len(delegate_uris)):\n            uri = delegate_uris[i]\n            peer_public_key = public_keys[i]\n            multiplexers = []\n            try:\n                temp_dir_1 = os.path.join(self.t, f\"dir_{i}_1\")\n                os.mkdir(temp_dir_1)\n                connection1 = _make_libp2p_client_connection(\n                    peer_public_key=peer_public_key, uri=uri, data_dir=temp_dir_1\n                )\n                multiplexer1 = Multiplexer([connection1])\n                multiplexer1.connect()\n                multiplexers.append(multiplexer1)\n\n                temp_dir_2 = os.path.join(self.t, f\"dir_{i}_2\")\n                os.mkdir(temp_dir_2)\n                connection2 = _make_libp2p_client_connection(\n                    peer_public_key=peer_public_key, uri=uri, data_dir=temp_dir_2\n                )\n                multiplexer2 = Multiplexer([connection2])\n                multiplexer2.connect()\n                multiplexers.append(multiplexer2)\n\n                addr_1 = connection1.address\n                addr_2 = connection2.address\n\n                msg = DefaultMessage(\n                    dialogue_reference=(\"\", \"\"),\n                    message_id=1,\n                    target=0,\n                    performative=DefaultMessage.Performative.BYTES,\n                    content=b\"hello\",\n                )\n                envelope = Envelope(\n                    to=addr_2,\n                    sender=addr_1,\n                    message=msg,\n                )\n\n                multiplexer1.put(envelope)\n                delivered_envelope = multiplexer2.get(block=True, timeout=20)\n\n                assert delivered_envelope is not None\n                assert delivered_envelope.to == envelope.to\n                assert delivered_envelope.sender == envelope.sender\n                assert (\n                    delivered_envelope.protocol_specification_id\n                    == envelope.protocol_specification_id\n                )\n                assert delivered_envelope.message != envelope.message\n                msg = DefaultMessage.serializer.decode(delivered_envelope.message)\n                msg.to = delivered_envelope.to\n                msg.sender = delivered_envelope.sender\n                assert envelope.message == msg\n            except Exception:\n                raise\n            finally:\n                for mux in multiplexers:\n                    mux.disconnect()\n\n    @pytest.mark.parametrize(\n        \"delegate_uris_public_keys\",\n        [\n            (PUBLIC_DHT_DELEGATE_URIS, PUBLIC_DHT_PUBLIC_KEYS),\n            (PUBLIC_STAGING_DHT_DELEGATE_URIS, PUBLIC_STAGING_DHT_PUBLIC_KEYS),\n        ],\n        indirect=True,\n    )\n    def test_communication_indirect(self, delegate_uris_public_keys):\n        \"\"\"Test communication indirect (i.e. clients registered to different peers).\"\"\"\n        delegate_uris, public_keys = delegate_uris_public_keys\n        assert len(delegate_uris) > 1, \"Test requires at least 2 public dht node\"\n\n        for i in range(len(delegate_uris)):\n            multiplexers = []\n            try:\n                temp_dir_1 = os.path.join(self.t, f\"dir_{i}__\")\n                os.mkdir(temp_dir_1)\n                connection1 = _make_libp2p_client_connection(\n                    peer_public_key=public_keys[i],\n                    uri=delegate_uris[i],\n                    data_dir=temp_dir_1,\n                )\n                multiplexer1 = Multiplexer([connection1])\n                multiplexer1.connect()\n                multiplexers.append(multiplexer1)\n\n                addr_1 = connection1.address\n\n                for j in range(len(delegate_uris)):\n                    if j == i:\n                        continue\n\n                    temp_dir_2 = os.path.join(self.t, f\"dir_{i}_{j}\")\n                    os.mkdir(temp_dir_2)\n                    connection2 = _make_libp2p_client_connection(\n                        peer_public_key=public_keys[j],\n                        uri=delegate_uris[j],\n                        data_dir=temp_dir_2,\n                    )\n                    multiplexer2 = Multiplexer([connection2])\n                    multiplexer2.connect()\n                    multiplexers.append(multiplexer2)\n\n                    addr_2 = connection2.address\n                    msg = DefaultMessage(\n                        dialogue_reference=(\"\", \"\"),\n                        message_id=1,\n                        target=0,\n                        performative=DefaultMessage.Performative.BYTES,\n                        content=b\"hello\",\n                    )\n                    envelope = Envelope(\n                        to=addr_2,\n                        sender=addr_1,\n                        message=msg,\n                    )\n\n                    multiplexer1.put(envelope)\n                    delivered_envelope = multiplexer2.get(block=True, timeout=20)\n\n                    assert delivered_envelope is not None\n                    assert delivered_envelope.to == envelope.to\n                    assert delivered_envelope.sender == envelope.sender\n                    assert (\n                        delivered_envelope.protocol_specification_id\n                        == envelope.protocol_specification_id\n                    )\n                    assert delivered_envelope.message != envelope.message\n                    msg = DefaultMessage.serializer.decode(delivered_envelope.message)\n                    msg.to = delivered_envelope.to\n                    msg.sender = delivered_envelope.sender\n                    assert envelope.message == msg\n                    multiplexer2.disconnect()\n                    del multiplexers[-1]\n            except Exception:\n                raise\n            finally:\n                for mux in multiplexers:\n                    mux.disconnect()\n\n    def teardown(self):\n        \"\"\"Tear down the test\"\"\"\n        os.chdir(self.cwd)\n        try:\n            shutil.rmtree(self.t)\n        except (OSError, IOError):\n            pass\n\n\n@pytest.mark.integration\nclass TestLibp2pConnectionPublicDHTRelayAEACli(AEATestCaseMany):\n    \"\"\"Test that public DHT's relay service is working properly, using aea cli\"\"\"\n\n    @libp2p_log_on_failure\n    @pytest.mark.parametrize(\n        \"maddrs\", [PUBLIC_DHT_MADDRS, PUBLIC_STAGING_DHT_MADDRS], indirect=True\n    )\n    def test_connectivity(self, maddrs):\n        \"\"\"Test connectivity.\"\"\"\n        self.log_files = []\n        self.agent_name = \"some\"\n        self.create_agents(self.agent_name)\n        self.set_agent_context(self.agent_name)\n        self.conn_key_file = os.path.join(\n            os.path.abspath(os.getcwd()), \"./conn_key.txt\"\n        )\n        self.generate_private_key()\n        self.add_private_key()\n        self.generate_private_key(private_key_file=self.conn_key_file)\n        self.add_private_key(private_key_filepath=self.conn_key_file, connection=True)\n        self.add_item(\"connection\", str(P2P_CONNECTION_PUBLIC_ID))\n        self.run_cli_command(\"build\", cwd=self._get_cwd())\n\n        self.set_config(\"agent.default_connection\", str(P2P_CONNECTION_PUBLIC_ID))\n\n        # for logging\n        log_file = \"libp2p_node_{}.log\".format(self.agent_name)\n        log_file = os.path.join(os.path.abspath(os.getcwd()), log_file)\n\n        config_path = \"vendor.fetchai.connections.p2p_libp2p.config\"\n        self.nested_set_config(\n            config_path,\n            {\n                \"local_uri\": \"127.0.0.1:{}\".format(DEFAULT_PORT),\n                \"entry_peers\": maddrs,\n                \"log_file\": log_file,\n            },\n        )\n\n        self.run_cli_command(\"issue-certificates\", cwd=self._get_cwd())\n\n        self.log_files = [log_file]\n        process = self.run_agent()\n\n        is_running = self.is_running(process, timeout=AEA_LIBP2P_LAUNCH_TIMEOUT)\n        assert is_running, \"AEA not running within timeout!\"\n\n        check_strings = \"Peer running in \"\n        missing_strings = self.missing_from_output(process, check_strings)\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in agent output.\".format(missing_strings)\n\n        self.terminate_agents(process)\n        assert self.is_successfully_terminated(\n            process\n        ), \"AEA wasn't successfully terminated.\"\n\n    def teardown(self):\n        \"\"\"Clean up after test case run.\"\"\"\n        self.unset_agent_context()\n        self.run_cli_command(\"delete\", self.agent_name)\n\n\n@pytest.mark.integration\nclass TestLibp2pConnectionPublicDHTDelegateAEACli(AEATestCaseMany):\n    \"\"\"Test that public DHT's delegate service is working properly, using aea cli\"\"\"\n\n    @pytest.mark.parametrize(\n        \"delegate_uris_public_keys\",\n        [\n            (PUBLIC_DHT_DELEGATE_URIS, PUBLIC_DHT_PUBLIC_KEYS),\n            (PUBLIC_STAGING_DHT_DELEGATE_URIS, PUBLIC_STAGING_DHT_PUBLIC_KEYS),\n        ],\n        indirect=True,\n    )\n    def test_connectivity(self, delegate_uris_public_keys):\n        \"\"\"Test connectivity.\"\"\"\n        delegate_uris, public_keys = delegate_uris_public_keys\n        self.agent_name = \"some\"\n        self.create_agents(self.agent_name)\n        self.set_agent_context(self.agent_name)\n        self.generate_private_key()\n        self.add_private_key()\n        self.add_item(\"connection\", str(P2P_CLIENT_CONNECTION_PUBLIC_ID))\n        config_path = \"vendor.fetchai.connections.p2p_libp2p_client.config\"\n        self.nested_set_config(\n            config_path,\n            {\"nodes\": [{\"uri\": \"{}\".format(uri)} for uri in delegate_uris]},\n        )\n        conn_path = \"vendor.fetchai.connections.p2p_libp2p_client\"\n        self.nested_set_config(\n            conn_path + \".config\",\n            {\n                \"nodes\": [\n                    {\"uri\": uri, \"public_key\": public_keys[i]}\n                    for i, uri in enumerate(delegate_uris)\n                ]\n            },\n        )\n\n        # generate certificates for connection\n        self.nested_set_config(\n            conn_path + \".cert_requests\",\n            [\n                CertRequest(\n                    identifier=\"acn\",\n                    ledger_id=\"fetchai\",\n                    not_after=\"2022-01-01\",\n                    not_before=\"2021-01-01\",\n                    public_key=public_key,\n                    message_format=\"{public_key}\",\n                    save_path=f\"./cli_test_cert_{public_key}.txt\",\n                )\n                for public_key in public_keys\n            ],\n        )\n        self.run_cli_command(\"issue-certificates\", cwd=self._get_cwd())\n\n        process = self.run_agent()\n        is_running = self.is_running(process, timeout=AEA_DEFAULT_LAUNCH_TIMEOUT)\n        assert is_running, \"AEA not running within timeout!\"\n        self.terminate_agents(process)\n        assert self.is_successfully_terminated(\n            process\n        ), \"AEA wasn't successfully terminated.\"\n\n    def teardown(self):\n        \"\"\"Clean up after test case run.\"\"\"\n        self.unset_agent_context()\n        self.run_cli_command(\"delete\", self.agent_name)\n"
  },
  {
    "path": "tests/test_packages/test_connections/test_p2p_libp2p/test_slow_queue.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This test module contains tests for P2PLibp2p connection.\"\"\"\nimport os\nimport shutil\nimport tempfile\nfrom unittest.mock import Mock\n\nimport pytest\n\nfrom aea.mail.base import Envelope\nfrom aea.multiplexer import Multiplexer\n\nfrom packages.fetchai.protocols.default.message import DefaultMessage\n\nfrom tests.common.utils import wait_for_condition\nfrom tests.conftest import (\n    _make_libp2p_connection,\n    libp2p_log_on_failure,\n    libp2p_log_on_failure_all,\n)\n\n\nDEFAULT_PORT = 10234\n\nMockDefaultMessageProtocol = Mock()\nMockDefaultMessageProtocol.protocol_id = DefaultMessage.protocol_id\nMockDefaultMessageProtocol.protocol_specification_id = (\n    DefaultMessage.protocol_specification_id\n)\n\n\n@libp2p_log_on_failure_all\nclass TestSlowQueue:\n    \"\"\"Test that libp2p node uses slow queue in case of long DHT lookups.\"\"\"\n\n    @classmethod\n    @libp2p_log_on_failure\n    def setup_class(cls):\n        \"\"\"Set the test up\"\"\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        os.chdir(cls.t)\n\n        cls.log_files = []\n        cls.multiplexers = []\n\n        try:\n            port_genesis = DEFAULT_PORT + 10\n            temp_dir_gen = os.path.join(cls.t, \"temp_dir_gen\")\n            os.mkdir(temp_dir_gen)\n            cls.bad_address = _make_libp2p_connection(\n                data_dir=temp_dir_gen, port=port_genesis\n            ).node.address\n            cls.connection_genesis = _make_libp2p_connection(\n                data_dir=temp_dir_gen, port=port_genesis\n            )\n            cls.multiplexer_genesis = Multiplexer(\n                [cls.connection_genesis], protocols=[MockDefaultMessageProtocol]\n            )\n            cls.log_files.append(cls.connection_genesis.node.log_file)\n            cls.multiplexer_genesis.connect()\n            cls.multiplexers.append(cls.multiplexer_genesis)\n\n            genesis_peer = cls.connection_genesis.node.multiaddrs[0]\n\n            cls.connections = [cls.connection_genesis]\n\n            temp_dir = os.path.join(cls.t, \"temp_dir_100\")\n            os.mkdir(temp_dir)\n\n            cls.conn = _make_libp2p_connection(\n                data_dir=temp_dir, port=port_genesis + 100, entry_peers=[genesis_peer]\n            )\n\n            port = port_genesis\n            for i in range(2):\n                port += 1\n                temp_dir = os.path.join(cls.t, f\"temp_dir_{i}\")\n                os.mkdir(temp_dir)\n                conn = _make_libp2p_connection(\n                    data_dir=temp_dir, port=port, entry_peers=[genesis_peer]\n                )\n                mux = Multiplexer([conn], protocols=[MockDefaultMessageProtocol])\n\n                cls.connections.append(conn)\n\n                cls.log_files.append(conn.node.log_file)\n                mux.connect()\n                cls.multiplexers.append(mux)\n\n            for conn in cls.connections:\n                assert conn.is_connected is True\n        except Exception as e:\n            cls.teardown_class()\n            raise e\n\n    @pytest.mark.asyncio\n    async def test_slow_queue(self):\n        \"\"\"Test slow queue.\"\"\"\n        con2 = self.connections[-1]\n        await self.conn.connect()\n\n        def _make_envelope(addr):\n            msg = DefaultMessage(\n                dialogue_reference=(\"\", \"\"),\n                message_id=1,\n                target=0,\n                performative=DefaultMessage.Performative.BYTES,\n                content=b\"hello\",\n            )\n\n            envelope = Envelope(\n                to=addr,\n                sender=self.conn.node.address,\n                message=msg,\n            )\n            return envelope\n\n        try:\n            for _ in range(50):\n                for addr in [con2.node.address, self.bad_address]:\n                    await self.conn._node_client.send_envelope(_make_envelope(addr))\n\n            for _ in range(2):\n                for addr in [self.bad_address, con2.node.address]:\n                    await self.conn._node_client.send_envelope(_make_envelope(addr))\n\n            def _check():\n                with open(self.conn.node.log_file) as f:\n                    return \"while sending slow envelope:\" in f.read()\n\n            wait_for_condition(_check, timeout=30, period=0.1)\n        finally:\n            await self.conn.disconnect()\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear down the test\"\"\"\n        for mux in cls.multiplexers:\n            mux.disconnect()\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n"
  },
  {
    "path": "tests/test_packages/test_connections/test_prometheus/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests of the prometheus connection implementation.\"\"\"\n"
  },
  {
    "path": "tests/test_packages/test_connections/test_prometheus/test_prometheus.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the prometheus connection module.\"\"\"\nimport asyncio\nfrom typing import cast\nfrom unittest.mock import MagicMock, Mock\n\nimport pytest\n\nfrom aea.common import Address\nfrom aea.configurations.base import ConnectionConfig, PublicId\nfrom aea.exceptions import AEAEnforceError\nfrom aea.identity.base import Identity\nfrom aea.mail.base import Envelope, Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\n\nfrom packages.fetchai.connections.prometheus.connection import (\n    ConnectionStates,\n    PrometheusConnection,\n)\nfrom packages.fetchai.protocols.prometheus.dialogues import PrometheusDialogue\nfrom packages.fetchai.protocols.prometheus.dialogues import (\n    PrometheusDialogues as BasePrometheusDialogues,\n)\nfrom packages.fetchai.protocols.prometheus.message import PrometheusMessage\n\n\nclass PrometheusDialogues(BasePrometheusDialogues):\n    \"\"\"The dialogues class keeps track of all prometheus dialogues.\"\"\"\n\n    def __init__(self, self_address: Address, **kwargs) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :return: None\n        \"\"\"\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return PrometheusDialogue.Role.AGENT\n\n        BasePrometheusDialogues.__init__(\n            self,\n            self_address=self_address,\n            role_from_first_message=role_from_first_message,\n        )\n\n\nclass TestPrometheusConnection:\n    \"\"\"Test the packages/connection/prometheus/connection.py.\"\"\"\n\n    def setup(self):\n        \"\"\"Initialise the class.\"\"\"\n        self.metrics = {}\n        configuration = ConnectionConfig(\n            connection_id=PrometheusConnection.connection_id,\n            port=9090,\n        )\n        self.some_skill = \"some/skill:0.1.0\"\n        self.agent_address = \"my_address\"\n        self.agent_public_key = \"my_public_key\"\n        self.protocol_specification_id = PublicId.from_str(\"fetchai/prometheus:1.1.7\")\n        identity = Identity(\n            \"name\", address=self.agent_address, public_key=self.agent_public_key\n        )\n        self.prometheus_con = PrometheusConnection(\n            identity=identity, configuration=configuration, data_dir=MagicMock()\n        )\n        self.loop = asyncio.get_event_loop()\n        self.prometheus_address = str(PrometheusConnection.connection_id)\n        self.dialogues = PrometheusDialogues(self.some_skill)\n\n    async def send_add_metric(self, title: str, metric_type: str) -> None:\n        \"\"\"Send an add_metric message.\"\"\"\n        msg, sending_dialogue = self.dialogues.create(\n            counterparty=self.prometheus_address,\n            performative=PrometheusMessage.Performative.ADD_METRIC,\n            title=title,\n            type=metric_type,\n            description=\"a gauge\",\n            labels={},\n        )\n        assert sending_dialogue is not None\n\n        envelope = Envelope(\n            to=msg.to,\n            sender=msg.sender,\n            message=msg,\n        )\n        await self.prometheus_con.send(envelope)\n\n    async def send_update_metric(self, title: str, update_func: str) -> None:\n        \"\"\"Send an update_metric message.\"\"\"\n        msg, sending_dialogue = self.dialogues.create(\n            counterparty=self.prometheus_address,\n            performative=PrometheusMessage.Performative.UPDATE_METRIC,\n            title=title,\n            callable=update_func,\n            value=1.0,\n            labels={},\n        )\n        assert sending_dialogue is not None\n        assert sending_dialogue.last_message is not None\n\n        envelope = Envelope(\n            to=msg.to,\n            sender=msg.sender,\n            message=msg,\n        )\n        await self.prometheus_con.send(envelope)\n\n    def teardown(self):\n        \"\"\"Clean up after tests.\"\"\"\n        self.loop.run_until_complete(self.prometheus_con.disconnect())\n\n    @pytest.mark.asyncio\n    async def test_connection(self):\n        \"\"\"Test connect.\"\"\"\n        assert (\n            self.prometheus_con.state == ConnectionStates.disconnected\n        ), \"should not be connected yet\"\n        await self.prometheus_con.connect()\n        assert (\n            self.prometheus_con.state == ConnectionStates.connected\n        ), \"should be connected\"\n\n        # test add metric (correct)\n        await self.send_add_metric(\"some_metric\", \"Gauge\")\n        envelope = await self.prometheus_con.receive()\n        msg = cast(PrometheusMessage, envelope.message)\n        assert msg.performative == PrometheusMessage.Performative.RESPONSE\n        assert msg.code == 200\n        assert msg.message == \"New Gauge successfully added: some_metric.\"\n\n        # test add metric (already exists)\n        await self.send_add_metric(\"some_metric\", \"Gauge\")\n        envelope = await self.prometheus_con.receive()\n        msg = cast(PrometheusMessage, envelope.message)\n        assert msg.performative == PrometheusMessage.Performative.RESPONSE\n        assert msg.code == 409\n        assert msg.message == \"Metric already exists.\"\n\n        # test add metric (wrong type)\n        await self.send_add_metric(\"cool_metric\", \"CoolBar\")\n        envelope = await self.prometheus_con.receive()\n        msg = cast(PrometheusMessage, envelope.message)\n        assert msg.performative == PrometheusMessage.Performative.RESPONSE\n        assert msg.code == 404\n        assert msg.message == \"CoolBar is not a recognized prometheus metric.\"\n\n        # test update metric (inc: correct)\n        await self.send_update_metric(\"some_metric\", \"inc\")\n        envelope = await self.prometheus_con.receive()\n        msg = cast(PrometheusMessage, envelope.message)\n        assert msg.performative == PrometheusMessage.Performative.RESPONSE\n        assert msg.code == 200\n        assert msg.message == \"Metric some_metric successfully updated.\"\n\n        # test update metric (set: correct)\n        await self.send_update_metric(\"some_metric\", \"set\")\n        envelope = await self.prometheus_con.receive()\n        msg = cast(PrometheusMessage, envelope.message)\n        assert msg.performative == PrometheusMessage.Performative.RESPONSE\n        assert msg.code == 200\n        assert msg.message == \"Metric some_metric successfully updated.\"\n\n        # test update metric (doesn't exist)\n        await self.send_update_metric(\"cool_metric\", \"inc\")\n        envelope = await self.prometheus_con.receive()\n        msg = cast(PrometheusMessage, envelope.message)\n        assert msg.performative == PrometheusMessage.Performative.RESPONSE\n        assert msg.code == 404\n        assert msg.message == \"Metric cool_metric not found.\"\n\n        # test update metric (bad update function: not found in attr)\n        await self.send_update_metric(\"some_metric\", \"go\")\n        envelope = await self.prometheus_con.receive()\n        msg = cast(PrometheusMessage, envelope.message)\n        assert msg.performative == PrometheusMessage.Performative.RESPONSE\n        assert msg.code == 400\n        assert msg.message == \"Update function go not found for metric some_metric.\"\n\n        # test update metric (bad update function: found in getattr, not a method)\n        await self.send_update_metric(\"some_metric\", \"name\")\n        envelope = await self.prometheus_con.receive()\n        msg = cast(PrometheusMessage, envelope.message)\n        assert msg.performative == PrometheusMessage.Performative.RESPONSE\n        assert msg.code == 400\n        assert (\n            msg.message\n            == \"Failed to update metric some_metric: name is not a valid update function.\"\n        )\n\n        # Test that invalid message is rejected.\n        with pytest.raises(AEAEnforceError):\n            envelope = Envelope(\n                to=\"some_address\",\n                sender=\"me\",\n                message=Mock(spec=Message),\n            )\n            await self.prometheus_con.channel.send(envelope)\n\n        # Test that envelope without dialogue produces warning.\n        msg = PrometheusMessage(\n            PrometheusMessage.Performative.RESPONSE, code=0, message=\"\"\n        )\n        envelope = Envelope(\n            to=self.prometheus_address,\n            sender=self.some_skill,\n            message=msg,\n        )\n        await self.prometheus_con.channel.send(envelope)\n\n        # Test that envelope with invalid protocol_specification_id raises error.\n        with pytest.raises(ValueError):\n            msg, _ = self.dialogues.create(\n                counterparty=self.prometheus_address,\n                performative=PrometheusMessage.Performative.UPDATE_METRIC,\n                title=\"\",\n                callable=\"\",\n                value=1.0,\n                labels={},\n            )\n            envelope = Envelope(\n                to=self.prometheus_address,\n                sender=self.some_skill,\n                message=msg,\n            )\n            envelope._protocol_specification_id = \"bad_id\"\n            await self.prometheus_con.channel.send(envelope)\n\n    @pytest.mark.asyncio\n    async def test_disconnect(self):\n        \"\"\"Test disconnect.\"\"\"\n        await self.prometheus_con.disconnect()\n        assert (\n            self.prometheus_con.state == ConnectionStates.disconnected\n        ), \"should be disconnected\"\n"
  },
  {
    "path": "tests/test_packages/test_connections/test_webhook/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests of the webhook connection implementation.\"\"\"\n"
  },
  {
    "path": "tests/test_packages/test_connections/test_webhook/test_webhook.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Tests for the webhook connection and channel.\"\"\"\n\nimport asyncio\nimport json\nimport logging\nfrom traceback import print_exc\nfrom typing import cast\nfrom unittest.mock import MagicMock, patch\n\nimport aiohttp\nimport pytest\nfrom aiohttp.client_reqrep import ClientResponse\n\nfrom aea.common import Address\nfrom aea.configurations.base import ConnectionConfig\nfrom aea.identity.base import Identity\nfrom aea.mail.base import Envelope\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue\n\nfrom packages.fetchai.connections.webhook.connection import WebhookConnection\nfrom packages.fetchai.protocols.http.dialogues import HttpDialogue\nfrom packages.fetchai.protocols.http.dialogues import HttpDialogues as BaseHttpDialogues\nfrom packages.fetchai.protocols.http.message import HttpMessage\n\nfrom tests.common.mocks import RegexComparator\nfrom tests.conftest import get_host, get_unused_tcp_port\n\n\nlogger = logging.getLogger(__name__)\n\n\nclass HttpDialogues(BaseHttpDialogues):\n    \"\"\"The dialogues class keeps track of all http dialogues.\"\"\"\n\n    def __init__(self, self_address: Address, **kwargs) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :return: None\n        \"\"\"\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> Dialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return HttpDialogue.Role.CLIENT\n\n        BaseHttpDialogues.__init__(\n            self,\n            self_address=self_address,\n            role_from_first_message=role_from_first_message,\n        )\n\n\n@pytest.mark.asyncio\nclass TestWebhookConnection:\n    \"\"\"Tests the webhook connection's 'connect' functionality.\"\"\"\n\n    def setup(self):\n        \"\"\"Initialise the class.\"\"\"\n        self.host = get_host()\n        self.port = get_unused_tcp_port()\n        self.target_skill_id = \"some_author/some_skill:0.1.0\"\n        self.identity = Identity(\n            \"identity\", address=\"some string\", public_key=\"some public_key\"\n        )\n        self.path = \"/webhooks/topic/{topic}/\"\n        self.loop = asyncio.get_event_loop()\n\n        configuration = ConnectionConfig(\n            webhook_address=self.host,\n            webhook_port=self.port,\n            webhook_url_path=self.path,\n            target_skill_id=self.target_skill_id,\n            connection_id=WebhookConnection.connection_id,\n        )\n        self.webhook_connection = WebhookConnection(\n            configuration=configuration,\n            data_dir=MagicMock(),\n            identity=self.identity,\n        )\n        self.skill_dialogues = HttpDialogues(self.target_skill_id)\n\n    async def test_initialization(self):\n        \"\"\"Test the initialisation of the class.\"\"\"\n        assert self.webhook_connection.address == self.identity.address\n\n    @pytest.mark.asyncio\n    async def test_connection(self):\n        \"\"\"Test the connect functionality of the webhook connection.\"\"\"\n        await self.webhook_connection.connect()\n        assert self.webhook_connection.is_connected is True\n\n    @pytest.mark.asyncio\n    async def test_disconnect(self):\n        \"\"\"Test the disconnect functionality of the webhook connection.\"\"\"\n        await self.webhook_connection.connect()\n        assert self.webhook_connection.is_connected is True\n\n        await self.webhook_connection.disconnect()\n        assert self.webhook_connection.is_connected is False\n\n    def teardown(self):\n        \"\"\"Close connection after testing.\"\"\"\n        try:\n            self.loop.run_until_complete(self.webhook_connection.disconnect())\n        except Exception:\n            print_exc()\n            raise\n\n    @pytest.mark.asyncio\n    async def test_receive_post_ok(self):\n        \"\"\"Test the connect functionality of the webhook connection.\"\"\"\n        await self.webhook_connection.connect()\n        assert self.webhook_connection.is_connected is True\n        payload = {\"hello\": \"world\"}\n        call_task = self.loop.create_task(self.call_webhook(\"test_topic\", json=payload))\n        envelope = await asyncio.wait_for(self.webhook_connection.receive(), timeout=10)\n\n        assert envelope\n\n        message = cast(HttpMessage, envelope.message)\n        dialogue = self.skill_dialogues.update(message)\n        assert dialogue is not None\n        assert message.method.upper() == \"POST\"\n        assert message.body.decode(\"utf-8\") == json.dumps(payload)\n        await call_task\n\n    @pytest.mark.asyncio\n    async def test_send(self):\n        \"\"\"Test the connect functionality of the webhook connection.\"\"\"\n        await self.webhook_connection.connect()\n        assert self.webhook_connection.is_connected is True\n\n        http_message = HttpMessage(\n            dialogue_reference=(\"\", \"\"),\n            target=0,\n            message_id=1,\n            performative=HttpMessage.Performative.REQUEST,\n            method=\"get\",\n            url=\"/\",\n            headers=\"\",\n            body=\"\",\n            version=\"\",\n        )\n        envelope = Envelope(\n            to=\"addr\",\n            sender=\"my_id\",\n            message=http_message,\n        )\n        with patch.object(self.webhook_connection.logger, \"warning\") as mock_logger:\n            await self.webhook_connection.send(envelope)\n            await asyncio.sleep(0.01)\n            mock_logger.assert_any_call(\n                RegexComparator(\n                    \"Dropping envelope=.* as sending via the webhook is not possible!\"\n                )\n            )\n\n    async def call_webhook(self, topic: str, **kwargs) -> ClientResponse:\n        \"\"\"\n        Make a http request to a webhook.\n\n        :param topic: topic to use\n        :params **kwargs: data or json for payload\n\n        :return: http response\n        \"\"\"\n        path = self.path.format(topic=topic)\n        method = kwargs.get(\"method\", \"post\")\n        url = f\"http://{self.host}:{self.port}{path}\"\n\n        try:\n            async with aiohttp.ClientSession() as session:\n                async with session.request(method, url, **kwargs) as resp:\n                    await resp.read()\n                    return resp\n        except Exception:\n            print_exc()\n            raise\n"
  },
  {
    "path": "tests/test_packages/test_contracts/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"The tests module contains the tests of the packages/contracts dir.\"\"\"\n"
  },
  {
    "path": "tests/test_packages/test_protocols/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"The tests module contains the tests of the packages/protocols dir.\"\"\"\n"
  },
  {
    "path": "tests/test_packages/test_protocols/test_aggregation.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests of the aggregation protocol package.\"\"\"\n\nimport sys\nfrom typing import Type\nfrom unittest import mock\n\nimport pytest\n\nfrom aea.common import Address\nfrom aea.exceptions import AEAEnforceError\nfrom aea.mail.base import Envelope\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\nfrom aea.protocols.dialogue.base import DialogueLabel\n\nimport packages\nfrom packages.fetchai.protocols.aggregation.dialogues import (\n    AggregationDialogue,\n    AggregationDialogues,\n)\nfrom packages.fetchai.protocols.aggregation.message import AggregationMessage\nfrom packages.fetchai.protocols.aggregation.message import (\n    _default_logger as aggregation_message_logger,\n)\n\nfrom tests.conftest import ROOT_DIR\n\n\nsys.path.append(ROOT_DIR)\n\n\ndef test_observation_serialization():\n    \"\"\"Test the serialization for 'observation' speech-act works.\"\"\"\n    msg = AggregationMessage(\n        message_id=1,\n        dialogue_reference=(str(0), \"\"),\n        target=0,\n        performative=AggregationMessage.Performative.OBSERVATION,\n        value=0,\n        time=\"some_time\",\n        source=\"some_source\",\n        signature=\"some_signature\",\n    )\n    msg.to = \"receiver\"\n    envelope = Envelope(\n        to=msg.to,\n        sender=\"sender\",\n        message=msg,\n    )\n    envelope_bytes = envelope.encode()\n\n    actual_envelope = Envelope.decode(envelope_bytes)\n    expected_envelope = envelope\n    assert expected_envelope.to == actual_envelope.to\n    assert expected_envelope.sender == actual_envelope.sender\n    assert (\n        expected_envelope.protocol_specification_id\n        == actual_envelope.protocol_specification_id\n    )\n    assert expected_envelope.message != actual_envelope.message\n\n    actual_msg = AggregationMessage.serializer.decode(actual_envelope.message)\n    actual_msg.to = actual_envelope.to\n    actual_msg.sender = actual_envelope.sender\n    expected_msg = msg\n    assert expected_msg == actual_msg\n\n\ndef test_aggregation_serialization():\n    \"\"\"Test the serialization for 'aggregation' speech-act works.\"\"\"\n    msg = AggregationMessage(\n        message_id=1,\n        dialogue_reference=(str(0), \"\"),\n        target=0,\n        performative=AggregationMessage.Performative.AGGREGATION,\n        value=0,\n        time=\"some_time\",\n        contributors=(\"address1\", \"address2\"),\n        signature=\"some_multisignature\",\n    )\n    msg.to = \"receiver\"\n    envelope = Envelope(\n        to=msg.to,\n        sender=\"sender\",\n        message=msg,\n    )\n    envelope_bytes = envelope.encode()\n\n    actual_envelope = Envelope.decode(envelope_bytes)\n    expected_envelope = envelope\n    assert expected_envelope.to == actual_envelope.to\n    assert expected_envelope.sender == actual_envelope.sender\n    assert (\n        expected_envelope.protocol_specification_id\n        == actual_envelope.protocol_specification_id\n    )\n    assert expected_envelope.message != actual_envelope.message\n\n    actual_msg = AggregationMessage.serializer.decode(actual_envelope.message)\n    actual_msg.to = actual_envelope.to\n    actual_msg.sender = actual_envelope.sender\n    expected_msg = msg\n    assert expected_msg == actual_msg\n\n\ndef test_performative_string_value():\n    \"\"\"Test the string value of the performatives.\"\"\"\n    assert (\n        str(AggregationMessage.Performative.OBSERVATION) == \"observation\"\n    ), \"The str value must be observation\"\n    assert (\n        str(AggregationMessage.Performative.AGGREGATION) == \"aggregation\"\n    ), \"The str value must be aggregation\"\n\n\ndef test_encoding_unknown_performative():\n    \"\"\"Test that we raise an exception when the performative is unknown during encoding.\"\"\"\n    msg = AggregationMessage(\n        message_id=1,\n        dialogue_reference=(str(0), \"\"),\n        target=0,\n        performative=AggregationMessage.Performative.AGGREGATION,\n        value=0,\n        time=\"some_time\",\n        contributors=(\"address1\", \"address2\"),\n        signature=\"some_multisignature\",\n    )\n\n    with pytest.raises(ValueError, match=\"Performative not valid:\"):\n        with mock.patch.object(\n            AggregationMessage.Performative, \"__eq__\", return_value=False\n        ):\n            AggregationMessage.serializer.encode(msg)\n\n\ndef test_decoding_unknown_performative():\n    \"\"\"Test that we raise an exception when the performative is unknown during decoding.\"\"\"\n    msg = AggregationMessage(\n        message_id=1,\n        dialogue_reference=(str(0), \"\"),\n        target=0,\n        performative=AggregationMessage.Performative.AGGREGATION,\n        value=0,\n        time=\"some_time\",\n        contributors=(\"address1\", \"address2\"),\n        signature=\"some_multisignature\",\n    )\n\n    encoded_msg = AggregationMessage.serializer.encode(msg)\n    with pytest.raises(ValueError, match=\"Performative not valid:\"):\n        with mock.patch.object(\n            AggregationMessage.Performative, \"__eq__\", return_value=False\n        ):\n            AggregationMessage.serializer.decode(encoded_msg)\n\n\n@mock.patch.object(\n    packages.fetchai.protocols.aggregation.message,\n    \"enforce\",\n    side_effect=AEAEnforceError(\"some error\"),\n)\ndef test_incorrect_message(mocked_enforce):\n    \"\"\"Test that we raise an exception when the message is incorrect.\"\"\"\n    with mock.patch.object(aggregation_message_logger, \"error\") as mock_logger:\n        AggregationMessage(\n            message_id=1,\n            dialogue_reference=(str(0), \"\"),\n            target=0,\n            performative=AggregationMessage.Performative.AGGREGATION,\n        )\n\n        mock_logger.assert_any_call(\"some error\")\n\n\nclass TestDialogues:\n    \"\"\"Tests aggregation dialogues.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set up the test.\"\"\"\n        cls.agent_addr = \"agent address\"\n        cls.peer_addr = \"peer address\"\n        cls.agent_dialogues = AgentDialogues(cls.agent_addr)\n        cls.server_dialogues = PeerDialogues(cls.peer_addr)\n\n    def test_create_self_initiated(self):\n        \"\"\"Test the self initialisation of a dialogue.\"\"\"\n        result = self.agent_dialogues._create_self_initiated(\n            dialogue_opponent_addr=self.peer_addr,\n            dialogue_reference=(str(0), \"\"),\n            role=AggregationDialogue.Role.AGENT,\n        )\n        assert isinstance(result, AggregationDialogue)\n        assert result.role == AggregationDialogue.Role.AGENT, \"The role must be Agent.\"\n\n    def test_create_opponent_initiated(self):\n        \"\"\"Test the opponent initialisation of a dialogue.\"\"\"\n        result = self.agent_dialogues._create_opponent_initiated(\n            dialogue_opponent_addr=self.peer_addr,\n            dialogue_reference=(str(0), \"\"),\n            role=AggregationDialogue.Role.AGENT,\n        )\n        assert isinstance(result, AggregationDialogue)\n        assert result.role == AggregationDialogue.Role.AGENT, \"The role must be Agent.\"\n\n\nclass AgentDialogue(AggregationDialogue):\n    \"\"\"The dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    def __init__(\n        self,\n        dialogue_label: DialogueLabel,\n        self_address: Address,\n        role: BaseDialogue.Role,\n        message_class: Type[AggregationMessage],\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n\n        :return: None\n        \"\"\"\n        AggregationDialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            self_address=self_address,\n            role=role,\n            message_class=message_class,\n        )\n\n\nclass AgentDialogues(AggregationDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, self_address: Address) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :return: None\n        \"\"\"\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return AggregationDialogue.Role.AGENT\n\n        AggregationDialogues.__init__(\n            self,\n            self_address=self_address,\n            role_from_first_message=role_from_first_message,\n            dialogue_class=AgentDialogue,\n        )\n\n\nclass PeerDialogue(AggregationDialogue):\n    \"\"\"The dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    def __init__(\n        self,\n        dialogue_label: DialogueLabel,\n        self_address: Address,\n        role: BaseDialogue.Role,\n        message_class: Type[AggregationMessage],\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n\n        :return: None\n        \"\"\"\n        AggregationDialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            self_address=self_address,\n            role=role,\n            message_class=message_class,\n        )\n\n\nclass PeerDialogues(AggregationDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, self_address: Address) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :return: None\n        \"\"\"\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return AggregationDialogue.Role.AGENT\n\n        AggregationDialogues.__init__(\n            self,\n            self_address=self_address,\n            role_from_first_message=role_from_first_message,\n            dialogue_class=PeerDialogue,\n        )\n"
  },
  {
    "path": "tests/test_packages/test_protocols/test_ml_trade.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests of the ml_trade protocol package.\"\"\"\n\nimport logging\nimport sys\nfrom typing import Type\nfrom unittest import mock\n\nimport pytest\n\nfrom aea.common import Address\nfrom aea.exceptions import AEAEnforceError\nfrom aea.helpers.search.models import Constraint, ConstraintType, Description, Query\nfrom aea.mail.base import Envelope\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\nfrom aea.protocols.dialogue.base import DialogueLabel\n\nimport packages\nfrom packages.fetchai.protocols.ml_trade.dialogues import (\n    MlTradeDialogue,\n    MlTradeDialogues,\n)\nfrom packages.fetchai.protocols.ml_trade.message import MlTradeMessage\nfrom packages.fetchai.protocols.ml_trade.message import (\n    _default_logger as ml_trade_message_logger,\n)\n\nfrom tests.conftest import ROOT_DIR\n\n\nlogger = logging.getLogger(__name__)\nsys.path.append(ROOT_DIR)\n\n\ndef test_cfp_serialization():\n    \"\"\"Test the serialization for 'cfp' speech-act works.\"\"\"\n    msg = MlTradeMessage(\n        performative=MlTradeMessage.Performative.CFP,\n        query=Query([Constraint(\"something\", ConstraintType(\">\", 1))]),\n    )\n    msg.to = \"receiver\"\n    envelope = Envelope(\n        to=msg.to,\n        sender=\"sender\",\n        message=msg,\n    )\n    envelope_bytes = envelope.encode()\n\n    actual_envelope = Envelope.decode(envelope_bytes)\n    expected_envelope = envelope\n    assert expected_envelope.to == actual_envelope.to\n    assert expected_envelope.sender == actual_envelope.sender\n    assert (\n        expected_envelope.protocol_specification_id\n        == actual_envelope.protocol_specification_id\n    )\n    assert expected_envelope.message != actual_envelope.message\n\n    actual_msg = MlTradeMessage.serializer.decode(actual_envelope.message)\n    actual_msg.to = actual_envelope.to\n    actual_msg.sender = actual_envelope.sender\n    expected_msg = msg\n    assert expected_msg == actual_msg\n\n\ndef test_terms_serialization():\n    \"\"\"Test the serialization for 'terms' speech-act works.\"\"\"\n    msg = MlTradeMessage(\n        message_id=2,\n        target=1,\n        performative=MlTradeMessage.Performative.TERMS,\n        terms=Description({\"foo1\": 1, \"bar1\": 2}),\n    )\n    msg.to = \"receiver\"\n    envelope = Envelope(\n        to=msg.to,\n        sender=\"sender\",\n        message=msg,\n    )\n    envelope_bytes = envelope.encode()\n\n    actual_envelope = Envelope.decode(envelope_bytes)\n    expected_envelope = envelope\n    assert expected_envelope.to == actual_envelope.to\n    assert expected_envelope.sender == actual_envelope.sender\n    assert (\n        expected_envelope.protocol_specification_id\n        == actual_envelope.protocol_specification_id\n    )\n    assert expected_envelope.message != actual_envelope.message\n\n    actual_msg = MlTradeMessage.serializer.decode(actual_envelope.message)\n    actual_msg.to = actual_envelope.to\n    actual_msg.sender = actual_envelope.sender\n    expected_msg = msg\n    assert expected_msg == actual_msg\n\n\ndef test_accept_serialization():\n    \"\"\"Test the serialization for 'accept' speech-act works.\"\"\"\n    msg = MlTradeMessage(\n        performative=MlTradeMessage.Performative.ACCEPT,\n        terms=Description({\"foo1\": 1, \"bar1\": 2}),\n        tx_digest=\"some_tx_digest\",\n    )\n    msg.to = \"receiver\"\n    envelope = Envelope(\n        to=msg.to,\n        sender=\"sender\",\n        message=msg,\n    )\n    envelope_bytes = envelope.encode()\n\n    actual_envelope = Envelope.decode(envelope_bytes)\n    expected_envelope = envelope\n    assert expected_envelope.to == actual_envelope.to\n    assert expected_envelope.sender == actual_envelope.sender\n    assert (\n        expected_envelope.protocol_specification_id\n        == actual_envelope.protocol_specification_id\n    )\n    assert expected_envelope.message != actual_envelope.message\n\n    actual_msg = MlTradeMessage.serializer.decode(actual_envelope.message)\n    actual_msg.to = actual_envelope.to\n    actual_msg.sender = actual_envelope.sender\n    expected_msg = msg\n    assert expected_msg == actual_msg\n\n\ndef test_data_serialization():\n    \"\"\"Test the serialization for 'data' speech-act works.\"\"\"\n    msg = MlTradeMessage(\n        performative=MlTradeMessage.Performative.DATA,\n        terms=Description({\"foo1\": 1, \"bar1\": 2}),\n        payload=b\"some_payload\",\n    )\n    msg.to = \"receiver\"\n    envelope = Envelope(\n        to=msg.to,\n        sender=\"sender\",\n        message=msg,\n    )\n    envelope_bytes = envelope.encode()\n\n    actual_envelope = Envelope.decode(envelope_bytes)\n    expected_envelope = envelope\n    assert expected_envelope.to == actual_envelope.to\n    assert expected_envelope.sender == actual_envelope.sender\n    assert (\n        expected_envelope.protocol_specification_id\n        == actual_envelope.protocol_specification_id\n    )\n    assert expected_envelope.message != actual_envelope.message\n\n    actual_msg = MlTradeMessage.serializer.decode(actual_envelope.message)\n    actual_msg.to = actual_envelope.to\n    actual_msg.sender = actual_envelope.sender\n    expected_msg = msg\n    assert expected_msg == actual_msg\n\n\ndef test_performative_string_value():\n    \"\"\"Test the string value of the performatives.\"\"\"\n    assert str(MlTradeMessage.Performative.CFP) == \"cfp\", \"The str value must be cfp\"\n    assert (\n        str(MlTradeMessage.Performative.TERMS) == \"terms\"\n    ), \"The str value must be terms\"\n    assert (\n        str(MlTradeMessage.Performative.ACCEPT) == \"accept\"\n    ), \"The str value must be accept\"\n    assert str(MlTradeMessage.Performative.DATA) == \"data\", \"The str value must be data\"\n\n\ndef test_encoding_unknown_performative():\n    \"\"\"Test that we raise an exception when the performative is unknown during encoding.\"\"\"\n    msg = MlTradeMessage(\n        performative=MlTradeMessage.Performative.CFP,\n        query=Query([Constraint(\"something\", ConstraintType(\">\", 1))]),\n    )\n\n    with pytest.raises(ValueError, match=\"Performative not valid:\"):\n        with mock.patch.object(\n            MlTradeMessage.Performative, \"__eq__\", return_value=False\n        ):\n            MlTradeMessage.serializer.encode(msg)\n\n\ndef test_decoding_unknown_performative():\n    \"\"\"Test that we raise an exception when the performative is unknown during decoding.\"\"\"\n    msg = MlTradeMessage(\n        performative=MlTradeMessage.Performative.CFP,\n        query=Query([Constraint(\"something\", ConstraintType(\">\", 1))]),\n    )\n\n    encoded_msg = MlTradeMessage.serializer.encode(msg)\n    with pytest.raises(ValueError, match=\"Performative not valid:\"):\n        with mock.patch.object(\n            MlTradeMessage.Performative, \"__eq__\", return_value=False\n        ):\n            MlTradeMessage.serializer.decode(encoded_msg)\n\n\n@mock.patch.object(\n    packages.fetchai.protocols.ml_trade.message,\n    \"enforce\",\n    side_effect=AEAEnforceError(\"some error\"),\n)\ndef test_fipa_incorrect_message(mocked_enforce):\n    \"\"\"Test that we raise an exception when the fipa message is incorrect.\"\"\"\n    with mock.patch.object(ml_trade_message_logger, \"error\") as mock_logger:\n        MlTradeMessage(\n            performative=MlTradeMessage.Performative.CFP,\n            query=Query([Constraint(\"something\", ConstraintType(\">\", 1))]),\n        )\n\n        mock_logger.assert_any_call(\"some error\")\n\n\nclass TestDialogues:\n    \"\"\"Tests ml_trade dialogues.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set up the test.\"\"\"\n        cls.buyer_addr = \"buyer address\"\n        cls.seller_addr = \"seller address\"\n        cls.buyer_dialogues = BuyerDialogues(cls.buyer_addr)\n        cls.seller_dialogues = SellerDialogues(cls.seller_addr)\n\n    def test_create_self_initiated(self):\n        \"\"\"Test the self initialisation of a dialogue.\"\"\"\n        result = self.buyer_dialogues._create_self_initiated(\n            dialogue_opponent_addr=self.seller_addr,\n            dialogue_reference=(str(0), \"\"),\n            role=MlTradeDialogue.Role.SELLER,\n        )\n        assert isinstance(result, MlTradeDialogue)\n        assert result.role == MlTradeDialogue.Role.SELLER, \"The role must be seller.\"\n\n    def test_create_opponent_initiated(self):\n        \"\"\"Test the opponent initialisation of a dialogue.\"\"\"\n        result = self.buyer_dialogues._create_opponent_initiated(\n            dialogue_opponent_addr=self.seller_addr,\n            dialogue_reference=(str(0), \"\"),\n            role=MlTradeDialogue.Role.BUYER,\n        )\n        assert isinstance(result, MlTradeDialogue)\n        assert result.role == MlTradeDialogue.Role.BUYER, \"The role must be buyer.\"\n\n\nclass BuyerDialogue(MlTradeDialogue):\n    \"\"\"The dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    def __init__(\n        self,\n        dialogue_label: DialogueLabel,\n        self_address: Address,\n        role: BaseDialogue.Role,\n        message_class: Type[MlTradeMessage],\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n\n        :return: None\n        \"\"\"\n        MlTradeDialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            self_address=self_address,\n            role=role,\n            message_class=message_class,\n        )\n\n\nclass BuyerDialogues(MlTradeDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, self_address: Address) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :return: None\n        \"\"\"\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return MlTradeDialogue.Role.BUYER\n\n        MlTradeDialogues.__init__(\n            self,\n            self_address=self_address,\n            role_from_first_message=role_from_first_message,\n            dialogue_class=BuyerDialogue,\n        )\n\n\nclass SellerDialogue(MlTradeDialogue):\n    \"\"\"The dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    def __init__(\n        self,\n        dialogue_label: DialogueLabel,\n        self_address: Address,\n        role: BaseDialogue.Role,\n        message_class: Type[MlTradeMessage],\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n\n        :return: None\n        \"\"\"\n        MlTradeDialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            self_address=self_address,\n            role=role,\n            message_class=message_class,\n        )\n\n\nclass SellerDialogues(MlTradeDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, self_address: Address) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :return: None\n        \"\"\"\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return MlTradeDialogue.Role.SELLER\n\n        MlTradeDialogues.__init__(\n            self,\n            self_address=self_address,\n            role_from_first_message=role_from_first_message,\n            dialogue_class=SellerDialogue,\n        )\n"
  },
  {
    "path": "tests/test_packages/test_protocols/test_prometheus.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests of the prometheus protocol package.\"\"\"\n\nimport sys\nfrom typing import Type\nfrom unittest import mock\n\nimport pytest\n\nfrom aea.common import Address\nfrom aea.exceptions import AEAEnforceError\nfrom aea.mail.base import Envelope\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\nfrom aea.protocols.dialogue.base import DialogueLabel\n\nimport packages\nfrom packages.fetchai.protocols.prometheus.dialogues import (\n    PrometheusDialogue,\n    PrometheusDialogues,\n)\nfrom packages.fetchai.protocols.prometheus.message import PrometheusMessage\nfrom packages.fetchai.protocols.prometheus.message import (\n    _default_logger as prometheus_message_logger,\n)\n\nfrom tests.conftest import ROOT_DIR\n\n\nsys.path.append(ROOT_DIR)\n\n\ndef test_add_metric_serialization():\n    \"\"\"Test the serialization for 'add_metric' speech-act works.\"\"\"\n    msg = PrometheusMessage(\n        message_id=1,\n        dialogue_reference=(str(0), \"\"),\n        target=0,\n        performative=PrometheusMessage.Performative.ADD_METRIC,\n        type=\"some_type\",\n        title=\"some_title\",\n        description=\"some_description\",\n        labels={\"label_key\": \"label_value\"},\n    )\n    msg.to = \"receiver\"\n    envelope = Envelope(\n        to=msg.to,\n        sender=\"sender\",\n        message=msg,\n    )\n    envelope_bytes = envelope.encode()\n\n    actual_envelope = Envelope.decode(envelope_bytes)\n    expected_envelope = envelope\n    assert expected_envelope.to == actual_envelope.to\n    assert expected_envelope.sender == actual_envelope.sender\n    assert (\n        expected_envelope.protocol_specification_id\n        == actual_envelope.protocol_specification_id\n    )\n    assert expected_envelope.message != actual_envelope.message\n\n    actual_msg = PrometheusMessage.serializer.decode(actual_envelope.message)\n    actual_msg.to = actual_envelope.to\n    actual_msg.sender = actual_envelope.sender\n    expected_msg = msg\n    assert expected_msg == actual_msg\n\n\ndef test_update_metric_serialization():\n    \"\"\"Test the serialization for 'update_metric' speech-act works.\"\"\"\n    msg = PrometheusMessage(\n        message_id=2,\n        dialogue_reference=(str(0), \"\"),\n        target=1,\n        performative=PrometheusMessage.Performative.UPDATE_METRIC,\n        title=\"some_title\",\n        callable=\"some_update_function\",\n        value=1.0,\n        labels={\"label_key\": \"label_value\"},\n    )\n    msg.to = \"receiver\"\n    envelope = Envelope(\n        to=msg.to,\n        sender=\"sender\",\n        message=msg,\n    )\n    envelope_bytes = envelope.encode()\n\n    actual_envelope = Envelope.decode(envelope_bytes)\n    expected_envelope = envelope\n    assert expected_envelope.to == actual_envelope.to\n    assert expected_envelope.sender == actual_envelope.sender\n    assert (\n        expected_envelope.protocol_specification_id\n        == actual_envelope.protocol_specification_id\n    )\n    assert expected_envelope.message != actual_envelope.message\n\n    actual_msg = PrometheusMessage.serializer.decode(actual_envelope.message)\n    actual_msg.to = actual_envelope.to\n    actual_msg.sender = actual_envelope.sender\n    expected_msg = msg\n    assert expected_msg == actual_msg\n\n\ndef test_response_serialization():\n    \"\"\"Test the serialization for 'response' speech-act works.\"\"\"\n    msg = PrometheusMessage(\n        message_id=1,\n        dialogue_reference=(str(0), \"\"),\n        target=0,\n        performative=PrometheusMessage.Performative.RESPONSE,\n        code=0,\n        message=\"some_message\",\n    )\n    msg.to = \"receiver\"\n    envelope = Envelope(\n        to=msg.to,\n        sender=\"sender\",\n        message=msg,\n    )\n    envelope_bytes = envelope.encode()\n\n    actual_envelope = Envelope.decode(envelope_bytes)\n    expected_envelope = envelope\n    assert expected_envelope.to == actual_envelope.to\n    assert expected_envelope.sender == actual_envelope.sender\n    assert (\n        expected_envelope.protocol_specification_id\n        == actual_envelope.protocol_specification_id\n    )\n    assert expected_envelope.message != actual_envelope.message\n\n    actual_msg = PrometheusMessage.serializer.decode(actual_envelope.message)\n    actual_msg.to = actual_envelope.to\n    actual_msg.sender = actual_envelope.sender\n    expected_msg = msg\n    assert expected_msg == actual_msg\n\n\ndef test_performative_string_value():\n    \"\"\"Test the string value of the performatives.\"\"\"\n    assert (\n        str(PrometheusMessage.Performative.ADD_METRIC) == \"add_metric\"\n    ), \"The str value must be add_metric\"\n    assert (\n        str(PrometheusMessage.Performative.UPDATE_METRIC) == \"update_metric\"\n    ), \"The str value must be update_metric\"\n    assert (\n        str(PrometheusMessage.Performative.RESPONSE) == \"response\"\n    ), \"The str value must be response\"\n\n\ndef test_encoding_unknown_performative():\n    \"\"\"Test that we raise an exception when the performative is unknown during encoding.\"\"\"\n    msg = PrometheusMessage(\n        message_id=1,\n        dialogue_reference=(str(0), \"\"),\n        target=0,\n        performative=PrometheusMessage.Performative.RESPONSE,\n        code=0,\n        message=\"some_message\",\n    )\n\n    with pytest.raises(ValueError, match=\"Performative not valid:\"):\n        with mock.patch.object(\n            PrometheusMessage.Performative, \"__eq__\", return_value=False\n        ):\n            PrometheusMessage.serializer.encode(msg)\n\n\ndef test_decoding_unknown_performative():\n    \"\"\"Test that we raise an exception when the performative is unknown during decoding.\"\"\"\n    msg = PrometheusMessage(\n        message_id=1,\n        dialogue_reference=(str(0), \"\"),\n        target=0,\n        performative=PrometheusMessage.Performative.RESPONSE,\n        code=0,\n        message=\"some_message\",\n    )\n\n    encoded_msg = PrometheusMessage.serializer.encode(msg)\n    with pytest.raises(ValueError, match=\"Performative not valid:\"):\n        with mock.patch.object(\n            PrometheusMessage.Performative, \"__eq__\", return_value=False\n        ):\n            PrometheusMessage.serializer.decode(encoded_msg)\n\n\n@mock.patch.object(\n    packages.fetchai.protocols.prometheus.message,\n    \"enforce\",\n    side_effect=AEAEnforceError(\"some error\"),\n)\ndef test_incorrect_message(mocked_enforce):\n    \"\"\"Test that we raise an exception when the message is incorrect.\"\"\"\n    with mock.patch.object(prometheus_message_logger, \"error\") as mock_logger:\n        PrometheusMessage(\n            message_id=1,\n            dialogue_reference=(str(0), \"\"),\n            target=0,\n            performative=PrometheusMessage.Performative.RESPONSE,\n            code=0,\n            message=\"some_message\",\n        )\n\n        mock_logger.assert_any_call(\"some error\")\n\n\nclass TestDialogues:\n    \"\"\"Tests prometheus dialogues.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set up the test.\"\"\"\n        cls.agent_addr = \"agent address\"\n        cls.server_addr = \"server address\"\n        cls.agent_dialogues = AgentDialogues(cls.agent_addr)\n        cls.server_dialogues = ServerDialogues(cls.server_addr)\n\n    def test_create_self_initiated(self):\n        \"\"\"Test the self initialisation of a dialogue.\"\"\"\n        result = self.agent_dialogues._create_self_initiated(\n            dialogue_opponent_addr=self.server_addr,\n            dialogue_reference=(str(0), \"\"),\n            role=PrometheusDialogue.Role.AGENT,\n        )\n        assert isinstance(result, PrometheusDialogue)\n        assert result.role == PrometheusDialogue.Role.AGENT, \"The role must be Agent.\"\n\n    def test_create_opponent_initiated(self):\n        \"\"\"Test the opponent initialisation of a dialogue.\"\"\"\n        result = self.agent_dialogues._create_opponent_initiated(\n            dialogue_opponent_addr=self.server_addr,\n            dialogue_reference=(str(0), \"\"),\n            role=PrometheusDialogue.Role.AGENT,\n        )\n        assert isinstance(result, PrometheusDialogue)\n        assert result.role == PrometheusDialogue.Role.AGENT, \"The role must be Agent.\"\n\n\nclass AgentDialogue(PrometheusDialogue):\n    \"\"\"The dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    def __init__(\n        self,\n        dialogue_label: DialogueLabel,\n        self_address: Address,\n        role: BaseDialogue.Role,\n        message_class: Type[PrometheusMessage],\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n\n        :return: None\n        \"\"\"\n        PrometheusDialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            self_address=self_address,\n            role=role,\n            message_class=message_class,\n        )\n\n\nclass AgentDialogues(PrometheusDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, self_address: Address) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :return: None\n        \"\"\"\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return PrometheusDialogue.Role.AGENT\n\n        PrometheusDialogues.__init__(\n            self,\n            self_address=self_address,\n            role_from_first_message=role_from_first_message,\n            dialogue_class=AgentDialogue,\n        )\n\n\nclass ServerDialogue(PrometheusDialogue):\n    \"\"\"The dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    def __init__(\n        self,\n        dialogue_label: DialogueLabel,\n        self_address: Address,\n        role: BaseDialogue.Role,\n        message_class: Type[PrometheusMessage],\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n\n        :return: None\n        \"\"\"\n        PrometheusDialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            self_address=self_address,\n            role=role,\n            message_class=message_class,\n        )\n\n\nclass ServerDialogues(PrometheusDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, self_address: Address) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :return: None\n        \"\"\"\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return PrometheusDialogue.Role.SERVER\n\n        PrometheusDialogues.__init__(\n            self,\n            self_address=self_address,\n            role_from_first_message=role_from_first_message,\n            dialogue_class=ServerDialogue,\n        )\n"
  },
  {
    "path": "tests/test_packages/test_skills/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"The tests module contains the tests of the packages/skills dir.\"\"\"\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_advanced_data_request/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"The tests module contains the tests of the packages/skills/advanced_data_request dir.\"\"\"\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_advanced_data_request/test_behaviours.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the behaviour classes of the advanced data request skill.\"\"\"\n\nfrom pathlib import Path\nfrom typing import cast\n\nfrom aea.test_tools.test_skill import BaseSkillTestCase\n\nfrom packages.fetchai.protocols.http.message import HttpMessage\nfrom packages.fetchai.protocols.prometheus.message import PrometheusMessage\nfrom packages.fetchai.skills.advanced_data_request.behaviours import (\n    AdvancedDataRequestBehaviour,\n)\nfrom packages.fetchai.skills.advanced_data_request.models import (\n    AdvancedDataRequestModel,\n)\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass TestSkillBehaviour(BaseSkillTestCase):\n    \"\"\"Test behaviours of advanced data request.\"\"\"\n\n    path_to_skill = Path(\n        ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"advanced_data_request\"\n    )\n\n    @classmethod\n    def setup(cls, **kwargs):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.advanced_data_request_behaviour = cast(\n            AdvancedDataRequestBehaviour,\n            cls._skill.skill_context.behaviours.advanced_data_request_behaviour,\n        )\n        cls.advanced_data_request_model = cast(\n            AdvancedDataRequestModel,\n            cls.advanced_data_request_behaviour.context.advanced_data_request_model,\n        )\n        cls.advanced_data_request_model.url = \"some_url\"\n\n    def test_send_http_request_message(self):\n        \"\"\"Test the send_http_request_message method of the advanced_data_request behaviour.\"\"\"\n        self.advanced_data_request_behaviour.send_http_request_message()\n        self.assert_quantity_in_outbox(1)\n        msg = cast(HttpMessage, self.get_message_from_outbox())\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=msg,\n            message_type=HttpMessage,\n            performative=HttpMessage.Performative.REQUEST,\n            url=\"some_url\",\n        )\n        assert has_attributes, error_str\n\n    def test_add_prometheus_metric(self):\n        \"\"\"Test the add_prometheus_metric method of the advanced_data_request behaviour.\"\"\"\n        self.advanced_data_request_behaviour.add_prometheus_metric(\n            \"some_metric\", \"Gauge\", \"some_description\", {\"label_key\": \"label_value\"}\n        )\n        self.assert_quantity_in_outbox(1)\n        msg = cast(PrometheusMessage, self.get_message_from_outbox())\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=msg,\n            message_type=PrometheusMessage,\n            performative=PrometheusMessage.Performative.ADD_METRIC,\n            type=\"Gauge\",\n            title=\"some_metric\",\n            description=\"some_description\",\n            labels={\"label_key\": \"label_value\"},\n        )\n        assert has_attributes, error_str\n\n    def test_update_prometheus_metric(self):\n        \"\"\"Test the update_prometheus_metric method of the advanced_data_request behaviour.\"\"\"\n        self.advanced_data_request_behaviour.update_prometheus_metric(\n            \"some_metric\", \"set\", 0.0, {\"label_key\": \"label_value\"}\n        )\n        self.assert_quantity_in_outbox(1)\n        msg = cast(PrometheusMessage, self.get_message_from_outbox())\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=msg,\n            message_type=PrometheusMessage,\n            performative=PrometheusMessage.Performative.UPDATE_METRIC,\n            callable=\"set\",\n            title=\"some_metric\",\n            value=0.0,\n            labels={\"label_key\": \"label_value\"},\n        )\n        assert has_attributes, error_str\n\n    def test_setup(self):\n        \"\"\"Test that the setup method puts two messages (prometheus metrics) in the outbox by default.\"\"\"\n        self.advanced_data_request_behaviour.setup()\n        self.assert_quantity_in_outbox(2)\n\n        msg = cast(PrometheusMessage, self.get_message_from_outbox())\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=msg,\n            message_type=PrometheusMessage,\n            performative=PrometheusMessage.Performative.ADD_METRIC,\n            type=\"Gauge\",\n            title=\"num_retrievals\",\n        )\n        assert has_attributes, error_str\n\n        msg = cast(PrometheusMessage, self.get_message_from_outbox())\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=msg,\n            message_type=PrometheusMessage,\n            performative=PrometheusMessage.Performative.ADD_METRIC,\n            type=\"Gauge\",\n            title=\"num_requests\",\n        )\n        assert has_attributes, error_str\n\n    def test_act(self):\n        \"\"\"Test that the act method of the advanced_data_request behaviour puts one message (http request) in the outbox.\"\"\"\n\n        self.advanced_data_request_behaviour.act()\n        self.assert_quantity_in_outbox(1)\n\n        msg = cast(HttpMessage, self.get_message_from_outbox())\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=msg,\n            message_type=HttpMessage,\n            performative=HttpMessage.Performative.REQUEST,\n            url=self.advanced_data_request_model.url,\n        )\n        assert has_attributes, error_str\n\n    def test_teardown(self):\n        \"\"\"Test that the teardown method of the advanced_data_request behaviour leaves no messages in the outbox.\"\"\"\n        assert self.advanced_data_request_behaviour.teardown() is None\n        self.assert_quantity_in_outbox(0)\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_advanced_data_request/test_handlers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the handler classes of the simple_data_request skill.\"\"\"\n\nimport logging\nfrom pathlib import Path\nfrom typing import cast\nfrom unittest.mock import patch\n\nfrom aea.protocols.dialogue.base import DialogueMessage\nfrom aea.test_tools.test_skill import BaseSkillTestCase\n\nfrom packages.fetchai.connections.http_server.connection import (\n    PUBLIC_ID as HTTP_SERVER_ID,\n)\nfrom packages.fetchai.protocols.http.message import HttpMessage\nfrom packages.fetchai.protocols.prometheus.message import PrometheusMessage\nfrom packages.fetchai.skills.advanced_data_request.dialogues import (\n    HttpDialogues,\n    PrometheusDialogues,\n)\nfrom packages.fetchai.skills.advanced_data_request.handlers import (\n    HttpHandler,\n    PrometheusHandler,\n)\nfrom packages.fetchai.skills.advanced_data_request.models import (\n    AdvancedDataRequestModel,\n)\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass TestHttpHandler(BaseSkillTestCase):\n    \"\"\"Test http handler of advanced_data_request skill.\"\"\"\n\n    path_to_skill = Path(\n        ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"advanced_data_request\"\n    )\n    is_agent_to_agent_messages = False\n\n    @classmethod\n    def setup(cls, **kwargs):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.http_handler = cast(HttpHandler, cls._skill.skill_context.handlers.http)\n        cls.logger = cls._skill.skill_context.logger\n\n        cls.advanced_data_request_model = cast(\n            AdvancedDataRequestModel,\n            cls._skill.skill_context.advanced_data_request_model,\n        )\n\n        cls.advanced_data_request_model.url = \"http://some-url\"\n        cls.advanced_data_request_model.outputs = [\n            {\"name\": \"output1\", \"json_path\": \"in1.in2\"},\n            {\"name\": \"output2\", \"json_path\": \"id\"},\n        ]\n\n        cls.http_dialogues = cast(\n            HttpDialogues, cls._skill.skill_context.http_dialogues\n        )\n\n        cls.list_of_messages = (\n            DialogueMessage(\n                HttpMessage.Performative.REQUEST,\n                {\n                    \"method\": \"get\",\n                    \"url\": \"some_url\",\n                    \"headers\": \"\",\n                    \"version\": \"\",\n                    \"body\": b\"\",\n                },\n            ),\n        )\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the http handler.\"\"\"\n        assert self.http_handler.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_setup_with_http_server(self):\n        \"\"\"Test the setup method of the http handler.\"\"\"\n        self.advanced_data_request_model.use_http_server = True\n        assert self.http_handler.setup() is None\n\n        assert self.http_handler._http_server_id == HTTP_SERVER_ID\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle_response(self):\n        \"\"\"Test the _handle_response method of the http handler to a valid response.\"\"\"\n        # setup\n        http_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.http_dialogues,\n            messages=self.list_of_messages[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=http_dialogue,\n            performative=HttpMessage.Performative.RESPONSE,\n            version=\"\",\n            status_code=200,\n            status_text=\"\",\n            headers=\"\",\n            body=b'{\"in1\": {\"in2\": 1.0}, \"id\": \"XXX\"}',\n        )\n\n        # handle message\n        self.http_handler.handle(incoming_message)\n\n        # check that data was correctly entered into shared state\n        observation = {\n            \"output1\": {\"value\": 100000, \"decimals\": 5},\n            \"output2\": {\"value\": \"XXX\"},\n        }\n        assert (\n            self.http_handler.context.shared_state[\"output1\"] == observation[\"output1\"]\n        )\n        assert (\n            self.http_handler.context.shared_state[\"output2\"] == observation[\"output2\"]\n        )\n\n        # check that outbox contains update_prometheus metric message\n        self.assert_quantity_in_outbox(1)\n\n    def test_handle__handle_unidentified_dialogue(self):\n        \"\"\"Test handling an unidentified dialogoue\"\"\"\n        # setup\n        incorrect_dialogue_reference = (\"\", \"\")\n        incoming_message = self.build_incoming_message(\n            message_type=HttpMessage,\n            dialogue_reference=incorrect_dialogue_reference,\n            performative=HttpMessage.Performative.RESPONSE,\n            version=\"\",\n            status_code=200,\n            status_text=\"\",\n            headers=\"\",\n            body=b\"{}\",\n        )\n\n        # operation\n        with patch.object(self.http_handler.context.logger, \"log\") as mock_logger:\n            self.http_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received invalid message={incoming_message}, unidentified dialogue.\",\n        )\n\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle_response_invalid_body(self):\n        \"\"\"Test the _handle_response method of the http handler to an unexpected response.\"\"\"\n        # setup\n        http_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.http_dialogues,\n            messages=self.list_of_messages[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=http_dialogue,\n            performative=HttpMessage.Performative.RESPONSE,\n            version=\"\",\n            status_code=200,\n            status_text=\"\",\n            headers=\"\",\n            body=b\"{}\",\n        )\n\n        # handle message with logging\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.http_handler.handle(incoming_message)\n\n        assert \"output1\" not in self.http_handler.context.shared_state\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            \"No valid output for output1 found in response.\",\n        )\n\n    def test_handle_response_missing_output(self):\n        \"\"\"Test the _handle_response method of the http handler to a response with a missing output.\"\"\"\n        # setup\n        http_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.http_dialogues,\n            messages=self.list_of_messages[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=http_dialogue,\n            performative=HttpMessage.Performative.RESPONSE,\n            version=\"\",\n            status_code=200,\n            status_text=\"\",\n            headers=\"\",\n            body=b'{\"in1\": {}, \"id\": \"XXX\"}',\n        )\n\n        # handle message with logging\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.http_handler.handle(incoming_message)\n\n        assert self.http_handler.context.shared_state[\"output2\"] == {\"value\": \"XXX\"}\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            \"No valid output for output1 found in response.\",\n        )\n        mock_logger.assert_any_call(\n            logging.INFO,\n            \"Observation: {'output2': {'value': 'XXX'}}\",\n        )\n\n    def test_handle_response_bad_response_code(self):\n        \"\"\"Test the _handle_response method of the http handler to a response with a code that is not 200.\"\"\"\n        # setup\n        http_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.http_dialogues,\n            messages=self.list_of_messages[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=http_dialogue,\n            performative=HttpMessage.Performative.RESPONSE,\n            version=\"\",\n            status_code=999,\n            status_text=\"\",\n            headers=\"\",\n            body=b'{\"in1\": {\"in2\": 1.0}, \"id\": \"XXX\"}',\n        )\n\n        # handle message with logging\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.http_handler.handle(incoming_message)\n\n        assert \"output1\" not in self.http_handler.context.shared_state\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            \"got unexpected http message: code = 999\",\n        )\n\n    def test_handle_request_get(self):\n        \"\"\"Test the _handle_request method of the http handler with 'get' method.\"\"\"\n\n        incoming_message = self.build_incoming_message(\n            message_type=HttpMessage,\n            performative=HttpMessage.Performative.REQUEST,\n            method=\"get\",\n            url=\"some_url\",\n            headers=\"\",\n            version=\"\",\n            body=b\"\",\n        )\n\n        self.http_handler._http_server_id = \"some_id\"\n\n        # handle message with logging\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.http_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            \"received http request with method=get, url=some_url and body=b''\",\n        )\n\n        # check that outbox contains the http response prometheus metric update messages\n        self.assert_quantity_in_outbox(2)\n\n    def test_handle_request_post(self):\n        \"\"\"Test the _handle_request method of the http handler with 'post' method.\"\"\"\n\n        incoming_message = self.build_incoming_message(\n            message_type=HttpMessage,\n            performative=HttpMessage.Performative.REQUEST,\n            method=\"post\",\n            url=\"some_url\",\n            headers=\"\",\n            version=\"\",\n            body=b\"\",\n        )\n\n        self.http_handler._http_server_id = \"some_id\"\n\n        # handle message with logging\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.http_handler.handle(incoming_message)\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            \"method 'post' is not supported.\",\n        )\n        # check that outbox is empty\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle_request_no_http_server(self):\n        \"\"\"Test the _handle_request method of the http handler when http server is disabled.\"\"\"\n\n        incoming_message = self.build_incoming_message(\n            message_type=HttpMessage,\n            performative=HttpMessage.Performative.REQUEST,\n            method=\"get\",\n            url=\"some_url\",\n            headers=\"\",\n            version=\"\",\n            body=b\"\",\n        )\n\n        # handle message with logging\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.http_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            \"received http request with method=get, url=some_url and body=b''\",\n        )\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            \"http server is not enabled.\",\n        )\n        # check that outbox is empty\n        self.assert_quantity_in_outbox(0)\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the http handler.\"\"\"\n        assert self.http_handler.teardown() is None\n        self.assert_quantity_in_outbox(0)\n\n\nclass TestPrometheusHandler(BaseSkillTestCase):\n    \"\"\"Test prometheus handler of advanced_data_request skill.\"\"\"\n\n    path_to_skill = Path(\n        ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"advanced_data_request\"\n    )\n    is_agent_to_agent_messages = False\n\n    @classmethod\n    def setup(cls, **kwargs):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.prometheus_handler = cast(\n            PrometheusHandler, cls._skill.skill_context.handlers.prometheus\n        )\n        cls.logger = cls._skill.skill_context.logger\n\n        cls.advanced_data_request_model = cast(\n            AdvancedDataRequestModel,\n            cls._skill.skill_context.advanced_data_request_model,\n        )\n\n        cls.prometheus_dialogues = cast(\n            PrometheusDialogues, cls._skill.skill_context.prometheus_dialogues\n        )\n\n        cls.list_of_messages = (\n            DialogueMessage(\n                PrometheusMessage.Performative.ADD_METRIC,\n                {\n                    \"type\": \"Gauge\",\n                    \"title\": \"some_title\",\n                    \"description\": \"some_description\",\n                    \"labels\": {},\n                },\n            ),\n        )\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the prometheus handler.\"\"\"\n        assert self.prometheus_handler.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle_response(self):\n        \"\"\"Test the _handle_response method of the prometheus handler to a valid response.\"\"\"\n        # setup\n        prometheus_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.prometheus_dialogues,\n            messages=self.list_of_messages[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=prometheus_dialogue,\n            performative=PrometheusMessage.Performative.RESPONSE,\n            code=200,\n            message=\"some_message\",\n        )\n\n        # handle message with logging\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.prometheus_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.DEBUG, \"Prometheus response (200): some_message\"\n        )\n\n    def test_handle_unidentified_dialogue(self):\n        \"\"\"Test the _handle_response method of the prometheus handler to an unidentified dialogue.\"\"\"\n        # setup\n        incoming_message = self.build_incoming_message(\n            message_type=PrometheusMessage,\n            performative=PrometheusMessage.Performative.RESPONSE,\n            code=200,\n            message=\"some_message\",\n        )\n\n        # handle message with logging\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.prometheus_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received invalid message={incoming_message}, unidentified dialogue.\",\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the prometheus handler.\"\"\"\n        assert self.prometheus_handler.teardown() is None\n        self.assert_quantity_in_outbox(0)\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_aries_alice/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"The tests module contains the tests of the packages/skills/aries_alice dir.\"\"\"\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_aries_alice/intermediate_class.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module sets up test environment for aries_alice skill.\"\"\"\n\nimport json\nfrom pathlib import Path\nfrom typing import cast\n\nfrom aea.helpers.search.models import (\n    Attribute,\n    Constraint,\n    ConstraintType,\n    DataModel,\n    Description,\n    Location,\n    Query,\n)\nfrom aea.protocols.dialogue.base import DialogueMessage\nfrom aea.test_tools.test_skill import BaseSkillTestCase\n\nfrom packages.fetchai.protocols.http.message import HttpMessage\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.skills.aries_alice.behaviours import AliceBehaviour\nfrom packages.fetchai.skills.aries_alice.dialogues import (\n    DefaultDialogues,\n    HttpDialogues,\n    OefSearchDialogues,\n)\nfrom packages.fetchai.skills.aries_alice.handlers import (\n    DefaultHandler,\n    HttpHandler,\n    OefSearchHandler,\n)\nfrom packages.fetchai.skills.aries_alice.strategy import Strategy\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass AriesAliceTestCase(BaseSkillTestCase):\n    \"\"\"Sets the aries_alice class up for testing.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"aries_alice\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        cls.location = {\"longitude\": 0.1270, \"latitude\": 51.5194}\n        cls.service_data = {\"key\": \"seller_service\", \"value\": \"some_value\"}\n        cls.personality_data = {\"piece\": \"genus\", \"value\": \"some_personality\"}\n        cls.classification = {\"piece\": \"classification\", \"value\": \"some_classification\"}\n        cls.admin_host = \"127.0.0.1\"\n        cls.admin_port = 8067\n        config_overrides = {\n            \"models\": {\n                \"strategy\": {\n                    \"args\": {\n                        \"location\": cls.location,\n                        \"service_data\": cls.service_data,\n                        \"personality_data\": cls.personality_data,\n                        \"classification\": cls.classification,\n                        \"admin_host\": cls.admin_host,\n                        \"admin_port\": cls.admin_port,\n                    }\n                }\n            },\n        }\n\n        super().setup(config_overrides=config_overrides)\n\n        # behaviours\n        cls.alice_behaviour = cast(\n            AliceBehaviour,\n            cls._skill.skill_context.behaviours.alice,\n        )\n\n        # dialogues\n        cls.default_dialogues = cast(\n            DefaultDialogues, cls._skill.skill_context.default_dialogues\n        )\n        cls.http_dialogues = cast(\n            HttpDialogues, cls._skill.skill_context.http_dialogues\n        )\n        cls.oef_search_dialogues = cast(\n            OefSearchDialogues, cls._skill.skill_context.oef_search_dialogues\n        )\n\n        # handlers\n        cls.default_handler = cast(\n            DefaultHandler, cls._skill.skill_context.handlers.default\n        )\n        cls.http_handler = cast(HttpHandler, cls._skill.skill_context.handlers.http)\n        cls.oef_search_handler = cast(\n            OefSearchHandler, cls._skill.skill_context.handlers.oef_search\n        )\n\n        # models\n        cls.strategy = cast(Strategy, cls._skill.skill_context.strategy)\n\n        cls.logger = cls._skill.skill_context.logger\n\n        # mocked objects\n        cls.mocked_method = \"SOME_METHOD\"\n        cls.mocked_url = \"www.some-url.com\"\n        cls.mocked_version = \"some_version\"\n        cls.mocked_headers = \"some_headers\"\n        cls.body_dict = {\"some_key\": \"some_value\"}\n        cls.body_str = \"some_body\"\n        cls.mocked_body_bytes = json.dumps(cls.body_str).encode(\"utf-8\")\n        cls.mocked_query = Query(\n            [Constraint(\"some_attribute_name\", ConstraintType(\"==\", \"some_value\"))],\n            DataModel(\n                \"some_data_model_name\",\n                [\n                    Attribute(\n                        \"some_attribute_name\",\n                        str,\n                        False,\n                        \"Some attribute descriptions.\",\n                    )\n                ],\n            ),\n        )\n        cls.mocked_proposal = Description(\n            {\n                \"contract_address\": \"some_contract_address\",\n                \"token_id\": \"123456\",\n                \"trade_nonce\": \"876438756348568\",\n                \"from_supply\": \"543\",\n                \"to_supply\": \"432\",\n                \"value\": \"67\",\n            }\n        )\n        cls.mocked_registration_description = Description({\"foo1\": 1, \"bar1\": 2})\n\n        cls.registration_message = OefSearchMessage(\n            dialogue_reference=(\"\", \"\"),\n            performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n            service_description=cls.mocked_registration_description,\n        )\n        cls.registration_message.sender = str(cls._skill.skill_context.skill_id)\n        cls.registration_message.to = cls._skill.skill_context.search_service_address\n\n        # list of messages\n        cls.list_of_http_messages = (\n            DialogueMessage(\n                HttpMessage.Performative.REQUEST,\n                {\n                    \"method\": cls.mocked_method,\n                    \"url\": cls.mocked_url,\n                    \"headers\": cls.mocked_headers,\n                    \"version\": cls.mocked_version,\n                    \"body\": cls.mocked_body_bytes,\n                },\n                is_incoming=False,\n            ),\n        )\n\n        cls.register_location_description = Description(\n            {\"location\": Location(51.5194, 0.1270)},\n            data_model=DataModel(\n                \"location_agent\", [Attribute(\"location\", Location, True)]\n            ),\n        )\n        cls.list_of_messages_register_location = (\n            DialogueMessage(\n                OefSearchMessage.Performative.REGISTER_SERVICE,\n                {\"service_description\": cls.register_location_description},\n                is_incoming=False,\n            ),\n        )\n\n        cls.register_service_description = Description(\n            {\"key\": \"some_key\", \"value\": \"some_value\"},\n            data_model=DataModel(\n                \"set_service_key\",\n                [Attribute(\"key\", str, True), Attribute(\"value\", str, True)],\n            ),\n        )\n        cls.list_of_messages_register_service = (\n            DialogueMessage(\n                OefSearchMessage.Performative.REGISTER_SERVICE,\n                {\"service_description\": cls.register_service_description},\n                is_incoming=False,\n            ),\n        )\n\n        cls.register_genus_description = Description(\n            {\"piece\": \"genus\", \"value\": \"some_value\"},\n            data_model=DataModel(\n                \"personality_agent\",\n                [Attribute(\"piece\", str, True), Attribute(\"value\", str, True)],\n            ),\n        )\n        cls.list_of_messages_register_genus = (\n            DialogueMessage(\n                OefSearchMessage.Performative.REGISTER_SERVICE,\n                {\"service_description\": cls.register_genus_description},\n                is_incoming=False,\n            ),\n        )\n\n        cls.register_classification_description = Description(\n            {\"piece\": \"classification\", \"value\": \"some_value\"},\n            data_model=DataModel(\n                \"personality_agent\",\n                [Attribute(\"piece\", str, True), Attribute(\"value\", str, True)],\n            ),\n        )\n        cls.list_of_messages_register_classification = (\n            DialogueMessage(\n                OefSearchMessage.Performative.REGISTER_SERVICE,\n                {\"service_description\": cls.register_classification_description},\n                is_incoming=False,\n            ),\n        )\n\n        cls.register_invalid_description = Description(\n            {\"piece\": \"classification\", \"value\": \"some_value\"},\n            data_model=DataModel(\n                \"some_different_name\",\n                [Attribute(\"piece\", str, True), Attribute(\"value\", str, True)],\n            ),\n        )\n        cls.list_of_messages_register_invalid = (\n            DialogueMessage(\n                OefSearchMessage.Performative.REGISTER_SERVICE,\n                {\"service_description\": cls.register_invalid_description},\n                is_incoming=False,\n            ),\n        )\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_aries_alice/test_behaviours.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the behaviour classes of the aries_alice skill.\"\"\"\n\nimport json\nimport logging\nfrom unittest.mock import patch\n\nfrom packages.fetchai.protocols.http.message import HttpMessage\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.skills.aries_alice.behaviours import HTTP_CLIENT_PUBLIC_ID\n\nfrom tests.test_packages.test_skills.test_aries_alice.intermediate_class import (\n    AriesAliceTestCase,\n)\n\n\nclass TestAliceBehaviour(AriesAliceTestCase):\n    \"\"\"Test alice behaviour of aries_alice.\"\"\"\n\n    def test_init(self):\n        \"\"\"Test the __init__ method of the alice behaviour.\"\"\"\n        assert self.alice_behaviour.failed_registration_msg is None\n        assert self.alice_behaviour._nb_retries == 0\n\n    def test_send_http_request_message(self):\n        \"\"\"Test the send_http_request_message method of the alice behaviour.\"\"\"\n        # operation\n        self.alice_behaviour.send_http_request_message(\n            self.mocked_method, self.mocked_url, self.body_dict\n        )\n\n        # after\n        self.assert_quantity_in_outbox(1)\n\n        message = self.get_message_from_outbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=HttpMessage,\n            performative=HttpMessage.Performative.REQUEST,\n            to=str(HTTP_CLIENT_PUBLIC_ID),\n            sender=str(self.skill.skill_context.skill_id),\n            method=self.mocked_method,\n            url=self.mocked_url,\n            headers=\"Content-Type: application/json\",\n            version=\"\",\n            body=json.dumps(self.body_dict).encode(\"utf-8\"),\n        )\n        assert has_attributes, error_str\n\n    def test_perform_agents_search(self) -> None:\n        \"\"\"Perform agents search to query proofs from.\"\"\"\n        self.strategy.is_searching = True  # type: ignore\n        with patch.object(self.alice_behaviour.context.logger, \"log\") as mock_logger:  # type: ignore\n            self.alice_behaviour.perform_agents_search()  # type: ignore\n\n        mock_logger.assert_any_call(logging.INFO, \"Searching for agents on SOEF...\")\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the alice behaviour.\"\"\"\n        # operation\n        with patch.object(\n            self.strategy,\n            \"get_location_description\",\n            return_value=self.mocked_registration_description,\n        ) as mock_desc:\n            with patch.object(self.logger, \"log\") as mock_logger:\n                self.alice_behaviour.setup()\n\n        # after\n        self.assert_quantity_in_outbox(1)\n\n        mock_logger.assert_any_call(\n            logging.INFO, f\"My address is: {self.skill.skill_context.agent_address}\"\n        )\n\n        mock_desc.assert_called_once()\n\n        # _register_agent\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=OefSearchMessage,\n            performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n            to=self.skill.skill_context.search_service_address,\n            sender=str(self.skill.skill_context.skill_id),\n            service_description=self.mocked_registration_description,\n        )\n        assert has_attributes, error_str\n\n        mock_logger.assert_any_call(logging.INFO, \"registering agent on SOEF.\")\n\n    def test_act_i(self):\n        \"\"\"Test the act method of the alice behaviour where failed_registration_msg is NOT None.\"\"\"\n        # setup\n        self.alice_behaviour.failed_registration_msg = self.registration_message\n\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.alice_behaviour.act()\n\n        # after\n        self.assert_quantity_in_outbox(1)\n\n        # _retry_failed_registration\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=type(self.registration_message),\n            performative=self.registration_message.performative,\n            to=self.registration_message.to,\n            sender=str(self.skill.skill_context.skill_id),\n            service_description=self.registration_message.service_description,\n        )\n        assert has_attributes, error_str\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"Retrying registration on SOEF. Retry {self.alice_behaviour._nb_retries} out of {self.alice_behaviour._max_soef_registration_retries}.\",\n        )\n        assert self.alice_behaviour.failed_registration_msg is None\n\n    def test_act_ii(self):\n        \"\"\"Test the act method of the alice behaviour where failed_registration_msg is NOT None and max retries is reached.\"\"\"\n        # setup\n        self.alice_behaviour.failed_registration_msg = self.registration_message\n        self.alice_behaviour._max_soef_registration_retries = 2\n        self.alice_behaviour._nb_retries = 2\n\n        self.alice_behaviour.act()\n\n        # after\n        self.assert_quantity_in_outbox(0)\n        assert self.skill.skill_context.is_active is False\n\n    def test_register_service(self):\n        \"\"\"Test the register_service method of the alice behaviour.\"\"\"\n        # operation\n        with patch.object(\n            self.strategy,\n            \"get_register_service_description\",\n            return_value=self.mocked_registration_description,\n        ):\n            with patch.object(self.logger, \"log\") as mock_logger:\n                self.alice_behaviour.register_service()\n\n        # after\n        self.assert_quantity_in_outbox(1)\n\n        message = self.get_message_from_outbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=OefSearchMessage,\n            performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n            to=self.skill.skill_context.search_service_address,\n            sender=str(self.skill.skill_context.skill_id),\n            service_description=self.mocked_registration_description,\n        )\n        assert has_attributes, error_str\n        mock_logger.assert_any_call(\n            logging.INFO, \"registering agent's service on the SOEF.\"\n        )\n\n    def test_register_genus(self):\n        \"\"\"Test the register_genus method of the alice behaviour.\"\"\"\n        # operation\n        with patch.object(\n            self.strategy,\n            \"get_register_personality_description\",\n            return_value=self.mocked_registration_description,\n        ):\n            with patch.object(self.logger, \"log\") as mock_logger:\n                self.alice_behaviour.register_genus()\n\n        # after\n        self.assert_quantity_in_outbox(1)\n\n        message = self.get_message_from_outbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=OefSearchMessage,\n            performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n            to=self.skill.skill_context.search_service_address,\n            sender=str(self.skill.skill_context.skill_id),\n            service_description=self.mocked_registration_description,\n        )\n        assert has_attributes, error_str\n        mock_logger.assert_any_call(\n            logging.INFO, \"registering agent's personality genus on the SOEF.\"\n        )\n\n    def test_register_classification(self):\n        \"\"\"Test the register_classification method of the alice behaviour.\"\"\"\n        # operation\n        with patch.object(\n            self.strategy,\n            \"get_register_classification_description\",\n            return_value=self.mocked_registration_description,\n        ):\n            with patch.object(self.logger, \"log\") as mock_logger:\n                self.alice_behaviour.register_classification()\n\n        # after\n        self.assert_quantity_in_outbox(1)\n\n        message = self.get_message_from_outbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=OefSearchMessage,\n            performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n            to=self.skill.skill_context.search_service_address,\n            sender=str(self.skill.skill_context.skill_id),\n            service_description=self.mocked_registration_description,\n        )\n        assert has_attributes, error_str\n        mock_logger.assert_any_call(\n            logging.INFO, \"registering agent's personality classification on the SOEF.\"\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the alice behaviour.\"\"\"\n        # operation\n        with patch.object(\n            self.strategy,\n            \"get_unregister_service_description\",\n            return_value=self.mocked_registration_description,\n        ):\n            with patch.object(\n                self.strategy,\n                \"get_location_description\",\n                return_value=self.mocked_registration_description,\n            ):\n                with patch.object(self.logger, \"log\") as mock_logger:\n                    self.alice_behaviour.teardown()\n\n        # after\n        self.assert_quantity_in_outbox(2)\n\n        # _unregister_service\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=OefSearchMessage,\n            performative=OefSearchMessage.Performative.UNREGISTER_SERVICE,\n            to=self.skill.skill_context.search_service_address,\n            sender=str(self.skill.skill_context.skill_id),\n            service_description=self.mocked_registration_description,\n        )\n        assert has_attributes, error_str\n        mock_logger.assert_any_call(logging.INFO, \"unregistering service from SOEF.\")\n\n        # _unregister_agent\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=OefSearchMessage,\n            performative=OefSearchMessage.Performative.UNREGISTER_SERVICE,\n            to=self.skill.skill_context.search_service_address,\n            sender=str(self.skill.skill_context.skill_id),\n            service_description=self.mocked_registration_description,\n        )\n        assert has_attributes, error_str\n        mock_logger.assert_any_call(logging.INFO, \"unregistering agent from SOEF.\")\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_aries_alice/test_dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the dialogue classes of the aries_alice skill.\"\"\"\n\nfrom aea.test_tools.test_skill import COUNTERPARTY_AGENT_ADDRESS\n\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.protocols.http.message import HttpMessage\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.skills.aries_alice.dialogues import (\n    DefaultDialogue,\n    HttpDialogue,\n    OefSearchDialogue,\n)\n\nfrom tests.test_packages.test_skills.test_aries_alice.intermediate_class import (\n    AriesAliceTestCase,\n)\n\n\nclass TestDialogues(AriesAliceTestCase):\n    \"\"\"Test dialogue classes of aries_alice.\"\"\"\n\n    def test_default_dialogues(self):\n        \"\"\"Test the DefaultDialogues class.\"\"\"\n        _, dialogue = self.default_dialogues.create(\n            counterparty=COUNTERPARTY_AGENT_ADDRESS,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"some_content\",\n        )\n        assert dialogue.role == DefaultDialogue.Role.AGENT\n        assert dialogue.self_address == self.skill.skill_context.agent_address\n\n    def test_http_dialogues(self):\n        \"\"\"Test the HttpDialogues class.\"\"\"\n        _, dialogue = self.http_dialogues.create(\n            counterparty=COUNTERPARTY_AGENT_ADDRESS,\n            performative=HttpMessage.Performative.REQUEST,\n            method=self.mocked_method,\n            url=self.mocked_url,\n            version=self.mocked_version,\n            headers=self.mocked_headers,\n            body=self.mocked_body_bytes,\n        )\n        assert dialogue.role == HttpDialogue.Role.CLIENT\n        assert dialogue.self_address == str(self.skill.skill_context.skill_id)\n\n    def test_oef_search_dialogues(self):\n        \"\"\"Test the OefSearchDialogues class.\"\"\"\n        _, dialogue = self.oef_search_dialogues.create(\n            counterparty=COUNTERPARTY_AGENT_ADDRESS,\n            performative=OefSearchMessage.Performative.SEARCH_SERVICES,\n            query=self.mocked_query,\n        )\n        assert dialogue.role == OefSearchDialogue.Role.AGENT\n        assert dialogue.self_address == str(self.skill.skill_context.skill_id)\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_aries_alice/test_handlers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the handler classes of the aries_alice skill.\"\"\"\nimport json\nimport logging\nfrom typing import cast\nfrom unittest.mock import ANY, patch\n\nfrom aea.protocols.dialogue.base import Dialogues\n\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.protocols.http.message import HttpMessage\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.skills.aries_alice.dialogues import (\n    HttpDialogue,\n    OefSearchDialogue,\n)\nfrom packages.fetchai.skills.aries_alice.handlers import ADMIN_COMMAND_RECEIVE_INVITE\n\nfrom tests.test_packages.test_skills.test_aries_alice.intermediate_class import (\n    AriesAliceTestCase,\n)\n\n\nclass TestDefaultHandler(AriesAliceTestCase):\n    \"\"\"Test default handler of aries_alice.\"\"\"\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the default handler.\"\"\"\n        assert self.default_handler.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle_i(self):\n        \"\"\"Test the handle method of the default handler where @type is in content.\"\"\"\n        # setup\n        content = {\"@type\": \"some\", \"@id\": \"conn_id\"}\n        content_bytes = json.dumps(content).encode(\"utf-8\")\n        incoming_message = cast(\n            DefaultMessage,\n            self.build_incoming_message(\n                message_type=DefaultMessage,\n                performative=DefaultMessage.Performative.BYTES,\n                dialogue_reference=Dialogues.new_self_initiated_dialogue_reference(),\n                content=content_bytes,\n            ),\n        )\n\n        # operation\n        with patch.object(\n            self.alice_behaviour, \"send_http_request_message\"\n        ) as mock_send:\n            with patch.object(self.logger, \"log\") as mock_logger:\n                self.default_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"Received message content:{content}\",\n        )\n        mock_send.assert_any_call(\n            method=\"POST\",\n            url=self.strategy.admin_url\n            + ADMIN_COMMAND_RECEIVE_INVITE\n            + \"?auto_accept=true\",\n            content=content,\n        )\n\n    def test_handle_ii(self):\n        \"\"\"Test the handle method of the default handler where http_dialogue is None.\"\"\"\n        # setup\n        incoming_message = cast(\n            DefaultMessage,\n            self.build_incoming_message(\n                message_type=DefaultMessage,\n                performative=DefaultMessage.Performative.ERROR,\n                dialogue_reference=(\"\", \"\"),\n                error_code=DefaultMessage.ErrorCode.INVALID_DIALOGUE,\n                error_msg=\"some_error_msg\",\n                error_data={\"some_key\": b\"some_bytes\"},\n            ),\n        )\n\n        # operation\n        with patch.object(\n            self.alice_behaviour, \"send_http_request_message\"\n        ) as mock_send:\n            with patch.object(self.logger, \"log\") as mock_logger:\n                self.default_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.ERROR,\n            \"alice -> default_handler -> handle(): something went wrong when adding the incoming default message to the dialogue.\",\n        )\n        mock_send.assert_not_called()\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the default handler.\"\"\"\n        assert self.default_handler.teardown() is None\n        self.assert_quantity_in_outbox(0)\n\n\nclass TestHttpHandler(AriesAliceTestCase):\n    \"\"\"Test http handler of aries_alice.\"\"\"\n\n    is_agent_to_agent_messages = False\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the http_handler handler.\"\"\"\n        assert self.http_handler.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle_unidentified_dialogue(self):\n        \"\"\"Test the handle method of the http handler where incoming message is invalid.\"\"\"\n        # setup\n        incorrect_dialogue_reference = (\"\", \"\")\n        incoming_message = cast(\n            HttpMessage,\n            self.build_incoming_message(\n                message_type=HttpMessage,\n                dialogue_reference=incorrect_dialogue_reference,\n                performative=HttpMessage.Performative.REQUEST,\n                method=self.mocked_method,\n                url=self.mocked_url,\n                headers=self.mocked_headers,\n                version=self.mocked_version,\n                body=self.mocked_body_bytes,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.http_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.ERROR,\n            \"alice -> http_handler -> handle() -> REQUEST: something went wrong when adding the incoming HTTP webhook request message to the dialogue.\",\n        )\n\n    def test_handle_request_connection_invitation(self):\n        \"\"\"Test the handle method of the http handler where performative is REQUEST.\"\"\"\n        # setup\n        invitation_msg_id = \"some\"\n        connection_id = \"someconid\"\n        addr = \"some addr\"\n        self.http_handler.connected = {}\n        self.strategy.aea_addresses = [addr]\n        self.strategy.invitations = {invitation_msg_id: addr}\n        name = \"bob\"\n        body = {\n            \"invitation_msg_id\": invitation_msg_id,\n            \"connection_id\": connection_id,\n            \"state\": \"active\",\n            \"their_label\": name,\n        }\n        mocked_body_bytes = json.dumps(body).encode(\"utf-8\")\n        incoming_message = cast(\n            HttpMessage,\n            self.build_incoming_message(\n                message_type=HttpMessage,\n                performative=HttpMessage.Performative.REQUEST,\n                method=self.mocked_method,\n                url=self.mocked_url,\n                headers=self.mocked_headers,\n                version=self.mocked_version,\n                body=mocked_body_bytes,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger, patch.object(\n            self.alice_behaviour, \"send_http_request_message\"\n        ) as send_http_request_message_mock:\n            self.http_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(logging.INFO, f\"Connected to {name}\")\n        assert connection_id in self.http_handler.connected\n\n        send_http_request_message_mock.assert_any_call(\n            method=\"POST\",\n            url=self.strategy.admin_url + \"/present-proof/send-request\",\n            content=ANY,\n        )\n\n    def test_handle_request_credentials_proof_request(self):\n        \"\"\"Test the handle method of the http handler where performative is REQUEST.\"\"\"\n        # setup\n        self.http_handler.presentation_requests = []\n        presentation_exchange_id = \"some\"\n        body = {\n            \"role\": \"prover\",\n            \"presentation_request_dict\": {},\n            \"state\": \"request_received\",\n            \"presentation_exchange_id\": presentation_exchange_id,\n        }\n        mocked_body_bytes = json.dumps(body).encode(\"utf-8\")\n        incoming_message = cast(\n            HttpMessage,\n            self.build_incoming_message(\n                message_type=HttpMessage,\n                performative=HttpMessage.Performative.REQUEST,\n                method=self.mocked_method,\n                url=self.mocked_url,\n                headers=self.mocked_headers,\n                version=self.mocked_version,\n                body=mocked_body_bytes,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger, patch.object(\n            self.alice_behaviour, \"send_http_request_message\"\n        ) as send_http_request_message_mock:\n            self.http_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(logging.INFO, \"Got credentials proof request\")\n\n        send_http_request_message_mock.assert_any_call(\n            method=\"GET\",\n            url=self.strategy.admin_url\n            + f\"/present-proof/records/{presentation_exchange_id}/credentials\",\n        )\n\n    def test_handle_request_get_credentials_proof(self):\n        \"\"\"Test the handle method of the http handler where performative is REQUEST.\"\"\"\n        # setup\n        self.http_handler.presentation_requests = []\n        connection_id = \"some\"\n        addr = \"some_addr\"\n        name = \"bob\"\n        self.http_handler.addr_names = {addr: name}\n        self.http_handler.connected = {connection_id: addr}\n        self.strategy.aea_addresses = [addr]\n        presentation_exchange_id = \"some\"\n        body = {\n            \"role\": \"verifier\",\n            \"presentation_request_dict\": {},\n            \"state\": \"presentation_received\",\n            \"presentation_exchange_id\": presentation_exchange_id,\n            \"connection_id\": connection_id,\n        }\n        mocked_body_bytes = json.dumps(body).encode(\"utf-8\")\n        incoming_message = cast(\n            HttpMessage,\n            self.build_incoming_message(\n                message_type=HttpMessage,\n                performative=HttpMessage.Performative.REQUEST,\n                method=self.mocked_method,\n                url=self.mocked_url,\n                headers=self.mocked_headers,\n                version=self.mocked_version,\n                body=mocked_body_bytes,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.http_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(logging.INFO, f\"Got credentials proof from {name}\")\n\n    def test_handle_request_get_credentials_issued(self):\n        \"\"\"Test the handle method of the http handler where performative is REQUEST.\"\"\"\n        # setup\n        connection_id = \"some\"\n        self.strategy.is_searching = False\n        cred_def_id = \"some_cred_def_id\"\n        body = {\n            \"credential_proposal_dict\": {\"credential_proposal\": \"\"},\n            \"state\": \"credential_acked\",\n            \"raw_credential\": {\"cred_def_id\": cred_def_id},\n            \"connection_id\": connection_id,\n        }\n        mocked_body_bytes = json.dumps(body).encode(\"utf-8\")\n        incoming_message = cast(\n            HttpMessage,\n            self.build_incoming_message(\n                message_type=HttpMessage,\n                performative=HttpMessage.Performative.REQUEST,\n                method=self.mocked_method,\n                url=self.mocked_url,\n                headers=self.mocked_headers,\n                version=self.mocked_version,\n                body=mocked_body_bytes,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger, patch.object(\n            self.alice_behaviour, \"perform_agents_search\"\n        ) as mock_perform_agents_search:\n            self.http_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"Got crendetials from faber: schema:{cred_def_id} {body['credential_proposal_dict']['credential_proposal']}\",\n        )\n        assert self.strategy.is_searching is True\n        assert self.http_handler.cred_def_id == cred_def_id\n        mock_perform_agents_search.assert_called_once()\n\n    def test_handle_response_i(self):\n        \"\"\"Test the handle method of the http handler where performative is RESPONSE and content has Error.\"\"\"\n        # setup\n        http_dialogue = cast(\n            HttpDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.http_dialogues,\n                messages=self.list_of_http_messages[:1],\n            ),\n        )\n\n        body = {\"Error\": \"something\"}\n        mocked_body_bytes = json.dumps(body).encode(\"utf-8\")\n        incoming_message = cast(\n            HttpMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=http_dialogue,\n                performative=HttpMessage.Performative.RESPONSE,\n                status_code=200,\n                status_text=\"some_status_code\",\n                headers=self.mocked_headers,\n                version=self.mocked_version,\n                body=mocked_body_bytes,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.http_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.ERROR,\n            \"Something went wrong after I sent the administrative command of 'invitation receive'\",\n        )\n\n    def test_handle_response_ii(self):\n        \"\"\"Test the handle method of the http handler where performative is RESPONSE and content does NOT have Error.\"\"\"\n        # setup\n        addr = \"some addr\"\n        self.strategy.aea_addresses = [addr]\n        connection_id = 2342\n        invitation = {\"some_key\": \"some_value\"}\n        http_dialogue = cast(\n            HttpDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.http_dialogues,\n                messages=self.list_of_http_messages[:1],\n            ),\n        )\n\n        body = {\"connection_id\": connection_id, \"invitation\": invitation}\n        mocked_body_bytes = json.dumps(body).encode(\"utf-8\")\n        incoming_message = cast(\n            HttpMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=http_dialogue,\n                performative=HttpMessage.Performative.RESPONSE,\n                status_code=200,\n                status_text=\"some_status_code\",\n                headers=self.mocked_headers,\n                version=self.mocked_version,\n                body=mocked_body_bytes,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.http_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO, f\"Received http response message content:{body}\"\n        )\n        assert connection_id in self.http_handler.connections_sent\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"Sent invitation to {addr}. Waiting for the invitation from agent some addr to finalise the connection...\",\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the http handler.\"\"\"\n        assert self.http_handler.teardown() is None\n        self.assert_quantity_in_outbox(0)\n\n\nclass TestOefSearchHandler(AriesAliceTestCase):\n    \"\"\"Test oef_search handler of aries_alice.\"\"\"\n\n    is_agent_to_agent_messages = False\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the oef_search handler.\"\"\"\n        assert self.oef_search_handler.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle_unidentified_dialogue(self):\n        \"\"\"Test the _handle_unidentified_dialogue method of the oef_search handler.\"\"\"\n        # setup\n        incorrect_dialogue_reference = (\"\", \"\")\n        incoming_message = cast(\n            OefSearchMessage,\n            self.build_incoming_message(\n                message_type=OefSearchMessage,\n                dialogue_reference=incorrect_dialogue_reference,\n                performative=OefSearchMessage.Performative.OEF_ERROR,\n                oef_error_operation=OefSearchMessage.OefErrorOperation.REGISTER_SERVICE,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received invalid oef_search message={incoming_message}, unidentified dialogue.\",\n        )\n\n    def test_handle_error(self):\n        \"\"\"Test the _handle_error method of the oef_search handler.\"\"\"\n        # setup\n        oef_search_dialogue = cast(\n            OefSearchDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.oef_search_dialogues,\n                messages=self.list_of_messages_register_location[:1],\n            ),\n        )\n        incoming_message = cast(\n            OefSearchMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=oef_search_dialogue,\n                performative=OefSearchMessage.Performative.OEF_ERROR,\n                oef_error_operation=OefSearchMessage.OefErrorOperation.REGISTER_SERVICE,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received oef_search error message={incoming_message} in dialogue={oef_search_dialogue}.\",\n        )\n\n    def test_handle_success_i(self):\n        \"\"\"Test the _handle_success method of the oef_search handler where the oef success targets register_service WITH location_agent data model description.\"\"\"\n        # setup\n        oef_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_search_dialogues,\n            messages=self.list_of_messages_register_location[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=oef_dialogue,\n            performative=OefSearchMessage.Performative.SUCCESS,\n            agents_info=OefSearchMessage.AgentsInfo({\"address\": {\"key\": \"value\"}}),\n        )\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            with patch.object(\n                self.alice_behaviour,\n                \"register_service\",\n            ) as mock_reg:\n                self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received oef_search success message={incoming_message} in dialogue={oef_dialogue}.\",\n        )\n        mock_reg.assert_called_once()\n\n    def test_handle_success_ii(self):\n        \"\"\"Test the _handle_success method of the oef_search handler where the oef success targets register_service WITH set_service_key data model description.\"\"\"\n        # setup\n        oef_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_search_dialogues,\n            messages=self.list_of_messages_register_service[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=oef_dialogue,\n            performative=OefSearchMessage.Performative.SUCCESS,\n            agents_info=OefSearchMessage.AgentsInfo({\"address\": {\"key\": \"value\"}}),\n        )\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            with patch.object(\n                self.alice_behaviour,\n                \"register_genus\",\n            ) as mock_reg:\n                self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received oef_search success message={incoming_message} in dialogue={oef_dialogue}.\",\n        )\n        mock_reg.assert_called_once()\n\n    def test_handle_success_iii(self):\n        \"\"\"Test the _handle_success method of the oef_search handler where the oef success targets register_service WITH personality_agent data model and genus value description.\"\"\"\n        # setup\n        oef_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_search_dialogues,\n            messages=self.list_of_messages_register_genus[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=oef_dialogue,\n            performative=OefSearchMessage.Performative.SUCCESS,\n            agents_info=OefSearchMessage.AgentsInfo({\"address\": {\"key\": \"value\"}}),\n        )\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            with patch.object(\n                self.alice_behaviour,\n                \"register_classification\",\n            ) as mock_reg:\n                self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received oef_search success message={incoming_message} in dialogue={oef_dialogue}.\",\n        )\n        mock_reg.assert_called_once()\n\n    def test_handle_success_iv(self):\n        \"\"\"Test the _handle_success method of the oef_search handler where the oef success targets register_service WITH personality_agent data model and classification value description.\"\"\"\n        # setup\n        oef_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_search_dialogues,\n            messages=self.list_of_messages_register_classification[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=oef_dialogue,\n            performative=OefSearchMessage.Performative.SUCCESS,\n            agents_info=OefSearchMessage.AgentsInfo({\"address\": {\"key\": \"value\"}}),\n        )\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received oef_search success message={incoming_message} in dialogue={oef_dialogue}.\",\n        )\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            \"the agent, with its genus and classification, and its service are successfully registered on the SOEF.\",\n        )\n\n    def test_handle_success_v(self):\n        \"\"\"Test the _handle_success method of the oef_search handler where the oef success targets unregister_service.\"\"\"\n        # setup\n        oef_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_search_dialogues,\n            messages=self.list_of_messages_register_invalid[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=oef_dialogue,\n            performative=OefSearchMessage.Performative.SUCCESS,\n            agents_info=OefSearchMessage.AgentsInfo({\"address\": {\"key\": \"value\"}}),\n        )\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received oef_search success message={incoming_message} in dialogue={oef_dialogue}.\",\n        )\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"received soef SUCCESS message as a reply to the following unexpected message: {oef_dialogue.get_message_by_id(incoming_message.target)}\",\n        )\n\n    def test_handle_invalid(self):\n        \"\"\"Test the _handle_invalid method of the oef_search handler.\"\"\"\n        # setup\n        incoming_message = cast(\n            OefSearchMessage,\n            self.build_incoming_message(\n                message_type=OefSearchMessage,\n                performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n                service_description=self.mocked_proposal,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"cannot handle oef_search message of performative={incoming_message.performative} in dialogue={self.oef_search_dialogues.get_dialogue(incoming_message)}.\",\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the oef_search handler.\"\"\"\n        assert self.oef_search_handler.teardown() is None\n        self.assert_quantity_in_outbox(0)\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_aries_alice/test_strategy.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the strategy class of the aries_alice skill.\"\"\"\n\nfrom aea.helpers.search.generic import (\n    AGENT_LOCATION_MODEL,\n    AGENT_PERSONALITY_MODEL,\n    AGENT_REMOVE_SERVICE_MODEL,\n    AGENT_SET_SERVICE_MODEL,\n)\nfrom aea.helpers.search.models import Description, Location\n\nfrom tests.test_packages.test_skills.test_aries_alice.intermediate_class import (\n    AriesAliceTestCase,\n)\n\n\nclass TestStrategy(AriesAliceTestCase):\n    \"\"\"Test Strategy of aries_alice.\"\"\"\n\n    def test_properties(self):\n        \"\"\"Test the properties of Strategy class.\"\"\"\n        assert self.strategy.admin_host == self.admin_host\n        assert self.strategy.admin_port == self.admin_port\n        assert self.strategy.admin_url == f\"http://{self.admin_host}:{self.admin_port}\"\n\n    def test_get_location_description(self):\n        \"\"\"Test the get_location_description method of the Strategy class.\"\"\"\n        description = self.strategy.get_location_description()\n\n        assert type(description) == Description\n        assert description.data_model is AGENT_LOCATION_MODEL\n        assert description.values.get(\"location\", \"\") == Location(\n            latitude=self.location[\"latitude\"], longitude=self.location[\"longitude\"]\n        )\n\n    def test_get_register_service_description(self):\n        \"\"\"Test the get_register_service_description method of the Strategy class.\"\"\"\n        description = self.strategy.get_register_service_description()\n\n        assert type(description) == Description\n        assert description.data_model is AGENT_SET_SERVICE_MODEL\n        assert description.values.get(\"key\", \"\") == self.service_data[\"key\"]\n        assert description.values.get(\"value\", \"\") == self.service_data[\"value\"]\n\n    def test_get_register_personality_description(self):\n        \"\"\"Test the get_register_personality_description method of the Strategy class.\"\"\"\n        description = self.strategy.get_register_personality_description()\n\n        assert type(description) == Description\n        assert description.data_model is AGENT_PERSONALITY_MODEL\n        assert description.values.get(\"piece\", \"\") == self.personality_data[\"piece\"]\n        assert description.values.get(\"value\", \"\") == self.personality_data[\"value\"]\n\n    def test_get_register_classification_description(self):\n        \"\"\"Test the get_register_classification_description method of the Strategy class.\"\"\"\n        description = self.strategy.get_register_classification_description()\n\n        assert type(description) == Description\n        assert description.data_model is AGENT_PERSONALITY_MODEL\n        assert description.values.get(\"piece\", \"\") == self.classification[\"piece\"]\n        assert description.values.get(\"value\", \"\") == self.classification[\"value\"]\n\n    def test_get_unregister_service_description(self):\n        \"\"\"Test the get_unregister_service_description method of the Strategy class.\"\"\"\n        description = self.strategy.get_unregister_service_description()\n\n        assert type(description) == Description\n        assert description.data_model is AGENT_REMOVE_SERVICE_MODEL\n        assert description.values.get(\"key\", \"\") == self.service_data[\"key\"]\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_aries_faber/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"The tests module contains the tests of the packages/skills/aries_faber dir.\"\"\"\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_aries_faber/intermediate_class.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module sets up test environment for aries_faber skill.\"\"\"\n\nimport json\nfrom pathlib import Path\nfrom typing import cast\n\nfrom aea.helpers.search.models import (\n    Attribute,\n    Constraint,\n    ConstraintType,\n    DataModel,\n    Description,\n    Query,\n)\nfrom aea.protocols.dialogue.base import DialogueMessage\nfrom aea.test_tools.test_skill import BaseSkillTestCase\n\nfrom packages.fetchai.protocols.http.message import HttpMessage\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.skills.aries_faber.behaviours import FaberBehaviour\nfrom packages.fetchai.skills.aries_faber.dialogues import (\n    DefaultDialogues,\n    HttpDialogues,\n    OefSearchDialogues,\n)\nfrom packages.fetchai.skills.aries_faber.handlers import HttpHandler, OefSearchHandler\nfrom packages.fetchai.skills.aries_faber.strategy import Strategy\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass AriesFaberTestCase(BaseSkillTestCase):\n    \"\"\"Sets the aries_faber class up for testing.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"aries_faber\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        cls.location = {\"longitude\": 0.1270, \"latitude\": 51.5194}\n        cls.search_query = {\n            \"search_key\": \"intro_service\",\n            \"search_value\": \"intro_alice\",\n            \"constraint_type\": \"==\",\n        }\n        cls.search_radius = 5.0\n        cls.admin_host = \"127.0.0.1\"\n        cls.admin_port = 8021\n        cls.ledger_url = \"http://127.0.0.1:9000\"\n        config_overrides = {\n            \"models\": {\n                \"strategy\": {\n                    \"args\": {\n                        \"location\": cls.location,\n                        \"search_query\": cls.search_query,\n                        \"search_radius\": cls.search_radius,\n                        \"admin_host\": cls.admin_host,\n                        \"admin_port\": cls.admin_port,\n                        \"ledger_url\": cls.ledger_url,\n                    }\n                }\n            },\n        }\n\n        super().setup(config_overrides=config_overrides)\n\n        # behaviours\n        cls.faber_behaviour = cast(\n            FaberBehaviour,\n            cls._skill.skill_context.behaviours.faber,\n        )\n\n        # dialogues\n        cls.default_dialogues = cast(\n            DefaultDialogues, cls._skill.skill_context.default_dialogues\n        )\n        cls.http_dialogues = cast(\n            HttpDialogues, cls._skill.skill_context.http_dialogues\n        )\n        cls.oef_search_dialogues = cast(\n            OefSearchDialogues, cls._skill.skill_context.oef_search_dialogues\n        )\n\n        # handlers\n        cls.http_handler = cast(HttpHandler, cls._skill.skill_context.handlers.http)\n        cls.oef_search_handler = cast(\n            OefSearchHandler, cls._skill.skill_context.handlers.oef_search\n        )\n\n        # models\n        cls.strategy = cast(Strategy, cls._skill.skill_context.strategy)\n\n        cls.logger = cls._skill.skill_context.logger\n\n        # mocked objects\n        cls.mocked_method = \"SOME_METHOD\"\n        cls.mocked_url = \"www.some-url.com\"\n        cls.mocked_version = \"some_version\"\n        cls.mocked_headers = \"some_headers\"\n        cls.body_dict = {\"some_key\": \"some_value\"}\n        cls.body_str = \"some_body\"\n        cls.body_bytes = b\"some_body\"\n        cls.mocked_body_bytes = json.dumps(cls.body_str).encode(\"utf-8\")\n        cls.mocked_query = Query(\n            [Constraint(\"some_attribute_name\", ConstraintType(\"==\", \"some_value\"))],\n            DataModel(\n                \"some_data_model_name\",\n                [\n                    Attribute(\n                        \"some_attribute_name\",\n                        str,\n                        False,\n                        \"Some attribute descriptions.\",\n                    )\n                ],\n            ),\n        )\n        cls.mocked_proposal = Description(\n            {\n                \"contract_address\": \"some_contract_address\",\n                \"token_id\": \"123456\",\n                \"trade_nonce\": \"876438756348568\",\n                \"from_supply\": \"543\",\n                \"to_supply\": \"432\",\n                \"value\": \"67\",\n            }\n        )\n\n        # list of messages\n        cls.list_of_http_messages = (\n            DialogueMessage(\n                HttpMessage.Performative.REQUEST,\n                {\n                    \"method\": cls.mocked_method,\n                    \"url\": cls.mocked_url,\n                    \"headers\": cls.mocked_headers,\n                    \"version\": cls.mocked_version,\n                    \"body\": cls.mocked_body_bytes,\n                },\n                is_incoming=False,\n            ),\n        )\n\n        cls.list_of_oef_search_messages = (\n            DialogueMessage(\n                OefSearchMessage.Performative.SEARCH_SERVICES,\n                {\"query\": cls.mocked_query},\n            ),\n        )\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_aries_faber/test_behaviours.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the behaviour classes of the aries_faber skill.\"\"\"\n\nimport json\nimport logging\nfrom unittest.mock import patch\n\nfrom packages.fetchai.protocols.http.message import HttpMessage\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.skills.aries_faber.behaviours import HTTP_CLIENT_PUBLIC_ID\n\nfrom tests.test_packages.test_skills.test_aries_faber.intermediate_class import (\n    AriesFaberTestCase,\n)\n\n\nclass TestFaberBehaviour(AriesFaberTestCase):\n    \"\"\"Test registration behaviour of aries_faber.\"\"\"\n\n    def test_send_http_request_message(self):\n        \"\"\"Test the send_http_request_message method of the faber behaviour.\"\"\"\n        # operation\n        self.faber_behaviour.send_http_request_message(\n            self.mocked_method, self.mocked_url, self.body_dict\n        )\n\n        # after\n        self.assert_quantity_in_outbox(1)\n\n        message = self.get_message_from_outbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=HttpMessage,\n            performative=HttpMessage.Performative.REQUEST,\n            to=str(HTTP_CLIENT_PUBLIC_ID),\n            sender=str(self.skill.skill_context.skill_id),\n            method=self.mocked_method,\n            url=self.mocked_url,\n            headers=\"Content-Type: application/json\",\n            version=\"\",\n            body=json.dumps(self.body_dict).encode(\"utf-8\"),\n        )\n        assert has_attributes, error_str\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the faber behaviour.\"\"\"\n        # operation\n        self.faber_behaviour.setup()\n\n        # after\n        self.assert_quantity_in_outbox(0)\n        assert self.strategy.is_searching is True\n\n    def test_act_is_searching(self):\n        \"\"\"Test the act method of the faber behaviour where is_searching is True.\"\"\"\n        # setup\n        self.strategy._is_searching = True\n\n        # operation\n        with patch.object(\n            self.strategy,\n            \"get_location_and_service_query\",\n            return_value=self.mocked_query,\n        ):\n            with patch.object(self.logger, \"log\") as mock_logger:\n                self.faber_behaviour.act()\n\n        # after\n        self.assert_quantity_in_outbox(1)\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=OefSearchMessage,\n            performative=OefSearchMessage.Performative.SEARCH_SERVICES,\n            to=self.skill.skill_context.search_service_address,\n            sender=str(self.skill.public_id),\n            query=self.mocked_query,\n        )\n        assert has_attributes, error_str\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            \"Searching for Alice on SOEF...\",\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the service_registration behaviour.\"\"\"\n        self.faber_behaviour.teardown()\n        self.assert_quantity_in_outbox(0)\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_aries_faber/test_dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the dialogue classes of the aries_faber skill.\"\"\"\n\nfrom aea.test_tools.test_skill import COUNTERPARTY_AGENT_ADDRESS\n\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.protocols.http.message import HttpMessage\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.skills.aries_faber.dialogues import (\n    DefaultDialogue,\n    HttpDialogue,\n    OefSearchDialogue,\n)\n\nfrom tests.test_packages.test_skills.test_aries_faber.intermediate_class import (\n    AriesFaberTestCase,\n)\n\n\nclass TestDialogues(AriesFaberTestCase):\n    \"\"\"Test dialogue classes of aries_faber.\"\"\"\n\n    def test_default_dialogues(self):\n        \"\"\"Test the DefaultDialogues class.\"\"\"\n        _, dialogue = self.default_dialogues.create(\n            counterparty=COUNTERPARTY_AGENT_ADDRESS,\n            performative=DefaultMessage.Performative.BYTES,\n            content=self.body_bytes,\n        )\n        assert dialogue.role == DefaultDialogue.Role.AGENT\n        assert dialogue.self_address == self.skill.skill_context.agent_address\n\n    def test_http_dialogues(self):\n        \"\"\"Test the HttpDialogues class.\"\"\"\n        _, dialogue = self.http_dialogues.create(\n            counterparty=COUNTERPARTY_AGENT_ADDRESS,\n            performative=HttpMessage.Performative.REQUEST,\n            method=self.mocked_method,\n            url=self.mocked_url,\n            version=self.mocked_version,\n            headers=self.mocked_headers,\n            body=self.mocked_body_bytes,\n        )\n        assert dialogue.role == HttpDialogue.Role.CLIENT\n        assert dialogue.self_address == str(self.skill.skill_context.skill_id)\n\n    def test_oef_search_dialogues(self):\n        \"\"\"Test the OefSearchDialogues class.\"\"\"\n        _, dialogue = self.oef_search_dialogues.create(\n            counterparty=COUNTERPARTY_AGENT_ADDRESS,\n            performative=OefSearchMessage.Performative.SEARCH_SERVICES,\n            query=self.mocked_query,\n        )\n        assert dialogue.role == OefSearchDialogue.Role.AGENT\n        assert dialogue.self_address == str(self.skill.skill_context.skill_id)\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_aries_faber/test_handlers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the handler classes of the aries_faber skill.\"\"\"\nimport json\nimport logging\nfrom typing import cast\nfrom unittest.mock import ANY, patch\n\nimport pytest\n\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.protocols.http.message import HttpMessage\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.skills.aries_faber.dialogues import (\n    HttpDialogue,\n    OefSearchDialogue,\n)\nfrom packages.fetchai.skills.aries_faber.handlers import SUPPORT_REVOCATION\nfrom packages.fetchai.skills.aries_faber.strategy import (\n    ADMIN_COMMAND_CREATE_INVITATION,\n    ADMIN_COMMAND_CREDDEF,\n    ADMIN_COMMAND_REGISTGER_PUBLIC_DID,\n    ADMIN_COMMAND_SCEHMAS,\n    ADMIN_COMMAND_STATUS,\n    FABER_ACA_IDENTITY,\n    LEDGER_COMMAND_REGISTER_DID,\n)\n\nfrom tests.test_packages.test_skills.test_aries_faber.intermediate_class import (\n    AriesFaberTestCase,\n)\n\n\nclass TestHttpHandler(AriesFaberTestCase):\n    \"\"\"Test http handler of aries_faber.\"\"\"\n\n    is_agent_to_agent_messages = False\n\n    def test__init__i(self):\n        \"\"\"Test the __init__ method of the http_request behaviour.\"\"\"\n\n        assert self.http_handler.faber_identity == FABER_ACA_IDENTITY\n\n        assert self.http_handler.did is None\n        assert self.http_handler._schema_id is None\n        assert self.http_handler.credential_definition_id is None\n\n        assert self.http_handler.connections_sent == {}\n        assert self.http_handler.connections_set == {}\n        assert self.http_handler.counterparts_names == {}\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the http_handler handler.\"\"\"\n        assert self.http_handler.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_properties(self):\n        \"\"\"Test the properties of the http_handler handler.\"\"\"\n        self.http_handler._schema_id = None\n        with pytest.raises(ValueError, match=\"schema_id not set\"):\n            assert self.http_handler.schema_id is None\n        self.http_handler._schema_id = \"some_schema_id\"\n        assert self.http_handler.schema_id == \"some_schema_id\"\n\n    def test_handle_unidentified_dialogue(self):\n        \"\"\"Test the handle method of the http handler where incoming message is invalid.\"\"\"\n        # setup\n        incorrect_dialogue_reference = (\"\", \"\")\n        incoming_message = cast(\n            HttpMessage,\n            self.build_incoming_message(\n                message_type=HttpMessage,\n                dialogue_reference=incorrect_dialogue_reference,\n                performative=HttpMessage.Performative.REQUEST,\n                method=self.mocked_method,\n                url=self.mocked_url,\n                headers=self.mocked_headers,\n                version=self.mocked_version,\n                body=self.mocked_body_bytes,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.http_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.ERROR,\n            \"something went wrong when adding the incoming HTTP message to the dialogue.\",\n        )\n\n    def test_handle_request(self):\n        \"\"\"Test the handle method of the http handler where performative is REQUEST.\"\"\"\n        # setup\n        con_id = 123\n        agent_addr = \"agent_addr\"\n        agent_name = \"alice\"\n        self.http_handler.connections_sent = {con_id: agent_addr}\n        self.http_handler.is_connected_to_Faber = False\n\n        body = {\"connection_id\": con_id, \"state\": \"active\", \"their_label\": agent_name}\n        mocked_body_bytes = json.dumps(body).encode(\"utf-8\")\n        incoming_message = cast(\n            HttpMessage,\n            self.build_incoming_message(\n                message_type=HttpMessage,\n                performative=HttpMessage.Performative.REQUEST,\n                method=self.mocked_method,\n                url=self.mocked_url,\n                headers=self.mocked_headers,\n                version=self.mocked_version,\n                body=mocked_body_bytes,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger, patch.object(\n            self.faber_behaviour, \"send_http_request_message\"\n        ) as mock_http_req:\n            self.http_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO, f\"Received webhook message content:{str(body)}\"\n        )\n        mock_logger.assert_any_call(\n            logging.INFO, f\"Connected to {agent_name}({agent_addr})\"\n        )\n        mock_http_req.assert_any_call(\n            method=\"POST\",\n            url=self.strategy.admin_url + \"/issue-credential/send\",\n            content=ANY,\n        )\n        assert self.http_handler.counterparts_names[agent_addr] == agent_name\n        assert self.http_handler.connections_set[con_id] == agent_addr\n\n    def test_handle_response_1(self):\n        \"\"\"Test the handle method of the http handler where performative is RESPONSE and content has version.\"\"\"\n        # setup\n        data = {\n            \"alias\": self.http_handler.faber_identity,\n            \"seed\": self.strategy.seed,\n            \"role\": \"TRUST_ANCHOR\",\n        }\n        http_dialogue = cast(\n            HttpDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.http_dialogues,\n                messages=self.list_of_http_messages[:1],\n            ),\n        )\n\n        body = {\"version\": \"some_version\"}\n        mocked_body_bytes = json.dumps(body).encode(\"utf-8\")\n        incoming_message = cast(\n            HttpMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=http_dialogue,\n                performative=HttpMessage.Performative.RESPONSE,\n                status_code=200,\n                status_text=\"some_status_code\",\n                headers=self.mocked_headers,\n                version=self.mocked_version,\n                body=mocked_body_bytes,\n            ),\n        )\n\n        # operation\n        with patch.object(\n            self.faber_behaviour, \"send_http_request_message\"\n        ) as mock_http_req:\n            with patch.object(self.logger, \"log\") as mock_logger:\n                self.http_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(logging.INFO, f\"Received message: {str(body)}\")\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"Registering Faber_ACA with seed {str(self.strategy.seed)}\",\n        )\n        mock_http_req.assert_any_call(\n            method=\"POST\",\n            url=self.strategy.ledger_url + LEDGER_COMMAND_REGISTER_DID,\n            content=data,\n        )\n\n    def test_handle_response_2(self):\n        \"\"\"Test the handle method of the http handler where performative is RESPONSE and content has did.\"\"\"\n        # setup\n        did = \"some_did\"\n        http_dialogue = cast(\n            HttpDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.http_dialogues,\n                messages=self.list_of_http_messages[:1],\n            ),\n        )\n\n        body = {\"did\": did}\n        mocked_body_bytes = json.dumps(body).encode(\"utf-8\")\n        incoming_message = cast(\n            HttpMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=http_dialogue,\n                performative=HttpMessage.Performative.RESPONSE,\n                status_code=200,\n                status_text=\"some_status_code\",\n                headers=self.mocked_headers,\n                version=self.mocked_version,\n                body=mocked_body_bytes,\n            ),\n        )\n\n        # operation\n        with patch.object(\n            self.faber_behaviour, \"send_http_request_message\"\n        ) as mock_http_req:\n            with patch.object(self.logger, \"log\") as mock_logger:\n                self.http_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(logging.INFO, f\"Received message: {str(body)}\")\n\n        mock_logger.assert_any_call(logging.INFO, f\"Received DID: {did}\")\n\n        mock_http_req.assert_any_call(\n            method=\"POST\",\n            url=self.strategy.admin_url\n            + ADMIN_COMMAND_REGISTGER_PUBLIC_DID\n            + f\"?did={did}\",\n            content=\"\",\n        )\n        assert self.http_handler.did == did\n\n    def test_handle_response_3(self):\n        \"\"\"Test the handle method of the http handler where performative is RESPONSE and content has did.\"\"\"\n        # setup\n        schema_body = {\n            \"schema_name\": \"degree schema\",\n            \"schema_version\": \"0.0.1\",\n            \"attributes\": [\"average\", \"date\", \"degree\", \"name\"],\n        }\n\n        http_dialogue = cast(\n            HttpDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.http_dialogues,\n                messages=self.list_of_http_messages[:1],\n            ),\n        )\n\n        body = {\"result\": {\"posture\": 123}}\n        mocked_body_bytes = json.dumps(body).encode(\"utf-8\")\n        incoming_message = cast(\n            HttpMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=http_dialogue,\n                performative=HttpMessage.Performative.RESPONSE,\n                status_code=200,\n                status_text=\"some_status_code\",\n                headers=self.mocked_headers,\n                version=self.mocked_version,\n                body=mocked_body_bytes,\n            ),\n        )\n\n        # operation\n        with patch.object(\n            self.faber_behaviour, \"send_http_request_message\"\n        ) as mock_http_req:\n            with patch.object(self.logger, \"log\") as mock_logger:\n                self.http_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(logging.INFO, f\"Received message: {str(body)}\")\n\n        mock_logger.assert_any_call(\n            logging.INFO, f\"Registering schema {str(schema_body)}\"\n        )\n        mock_http_req.assert_any_call(\n            method=\"POST\",\n            url=self.strategy.admin_url + ADMIN_COMMAND_SCEHMAS,\n            content=schema_body,\n        )\n\n    def test_handle_response_4(self):\n        \"\"\"Test the handle method of the http handler where performative is RESPONSE and content has schema_id.\"\"\"\n        # setup\n        schema_id = \"some_schema_id\"\n        credential_definition_body = {\n            \"schema_id\": schema_id,\n            \"support_revocation\": SUPPORT_REVOCATION,\n        }\n        http_dialogue = cast(\n            HttpDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.http_dialogues,\n                messages=self.list_of_http_messages[:1],\n            ),\n        )\n\n        body = {\"schema_id\": schema_id}\n        mocked_body_bytes = json.dumps(body).encode(\"utf-8\")\n        incoming_message = cast(\n            HttpMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=http_dialogue,\n                performative=HttpMessage.Performative.RESPONSE,\n                status_code=200,\n                status_text=\"some_status_code\",\n                headers=self.mocked_headers,\n                version=self.mocked_version,\n                body=mocked_body_bytes,\n            ),\n        )\n\n        # operation\n        with patch.object(\n            self.faber_behaviour, \"send_http_request_message\"\n        ) as mock_http_req:\n            with patch.object(self.logger, \"log\") as mock_logger:\n                self.http_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(logging.INFO, f\"Received message: {str(body)}\")\n\n        assert self.http_handler.schema_id == schema_id\n        mock_http_req.assert_any_call(\n            method=\"POST\",\n            url=self.strategy.admin_url + ADMIN_COMMAND_CREDDEF,\n            content=credential_definition_body,\n        )\n\n    def test_handle_response_5(self):\n        \"\"\"Test the handle method of the http handler where performative is RESPONSE and content has credential_definition_id.\"\"\"\n        # setup\n        credential_definition_id = \"some_credential_definition_id\"\n        self.strategy.aea_addresses = [\"some\"]\n        http_dialogue = cast(\n            HttpDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.http_dialogues,\n                messages=self.list_of_http_messages[:1],\n            ),\n        )\n\n        body = {\"credential_definition_id\": credential_definition_id}\n        mocked_body_bytes = json.dumps(body).encode(\"utf-8\")\n        incoming_message = cast(\n            HttpMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=http_dialogue,\n                performative=HttpMessage.Performative.RESPONSE,\n                status_code=200,\n                status_text=\"some_status_code\",\n                headers=self.mocked_headers,\n                version=self.mocked_version,\n                body=mocked_body_bytes,\n            ),\n        )\n\n        # operation\n        with patch.object(\n            self.faber_behaviour, \"send_http_request_message\"\n        ) as mock_http_req:\n            with patch.object(self.logger, \"log\") as mock_logger:\n                self.http_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(logging.INFO, f\"Received message: {str(body)}\")\n\n        assert self.http_handler.credential_definition_id == credential_definition_id\n        mock_http_req.assert_any_call(\n            method=\"POST\", url=self.strategy.admin_url + ADMIN_COMMAND_CREATE_INVITATION\n        )\n\n    def test_handle_response_6(self):\n        \"\"\"Test the handle method of the http handler where performative is RESPONSE and content has connection_id.\"\"\"\n        # setup\n        connection_id = 2342\n        addr = \"someaddr\"\n        self.strategy.aea_addresses = [addr]\n        invitation = {\"some_key\": \"some_value\"}\n        http_dialogue = cast(\n            HttpDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.http_dialogues,\n                messages=self.list_of_http_messages[:1],\n            ),\n        )\n\n        body = {\"connection_id\": connection_id, \"invitation\": invitation}\n        mocked_body_bytes = json.dumps(body).encode(\"utf-8\")\n        incoming_message = cast(\n            HttpMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=http_dialogue,\n                performative=HttpMessage.Performative.RESPONSE,\n                status_code=200,\n                status_text=\"some_status_code\",\n                headers=self.mocked_headers,\n                version=self.mocked_version,\n                body=mocked_body_bytes,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.http_handler.handle(incoming_message)\n\n        # after\n        self.assert_quantity_in_outbox(1)\n\n        mock_logger.assert_any_call(logging.INFO, f\"Received message: {str(body)}\")\n\n        assert connection_id in self.http_handler.connections_sent\n        mock_logger.assert_any_call(logging.INFO, f\"connection: {str(body)}\")\n        mock_logger.assert_any_call(logging.INFO, f\"connection id: {connection_id}\")\n        mock_logger.assert_any_call(logging.INFO, f\"invitation: {str(invitation)}\")\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"Sent invitation to {addr}. Waiting for the invitation from agent someaddr to finalise the connection...\",\n        )\n\n        # _send_default_message\n        message = self.get_message_from_outbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=DefaultMessage,\n            performative=DefaultMessage.Performative.BYTES,\n            to=addr,\n            sender=self.skill.skill_context.agent_address,\n            content=json.dumps(invitation).encode(\"utf-8\"),\n        )\n        assert has_attributes, error_str\n\n    def test_handle_response_7(self):\n        \"\"\"Test the handle method of the http handler where performative is RESPONSE and credentials issued.\"\"\"\n        # setup\n\n        connection_id = 2342\n        addr = \"someaddr\"\n        name = \"bob\"\n        self.strategy.aea_addresses = [addr]\n        self.http_handler.connections_set[connection_id] = addr\n        self.http_handler.counterparts_names[addr] = name\n\n        http_dialogue = cast(\n            HttpDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.http_dialogues,\n                messages=self.list_of_http_messages[:1],\n            ),\n        )\n\n        body = {\n            \"credential_proposal_dict\": {},\n            \"connection_id\": connection_id,\n            \"credential_offer_dict\": {\n                \"credential_preview\": {\n                    \"@type\": \"did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/issue-credential/1.0/credential-preview\",\n                    \"attributes\": [\n                        {\"name\": \"name\", \"value\": \"bob\"},\n                        {\"name\": \"date\", \"value\": \"2022-01-01\"},\n                        {\"name\": \"degree\", \"value\": \"History\"},\n                        {\"name\": \"average\", \"value\": \"4\"},\n                    ],\n                }\n            },\n        }\n        mocked_body_bytes = json.dumps(body).encode(\"utf-8\")\n        incoming_message = cast(\n            HttpMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=http_dialogue,\n                performative=HttpMessage.Performative.RESPONSE,\n                status_code=200,\n                status_text=\"some_status_code\",\n                headers=self.mocked_headers,\n                version=self.mocked_version,\n                body=mocked_body_bytes,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.http_handler.handle(incoming_message)\n\n        mock_logger.assert_any_call(logging.INFO, f\"Received message: {str(body)}\")\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"Credential issued for {name}({addr}): {body['credential_offer_dict']['credential_preview']}\",\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the http handler.\"\"\"\n        assert self.http_handler.teardown() is None\n        self.assert_quantity_in_outbox(0)\n\n\nclass TestOefSearchHandler(AriesFaberTestCase):\n    \"\"\"Test oef_search handler of aries_faber.\"\"\"\n\n    is_agent_to_agent_messages = False\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the oef_search handler.\"\"\"\n        assert self.oef_search_handler.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle_unidentified_dialogue(self):\n        \"\"\"Test the _handle_unidentified_dialogue method of the oef_search handler.\"\"\"\n        # setup\n        incorrect_dialogue_reference = (\"\", \"\")\n        incoming_message = cast(\n            OefSearchMessage,\n            self.build_incoming_message(\n                message_type=OefSearchMessage,\n                dialogue_reference=incorrect_dialogue_reference,\n                performative=OefSearchMessage.Performative.OEF_ERROR,\n                oef_error_operation=OefSearchMessage.OefErrorOperation.REGISTER_SERVICE,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received invalid oef_search message={incoming_message}, unidentified dialogue.\",\n        )\n\n    def test_handle_error(self):\n        \"\"\"Test the _handle_error method of the oef_search handler.\"\"\"\n        # setup\n        oef_search_dialogue = cast(\n            OefSearchDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.oef_search_dialogues,\n                messages=self.list_of_oef_search_messages[:1],\n            ),\n        )\n        incoming_message = cast(\n            OefSearchMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=oef_search_dialogue,\n                performative=OefSearchMessage.Performative.OEF_ERROR,\n                oef_error_operation=OefSearchMessage.OefErrorOperation.REGISTER_SERVICE,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received oef_search error message={incoming_message} in dialogue={oef_search_dialogue}.\",\n        )\n\n    def test_handle_search_i(self):\n        \"\"\"Test the _handle_search method of the oef_search handler where the number of agents found is NOT 0.\"\"\"\n        # setup\n        alice_address = \"alice\"\n        agents = (alice_address, \"bob\")\n        oef_search_dialogue = cast(\n            OefSearchDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.oef_search_dialogues,\n                messages=self.list_of_oef_search_messages[:1],\n            ),\n        )\n        incoming_message = cast(\n            OefSearchMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=oef_search_dialogue,\n                performative=OefSearchMessage.Performative.SEARCH_RESULT,\n                agents=agents,\n                agents_info=OefSearchMessage.AgentsInfo(\n                    {\n                        \"agent_1\": {\"key_1\": \"value_1\", \"key_2\": \"value_2\"},\n                        \"agent_2\": {\"key_3\": \"value_3\", \"key_4\": \"value_4\"},\n                    }\n                ),\n            ),\n        )\n\n        # operation\n        with patch.object(\n            self.faber_behaviour, \"send_http_request_message\"\n        ) as mock_http_req:\n            with patch.object(self.logger, \"log\") as mock_logger:\n                self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"found agents {', '.join(agents)}, stopping search.\",\n        )\n\n        assert self.strategy.is_searching is False\n        assert self.strategy.aea_addresses == list(agents)\n        mock_http_req.assert_any_call(\n            \"GET\", self.strategy.admin_url + ADMIN_COMMAND_STATUS\n        )\n\n    def test_handle_search_ii(self):\n        \"\"\"Test the _handle_search method of the oef_search handler where the number of agents found is 0.\"\"\"\n        # setup\n        agents = tuple()\n        oef_search_dialogue = cast(\n            OefSearchDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.oef_search_dialogues,\n                messages=self.list_of_oef_search_messages[:1],\n            ),\n        )\n        incoming_message = cast(\n            OefSearchMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=oef_search_dialogue,\n                performative=OefSearchMessage.Performative.SEARCH_RESULT,\n                agents=agents,\n                agents_info=OefSearchMessage.AgentsInfo({}),\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            \"Waiting for more agents.\",\n        )\n\n    def test_handle_invalid(self):\n        \"\"\"Test the _handle_invalid method of the oef_search handler.\"\"\"\n        # setup\n        incoming_message = cast(\n            OefSearchMessage,\n            self.build_incoming_message(\n                message_type=OefSearchMessage,\n                performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n                service_description=self.mocked_proposal,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"cannot handle oef_search message of performative={incoming_message.performative} in dialogue={self.oef_search_dialogues.get_dialogue(incoming_message)}.\",\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the oef_search handler.\"\"\"\n        assert self.oef_search_handler.teardown() is None\n        self.assert_quantity_in_outbox(0)\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_aries_faber/test_strategy.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the strategy class of the aries_faber skill.\"\"\"\n\nimport pytest\n\nfrom aea.exceptions import AEAEnforceError\nfrom aea.helpers.search.models import Constraint, ConstraintType, Query\n\nfrom tests.test_packages.test_skills.test_aries_faber.intermediate_class import (\n    AriesFaberTestCase,\n)\n\n\nclass TestStrategy(AriesFaberTestCase):\n    \"\"\"Test Strategy of aries_faber.\"\"\"\n\n    def test_properties(self):\n        \"\"\"Test the properties of Strategy class.\"\"\"\n        assert self.strategy.admin_host == self.admin_host\n        assert self.strategy.admin_port == self.admin_port\n        assert self.strategy.ledger_url == self.ledger_url\n        assert self.strategy.admin_url == f\"http://{self.admin_host}:{self.admin_port}\"\n        assert self.strategy.is_searching is False\n        assert self.strategy.aea_addresses == []\n        self.strategy.aea_addresses = [\"some\"]\n        assert self.strategy.aea_addresses == [\"some\"]\n        with pytest.raises(AEAEnforceError, match=\"Can only set bool on is_searching!\"):\n            self.strategy.is_searching = \"some_value\"\n        self.strategy.is_searching = True\n        assert self.strategy.is_searching is True\n\n    def test_get_location_and_service_query(self):\n        \"\"\"Test the get_location_and_service_query method of the Strategy class.\"\"\"\n        query = self.strategy.get_location_and_service_query()\n\n        assert type(query) == Query\n        assert len(query.constraints) == 2\n        assert query.model is None\n\n        location_constraint = Constraint(\n            \"location\",\n            ConstraintType(\n                \"distance\", (self.strategy._agent_location, self.search_radius)\n            ),\n        )\n        assert query.constraints[0] == location_constraint\n\n        service_key_constraint = Constraint(\n            self.search_query[\"search_key\"],\n            ConstraintType(\n                self.search_query[\"constraint_type\"],\n                self.search_query[\"search_value\"],\n            ),\n        )\n        assert query.constraints[1] == service_key_constraint\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_carpark_detection/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"The tests module contains the tests of the packages/skills/carpark_detection dir.\"\"\"\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_carpark_detection/test_database.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the RegistrationDB class of the carpark detection skill.\"\"\"\nimport os\nimport sqlite3\nfrom pathlib import Path\nfrom unittest.mock import Mock, patch\n\nfrom aea.test_tools.test_skill import BaseSkillTestCase\n\nfrom packages.fetchai.skills.carpark_detection.database import DetectionDatabase\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass TestDetectionDatabase(BaseSkillTestCase):\n    \"\"\"Test DetectionDatabase of carpark detection.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"carpark_detection\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.temp_dir = os.path.join(os.path.dirname(__file__), \"temp_files_placeholder\")\n        cls.create_if_not_present = True\n        cls.logger = None\n        cls.db = DetectionDatabase(\n            temp_dir=cls.temp_dir,\n            create_if_not_present=cls.create_if_not_present,\n            logger=cls.logger,\n        )\n\n    def test__init__i(self):\n        \"\"\"Test the __init__ method of the DetectionDatabase class.\"\"\"\n        # operation\n        with patch.object(self.db, \"initialise_backend\") as mock_initialise_back:\n            self.db.__init__(self.temp_dir, self.create_if_not_present, self.logger)\n\n        mock_initialise_back.assert_called_once()\n\n    def test_is_db_exits_i(self):\n        \"\"\"Test the is_db_exits method of the DetectionDatabase class where db exists.\"\"\"\n        # operation\n        with patch(\"os.path.isfile\", return_value=True) as mock_is_file:\n            with patch.object(\n                self.db, \"get_system_status\", return_value=\"Exists\"\n            ) as mock_status:\n                exists = self.db.is_db_exits()\n\n        # after\n        mock_is_file.assert_any_call(self.db.database_path)\n        mock_status.assert_any_call(\"db\", False)\n\n        assert exists is True\n\n    def test_is_db_exits_ii(self):\n        \"\"\"Test the is_db_exits method of the DetectionDatabase class where db file does NOT exist.\"\"\"\n        # operation\n        with patch(\"os.path.isfile\", return_value=False) as mock_is_file:\n            exists = self.db.is_db_exits()\n\n        # after\n        mock_is_file.assert_any_call(self.db.database_path)\n        assert exists is False\n\n    def test_is_db_exits_iii(self):\n        \"\"\"Test the is_db_exits method of the DetectionDatabase class where db status does NOT contain Exists.\"\"\"\n        # operation\n        with patch(\"os.path.isfile\", return_value=True) as mock_is_file:\n            with patch.object(\n                self.db, \"get_system_status\", return_value=\"Something\"\n            ) as mock_status:\n                exists = self.db.is_db_exits()\n\n        # after\n        mock_is_file.assert_any_call(self.db.database_path)\n        mock_status.assert_any_call(\"db\", False)\n\n        assert exists is False\n\n    def test_initialise_backend_i(self):\n        \"\"\"Test the initialise_backend method of the DetectionDatabase class where db NOT exists.\"\"\"\n        # operation\n        with patch.object(self.db, \"ensure_dirs_exist\") as mock_ensure:\n            with patch.object(self.db, \"execute_single_sql\") as mock_sql:\n                with patch.object(\n                    self.db, \"is_db_exits\", return_value=False\n                ) as mock_exists:\n                    with patch.object(self.db, \"set_system_status\") as mock_status:\n                        self.db.initialise_backend()\n\n        # after\n        mock_ensure.assert_called_once()\n        mock_sql.assert_called()\n        assert mock_sql.call_count == 6\n        mock_exists.assert_called_once()\n        mock_status.assert_called()\n        assert mock_status.call_count == 3\n\n    def test_initialise_backend_ii(self):\n        \"\"\"Test the initialise_backend method of the DetectionDatabase class where db exists.\"\"\"\n        # operation\n        with patch.object(self.db, \"ensure_dirs_exist\") as mock_ensure:\n            with patch.object(self.db, \"execute_single_sql\") as mock_sql:\n                with patch.object(\n                    self.db, \"is_db_exits\", return_value=True\n                ) as mock_exists:\n                    with patch.object(self.db, \"set_system_status\") as mock_status:\n                        self.db.initialise_backend()\n\n        # after\n        mock_ensure.assert_called_once()\n        mock_sql.assert_called()\n        assert mock_sql.call_count == 6\n        mock_exists.assert_called_once()\n        mock_status.assert_called()\n        assert mock_status.call_count == 1\n\n    def test_get_lat_lon_i(self):\n        \"\"\"Test the get_lat_lon method of the DetectionDatabase class where lat and lon are UNKNOWN.\"\"\"\n        # setup\n        lat = 1.2\n        lon = 3\n        expected_lon = 3.0\n\n        # operation\n        with patch.object(\n            self.db, \"get_system_status\", side_effect=[lat, lon]\n        ) as mock_status:\n            actual_lat, actual_lon = self.db.get_lat_lon()\n\n        # after\n        mock_status.assert_called()\n        assert mock_status.call_count == 2\n        assert actual_lat == lat\n        assert actual_lon == expected_lon\n\n    def test_get_lat_lon_ii(self):\n        \"\"\"Test the get_lat_lon method of the DetectionDatabase class where lat and lon are NOT UNKNOWN.\"\"\"\n        # setup\n        lat = \"UNKNOWN\"\n        lon = \"UNKNOWN\"\n\n        # operation\n        with patch.object(\n            self.db, \"get_system_status\", side_effect=[lat, lon]\n        ) as mock_status:\n            actual_lat, actual_lon = self.db.get_lat_lon()\n\n        # after\n        mock_status.assert_called()\n        assert mock_status.call_count == 2\n        assert actual_lat is None\n        assert actual_lon is None\n\n    def test_set_system_status(self):\n        \"\"\"Test the set_system_status method of the DetectionDatabase class.\"\"\"\n        # setup\n        system_name = \"some_system_name\"\n        status = \"some_status\"\n\n        # operation\n        with patch.object(self.db, \"execute_single_sql\") as mock_sql:\n            self.db.set_system_status(system_name, status)\n\n        # after\n        mock_sql.assert_any_call(\n            \"INSERT OR REPLACE INTO status_table(system_name, status) values(?, ?)\",\n            (system_name, status),\n        )\n\n    def test_get_system_status_i(self):\n        \"\"\"Test the get_system_status method of the DetectionDatabase class where result is NOT empty.\"\"\"\n        # setup\n        system_name = \"some_system_name\"\n        print_exceptions = True\n\n        expected_result = 1\n        mocked_result = [[expected_result, 2], [3, 4]]\n\n        # operation\n        with patch.object(\n            self.db, \"execute_single_sql\", return_value=mocked_result\n        ) as mock_sql:\n            actual_result = self.db.get_system_status(system_name, print_exceptions)\n\n        # after\n        mock_sql.assert_any_call(\n            \"SELECT status FROM status_table WHERE system_name=?\",\n            (system_name,),\n            print_exceptions,\n        )\n        assert actual_result == expected_result\n\n    def test_get_system_status_ii(self):\n        \"\"\"Test the get_system_status method of the DetectionDatabase class where result IS empty.\"\"\"\n        # setup\n        system_name = \"some_system_name\"\n        print_exceptions = True\n\n        mocked_result = []\n\n        # operation\n        with patch.object(\n            self.db, \"execute_single_sql\", return_value=mocked_result\n        ) as mock_sql:\n            actual_result = self.db.get_system_status(system_name, print_exceptions)\n\n        # after\n        mock_sql.assert_any_call(\n            \"SELECT status FROM status_table WHERE system_name=?\",\n            (system_name,),\n            print_exceptions,\n        )\n        assert actual_result == \"UNKNOWN\"\n\n    def test_execute_single_sql_i(self):\n        \"\"\"Test the execute_single_sql method of the DBCommunication class where NO exception is thrown.\"\"\"\n        # setup\n        command = \"some_command\"\n        variables = (1, \"2\", 4.3)\n        print_exceptions = True\n        result = [1, 2, 3, 4, 5]\n\n        mocked_conn = Mock(wrap=sqlite3.Connection)\n        mocked_cursor = Mock(wraps=sqlite3.Cursor)\n\n        # operation\n\n        with patch(\"sqlite3.connect\", return_value=mocked_conn) as mock_conn:\n            with patch.object(\n                mocked_conn, \"cursor\", return_value=mocked_cursor\n            ) as mock_curs:\n                with patch.object(mocked_cursor, \"execute\") as mock_exe:\n                    with patch.object(\n                        mocked_cursor, \"fetchall\", return_value=result\n                    ) as mock_fetchall:\n                        with patch.object(mocked_conn, \"commit\") as mock_commit:\n                            with patch.object(mocked_conn, \"close\") as mock_con_close:\n                                actual_result = self.db.execute_single_sql(\n                                    command, variables, print_exceptions\n                                )\n\n        # after\n        mock_conn.assert_called_once()\n        mock_curs.assert_called_once()\n        mock_exe.assert_any_call(\n            command,\n            variables,\n        )\n        mock_fetchall.assert_called_once()\n        mock_commit.assert_called_once()\n        mock_con_close.assert_called_once()\n        assert actual_result == result\n\n    def test_execute_single_sql_ii(self):\n        \"\"\"Test the execute_single_sql method of the DBCommunication class where an exception IS thrown.\"\"\"\n        # setup\n        command = \"some_command\"\n        variables = (1, \"2\", 4.3)\n        print_exceptions = True\n        result = [1, 2, 3, 4, 5]\n        exception_message = \"some_exception_message\"\n\n        mocked_conn = Mock(wrap=sqlite3.Connection)\n        mocked_cursor = Mock(wraps=sqlite3.Cursor)\n\n        # operation\n\n        with patch(\"sqlite3.connect\", return_value=mocked_conn) as mock_conn:\n            with patch.object(\n                mocked_conn, \"cursor\", return_value=mocked_cursor\n            ) as mock_curs:\n                with patch.object(mocked_cursor, \"execute\") as mock_exe:\n                    with patch.object(\n                        mocked_cursor, \"fetchall\", return_value=result\n                    ) as mock_fetchall:\n                        with patch.object(\n                            mocked_conn,\n                            \"commit\",\n                            side_effect=ValueError(exception_message),\n                        ) as mock_commit:\n                            with patch.object(mocked_conn, \"close\") as mock_con_close:\n                                with patch.object(\n                                    self.db.logger, \"warning\"\n                                ) as mock_logger:\n                                    actual_result = self.db.execute_single_sql(\n                                        command, variables, print_exceptions\n                                    )\n\n        # after\n        mock_conn.assert_called_once()\n        mock_curs.assert_called_once()\n        mock_exe.assert_any_call(\n            command,\n            variables,\n        )\n        mock_fetchall.assert_called_once()\n        mock_commit.assert_called_once()\n        mock_logger.assert_any_call(\n            f\"Exception in database: {exception_message}\",\n        )\n        mock_con_close.assert_called_once()\n        assert actual_result == result\n\n    def test_get_latest_detection_data_i(self):\n        \"\"\"Test the get_latest_detection_data method of the DBCommunication class where result is NOT None.\"\"\"\n        # setup\n        max_num_rows = 2\n        command = \"\"\"SELECT * FROM images ORDER BY epoch DESC LIMIT ?\"\"\"\n        result = [[1, 2, 3, 4, 5, 6, 7, 8]]\n        expected_result = [\n            {\n                \"epoch\": result[0][0],\n                \"raw_image_path\": result[0][1],\n                \"processed_image_path\": result[0][2],\n                \"total_count\": result[0][3],\n                \"moving_count\": result[0][4],\n                \"free_spaces\": result[0][5],\n                \"lat\": result[0][6],\n                \"lon\": result[0][7],\n            }\n        ]\n\n        # operation\n        with patch.object(\n            self.db, \"execute_single_sql\", return_value=result\n        ) as mock_exe:\n            actual_result = self.db.get_latest_detection_data(max_num_rows)\n\n        # after\n        mock_exe.assert_any_call(\n            command,\n            (max_num_rows,),\n        )\n        assert actual_result == expected_result\n\n    def test_get_latest_detection_data_ii(self):\n        \"\"\"Test the get_latest_detection_data method of the DBCommunication class where result IS None.\"\"\"\n        # setup\n        max_num_rows = 2\n        command = \"\"\"SELECT * FROM images ORDER BY epoch DESC LIMIT ?\"\"\"\n        result = None\n\n        # operation\n        with patch.object(\n            self.db, \"execute_single_sql\", return_value=result\n        ) as mock_exe:\n            actual_result = self.db.get_latest_detection_data(max_num_rows)\n\n        # after\n        mock_exe.assert_any_call(\n            command,\n            (max_num_rows,),\n        )\n        assert actual_result is None\n\n    def test_ensure_dirs_exist(self):\n        \"\"\"Test the ensure_dirs_exist method of the DetectionDatabase class where db exists.\"\"\"\n        # operation\n        with patch(\"os.path.isdir\", return_value=False) as mock_is_dir:\n            with patch(\"os.mkdir\") as mock_mkdir:\n                self.db.ensure_dirs_exist()\n\n        # after\n        mock_is_dir.assert_any_call(self.db.temp_dir)\n        mock_is_dir.assert_any_call(self.db.raw_image_dir)\n        mock_is_dir.assert_any_call(self.db.processed_image_dir)\n\n        mock_mkdir.assert_any_call(self.db.temp_dir)\n        mock_mkdir.assert_any_call(self.db.raw_image_dir)\n        mock_mkdir.assert_any_call(self.db.processed_image_dir)\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_carpark_detection/test_strategy.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the strategy class of the carpark detection skill.\"\"\"\n\nfrom pathlib import Path\nfrom unittest.mock import patch\n\nimport pytest\n\nfrom aea.exceptions import AEAEnforceError\nfrom aea.test_tools.test_skill import BaseSkillTestCase\n\nfrom packages.fetchai.skills.carpark_detection.strategy import (\n    DEFAULT_DB_IS_REL_TO_CWD,\n    DEFAULT_DB_REL_DIR,\n    Strategy,\n)\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass TestStrategy(BaseSkillTestCase):\n    \"\"\"Test Strategy of carpark detection.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"carpark_detection\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.db_is_rel_to_cwd = DEFAULT_DB_IS_REL_TO_CWD\n        cls.db_rel_dir = DEFAULT_DB_REL_DIR\n\n        cls.strategy = Strategy(\n            db_is_rel_to_cwd=cls.db_is_rel_to_cwd,\n            db_rel_dir=cls.db_rel_dir,\n            name=\"strategy\",\n            skill_context=cls._skill.skill_context,\n        )\n\n    def test__init__i(self):\n        \"\"\"Test the __init__ method of the Strategy class where db_dir does NOT exist.\"\"\"\n        # operation\n        with patch(\"os.path.isdir\", return_value=False):\n            with pytest.raises(ValueError, match=\"Database directory does not exist!\"):\n                Strategy(\n                    db_is_rel_to_cwd=self.db_is_rel_to_cwd,\n                    db_rel_dir=self.db_rel_dir,\n                    name=\"strategy\",\n                    skill_context=self.skill.skill_context,\n                )\n\n    def test__init__ii(self):\n        \"\"\"Test the __init__ method of the Strategy class where db_is_rel_to_cwd is True.\"\"\"\n        # operation\n        with patch(\"os.path.isdir\", return_value=True):\n            with patch.object(self.strategy, \"_update_service_data\") as mock_update:\n                self.strategy.__init__(\n                    db_is_rel_to_cwd=True,\n                    db_rel_dir=self.db_rel_dir,\n                    name=\"strategy\",\n                    skill_context=self.skill.skill_context,\n                )\n\n        mock_update.assert_called_once()\n\n    def test_update_service_data(self):\n        \"\"\"Test the _update_service_data method of the Strategy class.\"\"\"\n        lat = 2\n        lon = 3\n\n        # operation\n        with patch.object(\n            self.strategy.db, \"is_db_exits\", return_value=True\n        ) as mock_db_exists:\n            with patch.object(\n                self.strategy.db, \"get_latest_detection_data\", return_value=[1, 2]\n            ) as mock_latest_detection:\n                with patch.object(\n                    self.strategy.db, \"get_lat_lon\", return_value=(lat, lon)\n                ) as mock_lat_lon:\n                    self.strategy._update_service_data()\n\n        # after\n        mock_db_exists.assert_called_once()\n        mock_latest_detection.assert_any_call(1)\n        mock_lat_lon.assert_called_once()\n        assert self.strategy._service_data == {\n            \"latitude\": lat,\n            \"longitude\": lon,\n        }\n\n    def test_collect_from_data_source_i(self):\n        \"\"\"Test the collect_from_data_source method of the Strategy class where len(data)>0.\"\"\"\n        # setup\n        free_spaces = 24\n        data = [\n            {\n                \"epoch\": \"some_epoch\",\n                \"raw_image_path\": \"some_raw_image_path\",\n                \"processed_image_path\": \"some_processed_image_path\",\n                \"total_count\": \"some_total_count\",\n                \"moving_count\": \"some_moving_count\",\n                \"free_spaces\": free_spaces,\n                \"lat\": \"some_lat\",\n                \"lon\": \"some_lon\",\n            },\n            {\n                \"epoch\": \"some_other_epoch\",\n                \"raw_image_path\": \"some_other_raw_image_path\",\n                \"processed_image_path\": \"some_other_processed_image_path\",\n                \"total_count\": \"some_other_total_count\",\n                \"moving_count\": \"some_other_moving_count\",\n                \"free_spaces\": 10,\n                \"lat\": \"some_other_lat\",\n                \"lon\": \"some_other_lon\",\n            },\n            {\n                \"epoch\": \"some_yet_another_epoch\",\n                \"raw_image_path\": \"some_yet_another_raw_image_path\",\n                \"processed_image_path\": \"some_yet_another_processed_image_path\",\n                \"total_count\": \"some_yet_another_total_count\",\n                \"moving_count\": \"some_yet_another_moving_count\",\n                \"free_spaces\": 2,\n                \"lat\": \"some_yet_another_lat\",\n                \"lon\": \"some_yet_another_lon\",\n            },\n        ]\n        expected_result = {\"free_spaces\": str(free_spaces)}\n\n        # operation\n        with patch.object(\n            self.strategy.db, \"get_latest_detection_data\", return_value=data\n        ) as mock_get_data:\n            result = self.strategy.collect_from_data_source()\n\n        # after\n        mock_get_data.assert_any_call(1)\n        assert result == expected_result\n\n    def test_collect_from_data_source_ii(self):\n        \"\"\"Test the collect_from_data_source method of the Strategy class where len(data)==0.\"\"\"\n        # setup\n        data = []\n\n        # operation\n        with patch.object(\n            self.strategy.db, \"get_latest_detection_data\", return_value=data\n        ) as mock_get_data:\n            with pytest.raises(AEAEnforceError, match=\"Did not find any data.\"):\n                self.strategy.collect_from_data_source()\n\n        # after\n        mock_get_data.assert_any_call(1)\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_confirmation_aw1/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"The tests module contains the tests of the packages/skills/confirmation_aw1 dir.\"\"\"\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_confirmation_aw1/test_behaviours.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the behaviour classes of the confirmation aw1 skill.\"\"\"\n\nimport logging\nfrom pathlib import Path\nfrom typing import Tuple, cast\nfrom unittest.mock import patch\n\nimport pytest\n\nfrom aea.helpers.transaction.base import Terms\nfrom aea.protocols.dialogue.base import DialogueMessage\nfrom aea.test_tools.test_skill import BaseSkillTestCase\n\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\nfrom packages.fetchai.protocols.register.message import RegisterMessage\nfrom packages.fetchai.skills.confirmation_aw1.behaviours import (\n    LEDGER_API_ADDRESS,\n    TransactionBehaviour,\n)\nfrom packages.fetchai.skills.confirmation_aw1.dialogues import (\n    LedgerApiDialogue,\n    LedgerApiDialogues,\n    RegisterDialogue,\n    RegisterDialogues,\n)\nfrom packages.fetchai.skills.confirmation_aw1.strategy import Strategy\n\nfrom tests.conftest import ROOT_DIR\n\n\nFETCHAI = \"fetchai\"\n\n\nclass TestTransactionBehaviour(BaseSkillTestCase):\n    \"\"\"Test transaction behaviour of confirmation aw1.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"confirmation_aw1\")\n    is_agent_to_agent_messages = False\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.transaction_behaviour = cast(\n            TransactionBehaviour, cls._skill.skill_context.behaviours.transaction\n        )\n        cls.strategy = cast(Strategy, cls._skill.skill_context.strategy)\n        cls.logger = cls._skill.skill_context.logger\n\n        cls.register_dialogues = cast(\n            RegisterDialogues, cls._skill.skill_context.register_dialogues\n        )\n        cls.ledger_api_dialogues = cast(\n            LedgerApiDialogues, cls._skill.skill_context.ledger_api_dialogues\n        )\n\n        cls.list_of_registration_messages = (\n            DialogueMessage(\n                RegisterMessage.Performative.REGISTER,\n                {\"info\": {\"some_key\": \"some_value\"}},\n            ),\n        )\n\n    @staticmethod\n    def _check_start_processing_effects(self_, register_dialogue, mock_logger) -> None:\n        \"\"\"Perform checks related to running _start_processing.\"\"\"\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"Processing transaction, {len(self_.transaction_behaviour.waiting)} transactions remaining\",\n        )\n\n        message = self_.get_message_from_outbox()\n        has_attributes, error_str = self_.message_has_attributes(\n            actual_message=message,\n            message_type=LedgerApiMessage,\n            performative=LedgerApiMessage.Performative.GET_RAW_TRANSACTION,\n            to=LEDGER_API_ADDRESS,\n            sender=str(self_.skill.skill_context.skill_id),\n            terms=register_dialogue.terms,\n        )\n        assert has_attributes, error_str\n\n        ledger_api_dialogue = cast(\n            LedgerApiDialogue, self_.ledger_api_dialogues.get_dialogue(message)\n        )\n        assert ledger_api_dialogue.associated_register_dialogue == register_dialogue\n\n        assert self_.transaction_behaviour.processing_time == 0.0\n\n        assert self_.transaction_behaviour.processing == ledger_api_dialogue\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"requesting transfer transaction from ledger api for message={message}...\",\n        )\n\n    @staticmethod\n    def _setup_register_ledger_api_dialogues(\n        self_,\n    ) -> Tuple[LedgerApiDialogue, RegisterDialogue]:\n        \"\"\"Setup register and ledger_api dialogues for some of the following tests.\"\"\"\n        register_dialogue = cast(\n            RegisterDialogue,\n            self_.prepare_skill_dialogue(\n                dialogues=self_.register_dialogues,\n                messages=self_.list_of_registration_messages,\n                is_agent_to_agent_messages=True,\n            ),\n        )\n        register_dialogue.terms = Terms(\n            ledger_id=\"some_ledger_id\",\n            sender_address=\"some_sender_address\",\n            counterparty_address=\"some_counterparty\",\n            amount_by_currency_id={\"1\": -10},\n            quantities_by_good_id={},\n            is_sender_payable_tx_fee=True,\n            nonce=\"some_none\",\n            fee_by_currency_id={\"1\": 100},\n        )\n\n        ledger_api_dialogue = cast(\n            LedgerApiDialogue,\n            self_.prepare_skill_dialogue(\n                dialogues=self_.ledger_api_dialogues,\n                messages=(\n                    DialogueMessage(\n                        LedgerApiMessage.Performative.GET_BALANCE,\n                        {\"ledger_id\": \"some_ledger_id\", \"address\": \"some_address\"},\n                    ),\n                ),\n            ),\n        )\n        ledger_api_dialogue.associated_register_dialogue = register_dialogue\n\n        return ledger_api_dialogue, register_dialogue\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the transaction behaviour.\"\"\"\n        assert self.transaction_behaviour.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_act_i(self):\n        \"\"\"Test the act method of the transaction behaviour where processing IS None and len(self.waiting) is NOT 0.\"\"\"\n        # setup\n        _, register_dialogue = self._setup_register_ledger_api_dialogues(self)\n\n        processing_time = 5.0\n        max_processing = 120\n        self.transaction_behaviour.processing = None\n        self.transaction_behaviour.max_processing = max_processing\n        self.transaction_behaviour.processing_time = processing_time\n        self.transaction_behaviour.waiting = [register_dialogue]\n\n        # before\n        assert self.transaction_behaviour.processing_time == processing_time\n        assert self.transaction_behaviour.processing is None\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.transaction_behaviour.act()\n\n        # after\n        self.assert_quantity_in_outbox(1)\n\n        # _start_processing\n        self._check_start_processing_effects(self, register_dialogue, mock_logger)\n\n    def test_act_ii(self):\n        \"\"\"Test the act method of the transaction behaviour where processing is NOT None and processing_time < max_processing.\"\"\"\n        # setup\n        processing_time = 5.0\n        self.transaction_behaviour.processing = \"some_dialogue\"\n        self.transaction_behaviour.max_processing = 120\n        self.transaction_behaviour.processing_time = processing_time\n\n        # operation\n        self.transaction_behaviour.act()\n\n        # after\n        self.assert_quantity_in_outbox(0)\n        assert (\n            self.transaction_behaviour.processing_time\n            == processing_time + self.transaction_behaviour.tick_interval\n        )\n\n    def test_act_iii(self):\n        \"\"\"Test the act method of the transaction behaviour where processing is NOT None and processing_time > max_processing.\"\"\"\n        # setup\n        (\n            ledger_api_dialogue,\n            register_dialogue,\n        ) = self._setup_register_ledger_api_dialogues(self)\n\n        processing_time = 121.0\n        self.transaction_behaviour.processing = ledger_api_dialogue\n        self.transaction_behaviour.max_processing = 120\n        self.transaction_behaviour.processing_time = processing_time\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.transaction_behaviour.act()\n\n        # after\n        self.assert_quantity_in_outbox(1)\n\n        # _timeout_processing\n        assert ledger_api_dialogue.dialogue_label in self.transaction_behaviour.timedout\n        # below is overridden in _start_processing\n        # assert register_dialogue in self.transaction_behaviour.waiting\n        assert self.transaction_behaviour.processing_time == 0.0\n        # below is overridden in _start_processing\n        # assert self.transaction_behaviour.processing is None\n\n        # _start_processing\n        self._check_start_processing_effects(self, register_dialogue, mock_logger)\n\n    def test_timeout_processing(self):\n        \"\"\"Test the _timeout_processing method of the transaction behaviour where self.processing IS None.\"\"\"\n        # setup\n        self.transaction_behaviour.processing_time = None\n\n        # operation\n        self.transaction_behaviour._timeout_processing()\n\n        # after\n        self.assert_quantity_in_outbox(0)\n\n    def test_act_iv(self):\n        \"\"\"Test the act method of the transaction behaviour where len(waiting) == 0.\"\"\"\n        # setup\n        self.transaction_behaviour.processing = None\n        self.transaction_behaviour.waiting = []\n\n        # operation\n        self.transaction_behaviour.act()\n\n        # after\n        self.assert_quantity_in_outbox(0)\n\n    def test_failed_processing(self):\n        \"\"\"Test the failed_processing method of the transaction behaviour.\"\"\"\n        # setup\n        (\n            ledger_api_dialogue,\n            register_dialogue,\n        ) = self._setup_register_ledger_api_dialogues(self)\n\n        self.transaction_behaviour.timedout.add(ledger_api_dialogue.dialogue_label)\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.transaction_behaviour.failed_processing(ledger_api_dialogue)\n\n        # after\n        self.assert_quantity_in_outbox(0)\n\n        # finish_processing\n        assert self.transaction_behaviour.timedout == set()\n\n        mock_logger.assert_any_call(\n            logging.DEBUG,\n            f\"Timeout dialogue in transaction processing: {ledger_api_dialogue}\",\n        )\n\n        # failed_processing\n        assert register_dialogue in self.transaction_behaviour.waiting\n\n    def test_finish_processing_i(self):\n        \"\"\"Test the finish_processing method of the transaction behaviour where self.processing == ledger_api_dialogue.\"\"\"\n        # setup\n        (\n            ledger_api_dialogue,\n            register_dialogue,\n        ) = self._setup_register_ledger_api_dialogues(self)\n        self.transaction_behaviour.processing = ledger_api_dialogue\n\n        # operation\n        self.transaction_behaviour.failed_processing(ledger_api_dialogue)\n\n        # after\n        assert self.transaction_behaviour.processing_time == 0.0\n        assert self.transaction_behaviour.processing is None\n\n    def test_finish_processing_ii(self):\n        \"\"\"Test the finish_processing method of the transaction behaviour where ledger_api_dialogue's dialogue_label is NOT in self.timedout.\"\"\"\n        # setup\n        (\n            ledger_api_dialogue,\n            register_dialogue,\n        ) = self._setup_register_ledger_api_dialogues(self)\n\n        # operation\n        with pytest.raises(ValueError) as err:\n            self.transaction_behaviour.finish_processing(ledger_api_dialogue)\n\n        # after\n        assert (\n            err.value.args[0]\n            == f\"Non-matching dialogues in transaction behaviour: {self.transaction_behaviour.processing} and {ledger_api_dialogue}\"\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the transaction behaviour.\"\"\"\n        assert self.transaction_behaviour.teardown() is None\n        self.assert_quantity_in_outbox(0)\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_confirmation_aw1/test_dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the dialogue classes of the generic buyer skill.\"\"\"\n\nfrom pathlib import Path\nfrom typing import cast\n\nimport pytest\n\nfrom aea.exceptions import AEAEnforceError\nfrom aea.helpers.transaction.base import Terms\nfrom aea.protocols.dialogue.base import DialogueLabel\nfrom aea.test_tools.test_skill import BaseSkillTestCase, COUNTERPARTY_AGENT_ADDRESS\n\nfrom packages.fetchai.protocols.contract_api.custom_types import Kwargs\nfrom packages.fetchai.protocols.contract_api.message import ContractApiMessage\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\nfrom packages.fetchai.protocols.register.message import RegisterMessage\nfrom packages.fetchai.protocols.signing.message import SigningMessage\nfrom packages.fetchai.skills.confirmation_aw1.dialogues import (\n    ContractApiDialogue,\n    ContractApiDialogues,\n    DefaultDialogue,\n    DefaultDialogues,\n    LedgerApiDialogue,\n    LedgerApiDialogues,\n    RegisterDialogue,\n    RegisterDialogues,\n    SigningDialogue,\n    SigningDialogues,\n)\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass TestDialogues(BaseSkillTestCase):\n    \"\"\"Test dialogue classes of confirmation aw1.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"confirmation_aw1\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.default_dialogues = cast(\n            DefaultDialogues, cls._skill.skill_context.default_dialogues\n        )\n        cls.contract_api_dialogues = cast(\n            ContractApiDialogues, cls._skill.skill_context.contract_api_dialogues\n        )\n        cls.register_dialogues = cast(\n            RegisterDialogues, cls._skill.skill_context.register_dialogues\n        )\n        cls.ledger_api_dialogues = cast(\n            LedgerApiDialogues, cls._skill.skill_context.ledger_api_dialogues\n        )\n        cls.signing_dialogues = cast(\n            SigningDialogues, cls._skill.skill_context.signing_dialogues\n        )\n\n    def test_default_dialogues(self):\n        \"\"\"Test the DefaultDialogues class.\"\"\"\n        _, dialogue = self.default_dialogues.create(\n            counterparty=COUNTERPARTY_AGENT_ADDRESS,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"some_content\",\n        )\n        assert dialogue.role == DefaultDialogue.Role.AGENT\n        assert dialogue.self_address == self.skill.skill_context.agent_address\n\n    def test_register_dialogue(self):\n        \"\"\"Test the RegisterDialogue class.\"\"\"\n        register_dialogue = RegisterDialogue(\n            DialogueLabel(\n                (\"\", \"\"),\n                COUNTERPARTY_AGENT_ADDRESS,\n                self.skill.skill_context.agent_address,\n            ),\n            self.skill.skill_context.agent_address,\n            role=RegisterDialogue.Role.AGENT,\n        )\n\n        # terms\n        with pytest.raises(AEAEnforceError, match=\"Terms not set!\"):\n            assert register_dialogue.terms\n        terms = Terms(\n            \"some_ledger_id\",\n            self.skill.skill_context.agent_address,\n            \"counterprty\",\n            {\"currency_id\": 50},\n            {\"good_id\": -10},\n            \"some_nonce\",\n        )\n        register_dialogue.terms = terms\n        with pytest.raises(AEAEnforceError, match=\"Terms already set!\"):\n            register_dialogue.terms = terms\n        assert register_dialogue.terms == terms\n\n    def test_register_dialogues(self):\n        \"\"\"Test the RegisterDialogues class.\"\"\"\n        _, dialogue = self.register_dialogues.create(\n            counterparty=COUNTERPARTY_AGENT_ADDRESS,\n            performative=RegisterMessage.Performative.REGISTER,\n            info={\"some_key\": \"some_value\"},\n        )\n        assert dialogue.role == RegisterDialogue.Role.AGENT\n        assert dialogue.self_address == self.skill.skill_context.agent_address\n\n    def test_contract_api_dialogue(self):\n        \"\"\"Test the ContractApiDialogue class.\"\"\"\n        contract_api_dialogue = ContractApiDialogue(\n            DialogueLabel(\n                (\"\", \"\"),\n                COUNTERPARTY_AGENT_ADDRESS,\n                self.skill.skill_context.agent_address,\n            ),\n            self.skill.skill_context.agent_address,\n            role=ContractApiDialogue.Role.AGENT,\n        )\n\n        # associated_register_dialogue\n        with pytest.raises(ValueError, match=\"Associated register dialogue not set!\"):\n            assert contract_api_dialogue.associated_register_dialogue\n\n        register_dialogue = RegisterDialogue(\n            DialogueLabel(\n                (\"\", \"\"),\n                COUNTERPARTY_AGENT_ADDRESS,\n                self.skill.skill_context.agent_address,\n            ),\n            self.skill.skill_context.agent_address,\n            role=RegisterDialogue.Role.AGENT,\n        )\n        contract_api_dialogue.associated_register_dialogue = register_dialogue\n        with pytest.raises(\n            AEAEnforceError, match=\"Associated register dialogue already set!\"\n        ):\n            contract_api_dialogue.associated_register_dialogue = register_dialogue\n        assert contract_api_dialogue.associated_register_dialogue == register_dialogue\n\n        # terms\n        with pytest.raises(ValueError, match=\"Terms not set!\"):\n            assert contract_api_dialogue.terms\n        terms = Terms(\n            \"some_ledger_id\",\n            self.skill.skill_context.agent_address,\n            \"counterprty\",\n            {\"currency_id\": 50},\n            {\"good_id\": -10},\n            \"some_nonce\",\n        )\n        contract_api_dialogue.terms = terms\n        with pytest.raises(AEAEnforceError, match=\"Terms already set!\"):\n            contract_api_dialogue.terms = terms\n        assert contract_api_dialogue.terms == terms\n\n    def test_contract_api_dialogues(self):\n        \"\"\"Test the ContractApiDialogues class.\"\"\"\n        _, dialogue = self.contract_api_dialogues.create(\n            counterparty=COUNTERPARTY_AGENT_ADDRESS,\n            performative=ContractApiMessage.Performative.GET_DEPLOY_TRANSACTION,\n            ledger_id=\"some_ledger_id\",\n            contract_id=\"some_contract_id\",\n            callable=\"some_callable\",\n            kwargs=Kwargs({\"some_key\": \"some_value\"}),\n        )\n        assert dialogue.role == ContractApiDialogue.Role.AGENT\n        assert dialogue.self_address == str(self.skill.skill_context.skill_id)\n\n    def test_ledger_api_dialogue(self):\n        \"\"\"Test the LedgerApiDialogue class.\"\"\"\n        ledger_api_dialogue = LedgerApiDialogue(\n            DialogueLabel(\n                (\"\", \"\"),\n                COUNTERPARTY_AGENT_ADDRESS,\n                self.skill.skill_context.agent_address,\n            ),\n            self.skill.skill_context.agent_address,\n            role=LedgerApiDialogue.Role.AGENT,\n        )\n\n        # associated_register_dialogue\n        with pytest.raises(AEAEnforceError, match=\"RegisterDialogue not set!\"):\n            assert ledger_api_dialogue.associated_register_dialogue\n        register_dialogue = RegisterDialogue(\n            DialogueLabel(\n                (\"\", \"\"),\n                COUNTERPARTY_AGENT_ADDRESS,\n                self.skill.skill_context.agent_address,\n            ),\n            self.skill.skill_context.agent_address,\n            role=RegisterDialogue.Role.AGENT,\n        )\n        ledger_api_dialogue.associated_register_dialogue = register_dialogue\n        with pytest.raises(AEAEnforceError, match=\"RegisterDialogue already set!\"):\n            ledger_api_dialogue.associated_register_dialogue = register_dialogue\n        assert ledger_api_dialogue.associated_register_dialogue == register_dialogue\n\n    def test_ledger_api_dialogues(self):\n        \"\"\"Test the LedgerApiDialogues class.\"\"\"\n        _, dialogue = self.ledger_api_dialogues.create(\n            counterparty=COUNTERPARTY_AGENT_ADDRESS,\n            performative=LedgerApiMessage.Performative.GET_BALANCE,\n            ledger_id=\"some_ledger_id\",\n            address=\"some_address\",\n        )\n        assert dialogue.role == LedgerApiDialogue.Role.AGENT\n        assert dialogue.self_address == str(self.skill.skill_context.skill_id)\n\n    def test_signing_dialogue(self):\n        \"\"\"Test the SigningDialogue class.\"\"\"\n        signing_dialogue = SigningDialogue(\n            DialogueLabel(\n                (\"\", \"\"),\n                COUNTERPARTY_AGENT_ADDRESS,\n                self.skill.skill_context.agent_address,\n            ),\n            self.skill.skill_context.agent_address,\n            role=SigningDialogue.Role.SKILL,\n        )\n\n        # associated_ledger_api_dialogue\n        with pytest.raises(AEAEnforceError, match=\"LedgerApiDialogue not set!\"):\n            assert signing_dialogue.associated_ledger_api_dialogue\n        ledger_api_dialogue = LedgerApiDialogue(\n            DialogueLabel(\n                (\"\", \"\"),\n                COUNTERPARTY_AGENT_ADDRESS,\n                self.skill.skill_context.agent_address,\n            ),\n            self.skill.skill_context.agent_address,\n            role=LedgerApiDialogue.Role.AGENT,\n        )\n        signing_dialogue.associated_ledger_api_dialogue = ledger_api_dialogue\n        with pytest.raises(AEAEnforceError, match=\"LedgerApiDialogue already set!\"):\n            signing_dialogue.associated_ledger_api_dialogue = ledger_api_dialogue\n        assert signing_dialogue.associated_ledger_api_dialogue == ledger_api_dialogue\n\n    def test_signing_dialogues(self):\n        \"\"\"Test the SigningDialogues class.\"\"\"\n        _, dialogue = self.signing_dialogues.create(\n            counterparty=COUNTERPARTY_AGENT_ADDRESS,\n            performative=SigningMessage.Performative.SIGN_TRANSACTION,\n            terms=\"some_terms\",\n            raw_transaction=\"some_raw_transaction\",\n        )\n        assert dialogue.role == SigningDialogue.Role.SKILL\n        assert dialogue.self_address == str(self.skill.skill_context.skill_id)\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_confirmation_aw1/test_handlers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the handler classes of the confirmation aw1 skill.\"\"\"\n\nimport logging\nfrom pathlib import Path\nfrom typing import cast\nfrom unittest.mock import PropertyMock, patch\n\nimport pytest\n\nfrom aea.crypto.ledger_apis import LedgerApis\nfrom aea.helpers.transaction.base import (\n    RawTransaction,\n    SignedTransaction,\n    Terms,\n    TransactionDigest,\n    TransactionReceipt,\n)\nfrom aea.protocols.dialogue.base import DialogueMessage\nfrom aea.test_tools.test_skill import BaseSkillTestCase, COUNTERPARTY_AGENT_ADDRESS\n\nfrom packages.fetchai.protocols.contract_api.custom_types import Kwargs, State\nfrom packages.fetchai.protocols.contract_api.message import ContractApiMessage\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\nfrom packages.fetchai.protocols.register.message import RegisterMessage\nfrom packages.fetchai.protocols.signing.message import SigningMessage\nfrom packages.fetchai.skills.confirmation_aw1.behaviours import TransactionBehaviour\nfrom packages.fetchai.skills.confirmation_aw1.dialogues import (\n    ContractApiDialogue,\n    ContractApiDialogues,\n    LedgerApiDialogue,\n    LedgerApiDialogues,\n    RegisterDialogue,\n    RegisterDialogues,\n    SigningDialogue,\n    SigningDialogues,\n)\nfrom packages.fetchai.skills.confirmation_aw1.handlers import (\n    AW1RegistrationHandler,\n    ContractApiHandler,\n    LEDGER_API_ADDRESS,\n    LedgerApiHandler,\n    SigningHandler,\n)\nfrom packages.fetchai.skills.confirmation_aw1.strategy import Strategy\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass TestAW1RegistrationHandler(BaseSkillTestCase):\n    \"\"\"Test registration handler of confirmation aw1.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"confirmation_aw1\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.register_handler = cast(\n            AW1RegistrationHandler, cls._skill.skill_context.handlers.registration\n        )\n        cls.logger = cls._skill.skill_context.logger\n        cls.strategy = cast(Strategy, cls._skill.skill_context.strategy)\n\n        cls.tx_behaviour = cast(\n            TransactionBehaviour, cls._skill.skill_context.behaviours.transaction\n        )\n\n        cls.register_dialogues = cast(\n            RegisterDialogues, cls._skill.skill_context.register_dialogues\n        )\n        cls.contract_api_dialogues = cast(\n            ContractApiDialogues, cls._skill.skill_context.contract_api_dialogues\n        )\n\n        cls.info = {\"ethereum_address\": \"some_ethereum_address\"}\n        cls.kwargs = {\"address\": \"some_ethereum_address\"}\n        cls.terms = Terms(\n            ledger_id=\"some_ledger_id\",\n            sender_address=\"some_sender_address\",\n            counterparty_address=\"some_counterparty\",\n            amount_by_currency_id={\"1\": -10},\n            quantities_by_good_id={},\n            is_sender_payable_tx_fee=True,\n            nonce=\"some_none\",\n            fee_by_currency_id={\"1\": 100},\n        )\n        cls.list_of_registration_messages = (\n            DialogueMessage(RegisterMessage.Performative.REGISTER, {\"info\": cls.info}),\n        )\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the fipa handler.\"\"\"\n        assert self.register_handler.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle_unidentified_dialogue(self):\n        \"\"\"Test the _handle_unidentified_dialogue method of the register handler.\"\"\"\n        # setup\n        incorrect_dialogue_reference = (\"\", \"\")\n        incoming_message = self.build_incoming_message(\n            message_type=RegisterMessage,\n            dialogue_reference=incorrect_dialogue_reference,\n            performative=RegisterMessage.Performative.REGISTER,\n            info=self.info,\n        )\n\n        # operation\n        with patch.object(self.register_handler.context.logger, \"log\") as mock_logger:\n            self.register_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received invalid register_msg message={incoming_message}, unidentified dialogue.\",\n        )\n\n    def test_handle_register_is_valid_i(self):\n        \"\"\"Test the _handle_register method of the register handler where is_valid is True and NOT in developer_only_mode.\"\"\"\n        # setup\n        incoming_message = cast(\n            RegisterMessage,\n            self.build_incoming_message(\n                message_type=RegisterMessage,\n                performative=RegisterMessage.Performative.REGISTER,\n                info=self.info,\n            ),\n        )\n\n        # operation\n        with patch.object(\n            self.strategy,\n            \"valid_registration\",\n            return_value=(True, 0, \"all good!\"),\n        ) as mock_valid:\n            with patch.object(\n                self.strategy, \"lock_registration_temporarily\"\n            ) as mock_lock:\n                with patch.object(\n                    self.strategy, \"get_kwargs\", return_value=self.kwargs\n                ) as mock_kwargs:\n                    with patch.object(\n                        self.strategy, \"get_terms\", return_value=self.terms\n                    ) as mock_terms:\n                        with patch.object(self.logger, \"log\") as mock_logger:\n                            self.register_handler.handle(incoming_message)\n\n        # after\n        self.assert_quantity_in_outbox(1)\n\n        mock_valid.called_once()\n        mock_lock.called_once()\n        mock_kwargs.called_once()\n        mock_terms.called_once()\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"valid registration={incoming_message.info}. Verifying if tokens staked.\",\n        )\n\n        message = self.get_message_from_outbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=ContractApiMessage,\n            performative=ContractApiMessage.Performative.GET_STATE,\n            to=LEDGER_API_ADDRESS,\n            sender=str(self.skill.skill_context.skill_id),\n            contract_id=self.strategy.contract_id,\n            contract_address=self.strategy.contract_address,\n            callable=self.strategy.contract_callable,\n            kwargs=ContractApiMessage.Kwargs(self.kwargs),\n        )\n        assert has_attributes, error_str\n\n        contract_api_dialogue = cast(\n            ContractApiDialogue, self.contract_api_dialogues.get_dialogue(message)\n        )\n        register_dialogue = cast(\n            RegisterDialogue, self.register_dialogues.get_dialogue(incoming_message)\n        )\n\n        assert contract_api_dialogue.terms == self.terms\n        assert contract_api_dialogue.associated_register_dialogue == register_dialogue\n\n    def test_handle_register_is_valid_ii(self):\n        \"\"\"Test the _handle_register method of the register handler where is_valid is True and IN developer_only_mode.\"\"\"\n        # setup\n        self.strategy.developer_handle_only = True\n\n        incoming_message = cast(\n            RegisterMessage,\n            self.build_incoming_message(\n                message_type=RegisterMessage,\n                performative=RegisterMessage.Performative.REGISTER,\n                info=self.info,\n            ),\n        )\n\n        # operation\n        with patch.object(\n            self.strategy,\n            \"valid_registration\",\n            return_value=(True, 0, \"all good!\"),\n        ) as mock_valid:\n            with patch.object(\n                self.strategy, \"lock_registration_temporarily\"\n            ) as mock_lock:\n                with patch.object(\n                    self.strategy, \"get_terms\", return_value=self.terms\n                ) as mock_terms:\n                    with patch.object(\n                        self.strategy, \"finalize_registration\"\n                    ) as mock_finalize:\n                        with patch.object(self.logger, \"log\") as mock_logger:\n                            self.register_handler.handle(incoming_message)\n\n        # after\n        self.assert_quantity_in_outbox(0)\n\n        mock_valid.called_once()\n        mock_lock.called_once()\n        mock_terms.called_once()\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"valid registration={incoming_message.info}. Verifying if tokens staked.\",\n        )\n\n        mock_finalize.assert_called_once()\n        register_dialogue = cast(\n            RegisterDialogue, self.register_dialogues.get_dialogue(incoming_message)\n        )\n        assert register_dialogue.terms == self.terms\n        assert register_dialogue in self.tx_behaviour.waiting\n\n    def test_handle_register_is_not_valid(self):\n        \"\"\"Test the _handle_register method of the register handler where is_valid is False.\"\"\"\n        # setup\n        incoming_message = cast(\n            RegisterMessage,\n            self.build_incoming_message(\n                message_type=RegisterMessage,\n                performative=RegisterMessage.Performative.REGISTER,\n                info=self.info,\n            ),\n        )\n\n        error_code = 1\n        error_msg = \"already registered!\"\n\n        # operation\n        with patch.object(\n            self.strategy,\n            \"valid_registration\",\n            return_value=(False, error_code, error_msg),\n        ) as mock_valid:\n            with patch.object(self.logger, \"log\") as mock_logger:\n                self.register_handler.handle(incoming_message)\n\n        # after\n        self.assert_quantity_in_outbox(1)\n\n        mock_valid.called_once()\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"invalid registration={incoming_message.info}. Rejecting.\",\n        )\n\n        message = self.get_message_from_outbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=RegisterMessage,\n            performative=RegisterMessage.Performative.ERROR,\n            to=incoming_message.sender,\n            sender=self.skill.skill_context.agent_address,\n            error_code=error_code,\n            error_msg=error_msg,\n            info={},\n        )\n        assert has_attributes, error_str\n\n    def test_handle_invalid(self):\n        \"\"\"Test the _handle_invalid method of the fipa handler.\"\"\"\n        # setup\n        register_dialogue = cast(\n            RegisterDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.register_dialogues,\n                messages=self.list_of_registration_messages[:1],\n            ),\n        )\n        incoming_message = cast(\n            RegisterMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=register_dialogue,\n                performative=RegisterMessage.Performative.SUCCESS,\n                info=self.info,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.register_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"cannot handle register_msg message of performative={incoming_message.performative} in dialogue={register_dialogue}.\",\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the fipa handler.\"\"\"\n        assert self.register_handler.teardown() is None\n        self.assert_quantity_in_outbox(0)\n\n\nclass TestContractApiHandler(BaseSkillTestCase):\n    \"\"\"Test contract_api handler of confirmation aw1.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"confirmation_aw1\")\n    is_agent_to_agent_messages = False\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.contract_api_handler = cast(\n            ContractApiHandler, cls._skill.skill_context.handlers.contract_api\n        )\n        cls.tx_behaviour = cast(\n            TransactionBehaviour, cls._skill.skill_context.behaviours.transaction\n        )\n        cls.strategy = cast(Strategy, cls._skill.skill_context.strategy)\n        cls.logger = cls.contract_api_handler.context.logger\n\n        cls.contract_api_dialogues = cast(\n            ContractApiDialogues, cls._skill.skill_context.contract_api_dialogues\n        )\n        cls.register_dialogues = cast(\n            RegisterDialogues, cls._skill.skill_context.register_dialogues\n        )\n\n        cls.ledger_id = \"some_ledger_id\"\n        cls.contract_id = \"some_contract_id\"\n        cls.contract_address = \"some_contract_address,\"\n        cls.callable = \"some_callable\"\n        cls.kwargs = Kwargs({\"some_key\": \"some_value\"})\n\n        cls.state = State(\"some_ledger_id\", {\"some_key\": \"some_value\"})\n\n        cls.list_of_contract_api_messages = (\n            DialogueMessage(\n                ContractApiMessage.Performative.GET_STATE,\n                {\n                    \"ledger_id\": cls.ledger_id,\n                    \"contract_id\": cls.contract_id,\n                    \"contract_address\": cls.contract_address,\n                    \"callable\": cls.callable,\n                    \"kwargs\": cls.kwargs,\n                },\n            ),\n        )\n        cls.info = {\"ethereum_address\": \"some_ethereum_address\"}\n        cls.terms = Terms(\n            ledger_id=\"some_ledger_id\",\n            sender_address=\"some_sender_address\",\n            counterparty_address=\"some_counterparty\",\n            amount_by_currency_id={\"1\": -10},\n            quantities_by_good_id={},\n            is_sender_payable_tx_fee=True,\n            nonce=\"some_none\",\n            fee_by_currency_id={\"1\": 100},\n        )\n        cls.list_of_registration_messages = (\n            DialogueMessage(\n                RegisterMessage.Performative.REGISTER,\n                {\"info\": cls.info},\n                is_incoming=True,\n            ),\n        )\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the contract_api handler.\"\"\"\n        assert self.contract_api_handler.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle_unidentified_dialogue(self):\n        \"\"\"Test the _handle_unidentified_dialogue method of the contract_api handler.\"\"\"\n        # setup\n        incorrect_dialogue_reference = (\"\", \"\")\n        incoming_message = self.build_incoming_message(\n            message_type=ContractApiMessage,\n            dialogue_reference=incorrect_dialogue_reference,\n            performative=ContractApiMessage.Performative.STATE,\n            state=self.state,\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.contract_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received invalid contract_api message={incoming_message}, unidentified dialogue.\",\n        )\n\n    def test_handle_state_staked(\n        self,\n    ):\n        \"\"\"Test the _handle_state method of the contract_api handler where has_staked is True.\"\"\"\n        # setup\n        register_dialogue = cast(\n            RegisterDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.register_dialogues,\n                messages=self.list_of_registration_messages[:1],\n                is_agent_to_agent_messages=True,\n            ),\n        )\n\n        contract_api_dialogue = cast(\n            ContractApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.contract_api_dialogues,\n                messages=self.list_of_contract_api_messages[:1],\n            ),\n        )\n        contract_api_dialogue.associated_register_dialogue = register_dialogue\n        contract_api_dialogue.terms = self.terms\n\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=contract_api_dialogue,\n            performative=ContractApiMessage.Performative.STATE,\n            state=self.state,\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            with patch.object(self.strategy, \"has_staked\", return_value=True):\n                with patch.object(\n                    self.strategy, \"finalize_registration\"\n                ) as mock_finalize:\n                    self.contract_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO, f\"received state message={incoming_message}\"\n        )\n\n        mock_logger.assert_any_call(\n            logging.INFO, \"Has staked! Requesting funds release.\"\n        )\n\n        mock_finalize.assert_called_once()\n\n        assert register_dialogue.terms == contract_api_dialogue.terms\n\n        assert register_dialogue in self.tx_behaviour.waiting\n\n    def test_handle_state_not_staked(\n        self,\n    ):\n        \"\"\"Test the _handle_state method of the contract_api handler where has_staked is False.\"\"\"\n        # setup\n        register_dialogue = cast(\n            RegisterDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.register_dialogues,\n                messages=self.list_of_registration_messages[:1],\n                is_agent_to_agent_messages=True,\n            ),\n        )\n\n        contract_api_dialogue = cast(\n            ContractApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.contract_api_dialogues,\n                messages=self.list_of_contract_api_messages[:1],\n            ),\n        )\n        contract_api_dialogue.associated_register_dialogue = register_dialogue\n        contract_api_dialogue.terms = self.terms\n\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=contract_api_dialogue,\n            performative=ContractApiMessage.Performative.STATE,\n            state=self.state,\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            with patch.object(self.strategy, \"has_staked\", return_value=False):\n                with patch.object(self.strategy, \"unlock_registration\") as mock_unlock:\n                    self.contract_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO, f\"received state message={incoming_message}\"\n        )\n\n        mock_unlock.assert_called_once()\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"invalid registration={cast(RegisterMessage, register_dialogue.last_incoming_message).info}. Rejecting.\",\n        )\n\n        self.assert_quantity_in_outbox(1)\n        message = self.get_message_from_outbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=RegisterMessage,\n            performative=RegisterMessage.Performative.ERROR,\n            to=register_dialogue.dialogue_label.dialogue_opponent_addr,\n            sender=self.skill.skill_context.agent_address,\n            error_code=1,\n            error_msg=\"No funds staked!\",\n            info={},\n        )\n        assert has_attributes, error_str\n\n    def test_handle_state_register_msg_is_none(\n        self,\n    ):\n        \"\"\"Test the _handle_state method of the contract_api handler where register_msg is None.\"\"\"\n        # setup\n        register_dialogue = cast(\n            RegisterDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.register_dialogues,\n                messages=self.list_of_registration_messages[:1],\n                is_agent_to_agent_messages=True,\n            ),\n        )\n        register_dialogue._incoming_messages = []\n\n        contract_api_dialogue = cast(\n            ContractApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.contract_api_dialogues,\n                messages=self.list_of_contract_api_messages[:1],\n            ),\n        )\n        contract_api_dialogue.associated_register_dialogue = register_dialogue\n        contract_api_dialogue.terms = self.terms\n\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=contract_api_dialogue,\n            performative=ContractApiMessage.Performative.STATE,\n            state=self.state,\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            with pytest.raises(ValueError, match=\"Could not retrieve fipa message\"):\n                self.contract_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO, f\"received state message={incoming_message}\"\n        )\n\n    def test_handle_error_i(self):\n        \"\"\"Test the _handle_error method of the contract_api handler.\"\"\"\n        # setup\n        register_dialogue = cast(\n            RegisterDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.register_dialogues,\n                messages=self.list_of_registration_messages[:1],\n                is_agent_to_agent_messages=True,\n            ),\n        )\n\n        contract_api_dialogue = cast(\n            ContractApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.contract_api_dialogues,\n                messages=self.list_of_contract_api_messages[:1],\n            ),\n        )\n        contract_api_dialogue.associated_register_dialogue = register_dialogue\n        contract_api_dialogue.terms = self.terms\n\n        incoming_message = cast(\n            ContractApiMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=contract_api_dialogue,\n                performative=ContractApiMessage.Performative.ERROR,\n                data=b\"some_data\",\n            ),\n        )\n\n        # operation\n        with patch.object(self.strategy, \"unlock_registration\") as mock_unlock:\n            with patch.object(self.logger, \"log\") as mock_logger:\n                self.contract_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received ledger_api error message={incoming_message} in dialogue={contract_api_dialogue}.\",\n        )\n\n        mock_unlock.assert_called_once()\n\n    def test_handle_error_ii(self):\n        \"\"\"Test the _handle_error method of the contract_api handler where register_dialogue's last incoming message is None.\"\"\"\n        # setup\n        register_dialogue = cast(\n            RegisterDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.register_dialogues,\n                messages=self.list_of_registration_messages[:1],\n                is_agent_to_agent_messages=True,\n            ),\n        )\n        register_dialogue._incoming_messages = []\n\n        contract_api_dialogue = cast(\n            ContractApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.contract_api_dialogues,\n                messages=self.list_of_contract_api_messages[:1],\n            ),\n        )\n        contract_api_dialogue.associated_register_dialogue = register_dialogue\n        contract_api_dialogue.terms = self.terms\n\n        incoming_message = cast(\n            ContractApiMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=contract_api_dialogue,\n                performative=ContractApiMessage.Performative.ERROR,\n                data=b\"some_data\",\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            with pytest.raises(ValueError, match=\"Could not retrieve fipa message\"):\n                self.contract_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received ledger_api error message={incoming_message} in dialogue={contract_api_dialogue}.\",\n        )\n\n    def test_handle_invalid(self):\n        \"\"\"Test the _handle_invalid method of the contract_api handler.\"\"\"\n        # setup\n        invalid_performative = ContractApiMessage.Performative.GET_DEPLOY_TRANSACTION\n        incoming_message = self.build_incoming_message(\n            message_type=ContractApiMessage,\n            dialogue_reference=(\"1\", \"\"),\n            performative=invalid_performative,\n            ledger_id=self.ledger_id,\n            contract_id=self.contract_id,\n            callable=self.callable,\n            kwargs=self.kwargs,\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.contract_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"cannot handle contract_api message of performative={invalid_performative} in dialogue={self.contract_api_dialogues.get_dialogue(incoming_message)}.\",\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the contract_api handler.\"\"\"\n        assert self.contract_api_handler.teardown() is None\n        self.assert_quantity_in_outbox(0)\n\n\nclass TestSigningHandler(BaseSkillTestCase):\n    \"\"\"Test signing handler of confirmation aw1.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"confirmation_aw1\")\n    is_agent_to_agent_messages = False\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.signing_handler = cast(\n            SigningHandler, cls._skill.skill_context.handlers.signing\n        )\n        cls.tx_behaviour = cast(\n            TransactionBehaviour, cls._skill.skill_context.behaviours.transaction\n        )\n        cls.strategy = cast(Strategy, cls._skill.skill_context.strategy)\n        cls.logger = cls._skill.skill_context.logger\n\n        cls.register_dialogues = cast(\n            RegisterDialogue, cls._skill.skill_context.register_dialogues\n        )\n        cls.ledger_api_dialogues = cast(\n            LedgerApiDialogues, cls._skill.skill_context.ledger_api_dialogues\n        )\n        cls.signing_dialogues = cast(\n            SigningDialogues, cls._skill.skill_context.signing_dialogues\n        )\n        cls.terms = Terms(\n            \"some_ledger_id\",\n            cls._skill.skill_context.agent_address,\n            \"counterprty\",\n            {\"currency_id\": 50},\n            {\"good_id\": -10},\n            \"some_nonce\",\n        )\n\n        cls.info = {\"ethereum_address\": \"some_ethereum_address\"}\n        cls.list_of_registration_messages = (\n            DialogueMessage(\n                RegisterMessage.Performative.REGISTER,\n                {\"info\": cls.info},\n                is_incoming=True,\n            ),\n        )\n\n        cls.list_of_signing_messages = (\n            DialogueMessage(\n                SigningMessage.Performative.SIGN_TRANSACTION,\n                {\n                    \"terms\": cls.terms,\n                    \"raw_transaction\": SigningMessage.RawTransaction(\n                        \"some_ledger_id\", {\"some_key\": \"some_value\"}\n                    ),\n                },\n            ),\n        )\n\n        cls.list_of_ledger_api_messages = (\n            DialogueMessage(LedgerApiMessage.Performative.GET_RAW_TRANSACTION, {}),\n            DialogueMessage(LedgerApiMessage.Performative.RAW_TRANSACTION, {}),\n            DialogueMessage(LedgerApiMessage.Performative.SEND_SIGNED_TRANSACTION, {}),\n            DialogueMessage(LedgerApiMessage.Performative.TRANSACTION_DIGEST, {}),\n        )\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the signing handler.\"\"\"\n        assert self.signing_handler.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle_unidentified_dialogue(self):\n        \"\"\"Test the _handle_unidentified_dialogue method of the signing handler.\"\"\"\n        # setup\n        incorrect_dialogue_reference = (\"\", \"\")\n        incoming_message = self.build_incoming_message(\n            message_type=SigningMessage,\n            dialogue_reference=incorrect_dialogue_reference,\n            performative=SigningMessage.Performative.ERROR,\n            error_code=SigningMessage.ErrorCode.UNSUCCESSFUL_MESSAGE_SIGNING,\n            to=str(self.skill.skill_context.skill_id),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.signing_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received invalid signing message={incoming_message}, unidentified dialogue.\",\n        )\n\n    def test_handle_signed_transaction_last_ledger_api_message_is_none(\n        self,\n    ):\n        \"\"\"Test the _handle_signed_transaction method of the signing handler.\"\"\"\n        # setup\n        signing_dialogue = cast(\n            SigningDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.signing_dialogues,\n                messages=self.list_of_signing_messages[:1],\n            ),\n        )\n        ledger_api_dialogue = cast(\n            LedgerApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.ledger_api_dialogues,\n                messages=self.list_of_ledger_api_messages[:2],\n            ),\n        )\n        signing_dialogue.associated_ledger_api_dialogue = ledger_api_dialogue\n        signing_dialogue.associated_ledger_api_dialogue._incoming_messages = []\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=signing_dialogue,\n            performative=SigningMessage.Performative.SIGNED_TRANSACTION,\n            signed_transaction=SigningMessage.SignedTransaction(\n                \"some_ledger_id\", {\"some_key\": \"some_value\"}\n            ),\n        )\n\n        # operation\n        with pytest.raises(\n            ValueError, match=\"Could not retrieve last message in ledger api dialogue\"\n        ):\n            with patch.object(self.logger, \"log\") as mock_logger:\n                self.signing_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(logging.INFO, \"transaction signing was successful.\")\n\n    def test_handle_signed_transaction_last_ledger_api_message_is_not_none(\n        self,\n    ):\n        \"\"\"Test the _handle_signed_transaction method of the signing handler where the last ledger_api message is not None.\"\"\"\n        # setup\n        signing_counterparty = self.skill.skill_context.decision_maker_address\n        signing_dialogue = cast(\n            SigningDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.signing_dialogues,\n                messages=self.list_of_signing_messages[:1],\n                counterparty=signing_counterparty,\n            ),\n        )\n        ledger_api_dialogue = cast(\n            LedgerApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.ledger_api_dialogues,\n                messages=self.list_of_ledger_api_messages[:2],\n                counterparty=LEDGER_API_ADDRESS,\n            ),\n        )\n        signing_dialogue.associated_ledger_api_dialogue = ledger_api_dialogue\n        incoming_message = cast(\n            SigningMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=signing_dialogue,\n                performative=SigningMessage.Performative.SIGNED_TRANSACTION,\n                signed_transaction=SigningMessage.SignedTransaction(\n                    \"some_ledger_id\", {\"some_key\": \"some_value\"}\n                ),\n            ),\n        )\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.signing_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(logging.INFO, \"transaction signing was successful.\")\n\n        self.assert_quantity_in_outbox(1)\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=LedgerApiMessage,\n            performative=LedgerApiMessage.Performative.SEND_SIGNED_TRANSACTION,\n            to=LEDGER_API_ADDRESS,\n            sender=str(self.skill.skill_context.skill_id),\n            signed_transaction=incoming_message.signed_transaction,\n        )\n        assert has_attributes, error_str\n\n        mock_logger.assert_any_call(logging.INFO, \"sending transaction to ledger.\")\n\n    def test_handle_error(self):\n        \"\"\"Test the _handle_error method of the signing handler.\"\"\"\n        # setup\n        register_dialogue = cast(\n            RegisterDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.register_dialogues,\n                messages=self.list_of_registration_messages[:1],\n                counterparty=COUNTERPARTY_AGENT_ADDRESS,\n                is_agent_to_agent_messages=True,\n            ),\n        )\n\n        ledger_api_dialogue = cast(\n            LedgerApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.ledger_api_dialogues,\n                messages=self.list_of_ledger_api_messages[:4],\n                counterparty=LEDGER_API_ADDRESS,\n            ),\n        )\n        ledger_api_dialogue.associated_register_dialogue = register_dialogue\n\n        signing_counterparty = self.skill.skill_context.decision_maker_address\n        signing_dialogue = cast(\n            SigningDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.signing_dialogues,\n                messages=self.list_of_signing_messages[:1],\n                counterparty=signing_counterparty,\n            ),\n        )\n        signing_dialogue.associated_ledger_api_dialogue = ledger_api_dialogue\n\n        incoming_message = cast(\n            SigningMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=signing_dialogue,\n                performative=SigningMessage.Performative.ERROR,\n                error_code=SigningMessage.ErrorCode.UNSUCCESSFUL_TRANSACTION_SIGNING,\n            ),\n        )\n\n        # operation\n        with patch.object(self.tx_behaviour, \"failed_processing\"):\n            with patch.object(self.logger, \"log\") as mock_logger:\n                self.signing_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"transaction signing was not successful. Error_code={incoming_message.error_code} in dialogue={signing_dialogue}\",\n        )\n\n        # finish_processing\n        assert self.tx_behaviour.processing_time == 0.0\n        assert self.tx_behaviour.processing is None\n\n    def test_handle_invalid(self):\n        \"\"\"Test the _handle_invalid method of the signing handler.\"\"\"\n        # setup\n        invalid_performative = SigningMessage.Performative.SIGN_TRANSACTION\n        incoming_message = self.build_incoming_message(\n            message_type=SigningMessage,\n            dialogue_reference=(\"1\", \"\"),\n            performative=invalid_performative,\n            terms=self.terms,\n            raw_transaction=SigningMessage.RawTransaction(\n                \"some_ledger_id\", {\"some_key\": \"some_value\"}\n            ),\n            to=str(self.skill.skill_context.skill_id),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.signing_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"cannot handle signing message of performative={invalid_performative} in dialogue={self.signing_dialogues.get_dialogue(incoming_message)}.\",\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the signing handler.\"\"\"\n        assert self.signing_handler.teardown() is None\n        self.assert_quantity_in_outbox(0)\n\n\nclass TestGenericLedgerApiHandler(BaseSkillTestCase):\n    \"\"\"Test ledger_api handler of confirmation aw1.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"confirmation_aw1\")\n    is_agent_to_agent_messages = False\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.ledger_api_handler = cast(\n            LedgerApiHandler, cls._skill.skill_context.handlers.ledger_api\n        )\n        cls.transaction_behaviour = cast(\n            TransactionBehaviour, cls._skill.skill_context.behaviours.transaction\n        )\n        cls.strategy = cast(Strategy, cls._skill.skill_context.strategy)\n        cls.logger = cls._skill.skill_context.logger\n\n        cls.register_dialogues = cast(\n            RegisterDialogue, cls._skill.skill_context.register_dialogues\n        )\n        cls.ledger_api_dialogues = cast(\n            LedgerApiDialogues, cls._skill.skill_context.ledger_api_dialogues\n        )\n        cls.signing_dialogues = cast(\n            SigningDialogues, cls._skill.skill_context.signing_dialogues\n        )\n\n        cls.terms = Terms(\n            \"some_ledger_id\",\n            cls._skill.skill_context.agent_address,\n            \"counterprty\",\n            {\"currency_id\": 50},\n            {\"good_id\": -10},\n            \"some_nonce\",\n        )\n        cls.info = {\"ethereum_address\": \"some_ethereum_address\"}\n        cls.list_of_registration_messages = (\n            DialogueMessage(\n                RegisterMessage.Performative.REGISTER,\n                {\"info\": cls.info},\n                is_incoming=True,\n            ),\n        )\n\n        cls.raw_transaction = RawTransaction(\n            \"some_ledger_id\", {\"some_key\": \"some_value\"}\n        )\n        cls.signed_transaction = SignedTransaction(\n            \"some_ledger_id\", {\"some_key\": \"some_value\"}\n        )\n        cls.transaction_digest = TransactionDigest(\"some_ledger_id\", \"some_body\")\n        cls.transaction_receipt = TransactionReceipt(\n            \"some_ledger_id\",\n            {\"receipt_key\": \"receipt_value\"},\n            {\"transaction_key\": \"transaction_value\"},\n        )\n        cls.list_of_ledger_api_messages = (\n            DialogueMessage(\n                LedgerApiMessage.Performative.GET_RAW_TRANSACTION, {\"terms\": cls.terms}\n            ),\n            DialogueMessage(\n                LedgerApiMessage.Performative.RAW_TRANSACTION,\n                {\"raw_transaction\": cls.raw_transaction},\n            ),\n            DialogueMessage(\n                LedgerApiMessage.Performative.SEND_SIGNED_TRANSACTION,\n                {\"signed_transaction\": cls.signed_transaction},\n            ),\n            DialogueMessage(\n                LedgerApiMessage.Performative.TRANSACTION_DIGEST,\n                {\"transaction_digest\": cls.transaction_digest},\n            ),\n            DialogueMessage(\n                LedgerApiMessage.Performative.GET_TRANSACTION_RECEIPT,\n                {\"transaction_digest\": cls.transaction_digest},\n            ),\n            DialogueMessage(\n                LedgerApiMessage.Performative.TRANSACTION_RECEIPT,\n                {\"transaction_receipt\": cls.transaction_receipt},\n            ),\n        )\n\n        cls.list_of_aws_aeas = [\"awx_aea_1\", \"awx_aea_2\"]\n        cls.developer_handle = \"some_developer_handle\"\n\n    def _check_send_confirmation_details_to_awx_aeas(self, aea, mock_logger):\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"informing awx_aeas={self.list_of_aws_aeas} of registration success of confirmed aea={aea} of developer={self.developer_handle}.\",\n        )\n        for awx_awa in self.list_of_aws_aeas:\n            message = self.get_message_from_outbox()\n            has_attributes, error_str = self.message_has_attributes(\n                actual_message=message,\n                message_type=DefaultMessage,\n                performative=DefaultMessage.Performative.BYTES,\n                to=awx_awa,\n                sender=self.skill.skill_context.agent_address,\n                content=f\"{aea}_{self.developer_handle}\".encode(\"utf-8\"),\n            )\n            assert has_attributes, error_str\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the ledger_api handler.\"\"\"\n        # setup\n        list_of_aea = [\"aea_1\", \"aea_2\"]\n\n        # operation\n        with patch.object(\n            type(self.strategy),\n            \"all_registered_aeas\",\n            new_callable=PropertyMock,\n            return_value=list_of_aea,\n        ):\n            with patch.object(\n                type(self.strategy),\n                \"awx_aeas\",\n                new_callable=PropertyMock,\n                return_value=self.list_of_aws_aeas,\n            ):\n                with patch.object(\n                    self.strategy,\n                    \"get_developer_handle\",\n                    return_value=self.developer_handle,\n                ):\n                    with patch.object(self.logger, \"log\") as mock_logger:\n                        self.ledger_api_handler.setup()\n\n        # after\n        self.assert_quantity_in_outbox(len(self.list_of_aws_aeas) * len(list_of_aea))\n\n        for aea in list_of_aea:\n            self._check_send_confirmation_details_to_awx_aeas(aea, mock_logger)\n\n    def test_handle_unidentified_dialogue(self):\n        \"\"\"Test the _handle_unidentified_dialogue method of the ledger_api handler.\"\"\"\n        # setup\n        incorrect_dialogue_reference = (\"\", \"\")\n        incoming_message = self.build_incoming_message(\n            message_type=LedgerApiMessage,\n            dialogue_reference=incorrect_dialogue_reference,\n            performative=LedgerApiMessage.Performative.ERROR,\n            code=1,\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received invalid ledger_api message={incoming_message}, unidentified dialogue.\",\n        )\n\n    def test_handle_raw_transaction(self):\n        \"\"\"Test the _handle_raw_transaction method of the ledger_api handler.\"\"\"\n        # setup\n        register_dialogue = cast(\n            RegisterDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.register_dialogues,\n                messages=self.list_of_registration_messages[:1],\n                is_agent_to_agent_messages=True,\n            ),\n        )\n        register_dialogue.terms = self.terms\n\n        ledger_api_dialogue = cast(\n            LedgerApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.ledger_api_dialogues,\n                messages=self.list_of_ledger_api_messages[:1],\n                counterparty=LEDGER_API_ADDRESS,\n            ),\n        )\n        ledger_api_dialogue.associated_register_dialogue = register_dialogue\n\n        incoming_message = cast(\n            LedgerApiMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=ledger_api_dialogue,\n                performative=LedgerApiMessage.Performative.RAW_TRANSACTION,\n                raw_transaction=self.raw_transaction,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        self.assert_quantity_in_decision_making_queue(1)\n\n        mock_logger.assert_any_call(\n            logging.INFO, f\"received raw transaction={incoming_message}\"\n        )\n\n        message = self.get_message_from_decision_maker_inbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=SigningMessage,\n            performative=SigningMessage.Performative.SIGN_TRANSACTION,\n            to=self.skill.skill_context.decision_maker_address,\n            sender=str(self.skill.skill_context.skill_id),\n            terms=self.terms,\n        )\n        assert has_attributes, error_str\n\n        signing_dialogue = cast(\n            SigningDialogue, self.signing_dialogues.get_dialogue(message)\n        )\n\n        assert signing_dialogue.associated_ledger_api_dialogue == ledger_api_dialogue\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            \"proposing the transaction to the decision maker. Waiting for confirmation ...\",\n        )\n\n    def test_handle_transaction_digest(self):\n        \"\"\"Test the _handle_transaction_digest method of the ledger_api handler.\"\"\"\n        # setup\n        ledger_api_dialogue = cast(\n            LedgerApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.ledger_api_dialogues,\n                messages=self.list_of_ledger_api_messages[:3],\n                counterparty=LEDGER_API_ADDRESS,\n            ),\n        )\n        incoming_message = cast(\n            LedgerApiMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=ledger_api_dialogue,\n                performative=LedgerApiMessage.Performative.TRANSACTION_DIGEST,\n                transaction_digest=self.transaction_digest,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"transaction was successfully submitted. Transaction digest={incoming_message.transaction_digest}\",\n        )\n\n        self.assert_quantity_in_outbox(1)\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=LedgerApiMessage,\n            performative=LedgerApiMessage.Performative.GET_TRANSACTION_RECEIPT,\n            to=incoming_message.sender,\n            sender=str(self.skill.skill_context.skill_id),\n            transaction_digest=self.transaction_digest,\n        )\n        assert has_attributes, error_str\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            \"checking transaction is settled.\",\n        )\n\n    def test_handle_transaction_receipt_i(self):\n        \"\"\"Test the _handle_transaction_receipt method of the ledger_api handler.\"\"\"\n        # setup\n        register_dialogue = cast(\n            RegisterDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.register_dialogues,\n                messages=self.list_of_registration_messages[:1],\n                is_agent_to_agent_messages=True,\n            ),\n        )\n        register_dialogue.terms = self.terms\n\n        ledger_api_dialogue = cast(\n            LedgerApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.ledger_api_dialogues,\n                messages=self.list_of_ledger_api_messages[:5],\n                counterparty=LEDGER_API_ADDRESS,\n            ),\n        )\n        ledger_api_dialogue.associated_register_dialogue = register_dialogue\n        last_outgoing_message = cast(\n            LedgerApiMessage, ledger_api_dialogue.last_outgoing_message\n        )\n\n        incoming_message = cast(\n            LedgerApiMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=ledger_api_dialogue,\n                performative=LedgerApiMessage.Performative.TRANSACTION_RECEIPT,\n                transaction_receipt=self.transaction_receipt,\n            ),\n        )\n\n        # operation\n        with patch.object(\n            self.transaction_behaviour, \"finish_processing\"\n        ) as mocked_finish:\n            with patch.object(\n                LedgerApis, \"is_transaction_settled\", return_value=True\n            ) as mocked_settled:\n                with patch.object(\n                    type(self.strategy),\n                    \"awx_aeas\",\n                    new_callable=PropertyMock,\n                    return_value=self.list_of_aws_aeas,\n                ):\n                    with patch.object(\n                        self.strategy,\n                        \"get_developer_handle\",\n                        return_value=self.developer_handle,\n                    ):\n                        with patch.object(self.logger, \"log\") as mock_logger:\n                            self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mocked_settled.assert_called_once()\n        mocked_finish.assert_any_call(ledger_api_dialogue)\n\n        self.assert_quantity_in_outbox(3)\n        message = self.get_message_from_outbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=RegisterMessage,\n            performative=RegisterMessage.Performative.SUCCESS,\n            to=COUNTERPARTY_AGENT_ADDRESS,\n            sender=self.skill.skill_context.agent_address,\n            info={\"transaction_digest\": last_outgoing_message.transaction_digest.body},\n        )\n        assert has_attributes, error_str\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"informing counterparty={message.to} of registration success.\",\n        )\n\n        # _send_confirmation_details_to_awx_aeas\n        self._check_send_confirmation_details_to_awx_aeas(message.to, mock_logger)\n\n    def test_handle_transaction_receipt_ii(self):\n        \"\"\"Test the _handle_transaction_receipt method of the ledger_api handler where last register msg is None.\"\"\"\n        # setup\n        register_dialogue = cast(\n            RegisterDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.register_dialogues,\n                messages=self.list_of_registration_messages[:1],\n                is_agent_to_agent_messages=True,\n            ),\n        )\n        register_dialogue.terms = self.terms\n        register_dialogue._incoming_messages = []\n\n        ledger_api_dialogue = cast(\n            LedgerApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.ledger_api_dialogues,\n                messages=self.list_of_ledger_api_messages[:5],\n                counterparty=LEDGER_API_ADDRESS,\n            ),\n        )\n        ledger_api_dialogue.associated_register_dialogue = register_dialogue\n\n        incoming_message = cast(\n            LedgerApiMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=ledger_api_dialogue,\n                performative=LedgerApiMessage.Performative.TRANSACTION_RECEIPT,\n                transaction_receipt=self.transaction_receipt,\n            ),\n        )\n\n        # operation\n        with patch.object(\n            self.transaction_behaviour, \"finish_processing\"\n        ) as mocked_finish:\n            with patch.object(\n                LedgerApis, \"is_transaction_settled\", return_value=True\n            ) as mocked_settled:\n                with pytest.raises(\n                    ValueError, match=\"Could not retrieve last register message\"\n                ):\n                    self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mocked_settled.assert_called_once()\n        mocked_finish.assert_any_call(ledger_api_dialogue)\n\n    def test_handle_transaction_receipt_iii(self):\n        \"\"\"Test the _handle_transaction_receipt method of the ledger_api handler where tx is NOT settled.\"\"\"\n        # setup\n        register_dialogue = cast(\n            RegisterDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.register_dialogues,\n                messages=self.list_of_registration_messages[:1],\n                is_agent_to_agent_messages=True,\n            ),\n        )\n        register_dialogue.terms = self.terms\n\n        ledger_api_dialogue = cast(\n            LedgerApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.ledger_api_dialogues,\n                messages=self.list_of_ledger_api_messages[:5],\n                counterparty=LEDGER_API_ADDRESS,\n            ),\n        )\n        ledger_api_dialogue.associated_register_dialogue = register_dialogue\n\n        incoming_message = cast(\n            LedgerApiMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=ledger_api_dialogue,\n                performative=LedgerApiMessage.Performative.TRANSACTION_RECEIPT,\n                transaction_receipt=self.transaction_receipt,\n            ),\n        )\n\n        # operation\n        with patch.object(\n            self.transaction_behaviour, \"failed_processing\"\n        ) as mocked_failed:\n            with patch.object(\n                LedgerApis, \"is_transaction_settled\", return_value=False\n            ) as mocked_settled:\n                with patch.object(self.logger, \"log\") as mock_logger:\n                    self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mocked_settled.assert_called_once()\n        mocked_failed.assert_any_call(ledger_api_dialogue)\n\n        self.assert_quantity_in_outbox(0)\n        assert self.transaction_behaviour.processing is None\n        assert self.transaction_behaviour.processing_time == 0.0\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"transaction_receipt={self.transaction_receipt} not settled or not valid, aborting\",\n        )\n\n    def test_handle_error(self):\n        \"\"\"Test the _handle_error method of the ledger_api handler.\"\"\"\n        # setup\n        ledger_api_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.ledger_api_dialogues,\n            messages=self.list_of_ledger_api_messages[:1],\n        )\n        incoming_message = cast(\n            LedgerApiMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=ledger_api_dialogue,\n                performative=LedgerApiMessage.Performative.ERROR,\n                code=1,\n            ),\n        )\n\n        # operation\n        with patch.object(\n            self.transaction_behaviour, \"failed_processing\"\n        ) as mocked_failed:\n            with patch.object(self.logger, \"log\") as mock_logger:\n                self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mocked_failed.assert_called_once()\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received ledger_api error message={incoming_message} in dialogue={ledger_api_dialogue}.\",\n        )\n\n    def test_handle_invalid(self):\n        \"\"\"Test the _handle_invalid method of the ledger_api handler.\"\"\"\n        # setup\n        invalid_performative = LedgerApiMessage.Performative.GET_BALANCE\n        incoming_message = self.build_incoming_message(\n            message_type=LedgerApiMessage,\n            dialogue_reference=(\"1\", \"\"),\n            performative=invalid_performative,\n            ledger_id=\"some_ledger_id\",\n            address=\"some_address\",\n            to=str(self.skill.skill_context.skill_id),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"cannot handle ledger_api message of performative={invalid_performative} in dialogue={self.ledger_api_dialogues.get_dialogue(incoming_message)}.\",\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the ledger_api handler.\"\"\"\n        assert self.ledger_api_handler.teardown() is None\n        self.assert_quantity_in_outbox(0)\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_confirmation_aw1/test_registration_db.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the RegistrationDB class of the confirmation aw1 skill.\"\"\"\n\nfrom pathlib import Path\nfrom unittest.mock import patch\n\nimport pytest\n\nfrom aea.test_tools.test_skill import BaseSkillTestCase\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass TestStrategy(BaseSkillTestCase):\n    \"\"\"Test RegistrationDB of confirmation aw1.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"confirmation_aw1\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.custom_path = None\n        cls.db = cls._skill.skill_context.registration_db\n        cls.address = \"some_address\"\n\n    def test__initialise_backend(self):\n        \"\"\"Test the _initialise_backend method of the RegistrationDB class.\"\"\"\n        # operation\n        with patch(\"os.path.isfile\", return_value=False) as mock_is_file:\n            with patch.object(self.db, \"_execute_single_sql\") as mock_exe:\n                self.db._initialise_backend()\n\n        # after\n        mock_is_file.assert_called_once()\n        mock_exe.assert_any_call(\n            \"CREATE TABLE IF NOT EXISTS registered_table (address TEXT, ethereum_address TEXT, \"\n            \"ethereum_signature TEXT, fetchai_signature TEXT, \"\n            \"developer_handle TEXT, tweet TEXT)\"\n        )\n\n    def test_set_registered(self):\n        \"\"\"Test the set_registered method of the RegistrationDB class.\"\"\"\n        # setup\n        ethereum_address = \"some_ethereum_address\"\n        ethereum_signature = \"some_ethereum_signature\"\n        fetchai_signature = \"some_fetchai_signature\"\n        developer_handle = \"some_developer_handle\"\n        tweet = \"some_tweet\"\n\n        # operation\n        with patch.object(self.db, \"_execute_single_sql\") as mock_exe:\n            self.db.set_registered(\n                self.address,\n                ethereum_address,\n                ethereum_signature,\n                fetchai_signature,\n                developer_handle,\n                tweet,\n            )\n\n        # after\n        mock_exe.assert_any_call(\n            \"INSERT OR REPLACE INTO registered_table(address, ethereum_address, ethereum_signature, fetchai_signature, developer_handle, tweet) values(?, ?, ?, ?, ?, ?)\",\n            (\n                self.address,\n                ethereum_address,\n                ethereum_signature,\n                fetchai_signature,\n                developer_handle,\n                tweet,\n            ),\n        )\n\n    def test_set_registered_developer_only(self):\n        \"\"\"Test the set_registered_developer_only method of the RegistrationDB class.\"\"\"\n        # setup\n        developer_handle = \"some_developer_handle\"\n\n        # operation\n        with patch.object(self.db, \"_execute_single_sql\") as mock_exe:\n            self.db.set_registered_developer_only(\n                self.address,\n                developer_handle,\n            )\n\n        # after\n        mock_exe.assert_any_call(\n            \"INSERT OR REPLACE INTO registered_table(address, developer_handle) values(?, ?)\",\n            (\n                self.address,\n                developer_handle,\n            ),\n        )\n\n    def test_is_registered_i(self):\n        \"\"\"Test the is_registered method of the RegistrationDB class where result is NOT empty.\"\"\"\n        # setup\n        result = [[\"1\"], [\"2\", \"3\"]]\n\n        # operation\n        with patch.object(\n            self.db, \"_execute_single_sql\", return_value=result\n        ) as mock_exe:\n            is_registered = self.db.is_registered(self.address)\n\n        # after\n        mock_exe.assert_any_call(\n            \"SELECT * FROM registered_table WHERE address=?\", (self.address,)\n        )\n        assert is_registered\n\n    def test_is_registered_ii(self):\n        \"\"\"Test the is_registered method of the RegistrationDB class where result is empty.\"\"\"\n        # setup\n        result = []\n\n        # operation\n        with patch.object(\n            self.db, \"_execute_single_sql\", return_value=result\n        ) as mock_exe:\n            is_registered = self.db.is_registered(self.address)\n\n        # after\n        mock_exe.assert_any_call(\n            \"SELECT * FROM registered_table WHERE address=?\", (self.address,)\n        )\n        assert not is_registered\n\n    def test_get_developer_handle_i(self):\n        \"\"\"Test the get_developer_handle method of the RegistrationDB class where there is 1 developer handle in the result.\"\"\"\n        # setup\n        developer_handle = \"developer_handle_1\"\n        result = [[developer_handle], [\"developer_handle_1\"]]\n\n        # operation\n        with patch.object(\n            self.db, \"_execute_single_sql\", return_value=result\n        ) as mock_exe:\n            actual_developer_handle = self.db.get_developer_handle(self.address)\n\n        # after\n        mock_exe.assert_any_call(\n            \"SELECT developer_handle FROM registered_table WHERE address=?\",\n            (self.address,),\n        )\n        assert actual_developer_handle == developer_handle\n\n    def test_get_developer_handle_ii(self):\n        \"\"\"Test the get_developer_handle method of the RegistrationDB class where there is more than 1 developer handle in the result.\"\"\"\n        # setup\n        developer_handle = \"developer_handle_1\"\n        another_developer_handle = \"developer_handle_2\"\n        result = [[developer_handle, another_developer_handle], [\"developer_handle_1\"]]\n\n        # operation\n        with patch.object(\n            self.db, \"_execute_single_sql\", return_value=result\n        ) as mock_exe:\n            with pytest.raises(\n                ValueError,\n                match=f\"More than one developer_handle found for address={self.address}.\",\n            ):\n                self.db.get_developer_handle(self.address)\n\n        # after\n        mock_exe.assert_any_call(\n            \"SELECT developer_handle FROM registered_table WHERE address=?\",\n            (self.address,),\n        )\n\n    def test_get_all_registered(self):\n        \"\"\"Test the get_all_registered method of the RegistrationDB class.\"\"\"\n        # setup\n        result = [[\"1\", \"2\", \"3\"], [\"4\", \"5\", \"6\"]]\n        expected_registered = [\"1\", \"4\"]\n\n        # operation\n        with patch.object(\n            self.db, \"_execute_single_sql\", return_value=result\n        ) as mock_exe:\n            actual_registered = self.db.get_all_registered()\n\n        # after\n        mock_exe.assert_any_call(\"SELECT address FROM registered_table\", ())\n        assert expected_registered == actual_registered\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_confirmation_aw1/test_strategy.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the strategy class of the confirmation aw1 skill.\"\"\"\n\nimport logging\nfrom pathlib import Path\nfrom typing import cast\nfrom unittest.mock import patch\n\nfrom aea.crypto.ledger_apis import LedgerApis\nfrom aea.helpers.transaction.base import Terms\nfrom aea.test_tools.test_skill import BaseSkillTestCase\n\nfrom packages.fetchai.skills.confirmation_aw1.registration_db import RegistrationDB\nfrom packages.fetchai.skills.confirmation_aw1.strategy import (\n    DEVELOPER_ONLY_REQUIRED_KEYS,\n    PUBLIC_ID,\n    REQUIRED_KEYS,\n    Strategy,\n)\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass TestStrategy(BaseSkillTestCase):\n    \"\"\"Test Strategy of confirmation aw1.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"confirmation_aw1\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.token_denomination = \"atestfet\"  # nosec\n        cls.token_dispense_amount = 100000\n        cls.fetchai_staking_contract_address = (\n            \"0x351bac612b50e87b46e4b10a282f632d41397de2\"\n        )\n        cls.override_staking_check = False\n        cls.awx_aeas = []\n        cls.strategy = Strategy(\n            token_denomination=cls.token_denomination,\n            token_dispense_amount=cls.token_dispense_amount,\n            fetchai_staking_contract_address=cls.fetchai_staking_contract_address,\n            override_staking_check=cls.override_staking_check,\n            awx_aeas=cls.awx_aeas,\n            name=\"strategy\",\n            skill_context=cls._skill.skill_context,\n        )\n\n        cls.address = \"some_address\"\n        cls.info = {\n            \"ethereum_address\": \"some_value\",\n            \"signature_of_ethereum_address\": \"some_signature_of_ethereum_address\",\n            \"signature_of_fetchai_address\": \"some_signature_of_fetchai_address\",\n            \"developer_handle\": \"some_developer_handle\",\n            \"tweet\": \"some_tweet\",\n        }\n        cls.logger = cls._skill.skill_context.logger\n        cls.db = cast(RegistrationDB, cls._skill.skill_context.registration_db)\n\n    def test__init__(self):\n        \"\"\"Test the __init__ of Strategy class.\"\"\"\n        assert self.strategy._is_ready_to_register is False\n        assert self.strategy._is_registered is False\n        assert self.strategy.is_registration_pending is False\n        assert self.strategy.signature_of_ethereum_address is None\n        assert self.strategy._ledger_id == self.skill.skill_context.default_ledger_id\n        assert self.strategy._max_tx_fee == 100\n        assert self.strategy._contract_ledger_id == \"ethereum\"\n        assert self.strategy._contract_callable == \"get_stake\"\n        assert self.strategy._contract_id == str(PUBLIC_ID)\n        assert self.strategy._in_process_registrations == {}\n\n    def test_properties(self):\n        \"\"\"Test the properties of Strategy class.\"\"\"\n        assert self.strategy.contract_id == self.strategy._contract_id\n        assert self.strategy.contract_address == self.fetchai_staking_contract_address\n        assert self.strategy.contract_ledger_id == self.strategy._contract_ledger_id\n        assert self.strategy.contract_callable == self.strategy._contract_callable\n        assert self.strategy.awx_aeas == self.awx_aeas\n        assert self.strategy.all_registered_aeas == []\n\n    def test_lock_registration_temporarily(self):\n        \"\"\"Test the lock_registration_temporarily method of the Strategy class.\"\"\"\n        # before\n        assert self.address not in self.strategy._in_process_registrations\n\n        # operation\n        self.strategy.lock_registration_temporarily(self.address, self.info)\n\n        # after\n        assert self.strategy._in_process_registrations[self.address] == self.info\n\n    def test_finalize_registration_i(self):\n        \"\"\"Test the finalize_registration method of the Strategy class where NOT developer_only_mode.\"\"\"\n        # setup\n        self.strategy.developer_handle_only = False\n        self.strategy.lock_registration_temporarily(self.address, self.info)\n\n        # operation\n        with patch.object(self.db, \"set_registered\") as mock_set:\n            with patch.object(self.logger, \"log\") as mock_logger:\n                self.strategy.finalize_registration(self.address)\n\n        # after\n        assert self.address not in self.strategy._in_process_registrations\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"finalizing registration for address={self.address}, info={self.info}\",\n        )\n\n        mock_set.assert_any_call(\n            address=self.address,\n            ethereum_address=self.info[\"ethereum_address\"],\n            ethereum_signature=self.info[\"signature_of_ethereum_address\"],\n            fetchai_signature=self.info[\"signature_of_fetchai_address\"],\n            developer_handle=self.info[\"developer_handle\"],\n            tweet=self.info.get(\"tweet\", \"\"),\n        )\n\n    def test_finalize_registration_ii(self):\n        \"\"\"Test the finalize_registration method of the Strategy class where IS developer_only_mode.\"\"\"\n        # setup\n        self.strategy.developer_handle_only = True\n        self.strategy.lock_registration_temporarily(self.address, self.info)\n\n        # operation\n        with patch.object(self.db, \"set_registered_developer_only\") as mock_set:\n            with patch.object(self.logger, \"log\") as mock_logger:\n                self.strategy.finalize_registration(self.address)\n\n        # after\n        assert self.address not in self.strategy._in_process_registrations\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"finalizing registration for address={self.address}, info={self.info}\",\n        )\n\n        mock_set.assert_any_call(\n            address=self.address,\n            developer_handle=self.info[\"developer_handle\"],\n        )\n\n    def test_unlock_registration(self):\n        \"\"\"Test the unlock_registration method of the Strategy class.\"\"\"\n        # setup\n        self.strategy.lock_registration_temporarily(self.address, self.info)\n\n        # before\n        assert self.address in self.strategy._in_process_registrations\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.strategy.unlock_registration(self.address)\n\n        # after\n        assert self.address not in self.strategy._in_process_registrations\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"registration info did not pass staking checks = {self.info}\",\n        )\n\n    def test_get_developer_handle(self):\n        \"\"\"Test the get_developer_handle method of the Strategy class.\"\"\"\n        # operation\n        with patch.object(self.db, \"get_developer_handle\") as mock_get:\n            self.strategy.get_developer_handle(self.address)\n\n        # after\n        mock_get.assert_any_call(self.address)\n\n    def test_valid_registration_succeeds(self):\n        \"\"\"Test the valid_registration method of the Strategy class which succeeds.\"\"\"\n        # setup\n        registration_info = {\n            \"ethereum_address\": \"some_ethereum_address\",\n            \"fetchai_address\": self.address,\n            \"signature_of_ethereum_address\": \"some_signature_of_ethereum_address\",\n            \"signature_of_fetchai_address\": \"some_signature_of_fetchai_address\",\n            \"developer_handle\": \"some_developer_handle\",\n        }\n\n        # operation\n        with patch.object(\n            self.strategy, \"_valid_signature\", return_value=True\n        ) as mock_valid:\n            with patch.object(self.db, \"is_registered\", return_value=False) as mock_is:\n                is_valid, code, msg = self.strategy.valid_registration(\n                    registration_info, self.address\n                )\n\n        # after\n        mock_is.assert_called_once()\n        mock_valid.assert_called()\n\n        assert is_valid\n        assert code == 0\n        assert msg == \"all good!\"\n\n    def test_valid_registration_fails_i(self):\n        \"\"\"Test the valid_registration method of the Strategy class which fails because some key is missing.\"\"\"\n        # setup\n        incorrect_registration_info = {\n            \"ethereum_address\": \"some_ethereum_address\",\n            \"fetchai_address\": self.address,\n            \"signature_of_ethereum_address\": \"some_signature_of_ethereum_address\",\n            \"signature_of_fetchai_address\": \"some_signature_of_fetchai_address\",\n        }\n\n        # operation\n        is_valid, code, msg = self.strategy.valid_registration(\n            incorrect_registration_info, self.address\n        )\n\n        # after\n        assert not is_valid\n        assert code == 1\n        assert msg == f\"missing keys in registration info, required: {REQUIRED_KEYS}!\"\n\n    def test_valid_registration_fails_ii(self):\n        \"\"\"Test the valid_registration method of the Strategy class which fails because addresses do not match.\"\"\"\n        # setup\n        different_addres = \"some_other_address\"\n        incorrect_registration_info = {\n            \"ethereum_address\": \"some_ethereum_address\",\n            \"fetchai_address\": different_addres,\n            \"signature_of_ethereum_address\": \"some_signature_of_ethereum_address\",\n            \"signature_of_fetchai_address\": \"some_signature_of_fetchai_address\",\n            \"developer_handle\": \"some_developer_handle\",\n        }\n\n        # operation\n        is_valid, code, msg = self.strategy.valid_registration(\n            incorrect_registration_info, self.address\n        )\n\n        # after\n        assert not is_valid\n        assert code == 1\n        assert msg == \"fetchai address of agent and registration info do not match!\"\n\n    def test_valid_registration_fails_iii(self):\n        \"\"\"Test the valid_registration method of the Strategy class which fails because _valid_signature returns False for first call.\"\"\"\n        # setup\n        incorrect_registration_info = {\n            \"ethereum_address\": \"some_ethereum_address\",\n            \"fetchai_address\": self.address,\n            \"signature_of_ethereum_address\": \"some_signature_of_ethereum_address\",\n            \"signature_of_fetchai_address\": \"some_signature_of_fetchai_address\",\n            \"developer_handle\": \"some_developer_handle\",\n        }\n\n        # operation\n        with patch.object(\n            self.strategy, \"_valid_signature\", return_value=False\n        ) as mock_valid:\n            is_valid, code, msg = self.strategy.valid_registration(\n                incorrect_registration_info, self.address\n            )\n\n        # after\n        mock_valid.assert_called_once()\n\n        assert not is_valid\n        assert code == 1\n        assert msg == \"fetchai address and signature do not match!\"\n\n    def test_valid_registration_fails_iv(self):\n        \"\"\"Test the valid_registration method of the Strategy class which fails because _valid_signature returns False for second call.\"\"\"\n        # setup\n        incorrect_registration_info = {\n            \"ethereum_address\": \"some_ethereum_address\",\n            \"fetchai_address\": self.address,\n            \"signature_of_ethereum_address\": \"some_signature_of_ethereum_address\",\n            \"signature_of_fetchai_address\": \"some_signature_of_fetchai_address\",\n            \"developer_handle\": \"some_developer_handle\",\n        }\n\n        # operation\n        with patch.object(\n            self.strategy, \"_valid_signature\", side_effect=[True, False]\n        ) as mock_valid:\n            is_valid, code, msg = self.strategy.valid_registration(\n                incorrect_registration_info, self.address\n            )\n\n        # after\n        mock_valid.assert_called()\n\n        assert not is_valid\n        assert code == 1\n        assert msg == \"ethereum address and signature do not match!\"\n\n    def test_valid_registration_fails_v(self):\n        \"\"\"Test the valid_registration method of the Strategy class which fails because no developer_handle was provided.\"\"\"\n        # setup\n        incorrect_registration_info = {\n            \"ethereum_address\": \"some_ethereum_address\",\n            \"fetchai_address\": self.address,\n            \"signature_of_ethereum_address\": \"some_signature_of_ethereum_address\",\n            \"signature_of_fetchai_address\": \"some_signature_of_fetchai_address\",\n            \"developer_handle\": \"\",\n        }\n\n        # operation\n        is_valid, code, msg = self.strategy.valid_registration(\n            incorrect_registration_info, self.address\n        )\n\n        # after\n        assert not is_valid\n        assert code == 1\n        assert msg == \"missing developer_handle!\"\n\n    def test_valid_registration_fails_vi(self):\n        \"\"\"Test the valid_registration method of the Strategy class which fails because agent registration is in progress.\"\"\"\n        # setup\n        registration_info = {\n            \"ethereum_address\": \"some_ethereum_address\",\n            \"fetchai_address\": self.address,\n            \"signature_of_ethereum_address\": \"some_signature_of_ethereum_address\",\n            \"signature_of_fetchai_address\": \"some_signature_of_fetchai_address\",\n            \"developer_handle\": \"some_developer_handle\",\n        }\n        self.strategy.lock_registration_temporarily(self.address, self.info)\n\n        # operation\n        is_valid, code, msg = self.strategy.valid_registration(\n            registration_info, self.address\n        )\n\n        # after\n        assert not is_valid\n        assert code == 1\n        assert msg == \"registration in process for this address!\"\n\n    def test_valid_registration_fails_vii(self):\n        \"\"\"Test the valid_registration method of the Strategy class which fails because agent already registered.\"\"\"\n        # setup\n        registration_info = {\n            \"ethereum_address\": \"some_ethereum_address\",\n            \"fetchai_address\": self.address,\n            \"signature_of_ethereum_address\": \"some_signature_of_ethereum_address\",\n            \"signature_of_fetchai_address\": \"some_signature_of_fetchai_address\",\n            \"developer_handle\": \"some_developer_handle\",\n        }\n\n        # operation\n        with patch.object(self.db, \"is_registered\", return_value=True) as mock_is:\n            is_valid, code, msg = self.strategy.valid_registration(\n                registration_info, self.address\n            )\n\n        # after\n        mock_is.assert_called_once()\n\n        assert not is_valid\n        assert code == 1\n        assert msg == \"already registered!\"\n\n    def test_valid_registration_fails_developer_only_mode_i(self):\n        \"\"\"Test the valid_registration method of the Strategy class in developer_only_mode which fails because some key is missing.\"\"\"\n        # setup\n        self.strategy.developer_handle_only = True\n        incorrect_registration_info = {\n            \"fetchai_address\": self.address,\n        }\n\n        # operation\n        is_valid, code, msg = self.strategy.valid_registration(\n            incorrect_registration_info, self.address\n        )\n\n        # after\n        assert not is_valid\n        assert code == 1\n        assert (\n            msg\n            == f\"missing keys in registration info, required: {DEVELOPER_ONLY_REQUIRED_KEYS}!\"\n        )\n\n    def test_valid_registration_fails_developer_only_mode_ii(self):\n        \"\"\"Test the valid_registration method of the Strategy class which fails because addresses do not match.\"\"\"\n        # setup\n        self.strategy.developer_handle_only = True\n        different_addres = \"some_other_address\"\n        incorrect_registration_info = {\n            \"fetchai_address\": different_addres,\n            \"developer_handle\": \"some_developer_handle\",\n        }\n\n        # operation\n        is_valid, code, msg = self.strategy.valid_registration(\n            incorrect_registration_info, self.address\n        )\n\n        # after\n        assert not is_valid\n        assert code == 1\n        assert msg == \"fetchai address of agent and registration info do not match!\"\n\n    def test__valid_signature_i(self):\n        \"\"\"Test the _valid_signature method of the Strategy class where result is True.\"\"\"\n        # setup\n        expected_signer = \"some_expected_signer\"\n        signature = \"some_signature\"\n        message_str = \"some_message_str\"\n        ledger_id = \"some_ledger_id\"\n\n        # operation\n        with patch.object(\n            LedgerApis, \"recover_message\", return_value=(expected_signer,)\n        ) as mock_recover:\n            is_valid = self.strategy._valid_signature(\n                expected_signer, signature, message_str, ledger_id\n            )\n\n        # after\n        mock_recover.assert_called_once()\n        assert is_valid\n\n    def test__valid_signature_ii(self):\n        \"\"\"Test the _valid_signature method of the Strategy class where result is False.\"\"\"\n        # setup\n        expected_signer = \"some_expected_signer\"\n        signature = \"some_signature\"\n        message_str = \"some_message_str\"\n        ledger_id = \"some_ledger_id\"\n\n        # operation\n        with patch.object(\n            LedgerApis, \"recover_message\", return_value=(\"some_other_signer\",)\n        ) as mock_recover:\n            is_valid = self.strategy._valid_signature(\n                expected_signer, signature, message_str, ledger_id\n            )\n\n        # after\n        mock_recover.assert_called_once()\n        assert not is_valid\n\n    def test__valid_signature_iii(self):\n        \"\"\"Test the _valid_signature method of the Strategy class where an exception is raised.\"\"\"\n        # setup\n        expected_signer = \"some_expected_signer\"\n        signature = \"some_signature\"\n        message_str = \"some_message_str\"\n        ledger_id = \"some_ledger_id\"\n\n        exception_message = \"some_exception_message\"\n\n        # operation\n        with patch.object(\n            LedgerApis, \"recover_message\", side_effect=Exception(exception_message)\n        ) as mock_recover:\n            with patch.object(self.logger, \"log\") as mock_logger:\n                is_valid = self.strategy._valid_signature(\n                    expected_signer, signature, message_str, ledger_id\n                )\n\n        # after\n        mock_recover.assert_called_once()\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"Signing exception: {exception_message}\",\n        )\n        assert not is_valid\n\n    def test_get_terms(self):\n        \"\"\"Test the get_terms method of the Strategy class.\"\"\"\n        # setup\n        counterparty = \"some_counterparty\"\n        expected_terms = Terms(\n            ledger_id=self.strategy._ledger_id,\n            sender_address=self.skill.skill_context.agent_address,\n            counterparty_address=counterparty,\n            amount_by_currency_id={\n                self.token_denomination: -self.token_dispense_amount\n            },\n            quantities_by_good_id={},\n            is_sender_payable_tx_fee=True,\n            nonce=\"some\",\n            fee_by_currency_id={self.token_denomination: self.strategy._max_tx_fee},\n        )\n\n        # operation\n        actual_terms = self.strategy.get_terms(counterparty)\n\n        # after\n        assert actual_terms == expected_terms\n\n    def test_get_kwargs(self):\n        \"\"\"Test the get_kwargs method of the Strategy class.\"\"\"\n        # setup\n        expected_kwargs = {\"address\": self.info[\"ethereum_address\"]}\n\n        # operation\n        actual_kwargs = self.strategy.get_kwargs(self.info)\n\n        # after\n        assert actual_kwargs == expected_kwargs\n\n    def test_has_staked_i(self):\n        \"\"\"Test the get_kwargs method of the Strategy class where _override_staking_check is False and stake value is greater than 0.\"\"\"\n        # setup\n        state = {\"stake\": \"100\"}\n\n        # operation\n        has_staked = self.strategy.has_staked(state)\n\n        # after\n        assert has_staked is True\n\n    def test_has_staked_ii(self):\n        \"\"\"Test the get_kwargs method of the Strategy class where _override_staking_check is False and stake value is 0.\"\"\"\n        # setup\n        state = {\"stake\": \"0\"}\n\n        # operation\n        has_staked = self.strategy.has_staked(state)\n\n        # after\n        assert has_staked is False\n\n    def test_has_staked_iii(self):\n        \"\"\"Test the get_kwargs method of the Strategy class where _override_staking_check is True.\"\"\"\n        # setup\n        self.strategy._override_staking_check = True\n        state = {\"stake\": \"100\"}\n\n        # operation\n        has_staked = self.strategy.has_staked(state)\n\n        # after\n        assert has_staked is True\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_confirmation_aw2/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"The tests module contains the tests of the packages/skills/confirmation_aw2 dir.\"\"\"\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_confirmation_aw2/intermediate_class.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the behaviour classes of the simple_data_request skill.\"\"\"\nfrom pathlib import Path\n\nfrom aea.test_tools.test_skill import BaseSkillTestCase\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass ConfirmationAW2TestCase(BaseSkillTestCase):\n    \"\"\"Sets the confirmation_aw2 class up for testing (overrides the necessary config values so tests can be done on confirmation_aw2 skill).\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"confirmation_aw2\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        cls.aw1_aea = \"some_aw1_aea\"\n        config_overrides = {\"models\": {\"strategy\": {\"args\": {\"aw1_aea\": cls.aw1_aea}}}}\n\n        super().setup(config_overrides=config_overrides)\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_confirmation_aw2/test_handlers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the handler classes of the confirmation aw2 skill.\"\"\"\n\nimport logging\nfrom pathlib import Path\nfrom typing import cast\nfrom unittest.mock import patch\n\nfrom aea.crypto.ledger_apis import LedgerApis\nfrom aea.protocols.dialogue.base import DialogueMessage\n\nfrom packages.fetchai.protocols.default.dialogues import DefaultDialogue\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.protocols.register.message import RegisterMessage\nfrom packages.fetchai.skills.confirmation_aw2.dialogues import DefaultDialogues\nfrom packages.fetchai.skills.confirmation_aw2.handlers import DefaultHandler\nfrom packages.fetchai.skills.confirmation_aw2.strategy import Strategy\n\nfrom tests.conftest import ROOT_DIR\nfrom tests.test_packages.test_skills.test_confirmation_aw2.intermediate_class import (\n    ConfirmationAW2TestCase,\n)\n\n\nclass TestDefaultHandler(ConfirmationAW2TestCase):\n    \"\"\"Test default handler of confirmation aw2.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"confirmation_aw2\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.default_handler = cast(\n            DefaultHandler, cls._skill.skill_context.handlers.default_handler\n        )\n        cls.logger = cls._skill.skill_context.logger\n        cls.strategy = cast(Strategy, cls._skill.skill_context.strategy)\n\n        cls.default_dialogues = cast(\n            DefaultDialogues, cls._skill.skill_context.default_dialogues\n        )\n\n        cls.list_of_default_messages = (\n            DialogueMessage(\n                DefaultMessage.Performative.BYTES, {\"content\": b\"some_content\"}\n            ),\n        )\n\n        cls.confirmed_aea = b\"ConfirmedAEA\"\n        cls.developer_handle = b\"DeveloperHandle\"\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the default handler.\"\"\"\n        assert self.default_handler.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle_unidentified_dialogue(self):\n        \"\"\"Test the _handle_unidentified_dialogue method of the register handler.\"\"\"\n        # setup\n        incorrect_dialogue_reference = (\"\", \"\")\n        incoming_message = self.build_incoming_message(\n            message_type=DefaultMessage,\n            dialogue_reference=incorrect_dialogue_reference,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"some_content\",\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.default_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received invalid default message={incoming_message}, unidentified dialogue.\",\n        )\n\n    def test_handle_bytes_i(self):\n        \"\"\"Test the _handle_bytes method of the default handler where the sender IS aw1_aea.\"\"\"\n        # setup\n        incoming_message = cast(\n            RegisterMessage,\n            self.build_incoming_message(\n                message_type=DefaultMessage,\n                performative=DefaultMessage.Performative.BYTES,\n                content=self.confirmed_aea + b\"_\" + self.developer_handle,\n                sender=self.aw1_aea,\n            ),\n        )\n\n        # operation\n        with patch.object(LedgerApis, \"is_valid_address\", return_value=True):\n            with patch.object(self.logger, \"log\") as mock_logger:\n                with patch.object(\n                    self.strategy, \"register_counterparty\"\n                ) as mock_register:\n                    self.default_handler.handle(incoming_message)\n\n        # after\n        mock_register.called_once()\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"adding confirmed_aea={self.confirmed_aea.decode('utf-8')} with developer_handle={self.developer_handle.decode('utf-8')} to db.\",\n        )\n\n    def test_handle_bytes_ii(self):\n        \"\"\"Test the _handle_bytes method of the default handler where the content is undecodable.\"\"\"\n        # setup\n        incorrect_content = \"some_incorrect_content\"\n\n        incoming_message = cast(\n            RegisterMessage,\n            self.build_incoming_message(\n                message_type=DefaultMessage,\n                performative=DefaultMessage.Performative.BYTES,\n                content=incorrect_content,\n                sender=self.aw1_aea,\n            ),\n        )\n\n        # operation\n        with patch.object(LedgerApis, \"is_valid_address\", return_value=True):\n            with patch.object(self.logger, \"log\") as mock_logger:\n                with patch.object(\n                    self.strategy, \"register_counterparty\"\n                ) as mock_register:\n                    self.default_handler.handle(incoming_message)\n\n        # after\n        mock_register.called_once()\n\n        mock_logger.assert_any_call(\n            logging.WARNING, \"received invalid developer_handle=.\"\n        )\n\n    def test_handle_bytes_iii(self):\n        \"\"\"Test the _handle_bytes method of the default handler where is_valid_address is False.\"\"\"\n        # setup\n        incoming_message = cast(\n            RegisterMessage,\n            self.build_incoming_message(\n                message_type=DefaultMessage,\n                performative=DefaultMessage.Performative.BYTES,\n                content=self.confirmed_aea + b\"_\" + self.developer_handle,\n                sender=self.aw1_aea,\n            ),\n        )\n\n        # operation\n        with patch.object(LedgerApis, \"is_valid_address\", return_value=False):\n            with patch.object(self.logger, \"log\") as mock_logger:\n                with patch.object(\n                    self.strategy, \"register_counterparty\"\n                ) as mock_register:\n                    self.default_handler.handle(incoming_message)\n\n        # after\n        mock_register.called_once()\n\n        default_dialogue = cast(\n            DefaultDialogue, self.default_dialogues.get_dialogue(incoming_message)\n        )\n\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"received invalid address={self.confirmed_aea.decode('utf-8')} in dialogue={default_dialogue}.\",\n        )\n\n    def test_handle_bytes_iv(self):\n        \"\"\"Test the _handle_bytes method of the default handler where the sender is NOT aw1_aea.\"\"\"\n        # setup\n        incoming_message = cast(\n            RegisterMessage,\n            self.build_incoming_message(\n                message_type=DefaultMessage,\n                performative=DefaultMessage.Performative.BYTES,\n                content=self.confirmed_aea + b\"_\" + self.developer_handle,\n                sender=\"some_other_aea\",\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            with patch.object(self.strategy, \"register_counterparty\") as mock_register:\n                self.default_handler.handle(incoming_message)\n\n        # after\n        mock_register.called_once()\n\n        default_dialogue = cast(\n            DefaultDialogue, self.default_dialogues.get_dialogue(incoming_message)\n        )\n\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"cannot handle default message of performative={incoming_message.performative} in dialogue={default_dialogue}. Invalid sender={incoming_message.sender}\",\n        )\n\n    def test_handle_invalid(self):\n        \"\"\"Test the _handle_invalid method of the default handler.\"\"\"\n        # setup\n        default_dialogue = cast(\n            DefaultDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.default_dialogues,\n                messages=self.list_of_default_messages[:1],\n            ),\n        )\n        incoming_message = cast(\n            RegisterMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=default_dialogue,\n                performative=DefaultMessage.Performative.ERROR,\n                error_code=DefaultMessage.ErrorCode.DECODING_ERROR,\n                error_msg=\"some_error_message\",\n                error_data={\"some_key\": b\"some_value\"},\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.default_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"cannot handle default message of performative={incoming_message.performative} in dialogue={default_dialogue}.\",\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the default handler.\"\"\"\n        assert self.default_handler.teardown() is None\n        self.assert_quantity_in_outbox(0)\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_confirmation_aw2/test_registration_db.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the RegistrationDB class of the confirmation aw2 skill.\"\"\"\nimport datetime\nimport json\nimport logging\nfrom pathlib import Path\nfrom unittest.mock import Mock, patch\n\nfrom packages.fetchai.skills.confirmation_aw2.registration_db import RegistrationDB\n\nfrom tests.conftest import ROOT_DIR\nfrom tests.test_packages.test_skills.test_confirmation_aw2.intermediate_class import (\n    ConfirmationAW2TestCase,\n)\n\n\nclass TestStrategy(ConfirmationAW2TestCase):\n    \"\"\"Test RegistrationDB of confirmation aw2.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"confirmation_aw2\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.custom_path = None\n        cls.db = RegistrationDB(\n            custom_path=cls.custom_path,\n            name=\"strategy\",\n            skill_context=cls._skill.skill_context,\n        )\n        cls.address = \"some_address\"\n        cls.logger = cls._skill.skill_context.logger\n\n        cls.timestamp = datetime.datetime.now()\n        cls.data = {\"some_key_1\": \"some_value_1\", \"some_key_2\": \"some_value_2\"}\n\n        cls.developer_handle = \"developer_handle\"\n\n        cls.first_trade = \"2020-12-22 18:30:00.000000\"\n        cls.second_trade = \"second_trade\"\n        cls.first_info = \"first_info\"\n        cls.second_info = \"second_info\"\n\n    def test__initialise_backend(self):\n        \"\"\"Test the _initialise_backend method of the RegistrationDB class.\"\"\"\n        # operation\n        with patch.object(self.db, \"_execute_single_sql\") as mock_exe:\n            self.db._initialise_backend()\n\n        # after\n        mock_exe.assert_any_call(\n            \"CREATE TABLE IF NOT EXISTS registered_table (address TEXT, ethereum_address TEXT, \"\n            \"ethereum_signature TEXT, fetchai_signature TEXT, \"\n            \"developer_handle TEXT, tweet TEXT)\"\n        )\n        mock_exe.assert_any_call(\n            \"CREATE TABLE IF NOT EXISTS trade_table (address TEXT PRIMARY KEY, first_trade timestamp, \"\n            \"second_trade timestamp, first_info TEXT, second_info TEXT)\"\n        )\n\n    def test_set_trade_i(self):\n        \"\"\"Test the set_trade method of the RegistrationDB class where record IS None.\"\"\"\n        # operation\n        with patch.object(\n            self.db, \"get_trade_table\", return_value=None\n        ) as mock_get_trade_table:\n            with patch.object(self.db, \"_execute_single_sql\") as mock_exe:\n                self.db.set_trade(\n                    self.address,\n                    self.timestamp,\n                    self.data,\n                )\n\n        # after\n        mock_get_trade_table.assert_called_once()\n        mock_exe.assert_any_call(\n            \"INSERT INTO trade_table(address, first_trade, second_trade, first_info, second_info) values(?, ?, ?, ?, ?)\",\n            (self.address, self.timestamp, None, json.dumps(self.data), None),\n        )\n\n    def test_set_trade_ii(self):\n        \"\"\"Test the set_trade method of the RegistrationDB class where record is NOT None.\"\"\"\n        # setup\n        record = (\n            self.address,\n            self.first_trade,\n            None,\n            self.first_info,\n            self.second_info,\n        )\n\n        # operation\n        with patch.object(\n            self.db, \"get_trade_table\", return_value=record\n        ) as mock_get_trade_table:\n            with patch.object(self.db, \"_execute_single_sql\") as mock_exe:\n                self.db.set_trade(\n                    self.address,\n                    self.timestamp,\n                    self.data,\n                )\n\n        # after\n        mock_get_trade_table.assert_called_once()\n\n        mock_exe.assert_any_call(\n            \"INSERT or REPLACE into trade_table(address, first_trade, second_trade, first_info, second_info) values(?, ?, ?, ?, ?)\",\n            (\n                self.address,\n                self.first_trade,\n                self.timestamp,\n                self.first_info,\n                json.dumps(self.data),\n            ),\n        )\n\n    def test_set_trade_iii(self):\n        \"\"\"Test the set_trade method of the RegistrationDB class where record is NOT None and first_trade is None.\"\"\"\n        # setup\n        record = (\n            self.address,\n            None,\n            None,\n            self.first_info,\n            self.second_info,\n        )\n\n        # operation\n        with patch.object(\n            self.db, \"get_trade_table\", return_value=record\n        ) as mock_get_trade_table:\n            with patch.object(self.db, \"_execute_single_sql\") as mock_exe:\n                self.db.set_trade(\n                    self.address,\n                    self.timestamp,\n                    self.data,\n                )\n\n        # after\n        mock_get_trade_table.assert_called_once()\n\n        mock_exe.assert_not_called()\n\n    def test_get_trade_table(self):\n        \"\"\"Test the get_trade_table method of the RegistrationDB class.\"\"\"\n        # setup\n        trade_table = (\"something_1\", \"something_2\")\n        result = [trade_table, (\"something_3\",)]\n\n        # operation\n        with patch.object(\n            self.db, \"_execute_single_sql\", return_value=result\n        ) as mock_exe:\n            actual_trade_table = self.db.get_trade_table(self.address)\n\n        # after\n        mock_exe.assert_any_call(\n            \"SELECT * FROM trade_table where address=?\", (self.address,)\n        )\n        assert actual_trade_table == trade_table\n\n    def test_set_registered_i(self):\n        \"\"\"Test the set_registered method of the RegistrationDB class where is_registeredis is False.\"\"\"\n        # operation\n        with patch.object(\n            self.db, \"is_registered\", return_value=False\n        ) as mock_is_registered:\n            with patch.object(self.db, \"_execute_single_sql\") as mock_exe:\n                self.db.set_registered(\n                    self.address,\n                    self.developer_handle,\n                )\n\n        # after\n        mock_is_registered.assert_called_once()\n        mock_exe.assert_any_call(\n            \"INSERT OR REPLACE INTO registered_table(address, ethereum_address, ethereum_signature, fetchai_signature, developer_handle, tweet) values(?, ?, ?, ?, ?, ?)\",\n            (self.address, \"\", \"\", \"\", self.developer_handle, \"\"),\n        )\n\n    def test_set_registered_ii(self):\n        \"\"\"Test the set_registered method of the RegistrationDB class where is_registeredis is True.\"\"\"\n        # operation\n        with patch.object(\n            self.db, \"is_registered\", return_value=True\n        ) as mock_is_registered:\n            with patch.object(self.db, \"_execute_single_sql\") as mock_exe:\n                self.db.set_registered(\n                    self.address,\n                    self.developer_handle,\n                )\n\n        # after\n        mock_is_registered.assert_called_once()\n        mock_exe.assert_not_called()\n\n    def test_is_registered_i(self):\n        \"\"\"Test the is_registered method of the RegistrationDB class where result is NOT empty.\"\"\"\n        # setup\n        result = [[\"1\"], [\"2\", \"3\"]]\n\n        # operation\n        with patch.object(\n            self.db, \"_execute_single_sql\", return_value=result\n        ) as mock_exe:\n            is_registered = self.db.is_registered(self.address)\n\n        # after\n        mock_exe.assert_any_call(\n            \"SELECT * FROM registered_table WHERE address=?\", (self.address,)\n        )\n        assert is_registered\n\n    def test_is_registered_ii(self):\n        \"\"\"Test the is_registered method of the RegistrationDB class where result is empty.\"\"\"\n        # setup\n        result = []\n\n        # operation\n        with patch.object(\n            self.db, \"_execute_single_sql\", return_value=result\n        ) as mock_exe:\n            is_registered = self.db.is_registered(self.address)\n\n        # after\n        mock_exe.assert_any_call(\n            \"SELECT * FROM registered_table WHERE address=?\", (self.address,)\n        )\n        assert not is_registered\n\n    def test_is_allowed_to_trade_i(self):\n        \"\"\"Test the is_allowed_to_trade method of the RegistrationDB class where record IS None.\"\"\"\n        # setup\n        mininum_hours_between_txs = 1\n        record = None\n\n        # operation\n        with patch.object(\n            self.db, \"get_trade_table\", return_value=record\n        ) as mock_get_trade:\n            with patch.object(self.db, \"_execute_single_sql\") as mock_exe:\n                is_registered = self.db.is_allowed_to_trade(\n                    self.address, mininum_hours_between_txs\n                )\n\n        # after\n        mock_get_trade.assert_called_once()\n        mock_exe.assert_not_called()\n        assert is_registered\n\n    def test_is_allowed_to_trade_ii(self):\n        \"\"\"Test the is_allowed_to_trade method of the RegistrationDB class where first_trade and second_trade are NOT present.\"\"\"\n        # setup\n        minimum_hours_between_txs = 1\n        record = (self.address, None, None, self.first_info, self.second_info)\n\n        # operation\n        with patch.object(\n            self.db, \"get_trade_table\", return_value=record\n        ) as mock_get_trade:\n            is_registered = self.db.is_allowed_to_trade(\n                self.address, minimum_hours_between_txs\n            )\n\n        # after\n        mock_get_trade.assert_called_once()\n        assert is_registered\n\n    def test_is_allowed_to_trade_iii(self):\n        \"\"\"Test the is_allowed_to_trade method of the RegistrationDB class where is_allowed_to_trade_ is True.\"\"\"\n        # setup\n        minimum_hours_between_txs = 1\n        record = (\n            self.address,\n            self.first_trade,\n            None,\n            self.first_info,\n            self.second_info,\n        )\n\n        mocked_now_greater_than_minimum = \"2020-12-22 20:30:00.000000\"\n        datetime_mock = Mock(wraps=datetime.datetime)\n        datetime_mock.now.return_value = datetime.datetime.strptime(\n            mocked_now_greater_than_minimum, \"%Y-%m-%d %H:%M:%S.%f\"\n        )\n\n        # operation\n        with patch(\"datetime.datetime\", new=datetime_mock):\n            with patch.object(\n                self.db, \"get_trade_table\", return_value=record\n            ) as mock_get_trade:\n                is_registered = self.db.is_allowed_to_trade(\n                    self.address, minimum_hours_between_txs\n                )\n\n        # after\n        mock_get_trade.assert_called_once()\n        assert is_registered\n\n    def test_is_allowed_to_trade_iv(self):\n        \"\"\"Test the is_allowed_to_trade method of the RegistrationDB class where is_allowed_to_trade_ is False.\"\"\"\n        # setup\n        minimum_hours_between_txs = 1\n        record = (\n            self.address,\n            self.first_trade,\n            None,\n            self.first_info,\n            self.second_info,\n        )\n\n        mocked_now_less_than_minimum = \"2020-12-22 18:31:00.000000\"\n\n        # operation\n        datetime_mock = Mock(wraps=datetime.datetime)\n        datetime_mock.now.return_value = datetime.datetime.strptime(\n            mocked_now_less_than_minimum, \"%Y-%m-%d %H:%M:%S.%f\"\n        )\n        with patch(\"datetime.datetime\", new=datetime_mock):\n            with patch.object(\n                self.db, \"get_trade_table\", return_value=record\n            ) as mock_get_trade:\n                with patch.object(self.logger, \"log\") as mock_logger:\n                    is_registered = self.db.is_allowed_to_trade(\n                        self.address, minimum_hours_between_txs\n                    )\n\n        # after\n        mock_get_trade.assert_called_once()\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"Invalid attempt for counterparty={self.address}, not enough time since last trade!\",\n        )\n        assert not is_registered\n\n    def test_is_allowed_to_trade_v(self):\n        \"\"\"Test the is_allowed_to_trade method of the RegistrationDB class where second_trade IS present.\"\"\"\n        # setup\n        minimum_hours_between_txs = 1\n        record = (\n            self.address,\n            self.first_trade,\n            self.second_trade,\n            self.first_info,\n            self.second_info,\n        )\n\n        mocked_now = \"2020-12-22 18:31:00.000000\"\n        # operation\n        datetime_mock = Mock(wraps=datetime.datetime)\n        datetime_mock.now.return_value = datetime.datetime.strptime(\n            mocked_now, \"%Y-%m-%d %H:%M:%S.%f\"\n        )\n        with patch(\"datetime.datetime\", new=datetime_mock):\n            with patch.object(\n                self.db, \"get_trade_table\", return_value=record\n            ) as mock_get_trade:\n                with patch.object(self.logger, \"log\") as mock_logger:\n                    is_registered = self.db.is_allowed_to_trade(\n                        self.address, minimum_hours_between_txs\n                    )\n\n        # after\n        mock_get_trade.assert_called_once()\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"Invalid attempt for counterparty={self.address}, already completed 2 trades!\",\n        )\n        assert not is_registered\n\n    def test_has_completed_two_trades_i(self):\n        \"\"\"Test the has_completed_two_trades method of the RegistrationDB class where first and second trade are present.\"\"\"\n        # setup\n        record = (\n            self.address,\n            self.first_trade,\n            self.second_trade,\n            self.first_info,\n            self.second_info,\n        )\n\n        # operation\n        with patch.object(\n            self.db, \"get_trade_table\", return_value=record\n        ) as mock_get_trade:\n            has_completed = self.db.has_completed_two_trades(self.address)\n\n        # after\n        mock_get_trade.assert_called_once()\n        assert has_completed\n\n    def test_has_completed_two_trades_ii(self):\n        \"\"\"Test the has_completed_two_trades method of the RegistrationDB class where first and second trade are NOT present.\"\"\"\n        # setup\n        record = (self.address, None, None, self.first_info, self.second_info)\n\n        # operation\n        with patch.object(\n            self.db, \"get_trade_table\", return_value=record\n        ) as mock_get_trade:\n            has_completed = self.db.has_completed_two_trades(self.address)\n\n        # after\n        mock_get_trade.assert_called_once()\n        assert not has_completed\n\n    def test_has_completed_two_trades_iii(self):\n        \"\"\"Test the has_completed_two_trades method of the RegistrationDB class where first trade is NOT and second trade IS present.\"\"\"\n        # setup\n        record = (\n            self.address,\n            None,\n            self.second_trade,\n            self.first_info,\n            self.second_info,\n        )\n\n        # operation\n        with patch.object(\n            self.db, \"get_trade_table\", return_value=record\n        ) as mock_get_trade:\n            has_completed = self.db.has_completed_two_trades(self.address)\n\n        # after\n        mock_get_trade.assert_called_once()\n        assert not has_completed\n\n    def test_has_completed_two_trades_iv(self):\n        \"\"\"Test the has_completed_two_trades method of the RegistrationDB class where first trade IS and second trade is NOT present.\"\"\"\n        # setup\n        record = (\n            self.address,\n            self.first_trade,\n            None,\n            self.first_info,\n            self.second_info,\n        )\n\n        # operation\n        with patch.object(\n            self.db, \"get_trade_table\", return_value=record\n        ) as mock_get_trade:\n            has_completed = self.db.has_completed_two_trades(self.address)\n\n        # after\n        mock_get_trade.assert_called_once()\n        assert not has_completed\n\n    def test_has_completed_two_trades_v(self):\n        \"\"\"Test the has_completed_two_trades method of the RegistrationDB class where record IS None.\"\"\"\n        # setup\n        record = None\n\n        # operation\n        with patch.object(\n            self.db, \"get_trade_table\", return_value=record\n        ) as mock_get_trade:\n            has_completed = self.db.has_completed_two_trades(self.address)\n\n        # after\n        mock_get_trade.assert_called_once()\n        assert not has_completed\n\n    def test_completed_two_trades(self):\n        \"\"\"Test the completed_two_trades method of the RegistrationDB class.\"\"\"\n        # setup\n        row_1 = (\n            \"address_1\",\n            \"ethereum_address_1\",\n            \"something2_1\",\n            \"something3_1\",\n            \"developer_handle_1\",\n        )\n        row_2 = (\n            \"address_2\",\n            \"ethereum_address_2\",\n            \"something2_2\",\n            \"something3_2\",\n            \"developer_handle_2\",\n        )\n        row_3 = (\n            \"address_3\",\n            \"ethereum_address_3\",\n            \"something2_3\",\n            \"something3_3\",\n            \"developer_handle_3\",\n        )\n        result = [row_1, row_2, row_3]\n\n        has_completed = [True, False, True]\n\n        # operation\n        with patch.object(\n            self.db, \"_execute_single_sql\", return_value=result\n        ) as mock_exe:\n            with patch.object(\n                self.db, \"has_completed_two_trades\", side_effect=has_completed\n            ):\n                actual_completed = self.db.completed_two_trades()\n\n        # after\n        mock_exe.assert_any_call(\"SELECT * FROM registered_table\", ())\n        assert actual_completed == [\n            (\"address_1\", \"ethereum_address_1\", \"developer_handle_1\"),\n            (\"address_3\", \"ethereum_address_3\", \"developer_handle_3\"),\n        ]\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_confirmation_aw2/test_strategy.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the strategy class of the confirmation aw2 skill.\"\"\"\n\nimport datetime\nimport logging\nfrom pathlib import Path\nfrom typing import cast\nfrom unittest.mock import Mock, patch\n\nimport pytest\n\nfrom packages.fetchai.skills.confirmation_aw2.registration_db import RegistrationDB\nfrom packages.fetchai.skills.confirmation_aw2.strategy import Strategy\n\nfrom tests.conftest import ROOT_DIR\nfrom tests.test_packages.test_skills.test_confirmation_aw2.intermediate_class import (\n    ConfirmationAW2TestCase,\n)\n\n\nclass TestStrategy(ConfirmationAW2TestCase):\n    \"\"\"Test Strategy of confirmation aw2.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"confirmation_aw2\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n\n        cls.minimum_hours_between_txs = 4\n        cls.minimum_minutes_since_last_attempt = 2\n        cls.strategy = Strategy(\n            aw1_aea=\"some_aw1_aea\",\n            mininum_hours_between_txs=cls.minimum_hours_between_txs,\n            minimum_minutes_since_last_attempt=cls.minimum_minutes_since_last_attempt,\n            name=\"strategy\",\n            skill_context=cls._skill.skill_context,\n        )\n\n        cls.address = \"some_address\"\n        cls.info = {\n            \"ethereum_address\": \"some_value\",\n            \"signature_of_ethereum_address\": \"some_signature_of_ethereum_address\",\n            \"signature_of_fetchai_address\": \"some_signature_of_fetchai_address\",\n            \"developer_handle\": \"some_developer_handle\",\n            \"tweet\": \"some_tweet\",\n        }\n        cls.logger = cls._skill.skill_context.logger\n        cls.db = cast(RegistrationDB, cls._skill.skill_context.registration_db)\n\n        cls.counterparty = \"couterparty_1\"\n\n    def test__init__i(self):\n        \"\"\"Test the __init__ of Strategy class.\"\"\"\n        assert self.strategy.aw1_aea == self.aw1_aea\n        assert self.strategy.minimum_hours_between_txs == self.minimum_hours_between_txs\n        assert (\n            self.strategy.minimum_minutes_since_last_attempt\n            == self.minimum_minutes_since_last_attempt\n        )\n\n    def test__init__ii(self):\n        \"\"\"Test the __init__ of Strategy class where aw1_aea is None.\"\"\"\n        with pytest.raises(ValueError, match=\"aw1_aea must be provided!\"):\n            Strategy(\n                aw1_aea=None,\n                mininum_hours_between_txs=self.minimum_hours_between_txs,\n                minimum_minutes_since_last_attempt=self.minimum_minutes_since_last_attempt,\n                name=\"strategy\",\n                skill_context=self.skill.skill_context,\n            )\n\n    def test_get_acceptable_counterparties(self):\n        \"\"\"Test the get_acceptable_counterparties method of the Strategy class.\"\"\"\n        # setup\n        couterparties = (\"couterparty_1\", \"couterparty_2\", \"couterparty_3\")\n        is_valid_counterparty = [True, False, True]\n\n        # operation\n        with patch.object(\n            self.strategy, \"is_valid_counterparty\", side_effect=is_valid_counterparty\n        ):\n            actual_acceptable_counterparties = (\n                self.strategy.get_acceptable_counterparties(couterparties)\n            )\n\n        # after\n        assert actual_acceptable_counterparties == (\"couterparty_1\", \"couterparty_3\")\n\n    def test_is_enough_time_since_last_attempt_i(self):\n        \"\"\"Test the is_enough_time_since_last_attempt method of the Strategy class where now IS greater than last attempt + min minutes.\"\"\"\n        # setup\n        counterparty_last_attempt_time_str = \"2020-12-22 20:30:00.000000\"\n        counterparty_last_attempt_time = datetime.datetime.strptime(\n            counterparty_last_attempt_time_str, \"%Y-%m-%d %H:%M:%S.%f\"\n        )\n\n        mocked_now_greater_than_last_plus_minimum = \"2020-12-22 20:33:00.000000\"\n        datetime_mock = Mock(wraps=datetime.datetime)\n        datetime_mock.now.return_value = datetime.datetime.strptime(\n            mocked_now_greater_than_last_plus_minimum, \"%Y-%m-%d %H:%M:%S.%f\"\n        )\n        self.strategy.last_attempt = {self.counterparty: counterparty_last_attempt_time}\n\n        # operation\n        with patch(\"datetime.datetime\", new=datetime_mock):\n            is_enough_time = self.strategy.is_enough_time_since_last_attempt(\n                self.counterparty\n            )\n\n        # after\n        assert is_enough_time is True\n\n    def test_is_enough_time_since_last_attempt_ii(self):\n        \"\"\"Test the is_enough_time_since_last_attempt method of the Strategy class where now is NOT greater than last attempt + min minutes.\"\"\"\n        # setup\n        counterparty_last_attempt_time_str = \"2020-12-22 20:30:00.000000\"\n        counterparty_last_attempt_time = datetime.datetime.strptime(\n            counterparty_last_attempt_time_str, \"%Y-%m-%d %H:%M:%S.%f\"\n        )\n\n        mocked_now_less_than_last_plus_minimum = \"2020-12-22 20:31:00.000000\"\n        datetime_mock = Mock(wraps=datetime.datetime)\n        datetime_mock.now.return_value = datetime.datetime.strptime(\n            mocked_now_less_than_last_plus_minimum, \"%Y-%m-%d %H:%M:%S.%f\"\n        )\n        self.strategy.last_attempt = {self.counterparty: counterparty_last_attempt_time}\n\n        # operation\n        with patch(\"datetime.datetime\", new=datetime_mock):\n            is_enough_time = self.strategy.is_enough_time_since_last_attempt(\n                self.counterparty\n            )\n\n        # after\n        assert is_enough_time is False\n\n    def test_is_enough_time_since_last_attempt_iii(self):\n        \"\"\"Test the is_enough_time_since_last_attempt method of the Strategy class where now counterparty is NOT in last_attempt.\"\"\"\n        # setup\n        self.strategy.last_attempt = {}\n\n        # operation\n        is_enough_time = self.strategy.is_enough_time_since_last_attempt(\n            self.counterparty\n        )\n\n        # after\n        assert is_enough_time is True\n\n    def test_is_valid_counterparty_i(self):\n        \"\"\"Test the is_valid_counterparty method of the Strategy class where is_registered is False.\"\"\"\n        # operation\n        with patch.object(self.db, \"is_registered\", return_value=False):\n            with patch.object(self.logger, \"log\") as mock_logger:\n                is_valid = self.strategy.is_valid_counterparty(self.counterparty)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"Invalid counterparty={self.counterparty}, not registered!\",\n        )\n        assert is_valid is False\n\n    def test_is_valid_counterparty_ii(self):\n        \"\"\"Test the is_valid_counterparty method of the Strategy class where is_enough_time_since_last_attempt is False.\"\"\"\n        # operation\n        with patch.object(self.db, \"is_registered\", return_value=True):\n            with patch.object(\n                self.strategy, \"is_enough_time_since_last_attempt\", return_value=False\n            ):\n                with patch.object(self.logger, \"log\") as mock_logger:\n                    is_valid = self.strategy.is_valid_counterparty(self.counterparty)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.DEBUG,\n            f\"Not enough time since last attempt for counterparty={self.counterparty}!\",\n        )\n        assert is_valid is False\n\n    def test_is_valid_counterparty_iii(self):\n        \"\"\"Test the is_valid_counterparty method of the Strategy class where is_allowed_to_trade is False.\"\"\"\n        # operation\n        with patch.object(self.db, \"is_registered\", return_value=True):\n            with patch.object(\n                self.strategy, \"is_enough_time_since_last_attempt\", return_value=True\n            ):\n                with patch.object(self.db, \"is_allowed_to_trade\", return_value=False):\n                    is_valid = self.strategy.is_valid_counterparty(self.counterparty)\n\n        # after\n        assert is_valid is False\n\n    def test_is_valid_counterparty_iv(self):\n        \"\"\"Test the is_valid_counterparty method of the Strategy class where it succeeds.\"\"\"\n        # operation\n        with patch.object(self.db, \"is_registered\", return_value=True):\n            with patch.object(\n                self.strategy, \"is_enough_time_since_last_attempt\", return_value=True\n            ):\n                with patch.object(self.db, \"is_allowed_to_trade\", return_value=True):\n                    is_valid = self.strategy.is_valid_counterparty(self.counterparty)\n\n        # after\n        assert is_valid is True\n\n    def test_successful_trade_with_counterparty(self):\n        \"\"\"Test the successful_trade_with_counterparty method of the Strategy class.\"\"\"\n        # setup\n        data = {\"some_key_1\": \"some_value_1\", \"some_key_2\": \"some_value_2\"}\n\n        mocked_now_str = \"2020-12-22 20:33:00.000000\"\n        mock_now = datetime.datetime.strptime(mocked_now_str, \"%Y-%m-%d %H:%M:%S.%f\")\n        datetime_mock = Mock(wraps=datetime.datetime)\n        datetime_mock.now.return_value = mock_now\n\n        # operation\n        with patch.object(self.db, \"set_trade\") as mock_set_trade:\n            with patch(\"datetime.datetime\", new=datetime_mock):\n                with patch.object(self.logger, \"log\") as mock_logger:\n                    self.strategy.successful_trade_with_counterparty(\n                        self.counterparty, data\n                    )\n\n        # after\n        mock_set_trade.assert_any_call(self.counterparty, mock_now, data)\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"Successful trade with={self.counterparty}. Data acquired={data}!\",\n        )\n\n    def test_register_counterparty(self):\n        \"\"\"Test the register_counterparty method of the Strategy class.\"\"\"\n        # setup\n        developer_handle = \"some_developer_handle\"\n\n        # operation\n        with patch.object(self.db, \"set_registered\") as mock_set_registered:\n            self.strategy.register_counterparty(self.counterparty, developer_handle)\n\n        # after\n        mock_set_registered.assert_any_call(self.counterparty, developer_handle)\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_confirmation_aw3/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"The tests module contains the tests of the packages/skills/confirmation_aw3 dir.\"\"\"\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_confirmation_aw3/intermediate_class.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the behaviour classes of the simple_data_request skill.\"\"\"\nfrom pathlib import Path\n\nfrom aea.test_tools.test_skill import BaseSkillTestCase\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass ConfirmationAW3TestCase(BaseSkillTestCase):\n    \"\"\"Sets the confirmation_aw3 class up for testing (overrides the necessary config values so tests can be done on confirmation_aw3 skill).\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"confirmation_aw3\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        cls.aw1_aea = \"some_aw1_aea\"\n        cls.leaderboard_url = \"some_leaderboard_url\"\n        cls.leaderboard_token = \"some_leaderboard_token\"  # nosec\n        config_overrides = {\n            \"models\": {\n                \"strategy\": {\n                    \"args\": {\n                        \"aw1_aea\": cls.aw1_aea,\n                        \"leaderboard_url\": cls.leaderboard_url,\n                        \"leaderboard_token\": cls.leaderboard_token,\n                    }\n                }\n            }\n        }\n\n        super().setup(config_overrides=config_overrides)\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_confirmation_aw3/test_behaviours.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the behaviour classes of the confirmation aw3 skill.\"\"\"\n\nfrom pathlib import Path\nfrom typing import cast\nfrom unittest.mock import patch\n\nfrom aea.helpers.search.models import (\n    Attribute,\n    Constraint,\n    ConstraintType,\n    DataModel,\n    Query,\n)\n\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.skills.confirmation_aw3.behaviours import SearchBehaviour\nfrom packages.fetchai.skills.confirmation_aw3.strategy import Strategy\n\nfrom tests.conftest import ROOT_DIR\nfrom tests.test_packages.test_skills.test_confirmation_aw3.intermediate_class import (\n    ConfirmationAW3TestCase,\n)\n\n\nclass TestSearchBehaviour(ConfirmationAW3TestCase):\n    \"\"\"Test search behaviour of confirmation aw3.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"confirmation_aw3\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n\n        cls.search_behaviour = cast(\n            SearchBehaviour, cls._skill.skill_context.behaviours.search\n        )\n        cls.strategy = cast(Strategy, cls._skill.skill_context.strategy)\n\n    def test_act(self):\n        \"\"\"Test the act method of the transaction behaviour.\"\"\"\n        # setup\n        self.strategy.is_searching = True\n\n        mock_query = Query(\n            [Constraint(\"some_attribute\", ConstraintType(\"==\", \"some_service\"))],\n            DataModel(\n                \"some_name\",\n                [\n                    Attribute(\n                        \"some_attribute\", str, False, \"Some attribute descriptions.\"\n                    )\n                ],\n            ),\n        )\n\n        # operation\n        with patch.object(self.strategy, \"update_search_query_params\") as mock_update:\n            with patch.object(\n                self.strategy, \"get_location_and_service_query\", return_value=mock_query\n            ):\n                self.search_behaviour.act()\n\n        # after\n        self.assert_quantity_in_outbox(1)\n\n        mock_update.assert_called_once()\n\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=OefSearchMessage,\n            performative=OefSearchMessage.Performative.SEARCH_SERVICES,\n            to=self.skill.skill_context.search_service_address,\n            sender=str(self.skill.skill_context.skill_id),\n            query=mock_query,\n        )\n        assert has_attributes, error_str\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_confirmation_aw3/test_dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the dialogue classes of the generic buyer skill.\"\"\"\n\nfrom pathlib import Path\nfrom typing import cast\n\nfrom aea.test_tools.test_skill import COUNTERPARTY_AGENT_ADDRESS\n\nfrom packages.fetchai.protocols.http.message import HttpMessage\nfrom packages.fetchai.skills.confirmation_aw3.dialogues import (\n    HttpDialogue,\n    HttpDialogues,\n)\n\nfrom tests.conftest import ROOT_DIR\nfrom tests.test_packages.test_skills.test_confirmation_aw3.intermediate_class import (\n    ConfirmationAW3TestCase,\n)\n\n\nclass TestDialogues(ConfirmationAW3TestCase):\n    \"\"\"Test dialogue classes of confirmation aw3.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"confirmation_aw3\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n\n        cls.http_dialogues = cast(\n            HttpDialogues, cls._skill.skill_context.http_dialogues\n        )\n\n    def test_http_dialogues(self):\n        \"\"\"Test the HttpDialogues class.\"\"\"\n        _, dialogue = self.http_dialogues.create(\n            counterparty=COUNTERPARTY_AGENT_ADDRESS,\n            performative=HttpMessage.Performative.REQUEST,\n            method=\"some_method\",\n            url=\"some_url\",\n            version=\"some_version\",\n            headers=\"some_headers\",\n            body=b\"some_body\",\n        )\n        assert dialogue.role == HttpDialogue.Role.CLIENT\n        assert dialogue.self_address == str(self.skill.skill_context.skill_id)\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_confirmation_aw3/test_handlers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the handler classes of the confirmation aw3 skill.\"\"\"\n\nimport logging\nfrom pathlib import Path\nfrom typing import cast\nfrom unittest.mock import patch\n\nfrom aea.crypto.ledger_apis import LedgerApis\nfrom aea.protocols.dialogue.base import DialogueMessage\n\nfrom packages.fetchai.protocols.default.dialogues import DefaultDialogue\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.protocols.http.message import HttpMessage\nfrom packages.fetchai.skills.confirmation_aw3.dialogues import (\n    DefaultDialogues,\n    HttpDialogue,\n    HttpDialogues,\n)\nfrom packages.fetchai.skills.confirmation_aw3.handlers import (\n    DefaultHandler,\n    HttpHandler,\n)\nfrom packages.fetchai.skills.confirmation_aw3.strategy import Strategy\n\nfrom tests.conftest import ROOT_DIR\nfrom tests.test_packages.test_skills.test_confirmation_aw3.intermediate_class import (\n    ConfirmationAW3TestCase,\n)\n\n\nclass TestDefaultHandler(ConfirmationAW3TestCase):\n    \"\"\"Test default handler of confirmation aw3.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"confirmation_aw3\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.default_handler = cast(\n            DefaultHandler, cls._skill.skill_context.handlers.default_handler\n        )\n        cls.logger = cls._skill.skill_context.logger\n        cls.strategy = cast(Strategy, cls._skill.skill_context.strategy)\n\n        cls.default_dialogues = cast(\n            DefaultDialogues, cls._skill.skill_context.default_dialogues\n        )\n\n        cls.list_of_default_messages = (\n            DialogueMessage(\n                DefaultMessage.Performative.BYTES, {\"content\": b\"some_content\"}\n            ),\n        )\n\n        cls.confirmed_aea = b\"ConfirmedAEA\"\n        cls.developer_handle = b\"DeveloperHandle\"\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the default handler.\"\"\"\n        assert self.default_handler.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle_unidentified_dialogue(self):\n        \"\"\"Test the _handle_unidentified_dialogue method of the register handler.\"\"\"\n        # setup\n        incorrect_dialogue_reference = (\"\", \"\")\n        incoming_message = self.build_incoming_message(\n            message_type=DefaultMessage,\n            dialogue_reference=incorrect_dialogue_reference,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"some_content\",\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.default_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received invalid default message={incoming_message}, unidentified dialogue.\",\n        )\n\n    def test_handle_bytes_i(self):\n        \"\"\"Test the _handle_bytes method of the default handler where the sender IS aw1_aea.\"\"\"\n        # setup\n        incoming_message = cast(\n            DefaultMessage,\n            self.build_incoming_message(\n                message_type=DefaultMessage,\n                performative=DefaultMessage.Performative.BYTES,\n                content=self.confirmed_aea + b\"_\" + self.developer_handle,\n                sender=self.aw1_aea,\n            ),\n        )\n\n        # operation\n        with patch.object(LedgerApis, \"is_valid_address\", return_value=True):\n            with patch.object(self.logger, \"log\") as mock_logger:\n                with patch.object(\n                    self.strategy, \"register_counterparty\"\n                ) as mock_register:\n                    self.default_handler.handle(incoming_message)\n\n        # after\n        mock_register.called_once()\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"adding confirmed_aea={self.confirmed_aea.decode('utf-8')} with developer_handle={self.developer_handle.decode('utf-8')} to db.\",\n        )\n\n    def test_handle_bytes_ii(self):\n        \"\"\"Test the _handle_bytes method of the default handler where the content is undecodable.\"\"\"\n        # setup\n        incorrect_content = \"some_incorrect_content\"\n\n        incoming_message = cast(\n            DefaultMessage,\n            self.build_incoming_message(\n                message_type=DefaultMessage,\n                performative=DefaultMessage.Performative.BYTES,\n                content=incorrect_content,\n                sender=self.aw1_aea,\n            ),\n        )\n\n        # operation\n        with patch.object(LedgerApis, \"is_valid_address\", return_value=True):\n            with patch.object(self.logger, \"log\") as mock_logger:\n                with patch.object(\n                    self.strategy, \"register_counterparty\"\n                ) as mock_register:\n                    self.default_handler.handle(incoming_message)\n\n        # after\n        mock_register.called_once()\n\n        mock_logger.assert_any_call(\n            logging.WARNING, \"received invalid developer_handle=.\"\n        )\n\n    def test_handle_bytes_iii(self):\n        \"\"\"Test the _handle_bytes method of the default handler where is_valid_address is False.\"\"\"\n        # setup\n        incoming_message = cast(\n            DefaultMessage,\n            self.build_incoming_message(\n                message_type=DefaultMessage,\n                performative=DefaultMessage.Performative.BYTES,\n                content=self.confirmed_aea + b\"_\" + self.developer_handle,\n                sender=self.aw1_aea,\n            ),\n        )\n\n        # operation\n        with patch.object(LedgerApis, \"is_valid_address\", return_value=False):\n            with patch.object(self.logger, \"log\") as mock_logger:\n                with patch.object(\n                    self.strategy, \"register_counterparty\"\n                ) as mock_register:\n                    self.default_handler.handle(incoming_message)\n\n        # after\n        mock_register.called_once()\n\n        default_dialogue = cast(\n            DefaultDialogue, self.default_dialogues.get_dialogue(incoming_message)\n        )\n\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"received invalid address={self.confirmed_aea.decode('utf-8')} in dialogue={default_dialogue}.\",\n        )\n\n    def test_handle_bytes_iv(self):\n        \"\"\"Test the _handle_bytes method of the default handler where the sender is NOT aw1_aea.\"\"\"\n        # setup\n        incoming_message = cast(\n            DefaultMessage,\n            self.build_incoming_message(\n                message_type=DefaultMessage,\n                performative=DefaultMessage.Performative.BYTES,\n                content=self.confirmed_aea + b\"_\" + self.developer_handle,\n                sender=\"some_other_aea\",\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            with patch.object(self.strategy, \"register_counterparty\") as mock_register:\n                self.default_handler.handle(incoming_message)\n\n        # after\n        mock_register.called_once()\n\n        default_dialogue = cast(\n            DefaultDialogue, self.default_dialogues.get_dialogue(incoming_message)\n        )\n\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"cannot handle default message of performative={incoming_message.performative} in dialogue={default_dialogue}. Invalid sender={incoming_message.sender}\",\n        )\n\n    def test_handle_invalid(self):\n        \"\"\"Test the _handle_invalid method of the default handler.\"\"\"\n        # setup\n        default_dialogue = cast(\n            DefaultDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.default_dialogues,\n                messages=self.list_of_default_messages[:1],\n            ),\n        )\n        incoming_message = cast(\n            DefaultMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=default_dialogue,\n                performative=DefaultMessage.Performative.ERROR,\n                error_code=DefaultMessage.ErrorCode.DECODING_ERROR,\n                error_msg=\"some_error_message\",\n                error_data={\"some_key\": b\"some_value\"},\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.default_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"cannot handle default message of performative={incoming_message.performative} in dialogue={default_dialogue}.\",\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the default handler.\"\"\"\n        assert self.default_handler.teardown() is None\n        self.assert_quantity_in_outbox(0)\n\n\nclass TestHttpHandler(ConfirmationAW3TestCase):\n    \"\"\"Test http handler of confirmation aw3.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"confirmation_aw3\")\n    is_agent_to_agent_messages = False\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.http_handler = cast(\n            HttpHandler, cls._skill.skill_context.handlers.http_handler\n        )\n        cls.logger = cls._skill.skill_context.logger\n        cls.strategy = cast(Strategy, cls._skill.skill_context.strategy)\n\n        cls.http_dialogues = cast(\n            HttpDialogues, cls._skill.skill_context.http_dialogues\n        )\n\n        cls.method = \"some_method\"\n        cls.url = \"some_url\"\n        cls.version = \"some_version\"\n        cls.headers = \"some_headers\"\n        cls.body = b\"some_body\"\n\n        cls.list_of_http_messages = (\n            DialogueMessage(\n                HttpMessage.Performative.REQUEST,\n                {\n                    \"method\": cls.method,\n                    \"url\": cls.url,\n                    \"version\": cls.version,\n                    \"headers\": cls.headers,\n                    \"body\": cls.body,\n                },\n            ),\n        )\n\n        cls.confirmed_aea = b\"ConfirmedAEA\"\n        cls.developer_handle = b\"DeveloperHandle\"\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the http handler.\"\"\"\n        assert self.http_handler.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle_unidentified_dialogue(self):\n        \"\"\"Test the _handle_unidentified_dialogue method of the register handler.\"\"\"\n        # setup\n        incorrect_dialogue_reference = (\"\", \"\")\n        incoming_message = self.build_incoming_message(\n            message_type=HttpMessage,\n            dialogue_reference=incorrect_dialogue_reference,\n            performative=HttpMessage.Performative.RESPONSE,\n            version=self.version,\n            status_code=200,\n            status_text=\"some_status_text\",\n            headers=self.headers,\n            body=self.body,\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.http_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received invalid http message={incoming_message}, unidentified dialogue.\",\n        )\n\n    def test__handle_response(self):\n        \"\"\"Test the _handle_bytes method of the http handler where the sender IS aw1_aea.\"\"\"\n        # setup\n        status_code = 200\n        status_text = \"some_status_text\"\n\n        http_dialogue = cast(\n            HttpDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.http_dialogues,\n                messages=self.list_of_http_messages[:1],\n            ),\n        )\n\n        incoming_message = cast(\n            HttpMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=http_dialogue,\n                performative=HttpMessage.Performative.RESPONSE,\n                version=self.version,\n                status_code=status_code,\n                status_text=status_text,\n                headers=self.headers,\n                body=self.body,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.http_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            \"received http response with status_code={}, status_text={} and body={!r} in dialogue={}\".format(\n                status_code, status_text, self.body, http_dialogue\n            ),\n        )\n\n    def test_handle_invalid(self):\n        \"\"\"Test the _handle_invalid method of the http handler.\"\"\"\n        # setup\n        incoming_message = cast(\n            HttpMessage,\n            self.build_incoming_message(\n                message_type=HttpMessage,\n                performative=HttpMessage.Performative.REQUEST,\n                method=self.method,\n                url=self.url,\n                version=self.version,\n                headers=self.headers,\n                body=self.body,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.http_handler.handle(incoming_message)\n\n        # after\n        http_dialogue = cast(\n            HttpDialogue, self.http_dialogues.get_dialogue(incoming_message)\n        )\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"cannot handle http message of performative={incoming_message.performative} in dialogue={http_dialogue}.\",\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the http handler.\"\"\"\n        assert self.http_handler.teardown() is None\n        self.assert_quantity_in_outbox(0)\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_confirmation_aw3/test_registration_db.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the RegistrationDB class of the confirmation aw3 skill.\"\"\"\nimport datetime\nimport json\nfrom pathlib import Path\nfrom unittest.mock import patch\n\nimport pytest\n\nfrom packages.fetchai.skills.confirmation_aw3.registration_db import RegistrationDB\n\nfrom tests.conftest import ROOT_DIR\nfrom tests.test_packages.test_skills.test_confirmation_aw3.intermediate_class import (\n    ConfirmationAW3TestCase,\n)\n\n\nclass TestStrategy(ConfirmationAW3TestCase):\n    \"\"\"Test RegistrationDB of confirmation aw3.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"confirmation_aw3\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.custom_path = None\n        cls.db = RegistrationDB(\n            custom_path=cls.custom_path,\n            name=\"strategy\",\n            skill_context=cls._skill.skill_context,\n        )\n\n        cls.address = \"some_address\"\n        cls.timestamp = datetime.datetime.now()\n        cls.data = {\"some_key_1\": \"some_value_1\", \"some_key_2\": \"some_value_2\"}\n        cls.developer_handle = \"developer_handle\"\n\n    def test_set_trade(self):\n        \"\"\"Test the set_trade method of the RegistrationDB class.\"\"\"\n        # operation\n        with patch.object(self.db, \"_execute_single_sql\") as mock_exe:\n            self.db.set_trade(\n                self.address,\n                self.timestamp,\n                self.data,\n            )\n\n        # after\n        mock_exe.assert_any_call(\n            \"INSERT INTO trades_table(address, created_at, data) values(?, ?, ?)\",\n            (self.address, self.timestamp, json.dumps(self.data)),\n        )\n\n    def test_get_trade_count(self):\n        \"\"\"Test the get_trade_count method of the RegistrationDB class.\"\"\"\n        # setup\n        result = [[\"1\", \"2\"], [\"3\", \"4\"]]\n\n        # operation\n        with patch.object(\n            self.db, \"_execute_single_sql\", return_value=result\n        ) as mock_exe:\n            actual_result = self.db.get_trade_count(\n                self.address,\n            )\n\n        # after\n        mock_exe.assert_any_call(\n            \"SELECT COUNT(*) FROM trades_table where address=?\",\n            (self.address,),\n        )\n        assert actual_result == 1\n\n    def test_get_developer_handle_i(self):\n        \"\"\"Test the get_developer_handle method of the RegistrationDB class which succeeds.\"\"\"\n        # setup\n        result = [[\"developer_handle\"], [\"something_1\", \"something_2\"]]\n\n        # operation\n        with patch.object(\n            self.db, \"_execute_single_sql\", return_value=result\n        ) as mock_exe:\n            actual_result = self.db.get_developer_handle(\n                self.address,\n            )\n\n        # after\n        mock_exe.assert_any_call(\n            \"SELECT developer_handle FROM registered_table where address=?\",\n            (self.address,),\n        )\n        assert actual_result == \"developer_handle\"\n\n    def test_get_developer_handle_ii(self):\n        \"\"\"Test the get_developer_handle method of the RegistrationDB class where the length of result[0] != 1.\"\"\"\n        # setup\n        result = [[\"developer_handle\", \"something_1\"], [\"something_2\", \"something_3\"]]\n\n        # operation\n        with patch.object(\n            self.db, \"_execute_single_sql\", return_value=result\n        ) as mock_exe:\n            with pytest.raises(\n                ValueError,\n                match=f\"More than one developer_handle found for address={self.address}.\",\n            ):\n                self.db.get_developer_handle(self.address)\n\n        # after\n        mock_exe.assert_any_call(\n            \"SELECT developer_handle FROM registered_table where address=?\",\n            (self.address,),\n        )\n\n    def test_get_addresses_i(self):\n        \"\"\"Test the get_addresses method of the RegistrationDB class where there are more than 0 addresses.\"\"\"\n        # setup\n        result = [[\"address_1\", \"something_1\"], [\"address_2\", \"something_2\"]]\n\n        # operation\n        with patch.object(\n            self.db, \"_execute_single_sql\", return_value=result\n        ) as mock_exe:\n            actual_addresses = self.db.get_addresses(\n                self.developer_handle,\n            )\n\n        # after\n        mock_exe.assert_any_call(\n            \"SELECT address FROM registered_table where developer_handle=?\",\n            (self.developer_handle,),\n        )\n        assert actual_addresses == [\"address_1\", \"address_2\"]\n\n    def test_get_addresses_ii(self):\n        \"\"\"Test the get_addresses method of the RegistrationDB class where there are 0 addresses.\"\"\"\n        # setup\n        result = []\n\n        # operation\n        with patch.object(\n            self.db, \"_execute_single_sql\", return_value=result\n        ) as mock_exe:\n            with pytest.raises(\n                ValueError,\n                match=f\"Should find at least one address for developer_handle={self.developer_handle}.\",\n            ):\n                self.db.get_addresses(\n                    self.developer_handle,\n                )\n\n        # after\n        mock_exe.assert_any_call(\n            \"SELECT address FROM registered_table where developer_handle=?\",\n            (self.developer_handle,),\n        )\n\n    def test_get_handle_and_trades(self):\n        \"\"\"Test the get_handle_and_trades method of the RegistrationDB class.\"\"\"\n        # setup\n        result = [\"address_1\", \"address_2\"]\n        trade_counts = [2, 5]\n\n        # operation\n        with patch.object(\n            self.db, \"get_developer_handle\", return_value=self.developer_handle\n        ) as mock_developer_handle:\n            with patch.object(\n                self.db, \"get_addresses\", return_value=result\n            ) as mock_addresses:\n                with patch.object(\n                    self.db, \"get_trade_count\", side_effect=trade_counts\n                ) as mock_trade_counts:\n                    actual_addresses = self.db.get_handle_and_trades(\n                        self.address,\n                    )\n\n        # after\n        mock_developer_handle.assert_any_call(self.address)\n        mock_addresses.assert_any_call(self.developer_handle)\n        mock_trade_counts.assert_called()\n\n        assert actual_addresses == (self.developer_handle, sum(trade_counts))\n\n    def test_get_all_addresses_and_handles(self):\n        \"\"\"Test the get_all_addresses_and_handles method of the RegistrationDB class.\"\"\"\n        # setup\n        result = [(\"address_1\", \"something_1\"), (\"address_2\", \"something_2\")]\n\n        # operation\n        with patch.object(\n            self.db, \"_execute_single_sql\", return_value=result\n        ) as mock_exe:\n            actual_result = self.db.get_all_addresses_and_handles()\n\n        # after\n        mock_exe.assert_any_call(\n            \"SELECT address, developer_handle FROM registered_table\", ()\n        )\n        assert actual_result == result\n\n    def test_get_leaderboard_i(self):\n        \"\"\"Test the get_leaderboard method of the RegistrationDB class where none of the number of trades are 0.\"\"\"\n        # setup\n        addresses_and_handlers = [\n            (\"address_1\", \"handler_1\"),\n            (\"address_2\", \"handler_2\"),\n        ]\n        trade_counts = [2, 5]\n\n        expected_result = [(\"address_2\", \"handler_2\", 5), (\"address_1\", \"handler_1\", 2)]\n\n        # operation\n        with patch.object(\n            self.db,\n            \"get_all_addresses_and_handles\",\n            return_value=addresses_and_handlers,\n        ) as mock_get_addresses:\n            with patch.object(\n                self.db, \"get_trade_count\", side_effect=trade_counts\n            ) as mock_trade_counts:\n                actual_result = self.db.get_leaderboard()\n\n        # after\n        mock_get_addresses.assert_called_once()\n        mock_trade_counts.assert_called()\n\n        assert actual_result == expected_result\n\n    def test_get_leaderboard_ii(self):\n        \"\"\"Test the get_leaderboard method of the RegistrationDB class where some number of trades are 0.\"\"\"\n        # setup\n        addresses_and_handlers = [\n            (\"address_1\", \"handler_1\"),\n            (\"address_2\", \"handler_2\"),\n        ]\n        trade_counts = [2, 0]\n\n        expected_result = [(\"address_1\", \"handler_1\", 2)]\n\n        # operation\n        with patch.object(\n            self.db,\n            \"get_all_addresses_and_handles\",\n            return_value=addresses_and_handlers,\n        ) as mock_get_addresses:\n            with patch.object(\n                self.db, \"get_trade_count\", side_effect=trade_counts\n            ) as mock_trade_counts:\n                actual_result = self.db.get_leaderboard()\n\n        # after\n        mock_get_addresses.assert_called_once()\n        mock_trade_counts.assert_called()\n\n        assert actual_result == expected_result\n\n    def test_set_registered_i(self):\n        \"\"\"Test the set_registered method of the RegistrationDB class where is_registered is False.\"\"\"\n        # operation\n        with patch.object(\n            self.db, \"is_registered\", return_value=False\n        ) as mock_registered:\n            with patch.object(self.db, \"_execute_single_sql\") as mock_exe:\n                self.db.set_registered(self.address, self.developer_handle)\n\n        # after\n        mock_registered.assert_any_call(self.address)\n        mock_exe.assert_any_call(\n            \"INSERT OR REPLACE INTO registered_table(address, ethereum_address, ethereum_signature, fetchai_signature, developer_handle, tweet) values(?, ?, ?, ?, ?, ?)\",\n            (self.address, \"\", \"\", \"\", self.developer_handle, \"\"),\n        )\n\n    def test_set_registered_ii(self):\n        \"\"\"Test the set_registered method of the RegistrationDB class where is_registered is True.\"\"\"\n        # operation\n        with patch.object(\n            self.db, \"is_registered\", return_value=True\n        ) as mock_registered:\n            with patch.object(self.db, \"_execute_single_sql\") as mock_exe:\n                self.db.set_registered(self.address, self.developer_handle)\n\n        # after\n        mock_registered.assert_any_call(self.address)\n        mock_exe.assert_not_called()\n\n    def test_is_registered_i(self):\n        \"\"\"Test the is_registered method of the RegistrationDB class where result's length is more than 0.\"\"\"\n        # setup\n        result = [(\"address_1\", \"something_1\"), (\"address_2\", \"something_2\")]\n\n        # operation\n        with patch.object(\n            self.db, \"_execute_single_sql\", return_value=result\n        ) as mock_exe:\n            is_registered = self.db.is_registered(self.address)\n\n        # after\n        mock_exe.assert_any_call(\n            \"SELECT * FROM registered_table WHERE address=?\",\n            (self.address,),\n        )\n        assert is_registered is True\n\n    def test_is_registered_ii(self):\n        \"\"\"Test the is_registered method of the RegistrationDB class where result's length is 0.\"\"\"\n        # setup\n        result = []\n\n        # operation\n        with patch.object(\n            self.db, \"_execute_single_sql\", return_value=result\n        ) as mock_exe:\n            is_registered = self.db.is_registered(self.address)\n\n        # after\n        mock_exe.assert_any_call(\n            \"SELECT * FROM registered_table WHERE address=?\",\n            (self.address,),\n        )\n        assert is_registered is False\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_confirmation_aw3/test_strategy.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the strategy class of the confirmation aw3 skill.\"\"\"\n\nimport datetime\nimport json\nimport logging\nfrom pathlib import Path\nfrom typing import cast\nfrom unittest.mock import Mock, patch\n\nimport pytest\n\nfrom packages.fetchai.protocols.http.message import HttpMessage\nfrom packages.fetchai.skills.confirmation_aw3.registration_db import RegistrationDB\nfrom packages.fetchai.skills.confirmation_aw3.strategy import (\n    HTTP_CLIENT_PUBLIC_ID,\n    Strategy,\n)\n\nfrom tests.conftest import ROOT_DIR\nfrom tests.test_packages.test_skills.test_confirmation_aw3.intermediate_class import (\n    ConfirmationAW3TestCase,\n)\n\n\nclass TestStrategy(ConfirmationAW3TestCase):\n    \"\"\"Test Strategy of confirmation aw3.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"confirmation_aw3\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n\n        cls.location_name = \"berlin\"\n        cls.locations = {\n            cls.location_name: {\"latitude\": 52.52, \"longitude\": 13.405},\n        }\n        cls.search_query_type = \"weather\"\n        cls.search_queries = {\n            cls.search_query_type: {\n                \"constraint_type\": \"==\",\n                \"search_key\": \"seller_service\",\n                \"search_value\": \"weather_data\",\n            },\n        }\n        cls.leaderboard_url = \"some_url\"\n        cls.leaderboard_token = \"some_token\"  # nosec\n\n        cls.strategy = Strategy(\n            aw1_aea=\"some_aw1_aea\",\n            locations=cls.locations,\n            search_queries=cls.search_queries,\n            leaderboard_url=cls.leaderboard_url,\n            leaderboard_token=cls.leaderboard_token,\n            name=\"strategy\",\n            skill_context=cls._skill.skill_context,\n        )\n\n        cls.address = \"some_address\"\n        cls.info = {\n            \"ethereum_address\": \"some_value\",\n            \"signature_of_ethereum_address\": \"some_signature_of_ethereum_address\",\n            \"signature_of_fetchai_address\": \"some_signature_of_fetchai_address\",\n            \"developer_handle\": \"some_developer_handle\",\n            \"tweet\": \"some_tweet\",\n        }\n        cls.logger = cls._skill.skill_context.logger\n        cls.db = cast(RegistrationDB, cls._skill.skill_context.registration_db)\n\n        cls.counterparty = \"couterparty_1\"\n\n    def test__init__i(self):\n        \"\"\"Test the __init__ of Strategy class.\"\"\"\n        assert self.strategy.aw1_aea == self.aw1_aea\n        assert self.strategy._locations == self.locations\n        assert self.strategy._search_queries == self.search_queries\n        assert self.strategy.leaderboard_url == f\"{self.leaderboard_url}/insert\"\n        assert self.strategy.leaderboard_token == self.leaderboard_token\n\n    def test__init__ii(self):\n        \"\"\"Test the __init__ of Strategy class where aw1_aea is None.\"\"\"\n        with pytest.raises(ValueError, match=\"aw1_aea must be provided!\"):\n            Strategy(\n                aw1_aea=None,\n                locations=self.locations,\n                search_queries=self.search_queries,\n                leaderboard_url=self.leaderboard_url,\n                leaderboard_token=self.leaderboard_token,\n                name=\"strategy\",\n                skill_context=self.skill.skill_context,\n            )\n\n    def test__init__iii(self):\n        \"\"\"Test the __init__ of Strategy class where length of locations is 0.\"\"\"\n        with pytest.raises(ValueError, match=\"locations must have at least one entry\"):\n            Strategy(\n                aw1_aea=\"some_aw1_aea\",\n                locations={},\n                search_queries=self.search_queries,\n                leaderboard_url=self.leaderboard_url,\n                leaderboard_token=self.leaderboard_token,\n                name=\"strategy\",\n                skill_context=self.skill.skill_context,\n            )\n\n    def test__init__iv(self):\n        \"\"\"Test the __init__ of Strategy class where length of search_queries is 0.\"\"\"\n        with pytest.raises(\n            ValueError, match=\"search_queries must have at least one entry\"\n        ):\n            Strategy(\n                aw1_aea=\"some_aw1_aea\",\n                locations=self.locations,\n                search_queries={},\n                leaderboard_url=self.leaderboard_url,\n                leaderboard_token=self.leaderboard_token,\n                name=\"strategy\",\n                skill_context=self.skill.skill_context,\n            )\n\n    def test__init__v(self):\n        \"\"\"Test the __init__ of Strategy class where leaderboard_url is None.\"\"\"\n        with pytest.raises(ValueError, match=\"No leader board url provided!\"):\n            Strategy(\n                aw1_aea=\"some_aw1_aea\",\n                locations=self.locations,\n                search_queries=self.search_queries,\n                leaderboard_url=None,\n                leaderboard_token=self.leaderboard_token,\n                name=\"strategy\",\n                skill_context=self.skill.skill_context,\n            )\n\n    def test__init__vi(self):\n        \"\"\"Test the __init__ of Strategy class where leaderboard_token is None.\"\"\"\n        with pytest.raises(ValueError, match=\"No leader board token provided!\"):\n            Strategy(\n                aw1_aea=\"some_aw1_aea\",\n                locations=self.locations,\n                search_queries=self.search_queries,\n                leaderboard_url=self.leaderboard_url,\n                leaderboard_token=None,\n                name=\"strategy\",\n                skill_context=self.skill.skill_context,\n            )\n\n    def test_get_acceptable_counterparties(self):\n        \"\"\"Test the get_acceptable_counterparties method of the Strategy class.\"\"\"\n        # setup\n        couterparties = (\"couterparty_1\", \"couterparty_2\", \"couterparty_3\")\n        is_valid_counterparty = [True, False, True]\n\n        # operation\n        with patch.object(\n            self.strategy, \"is_valid_counterparty\", side_effect=is_valid_counterparty\n        ):\n            actual_acceptable_counterparties = (\n                self.strategy.get_acceptable_counterparties(couterparties)\n            )\n\n        # after\n        assert actual_acceptable_counterparties == (\"couterparty_1\", \"couterparty_3\")\n\n    def test_is_valid_counterparty_i(self):\n        \"\"\"Test the is_valid_counterparty method of the Strategy class where is_registered is False.\"\"\"\n        # operation\n        with patch.object(\n            self.db, \"is_registered\", return_value=False\n        ) as mock_is_regostered:\n            with patch.object(self.logger, \"log\") as mock_logger:\n                is_valid = self.strategy.is_valid_counterparty(self.counterparty)\n\n        # after\n        mock_is_regostered.assert_any_call(self.counterparty)\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"Invalid counterparty={self.counterparty}, not registered!\",\n        )\n        assert is_valid is False\n\n    def test_is_valid_counterparty_ii(self):\n        \"\"\"Test the is_valid_counterparty method of the Strategy class where is_registered is True.\"\"\"\n        # operation\n        with patch.object(\n            self.db, \"is_registered\", return_value=True\n        ) as mock_is_regostered:\n            is_valid = self.strategy.is_valid_counterparty(self.counterparty)\n\n        # after\n        mock_is_regostered.assert_any_call(self.counterparty)\n        assert is_valid is True\n\n    def test_successful_trade_with_counterparty(self):\n        \"\"\"Test the successful_trade_with_counterparty method of the Strategy class.\"\"\"\n        # setup\n        data = {\"some_key_1\": \"some_value_1\", \"some_key_2\": \"some_value_2\"}\n        developer_handle = \"some_developer_handle\"\n        nb_trades = 5\n\n        mocked_now_str = \"2020-12-22 20:33:00.000000\"\n        mock_now = datetime.datetime.strptime(mocked_now_str, \"%Y-%m-%d %H:%M:%S.%f\")\n        datetime_mock = Mock(wraps=datetime.datetime)\n        datetime_mock.now.return_value = mock_now\n\n        # operation\n        with patch.object(self.db, \"set_trade\") as mock_set_trade:\n            with patch(\"datetime.datetime\", new=datetime_mock):\n                with patch.object(self.logger, \"log\") as mock_logger:\n                    with patch.object(\n                        self.db,\n                        \"get_handle_and_trades\",\n                        return_value=(developer_handle, nb_trades),\n                    ) as mock_handle:\n                        self.strategy.successful_trade_with_counterparty(\n                            self.counterparty, data\n                        )\n\n        # after\n        mock_set_trade.assert_any_call(self.counterparty, mock_now, data)\n        mock_handle.assert_any_call(self.counterparty)\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"Successful trade with={self.counterparty}.\",\n        )\n\n        self.assert_quantity_in_outbox(1)\n\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=HttpMessage,\n            performative=HttpMessage.Performative.REQUEST,\n            to=str(HTTP_CLIENT_PUBLIC_ID),\n            sender=str(self.skill.skill_context.skill_id),\n            method=\"POST\",\n            url=self.strategy.leaderboard_url,\n            headers=\"Content-Type: application/json; charset=utf-8\",\n            version=\"\",\n            body=json.dumps(\n                {\n                    \"name\": developer_handle,\n                    \"points\": nb_trades,\n                    \"token\": self.leaderboard_token,\n                }\n            ).encode(\"utf-8\"),\n        )\n        assert has_attributes, error_str\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"Notifying leaderboard: developer_handle={developer_handle}, nb_trades={nb_trades}.\",\n        )\n\n    def test_register_counterparty(self):\n        \"\"\"Test the register_counterparty method of the Strategy class.\"\"\"\n        # setup\n        developer_handle = \"some_developer_handle\"\n\n        # operation\n        with patch.object(self.db, \"set_registered\") as mock_set_registered:\n            self.strategy.register_counterparty(self.counterparty, developer_handle)\n\n        # after\n        mock_set_registered.assert_any_call(self.counterparty, developer_handle)\n\n    def test_update_search_query_params(self):\n        \"\"\"Test the update_search_query_params method of the Strategy class.\"\"\"\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.strategy.update_search_query_params()\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"New search_type={self.search_query_type} and location={self.location_name}.\",\n        )\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_erc1155_deploy/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"The tests module contains the tests of the packages/skills/erc1155_deploy dir.\"\"\"\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_erc1155_deploy/intermediate_class.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module sets up test environment for erc1155_deploy skill.\"\"\"\n\nfrom pathlib import Path\nfrom typing import cast\n\nfrom aea.helpers.search.models import (\n    Attribute,\n    Constraint,\n    ConstraintType,\n    DataModel,\n    Description,\n    Location,\n    Query,\n)\nfrom aea.helpers.transaction.base import (\n    RawMessage,\n    RawTransaction,\n    SignedTransaction,\n    Terms,\n    TransactionDigest,\n    TransactionReceipt,\n)\nfrom aea.protocols.dialogue.base import DialogueMessage\nfrom aea.test_tools.test_skill import BaseSkillTestCase\n\nfrom packages.fetchai.protocols.contract_api.custom_types import Kwargs\nfrom packages.fetchai.protocols.contract_api.message import ContractApiMessage\nfrom packages.fetchai.protocols.fipa.message import FipaMessage\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.protocols.signing.message import SigningMessage\nfrom packages.fetchai.skills.erc1155_deploy.behaviours import (\n    ServiceRegistrationBehaviour,\n)\nfrom packages.fetchai.skills.erc1155_deploy.dialogues import (\n    ContractApiDialogues,\n    DefaultDialogues,\n    FipaDialogues,\n    LedgerApiDialogues,\n    OefSearchDialogues,\n    SigningDialogues,\n)\nfrom packages.fetchai.skills.erc1155_deploy.handlers import (\n    ContractApiHandler,\n    FipaHandler,\n    LedgerApiHandler,\n    OefSearchHandler,\n    SigningHandler,\n)\nfrom packages.fetchai.skills.erc1155_deploy.strategy import Strategy\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass ERC1155DeployTestCase(BaseSkillTestCase):\n    \"\"\"Sets the erc1155_deploy class up for testing.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"erc1155_deploy\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        cls.location = {\"longitude\": 0.1270, \"latitude\": 51.5194}\n        cls.mint_quantities = [100, 100, 100, 100, 100, 100, 100, 100, 100, 100]\n        cls.service_data = {\"key\": \"seller_service\", \"value\": \"some_value\"}\n        cls.personality_data = {\"piece\": \"genus\", \"value\": \"some_personality\"}\n        cls.classification = {\"piece\": \"classification\", \"value\": \"some_classification\"}\n        cls.from_supply = 756\n        cls.to_supply = 12\n        cls.value = 87\n        cls.token_type = 2\n        config_overrides = {\n            \"models\": {\n                \"strategy\": {\n                    \"args\": {\n                        \"location\": cls.location,\n                        \"mint_quantities\": cls.mint_quantities,\n                        \"service_data\": cls.service_data,\n                        \"personality_data\": cls.personality_data,\n                        \"classification\": cls.classification,\n                        \"from_supply\": cls.from_supply,\n                        \"to_supply\": cls.to_supply,\n                        \"value\": cls.value,\n                        \"token_type\": cls.token_type,\n                    }\n                }\n            },\n        }\n\n        super().setup(config_overrides=config_overrides)\n\n        # behaviours\n        cls.registration_behaviour = cast(\n            ServiceRegistrationBehaviour,\n            cls._skill.skill_context.behaviours.service_registration,\n        )\n\n        # dialogues\n        cls.contract_api_dialogues = cast(\n            ContractApiDialogues, cls._skill.skill_context.contract_api_dialogues\n        )\n        cls.default_dialogues = cast(\n            DefaultDialogues, cls._skill.skill_context.default_dialogues\n        )\n        cls.fipa_dialogues = cast(\n            FipaDialogues, cls._skill.skill_context.fipa_dialogues\n        )\n        cls.ledger_api_dialogues = cast(\n            LedgerApiDialogues, cls._skill.skill_context.ledger_api_dialogues\n        )\n        cls.oef_search_dialogues = cast(\n            OefSearchDialogues, cls._skill.skill_context.oef_search_dialogues\n        )\n        cls.signing_dialogues = cast(\n            SigningDialogues, cls._skill.skill_context.signing_dialogues\n        )\n\n        # handlers\n        cls.fipa_handler = cast(FipaHandler, cls._skill.skill_context.handlers.fipa)\n        cls.oef_search_handler = cast(\n            OefSearchHandler, cls._skill.skill_context.handlers.oef_search\n        )\n        cls.contract_api_handler = cast(\n            ContractApiHandler, cls._skill.skill_context.handlers.contract_api\n        )\n        cls.signing_handler = cast(\n            SigningHandler, cls._skill.skill_context.handlers.signing\n        )\n        cls.ledger_api_handler = cast(\n            LedgerApiHandler, cls._skill.skill_context.handlers.ledger_api\n        )\n\n        # models\n        cls.strategy = cast(Strategy, cls._skill.skill_context.strategy)\n\n        cls.logger = cls._skill.skill_context.logger\n\n        # mocked objects\n        cls.ledger_id = \"some_ledger_id\"\n        cls.contract_id = \"some_contract_id\"\n        cls.contract_address = \"some_contract_address\"\n        cls.callable = \"some_callable\"\n        cls.body_dict = {\"some_key\": \"some_value\"}\n        cls.body_str = \"some_body\"\n        cls.body_bytes = b\"some_body\"\n        cls.kwargs = Kwargs(cls.body_dict)\n        cls.address = \"some_address\"\n\n        cls.mocked_terms = Terms(\n            cls.ledger_id,\n            cls._skill.skill_context.agent_address,\n            \"counterprty\",\n            {\"currency_id\": 50},\n            {\"good_id\": -10},\n            \"some_nonce\",\n        )\n        cls.mocked_query = Query(\n            [Constraint(\"some_attribute_name\", ConstraintType(\"==\", \"some_value\"))],\n            DataModel(\n                \"some_data_model_name\",\n                [\n                    Attribute(\n                        \"some_attribute_name\",\n                        str,\n                        False,\n                        \"Some attribute descriptions.\",\n                    )\n                ],\n            ),\n        )\n        cls.mocked_proposal = Description(\n            {\n                \"contract_address\": \"some_contract_address\",\n                \"token_id\": \"123456\",\n                \"trade_nonce\": \"876438756348568\",\n                \"from_supply\": \"543\",\n                \"to_supply\": \"432\",\n                \"value\": \"67\",\n            }\n        )\n        cls.mocked_registration_description = Description({\"foo1\": 1, \"bar1\": 2})\n\n        cls.mocked_raw_tx = RawTransaction(cls.ledger_id, cls.body_dict)\n        cls.mocked_raw_msg = RawMessage(cls.ledger_id, cls.body_bytes)\n        cls.mocked_tx_digest = TransactionDigest(cls.ledger_id, cls.body_str)\n        cls.mocked_signed_tx = SignedTransaction(cls.ledger_id, cls.body_dict)\n        cls.mocked_tx_receipt = TransactionReceipt(\n            cls.ledger_id,\n            {\"receipt_key\": \"receipt_value\", \"contractAddress\": cls.contract_address},\n            {\"transaction_key\": \"transaction_value\"},\n        )\n\n        cls.registration_message = OefSearchMessage(\n            dialogue_reference=(\"\", \"\"),\n            performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n            service_description=cls.mocked_registration_description,\n        )\n        cls.registration_message.sender = str(cls._skill.skill_context.skill_id)\n        cls.registration_message.to = cls._skill.skill_context.search_service_address\n\n        # list of messages\n        cls.list_of_fipa_messages = (\n            DialogueMessage(FipaMessage.Performative.CFP, {\"query\": cls.mocked_query}),\n            DialogueMessage(\n                FipaMessage.Performative.PROPOSE, {\"proposal\": cls.mocked_proposal}\n            ),\n        )\n        cls.list_of_contract_api_messages = (\n            DialogueMessage(\n                ContractApiMessage.Performative.GET_RAW_TRANSACTION,\n                {\n                    \"ledger_id\": cls.ledger_id,\n                    \"contract_id\": cls.contract_id,\n                    \"contract_address\": cls.contract_address,\n                    \"callable\": cls.callable,\n                    \"kwargs\": cls.kwargs,\n                },\n            ),\n        )\n        cls.list_of_signing_messages = (\n            DialogueMessage(\n                SigningMessage.Performative.SIGN_TRANSACTION,\n                {\"terms\": cls.mocked_terms, \"raw_transaction\": cls.mocked_raw_tx},\n            ),\n        )\n        cls.list_of_ledger_api_balance_messages = (\n            DialogueMessage(\n                LedgerApiMessage.Performative.GET_BALANCE,\n                {\"ledger_id\": cls.ledger_id, \"address\": \"some_address\"},\n            ),\n        )\n\n        cls.list_of_ledger_api_messages = (\n            DialogueMessage(\n                LedgerApiMessage.Performative.GET_RAW_TRANSACTION,\n                {\"terms\": cls.mocked_terms},\n            ),\n            DialogueMessage(\n                LedgerApiMessage.Performative.RAW_TRANSACTION,\n                {\"raw_transaction\": cls.mocked_raw_tx},\n            ),\n            DialogueMessage(\n                LedgerApiMessage.Performative.SEND_SIGNED_TRANSACTION,\n                {\"signed_transaction\": cls.mocked_signed_tx},\n            ),\n            DialogueMessage(\n                LedgerApiMessage.Performative.TRANSACTION_DIGEST,\n                {\"transaction_digest\": cls.mocked_tx_digest},\n            ),\n            DialogueMessage(\n                LedgerApiMessage.Performative.GET_TRANSACTION_RECEIPT,\n                {\"transaction_digest\": cls.mocked_tx_digest},\n            ),\n            DialogueMessage(\n                LedgerApiMessage.Performative.TRANSACTION_RECEIPT,\n                {\"transaction_receipt\": cls.mocked_tx_receipt},\n            ),\n        )\n        cls.register_location_description = Description(\n            {\"location\": Location(51.5194, 0.1270)},\n            data_model=DataModel(\n                \"location_agent\", [Attribute(\"location\", Location, True)]\n            ),\n        )\n        cls.list_of_messages_register_location = (\n            DialogueMessage(\n                OefSearchMessage.Performative.REGISTER_SERVICE,\n                {\"service_description\": cls.register_location_description},\n                is_incoming=False,\n            ),\n        )\n\n        cls.register_service_description = Description(\n            {\"key\": \"some_key\", \"value\": \"some_value\"},\n            data_model=DataModel(\n                \"set_service_key\",\n                [Attribute(\"key\", str, True), Attribute(\"value\", str, True)],\n            ),\n        )\n        cls.list_of_messages_register_service = (\n            DialogueMessage(\n                OefSearchMessage.Performative.REGISTER_SERVICE,\n                {\"service_description\": cls.register_service_description},\n                is_incoming=False,\n            ),\n        )\n\n        cls.register_genus_description = Description(\n            {\"piece\": \"genus\", \"value\": \"some_value\"},\n            data_model=DataModel(\n                \"personality_agent\",\n                [Attribute(\"piece\", str, True), Attribute(\"value\", str, True)],\n            ),\n        )\n        cls.list_of_messages_register_genus = (\n            DialogueMessage(\n                OefSearchMessage.Performative.REGISTER_SERVICE,\n                {\"service_description\": cls.register_genus_description},\n                is_incoming=False,\n            ),\n        )\n\n        cls.register_classification_description = Description(\n            {\"piece\": \"classification\", \"value\": \"some_value\"},\n            data_model=DataModel(\n                \"personality_agent\",\n                [Attribute(\"piece\", str, True), Attribute(\"value\", str, True)],\n            ),\n        )\n        cls.list_of_messages_register_classification = (\n            DialogueMessage(\n                OefSearchMessage.Performative.REGISTER_SERVICE,\n                {\"service_description\": cls.register_classification_description},\n                is_incoming=False,\n            ),\n        )\n\n        cls.register_invalid_description = Description(\n            {\"piece\": \"classification\", \"value\": \"some_value\"},\n            data_model=DataModel(\n                \"some_different_name\",\n                [Attribute(\"piece\", str, True), Attribute(\"value\", str, True)],\n            ),\n        )\n        cls.list_of_messages_register_invalid = (\n            DialogueMessage(\n                OefSearchMessage.Performative.REGISTER_SERVICE,\n                {\"service_description\": cls.register_invalid_description},\n                is_incoming=False,\n            ),\n        )\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_erc1155_deploy/test_behaviours.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the behaviour classes of the erc1155_deploy skill.\"\"\"\n\nimport logging\nfrom typing import cast\nfrom unittest.mock import patch\n\nfrom packages.fetchai.protocols.contract_api.message import ContractApiMessage\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.skills.erc1155_deploy.behaviours import LEDGER_API_ADDRESS\nfrom packages.fetchai.skills.erc1155_deploy.dialogues import ContractApiDialogue\n\nfrom tests.test_packages.test_skills.test_erc1155_deploy.intermediate_class import (\n    ERC1155DeployTestCase,\n)\n\n\nclass TestServiceRegistrationBehaviour(ERC1155DeployTestCase):\n    \"\"\"Test registration behaviour of erc1155_deploy.\"\"\"\n\n    def test_init(self):\n        \"\"\"Test the __init__ method of the registration behaviour.\"\"\"\n        assert self.registration_behaviour.is_registered is False\n        assert self.registration_behaviour.registration_in_progress is False\n        assert self.registration_behaviour.failed_registration_msg is None\n        assert self.registration_behaviour._nb_retries == 0\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the registration behaviour.\"\"\"\n        # setup\n        self.strategy._is_contract_deployed = False\n\n        # before\n        assert self.strategy.is_behaviour_active is True\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.registration_behaviour.setup()\n\n        # after\n        self.assert_quantity_in_outbox(2)\n\n        # _request_balance\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=LedgerApiMessage,\n            performative=LedgerApiMessage.Performative.GET_BALANCE,\n            to=LEDGER_API_ADDRESS,\n            sender=str(self.skill.skill_context.skill_id),\n            ledger_id=self.strategy.ledger_id,\n            address=cast(\n                str,\n                self.skill.skill_context.agent_addresses.get(self.strategy.ledger_id),\n            ),\n        )\n        assert has_attributes, error_str\n\n        # _request_contract_deploy_transaction\n        assert self.strategy.is_behaviour_active is False\n\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=ContractApiMessage,\n            performative=ContractApiMessage.Performative.GET_DEPLOY_TRANSACTION,\n            to=LEDGER_API_ADDRESS,\n            sender=str(self.skill.skill_context.skill_id),\n            ledger_id=self.strategy.ledger_id,\n            contract_id=self.strategy.contract_id,\n            callable=\"get_deploy_transaction\",\n            kwargs=ContractApiMessage.Kwargs(\n                {\n                    \"deployer_address\": self.skill.skill_context.agent_address,\n                    \"gas\": self.strategy.gas,\n                }\n            ),\n        )\n        assert has_attributes, error_str\n\n        mock_logger.assert_any_call(\n            logging.INFO, \"requesting contract deployment transaction...\"\n        )\n\n    def test_act_i(self):\n        \"\"\"Test the act method of the registration behaviour where failed_registration_msg is NOT None.\"\"\"\n        # setup\n        self.registration_behaviour.failed_registration_msg = self.registration_message\n\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.registration_behaviour.act()\n\n        # after\n        self.assert_quantity_in_outbox(1)\n\n        # _retry_failed_registration\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=type(self.registration_message),\n            performative=self.registration_message.performative,\n            to=self.registration_message.to,\n            sender=str(self.skill.skill_context.skill_id),\n            service_description=self.registration_message.service_description,\n        )\n        assert has_attributes, error_str\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"Retrying registration on SOEF. Retry {self.registration_behaviour._nb_retries} out of {self.registration_behaviour._max_soef_registration_retries}.\",\n        )\n        assert self.registration_behaviour.failed_registration_msg is None\n\n    def test_act_ii(self):\n        \"\"\"Test the act method of the registration behaviour where failed_registration_msg is NOT None and max retries is reached.\"\"\"\n        # setup\n        self.registration_behaviour.failed_registration_msg = self.registration_message\n        self.registration_behaviour._max_soef_registration_retries = 2\n        self.registration_behaviour._nb_retries = 2\n\n        self.registration_behaviour.act()\n\n        # after\n        self.assert_quantity_in_outbox(0)\n        assert self.skill.skill_context.is_active is False\n\n    def test_act_iii(self):\n        \"\"\"Test the act method of the registration behaviour where is_behaviour_active IS False.\"\"\"\n        # setup\n        self.strategy.is_behaviour_active = False\n\n        # operation\n        self.registration_behaviour.act()\n\n        # after\n        self.assert_quantity_in_outbox(0)\n\n    def test_act_iv(self):\n        \"\"\"Test the act method of the registration behaviour where is_contract_deployed IS True and is_tokens_created IS False.\"\"\"\n        # setup\n        self.strategy.is_contract_deployed = True\n        self.strategy._is_tokens_created = False\n        self.strategy._contract_address = self.contract_address\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.registration_behaviour.act()\n\n        # after\n        self.assert_quantity_in_outbox(1)\n\n        assert self.strategy.is_behaviour_active is False\n\n        # _request_token_create_transaction\n        message = self.get_message_from_outbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=ContractApiMessage,\n            performative=ContractApiMessage.Performative.GET_RAW_TRANSACTION,\n            to=LEDGER_API_ADDRESS,\n            sender=str(self.skill.skill_context.skill_id),\n            ledger_id=self.strategy.ledger_id,\n            contract_id=self.strategy.contract_id,\n            contract_address=self.strategy.contract_address,\n            callable=\"get_create_batch_transaction\",\n            kwargs=ContractApiMessage.Kwargs(\n                {\n                    \"deployer_address\": self.skill.skill_context.agent_address,\n                    \"token_ids\": self.strategy.token_ids,\n                    \"gas\": self.strategy.gas,\n                }\n            ),\n        )\n        assert has_attributes, error_str\n\n        contract_api_dialogue = cast(\n            ContractApiDialogue, self.contract_api_dialogues.get_dialogue(message)\n        )\n        assert contract_api_dialogue.terms == self.strategy.get_create_token_terms()\n\n        mock_logger.assert_any_call(\n            logging.INFO, \"requesting create batch transaction...\"\n        )\n\n    def test_act_v(self):\n        \"\"\"Test the act method of the registration behaviour where is_contract_deployed IS True, is_tokens_created IS True and is_tokens_minted is False.\"\"\"\n        # setup\n        self.strategy.is_contract_deployed = True\n        self.strategy._is_tokens_created = True\n        self.strategy._is_tokens_minted = False\n        self.strategy._contract_address = self.contract_address\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.registration_behaviour.act()\n\n        # after\n        self.assert_quantity_in_outbox(1)\n\n        assert self.strategy.is_behaviour_active is False\n\n        # _request_token_mint_transaction\n        message = self.get_message_from_outbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=ContractApiMessage,\n            performative=ContractApiMessage.Performative.GET_RAW_TRANSACTION,\n            to=LEDGER_API_ADDRESS,\n            sender=str(self.skill.skill_context.skill_id),\n            ledger_id=self.strategy.ledger_id,\n            contract_id=self.strategy.contract_id,\n            contract_address=self.strategy.contract_address,\n            callable=\"get_mint_batch_transaction\",\n            kwargs=ContractApiMessage.Kwargs(\n                {\n                    \"deployer_address\": self.skill.skill_context.agent_address,\n                    \"recipient_address\": self.skill.skill_context.agent_address,\n                    \"token_ids\": self.strategy.token_ids,\n                    \"mint_quantities\": self.strategy.mint_quantities,\n                    \"gas\": self.strategy.gas,\n                }\n            ),\n        )\n        assert has_attributes, error_str\n\n        contract_api_dialogue = cast(\n            ContractApiDialogue, self.contract_api_dialogues.get_dialogue(message)\n        )\n        assert contract_api_dialogue.terms == self.strategy.get_mint_token_terms()\n\n        mock_logger.assert_any_call(\n            logging.INFO, \"requesting mint batch transaction...\"\n        )\n\n    def test_act_vi(self):\n        \"\"\"Test the act method of the registration behaviour where is_contract_deployed IS True, is_tokens_created IS True and is_tokens_minted is True and is_registered IS False.\"\"\"\n        # setup\n        self.strategy.is_contract_deployed = True\n        self.strategy._is_tokens_created = True\n        self.strategy._is_tokens_minted = True\n        self.strategy._contract_address = self.contract_address\n\n        # before\n        assert self.registration_behaviour.registration_in_progress is False\n\n        # operation\n        with patch.object(\n            self.strategy,\n            \"get_location_description\",\n            return_value=self.mocked_registration_description,\n        ) as mock_desc:\n            with patch.object(self.logger, \"log\") as mock_logger:\n                self.registration_behaviour.act()\n\n        # after\n        self.assert_quantity_in_outbox(1)\n\n        assert self.registration_behaviour.registration_in_progress is True\n\n        # _register_agent\n        mock_desc.assert_called_once()\n\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=OefSearchMessage,\n            performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n            to=self.skill.skill_context.search_service_address,\n            sender=str(self.skill.skill_context.skill_id),\n            service_description=self.mocked_registration_description,\n        )\n        assert has_attributes, error_str\n\n        mock_logger.assert_any_call(logging.INFO, \"registering agent on SOEF.\")\n\n    def test_register_service(self):\n        \"\"\"Test the register_service method of the registration behaviour.\"\"\"\n        # operation\n        with patch.object(\n            self.strategy,\n            \"get_register_service_description\",\n            return_value=self.mocked_registration_description,\n        ):\n            with patch.object(self.logger, \"log\") as mock_logger:\n                self.registration_behaviour.register_service()\n\n        # after\n        self.assert_quantity_in_outbox(1)\n\n        message = self.get_message_from_outbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=OefSearchMessage,\n            performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n            to=self.skill.skill_context.search_service_address,\n            sender=str(self.skill.skill_context.skill_id),\n            service_description=self.mocked_registration_description,\n        )\n        assert has_attributes, error_str\n        mock_logger.assert_any_call(\n            logging.INFO, \"registering agent's service on the SOEF.\"\n        )\n\n    def test_register_genus(self):\n        \"\"\"Test the register_genus method of the registration behaviour.\"\"\"\n        # operation\n        with patch.object(\n            self.strategy,\n            \"get_register_personality_description\",\n            return_value=self.mocked_registration_description,\n        ):\n            with patch.object(self.logger, \"log\") as mock_logger:\n                self.registration_behaviour.register_genus()\n\n        # after\n        self.assert_quantity_in_outbox(1)\n\n        message = self.get_message_from_outbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=OefSearchMessage,\n            performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n            to=self.skill.skill_context.search_service_address,\n            sender=str(self.skill.skill_context.skill_id),\n            service_description=self.mocked_registration_description,\n        )\n        assert has_attributes, error_str\n        mock_logger.assert_any_call(\n            logging.INFO, \"registering agent's personality genus on the SOEF.\"\n        )\n\n    def test_register_classification(self):\n        \"\"\"Test the register_classification method of the registration behaviour.\"\"\"\n        # operation\n        with patch.object(\n            self.strategy,\n            \"get_register_classification_description\",\n            return_value=self.mocked_registration_description,\n        ):\n            with patch.object(self.logger, \"log\") as mock_logger:\n                self.registration_behaviour.register_classification()\n\n        # after\n        self.assert_quantity_in_outbox(1)\n\n        message = self.get_message_from_outbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=OefSearchMessage,\n            performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n            to=self.skill.skill_context.search_service_address,\n            sender=str(self.skill.skill_context.skill_id),\n            service_description=self.mocked_registration_description,\n        )\n        assert has_attributes, error_str\n        mock_logger.assert_any_call(\n            logging.INFO, \"registering agent's personality classification on the SOEF.\"\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the service_registration behaviour.\"\"\"\n        # operation\n        with patch.object(\n            self.strategy,\n            \"get_unregister_service_description\",\n            return_value=self.mocked_registration_description,\n        ):\n            with patch.object(\n                self.strategy,\n                \"get_location_description\",\n                return_value=self.mocked_registration_description,\n            ):\n                with patch.object(self.logger, \"log\") as mock_logger:\n                    self.registration_behaviour.teardown()\n\n        # after\n        self.assert_quantity_in_outbox(2)\n\n        # _unregister_service\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=OefSearchMessage,\n            performative=OefSearchMessage.Performative.UNREGISTER_SERVICE,\n            to=self.skill.skill_context.search_service_address,\n            sender=str(self.skill.skill_context.skill_id),\n            service_description=self.mocked_registration_description,\n        )\n        assert has_attributes, error_str\n        mock_logger.assert_any_call(logging.INFO, \"unregistering service from SOEF.\")\n\n        # _unregister_agent\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=OefSearchMessage,\n            performative=OefSearchMessage.Performative.UNREGISTER_SERVICE,\n            to=self.skill.skill_context.search_service_address,\n            sender=str(self.skill.skill_context.skill_id),\n            service_description=self.mocked_registration_description,\n        )\n        assert has_attributes, error_str\n        mock_logger.assert_any_call(logging.INFO, \"unregistering agent from SOEF.\")\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_erc1155_deploy/test_dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the dialogue classes of the erc1155_deploy skill.\"\"\"\n\nimport pytest\n\nfrom aea.exceptions import AEAEnforceError\nfrom aea.protocols.dialogue.base import DialogueLabel\nfrom aea.test_tools.test_skill import COUNTERPARTY_AGENT_ADDRESS\n\nfrom packages.fetchai.protocols.contract_api.message import ContractApiMessage\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.protocols.fipa.message import FipaMessage\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.protocols.signing.message import SigningMessage\nfrom packages.fetchai.skills.erc1155_deploy.dialogues import (\n    ContractApiDialogue,\n    DefaultDialogue,\n    FipaDialogue,\n    LedgerApiDialogue,\n    OefSearchDialogue,\n    SigningDialogue,\n)\n\nfrom tests.test_packages.test_skills.test_erc1155_deploy.intermediate_class import (\n    ERC1155DeployTestCase,\n)\n\n\nclass TestDialogues(ERC1155DeployTestCase):\n    \"\"\"Test dialogue classes of erc1155_deploy.\"\"\"\n\n    def test_contract_api_dialogue(self):\n        \"\"\"Test the ContractApiDialogue class.\"\"\"\n        contract_api_dialogue = ContractApiDialogue(\n            DialogueLabel(\n                (\"\", \"\"),\n                COUNTERPARTY_AGENT_ADDRESS,\n                self.skill.skill_context.agent_address,\n            ),\n            self.skill.skill_context.agent_address,\n            role=ContractApiDialogue.Role.AGENT,\n        )\n\n        # terms\n        with pytest.raises(ValueError, match=\"Terms not set!\"):\n            assert contract_api_dialogue.terms\n        contract_api_dialogue.terms = self.mocked_terms\n        with pytest.raises(AEAEnforceError, match=\"Terms already set!\"):\n            contract_api_dialogue.terms = self.mocked_terms\n        assert contract_api_dialogue.terms == self.mocked_terms\n\n    def test_contract_api_dialogues(self):\n        \"\"\"Test the ContractApiDialogues class.\"\"\"\n        _, dialogue = self.contract_api_dialogues.create(\n            counterparty=COUNTERPARTY_AGENT_ADDRESS,\n            performative=ContractApiMessage.Performative.GET_DEPLOY_TRANSACTION,\n            ledger_id=self.ledger_id,\n            contract_id=self.contract_id,\n            callable=self.callable,\n            kwargs=self.kwargs,\n        )\n        assert dialogue.role == ContractApiDialogue.Role.AGENT\n        assert dialogue.self_address == str(self.skill.skill_context.skill_id)\n\n    def test_default_dialogues(self):\n        \"\"\"Test the DefaultDialogues class.\"\"\"\n        _, dialogue = self.default_dialogues.create(\n            counterparty=COUNTERPARTY_AGENT_ADDRESS,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"some_content\",\n        )\n        assert dialogue.role == DefaultDialogue.Role.AGENT\n        assert dialogue.self_address == self.skill.skill_context.agent_address\n\n    def test_fipa_dialogue(self):\n        \"\"\"Test the FipaDialogue class.\"\"\"\n        fipa_dialogue = FipaDialogue(\n            DialogueLabel(\n                (\"\", \"\"),\n                COUNTERPARTY_AGENT_ADDRESS,\n                self.skill.skill_context.agent_address,\n            ),\n            self.skill.skill_context.agent_address,\n            role=FipaDialogue.Role.BUYER,\n        )\n\n        # proposal\n        with pytest.raises(ValueError, match=\"Proposal not set!\"):\n            assert fipa_dialogue.proposal\n        fipa_dialogue.proposal = self.mocked_registration_description\n        with pytest.raises(AEAEnforceError, match=\"Proposal already set!\"):\n            fipa_dialogue.proposal = self.mocked_registration_description\n        assert fipa_dialogue.proposal == self.mocked_registration_description\n\n    def test_fipa_dialogues(self):\n        \"\"\"Test the FipaDialogues class.\"\"\"\n        _, dialogue = self.fipa_dialogues.create(\n            counterparty=COUNTERPARTY_AGENT_ADDRESS,\n            performative=FipaMessage.Performative.CFP,\n            query=self.mocked_query,\n        )\n        assert dialogue.role == FipaDialogue.Role.SELLER\n        assert dialogue.self_address == self.skill.skill_context.agent_address\n\n    def test_ledger_api_dialogue(self):\n        \"\"\"Test the LedgerApiDialogue class.\"\"\"\n        ledger_api_dialogue = LedgerApiDialogue(\n            DialogueLabel(\n                (\"\", \"\"),\n                COUNTERPARTY_AGENT_ADDRESS,\n                self.skill.skill_context.agent_address,\n            ),\n            self.skill.skill_context.agent_address,\n            role=ContractApiDialogue.Role.AGENT,\n        )\n\n        # associated_signing_dialogue\n        with pytest.raises(ValueError, match=\"Associated signing dialogue not set!\"):\n            assert ledger_api_dialogue.associated_signing_dialogue\n        signing_dialogue = SigningDialogue(\n            DialogueLabel(\n                (\"\", \"\"),\n                COUNTERPARTY_AGENT_ADDRESS,\n                self.skill.skill_context.agent_address,\n            ),\n            self.skill.skill_context.agent_address,\n            role=SigningDialogue.Role.SKILL,\n        )\n        ledger_api_dialogue.associated_signing_dialogue = signing_dialogue\n        with pytest.raises(\n            AEAEnforceError, match=\"Associated signing dialogue already set!\"\n        ):\n            ledger_api_dialogue.associated_signing_dialogue = signing_dialogue\n        assert ledger_api_dialogue.associated_signing_dialogue == signing_dialogue\n\n    def test_ledger_api_dialogues(self):\n        \"\"\"Test the LedgerApiDialogues class.\"\"\"\n        _, dialogue = self.ledger_api_dialogues.create(\n            counterparty=COUNTERPARTY_AGENT_ADDRESS,\n            performative=LedgerApiMessage.Performative.GET_BALANCE,\n            ledger_id=self.ledger_id,\n            address=self.address,\n        )\n        assert dialogue.role == LedgerApiDialogue.Role.AGENT\n        assert dialogue.self_address == str(self.skill.skill_context.skill_id)\n\n    def test_oef_search_dialogues(self):\n        \"\"\"Test the OefSearchDialogues class.\"\"\"\n        _, dialogue = self.oef_search_dialogues.create(\n            counterparty=COUNTERPARTY_AGENT_ADDRESS,\n            performative=OefSearchMessage.Performative.SEARCH_SERVICES,\n            query=self.mocked_query,\n        )\n        assert dialogue.role == OefSearchDialogue.Role.AGENT\n        assert dialogue.self_address == str(self.skill.skill_context.skill_id)\n\n    def test_signing_dialogue(self):\n        \"\"\"Test the SigningDialogue class.\"\"\"\n        signing_dialogue = SigningDialogue(\n            DialogueLabel(\n                (\"\", \"\"),\n                COUNTERPARTY_AGENT_ADDRESS,\n                self.skill.skill_context.agent_address,\n            ),\n            self.skill.skill_context.agent_address,\n            role=ContractApiDialogue.Role.AGENT,\n        )\n\n        # associated_contract_api_dialogue\n        with pytest.raises(\n            ValueError, match=\"Associated contract api dialogue not set!\"\n        ):\n            assert signing_dialogue.associated_contract_api_dialogue\n        contract_api_dialogue = ContractApiDialogue(\n            DialogueLabel(\n                (\"\", \"\"),\n                COUNTERPARTY_AGENT_ADDRESS,\n                self.skill.skill_context.agent_address,\n            ),\n            self.skill.skill_context.agent_address,\n            role=ContractApiDialogue.Role.AGENT,\n        )\n        signing_dialogue.associated_contract_api_dialogue = contract_api_dialogue\n        with pytest.raises(\n            AEAEnforceError, match=\"Associated contract api dialogue already set!\"\n        ):\n            signing_dialogue.associated_contract_api_dialogue = contract_api_dialogue\n        assert (\n            signing_dialogue.associated_contract_api_dialogue == contract_api_dialogue\n        )\n\n    def test_signing_dialogues(self):\n        \"\"\"Test the SigningDialogues class.\"\"\"\n        _, dialogue = self.signing_dialogues.create(\n            counterparty=COUNTERPARTY_AGENT_ADDRESS,\n            performative=SigningMessage.Performative.SIGN_TRANSACTION,\n            terms=self.mocked_terms,\n            raw_transaction=self.mocked_raw_tx,\n        )\n        assert dialogue.role == SigningDialogue.Role.SKILL\n        assert dialogue.self_address == str(self.skill.skill_context.skill_id)\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_erc1155_deploy/test_handlers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the handler classes of the erc1155_deploy skill.\"\"\"\n\nimport logging\nfrom typing import cast\nfrom unittest.mock import patch\n\nfrom aea.crypto.ledger_apis import LedgerApis\nfrom aea.helpers.transaction.base import State\nfrom aea.protocols.dialogue.base import Dialogues\nfrom aea.test_tools.test_skill import COUNTERPARTY_AGENT_ADDRESS\n\nfrom packages.fetchai.protocols.contract_api.message import ContractApiMessage\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.protocols.fipa.message import FipaMessage\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.protocols.signing.message import SigningMessage\nfrom packages.fetchai.skills.erc1155_deploy.dialogues import (\n    ContractApiDialogue,\n    FipaDialogue,\n    LedgerApiDialogue,\n    OefSearchDialogue,\n    SigningDialogue,\n)\nfrom packages.fetchai.skills.erc1155_deploy.handlers import LEDGER_API_ADDRESS\n\nfrom tests.test_packages.test_skills.test_erc1155_deploy.intermediate_class import (\n    ERC1155DeployTestCase,\n)\n\n\nclass TestFipaHandler(ERC1155DeployTestCase):\n    \"\"\"Test fipa handler of erc1155_deploy.\"\"\"\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the fipa handler.\"\"\"\n        assert self.fipa_handler.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle_unidentified_dialogue(self):\n        \"\"\"Test the _handle_unidentified_dialogue method of the fipa handler.\"\"\"\n        # setup\n        incorrect_dialogue_reference = (\"\", \"\")\n        incoming_message = cast(\n            FipaMessage,\n            self.build_incoming_message(\n                message_type=FipaMessage,\n                dialogue_reference=incorrect_dialogue_reference,\n                performative=FipaMessage.Performative.ACCEPT,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.fipa_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"unidentified dialogue for message={incoming_message}.\",\n        )\n\n        self.assert_quantity_in_outbox(1)\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=DefaultMessage,\n            performative=DefaultMessage.Performative.ERROR,\n            to=incoming_message.sender,\n            sender=self.skill.skill_context.agent_address,\n            error_code=DefaultMessage.ErrorCode.INVALID_DIALOGUE,\n            error_msg=\"Invalid dialogue.\",\n            error_data={\"fipa_message\": incoming_message.encode()},\n        )\n        assert has_attributes, error_str\n\n    def test_handle_cfp_i(self):\n        \"\"\"Test the _handle_cfp method of the fipa handler where is_tokens_minted is True.\"\"\"\n        # setup\n        self.strategy._is_tokens_minted = True\n        incoming_message = cast(\n            FipaMessage,\n            self.build_incoming_message(\n                message_type=FipaMessage,\n                performative=FipaMessage.Performative.CFP,\n                dialogue_reference=Dialogues.new_self_initiated_dialogue_reference(),\n                query=self.mocked_query,\n            ),\n        )\n\n        # operation\n        with patch.object(\n            self.strategy, \"get_proposal\", return_value=self.mocked_proposal\n        ) as mock_prop:\n            with patch.object(self.logger, \"log\") as mock_logger:\n                self.fipa_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received CFP from sender={COUNTERPARTY_AGENT_ADDRESS[-5:]}\",\n        )\n\n        mock_prop.assert_called_once()\n\n        self.assert_quantity_in_outbox(1)\n        message = self.get_message_from_outbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=FipaMessage,\n            performative=FipaMessage.Performative.PROPOSE,\n            to=incoming_message.sender,\n            sender=self.skill.skill_context.agent_address,\n            proposal=self.mocked_proposal,\n        )\n        assert has_attributes, error_str\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"sending PROPOSE to agent={COUNTERPARTY_AGENT_ADDRESS[-5:]}: proposal={self.mocked_proposal.values}\",\n        )\n\n    def test_handle_cfp_ii(self):\n        \"\"\"Test the _handle_cfp method of the fipa handler where is_tokens_minted is False.\"\"\"\n        # setup\n        self.strategy._is_tokens_minted = False\n        incoming_message = cast(\n            FipaMessage,\n            self.build_incoming_message(\n                message_type=FipaMessage,\n                performative=FipaMessage.Performative.CFP,\n                dialogue_reference=Dialogues.new_self_initiated_dialogue_reference(),\n                query=self.mocked_query,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.fipa_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received CFP from sender={COUNTERPARTY_AGENT_ADDRESS[-5:]}\",\n        )\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            \"Contract items not minted yet. Try again later.\",\n        )\n\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle_accept_w_inform_i(self):\n        \"\"\"Test the _handle_accept_w_inform method of the fipa handler where tx_signature is NOT None.\"\"\"\n        # setup\n        tx_signature = \"some_tx_signature\"\n        self.strategy.contract_address = self.contract_address\n        fipa_dialogue = cast(\n            FipaDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.fipa_dialogues,\n                messages=self.list_of_fipa_messages[:2],\n            ),\n        )\n        fipa_dialogue.proposal = self.mocked_proposal\n        incoming_message = cast(\n            FipaMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=fipa_dialogue,\n                performative=FipaMessage.Performative.ACCEPT_W_INFORM,\n                info={\"tx_signature\": tx_signature},\n            ),\n        )\n\n        # operation\n        with patch.object(\n            self.strategy, \"get_single_swap_terms\", return_value=self.mocked_terms\n        ) as mock_swap:\n            with patch.object(self.logger, \"log\") as mock_logger:\n                self.fipa_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received ACCEPT_W_INFORM from sender={COUNTERPARTY_AGENT_ADDRESS[-5:]}: tx_signature={tx_signature}\",\n        )\n\n        self.assert_quantity_in_outbox(1)\n        message = self.get_message_from_outbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=ContractApiMessage,\n            performative=ContractApiMessage.Performative.GET_RAW_TRANSACTION,\n            to=LEDGER_API_ADDRESS,\n            sender=str(self.skill.skill_context.skill_id),\n            ledger_id=self.strategy.ledger_id,\n            contract_id=self.strategy.contract_id,\n            contract_address=self.strategy.contract_address,\n            callable=\"get_atomic_swap_single_transaction\",\n            kwargs=ContractApiMessage.Kwargs(\n                {\n                    \"from_address\": self.skill.skill_context.agent_address,\n                    \"to_address\": incoming_message.sender,\n                    \"token_id\": int(fipa_dialogue.proposal.values[\"token_id\"]),\n                    \"from_supply\": int(fipa_dialogue.proposal.values[\"from_supply\"]),\n                    \"to_supply\": int(fipa_dialogue.proposal.values[\"to_supply\"]),\n                    \"value\": int(fipa_dialogue.proposal.values[\"value\"]),\n                    \"trade_nonce\": int(fipa_dialogue.proposal.values[\"trade_nonce\"]),\n                    \"signature\": tx_signature,\n                }\n            ),\n        )\n        assert has_attributes, error_str\n\n        mock_swap.assert_called_once()\n        contract_api_dialogue = cast(\n            ContractApiDialogue, self.contract_api_dialogues.get_dialogue(message)\n        )\n        assert contract_api_dialogue.terms == self.mocked_terms\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            \"requesting single atomic swap transaction...\",\n        )\n\n    def test_handle_accept_w_inform_ii(self):\n        \"\"\"Test the _handle_accept_w_inform method of the fipa handler where tx_signature is NOT None.\"\"\"\n        # setup\n        tx_signature = \"some_tx_signature\"\n        fipa_dialogue = cast(\n            FipaDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.fipa_dialogues,\n                messages=self.list_of_fipa_messages[:2],\n            ),\n        )\n        fipa_dialogue.proposal = self.mocked_proposal\n        incoming_message = cast(\n            FipaMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=fipa_dialogue,\n                performative=FipaMessage.Performative.ACCEPT_W_INFORM,\n                info={\"something\": tx_signature},\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.fipa_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received ACCEPT_W_INFORM from sender={COUNTERPARTY_AGENT_ADDRESS[-5:]} with no signature.\",\n        )\n\n    def test_handle_invalid(self):\n        \"\"\"Test the _handle_invalid method of the fipa handler.\"\"\"\n        # setup\n        fipa_dialogue = cast(\n            FipaDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.fipa_dialogues,\n                messages=self.list_of_fipa_messages[:2],\n            ),\n        )\n        incoming_message = cast(\n            FipaMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=fipa_dialogue,\n                performative=FipaMessage.Performative.ACCEPT,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.fipa_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"cannot handle fipa message of performative={incoming_message.performative} in dialogue={fipa_dialogue}.\",\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the fipa handler.\"\"\"\n        assert self.fipa_handler.teardown() is None\n        self.assert_quantity_in_outbox(0)\n\n\nclass TestLedgerApiHandler(ERC1155DeployTestCase):\n    \"\"\"Test ledger_api handler of erc1155_deploy.\"\"\"\n\n    is_agent_to_agent_messages = False\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the ledger_api handler.\"\"\"\n        assert self.ledger_api_handler.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle_unidentified_dialogue(self):\n        \"\"\"Test the _handle_unidentified_dialogue method of the ledger_api handler.\"\"\"\n        # setup\n        incorrect_dialogue_reference = (\"\", \"\")\n        incoming_message = cast(\n            LedgerApiMessage,\n            self.build_incoming_message(\n                message_type=LedgerApiMessage,\n                dialogue_reference=incorrect_dialogue_reference,\n                performative=LedgerApiMessage.Performative.BALANCE,\n                ledger_id=self.ledger_id,\n                balance=10,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received invalid ledger_api message={incoming_message}, unidentified dialogue.\",\n        )\n\n    def test_handle_balance(self):\n        \"\"\"Test the _handle_balance method of the ledger_api handler.\"\"\"\n        # setup\n        balance = 10\n        ledger_api_dialogue = cast(\n            LedgerApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.ledger_api_dialogues,\n                messages=self.list_of_ledger_api_balance_messages[:1],\n                counterparty=LEDGER_API_ADDRESS,\n            ),\n        )\n        incoming_message = cast(\n            LedgerApiMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=ledger_api_dialogue,\n                performative=LedgerApiMessage.Performative.BALANCE,\n                ledger_id=self.ledger_id,\n                balance=balance,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"starting balance on {self.ledger_id} ledger={incoming_message.balance}.\",\n        )\n\n    def test_handle_transaction_digest(self):\n        \"\"\"Test the _handle_transaction_digest method of the ledger_api handler.\"\"\"\n        # setup\n        ledger_api_dialogue = cast(\n            LedgerApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.ledger_api_dialogues,\n                messages=self.list_of_ledger_api_messages[:3],\n                counterparty=LEDGER_API_ADDRESS,\n            ),\n        )\n        incoming_message = cast(\n            LedgerApiMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=ledger_api_dialogue,\n                performative=LedgerApiMessage.Performative.TRANSACTION_DIGEST,\n                transaction_digest=self.mocked_tx_digest,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"transaction was successfully submitted. Transaction digest={incoming_message.transaction_digest}\",\n        )\n\n        self.assert_quantity_in_outbox(1)\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=LedgerApiMessage,\n            performative=LedgerApiMessage.Performative.GET_TRANSACTION_RECEIPT,\n            to=incoming_message.sender,\n            sender=str(self.skill.skill_context.skill_id),\n            transaction_digest=self.mocked_tx_digest,\n        )\n        assert has_attributes, error_str\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            \"requesting transaction receipt.\",\n        )\n\n    def test_handle_transaction_receipt_i(self):\n        \"\"\"Test the _handle_transaction_receipt method of the ledger_api handler where the transaction is NOT settled.\"\"\"\n        # setup\n        ledger_api_dialogue = cast(\n            LedgerApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.ledger_api_dialogues,\n                messages=self.list_of_ledger_api_messages[:5],\n                counterparty=LEDGER_API_ADDRESS,\n            ),\n        )\n        incoming_message = cast(\n            LedgerApiMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=ledger_api_dialogue,\n                performative=LedgerApiMessage.Performative.TRANSACTION_RECEIPT,\n                transaction_receipt=self.mocked_tx_receipt,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            with patch.object(LedgerApis, \"is_transaction_settled\", return_value=False):\n                self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.ERROR,\n            f\"transaction failed. Transaction receipt={incoming_message.transaction_receipt}\",\n        )\n\n    def test_handle_transaction_receipt_ii(self):\n        \"\"\"Test the _handle_transaction_receipt method of the ledger_api handler where is_contract_deployed is False.\"\"\"\n        # setup\n        self.strategy._is_contract_deployed = False\n\n        ledger_api_dialogue = cast(\n            LedgerApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.ledger_api_dialogues,\n                messages=self.list_of_ledger_api_messages[:5],\n                counterparty=LEDGER_API_ADDRESS,\n            ),\n        )\n        incoming_message = cast(\n            LedgerApiMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=ledger_api_dialogue,\n                performative=LedgerApiMessage.Performative.TRANSACTION_RECEIPT,\n                transaction_receipt=self.mocked_tx_receipt,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            with patch.object(LedgerApis, \"is_transaction_settled\", return_value=True):\n                self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"transaction was successfully settled. Transaction receipt={self.mocked_tx_receipt}\",\n        )\n\n        assert self.strategy.contract_address == self.contract_address\n        assert self.strategy.is_contract_deployed is True\n        assert self.strategy.is_behaviour_active is True\n\n    def test_handle_transaction_receipt_iii(self):\n        \"\"\"Test the _handle_transaction_receipt method of the ledger_api handler where is_tokens_created is False.\"\"\"\n        # setup\n        self.strategy._is_contract_deployed = True\n        self.strategy._is_tokens_created = False\n\n        ledger_api_dialogue = cast(\n            LedgerApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.ledger_api_dialogues,\n                messages=self.list_of_ledger_api_messages[:5],\n                counterparty=LEDGER_API_ADDRESS,\n            ),\n        )\n        incoming_message = cast(\n            LedgerApiMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=ledger_api_dialogue,\n                performative=LedgerApiMessage.Performative.TRANSACTION_RECEIPT,\n                transaction_receipt=self.mocked_tx_receipt,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            with patch.object(LedgerApis, \"is_transaction_settled\", return_value=True):\n                self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"transaction was successfully settled. Transaction receipt={self.mocked_tx_receipt}\",\n        )\n\n        assert self.strategy.is_tokens_created is True\n        assert self.strategy.is_behaviour_active is True\n\n    def test_handle_transaction_receipt_iv(self):\n        \"\"\"Test the _handle_transaction_receipt method of the ledger_api handler where is_tokens_minted is False.\"\"\"\n        # setup\n        self.strategy._is_contract_deployed = True\n        self.strategy._is_tokens_created = True\n        self.strategy._is_tokens_minted = False\n\n        ledger_api_dialogue = cast(\n            LedgerApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.ledger_api_dialogues,\n                messages=self.list_of_ledger_api_messages[:5],\n                counterparty=LEDGER_API_ADDRESS,\n            ),\n        )\n        incoming_message = cast(\n            LedgerApiMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=ledger_api_dialogue,\n                performative=LedgerApiMessage.Performative.TRANSACTION_RECEIPT,\n                transaction_receipt=self.mocked_tx_receipt,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            with patch.object(LedgerApis, \"is_transaction_settled\", return_value=True):\n                self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"transaction was successfully settled. Transaction receipt={self.mocked_tx_receipt}\",\n        )\n\n        assert self.strategy.is_tokens_minted is True\n        assert self.strategy.is_behaviour_active is True\n\n    def test_handle_transaction_receipt_v(self):\n        \"\"\"Test the _handle_transaction_receipt method of the ledger_api handler where is_tokens_minted is True.\"\"\"\n        # setup\n        self.strategy._is_contract_deployed = True\n        self.strategy._is_tokens_created = True\n        self.strategy._is_tokens_minted = True\n\n        ledger_api_dialogue = cast(\n            LedgerApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.ledger_api_dialogues,\n                messages=self.list_of_ledger_api_messages[:5],\n                counterparty=LEDGER_API_ADDRESS,\n            ),\n        )\n        incoming_message = cast(\n            LedgerApiMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=ledger_api_dialogue,\n                performative=LedgerApiMessage.Performative.TRANSACTION_RECEIPT,\n                transaction_receipt=self.mocked_tx_receipt,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            with patch.object(LedgerApis, \"is_transaction_settled\", return_value=True):\n                self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"transaction was successfully settled. Transaction receipt={self.mocked_tx_receipt}\",\n        )\n\n        assert self.skill.skill_context.is_active is False\n        mock_logger.assert_any_call(logging.INFO, \"demo finished!\")\n\n    def test_handle_error(self):\n        \"\"\"Test the _handle_error method of the ledger_api handler.\"\"\"\n        # setup\n        ledger_api_dialogue = cast(\n            LedgerApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.ledger_api_dialogues,\n                messages=self.list_of_ledger_api_balance_messages[:1],\n            ),\n        )\n        incoming_message = cast(\n            LedgerApiMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=ledger_api_dialogue,\n                performative=LedgerApiMessage.Performative.ERROR,\n                code=1,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received ledger_api error message={incoming_message} in dialogue={ledger_api_dialogue}.\",\n        )\n\n    def test_handle_invalid(self):\n        \"\"\"Test the _handle_invalid method of the ledger_api handler.\"\"\"\n        # setup\n        invalid_performative = LedgerApiMessage.Performative.GET_BALANCE\n        incoming_message = cast(\n            LedgerApiMessage,\n            self.build_incoming_message(\n                message_type=LedgerApiMessage,\n                dialogue_reference=(\"1\", \"\"),\n                performative=invalid_performative,\n                ledger_id=self.ledger_id,\n                address=self.address,\n                to=str(self.skill.skill_context.skill_id),\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"cannot handle ledger_api message of performative={invalid_performative} in dialogue={self.ledger_api_dialogues.get_dialogue(incoming_message)}.\",\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the ledger_api handler.\"\"\"\n        assert self.ledger_api_handler.teardown() is None\n        self.assert_quantity_in_outbox(0)\n\n\nclass TestContractApiHandler(ERC1155DeployTestCase):\n    \"\"\"Test contract_api handler of erc1155_deploy.\"\"\"\n\n    is_agent_to_agent_messages = False\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the contract_api handler.\"\"\"\n        assert self.contract_api_handler.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle_unidentified_dialogue(self):\n        \"\"\"Test the _handle_unidentified_dialogue method of the signing handler.\"\"\"\n        # setup\n        incorrect_dialogue_reference = (\"\", \"\")\n        incoming_message = cast(\n            ContractApiMessage,\n            self.build_incoming_message(\n                message_type=ContractApiMessage,\n                dialogue_reference=incorrect_dialogue_reference,\n                performative=ContractApiMessage.Performative.STATE,\n                state=State(self.ledger_id, self.body_dict),\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.contract_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received invalid contract_api message={incoming_message}, unidentified dialogue.\",\n        )\n\n    def test_handle_raw_transaction(self):\n        \"\"\"Test the _handle_raw_transaction method of the signing handler.\"\"\"\n        # setup\n        contract_api_dialogue = cast(\n            ContractApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.contract_api_dialogues,\n                messages=self.list_of_contract_api_messages[:1],\n            ),\n        )\n        contract_api_dialogue.terms = self.mocked_terms\n        incoming_message = cast(\n            ContractApiMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=contract_api_dialogue,\n                performative=ContractApiMessage.Performative.RAW_TRANSACTION,\n                raw_transaction=self.mocked_raw_tx,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.contract_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO, f\"received raw transaction={incoming_message}\"\n        )\n\n        self.assert_quantity_in_decision_making_queue(1)\n        message = self.get_message_from_decision_maker_inbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=SigningMessage,\n            performative=SigningMessage.Performative.SIGN_TRANSACTION,\n            to=self.skill.skill_context.decision_maker_address,\n            sender=str(self.skill.skill_context.skill_id),\n            raw_transaction=self.mocked_raw_tx,\n            terms=contract_api_dialogue.terms,\n        )\n        assert has_attributes, error_str\n\n        assert (\n            cast(\n                SigningDialogue, self.signing_dialogues.get_dialogue(message)\n            ).associated_contract_api_dialogue\n            == contract_api_dialogue\n        )\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            \"proposing the transaction to the decision maker. Waiting for confirmation ...\",\n        )\n\n    def test_handle_error(self):\n        \"\"\"Test the _handle_error method of the signing handler.\"\"\"\n        # setup\n        contract_api_dialogue = cast(\n            ContractApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.contract_api_dialogues,\n                messages=self.list_of_contract_api_messages[:1],\n            ),\n        )\n        incoming_message = cast(\n            ContractApiMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=contract_api_dialogue,\n                performative=ContractApiMessage.Performative.ERROR,\n                data=b\"some_data\",\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.contract_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received contract_api error message={incoming_message} in dialogue={contract_api_dialogue}.\",\n        )\n\n    def test_handle_invalid(self):\n        \"\"\"Test the _handle_invalid method of the signing handler.\"\"\"\n        # setup\n        invalid_performative = ContractApiMessage.Performative.GET_DEPLOY_TRANSACTION\n        incoming_message = cast(\n            ContractApiMessage,\n            self.build_incoming_message(\n                message_type=ContractApiMessage,\n                dialogue_reference=(\"1\", \"\"),\n                performative=invalid_performative,\n                ledger_id=self.ledger_id,\n                contract_id=self.contract_id,\n                callable=self.callable,\n                kwargs=self.kwargs,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.contract_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"cannot handle contract_api message of performative={invalid_performative} in dialogue={self.contract_api_dialogues.get_dialogue(incoming_message)}.\",\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the contract_api handler.\"\"\"\n        assert self.contract_api_handler.teardown() is None\n        self.assert_quantity_in_outbox(0)\n\n\nclass TestSigningHandler(ERC1155DeployTestCase):\n    \"\"\"Test signing handler of erc1155_deploy.\"\"\"\n\n    is_agent_to_agent_messages = False\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the signing handler.\"\"\"\n        assert self.signing_handler.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle_unidentified_dialogue(self):\n        \"\"\"Test the _handle_unidentified_dialogue method of the signing handler.\"\"\"\n        # setup\n        incorrect_dialogue_reference = (\"\", \"\")\n        incoming_message = cast(\n            SigningMessage,\n            self.build_incoming_message(\n                message_type=SigningMessage,\n                dialogue_reference=incorrect_dialogue_reference,\n                performative=SigningMessage.Performative.ERROR,\n                error_code=SigningMessage.ErrorCode.UNSUCCESSFUL_MESSAGE_SIGNING,\n                to=str(self.skill.skill_context.skill_id),\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.signing_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received invalid signing message={incoming_message}, unidentified dialogue.\",\n        )\n\n    def test_handle_signed_transaction(\n        self,\n    ):\n        \"\"\"Test the _handle_signed_transaction method of the signing handler.\"\"\"\n        # setup\n        signing_dialogue = cast(\n            SigningDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.signing_dialogues,\n                messages=self.list_of_signing_messages[:1],\n                counterparty=self.skill.skill_context.decision_maker_address,\n            ),\n        )\n        incoming_message = cast(\n            SigningMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=signing_dialogue,\n                performative=SigningMessage.Performative.SIGNED_TRANSACTION,\n                signed_transaction=self.mocked_signed_tx,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.signing_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(logging.INFO, \"transaction signing was successful.\")\n\n        self.assert_quantity_in_outbox(1)\n        message = self.get_message_from_outbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=LedgerApiMessage,\n            performative=LedgerApiMessage.Performative.SEND_SIGNED_TRANSACTION,\n            to=LEDGER_API_ADDRESS,\n            sender=str(self.skill.skill_context.skill_id),\n            signed_transaction=self.mocked_signed_tx,\n        )\n        assert has_attributes, error_str\n\n        ledger_api_dialogue = cast(\n            LedgerApiDialogue, self.ledger_api_dialogues.get_dialogue(message)\n        )\n        assert ledger_api_dialogue.associated_signing_dialogue == signing_dialogue\n\n        mock_logger.assert_any_call(logging.INFO, \"sending transaction to ledger.\")\n\n    def test_handle_error(self):\n        \"\"\"Test the _handle_error method of the signing handler.\"\"\"\n        # setup\n        signing_counterparty = self.skill.skill_context.decision_maker_address\n        signing_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.signing_dialogues,\n            messages=self.list_of_signing_messages[:1],\n            counterparty=signing_counterparty,\n        )\n        incoming_message = cast(\n            SigningMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=signing_dialogue,\n                performative=SigningMessage.Performative.ERROR,\n                error_code=SigningMessage.ErrorCode.UNSUCCESSFUL_TRANSACTION_SIGNING,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.signing_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"transaction signing was not successful. Error_code={incoming_message.error_code} in dialogue={signing_dialogue}\",\n        )\n\n    def test_handle_invalid(self):\n        \"\"\"Test the _handle_invalid method of the signing handler.\"\"\"\n        # setup\n        invalid_performative = SigningMessage.Performative.SIGN_TRANSACTION\n        incoming_message = self.build_incoming_message(\n            message_type=SigningMessage,\n            dialogue_reference=(\"1\", \"\"),\n            performative=invalid_performative,\n            terms=self.mocked_terms,\n            raw_transaction=SigningMessage.RawTransaction(\n                self.ledger_id, {\"some_key\": \"some_value\"}\n            ),\n            to=str(self.skill.skill_context.skill_id),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.signing_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"cannot handle signing message of performative={invalid_performative} in dialogue={self.signing_dialogues.get_dialogue(incoming_message)}.\",\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the signing handler.\"\"\"\n        assert self.signing_handler.teardown() is None\n        self.assert_quantity_in_outbox(0)\n\n\nclass TestOefSearchHandler(ERC1155DeployTestCase):\n    \"\"\"Test oef_search handler of erc1155_deploy.\"\"\"\n\n    is_agent_to_agent_messages = False\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the oef_search handler.\"\"\"\n        assert self.oef_search_handler.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle_unidentified_dialogue(self):\n        \"\"\"Test the _handle_unidentified_dialogue method of the oef_search handler.\"\"\"\n        # setup\n        incorrect_dialogue_reference = (\"\", \"\")\n        incoming_message = cast(\n            OefSearchMessage,\n            self.build_incoming_message(\n                message_type=OefSearchMessage,\n                dialogue_reference=incorrect_dialogue_reference,\n                performative=OefSearchMessage.Performative.OEF_ERROR,\n                oef_error_operation=OefSearchMessage.OefErrorOperation.REGISTER_SERVICE,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received invalid oef_search message={incoming_message}, unidentified dialogue.\",\n        )\n\n    def test_handle_error(self):\n        \"\"\"Test the _handle_error method of the oef_search handler.\"\"\"\n        # setup\n        oef_search_dialogue = cast(\n            OefSearchDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.oef_search_dialogues,\n                messages=self.list_of_messages_register_location[:1],\n            ),\n        )\n        incoming_message = cast(\n            OefSearchMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=oef_search_dialogue,\n                performative=OefSearchMessage.Performative.OEF_ERROR,\n                oef_error_operation=OefSearchMessage.OefErrorOperation.REGISTER_SERVICE,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received oef_search error message={incoming_message} in dialogue={oef_search_dialogue}.\",\n        )\n\n    def test_handle_success_i(self):\n        \"\"\"Test the _handle_success method of the oef_search handler where the oef success targets register_service WITH location_agent data model description.\"\"\"\n        # setup\n        oef_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_search_dialogues,\n            messages=self.list_of_messages_register_location[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=oef_dialogue,\n            performative=OefSearchMessage.Performative.SUCCESS,\n            agents_info=OefSearchMessage.AgentsInfo({\"address\": {\"key\": \"value\"}}),\n        )\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            with patch.object(\n                self.registration_behaviour,\n                \"register_service\",\n            ) as mock_reg:\n                self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received oef_search success message={incoming_message} in dialogue={oef_dialogue}.\",\n        )\n        mock_reg.assert_called_once()\n\n    def test_handle_success_ii(self):\n        \"\"\"Test the _handle_success method of the oef_search handler where the oef success targets register_service WITH set_service_key data model description.\"\"\"\n        # setup\n        oef_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_search_dialogues,\n            messages=self.list_of_messages_register_service[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=oef_dialogue,\n            performative=OefSearchMessage.Performative.SUCCESS,\n            agents_info=OefSearchMessage.AgentsInfo({\"address\": {\"key\": \"value\"}}),\n        )\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            with patch.object(\n                self.registration_behaviour,\n                \"register_genus\",\n            ) as mock_reg:\n                self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received oef_search success message={incoming_message} in dialogue={oef_dialogue}.\",\n        )\n        mock_reg.assert_called_once()\n\n    def test_handle_success_iii(self):\n        \"\"\"Test the _handle_success method of the oef_search handler where the oef success targets register_service WITH personality_agent data model and genus value description.\"\"\"\n        # setup\n        oef_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_search_dialogues,\n            messages=self.list_of_messages_register_genus[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=oef_dialogue,\n            performative=OefSearchMessage.Performative.SUCCESS,\n            agents_info=OefSearchMessage.AgentsInfo({\"address\": {\"key\": \"value\"}}),\n        )\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            with patch.object(\n                self.registration_behaviour,\n                \"register_classification\",\n            ) as mock_reg:\n                self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received oef_search success message={incoming_message} in dialogue={oef_dialogue}.\",\n        )\n        mock_reg.assert_called_once()\n\n    def test_handle_success_iv(self):\n        \"\"\"Test the _handle_success method of the oef_search handler where the oef success targets register_service WITH personality_agent data model and classification value description.\"\"\"\n        # setup\n        oef_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_search_dialogues,\n            messages=self.list_of_messages_register_classification[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=oef_dialogue,\n            performative=OefSearchMessage.Performative.SUCCESS,\n            agents_info=OefSearchMessage.AgentsInfo({\"address\": {\"key\": \"value\"}}),\n        )\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received oef_search success message={incoming_message} in dialogue={oef_dialogue}.\",\n        )\n\n        assert self.registration_behaviour.is_registered is True\n        assert self.registration_behaviour.registration_in_progress is False\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            \"the agent, with its genus and classification, and its service are successfully registered on the SOEF.\",\n        )\n\n    def test_handle_success_v(self):\n        \"\"\"Test the _handle_success method of the oef_search handler where the oef success targets unregister_service.\"\"\"\n        # setup\n        oef_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_search_dialogues,\n            messages=self.list_of_messages_register_invalid[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=oef_dialogue,\n            performative=OefSearchMessage.Performative.SUCCESS,\n            agents_info=OefSearchMessage.AgentsInfo({\"address\": {\"key\": \"value\"}}),\n        )\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received oef_search success message={incoming_message} in dialogue={oef_dialogue}.\",\n        )\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"received soef SUCCESS message as a reply to the following unexpected message: {oef_dialogue.get_message_by_id(incoming_message.target)}\",\n        )\n\n    def test_handle_invalid(self):\n        \"\"\"Test the _handle_invalid method of the oef_search handler.\"\"\"\n        # setup\n        incoming_message = cast(\n            OefSearchMessage,\n            self.build_incoming_message(\n                message_type=OefSearchMessage,\n                performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n                service_description=self.mocked_proposal,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"cannot handle oef_search message of performative={incoming_message.performative} in dialogue={self.oef_search_dialogues.get_dialogue(incoming_message)}.\",\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the oef_search handler.\"\"\"\n        assert self.oef_search_handler.teardown() is None\n        self.assert_quantity_in_outbox(0)\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_erc1155_deploy/test_strategy.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the strategy class of the erc1155_deploy skill.\"\"\"\n\nimport pytest\n\nfrom aea.exceptions import AEAEnforceError\nfrom aea.helpers.search.generic import (\n    AGENT_LOCATION_MODEL,\n    AGENT_PERSONALITY_MODEL,\n    AGENT_REMOVE_SERVICE_MODEL,\n    AGENT_SET_SERVICE_MODEL,\n)\nfrom aea.helpers.search.models import Description, Location\nfrom aea.helpers.transaction.base import Terms\n\nfrom packages.fetchai.contracts.erc1155.contract import ERC1155Contract\nfrom packages.fetchai.skills.erc1155_deploy.strategy import (\n    SIMPLE_SERVICE_MODEL,\n    Strategy,\n)\n\nfrom tests.test_packages.test_skills.test_erc1155_deploy.intermediate_class import (\n    ERC1155DeployTestCase,\n)\n\n\nclass TestStrategy(ERC1155DeployTestCase):\n    \"\"\"Test Strategy of erc1155_deploy.\"\"\"\n\n    def test__init__(self):\n        \"\"\"Test the properties of Strategy class.\"\"\"\n        assert Strategy(\n            location=self.location,\n            mint_quantities=[1, 1, 1, 1, 1, 1, 1, 1, 1, 1],\n            service_data=self.service_data,\n            personality_data=self.personality_data,\n            classification=self.classification,\n            from_supply=self.from_supply,\n            to_supply=self.to_supply,\n            value=self.value,\n            token_type=1,\n            name=\"strategy\",\n            skill_context=self.skill.skill_context,\n        )\n\n    def test_properties(self):\n        \"\"\"Test the properties of Strategy class.\"\"\"\n        assert self.strategy.ledger_id == self.skill.skill_context.default_ledger_id\n        assert self.strategy.contract_id == str(ERC1155Contract.contract_id)\n        assert self.strategy.mint_quantities == self.mint_quantities\n        assert self.strategy.token_ids == self.strategy._token_ids\n\n        self.strategy._token_ids = None\n        with pytest.raises(ValueError, match=\"Token ids not set.\"):\n            assert self.strategy.token_ids\n\n        with pytest.raises(ValueError, match=\"Contract address not set!\"):\n            assert self.strategy.contract_address\n        self.strategy.contract_address = self.contract_address\n        with pytest.raises(AEAEnforceError, match=\"Contract address already set!\"):\n            self.strategy.contract_address = self.contract_address\n        assert self.strategy.contract_address == self.contract_address\n\n        assert self.strategy.is_contract_deployed is False\n        self.strategy.is_contract_deployed = True\n        assert self.strategy.is_contract_deployed is True\n        with pytest.raises(AEAEnforceError, match=\"Only allowed to switch to true.\"):\n            self.strategy.is_contract_deployed = False\n\n        assert self.strategy.is_tokens_created is False\n        self.strategy.is_tokens_created = True\n        assert self.strategy.is_tokens_created is True\n        with pytest.raises(AEAEnforceError, match=\"Only allowed to switch to true.\"):\n            self.strategy.is_tokens_created = False\n\n        assert self.strategy.is_tokens_minted is False\n        self.strategy.is_tokens_minted = True\n        assert self.strategy.is_tokens_minted is True\n        with pytest.raises(AEAEnforceError, match=\"Only allowed to switch to true.\"):\n            self.strategy.is_tokens_minted = False\n\n        assert self.strategy.gas == self.strategy._gas\n\n    def test_get_location_description(self):\n        \"\"\"Test the get_location_description method of the Strategy class.\"\"\"\n        description = self.strategy.get_location_description()\n\n        assert type(description) == Description\n        assert description.data_model is AGENT_LOCATION_MODEL\n        assert description.values.get(\"location\", \"\") == Location(\n            latitude=self.location[\"latitude\"], longitude=self.location[\"longitude\"]\n        )\n\n    def test_get_register_service_description(self):\n        \"\"\"Test the get_register_service_description method of the Strategy class.\"\"\"\n        description = self.strategy.get_register_service_description()\n\n        assert type(description) == Description\n        assert description.data_model is AGENT_SET_SERVICE_MODEL\n        assert description.values.get(\"key\", \"\") == self.service_data[\"key\"]\n        assert description.values.get(\"value\", \"\") == self.service_data[\"value\"]\n\n    def test_get_register_personality_description(self):\n        \"\"\"Test the get_register_personality_description method of the Strategy class.\"\"\"\n        description = self.strategy.get_register_personality_description()\n\n        assert type(description) == Description\n        assert description.data_model is AGENT_PERSONALITY_MODEL\n        assert description.values.get(\"piece\", \"\") == self.personality_data[\"piece\"]\n        assert description.values.get(\"value\", \"\") == self.personality_data[\"value\"]\n\n    def test_get_register_classification_description(self):\n        \"\"\"Test the get_register_classification_description method of the Strategy class.\"\"\"\n        description = self.strategy.get_register_classification_description()\n\n        assert type(description) == Description\n        assert description.data_model is AGENT_PERSONALITY_MODEL\n        assert description.values.get(\"piece\", \"\") == self.classification[\"piece\"]\n        assert description.values.get(\"value\", \"\") == self.classification[\"value\"]\n\n    def test_get_service_description(self):\n        \"\"\"Test the get_service_description method of the Strategy class.\"\"\"\n        description = self.strategy.get_service_description()\n\n        assert type(description) == Description\n        assert description.data_model is SIMPLE_SERVICE_MODEL\n        assert (\n            description.values.get(\"seller_service\", \"\") == self.service_data[\"value\"]\n        )\n\n    def test_get_unregister_service_description(self):\n        \"\"\"Test the get_unregister_service_description method of the Strategy class.\"\"\"\n        description = self.strategy.get_unregister_service_description()\n\n        assert type(description) == Description\n        assert description.data_model is AGENT_REMOVE_SERVICE_MODEL\n        assert description.values.get(\"key\", \"\") == self.service_data[\"key\"]\n\n    def test_get_deploy_terms(self):\n        \"\"\"Test the get_deploy_terms of Strategy.\"\"\"\n        assert self.strategy.get_deploy_terms() == Terms(\n            ledger_id=self.ledger_id,\n            sender_address=self.skill.skill_context.agent_address,\n            counterparty_address=self.skill.skill_context.agent_address,\n            amount_by_currency_id={},\n            quantities_by_good_id={},\n            nonce=\"\",\n        )\n\n    def test_get_create_token_terms(self):\n        \"\"\"Test the get_create_token_terms of Parameters.\"\"\"\n        assert self.strategy.get_create_token_terms() == Terms(\n            ledger_id=self.ledger_id,\n            sender_address=self.skill.skill_context.agent_address,\n            counterparty_address=self.skill.skill_context.agent_address,\n            amount_by_currency_id={},\n            quantities_by_good_id={},\n            nonce=\"\",\n        )\n\n    def test_get_mint_token_terms(self):\n        \"\"\"Test the get_mint_token_terms of Strategy.\"\"\"\n        assert self.strategy.get_mint_token_terms() == Terms(\n            ledger_id=self.ledger_id,\n            sender_address=self.skill.skill_context.agent_address,\n            counterparty_address=self.skill.skill_context.agent_address,\n            amount_by_currency_id={},\n            quantities_by_good_id={},\n            nonce=\"\",\n        )\n\n    def test_get_proposal(self):\n        \"\"\"Test the get_proposal of Strategy.\"\"\"\n        # setup\n        self.strategy._contract_address = self.contract_address\n        first_id = 8768\n        self.strategy._token_ids = [first_id, 234, 879643]\n\n        # operation\n        actual_proposal = self.strategy.get_proposal()\n\n        # after\n        assert all(\n            keys in actual_proposal.values\n            for keys in [\n                \"contract_address\",\n                \"token_id\",\n                \"trade_nonce\",\n                \"from_supply\",\n                \"to_supply\",\n            ]\n        )\n        assert (\n            actual_proposal.values.get(\"contract_address\", \"\") == self.contract_address\n        )\n        assert actual_proposal.values.get(\"token_id\", \"\") == str(first_id)\n        assert isinstance(actual_proposal.values.get(\"trade_nonce\", \"\"), str)\n        assert actual_proposal.values.get(\"from_supply\", \"\") == str(self.from_supply)\n        assert actual_proposal.values.get(\"to_supply\", \"\") == str(self.to_supply)\n        assert actual_proposal.values.get(\"value\", \"\") == str(self.value)\n\n    def test_get_single_swap_terms(self):\n        \"\"\"Test the get_single_swap_terms of Strategy.\"\"\"\n        assert self.strategy.get_single_swap_terms(\n            self.mocked_proposal, \"some_address\"\n        ) == Terms(\n            ledger_id=self.ledger_id,\n            sender_address=self.skill.skill_context.agent_address,\n            counterparty_address=\"some_address\",\n            amount_by_currency_id={\n                str(self.mocked_proposal.values[\"token_id\"]): int(\n                    self.mocked_proposal.values[\"from_supply\"]\n                )\n                - int(self.mocked_proposal.values[\"to_supply\"])\n            },\n            quantities_by_good_id={},\n            is_sender_payable_tx_fee=True,\n            nonce=str(self.mocked_proposal.values[\"trade_nonce\"]),\n            fee_by_currency_id={},\n        )\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_fetch_block/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"The tests module contains the tests of the packages/skills/fetch_block dir.\"\"\"\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_fetch_block/test_behaviours.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the behaviour classes of the fetch block skill.\"\"\"\n\nfrom pathlib import Path\nfrom typing import cast\n\nfrom aea.test_tools.test_skill import BaseSkillTestCase\n\nfrom packages.fetchai.protocols.ledger_api.custom_types import Kwargs\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\nfrom packages.fetchai.skills.fetch_block.behaviours import FetchBlockBehaviour\n\nfrom tests.conftest import ROOT_DIR\n\n\nLEDGER_ID = \"fetchai\"\n\n\nclass TestSkillBehaviour(BaseSkillTestCase):\n    \"\"\"Test behaviours of fetch block.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"fetch_block\")\n\n    @classmethod\n    def setup(cls, **kwargs):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.fetch_block_behaviour = cast(\n            FetchBlockBehaviour,\n            cls._skill.skill_context.behaviours.fetch_block_behaviour,\n        )\n\n    def test__get_block(self):\n        \"\"\"Test that the _get_block function sends the right message to the ledger_api.\"\"\"\n\n        self.fetch_block_behaviour._get_block()\n        self.assert_quantity_in_outbox(1)\n\n        msg = cast(LedgerApiMessage, self.get_message_from_outbox())\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=msg,\n            message_type=LedgerApiMessage,\n            performative=LedgerApiMessage.Performative.GET_STATE,\n            ledger_id=LEDGER_ID,\n            callable=\"blocks\",\n            args=(\"latest\",),\n            kwargs=Kwargs({}),\n        )\n        assert has_attributes, error_str\n\n    def test_setup(self):\n        \"\"\"Test that the setup method puts no messages in the outbox by default.\"\"\"\n        self.fetch_block_behaviour.setup()\n        self.assert_quantity_in_outbox(0)\n\n    def test_act(self):\n        \"\"\"Test that the act method of the fetch_block behaviour puts the correct message in the outbox.\"\"\"\n        self.fetch_block_behaviour.act()\n        self.assert_quantity_in_outbox(1)\n        msg = cast(LedgerApiMessage, self.get_message_from_outbox())\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=msg,\n            message_type=LedgerApiMessage,\n            performative=LedgerApiMessage.Performative.GET_STATE,\n            ledger_id=LEDGER_ID,\n            callable=\"blocks\",\n            args=(\"latest\",),\n            kwargs=Kwargs({}),\n        )\n        assert has_attributes, error_str\n\n    def test_teardown(self):\n        \"\"\"Test that the teardown method of the fetch_block behaviour leaves no messages in the outbox.\"\"\"\n        assert self.fetch_block_behaviour.teardown() is None\n        self.assert_quantity_in_outbox(0)\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_fetch_block/test_handlers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the handler classes of the simple_data_request skill.\"\"\"\n\nimport logging\nfrom pathlib import Path\nfrom typing import cast\nfrom unittest.mock import patch\n\nfrom aea.protocols.dialogue.base import DialogueMessage\nfrom aea.test_tools.test_skill import BaseSkillTestCase\n\nfrom packages.fetchai.protocols.ledger_api.custom_types import State\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\nfrom packages.fetchai.skills.fetch_block.behaviours import FetchBlockBehaviour\nfrom packages.fetchai.skills.fetch_block.dialogues import LedgerApiDialogues\nfrom packages.fetchai.skills.fetch_block.handlers import LedgerApiHandler\n\nfrom tests.conftest import ROOT_DIR\n\n\nLEDGER_ID = \"fetchai\"\n\n\nclass TestLedgerApiHandler(BaseSkillTestCase):\n    \"\"\"Test ledger_api handler of fetch_block skill.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"fetch_block\")\n    is_agent_to_agent_messages = False\n\n    @classmethod\n    def setup(cls, **kwargs):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup(**kwargs)\n        cls.ledger_api_handler = cast(\n            LedgerApiHandler, cls._skill.skill_context.handlers.ledger_api\n        )\n        cls.logger = cls._skill.skill_context.logger\n        cls.fetch_block_behaviour = cast(\n            FetchBlockBehaviour,\n            cls._skill.skill_context.behaviours.fetch_block_behaviour,\n        )\n        cls.ledger_api_dialogues = cast(\n            LedgerApiDialogues, cls._skill.skill_context.ledger_api_dialogues\n        )\n\n        cls.list_of_ledger_api_messages = (\n            DialogueMessage(\n                LedgerApiMessage.Performative.GET_STATE,\n                {\n                    \"ledger_id\": LEDGER_ID,\n                    \"callable\": \"blocks\",\n                    \"args\": (\"latest\",),\n                    \"kwargs\": LedgerApiMessage.Kwargs({}),\n                },\n            ),\n            DialogueMessage(\n                LedgerApiMessage.Performative.GET_BALANCE,\n                {\"ledger_id\": LEDGER_ID, \"address\": \"some_eth_address\"},\n            ),\n        )\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the ledger_api handler.\"\"\"\n        assert self.ledger_api_handler.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle__handle_unidentified_dialogue(self):\n        \"\"\"Test handling an unidentified dialogoue\"\"\"\n        # setup\n        incorrect_dialogue_reference = (\"\", \"\")\n        incoming_message = self.build_incoming_message(\n            message_type=LedgerApiMessage,\n            dialogue_reference=incorrect_dialogue_reference,\n            performative=LedgerApiMessage.Performative.GET_STATE,\n            ledger_id=LEDGER_ID,\n            callable=\"blocks\",\n            args=(\"latest\",),\n            kwargs=LedgerApiMessage.Kwargs({}),\n        )\n\n        # operation\n        with patch.object(self.ledger_api_handler.context.logger, \"log\") as mock_logger:\n            self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received invalid ledger_api message={incoming_message}, unidentified dialogue.\",\n        )\n\n        self.assert_quantity_in_outbox(0)\n\n    def test__handle_state(self):\n        \"\"\"Test handling a state\"\"\"\n\n        # setup\n        test_block_data = {\n            \"block_id\": {\"hash\": \"00000000\"},\n            \"block\": {\n                \"header\": {\"height\": \"1\", \"entropy\": {\"group_signature\": \"SIGNATURE\"}}\n            },\n        }\n        dialogue = self.prepare_skill_dialogue(\n            self.ledger_api_dialogues, self.list_of_ledger_api_messages[:1]\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=dialogue,\n            performative=LedgerApiMessage.Performative.STATE,\n            ledger_id=LEDGER_ID,\n            state=State(LEDGER_ID, test_block_data),\n        )\n\n        # handle message\n        with patch.object(self.ledger_api_handler.context.logger, \"log\") as mock_logger:\n            self.ledger_api_handler.handle(incoming_message)\n\n        # check that data was correctly entered into shared state\n        assert self.ledger_api_handler.context.shared_state[\"observation\"] == {\n            \"block\": test_block_data\n        }\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            \"Retrieved latest block: \" + str({\"block_height\": 1}),\n        )\n\n        self.assert_quantity_in_outbox(0)\n\n    def test__handle_invalid(self):\n        \"\"\"Test handling an invalid performative\"\"\"\n        # setup\n        dialogue = self.prepare_skill_dialogue(\n            self.ledger_api_dialogues, self.list_of_ledger_api_messages[1:]\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=dialogue,\n            performative=LedgerApiMessage.Performative.BALANCE,\n            ledger_id=LEDGER_ID,\n            balance=0,\n        )\n\n        # operation\n        with patch.object(self.ledger_api_handler.context.logger, \"log\") as mock_logger:\n            self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"cannot handle ledger_api message of performative={incoming_message.performative} in dialogue={dialogue}.\",\n        )\n\n        self.assert_quantity_in_outbox(0)\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the ledger_api handler.\"\"\"\n        assert self.ledger_api_handler.teardown() is None\n        self.assert_quantity_in_outbox(0)\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_hello_world/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"Tests for fetchai/hellow_world skill.\"\"\"\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_hello_world/test_behaviours.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"Tests for hello_world skill's behaviour.\"\"\"\n\nimport logging\nfrom pathlib import Path\nfrom typing import cast\nfrom unittest.mock import patch\n\nfrom aea.test_tools.test_skill import BaseSkillTestCase\n\nfrom packages.fetchai.skills.hello_world.behaviours import HelloWorld\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass TestHelloWorld(BaseSkillTestCase):\n    \"\"\"Test HelloWorld behaviour of hello world.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"hello_world\")\n    is_agent_to_agent_messages = False\n\n    def setup_method(self):\n        \"\"\"Set up the test environment.\"\"\"\n        self.message = \"Hello Something Custom!\"\n        config_overrides = {\n            \"behaviours\": {\"hello_world\": {\"args\": {\"message\": self.message}}}\n        }\n\n        super().setup(config_overrides=config_overrides)\n        self.hello_world_behaviour = cast(\n            HelloWorld, self._skill.skill_context.behaviours.hello_world\n        )\n        self.logger = self._skill.skill_context.logger\n\n    def test_act(self):\n        \"\"\"Test the act method of the hello_world behaviour.\"\"\"\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            assert self.hello_world_behaviour.act() is None\n\n        # after\n        mock_logger.assert_any_call(logging.INFO, self.message)\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_http_echo/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"The tests module contains the tests of the packages/skills/http_echo dir.\"\"\"\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_http_echo/test_dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the dialogue classes of the http_echo skill.\"\"\"\n\nfrom pathlib import Path\nfrom typing import cast\n\nfrom aea.test_tools.test_skill import BaseSkillTestCase, COUNTERPARTY_AGENT_ADDRESS\n\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.protocols.http.message import HttpMessage\nfrom packages.fetchai.skills.http_echo.dialogues import (\n    DefaultDialogue,\n    DefaultDialogues,\n    HttpDialogue,\n    HttpDialogues,\n)\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass TestDialogues(BaseSkillTestCase):\n    \"\"\"Test dialogue class of http_echo.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"http_echo\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.default_dialogues = cast(\n            DefaultDialogues, cls._skill.skill_context.default_dialogues\n        )\n        cls.http_dialogues = cast(\n            HttpDialogues, cls._skill.skill_context.http_dialogues\n        )\n\n    def test_default_dialogues(self):\n        \"\"\"Test the DefaultDialogues class.\"\"\"\n        _, dialogue = self.default_dialogues.create(\n            counterparty=COUNTERPARTY_AGENT_ADDRESS,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"some_content\",\n        )\n        assert dialogue.role == DefaultDialogue.Role.AGENT\n        assert dialogue.self_address == self.skill.skill_context.agent_address\n\n    def test_http_dialogues(self):\n        \"\"\"Test the HttpDialogues class.\"\"\"\n        _, dialogue = self.http_dialogues.create(\n            counterparty=COUNTERPARTY_AGENT_ADDRESS,\n            performative=HttpMessage.Performative.REQUEST,\n            method=\"some_method\",\n            url=\"some_url\",\n            version=\"some_version\",\n            headers=\"some_headers\",\n            body=b\"some_body\",\n        )\n        assert dialogue.role == HttpDialogue.Role.SERVER\n        assert dialogue.self_address == str(self.skill.skill_context.skill_id)\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_http_echo/test_handlers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the handler class of the http_echo skill.\"\"\"\n\nimport json\nimport logging\nfrom pathlib import Path\nfrom typing import cast\nfrom unittest.mock import patch\n\nfrom aea.protocols.dialogue.base import DialogueMessage\nfrom aea.test_tools.test_skill import BaseSkillTestCase\n\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.protocols.http.message import HttpMessage\nfrom packages.fetchai.skills.http_echo.dialogues import HttpDialogues\nfrom packages.fetchai.skills.http_echo.handlers import HttpHandler\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass TestHttpHandler(BaseSkillTestCase):\n    \"\"\"Test HttpHandler of http_echo.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"http_echo\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.http_handler = cast(\n            HttpHandler, cls._skill.skill_context.handlers.http_handler\n        )\n        cls.logger = cls._skill.skill_context.logger\n\n        cls.http_dialogues = cast(\n            HttpDialogues, cls._skill.skill_context.http_dialogues\n        )\n\n        cls.get_method = \"get\"\n        cls.post_method = \"post\"\n        cls.url = \"some_url\"\n        cls.version = \"some_version\"\n        cls.headers = \"some_headers\"\n        cls.body = b\"some_body\"\n        cls.sender = \"fetchai/some_skill:0.1.0\"\n        cls.skill_id = str(cls._skill.skill_context.skill_id)\n\n        cls.status_code = 100\n        cls.status_text = \"some_status_text\"\n\n        cls.content = b\"some_content\"\n        cls.list_of_messages = (\n            DialogueMessage(\n                HttpMessage.Performative.REQUEST,\n                {\n                    \"method\": cls.get_method,\n                    \"url\": cls.url,\n                    \"version\": cls.version,\n                    \"headers\": cls.headers,\n                    \"body\": cls.body,\n                },\n            ),\n        )\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the http_echo handler.\"\"\"\n        assert self.http_handler.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle_unidentified_dialogue(self):\n        \"\"\"Test the _handle_unidentified_dialogue method of the http_echo handler.\"\"\"\n        # setup\n        incorrect_dialogue_reference = (\"\", \"\")\n        incoming_message = self.build_incoming_message(\n            message_type=HttpMessage,\n            dialogue_reference=incorrect_dialogue_reference,\n            performative=HttpMessage.Performative.REQUEST,\n            to=self.skill_id,\n            method=self.get_method,\n            url=self.url,\n            version=self.version,\n            headers=self.headers,\n            body=self.body,\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.http_handler.handle(incoming_message)\n\n        # after\n        self.assert_quantity_in_outbox(1)\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received invalid http message={incoming_message}, unidentified dialogue.\",\n        )\n\n        message = self.get_message_from_outbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=DefaultMessage,\n            performative=DefaultMessage.Performative.ERROR,\n            to=incoming_message.sender,\n            sender=self.skill.skill_context.agent_address,\n            error_code=DefaultMessage.ErrorCode.INVALID_DIALOGUE,\n            error_msg=\"Invalid dialogue.\",\n            error_data={\"http_message\": incoming_message.encode()},\n        )\n        assert has_attributes, error_str\n\n    def test_handle_request_get(self):\n        \"\"\"Test the _handle_request method of the http_echo handler where method is get.\"\"\"\n        # setup\n        incoming_message = cast(\n            HttpMessage,\n            self.build_incoming_message(\n                message_type=HttpMessage,\n                performative=HttpMessage.Performative.REQUEST,\n                to=self.skill_id,\n                sender=self.sender,\n                method=self.get_method,\n                url=self.url,\n                version=self.version,\n                headers=self.headers,\n                body=self.body,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.http_handler.handle(incoming_message)\n\n        # after\n        self.assert_quantity_in_outbox(1)\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            \"received http request with method={}, url={} and body={!r}\".format(\n                incoming_message.method, incoming_message.url, incoming_message.body\n            ),\n        )\n\n        # _handle_get\n        message = self.get_message_from_outbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=HttpMessage,\n            performative=HttpMessage.Performative.RESPONSE,\n            to=incoming_message.sender,\n            sender=incoming_message.to,\n            version=incoming_message.version,\n            status_code=200,\n            status_text=\"Success\",\n            headers=incoming_message.headers,\n            body=json.dumps({\"tom\": {\"type\": \"cat\", \"age\": 10}}).encode(\"utf-8\"),\n        )\n        assert has_attributes, error_str\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"responding with: {message}\",\n        )\n\n    def test_handle_request_post(self):\n        \"\"\"Test the _handle_request method of the http_echo handler where method is post.\"\"\"\n        # setup\n        incoming_message = cast(\n            HttpMessage,\n            self.build_incoming_message(\n                message_type=HttpMessage,\n                performative=HttpMessage.Performative.REQUEST,\n                to=self.skill_id,\n                sender=self.sender,\n                method=self.post_method,\n                url=self.url,\n                version=self.version,\n                headers=self.headers,\n                body=self.body,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.http_handler.handle(incoming_message)\n\n        # after\n        self.assert_quantity_in_outbox(1)\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            \"received http request with method={}, url={} and body={!r}\".format(\n                incoming_message.method, incoming_message.url, incoming_message.body\n            ),\n        )\n\n        # _handle_post\n        message = self.get_message_from_outbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=HttpMessage,\n            performative=HttpMessage.Performative.RESPONSE,\n            to=incoming_message.sender,\n            sender=incoming_message.to,\n            version=incoming_message.version,\n            status_code=200,\n            status_text=\"Success\",\n            headers=incoming_message.headers,\n            body=self.body,\n        )\n        assert has_attributes, error_str\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"responding with: {message}\",\n        )\n\n    def test_handle_invalid(self):\n        \"\"\"Test the _handle_invalid method of the http_echo handler.\"\"\"\n        # setup\n        http_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.http_dialogues,\n            messages=self.list_of_messages[:1],\n        )\n        incoming_message = cast(\n            HttpMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=http_dialogue,\n                performative=HttpMessage.Performative.RESPONSE,\n                version=self.version,\n                status_code=self.status_code,\n                status_text=self.status_text,\n                headers=self.headers,\n                body=self.body,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.http_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"cannot handle http message of performative={incoming_message.performative} in dialogue={http_dialogue}.\",\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the http_echo handler.\"\"\"\n        assert self.http_handler.teardown() is None\n        self.assert_quantity_in_outbox(0)\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_ml_data_provider/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"The tests module contains the tests of the packages/skills/ml_data_provider dir.\"\"\"\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_ml_data_provider/test_dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the dialogue classes of the ml_data_provider skill.\"\"\"\n\nfrom pathlib import Path\nfrom typing import cast\n\nfrom aea.test_tools.test_skill import BaseSkillTestCase, COUNTERPARTY_AGENT_ADDRESS\n\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\nfrom packages.fetchai.protocols.ml_trade.message import MlTradeMessage\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.skills.ml_data_provider.dialogues import (\n    DefaultDialogue,\n    DefaultDialogues,\n    LedgerApiDialogue,\n    LedgerApiDialogues,\n    MlTradeDialogue,\n    MlTradeDialogues,\n    OefSearchDialogue,\n    OefSearchDialogues,\n)\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass TestDialogues(BaseSkillTestCase):\n    \"\"\"Test dialogue classes of ml_data_provider.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"ml_data_provider\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.default_dialogues = cast(\n            DefaultDialogues, cls._skill.skill_context.default_dialogues\n        )\n        cls.ml_dialogues = cast(\n            MlTradeDialogues, cls._skill.skill_context.ml_trade_dialogues\n        )\n        cls.ledger_api_dialogues = cast(\n            LedgerApiDialogues, cls._skill.skill_context.ledger_api_dialogues\n        )\n        cls.oef_search_dialogues = cast(\n            OefSearchDialogues, cls._skill.skill_context.oef_search_dialogues\n        )\n\n    def test_default_dialogues(self):\n        \"\"\"Test the DefaultDialogues class.\"\"\"\n        _, dialogue = self.default_dialogues.create(\n            counterparty=COUNTERPARTY_AGENT_ADDRESS,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"some_content\",\n        )\n        assert dialogue.role == DefaultDialogue.Role.AGENT\n        assert dialogue.self_address == self.skill.skill_context.agent_address\n\n    def test_ml_dialogues(self):\n        \"\"\"Test the MlTradeDialogues class.\"\"\"\n        _, dialogue = self.ml_dialogues.create(\n            counterparty=COUNTERPARTY_AGENT_ADDRESS,\n            performative=MlTradeMessage.Performative.CFP,\n            query=\"some_query\",\n        )\n        assert dialogue.role == MlTradeDialogue.Role.SELLER\n        assert dialogue.self_address == self.skill.skill_context.agent_address\n\n    def test_ledger_api_dialogues(self):\n        \"\"\"Test the LedgerApiDialogues class.\"\"\"\n        _, dialogue = self.ledger_api_dialogues.create(\n            counterparty=COUNTERPARTY_AGENT_ADDRESS,\n            performative=LedgerApiMessage.Performative.GET_BALANCE,\n            ledger_id=\"some_ledger_id\",\n            address=\"some_address\",\n        )\n        assert dialogue.role == LedgerApiDialogue.Role.AGENT\n        assert dialogue.self_address == str(self.skill.skill_context.skill_id)\n\n    def test_oef_search_dialogues(self):\n        \"\"\"Test the OefSearchDialogues class.\"\"\"\n        _, dialogue = self.oef_search_dialogues.create(\n            counterparty=COUNTERPARTY_AGENT_ADDRESS,\n            performative=OefSearchMessage.Performative.SEARCH_SERVICES,\n            query=\"some_query\",\n        )\n        assert dialogue.role == OefSearchDialogue.Role.AGENT\n        assert dialogue.self_address == str(self.skill.skill_context.skill_id)\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_ml_data_provider/test_handlers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the handler classes of the ml_data_provider skill.\"\"\"\n\nimport logging\nimport uuid\nfrom pathlib import Path\nfrom typing import cast\nfrom unittest.mock import patch\n\nfrom aea.helpers.search.models import Attribute, DataModel, Description, Location\nfrom aea.helpers.transaction.base import TransactionDigest, TransactionReceipt\nfrom aea.protocols.dialogue.base import DialogueMessage, Dialogues\nfrom aea.test_tools.test_skill import BaseSkillTestCase, COUNTERPARTY_AGENT_ADDRESS\n\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\nfrom packages.fetchai.protocols.ml_trade.message import MlTradeMessage\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.skills.ml_data_provider.behaviours import (\n    ServiceRegistrationBehaviour,\n)\nfrom packages.fetchai.skills.ml_data_provider.dialogues import (\n    LedgerApiDialogue,\n    LedgerApiDialogues,\n    MlTradeDialogue,\n    MlTradeDialogues,\n    OefSearchDialogues,\n)\nfrom packages.fetchai.skills.ml_data_provider.handlers import (\n    LedgerApiHandler,\n    MlTradeHandler,\n    OefSearchHandler,\n)\nfrom packages.fetchai.skills.ml_data_provider.strategy import Strategy\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass TestMlTradeHandler(BaseSkillTestCase):\n    \"\"\"Test ml handler of ml_data_provider.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"ml_data_provider\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.ml_handler = cast(\n            MlTradeHandler, cls._skill.skill_context.handlers.ml_trade\n        )\n        cls.strategy = cast(Strategy, cls._skill.skill_context.strategy)\n        cls.ml_dialogues = cast(\n            MlTradeDialogues, cls._skill.skill_context.ml_trade_dialogues\n        )\n        cls.logger = cls._skill.skill_context.logger\n\n        cls.batch_size = 32\n        cls.price_per_data_batch = 10\n        cls.seller_tx_fee = 0\n        cls.buyer_tx_fee = 0\n        cls.currency_id = \"FET\"\n        cls.ledger_id = \"FET\"\n        cls.service_id = \"data_service\"\n\n        cls.terms = Description(\n            {\n                \"batch_size\": cls.batch_size,\n                \"price\": cls.price_per_data_batch,\n                \"seller_tx_fee\": cls.seller_tx_fee,\n                \"buyer_tx_fee\": cls.buyer_tx_fee,\n                \"currency_id\": cls.currency_id,\n                \"ledger_id\": cls.ledger_id,\n                \"address\": cls._skill.skill_context.agent_address,\n                \"service_id\": cls.service_id,\n                \"nonce\": uuid.uuid4().hex,\n            }\n        )\n\n        cls.list_of_messages = (\n            DialogueMessage(MlTradeMessage.Performative.CFP, {\"query\": \"some_query\"}),\n            DialogueMessage(MlTradeMessage.Performative.TERMS, {\"terms\": cls.terms}),\n            DialogueMessage(\n                MlTradeMessage.Performative.ACCEPT,\n                {\"terms\": cls.terms, \"tx_digest\": \"some_tx_digest\"},\n            ),\n        )\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the ml handler.\"\"\"\n        assert self.ml_handler.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle_unidentified_dialogue(self):\n        \"\"\"Test the _handle_unidentified_dialogue method of the ml handler.\"\"\"\n        # setup\n        incorrect_dialogue_reference = (\"\", \"\")\n        incoming_message = self.build_incoming_message(\n            message_type=MlTradeMessage,\n            dialogue_reference=incorrect_dialogue_reference,\n            performative=MlTradeMessage.Performative.ACCEPT,\n            terms=self.terms,\n            tx_digest=\"some_tx_digest\",\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.ml_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received invalid ml_trade message={incoming_message}, unidentified dialogue.\",\n        )\n        self.assert_quantity_in_outbox(1)\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=DefaultMessage,\n            performative=DefaultMessage.Performative.ERROR,\n            to=incoming_message.sender,\n            sender=self.skill.skill_context.agent_address,\n            error_code=DefaultMessage.ErrorCode.INVALID_DIALOGUE,\n            error_msg=\"Invalid dialogue.\",\n            error_data={\"ml_trade_message\": incoming_message.encode()},\n        )\n        assert has_attributes, error_str\n\n    def test_handle_cfp_is_matching_supply(self):\n        \"\"\"Test the _handle_cfp method of the ml handler where is_matching_supply is True.\"\"\"\n        # setup\n        incoming_message = self.build_incoming_message(\n            message_type=MlTradeMessage,\n            performative=MlTradeMessage.Performative.CFP,\n            dialogue_reference=Dialogues.new_self_initiated_dialogue_reference(),\n            query=\"some_query\",\n        )\n\n        # operation\n        with patch.object(self.strategy, \"is_matching_supply\", return_value=True):\n            with patch.object(self.strategy, \"generate_terms\", return_value=self.terms):\n                with patch.object(self.logger, \"log\") as mock_logger:\n                    self.ml_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"got a Call for Terms from {COUNTERPARTY_AGENT_ADDRESS[-5:]}.\",\n        )\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"sending to the address={COUNTERPARTY_AGENT_ADDRESS[-5:]} a Terms message: {self.terms.values}\",\n        )\n\n        self.assert_quantity_in_outbox(1)\n\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=MlTradeMessage,\n            performative=MlTradeMessage.Performative.TERMS,\n            to=COUNTERPARTY_AGENT_ADDRESS,\n            sender=self.skill.skill_context.agent_address,\n            target=incoming_message.message_id,\n            terms=self.terms,\n        )\n        assert has_attributes, error_str\n\n    def test_handle_cfp_not_is_matching_supply(self):\n        \"\"\"Test the _handle_cfp method of the ml handler where is_matching_supply is False.\"\"\"\n        # setup\n        incoming_message = self.build_incoming_message(\n            message_type=MlTradeMessage,\n            performative=MlTradeMessage.Performative.CFP,\n            dialogue_reference=Dialogues.new_self_initiated_dialogue_reference(),\n            query=\"some_query\",\n        )\n\n        # operation\n        with patch.object(self.strategy, \"is_matching_supply\", return_value=False):\n            with patch.object(self.logger, \"log\") as mock_logger:\n                self.ml_handler.handle(incoming_message)\n\n        # after\n        self.assert_quantity_in_outbox(0)\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"got a Call for Terms from {COUNTERPARTY_AGENT_ADDRESS[-5:]}.\",\n        )\n        mock_logger.assert_any_call(logging.INFO, \"query does not match supply.\")\n\n    def test_handle_accept_i(self):\n        \"\"\"Test the _handle_accept method of the ml handler.\"\"\"\n        # setup\n        mocked_tx_digest = \"some_tx_digest\"\n        terms = self.strategy.generate_terms()\n        expected_data = self.strategy.sample_data(terms.values[\"batch_size\"])\n\n        ml_dialogue = cast(\n            MlTradeDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.ml_dialogues,\n                messages=self.list_of_messages[:2],\n            ),\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=ml_dialogue,\n            performative=MlTradeMessage.Performative.ACCEPT,\n            terms=terms,\n            tx_digest=mocked_tx_digest,\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.ml_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"got an Accept from {COUNTERPARTY_AGENT_ADDRESS[-5:]}: {terms.values}\",\n        )\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"sending to address={COUNTERPARTY_AGENT_ADDRESS[-5:]} a Data message: shape={expected_data[0].shape}\",\n        )\n\n        self.assert_quantity_in_outbox(1)\n        message = cast(MlTradeMessage, self.get_message_from_outbox())\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=MlTradeMessage,\n            performative=MlTradeMessage.Performative.DATA,\n            to=COUNTERPARTY_AGENT_ADDRESS,\n            sender=self.skill.skill_context.agent_address,\n            terms=terms,\n        )\n        assert has_attributes, error_str\n        assert type(message.payload) == bytes\n\n    def test_handle_accept_ii(self):\n        \"\"\"Test the _handle_accept method of the ml handler where terms is NOT valid.\"\"\"\n        # setup\n        mocked_tx_digest = \"some_tx_digest\"\n\n        ml_dialogue = cast(\n            MlTradeDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.ml_dialogues,\n                messages=self.list_of_messages[:2],\n            ),\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=ml_dialogue,\n            performative=MlTradeMessage.Performative.ACCEPT,\n            terms=self.terms,\n            tx_digest=mocked_tx_digest,\n        )\n\n        # operation\n        with patch.object(self.strategy, \"is_valid_terms\", return_value=False):\n            with patch.object(self.logger, \"log\") as mock_logger:\n                self.ml_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"got an Accept from {COUNTERPARTY_AGENT_ADDRESS[-5:]}: {self.terms.values}\",\n        )\n        mock_logger.assert_any_call(logging.INFO, \"terms are not valid.\")\n\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle_invalid(self):\n        \"\"\"Test the _handle_invalid method of the ml handler.\"\"\"\n        # setup\n        ml_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.ml_dialogues,\n            messages=self.list_of_messages[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=ml_dialogue,\n            performative=MlTradeMessage.Performative.TERMS,\n            terms=self.terms,\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.ml_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"cannot handle ml_trade message of performative={incoming_message.performative} in dialogue={ml_dialogue}.\",\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the ml handler.\"\"\"\n        assert self.ml_handler.teardown() is None\n        self.assert_quantity_in_outbox(0)\n\n\nclass TestLedgerApiHandler(BaseSkillTestCase):\n    \"\"\"Test ledger_api handler of ml_data_provider.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"ml_data_provider\")\n    is_agent_to_agent_messages = False\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.ledger_api_handler = cast(\n            LedgerApiHandler, cls._skill.skill_context.handlers.ledger_api\n        )\n        cls.strategy = cast(Strategy, cls._skill.skill_context.strategy)\n        cls.ml_dialogues = cast(\n            MlTradeDialogues, cls._skill.skill_context.ml_trade_dialogues\n        )\n        cls.ledger_api_dialogues = cast(\n            LedgerApiDialogues, cls._skill.skill_context.ledger_api_dialogues\n        )\n        cls.logger = cls._skill.skill_context.logger\n\n        cls.ledger_id = \"FET\"\n        cls.transaction_digest = TransactionDigest(\"some_ledger_id\", \"some_body\")\n        cls.transaction_receipt = TransactionReceipt(\n            \"some_ledger_id\", {\"some_key\": \"some_value\"}, {\"some_key\": \"some_value\"}\n        )\n        cls.list_of_ledger_api_messages = (\n            DialogueMessage(\n                LedgerApiMessage.Performative.GET_TRANSACTION_RECEIPT,\n                {\"transaction_digest\": cls.transaction_digest},\n            ),\n            DialogueMessage(\n                LedgerApiMessage.Performative.TRANSACTION_RECEIPT,\n                {\"transaction_receipt\": cls.transaction_receipt},\n            ),\n        )\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the ledger_api handler.\"\"\"\n        assert self.ledger_api_handler.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle_unidentified_dialogue(self):\n        \"\"\"Test the _handle_unidentified_dialogue method of the ledger_api handler.\"\"\"\n        # setup\n        incorrect_dialogue_reference = (\"\", \"\")\n        incoming_message = self.build_incoming_message(\n            message_type=LedgerApiMessage,\n            dialogue_reference=incorrect_dialogue_reference,\n            performative=LedgerApiMessage.Performative.GET_BALANCE,\n            ledger_id=\"some_ledger_id\",\n            address=\"some_address\",\n        )\n\n        # operation\n        with patch.object(self.ledger_api_handler.context.logger, \"log\") as mock_logger:\n            self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received invalid ledger_api message={incoming_message}, unidentified dialogue.\",\n        )\n\n    def test_handle_balance(self):\n        \"\"\"Test the _handle_balance method of the ledger_api handler.\"\"\"\n        # setup\n        ledger_api_dialogue = cast(\n            LedgerApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.ledger_api_dialogues,\n                messages=(\n                    DialogueMessage(\n                        LedgerApiMessage.Performative.GET_BALANCE,\n                        {\"ledger_id\": \"some_ledger_id\", \"address\": \"some_address\"},\n                    ),\n                ),\n            ),\n        )\n        incoming_message = cast(\n            LedgerApiMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=ledger_api_dialogue,\n                performative=LedgerApiMessage.Performative.BALANCE,\n                ledger_id=self.ledger_id,\n                balance=10,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"starting balance on {self.ledger_id} ledger={incoming_message.balance}.\",\n        )\n\n    def test_handle_error(self):\n        \"\"\"Test the _handle_error method of the ledger_api handler.\"\"\"\n        # setup\n        ledger_api_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.ledger_api_dialogues,\n            messages=self.list_of_ledger_api_messages[:1],\n        )\n        incoming_message = cast(\n            LedgerApiMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=ledger_api_dialogue,\n                performative=LedgerApiMessage.Performative.ERROR,\n                code=1,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received ledger_api error message={incoming_message} in dialogue={ledger_api_dialogue}.\",\n        )\n\n    def test_handle_invalid(self):\n        \"\"\"Test the _handle_invalid method of the ledger_api handler.\"\"\"\n        # setup\n        invalid_performative = LedgerApiMessage.Performative.GET_BALANCE\n        incoming_message = self.build_incoming_message(\n            message_type=LedgerApiMessage,\n            dialogue_reference=(\"1\", \"\"),\n            performative=invalid_performative,\n            ledger_id=\"some_ledger_id\",\n            address=\"some_address\",\n            to=str(self.skill.skill_context.skill_id),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"cannot handle ledger_api message of performative={invalid_performative} in dialogue={self.ledger_api_dialogues.get_dialogue(incoming_message)}.\",\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the ledger_api handler.\"\"\"\n        assert self.ledger_api_handler.teardown() is None\n        self.assert_quantity_in_outbox(0)\n\n\nclass TestOefSearchHandler(BaseSkillTestCase):\n    \"\"\"Test oef search handler of ml_data_provider.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"ml_data_provider\")\n    is_agent_to_agent_messages = False\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.oef_search_handler = cast(\n            OefSearchHandler, cls._skill.skill_context.handlers.oef_search\n        )\n        cls.strategy = cast(Strategy, cls._skill.skill_context.strategy)\n        cls.oef_dialogues = cast(\n            OefSearchDialogues, cls._skill.skill_context.oef_search_dialogues\n        )\n        cls.service_registration_behaviour = cast(\n            ServiceRegistrationBehaviour,\n            cls._skill.skill_context.behaviours.service_registration,\n        )\n        cls.list_of_messages = (\n            DialogueMessage(\n                OefSearchMessage.Performative.SEARCH_SERVICES, {\"query\": \"some_query\"}\n            ),\n        )\n\n        cls.register_location_description = Description(\n            {\"location\": Location(51.5194, 0.1270)},\n            data_model=DataModel(\n                \"location_agent\", [Attribute(\"location\", Location, True)]\n            ),\n        )\n        cls.list_of_messages_register_location = (\n            DialogueMessage(\n                OefSearchMessage.Performative.REGISTER_SERVICE,\n                {\"service_description\": cls.register_location_description},\n                is_incoming=False,\n            ),\n        )\n\n        cls.register_service_description = Description(\n            {\"key\": \"some_key\", \"value\": \"some_value\"},\n            data_model=DataModel(\n                \"set_service_key\",\n                [Attribute(\"key\", str, True), Attribute(\"value\", str, True)],\n            ),\n        )\n        cls.list_of_messages_register_service = (\n            DialogueMessage(\n                OefSearchMessage.Performative.REGISTER_SERVICE,\n                {\"service_description\": cls.register_service_description},\n                is_incoming=False,\n            ),\n        )\n\n        cls.register_genus_description = Description(\n            {\"piece\": \"genus\", \"value\": \"some_value\"},\n            data_model=DataModel(\n                \"personality_agent\",\n                [Attribute(\"piece\", str, True), Attribute(\"value\", str, True)],\n            ),\n        )\n        cls.list_of_messages_register_genus = (\n            DialogueMessage(\n                OefSearchMessage.Performative.REGISTER_SERVICE,\n                {\"service_description\": cls.register_genus_description},\n                is_incoming=False,\n            ),\n        )\n\n        cls.register_classification_description = Description(\n            {\"piece\": \"classification\", \"value\": \"some_value\"},\n            data_model=DataModel(\n                \"personality_agent\",\n                [Attribute(\"piece\", str, True), Attribute(\"value\", str, True)],\n            ),\n        )\n        cls.list_of_messages_register_classification = (\n            DialogueMessage(\n                OefSearchMessage.Performative.REGISTER_SERVICE,\n                {\"service_description\": cls.register_classification_description},\n                is_incoming=False,\n            ),\n        )\n\n        cls.register_invalid_description = Description(\n            {\"piece\": \"classification\", \"value\": \"some_value\"},\n            data_model=DataModel(\n                \"some_different_name\",\n                [Attribute(\"piece\", str, True), Attribute(\"value\", str, True)],\n            ),\n        )\n        cls.list_of_messages_register_invalid = (\n            DialogueMessage(\n                OefSearchMessage.Performative.REGISTER_SERVICE,\n                {\"service_description\": cls.register_invalid_description},\n                is_incoming=False,\n            ),\n        )\n\n        cls.unregister_description = Description(\n            {\"key\": \"seller_service\"},\n            data_model=DataModel(\"remove\", [Attribute(\"key\", str, True)]),\n        )\n        cls.list_of_messages_unregister = (\n            DialogueMessage(\n                OefSearchMessage.Performative.UNREGISTER_SERVICE,\n                {\"service_description\": cls.unregister_description},\n                is_incoming=False,\n            ),\n        )\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the oef_search handler.\"\"\"\n        assert self.oef_search_handler.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle_unidentified_dialogue(self):\n        \"\"\"Test the _handle_unidentified_dialogue method of the oef_search handler.\"\"\"\n        # setup\n        incorrect_dialogue_reference = (\"\", \"\")\n        incoming_message = self.build_incoming_message(\n            message_type=OefSearchMessage,\n            dialogue_reference=incorrect_dialogue_reference,\n            performative=OefSearchMessage.Performative.SEARCH_SERVICES,\n        )\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received invalid oef_search message={incoming_message}, unidentified dialogue.\",\n        )\n\n    def test_handle_success_i(self):\n        \"\"\"Test the _handle_success method of the oef_search handler where the oef success targets register_service WITH location_agent data model description.\"\"\"\n        # setup\n        oef_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_dialogues,\n            messages=self.list_of_messages_register_location[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=oef_dialogue,\n            performative=OefSearchMessage.Performative.SUCCESS,\n            agents_info=OefSearchMessage.AgentsInfo({\"address\": {\"key\": \"value\"}}),\n        )\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            with patch.object(\n                self.service_registration_behaviour,\n                \"register_service\",\n            ) as mock_reg:\n                self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received oef_search success message={incoming_message} in dialogue={oef_dialogue}.\",\n        )\n        mock_reg.assert_called_once()\n\n    def test_handle_success_ii(self):\n        \"\"\"Test the _handle_success method of the oef_search handler where the oef success targets register_service WITH set_service_key data model description.\"\"\"\n        # setup\n        oef_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_dialogues,\n            messages=self.list_of_messages_register_service[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=oef_dialogue,\n            performative=OefSearchMessage.Performative.SUCCESS,\n            agents_info=OefSearchMessage.AgentsInfo({\"address\": {\"key\": \"value\"}}),\n        )\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            with patch.object(\n                self.service_registration_behaviour,\n                \"register_genus\",\n            ) as mock_reg:\n                self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received oef_search success message={incoming_message} in dialogue={oef_dialogue}.\",\n        )\n        mock_reg.assert_called_once()\n\n    def test_handle_success_iii(self):\n        \"\"\"Test the _handle_success method of the oef_search handler where the oef success targets register_service WITH personality_agent data model and genus value description.\"\"\"\n        # setup\n        oef_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_dialogues,\n            messages=self.list_of_messages_register_genus[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=oef_dialogue,\n            performative=OefSearchMessage.Performative.SUCCESS,\n            agents_info=OefSearchMessage.AgentsInfo({\"address\": {\"key\": \"value\"}}),\n        )\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            with patch.object(\n                self.service_registration_behaviour,\n                \"register_classification\",\n            ) as mock_reg:\n                self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received oef_search success message={incoming_message} in dialogue={oef_dialogue}.\",\n        )\n        mock_reg.assert_called_once()\n\n    def test_handle_success_iv(self):\n        \"\"\"Test the _handle_success method of the oef_search handler where the oef success targets register_service WITH personality_agent data model and classification value description.\"\"\"\n        # setup\n        oef_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_dialogues,\n            messages=self.list_of_messages_register_classification[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=oef_dialogue,\n            performative=OefSearchMessage.Performative.SUCCESS,\n            agents_info=OefSearchMessage.AgentsInfo({\"address\": {\"key\": \"value\"}}),\n        )\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received oef_search success message={incoming_message} in dialogue={oef_dialogue}.\",\n        )\n        mock_logger.assert_any_call(\n            logging.INFO,\n            \"the agent, with its genus and classification, and its service are successfully registered on the SOEF.\",\n        )\n\n    def test_handle_success_v(self):\n        \"\"\"Test the _handle_success method of the oef_search handler where the oef successtargets unregister_service.\"\"\"\n        # setup\n        oef_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_dialogues,\n            messages=self.list_of_messages_register_invalid[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=oef_dialogue,\n            performative=OefSearchMessage.Performative.SUCCESS,\n            agents_info=OefSearchMessage.AgentsInfo({\"address\": {\"key\": \"value\"}}),\n        )\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received oef_search success message={incoming_message} in dialogue={oef_dialogue}.\",\n        )\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"received soef SUCCESS message as a reply to the following unexpected message: {oef_dialogue.get_message_by_id(incoming_message.target)}\",\n        )\n\n    def test_handle_error_i(self):\n        \"\"\"Test the _handle_error method of the oef_search handler where the oef error targets register_service.\"\"\"\n        # setup\n        oef_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_dialogues,\n            messages=self.list_of_messages_register_location[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=oef_dialogue,\n            performative=OefSearchMessage.Performative.OEF_ERROR,\n            oef_error_operation=OefSearchMessage.OefErrorOperation.SEARCH_SERVICES,\n        )\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        self.assert_quantity_in_outbox(0)\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received oef_search error message={incoming_message} in dialogue={oef_dialogue}.\",\n        )\n        assert (\n            self.service_registration_behaviour.failed_registration_msg\n            == oef_dialogue.get_message_by_id(incoming_message.target)\n        )\n\n    def test_handle_error_ii(self):\n        \"\"\"Test the _handle_error method of the oef_search handler where the oef error does NOT target register_service.\"\"\"\n        # setup\n        oef_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_dialogues,\n            messages=self.list_of_messages_unregister[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=oef_dialogue,\n            performative=OefSearchMessage.Performative.OEF_ERROR,\n            oef_error_operation=OefSearchMessage.OefErrorOperation.SEARCH_SERVICES,\n        )\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        self.assert_quantity_in_outbox(0)\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received oef_search error message={incoming_message} in dialogue={oef_dialogue}.\",\n        )\n\n        assert self.service_registration_behaviour.failed_registration_msg is None\n\n    def test_handle_invalid(self):\n        \"\"\"Test the _handle_invalid method of the oef_search handler.\"\"\"\n        # setup\n        invalid_performative = OefSearchMessage.Performative.UNREGISTER_SERVICE\n        incoming_message = self.build_incoming_message(\n            message_type=OefSearchMessage,\n            dialogue_reference=(\"1\", \"\"),\n            performative=invalid_performative,\n            service_description=\"some_service_description\",\n        )\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"cannot handle oef_search message of performative={invalid_performative} in dialogue={self.oef_dialogues.get_dialogue(incoming_message)}.\",\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the oef_search handler.\"\"\"\n        assert self.oef_search_handler.teardown() is None\n        self.assert_quantity_in_outbox(0)\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_ml_data_provider/test_strategy.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the strategy class of the ml_data_provider skill.\"\"\"\n\nimport json\nfrom pathlib import Path\nfrom unittest.mock import PropertyMock, patch\n\nimport numpy as np\n\nfrom aea.configurations.constants import DEFAULT_LEDGER\nfrom aea.helpers.search.models import (\n    Constraint,\n    ConstraintType,\n    Description,\n    Location,\n    Query,\n)\nfrom aea.test_tools.test_skill import BaseSkillTestCase\n\nfrom packages.fetchai.skills.ml_data_provider.strategy import (\n    AGENT_LOCATION_MODEL,\n    AGENT_PERSONALITY_MODEL,\n    AGENT_REMOVE_SERVICE_MODEL,\n    AGENT_SET_SERVICE_MODEL,\n    DEFAULT_BATCH_SIZE,\n    DEFAULT_BUYER_TX_FEE,\n    DEFAULT_CLASSIFICATION,\n    DEFAULT_LOCATION,\n    DEFAULT_PERSONALITY_DATA,\n    DEFAULT_PRICE_PER_DATA_BATCH,\n    DEFAULT_SELLER_TX_FEE,\n    DEFAULT_SERVICE_DATA,\n    DEFAULT_SERVICE_ID,\n    SIMPLE_DATA_MODEL,\n    Strategy,\n)\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass TestGenericStrategy(BaseSkillTestCase):\n    \"\"\"Test Strategy of ml_data_provider.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"ml_data_provider\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.batch_size = DEFAULT_BATCH_SIZE\n        cls.price_per_data_batch = DEFAULT_PRICE_PER_DATA_BATCH\n        cls.seller_tx_fee = DEFAULT_SELLER_TX_FEE\n        cls.buyer_tx_fee = DEFAULT_BUYER_TX_FEE\n        cls.currency_id = \"some_currency_id\"\n        cls.ledger_id = DEFAULT_LEDGER\n        cls.is_ledger_tx = True\n        cls.service_id = DEFAULT_SERVICE_ID\n        cls.location = DEFAULT_LOCATION\n        cls.personality_data = DEFAULT_PERSONALITY_DATA\n        cls.classification = DEFAULT_CLASSIFICATION\n        cls.service_data = DEFAULT_SERVICE_DATA\n        cls.strategy = Strategy(\n            batch_size=cls.batch_size,\n            price_per_data_batch=cls.price_per_data_batch,\n            seller_tx_fee=cls.seller_tx_fee,\n            buyer_tx_fee=cls.buyer_tx_fee,\n            ledger_id=cls.ledger_id,\n            is_ledger_tx=cls.is_ledger_tx,\n            currency_id=cls.currency_id,\n            service_id=cls.service_id,\n            location=cls.location,\n            personality_data=cls.personality_data,\n            classification=cls.classification,\n            service_data=cls.service_data,\n            name=\"strategy\",\n            skill_context=cls._skill.skill_context,\n        )\n\n    def test_properties(self):\n        \"\"\"Test the properties of Strategy class.\"\"\"\n        assert self.strategy.ledger_id == self.ledger_id\n        assert self.strategy.is_ledger_tx == self.is_ledger_tx\n\n    def test_get_location_description(self):\n        \"\"\"Test the get_location_description method of the Strategy class.\"\"\"\n        description = self.strategy.get_location_description()\n\n        assert type(description) == Description\n        assert description.data_model is AGENT_LOCATION_MODEL\n        assert description.values.get(\"location\", \"\") == Location(\n            latitude=self.location[\"latitude\"], longitude=self.location[\"longitude\"]\n        )\n\n    def test_get_register_personality_description(self):\n        \"\"\"Test the get_register_personality_description method of the Strategy class.\"\"\"\n        description = self.strategy.get_register_personality_description()\n\n        assert type(description) == Description\n        assert description.data_model is AGENT_PERSONALITY_MODEL\n        assert description.values.get(\"piece\", \"\") == \"genus\"\n        assert description.values.get(\"value\", \"\") == \"data\"\n\n    def test_get_register_classification_description(self):\n        \"\"\"Test the get_register_classification_description method of the Strategy class.\"\"\"\n        description = self.strategy.get_register_classification_description()\n\n        assert type(description) == Description\n        assert description.data_model is AGENT_PERSONALITY_MODEL\n        assert description.values.get(\"piece\", \"\") == \"classification\"\n        assert description.values.get(\"value\", \"\") == \"seller\"\n\n    def test_get_register_service_description(self):\n        \"\"\"Test the get_register_service_description method of the Strategy class.\"\"\"\n        description = self.strategy.get_register_service_description()\n\n        assert type(description) == Description\n        assert description.data_model is AGENT_SET_SERVICE_MODEL\n        assert description.values.get(\"key\", \"\") == \"dataset_id\"\n        assert description.values.get(\"value\", \"\") == \"fmnist\"\n\n    def test_get_service_description(self):\n        \"\"\"Test the get_service_description method of the Strategy class.\"\"\"\n        description = self.strategy.get_service_description()\n\n        assert type(description) == Description\n        assert description.data_model is SIMPLE_DATA_MODEL\n        assert description.values.get(\"dataset_id\", \"\") == \"fmnist\"\n\n    def test_get_unregister_service_description(self):\n        \"\"\"Test the get_unregister_service_description method of the GenericStrategy class.\"\"\"\n        description = self.strategy.get_unregister_service_description()\n\n        assert type(description) == Description\n        assert description.data_model is AGENT_REMOVE_SERVICE_MODEL\n        assert description.values.get(\"key\", \"\") == \"dataset_id\"\n\n    def test_sample_data(self):\n        \"\"\"Test the sample_data method of the Strategy class.\"\"\"\n        data = self.strategy.sample_data(32)\n\n        assert type(data) == tuple\n        assert len(data) == 2\n        assert type(data[0]) == np.ndarray\n        assert type(data[0]) == np.ndarray\n\n    def test_encode_sample_data(self):\n        \"\"\"Test the encode_sample_data method of the Strategy class.\"\"\"\n        # setup\n        data = self.strategy.sample_data(32)\n\n        # operation\n        encoded_data = self.strategy.encode_sample_data(data)\n\n        # after\n        assert type(encoded_data) == bytes\n\n        # decode it and check identical\n        decoded_arrays = json.loads(encoded_data)\n        numpy_data_0 = np.asarray(decoded_arrays[\"data_0\"])\n        numpy_data_1 = np.asarray(decoded_arrays[\"data_1\"])\n\n        assert (numpy_data_0 == data[0]).all()\n        assert (numpy_data_1 == data[1]).all()\n\n    def test_is_matching_supply(self):\n        \"\"\"Test the is_matching_supply method of the Strategy class.\"\"\"\n        acceptable_constraint = Constraint(\"dataset_id\", ConstraintType(\"==\", \"fmnist\"))\n        matching_query = Query([acceptable_constraint])\n        is_matching_supply = self.strategy.is_matching_supply(matching_query)\n        assert is_matching_supply\n\n        unacceptable_constraint = Constraint(\n            \"dataset_id\", ConstraintType(\"==\", \"some_other_service\")\n        )\n        unmatching_query = Query([unacceptable_constraint])\n        is_matching_supply = self.strategy.is_matching_supply(unmatching_query)\n        assert not is_matching_supply\n\n    def test_generate_terms(self):\n        \"\"\"Test the generate_terms method of the Strategy class.\"\"\"\n        # setup\n        mocked_nonce = \"some_nonce\"\n        expected_proposal = Description(\n            {\n                \"batch_size\": self.batch_size,\n                \"price\": self.price_per_data_batch,\n                \"seller_tx_fee\": self.seller_tx_fee,\n                \"buyer_tx_fee\": self.buyer_tx_fee,\n                \"currency_id\": self.currency_id,\n                \"ledger_id\": self.ledger_id,\n                \"address\": self.skill.skill_context.agent_address,\n                \"service_id\": self.service_id,\n                \"nonce\": mocked_nonce,\n            }\n        )\n\n        # operation\n        with patch(\n            \"uuid.UUID.hex\", new_callable=PropertyMock, return_value=mocked_nonce\n        ) as mocked_uuid:\n            proposal = self.strategy.generate_terms()\n\n        # after\n        mocked_uuid.assert_called_once()\n        assert proposal == expected_proposal\n\n    def test_is_valid_terms_i(self):\n        \"\"\"Test the is_valid_terms method of the Strategy class where terms is VALID.\"\"\"\n        # setup\n        valid_proposal = Description(\n            {\n                \"batch_size\": self.batch_size,\n                \"price\": self.price_per_data_batch,\n                \"seller_tx_fee\": self.seller_tx_fee,\n                \"buyer_tx_fee\": self.buyer_tx_fee,\n                \"currency_id\": self.currency_id,\n                \"ledger_id\": self.ledger_id,\n                \"address\": self.skill.skill_context.agent_address,\n                \"service_id\": self.service_id,\n                \"nonce\": \"some_nonce\",\n            }\n        )\n\n        # operation\n        is_valid = self.strategy.is_valid_terms(valid_proposal)\n\n        # after\n        assert is_valid is True\n\n    def test_is_valid_terms_ii(self):\n        \"\"\"Test the is_valid_terms method of the Strategy class where terms is INVALID.\"\"\"\n        # setup\n        invalid_batch_size = 0\n        valid_proposal = Description(\n            {\n                \"batch_size\": invalid_batch_size,\n                \"price\": self.price_per_data_batch,\n                \"seller_tx_fee\": self.seller_tx_fee,\n                \"buyer_tx_fee\": self.buyer_tx_fee,\n                \"currency_id\": self.currency_id,\n                \"ledger_id\": self.ledger_id,\n                \"address\": self.skill.skill_context.agent_address,\n                \"service_id\": self.service_id,\n                \"nonce\": \"some_nonce\",\n            }\n        )\n\n        # operation\n        is_valid = self.strategy.is_valid_terms(valid_proposal)\n\n        # after\n        assert is_valid is False\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_ml_train/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"The tests module contains the tests of the packages/skills/ml_train dir.\"\"\"\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_ml_train/helpers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the handler classes of the ml_train skill.\"\"\"\nfrom typing import Tuple\n\nimport numpy as np\n\n\ndef produce_data(batch_size) -> Tuple:\n    \"\"\"Produce the data.\"\"\"\n    from tensorflow import keras  # pylint: disable=import-outside-toplevel\n\n    ((train_x, train_y), _) = keras.datasets.fashion_mnist.load_data()\n\n    idx = np.arange(train_x.shape[0])\n    mask = np.zeros_like(idx, dtype=bool)\n\n    selected = np.random.choice(idx, batch_size, replace=False)\n    mask[selected] = True\n\n    x_sample = train_x[mask]\n    y_sample = train_y[mask]\n    return x_sample, y_sample\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_ml_train/test_behaviours.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the behaviour classes of the ml_train skill.\"\"\"\n\nimport logging\nimport uuid\nfrom multiprocessing.pool import ApplyResult\nfrom pathlib import Path\nfrom typing import Tuple, cast\nfrom unittest.mock import Mock, patch\n\nimport pytest\n\nfrom aea.helpers.search.models import Description\nfrom aea.protocols.dialogue.base import DialogueMessage\nfrom aea.skills.tasks import TaskManager\nfrom aea.test_tools.test_skill import BaseSkillTestCase\n\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\nfrom packages.fetchai.protocols.ml_trade.message import MlTradeMessage\nfrom packages.fetchai.skills.ml_train.behaviours import (\n    GenericSearchBehaviour,\n    LEDGER_API_ADDRESS,\n    SearchBehaviour,\n    TransactionBehaviour,\n)\nfrom packages.fetchai.skills.ml_train.dialogues import (\n    LedgerApiDialogue,\n    LedgerApiDialogues,\n    MlTradeDialogue,\n    MlTradeDialogues,\n)\nfrom packages.fetchai.skills.ml_train.strategy import Strategy\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass TestSearchBehaviour(BaseSkillTestCase):\n    \"\"\"Test Search behaviour of ml_train.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"ml_train\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.search_behaviour = cast(\n            SearchBehaviour, cls._skill.skill_context.behaviours.search\n        )\n        cls.tx_behaviour = cast(\n            TransactionBehaviour, cls._skill.skill_context.behaviours.transaction\n        )\n        cls.strategy = cast(Strategy, cls._skill.skill_context.strategy)\n        cls.task_manager = cast(TaskManager, cls._skill.skill_context.task_manager)\n\n        cls.logger = cls._skill.skill_context.logger\n\n        cls._skill.skill_context.task_manager.start()\n\n    def test_act_no_task(self):\n        \"\"\"Test the act method of the search behaviour where current_task_id is None.\"\"\"\n        # setup\n        self.strategy._current_task_id = None\n\n        # operation\n        with patch.object(GenericSearchBehaviour, \"act\") as mock_generic_act:\n            self.search_behaviour.act()\n\n        # after\n        mock_generic_act.assert_called_once()\n\n    def test_act_task_not_ready(self):\n        \"\"\"Test the act method of the search behaviour where task isn't ready.\"\"\"\n        # setup\n        self.strategy._current_task_id = 1\n\n        mock_task_result = Mock(wraps=ApplyResult)\n        mock_task_result.ready.return_value = False\n\n        # operation\n        with patch.object(\n            self.task_manager, \"get_task_result\", return_value=mock_task_result\n        ):\n            self.search_behaviour.act()\n\n        # after\n        self.assert_quantity_in_outbox(0)\n        assert self.strategy._current_task_id == 1\n\n    def test_act_task_not_successful(self):\n        \"\"\"Test the act method of the search behaviour where task isn't successful.\"\"\"\n        # setup\n        self.strategy._current_task_id = 1\n\n        mock_task_result = Mock(wraps=ApplyResult)\n        mock_task_result.ready.return_value = True\n        mock_task_result.successful.return_value = False\n\n        # operation\n        with patch.object(\n            self.task_manager, \"get_task_result\", return_value=mock_task_result\n        ):\n            self.search_behaviour.act()\n\n        # after\n        self.assert_quantity_in_outbox(0)\n        assert self.strategy._current_task_id == 1\n\n    def test_act_task_ready_and_successful(self):\n        \"\"\"Test the act method of the search behaviour where task is ready and successful.\"\"\"\n        # setup\n        self.strategy._current_task_id = 1\n        mocked_weights = \"some_weights\"\n\n        mock_task_result = Mock(wraps=ApplyResult)\n        mock_task_result.ready.return_value = True\n        mock_task_result.successful.return_value = True\n        mock_task_result.get.return_value = mocked_weights\n\n        # operation\n        with patch.object(\n            self.task_manager, \"get_task_result\", return_value=mock_task_result\n        ):\n            with patch.object(GenericSearchBehaviour, \"act\") as mock_generic_act:\n                self.search_behaviour.act()\n\n        # after\n        assert self.strategy._current_task_id is None\n        assert self.strategy._weights == mocked_weights\n        mock_generic_act.assert_called_once()\n\n    def test_act_data_exists(self):\n        \"\"\"Test the act method of the search behaviour where no task is running and there is strategy.data is not empty.\"\"\"\n        # setup\n        self.strategy._current_task_id = None\n\n        mocked_data = ([], [])\n        self.strategy.data = [mocked_data]\n\n        mocked_task_id = 1\n\n        # operation\n        with patch.object(\n            self.task_manager, \"enqueue_task\", return_value=mocked_task_id\n        ) as mocked_enqueue_task:\n            self.search_behaviour.act()\n\n        # after\n        assert self.strategy.data == []\n        mocked_enqueue_task.assert_called_once()\n        assert self.strategy._current_task_id == mocked_task_id\n\n    @classmethod\n    def teardown(cls):\n        \"\"\"Tears down the test class.\"\"\"\n        cls._skill.skill_context.task_manager.stop()\n\n\nclass TestTransactionBehaviour(BaseSkillTestCase):\n    \"\"\"Test transaction behaviour of ml_train buyer.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"ml_train\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.transaction_behaviour = cast(\n            TransactionBehaviour, cls._skill.skill_context.behaviours.transaction\n        )\n        cls.strategy = cast(Strategy, cls._skill.skill_context.strategy)\n        cls.logger = cls._skill.skill_context.logger\n\n        cls.ml_dialogues = cast(\n            MlTradeDialogues, cls._skill.skill_context.ml_trade_dialogues\n        )\n        cls.ledger_api_dialogues = cast(\n            LedgerApiDialogues, cls._skill.skill_context.ledger_api_dialogues\n        )\n\n        cls.batch_size = 32\n        cls.price_per_data_batch = 10\n        cls.seller_tx_fee = 0\n        cls.buyer_tx_fee = 0\n        cls.currency_id = \"FET\"\n        cls.ledger_id = \"FET\"\n        cls.service_id = \"data_service\"\n\n        cls.terms = Description(\n            {\n                \"batch_size\": cls.batch_size,\n                \"price\": cls.price_per_data_batch,\n                \"seller_tx_fee\": cls.seller_tx_fee,\n                \"buyer_tx_fee\": cls.buyer_tx_fee,\n                \"currency_id\": cls.currency_id,\n                \"ledger_id\": cls.ledger_id,\n                \"address\": cls._skill.skill_context.agent_address,\n                \"service_id\": cls.service_id,\n                \"nonce\": uuid.uuid4().hex,\n            }\n        )\n\n        cls.list_of_messages = (\n            DialogueMessage(MlTradeMessage.Performative.CFP, {\"query\": \"some_query\"}),\n            DialogueMessage(MlTradeMessage.Performative.TERMS, {\"terms\": cls.terms}),\n            DialogueMessage(\n                MlTradeMessage.Performative.ACCEPT,\n                {\"terms\": cls.terms, \"tx_digest\": \"some_tx_digest\"},\n            ),\n        )\n\n    @staticmethod\n    def _check_start_processing_effects(self_, ml_dialogue, mock_logger) -> None:\n        \"\"\"Perform checks related to running _start_processing.\"\"\"\n        # _start_processing\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"Processing transaction, {len(self_.transaction_behaviour.waiting)} transactions remaining\",\n        )\n\n        message = self_.get_message_from_outbox()\n        has_attributes, error_str = self_.message_has_attributes(\n            actual_message=message,\n            message_type=LedgerApiMessage,\n            performative=LedgerApiMessage.Performative.GET_RAW_TRANSACTION,\n            to=LEDGER_API_ADDRESS,\n            sender=str(self_.skill.public_id),\n            terms=ml_dialogue.terms,\n        )\n        assert has_attributes, error_str\n\n        ledger_api_dialogue = cast(\n            LedgerApiDialogue, self_.ledger_api_dialogues.get_dialogue(message)\n        )\n        assert ledger_api_dialogue.associated_ml_trade_dialogue == ml_dialogue\n\n        assert self_.transaction_behaviour.processing_time == 0.0\n\n        assert self_.transaction_behaviour.processing == ledger_api_dialogue\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"requesting transfer transaction from ledger api for message={message}...\",\n        )\n\n    @staticmethod\n    def _setup_ml_ledger_api_dialogues(\n        self_,\n    ) -> Tuple[LedgerApiDialogue, MlTradeDialogue]:\n        \"\"\"Setup ml_trade and ledger_api dialogues for some of the following tests.\"\"\"\n        ml_dialogue = cast(\n            MlTradeDialogue,\n            self_.prepare_skill_dialogue(\n                dialogues=self_.ml_dialogues,\n                messages=self_.list_of_messages,\n            ),\n        )\n        ml_dialogue.terms = self_.terms\n\n        ledger_api_dialogue = cast(\n            LedgerApiDialogue,\n            self_.prepare_skill_dialogue(\n                dialogues=self_.ledger_api_dialogues,\n                messages=(\n                    DialogueMessage(\n                        LedgerApiMessage.Performative.GET_BALANCE,\n                        {\"ledger_id\": \"some_ledger_id\", \"address\": \"some_address\"},\n                    ),\n                ),\n            ),\n        )\n        ledger_api_dialogue.associated_ml_trade_dialogue = ml_dialogue\n\n        return ledger_api_dialogue, ml_dialogue\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the transaction behaviour.\"\"\"\n        assert self.transaction_behaviour.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_act_i(self):\n        \"\"\"Test the act method of the transaction behaviour where processing IS None and len(self.waiting) is NOT 0.\"\"\"\n        # setup\n        _, ml_dialogue = self._setup_ml_ledger_api_dialogues(self)\n\n        processing_time = 5.0\n        max_processing = 120\n        self.transaction_behaviour.processing = None\n        self.transaction_behaviour.max_processing = max_processing\n        self.transaction_behaviour.processing_time = processing_time\n        self.transaction_behaviour.waiting = [ml_dialogue]\n\n        # before\n        assert self.transaction_behaviour.processing_time == processing_time\n        assert self.transaction_behaviour.processing is None\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.transaction_behaviour.act()\n\n        # after\n        self.assert_quantity_in_outbox(1)\n\n        # _start_processing\n        self._check_start_processing_effects(self, ml_dialogue, mock_logger)\n\n    def test_act_ii(self):\n        \"\"\"Test the act method of the transaction behaviour where processing is NOT None and processing_time < max_processing.\"\"\"\n        # setup\n        processing_time = 5.0\n        self.transaction_behaviour.processing = \"some_dialogue\"\n        self.transaction_behaviour.max_processing = 120\n        self.transaction_behaviour.processing_time = processing_time\n\n        # operation\n        self.transaction_behaviour.act()\n\n        # after\n        self.assert_quantity_in_outbox(0)\n        assert (\n            self.transaction_behaviour.processing_time\n            == processing_time + self.transaction_behaviour.tick_interval\n        )\n\n    def test_act_iii(self):\n        \"\"\"Test the act method of the transaction behaviour where processing is NOT None and processing_time > max_processing.\"\"\"\n        # setup\n        ledger_api_dialogue, ml_dialogue = self._setup_ml_ledger_api_dialogues(self)\n\n        processing_time = 121.0\n        self.transaction_behaviour.processing = ledger_api_dialogue\n        self.transaction_behaviour.max_processing = 120\n        self.transaction_behaviour.processing_time = processing_time\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.transaction_behaviour.act()\n\n        # after\n        self.assert_quantity_in_outbox(1)\n\n        # _timeout_processing\n        assert ledger_api_dialogue.dialogue_label in self.transaction_behaviour.timedout\n        # below is overridden in _start_processing\n        # assert ml_dialogue in self.transaction_behaviour.waiting\n        assert self.transaction_behaviour.processing_time == 0.0\n        # below is overridden in _start_processing\n        # assert self.transaction_behaviour.processing is None\n\n        # _start_processing\n        self._check_start_processing_effects(self, ml_dialogue, mock_logger)\n\n    def test_timeout_processing(self):\n        \"\"\"Test the _timeout_processing method of the transaction behaviour where self.processing IS None.\"\"\"\n        # setup\n        self.transaction_behaviour.processing_time = None\n\n        # operation\n        self.transaction_behaviour._timeout_processing()\n\n        # after\n        self.assert_quantity_in_outbox(0)\n\n    def test_act_iv(self):\n        \"\"\"Test the act method of the transaction behaviour where len(waiting) == 0.\"\"\"\n        # setup\n        self.transaction_behaviour.processing = None\n        self.transaction_behaviour.waiting = []\n\n        # operation\n        self.transaction_behaviour.act()\n\n        # after\n        self.assert_quantity_in_outbox(0)\n\n    def test_failed_processing(self):\n        \"\"\"Test the failed_processing method of the transaction behaviour.\"\"\"\n        # setup\n        ledger_api_dialogue, ml_dialogue = self._setup_ml_ledger_api_dialogues(self)\n\n        self.transaction_behaviour.timedout.add(ledger_api_dialogue.dialogue_label)\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.transaction_behaviour.failed_processing(ledger_api_dialogue)\n\n        # after\n        self.assert_quantity_in_outbox(0)\n\n        # finish_processing\n        assert self.transaction_behaviour.timedout == set()\n\n        mock_logger.assert_any_call(\n            logging.DEBUG,\n            f\"Timeout dialogue in transaction processing: {ledger_api_dialogue}\",\n        )\n\n        # failed_processing\n        assert ml_dialogue in self.transaction_behaviour.waiting\n\n    def test_finish_processing_i(self):\n        \"\"\"Test the finish_processing method of the transaction behaviour where self.processing == ledger_api_dialogue.\"\"\"\n        # setup\n        ledger_api_dialogue, ml_dialogue = self._setup_ml_ledger_api_dialogues(self)\n        self.transaction_behaviour.processing = ledger_api_dialogue\n\n        # operation\n        self.transaction_behaviour.failed_processing(ledger_api_dialogue)\n\n        # after\n        assert self.transaction_behaviour.processing_time == 0.0\n        assert self.transaction_behaviour.processing is None\n\n    def test_finish_processing_ii(self):\n        \"\"\"Test the finish_processing method of the transaction behaviour where ledger_api_dialogue's dialogue_label is NOT in self.timedout.\"\"\"\n        # setup\n        ledger_api_dialogue, ml_dialogue = self._setup_ml_ledger_api_dialogues(self)\n\n        # operation\n        with pytest.raises(ValueError) as err:\n            self.transaction_behaviour.finish_processing(ledger_api_dialogue)\n\n        # after\n        assert (\n            err.value.args[0]\n            == f\"Non-matching dialogues in transaction behaviour: {self.transaction_behaviour.processing} and {ledger_api_dialogue}\"\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the transaction behaviour.\"\"\"\n        assert self.transaction_behaviour.teardown() is None\n        self.assert_quantity_in_outbox(0)\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_ml_train/test_dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the dialogue classes of the ml_train skill.\"\"\"\n\nfrom pathlib import Path\nfrom typing import cast\n\nimport pytest\n\nfrom aea.exceptions import AEAEnforceError\nfrom aea.helpers.transaction.base import Terms\nfrom aea.protocols.dialogue.base import DialogueLabel\nfrom aea.test_tools.test_skill import BaseSkillTestCase, COUNTERPARTY_AGENT_ADDRESS\n\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\nfrom packages.fetchai.protocols.ml_trade.message import MlTradeMessage\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.protocols.signing.message import SigningMessage\nfrom packages.fetchai.skills.ml_train.dialogues import (\n    DefaultDialogue,\n    DefaultDialogues,\n    LedgerApiDialogue,\n    LedgerApiDialogues,\n    MlTradeDialogue,\n    MlTradeDialogues,\n    OefSearchDialogue,\n    OefSearchDialogues,\n    SigningDialogue,\n    SigningDialogues,\n)\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass TestDialogues(BaseSkillTestCase):\n    \"\"\"Test dialogue classes of ml_train.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"ml_train\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.default_dialogues = cast(\n            DefaultDialogues, cls._skill.skill_context.default_dialogues\n        )\n        cls.ml_dialogues = cast(\n            MlTradeDialogues, cls._skill.skill_context.ml_trade_dialogues\n        )\n        cls.ledger_api_dialogues = cast(\n            LedgerApiDialogues, cls._skill.skill_context.ledger_api_dialogues\n        )\n        cls.oef_search_dialogues = cast(\n            OefSearchDialogues, cls._skill.skill_context.oef_search_dialogues\n        )\n        cls.signing_dialogues = cast(\n            SigningDialogues, cls._skill.skill_context.signing_dialogues\n        )\n\n    def test_default_dialogues(self):\n        \"\"\"Test the DefaultDialogues class.\"\"\"\n        _, dialogue = self.default_dialogues.create(\n            counterparty=COUNTERPARTY_AGENT_ADDRESS,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"some_content\",\n        )\n        assert dialogue.role == DefaultDialogue.Role.AGENT\n        assert dialogue.self_address == self.skill.skill_context.agent_address\n\n    def test_ml_dialogue(self):\n        \"\"\"Test the MlTradeDialogue class.\"\"\"\n        ml_dialogue = MlTradeDialogue(\n            DialogueLabel(\n                (\"\", \"\"),\n                COUNTERPARTY_AGENT_ADDRESS,\n                self.skill.skill_context.agent_address,\n            ),\n            self.skill.skill_context.agent_address,\n            role=MlTradeDialogue.Role.BUYER,\n        )\n\n        # terms\n        with pytest.raises(AEAEnforceError, match=\"Terms not set!\"):\n            assert ml_dialogue.terms\n        terms = Terms(\n            \"some_ledger_id\",\n            self.skill.skill_context.agent_address,\n            \"counterprty\",\n            {\"currency_id\": 50},\n            {\"good_id\": -10},\n            \"some_nonce\",\n        )\n        ml_dialogue.terms = terms\n        with pytest.raises(AEAEnforceError, match=\"Terms already set!\"):\n            ml_dialogue.terms = terms\n        assert ml_dialogue.terms == terms\n\n    def test_ml_dialogues(self):\n        \"\"\"Test the MlTradeDialogues class.\"\"\"\n        _, dialogue = self.ml_dialogues.create(\n            counterparty=COUNTERPARTY_AGENT_ADDRESS,\n            performative=MlTradeMessage.Performative.CFP,\n            query=\"some_query\",\n        )\n        assert dialogue.role == MlTradeDialogue.Role.BUYER\n        assert dialogue.self_address == self.skill.skill_context.agent_address\n\n    def test_ledger_api_dialogue(self):\n        \"\"\"Test the LedgerApiDialogue class.\"\"\"\n        ledger_api_dialogue = LedgerApiDialogue(\n            DialogueLabel(\n                (\"\", \"\"),\n                COUNTERPARTY_AGENT_ADDRESS,\n                self.skill.skill_context.agent_address,\n            ),\n            self.skill.skill_context.agent_address,\n            role=LedgerApiDialogue.Role.AGENT,\n        )\n\n        # associated_ml_trade_dialogue\n        with pytest.raises(AEAEnforceError, match=\"MlTradeDialogue not set!\"):\n            assert ledger_api_dialogue.associated_ml_trade_dialogue\n        ml_dialogue = MlTradeDialogue(\n            DialogueLabel(\n                (\"\", \"\"),\n                COUNTERPARTY_AGENT_ADDRESS,\n                self.skill.skill_context.agent_address,\n            ),\n            self.skill.skill_context.agent_address,\n            role=MlTradeDialogue.Role.BUYER,\n        )\n        ledger_api_dialogue.associated_ml_trade_dialogue = ml_dialogue\n        with pytest.raises(AEAEnforceError, match=\"MlTradeDialogue already set!\"):\n            ledger_api_dialogue.associated_ml_trade_dialogue = ml_dialogue\n        assert ledger_api_dialogue.associated_ml_trade_dialogue == ml_dialogue\n\n    def test_ledger_api_dialogues(self):\n        \"\"\"Test the LedgerApiDialogues class.\"\"\"\n        _, dialogue = self.ledger_api_dialogues.create(\n            counterparty=COUNTERPARTY_AGENT_ADDRESS,\n            performative=LedgerApiMessage.Performative.GET_BALANCE,\n            ledger_id=\"some_ledger_id\",\n            address=\"some_address\",\n        )\n        assert dialogue.role == LedgerApiDialogue.Role.AGENT\n        assert dialogue.self_address == str(self.skill.public_id)\n\n    def test_oef_search_dialogues(self):\n        \"\"\"Test the OefSearchDialogues class.\"\"\"\n        _, dialogue = self.oef_search_dialogues.create(\n            counterparty=COUNTERPARTY_AGENT_ADDRESS,\n            performative=OefSearchMessage.Performative.SEARCH_SERVICES,\n            query=\"some_query\",\n        )\n        assert dialogue.role == OefSearchDialogue.Role.AGENT\n        assert dialogue.self_address == str(self.skill.public_id)\n\n    def test_signing_dialogue(self):\n        \"\"\"Test the SigningDialogue class.\"\"\"\n        signing_dialogue = SigningDialogue(\n            DialogueLabel(\n                (\"\", \"\"),\n                COUNTERPARTY_AGENT_ADDRESS,\n                self.skill.skill_context.agent_address,\n            ),\n            self.skill.skill_context.agent_address,\n            role=SigningDialogue.Role.SKILL,\n        )\n\n        # associated_ledger_api_dialogue\n        with pytest.raises(AEAEnforceError, match=\"LedgerApiDialogue not set!\"):\n            assert signing_dialogue.associated_ledger_api_dialogue\n        ledger_api_dialogue = LedgerApiDialogue(\n            DialogueLabel(\n                (\"\", \"\"),\n                COUNTERPARTY_AGENT_ADDRESS,\n                self.skill.skill_context.agent_address,\n            ),\n            self.skill.skill_context.agent_address,\n            role=LedgerApiDialogue.Role.AGENT,\n        )\n        signing_dialogue.associated_ledger_api_dialogue = ledger_api_dialogue\n        with pytest.raises(AEAEnforceError, match=\"LedgerApiDialogue already set!\"):\n            signing_dialogue.associated_ledger_api_dialogue = ledger_api_dialogue\n        assert signing_dialogue.associated_ledger_api_dialogue == ledger_api_dialogue\n\n    def test_signing_dialogues(self):\n        \"\"\"Test the SigningDialogues class.\"\"\"\n        _, dialogue = self.signing_dialogues.create(\n            counterparty=COUNTERPARTY_AGENT_ADDRESS,\n            performative=SigningMessage.Performative.SIGN_TRANSACTION,\n            terms=\"some_terms\",\n            raw_transaction=\"some_raw_transaction\",\n        )\n        assert dialogue.role == SigningDialogue.Role.SKILL\n        assert dialogue.self_address == str(self.skill.public_id)\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_ml_train/test_handlers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the handler classes of the ml_train skill.\"\"\"\nimport json\nimport logging\nimport uuid\nfrom pathlib import Path\nfrom typing import cast\nfrom unittest.mock import patch\n\nimport numpy as np\nimport pytest\n\nfrom aea.crypto.ledger_apis import LedgerApis\nfrom aea.helpers.search.models import Description\nfrom aea.helpers.transaction.base import (\n    RawTransaction,\n    SignedTransaction,\n    Terms,\n    TransactionDigest,\n    TransactionReceipt,\n)\nfrom aea.protocols.dialogue.base import DialogueMessage\nfrom aea.skills.tasks import TaskManager\nfrom aea.test_tools.test_skill import BaseSkillTestCase, COUNTERPARTY_AGENT_ADDRESS\n\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\nfrom packages.fetchai.protocols.ml_trade.message import MlTradeMessage\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.protocols.signing.message import SigningMessage\nfrom packages.fetchai.skills.ml_data_provider.strategy import (\n    Strategy as DataProviderStrategy,\n)\nfrom packages.fetchai.skills.ml_train.behaviours import TransactionBehaviour\nfrom packages.fetchai.skills.ml_train.dialogues import (\n    LedgerApiDialogue,\n    LedgerApiDialogues,\n    MlTradeDialogue,\n    MlTradeDialogues,\n    OefSearchDialogues,\n    SigningDialogue,\n    SigningDialogues,\n)\nfrom packages.fetchai.skills.ml_train.handlers import (\n    DUMMY_DIGEST,\n    LEDGER_API_ADDRESS,\n    LedgerApiHandler,\n    MlTradeHandler,\n    OEFSearchHandler,\n    SigningHandler,\n)\nfrom packages.fetchai.skills.ml_train.strategy import Strategy\n\nfrom tests.conftest import ROOT_DIR\nfrom tests.test_packages.test_skills.test_ml_train.helpers import produce_data\n\n\nclass TestMlTradeHandler(BaseSkillTestCase):\n    \"\"\"Test ml_trade handler of ml_train.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"ml_train\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.ml_handler = cast(\n            MlTradeHandler, cls._skill.skill_context.handlers.ml_trade\n        )\n        cls.strategy = cast(Strategy, cls._skill.skill_context.strategy)\n        cls.ml_dialogues = cast(\n            MlTradeDialogues, cls._skill.skill_context.ml_trade_dialogues\n        )\n        cls.tx_behaviour = cast(\n            TransactionBehaviour, cls._skill.skill_context.behaviours.transaction\n        )\n        cls.ledger_api_dialogues = cast(\n            MlTradeDialogues, cls._skill.skill_context.ledger_api_dialogues\n        )\n        cls.task_manager = cast(TaskManager, cls._skill.skill_context.task_manager)\n\n        cls.logger = cls._skill.skill_context.logger\n\n        cls.batch_size = 32\n        cls.price_per_data_batch = 10\n        cls.seller_tx_fee = 0\n        cls.buyer_tx_fee = 0\n        cls.currency_id = \"FET\"\n        cls.ledger_id = \"FET\"\n        cls.service_id = \"data_service\"\n\n        cls.terms = Description(\n            {\n                \"batch_size\": cls.batch_size,\n                \"price\": cls.price_per_data_batch,\n                \"seller_tx_fee\": cls.seller_tx_fee,\n                \"buyer_tx_fee\": cls.buyer_tx_fee,\n                \"currency_id\": cls.currency_id,\n                \"ledger_id\": cls.ledger_id,\n                \"address\": cls._skill.skill_context.agent_address,\n                \"service_id\": cls.service_id,\n                \"nonce\": uuid.uuid4().hex,\n            }\n        )\n\n        cls.list_of_messages = (\n            DialogueMessage(MlTradeMessage.Performative.CFP, {\"query\": \"some_query\"}),\n            DialogueMessage(MlTradeMessage.Performative.TERMS, {\"terms\": cls.terms}),\n            DialogueMessage(\n                MlTradeMessage.Performative.ACCEPT,\n                {\"terms\": cls.terms, \"tx_digest\": \"some_tx_digest\"},\n            ),\n        )\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the ml_trade handler.\"\"\"\n        assert self.ml_handler.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle_unidentified_dialogue(self):\n        \"\"\"Test the _handle_unidentified_dialogue method of the ml_trade handler.\"\"\"\n        # setup\n        incorrect_dialogue_reference = (\"\", \"\")\n        incoming_message = self.build_incoming_message(\n            message_type=MlTradeMessage,\n            dialogue_reference=incorrect_dialogue_reference,\n            performative=MlTradeMessage.Performative.ACCEPT,\n            terms=self.terms,\n            tx_digest=\"some_tx_digest\",\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.ml_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received invalid ml_trade message={incoming_message}, unidentified dialogue.\",\n        )\n\n        self.assert_quantity_in_outbox(1)\n\n        message = self.get_message_from_outbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=DefaultMessage,\n            performative=DefaultMessage.Performative.ERROR,\n            to=incoming_message.sender,\n            sender=self.skill.skill_context.agent_address,\n            error_code=DefaultMessage.ErrorCode.INVALID_DIALOGUE,\n            error_msg=\"Invalid dialogue.\",\n            error_data={\"ml_trade_message\": incoming_message.encode()},\n        )\n        assert has_attributes, error_str\n\n    def test_handle_terms_not_affordable_nor_acceptable(self):\n        \"\"\"Test the _handle_propose method of the ml_trade handler where terms is not affordable nor acceptable.\"\"\"\n        # setup\n        ml_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.ml_dialogues,\n            messages=self.list_of_messages[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=ml_dialogue,\n            performative=MlTradeMessage.Performative.TERMS,\n            terms=self.terms,\n        )\n\n        # operation\n        with patch.object(\n            self.strategy,\n            \"is_acceptable_terms\",\n            return_value=False,\n        ) as mocked_acceptable:\n            with patch.object(\n                self.strategy,\n                \"is_affordable_terms\",\n                return_value=False,\n            ) as mocked_affordable:\n                with patch.object(self.logger, \"log\") as mock_logger:\n                    self.ml_handler.handle(incoming_message)\n\n        # after\n        incoming_message = cast(MlTradeMessage, incoming_message)\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received terms message from {incoming_message.sender[-5:]}: terms={incoming_message.terms.values}\",\n        )\n\n        mocked_acceptable.assert_called_once()\n        mocked_affordable.assert_called_once()\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            \"rejecting, terms are not acceptable and/or affordable\",\n        )\n\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle_terms_is_affordable_and_acceptable_not_ledger(self):\n        \"\"\"Test the _handle_terms method of the ml_train handler where terms is affordable and acceptable and is NOT ledger_tx.\"\"\"\n        # setup\n        self.strategy._is_ledger_tx = False\n        ml_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.ml_dialogues,\n            messages=self.list_of_messages[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=ml_dialogue,\n            performative=MlTradeMessage.Performative.TERMS,\n            terms=self.terms,\n        )\n\n        # operation\n        with patch.object(\n            self.strategy,\n            \"is_acceptable_terms\",\n            return_value=True,\n        ) as mocked_acceptable:\n            with patch.object(\n                self.strategy,\n                \"is_affordable_terms\",\n                return_value=True,\n            ) as mocked_affordable:\n                with patch.object(self.logger, \"log\") as mock_logger:\n                    self.ml_handler.handle(incoming_message)\n\n        # after\n        incoming_message = cast(MlTradeMessage, incoming_message)\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received terms message from {incoming_message.sender[-5:]}: terms={incoming_message.terms.values}\",\n        )\n\n        mocked_acceptable.assert_called_once()\n        mocked_affordable.assert_called_once()\n\n        self.assert_quantity_in_outbox(1)\n        message = self.get_message_from_outbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=MlTradeMessage,\n            performative=MlTradeMessage.Performative.ACCEPT,\n            to=incoming_message.sender,\n            sender=self.skill.skill_context.agent_address,\n            target=incoming_message.message_id,\n            tx_digest=DUMMY_DIGEST,\n            terms=self.terms,\n        )\n        assert has_attributes, error_str\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            \"sending dummy transaction digest ...\",\n        )\n\n    def test_handle_terms_is_affordable_and_acceptable_is_ledger(self):\n        \"\"\"Test the _handle_terms method of the ml_train handler where terms is affordable and acceptable and IS ledger_tx.\"\"\"\n        # setup\n        self.strategy._is_ledger_tx = True\n        ml_dialogue = cast(\n            MlTradeDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.ml_dialogues,\n                messages=self.list_of_messages[:1],\n            ),\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=ml_dialogue,\n            performative=MlTradeMessage.Performative.TERMS,\n            terms=self.terms,\n        )\n        mocked_terms_from_proposal = \"some_terms\"\n\n        # operation\n        with patch.object(\n            self.strategy,\n            \"is_acceptable_terms\",\n            return_value=True,\n        ) as mocked_acceptable:\n            with patch.object(\n                self.strategy,\n                \"is_affordable_terms\",\n                return_value=True,\n            ) as mocked_affordable:\n                with patch.object(\n                    self.strategy,\n                    \"terms_from_proposal\",\n                    return_value=mocked_terms_from_proposal,\n                ) as mocked_terms_from:\n                    with patch.object(self.logger, \"log\") as mock_logger:\n                        self.ml_handler.handle(incoming_message)\n\n        # after\n        incoming_message = cast(MlTradeMessage, incoming_message)\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received terms message from {incoming_message.sender[-5:]}: terms={incoming_message.terms.values}\",\n        )\n\n        mocked_acceptable.assert_called_once()\n        mocked_affordable.assert_called_once()\n        mocked_terms_from.assert_called_with(self.terms)\n\n        assert ml_dialogue.terms == mocked_terms_from_proposal\n        assert ml_dialogue in self.tx_behaviour.waiting\n\n    def test_handle_data_with_data(self):\n        \"\"\"Test the _handle_data method of the ml_trade handler where data is NOT None.\"\"\"\n        # setup\n        data = produce_data(self.batch_size)\n        payload = DataProviderStrategy.encode_sample_data(data)\n\n        ml_dialogue = cast(\n            MlTradeDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.ml_dialogues,\n                messages=self.list_of_messages[:3],\n            ),\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=ml_dialogue,\n            performative=MlTradeMessage.Performative.DATA,\n            terms=self.terms,\n            payload=payload,\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.ml_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received data message from {COUNTERPARTY_AGENT_ADDRESS[-5:]}: data shape={data[0].shape}, terms={self.terms.values}\",\n        )\n        assert len(self.strategy.data[0]) == len(data)\n        assert np.array_equal(self.strategy.data[0][0], data[0]) is True\n        assert np.array_equal(self.strategy.data[0][1], data[1]) is True\n        assert self.strategy.is_searching is True\n\n    def test_handle_data_without_data(self):\n        \"\"\"Test the _handle_data method of the ml_trade handler where data IS None.\"\"\"\n        # setup\n        data = None\n        payload = json.dumps(data).encode(\"utf-8\")\n\n        ml_dialogue = cast(\n            MlTradeDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.ml_dialogues,\n                messages=self.list_of_messages[:3],\n            ),\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=ml_dialogue,\n            performative=MlTradeMessage.Performative.DATA,\n            terms=self.terms,\n            payload=payload,\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.ml_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received data message with no data from {COUNTERPARTY_AGENT_ADDRESS[-5:]}\",\n        )\n\n    def test_handle_invalid(self):\n        \"\"\"Test the _handle_invalid method of the ml_trade handler.\"\"\"\n        # setup\n        ml_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.ml_dialogues,\n            messages=self.list_of_messages[:2],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=ml_dialogue,\n            performative=MlTradeMessage.Performative.ACCEPT,\n            terms=self.terms,\n            tx_digest=\"some_tx_digest\",\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.ml_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"cannot handle ml_trade message of performative={incoming_message.performative} in dialogue={ml_dialogue}.\",\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the ml handler.\"\"\"\n        assert self.ml_handler.teardown() is None\n        self.assert_quantity_in_outbox(0)\n\n\nclass TestOefSearchHandler(BaseSkillTestCase):\n    \"\"\"Test oef search handler of ml_train.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"ml_train\")\n    is_agent_to_agent_messages = False\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.oef_search_handler = cast(\n            OEFSearchHandler, cls._skill.skill_context.handlers.oef_search\n        )\n        cls.strategy = cast(Strategy, cls._skill.skill_context.strategy)\n        cls.oef_dialogues = cast(\n            OefSearchDialogues, cls._skill.skill_context.oef_search_dialogues\n        )\n        cls.logger = cls._skill.skill_context.logger\n        cls.list_of_messages = (\n            DialogueMessage(\n                OefSearchMessage.Performative.SEARCH_SERVICES, {\"query\": \"some_query\"}\n            ),\n        )\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the oef_search handler.\"\"\"\n        assert self.oef_search_handler.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle_unidentified_dialogue(self):\n        \"\"\"Test the _handle_unidentified_dialogue method of the oef_search handler.\"\"\"\n        # setup\n        incorrect_dialogue_reference = (\"\", \"\")\n        incoming_message = self.build_incoming_message(\n            message_type=OefSearchMessage,\n            dialogue_reference=incorrect_dialogue_reference,\n            performative=OefSearchMessage.Performative.SEARCH_SERVICES,\n        )\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received invalid oef_search message={incoming_message}, unidentified dialogue.\",\n        )\n\n    def test_handle_error(self):\n        \"\"\"Test the _handle_error method of the oef_search handler.\"\"\"\n        # setup\n        oef_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_dialogues,\n            messages=self.list_of_messages[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=oef_dialogue,\n            performative=OefSearchMessage.Performative.OEF_ERROR,\n            oef_error_operation=OefSearchMessage.OefErrorOperation.SEARCH_SERVICES,\n        )\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received oef_search error message={incoming_message} in dialogue={oef_dialogue}.\",\n        )\n\n    def test_handle_search_zero_agents(self):\n        \"\"\"Test the _handle_search method of the oef_search handler.\"\"\"\n        # setup\n        oef_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_dialogues,\n            messages=self.list_of_messages[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=oef_dialogue,\n            performative=OefSearchMessage.Performative.SEARCH_RESULT,\n            agents=tuple(),\n            agents_info=OefSearchMessage.AgentsInfo({}),\n        )\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"found no agents in dialogue={oef_dialogue}, continue searching.\",\n        )\n\n    def test_handle_search_i(self):\n        \"\"\"Test the _handle_search method of the oef_search handler where len(agent)<max_negotiations.\"\"\"\n        # setup\n        self.strategy._max_negotiations = 3\n        self.strategy._is_searching = True\n\n        oef_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_dialogues,\n            messages=self.list_of_messages[:1],\n        )\n        agents = (\"agnt1\", \"agnt2\")\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=oef_dialogue,\n            performative=OefSearchMessage.Performative.SEARCH_RESULT,\n            agents=agents,\n            agents_info=OefSearchMessage.AgentsInfo(\n                {\"agent_1\": {\"key_1\": \"value_1\"}, \"agent_2\": {\"key_2\": \"value_2\"}}\n            ),\n        )\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO, f\"found agents={list(agents)}, stopping search.\"\n        )\n\n        assert self.strategy.is_searching is False\n\n        self.assert_quantity_in_outbox(len(agents))\n        for agent in agents:\n            has_attributes, error_str = self.message_has_attributes(\n                actual_message=self.get_message_from_outbox(),\n                message_type=MlTradeMessage,\n                performative=MlTradeMessage.Performative.CFP,\n                to=agent,\n                sender=self.skill.skill_context.agent_address,\n                target=0,\n                query=self.strategy.get_service_query(),\n            )\n            assert has_attributes, error_str\n            mock_logger.assert_any_call(logging.INFO, f\"sending CFT to agent={agent}\")\n\n    def test_handle_search_ii(self):\n        \"\"\"Test the _handle_search method of the oef_search handler where number of agents founds is 0.\"\"\"\n        # setup\n        self.strategy._max_negotiations = 1\n        self.strategy._is_searching = True\n\n        oef_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_dialogues,\n            messages=self.list_of_messages[:1],\n        )\n        agents = ()\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=oef_dialogue,\n            performative=OefSearchMessage.Performative.SEARCH_RESULT,\n            agents=agents,\n            agents_info=OefSearchMessage.AgentsInfo({}),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"found no agents in dialogue={oef_dialogue}, continue searching.\",\n        )\n        assert self.strategy.is_searching is True\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle_search_more_than_max_negotiation(self):\n        \"\"\"Test the _handle_search method of the oef_search handler where number of agents is more than max_negotiation.\"\"\"\n        # setup\n        self.strategy._max_negotiations = 1\n        oef_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_dialogues,\n            messages=self.list_of_messages[:1],\n        )\n        agents = (\"agnt1\", \"agnt2\")\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=oef_dialogue,\n            performative=OefSearchMessage.Performative.SEARCH_RESULT,\n            agents=agents,\n            agents_info=OefSearchMessage.AgentsInfo(\n                {\"agent_1\": {\"key_1\": \"value_1\"}, \"agent_2\": {\"key_2\": \"value_2\"}}\n            ),\n        )\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO, f\"found agents={list(agents)}, stopping search.\"\n        )\n\n        assert not self.strategy.is_searching\n\n        self.assert_quantity_in_outbox(self.strategy._max_negotiations)\n        for idx in range(0, self.strategy._max_negotiations):\n            has_attributes, error_str = self.message_has_attributes(\n                actual_message=self.get_message_from_outbox(),\n                message_type=MlTradeMessage,\n                performative=MlTradeMessage.Performative.CFP,\n                to=agents[idx],\n                sender=self.skill.skill_context.agent_address,\n                target=0,\n                query=self.strategy.get_service_query(),\n            )\n            assert has_attributes, error_str\n            mock_logger.assert_any_call(\n                logging.INFO, f\"sending CFT to agent={agents[idx]}\"\n            )\n\n    def test_handle_invalid(self):\n        \"\"\"Test the _handle_invalid method of the oef_search handler.\"\"\"\n        # setup\n        invalid_performative = OefSearchMessage.Performative.UNREGISTER_SERVICE\n        incoming_message = self.build_incoming_message(\n            message_type=OefSearchMessage,\n            dialogue_reference=(\"1\", \"\"),\n            performative=invalid_performative,\n            service_description=\"some_service_description\",\n        )\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"cannot handle oef_search message of performative={invalid_performative} in dialogue={self.oef_dialogues.get_dialogue(incoming_message)}.\",\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the oef_search handler.\"\"\"\n        assert self.oef_search_handler.teardown() is None\n        self.assert_quantity_in_outbox(0)\n\n\nclass TestSigningHandler(BaseSkillTestCase):\n    \"\"\"Test signing handler of ml_train.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"ml_train\")\n    is_agent_to_agent_messages = False\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.signing_handler = cast(\n            SigningHandler, cls._skill.skill_context.handlers.signing\n        )\n        cls.strategy = cast(Strategy, cls._skill.skill_context.strategy)\n        cls.ml_dialogues = cast(\n            MlTradeDialogues, cls._skill.skill_context.ml_trade_dialogues\n        )\n        cls.ledger_api_dialogues = cast(\n            LedgerApiDialogues, cls._skill.skill_context.ledger_api_dialogues\n        )\n        cls.signing_dialogues = cast(\n            SigningDialogues, cls._skill.skill_context.signing_dialogues\n        )\n        cls.tx_terms = Terms(\n            \"some_ledger_id\",\n            cls._skill.skill_context.agent_address,\n            \"counterprty\",\n            {\"currency_id\": 50},\n            {\"good_id\": -10},\n            \"some_nonce\",\n        )\n\n        cls.batch_size = 32\n        cls.price_per_data_batch = 10\n        cls.seller_tx_fee = 0\n        cls.buyer_tx_fee = 0\n        cls.currency_id = \"FET\"\n        cls.ledger_id = \"FET\"\n        cls.service_id = \"data_service\"\n\n        cls.terms = Description(\n            {\n                \"batch_size\": cls.batch_size,\n                \"price\": cls.price_per_data_batch,\n                \"seller_tx_fee\": cls.seller_tx_fee,\n                \"buyer_tx_fee\": cls.buyer_tx_fee,\n                \"currency_id\": cls.currency_id,\n                \"ledger_id\": cls.ledger_id,\n                \"address\": cls._skill.skill_context.agent_address,\n                \"service_id\": cls.service_id,\n                \"nonce\": uuid.uuid4().hex,\n            }\n        )\n\n        cls.list_of_messages = (\n            DialogueMessage(MlTradeMessage.Performative.CFP, {\"query\": \"some_query\"}),\n            DialogueMessage(MlTradeMessage.Performative.TERMS, {\"terms\": cls.terms}),\n            DialogueMessage(\n                MlTradeMessage.Performative.ACCEPT,\n                {\"terms\": cls.terms, \"tx_digest\": \"some_tx_digest\"},\n            ),\n        )\n\n        cls.list_of_signing_messages = (\n            DialogueMessage(\n                SigningMessage.Performative.SIGN_TRANSACTION,\n                {\n                    \"terms\": cls.tx_terms,\n                    \"raw_transaction\": SigningMessage.RawTransaction(\n                        \"some_ledger_id\", {\"some_key\": \"some_value\"}\n                    ),\n                },\n            ),\n        )\n        cls.list_of_ledger_api_messages = (\n            DialogueMessage(LedgerApiMessage.Performative.GET_RAW_TRANSACTION, {}),\n            DialogueMessage(LedgerApiMessage.Performative.RAW_TRANSACTION, {}),\n            DialogueMessage(LedgerApiMessage.Performative.SEND_SIGNED_TRANSACTION, {}),\n            DialogueMessage(LedgerApiMessage.Performative.TRANSACTION_DIGEST, {}),\n        )\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the signing handler.\"\"\"\n        assert self.signing_handler.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle_unidentified_dialogue(self):\n        \"\"\"Test the _handle_unidentified_dialogue method of the signing handler.\"\"\"\n        # setup\n        incorrect_dialogue_reference = (\"\", \"\")\n        incoming_message = self.build_incoming_message(\n            message_type=SigningMessage,\n            dialogue_reference=incorrect_dialogue_reference,\n            performative=SigningMessage.Performative.ERROR,\n            error_code=SigningMessage.ErrorCode.UNSUCCESSFUL_MESSAGE_SIGNING,\n            to=str(self.skill.skill_context.skill_id),\n        )\n\n        # operation\n        with patch.object(self.signing_handler.context.logger, \"log\") as mock_logger:\n            self.signing_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received invalid signing message={incoming_message}, unidentified dialogue.\",\n        )\n\n    def test_handle_signed_transaction_last_ledger_api_message_is_none(\n        self,\n    ):\n        \"\"\"Test the _handle_signed_transaction method of the signing handler.\"\"\"\n        # setup\n        signing_dialogue = cast(\n            SigningDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.signing_dialogues,\n                messages=self.list_of_signing_messages[:1],\n            ),\n        )\n        ledger_api_dialogue = cast(\n            LedgerApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.ledger_api_dialogues,\n                messages=self.list_of_ledger_api_messages[:2],\n            ),\n        )\n        signing_dialogue.associated_ledger_api_dialogue = ledger_api_dialogue\n        signing_dialogue.associated_ledger_api_dialogue._incoming_messages = []\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=signing_dialogue,\n            performative=SigningMessage.Performative.SIGNED_TRANSACTION,\n            signed_transaction=SigningMessage.SignedTransaction(\n                \"some_ledger_id\", {\"some_key\": \"some_value\"}\n            ),\n        )\n\n        # operation\n        with pytest.raises(\n            ValueError, match=\"Could not retrieve last message in ledger api dialogue\"\n        ):\n            with patch.object(\n                self.signing_handler.context.logger, \"log\"\n            ) as mock_logger:\n                self.signing_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(logging.INFO, \"transaction signing was successful.\")\n\n    def test_handle_signed_transaction_last_ledger_api_message_is_not_none(\n        self,\n    ):\n        \"\"\"Test the _handle_signed_transaction method of the signing handler where the last ledger_api message is not None.\"\"\"\n        # setup\n        signing_counterparty = self.skill.skill_context.decision_maker_address\n        signing_dialogue = cast(\n            SigningDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.signing_dialogues,\n                messages=self.list_of_signing_messages[:1],\n                counterparty=signing_counterparty,\n            ),\n        )\n        ledger_api_dialogue = cast(\n            LedgerApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.ledger_api_dialogues,\n                messages=self.list_of_ledger_api_messages[:2],\n                counterparty=LEDGER_API_ADDRESS,\n            ),\n        )\n        signing_dialogue.associated_ledger_api_dialogue = ledger_api_dialogue\n        incoming_message = cast(\n            SigningMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=signing_dialogue,\n                performative=SigningMessage.Performative.SIGNED_TRANSACTION,\n                signed_transaction=SigningMessage.SignedTransaction(\n                    \"some_ledger_id\", {\"some_key\": \"some_value\"}\n                ),\n            ),\n        )\n        # operation\n        with patch.object(self.signing_handler.context.logger, \"log\") as mock_logger:\n            self.signing_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(logging.INFO, \"transaction signing was successful.\")\n\n        self.assert_quantity_in_outbox(1)\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=LedgerApiMessage,\n            performative=LedgerApiMessage.Performative.SEND_SIGNED_TRANSACTION,\n            to=LEDGER_API_ADDRESS,\n            sender=str(self.skill.skill_context.skill_id),\n            signed_transaction=incoming_message.signed_transaction,\n        )\n        assert has_attributes, error_str\n\n        mock_logger.assert_any_call(logging.INFO, \"sending transaction to ledger.\")\n\n    def test_handle_error(self):\n        \"\"\"Test the _handle_error method of the signing handler.\"\"\"\n        # setup\n        ml_dialogue = cast(\n            MlTradeDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.ml_dialogues,\n                messages=self.list_of_messages[:3],\n                counterparty=COUNTERPARTY_AGENT_ADDRESS,\n                is_agent_to_agent_messages=True,\n            ),\n        )\n\n        ledger_api_dialogue = cast(\n            LedgerApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.ledger_api_dialogues,\n                messages=self.list_of_ledger_api_messages[:4],\n                counterparty=LEDGER_API_ADDRESS,\n            ),\n        )\n        ledger_api_dialogue.associated_ml_trade_dialogue = ml_dialogue\n\n        signing_counterparty = self.skill.skill_context.decision_maker_address\n        signing_dialogue = cast(\n            SigningDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.signing_dialogues,\n                messages=self.list_of_signing_messages[:1],\n                counterparty=signing_counterparty,\n            ),\n        )\n        signing_dialogue.associated_ledger_api_dialogue = ledger_api_dialogue\n\n        incoming_message = cast(\n            SigningMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=signing_dialogue,\n                performative=SigningMessage.Performative.ERROR,\n                error_code=SigningMessage.ErrorCode.UNSUCCESSFUL_TRANSACTION_SIGNING,\n            ),\n        )\n\n        # operation\n        with patch.object(\n            self.signing_handler.context.behaviours.transaction, \"failed_processing\"\n        ):\n            with patch.object(\n                self.signing_handler.context.logger, \"log\"\n            ) as mock_logger:\n                self.signing_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"transaction signing was not successful. Error_code={incoming_message.error_code} in dialogue={signing_dialogue}\",\n        )\n\n        behaviour = cast(\n            TransactionBehaviour, self.skill.skill_context.behaviours.transaction\n        )\n\n        # finish_processing\n        assert behaviour.processing_time == 0.0\n        assert behaviour.processing is None\n\n    def test_handle_invalid(self):\n        \"\"\"Test the _handle_invalid method of the signing handler.\"\"\"\n        # setup\n        invalid_performative = SigningMessage.Performative.SIGN_TRANSACTION\n        incoming_message = self.build_incoming_message(\n            message_type=SigningMessage,\n            dialogue_reference=(\"1\", \"\"),\n            performative=invalid_performative,\n            terms=self.tx_terms,\n            raw_transaction=SigningMessage.RawTransaction(\n                \"some_ledger_id\", {\"some_key\": \"some_value\"}\n            ),\n            to=str(self.skill.skill_context.skill_id),\n        )\n\n        # operation\n        with patch.object(self.signing_handler.context.logger, \"log\") as mock_logger:\n            self.signing_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"cannot handle signing message of performative={invalid_performative} in dialogue={self.signing_dialogues.get_dialogue(incoming_message)}.\",\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the signing handler.\"\"\"\n        assert self.signing_handler.teardown() is None\n        self.assert_quantity_in_outbox(0)\n\n\nclass TestLedgerApiHandler(BaseSkillTestCase):\n    \"\"\"Test ledger_api handler of ml_train.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"ml_train\")\n    is_agent_to_agent_messages = False\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.ledger_api_handler = cast(\n            LedgerApiHandler, cls._skill.skill_context.handlers.ledger_api\n        )\n        cls.transaction_behaviour = cast(\n            TransactionBehaviour, cls._skill.skill_context.behaviours.transaction\n        )\n        cls.strategy = cast(Strategy, cls._skill.skill_context.strategy)\n        cls.logger = cls._skill.skill_context.logger\n\n        cls.ml_dialogues = cast(\n            MlTradeDialogues, cls._skill.skill_context.ml_trade_dialogues\n        )\n        cls.ledger_api_dialogues = cast(\n            LedgerApiDialogues, cls._skill.skill_context.ledger_api_dialogues\n        )\n\n        cls.tx_terms = Terms(\n            \"some_ledger_id\",\n            cls._skill.skill_context.agent_address,\n            \"counterprty\",\n            {\"currency_id\": 50},\n            {\"good_id\": -10},\n            \"some_nonce\",\n        )\n\n        cls.batch_size = 32\n        cls.price_per_data_batch = 10\n        cls.seller_tx_fee = 0\n        cls.buyer_tx_fee = 0\n        cls.currency_id = \"FET\"\n        cls.ledger_id = \"FET\"\n        cls.service_id = \"data_service\"\n\n        cls.terms = Description(\n            {\n                \"batch_size\": cls.batch_size,\n                \"price\": cls.price_per_data_batch,\n                \"seller_tx_fee\": cls.seller_tx_fee,\n                \"buyer_tx_fee\": cls.buyer_tx_fee,\n                \"currency_id\": cls.currency_id,\n                \"ledger_id\": cls.ledger_id,\n                \"address\": cls._skill.skill_context.agent_address,\n                \"service_id\": cls.service_id,\n                \"nonce\": uuid.uuid4().hex,\n            }\n        )\n\n        cls.list_of_messages = (\n            DialogueMessage(MlTradeMessage.Performative.CFP, {\"query\": \"some_query\"}),\n            DialogueMessage(MlTradeMessage.Performative.TERMS, {\"terms\": cls.terms}),\n            DialogueMessage(\n                MlTradeMessage.Performative.ACCEPT,\n                {\"terms\": cls.terms, \"tx_digest\": \"some_tx_digest\"},\n            ),\n        )\n\n        cls.raw_transaction = RawTransaction(\n            \"some_ledger_id\", {\"some_key\": \"some_value\"}\n        )\n        cls.signed_transaction = SignedTransaction(\n            \"some_ledger_id\", {\"some_key\": \"some_value\"}\n        )\n        cls.transaction_digest = TransactionDigest(\"some_ledger_id\", \"some_body\")\n        cls.transaction_receipt = TransactionReceipt(\n            \"some_ledger_id\",\n            {\"receipt_key\": \"receipt_value\"},\n            {\"transaction_key\": \"transaction_value\"},\n        )\n        cls.list_of_ledger_api_messages = (\n            DialogueMessage(\n                LedgerApiMessage.Performative.GET_RAW_TRANSACTION,\n                {\"terms\": cls.tx_terms},\n            ),\n            DialogueMessage(\n                LedgerApiMessage.Performative.RAW_TRANSACTION,\n                {\"raw_transaction\": cls.raw_transaction},\n            ),\n            DialogueMessage(\n                LedgerApiMessage.Performative.SEND_SIGNED_TRANSACTION,\n                {\"signed_transaction\": cls.signed_transaction},\n            ),\n            DialogueMessage(\n                LedgerApiMessage.Performative.TRANSACTION_DIGEST,\n                {\"transaction_digest\": cls.transaction_digest},\n            ),\n            DialogueMessage(\n                LedgerApiMessage.Performative.GET_TRANSACTION_RECEIPT,\n                {\"transaction_digest\": cls.transaction_digest},\n            ),\n            DialogueMessage(\n                LedgerApiMessage.Performative.TRANSACTION_RECEIPT,\n                {\"transaction_receipt\": cls.transaction_receipt},\n            ),\n        )\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the ledger_api handler.\"\"\"\n        assert self.ledger_api_handler.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle_unidentified_dialogue(self):\n        \"\"\"Test the _handle_unidentified_dialogue method of the ledger_api handler.\"\"\"\n        # setup\n        incorrect_dialogue_reference = (\"\", \"\")\n        incoming_message = self.build_incoming_message(\n            message_type=LedgerApiMessage,\n            dialogue_reference=incorrect_dialogue_reference,\n            performative=LedgerApiMessage.Performative.GET_BALANCE,\n            ledger_id=\"some_ledger_id\",\n            address=\"some_address\",\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received invalid ledger_api message={incoming_message}, unidentified dialogue.\",\n        )\n\n    def test_handle_balance_positive_balance(self):\n        \"\"\"Test the _handle_balance method of the ledger_api handler where balance is positive.\"\"\"\n        # setup\n        balance = 10\n        ledger_api_dialogue = cast(\n            LedgerApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.ledger_api_dialogues,\n                messages=(\n                    DialogueMessage(\n                        LedgerApiMessage.Performative.GET_BALANCE,\n                        {\"ledger_id\": \"some_ledger_id\", \"address\": \"some_address\"},\n                    ),\n                ),\n                counterparty=LEDGER_API_ADDRESS,\n            ),\n        )\n        incoming_message = cast(\n            LedgerApiMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=ledger_api_dialogue,\n                performative=LedgerApiMessage.Performative.BALANCE,\n                ledger_id=\"some-Ledger_id\",\n                balance=balance,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"starting balance on {self.strategy.ledger_id} ledger={incoming_message.balance}.\",\n        )\n        assert self.strategy.balance == balance\n        assert self.strategy.is_searching\n\n    def test_handle_balance_zero_balance(self):\n        \"\"\"Test the _handle_balance method of the ledger_api handler where balance is zero.\"\"\"\n        # setup\n        balance = 0\n        ledger_api_dialogue = cast(\n            LedgerApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.ledger_api_dialogues,\n                messages=(\n                    DialogueMessage(\n                        LedgerApiMessage.Performative.GET_BALANCE,\n                        {\"ledger_id\": \"some_ledger_id\", \"address\": \"some_address\"},\n                    ),\n                ),\n                counterparty=LEDGER_API_ADDRESS,\n            ),\n        )\n        incoming_message = cast(\n            LedgerApiMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=ledger_api_dialogue,\n                performative=LedgerApiMessage.Performative.BALANCE,\n                ledger_id=\"some-Ledger_id\",\n                balance=balance,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"you have no starting balance on {self.strategy.ledger_id} ledger!\",\n        )\n        assert not self.skill.skill_context.is_active\n\n    def test_handle_raw_transaction(self):\n        \"\"\"Test the _handle_raw_transaction method of the ledger_api handler.\"\"\"\n        # setup\n        ledger_api_dialogue = cast(\n            LedgerApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.ledger_api_dialogues,\n                messages=self.list_of_ledger_api_messages[:1],\n                counterparty=LEDGER_API_ADDRESS,\n            ),\n        )\n        ml_dialogue = cast(\n            MlTradeDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.ml_dialogues,\n                messages=self.list_of_messages[:3],\n                is_agent_to_agent_messages=True,\n            ),\n        )\n        ledger_api_dialogue.associated_ml_trade_dialogue = ml_dialogue\n        ml_dialogue.terms = self.tx_terms\n        incoming_message = cast(\n            LedgerApiMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=ledger_api_dialogue,\n                performative=LedgerApiMessage.Performative.RAW_TRANSACTION,\n                raw_transaction=self.raw_transaction,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO, f\"received raw transaction={incoming_message}\"\n        )\n\n        message_quantity = self.get_quantity_in_decision_maker_inbox()\n        assert (\n            message_quantity == 1\n        ), f\"Invalid number of messages in decision maker queue. Expected {1}. Found {message_quantity}.\"\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_decision_maker_inbox(),\n            message_type=SigningMessage,\n            performative=SigningMessage.Performative.SIGN_TRANSACTION,\n            to=self.skill.skill_context.decision_maker_address,\n            sender=str(self.skill.skill_context.skill_id),\n            terms=self.tx_terms,\n        )\n        assert has_attributes, error_str\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            \"proposing the transaction to the decision maker. Waiting for confirmation ...\",\n        )\n\n    def test_handle_transaction_digest(self):\n        \"\"\"Test the _handle_transaction_digest method of the ledger_api handler.\"\"\"\n        # setup\n        ledger_api_dialogue = cast(\n            LedgerApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.ledger_api_dialogues,\n                messages=self.list_of_ledger_api_messages[:3],\n                counterparty=LEDGER_API_ADDRESS,\n            ),\n        )\n        incoming_message = cast(\n            LedgerApiMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=ledger_api_dialogue,\n                performative=LedgerApiMessage.Performative.TRANSACTION_DIGEST,\n                transaction_digest=self.transaction_digest,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"transaction was successfully submitted. Transaction digest={incoming_message.transaction_digest}\",\n        )\n\n        self.assert_quantity_in_outbox(1)\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=LedgerApiMessage,\n            performative=LedgerApiMessage.Performative.GET_TRANSACTION_RECEIPT,\n            to=incoming_message.sender,\n            sender=str(self.skill.skill_context.skill_id),\n            transaction_digest=self.transaction_digest,\n        )\n        assert has_attributes, error_str\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            \"checking transaction is settled.\",\n        )\n\n    def test_handle_transaction_receipt_i(self):\n        \"\"\"Test the _handle_transaction_receipt method of the ledger_api handler.\"\"\"\n        # setup\n        ledger_api_dialogue = cast(\n            LedgerApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.ledger_api_dialogues,\n                messages=self.list_of_ledger_api_messages[:5],\n                counterparty=LEDGER_API_ADDRESS,\n            ),\n        )\n        ml_dialogue = cast(\n            MlTradeDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.ml_dialogues,\n                messages=self.list_of_messages[:3],\n                is_agent_to_agent_messages=True,\n            ),\n        )\n        ledger_api_dialogue.associated_ml_trade_dialogue = ml_dialogue\n        ml_dialogue.terms = self.tx_terms\n        incoming_message = cast(\n            LedgerApiMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=ledger_api_dialogue,\n                performative=LedgerApiMessage.Performative.TRANSACTION_RECEIPT,\n                transaction_receipt=self.transaction_receipt,\n            ),\n        )\n\n        # operation\n        with patch.object(\n            self.ledger_api_handler.context.behaviours.transaction, \"finish_processing\"\n        ):\n            with patch.object(LedgerApis, \"is_transaction_settled\", return_value=True):\n                with patch.object(self.logger, \"log\") as mock_logger:\n                    self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"informing counterparty={ml_dialogue.dialogue_label.dialogue_opponent_addr[-5:]} of transaction digest={self.transaction_digest}.\",\n        )\n\n        self.assert_quantity_in_outbox(1)\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=MlTradeMessage,\n            performative=MlTradeMessage.Performative.ACCEPT,\n            to=COUNTERPARTY_AGENT_ADDRESS,\n            sender=self.skill.skill_context.agent_address,\n            tx_digest=self.transaction_digest.body,\n            terms=self.terms,\n        )\n        assert has_attributes, error_str\n\n    def test_handle_transaction_receipt_ii(self):\n        \"\"\"Test the _handle_transaction_receipt method of the ledger_api handler where ml dialogue's last_incoming_message is None.\"\"\"\n        # setup\n        ledger_api_dialogue = cast(\n            LedgerApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.ledger_api_dialogues,\n                messages=self.list_of_ledger_api_messages[:5],\n                counterparty=LEDGER_API_ADDRESS,\n            ),\n        )\n        ml_dialogue = cast(\n            MlTradeDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.ml_dialogues,\n                messages=self.list_of_messages[:3],\n                is_agent_to_agent_messages=True,\n            ),\n        )\n        ledger_api_dialogue.associated_ml_trade_dialogue = ml_dialogue\n\n        ml_dialogue._incoming_messages = []\n\n        ml_dialogue.terms = self.tx_terms\n        incoming_message = cast(\n            LedgerApiMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=ledger_api_dialogue,\n                performative=LedgerApiMessage.Performative.TRANSACTION_RECEIPT,\n                transaction_receipt=self.transaction_receipt,\n            ),\n        )\n\n        # operation\n        with patch.object(\n            self.ledger_api_handler.context.behaviours.transaction, \"finish_processing\"\n        ):\n            with patch.object(LedgerApis, \"is_transaction_settled\", return_value=True):\n                with patch.object(self.logger, \"log\"):\n                    with pytest.raises(\n                        ValueError, match=\"Could not retrieve last ml_trade message\"\n                    ):\n                        self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle_transaction_receipt_iii(self):\n        \"\"\"Test the _handle_transaction_receipt method of the ledger_api handler where tx is NOT settled.\"\"\"\n        # setup\n        ledger_api_dialogue = cast(\n            LedgerApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.ledger_api_dialogues,\n                messages=self.list_of_ledger_api_messages[:5],\n                counterparty=LEDGER_API_ADDRESS,\n            ),\n        )\n        ml_dialogue = cast(\n            MlTradeDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.ml_dialogues,\n                messages=self.list_of_messages[:3],\n                is_agent_to_agent_messages=True,\n            ),\n        )\n        ledger_api_dialogue.associated_ml_trade_dialogue = ml_dialogue\n        ml_dialogue.terms = self.tx_terms\n        incoming_message = cast(\n            LedgerApiMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=ledger_api_dialogue,\n                performative=LedgerApiMessage.Performative.TRANSACTION_RECEIPT,\n                transaction_receipt=self.transaction_receipt,\n            ),\n        )\n\n        # operation\n        with patch.object(\n            self.ledger_api_handler.context.behaviours.transaction, \"failed_processing\"\n        ):\n            with patch.object(LedgerApis, \"is_transaction_settled\", return_value=False):\n                with patch.object(self.logger, \"log\") as mock_logger:\n                    self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        self.assert_quantity_in_outbox(0)\n        assert self.transaction_behaviour.processing is None\n        assert self.transaction_behaviour.processing_time == 0.0\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"transaction_receipt={self.transaction_receipt} not settled or not valid, aborting\",\n        )\n\n    def test_handle_error(self):\n        \"\"\"Test the _handle_error method of the ledger_api handler.\"\"\"\n        # setup\n        ledger_api_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.ledger_api_dialogues,\n            messages=self.list_of_ledger_api_messages[:1],\n        )\n        incoming_message = cast(\n            LedgerApiMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=ledger_api_dialogue,\n                performative=LedgerApiMessage.Performative.ERROR,\n                code=1,\n            ),\n        )\n        ledger_api_dialogue.associated_ml_trade_dialogue = \"mock\"\n        # operation\n        with patch.object(\n            self.ledger_api_handler.context.behaviours.transaction, \"failed_processing\"\n        ):\n            with patch.object(self.logger, \"log\") as mock_logger:\n                self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received ledger_api error message={incoming_message} in dialogue={ledger_api_dialogue}.\",\n        )\n\n    def test_handle_invalid(self):\n        \"\"\"Test the _handle_invalid method of the ledger_api handler.\"\"\"\n        # setup\n        invalid_performative = LedgerApiMessage.Performative.GET_BALANCE\n        incoming_message = self.build_incoming_message(\n            message_type=LedgerApiMessage,\n            dialogue_reference=(\"1\", \"\"),\n            performative=invalid_performative,\n            ledger_id=\"some_ledger_id\",\n            address=\"some_address\",\n            to=str(self.skill.public_id),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"cannot handle ledger_api message of performative={invalid_performative} in dialogue={self.ledger_api_dialogues.get_dialogue(incoming_message)}.\",\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the ledger_api handler.\"\"\"\n        assert self.ledger_api_handler.teardown() is None\n        self.assert_quantity_in_outbox(0)\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_ml_train/test_strategy.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the strategy class of the ml_train skill.\"\"\"\n\nimport json\nfrom pathlib import Path\n\nimport numpy as np\nimport pytest\n\nfrom aea.exceptions import AEAEnforceError\nfrom aea.helpers.search.models import Constraint, ConstraintType, Description, Query\nfrom aea.helpers.transaction.base import Terms\nfrom aea.test_tools.test_skill import BaseSkillTestCase, COUNTERPARTY_AGENT_ADDRESS\n\nfrom packages.fetchai.skills.ml_data_provider.strategy import (\n    Strategy as DataProviderStrategy,\n)\nfrom packages.fetchai.skills.ml_train.strategy import (\n    DEFAULT_LOCATION,\n    DEFAULT_MAX_NEGOTIATIONS,\n    DEFAULT_MAX_ROW_PRICE,\n    DEFAULT_MAX_TX_FEE,\n    DEFAULT_SEARCH_QUERY,\n    DEFAULT_SEARCH_RADIUS,\n    DEFAULT_SERVICE_ID,\n    SIMPLE_DATA_MODEL,\n    Strategy,\n)\n\nfrom tests.conftest import ROOT_DIR\nfrom tests.test_packages.test_skills.test_ml_train.helpers import produce_data\n\n\nclass TestStrategy(BaseSkillTestCase):\n    \"\"\"Test Strategy of ml_train.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"ml_train\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.max_unit_price = DEFAULT_MAX_ROW_PRICE\n        cls.max_buyer_tx_fee = DEFAULT_MAX_TX_FEE\n        cls.currency_id = \"FET\"\n        cls.ledger_id = \"fetchai\"\n        cls.is_ledger_tx = False\n        cls.max_negotiations = DEFAULT_MAX_NEGOTIATIONS\n        cls.service_id = DEFAULT_SERVICE_ID\n        cls.search_query = DEFAULT_SEARCH_QUERY\n        cls.location = DEFAULT_LOCATION\n        cls.search_radius = DEFAULT_SEARCH_RADIUS\n\n        cls.strategy = Strategy(\n            max_unit_price=cls.max_unit_price,\n            max_buyer_tx_fee=cls.max_buyer_tx_fee,\n            currency_id=cls.currency_id,\n            ledger_id=cls.ledger_id,\n            is_ledger_tx=cls.is_ledger_tx,\n            max_negotiations=cls.max_negotiations,\n            service_id=cls.service_id,\n            search_query=cls.search_query,\n            location=cls.location,\n            search_radius=cls.search_radius,\n            name=\"strategy\",\n            skill_context=cls._skill.skill_context,\n        )\n\n    def test_properties(self):\n        \"\"\"Test the properties of Strategy class.\"\"\"\n        assert self.strategy.ledger_id == self.ledger_id\n        assert self.strategy.is_ledger_tx == self.is_ledger_tx\n        assert self.strategy.max_negotiations == self.max_negotiations\n\n        assert self.strategy.is_searching is False\n        self.strategy.is_searching = True\n        assert self.strategy.is_searching is True\n        with pytest.raises(AEAEnforceError, match=\"Can only set bool on is_searching!\"):\n            self.strategy.is_searching = \"True\"\n\n        assert self.strategy.balance == 0\n        self.strategy.balance = 5\n        assert self.strategy.balance == 5\n\n        assert self.strategy.current_task_id is None\n        self.strategy.current_task_id = 2\n        assert self.strategy.current_task_id == 2\n\n        assert self.strategy.weights is None\n        self.strategy.weights = []\n        assert self.strategy.weights == []\n\n        assert self.strategy.data == []\n\n    def test_get_next_transaction_id(self):\n        \"\"\"Test the get_next_transaction_id method of the Strategy class.\"\"\"\n        tx_id = self.strategy.get_next_transaction_id()\n        assert tx_id == f\"transaction_{self.strategy._tx_id}\"\n\n    def test_get_location_and_service_query(self):\n        \"\"\"Test the get_location_and_service_query method of the Strategy class.\"\"\"\n        query = self.strategy.get_location_and_service_query()\n\n        assert type(query) == Query\n        assert len(query.constraints) == 2\n        assert query.model is None\n\n        location_constraint = Constraint(\n            \"location\",\n            ConstraintType(\n                \"distance\", (self.strategy._agent_location, self.search_radius)\n            ),\n        )\n        assert query.constraints[0] == location_constraint\n\n        service_key_constraint = Constraint(\n            self.search_query[\"search_key\"],\n            ConstraintType(\n                self.search_query[\"constraint_type\"],\n                self.search_query[\"search_value\"],\n            ),\n        )\n        assert query.constraints[1] == service_key_constraint\n\n    def test_get_service_query(self):\n        \"\"\"Test the get_service_query method of the Strategy class.\"\"\"\n        query = self.strategy.get_service_query()\n\n        assert type(query) == Query\n        assert len(query.constraints) == 1\n\n        assert query.model == SIMPLE_DATA_MODEL\n\n        service_key_constraint = Constraint(\n            self.search_query[\"search_key\"],\n            ConstraintType(\n                self.search_query[\"constraint_type\"],\n                self.search_query[\"search_value\"],\n            ),\n        )\n        assert query.constraints[0] == service_key_constraint\n\n    def test_is_acceptable_proposal(self):\n        \"\"\"Test the is_acceptable_proposal method of the Strategy class.\"\"\"\n        acceptable_description = Description(\n            {\n                \"ledger_id\": self.ledger_id,\n                \"price\": 20,\n                \"currency_id\": self.currency_id,\n                \"service_id\": self.service_id,\n                \"quantity\": 10,\n                \"tx_nonce\": \"some_tx_nonce\",\n                \"seller_tx_fee\": 0,\n                \"buyer_tx_fee\": 0,\n                \"batch_size\": 5,\n            }\n        )\n        is_acceptable = self.strategy.is_acceptable_terms(acceptable_description)\n        assert is_acceptable\n\n        unacceptable_description = Description(\n            {\n                \"ledger_id\": self.ledger_id,\n                \"price\": 250,\n                \"currency_id\": self.currency_id,\n                \"service_id\": self.service_id,\n                \"quantity\": 10,\n                \"tx_nonce\": \"some_tx_nonce\",\n                \"seller_tx_fee\": 0,\n                \"buyer_tx_fee\": 0,\n                \"batch_size\": 5,\n            }\n        )\n        is_acceptable = self.strategy.is_acceptable_terms(unacceptable_description)\n        assert not is_acceptable\n\n    def test_is_affordable_proposal(self):\n        \"\"\"Test the is_affordable_proposal method of the Strategy class.\"\"\"\n        self.strategy._is_ledger_tx = True\n        description = Description(\n            {\n                \"ledger_id\": self.ledger_id,\n                \"price\": 20,\n                \"currency_id\": self.currency_id,\n                \"service_id\": self.service_id,\n                \"quantity\": 10,\n                \"tx_nonce\": \"some_tx_nonce\",\n                \"seller_tx_fee\": 0,\n                \"buyer_tx_fee\": 0,\n                \"batch_size\": 5,\n            }\n        )\n        self.strategy.balance = 20\n        is_affordable = self.strategy.is_affordable_terms(description)\n        assert is_affordable\n\n        self.strategy.balance = 19\n        is_affordable = self.strategy.is_affordable_terms(description)\n        assert not is_affordable\n\n        self.strategy._is_ledger_tx = False\n        is_affordable = self.strategy.is_affordable_terms(description)\n        assert is_affordable\n\n    def test_terms_from_proposal(self):\n        \"\"\"Test the terms_from_proposal method of the Strategy class.\"\"\"\n        description = Description(\n            {\n                \"ledger_id\": self.ledger_id,\n                \"price\": 150,\n                \"address\": COUNTERPARTY_AGENT_ADDRESS,\n                \"currency_id\": self.currency_id,\n                \"service_id\": self.service_id,\n                \"quantity\": 10,\n                \"tx_nonce\": \"some_tx_nonce\",\n                \"seller_tx_fee\": 0,\n                \"buyer_tx_fee\": 0,\n                \"batch_size\": 5,\n                \"nonce\": \"some_tx_nonce\",\n            }\n        )\n        terms = Terms(\n            ledger_id=self.ledger_id,\n            sender_address=self.skill.skill_context.agent_address,\n            counterparty_address=COUNTERPARTY_AGENT_ADDRESS,\n            amount_by_currency_id={self.currency_id: -150},\n            quantities_by_good_id={self.service_id: 5},\n            is_sender_payable_tx_fee=True,\n            nonce=\"some_tx_nonce\",\n            fee_by_currency_id={self.currency_id: self.max_buyer_tx_fee},\n        )\n        assert self.strategy.terms_from_proposal(description) == terms\n\n    def test_decode_sample_data_i(self):\n        \"\"\"Test the decode_sample_data method of the Strategy class where data is NOT None.\"\"\"\n        # setup\n        data = produce_data(batch_size=32)\n        encoded_data = DataProviderStrategy.encode_sample_data(data)\n\n        # operation\n        decoded_data = self.strategy.decode_sample_data(encoded_data)\n\n        # after\n        assert type(decoded_data) == tuple\n\n        numpy_data_0 = decoded_data[0]\n        numpy_data_1 = decoded_data[1]\n\n        assert type(numpy_data_0) == type(numpy_data_1) == np.ndarray\n        assert (numpy_data_0 == data[0]).all()\n        assert (numpy_data_1 == data[1]).all()\n\n    def test_decode_sample_data_ii(self):\n        \"\"\"Test the decode_sample_data method of the Strategy class where data IS None.\"\"\"\n        # setup\n        data = None\n        encoded_data = json.dumps(data).encode(\"utf-8\")\n\n        # operation\n        decoded_data = self.strategy.decode_sample_data(encoded_data)\n\n        # after\n        assert decoded_data is None\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_ml_train/test_task.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the task class of the ml_train skill.\"\"\"\n\nfrom pathlib import Path\nfrom typing import Tuple\nfrom unittest.mock import patch\n\nimport numpy as np\n\nfrom aea.test_tools.test_skill import BaseSkillTestCase\n\nfrom packages.fetchai.skills.ml_train.tasks import MLTrainTask\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass TestTask(BaseSkillTestCase):\n    \"\"\"Test Task of ml_train.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"ml_train\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.batch_size = 32\n        cls.train_data = cls.produce_data(cls.batch_size)\n        cls.epochs_per_batch = 10\n        cls.weights = None\n\n        cls.task = MLTrainTask(\n            train_data=cls.train_data,\n            epochs_per_batch=cls.epochs_per_batch,\n            weights=cls.weights,\n        )\n        cls.logger = cls.task.logger\n\n    @staticmethod\n    def produce_data(batch_size) -> Tuple:\n        \"\"\"Prodice the data.\"\"\"\n        import tensorflow as tf  # pylint: disable=import-outside-toplevel\n\n        ((train_x, train_y), _) = tf.keras.datasets.fashion_mnist.load_data()\n\n        idx = np.arange(train_x.shape[0])\n        mask = np.zeros_like(idx, dtype=bool)\n\n        selected = np.random.choice(idx, batch_size, replace=False)\n        mask[selected] = True\n\n        x_sample = train_x[mask]\n        y_sample = train_y[mask]\n        return x_sample, y_sample\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the MLTrainTask class.\"\"\"\n        # operation\n        with patch.object(self.logger, \"info\") as mock_logger:\n            self.task.setup()\n\n        # after\n        mock_logger.assert_any_call(\"ML Train task: setup method called.\")\n\n    def test_make_model_i(self):\n        \"\"\"Test the make_model method of the MLTrainTask class where weights is None.\"\"\"\n        # setup\n        import tensorflow as tf  # pylint: disable=import-outside-toplevel\n\n        # operation\n        with patch(\"tensorflow.keras.Sequential.set_weights\") as mock_set_weights:\n            model = self.task.make_model()\n\n        # after\n        assert isinstance(model, tf.keras.Sequential)\n        mock_set_weights.assert_not_called()\n\n    def test_make_model_ii(self):\n        \"\"\"Test the make_model method of the MLTrainTask class where weights is NOT None.\"\"\"\n        # setup\n        import tensorflow as tf  # pylint: disable=import-outside-toplevel\n\n        # before\n        self.task.weights = []\n\n        # operation\n        with patch(\"tensorflow.keras.Sequential.set_weights\") as mock_set_weights:\n            model = self.task.make_model()\n\n        # after\n        assert isinstance(model, tf.keras.Sequential)\n        mock_set_weights.assert_any_call(self.task.weights)\n\n    def test_execute(self):\n        \"\"\"Test the execute method of the MLTrainTask class.\"\"\"\n        # before\n        mocked_new_weights = [\"new_weights\"]\n        mocked_loss = \"0.1\"\n        mocked_acc = \"0.8\"\n\n        # operation\n        with patch.object(self.logger, \"info\") as mock_logger:\n            with patch(\"tensorflow.keras.Sequential.fit\") as mock_fit:\n                with patch(\n                    \"tensorflow.keras.Sequential.get_weights\",\n                    return_value=mocked_new_weights,\n                ) as mock_get_weights:\n                    with patch(\n                        \"tensorflow.keras.Sequential.evaluate\",\n                        return_value=(mocked_loss, mocked_acc),\n                    ) as mock_evaluate:\n                        actual_new_weights = self.task.execute()\n\n        # after\n        mock_fit.assert_called_with(\n            self.task.train_x, self.task.train_y, epochs=self.task.epochs_per_batch\n        )\n        mock_get_weights.assert_called_once()\n        mock_evaluate.assert_called_with(\n            self.task.train_x, self.task.train_y, verbose=2\n        )\n\n        mock_logger.assert_any_call(\n            f\"Start training with {self.task.train_x.shape[0]} rows\"\n        )\n        mock_logger.assert_any_call(f\"Loss: {mocked_loss}, Acc: {mocked_acc}\")\n\n        assert actual_new_weights == mocked_new_weights\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the MLTrainTask class.\"\"\"\n        # operation\n        with patch.object(self.logger, \"info\") as mock_logger:\n            self.task.teardown()\n\n        # after\n        mock_logger.assert_any_call(\"ML Train task: teardown method called.\")\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_registration_aw1/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"The tests module contains the tests of the packages/skills/registration_aw1 dir.\"\"\"\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_registration_aw1/intermediate_class.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the strategy class of the tac negotiation skill.\"\"\"\n\nfrom pathlib import Path\nfrom typing import cast\nfrom unittest.mock import patch\n\nfrom aea.crypto.ledger_apis import LedgerApis\nfrom aea.test_tools.test_skill import BaseSkillTestCase\n\nfrom packages.fetchai.skills.registration_aw1.behaviours import AW1RegistrationBehaviour\nfrom packages.fetchai.skills.registration_aw1.dialogues import (\n    RegisterDialogues,\n    SigningDialogues,\n)\nfrom packages.fetchai.skills.registration_aw1.handlers import (\n    AW1RegistrationHandler,\n    SigningHandler,\n)\nfrom packages.fetchai.skills.registration_aw1.strategy import Strategy\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass RegiatrationAW1TestCase(BaseSkillTestCase):\n    \"\"\"Sets the registration_aw1 class up for testing (overrides the necessary config values so tests can be done on registration_aw1 skill).\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"registration_aw1\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        cls.developer_handle = \"some_developer_handle\"\n        cls.ethereum_address = \"some_ethereum_address\"\n        cls.signature_of_fetchai_address = \"some_signature_of_fetchai_address\"\n        cls.shared_storage_key = \"some_shared_storage_key\"\n        cls.tweet = \"some_tweet\"\n\n        cls.aw1_registration_aea = \"aw1_registration_aea_1\"\n        cls.aw1_registration_aeas = {cls.aw1_registration_aea}\n        cls.whitelist = [cls.aw1_registration_aea]\n        config_overrides = {\n            \"models\": {\n                \"strategy\": {\n                    \"args\": {\n                        \"developer_handle\": cls.developer_handle,\n                        \"ethereum_address\": cls.ethereum_address,\n                        \"signature_of_fetchai_address\": cls.signature_of_fetchai_address,\n                        \"shared_storage_key\": cls.shared_storage_key,\n                        \"whitelist\": cls.whitelist,\n                        \"tweet\": cls.tweet,\n                    }\n                }\n            },\n        }\n\n        with patch.object(LedgerApis, \"is_valid_address\", return_value=True):\n            super().setup(\n                config_overrides=config_overrides,\n                shared_state={cls.shared_storage_key: None},\n            )\n\n        cls.register_behaviour = cast(\n            AW1RegistrationBehaviour,\n            cls._skill.skill_context.behaviours.registration,\n        )\n        cls.register_handler = cast(\n            AW1RegistrationHandler, cls._skill.skill_context.handlers.registration\n        )\n        cls.signing_handler = cast(\n            SigningHandler, cls._skill.skill_context.handlers.signing\n        )\n\n        cls.register_dialogues = cast(\n            RegisterDialogues, cls._skill.skill_context.register_dialogues\n        )\n        cls.signing_dialogues = cast(\n            SigningDialogues, cls._skill.skill_context.signing_dialogues\n        )\n\n        cls.strategy = cast(Strategy, cls._skill.skill_context.strategy)\n        cls.logger = cls._skill.skill_context.logger\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_registration_aw1/test_behaviours.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the behaviour classes of the registration_aw1 skill.\"\"\"\n\nimport logging\nfrom pathlib import Path\nfrom unittest.mock import patch\n\nfrom aea.helpers.transaction.base import RawMessage, Terms\n\nfrom packages.fetchai.protocols.register.message import RegisterMessage\nfrom packages.fetchai.protocols.signing.message import SigningMessage\n\nfrom tests.conftest import ROOT_DIR\nfrom tests.test_packages.test_skills.test_registration_aw1.intermediate_class import (\n    RegiatrationAW1TestCase,\n)\n\n\nclass TestAW1Registration(RegiatrationAW1TestCase):\n    \"\"\"Test registration behaviour of registration_aw1.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"registration_aw1\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n\n    def test_setup_i(self):\n        \"\"\"Test the setup method of the registration behaviour NOT developer_handle_mode and announce_termination_key is None.\"\"\"\n        # setup\n        self.strategy.announce_termination_key = None\n        self.strategy.developer_handle_mode = False\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.register_behaviour.setup()\n\n        # after\n        self.assert_quantity_in_decision_making_queue(1)\n        message = self.get_message_from_decision_maker_inbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=SigningMessage,\n            performative=SigningMessage.Performative.SIGN_MESSAGE,\n            to=self.skill.skill_context.decision_maker_address,\n            sender=str(self.skill.skill_context.skill_id),\n            raw_message=RawMessage(\n                self.strategy.ledger_id, self.strategy.ethereum_address.encode(\"utf-8\")\n            ),\n            terms=Terms(\n                ledger_id=self.strategy.ledger_id,\n                sender_address=\"\",\n                counterparty_address=\"\",\n                amount_by_currency_id={},\n                quantities_by_good_id={},\n                nonce=\"\",\n            ),\n        )\n        assert has_attributes, error_str\n\n        mock_logger.assert_any_call(\n            logging.INFO, \"sending signing_msg to decision maker...\"\n        )\n\n    def test_setup_ii(self):\n        \"\"\"Test the setup method of the registration behaviour IN developer_handle_mode and announce_termination_key is NOT None.\"\"\"\n        # setup\n        key = \"some_key\"\n        self.strategy.announce_termination_key = key\n        self.strategy.developer_handle_only = True\n\n        # operation\n        self.register_behaviour.setup()\n\n        # after\n        self.assert_quantity_in_decision_making_queue(0)\n\n        assert self.skill.skill_context.shared_state[key] is False\n\n    def test_act_i(self):\n        \"\"\"Test the act method of the registration behaviour where is_ready_to_register is False.\"\"\"\n        # setup\n        self.strategy.is_ready_to_register = False\n\n        # operation\n        self.register_behaviour.act()\n\n        # after\n        self.assert_quantity_in_outbox(0)\n\n    def test_act_ii(self):\n        \"\"\"Test the act method of the registration behaviour where aw1_registration_aeas is None.\"\"\"\n        # setup\n        self.strategy.is_ready_to_register = True\n\n        # operation\n        self.register_behaviour.act()\n\n        # after\n        self.assert_quantity_in_outbox(0)\n\n    def test_act_iii(self):\n        \"\"\"Test the act method of the registration behaviour where is_registered is True.\"\"\"\n        # setup\n        self.strategy.is_ready_to_register = True\n        self.skill.skill_context.shared_state[\n            self.shared_storage_key\n        ] = self.aw1_registration_aeas\n        self.strategy.is_registered = True\n\n        # operation\n        self.register_behaviour.act()\n\n        # after\n        self.assert_quantity_in_outbox(0)\n\n    def test_act_iv(self):\n        \"\"\"Test the act method of the registration behaviour where is_registration_pending is True.\"\"\"\n        # setup\n        self.strategy.is_ready_to_register = True\n        self.skill.skill_context.shared_state[\n            self.shared_storage_key\n        ] = self.aw1_registration_aeas\n        self.strategy.is_registered = False\n        self.strategy.is_registration_pending = True\n\n        # operation\n        self.register_behaviour.act()\n\n        # after\n        self.assert_quantity_in_outbox(0)\n\n    def test_act_v(self):\n        \"\"\"Test the act method of the registration behaviour where _register_for_aw1 is called.\"\"\"\n        # setup\n        self.strategy.is_ready_to_register = True\n        self.skill.skill_context.shared_state[\n            self.shared_storage_key\n        ] = self.aw1_registration_aeas\n        self.strategy.is_registered = False\n        self.strategy.is_registration_pending = False\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.register_behaviour.act()\n\n        # after\n        self.assert_quantity_in_outbox(len(self.aw1_registration_aeas))\n\n        assert self.strategy.is_registration_pending is True\n\n        # _register_for_aw1\n        info = self.strategy.registration_info\n        message = self.get_message_from_outbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=RegisterMessage,\n            performative=RegisterMessage.Performative.REGISTER,\n            to=self.aw1_registration_aea,\n            sender=self.skill.skill_context.agent_address,\n            info=info,\n        )\n        assert has_attributes, error_str\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"sending registration info: {info}\",\n        )\n\n    def test_act_vi(self):\n        \"\"\"Test the act method of the registration behaviour where aw1 agent is NOT in the whitelist.\"\"\"\n        # setup\n        self.strategy.is_ready_to_register = True\n        self.skill.skill_context.shared_state[\n            self.shared_storage_key\n        ] = self.aw1_registration_aeas\n        self.strategy.is_registered = False\n        self.strategy.is_registration_pending = False\n        self.strategy._whitelist = []\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.register_behaviour.act()\n\n        # after\n        self.assert_quantity_in_outbox(0)\n\n        assert self.strategy.is_registration_pending is True\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"agent={self.aw1_registration_aea} not in whitelist={self.strategy._whitelist}\",\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the registration behaviour.\"\"\"\n        assert self.register_behaviour.teardown() is None\n        self.assert_quantity_in_outbox(0)\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_registration_aw1/test_dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the dialogue classes of the registration_aw1 skill.\"\"\"\n\nfrom pathlib import Path\n\nfrom aea.helpers.transaction.base import RawTransaction, Terms\nfrom aea.test_tools.test_skill import COUNTERPARTY_AGENT_ADDRESS\n\nfrom packages.fetchai.protocols.register.message import RegisterMessage\nfrom packages.fetchai.protocols.signing.message import SigningMessage\nfrom packages.fetchai.skills.registration_aw1.dialogues import (\n    RegisterDialogue,\n    SigningDialogue,\n)\n\nfrom tests.conftest import ROOT_DIR\nfrom tests.test_packages.test_skills.test_registration_aw1.intermediate_class import (\n    RegiatrationAW1TestCase,\n)\n\n\nclass TestDialogues(RegiatrationAW1TestCase):\n    \"\"\"Test dialogue classes of registration_aw1.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"registration_aw1\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n\n    def test_register_dialogues(self):\n        \"\"\"Test the FipaDialogues class.\"\"\"\n        _, dialogue = self.register_dialogues.create(\n            counterparty=COUNTERPARTY_AGENT_ADDRESS,\n            performative=RegisterMessage.Performative.REGISTER,\n            info={\"some_key\": \"some_value\"},\n        )\n        assert dialogue.role == RegisterDialogue.Role.AGENT\n        assert dialogue.self_address == self.skill.skill_context.agent_address\n\n    def test_signing_dialogues(self):\n        \"\"\"Test the SigningDialogues class.\"\"\"\n        _, dialogue = self.signing_dialogues.create(\n            counterparty=COUNTERPARTY_AGENT_ADDRESS,\n            performative=SigningMessage.Performative.SIGN_TRANSACTION,\n            terms=Terms(\n                \"some_ledger_id\",\n                \"some_sender_address\",\n                \"some_counterparty_address\",\n                dict(),\n                dict(),\n                \"some_nonce\",\n            ),\n            raw_transaction=RawTransaction(\n                \"some_ledger_id\", {\"some_key\": \"some_value\"}\n            ),\n        )\n        assert dialogue.role == SigningDialogue.Role.SKILL\n        assert dialogue.self_address == str(self.skill.skill_context.skill_id)\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_registration_aw1/test_handlers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the handler classes of the registration_aw1 skill.\"\"\"\n\nimport logging\nfrom pathlib import Path\nfrom typing import cast\nfrom unittest.mock import patch\n\nfrom aea.helpers.transaction.base import Terms\nfrom aea.protocols.dialogue.base import DialogueMessage\n\nfrom packages.fetchai.protocols.register.message import RegisterMessage\nfrom packages.fetchai.protocols.signing.message import SigningMessage\nfrom packages.fetchai.skills.registration_aw1.dialogues import (\n    RegisterDialogue,\n    SigningDialogue,\n)\n\nfrom tests.conftest import ROOT_DIR\nfrom tests.test_packages.test_skills.test_registration_aw1.intermediate_class import (\n    RegiatrationAW1TestCase,\n)\n\n\nclass TestAW1RegistrationHandler(RegiatrationAW1TestCase):\n    \"\"\"Test registration handler of registration_aw1.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"registration_aw1\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n\n        cls.signature_of_ethereum_address = \"some_signature_of_ethereum_address\"\n        cls.info = {\n            \"ethereum_address\": cls.ethereum_address,\n            \"fetchai_address\": cls._skill.skill_context.agent_address,\n            \"signature_of_ethereum_address\": cls.signature_of_ethereum_address,\n            \"signature_of_fetchai_address\": cls.signature_of_fetchai_address,\n            \"developer_handle\": cls.developer_handle,\n            \"tweet\": cls.tweet,\n        }\n        cls.list_of_messages = (\n            DialogueMessage(RegisterMessage.Performative.REGISTER, {\"info\": cls.info}),\n        )\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the registration_aw1 handler.\"\"\"\n        assert self.register_handler.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle_unidentified_dialogue(self):\n        \"\"\"Test the _handle_unidentified_dialogue method of the registration_aw1 handler.\"\"\"\n        # setup\n        incorrect_dialogue_reference = (\"\", \"\")\n        incoming_message = self.build_incoming_message(\n            message_type=RegisterMessage,\n            dialogue_reference=incorrect_dialogue_reference,\n            performative=RegisterMessage.Performative.REGISTER,\n            info={\"some_key\": \"some_value\"},\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.register_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received invalid register_msg message={incoming_message}, unidentified dialogue.\",\n        )\n\n    def test_handle_success_i(self):\n        \"\"\"Test the _handle_success method of the registration_aw1 handler where announce_termination_key IS None.\"\"\"\n        # setup\n        self.strategy.announce_termination_key = None\n\n        register_dialogue = cast(\n            RegisterDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.register_dialogues,\n                messages=self.list_of_messages,\n                is_agent_to_agent_messages=True,\n            ),\n        )\n        incoming_message = cast(\n            RegisterMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=register_dialogue,\n                performative=RegisterMessage.Performative.SUCCESS,\n                info={\"transaction_digest\": \"some_transaction_digest\"},\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.register_handler.handle(incoming_message)\n\n        # after\n        self.assert_quantity_in_outbox(0)\n\n        mock_logger.assert_any_call(\n            logging.DEBUG,\n            f\"received register_msg success message={incoming_message} in dialogue={register_dialogue}.\",\n        )\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received register message success, info={incoming_message.info}. Stop me now!\",\n        )\n\n        assert self.strategy.is_registered is True\n        assert self.strategy.is_registration_pending is False\n        assert self.strategy.is_ready_to_register is False\n\n    def test_handle_success_ii(self):\n        \"\"\"Test the _handle_success method of the registration_aw1 handler where announce_termination_key is NOT None.\"\"\"\n        # setup\n        key = \"some_key\"\n        self.strategy.announce_termination_key = key\n\n        register_dialogue = cast(\n            RegisterDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.register_dialogues,\n                messages=self.list_of_messages,\n                is_agent_to_agent_messages=True,\n            ),\n        )\n        incoming_message = cast(\n            RegisterMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=register_dialogue,\n                performative=RegisterMessage.Performative.SUCCESS,\n                info={\"transaction_digest\": \"some_transaction_digest\"},\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.register_handler.handle(incoming_message)\n\n        # after\n        self.assert_quantity_in_outbox(0)\n\n        mock_logger.assert_any_call(\n            logging.DEBUG,\n            f\"received register_msg success message={incoming_message} in dialogue={register_dialogue}.\",\n        )\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received register message success, info={incoming_message.info}. Stop me now!\",\n        )\n\n        assert self.strategy.is_registered is True\n        assert self.strategy.is_registration_pending is False\n        assert self.strategy.is_ready_to_register is False\n\n        assert self.skill.skill_context.shared_state[key] is True\n\n    def test_handle_error(self):\n        \"\"\"Test the _handle_error method of the registration_aw1 handler.\"\"\"\n        # setup\n        register_dialogue = cast(\n            RegisterDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.register_dialogues,\n                messages=self.list_of_messages,\n                is_agent_to_agent_messages=True,\n            ),\n        )\n        incoming_message = cast(\n            RegisterMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=register_dialogue,\n                performative=RegisterMessage.Performative.ERROR,\n                error_code=1,\n                error_msg=\"some_error_msg\",\n                info={\"some_key\": \"some_value\"},\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.register_handler.handle(incoming_message)\n\n        # after\n        self.assert_quantity_in_outbox(0)\n\n        mock_logger.assert_any_call(\n            logging.DEBUG,\n            f\"received register_msg error message={incoming_message} in dialogue={register_dialogue}.\",\n        )\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received register message error, error_msg={incoming_message.error_msg}. Stop me now!\",\n        )\n\n        assert self.strategy.is_registration_pending is False\n        assert self.strategy.is_ready_to_register is False\n\n    def test_handle_invalid(self):\n        \"\"\"Test the _handle_invalid method of the registration_aw1 handler.\"\"\"\n        # setup\n        incoming_message = cast(\n            RegisterMessage,\n            self.build_incoming_message(\n                message_type=RegisterMessage,\n                performative=RegisterMessage.Performative.REGISTER,\n                info=self.info,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.register_handler.handle(incoming_message)\n\n        # after\n        self.assert_quantity_in_outbox(0)\n\n        register_dialogue = self.register_dialogues.get_dialogue(incoming_message)\n\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"cannot handle register_msg message of performative={incoming_message.performative} in dialogue={register_dialogue}.\",\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the registration_aw1 handler.\"\"\"\n        assert self.register_handler.teardown() is None\n        self.assert_quantity_in_outbox(0)\n\n\nclass TestSigningHandler(RegiatrationAW1TestCase):\n    \"\"\"Test signing handler of registration_aw1.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"registration_aw1\")\n    is_agent_to_agent_messages = False\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n\n        cls.ledger_id = \"some_ledger_id\"\n        cls.body_bytes = b\"some_body\"\n        cls.body_str = \"some_body\"\n        cls.terms = Terms(\n            \"some_ledger_id\",\n            cls._skill.skill_context.agent_address,\n            \"counterprty\",\n            {\"currency_id\": 50},\n            {\"good_id\": -10},\n            \"some_nonce\",\n        )\n        cls.list_of_signing_msg_messages = (\n            DialogueMessage(\n                SigningMessage.Performative.SIGN_MESSAGE,\n                {\n                    \"terms\": cls.terms,\n                    \"raw_message\": SigningMessage.RawMessage(\n                        cls.ledger_id, cls.body_bytes\n                    ),\n                },\n            ),\n        )\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the signing handler.\"\"\"\n        assert self.signing_handler.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle_unidentified_dialogue(self):\n        \"\"\"Test the _handle_unidentified_dialogue method of the signing handler.\"\"\"\n        # setup\n        incorrect_dialogue_reference = (\"\", \"\")\n        incoming_message = self.build_incoming_message(\n            message_type=SigningMessage,\n            dialogue_reference=incorrect_dialogue_reference,\n            performative=SigningMessage.Performative.ERROR,\n            error_code=SigningMessage.ErrorCode.UNSUCCESSFUL_MESSAGE_SIGNING,\n            to=str(self.skill.skill_context.skill_id),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.signing_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received invalid signing message={incoming_message}, unidentified dialogue.\",\n        )\n\n    def test_handle_signed_message(self):\n        \"\"\"Test the _handle_signed_message method of the signing handler.\"\"\"\n        # setup\n        signing_dialogue = cast(\n            SigningDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.signing_dialogues,\n                messages=self.list_of_signing_msg_messages[:1],\n                counterparty=self.skill.skill_context.decision_maker_address,\n            ),\n        )\n\n        incoming_message = cast(\n            SigningMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=signing_dialogue,\n                performative=SigningMessage.Performative.SIGNED_MESSAGE,\n                signed_message=SigningMessage.SignedMessage(\n                    self.ledger_id, self.body_str\n                ),\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.signing_handler.handle(incoming_message)\n\n        # after\n        self.assert_quantity_in_outbox(0)\n\n        mock_logger.assert_any_call(\n            logging.DEBUG,\n            f\"received signing message from decision maker, message={incoming_message} in dialogue={signing_dialogue}\",\n        )\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received signing message from decision maker, signature={incoming_message.signed_message.body} stored!\",\n        )\n\n        assert self.strategy.signature_of_ethereum_address == self.body_str\n        assert self.strategy.is_ready_to_register is True\n\n    def test_handle_error(self):\n        \"\"\"Test the _handle_error method of the signing handler.\"\"\"\n        # setup\n        signing_counterparty = self.skill.skill_context.decision_maker_address\n        signing_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.signing_dialogues,\n            messages=self.list_of_signing_msg_messages[:1],\n            counterparty=signing_counterparty,\n        )\n        incoming_message = cast(\n            SigningMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=signing_dialogue,\n                performative=SigningMessage.Performative.ERROR,\n                error_code=SigningMessage.ErrorCode.UNSUCCESSFUL_TRANSACTION_SIGNING,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.signing_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"transaction signing was not successful. Error_code={incoming_message.error_code} in dialogue={signing_dialogue}\",\n        )\n\n    def test_handle_invalid(self):\n        \"\"\"Test the _handle_invalid method of the signing handler.\"\"\"\n        # setup\n        invalid_performative = SigningMessage.Performative.SIGN_TRANSACTION\n        incoming_message = self.build_incoming_message(\n            message_type=SigningMessage,\n            dialogue_reference=(\"1\", \"\"),\n            performative=invalid_performative,\n            terms=self.terms,\n            raw_transaction=SigningMessage.RawTransaction(\n                \"some_ledger_id\", {\"some_key\": \"some_value\"}\n            ),\n            to=str(self.skill.skill_context.skill_id),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.signing_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"cannot handle signing message of performative={incoming_message.performative} in dialogue={self.signing_dialogues.get_dialogue(incoming_message)}.\",\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the signing handler.\"\"\"\n        assert self.signing_handler.teardown() is None\n        self.assert_quantity_in_outbox(0)\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_registration_aw1/test_strategy.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the strategy class of the registration_aw1 skill.\"\"\"\n\nfrom pathlib import Path\nfrom unittest.mock import patch\n\nfrom aea.crypto.ledger_apis import LedgerApis\n\nfrom packages.fetchai.skills.registration_aw1.strategy import Strategy\n\nfrom tests.conftest import ROOT_DIR\nfrom tests.test_packages.test_skills.test_registration_aw1.intermediate_class import (\n    RegiatrationAW1TestCase,\n)\n\n\nclass TestStrategy(RegiatrationAW1TestCase):\n    \"\"\"Test Strategy of registration_aw1.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"registration_aw1\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n\n    def test__init__i(self):\n        \"\"\"Test __init__ where developer_handle_only is False.\"\"\"\n        announce_termination_key = True\n        developer_handle_only = False\n\n        with patch.object(LedgerApis, \"is_valid_address\", return_value=True):\n            strategy = Strategy(\n                developer_handle=self.developer_handle,\n                ethereum_address=self.ethereum_address,\n                signature_of_fetchai_address=self.signature_of_fetchai_address,\n                shared_storage_key=self.shared_storage_key,\n                whitelist=self.whitelist,\n                tweet=self.tweet,\n                announce_termination_key=announce_termination_key,\n                developer_handle_only=developer_handle_only,\n                name=Strategy,\n                skill_context=self.skill.skill_context,\n            )\n        assert strategy._developer_handle == self.developer_handle\n        assert strategy._whitelist == self.whitelist\n        assert strategy._shared_storage_key == self.shared_storage_key\n        assert strategy.announce_termination_key == announce_termination_key\n        assert strategy.developer_handle_only == developer_handle_only\n\n        assert strategy._ethereum_address == self.ethereum_address\n        assert (\n            strategy._signature_of_fetchai_address == self.signature_of_fetchai_address\n        )\n        assert strategy._tweet == self.tweet\n        assert strategy._is_ready_to_register is False\n\n        assert strategy._is_registered is False\n        assert strategy.is_registration_pending is False\n        assert strategy.signature_of_ethereum_address is None\n        assert strategy._ledger_id == self.skill.skill_context.default_ledger_id\n\n    def test__init__ii(self):\n        \"\"\"Test __init__ where developer_handle_only is True.\"\"\"\n        announce_termination_key = False\n        developer_handle_only = True\n\n        strategy = Strategy(\n            developer_handle=self.developer_handle,\n            ethereum_address=self.ethereum_address,\n            signature_of_fetchai_address=self.signature_of_fetchai_address,\n            shared_storage_key=self.shared_storage_key,\n            whitelist=self.whitelist,\n            tweet=self.tweet,\n            announce_termination_key=announce_termination_key,\n            developer_handle_only=developer_handle_only,\n            name=Strategy,\n            skill_context=self.skill.skill_context,\n        )\n        assert strategy._developer_handle == self.developer_handle\n        assert strategy._whitelist == self.whitelist\n        assert strategy._shared_storage_key == self.shared_storage_key\n        assert strategy.announce_termination_key == announce_termination_key\n        assert strategy.developer_handle_only == developer_handle_only\n\n        assert strategy._is_ready_to_register is True\n        assert strategy._ethereum_address == \"some_dummy_address\"\n        assert strategy._signature_of_fetchai_address is None\n        assert strategy._tweet is None\n\n        assert strategy._is_registered is False\n        assert strategy.is_registration_pending is False\n        assert strategy.signature_of_ethereum_address is None\n        assert strategy._ledger_id == self.skill.skill_context.default_ledger_id\n\n    def test_properties(self):\n        \"\"\"Test the properties of Strategy class.\"\"\"\n        assert self.strategy.shared_storage_key == self.shared_storage_key\n        assert self.strategy.whitelist == self.whitelist\n        assert self.strategy.ethereum_address == self.ethereum_address\n        assert self.strategy.ledger_id == self.skill.skill_context.default_ledger_id\n\n        assert self.strategy.is_registration_pending is False\n        assert self.strategy.signature_of_ethereum_address is None\n\n        assert self.strategy.is_ready_to_register is False\n        self.strategy.is_ready_to_register = True\n        assert self.strategy.is_ready_to_register is True\n\n        assert self.strategy.is_registered is False\n        self.strategy.is_registered = True\n        assert self.strategy.is_registered is True\n\n        info_i = {\n            \"ethereum_address\": self.ethereum_address,\n            \"fetchai_address\": self.skill.skill_context.agent_address,\n            \"signature_of_ethereum_address\": self.strategy.signature_of_ethereum_address,\n            \"signature_of_fetchai_address\": self.signature_of_fetchai_address,\n            \"developer_handle\": self.developer_handle,\n            \"tweet\": self.tweet,\n        }\n        assert self.strategy.registration_info == info_i\n\n        self.strategy._tweet = \"PUT_THE_LINK_TO_YOUR_TWEET_HERE\"\n        info_ii = {\n            \"ethereum_address\": self.ethereum_address,\n            \"fetchai_address\": self.skill.skill_context.agent_address,\n            \"signature_of_ethereum_address\": self.strategy.signature_of_ethereum_address,\n            \"signature_of_fetchai_address\": self.signature_of_fetchai_address,\n            \"developer_handle\": self.developer_handle,\n        }\n        assert self.strategy.registration_info == info_ii\n\n        info_iii = {\n            \"fetchai_address\": self.skill.skill_context.agent_address,\n            \"developer_handle\": self.developer_handle,\n        }\n        self.strategy.developer_handle_only = True\n        assert self.strategy.registration_info == info_iii\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_simple_aggregation/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"The tests module contains the tests of the packages/skills/simple_aggregation dir.\"\"\"\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_simple_aggregation/test_behaviours.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the behaviour classes of the advanced data request skill.\"\"\"\n\nimport logging\nfrom pathlib import Path\nfrom typing import cast\nfrom unittest.mock import patch\n\nfrom aea_ledger_fetchai import FetchAICrypto\n\nfrom aea.helpers.search.models import Description\nfrom aea.test_tools.test_skill import BaseSkillTestCase\n\nfrom packages.fetchai.protocols.aggregation.message import AggregationMessage\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.skills.simple_aggregation.behaviours import (\n    AggregationBehaviour,\n    DEFAULT_SIGNATURE,\n    DEFAULT_SOURCE,\n    SearchBehaviour,\n)\nfrom packages.fetchai.skills.simple_aggregation.strategy import AggregationStrategy\n\nfrom tests.conftest import ROOT_DIR\n\n\nDATA_REQUEST_OBS = {\"some_quantity\": {\"value\": 100, \"decimals\": 0}}\nOBSERVATION = {\n    \"value\": 100,\n    \"time\": \"some_time\",\n    \"signature\": DEFAULT_SIGNATURE,\n    \"source\": DEFAULT_SOURCE,\n}\nLEDGER_ID = FetchAICrypto.identifier\nPEERS = (\"peer1\", \"peer2\")\n\n\nclass TestAggregationBehaviour(BaseSkillTestCase):\n    \"\"\"Test aggregation behaviour of simple aggregation skill.\"\"\"\n\n    path_to_skill = Path(\n        ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"simple_aggregation\"\n    )\n\n    @classmethod\n    def setup(cls, **kwargs):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.aggregation_behaviour = cast(\n            AggregationBehaviour,\n            cls._skill.skill_context.behaviours.aggregation,\n        )\n        cls.aggregation_strategy = cast(\n            AggregationStrategy,\n            cls.aggregation_behaviour.context.strategy,\n        )\n        cls.aggregation_strategy.url = \"some_url\"\n        cls.aggregation_strategy._quantity_name = \"some_quantity\"\n        cls.agent_address = cls.aggregation_behaviour.context.agent_addresses[LEDGER_ID]\n\n    def test_act(self):\n        \"\"\"Test the act method of the aggregation behaviour.\"\"\"\n\n        with patch.object(\n            self.aggregation_behaviour.context.logger, \"log\"\n        ) as mock_logger:\n            self.aggregation_behaviour.act()\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            \"No observation to send\",\n        )\n        self.assert_quantity_in_outbox(0)\n\n        # mock an observation\n        self.aggregation_behaviour.context.shared_state[\n            \"some_quantity\"\n        ] = DATA_REQUEST_OBS[\"some_quantity\"]\n\n        self.aggregation_strategy.add_peers(PEERS)\n        assert all([peer in self.aggregation_strategy.peers for peer in PEERS])\n\n        with patch.object(\n            self.aggregation_behaviour.context.logger, \"log\"\n        ) as mock_logger:\n            self.aggregation_behaviour.act()\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"sending observation to peer={PEERS[0]}\",\n        )\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"sending observation to peer={PEERS[1]}\",\n        )\n\n        obs = self.aggregation_strategy.observation\n        assert obs[\"value\"] == OBSERVATION[\"value\"]\n\n        # test broadcast_observation\n        self.assert_quantity_in_outbox(2)\n        msg = cast(AggregationMessage, self.get_message_from_outbox())\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=msg,\n            message_type=AggregationMessage,\n            performative=AggregationMessage.Performative.OBSERVATION,\n            value=100,\n            source=DEFAULT_SOURCE,\n            signature=DEFAULT_SIGNATURE,\n        )\n        assert has_attributes, error_str\n\n\nclass TestSearchBehaviour(BaseSkillTestCase):\n    \"\"\"Test search behaviour of simple aggregation skill.\"\"\"\n\n    path_to_skill = Path(\n        ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"simple_aggregation\"\n    )\n\n    @classmethod\n    def setup(cls, **kwargs):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.search_behaviour = cast(\n            SearchBehaviour,\n            cls._skill.skill_context.behaviours.search,\n        )\n        cls.aggregation_strategy = cast(\n            AggregationStrategy,\n            cls.search_behaviour.context.strategy,\n        )\n        cls.aggregation_strategy.url = \"some_url\"\n        cls.aggregation_strategy._quantity_name = \"some_quantity\"\n        cls.agent_address = cls.search_behaviour.context.agent_addresses[LEDGER_ID]\n        cls.logger = cls._skill.skill_context.logger\n\n        cls.registration_message = OefSearchMessage(\n            dialogue_reference=(\"\", \"\"),\n            performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n            service_description=\"some_service_description\",\n        )\n        cls.registration_message.sender = str(cls._skill.skill_context.skill_id)\n        cls.registration_message.to = cls._skill.skill_context.search_service_address\n\n        cls.mocked_description = Description({\"foo1\": 1, \"bar1\": 2})\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the search behaviour.\"\"\"\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.search_behaviour.setup()\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            \"registering agent on SOEF.\",\n        )\n\n        description = self.aggregation_strategy.get_location_description()\n\n        # test SOEF messages\n        self.assert_quantity_in_outbox(1)\n        msg = cast(OefSearchMessage, self.get_message_from_outbox())\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=msg,\n            message_type=OefSearchMessage,\n            performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n            service_description=description,\n        )\n        assert has_attributes, error_str\n\n    def test_act_i(self):\n        \"\"\"Test the act method of the search behaviour where failed_registration_msg IS None.\"\"\"\n\n        query = self.aggregation_strategy.get_location_and_service_query()\n\n        self.search_behaviour.act()\n\n        # test SOEF search query\n        self.assert_quantity_in_outbox(1)\n        msg = cast(OefSearchMessage, self.get_message_from_outbox())\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=msg,\n            message_type=OefSearchMessage,\n            performative=OefSearchMessage.Performative.SEARCH_SERVICES,\n            query=query,\n        )\n        assert has_attributes, error_str\n\n    def test_act_ii(self):\n        \"\"\"Test the act method of the service_registration behaviour where failed_registration_msg is NOT None.\"\"\"\n        # setup\n        self.search_behaviour.failed_registration_msg = self.registration_message\n        query = self.aggregation_strategy.get_location_and_service_query()\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.search_behaviour.act()\n\n        # after\n        self.assert_quantity_in_outbox(2)\n\n        # _retry_failed_registration\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=type(self.registration_message),\n            performative=self.registration_message.performative,\n            to=self.registration_message.to,\n            sender=str(self.skill.skill_context.skill_id),\n            service_description=self.registration_message.service_description,\n        )\n        assert has_attributes, error_str\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"Retrying registration on SOEF. Retry {self.search_behaviour._nb_retries} out of {self.search_behaviour._max_soef_registration_retries}.\",\n        )\n        assert self.search_behaviour.failed_registration_msg is None\n\n        # act\n        msg = cast(OefSearchMessage, self.get_message_from_outbox())\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=msg,\n            message_type=OefSearchMessage,\n            performative=OefSearchMessage.Performative.SEARCH_SERVICES,\n            query=query,\n        )\n        assert has_attributes, error_str\n\n    def test_act_iii(self):\n        \"\"\"Test the act method of the service_registration behaviour where failed_registration_msg is NOT None and max retries is reached.\"\"\"\n        # setup\n        self.search_behaviour.failed_registration_msg = self.registration_message\n        self.search_behaviour._max_soef_registration_retries = 2\n        self.search_behaviour._nb_retries = 2\n\n        query = self.aggregation_strategy.get_location_and_service_query()\n\n        # operation\n        self.search_behaviour.act()\n\n        # after\n        self.assert_quantity_in_outbox(1)\n        msg = cast(OefSearchMessage, self.get_message_from_outbox())\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=msg,\n            message_type=OefSearchMessage,\n            performative=OefSearchMessage.Performative.SEARCH_SERVICES,\n            query=query,\n        )\n        assert has_attributes, error_str\n\n        assert self.skill.skill_context.is_active is False\n\n    def test_register_service(self):\n        \"\"\"Test the register_service method of the service_registration behaviour.\"\"\"\n        # operation\n        with patch.object(\n            self.aggregation_strategy,\n            \"get_register_service_description\",\n            return_value=self.mocked_description,\n        ):\n            with patch.object(self.logger, \"log\") as mock_logger:\n                self.search_behaviour.register_service()\n\n        # after\n        self.assert_quantity_in_outbox(1)\n\n        message = self.get_message_from_outbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=OefSearchMessage,\n            performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n            to=self.skill.skill_context.search_service_address,\n            sender=str(self.skill.skill_context.skill_id),\n            service_description=self.mocked_description,\n        )\n        assert has_attributes, error_str\n        mock_logger.assert_any_call(\n            logging.INFO, \"registering agent's service on the SOEF.\"\n        )\n\n    def test_register_genus(self):\n        \"\"\"Test the register_genus method of the service_registration behaviour.\"\"\"\n        # operation\n        with patch.object(\n            self.aggregation_strategy,\n            \"get_register_personality_description\",\n            return_value=self.mocked_description,\n        ):\n            with patch.object(self.logger, \"log\") as mock_logger:\n                self.search_behaviour.register_genus()\n\n        # after\n        self.assert_quantity_in_outbox(1)\n\n        message = self.get_message_from_outbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=OefSearchMessage,\n            performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n            to=self.skill.skill_context.search_service_address,\n            sender=str(self.skill.skill_context.skill_id),\n            service_description=self.mocked_description,\n        )\n        assert has_attributes, error_str\n        mock_logger.assert_any_call(\n            logging.INFO, \"registering agent's personality genus on the SOEF.\"\n        )\n\n    def test_register_classification(self):\n        \"\"\"Test the register_classification method of the service_registration behaviour.\"\"\"\n        # operation\n        with patch.object(\n            self.aggregation_strategy,\n            \"get_register_classification_description\",\n            return_value=self.mocked_description,\n        ):\n            with patch.object(self.logger, \"log\") as mock_logger:\n                self.search_behaviour.register_classification()\n\n        # after\n        self.assert_quantity_in_outbox(1)\n\n        message = self.get_message_from_outbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=OefSearchMessage,\n            performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n            to=self.skill.skill_context.search_service_address,\n            sender=str(self.skill.skill_context.skill_id),\n            service_description=self.mocked_description,\n        )\n        assert has_attributes, error_str\n        mock_logger.assert_any_call(\n            logging.INFO, \"registering agent's personality classification on the SOEF.\"\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the search behaviour.\"\"\"\n\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.search_behaviour.teardown()\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            \"unregistering agent from SOEF.\",\n        )\n        mock_logger.assert_any_call(\n            logging.INFO,\n            \"unregistering service from SOEF.\",\n        )\n\n        descriptions = [\n            self.aggregation_strategy.get_unregister_service_description(),\n            self.aggregation_strategy.get_location_description(),\n        ]\n\n        # test SOEF messages\n        self.assert_quantity_in_outbox(len(descriptions))\n        for description in descriptions:\n            msg = cast(OefSearchMessage, self.get_message_from_outbox())\n            has_attributes, error_str = self.message_has_attributes(\n                actual_message=msg,\n                message_type=OefSearchMessage,\n                performative=OefSearchMessage.Performative.UNREGISTER_SERVICE,\n                service_description=description,\n            )\n            assert has_attributes, error_str\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_simple_aggregation/test_handlers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the handler classes of the simple_data_request skill.\"\"\"\n\nimport logging\nimport statistics\nfrom pathlib import Path\nfrom typing import cast\nfrom unittest.mock import patch\n\nfrom aea.helpers.search.models import Attribute, DataModel, Description, Location\nfrom aea.protocols.dialogue.base import DialogueMessage\nfrom aea.test_tools.test_skill import BaseSkillTestCase\n\nfrom packages.fetchai.protocols.aggregation.message import AggregationMessage\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.skills.simple_aggregation.behaviours import (\n    DEFAULT_SIGNATURE,\n    DEFAULT_SOURCE,\n    SearchBehaviour,\n)\nfrom packages.fetchai.skills.simple_aggregation.dialogues import (\n    AggregationDialogues,\n    OefSearchDialogues,\n)\nfrom packages.fetchai.skills.simple_aggregation.handlers import (\n    AggregationHandler,\n    OefSearchHandler,\n    get_observation_from_message,\n)\nfrom packages.fetchai.skills.simple_aggregation.strategy import AggregationStrategy\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass TestAggregationHandler(BaseSkillTestCase):\n    \"\"\"Test aggregation handler of simple_aggregation skill.\"\"\"\n\n    path_to_skill = Path(\n        ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"simple_aggregation\"\n    )\n    is_agent_to_agent_messages = False\n\n    @classmethod\n    def setup(cls, **kwargs):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.aggregation_handler = cast(\n            AggregationHandler, cls._skill.skill_context.handlers.aggregation\n        )\n        cls.logger = cls._skill.skill_context.logger\n\n        cls.aggregation_strategy = cast(\n            AggregationStrategy,\n            cls._skill.skill_context.strategy,\n        )\n\n        cls.aggregation_dialogues = cast(\n            AggregationDialogues, cls._skill.skill_context.aggregation_dialogues\n        )\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the aggregation handler.\"\"\"\n        assert self.aggregation_handler.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle_observation(self):\n        \"\"\"Test the _handle_observation method of the aggregation handler to a valid observation.\"\"\"\n\n        self.aggregation_strategy._quantity_name = \"some_quantity\"\n\n        sender = \"some_sender_address\"\n        sender_value = 100\n        my_value = 50\n        values = [float(my_value), float(sender_value)]\n        aggregate = getattr(statistics, self.aggregation_strategy._aggregation_function)\n        incoming_message = self.build_incoming_message(\n            message_type=AggregationMessage,\n            performative=AggregationMessage.Performative.OBSERVATION,\n            sender=sender,\n            to=self._skill.skill_context.agent_address,\n            value=sender_value,\n            time=\"some_time\",\n            source=DEFAULT_SOURCE,\n            signature=DEFAULT_SIGNATURE,\n        )\n\n        self.aggregation_strategy.add_peers((sender,))\n        assert sender in self.aggregation_strategy._peers\n\n        self.aggregation_strategy.make_observation(my_value, \"some_time\")\n\n        # handle message with logging\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.aggregation_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO, f\"received observation from sender={sender[-5:]}\"\n        )\n\n        expected_aggregation = {\"value\": aggregate(values), \"decimals\": 0}\n        aggregated_key = (\n            \"some_quantity\" + \"_\" + self.aggregation_strategy._aggregation_function\n        )\n\n        obs = get_observation_from_message(incoming_message)\n        assert len(self.aggregation_strategy._observations) == 2\n        assert self.aggregation_strategy._observations[sender] == obs\n        assert self.aggregation_strategy._aggregation == aggregate(values)\n        assert (\n            self.aggregation_handler.context.shared_state[aggregated_key]\n            == expected_aggregation\n        )\n\n        mock_logger.assert_any_call(logging.INFO, f\"Observations: {values}\")\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"Aggregation ({self.aggregation_strategy._aggregation_function}): {self.aggregation_strategy._aggregation}\",\n        )\n\n    def test_handle_aggregation(self):\n        \"\"\"Test the _handle_aggregation method of the aggregation handler to a valid aggregation.\"\"\"\n\n        sender = \"some_sender_address\"\n        sender_value = 75\n        incoming_message = self.build_incoming_message(\n            message_type=AggregationMessage,\n            performative=AggregationMessage.Performative.AGGREGATION,\n            sender=sender,\n            to=self._skill.skill_context.agent_address,\n            value=sender_value,\n            time=\"some_time\",\n            contributors=(sender, \"some_other_peer\"),\n            signature=DEFAULT_SIGNATURE,\n        )\n\n        # handle message with logging\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.aggregation_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO, f\"received aggregation from sender={sender[-5:]}\"\n        )\n\n    def test_handle_unidentified_dialogue(self):\n        \"\"\"Test the _handle_response method of the aggregation handler to an unidentified dialogue.\"\"\"\n        # setup\n        incoming_message = self.build_incoming_message(\n            message_type=OefSearchMessage,\n            performative=OefSearchMessage.Performative.SEARCH_SERVICES,\n            query=self.aggregation_strategy.get_location_and_service_query(),\n            sender=\"some_sender\",\n            to=self._skill.skill_context.agent_address,\n        )\n\n        # handle message with logging\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.aggregation_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received invalid aggregation message={incoming_message}, unidentified dialogue.\",\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the aggregation handler.\"\"\"\n        assert self.aggregation_handler.teardown() is None\n        self.assert_quantity_in_outbox(0)\n\n\nclass TestOefSearchHandler(BaseSkillTestCase):\n    \"\"\"Test oef search handler of simple aggregation skill.\"\"\"\n\n    path_to_skill = Path(\n        ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"simple_aggregation\"\n    )\n    is_agent_to_agent_messages = False\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.oef_search_handler = cast(\n            OefSearchHandler, cls._skill.skill_context.handlers.oef_search\n        )\n        cls.strategy = cast(\n            AggregationStrategy,\n            cls._skill.skill_context.strategy,\n        )\n        cls.oef_dialogues = cast(\n            OefSearchDialogues, cls._skill.skill_context.oef_search_dialogues\n        )\n        cls.service_registration_behaviour = cast(\n            SearchBehaviour,\n            cls._skill.skill_context.behaviours.search,\n        )\n\n        cls.register_location_description = Description(\n            {\"location\": Location(51.5194, 0.1270)},\n            data_model=DataModel(\n                \"location_agent\", [Attribute(\"location\", Location, True)]\n            ),\n        )\n        cls.list_of_messages_register_location = (\n            DialogueMessage(\n                OefSearchMessage.Performative.REGISTER_SERVICE,\n                {\"service_description\": cls.register_location_description},\n                is_incoming=False,\n            ),\n        )\n\n        cls.register_service_description = Description(\n            {\"key\": \"some_key\", \"value\": \"some_value\"},\n            data_model=DataModel(\n                \"set_service_key\",\n                [Attribute(\"key\", str, True), Attribute(\"value\", str, True)],\n            ),\n        )\n        cls.list_of_messages_register_service = (\n            DialogueMessage(\n                OefSearchMessage.Performative.REGISTER_SERVICE,\n                {\"service_description\": cls.register_service_description},\n                is_incoming=False,\n            ),\n        )\n\n        cls.register_genus_description = Description(\n            {\"piece\": \"genus\", \"value\": \"some_value\"},\n            data_model=DataModel(\n                \"personality_agent\",\n                [Attribute(\"piece\", str, True), Attribute(\"value\", str, True)],\n            ),\n        )\n        cls.list_of_messages_register_genus = (\n            DialogueMessage(\n                OefSearchMessage.Performative.REGISTER_SERVICE,\n                {\"service_description\": cls.register_genus_description},\n                is_incoming=False,\n            ),\n        )\n\n        cls.register_classification_description = Description(\n            {\"piece\": \"classification\", \"value\": \"some_value\"},\n            data_model=DataModel(\n                \"personality_agent\",\n                [Attribute(\"piece\", str, True), Attribute(\"value\", str, True)],\n            ),\n        )\n        cls.list_of_messages_register_classification = (\n            DialogueMessage(\n                OefSearchMessage.Performative.REGISTER_SERVICE,\n                {\"service_description\": cls.register_classification_description},\n                is_incoming=False,\n            ),\n        )\n\n        cls.register_invalid_description = Description(\n            {\"piece\": \"classification\", \"value\": \"some_value\"},\n            data_model=DataModel(\n                \"some_different_name\",\n                [Attribute(\"piece\", str, True), Attribute(\"value\", str, True)],\n            ),\n        )\n        cls.list_of_messages_register_invalid = (\n            DialogueMessage(\n                OefSearchMessage.Performative.REGISTER_SERVICE,\n                {\"service_description\": cls.register_invalid_description},\n                is_incoming=False,\n            ),\n        )\n\n        cls.unregister_description = Description(\n            {\"key\": \"seller_service\"},\n            data_model=DataModel(\"remove\", [Attribute(\"key\", str, True)]),\n        )\n        cls.list_of_messages_unregister = (\n            DialogueMessage(\n                OefSearchMessage.Performative.UNREGISTER_SERVICE,\n                {\"service_description\": cls.unregister_description},\n                is_incoming=False,\n            ),\n        )\n\n        cls.list_of_messages_search = (\n            DialogueMessage(\n                OefSearchMessage.Performative.SEARCH_SERVICES,\n                {\"query\": cls.strategy.get_location_and_service_query()},\n                is_incoming=False,\n            ),\n        )\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the oef_search handler.\"\"\"\n        assert self.oef_search_handler.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle_unidentified_dialogue(self):\n        \"\"\"Test the _handle_unidentified_dialogue method of the oef_search handler.\"\"\"\n        # setup\n        incorrect_dialogue_reference = (\"\", \"\")\n        incoming_message = self.build_incoming_message(\n            message_type=OefSearchMessage,\n            dialogue_reference=incorrect_dialogue_reference,\n            performative=OefSearchMessage.Performative.SEARCH_SERVICES,\n            query=self.strategy.get_location_and_service_query(),\n        )\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received invalid oef_search message={incoming_message}, unidentified dialogue.\",\n        )\n\n    def test_handle_success_i(self):\n        \"\"\"Test the _handle_success method of the oef_search handler where the oef success targets register_service WITH location_agent data model description.\"\"\"\n        # setup\n        oef_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_dialogues,\n            messages=self.list_of_messages_register_location[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=oef_dialogue,\n            performative=OefSearchMessage.Performative.SUCCESS,\n            agents_info=OefSearchMessage.AgentsInfo({\"address\": {\"key\": \"value\"}}),\n        )\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            with patch.object(\n                self.service_registration_behaviour,\n                \"register_service\",\n            ) as mock_reg:\n                self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received oef_search success message={incoming_message} in dialogue={oef_dialogue}.\",\n        )\n        mock_reg.assert_called_once()\n\n    def test_handle_success_ii(self):\n        \"\"\"Test the _handle_success method of the oef_search handler where the oef success targets register_service WITH set_service_key data model description.\"\"\"\n        # setup\n        oef_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_dialogues,\n            messages=self.list_of_messages_register_service[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=oef_dialogue,\n            performative=OefSearchMessage.Performative.SUCCESS,\n            agents_info=OefSearchMessage.AgentsInfo({\"address\": {\"key\": \"value\"}}),\n        )\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            with patch.object(\n                self.service_registration_behaviour,\n                \"register_genus\",\n            ) as mock_reg:\n                self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received oef_search success message={incoming_message} in dialogue={oef_dialogue}.\",\n        )\n        mock_reg.assert_called_once()\n\n    def test_handle_success_iii(self):\n        \"\"\"Test the _handle_success method of the oef_search handler where the oef success targets register_service WITH personality_agent data model and genus value description.\"\"\"\n        # setup\n        oef_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_dialogues,\n            messages=self.list_of_messages_register_genus[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=oef_dialogue,\n            performative=OefSearchMessage.Performative.SUCCESS,\n            agents_info=OefSearchMessage.AgentsInfo({\"address\": {\"key\": \"value\"}}),\n        )\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            with patch.object(\n                self.service_registration_behaviour,\n                \"register_classification\",\n            ) as mock_reg:\n                self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received oef_search success message={incoming_message} in dialogue={oef_dialogue}.\",\n        )\n        mock_reg.assert_called_once()\n\n    def test_handle_success_iv(self):\n        \"\"\"Test the _handle_success method of the oef_search handler where the oef success targets register_service WITH personality_agent data model and classification value description.\"\"\"\n        # setup\n        oef_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_dialogues,\n            messages=self.list_of_messages_register_classification[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=oef_dialogue,\n            performative=OefSearchMessage.Performative.SUCCESS,\n            agents_info=OefSearchMessage.AgentsInfo({\"address\": {\"key\": \"value\"}}),\n        )\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received oef_search success message={incoming_message} in dialogue={oef_dialogue}.\",\n        )\n        mock_logger.assert_any_call(\n            logging.INFO,\n            \"the agent, with its genus and classification, and its service are successfully registered on the SOEF.\",\n        )\n\n    def test_handle_success_v(self):\n        \"\"\"Test the _handle_success method of the oef_search handler where the oef successtargets unregister_service.\"\"\"\n        # setup\n        oef_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_dialogues,\n            messages=self.list_of_messages_register_invalid[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=oef_dialogue,\n            performative=OefSearchMessage.Performative.SUCCESS,\n            agents_info=OefSearchMessage.AgentsInfo({\"address\": {\"key\": \"value\"}}),\n        )\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received oef_search success message={incoming_message} in dialogue={oef_dialogue}.\",\n        )\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"received soef SUCCESS message as a reply to the following unexpected message: {oef_dialogue.get_message_by_id(incoming_message.target)}\",\n        )\n\n    def test_handle_error_i(self):\n        \"\"\"Test the _handle_error method of the oef_search handler where the oef error targets register_service.\"\"\"\n        # setup\n        oef_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_dialogues,\n            messages=self.list_of_messages_register_location[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=oef_dialogue,\n            performative=OefSearchMessage.Performative.OEF_ERROR,\n            oef_error_operation=OefSearchMessage.OefErrorOperation.SEARCH_SERVICES,\n        )\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        self.assert_quantity_in_outbox(0)\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received oef_search error message={incoming_message} in dialogue={oef_dialogue}.\",\n        )\n        assert (\n            self.service_registration_behaviour.failed_registration_msg\n            == oef_dialogue.get_message_by_id(incoming_message.target)\n        )\n\n    def test_handle_error_ii(self):\n        \"\"\"Test the _handle_error method of the oef_search handler where the oef error does NOT target register_service.\"\"\"\n        # setup\n        oef_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_dialogues,\n            messages=self.list_of_messages_unregister[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=oef_dialogue,\n            performative=OefSearchMessage.Performative.OEF_ERROR,\n            oef_error_operation=OefSearchMessage.OefErrorOperation.SEARCH_SERVICES,\n        )\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        self.assert_quantity_in_outbox(0)\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received oef_search error message={incoming_message} in dialogue={oef_dialogue}.\",\n        )\n\n        assert self.service_registration_behaviour.failed_registration_msg is None\n\n    def test_handle_search_no_agents(self):\n        \"\"\"Test the _handle_search method of the oef_search handler.\"\"\"\n        # setup\n        oef_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_dialogues,\n            messages=self.list_of_messages_search[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=oef_dialogue,\n            performative=OefSearchMessage.Performative.SEARCH_RESULT,\n            agents=tuple(),\n            agents_info=OefSearchMessage.AgentsInfo({}),\n        )\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"found no agents in dialogue={oef_dialogue}, continue searching.\",\n        )\n\n    def test_handle_search_found_agents(self):\n        \"\"\"Test the _handle_search method of the oef_search handler.\"\"\"\n        # setup\n        oef_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_dialogues,\n            messages=self.list_of_messages_search[:1],\n        )\n        agents = (\"agnt1\", \"agnt2\")\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=oef_dialogue,\n            performative=OefSearchMessage.Performative.SEARCH_RESULT,\n            agents=agents,\n            agents_info=OefSearchMessage.AgentsInfo(\n                {\"agent_1\": {\"key_1\": \"value_1\"}, \"agent_2\": {\"key_2\": \"value_2\"}}\n            ),\n        )\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(logging.INFO, f\"found agents={list(agents)}.\")\n\n        assert len(self.strategy._peers) == 2\n        for agent in agents:\n            assert agent in self.strategy._peers\n\n    def test_handle_invalid(self):\n        \"\"\"Test the _handle_invalid method of the oef_search handler.\"\"\"\n        # setup\n        invalid_performative = OefSearchMessage.Performative.UNREGISTER_SERVICE\n        incoming_message = self.build_incoming_message(\n            message_type=OefSearchMessage,\n            dialogue_reference=(\"1\", \"\"),\n            performative=invalid_performative,\n            service_description=self.strategy.get_unregister_service_description(),\n        )\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"cannot handle oef_search message of performative={invalid_performative} in dialogue={self.oef_dialogues.get_dialogue(incoming_message)}.\",\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the oef_search handler.\"\"\"\n        assert self.oef_search_handler.teardown() is None\n        self.assert_quantity_in_outbox(0)\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_simple_aggregation/test_strategy.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the strategy class of the simple_aggregation skill.\"\"\"\n\nfrom pathlib import Path\nfrom typing import cast\n\nfrom aea.helpers.search.models import Description\nfrom aea.test_tools.test_skill import BaseSkillTestCase\n\nfrom packages.fetchai.skills.simple_aggregation.strategy import (\n    AGENT_PERSONALITY_MODEL,\n    AGENT_REMOVE_SERVICE_MODEL,\n    AGENT_SET_SERVICE_MODEL,\n    AggregationStrategy,\n)\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass TestAggregationStrategy(BaseSkillTestCase):\n    \"\"\"Test AggregationStrategy of simple_aggregation.\"\"\"\n\n    path_to_skill = Path(\n        ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"simple_aggregation\"\n    )\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.strategy = cast(AggregationStrategy, cls._skill.skill_context.strategy)\n\n    def test_get_register_service_description(self):\n        \"\"\"Test the get_register_service_description method of the GenericStrategy class.\"\"\"\n        description = self.strategy.get_register_service_description()\n\n        assert type(description) == Description\n        assert description.data_model is AGENT_SET_SERVICE_MODEL\n        assert description.values.get(\"key\", \"\") == \"service\"\n        assert description.values.get(\"value\", \"\") == \"generic_aggregation_service\"\n\n    def test_get_register_personality_description(self):\n        \"\"\"Test the get_register_personality_description method of the GenericStrategy class.\"\"\"\n        description = self.strategy.get_register_personality_description()\n\n        assert type(description) == Description\n        assert description.data_model is AGENT_PERSONALITY_MODEL\n        assert description.values.get(\"piece\", \"\") == \"genus\"\n        assert description.values.get(\"value\", \"\") == \"data\"\n\n    def test_get_register_classification_description(self):\n        \"\"\"Test the get_register_classification_description method of the GenericStrategy class.\"\"\"\n        description = self.strategy.get_register_classification_description()\n\n        assert type(description) == Description\n        assert description.data_model is AGENT_PERSONALITY_MODEL\n        assert description.values.get(\"piece\", \"\") == \"classification\"\n        assert description.values.get(\"value\", \"\") == \"agent\"\n\n    def test_get_unregister_service_description(self):\n        \"\"\"Test the get_unregister_service_description method of the GenericStrategy class.\"\"\"\n        description = self.strategy.get_unregister_service_description()\n\n        assert type(description) == Description\n        assert description.data_model is AGENT_REMOVE_SERVICE_MODEL\n        assert description.values.get(\"key\", \"\") == \"service\"\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_simple_buyer/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"The tests module contains the tests of the packages/skills/simple_buyer dir.\"\"\"\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_simple_data_request/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"The tests module contains the tests of the packages/skills/simple_data_request dir.\"\"\"\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_simple_data_request/intermediate_class.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the behaviour classes of the simple_data_request skill.\"\"\"\nfrom pathlib import Path\n\nfrom aea.test_tools.test_skill import BaseSkillTestCase\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass SimpleDataRequestTestCase(BaseSkillTestCase):\n    \"\"\"Sets the simple_data_request class up for testing (overrides the necessary config values so tests can be done on simple_data_request skill).\"\"\"\n\n    path_to_skill = Path(\n        ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"simple_data_request\"\n    )\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        cls.mocked_method = \"some_method\"\n        cls.mocked_url = \"some_url\"\n        cls.mocked_shared_state_key = \"some_name_for_data\"\n\n        config_overrides = {\n            \"behaviours\": {\n                \"http_request\": {\n                    \"args\": {\"method\": cls.mocked_method, \"url\": cls.mocked_url}\n                }\n            },\n            \"handlers\": {\n                \"http\": {\"args\": {\"shared_state_key\": cls.mocked_shared_state_key}}\n            },\n        }\n\n        super().setup(config_overrides=config_overrides)\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_simple_data_request/test_behaviours.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the behaviour classes of the simple_data_request skill.\"\"\"\n\nimport json\nfrom typing import cast\n\nimport pytest\n\nfrom packages.fetchai.protocols.http.message import HttpMessage\nfrom packages.fetchai.skills.simple_data_request.behaviours import (\n    HTTP_CLIENT_PUBLIC_ID,\n    HttpRequestBehaviour,\n)\n\nfrom tests.test_packages.test_skills.test_simple_data_request.intermediate_class import (\n    SimpleDataRequestTestCase,\n)\n\n\nclass TestHttpRequestBehaviour(SimpleDataRequestTestCase):\n    \"\"\"Test http_request behaviour of http_request.\"\"\"\n\n    is_agent_to_agent_messages = False\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.http_request_behaviour = cast(\n            HttpRequestBehaviour, cls._skill.skill_context.behaviours.http_request\n        )\n\n    def test__init__i(self):\n        \"\"\"Test the __init__ method of the http_request behaviour.\"\"\"\n        assert self.http_request_behaviour.url == \"some_url\"\n        assert self.http_request_behaviour.method == \"some_method\"\n        assert self.http_request_behaviour.body == \"\"\n\n    def test__init__ii(self):\n        \"\"\"Test the __init__ method of the http_request behaviour where ValueError is raise.\"\"\"\n        with pytest.raises(ValueError, match=\"Url, method and body must be provided.\"):\n            self.http_request_behaviour.__init__(\n                url=None, method=\"some_method\", body=\"some_body\"\n            )\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the http_request behaviour.\"\"\"\n        assert self.http_request_behaviour.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_act_i(self):\n        \"\"\"Test the act method of the http_request behaviour where lookup_termination_key IS None.\"\"\"\n        # setup\n        self.http_request_behaviour.lookup_termination_key = None\n\n        # operation\n        self.http_request_behaviour.act()\n\n        # after\n        self.assert_quantity_in_outbox(1)\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=HttpMessage,\n            performative=HttpMessage.Performative.REQUEST,\n            to=str(HTTP_CLIENT_PUBLIC_ID),\n            sender=str(self.skill.skill_context.skill_id),\n            method=self.mocked_method,\n            url=self.mocked_url,\n            headers=\"\",\n            version=\"\",\n            body=json.dumps(self.http_request_behaviour.body).encode(\"utf-8\"),\n        )\n        assert has_attributes, error_str\n\n    def test_act_ii(self):\n        \"\"\"Test the act method of the http_request behaviour where lookup_termination_key is NOT None and lookup_termination_key is False.\"\"\"\n        # setup\n        key = \"some_key\"\n        self.http_request_behaviour.lookup_termination_key = key\n        self.skill.skill_context.shared_state[key] = False\n\n        # operation\n        self.http_request_behaviour.act()\n\n        # after\n        self.assert_quantity_in_outbox(0)\n\n    def test_act_iii(self):\n        \"\"\"Test the act method of the http_request behaviour where lookup_termination_key is NOT None and lookup_termination_key is True.\"\"\"\n        # setup\n        key = \"some_key\"\n        self.http_request_behaviour.lookup_termination_key = key\n        self.skill.skill_context.shared_state[key] = True\n\n        # operation\n        self.http_request_behaviour.act()\n\n        # after\n        self.assert_quantity_in_outbox(1)\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=HttpMessage,\n            performative=HttpMessage.Performative.REQUEST,\n            to=str(HTTP_CLIENT_PUBLIC_ID),\n            sender=str(self.skill.skill_context.skill_id),\n            method=self.mocked_method,\n            url=self.mocked_url,\n            headers=\"\",\n            version=\"\",\n            body=json.dumps(self.http_request_behaviour.body).encode(\"utf-8\"),\n        )\n        assert has_attributes, error_str\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the http_request behaviour.\"\"\"\n        assert self.http_request_behaviour.teardown() is None\n        self.assert_quantity_in_outbox(0)\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_simple_data_request/test_dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the dialogue classes of the simple_data_request skill.\"\"\"\n\nfrom typing import cast\n\nfrom aea.test_tools.test_skill import COUNTERPARTY_AGENT_ADDRESS\n\nfrom packages.fetchai.protocols.http.message import HttpMessage\nfrom packages.fetchai.skills.simple_data_request.dialogues import (\n    HttpDialogue,\n    HttpDialogues,\n)\n\nfrom tests.test_packages.test_skills.test_simple_data_request.intermediate_class import (\n    SimpleDataRequestTestCase,\n)\n\n\nclass TestDialogues(SimpleDataRequestTestCase):\n    \"\"\"Test dialogue class of simple_data_request.\"\"\"\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.http_dialogues = cast(\n            HttpDialogues, cls._skill.skill_context.http_dialogues\n        )\n\n    def test_http_dialogues(self):\n        \"\"\"Test the HttpDialogues class.\"\"\"\n        _, dialogue = self.http_dialogues.create(\n            counterparty=COUNTERPARTY_AGENT_ADDRESS,\n            performative=HttpMessage.Performative.REQUEST,\n            method=\"some_method\",\n            url=\"some_url\",\n            version=\"some_version\",\n            headers=\"some_headers\",\n            body=b\"some_body\",\n        )\n        assert dialogue.role == HttpDialogue.Role.CLIENT\n        assert dialogue.self_address == str(self.skill.skill_context.skill_id)\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_simple_data_request/test_handlers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the handler classes of the simple_data_request skill.\"\"\"\n\nimport logging\nfrom typing import cast\nfrom unittest.mock import patch\n\nimport pytest\n\nfrom aea.protocols.dialogue.base import DialogueMessage\n\nfrom packages.fetchai.protocols.http.message import HttpMessage\nfrom packages.fetchai.skills.simple_data_request.dialogues import HttpDialogues\nfrom packages.fetchai.skills.simple_data_request.handlers import HttpHandler\n\nfrom tests.test_packages.test_skills.test_simple_data_request.intermediate_class import (\n    SimpleDataRequestTestCase,\n)\n\n\nclass TestHttpHandler(SimpleDataRequestTestCase):\n    \"\"\"Test http handler of simple_data_request.\"\"\"\n\n    is_agent_to_agent_messages = False\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.http_handler = cast(HttpHandler, cls._skill.skill_context.handlers.http)\n        cls.logger = cls._skill.skill_context.logger\n\n        cls.http_dialogues = cast(\n            HttpDialogues, cls._skill.skill_context.http_dialogues\n        )\n\n        cls.data = b\"some_body\"\n\n        cls.list_of_messages = (\n            DialogueMessage(\n                HttpMessage.Performative.REQUEST,\n                {\n                    \"method\": \"some_method\",\n                    \"url\": \"some_url\",\n                    \"headers\": \"some_headers\",\n                    \"version\": \"some_version\",\n                    \"body\": b\"some_body\",\n                },\n            ),\n        )\n\n    def test__init__(self):\n        \"\"\"Test the __init__ method of the http handler where ValueError is raise.\"\"\"\n        with pytest.raises(ValueError, match=\"No shared_state_key provided!\"):\n            self.http_handler.__init__(shared_state_key=None)\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the http handler.\"\"\"\n        assert self.http_handler.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle_unidentified_dialogue(self):\n        \"\"\"Test the _handle_unidentified_dialogue method of the http handler.\"\"\"\n        # setup\n        incorrect_dialogue_reference = (\"\", \"\")\n        incoming_message = self.build_incoming_message(\n            message_type=HttpMessage,\n            dialogue_reference=incorrect_dialogue_reference,\n            performative=HttpMessage.Performative.RESPONSE,\n            method=\"some_method\",\n            url=\"some_url\",\n            headers=\"some_headers\",\n            version=\"some_version\",\n            body=b\"some_body\",\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.http_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received invalid http message={incoming_message}, unidentified dialogue.\",\n        )\n\n    def test_handle_response(self):\n        \"\"\"Test the _handle_response method of the http handler.\"\"\"\n        # setup\n        http_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.http_dialogues,\n            messages=self.list_of_messages[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=http_dialogue,\n            performative=HttpMessage.Performative.RESPONSE,\n            method=\"some_method\",\n            url=\"some_url\",\n            headers=\"some_headers\",\n            version=\"some_version\",\n            body=self.data,\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.http_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.DEBUG,\n            f\"received http response={incoming_message} in dialogue={http_dialogue}.\",\n        )\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            \"updating shared_state with received data=b'some_body'!\",\n        )\n\n        assert (\n            self.skill.skill_context._agent_context.shared_state[\n                self.mocked_shared_state_key\n            ]\n            == self.data\n        )\n\n    def test_handle_invalid(self):\n        \"\"\"Test the _handle_invalid method of the http handler.\"\"\"\n        # setup\n        incoming_message = self.build_incoming_message(\n            message_type=HttpMessage,\n            performative=HttpMessage.Performative.REQUEST,\n            method=\"some_method\",\n            url=\"some_url\",\n            headers=\"some_headers\",\n            version=\"some_version\",\n            body=self.data,\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.http_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"cannot handle http message of performative={incoming_message.performative} in dialogue={self.http_dialogues.get_dialogue(incoming_message)}.\",\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the http handler.\"\"\"\n        assert self.http_handler.teardown() is None\n        self.assert_quantity_in_outbox(0)\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_simple_oracle/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"The tests module contains the tests of the packages/skills/simple_oracle dir.\"\"\"\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_simple_oracle/test_behaviours.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the behaviour classes of the simple oracle skill.\"\"\"\n\nimport logging\nfrom pathlib import Path\nfrom typing import cast\nfrom unittest.mock import patch\n\nfrom aea.test_tools.test_skill import BaseSkillTestCase\n\nfrom packages.fetchai.contracts.oracle.contract import PUBLIC_ID as CONTRACT_PUBLIC_ID\nfrom packages.fetchai.protocols.contract_api.message import ContractApiMessage\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\nfrom packages.fetchai.protocols.prometheus.message import PrometheusMessage\nfrom packages.fetchai.skills.simple_oracle.behaviours import SimpleOracleBehaviour\nfrom packages.fetchai.skills.simple_oracle.dialogues import PrometheusDialogues\nfrom packages.fetchai.skills.simple_oracle.strategy import Strategy\n\nfrom tests.conftest import ROOT_DIR\n\n\nETHEREUM_LEDGER_ID = \"ethereum\"\nFETCHAI_LEDGER_ID = \"fetchai\"\nAGENT_ADDRESS = \"some_eth_address\"\nDEFAULT_ADDRESS = \"0x0000000000000000000000000000000000000000\"\n\n\nclass TestSkillBehaviour(BaseSkillTestCase):\n    \"\"\"Test behaviours of simple oracle.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"simple_oracle\")\n\n    @classmethod\n    def setup(cls, **kwargs):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.simple_oracle_behaviour = cast(\n            SimpleOracleBehaviour,\n            cls._skill.skill_context.behaviours.simple_oracle_behaviour,\n        )\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the simple_oracle behaviour.\"\"\"\n        strategy = cast(Strategy, self.simple_oracle_behaviour.context.strategy)\n        strategy._ledger_id = ETHEREUM_LEDGER_ID\n\n        self.simple_oracle_behaviour.setup()\n        self.assert_quantity_in_outbox(3)\n\n        msg = cast(ContractApiMessage, self.get_message_from_outbox())\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=msg,\n            message_type=ContractApiMessage,\n            performative=ContractApiMessage.Performative.GET_DEPLOY_TRANSACTION,\n            contract_id=str(CONTRACT_PUBLIC_ID),\n            callable=\"get_deploy_transaction\",\n        )\n        assert has_attributes, error_str\n\n        msg = cast(PrometheusMessage, self.get_message_from_outbox())\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=msg,\n            message_type=PrometheusMessage,\n            performative=PrometheusMessage.Performative.ADD_METRIC,\n            type=\"Gauge\",\n            title=\"oracle_account_balance_ETH\",\n            description=\"Balance of oracle contract (ETH)\",\n        )\n        assert has_attributes, error_str\n\n        msg = cast(PrometheusMessage, self.get_message_from_outbox())\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=msg,\n            message_type=PrometheusMessage,\n            performative=PrometheusMessage.Performative.ADD_METRIC,\n            type=\"Gauge\",\n            title=\"num_oracle_updates\",\n            description=\"Number of updates published to oracle contract\",\n        )\n        assert has_attributes, error_str\n\n    def test_setup_with_contract_set(self):\n        \"\"\"Test the setup method of the simple_oracle behaviour for existing contract.\"\"\"\n        prometheus_dialogues = cast(\n            PrometheusDialogues,\n            self.simple_oracle_behaviour.context.prometheus_dialogues,\n        )\n        prometheus_dialogues.enabled = False\n        strategy = cast(Strategy, self.simple_oracle_behaviour.context.strategy)\n        strategy.contract_address = DEFAULT_ADDRESS\n        strategy.is_contract_deployed = True\n\n        with patch.object(\n            self.simple_oracle_behaviour.context.logger, \"log\"\n        ) as mock_logger:\n            self.simple_oracle_behaviour.setup()\n        mock_logger.assert_any_call(\n            logging.INFO,\n            \"Fetch oracle contract address already added\",\n        )\n        self.assert_quantity_in_outbox(0)\n\n    def test_setup_with_contract_set_and_oracle_role_granted(self):\n        \"\"\"Test the setup method of the simple_oracle behaviour for existing contract and oracle role.\"\"\"\n        prometheus_dialogues = cast(\n            PrometheusDialogues,\n            self.simple_oracle_behaviour.context.prometheus_dialogues,\n        )\n        prometheus_dialogues.enabled = False\n        strategy = cast(Strategy, self.simple_oracle_behaviour.context.strategy)\n        strategy.contract_address = DEFAULT_ADDRESS\n        strategy.is_contract_deployed = True\n        strategy.is_oracle_role_granted = True\n\n        assert strategy.erc20_address == DEFAULT_ADDRESS\n\n        with patch.object(\n            self.simple_oracle_behaviour.context.logger, \"log\"\n        ) as mock_logger:\n            self.simple_oracle_behaviour.setup()\n        mock_logger.assert_any_call(\n            logging.INFO,\n            \"Oracle role already granted\",\n        )\n\n        self.assert_quantity_in_outbox(0)\n\n    def test_act_pre_deploy(self):\n        \"\"\"Test the act method of the simple_oracle behaviour before contract is deployed.\"\"\"\n        strategy = cast(Strategy, self.simple_oracle_behaviour.context.strategy)\n        strategy._ledger_id = ETHEREUM_LEDGER_ID\n\n        self.simple_oracle_behaviour.context.agent_addresses[\n            ETHEREUM_LEDGER_ID\n        ] = \"AGENT_ADDRESS\"\n        self.simple_oracle_behaviour.act()\n        self.assert_quantity_in_outbox(1)\n\n        msg = cast(LedgerApiMessage, self.get_message_from_outbox())\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=msg,\n            message_type=LedgerApiMessage,\n            performative=LedgerApiMessage.Performative.GET_BALANCE,\n            ledger_id=ETHEREUM_LEDGER_ID,\n            address=cast(\n                str,\n                self.simple_oracle_behaviour.context.agent_addresses.get(\n                    ETHEREUM_LEDGER_ID\n                ),\n            ),\n        )\n        assert has_attributes, error_str\n\n    def test_act_grant_role(self):\n        \"\"\"Test the act method of the simple_oracle behaviour before role is granted.\"\"\"\n        strategy = cast(Strategy, self.simple_oracle_behaviour.context.strategy)\n        strategy.contract_address = DEFAULT_ADDRESS\n        strategy._ledger_id = ETHEREUM_LEDGER_ID\n        strategy.is_contract_deployed = True\n        self.simple_oracle_behaviour.context.agent_addresses[\n            ETHEREUM_LEDGER_ID\n        ] = \"AGENT_ADDRESS\"\n        self.simple_oracle_behaviour.act()\n        self.assert_quantity_in_outbox(2)\n\n        msg = cast(LedgerApiMessage, self.get_message_from_outbox())\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=msg,\n            message_type=LedgerApiMessage,\n            performative=LedgerApiMessage.Performative.GET_BALANCE,\n            ledger_id=ETHEREUM_LEDGER_ID,\n            address=cast(\n                str,\n                self.simple_oracle_behaviour.context.agent_addresses.get(\n                    ETHEREUM_LEDGER_ID\n                ),\n            ),\n        )\n        assert has_attributes, error_str\n\n        msg = cast(ContractApiMessage, self.get_message_from_outbox())\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=msg,\n            message_type=ContractApiMessage,\n            performative=ContractApiMessage.Performative.GET_RAW_TRANSACTION,\n            contract_id=str(CONTRACT_PUBLIC_ID),\n            contract_address=strategy.contract_address,\n            callable=\"get_grant_role_transaction\",\n        )\n        assert has_attributes, error_str\n\n    def test_act_update(self):\n        \"\"\"Test the act method of the simple_oracle behaviour for normal updating.\"\"\"\n        strategy = cast(Strategy, self.simple_oracle_behaviour.context.strategy)\n        strategy.contract_address = DEFAULT_ADDRESS\n        strategy._ledger_id = ETHEREUM_LEDGER_ID\n        strategy.is_contract_deployed = True\n        strategy.is_oracle_role_granted = True\n        strategy._oracle_value_name = \"oracle_value\"\n        self.simple_oracle_behaviour.context.shared_state[\"oracle_value\"] = {\n            \"some_key\": \"some_value\"\n        }\n        self.simple_oracle_behaviour.context.agent_addresses[\n            ETHEREUM_LEDGER_ID\n        ] = \"AGENT_ADDRESS\"\n        self.simple_oracle_behaviour.act()\n        self.assert_quantity_in_outbox(2)\n\n        msg = cast(LedgerApiMessage, self.get_message_from_outbox())\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=msg,\n            message_type=LedgerApiMessage,\n            performative=LedgerApiMessage.Performative.GET_BALANCE,\n            ledger_id=ETHEREUM_LEDGER_ID,\n            address=cast(\n                str,\n                self.simple_oracle_behaviour.context.agent_addresses.get(\n                    ETHEREUM_LEDGER_ID\n                ),\n            ),\n        )\n        assert has_attributes, error_str\n\n        msg = cast(ContractApiMessage, self.get_message_from_outbox())\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=msg,\n            message_type=ContractApiMessage,\n            performative=ContractApiMessage.Performative.GET_RAW_TRANSACTION,\n            contract_id=str(CONTRACT_PUBLIC_ID),\n            contract_address=strategy.contract_address,\n            callable=\"get_update_transaction\",\n        )\n        assert has_attributes, error_str\n\n    def test_act_no_oracle_value(self):\n        \"\"\"Test the act method of the simple_oracle behaviour when no oracle value is present.\"\"\"\n        strategy = cast(Strategy, self.simple_oracle_behaviour.context.strategy)\n        strategy.contract_address = DEFAULT_ADDRESS\n        strategy._ledger_id = ETHEREUM_LEDGER_ID\n        strategy.is_contract_deployed = True\n        strategy.is_oracle_role_granted = True\n        self.simple_oracle_behaviour.context.agent_addresses[\n            ETHEREUM_LEDGER_ID\n        ] = \"AGENT_ADDRESS\"\n        self.simple_oracle_behaviour.act()\n        self.assert_quantity_in_outbox(1)\n\n        msg = cast(LedgerApiMessage, self.get_message_from_outbox())\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=msg,\n            message_type=LedgerApiMessage,\n            performative=LedgerApiMessage.Performative.GET_BALANCE,\n            ledger_id=ETHEREUM_LEDGER_ID,\n            address=cast(\n                str,\n                self.simple_oracle_behaviour.context.agent_addresses.get(\n                    ETHEREUM_LEDGER_ID\n                ),\n            ),\n        )\n        assert has_attributes, error_str\n\n    def test__request_contract_deploy_transaction(self):\n        \"\"\"Test that the _request_contract_deploy_transaction function sends the right message to the contract_api for ethereum ledger.\"\"\"\n        strategy = cast(Strategy, self.simple_oracle_behaviour.context.strategy)\n        strategy._ledger_id = ETHEREUM_LEDGER_ID\n\n        self.simple_oracle_behaviour._request_contract_deploy_transaction()\n        self.assert_quantity_in_outbox(1)\n\n        kwargs = strategy.get_deploy_kwargs()\n        assert \"ERC20Address\" in kwargs.body\n        assert \"initialFee\" in kwargs.body\n\n        msg = cast(ContractApiMessage, self.get_message_from_outbox())\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=msg,\n            message_type=ContractApiMessage,\n            performative=ContractApiMessage.Performative.GET_DEPLOY_TRANSACTION,\n            contract_id=str(CONTRACT_PUBLIC_ID),\n            callable=\"get_deploy_transaction\",\n            kwargs=kwargs,\n        )\n        assert has_attributes, error_str\n\n    def test__request_contract_store_transaction(self):\n        \"\"\"Test that the _request_contract_deploy_transaction function sends the right message to the contract_api for fetchai ledger.\"\"\"\n        strategy = cast(Strategy, self.simple_oracle_behaviour.context.strategy)\n        strategy._ledger_id = FETCHAI_LEDGER_ID\n\n        self.simple_oracle_behaviour._request_contract_deploy_transaction()\n        self.assert_quantity_in_outbox(1)\n\n        kwargs = strategy.get_deploy_kwargs()\n        assert \"ERC20Address\" not in kwargs.body\n        assert \"initialFee\" not in kwargs.body\n\n        msg = cast(ContractApiMessage, self.get_message_from_outbox())\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=msg,\n            message_type=ContractApiMessage,\n            performative=ContractApiMessage.Performative.GET_DEPLOY_TRANSACTION,\n            contract_id=str(CONTRACT_PUBLIC_ID),\n            callable=\"get_deploy_transaction\",\n            kwargs=kwargs,\n        )\n        assert has_attributes, error_str\n\n    def test__request_grant_role_transaction(self):\n        \"\"\"Test that the _request_grant_role_transaction function sends the right message to the contract_api.\"\"\"\n        strategy = cast(Strategy, self.simple_oracle_behaviour.context.strategy)\n        strategy.contract_address = DEFAULT_ADDRESS\n        strategy._ledger_id = ETHEREUM_LEDGER_ID\n\n        self.simple_oracle_behaviour._request_grant_role_transaction()\n        self.assert_quantity_in_outbox(1)\n\n        msg = cast(ContractApiMessage, self.get_message_from_outbox())\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=msg,\n            message_type=ContractApiMessage,\n            performative=ContractApiMessage.Performative.GET_RAW_TRANSACTION,\n            contract_id=str(CONTRACT_PUBLIC_ID),\n            contract_address=strategy.contract_address,\n            callable=\"get_grant_role_transaction\",\n        )\n        assert has_attributes, error_str\n\n    def test__request_update_transaction(self):\n        \"\"\"Test that the _request_update_transaction function sends the right message to the contract_api.\"\"\"\n        strategy = cast(Strategy, self.simple_oracle_behaviour.context.strategy)\n        strategy.contract_address = DEFAULT_ADDRESS\n        strategy._ledger_id = ETHEREUM_LEDGER_ID\n\n        update_args = {\"some\": \"args\"}\n        self.simple_oracle_behaviour._request_update_transaction(update_args)\n        self.assert_quantity_in_outbox(1)\n\n        msg = cast(ContractApiMessage, self.get_message_from_outbox())\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=msg,\n            message_type=ContractApiMessage,\n            performative=ContractApiMessage.Performative.GET_RAW_TRANSACTION,\n            contract_id=str(CONTRACT_PUBLIC_ID),\n            contract_address=strategy.contract_address,\n            callable=\"get_update_transaction\",\n        )\n        assert has_attributes, error_str\n\n    def test__get_balance(self):\n        \"\"\"Test that the _get_balance function sends the right message to the ledger_api.\"\"\"\n        strategy = cast(Strategy, self.simple_oracle_behaviour.context.strategy)\n        strategy._ledger_id = ETHEREUM_LEDGER_ID\n        self.simple_oracle_behaviour.context.agent_addresses[\n            ETHEREUM_LEDGER_ID\n        ] = \"AGENT_ADDRESS\"\n\n        self.simple_oracle_behaviour._get_balance()\n        self.assert_quantity_in_outbox(1)\n\n        msg = cast(LedgerApiMessage, self.get_message_from_outbox())\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=msg,\n            message_type=LedgerApiMessage,\n            performative=LedgerApiMessage.Performative.GET_BALANCE,\n            ledger_id=ETHEREUM_LEDGER_ID,\n            address=cast(\n                str,\n                self.simple_oracle_behaviour.context.agent_addresses.get(\n                    ETHEREUM_LEDGER_ID\n                ),\n            ),\n        )\n        assert has_attributes, error_str\n\n    def test_add_prometheus_metric(self):\n        \"\"\"Test the send_http_request_message method of the simple_oracle behaviour.\"\"\"\n        self.simple_oracle_behaviour.add_prometheus_metric(\n            \"some_metric\", \"Gauge\", \"some_description\", {\"label_key\": \"label_value\"}\n        )\n        self.assert_quantity_in_outbox(1)\n\n        msg = cast(PrometheusMessage, self.get_message_from_outbox())\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=msg,\n            message_type=PrometheusMessage,\n            performative=PrometheusMessage.Performative.ADD_METRIC,\n            type=\"Gauge\",\n            title=\"some_metric\",\n            description=\"some_description\",\n            labels={\"label_key\": \"label_value\"},\n        )\n        assert has_attributes, error_str\n\n    def test_update_prometheus_metric(self):\n        \"\"\"Test the test_update_prometheus_metric method of the simple_oracle behaviour.\"\"\"\n        self.simple_oracle_behaviour.update_prometheus_metric(\n            \"some_metric\", \"set\", 0.0, {\"label_key\": \"label_value\"}\n        )\n        self.assert_quantity_in_outbox(1)\n\n        msg = cast(PrometheusMessage, self.get_message_from_outbox())\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=msg,\n            message_type=PrometheusMessage,\n            performative=PrometheusMessage.Performative.UPDATE_METRIC,\n            callable=\"set\",\n            title=\"some_metric\",\n            value=0.0,\n            labels={\"label_key\": \"label_value\"},\n        )\n        assert has_attributes, error_str\n\n    def test_teardown(self):\n        \"\"\"Test that the teardown method of the simple_oracle behaviour leaves no messages in the outbox.\"\"\"\n        assert self.simple_oracle_behaviour.teardown() is None\n        self.assert_quantity_in_outbox(0)\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_simple_oracle/test_handlers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the handler classes of the simple_data_request skill.\"\"\"\n\nimport logging\nfrom pathlib import Path\nfrom typing import cast\nfrom unittest.mock import patch\n\nfrom aea.crypto.ledger_apis import LedgerApis\nfrom aea.helpers.transaction.base import Terms\nfrom aea.protocols.dialogue.base import DialogueMessage\nfrom aea.test_tools.test_skill import BaseSkillTestCase\n\nfrom packages.fetchai.connections.ledger.base import (\n    CONNECTION_ID as LEDGER_CONNECTION_PUBLIC_ID,\n)\nfrom packages.fetchai.contracts.oracle.contract import PUBLIC_ID as CONTRACT_PUBLIC_ID\nfrom packages.fetchai.protocols.contract_api.custom_types import Kwargs\nfrom packages.fetchai.protocols.contract_api.custom_types import (\n    Kwargs as ContractApiKwargs,\n)\nfrom packages.fetchai.protocols.contract_api.custom_types import State\nfrom packages.fetchai.protocols.contract_api.message import ContractApiMessage\nfrom packages.fetchai.protocols.ledger_api.custom_types import (\n    SignedTransaction,\n    TransactionDigest,\n    TransactionReceipt,\n)\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\nfrom packages.fetchai.protocols.prometheus.message import PrometheusMessage\nfrom packages.fetchai.protocols.signing.custom_types import RawTransaction\nfrom packages.fetchai.protocols.signing.message import SigningMessage\nfrom packages.fetchai.skills.simple_oracle.behaviours import SimpleOracleBehaviour\nfrom packages.fetchai.skills.simple_oracle.dialogues import (\n    ContractApiDialogue,\n    ContractApiDialogues,\n    LedgerApiDialogue,\n    LedgerApiDialogues,\n    PrometheusDialogues,\n    SigningDialogue,\n    SigningDialogues,\n)\nfrom packages.fetchai.skills.simple_oracle.handlers import (\n    ContractApiHandler,\n    LedgerApiHandler,\n    PrometheusHandler,\n    SigningHandler,\n)\nfrom packages.fetchai.skills.simple_oracle.strategy import Strategy\n\nfrom tests.conftest import ROOT_DIR\n\n\nETHEREUM_LEDGER_ID = \"ethereum\"\nFETCHAI_LEDGER_ID = \"fetchai\"\nDEFAULT_TX = {\"some_tx_key\": \"some_tx_value\"}\nDEFAULT_TERMS = [\n    ETHEREUM_LEDGER_ID,\n    \"sender_address\",\n    \"counterparty_address\",\n    {},\n    {},\n    \"some_nonce\",\n]\nFETCHAI_DEPLOY_RECEIPT = {\n    \"logs\": [\n        {\n            \"events\": [\n                {\n                    \"attributes\": [\n                        {\"key\": \"code_id\", \"value\": \"8888\"},\n                        {\"key\": \"_contract_address\", \"value\": \"some_contract_address\"},\n                    ]\n                }\n            ]\n        }\n    ]\n}\n\n\nclass TestLedgerApiHandler(BaseSkillTestCase):\n    \"\"\"Test ledger_api handler of simple_oracle skill.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"simple_oracle\")\n    is_agent_to_agent_messages = False\n\n    @classmethod\n    def setup(cls, **kwargs):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup(**kwargs)\n        cls.ledger_api_handler = cast(\n            LedgerApiHandler, cls._skill.skill_context.handlers.ledger_api\n        )\n        cls.logger = cls._skill.skill_context.logger\n        cls.simple_oracle_behaviour = cast(\n            SimpleOracleBehaviour,\n            cls._skill.skill_context.behaviours.simple_oracle_behaviour,\n        )\n        cls.ledger_api_dialogues = cast(\n            LedgerApiDialogues, cls._skill.skill_context.ledger_api_dialogues\n        )\n        cls.contract_api_dialogues = cast(\n            ContractApiDialogues, cls._skill.skill_context.contract_api_dialogues\n        )\n        cls.signing_dialogues = cast(\n            SigningDialogues, cls._skill.skill_context.signing_dialogues\n        )\n\n        cls.list_of_ledger_api_messages = (\n            DialogueMessage(\n                LedgerApiMessage.Performative.GET_BALANCE,\n                {\"ledger_id\": ETHEREUM_LEDGER_ID, \"address\": \"some_eth_address\"},\n            ),\n            DialogueMessage(\n                LedgerApiMessage.Performative.SEND_SIGNED_TRANSACTION,\n                {\n                    \"signed_transaction\": SignedTransaction(\n                        ETHEREUM_LEDGER_ID, DEFAULT_TX\n                    )\n                },\n            ),\n            DialogueMessage(\n                LedgerApiMessage.Performative.GET_TRANSACTION_RECEIPT,\n                {\n                    \"transaction_digest\": TransactionDigest(\n                        ETHEREUM_LEDGER_ID, \"some_digest\"\n                    )\n                },\n            ),\n            DialogueMessage(\n                LedgerApiMessage.Performative.GET_STATE,\n                {\n                    \"ledger_id\": ETHEREUM_LEDGER_ID,\n                    \"callable\": \"some_callable\",\n                    \"args\": (),\n                    \"kwargs\": LedgerApiMessage.Kwargs({}),\n                },\n            ),\n        )\n        cls.list_of_contract_api_messages = (\n            DialogueMessage(\n                ContractApiMessage.Performative.GET_DEPLOY_TRANSACTION,\n                {\n                    \"ledger_id\": ETHEREUM_LEDGER_ID,\n                    \"contract_id\": \"some_contract_id\",\n                    \"callable\": \"some_callable\",\n                    \"kwargs\": ContractApiKwargs({\"some_key\": \"some_value\"}),\n                },\n            ),\n            DialogueMessage(\n                ContractApiMessage.Performative.GET_DEPLOY_TRANSACTION,\n                {\n                    \"ledger_id\": \"fetchai\",\n                    \"contract_id\": \"some_contract_id\",\n                    \"callable\": \"some_callable\",\n                    \"kwargs\": ContractApiKwargs({\"some_key\": \"some_value\"}),\n                },\n            ),\n        )\n        cls.list_of_signing_messages = (\n            DialogueMessage(\n                SigningMessage.Performative.SIGN_TRANSACTION,\n                {\n                    \"terms\": Terms(*DEFAULT_TERMS),\n                    \"raw_transaction\": RawTransaction(ETHEREUM_LEDGER_ID, DEFAULT_TX),\n                },\n            ),\n        )\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the ledger_api handler.\"\"\"\n        assert self.ledger_api_handler.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle__handle_unidentified_dialogue(self):\n        \"\"\"Test handling an unidentified dialogoue\"\"\"\n        # setup\n        incorrect_dialogue_reference = (\"\", \"\")\n        incoming_message = self.build_incoming_message(\n            message_type=LedgerApiMessage,\n            dialogue_reference=incorrect_dialogue_reference,\n            performative=LedgerApiMessage.Performative.GET_BALANCE,\n            ledger_id=ETHEREUM_LEDGER_ID,\n            address=\"some_eth_address\",\n        )\n\n        # operation\n        with patch.object(self.ledger_api_handler.context.logger, \"log\") as mock_logger:\n            self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received invalid ledger_api message={incoming_message}, unidentified dialogue.\",\n        )\n\n        self.assert_quantity_in_outbox(0)\n\n    def test__handle_balance(self):\n        \"\"\"Test handling a balance\"\"\"\n        # setup\n        balance = 0\n        dialogue = self.prepare_skill_dialogue(\n            self.ledger_api_dialogues, self.list_of_ledger_api_messages[:1]\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=dialogue,\n            performative=LedgerApiMessage.Performative.BALANCE,\n            ledger_id=ETHEREUM_LEDGER_ID,\n            balance=balance,\n        )\n\n        # operation\n        with patch.object(self.ledger_api_handler.context.logger, \"log\") as mock_logger:\n            self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"Balance on {ETHEREUM_LEDGER_ID} ledger={balance}.\",\n        )\n\n        self.assert_quantity_in_outbox(1)\n\n    def test__handle_transaction_digest(self):\n        \"\"\"Test handling a transaction digest\"\"\"\n        # setup\n        dialogue = self.prepare_skill_dialogue(\n            self.ledger_api_dialogues, self.list_of_ledger_api_messages[1:2]\n        )\n        digest = \"some_digest\"\n        transaction_digest = TransactionDigest(ETHEREUM_LEDGER_ID, digest)\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=dialogue,\n            performative=LedgerApiMessage.Performative.TRANSACTION_DIGEST,\n            transaction_digest=transaction_digest,\n        )\n\n        # operation\n        with patch.object(self.ledger_api_handler.context.logger, \"log\") as mock_logger:\n            self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"transaction was successfully submitted. Transaction digest=TransactionDigest: ledger_id={ETHEREUM_LEDGER_ID}, body={digest}\",\n        )\n\n        self.assert_quantity_in_outbox(1)\n\n    def test__handle_transaction_receipt_failed(self):\n        \"\"\"Test handling a transaction receipt\"\"\"\n        # setup\n        dialogue = self.prepare_skill_dialogue(\n            self.ledger_api_dialogues, self.list_of_ledger_api_messages[2:3]\n        )\n\n        receipt = {\"status\": 0}\n        transaction_receipt = TransactionReceipt(\n            ETHEREUM_LEDGER_ID, receipt, DEFAULT_TX\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=dialogue,\n            performative=LedgerApiMessage.Performative.TRANSACTION_RECEIPT,\n            transaction_receipt=transaction_receipt,\n        )\n\n        # operation\n        with patch.object(self.ledger_api_handler.context.logger, \"log\") as mock_logger:\n            self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.ERROR,\n            f\"transaction failed. Transaction receipt={transaction_receipt}\",\n        )\n\n        self.assert_quantity_in_outbox(0)\n\n    def test__handle_transaction_receipt_deploy(self):\n        \"\"\"Test handling a deploy transaction receipt\"\"\"\n        # setup\n        ledger_api_dialogue = self.prepare_skill_dialogue(\n            self.ledger_api_dialogues, self.list_of_ledger_api_messages[2:3]\n        )\n        contract_api_dialogue = self.prepare_skill_dialogue(\n            self.contract_api_dialogues, self.list_of_contract_api_messages[:1]\n        )\n        signing_dialogue = self.prepare_skill_dialogue(\n            self.signing_dialogues, self.list_of_signing_messages[:1]\n        )\n\n        terms = Terms(*DEFAULT_TERMS, label=\"deploy\")\n\n        contract_api_dialogue.terms = terms\n        signing_dialogue.associated_contract_api_dialogue = contract_api_dialogue\n        ledger_api_dialogue.associated_signing_dialogue = signing_dialogue\n\n        transaction_receipt = TransactionReceipt(\n            FETCHAI_LEDGER_ID, FETCHAI_DEPLOY_RECEIPT, DEFAULT_TX\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=ledger_api_dialogue,\n            performative=LedgerApiMessage.Performative.TRANSACTION_RECEIPT,\n            transaction_receipt=transaction_receipt,\n        )\n\n        # operation\n        with patch.object(self.ledger_api_handler.context.logger, \"log\") as mock_logger:\n            self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"transaction was successfully settled. Transaction receipt={transaction_receipt}\",\n        )\n        mock_logger.assert_any_call(\n            logging.INFO,\n            \"Oracle contract successfully deployed at address: some_contract_address\",\n        )\n\n        assert (\n            self.simple_oracle_behaviour.context.strategy.is_contract_deployed\n        ), \"Contract deployment status not set\"\n        self.assert_quantity_in_outbox(0)\n\n    def test__handle_transaction_receipt_store(self):\n        \"\"\"Test handling a store contract code transaction receipt\"\"\"\n        # setup\n        ledger_api_dialogue = self.prepare_skill_dialogue(\n            self.ledger_api_dialogues, self.list_of_ledger_api_messages[2:3]\n        )\n        contract_api_dialogue = self.prepare_skill_dialogue(\n            self.contract_api_dialogues, self.list_of_contract_api_messages[1:2]\n        )\n        signing_dialogue = self.prepare_skill_dialogue(\n            self.signing_dialogues, self.list_of_signing_messages[:1]\n        )\n\n        strategy = cast(Strategy, self.simple_oracle_behaviour.context.strategy)\n        strategy._ledger_id = \"fetchai\"\n\n        contract_api_dialogue.terms = strategy.get_deploy_terms()\n        assert contract_api_dialogue.terms.kwargs[\"label\"] == \"store\"\n\n        signing_dialogue.associated_contract_api_dialogue = contract_api_dialogue\n        ledger_api_dialogue.associated_signing_dialogue = signing_dialogue\n\n        transaction_receipt = TransactionReceipt(\n            FETCHAI_LEDGER_ID, FETCHAI_DEPLOY_RECEIPT, DEFAULT_TX\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=ledger_api_dialogue,\n            performative=LedgerApiMessage.Performative.TRANSACTION_RECEIPT,\n            transaction_receipt=transaction_receipt,\n        )\n\n        # operation\n        with patch.object(self.ledger_api_handler.context.logger, \"log\") as mock_logger:\n            self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"transaction was successfully settled. Transaction receipt={transaction_receipt}\",\n        )\n\n        self.assert_quantity_in_outbox(1)\n        msg = cast(ContractApiMessage, self.get_message_from_outbox())\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=msg,\n            message_type=ContractApiMessage,\n            performative=ContractApiMessage.Performative.GET_DEPLOY_TRANSACTION,\n            ledger_id=\"fetchai\",\n            contract_id=str(CONTRACT_PUBLIC_ID),\n            callable=\"get_deploy_transaction\",\n            kwargs=ContractApiMessage.Kwargs(\n                {\n                    \"label\": \"OracleContract\",\n                    \"init_msg\": {\"fee\": str(strategy.initial_fee_deploy)},\n                    \"gas\": strategy.gas_limit_instantiate,\n                    \"tx_fee\": strategy.gas_price * strategy.gas_limit_instantiate,\n                    \"amount\": 1,\n                    \"code_id\": 8888,\n                    \"deployer_address\": \"test_agent_address\",\n                }\n            ),\n        )\n        assert has_attributes, error_str\n\n    def test__handle_transaction_receipt_init(self):\n        \"\"\"Test handling a store contract code transaction receipt\"\"\"\n        # setup\n        ledger_api_dialogue = self.prepare_skill_dialogue(\n            self.ledger_api_dialogues, self.list_of_ledger_api_messages[2:3]\n        )\n        contract_api_dialogue = self.prepare_skill_dialogue(\n            self.contract_api_dialogues, self.list_of_contract_api_messages[1:2]\n        )\n        signing_dialogue = self.prepare_skill_dialogue(\n            self.signing_dialogues, self.list_of_signing_messages[:1]\n        )\n\n        strategy = cast(Strategy, self.simple_oracle_behaviour.context.strategy)\n        strategy._ledger_id = \"fetchai\"\n\n        contract_api_dialogue.terms = strategy.get_deploy_terms(\n            is_init_transaction=True\n        )\n        signing_dialogue.associated_contract_api_dialogue = contract_api_dialogue\n        ledger_api_dialogue.associated_signing_dialogue = signing_dialogue\n\n        receipt = {\"status\": 1, \"contractAddress\": \"some_contract_address\"}\n        transaction_receipt = TransactionReceipt(\n            ETHEREUM_LEDGER_ID, receipt, DEFAULT_TX\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=ledger_api_dialogue,\n            performative=LedgerApiMessage.Performative.TRANSACTION_RECEIPT,\n            transaction_receipt=transaction_receipt,\n        )\n\n        # operation\n        with patch.object(\n            LedgerApis, \"get_contract_address\", return_value=\"some_contract_address\"\n        ):\n            with patch.object(\n                self.ledger_api_handler.context.logger, \"log\"\n            ) as mock_logger:\n                self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"transaction was successfully settled. Transaction receipt={transaction_receipt}\",\n        )\n        mock_logger.assert_any_call(\n            logging.INFO,\n            \"Oracle contract successfully deployed at address: some_contract_address\",\n        )\n\n        assert (\n            self.simple_oracle_behaviour.context.strategy.is_contract_deployed\n        ), \"Contract deployment status not set\"\n        self.assert_quantity_in_outbox(0)\n\n    def test__handle_transaction_receipt_grant_role(self):\n        \"\"\"Test handling a grant_role transaction receipt\"\"\"\n        # setup\n        ledger_api_dialogue = self.prepare_skill_dialogue(\n            self.ledger_api_dialogues, self.list_of_ledger_api_messages[2:3]\n        )\n        contract_api_dialogue = self.prepare_skill_dialogue(\n            self.contract_api_dialogues, self.list_of_contract_api_messages[:1]\n        )\n        signing_dialogue = self.prepare_skill_dialogue(\n            self.signing_dialogues, self.list_of_signing_messages[:1]\n        )\n\n        terms = Terms(*DEFAULT_TERMS, label=\"grant_role\")\n\n        strategy = cast(Strategy, self.simple_oracle_behaviour.context.strategy)\n        strategy.is_contract_deployed = True\n\n        contract_api_dialogue.terms = terms\n        signing_dialogue.associated_contract_api_dialogue = contract_api_dialogue\n        ledger_api_dialogue.associated_signing_dialogue = signing_dialogue\n\n        receipt = {\"status\": 1, \"contractAddress\": \"some_contract_address\"}\n        transaction_receipt = TransactionReceipt(\n            ETHEREUM_LEDGER_ID, receipt, DEFAULT_TX\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=ledger_api_dialogue,\n            performative=LedgerApiMessage.Performative.TRANSACTION_RECEIPT,\n            transaction_receipt=transaction_receipt,\n        )\n\n        # operation\n        with patch.object(self.ledger_api_handler.context.logger, \"log\") as mock_logger:\n            self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"transaction was successfully settled. Transaction receipt={transaction_receipt}\",\n        )\n        mock_logger.assert_any_call(\n            logging.INFO,\n            \"Oracle role successfully granted!\",\n        )\n\n        assert (\n            self.simple_oracle_behaviour.context.strategy.is_oracle_role_granted\n        ), \"Oracle role status not set\"\n\n        self.assert_quantity_in_outbox(0)\n\n    def test__handle_transaction_receipt_update(self):\n        \"\"\"Test handling an update transaction receipt\"\"\"\n        # setup\n        ledger_api_dialogue = self.prepare_skill_dialogue(\n            self.ledger_api_dialogues, self.list_of_ledger_api_messages[2:3]\n        )\n        contract_api_dialogue = self.prepare_skill_dialogue(\n            self.contract_api_dialogues, self.list_of_contract_api_messages[:1]\n        )\n        signing_dialogue = self.prepare_skill_dialogue(\n            self.signing_dialogues, self.list_of_signing_messages[:1]\n        )\n\n        terms = Terms(*DEFAULT_TERMS, label=\"update\")\n\n        strategy = cast(Strategy, self.simple_oracle_behaviour.context.strategy)\n        strategy.is_contract_deployed = True\n        strategy.is_oracle_role_granted = True\n\n        contract_api_dialogue.terms = terms\n        signing_dialogue.associated_contract_api_dialogue = contract_api_dialogue\n        ledger_api_dialogue.associated_signing_dialogue = signing_dialogue\n\n        receipt = {\"status\": 1, \"contractAddress\": \"some_contract_address\"}\n        transaction_receipt = TransactionReceipt(\n            ETHEREUM_LEDGER_ID, receipt, DEFAULT_TX\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=ledger_api_dialogue,\n            performative=LedgerApiMessage.Performative.TRANSACTION_RECEIPT,\n            transaction_receipt=transaction_receipt,\n        )\n\n        # operation\n        with patch.object(self.ledger_api_handler.context.logger, \"log\") as mock_logger:\n            self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"transaction was successfully settled. Transaction receipt={transaction_receipt}\",\n        )\n        mock_logger.assert_any_call(\n            logging.INFO,\n            \"Oracle value successfully updated!\",\n        )\n\n        self.assert_quantity_in_outbox(1)\n        msg = cast(PrometheusMessage, self.get_message_from_outbox())\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=msg,\n            message_type=PrometheusMessage,\n            performative=PrometheusMessage.Performative.UPDATE_METRIC,\n            callable=\"inc\",\n            title=\"num_oracle_updates\",\n            value=1.0,\n            labels={},\n        )\n        assert has_attributes, error_str\n\n    def test__handle_error(self):\n        \"\"\"Test handling an error message\"\"\"\n        # setup\n        dialogue = self.prepare_skill_dialogue(\n            self.ledger_api_dialogues, self.list_of_ledger_api_messages[2:3]\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=dialogue,\n            performative=LedgerApiMessage.Performative.ERROR,\n            code=1,\n        )\n\n        # operation\n        with patch.object(self.ledger_api_handler.context.logger, \"log\") as mock_logger:\n            self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received ledger_api error message={incoming_message} in dialogue={dialogue}.\",\n        )\n\n        self.assert_quantity_in_outbox(0)\n\n    def test__handle_invalid(self):\n        \"\"\"Test handling an invalid performative\"\"\"\n        # setup\n        dialogue = self.prepare_skill_dialogue(\n            self.ledger_api_dialogues, self.list_of_ledger_api_messages[3:4]\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=dialogue,\n            performative=LedgerApiMessage.Performative.STATE,\n            ledger_id=ETHEREUM_LEDGER_ID,\n            state=LedgerApiMessage.State(ETHEREUM_LEDGER_ID, {}),\n        )\n\n        # operation\n        with patch.object(self.ledger_api_handler.context.logger, \"log\") as mock_logger:\n            self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"cannot handle ledger_api message of performative={incoming_message.performative} in dialogue={dialogue}.\",\n        )\n\n        self.assert_quantity_in_outbox(0)\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the ledger_api handler.\"\"\"\n        assert self.ledger_api_handler.teardown() is None\n        self.assert_quantity_in_outbox(0)\n\n\nclass TestContractApiHandler(BaseSkillTestCase):\n    \"\"\"Test contract_api handler of simple oracle.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"simple_oracle\")\n    is_agent_to_agent_messages = False\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.contract_api_handler = cast(\n            ContractApiHandler, cls._skill.skill_context.handlers.contract_api\n        )\n        cls.strategy = cast(Strategy, cls._skill.skill_context.strategy)\n        cls.logger = cls.contract_api_handler.context.logger\n\n        cls.contract_api_dialogues = cast(\n            ContractApiDialogues, cls._skill.skill_context.contract_api_dialogues\n        )\n\n        cls.contract_id = \"some_contract_id\"\n        cls.contract_address = \"some_contract_address,\"\n        cls.callable = \"some_callable\"\n        cls.kwargs = Kwargs({\"some_key\": \"some_value\"})\n\n        cls.state = State(\"some_ledger_id\", {\"some_key\": \"some_value\"})\n        cls.terms = Terms(\n            ledger_id=\"some_ledger_id\",\n            sender_address=\"some_sender_address\",\n            counterparty_address=\"some_counterparty\",\n            amount_by_currency_id={\"1\": -10},\n            quantities_by_good_id={},\n            is_sender_payable_tx_fee=True,\n            nonce=\"some_none\",\n            fee_by_currency_id={\"1\": 100},\n        )\n        cls.list_of_contract_api_messages = (\n            DialogueMessage(\n                ContractApiMessage.Performative.GET_DEPLOY_TRANSACTION,\n                {\n                    \"ledger_id\": ETHEREUM_LEDGER_ID,\n                    \"contract_id\": cls.contract_id,\n                    \"callable\": cls.callable,\n                    \"kwargs\": cls.kwargs,\n                },\n            ),\n        )\n        cls.info = {\"ethereum_address\": \"some_ethereum_address\"}\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the contract_api handler.\"\"\"\n        assert self.contract_api_handler.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle_unidentified_dialogue(self):\n        \"\"\"Test the _handle_unidentified_dialogue method of the contract_api handler.\"\"\"\n        # setup\n        incorrect_dialogue_reference = (\"\", \"\")\n        incoming_message = self.build_incoming_message(\n            message_type=ContractApiMessage,\n            dialogue_reference=incorrect_dialogue_reference,\n            performative=ContractApiMessage.Performative.STATE,\n            state=self.state,\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.contract_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received invalid contract_api message={incoming_message}, unidentified dialogue.\",\n        )\n\n    def test_handle_raw_transaction(self):\n        \"\"\"Test the _handle_raw_transaction method of the contract_api handler.\"\"\"\n        # setup\n        contract_api_dialogue = cast(\n            ContractApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.contract_api_dialogues,\n                messages=self.list_of_contract_api_messages[:1],\n            ),\n        )\n        contract_api_dialogue.terms = self.terms\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=contract_api_dialogue,\n            performative=ContractApiMessage.Performative.RAW_TRANSACTION,\n            raw_transaction=ContractApiMessage.RawTransaction(ETHEREUM_LEDGER_ID, {}),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.contract_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received raw transaction={incoming_message}\",\n        )\n        mock_logger.assert_any_call(\n            logging.INFO,\n            \"proposing the transaction to the decision maker. Waiting for confirmation ...\",\n        )\n\n        self.assert_quantity_in_decision_making_queue(1)\n\n    def test_handle_error(self):\n        \"\"\"Test the _handle_error method of the contract_api handler.\"\"\"\n        # setup\n        contract_api_dialogue = cast(\n            ContractApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.contract_api_dialogues,\n                messages=self.list_of_contract_api_messages[:1],\n            ),\n        )\n\n        incoming_message = cast(\n            ContractApiMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=contract_api_dialogue,\n                performative=ContractApiMessage.Performative.ERROR,\n                data=b\"some_data\",\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.contract_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received ledger_api error message={incoming_message} in dialogue={contract_api_dialogue}.\",\n        )\n\n    def test_handle_invalid(self):\n        \"\"\"Test the _handle_invalid method of the contract_api handler.\"\"\"\n        # setup\n        invalid_performative = ContractApiMessage.Performative.GET_DEPLOY_TRANSACTION\n        incoming_message = self.build_incoming_message(\n            message_type=ContractApiMessage,\n            dialogue_reference=(\"1\", \"\"),\n            performative=invalid_performative,\n            ledger_id=ETHEREUM_LEDGER_ID,\n            contract_id=self.contract_id,\n            callable=self.callable,\n            kwargs=self.kwargs,\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.contract_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"cannot handle contract_api message of performative={invalid_performative} in dialogue={self.contract_api_dialogues.get_dialogue(incoming_message)}.\",\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the contract_api handler.\"\"\"\n        assert self.contract_api_handler.teardown() is None\n        self.assert_quantity_in_outbox(0)\n\n\nclass TestSigningHandler(BaseSkillTestCase):\n    \"\"\"Test signing handler of simple oracle.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"simple_oracle\")\n    is_agent_to_agent_messages = False\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.signing_handler = cast(\n            SigningHandler, cls._skill.skill_context.handlers.signing\n        )\n        cls.ledger_api_dialogues = cast(\n            LedgerApiDialogues, cls._skill.skill_context.ledger_api_dialogues\n        )\n        cls.signing_dialogues = cast(\n            SigningDialogues, cls._skill.skill_context.signing_dialogues\n        )\n        cls.logger = cls.signing_handler.context.logger\n\n        cls.terms = Terms(\n            \"some_ledger_id\",\n            cls._skill.skill_context.agent_address,\n            \"counterprty\",\n            {\"currency_id\": 50},\n            {\"good_id\": -10},\n            \"some_nonce\",\n        )\n        cls.list_of_signing_messages = (\n            DialogueMessage(\n                SigningMessage.Performative.SIGN_TRANSACTION,\n                {\n                    \"terms\": cls.terms,\n                    \"raw_transaction\": SigningMessage.RawTransaction(\n                        \"some_ledger_id\", {\"some_key\": \"some_value\"}\n                    ),\n                },\n            ),\n        )\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the signing handler.\"\"\"\n        assert self.signing_handler.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle_unidentified_dialogue(self):\n        \"\"\"Test the _handle_unidentified_dialogue method of the signing handler.\"\"\"\n        # setup\n        incorrect_dialogue_reference = (\"\", \"\")\n        incoming_message = self.build_incoming_message(\n            message_type=SigningMessage,\n            dialogue_reference=incorrect_dialogue_reference,\n            performative=SigningMessage.Performative.ERROR,\n            error_code=SigningMessage.ErrorCode.UNSUCCESSFUL_MESSAGE_SIGNING,\n            to=str(self.skill.skill_context.skill_id),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.signing_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received invalid signing message={incoming_message}, unidentified dialogue.\",\n        )\n\n    def test_handle_signed_transaction(\n        self,\n    ):\n        \"\"\"Test the _handle_signed_transaction method of the signing handler.\"\"\"\n        # setup\n        signing_counterparty = self.skill.skill_context.decision_maker_address\n        signing_dialogue = cast(\n            SigningDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.signing_dialogues,\n                messages=self.list_of_signing_messages[:1],\n                counterparty=signing_counterparty,\n            ),\n        )\n        incoming_message = cast(\n            SigningMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=signing_dialogue,\n                performative=SigningMessage.Performative.SIGNED_TRANSACTION,\n                signed_transaction=SigningMessage.SignedTransaction(\n                    \"some_ledger_id\", {\"some_key\": \"some_value\"}\n                ),\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.signing_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(logging.INFO, \"transaction signing was successful.\")\n\n        self.assert_quantity_in_outbox(1)\n        message = self.get_message_from_outbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=LedgerApiMessage,\n            performative=LedgerApiMessage.Performative.SEND_SIGNED_TRANSACTION,\n            to=str(LEDGER_CONNECTION_PUBLIC_ID),\n            sender=str(self.skill.skill_context.skill_id),\n            signed_transaction=incoming_message.signed_transaction,\n        )\n        assert has_attributes, error_str\n\n        assert (\n            cast(\n                LedgerApiDialogue, self.ledger_api_dialogues.get_dialogue(message)\n            ).associated_signing_dialogue\n            == signing_dialogue\n        )\n\n        mock_logger.assert_any_call(logging.INFO, \"sending transaction to ledger.\")\n\n    def test_handle_error(self):\n        \"\"\"Test the _handle_error method of the signing handler.\"\"\"\n        # setup\n        signing_counterparty = self.skill.skill_context.decision_maker_address\n        signing_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.signing_dialogues,\n            messages=self.list_of_signing_messages[:1],\n            counterparty=signing_counterparty,\n        )\n        incoming_message = cast(\n            SigningMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=signing_dialogue,\n                performative=SigningMessage.Performative.ERROR,\n                error_code=SigningMessage.ErrorCode.UNSUCCESSFUL_TRANSACTION_SIGNING,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.signing_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"transaction signing was not successful. Error_code={incoming_message.error_code} in dialogue={signing_dialogue}\",\n        )\n\n    def test_handle_invalid(self):\n        \"\"\"Test the _handle_invalid method of the signing handler.\"\"\"\n        # setup\n        invalid_performative = SigningMessage.Performative.SIGN_TRANSACTION\n        incoming_message = self.build_incoming_message(\n            message_type=SigningMessage,\n            dialogue_reference=(\"1\", \"\"),\n            performative=invalid_performative,\n            terms=self.terms,\n            raw_transaction=SigningMessage.RawTransaction(\n                \"some_ledger_id\", {\"some_key\": \"some_value\"}\n            ),\n            to=str(self.skill.skill_context.skill_id),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.signing_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"cannot handle signing message of performative={invalid_performative} in dialogue={self.signing_dialogues.get_dialogue(incoming_message)}.\",\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the signing handler.\"\"\"\n        assert self.signing_handler.teardown() is None\n        self.assert_quantity_in_outbox(0)\n\n\nclass TestPrometheusHandler(BaseSkillTestCase):\n    \"\"\"Test prometheus handler of simple_oracle skill.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"simple_oracle\")\n    is_agent_to_agent_messages = False\n\n    @classmethod\n    def setup(cls, **kwargs):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.prometheus_handler = cast(\n            PrometheusHandler, cls._skill.skill_context.handlers.prometheus\n        )\n        cls.logger = cls._skill.skill_context.logger\n\n        cls.strategy = cast(Strategy, cls._skill.skill_context.strategy)\n\n        cls.prometheus_dialogues = cast(\n            PrometheusDialogues, cls._skill.skill_context.prometheus_dialogues\n        )\n\n        cls.list_of_messages = (\n            DialogueMessage(\n                PrometheusMessage.Performative.ADD_METRIC,\n                {\n                    \"type\": \"Gauge\",\n                    \"title\": \"some_title\",\n                    \"description\": \"some_description\",\n                    \"labels\": {},\n                },\n            ),\n        )\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the prometheus handler.\"\"\"\n        assert self.prometheus_handler.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle_response(self):\n        \"\"\"Test the _handle_response method of the prometheus handler to a valid response.\"\"\"\n        # setup\n        prometheus_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.prometheus_dialogues,\n            messages=self.list_of_messages[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=prometheus_dialogue,\n            performative=PrometheusMessage.Performative.RESPONSE,\n            code=200,\n            message=\"some_message\",\n        )\n\n        # handle message with logging\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.prometheus_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.DEBUG, \"Prometheus response (200): some_message\"\n        )\n\n    def test_handle_unidentified_dialogue(self):\n        \"\"\"Test the _handle_response method of the prometheus handler to an unidentified dialogue.\"\"\"\n        # setup\n        incoming_message = self.build_incoming_message(\n            message_type=PrometheusMessage,\n            performative=PrometheusMessage.Performative.RESPONSE,\n            code=200,\n            message=\"some_message\",\n        )\n\n        # handle message with logging\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.prometheus_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received invalid message={incoming_message}, unidentified dialogue.\",\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the prometheus handler.\"\"\"\n        assert self.prometheus_handler.teardown() is None\n        self.assert_quantity_in_outbox(0)\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_simple_oracle_client/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"The tests module contains the tests of the packages/skills/simple_oracle_client dir.\"\"\"\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_simple_oracle_client/test_behaviours.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the behaviour classes of the simple oracle client skill.\"\"\"\n\nimport logging\nfrom pathlib import Path\nfrom typing import cast\nfrom unittest.mock import patch\n\nfrom aea.test_tools.test_skill import BaseSkillTestCase\n\nfrom packages.fetchai.contracts.fet_erc20.contract import PUBLIC_ID as ERC20_PUBLIC_ID\nfrom packages.fetchai.contracts.oracle_client.contract import (\n    PUBLIC_ID as CLIENT_CONTRACT_PUBLIC_ID,\n)\nfrom packages.fetchai.protocols.contract_api.message import ContractApiMessage\nfrom packages.fetchai.skills.simple_oracle_client.behaviours import (\n    SimpleOracleClientBehaviour,\n)\nfrom packages.fetchai.skills.simple_oracle_client.strategy import Strategy\n\nfrom tests.conftest import ROOT_DIR\n\n\nDEFAULT_ADDRESS = \"0x0000000000000000000000000000000000000000\"\nETHEREUM_LEDGER_ID = \"ethereum\"\nFETCHAI_LEDGER_ID = \"fetchai\"\n\n\nclass TestSkillBehaviour(BaseSkillTestCase):\n    \"\"\"Test behaviours of simple oracle client.\"\"\"\n\n    path_to_skill = Path(\n        ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"simple_oracle_client\"\n    )\n\n    @classmethod\n    def setup(cls, **kwargs):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.simple_oracle_client_behaviour = cast(\n            SimpleOracleClientBehaviour,\n            cls._skill.skill_context.behaviours.simple_oracle_client_behaviour,\n        )\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the simple_oracle_client behaviour.\"\"\"\n        strategy = cast(Strategy, self.simple_oracle_client_behaviour.context.strategy)\n        strategy.oracle_contract_address = DEFAULT_ADDRESS\n        strategy.erc20_address = DEFAULT_ADDRESS\n        strategy.is_oracle_contract_set = True\n        strategy._ledger_id = ETHEREUM_LEDGER_ID\n\n        self.simple_oracle_client_behaviour.setup()\n\n        self.assert_quantity_in_outbox(1)\n\n        msg = cast(ContractApiMessage, self.get_message_from_outbox())\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=msg,\n            message_type=ContractApiMessage,\n            performative=ContractApiMessage.Performative.GET_DEPLOY_TRANSACTION,\n            contract_id=str(CLIENT_CONTRACT_PUBLIC_ID),\n            callable=\"get_deploy_transaction\",\n        )\n        assert has_attributes, error_str\n\n    def test_setup_with_contract_set(self):\n        \"\"\"Test the setup method of the simple_oracle_client behaviour for existing contract.\"\"\"\n        strategy = cast(Strategy, self.simple_oracle_client_behaviour.context.strategy)\n        strategy.client_contract_address = DEFAULT_ADDRESS\n        strategy.oracle_contract_address = DEFAULT_ADDRESS\n        strategy.erc20_address = DEFAULT_ADDRESS\n        strategy.is_client_contract_deployed = True\n        strategy.is_oracle_contract_set = True\n        strategy._ledger_id = ETHEREUM_LEDGER_ID\n\n        with patch.object(\n            self.simple_oracle_client_behaviour.context.logger, \"log\"\n        ) as mock_logger:\n            self.simple_oracle_client_behaviour.setup()\n        mock_logger.assert_any_call(\n            logging.INFO,\n            \"Fetch oracle client contract address already added\",\n        )\n        self.assert_quantity_in_outbox(0)\n\n    def test_act_pre_deploy(self):\n        \"\"\"Test the act method of the simple_oracle_client behaviour before contract is deployed.\"\"\"\n\n        with patch.object(\n            self.simple_oracle_client_behaviour.context.logger, \"log\"\n        ) as mock_logger:\n            self.simple_oracle_client_behaviour.act()\n        mock_logger.assert_any_call(\n            logging.INFO,\n            \"Oracle client contract not yet deployed\",\n        )\n        self.assert_quantity_in_outbox(0)\n\n    def test_act_approve_transactions(self):\n        \"\"\"Test the act method of the simple_oracle_client behaviour before transactions are approved.\"\"\"\n        strategy = cast(Strategy, self.simple_oracle_client_behaviour.context.strategy)\n        strategy.client_contract_address = DEFAULT_ADDRESS\n        strategy.oracle_contract_address = DEFAULT_ADDRESS\n        strategy.erc20_address = DEFAULT_ADDRESS\n        strategy.is_client_contract_deployed = True\n        strategy.is_oracle_contract_set = True\n        strategy._ledger_id = ETHEREUM_LEDGER_ID\n\n        self.simple_oracle_client_behaviour.act()\n        self.assert_quantity_in_outbox(1)\n\n        msg = cast(ContractApiMessage, self.get_message_from_outbox())\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=msg,\n            message_type=ContractApiMessage,\n            performative=ContractApiMessage.Performative.GET_RAW_TRANSACTION,\n            contract_id=str(ERC20_PUBLIC_ID),\n            contract_address=strategy.client_contract_address,\n            callable=\"get_approve_transaction\",\n        )\n        assert has_attributes, error_str\n\n    def test_act_query(self):\n        \"\"\"Test the act method of the simple_oracle_client behaviour for normal querying.\"\"\"\n        strategy = cast(Strategy, self.simple_oracle_client_behaviour.context.strategy)\n        strategy.client_contract_address = DEFAULT_ADDRESS\n        strategy.oracle_contract_address = DEFAULT_ADDRESS\n        strategy.erc20_address = DEFAULT_ADDRESS\n        strategy.is_client_contract_deployed = True\n        strategy.is_oracle_transaction_approved = True\n        strategy.is_oracle_contract_set = True\n        strategy._ledger_id = ETHEREUM_LEDGER_ID\n\n        self.simple_oracle_client_behaviour.act()\n        self.assert_quantity_in_outbox(1)\n        assert strategy.is_oracle_contract_set\n\n        msg = cast(ContractApiMessage, self.get_message_from_outbox())\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=msg,\n            message_type=ContractApiMessage,\n            performative=ContractApiMessage.Performative.GET_RAW_TRANSACTION,\n            contract_id=str(CLIENT_CONTRACT_PUBLIC_ID),\n            contract_address=strategy.client_contract_address,\n            callable=\"get_query_transaction\",\n        )\n        assert has_attributes, error_str\n\n    def test__request_contract_deploy_transaction(self):\n        \"\"\"Test that the _request_contract_deploy_transaction function sends the right message to the contract_api for ethereum ledger.\"\"\"\n        strategy = cast(Strategy, self.simple_oracle_client_behaviour.context.strategy)\n        strategy.oracle_contract_address = \"some_address\"\n        strategy._ledger_id = ETHEREUM_LEDGER_ID\n\n        self.simple_oracle_client_behaviour._request_contract_deploy_transaction()\n        self.assert_quantity_in_outbox(1)\n\n        kwargs = strategy.get_deploy_kwargs()\n        assert \"fetchOracleContractAddress\" in kwargs.body\n\n        msg = cast(ContractApiMessage, self.get_message_from_outbox())\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=msg,\n            message_type=ContractApiMessage,\n            performative=ContractApiMessage.Performative.GET_DEPLOY_TRANSACTION,\n            contract_id=str(CLIENT_CONTRACT_PUBLIC_ID),\n            callable=\"get_deploy_transaction\",\n            kwargs=kwargs,\n        )\n        assert has_attributes, error_str\n\n    def test__request_contract_store_transaction(self):\n        \"\"\"Test that the _request_contract_deploy_transaction function sends the right message to the contract_api for fetchai ledger.\"\"\"\n        strategy = cast(Strategy, self.simple_oracle_client_behaviour.context.strategy)\n        strategy.oracle_contract_address = \"some_address\"\n        strategy._ledger_id = FETCHAI_LEDGER_ID\n\n        self.simple_oracle_client_behaviour._request_contract_deploy_transaction()\n        self.assert_quantity_in_outbox(1)\n\n        kwargs = strategy.get_deploy_kwargs()\n        assert \"fetchOracleContractAddress\" not in kwargs.body\n\n        msg = cast(ContractApiMessage, self.get_message_from_outbox())\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=msg,\n            message_type=ContractApiMessage,\n            performative=ContractApiMessage.Performative.GET_DEPLOY_TRANSACTION,\n            contract_id=str(CLIENT_CONTRACT_PUBLIC_ID),\n            callable=\"get_deploy_transaction\",\n            kwargs=kwargs,\n        )\n        assert has_attributes, error_str\n\n    def test_teardown(self):\n        \"\"\"Test that the teardown method of the simple_oracle_client behaviour leaves no messages in the outbox.\"\"\"\n        assert self.simple_oracle_client_behaviour.teardown() is None\n        self.assert_quantity_in_outbox(0)\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_simple_oracle_client/test_handlers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the handler classes of the simple_data_request skill.\"\"\"\n\nimport logging\nfrom pathlib import Path\nfrom typing import cast\nfrom unittest.mock import patch\n\nfrom aea.helpers.transaction.base import Terms\nfrom aea.protocols.dialogue.base import DialogueMessage\nfrom aea.test_tools.test_skill import BaseSkillTestCase\n\nfrom packages.fetchai.connections.ledger.base import (\n    CONNECTION_ID as LEDGER_CONNECTION_PUBLIC_ID,\n)\nfrom packages.fetchai.contracts.oracle_client.contract import (\n    PUBLIC_ID as CONTRACT_PUBLIC_ID,\n)\nfrom packages.fetchai.protocols.contract_api.custom_types import Kwargs\nfrom packages.fetchai.protocols.contract_api.custom_types import (\n    Kwargs as ContractApiKwargs,\n)\nfrom packages.fetchai.protocols.contract_api.custom_types import State\nfrom packages.fetchai.protocols.contract_api.message import ContractApiMessage\nfrom packages.fetchai.protocols.ledger_api.custom_types import (\n    SignedTransaction,\n    TransactionDigest,\n    TransactionReceipt,\n)\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\nfrom packages.fetchai.protocols.signing.custom_types import RawTransaction\nfrom packages.fetchai.protocols.signing.message import SigningMessage\nfrom packages.fetchai.skills.simple_oracle_client.behaviours import (\n    SimpleOracleClientBehaviour,\n)\nfrom packages.fetchai.skills.simple_oracle_client.dialogues import (\n    ContractApiDialogue,\n    ContractApiDialogues,\n    LedgerApiDialogue,\n    LedgerApiDialogues,\n    SigningDialogue,\n    SigningDialogues,\n)\nfrom packages.fetchai.skills.simple_oracle_client.handlers import (\n    ContractApiHandler,\n    LedgerApiHandler,\n    SigningHandler,\n)\nfrom packages.fetchai.skills.simple_oracle_client.strategy import Strategy\n\nfrom tests.conftest import ROOT_DIR\n\n\nETHEREUM_LEDGER_ID = \"ethereum\"\nFETCHAI_LEDGER_ID = \"fetchai\"\nDEFAULT_TX = {\"some_tx_key\": \"some_tx_value\"}\nDEFAULT_TERMS = [\n    ETHEREUM_LEDGER_ID,\n    \"sender_address\",\n    \"counterparty_address\",\n    {},\n    {},\n    \"some_nonce\",\n]\nFETCHAI_DEPLOY_RECEIPT = {\n    \"logs\": [\n        {\n            \"events\": [\n                {\n                    \"attributes\": [\n                        {\"key\": \"code_id\", \"value\": \"8888\"},\n                        {\"key\": \"_contract_address\", \"value\": \"some_contract_address\"},\n                    ]\n                }\n            ]\n        }\n    ]\n}\n\n\nclass TestLedgerApiHandler(BaseSkillTestCase):\n    \"\"\"Test ledger_api handler of simple_oracle_client skill.\"\"\"\n\n    path_to_skill = Path(\n        ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"simple_oracle_client\"\n    )\n    is_agent_to_agent_messages = False\n\n    @classmethod\n    def setup(cls, **kwargs):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup(**kwargs)\n        cls.ledger_api_handler = cast(\n            LedgerApiHandler, cls._skill.skill_context.handlers.ledger_api\n        )\n        cls.logger = cls._skill.skill_context.logger\n        cls.simple_oracle_client_behaviour = cast(\n            SimpleOracleClientBehaviour,\n            cls._skill.skill_context.behaviours.simple_oracle_client_behaviour,\n        )\n        cls.ledger_api_dialogues = cast(\n            LedgerApiDialogues, cls._skill.skill_context.ledger_api_dialogues\n        )\n        cls.contract_api_dialogues = cast(\n            ContractApiDialogues, cls._skill.skill_context.contract_api_dialogues\n        )\n        cls.signing_dialogues = cast(\n            SigningDialogues, cls._skill.skill_context.signing_dialogues\n        )\n\n        cls.list_of_ledger_api_messages = (\n            DialogueMessage(\n                LedgerApiMessage.Performative.GET_BALANCE,\n                {\"ledger_id\": ETHEREUM_LEDGER_ID, \"address\": \"some_eth_address\"},\n            ),\n            DialogueMessage(\n                LedgerApiMessage.Performative.SEND_SIGNED_TRANSACTION,\n                {\n                    \"signed_transaction\": SignedTransaction(\n                        ETHEREUM_LEDGER_ID, DEFAULT_TX\n                    )\n                },\n            ),\n            DialogueMessage(\n                LedgerApiMessage.Performative.GET_TRANSACTION_RECEIPT,\n                {\n                    \"transaction_digest\": TransactionDigest(\n                        ETHEREUM_LEDGER_ID, \"some_digest\"\n                    )\n                },\n            ),\n            DialogueMessage(\n                LedgerApiMessage.Performative.GET_STATE,\n                {\n                    \"ledger_id\": ETHEREUM_LEDGER_ID,\n                    \"callable\": \"some_callable\",\n                    \"args\": (),\n                    \"kwargs\": LedgerApiMessage.Kwargs({}),\n                },\n            ),\n        )\n        cls.list_of_contract_api_messages = (\n            DialogueMessage(\n                ContractApiMessage.Performative.GET_DEPLOY_TRANSACTION,\n                {\n                    \"ledger_id\": ETHEREUM_LEDGER_ID,\n                    \"contract_id\": \"some_contract_id\",\n                    \"callable\": \"some_callable\",\n                    \"kwargs\": ContractApiKwargs({\"some_key\": \"some_value\"}),\n                },\n            ),\n            DialogueMessage(\n                ContractApiMessage.Performative.GET_DEPLOY_TRANSACTION,\n                {\n                    \"ledger_id\": FETCHAI_LEDGER_ID,\n                    \"contract_id\": \"some_contract_id\",\n                    \"callable\": \"some_callable\",\n                    \"kwargs\": ContractApiKwargs({\"some_key\": \"some_value\"}),\n                },\n            ),\n        )\n        cls.list_of_signing_messages = (\n            DialogueMessage(\n                SigningMessage.Performative.SIGN_TRANSACTION,\n                {\n                    \"terms\": Terms(*DEFAULT_TERMS),\n                    \"raw_transaction\": RawTransaction(ETHEREUM_LEDGER_ID, DEFAULT_TX),\n                },\n            ),\n        )\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the ledger_api handler.\"\"\"\n        assert self.ledger_api_handler.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle__handle_unidentified_dialogue(self):\n        \"\"\"Test handling an unidentified dialogoue\"\"\"\n        # setup\n        incorrect_dialogue_reference = (\"\", \"\")\n        incoming_message = self.build_incoming_message(\n            message_type=LedgerApiMessage,\n            dialogue_reference=incorrect_dialogue_reference,\n            performative=LedgerApiMessage.Performative.GET_BALANCE,\n            ledger_id=ETHEREUM_LEDGER_ID,\n            address=\"some_eth_address\",\n        )\n\n        # operation\n        with patch.object(self.ledger_api_handler.context.logger, \"log\") as mock_logger:\n            self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received invalid ledger_api message={incoming_message}, unidentified dialogue.\",\n        )\n\n        self.assert_quantity_in_outbox(0)\n\n    def test__handle_balance(self):\n        \"\"\"Test handling a balance\"\"\"\n        # setup\n        balance = 0\n        dialogue = self.prepare_skill_dialogue(\n            self.ledger_api_dialogues, self.list_of_ledger_api_messages[:1]\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=dialogue,\n            performative=LedgerApiMessage.Performative.BALANCE,\n            ledger_id=ETHEREUM_LEDGER_ID,\n            balance=balance,\n        )\n\n        # operation\n        with patch.object(self.ledger_api_handler.context.logger, \"log\") as mock_logger:\n            self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"starting balance on {ETHEREUM_LEDGER_ID} ledger={balance}.\",\n        )\n\n        self.assert_quantity_in_outbox(0)\n\n    def test__handle_transaction_digest(self):\n        \"\"\"Test handling a transaction digest\"\"\"\n        # setup\n        dialogue = self.prepare_skill_dialogue(\n            self.ledger_api_dialogues, self.list_of_ledger_api_messages[1:2]\n        )\n        digest = \"some_digest\"\n        transaction_digest = TransactionDigest(ETHEREUM_LEDGER_ID, digest)\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=dialogue,\n            performative=LedgerApiMessage.Performative.TRANSACTION_DIGEST,\n            transaction_digest=transaction_digest,\n        )\n\n        # operation\n        with patch.object(self.ledger_api_handler.context.logger, \"log\") as mock_logger:\n            self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"transaction was successfully submitted. Transaction digest=TransactionDigest: ledger_id={ETHEREUM_LEDGER_ID}, body={digest}\",\n        )\n\n        self.assert_quantity_in_outbox(1)\n\n    def test__handle_transaction_receipt_failed(self):\n        \"\"\"Test handling a transaction receipt\"\"\"\n        # setup\n        dialogue = self.prepare_skill_dialogue(\n            self.ledger_api_dialogues, self.list_of_ledger_api_messages[2:3]\n        )\n\n        receipt = {\"status\": 0}\n        transaction_receipt = TransactionReceipt(\n            ETHEREUM_LEDGER_ID, receipt, DEFAULT_TX\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=dialogue,\n            performative=LedgerApiMessage.Performative.TRANSACTION_RECEIPT,\n            transaction_receipt=transaction_receipt,\n        )\n\n        # operation\n        with patch.object(self.ledger_api_handler.context.logger, \"log\") as mock_logger:\n            self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.ERROR,\n            f\"transaction failed. Transaction receipt={transaction_receipt}\",\n        )\n\n        self.assert_quantity_in_outbox(0)\n\n    def test__handle_transaction_receipt_deploy(self):\n        \"\"\"Test handling a deploy transaction receipt\"\"\"\n        # setup\n        ledger_api_dialogue = self.prepare_skill_dialogue(\n            self.ledger_api_dialogues, self.list_of_ledger_api_messages[2:3]\n        )\n        contract_api_dialogue = self.prepare_skill_dialogue(\n            self.contract_api_dialogues, self.list_of_contract_api_messages[:1]\n        )\n        signing_dialogue = self.prepare_skill_dialogue(\n            self.signing_dialogues, self.list_of_signing_messages[:1]\n        )\n\n        ledger_id = ETHEREUM_LEDGER_ID\n        strategy = cast(Strategy, self.simple_oracle_client_behaviour.context.strategy)\n        strategy._ledger_id = ledger_id\n\n        contract_api_dialogue.terms = strategy.get_deploy_terms()\n        signing_dialogue.associated_contract_api_dialogue = contract_api_dialogue\n        ledger_api_dialogue.associated_signing_dialogue = signing_dialogue\n\n        receipt = {\"status\": 1, \"contractAddress\": \"some_contract_address\"}\n        transaction_receipt = TransactionReceipt(ledger_id, receipt, DEFAULT_TX)\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=ledger_api_dialogue,\n            performative=LedgerApiMessage.Performative.TRANSACTION_RECEIPT,\n            transaction_receipt=transaction_receipt,\n        )\n\n        # operation\n        with patch.object(self.ledger_api_handler.context.logger, \"log\") as mock_logger:\n            with patch(\n                \"aea.crypto.ledger_apis.LedgerApis.get_contract_address\",\n                return_value=\"some_contract_address\",\n            ):\n                self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"transaction was successfully settled. Transaction receipt={transaction_receipt}\",\n        )\n        mock_logger.assert_any_call(\n            logging.INFO,\n            \"Oracle client contract successfully deployed at address: some_contract_address\",\n        )\n\n        assert (\n            self.simple_oracle_client_behaviour.context.strategy.is_client_contract_deployed\n        ), \"Contract deployment status not set\"\n        self.assert_quantity_in_outbox(0)\n\n    def test__handle_transaction_receipt_store(self):\n        \"\"\"Test handling a store contract code transaction receipt\"\"\"\n        # setup\n        ledger_api_dialogue = self.prepare_skill_dialogue(\n            self.ledger_api_dialogues, self.list_of_ledger_api_messages[2:3]\n        )\n        contract_api_dialogue = self.prepare_skill_dialogue(\n            self.contract_api_dialogues, self.list_of_contract_api_messages[1:2]\n        )\n        signing_dialogue = self.prepare_skill_dialogue(\n            self.signing_dialogues, self.list_of_signing_messages[:1]\n        )\n\n        strategy = cast(Strategy, self.simple_oracle_client_behaviour.context.strategy)\n        strategy._ledger_id = \"fetchai\"\n        strategy.oracle_contract_address = \"some_oracle_address\"\n\n        contract_api_dialogue.terms = strategy.get_deploy_terms()\n        assert contract_api_dialogue.terms.kwargs[\"label\"] == \"store\"\n\n        signing_dialogue.associated_contract_api_dialogue = contract_api_dialogue\n        ledger_api_dialogue.associated_signing_dialogue = signing_dialogue\n\n        transaction_receipt = TransactionReceipt(\n            FETCHAI_LEDGER_ID, FETCHAI_DEPLOY_RECEIPT, DEFAULT_TX\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=ledger_api_dialogue,\n            performative=LedgerApiMessage.Performative.TRANSACTION_RECEIPT,\n            transaction_receipt=transaction_receipt,\n        )\n\n        # operation\n        with patch.object(self.ledger_api_handler.context.logger, \"log\") as mock_logger:\n            self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"transaction was successfully settled. Transaction receipt={transaction_receipt}\",\n        )\n        self.assert_quantity_in_outbox(1)\n        msg = cast(ContractApiMessage, self.get_message_from_outbox())\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=msg,\n            message_type=ContractApiMessage,\n            performative=ContractApiMessage.Performative.GET_DEPLOY_TRANSACTION,\n            ledger_id=\"fetchai\",\n            contract_id=str(CONTRACT_PUBLIC_ID),\n            callable=\"get_deploy_transaction\",\n            kwargs=ContractApiMessage.Kwargs(\n                {\n                    \"label\": \"OracleContract\",\n                    \"init_msg\": {\n                        \"oracle_contract_address\": strategy.oracle_contract_address\n                    },\n                    \"gas\": strategy.gas_limit_instantiate,\n                    \"tx_fee\": strategy.gas_price * strategy.gas_limit_instantiate,\n                    \"amount\": 0,\n                    \"code_id\": 8888,\n                    \"deployer_address\": \"test_agent_address\",\n                }\n            ),\n        )\n        assert has_attributes, error_str\n\n    def test__handle_transaction_receipt_init(self):\n        \"\"\"Test handling a store contract code transaction receipt\"\"\"\n        # setup\n        ledger_api_dialogue = self.prepare_skill_dialogue(\n            self.ledger_api_dialogues, self.list_of_ledger_api_messages[2:3]\n        )\n        contract_api_dialogue = self.prepare_skill_dialogue(\n            self.contract_api_dialogues, self.list_of_contract_api_messages[1:2]\n        )\n        signing_dialogue = self.prepare_skill_dialogue(\n            self.signing_dialogues, self.list_of_signing_messages[:1]\n        )\n\n        ledger_id = FETCHAI_LEDGER_ID\n        strategy = cast(Strategy, self.simple_oracle_client_behaviour.context.strategy)\n        strategy._ledger_id = ledger_id\n\n        contract_api_dialogue.terms = strategy.get_deploy_terms(\n            is_init_transaction=True\n        )\n        signing_dialogue.associated_contract_api_dialogue = contract_api_dialogue\n        ledger_api_dialogue.associated_signing_dialogue = signing_dialogue\n\n        transaction_receipt = TransactionReceipt(\n            ledger_id, FETCHAI_DEPLOY_RECEIPT, DEFAULT_TX\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=ledger_api_dialogue,\n            performative=LedgerApiMessage.Performative.TRANSACTION_RECEIPT,\n            transaction_receipt=transaction_receipt,\n        )\n\n        # operation\n        with patch.object(self.ledger_api_handler.context.logger, \"log\") as mock_logger:\n            self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"transaction was successfully settled. Transaction receipt={transaction_receipt}\",\n        )\n        mock_logger.assert_any_call(\n            logging.INFO,\n            \"Oracle client contract successfully deployed at address: some_contract_address\",\n        )\n\n        assert (\n            self.simple_oracle_client_behaviour.context.strategy.is_client_contract_deployed\n        ), \"Contract deployment status not set\"\n        self.assert_quantity_in_outbox(0)\n\n    def test__handle_transaction_receipt_approve(self):\n        \"\"\"Test handling an approve transaction receipt\"\"\"\n        # setup\n        ledger_api_dialogue = self.prepare_skill_dialogue(\n            self.ledger_api_dialogues, self.list_of_ledger_api_messages[2:3]\n        )\n        contract_api_dialogue = self.prepare_skill_dialogue(\n            self.contract_api_dialogues, self.list_of_contract_api_messages[:1]\n        )\n        signing_dialogue = self.prepare_skill_dialogue(\n            self.signing_dialogues, self.list_of_signing_messages[:1]\n        )\n\n        terms = Terms(*DEFAULT_TERMS, label=\"approve\")\n\n        strategy = cast(Strategy, self.simple_oracle_client_behaviour.context.strategy)\n        strategy.is_client_contract_deployed = True\n\n        contract_api_dialogue.terms = terms\n        signing_dialogue.associated_contract_api_dialogue = contract_api_dialogue\n        ledger_api_dialogue.associated_signing_dialogue = signing_dialogue\n\n        receipt = {\"status\": 1, \"contractAddress\": \"some_contract_address\"}\n        transaction_receipt = TransactionReceipt(\n            ETHEREUM_LEDGER_ID, receipt, DEFAULT_TX\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=ledger_api_dialogue,\n            performative=LedgerApiMessage.Performative.TRANSACTION_RECEIPT,\n            transaction_receipt=transaction_receipt,\n        )\n\n        # operation\n        with patch.object(self.ledger_api_handler.context.logger, \"log\") as mock_logger:\n            self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"transaction was successfully settled. Transaction receipt={transaction_receipt}\",\n        )\n        mock_logger.assert_any_call(\n            logging.INFO,\n            \"Oracle client transactions approved!\",\n        )\n\n        assert (\n            self.simple_oracle_client_behaviour.context.strategy.is_oracle_transaction_approved\n        ), \"Contract deployment status not set\"\n\n        self.assert_quantity_in_outbox(0)\n\n    def test__handle_transaction_receipt_query(self):\n        \"\"\"Test handling a query transaction receipt\"\"\"\n        # setup\n        ledger_api_dialogue = self.prepare_skill_dialogue(\n            self.ledger_api_dialogues, self.list_of_ledger_api_messages[2:3]\n        )\n        contract_api_dialogue = self.prepare_skill_dialogue(\n            self.contract_api_dialogues, self.list_of_contract_api_messages[:1]\n        )\n        signing_dialogue = self.prepare_skill_dialogue(\n            self.signing_dialogues, self.list_of_signing_messages[:1]\n        )\n\n        terms = Terms(*DEFAULT_TERMS, label=\"query\")\n\n        strategy = cast(Strategy, self.simple_oracle_client_behaviour.context.strategy)\n        strategy.is_client_contract_deployed = True\n        strategy.is_oracle_role_granted = True\n\n        contract_api_dialogue.terms = terms\n        signing_dialogue.associated_contract_api_dialogue = contract_api_dialogue\n        ledger_api_dialogue.associated_signing_dialogue = signing_dialogue\n\n        receipt = {\"status\": 1, \"contractAddress\": \"some_contract_address\"}\n        transaction_receipt = TransactionReceipt(\n            ETHEREUM_LEDGER_ID, receipt, DEFAULT_TX\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=ledger_api_dialogue,\n            performative=LedgerApiMessage.Performative.TRANSACTION_RECEIPT,\n            transaction_receipt=transaction_receipt,\n        )\n\n        # operation\n        with patch.object(self.ledger_api_handler.context.logger, \"log\") as mock_logger:\n            self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"transaction was successfully settled. Transaction receipt={transaction_receipt}\",\n        )\n        mock_logger.assert_any_call(\n            logging.INFO,\n            \"Oracle value successfully requested!\",\n        )\n\n        self.assert_quantity_in_outbox(0)\n\n    def test__handle_error(self):\n        \"\"\"Test handling an error message\"\"\"\n        # setup\n        dialogue = self.prepare_skill_dialogue(\n            self.ledger_api_dialogues, self.list_of_ledger_api_messages[2:3]\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=dialogue,\n            performative=LedgerApiMessage.Performative.ERROR,\n            code=1,\n        )\n\n        # operation\n        with patch.object(self.ledger_api_handler.context.logger, \"log\") as mock_logger:\n            self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received ledger_api error message={incoming_message} in dialogue={dialogue}.\",\n        )\n\n        self.assert_quantity_in_outbox(0)\n\n    def test__handle_invalid(self):\n        \"\"\"Test handling an invalid performative\"\"\"\n        # setup\n        dialogue = self.prepare_skill_dialogue(\n            self.ledger_api_dialogues, self.list_of_ledger_api_messages[3:4]\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=dialogue,\n            performative=LedgerApiMessage.Performative.STATE,\n            ledger_id=ETHEREUM_LEDGER_ID,\n            state=LedgerApiMessage.State(ETHEREUM_LEDGER_ID, {}),\n        )\n\n        # operation\n        with patch.object(self.ledger_api_handler.context.logger, \"log\") as mock_logger:\n            self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"cannot handle ledger_api message of performative={incoming_message.performative} in dialogue={dialogue}.\",\n        )\n\n        self.assert_quantity_in_outbox(0)\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the ledger_api handler.\"\"\"\n        assert self.ledger_api_handler.teardown() is None\n        self.assert_quantity_in_outbox(0)\n\n\nclass TestContractApiHandler(BaseSkillTestCase):\n    \"\"\"Test contract_api handler of simple oracle client.\"\"\"\n\n    path_to_skill = Path(\n        ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"simple_oracle_client\"\n    )\n    is_agent_to_agent_messages = False\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.contract_api_handler = cast(\n            ContractApiHandler, cls._skill.skill_context.handlers.contract_api\n        )\n        cls.strategy = cast(Strategy, cls._skill.skill_context.strategy)\n        cls.logger = cls.contract_api_handler.context.logger\n\n        cls.contract_api_dialogues = cast(\n            ContractApiDialogues, cls._skill.skill_context.contract_api_dialogues\n        )\n\n        cls.contract_id = \"some_contract_id\"\n        cls.contract_address = \"some_contract_address,\"\n        cls.callable = \"some_callable\"\n        cls.kwargs = Kwargs({\"some_key\": \"some_value\"})\n\n        cls.state = State(\"some_ledger_id\", {\"some_key\": \"some_value\"})\n        cls.terms = Terms(\n            ledger_id=\"some_ledger_id\",\n            sender_address=\"some_sender_address\",\n            counterparty_address=\"some_counterparty\",\n            amount_by_currency_id={\"1\": -10},\n            quantities_by_good_id={},\n            is_sender_payable_tx_fee=True,\n            nonce=\"some_none\",\n            fee_by_currency_id={\"1\": 100},\n        )\n        cls.list_of_contract_api_messages = (\n            DialogueMessage(\n                ContractApiMessage.Performative.GET_DEPLOY_TRANSACTION,\n                {\n                    \"ledger_id\": ETHEREUM_LEDGER_ID,\n                    \"contract_id\": cls.contract_id,\n                    \"callable\": cls.callable,\n                    \"kwargs\": cls.kwargs,\n                },\n            ),\n        )\n        cls.info = {\"ethereum_address\": \"some_ethereum_address\"}\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the contract_api handler.\"\"\"\n        assert self.contract_api_handler.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle_unidentified_dialogue(self):\n        \"\"\"Test the _handle_unidentified_dialogue method of the contract_api handler.\"\"\"\n        # setup\n        incorrect_dialogue_reference = (\"\", \"\")\n        incoming_message = self.build_incoming_message(\n            message_type=ContractApiMessage,\n            dialogue_reference=incorrect_dialogue_reference,\n            performative=ContractApiMessage.Performative.STATE,\n            state=self.state,\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.contract_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received invalid contract_api message={incoming_message}, unidentified dialogue.\",\n        )\n\n    def test_handle_raw_transaction(self):\n        \"\"\"Test the _handle_raw_transaction method of the contract_api handler.\"\"\"\n        # setup\n        contract_api_dialogue = cast(\n            ContractApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.contract_api_dialogues,\n                messages=self.list_of_contract_api_messages[:1],\n            ),\n        )\n        contract_api_dialogue.terms = self.terms\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=contract_api_dialogue,\n            performative=ContractApiMessage.Performative.RAW_TRANSACTION,\n            raw_transaction=ContractApiMessage.RawTransaction(ETHEREUM_LEDGER_ID, {}),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.contract_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received raw transaction={incoming_message}\",\n        )\n        mock_logger.assert_any_call(\n            logging.INFO,\n            \"proposing the transaction to the decision maker. Waiting for confirmation ...\",\n        )\n\n        self.assert_quantity_in_decision_making_queue(1)\n\n    def test_handle_error(self):\n        \"\"\"Test the _handle_error method of the contract_api handler.\"\"\"\n        # setup\n        contract_api_dialogue = cast(\n            ContractApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.contract_api_dialogues,\n                messages=self.list_of_contract_api_messages[:1],\n            ),\n        )\n\n        incoming_message = cast(\n            ContractApiMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=contract_api_dialogue,\n                performative=ContractApiMessage.Performative.ERROR,\n                data=b\"some_data\",\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.contract_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received ledger_api error message={incoming_message} in dialogue={contract_api_dialogue}.\",\n        )\n\n    def test_handle_invalid(self):\n        \"\"\"Test the _handle_invalid method of the contract_api handler.\"\"\"\n        # setup\n        invalid_performative = ContractApiMessage.Performative.GET_DEPLOY_TRANSACTION\n        incoming_message = self.build_incoming_message(\n            message_type=ContractApiMessage,\n            dialogue_reference=(\"1\", \"\"),\n            performative=invalid_performative,\n            ledger_id=ETHEREUM_LEDGER_ID,\n            contract_id=self.contract_id,\n            callable=self.callable,\n            kwargs=self.kwargs,\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.contract_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"cannot handle contract_api message of performative={invalid_performative} in dialogue={self.contract_api_dialogues.get_dialogue(incoming_message)}.\",\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the contract_api handler.\"\"\"\n        assert self.contract_api_handler.teardown() is None\n        self.assert_quantity_in_outbox(0)\n\n\nclass TestSigningHandler(BaseSkillTestCase):\n    \"\"\"Test signing handler of simple oracle client.\"\"\"\n\n    path_to_skill = Path(\n        ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"simple_oracle_client\"\n    )\n    is_agent_to_agent_messages = False\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.signing_handler = cast(\n            SigningHandler, cls._skill.skill_context.handlers.signing\n        )\n        cls.ledger_api_dialogues = cast(\n            LedgerApiDialogues, cls._skill.skill_context.ledger_api_dialogues\n        )\n        cls.signing_dialogues = cast(\n            SigningDialogues, cls._skill.skill_context.signing_dialogues\n        )\n        cls.logger = cls.signing_handler.context.logger\n\n        cls.terms = Terms(\n            \"some_ledger_id\",\n            cls._skill.skill_context.agent_address,\n            \"counterprty\",\n            {\"currency_id\": 50},\n            {\"good_id\": -10},\n            \"some_nonce\",\n        )\n        cls.list_of_signing_messages = (\n            DialogueMessage(\n                SigningMessage.Performative.SIGN_TRANSACTION,\n                {\n                    \"terms\": cls.terms,\n                    \"raw_transaction\": SigningMessage.RawTransaction(\n                        \"some_ledger_id\", {\"some_key\": \"some_value\"}\n                    ),\n                },\n            ),\n        )\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the signing handler.\"\"\"\n        assert self.signing_handler.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle_unidentified_dialogue(self):\n        \"\"\"Test the _handle_unidentified_dialogue method of the signing handler.\"\"\"\n        # setup\n        incorrect_dialogue_reference = (\"\", \"\")\n        incoming_message = self.build_incoming_message(\n            message_type=SigningMessage,\n            dialogue_reference=incorrect_dialogue_reference,\n            performative=SigningMessage.Performative.ERROR,\n            error_code=SigningMessage.ErrorCode.UNSUCCESSFUL_MESSAGE_SIGNING,\n            to=str(self.skill.skill_context.skill_id),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.signing_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received invalid signing message={incoming_message}, unidentified dialogue.\",\n        )\n\n    def test_handle_signed_transaction(\n        self,\n    ):\n        \"\"\"Test the _handle_signed_transaction method of the signing handler.\"\"\"\n        # setup\n        signing_counterparty = self.skill.skill_context.decision_maker_address\n        signing_dialogue = cast(\n            SigningDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.signing_dialogues,\n                messages=self.list_of_signing_messages[:1],\n                counterparty=signing_counterparty,\n            ),\n        )\n        incoming_message = cast(\n            SigningMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=signing_dialogue,\n                performative=SigningMessage.Performative.SIGNED_TRANSACTION,\n                signed_transaction=SigningMessage.SignedTransaction(\n                    \"some_ledger_id\", {\"some_key\": \"some_value\"}\n                ),\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.signing_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(logging.INFO, \"transaction signing was successful.\")\n\n        self.assert_quantity_in_outbox(1)\n        message = self.get_message_from_outbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=LedgerApiMessage,\n            performative=LedgerApiMessage.Performative.SEND_SIGNED_TRANSACTION,\n            to=str(LEDGER_CONNECTION_PUBLIC_ID),\n            sender=str(self.skill.skill_context.skill_id),\n            signed_transaction=incoming_message.signed_transaction,\n        )\n        assert has_attributes, error_str\n\n        assert (\n            cast(\n                LedgerApiDialogue, self.ledger_api_dialogues.get_dialogue(message)\n            ).associated_signing_dialogue\n            == signing_dialogue\n        )\n\n        mock_logger.assert_any_call(logging.INFO, \"sending transaction to ledger.\")\n\n    def test_handle_error(self):\n        \"\"\"Test the _handle_error method of the signing handler.\"\"\"\n        # setup\n        signing_counterparty = self.skill.skill_context.decision_maker_address\n        signing_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.signing_dialogues,\n            messages=self.list_of_signing_messages[:1],\n            counterparty=signing_counterparty,\n        )\n        incoming_message = cast(\n            SigningMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=signing_dialogue,\n                performative=SigningMessage.Performative.ERROR,\n                error_code=SigningMessage.ErrorCode.UNSUCCESSFUL_TRANSACTION_SIGNING,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.signing_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"transaction signing was not successful. Error_code={incoming_message.error_code} in dialogue={signing_dialogue}\",\n        )\n\n    def test_handle_invalid(self):\n        \"\"\"Test the _handle_invalid method of the signing handler.\"\"\"\n        # setup\n        invalid_performative = SigningMessage.Performative.SIGN_TRANSACTION\n        incoming_message = self.build_incoming_message(\n            message_type=SigningMessage,\n            dialogue_reference=(\"1\", \"\"),\n            performative=invalid_performative,\n            terms=self.terms,\n            raw_transaction=SigningMessage.RawTransaction(\n                \"some_ledger_id\", {\"some_key\": \"some_value\"}\n            ),\n            to=str(self.skill.skill_context.skill_id),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.signing_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"cannot handle signing message of performative={invalid_performative} in dialogue={self.signing_dialogues.get_dialogue(incoming_message)}.\",\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the signing handler.\"\"\"\n        assert self.signing_handler.teardown() is None\n        self.assert_quantity_in_outbox(0)\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_simple_seller/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"The tests module contains the tests of the packages/skills/simple_seller dir.\"\"\"\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_simple_seller/test_strategy.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the strategy class of the simple seller skill.\"\"\"\n\nimport logging\nfrom pathlib import Path\nfrom typing import cast\nfrom unittest.mock import patch\n\nimport pytest\n\nfrom aea.test_tools.test_skill import BaseSkillTestCase\n\nfrom packages.fetchai.skills.simple_seller.strategy import Strategy\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass TestStrategy(BaseSkillTestCase):\n    \"\"\"Test Strategy of simple seller.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"simple_seller\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        cls.mocked_name_of_data = \"some_name_for_data\"\n        config_overrides = {\n            \"models\": {\n                \"strategy\": {\"args\": {\"shared_state_key\": cls.mocked_name_of_data}}\n            }\n        }\n\n        super().setup(config_overrides=config_overrides)\n\n        cls.strategy = cast(Strategy, cls._skill.skill_context.strategy)\n\n        cls.mocked_data_1 = (\n            b'[{\"type_1\": \"data_1\", \"type_2\": \"data_2\", \"type_3\": \"data_3\"}]'\n        )\n        cls.mocked_data_2 = (\n            b'{\"type_1\": \"data_1\", \"type_2\": \"data_2\", \"type_3\": \"data_3\"}'\n        )\n        cls.mocked_data_3 = b\"some_non_jason_data\"\n\n    def test__init__(self):\n        \"\"\"Test the __init__ method of the Strategy class.\"\"\"\n        with pytest.raises(ValueError, match=\"No shared_state_key provided!\"):\n            Strategy(shared_state_key=None)\n\n    def test_collect_from_data_source_i(self):\n        \"\"\"Test the collect_from_data_source method of the Strategy class where the data is NOT a dictionary.\"\"\"\n        self.skill.skill_context._agent_context._shared_state[\n            self.mocked_name_of_data\n        ] = self.mocked_data_1\n        expected_formatted_data = {\n            \"data\": '[{\"type_1\": \"data_1\", \"type_2\": \"data_2\", \"type_3\": \"data_3\"}]'\n        }\n\n        actual_data = self.strategy.collect_from_data_source()\n        assert actual_data == expected_formatted_data\n\n    def test_collect_from_data_source_ii(self):\n        \"\"\"Test the collect_from_data_source method of the Strategy class where the data IS a dictionary.\"\"\"\n        self.skill.skill_context._agent_context._shared_state[\n            self.mocked_name_of_data\n        ] = self.mocked_data_2\n        expected_formatted_data = {\n            \"type_1\": \"data_1\",\n            \"type_2\": \"data_2\",\n            \"type_3\": \"data_3\",\n        }\n\n        actual_data = self.strategy.collect_from_data_source()\n        assert actual_data == expected_formatted_data\n\n    def test_format_data_exception(self):\n        \"\"\"Test the _format_data method of the Strategy class where JSONDecodeError raises.\"\"\"\n        with patch.object(self.skill.skill_context.logger, \"log\") as mock_logger:\n            self.strategy._format_data(self.mocked_data_3)\n\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"error when loading json: {'Expecting value: line 1 column 1 (char 0)'}\",\n        )\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_simple_service_registration/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"The tests module contains the tests of the packages/skills/simple_service_registration dir.\"\"\"\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_simple_service_registration/test_behaviours.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the behaviour classes of the simple_service_registration skill.\"\"\"\n\nimport logging\nfrom pathlib import Path\nfrom typing import cast\nfrom unittest.mock import patch\n\nfrom aea.helpers.search.models import Description\nfrom aea.test_tools.test_skill import BaseSkillTestCase\n\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.skills.simple_service_registration.behaviours import (\n    ServiceRegistrationBehaviour,\n)\nfrom packages.fetchai.skills.simple_service_registration.strategy import Strategy\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass TestServiceRegistrationBehaviour(BaseSkillTestCase):\n    \"\"\"Test service behaviour of simple_service_registration.\"\"\"\n\n    path_to_skill = Path(\n        ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"simple_service_registration\"\n    )\n    is_agent_to_agent_messages = False\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.service_behaviour = cast(\n            ServiceRegistrationBehaviour, cls._skill.skill_context.behaviours.service\n        )\n        cls.strategy = cast(Strategy, cls._skill.skill_context.strategy)\n        cls.logger = cls._skill.skill_context.logger\n\n        cls.mocked_description_1 = Description({\"foo1\": 1, \"bar1\": 2})\n        cls.mocked_description_2 = Description({\"foo2\": 1, \"bar2\": 2})\n\n        cls.registration_message = OefSearchMessage(\n            dialogue_reference=(\"\", \"\"),\n            performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n            service_description=\"some_service_description\",\n        )\n        cls.registration_message.sender = str(cls._skill.skill_context.skill_id)\n        cls.registration_message.to = cls._skill.skill_context.search_service_address\n\n        cls.mocked_description = Description({\"foo1\": 1, \"bar1\": 2})\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the service behaviour.\"\"\"\n        # operation\n        with patch.object(\n            self.strategy,\n            \"get_location_description\",\n            return_value=self.mocked_description_1,\n        ):\n            with patch.object(\n                self.strategy,\n                \"get_register_service_description\",\n                return_value=self.mocked_description_2,\n            ):\n                with patch.object(self.logger, \"log\") as mock_logger:\n                    self.service_behaviour.setup()\n\n        # after\n        self.assert_quantity_in_outbox(1)\n\n        # _register_agent\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=OefSearchMessage,\n            performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n            to=self.skill.skill_context.search_service_address,\n            sender=str(self.skill.skill_context.skill_id),\n            service_description=self.mocked_description_1,\n        )\n        assert has_attributes, error_str\n\n        mock_logger.assert_any_call(logging.INFO, \"registering agent on SOEF.\")\n\n    def test_act_i(self):\n        \"\"\"Test the act method of the service behaviour where failed_registration_msg IS None.\"\"\"\n        # setup\n        self.service_behaviour.failed_registration_msg = None\n\n        # operation\n        assert self.service_behaviour.act() is None\n\n        # after\n        self.assert_quantity_in_outbox(0)\n\n    def test_act_ii(self):\n        \"\"\"Test the act method of the service behaviour where failed_registration_msg is NOT None.\"\"\"\n        # setup\n        self.service_behaviour.failed_registration_msg = self.registration_message\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.service_behaviour.act()\n\n        # after\n        self.assert_quantity_in_outbox(1)\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=type(self.registration_message),\n            performative=self.registration_message.performative,\n            to=self.registration_message.to,\n            sender=str(self.skill.skill_context.skill_id),\n            service_description=self.registration_message.service_description,\n        )\n        assert has_attributes, error_str\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"Retrying registration on SOEF. Retry {self.service_behaviour._nb_retries} out of {self.service_behaviour._max_soef_registration_retries}.\",\n        )\n        assert self.service_behaviour.failed_registration_msg is None\n\n    def test_act_iii(self):\n        \"\"\"Test the act method of the service behaviour where failed_registration_msg is NOT None and max retries is reached.\"\"\"\n        # setup\n        self.service_behaviour.failed_registration_msg = self.registration_message\n        self.service_behaviour._max_soef_registration_retries = 2\n        self.service_behaviour._nb_retries = 2\n\n        # operation\n        self.service_behaviour.act()\n\n        # after\n        self.assert_quantity_in_outbox(0)\n        assert self.skill.skill_context.is_active is False\n\n    def test_register_service(self):\n        \"\"\"Test the register_service method of the service_registration behaviour.\"\"\"\n        # operation\n        with patch.object(\n            self.strategy,\n            \"get_register_service_description\",\n            return_value=self.mocked_description,\n        ):\n            with patch.object(self.logger, \"log\") as mock_logger:\n                self.service_behaviour.register_service()\n\n        # after\n        self.assert_quantity_in_outbox(1)\n\n        message = self.get_message_from_outbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=OefSearchMessage,\n            performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n            to=self.skill.skill_context.search_service_address,\n            sender=str(self.skill.skill_context.skill_id),\n            service_description=self.mocked_description,\n        )\n        assert has_attributes, error_str\n        mock_logger.assert_any_call(\n            logging.INFO, \"registering agent's service on the SOEF.\"\n        )\n\n    def test_register_genus(self):\n        \"\"\"Test the register_genus method of the service_registration behaviour.\"\"\"\n        # operation\n        with patch.object(\n            self.strategy,\n            \"get_register_personality_description\",\n            return_value=self.mocked_description,\n        ):\n            with patch.object(self.logger, \"log\") as mock_logger:\n                self.service_behaviour.register_genus()\n\n        # after\n        self.assert_quantity_in_outbox(1)\n\n        message = self.get_message_from_outbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=OefSearchMessage,\n            performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n            to=self.skill.skill_context.search_service_address,\n            sender=str(self.skill.skill_context.skill_id),\n            service_description=self.mocked_description,\n        )\n        assert has_attributes, error_str\n        mock_logger.assert_any_call(\n            logging.INFO, \"registering agent's personality genus on the SOEF.\"\n        )\n\n    def test_register_classification(self):\n        \"\"\"Test the register_classification method of the service_registration behaviour.\"\"\"\n        # operation\n        with patch.object(\n            self.strategy,\n            \"get_register_classification_description\",\n            return_value=self.mocked_description,\n        ):\n            with patch.object(self.logger, \"log\") as mock_logger:\n                self.service_behaviour.register_classification()\n\n        # after\n        self.assert_quantity_in_outbox(1)\n\n        message = self.get_message_from_outbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=OefSearchMessage,\n            performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n            to=self.skill.skill_context.search_service_address,\n            sender=str(self.skill.skill_context.skill_id),\n            service_description=self.mocked_description,\n        )\n        assert has_attributes, error_str\n        mock_logger.assert_any_call(\n            logging.INFO, \"registering agent's personality classification on the SOEF.\"\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the service behaviour.\"\"\"\n        # operation\n        with patch.object(\n            self.strategy,\n            \"get_location_description\",\n            return_value=self.mocked_description_1,\n        ):\n            with patch.object(\n                self.strategy,\n                \"get_unregister_service_description\",\n                return_value=self.mocked_description_2,\n            ):\n                with patch.object(self.logger, \"log\") as mock_logger:\n                    self.service_behaviour.teardown()\n\n        # after\n        self.assert_quantity_in_outbox(2)\n\n        # _unregister_service\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=OefSearchMessage,\n            performative=OefSearchMessage.Performative.UNREGISTER_SERVICE,\n            to=self.skill.skill_context.search_service_address,\n            sender=str(self.skill.skill_context.skill_id),\n            service_description=self.mocked_description_2,\n        )\n        assert has_attributes, error_str\n\n        mock_logger.assert_any_call(logging.INFO, \"unregistering service from SOEF.\")\n\n        # _unregister_agent\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=OefSearchMessage,\n            performative=OefSearchMessage.Performative.UNREGISTER_SERVICE,\n            to=self.skill.skill_context.search_service_address,\n            sender=str(self.skill.skill_context.skill_id),\n            service_description=self.mocked_description_1,\n        )\n        assert has_attributes, error_str\n\n        mock_logger.assert_any_call(logging.INFO, \"unregistering agent from SOEF.\")\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_simple_service_registration/test_dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the dialogue classes of the simple_service_registration skill.\"\"\"\n\nfrom pathlib import Path\nfrom typing import cast\n\nfrom aea.helpers.search.models import Description\nfrom aea.test_tools.test_skill import BaseSkillTestCase\n\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.skills.simple_service_registration.dialogues import (\n    OefSearchDialogue,\n    OefSearchDialogues,\n)\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass TestDialogues(BaseSkillTestCase):\n    \"\"\"Test dialogue class of simple_service_registration.\"\"\"\n\n    path_to_skill = Path(\n        ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"simple_service_registration\"\n    )\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.oef_search_dialogues = cast(\n            OefSearchDialogues, cls._skill.skill_context.oef_search_dialogues\n        )\n        cls.mocked_description = Description({\"foo1\": 1, \"bar1\": 2})\n\n    def test_oef_search_dialogues(self):\n        \"\"\"Test the OefSearchDialogue class.\"\"\"\n        _, dialogue = self.oef_search_dialogues.create(\n            counterparty=self.skill.skill_context.search_service_address,\n            performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n            service_description=self.mocked_description,\n        )\n        assert dialogue.role == OefSearchDialogue.Role.AGENT\n        assert dialogue.self_address == str(self.skill.skill_context.skill_id)\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_simple_service_registration/test_handlers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the handler classes of the simple_service_registration skill.\"\"\"\n\nimport logging\nfrom pathlib import Path\nfrom typing import cast\nfrom unittest.mock import patch\n\nfrom aea.helpers.search.models import Attribute, DataModel, Description, Location\nfrom aea.protocols.dialogue.base import DialogueMessage\nfrom aea.test_tools.test_skill import BaseSkillTestCase\n\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.skills.simple_service_registration.behaviours import (\n    ServiceRegistrationBehaviour,\n)\nfrom packages.fetchai.skills.simple_service_registration.dialogues import (\n    OefSearchDialogues,\n)\nfrom packages.fetchai.skills.simple_service_registration.handlers import (\n    OefSearchHandler,\n)\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass TestOefSearchHandler(BaseSkillTestCase):\n    \"\"\"Test oef_search handler of simple_service_registration.\"\"\"\n\n    path_to_skill = Path(\n        ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"simple_service_registration\"\n    )\n    is_agent_to_agent_messages = False\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.oef_search_handler = cast(\n            OefSearchHandler, cls._skill.skill_context.handlers.oef_search\n        )\n        cls.service_registration_behaviour = cast(\n            ServiceRegistrationBehaviour,\n            cls._skill.skill_context.behaviours.service,\n        )\n        cls.logger = cls._skill.skill_context.logger\n\n        cls.oef_dialogues = cast(\n            OefSearchDialogues, cls._skill.skill_context.oef_search_dialogues\n        )\n\n        cls.data = b\"some_body\"\n        cls.mocked_description = Description({\"foo1\": 1, \"bar1\": 2})\n\n        cls.register_location_description = Description(\n            {\"location\": Location(51.5194, 0.1270)},\n            data_model=DataModel(\n                \"location_agent\", [Attribute(\"location\", Location, True)]\n            ),\n        )\n        cls.list_of_messages_register_location = (\n            DialogueMessage(\n                OefSearchMessage.Performative.REGISTER_SERVICE,\n                {\"service_description\": cls.register_location_description},\n                is_incoming=False,\n            ),\n        )\n\n        cls.register_service_description = Description(\n            {\"key\": \"some_key\", \"value\": \"some_value\"},\n            data_model=DataModel(\n                \"set_service_key\",\n                [Attribute(\"key\", str, True), Attribute(\"value\", str, True)],\n            ),\n        )\n        cls.list_of_messages_register_service = (\n            DialogueMessage(\n                OefSearchMessage.Performative.REGISTER_SERVICE,\n                {\"service_description\": cls.register_service_description},\n                is_incoming=False,\n            ),\n        )\n\n        cls.register_genus_description = Description(\n            {\"piece\": \"genus\", \"value\": \"some_value\"},\n            data_model=DataModel(\n                \"personality_agent\",\n                [Attribute(\"piece\", str, True), Attribute(\"value\", str, True)],\n            ),\n        )\n        cls.list_of_messages_register_genus = (\n            DialogueMessage(\n                OefSearchMessage.Performative.REGISTER_SERVICE,\n                {\"service_description\": cls.register_genus_description},\n                is_incoming=False,\n            ),\n        )\n\n        cls.register_classification_description = Description(\n            {\"piece\": \"classification\", \"value\": \"some_value\"},\n            data_model=DataModel(\n                \"personality_agent\",\n                [Attribute(\"piece\", str, True), Attribute(\"value\", str, True)],\n            ),\n        )\n        cls.list_of_messages_register_classification = (\n            DialogueMessage(\n                OefSearchMessage.Performative.REGISTER_SERVICE,\n                {\"service_description\": cls.register_classification_description},\n                is_incoming=False,\n            ),\n        )\n\n        cls.register_invalid_description = Description(\n            {\"piece\": \"classification\", \"value\": \"some_value\"},\n            data_model=DataModel(\n                \"some_different_name\",\n                [Attribute(\"piece\", str, True), Attribute(\"value\", str, True)],\n            ),\n        )\n        cls.list_of_messages_register_invalid = (\n            DialogueMessage(\n                OefSearchMessage.Performative.REGISTER_SERVICE,\n                {\"service_description\": cls.register_invalid_description},\n                is_incoming=False,\n            ),\n        )\n\n        cls.unregister_description = Description(\n            {\"key\": \"seller_service\"},\n            data_model=DataModel(\"remove\", [Attribute(\"key\", str, True)]),\n        )\n        cls.list_of_messages_unregister = (\n            DialogueMessage(\n                OefSearchMessage.Performative.UNREGISTER_SERVICE,\n                {\"service_description\": cls.unregister_description},\n                is_incoming=False,\n            ),\n        )\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the oef_search handler.\"\"\"\n        assert self.oef_search_handler.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle_unidentified_dialogue(self):\n        \"\"\"Test the _handle_unidentified_dialogue method of the oef_search handler.\"\"\"\n        # setup\n        incorrect_dialogue_reference = (\"\", \"\")\n        incoming_message = self.build_incoming_message(\n            message_type=OefSearchMessage,\n            dialogue_reference=incorrect_dialogue_reference,\n            performative=OefSearchMessage.Performative.OEF_ERROR,\n            oef_error_operation=OefSearchMessage.OefErrorOperation.REGISTER_SERVICE,\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received invalid oef_search message={incoming_message}, unidentified dialogue.\",\n        )\n\n    def test_handle_success_i(self):\n        \"\"\"Test the _handle_success method of the oef_search handler where the oef success targets register_service WITH location_agent data model description.\"\"\"\n        # setup\n        oef_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_dialogues,\n            messages=self.list_of_messages_register_location[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=oef_dialogue,\n            performative=OefSearchMessage.Performative.SUCCESS,\n            agents_info=OefSearchMessage.AgentsInfo({\"address\": {\"key\": \"value\"}}),\n        )\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            with patch.object(\n                self.service_registration_behaviour,\n                \"register_service\",\n            ) as mock_reg:\n                self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received oef_search success message={incoming_message} in dialogue={oef_dialogue}.\",\n        )\n        mock_reg.assert_called_once()\n\n    def test_handle_success_ii(self):\n        \"\"\"Test the _handle_success method of the oef_search handler where the oef success targets register_service WITH set_service_key data model description.\"\"\"\n        # setup\n        oef_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_dialogues,\n            messages=self.list_of_messages_register_service[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=oef_dialogue,\n            performative=OefSearchMessage.Performative.SUCCESS,\n            agents_info=OefSearchMessage.AgentsInfo({\"address\": {\"key\": \"value\"}}),\n        )\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            with patch.object(\n                self.service_registration_behaviour,\n                \"register_genus\",\n            ) as mock_reg:\n                self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received oef_search success message={incoming_message} in dialogue={oef_dialogue}.\",\n        )\n        mock_reg.assert_called_once()\n\n    def test_handle_success_iii(self):\n        \"\"\"Test the _handle_success method of the oef_search handler where the oef success targets register_service WITH personality_agent data model and genus value description.\"\"\"\n        # setup\n        oef_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_dialogues,\n            messages=self.list_of_messages_register_genus[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=oef_dialogue,\n            performative=OefSearchMessage.Performative.SUCCESS,\n            agents_info=OefSearchMessage.AgentsInfo({\"address\": {\"key\": \"value\"}}),\n        )\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            with patch.object(\n                self.service_registration_behaviour,\n                \"register_classification\",\n            ) as mock_reg:\n                self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received oef_search success message={incoming_message} in dialogue={oef_dialogue}.\",\n        )\n        mock_reg.assert_called_once()\n\n    def test_handle_success_iv(self):\n        \"\"\"Test the _handle_success method of the oef_search handler where the oef success targets register_service WITH personality_agent data model and classification value description.\"\"\"\n        # setup\n        oef_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_dialogues,\n            messages=self.list_of_messages_register_classification[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=oef_dialogue,\n            performative=OefSearchMessage.Performative.SUCCESS,\n            agents_info=OefSearchMessage.AgentsInfo({\"address\": {\"key\": \"value\"}}),\n        )\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received oef_search success message={incoming_message} in dialogue={oef_dialogue}.\",\n        )\n        mock_logger.assert_any_call(\n            logging.INFO,\n            \"the agent, with its genus and classification, and its service are successfully registered on the SOEF.\",\n        )\n\n    def test_handle_success_v(self):\n        \"\"\"Test the _handle_success method of the oef_search handler where the oef successtargets unregister_service.\"\"\"\n        # setup\n        oef_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_dialogues,\n            messages=self.list_of_messages_register_invalid[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=oef_dialogue,\n            performative=OefSearchMessage.Performative.SUCCESS,\n            agents_info=OefSearchMessage.AgentsInfo({\"address\": {\"key\": \"value\"}}),\n        )\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received oef_search success message={incoming_message} in dialogue={oef_dialogue}.\",\n        )\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"received soef SUCCESS message as a reply to the following unexpected message: {oef_dialogue.get_message_by_id(incoming_message.target)}\",\n        )\n\n    def test_handle_error_i(self):\n        \"\"\"Test the _handle_error method of the oef_search handler where the oef error targets register_service.\"\"\"\n        # setup\n        oef_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_dialogues,\n            messages=self.list_of_messages_register_location[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=oef_dialogue,\n            performative=OefSearchMessage.Performative.OEF_ERROR,\n            oef_error_operation=OefSearchMessage.OefErrorOperation.SEARCH_SERVICES,\n        )\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        self.assert_quantity_in_outbox(0)\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received oef_search error message={incoming_message} in dialogue={oef_dialogue}.\",\n        )\n        assert (\n            self.service_registration_behaviour.failed_registration_msg\n            == oef_dialogue.get_message_by_id(incoming_message.target)\n        )\n\n    def test_handle_error_ii(self):\n        \"\"\"Test the _handle_error method of the oef_search handler where the oef error does NOT target register_service.\"\"\"\n        # setup\n        oef_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_dialogues,\n            messages=self.list_of_messages_unregister[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=oef_dialogue,\n            performative=OefSearchMessage.Performative.OEF_ERROR,\n            oef_error_operation=OefSearchMessage.OefErrorOperation.SEARCH_SERVICES,\n        )\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        self.assert_quantity_in_outbox(0)\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received oef_search error message={incoming_message} in dialogue={oef_dialogue}.\",\n        )\n\n        assert self.service_registration_behaviour.failed_registration_msg is None\n\n    def test_handle_invalid(self):\n        \"\"\"Test the _handle_invalid method of the oef_search handler.\"\"\"\n        # setup\n        incoming_message = self.build_incoming_message(\n            message_type=OefSearchMessage,\n            performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n            service_description=self.mocked_description,\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"cannot handle oef_search message of performative={incoming_message.performative} in dialogue={self.oef_dialogues.get_dialogue(incoming_message)}.\",\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the oef_search handler.\"\"\"\n        assert self.oef_search_handler.teardown() is None\n        self.assert_quantity_in_outbox(0)\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_simple_service_registration/test_strategy.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the strategy class of the simple_service_registration skill.\"\"\"\n\nfrom pathlib import Path\n\nimport pytest\n\nfrom aea.exceptions import AEAEnforceError\nfrom aea.helpers.search.models import Description, Location\nfrom aea.test_tools.test_skill import BaseSkillTestCase\n\nfrom packages.fetchai.skills.simple_service_registration.strategy import (\n    AGENT_LOCATION_MODEL,\n    AGENT_PERSONALITY_MODEL,\n    AGENT_REMOVE_SERVICE_MODEL,\n    AGENT_SET_SERVICE_MODEL,\n    Strategy,\n)\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass TestStrategy(BaseSkillTestCase):\n    \"\"\"Test Strategy of simple_service_registration.\"\"\"\n\n    path_to_skill = Path(\n        ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"simple_service_registration\"\n    )\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.location = {\"longitude\": 0.1270, \"latitude\": 51.5194}\n        cls.service_data = {\"key\": \"seller_service\", \"value\": \"generic_service\"}\n\n        cls.strategy = Strategy(\n            location=cls.location,\n            service_data=cls.service_data,\n            name=\"strategy\",\n            skill_context=cls._skill.skill_context,\n        )\n\n    def test__init__(self):\n        \"\"\"Test the __init__ method of the Strategy class.\"\"\"\n        assert self.strategy._remove_service_data == {\"key\": self.service_data[\"key\"]}\n\n    def test__init__exception(self):\n        \"\"\"Test the __init__ method of the Strategy class where exception is raise.\"\"\"\n        incorrect_service_data_1 = {\"key\": \"seller_service\"}\n        incorrect_service_data_2 = {\n            \"incorrect_key\": \"seller_service\",\n            \"value\": \"generic_service\",\n        }\n        incorrect_service_data_3 = {\n            \"key\": \"seller_service\",\n            \"incorrect_key\": \"generic_service\",\n        }\n        with pytest.raises(\n            AEAEnforceError, match=\"service_data must contain keys `key` and `value`\"\n        ):\n            Strategy(\n                location=self.location,\n                service_data=incorrect_service_data_1,\n            )\n\n        with pytest.raises(\n            AEAEnforceError, match=\"service_data must contain keys `key` and `value`\"\n        ):\n            Strategy(\n                location=self.location,\n                service_data=incorrect_service_data_2,\n            )\n\n        with pytest.raises(\n            AEAEnforceError, match=\"service_data must contain keys `key` and `value`\"\n        ):\n            Strategy(\n                location=self.location,\n                service_data=incorrect_service_data_3,\n            )\n\n    def test_get_location_description(self):\n        \"\"\"Test the get_location_description method of the Strategy class.\"\"\"\n        description = self.strategy.get_location_description()\n\n        assert type(description) == Description\n        assert description.data_model is AGENT_LOCATION_MODEL\n        assert description.values.get(\"location\", \"\") == Location(\n            latitude=self.location[\"latitude\"], longitude=self.location[\"longitude\"]\n        )\n\n    def test_get_register_service_description(self):\n        \"\"\"Test the get_register_service_description method of the Strategy class.\"\"\"\n        description = self.strategy.get_register_service_description()\n\n        assert type(description) == Description\n        assert description.data_model is AGENT_SET_SERVICE_MODEL\n        assert description.values.get(\"key\", \"\") == self.service_data[\"key\"]\n        assert description.values.get(\"value\", \"\") == self.service_data[\"value\"]\n\n    def test_get_register_personality_description(self):\n        \"\"\"Test the get_register_personality_description method of the GenericStrategy class.\"\"\"\n        description = self.strategy.get_register_personality_description()\n\n        assert type(description) == Description\n        assert description.data_model is AGENT_PERSONALITY_MODEL\n        assert description.values.get(\"piece\", \"\") == \"genus\"\n        assert description.values.get(\"value\", \"\") == \"data\"\n\n    def test_get_register_classification_description(self):\n        \"\"\"Test the get_register_classification_description method of the GenericStrategy class.\"\"\"\n        description = self.strategy.get_register_classification_description()\n\n        assert type(description) == Description\n        assert description.data_model is AGENT_PERSONALITY_MODEL\n        assert description.values.get(\"piece\", \"\") == \"classification\"\n        assert description.values.get(\"value\", \"\") == \"seller\"\n\n    def test_get_unregister_service_description(self):\n        \"\"\"Test the get_unregister_service_description method of the Strategy class.\"\"\"\n        description = self.strategy.get_unregister_service_description()\n\n        assert type(description) == Description\n        assert description.data_model is AGENT_REMOVE_SERVICE_MODEL\n        assert description.values.get(\"key\", \"\") == self.service_data[\"key\"]\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_simple_service_search/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"The tests module contains the tests of the packages/skills/simple_service_search dir.\"\"\"\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_simple_service_search/test_behaviours.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the behaviour class of the simple_service_search skill.\"\"\"\n\nimport logging\nfrom pathlib import Path\nfrom typing import cast\nfrom unittest.mock import patch\n\nfrom aea.helpers.search.models import (\n    Attribute,\n    Constraint,\n    ConstraintType,\n    DataModel,\n    Query,\n)\nfrom aea.test_tools.test_skill import BaseSkillTestCase\n\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.skills.simple_service_search.behaviours import (\n    ServiceSearchBehaviour,\n)\nfrom packages.fetchai.skills.simple_service_search.strategy import Strategy\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass TestServiceSearchBehaviour(BaseSkillTestCase):\n    \"\"\"Test service_search behaviour of simple_service_search.\"\"\"\n\n    path_to_skill = Path(\n        ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"simple_service_search\"\n    )\n    is_agent_to_agent_messages = False\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.search_behaviour = cast(\n            ServiceSearchBehaviour, cls._skill.skill_context.behaviours.service_search\n        )\n        cls.strategy = cast(Strategy, cls._skill.skill_context.strategy)\n        cls.logger = cls._skill.skill_context.logger\n\n        cls.query = Query(\n            [Constraint(\"some_attribute\", ConstraintType(\"==\", \"some_service\"))],\n            DataModel(\n                \"some_name\",\n                [\n                    Attribute(\n                        \"some_attribute\", str, False, \"Some attribute descriptions.\"\n                    )\n                ],\n            ),\n        )\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the service_search behaviour.\"\"\"\n        assert self.search_behaviour.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_act(self):\n        \"\"\"Test the act method of the service_search behaviour.\"\"\"\n        # operation\n        with patch.object(self.strategy, \"get_query\", return_value=self.query):\n            with patch.object(self.logger, \"log\") as mock_logger:\n                self.search_behaviour.act()\n\n        # after\n        self.assert_quantity_in_outbox(1)\n\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=OefSearchMessage,\n            performative=OefSearchMessage.Performative.SEARCH_SERVICES,\n            to=self.skill.skill_context.search_service_address,\n            sender=str(self.skill.skill_context.skill_id),\n            query=self.query,\n        )\n        assert has_attributes, error_str\n\n        mock_logger.assert_any_call(\n            logging.INFO, \"sending search request to OEF search node\"\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the service_search behaviour.\"\"\"\n        assert self.search_behaviour.teardown() is None\n        self.assert_quantity_in_outbox(0)\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_simple_service_search/test_dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the dialogue classes of the simple_service_search skill.\"\"\"\n\nfrom pathlib import Path\nfrom typing import cast\n\nfrom aea.helpers.search.models import Description\nfrom aea.test_tools.test_skill import BaseSkillTestCase\n\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.skills.simple_service_search.dialogues import (\n    OefSearchDialogue,\n    OefSearchDialogues,\n)\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass TestDialogues(BaseSkillTestCase):\n    \"\"\"Test dialogue class of simple_service_search.\"\"\"\n\n    path_to_skill = Path(\n        ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"simple_service_search\"\n    )\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.oef_search_dialogues = cast(\n            OefSearchDialogues, cls._skill.skill_context.oef_search_dialogues\n        )\n        cls.mocked_description = Description({\"foo1\": 1, \"bar1\": 2})\n\n    def test_oef_search_dialogues(self):\n        \"\"\"Test the OefSearchDialogues class.\"\"\"\n        _, dialogue = self.oef_search_dialogues.create(\n            counterparty=self.skill.skill_context.search_service_address,\n            performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n            service_description=self.mocked_description,\n        )\n        assert dialogue.role == OefSearchDialogue.Role.AGENT\n        assert dialogue.self_address == str(self.skill.skill_context.skill_id)\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_simple_service_search/test_handlers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the handler class of the simple_service_search skill.\"\"\"\n\nimport logging\nfrom pathlib import Path\nfrom typing import cast\nfrom unittest.mock import patch\n\nfrom aea.helpers.search.models import (\n    Attribute,\n    Constraint,\n    ConstraintType,\n    DataModel,\n    Description,\n    Query,\n)\nfrom aea.protocols.dialogue.base import DialogueMessage\nfrom aea.test_tools.test_skill import BaseSkillTestCase\n\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.skills.simple_service_search.dialogues import OefSearchDialogues\nfrom packages.fetchai.skills.simple_service_search.handlers import OefSearchHandler\nfrom packages.fetchai.skills.simple_service_search.strategy import Strategy\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass TestOefSearchHandler(BaseSkillTestCase):\n    \"\"\"Test oef_search handler of simple_service_search.\"\"\"\n\n    path_to_skill = Path(\n        ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"simple_service_search\"\n    )\n    is_agent_to_agent_messages = False\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.oef_search_handler = cast(\n            OefSearchHandler, cls._skill.skill_context.handlers.oef_search\n        )\n        cls.strategy = cast(Strategy, cls._skill.skill_context.strategy)\n        cls.logger = cls._skill.skill_context.logger\n\n        cls.oef_search_dialogues = cast(\n            OefSearchDialogues, cls._skill.skill_context.oef_search_dialogues\n        )\n\n        cls.data = b\"some_body\"\n        cls.query = Query(\n            [Constraint(\"some_attribute\", ConstraintType(\"==\", \"some_service\"))],\n            DataModel(\n                \"some_name\",\n                [\n                    Attribute(\n                        \"some_attribute\", str, False, \"Some attribute descriptions.\"\n                    )\n                ],\n            ),\n        )\n        cls.mocked_description = Description({\"foo1\": 1, \"bar1\": 2})\n\n        cls.list_of_messages = (\n            DialogueMessage(\n                OefSearchMessage.Performative.SEARCH_SERVICES, {\"query\": cls.query}\n            ),\n        )\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the oef_search handler.\"\"\"\n        assert self.oef_search_handler.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle_unidentified_dialogue(self):\n        \"\"\"Test the _handle_unidentified_dialogue method of the oef_search handler.\"\"\"\n        # setup\n        incorrect_dialogue_reference = (\"\", \"\")\n        incoming_message = self.build_incoming_message(\n            message_type=OefSearchMessage,\n            dialogue_reference=incorrect_dialogue_reference,\n            performative=OefSearchMessage.Performative.OEF_ERROR,\n            oef_error_operation=OefSearchMessage.OefErrorOperation.REGISTER_SERVICE,\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received invalid oef_search message={incoming_message}, unidentified dialogue.\",\n        )\n\n    def test_handle_error(self):\n        \"\"\"Test the _handle_error method of the oef_search handler.\"\"\"\n        # setup\n        oef_search_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_search_dialogues,\n            messages=self.list_of_messages[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=oef_search_dialogue,\n            performative=OefSearchMessage.Performative.OEF_ERROR,\n            oef_error_operation=OefSearchMessage.OefErrorOperation.REGISTER_SERVICE,\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received oef_search error message={incoming_message} in dialogue={oef_search_dialogue}.\",\n        )\n\n    def test_handle_search_i(self):\n        \"\"\"Test the _handle_search method of the oef_search handler where the number of agents found is 0.\"\"\"\n        # setup\n        agents = (\"agent_1\", \"agent_2\")\n        oef_search_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_search_dialogues,\n            messages=self.list_of_messages[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=oef_search_dialogue,\n            performative=OefSearchMessage.Performative.SEARCH_RESULT,\n            agents=agents,\n            agents_info=OefSearchMessage.AgentsInfo(\n                {\n                    \"agent_1\": {\"key_1\": \"value_1\", \"key_2\": \"value_2\"},\n                    \"agent_2\": {\"key_3\": \"value_3\", \"key_4\": \"value_4\"},\n                }\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"found number of agents={len(agents)}, search_response={incoming_message}\",\n        )\n\n        assert self.skill.skill_context._agent_context.shared_state[\n            self.strategy.shared_storage_key\n        ] == set(agents)\n\n    def test_handle_search_ii(self):\n        \"\"\"Test the _handle_search method of the oef_search handler where the number of agents found is 0.\"\"\"\n        # setup\n        agents = tuple()\n        oef_search_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_search_dialogues,\n            messages=self.list_of_messages[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=oef_search_dialogue,\n            performative=OefSearchMessage.Performative.SEARCH_RESULT,\n            agents=agents,\n            agents_info=OefSearchMessage.AgentsInfo(\n                {\n                    \"agent_1\": {\"key_1\": \"value_1\", \"key_2\": \"value_2\"},\n                    \"agent_2\": {\"key_3\": \"value_3\", \"key_4\": \"value_4\"},\n                }\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"no agents found, search_response={incoming_message}\",\n        )\n\n    def test_handle_invalid(self):\n        \"\"\"Test the _handle_invalid method of the oef_search handler.\"\"\"\n        # setup\n        incoming_message = self.build_incoming_message(\n            message_type=OefSearchMessage,\n            performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n            service_description=self.mocked_description,\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"cannot handle oef_search message of performative={incoming_message.performative} in dialogue={self.oef_search_dialogues.get_dialogue(incoming_message)}.\",\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the oef_search handler.\"\"\"\n        assert self.oef_search_handler.teardown() is None\n        self.assert_quantity_in_outbox(0)\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_simple_service_search/test_strategy.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the strategy class of the simple_service_search skill.\"\"\"\n\nfrom pathlib import Path\n\nfrom aea.helpers.search.models import Constraint, ConstraintType, Query\nfrom aea.test_tools.test_skill import BaseSkillTestCase\n\nfrom packages.fetchai.skills.simple_service_search.strategy import Strategy\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass TestStrategy(BaseSkillTestCase):\n    \"\"\"Test Strategy of simple_service_search.\"\"\"\n\n    path_to_skill = Path(\n        ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"simple_service_search\"\n    )\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.mocked_name_of_data = \"some_name_for_data\"\n        cls.mocked_data_1 = (\n            b'[{\"type_1\": \"data_1\", \"type_2\": \"data_2\", \"type_3\": \"data_3\"}]'\n        )\n        cls.mocked_data_2 = (\n            b'{\"type_1\": \"data_1\", \"type_2\": \"data_2\", \"type_3\": \"data_3\"}'\n        )\n        cls.mocked_data_3 = b\"some_non_jason_data\"\n\n        cls.search_query = {\n            \"search_key\": \"seller_service\",\n            \"search_value\": \"generic_service\",\n            \"constraint_type\": \"==\",\n        }\n        cls.search_location = {\"longitude\": 0.1270, \"latitude\": 51.5194}\n        cls.search_radius = 5.0\n        cls.shared_state_key = \"agents_found\"\n\n        cls.strategy = Strategy(\n            search_query=cls.search_query,\n            search_location=cls.search_location,\n            search_radius=cls.search_radius,\n            shared_storage_key=cls.shared_state_key,\n            name=\"strategy\",\n            skill_context=cls._skill.skill_context,\n        )\n\n    def test_simple_properties(self):\n        \"\"\"Test simple properties of the Strategy class.\"\"\"\n        assert self.strategy.shared_storage_key == self.shared_state_key\n\n    def test_get_query(self):\n        \"\"\"Test the get_query method of the Strategy class.\"\"\"\n        query = self.strategy.get_query()\n\n        assert type(query) == Query\n        assert len(query.constraints) == 2\n        assert query.model is None\n\n        location_constraint = Constraint(\n            \"location\",\n            ConstraintType(\n                \"distance\", (self.strategy._agent_location, self.search_radius)\n            ),\n        )\n        assert query.constraints[0] == location_constraint\n\n        service_key_constraint = Constraint(\n            self.search_query[\"search_key\"],\n            ConstraintType(\n                self.search_query[\"constraint_type\"],\n                self.search_query[\"search_value\"],\n            ),\n        )\n        assert query.constraints[1] == service_key_constraint\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_tac_control/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"The tests module contains the tests of the packages/skills/tac_control dir.\"\"\"\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_tac_control/test_behaviours.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the behaviour classes of the tac control skill.\"\"\"\n\nimport datetime\nimport logging\nfrom pathlib import Path\nfrom typing import cast\nfrom unittest.mock import Mock, PropertyMock, patch\n\nimport pytest\n\nfrom aea.helpers.search.models import Description\nfrom aea.mail.base import Address\nfrom aea.protocols.dialogue.base import DialogueMessage\nfrom aea.test_tools.test_skill import BaseSkillTestCase, COUNTERPARTY_AGENT_ADDRESS\n\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.protocols.tac.message import TacMessage\nfrom packages.fetchai.skills.tac_control.behaviours import TacBehaviour\nfrom packages.fetchai.skills.tac_control.dialogues import TacDialogues\nfrom packages.fetchai.skills.tac_control.game import Game, Phase\nfrom packages.fetchai.skills.tac_control.parameters import Parameters\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass TestSkillBehaviour(BaseSkillTestCase):\n    \"\"\"Test tac behaviour of tac_control.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"tac_control\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.tac_behaviour = cast(TacBehaviour, cls._skill.skill_context.behaviours.tac)\n        cls.game = cast(Game, cls._skill.skill_context.game)\n        cls.parameters = cast(Parameters, cls._skill.skill_context.parameters)\n        cls.tac_dialogues = cast(TacDialogues, cls._skill.skill_context.tac_dialogues)\n\n        cls.mocked_reg_time = cls._time(\"00:02\")\n        cls.mocked_start_time = cls._time(\"00:04\")\n        cls.mocked_end_time = cls._time(\"00:06\")\n\n        cls.parameters._registration_start_time = cls.mocked_reg_time\n        cls.parameters._start_time = cls.mocked_start_time\n        cls.parameters._end_time = cls.mocked_end_time\n\n        cls.mocked_description = Description({\"foo1\": 1, \"bar1\": 2})\n\n        cls.agent_1_address = \"agent_address_1\"\n        cls.agent_1_name = \"agent_name_1\"\n        cls.agent_2_address = \"agent_address_2\"\n        cls.agent_2_name = \"agent_name_2\"\n\n        cls.registration_message = OefSearchMessage(\n            dialogue_reference=(\"\", \"\"),\n            performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n            service_description=\"some_service_description\",\n        )\n        cls.registration_message.sender = str(cls._skill.skill_context.skill_id)\n        cls.registration_message.to = cls._skill.skill_context.search_service_address\n\n    def test_init(self):\n        \"\"\"Test the __init__ method of the tac behaviour.\"\"\"\n        assert self.tac_behaviour._registered_description is None\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the tac behaviour.\"\"\"\n        # operation\n        with patch.object(\n            self.game, \"get_location_description\", return_value=self.mocked_description\n        ):\n            with patch.object(self.tac_behaviour.context.logger, \"log\") as mock_logger:\n                self.tac_behaviour.setup()\n\n        # after\n        self.assert_quantity_in_outbox(1)\n\n        # _register_agent\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=OefSearchMessage,\n            performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n            to=self.skill.skill_context.search_service_address,\n            sender=str(self.skill.skill_context.skill_id),\n            service_description=self.mocked_description,\n        )\n        assert has_attributes, error_str\n\n        mock_logger.assert_any_call(logging.INFO, \"registering agent on SOEF.\")\n\n    @staticmethod\n    def _time(time: str):\n        date_time = \"01 01 2020  \" + time\n        return datetime.datetime.strptime(date_time, \"%d %m %Y %H:%M\")\n\n    def test_act_i(self):\n        \"\"\"Test the act method of the tac behaviour where phase is pre_game and reg_start_time < now < start_time.\"\"\"\n        # setup\n        self.game._phase = Phase.PRE_GAME\n        self.game.is_registered_agent = True\n\n        mocked_now_time = self._time(\"00:03\")\n        datetime_mock = Mock(wraps=datetime.datetime)\n        datetime_mock.now.return_value = mocked_now_time\n\n        # operation\n        with patch(\"datetime.datetime\", new=datetime_mock):\n            with patch.object(\n                self.game,\n                \"get_register_tac_description\",\n                return_value=self.mocked_description,\n            ):\n                with patch.object(\n                    self.tac_behaviour.context.logger, \"log\"\n                ) as mock_logger:\n                    self.tac_behaviour.act()\n\n        # after\n        # act\n        assert self.game.phase == Phase.GAME_REGISTRATION\n\n        # _register_tac\n        self.assert_quantity_in_outbox(1)\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=OefSearchMessage,\n            performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n            to=self.skill.skill_context.search_service_address,\n            sender=str(self.skill.skill_context.skill_id),\n            service_description=self.mocked_description,\n        )\n        assert has_attributes, error_str\n        mock_logger.assert_any_call(logging.INFO, \"registering TAC data model on SOEF.\")\n\n        # act\n        mock_logger.assert_any_call(\n            logging.INFO, f\"TAC open for registration until: {self.mocked_start_time}\"\n        )\n\n    def test_act_ii(self):\n        \"\"\"Test the act method of the tac behaviour where phase is game_registration and start_time < now < end_time and nb_agent < min_nb_agents.\"\"\"\n        # setup\n        self.game._phase = Phase.GAME_REGISTRATION\n\n        mocked_now_time = self._time(\"00:05\")\n        datetime_mock = Mock(wraps=datetime.datetime)\n        datetime_mock.now.return_value = mocked_now_time\n\n        self.parameters._min_nb_agents = 2\n        self.game._registration.register_agent(\n            COUNTERPARTY_AGENT_ADDRESS, self.agent_1_name\n        )\n\n        self.prepare_skill_dialogue(\n            self.tac_dialogues,\n            (\n                DialogueMessage(\n                    TacMessage.Performative.REGISTER,\n                    {\"agent_name\": \"some_agent_name\"},\n                    True,\n                ),\n            ),\n        )\n\n        # operation\n        with patch(\"datetime.datetime\", new=datetime_mock):\n            with patch.object(\n                self.game,\n                \"get_unregister_tac_description\",\n                return_value=self.mocked_description,\n            ):\n                with patch.object(\n                    self.tac_behaviour.context.logger, \"log\"\n                ) as mock_logger:\n                    self.tac_behaviour.act()\n\n        # after\n        self.assert_quantity_in_outbox(2)\n\n        # _cancel_tac\n        mock_logger.assert_any_call(\n            logging.INFO, \"notifying agents that TAC is cancelled.\"\n        )\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=TacMessage,\n            performative=TacMessage.Performative.CANCELLED,\n            to=COUNTERPARTY_AGENT_ADDRESS,\n            sender=self.skill.skill_context.agent_address,\n        )\n        assert has_attributes, error_str\n\n        # phase is POST_GAME\n        assert self.game.phase == Phase.POST_GAME\n\n        # _unregister_tac\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=OefSearchMessage,\n            performative=OefSearchMessage.Performative.UNREGISTER_SERVICE,\n            to=self.skill.skill_context.search_service_address,\n            sender=str(self.skill.skill_context.skill_id),\n            service_description=self.mocked_description,\n        )\n        assert has_attributes, error_str\n        mock_logger.assert_any_call(\n            logging.INFO, \"unregistering TAC data model from SOEF.\"\n        )\n\n    def test_cancel_tac_not_1_dialogue(self):\n        \"\"\"Test the _cancel_tac method of the tac behaviour where number of dialogues for an agent is 0.\"\"\"\n        # setup\n        self.game._phase = Phase.GAME_REGISTRATION\n\n        mocked_now_time = self._time(\"00:05\")\n        datetime_mock = Mock(wraps=datetime.datetime)\n        datetime_mock.now.return_value = mocked_now_time\n\n        self.parameters._min_nb_agents = 2\n        self.game._registration.register_agent(\n            COUNTERPARTY_AGENT_ADDRESS, self.agent_1_name\n        )\n\n        # operation\n        with patch(\"datetime.datetime\", new=datetime_mock):\n            with patch.object(\n                self.game,\n                \"get_unregister_tac_description\",\n                return_value=self.mocked_description,\n            ):\n                with patch.object(self.tac_behaviour.context.logger, \"log\"):\n                    with pytest.raises(\n                        ValueError, match=\"Error when retrieving dialogue.\"\n                    ):\n                        self.tac_behaviour.act()\n\n    def test_cancel_tac_empty_dialogue(self):\n        \"\"\"Test the _cancel_tac method of the tac behaviour where the dialogue is empty.\"\"\"\n        # setup\n        self.game._phase = Phase.GAME_REGISTRATION\n\n        mocked_now_time = self._time(\"00:05\")\n        datetime_mock = Mock(wraps=datetime.datetime)\n        datetime_mock.now.return_value = mocked_now_time\n\n        self.parameters._min_nb_agents = 2\n        self.game._registration.register_agent(\n            self.skill.skill_context.agent_address, self.agent_1_name\n        )\n\n        dialogue = self.prepare_skill_dialogue(\n            self.tac_dialogues,\n            (\n                DialogueMessage(\n                    TacMessage.Performative.REGISTER,\n                    {\"agent_name\": \"some_agent_name\"},\n                    True,\n                ),\n            ),\n        )\n        dialogue._incoming_messages = []\n\n        # operation\n        with patch(\"datetime.datetime\", new=datetime_mock):\n            with patch.object(\n                self.game,\n                \"get_unregister_tac_description\",\n                return_value=self.mocked_description,\n            ):\n                with patch.object(self.tac_behaviour.context.logger, \"log\"):\n                    with pytest.raises(\n                        ValueError, match=\"Error when retrieving dialogue.\"\n                    ):\n                        self.tac_behaviour.act()\n\n    def _assert_tac_message_and_logging_output(\n        self,\n        tac_message: TacMessage,\n        participant_address: Address,\n        mocked_logger,\n    ):\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=tac_message,\n            message_type=TacMessage,\n            performative=TacMessage.Performative.GAME_DATA,\n            to=participant_address,\n            sender=self.skill.skill_context.agent_address,\n        )\n        assert has_attributes, error_str\n        mocked_logger.assert_any_call(\n            logging.DEBUG,\n            f\"sending game data to '{participant_address}': {str(tac_message)}\",\n        )\n\n    def test_act_iii(self):\n        \"\"\"Test the act method of the tac behaviour where phase is game_registration and start_time < now < end_time and nb_agent >= min_nb_agents\"\"\"\n        # setup\n        self.game._phase = Phase.GAME_REGISTRATION\n\n        mocked_now_time = self._time(\"00:05\")\n        datetime_mock = Mock(wraps=datetime.datetime)\n        datetime_mock.now.return_value = mocked_now_time\n\n        self.parameters._min_nb_agents = 2\n\n        self.game._registration.register_agent(self.agent_1_address, self.agent_1_name)\n        self.game._registration.register_agent(self.agent_2_address, self.agent_2_name)\n        mocked_holdings_summary = \"some_holdings_summary\"\n        mocked_equilibrium_summary = \"some_equilibrium_summary\"\n\n        self.prepare_skill_dialogue(\n            self.tac_dialogues,\n            (\n                DialogueMessage(\n                    TacMessage.Performative.REGISTER,\n                    {\"agent_name\": self.agent_1_name},\n                    True,\n                ),\n            ),\n            self.agent_1_address,\n        )\n        self.prepare_skill_dialogue(\n            self.tac_dialogues,\n            (\n                DialogueMessage(\n                    TacMessage.Performative.REGISTER,\n                    {\"agent_name\": self.agent_2_name},\n                    True,\n                ),\n            ),\n            self.agent_2_address,\n        )\n\n        # operation\n        with patch(\"datetime.datetime\", new=datetime_mock):\n            with patch.object(\n                self.game,\n                \"get_unregister_tac_description\",\n                return_value=self.mocked_description,\n            ):\n                with patch.object(\n                    type(self.game),\n                    \"holdings_summary\",\n                    new_callable=PropertyMock,\n                    return_value=mocked_holdings_summary,\n                ):\n                    with patch.object(\n                        type(self.game),\n                        \"equilibrium_summary\",\n                        new_callable=PropertyMock,\n                        return_value=mocked_equilibrium_summary,\n                    ):\n                        with patch.object(\n                            self.tac_behaviour.context.logger, \"log\"\n                        ) as mock_logger:\n                            self.tac_behaviour.act()\n\n        # after\n        self.assert_quantity_in_outbox(3)\n\n        # _start_tac\n        mock_logger.assert_any_call(\n            logging.INFO, f\"started competition:\\n{mocked_holdings_summary}\"\n        )\n        mock_logger.assert_any_call(\n            logging.INFO, f\"computed equilibrium:\\n{mocked_equilibrium_summary}\"\n        )\n\n        tac_message_1_in_outbox = cast(TacMessage, self.get_message_from_outbox())\n        self._assert_tac_message_and_logging_output(\n            tac_message_1_in_outbox, self.agent_1_address, mock_logger\n        )\n\n        tac_message_2_in_outbox = cast(TacMessage, self.get_message_from_outbox())\n        self._assert_tac_message_and_logging_output(\n            tac_message_2_in_outbox, self.agent_2_address, mock_logger\n        )\n\n        # phase is POST_GAME\n        assert self.game.phase == Phase.GAME\n\n        # _unregister_tac\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=OefSearchMessage,\n            performative=OefSearchMessage.Performative.UNREGISTER_SERVICE,\n            to=self.skill.skill_context.search_service_address,\n            sender=str(self.skill.skill_context.skill_id),\n            service_description=self.mocked_description,\n        )\n        assert has_attributes, error_str\n\n        assert self.tac_behaviour._registered_description is None\n\n        mock_logger.assert_any_call(\n            logging.INFO, \"unregistering TAC data model from SOEF.\"\n        )\n\n    def test_register_genus(self):\n        \"\"\"Test the register_genus method of the service_registration behaviour.\"\"\"\n        # operation\n        with patch.object(\n            self.game,\n            \"get_register_personality_description\",\n            return_value=self.mocked_description,\n        ):\n            with patch.object(self.tac_behaviour.context.logger, \"log\") as mock_logger:\n                self.tac_behaviour.register_genus()\n\n        # after\n        self.assert_quantity_in_outbox(1)\n\n        message = self.get_message_from_outbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=OefSearchMessage,\n            performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n            to=self.skill.skill_context.search_service_address,\n            sender=str(self.skill.skill_context.skill_id),\n            service_description=self.mocked_description,\n        )\n        assert has_attributes, error_str\n        mock_logger.assert_any_call(\n            logging.INFO, \"registering agent's personality genus on the SOEF.\"\n        )\n\n    def test_register_classification(self):\n        \"\"\"Test the register_classification method of the service_registration behaviour.\"\"\"\n        # operation\n        with patch.object(\n            self.game,\n            \"get_register_classification_description\",\n            return_value=self.mocked_description,\n        ):\n            with patch.object(self.tac_behaviour.context.logger, \"log\") as mock_logger:\n                self.tac_behaviour.register_classification()\n\n        # after\n        self.assert_quantity_in_outbox(1)\n\n        message = self.get_message_from_outbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=OefSearchMessage,\n            performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n            to=self.skill.skill_context.search_service_address,\n            sender=str(self.skill.skill_context.skill_id),\n            service_description=self.mocked_description,\n        )\n        assert has_attributes, error_str\n        mock_logger.assert_any_call(\n            logging.INFO, \"registering agent's personality classification on the SOEF.\"\n        )\n\n    def test_start_tac_not_1_dialogue(self):\n        \"\"\"Test the _start_tac method of the tac behaviour where number of dialogues for an agent is 0.\"\"\"\n        # setup\n        self.game._phase = Phase.GAME_REGISTRATION\n\n        mocked_now_time = self._time(\"00:05\")\n        datetime_mock = Mock(wraps=datetime.datetime)\n        datetime_mock.now.return_value = mocked_now_time\n\n        self.parameters._min_nb_agents = 2\n        self.game._registration.register_agent(self.agent_1_address, self.agent_1_name)\n        self.game._registration.register_agent(self.agent_2_address, self.agent_2_name)\n\n        # operation\n        with patch(\"datetime.datetime\", new=datetime_mock):\n            with patch.object(\n                self.game,\n                \"get_unregister_tac_description\",\n                return_value=self.mocked_description,\n            ):\n                with patch.object(self.tac_behaviour.context.logger, \"log\"):\n                    with pytest.raises(\n                        ValueError, match=\"Error when retrieving dialogue.\"\n                    ):\n                        self.tac_behaviour.act()\n\n    def test_start_tac_empty_dialogue(self):\n        \"\"\"Test the _start_tac method of the tac behaviour where a dialogue is empty.\"\"\"\n        # setup\n        self.game._phase = Phase.GAME_REGISTRATION\n\n        mocked_now_time = self._time(\"00:05\")\n        datetime_mock = Mock(wraps=datetime.datetime)\n        datetime_mock.now.return_value = mocked_now_time\n\n        self.parameters._min_nb_agents = 2\n        self.game._registration.register_agent(self.agent_1_address, self.agent_1_name)\n        self.game._registration.register_agent(self.agent_2_address, self.agent_2_name)\n\n        dialogue_1 = self.prepare_skill_dialogue(\n            self.tac_dialogues,\n            (\n                DialogueMessage(\n                    TacMessage.Performative.REGISTER,\n                    {\"agent_name\": self.agent_1_name},\n                    True,\n                ),\n            ),\n            self.agent_1_address,\n        )\n\n        dialogue_1._incoming_messages = []\n\n        # operation\n        with patch(\"datetime.datetime\", new=datetime_mock):\n            with patch.object(\n                self.game,\n                \"get_unregister_tac_description\",\n                return_value=self.mocked_description,\n            ):\n                with patch.object(self.tac_behaviour.context.logger, \"log\"):\n                    with pytest.raises(\n                        ValueError, match=\"Error when retrieving last message.\"\n                    ):\n                        self.tac_behaviour.act()\n\n    def test_act_iv(self):\n        \"\"\"Test the act method of the tac behaviour where phase is GAME and end_time < now.\"\"\"\n        # setup\n        self.game._phase = Phase.GAME\n\n        mocked_now_time = self._time(\"00:07\")\n        datetime_mock = Mock(wraps=datetime.datetime)\n        datetime_mock.now.return_value = mocked_now_time\n\n        self.parameters._min_nb_agents = 2\n        self.game._registration.register_agent(self.agent_1_address, self.agent_1_name)\n        self.game._registration.register_agent(self.agent_2_address, self.agent_2_name)\n\n        mocked_holdings_summary = \"some_holdings_summary\"\n        mocked_equilibrium_summary = \"some_equilibrium_summary\"\n\n        self.prepare_skill_dialogue(\n            self.tac_dialogues,\n            (\n                DialogueMessage(\n                    TacMessage.Performative.REGISTER,\n                    {\"agent_name\": self.agent_1_name},\n                    True,\n                ),\n            ),\n            self.agent_1_address,\n        )\n        self.prepare_skill_dialogue(\n            self.tac_dialogues,\n            (\n                DialogueMessage(\n                    TacMessage.Performative.REGISTER,\n                    {\"agent_name\": self.agent_2_name},\n                    True,\n                ),\n            ),\n            self.agent_2_address,\n        )\n\n        # operation\n        with patch(\"datetime.datetime\", new=datetime_mock):\n            with patch.object(\n                self.game,\n                \"get_unregister_tac_description\",\n                return_value=self.mocked_description,\n            ):\n                with patch.object(\n                    type(self.game),\n                    \"holdings_summary\",\n                    new_callable=PropertyMock,\n                    return_value=mocked_holdings_summary,\n                ):\n                    with patch.object(\n                        type(self.game),\n                        \"equilibrium_summary\",\n                        new_callable=PropertyMock,\n                        return_value=mocked_equilibrium_summary,\n                    ):\n                        with patch.object(\n                            self.tac_behaviour.context.logger, \"log\"\n                        ) as mock_logger:\n                            self.tac_behaviour.act()\n\n        # after\n        self.assert_quantity_in_outbox(2)\n\n        # _cancel_tac\n        mock_logger.assert_any_call(\n            logging.INFO, \"notifying agents that TAC is cancelled.\"\n        )\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=TacMessage,\n            performative=TacMessage.Performative.CANCELLED,\n            to=self.agent_1_address,\n            sender=self.skill.skill_context.agent_address,\n        )\n        assert has_attributes, error_str\n\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=TacMessage,\n            performative=TacMessage.Performative.CANCELLED,\n            to=self.agent_2_address,\n            sender=self.skill.skill_context.agent_address,\n        )\n        assert has_attributes, error_str\n\n        mock_logger.assert_any_call(\n            logging.INFO, f\"finished competition:\\n{mocked_holdings_summary}\"\n        )\n        mock_logger.assert_any_call(\n            logging.INFO, f\"computed equilibrium:\\n{mocked_equilibrium_summary}\"\n        )\n\n        # phase is POST_GAME\n        assert self.game.phase == Phase.POST_GAME\n        assert self.skill.skill_context.is_active is False\n\n    def test_act_v(self):\n        \"\"\"Test the act method of the tac behaviour where failed_registration_msg is NOT None.\"\"\"\n        # setup\n        self.tac_behaviour.failed_registration_msg = self.registration_message\n\n        with patch.object(self.tac_behaviour.context.logger, \"log\") as mock_logger:\n            self.tac_behaviour.act()\n\n        # after\n        self.assert_quantity_in_outbox(1)\n\n        # _retry_failed_registration\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=type(self.registration_message),\n            performative=self.registration_message.performative,\n            to=self.registration_message.to,\n            sender=str(self.skill.skill_context.skill_id),\n            service_description=self.registration_message.service_description,\n        )\n        assert has_attributes, error_str\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"Retrying registration on SOEF. Retry {self.tac_behaviour._nb_retries} out of {self.tac_behaviour._max_soef_registration_retries}.\",\n        )\n        assert self.tac_behaviour.failed_registration_msg is None\n\n    def test_act_vi(self):\n        \"\"\"Test the act method of the tac behaviour where failed_registration_msg is NOT None and max retries is reached.\"\"\"\n        # setup\n        self.tac_behaviour.failed_registration_msg = self.registration_message\n        self.tac_behaviour._max_soef_registration_retries = 2\n        self.tac_behaviour._nb_retries = 2\n\n        self.tac_behaviour.act()\n\n        # after\n        self.assert_quantity_in_outbox(0)\n        assert self.skill.skill_context.is_active is False\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the service_registration behaviour.\"\"\"\n        # setup\n        mocked_location_description = Description({\"foo1\": 1, \"bar1\": 2})\n\n        # operation\n        with patch.object(\n            self.game,\n            \"get_unregister_tac_description\",\n            return_value=self.mocked_description,\n        ):\n            with patch.object(\n                self.game,\n                \"get_location_description\",\n                return_value=mocked_location_description,\n            ):\n                with patch.object(\n                    self.tac_behaviour.context.logger, \"log\"\n                ) as mock_logger:\n                    self.tac_behaviour.teardown()\n\n        # after\n        self.assert_quantity_in_outbox(2)\n\n        # _unregister_tac\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=OefSearchMessage,\n            performative=OefSearchMessage.Performative.UNREGISTER_SERVICE,\n            to=self.skill.skill_context.search_service_address,\n            sender=str(self.skill.skill_context.skill_id),\n            service_description=self.mocked_description,\n        )\n        assert has_attributes, error_str\n        mock_logger.assert_any_call(\n            logging.INFO, \"unregistering TAC data model from SOEF.\"\n        )\n\n        # _unregister_agent\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=OefSearchMessage,\n            performative=OefSearchMessage.Performative.UNREGISTER_SERVICE,\n            to=self.skill.skill_context.search_service_address,\n            sender=str(self.skill.skill_context.skill_id),\n            service_description=mocked_location_description,\n        )\n        assert has_attributes, error_str\n        mock_logger.assert_any_call(logging.INFO, \"unregistering agent from SOEF.\")\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_tac_control/test_dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the dialogue classes of the tac control skill.\"\"\"\n\nfrom pathlib import Path\nfrom typing import cast\n\nfrom aea.test_tools.test_skill import BaseSkillTestCase, COUNTERPARTY_AGENT_ADDRESS\n\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.protocols.tac.message import TacMessage\nfrom packages.fetchai.skills.tac_control.dialogues import (\n    DefaultDialogue,\n    DefaultDialogues,\n    OefSearchDialogue,\n    OefSearchDialogues,\n    TacDialogue,\n    TacDialogues,\n)\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass TestTacDialogues(BaseSkillTestCase):\n    \"\"\"Test dialogue classes of tac control.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"tac_control\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.default_dialogues = cast(\n            DefaultDialogues, cls._skill.skill_context.default_dialogues\n        )\n        cls.tac_dialogues = cast(TacDialogues, cls._skill.skill_context.tac_dialogues)\n        cls.oef_search_dialogues = cast(\n            OefSearchDialogues, cls._skill.skill_context.oef_search_dialogues\n        )\n\n    def test_default_dialogues(self):\n        \"\"\"Test the DefaultDialogues class.\"\"\"\n        _, dialogue = self.default_dialogues.create(\n            counterparty=COUNTERPARTY_AGENT_ADDRESS,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"some_content\",\n        )\n        assert dialogue.role == DefaultDialogue.Role.AGENT\n        assert dialogue.self_address == self.skill.skill_context.agent_address\n\n    def test_oef_search_dialogues(self):\n        \"\"\"Test the OefSearchDialogues class.\"\"\"\n        _, dialogue = self.oef_search_dialogues.create(\n            counterparty=COUNTERPARTY_AGENT_ADDRESS,\n            performative=OefSearchMessage.Performative.SEARCH_SERVICES,\n            query=\"some_query\",\n        )\n        assert dialogue.role == OefSearchDialogue.Role.AGENT\n        assert dialogue.self_address == str(self.skill.skill_context.skill_id)\n\n    def test_tac_dialogues(self):\n        \"\"\"Test the TacDialogues class.\"\"\"\n        _, dialogue = self.tac_dialogues.create(\n            counterparty=COUNTERPARTY_AGENT_ADDRESS,\n            performative=TacMessage.Performative.REGISTER,\n            agent_name=\"some_agent_name\",\n        )\n        assert dialogue.role == TacDialogue.Role.CONTROLLER\n        assert dialogue.self_address == self.skill.skill_context.agent_address\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_tac_control/test_game.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the models of the tac control skill.\"\"\"\n\nimport datetime\nimport logging\nimport pprint\nfrom pathlib import Path\nfrom unittest.mock import Mock, patch\n\nimport pytest\n\nfrom aea.crypto.ledger_apis import LedgerApis\nfrom aea.exceptions import AEAEnforceError\nfrom aea.helpers.preference_representations.base import (\n    linear_utility,\n    logarithmic_utility,\n)\nfrom aea.helpers.search.models import Description, Location\nfrom aea.test_tools.test_skill import BaseSkillTestCase\n\nfrom packages.fetchai.protocols.tac.message import TacMessage\nfrom packages.fetchai.skills.tac_control.game import (\n    AGENT_LOCATION_MODEL,\n    AGENT_PERSONALITY_MODEL,\n    AGENT_REMOVE_SERVICE_MODEL,\n    AGENT_SET_SERVICE_MODEL,\n    AgentState,\n    Configuration,\n    Game,\n    Initialization,\n    Phase,\n    Registration,\n    Transaction,\n    Transactions,\n)\nfrom packages.fetchai.skills.tac_control.parameters import Parameters\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass TestConfiguration:\n    \"\"\"Test Configuration class of tac control.\"\"\"\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        cls.version_id = \"some_version_id\"\n        cls.tx_fee = 1\n        cls.agent_addr_to_name = {\n            \"agent_address_1\": \"agent_name_1\",\n            \"agent_address_2\": \"agent_name_2\",\n        }\n        cls.currency_id_to_name = {\"1\": \"currency_1\"}\n        cls.good_id_to_name = {\"3\": \"good_1\", \"4\": \"good_2\"}\n\n        cls.configuration = Configuration(\n            cls.version_id,\n            cls.tx_fee,\n            cls.agent_addr_to_name,\n            cls.currency_id_to_name,\n            cls.good_id_to_name,\n        )\n\n    def test_simple_properties(self):\n        \"\"\"Test the properties of Game class.\"\"\"\n        assert self.configuration.version_id == self.version_id\n\n        assert self.configuration.fee_by_currency_id == {\"1\": 1}\n\n        assert self.configuration.agent_addr_to_name == self.agent_addr_to_name\n\n        assert self.configuration.currency_id_to_name == self.currency_id_to_name\n\n        assert self.configuration.good_id_to_name == self.good_id_to_name\n\n        assert self.configuration.has_contract_address is False\n\n        with pytest.raises(AEAEnforceError, match=\"Contract_address not set yet!\"):\n            assert self.configuration.contract_address\n\n        self.configuration.contract_address = \"some_contract_address\"\n\n        assert self.configuration.has_contract_address is True\n        assert self.configuration.contract_address == \"some_contract_address\"\n\n        with pytest.raises(AEAEnforceError, match=\"Contract_address already set!\"):\n            self.configuration.contract_address = \"some_other_contract_address\"\n\n    def test_check_consistency_succeeds(self):\n        \"\"\"Test the _check_consistency of Configuration class which succeeds.\"\"\"\n        self.configuration._check_consistency()\n\n    def test_check_consistency_fails_i(self):\n        \"\"\"Test the _check_consistency of Configuration class which fails on version being None.\"\"\"\n        self.configuration._version_id = None\n        with pytest.raises(AEAEnforceError, match=\"A version id must be set.\"):\n            assert self.configuration._check_consistency()\n\n    def test_check_consistency_fails_ii(self):\n        \"\"\"Test the _check_consistency of Configuration class which fails because tx_fee < 0.\"\"\"\n        self.configuration._tx_fee = -5\n        with pytest.raises(AEAEnforceError, match=\"Tx fee must be non-negative.\"):\n            assert self.configuration._check_consistency()\n\n    def test_check_consistency_fails_iii(self):\n        \"\"\"Test the _check_consistency of Configuration class which fails because number of agents is less than 2.\"\"\"\n        self.configuration._agent_addr_to_name = {\"agent_address_1\": \"agent_name_1\"}\n        with pytest.raises(AEAEnforceError, match=\"Must have at least two agents.\"):\n            assert self.configuration._check_consistency()\n\n    def test_check_consistency_fails_iv(self):\n        \"\"\"Test the _check_consistency of Configuration class which fails because number of goods is less than 2.\"\"\"\n        self.configuration._good_id_to_name = {\"3\": \"good_1\"}\n        with pytest.raises(AEAEnforceError, match=\"Must have at least two goods.\"):\n            assert self.configuration._check_consistency()\n\n    def test_check_consistency_fails_v(self):\n        \"\"\"Test the _check_consistency of Configuration class which fails because number of currencies is not 1.\"\"\"\n        self.configuration._currency_id_to_name = {\"1\": \"currency_1\", \"2\": \"currency_2\"}\n        with pytest.raises(AEAEnforceError, match=\"Must have exactly one currency.\"):\n            assert self.configuration._check_consistency()\n\n    def test_check_consistency_fails_vi(self):\n        \"\"\"Test the _check_consistency of Configuration class which fails because same id for good and currency.\"\"\"\n        self.configuration._good_id_to_name = {\"1\": \"good_1\", \"2\": \"good_2\"}\n        self.configuration._currency_id_to_name = {\"1\": \"currency_1\"}\n        with pytest.raises(\n            AEAEnforceError, match=\"Currency id and good ids cannot overlap.\"\n        ):\n            assert self.configuration._check_consistency()\n\n\nclass TestInitialization:\n    \"\"\"Test Initialization class of tac control.\"\"\"\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        cls.agent_addr_to_currency_endowments = {\n            \"agent_address_1\": {\"1\": 10},\n            \"agent_address_2\": {\"1\": 5},\n        }\n        cls.agent_addr_to_exchange_params = {\n            \"agent_address_1\": {\"1\": 1.0},\n            \"agent_address_2\": {\"1\": 1.5},\n        }\n        cls.agent_addr_to_good_endowments = {\n            \"agent_address_1\": {\"2\": 5, \"3\": 7},\n            \"agent_address_2\": {\"2\": 4, \"3\": 6},\n        }\n        cls.agent_addr_to_utility_params = {\n            \"agent_address_1\": {\"2\": 1.0, \"3\": 1.1},\n            \"agent_address_2\": {\"2\": 1.3, \"3\": 1.5},\n        }\n        cls.good_id_to_eq_prices = {\"2\": 1.7, \"3\": 1.3}\n        cls.agent_addr_to_eq_good_holdings = {\n            \"agent_address_1\": {\"2\": 1.2, \"3\": 1.1},\n            \"agent_address_2\": {\"2\": 1.1, \"3\": 1.4},\n        }\n        cls.agent_addr_to_eq_currency_holdings = {\n            \"agent_address_1\": {\"1\": 1.1},\n            \"agent_address_2\": {\"1\": 1.2},\n        }\n\n        cls.initialization = Initialization(\n            cls.agent_addr_to_currency_endowments,\n            cls.agent_addr_to_exchange_params,\n            cls.agent_addr_to_good_endowments,\n            cls.agent_addr_to_utility_params,\n            cls.good_id_to_eq_prices,\n            cls.agent_addr_to_eq_good_holdings,\n            cls.agent_addr_to_eq_currency_holdings,\n        )\n\n    def test_simple_properties(self):\n        \"\"\"Test the properties of Game class.\"\"\"\n        assert (\n            self.initialization.agent_addr_to_currency_endowments\n            == self.agent_addr_to_currency_endowments\n        )\n        assert (\n            self.initialization.agent_addr_to_exchange_params\n            == self.agent_addr_to_exchange_params\n        )\n        assert (\n            self.initialization.agent_addr_to_good_endowments\n            == self.agent_addr_to_good_endowments\n        )\n        assert (\n            self.initialization.agent_addr_to_utility_params\n            == self.agent_addr_to_utility_params\n        )\n        assert self.initialization.good_id_to_eq_prices == self.good_id_to_eq_prices\n        assert (\n            self.initialization.agent_addr_to_eq_good_holdings\n            == self.agent_addr_to_eq_good_holdings\n        )\n        assert (\n            self.initialization.agent_addr_to_eq_currency_holdings\n            == self.agent_addr_to_eq_currency_holdings\n        )\n\n    def test_check_consistency_succeeds(self):\n        \"\"\"Test the _check_consistency of Configuration class which succeeds.\"\"\"\n        self.initialization._check_consistency()\n\n    def test_check_consistency_fails_i(self):\n        \"\"\"Test the _check_consistency of Configuration class which fails because currency endowments are negative.\"\"\"\n        self.initialization._agent_addr_to_currency_endowments = {\n            \"agent_address_1\": {\"1\": -1},\n            \"agent_address_2\": {\"1\": 5},\n        }\n        with pytest.raises(\n            AEAEnforceError, match=\"Currency endowments must be non-negative.\"\n        ):\n            assert self.initialization._check_consistency()\n\n    def test_check_consistency_fails_ii(self):\n        \"\"\"Test the _check_consistency of Configuration class which fails because ExchangeParams are not strictly positive.\"\"\"\n        self.initialization._agent_addr_to_exchange_params = {\n            \"agent_address_1\": {\"1\": 0.0},\n            \"agent_address_2\": {\"1\": -1.2},\n        }\n        with pytest.raises(\n            AEAEnforceError, match=\"ExchangeParams must be strictly positive.\"\n        ):\n            assert self.initialization._check_consistency()\n\n    def test_check_consistency_fails_iii(self):\n        \"\"\"Test the _check_consistency of Configuration class which fails because Good endowments are not strictly positive.\"\"\"\n        self.initialization._agent_addr_to_good_endowments = {\n            \"agent_address_1\": {\"2\": 0, \"3\": -1},\n            \"agent_address_2\": {\"2\": -7, \"3\": 0},\n        }\n        with pytest.raises(\n            AEAEnforceError, match=\"Good endowments must be strictly positive.\"\n        ):\n            assert self.initialization._check_consistency()\n\n    def test_check_consistency_fails_iv(self):\n        \"\"\"Test the _check_consistency of Configuration class which fails because UtilityParams are not strictly positive.\"\"\"\n        self.initialization._agent_addr_to_utility_params = {\n            \"agent_address_1\": {\"2\": 0, \"3\": -7},\n            \"agent_address_2\": {\"2\": -4, \"3\": 0},\n        }\n        with pytest.raises(\n            AEAEnforceError, match=\"UtilityParams must be strictly positive.\"\n        ):\n            assert self.initialization._check_consistency()\n\n    def test_check_consistency_fails_v(self):\n        \"\"\"Test the _check_consistency of Configuration class which fails because lengths of endowments are not the same.\"\"\"\n        self.initialization._agent_addr_to_currency_endowments = {\n            \"agent_address_1\": {\"1\": 10},\n        }\n        with pytest.raises(\n            AEAEnforceError, match=\"Length of endowments must be the same.\"\n        ):\n            assert self.initialization._check_consistency()\n\n    def test_check_consistency_fails_vi(self):\n        \"\"\"Test the _check_consistency of Configuration class which fails because lengths of params are not the same.\"\"\"\n        self.initialization._agent_addr_to_exchange_params = {\n            \"agent_address_1\": {\"1\": 1.0},\n        }\n        with pytest.raises(AEAEnforceError, match=\"Length of params must be the same.\"):\n            assert self.initialization._check_consistency()\n\n    def test_check_consistency_fails_vii(self):\n        \"\"\"Test the _check_consistency of Configuration class which fails because length of eq_prices and elements of eq_good_holdings are not the same.\"\"\"\n        self.initialization._good_id_to_eq_prices = {\"2\": 1.7}\n        with pytest.raises(\n            AEAEnforceError,\n            match=\"Length of eq_prices and an element of eq_good_holdings must be the same.\",\n        ):\n            assert self.initialization._check_consistency()\n\n    def test_check_consistency_fails_viii(self):\n        \"\"\"Test the _check_consistency of Configuration class which fails because length of eq_good_holdings and eq_currency_holdings are not the same.\"\"\"\n        self.initialization._agent_addr_to_eq_currency_holdings = {\n            \"agent_address_1\": {\"1\": 1.1},\n        }\n        with pytest.raises(\n            AEAEnforceError,\n            match=\"Length of eq_good_holdings and eq_currency_holdings must be the same.\",\n        ):\n            assert self.initialization._check_consistency()\n\n    def test_check_consistency_fails_ix(self):\n        \"\"\"Test the _check_consistency of Configuration class which fails because exchange_params and currency_endowments have different number of rows.\"\"\"\n        self.initialization._agent_addr_to_currency_endowments = {\n            \"agent_address_1\": {\"1\": 10, \"2\": 11},\n            \"agent_address_2\": {\"1\": 5},\n        }\n        with pytest.raises(\n            AEAEnforceError,\n            match=\"Dimensions for exchange_params and currency_endowments rows must be the same.\",\n        ):\n            assert self.initialization._check_consistency()\n\n    def test_check_consistency_fails_x(self):\n        \"\"\"Test the _check_consistency of Configuration class which fails because utility_params and rows have different number of rows.\"\"\"\n        self.initialization._agent_addr_to_good_endowments = {\n            \"agent_address_1\": {\"2\": 5, \"3\": 7, \"4\": 8},\n            \"agent_address_2\": {\"2\": 4, \"3\": 6},\n        }\n        with pytest.raises(\n            AEAEnforceError,\n            match=\"Dimensions for utility_params and good_endowments rows must be the same.\",\n        ):\n            assert self.initialization._check_consistency()\n\n\nclass TestTransaction:\n    \"\"\"Test Initialization class of tac control.\"\"\"\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        cls.ledger_id = \"ethereum\"\n        cls.sender_address = \"some_sender_address\"\n        cls.counterparty_address = \"some_counterparty_address\"\n        cls.amount_by_currency_id = {\"1\": 10}\n        cls.quantities_by_good_id = {\"2\": 5, \"5\": 10}\n        cls.is_sender_payable_tx_fee = True\n        cls.nonce = \"some_nonce\"\n        cls.fee_by_currency_id = {\"1\": 1}\n        cls.sender_signature = \"some_sender_signature\"\n        cls.counterparty_signature = \"some_counterparty_signature\"\n\n        cls.transaction = Transaction(\n            cls.ledger_id,\n            cls.sender_address,\n            cls.counterparty_address,\n            cls.amount_by_currency_id,\n            cls.quantities_by_good_id,\n            cls.is_sender_payable_tx_fee,\n            cls.nonce,\n            cls.fee_by_currency_id,\n            cls.sender_signature,\n            cls.counterparty_signature,\n        )\n\n    def test_simple_properties(self):\n        \"\"\"Test the properties of Game class.\"\"\"\n        assert self.transaction.sender_signature == self.sender_signature\n        assert self.transaction.counterparty_signature == self.counterparty_signature\n\n    def test_has_matching_signatures_succeeds(self):\n        \"\"\"Test the has_matching_signatures method of Transaction class where the two addresses appear in the hash.\"\"\"\n        with patch.object(\n            LedgerApis,\n            \"recover_message\",\n            return_value=(self.sender_address, self.counterparty_address),\n        ):\n            assert self.transaction.has_matching_signatures() is True\n\n    def test_has_matching_signatures_fails_sender_not_in_hash(self):\n        \"\"\"Test the has_matching_signatures method of Transaction class where the sender address does not appear in the hash.\"\"\"\n        with patch.object(\n            LedgerApis, \"recover_message\", return_value=(self.counterparty_address,)\n        ):\n            assert self.transaction.has_matching_signatures() is False\n\n    def test_has_matching_signatures_fails_counterparty_not_in_hash(self):\n        \"\"\"Test the has_matching_signatures method of Transaction class where the counterparty addresses does not appear in the hash.\"\"\"\n        with patch.object(\n            LedgerApis, \"recover_message\", return_value=(self.sender_address,)\n        ):\n            assert self.transaction.has_matching_signatures() is False\n\n    def test_has_matching_signatures_fails_sender_and_counterparty_not_in_hash(self):\n        \"\"\"Test the has_matching_signatures method of Transaction class where the sender and counterparty addresses do not appear in the hash.\"\"\"\n        with patch.object(LedgerApis, \"recover_message\", return_value=tuple()):\n            assert self.transaction.has_matching_signatures() is False\n\n    def test_from_message(self):\n        \"\"\"Test the from_message method of Transaction class.\"\"\"\n        ledger_id = \"some_ledger_id\"\n        sender_address = \"some_sender_address\"\n        counterparty_address = \"some_counterparty_address\"\n        amount_by_currency_id = {\"FET\": 10}\n        fee_by_currency_id = {\"FET\": 2}\n        quantities_by_good_id = {\"G1\": -1}\n        nonce = \"some_nonce\"\n        sender_signature = \"some_signature\"\n        counterparty_signature = \"some_other_signature\"\n\n        tx_id = Transaction.get_hash(\n            ledger_id,\n            sender_address=sender_address,\n            counterparty_address=counterparty_address,\n            good_ids=[\"G1\"],\n            sender_supplied_quantities=[0],\n            counterparty_supplied_quantities=[1],\n            sender_payable_amount=0,\n            counterparty_payable_amount=10,\n            nonce=nonce,\n        )\n\n        tx = Transaction.from_message(\n            TacMessage(\n                performative=TacMessage.Performative.TRANSACTION,\n                transaction_id=tx_id,\n                ledger_id=ledger_id,\n                sender_address=sender_address,\n                counterparty_address=counterparty_address,\n                amount_by_currency_id=amount_by_currency_id,\n                fee_by_currency_id=fee_by_currency_id,\n                quantities_by_good_id=quantities_by_good_id,\n                nonce=nonce,\n                sender_signature=sender_signature,\n                counterparty_signature=counterparty_signature,\n            )\n        )\n\n        assert tx.ledger_id == ledger_id\n        assert tx.sender_address == sender_address\n        assert tx.counterparty_address == counterparty_address\n        assert tx.amount_by_currency_id == amount_by_currency_id\n        assert tx.fee_by_currency_id == fee_by_currency_id\n        assert tx.quantities_by_good_id == quantities_by_good_id\n        assert tx.nonce == nonce\n        assert tx.sender_signature == sender_signature\n        assert tx.counterparty_signature == counterparty_signature\n\n    def test__eq__(self):\n        \"\"\"Test the __eq__ method of Transaction class.\"\"\"\n        equal_transaction = Transaction(\n            self.ledger_id,\n            self.sender_address,\n            self.counterparty_address,\n            self.amount_by_currency_id,\n            self.quantities_by_good_id,\n            self.is_sender_payable_tx_fee,\n            self.nonce,\n            self.fee_by_currency_id,\n            self.sender_signature,\n            self.counterparty_signature,\n        )\n        assert self.transaction.__eq__(equal_transaction) is True\n\n        not_equal_transaction = Transaction(\n            self.ledger_id,\n            \"some_different_sender_address\",\n            self.counterparty_address,\n            self.amount_by_currency_id,\n            self.quantities_by_good_id,\n            self.is_sender_payable_tx_fee,\n            self.nonce,\n            self.fee_by_currency_id,\n            self.sender_signature,\n            self.counterparty_signature,\n        )\n        assert self.transaction.__eq__(not_equal_transaction) is False\n\n\nclass TestAgentState:\n    \"\"\"Test AgentState class of tac control.\"\"\"\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        cls.agent_address = \"sender_address\"\n        cls.amount_by_currency_id = {\"1\": 10}\n        cls.quantities_by_good_id = {\"2\": 1, \"3\": 2}\n        cls.exchange_params_by_currency_id = {\"1\": 1.0}\n        cls.utility_params_by_good_id = {\"2\": 1.0, \"3\": 1.5}\n\n        cls.agent_state = AgentState(\n            cls.agent_address,\n            cls.amount_by_currency_id,\n            cls.exchange_params_by_currency_id,\n            cls.quantities_by_good_id,\n            cls.utility_params_by_good_id,\n        )\n\n        cls.ledger_id = \"ethereum\"\n        cls.sender_address = cls.agent_address\n        cls.counterparty_address = \"some_counterparty_address\"\n        cls.tx_amount_by_currency_id = {\"1\": 10}\n        cls.tx_quantities_by_good_id = {\"2\": -1, \"3\": -2}\n        cls.is_sender_payable_tx_fee = True\n        cls.nonce = \"some_nonce\"\n        cls.fee_by_currency_id = {\"1\": 1}\n        cls.sender_signature = \"some_sender_signature\"\n        cls.counterparty_signature = \"some_counterparty_signature\"\n        cls.transaction_1 = Transaction(\n            cls.ledger_id,\n            cls.sender_address,\n            cls.counterparty_address,\n            cls.tx_amount_by_currency_id,\n            cls.tx_quantities_by_good_id,\n            cls.is_sender_payable_tx_fee,\n            cls.nonce,\n            cls.fee_by_currency_id,\n            cls.sender_signature,\n            cls.counterparty_signature,\n        )\n\n        cls.amount_by_currency_id_2 = {\"1\": -9}\n        cls.quantities_by_good_id_2 = {\"2\": 1, \"3\": 2}\n        cls.transaction_2 = Transaction(\n            cls.ledger_id,\n            cls.sender_address,\n            cls.counterparty_address,\n            cls.amount_by_currency_id_2,\n            cls.quantities_by_good_id_2,\n            cls.is_sender_payable_tx_fee,\n            cls.nonce,\n            cls.fee_by_currency_id,\n            cls.sender_signature,\n            cls.counterparty_signature,\n        )\n\n    def test_simple_properties(self):\n        \"\"\"Test the properties of AgentState class.\"\"\"\n        assert self.agent_state.agent_address == self.agent_address\n        assert self.agent_state.amount_by_currency_id == self.amount_by_currency_id\n        assert (\n            self.agent_state.exchange_params_by_currency_id\n            == self.exchange_params_by_currency_id\n        )\n        assert self.agent_state.quantities_by_good_id == self.quantities_by_good_id\n        assert (\n            self.agent_state.utility_params_by_good_id == self.utility_params_by_good_id\n        )\n\n    def test_get_score(self):\n        \"\"\"Test the get_score of AgentState class.\"\"\"\n        assert self.agent_state.get_score() == logarithmic_utility(\n            self.utility_params_by_good_id, self.quantities_by_good_id\n        ) + linear_utility(\n            self.exchange_params_by_currency_id, self.amount_by_currency_id\n        )\n\n    def test_is_consistent_transaction_succeeds(self):\n        \"\"\"Test the is_consistent_transaction of AgentState class where it returns True.\"\"\"\n        assert self.agent_state.is_consistent_transaction(self.transaction_1) is True\n\n    def test_is_consistent_transaction_fails_i(self):\n        \"\"\"Test the is_consistent_transaction of AgentState class where it fails because agent address is not sender/counterparty.\"\"\"\n        self.transaction_1._sender_address = \"some_sender_address\"\n        assert self.agent_state.is_consistent_transaction(self.transaction_1) is False\n\n    def test_is_consistent_transaction_fails_ii(self):\n        \"\"\"Test the is_consistent_transaction of AgentState class where it fails because tx is not single currency.\"\"\"\n        self.transaction_1._amount_by_currency_id = {\"1\": 10, \"2\": 20}\n        assert self.agent_state.is_consistent_transaction(self.transaction_1) is False\n\n    def test_is_consistent_transaction_fails_iii(self):\n        \"\"\"Test the is_consistent_transaction of AgentState class where it fails because there is no exchange of wealth.\"\"\"\n        self.transaction_1._amount_by_currency_id = {\"1\": 0}\n        self.transaction_1._quantities_by_good_id = {\"2\": 0, \"3\": 0}\n        assert self.agent_state.is_consistent_transaction(self.transaction_1) is False\n\n    def test_is_consistent_transaction_fails_iv(self):\n        \"\"\"Test the is_consistent_transaction of AgentState class where it fails because sender does not have enough funds.\"\"\"\n        self.transaction_1._amount_by_currency_id = {\"1\": -11}\n        self.transaction_1._quantities_by_good_id = {\"2\": 1, \"3\": 0}\n        assert self.agent_state.is_consistent_transaction(self.transaction_1) is False\n\n    def test_is_consistent_transaction_succeeds_iv(self):\n        \"\"\"Test the is_consistent_transaction of AgentState class where it succeeds and sender does have enough funds.\"\"\"\n        self.transaction_1._amount_by_currency_id = {\"1\": -9}\n        self.transaction_1._quantities_by_good_id = {\"2\": 1, \"3\": 0}\n        assert self.agent_state.is_consistent_transaction(self.transaction_1) is True\n\n    def test_is_consistent_transaction_fails_v(self):\n        \"\"\"Test the is_consistent_transaction of AgentState class where it fails because counterparty does not have enough goods.\"\"\"\n        self.transaction_1._counterparty_address = self.agent_address\n        self.transaction_1._sender_address = \"some_sender_address\"\n\n        self.transaction_1._amount_by_currency_id = {\"1\": -10}\n        self.transaction_1._quantities_by_good_id = {\"2\": 2, \"3\": 2}\n        assert self.agent_state.is_consistent_transaction(self.transaction_1) is False\n\n    def test_is_consistent_transaction_succeeds_v(self):\n        \"\"\"Test the is_consistent_transaction of AgentState class where it succeeds and counterparty does have enough goods.\"\"\"\n        self.transaction_1._counterparty_address = self.agent_address\n        self.transaction_1._sender_address = \"some_sender_address\"\n\n        self.transaction_1._amount_by_currency_id = {\"1\": -10}\n        self.transaction_1._quantities_by_good_id = {\"2\": 1, \"3\": 2}\n        assert self.agent_state.is_consistent_transaction(self.transaction_1) is True\n\n    def test_is_consistent_transaction_fails_vi(self):\n        \"\"\"Test the is_consistent_transaction of AgentState class where it fails because sender does not have enough goods.\"\"\"\n        self.transaction_1._amount_by_currency_id = {\"1\": 10}\n        self.transaction_1._quantities_by_good_id = {\"2\": -2, \"3\": -2}\n        assert self.agent_state.is_consistent_transaction(self.transaction_1) is False\n\n    def test_is_consistent_transaction_succeeds_vi(self):\n        \"\"\"Test the is_consistent_transaction of AgentState class where it succeeds and sender does have enough goods.\"\"\"\n        self.transaction_1._amount_by_currency_id = {\"1\": 10}\n        self.transaction_1._quantities_by_good_id = {\"2\": -1, \"3\": -2}\n        assert self.agent_state.is_consistent_transaction(self.transaction_1) is True\n\n    def test_is_consistent_transaction_fails_vii(self):\n        \"\"\"Test the is_consistent_transaction of AgentState class where it fails because counterparty does not have enough funds.\"\"\"\n        self.transaction_1._counterparty_address = self.agent_address\n        self.transaction_1._sender_address = \"some_sender_address\"\n\n        self.transaction_1._amount_by_currency_id = {\"1\": 11}\n        self.transaction_1._quantities_by_good_id = {\"2\": -1, \"3\": -2}\n        assert self.agent_state.is_consistent_transaction(self.transaction_1) is False\n\n    def test_is_consistent_transaction_succeeds_vii(self):\n        \"\"\"Test the is_consistent_transaction of AgentState class where it succeeds and counterparty does have enough funds.\"\"\"\n        self.transaction_1._counterparty_address = self.agent_address\n        self.transaction_1._sender_address = \"some_sender_address\"\n\n        self.transaction_1._amount_by_currency_id = {\"1\": 9}\n        self.transaction_1._quantities_by_good_id = {\"2\": -1, \"3\": -2}\n        assert self.agent_state.is_consistent_transaction(self.transaction_1) is True\n\n    def test_is_consistent_transaction_fails_viii(self):\n        \"\"\"Test the is_consistent_transaction of AgentState class where it fails because inconsistent values.\"\"\"\n        self.transaction_1._amount_by_currency_id = {\"1\": -11}\n        self.transaction_1._quantities_by_good_id = {\"2\": -1, \"3\": -2}\n        assert self.agent_state.is_consistent_transaction(self.transaction_1) is False\n\n    def test_apply(self):\n        \"\"\"Test the apply of AgentState class.\"\"\"\n        new_agent_state = self.agent_state.apply(\n            [self.transaction_1, self.transaction_2]\n        )\n        assert new_agent_state.amount_by_currency_id == {\"1\": 11}\n        assert new_agent_state.quantities_by_good_id == {\"2\": 1, \"3\": 2}\n\n    def test_update_sender_i(self):\n        \"\"\"Test the update of AgentState class where agent is tx sender.\"\"\"\n        self.agent_state.update(self.transaction_1)\n        assert self.agent_state.amount_by_currency_id == {\"1\": 20}\n        assert self.agent_state.quantities_by_good_id == {\"2\": 0, \"3\": 0}\n\n    def test_update_sender_ii(self):\n        \"\"\"Test the update of AgentState class where agent is tx sender.\"\"\"\n        self.agent_state.update(self.transaction_2)\n        assert self.agent_state.amount_by_currency_id == {\"1\": 1}\n        assert self.agent_state.quantities_by_good_id == {\"2\": 2, \"3\": 4}\n\n    def test_update_counterparty_i(self):\n        \"\"\"Test the update of AgentState class where agent is tx counterparty.\"\"\"\n        # setup\n        self.transaction_1._sender_address = \"some_sender_address\"\n        self.transaction_1._counterparty_address = self.agent_address\n\n        # operation\n        self.agent_state.update(self.transaction_1)\n\n        # after\n        assert self.agent_state.amount_by_currency_id == {\"1\": 0}\n        assert self.agent_state.quantities_by_good_id == {\"2\": 2, \"3\": 4}\n\n    def test_update_counterparty_ii(self):\n        \"\"\"Test the update of AgentState class where agent is tx counterparty.\"\"\"\n        # setup\n        self.transaction_2._sender_address = \"some_sender_address\"\n        self.transaction_2._counterparty_address = self.agent_address\n\n        # operation\n        self.agent_state.update(self.transaction_2)\n\n        # after\n        assert self.agent_state.amount_by_currency_id == {\"1\": 19}\n        assert self.agent_state.quantities_by_good_id == {\"2\": 0, \"3\": 0}\n\n    def test__copy__(self):\n        \"\"\"Test the __copy__ of AgentState class.\"\"\"\n        new_agent_state = self.agent_state.__copy__()\n        assert new_agent_state == self.agent_state\n\n    def test__str__(self):\n        \"\"\"Test the __str__ of AgentState class.\"\"\"\n        agent_state_str = self.agent_state.__str__()\n        assert agent_state_str == \"AgentState{}\".format(\n            pprint.pformat(\n                {\n                    \"agent_address\": self.agent_state.agent_address,\n                    \"amount_by_currency_id\": self.agent_state.amount_by_currency_id,\n                    \"exchange_params_by_currency_id\": self.agent_state.exchange_params_by_currency_id,\n                    \"quantities_by_good_id\": self.agent_state.quantities_by_good_id,\n                    \"utility_params_by_good_id\": self.agent_state.utility_params_by_good_id,\n                }\n            )\n        )\n\n    def test__eq__(self):\n        \"\"\"Test the __eq__ of AgentState class.\"\"\"\n        another_agent_state = AgentState(\n            self.agent_address,\n            self.amount_by_currency_id,\n            self.exchange_params_by_currency_id,\n            self.quantities_by_good_id,\n            self.utility_params_by_good_id,\n        )\n\n        assert self.agent_state.__eq__(another_agent_state) is True\n\n\nclass TestTransactions:\n    \"\"\"Test Initialization class of tac control.\"\"\"\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        cls.transactions = Transactions()\n\n    def test_simple_properties(self):\n        \"\"\"Test the properties of Game class.\"\"\"\n        assert self.transactions.confirmed == {}\n        assert self.transactions.confirmed_per_agent == {}\n\n    def test_add(self):\n        \"\"\"Test the add of Transactions class which succeeds.\"\"\"\n        ledger_id = \"ethereum\"\n        sender_address = \"some_agent_address\"\n        counterparty_address = \"some_counterparty_address\"\n        tx_amount_by_currency_id = {\"1\": 10}\n        tx_quantities_by_good_id = {\"2\": -1, \"3\": -2}\n        is_sender_payable_tx_fee = True\n        nonce = \"some_nonce\"\n        fee_by_currency_id = {\"1\": 1}\n        sender_signature = \"some_sender_signature\"\n        counterparty_signature = \"some_counterparty_signature\"\n        transaction = Transaction(\n            ledger_id,\n            sender_address,\n            counterparty_address,\n            tx_amount_by_currency_id,\n            tx_quantities_by_good_id,\n            is_sender_payable_tx_fee,\n            nonce,\n            fee_by_currency_id,\n            sender_signature,\n            counterparty_signature,\n        )\n\n        mocked_now = datetime.datetime.strptime(\"01 01 2020  00:01\", \"%d %m %Y %H:%M\")\n\n        datetime_mock = Mock(wraps=datetime.datetime)\n        datetime_mock.now.return_value = mocked_now\n\n        with patch(\"datetime.datetime\", new=datetime_mock):\n            self.transactions.add(transaction)\n\n        assert self.transactions.confirmed[mocked_now] == transaction\n        assert (\n            self.transactions.confirmed_per_agent[sender_address][mocked_now]\n            == transaction\n        )\n        assert (\n            self.transactions.confirmed_per_agent[counterparty_address][mocked_now]\n            == transaction\n        )\n\n\nclass TestRegistration:\n    \"\"\"Test Registration class of tac control.\"\"\"\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        cls.registration = Registration()\n\n    def test_simple_properties(self):\n        \"\"\"Test the properties of Game class.\"\"\"\n        assert self.registration.agent_addr_to_name == {}\n        assert self.registration.nb_agents == 0\n\n    def test_register_agent(self):\n        \"\"\"Test the register_agent of Registration class which succeeds.\"\"\"\n        agent_addr = \"some_agent_address\"\n        agent_name = \"some_agent_name\"\n\n        self.registration.register_agent(agent_addr, agent_name)\n\n        assert self.registration.agent_addr_to_name == {agent_addr: agent_name}\n        assert self.registration.nb_agents == 1\n\n    def test_unregister_agent(self):\n        \"\"\"Test the unregister_agent of Registration class which succeeds.\"\"\"\n        agent_addr = \"some_agent_address\"\n        agent_name = \"some_agent_name\"\n\n        self.registration.register_agent(agent_addr, agent_name)\n        assert self.registration.agent_addr_to_name == {agent_addr: agent_name}\n        assert self.registration.nb_agents == 1\n\n        self.registration.unregister_agent(agent_addr)\n        assert self.registration.agent_addr_to_name == {}\n        assert self.registration.nb_agents == 0\n\n\nclass TestGame(BaseSkillTestCase):\n    \"\"\"Test Game class of tac control.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"tac_control\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.amount_by_currency_id = {\"FET\": 10}\n        cls.exchange_params_by_currency_id = {\"FET\": 1.0}\n        cls.quantities_by_good_id = {\"G1\": 1, \"G2\": 2}\n        cls.utility_params_by_good_id = {\"G1\": 1.0, \"G2\": 1.5}\n        cls.game = Game(name=\"Game\", skill_context=cls._skill.skill_context)\n        cls._skill.skill_context.parameters = Parameters(\n            ledger_id=\"\",\n            contract_address=None,\n            good_ids=[],\n            currency_ids=[],\n            min_nb_agents=2,\n            money_endowment=200,\n            nb_goods=9,\n            nb_currencies=1,\n            tx_fee=1,\n            base_good_endowment=2,\n            lower_bound_factor=1,\n            upper_bound_factor=1,\n            registration_start_time=\"01 01 2020  00:01\",\n            registration_timeout=60,\n            item_setup_timeout=60,\n            competition_timeout=300,\n            inactivity_timeout=30,\n            whitelist=[],\n            location={\"longitude\": 0.1270, \"latitude\": 51.5194},\n            service_data={\"key\": \"tac\", \"value\": \"v1\"},\n            name=\"parameters\",\n            skill_context=cls._skill.skill_context,\n        )\n        cls.game._conf = \"stub\"\n\n    def test_simple_properties(self):\n        \"\"\"Test the properties of Game class.\"\"\"\n        self.game._conf = None\n        # phase\n        assert self.game.phase == Phase.PRE_GAME\n\n        with patch.object(self.game.context.logger, \"log\") as mock_logger:\n            self.game.phase = Phase.GAME\n        mock_logger.assert_any_call(logging.DEBUG, f\"Game phase set to: {Phase.GAME}\")\n        assert self.game.phase == Phase.GAME\n\n        # registration\n        assert self.game.registration.nb_agents == 0\n        assert self.game.registration.agent_addr_to_name == {}\n\n        # conf\n        with pytest.raises(\n            AEAEnforceError, match=\"Call create before calling configuration.\"\n        ):\n            assert self.game.conf\n        conf = Configuration(\n            \"some_version_id\",\n            1,\n            {\"ag_1_add\": \"ag_1\", \"ag_2_add\": \"ag_2\"},\n            {\"FET\": \"fetch\"},\n            {\"G_1\": \"good_1\", \"G_2\": \"good_2\"},\n        )\n        self.game._conf = conf\n        assert self.game.conf == conf\n\n        # initialization\n        with pytest.raises(\n            AEAEnforceError, match=\"Call create before calling initialization.\"\n        ):\n            assert self.game.initialization\n        init = Initialization({}, {}, {}, {}, {}, {}, {})\n        self.game._initialization = init\n        assert self.game.initialization == init\n\n        # initial_agent_states\n        with pytest.raises(\n            AEAEnforceError, match=\"Call create before calling initial_agent_states.\"\n        ):\n            assert self.game.initial_agent_states\n        ias = {}\n        self.game._initial_agent_states = ias\n        assert self.game.initial_agent_states == ias\n\n        # current_agent_states\n        with pytest.raises(\n            AEAEnforceError, match=\"Call create before calling current_agent_states.\"\n        ):\n            assert self.game.current_agent_states\n        cas = {}\n        self.game._current_agent_states = cas\n        assert self.game.current_agent_states == cas\n\n        # transactions\n        tx = Transactions()\n        self.game._transactions = tx\n        assert self.game.transactions == tx\n\n        # is_allowed_to_mint\n        assert self.game.is_allowed_to_mint is True\n        self.game.is_allowed_to_mint = False\n        assert self.game.is_allowed_to_mint is False\n\n    def test_create_succeeds(self):\n        \"\"\"Test the create method of the Game class which succeeds.\"\"\"\n        self.game.phase = Phase.PRE_GAME\n        with patch.object(self.game, \"_generate\") as mock_generate:\n            self.game.create()\n\n        assert self.game.phase == Phase.GAME_SETUP\n        mock_generate.assert_called_once()\n\n    def test_create_fails(self):\n        \"\"\"Test the create method of the Game class which fails because phase is Game.\"\"\"\n        self.game.phase = Phase.GAME\n        with pytest.raises(AEAEnforceError, match=\"A game phase is already active.\"):\n            with patch.object(self.game, \"_generate\"):\n                self.game.create()\n\n        assert self.game.phase == Phase.GAME\n\n    def test_get_next_agent_state_for_minting(self):\n        \"\"\"Test the get_next_agent_state_for_minting method of the Game class.\"\"\"\n        agent_state = AgentState(\n            \"some_address_1\",\n            self.amount_by_currency_id,\n            self.exchange_params_by_currency_id,\n            self.quantities_by_good_id,\n            self.utility_params_by_good_id,\n        )\n        self.game._initial_agent_states = {\"ag1\": agent_state}\n        self.game._already_minted_agents = []\n\n        actual_agent_state = self.game.get_next_agent_state_for_minting()\n        assert actual_agent_state == agent_state\n\n        self.game._already_minted_agents = [\"ag1\"]\n        actual_agent_state = self.game.get_next_agent_state_for_minting()\n        assert actual_agent_state is None\n\n    def test_create_generate(self):\n        \"\"\"Test the _generate method of the Game class.\"\"\"\n        # before\n        assert self.game._conf == \"stub\"\n        assert self.game._initialization is None\n        assert self.game._initial_agent_states is None\n        assert self.game._current_agent_states is None\n\n        agent_addr_1 = \"some_agent_address_1\"\n        agent_name_1 = \"some_agent_name_1\"\n        agent_addr_2 = \"some_agent_address_2\"\n        agent_name_2 = \"some_agent_name_2\"\n        self.game.registration.register_agent(agent_addr_1, agent_name_1)\n        self.game.registration.register_agent(agent_addr_2, agent_name_2)\n\n        # operation\n        self.game._generate()\n\n        # after\n        assert self.game._conf != \"stub\"\n        assert self.game.initialization is not None\n        assert self.game._initial_agent_states is not None\n        assert self.game._current_agent_states is not None\n\n    def test_holdings_summary(self):\n        \"\"\"Test the holdings_summary method of the Game class.\"\"\"\n        # before\n        agent_address_1 = \"agent_address_1\"\n        agent_address_2 = \"agent_address_2\"\n\n        self.game._conf = Configuration(\n            \"some_version_id\",\n            1,\n            {agent_address_1: \"agent_name_1\", agent_address_2: \"agent_name_2\"},\n            {\"1\": \"currency_1\"},\n            {\"2\": \"good_1\", \"3\": \"good_2\"},\n        )\n        agent_state_1 = AgentState(\n            agent_address_1,\n            {\"1\": 10},\n            {\"1\": 1.0},\n            {\"2\": 1, \"3\": 2},\n            {\"2\": 1.0, \"3\": 1.5},\n        )\n        agent_state_2 = AgentState(\n            agent_address_2,\n            {\"1\": 10},\n            {\"1\": 1.0},\n            {\"2\": 1, \"3\": 2},\n            {\"2\": 1.0, \"3\": 1.5},\n        )\n\n        self.game._current_agent_states = {\n            agent_address_1: agent_state_1,\n            agent_address_2: agent_state_2,\n        }\n        expected_holding_summary = (\n            \"\\nCurrent good & money allocation & score: \\n\"\n            \"- agent_name_1:\\n\"\n            \"    good_1: 1\\n\"\n            \"    good_2: 2\\n\"\n            \"    currency_1: 10\\n\"\n            \"    score: 21.55\\n\"\n            \"- agent_name_2:\\n\"\n            \"    good_1: 1\\n\"\n            \"    good_2: 2\\n\"\n            \"    currency_1: 10\\n\"\n            \"    score: 21.55\\n\\n\"\n        )\n\n        # operation\n        holding_summary = self.game.holdings_summary\n\n        # after\n        assert holding_summary == expected_holding_summary\n\n    def test_equilibrium_summary(self):\n        \"\"\"Test the equilibrium_summary method of the Game class.\"\"\"\n        # before\n        agent_address_1 = \"agent_address_1\"\n        agent_address_2 = \"agent_address_2\"\n\n        self.game._conf = Configuration(\n            \"some_version_id\",\n            1,\n            {agent_address_1: \"agent_name_1\", agent_address_2: \"agent_name_2\"},\n            {\"1\": \"currency_1\"},\n            {\"2\": \"good_1\", \"3\": \"good_2\"},\n        )\n\n        self.game._initialization = Initialization(\n            {agent_address_1: {\"1\": 10}, agent_address_2: {\"1\": 5}},\n            {agent_address_1: {\"1\": 1.0}, agent_address_2: {\"1\": 1.5}},\n            {agent_address_1: {\"2\": 5, \"3\": 7}, agent_address_2: {\"2\": 4, \"3\": 6}},\n            {\n                agent_address_1: {\"2\": 1.0, \"3\": 1.1},\n                agent_address_2: {\"2\": 1.3, \"3\": 1.5},\n            },\n            {\"2\": 1.7, \"3\": 1.3},\n            {\n                agent_address_1: {\"2\": 1.2, \"3\": 1.1},\n                agent_address_2: {\"2\": 1.1, \"3\": 1.4},\n            },\n            {agent_address_1: {\"1\": 1.1}, agent_address_2: {\"1\": 1.2}},\n        )\n        expected_equilibrium_summary = (\n            \"\\nEquilibrium prices: \\n\"\n            \"good_1 1.7\\n\"\n            \"good_2 1.3\\n\\n\"\n            \"Equilibrium good allocation: \\n\"\n            \"- agent_name_1:\\n\"\n            \"    good_1: 1.2\\n\"\n            \"    good_2: 1.1\\n\"\n            \"- agent_name_2:\\n\"\n            \"    good_1: 1.1\\n\"\n            \"    good_2: 1.4\\n\\n\"\n            \"Equilibrium money allocation: \\n\"\n            \"- agent_name_1:\\n\"\n            \"    currency_1: 1.1\\n\"\n            \"- agent_name_2:\\n\"\n            \"    currency_1: 1.2\\n\\n\"\n        )\n        # operation\n        equilibrium_summary = self.game.equilibrium_summary\n\n        # after\n        assert equilibrium_summary == expected_equilibrium_summary\n\n    def test_is_transaction_valid_succeeds(self):\n        \"\"\"Test the is_transaction_valid method of the Game class which succeeds.\"\"\"\n        # before\n        agent_address_1 = \"agent_address_1\"\n        agent_address_2 = \"agent_address_2\"\n\n        tx = Transaction(\n            \"ethereum\",\n            agent_address_1,\n            agent_address_2,\n            {\"1\": 10},\n            {\"2\": 5, \"5\": 10},\n            True,\n            \"some_nonce\",\n            {\"1\": 1},\n            \"some_sender_signature\",\n            \"some_counterparty_signature\",\n        )\n\n        agent_state_1 = AgentState(\n            agent_address_1,\n            {\"1\": 10},\n            {\"1\": 1.0},\n            {\"2\": 1, \"3\": 2},\n            {\"2\": 1.0, \"3\": 1.5},\n        )\n        agent_state_2 = AgentState(\n            agent_address_2,\n            {\"1\": 10},\n            {\"1\": 1.0},\n            {\"2\": 1, \"3\": 2},\n            {\"2\": 1.0, \"3\": 1.5},\n        )\n\n        self.game._current_agent_states = {\n            agent_address_1: agent_state_1,\n            agent_address_2: agent_state_2,\n        }\n\n        # operation\n        with patch.object(Transaction, \"has_matching_signatures\", return_value=True):\n            with patch.object(\n                AgentState, \"is_consistent_transaction\", return_value=True\n            ):\n                assert self.game.is_transaction_valid(tx) is True\n\n    def test_is_transaction_valid_fails_not_matching_signatures(self):\n        \"\"\"Test the is_transaction_valid method of the Game class which fails because the signatures do no match.\"\"\"\n        # before\n        agent_address_1 = \"agent_address_1\"\n        agent_address_2 = \"agent_address_2\"\n\n        tx = Transaction(\n            \"ethereum\",\n            agent_address_1,\n            agent_address_2,\n            {\"1\": 10},\n            {\"2\": 5, \"5\": 10},\n            True,\n            \"some_nonce\",\n            {\"1\": 1},\n            \"some_sender_signature\",\n            \"some_counterparty_signature\",\n        )\n\n        agent_state_1 = AgentState(\n            agent_address_1,\n            {\"1\": 10},\n            {\"1\": 1.0},\n            {\"2\": 1, \"3\": 2},\n            {\"2\": 1.0, \"3\": 1.5},\n        )\n        agent_state_2 = AgentState(\n            agent_address_2,\n            {\"1\": 10},\n            {\"1\": 1.0},\n            {\"2\": 1, \"3\": 2},\n            {\"2\": 1.0, \"3\": 1.5},\n        )\n\n        self.game._current_agent_states = {\n            agent_address_1: agent_state_1,\n            agent_address_2: agent_state_2,\n        }\n\n        # operation\n        with patch.object(Transaction, \"has_matching_signatures\", return_value=False):\n            with patch.object(\n                AgentState, \"is_consistent_transaction\", return_value=True\n            ):\n                assert self.game.is_transaction_valid(tx) is False\n\n    def test_is_transaction_valid_fails_tx_inconsistent(self):\n        \"\"\"Test the is_transaction_valid method of the Game class which fails because transactions are inconsistent.\"\"\"\n        # before\n        agent_address_1 = \"agent_address_1\"\n        agent_address_2 = \"agent_address_2\"\n\n        tx = Transaction(\n            \"ethereum\",\n            agent_address_1,\n            agent_address_2,\n            {\"1\": 10},\n            {\"2\": 5, \"5\": 10},\n            True,\n            \"some_nonce\",\n            {\"1\": 1},\n            \"some_sender_signature\",\n            \"some_counterparty_signature\",\n        )\n\n        agent_state_1 = AgentState(\n            agent_address_1,\n            {\"1\": 10},\n            {\"1\": 1.0},\n            {\"2\": 1, \"3\": 2},\n            {\"2\": 1.0, \"3\": 1.5},\n        )\n        agent_state_2 = AgentState(\n            agent_address_2,\n            {\"1\": 10},\n            {\"1\": 1.0},\n            {\"2\": 1, \"3\": 2},\n            {\"2\": 1.0, \"3\": 1.5},\n        )\n\n        self.game._current_agent_states = {\n            agent_address_1: agent_state_1,\n            agent_address_2: agent_state_2,\n        }\n\n        # operation\n        with patch.object(Transaction, \"has_matching_signatures\", return_value=True):\n            with patch.object(\n                AgentState, \"is_consistent_transaction\", return_value=False\n            ):\n                assert self.game.is_transaction_valid(tx) is False\n\n    def test_settle_transaction_succeeds(self):\n        \"\"\"Test the settle_transaction method of the Game class which succeeds.\"\"\"\n        # setup\n        agent_address_1 = \"agent_address_1\"\n        agent_address_2 = \"agent_address_2\"\n\n        tx = Transaction(\n            \"ethereum\",\n            agent_address_1,\n            agent_address_2,\n            {\"1\": 10},\n            {\"2\": -1, \"3\": 0},\n            True,\n            \"some_nonce\",\n            {\"1\": 1},\n            \"some_sender_signature\",\n            \"some_counterparty_signature\",\n        )\n        agent_state_1 = AgentState(\n            agent_address_1,\n            {\"1\": 10},\n            {\"1\": 1.0},\n            {\"2\": 1, \"3\": 2},\n            {\"2\": 1.0, \"3\": 1.5},\n        )\n        agent_state_2 = AgentState(\n            agent_address_2,\n            {\"1\": 10},\n            {\"1\": 1.0},\n            {\"2\": 1, \"3\": 2},\n            {\"2\": 1.0, \"3\": 1.5},\n        )\n\n        self.game._current_agent_states = {\n            agent_address_1: agent_state_1,\n            agent_address_2: agent_state_2,\n        }\n\n        expected_agent_state_1 = AgentState(\n            agent_address_1,\n            {\"1\": 20},\n            {\"1\": 1.0},\n            {\"2\": 0, \"3\": 2},\n            {\"2\": 1.0, \"3\": 1.5},\n        )\n        expected_agent_state_2 = AgentState(\n            agent_address_2,\n            {\"1\": 0},\n            {\"1\": 1.0},\n            {\"2\": 2, \"3\": 2},\n            {\"2\": 1.0, \"3\": 1.5},\n        )\n\n        # before\n        assert self.game._current_agent_states[agent_address_1] == agent_state_1\n        assert self.game._current_agent_states[agent_address_2] == agent_state_2\n\n        # operation\n        with patch.object(Transaction, \"has_matching_signatures\", return_value=True):\n            self.game.settle_transaction(tx)\n\n        # after\n        assert (\n            self.game._current_agent_states[agent_address_1] == expected_agent_state_1\n        )\n        assert (\n            self.game._current_agent_states[agent_address_2] == expected_agent_state_2\n        )\n\n    def test_settle_transaction_fails_current_agent_states_is_none(self):\n        \"\"\"Test the settle_transaction method of the Game class which fails because current_agent_states is None.\"\"\"\n        # before\n        agent_address_1 = \"agent_address_1\"\n        agent_address_2 = \"agent_address_2\"\n\n        tx = Transaction(\n            \"ethereum\",\n            agent_address_1,\n            agent_address_2,\n            {\"1\": 10},\n            {\"2\": 5, \"5\": 10},\n            True,\n            \"some_nonce\",\n            {\"1\": 1},\n            \"some_sender_signature\",\n            \"some_counterparty_signature\",\n        )\n\n        # operation\n        with pytest.raises(\n            AEAEnforceError, match=\"Call create before calling current_agent_states.\"\n        ):\n            assert self.game.settle_transaction(tx)\n\n    def test_settle_transaction_fails_tx_invalid(self):\n        \"\"\"Test the settle_transaction method of the Game class which fails because transaction is invalid.\"\"\"\n        # before\n        agent_address_1 = \"agent_address_1\"\n        agent_address_2 = \"agent_address_2\"\n\n        tx = Transaction(\n            \"ethereum\",\n            agent_address_1,\n            agent_address_2,\n            {\"1\": 10},\n            {\"2\": 5, \"5\": 10},\n            True,\n            \"some_nonce\",\n            {\"1\": 1},\n            \"some_sender_signature\",\n            \"some_counterparty_signature\",\n        )\n        self.game._current_agent_states = \"some_current_agent_states\"\n\n        # operation\n        with patch.object(self.game, \"is_transaction_valid\", return_value=False):\n            with pytest.raises(AEAEnforceError, match=\"Transaction is not valid.\"):\n                assert self.game.settle_transaction(tx)\n\n    def test_get_location_description(self):\n        \"\"\"Test the get_location_description method of the Game class.\"\"\"\n        description = self.game.get_location_description()\n\n        assert type(description) == Description\n        assert description.data_model is AGENT_LOCATION_MODEL\n        assert description.values.get(\"location\", \"\") == Location(\n            longitude=0.1270, latitude=51.5194\n        )\n\n    def test_get_register_tac_description(self):\n        \"\"\"Test the get_register_tac_description method of the Game class.\"\"\"\n        description = self.game.get_register_tac_description()\n\n        assert type(description) == Description\n        assert description.data_model is AGENT_SET_SERVICE_MODEL\n        assert description.values.get(\"key\", \"\") == \"tac\"\n        assert description.values.get(\"value\", \"\") == \"v1\"\n\n    def test_get_register_personality_description(self):\n        \"\"\"Test the get_register_personality_description method of the GenericStrategy class.\"\"\"\n        description = self.game.get_register_personality_description()\n\n        assert type(description) == Description\n        assert description.data_model is AGENT_PERSONALITY_MODEL\n        assert description.values.get(\"piece\", \"\") == \"genus\"\n        assert description.values.get(\"value\", \"\") == \"service\"\n\n    def test_get_register_classification_description(self):\n        \"\"\"Test the get_register_classification_description method of the GenericStrategy class.\"\"\"\n        description = self.game.get_register_classification_description()\n\n        assert type(description) == Description\n        assert description.data_model is AGENT_PERSONALITY_MODEL\n        assert description.values.get(\"piece\", \"\") == \"classification\"\n        assert description.values.get(\"value\", \"\") == \"tac.controller\"\n\n    def test_get_unregister_tac_description(self):\n        \"\"\"Test the get_unregister_tac_description method of the Game class.\"\"\"\n        description = self.game.get_unregister_tac_description()\n\n        assert type(description) == Description\n        assert description.data_model is AGENT_REMOVE_SERVICE_MODEL\n        assert description.values.get(\"key\", \"\") == \"tac\"\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_tac_control/test_handlers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the handler classes of the tac control skill.\"\"\"\n\nimport logging\nfrom pathlib import Path\nfrom typing import cast\nfrom unittest.mock import PropertyMock, patch\n\nimport pytest\n\nfrom aea.helpers.search.models import Attribute, DataModel, Description, Location\nfrom aea.protocols.dialogue.base import DialogueMessage, Dialogues\nfrom aea.test_tools.test_skill import BaseSkillTestCase, COUNTERPARTY_AGENT_ADDRESS\n\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.protocols.tac.message import TacMessage\nfrom packages.fetchai.skills.tac_control.behaviours import TacBehaviour\nfrom packages.fetchai.skills.tac_control.dialogues import (\n    OefSearchDialogues,\n    TacDialogues,\n)\nfrom packages.fetchai.skills.tac_control.game import (\n    Configuration,\n    Game,\n    Phase,\n    Transaction,\n)\nfrom packages.fetchai.skills.tac_control.handlers import OefSearchHandler, TacHandler\nfrom packages.fetchai.skills.tac_control.parameters import Parameters\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass TestTacHandler(BaseSkillTestCase):\n    \"\"\"Test tac handler of tac control.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"tac_control\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.tac_handler = cast(TacHandler, cls._skill.skill_context.handlers.tac)\n        cls.tac_dialogues = cast(TacDialogues, cls._skill.skill_context.tac_dialogues)\n        cls.game = cast(Game, cls._skill.skill_context.game)\n        cls.parameters = cast(Parameters, cls._skill.skill_context.parameters)\n\n        cls.agent_name = \"some_agent_name\"\n        cls.list_of_messages = (\n            DialogueMessage(\n                TacMessage.Performative.REGISTER, {\"agent_name\": cls.agent_name}, True\n            ),\n            DialogueMessage(\n                TacMessage.Performative.GAME_DATA,\n                {\n                    \"amount_by_currency_id\": {\"FET\": 1},\n                    \"exchange_params_by_currency_id\": {\"FET\": 1.0},\n                    \"quantities_by_good_id\": {\"G1\": 10},\n                    \"utility_params_by_good_id\": {\"G1\": 1.0},\n                    \"fee_by_currency_id\": {\"FET\": 1},\n                    \"agent_addr_to_name\": {COUNTERPARTY_AGENT_ADDRESS: \"some_name\"},\n                    \"currency_id_to_name\": {\"FET\": \"FETCH\"},\n                    \"good_id_to_name\": {\"G1\": \"Good_1\"},\n                    \"version_id\": \"v1\",\n                },\n            ),\n        )\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the fipa handler.\"\"\"\n        assert self.tac_handler.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle_unidentified_dialogue(self):\n        \"\"\"Test the _handle_unidentified_dialogue method of the fipa handler.\"\"\"\n        # setup\n        incorrect_dialogue_reference = (\"\", \"\")\n        incoming_message = self.build_incoming_message(\n            message_type=TacMessage,\n            dialogue_reference=incorrect_dialogue_reference,\n            performative=TacMessage.Performative.CANCELLED,\n        )\n\n        # operation\n        with patch.object(self.tac_handler.context.logger, \"log\") as mock_logger:\n            self.tac_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received invalid tac message={incoming_message}, unidentified dialogue (reference={incoming_message.dialogue_reference}).\",\n        )\n        self.assert_quantity_in_outbox(1)\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=DefaultMessage,\n            performative=DefaultMessage.Performative.ERROR,\n            to=incoming_message.sender,\n            sender=self.skill.skill_context.agent_address,\n            error_code=DefaultMessage.ErrorCode.INVALID_DIALOGUE,\n            error_msg=\"Invalid dialogue.\",\n            error_data={\"tac_message\": incoming_message.encode()},\n        )\n        assert has_attributes, error_str\n\n    def test_on_register_not_pre_reg_phase(self):\n        \"\"\"Test the _on_register method of the tac handler where phase is NOT pre_registration.\"\"\"\n        # setup\n        self.game._phase = Phase.PRE_GAME\n\n        incoming_message = self.build_incoming_message(\n            message_type=TacMessage,\n            performative=TacMessage.Performative.REGISTER,\n            dialogue_reference=Dialogues.new_self_initiated_dialogue_reference(),\n            agent_name=self.agent_name,\n        )\n\n        # operation\n        with patch.object(self.tac_handler.context.logger, \"log\") as mock_logger:\n            self.tac_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"received registration outside of game registration phase: '{incoming_message}'\",\n        )\n\n    def test_on_register_agent_not_in_whitelist(self):\n        \"\"\"Test the _on_register method of the tac handler where the agent is NOT in the whitelist.\"\"\"\n        # setup\n        self.game._phase = Phase.GAME_REGISTRATION\n        self.parameters._whitelist = [\"some_other_agent\", \"yet_another_agent\"]\n\n        incoming_message = self.build_incoming_message(\n            message_type=TacMessage,\n            performative=TacMessage.Performative.REGISTER,\n            dialogue_reference=Dialogues.new_self_initiated_dialogue_reference(),\n            agent_name=self.agent_name,\n        )\n\n        # operation\n        with patch.object(self.tac_handler.context.logger, \"log\") as mock_logger:\n            self.tac_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING, f\"agent name not in whitelist: '{self.agent_name}'\"\n        )\n        self.assert_quantity_in_outbox(1)\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=TacMessage,\n            performative=TacMessage.Performative.TAC_ERROR,\n            to=COUNTERPARTY_AGENT_ADDRESS,\n            sender=self.skill.skill_context.agent_address,\n            target=incoming_message.message_id,\n            error_code=TacMessage.ErrorCode.AGENT_NAME_NOT_IN_WHITELIST,\n        )\n        assert has_attributes, error_str\n\n    def test_on_register_agent_address_already_exists(self):\n        \"\"\"Test the _on_register method of the tac handler where the agent address of the sender is already registered.\"\"\"\n        # setup\n        self.game._phase = Phase.GAME_REGISTRATION\n        self.game._registration.register_agent(\n            COUNTERPARTY_AGENT_ADDRESS, self.agent_name\n        )\n\n        incoming_message = self.build_incoming_message(\n            message_type=TacMessage,\n            performative=TacMessage.Performative.REGISTER,\n            dialogue_reference=Dialogues.new_self_initiated_dialogue_reference(),\n            agent_name=\"some_name\",\n        )\n\n        # operation\n        with patch.object(self.tac_handler.context.logger, \"log\") as mock_logger:\n            self.tac_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING, f\"agent already registered: '{self.agent_name}'\"\n        )\n        self.assert_quantity_in_outbox(1)\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=TacMessage,\n            performative=TacMessage.Performative.TAC_ERROR,\n            to=COUNTERPARTY_AGENT_ADDRESS,\n            sender=self.skill.skill_context.agent_address,\n            target=incoming_message.message_id,\n            error_code=TacMessage.ErrorCode.AGENT_ADDR_ALREADY_REGISTERED,\n        )\n        assert has_attributes, error_str\n\n    def test_on_register_agent_name_already_exists(self):\n        \"\"\"Test the _on_register method of the tac handler where the agent name of the sender is already registered.\"\"\"\n        # setup\n        self.game._phase = Phase.GAME_REGISTRATION\n        self.game._registration.register_agent(\"some_address\", self.agent_name)\n\n        incoming_message = self.build_incoming_message(\n            message_type=TacMessage,\n            performative=TacMessage.Performative.REGISTER,\n            dialogue_reference=Dialogues.new_self_initiated_dialogue_reference(),\n            agent_name=self.agent_name,\n        )\n\n        # operation\n        with patch.object(self.tac_handler.context.logger, \"log\") as mock_logger:\n            self.tac_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"agent with this name already registered: '{self.agent_name}'\",\n        )\n        self.assert_quantity_in_outbox(1)\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=TacMessage,\n            performative=TacMessage.Performative.TAC_ERROR,\n            to=COUNTERPARTY_AGENT_ADDRESS,\n            sender=self.skill.skill_context.agent_address,\n            target=incoming_message.message_id,\n            error_code=TacMessage.ErrorCode.AGENT_NAME_ALREADY_REGISTERED,\n        )\n        assert has_attributes, error_str\n\n    def test_on_register(self):\n        \"\"\"Test the _on_register method of the tac handler, the successful case.\"\"\"\n        # setup\n        self.game._phase = Phase.GAME_REGISTRATION\n\n        incoming_message = self.build_incoming_message(\n            message_type=TacMessage,\n            performative=TacMessage.Performative.REGISTER,\n            dialogue_reference=Dialogues.new_self_initiated_dialogue_reference(),\n            agent_name=self.agent_name,\n        )\n\n        # before\n        assert self.game.registration.nb_agents == 0\n\n        # operation\n        with patch.object(self.tac_handler.context.logger, \"log\") as mock_logger:\n            self.tac_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"agent '{incoming_message.sender}' registered as '{self.agent_name}'\",\n        )\n        assert self.game.registration.nb_agents == 1\n\n    def test_on_unregister_not_pre_reg_phase(self):\n        \"\"\"Test the _on_unregister method of the tac handler where phase is NOT pre_registration.\"\"\"\n        # setup\n        self.game._phase = Phase.PRE_GAME\n\n        dialogue = self.prepare_skill_dialogue(\n            self.tac_dialogues, self.list_of_messages[:1]\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=dialogue,\n            performative=TacMessage.Performative.UNREGISTER,\n        )\n\n        # operation\n        with patch.object(self.tac_handler.context.logger, \"log\") as mock_logger:\n            self.tac_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"received unregister outside of game registration phase: '{incoming_message}'\",\n        )\n\n    def test_on_unregister_agent_address_not_registered(self):\n        \"\"\"Test the _on_unregister method of the tac handler where the agent address of the sender is not registered.\"\"\"\n        # setup\n        self.game._phase = Phase.GAME_REGISTRATION\n\n        dialogue = self.prepare_skill_dialogue(\n            self.tac_dialogues, self.list_of_messages[:1]\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=dialogue,\n            performative=TacMessage.Performative.UNREGISTER,\n        )\n\n        # operation\n        with patch.object(self.tac_handler.context.logger, \"log\") as mock_logger:\n            self.tac_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING, f\"agent not registered: '{COUNTERPARTY_AGENT_ADDRESS}'\"\n        )\n        self.assert_quantity_in_outbox(1)\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=TacMessage,\n            performative=TacMessage.Performative.TAC_ERROR,\n            to=COUNTERPARTY_AGENT_ADDRESS,\n            sender=self.skill.skill_context.agent_address,\n            target=incoming_message.message_id,\n            error_code=TacMessage.ErrorCode.AGENT_NOT_REGISTERED,\n        )\n        assert has_attributes, error_str\n\n    def test_on_unregister(self):\n        \"\"\"Test the _on_unregister method of the tac handler: successful.\"\"\"\n        # setup\n        self.game._phase = Phase.GAME_REGISTRATION\n        self.game._registration.register_agent(\n            COUNTERPARTY_AGENT_ADDRESS, self.agent_name\n        )\n        self.game._registration.register_agent(\"address_2\", \"name_2\")\n        self.game._conf = Configuration(\n            \"v1\",\n            1,\n            self.game.registration.agent_addr_to_name,\n            {\"key_1\": \"v_1\"},\n            {\"k_1\": \"v_1\", \"k_2\": \"v_2\"},\n        )\n\n        dialogue = self.prepare_skill_dialogue(\n            self.tac_dialogues, self.list_of_messages[:1]\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=dialogue,\n            performative=TacMessage.Performative.UNREGISTER,\n        )\n\n        # before\n        assert self.game.registration.nb_agents == 2\n\n        # operation\n        with patch.object(self.tac_handler.context.logger, \"log\") as mock_logger:\n            self.tac_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.DEBUG, f\"agent unregistered: '{self.agent_name}'\"\n        )\n        assert self.game.registration.nb_agents == 1\n\n    def test_on_transaction(self):\n        \"\"\"Test the _on_transaction method of the tac handler where phase is NOT GAME.\"\"\"\n        # setup\n        self.game._phase = Phase.PRE_GAME\n        dialogue = self.prepare_skill_dialogue(\n            self.tac_dialogues, self.list_of_messages[:2]\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=dialogue,\n            performative=TacMessage.Performative.TRANSACTION,\n            transaction_id=\"some_id\",\n            ledger_id=\"some_ledger\",\n            sender_address=COUNTERPARTY_AGENT_ADDRESS,\n            counterparty_address=self.skill.skill_context.agent_address,\n            amount_by_currency_id={\"FET\": 1},\n            fee_by_currency_id={\"FET\": 2},\n            quantities_by_good_id={\"G1\": 1},\n            nonce=\"some_nonce\",\n            sender_signature=\"some_signature\",\n            counterparty_signature=\"some_other_signature\",\n        )\n\n        # operation\n        with patch.object(self.tac_handler.context.logger, \"log\") as mock_logger:\n            self.tac_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"received transaction outside of game phase: '{incoming_message}'\",\n        )\n\n    def test_on_transaction_valid(self):\n        \"\"\"Test the _on_transaction method of the tac handler where the transaction is valid.\"\"\"\n        # setup\n        self.game._phase = Phase.GAME\n\n        tac_participant_sender = COUNTERPARTY_AGENT_ADDRESS\n        tac_participant_counterparty = \"counterparties_counterparty\"\n\n        counterparty_dialogue = self.prepare_skill_dialogue(\n            self.tac_dialogues, self.list_of_messages[:2], tac_participant_counterparty\n        )\n        self_dialogue = self.prepare_skill_dialogue(\n            self.tac_dialogues,\n            self.list_of_messages[:2],\n        )\n\n        ledger_id = \"some_ledger\"\n        good_ids = [\"G1\"]\n        nonce = \"some_nonce\"\n        amount_by_currency_id = {\"FET\": 1}\n        quantities_by_good_id = {\"G1\": 1}\n        tx_id = Transaction.get_hash(\n            ledger_id=ledger_id,\n            sender_address=tac_participant_sender,\n            counterparty_address=tac_participant_counterparty,\n            good_ids=good_ids,\n            sender_supplied_quantities=[1],\n            counterparty_supplied_quantities=[0],\n            sender_payable_amount=0,\n            counterparty_payable_amount=1,\n            nonce=nonce,\n        )\n        incoming_message = cast(\n            TacMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=self_dialogue,\n                performative=TacMessage.Performative.TRANSACTION,\n                transaction_id=tx_id,\n                ledger_id=ledger_id,\n                sender_address=tac_participant_sender,\n                counterparty_address=tac_participant_counterparty,\n                amount_by_currency_id=amount_by_currency_id,\n                fee_by_currency_id={\"FET\": 2},\n                quantities_by_good_id=quantities_by_good_id,\n                nonce=nonce,\n                sender_signature=\"some_signature\",\n                counterparty_signature=\"some_other_signature\",\n            ),\n        )\n        tx = Transaction.from_message(incoming_message)\n\n        mocked_holdings_summary = \"some_holdings_summary\"\n\n        # operation\n        with patch.object(\n            type(self.game),\n            \"holdings_summary\",\n            new_callable=PropertyMock,\n            return_value=mocked_holdings_summary,\n        ):\n            with patch.object(self.game, \"is_transaction_valid\", return_value=True):\n                with patch.object(self.game, \"settle_transaction\"):\n                    with patch.object(\n                        self.tac_handler.context.logger, \"log\"\n                    ) as mock_logger:\n                        self.tac_handler.handle(incoming_message)\n\n        # after\n        self.assert_quantity_in_outbox(2)\n\n        # _on_transaction\n        mock_logger.assert_any_call(logging.DEBUG, f\"handling transaction: {tx}\")\n\n        # _handle_valid_transaction\n        mock_logger.assert_any_call(\n            logging.INFO, f\"handling valid transaction: {tx_id[-10:]}\"\n        )\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=TacMessage,\n            performative=TacMessage.Performative.TRANSACTION_CONFIRMATION,\n            to=tac_participant_sender,\n            sender=self.skill.skill_context.agent_address,\n            target=incoming_message.message_id,\n            transaction_id=tx_id,\n            amount_by_currency_id=amount_by_currency_id,\n            quantities_by_good_id=quantities_by_good_id,\n        )\n        assert has_attributes, error_str\n\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=TacMessage,\n            performative=TacMessage.Performative.TRANSACTION_CONFIRMATION,\n            to=tac_participant_counterparty,\n            sender=self.skill.skill_context.agent_address,\n            # in this case message_id is negative so previous  negative id is  id + 1\n            target=counterparty_dialogue.last_message.message_id + 1,\n            transaction_id=tx.counterparty_hash,\n            amount_by_currency_id=amount_by_currency_id,\n            quantities_by_good_id=quantities_by_good_id,\n        )\n        assert has_attributes, error_str\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"transaction '{tx_id[-10:]}' between '{self.skill.skill_context.agent_address}' and '{self.skill.skill_context.agent_address}' settled successfully.\",\n        )\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"total number of transactions settled: {len(self.game.transactions.confirmed)}\",\n        )\n        mock_logger.assert_any_call(\n            logging.INFO, f\"current state:\\n{mocked_holdings_summary}\"\n        )\n\n    def test_handle_valid_transaction_recovered_tac_dialogue_not_1(self):\n        \"\"\"Test the _handle_valid_transaction method of the tac handler where the number of recivered tac dialogues is 0.\"\"\"\n        # setup\n        self.game._phase = Phase.GAME\n\n        tac_participant_sender = COUNTERPARTY_AGENT_ADDRESS\n        tac_participant_counterparty = \"counterparties_counterparty\"\n\n        self_dialogue = self.prepare_skill_dialogue(\n            self.tac_dialogues,\n            self.list_of_messages[:2],\n        )\n\n        ledger_id = \"some_ledger\"\n        good_ids = [\"G1\"]\n        nonce = \"some_nonce\"\n        amount_by_currency_id = {\"FET\": 1}\n        quantities_by_good_id = {\"G1\": 1}\n        tx_id = Transaction.get_hash(\n            ledger_id=ledger_id,\n            sender_address=tac_participant_sender,\n            counterparty_address=tac_participant_counterparty,\n            good_ids=good_ids,\n            sender_supplied_quantities=[1],\n            counterparty_supplied_quantities=[0],\n            sender_payable_amount=0,\n            counterparty_payable_amount=1,\n            nonce=nonce,\n        )\n        incoming_message = cast(\n            TacMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=self_dialogue,\n                performative=TacMessage.Performative.TRANSACTION,\n                transaction_id=tx_id,\n                ledger_id=ledger_id,\n                sender_address=tac_participant_sender,\n                counterparty_address=tac_participant_counterparty,\n                amount_by_currency_id=amount_by_currency_id,\n                fee_by_currency_id={\"FET\": 2},\n                quantities_by_good_id=quantities_by_good_id,\n                nonce=nonce,\n                sender_signature=\"some_signature\",\n                counterparty_signature=\"some_other_signature\",\n            ),\n        )\n        tx = Transaction.from_message(incoming_message)\n\n        mocked_holdings_summary = \"some_holdings_summary\"\n\n        # operation\n        with patch.object(\n            type(self.game),\n            \"holdings_summary\",\n            new_callable=PropertyMock,\n            return_value=mocked_holdings_summary,\n        ):\n            with patch.object(self.game, \"is_transaction_valid\", return_value=True):\n                with patch.object(self.game, \"settle_transaction\"):\n                    with patch.object(\n                        self.tac_handler.context.logger, \"log\"\n                    ) as mock_logger:\n                        with pytest.raises(\n                            ValueError, match=\"Error when retrieving dialogue.\"\n                        ):\n                            self.tac_handler.handle(incoming_message)\n\n        # after\n        self.assert_quantity_in_outbox(1)\n\n        # _on_transaction\n        mock_logger.assert_any_call(logging.DEBUG, f\"handling transaction: {tx}\")\n\n        # _handle_valid_transaction\n        mock_logger.assert_any_call(\n            logging.INFO, f\"handling valid transaction: {tx_id[-10:]}\"\n        )\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=TacMessage,\n            performative=TacMessage.Performative.TRANSACTION_CONFIRMATION,\n            to=tac_participant_sender,\n            sender=self.skill.skill_context.agent_address,\n            target=incoming_message.message_id,\n            transaction_id=tx_id,\n            amount_by_currency_id=amount_by_currency_id,\n            quantities_by_good_id=quantities_by_good_id,\n        )\n        assert has_attributes, error_str\n\n    def test_handle_valid_transaction_no_last_message(self):\n        \"\"\"Test the _handle_valid_transaction method of the tac handler where the recovered dialogue is empty.\"\"\"\n        # setup\n        self.game._phase = Phase.GAME\n\n        tac_participant_sender = COUNTERPARTY_AGENT_ADDRESS\n        tac_participant_counterparty = \"counterparties_counterparty\"\n\n        counterparty_dialogue = self.prepare_skill_dialogue(\n            self.tac_dialogues, self.list_of_messages[:2], tac_participant_counterparty\n        )\n        self_dialogue = self.prepare_skill_dialogue(\n            self.tac_dialogues,\n            self.list_of_messages[:2],\n        )\n        counterparty_dialogue._incoming_messages = []\n        counterparty_dialogue._outgoing_messages = []\n\n        ledger_id = \"some_ledger\"\n        good_ids = [\"G1\"]\n        nonce = \"some_nonce\"\n        amount_by_currency_id = {\"FET\": 1}\n        quantities_by_good_id = {\"G1\": 1}\n        tx_id = Transaction.get_hash(\n            ledger_id=ledger_id,\n            sender_address=tac_participant_sender,\n            counterparty_address=tac_participant_counterparty,\n            good_ids=good_ids,\n            sender_supplied_quantities=[1],\n            counterparty_supplied_quantities=[0],\n            sender_payable_amount=0,\n            counterparty_payable_amount=1,\n            nonce=nonce,\n        )\n        incoming_message = cast(\n            TacMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=self_dialogue,\n                performative=TacMessage.Performative.TRANSACTION,\n                transaction_id=tx_id,\n                ledger_id=ledger_id,\n                sender_address=tac_participant_sender,\n                counterparty_address=tac_participant_counterparty,\n                amount_by_currency_id=amount_by_currency_id,\n                fee_by_currency_id={\"FET\": 2},\n                quantities_by_good_id=quantities_by_good_id,\n                nonce=nonce,\n                sender_signature=\"some_signature\",\n                counterparty_signature=\"some_other_signature\",\n            ),\n        )\n        tx = Transaction.from_message(incoming_message)\n\n        mocked_holdings_summary = \"some_holdings_summary\"\n\n        # operation\n        with patch.object(\n            type(self.game),\n            \"holdings_summary\",\n            new_callable=PropertyMock,\n            return_value=mocked_holdings_summary,\n        ):\n            with patch.object(self.game, \"is_transaction_valid\", return_value=True):\n                with patch.object(self.game, \"settle_transaction\"):\n                    with patch.object(\n                        self.tac_handler.context.logger, \"log\"\n                    ) as mock_logger:\n                        with pytest.raises(\n                            ValueError, match=\"Error when retrieving last message.\"\n                        ):\n                            self.tac_handler.handle(incoming_message)\n\n        # after\n        self.assert_quantity_in_outbox(1)\n\n        # _on_transaction\n        mock_logger.assert_any_call(logging.DEBUG, f\"handling transaction: {tx}\")\n\n        # _handle_valid_transaction\n        mock_logger.assert_any_call(\n            logging.INFO, f\"handling valid transaction: {tx_id[-10:]}\"\n        )\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=TacMessage,\n            performative=TacMessage.Performative.TRANSACTION_CONFIRMATION,\n            to=tac_participant_sender,\n            sender=self.skill.skill_context.agent_address,\n            target=incoming_message.message_id,\n            transaction_id=tx_id,\n            amount_by_currency_id=amount_by_currency_id,\n            quantities_by_good_id=quantities_by_good_id,\n        )\n        assert has_attributes, error_str\n\n    def test_on_transaction_invalid(self):\n        \"\"\"Test the _on_transaction method of the tac handler where the transaction is invalid.\"\"\"\n        # setup\n        self.game._phase = Phase.GAME\n\n        tac_participant_sender = COUNTERPARTY_AGENT_ADDRESS\n        tac_participant_counterparty = \"counterparties_counterparty\"\n\n        self_dialogue = self.prepare_skill_dialogue(\n            self.tac_dialogues,\n            self.list_of_messages[:2],\n        )\n\n        ledger_id = \"some_ledger\"\n        good_ids = [\"G1\"]\n        nonce = \"some_nonce\"\n        amount_by_currency_id = {\"FET\": 1}\n        quantities_by_good_id = {\"G1\": 1}\n        tx_id = Transaction.get_hash(\n            ledger_id=ledger_id,\n            sender_address=tac_participant_sender,\n            counterparty_address=tac_participant_counterparty,\n            good_ids=good_ids,\n            sender_supplied_quantities=[1],\n            counterparty_supplied_quantities=[0],\n            sender_payable_amount=0,\n            counterparty_payable_amount=1,\n            nonce=nonce,\n        )\n        incoming_message = cast(\n            TacMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=self_dialogue,\n                performative=TacMessage.Performative.TRANSACTION,\n                transaction_id=tx_id,\n                ledger_id=ledger_id,\n                sender_address=tac_participant_sender,\n                counterparty_address=tac_participant_counterparty,\n                amount_by_currency_id=amount_by_currency_id,\n                fee_by_currency_id={\"FET\": 2},\n                quantities_by_good_id=quantities_by_good_id,\n                nonce=nonce,\n                sender_signature=\"some_signature\",\n                counterparty_signature=\"some_other_signature\",\n            ),\n        )\n        tx = Transaction.from_message(incoming_message)\n\n        # operation\n        with patch.object(self.game, \"is_transaction_valid\", return_value=False):\n            with patch.object(self.tac_handler.context.logger, \"log\") as mock_logger:\n                self.tac_handler.handle(incoming_message)\n\n        # after\n        self.assert_quantity_in_outbox(1)\n\n        # _on_transaction\n        mock_logger.assert_any_call(logging.DEBUG, f\"handling transaction: {tx}\")\n\n        # _handle_invalid_transaction\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"handling invalid transaction: {tx_id}, tac_msg={incoming_message}\",\n        )\n\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=TacMessage,\n            performative=TacMessage.Performative.TAC_ERROR,\n            to=tac_participant_sender,\n            sender=self.skill.skill_context.agent_address,\n            target=incoming_message.message_id,\n            error_code=TacMessage.ErrorCode.TRANSACTION_NOT_VALID,\n            info={\"transaction_id\": tx_id},\n        )\n        assert has_attributes, error_str\n\n    def test_handle_invalid(self):\n        \"\"\"Test the _handle_invalid method of the fipa handler.\"\"\"\n        # setup\n        tac_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.tac_dialogues,\n            messages=self.list_of_messages[:2],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=tac_dialogue,\n            performative=TacMessage.Performative.CANCELLED,\n        )\n\n        # operation\n        with patch.object(self.tac_handler.context.logger, \"log\") as mock_logger:\n            self.tac_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"cannot handle tac message of performative={incoming_message.performative} in dialogue={tac_dialogue}.\",\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the fipa handler.\"\"\"\n        assert self.tac_handler.teardown() is None\n        self.assert_quantity_in_outbox(0)\n\n\nclass TestOefSearchHandler(BaseSkillTestCase):\n    \"\"\"Test oef search handler of tac control.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"tac_control\")\n    is_agent_to_agent_messages = False\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.oef_search_handler = cast(\n            OefSearchHandler, cls._skill.skill_context.handlers.oef\n        )\n        cls.oef_dialogues = cast(\n            OefSearchDialogues, cls._skill.skill_context.oef_search_dialogues\n        )\n        cls.service_registration_behaviour = cast(\n            TacBehaviour,\n            cls._skill.skill_context.behaviours.tac,\n        )\n        cls.game = cast(Game, cls._skill.skill_context.game)\n        cls.list_of_messages = (\n            DialogueMessage(\n                OefSearchMessage.Performative.SEARCH_SERVICES, {\"query\": \"some_query\"}\n            ),\n        )\n\n        cls.register_location_description = Description(\n            {\"location\": Location(51.5194, 0.1270)},\n            data_model=DataModel(\n                \"location_agent\", [Attribute(\"location\", Location, True)]\n            ),\n        )\n        cls.list_of_messages_register_location = (\n            DialogueMessage(\n                OefSearchMessage.Performative.REGISTER_SERVICE,\n                {\"service_description\": cls.register_location_description},\n                is_incoming=False,\n            ),\n        )\n\n        cls.register_service_description = Description(\n            {\"key\": \"some_key\", \"value\": \"some_value\"},\n            data_model=DataModel(\n                \"set_service_key\",\n                [Attribute(\"key\", str, True), Attribute(\"value\", str, True)],\n            ),\n        )\n        cls.list_of_messages_register_service = (\n            DialogueMessage(\n                OefSearchMessage.Performative.REGISTER_SERVICE,\n                {\"service_description\": cls.register_service_description},\n                is_incoming=False,\n            ),\n        )\n\n        cls.register_genus_description = Description(\n            {\"piece\": \"genus\", \"value\": \"some_value\"},\n            data_model=DataModel(\n                \"personality_agent\",\n                [Attribute(\"piece\", str, True), Attribute(\"value\", str, True)],\n            ),\n        )\n        cls.list_of_messages_register_genus = (\n            DialogueMessage(\n                OefSearchMessage.Performative.REGISTER_SERVICE,\n                {\"service_description\": cls.register_genus_description},\n                is_incoming=False,\n            ),\n        )\n\n        cls.register_classification_description = Description(\n            {\"piece\": \"classification\", \"value\": \"some_value\"},\n            data_model=DataModel(\n                \"personality_agent\",\n                [Attribute(\"piece\", str, True), Attribute(\"value\", str, True)],\n            ),\n        )\n        cls.list_of_messages_register_classification = (\n            DialogueMessage(\n                OefSearchMessage.Performative.REGISTER_SERVICE,\n                {\"service_description\": cls.register_classification_description},\n                is_incoming=False,\n            ),\n        )\n\n        cls.register_invalid_description = Description(\n            {\"piece\": \"classification\", \"value\": \"some_value\"},\n            data_model=DataModel(\n                \"some_different_name\",\n                [Attribute(\"piece\", str, True), Attribute(\"value\", str, True)],\n            ),\n        )\n        cls.list_of_messages_register_invalid = (\n            DialogueMessage(\n                OefSearchMessage.Performative.REGISTER_SERVICE,\n                {\"service_description\": cls.register_invalid_description},\n                is_incoming=False,\n            ),\n        )\n\n        cls.unregister_description = Description(\n            {\"key\": \"seller_service\"},\n            data_model=DataModel(\"remove\", [Attribute(\"key\", str, True)]),\n        )\n        cls.list_of_messages_unregister = (\n            DialogueMessage(\n                OefSearchMessage.Performative.UNREGISTER_SERVICE,\n                {\"service_description\": cls.unregister_description},\n                is_incoming=False,\n            ),\n        )\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the oef handler.\"\"\"\n        assert self.oef_search_handler.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle_unidentified_dialogue(self):\n        \"\"\"Test the _handle_unidentified_dialogue method of the oef handler.\"\"\"\n        # setup\n        incorrect_dialogue_reference = (\"\", \"\")\n        incoming_message = self.build_incoming_message(\n            message_type=OefSearchMessage,\n            dialogue_reference=incorrect_dialogue_reference,\n            performative=OefSearchMessage.Performative.SEARCH_SERVICES,\n        )\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received invalid oef_search message={incoming_message}, unidentified dialogue.\",\n        )\n\n    def test_handle_success_i(self):\n        \"\"\"Test the _handle_success method of the oef_search handler where the oef success targets register_service WITH location_agent data model description.\"\"\"\n        # setup\n        oef_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_dialogues,\n            messages=self.list_of_messages_register_location[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=oef_dialogue,\n            performative=OefSearchMessage.Performative.SUCCESS,\n            agents_info=OefSearchMessage.AgentsInfo({\"address\": {\"key\": \"value\"}}),\n        )\n\n        # before\n        assert self.game.is_registered_agent is False\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            with patch.object(\n                self.service_registration_behaviour,\n                \"register_genus\",\n            ) as mock_reg:\n                self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received oef_search success message={incoming_message} in dialogue={oef_dialogue}.\",\n        )\n        mock_reg.assert_called_once()\n        assert self.game.is_registered_agent is False\n\n    def test_handle_success_ii(self):\n        \"\"\"Test the _handle_success method of the oef_search handler where the oef success targets register_service WITH personality_agent data model and genus value description.\"\"\"\n        # setup\n        oef_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_dialogues,\n            messages=self.list_of_messages_register_genus[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=oef_dialogue,\n            performative=OefSearchMessage.Performative.SUCCESS,\n            agents_info=OefSearchMessage.AgentsInfo({\"address\": {\"key\": \"value\"}}),\n        )\n\n        # before\n        assert self.game.is_registered_agent is False\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            with patch.object(\n                self.service_registration_behaviour,\n                \"register_classification\",\n            ) as mock_reg:\n                self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received oef_search success message={incoming_message} in dialogue={oef_dialogue}.\",\n        )\n        mock_reg.assert_called_once()\n        assert self.game.is_registered_agent is False\n\n    def test_handle_success_iii(self):\n        \"\"\"Test the _handle_success method of the oef_search handler where the oef success targets register_service WITH personality_agent data model and classification value description.\"\"\"\n        # setup\n        oef_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_dialogues,\n            messages=self.list_of_messages_register_classification[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=oef_dialogue,\n            performative=OefSearchMessage.Performative.SUCCESS,\n            agents_info=OefSearchMessage.AgentsInfo({\"address\": {\"key\": \"value\"}}),\n        )\n\n        # before\n        assert self.game.is_registered_agent is False\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received oef_search success message={incoming_message} in dialogue={oef_dialogue}.\",\n        )\n        mock_logger.assert_any_call(\n            logging.INFO,\n            \"the agent, with its genus and classification, is successfully registered on the SOEF.\",\n        )\n        assert self.game.is_registered_agent is True\n\n    def test_handle_success_v(self):\n        \"\"\"Test the _handle_success method of the oef_search handler where the oef successtargets unregister_service.\"\"\"\n        # setup\n        oef_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_dialogues,\n            messages=self.list_of_messages_register_invalid[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=oef_dialogue,\n            performative=OefSearchMessage.Performative.SUCCESS,\n            agents_info=OefSearchMessage.AgentsInfo({\"address\": {\"key\": \"value\"}}),\n        )\n\n        # before\n        assert self.game.is_registered_agent is False\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received oef_search success message={incoming_message} in dialogue={oef_dialogue}.\",\n        )\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"received soef SUCCESS message as a reply to the following unexpected message: {oef_dialogue.get_message_by_id(incoming_message.target)}\",\n        )\n        assert self.game.is_registered_agent is False\n\n    def test_handle_error_i(self):\n        \"\"\"Test the _handle_error method of the oef_search handler where the oef error targets register_service.\"\"\"\n        # setup\n        oef_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_dialogues,\n            messages=self.list_of_messages_register_location[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=oef_dialogue,\n            performative=OefSearchMessage.Performative.OEF_ERROR,\n            oef_error_operation=OefSearchMessage.OefErrorOperation.SEARCH_SERVICES,\n        )\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        self.assert_quantity_in_outbox(0)\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received oef_search error message={incoming_message} in dialogue={oef_dialogue}.\",\n        )\n        assert (\n            self.service_registration_behaviour.failed_registration_msg\n            == oef_dialogue.get_message_by_id(incoming_message.target)\n        )\n\n    def test_handle_error_ii(self):\n        \"\"\"Test the _handle_error method of the oef_search handler where the oef error does NOT target register_service.\"\"\"\n        # setup\n        oef_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_dialogues,\n            messages=self.list_of_messages_unregister[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=oef_dialogue,\n            performative=OefSearchMessage.Performative.OEF_ERROR,\n            oef_error_operation=OefSearchMessage.OefErrorOperation.SEARCH_SERVICES,\n        )\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        self.assert_quantity_in_outbox(0)\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received oef_search error message={incoming_message} in dialogue={oef_dialogue}.\",\n        )\n\n        assert self.service_registration_behaviour.failed_registration_msg is None\n\n    def test_handle_invalid(self):\n        \"\"\"Test the _handle_invalid method of the oef handler.\"\"\"\n        # setup\n        invalid_performative = OefSearchMessage.Performative.UNREGISTER_SERVICE\n        incoming_message = self.build_incoming_message(\n            message_type=OefSearchMessage,\n            dialogue_reference=(\"1\", \"\"),\n            performative=invalid_performative,\n            service_description=\"some_service_description\",\n        )\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"cannot handle oef_search message of performative={invalid_performative} in dialogue={self.oef_dialogues.get_dialogue(incoming_message)}.\",\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the oef_search handler.\"\"\"\n        assert self.oef_search_handler.teardown() is None\n        self.assert_quantity_in_outbox(0)\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_tac_control/test_helpers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the helpers module of the tac control skill.\"\"\"\n\nfrom pathlib import Path\nfrom unittest.mock import patch\n\nimport pytest\n\nfrom aea.exceptions import AEAEnforceError\nfrom aea.test_tools.test_skill import BaseSkillTestCase\n\nfrom packages.fetchai.skills.tac_control.helpers import (\n    ERC1155Contract,\n    _sample_good_instances,\n    determine_scaling_factor,\n    generate_currency_endowments,\n    generate_currency_id_to_name,\n    generate_currency_ids,\n    generate_equilibrium_prices_and_holdings,\n    generate_exchange_params,\n    generate_good_endowments,\n    generate_good_id_to_name,\n    generate_good_ids,\n    generate_utility_params,\n)\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass TestHelpers(BaseSkillTestCase):\n    \"\"\"Test Helper module methods of tac control.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"tac_control\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n\n    def test_generate_good_ids_succeeds(self):\n        \"\"\"Test the generate_good_ids of Helpers module.\"\"\"\n        expected_list = [1, 2, 3, 4, 5]\n        with patch.object(\n            ERC1155Contract, \"generate_token_ids\", return_value=expected_list\n        ):\n            good_ids = generate_good_ids(5, 2)\n        assert good_ids == expected_list\n\n    def test_generate_good_ids_fails(self):\n        \"\"\"Test the generate_good_ids of Helpers module which fails because the generate_token_ids generates wrong good ids.\"\"\"\n        expected_list = [1, 2, 3, 4, 5, 6]\n        with patch.object(\n            ERC1155Contract, \"generate_token_ids\", return_value=expected_list\n        ):\n            with pytest.raises(\n                AEAEnforceError,\n                match=\"Length of good ids and number of goods must match.\",\n            ):\n                assert generate_good_ids(5, 2)\n\n    def test_generate_currency_ids_succeeds(self):\n        \"\"\"Test the generate_good_ids of Helpers module which succeeds.\"\"\"\n        expected_list = [1, 2, 3, 4, 5]\n        with patch.object(\n            ERC1155Contract, \"generate_token_ids\", return_value=expected_list\n        ):\n            currency_ids = generate_currency_ids(5, 2)\n        assert currency_ids == expected_list\n\n    def test_generate_currency_ids_fails(self):\n        \"\"\"Test the generate_good_ids of Helpers module which fails because generate_token_ids generates wrong currency ids.\"\"\"\n        expected_list = [1, 2, 3, 4, 5, 6]\n        with patch.object(\n            ERC1155Contract, \"generate_token_ids\", return_value=expected_list\n        ):\n            with pytest.raises(\n                AEAEnforceError,\n                match=\"Length of currency ids and number of currencies must match.\",\n            ):\n                assert generate_currency_ids(5, 2)\n\n    def test_generate_currency_id_to_name(self):\n        \"\"\"Test the generate_currency_id_to_name of Helpers module.\"\"\"\n        expected_currency_id_to_name = {\n            \"1\": \"FT_1\",\n            \"3\": \"FT_3\",\n            \"5\": \"FT_5\",\n            \"7\": \"FT_7\",\n            \"9\": \"FT_9\",\n        }\n        currency_id_to_name = generate_currency_id_to_name(5, [1, 3, 5, 7, 9])\n        assert currency_id_to_name == expected_currency_id_to_name\n\n    def test_generate_currency_id_to_name_invalid_lengths(self):\n        \"\"\"Test the generate_currency_id_to_name of Helpers module where the lengths do not match.\"\"\"\n        # phase\n        with pytest.raises(\n            AEAEnforceError,\n            match=\"Length of currency_ids does not match nb_currencies.\",\n        ):\n            assert generate_currency_id_to_name(nb_currencies=1, currency_ids=[1, 2])\n\n    def test_generate_good_id_to_name(self):\n        \"\"\"Test the generate_good_id_to_name of Helpers module.\"\"\"\n        expected_good_id_to_name = {\n            \"1\": \"FT_1\",\n            \"3\": \"FT_3\",\n            \"5\": \"FT_5\",\n            \"7\": \"FT_7\",\n            \"9\": \"FT_9\",\n        }\n        good_id_to_name = generate_good_id_to_name(5, [1, 3, 5, 7, 9])\n        assert good_id_to_name == expected_good_id_to_name\n\n    def test_generate_good_id_to_name_invalid_lengths(self):\n        \"\"\"Test the generate_good_id_to_name of Helpers module.\"\"\"\n        # phase\n        with pytest.raises(\n            AEAEnforceError, match=\"Length of good_ids does not match nb_goods.\"\n        ):\n            assert generate_good_id_to_name(nb_goods=1, good_ids=[1, 2])\n\n    def test_determine_scaling_factor(self):\n        \"\"\"Test the determine_scaling_factor of Helpers module.\"\"\"\n        money_endowment = 53730411\n        scaling_factor = determine_scaling_factor(money_endowment)\n        assert scaling_factor == 10000000.0\n\n    def test_generate_good_endowments(self):\n        \"\"\"Test the generate_good_endowments of Helpers module.\"\"\"\n        endowments = generate_good_endowments(\n            [\"ag_1_add\", \"ag_2_add\"], [\"good_id_1\", \"good_id_2\"], 2, 1, 1\n        )\n        assert \"good_id_1\" in endowments[\"ag_1_add\"]\n        assert \"good_id_2\" in endowments[\"ag_1_add\"]\n        assert \"good_id_1\" in endowments[\"ag_2_add\"]\n        assert \"good_id_2\" in endowments[\"ag_2_add\"]\n\n    def test_generate_utility_params(self):\n        \"\"\"Test the generate_utility_params of Helpers module.\"\"\"\n        utility_function_params = generate_utility_params(\n            [\"ag_1_add\", \"ag_2_add\"], [\"good_id_1\", \"good_id_2\"], 1000.0\n        )\n        assert \"good_id_1\" in utility_function_params[\"ag_1_add\"].keys()\n        assert \"good_id_2\" in utility_function_params[\"ag_1_add\"].keys()\n        assert \"good_id_1\" in utility_function_params[\"ag_2_add\"].keys()\n        assert \"good_id_2\" in utility_function_params[\"ag_2_add\"].keys()\n\n    def test_sample_good_instances(self):\n        \"\"\"Test the _sample_good_instances of Helpers module.\"\"\"\n        nb_instances = _sample_good_instances(2, [\"good_id_1\", \"good_id_2\"], 2, 1, 1)\n        assert type(nb_instances[\"good_id_1\"]) == int\n        assert type(nb_instances[\"good_id_2\"]) == int\n\n    def test_generate_currency_endowments(self):\n        \"\"\"Test the generate_currency_endowments of Helpers module.\"\"\"\n        currency_endowments = generate_currency_endowments(\n            [\"ag_1_add\", \"ag_2_add\"], [\"currency_id_1\", \"currency_id_2\"], 10\n        )\n        assert \"currency_id_1\" in currency_endowments[\"ag_1_add\"].keys()\n        assert \"currency_id_2\" in currency_endowments[\"ag_2_add\"].keys()\n        assert currency_endowments[\"ag_1_add\"][\"currency_id_1\"] == 10\n        assert currency_endowments[\"ag_1_add\"][\"currency_id_2\"] == 10\n\n        assert currency_endowments[\"ag_2_add\"][\"currency_id_1\"] == 10\n        assert currency_endowments[\"ag_2_add\"][\"currency_id_2\"] == 10\n\n    def test_generate_exchange_params(self):\n        \"\"\"Test the generate_exchange_params of Helpers module.\"\"\"\n        currency_endowments = generate_exchange_params(\n            [\"ag_1_add\", \"ag_2_add\"], [\"currency_id_1\", \"currency_id_2\"]\n        )\n        assert \"currency_id_1\" in currency_endowments[\"ag_1_add\"].keys()\n        assert \"currency_id_2\" in currency_endowments[\"ag_2_add\"].keys()\n        assert currency_endowments[\"ag_1_add\"][\"currency_id_1\"] == 1.0\n        assert currency_endowments[\"ag_1_add\"][\"currency_id_2\"] == 1.0\n\n        assert currency_endowments[\"ag_2_add\"][\"currency_id_1\"] == 1.0\n        assert currency_endowments[\"ag_2_add\"][\"currency_id_2\"] == 1.0\n\n    def test_generate_equilibrium_prices_and_holdings(self):\n        \"\"\"Test the generate_equilibrium_prices_and_holdings of Helpers module.\"\"\"\n        (\n            eq_prices_dict,\n            eq_good_holdings_dict,\n            eq_currency_holdings_dict,\n        ) = generate_equilibrium_prices_and_holdings(\n            {\"ag_1\": {\"good_1\": 1}},\n            {\"ag_1\": {\"good_1\": 1.0}},\n            {\"ag_1\": {\"currency_1\": 10}},\n            {\"ag_1\": {\"currency_1\": 1.0}},\n            2.0,\n        )\n\n        assert len(eq_prices_dict) == 1\n        assert type(eq_prices_dict[\"good_1\"]) == float\n\n        assert len(eq_good_holdings_dict) == 1\n        assert len(eq_good_holdings_dict[\"ag_1\"]) == 1\n        assert type(eq_good_holdings_dict[\"ag_1\"][\"good_1\"]) == float\n\n        assert len(eq_currency_holdings_dict) == 1\n        assert type(eq_currency_holdings_dict[\"ag_1\"][\"currency_1\"]) == float\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_tac_control/test_parameters.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the parameters module of the tac control skill.\"\"\"\n\nimport datetime\nimport logging\nfrom pathlib import Path\nfrom unittest.mock import Mock, patch\n\nimport pytest\n\nfrom aea.exceptions import AEAEnforceError\nfrom aea.helpers.search.models import Location\nfrom aea.test_tools.test_skill import BaseSkillTestCase\n\nfrom packages.fetchai.skills.tac_control.parameters import Parameters\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass TestParameters(BaseSkillTestCase):\n    \"\"\"Test Parameters module of tac control.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"tac_control\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.kwargs = {\n            \"ledger_id\": \"some_ledger_id\",\n            \"contract_address\": None,\n            \"good_ids\": [],\n            \"currency_ids\": [],\n            \"min_nb_agents\": 2,\n            \"money_endowment\": 200,\n            \"nb_goods\": 9,\n            \"nb_currencies\": 1,\n            \"tx_fee\": 1,\n            \"base_good_endowment\": 2,\n            \"lower_bound_factor\": 1,\n            \"upper_bound_factor\": 1,\n            \"registration_start_time\": \"01 01 2020  00:01\",\n            \"registration_timeout\": 60,\n            \"item_setup_timeout\": 60,\n            \"competition_timeout\": 300,\n            \"inactivity_timeout\": 30,\n            \"whitelist\": [],\n            \"location\": {\"longitude\": 0.1270, \"latitude\": 51.5194},\n            \"service_data\": {\"key\": \"tac\", \"value\": \"v1\"},\n            \"name\": \"parameters\",\n            \"skill_context\": cls._skill.skill_context,\n        }\n        cls.parameters = Parameters(**cls.kwargs)\n\n    @staticmethod\n    def _time(date_time: str):\n        return datetime.datetime.strptime(date_time, \"%d %m %Y %H:%M\")\n\n    def test_init_now_after_start(self):\n        \"\"\"Test the init of Parameters where now is after the registration_start_time.\"\"\"\n        mocked_start_time = self._time(\"01 01 2020 00:01\")\n        mocked_now_time = self._time(\"01 01 2020 00:02\")\n\n        datetime_mock = Mock(wraps=datetime.datetime)\n        datetime_mock.now.return_value = mocked_now_time\n\n        with patch(\"datetime.datetime\", new=datetime_mock):\n            with patch.object(self.parameters.context.logger, \"log\") as mocked_logger:\n                Parameters(**self.kwargs)\n        mocked_logger.assert_any_call(\n            logging.WARNING,\n            f\"TAC registration start time {mocked_start_time} is in the past! Deregistering skill.\",\n        )\n        assert self.skill.skill_context.is_active is False\n\n    def test_init_now_before_start(self):\n        \"\"\"Test the init of Parameters where now is before the registration_start_time.\"\"\"\n        mocked_start_time_str = \"01 01 2020  00:03\"\n\n        mocked_start_time = self._time(mocked_start_time_str)\n        mocked_now_time = self._time(\"01 01 2020  00:02\")\n\n        datetime_mock = Mock(wraps=datetime.datetime)\n        datetime_mock.now.return_value = mocked_now_time\n\n        self.kwargs[\"registration_start_time\"] = mocked_start_time_str\n\n        with patch(\"datetime.datetime\", new=datetime_mock):\n            with patch.object(self.parameters.context.logger, \"log\") as mocked_logger:\n                par = Parameters(**self.kwargs)\n        mocked_logger.assert_any_call(\n            logging.INFO,\n            f\"TAC registation start time: {mocked_start_time}, and registration end time: {par.registration_end_time}, and start time: \"\n            f\"{par.start_time}, \"\n            f\"and end time: {par.end_time}\",\n        )\n\n    def test_simple_properties(self):\n        \"\"\"Test the properties of Parameters class.\"\"\"\n        # phase\n        assert self.parameters.ledger_id == \"some_ledger_id\"\n\n        self.parameters._contract_address = None\n        with pytest.raises(AEAEnforceError, match=\"No contract address provided.\"):\n            assert self.parameters.contract_address\n\n        self.parameters.contract_address = \"some_contract_address\"\n        assert self.parameters.contract_address == \"some_contract_address\"\n\n        with pytest.raises(AEAEnforceError, match=\"Contract address already provided.\"):\n            self.parameters.contract_address = \"some_contract_address\"\n\n        assert self.parameters.contract_id == self.parameters._contract_id\n\n        assert self.parameters.is_contract_deployed is True\n        self.parameters._contract_address = None\n        assert self.parameters.is_contract_deployed is False\n\n        assert self.parameters.registration_end_time == datetime.datetime.strptime(\n            \"01 01 2020  00:02\", \"%d %m %Y %H:%M\"\n        )\n\n        assert self.parameters.inactivity_timeout == 30\n\n        assert self.parameters.agent_location == {\n            \"location\": Location(latitude=51.5194, longitude=0.1270)\n        }\n        assert self.parameters.set_service_data == {\"key\": \"tac\", \"value\": \"v1\"}\n        assert self.parameters.set_personality_data == {\n            \"piece\": \"genus\",\n            \"value\": \"service\",\n        }\n        assert self.parameters.set_classification == {\n            \"piece\": \"classification\",\n            \"value\": \"tac.controller\",\n        }\n        assert self.parameters.remove_service_data == {\"key\": \"tac\"}\n        assert self.parameters.simple_service_data == {\"tac\": \"v1\"}\n\n    def test_init_inconsistent(self):\n        \"\"\"Test the __init__ of the Parameters class where _check_consistency raises an exception.\"\"\"\n        self.kwargs[\"contract_address\"] = \"some_contract_address\"\n        error_message = \"If the contract address is set, then good ids and currency id must be provided and consistent.\"\n\n        with pytest.raises(ValueError, match=error_message):\n            assert Parameters(\n                **self.kwargs,\n            )\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_tac_control_contract/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"The tests module contains the tests of the packages/skills/tac_control_contract dir.\"\"\"\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_tac_control_contract/test_behaviours.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the behaviour classes of the tac control contract skill.\"\"\"\n\nimport datetime\nimport logging\nfrom pathlib import Path\nfrom typing import cast\nfrom unittest.mock import Mock, patch\n\nfrom aea.helpers.search.models import Description\nfrom aea.test_tools.test_skill import BaseSkillTestCase, COUNTERPARTY_AGENT_ADDRESS\n\nfrom packages.fetchai.protocols.contract_api.message import ContractApiMessage\nfrom packages.fetchai.skills.tac_control_contract.behaviours import (\n    LEDGER_API_ADDRESS,\n    TacBehaviour,\n)\nfrom packages.fetchai.skills.tac_control_contract.dialogues import (\n    ContractApiDialogue,\n    ContractApiDialogues,\n    TacDialogues,\n)\nfrom packages.fetchai.skills.tac_control_contract.game import (\n    AgentState,\n    Configuration,\n    Game,\n    Phase,\n)\nfrom packages.fetchai.skills.tac_control_contract.parameters import (\n    DEFAULT_CONTRACT_DEPLOY_FEE,\n    DEFAULT_CONTRACT_EXECUTE_FEE,\n    Parameters,\n)\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass TestSkillBehaviour(BaseSkillTestCase):\n    \"\"\"Test tac behaviour of tac_control_contract.\"\"\"\n\n    path_to_skill = Path(\n        ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"tac_control_contract\"\n    )\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.tac_behaviour = cast(TacBehaviour, cls._skill.skill_context.behaviours.tac)\n        cls.game = cast(Game, cls._skill.skill_context.game)\n        cls.parameters = cast(Parameters, cls._skill.skill_context.parameters)\n        cls.tac_dialogues = cast(TacDialogues, cls._skill.skill_context.tac_dialogues)\n        cls.contract_api_dialogues = cast(\n            ContractApiDialogues, cls._skill.skill_context.contract_api_dialogues\n        )\n        cls.logger = cls.tac_behaviour.context.logger\n\n        cls.mocked_reg_start_time = cls._time(\"00:02\")\n        cls.mocked_reg_end_time = cls._time(\"00:04\")\n        cls.mocked_start_time = cls._time(\"00:06\")\n        cls.mocked_end_time = cls._time(\"00:08\")\n\n        cls.parameters._registration_start_time = cls.mocked_reg_start_time\n        cls.parameters._registration_end_time = cls.mocked_reg_end_time\n        cls.parameters._start_time = cls.mocked_start_time\n        cls.parameters._end_time = cls.mocked_end_time\n\n        cls.mocked_description = Description({\"foo1\": 1, \"bar1\": 2})\n\n        cls.agent_1_address = \"agent_address_1\"\n        cls.agent_1_name = \"agent_name_1\"\n        cls.agent_2_address = \"agent_address_2\"\n        cls.agent_2_name = \"agent_name_2\"\n\n        cls.amount_by_currency_id = {\"1\": 10}\n        cls.exchange_params_by_currency_id = {\"1\": 1.0}\n        cls.quantities_by_good_id = {\"2\": 1, \"3\": 2}\n        cls.utility_params_by_good_id = {\"2\": 1.0, \"3\": 1.5}\n\n        cls.agent_1_state = AgentState(\n            cls.agent_1_address,\n            cls.amount_by_currency_id,\n            cls.exchange_params_by_currency_id,\n            cls.quantities_by_good_id,\n            cls.utility_params_by_good_id,\n        )\n        cls.agent_2_state = AgentState(\n            cls.agent_2_address,\n            cls.amount_by_currency_id,\n            cls.exchange_params_by_currency_id,\n            cls.quantities_by_good_id,\n            cls.utility_params_by_good_id,\n        )\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the tac behaviour.\"\"\"\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.tac_behaviour.setup()\n\n        # after\n        assert self.game.phase == Phase.CONTRACT_DEPLOYMENT_PROPOSAL\n\n        self.assert_quantity_in_outbox(2)\n\n        # first message is produced in superclass (from tac_control skill) which has its own unit tests\n        self.drop_messages_from_outbox(1)\n\n        # _request_contract_deploy_transaction\n        message = self.get_message_from_outbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=ContractApiMessage,\n            performative=ContractApiMessage.Performative.GET_DEPLOY_TRANSACTION,\n            to=LEDGER_API_ADDRESS,\n            sender=str(self.skill.skill_context.skill_id),\n            ledger_id=self.parameters.ledger_id,\n            contract_id=self.parameters.contract_id,\n            callable=ContractApiDialogue.Callable.GET_DEPLOY_TRANSACTION.value,\n            kwargs=ContractApiMessage.Kwargs(\n                {\n                    \"deployer_address\": self.skill.skill_context.agent_address,\n                    \"gas\": 5000000,\n                    \"tx_fee\": DEFAULT_CONTRACT_DEPLOY_FEE,\n                }\n            ),\n        )\n        assert has_attributes, error_str\n        assert (\n            cast(\n                ContractApiDialogue, self.contract_api_dialogues.get_dialogue(message)\n            ).terms\n            == self.parameters.get_deploy_terms()\n        )\n        assert (\n            cast(\n                ContractApiDialogue, self.contract_api_dialogues.get_dialogue(message)\n            ).callable\n            == ContractApiDialogue.Callable.GET_DEPLOY_TRANSACTION\n        )\n        mock_logger.assert_any_call(\n            logging.INFO, \"requesting contract deployment transaction...\"\n        )\n\n    @staticmethod\n    def _time(time: str):\n        date_time = \"01 01 2020  \" + time\n        return datetime.datetime.strptime(date_time, \"%d %m %Y %H:%M\")\n\n    @staticmethod\n    def _mock_time(time: str) -> Mock:\n        mocked_now_time = TestSkillBehaviour._time(time)\n\n        datetime_mock = Mock(wraps=datetime.datetime)\n        datetime_mock.now.return_value = mocked_now_time\n        return datetime_mock\n\n    def test_act_i(self):\n        \"\"\"Test the act method of the tac behaviour where phase is contract_deployed and reg_start_time < now < reg_end_time.\"\"\"\n        # setup\n        self.game._phase = Phase.CONTRACT_DEPLOYED\n\n        mocked_now = self._mock_time(\"00:03\")\n\n        # operation\n        with patch(\"datetime.datetime\", new=mocked_now):\n            with patch.object(self.tac_behaviour, \"_register_tac\") as mock_register_tac:\n                with patch.object(self.logger, \"log\") as mock_logger:\n                    self.tac_behaviour.act()\n\n        # after\n        assert self.game.phase == Phase.GAME_REGISTRATION\n\n        # _register_tac is a superclass method with its own unit test in test_tac_control\n        mock_register_tac.assert_called_once()\n\n        mock_logger.assert_any_call(\n            logging.INFO, f\"TAC open for registration until: {self.mocked_reg_end_time}\"\n        )\n\n    def test_act_ii(self):\n        \"\"\"Test the act method of the tac behaviour where phase is game_registration and reg_end_time < now < start_time and nb_agent < min_nb_agents.\"\"\"\n        # setup\n        self.game._phase = Phase.GAME_REGISTRATION\n\n        mocked_now = self._mock_time(\"00:05\")\n\n        self.parameters._min_nb_agents = 2\n        self.game._registration.register_agent(\n            COUNTERPARTY_AGENT_ADDRESS, self.agent_1_name\n        )\n\n        # operation\n        with patch(\"datetime.datetime\", new=mocked_now):\n            with patch.object(self.tac_behaviour, \"_cancel_tac\") as mock_cancel_tac:\n                with patch.object(\n                    self.tac_behaviour, \"_unregister_tac\"\n                ) as mock_unregister_tac:\n                    with patch.object(self.logger, \"log\") as mock_logger:\n                        self.tac_behaviour.act()\n\n        # after\n        mock_logger.assert_any_call(logging.INFO, \"closing registration!\")\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"registered agents={1}, minimum agents required={self.parameters._min_nb_agents}\",\n        )\n\n        # _cancel_tac is a superclass method with its own unit test in test_tac_control\n        mock_cancel_tac.assert_called_with(self.game)\n\n        assert self.game.phase == Phase.POST_GAME\n\n        # _unregister_tac is a superclass method with its own unit test in test_tac_control\n        mock_unregister_tac.assert_called_once()\n\n        assert self.skill.skill_context.is_active is False\n\n    def test_act_iii(self):\n        \"\"\"Test the act method of the tac behaviour where phase is game_registration and reg_end_time < now < start_time and nb_agent >= min_nb_agents.\"\"\"\n        # setup\n        self.game._phase = Phase.GAME_REGISTRATION\n\n        mocked_now = self._mock_time(\"00:05\")\n\n        self.parameters._contract_address = \"some_contract_address\"\n\n        self.parameters._min_nb_agents = 2\n        self.game._registration.register_agent(self.agent_1_address, self.agent_1_name)\n        self.game._registration.register_agent(self.agent_2_address, self.agent_2_name)\n\n        # operation\n        with patch(\"datetime.datetime\", new=mocked_now):\n            with patch.object(\n                self.tac_behaviour, \"_unregister_tac\"\n            ) as mock_unregister_tac:\n                with patch.object(self.logger, \"log\") as mock_logger:\n                    self.tac_behaviour.act()\n\n        # after\n        mock_logger.assert_any_call(logging.INFO, \"closing registration!\")\n        assert self.game.phase == Phase.GAME_SETUP\n        assert self.game.conf.contract_address == self.parameters.contract_address\n\n        # _unregister_tac is a superclass method with its own unit test in test_tac_control\n        mock_unregister_tac.assert_called_once()\n\n    def test_act_iv(self):\n        \"\"\"Test the act method of the tac behaviour where phase is GAME_SETUP and reg_end_time < now < start_time.\"\"\"\n        # setup\n        self.game._phase = Phase.GAME_SETUP\n\n        mocked_now = self._mock_time(\"00:05\")\n\n        self.parameters._min_nb_agents = 2\n        self.game._registration.register_agent(self.agent_1_address, self.agent_1_name)\n        self.game._registration.register_agent(self.agent_2_address, self.agent_2_name)\n\n        self.game._conf = Configuration(\n            \"v1\",\n            1,\n            self.game.registration.agent_addr_to_name,\n            {\"1\": \"currency_name\"},\n            {\"2\": \"good_1\", \"3\": \"good_2\"},\n        )\n\n        self.parameters._contract_address = \"some_contract_address\"\n\n        # operation\n        with patch(\"datetime.datetime\", new=mocked_now):\n            with patch.object(self.logger, \"log\") as mock_logger:\n                self.tac_behaviour.act()\n\n        # after\n        assert self.game.phase == Phase.TOKENS_CREATION_PROPOSAL\n\n        # _request_create_items_transaction\n        self.assert_quantity_in_outbox(1)\n        message = self.get_message_from_outbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=ContractApiMessage,\n            performative=ContractApiMessage.Performative.GET_RAW_TRANSACTION,\n            to=LEDGER_API_ADDRESS,\n            sender=str(self.skill.skill_context.skill_id),\n            ledger_id=self.parameters.ledger_id,\n            contract_id=self.parameters.contract_id,\n            contract_address=self.parameters.contract_address,\n            callable=ContractApiDialogue.Callable.GET_CREATE_BATCH_TRANSACTION.value,\n            kwargs=ContractApiMessage.Kwargs(\n                {\n                    \"deployer_address\": self.skill.skill_context.agent_address,\n                    \"token_ids\": [2, 3, 1],\n                    \"gas\": 5000000,\n                    \"tx_fee\": DEFAULT_CONTRACT_EXECUTE_FEE,\n                }\n            ),\n        )\n        assert has_attributes, error_str\n        assert (\n            cast(\n                ContractApiDialogue, self.contract_api_dialogues.get_dialogue(message)\n            ).terms\n            == self.parameters.get_create_token_terms()\n        )\n        assert (\n            cast(\n                ContractApiDialogue, self.contract_api_dialogues.get_dialogue(message)\n            ).callable\n            == ContractApiDialogue.Callable.GET_CREATE_BATCH_TRANSACTION\n        )\n        mock_logger.assert_any_call(\n            logging.INFO, \"requesting create items transaction...\"\n        )\n\n    def test_act_v(self):\n        \"\"\"Test the act method of the tac behaviour where phase is TOKENS_CREATED.\"\"\"\n        # setup\n        self.game._phase = Phase.TOKENS_CREATED\n\n        self.parameters._min_nb_agents = 2\n        self.game._registration.register_agent(self.agent_1_address, self.agent_1_name)\n        self.game._registration.register_agent(self.agent_2_address, self.agent_2_name)\n\n        self.game._initial_agent_states = {\n            self.agent_1_address: self.agent_1_state,\n            self.agent_2_address: self.agent_2_state,\n        }\n\n        self.parameters._contract_address = \"some_contract_address\"\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.tac_behaviour.act()\n\n        # after\n        assert self.game.phase == Phase.TOKENS_MINTING_PROPOSAL\n\n        # _request_mint_items_transaction\n        assert self.game.is_allowed_to_mint is False\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"requesting mint_items transactions for agent={self.agent_1_name}.\",\n        )\n\n        self.assert_quantity_in_outbox(1)\n        message = self.get_message_from_outbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=ContractApiMessage,\n            performative=ContractApiMessage.Performative.GET_RAW_TRANSACTION,\n            to=LEDGER_API_ADDRESS,\n            sender=str(self.skill.skill_context.skill_id),\n            ledger_id=self.parameters.ledger_id,\n            contract_id=self.parameters.contract_id,\n            contract_address=self.parameters.contract_address,\n            callable=ContractApiDialogue.Callable.GET_MINT_BATCH_TRANSACTION.value,\n            kwargs=ContractApiMessage.Kwargs(\n                {\n                    \"deployer_address\": self.skill.skill_context.agent_address,\n                    \"recipient_address\": self.agent_1_address,\n                    \"token_ids\": [2, 3, 1],\n                    \"mint_quantities\": [1, 2, 10],\n                    \"gas\": 5000000,\n                    \"tx_fee\": DEFAULT_CONTRACT_EXECUTE_FEE,\n                }\n            ),\n        )\n        assert has_attributes, error_str\n\n        assert (\n            cast(\n                ContractApiDialogue, self.contract_api_dialogues.get_dialogue(message)\n            ).terms\n            == self.parameters.get_mint_token_terms()\n        )\n        assert (\n            cast(\n                ContractApiDialogue, self.contract_api_dialogues.get_dialogue(message)\n            ).callable\n            == ContractApiDialogue.Callable.GET_MINT_BATCH_TRANSACTION\n        )\n\n    def test_request_mint_items_transaction_not_allowed_to_mint(self):\n        \"\"\"Test the _request_mint_items_transaction method of the tac behaviour where is_allowed_to_mint is False.\"\"\"\n        # setup\n        self.game._phase = Phase.TOKENS_CREATED\n        self.game.is_allowed_to_mint = False\n\n        # operation\n        self.tac_behaviour.act()\n\n        # after\n        assert self.game.phase == Phase.TOKENS_MINTING_PROPOSAL\n\n        # _request_mint_items_transaction\n        self.assert_quantity_in_outbox(0)\n\n    def test_request_mint_items_transaction_agent_state_is_none(self):\n        \"\"\"Test the _request_mint_items_transaction method of the tac behaviour where agent_state is None.\"\"\"\n        # setup\n        self.game._phase = Phase.TOKENS_CREATED\n        self.game._initial_agent_states = {self.agent_1_address: None}\n\n        # operation\n        self.tac_behaviour.act()\n\n        # after\n        assert self.game.phase == Phase.TOKENS_MINTING_PROPOSAL\n\n        # _request_mint_items_transaction\n        assert self.game.is_allowed_to_mint is False\n        self.assert_quantity_in_outbox(0)\n\n    def test_act_vi(self):\n        \"\"\"Test the act method of the tac behaviour where phase is TOKENS_MINTING_PROPOSAL.\"\"\"\n        # setup\n        self.game._phase = Phase.TOKENS_MINTING_PROPOSAL\n\n        self.parameters._min_nb_agents = 2\n        self.game._registration.register_agent(self.agent_1_address, self.agent_1_name)\n        self.game._registration.register_agent(self.agent_2_address, self.agent_2_name)\n\n        self.game._initial_agent_states = {\n            self.agent_1_address: self.agent_1_state,\n            self.agent_2_address: self.agent_2_state,\n        }\n\n        self.parameters._contract_address = \"some_contract_address\"\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.tac_behaviour.act()\n\n        # after\n        assert self.game.phase == Phase.TOKENS_MINTING_PROPOSAL\n\n        # _request_mint_items_transaction\n        assert self.game.is_allowed_to_mint is False\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"requesting mint_items transactions for agent={self.agent_1_name}.\",\n        )\n\n        self.assert_quantity_in_outbox(1)\n        message = self.get_message_from_outbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=ContractApiMessage,\n            performative=ContractApiMessage.Performative.GET_RAW_TRANSACTION,\n            to=LEDGER_API_ADDRESS,\n            sender=str(self.skill.skill_context.skill_id),\n            ledger_id=self.parameters.ledger_id,\n            contract_id=self.parameters.contract_id,\n            contract_address=self.parameters.contract_address,\n            callable=ContractApiDialogue.Callable.GET_MINT_BATCH_TRANSACTION.value,\n            kwargs=ContractApiMessage.Kwargs(\n                {\n                    \"deployer_address\": self.skill.skill_context.agent_address,\n                    \"recipient_address\": self.agent_1_address,\n                    \"token_ids\": [2, 3, 1],\n                    \"mint_quantities\": [1, 2, 10],\n                    \"gas\": 5000000,\n                    \"tx_fee\": DEFAULT_CONTRACT_EXECUTE_FEE,\n                }\n            ),\n        )\n        assert has_attributes, error_str\n\n        assert (\n            cast(\n                ContractApiDialogue, self.contract_api_dialogues.get_dialogue(message)\n            ).terms\n            == self.parameters.get_mint_token_terms()\n        )\n        assert (\n            cast(\n                ContractApiDialogue, self.contract_api_dialogues.get_dialogue(message)\n            ).callable\n            == ContractApiDialogue.Callable.GET_MINT_BATCH_TRANSACTION\n        )\n\n    def test_act_vii(self):\n        \"\"\"Test the act method of the tac behaviour where phase is TOKENS_MINTED and start_time < now < end_time.\"\"\"\n        # setup\n        self.game._phase = Phase.TOKENS_MINTED\n\n        mocked_now = self._mock_time(\"00:07\")\n\n        # operation\n        with patch(\"datetime.datetime\", new=mocked_now):\n            with patch.object(self.tac_behaviour, \"_start_tac\") as mock_start_tac:\n                with patch.object(self.logger, \"log\"):\n                    self.tac_behaviour.act()\n\n        # after\n        assert self.game.phase == Phase.GAME\n\n        # _start_tac is a superclass method with its own unit test in test_tac_control\n        mock_start_tac.assert_called_with(self.game)\n\n    def test_act_viii(self):\n        \"\"\"Test the act method of the tac behaviour where phase is GAME and end_time < now.\"\"\"\n        # setup\n        self.game._phase = Phase.GAME\n\n        mocked_now = self._mock_time(\"00:09\")\n\n        # operation\n        with patch(\"datetime.datetime\", new=mocked_now):\n            with patch.object(self.tac_behaviour, \"_cancel_tac\") as mock_cancel_tac:\n                with patch.object(self.logger, \"log\"):\n                    self.tac_behaviour.act()\n\n        # after\n        assert self.game.phase == Phase.POST_GAME\n\n        # _cancel_tac is a superclass method with its own unit test in test_tac_control\n        mock_cancel_tac.assert_called_with(self.game)\n\n        assert self.skill.skill_context.is_active is False\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_tac_control_contract/test_dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the dialogue classes of the tac control contract skill.\"\"\"\n\nfrom pathlib import Path\nfrom typing import cast\n\nimport pytest\n\nfrom aea.exceptions import AEAEnforceError\nfrom aea.helpers.transaction.base import RawTransaction, Terms\nfrom aea.protocols.dialogue.base import DialogueLabel\nfrom aea.test_tools.test_skill import BaseSkillTestCase, COUNTERPARTY_AGENT_ADDRESS\n\nfrom packages.fetchai.protocols.contract_api.custom_types import Kwargs\nfrom packages.fetchai.protocols.contract_api.message import ContractApiMessage\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\nfrom packages.fetchai.protocols.signing.message import SigningMessage\nfrom packages.fetchai.skills.tac_control_contract.dialogues import (\n    ContractApiDialogue,\n    ContractApiDialogues,\n    LedgerApiDialogue,\n    LedgerApiDialogues,\n    SigningDialogue,\n    SigningDialogues,\n)\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass TestTacDialogues(BaseSkillTestCase):\n    \"\"\"Test dialogue classes of tac control contract.\"\"\"\n\n    path_to_skill = Path(\n        ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"tac_control_contract\"\n    )\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.contract_api_dialogues = cast(\n            ContractApiDialogues, cls._skill.skill_context.contract_api_dialogues\n        )\n        cls.signing_dialogues = cast(\n            SigningDialogues, cls._skill.skill_context.signing_dialogues\n        )\n        cls.ledger_api_dialogues = cast(\n            LedgerApiDialogues, cls._skill.skill_context.ledger_api_dialogues\n        )\n\n    def test_contract_api_dialogue(self):\n        \"\"\"Test the ContractApiDialogue class.\"\"\"\n        contract_api_dialogue = ContractApiDialogue(\n            DialogueLabel(\n                (\"\", \"\"),\n                COUNTERPARTY_AGENT_ADDRESS,\n                self.skill.skill_context.agent_address,\n            ),\n            self.skill.skill_context.agent_address,\n            role=ContractApiDialogue.Role.AGENT,\n        )\n\n        # callable\n        with pytest.raises(ValueError, match=\"Callable not set!\"):\n            assert contract_api_dialogue.callable\n\n        callable = ContractApiDialogue.Callable.GET_DEPLOY_TRANSACTION\n        contract_api_dialogue.callable = callable\n        with pytest.raises(AEAEnforceError, match=\"Callable already set!\"):\n            contract_api_dialogue.callable = callable\n        assert contract_api_dialogue.callable == callable\n\n        # terms\n        with pytest.raises(ValueError, match=\"Terms not set!\"):\n            assert contract_api_dialogue.terms\n        terms = Terms(\n            \"some_ledger_id\",\n            self.skill.skill_context.agent_address,\n            \"counterprty\",\n            {\"currency_id\": 50},\n            {\"good_id\": -10},\n            \"some_nonce\",\n        )\n        contract_api_dialogue.terms = terms\n        with pytest.raises(AEAEnforceError, match=\"Terms already set!\"):\n            contract_api_dialogue.terms = terms\n        assert contract_api_dialogue.terms == terms\n\n    def test_contract_api_dialogues(self):\n        \"\"\"Test the ContractApiDialogues class.\"\"\"\n        _, dialogue = self.contract_api_dialogues.create(\n            counterparty=COUNTERPARTY_AGENT_ADDRESS,\n            performative=ContractApiMessage.Performative.GET_DEPLOY_TRANSACTION,\n            ledger_id=\"some_ledger_id\",\n            contract_id=\"some_contract_id\",\n            callable=\"some_callable\",\n            kwargs=Kwargs({\"some_key\": \"some_value\"}),\n        )\n        assert dialogue.role == ContractApiDialogue.Role.AGENT\n        assert dialogue.self_address == str(self.skill.skill_context.skill_id)\n\n    def test_ledger_api_dialogue(self):\n        \"\"\"Test the LedgerApiDialogue class.\"\"\"\n        ledger_api_dialogue = LedgerApiDialogue(\n            DialogueLabel(\n                (\"\", \"\"),\n                COUNTERPARTY_AGENT_ADDRESS,\n                self.skill.skill_context.agent_address,\n            ),\n            self.skill.skill_context.agent_address,\n            role=ContractApiDialogue.Role.AGENT,\n        )\n\n        # associated_signing_dialogue\n        with pytest.raises(ValueError, match=\"Associated signing dialogue not set!\"):\n            assert ledger_api_dialogue.associated_signing_dialogue\n        signing_dialogue = SigningDialogue(\n            DialogueLabel(\n                (\"\", \"\"),\n                COUNTERPARTY_AGENT_ADDRESS,\n                self.skill.skill_context.agent_address,\n            ),\n            self.skill.skill_context.agent_address,\n            role=SigningDialogue.Role.SKILL,\n        )\n        ledger_api_dialogue.associated_signing_dialogue = signing_dialogue\n        with pytest.raises(\n            AEAEnforceError, match=\"Associated signing dialogue already set!\"\n        ):\n            ledger_api_dialogue.associated_signing_dialogue = signing_dialogue\n        assert ledger_api_dialogue.associated_signing_dialogue == signing_dialogue\n\n    def test_ledger_api_dialogues(self):\n        \"\"\"Test the LedgerApiDialogues class.\"\"\"\n        _, dialogue = self.ledger_api_dialogues.create(\n            counterparty=COUNTERPARTY_AGENT_ADDRESS,\n            performative=LedgerApiMessage.Performative.GET_BALANCE,\n            ledger_id=\"some_ledger_id\",\n            address=\"some_address\",\n        )\n        assert dialogue.role == LedgerApiDialogue.Role.AGENT\n        assert dialogue.self_address == str(self.skill.skill_context.skill_id)\n\n    def test_signing_dialogue(self):\n        \"\"\"Test the SigningDialogue class.\"\"\"\n        signing_dialogue = SigningDialogue(\n            DialogueLabel(\n                (\"\", \"\"),\n                COUNTERPARTY_AGENT_ADDRESS,\n                self.skill.skill_context.agent_address,\n            ),\n            self.skill.skill_context.agent_address,\n            role=ContractApiDialogue.Role.AGENT,\n        )\n\n        # associated_contract_api_dialogue\n        with pytest.raises(\n            ValueError, match=\"Associated contract api dialogue not set!\"\n        ):\n            assert signing_dialogue.associated_contract_api_dialogue\n        contract_api_dialogue = ContractApiDialogue(\n            DialogueLabel(\n                (\"\", \"\"),\n                COUNTERPARTY_AGENT_ADDRESS,\n                self.skill.skill_context.agent_address,\n            ),\n            self.skill.skill_context.agent_address,\n            role=ContractApiDialogue.Role.AGENT,\n        )\n        signing_dialogue.associated_contract_api_dialogue = contract_api_dialogue\n        with pytest.raises(\n            AEAEnforceError, match=\"Associated contract api dialogue already set!\"\n        ):\n            signing_dialogue.associated_contract_api_dialogue = contract_api_dialogue\n        assert (\n            signing_dialogue.associated_contract_api_dialogue == contract_api_dialogue\n        )\n\n    def test_signing_dialogues(self):\n        \"\"\"Test the SigningDialogues class.\"\"\"\n        _, dialogue = self.signing_dialogues.create(\n            counterparty=COUNTERPARTY_AGENT_ADDRESS,\n            performative=SigningMessage.Performative.SIGN_TRANSACTION,\n            terms=Terms(\n                \"some_ledger_id\",\n                \"some_sender_address\",\n                \"some_counterparty_address\",\n                dict(),\n                dict(),\n                \"some_nonce\",\n            ),\n            raw_transaction=RawTransaction(\n                \"some_ledger_id\", {\"some_key\": \"some_value\"}\n            ),\n        )\n        assert dialogue.role == SigningDialogue.Role.SKILL\n        assert dialogue.self_address == str(self.skill.skill_context.skill_id)\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_tac_control_contract/test_handlers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the handler classes of the tac control skill.\"\"\"\n\nimport logging\nfrom pathlib import Path\nfrom typing import Dict, cast\nfrom unittest.mock import patch\n\nfrom aea_ledger_fetchai import FetchAIApi\n\nfrom aea.crypto.ledger_apis import LedgerApis\nfrom aea.helpers.transaction.base import (\n    RawTransaction,\n    SignedTransaction,\n    State,\n    Terms,\n    TransactionDigest,\n    TransactionReceipt,\n)\nfrom aea.protocols.dialogue.base import DialogueMessage\nfrom aea.test_tools.test_skill import BaseSkillTestCase\n\nfrom packages.fetchai.protocols.contract_api.custom_types import Kwargs\nfrom packages.fetchai.protocols.contract_api.message import ContractApiMessage\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\nfrom packages.fetchai.protocols.signing.message import SigningMessage\nfrom packages.fetchai.skills.tac_control_contract.dialogues import (\n    ContractApiDialogue,\n    ContractApiDialogues,\n    LedgerApiDialogue,\n    LedgerApiDialogues,\n    SigningDialogue,\n    SigningDialogues,\n)\nfrom packages.fetchai.skills.tac_control_contract.game import Game, Phase\nfrom packages.fetchai.skills.tac_control_contract.handlers import (\n    ContractApiHandler,\n    LEDGER_API_ADDRESS,\n    LedgerApiHandler,\n    SigningHandler,\n)\nfrom packages.fetchai.skills.tac_control_contract.parameters import (\n    DEFAULT_CONTRACT_DEPLOY_FEE,\n    Parameters,\n)\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass TestContractApiHandler(BaseSkillTestCase):\n    \"\"\"Test contract_api handler of tac control contract.\"\"\"\n\n    path_to_skill = Path(\n        ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"tac_control_contract\"\n    )\n    is_agent_to_agent_messages = False\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.contract_api_handler = cast(\n            ContractApiHandler, cls._skill.skill_context.handlers.contract_api\n        )\n        cls.contract_api_dialogues = cast(\n            ContractApiDialogues, cls._skill.skill_context.contract_api_dialogues\n        )\n        cls.signing_dialogues = cast(\n            SigningDialogues, cls._skill.skill_context.signing_dialogues\n        )\n        cls.logger = cls.contract_api_handler.context.logger\n\n        cls.ledger_id = \"some_ledger_id\"\n        cls.contract_id = \"some_contract_id\"\n        cls.callable = \"some_callable\"\n        cls.kwargs = Kwargs({\"some_key\": \"some_value\"})\n\n        cls.list_of_contract_api_messages = (\n            DialogueMessage(\n                ContractApiMessage.Performative.GET_DEPLOY_TRANSACTION,\n                {\n                    \"ledger_id\": cls.ledger_id,\n                    \"contract_id\": cls.contract_id,\n                    \"callable\": cls.callable,\n                    \"kwargs\": cls.kwargs,\n                },\n            ),\n        )\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the contract_api handler.\"\"\"\n        assert self.contract_api_handler.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle_unidentified_dialogue(self):\n        \"\"\"Test the _handle_unidentified_dialogue method of the signing handler.\"\"\"\n        # setup\n        incorrect_dialogue_reference = (\"\", \"\")\n        incoming_message = self.build_incoming_message(\n            message_type=ContractApiMessage,\n            dialogue_reference=incorrect_dialogue_reference,\n            performative=ContractApiMessage.Performative.STATE,\n            state=State(\"some_ledger_id\", {\"some_key\": \"some_value\"}),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.contract_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received invalid contract_api message={incoming_message}, unidentified dialogue.\",\n        )\n\n    def test_handle_raw_transaction(\n        self,\n    ):\n        \"\"\"Test the _handle_signed_transaction method of the signing handler.\"\"\"\n        # setup\n        contract_api_dialogue = cast(\n            ContractApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.contract_api_dialogues,\n                messages=self.list_of_contract_api_messages[:1],\n            ),\n        )\n        contract_api_dialogue.terms = Terms(\n            \"some_ledger_id\",\n            self.skill.skill_context.agent_address,\n            \"counterprty\",\n            {\"currency_id\": 50},\n            {\"good_id\": -10},\n            \"some_nonce\",\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=contract_api_dialogue,\n            performative=ContractApiMessage.Performative.RAW_TRANSACTION,\n            raw_transaction=ContractApiMessage.RawTransaction(\n                \"some_ledger_id\", {\"some_key\": \"some_value\"}\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.contract_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO, f\"received raw transaction={incoming_message}\"\n        )\n\n        self.assert_quantity_in_decision_making_queue(1)\n        message = self.get_message_from_decision_maker_inbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=SigningMessage,\n            performative=SigningMessage.Performative.SIGN_TRANSACTION,\n            to=self.skill.skill_context.decision_maker_address,\n            sender=str(self.skill.skill_context.skill_id),\n            terms=contract_api_dialogue.terms,\n        )\n        assert has_attributes, error_str\n\n        assert (\n            cast(\n                SigningDialogue, self.signing_dialogues.get_dialogue(message)\n            ).associated_contract_api_dialogue\n            == contract_api_dialogue\n        )\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            \"proposing the transaction to the decision maker. Waiting for confirmation ...\",\n        )\n\n    def test_handle_error(self):\n        \"\"\"Test the _handle_error method of the signing handler.\"\"\"\n        # setup\n        contract_api_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.contract_api_dialogues,\n            messages=self.list_of_contract_api_messages[:1],\n        )\n        incoming_message = cast(\n            ContractApiMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=contract_api_dialogue,\n                performative=ContractApiMessage.Performative.ERROR,\n                data=b\"some_data\",\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.contract_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received contract_api error message={incoming_message} in dialogue={contract_api_dialogue}.\",\n        )\n\n    def test_handle_invalid(self):\n        \"\"\"Test the _handle_invalid method of the signing handler.\"\"\"\n        # setup\n        invalid_performative = ContractApiMessage.Performative.GET_DEPLOY_TRANSACTION\n        incoming_message = self.build_incoming_message(\n            message_type=ContractApiMessage,\n            dialogue_reference=(\"1\", \"\"),\n            performative=invalid_performative,\n            ledger_id=self.ledger_id,\n            contract_id=self.contract_id,\n            callable=self.callable,\n            kwargs=self.kwargs,\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.contract_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"cannot handle contract_api message of performative={invalid_performative} in dialogue={self.contract_api_dialogues.get_dialogue(incoming_message)}.\",\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the contract_api handler.\"\"\"\n        assert self.contract_api_handler.teardown() is None\n        self.assert_quantity_in_outbox(0)\n\n\nclass TestSigningHandler(BaseSkillTestCase):\n    \"\"\"Test signing handler of tac control contract.\"\"\"\n\n    path_to_skill = Path(\n        ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"tac_control_contract\"\n    )\n    is_agent_to_agent_messages = False\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.signing_handler = cast(\n            SigningHandler, cls._skill.skill_context.handlers.signing\n        )\n        cls.ledger_api_dialogues = cast(\n            LedgerApiDialogues, cls._skill.skill_context.ledger_api_dialogues\n        )\n        cls.signing_dialogues = cast(\n            SigningDialogues, cls._skill.skill_context.signing_dialogues\n        )\n        cls.logger = cls.signing_handler.context.logger\n\n        cls.terms = Terms(\n            \"some_ledger_id\",\n            cls._skill.skill_context.agent_address,\n            \"counterprty\",\n            {\"currency_id\": 50},\n            {\"good_id\": -10},\n            \"some_nonce\",\n        )\n        cls.list_of_signing_messages = (\n            DialogueMessage(\n                SigningMessage.Performative.SIGN_TRANSACTION,\n                {\n                    \"terms\": cls.terms,\n                    \"raw_transaction\": SigningMessage.RawTransaction(\n                        \"some_ledger_id\", {\"some_key\": \"some_value\"}\n                    ),\n                },\n            ),\n        )\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the signing handler.\"\"\"\n        assert self.signing_handler.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle_unidentified_dialogue(self):\n        \"\"\"Test the _handle_unidentified_dialogue method of the signing handler.\"\"\"\n        # setup\n        incorrect_dialogue_reference = (\"\", \"\")\n        incoming_message = self.build_incoming_message(\n            message_type=SigningMessage,\n            dialogue_reference=incorrect_dialogue_reference,\n            performative=SigningMessage.Performative.ERROR,\n            error_code=SigningMessage.ErrorCode.UNSUCCESSFUL_MESSAGE_SIGNING,\n            to=str(self.skill.skill_context.skill_id),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.signing_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received invalid signing message={incoming_message}, unidentified dialogue.\",\n        )\n\n    def test_handle_signed_transaction(\n        self,\n    ):\n        \"\"\"Test the _handle_signed_transaction method of the signing handler.\"\"\"\n        # setup\n        signing_counterparty = self.skill.skill_context.decision_maker_address\n        signing_dialogue = cast(\n            SigningDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.signing_dialogues,\n                messages=self.list_of_signing_messages[:1],\n                counterparty=signing_counterparty,\n            ),\n        )\n        incoming_message = cast(\n            SigningMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=signing_dialogue,\n                performative=SigningMessage.Performative.SIGNED_TRANSACTION,\n                signed_transaction=SigningMessage.SignedTransaction(\n                    \"some_ledger_id\", {\"some_key\": \"some_value\"}\n                ),\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.signing_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(logging.INFO, \"transaction signing was successful.\")\n\n        self.assert_quantity_in_outbox(1)\n        message = self.get_message_from_outbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=LedgerApiMessage,\n            performative=LedgerApiMessage.Performative.SEND_SIGNED_TRANSACTION,\n            to=LEDGER_API_ADDRESS,\n            sender=str(self.skill.skill_context.skill_id),\n            signed_transaction=incoming_message.signed_transaction,\n        )\n        assert has_attributes, error_str\n\n        assert (\n            cast(\n                LedgerApiDialogue, self.ledger_api_dialogues.get_dialogue(message)\n            ).associated_signing_dialogue\n            == signing_dialogue\n        )\n\n        mock_logger.assert_any_call(logging.INFO, \"sending transaction to ledger.\")\n\n    def test_handle_error(self):\n        \"\"\"Test the _handle_error method of the signing handler.\"\"\"\n        # setup\n        signing_counterparty = self.skill.skill_context.decision_maker_address\n        signing_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.signing_dialogues,\n            messages=self.list_of_signing_messages[:1],\n            counterparty=signing_counterparty,\n        )\n        incoming_message = cast(\n            SigningMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=signing_dialogue,\n                performative=SigningMessage.Performative.ERROR,\n                error_code=SigningMessage.ErrorCode.UNSUCCESSFUL_TRANSACTION_SIGNING,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.signing_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"transaction signing was not successful. Error_code={incoming_message.error_code} in dialogue={signing_dialogue}\",\n        )\n\n    def test_handle_invalid(self):\n        \"\"\"Test the _handle_invalid method of the signing handler.\"\"\"\n        # setup\n        invalid_performative = SigningMessage.Performative.SIGN_TRANSACTION\n        incoming_message = self.build_incoming_message(\n            message_type=SigningMessage,\n            dialogue_reference=(\"1\", \"\"),\n            performative=invalid_performative,\n            terms=self.terms,\n            raw_transaction=SigningMessage.RawTransaction(\n                \"some_ledger_id\", {\"some_key\": \"some_value\"}\n            ),\n            to=str(self.skill.skill_context.skill_id),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.signing_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"cannot handle signing message of performative={invalid_performative} in dialogue={self.signing_dialogues.get_dialogue(incoming_message)}.\",\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the signing handler.\"\"\"\n        assert self.signing_handler.teardown() is None\n        self.assert_quantity_in_outbox(0)\n\n\nclass TestLedgerApiHandler(BaseSkillTestCase):\n    \"\"\"Test ledger_api handler of tac control contract.\"\"\"\n\n    path_to_skill = Path(\n        ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"tac_control_contract\"\n    )\n    is_agent_to_agent_messages = False\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.ledger_api_handler = cast(\n            LedgerApiHandler, cls._skill.skill_context.handlers.ledger_api\n        )\n        cls.ledger_api_dialogues = cast(\n            LedgerApiDialogues, cls._skill.skill_context.ledger_api_dialogues\n        )\n        cls.signing_dialogues = cast(\n            SigningDialogues, cls._skill.skill_context.signing_dialogues\n        )\n        cls.contract_api_dialogues = cast(\n            ContractApiDialogues, cls._skill.skill_context.contract_api_dialogues\n        )\n        cls.parameters = cast(Parameters, cls._skill.skill_context.parameters)\n        cls.game = cast(Game, cls._skill.skill_context.game)\n\n        cls.logger = cls.ledger_api_handler.context.logger\n\n        cls.ledger_id = \"some_ledger_id\"\n        cls.contract_id = \"some_contract_id\"\n        cls.callable = \"some_callable\"\n        cls.kwargs = Kwargs({\"some_key\": \"some_value\"})\n\n        cls.body = {\"some_key\": \"some_value\"}\n        cls.body_str = \"some_body\"\n        cls.contract_address = \"some_contract_address\"\n\n        cls.raw_transaction = RawTransaction(cls.ledger_id, cls.body)\n        cls.signed_transaction = SignedTransaction(cls.ledger_id, cls.body)\n        cls.transaction_digest = TransactionDigest(cls.ledger_id, cls.body_str)\n        cls.receipt = {\"contractAddress\": cls.contract_address}\n        cls.code_id = 8888\n        cls.fetch_deploy_receipt = {\n            \"logs\": [\n                {\n                    \"events\": [\n                        {\n                            \"attributes\": [\n                                {\"key\": \"code_id\", \"value\": cls.code_id},\n                                {\n                                    \"key\": \"contract_address\",\n                                    \"value\": \"some_contract_address\",\n                                },\n                            ]\n                        }\n                    ]\n                }\n            ]\n        }\n        cls.fetch_deploy_receipt_no_code_id = {\n            \"logs\": [\n                {\n                    \"events\": [\n                        {\n                            \"attributes\": [\n                                {\"key\": \"not_a_code_id\", \"value\": \"something\"},\n                                {\n                                    \"key\": \"contract_address\",\n                                    \"value\": \"some_contract_address\",\n                                },\n                            ]\n                        }\n                    ]\n                }\n            ]\n        }\n        cls.fetch_init_receipt = {\"status\": 1, \"contractAddress\": cls.contract_address}\n        cls.transaction_receipt = TransactionReceipt(\n            cls.ledger_id, cls.receipt, {\"transaction_key\": \"transaction_value\"}\n        )\n\n        cls.terms_dict = {\n            \"ledger_id\": cls.ledger_id,\n            \"sender_address\": cls._skill.skill_context.agent_address,\n            \"counterparty_address\": \"counterprty\",\n            \"amount_by_currency_id\": {\"currency_id\": 50},\n            \"quantities_by_good_id\": {\"good_id\": -10},\n            \"nonce\": \"some_nonce\",\n        }\n\n        cls.list_of_signing_messages = (\n            DialogueMessage(\n                SigningMessage.Performative.SIGN_TRANSACTION,\n                {\n                    \"terms\": Terms(**cls.terms_dict),\n                    \"raw_transaction\": SigningMessage.RawTransaction(\n                        cls.ledger_id, cls.body\n                    ),\n                },\n            ),\n        )\n        cls.list_of_contract_api_messages = (\n            DialogueMessage(\n                ContractApiMessage.Performative.GET_DEPLOY_TRANSACTION,\n                {\n                    \"ledger_id\": cls.ledger_id,\n                    \"contract_id\": cls.contract_id,\n                    \"callable\": cls.callable,\n                    \"kwargs\": cls.kwargs,\n                },\n            ),\n        )\n        cls.list_of_ledger_api_messages = (\n            DialogueMessage(\n                LedgerApiMessage.Performative.GET_RAW_TRANSACTION,\n                {\"terms\": Terms(**cls.terms_dict)},\n            ),\n            DialogueMessage(\n                LedgerApiMessage.Performative.RAW_TRANSACTION,\n                {\"raw_transaction\": cls.raw_transaction},\n            ),\n            DialogueMessage(\n                LedgerApiMessage.Performative.SEND_SIGNED_TRANSACTION,\n                {\"signed_transaction\": cls.signed_transaction},\n            ),\n            DialogueMessage(\n                LedgerApiMessage.Performative.TRANSACTION_DIGEST,\n                {\"transaction_digest\": cls.transaction_digest},\n            ),\n            DialogueMessage(\n                LedgerApiMessage.Performative.GET_TRANSACTION_RECEIPT,\n                {\"transaction_digest\": cls.transaction_digest},\n            ),\n        )\n\n    @staticmethod\n    def _terms(terms_dict: Dict, label: str) -> Terms:\n        \"\"\"\n        Provides Terms with the specified label.\n\n        :param label: the label\n        :return: Terms\n        \"\"\"\n        terms_dict[\"label\"] = label\n        return Terms(**terms_dict)\n\n    @staticmethod\n    def _transaction_receipt_builder(ledger_id: str, receipt) -> TransactionReceipt:\n        \"\"\"\n        Provides Terms with the specified label.\n\n        :param ledger_id: the ledger_id\n        :param receipt: the transaction receipt\n        :return: Terms\n        \"\"\"\n        transaction_receipt = TransactionReceipt(\n            ledger_id, receipt, {\"transaction_key\": \"transaction_value\"}\n        )\n        return transaction_receipt\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the ledger_api handler.\"\"\"\n        assert self.ledger_api_handler.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle_unidentified_dialogue(self):\n        \"\"\"Test the _handle_unidentified_dialogue method of the ledger_api handler.\"\"\"\n        # setup\n        incorrect_dialogue_reference = (\"\", \"\")\n        incoming_message = self.build_incoming_message(\n            message_type=LedgerApiMessage,\n            dialogue_reference=incorrect_dialogue_reference,\n            performative=LedgerApiMessage.Performative.BALANCE,\n            ledger_id=\"some_ledger_id\",\n            balance=10,\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received invalid ledger_api message={incoming_message}, unidentified dialogue.\",\n        )\n\n    def test_handle_balance(self):\n        \"\"\"Test the _handle_balance method of the ledger_api handler.\"\"\"\n        # setup\n        balance = 10\n        ledger_api_dialogue = cast(\n            LedgerApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.ledger_api_dialogues,\n                messages=(\n                    DialogueMessage(\n                        LedgerApiMessage.Performative.GET_BALANCE,\n                        {\"ledger_id\": self.ledger_id, \"address\": \"some_address\"},\n                    ),\n                ),\n                counterparty=LEDGER_API_ADDRESS,\n            ),\n        )\n        incoming_message = cast(\n            LedgerApiMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=ledger_api_dialogue,\n                performative=LedgerApiMessage.Performative.BALANCE,\n                ledger_id=self.ledger_id,\n                balance=balance,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"starting balance on {self.ledger_id} ledger={incoming_message.balance}.\",\n        )\n\n    def test_handle_transaction_digest(self):\n        \"\"\"Test the _handle_transaction_digest method of the ledger_api handler.\"\"\"\n        # setup\n        ledger_api_dialogue = cast(\n            LedgerApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.ledger_api_dialogues,\n                messages=self.list_of_ledger_api_messages[:3],\n                counterparty=LEDGER_API_ADDRESS,\n            ),\n        )\n        incoming_message = cast(\n            LedgerApiMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=ledger_api_dialogue,\n                performative=LedgerApiMessage.Performative.TRANSACTION_DIGEST,\n                transaction_digest=self.transaction_digest,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"transaction was successfully submitted. Transaction digest={incoming_message.transaction_digest}\",\n        )\n\n        self.assert_quantity_in_outbox(1)\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=LedgerApiMessage,\n            performative=LedgerApiMessage.Performative.GET_TRANSACTION_RECEIPT,\n            to=LEDGER_API_ADDRESS,\n            sender=str(self.skill.skill_context.skill_id),\n            transaction_digest=incoming_message.transaction_digest,\n        )\n        assert has_attributes, error_str\n\n        mock_logger.assert_any_call(logging.INFO, \"requesting transaction receipt.\")\n\n    def test_handle_transaction_receipt_failed(self):\n        \"\"\"Test the _handle_transaction_receipt method of the ledger_api handler where the transaction is NOT settled.\"\"\"\n        # setup\n        ledger_api_dialogue = cast(\n            LedgerApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.ledger_api_dialogues,\n                messages=self.list_of_ledger_api_messages[:5],\n                counterparty=LEDGER_API_ADDRESS,\n            ),\n        )\n        signing_dialogue = cast(\n            SigningDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.signing_dialogues,\n                messages=self.list_of_signing_messages[:4],\n            ),\n        )\n        contract_api_dialogue = cast(\n            ContractApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.signing_dialogues,\n                messages=self.list_of_signing_messages[:4],\n            ),\n        )\n\n        signing_dialogue.associated_contract_api_dialogue = contract_api_dialogue\n        ledger_api_dialogue.associated_signing_dialogue = signing_dialogue\n\n        incoming_message = cast(\n            LedgerApiMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=ledger_api_dialogue,\n                performative=LedgerApiMessage.Performative.TRANSACTION_RECEIPT,\n                transaction_receipt=self.transaction_receipt,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            with patch.object(LedgerApis, \"is_transaction_settled\", return_value=False):\n                self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.ERROR,\n            f\"transaction failed. Transaction receipt={incoming_message.transaction_receipt}\",\n        )\n\n    def test_handle_transaction_receipt_callable_get_deploy_transaction_label_store(\n        self,\n    ):\n        \"\"\"Test the _handle_transaction_receipt method of the ledger_api handler where contract_api callable is GET_DEPLOY_TRANSACTION and terms label is 'store'.\"\"\"\n        # setup\n        ledger_api_dialogue = cast(\n            LedgerApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.ledger_api_dialogues,\n                messages=self.list_of_ledger_api_messages[:5],\n                counterparty=LEDGER_API_ADDRESS,\n            ),\n        )\n        signing_dialogue = cast(\n            SigningDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.signing_dialogues,\n                messages=self.list_of_signing_messages[:4],\n            ),\n        )\n        contract_api_dialogue = cast(\n            ContractApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.contract_api_dialogues,\n                messages=self.list_of_contract_api_messages[:4],\n            ),\n        )\n\n        signing_dialogue.associated_contract_api_dialogue = contract_api_dialogue\n        ledger_api_dialogue.associated_signing_dialogue = signing_dialogue\n\n        contract_api_dialogue.callable = (\n            ContractApiDialogue.Callable.GET_DEPLOY_TRANSACTION\n        )\n        contract_api_dialogue.terms = self._terms(self.terms_dict, \"store\")\n\n        incoming_message = cast(\n            LedgerApiMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=ledger_api_dialogue,\n                performative=LedgerApiMessage.Performative.TRANSACTION_RECEIPT,\n                transaction_receipt=self._transaction_receipt_builder(\n                    FetchAIApi.identifier, self.fetch_deploy_receipt\n                ),\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            with patch.object(LedgerApis, \"is_transaction_settled\", return_value=True):\n                self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        # _request_init_transaction\n        self.assert_quantity_in_outbox(1)\n        msg = cast(ContractApiMessage, self.get_message_from_outbox())\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=msg,\n            message_type=ContractApiMessage,\n            performative=ContractApiMessage.Performative.GET_DEPLOY_TRANSACTION,\n            ledger_id=self.parameters.ledger_id,\n            contract_id=self.parameters.contract_id,\n            callable=ContractApiDialogue.Callable.GET_DEPLOY_TRANSACTION.value,\n            kwargs=ContractApiMessage.Kwargs(\n                {\n                    \"label\": \"TACERC1155\",\n                    \"init_msg\": {},\n                    \"gas\": self.parameters.gas,\n                    \"amount\": 0,\n                    \"code_id\": self.code_id,\n                    \"deployer_address\": self.skill.skill_context.agent_address,\n                    \"tx_fee\": DEFAULT_CONTRACT_DEPLOY_FEE,\n                }\n            ),\n        )\n        assert has_attributes, error_str\n\n        assert contract_api_dialogue.terms == self.parameters.get_deploy_terms(\n            is_init_transaction=True\n        )\n        assert (\n            contract_api_dialogue.callable\n            == ContractApiDialogue.Callable.GET_DEPLOY_TRANSACTION\n        )\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            \"requesting contract initialisation transaction...\",\n        )\n\n    def test_handle_transaction_receipt_callable_get_deploy_transaction_label_store_no_code_id(\n        self,\n    ):\n        \"\"\"Test the _handle_transaction_receipt method of the ledger_api handler where contract_api callable is GET_DEPLOY_TRANSACTION and terms label is 'store' and no code_id.\"\"\"\n        # setup\n        ledger_api_dialogue = cast(\n            LedgerApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.ledger_api_dialogues,\n                messages=self.list_of_ledger_api_messages[:5],\n                counterparty=LEDGER_API_ADDRESS,\n            ),\n        )\n        signing_dialogue = cast(\n            SigningDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.signing_dialogues,\n                messages=self.list_of_signing_messages[:4],\n            ),\n        )\n        contract_api_dialogue = cast(\n            ContractApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.contract_api_dialogues,\n                messages=self.list_of_contract_api_messages[:4],\n            ),\n        )\n\n        signing_dialogue.associated_contract_api_dialogue = contract_api_dialogue\n        ledger_api_dialogue.associated_signing_dialogue = signing_dialogue\n\n        contract_api_dialogue.callable = (\n            ContractApiDialogue.Callable.GET_DEPLOY_TRANSACTION\n        )\n        contract_api_dialogue.terms = self._terms(self.terms_dict, \"store\")\n\n        incoming_message = cast(\n            LedgerApiMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=ledger_api_dialogue,\n                performative=LedgerApiMessage.Performative.TRANSACTION_RECEIPT,\n                transaction_receipt=self._transaction_receipt_builder(\n                    FetchAIApi.identifier, self.fetch_deploy_receipt_no_code_id\n                ),\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            with patch.object(LedgerApis, \"is_transaction_settled\", return_value=True):\n                self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        # _request_init_transaction\n        self.assert_quantity_in_outbox(0)\n        mock_logger.assert_any_call(\n            logging.INFO,\n            \"Failed to initialise contract: code_id not found\",\n        )\n\n    def test_handle_transaction_receipt_callable_get_deploy_transaction_label_init(\n        self,\n    ):\n        \"\"\"Test the _handle_transaction_receipt method of the ledger_api handler where contract_api callable is GET_DEPLOY_TRANSACTION and terms label is 'init'.\"\"\"\n        # setup\n        ledger_api_dialogue = cast(\n            LedgerApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.ledger_api_dialogues,\n                messages=self.list_of_ledger_api_messages[:5],\n                counterparty=LEDGER_API_ADDRESS,\n            ),\n        )\n        signing_dialogue = cast(\n            SigningDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.signing_dialogues,\n                messages=self.list_of_signing_messages[:4],\n            ),\n        )\n        contract_api_dialogue = cast(\n            ContractApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.contract_api_dialogues,\n                messages=self.list_of_contract_api_messages[:4],\n            ),\n        )\n\n        signing_dialogue.associated_contract_api_dialogue = contract_api_dialogue\n        ledger_api_dialogue.associated_signing_dialogue = signing_dialogue\n\n        contract_api_dialogue.callable = (\n            ContractApiDialogue.Callable.GET_DEPLOY_TRANSACTION\n        )\n        contract_api_dialogue.terms = self._terms(self.terms_dict, \"init\")\n\n        incoming_message = cast(\n            LedgerApiMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=ledger_api_dialogue,\n                performative=LedgerApiMessage.Performative.TRANSACTION_RECEIPT,\n                transaction_receipt=self._transaction_receipt_builder(\n                    FetchAIApi.identifier, self.fetch_init_receipt\n                ),\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            with patch.object(LedgerApis, \"is_transaction_settled\", return_value=True):\n                with patch.object(\n                    LedgerApis,\n                    \"get_contract_address\",\n                    return_value=self.contract_address,\n                ):\n                    self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        assert self.parameters.contract_address == self.contract_address\n        assert self.game.phase == Phase.CONTRACT_DEPLOYED\n\n        mock_logger.assert_any_call(logging.INFO, \"contract deployed.\")\n\n    def test_handle_transaction_receipt_callable_get_deploy_transaction_label_deploy(\n        self,\n    ):\n        \"\"\"Test the _handle_transaction_receipt method of the ledger_api handler where contract_api callable is GET_DEPLOY_TRANSACTION and terms label is 'deploy'.\"\"\"\n        # setup\n        ledger_api_dialogue = cast(\n            LedgerApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.ledger_api_dialogues,\n                messages=self.list_of_ledger_api_messages[:5],\n                counterparty=LEDGER_API_ADDRESS,\n            ),\n        )\n        signing_dialogue = cast(\n            SigningDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.signing_dialogues,\n                messages=self.list_of_signing_messages[:4],\n            ),\n        )\n        contract_api_dialogue = cast(\n            ContractApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.contract_api_dialogues,\n                messages=self.list_of_contract_api_messages[:4],\n            ),\n        )\n\n        signing_dialogue.associated_contract_api_dialogue = contract_api_dialogue\n        ledger_api_dialogue.associated_signing_dialogue = signing_dialogue\n\n        contract_api_dialogue.callable = (\n            ContractApiDialogue.Callable.GET_DEPLOY_TRANSACTION\n        )\n        contract_api_dialogue.terms = self._terms(self.terms_dict, \"deploy\")\n\n        incoming_message = cast(\n            LedgerApiMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=ledger_api_dialogue,\n                performative=LedgerApiMessage.Performative.TRANSACTION_RECEIPT,\n                transaction_receipt=self._transaction_receipt_builder(\n                    FetchAIApi.identifier, self.fetch_init_receipt\n                ),\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            with patch.object(LedgerApis, \"is_transaction_settled\", return_value=True):\n                with patch.object(\n                    LedgerApis,\n                    \"get_contract_address\",\n                    return_value=self.contract_address,\n                ):\n                    self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        assert self.parameters.contract_address == self.contract_address\n        assert self.game.phase == Phase.CONTRACT_DEPLOYED\n\n        mock_logger.assert_any_call(logging.INFO, \"contract deployed.\")\n\n    def test_handle_transaction_receipt_callable_get_create_batch_transaction(self):\n        \"\"\"Test the _handle_transaction_receipt method of the ledger_api handler where contract_api callable is GET_CREATE_BATCH_TRANSACTION.\"\"\"\n        # setup\n        ledger_api_dialogue = cast(\n            LedgerApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.ledger_api_dialogues,\n                messages=self.list_of_ledger_api_messages[:5],\n                counterparty=LEDGER_API_ADDRESS,\n            ),\n        )\n        signing_dialogue = cast(\n            SigningDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.signing_dialogues,\n                messages=self.list_of_signing_messages[:4],\n            ),\n        )\n        contract_api_dialogue = cast(\n            ContractApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.contract_api_dialogues,\n                messages=self.list_of_contract_api_messages[:4],\n            ),\n        )\n\n        signing_dialogue.associated_contract_api_dialogue = contract_api_dialogue\n        ledger_api_dialogue.associated_signing_dialogue = signing_dialogue\n\n        contract_api_dialogue.callable = (\n            ContractApiDialogue.Callable.GET_CREATE_BATCH_TRANSACTION\n        )\n\n        incoming_message = cast(\n            LedgerApiMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=ledger_api_dialogue,\n                performative=LedgerApiMessage.Performative.TRANSACTION_RECEIPT,\n                transaction_receipt=self.transaction_receipt,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            with patch.object(LedgerApis, \"is_transaction_settled\", return_value=True):\n                self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        assert self.game.phase == Phase.TOKENS_CREATED\n\n        mock_logger.assert_any_call(logging.INFO, \"tokens created.\")\n\n    def test_handle_transaction_receipt_callable_get_mint_batch_transaction_i(self):\n        \"\"\"Test the _handle_transaction_receipt method of the ledger_api handler where contract_api callable is GET_MINT_BATCH_TRANSACTION and all tokens are NOT minted.\"\"\"\n        # setup\n        ledger_api_dialogue = cast(\n            LedgerApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.ledger_api_dialogues,\n                messages=self.list_of_ledger_api_messages[:5],\n                counterparty=LEDGER_API_ADDRESS,\n            ),\n        )\n        signing_dialogue = cast(\n            SigningDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.signing_dialogues,\n                messages=self.list_of_signing_messages[:4],\n            ),\n        )\n        contract_api_dialogue = cast(\n            ContractApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.contract_api_dialogues,\n                messages=self.list_of_contract_api_messages[:4],\n            ),\n        )\n\n        signing_dialogue.associated_contract_api_dialogue = contract_api_dialogue\n        ledger_api_dialogue.associated_signing_dialogue = signing_dialogue\n\n        contract_api_dialogue.callable = (\n            ContractApiDialogue.Callable.GET_MINT_BATCH_TRANSACTION\n        )\n\n        incoming_message = cast(\n            LedgerApiMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=ledger_api_dialogue,\n                performative=LedgerApiMessage.Performative.TRANSACTION_RECEIPT,\n                transaction_receipt=self.transaction_receipt,\n            ),\n        )\n\n        self.parameters.nb_completed_minting = 0\n        self.game._registration._agent_addr_to_name = {\n            \"some_address_1\": \"some_name_1\",\n            \"some_address_2\": \"some_name_2\",\n        }\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            with patch.object(LedgerApis, \"is_transaction_settled\", return_value=True):\n                self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(logging.INFO, \"tokens minted.\")\n        assert self.parameters.nb_completed_minting == 1\n        assert self.game.is_allowed_to_mint is True\n        assert self.game.phase != Phase.TOKENS_MINTED\n\n    def test_handle_transaction_receipt_callable_get_mint_batch_transaction_ii(self):\n        \"\"\"Test the _handle_transaction_receipt method of the ledger_api handler where contract_api callable is GET_MINT_BATCH_TRANSACTION and all tokens are minted.\"\"\"\n        # setup\n        ledger_api_dialogue = cast(\n            LedgerApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.ledger_api_dialogues,\n                messages=self.list_of_ledger_api_messages[:5],\n                counterparty=LEDGER_API_ADDRESS,\n            ),\n        )\n        signing_dialogue = cast(\n            SigningDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.signing_dialogues,\n                messages=self.list_of_signing_messages[:4],\n            ),\n        )\n        contract_api_dialogue = cast(\n            ContractApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.contract_api_dialogues,\n                messages=self.list_of_contract_api_messages[:4],\n            ),\n        )\n\n        signing_dialogue.associated_contract_api_dialogue = contract_api_dialogue\n        ledger_api_dialogue.associated_signing_dialogue = signing_dialogue\n\n        contract_api_dialogue.callable = (\n            ContractApiDialogue.Callable.GET_MINT_BATCH_TRANSACTION\n        )\n\n        incoming_message = cast(\n            LedgerApiMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=ledger_api_dialogue,\n                performative=LedgerApiMessage.Performative.TRANSACTION_RECEIPT,\n                transaction_receipt=self.transaction_receipt,\n            ),\n        )\n\n        self.parameters.nb_completed_minting = 0\n        self.game._registration._agent_addr_to_name = {\"some_address\": \"some_name\"}\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            with patch.object(LedgerApis, \"is_transaction_settled\", return_value=True):\n                self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(logging.INFO, \"tokens minted.\")\n        assert self.parameters.nb_completed_minting == 1\n        assert self.game.is_allowed_to_mint is True\n        assert self.game.phase == Phase.TOKENS_MINTED\n        mock_logger.assert_any_call(logging.INFO, \"all tokens minted.\")\n\n    def test_handle_transaction_receipt_incorrect_callable(self):\n        \"\"\"Test the _handle_transaction_receipt method of the ledger_api handler where contract_api callable is incorrect.\"\"\"\n        # setup\n        ledger_api_dialogue = cast(\n            LedgerApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.ledger_api_dialogues,\n                messages=self.list_of_ledger_api_messages[:5],\n                counterparty=LEDGER_API_ADDRESS,\n            ),\n        )\n        signing_dialogue = cast(\n            SigningDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.signing_dialogues,\n                messages=self.list_of_signing_messages[:4],\n            ),\n        )\n        contract_api_dialogue = cast(\n            ContractApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.contract_api_dialogues,\n                messages=self.list_of_contract_api_messages[:4],\n            ),\n        )\n\n        signing_dialogue.associated_contract_api_dialogue = contract_api_dialogue\n        ledger_api_dialogue.associated_signing_dialogue = signing_dialogue\n\n        contract_api_dialogue.callable = \"some_incorrect_callable\"\n\n        incoming_message = cast(\n            LedgerApiMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=ledger_api_dialogue,\n                performative=LedgerApiMessage.Performative.TRANSACTION_RECEIPT,\n                transaction_receipt=self.transaction_receipt,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            with patch.object(LedgerApis, \"is_transaction_settled\", return_value=True):\n                self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(logging.ERROR, \"unexpected transaction receipt!\")\n\n    def test_handle_error(self):\n        \"\"\"Test the _handle_error method of the ledger_api handler.\"\"\"\n        # setup\n        ledger_api_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.ledger_api_dialogues,\n            messages=self.list_of_ledger_api_messages[:1],\n        )\n        incoming_message = cast(\n            LedgerApiMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=ledger_api_dialogue,\n                performative=LedgerApiMessage.Performative.ERROR,\n                code=1,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received ledger_api error message={incoming_message} in dialogue={ledger_api_dialogue}.\",\n        )\n\n    def test_handle_invalid(self):\n        \"\"\"Test the _handle_invalid method of the ledger_api handler.\"\"\"\n        # setup\n        invalid_performative = LedgerApiMessage.Performative.GET_BALANCE\n        incoming_message = self.build_incoming_message(\n            message_type=LedgerApiMessage,\n            dialogue_reference=(\"1\", \"\"),\n            performative=invalid_performative,\n            ledger_id=\"some_ledger_id\",\n            address=\"some_address\",\n            to=str(self.skill.skill_context.skill_id),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"cannot handle ledger_api message of performative={invalid_performative} in dialogue={self.ledger_api_dialogues.get_dialogue(incoming_message)}.\",\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the ledger_api handler.\"\"\"\n        assert self.ledger_api_handler.teardown() is None\n        self.assert_quantity_in_outbox(0)\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_tac_control_contract/test_helpers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the helpers module of the tac control contract skill.\"\"\"\n\nfrom pathlib import Path\nfrom unittest.mock import patch\n\nimport pytest\n\nfrom aea.exceptions import AEAEnforceError\nfrom aea.test_tools.test_skill import BaseSkillTestCase\n\nfrom packages.fetchai.skills.tac_control_contract.helpers import (\n    ERC1155Contract,\n    _sample_good_instances,\n    determine_scaling_factor,\n    generate_currency_endowments,\n    generate_currency_id_to_name,\n    generate_currency_ids,\n    generate_equilibrium_prices_and_holdings,\n    generate_exchange_params,\n    generate_good_endowments,\n    generate_good_id_to_name,\n    generate_good_ids,\n    generate_utility_params,\n)\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass TestHelpers(BaseSkillTestCase):\n    \"\"\"Test Helper module methods of tac control.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"tac_control\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n\n    def test_generate_good_ids_succeeds(self):\n        \"\"\"Test the generate_good_ids of Helpers module which succeeds.\"\"\"\n        expected_list = [1, 2, 3, 4, 5]\n        with patch.object(\n            ERC1155Contract, \"generate_token_ids\", return_value=expected_list\n        ):\n            good_ids = generate_good_ids(5)\n        assert good_ids == expected_list\n\n    def test_generate_good_ids_fails(self):\n        \"\"\"Test the generate_good_ids of Helpers module which fails because generate_token_ids generates wrong good ids.\"\"\"\n        expected_list = [1, 2, 3, 4, 5, 6]\n        with patch.object(\n            ERC1155Contract, \"generate_token_ids\", return_value=expected_list\n        ):\n            with pytest.raises(\n                AEAEnforceError,\n                match=\"Length of good ids and number of goods must match.\",\n            ):\n                assert generate_good_ids(5)\n\n    def test_generate_currency_ids_succeeds(self):\n        \"\"\"Test the generate_good_ids of Helpers module which succeeds.\"\"\"\n        expected_list = [1, 2, 3, 4, 5]\n        with patch.object(\n            ERC1155Contract, \"generate_token_ids\", return_value=expected_list\n        ):\n            currency_ids = generate_currency_ids(5)\n        assert currency_ids == expected_list\n\n    def test_generate_currency_ids_fails(self):\n        \"\"\"Test the generate_good_ids of Helpers module which fails because generate_token_ids generates wrong currency ids.\"\"\"\n        expected_list = [1, 2, 3, 4, 5, 6]\n        with patch.object(\n            ERC1155Contract, \"generate_token_ids\", return_value=expected_list\n        ):\n            with pytest.raises(\n                AEAEnforceError,\n                match=\"Length of currency ids and number of currencies must match.\",\n            ):\n                assert generate_currency_ids(5)\n\n    def test_generate_currency_id_to_name(self):\n        \"\"\"Test the generate_currency_id_to_name of Helpers module.\"\"\"\n        expected_currency_id_to_name = {\n            \"1\": \"FT_1\",\n            \"3\": \"FT_3\",\n            \"5\": \"FT_5\",\n            \"7\": \"FT_7\",\n            \"9\": \"FT_9\",\n        }\n        currency_id_to_name = generate_currency_id_to_name([1, 3, 5, 7, 9])\n        assert currency_id_to_name == expected_currency_id_to_name\n\n    def test_generate_good_id_to_name(self):\n        \"\"\"Test the generate_good_id_to_name of Helpers module.\"\"\"\n        expected_good_id_to_name = {\n            \"1\": \"FT_1\",\n            \"3\": \"FT_3\",\n            \"5\": \"FT_5\",\n            \"7\": \"FT_7\",\n            \"9\": \"FT_9\",\n        }\n        good_id_to_name = generate_good_id_to_name([1, 3, 5, 7, 9])\n        assert good_id_to_name == expected_good_id_to_name\n\n    def test_determine_scaling_factor(self):\n        \"\"\"Test the determine_scaling_factor of Helpers module.\"\"\"\n        money_endowment = 53730411\n        scaling_factor = determine_scaling_factor(money_endowment)\n        assert scaling_factor == 10000000.0\n\n    def test_generate_good_endowments(self):\n        \"\"\"Test the generate_good_endowments of Helpers module.\"\"\"\n        endowments = generate_good_endowments(\n            [\"ag_1_add\", \"ag_2_add\"], [\"good_id_1\", \"good_id_2\"], 2, 1, 1\n        )\n        assert \"good_id_1\" in endowments[\"ag_1_add\"]\n        assert \"good_id_2\" in endowments[\"ag_1_add\"]\n        assert \"good_id_1\" in endowments[\"ag_2_add\"]\n        assert \"good_id_2\" in endowments[\"ag_2_add\"]\n\n    def test_generate_utility_params(self):\n        \"\"\"Test the generate_utility_params of Helpers module.\"\"\"\n        utility_function_params = generate_utility_params(\n            [\"ag_1_add\", \"ag_2_add\"], [\"good_id_1\", \"good_id_2\"], 1000.0\n        )\n        assert \"good_id_1\" in utility_function_params[\"ag_1_add\"].keys()\n        assert \"good_id_2\" in utility_function_params[\"ag_1_add\"].keys()\n        assert \"good_id_1\" in utility_function_params[\"ag_2_add\"].keys()\n        assert \"good_id_2\" in utility_function_params[\"ag_2_add\"].keys()\n\n    def test_sample_good_instances(self):\n        \"\"\"Test the _sample_good_instances of Helpers module.\"\"\"\n        nb_instances = _sample_good_instances(2, [\"good_id_1\", \"good_id_2\"], 2, 1, 1)\n        assert type(nb_instances[\"good_id_1\"]) == int\n        assert type(nb_instances[\"good_id_2\"]) == int\n\n    def test_generate_currency_endowments(self):\n        \"\"\"Test the generate_currency_endowments of Helpers module.\"\"\"\n        currency_endowments = generate_currency_endowments(\n            [\"ag_1_add\", \"ag_2_add\"], [\"currency_id_1\", \"currency_id_2\"], 10\n        )\n        assert \"currency_id_1\" in currency_endowments[\"ag_1_add\"].keys()\n        assert \"currency_id_2\" in currency_endowments[\"ag_2_add\"].keys()\n        assert currency_endowments[\"ag_1_add\"][\"currency_id_1\"] == 10\n        assert currency_endowments[\"ag_1_add\"][\"currency_id_2\"] == 10\n\n        assert currency_endowments[\"ag_2_add\"][\"currency_id_1\"] == 10\n        assert currency_endowments[\"ag_2_add\"][\"currency_id_2\"] == 10\n\n    def test_generate_exchange_params(self):\n        \"\"\"Test the generate_exchange_params of Helpers module.\"\"\"\n        currency_endowments = generate_exchange_params(\n            [\"ag_1_add\", \"ag_2_add\"], [\"currency_id_1\", \"currency_id_2\"]\n        )\n        assert \"currency_id_1\" in currency_endowments[\"ag_1_add\"].keys()\n        assert \"currency_id_2\" in currency_endowments[\"ag_2_add\"].keys()\n        assert currency_endowments[\"ag_1_add\"][\"currency_id_1\"] == 1.0\n        assert currency_endowments[\"ag_1_add\"][\"currency_id_2\"] == 1.0\n\n        assert currency_endowments[\"ag_2_add\"][\"currency_id_1\"] == 1.0\n        assert currency_endowments[\"ag_2_add\"][\"currency_id_2\"] == 1.0\n\n    def test_generate_equilibrium_prices_and_holdings(self):\n        \"\"\"Test the generate_equilibrium_prices_and_holdings of Helpers module.\"\"\"\n        (\n            eq_prices_dict,\n            eq_good_holdings_dict,\n            eq_currency_holdings_dict,\n        ) = generate_equilibrium_prices_and_holdings(\n            {\"ag_1\": {\"good_1\": 1}},\n            {\"ag_1\": {\"good_1\": 1.0}},\n            {\"ag_1\": {\"currency_1\": 10}},\n            {\"ag_1\": {\"currency_1\": 1.0}},\n            2.0,\n        )\n\n        assert len(eq_prices_dict) == 1\n        assert type(eq_prices_dict[\"good_1\"]) == float\n\n        assert len(eq_good_holdings_dict) == 1\n        assert len(eq_good_holdings_dict[\"ag_1\"]) == 1\n        assert type(eq_good_holdings_dict[\"ag_1\"][\"good_1\"]) == float\n\n        assert len(eq_currency_holdings_dict) == 1\n        assert type(eq_currency_holdings_dict[\"ag_1\"]) == float\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_tac_control_contract/test_parameters.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the parameters module of the tac control contract skill.\"\"\"\n\nfrom pathlib import Path\n\nfrom aea_ledger_ethereum import EthereumApi\nfrom aea_ledger_fetchai import FetchAIApi\n\nfrom aea.helpers.transaction.base import Terms\nfrom aea.test_tools.test_skill import BaseSkillTestCase\n\nfrom packages.fetchai.skills.tac_control_contract.parameters import Parameters\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass TestParameters(BaseSkillTestCase):\n    \"\"\"Test Parameters module of tac control contract.\"\"\"\n\n    path_to_skill = Path(\n        ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"tac_control_contract\"\n    )\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.kwargs = {\n            \"ledger_id\": \"some_ledger_id\",\n            \"contract_address\": None,\n            \"good_ids\": [],\n            \"currency_ids\": [],\n            \"min_nb_agents\": 2,\n            \"money_endowment\": 200,\n            \"nb_goods\": 9,\n            \"nb_currencies\": 1,\n            \"tx_fee\": 1,\n            \"base_good_endowment\": 2,\n            \"lower_bound_factor\": 1,\n            \"upper_bound_factor\": 1,\n            \"registration_start_time\": \"01 01 2020  00:01\",\n            \"registration_timeout\": 60,\n            \"item_setup_timeout\": 60,\n            \"competition_timeout\": 300,\n            \"inactivity_timeout\": 30,\n            \"whitelist\": [],\n            \"location\": {\"longitude\": 0.1270, \"latitude\": 51.5194},\n            \"service_data\": {\"key\": \"tac\", \"value\": \"v1\"},\n            \"name\": \"parameters\",\n            \"skill_context\": cls._skill.skill_context,\n        }\n        cls.parameters = Parameters(**cls.kwargs)\n\n    def test__init__(self):\n        \"\"\"Test the __init__ of Parameters.\"\"\"\n        assert self.parameters.nb_completed_minting == 0\n\n    def test_get_deploy_terms(self):\n        \"\"\"Test the get_deploy_terms of Parameters.\"\"\"\n        self.parameters._ledger_id = FetchAIApi.identifier\n        assert self.parameters.get_deploy_terms() == Terms(\n            FetchAIApi.identifier,\n            self.skill.skill_context.agent_address,\n            self.skill.skill_context.agent_address,\n            {},\n            {},\n            \"\",\n            label=\"store\",\n        )\n\n        self.parameters._ledger_id = FetchAIApi.identifier\n        assert self.parameters.get_deploy_terms(True) == Terms(\n            FetchAIApi.identifier,\n            self.skill.skill_context.agent_address,\n            self.skill.skill_context.agent_address,\n            {},\n            {},\n            \"\",\n            label=\"init\",\n        )\n\n        self.parameters._ledger_id = EthereumApi.identifier\n        assert self.parameters.get_deploy_terms() == Terms(\n            EthereumApi.identifier,\n            self.skill.skill_context.agent_address,\n            self.skill.skill_context.agent_address,\n            {},\n            {},\n            \"\",\n            label=\"deploy\",\n        )\n\n    def test_get_create_token_terms(self):\n        \"\"\"Test the get_create_token_terms of Parameters.\"\"\"\n        assert self.parameters.get_create_token_terms() == Terms(\n            \"some_ledger_id\",\n            self.skill.skill_context.agent_address,\n            self.skill.skill_context.agent_address,\n            {},\n            {},\n            \"\",\n        )\n\n    def test_get_mint_token_terms(self):\n        \"\"\"Test the get_mint_token_terms of Parameters.\"\"\"\n        assert self.parameters.get_mint_token_terms() == Terms(\n            \"some_ledger_id\",\n            self.skill.skill_context.agent_address,\n            self.skill.skill_context.agent_address,\n            {},\n            {},\n            \"\",\n        )\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_tac_negotiation/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"The tests module contains the tests of the packages/skills/tac_negotiation dir.\"\"\"\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_tac_negotiation/test_behaviours.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the behaviour classes of the tac negotiation skill.\"\"\"\n\nimport logging\nfrom pathlib import Path\nfrom typing import cast\nfrom unittest.mock import PropertyMock, patch\n\nfrom aea.decision_maker.gop import GoalPursuitReadiness, OwnershipState, Preferences\nfrom aea.helpers.search.models import Constraint, ConstraintType, Description, Query\nfrom aea.test_tools.test_skill import BaseSkillTestCase\n\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.skills.tac_negotiation.behaviours import (\n    GoodsRegisterAndSearchBehaviour,\n    TransactionCleanUpBehaviour,\n)\nfrom packages.fetchai.skills.tac_negotiation.dialogues import (\n    OefSearchDialogue,\n    OefSearchDialogues,\n)\nfrom packages.fetchai.skills.tac_negotiation.strategy import Strategy\nfrom packages.fetchai.skills.tac_negotiation.transactions import Transactions\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass TestSkillBehaviour(BaseSkillTestCase):\n    \"\"\"Test tac behaviour of tac negotiation.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"tac_negotiation\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        tac_dm_context_kwargs = {\n            \"goal_pursuit_readiness\": GoalPursuitReadiness(),\n            \"ownership_state\": OwnershipState(),\n            \"preferences\": Preferences(),\n        }\n        super().setup(dm_context_kwargs=tac_dm_context_kwargs)\n        cls.tac_negotiation = cast(\n            GoodsRegisterAndSearchBehaviour,\n            cls._skill.skill_context.behaviours.tac_negotiation,\n        )\n        cls.oef_search_dialogues = cast(\n            OefSearchDialogues, cls._skill.skill_context.oef_search_dialogues\n        )\n        cls.goal_pursuit_readiness = (\n            cls._skill.skill_context.decision_maker_handler_context.goal_pursuit_readiness\n        )\n        cls.strategy = cast(Strategy, cls._skill.skill_context.strategy)\n        cls.logger = cls._skill.skill_context.logger\n\n        cls.mocked_description = Description({\"foo1\": 1, \"bar1\": 2})\n        cls.mocked_query = Query(\n            [Constraint(\"tac_service\", ConstraintType(\"==\", \"both\"))]\n        )\n        cls.sender = str(cls._skill.skill_context.skill_id)\n\n        cls.registration_message = OefSearchMessage(\n            dialogue_reference=(\"\", \"\"),\n            performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n            service_description=\"some_service_description\",\n        )\n        cls.registration_message.sender = str(cls._skill.skill_context.skill_id)\n        cls.registration_message.to = cls._skill.skill_context.search_service_address\n\n        cls.tac_version_id = \"some_tac_version_id\"\n\n    def test_init(self):\n        \"\"\"Test the __init__ method of the negotiation behaviour.\"\"\"\n        assert self.tac_negotiation.is_registered is False\n        assert self.tac_negotiation.failed_registration_msg is None\n        assert self.tac_negotiation._nb_retries == 0\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the negotiation behaviour.\"\"\"\n        assert self.tac_negotiation.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_act_i(self):\n        \"\"\"Test the act method of the negotiation behaviour where is_game_finished is True.\"\"\"\n        # setup\n        self.skill.skill_context._agent_context._shared_state = {\n            \"is_game_finished\": True\n        }\n\n        # operation\n        self.tac_negotiation.act()\n\n        # after\n        self.assert_quantity_in_outbox(0)\n        assert self.skill.skill_context.is_active is False\n\n    def test_act_ii(self):\n        \"\"\"Test the act method of the negotiation behaviour where goal_pursuit_readiness is not ready.\"\"\"\n        # setup\n        self.skill.skill_context._agent_context._shared_state = {\n            \"is_game_finished\": False\n        }\n        self.goal_pursuit_readiness._status = GoalPursuitReadiness.Status.NOT_READY\n\n        # operation\n        self.tac_negotiation.act()\n\n        # after\n        self.assert_quantity_in_outbox(0)\n\n    def test_act_iii(self):\n        \"\"\"Test the act method of the negotiation behaviour where tac_version_id is NOT in the shared state.\"\"\"\n        # setup\n        self.skill.skill_context._agent_context._shared_state = {\n            \"is_game_finished\": False\n        }\n        self.goal_pursuit_readiness._status = GoalPursuitReadiness.Status.READY\n\n        if \"tac_version_id\" in self.skill.skill_context._agent_context._shared_state:\n            self.skill.skill_context._agent_context._shared_state.pop(\"tac_version_id\")\n\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.tac_negotiation.act()\n\n        # after\n        self.assert_quantity_in_outbox(0)\n        mock_logger.assert_any_call(\n            logging.ERROR, \"Cannot get the tac_version_id. Stopping!\"\n        )\n\n    def test_act_iv(self):\n        \"\"\"Test the act method of the negotiation behaviour where is_registered is False.\"\"\"\n        # setup\n        self.skill.skill_context._agent_context._shared_state = {\n            \"is_game_finished\": False,\n            \"tac_version_id\": self.tac_version_id,\n        }\n        self.goal_pursuit_readiness._status = GoalPursuitReadiness.Status.READY\n\n        searching_for_types = [(True, \"sellers\"), (False, \"buyers\")]\n        no_searches = len(searching_for_types)\n\n        self.tac_negotiation.failed_registration_msg = None\n\n        # operation\n        with patch.object(\n            self.strategy,\n            \"get_location_description\",\n            return_value=self.mocked_description,\n        ):\n            with patch.object(\n                self.strategy,\n                \"get_register_service_description\",\n                return_value=self.mocked_description,\n            ):\n                with patch.object(\n                    self.strategy,\n                    \"get_location_and_service_query\",\n                    return_value=self.mocked_query,\n                ):\n                    with patch.object(\n                        type(self.strategy),\n                        \"searching_for_types\",\n                        new_callable=PropertyMock,\n                        return_value=searching_for_types,\n                    ):\n                        with patch.object(self.logger, \"log\") as mock_logger:\n                            self.tac_negotiation.act()\n\n        # after\n        self.assert_quantity_in_outbox(no_searches + 1)\n\n        # _register_agent\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=OefSearchMessage,\n            performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n            to=self.skill.skill_context.search_service_address,\n            sender=self.sender,\n            service_description=self.mocked_description,\n        )\n        assert has_attributes, error_str\n\n        mock_logger.assert_any_call(logging.INFO, \"registering agent on SOEF.\")\n\n        # _search_services\n        for search in searching_for_types:\n            message = self.get_message_from_outbox()\n            has_attributes, error_str = self.message_has_attributes(\n                actual_message=message,\n                message_type=OefSearchMessage,\n                performative=OefSearchMessage.Performative.SEARCH_SERVICES,\n                to=self.skill.skill_context.search_service_address,\n                sender=self.sender,\n                query=self.mocked_query,\n            )\n            assert has_attributes, error_str\n\n            assert (\n                cast(\n                    OefSearchDialogue, self.oef_search_dialogues.get_dialogue(message)\n                ).is_seller_search\n                == search[0]\n            )\n\n            mock_logger.assert_any_call(\n                logging.INFO,\n                f\"searching for {search[1]}, search_id={message.dialogue_reference}.\",\n            )\n\n    def test_act_v(self):\n        \"\"\"Test the act method of the negotiation behaviour where failed_registration_msg is NOT None.\"\"\"\n        # setup\n        self.skill.skill_context._agent_context._shared_state = {\n            \"is_game_finished\": False,\n            \"tac_version_id\": self.tac_version_id,\n        }\n        self.goal_pursuit_readiness._status = GoalPursuitReadiness.Status.READY\n\n        searching_for_types = [(True, \"sellers\"), (False, \"buyers\")]\n        no_searches = len(searching_for_types)\n\n        self.tac_negotiation.failed_registration_msg = self.registration_message\n\n        # operation\n        with patch.object(\n            self.strategy,\n            \"get_location_description\",\n            return_value=self.mocked_description,\n        ):\n            with patch.object(\n                self.strategy,\n                \"get_register_service_description\",\n                return_value=self.mocked_description,\n            ):\n                with patch.object(\n                    self.strategy,\n                    \"get_location_and_service_query\",\n                    return_value=self.mocked_query,\n                ):\n                    with patch.object(\n                        type(self.strategy),\n                        \"searching_for_types\",\n                        new_callable=PropertyMock,\n                        return_value=searching_for_types,\n                    ):\n                        with patch.object(self.logger, \"log\") as mock_logger:\n                            self.tac_negotiation.act()\n\n        # after\n        self.assert_quantity_in_outbox(no_searches + 2)\n\n        # _retry_failed_registration\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=type(self.registration_message),\n            performative=self.registration_message.performative,\n            to=self.registration_message.to,\n            sender=str(self.skill.skill_context.skill_id),\n            service_description=self.registration_message.service_description,\n        )\n        assert has_attributes, error_str\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"Retrying registration on SOEF. Retry {self.tac_negotiation._nb_retries} out of {self.tac_negotiation._max_soef_registration_retries}.\",\n        )\n        assert self.tac_negotiation.failed_registration_msg is None\n\n        # _register_agent\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=OefSearchMessage,\n            performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n            to=self.skill.skill_context.search_service_address,\n            sender=self.sender,\n            service_description=self.mocked_description,\n        )\n        assert has_attributes, error_str\n\n        mock_logger.assert_any_call(logging.INFO, \"registering agent on SOEF.\")\n\n        # _search_services\n        for search in searching_for_types:\n            message = self.get_message_from_outbox()\n            has_attributes, error_str = self.message_has_attributes(\n                actual_message=message,\n                message_type=OefSearchMessage,\n                performative=OefSearchMessage.Performative.SEARCH_SERVICES,\n                to=self.skill.skill_context.search_service_address,\n                sender=self.sender,\n                query=self.mocked_query,\n            )\n            assert has_attributes, error_str\n\n            assert (\n                cast(\n                    OefSearchDialogue, self.oef_search_dialogues.get_dialogue(message)\n                ).is_seller_search\n                == search[0]\n            )\n\n            mock_logger.assert_any_call(\n                logging.INFO,\n                f\"searching for {search[1]}, search_id={message.dialogue_reference}.\",\n            )\n\n    def test_act_vi(self):\n        \"\"\"Test the act method of the negotiation behaviour where failed_registration_msg is NOT None and max retries is reached.\"\"\"\n        # setup\n        self.skill.skill_context._agent_context._shared_state = {\n            \"is_game_finished\": False,\n            \"tac_version_id\": self.tac_version_id,\n        }\n        self.goal_pursuit_readiness._status = GoalPursuitReadiness.Status.READY\n\n        searching_for_types = [(True, \"sellers\"), (False, \"buyers\")]\n        no_searches = len(searching_for_types)\n\n        self.tac_negotiation.failed_registration_msg = self.registration_message\n        self.tac_negotiation._max_soef_registration_retries = 2\n        self.tac_negotiation._nb_retries = 2\n\n        # operation\n        with patch.object(\n            self.strategy,\n            \"get_location_description\",\n            return_value=self.mocked_description,\n        ):\n            with patch.object(\n                self.strategy,\n                \"get_register_service_description\",\n                return_value=self.mocked_description,\n            ):\n                with patch.object(\n                    self.strategy,\n                    \"get_location_and_service_query\",\n                    return_value=self.mocked_query,\n                ):\n                    with patch.object(\n                        type(self.strategy),\n                        \"searching_for_types\",\n                        new_callable=PropertyMock,\n                        return_value=searching_for_types,\n                    ):\n                        with patch.object(self.logger, \"log\") as mock_logger:\n                            self.tac_negotiation.act()\n\n        # after\n        self.assert_quantity_in_outbox(no_searches + 1)\n        assert self.skill.skill_context.is_active is False\n\n        # _register_agent\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=OefSearchMessage,\n            performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n            to=self.skill.skill_context.search_service_address,\n            sender=self.sender,\n            service_description=self.mocked_description,\n        )\n        assert has_attributes, error_str\n\n        mock_logger.assert_any_call(logging.INFO, \"registering agent on SOEF.\")\n\n        # _search_services\n        for search in searching_for_types:\n            message = self.get_message_from_outbox()\n            has_attributes, error_str = self.message_has_attributes(\n                actual_message=message,\n                message_type=OefSearchMessage,\n                performative=OefSearchMessage.Performative.SEARCH_SERVICES,\n                to=self.skill.skill_context.search_service_address,\n                sender=self.sender,\n                query=self.mocked_query,\n            )\n            assert has_attributes, error_str\n\n            assert (\n                cast(\n                    OefSearchDialogue, self.oef_search_dialogues.get_dialogue(message)\n                ).is_seller_search\n                == search[0]\n            )\n\n            mock_logger.assert_any_call(\n                logging.INFO,\n                f\"searching for {search[1]}, search_id={message.dialogue_reference}.\",\n            )\n\n    def test_act_vii(self):\n        \"\"\"Test the act method of the negotiation behaviour where is_registered is True.\"\"\"\n        # setup\n        self.skill.skill_context._agent_context._shared_state = {\n            \"is_game_finished\": False,\n            \"tac_version_id\": self.tac_version_id,\n        }\n        self.goal_pursuit_readiness._status = GoalPursuitReadiness.Status.READY\n        self.tac_negotiation.is_registered = True\n\n        searching_for_types = [(True, \"sellers\"), (False, \"buyers\")]\n        no_searches = len(searching_for_types)\n\n        # operation\n        with patch.object(\n            self.strategy,\n            \"get_location_and_service_query\",\n            return_value=self.mocked_query,\n        ):\n            with patch.object(\n                type(self.strategy),\n                \"searching_for_types\",\n                new_callable=PropertyMock,\n                return_value=searching_for_types,\n            ):\n                with patch.object(self.logger, \"log\") as mock_logger:\n                    self.tac_negotiation.act()\n\n        # after\n        self.assert_quantity_in_outbox(no_searches)\n\n        # _search_services\n        for search in searching_for_types:\n            message = self.get_message_from_outbox()\n            has_attributes, error_str = self.message_has_attributes(\n                actual_message=message,\n                message_type=OefSearchMessage,\n                performative=OefSearchMessage.Performative.SEARCH_SERVICES,\n                to=self.skill.skill_context.search_service_address,\n                sender=self.sender,\n                query=self.mocked_query,\n            )\n            assert has_attributes, error_str\n\n            assert (\n                cast(\n                    OefSearchDialogue, self.oef_search_dialogues.get_dialogue(message)\n                ).is_seller_search\n                == search[0]\n            )\n\n            mock_logger.assert_any_call(\n                logging.INFO,\n                f\"searching for {search[1]}, search_id={message.dialogue_reference}.\",\n            )\n\n    def test_register_service(self):\n        \"\"\"Test the register_service method of the service_registration behaviour.\"\"\"\n        # operation\n        with patch.object(\n            self.strategy,\n            \"get_register_service_description\",\n            return_value=self.mocked_description,\n        ):\n            with patch.object(self.logger, \"log\") as mock_logger:\n                self.tac_negotiation.register_service()\n\n        # after\n        self.assert_quantity_in_outbox(1)\n\n        message = self.get_message_from_outbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=OefSearchMessage,\n            performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n            to=self.skill.skill_context.search_service_address,\n            sender=str(self.skill.skill_context.skill_id),\n            service_description=self.mocked_description,\n        )\n        assert has_attributes, error_str\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"updating service directory as {self.strategy.registering_as}.\",\n        )\n\n    def test_register_genus(self):\n        \"\"\"Test the register_genus method of the service_registration behaviour.\"\"\"\n        # operation\n        with patch.object(\n            self.strategy,\n            \"get_register_personality_description\",\n            return_value=self.mocked_description,\n        ):\n            with patch.object(self.logger, \"log\") as mock_logger:\n                self.tac_negotiation.register_genus()\n\n        # after\n        self.assert_quantity_in_outbox(1)\n\n        message = self.get_message_from_outbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=OefSearchMessage,\n            performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n            to=self.skill.skill_context.search_service_address,\n            sender=str(self.skill.skill_context.skill_id),\n            service_description=self.mocked_description,\n        )\n        assert has_attributes, error_str\n        mock_logger.assert_any_call(\n            logging.INFO, \"registering agent's personality genus on the SOEF.\"\n        )\n\n    def test_register_classification(self):\n        \"\"\"Test the register_classification method of the service_registration behaviour.\"\"\"\n        # operation\n        with patch.object(\n            self.strategy,\n            \"get_register_classification_description\",\n            return_value=self.mocked_description,\n        ):\n            with patch.object(self.logger, \"log\") as mock_logger:\n                self.tac_negotiation.register_classification()\n\n        # after\n        self.assert_quantity_in_outbox(1)\n\n        message = self.get_message_from_outbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=OefSearchMessage,\n            performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n            to=self.skill.skill_context.search_service_address,\n            sender=str(self.skill.skill_context.skill_id),\n            service_description=self.mocked_description,\n        )\n        assert has_attributes, error_str\n        mock_logger.assert_any_call(\n            logging.INFO, \"registering agent's personality classification on the SOEF.\"\n        )\n\n    def test_teardown_i(self):\n        \"\"\"Test the teardown method of the negotiation behaviour.\"\"\"\n        # setup\n        self.tac_negotiation.is_registered = True\n\n        # operation\n        with patch.object(\n            self.strategy,\n            \"get_unregister_service_description\",\n            return_value=self.mocked_description,\n        ):\n            with patch.object(\n                self.strategy,\n                \"get_location_description\",\n                return_value=self.mocked_description,\n            ):\n                with patch.object(self.logger, \"log\") as mock_logger:\n                    self.tac_negotiation.teardown()\n\n        # after\n        self.assert_quantity_in_outbox(2)\n\n        # _unregister_service\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=OefSearchMessage,\n            performative=OefSearchMessage.Performative.UNREGISTER_SERVICE,\n            to=self.skill.skill_context.search_service_address,\n            sender=self.sender,\n            service_description=self.mocked_description,\n        )\n        assert has_attributes, error_str\n        mock_logger.assert_any_call(\n            logging.DEBUG,\n            f\"unregistering from service directory as {self.strategy.registering_as}.\",\n        )\n\n        # _unregister_agent\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=OefSearchMessage,\n            performative=OefSearchMessage.Performative.UNREGISTER_SERVICE,\n            to=self.skill.skill_context.search_service_address,\n            sender=self.sender,\n            service_description=self.mocked_description,\n        )\n        assert has_attributes, error_str\n        mock_logger.assert_any_call(logging.INFO, \"unregistering agent from SOEF.\")\n\n        # teardown\n        assert self.tac_negotiation.is_registered is False\n\n    def test_teardown_ii(self):\n        \"\"\"Test the teardown method of the negotiation behaviour where is_registered is False.\"\"\"\n        # setup\n        self.tac_negotiation.is_registered = False\n\n        # operation\n        assert self.tac_negotiation.teardown() is None\n\n        # after\n        self.assert_quantity_in_outbox(0)\n\n\nclass TestTransactionCleanUpBehaviour(BaseSkillTestCase):\n    \"\"\"Test clean_up behaviour of tac negotiation.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"tac_negotiation\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.clean_up_behaviour = cast(\n            TransactionCleanUpBehaviour, cls._skill.skill_context.behaviours.clean_up\n        )\n        cls.transactions = cast(Transactions, cls._skill.skill_context.transactions)\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the clean_up behaviour.\"\"\"\n        assert self.clean_up_behaviour.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_act(self):\n        \"\"\"Test the act method of the clean_up behaviour.\"\"\"\n        # operation\n        with patch.object(\n            self.transactions, \"update_confirmed_transactions\"\n        ) as mocked_update:\n            with patch.object(\n                self.transactions, \"cleanup_pending_transactions\"\n            ) as mocked_cleanup:\n                self.clean_up_behaviour.act()\n\n        # after\n        self.assert_quantity_in_outbox(0)\n        mocked_update.assert_called_once()\n        mocked_cleanup.assert_called_once()\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the clean_up behaviour.\"\"\"\n        assert self.clean_up_behaviour.teardown() is None\n        self.assert_quantity_in_outbox(0)\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_tac_negotiation/test_dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the dialogue classes of the tac control contract skill.\"\"\"\n\nfrom pathlib import Path\nfrom typing import cast\n\nimport pytest\n\nfrom aea.exceptions import AEAEnforceError\nfrom aea.helpers.search.models import (\n    Attribute,\n    Constraint,\n    ConstraintType,\n    DataModel,\n    Description,\n    Query,\n)\nfrom aea.helpers.transaction.base import RawTransaction, Terms\nfrom aea.protocols.dialogue.base import DialogueLabel\nfrom aea.test_tools.test_skill import BaseSkillTestCase, COUNTERPARTY_AGENT_ADDRESS\n\nfrom packages.fetchai.protocols.contract_api.custom_types import Kwargs\nfrom packages.fetchai.protocols.contract_api.message import ContractApiMessage\nfrom packages.fetchai.protocols.cosm_trade.message import CosmTradeMessage\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.protocols.fipa.message import FipaMessage\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.protocols.signing.message import SigningMessage\nfrom packages.fetchai.skills.tac_negotiation.dialogues import (\n    ContractApiDialogue,\n    ContractApiDialogues,\n    CosmTradeDialogue,\n    CosmTradeDialogues,\n    DefaultDialogue,\n    DefaultDialogues,\n    FipaDialogue,\n    FipaDialogues,\n    LedgerApiDialogue,\n    LedgerApiDialogues,\n    OefSearchDialogue,\n    OefSearchDialogues,\n    SigningDialogue,\n    SigningDialogues,\n)\nfrom packages.fetchai.skills.tac_negotiation.helpers import SUPPLY_DATAMODEL_NAME\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass TestDialogues(BaseSkillTestCase):\n    \"\"\"Test dialogue classes of tac negotiation.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"tac_negotiation\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.fipa_dialogues = cast(\n            FipaDialogues, cls._skill.skill_context.fipa_dialogues\n        )\n        cls.contract_api_dialogues = cast(\n            ContractApiDialogues, cls._skill.skill_context.contract_api_dialogues\n        )\n        cls.cosm_trade_dialogues = cast(\n            CosmTradeDialogues, cls._skill.skill_context.cosm_trade_dialogues\n        )\n        cls.default_dialogues = cast(\n            DefaultDialogues, cls._skill.skill_context.default_dialogues\n        )\n        cls.signing_dialogues = cast(\n            SigningDialogues, cls._skill.skill_context.signing_dialogues\n        )\n        cls.ledger_api_dialogues = cast(\n            LedgerApiDialogues, cls._skill.skill_context.ledger_api_dialogues\n        )\n        cls.oef_search_dialogues = cast(\n            OefSearchDialogues, cls._skill.skill_context.oef_search_dialogues\n        )\n        cls.query = Query(\n            [Constraint(\"some_attribute\", ConstraintType(\"==\", \"some_service\"))],\n            DataModel(\n                SUPPLY_DATAMODEL_NAME,\n                [\n                    Attribute(\n                        \"some_attribute\", str, False, \"Some attribute descriptions.\"\n                    )\n                ],\n            ),\n        )\n\n    def test_fipa_dialogue(self):\n        \"\"\"Test the FipaDialogue class.\"\"\"\n        fipa_dialogue = FipaDialogue(\n            DialogueLabel(\n                (\"\", \"\"),\n                COUNTERPARTY_AGENT_ADDRESS,\n                self.skill.skill_context.agent_address,\n            ),\n            self.skill.skill_context.agent_address,\n            role=FipaDialogue.Role.BUYER,\n        )\n\n        # counterparty_signature\n        with pytest.raises(ValueError, match=\"counterparty_signature not set!\"):\n            assert fipa_dialogue.counterparty_signature\n        fipa_dialogue.counterparty_signature = \"some_counterparty_signature\"\n        with pytest.raises(\n            AEAEnforceError, match=\"counterparty_signature already set!\"\n        ):\n            fipa_dialogue.counterparty_signature = \"some_other_counterparty_signature\"\n        assert fipa_dialogue.counterparty_signature == \"some_counterparty_signature\"\n\n        # proposal\n        with pytest.raises(ValueError, match=\"Proposal not set!\"):\n            assert fipa_dialogue.proposal\n        description = Description({\"foo1\": 1, \"bar1\": 2})\n        fipa_dialogue.proposal = description\n        with pytest.raises(AEAEnforceError, match=\"Proposal already set!\"):\n            fipa_dialogue.proposal = description\n        assert fipa_dialogue.proposal == description\n\n        # terms\n        with pytest.raises(ValueError, match=\"Terms not set!\"):\n            assert fipa_dialogue.terms\n        terms = Terms(\n            \"some_ledger_id\",\n            self.skill.skill_context.agent_address,\n            \"counterprty\",\n            {\"currency_id\": 50},\n            {\"good_id\": -10},\n            \"some_nonce\",\n        )\n        fipa_dialogue.terms = terms\n        with pytest.raises(AEAEnforceError, match=\"Terms already set!\"):\n            fipa_dialogue.terms = terms\n        assert fipa_dialogue.terms == terms\n\n    def test_fipa_dialogues(self):\n        \"\"\"Test the FipaDialogues class.\"\"\"\n        _, dialogue = self.fipa_dialogues.create(\n            counterparty=COUNTERPARTY_AGENT_ADDRESS,\n            performative=FipaMessage.Performative.CFP,\n            query=self.query,\n        )\n        assert dialogue.role == FipaDialogue.Role.BUYER\n        assert dialogue.self_address == self.skill.skill_context.agent_address\n\n    def test_contract_api_dialogue(self):\n        \"\"\"Test the ContractApiDialogue class.\"\"\"\n        contract_api_dialogue = ContractApiDialogue(\n            DialogueLabel(\n                (\"\", \"\"),\n                COUNTERPARTY_AGENT_ADDRESS,\n                self.skill.skill_context.agent_address,\n            ),\n            self.skill.skill_context.agent_address,\n            role=ContractApiDialogue.Role.AGENT,\n        )\n\n        # associated_fipa_dialogue\n        with pytest.raises(ValueError, match=\"associated_fipa_dialogue not set!\"):\n            assert contract_api_dialogue.associated_fipa_dialogue\n\n        fipa_dialogue = FipaDialogue(\n            DialogueLabel(\n                (\"\", \"\"),\n                COUNTERPARTY_AGENT_ADDRESS,\n                self.skill.skill_context.agent_address,\n            ),\n            self.skill.skill_context.agent_address,\n            role=FipaDialogue.Role.BUYER,\n        )\n        contract_api_dialogue.associated_fipa_dialogue = fipa_dialogue\n        with pytest.raises(\n            AEAEnforceError, match=\"associated_fipa_dialogue already set!\"\n        ):\n            contract_api_dialogue.associated_fipa_dialogue = fipa_dialogue\n        assert contract_api_dialogue.associated_fipa_dialogue == fipa_dialogue\n\n    def test_contract_api_dialogues(self):\n        \"\"\"Test the ContractApiDialogues class.\"\"\"\n        _, dialogue = self.contract_api_dialogues.create(\n            counterparty=COUNTERPARTY_AGENT_ADDRESS,\n            performative=ContractApiMessage.Performative.GET_DEPLOY_TRANSACTION,\n            ledger_id=\"some_ledger_id\",\n            contract_id=\"some_contract_id\",\n            callable=\"some_callable\",\n            kwargs=Kwargs({\"some_key\": \"some_value\"}),\n        )\n        assert dialogue.role == ContractApiDialogue.Role.AGENT\n        assert dialogue.self_address == str(self.skill.skill_context.skill_id)\n\n    def test_cosm_trade_dialogues(self):\n        \"\"\"Test the CosmTradeDialogues class.\"\"\"\n        _, dialogue = self.cosm_trade_dialogues.create(\n            counterparty=COUNTERPARTY_AGENT_ADDRESS,\n            performative=CosmTradeMessage.Performative.INFORM_PUBLIC_KEY,\n            public_key=\"some_public_key\",\n        )\n        assert dialogue.role == CosmTradeDialogue.Role.AGENT\n        assert dialogue.self_address == self.skill.skill_context.agent_address\n\n    def test_default_dialogues(self):\n        \"\"\"Test the DefaultDialogues class.\"\"\"\n        _, dialogue = self.default_dialogues.create(\n            counterparty=COUNTERPARTY_AGENT_ADDRESS,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"some_content\",\n        )\n        assert dialogue.role == DefaultDialogue.Role.AGENT\n        assert dialogue.self_address == self.skill.skill_context.agent_address\n\n    def test_ledger_api_dialogue(self):\n        \"\"\"Test the LedgerApiDialogue class.\"\"\"\n        ledger_api_dialogue = LedgerApiDialogue(\n            DialogueLabel(\n                (\"\", \"\"),\n                COUNTERPARTY_AGENT_ADDRESS,\n                self.skill.skill_context.agent_address,\n            ),\n            self.skill.skill_context.agent_address,\n            role=ContractApiDialogue.Role.AGENT,\n        )\n\n        # associated_signing_dialogue\n        with pytest.raises(ValueError, match=\"Associated signing dialogue not set!\"):\n            assert ledger_api_dialogue.associated_signing_dialogue\n        signing_dialogue = SigningDialogue(\n            DialogueLabel(\n                (\"\", \"\"),\n                COUNTERPARTY_AGENT_ADDRESS,\n                self.skill.skill_context.agent_address,\n            ),\n            self.skill.skill_context.agent_address,\n            role=SigningDialogue.Role.SKILL,\n        )\n        ledger_api_dialogue.associated_signing_dialogue = signing_dialogue\n        with pytest.raises(\n            AEAEnforceError, match=\"Associated signing dialogue already set!\"\n        ):\n            ledger_api_dialogue.associated_signing_dialogue = signing_dialogue\n        assert ledger_api_dialogue.associated_signing_dialogue == signing_dialogue\n\n    def test_ledger_api_dialogues(self):\n        \"\"\"Test the LedgerApiDialogues class.\"\"\"\n        _, dialogue = self.ledger_api_dialogues.create(\n            counterparty=COUNTERPARTY_AGENT_ADDRESS,\n            performative=LedgerApiMessage.Performative.GET_BALANCE,\n            ledger_id=\"some_ledger_id\",\n            address=\"some_address\",\n        )\n        assert dialogue.role == LedgerApiDialogue.Role.AGENT\n        assert dialogue.self_address == str(self.skill.skill_context.skill_id)\n\n    def test_oef_search_dialogue(self):\n        \"\"\"Test the OefSearchDialogue class.\"\"\"\n        oef_search_dialogue = OefSearchDialogue(\n            DialogueLabel(\n                (\"\", \"\"),\n                COUNTERPARTY_AGENT_ADDRESS,\n                self.skill.skill_context.agent_address,\n            ),\n            self.skill.skill_context.agent_address,\n            role=ContractApiDialogue.Role.AGENT,\n        )\n\n        # is_seller_search\n        with pytest.raises(ValueError, match=\"is_seller_search not set!\"):\n            assert oef_search_dialogue.is_seller_search\n        oef_search_dialogue.is_seller_search = True\n        with pytest.raises(AEAEnforceError, match=\"is_seller_search already set!\"):\n            oef_search_dialogue.is_seller_search = False\n        assert oef_search_dialogue.is_seller_search is True\n\n    def test_oef_search_dialogues(self):\n        \"\"\"Test the OefSearchDialogues class.\"\"\"\n        _, dialogue = self.oef_search_dialogues.create(\n            counterparty=COUNTERPARTY_AGENT_ADDRESS,\n            performative=OefSearchMessage.Performative.SEARCH_SERVICES,\n            query=self.query,\n        )\n        assert dialogue.role == OefSearchDialogue.Role.AGENT\n        assert dialogue.self_address == str(self.skill.skill_context.skill_id)\n\n    def test_signing_dialogue(self):\n        \"\"\"Test the SigningDialogue class.\"\"\"\n        signing_dialogue = SigningDialogue(\n            DialogueLabel(\n                (\"\", \"\"),\n                COUNTERPARTY_AGENT_ADDRESS,\n                self.skill.skill_context.agent_address,\n            ),\n            self.skill.skill_context.agent_address,\n            role=ContractApiDialogue.Role.AGENT,\n        )\n\n        # associated_fipa_dialogue\n        with pytest.raises(ValueError, match=\"associated_fipa_dialogue not set!\"):\n            assert signing_dialogue.associated_fipa_dialogue\n        fipa_dialogue = FipaDialogue(\n            DialogueLabel(\n                (\"\", \"\"),\n                COUNTERPARTY_AGENT_ADDRESS,\n                self.skill.skill_context.agent_address,\n            ),\n            self.skill.skill_context.agent_address,\n            role=FipaDialogue.Role.BUYER,\n        )\n        signing_dialogue.associated_fipa_dialogue = fipa_dialogue\n        with pytest.raises(\n            AEAEnforceError, match=\"associated_fipa_dialogue already set!\"\n        ):\n            signing_dialogue.associated_fipa_dialogue = fipa_dialogue\n        assert signing_dialogue.associated_fipa_dialogue == fipa_dialogue\n\n        # associated_cosm_trade_dialogue\n        cosm_trade_dialogue = CosmTradeDialogue(\n            DialogueLabel(\n                (\"\", \"\"),\n                COUNTERPARTY_AGENT_ADDRESS,\n                self.skill.skill_context.agent_address,\n            ),\n            self.skill.skill_context.agent_address,\n            role=CosmTradeDialogue.Role.AGENT,\n        )\n        signing_dialogue.associated_cosm_trade_dialogue = cosm_trade_dialogue\n        with pytest.raises(\n            AEAEnforceError, match=\"associated_cosm_trade_dialogue already set!\"\n        ):\n            signing_dialogue.associated_cosm_trade_dialogue = cosm_trade_dialogue\n        assert signing_dialogue.associated_cosm_trade_dialogue == cosm_trade_dialogue\n\n    def test_signing_dialogues(self):\n        \"\"\"Test the SigningDialogues class.\"\"\"\n        _, dialogue = self.signing_dialogues.create(\n            counterparty=COUNTERPARTY_AGENT_ADDRESS,\n            performative=SigningMessage.Performative.SIGN_TRANSACTION,\n            terms=Terms(\n                \"some_ledger_id\",\n                \"some_sender_address\",\n                \"some_counterparty_address\",\n                dict(),\n                dict(),\n                \"some_nonce\",\n            ),\n            raw_transaction=RawTransaction(\n                \"some_ledger_id\", {\"some_key\": \"some_value\"}\n            ),\n        )\n        assert dialogue.role == SigningDialogue.Role.SKILL\n        assert dialogue.self_address == str(self.skill.skill_context.skill_id)\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_tac_negotiation/test_handlers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the handler classes of the tac negotiation skill.\"\"\"\n\nimport logging\nfrom pathlib import Path\nfrom typing import Optional, cast\nfrom unittest.mock import PropertyMock, patch\n\nimport pytest\nfrom aea_ledger_ethereum import EthereumApi\nfrom aea_ledger_fetchai import FetchAIApi\n\nfrom aea.crypto.ledger_apis import LedgerApis\nfrom aea.exceptions import AEAEnforceError\nfrom aea.helpers.search.models import (\n    Attribute,\n    Constraint,\n    ConstraintType,\n    DataModel,\n    Description,\n    Location,\n    Query,\n)\nfrom aea.helpers.transaction.base import (\n    RawMessage,\n    RawTransaction,\n    SignedTransaction,\n    State,\n    Terms,\n    TransactionDigest,\n    TransactionReceipt,\n)\nfrom aea.protocols.dialogue.base import DialogueMessage, DialogueStats\nfrom aea.test_tools.test_skill import BaseSkillTestCase, COUNTERPARTY_AGENT_ADDRESS\n\nfrom packages.fetchai.protocols.contract_api.custom_types import Kwargs\nfrom packages.fetchai.protocols.contract_api.message import ContractApiMessage\nfrom packages.fetchai.protocols.cosm_trade.message import CosmTradeMessage\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.protocols.fipa.message import FipaMessage\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.protocols.signing.message import SigningMessage\nfrom packages.fetchai.skills.tac_negotiation.behaviours import (\n    GoodsRegisterAndSearchBehaviour,\n)\nfrom packages.fetchai.skills.tac_negotiation.dialogues import (\n    ContractApiDialogue,\n    ContractApiDialogues,\n    CosmTradeDialogue,\n    CosmTradeDialogues,\n    FipaDialogue,\n    FipaDialogues,\n    LedgerApiDialogue,\n    LedgerApiDialogues,\n    OefSearchDialogue,\n    OefSearchDialogues,\n    SigningDialogue,\n    SigningDialogues,\n)\nfrom packages.fetchai.skills.tac_negotiation.handlers import (\n    ContractApiHandler,\n    CosmTradeHandler,\n    FipaNegotiationHandler,\n    LEDGER_API_ADDRESS,\n    LedgerApiHandler,\n    OefSearchHandler,\n    SigningHandler,\n)\nfrom packages.fetchai.skills.tac_negotiation.helpers import SUPPLY_DATAMODEL_NAME\nfrom packages.fetchai.skills.tac_negotiation.strategy import Strategy\nfrom packages.fetchai.skills.tac_negotiation.transactions import Transactions\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass TestFipaHandler(BaseSkillTestCase):\n    \"\"\"Test fipa handler of tac negotiation.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"tac_negotiation\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.fipa_handler = cast(\n            FipaNegotiationHandler, cls._skill.skill_context.handlers.fipa\n        )\n        cls.strategy = cast(Strategy, cls._skill.skill_context.strategy)\n        cls.transactions = cast(Transactions, cls._skill.skill_context.transactions)\n        cls.logger = cls._skill.skill_context.logger\n\n        cls.fipa_dialogues = cast(\n            FipaDialogues, cls._skill.skill_context.fipa_dialogues\n        )\n        cls.contract_api_dialogues = cast(\n            ContractApiDialogues, cls._skill.skill_context.contract_api_dialogues\n        )\n        cls.signing_dialogues = cast(\n            SigningDialogues, cls._skill.skill_context.signing_dialogues\n        )\n\n        cls.dialogue_stats = cls.fipa_dialogues.dialogue_stats\n        cls.ledger_id = \"some_ledger_id\"\n        cls.counterprty_address = COUNTERPARTY_AGENT_ADDRESS\n        cls.amount_by_currency_id = {\"1\": 50}\n        cls.quantities_by_good_id = {\"2\": -10}\n        cls.nonce = \"234543\"\n        cls.contract_id = \"some_contract_id\"\n        cls.contract_address = \"some_contract_address\"\n        cls.kwargs = {\"some_key\": \"some_value\"}\n        cls.counterparty_signature = \"some_counterparty_signature\"\n        cls.terms = Terms(\n            cls.ledger_id,\n            cls._skill.skill_context.agent_address,\n            cls.counterprty_address,\n            cls.amount_by_currency_id,\n            cls.quantities_by_good_id,\n            cls.nonce,\n        )\n        cls.raw_message = RawMessage(\n            ledger_id=cls.ledger_id, body=cls.terms.sender_hash.encode(\"utf-8\")\n        )\n\n        cls.cfp_query = Query(\n            [Constraint(\"some_attribute\", ConstraintType(\"==\", \"some_service\"))],\n            DataModel(\n                SUPPLY_DATAMODEL_NAME,\n                [\n                    Attribute(\n                        \"some_attribute\", str, False, \"Some attribute descriptions.\"\n                    )\n                ],\n            ),\n        )\n        cls.proposal = Description(\n            {\n                \"ledger_id\": cls.ledger_id,\n                \"price\": 100,\n                \"currency_id\": \"1\",\n                \"fee\": 1,\n                \"nonce\": cls.nonce,\n            }\n        )\n        cls.list_of_messages_other_initiated = (\n            DialogueMessage(\n                FipaMessage.Performative.CFP, {\"query\": cls.cfp_query}, True\n            ),\n            DialogueMessage(\n                FipaMessage.Performative.PROPOSE, {\"proposal\": cls.proposal}\n            ),\n            DialogueMessage(FipaMessage.Performative.ACCEPT),\n            DialogueMessage(\n                FipaMessage.Performative.MATCH_ACCEPT_W_INFORM,\n                {\"info\": {\"address\": \"some_term_sender_address\"}},\n            ),\n            DialogueMessage(\n                FipaMessage.Performative.INFORM,\n                {\"info\": {\"transaction_digest\": \"some_transaction_digest_body\"}},\n            ),\n        )\n        cls.list_of_messages_self_initiated = (\n            DialogueMessage(FipaMessage.Performative.CFP, {\"query\": cls.cfp_query}),\n            DialogueMessage(\n                FipaMessage.Performative.PROPOSE, {\"proposal\": cls.proposal}\n            ),\n            DialogueMessage(FipaMessage.Performative.ACCEPT),\n            DialogueMessage(\n                FipaMessage.Performative.MATCH_ACCEPT_W_INFORM,\n                {\"info\": {\"address\": \"some_term_sender_address\"}},\n            ),\n            DialogueMessage(\n                FipaMessage.Performative.INFORM,\n                {\"info\": {\"transaction_digest\": \"some_transaction_digest_body\"}},\n            ),\n        )\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the fipa handler.\"\"\"\n        assert self.fipa_handler.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle_unidentified_dialogue(self):\n        \"\"\"Test the _handle_unidentified_dialogue method of the fipa handler.\"\"\"\n        # setup\n        incorrect_dialogue_reference = (\"\", \"\")\n        incoming_message = self.build_incoming_message(\n            message_type=FipaMessage,\n            dialogue_reference=incorrect_dialogue_reference,\n            performative=FipaMessage.Performative.ACCEPT,\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.fipa_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received invalid fipa message={incoming_message}, unidentified dialogue.\",\n        )\n\n        self.assert_quantity_in_outbox(1)\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=DefaultMessage,\n            performative=DefaultMessage.Performative.ERROR,\n            to=incoming_message.sender,\n            sender=self.skill.skill_context.agent_address,\n            error_code=DefaultMessage.ErrorCode.INVALID_DIALOGUE,\n            error_msg=\"Invalid dialogue.\",\n            error_data={\"fipa_message\": incoming_message.encode()},\n        )\n        assert has_attributes, error_str\n\n    def _assert_stat_state(\n        self,\n        dialogue_stats: DialogueStats,\n        changed_agent: Optional[str] = None,\n        changed_end_state: Optional[FipaDialogue.EndState] = None,\n    ) -> None:\n        \"\"\"\n        Evaluates the state of dialogue stats.\n\n        If 'changed_agent' and 'changed_end_state' are None,\n        it asserts that the dialogue stats are 0 for all end_states.\n\n        If they are not None, it checks that all end_states are 0, except for 'changed_end_state'\n        in dialogues started by 'changed_agent' (i.e. 'self' or 'other').\n\n        :param changed_agent: can either by 'self' or 'other'. Dialogues started by this agent has a none-zero end_state.\n        :param changed_end_state: the changed end_state.\n        :return:\n        \"\"\"\n        if changed_agent is None and changed_end_state is None:\n            unchanged_dict_1 = dialogue_stats.self_initiated\n            unchanged_dict_2 = dialogue_stats.other_initiated\n            for end_state_numbers in unchanged_dict_1.values():\n                assert end_state_numbers == 0\n            for end_state_numbers in unchanged_dict_2.values():\n                assert end_state_numbers == 0\n        elif changed_agent is not None and changed_end_state is not None:\n            if changed_agent == \"self\":\n                changed_dict = dialogue_stats.self_initiated\n                unchanged_dict = dialogue_stats.other_initiated\n            elif changed_agent == \"other\":\n                changed_dict = dialogue_stats.other_initiated\n                unchanged_dict = dialogue_stats.self_initiated\n            else:\n                raise SyntaxError(\n                    f\"changed_agent can only be 'self' or 'other'. Found {changed_agent}.\"\n                )\n\n            for end_state_numbers in unchanged_dict.values():\n                assert end_state_numbers == 0\n            for end_state, end_state_numbers in changed_dict.items():\n                if end_state == changed_end_state:\n                    assert end_state_numbers == 1\n                else:\n                    assert end_state_numbers == 0\n        else:\n            raise SyntaxError(\n                \"changed_agent and changed_end_state should either both be None, or neither.\"\n            )\n\n    def test_handle_cfp_i(self):\n        \"\"\"Test the _on_cfp method of the fipa handler where proposal_for_query is None.\"\"\"\n        # setup\n        mocked_proposal = None\n        incoming_message = self.build_incoming_message(\n            message_type=FipaMessage,\n            performative=FipaMessage.Performative.CFP,\n            query=self.cfp_query,\n        )\n\n        # before\n        self._assert_stat_state(self.dialogue_stats)\n\n        # operation\n        with patch.object(\n            self.strategy,\n            \"get_proposal_for_query\",\n            return_value=mocked_proposal,\n        ):\n            with patch.object(self.logger, \"log\") as mock_logger:\n                self.fipa_handler.handle(incoming_message)\n\n        # after\n        self.assert_quantity_in_outbox(1)\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received {incoming_message.performative} from {incoming_message.sender[-5:]} (as {self.fipa_dialogues.get_dialogue(incoming_message).role}), message={incoming_message}\",\n        )\n\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=FipaMessage,\n            performative=FipaMessage.Performative.DECLINE,\n            to=incoming_message.sender,\n            sender=self.skill.skill_context.agent_address,\n            target=incoming_message.message_id,\n        )\n        assert has_attributes, error_str\n\n        self._assert_stat_state(\n            self.dialogue_stats, \"other\", FipaDialogue.EndState.DECLINED_CFP\n        )\n\n    def test_handle_cfp_ii(self):\n        \"\"\"Test the _on_cfp method of the fipa handler where proposal_for_query is NOT None.\"\"\"\n        # setup\n        incoming_message = self.build_incoming_message(\n            message_type=FipaMessage,\n            performative=FipaMessage.Performative.CFP,\n            query=self.cfp_query,\n        )\n\n        # operation\n        with patch.object(\n            self.strategy, \"get_proposal_for_query\", return_value=self.proposal\n        ):\n            with patch.object(self.strategy, \"terms_from_proposal\") as mock_terms:\n                with patch.object(\n                    self.transactions, \"add_pending_proposal\"\n                ) as mock_pending:\n                    with patch.object(self.logger, \"log\") as mock_logger:\n                        self.fipa_handler.handle(incoming_message)\n\n        # after\n        self.assert_quantity_in_outbox(1)\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received {incoming_message.performative} from {incoming_message.sender[-5:]} (as {self.fipa_dialogues.get_dialogue(incoming_message).role}), message={incoming_message}\",\n        )\n\n        message = self.get_message_from_outbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=FipaMessage,\n            performative=FipaMessage.Performative.PROPOSE,\n            to=incoming_message.sender,\n            sender=self.skill.skill_context.agent_address,\n            target=incoming_message.message_id,\n            proposal=self.proposal,\n        )\n        assert has_attributes, error_str\n\n        mock_terms.assert_called_once()\n        mock_pending.assert_called_once()\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"sending {message.performative} to {message.to[-5:]} (as {self.fipa_dialogues.get_dialogue(message).role}), message={message}\",\n        )\n\n    def test_handle_propose_i(self):\n        \"\"\"Test the _handle_propose method of the fipa handler where the tx IS profitable.\"\"\"\n        # setup\n        fipa_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.fipa_dialogues,\n            messages=self.list_of_messages_self_initiated[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=fipa_dialogue,\n            performative=FipaMessage.Performative.PROPOSE,\n            proposal=self.proposal,\n        )\n\n        # operation\n        with patch.object(\n            self.strategy, \"is_profitable_transaction\", return_value=True\n        ):\n            with patch.object(self.transactions, \"add_locked_tx\") as mock_lock:\n                with patch.object(\n                    self.transactions, \"add_pending_initial_acceptance\"\n                ) as mock_pending:\n                    with patch.object(self.logger, \"log\") as mock_logger:\n                        self.fipa_handler.handle(incoming_message)\n\n        # after\n        self.assert_quantity_in_outbox(1)\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received {incoming_message.performative} from {incoming_message.sender[-5:]} (as {self.fipa_dialogues.get_dialogue(incoming_message).role}), message={incoming_message}\",\n        )\n\n        message = self.get_message_from_outbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=FipaMessage,\n            performative=FipaMessage.Performative.ACCEPT,\n            to=incoming_message.sender,\n            sender=self.skill.skill_context.agent_address,\n            target=incoming_message.message_id,\n        )\n        assert has_attributes, error_str\n\n        mock_lock.assert_called_once()\n        mock_pending.assert_called_once()\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"sending {message.performative} to {message.to[-5:]} (as {self.fipa_dialogues.get_dialogue(message).role}), message={message}\",\n        )\n\n    def test_handle_propose_ii(self):\n        \"\"\"Test the _handle_propose method of the fipa handler where the tx is NOT profitable.\"\"\"\n        # setup\n        fipa_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.fipa_dialogues,\n            messages=self.list_of_messages_self_initiated[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=fipa_dialogue,\n            performative=FipaMessage.Performative.PROPOSE,\n            proposal=self.proposal,\n        )\n\n        # before\n        self._assert_stat_state(self.dialogue_stats)\n\n        # operation\n        with patch.object(\n            self.strategy, \"is_profitable_transaction\", return_value=False\n        ):\n            with patch.object(self.logger, \"log\") as mock_logger:\n                self.fipa_handler.handle(incoming_message)\n\n        # after\n        self.assert_quantity_in_outbox(1)\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received {incoming_message.performative} from {incoming_message.sender[-5:]} (as {self.fipa_dialogues.get_dialogue(incoming_message).role}), message={incoming_message}\",\n        )\n\n        message = self.get_message_from_outbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=FipaMessage,\n            performative=FipaMessage.Performative.DECLINE,\n            to=incoming_message.sender,\n            sender=self.skill.skill_context.agent_address,\n            target=incoming_message.message_id,\n        )\n        assert has_attributes, error_str\n\n        self._assert_stat_state(\n            self.dialogue_stats, \"self\", FipaDialogue.EndState.DECLINED_PROPOSE\n        )\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"sending {message.performative} to {message.to[-5:]} (as {self.fipa_dialogues.get_dialogue(message).role}), message={message}\",\n        )\n\n    def test_handle_decline_decline_cfp(self):\n        \"\"\"Test the _handle_decline method of the fipa handler where the end state is decline_cfp.\"\"\"\n        # setup\n        fipa_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.fipa_dialogues,\n            messages=self.list_of_messages_self_initiated[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=fipa_dialogue,\n            performative=FipaMessage.Performative.DECLINE,\n        )\n\n        # before\n        self._assert_stat_state(self.dialogue_stats)\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.fipa_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received {incoming_message.performative} from {incoming_message.sender[-5:]} (as {self.fipa_dialogues.get_dialogue(incoming_message).role}), message={incoming_message}\",\n        )\n\n        self._assert_stat_state(\n            self.dialogue_stats, \"self\", FipaDialogue.EndState.DECLINED_CFP\n        )\n\n    def test_handle_decline_decline_propose(self):\n        \"\"\"Test the _handle_decline method of the fipa handler where the end state is decline_propose.\"\"\"\n        # setup\n        fipa_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.fipa_dialogues,\n            messages=self.list_of_messages_other_initiated[:2],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=fipa_dialogue,\n            performative=FipaMessage.Performative.DECLINE,\n        )\n\n        # before\n        self._assert_stat_state(self.dialogue_stats)\n\n        # operation\n        with patch.object(self.transactions, \"pop_pending_proposal\") as mock_pending:\n            with patch.object(self.logger, \"log\") as mock_logger:\n                self.fipa_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received {incoming_message.performative} from {incoming_message.sender[-5:]} (as {self.fipa_dialogues.get_dialogue(incoming_message).role}), message={incoming_message}\",\n        )\n\n        self._assert_stat_state(\n            self.dialogue_stats, \"other\", FipaDialogue.EndState.DECLINED_PROPOSE\n        )\n\n        mock_pending.assert_called_once()\n\n    def test_handle_decline_decline_accept(self):\n        \"\"\"Test the _handle_decline method of the fipa handler where the end state is decline_accept.\"\"\"\n        # setup\n        fipa_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.fipa_dialogues,\n            messages=self.list_of_messages_self_initiated[:3],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=fipa_dialogue,\n            performative=FipaMessage.Performative.DECLINE,\n        )\n\n        # before\n        self._assert_stat_state(self.dialogue_stats)\n\n        # operation\n        with patch.object(\n            self.transactions, \"pop_pending_initial_acceptance\"\n        ) as mock_pending:\n            with patch.object(self.transactions, \"pop_locked_tx\") as mock_locked:\n                with patch.object(self.logger, \"log\") as mock_logger:\n                    self.fipa_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received {incoming_message.performative} from {incoming_message.sender[-5:]} (as {self.fipa_dialogues.get_dialogue(incoming_message).role}), message={incoming_message}\",\n        )\n\n        self._assert_stat_state(\n            self.dialogue_stats, \"self\", FipaDialogue.EndState.DECLINED_ACCEPT\n        )\n\n        mock_pending.assert_called_once()\n        mock_locked.assert_called_once()\n\n    def test_handle_accept_i(self):\n        \"\"\"Test the _on_accept method of the fipa handler where the tx IS profitable, is_contract_tx is True, ledger is Ethereum.\"\"\"\n        # setup\n        self.strategy._is_contract_tx = True\n        self.strategy._ledger_id = EthereumApi.identifier\n\n        fipa_dialogue = cast(\n            FipaDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.fipa_dialogues,\n                messages=self.list_of_messages_other_initiated[:2],\n                is_agent_to_agent_messages=True,\n            ),\n        )\n        fipa_dialogue._terms = self.terms\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=fipa_dialogue,\n            performative=FipaMessage.Performative.ACCEPT,\n        )\n\n        # operation\n        with patch.object(self.transactions, \"pop_pending_proposal\") as mock_pending:\n            with patch.object(\n                self.strategy, \"is_profitable_transaction\", return_value=True\n            ):\n                with patch.object(self.transactions, \"add_locked_tx\") as mock_lock:\n                    with patch.object(\n                        type(self.strategy),\n                        \"contract_id\",\n                        new_callable=PropertyMock,\n                        return_value=self.contract_id,\n                    ):\n                        with patch.object(\n                            type(self.strategy),\n                            \"contract_address\",\n                            new_callable=PropertyMock,\n                            return_value=self.contract_address,\n                        ):\n                            with patch.object(\n                                self.strategy,\n                                \"kwargs_from_terms\",\n                                return_value=self.kwargs,\n                            ):\n                                with patch.object(self.logger, \"log\") as mock_logger:\n                                    self.fipa_handler.handle(incoming_message)\n\n        # after\n        self.assert_quantity_in_outbox(1)\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received {incoming_message.performative} from {incoming_message.sender[-5:]} (as {self.fipa_dialogues.get_dialogue(incoming_message).role}), message={incoming_message}\",\n        )\n\n        mock_pending.assert_called_once()\n        mock_lock.assert_called_once()\n\n        message = self.get_message_from_outbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=ContractApiMessage,\n            performative=ContractApiMessage.Performative.GET_RAW_MESSAGE,\n            to=LEDGER_API_ADDRESS,\n            sender=str(self.skill.skill_context.skill_id),\n            ledger_id=EthereumApi.identifier,\n            contract_id=self.contract_id,\n            contract_address=self.contract_address,\n            callable=\"get_hash_batch\",\n            kwargs=ContractApiMessage.Kwargs(self.kwargs),\n        )\n        assert has_attributes, error_str\n\n        assert (\n            cast(\n                ContractApiDialogue, self.contract_api_dialogues.get_dialogue(message)\n            ).associated_fipa_dialogue\n            == fipa_dialogue\n        )\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"requesting batch transaction hash, sending {message.performative} to {self.contract_id}, message={message}\",\n        )\n\n    def test_handle_accept_ii(self):\n        \"\"\"Test the _on_accept method of the fipa handler where the tx IS profitable and strategy's is_contract_tx is False.\"\"\"\n        # setup\n        self.strategy._is_contract_tx = False\n\n        fipa_dialogue = cast(\n            FipaDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.fipa_dialogues,\n                messages=self.list_of_messages_other_initiated[:2],\n            ),\n        )\n        fipa_dialogue._terms = self.terms\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=fipa_dialogue,\n            performative=FipaMessage.Performative.ACCEPT,\n        )\n\n        # operation\n        with patch.object(\n            self.transactions, \"pop_pending_proposal\", return_value=self.terms\n        ) as mock_pending:\n            with patch.object(\n                self.strategy, \"is_profitable_transaction\", return_value=True\n            ):\n                with patch.object(self.logger, \"log\") as mock_logger:\n                    self.fipa_handler.handle(incoming_message)\n\n        # after\n        self.assert_quantity_in_decision_making_queue(1)\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received {incoming_message.performative} from {incoming_message.sender[-5:]} (as {self.fipa_dialogues.get_dialogue(incoming_message).role}), message={incoming_message}\",\n        )\n\n        mock_pending.assert_called_once()\n\n        message = self.get_message_from_decision_maker_inbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=SigningMessage,\n            performative=SigningMessage.Performative.SIGN_MESSAGE,\n            to=self.skill.skill_context.decision_maker_address,\n            sender=str(self.skill.skill_context.skill_id),\n            terms=self.terms,\n            raw_message=self.raw_message,\n        )\n        assert has_attributes, error_str\n\n        assert (\n            cast(\n                SigningDialogue, self.signing_dialogues.get_dialogue(message)\n            ).associated_fipa_dialogue\n            == fipa_dialogue\n        )\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"requesting signature, sending {message.performative} to decision_maker, message={message}\",\n        )\n\n    def test_handle_accept_iii(self):\n        \"\"\"Test the _on_accept method of the fipa handler where the tx IS profitable, is_contract_tx is True, ledger is FetchAi.\"\"\"\n        # setup\n        self.strategy._is_contract_tx = True\n        self.strategy._ledger_id = FetchAIApi.identifier\n\n        fipa_dialogue = cast(\n            FipaDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.fipa_dialogues,\n                messages=self.list_of_messages_other_initiated[:2],\n                is_agent_to_agent_messages=True,\n            ),\n        )\n        fipa_dialogue._terms = self.terms\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=fipa_dialogue,\n            performative=FipaMessage.Performative.ACCEPT,\n        )\n\n        # operation\n        with patch.object(self.transactions, \"pop_pending_proposal\") as mock_pending:\n            with patch.object(\n                self.strategy, \"is_profitable_transaction\", return_value=True\n            ):\n                with patch.object(self.logger, \"log\") as mock_logger:\n                    self.fipa_handler.handle(incoming_message)\n\n        # after\n        self.assert_quantity_in_outbox(1)\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received {incoming_message.performative} from {incoming_message.sender[-5:]} (as {self.fipa_dialogues.get_dialogue(incoming_message).role}), message={incoming_message}\",\n        )\n\n        mock_pending.assert_called_once()\n\n        message = self.get_message_from_outbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=FipaMessage,\n            performative=FipaMessage.Performative.MATCH_ACCEPT_W_INFORM,\n            to=incoming_message.sender,\n            sender=self.skill.skill_context.agent_address,\n            info={\n                \"public_key\": self.skill.skill_context.public_keys[\n                    self.strategy.ledger_id\n                ]\n            },\n        )\n        assert has_attributes, error_str\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"sending {message.performative.value} to {incoming_message.sender[-5:]} (as {self.fipa_dialogues.get_dialogue(incoming_message).role}), message={message}.\",\n        )\n\n    def test_handle_accept_iv(self):\n        \"\"\"Test the _on_accept method of the fipa handler where the tx IS profitable, is_contract_tx is True, ledger is FetchAi, public_key is None.\"\"\"\n        # setup\n        self.strategy._is_contract_tx = True\n        self.strategy._ledger_id = FetchAIApi.identifier\n\n        fipa_dialogue = cast(\n            FipaDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.fipa_dialogues,\n                messages=self.list_of_messages_other_initiated[:2],\n                is_agent_to_agent_messages=True,\n            ),\n        )\n        fipa_dialogue._terms = self.terms\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=fipa_dialogue,\n            performative=FipaMessage.Performative.ACCEPT,\n        )\n\n        # operation\n        with patch.object(self.transactions, \"pop_pending_proposal\") as mock_pending:\n            with patch.object(\n                self.strategy, \"is_profitable_transaction\", return_value=True\n            ):\n                with patch.object(\n                    type(self.strategy),\n                    \"contract_address\",\n                    new_callable=PropertyMock,\n                    return_value=self.contract_address,\n                ):\n                    with patch.object(\n                        type(self.skill.skill_context),\n                        \"public_keys\",\n                        new_callable=PropertyMock,\n                        return_value={\"some_ledger\": \"some_public_key\"},\n                    ):\n                        with patch.object(self.logger, \"log\") as mock_logger:\n                            self.fipa_handler.handle(incoming_message)\n\n        # after\n        self.assert_quantity_in_outbox(0)\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received {incoming_message.performative} from {incoming_message.sender[-5:]} (as {self.fipa_dialogues.get_dialogue(incoming_message).role}), message={incoming_message}\",\n        )\n\n        mock_pending.assert_called_once()\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"Agent has no public key for {self.strategy.ledger_id}.\",\n        )\n\n    def test_handle_accept_v(self):\n        \"\"\"Test the _on_accept method of the fipa handler where the tx IS profitable, is_contract_tx is True, ledger is not FetchAi nor Ethereum.\"\"\"\n        # setup\n        self.strategy._is_contract_tx = True\n        self.strategy._ledger_id = self.ledger_id\n\n        fipa_dialogue = cast(\n            FipaDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.fipa_dialogues,\n                messages=self.list_of_messages_other_initiated[:2],\n                is_agent_to_agent_messages=True,\n            ),\n        )\n        fipa_dialogue._terms = self.terms\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=fipa_dialogue,\n            performative=FipaMessage.Performative.ACCEPT,\n        )\n\n        # operation\n        with patch.object(self.transactions, \"pop_pending_proposal\") as mock_pending:\n            with patch.object(\n                self.strategy, \"is_profitable_transaction\", return_value=True\n            ):\n                with patch.object(self.logger, \"log\") as mock_logger:\n                    with pytest.raises(\n                        AEAEnforceError,\n                        match=f\"Unidentified ledger id: {self.ledger_id}\",\n                    ):\n                        self.fipa_handler.handle(incoming_message)\n\n        # after\n        self.assert_quantity_in_outbox(0)\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received {incoming_message.performative} from {incoming_message.sender[-5:]} (as {self.fipa_dialogues.get_dialogue(incoming_message).role}), message={incoming_message}\",\n        )\n        mock_pending.assert_called_once()\n\n    def test_handle_accept_vi(self):\n        \"\"\"Test the _on_accept method of the fipa handler where the tx is NOT profitable.\"\"\"\n        # setup\n        fipa_dialogue = cast(\n            FipaDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.fipa_dialogues,\n                messages=self.list_of_messages_other_initiated[:2],\n            ),\n        )\n        fipa_dialogue._terms = self.terms\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=fipa_dialogue,\n            performative=FipaMessage.Performative.ACCEPT,\n        )\n\n        # before\n        self._assert_stat_state(self.dialogue_stats)\n\n        # operation\n        with patch.object(\n            self.transactions, \"pop_pending_proposal\", return_value=self.terms\n        ) as mock_pending:\n            with patch.object(\n                self.strategy, \"is_profitable_transaction\", return_value=False\n            ):\n                with patch.object(self.logger, \"log\") as mock_logger:\n                    self.fipa_handler.handle(incoming_message)\n\n        # after\n        self.assert_quantity_in_outbox(1)\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received {incoming_message.performative} from {incoming_message.sender[-5:]} (as {self.fipa_dialogues.get_dialogue(incoming_message).role}), message={incoming_message}\",\n        )\n\n        mock_pending.assert_called_once()\n\n        message = self.get_message_from_outbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=FipaMessage,\n            performative=FipaMessage.Performative.DECLINE,\n            to=incoming_message.sender,\n            sender=self.skill.skill_context.agent_address,\n            target=incoming_message.message_id,\n        )\n        assert has_attributes, error_str\n\n        self._assert_stat_state(\n            self.dialogue_stats, \"other\", FipaDialogue.EndState.DECLINED_ACCEPT\n        )\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"sending {message.performative} to {message.to[-5:]} (as {self.fipa_dialogues.get_dialogue(message).role}), message={message}\",\n        )\n\n    def test_handle_match_accept_i(self):\n        \"\"\"Test the _handle_match_accept method of the fipa handler where is_contract_tx is True and ledger_id is Fetchai.\"\"\"\n        # setup\n        self.strategy._is_contract_tx = True\n        self.strategy._ledger_id = FetchAIApi.identifier\n\n        fipa_dialogue = cast(\n            FipaDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.fipa_dialogues,\n                messages=self.list_of_messages_self_initiated[:3],\n            ),\n        )\n        fipa_dialogue._terms = self.terms\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=fipa_dialogue,\n            performative=FipaMessage.Performative.MATCH_ACCEPT_W_INFORM,\n            info={},\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.fipa_handler.handle(incoming_message)\n\n        # after\n        self.assert_quantity_in_outbox(0)\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received {incoming_message.performative} from {incoming_message.sender[-5:]} (as {self.fipa_dialogues.get_dialogue(incoming_message).role}), message={incoming_message}\",\n        )\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"{incoming_message.performative} did not contain counterparty public_key!\",\n        )\n\n    def test_handle_match_accept_ii(self):\n        \"\"\"Test the _handle_match_accept method of the fipa handler where is_contract_tx is True and ledger_id is Fetchai.\"\"\"\n        # setup\n        self.strategy._is_contract_tx = True\n        self.strategy._ledger_id = FetchAIApi.identifier\n        counterparty_public_key = \"counterparty_public_key\"\n\n        fipa_dialogue = cast(\n            FipaDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.fipa_dialogues,\n                messages=self.list_of_messages_self_initiated[:3],\n            ),\n        )\n        fipa_dialogue._terms = self.terms\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=fipa_dialogue,\n            performative=FipaMessage.Performative.MATCH_ACCEPT_W_INFORM,\n            info={\"public_key\": counterparty_public_key},\n        )\n\n        # operation\n        with patch.object(\n            type(self.strategy),\n            \"contract_address\",\n            new_callable=PropertyMock,\n            return_value=self.contract_address,\n        ):\n            with patch.object(\n                type(self.strategy),\n                \"contract_id\",\n                new_callable=PropertyMock,\n                return_value=self.contract_id,\n            ):\n                with patch.object(\n                    self.strategy, \"kwargs_from_terms\", return_value=self.kwargs\n                ):\n                    with patch.object(self.logger, \"log\") as mock_logger:\n                        self.fipa_handler.handle(incoming_message)\n\n        # after\n        self.assert_quantity_in_outbox(1)\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received {incoming_message.performative} from {incoming_message.sender[-5:]} (as {self.fipa_dialogues.get_dialogue(incoming_message).role}), message={incoming_message}\",\n        )\n\n        message = self.get_message_from_outbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=ContractApiMessage,\n            performative=ContractApiMessage.Performative.GET_RAW_TRANSACTION,\n            to=LEDGER_API_ADDRESS,\n            sender=str(self.skill.skill_context.skill_id),\n            ledger_id=FetchAIApi.identifier,\n            contract_id=self.contract_id,\n            contract_address=self.contract_address,\n            callable=\"get_atomic_swap_batch_transaction\",\n            kwargs=ContractApiMessage.Kwargs(self.kwargs),\n        )\n        assert has_attributes, error_str\n\n        assert (\n            cast(\n                ContractApiDialogue, self.contract_api_dialogues.get_dialogue(message)\n            ).associated_fipa_dialogue\n            == fipa_dialogue\n        )\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"requesting batch atomic swap transaction, sending {message.performative} to {self.contract_id}, message={message}\",\n        )\n\n    def test_handle_match_accept_iii(self):\n        \"\"\"Test the _handle_match_accept method of the fipa handler where is_contract_tx is True and ledger_id is neither Fetchai nor Ethereum.\"\"\"\n        # setup\n        self.strategy._is_contract_tx = True\n        self.strategy._ledger_id = self.ledger_id\n\n        fipa_dialogue = cast(\n            FipaDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.fipa_dialogues,\n                messages=self.list_of_messages_self_initiated[:3],\n            ),\n        )\n        fipa_dialogue._terms = self.terms\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=fipa_dialogue,\n            performative=FipaMessage.Performative.MATCH_ACCEPT_W_INFORM,\n            info={},\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            with pytest.raises(\n                AEAEnforceError, match=f\"Unidentified ledger id: {self.ledger_id}\"\n            ):\n                self.fipa_handler.handle(incoming_message)\n\n        # after\n        self.assert_quantity_in_outbox(0)\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received {incoming_message.performative} from {incoming_message.sender[-5:]} (as {self.fipa_dialogues.get_dialogue(incoming_message).role}), message={incoming_message}\",\n        )\n\n    def test_handle_match_accept_iv(self):\n        \"\"\"Test the _handle_match_accept method of the fipa handler where is_contract_tx is True, ledger_id is Ethereum and counterparty signature is None.\"\"\"\n        # setup\n        self.strategy._is_contract_tx = True\n        self.strategy._ledger_id = EthereumApi.identifier\n\n        fipa_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.fipa_dialogues,\n            messages=self.list_of_messages_self_initiated[:3],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=fipa_dialogue,\n            performative=FipaMessage.Performative.MATCH_ACCEPT_W_INFORM,\n            info={\"signature\": None},\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.fipa_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received {incoming_message.performative} from {incoming_message.sender[-5:]} (as {self.fipa_dialogues.get_dialogue(incoming_message).role}), message={incoming_message}\",\n        )\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"{incoming_message.performative} did not contain counterparty signature!\",\n        )\n\n    def test_handle_match_accept_v(self):\n        \"\"\"Test the _handle_match_accept method of the fipa handler where is_contract_tx is True and counterparty signature is NOT None.\"\"\"\n        # setup\n        self.strategy._is_contract_tx = True\n        self.strategy._ledger_id = EthereumApi.identifier\n\n        fipa_dialogue = cast(\n            FipaDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.fipa_dialogues,\n                messages=self.list_of_messages_self_initiated[:3],\n            ),\n        )\n        fipa_dialogue._terms = self.terms\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=fipa_dialogue,\n            performative=FipaMessage.Performative.MATCH_ACCEPT_W_INFORM,\n            info={\"signature\": self.counterparty_signature},\n        )\n\n        # operation\n        with patch.object(\n            type(self.strategy),\n            \"contract_id\",\n            new_callable=PropertyMock,\n            return_value=self.contract_id,\n        ):\n            with patch.object(\n                type(self.strategy),\n                \"contract_address\",\n                new_callable=PropertyMock,\n                return_value=self.contract_address,\n            ):\n                with patch.object(\n                    self.strategy, \"kwargs_from_terms\", return_value=self.kwargs\n                ):\n                    with patch.object(self.logger, \"log\") as mock_logger:\n                        self.fipa_handler.handle(incoming_message)\n\n        # after\n        self.assert_quantity_in_outbox(1)\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received {incoming_message.performative} from {incoming_message.sender[-5:]} (as {self.fipa_dialogues.get_dialogue(incoming_message).role}), message={incoming_message}\",\n        )\n\n        assert fipa_dialogue.counterparty_signature == self.counterparty_signature\n\n        message = self.get_message_from_outbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=ContractApiMessage,\n            performative=ContractApiMessage.Performative.GET_RAW_TRANSACTION,\n            to=LEDGER_API_ADDRESS,\n            sender=str(self.skill.skill_context.skill_id),\n            ledger_id=EthereumApi.identifier,\n            contract_id=self.contract_id,\n            contract_address=self.contract_address,\n            callable=\"get_atomic_swap_batch_transaction\",\n            kwargs=ContractApiMessage.Kwargs(self.kwargs),\n        )\n        assert has_attributes, error_str\n\n        assert (\n            cast(\n                ContractApiDialogue, self.contract_api_dialogues.get_dialogue(message)\n            ).associated_fipa_dialogue\n            == fipa_dialogue\n        )\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"requesting batch atomic swap transaction, sending {message.performative} to {self.contract_id}, message={message}\",\n        )\n\n    def test_handle_match_accept_vi(self):\n        \"\"\"Test the _handle_match_accept method of the fipa handler where is_contract_tx is False and counterparty signature is NOT None.\"\"\"\n        # setup\n        self.strategy._is_contract_tx = False\n\n        fipa_dialogue = cast(\n            FipaDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.fipa_dialogues,\n                messages=self.list_of_messages_self_initiated[:3],\n            ),\n        )\n        fipa_dialogue._terms = self.terms\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=fipa_dialogue,\n            performative=FipaMessage.Performative.MATCH_ACCEPT_W_INFORM,\n            info={\"signature\": self.counterparty_signature},\n        )\n\n        # operation\n        with patch.object(\n            self.transactions, \"pop_pending_initial_acceptance\", return_value=self.terms\n        ) as mock_pending:\n            with patch.object(self.logger, \"log\") as mock_logger:\n                self.fipa_handler.handle(incoming_message)\n\n        # after\n        self.assert_quantity_in_decision_making_queue(1)\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received {incoming_message.performative} from {incoming_message.sender[-5:]} (as {self.fipa_dialogues.get_dialogue(incoming_message).role}), message={incoming_message}\",\n        )\n\n        mock_pending.assert_called_once()\n\n        assert fipa_dialogue.counterparty_signature == self.counterparty_signature\n\n        message = self.get_message_from_decision_maker_inbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=SigningMessage,\n            performative=SigningMessage.Performative.SIGN_MESSAGE,\n            to=self.skill.skill_context.decision_maker_address,\n            sender=str(self.skill.skill_context.skill_id),\n            terms=self.terms,\n            raw_message=self.raw_message,\n        )\n        assert has_attributes, error_str\n\n        assert (\n            cast(\n                SigningDialogue, self.signing_dialogues.get_dialogue(message)\n            ).associated_fipa_dialogue\n            == fipa_dialogue\n        )\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"requesting signature, sending {message.performative} to decision_maker, message={message}\",\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the fipa handler.\"\"\"\n        assert self.fipa_handler.teardown() is None\n        self.assert_quantity_in_outbox(0)\n\n\nclass TestCosmTradeHandler(BaseSkillTestCase):\n    \"\"\"Test cosm_trade handler of tac negotiation.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"tac_negotiation\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.cosm_trade_handler = cast(\n            CosmTradeHandler, cls._skill.skill_context.handlers.cosm_trade\n        )\n        cls.strategy = cast(Strategy, cls._skill.skill_context.strategy)\n        cls.logger = cls._skill.skill_context.logger\n\n        cls.fipa_dialogues = cast(\n            FipaDialogues, cls._skill.skill_context.fipa_dialogues\n        )\n        cls.cosm_trade_dialogues = cast(\n            CosmTradeDialogues, cls._skill.skill_context.cosm_trade_dialogues\n        )\n        cls.signing_dialogues = cast(\n            SigningDialogues, cls._skill.skill_context.signing_dialogues\n        )\n\n        cls.dialogue_stats = cls.cosm_trade_dialogues.dialogue_stats\n        cls.ledger_id = \"some_ledger_id\"\n        cls.counterprty_address = COUNTERPARTY_AGENT_ADDRESS\n        cls.amount_by_currency_id = {\"1\": 50}\n        cls.quantities_by_good_id = {\"2\": -10}\n        cls.nonce = \"234543\"\n        cls.body = {\"some_key\": \"some_value\"}\n        cls.fipa_dialogue_id = (\"1\", \"1\")\n        cls.terms = Terms(\n            cls.ledger_id,\n            cls._skill.skill_context.agent_address,\n            cls.counterprty_address,\n            cls.amount_by_currency_id,\n            cls.quantities_by_good_id,\n            cls.nonce,\n        )\n        cls.raw_message = RawMessage(\n            ledger_id=cls.ledger_id, body=cls.terms.sender_hash.encode(\"utf-8\")\n        )\n        cls.signed_tx = SignedTransaction(cls.ledger_id, cls.body)\n\n        cls.cfp_query = Query(\n            [Constraint(\"some_attribute\", ConstraintType(\"==\", \"some_service\"))],\n            DataModel(\n                SUPPLY_DATAMODEL_NAME,\n                [\n                    Attribute(\n                        \"some_attribute\", str, False, \"Some attribute descriptions.\"\n                    )\n                ],\n            ),\n        )\n        cls.proposal = Description(\n            {\n                \"ledger_id\": cls.ledger_id,\n                \"price\": 100,\n                \"currency_id\": \"1\",\n                \"fee\": 1,\n                \"nonce\": cls.nonce,\n            }\n        )\n        cls.list_of_fipa_messages = (\n            DialogueMessage(\n                FipaMessage.Performative.CFP, {\"query\": cls.cfp_query}, True\n            ),\n            DialogueMessage(\n                FipaMessage.Performative.PROPOSE, {\"proposal\": cls.proposal}\n            ),\n            DialogueMessage(FipaMessage.Performative.ACCEPT),\n            DialogueMessage(\n                FipaMessage.Performative.MATCH_ACCEPT_W_INFORM,\n                {\"info\": {\"address\": \"some_term_sender_address\"}},\n            ),\n            DialogueMessage(\n                FipaMessage.Performative.INFORM,\n                {\"info\": {\"transaction_digest\": \"some_transaction_digest_body\"}},\n            ),\n        )\n        cls.list_of_cosm_trade_messages = (\n            DialogueMessage(\n                CosmTradeMessage.Performative.INFORM_SIGNED_TRANSACTION,\n                {\"signed_transaction\": cls.signed_tx, \"fipa_dialogue_id\": (\"1\", \"\")},\n            ),\n        )\n\n    @staticmethod\n    def _assert_stat_state(\n        dialogue_stats: DialogueStats,\n        changed_agent: Optional[str] = None,\n        changed_end_state: Optional[CosmTradeDialogue.EndState] = None,\n    ) -> None:\n        \"\"\"\n        Evaluates the state of dialogue stats.\n\n        If 'changed_agent' and 'changed_end_state' are None,\n        it asserts that the dialogue stats are 0 for all end_states.\n\n        If they are not None, it checks that all end_states are 0, except for 'changed_end_state'\n        in dialogues started by 'changed_agent' (i.e. 'self' or 'other').\n\n        :param changed_agent: can either by 'self' or 'other'. Dialogues started by this agent has a none-zero end_state.\n        :param changed_end_state: the changed end_state.\n        :return:\n        \"\"\"\n        if changed_agent is None and changed_end_state is None:\n            unchanged_dict_1 = dialogue_stats.self_initiated\n            unchanged_dict_2 = dialogue_stats.other_initiated\n            for end_state_numbers in unchanged_dict_1.values():\n                assert end_state_numbers == 0\n            for end_state_numbers in unchanged_dict_2.values():\n                assert end_state_numbers == 0\n        elif changed_agent is not None and changed_end_state is not None:\n            if changed_agent == \"self\":\n                changed_dict = dialogue_stats.self_initiated\n                unchanged_dict = dialogue_stats.other_initiated\n            elif changed_agent == \"other\":\n                changed_dict = dialogue_stats.other_initiated\n                unchanged_dict = dialogue_stats.self_initiated\n            else:\n                raise SyntaxError(\n                    f\"changed_agent can only be 'self' or 'other'. Found {changed_agent}.\"\n                )\n\n            for end_state_numbers in unchanged_dict.values():\n                assert end_state_numbers == 0\n            for end_state, end_state_numbers in changed_dict.items():\n                if end_state == changed_end_state:\n                    assert end_state_numbers == 1\n                else:\n                    assert end_state_numbers == 0\n        else:\n            raise SyntaxError(\n                \"changed_agent and changed_end_state should either both be None, or neither.\"\n            )\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the cosm_trade handler.\"\"\"\n        assert self.cosm_trade_handler.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle_unidentified_dialogue(self):\n        \"\"\"Test the _handle_unidentified_dialogue method of the cosm_trade handler.\"\"\"\n        # setup\n        self.strategy._is_contract_tx = True\n        incorrect_dialogue_reference = (\"\", \"\")\n        incoming_message = self.build_incoming_message(\n            message_type=CosmTradeMessage,\n            dialogue_reference=incorrect_dialogue_reference,\n            performative=CosmTradeMessage.Performative.INFORM_PUBLIC_KEY,\n            public_key=\"some_public_key\",\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.cosm_trade_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received invalid cosm_trade message={incoming_message}, unidentified dialogue.\",\n        )\n\n        self.assert_quantity_in_outbox(1)\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=DefaultMessage,\n            performative=DefaultMessage.Performative.ERROR,\n            to=incoming_message.sender,\n            sender=self.skill.skill_context.agent_address,\n            error_code=DefaultMessage.ErrorCode.INVALID_DIALOGUE,\n            error_msg=\"Invalid dialogue.\",\n            error_data={\"cosm_trade_message\": incoming_message.encode()},\n        )\n        assert has_attributes, error_str\n\n    def test_handle_signed_tx_i(self):\n        \"\"\"Test the _on_accept method of the cosm_trade handler.\"\"\"\n        # setup\n        self.strategy._is_contract_tx = True\n        self.strategy._ledger_id = FetchAIApi.identifier\n\n        fipa_dialogue = cast(\n            FipaDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.fipa_dialogues,\n                messages=self.list_of_fipa_messages[:4],\n                is_agent_to_agent_messages=True,\n            ),\n        )\n        fipa_dialogue._terms = self.terms\n        incoming_message = self.build_incoming_message(\n            message_type=CosmTradeMessage,\n            performative=CosmTradeMessage.Performative.INFORM_SIGNED_TRANSACTION,\n            signed_transaction=self.signed_tx,\n            fipa_dialogue_id=fipa_dialogue.dialogue_label.dialogue_reference,\n        )\n\n        raw_tx = RawTransaction(\n            ledger_id=self.signed_tx.ledger_id,\n            body=self.signed_tx.body,\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.cosm_trade_handler.handle(incoming_message)\n\n        # after\n        self.assert_quantity_in_decision_making_queue(1)\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received inform_signed_tx with signed_tx={self.signed_tx}\",\n        )\n\n        message = self.get_message_from_decision_maker_inbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=SigningMessage,\n            performative=SigningMessage.Performative.SIGN_TRANSACTION,\n            to=self.skill.skill_context.decision_maker_address,\n            sender=str(self.skill.skill_context.skill_id),\n            terms=self.terms,\n            raw_transaction=raw_tx,\n        )\n        assert has_attributes, error_str\n\n        assert (\n            cast(\n                SigningDialogue, self.signing_dialogues.get_dialogue(message)\n            ).associated_fipa_dialogue\n            == fipa_dialogue\n        )\n        assert cast(\n            SigningDialogue, self.signing_dialogues.get_dialogue(message)\n        ).associated_cosm_trade_dialogue == self.cosm_trade_dialogues.get_dialogue(\n            incoming_message\n        )\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            \"proposing the transaction to the decision maker. Waiting for confirmation ...\",\n        )\n\n    def test_handle_signed_tx_ii(self):\n        \"\"\"Test the _on_accept method of the cosm_trade handler where fipa_dialogue_id IS None.\"\"\"\n        # setup\n        self.strategy._is_contract_tx = True\n        self.strategy._ledger_id = FetchAIApi.identifier\n\n        fipa_dialogue = cast(\n            FipaDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.fipa_dialogues,\n                messages=self.list_of_fipa_messages[:4],\n                is_agent_to_agent_messages=True,\n            ),\n        )\n        fipa_dialogue._terms = self.terms\n        incoming_message = self.build_incoming_message(\n            message_type=CosmTradeMessage,\n            performative=CosmTradeMessage.Performative.INFORM_SIGNED_TRANSACTION,\n            signed_transaction=self.signed_tx,\n            fipa_dialogue_id=None,\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.cosm_trade_handler.handle(incoming_message)\n\n        # after\n        self.assert_quantity_in_decision_making_queue(0)\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received inform_signed_tx with signed_tx={self.signed_tx}\",\n        )\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            \"inform_signed_tx must contain fipa dialogue reference.\",\n        )\n\n    def test_handle_error(self):\n        \"\"\"Test the _handle_decline method of the cosm_trade handler where the end state is Failed.\"\"\"\n        # setup\n        self.strategy._is_contract_tx = True\n        self.strategy._ledger_id = FetchAIApi.identifier\n        cosm_trade_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.cosm_trade_dialogues,\n            messages=self.list_of_cosm_trade_messages[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=cosm_trade_dialogue,\n            performative=CosmTradeMessage.Performative.ERROR,\n            code=1,\n        )\n\n        # before\n        self._assert_stat_state(self.dialogue_stats)\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.cosm_trade_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received cosm_trade_api error message={incoming_message} in dialogue={cosm_trade_dialogue}.\",\n        )\n\n        self._assert_stat_state(\n            self.dialogue_stats, \"self\", CosmTradeDialogue.EndState.FAILED\n        )\n\n    def test_handle_end(self):\n        \"\"\"Test the _handle_decline method of the cosm_trade handler where the end state is SUCCESS.\"\"\"\n        # setup\n        self.strategy._is_contract_tx = True\n        self.strategy._ledger_id = FetchAIApi.identifier\n        cosm_trade_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.cosm_trade_dialogues,\n            messages=self.list_of_cosm_trade_messages[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=cosm_trade_dialogue,\n            performative=CosmTradeMessage.Performative.END,\n        )\n\n        # before\n        self._assert_stat_state(self.dialogue_stats)\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.cosm_trade_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received cosm_trade_api end message={incoming_message} in dialogue={cosm_trade_dialogue}.\",\n        )\n\n        self._assert_stat_state(\n            self.dialogue_stats, \"self\", CosmTradeDialogue.EndState.SUCCESSFUL\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the cosm_trade handler.\"\"\"\n        assert self.cosm_trade_handler.teardown() is None\n        self.assert_quantity_in_outbox(0)\n\n\nclass TestSigningHandler(BaseSkillTestCase):\n    \"\"\"Test signing handler of tac negotiation.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"tac_negotiation\")\n    is_agent_to_agent_messages = False\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.signing_handler = cast(\n            SigningHandler, cls._skill.skill_context.handlers.signing\n        )\n        cls.strategy = cast(Strategy, cls._skill.skill_context.strategy)\n        cls.logger = cls.signing_handler.context.logger\n\n        cls.signing_dialogues = cast(\n            SigningDialogues, cls._skill.skill_context.signing_dialogues\n        )\n        cls.fipa_dialogues = cast(\n            FipaDialogues, cls._skill.skill_context.fipa_dialogues\n        )\n        cls.cosm_trade_dialogues = cast(\n            CosmTradeDialogues, cls._skill.skill_context.cosm_trade_dialogues\n        )\n        cls.ledger_api_dialogues = cast(\n            LedgerApiDialogues, cls._skill.skill_context.ledger_api_dialogues\n        )\n\n        cls.ledger_id = \"some_ledger_id\"\n        cls.nonce = \"some_nonce\"\n        cls.body = {\"some_key\": \"some_value\"}\n        cls.body_bytes = b\"some_body\"\n        cls.body_str = \"some_body\"\n        cls.counterparty_signature = \"some_counterparty_signature\"\n        cls.terms = Terms(\n            \"some_ledger_id\",\n            cls._skill.skill_context.agent_address,\n            \"counterprty\",\n            {\"currency_id\": 50},\n            {\"good_id\": -10},\n            \"some_nonce\",\n        )\n        cls.list_of_signing_msg_messages = (\n            DialogueMessage(\n                SigningMessage.Performative.SIGN_MESSAGE,\n                {\n                    \"terms\": cls.terms,\n                    \"raw_message\": SigningMessage.RawMessage(\n                        cls.ledger_id, cls.body_bytes\n                    ),\n                },\n            ),\n        )\n        cls.list_of_signing_tx_messages = (\n            DialogueMessage(\n                SigningMessage.Performative.SIGN_TRANSACTION,\n                {\n                    \"terms\": cls.terms,\n                    \"raw_transaction\": SigningMessage.RawTransaction(\n                        cls.ledger_id, cls.body\n                    ),\n                },\n            ),\n        )\n\n        cls.cfp_query = Query(\n            [Constraint(\"some_attribute\", ConstraintType(\"==\", \"some_service\"))],\n            DataModel(\n                SUPPLY_DATAMODEL_NAME,\n                [\n                    Attribute(\n                        \"some_attribute\", str, False, \"Some attribute descriptions.\"\n                    )\n                ],\n            ),\n        )\n        cls.proposal = Description(\n            {\n                \"ledger_id\": cls.ledger_id,\n                \"price\": 100,\n                \"currency_id\": \"1\",\n                \"fee\": 1,\n                \"nonce\": cls.nonce,\n            }\n        )\n        cls.list_of_other_initiated_fipa_messages = (\n            DialogueMessage(\n                FipaMessage.Performative.CFP, {\"query\": cls.cfp_query}, True\n            ),\n            DialogueMessage(\n                FipaMessage.Performative.PROPOSE, {\"proposal\": cls.proposal}\n            ),\n            DialogueMessage(FipaMessage.Performative.ACCEPT),\n            DialogueMessage(\n                FipaMessage.Performative.MATCH_ACCEPT_W_INFORM,\n                {\"info\": {\"address\": \"some_term_sender_address\"}},\n            ),\n            DialogueMessage(\n                FipaMessage.Performative.INFORM,\n                {\"info\": {\"transaction_digest\": \"some_transaction_digest_body\"}},\n            ),\n        )\n        cls.list_of_self_initiated_fipa_messages_ethereum = (\n            DialogueMessage(FipaMessage.Performative.CFP, {\"query\": cls.cfp_query}),\n            DialogueMessage(\n                FipaMessage.Performative.PROPOSE, {\"proposal\": cls.proposal}\n            ),\n            DialogueMessage(FipaMessage.Performative.ACCEPT),\n            DialogueMessage(\n                FipaMessage.Performative.MATCH_ACCEPT_W_INFORM,\n                {\"info\": {\"address\": \"some_term_sender_address\"}},\n            ),\n            DialogueMessage(\n                FipaMessage.Performative.INFORM,\n                {\"info\": {\"transaction_digest\": \"some_transaction_digest_body\"}},\n            ),\n        )\n        cls.list_of_self_initiated_fipa_messages_fetchai = (\n            DialogueMessage(FipaMessage.Performative.CFP, {\"query\": cls.cfp_query}),\n            DialogueMessage(\n                FipaMessage.Performative.PROPOSE, {\"proposal\": cls.proposal}\n            ),\n            DialogueMessage(FipaMessage.Performative.ACCEPT),\n            DialogueMessage(\n                FipaMessage.Performative.MATCH_ACCEPT_W_INFORM,\n                {\"info\": {\"address\": \"some_term_sender_address\"}},\n            ),\n            DialogueMessage(\n                FipaMessage.Performative.INFORM,\n                {\"info\": {\"public_key\": \"some_public_key\"}},\n            ),\n        )\n\n        cls.signed_tx = SignedTransaction(cls.ledger_id, cls.body)\n\n        cls.list_of_cosm_trade_messages = (\n            DialogueMessage(\n                CosmTradeMessage.Performative.INFORM_SIGNED_TRANSACTION,\n                {\"signed_transaction\": cls.signed_tx, \"fipa_dialogue_id\": (\"1\", \"\")},\n            ),\n        )\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the signing handler.\"\"\"\n        assert self.signing_handler.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle_unidentified_dialogue(self):\n        \"\"\"Test the _handle_unidentified_dialogue method of the signing handler.\"\"\"\n        # setup\n        incorrect_dialogue_reference = (\"\", \"\")\n        incoming_message = self.build_incoming_message(\n            message_type=SigningMessage,\n            dialogue_reference=incorrect_dialogue_reference,\n            performative=SigningMessage.Performative.ERROR,\n            error_code=SigningMessage.ErrorCode.UNSUCCESSFUL_MESSAGE_SIGNING,\n            to=str(self.skill.skill_context.skill_id),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.signing_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received invalid signing message={incoming_message}, unidentified dialogue.\",\n        )\n\n    def test_handle_signed_message_i(self):\n        \"\"\"Test the _handle_signed_message method of the signing handler where last fipa message is ACCEPT.\"\"\"\n        # setup\n        fipa_dialogue = cast(\n            FipaDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.fipa_dialogues,\n                messages=self.list_of_other_initiated_fipa_messages[:3],\n                is_agent_to_agent_messages=True,\n            ),\n        )\n\n        signing_dialogue = cast(\n            SigningDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.signing_dialogues,\n                messages=self.list_of_signing_msg_messages[:1],\n                counterparty=self.skill.skill_context.decision_maker_address,\n            ),\n        )\n        signing_dialogue.associated_fipa_dialogue = fipa_dialogue\n\n        incoming_message = cast(\n            SigningMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=signing_dialogue,\n                performative=SigningMessage.Performative.SIGNED_MESSAGE,\n                signed_message=SigningMessage.SignedMessage(\n                    self.ledger_id, self.body_str\n                ),\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.signing_handler.handle(incoming_message)\n\n        # after\n        self.assert_quantity_in_outbox(1)\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received {incoming_message.performative} from decision_maker, message={incoming_message}\",\n        )\n\n        message = self.get_message_from_outbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=FipaMessage,\n            performative=FipaMessage.Performative.MATCH_ACCEPT_W_INFORM,\n            to=fipa_dialogue.dialogue_label.dialogue_opponent_addr,\n            # (line below) match-accept is already added to fipa_dialogue, hence \"-1\"\n            target=fipa_dialogue.last_incoming_message.message_id,\n            sender=self.skill.skill_context.agent_address,\n            info={\"signature\": incoming_message.signed_message.body},\n        )\n        assert has_attributes, error_str\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"sending {message.performative.value} to {message.to[-5:]} (as {fipa_dialogue.role}), message={message}.\",\n        )\n\n    def test_handle_signed_message_ii(self):\n        \"\"\"Test the _handle_signed_message method of the signing handler where last fipa message is MATCH_ACCEPT.\"\"\"\n        # setup\n        mocked_tx = {\n            \"terms\": self.terms,\n            \"sender_signature\": self.body_str,\n            \"counterparty_signature\": self.counterparty_signature,\n        }\n\n        fipa_dialogue = cast(\n            FipaDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.fipa_dialogues,\n                messages=self.list_of_self_initiated_fipa_messages_ethereum[:4],\n                is_agent_to_agent_messages=True,\n            ),\n        )\n        fipa_dialogue.counterparty_signature = self.counterparty_signature\n        fipa_dialogue.terms = self.terms\n\n        signing_dialogue = cast(\n            SigningDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.signing_dialogues,\n                messages=self.list_of_signing_msg_messages[:1],\n                counterparty=self.skill.skill_context.decision_maker_address,\n            ),\n        )\n        signing_dialogue.associated_fipa_dialogue = fipa_dialogue\n\n        incoming_message = cast(\n            SigningMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=signing_dialogue,\n                performative=SigningMessage.Performative.SIGNED_MESSAGE,\n                signed_message=SigningMessage.SignedMessage(\n                    self.ledger_id, self.body_str\n                ),\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.signing_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received {incoming_message.performative} from decision_maker, message={incoming_message}\",\n        )\n\n        assert (\n            self.skill.skill_context.shared_state[\"transactions\"][\n                fipa_dialogue.terms.sender_hash\n            ]\n            == mocked_tx\n        )\n\n        mock_logger.assert_any_call(\n            logging.INFO, f\"sending transaction to controller, tx={mocked_tx}.\"\n        )\n\n    def test_handle_signed_message_iii(self):\n        \"\"\"Test the _handle_signed_message method of the signing handler where last fipa message is neither ACCEPT nor MATCH_ACCEPT.\"\"\"\n        # setup\n        fipa_dialogue = cast(\n            FipaDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.fipa_dialogues,\n                messages=self.list_of_self_initiated_fipa_messages_ethereum[:3],\n                is_agent_to_agent_messages=True,\n            ),\n        )\n\n        signing_dialogue = cast(\n            SigningDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.signing_dialogues,\n                messages=self.list_of_signing_msg_messages[:1],\n                counterparty=self.skill.skill_context.decision_maker_address,\n            ),\n        )\n        signing_dialogue.associated_fipa_dialogue = fipa_dialogue\n\n        incoming_message = cast(\n            SigningMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=signing_dialogue,\n                performative=SigningMessage.Performative.SIGNED_MESSAGE,\n                signed_message=SigningMessage.SignedMessage(\n                    self.ledger_id, self.body_str\n                ),\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            with pytest.raises(\n                AEAEnforceError,\n                match=\"last message should be of performative accept or match accept.\",\n            ):\n                self.signing_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received {incoming_message.performative} from decision_maker, message={incoming_message}\",\n        )\n\n    def test_handle_signed_message_iv(self):\n        \"\"\"Test the _handle_signed_message method of the signing handler where last fipa message is None.\"\"\"\n        # setup\n        fipa_dialogue = cast(\n            FipaDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.fipa_dialogues,\n                messages=self.list_of_self_initiated_fipa_messages_ethereum[:1],\n                is_agent_to_agent_messages=True,\n            ),\n        )\n        fipa_dialogue._incoming_messages = []\n        fipa_dialogue._outgoing_messages = []\n\n        signing_dialogue = cast(\n            SigningDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.signing_dialogues,\n                messages=self.list_of_signing_msg_messages[:1],\n                counterparty=self.skill.skill_context.decision_maker_address,\n            ),\n        )\n        signing_dialogue.associated_fipa_dialogue = fipa_dialogue\n\n        incoming_message = cast(\n            SigningMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=signing_dialogue,\n                performative=SigningMessage.Performative.SIGNED_MESSAGE,\n                signed_message=SigningMessage.SignedMessage(\n                    self.ledger_id, self.body_str\n                ),\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            with pytest.raises(AEAEnforceError, match=\"last message not recovered.\"):\n                self.signing_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received {incoming_message.performative} from decision_maker, message={incoming_message}\",\n        )\n\n    def test_handle_signed_transaction_v(self):\n        \"\"\"Test the _handle_signed_transaction method of the signing handler where is_contract_tx is False.\"\"\"\n        # setup\n        self.strategy._is_contract_tx = False\n\n        signing_dialogue = cast(\n            SigningDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.signing_dialogues,\n                messages=self.list_of_signing_tx_messages[:1],\n                counterparty=self.skill.skill_context.decision_maker_address,\n            ),\n        )\n\n        incoming_message = cast(\n            SigningMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=signing_dialogue,\n                performative=SigningMessage.Performative.SIGNED_TRANSACTION,\n                signed_transaction=self.signed_tx,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.signing_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received {incoming_message.performative} from decision_maker, message={incoming_message}\",\n        )\n\n        mock_logger.assert_any_call(\n            logging.WARNING, \"signed transaction handler only for contract case.\"\n        )\n\n    def test_handle_signed_transaction_vi(self):\n        \"\"\"Test the _handle_signed_transaction method of the signing handler where is_contract_tx is True, associated cosm_trade dialogue is NOT None.\"\"\"\n        # setup\n        self.strategy._is_contract_tx = True\n\n        cosm_trade_dialogue = cast(\n            CosmTradeDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.cosm_trade_dialogues,\n                messages=self.list_of_cosm_trade_messages,\n                is_agent_to_agent_messages=True,\n            ),\n        )\n\n        signing_dialogue = cast(\n            SigningDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.signing_dialogues,\n                messages=self.list_of_signing_tx_messages[:1],\n                counterparty=self.skill.skill_context.decision_maker_address,\n            ),\n        )\n        signing_dialogue.associated_cosm_trade_dialogue = cosm_trade_dialogue\n\n        incoming_message = cast(\n            SigningMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=signing_dialogue,\n                performative=SigningMessage.Performative.SIGNED_TRANSACTION,\n                signed_transaction=self.signed_tx,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.signing_handler.handle(incoming_message)\n\n        # after\n        self.assert_quantity_in_outbox(1)\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received {incoming_message.performative} from decision_maker, message={incoming_message}\",\n        )\n\n        message = self.get_message_from_outbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=LedgerApiMessage,\n            performative=LedgerApiMessage.Performative.SEND_SIGNED_TRANSACTION,\n            to=LEDGER_API_ADDRESS,\n            sender=str(self.skill.skill_context.skill_id),\n            signed_transaction=incoming_message.signed_transaction,\n        )\n        assert has_attributes, error_str\n\n        assert (\n            cast(\n                LedgerApiDialogue, self.ledger_api_dialogues.get_dialogue(message)\n            ).associated_signing_dialogue\n            == signing_dialogue\n        )\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"sending {message.performative} to ledger {self.strategy.ledger_id}, message={message}\",\n        )\n\n    def test_handle_signed_transaction_i(self):\n        \"\"\"Test the _handle_signed_transaction method of the signing handler where is_contract_tx is True and last fipa message is ACCEPT.\"\"\"\n        # setup\n        self.strategy._is_contract_tx = True\n\n        fipa_dialogue = cast(\n            FipaDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.fipa_dialogues,\n                messages=self.list_of_other_initiated_fipa_messages[:3],\n                is_agent_to_agent_messages=True,\n            ),\n        )\n\n        signing_dialogue = cast(\n            SigningDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.signing_dialogues,\n                messages=self.list_of_signing_tx_messages[:1],\n                counterparty=self.skill.skill_context.decision_maker_address,\n            ),\n        )\n        signing_dialogue.associated_fipa_dialogue = fipa_dialogue\n\n        incoming_message = cast(\n            SigningMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=signing_dialogue,\n                performative=SigningMessage.Performative.SIGNED_TRANSACTION,\n                signed_transaction=self.signed_tx,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.signing_handler.handle(incoming_message)\n\n        # after\n        self.assert_quantity_in_outbox(1)\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received {incoming_message.performative} from decision_maker, message={incoming_message}\",\n        )\n\n        message = self.get_message_from_outbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=FipaMessage,\n            performative=FipaMessage.Performative.MATCH_ACCEPT_W_INFORM,\n            to=fipa_dialogue.dialogue_label.dialogue_opponent_addr,\n            # (line below) match-accept is already added to fipa_dialogue, hence \"-1\"\n            sender=self.skill.skill_context.agent_address,\n            info={\"tx_signature\": incoming_message.signed_transaction},\n        )\n        assert has_attributes, error_str\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"sending {message.performative.value} to {message.to[-5:]} (as {fipa_dialogue.role}), message={message}.\",\n        )\n\n    def test_handle_signed_transaction_ii(self):\n        \"\"\"Test the _handle_signed_transaction method of the signing handler where is_contract_tx is True and last fipa message is MATCH_ACCEPT and ledger is Ethereum.\"\"\"\n        # setup\n        self.strategy._is_contract_tx = True\n        self.strategy._ledger_id = EthereumApi.identifier\n\n        fipa_dialogue = cast(\n            FipaDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.fipa_dialogues,\n                messages=self.list_of_self_initiated_fipa_messages_ethereum[:4],\n                is_agent_to_agent_messages=True,\n            ),\n        )\n\n        signing_dialogue = cast(\n            SigningDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.signing_dialogues,\n                messages=self.list_of_signing_tx_messages[:1],\n                counterparty=self.skill.skill_context.decision_maker_address,\n            ),\n        )\n        signing_dialogue.associated_fipa_dialogue = fipa_dialogue\n\n        incoming_message = cast(\n            SigningMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=signing_dialogue,\n                performative=SigningMessage.Performative.SIGNED_TRANSACTION,\n                signed_transaction=self.signed_tx,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.signing_handler.handle(incoming_message)\n\n        # after\n        self.assert_quantity_in_outbox(1)\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received {incoming_message.performative} from decision_maker, message={incoming_message}\",\n        )\n\n        message = self.get_message_from_outbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=LedgerApiMessage,\n            performative=LedgerApiMessage.Performative.SEND_SIGNED_TRANSACTION,\n            to=LEDGER_API_ADDRESS,\n            sender=str(self.skill.skill_context.skill_id),\n            signed_transaction=incoming_message.signed_transaction,\n        )\n        assert has_attributes, error_str\n\n        assert (\n            cast(\n                LedgerApiDialogue, self.ledger_api_dialogues.get_dialogue(message)\n            ).associated_signing_dialogue\n            == signing_dialogue\n        )\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"sending {message.performative} to ledger {self.strategy.ledger_id}, message={message}\",\n        )\n\n    def test_handle_signed_transaction_vii(self):\n        \"\"\"Test the _handle_signed_transaction method of the signing handler where is_contract_tx is True and last fipa message is MATCH_ACCEPT and ledger is Fetchai.\"\"\"\n        # setup\n        self.strategy._is_contract_tx = True\n        self.strategy._ledger_id = FetchAIApi.identifier\n\n        fipa_dialogue = cast(\n            FipaDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.fipa_dialogues,\n                messages=self.list_of_self_initiated_fipa_messages_fetchai[:4],\n                is_agent_to_agent_messages=True,\n            ),\n        )\n\n        signing_dialogue = cast(\n            SigningDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.signing_dialogues,\n                messages=self.list_of_signing_tx_messages[:1],\n                counterparty=self.skill.skill_context.decision_maker_address,\n            ),\n        )\n        signing_dialogue.associated_fipa_dialogue = fipa_dialogue\n\n        incoming_message = cast(\n            SigningMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=signing_dialogue,\n                performative=SigningMessage.Performative.SIGNED_TRANSACTION,\n                signed_transaction=self.signed_tx,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.signing_handler.handle(incoming_message)\n\n        # after\n        self.assert_quantity_in_outbox(1)\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received {incoming_message.performative} from decision_maker, message={incoming_message}\",\n        )\n\n        message = self.get_message_from_outbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=CosmTradeMessage,\n            performative=CosmTradeMessage.Performative.INFORM_SIGNED_TRANSACTION,\n            to=fipa_dialogue.dialogue_label.dialogue_opponent_addr,\n            sender=self.skill.skill_context.agent_address,\n            signed_transaction=incoming_message.signed_transaction,\n            fipa_dialogue_id=fipa_dialogue.dialogue_label.dialogue_reference,\n        )\n        assert has_attributes, error_str\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"sending {message.performative.value} to {message.to[-5:]}, message={message}.\",\n        )\n\n    def test_handle_signed_transaction_viii(self):\n        \"\"\"Test the _handle_signed_transaction method of the signing handler where is_contract_tx is True and last fipa message is MATCH_ACCEPT and ledger is neither Ethereum nor Fetchai.\"\"\"\n        # setup\n        self.strategy._is_contract_tx = True\n        self.strategy._ledger_id = self.ledger_id\n\n        fipa_dialogue = cast(\n            FipaDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.fipa_dialogues,\n                messages=self.list_of_self_initiated_fipa_messages_fetchai[:4],\n                is_agent_to_agent_messages=True,\n            ),\n        )\n\n        signing_dialogue = cast(\n            SigningDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.signing_dialogues,\n                messages=self.list_of_signing_tx_messages[:1],\n                counterparty=self.skill.skill_context.decision_maker_address,\n            ),\n        )\n        signing_dialogue.associated_fipa_dialogue = fipa_dialogue\n\n        incoming_message = cast(\n            SigningMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=signing_dialogue,\n                performative=SigningMessage.Performative.SIGNED_TRANSACTION,\n                signed_transaction=self.signed_tx,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            with pytest.raises(\n                AEAEnforceError,\n                match=f\"Unidentified ledger id: {self.ledger_id}\",\n            ):\n                self.signing_handler.handle(incoming_message)\n\n        # after\n        self.assert_quantity_in_outbox(0)\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received {incoming_message.performative} from decision_maker, message={incoming_message}\",\n        )\n\n    def test_handle_signed_transaction_iii(self):\n        \"\"\"Test the _handle_signed_transaction method of the signing handler where is_contract_tx is True and last fipa message is neither ACCEPT nor MATCH_ACCEPT.\"\"\"\n        # setup\n        self.strategy._is_contract_tx = True\n\n        fipa_dialogue = cast(\n            FipaDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.fipa_dialogues,\n                messages=self.list_of_self_initiated_fipa_messages_ethereum[:3],\n                is_agent_to_agent_messages=True,\n            ),\n        )\n\n        signing_dialogue = cast(\n            SigningDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.signing_dialogues,\n                messages=self.list_of_signing_tx_messages[:1],\n                counterparty=self.skill.skill_context.decision_maker_address,\n            ),\n        )\n        signing_dialogue.associated_fipa_dialogue = fipa_dialogue\n\n        incoming_message = cast(\n            SigningMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=signing_dialogue,\n                performative=SigningMessage.Performative.SIGNED_TRANSACTION,\n                signed_transaction=self.signed_tx,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            with pytest.raises(\n                AEAEnforceError,\n                match=\"last message should be of performative accept or match accept.\",\n            ):\n                self.signing_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received {incoming_message.performative} from decision_maker, message={incoming_message}\",\n        )\n\n    def test_handle_signed_transaction_iv(self):\n        \"\"\"Test the _handle_signed_transaction method of the signing handler where is_contract_tx is True and last incoming fipa message is None.\"\"\"\n        # setup\n        self.strategy._is_contract_tx = True\n\n        fipa_dialogue = cast(\n            FipaDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.fipa_dialogues,\n                messages=self.list_of_self_initiated_fipa_messages_ethereum[:3],\n                is_agent_to_agent_messages=True,\n            ),\n        )\n        fipa_dialogue._incoming_messages = []\n        fipa_dialogue._outgoing_messages = []\n\n        signing_dialogue = cast(\n            SigningDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.signing_dialogues,\n                messages=self.list_of_signing_tx_messages[:1],\n                counterparty=self.skill.skill_context.decision_maker_address,\n            ),\n        )\n        signing_dialogue.associated_fipa_dialogue = fipa_dialogue\n\n        incoming_message = cast(\n            SigningMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=signing_dialogue,\n                performative=SigningMessage.Performative.SIGNED_TRANSACTION,\n                signed_transaction=self.signed_tx,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            with pytest.raises(AEAEnforceError, match=\"last message not recovered.\"):\n                self.signing_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received {incoming_message.performative} from decision_maker, message={incoming_message}\",\n        )\n\n    def test_handle_error(self):\n        \"\"\"Test the _handle_error method of the signing handler.\"\"\"\n        # setup\n        signing_counterparty = self.skill.skill_context.decision_maker_address\n        signing_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.signing_dialogues,\n            messages=self.list_of_signing_tx_messages[:1],\n            counterparty=signing_counterparty,\n        )\n        incoming_message = cast(\n            SigningMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=signing_dialogue,\n                performative=SigningMessage.Performative.ERROR,\n                error_code=SigningMessage.ErrorCode.UNSUCCESSFUL_TRANSACTION_SIGNING,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.signing_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received {incoming_message.performative} from decision_maker, message={incoming_message}\",\n        )\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"transaction signing was not successful. Error_code={incoming_message.error_code} in dialogue={signing_dialogue}\",\n        )\n\n    def test_handle_invalid(self):\n        \"\"\"Test the _handle_invalid method of the signing handler.\"\"\"\n        # setup\n        invalid_performative = SigningMessage.Performative.SIGN_TRANSACTION\n        incoming_message = self.build_incoming_message(\n            message_type=SigningMessage,\n            dialogue_reference=(\"1\", \"\"),\n            performative=invalid_performative,\n            terms=self.terms,\n            raw_transaction=SigningMessage.RawTransaction(\n                \"some_ledger_id\", {\"some_key\": \"some_value\"}\n            ),\n            to=str(self.skill.skill_context.skill_id),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.signing_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received {incoming_message.performative} from decision_maker, message={incoming_message}\",\n        )\n\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"cannot handle signing message of performative={invalid_performative} in dialogue={self.signing_dialogues.get_dialogue(incoming_message)}.\",\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the signing handler.\"\"\"\n        assert self.signing_handler.teardown() is None\n        self.assert_quantity_in_outbox(0)\n\n\nclass TestLedgerApiHandler(BaseSkillTestCase):\n    \"\"\"Test ledger_api handler of tac negotiation.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"tac_negotiation\")\n    is_agent_to_agent_messages = False\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.ledger_api_handler = cast(\n            LedgerApiHandler, cls._skill.skill_context.handlers.ledger_api\n        )\n        cls.logger = cls.ledger_api_handler.context.logger\n\n        cls.ledger_api_dialogues = cast(\n            LedgerApiDialogues, cls._skill.skill_context.ledger_api_dialogues\n        )\n\n        cls.ledger_id = \"some_ledger_id\"\n        cls.contract_id = \"some_contract_id\"\n        cls.callable = \"some_callable\"\n        cls.kwargs = Kwargs({\"some_key\": \"some_value\"})\n\n        cls.body = {\"some_key\": \"some_value\"}\n        cls.body_str = \"some_body\"\n        cls.contract_address = \"some_contract_address\"\n\n        cls.raw_transaction = RawTransaction(cls.ledger_id, cls.body)\n        cls.signed_transaction = SignedTransaction(cls.ledger_id, cls.body)\n        cls.transaction_digest = TransactionDigest(cls.ledger_id, cls.body_str)\n        cls.receipt = {\"contractAddress\": cls.contract_address}\n        cls.transaction_receipt = TransactionReceipt(\n            cls.ledger_id, cls.receipt, {\"transaction_key\": \"transaction_value\"}\n        )\n        cls.address = \"some_address\"\n\n        cls.terms = Terms(\n            cls.ledger_id,\n            cls._skill.skill_context.agent_address,\n            \"counterparty\",\n            {\"currency_id\": 50},\n            {\"good_id\": -10},\n            \"some_nonce\",\n        )\n\n        cls.list_of_ledger_api_messages = (\n            DialogueMessage(\n                LedgerApiMessage.Performative.GET_RAW_TRANSACTION, {\"terms\": cls.terms}\n            ),\n            DialogueMessage(\n                LedgerApiMessage.Performative.RAW_TRANSACTION,\n                {\"raw_transaction\": cls.raw_transaction},\n            ),\n            DialogueMessage(\n                LedgerApiMessage.Performative.SEND_SIGNED_TRANSACTION,\n                {\"signed_transaction\": cls.signed_transaction},\n            ),\n            DialogueMessage(\n                LedgerApiMessage.Performative.TRANSACTION_DIGEST,\n                {\"transaction_digest\": cls.transaction_digest},\n            ),\n            DialogueMessage(\n                LedgerApiMessage.Performative.GET_TRANSACTION_RECEIPT,\n                {\"transaction_digest\": cls.transaction_digest},\n            ),\n        )\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the ledger_api handler.\"\"\"\n        assert self.ledger_api_handler.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle_unidentified_dialogue(self):\n        \"\"\"Test the _handle_unidentified_dialogue method of the ledger_api handler.\"\"\"\n        # setup\n        incorrect_dialogue_reference = (\"\", \"\")\n        incoming_message = self.build_incoming_message(\n            message_type=LedgerApiMessage,\n            dialogue_reference=incorrect_dialogue_reference,\n            performative=LedgerApiMessage.Performative.BALANCE,\n            ledger_id=\"some_ledger_id\",\n            balance=10,\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received invalid ledger_api message={incoming_message}, unidentified dialogue.\",\n        )\n\n    def test_handle_balance(self):\n        \"\"\"Test the _handle_balance method of the ledger_api handler.\"\"\"\n        # setup\n        balance = 10\n        ledger_api_dialogue = cast(\n            LedgerApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.ledger_api_dialogues,\n                messages=(\n                    DialogueMessage(\n                        LedgerApiMessage.Performative.GET_BALANCE,\n                        {\"ledger_id\": self.ledger_id, \"address\": self.address},\n                    ),\n                ),\n                counterparty=LEDGER_API_ADDRESS,\n            ),\n        )\n        incoming_message = cast(\n            LedgerApiMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=ledger_api_dialogue,\n                performative=LedgerApiMessage.Performative.BALANCE,\n                ledger_id=self.ledger_id,\n                balance=balance,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"starting balance on {self.ledger_id} ledger={incoming_message.balance}.\",\n        )\n\n    def test_handle_transaction_digest(self):\n        \"\"\"Test the _handle_transaction_digest method of the ledger_api handler.\"\"\"\n        # setup\n        ledger_api_dialogue = cast(\n            LedgerApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.ledger_api_dialogues,\n                messages=self.list_of_ledger_api_messages[:3],\n                counterparty=LEDGER_API_ADDRESS,\n            ),\n        )\n        incoming_message = cast(\n            LedgerApiMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=ledger_api_dialogue,\n                performative=LedgerApiMessage.Performative.TRANSACTION_DIGEST,\n                transaction_digest=self.transaction_digest,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"transaction was successfully submitted. Transaction digest={incoming_message.transaction_digest}\",\n        )\n\n        self.assert_quantity_in_outbox(1)\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=LedgerApiMessage,\n            performative=LedgerApiMessage.Performative.GET_TRANSACTION_RECEIPT,\n            target=incoming_message.message_id,\n            to=LEDGER_API_ADDRESS,\n            sender=str(self.skill.skill_context.skill_id),\n            transaction_digest=incoming_message.transaction_digest,\n        )\n        assert has_attributes, error_str\n\n        mock_logger.assert_any_call(logging.INFO, \"requesting transaction receipt.\")\n\n    def test_handle_transaction_receipt_failed(self):\n        \"\"\"Test the _handle_transaction_receipt method of the ledger_api handler where the transaction is NOT settled.\"\"\"\n        # setup\n        ledger_api_dialogue = cast(\n            LedgerApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.ledger_api_dialogues,\n                messages=self.list_of_ledger_api_messages[:5],\n                counterparty=LEDGER_API_ADDRESS,\n            ),\n        )\n        incoming_message = cast(\n            LedgerApiMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=ledger_api_dialogue,\n                performative=LedgerApiMessage.Performative.TRANSACTION_RECEIPT,\n                transaction_receipt=self.transaction_receipt,\n            ),\n        )\n\n        # operation\n        with patch.object(LedgerApis, \"is_transaction_settled\", return_value=False):\n            with patch.object(self.logger, \"log\") as mock_logger:\n                self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.ERROR,\n            f\"transaction failed. Transaction receipt={incoming_message.transaction_receipt}\",\n        )\n\n    def test_handle_transaction_receipt_succeeds(self):\n        \"\"\"Test the _handle_transaction_receipt method of the ledger_api handler where the transaction is NOT settled.\"\"\"\n        # setup\n        ledger_api_dialogue = cast(\n            LedgerApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.ledger_api_dialogues,\n                messages=self.list_of_ledger_api_messages[:5],\n                counterparty=LEDGER_API_ADDRESS,\n            ),\n        )\n        incoming_message = cast(\n            LedgerApiMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=ledger_api_dialogue,\n                performative=LedgerApiMessage.Performative.TRANSACTION_RECEIPT,\n                transaction_receipt=self.transaction_receipt,\n            ),\n        )\n\n        # operation\n        with patch.object(LedgerApis, \"is_transaction_settled\", return_value=True):\n            with patch.object(self.logger, \"log\") as mock_logger:\n                self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"transaction was successfully settled. Transaction receipt={incoming_message.transaction_receipt}\",\n        )\n\n    def test_handle_error(self):\n        \"\"\"Test the _handle_error method of the ledger_api handler.\"\"\"\n        # setup\n        ledger_api_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.ledger_api_dialogues,\n            messages=self.list_of_ledger_api_messages[:1],\n        )\n        incoming_message = cast(\n            LedgerApiMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=ledger_api_dialogue,\n                performative=LedgerApiMessage.Performative.ERROR,\n                code=1,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received ledger_api error message={incoming_message} in dialogue={ledger_api_dialogue}.\",\n        )\n\n    def test_handle_invalid(self):\n        \"\"\"Test the _handle_invalid method of the ledger_api handler.\"\"\"\n        # setup\n        invalid_performative = LedgerApiMessage.Performative.GET_BALANCE\n        incoming_message = self.build_incoming_message(\n            message_type=LedgerApiMessage,\n            dialogue_reference=(\"1\", \"\"),\n            performative=invalid_performative,\n            ledger_id=\"some_ledger_id\",\n            address=self.address,\n            to=str(self.skill.skill_context.skill_id),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"cannot handle ledger_api message of performative={invalid_performative} in dialogue={self.ledger_api_dialogues.get_dialogue(incoming_message)}.\",\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the ledger_api handler.\"\"\"\n        assert self.ledger_api_handler.teardown() is None\n        self.assert_quantity_in_outbox(0)\n\n\nclass TestOefSearchHandler(BaseSkillTestCase):\n    \"\"\"Test oef search handler of tac negotiation.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"tac_negotiation\")\n    is_agent_to_agent_messages = False\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.oef_search_handler = cast(\n            OefSearchHandler, cls._skill.skill_context.handlers.oef\n        )\n        cls.strategy = cast(Strategy, cls._skill.skill_context.strategy)\n        cls.logger = cls._skill.skill_context.logger\n        cls.service_registration_behaviour = cast(\n            GoodsRegisterAndSearchBehaviour,\n            cls._skill.skill_context.behaviours.tac_negotiation,\n        )\n\n        cls.oef_dialogues = cast(\n            OefSearchDialogues, cls._skill.skill_context.oef_search_dialogues\n        )\n        cls.fipa_dialogues = cast(\n            FipaDialogues, cls._skill.skill_context.fipa_dialogues\n        )\n\n        cls.controller_address = \"some_controller_address\"\n        cls.self_address = cls._skill.skill_context.agent_address\n        cls.found_agent_address_1 = \"some_agent_address_1\"\n        cls.found_agent_address_2 = \"some_agent_address_2\"\n        cls.found_agent_address_3 = \"some_agent_address_3\"\n        cls.found_agents = [\n            cls.self_address,\n            cls.found_agent_address_1,\n            cls.found_agent_address_2,\n            cls.found_agent_address_3,\n        ]\n        cls.found_agents_less_self = [\n            cls.found_agent_address_1,\n            cls.found_agent_address_2,\n            cls.found_agent_address_3,\n        ]\n        cls.cfp_query = Query(\n            [Constraint(\"some_attribute\", ConstraintType(\"==\", \"some_service\"))],\n            DataModel(\n                SUPPLY_DATAMODEL_NAME,\n                [\n                    Attribute(\n                        \"some_attribute\", str, False, \"Some attribute descriptions.\"\n                    )\n                ],\n            ),\n        )\n\n        cls.list_of_messages = (\n            DialogueMessage(\n                OefSearchMessage.Performative.SEARCH_SERVICES, {\"query\": \"some_query\"}\n            ),\n        )\n\n        cls.register_location_description = Description(\n            {\"location\": Location(51.5194, 0.1270)},\n            data_model=DataModel(\n                \"location_agent\", [Attribute(\"location\", Location, True)]\n            ),\n        )\n        cls.list_of_messages_register_location = (\n            DialogueMessage(\n                OefSearchMessage.Performative.REGISTER_SERVICE,\n                {\"service_description\": cls.register_location_description},\n                is_incoming=False,\n            ),\n        )\n\n        cls.register_service_description = Description(\n            {\"key\": \"some_key\", \"value\": \"some_value\"},\n            data_model=DataModel(\n                \"set_service_key\",\n                [Attribute(\"key\", str, True), Attribute(\"value\", str, True)],\n            ),\n        )\n        cls.list_of_messages_register_service = (\n            DialogueMessage(\n                OefSearchMessage.Performative.REGISTER_SERVICE,\n                {\"service_description\": cls.register_service_description},\n                is_incoming=False,\n            ),\n        )\n\n        cls.register_genus_description = Description(\n            {\"piece\": \"genus\", \"value\": \"some_value\"},\n            data_model=DataModel(\n                \"personality_agent\",\n                [Attribute(\"piece\", str, True), Attribute(\"value\", str, True)],\n            ),\n        )\n        cls.list_of_messages_register_genus = (\n            DialogueMessage(\n                OefSearchMessage.Performative.REGISTER_SERVICE,\n                {\"service_description\": cls.register_genus_description},\n                is_incoming=False,\n            ),\n        )\n\n        cls.register_classification_description = Description(\n            {\"piece\": \"classification\", \"value\": \"some_value\"},\n            data_model=DataModel(\n                \"personality_agent\",\n                [Attribute(\"piece\", str, True), Attribute(\"value\", str, True)],\n            ),\n        )\n        cls.list_of_messages_register_classification = (\n            DialogueMessage(\n                OefSearchMessage.Performative.REGISTER_SERVICE,\n                {\"service_description\": cls.register_classification_description},\n                is_incoming=False,\n            ),\n        )\n\n        cls.register_invalid_description = Description(\n            {\"piece\": \"classification\", \"value\": \"some_value\"},\n            data_model=DataModel(\n                \"some_different_name\",\n                [Attribute(\"piece\", str, True), Attribute(\"value\", str, True)],\n            ),\n        )\n        cls.list_of_messages_register_invalid = (\n            DialogueMessage(\n                OefSearchMessage.Performative.REGISTER_SERVICE,\n                {\"service_description\": cls.register_invalid_description},\n                is_incoming=False,\n            ),\n        )\n\n        cls.unregister_description = Description(\n            {\"key\": \"seller_service\"},\n            data_model=DataModel(\"remove\", [Attribute(\"key\", str, True)]),\n        )\n        cls.list_of_messages_unregister = (\n            DialogueMessage(\n                OefSearchMessage.Performative.UNREGISTER_SERVICE,\n                {\"service_description\": cls.unregister_description},\n                is_incoming=False,\n            ),\n        )\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the oef handler.\"\"\"\n        assert self.oef_search_handler.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle_unidentified_dialogue(self):\n        \"\"\"Test the _handle_unidentified_dialogue method of the oef handler.\"\"\"\n        # setup\n        incorrect_dialogue_reference = (\"\", \"\")\n        incoming_message = self.build_incoming_message(\n            message_type=OefSearchMessage,\n            dialogue_reference=incorrect_dialogue_reference,\n            performative=OefSearchMessage.Performative.SEARCH_RESULT,\n            to=str(self.skill.skill_context.skill_id),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"received invalid oef_search message={incoming_message}, unidentified dialogue.\",\n        )\n\n    def test_handle_success_i(self):\n        \"\"\"Test the _handle_success method of the oef_search handler where the oef success targets register_service WITH location_agent data model description.\"\"\"\n        # setup\n        oef_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_dialogues,\n            messages=self.list_of_messages_register_location[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=oef_dialogue,\n            performative=OefSearchMessage.Performative.SUCCESS,\n            agents_info=OefSearchMessage.AgentsInfo({\"address\": {\"key\": \"value\"}}),\n        )\n\n        # before\n        assert self.service_registration_behaviour.is_registered is False\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            with patch.object(\n                self.service_registration_behaviour,\n                \"register_service\",\n            ) as mock_reg:\n                self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received oef_search success message={incoming_message} in dialogue={oef_dialogue}.\",\n        )\n        mock_reg.assert_called_once()\n        assert self.service_registration_behaviour.is_registered is False\n\n    def test_handle_success_ii(self):\n        \"\"\"Test the _handle_success method of the oef_search handler where the oef success targets register_service WITH set_service_key data model description.\"\"\"\n        # setup\n        oef_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_dialogues,\n            messages=self.list_of_messages_register_service[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=oef_dialogue,\n            performative=OefSearchMessage.Performative.SUCCESS,\n            agents_info=OefSearchMessage.AgentsInfo({\"address\": {\"key\": \"value\"}}),\n        )\n\n        # before\n        assert self.service_registration_behaviour.is_registered is False\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            with patch.object(\n                self.service_registration_behaviour,\n                \"register_genus\",\n            ) as mock_reg:\n                self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received oef_search success message={incoming_message} in dialogue={oef_dialogue}.\",\n        )\n        mock_reg.assert_called_once()\n        assert self.service_registration_behaviour.is_registered is False\n\n    def test_handle_success_iii(self):\n        \"\"\"Test the _handle_success method of the oef_search handler where the oef success targets register_service WITH personality_agent data model and genus value description.\"\"\"\n        # setup\n        oef_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_dialogues,\n            messages=self.list_of_messages_register_genus[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=oef_dialogue,\n            performative=OefSearchMessage.Performative.SUCCESS,\n            agents_info=OefSearchMessage.AgentsInfo({\"address\": {\"key\": \"value\"}}),\n        )\n\n        # before\n        assert self.service_registration_behaviour.is_registered is False\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            with patch.object(\n                self.service_registration_behaviour,\n                \"register_classification\",\n            ) as mock_reg:\n                self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received oef_search success message={incoming_message} in dialogue={oef_dialogue}.\",\n        )\n        mock_reg.assert_called_once()\n        assert self.service_registration_behaviour.is_registered is False\n\n    def test_handle_success_iv(self):\n        \"\"\"Test the _handle_success method of the oef_search handler where the oef success targets register_service WITH personality_agent data model and classification value description.\"\"\"\n        # setup\n        oef_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_dialogues,\n            messages=self.list_of_messages_register_classification[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=oef_dialogue,\n            performative=OefSearchMessage.Performative.SUCCESS,\n            agents_info=OefSearchMessage.AgentsInfo({\"address\": {\"key\": \"value\"}}),\n        )\n\n        # before\n        assert self.service_registration_behaviour.is_registered is False\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received oef_search success message={incoming_message} in dialogue={oef_dialogue}.\",\n        )\n        mock_logger.assert_any_call(\n            logging.INFO,\n            \"the agent, with its genus and classification, and its service are successfully registered on the SOEF.\",\n        )\n        assert self.service_registration_behaviour.is_registered is True\n\n    def test_handle_success_v(self):\n        \"\"\"Test the _handle_success method of the oef_search handler where the oef successtargets unregister_service.\"\"\"\n        # setup\n        oef_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_dialogues,\n            messages=self.list_of_messages_register_invalid[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=oef_dialogue,\n            performative=OefSearchMessage.Performative.SUCCESS,\n            agents_info=OefSearchMessage.AgentsInfo({\"address\": {\"key\": \"value\"}}),\n        )\n\n        # before\n        assert self.service_registration_behaviour.is_registered is False\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received oef_search success message={incoming_message} in dialogue={oef_dialogue}.\",\n        )\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"received soef SUCCESS message as a reply to the following unexpected message: {oef_dialogue.get_message_by_id(incoming_message.target)}\",\n        )\n        assert self.service_registration_behaviour.is_registered is False\n\n    def test_on_oef_error_i(self):\n        \"\"\"Test the _handle_error method of the oef_search handler where the oef error targets register_service.\"\"\"\n        # setup\n        oef_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_dialogues,\n            messages=self.list_of_messages_register_location[:1],\n        )\n        incoming_message = cast(\n            OefSearchMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=oef_dialogue,\n                performative=OefSearchMessage.Performative.OEF_ERROR,\n                oef_error_operation=OefSearchMessage.OefErrorOperation.SEARCH_SERVICES,\n            ),\n        )\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        self.assert_quantity_in_outbox(0)\n\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"received OEF Search error: dialogue_reference={oef_dialogue.dialogue_label.dialogue_reference}, oef_error_operation={incoming_message.oef_error_operation}\",\n        )\n        assert (\n            self.service_registration_behaviour.failed_registration_msg\n            == oef_dialogue.get_message_by_id(incoming_message.target)\n        )\n\n    def test_on_oef_error_ii(self):\n        \"\"\"Test the _handle_error method of the oef_search handler where the oef error does NOT target register_service.\"\"\"\n        # setup\n        oef_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_dialogues,\n            messages=self.list_of_messages_unregister[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=oef_dialogue,\n            performative=OefSearchMessage.Performative.OEF_ERROR,\n            oef_error_operation=OefSearchMessage.OefErrorOperation.SEARCH_SERVICES,\n        )\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        self.assert_quantity_in_outbox(0)\n\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"received OEF Search error: dialogue_reference={oef_dialogue.dialogue_label.dialogue_reference}, oef_error_operation={incoming_message.oef_error_operation}\",\n        )\n\n        assert self.service_registration_behaviour.failed_registration_msg is None\n\n    def test_on_search_result_i(self):\n        \"\"\"Test the _on_search_result method of the oef handler.\"\"\"\n        # setup\n        oef_dialogue = cast(\n            OefSearchDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.oef_dialogues,\n                messages=self.list_of_messages[:1],\n            ),\n        )\n        oef_dialogue._is_seller_search = True\n        search_for = \"sellers\"\n\n        incoming_message = cast(\n            OefSearchMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=oef_dialogue,\n                performative=OefSearchMessage.Performative.SEARCH_RESULT,\n                to=str(self.skill.skill_context.skill_id),\n                agents=tuple(self.found_agents),\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            with patch.object(\n                self.strategy, \"get_own_services_query\", return_value=self.cfp_query\n            ) as mock_own:\n                self.oef_search_handler.handle(incoming_message)\n\n        # after\n        self.assert_quantity_in_outbox(len(self.found_agents_less_self))\n\n        # _handle_search\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"found potential {search_for} agents={list(map(lambda x: x[-5:], self.found_agents_less_self))} on search_id={incoming_message.dialogue_reference[0]}.\",\n        )\n        mock_own.assert_called_once()\n\n        for agent in self.found_agents_less_self:\n            mock_logger.assert_any_call(\n                logging.INFO,\n                f\"sending CFP to agent={agent[-5:]}\",\n            )\n            has_attributes, error_str = self.message_has_attributes(\n                actual_message=self.get_message_from_outbox(),\n                message_type=FipaMessage,\n                performative=FipaMessage.Performative.CFP,\n                to=agent,\n                sender=self.self_address,\n                query=self.cfp_query,\n            )\n            assert has_attributes, error_str\n\n    def test_on_search_result_ii(self):\n        \"\"\"Test the _on_search_result method of the oef handler where number of agents found is 0.\"\"\"\n        # setup\n        oef_dialogue = cast(\n            OefSearchDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.oef_dialogues,\n                messages=self.list_of_messages[:1],\n            ),\n        )\n        oef_dialogue._is_seller_search = False\n        search_for = \"buyers\"\n\n        incoming_message = cast(\n            OefSearchMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=oef_dialogue,\n                performative=OefSearchMessage.Performative.SEARCH_RESULT,\n                to=str(self.skill.skill_context.skill_id),\n                agents=tuple(),\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        self.assert_quantity_in_outbox(0)\n\n        # _handle_search\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"found no {search_for} agents on search_id={incoming_message.dialogue_reference[0]}, continue searching.\",\n        )\n\n    def test_handle_invalid(self):\n        \"\"\"Test the _handle_invalid method of the oef handler.\"\"\"\n        # setup\n        invalid_performative = OefSearchMessage.Performative.UNREGISTER_SERVICE\n        incoming_message = self.build_incoming_message(\n            message_type=OefSearchMessage,\n            dialogue_reference=(\"1\", \"\"),\n            performative=invalid_performative,\n            to=str(self.skill.skill_context.skill_id),\n            service_description=\"some_service_description\",\n        )\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"cannot handle oef_search message of performative={invalid_performative} in dialogue={self.oef_dialogues.get_dialogue(incoming_message)}.\",\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the oef_search handler.\"\"\"\n        assert self.oef_search_handler.teardown() is None\n        self.assert_quantity_in_outbox(0)\n\n\nclass TestContractApiHandler(BaseSkillTestCase):\n    \"\"\"Test contract_api handler of tac negotiation.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"tac_negotiation\")\n    is_agent_to_agent_messages = False\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.contract_api_handler = cast(\n            ContractApiHandler, cls._skill.skill_context.handlers.contract_api\n        )\n        cls.logger = cls.contract_api_handler.context.logger\n\n        cls.contract_api_dialogues = cast(\n            ContractApiDialogues, cls._skill.skill_context.contract_api_dialogues\n        )\n        cls.signing_dialogues = cast(\n            SigningDialogues, cls._skill.skill_context.signing_dialogues\n        )\n        cls.fipa_dialogues = cast(\n            FipaDialogues, cls._skill.skill_context.fipa_dialogues\n        )\n\n        cls.ledger_id = \"some_ledger_id\"\n        cls.contract_id = \"some_contract_id\"\n        cls.contract_address = \"some_contract_address\"\n        cls.callable = \"some_callable\"\n        cls.kwargs = Kwargs({\"some_key\": \"some_value\"})\n        cls.body = {\"some_key\": \"some_value\"}\n        cls.body_bytes = b\"some_body\"\n        cls.nonce = \"some_nonce\"\n        cls.counterprty_address = COUNTERPARTY_AGENT_ADDRESS\n        cls.amount_by_currency_id = {\"1\": 50}\n        cls.quantities_by_good_id = {\"2\": -10}\n        cls.terms = Terms(\n            cls.ledger_id,\n            cls._skill.skill_context.agent_address,\n            cls.counterprty_address,\n            cls.amount_by_currency_id,\n            cls.quantities_by_good_id,\n            cls.nonce,\n        )\n\n        cls.list_of_contract_api_messages_get_deploy_tx = (\n            DialogueMessage(\n                ContractApiMessage.Performative.GET_DEPLOY_TRANSACTION,\n                {\n                    \"ledger_id\": cls.ledger_id,\n                    \"contract_id\": cls.contract_id,\n                    \"callable\": cls.callable,\n                    \"kwargs\": cls.kwargs,\n                },\n            ),\n        )\n        cls.list_of_contract_api_messages_raw_msg = (\n            DialogueMessage(\n                ContractApiMessage.Performative.GET_RAW_MESSAGE,\n                {\n                    \"ledger_id\": cls.ledger_id,\n                    \"contract_id\": cls.contract_id,\n                    \"contract_address\": cls.contract_address,\n                    \"callable\": cls.callable,\n                    \"kwargs\": cls.kwargs,\n                },\n            ),\n        )\n\n        cls.cfp_query = Query(\n            [Constraint(\"some_attribute\", ConstraintType(\"==\", \"some_service\"))],\n            DataModel(\n                SUPPLY_DATAMODEL_NAME,\n                [\n                    Attribute(\n                        \"some_attribute\", str, False, \"Some attribute descriptions.\"\n                    )\n                ],\n            ),\n        )\n        cls.list_of_fipa_messages = (\n            DialogueMessage(FipaMessage.Performative.CFP, {\"query\": cls.cfp_query}),\n        )\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the contract_api handler.\"\"\"\n        assert self.contract_api_handler.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle_unidentified_dialogue(self):\n        \"\"\"Test the _handle_unidentified_dialogue method of the signing handler.\"\"\"\n        # setup\n        incorrect_dialogue_reference = (\"\", \"\")\n        incoming_message = self.build_incoming_message(\n            message_type=ContractApiMessage,\n            dialogue_reference=incorrect_dialogue_reference,\n            performative=ContractApiMessage.Performative.STATE,\n            state=State(\"some_ledger_id\", {\"some_key\": \"some_value\"}),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.contract_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received invalid contract_api message={incoming_message}, unidentified dialogue.\",\n        )\n\n    def test_handle_raw_message(self):\n        \"\"\"Test the _handle_raw_message method of the signing handler.\"\"\"\n        # setup\n        fipa_dialogue = cast(\n            FipaDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.fipa_dialogues,\n                messages=self.list_of_fipa_messages[:1],\n            ),\n        )\n        fipa_dialogue.terms = self.terms\n\n        contract_api_dialogue = cast(\n            ContractApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.contract_api_dialogues,\n                messages=self.list_of_contract_api_messages_raw_msg[:1],\n            ),\n        )\n        contract_api_dialogue.associated_fipa_dialogue = fipa_dialogue\n\n        incoming_message = cast(\n            ContractApiMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=contract_api_dialogue,\n                performative=ContractApiMessage.Performative.RAW_MESSAGE,\n                raw_message=ContractApiMessage.RawMessage(\n                    self.ledger_id, self.body_bytes\n                ),\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.contract_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO, f\"received raw message={incoming_message}\"\n        )\n\n        self.assert_quantity_in_decision_making_queue(1)\n        message = self.get_message_from_decision_maker_inbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=SigningMessage,\n            performative=SigningMessage.Performative.SIGN_MESSAGE,\n            to=self.skill.skill_context.decision_maker_address,\n            sender=str(self.skill.skill_context.skill_id),\n            terms=self.terms,\n            raw_message=RawMessage(\n                self.ledger_id,\n                self.body_bytes,\n                is_deprecated_mode=True,\n            ),\n        )\n        assert has_attributes, error_str\n\n        assert (\n            cast(\n                SigningDialogue, self.signing_dialogues.get_dialogue(message)\n            ).associated_fipa_dialogue\n            == fipa_dialogue\n        )\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            \"proposing the message to the decision maker. Waiting for confirmation ...\",\n        )\n\n    def test_handle_raw_transaction(self):\n        \"\"\"Test the _handle_signed_transaction method of the signing handler.\"\"\"\n        # setup\n        fipa_dialogue = cast(\n            FipaDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.fipa_dialogues,\n                messages=self.list_of_fipa_messages[:1],\n            ),\n        )\n        fipa_dialogue.terms = self.terms\n\n        contract_api_dialogue = cast(\n            ContractApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.contract_api_dialogues,\n                messages=self.list_of_contract_api_messages_get_deploy_tx[:1],\n            ),\n        )\n        contract_api_dialogue.associated_fipa_dialogue = fipa_dialogue\n\n        incoming_message = cast(\n            ContractApiMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=contract_api_dialogue,\n                performative=ContractApiMessage.Performative.RAW_TRANSACTION,\n                raw_transaction=ContractApiMessage.RawTransaction(\n                    self.ledger_id, self.body\n                ),\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.contract_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO, f\"received raw transaction={incoming_message}\"\n        )\n\n        self.assert_quantity_in_decision_making_queue(1)\n        message = self.get_message_from_decision_maker_inbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=SigningMessage,\n            performative=SigningMessage.Performative.SIGN_TRANSACTION,\n            to=self.skill.skill_context.decision_maker_address,\n            sender=str(self.skill.skill_context.skill_id),\n            terms=self.terms,\n            raw_transaction=incoming_message.raw_transaction,\n        )\n        assert has_attributes, error_str\n\n        assert (\n            cast(\n                SigningDialogue, self.signing_dialogues.get_dialogue(message)\n            ).associated_fipa_dialogue\n            == fipa_dialogue\n        )\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            \"proposing the transaction to the decision maker. Waiting for confirmation ...\",\n        )\n\n    def test_handle_error(self):\n        \"\"\"Test the _handle_error method of the signing handler.\"\"\"\n        # setup\n        contract_api_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.contract_api_dialogues,\n            messages=self.list_of_contract_api_messages_get_deploy_tx[:1],\n        )\n        incoming_message = cast(\n            ContractApiMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=contract_api_dialogue,\n                performative=ContractApiMessage.Performative.ERROR,\n                data=b\"some_data\",\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.contract_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received contract_api error message={incoming_message} in dialogue={contract_api_dialogue}.\",\n        )\n\n    def test_handle_invalid(self):\n        \"\"\"Test the _handle_invalid method of the signing handler.\"\"\"\n        # setup\n        invalid_performative = ContractApiMessage.Performative.GET_DEPLOY_TRANSACTION\n        incoming_message = self.build_incoming_message(\n            message_type=ContractApiMessage,\n            dialogue_reference=(\"1\", \"\"),\n            performative=invalid_performative,\n            ledger_id=self.ledger_id,\n            contract_id=self.contract_id,\n            callable=self.callable,\n            kwargs=self.kwargs,\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.contract_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"cannot handle contract_api message of performative={invalid_performative} in dialogue={self.contract_api_dialogues.get_dialogue(incoming_message)}.\",\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the contract_api handler.\"\"\"\n        assert self.contract_api_handler.teardown() is None\n        self.assert_quantity_in_outbox(0)\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_tac_negotiation/test_helpers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the helpers module of the tac negotiation.\"\"\"\n\nfrom pathlib import Path\n\nfrom aea.helpers.search.models import (\n    Attribute,\n    Constraint,\n    ConstraintType,\n    DataModel,\n    Description,\n)\nfrom aea.test_tools.test_skill import BaseSkillTestCase\n\nfrom packages.fetchai.skills.tac_negotiation.helpers import (\n    DEMAND_DATAMODEL_NAME,\n    SUPPLY_DATAMODEL_NAME,\n    _build_goods_datamodel,\n    build_goods_description,\n    build_goods_query,\n)\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass TestHelpers(BaseSkillTestCase):\n    \"\"\"Test Helper module methods of tac control.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"tac_negotiation\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n\n    def test_build_goods_datamodel_supply(self):\n        \"\"\"Test the _build_goods_datamodel of Helpers module for a supply.\"\"\"\n        good_ids = [\"1\", \"2\"]\n        is_supply = True\n        attributes = [\n            Attribute(\"1\", int, True, \"A good on offer.\"),\n            Attribute(\"2\", int, True, \"A good on offer.\"),\n            Attribute(\"ledger_id\", str, True, \"The ledger for transacting.\"),\n            Attribute(\n                \"currency_id\",\n                str,\n                True,\n                \"The currency for pricing and transacting the goods.\",\n            ),\n            Attribute(\"price\", int, False, \"The price of the goods in the currency.\"),\n            Attribute(\n                \"fee\",\n                int,\n                False,\n                \"The transaction fee payable by the buyer in the currency.\",\n            ),\n            Attribute(\n                \"nonce\", str, False, \"The nonce to distinguish identical descriptions.\"\n            ),\n        ]\n        expected_data_model = DataModel(SUPPLY_DATAMODEL_NAME, attributes)\n        actual_data_model = _build_goods_datamodel(good_ids, is_supply)\n        assert actual_data_model == expected_data_model\n\n    def test_build_goods_datamodel_demand(self):\n        \"\"\"Test the _build_goods_datamodel of Helpers module for a demand.\"\"\"\n        good_ids = [\"1\", \"2\"]\n        is_supply = False\n        attributes = [\n            Attribute(\"1\", int, True, \"A good on offer.\"),\n            Attribute(\"2\", int, True, \"A good on offer.\"),\n            Attribute(\"ledger_id\", str, True, \"The ledger for transacting.\"),\n            Attribute(\n                \"currency_id\",\n                str,\n                True,\n                \"The currency for pricing and transacting the goods.\",\n            ),\n            Attribute(\"price\", int, False, \"The price of the goods in the currency.\"),\n            Attribute(\n                \"fee\",\n                int,\n                False,\n                \"The transaction fee payable by the buyer in the currency.\",\n            ),\n            Attribute(\n                \"nonce\", str, False, \"The nonce to distinguish identical descriptions.\"\n            ),\n        ]\n        expected_data_model = DataModel(DEMAND_DATAMODEL_NAME, attributes)\n        actual_data_model = _build_goods_datamodel(good_ids, is_supply)\n        assert actual_data_model == expected_data_model\n\n    def test_build_goods_description_supply(self):\n        \"\"\"Test the build_goods_description of Helpers module for supply.\"\"\"\n        quantities_by_good_id = {\"2\": 5, \"3\": 10}\n        currency_id = \"1\"\n        ledger_id = \"some_ledger_id\"\n        is_supply = True\n\n        attributes = [\n            Attribute(\"2\", int, True, \"A good on offer.\"),\n            Attribute(\"3\", int, True, \"A good on offer.\"),\n            Attribute(\"ledger_id\", str, True, \"The ledger for transacting.\"),\n            Attribute(\n                \"currency_id\",\n                str,\n                True,\n                \"The currency for pricing and transacting the goods.\",\n            ),\n            Attribute(\"price\", int, False, \"The price of the goods in the currency.\"),\n            Attribute(\n                \"fee\",\n                int,\n                False,\n                \"The transaction fee payable by the buyer in the currency.\",\n            ),\n            Attribute(\n                \"nonce\", str, False, \"The nonce to distinguish identical descriptions.\"\n            ),\n        ]\n        expected_data_model = DataModel(SUPPLY_DATAMODEL_NAME, attributes)\n        expected_values = {\"currency_id\": currency_id, \"ledger_id\": ledger_id}\n        expected_values.update(quantities_by_good_id)\n        expected_description = Description(expected_values, expected_data_model)\n\n        actual_description = build_goods_description(\n            quantities_by_good_id, currency_id, ledger_id, is_supply\n        )\n        assert actual_description == expected_description\n\n    def test_build_goods_description_demand(self):\n        \"\"\"Test the build_goods_description of Helpers module for demand (same as above).\"\"\"\n        quantities_by_good_id = {\"2\": 5, \"3\": 10}\n        currency_id = \"1\"\n        ledger_id = \"some_ledger_id\"\n        is_supply = False\n\n        attributes = [\n            Attribute(\"2\", int, True, \"A good on offer.\"),\n            Attribute(\"3\", int, True, \"A good on offer.\"),\n            Attribute(\"ledger_id\", str, True, \"The ledger for transacting.\"),\n            Attribute(\n                \"currency_id\",\n                str,\n                True,\n                \"The currency for pricing and transacting the goods.\",\n            ),\n            Attribute(\"price\", int, False, \"The price of the goods in the currency.\"),\n            Attribute(\n                \"fee\",\n                int,\n                False,\n                \"The transaction fee payable by the buyer in the currency.\",\n            ),\n            Attribute(\n                \"nonce\", str, False, \"The nonce to distinguish identical descriptions.\"\n            ),\n        ]\n        expected_data_model = DataModel(DEMAND_DATAMODEL_NAME, attributes)\n        expected_values = {\"currency_id\": currency_id, \"ledger_id\": ledger_id}\n        expected_values.update(quantities_by_good_id)\n        expected_description = Description(expected_values, expected_data_model)\n\n        actual_description = build_goods_description(\n            quantities_by_good_id, currency_id, ledger_id, is_supply\n        )\n        assert actual_description == expected_description\n\n    def test_build_goods_query(self):\n        \"\"\"Test the build_goods_query of Helpers module.\"\"\"\n        good_ids = [\"2\", \"3\"]\n        currency_id = \"1\"\n        ledger_id = \"some_ledger_id\"\n        is_searching_for_sellers = True\n\n        attributes = [\n            Attribute(\"2\", int, True, \"A good on offer.\"),\n            Attribute(\"3\", int, True, \"A good on offer.\"),\n            Attribute(\"ledger_id\", str, True, \"The ledger for transacting.\"),\n            Attribute(\n                \"currency_id\",\n                str,\n                True,\n                \"The currency for pricing and transacting the goods.\",\n            ),\n            Attribute(\"price\", int, False, \"The price of the goods in the currency.\"),\n            Attribute(\n                \"fee\",\n                int,\n                False,\n                \"The transaction fee payable by the buyer in the currency.\",\n            ),\n            Attribute(\n                \"nonce\", str, False, \"The nonce to distinguish identical descriptions.\"\n            ),\n        ]\n        expected_data_model = DataModel(SUPPLY_DATAMODEL_NAME, attributes)\n\n        expected_constraints = [\n            Constraint(\"2\", ConstraintType(\">=\", 1)),\n            Constraint(\"3\", ConstraintType(\">=\", 1)),\n            Constraint(\"ledger_id\", ConstraintType(\"==\", ledger_id)),\n            Constraint(\"currency_id\", ConstraintType(\"==\", currency_id)),\n        ]\n\n        actual_query = build_goods_query(\n            good_ids, currency_id, ledger_id, is_searching_for_sellers\n        )\n\n        constraints = [\n            (c.constraint_type.type, c.constraint_type.value)\n            for c in actual_query.constraints[0].constraints\n        ]\n        for constraint in expected_constraints:\n            assert (\n                constraint.constraint_type.type,\n                constraint.constraint_type.value,\n            ) in constraints\n        assert actual_query.model == expected_data_model\n\n    def test_build_goods_query_1_good(self):\n        \"\"\"Test the build_goods_query of Helpers module where there is 1 good.\"\"\"\n        good_ids = [\"2\"]\n        currency_id = \"1\"\n        ledger_id = \"some_ledger_id\"\n        is_searching_for_sellers = True\n\n        attributes = [\n            Attribute(\"2\", int, True, \"A good on offer.\"),\n            Attribute(\"ledger_id\", str, True, \"The ledger for transacting.\"),\n            Attribute(\n                \"currency_id\",\n                str,\n                True,\n                \"The currency for pricing and transacting the goods.\",\n            ),\n            Attribute(\"price\", int, False, \"The price of the goods in the currency.\"),\n            Attribute(\n                \"fee\",\n                int,\n                False,\n                \"The transaction fee payable by the buyer in the currency.\",\n            ),\n            Attribute(\n                \"nonce\", str, False, \"The nonce to distinguish identical descriptions.\"\n            ),\n        ]\n        expected_data_model = DataModel(SUPPLY_DATAMODEL_NAME, attributes)\n\n        expected_constraints = [\n            Constraint(\"2\", ConstraintType(\">=\", 1)),\n            Constraint(\"ledger_id\", ConstraintType(\"==\", ledger_id)),\n            Constraint(\"currency_id\", ConstraintType(\"==\", currency_id)),\n        ]\n\n        actual_query = build_goods_query(\n            good_ids, currency_id, ledger_id, is_searching_for_sellers\n        )\n\n        for constraint in expected_constraints:\n            assert constraint in actual_query.constraints\n        assert actual_query.model == expected_data_model\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_tac_negotiation/test_logical.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains tests for the logical behaviour of the tac negotiation skill.\"\"\"\nimport copy\nfrom pathlib import Path\nfrom unittest.mock import patch\n\nfrom aea.decision_maker.gop import GoalPursuitReadiness, OwnershipState, Preferences\nfrom aea.helpers.preference_representations.base import (\n    linear_utility,\n    logarithmic_utility,\n)\nfrom aea.test_tools.test_skill import BaseSkillTestCase\n\nfrom packages.fetchai.skills.tac_control.helpers import (\n    determine_scaling_factor,\n    generate_utility_params,\n)\nfrom packages.fetchai.skills.tac_negotiation.dialogues import FipaDialogue\nfrom packages.fetchai.skills.tac_negotiation.strategy import Strategy\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass TestLogical(BaseSkillTestCase):\n    \"\"\"Logical Tests for tac negotiation.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"tac_negotiation\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        tac_dm_context_kwargs = {\n            \"goal_pursuit_readiness\": GoalPursuitReadiness(),\n            \"ownership_state\": OwnershipState(),\n            \"preferences\": Preferences(),\n        }\n        super().setup(dm_context_kwargs=tac_dm_context_kwargs)\n        cls.register_as = \"both\"\n        cls.search_for = \"both\"\n        cls.is_contract_tx = False\n        cls.ledger_id = \"some_ledger_id\"\n        cls.location = {\"longitude\": 0.1270, \"latitude\": 51.5194}\n        cls.search_radius = 5.0\n        cls.service_key = \"tac_service\"\n\n        cls.strategy = Strategy(\n            register_as=cls.register_as,\n            search_for=cls.search_for,\n            is_contract_tx=cls.is_contract_tx,\n            ledger_id=cls.ledger_id,\n            location=cls.location,\n            service_key=cls.service_key,\n            search_radius=cls.search_radius,\n            name=\"strategy\",\n            skill_context=cls._skill.skill_context,\n        )\n\n        cls.sender = \"some_sender_address\"\n        cls.counterparty = \"some_counterparty_address\"\n\n        cls.mocked_currency_id = \"12\"\n        cls.mocked_currency_amount = 2000000\n        cls.mocked_amount_by_currency_id = {\n            cls.mocked_currency_id: cls.mocked_currency_amount\n        }\n        cls.mocked_good_ids = [\"13\", \"14\", \"15\", \"16\", \"17\", \"18\", \"19\", \"20\", \"21\"]\n        cls.mocked_good_quantities = [5, 7, 4, 3, 5, 4, 3, 5, 6]\n        cls.mocked_quantities_by_good_id = dict(\n            zip(cls.mocked_good_ids, cls.mocked_good_quantities)\n        )\n        cls.mocked_ownership_state = (\n            cls._skill.skill_context.decision_maker_handler_context.ownership_state\n        )\n        cls.mocked_ownership_state.set(\n            cls.mocked_amount_by_currency_id, cls.mocked_quantities_by_good_id\n        )\n\n        cls.exchange_params_by_currency_id = {cls.mocked_currency_id: 1.0}\n        cls.utility_params_by_good_id = generate_utility_params(\n            [cls._skill.skill_context.agent_address],\n            cls.mocked_good_ids,\n            determine_scaling_factor(cls.mocked_currency_amount),\n        )[cls._skill.skill_context.agent_address]\n        cls.mocked_preferences = (\n            cls._skill.skill_context.decision_maker_handler_context.preferences\n        )\n        cls.mocked_preferences.set(\n            exchange_params_by_currency_id=cls.exchange_params_by_currency_id,\n            utility_params_by_good_id=cls.utility_params_by_good_id,\n        )\n\n    @staticmethod\n    def _calculate_score(preferences, ownership_state):\n        \"\"\"Calculate the score given a preferences and an ownership_state object.\"\"\"\n        goods_score = logarithmic_utility(\n            preferences.utility_params_by_good_id,\n            ownership_state.quantities_by_good_id,\n        )\n        money_score = linear_utility(\n            preferences.exchange_params_by_currency_id,\n            ownership_state.amount_by_currency_id,\n        )\n        return goods_score + money_score\n\n    def test_generated_proposals_increase_score_seller(self):\n        \"\"\"Test whether the proposals generated by _generate_candidate_proposals method of the Strategy class actually increases agent's score where role is seller.\"\"\"\n        # setup\n        is_searching_for_sellers = True\n\n        # operation\n        with patch.object(\n            self.skill.skill_context.transactions,\n            \"ownership_state_after_locks\",\n            return_value=self.mocked_ownership_state,\n        ) as mock_ownership:\n            actual_proposals = self.strategy._generate_candidate_proposals(\n                is_searching_for_sellers\n            )\n\n        # after\n        mock_ownership.assert_any_call(is_seller=is_searching_for_sellers)\n\n        current_score = self._calculate_score(\n            self.mocked_preferences, self.mocked_ownership_state\n        )\n        for proposal in actual_proposals:\n            # applying proposal on a new ownership_state\n            terms = self.strategy.terms_from_proposal(\n                proposal, self.sender, self.counterparty, FipaDialogue.Role.SELLER\n            )\n            new_ownership_state = copy.copy(self.mocked_ownership_state)\n            new_ownership_state.apply_delta(\n                terms.amount_by_currency_id, terms.quantities_by_good_id\n            )\n\n            # new score\n            new_score = self._calculate_score(\n                self.mocked_preferences, new_ownership_state\n            )\n\n            assert new_score >= current_score\n\n    def test_generated_proposals_increase_score_buyer(self):\n        \"\"\"Test whether the proposals generated by _generate_candidate_proposals method of the Strategy class actually increases agent's score  where role is buyer.\"\"\"\n        # setup\n        is_searching_for_sellers = False\n\n        # operation\n        with patch.object(\n            self.skill.skill_context.transactions,\n            \"ownership_state_after_locks\",\n            return_value=self.mocked_ownership_state,\n        ) as mock_ownership:\n            actual_proposals = self.strategy._generate_candidate_proposals(\n                is_searching_for_sellers\n            )\n\n        # after\n        mock_ownership.assert_any_call(is_seller=is_searching_for_sellers)\n\n        current_score = self._calculate_score(\n            self.mocked_preferences, self.mocked_ownership_state\n        )\n        for proposal in actual_proposals:\n            # applying proposal on a new ownership_state\n            terms = self.strategy.terms_from_proposal(\n                proposal, self.sender, self.counterparty, FipaDialogue.Role.BUYER\n            )\n            new_ownership_state = copy.copy(self.mocked_ownership_state)\n            new_ownership_state.apply_delta(\n                terms.amount_by_currency_id, terms.quantities_by_good_id\n            )\n\n            # new score\n            new_score = self._calculate_score(\n                self.mocked_preferences, new_ownership_state\n            )\n\n            assert new_score >= current_score\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_tac_negotiation/test_strategy.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the strategy class of the tac negotiation skill.\"\"\"\n\nimport re\nfrom pathlib import Path\nfrom unittest.mock import patch\n\nimport pytest\n\nfrom aea.decision_maker.gop import GoalPursuitReadiness, OwnershipState, Preferences\nfrom aea.exceptions import AEAEnforceError\nfrom aea.helpers.search.models import (\n    Attribute,\n    Constraint,\n    ConstraintType,\n    DataModel,\n    Description,\n    Location,\n    Query,\n)\nfrom aea.helpers.transaction.base import Terms\nfrom aea.test_tools.test_skill import BaseSkillTestCase\n\nfrom packages.fetchai.skills.tac_negotiation.dialogues import FipaDialogue\nfrom packages.fetchai.skills.tac_negotiation.helpers import (\n    build_goods_description,\n    build_goods_query,\n)\nfrom packages.fetchai.skills.tac_negotiation.strategy import (\n    AGENT_LOCATION_MODEL,\n    AGENT_PERSONALITY_MODEL,\n    AGENT_REMOVE_SERVICE_MODEL,\n    AGENT_SET_SERVICE_MODEL,\n    CONTRACT_ID,\n    DEFAULT_TX_FEE_PROPOSAL,\n    Strategy,\n)\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass TestStrategy(BaseSkillTestCase):\n    \"\"\"Test Strategy of tac negotiation.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"tac_negotiation\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        tac_dm_context_kwargs = {\n            \"goal_pursuit_readiness\": GoalPursuitReadiness(),\n            \"ownership_state\": OwnershipState(),\n            \"preferences\": Preferences(),\n        }\n        super().setup(dm_context_kwargs=tac_dm_context_kwargs)\n        cls.register_as = \"both\"\n        cls.search_for = \"both\"\n        cls.is_contract_tx = False\n        cls.ledger_id = \"some_ledger_id\"\n        cls.location = {\"longitude\": 0.1270, \"latitude\": 51.5194}\n        cls.search_radius = 5.0\n        cls.service_key = \"tac_service\"\n\n        cls.strategy = Strategy(\n            register_as=cls.register_as,\n            search_for=cls.search_for,\n            is_contract_tx=cls.is_contract_tx,\n            ledger_id=cls.ledger_id,\n            location=cls.location,\n            service_key=cls.service_key,\n            search_radius=cls.search_radius,\n            name=\"strategy\",\n            skill_context=cls._skill.skill_context,\n        )\n\n        cls.nonce = \"125\"\n        cls.sender = \"some_sender_address\"\n        cls.counterparty = \"some_counterparty_address\"\n        cls.signature = \"some_signature\"\n        cls.sender_pk = \"some_sender_public_key\"\n        cls.counterparty_pk = \"some_counterparty_public_key\"\n\n        cls.mocked_currency_id = \"12\"\n        cls.mocked_currency_amount = 2000000\n        cls.mocked_amount_by_currency_id = {\n            cls.mocked_currency_id: cls.mocked_currency_amount\n        }\n        cls.mocked_good_ids = [\"13\", \"14\", \"15\", \"16\", \"17\", \"18\", \"19\", \"20\", \"21\"]\n        cls.mocked_good_quantities = [5, 7, 4, 3, 5, 4, 3, 5, 6]\n        cls.mocked_quantities_by_good_id = dict(\n            zip(cls.mocked_good_ids, cls.mocked_good_quantities)\n        )\n        cls.mocked_ownership_state = (\n            cls._skill.skill_context.decision_maker_handler_context.ownership_state\n        )\n        cls.mocked_ownership_state.set(\n            cls.mocked_amount_by_currency_id, cls.mocked_quantities_by_good_id\n        )\n\n        cls.exchange_params_by_currency_id = {cls.mocked_currency_id: 1.0}\n        cls.utility_params_by_good_id = {\n            \"13\": 48300.0,\n            \"14\": 43700.0,\n            \"15\": 163200.0,\n            \"16\": 59800.0,\n            \"17\": 114900.0,\n            \"18\": 128700.00000000001,\n            \"19\": 126400.00000000001,\n            \"20\": 211500.0,\n            \"21\": 103500.0,\n        }\n        cls.mocked_preferences = (\n            cls._skill.skill_context.decision_maker_handler_context.preferences\n        )\n        cls.mocked_preferences.set(\n            exchange_params_by_currency_id=cls.exchange_params_by_currency_id,\n            utility_params_by_good_id=cls.utility_params_by_good_id,\n        )\n\n    def test_properties(self):\n        \"\"\"Test the properties of Strategy class.\"\"\"\n        assert self.strategy.registering_as == \"buyer and seller\"\n\n        assert self.strategy.searching_for == \"buyer and seller\"\n\n        assert self.strategy.searching_for_types == [\n            (True, \"sellers\"),\n            (False, \"buyers\"),\n        ]\n\n        assert self.strategy.is_contract_tx == self.is_contract_tx\n\n        assert self.strategy.ledger_id == self.ledger_id\n\n        assert self.strategy.contract_id == str(CONTRACT_ID)\n\n        with pytest.raises(AEAEnforceError, match=\"ERC1155Contract address not set!\"):\n            assert self.strategy.contract_address\n        self.skill.skill_context._agent_context._shared_state = {\n            \"erc1155_contract_address\": \"some_address\"\n        }\n        assert self.strategy.contract_address == \"some_address\"\n\n    def test_get_location_description(self):\n        \"\"\"Test the get_location_description method of the Strategy class.\"\"\"\n        description = self.strategy.get_location_description()\n\n        assert type(description) == Description\n        assert description.data_model is AGENT_LOCATION_MODEL\n        assert description.values.get(\"location\", \"\") == Location(\n            latitude=self.location[\"latitude\"], longitude=self.location[\"longitude\"]\n        )\n\n    def test_get_register_service_description(self):\n        \"\"\"Test the get_register_service_description method of the GenericStrategy class.\"\"\"\n        # setup\n        self.strategy.tac_version_id = \"some_tac_id\"\n\n        # operation\n        description = self.strategy.get_register_service_description()\n\n        # after\n        assert type(description) == Description\n        assert description.data_model is AGENT_SET_SERVICE_MODEL\n        assert (\n            description.values.get(\"key\", \"\")\n            == f\"{self.service_key}_{self.strategy.tac_version_id}\"\n        )\n        assert description.values.get(\"value\", \"\") == self.register_as\n\n    def test_get_register_personality_description(self):\n        \"\"\"Test the get_register_personality_description method of the GenericStrategy class.\"\"\"\n        description = self.strategy.get_register_personality_description()\n\n        assert type(description) == Description\n        assert description.data_model is AGENT_PERSONALITY_MODEL\n        assert description.values.get(\"piece\", \"\") == \"genus\"\n        assert description.values.get(\"value\", \"\") == \"data\"\n\n    def test_get_register_classification_description(self):\n        \"\"\"Test the get_register_classification_description method of the GenericStrategy class.\"\"\"\n        description = self.strategy.get_register_classification_description()\n\n        assert type(description) == Description\n        assert description.data_model is AGENT_PERSONALITY_MODEL\n        assert description.values.get(\"piece\", \"\") == \"classification\"\n        assert description.values.get(\"value\", \"\") == \"tac.participant\"\n\n    def test_get_unregister_service_description(self):\n        \"\"\"Test the get_unregister_service_description method of the GenericStrategy class.\"\"\"\n        description = self.strategy.get_unregister_service_description()\n\n        assert type(description) == Description\n        assert description.data_model is AGENT_REMOVE_SERVICE_MODEL\n        assert description.values.get(\"key\", \"\") == self.service_key\n\n    def test_get_location_and_service_query(self):\n        \"\"\"Test the get_location_and_service_query method of the Strategy class.\"\"\"\n        # setup\n        self.strategy.tac_version_id = \"some_tac_id\"\n\n        # operation\n        query = self.strategy.get_location_and_service_query()\n\n        # after\n        assert type(query) == Query\n        assert len(query.constraints) == 2\n        assert query.model is None\n\n        location_constraint = Constraint(\n            \"location\",\n            ConstraintType(\n                \"distance\",\n                (\n                    Location(\n                        latitude=self.location[\"latitude\"],\n                        longitude=self.location[\"longitude\"],\n                    ),\n                    self.search_radius,\n                ),\n            ),\n        )\n        assert query.constraints[0] == location_constraint\n\n        service_key_filter = Constraint(\n            f\"{self.service_key}_{self.strategy.tac_version_id}\",\n            ConstraintType(\"==\", self.search_for),\n        )\n        assert query.constraints[1] == service_key_filter\n\n    def test_get_own_service_description_is_supply(self):\n        \"\"\"Test the get_own_service_description method of the Strategy class where is_supply is True.\"\"\"\n        # setup\n        is_supply = True\n        mocked_supplied_quantities_by_good_id = {\n            good_id: quantity - 1\n            for good_id, quantity in self.mocked_quantities_by_good_id.items()\n        }\n        expected_description = build_goods_description(\n            mocked_supplied_quantities_by_good_id,\n            self.mocked_currency_id,\n            self.ledger_id,\n            is_supply,\n        )\n\n        # operation\n        with patch.object(\n            self.skill.skill_context.transactions,\n            \"ownership_state_after_locks\",\n            return_value=self.mocked_ownership_state,\n        ) as mock_ownership:\n            actual_description = self.strategy.get_own_service_description(is_supply)\n\n        # after\n        mock_ownership.assert_any_call(is_seller=is_supply)\n        assert actual_description == expected_description\n\n    def test_get_own_service_description_not_is_supply(self):\n        \"\"\"Test the get_own_service_description method of the Strategy class where is_supply is False.\"\"\"\n        # setup\n        is_supply = False\n        mocked_demanded_quantities_by_good_id = {\n            good_id: 1 for good_id in self.mocked_quantities_by_good_id.keys()\n        }\n        expected_description = build_goods_description(\n            mocked_demanded_quantities_by_good_id,\n            self.mocked_currency_id,\n            self.ledger_id,\n            is_supply,\n        )\n\n        # operation\n        with patch.object(\n            self.skill.skill_context.transactions,\n            \"ownership_state_after_locks\",\n            return_value=self.mocked_ownership_state,\n        ) as mock_ownership:\n            actual_description = self.strategy.get_own_service_description(is_supply)\n\n        # after\n        mock_ownership.assert_any_call(is_seller=is_supply)\n        assert actual_description == expected_description\n\n    def test_supplied_goods(self):\n        \"\"\"Test the _supplied_goods method of the Strategy class.\"\"\"\n        good_holdings = {\"1\": 1, \"2\": 5, \"3\": 10, \"4\": 1, \"5\": 0}\n        actual_supply = self.strategy._supplied_goods(good_holdings)\n\n        expected_supply = {\"1\": 0, \"2\": 4, \"3\": 9, \"4\": 0, \"5\": 0}\n        assert actual_supply == expected_supply\n\n    def test_demanded_goods(self):\n        \"\"\"Test the _demanded_goods method of the Strategy class.\"\"\"\n        good_holdings = {\"1\": 1, \"2\": 5, \"3\": 10, \"4\": 1, \"5\": 0}\n        actual_demand = self.strategy._demanded_goods(good_holdings)\n\n        expected_demand = {\"1\": 1, \"2\": 1, \"3\": 1, \"4\": 1, \"5\": 1}\n        assert actual_demand == expected_demand\n\n    def test_get_own_services_query_searching_seller(self):\n        \"\"\"Test the get_own_services_query method of the Strategy class where is_searching_for_sellers is True.\"\"\"\n        # setup\n        is_searching_for_sellers = True\n        expected_query = build_goods_query(\n            list(self.mocked_quantities_by_good_id.keys()),\n            self.mocked_currency_id,\n            self.ledger_id,\n            is_searching_for_sellers,\n        )\n\n        # operation\n        with patch.object(\n            self.skill.skill_context.transactions,\n            \"ownership_state_after_locks\",\n            return_value=self.mocked_ownership_state,\n        ) as mock_ownership:\n            actual_query = self.strategy.get_own_services_query(\n                is_searching_for_sellers\n            )\n\n        # after\n        mock_ownership.assert_any_call(is_seller=not is_searching_for_sellers)\n        assert actual_query == expected_query\n\n    def test_get_own_services_query_searching_buyers(self):\n        \"\"\"Test the get_own_services_query method of the Strategy class where is_searching_for_sellers is False (same as above).\"\"\"\n        # setup\n        is_searching_for_sellers = False\n        expected_query = build_goods_query(\n            list(self.mocked_quantities_by_good_id.keys()),\n            self.mocked_currency_id,\n            self.ledger_id,\n            is_searching_for_sellers,\n        )\n\n        # operation\n        with patch.object(\n            self.skill.skill_context.transactions,\n            \"ownership_state_after_locks\",\n            return_value=self.mocked_ownership_state,\n        ) as mock_ownership:\n            actual_query = self.strategy.get_own_services_query(\n                is_searching_for_sellers\n            )\n\n        # after\n        mock_ownership.assert_any_call(is_seller=not is_searching_for_sellers)\n        assert actual_query == expected_query\n\n    def test__get_proposal_for_query(self):\n        \"\"\"Test the _get_proposal_for_query method of the Strategy class.\"\"\"\n        # setup\n        is_seller = True\n        mocked_query = Query(\n            [Constraint(\"some_attribute_name\", ConstraintType(\"==\", \"some_value\"))],\n            DataModel(\n                \"some_data_model_name\",\n                [\n                    Attribute(\n                        \"some_attribute_name\",\n                        str,\n                        False,\n                        \"Some attribute descriptions.\",\n                    )\n                ],\n            ),\n        )\n\n        proposal_1 = Description(\n            {\n                \"some_attribute_name\": \"some_value\",\n                \"ledger_id\": self.ledger_id,\n                \"price\": 100,\n                \"currency_id\": \"1\",\n                \"fee\": 1,\n                \"nonce\": self.nonce,\n            }\n        )\n        proposal_2 = Description(\n            {\n                \"some_attribute_name\": \"some_value\",\n                \"ledger_id\": self.ledger_id,\n                \"price\": -100,\n                \"currency_id\": \"1\",\n                \"fee\": 2,\n                \"nonce\": self.nonce,\n            }\n        )\n        mocked_candidate_proposals = [proposal_1, proposal_2]\n\n        # operation\n        with patch.object(\n            self.strategy,\n            \"_generate_candidate_proposals\",\n            return_value=mocked_candidate_proposals,\n        ) as mock_candid:\n            actual_query = self.strategy._get_proposal_for_query(\n                mocked_query, is_seller\n            )\n\n        # after\n        mock_candid.assert_any_call(is_seller)\n        assert actual_query in mocked_candidate_proposals\n\n    def test_get_proposal_for_query(self):\n        \"\"\"Test the get_proposal_for_query method of the Strategy class.\"\"\"\n        # setup\n        role = FipaDialogue.Role.SELLER\n        is_seller = True\n\n        mocked_query = Query(\n            [Constraint(\"some_attribute_name\", ConstraintType(\"==\", \"some_value\"))],\n            DataModel(\n                \"some_data_model_name\",\n                [\n                    Attribute(\n                        \"some_attribute_name\",\n                        str,\n                        False,\n                        \"Some attribute descriptions.\",\n                    )\n                ],\n            ),\n        )\n        own_description = Description(\n            {\n                \"some_attribute_name\": \"some_value\",\n                \"ledger_id\": self.ledger_id,\n                \"price\": 100,\n                \"currency_id\": \"1\",\n                \"fee\": 1,\n                \"nonce\": self.nonce,\n            }\n        )\n\n        expected_proposal = own_description\n\n        # operation\n        with patch.object(\n            self.strategy, \"get_own_service_description\", return_value=own_description\n        ) as mock_own:\n            with patch.object(\n                self.strategy, \"_get_proposal_for_query\", return_value=expected_proposal\n            ) as mock_get_proposal:\n                actual_proposal = self.strategy.get_proposal_for_query(\n                    mocked_query, role\n                )\n\n        # after\n        mock_own.assert_any_call(is_supply=is_seller)\n        mock_get_proposal.assert_any_call(mocked_query, is_seller=is_seller)\n        assert actual_proposal == expected_proposal\n\n    def test_generate_candidate_proposals_i(self):\n        \"\"\"Test the _generate_candidate_proposals method of the Strategy class where role is seller.\"\"\"\n        # setup\n        is_searching_for_sellers = True\n        expected_proposed_prices = [463, 411, 1578, 584, 1101, 1244, 1234, 2025, 982]\n\n        # operation\n        with patch.object(\n            self.skill.skill_context.transactions,\n            \"ownership_state_after_locks\",\n            return_value=self.mocked_ownership_state,\n        ) as mock_ownership:\n            actual_proposals = self.strategy._generate_candidate_proposals(\n                is_searching_for_sellers\n            )\n\n        # after\n        mock_ownership.assert_any_call(is_seller=is_searching_for_sellers)\n\n        assert type(actual_proposals) == list\n        assert len(actual_proposals) == 9\n\n        for index in range(9):\n            assert type(actual_proposals[index]) == Description\n            assert actual_proposals[index].values[self.mocked_good_ids[index]] == 1\n            for good_id_index in range(9):\n                if index != good_id_index:\n                    assert (\n                        actual_proposals[index].values[\n                            self.mocked_good_ids[good_id_index]\n                        ]\n                        == 0\n                    )\n            assert (\n                actual_proposals[index].values[\"currency_id\"] == self.mocked_currency_id\n            )\n            assert actual_proposals[index].values[\"ledger_id\"] == self.ledger_id\n            assert (\n                actual_proposals[index].values[\"price\"]\n                == expected_proposed_prices[index]\n            )\n            assert actual_proposals[index].values[\"fee\"] == DEFAULT_TX_FEE_PROPOSAL\n            assert actual_proposals[index].values[\"nonce\"] == str(index + 1)\n\n    def test_generate_candidate_proposals_ii(self):\n        \"\"\"Test the _generate_candidate_proposals method of the Strategy class where role is buyer.\"\"\"\n        # setup\n        expected_proposed_prices = [457, 406, 1561, 577, 1088, 1231, 1220, 2004, 971]\n        is_searching_for_sellers = False\n        # operation\n        with patch.object(\n            self.skill.skill_context.transactions,\n            \"ownership_state_after_locks\",\n            return_value=self.mocked_ownership_state,\n        ) as mock_ownership:\n            with patch.object(self.strategy, \"_tx_fee_proposal\", 0):\n                actual_proposals = self.strategy._generate_candidate_proposals(\n                    is_searching_for_sellers\n                )\n\n        # after\n        mock_ownership.assert_any_call(is_seller=is_searching_for_sellers)\n\n        assert type(actual_proposals) == list\n        assert len(actual_proposals) == len(self.mocked_good_ids)\n\n        for index in range(9):\n            assert type(actual_proposals[index]) == Description\n            assert actual_proposals[index].values[self.mocked_good_ids[index]] == 1\n            for good_id_index in range(9):\n                if index != good_id_index:\n                    assert (\n                        actual_proposals[index].values[\n                            self.mocked_good_ids[good_id_index]\n                        ]\n                        == 0\n                    )\n            assert (\n                actual_proposals[index].values[\"currency_id\"] == self.mocked_currency_id\n            )\n            assert actual_proposals[index].values[\"ledger_id\"] == self.ledger_id\n            assert (\n                actual_proposals[index].values[\"price\"]\n                == expected_proposed_prices[index]\n            )\n            assert actual_proposals[index].values[\"fee\"] == 0  # empty fee is ok here\n            assert actual_proposals[index].values[\"nonce\"] == str(index + 1)\n\n    def test_generate_candidate_proposals_iii(self):\n        \"\"\"Test the _generate_candidate_proposals method of the Strategy class where is_seller and quantity is 0.\"\"\"\n        # setup\n        is_searching_for_sellers = True\n        expected_proposed_price = 982\n\n        mocked_good_quantities = [1, 0, 0, 1, 0, 1, 0, 1, 6]\n        mocked_quantities_by_good_id = dict(\n            zip(self.mocked_good_ids, mocked_good_quantities)\n        )\n        self.mocked_ownership_state._amount_by_currency_id = None\n        self.mocked_ownership_state._quantities_by_good_id = None\n        self.mocked_ownership_state.set(\n            self.mocked_amount_by_currency_id, mocked_quantities_by_good_id\n        )\n\n        # operation\n        with patch.object(\n            self.skill.skill_context.transactions,\n            \"ownership_state_after_locks\",\n            return_value=self.mocked_ownership_state,\n        ) as mock_ownership:\n            actual_proposals = self.strategy._generate_candidate_proposals(\n                is_searching_for_sellers\n            )\n\n        # after\n        mock_ownership.assert_any_call(is_seller=is_searching_for_sellers)\n\n        assert type(actual_proposals) == list\n        assert len(actual_proposals) == 1\n        actual_proposal = actual_proposals[0]\n\n        assert type(actual_proposal) == Description\n        assert actual_proposal.values[self.mocked_good_ids[8]] == 1\n        for good_id_index in range(8):\n            assert actual_proposal.values[self.mocked_good_ids[good_id_index]] == 0\n        assert actual_proposal.values[\"currency_id\"] == self.mocked_currency_id\n        assert actual_proposal.values[\"ledger_id\"] == self.ledger_id\n        assert actual_proposal.values[\"price\"] == expected_proposed_price\n        assert actual_proposal.values[\"fee\"] == DEFAULT_TX_FEE_PROPOSAL\n        assert actual_proposal.values[\"nonce\"] == \"1\"\n\n    def test_generate_candidate_proposals_iv(self):\n        \"\"\"Test the _generate_candidate_proposals method of the Strategy class where proposed price is 0.\"\"\"\n        # setup\n        is_searching_for_sellers = True\n\n        mocked_good_quantities = [2, 0, 0, 1, 0, 1, 0, 1, 0]\n        mocked_quantities_by_good_id = dict(\n            zip(self.mocked_good_ids, mocked_good_quantities)\n        )\n        self.mocked_ownership_state._amount_by_currency_id = None\n        self.mocked_ownership_state._quantities_by_good_id = None\n        self.mocked_ownership_state.set(\n            self.mocked_amount_by_currency_id, mocked_quantities_by_good_id\n        )\n\n        utility_params_by_good_id = {\n            \"13\": -100.0,\n            \"14\": 43700.0,\n            \"15\": 163200.0,\n            \"16\": 59800.0,\n            \"17\": 114900.0,\n            \"18\": 128700.00000000001,\n            \"19\": 126400.00000000001,\n            \"20\": 211500.0,\n            \"21\": 103500.0,\n        }\n        self.mocked_preferences._exchange_params_by_currency_id = None\n        self.mocked_preferences._utility_params_by_good_id = None\n        self.mocked_preferences.set(\n            exchange_params_by_currency_id=self.exchange_params_by_currency_id,\n            utility_params_by_good_id=utility_params_by_good_id,\n        )\n\n        # operation\n        with patch.object(\n            self.skill.skill_context.transactions,\n            \"ownership_state_after_locks\",\n            return_value=self.mocked_ownership_state,\n        ) as mock_ownership:\n            actual_proposals = self.strategy._generate_candidate_proposals(\n                is_searching_for_sellers\n            )\n\n        # after\n        mock_ownership.assert_any_call(is_seller=is_searching_for_sellers)\n        assert actual_proposals == []\n\n    def test_is_profitable_transaction_not_affordable(self):\n        \"\"\"Test the is_profitable_transaction method of the Strategy class where is_affordable_transaction is False.\"\"\"\n        is_searching_for_sellers = False\n        role = FipaDialogue.Role.BUYER\n        proposal = Description(\n            {\n                \"13\": 1,\n                \"14\": 0,\n                \"15\": 0,\n                \"16\": 0,\n                \"17\": 0,\n                \"18\": 0,\n                \"19\": 0,\n                \"20\": 0,\n                \"21\": 0,\n                \"ledger_id\": self.ledger_id,\n                \"price\": 10000000,\n                \"currency_id\": self.mocked_currency_id,\n                \"fee\": 0,\n                \"nonce\": self.nonce,\n            }\n        )\n        terms = self.strategy.terms_from_proposal(\n            proposal, self.sender, self.counterparty, role\n        )\n\n        # operation\n        with patch.object(\n            self.skill.skill_context.transactions,\n            \"ownership_state_after_locks\",\n            return_value=self.mocked_ownership_state,\n        ) as mock_ownership:\n            with patch.object(\n                self.mocked_ownership_state,\n                \"is_affordable_transaction\",\n                return_value=False,\n            ) as mock_is_affordable:\n                is_profitable = self.strategy.is_profitable_transaction(terms, role)\n\n        # after\n        mock_ownership.assert_any_call(is_searching_for_sellers)\n        mock_is_affordable.assert_any_call(terms)\n\n        assert not is_profitable\n\n    def test_is_profitable_transaction_is_affordable(self):\n        \"\"\"Test the is_profitable_transaction method of the Strategy class where is_affordable_transaction is True.\"\"\"\n        is_searching_for_sellers = True\n        role = FipaDialogue.Role.SELLER\n        proposal = Description(\n            {\n                \"13\": 1,\n                \"14\": 0,\n                \"15\": 0,\n                \"16\": 0,\n                \"17\": 0,\n                \"18\": 0,\n                \"19\": 0,\n                \"20\": 0,\n                \"21\": 0,\n                \"ledger_id\": self.ledger_id,\n                \"price\": 463,\n                \"currency_id\": self.mocked_currency_id,\n                \"fee\": 0,\n                \"nonce\": self.nonce,\n            }\n        )\n        terms = self.strategy.terms_from_proposal(\n            proposal, self.sender, self.counterparty, role\n        )\n\n        # operation\n        with patch.object(\n            self.skill.skill_context.transactions,\n            \"ownership_state_after_locks\",\n            return_value=self.mocked_ownership_state,\n        ) as mock_ownership:\n            with patch.object(\n                self.mocked_ownership_state,\n                \"is_affordable_transaction\",\n                return_value=True,\n            ) as mock_is_affordable:\n                is_profitable = self.strategy.is_profitable_transaction(terms, role)\n\n        # after\n        mock_ownership.assert_any_call(is_searching_for_sellers)\n        mock_is_affordable.assert_any_call(terms)\n\n        assert is_profitable\n\n    def test_terms_from_proposal_seller(self):\n        \"\"\"Test the terms_from_proposal method of the Strategy class where is_seller is True.\"\"\"\n        proposal = Description(\n            {\n                \"2\": 5,\n                \"ledger_id\": self.ledger_id,\n                \"price\": 100,\n                \"currency_id\": \"FET\",\n                \"fee\": 1,\n                \"nonce\": self.nonce,\n            }\n        )\n        role = FipaDialogue.Role.SELLER\n        is_seller = True\n\n        expected_terms = Terms(\n            ledger_id=self.ledger_id,\n            sender_address=self.sender,\n            counterparty_address=self.counterparty,\n            amount_by_currency_id={\n                proposal.values[\"currency_id\"]: proposal.values[\"price\"]\n            },\n            quantities_by_good_id={\"2\": -5},\n            is_sender_payable_tx_fee=not is_seller,\n            nonce=self.nonce,\n            fee_by_currency_id={proposal.values[\"currency_id\"]: proposal.values[\"fee\"]},\n        )\n\n        actual_terms = self.strategy.terms_from_proposal(\n            proposal, self.sender, self.counterparty, role\n        )\n\n        assert actual_terms == expected_terms\n\n    def test_terms_from_proposal_buyer(self):\n        \"\"\"Test the terms_from_proposal method of the Strategy class where is_seller is False.\"\"\"\n        proposal = Description(\n            {\n                \"2\": 5,\n                \"ledger_id\": self.ledger_id,\n                \"price\": 100,\n                \"currency_id\": \"FET\",\n                \"fee\": 1,\n                \"nonce\": self.nonce,\n            }\n        )\n        role = FipaDialogue.Role.BUYER\n        is_seller = False\n\n        expected_terms = Terms(\n            ledger_id=self.ledger_id,\n            sender_address=self.sender,\n            counterparty_address=self.counterparty,\n            amount_by_currency_id={\n                proposal.values[\"currency_id\"]: -proposal.values[\"price\"]\n            },\n            quantities_by_good_id={\"2\": 5},\n            is_sender_payable_tx_fee=not is_seller,\n            nonce=self.nonce,\n            fee_by_currency_id={proposal.values[\"currency_id\"]: proposal.values[\"fee\"]},\n        )\n\n        actual_terms = self.strategy.terms_from_proposal(\n            proposal, self.sender, self.counterparty, role\n        )\n\n        assert actual_terms == expected_terms\n\n    def test_kwargs_from_terms_seller_ethereum(self):\n        \"\"\"Test the kwargs_from_terms method of the Strategy class where is_seller is True.\"\"\"\n        is_seller = True\n        terms = Terms(\n            ledger_id=self.ledger_id,\n            sender_address=self.sender,\n            counterparty_address=self.counterparty,\n            amount_by_currency_id={\"1\": 10},\n            quantities_by_good_id={\"2\": -5},\n            is_sender_payable_tx_fee=not is_seller,\n            nonce=self.nonce,\n            fee_by_currency_id={\"1\": 1},\n        )\n\n        expected_kwargs = {\n            \"from_address\": self.sender,\n            \"to_address\": self.counterparty,\n            \"token_ids\": [1, 2],\n            \"from_supplies\": [0, 5],\n            \"to_supplies\": [10, 0],\n            \"value\": 0,\n            \"trade_nonce\": 125,\n            \"signature\": self.signature,\n            \"tx_fee\": 1,\n        }\n\n        actual_kwargs = self.strategy.kwargs_from_terms(\n            terms, self.signature, is_from_terms_sender=True\n        )\n\n        assert actual_kwargs == expected_kwargs\n\n        expected_kwargs = {\n            \"from_address\": self.counterparty,\n            \"to_address\": self.sender,\n            \"token_ids\": [1, 2],\n            \"from_supplies\": [10, 0],\n            \"to_supplies\": [0, 5],\n            \"value\": 0,\n            \"trade_nonce\": 125,\n            \"signature\": self.signature,\n            \"tx_fee\": 1,\n        }\n        actual_kwargs = self.strategy.kwargs_from_terms(\n            terms, self.signature, is_from_terms_sender=False\n        )\n\n        assert actual_kwargs == expected_kwargs\n\n    def test_kwargs_from_terms_buyer_fetchai(self):\n        \"\"\"Test the kwargs_from_terms method of the Strategy class where is_seller is False (no difference with seller).\"\"\"\n        is_seller = False\n        terms = Terms(\n            ledger_id=self.ledger_id,\n            sender_address=self.sender,\n            counterparty_address=self.counterparty,\n            amount_by_currency_id={\"1\": 10},\n            quantities_by_good_id={\"2\": -5},\n            is_sender_payable_tx_fee=not is_seller,\n            nonce=self.nonce,\n            fee_by_currency_id={\"1\": 1},\n        )\n\n        expected_kwargs = {\n            \"from_address\": self.sender,\n            \"to_address\": self.counterparty,\n            \"token_ids\": [1, 2],\n            \"from_supplies\": [0, 5],\n            \"to_supplies\": [10, 0],\n            \"value\": 1,\n            \"trade_nonce\": 125,\n            \"from_pubkey\": self.sender_pk,\n            \"to_pubkey\": self.counterparty_pk,\n            \"tx_fee\": 1,\n        }\n\n        actual_kwargs = self.strategy.kwargs_from_terms(\n            terms,\n            sender_public_key=self.sender_pk,\n            counterparty_public_key=self.counterparty_pk,\n        )\n\n        assert actual_kwargs == expected_kwargs\n\n    def test_kwargs_from_terms_i(self):\n        \"\"\"Test the kwargs_from_terms method of the Strategy class where sender's IS and counterparty's public key is NOT provided.\"\"\"\n        is_seller = True\n        terms = Terms(\n            ledger_id=self.ledger_id,\n            sender_address=self.sender,\n            counterparty_address=self.counterparty,\n            amount_by_currency_id={\"1\": 10},\n            quantities_by_good_id={\"2\": -5},\n            is_sender_payable_tx_fee=not is_seller,\n            nonce=self.nonce,\n            fee_by_currency_id={\"1\": 1},\n        )\n\n        with pytest.raises(\n            AEAEnforceError,\n            match=\"Either provide both sender's and counterparty's public-keys or neither's.\",\n        ):\n            self.strategy.kwargs_from_terms(\n                terms,\n                self.signature,\n                is_from_terms_sender=True,\n                sender_public_key=\"some_public_key\",\n            )\n\n    def test_kwargs_from_terms_ii(self):\n        \"\"\"Test the kwargs_from_terms method of the Strategy class where sender's is NOT and counterparty's public key IS provided.\"\"\"\n        is_seller = True\n        terms = Terms(\n            ledger_id=self.ledger_id,\n            sender_address=self.sender,\n            counterparty_address=self.counterparty,\n            amount_by_currency_id={\"1\": 10},\n            quantities_by_good_id={\"2\": -5},\n            is_sender_payable_tx_fee=not is_seller,\n            nonce=self.nonce,\n            fee_by_currency_id={\"1\": 1},\n        )\n\n        with pytest.raises(\n            AEAEnforceError,\n            match=\"Either provide both sender's and counterparty's public-keys or neither's.\",\n        ):\n            self.strategy.kwargs_from_terms(\n                terms,\n                self.signature,\n                is_from_terms_sender=True,\n                counterparty_public_key=\"some_public_key\",\n            )\n\n    def test_kwargs_from_terms_iii(self):\n        \"\"\"Test the kwargs_from_terms method of the Strategy class where signature IS and a public_key is NOT provided.\"\"\"\n        is_seller = True\n        terms = Terms(\n            ledger_id=self.ledger_id,\n            sender_address=self.sender,\n            counterparty_address=self.counterparty,\n            amount_by_currency_id={\"1\": 10},\n            quantities_by_good_id={\"2\": -5},\n            is_sender_payable_tx_fee=not is_seller,\n            nonce=self.nonce,\n            fee_by_currency_id={\"1\": 1},\n        )\n\n        with pytest.raises(\n            AEAEnforceError,\n            match=re.escape(\n                \"Either provide signature (for Ethereum-based TAC) or sender and counterparty's public keys (for Fetchai-based TAC), or neither (for and non-contract-based Tac)\"\n            ),\n        ):\n            self.strategy.kwargs_from_terms(\n                terms,\n                self.signature,\n                is_from_terms_sender=True,\n                sender_public_key=\"some_public_key\",\n                counterparty_public_key=\"some_other_public_key\",\n            )\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_tac_negotiation/test_transactions.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the Transactions class of the tac negotiation skill.\"\"\"\n\nimport datetime\nimport logging\nfrom pathlib import Path\nfrom typing import Deque, Tuple, cast\nfrom unittest.mock import Mock, patch\n\nimport pytest\n\nfrom aea.decision_maker.gop import GoalPursuitReadiness, OwnershipState, Preferences\nfrom aea.exceptions import AEAEnforceError\nfrom aea.helpers.transaction.base import Terms\nfrom aea.protocols.dialogue.base import DialogueLabel\nfrom aea.test_tools.test_skill import BaseSkillTestCase, COUNTERPARTY_AGENT_ADDRESS\n\nfrom packages.fetchai.skills.tac_negotiation.dialogues import FipaDialogue\nfrom packages.fetchai.skills.tac_negotiation.transactions import Transactions\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass TestTransactions(BaseSkillTestCase):\n    \"\"\"Test Transactions class of tac negotiation.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"tac_negotiation\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        tac_dm_context_kwargs = {\n            \"goal_pursuit_readiness\": GoalPursuitReadiness(),\n            \"ownership_state\": OwnershipState(),\n            \"preferences\": Preferences(),\n        }\n        super().setup(dm_context_kwargs=tac_dm_context_kwargs)\n        cls.pending_transaction_timeout = 30\n        cls.transactions = Transactions(\n            pending_transaction_timeout=cls.pending_transaction_timeout,\n            name=\"transactions\",\n            skill_context=cls._skill.skill_context,\n        )\n\n        cls.nonce = \"125\"\n        cls.sender = \"some_sender_address\"\n        cls.counterparty = \"some_counterparty_address\"\n        cls.ledger_id = \"some_ledger_id\"\n        cls.terms = Terms(\n            ledger_id=cls.ledger_id,\n            sender_address=cls.sender,\n            counterparty_address=cls.counterparty,\n            amount_by_currency_id={\"1\": 10},\n            quantities_by_good_id={\"2\": -5},\n            is_sender_payable_tx_fee=True,\n            nonce=cls.nonce,\n            fee_by_currency_id={\"1\": 1},\n        )\n        cls.dialogue_label = DialogueLabel(\n            (\"\", \"\"),\n            COUNTERPARTY_AGENT_ADDRESS,\n            cls._skill.skill_context.agent_address,\n        )\n        cls.proposal_id = 5\n        cls.transaction_id = \"some_transaction_id\"\n\n    def test_simple_properties(self):\n        \"\"\"Test the properties of Transactions class.\"\"\"\n        assert self.transactions.pending_proposals == {}\n        assert self.transactions.pending_initial_acceptances == {}\n\n    def test_get_next_nonce(self):\n        \"\"\"Test the get_next_nonce method of the Transactions class.\"\"\"\n        assert self.transactions.get_next_nonce() == \"1\"\n        assert self.transactions._nonce == 1\n\n    def test_update_confirmed_transactions(self):\n        \"\"\"Test the update_confirmed_transactions method of the Transactions class.\"\"\"\n        # setup\n        self.skill.skill_context._get_agent_context().shared_state[\n            \"confirmed_tx_ids\"\n        ] = [self.transaction_id]\n        self.transactions._locked_txs[self.transaction_id] = self.terms\n        self.transactions._locked_txs_as_buyer[self.transaction_id] = self.terms\n        self.transactions._locked_txs_as_seller[self.transaction_id] = self.terms\n\n        # operation\n        self.transactions.update_confirmed_transactions()\n\n        # after\n        assert self.transactions._locked_txs == {}\n        assert self.transactions._locked_txs_as_buyer == {}\n        assert self.transactions._locked_txs_as_seller == {}\n\n    def test_cleanup_pending_transactions_i(self):\n        \"\"\"Test the cleanup_pending_transactions method of the Transactions class where _last_update_for_transactions is NOT empty.\"\"\"\n        # setup\n        datetime_mock = Mock(wraps=datetime.datetime)\n        datetime_mock.now.return_value = datetime.datetime.strptime(\n            \"01 01 2020  00:03\", \"%d %m %Y %H:%M\"\n        )\n        with patch(\"datetime.datetime\", new=datetime_mock):\n            self.transactions._register_transaction_with_time(self.transaction_id)\n\n        self.transactions._locked_txs[self.transaction_id] = self.terms\n        self.transactions._locked_txs_as_buyer[self.transaction_id] = self.terms\n        self.transactions._locked_txs_as_seller[self.transaction_id] = self.terms\n\n        # operation\n        with patch.object(self.skill.skill_context.logger, \"log\") as mock_logger:\n            self.transactions.cleanup_pending_transactions()\n\n        # after\n        mock_logger.assert_any_call(\n            logging.DEBUG,\n            f\"removing transaction from pending list: {self.transaction_id}\",\n        )\n        assert self.transactions._locked_txs == {}\n        assert self.transactions._locked_txs_as_buyer == {}\n        assert self.transactions._locked_txs_as_seller == {}\n\n    def test_cleanup_pending_transactions_ii(self):\n        \"\"\"Test the cleanup_pending_transactions method of the Transactions class where _last_update_for_transactions is empty.\"\"\"\n        # setup\n        cast(\n            Deque[Tuple[datetime.datetime, str]],\n            self.transactions._last_update_for_transactions,\n        )\n\n        assert self.transactions._locked_txs == {}\n        assert self.transactions._locked_txs_as_buyer == {}\n        assert self.transactions._locked_txs_as_seller == {}\n\n        # operation\n        self.transactions.cleanup_pending_transactions()\n\n        # after\n        assert self.transactions._locked_txs == {}\n        assert self.transactions._locked_txs_as_buyer == {}\n        assert self.transactions._locked_txs_as_seller == {}\n\n    def test_add_pending_proposal_i(self):\n        \"\"\"Test the add_pending_proposal method of the Transactions class.\"\"\"\n        # before\n        assert self.dialogue_label not in self.transactions._pending_proposals\n\n        # operation\n        self.transactions.add_pending_proposal(\n            self.dialogue_label, self.proposal_id, self.terms\n        )\n\n        # after\n        assert (\n            self.transactions._pending_proposals[self.dialogue_label][self.proposal_id]\n            == self.terms\n        )\n\n    def test_add_pending_proposal_ii(self):\n        \"\"\"Test the add_pending_proposal method of the Transactions class where dialogue_label IS in _pending_proposals.\"\"\"\n        # setup\n        self.transactions._pending_proposals[self.dialogue_label] = {1: self.terms}\n\n        # operation\n        with pytest.raises(\n            AEAEnforceError,\n            match=\"Proposal is already in the list of pending proposals.\",\n        ):\n            self.transactions.add_pending_proposal(\n                self.dialogue_label, self.proposal_id, self.terms\n            )\n\n    def test_add_pending_proposal_iii(self):\n        \"\"\"Test the add_pending_proposal method of the Transactions class where proposal_id IS in _pending_proposals.\"\"\"\n        # setup\n        self.transactions._pending_proposals[self.dialogue_label][\n            self.proposal_id\n        ] = self.terms\n\n        # operation\n        with pytest.raises(\n            AEAEnforceError,\n            match=\"Proposal is already in the list of pending proposals.\",\n        ):\n            self.transactions.add_pending_proposal(\n                self.dialogue_label, self.proposal_id, self.terms\n            )\n\n    def test_pop_pending_proposal_i(self):\n        \"\"\"Test the pop_pending_proposal method of the Transactions class.\"\"\"\n        # setup\n        self.transactions.add_pending_proposal(\n            self.dialogue_label, self.proposal_id, self.terms\n        )\n\n        # operation\n        actual_terms = self.transactions.pop_pending_proposal(\n            self.dialogue_label, self.proposal_id\n        )\n\n        # after\n        assert actual_terms == self.terms\n        assert (\n            self.proposal_id\n            not in self.transactions._pending_proposals[self.dialogue_label]\n        )\n\n    def test_pop_pending_proposal_ii(self):\n        \"\"\"Test the pop_pending_proposal method of the Transactions class where dialogue_label IS in _pending_proposals.\"\"\"\n        # setup\n        self.transactions.add_pending_proposal(\n            self.dialogue_label, self.proposal_id, self.terms\n        )\n        self.transactions._pending_proposals = {}\n\n        # operation\n        with pytest.raises(\n            AEAEnforceError,\n            match=\"Cannot find the proposal in the list of pending proposals.\",\n        ):\n            assert self.transactions.pop_pending_proposal(\n                self.dialogue_label, self.proposal_id\n            )\n\n    def test_pop_pending_proposal_iii(self):\n        \"\"\"Test the pop_pending_proposal method of the Transactions class where dialogue_label and proposal_id IS in _pending_proposals.\"\"\"\n        # setup\n        self.transactions.add_pending_proposal(\n            self.dialogue_label, self.proposal_id, self.terms\n        )\n        self.transactions._pending_proposals[self.dialogue_label] = {1: self.terms}\n\n        # operation\n        with pytest.raises(\n            AEAEnforceError,\n            match=\"Cannot find the proposal in the list of pending proposals.\",\n        ):\n            assert self.transactions.pop_pending_proposal(\n                self.dialogue_label, self.proposal_id\n            )\n\n    def test_add_pending_initial_acceptance_i(self):\n        \"\"\"Test the add_pending_initial_acceptance method of the Transactions class.\"\"\"\n        # before\n        assert self.transactions._pending_initial_acceptances == {}\n\n        # operation\n        self.transactions.add_pending_initial_acceptance(\n            self.dialogue_label,\n            self.proposal_id,\n            self.terms,\n        )\n\n        # after\n        assert (\n            self.transactions._pending_initial_acceptances[self.dialogue_label][\n                self.proposal_id\n            ]\n            == self.terms\n        )\n\n    def test_add_pending_initial_acceptance_ii(self):\n        \"\"\"Test the add_pending_initial_acceptance method of the Transactions class where dialogue_label IS in _pending_initial_acceptances.\"\"\"\n        # setup\n        self.transactions._pending_initial_acceptances[self.dialogue_label] = {\n            1: self.terms\n        }\n\n        # operation\n        with pytest.raises(\n            AEAEnforceError,\n            match=\"Initial acceptance is already in the list of pending initial acceptances.\",\n        ):\n            self.transactions.add_pending_initial_acceptance(\n                self.dialogue_label,\n                self.proposal_id,\n                self.terms,\n            )\n\n    def test_add_pending_initial_acceptance_iii(self):\n        \"\"\"Test the add_pending_initial_acceptance method of the Transactions class where dialogue_label and proposal_id IS in _pending_initial_acceptances.\"\"\"\n        # setup\n        self.transactions._pending_initial_acceptances[self.dialogue_label] = {\n            self.proposal_id: self.terms\n        }\n\n        # operation\n        with pytest.raises(\n            AEAEnforceError,\n            match=\"Initial acceptance is already in the list of pending initial acceptances.\",\n        ):\n            self.transactions.add_pending_initial_acceptance(\n                self.dialogue_label,\n                self.proposal_id,\n                self.terms,\n            )\n\n    def test_pop_pending_initial_acceptance_i(self):\n        \"\"\"Test the pop_pending_initial_acceptance method of the Transactions class.\"\"\"\n        # setup\n        self.transactions.add_pending_initial_acceptance(\n            self.dialogue_label,\n            self.proposal_id,\n            self.terms,\n        )\n\n        # operation\n        actual_terms = self.transactions.pop_pending_initial_acceptance(\n            self.dialogue_label, self.proposal_id\n        )\n\n        # after\n        assert actual_terms == self.terms\n        assert (\n            self.proposal_id\n            not in self.transactions._pending_proposals[self.dialogue_label]\n        )\n\n    def test_pop_pending_initial_acceptance_ii(self):\n        \"\"\"Test the pop_pending_initial_acceptance method of the Transactions class where dialogue_label IS in _pending_initial_acceptances.\"\"\"\n        # setup\n        self.transactions.add_pending_initial_acceptance(\n            self.dialogue_label,\n            self.proposal_id,\n            self.terms,\n        )\n        self.transactions._pending_initial_acceptances = {}\n\n        # operation\n        with pytest.raises(\n            AEAEnforceError,\n            match=\"Cannot find the initial acceptance in the list of pending initial acceptances.\",\n        ):\n            assert self.transactions.pop_pending_initial_acceptance(\n                self.dialogue_label, self.proposal_id\n            )\n\n    def test_pop_pending_initial_acceptance_iii(self):\n        \"\"\"Test the pop_pending_initial_acceptance method of the Transactions class where dialogue_label and proposal_id IS in _pending_initial_acceptances.\"\"\"\n        # setup\n        self.transactions.add_pending_initial_acceptance(\n            self.dialogue_label,\n            self.proposal_id,\n            self.terms,\n        )\n        self.transactions._pending_initial_acceptances[self.dialogue_label] = {\n            1: self.terms\n        }\n\n        # operation\n        with pytest.raises(\n            AEAEnforceError,\n            match=\"Cannot find the initial acceptance in the list of pending initial acceptances.\",\n        ):\n            assert self.transactions.pop_pending_initial_acceptance(\n                self.dialogue_label, self.proposal_id\n            )\n\n    def test_register_transaction_with_time(self):\n        \"\"\"Test the _register_transaction_with_time method of the Transactions class.\"\"\"\n        # setup\n        datetime_mock = Mock(wraps=datetime.datetime)\n        mocked_now = datetime.datetime.strptime(\"01 01 2020  00:03\", \"%d %m %Y %H:%M\")\n        datetime_mock.now.return_value = mocked_now\n\n        # operation\n        with patch(\"datetime.datetime\", new=datetime_mock):\n            self.transactions._register_transaction_with_time(self.transaction_id)\n\n        # after\n        assert (mocked_now, self.transaction_id,)[\n            1\n        ] == self.transactions._last_update_for_transactions[0][1]\n\n    def test_add_locked_tx_seller(self):\n        \"\"\"Test the add_locked_tx method of the Transactions class as Seller.\"\"\"\n        # setup\n        datetime_mock = Mock(wraps=datetime.datetime)\n        mocked_now = datetime.datetime.strptime(\"01 01 2020  00:03\", \"%d %m %Y %H:%M\")\n        datetime_mock.now.return_value = mocked_now\n\n        # operation\n        with patch(\"datetime.datetime\", new=datetime_mock):\n            self.transactions.add_locked_tx(self.terms, FipaDialogue.Role.SELLER)\n\n        # after\n        assert (mocked_now, self.terms.id,)[\n            1\n        ] == self.transactions._last_update_for_transactions[0][1]\n        assert self.transactions._locked_txs[self.terms.id] == self.terms\n        assert self.transactions._locked_txs_as_seller[self.terms.id] == self.terms\n        assert self.terms.id not in self.transactions._locked_txs_as_buyer\n\n    def test_add_locked_tx_buyer(self):\n        \"\"\"Test the add_locked_tx method of the Transactions class as Seller.\"\"\"\n        # setup\n        datetime_mock = Mock(wraps=datetime.datetime)\n        mocked_now = datetime.datetime.strptime(\"01 01 2020  00:03\", \"%d %m %Y %H:%M\")\n        datetime_mock.now.return_value = mocked_now\n\n        # operation\n        with patch(\"datetime.datetime\", new=datetime_mock):\n            self.transactions.add_locked_tx(self.terms, FipaDialogue.Role.BUYER)\n\n        # after\n        assert (mocked_now, self.terms.id,)[\n            1\n        ] == self.transactions._last_update_for_transactions[0][1]\n        assert self.transactions._locked_txs[self.terms.id] == self.terms\n        assert self.transactions._locked_txs_as_buyer[self.terms.id] == self.terms\n        assert self.terms.id not in self.transactions._locked_txs_as_seller\n\n    def test_add_locked_tx_fails(self):\n        \"\"\"Test the add_locked_tx method of the Transactions class where transaction_id IS in _locked_txs.\"\"\"\n        # setup\n        self.transactions._locked_txs[self.terms.id] = self.terms\n\n        datetime_mock = Mock(wraps=datetime.datetime)\n        mocked_now = datetime.datetime.strptime(\"01 01 2020  00:03\", \"%d %m %Y %H:%M\")\n        datetime_mock.now.return_value = mocked_now\n\n        # operation\n        with patch(\"datetime.datetime\", new=datetime_mock):\n            with pytest.raises(\n                AEAEnforceError,\n                match=\"This transaction is already a locked transaction.\",\n            ):\n                self.transactions.add_locked_tx(self.terms, FipaDialogue.Role.BUYER)\n\n        # after\n        assert (\n            mocked_now,\n            self.terms.id,\n        ) not in self.transactions._last_update_for_transactions\n        assert self.terms.id not in self.transactions._locked_txs_as_buyer\n        assert self.terms.id not in self.transactions._locked_txs_as_seller\n\n    def test_pop_locked_tx(self):\n        \"\"\"Test the pop_locked_tx method of the Transactions class.\"\"\"\n        # setup\n        self.transactions.add_locked_tx(self.terms, FipaDialogue.Role.BUYER)\n\n        # before\n        assert self.terms.id in self.transactions._locked_txs\n        assert self.terms.id in self.transactions._locked_txs_as_buyer\n        assert self.terms.id not in self.transactions._locked_txs_as_seller\n\n        # operation\n        actual_terms = self.transactions.pop_locked_tx(self.terms)\n\n        # after\n        assert actual_terms == self.terms\n\n        assert self.terms.id not in self.transactions._locked_txs\n        assert self.terms.id not in self.transactions._locked_txs_as_buyer\n        assert self.terms.id not in self.transactions._locked_txs_as_seller\n\n    def test_pop_locked_tx_fails(self):\n        \"\"\"Test the pop_locked_tx method of the Transactions class where terms.id is NOT in _locked_txs.\"\"\"\n        # before\n        assert self.terms.id not in self.transactions._locked_txs\n        assert self.terms.id not in self.transactions._locked_txs_as_buyer\n        assert self.terms.id not in self.transactions._locked_txs_as_seller\n\n        # operation\n        with pytest.raises(\n            AEAEnforceError,\n            match=\"Cannot find this transaction in the list of locked transactions.\",\n        ):\n            self.transactions.pop_locked_tx(self.terms)\n\n        # after\n        assert self.terms.id not in self.transactions._locked_txs\n        assert self.terms.id not in self.transactions._locked_txs_as_buyer\n        assert self.terms.id not in self.transactions._locked_txs_as_seller\n\n    def test_ownership_state_after_locks(self):\n        \"\"\"Test the ownership_state_after_locks method of the Transactions class.\"\"\"\n        # setup\n        is_seller = True\n        self.transactions._locked_txs_as_seller[self.transaction_id] = self.terms\n        expected_apply_transactions_argument = [self.terms]\n        expected_ownership_state = OwnershipState()\n\n        # operation\n        with patch.object(\n            self.skill.skill_context.decision_maker_handler_context.ownership_state,\n            \"apply_transactions\",\n            return_value=expected_ownership_state,\n        ) as mock_apply_transactions:\n            actual_ownership_states = self.transactions.ownership_state_after_locks(\n                is_seller\n            )\n\n        # after\n        mock_apply_transactions.assert_any_call(expected_apply_transactions_argument)\n        assert actual_ownership_states == expected_ownership_state\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_tac_participation/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"The tests module contains the tests of the packages/skills/tac_participation dir.\"\"\"\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_tac_participation/test_behaviours.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the behaviour classes of the tac participation skill.\"\"\"\n\nimport logging\nfrom collections import OrderedDict\nfrom pathlib import Path\nfrom typing import cast\nfrom unittest.mock import patch\n\nimport pytest\n\nfrom aea.helpers.transaction.base import Terms\nfrom aea.protocols.dialogue.base import DialogueMessage\nfrom aea.test_tools.test_skill import BaseSkillTestCase, COUNTERPARTY_AGENT_ADDRESS\n\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.protocols.tac.message import TacMessage\nfrom packages.fetchai.skills.tac_participation.behaviours import (\n    TacSearchBehaviour,\n    TransactionProcessBehaviour,\n)\nfrom packages.fetchai.skills.tac_participation.dialogues import TacDialogues\nfrom packages.fetchai.skills.tac_participation.game import Game, Phase\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass TestTacSearchBehaviour(BaseSkillTestCase):\n    \"\"\"Test tac behaviour of tac participation.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"tac_participation\")\n    is_agent_to_agent_messages = True\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.tac_search_behaviour = cast(\n            TacSearchBehaviour, cls._skill.skill_context.behaviours.tac_search\n        )\n        cls.game = cast(Game, cls._skill.skill_context.game)\n        cls.logger = cls.tac_search_behaviour.context.logger\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the tac_search behaviour.\"\"\"\n        assert self.tac_search_behaviour.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_act_i(self):\n        \"\"\"Test the act method of the tac_search behaviour where phase is not PRE_GAME.\"\"\"\n        # setup\n        self.game._phase = Phase.GAME\n\n        # operation\n        with patch.object(self.logger, \"log\"):\n            self.tac_search_behaviour.act()\n\n        # after\n        assert self.game.phase == Phase.GAME\n        self.assert_quantity_in_outbox(0)\n\n    def test_act_ii(self):\n        \"\"\"Test the act method of the tac_search behaviour where phase is PRE_GAME.\"\"\"\n        # setup\n        self.game._phase = Phase.PRE_GAME\n        mocked_query = \"some_query\"\n\n        # operation\n        with patch.object(self.game, \"get_game_query\", return_value=mocked_query):\n            with patch.object(self.logger, \"log\") as mock_logger:\n                self.tac_search_behaviour.act()\n\n        # after\n        self.assert_quantity_in_outbox(1)\n\n        # _search_for_tac\n        message = self.get_message_from_outbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=OefSearchMessage,\n            performative=OefSearchMessage.Performative.SEARCH_SERVICES,\n            to=self.skill.skill_context.search_service_address,\n            sender=str(self.skill.skill_context.skill_id),\n            query=mocked_query,\n        )\n        assert has_attributes, error_str\n\n        mock_logger.assert_any_call(\n            logging.INFO, f\"searching for TAC, search_id={message.dialogue_reference}\"\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the tac_search behaviour.\"\"\"\n        assert self.tac_search_behaviour.teardown() is None\n        self.assert_quantity_in_outbox(0)\n\n\nclass TestTransactionProcessBehaviour(BaseSkillTestCase):\n    \"\"\"Test tac behaviour of tac participation.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"tac_participation\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.transaction_process_behaviour = cast(\n            TransactionProcessBehaviour,\n            cls._skill.skill_context.behaviours.transaction_processing,\n        )\n        cls.game = cast(Game, cls._skill.skill_context.game)\n        cls.logger = cls.transaction_process_behaviour.context.logger\n\n        cls.tac_dialogues = cast(TacDialogues, cls._skill.skill_context.tac_dialogues)\n\n        cls.list_of_tac_messages = (\n            DialogueMessage(\n                TacMessage.Performative.REGISTER, {\"agent_name\": \"some_agent_name\"}\n            ),\n            DialogueMessage(\n                TacMessage.Performative.GAME_DATA,\n                {\n                    \"amount_by_currency_id\": {\"FET\": 1},\n                    \"exchange_params_by_currency_id\": {\"FET\": 1.0},\n                    \"quantities_by_good_id\": {\"2\": 10},\n                    \"utility_params_by_good_id\": {\"2\": 1.0},\n                    \"fee_by_currency_id\": {\"1\": 1},\n                    \"agent_addr_to_name\": {\n                        COUNTERPARTY_AGENT_ADDRESS: \"some_agent_name\"\n                    },\n                    \"currency_id_to_name\": {\"1\": \"FETCH\"},\n                    \"good_id_to_name\": {\"2\": \"Good_1\"},\n                    \"version_id\": \"v1\",\n                },\n            ),\n        )\n\n        cls.tx_ids = [\"tx_1\", \"tx_2\"]\n        cls.terms_1 = Terms(\n            \"some_ledger_id\",\n            \"some_sender_address_1\",\n            \"some_counterparty_address_1\",\n            {\"1\": 10},\n            {\"2\": 5},\n            \"some_nonce_1\",\n            fee_by_currency_id={\"1\": 1},\n        )\n        cls.terms_2 = Terms(\n            \"some_ledger_id\",\n            \"some_sender_address_2\",\n            \"some_counterparty_address_2\",\n            {\"1\": 11},\n            {\"2\": 6},\n            \"some_nonce_2\",\n            fee_by_currency_id={\"1\": 2},\n        )\n        cls.terms = [cls.terms_1, cls.terms_2]\n        cls.sender_signatures = [\"sender_signature_1\", \"sender_signature_2\"]\n        cls.counterparty_signatures = [\n            \"counterparty_signature_1\",\n            \"counterparty_signature_2\",\n        ]\n\n        cls.txs = OrderedDict(\n            {\n                cls.tx_ids[0]: {\n                    \"terms\": cls.terms[0],\n                    \"sender_signature\": cls.sender_signatures[0],\n                    \"counterparty_signature\": cls.counterparty_signatures[0],\n                },\n                cls.tx_ids[1]: {\n                    \"terms\": cls.terms[1],\n                    \"sender_signature\": cls.sender_signatures[1],\n                    \"counterparty_signature\": cls.counterparty_signatures[1],\n                },\n            }\n        )\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the transaction_process behaviour.\"\"\"\n        assert self.transaction_process_behaviour.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_act_i(self):\n        \"\"\"Test the act method of the transaction_process behaviour where phase is not GAME.\"\"\"\n        # setup\n        self.game._phase = Phase.PRE_GAME\n\n        # operation\n        with patch.object(self.logger, \"log\"):\n            self.transaction_process_behaviour.act()\n\n        # after\n        assert self.game.phase == Phase.PRE_GAME\n        self.assert_quantity_in_outbox(0)\n\n    def test_act_ii(self):\n        \"\"\"Test the act method of the transaction_process behaviour where phase is GAME.\"\"\"\n        # setup\n        self.game._phase = Phase.GAME\n        no_tx = len(self.txs)\n        self.skill.skill_context._agent_context._shared_state = {\n            \"transactions\": self.txs\n        }\n        tac_dialogue = self.prepare_skill_dialogue(\n            self.tac_dialogues,\n            self.list_of_tac_messages,\n        )\n        self.game._tac_dialogue = tac_dialogue\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.transaction_process_behaviour.act()\n\n        # after\n        self.assert_quantity_in_outbox(no_tx)\n\n        # _process_transactions\n        count = 0\n        while count != no_tx:\n            message = self.get_message_from_outbox()\n            mock_logger.assert_any_call(\n                logging.INFO,\n                f\"sending transaction {self.tx_ids[count]} to controller, message={message}.\",\n            )\n            has_attributes, error_str = self.message_has_attributes(\n                actual_message=message,\n                message_type=TacMessage,\n                performative=TacMessage.Performative.TRANSACTION,\n                to=COUNTERPARTY_AGENT_ADDRESS,\n                sender=self.skill.skill_context.agent_address,\n                transaction_id=self.tx_ids[count],\n                ledger_id=self.terms[count].ledger_id,\n                sender_address=self.terms[count].sender_address,\n                counterparty_address=self.terms[count].counterparty_address,\n                amount_by_currency_id=self.terms[count].amount_by_currency_id,\n                fee_by_currency_id=self.terms[count].fee_by_currency_id,\n                quantities_by_good_id=self.terms[count].quantities_by_good_id,\n                sender_signature=self.sender_signatures[count],\n                counterparty_signature=self.counterparty_signatures[count],\n                nonce=self.terms[count].nonce,\n            )\n            assert has_attributes, error_str\n            count += 1\n\n    def test_process_transactions_tac_dialogue_is_empty(self):\n        \"\"\"Test the _process_transactions method of the transaction_process behaviour where last message of tac_dialogue is None.\"\"\"\n        # setup\n        self.game._phase = Phase.GAME\n        self.skill.skill_context._agent_context._shared_state = {\n            \"transactions\": self.txs\n        }\n\n        tac_dialogue = self.prepare_skill_dialogue(\n            self.tac_dialogues,\n            self.list_of_tac_messages,\n        )\n\n        tac_dialogue._incoming_messages = []\n        tac_dialogue._outgoing_messages = []\n\n        self.game._tac_dialogue = tac_dialogue\n\n        # operation\n        with pytest.raises(ValueError, match=\"No last message available.\"):\n            self.transaction_process_behaviour.act()\n\n    def test_process_transactions_invalid_tx(self):\n        \"\"\"Test the _process_transactions method of the transaction_process behaviour where transactions are None.\"\"\"\n        # setup\n        self.game._phase = Phase.GAME\n        self.skill.skill_context._agent_context._shared_state = {\n            \"transactions\": {self.tx_ids[0]: None, self.tx_ids[1]: None}\n        }\n\n        tac_dialogue = self.prepare_skill_dialogue(\n            self.tac_dialogues,\n            self.list_of_tac_messages,\n        )\n        self.game._tac_dialogue = tac_dialogue\n\n        # operation\n        with pytest.raises(ValueError, match=f\"Tx for id={self.tx_ids[0]} not found.\"):\n            self.transaction_process_behaviour.act()\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the transaction_process behaviour.\"\"\"\n        assert self.transaction_process_behaviour.teardown() is None\n        self.assert_quantity_in_outbox(0)\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_tac_participation/test_dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the dialogue classes of the tac participation skill.\"\"\"\n\nfrom pathlib import Path\nfrom typing import cast\n\nfrom aea.test_tools.test_skill import BaseSkillTestCase, COUNTERPARTY_AGENT_ADDRESS\n\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.protocols.state_update.message import StateUpdateMessage\nfrom packages.fetchai.protocols.tac.message import TacMessage\nfrom packages.fetchai.skills.tac_participation.dialogues import (\n    OefSearchDialogue,\n    OefSearchDialogues,\n    StateUpdateDialogue,\n    StateUpdateDialogues,\n    TacDialogue,\n    TacDialogues,\n)\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass TestDialogues(BaseSkillTestCase):\n    \"\"\"Test dialogue classes of tac participation.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"tac_participation\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.oef_search_dialogues = cast(\n            OefSearchDialogues, cls._skill.skill_context.oef_search_dialogues\n        )\n        cls.state_update_dialogues = cast(\n            StateUpdateDialogues, cls._skill.skill_context.state_update_dialogues\n        )\n        cls.tac_dialogues = cast(TacDialogues, cls._skill.skill_context.tac_dialogues)\n\n    def test_oef_search_dialogues(self):\n        \"\"\"Test the OefSearchDialogues class.\"\"\"\n        _, dialogue = self.oef_search_dialogues.create(\n            counterparty=COUNTERPARTY_AGENT_ADDRESS,\n            performative=OefSearchMessage.Performative.SEARCH_SERVICES,\n            query=\"some_query\",\n        )\n        assert dialogue.role == OefSearchDialogue.Role.AGENT\n        assert dialogue.self_address == str(self.skill.skill_context.skill_id)\n\n    def test_state_update_dialogues(self):\n        \"\"\"Test the StateUpdateDialogues class.\"\"\"\n        _, dialogue = self.state_update_dialogues.create(\n            counterparty=COUNTERPARTY_AGENT_ADDRESS,\n            performative=StateUpdateMessage.Performative.INITIALIZE,\n            exchange_params_by_currency_id={\"some_currency_id\": 1.0},\n            utility_params_by_good_id={\"some_good_id\": 2.0},\n            amount_by_currency_id={\"some_currency_id\": 10},\n            quantities_by_good_id={\"some_good_id\": 5},\n        )\n        assert dialogue.role == StateUpdateDialogue.Role.SKILL\n        assert dialogue.self_address == str(self.skill.skill_context.skill_id)\n\n    def test_tac_dialogues(self):\n        \"\"\"Test the TacDialogues class.\"\"\"\n        _, dialogue = self.tac_dialogues.create(\n            counterparty=COUNTERPARTY_AGENT_ADDRESS,\n            performative=TacMessage.Performative.REGISTER,\n            agent_name=\"some_agent_name\",\n        )\n        assert dialogue.role == TacDialogue.Role.PARTICIPANT\n        assert dialogue.self_address == self.skill.skill_context.agent_address\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_tac_participation/test_game.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the models of the tac participation skill.\"\"\"\n\nimport logging\nfrom pathlib import Path\nfrom typing import cast\nfrom unittest.mock import patch\n\nimport pytest\n\nfrom aea.exceptions import AEAEnforceError\nfrom aea.helpers.search.models import Constraint, ConstraintType, Location, Query\nfrom aea.test_tools.test_skill import BaseSkillTestCase\n\nfrom packages.fetchai.protocols.state_update.message import StateUpdateMessage\nfrom packages.fetchai.protocols.tac.message import TacMessage\nfrom packages.fetchai.skills.tac_participation.dialogues import (\n    StateUpdateDialogues,\n    TacDialogues,\n)\nfrom packages.fetchai.skills.tac_participation.game import Configuration, Game, Phase\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass TestConfiguration:\n    \"\"\"Test Configuration class of tac participation.\"\"\"\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        cls.version_id = \"some_version_id\"\n        cls.fee_by_currency_id = {\"1\": 1}\n        cls.agent_addr_to_name = {\n            \"agent_address_1\": \"agent_name_1\",\n            \"agent_address_2\": \"agent_name_2\",\n        }\n        cls.good_id_to_name = {\"3\": \"good_1\", \"4\": \"good_2\"}\n        cls.controller_addr = \"some_controller_address\"\n\n        cls.configuration = Configuration(\n            cls.version_id,\n            cls.fee_by_currency_id,\n            cls.agent_addr_to_name,\n            cls.good_id_to_name,\n            cls.controller_addr,\n        )\n\n    def test_simple_properties(self):\n        \"\"\"Test the properties of Game class.\"\"\"\n        assert self.configuration.version_id == self.version_id\n\n        assert self.configuration.nb_agents == len(self.agent_addr_to_name)\n\n        assert self.configuration.nb_goods == len(self.good_id_to_name)\n\n        assert self.configuration.tx_fee == 1\n\n        self.configuration._fee_by_currency_id = {\"1\": 1, \"2\": 2}\n        with pytest.raises(AEAEnforceError, match=\"More than one currency id present!\"):\n            assert self.configuration.tx_fee\n        self.configuration._fee_by_currency_id = self.fee_by_currency_id\n\n        assert self.configuration.fee_by_currency_id == self.fee_by_currency_id\n\n        assert self.configuration.agent_addr_to_name == self.agent_addr_to_name\n\n        assert self.configuration.good_id_to_name == self.good_id_to_name\n\n        assert self.configuration.agent_addresses == list(\n            self.agent_addr_to_name.keys()\n        )\n\n        assert self.configuration.agent_names == list(self.agent_addr_to_name.values())\n\n        assert self.configuration.good_ids == list(self.good_id_to_name.keys())\n\n        assert self.configuration.good_names == list(self.good_id_to_name.values())\n\n        assert self.configuration.controller_addr == self.controller_addr\n\n    def test_check_consistency_succeeds(self):\n        \"\"\"Test the _check_consistency of Configuration class which succeeds.\"\"\"\n        self.configuration._check_consistency()\n\n    def test_check_consistency_fails_i(self):\n        \"\"\"Test the _check_consistency of Configuration class which fails on version being None.\"\"\"\n        self.configuration._version_id = None\n        with pytest.raises(AEAEnforceError, match=\"A version id must be set.\"):\n            assert self.configuration._check_consistency()\n\n    def test_check_consistency_fails_ii(self):\n        \"\"\"Test the _check_consistency of Configuration class which fails because _fee_by_currency_id has more than one currencies.\"\"\"\n        self.configuration._fee_by_currency_id = {\"1\": 1, \"2\": 2}\n        with pytest.raises(AEAEnforceError, match=\"Tx fee must be non-negative.\"):\n            assert self.configuration._check_consistency()\n\n    def test_check_consistency_fails_iii(self):\n        \"\"\"Test the _check_consistency of Configuration class which fails because tx_fee < 0.\"\"\"\n        self.configuration._fee_by_currency_id = {\"1\": -5}\n        with pytest.raises(AEAEnforceError, match=\"Tx fee must be non-negative.\"):\n            assert self.configuration._check_consistency()\n\n    def test_check_consistency_fails_iv(self):\n        \"\"\"Test the _check_consistency of Configuration class which fails because number of agents is less than 2.\"\"\"\n        incorrect_agent_addr_to_name = {\"agent_address_1\": \"agent_name_1\"}\n        with pytest.raises(AEAEnforceError, match=\"Must have at least two agents.\"):\n            Configuration(\n                self.version_id,\n                self.fee_by_currency_id,\n                incorrect_agent_addr_to_name,\n                self.good_id_to_name,\n                self.controller_addr,\n            )\n\n    def test_check_consistency_fails_v(self):\n        \"\"\"Test the _check_consistency of Configuration class which fails because number of goods is less than 2.\"\"\"\n        incorrect_good_id_to_name = {\"3\": \"good_1\"}\n        with pytest.raises(AEAEnforceError, match=\"Must have at least two goods.\"):\n            Configuration(\n                self.version_id,\n                self.fee_by_currency_id,\n                self.agent_addr_to_name,\n                incorrect_good_id_to_name,\n                self.controller_addr,\n            )\n\n    def test_check_consistency_fails_vi(self):\n        \"\"\"Test the _check_consistency of Configuration class which fails because number of goods is less than 2.\"\"\"\n        self.configuration._agent_addr_to_name = {\"agent_address_1\": \"agent_name_1\"}\n        with pytest.raises(\n            AEAEnforceError, match=\"There must be one address for each agent.\"\n        ):\n            self.configuration._check_consistency()\n\n    def test_check_consistency_fails_vii(self):\n        \"\"\"Test the _check_consistency of Configuration class which fails because number of goods is less than 2.\"\"\"\n        incorrect_agent_addr_to_name = {\n            \"agent_address_1\": \"agent_name_1\",\n            \"agent_address_2\": \"agent_name_1\",\n        }\n        with pytest.raises(AEAEnforceError, match=\"Agents' names must be unique.\"):\n            Configuration(\n                self.version_id,\n                self.fee_by_currency_id,\n                incorrect_agent_addr_to_name,\n                self.good_id_to_name,\n                self.controller_addr,\n            )\n\n    def test_check_consistency_fails_viii(self):\n        \"\"\"Test the _check_consistency of Configuration class which fails because number of goods is less than 2.\"\"\"\n        self.configuration._good_id_to_name = {\n            \"3\": \"good_1\",\n            \"4\": \"good_2\",\n            \"5\": \"good_3\",\n        }\n        with pytest.raises(\n            AEAEnforceError, match=\"There must be one id for each good.\"\n        ):\n            self.configuration._check_consistency()\n\n    def test_check_consistency_fails_ix(self):\n        \"\"\"Test the _check_consistency of Configuration class which fails because number of goods is less than 2.\"\"\"\n        incorrect_good_id_to_name = {\"3\": \"good_1\", \"4\": \"good_1\"}\n        with pytest.raises(AEAEnforceError, match=\"Goods' names must be unique.\"):\n            Configuration(\n                self.version_id,\n                self.fee_by_currency_id,\n                self.agent_addr_to_name,\n                incorrect_good_id_to_name,\n                self.controller_addr,\n            )\n\n\nclass TestGame(BaseSkillTestCase):\n    \"\"\"Test Game class of tac participation.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"tac_participation\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.expected_version_id = \"v1\"\n        cls.expected_controller_addr = \"some_controller_address\"\n        cls.search_query = {\n            \"search_key\": \"tac\",\n            \"search_value\": \"v1\",\n            \"constraint_type\": \"==\",\n        }\n        cls.location = {\"longitude\": 0.1270, \"latitude\": 51.5194}\n        cls.search_radius = 5.0\n        cls.ledger_id = \"some_ledger_id\"\n        cls.is_using_contract = False\n\n        cls.game = Game(\n            expected_version_id=cls.expected_version_id,\n            expected_controller_addr=cls.expected_controller_addr,\n            search_query=cls.search_query,\n            location=cls.location,\n            search_radius=cls.search_radius,\n            ledger_id=cls.ledger_id,\n            is_using_contract=cls.is_using_contract,\n            name=\"game\",\n            skill_context=cls._skill.skill_context,\n        )\n\n    def test_simple_properties(self):\n        \"\"\"Test the properties of Game class.\"\"\"\n        assert self.game.ledger_id == self.ledger_id\n\n        assert self.game.is_using_contract == self.is_using_contract\n\n        assert self.game.expected_version_id == self.expected_version_id\n\n        assert self.game.phase == Phase.PRE_GAME\n\n        with pytest.raises(AEAEnforceError, match=\"Contract address not set!\"):\n            assert self.game.contract_address\n        self.game.contract_address = \"some_contract_address\"\n        assert self.game.contract_address == \"some_contract_address\"\n        with pytest.raises(AEAEnforceError, match=\"Contract address already set!\"):\n            self.game.contract_address = \"some_other_contract_address\"\n\n        with pytest.raises(AEAEnforceError, match=\"TacDialogue not set!\"):\n            assert self.game.tac_dialogue\n        _, tac_dialogue = cast(\n            TacDialogues, self.skill.skill_context.tac_dialogues\n        ).create(\n            counterparty=\"some_address\",\n            performative=TacMessage.Performative.REGISTER,\n            agent_name=\"some_agent_name\",\n        )\n        self.game.tac_dialogue = tac_dialogue\n        assert self.game.tac_dialogue == tac_dialogue\n        with pytest.raises(AEAEnforceError, match=\"TacDialogue already set!\"):\n            self.game.tac_dialogue = tac_dialogue\n\n        with pytest.raises(AEAEnforceError, match=\"StateUpdateDialogue not set!\"):\n            assert self.game.state_update_dialogue\n        _, state_update_dialogue = cast(\n            StateUpdateDialogues, self.skill.skill_context.state_update_dialogues\n        ).create(\n            counterparty=\"some_address\",\n            performative=StateUpdateMessage.Performative.INITIALIZE,\n            exchange_params_by_currency_id={\"some_currency_id\": 1.0},\n            utility_params_by_good_id={\"some_good_id\": 2.0},\n            amount_by_currency_id={\"some_currency_id\": 10},\n            quantities_by_good_id={\"some_good_id\": 5},\n        )\n        self.game.state_update_dialogue = state_update_dialogue\n        assert self.game.state_update_dialogue == state_update_dialogue\n        with pytest.raises(AEAEnforceError, match=\"StateUpdateDialogue already set!\"):\n            self.game.state_update_dialogue = state_update_dialogue\n\n        assert self.game.expected_controller_addr == self.expected_controller_addr\n        self.game._expected_controller_addr = None\n        with pytest.raises(\n            AEAEnforceError, match=\"Expected controller address not assigned!\"\n        ):\n            assert self.game.expected_controller_addr\n\n        with pytest.raises(AEAEnforceError, match=\"Game configuration not assigned!\"):\n            assert self.game.conf\n        configuration = Configuration(\n            \"some_version_id\",\n            {\"1\": 1},\n            {\"agent_address_1\": \"agent_name_1\", \"agent_address_2\": \"agent_name_2\"},\n            {\"3\": \"good_1\", \"4\": \"good_2\"},\n            \"some_controller_address\",\n        )\n        self.game._conf = configuration\n        assert self.game.conf == configuration\n\n    def test_init_succeeds(self):\n        \"\"\"Test the init method of the Game class which succeeds.\"\"\"\n        fee_by_currency_id = {\"1\": 1}\n        agent_addr_to_name = {\n            \"some_address_1\": \"some_name_1\",\n            \"some_address_2\": \"some_name_2\",\n        }\n        good_id_to_name = {\"2\": \"good_2\", \"3\": \"good_3\"}\n        tac_message = cast(\n            TacMessage,\n            self.build_incoming_message(\n                message_type=TacMessage,\n                performative=TacMessage.Performative.GAME_DATA,\n                amount_by_currency_id={\"1\": 10},\n                exchange_params_by_currency_id={\"1\": 1.0},\n                quantities_by_good_id={\"2\": 10, \"3\": 11},\n                utility_params_by_good_id={\"2\": 1.2, \"3\": 1.1},\n                fee_by_currency_id=fee_by_currency_id,\n                agent_addr_to_name=agent_addr_to_name,\n                currency_id_to_name={\"1\": \"FETCH\"},\n                good_id_to_name=good_id_to_name,\n                version_id=self.expected_version_id,\n            ),\n        )\n\n        self.game.init(tac_message, self.expected_controller_addr)\n\n        assert self.game.conf is not None\n        assert self.game.conf.version_id == self.expected_version_id\n        assert self.game.conf.fee_by_currency_id == fee_by_currency_id\n        assert self.game.conf.agent_addr_to_name == agent_addr_to_name\n        assert self.game.conf.good_id_to_name == good_id_to_name\n        assert self.game.conf.controller_addr == self.expected_controller_addr\n\n    def test_init_fails_i(self):\n        \"\"\"Test the init method of the Game class which fails because performative is NOT GAME_DATA.\"\"\"\n        tac_message = cast(\n            TacMessage,\n            self.build_incoming_message(\n                message_type=TacMessage,\n                performative=TacMessage.Performative.REGISTER,\n                agent_name=\"some_agent_name\",\n            ),\n        )\n\n        with pytest.raises(\n            AEAEnforceError, match=\"Wrong TacMessage for initialization of TAC game.\"\n        ):\n            self.game.init(tac_message, self.expected_controller_addr)\n\n    def test_init_fails_ii(self):\n        \"\"\"Test the init method of the Game class which fails because controller address is incorrect.\"\"\"\n        fee_by_currency_id = {\"1\": 1}\n        agent_addr_to_name = {\n            \"some_address_1\": \"some_name_1\",\n            \"some_address_2\": \"some_name_2\",\n        }\n        good_id_to_name = {\"2\": \"good_2\", \"3\": \"good_3\"}\n        incorrect_controller_addr = \"some_other_controller_address\"\n        tac_message = cast(\n            TacMessage,\n            self.build_incoming_message(\n                message_type=TacMessage,\n                performative=TacMessage.Performative.GAME_DATA,\n                amount_by_currency_id={\"1\": 10},\n                exchange_params_by_currency_id={\"1\": 1.0},\n                quantities_by_good_id={\"2\": 10, \"3\": 11},\n                utility_params_by_good_id={\"2\": 1.2, \"3\": 1.1},\n                fee_by_currency_id=fee_by_currency_id,\n                agent_addr_to_name=agent_addr_to_name,\n                currency_id_to_name={\"1\": \"FETCH\"},\n                good_id_to_name=good_id_to_name,\n                version_id=self.expected_version_id,\n            ),\n        )\n\n        with pytest.raises(\n            AEAEnforceError, match=\"TacMessage from unexpected controller.\"\n        ):\n            self.game.init(tac_message, incorrect_controller_addr)\n\n    def test_init_fails_iii(self):\n        \"\"\"Test the init method of the Game class which fails because version id is incorrect.\"\"\"\n        fee_by_currency_id = {\"1\": 1}\n        agent_addr_to_name = {\n            \"some_address_1\": \"some_name_1\",\n            \"some_address_2\": \"some_name_2\",\n        }\n        good_id_to_name = {\"2\": \"good_2\", \"3\": \"good_3\"}\n        incorrect_version_id = \"some_other_version_id\"\n        tac_message = cast(\n            TacMessage,\n            self.build_incoming_message(\n                message_type=TacMessage,\n                performative=TacMessage.Performative.GAME_DATA,\n                amount_by_currency_id={\"1\": 10},\n                exchange_params_by_currency_id={\"1\": 1.0},\n                quantities_by_good_id={\"2\": 10, \"3\": 11},\n                utility_params_by_good_id={\"2\": 1.2, \"3\": 1.1},\n                fee_by_currency_id=fee_by_currency_id,\n                agent_addr_to_name=agent_addr_to_name,\n                currency_id_to_name={\"1\": \"FETCH\"},\n                good_id_to_name=good_id_to_name,\n                version_id=incorrect_version_id,\n            ),\n        )\n\n        with pytest.raises(AEAEnforceError, match=\"TacMessage for unexpected game.\"):\n            self.game.init(tac_message, self.expected_controller_addr)\n\n    def test_update_expected_controller_addr(self):\n        \"\"\"Test the update_expected_controller_addr method of the Game class.\"\"\"\n        new_contract_address = \"some_different_controller_address\"\n        with patch.object(self.skill.skill_context.logger, \"log\") as mock_logger:\n            self.game.update_expected_controller_addr(new_contract_address)\n\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            \"TAKE CARE! Circumventing controller identity check! For added security provide the expected controller key as an argument to the Game instance \"\n            \"and check against it.\",\n        )\n        assert self.game.expected_controller_addr == new_contract_address\n\n    def test_update_game_phase(self):\n        \"\"\"Test the update_game_phase method of the Game class.\"\"\"\n        assert self.game.phase == Phase.PRE_GAME\n        self.game.update_game_phase(Phase.GAME)\n        assert self.game.phase == Phase.GAME\n\n    def test_get_game_query(self):\n        \"\"\"Test the get_game_query method of the Game class.\"\"\"\n        expected_location = Location(\n            latitude=self.location[\"latitude\"], longitude=self.location[\"longitude\"]\n        )\n        expected_query = Query(\n            [\n                Constraint(\n                    \"location\",\n                    ConstraintType(\"distance\", (expected_location, self.search_radius)),\n                ),\n                Constraint(\n                    self.search_query[\"search_key\"],\n                    ConstraintType(\n                        self.search_query[\"constraint_type\"],\n                        self.search_query[\"search_value\"],\n                    ),\n                ),\n            ],\n        )\n\n        actual_query = self.game.get_game_query()\n        assert actual_query == expected_query\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_tac_participation/test_handlers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the handler classes of the tac participation skill.\"\"\"\n\nimport logging\nfrom pathlib import Path\nfrom typing import cast\nfrom unittest.mock import patch\n\nimport pytest\n\nfrom aea.protocols.dialogue.base import DialogueMessage\nfrom aea.test_tools.test_skill import BaseSkillTestCase, COUNTERPARTY_AGENT_ADDRESS\n\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.protocols.state_update.message import StateUpdateMessage\nfrom packages.fetchai.protocols.tac.message import TacMessage\nfrom packages.fetchai.skills.tac_participation.dialogues import (\n    OefSearchDialogues,\n    StateUpdateDialogue,\n    StateUpdateDialogues,\n    TacDialogues,\n)\nfrom packages.fetchai.skills.tac_participation.game import Game, Phase\nfrom packages.fetchai.skills.tac_participation.handlers import (\n    OefSearchHandler,\n    TacHandler,\n)\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass TestOefSearchHandler(BaseSkillTestCase):\n    \"\"\"Test oef search handler of tac participation.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"tac_participation\")\n    is_agent_to_agent_messages = False\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.oef_search_handler = cast(\n            OefSearchHandler, cls._skill.skill_context.handlers.oef\n        )\n        cls.game = cast(Game, cls._skill.skill_context.game)\n        cls.oef_dialogues = cast(\n            OefSearchDialogues, cls._skill.skill_context.oef_search_dialogues\n        )\n        cls.list_of_messages = (\n            DialogueMessage(\n                OefSearchMessage.Performative.SEARCH_SERVICES, {\"query\": \"some_query\"}\n            ),\n        )\n        cls.controller_address = \"some_controller_address\"\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the oef handler.\"\"\"\n        assert self.oef_search_handler.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle_unidentified_dialogue(self):\n        \"\"\"Test the _handle_unidentified_dialogue method of the oef handler.\"\"\"\n        # setup\n        incorrect_dialogue_reference = (\"\", \"\")\n        incoming_message = self.build_incoming_message(\n            message_type=OefSearchMessage,\n            dialogue_reference=incorrect_dialogue_reference,\n            performative=OefSearchMessage.Performative.SEARCH_RESULT,\n            to=str(self.skill.skill_context.skill_id),\n        )\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"received invalid oef_search message={incoming_message}, unidentified dialogue.\",\n        )\n\n    def test_handle_error(self):\n        \"\"\"Test the _handle_error method of the oef handler.\"\"\"\n        # setup\n        oef_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_dialogues,\n            messages=self.list_of_messages[:1],\n        )\n        incoming_message = cast(\n            OefSearchMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=oef_dialogue,\n                performative=OefSearchMessage.Performative.OEF_ERROR,\n                to=str(self.skill.skill_context.skill_id),\n                oef_error_operation=OefSearchMessage.OefErrorOperation.SEARCH_SERVICES,\n            ),\n        )\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"received OEF Search error: dialogue_reference={oef_dialogue.dialogue_label.dialogue_reference}, oef_error_operation={incoming_message.oef_error_operation}\",\n        )\n\n    def test_on_search_result(self):\n        \"\"\"Test the _on_search_result method of the oef handler.\"\"\"\n        # setup\n        oef_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_dialogues,\n            messages=self.list_of_messages[:1],\n        )\n        incoming_message = cast(\n            OefSearchMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=oef_dialogue,\n                performative=OefSearchMessage.Performative.SEARCH_RESULT,\n                to=str(self.skill.skill_context.skill_id),\n                agents=(self.controller_address,),\n            ),\n        )\n        self.game._phase = Phase.PRE_GAME\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        self.assert_quantity_in_outbox(1)\n\n        # _on_search_result\n        mock_logger.assert_any_call(\n            logging.DEBUG,\n            f\"on search result: dialogue_reference={oef_dialogue.dialogue_label.dialogue_reference} agents={incoming_message.agents}\",\n        )\n\n        # _on_controller_search_result\n        mock_logger.assert_any_call(\n            logging.INFO,\n            \"found the TAC controller. Registering...\",\n        )\n\n        # _register_to_tac\n        assert self.game._expected_controller_addr == self.controller_address\n        assert self.game.phase == Phase.GAME_REGISTRATION\n\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=TacMessage,\n            performative=TacMessage.Performative.REGISTER,\n            to=self.controller_address,\n            sender=self.skill.skill_context.agent_address,\n            agent_name=self.skill.skill_context.agent_name,\n        )\n        assert has_attributes, error_str\n\n        assert self.game._tac_dialogue is not None\n        assert self.skill.skill_context.behaviours.tac_search.is_active is False\n        assert (\n            self.skill.skill_context.shared_state.get(\"tac_version_id\", None)\n            == self.game.expected_version_id\n        )\n\n    def test_on_controller_search_result_i(self):\n        \"\"\"Test the _on_controller_search_result method of the oef handler where phase is not PRE_GAME.\"\"\"\n        # setup\n        oef_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_dialogues,\n            messages=self.list_of_messages[:1],\n        )\n        incoming_message = cast(\n            OefSearchMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=oef_dialogue,\n                performative=OefSearchMessage.Performative.SEARCH_RESULT,\n                to=str(self.skill.skill_context.skill_id),\n                agents=(\"agent_1\", \"agent_2\"),\n            ),\n        )\n        self.game._phase = Phase.GAME\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        # _on_search_result\n        mock_logger.assert_any_call(\n            logging.DEBUG,\n            f\"on search result: dialogue_reference={oef_dialogue.dialogue_label.dialogue_reference} agents={incoming_message.agents}\",\n        )\n\n        # _on_controller_search_result\n        mock_logger.assert_any_call(\n            logging.DEBUG,\n            \"ignoring controller search result, the agent is already competing.\",\n        )\n\n    def test_on_controller_search_result_ii(self):\n        \"\"\"Test the _on_controller_search_result method of the oef handler where list of agent addresses is empty.\"\"\"\n        # setup\n        oef_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_dialogues,\n            messages=self.list_of_messages[:1],\n        )\n        incoming_message = cast(\n            OefSearchMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=oef_dialogue,\n                performative=OefSearchMessage.Performative.SEARCH_RESULT,\n                to=str(self.skill.skill_context.skill_id),\n                agents=tuple(),\n            ),\n        )\n        self.game._phase = Phase.PRE_GAME\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        # _on_search_result\n        mock_logger.assert_any_call(\n            logging.DEBUG,\n            f\"on search result: dialogue_reference={oef_dialogue.dialogue_label.dialogue_reference} agents={incoming_message.agents}\",\n        )\n\n        # _on_controller_search_result\n        mock_logger.assert_any_call(\n            logging.INFO,\n            \"couldn't find the TAC controller. Retrying...\",\n        )\n\n    def test_on_controller_search_result_more_than_one_agents(self):\n        \"\"\"Test the _on_controller_search_result method of the oef handler where list of agents contains more than one agents.\"\"\"\n        # setup\n        oef_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_dialogues,\n            messages=self.list_of_messages[:1],\n        )\n        incoming_message = cast(\n            OefSearchMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=oef_dialogue,\n                performative=OefSearchMessage.Performative.SEARCH_RESULT,\n                to=str(self.skill.skill_context.skill_id),\n                agents=(\"agent_1\", \"agent_2\"),\n            ),\n        )\n        self.game._phase = Phase.PRE_GAME\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        # _on_search_result\n        mock_logger.assert_any_call(\n            logging.DEBUG,\n            f\"on search result: dialogue_reference={oef_dialogue.dialogue_label.dialogue_reference} agents={incoming_message.agents}\",\n        )\n\n        # _on_controller_search_result\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            \"found more than one TAC controller. Retrying...\",\n        )\n\n    def test_handle_invalid(self):\n        \"\"\"Test the _handle_invalid method of the oef handler.\"\"\"\n        # setup\n        invalid_performative = OefSearchMessage.Performative.UNREGISTER_SERVICE\n        incoming_message = self.build_incoming_message(\n            message_type=OefSearchMessage,\n            dialogue_reference=(\"1\", \"\"),\n            performative=invalid_performative,\n            to=str(self.skill.skill_context.skill_id),\n            service_description=\"some_service_description\",\n        )\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"cannot handle oef_search message of performative={invalid_performative} in dialogue={self.oef_dialogues.get_dialogue(incoming_message)}.\",\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the oef_search handler.\"\"\"\n        assert self.oef_search_handler.teardown() is None\n        self.assert_quantity_in_outbox(0)\n\n\nclass TestTacHandler(BaseSkillTestCase):\n    \"\"\"Test tac handler of tac participation.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"tac_participation\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.tac_handler = cast(TacHandler, cls._skill.skill_context.handlers.tac)\n        cls.tac_dialogues = cast(TacDialogues, cls._skill.skill_context.tac_dialogues)\n        cls.state_update_dialogues = cast(\n            StateUpdateDialogues, cls._skill.skill_context.state_update_dialogues\n        )\n        cls.game = cast(Game, cls._skill.skill_context.game)\n        cls.logger = cls.tac_handler.context.logger\n\n        cls.agent_name = \"some_agent_name\"\n        cls.amount_by_currency_id = {\"1\": 10}\n        cls.exchange_params_by_currency_id = {\"1\": 1.0}\n        cls.quantities_by_good_id = {\"2\": 10}\n        cls.utility_params_by_good_id = {\"2\": 1.0}\n        cls.fee_by_currency_id = {\"1\": 1}\n        cls.agent_addr_to_name = {COUNTERPARTY_AGENT_ADDRESS: \"some_name\"}\n        cls.currency_id_to_name = {\"1\": \"FETCH\"}\n        cls.good_id_to_name = {\"2\": \"Good_1\"}\n        cls.version_id = \"v1\"\n        cls.list_of_messages = (\n            DialogueMessage(\n                TacMessage.Performative.REGISTER, {\"agent_name\": cls.agent_name}, True\n            ),\n            DialogueMessage(\n                TacMessage.Performative.GAME_DATA,\n                {\n                    \"amount_by_currency_id\": cls.amount_by_currency_id,\n                    \"exchange_params_by_currency_id\": cls.exchange_params_by_currency_id,\n                    \"quantities_by_good_id\": cls.quantities_by_good_id,\n                    \"utility_params_by_good_id\": cls.utility_params_by_good_id,\n                    \"fee_by_currency_id\": cls.fee_by_currency_id,\n                    \"agent_addr_to_name\": cls.agent_addr_to_name,\n                    \"currency_id_to_name\": cls.currency_id_to_name,\n                    \"good_id_to_name\": cls.good_id_to_name,\n                    \"version_id\": cls.version_id,\n                },\n            ),\n            DialogueMessage(\n                TacMessage.Performative.TRANSACTION,\n                {\n                    \"transaction_id\": \"some_transaction_id\",\n                    \"ledger_id\": \"some_ledger_id\",\n                    \"sender_address\": \"some_sender_address\",\n                    \"counterparty_address\": \"some_counterparty_address\",\n                    \"amount_by_currency_id\": {\"1\": 5},\n                    \"fee_by_currency_id\": {\"1\": 1},\n                    \"quantities_by_good_id\": {\"2\": -5},\n                    \"nonce\": \"some_nonce\",\n                    \"sender_signature\": \"some_sender_signature\",\n                    \"counterparty_signature\": \"some_counterparty_signature\",\n                },\n            ),\n        )\n\n        cls.list_of_state_update_messages = (\n            DialogueMessage(\n                StateUpdateMessage.Performative.INITIALIZE,\n                {\n                    \"amount_by_currency_id\": cls.amount_by_currency_id,\n                    \"quantities_by_good_id\": cls.quantities_by_good_id,\n                },\n            ),\n        )\n\n        cls.game._expected_controller_addr = COUNTERPARTY_AGENT_ADDRESS\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the tac handler.\"\"\"\n        assert self.tac_handler.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle_sender_not_equal_to_expected_controller(self):\n        \"\"\"Test the handle method of the tac handler where message sender is NOT equal to the expected controller.\"\"\"\n        # setup\n        self.game._expected_controller_addr = \"some_different_controller_address\"\n\n        dialogue = self.prepare_skill_dialogue(\n            self.tac_dialogues, self.list_of_messages[:1]\n        )\n\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=dialogue,\n            message_type=TacMessage,\n            performative=TacMessage.Performative.TAC_ERROR,\n            error_code=TacMessage.ErrorCode.AGENT_ADDR_ALREADY_REGISTERED,\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            with pytest.raises(\n                ValueError,\n                match=\"The sender of the message is not the controller agent we registered with.\",\n            ):\n                self.tac_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.DEBUG,\n            f\"handling controller response. performative={incoming_message.performative}\",\n        )\n\n    def test_handle_unidentified_dialogue(self):\n        \"\"\"Test the _handle_unidentified_dialogue method of the tac handler.\"\"\"\n        # setup\n        incorrect_dialogue_reference = (\"\", \"\")\n        incoming_message = self.build_incoming_message(\n            message_type=TacMessage,\n            dialogue_reference=incorrect_dialogue_reference,\n            performative=TacMessage.Performative.CANCELLED,\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.tac_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"received invalid tac message={incoming_message}, unidentified dialogue.\",\n        )\n\n    def test_on_tac_error_code_i(self):\n        \"\"\"Test the _on_tac_error method of the tac handler where error_code is NOT TRANSACTION_NOT_VALID.\"\"\"\n        # setup\n        dialogue = self.prepare_skill_dialogue(\n            self.tac_dialogues, self.list_of_messages[:1]\n        )\n\n        error_code = TacMessage.ErrorCode.AGENT_ADDR_ALREADY_REGISTERED\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=dialogue,\n            message_type=TacMessage,\n            performative=TacMessage.Performative.TAC_ERROR,\n            error_code=error_code,\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.tac_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.DEBUG,\n            f\"received error from the controller in dialogue={dialogue}. error_msg={TacMessage.ErrorCode.to_msg(error_code.value)}\",\n        )\n\n    def test_on_tac_error_code_ii(self):\n        \"\"\"Test the _on_tac_error method of the tac handler where error_code is TRANSACTION_NOT_VALID.\"\"\"\n        # setup\n        dialogue = self.prepare_skill_dialogue(\n            self.tac_dialogues, self.list_of_messages[:1]\n        )\n\n        tx_id = \"some_tx_id\"\n        error_code = TacMessage.ErrorCode.TRANSACTION_NOT_VALID\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=dialogue,\n            message_type=TacMessage,\n            performative=TacMessage.Performative.TAC_ERROR,\n            error_code=error_code,\n            info={\"transaction_id\": tx_id},\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.tac_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.DEBUG,\n            f\"received error from the controller in dialogue={dialogue}. error_msg={TacMessage.ErrorCode.to_msg(error_code.value)}\",\n        )\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"received error on transaction id: {tx_id[-10:]}\",\n        )\n\n    def test_on_start_i(self):\n        \"\"\"Test the _on_start method of the tac handler.\"\"\"\n        # setup\n        self.game._phase = Phase.GAME_REGISTRATION\n        self.game._is_using_contract = False\n\n        dialogue = self.prepare_skill_dialogue(\n            self.tac_dialogues, self.list_of_messages[:1]\n        )\n\n        incoming_message = cast(\n            TacMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=dialogue,\n                message_type=TacMessage,\n                performative=TacMessage.Performative.GAME_DATA,\n                amount_by_currency_id=self.amount_by_currency_id,\n                exchange_params_by_currency_id=self.exchange_params_by_currency_id,\n                quantities_by_good_id=self.quantities_by_good_id,\n                utility_params_by_good_id=self.utility_params_by_good_id,\n                fee_by_currency_id=self.fee_by_currency_id,\n                agent_addr_to_name=self.agent_addr_to_name,\n                currency_id_to_name=self.currency_id_to_name,\n                good_id_to_name=self.good_id_to_name,\n                version_id=self.version_id,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            with patch.object(self.game, \"init\"):\n                self.tac_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            \"received start event from the controller. Starting to compete...\",\n        )\n\n        self.assert_quantity_in_decision_making_queue(1)\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_decision_maker_inbox(),\n            message_type=StateUpdateMessage,\n            performative=StateUpdateMessage.Performative.INITIALIZE,\n            to=self.skill.skill_context.decision_maker_address,\n            sender=str(self.skill.skill_context.skill_id),\n            amount_by_currency_id=incoming_message.amount_by_currency_id,\n            quantities_by_good_id=incoming_message.quantities_by_good_id,\n            exchange_params_by_currency_id=incoming_message.exchange_params_by_currency_id,\n            utility_params_by_good_id=incoming_message.utility_params_by_good_id,\n        )\n        assert has_attributes, error_str\n        assert (\n            self.skill.skill_context.shared_state[\"fee_by_currency_id\"]\n            == incoming_message.fee_by_currency_id\n        )\n        assert self.game.state_update_dialogue is not None\n\n    def test_on_start_ii(self):\n        \"\"\"Test the _on_start method of the tac handler where phase is NOT GAME_REGISTRATION.\"\"\"\n        # setup\n        self.game._phase = Phase.PRE_GAME\n        self.game._is_using_contract = False\n\n        dialogue = self.prepare_skill_dialogue(\n            self.tac_dialogues, self.list_of_messages[:1]\n        )\n\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=dialogue,\n            message_type=TacMessage,\n            performative=TacMessage.Performative.GAME_DATA,\n            amount_by_currency_id=self.amount_by_currency_id,\n            exchange_params_by_currency_id=self.exchange_params_by_currency_id,\n            quantities_by_good_id=self.quantities_by_good_id,\n            utility_params_by_good_id=self.utility_params_by_good_id,\n            fee_by_currency_id=self.fee_by_currency_id,\n            agent_addr_to_name=self.agent_addr_to_name,\n            currency_id_to_name=self.currency_id_to_name,\n            good_id_to_name=self.good_id_to_name,\n            version_id=self.version_id,\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.tac_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"we do not expect a start message in game phase={self.game.phase.value}\",\n        )\n\n    def test_on_start_iii(self):\n        \"\"\"Test the _on_start method of the tac handler where game uses contract.\"\"\"\n        # setup\n        self.game._phase = Phase.GAME_REGISTRATION\n        self.game._is_using_contract = True\n\n        dialogue = self.prepare_skill_dialogue(\n            self.tac_dialogues, self.list_of_messages[:1]\n        )\n\n        contract_address = \"some_contract_address\"\n        incoming_message = cast(\n            TacMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=dialogue,\n                message_type=TacMessage,\n                performative=TacMessage.Performative.GAME_DATA,\n                amount_by_currency_id=self.amount_by_currency_id,\n                exchange_params_by_currency_id=self.exchange_params_by_currency_id,\n                quantities_by_good_id=self.quantities_by_good_id,\n                utility_params_by_good_id=self.utility_params_by_good_id,\n                fee_by_currency_id=self.fee_by_currency_id,\n                agent_addr_to_name=self.agent_addr_to_name,\n                currency_id_to_name=self.currency_id_to_name,\n                good_id_to_name=self.good_id_to_name,\n                version_id=self.version_id,\n                info={\"contract_address\": contract_address},\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            with patch.object(self.game, \"init\"):\n                with patch.object(\n                    self.tac_handler, \"_update_ownership_and_preferences\"\n                ) as mocked_uoap:\n                    self.tac_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            \"received start event from the controller. Starting to compete...\",\n        )\n        assert self.game.contract_address == contract_address\n        assert (\n            self.skill.skill_context.shared_state[\"erc1155_contract_address\"]\n            == contract_address\n        )\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received a contract address: {contract_address}\",\n        )\n        mocked_uoap.assert_called_once()\n\n    def test_on_start_iv(self):\n        \"\"\"Test the _on_start method of the tac handler where game uses contract.\"\"\"\n        # setup\n        self.game._phase = Phase.GAME_REGISTRATION\n        self.game._is_using_contract = True\n\n        dialogue = self.prepare_skill_dialogue(\n            self.tac_dialogues, self.list_of_messages[:1]\n        )\n\n        incoming_message = cast(\n            TacMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=dialogue,\n                message_type=TacMessage,\n                performative=TacMessage.Performative.GAME_DATA,\n                amount_by_currency_id=self.amount_by_currency_id,\n                exchange_params_by_currency_id=self.exchange_params_by_currency_id,\n                quantities_by_good_id=self.quantities_by_good_id,\n                utility_params_by_good_id=self.utility_params_by_good_id,\n                fee_by_currency_id=self.fee_by_currency_id,\n                agent_addr_to_name=self.agent_addr_to_name,\n                currency_id_to_name=self.currency_id_to_name,\n                good_id_to_name=self.good_id_to_name,\n                version_id=self.version_id,\n                info={\"contract_address\": None},\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            with patch.object(self.game, \"init\"):\n                with patch.object(\n                    self.tac_handler, \"_update_ownership_and_preferences\"\n                ) as mocked_uoap:\n                    self.tac_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            \"received start event from the controller. Starting to compete...\",\n        )\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            \"did not receive a contract address!\",\n        )\n        mocked_uoap.assert_not_called()\n\n    def test_on_cancelled_i(self):\n        \"\"\"Test the _on_cancelled method of the tac handler where phase is GAME_REGISTRATION.\"\"\"\n        # setup\n        self.game._phase = Phase.GAME_REGISTRATION\n\n        dialogue = self.prepare_skill_dialogue(\n            self.tac_dialogues, self.list_of_messages[:1]\n        )\n\n        incoming_message = cast(\n            TacMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=dialogue,\n                message_type=TacMessage,\n                performative=TacMessage.Performative.CANCELLED,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.tac_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            \"received cancellation from the controller.\",\n        )\n        assert self.game.phase == Phase.POST_GAME\n        assert self.skill.skill_context.is_active is False\n        assert self.skill.skill_context.shared_state[\"is_game_finished\"] is True\n\n    def test_on_cancelled_ii(self):\n        \"\"\"Test the _on_cancelled method of the tac handler where phase is GAME.\"\"\"\n        # setup\n        self.game._phase = Phase.GAME\n\n        dialogue = self.prepare_skill_dialogue(\n            self.tac_dialogues, self.list_of_messages[:1]\n        )\n\n        incoming_message = cast(\n            TacMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=dialogue,\n                message_type=TacMessage,\n                performative=TacMessage.Performative.CANCELLED,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.tac_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            \"received cancellation from the controller.\",\n        )\n        assert self.game.phase == Phase.POST_GAME\n        assert self.skill.skill_context.is_active is False\n        assert self.skill.skill_context.shared_state[\"is_game_finished\"] is True\n\n    def test_on_cancelled_iii(self):\n        \"\"\"Test the _on_cancelled method of the tac handler where phase is NOT GAME_REGISTRATION nor GAME.\"\"\"\n        # setup\n        self.game._phase = Phase.PRE_GAME\n\n        dialogue = self.prepare_skill_dialogue(\n            self.tac_dialogues, self.list_of_messages[:1]\n        )\n\n        incoming_message = cast(\n            TacMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=dialogue,\n                message_type=TacMessage,\n                performative=TacMessage.Performative.CANCELLED,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.tac_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"we do not expect a message in game phase={self.game.phase.value}, received msg={incoming_message}\",\n        )\n\n    def test_on_transaction_confirmed_i(self):\n        \"\"\"Test the _on_transaction_confirmed method of the tac handler.\"\"\"\n        # setup\n        self.game._phase = Phase.GAME\n\n        state_update_dialogue = cast(\n            StateUpdateDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.state_update_dialogues,\n                messages=self.list_of_state_update_messages[:1],\n                counterparty=self.skill.skill_context.decision_maker_address,\n            ),\n        )\n        self.game._state_update_dialogue = state_update_dialogue\n\n        dialogue = self.prepare_skill_dialogue(\n            self.tac_dialogues, self.list_of_messages[:3]\n        )\n\n        transaction_id = \"some_transaction_id\"\n        incoming_message = cast(\n            TacMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=dialogue,\n                message_type=TacMessage,\n                performative=TacMessage.Performative.TRANSACTION_CONFIRMATION,\n                transaction_id=transaction_id,\n                amount_by_currency_id=self.amount_by_currency_id,\n                quantities_by_good_id=self.quantities_by_good_id,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.tac_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received transaction confirmation from the controller: transaction_id={transaction_id}\",\n        )\n\n        self.assert_quantity_in_decision_making_queue(1)\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_decision_maker_inbox(),\n            message_type=StateUpdateMessage,\n            performative=StateUpdateMessage.Performative.APPLY,\n            to=self.skill.skill_context.decision_maker_address,\n            sender=str(self.skill.skill_context.skill_id),\n            amount_by_currency_id=incoming_message.amount_by_currency_id,\n            quantities_by_good_id=incoming_message.quantities_by_good_id,\n        )\n        assert has_attributes, error_str\n        assert (\n            incoming_message.transaction_id\n            in self.skill.skill_context.shared_state[\"confirmed_tx_ids\"]\n        )\n\n    def test_on_transaction_confirmed_ii(self):\n        \"\"\"Test the _on_transaction_confirmed method of the tac handler where phase is not GAME.\"\"\"\n        # setup\n        self.game._phase = Phase.PRE_GAME\n\n        dialogue = self.prepare_skill_dialogue(\n            self.tac_dialogues, self.list_of_messages[:3]\n        )\n\n        transaction_id = \"some_transaction_id\"\n        incoming_message = cast(\n            TacMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=dialogue,\n                message_type=TacMessage,\n                performative=TacMessage.Performative.TRANSACTION_CONFIRMATION,\n                transaction_id=transaction_id,\n                amount_by_currency_id=self.amount_by_currency_id,\n                quantities_by_good_id=self.quantities_by_good_id,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.tac_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"we do not expect a transaction in game phase={self.game.phase.value}, received msg={incoming_message}\",\n        )\n\n    def test_on_transaction_confirmed_iii(self):\n        \"\"\"Test the _on_transaction_confirmed method of the tac handler where state_update dialogue is empty.\"\"\"\n        # setup\n        self.game._phase = Phase.GAME\n\n        state_update_dialogue = cast(\n            StateUpdateDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.state_update_dialogues,\n                messages=self.list_of_state_update_messages[:1],\n                counterparty=self.skill.skill_context.decision_maker_address,\n            ),\n        )\n        state_update_dialogue._incoming_messages = []\n        state_update_dialogue._outgoing_messages = []\n        self.game._state_update_dialogue = state_update_dialogue\n\n        dialogue = self.prepare_skill_dialogue(\n            self.tac_dialogues, self.list_of_messages[:3]\n        )\n\n        transaction_id = \"some_transaction_id\"\n        incoming_message = cast(\n            TacMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=dialogue,\n                message_type=TacMessage,\n                performative=TacMessage.Performative.TRANSACTION_CONFIRMATION,\n                transaction_id=transaction_id,\n                amount_by_currency_id=self.amount_by_currency_id,\n                quantities_by_good_id=self.quantities_by_good_id,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            with pytest.raises(ValueError, match=\"Could not retrieve last message.\"):\n                self.tac_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received transaction confirmation from the controller: transaction_id={transaction_id}\",\n        )\n\n    def test_handle_invalid(self):\n        \"\"\"Test the _handle_invalid method of the tac handler.\"\"\"\n        # setup\n        tac_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.tac_dialogues,\n            messages=self.list_of_messages[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=tac_dialogue,\n            performative=TacMessage.Performative.UNREGISTER,\n            sender=COUNTERPARTY_AGENT_ADDRESS,\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.tac_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"cannot handle tac message of performative={incoming_message.performative} in dialogue={tac_dialogue}.\",\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the tac handler.\"\"\"\n        assert self.tac_handler.teardown() is None\n        self.assert_quantity_in_outbox(0)\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_thermometer/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"The tests module contains the tests of the packages/skills/thermometer dir.\"\"\"\n"
  },
  {
    "path": "tests/test_packages/test_skills/test_thermometer/test_strategy.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the strategy class of the thermometer skill.\"\"\"\n\nimport logging\nfrom pathlib import Path\nfrom unittest.mock import Mock, patch\n\nfrom aea.test_tools.test_skill import BaseSkillTestCase\n\nfrom packages.fetchai.skills.thermometer.strategy import MAX_RETRIES, Strategy\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass TestStrategy(BaseSkillTestCase):\n    \"\"\"Test Strategy of thermometer.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"thermometer\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.strategy = Strategy(\n            name=\"strategy\",\n            skill_context=cls._skill.skill_context,\n        )\n        cls.logger = cls._skill.skill_context.logger\n\n    def test_collect_from_data_source_i(self):\n        \"\"\"Test the collect_from_data_source method of the Strategy class where max retires result is successful.\"\"\"\n        # setup\n        temp = 24\n        results = [{\"internal temperature\": temp, \"some_other_info\": \"some_info\"}]\n        expected_degree = {\"thermometer_data\": str(temp)}\n\n        temper_mock = Mock()\n        temper_mock.read.return_value = results\n\n        # operation\n        with patch(\"temper.Temper.__init__\", return_value=None) as mock_init:\n            with patch(\"temper.Temper.read\", return_value=results) as mock_read:\n                with patch.object(self.logger, \"log\") as mock_logger:\n                    degree = self.strategy.collect_from_data_source()\n\n        # after\n        mock_init.assert_called_once()\n        mock_read.assert_called_once()\n        mock_logger.assert_not_called()\n        assert degree == expected_degree\n\n    def test_collect_from_data_source_ii(self):\n        \"\"\"Test the collect_from_data_source method of the Strategy class where max retires result is successful.\"\"\"\n        # setup\n        temp = 24\n        results = [{\"NOT internal temperature\": temp, \"some_other_info\": \"some_info\"}]\n\n        temper_mock = Mock()\n        temper_mock.read.return_value = results\n\n        # operation\n        with patch(\"temper.Temper.__init__\", return_value=None) as mock_init:\n            with patch(\"temper.Temper.read\", return_value=results) as mock_read:\n                with patch.object(self.logger, \"log\") as mock_logger:\n                    degree = self.strategy.collect_from_data_source()\n\n        # after\n        mock_init.assert_called_once()\n        assert mock_read.call_count == MAX_RETRIES\n        mock_logger.assert_any_call(\n            logging.DEBUG, \"Couldn't read the sensor I am re-trying.\"\n        )\n        assert degree == {}\n"
  },
  {
    "path": "tests/test_packages/test_skills_integration/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"The tests module contains the integration tests of the packages/skills dir.\"\"\"\n"
  },
  {
    "path": "tests/test_packages/test_skills_integration/test_aries_demo.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This package contains integration test for the aries_alice skill and the aries_faber skill.\"\"\"\nimport random\nimport string\nimport subprocess  # nosec\nfrom random import randint  # nosec\n\nimport pytest\n\nfrom aea.test_tools.test_cases import AEATestCaseMany\n\nfrom packages.fetchai.connections.p2p_libp2p.connection import (\n    LIBP2P_SUCCESS_MESSAGE,\n    P2PLibp2pConnection,\n)\nfrom packages.fetchai.skills.aries_alice import PUBLIC_ID as ALICE_SKILL_PUBLIC_ID\nfrom packages.fetchai.skills.aries_faber import PUBLIC_ID as FABER_SKILL_PUBLIC_ID\n\n\ndef _rand_seed():\n    return \"\".join(\n        random.choice(string.ascii_uppercase + string.digits)  # nosec\n        for _ in range(32)\n    )\n\n\nREADME = \"\"\"\nTo start with test:\n`apt install libindy`  to instal indy library binary file. required by acapy\n`pip install aries-cloudagent[indy]` acaPY is required\n\n## VON Network\n\nIn the first terminal move to the `von-network` directory and run an instance of `von-network` locally in docker.\n\nThis <a href=\"https://github.com/bcgov/von-network#running-the-network-locally\" target=\"_blank\">tutorial</a> has information on starting (and stopping) the network locally.\n\n``` bash\n./manage build\n./manage start 172.17.0.1,172.17.0.1,172.17.0.1,172.17.0.1 --logs\n```\n\n172.17.0.1 - is ip address of the docker0 network interface, can be used  any address assigned to the host except 127.0.0.1\n\nUPDATE `ACAPY_HOST` at line 76 to the same host selected for von network\n\nchange `SKIP_TEST = True` to `SKIP_TEST = False`\n\"\"\"\n\n# set to False to run it manually\nSKIP_TEST = True\n\n\n@pytest.mark.unstable\n@pytest.mark.integration\nclass TestAriesSkillsDemo(AEATestCaseMany):\n    \"\"\"Test integrated aries skills.\"\"\"\n\n    ACAPY_HOST = \"172.17.0.1\"\n    capture_log = True\n    alice_seed: str\n    bob_seed: str\n    faber_seed: str\n\n    @classmethod\n    def get_port(cls) -> int:\n        \"\"\"Get next tcp port number.\"\"\"\n        cls.port += 1  # type: ignore\n        return cls.port  # type: ignore\n\n    @classmethod\n    def start_acapy(\n        cls, name: str, base_port: int, seed: str, endpoint_host: str, genesis_url: str\n    ) -> subprocess.Popen:\n        \"\"\"Start acapy process.\"\"\"\n        return subprocess.Popen(  # nosec\n            [\n                \"python3\",\n                \"-m\",\n                \"aries_cloudagent\",\n                \"start\",\n                \"--auto-ping-connection\",\n                \"--auto-respond-messages\",\n                \"--auto-store-credential\",\n                \"--auto-accept-invites\",\n                \"--auto-accept-requests\",\n                \"--auto-respond-credential-proposal\",\n                \"--auto-respond-credential-offer\",\n                \"--auto-respond-credential-request\",\n                \"--auto-respond-presentation-proposal\",\n                \"--auto-respond-presentation-request\",\n                # \"--debug-credentials\",\n                # \"--debug-presentations\",\n                # \"--debug-connections\",\n                \"--admin\",\n                \"127.0.0.1\",\n                str(base_port + 1),\n                \"--admin-insecure-mode\",\n                \"--inbound-transport\",\n                \"http\",\n                \"0.0.0.0\",\n                str(base_port),\n                \"--outbound-transp\",\n                \"http\",\n                \"--webhook-url\",\n                f\"http://127.0.0.1:{str(base_port+2)}/webhooks\",\n                \"-e\",\n                f\"http://{endpoint_host}:{base_port}\",\n                \"--genesis-url\",\n                genesis_url,\n                \"--wallet-type\",\n                \"indy\",\n                \"--wallet-name\",\n                name + str(randint(10000000, 999999999999)),  # nosec\n                \"--wallet-key\",\n                \"walkey\",\n                \"--seed\",\n                seed,  # type: ignore\n                \"--recreate-wallet\",\n                \"--wallet-local-did\",\n                \"--auto-provision\",\n                \"--label\",\n                name,\n            ]\n        )\n\n    @classmethod\n    def setup_class(cls) -> None:\n        \"\"\"Setup test case.\"\"\"\n        if SKIP_TEST:\n            cls._is_teardown_class_called = True  # fix for teardown check fixture\n            raise pytest.skip(\"test skipped, check code to enable it\")\n        check_acapy = subprocess.run(\"aca-py\", shell=True, capture_output=True)  # nosec\n        assert b\"usage: aca-py\" in check_acapy.stdout, \"aca-py is not installed!\"\n\n        cls.port = 10001  # type: ignore\n        super(TestAriesSkillsDemo, cls).setup_class()\n        acapy_host = cls.ACAPY_HOST\n        cls.alice = \"alice\"  # type: ignore\n        cls.soef_id = \"intro_aries\" + str(  # type: ignore\n            randint(1000000, 99999999999999)  # nosec\n        )\n        cls.alice_seed = _rand_seed()  # type: ignore\n\n        cls.bob = \"bob\"  # type: ignore\n        cls.bob_seed = _rand_seed()  # type: ignore\n\n        cls.faber = \"faber\"  # type: ignore\n        cls.faber_seed = _rand_seed()  # type: ignore\n        cls.controller = \"controller\"  # type: ignore\n        cls.fetch_agent(\"fetchai/aries_alice\", cls.alice, is_local=True)  # type: ignore\n        cls.fetch_agent(\"fetchai/aries_alice\", cls.bob, is_local=True)  # type: ignore\n        cls.fetch_agent(\"fetchai/aries_faber\", cls.faber, is_local=True)  # type: ignore\n        cls.create_agents(\n            cls.controller,  # type: ignore\n        )\n\n        cls.set_agent_context(cls.controller)  # type: ignore\n        cls.add_item(\"connection\", \"fetchai/p2p_libp2p\")\n\n        addr = f\"127.0.0.1:{cls.get_port()}\"\n        p2p_config = {  # type: ignore\n            \"delegate_uri\": None,  # f\"127.0.0.1:{cls.get_port()}\",\n            \"entry_peers\": [],\n            \"local_uri\": addr,\n            \"public_uri\": addr,\n        }\n        cls.nested_set_config(\n            \"vendor.fetchai.connections.p2p_libp2p.config\", p2p_config\n        )\n        cls.generate_private_key(\"fetchai\", \"fetchai.key\")\n        cls.add_private_key(\"fetchai\", \"fetchai.key\")\n        cls.add_private_key(\"fetchai\", \"fetchai.key\", connection=True)\n        cls.run_cli_command(\"build\", cwd=cls._get_cwd())\n        cls.run_cli_command(\"issue-certificates\", cwd=cls._get_cwd())\n        r = cls.run_cli_command(\n            \"get-multiaddress\",\n            \"fetchai\",\n            \"-c\",\n            \"-i\",\n            str(P2PLibp2pConnection.connection_id),\n            \"-u\",\n            \"public_uri\",\n            cwd=cls._get_cwd(),\n        )\n        peer_addr = r.stdout.strip()\n        for agent_name in [cls.alice, cls.bob, cls.faber]:  # type: ignore\n            cls.set_agent_context(agent_name)\n            p2p_config = {\n                \"delegate_uri\": None,  # f\"127.0.0.1:{cls.get_port()}\",\n                \"entry_peers\": [peer_addr],\n                \"local_uri\": f\"127.0.0.1:{cls.get_port()}\",\n                \"public_uri\": None,\n            }\n            cls.generate_private_key(\"fetchai\", \"fetchai.key\")\n            cls.add_private_key(\"fetchai\", \"fetchai.key\")\n            cls.add_private_key(\n                \"fetchai\",\n                \"fetchai.key\",\n                connection=True,\n            )\n            cls.nested_set_config(\n                \"vendor.fetchai.connections.p2p_libp2p.config\", p2p_config\n            )\n\n            cls.run_cli_command(\"build\", cwd=cls._get_cwd())\n            cls.run_cli_command(\"issue-certificates\", cwd=cls._get_cwd())\n\n        cls.set_agent_context(cls.alice)  # type: ignore\n        cls.set_config(\n            \"vendor.fetchai.skills.aries_alice.models.strategy.args.seed\",\n            cls.alice_seed,  # type: ignore\n        )\n        cls.set_config(\n            \"vendor.fetchai.skills.aries_alice.models.strategy.args.service_data.value\",\n            cls.soef_id,  # type: ignore\n        )\n        cls.set_config(\n            \"vendor.fetchai.skills.aries_alice.models.strategy.args.search_query.search_value\",\n            cls.soef_id,  # type: ignore\n        )\n        cls.set_config(\n            \"vendor.fetchai.skills.aries_alice.models.strategy.args.admin_host\",\n            \"127.0.0.1\",\n        )\n        cls.set_config(\n            \"vendor.fetchai.skills.aries_alice.models.strategy.args.admin_port\",\n            \"8031\",\n            \"int\",\n        )\n\n        cls.set_config(\n            \"vendor.fetchai.connections.webhook.config.webhook_port\", \"8032\", \"int\"\n        )\n        cls.set_config(\n            \"vendor.fetchai.connections.webhook.config.webhook_address\", \"127.0.0.1\"\n        )\n        cls.set_config(\n            \"vendor.fetchai.connections.webhook.config.target_skill_id\",\n            str(ALICE_SKILL_PUBLIC_ID),\n        )\n        cls.set_config(\n            \"vendor.fetchai.connections.webhook.config.webhook_url_path\",\n            \"/webhooks/topic/{topic}/\",\n        )\n\n        cls.set_agent_context(cls.bob)  # type: ignore\n        cls.set_config(\n            \"vendor.fetchai.skills.aries_alice.models.strategy.args.seed\",\n            cls.bob_seed,  # type: ignore\n        )\n        cls.set_config(\n            \"vendor.fetchai.skills.aries_alice.models.strategy.args.service_data.value\",\n            cls.soef_id,  # type: ignore\n        )\n        cls.set_config(\n            \"vendor.fetchai.skills.aries_alice.models.strategy.args.search_query.search_value\",\n            cls.soef_id,  # type: ignore\n        )\n        cls.set_config(\n            \"vendor.fetchai.skills.aries_alice.models.strategy.args.admin_host\",\n            \"127.0.0.1\",\n        )\n        cls.set_config(\n            \"vendor.fetchai.skills.aries_alice.models.strategy.args.admin_port\",\n            \"8041\",\n            \"int\",\n        )\n\n        cls.set_config(\n            \"vendor.fetchai.connections.webhook.config.webhook_port\", \"8042\", \"int\"\n        )\n        cls.set_config(\n            \"vendor.fetchai.connections.webhook.config.webhook_address\", \"127.0.0.1\"\n        )\n        cls.set_config(\n            \"vendor.fetchai.connections.webhook.config.target_skill_id\",\n            str(ALICE_SKILL_PUBLIC_ID),\n        )\n        cls.set_config(\n            \"vendor.fetchai.connections.webhook.config.webhook_url_path\",\n            \"/webhooks/topic/{topic}/\",\n        )\n\n        cls.set_agent_context(cls.faber)  # type: ignore\n        cls.set_config(\n            \"vendor.fetchai.skills.aries_faber.models.strategy.args.seed\",\n            cls.faber_seed,  # type: ignore\n        )\n\n        cls.set_config(\n            \"vendor.fetchai.skills.aries_faber.models.strategy.args.search_query.search_value\",\n            cls.soef_id,  # type: ignore\n        )\n        cls.set_config(\n            \"vendor.fetchai.skills.aries_faber.models.strategy.args.admin_host\",\n            \"127.0.0.1\",\n        )\n        cls.set_config(\n            \"vendor.fetchai.skills.aries_faber.models.strategy.args.admin_port\",\n            \"8021\",\n            \"int\",\n        )\n\n        cls.set_config(\n            \"vendor.fetchai.connections.webhook.config.target_skill_id\",\n            str(FABER_SKILL_PUBLIC_ID),\n        )\n        cls.set_config(\n            \"vendor.fetchai.connections.webhook.config.webhook_port\", \"8022\", \"int\"\n        )\n        cls.set_config(\n            \"vendor.fetchai.connections.webhook.config.webhook_address\", \"127.0.0.1\"\n        )\n        cls.set_config(\n            \"vendor.fetchai.connections.webhook.config.webhook_url_path\",\n            \"/webhooks/topic/{topic}/\",\n        )\n\n        cls.extra_processes = [  # type: ignore\n            cls.start_acapy(\n                \"alice\",\n                8030,\n                cls.alice_seed,\n                acapy_host,\n                \"http://localhost:9000/genesis\",\n            ),\n            cls.start_acapy(\n                \"bob\",\n                8040,\n                cls.bob_seed,\n                acapy_host,\n                \"http://localhost:9000/genesis\",\n            ),\n            cls.start_acapy(\n                \"faber\",\n                8020,\n                cls.faber_seed,\n                acapy_host,\n                \"http://localhost:9000/genesis\",\n            ),\n        ]\n\n    def test_alice_faber_demo(self):\n        \"\"\"Run demo test.\"\"\"\n        self.set_agent_context(self.controller)\n        controller_process = self.run_agent()\n        self.extra_processes.append(controller_process)\n\n        check_strings = (\n            \"Starting libp2p node...\",\n            \"Connecting to libp2p node...\",\n            \"Successfully connected to libp2p node!\",\n            LIBP2P_SUCCESS_MESSAGE,\n        )\n\n        missing_strings = self.missing_from_output(\n            controller_process, check_strings, timeout=30, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in controller output.\".format(missing_strings)\n\n        self.set_agent_context(self.faber)\n        faber_process = self.run_agent()\n        self.extra_processes.append(faber_process)\n\n        self.set_agent_context(self.alice)\n        alice_process = self.run_agent()\n        self.extra_processes.append(alice_process)\n\n        self.set_agent_context(self.bob)\n        bob_process = self.run_agent()\n        self.extra_processes.append(bob_process)\n\n        missing_strings = self.missing_from_output(\n            faber_process,\n            [\"Connected to alice\", \"Connected to bob\"],\n            timeout=80,\n            is_terminating=False,\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in faber output.\".format(missing_strings)\n\n        missing_strings = self.missing_from_output(\n            alice_process,\n            [\"Connected to faber\", \"Got credentials proof from bob\"],\n            timeout=80,\n            is_terminating=False,\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in alice output.\".format(missing_strings)\n\n        missing_strings = self.missing_from_output(\n            bob_process,\n            [\"Connected to faber\", \"Got credentials proof from alice\"],\n            timeout=80,\n            is_terminating=False,\n        )\n        assert missing_strings == [], \"Strings {} didn't appear in bob output.\".format(\n            missing_strings\n        )\n\n    @classmethod\n    def teardown_class(cls) -> None:\n        \"\"\"Tear down test case.\"\"\"\n        super(TestAriesSkillsDemo, cls).teardown_class()\n        for proc in cls.extra_processes:  # type: ignore\n            proc.kill()\n            proc.wait(10)\n\n\nif __name__ == \"__main__\":\n    pytest.main([__file__])\n"
  },
  {
    "path": "tests/test_packages/test_skills_integration/test_carpark.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This test module contains the integration test for the weather skills.\"\"\"\n\nfrom random import uniform\n\nimport pytest\nfrom aea_ledger_fetchai import FetchAICrypto\n\nfrom aea.test_tools.test_cases import AEATestCaseManyFlaky\n\nfrom packages.fetchai.connections.p2p_libp2p.connection import LIBP2P_SUCCESS_MESSAGE\n\nfrom tests.conftest import (\n    FETCHAI_PRIVATE_KEY_FILE,\n    FETCHAI_PRIVATE_KEY_FILE_CONNECTION,\n    MAX_FLAKY_RERUNS_INTEGRATION,\n    NON_FUNDED_FETCHAI_PRIVATE_KEY_1,\n    NON_GENESIS_CONFIG,\n    wait_for_localhost_ports_to_close,\n)\n\n\n@pytest.mark.integration\nclass TestCarPark(AEATestCaseManyFlaky):\n    \"\"\"Test that carpark skills work.\"\"\"\n\n    @pytest.mark.flaky(\n        reruns=MAX_FLAKY_RERUNS_INTEGRATION\n    )  # cause possible network issues\n    def test_carpark(self):\n        \"\"\"Run the weather skills sequence.\"\"\"\n        carpark_aea_name = \"my_carpark_aea\"\n        carpark_client_aea_name = \"my_carpark_client_aea\"\n        self.create_agents(carpark_aea_name, carpark_client_aea_name)\n\n        default_routing = {\n            \"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n            \"fetchai/oef_search:1.1.7\": \"fetchai/soef:0.27.6\",\n        }\n\n        # generate random location\n        location = {\n            \"latitude\": round(uniform(-90, 90), 2),  # nosec\n            \"longitude\": round(uniform(-180, 180), 2),  # nosec\n        }\n\n        # Setup agent one\n        self.set_agent_context(carpark_aea_name)\n        self.add_item(\"connection\", \"fetchai/p2p_libp2p:0.27.5\")\n        self.add_item(\"connection\", \"fetchai/soef:0.27.6\")\n        self.set_config(\"agent.default_connection\", \"fetchai/p2p_libp2p:0.27.5\")\n        self.add_item(\"connection\", \"fetchai/ledger:0.21.5\")\n        self.add_item(\"skill\", \"fetchai/carpark_detection:0.27.6\")\n        setting_path = (\n            \"vendor.fetchai.skills.carpark_detection.models.strategy.args.is_ledger_tx\"\n        )\n        self.set_config(setting_path, False, \"bool\")\n        setting_path = \"agent.default_routing\"\n        self.nested_set_config(setting_path, default_routing)\n        self.run_install()\n\n        # add keys\n        self.generate_private_key(FetchAICrypto.identifier)\n        self.generate_private_key(\n            FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE_CONNECTION\n        )\n        self.add_private_key(FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE)\n        self.add_private_key(\n            FetchAICrypto.identifier,\n            FETCHAI_PRIVATE_KEY_FILE_CONNECTION,\n            connection=True,\n        )\n        self.replace_private_key_in_file(\n            NON_FUNDED_FETCHAI_PRIVATE_KEY_1, FETCHAI_PRIVATE_KEY_FILE_CONNECTION\n        )\n\n        # replace location\n        setting_path = (\n            \"vendor.fetchai.skills.carpark_detection.models.strategy.args.location\"\n        )\n        self.nested_set_config(setting_path, location)\n        self.run_cli_command(\"build\", cwd=self._get_cwd())\n        self.run_cli_command(\"issue-certificates\", cwd=self._get_cwd())\n\n        # Setup agent two\n        self.set_agent_context(carpark_client_aea_name)\n        self.add_item(\"connection\", \"fetchai/p2p_libp2p:0.27.5\")\n        self.add_item(\"connection\", \"fetchai/soef:0.27.6\")\n        self.set_config(\"agent.default_connection\", \"fetchai/p2p_libp2p:0.27.5\")\n        self.add_item(\"connection\", \"fetchai/ledger:0.21.5\")\n        self.add_item(\"skill\", \"fetchai/carpark_client:0.27.6\")\n        setting_path = (\n            \"vendor.fetchai.skills.carpark_client.models.strategy.args.is_ledger_tx\"\n        )\n        self.set_config(setting_path, False, \"bool\")\n        setting_path = \"agent.default_routing\"\n        self.nested_set_config(setting_path, default_routing)\n        self.run_install()\n\n        # add keys\n        self.generate_private_key(FetchAICrypto.identifier)\n        self.generate_private_key(\n            FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE_CONNECTION\n        )\n        self.add_private_key(FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE)\n        self.add_private_key(\n            FetchAICrypto.identifier,\n            FETCHAI_PRIVATE_KEY_FILE_CONNECTION,\n            connection=True,\n        )\n\n        # set p2p configs\n        setting_path = \"vendor.fetchai.connections.p2p_libp2p.config\"\n        self.nested_set_config(setting_path, NON_GENESIS_CONFIG)\n\n        # replace location\n        setting_path = (\n            \"vendor.fetchai.skills.carpark_client.models.strategy.args.location\"\n        )\n        self.nested_set_config(setting_path, location)\n        self.run_cli_command(\"build\", cwd=self._get_cwd())\n        self.run_cli_command(\"issue-certificates\", cwd=self._get_cwd())\n\n        # Fire the sub-processes and the threads.\n        self.set_agent_context(carpark_aea_name)\n        carpark_aea_process = self.run_agent()\n\n        check_strings = (\n            \"Starting libp2p node...\",\n            \"Connecting to libp2p node...\",\n            \"Successfully connected to libp2p node!\",\n            LIBP2P_SUCCESS_MESSAGE,\n        )\n        missing_strings = self.missing_from_output(\n            carpark_aea_process, check_strings, timeout=30, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in carpark_aea output.\".format(missing_strings)\n\n        self.set_agent_context(carpark_client_aea_name)\n        carpark_client_aea_process = self.run_agent()\n\n        check_strings = (\n            \"Starting libp2p node...\",\n            \"Connecting to libp2p node...\",\n            \"Successfully connected to libp2p node!\",\n            LIBP2P_SUCCESS_MESSAGE,\n        )\n        missing_strings = self.missing_from_output(\n            carpark_client_aea_process, check_strings, timeout=30, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in carpark_client_aea output.\".format(\n            missing_strings\n        )\n\n        check_strings = (\n            \"registering agent on SOEF.\",\n            \"registering agent's service on the SOEF.\",\n            \"registering agent's personality genus on the SOEF.\",\n            \"registering agent's personality classification on the SOEF.\",\n            \"received CFP from sender=\",\n            \"sending a PROPOSE with proposal=\",\n            \"received ACCEPT from sender=\",\n            \"sending MATCH_ACCEPT_W_INFORM to sender=\",\n            \"received INFORM from sender=\",\n            \"transaction confirmed, sending data=\",\n        )\n        missing_strings = self.missing_from_output(\n            carpark_aea_process, check_strings, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in carpark_aea output.\".format(missing_strings)\n\n        check_strings = (\n            \"found agents=\",\n            \"sending CFP to agent=\",\n            \"received proposal=\",\n            \"accepting the proposal from sender=\",\n            \"informing counterparty=\",\n            \"received INFORM from sender=\",\n            \"received the following data=\",\n        )\n        missing_strings = self.missing_from_output(\n            carpark_client_aea_process, check_strings, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in carpark_client_aea output.\".format(\n            missing_strings\n        )\n\n        self.terminate_agents(carpark_aea_process, carpark_client_aea_process)\n        assert (\n            self.is_successfully_terminated()\n        ), \"Agents weren't successfully terminated.\"\n        wait_for_localhost_ports_to_close([9000, 9001])\n\n\n@pytest.mark.integration\nclass TestCarParkFetchaiLedger(AEATestCaseManyFlaky):\n    \"\"\"Test that carpark skills work.\"\"\"\n\n    @pytest.mark.flaky(\n        reruns=MAX_FLAKY_RERUNS_INTEGRATION\n    )  # cause possible network issues\n    def test_carpark(self):\n        \"\"\"Run the weather skills sequence.\"\"\"\n        carpark_aea_name = \"my_carpark_aea\"\n        carpark_client_aea_name = \"my_carpark_client_aea\"\n        self.create_agents(carpark_aea_name, carpark_client_aea_name)\n\n        default_routing = {\n            \"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n            \"fetchai/oef_search:1.1.7\": \"fetchai/soef:0.27.6\",\n        }\n\n        # generate random location\n        location = {\n            \"latitude\": round(uniform(-90, 90), 2),  # nosec\n            \"longitude\": round(uniform(-180, 180), 2),  # nosec\n        }\n\n        # Setup agent one\n        self.set_agent_context(carpark_aea_name)\n        self.add_item(\"connection\", \"fetchai/p2p_libp2p:0.27.5\")\n        self.add_item(\"connection\", \"fetchai/soef:0.27.6\")\n        self.set_config(\"agent.default_connection\", \"fetchai/p2p_libp2p:0.27.5\")\n        self.add_item(\"connection\", \"fetchai/ledger:0.21.5\")\n        self.add_item(\"skill\", \"fetchai/carpark_detection:0.27.6\")\n        setting_path = \"agent.default_routing\"\n        self.nested_set_config(setting_path, default_routing)\n        self.run_install()\n\n        diff = self.difference_to_fetched_agent(\n            \"fetchai/car_detector:0.32.5\", carpark_aea_name\n        )\n        assert (\n            diff == []\n        ), \"Difference between created and fetched project for files={}\".format(diff)\n\n        # add keys\n        self.generate_private_key(FetchAICrypto.identifier)\n        self.generate_private_key(\n            FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE_CONNECTION\n        )\n        self.add_private_key(FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE)\n        self.add_private_key(\n            FetchAICrypto.identifier,\n            FETCHAI_PRIVATE_KEY_FILE_CONNECTION,\n            connection=True,\n        )\n        self.replace_private_key_in_file(\n            NON_FUNDED_FETCHAI_PRIVATE_KEY_1, FETCHAI_PRIVATE_KEY_FILE_CONNECTION\n        )\n\n        # replace location\n        setting_path = (\n            \"vendor.fetchai.skills.carpark_detection.models.strategy.args.location\"\n        )\n        self.nested_set_config(setting_path, location)\n        self.run_cli_command(\"build\", cwd=self._get_cwd())\n        self.run_cli_command(\"issue-certificates\", cwd=self._get_cwd())\n\n        # Setup agent two\n        self.set_agent_context(carpark_client_aea_name)\n        self.add_item(\"connection\", \"fetchai/p2p_libp2p:0.27.5\")\n        self.add_item(\"connection\", \"fetchai/soef:0.27.6\")\n        self.set_config(\"agent.default_connection\", \"fetchai/p2p_libp2p:0.27.5\")\n        self.add_item(\"connection\", \"fetchai/ledger:0.21.5\")\n        self.add_item(\"skill\", \"fetchai/carpark_client:0.27.6\")\n        setting_path = \"agent.default_routing\"\n        self.nested_set_config(setting_path, default_routing)\n        self.run_install()\n\n        diff = self.difference_to_fetched_agent(\n            \"fetchai/car_data_buyer:0.33.5\", carpark_client_aea_name\n        )\n        assert (\n            diff == []\n        ), \"Difference between created and fetched project for files={}\".format(diff)\n\n        # add keys\n        self.generate_private_key(FetchAICrypto.identifier)\n        self.generate_private_key(\n            FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE_CONNECTION\n        )\n        self.add_private_key(FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE)\n        self.add_private_key(\n            FetchAICrypto.identifier,\n            FETCHAI_PRIVATE_KEY_FILE_CONNECTION,\n            connection=True,\n        )\n\n        # fund key\n        self.generate_wealth(FetchAICrypto.identifier)\n\n        # set p2p configs\n        setting_path = \"vendor.fetchai.connections.p2p_libp2p.config\"\n        self.nested_set_config(setting_path, NON_GENESIS_CONFIG)\n\n        # replace location\n        setting_path = (\n            \"vendor.fetchai.skills.carpark_client.models.strategy.args.location\"\n        )\n        self.nested_set_config(setting_path, location)\n        self.run_cli_command(\"build\", cwd=self._get_cwd())\n        self.run_cli_command(\"issue-certificates\", cwd=self._get_cwd())\n\n        # Fire the sub-processes and the threads.\n        self.set_agent_context(carpark_aea_name)\n        carpark_aea_process = self.run_agent()\n\n        check_strings = (\n            \"Starting libp2p node...\",\n            \"Connecting to libp2p node...\",\n            \"Successfully connected to libp2p node!\",\n            LIBP2P_SUCCESS_MESSAGE,\n        )\n        missing_strings = self.missing_from_output(\n            carpark_aea_process, check_strings, timeout=30, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in carpark_aea output.\".format(missing_strings)\n\n        self.set_agent_context(carpark_client_aea_name)\n        carpark_client_aea_process = self.run_agent()\n\n        check_strings = (\n            \"Starting libp2p node...\",\n            \"Connecting to libp2p node...\",\n            \"Successfully connected to libp2p node!\",\n            LIBP2P_SUCCESS_MESSAGE,\n        )\n        missing_strings = self.missing_from_output(\n            carpark_client_aea_process, check_strings, timeout=30, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in carpark_client_aea output.\".format(\n            missing_strings\n        )\n\n        check_strings = (\n            \"registering agent on SOEF.\",\n            \"registering agent's service on the SOEF.\",\n            \"registering agent's personality genus on the SOEF.\",\n            \"registering agent's personality classification on the SOEF.\",\n            \"received CFP from sender=\",\n            \"sending a PROPOSE with proposal=\",\n            \"received ACCEPT from sender=\",\n            \"sending MATCH_ACCEPT_W_INFORM to sender=\",\n            \"received INFORM from sender=\",\n            \"checking whether transaction=\",\n            \"transaction confirmed, sending data=\",\n        )\n        missing_strings = self.missing_from_output(\n            carpark_aea_process, check_strings, timeout=120, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in carpark_aea output.\".format(missing_strings)\n\n        check_strings = (\n            \"found agents=\",\n            \"sending CFP to agent=\",\n            \"received proposal=\",\n            \"accepting the proposal from sender=\",\n            \"received MATCH_ACCEPT_W_INFORM from sender=\",\n            \"requesting transfer transaction from ledger api for message=\",\n            \"received raw transaction=\",\n            \"proposing the transaction to the decision maker. Waiting for confirmation ...\",\n            \"transaction signing was successful.\",\n            \"sending transaction to ledger.\",\n            \"transaction was successfully submitted. Transaction digest=\",\n            \"informing counterparty=\",\n            \"received INFORM from sender=\",\n            \"received the following data=\",\n        )\n        missing_strings = self.missing_from_output(\n            carpark_client_aea_process, check_strings, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in carpark_client_aea output.\".format(\n            missing_strings\n        )\n\n        self.terminate_agents(carpark_aea_process, carpark_client_aea_process)\n        assert (\n            self.is_successfully_terminated()\n        ), \"Agents weren't successfully terminated.\"\n        wait_for_localhost_ports_to_close([9000, 9001])\n"
  },
  {
    "path": "tests/test_packages/test_skills_integration/test_coin_price.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This test module contains the integration test for the coin price skill.\"\"\"\nimport time\nfrom typing import Dict\n\nimport pytest\n\nfrom aea.helpers import http_requests as requests\nfrom aea.test_tools.test_cases import AEATestCaseEmpty\n\nfrom tests.common.utils import wait_for_condition\n\n\ndef parse_prometheus_output(prom_data: bytes) -> Dict[str, float]:\n    \"\"\"Convert prometheus text output to a dict of {\"metric\": value}\"\"\"\n    metrics = {}\n    for line in prom_data.decode().splitlines():\n        tokens = line.split()\n        if tokens[0] != \"#\":\n            metrics.update({tokens[0]: float(tokens[1])})\n    return metrics\n\n\n@pytest.mark.integration\nclass TestCoinPriceSkill(AEATestCaseEmpty):\n    \"\"\"Test that coin price skill works.\"\"\"\n\n    def test_coin_price(self):\n        \"\"\"Run the coin price skill sequence.\"\"\"\n\n        coin_price_feed_aea_name = self.agent_name\n\n        self.generate_private_key()\n        self.add_private_key()\n        self.add_item(\"connection\", \"fetchai/http_client:0.24.6\")\n        self.add_item(\"connection\", \"fetchai/http_server:0.23.6\")\n        self.add_item(\"connection\", \"fetchai/prometheus:0.9.6\")\n        self.add_item(\"skill\", \"fetchai/advanced_data_request:0.7.6\")\n        self.set_config(\"agent.default_connection\", \"fetchai/http_server:0.23.6\")\n\n        default_routing = {\n            \"fetchai/http:1.1.7\": \"fetchai/http_client:0.24.6\",\n            \"fetchai/prometheus:1.1.7\": \"fetchai/prometheus:0.9.6\",\n        }\n        setting_path = \"agent.default_routing\"\n        self.nested_set_config(setting_path, default_routing)\n\n        # set 'api spec path' *after* comparison with fetched agent.\n        self.set_config(\n            \"vendor.fetchai.connections.http_server.config.api_spec_path\",\n            \"vendor/fetchai/skills/advanced_data_request/api_spec.yaml\",\n        )\n        self.set_config(\n            \"vendor.fetchai.connections.http_server.config.target_skill_id\",\n            \"fetchai/advanced_data_request:0.7.6\",\n        )\n        self.set_config(\n            \"vendor.fetchai.skills.advanced_data_request.models.advanced_data_request_model.args.use_http_server\",\n            True,\n            type_=\"bool\",\n        )\n        self.set_config(\n            \"vendor.fetchai.skills.advanced_data_request.models.advanced_data_request_model.args.url\",\n            \"https://api.coingecko.com/api/v3/simple/price?ids=fetch-ai&vs_currencies=usd\",\n            type_=\"str\",\n        )\n        self.set_config(\n            \"vendor.fetchai.skills.advanced_data_request.models.advanced_data_request_model.args.outputs\",\n            '[{\"name\": \"price\", \"json_path\": \"fetch-ai.usd\"}]',\n            type_=\"list\",\n        )\n\n        diff = self.difference_to_fetched_agent(\n            \"fetchai/coin_price_feed:0.15.5\", coin_price_feed_aea_name\n        )\n        assert (\n            diff == []\n        ), \"Difference between created and fetched project for files={}\".format(diff)\n\n        self.run_install()\n\n        process = self.run_agent()\n        is_running = self.is_running(process)\n        assert is_running, \"AEA not running within timeout!\"\n\n        time.sleep(6)  # we wait a bit longer than the tick rate of the behaviour\n\n        def wait():\n            response = requests.get(\"http://127.0.0.1:8000/data\")\n            if response.status_code != 200:\n                return False\n            coin_price = response.json()\n            return \"price\" in coin_price\n\n        wait_for_condition(\n            wait, timeout=10, period=0.1, error_msg=\"Response does not contain 'price'\"\n        )\n\n        response = requests.get(\"http://127.0.0.1:8000\")\n        assert response.status_code == 404\n        assert response.content == b\"\", \"Get request should not work without valid path\"\n\n        response = requests.post(\"http://127.0.0.1:8000/data\")\n        assert response.status_code == 404\n        assert response.content == b\"\", \"Post not allowed\"\n\n        # test prometheus metrics\n        prom_response = requests.get(\"http://127.0.0.1:9090/metrics\")\n        metrics = parse_prometheus_output(prom_response.content)\n        assert metrics[\"num_retrievals\"] > 0.0, \"num_retrievals metric not updated\"\n        assert metrics[\"num_requests\"] == 1.0, \"num_requests metric not equal to 1\"\n\n        self.terminate_agents()\n        assert (\n            self.is_successfully_terminated()\n        ), \"Http echo agent wasn't successfully terminated.\"\n"
  },
  {
    "path": "tests/test_packages/test_skills_integration/test_erc1155.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This test module contains the integration test for the generic buyer and seller skills.\"\"\"\nimport json\nfrom random import uniform\n\nimport pytest\nfrom aea_ledger_ethereum import EthereumCrypto\nfrom aea_ledger_fetchai import FetchAICrypto\n\nfrom aea.test_tools.test_cases import AEATestCaseManyFlaky\n\nfrom packages.fetchai.connections.p2p_libp2p.connection import LIBP2P_SUCCESS_MESSAGE\n\nfrom tests.conftest import (\n    ETHEREUM_PRIVATE_KEY_FILE,\n    FETCHAI_PRIVATE_KEY_FILE_CONNECTION,\n    FUNDED_ETH_PRIVATE_KEY_2,\n    FUNDED_ETH_PRIVATE_KEY_3,\n    MAX_FLAKY_RERUNS_ETH,\n    NON_FUNDED_FETCHAI_PRIVATE_KEY_1,\n    NON_GENESIS_CONFIG,\n    UseGanache,\n    wait_for_localhost_ports_to_close,\n)\n\n\n@pytest.mark.integration\nclass TestERCSkillsEthereumLedger(AEATestCaseManyFlaky, UseGanache):\n    \"\"\"Test that erc1155 skills work.\"\"\"\n\n    @pytest.mark.integration\n    @pytest.mark.ledger\n    @pytest.mark.flaky(reruns=MAX_FLAKY_RERUNS_ETH)  # cause possible network issues\n    def test_generic(self):\n        \"\"\"Run the generic skills sequence.\"\"\"\n        deploy_aea_name = \"deploy_aea\"\n        client_aea_name = \"client_aea\"\n\n        self.create_agents(deploy_aea_name, client_aea_name)\n\n        # add ethereum ledger in both configuration files\n        default_routing = {\n            \"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n            \"fetchai/contract_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n            \"fetchai/oef_search:1.1.7\": \"fetchai/soef:0.27.6\",\n        }\n\n        # generate random location\n        location = {\n            \"latitude\": round(uniform(-90, 90), 2),  # nosec\n            \"longitude\": round(uniform(-180, 180), 2),  # nosec\n        }\n\n        # add packages for agent one\n        self.set_agent_context(deploy_aea_name)\n        self.add_item(\"connection\", \"fetchai/p2p_libp2p:0.27.5\")\n        self.add_item(\"connection\", \"fetchai/ledger:0.21.5\")\n        self.add_item(\"connection\", \"fetchai/soef:0.27.6\")\n        self.set_config(\"agent.default_connection\", \"fetchai/p2p_libp2p:0.27.5\")\n        self.set_config(\"agent.default_ledger\", EthereumCrypto.identifier)\n        self.nested_set_config(\n            \"agent.required_ledgers\",\n            [FetchAICrypto.identifier, EthereumCrypto.identifier],\n        )\n        setting_path = \"agent.default_routing\"\n        self.nested_set_config(setting_path, default_routing)\n        self.add_item(\"skill\", \"fetchai/erc1155_deploy:0.31.6\")\n\n        self.generate_private_key(EthereumCrypto.identifier)\n        self.add_private_key(EthereumCrypto.identifier, ETHEREUM_PRIVATE_KEY_FILE)\n        self.replace_private_key_in_file(\n            FUNDED_ETH_PRIVATE_KEY_3, ETHEREUM_PRIVATE_KEY_FILE\n        )\n        self.generate_private_key(\n            FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE_CONNECTION\n        )\n        self.add_private_key(\n            FetchAICrypto.identifier,\n            FETCHAI_PRIVATE_KEY_FILE_CONNECTION,\n            connection=True,\n        )\n        self.replace_private_key_in_file(\n            NON_FUNDED_FETCHAI_PRIVATE_KEY_1, FETCHAI_PRIVATE_KEY_FILE_CONNECTION\n        )\n        setting_path = \"vendor.fetchai.connections.soef.config.chain_identifier\"\n        self.set_config(setting_path, \"ethereum\")\n        setting_path = \"vendor.fetchai.connections.p2p_libp2p.cert_requests\"\n        settings = json.dumps(\n            [\n                {\n                    \"identifier\": \"acn\",\n                    \"ledger_id\": EthereumCrypto.identifier,\n                    \"not_after\": \"2023-01-01\",\n                    \"not_before\": \"2022-01-01\",\n                    \"public_key\": FetchAICrypto.identifier,\n                    \"message_format\": \"{public_key}\",\n                    \"save_path\": \".certs/conn_cert.txt\",\n                }\n            ]\n        )\n        self.set_config(setting_path, settings, type_=\"list\")\n        self.run_install()\n\n        # replace location\n        setting_path = (\n            \"vendor.fetchai.skills.erc1155_deploy.models.strategy.args.location\"\n        )\n        self.nested_set_config(setting_path, location)\n\n        diff = self.difference_to_fetched_agent(\n            \"fetchai/erc1155_deployer:0.34.5\", deploy_aea_name\n        )\n        assert (\n            diff == []\n        ), \"Difference between created and fetched project for files={}\".format(diff)\n\n        # add packages for agent two\n        self.set_agent_context(client_aea_name)\n        self.add_item(\"connection\", \"fetchai/p2p_libp2p:0.27.5\")\n        self.add_item(\"connection\", \"fetchai/ledger:0.21.5\")\n        self.add_item(\"connection\", \"fetchai/soef:0.27.6\")\n        self.set_config(\"agent.default_connection\", \"fetchai/p2p_libp2p:0.27.5\")\n        self.set_config(\"agent.default_ledger\", EthereumCrypto.identifier)\n        self.nested_set_config(\n            \"agent.required_ledgers\",\n            [FetchAICrypto.identifier, EthereumCrypto.identifier],\n        )\n        setting_path = \"agent.default_routing\"\n        self.nested_set_config(setting_path, default_routing)\n        self.add_item(\"skill\", \"fetchai/erc1155_client:0.29.6\")\n\n        self.generate_private_key(EthereumCrypto.identifier)\n        self.add_private_key(EthereumCrypto.identifier, ETHEREUM_PRIVATE_KEY_FILE)\n        self.replace_private_key_in_file(\n            FUNDED_ETH_PRIVATE_KEY_2, ETHEREUM_PRIVATE_KEY_FILE\n        )\n        self.generate_private_key(\n            FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE_CONNECTION\n        )\n        self.add_private_key(\n            FetchAICrypto.identifier,\n            FETCHAI_PRIVATE_KEY_FILE_CONNECTION,\n            connection=True,\n        )\n        setting_path = \"vendor.fetchai.connections.soef.config.chain_identifier\"\n        self.set_config(setting_path, \"ethereum\")\n        setting_path = \"vendor.fetchai.connections.p2p_libp2p.config\"\n        self.nested_set_config(setting_path, NON_GENESIS_CONFIG)\n        setting_path = \"vendor.fetchai.connections.p2p_libp2p.cert_requests\"\n        settings = json.dumps(\n            [\n                {\n                    \"identifier\": \"acn\",\n                    \"ledger_id\": EthereumCrypto.identifier,\n                    \"not_after\": \"2023-01-01\",\n                    \"not_before\": \"2022-01-01\",\n                    \"public_key\": FetchAICrypto.identifier,\n                    \"message_format\": \"{public_key}\",\n                    \"save_path\": \".certs/conn_cert.txt\",\n                }\n            ]\n        )\n        self.set_config(setting_path, settings, type_=\"list\")\n        self.run_install()\n\n        # replace location\n        setting_path = (\n            \"vendor.fetchai.skills.erc1155_client.models.strategy.args.location\"\n        )\n        self.nested_set_config(setting_path, location)\n\n        diff = self.difference_to_fetched_agent(\n            \"fetchai/erc1155_client:0.34.5\", client_aea_name\n        )\n        assert (\n            diff == []\n        ), \"Difference between created and fetched project for files={}\".format(diff)\n\n        # run agents\n        self.set_agent_context(deploy_aea_name)\n        self.run_cli_command(\"build\", cwd=self._get_cwd())\n        self.run_cli_command(\"issue-certificates\", cwd=self._get_cwd())\n        deploy_aea_process = self.run_agent()\n\n        check_strings = (\n            \"Starting libp2p node...\",\n            \"Connecting to libp2p node...\",\n            \"Successfully connected to libp2p node!\",\n            LIBP2P_SUCCESS_MESSAGE,\n        )\n        missing_strings = self.missing_from_output(\n            deploy_aea_process, check_strings, timeout=30, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in deploy_aea output.\".format(missing_strings)\n\n        check_strings = (\n            \"starting balance on ethereum ledger=\",\n            \"received raw transaction=\",\n            \"proposing the transaction to the decision maker. Waiting for confirmation ...\",\n            \"transaction signing was successful.\",\n            \"sending transaction to ledger.\",\n            \"transaction was successfully submitted. Transaction digest=\",\n            \"requesting transaction receipt.\",\n            \"transaction was successfully settled. Transaction receipt=\",\n            \"requesting create batch transaction...\",\n            \"requesting mint batch transaction...\",\n            \"registering agent on SOEF.\",\n            \"registering agent's service on the SOEF.\",\n            \"registering agent's personality genus on the SOEF.\",\n            \"registering agent's personality classification on the SOEF.\",\n        )\n        missing_strings = self.missing_from_output(\n            deploy_aea_process, check_strings, timeout=420, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in deploy_aea output.\".format(missing_strings)\n\n        self.set_agent_context(client_aea_name)\n        self.run_cli_command(\"build\", cwd=self._get_cwd())\n        self.run_cli_command(\"issue-certificates\", cwd=self._get_cwd())\n        client_aea_process = self.run_agent()\n\n        check_strings = (\n            \"Starting libp2p node...\",\n            \"Connecting to libp2p node...\",\n            \"Successfully connected to libp2p node!\",\n            LIBP2P_SUCCESS_MESSAGE,\n        )\n        missing_strings = self.missing_from_output(\n            client_aea_process, check_strings, timeout=30, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in client_aea output.\".format(missing_strings)\n\n        check_strings = (\n            \"received CFP from sender=\",\n            \"sending PROPOSE to agent=\",\n            \"received ACCEPT_W_INFORM from sender=\",\n            \"requesting single atomic swap transaction...\",\n            \"received raw transaction=\",\n            \"proposing the transaction to the decision maker. Waiting for confirmation ...\",\n            \"transaction signing was successful.\",\n            \"sending transaction to ledger.\",\n            \"transaction was successfully submitted. Transaction digest=\",\n            \"requesting transaction receipt.\",\n            \"transaction was successfully settled. Transaction receipt=\",\n            \"demo finished!\",\n        )\n        missing_strings = self.missing_from_output(\n            deploy_aea_process, check_strings, timeout=360, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in deploy_aea output.\".format(missing_strings)\n\n        check_strings = (\n            \"found agents=\",\n            \"sending CFP to agent=\",\n            \"received valid PROPOSE from sender=\",\n            \"requesting single hash message from contract api...\",\n            \"received raw message=\",\n            \"proposing the transaction to the decision maker. Waiting for confirmation ...\",\n            \"sending ACCEPT_W_INFORM to agent=\",\n        )\n        missing_strings = self.missing_from_output(\n            client_aea_process, check_strings, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in client_aea output.\".format(missing_strings)\n\n        self.terminate_agents(deploy_aea_process, client_aea_process)\n        assert (\n            self.is_successfully_terminated()\n        ), \"Agents weren't successfully terminated.\"\n        wait_for_localhost_ports_to_close([9000, 9001])\n"
  },
  {
    "path": "tests/test_packages/test_skills_integration/test_fetch_block.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This test module contains the integration test for the fetch block skill.\"\"\"\n\nimport pytest\n\nfrom aea.test_tools.test_cases import AEATestCaseEmpty\n\n\n@pytest.mark.integration\nclass TestFetchBlockSkill(AEATestCaseEmpty):\n    \"\"\"Test that fetch block skill works.\"\"\"\n\n    def test_fetch_block(self):\n        \"\"\"Run the fetch block skill sequence.\"\"\"\n        self.generate_private_key()\n        self.add_private_key()\n        self.add_item(\"connection\", \"fetchai/ledger:0.21.5\")\n        self.add_item(\"skill\", \"fetchai/fetch_block:0.12.6\")\n        self.set_config(\"agent.default_connection\", \"fetchai/ledger:0.21.5\")\n\n        self.run_install()\n\n        process = self.run_agent()\n        is_running = self.is_running(process)\n        assert is_running, \"AEA not running within timeout!\"\n\n        check_strings = (\n            \"setting up FetchBlockBehaviour\",\n            \"Fetching latest block...\",\n            \"Retrieved latest block:\",\n        )\n        missing_strings = self.missing_from_output(process, check_strings)\n        assert len(missing_strings) in [\n            0,\n            1,\n        ], \"Strings {} didn't appear in agent output.\".format(missing_strings)\n\n        self.terminate_agents()\n        assert self.is_successfully_terminated(), \"AEA wasn't successfully terminated.\"\n"
  },
  {
    "path": "tests/test_packages/test_skills_integration/test_generic.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This test module contains the integration test for the generic buyer and seller skills.\"\"\"\n\nfrom random import uniform\n\nimport pytest\nfrom aea_ledger_fetchai import FetchAICrypto\n\nfrom aea.test_tools.test_cases import AEATestCaseManyFlaky\n\nfrom packages.fetchai.connections.p2p_libp2p.connection import LIBP2P_SUCCESS_MESSAGE\n\nfrom tests.conftest import (\n    FETCHAI_PRIVATE_KEY_FILE,\n    FETCHAI_PRIVATE_KEY_FILE_CONNECTION,\n    MAX_FLAKY_RERUNS_INTEGRATION,\n    NON_FUNDED_FETCHAI_PRIVATE_KEY_1,\n    NON_GENESIS_CONFIG,\n    wait_for_localhost_ports_to_close,\n)\n\n\n@pytest.mark.integration\nclass TestGenericSkills(AEATestCaseManyFlaky):\n    \"\"\"Test that generic skills work.\"\"\"\n\n    capture_log = True\n\n    @pytest.mark.flaky(\n        reruns=MAX_FLAKY_RERUNS_INTEGRATION\n    )  # cause possible network issues\n    def test_generic(self, pytestconfig):\n        \"\"\"Run the generic skills sequence.\"\"\"\n        seller_aea_name = \"my_generic_seller\"\n        buyer_aea_name = \"my_generic_buyer\"\n        self.create_agents(seller_aea_name, buyer_aea_name)\n\n        default_routing = {\n            \"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n            \"fetchai/oef_search:1.1.7\": \"fetchai/soef:0.27.6\",\n        }\n\n        # generate random location\n        location = {\n            \"latitude\": round(uniform(-90, 90), 2),  # nosec\n            \"longitude\": round(uniform(-180, 180), 2),  # nosec\n        }\n\n        # prepare seller agent\n        self.set_agent_context(seller_aea_name)\n        self.add_item(\"connection\", \"fetchai/p2p_libp2p:0.27.5\")\n        self.add_item(\"connection\", \"fetchai/soef:0.27.6\")\n        self.set_config(\"agent.default_connection\", \"fetchai/p2p_libp2p:0.27.5\")\n        self.add_item(\"connection\", \"fetchai/ledger:0.21.5\")\n        self.add_item(\"skill\", \"fetchai/generic_seller:0.28.6\")\n        setting_path = (\n            \"vendor.fetchai.skills.generic_seller.models.strategy.args.is_ledger_tx\"\n        )\n        self.set_config(setting_path, False, \"bool\")\n        setting_path = \"agent.default_routing\"\n        self.nested_set_config(setting_path, default_routing)\n        self.run_install()\n\n        # add keys\n        self.generate_private_key(FetchAICrypto.identifier)\n        self.generate_private_key(\n            FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE_CONNECTION\n        )\n        self.add_private_key(FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE)\n        self.add_private_key(\n            FetchAICrypto.identifier,\n            FETCHAI_PRIVATE_KEY_FILE_CONNECTION,\n            connection=True,\n        )\n        self.replace_private_key_in_file(\n            NON_FUNDED_FETCHAI_PRIVATE_KEY_1, FETCHAI_PRIVATE_KEY_FILE_CONNECTION\n        )\n\n        # make runable:\n        setting_path = \"vendor.fetchai.skills.generic_seller.is_abstract\"\n        self.set_config(setting_path, False, \"bool\")\n\n        # replace location\n        setting_path = (\n            \"vendor.fetchai.skills.generic_seller.models.strategy.args.location\"\n        )\n        self.nested_set_config(setting_path, location)\n        self.run_cli_command(\"build\", cwd=self._get_cwd())\n        self.run_cli_command(\"issue-certificates\", cwd=self._get_cwd())\n\n        # prepare buyer agent\n        self.set_agent_context(buyer_aea_name)\n        self.add_item(\"connection\", \"fetchai/p2p_libp2p:0.27.5\")\n        self.add_item(\"connection\", \"fetchai/soef:0.27.6\")\n        self.set_config(\"agent.default_connection\", \"fetchai/p2p_libp2p:0.27.5\")\n        self.add_item(\"connection\", \"fetchai/ledger:0.21.5\")\n        self.add_item(\"skill\", \"fetchai/generic_buyer:0.27.6\")\n        setting_path = (\n            \"vendor.fetchai.skills.generic_buyer.models.strategy.args.is_ledger_tx\"\n        )\n        self.set_config(setting_path, False, \"bool\")\n        setting_path = \"agent.default_routing\"\n        self.nested_set_config(setting_path, default_routing)\n\n        self.run_install()\n\n        # add keys\n        self.generate_private_key(FetchAICrypto.identifier)\n        self.generate_private_key(\n            FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE_CONNECTION\n        )\n        self.add_private_key(FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE)\n        self.add_private_key(\n            FetchAICrypto.identifier,\n            FETCHAI_PRIVATE_KEY_FILE_CONNECTION,\n            connection=True,\n        )\n\n        # set p2p configs\n        setting_path = \"vendor.fetchai.connections.p2p_libp2p.config\"\n        self.nested_set_config(setting_path, NON_GENESIS_CONFIG)\n\n        # make runable:\n        setting_path = \"vendor.fetchai.skills.generic_buyer.is_abstract\"\n        self.set_config(setting_path, False, \"bool\")\n\n        # replace location\n        setting_path = (\n            \"vendor.fetchai.skills.generic_buyer.models.strategy.args.location\"\n        )\n        self.nested_set_config(setting_path, location)\n        self.run_cli_command(\"build\", cwd=self._get_cwd())\n        self.run_cli_command(\"issue-certificates\", cwd=self._get_cwd())\n\n        # run AEAs\n        self.set_agent_context(seller_aea_name)\n        seller_aea_process = self.run_agent()\n\n        check_strings = (\n            \"Starting libp2p node...\",\n            \"Connecting to libp2p node...\",\n            \"Successfully connected to libp2p node!\",\n            LIBP2P_SUCCESS_MESSAGE,\n        )\n        missing_strings = self.missing_from_output(\n            seller_aea_process, check_strings, timeout=30, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in seller_aea output.\".format(missing_strings)\n\n        self.set_agent_context(buyer_aea_name)\n        buyer_aea_process = self.run_agent()\n\n        check_strings = (\n            \"Starting libp2p node...\",\n            \"Connecting to libp2p node...\",\n            \"Successfully connected to libp2p node!\",\n            LIBP2P_SUCCESS_MESSAGE,\n        )\n        missing_strings = self.missing_from_output(\n            buyer_aea_process, check_strings, timeout=30, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in buyer_aea output.\".format(missing_strings)\n\n        check_strings = (\n            \"registering agent on SOEF.\",\n            \"registering agent's service on the SOEF.\",\n            \"registering agent's personality genus on the SOEF.\",\n            \"registering agent's personality classification on the SOEF.\",\n            \"received CFP from sender=\",\n            \"sending a PROPOSE with proposal=\",\n            \"received ACCEPT from sender=\",\n            \"sending MATCH_ACCEPT_W_INFORM to sender=\",\n            \"received INFORM from sender=\",\n            \"transaction confirmed, sending data=\",\n        )\n        missing_strings = self.missing_from_output(\n            seller_aea_process, check_strings, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in seller_aea output.\".format(missing_strings)\n\n        check_strings = (\n            \"found agents=\",\n            \"sending CFP to agent=\",\n            \"received proposal=\",\n            \"accepting the proposal from sender=\",\n            \"received MATCH_ACCEPT_W_INFORM from sender=\",\n            \"informing counterparty=\",\n            \"received INFORM from sender=\",\n            \"received the following data=\",\n        )\n        missing_strings = self.missing_from_output(\n            buyer_aea_process, check_strings, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in buyer_aea output.\".format(missing_strings)\n\n        self.terminate_agents(seller_aea_process, buyer_aea_process)\n        assert (\n            self.is_successfully_terminated()\n        ), \"Agents weren't successfully terminated.\"\n        wait_for_localhost_ports_to_close([9000, 9001])\n\n\n@pytest.mark.sync\n@pytest.mark.integration\nclass TestGenericSkillsFetchaiLedger(AEATestCaseManyFlaky):\n    \"\"\"Test that generic skills work.\"\"\"\n\n    capture_log = True\n\n    @pytest.mark.flaky(\n        reruns=MAX_FLAKY_RERUNS_INTEGRATION\n    )  # cause possible network issues\n    def test_generic(self, pytestconfig):\n        \"\"\"Run the generic skills sequence.\"\"\"\n        seller_aea_name = \"my_generic_seller\"\n        buyer_aea_name = \"my_generic_buyer\"\n        self.create_agents(seller_aea_name, buyer_aea_name)\n\n        default_routing = {\n            \"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n            \"fetchai/oef_search:1.1.7\": \"fetchai/soef:0.27.6\",\n        }\n\n        # generate random location\n        location = {\n            \"latitude\": round(uniform(-90, 90), 2),  # nosec\n            \"longitude\": round(uniform(-180, 180), 2),  # nosec\n        }\n\n        # prepare seller agent\n        self.set_agent_context(seller_aea_name)\n        self.add_item(\"connection\", \"fetchai/p2p_libp2p:0.27.5\")\n        self.add_item(\"connection\", \"fetchai/soef:0.27.6\")\n        self.set_config(\"agent.default_connection\", \"fetchai/p2p_libp2p:0.27.5\")\n        self.add_item(\"connection\", \"fetchai/ledger:0.21.5\")\n        self.add_item(\"skill\", \"fetchai/generic_seller:0.28.6\")\n        setting_path = \"agent.default_routing\"\n        self.nested_set_config(setting_path, default_routing)\n        self.run_install()\n\n        diff = self.difference_to_fetched_agent(\n            \"fetchai/generic_seller:0.29.5\", seller_aea_name\n        )\n        assert (\n            diff == []\n        ), \"Difference between created and fetched project for files={}\".format(diff)\n\n        # add keys\n        self.generate_private_key(FetchAICrypto.identifier)\n        self.generate_private_key(\n            FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE_CONNECTION\n        )\n        self.add_private_key(FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE)\n        self.add_private_key(\n            FetchAICrypto.identifier,\n            FETCHAI_PRIVATE_KEY_FILE_CONNECTION,\n            connection=True,\n        )\n        self.replace_private_key_in_file(\n            NON_FUNDED_FETCHAI_PRIVATE_KEY_1, FETCHAI_PRIVATE_KEY_FILE_CONNECTION\n        )\n\n        # make runable:\n        setting_path = \"vendor.fetchai.skills.generic_seller.is_abstract\"\n        self.set_config(setting_path, False, \"bool\")\n\n        # replace location\n        setting_path = (\n            \"vendor.fetchai.skills.generic_seller.models.strategy.args.location\"\n        )\n        self.nested_set_config(setting_path, location)\n        self.run_cli_command(\"build\", cwd=self._get_cwd())\n        self.run_cli_command(\"issue-certificates\", cwd=self._get_cwd())\n\n        # prepare buyer agent\n        self.set_agent_context(buyer_aea_name)\n        self.add_item(\"connection\", \"fetchai/p2p_libp2p:0.27.5\")\n        self.add_item(\"connection\", \"fetchai/soef:0.27.6\")\n        self.set_config(\"agent.default_connection\", \"fetchai/p2p_libp2p:0.27.5\")\n        self.add_item(\"connection\", \"fetchai/ledger:0.21.5\")\n        self.add_item(\"skill\", \"fetchai/generic_buyer:0.27.6\")\n        setting_path = \"agent.default_routing\"\n        self.nested_set_config(setting_path, default_routing)\n\n        self.run_install()\n\n        diff = self.difference_to_fetched_agent(\n            \"fetchai/generic_buyer:0.30.5\", buyer_aea_name\n        )\n        assert (\n            diff == []\n        ), \"Difference between created and fetched project for files={}\".format(diff)\n\n        setting_path = \"vendor.fetchai.skills.generic_buyer.is_abstract\"\n        self.set_config(setting_path, False, \"bool\")\n        self.set_config(\n            \"vendor.fetchai.skills.generic_buyer.models.strategy.args.max_tx_fee\",\n            7750000000000000,\n        )\n\n        # add keys\n        self.generate_private_key(FetchAICrypto.identifier)\n        self.generate_private_key(\n            FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE_CONNECTION\n        )\n        self.add_private_key(FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE)\n        self.add_private_key(\n            FetchAICrypto.identifier,\n            FETCHAI_PRIVATE_KEY_FILE_CONNECTION,\n            connection=True,\n        )\n\n        # fund key\n        self.generate_wealth(FetchAICrypto.identifier)\n\n        # set p2p configs\n        setting_path = \"vendor.fetchai.connections.p2p_libp2p.config\"\n        self.nested_set_config(setting_path, NON_GENESIS_CONFIG)\n\n        # replace location\n        setting_path = (\n            \"vendor.fetchai.skills.generic_buyer.models.strategy.args.location\"\n        )\n        self.nested_set_config(setting_path, location)\n        self.run_cli_command(\"build\", cwd=self._get_cwd())\n        self.run_cli_command(\"issue-certificates\", cwd=self._get_cwd())\n\n        # run AEAs\n        self.set_agent_context(seller_aea_name)\n        seller_aea_process = self.run_agent()\n\n        check_strings = (\n            \"Starting libp2p node...\",\n            \"Connecting to libp2p node...\",\n            \"Successfully connected to libp2p node!\",\n            LIBP2P_SUCCESS_MESSAGE,\n        )\n        missing_strings = self.missing_from_output(\n            seller_aea_process, check_strings, timeout=30, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in seller_aea output.\".format(missing_strings)\n\n        self.set_agent_context(buyer_aea_name)\n        buyer_aea_process = self.run_agent()\n\n        check_strings = (\n            \"Starting libp2p node...\",\n            \"Connecting to libp2p node...\",\n            \"Successfully connected to libp2p node!\",\n            LIBP2P_SUCCESS_MESSAGE,\n        )\n        missing_strings = self.missing_from_output(\n            buyer_aea_process, check_strings, timeout=30, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in buyer_aea output.\".format(missing_strings)\n\n        check_strings = (\n            \"registering agent on SOEF.\",\n            \"registering agent's service on the SOEF.\",\n            \"registering agent's personality genus on the SOEF.\",\n            \"registering agent's personality classification on the SOEF.\",\n            \"received CFP from sender=\",\n            \"sending a PROPOSE with proposal=\",\n            \"received ACCEPT from sender=\",\n            \"sending MATCH_ACCEPT_W_INFORM to sender=\",\n            \"received INFORM from sender=\",\n            \"checking whether transaction=\",\n            \"transaction confirmed, sending data=\",\n        )\n        missing_strings = self.missing_from_output(\n            seller_aea_process, check_strings, timeout=120, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in seller_aea output.\".format(missing_strings)\n\n        check_strings = (\n            \"found agents=\",\n            \"sending CFP to agent=\",\n            \"received proposal=\",\n            \"accepting the proposal from sender=\",\n            \"received MATCH_ACCEPT_W_INFORM from sender=\",\n            \"requesting transfer transaction from ledger api for message=\",\n            \"received raw transaction=\",\n            \"proposing the transaction to the decision maker. Waiting for confirmation ...\",\n            \"transaction signing was successful.\",\n            \"sending transaction to ledger.\",\n            \"transaction was successfully submitted. Transaction digest=\",\n            \"transaction confirmed, informing counterparty=\",\n            \"received INFORM from sender=\",\n            \"received the following data=\",\n        )\n        missing_strings = self.missing_from_output(\n            buyer_aea_process, check_strings, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in buyer_aea output.\".format(missing_strings)\n\n        self.terminate_agents(seller_aea_process, buyer_aea_process)\n        assert (\n            self.is_successfully_terminated()\n        ), \"Agents weren't successfully terminated.\"\n        wait_for_localhost_ports_to_close([9000, 9001])\n"
  },
  {
    "path": "tests/test_packages/test_skills_integration/test_gym.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This test module contains the integration test for the gym skill.\"\"\"\n\nimport os\nimport shutil\n\nfrom aea.test_tools.test_cases import AEATestCaseEmpty\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass TestGymSkill(AEATestCaseEmpty):\n    \"\"\"Test that gym skill works.\"\"\"\n\n    def test_gym(self):\n        \"\"\"Run the gym skill sequence.\"\"\"\n        self.generate_private_key()\n        self.add_private_key()\n        self.add_item(\"skill\", \"fetchai/gym:0.21.6\")\n        self.run_install()\n\n        # change default connection\n        setting_path = \"agent.default_connection\"\n        self.set_config(setting_path, \"fetchai/gym:0.20.6\")\n\n        diff = self.difference_to_fetched_agent(\n            \"fetchai/gym_aea:0.26.5\", self.agent_name\n        )\n        assert (\n            diff == []\n        ), \"Difference between created and fetched project for files={}\".format(diff)\n\n        # change connection config\n        setting_path = \"vendor.fetchai.connections.gym.config.env\"\n        self.set_config(setting_path, \"gyms.env.BanditNArmedRandom\")\n\n        # add gyms folder from examples\n        gyms_src = os.path.join(ROOT_DIR, \"examples\", \"gym_ex\", \"gyms\")\n        gyms_dst = os.path.join(self.agent_name, \"gyms\")\n        shutil.copytree(gyms_src, gyms_dst)\n\n        # change number of training steps\n        setting_path = \"vendor.fetchai.skills.gym.handlers.gym.args.nb_steps\"\n        self.set_config(setting_path, 20, \"int\")\n\n        gym_aea_process = self.run_agent()\n\n        check_strings = (\n            \"Training starting ...\",\n            \"Training finished. You can exit now via CTRL+C.\",\n        )\n        missing_strings = self.missing_from_output(gym_aea_process, check_strings)\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in agent output.\".format(missing_strings)\n\n        assert (\n            self.is_successfully_terminated()\n        ), \"Gym agent wasn't successfully terminated.\"\n"
  },
  {
    "path": "tests/test_packages/test_skills_integration/test_ml_skills.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This test module contains the integration test for the weather skills.\"\"\"\nimport importlib\nfrom random import uniform\n\nimport pytest\nfrom aea_ledger_fetchai import FetchAICrypto\n\nfrom aea.test_tools.test_cases import AEATestCaseManyFlaky\n\nfrom packages.fetchai.connections.p2p_libp2p.connection import LIBP2P_SUCCESS_MESSAGE\n\nfrom tests.conftest import (\n    FETCHAI_PRIVATE_KEY_FILE,\n    FETCHAI_PRIVATE_KEY_FILE_CONNECTION,\n    MAX_FLAKY_RERUNS_INTEGRATION,\n    NON_FUNDED_FETCHAI_PRIVATE_KEY_1,\n    NON_GENESIS_CONFIG,\n    wait_for_localhost_ports_to_close,\n)\n\n\ndef _is_not_tensorflow_installed():\n    tf_spec = importlib.util.find_spec(\"tensorflow\")\n    return tf_spec is None\n\n\n@pytest.mark.integration\nclass TestMLSkills(AEATestCaseManyFlaky):\n    \"\"\"Test that ml skills work.\"\"\"\n\n    capture_log = True\n    cli_log_options = [\"-v\", \"DEBUG\"]\n\n    @pytest.mark.flaky(\n        reruns=MAX_FLAKY_RERUNS_INTEGRATION\n    )  # cause possible network issues\n    @pytest.mark.skipif(\n        _is_not_tensorflow_installed(),\n        reason=\"This test requires Tensorflow.\",\n    )\n    def test_ml_skills(self, pytestconfig):\n        \"\"\"Run the ml skills sequence.\"\"\"\n        data_provider_aea_name = \"ml_data_provider\"\n        model_trainer_aea_name = \"ml_model_trainer\"\n        self.create_agents(data_provider_aea_name, model_trainer_aea_name)\n\n        default_routing = {\n            \"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n            \"fetchai/oef_search:1.1.7\": \"fetchai/soef:0.27.6\",\n        }\n\n        # generate random location\n        location = {\n            \"latitude\": round(uniform(-90, 90), 2),  # nosec\n            \"longitude\": round(uniform(-180, 180), 2),  # nosec\n        }\n\n        # prepare data provider agent\n        self.set_agent_context(data_provider_aea_name)\n        self.add_item(\"connection\", \"fetchai/p2p_libp2p:0.27.5\")\n        self.add_item(\"connection\", \"fetchai/soef:0.27.6\")\n        self.set_config(\"agent.default_connection\", \"fetchai/p2p_libp2p:0.27.5\")\n        self.add_item(\"connection\", \"fetchai/ledger:0.21.5\")\n        self.add_item(\"skill\", \"fetchai/ml_data_provider:0.27.6\")\n        setting_path = (\n            \"vendor.fetchai.skills.ml_data_provider.models.strategy.args.is_ledger_tx\"\n        )\n        self.set_config(setting_path, False, \"bool\")\n        setting_path = \"agent.default_routing\"\n        self.nested_set_config(setting_path, default_routing)\n        self.run_install()\n\n        # add keys\n        self.generate_private_key(FetchAICrypto.identifier)\n        self.generate_private_key(\n            FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE_CONNECTION\n        )\n        self.add_private_key(FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE)\n        self.add_private_key(\n            FetchAICrypto.identifier,\n            FETCHAI_PRIVATE_KEY_FILE_CONNECTION,\n            connection=True,\n        )\n        self.replace_private_key_in_file(\n            NON_FUNDED_FETCHAI_PRIVATE_KEY_1, FETCHAI_PRIVATE_KEY_FILE_CONNECTION\n        )\n\n        setting_path = \"vendor.fetchai.connections.p2p_libp2p.config.ledger_id\"\n        self.set_config(setting_path, FetchAICrypto.identifier)\n\n        # replace location\n        setting_path = (\n            \"vendor.fetchai.skills.ml_data_provider.models.strategy.args.location\"\n        )\n        self.nested_set_config(setting_path, location)\n\n        # prepare model trainer agent\n        self.set_agent_context(model_trainer_aea_name)\n        self.add_item(\"connection\", \"fetchai/p2p_libp2p:0.27.5\")\n        self.add_item(\"connection\", \"fetchai/soef:0.27.6\")\n        self.set_config(\"agent.default_connection\", \"fetchai/p2p_libp2p:0.27.5\")\n        self.add_item(\"connection\", \"fetchai/ledger:0.21.5\")\n        self.add_item(\"skill\", \"fetchai/ml_train:0.29.6\")\n        setting_path = (\n            \"vendor.fetchai.skills.ml_train.models.strategy.args.is_ledger_tx\"\n        )\n        self.set_config(setting_path, False, \"bool\")\n        setting_path = \"agent.default_routing\"\n        self.nested_set_config(setting_path, default_routing)\n        self.run_install()\n\n        # add keys\n        self.generate_private_key(FetchAICrypto.identifier)\n        self.generate_private_key(\n            FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE_CONNECTION\n        )\n        self.add_private_key(FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE)\n        self.add_private_key(\n            FetchAICrypto.identifier,\n            FETCHAI_PRIVATE_KEY_FILE_CONNECTION,\n            connection=True,\n        )\n\n        # set p2p configs\n        setting_path = \"vendor.fetchai.connections.p2p_libp2p.config\"\n        self.nested_set_config(setting_path, NON_GENESIS_CONFIG)\n\n        # replace location\n        setting_path = \"vendor.fetchai.skills.ml_train.models.strategy.args.location\"\n        self.nested_set_config(setting_path, location)\n\n        self.set_agent_context(data_provider_aea_name)\n        self.run_cli_command(\"build\", cwd=self._get_cwd())\n        self.run_cli_command(\"issue-certificates\", cwd=self._get_cwd())\n        data_provider_aea_process = self.run_agent()\n\n        check_strings = (\n            \"Starting libp2p node...\",\n            \"Connecting to libp2p node...\",\n            \"Successfully connected to libp2p node!\",\n            LIBP2P_SUCCESS_MESSAGE,\n        )\n        missing_strings = self.missing_from_output(\n            data_provider_aea_process, check_strings, timeout=30, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in data_provider_aea output.\".format(\n            missing_strings\n        )\n\n        self.set_agent_context(model_trainer_aea_name)\n        self.run_cli_command(\"build\", cwd=self._get_cwd())\n        self.run_cli_command(\"issue-certificates\", cwd=self._get_cwd())\n        model_trainer_aea_process = self.run_agent()\n\n        check_strings = (\n            \"Starting libp2p node...\",\n            \"Connecting to libp2p node...\",\n            \"Successfully connected to libp2p node!\",\n            LIBP2P_SUCCESS_MESSAGE,\n        )\n        missing_strings = self.missing_from_output(\n            model_trainer_aea_process, check_strings, timeout=30, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in model_trainer_aea output.\".format(\n            missing_strings\n        )\n\n        check_strings = (\n            \"registering agent on SOEF.\",\n            \"registering agent's service on the SOEF.\",\n            \"registering agent's personality genus on the SOEF.\",\n            \"registering agent's personality classification on the SOEF.\",\n            \"got a Call for Terms from\",\n            \"a Terms message:\",\n            \"got an Accept from\",\n            \"a Data message:\",\n        )\n        missing_strings = self.missing_from_output(\n            data_provider_aea_process, check_strings, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in data_provider_aea output.\".format(\n            missing_strings\n        )\n\n        check_strings = (\n            \"found agents=\",\n            \"sending CFT to agent=\",\n            \"received terms message from\",\n            \"sending dummy transaction digest ...\",\n            \"received data message from\",\n            \"Loss:\",\n        )\n        missing_strings = self.missing_from_output(\n            model_trainer_aea_process, check_strings, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in model_trainer_aea output.\".format(\n            missing_strings\n        )\n\n        self.terminate_agents(data_provider_aea_process, model_trainer_aea_process)\n        assert (\n            self.is_successfully_terminated()\n        ), \"Agents weren't successfully terminated.\"\n        wait_for_localhost_ports_to_close([9000, 9001])\n\n\n@pytest.mark.integration\nclass TestMLSkillsFetchaiLedger(AEATestCaseManyFlaky):\n    \"\"\"Test that ml skills work.\"\"\"\n\n    @pytest.mark.flaky(\n        reruns=MAX_FLAKY_RERUNS_INTEGRATION\n    )  # cause possible network issues\n    @pytest.mark.skipif(\n        _is_not_tensorflow_installed(),\n        reason=\"This test requires Tensorflow.\",\n    )\n    def test_ml_skills(self, pytestconfig):\n        \"\"\"Run the ml skills sequence.\"\"\"\n        data_provider_aea_name = \"ml_data_provider\"\n        model_trainer_aea_name = \"ml_model_trainer\"\n        self.create_agents(data_provider_aea_name, model_trainer_aea_name)\n\n        default_routing = {\n            \"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n            \"fetchai/oef_search:1.1.7\": \"fetchai/soef:0.27.6\",\n        }\n\n        # generate random location\n        location = {\n            \"latitude\": round(uniform(-90, 90), 2),  # nosec\n            \"longitude\": round(uniform(-180, 180), 2),  # nosec\n        }\n\n        # prepare data provider agent\n        self.set_agent_context(data_provider_aea_name)\n        self.add_item(\"connection\", \"fetchai/p2p_libp2p:0.27.5\")\n        self.add_item(\"connection\", \"fetchai/soef:0.27.6\")\n        self.set_config(\"agent.default_connection\", \"fetchai/p2p_libp2p:0.27.5\")\n        self.add_item(\"connection\", \"fetchai/ledger:0.21.5\")\n        self.add_item(\"skill\", \"fetchai/ml_data_provider:0.27.6\")\n        setting_path = \"agent.default_routing\"\n        self.nested_set_config(setting_path, default_routing)\n        self.run_install()\n\n        diff = self.difference_to_fetched_agent(\n            \"fetchai/ml_data_provider:0.32.5\", data_provider_aea_name\n        )\n        assert (\n            diff == []\n        ), \"Difference between created and fetched project for files={}\".format(diff)\n\n        # add keys\n        self.generate_private_key(FetchAICrypto.identifier)\n        self.generate_private_key(\n            FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE_CONNECTION\n        )\n        self.add_private_key(FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE)\n        self.add_private_key(\n            FetchAICrypto.identifier,\n            FETCHAI_PRIVATE_KEY_FILE_CONNECTION,\n            connection=True,\n        )\n        self.replace_private_key_in_file(\n            NON_FUNDED_FETCHAI_PRIVATE_KEY_1, FETCHAI_PRIVATE_KEY_FILE_CONNECTION\n        )\n\n        setting_path = \"vendor.fetchai.connections.p2p_libp2p.config.ledger_id\"\n        self.set_config(setting_path, FetchAICrypto.identifier)\n\n        # replace location\n        setting_path = (\n            \"vendor.fetchai.skills.ml_data_provider.models.strategy.args.location\"\n        )\n        self.nested_set_config(setting_path, location)\n\n        # prepare model trainer agent\n        self.set_agent_context(model_trainer_aea_name)\n        self.add_item(\"connection\", \"fetchai/p2p_libp2p:0.27.5\")\n        self.add_item(\"connection\", \"fetchai/soef:0.27.6\")\n        self.set_config(\"agent.default_connection\", \"fetchai/p2p_libp2p:0.27.5\")\n        self.add_item(\"connection\", \"fetchai/ledger:0.21.5\")\n        self.add_item(\"skill\", \"fetchai/ml_train:0.29.6\")\n        setting_path = \"agent.default_routing\"\n        self.nested_set_config(setting_path, default_routing)\n        self.run_install()\n\n        diff = self.difference_to_fetched_agent(\n            \"fetchai/ml_model_trainer:0.33.5\", model_trainer_aea_name\n        )\n        assert (\n            diff == []\n        ), \"Difference between created and fetched project for files={}\".format(diff)\n\n        # add keys\n        self.generate_private_key(FetchAICrypto.identifier)\n        self.generate_private_key(\n            FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE_CONNECTION\n        )\n        self.add_private_key(FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE)\n        self.add_private_key(\n            FetchAICrypto.identifier,\n            FETCHAI_PRIVATE_KEY_FILE_CONNECTION,\n            connection=True,\n        )\n\n        # fund key\n        self.generate_wealth(FetchAICrypto.identifier)\n\n        # set p2p configs\n        setting_path = \"vendor.fetchai.connections.p2p_libp2p.config\"\n        self.nested_set_config(setting_path, NON_GENESIS_CONFIG)\n\n        # replace location\n        setting_path = \"vendor.fetchai.skills.ml_train.models.strategy.args.location\"\n        self.nested_set_config(setting_path, location)\n\n        self.set_agent_context(data_provider_aea_name)\n        self.run_cli_command(\"build\", cwd=self._get_cwd())\n        self.run_cli_command(\"issue-certificates\", cwd=self._get_cwd())\n        data_provider_aea_process = self.run_agent()\n\n        check_strings = (\n            \"Starting libp2p node...\",\n            \"Connecting to libp2p node...\",\n            \"Successfully connected to libp2p node!\",\n            LIBP2P_SUCCESS_MESSAGE,\n        )\n        missing_strings = self.missing_from_output(\n            data_provider_aea_process, check_strings, timeout=30, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in data_provider_aea output.\".format(\n            missing_strings\n        )\n\n        self.set_agent_context(model_trainer_aea_name)\n        self.run_cli_command(\"build\", cwd=self._get_cwd())\n        self.run_cli_command(\"issue-certificates\", cwd=self._get_cwd())\n        model_trainer_aea_process = self.run_agent()\n\n        check_strings = (\n            \"Starting libp2p node...\",\n            \"Connecting to libp2p node...\",\n            \"Successfully connected to libp2p node!\",\n            LIBP2P_SUCCESS_MESSAGE,\n        )\n        missing_strings = self.missing_from_output(\n            model_trainer_aea_process, check_strings, timeout=30, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in model_trainer_aea output.\".format(\n            missing_strings\n        )\n\n        check_strings = (\n            \"registering agent on SOEF.\",\n            \"registering agent's service on the SOEF.\",\n            \"registering agent's personality genus on the SOEF.\",\n            \"registering agent's personality classification on the SOEF.\",\n            \"got a Call for Terms from\",\n            \"a Terms message:\",\n            \"got an Accept from\",\n            \"a Data message:\",\n        )\n        missing_strings = self.missing_from_output(\n            data_provider_aea_process, check_strings, timeout=240, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in data_provider_aea output.\".format(\n            missing_strings\n        )\n\n        check_strings = (\n            \"found agents=\",\n            \"sending CFT to agent=\",\n            \"received terms message from\",\n            \"requesting transfer transaction from ledger api for message=\",\n            \"received raw transaction=\",\n            \"proposing the transaction to the decision maker. Waiting for confirmation ...\",\n            \"transaction signing was successful.\",\n            \"sending transaction to ledger.\",\n            \"transaction was successfully submitted. Transaction digest=\",\n            \"informing counterparty=\",\n            \"received data message from\",\n            \"Loss:\",\n        )\n        missing_strings = self.missing_from_output(\n            model_trainer_aea_process, check_strings, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in model_trainer_aea output.\".format(\n            missing_strings\n        )\n\n        self.terminate_agents(data_provider_aea_process, model_trainer_aea_process)\n        assert (\n            self.is_successfully_terminated()\n        ), \"Agents weren't successfully terminated.\"\n        wait_for_localhost_ports_to_close([9000, 9001])\n"
  },
  {
    "path": "tests/test_packages/test_skills_integration/test_simple_aggregation.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This test module contains the integration test for the simple aggregation skill.\"\"\"\nimport json\n\nimport pytest\nfrom aea_ledger_fetchai import FetchAICrypto\n\nfrom aea.test_tools.test_cases import AEATestCaseManyFlaky\n\nfrom packages.fetchai.connections.p2p_libp2p.connection import LIBP2P_SUCCESS_MESSAGE\n\nfrom tests.conftest import (\n    FETCHAI_PRIVATE_KEY_FILE,\n    FETCHAI_PRIVATE_KEY_FILE_CONNECTION,\n    UseSOEF,\n)\n\n\nMAX_RERUNS = 1\n\nCOIN_URLS = [\n    \"https://api.coinbase.com/v2/prices/BTC-USD/buy\",\n    \"https://api.coinpaprika.com/v1/tickers/btc-bitcoin\",\n    \"https://api.cryptowat.ch/markets/kraken/btcusd/price\",\n    \"https://api.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies=usd\",\n]\nJSON_PATHS = [\n    \"data.amount\",\n    \"quotes.USD.price\",\n    \"result.price\",\n    \"bitcoin.usd\",\n]\nSERVICE_ID = \"generic_aggregation_service\"\n\n\n@pytest.mark.integration\nclass TestSimpleAggregationSkill(AEATestCaseManyFlaky, UseSOEF):\n    \"\"\"Test that simple aggregation skill works.\"\"\"\n\n    @pytest.mark.flaky(reruns=MAX_RERUNS)  # cause possible network issues\n    def test_simple_aggregation(self):\n        \"\"\"Run the simple aggregation skill sequence.\"\"\"\n\n        agg0_name = \"agg0_aea\"\n        agg1_name = \"agg1_aea\"\n        agg2_name = \"agg2_aea\"\n        agg3_name = \"agg3_aea\"\n\n        agents = (agg0_name, agg1_name, agg2_name, agg3_name)\n\n        self.create_agents(*agents)\n\n        aea_processes = []\n        for (i, agent) in enumerate(agents):\n            # add packages for agent\n            self.set_agent_context(agent)\n            self.add_item(\"connection\", \"fetchai/p2p_libp2p:0.27.5\")\n            self.add_item(\"connection\", \"fetchai/http_client:0.24.6\")\n            self.add_item(\"connection\", \"fetchai/http_server:0.23.6\")\n            self.add_item(\"connection\", \"fetchai/soef:0.27.6\")\n            self.add_item(\"connection\", \"fetchai/prometheus:0.9.6\")\n            self.set_config(\"agent.default_connection\", \"fetchai/p2p_libp2p:0.27.5\")\n            self.nested_set_config(\n                \"agent.required_ledgers\",\n                [FetchAICrypto.identifier],\n            )\n            self.add_item(\"skill\", \"fetchai/advanced_data_request:0.7.6\")\n            self.add_item(\"skill\", \"fetchai/simple_aggregation:0.3.6\")\n\n            self.set_config(\n                \"vendor.fetchai.skills.advanced_data_request.models.advanced_data_request_model.args.decimals\",\n                0,\n                type_=\"int\",\n            )\n            self.set_config(\n                \"vendor.fetchai.skills.advanced_data_request.models.advanced_data_request_model.args.use_http_server\",\n                \"false\",\n                type_=\"bool\",\n            )\n            setting_path = (\n                \"vendor.fetchai.connections.http_server.config.target_skill_id\"\n            )\n            self.set_config(setting_path, \"fetchai/advanced_data_request:0.7.6\")\n            self.set_config(\n                \"vendor.fetchai.skills.simple_aggregation.models.strategy.args.quantity_name\",\n                \"price\",\n            )\n            self.set_config(\n                \"vendor.fetchai.skills.simple_aggregation.models.strategy.args.aggregation_function\",\n                \"mean\",\n            )\n            self.set_config(\n                \"vendor.fetchai.skills.simple_aggregation.models.strategy.args.search_query.search_value\",\n                SERVICE_ID,\n            )\n            self.set_config(\n                \"vendor.fetchai.skills.simple_aggregation.models.strategy.args.service_id\",\n                SERVICE_ID,\n            )\n\n            self.generate_private_key(FetchAICrypto.identifier)\n            self.add_private_key(FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE)\n            self.generate_private_key(\n                FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE_CONNECTION\n            )\n            self.add_private_key(\n                FetchAICrypto.identifier,\n                FETCHAI_PRIVATE_KEY_FILE_CONNECTION,\n                connection=True,\n            )\n            self.run_install()\n            self.run_cli_command(\"issue-certificates\", cwd=self._get_cwd())\n            self.run_cli_command(\"build\", cwd=self._get_cwd())\n            setting_path = \"vendor.fetchai.connections.p2p_libp2p.cert_requests\"\n            settings = json.dumps(\n                [\n                    {\n                        \"identifier\": \"acn\",\n                        \"ledger_id\": FetchAICrypto.identifier,\n                        \"not_after\": \"2023-01-01\",\n                        \"not_before\": \"2022-01-01\",\n                        \"public_key\": FetchAICrypto.identifier,\n                        \"message_format\": \"{public_key}\",\n                        \"save_path\": \".certs/conn_cert.txt\",\n                    }\n                ]\n            )\n            self.set_config(setting_path, settings, type_=\"list\")\n\n            if i == 0:\n                diff = self.difference_to_fetched_agent(\n                    \"fetchai/simple_aggregator:0.5.5\", agent\n                )\n                assert (\n                    diff == []\n                ), \"Difference between created and fetched project for files={}\".format(\n                    diff\n                )\n\n                result = self.run_cli_command(\n                    \"get-multiaddress\", \"fetchai\", \"--connection\", cwd=self._get_cwd()\n                )\n                multiaddr = result.stdout\n            else:\n                setting_path = \"vendor.fetchai.connections.p2p_libp2p.config\"\n                settings = json.dumps(\n                    {\n                        \"delegate_uri\": f\"127.0.0.1:{11000 + i}\",\n                        \"entry_peers\": [f\"/dns4/127.0.0.1/tcp/9000/p2p/{multiaddr}\"],\n                        \"local_uri\": f\"127.0.0.1:{9000 + i}\",\n                        \"log_file\": \"libp2p_node.log\",\n                        \"public_uri\": f\"127.0.0.1:{9000 + i}\",\n                    }\n                )\n                self.set_config(setting_path, settings, type_=\"dict\")\n                setting_path = \"vendor.fetchai.connections.prometheus.config.port\"\n                self.set_config(setting_path, 20000 + i)\n                setting_path = \"vendor.fetchai.connections.http_server.config.port\"\n                self.set_config(setting_path, 8000 + i)\n\n            # set SOEF configuration\n            setting_path = \"vendor.fetchai.connections.soef.config.is_https\"\n            self.set_config(setting_path, False)\n            setting_path = \"vendor.fetchai.connections.soef.config.soef_addr\"\n            self.set_config(setting_path, \"127.0.0.1\")\n            setting_path = \"vendor.fetchai.connections.soef.config.soef_port\"\n            self.set_config(setting_path, 12002)\n\n            # set up data request skill to fetch coin price\n            self.set_config(\n                \"vendor.fetchai.skills.advanced_data_request.models.advanced_data_request_model.args.url\",\n                COIN_URLS[i],\n                type_=\"str\",\n            )\n            self.set_config(\n                \"vendor.fetchai.skills.advanced_data_request.models.advanced_data_request_model.args.outputs\",\n                f'[{{\"name\": \"price\", \"json_path\": \"{JSON_PATHS[i]}\"}}]',\n                type_=\"list\",\n            )\n\n            # run agent\n            aea_processes.append(self.run_agent())\n\n        for agent in agents:\n            self.set_agent_context(agent)\n            check_strings = (\n                \"Starting libp2p node...\",\n                \"Connecting to libp2p node...\",\n                \"Successfully connected to libp2p node!\",\n                LIBP2P_SUCCESS_MESSAGE,\n            )\n            missing_strings = self.missing_from_output(\n                aea_processes[0], check_strings, timeout=30, is_terminating=False\n            )\n            assert (\n                missing_strings == []\n            ), \"Strings {} didn't appear in aea output.\".format(missing_strings)\n\n        for agent in agents:\n            self.set_agent_context(agent)\n            check_strings = (\n                \"setting up HttpHandler\",\n                \"setting up PrometheusHandler\",\n                \"setting up AdvancedDataRequestBehaviour\",\n                \"Adding Prometheus metric: num_retrievals\",\n                \"Adding Prometheus metric: num_requests\",\n                \"registering agent on SOEF.\",\n                \"registering agent's service on the SOEF.\",\n                \"registering agent's personality genus on the SOEF.\",\n                \"registering agent's personality classification on the SOEF.\",\n                \"Start processing messages...\",\n                \"Fetching data from\",\n                \"Observation: {'price': {'value': \",\n                \"found agents=\",\n                \"sending observation to peer=\",\n                \"received observation from sender=\",\n                \"Observations:\",\n                \"Aggregation (mean):\",\n            )\n            missing_strings = self.missing_from_output(\n                aea_processes[0], check_strings, timeout=30, is_terminating=False\n            )\n            assert (\n                missing_strings == []\n            ), \"Strings {} didn't appear in aea output.\".format(missing_strings)\n\n        self.terminate_agents(*aea_processes, timeout=30)\n        assert (\n            self.is_successfully_terminated()\n        ), \"Agents weren't successfully terminated.\"\n"
  },
  {
    "path": "tests/test_packages/test_skills_integration/test_simple_oracle.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This test module contains the integration test for the generic buyer and seller skills.\"\"\"\nimport os\n\nimport pytest\nfrom aea_ledger_ethereum import EthereumCrypto\nfrom aea_ledger_fetchai import FetchAICrypto\n\nfrom aea.test_tools.test_cases import AEATestCaseManyFlaky\n\nfrom tests.conftest import (\n    CUR_PATH,\n    DEFAULT_FETCH_LEDGER_ADDR,\n    DEFAULT_FETCH_LEDGER_REST_PORT,\n    ETHEREUM_PRIVATE_KEY_FILE,\n    FETCHAI_PRIVATE_KEY_FILE,\n    FETCHAI_PRIVATE_KEY_FILE_CONNECTION,\n    FUNDED_ETH_PRIVATE_KEY_2,\n    FUNDED_ETH_PRIVATE_KEY_3,\n    FUNDED_FETCHAI_PRIVATE_KEY_1,\n    FUNDED_FETCHAI_PRIVATE_KEY_2,\n    MAX_FLAKY_RERUNS_ETH,\n    UseGanache,\n    UseLocalFetchNode,\n)\n\n\nORACLE_CONTRACT_ADDRESS_FILE = os.path.join(CUR_PATH, \"oracle_contract_address.txt\")\n\n\n@pytest.mark.integration\nclass TestOracleSkillsFetchAI(AEATestCaseManyFlaky, UseLocalFetchNode):\n    \"\"\"Test that oracle skills work.\"\"\"\n\n    @pytest.mark.ledger\n    # @pytest.mark.flaky(reruns=MAX_FLAKY_RERUNS_ETH)  # cause possible network issues\n    def test_oracle(\n        self,\n        fund_fetchai_accounts,\n    ):\n        \"\"\"Run the oracle skills sequence.\"\"\"\n        oracle_agent_name = \"oracle_aea\"\n        client_agent_name = \"client_aea\"\n        processes = []\n        try:\n\n            ledger_id = \"fetchai\"\n            private_key_file = FETCHAI_PRIVATE_KEY_FILE\n            funded_private_key_1 = FUNDED_FETCHAI_PRIVATE_KEY_1\n            funded_private_key_2 = FUNDED_FETCHAI_PRIVATE_KEY_2\n            update_function = \"update_oracle_value\"\n            query_function = \"query_oracle_value\"\n\n            self.create_agents(oracle_agent_name, client_agent_name)\n\n            default_routing = {\n                \"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n                \"fetchai/contract_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n                \"fetchai/http:1.1.7\": \"fetchai/http_client:0.24.6\",\n                \"fetchai/prometheus:1.1.7\": \"fetchai/prometheus:0.9.6\",\n            }\n\n            # add packages for oracle agent\n            self.set_agent_context(oracle_agent_name)\n            self.add_item(\"connection\", \"fetchai/ledger:0.21.5\")\n            self.add_item(\"connection\", \"fetchai/http_client:0.24.6\")\n            self.add_item(\"connection\", \"fetchai/prometheus:0.9.6\")\n            self.set_config(\"agent.default_connection\", \"fetchai/ledger:0.21.5\")\n            self.set_config(\"agent.default_ledger\", ledger_id)\n            self.nested_set_config(\n                \"agent.required_ledgers\",\n                [FetchAICrypto.identifier],\n            )\n            setting_path = \"agent.default_routing\"\n            self.nested_set_config(setting_path, default_routing)\n            self.add_item(\"skill\", \"fetchai/advanced_data_request:0.7.6\")\n            self.add_item(\"contract\", \"fetchai/oracle:0.12.3\")\n            self.add_item(\"skill\", \"fetchai/simple_oracle:0.16.5\")\n\n            # set up data request skill to fetch coin price\n            self.set_config(\n                \"vendor.fetchai.skills.advanced_data_request.models.advanced_data_request_model.args.url\",\n                \"https://api.coingecko.com/api/v3/simple/price?ids=fetch-ai&vs_currencies=usd\",\n                type_=\"str\",\n            )\n            self.set_config(\n                \"vendor.fetchai.skills.advanced_data_request.models.advanced_data_request_model.args.outputs\",\n                '[{\"name\": \"price\", \"json_path\": \"fetch-ai.usd\"}]',\n                type_=\"list\",\n            )\n\n            setting_path = (\n                \"vendor.fetchai.skills.simple_oracle.models.strategy.args.ledger_id\"\n            )\n            self.set_config(setting_path, ledger_id)\n            setting_path = \"vendor.fetchai.skills.simple_oracle.models.strategy.args.update_function\"\n            self.set_config(setting_path, update_function)\n            setting_path = \"vendor.fetchai.skills.simple_oracle.models.strategy.args.oracle_value_name\"\n            self.set_config(setting_path, \"price\")\n\n            self.generate_private_key(ledger_id)\n            self.add_private_key(ledger_id, private_key_file)\n            self.replace_private_key_in_file(funded_private_key_1, private_key_file)\n            self.generate_private_key(\n                FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE_CONNECTION\n            )\n            self.add_private_key(\n                FetchAICrypto.identifier,\n                FETCHAI_PRIVATE_KEY_FILE_CONNECTION,\n                connection=True,\n            )\n            self.run_install()\n\n            diff = self.difference_to_fetched_agent(\n                \"fetchai/coin_price_oracle:0.17.6\", oracle_agent_name\n            )\n            assert (\n                diff == []\n            ), \"Difference between created and fetched project for files={}\".format(\n                diff\n            )\n\n            # redirect fetchai ledger address to local test node\n            setting_path = (\n                \"vendor.fetchai.connections.ledger.config.ledger_apis.fetchai.address\"\n            )\n            self.set_config(\n                setting_path,\n                f\"{DEFAULT_FETCH_LEDGER_ADDR}:{DEFAULT_FETCH_LEDGER_REST_PORT}\",\n            )\n\n            # use alternate port for prometheus connection\n            setting_path = \"vendor.fetchai.connections.prometheus.config.port\"\n            self.set_config(\n                setting_path, 19091, type_=\"int\"\n            )  # 9091 used by fetchd docker image\n\n            setting_path = \"vendor.fetchai.skills.simple_oracle.models.strategy.args.contract_address_file\"\n            self.set_config(setting_path, ORACLE_CONTRACT_ADDRESS_FILE)\n\n            # add packages for oracle client agent\n            self.set_agent_context(client_agent_name)\n            self.add_item(\"connection\", \"fetchai/ledger:0.21.5\")\n            self.add_item(\"connection\", \"fetchai/http_client:0.24.6\")\n            self.set_config(\"agent.default_connection\", \"fetchai/ledger:0.21.5\")\n            self.set_config(\"agent.default_ledger\", ledger_id)\n            self.nested_set_config(\n                \"agent.required_ledgers\",\n                [FetchAICrypto.identifier],\n            )\n\n            default_routing = {\n                \"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n                \"fetchai/contract_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n                \"fetchai/http:1.1.7\": \"fetchai/http_client:0.24.6\",\n            }\n            setting_path = \"agent.default_routing\"\n            self.nested_set_config(setting_path, default_routing)\n            self.add_item(\"contract\", \"fetchai/oracle_client:0.11.3\")\n            self.add_item(\"contract\", \"fetchai/fet_erc20:0.9.2\")\n            self.add_item(\"skill\", \"fetchai/simple_oracle_client:0.13.5\")\n\n            self.generate_private_key(ledger_id)\n            self.add_private_key(ledger_id, private_key_file)\n            self.replace_private_key_in_file(funded_private_key_2, private_key_file)\n            setting_path = \"vendor.fetchai.skills.simple_oracle_client.models.strategy.args.ledger_id\"\n            self.set_config(setting_path, ledger_id)\n            setting_path = \"vendor.fetchai.skills.simple_oracle_client.models.strategy.args.query_function\"\n            self.set_config(setting_path, query_function)\n\n            diff = self.difference_to_fetched_agent(\n                \"fetchai/coin_price_oracle_client:0.12.6\", client_agent_name\n            )\n            assert (\n                diff == []\n            ), \"Difference between created and fetched project for files={}\".format(\n                diff\n            )\n\n            # redirect fetchai ledger address to local test node\n            setting_path = (\n                \"vendor.fetchai.connections.ledger.config.ledger_apis.fetchai.address\"\n            )\n            self.set_config(\n                setting_path,\n                f\"{DEFAULT_FETCH_LEDGER_ADDR}:{DEFAULT_FETCH_LEDGER_REST_PORT}\",\n            )\n\n            # run oracle agent\n            self.set_agent_context(oracle_agent_name)\n            oracle_aea_process = self.run_agent()\n            processes.append(oracle_aea_process)\n\n            check_strings = (\n                \"setting up HttpHandler\",\n                \"setting up AdvancedDataRequestBehaviour\",\n                \"Setting up Fetch oracle contract...\",\n                \"Fetching data from https://api.coingecko.com/api/v3/simple/price?ids=fetch-ai&vs_currencies=usd\",\n                \"received raw transaction=\",\n                \"Observation: {'price': {'value': \",\n                \"transaction was successfully submitted. Transaction digest=\",\n                \"requesting transaction receipt.\",\n                \"transaction was successfully settled. Transaction receipt=\",\n                \"Oracle value successfully updated!\",\n            )\n            missing_strings = self.missing_from_output(\n                oracle_aea_process,\n                check_strings,\n                timeout=60,\n                is_terminating=False,\n            )\n            assert (\n                missing_strings == []\n            ), \"Strings {} didn't appear in aea output: \\n{}\".format(\n                missing_strings, self.stdout[oracle_aea_process.pid]\n            )\n\n            # Get oracle contract address from file\n            with open(ORACLE_CONTRACT_ADDRESS_FILE) as file:\n                oracle_address = file.read()\n\n            # run oracle client agent\n            self.set_agent_context(client_agent_name)\n\n            # set oracle contract address in oracle client\n            setting_path = \"vendor.fetchai.skills.simple_oracle_client.models.strategy.args.oracle_contract_address\"\n            self.set_config(setting_path, oracle_address)\n\n            client_aea_process = self.run_agent()\n            processes.append(client_aea_process)\n\n            check_strings = (\n                \"requesting contract deployment transaction...\",\n                \"received raw transaction=\",\n                \"transaction was successfully submitted. Transaction digest=\",\n                \"requesting transaction receipt.\",\n                \"transaction was successfully settled. Transaction receipt=\",\n                \"Oracle value successfully requested!\",\n            )\n            missing_strings = self.missing_from_output(\n                client_aea_process,\n                check_strings,\n                timeout=60,\n                is_terminating=False,\n            )\n            assert (\n                missing_strings == []\n            ), \"Strings {} didn't appear in aea output: \\n{}\".format(\n                missing_strings, self.stdout[client_aea_process.pid]\n            )\n        finally:\n            if processes:\n                self.terminate_agents(*processes)\n            assert (\n                self.is_successfully_terminated()\n            ), \"Agents weren't successfully terminated.\"\n\n\n@pytest.mark.integration\nclass TestOracleSkillsETH(AEATestCaseManyFlaky, UseGanache):\n    \"\"\"Test that oracle skills work.\"\"\"\n\n    @pytest.mark.ledger\n    @pytest.mark.flaky(reruns=MAX_FLAKY_RERUNS_ETH)  # cause possible network issues\n    def test_oracle(\n        self,\n        erc20_contract,\n        oracle_contract,\n    ):\n        \"\"\"Run the oracle skills sequence.\"\"\"\n        oracle_agent_name = \"oracle_aea\"\n        client_agent_name = \"client_aea\"\n        processes = []\n        try:\n\n            _, erc20_address = erc20_contract\n            _, oracle_address = oracle_contract\n\n            ledger_id = \"ethereum\"\n            private_key_file = ETHEREUM_PRIVATE_KEY_FILE\n            funded_private_key_1 = FUNDED_ETH_PRIVATE_KEY_3\n            funded_private_key_2 = FUNDED_ETH_PRIVATE_KEY_2\n            update_function = \"updateOracleValue\"\n            query_function = \"queryOracleValue\"\n\n            self.create_agents(oracle_agent_name, client_agent_name)\n\n            default_routing = {\n                \"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n                \"fetchai/contract_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n                \"fetchai/http:1.1.7\": \"fetchai/http_client:0.24.6\",\n                \"fetchai/prometheus:1.1.7\": \"fetchai/prometheus:0.9.6\",\n            }\n\n            # add packages for oracle agent\n            self.set_agent_context(oracle_agent_name)\n            self.add_item(\"connection\", \"fetchai/ledger:0.21.5\")\n            self.add_item(\"connection\", \"fetchai/http_client:0.24.6\")\n            self.add_item(\"connection\", \"fetchai/prometheus:0.9.6\")\n            self.set_config(\"agent.default_connection\", \"fetchai/ledger:0.21.5\")\n            self.set_config(\"agent.default_ledger\", ledger_id)\n            self.nested_set_config(\n                \"agent.required_ledgers\",\n                [FetchAICrypto.identifier, EthereumCrypto.identifier],\n            )\n            setting_path = \"agent.default_routing\"\n            self.nested_set_config(setting_path, default_routing)\n            self.add_item(\"skill\", \"fetchai/advanced_data_request:0.7.6\")\n            self.add_item(\"contract\", \"fetchai/oracle:0.12.3\")\n            self.add_item(\"skill\", \"fetchai/simple_oracle:0.16.5\")\n\n            # set up data request skill to fetch coin price\n            self.set_config(\n                \"vendor.fetchai.skills.advanced_data_request.models.advanced_data_request_model.args.url\",\n                \"https://api.coingecko.com/api/v3/simple/price?ids=fetch-ai&vs_currencies=usd\",\n                type_=\"str\",\n            )\n            self.set_config(\n                \"vendor.fetchai.skills.advanced_data_request.models.advanced_data_request_model.args.outputs\",\n                '[{\"name\": \"price\", \"json_path\": \"fetch-ai.usd\"}]',\n                type_=\"list\",\n            )\n\n            setting_path = (\n                \"vendor.fetchai.skills.simple_oracle.models.strategy.args.ledger_id\"\n            )\n            self.set_config(setting_path, ledger_id)\n            setting_path = \"vendor.fetchai.skills.simple_oracle.models.strategy.args.update_function\"\n            self.set_config(setting_path, update_function)\n            setting_path = \"vendor.fetchai.skills.simple_oracle.models.strategy.args.oracle_value_name\"\n            self.set_config(setting_path, \"price\")\n\n            self.generate_private_key(ledger_id)\n            self.add_private_key(ledger_id, private_key_file)\n            self.replace_private_key_in_file(funded_private_key_1, private_key_file)\n            self.generate_private_key(\n                FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE_CONNECTION\n            )\n            self.add_private_key(\n                FetchAICrypto.identifier,\n                FETCHAI_PRIVATE_KEY_FILE_CONNECTION,\n                connection=True,\n            )\n            self.run_install()\n\n            # set erc20 address\n            setting_path = (\n                \"vendor.fetchai.skills.simple_oracle.models.strategy.args.erc20_address\"\n            )\n            self.set_config(setting_path, erc20_address)\n            setting_path = \"vendor.fetchai.skills.simple_oracle.models.strategy.args.contract_address\"\n            self.set_config(setting_path, oracle_address)\n\n            setting_path = \"vendor.fetchai.skills.simple_oracle.models.strategy.args.contract_address_file\"\n            self.set_config(setting_path, ORACLE_CONTRACT_ADDRESS_FILE)\n\n            # add packages for oracle client agent\n            self.set_agent_context(client_agent_name)\n            self.add_item(\"connection\", \"fetchai/ledger:0.21.5\")\n            self.add_item(\"connection\", \"fetchai/http_client:0.24.6\")\n            self.set_config(\"agent.default_connection\", \"fetchai/ledger:0.21.5\")\n            self.set_config(\"agent.default_ledger\", ledger_id)\n            self.nested_set_config(\n                \"agent.required_ledgers\",\n                [FetchAICrypto.identifier, EthereumCrypto.identifier],\n            )\n\n            default_routing = {\n                \"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n                \"fetchai/contract_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n                \"fetchai/http:1.1.7\": \"fetchai/http_client:0.24.6\",\n            }\n            setting_path = \"agent.default_routing\"\n            self.nested_set_config(setting_path, default_routing)\n            self.add_item(\"contract\", \"fetchai/oracle_client:0.11.3\")\n            self.add_item(\"contract\", \"fetchai/fet_erc20:0.9.2\")\n            self.add_item(\"skill\", \"fetchai/simple_oracle_client:0.13.5\")\n\n            self.generate_private_key(ledger_id)\n            self.add_private_key(ledger_id, private_key_file)\n            self.replace_private_key_in_file(funded_private_key_2, private_key_file)\n            setting_path = \"vendor.fetchai.skills.simple_oracle_client.models.strategy.args.ledger_id\"\n            self.set_config(setting_path, ledger_id)\n            setting_path = \"vendor.fetchai.skills.simple_oracle_client.models.strategy.args.query_function\"\n            self.set_config(setting_path, query_function)\n\n            # set addresses *after* comparison with fetched agent!\n            setting_path = \"vendor.fetchai.skills.simple_oracle_client.models.strategy.args.erc20_address\"\n            self.set_config(setting_path, erc20_address)\n\n            # run oracle agent\n            self.set_agent_context(oracle_agent_name)\n            self.run_cli_command(\"build\", cwd=self._get_cwd())\n            self.run_cli_command(\"issue-certificates\", cwd=self._get_cwd())\n            oracle_aea_process = self.run_agent()\n            processes.append(oracle_aea_process)\n\n            check_strings = (\n                \"setting up HttpHandler\",\n                \"setting up AdvancedDataRequestBehaviour\",\n                \"Setting up Fetch oracle contract...\",\n                \"Fetching data from https://api.coingecko.com/api/v3/simple/price?ids=fetch-ai&vs_currencies=usd\",\n                \"received raw transaction=\",\n                \"Observation: {'price': {'value': \",\n                \"transaction was successfully submitted. Transaction digest=\",\n                \"requesting transaction receipt.\",\n                \"transaction was successfully settled. Transaction receipt=\",\n                \"Oracle value successfully updated!\",\n            )\n            missing_strings = self.missing_from_output(\n                oracle_aea_process,\n                check_strings,\n                timeout=60,\n                is_terminating=False,\n            )\n            assert (\n                missing_strings == []\n            ), \"Strings {} didn't appear in aea output: \\n{}\".format(\n                missing_strings, self.stdout[oracle_aea_process.pid]\n            )\n\n            if ledger_id == FetchAICrypto.identifier:\n                # Get oracle contract address from file\n                with open(ORACLE_CONTRACT_ADDRESS_FILE) as file:\n                    oracle_address = file.read()\n\n            # run oracle client agent\n            self.set_agent_context(client_agent_name)\n\n            # set oracle contract address in oracle client\n            setting_path = \"vendor.fetchai.skills.simple_oracle_client.models.strategy.args.oracle_contract_address\"\n            self.set_config(setting_path, oracle_address)\n\n            client_aea_process = self.run_agent()\n            processes.append(client_aea_process)\n\n            check_strings = (\n                \"requesting contract deployment transaction...\",\n                \"received raw transaction=\",\n                \"transaction was successfully submitted. Transaction digest=\",\n                \"requesting transaction receipt.\",\n                \"transaction was successfully settled. Transaction receipt=\",\n                \"Oracle value successfully requested!\",\n            )\n            missing_strings = self.missing_from_output(\n                client_aea_process,\n                check_strings,\n                timeout=60,\n                is_terminating=False,\n            )\n            assert (\n                missing_strings == []\n            ), \"Strings {} didn't appear in aea output: \\n{}\".format(\n                missing_strings, self.stdout[client_aea_process.pid]\n            )\n        finally:\n            if processes:\n                self.terminate_agents(*processes)\n            assert (\n                self.is_successfully_terminated()\n            ), \"Agents weren't successfully terminated.\"\n"
  },
  {
    "path": "tests/test_packages/test_skills_integration/test_tac.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This test module contains the integration test for the tac skills.\"\"\"\n\nimport datetime\nimport json\nimport uuid\nfrom random import uniform\n\nimport pytest\nfrom aea_ledger_ethereum import EthereumCrypto\nfrom aea_ledger_fetchai import FetchAICrypto\n\nfrom aea.test_tools.test_cases import AEATestCaseManyFlaky\n\nfrom packages.fetchai.connections.p2p_libp2p.connection import LIBP2P_SUCCESS_MESSAGE\n\nfrom tests.conftest import (\n    DEFAULT_DENOMINATION,\n    DEFAULT_FETCH_CHAIN_ID,\n    DEFAULT_FETCH_LEDGER_ADDR,\n    DEFAULT_FETCH_LEDGER_REST_PORT,\n    ETHEREUM_PRIVATE_KEY_FILE,\n    FETCHAI_PRIVATE_KEY_FILE,\n    FETCHAI_PRIVATE_KEY_FILE_CONNECTION,\n    FUNDED_ETH_PRIVATE_KEY_1,\n    FUNDED_ETH_PRIVATE_KEY_2,\n    FUNDED_ETH_PRIVATE_KEY_3,\n    MAX_FLAKY_RERUNS_ETH,\n    MAX_FLAKY_RERUNS_INTEGRATION,\n    NON_FUNDED_FETCHAI_PRIVATE_KEY_1,\n    NON_GENESIS_CONFIG,\n    NON_GENESIS_CONFIG_TWO,\n    UseGanache,\n    UseLocalFetchNode,\n    UseSOEF,\n    fund_accounts_from_local_validator,\n)\n\n\nMAX_FLAKY_RERUNS_ETH -= 1\n\n\nclass TestTacSkills(AEATestCaseManyFlaky):\n    \"\"\"Test that tac skills work.\"\"\"\n\n    capture_log = True\n\n    @pytest.mark.integration\n    @pytest.mark.flaky(\n        reruns=MAX_FLAKY_RERUNS_INTEGRATION\n    )  # cause possible network issues\n    def test_tac(self):\n        \"\"\"Run the tac skills sequence.\"\"\"\n        tac_aea_one = \"tac_participant_one\"\n        tac_aea_two = \"tac_participant_two\"\n        tac_controller_name = \"tac_controller\"\n\n        # create tac controller, agent one and agent two\n        self.create_agents(\n            tac_aea_one,\n            tac_aea_two,\n            tac_controller_name,\n        )\n\n        default_routing = {\n            \"fetchai/oef_search:1.1.7\": \"fetchai/soef:0.27.6\",\n        }\n\n        # generate random location\n        location = {\n            \"latitude\": round(uniform(-90, 90), 2),  # nosec\n            \"longitude\": round(uniform(-180, 180), 2),  # nosec\n        }\n\n        # tac name\n        tac_id = uuid.uuid4().hex\n        tac_service = f\"tac_service_{tac_id[:5]}\"\n\n        # prepare tac controller for test\n        self.set_agent_context(tac_controller_name)\n        self.add_item(\"connection\", \"fetchai/p2p_libp2p:0.27.5\")\n        self.set_config(\"agent.default_connection\", \"fetchai/p2p_libp2p:0.27.5\")\n        self.add_item(\"connection\", \"fetchai/soef:0.27.6\")\n        self.add_item(\"skill\", \"fetchai/tac_control:0.25.6\")\n        self.set_config(\"agent.default_ledger\", FetchAICrypto.identifier)\n        setting_path = \"agent.default_routing\"\n        self.nested_set_config(setting_path, default_routing)\n        self.run_install()\n\n        diff = self.difference_to_fetched_agent(\n            \"fetchai/tac_controller:0.30.5\", tac_controller_name\n        )\n        assert (\n            diff == []\n        ), \"Difference between created and fetched project for files={}\".format(diff)\n\n        # add keys\n        self.generate_private_key(FetchAICrypto.identifier)\n        self.generate_private_key(\n            FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE_CONNECTION\n        )\n        self.add_private_key(FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE)\n        self.add_private_key(\n            FetchAICrypto.identifier,\n            FETCHAI_PRIVATE_KEY_FILE_CONNECTION,\n            connection=True,\n        )\n        self.replace_private_key_in_file(\n            NON_FUNDED_FETCHAI_PRIVATE_KEY_1, FETCHAI_PRIVATE_KEY_FILE_CONNECTION\n        )\n        setting_path = \"vendor.fetchai.connections.p2p_libp2p.config.ledger_id\"\n        self.set_config(setting_path, FetchAICrypto.identifier)\n\n        # replace location\n        setting_path = (\n            \"vendor.fetchai.skills.tac_control.models.parameters.args.location\"\n        )\n        self.nested_set_config(setting_path, location)\n\n        # set tac id\n        data = {\"key\": \"tac\", \"value\": tac_id}\n        setting_path = (\n            \"vendor.fetchai.skills.tac_control.models.parameters.args.service_data\"\n        )\n        self.nested_set_config(setting_path, data)\n\n        default_routing = {\n            \"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n            \"fetchai/oef_search:1.1.7\": \"fetchai/soef:0.27.6\",\n        }\n\n        self.run_cli_command(\"build\", cwd=self._get_cwd())\n        self.run_cli_command(\"issue-certificates\", cwd=self._get_cwd())\n\n        # prepare agents for test\n        for agent_name, config in (\n            (tac_aea_one, NON_GENESIS_CONFIG),\n            (tac_aea_two, NON_GENESIS_CONFIG_TWO),\n        ):\n            self.set_agent_context(agent_name)\n            self.add_item(\"connection\", \"fetchai/p2p_libp2p:0.27.5\")\n            self.set_config(\"agent.default_connection\", \"fetchai/p2p_libp2p:0.27.5\")\n            self.add_item(\"connection\", \"fetchai/soef:0.27.6\")\n            self.add_item(\"connection\", \"fetchai/ledger:0.21.5\")\n            self.add_item(\"skill\", \"fetchai/tac_participation:0.25.6\")\n            self.add_item(\"skill\", \"fetchai/tac_negotiation:0.29.6\")\n            self.set_config(\"agent.default_ledger\", FetchAICrypto.identifier)\n            setting_path = \"agent.default_routing\"\n            self.nested_set_config(setting_path, default_routing)\n            data = {\n                \"dotted_path\": \"aea.decision_maker.gop:DecisionMakerHandler\",\n                \"file_path\": None,\n                \"config\": {},\n            }\n            setting_path = \"agent.decision_maker_handler\"\n            self.nested_set_config(setting_path, data)\n            self.run_install()\n            diff = self.difference_to_fetched_agent(\n                \"fetchai/tac_participant:0.32.5\", agent_name\n            )\n            assert (\n                diff == []\n            ), \"Difference between created and fetched project for files={}\".format(\n                diff\n            )\n\n            # add keys\n            self.generate_private_key(FetchAICrypto.identifier)\n            self.generate_private_key(\n                FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE_CONNECTION\n            )\n            self.add_private_key(FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE)\n            self.add_private_key(\n                FetchAICrypto.identifier,\n                FETCHAI_PRIVATE_KEY_FILE_CONNECTION,\n                connection=True,\n            )\n\n            # set p2p configs\n            setting_path = \"vendor.fetchai.connections.p2p_libp2p.config\"\n            self.nested_set_config(setting_path, config)\n\n            # replace location\n            setting_path = (\n                \"vendor.fetchai.skills.tac_participation.models.game.args.location\"\n            )\n            self.nested_set_config(setting_path, location)\n\n            # set tac id\n            data = {\n                \"search_key\": \"tac\",\n                \"search_value\": tac_id,\n                \"constraint_type\": \"==\",\n            }\n            setting_path = (\n                \"vendor.fetchai.skills.tac_participation.models.game.args.search_query\"\n            )\n            self.nested_set_config(setting_path, data)\n            self.set_config(\n                \"vendor.fetchai.skills.tac_negotiation.models.strategy.args.service_key\",\n                tac_service,\n            )\n\n            self.run_cli_command(\"build\", cwd=self._get_cwd())\n            self.run_cli_command(\"issue-certificates\", cwd=self._get_cwd())\n\n        # run tac controller\n        self.set_agent_context(tac_controller_name)\n        now = datetime.datetime.now().strftime(\"%d %m %Y %H:%M\")\n        now_min = datetime.datetime.strptime(now, \"%d %m %Y %H:%M\")\n        fut = now_min + datetime.timedelta(0, 60)\n        start_time = fut.strftime(\"%d %m %Y %H:%M\")\n        setting_path = \"vendor.fetchai.skills.tac_control.models.parameters.args.registration_start_time\"\n        self.set_config(setting_path, start_time)\n        tac_controller_process = self.run_agent()\n\n        check_strings = (\n            \"Starting libp2p node...\",\n            \"Connecting to libp2p node...\",\n            \"Successfully connected to libp2p node!\",\n            LIBP2P_SUCCESS_MESSAGE,\n        )\n        missing_strings = self.missing_from_output(\n            tac_controller_process, check_strings, timeout=30, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in tac_controller output.\".format(missing_strings)\n\n        # run two agents (participants)\n        self.set_agent_context(tac_aea_one)\n        tac_aea_one_process = self.run_agent()\n\n        self.set_agent_context(tac_aea_two)\n        tac_aea_two_process = self.run_agent()\n\n        check_strings = (\n            \"Starting libp2p node...\",\n            \"Connecting to libp2p node...\",\n            \"Successfully connected to libp2p node!\",\n            LIBP2P_SUCCESS_MESSAGE,\n        )\n        missing_strings = self.missing_from_output(\n            tac_aea_one_process, check_strings, timeout=30, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in tac_aea_one output.\".format(missing_strings)\n\n        check_strings = (\n            \"Starting libp2p node...\",\n            \"Connecting to libp2p node...\",\n            \"Successfully connected to libp2p node!\",\n            LIBP2P_SUCCESS_MESSAGE,\n        )\n        missing_strings = self.missing_from_output(\n            tac_aea_two_process, check_strings, timeout=30, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in tac_aea_two output.\".format(missing_strings)\n\n        check_strings = (\n            \"registering agent on SOEF.\",\n            \"registering TAC data model on SOEF.\",\n            \"TAC open for registration until:\",\n            \"registered as 'tac_participant_one'\",\n            \"registered as 'tac_participant_two'\",\n            \"started competition:\",\n            \"unregistering TAC data model from SOEF.\",\n            \"handling valid transaction:\",\n            \"Current good & money allocation & score: \",\n        )\n        missing_strings = self.missing_from_output(\n            tac_controller_process, check_strings, timeout=240, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in tac_controller output.\".format(missing_strings)\n\n        check_strings = (\n            \"searching for TAC, search_id=\",\n            \"found the TAC controller. Registering...\",\n            \"received start event from the controller. Starting to compete...\",\n            \"registering agent on SOEF.\",\n            \"searching for sellers, search_id=\",\n            \"searching for buyers, search_id=\",\n            \"found potential sellers agents=\",\n            \"received cfp from\",\n            \"received decline from\",\n            \"received propose from\",\n            \"received accept from\",\n            \"received match_accept_w_inform from\",\n            \"sending CFP to agent=\",\n            \"sending propose to\",\n            \"sending accept to\",\n            \"requesting signature, sending sign_message to decision_maker, message=\",\n            \"received signed_message from decision_maker, message=\",\n            \"sending transaction to controller, tx=\",\n            \"received transaction confirmation from the controller:\",\n            \"Applying state update!\",\n            \"found potential buyers agents=\",\n            \"sending CFP to agent=\",\n        )\n        missing_strings = self.missing_from_output(\n            tac_aea_one_process, check_strings, timeout=240, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in tac_aea_one output.\".format(missing_strings)\n\n        # Note, we do not need to check std output of the other participant as it is implied\n\n        self.terminate_agents(\n            tac_controller_process, tac_aea_one_process, tac_aea_two_process\n        )\n        assert (\n            self.is_successfully_terminated()\n        ), \"Agents weren't successfully terminated.\"\n\n\nclass TestTacSkillsContractEthereum(AEATestCaseManyFlaky, UseGanache, UseSOEF):\n    \"\"\"Test that tac skills work.\"\"\"\n\n    capture_log = True\n\n    @pytest.mark.integration\n    @pytest.mark.ledger\n    @pytest.mark.flaky(reruns=MAX_FLAKY_RERUNS_ETH)  # cause possible network issues\n    def test_tac(self):\n        \"\"\"Run the tac skills sequence.\"\"\"\n        tac_aea_one = \"tac_participant_one\"\n        tac_aea_two = \"tac_participant_two\"\n        tac_controller_name = \"tac_controller_contract\"\n\n        # create tac controller, agent one and agent two\n        self.create_agents(\n            tac_aea_one,\n            tac_aea_two,\n            tac_controller_name,\n        )\n\n        # default routing (both for controller and participants)\n        default_routing = {\n            \"fetchai/contract_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n            \"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n            \"fetchai/oef_search:1.1.7\": \"fetchai/soef:0.27.6\",\n        }\n\n        # generate random location\n        location = {\n            \"latitude\": round(uniform(-90, 90), 2),  # nosec\n            \"longitude\": round(uniform(-180, 180), 2),  # nosec\n        }\n\n        # tac name\n        tac_id = uuid.uuid4().hex\n        tac_service = f\"tac_service_{tac_id[:5]}\"\n\n        # prepare tac controller for test\n        self.set_agent_context(tac_controller_name)\n        self.add_item(\"connection\", \"fetchai/p2p_libp2p:0.27.5\")\n        self.set_config(\"agent.default_connection\", \"fetchai/p2p_libp2p:0.27.5\")\n        self.add_item(\"connection\", \"fetchai/soef:0.27.6\")\n        self.add_item(\"connection\", \"fetchai/ledger:0.21.5\")\n        self.add_item(\"skill\", \"fetchai/tac_control_contract:0.27.6\")\n        self.set_config(\"agent.default_ledger\", FetchAICrypto.identifier)\n        self.nested_set_config(\n            \"agent.required_ledgers\",\n            [FetchAICrypto.identifier, EthereumCrypto.identifier],\n        )\n        setting_path = \"agent.default_routing\"\n        self.nested_set_config(setting_path, default_routing)\n        self.run_install()\n\n        # add keys\n        self.generate_private_key(EthereumCrypto.identifier)\n        self.generate_private_key(\n            FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE_CONNECTION\n        )\n        self.add_private_key(EthereumCrypto.identifier, ETHEREUM_PRIVATE_KEY_FILE)\n        self.add_private_key(\n            FetchAICrypto.identifier,\n            FETCHAI_PRIVATE_KEY_FILE_CONNECTION,\n            connection=True,\n        )\n        self.replace_private_key_in_file(\n            FUNDED_ETH_PRIVATE_KEY_1, ETHEREUM_PRIVATE_KEY_FILE\n        )\n        self.replace_private_key_in_file(\n            NON_FUNDED_FETCHAI_PRIVATE_KEY_1, FETCHAI_PRIVATE_KEY_FILE_CONNECTION\n        )\n        setting_path = \"vendor.fetchai.connections.p2p_libp2p.cert_requests\"\n        settings = json.dumps(\n            [\n                {\n                    \"identifier\": \"acn\",\n                    \"ledger_id\": EthereumCrypto.identifier,\n                    \"not_after\": \"2023-01-01\",\n                    \"not_before\": \"2022-01-01\",\n                    \"public_key\": FetchAICrypto.identifier,\n                    \"message_format\": \"{public_key}\",\n                    \"save_path\": \".certs/conn_cert.txt\",\n                }\n            ]\n        )\n        self.set_config(setting_path, settings, type_=\"list\")\n        settings = json.dumps(\n            [\n                {\n                    \"identifier\": \"acn\",\n                    \"ledger_id\": FetchAICrypto.identifier,\n                    \"not_after\": \"2023-01-01\",\n                    \"not_before\": \"2022-01-01\",\n                    \"public_key\": FetchAICrypto.identifier,\n                    \"message_format\": \"{public_key}\",\n                    \"save_path\": \".certs/conn_cert.txt\",\n                }\n            ]\n        )\n        self.set_config(setting_path, settings, type_=\"list\")\n\n        # set SOEF configuration\n        setting_path = \"vendor.fetchai.connections.soef.config.chain_identifier\"\n        self.set_config(setting_path, \"fetchai_v2_misc\")\n\n        setting_path = \"vendor.fetchai.skills.tac_control.is_abstract\"\n        self.set_config(setting_path, True, \"bool\")\n\n        # replace location\n        setting_path = (\n            \"vendor.fetchai.skills.tac_control_contract.models.parameters.args.location\"\n        )\n        self.nested_set_config(setting_path, location)\n\n        # set tac id\n        data = {\"key\": \"tac\", \"value\": tac_id}\n        setting_path = \"vendor.fetchai.skills.tac_control_contract.models.parameters.args.service_data\"\n        self.nested_set_config(setting_path, data)\n\n        # check manually built agent is the same as the fetched one\n        diff = self.difference_to_fetched_agent(\n            \"fetchai/tac_controller_contract:0.32.5\", tac_controller_name\n        )\n        assert (\n            diff == []\n        ), \"Difference between created and fetched project for files={}\".format(diff)\n\n        # change default ledger to Ethereum\n        self.set_config(\"agent.default_ledger\", EthereumCrypto.identifier)\n\n        # set SOEF connection configuration\n        setting_path = \"vendor.fetchai.connections.soef.config.chain_identifier\"\n        self.set_config(setting_path, EthereumCrypto.identifier)\n\n        # set p2p_libp2p connection config\n        setting_path = \"vendor.fetchai.connections.p2p_libp2p.cert_requests\"\n        settings = json.dumps(\n            [\n                {\n                    \"identifier\": \"acn\",\n                    \"ledger_id\": EthereumCrypto.identifier,\n                    \"not_after\": \"2023-01-01\",\n                    \"not_before\": \"2022-01-01\",\n                    \"public_key\": FetchAICrypto.identifier,\n                    \"message_format\": \"{public_key}\",\n                    \"save_path\": \".certs/conn_cert.txt\",\n                }\n            ]\n        )\n        self.set_config(setting_path, settings, type_=\"list\")\n\n        # change SOEF configuration to local\n        setting_path = \"vendor.fetchai.connections.soef.config.is_https\"\n        self.set_config(setting_path, False)\n        setting_path = \"vendor.fetchai.connections.soef.config.soef_addr\"\n        self.set_config(setting_path, \"127.0.0.1\")\n        setting_path = \"vendor.fetchai.connections.soef.config.soef_port\"\n        self.set_config(setting_path, 12002)\n\n        # prepare agents for test\n        for agent_name, config, private_key in (\n            (tac_aea_one, NON_GENESIS_CONFIG, FUNDED_ETH_PRIVATE_KEY_2),\n            (tac_aea_two, NON_GENESIS_CONFIG_TWO, FUNDED_ETH_PRIVATE_KEY_3),\n        ):\n            self.set_agent_context(agent_name)\n\n            # add items\n            self.add_item(\"connection\", \"fetchai/p2p_libp2p:0.27.5\")\n            self.add_item(\"connection\", \"fetchai/soef:0.27.6\")\n            self.add_item(\"connection\", \"fetchai/ledger:0.21.5\")\n            self.add_item(\"skill\", \"fetchai/tac_participation:0.25.6\")\n            self.add_item(\"skill\", \"fetchai/tac_negotiation:0.29.6\")\n\n            # set AEA config (no component overrides)\n            self.set_config(\"agent.default_connection\", \"fetchai/p2p_libp2p:0.27.5\")\n            self.set_config(\"agent.default_ledger\", FetchAICrypto.identifier)\n            self.nested_set_config(\n                \"agent.required_ledgers\",\n                [FetchAICrypto.identifier, EthereumCrypto.identifier],\n            )\n            setting_path = \"agent.default_routing\"\n            self.nested_set_config(setting_path, default_routing)\n            data = {\n                \"dotted_path\": \"aea.decision_maker.gop:DecisionMakerHandler\",\n                \"file_path\": None,\n                \"config\": {},\n            }\n            setting_path = \"agent.decision_maker_handler\"\n            self.nested_set_config(setting_path, data)\n\n            # install PyPI dependencies\n            self.run_install()\n\n            # add keys\n            self.generate_private_key(EthereumCrypto.identifier)\n            self.generate_private_key(\n                FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE_CONNECTION\n            )\n            self.add_private_key(EthereumCrypto.identifier, ETHEREUM_PRIVATE_KEY_FILE)\n            self.add_private_key(\n                FetchAICrypto.identifier,\n                FETCHAI_PRIVATE_KEY_FILE_CONNECTION,\n                connection=True,\n            )\n            self.replace_private_key_in_file(private_key, ETHEREUM_PRIVATE_KEY_FILE)\n\n            # set p2p configs\n            setting_path = \"vendor.fetchai.connections.p2p_libp2p.config\"\n            self.nested_set_config(setting_path, config)\n            setting_path = \"vendor.fetchai.connections.p2p_libp2p.cert_requests\"\n            settings = json.dumps(\n                [\n                    {\n                        \"identifier\": \"acn\",\n                        \"ledger_id\": EthereumCrypto.identifier,\n                        \"not_after\": \"2023-01-01\",\n                        \"not_before\": \"2022-01-01\",\n                        \"public_key\": FetchAICrypto.identifier,\n                        \"message_format\": \"{public_key}\",\n                        \"save_path\": \".certs/conn_cert.txt\",\n                    }\n                ]\n            )\n            self.set_config(setting_path, settings, type_=\"list\")\n            settings = json.dumps(\n                [\n                    {\n                        \"identifier\": \"acn\",\n                        \"ledger_id\": FetchAICrypto.identifier,\n                        \"not_after\": \"2023-01-01\",\n                        \"not_before\": \"2022-01-01\",\n                        \"public_key\": FetchAICrypto.identifier,\n                        \"message_format\": \"{public_key}\",\n                        \"save_path\": \".certs/conn_cert.txt\",\n                    }\n                ]\n            )\n            self.set_config(setting_path, settings, type_=\"list\")\n\n            # set SOEF configuration\n            setting_path = \"vendor.fetchai.connections.soef.config.chain_identifier\"\n            self.set_config(setting_path, \"fetchai_v2_misc\")\n\n            # set tac participant configuration\n            self.set_config(\n                \"vendor.fetchai.skills.tac_participation.models.game.args.is_using_contract\",\n                True,\n                \"bool\",\n            )\n\n            # set tac negotiation configuration\n            self.set_config(\n                \"vendor.fetchai.skills.tac_negotiation.models.strategy.args.is_contract_tx\",\n                True,\n                \"bool\",\n            )\n\n            # replace location\n            setting_path = (\n                \"vendor.fetchai.skills.tac_participation.models.game.args.location\"\n            )\n            self.nested_set_config(setting_path, location)\n\n            # set tac id\n            data = {\n                \"search_key\": \"tac\",\n                \"search_value\": tac_id,\n                \"constraint_type\": \"==\",\n            }\n            setting_path = (\n                \"vendor.fetchai.skills.tac_participation.models.game.args.search_query\"\n            )\n            self.nested_set_config(setting_path, data)\n\n            diff = self.difference_to_fetched_agent(\n                \"fetchai/tac_participant_contract:0.22.5\", agent_name\n            )\n            assert (\n                diff == []\n            ), \"Difference between created and fetched project for files={}\".format(\n                diff\n            )\n\n            # change default ledger to Ethereum\n            self.set_config(\"agent.default_ledger\", EthereumCrypto.identifier)\n\n            # set SOEF connection configuration\n            setting_path = \"vendor.fetchai.connections.soef.config.chain_identifier\"\n            self.set_config(setting_path, EthereumCrypto.identifier)\n\n            # set p2p_libp2p connection config\n            setting_path = \"vendor.fetchai.connections.p2p_libp2p.cert_requests\"\n            settings = json.dumps(\n                [\n                    {\n                        \"identifier\": \"acn\",\n                        \"ledger_id\": EthereumCrypto.identifier,\n                        \"not_after\": \"2023-01-01\",\n                        \"not_before\": \"2022-01-01\",\n                        \"public_key\": FetchAICrypto.identifier,\n                        \"message_format\": \"{public_key}\",\n                        \"save_path\": \".certs/conn_cert.txt\",\n                    }\n                ]\n            )\n            self.set_config(setting_path, settings, type_=\"list\")\n\n            # change SOEF configuration to local\n            setting_path = \"vendor.fetchai.connections.soef.config.is_https\"\n            self.set_config(setting_path, False)\n            setting_path = \"vendor.fetchai.connections.soef.config.soef_addr\"\n            self.set_config(setting_path, \"127.0.0.1\")\n            setting_path = \"vendor.fetchai.connections.soef.config.soef_port\"\n            self.set_config(setting_path, 12002)\n\n            self.set_config(\n                \"vendor.fetchai.skills.tac_negotiation.models.strategy.args.service_key\",\n                tac_service,\n            )\n\n        # run tac controller\n        self.set_agent_context(tac_controller_name)\n        self.run_cli_command(\"build\", cwd=self._get_cwd())\n        self.run_cli_command(\"issue-certificates\", cwd=self._get_cwd())\n        now = datetime.datetime.now().strftime(\"%d %m %Y %H:%M\")\n        now_min = datetime.datetime.strptime(now, \"%d %m %Y %H:%M\")\n        fut = now_min + datetime.timedelta(\n            0, 120\n        )  # we provide 2 minutes time for contract deployment\n        start_time = fut.strftime(\"%d %m %Y %H:%M\")\n        setting_path = \"vendor.fetchai.skills.tac_control_contract.models.parameters.args.registration_start_time\"\n        self.set_config(setting_path, start_time)\n        tac_controller_process = self.run_agent()\n\n        check_strings = (\n            \"Starting libp2p node...\",\n            \"Connecting to libp2p node...\",\n            \"Successfully connected to libp2p node!\",\n            LIBP2P_SUCCESS_MESSAGE,\n            \"registering agent on SOEF.\",\n            \"requesting contract deployment transaction...\",\n            \"Start processing messages...\",\n            \"received raw transaction=\",\n            \"transaction signing was successful.\",\n            \"sending transaction to ledger.\",\n            \"transaction was successfully submitted. Transaction digest=\",\n            \"requesting transaction receipt.\",\n            \"transaction was successfully settled. Transaction receipt=\",\n            \"contract deployed.\",\n            \"registering TAC data model on SOEF.\",\n            \"TAC open for registration until:\",\n        )\n        missing_strings = self.missing_from_output(\n            tac_controller_process, check_strings, timeout=180, is_terminating=False\n        )  # we need to wait sufficiently long (at least 2 minutes - see above for deployment)\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in tac_controller output.\".format(missing_strings)\n\n        # run two agents (participants)\n        self.set_agent_context(tac_aea_one)\n        self.run_cli_command(\"build\", cwd=self._get_cwd())\n        self.run_cli_command(\"issue-certificates\", cwd=self._get_cwd())\n        tac_aea_one_process = self.run_agent()\n\n        self.set_agent_context(tac_aea_two)\n        self.run_cli_command(\"build\", cwd=self._get_cwd())\n        self.run_cli_command(\"issue-certificates\", cwd=self._get_cwd())\n        tac_aea_two_process = self.run_agent()\n\n        check_strings = (\n            \"Starting libp2p node...\",\n            \"Connecting to libp2p node...\",\n            \"Successfully connected to libp2p node!\",\n            LIBP2P_SUCCESS_MESSAGE,\n            \"Start processing messages...\",\n            \"searching for TAC, search_id=\",\n        )\n        missing_strings = self.missing_from_output(\n            tac_aea_one_process, check_strings, timeout=30, is_terminating=False\n        )\n        check_strings = (\"found the TAC controller. Registering...\",)\n        missing_strings = self.missing_from_output(\n            tac_aea_one_process, check_strings, timeout=60, is_terminating=False\n        )  # we need to wait sufficiently long (at least 1 minutes - for registration)\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in tac_aea_one output.\".format(missing_strings)\n\n        check_strings = (\n            \"Starting libp2p node...\",\n            \"Connecting to libp2p node...\",\n            \"Successfully connected to libp2p node!\",\n            LIBP2P_SUCCESS_MESSAGE,\n            \"Start processing messages...\",\n            \"searching for TAC, search_id=\",\n            \"found the TAC controller. Registering...\",\n        )\n        missing_strings = self.missing_from_output(\n            tac_aea_two_process, check_strings, timeout=30, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in tac_aea_two output.\".format(missing_strings)\n\n        check_strings = (\n            \"registered as 'tac_participant_one'\",\n            \"registered as 'tac_participant_two'\",\n            \"closing registration!\",\n            \"unregistering TAC data model from SOEF.\",\n            \"requesting create items transaction...\",\n            \"received raw transaction=\",\n            \"proposing the transaction to the decision maker. Waiting for confirmation ...\",\n            \"transaction signing was successful.\",\n            \"transaction was successfully submitted. Transaction digest=\",\n            \"requesting transaction receipt.\",\n            \"transaction was successfully settled. Transaction receipt=\",\n            \"tokens created.\",\n            \"requesting mint_items transactions for agent=\",\n            \"tokens minted.\",\n            \"requesting mint_items transactions for agent=\",\n            \"tokens minted.\",\n            \"all tokens minted.\",\n            \"started competition:\",\n        )\n        missing_strings = self.missing_from_output(\n            tac_controller_process, check_strings, timeout=240, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in tac_controller output.\".format(missing_strings)\n\n        check_strings = (\n            \"received start event from the controller. Starting to compete...\",\n            \"received a contract address:\",\n            \"registering agent on SOEF.\",\n            \"searching for sellers, search_id=\",\n            \"searching for buyers, search_id=\",\n            \"found potential sellers agents=\",\n            \"found potential buyers agents=\",\n            \"sending CFP to agent=\",\n            \"received cfp from\",\n            \"received propose from\",\n            \"received decline from\",\n            \"received accept from\",\n            \"received match_accept_w_inform from\",\n            \"sending propose to\",\n            \"sending accept to\",\n            \"requesting batch transaction hash, sending get_raw_message to fetchai/erc1155:0.23.3, message=\",\n            \"requesting batch atomic swap transaction, sending get_raw_transaction to fetchai/erc1155:0.23.3, message=\",\n            \"received raw transaction=\",\n            \"received raw message=\",\n            \"proposing the transaction to the decision maker. Waiting for confirmation ...\",\n            \"proposing the message to the decision maker. Waiting for confirmation ...\",\n            \"received signed_message from decision_maker, message=\",\n            \"received signed_transaction from decision_maker, message=\",\n            \"sending send_signed_transaction to ledger ethereum, message=\",\n            \"transaction was successfully submitted. Transaction digest=\",\n            \"transaction was successfully settled. Transaction receipt=\",\n        )\n        missing_strings = self.missing_from_output(\n            tac_aea_one_process, check_strings, timeout=300, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in tac_aea_one output.\".format(missing_strings)\n\n        check_strings = (\n            \"received start event from the controller. Starting to compete...\",\n            \"received a contract address:\",\n            \"registering agent on SOEF.\",\n            \"searching for sellers, search_id=\",\n            \"searching for buyers, search_id=\",\n            \"found potential sellers agents=\",\n            \"found potential buyers agents=\",\n            \"sending CFP to agent=\",\n            \"received cfp from\",\n            \"received propose from\",\n            \"received decline from\",\n            \"received accept from\",\n            \"received match_accept_w_inform from\",\n            \"sending propose to\",\n            \"sending accept to\",\n            \"requesting batch transaction hash, sending get_raw_message to fetchai/erc1155:0.23.3, message=\",\n            \"requesting batch atomic swap transaction, sending get_raw_transaction to fetchai/erc1155:0.23.3, message=\",\n            \"received raw transaction=\",\n            \"received raw message=\",\n            \"proposing the transaction to the decision maker. Waiting for confirmation ...\",\n            \"proposing the message to the decision maker. Waiting for confirmation ...\",\n            \"received signed_message from decision_maker, message=\",\n            \"received signed_transaction from decision_maker, message=\",\n            \"sending send_signed_transaction to ledger ethereum, message=\",\n            \"transaction was successfully submitted. Transaction digest=\",\n            \"transaction was successfully settled. Transaction receipt=\",\n        )\n        missing_strings = self.missing_from_output(\n            tac_aea_two_process, check_strings, timeout=360, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in tac_aea_two output.\".format(missing_strings)\n\n        # Note, we do not need to check std output of the other participant as it is implied\n\n        self.terminate_agents(\n            tac_controller_process, tac_aea_one_process, tac_aea_two_process\n        )\n        assert (\n            self.is_successfully_terminated()\n        ), \"Agents weren't successfully terminated.\"\n\n\nclass TestTacSkillsContractFetchai(AEATestCaseManyFlaky, UseLocalFetchNode, UseSOEF):\n    \"\"\"Test that tac skills work.\"\"\"\n\n    capture_log = True\n    LOCAL_TESTNET_CHAIN_ID = DEFAULT_FETCH_CHAIN_ID\n\n    @pytest.mark.integration\n    @pytest.mark.ledger\n    @pytest.mark.flaky(reruns=MAX_FLAKY_RERUNS_ETH)  # cause possible network issues\n    def test_tac(self):\n        \"\"\"Run the tac skills sequence.\"\"\"\n        tac_aea_one = \"tac_participant_one\"\n        tac_aea_two = \"tac_participant_two\"\n        tac_controller_name = \"tac_controller_contract\"\n\n        # create tac controller, agent one and agent two\n        self.create_agents(\n            tac_aea_one,\n            tac_aea_two,\n            tac_controller_name,\n        )\n\n        # default routing (both for controller and participants)\n        default_routing = {\n            \"fetchai/contract_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n            \"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n            \"fetchai/oef_search:1.1.7\": \"fetchai/soef:0.27.6\",\n        }\n\n        # generate random location\n        location = {\n            \"latitude\": round(uniform(-90, 90), 2),  # nosec\n            \"longitude\": round(uniform(-180, 180), 2),  # nosec\n        }\n\n        # tac name\n        tac_id = uuid.uuid4().hex\n        tac_service = f\"tac_service_{tac_id[:5]}\"\n\n        # prepare tac controller for test\n        self.set_agent_context(tac_controller_name)\n        self.add_item(\"connection\", \"fetchai/p2p_libp2p:0.27.5\")\n        self.set_config(\"agent.default_connection\", \"fetchai/p2p_libp2p:0.27.5\")\n        self.add_item(\"connection\", \"fetchai/soef:0.27.6\")\n        self.add_item(\"connection\", \"fetchai/ledger:0.21.5\")\n        self.add_item(\"skill\", \"fetchai/tac_control_contract:0.27.6\")\n        self.set_config(\"agent.default_ledger\", FetchAICrypto.identifier)\n        self.nested_set_config(\n            \"agent.required_ledgers\",\n            [FetchAICrypto.identifier, EthereumCrypto.identifier],\n        )\n        setting_path = \"agent.default_routing\"\n        self.nested_set_config(setting_path, default_routing)\n        self.run_install()\n\n        # add keys\n        self.generate_private_key(FetchAICrypto.identifier)\n        self.generate_private_key(\n            FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE_CONNECTION\n        )\n        self.add_private_key(FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE)\n        self.add_private_key(\n            FetchAICrypto.identifier,\n            FETCHAI_PRIVATE_KEY_FILE_CONNECTION,\n            connection=True,\n        )\n\n        # fund controller account\n        controller_address = self.get_address(FetchAICrypto.identifier)\n        fund_accounts_from_local_validator([controller_address], 10000000000000000000)\n\n        self.replace_private_key_in_file(\n            NON_FUNDED_FETCHAI_PRIVATE_KEY_1, FETCHAI_PRIVATE_KEY_FILE_CONNECTION\n        )\n\n        setting_path = \"vendor.fetchai.connections.p2p_libp2p.cert_requests\"\n        settings = json.dumps(\n            [\n                {\n                    \"identifier\": \"acn\",\n                    \"ledger_id\": EthereumCrypto.identifier,\n                    \"not_after\": \"2023-01-01\",\n                    \"not_before\": \"2022-01-01\",\n                    \"public_key\": FetchAICrypto.identifier,\n                    \"message_format\": \"{public_key}\",\n                    \"save_path\": \".certs/conn_cert.txt\",\n                }\n            ]\n        )\n        self.set_config(setting_path, settings, type_=\"list\")\n        settings = json.dumps(\n            [\n                {\n                    \"identifier\": \"acn\",\n                    \"ledger_id\": FetchAICrypto.identifier,\n                    \"not_after\": \"2023-01-01\",\n                    \"not_before\": \"2022-01-01\",\n                    \"public_key\": FetchAICrypto.identifier,\n                    \"message_format\": \"{public_key}\",\n                    \"save_path\": \".certs/conn_cert.txt\",\n                }\n            ]\n        )\n        self.set_config(setting_path, settings, type_=\"list\")\n\n        # set SOEF configuration\n        setting_path = \"vendor.fetchai.connections.soef.config.chain_identifier\"\n        self.set_config(setting_path, \"fetchai_v2_misc\")\n\n        setting_path = \"vendor.fetchai.skills.tac_control.is_abstract\"\n        self.set_config(setting_path, True, \"bool\")\n\n        # replace location\n        setting_path = (\n            \"vendor.fetchai.skills.tac_control_contract.models.parameters.args.location\"\n        )\n        self.nested_set_config(setting_path, location)\n\n        # set tac id\n        data = {\"key\": \"tac\", \"value\": tac_id}\n        setting_path = \"vendor.fetchai.skills.tac_control_contract.models.parameters.args.service_data\"\n        self.nested_set_config(setting_path, data)\n\n        # check manually built agent is the same as the fetched one\n        diff = self.difference_to_fetched_agent(\n            \"fetchai/tac_controller_contract:0.32.5\", tac_controller_name\n        )\n        assert (\n            diff == []\n        ), \"Difference between created and fetched project for files={}\".format(diff)\n\n        # use local test-net\n        setting_path = (\n            \"vendor.fetchai.connections.ledger.config.ledger_apis.fetchai.address\"\n        )\n        self.set_config(\n            setting_path,\n            f\"{DEFAULT_FETCH_LEDGER_ADDR}:{DEFAULT_FETCH_LEDGER_REST_PORT}\",\n        )\n        setting_path = (\n            \"vendor.fetchai.connections.ledger.config.ledger_apis.fetchai.denom\"\n        )\n        self.set_config(setting_path, DEFAULT_DENOMINATION)\n        setting_path = (\n            \"vendor.fetchai.connections.ledger.config.ledger_apis.fetchai.chain_id\"\n        )\n        self.set_config(setting_path, self.LOCAL_TESTNET_CHAIN_ID)\n\n        # change SOEF configuration to local\n        setting_path = \"vendor.fetchai.connections.soef.config.is_https\"\n        self.set_config(setting_path, False)\n        setting_path = \"vendor.fetchai.connections.soef.config.soef_addr\"\n        self.set_config(setting_path, \"127.0.0.1\")\n        setting_path = \"vendor.fetchai.connections.soef.config.soef_port\"\n        self.set_config(setting_path, 12002)\n\n        # prepare agents for test\n        for agent_name, config in (\n            (tac_aea_one, NON_GENESIS_CONFIG),\n            (tac_aea_two, NON_GENESIS_CONFIG_TWO),\n        ):\n            self.set_agent_context(agent_name)\n\n            # add items\n            self.add_item(\"connection\", \"fetchai/p2p_libp2p:0.27.5\")\n            self.add_item(\"connection\", \"fetchai/soef:0.27.6\")\n            self.add_item(\"connection\", \"fetchai/ledger:0.21.5\")\n            self.add_item(\"skill\", \"fetchai/tac_participation:0.25.6\")\n            self.add_item(\"skill\", \"fetchai/tac_negotiation:0.29.6\")\n\n            # set AEA config (no component overrides)\n            self.set_config(\"agent.default_connection\", \"fetchai/p2p_libp2p:0.27.5\")\n            self.set_config(\"agent.default_ledger\", FetchAICrypto.identifier)\n            self.nested_set_config(\n                \"agent.required_ledgers\",\n                [FetchAICrypto.identifier, EthereumCrypto.identifier],\n            )\n            setting_path = \"agent.default_routing\"\n            self.nested_set_config(setting_path, default_routing)\n            data = {\n                \"dotted_path\": \"aea.decision_maker.gop:DecisionMakerHandler\",\n                \"file_path\": None,\n                \"config\": {},\n            }\n            setting_path = \"agent.decision_maker_handler\"\n            self.nested_set_config(setting_path, data)\n\n            # install PyPI dependencies\n            self.run_install()\n\n            # add keys\n            self.generate_private_key(FetchAICrypto.identifier)\n            self.generate_private_key(\n                FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE_CONNECTION\n            )\n            self.add_private_key(FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE)\n            self.add_private_key(\n                FetchAICrypto.identifier,\n                FETCHAI_PRIVATE_KEY_FILE_CONNECTION,\n                connection=True,\n            )\n\n            # fund participant account\n            participant_address = self.get_address(FetchAICrypto.identifier)\n            fund_accounts_from_local_validator(\n                [participant_address], 10000000000000000000\n            )\n\n            # set p2p configs\n            setting_path = \"vendor.fetchai.connections.p2p_libp2p.config\"\n            self.nested_set_config(setting_path, config)\n            setting_path = \"vendor.fetchai.connections.p2p_libp2p.cert_requests\"\n            settings = json.dumps(\n                [\n                    {\n                        \"identifier\": \"acn\",\n                        \"ledger_id\": EthereumCrypto.identifier,\n                        \"not_after\": \"2023-01-01\",\n                        \"not_before\": \"2022-01-01\",\n                        \"public_key\": FetchAICrypto.identifier,\n                        \"message_format\": \"{public_key}\",\n                        \"save_path\": \".certs/conn_cert.txt\",\n                    }\n                ]\n            )\n            self.set_config(setting_path, settings, type_=\"list\")\n            settings = json.dumps(\n                [\n                    {\n                        \"identifier\": \"acn\",\n                        \"ledger_id\": FetchAICrypto.identifier,\n                        \"not_after\": \"2023-01-01\",\n                        \"not_before\": \"2022-01-01\",\n                        \"public_key\": FetchAICrypto.identifier,\n                        \"message_format\": \"{public_key}\",\n                        \"save_path\": \".certs/conn_cert.txt\",\n                    }\n                ]\n            )\n            self.set_config(setting_path, settings, type_=\"list\")\n\n            # set SOEF configuration\n            setting_path = \"vendor.fetchai.connections.soef.config.chain_identifier\"\n            self.set_config(setting_path, \"fetchai_v2_misc\")\n\n            # set tac participant configuration\n            self.set_config(\n                \"vendor.fetchai.skills.tac_participation.models.game.args.is_using_contract\",\n                True,\n                \"bool\",\n            )\n\n            # set tac negotiation configuration\n            self.set_config(\n                \"vendor.fetchai.skills.tac_negotiation.models.strategy.args.is_contract_tx\",\n                True,\n                \"bool\",\n            )\n\n            # replace location\n            setting_path = (\n                \"vendor.fetchai.skills.tac_participation.models.game.args.location\"\n            )\n            self.nested_set_config(setting_path, location)\n\n            # set tac id\n            data = {\n                \"search_key\": \"tac\",\n                \"search_value\": tac_id,\n                \"constraint_type\": \"==\",\n            }\n            setting_path = (\n                \"vendor.fetchai.skills.tac_participation.models.game.args.search_query\"\n            )\n            self.nested_set_config(setting_path, data)\n\n            diff = self.difference_to_fetched_agent(\n                \"fetchai/tac_participant_contract:0.22.5\", agent_name\n            )\n            assert (\n                diff == []\n            ), \"Difference between created and fetched project for files={}\".format(\n                diff\n            )\n\n            # use local test-net\n            setting_path = (\n                \"vendor.fetchai.connections.ledger.config.ledger_apis.fetchai.address\"\n            )\n            self.set_config(\n                setting_path,\n                f\"{DEFAULT_FETCH_LEDGER_ADDR}:{DEFAULT_FETCH_LEDGER_REST_PORT}\",\n            )\n            setting_path = (\n                \"vendor.fetchai.connections.ledger.config.ledger_apis.fetchai.denom\"\n            )\n            self.set_config(setting_path, DEFAULT_DENOMINATION)\n            setting_path = (\n                \"vendor.fetchai.connections.ledger.config.ledger_apis.fetchai.chain_id\"\n            )\n            self.set_config(setting_path, self.LOCAL_TESTNET_CHAIN_ID)\n\n            # change SOEF configuration to local\n            setting_path = \"vendor.fetchai.connections.soef.config.is_https\"\n            self.set_config(setting_path, False)\n            setting_path = \"vendor.fetchai.connections.soef.config.soef_addr\"\n            self.set_config(setting_path, \"127.0.0.1\")\n            setting_path = \"vendor.fetchai.connections.soef.config.soef_port\"\n            self.set_config(setting_path, 12002)\n\n            self.set_config(\n                \"vendor.fetchai.skills.tac_negotiation.models.strategy.args.service_key\",\n                tac_service,\n            )\n\n        # run tac controller\n        self.set_agent_context(tac_controller_name)\n        self.run_cli_command(\"build\", cwd=self._get_cwd())\n        self.run_cli_command(\"issue-certificates\", cwd=self._get_cwd())\n        now = datetime.datetime.now().strftime(\"%d %m %Y %H:%M\")\n        now_min = datetime.datetime.strptime(now, \"%d %m %Y %H:%M\")\n        fut = now_min + datetime.timedelta(\n            0, 120\n        )  # we provide 2 minutes time for contract deployment\n        start_time = fut.strftime(\"%d %m %Y %H:%M\")\n        setting_path = \"vendor.fetchai.skills.tac_control_contract.models.parameters.args.registration_start_time\"\n        self.set_config(setting_path, start_time)\n        tac_controller_process = self.run_agent()\n\n        check_strings = (\n            \"Starting libp2p node...\",\n            \"Connecting to libp2p node...\",\n            \"Successfully connected to libp2p node!\",\n            LIBP2P_SUCCESS_MESSAGE,\n            \"registering agent on SOEF.\",\n            \"requesting contract deployment transaction...\",\n            \"Start processing messages...\",\n            \"received raw transaction=\",\n            \"transaction signing was successful.\",\n            \"sending transaction to ledger.\",\n            \"transaction was successfully submitted. Transaction digest=\",\n            \"requesting transaction receipt.\",\n            \"transaction was successfully settled. Transaction receipt=\",\n            \"requesting contract initialisation transaction...\",\n            \"contract deployed.\",\n            \"registering TAC data model on SOEF.\",\n            \"TAC open for registration until:\",\n        )\n        missing_strings = self.missing_from_output(\n            tac_controller_process, check_strings, timeout=180, is_terminating=False\n        )  # we need to wait sufficiently long (at least 2 minutes - see above for deployment)\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in tac_controller output.\".format(missing_strings)\n\n        # run two agents (participants)\n        self.set_agent_context(tac_aea_one)\n        self.run_cli_command(\"build\", cwd=self._get_cwd())\n        self.run_cli_command(\"issue-certificates\", cwd=self._get_cwd())\n        tac_aea_one_process = self.run_agent()\n\n        self.set_agent_context(tac_aea_two)\n        self.run_cli_command(\"build\", cwd=self._get_cwd())\n        self.run_cli_command(\"issue-certificates\", cwd=self._get_cwd())\n        tac_aea_two_process = self.run_agent()\n\n        check_strings = (\n            \"Starting libp2p node...\",\n            \"Connecting to libp2p node...\",\n            \"Successfully connected to libp2p node!\",\n            LIBP2P_SUCCESS_MESSAGE,\n            \"Start processing messages...\",\n            \"searching for TAC, search_id=\",\n        )\n        missing_strings = self.missing_from_output(\n            tac_aea_one_process, check_strings, timeout=30, is_terminating=False\n        )\n        check_strings = (\"found the TAC controller. Registering...\",)\n        missing_strings = self.missing_from_output(\n            tac_aea_one_process, check_strings, timeout=60, is_terminating=False\n        )  # we need to wait sufficiently long (at least 1 minutes - for registration)\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in tac_aea_one output.\".format(missing_strings)\n\n        check_strings = (\n            \"Starting libp2p node...\",\n            \"Connecting to libp2p node...\",\n            \"Successfully connected to libp2p node!\",\n            LIBP2P_SUCCESS_MESSAGE,\n            \"Start processing messages...\",\n            \"searching for TAC, search_id=\",\n            \"found the TAC controller. Registering...\",\n        )\n        missing_strings = self.missing_from_output(\n            tac_aea_two_process, check_strings, timeout=30, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in tac_aea_two output.\".format(missing_strings)\n\n        check_strings = (\n            \"registered as 'tac_participant_one'\",\n            \"registered as 'tac_participant_two'\",\n            \"closing registration!\",\n            \"unregistering TAC data model from SOEF.\",\n            \"requesting create items transaction...\",\n            \"received raw transaction=\",\n            \"proposing the transaction to the decision maker. Waiting for confirmation ...\",\n            \"transaction signing was successful.\",\n            \"transaction was successfully submitted. Transaction digest=\",\n            \"requesting transaction receipt.\",\n            \"transaction was successfully settled. Transaction receipt=\",\n            \"tokens created.\",\n            \"requesting mint_items transactions for agent=\",\n            \"tokens minted.\",\n            \"requesting mint_items transactions for agent=\",\n            \"tokens minted.\",\n            \"all tokens minted.\",\n            \"started competition:\",\n        )\n        missing_strings = self.missing_from_output(\n            tac_controller_process, check_strings, timeout=240, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in tac_controller output.\".format(missing_strings)\n\n        check_strings = (\n            \"received start event from the controller. Starting to compete...\",\n            \"received a contract address:\",\n            \"registering agent on SOEF.\",\n            \"searching for sellers, search_id=\",\n            \"searching for buyers, search_id=\",\n            \"found potential sellers agents=\",\n            \"found potential buyers agents=\",\n            \"sending CFP to agent=\",\n            \"received cfp from\",\n            \"received propose from\",\n            \"received decline from\",\n            \"received accept from\",\n            \"received match_accept_w_inform from\",\n            \"sending propose to\",\n            \"sending accept to\",\n            \"sending match_accept_w_inform to\",\n            \"requesting batch atomic swap transaction, sending get_raw_transaction to fetchai/erc1155:0.23.3, message=\",\n            \"received raw transaction=\",\n            \"proposing the transaction to the decision maker. Waiting for confirmation ...\",\n            \"received signed_transaction from decision_maker, message=\",\n            \"sending inform_signed_transaction to\",\n            \"received inform_signed_transaction from\",\n            \"sending send_signed_transaction to ledger fetchai, message=\",\n            \"transaction was successfully submitted. Transaction digest=\",\n            \"transaction was successfully settled. Transaction receipt=\",\n        )\n        missing_strings = self.missing_from_output(\n            tac_aea_one_process, check_strings, timeout=300, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in tac_aea_one output.\".format(missing_strings)\n\n        check_strings = (\n            \"received start event from the controller. Starting to compete...\",\n            \"received a contract address:\",\n            \"registering agent on SOEF.\",\n            \"searching for sellers, search_id=\",\n            \"searching for buyers, search_id=\",\n            \"found potential sellers agents=\",\n            \"found potential buyers agents=\",\n            \"sending CFP to agent=\",\n            \"received cfp from\",\n            \"received propose from\",\n            \"received decline from\",\n            \"received accept from\",\n            \"received match_accept_w_inform from\",\n            \"sending propose to\",\n            \"sending accept to\",\n            \"sending match_accept_w_inform to\",\n            \"requesting batch atomic swap transaction, sending get_raw_transaction to fetchai/erc1155:0.23.3, message=\",\n            \"received raw transaction=\",\n            \"proposing the transaction to the decision maker. Waiting for confirmation ...\",\n            \"received signed_transaction from decision_maker, message=\",\n            \"sending inform_signed_transaction to\",\n            \"received inform_signed_transaction from\",\n            \"sending send_signed_transaction to ledger fetchai, message=\",\n            \"transaction was successfully submitted. Transaction digest=\",\n            \"transaction was successfully settled. Transaction receipt=\",\n        )\n        missing_strings = self.missing_from_output(\n            tac_aea_two_process, check_strings, timeout=360, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in tac_aea_two output.\".format(missing_strings)\n\n        # Note, we do not need to check std output of the other participant as it is implied\n\n        self.terminate_agents(\n            tac_controller_process, tac_aea_one_process, tac_aea_two_process\n        )\n        assert (\n            self.is_successfully_terminated()\n        ), \"Agents weren't successfully terminated.\"\n"
  },
  {
    "path": "tests/test_packages/test_skills_integration/test_thermometer.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This test module contains the integration test for the thermometer skills.\"\"\"\n\nfrom random import uniform\n\nimport pytest\nfrom aea_ledger_fetchai import FetchAICrypto\n\nfrom aea.test_tools.test_cases import AEATestCaseManyFlaky\n\nfrom packages.fetchai.connections.p2p_libp2p.connection import LIBP2P_SUCCESS_MESSAGE\n\nfrom tests.conftest import (\n    FETCHAI_PRIVATE_KEY_FILE,\n    FETCHAI_PRIVATE_KEY_FILE_CONNECTION,\n    MAX_FLAKY_RERUNS_INTEGRATION,\n    NON_FUNDED_FETCHAI_PRIVATE_KEY_1,\n    NON_GENESIS_CONFIG,\n    wait_for_localhost_ports_to_close,\n)\n\n\n@pytest.mark.integration\nclass TestThermometerSkill(AEATestCaseManyFlaky):\n    \"\"\"Test that thermometer skills work.\"\"\"\n\n    @pytest.mark.flaky(\n        reruns=MAX_FLAKY_RERUNS_INTEGRATION\n    )  # cause possible network issues\n    def test_thermometer(self):\n        \"\"\"Run the thermometer skills sequence.\"\"\"\n\n        thermometer_aea_name = \"my_thermometer\"\n        thermometer_client_aea_name = \"my_thermometer_client\"\n        self.create_agents(thermometer_aea_name, thermometer_client_aea_name)\n\n        default_routing = {\n            \"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n            \"fetchai/oef_search:1.1.7\": \"fetchai/soef:0.27.6\",\n        }\n\n        # generate random location\n        location = {\n            \"latitude\": round(uniform(-90, 90), 2),  # nosec\n            \"longitude\": round(uniform(-180, 180), 2),  # nosec\n        }\n\n        # add packages for agent one and run it\n        self.set_agent_context(thermometer_aea_name)\n        self.add_item(\"connection\", \"fetchai/p2p_libp2p:0.27.5\")\n        self.add_item(\"connection\", \"fetchai/soef:0.27.6\")\n        self.set_config(\n            \"agent.dependencies\",\n            '{\\\n            \"aea-ledger-fetchai\": {\"version\": \"<2.0.0,>=1.0.0\"}\\\n        }',\n            type_=\"dict\",\n        )\n        self.set_config(\"agent.default_connection\", \"fetchai/p2p_libp2p:0.27.5\")\n        self.add_item(\"connection\", \"fetchai/ledger:0.21.5\")\n        self.add_item(\"skill\", \"fetchai/thermometer:0.27.6\")\n        setting_path = (\n            \"vendor.fetchai.skills.thermometer.models.strategy.args.is_ledger_tx\"\n        )\n        self.set_config(setting_path, False, \"bool\")\n        setting_path = \"agent.default_routing\"\n        self.nested_set_config(setting_path, default_routing)\n        self.run_install()\n\n        # add keys\n        self.generate_private_key(FetchAICrypto.identifier)\n        self.generate_private_key(\n            FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE_CONNECTION\n        )\n        self.add_private_key(FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE)\n        self.add_private_key(\n            FetchAICrypto.identifier,\n            FETCHAI_PRIVATE_KEY_FILE_CONNECTION,\n            connection=True,\n        )\n        self.replace_private_key_in_file(\n            NON_FUNDED_FETCHAI_PRIVATE_KEY_1, FETCHAI_PRIVATE_KEY_FILE_CONNECTION\n        )\n        setting_path = \"vendor.fetchai.connections.p2p_libp2p.config.ledger_id\"\n        self.set_config(setting_path, FetchAICrypto.identifier)\n\n        # replace location\n        setting_path = \"vendor.fetchai.skills.thermometer.models.strategy.args.location\"\n        self.nested_set_config(setting_path, location)\n\n        # add packages for agent two and run it\n        self.set_agent_context(thermometer_client_aea_name)\n        self.add_item(\"connection\", \"fetchai/p2p_libp2p:0.27.5\")\n        self.add_item(\"connection\", \"fetchai/soef:0.27.6\")\n        self.set_config(\n            \"agent.dependencies\",\n            '{\\\n            \"aea-ledger-fetchai\": {\"version\": \"<2.0.0,>=1.0.0\"}\\\n        }',\n            type_=\"dict\",\n        )\n        self.set_config(\"agent.default_connection\", \"fetchai/p2p_libp2p:0.27.5\")\n        self.add_item(\"connection\", \"fetchai/ledger:0.21.5\")\n        self.add_item(\"skill\", \"fetchai/thermometer_client:0.26.6\")\n        setting_path = (\n            \"vendor.fetchai.skills.thermometer_client.models.strategy.args.is_ledger_tx\"\n        )\n        self.set_config(setting_path, False, \"bool\")\n        setting_path = \"agent.default_routing\"\n        self.nested_set_config(setting_path, default_routing)\n        self.run_install()\n\n        # add keys\n        self.generate_private_key(FetchAICrypto.identifier)\n        self.generate_private_key(\n            FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE_CONNECTION\n        )\n        self.add_private_key(FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE)\n        self.add_private_key(\n            FetchAICrypto.identifier,\n            FETCHAI_PRIVATE_KEY_FILE_CONNECTION,\n            connection=True,\n        )\n\n        # set p2p configs\n        setting_path = \"vendor.fetchai.connections.p2p_libp2p.config\"\n        self.nested_set_config(setting_path, NON_GENESIS_CONFIG)\n\n        # replace location\n        setting_path = (\n            \"vendor.fetchai.skills.thermometer_client.models.strategy.args.location\"\n        )\n        self.nested_set_config(setting_path, location)\n\n        # run AEAs\n        self.set_agent_context(thermometer_aea_name)\n        self.run_cli_command(\"build\", cwd=self._get_cwd())\n        self.run_cli_command(\"issue-certificates\", cwd=self._get_cwd())\n        thermometer_aea_process = self.run_agent()\n\n        check_strings = (\n            \"Starting libp2p node...\",\n            \"Connecting to libp2p node...\",\n            \"Successfully connected to libp2p node!\",\n            LIBP2P_SUCCESS_MESSAGE,\n        )\n        missing_strings = self.missing_from_output(\n            thermometer_aea_process, check_strings, timeout=30, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in thermometer_aea output.\".format(missing_strings)\n\n        self.set_agent_context(thermometer_client_aea_name)\n        self.run_cli_command(\"build\", cwd=self._get_cwd())\n        self.run_cli_command(\"issue-certificates\", cwd=self._get_cwd())\n        thermometer_client_aea_process = self.run_agent()\n\n        check_strings = (\n            \"Starting libp2p node...\",\n            \"Connecting to libp2p node...\",\n            \"Successfully connected to libp2p node!\",\n            LIBP2P_SUCCESS_MESSAGE,\n        )\n        missing_strings = self.missing_from_output(\n            thermometer_client_aea_process,\n            check_strings,\n            timeout=240,\n            is_terminating=False,\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in thermometer_client_aea output.\".format(\n            missing_strings\n        )\n\n        check_strings = (\n            \"registering agent on SOEF.\",\n            \"registering agent's service on the SOEF.\",\n            \"registering agent's personality genus on the SOEF.\",\n            \"registering agent's personality classification on the SOEF.\",\n            \"received CFP from sender=\",\n            \"sending a PROPOSE with proposal=\",\n            \"received ACCEPT from sender=\",\n            \"sending MATCH_ACCEPT_W_INFORM to sender=\",\n            \"received INFORM from sender=\",\n            \"transaction confirmed, sending data=\",\n        )\n        missing_strings = self.missing_from_output(\n            thermometer_aea_process, check_strings, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in thermometer_aea output.\".format(missing_strings)\n\n        check_strings = (\n            \"found agents=\",\n            \"sending CFP to agent=\",\n            \"received proposal=\",\n            \"accepting the proposal from sender=\",\n            \"informing counterparty=\",\n            \"received INFORM from sender=\",\n            \"received the following data=\",\n        )\n        missing_strings = self.missing_from_output(\n            thermometer_client_aea_process, check_strings, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in thermometer_client_aea output.\".format(\n            missing_strings\n        )\n\n        self.terminate_agents(thermometer_aea_process, thermometer_client_aea_process)\n        assert (\n            self.is_successfully_terminated()\n        ), \"Agents weren't successfully terminated.\"\n        wait_for_localhost_ports_to_close([9000, 9001])\n\n\n@pytest.mark.integration\nclass TestThermometerSkillFetchaiLedger(AEATestCaseManyFlaky):\n    \"\"\"Test that thermometer skills work.\"\"\"\n\n    @pytest.mark.flaky(\n        reruns=MAX_FLAKY_RERUNS_INTEGRATION\n    )  # cause possible network issues\n    def test_thermometer(self):\n        \"\"\"Run the thermometer skills sequence.\"\"\"\n\n        thermometer_aea_name = \"my_thermometer\"\n        thermometer_client_aea_name = \"my_thermometer_client\"\n        self.create_agents(thermometer_aea_name, thermometer_client_aea_name)\n\n        default_routing = {\n            \"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n            \"fetchai/oef_search:1.1.7\": \"fetchai/soef:0.27.6\",\n        }\n\n        # generate random location\n        location = {\n            \"latitude\": round(uniform(-90, 90), 2),  # nosec\n            \"longitude\": round(uniform(-180, 180), 2),  # nosec\n        }\n\n        # add packages for agent one and run it\n        self.set_agent_context(thermometer_aea_name)\n        self.add_item(\"connection\", \"fetchai/p2p_libp2p:0.27.5\")\n        self.add_item(\"connection\", \"fetchai/soef:0.27.6\")\n        self.set_config(\n            \"agent.dependencies\",\n            '{\\\n            \"aea-ledger-fetchai\": {\"version\": \"<2.0.0,>=1.0.0\"}\\\n        }',\n            type_=\"dict\",\n        )\n        self.set_config(\"agent.default_connection\", \"fetchai/p2p_libp2p:0.27.5\")\n        self.add_item(\"connection\", \"fetchai/ledger:0.21.5\")\n        self.add_item(\"skill\", \"fetchai/thermometer:0.27.6\")\n        setting_path = \"agent.default_routing\"\n        self.nested_set_config(setting_path, default_routing)\n        self.run_install()\n\n        diff = self.difference_to_fetched_agent(\n            \"fetchai/thermometer_aea:0.30.5\", thermometer_aea_name\n        )\n        assert (\n            diff == []\n        ), \"Difference between created and fetched project for files={}\".format(diff)\n\n        # add keys\n        self.generate_private_key(FetchAICrypto.identifier)\n        self.generate_private_key(\n            FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE_CONNECTION\n        )\n        self.add_private_key(FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE)\n        self.add_private_key(\n            FetchAICrypto.identifier,\n            FETCHAI_PRIVATE_KEY_FILE_CONNECTION,\n            connection=True,\n        )\n        self.replace_private_key_in_file(\n            NON_FUNDED_FETCHAI_PRIVATE_KEY_1, FETCHAI_PRIVATE_KEY_FILE_CONNECTION\n        )\n        setting_path = \"vendor.fetchai.connections.p2p_libp2p.config.ledger_id\"\n        self.set_config(setting_path, FetchAICrypto.identifier)\n\n        # replace location\n        setting_path = \"vendor.fetchai.skills.thermometer.models.strategy.args.location\"\n        self.nested_set_config(setting_path, location)\n\n        # add packages for agent two and run it\n        self.set_agent_context(thermometer_client_aea_name)\n        self.add_item(\"connection\", \"fetchai/p2p_libp2p:0.27.5\")\n        self.add_item(\"connection\", \"fetchai/soef:0.27.6\")\n        self.set_config(\n            \"agent.dependencies\",\n            '{\\\n            \"aea-ledger-fetchai\": {\"version\": \"<2.0.0,>=1.0.0\"}\\\n        }',\n            type_=\"dict\",\n        )\n        self.set_config(\"agent.default_connection\", \"fetchai/p2p_libp2p:0.27.5\")\n        self.add_item(\"connection\", \"fetchai/ledger:0.21.5\")\n        self.add_item(\"skill\", \"fetchai/thermometer_client:0.26.6\")\n        setting_path = \"agent.default_routing\"\n        self.nested_set_config(setting_path, default_routing)\n        self.run_install()\n\n        diff = self.difference_to_fetched_agent(\n            \"fetchai/thermometer_client:0.32.5\", thermometer_client_aea_name\n        )\n        assert (\n            diff == []\n        ), \"Difference between created and fetched project for files={}\".format(diff)\n\n        # add keys\n        self.generate_private_key(FetchAICrypto.identifier)\n        self.generate_private_key(\n            FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE_CONNECTION\n        )\n        self.add_private_key(FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE)\n        self.add_private_key(\n            FetchAICrypto.identifier,\n            FETCHAI_PRIVATE_KEY_FILE_CONNECTION,\n            connection=True,\n        )\n\n        # fund key\n        self.generate_wealth(FetchAICrypto.identifier)\n\n        # set p2p configs\n        setting_path = \"vendor.fetchai.connections.p2p_libp2p.config\"\n        self.nested_set_config(setting_path, NON_GENESIS_CONFIG)\n\n        # replace location\n        setting_path = (\n            \"vendor.fetchai.skills.thermometer_client.models.strategy.args.location\"\n        )\n        self.nested_set_config(setting_path, location)\n\n        # run AEAs\n        self.set_agent_context(thermometer_aea_name)\n        self.run_cli_command(\"build\", cwd=self._get_cwd())\n        self.run_cli_command(\"issue-certificates\", cwd=self._get_cwd())\n        thermometer_aea_process = self.run_agent()\n\n        check_strings = (\n            \"Starting libp2p node...\",\n            \"Connecting to libp2p node...\",\n            \"Successfully connected to libp2p node!\",\n            LIBP2P_SUCCESS_MESSAGE,\n        )\n        missing_strings = self.missing_from_output(\n            thermometer_aea_process, check_strings, timeout=30, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in thermometer_aea output.\".format(missing_strings)\n\n        self.set_agent_context(thermometer_client_aea_name)\n        self.run_cli_command(\"build\", cwd=self._get_cwd())\n        self.run_cli_command(\"issue-certificates\", cwd=self._get_cwd())\n        thermometer_client_aea_process = self.run_agent()\n\n        check_strings = (\n            \"Starting libp2p node...\",\n            \"Connecting to libp2p node...\",\n            \"Successfully connected to libp2p node!\",\n            LIBP2P_SUCCESS_MESSAGE,\n        )\n        missing_strings = self.missing_from_output(\n            thermometer_client_aea_process,\n            check_strings,\n            timeout=30,\n            is_terminating=False,\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in thermometer_client_aea output.\".format(\n            missing_strings\n        )\n\n        check_strings = (\n            \"registering agent on SOEF.\",\n            \"registering agent's service on the SOEF.\",\n            \"registering agent's personality genus on the SOEF.\",\n            \"registering agent's personality classification on the SOEF.\",\n            \"received CFP from sender=\",\n            \"sending a PROPOSE with proposal=\",\n            \"received ACCEPT from sender=\",\n            \"sending MATCH_ACCEPT_W_INFORM to sender=\",\n            \"received INFORM from sender=\",\n            \"checking whether transaction=\",\n            \"transaction confirmed, sending data=\",\n        )\n        missing_strings = self.missing_from_output(\n            thermometer_aea_process, check_strings, timeout=240, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in thermometer_aea output.\".format(missing_strings)\n\n        check_strings = (\n            \"found agents=\",\n            \"sending CFP to agent=\",\n            \"received proposal=\",\n            \"accepting the proposal from sender=\",\n            \"received MATCH_ACCEPT_W_INFORM from sender=\",\n            \"requesting transfer transaction from ledger api for message=\",\n            \"received raw transaction=\",\n            \"proposing the transaction to the decision maker. Waiting for confirmation ...\",\n            \"transaction signing was successful.\",\n            \"sending transaction to ledger.\",\n            \"transaction was successfully submitted. Transaction digest=\",\n            \"informing counterparty=\",\n            \"received INFORM from sender=\",\n            \"received the following data=\",\n        )\n        missing_strings = self.missing_from_output(\n            thermometer_client_aea_process, check_strings, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in thermometer_client_aea output.\".format(\n            missing_strings\n        )\n\n        self.terminate_agents(thermometer_aea_process, thermometer_client_aea_process)\n        assert (\n            self.is_successfully_terminated()\n        ), \"Agents weren't successfully terminated.\"\n        wait_for_localhost_ports_to_close([9000, 9001])\n"
  },
  {
    "path": "tests/test_packages/test_skills_integration/test_weather.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This test module contains the integration test for the weather skills.\"\"\"\n\nfrom random import uniform\n\nimport pytest\nfrom aea_ledger_fetchai import FetchAICrypto\n\nfrom aea.test_tools.test_cases import AEATestCaseManyFlaky\n\nfrom packages.fetchai.connections.p2p_libp2p.connection import LIBP2P_SUCCESS_MESSAGE\n\nfrom tests.conftest import (\n    FETCHAI_PRIVATE_KEY_FILE,\n    FETCHAI_PRIVATE_KEY_FILE_CONNECTION,\n    MAX_FLAKY_RERUNS_INTEGRATION,\n    NON_FUNDED_FETCHAI_PRIVATE_KEY_1,\n    NON_GENESIS_CONFIG,\n    wait_for_localhost_ports_to_close,\n)\n\n\n@pytest.mark.integration\nclass TestWeatherSkills(AEATestCaseManyFlaky):\n    \"\"\"Test that weather skills work.\"\"\"\n\n    @pytest.mark.flaky(\n        reruns=MAX_FLAKY_RERUNS_INTEGRATION\n    )  # cause possible network issues\n    def test_weather(self):\n        \"\"\"Run the weather skills sequence.\"\"\"\n        weather_station_aea_name = \"my_weather_station\"\n        weather_client_aea_name = \"my_weather_client\"\n        self.create_agents(weather_station_aea_name, weather_client_aea_name)\n\n        default_routing = {\n            \"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n            \"fetchai/oef_search:1.1.7\": \"fetchai/soef:0.27.6\",\n        }\n\n        # generate random location\n        location = {\n            \"latitude\": round(uniform(-90, 90), 2),  # nosec\n            \"longitude\": round(uniform(-180, 180), 2),  # nosec\n        }\n\n        # prepare agent one (weather station)\n        self.set_agent_context(weather_station_aea_name)\n        self.add_item(\"connection\", \"fetchai/p2p_libp2p:0.27.5\")\n        self.add_item(\"connection\", \"fetchai/soef:0.27.6\")\n        self.set_config(\n            \"agent.dependencies\",\n            '{\\\n            \"aea-ledger-fetchai\": {\"version\": \"<2.0.0,>=1.0.0\"}\\\n        }',\n            type_=\"dict\",\n        )\n        self.set_config(\"agent.default_connection\", \"fetchai/p2p_libp2p:0.27.5\")\n        self.add_item(\"connection\", \"fetchai/ledger:0.21.5\")\n        self.add_item(\"skill\", \"fetchai/weather_station:0.27.6\")\n        dotted_path = (\n            \"vendor.fetchai.skills.weather_station.models.strategy.args.is_ledger_tx\"\n        )\n        self.set_config(dotted_path, False, \"bool\")\n        setting_path = \"agent.default_routing\"\n        self.nested_set_config(setting_path, default_routing)\n        self.run_install()\n\n        # add keys\n        self.generate_private_key(FetchAICrypto.identifier)\n        self.generate_private_key(\n            FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE_CONNECTION\n        )\n        self.add_private_key(FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE)\n        self.add_private_key(\n            FetchAICrypto.identifier,\n            FETCHAI_PRIVATE_KEY_FILE_CONNECTION,\n            connection=True,\n        )\n        self.replace_private_key_in_file(\n            NON_FUNDED_FETCHAI_PRIVATE_KEY_1, FETCHAI_PRIVATE_KEY_FILE_CONNECTION\n        )\n        setting_path = \"vendor.fetchai.connections.p2p_libp2p.config.ledger_id\"\n        self.set_config(setting_path, FetchAICrypto.identifier)\n\n        # replace location\n        setting_path = (\n            \"vendor.fetchai.skills.weather_station.models.strategy.args.location\"\n        )\n        self.nested_set_config(setting_path, location)\n\n        # prepare agent two (weather client)\n        self.set_agent_context(weather_client_aea_name)\n        self.add_item(\"connection\", \"fetchai/p2p_libp2p:0.27.5\")\n        self.add_item(\"connection\", \"fetchai/soef:0.27.6\")\n        self.set_config(\n            \"agent.dependencies\",\n            '{\\\n            \"aea-ledger-fetchai\": {\"version\": \"<2.0.0,>=1.0.0\"}\\\n        }',\n            type_=\"dict\",\n        )\n        self.set_config(\"agent.default_connection\", \"fetchai/p2p_libp2p:0.27.5\")\n        self.add_item(\"connection\", \"fetchai/ledger:0.21.5\")\n        self.add_item(\"skill\", \"fetchai/weather_client:0.26.6\")\n        self.set_config(\"agent.default_connection\", \"fetchai/p2p_libp2p:0.27.5\")\n        dotted_path = (\n            \"vendor.fetchai.skills.weather_client.models.strategy.args.is_ledger_tx\"\n        )\n        self.set_config(dotted_path, False, \"bool\")\n        setting_path = \"agent.default_routing\"\n        self.nested_set_config(setting_path, default_routing)\n        self.run_install()\n\n        # add keys\n        self.generate_private_key(FetchAICrypto.identifier)\n        self.generate_private_key(\n            FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE_CONNECTION\n        )\n        self.add_private_key(FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE)\n        self.add_private_key(\n            FetchAICrypto.identifier,\n            FETCHAI_PRIVATE_KEY_FILE_CONNECTION,\n            connection=True,\n        )\n\n        # set p2p configs\n        setting_path = \"vendor.fetchai.connections.p2p_libp2p.config\"\n        self.nested_set_config(setting_path, NON_GENESIS_CONFIG)\n\n        # replace location\n        setting_path = (\n            \"vendor.fetchai.skills.weather_client.models.strategy.args.location\"\n        )\n        self.nested_set_config(setting_path, location)\n\n        # run agents\n        self.set_agent_context(weather_station_aea_name)\n        self.run_cli_command(\"build\", cwd=self._get_cwd())\n        self.run_cli_command(\"issue-certificates\", cwd=self._get_cwd())\n        weather_station_process = self.run_agent()\n\n        check_strings = (\n            \"Starting libp2p node...\",\n            \"Connecting to libp2p node...\",\n            \"Successfully connected to libp2p node!\",\n            LIBP2P_SUCCESS_MESSAGE,\n        )\n        missing_strings = self.missing_from_output(\n            weather_station_process, check_strings, timeout=30, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in weather_station output.\".format(missing_strings)\n\n        self.set_agent_context(weather_client_aea_name)\n        self.run_cli_command(\"build\", cwd=self._get_cwd())\n        self.run_cli_command(\"issue-certificates\", cwd=self._get_cwd())\n        weather_client_process = self.run_agent()\n\n        check_strings = (\n            \"Starting libp2p node...\",\n            \"Connecting to libp2p node...\",\n            \"Successfully connected to libp2p node!\",\n            LIBP2P_SUCCESS_MESSAGE,\n        )\n        missing_strings = self.missing_from_output(\n            weather_client_process,\n            check_strings,\n            timeout=30,\n            is_terminating=False,\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in weather_client output.\".format(missing_strings)\n\n        check_strings = (\n            \"registering agent on SOEF.\",\n            \"registering agent's service on the SOEF.\",\n            \"registering agent's personality genus on the SOEF.\",\n            \"registering agent's personality classification on the SOEF.\",\n            \"received CFP from sender=\",\n            \"sending a PROPOSE with proposal=\",\n            \"received ACCEPT from sender=\",\n            \"sending MATCH_ACCEPT_W_INFORM to sender=\",\n            \"received INFORM from sender=\",\n            \"transaction confirmed, sending data=\",\n        )\n        missing_strings = self.missing_from_output(\n            weather_station_process, check_strings, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in weather_station output.\".format(missing_strings)\n\n        check_strings = (\n            \"found agents=\",\n            \"sending CFP to agent=\",\n            \"received proposal=\",\n            \"accepting the proposal from sender=\",\n            \"informing counterparty=\",\n            \"received INFORM from sender=\",\n            \"received the following data=\",\n        )\n        missing_strings = self.missing_from_output(\n            weather_client_process, check_strings, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in weather_client output.\".format(missing_strings)\n\n        self.terminate_agents(weather_station_process, weather_client_process)\n        assert (\n            self.is_successfully_terminated()\n        ), \"Agents weren't successfully terminated.\"\n        wait_for_localhost_ports_to_close([9000, 9001])\n\n\n@pytest.mark.integration\nclass TestWeatherSkillsFetchaiLedger(AEATestCaseManyFlaky):\n    \"\"\"Test that weather skills work.\"\"\"\n\n    @pytest.mark.flaky(\n        reruns=MAX_FLAKY_RERUNS_INTEGRATION\n    )  # cause possible network issues\n    def test_weather(self):\n        \"\"\"Run the weather skills sequence.\"\"\"\n        weather_station_aea_name = \"my_weather_station\"\n        weather_client_aea_name = \"my_weather_client\"\n        self.create_agents(weather_station_aea_name, weather_client_aea_name)\n\n        default_routing = {\n            \"fetchai/ledger_api:1.1.7\": \"fetchai/ledger:0.21.5\",\n            \"fetchai/oef_search:1.1.7\": \"fetchai/soef:0.27.6\",\n        }\n\n        # generate random location\n        location = {\n            \"latitude\": round(uniform(-90, 90), 2),  # nosec\n            \"longitude\": round(uniform(-180, 180), 2),  # nosec\n        }\n\n        # add packages for agent one\n        self.set_agent_context(weather_station_aea_name)\n        self.add_item(\"connection\", \"fetchai/p2p_libp2p:0.27.5\")\n        self.add_item(\"connection\", \"fetchai/soef:0.27.6\")\n        self.set_config(\n            \"agent.dependencies\",\n            '{\\\n            \"aea-ledger-fetchai\": {\"version\": \"<2.0.0,>=1.0.0\"}\\\n        }',\n            type_=\"dict\",\n        )\n        self.set_config(\"agent.default_connection\", \"fetchai/p2p_libp2p:0.27.5\")\n        self.add_item(\"connection\", \"fetchai/ledger:0.21.5\")\n        self.add_item(\"skill\", \"fetchai/weather_station:0.27.6\")\n        setting_path = \"agent.default_routing\"\n        self.nested_set_config(setting_path, default_routing)\n        self.run_install()\n\n        diff = self.difference_to_fetched_agent(\n            \"fetchai/weather_station:0.32.5\", weather_station_aea_name\n        )\n        assert (\n            diff == []\n        ), \"Difference between created and fetched project for files={}\".format(diff)\n\n        # add keys\n        self.generate_private_key(FetchAICrypto.identifier)\n        self.generate_private_key(\n            FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE_CONNECTION\n        )\n        self.add_private_key(FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE)\n        self.add_private_key(\n            FetchAICrypto.identifier,\n            FETCHAI_PRIVATE_KEY_FILE_CONNECTION,\n            connection=True,\n        )\n        self.replace_private_key_in_file(\n            NON_FUNDED_FETCHAI_PRIVATE_KEY_1, FETCHAI_PRIVATE_KEY_FILE_CONNECTION\n        )\n        setting_path = \"vendor.fetchai.connections.p2p_libp2p.config.ledger_id\"\n        self.set_config(setting_path, FetchAICrypto.identifier)\n\n        # replace location\n        setting_path = (\n            \"vendor.fetchai.skills.weather_station.models.strategy.args.location\"\n        )\n        self.nested_set_config(setting_path, location)\n\n        # add packages for agent two\n        self.set_agent_context(weather_client_aea_name)\n        self.add_item(\"connection\", \"fetchai/p2p_libp2p:0.27.5\")\n        self.add_item(\"connection\", \"fetchai/soef:0.27.6\")\n        self.set_config(\n            \"agent.dependencies\",\n            '{\\\n            \"aea-ledger-fetchai\": {\"version\": \"<2.0.0,>=1.0.0\"}\\\n        }',\n            type_=\"dict\",\n        )\n        self.set_config(\"agent.default_connection\", \"fetchai/p2p_libp2p:0.27.5\")\n        self.add_item(\"connection\", \"fetchai/ledger:0.21.5\")\n        self.add_item(\"skill\", \"fetchai/weather_client:0.26.6\")\n        setting_path = \"agent.default_routing\"\n        self.nested_set_config(setting_path, default_routing)\n        self.run_install()\n\n        diff = self.difference_to_fetched_agent(\n            \"fetchai/weather_client:0.33.5\", weather_client_aea_name\n        )\n        assert (\n            diff == []\n        ), \"Difference between created and fetched project for files={}\".format(diff)\n\n        # add keys\n        self.generate_private_key(FetchAICrypto.identifier)\n        self.generate_private_key(\n            FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE_CONNECTION\n        )\n        self.add_private_key(FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE)\n        self.add_private_key(\n            FetchAICrypto.identifier,\n            FETCHAI_PRIVATE_KEY_FILE_CONNECTION,\n            connection=True,\n        )\n\n        # fund key\n        self.generate_wealth(FetchAICrypto.identifier)\n\n        # set p2p configs\n        setting_path = \"vendor.fetchai.connections.p2p_libp2p.config\"\n        self.nested_set_config(setting_path, NON_GENESIS_CONFIG)\n\n        # replace location\n        setting_path = (\n            \"vendor.fetchai.skills.weather_client.models.strategy.args.location\"\n        )\n        self.nested_set_config(setting_path, location)\n\n        self.set_agent_context(weather_station_aea_name)\n        self.run_cli_command(\"build\", cwd=self._get_cwd())\n        self.run_cli_command(\"issue-certificates\", cwd=self._get_cwd())\n        weather_station_process = self.run_agent()\n\n        check_strings = (\n            \"Starting libp2p node...\",\n            \"Connecting to libp2p node...\",\n            \"Successfully connected to libp2p node!\",\n            LIBP2P_SUCCESS_MESSAGE,\n        )\n        missing_strings = self.missing_from_output(\n            weather_station_process, check_strings, timeout=30, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in weather_station output.\".format(missing_strings)\n\n        self.set_agent_context(weather_client_aea_name)\n        self.run_cli_command(\"build\", cwd=self._get_cwd())\n        self.run_cli_command(\"issue-certificates\", cwd=self._get_cwd())\n        weather_client_process = self.run_agent()\n\n        check_strings = (\n            \"Starting libp2p node...\",\n            \"Connecting to libp2p node...\",\n            \"Successfully connected to libp2p node!\",\n            LIBP2P_SUCCESS_MESSAGE,\n        )\n        missing_strings = self.missing_from_output(\n            weather_client_process,\n            check_strings,\n            timeout=30,\n            is_terminating=False,\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in weather_client output.\".format(missing_strings)\n\n        check_strings = (\n            \"registering agent on SOEF.\",\n            \"registering agent's service on the SOEF.\",\n            \"registering agent's personality genus on the SOEF.\",\n            \"registering agent's personality classification on the SOEF.\",\n            \"received CFP from sender=\",\n            \"sending a PROPOSE with proposal=\",\n            \"received ACCEPT from sender=\",\n            \"sending MATCH_ACCEPT_W_INFORM to sender=\",\n            \"received INFORM from sender=\",\n            \"checking whether transaction=\",\n            \"transaction confirmed, sending data=\",\n        )\n        missing_strings = self.missing_from_output(\n            weather_station_process, check_strings, timeout=120, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in weather_station output.\".format(missing_strings)\n\n        check_strings = (\n            \"found agents=\",\n            \"sending CFP to agent=\",\n            \"received proposal=\",\n            \"accepting the proposal from sender=\",\n            \"received MATCH_ACCEPT_W_INFORM from sender=\",\n            \"requesting transfer transaction from ledger api for message=\",\n            \"received raw transaction=\",\n            \"proposing the transaction to the decision maker. Waiting for confirmation ...\",\n            \"transaction signing was successful.\",\n            \"sending transaction to ledger.\",\n            \"transaction was successfully submitted. Transaction digest=\",\n            \"informing counterparty=\",\n            \"received INFORM from sender=\",\n            \"received the following data=\",\n        )\n        missing_strings = self.missing_from_output(\n            weather_client_process, check_strings, is_terminating=False\n        )\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in weather_client output.\".format(missing_strings)\n\n        self.terminate_agents(weather_station_process, weather_client_process)\n        assert (\n            self.is_successfully_terminated()\n        ), \"Agents weren't successfully terminated.\"\n        wait_for_localhost_ports_to_close([9000, 9001])\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"The tests module contains the tests for packages  required for AEA tests to run.\"\"\"\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_connections/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"The tests module contains the tests of the packages/contracts dir.\"\"\"\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_connections/test_gym/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests of the gym connection implementation.\"\"\"\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_connections/test_gym/test_gym.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the gym connection module.\"\"\"\nimport asyncio\nimport logging\nimport os\nfrom typing import cast\nfrom unittest.mock import MagicMock, patch\n\nimport gym\nimport pytest\n\nfrom aea.common import Address\nfrom aea.configurations.base import ConnectionConfig\nfrom aea.identity.base import Identity\nfrom aea.mail.base import Envelope, Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\n\nfrom packages.fetchai.connections.gym.connection import GymConnection\nfrom packages.fetchai.protocols.gym.dialogues import GymDialogue\nfrom packages.fetchai.protocols.gym.dialogues import GymDialogues as BaseGymDialogues\nfrom packages.fetchai.protocols.gym.message import GymMessage\n\nfrom tests.conftest import ROOT_DIR, UNKNOWN_PROTOCOL_PUBLIC_ID\n\n\nlogger = logging.getLogger(__name__)\n\n\nclass GymDialogues(BaseGymDialogues):\n    \"\"\"The dialogues class keeps track of all gym dialogues.\"\"\"\n\n    def __init__(self, self_address: Address, **kwargs) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :return: None\n        \"\"\"\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return GymDialogue.Role.AGENT\n\n        BaseGymDialogues.__init__(\n            self,\n            self_address=self_address,\n            role_from_first_message=role_from_first_message,\n        )\n\n\nclass TestGymConnection:\n    \"\"\"Test the packages/connection/gym/connection.py.\"\"\"\n\n    def setup(self):\n        \"\"\"Initialise the class.\"\"\"\n        self.env = gym.GoalEnv()\n        configuration = ConnectionConfig(connection_id=GymConnection.connection_id)\n        self.agent_address = \"my_address\"\n        self.agent_public_key = \"my_public_key\"\n        identity = Identity(\n            \"name\", address=self.agent_address, public_key=self.agent_public_key\n        )\n        self.gym_con = GymConnection(\n            gym_env=self.env,\n            identity=identity,\n            configuration=configuration,\n            data_dir=MagicMock(),\n        )\n        self.loop = asyncio.get_event_loop()\n        self.gym_address = str(GymConnection.connection_id)\n        self.skill_id = \"some/skill:0.1.0\"\n        self.dialogues = GymDialogues(self.skill_id)\n\n    def teardown(self):\n        \"\"\"Clean up after tests.\"\"\"\n        self.loop.run_until_complete(self.gym_con.disconnect())\n\n    @pytest.mark.asyncio\n    async def test_gym_connection_connect(self):\n        \"\"\"Test the connection None return value after connect().\"\"\"\n        assert self.gym_con.channel._queue is None\n        await self.gym_con.channel.connect()\n        assert self.gym_con.channel._queue is not None\n\n    @pytest.mark.asyncio\n    async def test_decode_envelope_error(self):\n        \"\"\"Test the decoding error for the envelopes.\"\"\"\n        await self.gym_con.connect()\n        envelope = Envelope(\n            to=self.gym_address,\n            sender=self.skill_id,\n            protocol_specification_id=UNKNOWN_PROTOCOL_PUBLIC_ID,\n            message=b\"hello\",\n        )\n\n        with pytest.raises(ValueError):\n            await self.gym_con.send(envelope)\n\n    @pytest.mark.asyncio\n    async def test_send_connection_error(self):\n        \"\"\"Test send connection error.\"\"\"\n        msg, sending_dialogue = self.dialogues.create(\n            counterparty=self.gym_address,\n            performative=GymMessage.Performative.RESET,\n        )\n        envelope = Envelope(\n            to=msg.to,\n            sender=msg.sender,\n            message=msg,\n        )\n\n        with pytest.raises(ConnectionError):\n            await self.gym_con.send(envelope)\n\n    @pytest.mark.asyncio\n    async def test_send_act(self):\n        \"\"\"Test send act message.\"\"\"\n        sending_dialogue = await self.send_reset()\n        assert sending_dialogue.last_message is not None\n        msg = sending_dialogue.reply(\n            performative=GymMessage.Performative.ACT,\n            action=GymMessage.AnyObject(\"any_action\"),\n            step_id=1,\n        )\n        envelope = Envelope(\n            to=msg.to,\n            sender=msg.sender,\n            message=msg,\n        )\n        await self.gym_con.connect()\n\n        observation = 1\n        reward = 1.0\n        done = True\n        info = \"some info\"\n        with patch.object(\n            self.env, \"step\", return_value=(observation, reward, done, info)\n        ) as mock:\n            await self.gym_con.send(envelope)\n            mock.assert_called()\n\n        response = await asyncio.wait_for(self.gym_con.receive(), timeout=3)\n        response_msg = cast(GymMessage, response.message)\n        response_dialogue = self.dialogues.update(response_msg)\n\n        assert response_msg.performative == GymMessage.Performative.PERCEPT\n        assert response_msg.step_id == msg.step_id\n        assert response_msg.observation.any == observation\n        assert response_msg.reward == reward\n        assert response_msg.done == done\n        assert response_msg.info.any == info\n        assert sending_dialogue == response_dialogue\n\n    @pytest.mark.asyncio\n    async def test_send_reset(self):\n        \"\"\"Test send reset message.\"\"\"\n        _ = await self.send_reset()\n\n    @pytest.mark.asyncio\n    async def test_send_close(self):\n        \"\"\"Test send close message.\"\"\"\n        sending_dialogue = await self.send_reset()\n        assert sending_dialogue.last_message is not None\n        msg = sending_dialogue.reply(\n            performative=GymMessage.Performative.CLOSE,\n        )\n        envelope = Envelope(\n            to=msg.to,\n            sender=msg.sender,\n            message=msg,\n        )\n        await self.gym_con.connect()\n\n        with patch.object(self.env, \"close\") as mock:\n            await self.gym_con.send(envelope)\n            mock.assert_called()\n\n    @pytest.mark.asyncio\n    async def test_send_close_negative(self):\n        \"\"\"Test send close message with invalid reference and message id and target.\"\"\"\n        incorrect_msg = GymMessage(\n            performative=GymMessage.Performative.CLOSE,\n            dialogue_reference=self.dialogues.new_self_initiated_dialogue_reference(),\n        )\n        incorrect_msg.to = self.gym_address\n        incorrect_msg.sender = self.skill_id\n\n        # the incorrect message cannot be sent into a dialogue, so this is omitted.\n\n        envelope = Envelope(\n            to=incorrect_msg.to,\n            sender=incorrect_msg.sender,\n            protocol_specification_id=incorrect_msg.protocol_specification_id,\n            message=incorrect_msg,\n        )\n        await self.gym_con.connect()\n\n        with patch.object(self.gym_con.channel.logger, \"warning\") as mock_logger:\n            await self.gym_con.send(envelope)\n            mock_logger.assert_any_call(\n                f\"Could not create dialogue from message={incorrect_msg}\"\n            )\n\n    async def send_reset(self) -> GymDialogue:\n        \"\"\"Send a reset.\"\"\"\n        msg, sending_dialogue = self.dialogues.create(\n            counterparty=self.gym_address,\n            performative=GymMessage.Performative.RESET,\n        )\n        assert sending_dialogue is not None\n        envelope = Envelope(\n            to=msg.to,\n            sender=msg.sender,\n            message=msg,\n        )\n        await self.gym_con.connect()\n\n        with patch.object(self.env, \"reset\") as mock:\n            await self.gym_con.send(envelope)\n            mock.assert_called()\n\n        response = await asyncio.wait_for(self.gym_con.receive(), timeout=3)\n        response_msg = cast(GymMessage, response.message)\n        response_dialogue = self.dialogues.update(response_msg)\n\n        assert response_msg.performative == GymMessage.Performative.STATUS\n        assert response_msg.content == {\"reset\": \"success\"}\n        assert sending_dialogue == response_dialogue\n        return sending_dialogue\n\n    @pytest.mark.asyncio\n    async def test_receive_connection_error(self):\n        \"\"\"Test receive connection error and Cancel Error.\"\"\"\n        with pytest.raises(ConnectionError):\n            await self.gym_con.receive()\n\n    def test_gym_env_load(self):\n        \"\"\"Load gym env from file.\"\"\"\n        curdir = os.getcwd()\n        os.chdir(os.path.join(ROOT_DIR, \"examples\", \"gym_ex\"))\n        gym_env_path = \"gyms.env.BanditNArmedRandom\"\n        configuration = ConnectionConfig(\n            connection_id=GymConnection.connection_id, env=gym_env_path\n        )\n        identity = Identity(\n            \"name\", address=self.agent_address, public_key=self.agent_public_key\n        )\n        gym_con = GymConnection(\n            gym_env=None,\n            identity=identity,\n            configuration=configuration,\n            data_dir=MagicMock(),\n        )\n        assert gym_con.channel.gym_env is not None\n        os.chdir(curdir)\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_connections/test_local/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests of the local OEF node implementation.\"\"\"\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_connections/test_local/test_misc.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests of the local OEF node implementation.\"\"\"\nimport asyncio\nimport unittest.mock\n\nimport pytest\n\nfrom aea.helpers.search.models import Constraint, ConstraintType, Description, Query\nfrom aea.mail.base import Envelope\nfrom aea.multiplexer import Multiplexer\n\nfrom packages.fetchai.connections.local.connection import LocalNode\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.protocols.fipa.message import FipaMessage\n\nfrom tests.conftest import _make_local_connection\n\n\ndef test_connection():\n    \"\"\"Test that two OEF local connection can connect to a local node.\"\"\"\n    with LocalNode() as node:\n\n        multiplexer1 = Multiplexer(\n            [_make_local_connection(\"multiplexer1\", \"my_public_key_1\", node)]\n        )\n        multiplexer2 = Multiplexer(\n            [_make_local_connection(\"multiplexer2\", \"my_public_key_2\", node)]\n        )\n\n        multiplexer1.connect()\n        multiplexer2.connect()\n\n        multiplexer1.disconnect()\n        multiplexer2.disconnect()\n\n\n@pytest.mark.asyncio\nasync def test_connection_twice_return_none():\n    \"\"\"Test that connecting twice works.\"\"\"\n    with LocalNode() as node:\n        address = \"address\"\n        public_key = \"public_key\"\n        connection = _make_local_connection(address, public_key, node)\n        await connection.connect()\n        await node.connect(address, connection._reader)\n        message = DefaultMessage(\n            dialogue_reference=(\"\", \"\"),\n            message_id=1,\n            target=0,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"hello\",\n        )\n        expected_envelope = Envelope(\n            to=address,\n            sender=address,\n            message=message,\n        )\n        await connection.send(expected_envelope)\n        actual_envelope = await connection.receive()\n\n        assert expected_envelope == actual_envelope\n\n        await connection.disconnect()\n\n\n@pytest.mark.asyncio\nasync def test_receiving_when_not_connected_raise_exception():\n    \"\"\"Test that when we try to receive an envelope from a not connected connection we raise exception.\"\"\"\n    with LocalNode() as node:\n        with pytest.raises(ConnectionError):\n            address = \"address\"\n            public_key = \"public_key\"\n            connection = _make_local_connection(address, public_key, node)\n            await connection.receive()\n\n\n@pytest.mark.asyncio\nasync def test_receiving_returns_none_when_error_occurs():\n    \"\"\"Test that when we try to receive an envelope and an error occurs we return None.\"\"\"\n    with LocalNode() as node:\n        address = \"address\"\n        public_key = \"public_key\"\n        connection = _make_local_connection(address, public_key, node)\n        await connection.connect()\n\n        with unittest.mock.patch.object(\n            connection._reader, \"get\", side_effect=Exception\n        ):\n            result = await connection.receive()\n            assert result is None\n\n        await connection.disconnect()\n\n\ndef test_communication():\n    \"\"\"Test that two multiplexer can communicate through the node.\"\"\"\n    with LocalNode() as node:\n\n        multiplexer1 = Multiplexer(\n            [_make_local_connection(\"multiplexer1\", \"multiplexer1_public_key\", node)]\n        )\n        multiplexer2 = Multiplexer(\n            [_make_local_connection(\"multiplexer2\", \"multiplexer1_public_key\", node)]\n        )\n\n        multiplexer1.connect()\n        multiplexer2.connect()\n\n        msg = DefaultMessage(\n            dialogue_reference=(\"\", \"\"),\n            message_id=1,\n            target=0,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"hello\",\n        )\n        envelope = Envelope(\n            to=\"multiplexer2\",\n            sender=\"multiplexer1\",\n            message=msg,\n        )\n        multiplexer1.put(envelope)\n\n        msg = FipaMessage(\n            performative=FipaMessage.Performative.CFP,\n            dialogue_reference=(str(0), \"\"),\n            message_id=1,\n            target=0,\n            query=Query([Constraint(\"something\", ConstraintType(\">\", 1))]),\n        )\n        envelope = Envelope(\n            to=\"multiplexer2\",\n            sender=\"multiplexer1\",\n            message=msg,\n        )\n        multiplexer1.put(envelope)\n\n        msg = FipaMessage(\n            performative=FipaMessage.Performative.PROPOSE,\n            dialogue_reference=(str(0), \"\"),\n            message_id=2,\n            target=1,\n            proposal=Description({}),\n        )\n\n        envelope = Envelope(\n            to=\"multiplexer2\",\n            sender=\"multiplexer1\",\n            message=msg,\n        )\n        multiplexer1.put(envelope)\n\n        msg = FipaMessage(\n            performative=FipaMessage.Performative.ACCEPT,\n            dialogue_reference=(str(0), \"\"),\n            message_id=1,\n            target=0,\n        )\n        envelope = Envelope(\n            to=\"multiplexer2\",\n            sender=\"multiplexer1\",\n            message=msg,\n        )\n        multiplexer1.put(envelope)\n\n        msg = FipaMessage(\n            performative=FipaMessage.Performative.DECLINE,\n            dialogue_reference=(str(0), \"\"),\n            message_id=1,\n            target=0,\n        )\n        envelope = Envelope(\n            to=\"multiplexer2\",\n            sender=\"multiplexer1\",\n            message=msg,\n        )\n        multiplexer1.put(envelope)\n\n        envelope = multiplexer2.get(block=True, timeout=1.0)\n        msg = envelope.message\n        assert (\n            envelope.protocol_specification_id\n            == DefaultMessage.protocol_specification_id\n        )\n        assert msg.content == b\"hello\"\n        envelope = multiplexer2.get(block=True, timeout=1.0)\n        msg = envelope.message\n        assert (\n            envelope.protocol_specification_id == FipaMessage.protocol_specification_id\n        )\n        assert msg.performative == FipaMessage.Performative.CFP\n        envelope = multiplexer2.get(block=True, timeout=1.0)\n        msg = envelope.message\n        assert (\n            envelope.protocol_specification_id == FipaMessage.protocol_specification_id\n        )\n        assert msg.performative == FipaMessage.Performative.PROPOSE\n        envelope = multiplexer2.get(block=True, timeout=1.0)\n        msg = envelope.message\n        assert (\n            envelope.protocol_specification_id == FipaMessage.protocol_specification_id\n        )\n        assert msg.performative == FipaMessage.Performative.ACCEPT\n        envelope = multiplexer2.get(block=True, timeout=1.0)\n        msg = envelope.message\n        assert (\n            envelope.protocol_specification_id == FipaMessage.protocol_specification_id\n        )\n        assert msg.performative == FipaMessage.Performative.DECLINE\n        multiplexer1.disconnect()\n        multiplexer2.disconnect()\n\n\n@pytest.mark.asyncio\nasync def test_connecting_to_node_with_same_key():\n    \"\"\"Test that connecting twice with the same key works correctly.\"\"\"\n    with LocalNode() as node:\n        address = \"my_address\"\n        my_queue = asyncio.Queue()\n\n        ret = await node.connect(address, my_queue)\n        assert ret is not None and isinstance(ret, asyncio.Queue)\n        ret = await node.connect(address, my_queue)\n        assert ret is None\n\n\ndef test_stop_before_start():\n    \"\"\"Test stop called before start.\"\"\"\n    node = LocalNode()\n    with pytest.raises(ValueError, match=\"Connection not started!\"):\n        node.stop()\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_connections/test_local/test_search_services.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests for the search feature of the local OEF node.\"\"\"\nimport unittest.mock\nfrom typing import cast\n\nimport pytest\n\nfrom aea.common import Address\nfrom aea.helpers.search.models import (\n    Attribute,\n    Constraint,\n    ConstraintType,\n    DataModel,\n    Description,\n    Query,\n)\nfrom aea.mail.base import Envelope, EnvelopeContext, Message\nfrom aea.multiplexer import InBox, Multiplexer\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\n\nfrom packages.fetchai.connections.local.connection import (\n    LocalNode,\n    OEFLocalConnection,\n    OEF_LOCAL_NODE_ADDRESS,\n    OEF_LOCAL_NODE_SEARCH_ADDRESS,\n)\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.protocols.fipa.dialogues import FipaDialogue, FipaDialogues\nfrom packages.fetchai.protocols.fipa.message import FipaMessage\nfrom packages.fetchai.protocols.oef_search.dialogues import OefSearchDialogue\nfrom packages.fetchai.protocols.oef_search.dialogues import (\n    OefSearchDialogues as BaseOefSearchDialogues,\n)\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\n\nfrom tests.common.mocks import AnyStringWith\nfrom tests.common.utils import wait_for_condition\nfrom tests.conftest import MAX_FLAKY_RERUNS, _make_local_connection\n\n\nclass OefSearchDialogues(BaseOefSearchDialogues):\n    \"\"\"The dialogues class keeps track of all http dialogues.\"\"\"\n\n    def __init__(self, self_address: Address, **kwargs) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :return: None\n        \"\"\"\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return OefSearchDialogue.Role.AGENT\n\n        BaseOefSearchDialogues.__init__(\n            self,\n            self_address=self_address,\n            role_from_first_message=role_from_first_message,\n        )\n\n\nclass TestNoValidDialogue:\n    \"\"\"Test that the search request returns an empty search result.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set up the test.\"\"\"\n        cls.node = LocalNode()\n        cls.node.start()\n\n        cls.address_1 = \"address_1\"\n        cls.public_key_1 = \"public_key_1\"\n        cls.connection = _make_local_connection(\n            cls.address_1,\n            cls.public_key_1,\n            cls.node,\n        )\n        cls.multiplexer = Multiplexer([cls.connection])\n\n        cls.multiplexer.connect()\n        cls.dialogues = OefSearchDialogues(cls.address_1)\n\n    @pytest.mark.asyncio\n    async def test_wrong_dialogue(self):\n        \"\"\"Test that at the beginning, the search request returns an empty search result.\"\"\"\n        query = Query(\n            constraints=[Constraint(\"foo\", ConstraintType(\"==\", 1))], model=None\n        )\n\n        # build and send the request\n        search_services_request = OefSearchMessage(\n            performative=OefSearchMessage.Performative.SEARCH_SERVICES,\n            message_id=2,\n            target=1,\n            dialogue_reference=self.dialogues.new_self_initiated_dialogue_reference(),\n            query=query,\n        )\n        search_services_request.to = OEF_LOCAL_NODE_SEARCH_ADDRESS\n\n        # the incorrect message cannot be sent into a dialogue, so this is omitted.\n\n        search_services_request.sender = self.address_1\n        envelope = Envelope(\n            to=search_services_request.to,\n            sender=search_services_request.sender,\n            message=search_services_request,\n        )\n        with unittest.mock.patch.object(\n            self.node, \"_handle_oef_message\", side_effect=self.node._handle_oef_message\n        ) as mock_handle:\n            with unittest.mock.patch.object(self.node.logger, \"warning\") as mock_logger:\n                self.multiplexer.put(envelope)\n                wait_for_condition(lambda: mock_handle.called, timeout=1.0)\n                mock_logger.assert_any_call(\n                    AnyStringWith(\"Could not create dialogue for message=\")\n                )\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Teardown the test.\"\"\"\n        cls.multiplexer.disconnect()\n        cls.node.stop()\n\n\nclass TestEmptySearch:\n    \"\"\"Test that the search request returns an empty search result.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set up the test.\"\"\"\n        cls.node = LocalNode()\n        cls.node.start()\n\n        cls.address_1 = \"address_1\"\n        cls.public_key_1 = \"public_key_1\"\n        cls.multiplexer = Multiplexer(\n            [\n                _make_local_connection(\n                    cls.address_1,\n                    cls.public_key_1,\n                    cls.node,\n                )\n            ]\n        )\n\n        cls.multiplexer.connect()\n        cls.dialogues = OefSearchDialogues(cls.address_1)\n\n    def test_empty_search_result(self):\n        \"\"\"Test that at the beginning, the search request returns an empty search result.\"\"\"\n        search_services_request, sending_dialogue = self.dialogues.create(\n            counterparty=OEF_LOCAL_NODE_SEARCH_ADDRESS,\n            performative=OefSearchMessage.Performative.SEARCH_SERVICES,\n            query=Query(constraints=[], model=None),\n        )\n        envelope = Envelope(\n            to=search_services_request.to,\n            sender=search_services_request.sender,\n            message=search_services_request,\n        )\n        self.multiplexer.put(envelope)\n\n        # check the result\n        response_envelope = self.multiplexer.get(block=True, timeout=2.0)\n        assert (\n            response_envelope.protocol_specification_id\n            == OefSearchMessage.protocol_specification_id\n        )\n        search_result = cast(OefSearchMessage, response_envelope.message)\n        response_dialogue = self.dialogues.update(search_result)\n        assert response_dialogue == sending_dialogue\n        assert search_result.performative == OefSearchMessage.Performative.SEARCH_RESULT\n        assert search_result.agents == ()\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Teardown the test.\"\"\"\n        cls.multiplexer.disconnect()\n        cls.node.stop()\n\n\nclass TestSimpleSearchResult:\n    \"\"\"Test that a simple search result return the expected result.\"\"\"\n\n    def setup(self):\n        \"\"\"Set up the test.\"\"\"\n        self.node = LocalNode()\n        self.node.start()\n\n        self.address_1 = \"address\"\n        self.public_key_1 = \"public_key_1\"\n        self.multiplexer = Multiplexer(\n            [\n                _make_local_connection(\n                    self.address_1,\n                    self.public_key_1,\n                    self.node,\n                )\n            ]\n        )\n\n        self.multiplexer.connect()\n\n        # register a service.\n        self.dialogues = OefSearchDialogues(self.address_1)\n        self.data_model = DataModel(\n            \"foobar\",\n            attributes=[Attribute(\"foo\", int, True), Attribute(\"bar\", str, True)],\n        )\n        service_description = Description(\n            {\"foo\": 1, \"bar\": \"baz\"}, data_model=self.data_model\n        )\n        register_service_request, self.sending_dialogue = self.dialogues.create(\n            counterparty=OEF_LOCAL_NODE_SEARCH_ADDRESS,\n            performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n            service_description=service_description,\n        )\n        envelope = Envelope(\n            to=register_service_request.to,\n            sender=register_service_request.sender,\n            message=register_service_request,\n        )\n        self.multiplexer.put(envelope)\n\n    @pytest.mark.flaky(\n        reruns=MAX_FLAKY_RERUNS\n    )  # TODO: check reasons!. quite unstable test\n    def test_not_empty_search_result(self):\n        \"\"\"Test that the search result contains one entry after a successful registration.\"\"\"\n        # build and send the request\n        search_services_request, sending_dialogue = self.dialogues.create(\n            counterparty=OEF_LOCAL_NODE_SEARCH_ADDRESS,\n            performative=OefSearchMessage.Performative.SEARCH_SERVICES,\n            query=Query(constraints=[], model=self.data_model),\n        )\n        envelope = Envelope(\n            to=search_services_request.to,\n            sender=search_services_request.sender,\n            message=search_services_request,\n        )\n        self.multiplexer.put(envelope)\n\n        # check the result\n        response_envelope = self.multiplexer.get(block=True, timeout=2.0)\n        assert (\n            response_envelope.protocol_specification_id\n            == OefSearchMessage.protocol_specification_id\n        )\n        search_result = cast(OefSearchMessage, response_envelope.message)\n        response_dialogue = self.dialogues.update(search_result)\n        assert response_dialogue == sending_dialogue\n        assert search_result.performative == OefSearchMessage.Performative.SEARCH_RESULT\n        assert search_result.agents == (self.address_1,)\n\n    def teardown(self):\n        \"\"\"Teardown the test.\"\"\"\n        self.multiplexer.disconnect()\n        self.node.stop()\n\n\nclass TestUnregister:\n    \"\"\"Test that the unregister service results to Error Message.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set up the test.\"\"\"\n        cls.node = LocalNode()\n        cls.node.start()\n\n        cls.address_1 = \"address_1\"\n        cls.public_key_1 = \"public_key_1\"\n        cls.multiplexer1 = Multiplexer(\n            [\n                _make_local_connection(\n                    cls.address_1,\n                    cls.public_key_1,\n                    cls.node,\n                )\n            ]\n        )\n        cls.address_2 = \"address_2\"\n        cls.public_key_2 = \"public_key_2\"\n        cls.multiplexer2 = Multiplexer(\n            [\n                _make_local_connection(\n                    cls.address_2,\n                    cls.public_key_2,\n                    cls.node,\n                )\n            ]\n        )\n        cls.multiplexer1.connect()\n        cls.multiplexer2.connect()\n        cls.dialogues = OefSearchDialogues(cls.address_1)\n\n    def test_unregister_service_result(self):\n        \"\"\"Test that at the beginning, the search request returns an empty search result.\"\"\"\n        data_model = DataModel(\n            \"foobar\",\n            attributes=[Attribute(\"foo\", int, True), Attribute(\"bar\", str, True)],\n        )\n        service_description = Description(\n            {\"foo\": 1, \"bar\": \"baz\"}, data_model=data_model\n        )\n        msg, sending_dialogue = self.dialogues.create(\n            counterparty=OEF_LOCAL_NODE_SEARCH_ADDRESS,\n            performative=OefSearchMessage.Performative.UNREGISTER_SERVICE,\n            service_description=service_description,\n        )\n        envelope = Envelope(\n            to=msg.to,\n            sender=msg.sender,\n            message=msg,\n            context=EnvelopeContext(connection_id=OEFLocalConnection.connection_id),\n        )\n        self.multiplexer1.put(envelope)\n\n        # check the result\n        response_envelope = self.multiplexer1.get(block=True, timeout=5.0)\n        assert (\n            response_envelope.protocol_specification_id\n            == OefSearchMessage.protocol_specification_id\n        )\n        response = cast(OefSearchMessage, response_envelope.message)\n        response_dialogue = self.dialogues.update(response)\n        assert response_dialogue == sending_dialogue\n        assert response.performative == OefSearchMessage.Performative.OEF_ERROR\n\n        msg, sending_dialogue = self.dialogues.create(\n            counterparty=OEF_LOCAL_NODE_SEARCH_ADDRESS,\n            performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n            service_description=service_description,\n        )\n        envelope = Envelope(\n            to=msg.to,\n            sender=msg.sender,\n            message=msg,\n            context=EnvelopeContext(connection_id=OEFLocalConnection.connection_id),\n        )\n        self.multiplexer1.put(envelope)\n\n        # Search for the registered service\n        msg, sending_dialogue = self.dialogues.create(\n            counterparty=OEF_LOCAL_NODE_SEARCH_ADDRESS,\n            performative=OefSearchMessage.Performative.SEARCH_SERVICES,\n            query=Query([Constraint(\"foo\", ConstraintType(\"==\", 1))]),\n        )\n        envelope = Envelope(\n            to=msg.to,\n            sender=msg.sender,\n            message=msg,\n            context=EnvelopeContext(connection_id=OEFLocalConnection.connection_id),\n        )\n        self.multiplexer1.put(envelope)\n        # check the result\n        response_envelope = self.multiplexer1.get(block=True, timeout=5.0)\n        search_result = cast(OefSearchMessage, response_envelope.message)\n        response_dialogue = self.dialogues.update(search_result)\n        assert response_dialogue == sending_dialogue\n        assert search_result.performative == OefSearchMessage.Performative.SEARCH_RESULT\n        assert len(search_result.agents) == 1\n\n        # unregister the service\n        msg, sending_dialogue = self.dialogues.create(\n            counterparty=OEF_LOCAL_NODE_SEARCH_ADDRESS,\n            performative=OefSearchMessage.Performative.UNREGISTER_SERVICE,\n            service_description=service_description,\n        )\n        envelope = Envelope(\n            to=msg.to,\n            sender=msg.sender,\n            message=msg,\n            context=EnvelopeContext(connection_id=OEFLocalConnection.connection_id),\n        )\n        self.multiplexer1.put(envelope)\n\n        # the same query returns empty\n        # Search for the register agent\n        msg, sending_dialogue = self.dialogues.create(\n            counterparty=OEF_LOCAL_NODE_SEARCH_ADDRESS,\n            performative=OefSearchMessage.Performative.SEARCH_SERVICES,\n            query=Query([Constraint(\"foo\", ConstraintType(\"==\", 1))]),\n        )\n        envelope = Envelope(\n            to=msg.to,\n            sender=msg.sender,\n            message=msg,\n            context=EnvelopeContext(connection_id=OEFLocalConnection.connection_id),\n        )\n        self.multiplexer1.put(envelope)\n        # check the result\n        response_envelope = self.multiplexer1.get(block=True, timeout=5.0)\n        search_result = cast(OefSearchMessage, response_envelope.message)\n        response_dialogue = self.dialogues.update(search_result)\n        assert response_dialogue == sending_dialogue\n        assert search_result.performative == OefSearchMessage.Performative.SEARCH_RESULT\n        assert search_result.agents == ()\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Teardown the test.\"\"\"\n        cls.multiplexer1.disconnect()\n        cls.multiplexer2.disconnect()\n        cls.node.stop()\n\n\nclass TestAgentMessage:\n    \"\"\"Test the the OEF will return Dialogue Error if it doesn't know the agent address.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set up the test.\"\"\"\n        cls.node = LocalNode()\n        cls.node.start()\n\n        cls.address_1 = \"address_1\"\n        cls.public_key_1 = \"public_key_1\"\n        cls.multiplexer1 = Multiplexer(\n            [\n                _make_local_connection(\n                    cls.address_1,\n                    cls.public_key_1,\n                    cls.node,\n                )\n            ]\n        )\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return FipaDialogue.Role.SELLER\n\n        cls.dialogues = FipaDialogues(cls.address_1, role_from_first_message)\n\n    @pytest.mark.asyncio\n    async def test_messages(self):\n        \"\"\"Test that at the beginning, the search request returns an empty search result.\"\"\"\n        msg, sending_dialogue = self.dialogues.create(\n            counterparty=\"some_agent\",\n            performative=FipaMessage.Performative.CFP,\n            query=Query([Constraint(\"something\", ConstraintType(\">\", 1))]),\n        )\n        envelope = Envelope(\n            to=msg.to,\n            sender=msg.sender,\n            message=msg,\n            context=EnvelopeContext(connection_id=OEFLocalConnection.connection_id),\n        )\n        with pytest.raises(ConnectionError):\n            await _make_local_connection(\n                self.address_1,\n                self.public_key_1,\n                self.node,\n            ).send(envelope)\n\n        self.multiplexer1.connect()\n        msg, sending_dialogue = self.dialogues.create(\n            counterparty=\"this_address_does_not_exist\",\n            performative=FipaMessage.Performative.CFP,\n            query=Query([Constraint(\"something\", ConstraintType(\">\", 1))]),\n        )\n        envelope = Envelope(\n            to=msg.to,\n            sender=msg.sender,\n            message=msg,\n        )\n        self.multiplexer1.put(envelope)\n\n        # check the result\n        response_envelope = self.multiplexer1.get(block=True, timeout=5.0)\n        assert (\n            response_envelope.protocol_specification_id\n            == DefaultMessage.protocol_specification_id\n        )\n        assert response_envelope.sender == OEF_LOCAL_NODE_ADDRESS\n        result = response_envelope.message\n        assert result.performative == DefaultMessage.Performative.ERROR\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Teardown the test.\"\"\"\n        cls.multiplexer1.disconnect()\n        cls.node.stop()\n\n\nclass TestFilteredSearchResult:\n    \"\"\"Test that the query system of the search gives the expected result.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set up the test.\"\"\"\n        cls.node = LocalNode()\n        cls.node.start()\n\n        cls.address_1 = \"multiplexer1\"\n        cls.public_key_1 = \"public_key_1\"\n        cls.address_2 = \"multiplexer2\"\n        cls.public_key_2 = \"public_key_2\"\n        cls.multiplexer1 = Multiplexer(\n            [\n                _make_local_connection(\n                    cls.address_1,\n                    cls.public_key_1,\n                    cls.node,\n                )\n            ]\n        )\n        cls.multiplexer2 = Multiplexer(\n            [\n                _make_local_connection(\n                    cls.address_2,\n                    cls.public_key_2,\n                    cls.node,\n                )\n            ]\n        )\n        cls.multiplexer1.connect()\n        cls.multiplexer2.connect()\n        cls.dialogues1 = OefSearchDialogues(cls.address_1)\n        cls.dialogues2 = OefSearchDialogues(cls.address_2)\n\n        # register 'multiplexer1' as a service 'foobar'.\n        cls.data_model_foobar = DataModel(\n            \"foobar\",\n            attributes=[Attribute(\"foo\", int, True), Attribute(\"bar\", str, True)],\n        )\n        service_description = Description(\n            {\"foo\": 1, \"bar\": \"baz\"}, data_model=cls.data_model_foobar\n        )\n        register_service_request, sending_dialogue = cls.dialogues1.create(\n            counterparty=OEF_LOCAL_NODE_SEARCH_ADDRESS,\n            performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n            service_description=service_description,\n        )\n        envelope = Envelope(\n            to=register_service_request.to,\n            sender=register_service_request.sender,\n            message=register_service_request,\n            context=EnvelopeContext(connection_id=OEFLocalConnection.connection_id),\n        )\n        cls.multiplexer1.put(envelope)\n        wait_for_condition(lambda: len(cls.node.services) == 1, timeout=10)\n\n        # register 'multiplexer2' as a service 'barfoo'.\n        cls.data_model_barfoo = DataModel(\n            \"barfoo\",\n            attributes=[Attribute(\"foo\", int, True), Attribute(\"bar\", str, True)],\n        )\n        service_description = Description(\n            {\"foo\": 1, \"bar\": \"baz\"}, data_model=cls.data_model_barfoo\n        )\n        register_service_request, sending_dialogue = cls.dialogues2.create(\n            counterparty=OEF_LOCAL_NODE_SEARCH_ADDRESS,\n            performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n            service_description=service_description,\n        )\n        envelope = Envelope(\n            to=register_service_request.to,\n            sender=register_service_request.sender,\n            message=register_service_request,\n            context=EnvelopeContext(connection_id=OEFLocalConnection.connection_id),\n        )\n\n        cls.multiplexer2.put(envelope)\n        wait_for_condition(lambda: len(cls.node.services) == 2, timeout=10)\n\n        # unregister multiplexer1\n        data_model = DataModel(\n            \"foobar\",\n            attributes=[Attribute(\"foo\", int, True), Attribute(\"bar\", str, True)],\n        )\n        service_description = Description(\n            {\"foo\": 1, \"bar\": \"baz\"}, data_model=data_model\n        )\n        msg, sending_dialogue = cls.dialogues1.create(\n            counterparty=OEF_LOCAL_NODE_SEARCH_ADDRESS,\n            performative=OefSearchMessage.Performative.UNREGISTER_SERVICE,\n            service_description=service_description,\n        )\n        envelope = Envelope(\n            to=msg.to,\n            sender=msg.sender,\n            message=msg,\n            context=EnvelopeContext(connection_id=OEFLocalConnection.connection_id),\n        )\n        cls.multiplexer1.put(envelope)\n        # ensure one service stays registered\n        wait_for_condition(lambda: len(cls.node.services) == 1, timeout=10)\n\n    def test_filtered_search_result(self):\n        \"\"\"Test that the search result contains only the entries matching the query.\"\"\"\n        # build and send the request\n        search_services_request, sending_dialogue = self.dialogues1.create(\n            counterparty=OEF_LOCAL_NODE_SEARCH_ADDRESS,\n            performative=OefSearchMessage.Performative.SEARCH_SERVICES,\n            query=Query(constraints=[], model=self.data_model_barfoo),\n        )\n        envelope = Envelope(\n            to=search_services_request.to,\n            sender=search_services_request.sender,\n            message=search_services_request,\n            context=EnvelopeContext(connection_id=OEFLocalConnection.connection_id),\n        )\n        self.multiplexer1.put(envelope)\n\n        # check the result\n        response_envelope = InBox(self.multiplexer1).get(block=True, timeout=5.0)\n        search_result = cast(OefSearchMessage, response_envelope.message)\n        response_dialogue = self.dialogues1.update(search_result)\n        assert response_dialogue == sending_dialogue\n        assert search_result.performative == OefSearchMessage.Performative.SEARCH_RESULT\n        assert search_result.agents == (self.address_2,), self.node.services\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Teardown the test.\"\"\"\n        cls.multiplexer1.disconnect()\n        cls.multiplexer2.disconnect()\n        cls.node.stop()\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_connections/test_oef/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests of the OEF channel.\"\"\"\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_connections/test_oef/test_communication.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This test module contains the tests for the OEF communication using an OEF.\"\"\"\nimport asyncio\nimport logging\nimport sys\nimport time\nimport unittest\nimport warnings\nfrom contextlib import suppress\nfrom typing import cast\nfrom unittest import mock\nfrom unittest.mock import patch\n\nimport pytest\nfrom oef.messages import OEFErrorOperation\nfrom oef.query import ConstraintExpr\n\nfrom aea.common import Address\nfrom aea.helpers.search.models import (\n    Attribute,\n    Constraint,\n    ConstraintType,\n    ConstraintTypes,\n    DataModel,\n    Description,\n    Location,\n    Query,\n)\nfrom aea.mail.base import Envelope\nfrom aea.mail.base_pb2 import DialogueMessage\nfrom aea.mail.base_pb2 import Message as ProtobufMessage\nfrom aea.multiplexer import Multiplexer\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\n\nfrom packages.fetchai.connections.oef.connection import OEFObjectTranslator\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.protocols.fipa import fipa_pb2\nfrom packages.fetchai.protocols.fipa.message import FipaMessage\nfrom packages.fetchai.protocols.oef_search.dialogues import OefSearchDialogue\nfrom packages.fetchai.protocols.oef_search.dialogues import (\n    OefSearchDialogues as BaseOefSearchDialogues,\n)\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\n\nfrom tests.common.utils import UseOef\nfrom tests.conftest import (\n    FETCHAI_ADDRESS_ONE,\n    FETCHAI_ADDRESS_TWO,\n    _make_oef_connection,\n)\n\n\nlogger = logging.getLogger(__name__)\n\nSOME_SKILL_ID = \"some/skill:0.1.0\"\n\nDUMMY_PUBLIC_KEY = \"some_public_key\"\n\n\nclass OefSearchDialogues(BaseOefSearchDialogues):\n    \"\"\"This class keeps track of all oef_search dialogues.\"\"\"\n\n    def __init__(self, self_address: str) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param self_address: the address of the entity for whom dialogues are maintained\n        :return: None\n        \"\"\"\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return OefSearchDialogue.Role.AGENT\n\n        BaseOefSearchDialogues.__init__(\n            self,\n            self_address=self_address,\n            role_from_first_message=role_from_first_message,\n        )\n\n\nclass TestDefault(UseOef):\n    \"\"\"Test that the default protocol is correctly implemented by the OEF channel.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.connection = _make_oef_connection(\n            FETCHAI_ADDRESS_ONE,\n            DUMMY_PUBLIC_KEY,\n            oef_addr=\"127.0.0.1\",\n            oef_port=10000,\n        )\n        cls.multiplexer = Multiplexer(\n            [cls.connection], protocols=[FipaMessage, DefaultMessage]\n        )\n        cls.multiplexer.connect()\n\n    def test_send_message(self):\n        \"\"\"Test that a default byte message can be sent correctly.\"\"\"\n        msg = DefaultMessage(\n            dialogue_reference=(\"\", \"\"),\n            message_id=1,\n            target=0,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"hello\",\n        )\n        self.multiplexer.put(\n            Envelope(\n                to=FETCHAI_ADDRESS_ONE,\n                sender=FETCHAI_ADDRESS_ONE,\n                message=msg,\n            )\n        )\n        recv_msg = self.multiplexer.get(block=True, timeout=3.0)\n        assert recv_msg is not None\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Teardowm the test.\"\"\"\n        cls.multiplexer.disconnect()\n\n\nclass TestOEF(UseOef):\n    \"\"\"Test that the OEF protocol is correctly implemented by the OEF channel.\"\"\"\n\n    class TestSearchServices:\n        \"\"\"Tests related to service search functionality.\"\"\"\n\n        def setup(self):\n            \"\"\"Set the test up.\"\"\"\n            self.connection = _make_oef_connection(\n                FETCHAI_ADDRESS_ONE,\n                DUMMY_PUBLIC_KEY,\n                oef_addr=\"127.0.0.1\",\n                oef_port=10000,\n            )\n            self.multiplexer = Multiplexer(\n                [self.connection], protocols=[FipaMessage, DefaultMessage]\n            )\n            self.multiplexer.connect()\n            self.oef_search_dialogues = OefSearchDialogues(SOME_SKILL_ID)\n\n        def test_search_services_with_query_without_model(self):\n            \"\"\"Test that a search services request can be sent correctly.\n\n            In this test, the query has no data model.\n            \"\"\"\n            search_query_empty_model = Query(\n                [Constraint(\"foo\", ConstraintType(\"==\", \"bar\"))], model=None\n            )\n            oef_search_request, sending_dialogue = self.oef_search_dialogues.create(\n                counterparty=str(self.connection.connection_id),\n                performative=OefSearchMessage.Performative.SEARCH_SERVICES,\n                query=search_query_empty_model,\n            )\n            self.multiplexer.put(\n                Envelope(\n                    to=oef_search_request.to,\n                    sender=oef_search_request.sender,\n                    message=oef_search_request,\n                )\n            )\n\n            envelope = self.multiplexer.get(block=True, timeout=5.0)\n            oef_search_response = envelope.message\n            oef_search_dialogue = self.oef_search_dialogues.update(oef_search_response)\n            assert (\n                oef_search_response.performative\n                == OefSearchMessage.Performative.SEARCH_RESULT\n            )\n            assert oef_search_dialogue is not None\n            assert oef_search_dialogue == sending_dialogue\n            assert oef_search_response.agents == ()\n\n        def test_search_services_with_query_with_model(self):\n            \"\"\"Test that a search services request can be sent correctly.\n\n            In this test, the query has a simple data model.\n            \"\"\"\n            data_model = DataModel(\"foobar\", [Attribute(\"foo\", str, True)])\n            search_query = Query(\n                [Constraint(\"foo\", ConstraintType(\"==\", \"bar\"))], model=data_model\n            )\n            oef_search_request, sending_dialogue = self.oef_search_dialogues.create(\n                counterparty=str(self.connection.connection_id),\n                performative=OefSearchMessage.Performative.SEARCH_SERVICES,\n                query=search_query,\n            )\n            self.multiplexer.put(\n                Envelope(\n                    to=oef_search_request.to,\n                    sender=oef_search_request.sender,\n                    message=oef_search_request,\n                )\n            )\n\n            envelope = self.multiplexer.get(block=True, timeout=5.0)\n            oef_search_response = envelope.message\n            oef_search_dialogue = self.oef_search_dialogues.update(oef_search_response)\n            assert (\n                oef_search_response.performative\n                == OefSearchMessage.Performative.SEARCH_RESULT\n            )\n            assert oef_search_dialogue is not None\n            assert oef_search_dialogue == sending_dialogue\n            assert oef_search_response.agents == ()\n\n        def test_search_services_with_distance_query(self):\n            \"\"\"Test that a search services request can be sent correctly.\n\n            In this test, the query has a simple data model.\n            \"\"\"\n            tour_eiffel = Location(48.8581064, 2.29447)\n            attribute = Attribute(\"latlon\", Location, True)\n            data_model = DataModel(\"geolocation\", [attribute])\n            search_query = Query(\n                [\n                    Constraint(\n                        attribute.name, ConstraintType(\"distance\", (tour_eiffel, 1.0))\n                    )\n                ],\n                model=data_model,\n            )\n            oef_search_request, sending_dialogue = self.oef_search_dialogues.create(\n                counterparty=str(self.connection.connection_id),\n                performative=OefSearchMessage.Performative.SEARCH_SERVICES,\n                query=search_query,\n            )\n            self.multiplexer.put(\n                Envelope(\n                    to=oef_search_request.to,\n                    sender=oef_search_request.sender,\n                    message=oef_search_request,\n                )\n            )\n            envelope = self.multiplexer.get(block=True, timeout=5.0)\n            oef_search_response = envelope.message\n            oef_search_dialogue = self.oef_search_dialogues.update(oef_search_response)\n            assert (\n                oef_search_response.performative\n                == OefSearchMessage.Performative.SEARCH_RESULT\n            )\n            assert oef_search_dialogue is not None\n            assert oef_search_dialogue == sending_dialogue\n            assert oef_search_response.agents == ()\n\n        def teardown(self):\n            \"\"\"Teardowm the test.\"\"\"\n            self.multiplexer.disconnect()\n\n    class TestRegisterService:\n        \"\"\"Tests related to service registration functionality.\"\"\"\n\n        @classmethod\n        def setup_class(cls):\n            \"\"\"Set the test up.\"\"\"\n            cls.connection = _make_oef_connection(\n                FETCHAI_ADDRESS_ONE,\n                DUMMY_PUBLIC_KEY,\n                oef_addr=\"127.0.0.1\",\n                oef_port=10000,\n            )\n            cls.multiplexer = Multiplexer(\n                [cls.connection], protocols=[FipaMessage, DefaultMessage]\n            )\n            cls.multiplexer.connect()\n            cls.oef_search_dialogues = OefSearchDialogues(SOME_SKILL_ID)\n\n        def test_register_service(self):\n            \"\"\"Test that a register service request works correctly.\"\"\"\n            foo_datamodel = DataModel(\n                \"foo\", [Attribute(\"bar\", int, True, \"A bar attribute.\")]\n            )\n            desc = Description({\"bar\": 1}, data_model=foo_datamodel)\n            oef_search_registration, _ = self.oef_search_dialogues.create(\n                counterparty=str(self.connection.connection_id),\n                performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n                service_description=desc,\n            )\n            self.multiplexer.put(\n                Envelope(\n                    to=oef_search_registration.to,\n                    sender=oef_search_registration.sender,\n                    message=oef_search_registration,\n                )\n            )\n            time.sleep(1)\n\n            oef_search_request, sending_dialogue_2 = self.oef_search_dialogues.create(\n                counterparty=str(self.connection.connection_id),\n                performative=OefSearchMessage.Performative.SEARCH_SERVICES,\n                query=Query(\n                    [Constraint(\"bar\", ConstraintType(\"==\", 1))], model=foo_datamodel\n                ),\n            )\n            self.multiplexer.put(\n                Envelope(\n                    to=oef_search_request.to,\n                    sender=oef_search_request.sender,\n                    message=oef_search_request,\n                )\n            )\n            envelope = self.multiplexer.get(block=True, timeout=5.0)\n            oef_search_response = envelope.message\n            oef_search_dialogue = self.oef_search_dialogues.update(oef_search_response)\n            assert (\n                oef_search_response.performative\n                == OefSearchMessage.Performative.SEARCH_RESULT\n            )\n            assert oef_search_dialogue == sending_dialogue_2\n            assert oef_search_response.agents == (\n                FETCHAI_ADDRESS_ONE,\n            ), \"search_result.agents != [FETCHAI_ADDRESS_ONE] FAILED in test_oef/test_communication.py\"\n\n        @classmethod\n        def teardown_class(cls):\n            \"\"\"Teardowm the test.\"\"\"\n            cls.multiplexer.disconnect()\n\n    class TestUnregisterService:\n        \"\"\"Tests related to service unregistration functionality.\"\"\"\n\n        @classmethod\n        def setup_class(cls):\n            \"\"\"\n            Set the test up.\n\n            Steps:\n            - Register a service\n            - Check that the registration worked.\n            \"\"\"\n            cls.connection = _make_oef_connection(\n                FETCHAI_ADDRESS_ONE,\n                DUMMY_PUBLIC_KEY,\n                oef_addr=\"127.0.0.1\",\n                oef_port=10000,\n            )\n            cls.multiplexer = Multiplexer(\n                [cls.connection], protocols=[FipaMessage, DefaultMessage]\n            )\n            cls.multiplexer.connect()\n            cls.oef_search_dialogues = OefSearchDialogues(SOME_SKILL_ID)\n\n            cls.foo_datamodel = DataModel(\n                \"foo\", [Attribute(\"bar\", int, True, \"A bar attribute.\")]\n            )\n            cls.desc = Description({\"bar\": 1}, data_model=cls.foo_datamodel)\n            oef_search_registration, _ = cls.oef_search_dialogues.create(\n                counterparty=str(cls.connection.connection_id),\n                performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n                service_description=cls.desc,\n            )\n\n            cls.multiplexer.put(\n                Envelope(\n                    to=oef_search_registration.to,\n                    sender=oef_search_registration.sender,\n                    message=oef_search_registration,\n                )\n            )\n\n            time.sleep(1.0)\n\n            (oef_search_request, sending_dialogue_2,) = cls.oef_search_dialogues.create(\n                counterparty=str(cls.connection.connection_id),\n                performative=OefSearchMessage.Performative.SEARCH_SERVICES,\n                query=Query(\n                    [Constraint(\"bar\", ConstraintType(\"==\", 1))],\n                    model=cls.foo_datamodel,\n                ),\n            )\n            cls.multiplexer.put(\n                Envelope(\n                    to=oef_search_request.to,\n                    sender=oef_search_request.sender,\n                    message=oef_search_request,\n                )\n            )\n            envelope = cls.multiplexer.get(block=True, timeout=5.0)\n            oef_search_response = envelope.message\n            oef_search_dialogue = cls.oef_search_dialogues.update(oef_search_response)\n            assert (\n                oef_search_response.performative\n                == OefSearchMessage.Performative.SEARCH_RESULT\n            )\n            assert oef_search_dialogue == sending_dialogue_2\n            assert oef_search_response.agents == (\n                FETCHAI_ADDRESS_ONE,\n            ), \"search_result.agents != [FETCHAI_ADDRESS_ONE] FAILED in test_oef/test_communication.py\"\n\n        def test_unregister_service(self):\n            \"\"\"Test that an unregister service request works correctly.\n\n            Steps:\n            2. unregister the service\n            3. search for that service\n            4. assert that no result is found.\n            \"\"\"\n            oef_search_deregistration, _ = self.oef_search_dialogues.create(\n                counterparty=str(self.connection.connection_id),\n                performative=OefSearchMessage.Performative.UNREGISTER_SERVICE,\n                service_description=self.desc,\n            )\n            self.multiplexer.put(\n                Envelope(\n                    to=oef_search_deregistration.to,\n                    sender=oef_search_deregistration.sender,\n                    message=oef_search_deregistration,\n                )\n            )\n\n            time.sleep(1.0)\n\n            oef_search_request, sending_dialogue_2 = self.oef_search_dialogues.create(\n                counterparty=str(self.connection.connection_id),\n                performative=OefSearchMessage.Performative.SEARCH_SERVICES,\n                query=Query(\n                    [Constraint(\"bar\", ConstraintType(\"==\", 1))],\n                    model=self.foo_datamodel,\n                ),\n            )\n            self.multiplexer.put(\n                Envelope(\n                    to=oef_search_request.to,\n                    sender=oef_search_request.sender,\n                    message=oef_search_request,\n                )\n            )\n\n            envelope = self.multiplexer.get(block=True, timeout=5.0)\n            oef_search_response = envelope.message\n            oef_search_dialogue = self.oef_search_dialogues.update(oef_search_response)\n            assert (\n                oef_search_response.performative\n                == OefSearchMessage.Performative.SEARCH_RESULT\n            )\n            assert oef_search_dialogue == sending_dialogue_2\n            assert oef_search_response.agents == ()\n\n        @classmethod\n        def teardown_class(cls):\n            \"\"\"Teardown the test.\"\"\"\n            cls.multiplexer.disconnect()\n\n\nclass TestFIPA(UseOef):\n    \"\"\"Test that the FIPA protocol is correctly implemented by the OEF channel.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set up the test class.\"\"\"\n        cls.connection1 = _make_oef_connection(\n            FETCHAI_ADDRESS_ONE,\n            DUMMY_PUBLIC_KEY,\n            oef_addr=\"127.0.0.1\",\n            oef_port=10000,\n        )\n        cls.connection2 = _make_oef_connection(\n            FETCHAI_ADDRESS_TWO,\n            DUMMY_PUBLIC_KEY,\n            oef_addr=\"127.0.0.1\",\n            oef_port=10000,\n        )\n        cls.multiplexer1 = Multiplexer(\n            [cls.connection1], protocols=[FipaMessage, DefaultMessage]\n        )\n        cls.multiplexer2 = Multiplexer(\n            [cls.connection2], protocols=[FipaMessage, DefaultMessage]\n        )\n        cls.multiplexer1.connect()\n        cls.multiplexer2.connect()\n\n    def test_cfp(self):\n        \"\"\"Test that a CFP can be sent correctly.\"\"\"\n        cfp_message = FipaMessage(\n            message_id=1,\n            dialogue_reference=(str(0), \"\"),\n            target=0,\n            performative=FipaMessage.Performative.CFP,\n            query=Query([Constraint(\"something\", ConstraintType(\">\", 1))]),\n        )\n        cfp_message.to = FETCHAI_ADDRESS_TWO\n        cfp_message.sender = FETCHAI_ADDRESS_ONE\n        self.multiplexer1.put(\n            Envelope(\n                to=cfp_message.to,\n                sender=cfp_message.sender,\n                message=cfp_message,\n            )\n        )\n        envelope = self.multiplexer2.get(block=True, timeout=5.0)\n        expected_cfp_message = FipaMessage.serializer.decode(envelope.message)\n        expected_cfp_message.to = cfp_message.to\n        expected_cfp_message.sender = cfp_message.sender\n        assert expected_cfp_message == cfp_message\n\n        cfp_none = FipaMessage(\n            message_id=1,\n            dialogue_reference=(str(0), \"\"),\n            target=0,\n            performative=FipaMessage.Performative.CFP,\n            query=Query([Constraint(\"something\", ConstraintType(\">\", 1))]),\n        )\n        cfp_none.to = FETCHAI_ADDRESS_TWO\n        cfp_none.sender = FETCHAI_ADDRESS_ONE\n        self.multiplexer1.put(\n            Envelope(\n                to=cfp_none.to,\n                sender=cfp_none.sender,\n                message=cfp_none,\n            )\n        )\n        envelope = self.multiplexer2.get(block=True, timeout=5.0)\n        expected_cfp_none = FipaMessage.serializer.decode(envelope.message)\n        expected_cfp_none.to = cfp_none.to\n        expected_cfp_none.sender = cfp_none.sender\n        assert expected_cfp_none == cfp_none\n\n    def test_propose(self):\n        \"\"\"Test that a Propose can be sent correctly.\"\"\"\n        propose_empty = FipaMessage(\n            message_id=1,\n            dialogue_reference=(str(0), \"\"),\n            target=0,\n            performative=FipaMessage.Performative.PROPOSE,\n            proposal=Description({\"foo\": \"bar\"}),\n        )\n        propose_empty.to = FETCHAI_ADDRESS_TWO\n        propose_empty.sender = FETCHAI_ADDRESS_ONE\n        self.multiplexer1.put(\n            Envelope(\n                to=propose_empty.to,\n                sender=propose_empty.sender,\n                message=propose_empty,\n            )\n        )\n        envelope = self.multiplexer2.get(block=True, timeout=2.0)\n        expected_propose_empty = FipaMessage.serializer.decode(envelope.message)\n        expected_propose_empty.to = propose_empty.to\n        expected_propose_empty.sender = propose_empty.sender\n        assert expected_propose_empty == propose_empty\n\n        propose_descriptions = FipaMessage(\n            message_id=1,\n            dialogue_reference=(str(0), \"\"),\n            target=0,\n            performative=FipaMessage.Performative.PROPOSE,\n            proposal=Description(\n                {\"foo\": \"bar\"}, DataModel(\"foobar\", [Attribute(\"foo\", str, True)])\n            ),\n        )\n\n        propose_descriptions.to = FETCHAI_ADDRESS_TWO\n        propose_descriptions.sender = FETCHAI_ADDRESS_ONE\n        self.multiplexer1.put(\n            Envelope(\n                to=propose_descriptions.to,\n                sender=propose_descriptions.sender,\n                message=propose_descriptions,\n            )\n        )\n        envelope = self.multiplexer2.get(block=True, timeout=2.0)\n        expected_propose_descriptions = FipaMessage.serializer.decode(envelope.message)\n        expected_propose_descriptions.to = propose_descriptions.to\n        expected_propose_descriptions.sender = propose_descriptions.sender\n        assert expected_propose_descriptions == propose_descriptions\n\n    def test_accept(self):\n        \"\"\"Test that an Accept can be sent correctly.\"\"\"\n        accept = FipaMessage(\n            message_id=1,\n            dialogue_reference=(str(0), \"\"),\n            target=0,\n            performative=FipaMessage.Performative.ACCEPT,\n        )\n        accept.to = FETCHAI_ADDRESS_TWO\n        accept.sender = FETCHAI_ADDRESS_ONE\n        self.multiplexer1.put(\n            Envelope(\n                to=accept.to,\n                sender=accept.sender,\n                message=accept,\n            )\n        )\n        envelope = self.multiplexer2.get(block=True, timeout=2.0)\n        expected_accept = FipaMessage.serializer.decode(envelope.message)\n        expected_accept.to = accept.to\n        expected_accept.sender = accept.sender\n        assert expected_accept == accept\n\n    def test_match_accept(self):\n        \"\"\"Test that a match accept can be sent correctly.\"\"\"\n        # NOTE since the OEF SDK doesn't support the match accept, we have to use a fixed message id!\n        match_accept = FipaMessage(\n            message_id=4,\n            dialogue_reference=(str(0), \"\"),\n            target=3,\n            performative=FipaMessage.Performative.MATCH_ACCEPT,\n        )\n        match_accept.to = FETCHAI_ADDRESS_TWO\n        match_accept.sender = FETCHAI_ADDRESS_ONE\n        self.multiplexer1.put(\n            Envelope(\n                to=match_accept.to,\n                sender=match_accept.sender,\n                message=match_accept,\n            )\n        )\n        envelope = self.multiplexer2.get(block=True, timeout=2.0)\n        expected_match_accept = FipaMessage.serializer.decode(envelope.message)\n        expected_match_accept.to = match_accept.to\n        expected_match_accept.sender = match_accept.sender\n        assert expected_match_accept == match_accept\n\n    def test_decline(self):\n        \"\"\"Test that a Decline can be sent correctly.\"\"\"\n        decline = FipaMessage(\n            message_id=1,\n            dialogue_reference=(str(0), \"\"),\n            target=0,\n            performative=FipaMessage.Performative.DECLINE,\n        )\n        decline.to = FETCHAI_ADDRESS_TWO\n        decline.sender = FETCHAI_ADDRESS_ONE\n        self.multiplexer1.put(\n            Envelope(\n                to=decline.to,\n                sender=decline.sender,\n                message=decline,\n            )\n        )\n        envelope = self.multiplexer2.get(block=True, timeout=2.0)\n        expected_decline = FipaMessage.serializer.decode(envelope.message)\n        expected_decline.to = decline.to\n        expected_decline.sender = decline.sender\n        assert expected_decline == decline\n\n    def test_match_accept_w_inform(self):\n        \"\"\"Test that a match accept with inform can be sent correctly.\"\"\"\n        match_accept_w_inform = FipaMessage(\n            message_id=1,\n            dialogue_reference=(str(0), \"\"),\n            target=0,\n            performative=FipaMessage.Performative.MATCH_ACCEPT_W_INFORM,\n            info={\"address\": \"my_address\"},\n        )\n        match_accept_w_inform.to = FETCHAI_ADDRESS_TWO\n        match_accept_w_inform.sender = FETCHAI_ADDRESS_ONE\n        self.multiplexer1.put(\n            Envelope(\n                to=match_accept_w_inform.to,\n                sender=match_accept_w_inform.sender,\n                message=match_accept_w_inform,\n            )\n        )\n        envelope = self.multiplexer2.get(block=True, timeout=2.0)\n        returned_match_accept_w_inform = FipaMessage.serializer.decode(envelope.message)\n        returned_match_accept_w_inform.to = match_accept_w_inform.to\n        returned_match_accept_w_inform.sender = match_accept_w_inform.sender\n        assert returned_match_accept_w_inform == match_accept_w_inform\n\n    def test_accept_w_inform(self):\n        \"\"\"Test that an accept with address can be sent correctly.\"\"\"\n        accept_w_inform = FipaMessage(\n            message_id=1,\n            dialogue_reference=(str(0), \"\"),\n            target=0,\n            performative=FipaMessage.Performative.ACCEPT_W_INFORM,\n            info={\"address\": \"my_address\"},\n        )\n        accept_w_inform.to = FETCHAI_ADDRESS_TWO\n        accept_w_inform.sender = FETCHAI_ADDRESS_ONE\n        self.multiplexer1.put(\n            Envelope(\n                to=accept_w_inform.to,\n                sender=accept_w_inform.sender,\n                message=accept_w_inform,\n            )\n        )\n        envelope = self.multiplexer2.get(block=True, timeout=2.0)\n        returned_accept_w_inform = FipaMessage.serializer.decode(envelope.message)\n        returned_accept_w_inform.to = accept_w_inform.to\n        returned_accept_w_inform.sender = accept_w_inform.sender\n        assert returned_accept_w_inform == accept_w_inform\n\n    def test_inform(self):\n        \"\"\"Test that an inform can be sent correctly.\"\"\"\n        payload = {\"foo\": \"bar\"}\n        inform = FipaMessage(\n            message_id=1,\n            dialogue_reference=(str(0), \"\"),\n            target=0,\n            performative=FipaMessage.Performative.INFORM,\n            info=payload,\n        )\n        inform.to = FETCHAI_ADDRESS_TWO\n        inform.sender = FETCHAI_ADDRESS_ONE\n        self.multiplexer1.put(\n            Envelope(\n                to=inform.to,\n                sender=inform.sender,\n                message=inform,\n            )\n        )\n        envelope = self.multiplexer2.get(block=True, timeout=2.0)\n        returned_inform = FipaMessage.serializer.decode(envelope.message)\n        returned_inform.to = inform.to\n        returned_inform.sender = inform.sender\n        assert returned_inform == inform\n\n    def test_serialisation_fipa(self):\n        \"\"\"Tests a Value Error flag for wrong CFP query.\"\"\"\n\n        def _encode_fipa_cfp(msg: FipaMessage) -> bytes:\n            \"\"\"Helper function to serialize FIPA CFP message.\"\"\"\n            message_pb = ProtobufMessage()\n            dialogue_message_pb = DialogueMessage()\n            fipa_msg = fipa_pb2.FipaMessage()\n\n            dialogue_message_pb.message_id = msg.message_id\n            dialogue_reference = msg.dialogue_reference\n            dialogue_message_pb.dialogue_starter_reference = dialogue_reference[0]\n            dialogue_message_pb.dialogue_responder_reference = dialogue_reference[1]\n            dialogue_message_pb.target = msg.target\n\n            performative = fipa_pb2.FipaMessage.Cfp_Performative()  # type: ignore\n            # the following are commented to make the decoding to fail.\n            # query = msg.query  # noqa: E800\n            # Query.encode(performative.query, query)  # noqa: E800\n            fipa_msg.cfp.CopyFrom(performative)\n            dialogue_message_pb.content = fipa_msg.SerializeToString()\n\n            message_pb.dialogue_message.CopyFrom(dialogue_message_pb)\n            fipa_bytes = message_pb.SerializeToString()\n            return fipa_bytes\n\n        with pytest.raises(ValueError):\n            msg = FipaMessage(\n                performative=FipaMessage.Performative.CFP,\n                message_id=1,\n                dialogue_reference=(str(0), \"\"),\n                target=0,\n                query=Query([Constraint(\"something\", ConstraintType(\">\", 1))]),\n            )\n            with mock.patch.object(\n                FipaMessage, \"Performative\"\n            ) as mock_performative_enum:\n                mock_performative_enum.CFP.value = \"unknown\"\n                FipaMessage.serializer.encode(msg), \"Raises Value Error\"\n        # with pytest.raises(EOFError):  # noqa: E800\n        #     cfp_msg = FipaMessage(  # noqa: E800\n        #         message_id=1,  # noqa: E800\n        #         dialogue_reference=(str(0), \"\"),  # noqa: E800\n        #         target=0,  # noqa: E800\n        #         performative=FipaMessage.Performative.CFP,  # noqa: E800\n        #         query=Query([Constraint(\"something\", ConstraintType(\">\", 1))]),  # noqa: E800\n        #     )  # noqa: E800\n        #     cfp_msg.set(\"query\", \"hello\")  # noqa: E800\n        #     fipa_bytes = _encode_fipa_cfp(cfp_msg)  # noqa: E800\n\n        #     # The encoded message is not a valid FIPA message.  # noqa: E800\n        #     FipaMessage.serializer.decode(fipa_bytes)  # noqa: E800\n        with pytest.raises(ValueError):\n            cfp_msg = FipaMessage(\n                message_id=1,\n                dialogue_reference=(str(0), \"\"),\n                target=0,\n                performative=FipaMessage.Performative.CFP,\n                query=Query([Constraint(\"something\", ConstraintType(\">\", 1))]),\n            )\n            with mock.patch.object(\n                FipaMessage, \"Performative\"\n            ) as mock_performative_enum:\n                mock_performative_enum.CFP.value = \"unknown\"\n                fipa_bytes = _encode_fipa_cfp(cfp_msg)\n                # The encoded message is not a FIPA message\n                FipaMessage.serializer.decode(fipa_bytes)\n\n    def test_on_oef_error(self):\n        \"\"\"Test the oef error.\"\"\"\n        oef_connection = self.multiplexer1.connections[0]\n        oef_channel = oef_connection.channel\n\n        oef_channel.oef_msg_id += 1\n        dialogue_reference = (\"1\", \"\")\n        query = Query(\n            constraints=[Constraint(\"foo\", ConstraintType(\"==\", \"bar\"))],\n            model=None,\n        )\n        dialogues = oef_channel.oef_search_dialogues\n        oef_search_msg = OefSearchMessage(\n            performative=OefSearchMessage.Performative.SEARCH_SERVICES,\n            dialogue_reference=dialogue_reference,\n            query=query,\n        )\n        oef_search_msg.to = str(oef_connection.connection_id)\n        oef_search_msg.sender = SOME_SKILL_ID\n        dialogue = dialogues.update(oef_search_msg)\n        assert dialogue is not None\n        oef_channel.oef_msg_id_to_dialogue[oef_channel.oef_msg_id] = dialogue\n        oef_channel.on_oef_error(\n            answer_id=oef_channel.oef_msg_id,\n            operation=OEFErrorOperation.SEARCH_SERVICES,\n        )\n        envelope = self.multiplexer1.get(block=True, timeout=5.0)\n        dec_msg = envelope.message\n        assert dec_msg.dialogue_reference[0] == dialogue_reference[0]\n        assert (\n            dec_msg.performative is OefSearchMessage.Performative.OEF_ERROR\n        ), \"It should be an error message\"\n\n    def test_send(self):\n        \"\"\"Test the send method.\"\"\"\n        envelope = Envelope(\n            to=str(self.connection1.connection_id),\n            sender=SOME_SKILL_ID,\n            protocol_specification_id=DefaultMessage.protocol_specification_id,\n            message=b\"Hello\",\n        )\n        self.multiplexer1.put(envelope)\n        received_envelope = self.multiplexer1.get(block=True, timeout=5.0)\n        assert received_envelope is not None\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Teardown the test.\"\"\"\n        cls.multiplexer1.disconnect()\n        cls.multiplexer2.disconnect()\n\n\nclass TestOefConnection(UseOef):\n    \"\"\"Tests the con.connection_status.is_connected property.\"\"\"\n\n    def test_connection(self):\n        \"\"\"Test that an OEF connection can be established to the OEF.\"\"\"\n        connection = _make_oef_connection(\n            FETCHAI_ADDRESS_ONE,\n            DUMMY_PUBLIC_KEY,\n            oef_addr=\"127.0.0.1\",\n            oef_port=10000,\n        )\n        multiplexer = Multiplexer([connection], protocols=[FipaMessage, DefaultMessage])\n        multiplexer.connect()\n        multiplexer.disconnect()\n\n\nclass TestOefConstraint:\n    \"\"\"Tests oef_constraint expressions.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"\n        Set the test up.\n\n        Steps:\n        - Register a service\n        - Check that the registration worked.\n        \"\"\"\n        cls.obj_transaltor = OEFObjectTranslator()\n\n    def test_oef_constraint_types(self):\n        \"\"\"Test the constraint types of the OEF.\"\"\"\n        with pytest.raises(ValueError):\n            m_constraint = self.obj_transaltor.from_oef_constraint_type(\n                ConstraintType(ConstraintTypes.EQUAL, \"==\")\n            )\n            eq = self.obj_transaltor.to_oef_constraint_type(m_constraint)\n            assert eq.value == \"==\"\n\n        m_constraint = ConstraintType(ConstraintTypes.NOT_EQUAL, \"!=\")\n        neq = self.obj_transaltor.to_oef_constraint_type(m_constraint)\n        m_constr = self.obj_transaltor.from_oef_constraint_type(neq)\n        assert m_constraint == m_constr\n        assert neq.value == \"!=\"\n        m_constraint = ConstraintType(ConstraintTypes.LESS_THAN, \"<\")\n        lt = self.obj_transaltor.to_oef_constraint_type(m_constraint)\n        m_constr = self.obj_transaltor.from_oef_constraint_type(lt)\n        assert m_constraint == m_constr\n        assert lt.value == \"<\"\n        m_constraint = ConstraintType(ConstraintTypes.LESS_THAN_EQ, \"<=\")\n        lt_eq = self.obj_transaltor.to_oef_constraint_type(m_constraint)\n        m_constr = self.obj_transaltor.from_oef_constraint_type(lt_eq)\n        assert m_constraint == m_constr\n        assert lt_eq.value == \"<=\"\n        m_constraint = ConstraintType(ConstraintTypes.GREATER_THAN, \">\")\n        gt = self.obj_transaltor.to_oef_constraint_type(m_constraint)\n        m_constr = self.obj_transaltor.from_oef_constraint_type(gt)\n        assert m_constraint == m_constr\n        assert gt.value == \">\"\n        m_constraint = ConstraintType(ConstraintTypes.GREATER_THAN_EQ, \">=\")\n        gt_eq = self.obj_transaltor.to_oef_constraint_type(m_constraint)\n        m_constr = self.obj_transaltor.from_oef_constraint_type(gt_eq)\n        assert m_constraint == m_constr\n        assert gt_eq.value == \">=\"\n        m_constraint = ConstraintType(\"within\", (-10.0, 10.0))\n        with_in = self.obj_transaltor.to_oef_constraint_type(m_constraint)\n        m_constr = self.obj_transaltor.from_oef_constraint_type(with_in)\n        assert m_constraint == m_constr\n        assert with_in._value[0] <= 10 <= with_in._value[1]\n        m_constraint = ConstraintType(\"in\", (1, 2, 3))\n        in_set = self.obj_transaltor.to_oef_constraint_type(m_constraint)\n        m_constr = self.obj_transaltor.from_oef_constraint_type(in_set)\n        assert m_constraint == m_constr\n        assert 2 in in_set._value\n        m_constraint = ConstraintType(\"not_in\", (\"C\", \"Java\", \"Python\"))\n        not_in = self.obj_transaltor.to_oef_constraint_type(m_constraint)\n        m_constr = self.obj_transaltor.from_oef_constraint_type(not_in)\n        assert m_constraint == m_constr\n        assert \"C++\" not in not_in._value\n        location = Location(47.692180, 10.039470)\n        distance_float = 0.2\n        m_constraint = ConstraintType(\"distance\", (location, distance_float))\n        distance = self.obj_transaltor.to_oef_constraint_type(m_constraint)\n        m_constr = self.obj_transaltor.from_oef_constraint_type(distance)\n        assert m_constraint == m_constr\n        assert (\n            distance.center == self.obj_transaltor.to_oef_location(location)\n            and distance.distance == distance_float\n        )\n\n        with pytest.raises(ValueError):\n            m_constraint = ConstraintType(ConstraintTypes.EQUAL, \"foo\")\n            with mock.patch.object(\n                m_constraint, \"type\", return_value=\"unknown_constraint_type\"\n            ):\n                eq = self.obj_transaltor.to_oef_constraint_type(m_constraint)\n\n        with pytest.raises(ValueError):\n            self.obj_transaltor.from_oef_constraint_expr(\n                oef_constraint_expr=cast(ConstraintExpr, DummyConstrainExpr())\n            )\n\n    def test_oef_constraint_expr(self):\n        \"\"\"Test the value error of constraint type.\"\"\"\n        with pytest.raises(ValueError):\n            self.obj_transaltor.to_oef_constraint_expr(\n                constraint_expr=cast(ConstraintExpr, DummyConstrainExpr())\n            )\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Teardown the test.\"\"\"\n        pass\n\n\nclass DummyConstrainExpr(ConstraintExpr):\n    \"\"\"This class is used to represent a constraint expression.\"\"\"\n\n    def check(self, description: Description) -> bool:\n        \"\"\"\n        Check if a description satisfies the constraint expression.\n\n        :param description: the description to check.\n        :return: ``True`` if the description satisfy the constraint expression, ``False`` otherwise.\n        \"\"\"\n        pass\n\n    def is_valid(self, data_model: DataModel) -> bool:\n        \"\"\"\n        Check whether a constraint expression is valid wrt a data model. Specifically, check the following conditions.\n\n        - If all the attributes referenced by the constraints are correctly associated with the Data Model attributes.\n\n        :param data_model: the data model used to check the validity of the constraint expression.\n        :return: ``True`` if the constraint expression is valid wrt the data model, ``False`` otherwise.\n        \"\"\"\n        pass\n\n    def _check_validity(self) -> None:\n        \"\"\"Check whether a Constraint Expression satisfies some basic requirements.\n\n        E.g. an :class:`~oef.query.And` expression must have at least 2 subexpressions.\n        :return ``None``\n        :raises ValueError: if the object does not satisfy some requirements.\n        \"\"\"\n        return\n\n    @property\n    def _node(self):\n        pass\n\n\nclass TestSendWithOEF(UseOef):\n    \"\"\"Test other usecases with OEF.\"\"\"\n\n    @pytest.mark.asyncio\n    async def test_send_oef_message(self, pytestconfig, caplog):\n        \"\"\"Test the send oef message.\"\"\"\n        with warnings.catch_warnings():\n            warnings.simplefilter(\"ignore\")\n            oef_connection = _make_oef_connection(\n                address=FETCHAI_ADDRESS_ONE,\n                public_key=DUMMY_PUBLIC_KEY,\n                oef_addr=\"127.0.0.1\",\n                oef_port=10000,\n            )\n            await oef_connection.connect()\n            oef_search_dialogues = OefSearchDialogues(SOME_SKILL_ID)\n            msg = OefSearchMessage(\n                performative=OefSearchMessage.Performative.OEF_ERROR,\n                dialogue_reference=oef_search_dialogues.new_self_initiated_dialogue_reference(),\n                oef_error_operation=OefSearchMessage.OefErrorOperation.SEARCH_SERVICES,\n            )\n            msg.to = str(oef_connection.connection_id)\n            msg.sender = SOME_SKILL_ID\n            envelope = Envelope(\n                to=msg.to,\n                sender=msg.sender,\n                message=msg,\n            )\n            with caplog.at_level(logging.DEBUG, \"aea.packages.fetchai.connections.oef\"):\n                await oef_connection.send(envelope)\n                assert \"Could not create dialogue for message=\" in caplog.text\n\n            data_model = DataModel(\"foobar\", attributes=[Attribute(\"foo\", str, True)])\n            query = Query(\n                constraints=[Constraint(\"foo\", ConstraintType(\"==\", \"bar\"))],\n                model=data_model,\n            )\n\n            msg, sending_dialogue = oef_search_dialogues.create(\n                counterparty=str(oef_connection.connection_id),\n                performative=OefSearchMessage.Performative.SEARCH_SERVICES,\n                query=query,\n            )\n            envelope = Envelope(\n                to=msg.to,\n                sender=msg.sender,\n                message=msg,\n            )\n            await oef_connection.send(envelope)\n            envelope = await oef_connection.receive()\n            search_result = envelope.message\n            response_dialogue = oef_search_dialogues.update(search_result)\n            assert (\n                search_result.performative\n                == OefSearchMessage.Performative.SEARCH_RESULT\n            )\n            assert sending_dialogue == response_dialogue\n            await asyncio.sleep(2.0)\n            await oef_connection.disconnect()\n\n    @pytest.mark.asyncio\n    async def test_cancelled_receive(self, pytestconfig, caplog):\n        \"\"\"Test the case when a receive request is cancelled.\"\"\"\n        oef_connection = _make_oef_connection(\n            address=FETCHAI_ADDRESS_ONE,\n            public_key=DUMMY_PUBLIC_KEY,\n            oef_addr=\"127.0.0.1\",\n            oef_port=10000,\n        )\n        await oef_connection.connect()\n\n        with caplog.at_level(logging.DEBUG, \"aea.packages.fetchai.connections.oef\"):\n\n            async def receive():\n                await oef_connection.receive()\n\n            task = asyncio.ensure_future(receive(), loop=asyncio.get_event_loop())\n            await asyncio.sleep(0.1)\n            task.cancel()\n            await asyncio.sleep(0.1)\n            await oef_connection.disconnect()\n\n            assert \"Receive cancelled.\" in caplog.text\n\n    @pytest.mark.asyncio\n    async def test_exception_during_receive(self, pytestconfig):\n        \"\"\"Test the case when there is an exception during a receive request.\"\"\"\n        oef_connection = _make_oef_connection(\n            address=FETCHAI_ADDRESS_ONE,\n            public_key=DUMMY_PUBLIC_KEY,\n            oef_addr=\"127.0.0.1\",\n            oef_port=10000,\n        )\n        await oef_connection.connect()\n\n        with unittest.mock.patch.object(\n            oef_connection.channel._in_queue, \"get\", side_effect=Exception\n        ):\n            result = await oef_connection.receive()\n            assert result is None\n\n        await oef_connection.disconnect()\n\n    @pytest.mark.asyncio\n    async def test_connecting_twice_is_ok(self, pytestconfig):\n        \"\"\"Test that calling 'connect' twice works as expected.\"\"\"\n        oef_connection = _make_oef_connection(\n            address=FETCHAI_ADDRESS_ONE,\n            public_key=DUMMY_PUBLIC_KEY,\n            oef_addr=\"127.0.0.1\",\n            oef_port=10000,\n        )\n\n        assert not oef_connection.is_connected\n        await oef_connection.connect()\n        assert oef_connection.is_connected\n        await oef_connection.connect()\n        assert oef_connection.is_connected\n\n        await oef_connection.disconnect()\n\n\n@pytest.mark.asyncio\n@pytest.mark.skipif(\n    sys.version_info < (3, 7), reason=\"Python version < 3.7 not supported by the OEF.\"\n)\nasync def test_cannot_connect_to_oef():\n    \"\"\"Test the case when we can't connect to the OEF.\"\"\"\n    oef_connection = _make_oef_connection(\n        address=FETCHAI_ADDRESS_ONE,\n        public_key=DUMMY_PUBLIC_KEY,\n        oef_addr=\"127.0.0.1\",\n        oef_port=61234,  # use addr instead of hostname to avoid name resolution\n    )\n\n    with mock.patch.object(oef_connection.logger, \"warning\") as mock_logger:\n\n        task = asyncio.ensure_future(\n            oef_connection.connect(), loop=asyncio.get_event_loop()\n        )\n        await asyncio.sleep(3.0)\n        mock_logger.assert_any_call(\n            \"Cannot connect to OEFChannel. Retrying in 5 seconds...\"\n        )\n        with suppress(asyncio.CancelledError):\n            task.cancel()\n            await task\n        await oef_connection.disconnect()\n\n\n@pytest.mark.asyncio\n@pytest.mark.skipif(\n    sys.version_info < (3, 7), reason=\"Python version < 3.7 not supported by the OEF.\"\n)\nasync def test_methods_with_logging_only():\n    \"\"\"Test the case when we can't connect to the OEF.\"\"\"\n    oef_connection = _make_oef_connection(\n        address=FETCHAI_ADDRESS_ONE,\n        public_key=DUMMY_PUBLIC_KEY,\n        oef_addr=\"127.0.0.1\",\n        oef_port=61234,  # use addr instead of hostname to avoid name resolution\n    )\n\n    with patch.object(oef_connection.channel, \"_oef_agent_connect\", return_value=True):\n        await oef_connection.connect()\n\n    oef_connection.channel.on_cfp(\n        msg_id=1, dialogue_id=1, origin=\"some\", target=1, query=b\"\"\n    )\n    oef_connection.channel.on_decline(msg_id=1, dialogue_id=1, origin=\"some\", target=1)\n    oef_connection.channel.on_propose(\n        msg_id=1, dialogue_id=1, origin=\"some\", target=1, proposals=b\"\"\n    )\n    oef_connection.channel.on_accept(msg_id=1, dialogue_id=1, origin=\"some\", target=1)\n\n    try:\n        await oef_connection.disconnect()\n    except Exception:  # nosec\n        pass\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_connections/test_oef/test_models.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This test module contains the tests for the OEF models.\"\"\"\n\nimport pickle  # nosec\nfrom unittest import mock\n\nimport pytest\n\nfrom aea.helpers.search.models import (\n    And,\n    Attribute,\n    Constraint,\n    ConstraintType,\n    DataModel,\n    Description,\n    Location,\n    Not,\n    Or,\n    Query,\n)\n\nfrom packages.fetchai.connections.oef.connection import OEFObjectTranslator\n\n\nclass TestTranslator:\n    \"\"\"Test that the translation of the OEF classes from and to the SDK classes works correctly.\"\"\"\n\n    def test_attribute(self):\n        \"\"\"Test that the translation for the Attribute class works.\"\"\"\n        attribute = Attribute(\"foo\", int, True, \"a foo attribute.\")\n        oef_attribute = OEFObjectTranslator.to_oef_attribute(attribute)\n        expected_attribute = OEFObjectTranslator.from_oef_attribute(oef_attribute)\n        actual_attribute = attribute\n        assert expected_attribute == actual_attribute\n\n    def test_data_model(self):\n        \"\"\"Test that the translation for the DataModel class works.\"\"\"\n        attribute_foo = Attribute(\"foo\", int, True, \"a foo attribute.\")\n        attribute_bar = Attribute(\"bar\", str, True, \"a bar attribute.\")\n        data_model_foobar = DataModel(\n            \"foobar\", [attribute_foo, attribute_bar], \"A foobar data model.\"\n        )\n        oef_data_model = OEFObjectTranslator.to_oef_data_model(data_model_foobar)\n        expected_data_model = OEFObjectTranslator.from_oef_data_model(oef_data_model)\n        actual_data_model = data_model_foobar\n        assert expected_data_model == actual_data_model\n\n    def test_description(self):\n        \"\"\"Test that the translation for the Description class works.\"\"\"\n        attribute_foo = Attribute(\"foo\", int, True, \"a foo attribute.\")\n        attribute_bar = Attribute(\"bar\", str, True, \"a bar attribute.\")\n        data_model_foobar = DataModel(\n            \"foobar\", [attribute_foo, attribute_bar], \"A foobar data model.\"\n        )\n        description_foobar = Description(\n            {\"foo\": 1, \"bar\": \"baz\"}, data_model=data_model_foobar\n        )\n        oef_description = OEFObjectTranslator.to_oef_description(description_foobar)\n        expected_description = OEFObjectTranslator.from_oef_description(oef_description)\n        actual_description = description_foobar\n        assert expected_description == actual_description\n        m_desc = iter(description_foobar.values)\n        assert next(m_desc) == \"foo\"\n        assert {\"foo\", \"bar\"} == set(iter(description_foobar))\n\n    def test_query(self):\n        \"\"\"Test that the translation for the Query class works.\"\"\"\n        attribute_foo = Attribute(\"foo\", int, True, \"a foo attribute.\")\n        attribute_bar = Attribute(\"bar\", str, True, \"a bar attribute.\")\n        data_model_foobar = DataModel(\n            \"foobar\", [attribute_foo, attribute_bar], \"A foobar data model.\"\n        )\n\n        query = Query(\n            [\n                And(\n                    [\n                        Or(\n                            [\n                                Not(Constraint(\"foo\", ConstraintType(\"==\", 1))),\n                                Not(Constraint(\"bar\", ConstraintType(\"==\", \"baz\"))),\n                            ]\n                        ),\n                        Constraint(\"foo\", ConstraintType(\"<\", 2)),\n                    ]\n                )\n            ],\n            data_model_foobar,\n        )\n\n        oef_query = OEFObjectTranslator.to_oef_query(query)\n        expected_query = OEFObjectTranslator.from_oef_query(oef_query)\n        actual_query = query\n        assert expected_query == actual_query\n\n\nclass TestPickable:\n    \"\"\"Test that the OEF objects can be pickled.\"\"\"\n\n    def test_pickable_attribute(self):\n        \"\"\"Test that an istance of the Attribute class is pickable.\"\"\"\n        attribute_foo = Attribute(\"foo\", int, True, \"a foo attribute.\")\n        try:\n            pickle.dumps(attribute_foo)\n        except Exception:\n            pytest.fail(\"Error during pickling.\")\n\n    def test_pickable_data_model(self):\n        \"\"\"Test that an istance of the DataModel class is pickable.\"\"\"\n        attribute_foo = Attribute(\"foo\", int, True, \"a foo attribute.\")\n        attribute_bar = Attribute(\"bar\", str, True, \"a bar attribute.\")\n        data_model_foobar = DataModel(\n            \"foobar\", [attribute_foo, attribute_bar], \"A foobar data model.\"\n        )\n        try:\n            pickle.dumps(data_model_foobar)\n        except Exception:\n            pytest.fail(\"Error during pickling.\")\n\n    def test_pickable_description(self):\n        \"\"\"Test that an istance of the Description class is pickable.\"\"\"\n        attribute_foo = Attribute(\"foo\", int, True, \"a foo attribute.\")\n        attribute_bar = Attribute(\"bar\", str, True, \"a bar attribute.\")\n        data_model_foobar = DataModel(\n            \"foobar\", [attribute_foo, attribute_bar], \"A foobar data model.\"\n        )\n        description_foobar = Description(\n            {\"foo\": 1, \"bar\": \"baz\"}, data_model=data_model_foobar\n        )\n        try:\n            pickle.dumps(description_foobar)\n        except Exception:\n            pytest.fail(\"Error during pickling.\")\n\n    def test_pickable_query(self):\n        \"\"\"Test that an istance of the Query class is pickable.\"\"\"\n        attribute_foo = Attribute(\"foo\", int, True, \"a foo attribute.\")\n        attribute_bar = Attribute(\"bar\", str, True, \"a bar attribute.\")\n        data_model_foobar = DataModel(\n            \"foobar\", [attribute_foo, attribute_bar], \"A foobar data model.\"\n        )\n\n        query = Query(\n            [\n                And(\n                    [\n                        Or(\n                            [\n                                Not(Constraint(\"foo\", ConstraintType(\"==\", 1))),\n                                Not(Constraint(\"bar\", ConstraintType(\"==\", \"baz\"))),\n                            ]\n                        ),\n                        Constraint(\"foo\", ConstraintType(\"<\", 2)),\n                    ]\n                )\n            ],\n            data_model_foobar,\n        )\n        try:\n            pickle.dumps(query)\n        except Exception:\n            pytest.fail(\"Error during pickling.\")\n\n\nclass TestCheckValidity:\n    \"\"\"Test the initialization of the Constraint type.\"\"\"\n\n    def test_validity(self):\n        \"\"\"Test the validity of the Constraint type.\"\"\"\n        m_constraint = ConstraintType(\"==\", 3)\n        assert m_constraint.check(3)\n        assert str(m_constraint.type) == \"==\"\n        m_constraint = ConstraintType(\"!=\", \"London\")\n        assert m_constraint.check(\"Paris\")\n        assert str(m_constraint.type) == \"!=\"\n        m_constraint = ConstraintType(\"<\", 3.14)\n        assert m_constraint.check(3.0)\n        assert str(m_constraint.type) == \"<\"\n        m_constraint = ConstraintType(\">\", 3.14)\n        assert m_constraint.check(5.0)\n        assert str(m_constraint.type) == \">\"\n        m_constraint = ConstraintType(\"<=\", 5)\n        assert m_constraint.check(5)\n        assert str(m_constraint.type) == \"<=\"\n        m_constraint = ConstraintType(\">=\", 5)\n        assert m_constraint.check(5)\n        assert str(m_constraint.type) == \">=\"\n        m_constraint = ConstraintType(\"within\", (-10.0, 10.0))\n        assert m_constraint.check(5)\n        assert str(m_constraint.type) == \"within\"\n        m_constraint = ConstraintType(\"in\", (1, 2, 3))\n        assert m_constraint.check(2)\n        assert str(m_constraint.type) == \"in\"\n        m_constraint = ConstraintType(\"not_in\", (\"C\", \"Java\", \"Python\"))\n        assert m_constraint.check(\"C++\")\n        assert str(m_constraint.type) == \"not_in\"\n\n        tour_eiffel = Location(48.8581064, 2.29447)\n        colosseum = Location(41.8902102, 12.4922309)\n        le_jules_verne_restaurant = Location(48.8579675, 2.2951849)\n        m_constraint = ConstraintType(\"distance\", (tour_eiffel, 1.0))\n        assert m_constraint.check(tour_eiffel)\n        assert m_constraint.check(le_jules_verne_restaurant)\n        assert not m_constraint.check(colosseum)\n\n        m_constraint.type = \"unknown\"\n        with pytest.raises(ValueError):\n            m_constraint.check(\"HelloWorld\")\n\n        m_constraint = ConstraintType(\"==\", 3)\n        with mock.patch(\"aea.helpers.search.models.ConstraintTypes\") as mocked_types:\n            mocked_types.EQUAL.value = \"unknown\"\n            assert not m_constraint.check_validity(), \"My constraint must not be valid\"\n\n    def test_not_check(self):\n        \"\"\"Test the not().check function.\"\"\"\n        attribute_foo = Attribute(\"foo\", int, True, \"a foo attribute.\")\n        attribute_bar = Attribute(\"bar\", str, True, \"a bar attribute.\")\n        data_model_foobar = DataModel(\n            \"foobar\", [attribute_foo, attribute_bar], \"A foobar data model.\"\n        )\n        description_foobar = Description(\n            {\"foo\": 1, \"bar\": \"baz\"}, data_model=data_model_foobar\n        )\n\n        no_constraint_1 = Not(Constraint(\"foo\", ConstraintType(\"==\", 5)))\n        assert no_constraint_1.check(description_foobar)\n\n        no_constraint_2 = Not(Constraint(\"bar\", ConstraintType(\"==\", \"hi\")))\n        assert no_constraint_2.check(description_foobar)\n\n        no_constraint_3 = Not(Constraint(\"foo\", ConstraintType(\"==\", 1)))\n        assert not no_constraint_3.check(description_foobar)\n\n        no_constraint_4 = Not(Constraint(\"bar\", ConstraintType(\"==\", \"baz\")))\n        assert not no_constraint_4.check(description_foobar)\n\n        no_constraint_5 = Constraint(\"foo\", ConstraintType(\"!=\", 98273))\n        assert no_constraint_5.check(description_foobar)\n\n        no_constraint_6 = Constraint(\"bar\", ConstraintType(\"!=\", \"hello_again\"))\n        assert no_constraint_6.check(description_foobar)\n\n        no_constraint_7 = Constraint(\"foo\", ConstraintType(\"!=\", 1))\n        assert not no_constraint_7.check(description_foobar)\n\n        no_constraint_8 = Constraint(\"bar\", ConstraintType(\"!=\", \"baz\"))\n        assert not no_constraint_8.check(description_foobar)\n\n    def test_or_check(self):\n        \"\"\"Test the or().check function.\"\"\"\n        attribute_foo = Attribute(\"foo\", int, True, \"a foo attribute.\")\n        attribute_bar = Attribute(\"bar\", str, True, \"a bar attribute.\")\n        data_model_foobar = DataModel(\n            \"foobar\", [attribute_foo, attribute_bar], \"A foobar data model.\"\n        )\n        description_foobar = Description(\n            {\"foo\": 1, \"bar\": \"baz\"}, data_model=data_model_foobar\n        )\n        constraint = Or(\n            [\n                (Constraint(\"foo\", ConstraintType(\"==\", 1))),\n                (Constraint(\"bar\", ConstraintType(\"==\", \"baz\"))),\n            ]\n        )\n        assert constraint.check(description_foobar)\n\n    def test_and_check(self):\n        \"\"\"Test the and().check function.\"\"\"\n        attribute_foo = Attribute(\"foo\", int, True, \"a foo attribute.\")\n        attribute_bar = Attribute(\"bar\", str, True, \"a bar attribute.\")\n        data_model_foobar = DataModel(\n            \"foobar\", [attribute_foo, attribute_bar], \"A foobar data model.\"\n        )\n        description_foobar = Description(\n            {\"foo\": 1, \"bar\": \"baz\"}, data_model=data_model_foobar\n        )\n        constraint = And(\n            [\n                (Constraint(\"foo\", ConstraintType(\"==\", 1))),\n                (Constraint(\"bar\", ConstraintType(\"==\", \"baz\"))),\n            ]\n        )\n        assert constraint.check(description_foobar)\n\n    def test_query_check(self):\n        \"\"\"Test that the query.check() method works.\"\"\"\n        attribute_foo = Attribute(\"foo\", int, True, \"a foo attribute.\")\n        attribute_bar = Attribute(\"bar\", str, True, \"a bar attribute.\")\n        data_model_foobar = DataModel(\n            \"foobar\", [attribute_foo, attribute_bar], \"A foobar data model.\"\n        )\n        description_foobar = Description(\n            {\"foo\": 1, \"bar\": \"baz\"}, data_model=data_model_foobar\n        )\n        query = Query(\n            [\n                And(\n                    [\n                        Or(\n                            [\n                                Not(Constraint(\"foo\", ConstraintType(\"==\", 1))),\n                                Not(Constraint(\"bar\", ConstraintType(\"==\", \"baz\"))),\n                            ]\n                        ),\n                        Constraint(\"foo\", ConstraintType(\"<\", 2)),\n                    ]\n                )\n            ],\n            data_model_foobar,\n        )\n        assert not query.check(description=description_foobar)\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_connections/test_oef/test_oef_serializer.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This test module contains the tests for the OEF serializer.\"\"\"\n\nfrom aea.helpers.search.models import (\n    Attribute,\n    Constraint,\n    ConstraintType,\n    DataModel,\n    Description,\n    Location,\n    Query,\n)\n\nfrom packages.fetchai.connections.oef.object_translator import OEFObjectTranslator\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\n\n\ndef test_oef_serialization_description():\n    \"\"\"Testing the serialization of the OEF.\"\"\"\n    foo_datamodel = DataModel(\n        \"foo\",\n        [\n            Attribute(\"bar\", int, True, \"A bar attribute.\"),\n            Attribute(\"location\", Location, True, \"A location attribute.\"),\n        ],\n    )\n    desc = Description(\n        {\"bar\": 1, \"location\": Location(10.0, 10.0)}, data_model=foo_datamodel\n    )\n    msg = OefSearchMessage(\n        performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n        dialogue_reference=(str(1), \"\"),\n        service_description=desc,\n    )\n    msg_bytes = OefSearchMessage.serializer.encode(msg)\n    assert len(msg_bytes) > 0\n    recovered_msg = OefSearchMessage.serializer.decode(msg_bytes)\n    assert recovered_msg == msg\n\n\ndef test_oef_object_transator():\n    \"\"\"Test oef description and description tranlations.\"\"\"\n    foo_datamodel = DataModel(\n        \"foo\",\n        [\n            Attribute(\"bar\", int, True, \"A bar attribute.\"),\n            Attribute(\"location\", Location, True, \"A location attribute.\"),\n        ],\n    )\n    desc = Description(\n        {\"bar\": 1, \"location\": Location(10.0, 10.0)}, data_model=foo_datamodel\n    )\n    oef_desc = OEFObjectTranslator.to_oef_description(desc)\n    new_desc = OEFObjectTranslator.from_oef_description(oef_desc)\n    assert desc.values[\"location\"] == new_desc.values[\"location\"]\n\n\ndef test_oef_serialization_query():\n    \"\"\"Testing the serialization of the OEF.\"\"\"\n    query = Query([Constraint(\"foo\", ConstraintType(\"==\", \"bar\"))], model=None)\n    msg = OefSearchMessage(\n        performative=OefSearchMessage.Performative.SEARCH_SERVICES,\n        dialogue_reference=(str(1), \"\"),\n        query=query,\n    )\n    msg_bytes = OefSearchMessage.serializer.encode(msg)\n    assert len(msg_bytes) > 0\n    recovered_msg = OefSearchMessage.serializer.decode(msg_bytes)\n    assert recovered_msg == msg\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_connections/test_p2p_libp2p_client/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests of the Libp2p client connection.\"\"\"\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_connections/test_p2p_libp2p_client/test_aea_cli.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This test module contains AEA cli tests for Libp2p tcp client connection.\"\"\"\nimport os\n\nfrom aea_ledger_fetchai import FetchAICrypto\n\nfrom aea.helpers.base import CertRequest\nfrom aea.multiplexer import Multiplexer\nfrom aea.test_tools.test_cases import AEATestCaseEmpty\n\nfrom packages.fetchai.connections.p2p_libp2p_client.connection import PUBLIC_ID\n\nfrom tests.conftest import (\n    _make_libp2p_connection,\n    libp2p_log_on_failure,\n    libp2p_log_on_failure_all,\n)\n\n\nDEFAULT_PORT = 10234\nDEFAULT_DELEGATE_PORT = 11234\nDEFAULT_HOST = \"127.0.0.1\"\nDEFAULT_CLIENTS_PER_NODE = 4\n\nDEFAULT_LAUNCH_TIMEOUT = 10\n\n\n@libp2p_log_on_failure_all\nclass TestP2PLibp2pClientConnectionAEARunning(AEATestCaseEmpty):\n    \"\"\"Test AEA with p2p_libp2p_client connection is correctly run\"\"\"\n\n    @classmethod\n    @libp2p_log_on_failure\n    def setup_class(cls):\n        \"\"\"Set up the test class.\"\"\"\n        super(TestP2PLibp2pClientConnectionAEARunning, cls).setup_class()\n\n        temp_dir = os.path.join(cls.t, \"temp_dir_node\")\n        os.mkdir(temp_dir)\n        cls.node_connection = _make_libp2p_connection(\n            data_dir=temp_dir,\n            delegate_host=DEFAULT_HOST,\n            delegate_port=DEFAULT_DELEGATE_PORT,\n            delegate=True,\n        )\n        cls.node_multiplexer = Multiplexer([cls.node_connection])\n        cls.log_files = [cls.node_connection.node.log_file]\n\n        cls.node_multiplexer.connect()\n\n    def test_node(self):\n        \"\"\"Test the node is connected.\"\"\"\n        assert self.node_connection.is_connected is True\n\n    def test_connection(self):\n        \"\"\"Test the connection can be used in an aea.\"\"\"\n        self.generate_private_key()\n        self.add_private_key()\n        self.add_item(\"connection\", str(PUBLIC_ID))\n        conn_path = \"vendor.fetchai.connections.p2p_libp2p_client\"\n        self.nested_set_config(\n            conn_path + \".config\",\n            {\n                \"nodes\": [\n                    {\n                        \"uri\": \"{}:{}\".format(DEFAULT_HOST, DEFAULT_DELEGATE_PORT),\n                        \"public_key\": self.node_connection.node.pub,\n                    }\n                ]\n            },\n        )\n\n        # generate certificates for connection\n        self.nested_set_config(\n            conn_path + \".cert_requests\",\n            [\n                CertRequest(\n                    identifier=\"acn\",\n                    ledger_id=FetchAICrypto.identifier,\n                    not_after=\"2022-01-01\",\n                    not_before=\"2021-01-01\",\n                    public_key=self.node_connection.node.pub,\n                    message_format=\"{public_key}\",\n                    save_path=\"./cli_test_cert.txt\",\n                )\n            ],\n        )\n        self.run_cli_command(\"issue-certificates\", cwd=self._get_cwd())\n\n        process = self.run_agent()\n        is_running = self.is_running(process, timeout=DEFAULT_LAUNCH_TIMEOUT)\n        assert is_running, \"AEA not running within timeout!\"\n\n        check_strings = \"Successfully connected to libp2p node {}:{}\".format(\n            DEFAULT_HOST, DEFAULT_DELEGATE_PORT\n        )\n        missing_strings = self.missing_from_output(process, check_strings)\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in agent output.\".format(missing_strings)\n\n        self.terminate_agents(process)\n        assert self.is_successfully_terminated(\n            process\n        ), \"AEA wasn't successfully terminated.\"\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear down the test\"\"\"\n        cls.terminate_agents()\n\n        super(TestP2PLibp2pClientConnectionAEARunning, cls).teardown_class()\n\n        cls.node_multiplexer.disconnect()\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_connections/test_p2p_libp2p_client/test_communication.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This test module contains tests for Libp2p tcp client connection.\"\"\"\nimport asyncio\nimport os\nimport shutil\nimport tempfile\nimport time\nfrom unittest import mock\nfrom unittest.mock import Mock, call\n\nimport pytest\nfrom aea_ledger_ethereum import EthereumCrypto\nfrom aea_ledger_fetchai import FetchAICrypto\n\nfrom aea.mail.base import Empty, Envelope\nfrom aea.multiplexer import Multiplexer\n\nfrom packages.fetchai.connections.p2p_libp2p_client.connection import NodeClient, Uri\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.protocols.default.serialization import DefaultSerializer\n\nfrom tests.common.mocks import RegexComparator\nfrom tests.common.utils import wait_for_condition\nfrom tests.conftest import (\n    _make_libp2p_client_connection,\n    _make_libp2p_connection,\n    libp2p_log_on_failure,\n    libp2p_log_on_failure_all,\n)\n\n\nDEFAULT_PORT = 10234\nDEFAULT_DELEGATE_PORT = 11234\nDEFAULT_HOST = \"127.0.0.1\"\nDEFAULT_CLIENTS_PER_NODE = 1\n\nMockDefaultMessageProtocol = Mock()\nMockDefaultMessageProtocol.protocol_id = DefaultMessage.protocol_id\nMockDefaultMessageProtocol.protocol_specification_id = (\n    DefaultMessage.protocol_specification_id\n)\n\n\n@pytest.mark.asyncio\nclass TestLibp2pClientConnectionConnectDisconnect:\n    \"\"\"Test that connection is established and torn down correctly\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up\"\"\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        os.chdir(cls.t)\n\n        temp_dir = os.path.join(cls.t, \"temp_dir_node\")\n        os.mkdir(temp_dir)\n        cls.connection_node = _make_libp2p_connection(data_dir=temp_dir, delegate=True)\n        temp_dir_client = os.path.join(cls.t, \"temp_dir_client\")\n        os.mkdir(temp_dir_client)\n        cls.connection = _make_libp2p_client_connection(\n            data_dir=temp_dir_client, peer_public_key=cls.connection_node.node.pub\n        )\n\n    @pytest.mark.asyncio\n    async def test_libp2pclientconnection_connect_disconnect(self):\n        \"\"\"Test connnect then disconnect.\"\"\"\n        assert self.connection.is_connected is False\n        try:\n            await self.connection_node.connect()\n            await self.connection.connect()\n            assert self.connection.is_connected is True\n\n            await self.connection.disconnect()\n            assert self.connection.is_connected is False\n        except Exception:\n            raise\n        finally:\n            await self.connection_node.disconnect()\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear down the test\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\n@libp2p_log_on_failure_all\nclass TestLibp2pClientConnectionEchoEnvelope:\n    \"\"\"Test that connection will route envelope to destination through the same libp2p node\"\"\"\n\n    @classmethod\n    @libp2p_log_on_failure\n    def setup_class(cls):\n        \"\"\"Set the test up\"\"\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        os.chdir(cls.t)\n\n        cls.log_files = []\n        temp_dir = os.path.join(cls.t, \"temp_dir_node\")\n        os.mkdir(temp_dir)\n        cls.connection_node = _make_libp2p_connection(\n            data_dir=temp_dir, port=DEFAULT_PORT + 1, delegate=True\n        )\n        cls.multiplexer_node = Multiplexer(\n            [cls.connection_node], protocols=[MockDefaultMessageProtocol]\n        )\n        cls.log_files.append(cls.connection_node.node.log_file)\n        cls.multiplexer_node.connect()\n\n        try:\n            temp_dir_client_1 = os.path.join(cls.t, \"temp_dir_client_1\")\n            os.mkdir(temp_dir_client_1)\n            cls.connection_client_1 = _make_libp2p_client_connection(\n                data_dir=temp_dir_client_1,\n                peer_public_key=cls.connection_node.node.pub,\n                ledger_api_id=FetchAICrypto.identifier,\n            )\n            cls.multiplexer_client_1 = Multiplexer(\n                [cls.connection_client_1], protocols=[MockDefaultMessageProtocol]\n            )\n            cls.multiplexer_client_1.connect()\n\n            temp_dir_client_2 = os.path.join(cls.t, \"temp_dir_client_2\")\n            os.mkdir(temp_dir_client_2)\n            cls.connection_client_2 = _make_libp2p_client_connection(\n                data_dir=temp_dir_client_2,\n                peer_public_key=cls.connection_node.node.pub,\n                ledger_api_id=EthereumCrypto.identifier,\n            )\n            cls.multiplexer_client_2 = Multiplexer(\n                [cls.connection_client_2], protocols=[MockDefaultMessageProtocol]\n            )\n            cls.multiplexer_client_2.connect()\n\n            wait_for_condition(lambda: cls.connection_client_1.is_connected is True, 10)\n            wait_for_condition(lambda: cls.connection_client_2.is_connected is True, 10)\n        except Exception:\n            cls.multiplexer_node.disconnect()\n            raise\n\n    def test_connection_is_established(self):\n        \"\"\"Test connection is established.\"\"\"\n        assert self.connection_client_1.is_connected is True\n        assert self.connection_client_2.is_connected is True\n\n    def test_envelope_routed(self):\n        \"\"\"Test the envelope is routed.\"\"\"\n        addr_1 = self.connection_client_1.address\n        addr_2 = self.connection_client_2.address\n\n        msg = DefaultMessage(\n            dialogue_reference=(\"\", \"\"),\n            message_id=1,\n            target=0,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"hello\",\n        )\n        envelope = Envelope(\n            to=addr_2,\n            sender=addr_1,\n            protocol_specification_id=DefaultMessage.protocol_specification_id,\n            message=DefaultSerializer().encode(msg),\n        )\n\n        self.multiplexer_client_1.put(envelope)\n        delivered_envelope = self.multiplexer_client_2.get(block=True, timeout=20)\n\n        assert delivered_envelope is not None\n        assert delivered_envelope.to == envelope.to\n        assert delivered_envelope.sender == envelope.sender\n        assert (\n            delivered_envelope.protocol_specification_id\n            == envelope.protocol_specification_id\n        )\n        assert delivered_envelope.message == envelope.message\n\n    def test_envelope_echoed_back(self):\n        \"\"\"Test the envelope is echoed back.\"\"\"\n        addr_1 = self.connection_client_1.address\n        addr_2 = self.connection_client_2.address\n\n        msg = DefaultMessage(\n            dialogue_reference=(\"\", \"\"),\n            message_id=1,\n            target=0,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"hello\",\n        )\n        original_envelope = Envelope(\n            to=addr_2,\n            sender=addr_1,\n            protocol_specification_id=DefaultMessage.protocol_specification_id,\n            message=DefaultSerializer().encode(msg),\n        )\n\n        self.multiplexer_client_1.put(original_envelope)\n        delivered_envelope = self.multiplexer_client_2.get(block=True, timeout=10)\n        assert delivered_envelope is not None\n\n        delivered_envelope.to = addr_1\n        delivered_envelope.sender = addr_2\n\n        self.multiplexer_client_2.put(delivered_envelope)\n        echoed_envelope = self.multiplexer_client_1.get(block=True, timeout=5)\n\n        assert echoed_envelope is not None\n        assert echoed_envelope.to == original_envelope.sender\n        assert delivered_envelope.sender == original_envelope.to\n        assert (\n            delivered_envelope.protocol_specification_id\n            == original_envelope.protocol_specification_id\n        )\n        assert delivered_envelope.message == original_envelope.message\n\n    def test_envelope_echoed_back_node_agent(self):\n        \"\"\"Test the envelope is echoed back.\"\"\"\n        addr_1 = self.connection_client_1.address\n        addr_n = self.connection_node.address\n\n        msg = DefaultMessage(\n            dialogue_reference=(\"\", \"\"),\n            message_id=1,\n            target=0,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"hello\",\n        )\n        original_envelope = Envelope(\n            to=addr_n,\n            sender=addr_1,\n            protocol_specification_id=DefaultMessage.protocol_specification_id,\n            message=DefaultSerializer().encode(msg),\n        )\n\n        self.multiplexer_client_1.put(original_envelope)\n        delivered_envelope = self.multiplexer_node.get(block=True, timeout=10)\n        assert delivered_envelope is not None\n\n        delivered_envelope.to = addr_1\n        delivered_envelope.sender = addr_n\n\n        self.multiplexer_node.put(delivered_envelope)\n        echoed_envelope = self.multiplexer_client_1.get(block=True, timeout=5)\n\n        assert echoed_envelope is not None\n        assert echoed_envelope.to == original_envelope.sender\n        assert delivered_envelope.sender == original_envelope.to\n        assert (\n            delivered_envelope.protocol_specification_id\n            == original_envelope.protocol_specification_id\n        )\n        assert delivered_envelope.message == original_envelope.message\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear down the test\"\"\"\n        cls.multiplexer_client_1.disconnect()\n        cls.multiplexer_client_2.disconnect()\n        cls.multiplexer_node.disconnect()\n\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\n@libp2p_log_on_failure_all\nclass TestLibp2pClientConnectionEchoEnvelopeTwoDHTNode:\n    \"\"\"Test that connection will route envelope to destination connected to different node\"\"\"\n\n    @classmethod\n    @libp2p_log_on_failure\n    def setup_class(cls):\n        \"\"\"Set the test up\"\"\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        os.chdir(cls.t)\n\n        cls.log_files = []\n        cls.mutliplexers = []\n\n        temp_dir_node_1 = os.path.join(cls.t, \"temp_dir_node_1\")\n        os.mkdir(temp_dir_node_1)\n        cls.connection_node_1 = _make_libp2p_connection(\n            data_dir=temp_dir_node_1,\n            port=DEFAULT_PORT + 1,\n            delegate_port=DEFAULT_DELEGATE_PORT + 1,\n            delegate=True,\n        )\n        cls.multiplexer_node_1 = Multiplexer(\n            [cls.connection_node_1], protocols=[MockDefaultMessageProtocol]\n        )\n        cls.log_files.append(cls.connection_node_1.node.log_file)\n        cls.multiplexer_node_1.connect()\n        cls.mutliplexers.append(cls.multiplexer_node_1)\n\n        genesis_peer = cls.connection_node_1.node.multiaddrs[0]\n\n        temp_dir_node_2 = os.path.join(cls.t, \"temp_dir_node_2\")\n        os.mkdir(temp_dir_node_2)\n        try:\n            cls.connection_node_2 = _make_libp2p_connection(\n                data_dir=temp_dir_node_2,\n                port=DEFAULT_PORT + 2,\n                delegate_port=DEFAULT_DELEGATE_PORT + 2,\n                entry_peers=[genesis_peer],\n                delegate=True,\n            )\n            cls.multiplexer_node_2 = Multiplexer(\n                [cls.connection_node_2], protocols=[MockDefaultMessageProtocol]\n            )\n            cls.log_files.append(cls.connection_node_2.node.log_file)\n            cls.multiplexer_node_2.connect()\n            cls.mutliplexers.append(cls.multiplexer_node_2)\n\n            temp_dir_client_1 = os.path.join(cls.t, \"temp_dir_client_1\")\n            os.mkdir(temp_dir_client_1)\n            cls.connection_client_1 = _make_libp2p_client_connection(\n                data_dir=temp_dir_client_1,\n                peer_public_key=cls.connection_node_1.node.pub,\n                node_port=DEFAULT_DELEGATE_PORT + 1,\n            )\n            cls.multiplexer_client_1 = Multiplexer(\n                [cls.connection_client_1], protocols=[MockDefaultMessageProtocol]\n            )\n            cls.multiplexer_client_1.connect()\n            cls.mutliplexers.append(cls.multiplexer_client_1)\n\n            temp_dir_client_2 = os.path.join(cls.t, \"temp_dir_client_2\")\n            os.mkdir(temp_dir_client_2)\n            cls.connection_client_2 = _make_libp2p_client_connection(\n                data_dir=temp_dir_client_2,\n                peer_public_key=cls.connection_node_2.node.pub,\n                node_port=DEFAULT_DELEGATE_PORT + 2,\n            )\n            cls.multiplexer_client_2 = Multiplexer(\n                [cls.connection_client_2], protocols=[MockDefaultMessageProtocol]\n            )\n            cls.multiplexer_client_2.connect()\n            cls.mutliplexers.append(cls.multiplexer_client_2)\n\n            wait_for_condition(lambda: cls.connection_node_1.is_connected is True, 10)\n            wait_for_condition(lambda: cls.connection_node_2.is_connected is True, 10)\n            wait_for_condition(lambda: cls.connection_client_1.is_connected is True, 10)\n            wait_for_condition(lambda: cls.connection_client_2.is_connected is True, 10)\n\n        except Exception:\n            cls.teardown_class()\n            raise\n\n    def test_connection_is_established(self):\n        \"\"\"Test the connection is established.\"\"\"\n        assert self.connection_node_1.is_connected is True\n        assert self.connection_node_2.is_connected is True\n        assert self.connection_client_1.is_connected is True\n        assert self.connection_client_2.is_connected is True\n\n    def test_envelope_routed(self):\n        \"\"\"Test the envelope is routed.\"\"\"\n        addr_1 = self.connection_client_1.address\n        addr_2 = self.connection_client_2.address\n\n        msg = DefaultMessage(\n            dialogue_reference=(\"\", \"\"),\n            message_id=1,\n            target=0,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"hello\",\n        )\n        envelope = Envelope(\n            to=addr_2,\n            sender=addr_1,\n            protocol_specification_id=DefaultMessage.protocol_specification_id,\n            message=DefaultSerializer().encode(msg),\n        )\n\n        self.multiplexer_client_1.put(envelope)\n        delivered_envelope = self.multiplexer_client_2.get(block=True, timeout=20)\n\n        assert delivered_envelope is not None\n        assert delivered_envelope.to == envelope.to\n        assert delivered_envelope.sender == envelope.sender\n        assert (\n            delivered_envelope.protocol_specification_id\n            == envelope.protocol_specification_id\n        )\n        assert delivered_envelope.message == envelope.message\n\n    def test_envelope_echoed_back(self):\n        \"\"\"Test the envelope is echoed back.\"\"\"\n        addr_1 = self.connection_client_1.address\n        addr_2 = self.connection_client_2.address\n\n        msg = DefaultMessage(\n            dialogue_reference=(\"\", \"\"),\n            message_id=1,\n            target=0,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"hello\",\n        )\n        original_envelope = Envelope(\n            to=addr_2,\n            sender=addr_1,\n            protocol_specification_id=DefaultMessage.protocol_specification_id,\n            message=DefaultSerializer().encode(msg),\n        )\n\n        self.multiplexer_client_1.put(original_envelope)\n        delivered_envelope = self.multiplexer_client_2.get(block=True, timeout=10)\n        assert delivered_envelope is not None\n\n        delivered_envelope.to = addr_1\n        delivered_envelope.sender = addr_2\n\n        self.multiplexer_client_2.put(delivered_envelope)\n        echoed_envelope = self.multiplexer_client_1.get(block=True, timeout=5)\n\n        assert echoed_envelope is not None\n        assert echoed_envelope.to == original_envelope.sender\n        assert delivered_envelope.sender == original_envelope.to\n        assert (\n            delivered_envelope.protocol_specification_id\n            == original_envelope.protocol_specification_id\n        )\n        assert delivered_envelope.message == original_envelope.message\n\n    def test_envelope_echoed_back_node_agent(self):\n        \"\"\"Test the envelope is echoed back node agent.\"\"\"\n        addr_1 = self.connection_client_1.address\n        addr_n = self.connection_node_2.address\n\n        msg = DefaultMessage(\n            dialogue_reference=(\"\", \"\"),\n            message_id=1,\n            target=0,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"hello\",\n        )\n        original_envelope = Envelope(\n            to=addr_n,\n            sender=addr_1,\n            protocol_specification_id=DefaultMessage.protocol_specification_id,\n            message=DefaultSerializer().encode(msg),\n        )\n\n        self.multiplexer_client_1.put(original_envelope)\n        delivered_envelope = self.multiplexer_node_2.get(block=True, timeout=10)\n        assert delivered_envelope is not None\n\n        delivered_envelope.to = addr_1\n        delivered_envelope.sender = addr_n\n\n        self.multiplexer_node_2.put(delivered_envelope)\n        echoed_envelope = self.multiplexer_client_1.get(block=True, timeout=5)\n\n        assert echoed_envelope is not None\n        assert echoed_envelope.to == original_envelope.sender\n        assert delivered_envelope.sender == original_envelope.to\n        assert (\n            delivered_envelope.protocol_specification_id\n            == original_envelope.protocol_specification_id\n        )\n        assert delivered_envelope.message == original_envelope.message\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear down the test\"\"\"\n        for mux in reversed(cls.mutliplexers):\n            mux.disconnect()\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\n@libp2p_log_on_failure_all\nclass TestLibp2pClientConnectionRouting:\n    \"\"\"Test that libp2p DHT network will reliably route envelopes from clients connected to different nodes\"\"\"\n\n    @classmethod\n    @libp2p_log_on_failure\n    def setup_class(cls):\n        \"\"\"Set the test up\"\"\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        os.chdir(cls.t)\n\n        cls.log_files = []\n        cls.multiplexers = []\n\n        try:\n            temp_dir_node_1 = os.path.join(cls.t, \"temp_dir_node_1\")\n            os.mkdir(temp_dir_node_1)\n            cls.connection_node_1 = _make_libp2p_connection(\n                data_dir=temp_dir_node_1,\n                port=DEFAULT_PORT + 1,\n                delegate_port=DEFAULT_DELEGATE_PORT + 1,\n                delegate=True,\n            )\n            cls.multiplexer_node_1 = Multiplexer(\n                [cls.connection_node_1], protocols=[MockDefaultMessageProtocol]\n            )\n            cls.log_files.append(cls.connection_node_1.node.log_file)\n            cls.multiplexer_node_1.connect()\n            cls.multiplexers.append(cls.multiplexer_node_1)\n\n            entry_peer = cls.connection_node_1.node.multiaddrs[0]\n\n            temp_dir_node_2 = os.path.join(cls.t, \"temp_dir_node_2\")\n            os.mkdir(temp_dir_node_2)\n            cls.connection_node_2 = _make_libp2p_connection(\n                data_dir=temp_dir_node_2,\n                port=DEFAULT_PORT + 2,\n                delegate_port=DEFAULT_DELEGATE_PORT + 2,\n                entry_peers=[entry_peer],\n                delegate=True,\n            )\n            cls.multiplexer_node_2 = Multiplexer(\n                [cls.connection_node_2], protocols=[MockDefaultMessageProtocol]\n            )\n            cls.log_files.append(cls.connection_node_2.node.log_file)\n            cls.multiplexer_node_2.connect()\n\n            cls.multiplexers.append(cls.multiplexer_node_2)\n\n            wait_for_condition(lambda: cls.multiplexer_node_1.is_connected, 10)\n            wait_for_condition(lambda: cls.multiplexer_node_2.is_connected, 10)\n            wait_for_condition(lambda: cls.connection_node_1.is_connected, 10)\n            wait_for_condition(lambda: cls.connection_node_2.is_connected, 10)\n            cls.connections = [cls.connection_node_1, cls.connection_node_2]\n            cls.addresses = [\n                cls.connection_node_1.address,\n                cls.connection_node_2.address,\n            ]\n\n            for j in range(DEFAULT_CLIENTS_PER_NODE):\n                ports = [DEFAULT_DELEGATE_PORT + 1, DEFAULT_DELEGATE_PORT + 2]\n                peers_public_keys = [\n                    cls.connection_node_1.node.pub,\n                    cls.connection_node_2.node.pub,\n                ]\n                for i in range(len(ports)):\n                    port = ports[i]\n                    peer_public_key = peers_public_keys[i]\n                    temp_dir_client = os.path.join(cls.t, f\"temp_dir_client__{j}_{i}\")\n                    os.mkdir(temp_dir_client)\n                    conn = _make_libp2p_client_connection(\n                        data_dir=temp_dir_client,\n                        peer_public_key=peer_public_key,\n                        node_port=port,\n                    )\n                    mux = Multiplexer([conn], protocols=[MockDefaultMessageProtocol])\n\n                    cls.connections.append(conn)\n                    cls.addresses.append(conn.address)\n\n                    mux.connect()\n                    wait_for_condition((lambda m: lambda: m.is_connected)(mux), 10)\n                    wait_for_condition((lambda c: lambda: c.is_connected)(conn), 10)\n                    cls.multiplexers.append(mux)\n                break\n\n        except Exception:\n            cls.teardown_class()\n            raise\n\n    def test_connection_is_established(self):\n        \"\"\"Test connection is established.\"\"\"\n        for conn in self.connections:\n            assert conn.is_connected is True\n\n    def test_star_routing_connectivity(self):\n        \"\"\"Test routing with star connectivity.\"\"\"\n        msg = DefaultMessage(\n            dialogue_reference=(\"\", \"\"),\n            message_id=1,\n            target=0,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"hello\",\n        )\n        for source in range(len(self.multiplexers)):\n            for destination in range(len(self.multiplexers)):\n                if destination == source:\n                    continue\n                envelope = Envelope(\n                    to=self.addresses[destination],\n                    sender=self.addresses[source],\n                    protocol_specification_id=DefaultMessage.protocol_specification_id,\n                    message=DefaultSerializer().encode(msg),\n                )\n\n                self.multiplexers[source].put(envelope)\n                delivered_envelope = self.multiplexers[destination].get(\n                    block=True, timeout=10\n                )\n                assert delivered_envelope is not None\n                assert delivered_envelope.to == envelope.to\n                assert delivered_envelope.sender == envelope.sender\n                assert (\n                    delivered_envelope.protocol_specification_id\n                    == envelope.protocol_specification_id\n                )\n                assert delivered_envelope.message == envelope.message\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear down the test\"\"\"\n        for mux in reversed(cls.multiplexers):\n            mux.disconnect()\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\ndef test_libp2pclientconnection_uri():\n    \"\"\"Test the uri.\"\"\"\n    uri = Uri(host=\"127.0.0.1\")\n    uri = Uri(host=\"127.0.0.1\", port=10000)\n    assert uri.host == \"127.0.0.1\" and uri.port == 10000\n\n\n@libp2p_log_on_failure_all\nclass BaseTestLibp2pClientSamePeer:\n    \"\"\"Base test class for reconnection tests.\"\"\"\n\n    @classmethod\n    @libp2p_log_on_failure\n    def setup_class(cls):\n        \"\"\"Set the test up\"\"\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        os.chdir(cls.t)\n\n        MockDefaultMessageProtocol = Mock()\n        MockDefaultMessageProtocol.protocol_id = DefaultMessage.protocol_id\n        MockDefaultMessageProtocol.protocol_specification_id = (\n            DefaultMessage.protocol_specification_id\n        )\n\n        cls.log_files = []\n        temp_dir = os.path.join(cls.t, \"temp_dir_node\")\n        os.mkdir(temp_dir)\n        cls.connection_node = _make_libp2p_connection(\n            data_dir=temp_dir, port=DEFAULT_PORT + 1, delegate=True\n        )\n        cls.multiplexer_node = Multiplexer(\n            [cls.connection_node], protocols=[MockDefaultMessageProtocol]\n        )\n        cls.log_files.append(cls.connection_node.node.log_file)\n        cls.multiplexer_node.connect()\n\n        try:\n            temp_dir_client_1 = os.path.join(cls.t, \"temp_dir_client_1\")\n            os.mkdir(temp_dir_client_1)\n            cls.connection_client_1 = _make_libp2p_client_connection(\n                data_dir=temp_dir_client_1,\n                peer_public_key=cls.connection_node.node.pub,\n                ledger_api_id=FetchAICrypto.identifier,\n            )\n            cls.multiplexer_client_1 = Multiplexer(\n                [cls.connection_client_1], protocols=[MockDefaultMessageProtocol]\n            )\n            cls.multiplexer_client_1.connect()\n\n            temp_dir_client_2 = os.path.join(cls.t, \"temp_dir_client_2\")\n            os.mkdir(temp_dir_client_2)\n            cls.connection_client_2 = _make_libp2p_client_connection(\n                data_dir=temp_dir_client_2,\n                peer_public_key=cls.connection_node.node.pub,\n                ledger_api_id=EthereumCrypto.identifier,\n            )\n            cls.multiplexer_client_2 = Multiplexer(\n                [cls.connection_client_2], protocols=[MockDefaultMessageProtocol]\n            )\n            cls.multiplexer_client_2.connect()\n            wait_for_condition(lambda: cls.multiplexer_client_2.is_connected, 20)\n            wait_for_condition(lambda: cls.multiplexer_client_1.is_connected, 20)\n            wait_for_condition(lambda: cls.connection_client_2.is_connected, 20)\n            wait_for_condition(lambda: cls.connection_client_1.is_connected, 20)\n            wait_for_condition(lambda: cls.connection_node.is_connected, 20)\n        except Exception:\n            cls.multiplexer_node.disconnect()\n            raise\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear down the test\"\"\"\n        cls.multiplexer_client_1.disconnect()\n        cls.multiplexer_client_2.disconnect()\n        cls.multiplexer_node.disconnect()\n\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n    def _make_envelope(\n        self,\n        sender_address: str,\n        receiver_address: str,\n        message_id: int = 1,\n        target: int = 0,\n    ):\n        \"\"\"Make an envelope for testing purposes.\"\"\"\n        msg = DefaultMessage(\n            dialogue_reference=(\"\", \"\"),\n            message_id=message_id,\n            target=target,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"hello\",\n        )\n        envelope = Envelope(\n            to=receiver_address,\n            sender=sender_address,\n            protocol_specification_id=DefaultMessage.protocol_specification_id,\n            message=DefaultSerializer().encode(msg),\n        )\n        return envelope\n\n\n@libp2p_log_on_failure_all\nclass TestLibp2pClientReconnectionSendEnvelope(BaseTestLibp2pClientSamePeer):\n    \"\"\"Test that connection will send envelope with error, and that reconnection fixes it.\"\"\"\n\n    def test_envelope_sent(self):\n        \"\"\"Test the envelope is routed.\"\"\"\n        addr_1 = self.connection_client_1.address\n        addr_2 = self.connection_client_2.address\n        envelope = self._make_envelope(addr_1, addr_2)\n\n        # make the send to fail\n        with mock.patch.object(\n            self.connection_client_1.logger, \"exception\"\n        ) as _mock_logger, mock.patch.object(\n            self.connection_client_1._node_client, \"_write\", side_effect=Exception\n        ):\n            self.multiplexer_client_1.put(envelope)\n            delivered_envelope = self.multiplexer_client_2.get(block=True, timeout=20)\n            _mock_logger.assert_has_calls(\n                [\n                    call(\n                        \"Exception raised on message send. Try reconnect and send again.\"\n                    )\n                ]\n            )\n\n        assert delivered_envelope is not None\n        assert delivered_envelope.to == envelope.to\n        assert delivered_envelope.sender == envelope.sender\n        assert (\n            delivered_envelope.protocol_specification_id\n            == envelope.protocol_specification_id\n        )\n        assert delivered_envelope.message == envelope.message\n\n\n@libp2p_log_on_failure_all\nclass TestLibp2pClientReconnectionReceiveEnvelope(BaseTestLibp2pClientSamePeer):\n    \"\"\"Test that connection will receive envelope with error, and that reconnection fixes it.\"\"\"\n\n    def test_envelope_received(self):\n        \"\"\"Test the envelope is routed.\"\"\"\n        sender = self.connection_client_2.address\n        receiver = self.connection_client_1.address\n        envelope = self._make_envelope(sender, receiver)\n\n        # make the receive to fail\n        with mock.patch.object(\n            self.connection_client_1.logger, \"error\"\n        ) as _mock_logger, mock.patch.object(\n            self.connection_client_1._node_client,\n            \"_read\",\n            side_effect=ConnectionError(),\n        ):\n            # this envelope will be lost.\n            self.multiplexer_client_2.put(envelope)\n            # give time to reconnect\n            time.sleep(2.0)\n            _mock_logger.assert_has_calls(\n                [\n                    call(\n                        RegexComparator(\n                            \"Connection error:.*Try to reconnect and read again\"\n                        )\n                    )\n                ]\n            )\n        # proceed as usual. Now we expect the connection to have reconnected successfully\n        delivered_envelope = self.multiplexer_client_1.get(block=True, timeout=20)\n\n        assert delivered_envelope is not None\n        assert delivered_envelope.to == envelope.to\n        assert delivered_envelope.sender == envelope.sender\n        assert (\n            delivered_envelope.protocol_specification_id\n            == envelope.protocol_specification_id\n        )\n        assert delivered_envelope.message == envelope.message\n\n\nclass TestLibp2pClientEnvelopeOrderSamePeer(BaseTestLibp2pClientSamePeer):\n    \"\"\"Test that the order of envelope is the guaranteed to be the same.\"\"\"\n\n    NB_ENVELOPES = 1000\n\n    def test_burst_order(self):\n        \"\"\"Test order of envelope burst is guaranteed on receiving end.\"\"\"\n        addr_1 = self.connection_client_1.address\n        addr_2 = self.connection_client_2.address\n\n        sent_envelopes = [\n            self._make_envelope(addr_1, addr_2, i, i - 1)\n            for i in range(1, self.NB_ENVELOPES + 1)\n        ]\n        for envelope in sent_envelopes:\n            self.multiplexer_client_1.put(envelope)\n\n        received_envelopes = []\n        for _ in range(1, self.NB_ENVELOPES + 1):\n            envelope = self.multiplexer_client_2.get(block=True, timeout=20)\n            received_envelopes.append(envelope)\n\n        # test no new message is \"created\"\n        with pytest.raises(Empty):\n            self.multiplexer_client_2.get(block=True, timeout=1)\n\n        assert len(sent_envelopes) == len(\n            received_envelopes\n        ), f\"expected number of envelopes {len(sent_envelopes)}, got {len(received_envelopes)}\"\n        for expected, actual in zip(sent_envelopes, received_envelopes):\n            assert expected.message == actual.message, (\n                \"message content differ; probably a wrong message \"\n                \"ordering on the receiving end\"\n            )\n\n\n@pytest.mark.asyncio\nasync def test_nodeclient_pipe_connect():\n    \"\"\"Test pipe.connect called on NodeClient.connect.\"\"\"\n    f = asyncio.Future()\n    f.set_result(None)\n    pipe = Mock()\n    pipe.connect.return_value = f\n    node_client = NodeClient(pipe, Mock())\n    await node_client.connect()\n    pipe.connect.assert_called_once()\n\n\n@pytest.mark.asyncio\nasync def test_write_acn_error():\n    \"\"\"Test pipe.connect called on NodeClient.connect.\"\"\"\n    f = asyncio.Future()\n    f.set_result(None)\n    pipe = Mock()\n    pipe.write.return_value = f\n    node_client = NodeClient(pipe, Mock())\n    await node_client.write_acn_status_error(\"some message\")\n    pipe.write.assert_called_once()\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_connections/test_p2p_libp2p_client/test_errors.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This test module contains negative tests for Libp2p tcp client connection.\"\"\"\nimport asyncio\nimport os\nimport shutil\nimport tempfile\nfrom asyncio.futures import Future\nfrom unittest.mock import Mock, patch\n\nimport pytest\n\nfrom aea.configurations.base import ConnectionConfig\nfrom aea.configurations.constants import DEFAULT_LEDGER\nfrom aea.crypto.registries import make_crypto\nfrom aea.helpers.base import CertRequest\nfrom aea.identity.base import Identity\nfrom aea.multiplexer import Multiplexer\n\nfrom packages.fetchai.connections.p2p_libp2p_client.connection import (\n    NodeClient,\n    P2PLibp2pClientConnection,\n    POR_DEFAULT_SERVICE_ID,\n)\n\nfrom tests.conftest import (\n    _make_libp2p_client_connection,\n    _make_libp2p_connection,\n    _process_cert,\n    libp2p_log_on_failure,\n)\n\n\n@pytest.mark.asyncio\nclass TestLibp2pClientConnectionFailureNodeNotConnected:\n    \"\"\"Test that connection fails when node not running\"\"\"\n\n    @pytest.mark.asyncio\n    async def test_node_not_running(self):\n        \"\"\"Test the node is not running.\"\"\"\n        with tempfile.TemporaryDirectory() as dirname:\n            conn = _make_libp2p_client_connection(\n                data_dir=dirname, peer_public_key=make_crypto(DEFAULT_LEDGER).public_key\n            )\n            with pytest.raises(Exception):\n                await conn.connect()\n\n\nclass TestLibp2pClientConnectionFailureConnectionSetup:\n    \"\"\"Test that connection fails when setup incorrectly\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up\"\"\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        os.chdir(cls.t)\n        crypto = make_crypto(DEFAULT_LEDGER)\n        cls.node_host = \"localhost\"\n        cls.node_port = \"11234\"\n        cls.identity = Identity(\n            \"identity\", address=crypto.address, public_key=crypto.public_key\n        )\n\n        cls.key_file = os.path.join(cls.t, \"keyfile\")\n        crypto.dump(cls.key_file)\n\n        cls.peer_crypto = make_crypto(DEFAULT_LEDGER)\n        cls.cert_request = CertRequest(\n            cls.peer_crypto.public_key,\n            POR_DEFAULT_SERVICE_ID,\n            DEFAULT_LEDGER,\n            \"2021-01-01\",\n            \"2021-01-02\",\n            \"{public_key}\",\n            f\"./{crypto.address}_cert.txt\",\n        )\n        _process_cert(crypto, cls.cert_request, cls.t)\n\n    def test_empty_nodes(self):\n        \"\"\"Test empty nodes.\"\"\"\n        configuration = ConnectionConfig(\n            tcp_key_file=self.key_file,\n            nodes=[\n                {\n                    \"uri\": \"{}:{}\".format(self.node_host, self.node_port),\n                    \"public_key\": self.peer_crypto.public_key,\n                }\n            ],\n            connection_id=P2PLibp2pClientConnection.connection_id,\n            cert_requests=[self.cert_request],\n        )\n        P2PLibp2pClientConnection(\n            configuration=configuration, data_dir=self.t, identity=self.identity\n        )\n\n        configuration = ConnectionConfig(\n            tcp_key_file=self.key_file,\n            nodes=None,\n            connection_id=P2PLibp2pClientConnection.connection_id,\n        )\n        with pytest.raises(Exception):\n            P2PLibp2pClientConnection(\n                configuration=configuration,\n                data_dir=self.t,\n                identity=self.identity,\n            )\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear down the test\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestLibp2pClientConnectionNodeDisconnected:\n    \"\"\"Test that connection will properly handle node disconnecting\"\"\"\n\n    @classmethod\n    @libp2p_log_on_failure\n    def setup_class(cls):\n        \"\"\"Set the test up\"\"\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        os.chdir(cls.t)\n\n        cls.log_files = []\n        cls.multiplexers = []\n\n        temp_node_dir = os.path.join(cls.t, \"node_dir\")\n        os.mkdir(temp_node_dir)\n        try:\n            cls.connection_node = _make_libp2p_connection(\n                data_dir=temp_node_dir, delegate=True\n            )\n            cls.multiplexer_node = Multiplexer([cls.connection_node])\n            cls.log_files.append(cls.connection_node.node.log_file)\n            cls.multiplexer_node.connect()\n            cls.multiplexers.append(cls.multiplexer_node)\n\n            temp_client_dir = os.path.join(cls.t, \"client_dir\")\n            os.mkdir(temp_client_dir)\n            cls.connection_client = _make_libp2p_client_connection(\n                data_dir=temp_client_dir, peer_public_key=cls.connection_node.node.pub\n            )\n            cls.multiplexer_client = Multiplexer([cls.connection_client])\n            cls.multiplexer_client.connect()\n            cls.multiplexers.append(cls.multiplexer_client)\n        except Exception:\n            cls.teardown_class()\n            raise\n\n    def test_node_disconnected(self):\n        \"\"\"Test node disconnected.\"\"\"\n        assert self.connection_client.is_connected is True\n        self.multiplexer_client.disconnect()\n        self.multiplexer_node.disconnect()\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear down the test\"\"\"\n        for mux in cls.multiplexers:\n            mux.disconnect()\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\ndone_future: asyncio.Future = asyncio.Future()\ndone_future.set_result(None)\n\n\n@pytest.mark.asyncio\nasync def test_connect_attempts():\n    \"\"\"Test connect attempts.\"\"\"\n    # test connects\n    with tempfile.TemporaryDirectory() as dirname:\n        con = _make_libp2p_client_connection(\n            data_dir=dirname, peer_public_key=make_crypto(DEFAULT_LEDGER).public_key\n        )\n        con.connect_retries = 2\n        with patch(\n            \"aea.helpers.pipe.TCPSocketChannelClient.connect\",\n            side_effect=Exception(\"test exception on connect\"),\n        ) as open_connection_mock:\n            with pytest.raises(Exception, match=\"test exception on connect\"):\n                await con.connect()\n            assert open_connection_mock.call_count == con.connect_retries\n\n\n@pytest.mark.asyncio\nasync def test_reconnect_on_receive_fail():\n    \"\"\"Test reconnect on receive fails.\"\"\"\n    with tempfile.TemporaryDirectory() as dirname:\n        con = _make_libp2p_client_connection(\n            data_dir=dirname, peer_public_key=make_crypto(DEFAULT_LEDGER).public_key\n        )\n        con._in_queue = Mock()\n        con._node_client = Mock()\n        exception_future = Future()\n        exception_future.set_exception(ConnectionError(\"oops\"))\n        result = Future()\n        result.set_result(None)\n        con._node_client.read_envelope.side_effect = [exception_future, result]\n\n        with patch.object(\n            con, \"_perform_connection_to_node\", return_value=done_future\n        ) as connect_mock:\n            assert await con._read_envelope_from_node() is None\n            connect_mock.assert_called()\n\n\n@pytest.mark.asyncio\nasync def test_reconnect_on_send_fail():\n    \"\"\"Test reconnect on send fails.\"\"\"\n    with tempfile.TemporaryDirectory() as dirname:\n        con = _make_libp2p_client_connection(\n            data_dir=dirname, peer_public_key=make_crypto(DEFAULT_LEDGER).public_key\n        )\n        con._node_client = Mock()\n        f = Future()\n        f.set_exception(Exception(\"oops\"))\n        con._node_client.send_envelope.side_effect = Exception(\"oops\")\n        # test reconnect on send fails\n        with patch.object(\n            con, \"_perform_connection_to_node\", return_value=done_future\n        ) as connect_mock, patch.object(\n            con, \"_ensure_valid_envelope_for_external_comms\"\n        ):\n            with pytest.raises(Exception, match=\"oops\"):\n                await con._send_envelope_with_node_client(Mock())\n            connect_mock.assert_called()\n\n\n@pytest.mark.asyncio\nasync def test_acn_decode_error_on_read():\n    \"\"\"Test nodeclient send fails on read.\"\"\"\n    f = Future()\n    f.set_result(b\"some_data\")\n    pipe = Mock()\n    pipe.connect = Mock(return_value=f)\n\n    node_client = NodeClient(pipe, Mock())\n    with patch.object(node_client, \"_read\", lambda: f), patch.object(\n        node_client, \"write_acn_status_error\", return_value=f\n    ) as mocked_write_acn_status_error, pytest.raises(\n        Exception, match=r\"Error parsing acn message:\"\n    ):\n        await node_client.read_envelope()\n\n    mocked_write_acn_status_error.assert_called_once()\n\n\n@pytest.mark.asyncio\nclass TestLibp2pClientConnectionCheckSignature:\n    \"\"\"Test that TLS signature is checked properly.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up\"\"\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        os.chdir(cls.t)\n\n        temp_dir = os.path.join(cls.t, \"temp_dir_node\")\n        os.mkdir(temp_dir)\n        cls.connection_node = _make_libp2p_connection(data_dir=temp_dir, delegate=True)\n        temp_dir_client = os.path.join(cls.t, \"temp_dir_client\")\n        os.mkdir(temp_dir_client)\n        cls.connection = _make_libp2p_client_connection(\n            data_dir=temp_dir_client, peer_public_key=cls.connection_node.node.pub\n        )\n\n    @pytest.mark.asyncio\n    async def test_signature_check_fail(self):\n        \"\"\"Test signature check failed.\"\"\"\n        key = make_crypto(DEFAULT_LEDGER)\n\n        assert self.connection.is_connected is False\n        await self.connection_node.connect()\n        self.connection.connect_retries = 1\n        try:\n            self.connection.node_por._representative_public_key = key.public_key\n            with pytest.raises(\n                ValueError,\n                match=\".*Invalid TLS session key signature: Signature verification failed.*\",\n            ):\n                await self.connection.connect()\n            assert self.connection.is_connected is False\n        finally:\n            await self.connection_node.disconnect()\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear down the test\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_connections/test_p2p_libp2p_mailbox/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests of the Libp2p client connection.\"\"\"\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_connections/test_p2p_libp2p_mailbox/test_aea_cli.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This test module contains AEA cli tests for Libp2p tcp client connection.\"\"\"\nimport os\n\nfrom aea_ledger_fetchai import FetchAICrypto\n\nfrom aea.helpers.base import CertRequest\nfrom aea.multiplexer import Multiplexer\nfrom aea.test_tools.test_cases import AEATestCaseEmpty\n\nfrom packages.fetchai.connections.p2p_libp2p_mailbox.connection import PUBLIC_ID\n\nfrom tests.conftest import (\n    _make_libp2p_connection,\n    libp2p_log_on_failure,\n    libp2p_log_on_failure_all,\n)\n\n\nDEFAULT_PORT = 10234\nDEFAULT_DELEGATE_PORT = 11234\nDEFAULT_HOST = \"127.0.0.1\"\nDEFAULT_MAILBOX_PORT = 8888\nDEFAULT_CLIENTS_PER_NODE = 4\n\nDEFAULT_LAUNCH_TIMEOUT = 10\n\n\n@libp2p_log_on_failure_all\nclass TestP2PLibp2pClientConnectionAEARunning(AEATestCaseEmpty):\n    \"\"\"Test AEA with p2p_libp2p_client connection is correctly run\"\"\"\n\n    @classmethod\n    @libp2p_log_on_failure\n    def setup_class(cls):\n        \"\"\"Set up the test class.\"\"\"\n        super(TestP2PLibp2pClientConnectionAEARunning, cls).setup_class()\n\n        temp_dir = os.path.join(cls.t, \"temp_dir_node\")\n        os.mkdir(temp_dir)\n        cls.node_connection = _make_libp2p_connection(\n            data_dir=temp_dir,\n            delegate_host=DEFAULT_HOST,\n            delegate_port=DEFAULT_DELEGATE_PORT,\n            mailbox_port=DEFAULT_MAILBOX_PORT,\n            delegate=True,\n            mailbox=True,\n        )\n        cls.node_multiplexer = Multiplexer([cls.node_connection])\n        cls.log_files = [cls.node_connection.node.log_file]\n\n        cls.node_multiplexer.connect()\n\n    def test_node(self):\n        \"\"\"Test the node is connected.\"\"\"\n        assert self.node_connection.is_connected is True\n\n    def test_connection(self):\n        \"\"\"Test the connection can be used in an aea.\"\"\"\n        self.generate_private_key()\n        self.add_private_key()\n        self.add_item(\"connection\", str(PUBLIC_ID))\n        conn_path = \"vendor.fetchai.connections.p2p_libp2p_mailbox\"\n        self.nested_set_config(\n            conn_path + \".config\",\n            {\n                \"nodes\": [\n                    {\n                        \"uri\": \"{}:{}\".format(DEFAULT_HOST, DEFAULT_MAILBOX_PORT),\n                        \"public_key\": self.node_connection.node.pub,\n                    }\n                ]\n            },\n        )\n\n        # generate certificates for connection\n        self.nested_set_config(\n            conn_path + \".cert_requests\",\n            [\n                CertRequest(\n                    identifier=\"acn\",\n                    ledger_id=FetchAICrypto.identifier,\n                    not_after=\"2022-01-01\",\n                    not_before=\"2021-01-01\",\n                    public_key=self.node_connection.node.pub,\n                    message_format=\"{public_key}\",\n                    save_path=\"./cli_test_cert.txt\",\n                )\n            ],\n        )\n        self.run_cli_command(\"issue-certificates\", cwd=self._get_cwd())\n\n        process = self.run_agent()\n        is_running = self.is_running(process, timeout=DEFAULT_LAUNCH_TIMEOUT)\n        assert is_running, \"AEA not running within timeout!\"\n\n        check_strings = \"Successfully connected to libp2p node {}:{}\".format(\n            DEFAULT_HOST, DEFAULT_MAILBOX_PORT\n        )\n        missing_strings = self.missing_from_output(process, check_strings)\n        assert (\n            missing_strings == []\n        ), \"Strings {} didn't appear in agent output.\".format(missing_strings)\n\n        self.terminate_agents(process)\n        assert self.is_successfully_terminated(\n            process\n        ), \"AEA wasn't successfully terminated.\"\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear down the test\"\"\"\n        cls.terminate_agents()\n\n        super(TestP2PLibp2pClientConnectionAEARunning, cls).teardown_class()\n\n        cls.node_multiplexer.disconnect()\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_connections/test_p2p_libp2p_mailbox/test_communication.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This test module contains tests for Libp2p tcp client connection.\"\"\"\nimport os\nimport shutil\nimport tempfile\nfrom unittest.mock import Mock\n\nimport pytest\nfrom aea_ledger_ethereum import EthereumCrypto\nfrom aea_ledger_fetchai import FetchAICrypto\n\nfrom aea.mail.base import Empty, Envelope\nfrom aea.multiplexer import Multiplexer\n\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.protocols.default.serialization import DefaultSerializer\n\nfrom tests.common.utils import wait_for_condition\nfrom tests.conftest import (\n    _make_libp2p_connection,\n    _make_libp2p_mailbox_connection,\n    libp2p_log_on_failure,\n    libp2p_log_on_failure_all,\n)\n\n\nDEFAULT_PORT = 10234\nDEFAULT_DELEGATE_PORT = 11234\nDEFAULT_MAILBOX_PORT = 8888\nDEFAULT_HOST = \"127.0.0.1\"\nDEFAULT_CLIENTS_PER_NODE = 1\n\nMockDefaultMessageProtocol = Mock()\nMockDefaultMessageProtocol.protocol_id = DefaultMessage.protocol_id\nMockDefaultMessageProtocol.protocol_specification_id = (\n    DefaultMessage.protocol_specification_id\n)\n\n\n@pytest.mark.asyncio\nclass TestLibp2pClientConnectionConnectDisconnect:\n    \"\"\"Test that connection is established and torn down correctly\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up\"\"\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        os.chdir(cls.t)\n\n        temp_dir = os.path.join(cls.t, \"temp_dir_node\")\n        os.mkdir(temp_dir)\n        cls.connection_node = _make_libp2p_connection(\n            data_dir=temp_dir, delegate=True, mailbox=True\n        )\n        temp_dir_client = os.path.join(cls.t, \"temp_dir_client\")\n        os.mkdir(temp_dir_client)\n        cls.connection = _make_libp2p_mailbox_connection(\n            data_dir=temp_dir_client,\n            peer_public_key=cls.connection_node.node.pub,\n        )\n\n    @pytest.mark.asyncio\n    async def test_libp2pclientconnection_connect_disconnect(self):\n        \"\"\"Test connnect then disconnect.\"\"\"\n        assert self.connection.is_connected is False\n        try:\n            await self.connection_node.connect()\n            await self.connection.connect()\n            assert self.connection.is_connected is True\n\n            await self.connection.disconnect()\n            assert self.connection.is_connected is False\n        except Exception:\n            raise\n        finally:\n            await self.connection_node.disconnect()\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear down the test\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\n@libp2p_log_on_failure_all\nclass TestLibp2pClientConnectionEchoEnvelope:\n    \"\"\"Test that connection will route envelope to destination through the same libp2p node\"\"\"\n\n    @classmethod\n    @libp2p_log_on_failure\n    def setup_class(cls):\n        \"\"\"Set the test up\"\"\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        os.chdir(cls.t)\n\n        cls.log_files = []\n        temp_dir = os.path.join(cls.t, \"temp_dir_node\")\n        os.mkdir(temp_dir)\n        cls.connection_node = _make_libp2p_connection(\n            data_dir=temp_dir, port=DEFAULT_PORT + 1, delegate=True, mailbox=True\n        )\n        cls.multiplexer_node = Multiplexer(\n            [cls.connection_node], protocols=[MockDefaultMessageProtocol]\n        )\n        cls.log_files.append(cls.connection_node.node.log_file)\n        cls.multiplexer_node.connect()\n\n        try:\n            temp_dir_client_1 = os.path.join(cls.t, \"temp_dir_client_1\")\n            os.mkdir(temp_dir_client_1)\n            cls.connection_client_1 = _make_libp2p_mailbox_connection(\n                data_dir=temp_dir_client_1,\n                peer_public_key=cls.connection_node.node.pub,\n                ledger_api_id=FetchAICrypto.identifier,\n            )\n            cls.multiplexer_client_1 = Multiplexer(\n                [cls.connection_client_1], protocols=[MockDefaultMessageProtocol]\n            )\n            cls.multiplexer_client_1.connect()\n\n            temp_dir_client_2 = os.path.join(cls.t, \"temp_dir_client_2\")\n            os.mkdir(temp_dir_client_2)\n            cls.connection_client_2 = _make_libp2p_mailbox_connection(\n                data_dir=temp_dir_client_2,\n                peer_public_key=cls.connection_node.node.pub,\n                ledger_api_id=EthereumCrypto.identifier,\n            )\n            cls.multiplexer_client_2 = Multiplexer(\n                [cls.connection_client_2], protocols=[MockDefaultMessageProtocol]\n            )\n            cls.multiplexer_client_2.connect()\n\n            wait_for_condition(lambda: cls.connection_client_1.is_connected is True, 10)\n            wait_for_condition(lambda: cls.connection_client_2.is_connected is True, 10)\n        except Exception:\n            cls.multiplexer_node.disconnect()\n            raise\n\n    def test_connection_is_established(self):\n        \"\"\"Test connection is established.\"\"\"\n        assert self.connection_client_1.is_connected is True\n        assert self.connection_client_2.is_connected is True\n\n    def test_envelope_routed(self):\n        \"\"\"Test the envelope is routed.\"\"\"\n        addr_1 = self.connection_client_1.address\n        addr_2 = self.connection_client_2.address\n\n        msg = DefaultMessage(\n            dialogue_reference=(\"\", \"\"),\n            message_id=1,\n            target=0,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"hello\",\n        )\n        envelope = Envelope(\n            to=addr_2,\n            sender=addr_1,\n            protocol_specification_id=DefaultMessage.protocol_specification_id,\n            message=DefaultSerializer().encode(msg),\n        )\n\n        self.multiplexer_client_1.put(envelope)\n        delivered_envelope = self.multiplexer_client_2.get(block=True, timeout=20)\n\n        assert delivered_envelope is not None\n        assert delivered_envelope.to == envelope.to\n        assert delivered_envelope.sender == envelope.sender\n        assert (\n            delivered_envelope.protocol_specification_id\n            == envelope.protocol_specification_id\n        )\n        assert delivered_envelope.message == envelope.message\n\n    def test_envelope_echoed_back(self):\n        \"\"\"Test the envelope is echoed back.\"\"\"\n        addr_1 = self.connection_client_1.address\n        addr_2 = self.connection_client_2.address\n\n        msg = DefaultMessage(\n            dialogue_reference=(\"\", \"\"),\n            message_id=1,\n            target=0,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"hello\",\n        )\n        original_envelope = Envelope(\n            to=addr_2,\n            sender=addr_1,\n            protocol_specification_id=DefaultMessage.protocol_specification_id,\n            message=DefaultSerializer().encode(msg),\n        )\n\n        self.multiplexer_client_1.put(original_envelope)\n        delivered_envelope = self.multiplexer_client_2.get(block=True, timeout=10)\n        assert delivered_envelope is not None\n\n        delivered_envelope.to = addr_1\n        delivered_envelope.sender = addr_2\n\n        self.multiplexer_client_2.put(delivered_envelope)\n        echoed_envelope = self.multiplexer_client_1.get(block=True, timeout=5)\n\n        assert echoed_envelope is not None\n        assert echoed_envelope.to == original_envelope.sender\n        assert delivered_envelope.sender == original_envelope.to\n        assert (\n            delivered_envelope.protocol_specification_id\n            == original_envelope.protocol_specification_id\n        )\n        assert delivered_envelope.message == original_envelope.message\n\n    def test_envelope_echoed_back_node_agent(self):\n        \"\"\"Test the envelope is echoed back.\"\"\"\n        addr_1 = self.connection_client_1.address\n        addr_n = self.connection_node.address\n\n        msg = DefaultMessage(\n            dialogue_reference=(\"\", \"\"),\n            message_id=1,\n            target=0,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"hello\",\n        )\n        original_envelope = Envelope(\n            to=addr_n,\n            sender=addr_1,\n            protocol_specification_id=DefaultMessage.protocol_specification_id,\n            message=DefaultSerializer().encode(msg),\n        )\n\n        self.multiplexer_client_1.put(original_envelope)\n        delivered_envelope = self.multiplexer_node.get(block=True, timeout=10)\n        assert delivered_envelope is not None\n\n        delivered_envelope.to = addr_1\n        delivered_envelope.sender = addr_n\n\n        self.multiplexer_node.put(delivered_envelope)\n        echoed_envelope = self.multiplexer_client_1.get(block=True, timeout=5)\n\n        assert echoed_envelope is not None\n        assert echoed_envelope.to == original_envelope.sender\n        assert delivered_envelope.sender == original_envelope.to\n        assert (\n            delivered_envelope.protocol_specification_id\n            == original_envelope.protocol_specification_id\n        )\n        assert delivered_envelope.message == original_envelope.message\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear down the test\"\"\"\n        cls.multiplexer_client_1.disconnect()\n        cls.multiplexer_client_2.disconnect()\n        cls.multiplexer_node.disconnect()\n\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\n@libp2p_log_on_failure_all\nclass TestLibp2pClientConnectionEchoEnvelopeTwoDHTNode:\n    \"\"\"Test that connection will route envelope to destination connected to different node\"\"\"\n\n    @classmethod\n    @libp2p_log_on_failure\n    def setup_class(cls):\n        \"\"\"Set the test up\"\"\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        os.chdir(cls.t)\n\n        cls.log_files = []\n        cls.mutliplexers = []\n\n        temp_dir_node_1 = os.path.join(cls.t, \"temp_dir_node_1\")\n        os.mkdir(temp_dir_node_1)\n        cls.connection_node_1 = _make_libp2p_connection(\n            data_dir=temp_dir_node_1,\n            port=DEFAULT_PORT + 1,\n            delegate_port=DEFAULT_DELEGATE_PORT + 1,\n            mailbox_port=DEFAULT_MAILBOX_PORT + 1,\n            delegate=True,\n            mailbox=True,\n        )\n        cls.multiplexer_node_1 = Multiplexer(\n            [cls.connection_node_1], protocols=[MockDefaultMessageProtocol]\n        )\n        cls.log_files.append(cls.connection_node_1.node.log_file)\n        cls.multiplexer_node_1.connect()\n        cls.mutliplexers.append(cls.multiplexer_node_1)\n\n        genesis_peer = cls.connection_node_1.node.multiaddrs[0]\n\n        temp_dir_node_2 = os.path.join(cls.t, \"temp_dir_node_2\")\n        os.mkdir(temp_dir_node_2)\n        try:\n            cls.connection_node_2 = _make_libp2p_connection(\n                data_dir=temp_dir_node_2,\n                port=DEFAULT_PORT + 2,\n                delegate_port=DEFAULT_DELEGATE_PORT + 2,\n                mailbox_port=DEFAULT_MAILBOX_PORT + 2,\n                entry_peers=[genesis_peer],\n                delegate=True,\n                mailbox=True,\n            )\n            cls.multiplexer_node_2 = Multiplexer(\n                [cls.connection_node_2], protocols=[MockDefaultMessageProtocol]\n            )\n            cls.log_files.append(cls.connection_node_2.node.log_file)\n            cls.multiplexer_node_2.connect()\n            cls.mutliplexers.append(cls.multiplexer_node_2)\n\n            temp_dir_client_1 = os.path.join(cls.t, \"temp_dir_client_1\")\n            os.mkdir(temp_dir_client_1)\n            cls.connection_client_1 = _make_libp2p_mailbox_connection(\n                data_dir=temp_dir_client_1,\n                peer_public_key=cls.connection_node_1.node.pub,\n                node_port=DEFAULT_MAILBOX_PORT + 1,\n            )\n            cls.multiplexer_client_1 = Multiplexer(\n                [cls.connection_client_1], protocols=[MockDefaultMessageProtocol]\n            )\n            cls.multiplexer_client_1.connect()\n            cls.mutliplexers.append(cls.multiplexer_client_1)\n\n            temp_dir_client_2 = os.path.join(cls.t, \"temp_dir_client_2\")\n            os.mkdir(temp_dir_client_2)\n            cls.connection_client_2 = _make_libp2p_mailbox_connection(\n                data_dir=temp_dir_client_2,\n                peer_public_key=cls.connection_node_2.node.pub,\n                node_port=DEFAULT_MAILBOX_PORT + 2,\n            )\n            cls.multiplexer_client_2 = Multiplexer(\n                [cls.connection_client_2], protocols=[MockDefaultMessageProtocol]\n            )\n            cls.multiplexer_client_2.connect()\n            cls.mutliplexers.append(cls.multiplexer_client_2)\n\n            wait_for_condition(lambda: cls.connection_node_1.is_connected is True, 10)\n            wait_for_condition(lambda: cls.connection_node_2.is_connected is True, 10)\n            wait_for_condition(lambda: cls.connection_client_1.is_connected is True, 10)\n            wait_for_condition(lambda: cls.connection_client_2.is_connected is True, 10)\n\n        except Exception:\n            cls.teardown_class()\n            raise\n\n    def test_connection_is_established(self):\n        \"\"\"Test the connection is established.\"\"\"\n        assert self.connection_node_1.is_connected is True\n        assert self.connection_node_2.is_connected is True\n        assert self.connection_client_1.is_connected is True\n        assert self.connection_client_2.is_connected is True\n\n    def test_envelope_routed(self):\n        \"\"\"Test the envelope is routed.\"\"\"\n        addr_1 = self.connection_client_1.address\n        addr_2 = self.connection_client_2.address\n\n        msg = DefaultMessage(\n            dialogue_reference=(\"\", \"\"),\n            message_id=1,\n            target=0,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"hello\",\n        )\n        envelope = Envelope(\n            to=addr_2,\n            sender=addr_1,\n            protocol_specification_id=DefaultMessage.protocol_specification_id,\n            message=DefaultSerializer().encode(msg),\n        )\n\n        self.multiplexer_client_1.put(envelope)\n        delivered_envelope = self.multiplexer_client_2.get(block=True, timeout=20)\n\n        assert delivered_envelope is not None\n        assert delivered_envelope.to == envelope.to\n        assert delivered_envelope.sender == envelope.sender\n        assert (\n            delivered_envelope.protocol_specification_id\n            == envelope.protocol_specification_id\n        )\n        assert delivered_envelope.message == envelope.message\n\n    def test_envelope_echoed_back(self):\n        \"\"\"Test the envelope is echoed back.\"\"\"\n        addr_1 = self.connection_client_1.address\n        addr_2 = self.connection_client_2.address\n\n        msg = DefaultMessage(\n            dialogue_reference=(\"\", \"\"),\n            message_id=1,\n            target=0,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"hello\",\n        )\n        original_envelope = Envelope(\n            to=addr_2,\n            sender=addr_1,\n            protocol_specification_id=DefaultMessage.protocol_specification_id,\n            message=DefaultSerializer().encode(msg),\n        )\n\n        self.multiplexer_client_1.put(original_envelope)\n        delivered_envelope = self.multiplexer_client_2.get(block=True, timeout=10)\n        assert delivered_envelope is not None\n\n        delivered_envelope.to = addr_1\n        delivered_envelope.sender = addr_2\n\n        self.multiplexer_client_2.put(delivered_envelope)\n        echoed_envelope = self.multiplexer_client_1.get(block=True, timeout=5)\n\n        assert echoed_envelope is not None\n        assert echoed_envelope.to == original_envelope.sender\n        assert delivered_envelope.sender == original_envelope.to\n        assert (\n            delivered_envelope.protocol_specification_id\n            == original_envelope.protocol_specification_id\n        )\n        assert delivered_envelope.message == original_envelope.message\n\n    def test_envelope_echoed_back_node_agent(self):\n        \"\"\"Test the envelope is echoed back node agent.\"\"\"\n        addr_1 = self.connection_client_1.address\n        addr_n = self.connection_node_2.address\n\n        msg = DefaultMessage(\n            dialogue_reference=(\"\", \"\"),\n            message_id=1,\n            target=0,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"hello\",\n        )\n        original_envelope = Envelope(\n            to=addr_n,\n            sender=addr_1,\n            protocol_specification_id=DefaultMessage.protocol_specification_id,\n            message=DefaultSerializer().encode(msg),\n        )\n\n        self.multiplexer_client_1.put(original_envelope)\n        delivered_envelope = self.multiplexer_node_2.get(block=True, timeout=10)\n        assert delivered_envelope is not None\n\n        delivered_envelope.to = addr_1\n        delivered_envelope.sender = addr_n\n\n        self.multiplexer_node_2.put(delivered_envelope)\n        echoed_envelope = self.multiplexer_client_1.get(block=True, timeout=5)\n\n        assert echoed_envelope is not None\n        assert echoed_envelope.to == original_envelope.sender\n        assert delivered_envelope.sender == original_envelope.to\n        assert (\n            delivered_envelope.protocol_specification_id\n            == original_envelope.protocol_specification_id\n        )\n        assert delivered_envelope.message == original_envelope.message\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear down the test\"\"\"\n        for mux in reversed(cls.mutliplexers):\n            mux.disconnect()\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\n@libp2p_log_on_failure_all\nclass TestLibp2pClientConnectionRouting:\n    \"\"\"Test that libp2p DHT network will reliably route envelopes from clients connected to different nodes\"\"\"\n\n    @classmethod\n    @libp2p_log_on_failure\n    def setup_class(cls):\n        \"\"\"Set the test up\"\"\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        os.chdir(cls.t)\n\n        cls.log_files = []\n        cls.multiplexers = []\n\n        try:\n            temp_dir_node_1 = os.path.join(cls.t, \"temp_dir_node_1\")\n            os.mkdir(temp_dir_node_1)\n            cls.connection_node_1 = _make_libp2p_connection(\n                data_dir=temp_dir_node_1,\n                port=DEFAULT_PORT + 1,\n                delegate_port=DEFAULT_DELEGATE_PORT + 1,\n                mailbox_port=DEFAULT_MAILBOX_PORT + 1,\n                delegate=True,\n                mailbox=True,\n            )\n            cls.multiplexer_node_1 = Multiplexer(\n                [cls.connection_node_1], protocols=[MockDefaultMessageProtocol]\n            )\n            cls.log_files.append(cls.connection_node_1.node.log_file)\n            cls.multiplexer_node_1.connect()\n            cls.multiplexers.append(cls.multiplexer_node_1)\n\n            entry_peer = cls.connection_node_1.node.multiaddrs[0]\n\n            temp_dir_node_2 = os.path.join(cls.t, \"temp_dir_node_2\")\n            os.mkdir(temp_dir_node_2)\n            cls.connection_node_2 = _make_libp2p_connection(\n                data_dir=temp_dir_node_2,\n                port=DEFAULT_PORT + 2,\n                delegate_port=DEFAULT_DELEGATE_PORT + 2,\n                mailbox_port=DEFAULT_MAILBOX_PORT + 2,\n                entry_peers=[entry_peer],\n                delegate=True,\n                mailbox=True,\n            )\n            cls.multiplexer_node_2 = Multiplexer(\n                [cls.connection_node_2], protocols=[MockDefaultMessageProtocol]\n            )\n            cls.log_files.append(cls.connection_node_2.node.log_file)\n            cls.multiplexer_node_2.connect()\n\n            cls.multiplexers.append(cls.multiplexer_node_2)\n\n            wait_for_condition(lambda: cls.multiplexer_node_1.is_connected, 10)\n            wait_for_condition(lambda: cls.multiplexer_node_2.is_connected, 10)\n            wait_for_condition(lambda: cls.connection_node_1.is_connected, 10)\n            wait_for_condition(lambda: cls.connection_node_2.is_connected, 10)\n            cls.connections = [cls.connection_node_1, cls.connection_node_2]\n            cls.addresses = [\n                cls.connection_node_1.address,\n                cls.connection_node_2.address,\n            ]\n\n            for j in range(DEFAULT_CLIENTS_PER_NODE):\n                ports = [DEFAULT_MAILBOX_PORT + 1, DEFAULT_MAILBOX_PORT + 2]\n                peers_public_keys = [\n                    cls.connection_node_1.node.pub,\n                    cls.connection_node_2.node.pub,\n                ]\n                for i in range(len(ports)):\n                    port = ports[i]\n                    peer_public_key = peers_public_keys[i]\n                    temp_dir_client = os.path.join(cls.t, f\"temp_dir_client__{j}_{i}\")\n                    os.mkdir(temp_dir_client)\n                    conn = _make_libp2p_mailbox_connection(\n                        data_dir=temp_dir_client,\n                        peer_public_key=peer_public_key,\n                        node_port=port,\n                    )\n                    mux = Multiplexer([conn], protocols=[MockDefaultMessageProtocol])\n\n                    cls.connections.append(conn)\n                    cls.addresses.append(conn.address)\n\n                    mux.connect()\n                    wait_for_condition((lambda m: lambda: m.is_connected)(mux), 10)\n                    wait_for_condition((lambda c: lambda: c.is_connected)(conn), 10)\n                    cls.multiplexers.append(mux)\n                break\n\n        except Exception:\n            cls.teardown_class()\n            raise\n\n    def test_connection_is_established(self):\n        \"\"\"Test connection is established.\"\"\"\n        for conn in self.connections:\n            assert conn.is_connected is True\n\n    def test_star_routing_connectivity(self):\n        \"\"\"Test routing with star connectivity.\"\"\"\n        msg = DefaultMessage(\n            dialogue_reference=(\"\", \"\"),\n            message_id=1,\n            target=0,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"hello\",\n        )\n        for source in range(len(self.multiplexers)):\n            for destination in range(len(self.multiplexers)):\n                if destination == source:\n                    continue\n                envelope = Envelope(\n                    to=self.addresses[destination],\n                    sender=self.addresses[source],\n                    protocol_specification_id=DefaultMessage.protocol_specification_id,\n                    message=DefaultSerializer().encode(msg),\n                )\n\n                self.multiplexers[source].put(envelope)\n                delivered_envelope = self.multiplexers[destination].get(\n                    block=True, timeout=10\n                )\n                assert delivered_envelope is not None\n                assert delivered_envelope.to == envelope.to\n                assert delivered_envelope.sender == envelope.sender\n                assert (\n                    delivered_envelope.protocol_specification_id\n                    == envelope.protocol_specification_id\n                )\n                assert delivered_envelope.message == envelope.message\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear down the test\"\"\"\n        for mux in reversed(cls.multiplexers):\n            mux.disconnect()\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\n@libp2p_log_on_failure_all\nclass BaseTestLibp2pClientSamePeer:\n    \"\"\"Base test class for reconnection tests.\"\"\"\n\n    @classmethod\n    @libp2p_log_on_failure\n    def setup_class(cls):\n        \"\"\"Set the test up\"\"\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        os.chdir(cls.t)\n\n        MockDefaultMessageProtocol = Mock()\n        MockDefaultMessageProtocol.protocol_id = DefaultMessage.protocol_id\n        MockDefaultMessageProtocol.protocol_specification_id = (\n            DefaultMessage.protocol_specification_id\n        )\n\n        cls.log_files = []\n        temp_dir = os.path.join(cls.t, \"temp_dir_node\")\n        os.mkdir(temp_dir)\n        cls.connection_node = _make_libp2p_connection(\n            data_dir=temp_dir, port=DEFAULT_PORT + 1, delegate=True, mailbox=True\n        )\n        cls.multiplexer_node = Multiplexer(\n            [cls.connection_node], protocols=[MockDefaultMessageProtocol]\n        )\n        cls.log_files.append(cls.connection_node.node.log_file)\n        cls.multiplexer_node.connect()\n\n        try:\n            temp_dir_client_1 = os.path.join(cls.t, \"temp_dir_client_1\")\n            os.mkdir(temp_dir_client_1)\n            cls.connection_client_1 = _make_libp2p_mailbox_connection(\n                data_dir=temp_dir_client_1,\n                peer_public_key=cls.connection_node.node.pub,\n                ledger_api_id=FetchAICrypto.identifier,\n            )\n            cls.multiplexer_client_1 = Multiplexer(\n                [cls.connection_client_1], protocols=[MockDefaultMessageProtocol]\n            )\n            cls.multiplexer_client_1.connect()\n\n            temp_dir_client_2 = os.path.join(cls.t, \"temp_dir_client_2\")\n            os.mkdir(temp_dir_client_2)\n            cls.connection_client_2 = _make_libp2p_mailbox_connection(\n                data_dir=temp_dir_client_2,\n                peer_public_key=cls.connection_node.node.pub,\n                ledger_api_id=EthereumCrypto.identifier,\n            )\n            cls.multiplexer_client_2 = Multiplexer(\n                [cls.connection_client_2], protocols=[MockDefaultMessageProtocol]\n            )\n            cls.multiplexer_client_2.connect()\n            wait_for_condition(lambda: cls.multiplexer_client_2.is_connected, 20)\n            wait_for_condition(lambda: cls.multiplexer_client_1.is_connected, 20)\n            wait_for_condition(lambda: cls.connection_client_2.is_connected, 20)\n            wait_for_condition(lambda: cls.connection_client_1.is_connected, 20)\n            wait_for_condition(lambda: cls.connection_node.is_connected, 20)\n        except Exception:\n            cls.multiplexer_node.disconnect()\n            raise\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear down the test\"\"\"\n        cls.multiplexer_client_1.disconnect()\n        cls.multiplexer_client_2.disconnect()\n        cls.multiplexer_node.disconnect()\n\n        os.chdir(cls.cwd)\n        print(open(cls.connection_node.node.log_file, \"r\").read())\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n    def _make_envelope(\n        self,\n        sender_address: str,\n        receiver_address: str,\n        message_id: int = 1,\n        target: int = 0,\n    ):\n        \"\"\"Make an envelope for testing purposes.\"\"\"\n        msg = DefaultMessage(\n            dialogue_reference=(\"\", \"\"),\n            message_id=message_id,\n            target=target,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"hello\",\n        )\n        envelope = Envelope(\n            to=receiver_address,\n            sender=sender_address,\n            protocol_specification_id=DefaultMessage.protocol_specification_id,\n            message=DefaultSerializer().encode(msg),\n        )\n        return envelope\n\n\n@libp2p_log_on_failure_all\nclass TestLibp2pClientEnvelopeOrderSamePeer(BaseTestLibp2pClientSamePeer):\n    \"\"\"Test that the order of envelope is the guaranteed to be the same.\"\"\"\n\n    NB_ENVELOPES = 1000\n\n    def test_burst_order(self):\n        \"\"\"Test order of envelope burst is guaranteed on receiving end.\"\"\"\n        addr_1 = self.connection_client_1.address\n        addr_2 = self.connection_client_2.address\n\n        sent_envelopes = [\n            self._make_envelope(addr_1, addr_2, i, i - 1)\n            for i in range(1, self.NB_ENVELOPES + 1)\n        ]\n        for envelope in sent_envelopes:\n            self.multiplexer_client_1.put(envelope)\n\n        received_envelopes = []\n        for _ in range(1, self.NB_ENVELOPES + 1):\n            envelope = self.multiplexer_client_2.get(block=True, timeout=20)\n            received_envelopes.append(envelope)\n\n        # test no new message is \"created\"\n        with pytest.raises(Empty):\n            self.multiplexer_client_2.get(block=True, timeout=1)\n\n        assert len(sent_envelopes) == len(\n            received_envelopes\n        ), f\"expected number of envelopes {len(sent_envelopes)}, got {len(received_envelopes)}\"\n        for expected, actual in zip(sent_envelopes, received_envelopes):\n            assert expected.message == actual.message, (\n                \"message content differ; probably a wrong message \"\n                \"ordering on the receiving end\"\n            )\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_connections/test_p2p_libp2p_mailbox/test_errors.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This test module contains negative tests for Libp2p tcp client connection.\"\"\"\nimport asyncio\nimport os\nimport shutil\nimport tempfile\nfrom asyncio.futures import Future\nfrom unittest.mock import Mock, patch\n\nimport pytest\n\nfrom aea.configurations.base import ConnectionConfig\nfrom aea.configurations.constants import DEFAULT_LEDGER\nfrom aea.crypto.registries import make_crypto\nfrom aea.helpers.base import CertRequest\nfrom aea.identity.base import Identity\nfrom aea.multiplexer import Multiplexer\n\nfrom packages.fetchai.connections.p2p_libp2p_client.connection import (\n    POR_DEFAULT_SERVICE_ID,\n)\nfrom packages.fetchai.connections.p2p_libp2p_mailbox.connection import (\n    P2PLibp2pMailboxConnection,\n)\n\nfrom tests.conftest import (\n    _make_libp2p_client_connection,\n    _make_libp2p_connection,\n    _make_libp2p_mailbox_connection,\n    _process_cert,\n    libp2p_log_on_failure,\n)\n\n\n@pytest.mark.asyncio\nclass TestLibp2pClientConnectionFailureNodeNotConnected:\n    \"\"\"Test that connection fails when node not running\"\"\"\n\n    @pytest.mark.asyncio\n    async def test_node_not_running(self):\n        \"\"\"Test the node is not running.\"\"\"\n        with tempfile.TemporaryDirectory() as dirname:\n            conn = _make_libp2p_mailbox_connection(\n                data_dir=dirname, peer_public_key=make_crypto(DEFAULT_LEDGER).public_key\n            )\n            with pytest.raises(Exception):\n                await conn.connect()\n\n\nclass TestLibp2pClientConnectionFailureConnectionSetup:\n    \"\"\"Test that connection fails when setup incorrectly\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up\"\"\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        os.chdir(cls.t)\n        crypto = make_crypto(DEFAULT_LEDGER)\n        cls.node_host = \"localhost\"\n        cls.node_port = \"11234\"\n        cls.identity = Identity(\n            \"identity\", address=crypto.address, public_key=crypto.public_key\n        )\n\n        cls.key_file = os.path.join(cls.t, \"keyfile\")\n        crypto.dump(cls.key_file)\n\n        cls.peer_crypto = make_crypto(DEFAULT_LEDGER)\n        cls.cert_request = CertRequest(\n            cls.peer_crypto.public_key,\n            POR_DEFAULT_SERVICE_ID,\n            DEFAULT_LEDGER,\n            \"2021-01-01\",\n            \"2021-01-02\",\n            \"{public_key}\",\n            f\"./{crypto.address}_cert.txt\",\n        )\n        _process_cert(crypto, cls.cert_request, cls.t)\n\n    def test_empty_nodes(self):\n        \"\"\"Test empty nodes.\"\"\"\n        configuration = ConnectionConfig(\n            tcp_key_file=self.key_file,\n            nodes=[\n                {\n                    \"uri\": \"{}:{}\".format(self.node_host, self.node_port),\n                    \"public_key\": self.peer_crypto.public_key,\n                }\n            ],\n            connection_id=P2PLibp2pMailboxConnection.connection_id,\n            cert_requests=[self.cert_request],\n        )\n        P2PLibp2pMailboxConnection(\n            configuration=configuration, data_dir=self.t, identity=self.identity\n        )\n\n        configuration = ConnectionConfig(\n            tcp_key_file=self.key_file,\n            nodes=None,\n            connection_id=P2PLibp2pMailboxConnection.connection_id,\n        )\n        with pytest.raises(Exception):\n            P2PLibp2pMailboxConnection(\n                configuration=configuration,\n                data_dir=self.t,\n                identity=self.identity,\n            )\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear down the test\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\nclass TestLibp2pClientConnectionNodeDisconnected:\n    \"\"\"Test that connection will properly handle node disconnecting\"\"\"\n\n    @classmethod\n    @libp2p_log_on_failure\n    def setup_class(cls):\n        \"\"\"Set the test up\"\"\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        os.chdir(cls.t)\n\n        cls.log_files = []\n        cls.multiplexers = []\n\n        temp_node_dir = os.path.join(cls.t, \"node_dir\")\n        os.mkdir(temp_node_dir)\n        try:\n            cls.connection_node = _make_libp2p_connection(\n                data_dir=temp_node_dir, delegate=True\n            )\n            cls.multiplexer_node = Multiplexer([cls.connection_node])\n            cls.log_files.append(cls.connection_node.node.log_file)\n            cls.multiplexer_node.connect()\n            cls.multiplexers.append(cls.multiplexer_node)\n\n            temp_client_dir = os.path.join(cls.t, \"client_dir\")\n            os.mkdir(temp_client_dir)\n            cls.connection_client = _make_libp2p_client_connection(\n                data_dir=temp_client_dir, peer_public_key=cls.connection_node.node.pub\n            )\n            cls.multiplexer_client = Multiplexer([cls.connection_client])\n            cls.multiplexer_client.connect()\n            cls.multiplexers.append(cls.multiplexer_client)\n        except Exception:\n            cls.teardown_class()\n            raise\n\n    def test_node_disconnected(self):\n        \"\"\"Test node disconnected.\"\"\"\n        assert self.connection_client.is_connected is True\n        self.multiplexer_client.disconnect()\n        self.multiplexer_node.disconnect()\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear down the test\"\"\"\n        for mux in cls.multiplexers:\n            mux.disconnect()\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n\n\ndone_future: asyncio.Future = asyncio.Future()\ndone_future.set_result(None)\n\n\n@pytest.mark.asyncio\nasync def test_connect_attempts():\n    \"\"\"Test connect attempts.\"\"\"\n    # test connects\n    with tempfile.TemporaryDirectory() as dirname:\n        con = _make_libp2p_client_connection(\n            data_dir=dirname, peer_public_key=make_crypto(DEFAULT_LEDGER).public_key\n        )\n        con.connect_retries = 2\n        with patch(\n            \"aea.helpers.pipe.TCPSocketChannelClient.connect\",\n            side_effect=Exception(\"test exception on connect\"),\n        ) as open_connection_mock:\n            with pytest.raises(Exception, match=\"test exception on connect\"):\n                await con.connect()\n            assert open_connection_mock.call_count == con.connect_retries\n\n\n@pytest.mark.asyncio\nasync def test_reconnect_on_receive_fail():\n    \"\"\"Test reconnect on receive fails.\"\"\"\n    with tempfile.TemporaryDirectory() as dirname:\n        con = _make_libp2p_mailbox_connection(\n            data_dir=dirname, peer_public_key=make_crypto(DEFAULT_LEDGER).public_key\n        )\n        con._in_queue = Mock()\n        con._node_client = Mock()\n        f = Future()\n        f.set_exception(ConnectionError(\"oops\"))\n        con._node_client.read_envelope.return_value = f\n\n        with patch.object(\n            con, \"_perform_connection_to_node\", return_value=done_future\n        ) as connect_mock:\n            assert await con._read_envelope_from_node() is None\n            connect_mock.assert_called()\n\n\n@pytest.mark.asyncio\nasync def test_reconnect_on_send_fail():\n    \"\"\"Test reconnect on send fails.\"\"\"\n    with tempfile.TemporaryDirectory() as dirname:\n        con = _make_libp2p_mailbox_connection(\n            data_dir=dirname, peer_public_key=make_crypto(DEFAULT_LEDGER).public_key\n        )\n        con._node_client = Mock()\n        f = Future()\n        f.set_exception(Exception(\"oops\"))\n        con._node_client.send_envelope.side_effect = Exception(\"oops\")\n        # test reconnect on send fails\n        with patch.object(\n            con, \"_perform_connection_to_node\", return_value=done_future\n        ) as connect_mock, patch.object(\n            con, \"_ensure_valid_envelope_for_external_comms\"\n        ):\n            with pytest.raises(Exception, match=\"oops\"):\n                await con._send_envelope_with_node_client(Mock())\n            connect_mock.assert_called()\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_connections/test_p2p_libp2p_mailbox/test_mailbox_service.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This test module contains tests for P2PLibp2p connection.\"\"\"\nimport os\nimport re\nimport shutil\nimport tempfile\nfrom unittest.mock import Mock\n\nimport pytest\nimport requests\n\nfrom aea.mail.base import Envelope\nfrom aea.multiplexer import Multiplexer\n\nfrom packages.fetchai.connections.p2p_libp2p_mailbox.connection import NodeClient\nfrom packages.fetchai.protocols.acn import acn_pb2\nfrom packages.fetchai.protocols.acn.message import AcnMessage\nfrom packages.fetchai.protocols.default import DefaultSerializer\nfrom packages.fetchai.protocols.default.message import DefaultMessage\n\nfrom tests.common.utils import wait_for_condition\nfrom tests.conftest import _make_libp2p_client_connection, _make_libp2p_connection\n\n\nMockDefaultMessageProtocol = Mock()\nMockDefaultMessageProtocol.protocol_id = DefaultMessage.protocol_id\nMockDefaultMessageProtocol.protocol_specification_id = (\n    DefaultMessage.protocol_specification_id\n)\n\n\n@pytest.mark.asyncio\nclass TestMailboxAPI:\n    \"\"\"Test that connection is established and torn down correctly\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up\"\"\"\n        cls.cwd = os.getcwd()\n        cls.t = tempfile.mkdtemp()\n        os.chdir(cls.t)\n\n        cls.temp_dir = os.path.join(cls.t, \"temp_dir_node\")\n        os.mkdir(cls.temp_dir)\n        cls.connection_node = _make_libp2p_connection(\n            data_dir=cls.temp_dir, delegate=True, mailbox=True\n        )\n        temp_dir_client1 = os.path.join(cls.t, \"temp_dir_client\")\n        os.mkdir(temp_dir_client1)\n        temp_dir_client2 = os.path.join(cls.t, \"temp_dir_client2\")\n        os.mkdir(temp_dir_client2)\n        cls.connection1 = _make_libp2p_client_connection(\n            data_dir=temp_dir_client1, peer_public_key=cls.connection_node.node.pub\n        )\n\n        cls.connection2 = _make_libp2p_client_connection(\n            data_dir=temp_dir_client2, peer_public_key=cls.connection_node.node.pub\n        )\n        cls.multiplexer1 = Multiplexer([cls.connection_node])\n        cls.multiplexer1.connect()\n\n        wait_for_condition(lambda: cls.connection_node.is_connected is True, 10)\n\n    @pytest.mark.asyncio\n    async def test_message_delivery(self):  # nosec\n        \"\"\"Test connnect then disconnect.\"\"\"\n        r = requests.get(\"https://localhost:8888/ssl_signature\", verify=False)  # nosec\n        assert r.status_code == 200, r.text\n\n        node_client = NodeClient(Mock(), self.connection2.node_por)\n        agent_record = node_client.make_agent_record()\n        addr = agent_record.address\n        performative = acn_pb2.AcnMessage.Register_Performative()  # type: ignore\n        AcnMessage.AgentRecord.encode(\n            performative.record, agent_record  # pylint: disable=no-member\n        )\n        data = performative.record.SerializeToString()  # pylint: disable=no-member\n\n        r = requests.post(\n            \"https://localhost:8888/register\", data=data, verify=False  # nosec\n        )\n        assert r.status_code == 200, r.text\n        assert re.match(\n            \"[0-9a-f]{32}\", r.text, re.I\n        ), r.text  # pylint: disable=no-member\n        session_id = r.text\n\n        envelope = self.make_envelope(addr, addr)\n        r = requests.post(\n            \"https://localhost:8888/send_envelope\",\n            data=envelope.encode(),\n            headers={\"Session-Id\": session_id},\n            verify=False,  # nosec\n        )\n        assert r.status_code == 200, r.text\n\n        r = requests.get(\n            \"https://localhost:8888/get_envelope\",\n            headers={\"Session-Id\": session_id},\n            verify=False,  # nosec\n        )\n        assert r.status_code == 200, r.text\n        assert r.content, \"no envelope\"\n\n        delivered_envelope = Envelope.decode(r.content)\n        assert delivered_envelope is not None\n        assert delivered_envelope.to == envelope.to\n        assert delivered_envelope.sender == envelope.sender\n        assert (\n            delivered_envelope.protocol_specification_id\n            == envelope.protocol_specification_id\n        )\n        assert delivered_envelope.message == envelope.message\n\n        # no new envelopes\n        r = requests.get(\n            \"https://localhost:8888/get_envelope\",\n            headers={\"Session-Id\": session_id},\n            verify=False,  # nosec\n        )\n        assert r.status_code == 200, r.text\n        assert not r.content\n\n        # unregister\n        r = requests.get(\n            \"https://localhost:8888/unregister\",\n            headers={\"Session-Id\": session_id},\n            verify=False,  # nosec\n        )\n        assert r.status_code == 200, r.text\n\n        # bad session!\n        r = requests.get(\n            \"https://localhost:8888/get_envelope\",\n            headers={\"Session-Id\": session_id},\n            verify=False,  # nosec\n        )\n        assert r.status_code == 400, r.text\n        assert \"session_id\" in r.text\n\n    def make_envelope(self, from_: str, to_: str) -> Envelope:\n        \"\"\"Make sample envelope.\"\"\"\n        msg = DefaultMessage(\n            dialogue_reference=(\"\", \"\"),\n            message_id=1,\n            target=0,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"hello\",\n        )\n        envelope = Envelope(\n            to=to_,\n            sender=from_,\n            protocol_specification_id=DefaultMessage.protocol_specification_id,\n            message=DefaultSerializer().encode(msg),\n        )\n        return envelope\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear down the test\"\"\"\n        cls.multiplexer1.disconnect()\n        os.chdir(cls.cwd)\n        print(open(cls.connection_node.node.log_file, \"r\").read())\n        try:\n\n            shutil.rmtree(cls.t)\n        except (OSError, IOError):\n            pass\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_connections/test_p2p_stub/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"The tests module contains the tests of the p2p stub connection package.\"\"\"\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_connections/test_p2p_stub/test_p2p_stub.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This test module contains the tests for the p2p_stub connection.\"\"\"\n\nimport asyncio\nimport os\nimport shutil\nimport tempfile\nfrom pathlib import Path\nfrom unittest.mock import MagicMock\n\nimport pytest\n\nfrom aea.configurations.base import ConnectionConfig\nfrom aea.identity.base import Identity\nfrom aea.mail.base import Envelope\n\nfrom packages.fetchai.connections.p2p_stub.connection import P2PStubConnection\nfrom packages.fetchai.protocols.default.message import DefaultMessage\n\n\nSEPARATOR = \",\"\n\n\ndef make_test_envelope(to_=\"any\", sender_=\"sender\") -> Envelope:\n    \"\"\"Create a test envelope.\"\"\"\n    msg = DefaultMessage(\n        dialogue_reference=(\"\", \"\"),\n        message_id=1,\n        target=0,\n        performative=DefaultMessage.Performative.BYTES,\n        content=b\"hello\",\n    )\n    msg.to = to_\n    msg.sender = sender_\n    envelope = Envelope(\n        to=to_,\n        sender=sender_,\n        message=msg,\n    )\n    return envelope\n\n\nclass Testp2pStubConnectionReception:\n    \"\"\"Test that the stub connection is implemented correctly.\"\"\"\n\n    def setup(self):\n        \"\"\"Set the test up.\"\"\"\n        self.cwd = os.getcwd()\n        self.tmpdir = Path(tempfile.mkdtemp())\n        d = self.tmpdir / \"test_p2p_stub\"\n        d.mkdir(parents=True)\n\n        configuration = ConnectionConfig(\n            namespace_dir=d,\n            connection_id=P2PStubConnection.connection_id,\n        )\n        self.loop = asyncio.get_event_loop()\n        self.identity1 = Identity(\"test\", \"con1\", \"public_key_1\")\n        self.identity2 = Identity(\"test\", \"con2\", \"public_key_2\")\n        self.connection1 = P2PStubConnection(\n            configuration=configuration, data_dir=MagicMock(), identity=self.identity1\n        )\n        self.connection2 = P2PStubConnection(\n            configuration=configuration, data_dir=MagicMock(), identity=self.identity2\n        )\n        os.chdir(self.tmpdir)\n\n    @pytest.mark.asyncio\n    async def test_send(self):\n        \"\"\"Test that the connection receives what has been enqueued in the input file.\"\"\"\n        await self.connection1.connect()\n        assert self.connection1.is_connected\n\n        await self.connection2.connect()\n        assert self.connection2.is_connected\n\n        envelope = make_test_envelope(to_=\"con2\")\n        await self.connection1.send(envelope)\n\n        received_envelope = await asyncio.wait_for(\n            self.connection2.receive(), timeout=5\n        )\n        assert received_envelope\n        assert received_envelope.message == envelope.message.encode()\n\n    def teardown(self):\n        \"\"\"Clean up after tests.\"\"\"\n        os.chdir(self.cwd)\n        self.loop.run_until_complete(self.connection1.disconnect())\n        self.loop.run_until_complete(self.connection2.disconnect())\n        try:\n            shutil.rmtree(self.tmpdir)\n        except (OSError, IOError):\n            pass\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_connections/test_soef/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"The tests module contains the tests of the soef connection.\"\"\"\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_connections/test_soef/models.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains models for soef connection tests.\"\"\"\n\nfrom aea.helpers.search.models import Attribute, DataModel, Location\n\nfrom packages.fetchai.connections.soef.connection import ModelNames\n\n\nAGENT_LOCATION_MODEL = DataModel(\n    ModelNames.LOCATION_AGENT.value,\n    [\n        Attribute(\"location\", Location, True, \"The location where the agent is.\"),\n        Attribute(\"disclosure_accuracy\", str, False, \"Optional disclosure accuracy.\"),\n    ],\n    \"A data model to describe location of an agent.\",\n)\n\n\nAGENT_PERSONALITY_MODEL = DataModel(\n    ModelNames.PERSONALITY_AGENT.value,\n    [\n        Attribute(\"piece\", str, True, \"The personality piece key.\"),\n        Attribute(\"value\", str, True, \"The personality piece value.\"),\n    ],\n    \"A data model to describe the personality of an agent.\",\n)\n\n\nSET_SERVICE_KEY_MODEL = DataModel(\n    ModelNames.SET_SERVICE_KEY.value,\n    [\n        Attribute(\"key\", str, True, \"Service key name.\"),\n        Attribute(\"value\", str, True, \"Service key value.\"),\n    ],\n    \"A data model to set service key.\",\n)\n\n\nREMOVE_SERVICE_KEY_MODEL = DataModel(\n    ModelNames.REMOVE_SERVICE_KEY.value,\n    [Attribute(\"key\", str, True, \"Service key name.\")],\n    \"A data model to remove service key.\",\n)\n\nPING_MODEL = DataModel(\n    ModelNames.PING.value,\n    [],\n    \"A data model for ping command.\",\n)\n\n\nSEARCH_MODEL = DataModel(\n    ModelNames.SEARCH_MODEL.value,\n    [Attribute(\"location\", Location, True, \"The location where the agent is.\")],\n    \"A data model to perform search.\",\n)\n\n\nAGENT_GENERIC_COMMAND_MODEL = DataModel(\n    ModelNames.GENERIC_COMMAND.value,\n    [\n        Attribute(\"command\", str, True, \"Command name to execute.\"),\n        Attribute(\"parameters\", str, False, \"Url encoded parameters string.\"),\n    ],\n    \"A data model to describe the generic soef command.\",\n)\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_connections/test_soef/test_soef.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the soef connection module.\"\"\"\nimport asyncio\nimport os\nimport shutil\nimport tempfile\nfrom pathlib import Path\nfrom typing import Any, Callable\nfrom unittest.mock import MagicMock, patch\n\nimport pytest\n\nfrom aea.common import Address\nfrom aea.configurations.base import ConnectionConfig\nfrom aea.configurations.constants import DEFAULT_LEDGER\nfrom aea.crypto.registries import make_crypto\nfrom aea.exceptions import AEAEnforceError\nfrom aea.helpers.search.models import (\n    Attribute,\n    Constraint,\n    ConstraintType,\n    DataModel,\n    Description,\n    Location,\n    Query,\n)\nfrom aea.identity.base import Identity\nfrom aea.mail.base import Envelope\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\n\nfrom packages.fetchai.connections.soef.connection import (\n    SOEFConnection,\n    SOEFException,\n    SOEFNetworkConnectionError,\n    SOEFServerBadResponseError,\n    requests,\n)\nfrom packages.fetchai.protocols.oef_search.dialogues import OefSearchDialogue\nfrom packages.fetchai.protocols.oef_search.dialogues import (\n    OefSearchDialogues as BaseOefSearchDialogues,\n)\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\n\nfrom tests.conftest import UNKNOWN_PROTOCOL_PUBLIC_ID\nfrom tests.test_packages_for_aea_tests.test_connections.test_soef import models\n\n\ndef make_async(return_value: Any) -> Callable:\n    \"\"\"Wrap value into async function.\"\"\"\n    # pydocstyle\n    async def fn(*args, **kwargs):\n        return return_value\n\n    return fn\n\n\ndef wrap_future(return_value: Any) -> asyncio.Future:\n    \"\"\"Wrap value into future.\"\"\"\n    f: asyncio.Future = asyncio.Future()\n    f.set_result(return_value)\n    return f\n\n\nclass OefSearchDialogues(BaseOefSearchDialogues):\n    \"\"\"This class keeps track of all oef_search dialogues.\"\"\"\n\n    def __init__(self, self_address: str) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :param self_address: the address of the entity for whom dialogues are maintained\n        :return: None\n        \"\"\"\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return OefSearchDialogue.Role.AGENT\n\n        BaseOefSearchDialogues.__init__(\n            self,\n            self_address=self_address,\n            role_from_first_message=role_from_first_message,\n        )\n\n\nclass TestSoefTokenStorage:\n    \"\"\"Set of unit tests for soef connection token storage.\"\"\"\n\n    def setup(self):\n        \"\"\"Set up.\"\"\"\n        self.skill_id = \"some_author/some_skill:0.1.0\"\n        self.crypto = make_crypto(DEFAULT_LEDGER)\n        self.crypto2 = make_crypto(DEFAULT_LEDGER)\n        self.data_dir = tempfile.mkdtemp()\n        identity = Identity(\n            \"identity\", address=self.crypto.address, public_key=self.crypto.public_key\n        )\n        self.oef_search_dialogues = OefSearchDialogues(self.skill_id)\n\n        # create the connection and multiplexer objects\n        self.token_storage_path = \"test.storage\"  # nosec\n        configuration = ConnectionConfig(\n            api_key=\"TwiCIriSl0mLahw17pyqoA\",\n            soef_addr=\"s-oef.fetch.ai\",\n            soef_port=443,\n            token_storage_path=self.token_storage_path,\n            restricted_to_protocols={OefSearchMessage.protocol_specification_id},\n            connection_id=SOEFConnection.connection_id,\n        )\n        self.connection = SOEFConnection(\n            configuration=configuration,\n            data_dir=self.data_dir,\n            identity=identity,\n        )\n\n    def teardown(self):\n        \"\"\"Tear down.\"\"\"\n        try:\n            os.remove(self.token_storage_path)\n            shutil.rmtree(self.data_dir)\n        except Exception as e:\n            print(e)\n\n    def test_unique_page_address_default_no_file(self):\n        \"\"\"Test unique page address does not raise if file not found.\"\"\"\n        assert self.connection.channel.unique_page_address is None\n\n    def test_unique_page_address_default_file(self):\n        \"\"\"Test unique page address is None by default for new file.\"\"\"\n        with open(self.token_storage_path, \"w\"):\n            os.utime(self.token_storage_path, None)\n        assert self.connection.channel.unique_page_address is None\n\n    def test_unique_page_address_set_and_get(self):\n        \"\"\"Test unique page address set and get including None.\"\"\"\n        self.connection.channel.unique_page_address = \"test\"\n        assert self.connection.channel._unique_page_address == \"test\"\n        assert self.connection.channel.unique_page_address == \"test\"\n        expected_token_storage_path = Path(self.data_dir) / self.token_storage_path\n        with expected_token_storage_path.open() as f:\n            in_file = f.read()\n        assert in_file == \"test\"\n        self.connection.channel.unique_page_address = None\n        assert self.connection.channel._unique_page_address is None\n        assert self.connection.channel.unique_page_address is None\n        with expected_token_storage_path.open() as f:\n            in_file = f.read()\n        assert in_file == self.connection.channel.NONE_UNIQUE_PAGE_ADDRESS\n\n\nclass TestSoef:\n    \"\"\"Set of unit tests for soef connection.\"\"\"\n\n    search_success_response = \"\"\"<?xml version=\"1.0\" encoding=\"UTF-8\"?><response><success>1</success><total>2</total><capped>0</capped><results><agent name=\"8c25cc02fd0c45f8895a3d4b3895376a\" genus=\"\" classification=\"\"><identities><identity chain_identifier=\"fetchai\">2ayYmgrCg76R1mzr2zWCmivzJG31hXtFVwQvR4XrXrD88Rc3sT</identity></identities><range_in_km>0</range_in_km></agent><agent name=\"9b61f3d2217b4d4f995e779db775fbdd\" genus=\"\" classification=\"\"><identities><identity chain_identifier=\"fetchai\">2DvN8QNXKE2tjnKgMKvBy9ZFyC6JaFYFrcLyWSS4A9RDWeTP4k</identity></identities><range_in_km>0</range_in_km></agent></results></response>\"\"\"\n    search_empty_response = \"\"\"<?xml version=\"1.0\" encoding=\"UTF-8\"?><response><success>1</success><total>0</total><capped>0</capped><results></results></response>\"\"\"\n    search_fail_response = (\n        \"\"\"<?xml version=\"1.0\" encoding=\"UTF-8\"?><notaresponse></notaresponse>\"\"\"\n    )\n    generic_success_response = \"\"\"<?xml version=\"1.0\" encoding=\"UTF-8\"?><response><success>1</success></response>\"\"\"\n\n    def setup(self):\n        \"\"\"Set up.\"\"\"\n        self.skill_id = \"some_author/some_skill:0.1.0\"\n        self.crypto = make_crypto(DEFAULT_LEDGER)\n        self.crypto2 = make_crypto(DEFAULT_LEDGER)\n        identity = Identity(\n            \"identity\", address=self.crypto.address, public_key=self.crypto.public_key\n        )\n        self.oef_search_dialogues = OefSearchDialogues(self.skill_id)\n        self.data_dir = tempfile.mkdtemp()\n\n        # create the connection and multiplexer objects\n        configuration = ConnectionConfig(\n            api_key=\"TwiCIriSl0mLahw17pyqoA\",\n            soef_addr=\"s-oef.fetch.ai\",\n            soef_port=443,\n            restricted_to_protocols={OefSearchMessage.protocol_specification_id},\n            connection_id=SOEFConnection.connection_id,\n        )\n        self.connection = SOEFConnection(\n            configuration=configuration,\n            data_dir=self.data_dir,\n            identity=identity,\n        )\n        self.connection2 = SOEFConnection(\n            configuration=configuration,\n            data_dir=self.data_dir,\n            identity=Identity(\n                \"identity\",\n                address=self.crypto2.address,\n                public_key=self.crypto2.public_key,\n            ),\n        )\n        self.loop = asyncio.get_event_loop()\n        self.loop.run_until_complete(self.connection.connect())\n        self.loop.run_until_complete(self.connection2.connect())\n        self.connection.channel.unique_page_address = \"some_addr\"\n\n    @pytest.mark.asyncio\n    async def test_set_service_key(self):\n        \"\"\"Test set service key.\"\"\"\n        service_instance = {\"key\": \"test\", \"value\": \"test\"}\n        service_description = Description(\n            service_instance, data_model=models.SET_SERVICE_KEY_MODEL\n        )\n        message, _ = self.oef_search_dialogues.create(\n            counterparty=str(SOEFConnection.connection_id.to_any()),\n            performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n            service_description=service_description,\n        )\n        envelope = Envelope(\n            to=message.to,\n            sender=message.sender,\n            message=message,\n        )\n\n        with patch.object(\n            self.connection.channel,\n            \"_request_text\",\n            make_async(self.generic_success_response),\n        ):\n            await self.connection.send(envelope)\n\n        response = await asyncio.wait_for(self.connection.receive(), timeout=1)\n        assert response.message.performative == OefSearchMessage.Performative.SUCCESS\n        assert response.message.agents_info.body == {}\n\n    @pytest.mark.asyncio\n    async def test_remove_service_key(self):\n        \"\"\"Test remove service key.\"\"\"\n        await self.test_set_service_key()\n        service_instance = {\"key\": \"test\"}\n        service_description = Description(\n            service_instance, data_model=models.REMOVE_SERVICE_KEY_MODEL\n        )\n        message, _ = self.oef_search_dialogues.create(\n            counterparty=str(SOEFConnection.connection_id.to_any()),\n            performative=OefSearchMessage.Performative.UNREGISTER_SERVICE,\n            service_description=service_description,\n        )\n        envelope = Envelope(\n            to=message.to,\n            sender=message.sender,\n            message=message,\n        )\n\n        with patch.object(\n            self.connection.channel,\n            \"_request_text\",\n            make_async(self.generic_success_response),\n        ):\n            await self.connection.send(envelope)\n\n        response = await asyncio.wait_for(self.connection.receive(), timeout=1)\n        assert response.message.performative == OefSearchMessage.Performative.SUCCESS\n        assert response.message.agents_info.body == {}\n\n    def test_connected(self):\n        \"\"\"Test connected==True.\"\"\"\n        assert self.connection.is_connected\n\n    @pytest.mark.asyncio\n    async def test_disconnected(self):\n        \"\"\"Test disconnect.\"\"\"\n        assert self.connection.is_connected\n        with patch.object(\n            self.connection.channel,\n            \"_request_text\",\n            make_async(\"<response><message>Goodbye!</message></response>\"),\n        ):\n            await self.connection.disconnect()\n        assert not self.connection.is_connected\n\n    @pytest.mark.asyncio\n    async def test_register_service(self):\n        \"\"\"Test register service.\"\"\"\n        agent_location = Location(52.2057092, 2.1183431)\n        service_instance = {\"location\": agent_location}\n        service_description = Description(\n            service_instance, data_model=models.AGENT_LOCATION_MODEL\n        )\n        message, _ = self.oef_search_dialogues.create(\n            counterparty=str(SOEFConnection.connection_id.to_any()),\n            performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n            service_description=service_description,\n        )\n        envelope = Envelope(\n            to=message.to,\n            sender=message.sender,\n            message=message,\n        )\n\n        with patch.object(\n            self.connection.channel,\n            \"_request_text\",\n            make_async(self.generic_success_response),\n        ):\n            await self.connection.send(envelope)\n\n        response = await asyncio.wait_for(self.connection.receive(), timeout=1)\n        assert response.message.performative == OefSearchMessage.Performative.SUCCESS\n        assert response.message.agents_info.body == {}\n\n        assert self.connection.channel.agent_location == agent_location\n\n    @pytest.mark.asyncio\n    async def test_bad_register_service(self):\n        \"\"\"Test register service fails on bad values provided.\"\"\"\n        bad_location_model = DataModel(\n            \"not_location_agent\",\n            [\n                Attribute(\n                    \"non_location\", Location, True, \"The location where the agent is.\"\n                )\n            ],\n            \"A data model to describe location of an agent.\",\n        )\n        agent_location = Location(52.2057092, 2.1183431)\n        service_instance = {\"non_location\": agent_location}\n        service_description = Description(\n            service_instance, data_model=bad_location_model\n        )\n        message, sending_dialogue = self.oef_search_dialogues.create(\n            counterparty=str(SOEFConnection.connection_id.to_any()),\n            performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n            service_description=service_description,\n        )\n        envelope = Envelope(\n            to=message.to,\n            sender=message.sender,\n            message=message,\n        )\n        await self.connection.send(envelope)\n\n        expected_envelope = await asyncio.wait_for(self.connection.receive(), timeout=1)\n        assert expected_envelope\n        assert (\n            expected_envelope.message.performative\n            == OefSearchMessage.Performative.OEF_ERROR\n        )\n        message = expected_envelope.message\n        receiving_dialogue = self.oef_search_dialogues.update(message)\n        assert sending_dialogue == receiving_dialogue\n\n    @pytest.mark.asyncio\n    async def test_unregister_service(self):\n        \"\"\"Test unregister service.\"\"\"\n        agent_location = Location(52.2057092, 2.1183431)\n        service_instance = {\"location\": agent_location}\n        service_description = Description(\n            service_instance, data_model=models.AGENT_LOCATION_MODEL\n        )\n        message, _ = self.oef_search_dialogues.create(\n            counterparty=str(SOEFConnection.connection_id.to_any()),\n            performative=OefSearchMessage.Performative.UNREGISTER_SERVICE,\n            service_description=service_description,\n        )\n        envelope = Envelope(\n            to=message.to,\n            sender=message.sender,\n            message=message,\n        )\n        with patch.object(\n            self.connection.channel,\n            \"_request_text\",\n            make_async(\"<response><message>Goodbye!</message></response>\"),\n        ):\n            await self.connection.send(envelope)\n\n        assert self.connection.channel.unique_page_address is None\n\n    @pytest.mark.asyncio\n    async def test_register_personailty_pieces(self):\n        \"\"\"Test register service with personality pieces.\"\"\"\n        service_instance = {\"piece\": \"genus\", \"value\": \"service\"}\n        service_description = Description(\n            service_instance, data_model=models.AGENT_PERSONALITY_MODEL\n        )\n        message, _ = self.oef_search_dialogues.create(\n            counterparty=str(SOEFConnection.connection_id.to_any()),\n            performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n            service_description=service_description,\n        )\n        envelope = Envelope(\n            to=message.to,\n            sender=message.sender,\n            message=message,\n        )\n        with patch.object(\n            self.connection.channel,\n            \"_request_text\",\n            make_async(self.generic_success_response),\n        ):\n            await self.connection.send(envelope)\n\n        response = await asyncio.wait_for(self.connection.receive(), timeout=1)\n        assert response.message.performative == OefSearchMessage.Performative.SUCCESS\n        assert response.message.agents_info.body == {}\n\n    @pytest.mark.asyncio\n    async def test_bad_message(self):\n        \"\"\"Test fail on bad message.\"\"\"\n        envelope = Envelope(\n            to=\"soef\",\n            sender=self.crypto.address,\n            protocol_specification_id=UNKNOWN_PROTOCOL_PUBLIC_ID,\n            message=b\"some msg\",\n        )\n        with pytest.raises(\n            AEAEnforceError, match=r\"Message not of type OefSearchMessage\"\n        ):\n            await self.connection.send(envelope)\n\n    @pytest.mark.asyncio\n    async def test_bad_performative(self):\n        \"\"\"Test fail on bad perfromative.\"\"\"\n        agent_location = Location(52.2057092, 2.1183431)\n        service_instance = {\"location\": agent_location}\n        service_description = Description(\n            service_instance, data_model=models.AGENT_LOCATION_MODEL\n        )\n        message = OefSearchMessage(\n            performative=\"oef_error\",\n            dialogue_reference=self.oef_search_dialogues.new_self_initiated_dialogue_reference(),\n            service_description=service_description,\n        )\n        message.to = str(SOEFConnection.connection_id.to_any())\n        message.sender = self.skill_id\n        envelope = Envelope(\n            to=message.to,\n            sender=message.sender,\n            message=message,\n        )\n        with pytest.raises(ValueError):\n            await self.connection.send(envelope)\n\n    @pytest.mark.asyncio\n    async def test_bad_search_query(self):\n        \"\"\"Test fail on invalid query for search.\"\"\"\n        await self.test_register_service()\n        closeness_query = Query([], model=models.AGENT_LOCATION_MODEL)\n        message, sending_dialogue = self.oef_search_dialogues.create(\n            counterparty=str(SOEFConnection.connection_id.to_any()),\n            performative=OefSearchMessage.Performative.SEARCH_SERVICES,\n            query=closeness_query,\n        )\n        envelope = Envelope(\n            to=message.to,\n            sender=message.sender,\n            message=message,\n        )\n\n        with patch.object(\n            self.connection.channel,\n            \"_request_text\",\n            make_async(self.search_empty_response),\n        ):\n            await self.connection.send(envelope)\n\n        expected_envelope = await asyncio.wait_for(self.connection.receive(), timeout=1)\n        assert expected_envelope\n        message = expected_envelope.message\n        assert message.performative == OefSearchMessage.Performative.OEF_ERROR\n        message = expected_envelope.message\n        receiving_dialogue = self.oef_search_dialogues.update(message)\n        assert sending_dialogue == receiving_dialogue\n\n    @pytest.mark.asyncio\n    async def test_search(self):\n        \"\"\"Test search.\"\"\"\n        agent_location = Location(52.2057092, 2.1183431)\n        radius = 0.1\n        close_to_my_service = Constraint(\n            \"location\", ConstraintType(\"distance\", (agent_location, radius))\n        )\n        personality_filters = [\n            Constraint(\"genus\", ConstraintType(\"==\", \"vehicle\")),\n            Constraint(\n                \"classification\", ConstraintType(\"==\", \"mobility.railway.train\")\n            ),\n        ]\n        service_key_filters = [\n            Constraint(\"custom_key\", ConstraintType(\"==\", \"custom_value\")),\n        ]\n        closeness_query = Query(\n            [close_to_my_service] + personality_filters + service_key_filters\n        )\n        message, sending_dialogue = self.oef_search_dialogues.create(\n            counterparty=str(SOEFConnection.connection_id.to_any()),\n            performative=OefSearchMessage.Performative.SEARCH_SERVICES,\n            query=closeness_query,\n        )\n        envelope = Envelope(\n            to=message.to,\n            sender=message.sender,\n            message=message,\n        )\n\n        with patch.object(\n            self.connection.channel,\n            \"_request_text\",\n            make_async(self.search_success_response),\n        ):\n            await self.connection.send(envelope)\n            expected_envelope = await asyncio.wait_for(\n                self.connection.receive(), timeout=1\n            )\n\n        assert expected_envelope\n        message = expected_envelope.message\n        assert len(message.agents) >= 1\n        message = expected_envelope.message\n        receiving_dialogue = self.oef_search_dialogues.update(message)\n        assert sending_dialogue == receiving_dialogue\n\n    @pytest.mark.asyncio\n    async def test_find_around_me(self):\n        \"\"\"Test internal method find around me.\"\"\"\n        agent_location = Location(52.2057092, 2.1183431)\n        radius = 0.1\n        close_to_my_service = Constraint(\n            \"location\", ConstraintType(\"distance\", (agent_location, radius))\n        )\n        personality_filters = [\n            Constraint(\"genus\", ConstraintType(\"==\", \"vehicle\")),\n            Constraint(\n                \"classification\", ConstraintType(\"==\", \"mobility.railway.train\")\n            ),\n        ]\n        service_key_filters = [\n            Constraint(\"custom_key\", ConstraintType(\"==\", \"custom_value\")),\n        ]\n        closeness_query = Query(\n            [close_to_my_service] + personality_filters + service_key_filters\n        )\n\n        message_1, sending_dialogue = self.oef_search_dialogues.create(\n            counterparty=str(SOEFConnection.connection_id.to_any()),\n            performative=OefSearchMessage.Performative.SEARCH_SERVICES,\n            query=closeness_query,\n        )\n\n        internal_dialogue_1 = self.connection.channel.oef_search_dialogues.update(\n            message_1\n        )\n        assert internal_dialogue_1 is not None\n\n        message_2, sending_dialogue = self.oef_search_dialogues.create(\n            counterparty=str(SOEFConnection.connection_id.to_any()),\n            performative=OefSearchMessage.Performative.SEARCH_SERVICES,\n            query=closeness_query,\n        )\n\n        internal_dialogue_2 = self.connection.channel.oef_search_dialogues.update(\n            message_2\n        )\n        assert internal_dialogue_2 is not None\n\n        message_3, sending_dialogue = self.oef_search_dialogues.create(\n            counterparty=str(SOEFConnection.connection_id.to_any()),\n            performative=OefSearchMessage.Performative.SEARCH_SERVICES,\n            query=closeness_query,\n        )\n\n        internal_dialogue_3 = self.connection.channel.oef_search_dialogues.update(\n            message_3\n        )\n        assert internal_dialogue_3 is not None\n\n        with patch.object(\n            self.connection.channel,\n            \"_request_text\",\n            new_callable=MagicMock,\n            side_effect=[\n                wrap_future(self.search_empty_response),\n                wrap_future(self.search_success_response),\n                wrap_future(self.search_fail_response),\n            ],\n        ):\n            await self.connection.channel._find_around_me_handle_request(\n                message_1, internal_dialogue_1, 1, {}\n            )\n            await self.connection.channel._find_around_me_handle_request(\n                message_2, internal_dialogue_2, 1, {}\n            )\n            with pytest.raises(\n                SOEFException, match=r\".* `find_around_me` .*Exception: .*\"\n            ):\n                await self.connection.channel._find_around_me_handle_request(\n                    message_3, internal_dialogue_3, 1, {}\n                )\n\n    @pytest.mark.asyncio\n    async def test_register_agent(self):\n        \"\"\"Test internal method register agent.\"\"\"\n        resp_text = '<?xml version=\"1.0\" encoding=\"UTF-8\"?><response></response>'\n        with patch.object(\n            self.connection.channel, \"_request_text\", make_async(resp_text)\n        ):\n            with pytest.raises(\n                SOEFException,\n                match=\"Agent registration error - page address or token not received\",\n            ):\n                await self.connection.channel._register_agent()\n\n        resp_text = '<?xml version=\"1.0\" encoding=\"UTF-8\"?><response><encrypted>0</encrypted><token>672DB3B67780F98984ABF1123BD11</token><page_address>oef_C95B21A4D5759C8FE7A6304B62B726AB8077BEE4BA191A7B92B388F9B1</page_address></response>'\n        with patch.object(\n            self.connection.channel, \"_request_text\", make_async(resp_text)\n        ):\n            with pytest.raises(\n                SOEFException,\n                match=r\"`acknowledge` .*Exception: .*\",\n            ):\n                await self.connection.channel._register_agent()\n\n        resp_text1 = '<?xml version=\"1.0\" encoding=\"UTF-8\"?><response><encrypted>0</encrypted><token>672DB3B67780F98984ABF1123BD11</token><page_address>oef_C95B21A4D5759C8FE7A6304B62B726AB8077BEE4BA191A7B92B388F9B1</page_address></response>'\n        resp_text2 = '<?xml version=\"1.0\" encoding=\"UTF-8\"?><response><success>1</success></response>'\n        resp_text3 = '<?xml version=\"1.0\" encoding=\"UTF-8\"?><response><success>1</success></response>'\n        with patch.object(\n            self.connection.channel,\n            \"_request_text\",\n            new_callable=MagicMock,\n            side_effect=[\n                wrap_future(resp_text1),\n                wrap_future(resp_text2),\n                wrap_future(resp_text3),\n            ],\n        ):\n            await self.connection.channel._register_agent()\n            assert self.connection.channel._ping_periodic_task is not None\n\n    @pytest.mark.asyncio\n    async def test_check_server_reachable(self):\n        \"\"\"Test server can not be reached.\"\"\"\n        resp = MagicMock()\n        resp.status_code = 200\n        resp.text = \"<a></a>\"\n\n        async def slow_request(*args, **kwargs):\n            await asyncio.sleep(10)\n\n        with patch.object(\n            self.connection.channel, \"_request_text\", slow_request\n        ), patch.object(self.connection.channel, \"connection_check_timeout\", 0.01):\n            with pytest.raises(\n                SOEFNetworkConnectionError,\n                match=\"<SOEF Network Connection Error: Server can not be reached within timeout=\",\n            ):\n                await self.connection.channel._check_server_reachable()\n\n    @pytest.mark.asyncio\n    async def test_request_text_ok(self):\n        \"\"\"Test internal method request_text works ok.\"\"\"\n        resp = MagicMock()\n        resp.status_code = 200\n        resp.text = \"<a></a>\"\n        with patch(\"aea.helpers.http_requests.request\", return_value=resp):\n            await self.connection.channel._request_text(\"get\", \"http://not-exists.com\")\n\n    @pytest.mark.asyncio\n    async def test_request_text_fail(self):\n        \"\"\"Test internal method request_text fails.\"\"\"\n        resp = MagicMock()\n        resp.status_code = 400\n        resp.text = \"<a></a>\"\n        with pytest.raises(\n            SOEFServerBadResponseError,\n            match=\"<SOEF Server Bad Response Error: Bad server response: code 400 when 2XX expected.\",\n        ):\n            with patch(\"aea.helpers.http_requests.request\", return_value=resp):\n                await self.connection.channel._request_text(\n                    \"get\", \"http://not-exists.com\"\n                )\n\n        resp.status_code = 200\n        resp.text = \"\"\n        with pytest.raises(\n            SOEFServerBadResponseError,\n            match=\"SOEF Server Bad Response Error: Bad server response: empty response. Request data:\",\n        ):\n            with patch(\"aea.helpers.http_requests.request\", return_value=resp):\n                await self.connection.channel._request_text(\n                    \"get\", \"http://not-exists.com\"\n                )\n\n        resp.status_code = 200\n        resp.text = \"\"\n        with pytest.raises(\n            SOEFNetworkConnectionError,\n            match=\"SOEF Network Connection Error:.*expected!\",\n        ):\n            with patch(\n                \"aea.helpers.http_requests.request\",\n                side_effect=requests.ConnectionError(\"expected!\"),\n            ):\n                await self.connection.channel._request_text(\n                    \"get\", \"http://not-exists.com\"\n                )\n\n    @pytest.mark.asyncio\n    async def test_set_location(self):\n        \"\"\"Test internal method set location.\"\"\"\n        agent_location = Location(52.2057092, 2.1183431)\n        resp_text = '<?xml version=\"1.0\" encoding=\"UTF-8\"?><response></response>'\n        with patch.object(\n            self.connection.channel, \"_request_text\", make_async(resp_text)\n        ):\n            with pytest.raises(SOEFException, match=r\"`set_position`.*Exception: .*\"):\n                await self.connection.channel._set_location(agent_location)\n\n        resp_text = '<?xml version=\"1.0\" encoding=\"UTF-8\"?><response><success>1</success></response>'\n        with patch.object(\n            self.connection.channel, \"_request_text\", make_async(resp_text)\n        ):\n            await self.connection.channel._set_location(agent_location)\n\n    @pytest.mark.asyncio\n    async def test_set_personality_piece(self):\n        \"\"\"Test internal method set_personality_piece.\"\"\"\n        resp_text = '<?xml version=\"1.0\" encoding=\"UTF-8\"?><response></response>'\n        with patch.object(\n            self.connection.channel, \"_request_text\", make_async(resp_text)\n        ):\n            with pytest.raises(\n                SOEFException, match=r\"`set_personality_piece` .*Exception: .*\"\n            ):\n                await self.connection.channel._set_personality_piece(1, 1)\n\n        resp_text = '<?xml version=\"1.0\" encoding=\"UTF-8\"?><response><success>1</success></response>'\n        with patch.object(\n            self.connection.channel, \"_request_text\", make_async(resp_text)\n        ):\n            await self.connection.channel._set_personality_piece(1, 1)\n\n    def teardown(self):\n        \"\"\"Clean up.\"\"\"\n        try:\n            with patch.object(\n                self.connection.channel,\n                \"_request_text\",\n                make_async(\"<response><message>Goodbye!</message></response>\"),\n            ):\n                self.loop.run_until_complete(self.connection.disconnect())\n                shutil.rmtree(self.data_dir)\n        except Exception:  # nosec\n            pass\n\n    @pytest.mark.asyncio\n    async def test__set_value(self):\n        \"\"\"Test set pieces.\"\"\"\n        resp_text = '<?xml version=\"1.0\" encoding=\"UTF-8\"?><response></response>'\n        with patch.object(\n            self.connection.channel, \"_request_text\", make_async(resp_text)\n        ):\n            with pytest.raises(\n                SOEFException, match=r\"`set_personality_piece`.*Exception:\"\n            ):\n                await self.connection.channel._set_personality_piece(1, 1)\n\n        resp_text = '<?xml version=\"1.0\" encoding=\"UTF-8\"?><response><success>1</success></response>'\n        with patch.object(\n            self.connection.channel, \"_request_text\", make_async(resp_text)\n        ):\n            await self.connection.channel._set_personality_piece(1, 1)\n\n    def test_chain_identifier_fail(self):\n        \"\"\"Test fail on invalid chain id.\"\"\"\n        chain_identifier = \"test\"\n        identity = Identity(\"identity\", \"\", \"\")\n\n        configuration = ConnectionConfig(\n            api_key=\"TwiCIriSl0mLahw17pyqoA\",\n            soef_addr=\"s-oef.fetch.ai\",\n            soef_port=443,\n            restricted_to_protocols={OefSearchMessage.protocol_specification_id},\n            connection_id=SOEFConnection.connection_id,\n            chain_identifier=chain_identifier,\n        )\n        with pytest.raises(ValueError, match=\"Unsupported chain_identifier\"):\n            SOEFConnection(\n                configuration=configuration,\n                data_dir=MagicMock(),\n                identity=identity,\n            )\n\n    def test_chain_identifier_ok(self):\n        \"\"\"Test set valid chain id.\"\"\"\n        chain_identifier = \"fetchai_cosmos\"\n        identity = Identity(\"identity\", \"\", \"\")\n\n        configuration = ConnectionConfig(\n            api_key=\"TwiCIriSl0mLahw17pyqoA\",\n            soef_addr=\"s-oef.fetch.ai\",\n            soef_port=443,\n            restricted_to_protocols={OefSearchMessage.protocol_specification_id},\n            connection_id=SOEFConnection.connection_id,\n            chain_identifier=chain_identifier,\n        )\n        connection = SOEFConnection(\n            configuration=configuration,\n            data_dir=MagicMock(),\n            identity=identity,\n        )\n\n        assert connection.channel.chain_identifier == chain_identifier\n\n    @pytest.mark.asyncio\n    async def test_ping_command(self):\n        \"\"\"Test set service key.\"\"\"\n        service_description = Description({}, data_model=models.PING_MODEL)\n        message, _ = self.oef_search_dialogues.create(\n            counterparty=str(SOEFConnection.connection_id.to_any()),\n            performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n            service_description=service_description,\n        )\n        envelope = Envelope(\n            to=message.to,\n            sender=message.sender,\n            message=message,\n        )\n\n        with patch.object(\n            self.connection.channel,\n            \"_request_text\",\n            make_async(self.generic_success_response),\n        ):\n            await self.connection.send(envelope)\n\n        response = await asyncio.wait_for(self.connection.receive(), timeout=1)\n        assert response.message.performative == OefSearchMessage.Performative.SUCCESS\n        assert response.message.agents_info.body == {}\n\n    @pytest.mark.asyncio\n    async def test_periodic_ping_task_is_set(self):\n        \"\"\"Test periodic ping task is set on agent register.\"\"\"\n        resp_text1 = '<?xml version=\"1.0\" encoding=\"UTF-8\"?><response><encrypted>0</encrypted><token>672DB3B67780F98984ABF1123BD11</token><page_address>oef_C95B21A4D5759C8FE7A6304B62B726AB8077BEE4BA191A7B92B388F9B1</page_address></response>'\n        resp_text2 = '<?xml version=\"1.0\" encoding=\"UTF-8\"?><response><success>1</success></response>'\n        resp_text3 = '<?xml version=\"1.0\" encoding=\"UTF-8\"?><response><success>1</success></response>'\n        self.connection.channel.PING_PERIOD = 0.1\n\n        with patch.object(\n            self.connection.channel,\n            \"_request_text\",\n            new_callable=MagicMock,\n            side_effect=[\n                wrap_future(resp_text1),\n                wrap_future(resp_text2),\n                wrap_future(resp_text3),\n            ],\n        ):\n            with patch.object(\n                self.connection.channel, \"_ping_command\", return_value=wrap_future(None)\n            ) as mocked_ping:\n                await self.connection.channel._register_agent()\n\n                assert self.connection.channel._ping_periodic_task is not None\n                await asyncio.sleep(0.3)\n                assert mocked_ping.call_count > 1\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_connections/test_soef/test_soef_integration.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the soef connection module.\"\"\"\nimport logging\nimport time\nimport urllib\nfrom threading import Thread\nfrom typing import Any, Dict, Optional, Tuple, cast\nfrom unittest.mock import MagicMock\nfrom urllib.parse import urlencode\n\nimport pytest\nfrom defusedxml import ElementTree as ET  # pylint: disable=wrong-import-order\n\nfrom aea.configurations.base import ConnectionConfig\nfrom aea.configurations.constants import DEFAULT_LEDGER\nfrom aea.crypto.base import Crypto\nfrom aea.crypto.registries import make_crypto\nfrom aea.helpers.search.models import (\n    Constraint,\n    ConstraintType,\n    Description,\n    Location,\n    Query,\n)\nfrom aea.identity.base import Identity\nfrom aea.mail.base import Envelope\nfrom aea.multiplexer import Multiplexer\n\nfrom packages.fetchai.connections.soef.connection import SOEFConnection\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\n\nfrom .test_soef import OefSearchDialogues\nfrom tests.common.utils import wait_for_condition\nfrom tests.test_packages_for_aea_tests.test_connections.test_soef import models\n\n\nlogging.basicConfig(level=logging.DEBUG)\n\nlogger = logging.getLogger(__name__)\n\n\ndef make_multiplexer_and_dialogues() -> Tuple[\n    Multiplexer, OefSearchDialogues, Crypto, SOEFConnection\n]:\n    \"\"\"Return multplexer, dialogues and crypto instances.\"\"\"\n    crypto = make_crypto(DEFAULT_LEDGER)\n    identity = Identity(\n        \"identity\", address=crypto.address, public_key=crypto.public_key\n    )\n    skill_id = \"some/skill:0.1.0\"\n    oef_search_dialogues = OefSearchDialogues(skill_id)\n\n    # create the connection and multiplexer objects\n    configuration = ConnectionConfig(\n        api_key=\"TwiCIriSl0mLahw17pyqoA\",\n        soef_addr=\"s-oef.fetch.ai\",\n        soef_port=443,\n        restricted_to_protocols={\n            OefSearchMessage.protocol_specification_id,\n            OefSearchMessage.protocol_id,\n        },\n        connection_id=SOEFConnection.connection_id,\n    )\n    soef_connection = SOEFConnection(\n        configuration=configuration,\n        data_dir=MagicMock(),\n        identity=identity,\n    )\n    multiplexer = Multiplexer([soef_connection])\n    return multiplexer, oef_search_dialogues, crypto, soef_connection\n\n\nclass Instance:\n    \"\"\"Test agent instance.\"\"\"\n\n    def __init__(self, location: Location) -> None:\n        \"\"\"Init instance with location provided.\"\"\"\n        self.location = location\n        (\n            self.multiplexer,\n            self.oef_search_dialogues,\n            self.crypto,\n            self.connection,\n        ) = make_multiplexer_and_dialogues()\n        self.thread = Thread(target=self.multiplexer.connect)\n\n    @property\n    def address(self) -> str:\n        \"\"\"Get agent adress.\"\"\"\n        return self.crypto.address\n\n    def start(self) -> None:\n        \"\"\"Start multipelxer.\"\"\"\n        self.thread.start()\n        wait_for_condition(lambda: self.multiplexer.is_connected, timeout=5)\n        self.register_location()\n\n    def stop(self):\n        \"\"\"Stop multipelxer and wait.\"\"\"\n        self.multiplexer.disconnect()\n        self.thread.join()\n\n    def register_location(self, disclosure_accuracy: Optional[str] = None) -> None:\n        \"\"\"Register location.\"\"\"\n        service_instance: Dict[str, Any] = {\"location\": self.location}\n\n        if disclosure_accuracy:\n            service_instance[\"disclosure_accuracy\"] = disclosure_accuracy\n\n        service_description = Description(\n            service_instance, data_model=models.AGENT_LOCATION_MODEL\n        )\n        message, sending_dialogue = self.oef_search_dialogues.create(\n            counterparty=str(SOEFConnection.connection_id.to_any()),\n            performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n            service_description=service_description,\n        )\n        envelope = Envelope(\n            to=message.to,\n            sender=message.sender,\n            message=message,\n        )\n        logger.info(\n            \"Registering agent at location=({},{}) by agent={}\".format(\n                self.location.latitude,\n                self.location.longitude,\n                self.crypto.address,\n            )\n        )\n        self.multiplexer.put(envelope)\n        # check for register results\n        envelope = self.get()\n        assert envelope\n        message = cast(OefSearchMessage, envelope.message)\n        receiving_dialogue = self.oef_search_dialogues.update(message)\n        assert sending_dialogue == receiving_dialogue\n\n    def wait_registered(self) -> None:\n        \"\"\"Wait connection gets unique_page_address.\"\"\"\n        wait_for_condition(\n            lambda: self.connection.channel.unique_page_address, timeout=10\n        )\n\n    def register_personality_pieces(\n        self, piece: str = \"genus\", value: str = \"service\"\n    ) -> None:\n        \"\"\"Register personality pieces.\"\"\"\n        service_instance = {\"piece\": piece, \"value\": value}\n        service_description = Description(\n            service_instance, data_model=models.AGENT_PERSONALITY_MODEL\n        )\n        message, sending_dialogue = self.oef_search_dialogues.create(\n            counterparty=str(SOEFConnection.connection_id.to_any()),\n            performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n            service_description=service_description,\n        )\n        envelope = Envelope(\n            to=message.to,\n            sender=message.sender,\n            message=message,\n        )\n        logger.info(\"Registering agent personality\")\n        self.multiplexer.put(envelope)\n        # check for register results\n        envelope = self.get()\n        assert envelope\n        message = cast(OefSearchMessage, envelope.message)\n        receiving_dialogue = self.oef_search_dialogues.update(message)\n        assert sending_dialogue == receiving_dialogue\n\n    def register_service_key(self, key: str, value: str) -> None:\n        \"\"\"Register service key.\"\"\"\n        service_instance = {\"key\": \"test\", \"value\": \"test\"}\n        service_description = Description(\n            service_instance, data_model=models.SET_SERVICE_KEY_MODEL\n        )\n        message, sending_dialogue = self.oef_search_dialogues.create(\n            counterparty=str(SOEFConnection.connection_id.to_any()),\n            performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n            service_description=service_description,\n        )\n        envelope = Envelope(\n            to=message.to,\n            sender=message.sender,\n            message=message,\n        )\n        logger.info(\"Registering agent service key\")\n        self.multiplexer.put(envelope)\n        # check for register results\n        envelope = self.get()\n        assert envelope\n        message = cast(OefSearchMessage, envelope.message)\n        receiving_dialogue = self.oef_search_dialogues.update(message)\n        assert sending_dialogue == receiving_dialogue\n\n    def search(self, query: Query) -> OefSearchMessage:\n        \"\"\"Perform search with query provided.\"\"\"\n        message, sending_dialogue = self.oef_search_dialogues.create(\n            counterparty=str(SOEFConnection.connection_id.to_any()),\n            performative=OefSearchMessage.Performative.SEARCH_SERVICES,\n            query=query,\n        )\n        search_envelope = Envelope(\n            to=message.to,\n            sender=message.sender,\n            message=message,\n        )\n        logger.info(f\"Searching for agents with query: {query}\")\n        self.multiplexer.put(search_envelope)\n\n        # check for search results\n        envelope = self.get()\n        assert envelope\n        message = cast(OefSearchMessage, envelope.message)\n        receiving_dialogue = self.oef_search_dialogues.update(message)\n        assert sending_dialogue == receiving_dialogue\n        return message\n\n    def get(self):\n        \"\"\"Get an instance.\"\"\"\n        wait_for_condition(lambda: not self.multiplexer.in_queue.empty(), timeout=20)\n        return self.multiplexer.get()\n\n    def generic_command(self, command: str, parameters: Optional[dict] = None) -> None:\n        \"\"\"Register personality pieces.\"\"\"\n        service_instance = {\"command\": command}\n\n        if parameters:\n            service_instance[\"parameters\"] = urlencode(parameters)\n\n        service_description = Description(\n            service_instance, data_model=models.AGENT_GENERIC_COMMAND_MODEL\n        )\n        message, _ = self.oef_search_dialogues.create(\n            counterparty=str(SOEFConnection.connection_id.to_any()),\n            performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n            service_description=service_description,\n        )\n        envelope = Envelope(\n            to=message.to,\n            sender=message.sender,\n            message=message,\n        )\n        logger.info(f\"Send generic command {command} {parameters}\")\n        self.multiplexer.put(envelope)\n\n\nclass TestRealNetwork:\n    \"\"\"Perform tests using real soef server.\"\"\"\n\n    LOCATION = (52.2057092, 2.1183431)\n\n    @pytest.mark.integration\n    def test_search_no_filters(self):\n        \"\"\"Perform tests over real networ with no filters.\"\"\"\n        agent_location = Location(*self.LOCATION)\n        agent = Instance(agent_location)\n        agent2 = Instance(agent_location)\n\n        try:\n            agent.start()\n            agent2.start()\n            agent.wait_registered()\n            agent2.wait_registered()\n            time.sleep(2)\n            # find agents near me\n            radius = 0.1\n            close_to_my_service = Constraint(\n                \"location\", ConstraintType(\"distance\", (agent_location, radius))\n            )\n            closeness_query = Query(\n                [close_to_my_service], model=models.AGENT_LOCATION_MODEL\n            )\n\n            # search for agents close to me\n            message = agent.search(closeness_query)\n            assert message.performative == OefSearchMessage.Performative.SEARCH_RESULT\n            assert len(message.agents) >= 1\n\n            # second message in a raw to check we dont hit limit\n            message = agent.search(closeness_query)\n            assert message.performative == OefSearchMessage.Performative.SEARCH_RESULT\n            assert len(message.agents) >= 1\n\n            assert agent2.address in message.agents\n        finally:\n            agent.stop()\n            agent2.stop()\n\n    @pytest.mark.integration\n    def test_search_filters(self):\n        \"\"\"Test find agents near me with filter.\"\"\"\n        agent_location = Location(*self.LOCATION)\n        agent = Instance(agent_location)\n        agent2 = Instance(agent_location)\n        agent3 = Instance(agent_location)\n        agent.start()\n        agent2.start()\n        agent3.start()\n\n        try:\n            agent2.register_personality_pieces(piece=\"genus\", value=\"service\")\n            agent2.register_service_key(key=\"test\", value=\"test\")\n            agent2.register_location(disclosure_accuracy=\"medium\")\n\n            agent3.register_personality_pieces(piece=\"genus\", value=\"service\")\n            agent3.register_service_key(key=\"test\", value=\"test\")\n            time.sleep(3)\n\n            radius = 0.1\n            close_to_my_service = Constraint(\n                \"location\", ConstraintType(\"distance\", (agent_location, radius))\n            )\n            personality_filters = [\n                Constraint(\"genus\", ConstraintType(\"==\", \"service\")),\n            ]\n            service_key_filters = [\n                Constraint(\"test\", ConstraintType(\"==\", \"test\")),\n            ]\n            constraints = (\n                [close_to_my_service] + personality_filters + service_key_filters\n            )\n\n            closeness_query = Query(constraints)\n            logger.info(\n                \"Searching for agents in radius={} of myself at location=({},{}) with personality filters\".format(\n                    radius,\n                    agent_location.latitude,\n                    agent_location.longitude,\n                )\n            )\n            message = agent.search(closeness_query)\n            assert message.performative == OefSearchMessage.Performative.SEARCH_RESULT\n            assert len(message.agents) >= 1\n            assert agent2.address in message.agents\n            assert agent3.address in message.agents\n\n            agent2_info = message.agents_info.get_info_for_agent(agent2.address)\n            assert agent2_info\n            assert \"name\" in agent2_info\n            assert \"location\" in agent2_info\n            assert agent2_info[\"genus\"] == \"service\"\n\n            agent3_info = message.agents_info.get_info_for_agent(agent3.address)\n            assert agent3_info\n            assert \"name\" in agent3_info\n            assert \"location\" not in agent3_info\n            assert agent3_info[\"genus\"] == \"service\"\n\n        finally:\n            agent.stop()\n            agent2.stop()\n            agent3.stop()\n\n    @pytest.mark.integration\n    def test_ping(self):\n        \"\"\"Test ping command.\"\"\"\n        agent_location = Location(*self.LOCATION)\n        agent = Instance(agent_location)\n        agent.start()\n        try:\n            service_description = Description({}, data_model=models.PING_MODEL)\n            message, _ = agent.oef_search_dialogues.create(\n                counterparty=str(SOEFConnection.connection_id.to_any()),\n                performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n                service_description=service_description,\n            )\n            envelope = Envelope(\n                to=message.to,\n                sender=\"some/skill:0.1.0\",\n                message=message,\n            )\n            logger.info(\"Pinging\")\n            agent.multiplexer.put(envelope)\n            envelope = agent.get()\n            assert (\n                envelope.message.performative == OefSearchMessage.Performative.SUCCESS\n            )\n\n        finally:\n            agent.stop()\n\n    @pytest.mark.integration\n    def test_generic_command(self):\n        \"\"\"Test generic command.\"\"\"\n        agent_location = Location(*self.LOCATION)\n        agent = Instance(agent_location)\n        agent.start()\n\n        try:\n            agent.generic_command(\"set_service_key\", {\"key\": \"test\", \"value\": \"test\"})\n            envelope = agent.get()\n            assert (\n                envelope.message.performative == OefSearchMessage.Performative.SUCCESS\n            )\n            ET.fromstring(envelope.message.agents_info.body[\"response\"][\"content\"])\n\n            agent.generic_command(\"bad_command\")\n            envelope = agent.get()\n            assert (\n                envelope.message.performative == OefSearchMessage.Performative.OEF_ERROR\n            )\n\n        finally:\n            agent.stop()\n\n    @pytest.mark.integration\n    def test_generic_command_set_declared_name(self):\n        \"\"\"Test generic command.\"\"\"\n        agent_location = Location(*self.LOCATION)\n        agent1 = Instance(agent_location)\n        agent1.start()\n        agent2 = Instance(agent_location)\n        agent2.start()\n\n        declared_name = \"new_declared_name\"\n        try:\n            # send generic command.\"\"\"\n            service_description = Description(\n                {\n                    \"command\": \"set_declared_name\",\n                    \"parameters\": urllib.parse.urlencode({\"name\": declared_name}),\n                },\n                data_model=models.AGENT_GENERIC_COMMAND_MODEL,\n            )\n            message, _ = agent1.oef_search_dialogues.create(\n                performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n                service_description=service_description,\n                counterparty=str(SOEFConnection.connection_id.to_any()),\n            )\n\n            envelope = Envelope(\n                to=message.to,\n                sender=message.sender,\n                message=message,\n            )\n            agent1.multiplexer.put(envelope)\n\n            envelope = agent1.get()\n            assert (\n                envelope.message.performative == OefSearchMessage.Performative.SUCCESS\n            )\n\n            radius = 0.1\n            close_to_my_service = Constraint(\n                \"location\", ConstraintType(\"distance\", (agent_location, radius))\n            )\n            closeness_query = Query(\n                [close_to_my_service], model=models.AGENT_LOCATION_MODEL\n            )\n\n            message = agent2.search(closeness_query)\n            assert message.performative == OefSearchMessage.Performative.SEARCH_RESULT\n            assert len(message.agents) >= 1\n\n            assert agent1.address in message.agents_info.body\n            assert message.agents_info.body[agent1.address][\"name\"] == declared_name\n\n        finally:\n            agent1.stop()\n            agent2.stop()\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_connections/test_stub/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests of the stub connection implementation.\"\"\"\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_connections/test_stub/test_stub.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This test module contains the tests for the stub connection.\"\"\"\nimport asyncio\nimport base64\nimport os\nimport shutil\nimport tempfile\nimport time\nfrom asyncio.tasks import ensure_future\nfrom pathlib import Path\nfrom unittest import mock\n\nimport pytest\n\nfrom aea.configurations.base import PublicId\nfrom aea.crypto.wallet import CryptoStore\nfrom aea.helpers.file_io import write_with_lock\nfrom aea.identity.base import Identity\nfrom aea.mail.base import Envelope\nfrom aea.multiplexer import Multiplexer\n\nfrom packages.fetchai.connections.stub.connection import (\n    StubConnection,\n    envelope_from_bytes,\n    lock_file,\n    write_envelope,\n)\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\n\nfrom tests.conftest import ROOT_DIR, _make_stub_connection\n\n\nSEPARATOR = \",\"\n\n\ndef make_test_envelope() -> Envelope:\n    \"\"\"Create a test envelope.\"\"\"\n    msg = DefaultMessage(\n        dialogue_reference=(\"\", \"\"),\n        message_id=1,\n        target=0,\n        performative=DefaultMessage.Performative.BYTES,\n        content=b\"hello\",\n    )\n    msg.to = \"any\"\n    envelope = Envelope(\n        to=\"any\",\n        sender=\"any\",\n        message=msg,\n    )\n    return envelope\n\n\nclass TestStubConnectionReception:\n    \"\"\"Test that the stub connection is implemented correctly.\"\"\"\n\n    def setup(self):\n        \"\"\"Set the test up.\"\"\"\n        self.cwd = os.getcwd()\n        self.tmpdir = Path(tempfile.mkdtemp())\n        d = self.tmpdir / \"test_stub\"\n        d.mkdir(parents=True)\n        self.input_file_path = d / \"input_file.csv\"\n        self.output_file_path = d / \"output_file.csv\"\n        self.connection = _make_stub_connection(\n            self.input_file_path, self.output_file_path\n        )\n\n        self.multiplexer = Multiplexer([self.connection])\n        self.multiplexer.connect()\n        os.chdir(self.tmpdir)\n\n    def test_reception_a(self):\n        \"\"\"Test that the connection receives what has been enqueued in the input file.\"\"\"\n        msg = DefaultMessage(\n            dialogue_reference=(\"\", \"\"),\n            message_id=1,\n            target=0,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"hello\",\n        )\n        expected_envelope = Envelope(\n            to=\"any\",\n            sender=\"anys\",\n            message=msg,\n        )\n\n        with open(self.input_file_path, \"ab+\") as f:\n            write_envelope(expected_envelope, f)\n\n        actual_envelope = self.multiplexer.get(block=True, timeout=3.0)\n        assert expected_envelope.to == actual_envelope.to\n        assert expected_envelope.sender == actual_envelope.sender\n        assert (\n            expected_envelope.protocol_specification_id\n            == actual_envelope.protocol_specification_id\n        )\n        msg = DefaultMessage.serializer.decode(actual_envelope.message)\n        msg.to = actual_envelope.to\n        msg.sender = actual_envelope.sender\n        assert expected_envelope.message == msg\n\n    def test_reception_b(self):\n        \"\"\"Test that the connection receives what has been enqueued in the input file.\"\"\"\n        # a message containing delimiters and newline characters\n        msg = b\"\\x08\\x02\\x12\\x011\\x1a\\x011 \\x01:,\\n*0x32468d\\n,\\nB8Ab795\\n\\n49B49C88DC991990E7910891,,dbd\\n\"\n        protocol_specification_id = PublicId.from_str(\"some_author/some_name:0.1.0\")\n        encoded_envelope = \"{}{}{}{}{}{}{}{}\".format(\n            \"any\",\n            SEPARATOR,\n            \"any\",\n            SEPARATOR,\n            protocol_specification_id,\n            SEPARATOR,\n            msg.decode(\"utf-8\"),\n            SEPARATOR,\n        )\n        encoded_envelope = encoded_envelope.encode(\"utf-8\")\n\n        with open(self.input_file_path, \"ab+\") as f:\n            write_with_lock(f, encoded_envelope)\n\n        actual_envelope = self.multiplexer.get(block=True, timeout=3.0)\n        assert \"any\" == actual_envelope.to\n        assert \"any\" == actual_envelope.sender\n        assert protocol_specification_id == actual_envelope.protocol_specification_id\n        assert msg == actual_envelope.message\n\n    def test_reception_c(self):\n        \"\"\"Test that the connection receives what has been enqueued in the input file.\"\"\"\n        encoded_envelope = b\"0x5E22777dD831A459535AA4306AceC9cb22eC4cB5,default_oef,fetchai/oef_search:1.0.0,\\x08\\x02\\x12\\x011\\x1a\\x011 \\x01:,\\n*0x32468dB8Ab79549B49C88DC991990E7910891dbd,\"\n        expected_envelope = Envelope(\n            to=\"0x5E22777dD831A459535AA4306AceC9cb22eC4cB5\",\n            sender=\"default_oef\",\n            protocol_specification_id=OefSearchMessage.protocol_specification_id,\n            message=b\"\\x08\\x02\\x12\\x011\\x1a\\x011 \\x01:,\\n*0x32468dB8Ab79549B49C88DC991990E7910891dbd\",\n        )\n        with open(self.input_file_path, \"ab+\") as f:\n            write_with_lock(f, encoded_envelope)\n\n        actual_envelope = self.multiplexer.get(block=True, timeout=3.0)\n        assert expected_envelope == actual_envelope\n\n    def teardown(self):\n        \"\"\"Tear down the test.\"\"\"\n        os.chdir(self.cwd)\n        try:\n            shutil.rmtree(self.tmpdir)\n        except (OSError, IOError):\n            pass\n        self.multiplexer.disconnect()\n\n\nclass TestStubConnectionSending:\n    \"\"\"Test that the stub connection is implemented correctly.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set the test up.\"\"\"\n        cls.cwd = os.getcwd()\n        cls.tmpdir = Path(tempfile.mkdtemp())\n        d = cls.tmpdir / \"test_stub\"\n        d.mkdir(parents=True)\n        cls.input_file_path = d / \"input_file.csv\"\n        cls.output_file_path = d / \"output_file.csv\"\n        cls.connection = _make_stub_connection(\n            cls.input_file_path, cls.output_file_path\n        )\n\n        cls.multiplexer = Multiplexer([cls.connection])\n        cls.multiplexer.connect()\n        os.chdir(cls.tmpdir)\n\n    def test_connection_is_established(self):\n        \"\"\"Test the stub connection is established and then bad formatted messages.\"\"\"\n        assert self.connection.is_connected\n        msg = DefaultMessage(\n            dialogue_reference=(\"\", \"\"),\n            message_id=1,\n            target=0,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"hello\",\n        )\n        encoded_envelope = \"{}{}{}{}{}{}{}{}\".format(\n            \"any\",\n            SEPARATOR,\n            \"any\",\n            SEPARATOR,\n            DefaultMessage.protocol_specification_id,\n            SEPARATOR,\n            DefaultMessage.serializer.encode(msg).decode(\"utf-8\"),\n            SEPARATOR,\n        )\n        encoded_envelope = base64.b64encode(encoded_envelope.encode(\"utf-8\"))\n        envelope = envelope_from_bytes(encoded_envelope)\n        if envelope is not None:\n            self.connection._put_envelopes([envelope])\n\n        assert (\n            self.connection.in_queue.empty()\n        ), \"The inbox must be empty due to bad encoded message\"\n\n    def test_send_message(self):\n        \"\"\"Test that the messages in the outbox are posted on the output file.\"\"\"\n        msg = DefaultMessage(\n            dialogue_reference=(\"\", \"\"),\n            message_id=1,\n            target=0,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"hello\",\n        )\n        expected_envelope = Envelope(\n            to=\"any\",\n            sender=\"anys\",\n            message=msg,\n        )\n\n        self.multiplexer.put(expected_envelope)\n        time.sleep(0.1)\n\n        with open(self.output_file_path, \"rb+\") as f:\n            lines = f.readlines()\n\n        assert len(lines) == 2\n        line = lines[0] + lines[1]\n        to, sender, protocol_specification_id, message, end = line.strip().split(\n            \"{}\".format(SEPARATOR).encode(\"utf-8\"), maxsplit=4\n        )\n        to = to.decode(\"utf-8\")\n        sender = sender.decode(\"utf-8\")\n        protocol_specification_id = PublicId.from_str(\n            protocol_specification_id.decode(\"utf-8\")\n        )\n        assert end in [b\"\", b\"\\n\"]\n\n        actual_envelope = Envelope(\n            to=to,\n            sender=sender,\n            protocol_specification_id=protocol_specification_id,\n            message=message,\n        )\n        assert expected_envelope.to == actual_envelope.to\n        assert expected_envelope.sender == actual_envelope.sender\n        assert (\n            expected_envelope.protocol_specification_id\n            == actual_envelope.protocol_specification_id\n        )\n        msg = DefaultMessage.serializer.decode(actual_envelope.message)\n        msg.to = actual_envelope.to\n        msg.sender = actual_envelope.sender\n        assert expected_envelope.message == msg\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear down the test.\"\"\"\n        os.chdir(cls.cwd)\n        try:\n            shutil.rmtree(cls.tmpdir)\n        except (OSError, IOError):\n            pass\n        cls.multiplexer.disconnect()\n\n\n@pytest.mark.asyncio\nasync def test_disconnection_when_already_disconnected():\n    \"\"\"Test the case when disconnecting a connection already disconnected.\"\"\"\n    tmpdir = Path(tempfile.mkdtemp())\n    d = tmpdir / \"test_stub\"\n    d.mkdir(parents=True)\n    input_file_path = d / \"input_file.csv\"\n    output_file_path = d / \"output_file.csv\"\n    connection = _make_stub_connection(input_file_path, output_file_path)\n\n    assert not connection.is_connected\n    await connection.disconnect()\n    assert not connection.is_connected\n\n\n@pytest.mark.asyncio\nasync def test_connection_when_already_connected():\n    \"\"\"Test the case when connecting a connection already connected.\"\"\"\n    tmpdir = Path(tempfile.mkdtemp())\n    d = tmpdir / \"test_stub\"\n    d.mkdir(parents=True)\n    input_file_path = d / \"input_file.csv\"\n    output_file_path = d / \"output_file.csv\"\n    connection = _make_stub_connection(input_file_path, output_file_path)\n\n    assert not connection.is_connected\n    await connection.connect()\n    assert connection.is_connected\n    await connection.connect()\n    assert connection.is_connected\n\n    await connection.disconnect()\n\n\n@pytest.mark.asyncio\nasync def test_receiving_returns_none_when_error_occurs():\n    \"\"\"Test that when we try to receive an envelope and an error occurs we return None.\"\"\"\n    tmpdir = Path(tempfile.mkdtemp())\n    d = tmpdir / \"test_stub\"\n    d.mkdir(parents=True)\n    input_file_path = d / \"input_file.csv\"\n    output_file_path = d / \"output_file.csv\"\n    connection = _make_stub_connection(input_file_path, output_file_path)\n\n    await connection.connect()\n    with mock.patch.object(connection.in_queue, \"get\", side_effect=Exception):\n        ret = await connection.receive()\n        assert ret is None\n\n    await connection.disconnect()\n\n\n@pytest.mark.asyncio\nasync def test_multiple_envelopes():\n    \"\"\"Test many envelopes received.\"\"\"\n    tmpdir = Path(tempfile.mkdtemp())\n    d = tmpdir / \"test_stub\"\n    d.mkdir(parents=True)\n    input_file_path = d / \"input_file.csv\"\n    output_file_path = d / \"output_file.csv\"\n    connection = _make_stub_connection(input_file_path, output_file_path)\n\n    num_envelopes = 5\n    await connection.connect()\n    assert connection.is_connected\n\n    async def wait_num(num):\n        for _ in range(num):\n            assert await connection.receive()\n\n    task = asyncio.get_event_loop().create_task(wait_num(num_envelopes))\n\n    with open(input_file_path, \"ab+\") as f:\n        for _ in range(num_envelopes):\n            write_envelope(make_test_envelope(), f)\n            await asyncio.sleep(0.01)  # spin asyncio loop\n\n    await asyncio.wait_for(task, timeout=3)\n    await connection.disconnect()\n\n\n@pytest.mark.asyncio\nasync def test_bad_envelope():\n    \"\"\"Test bad format envelop.\"\"\"\n    tmpdir = Path(tempfile.mkdtemp())\n    d = tmpdir / \"test_stub\"\n    d.mkdir(parents=True)\n    input_file_path = d / \"input_file.csv\"\n    output_file_path = d / \"output_file.csv\"\n    connection = _make_stub_connection(input_file_path, output_file_path)\n\n    await connection.connect()\n\n    with open(input_file_path, \"ab+\") as f:\n        f.write(b\"1,2,3,4,5,\")\n        f.flush()\n\n    with pytest.raises(asyncio.TimeoutError):\n        f = ensure_future(connection.receive())\n        await asyncio.wait_for(f, timeout=0.1)\n\n    await connection.disconnect()\n\n\n@pytest.mark.asyncio\nasync def test_load_from_dir():\n    \"\"\"Test stub connection can be loaded from dir.\"\"\"\n    StubConnection.from_dir(\n        ROOT_DIR + \"/packages/fetchai/connections/stub\",\n        Identity(\"name\", \"address\", \"public_key\"),\n        CryptoStore(),\n        os.getcwd(),\n    )\n\n\nclass TestFileLock:\n    \"\"\"Test for filelocks.\"\"\"\n\n    def test_lock_file_ok(self):\n        \"\"\"Work ok ok for random file.\"\"\"\n        with tempfile.TemporaryFile() as fp:\n            with lock_file(fp):\n                pass\n\n    def test_lock_file_error(self):\n        \"\"\"Fail on closed file.\"\"\"\n        with tempfile.TemporaryFile() as fp:\n            fp.close()\n            with pytest.raises(ValueError):\n                with lock_file(fp):\n                    pass\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_connections/test_tcp/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests of the TCP connection.\"\"\"\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_connections/test_tcp/test_base.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests for the TCP base module.\"\"\"\n\nimport asyncio\nimport unittest.mock\nfrom asyncio import CancelledError\n\nimport pytest\n\nfrom aea.mail.base import Envelope\n\nfrom packages.fetchai.protocols.default.message import DefaultMessage\n\nfrom tests.conftest import (\n    _make_tcp_client_connection,\n    _make_tcp_server_connection,\n    get_unused_tcp_port,\n)\n\n\n@pytest.mark.asyncio\nasync def test_connect_twice():\n    \"\"\"Test that connecting twice the tcp connection works correctly.\"\"\"\n    port = get_unused_tcp_port()\n    tcp_connection = _make_tcp_server_connection(\n        \"address\", \"public_key\", \"127.0.0.1\", port\n    )\n\n    await tcp_connection.connect()\n    await asyncio.sleep(0.1)\n    with unittest.mock.patch.object(tcp_connection.logger, \"warning\") as mock_logger:\n        await tcp_connection.connect()\n        mock_logger.assert_called_with(\"Connection already set up.\")\n\n    await tcp_connection.disconnect()\n\n\n@pytest.mark.asyncio\nasync def test_connect_raises_exception():\n    \"\"\"Test the case that a connection attempt raises an exception.\"\"\"\n    port = get_unused_tcp_port()\n    tcp_connection = _make_tcp_server_connection(\n        \"address\", \"public_key\", \"127.0.0.1\", port\n    )\n\n    with unittest.mock.patch.object(tcp_connection.logger, \"error\") as mock_logger:\n        with unittest.mock.patch.object(\n            tcp_connection, \"setup\", side_effect=Exception(\"error during setup\")\n        ):\n            await tcp_connection.connect()\n            mock_logger.assert_called_with(\"error during setup\")\n\n\n@pytest.mark.asyncio\nasync def test_disconnect_when_already_disconnected():\n    \"\"\"Test that disconnecting a connection already disconnected works correctly.\"\"\"\n    port = get_unused_tcp_port()\n    tcp_connection = _make_tcp_server_connection(\n        \"address\", \"public_key\", \"127.0.0.1\", port\n    )\n\n    with unittest.mock.patch.object(tcp_connection.logger, \"warning\") as mock_logger:\n        await tcp_connection.disconnect()\n        mock_logger.assert_called_with(\"Connection already disconnected.\")\n\n\n@pytest.mark.asyncio\nasync def test_send_to_unknown_destination():\n    \"\"\"Test that a message to an unknown destination logs an error.\"\"\"\n    address = \"address\"\n    port = get_unused_tcp_port()\n    tcp_connection = _make_tcp_server_connection(\n        \"address\", \"public_key\", \"127.0.0.1\", port\n    )\n    envelope = Envelope(\n        to=\"non_existing_destination\",\n        sender=\"address\",\n        protocol_specification_id=DefaultMessage.protocol_specification_id,\n        message=b\"\",\n    )\n    with unittest.mock.patch.object(tcp_connection.logger, \"error\") as mock_logger:\n        await tcp_connection.send(envelope)\n        mock_logger.assert_called_with(\n            \"[{}]: Cannot send envelope {}\".format(address, envelope)\n        )\n\n\n@pytest.mark.asyncio\nasync def test_send_cancelled():\n    \"\"\"Test that cancelling a send works correctly.\"\"\"\n    port = get_unused_tcp_port()\n    tcp_server = _make_tcp_server_connection(\n        \"address_server\", \"public_key\", \"127.0.0.1\", port\n    )\n    tcp_client = _make_tcp_client_connection(\n        \"address_client\", \"public_key_client\", \"127.0.0.1\", port\n    )\n\n    await tcp_server.connect()\n    await tcp_client.connect()\n\n    with unittest.mock.patch.object(\n        tcp_client._writer, \"drain\", side_effect=CancelledError\n    ):\n        envelope = Envelope(\n            to=\"address_client\",\n            sender=\"address_server\",\n            protocol_specification_id=DefaultMessage.protocol_specification_id,\n            message=b\"\",\n        )\n        await tcp_client.send(envelope)\n\n    await tcp_client.disconnect()\n    await tcp_server.disconnect()\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_connections/test_tcp/test_communication.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests for the TCP connection communication.\"\"\"\n\nimport asyncio\nimport struct\nimport unittest.mock\n\nimport pytest\n\nfrom aea.mail.base import Envelope\nfrom aea.multiplexer import Multiplexer\n\nfrom packages.fetchai.protocols.default.message import DefaultMessage\n\nfrom tests.conftest import (\n    _make_tcp_client_connection,\n    _make_tcp_server_connection,\n    get_unused_tcp_port,\n)\n\n\nclass TestTCPCommunication:\n    \"\"\"Test that TCP Server and TCP Client can communicate.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set up the test class.\"\"\"\n        cls.host = \"127.0.0.1\"\n        cls.port = get_unused_tcp_port()\n\n        cls.server_addr = \"server_addr\"\n        cls.server_public_key = \"server_public_key\"\n        cls.client_addr_1 = \"client_addr_1\"\n        cls.client_public_key_1 = \"client_public_key_1\"\n        cls.client_addr_2 = \"client_addr_2\"\n        cls.client_public_key_2 = \"client_public_key_2\"\n\n        cls.server_conn = _make_tcp_server_connection(\n            cls.server_addr,\n            cls.server_public_key,\n            cls.host,\n            cls.port,\n        )\n        cls.client_conn_1 = _make_tcp_client_connection(\n            cls.client_addr_1,\n            cls.client_public_key_1,\n            cls.host,\n            cls.port,\n        )\n        cls.client_conn_2 = _make_tcp_client_connection(\n            cls.client_addr_2,\n            cls.client_public_key_2,\n            cls.host,\n            cls.port,\n        )\n\n        cls.server_multiplexer = Multiplexer([cls.server_conn])\n        cls.client_1_multiplexer = Multiplexer([cls.client_conn_1])\n        cls.client_2_multiplexer = Multiplexer([cls.client_conn_2])\n\n        assert not cls.server_conn.is_connected\n        assert not cls.client_conn_1.is_connected\n        assert not cls.client_conn_2.is_connected\n\n        cls.server_multiplexer.connect()\n        cls.client_1_multiplexer.connect()\n        cls.client_2_multiplexer.connect()\n\n    def test_is_connected(self):\n        \"\"\"Test that the connection status are connected.\"\"\"\n        assert self.server_conn.is_connected\n        assert self.client_conn_1.is_connected\n        assert self.client_conn_2.is_connected\n\n    def test_communication_client_server(self):\n        \"\"\"Test that envelopes can be sent from a client to a server.\"\"\"\n        msg = DefaultMessage(\n            dialogue_reference=(\"\", \"\"),\n            message_id=1,\n            target=0,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"hello\",\n        )\n        expected_envelope = Envelope(\n            to=self.server_addr,\n            sender=self.client_addr_1,\n            message=msg,\n        )\n        self.client_1_multiplexer.put(expected_envelope)\n        actual_envelope = self.server_multiplexer.get(block=True, timeout=5.0)\n\n        assert expected_envelope.to == actual_envelope.to\n        assert expected_envelope.sender == actual_envelope.sender\n        assert (\n            expected_envelope.protocol_specification_id\n            == actual_envelope.protocol_specification_id\n        )\n        assert expected_envelope.message != actual_envelope.message\n        msg = DefaultMessage.serializer.decode(actual_envelope.message)\n        msg.to = actual_envelope.to\n        msg.sender = actual_envelope.sender\n        assert expected_envelope.message == msg\n\n    def test_communication_server_client(self):\n        \"\"\"Test that envelopes can be sent from a server to a client.\"\"\"\n        msg = DefaultMessage(\n            dialogue_reference=(\"\", \"\"),\n            message_id=1,\n            target=0,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"hello\",\n        )\n        expected_envelope = Envelope(\n            to=self.client_addr_1,\n            sender=self.server_addr,\n            message=msg,\n        )\n        self.server_multiplexer.put(expected_envelope)\n        actual_envelope = self.client_1_multiplexer.get(block=True, timeout=5.0)\n\n        assert expected_envelope.to == actual_envelope.to\n        assert expected_envelope.sender == actual_envelope.sender\n        assert (\n            expected_envelope.protocol_specification_id\n            == actual_envelope.protocol_specification_id\n        )\n        assert expected_envelope.message != actual_envelope.message\n        msg = DefaultMessage.serializer.decode(actual_envelope.message)\n        msg.to = actual_envelope.to\n        msg.sender = actual_envelope.sender\n        assert expected_envelope.message == msg\n\n        msg = DefaultMessage(\n            dialogue_reference=(\"\", \"\"),\n            message_id=1,\n            target=0,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"hello\",\n        )\n        expected_envelope = Envelope(\n            to=self.client_addr_2,\n            sender=self.server_addr,\n            message=msg,\n        )\n        self.server_multiplexer.put(expected_envelope)\n        actual_envelope = self.client_2_multiplexer.get(block=True, timeout=5.0)\n\n        assert expected_envelope.to == actual_envelope.to\n        assert expected_envelope.sender == actual_envelope.sender\n        assert (\n            expected_envelope.protocol_specification_id\n            == actual_envelope.protocol_specification_id\n        )\n        assert expected_envelope.message != actual_envelope.message\n        msg = DefaultMessage.serializer.decode(actual_envelope.message)\n        msg.to = actual_envelope.to\n        msg.sender = actual_envelope.sender\n        assert expected_envelope.message == msg\n\n    @classmethod\n    def teardown_class(cls):\n        \"\"\"Tear down the test class.\"\"\"\n        cls.server_multiplexer.disconnect()\n        cls.client_1_multiplexer.disconnect()\n        cls.client_2_multiplexer.disconnect()\n\n\nclass TestTCPClientConnection:\n    \"\"\"Test TCP Client code.\"\"\"\n\n    @pytest.mark.asyncio\n    async def test_receive_cancelled(self):\n        \"\"\"Test that cancelling a receive task works correctly.\"\"\"\n        port = get_unused_tcp_port()\n        tcp_server = _make_tcp_server_connection(\n            \"address_server\",\n            \"public_key_server\",\n            \"127.0.0.1\",\n            port,\n        )\n        tcp_client = _make_tcp_client_connection(\n            \"address_client\",\n            \"public_key_client\",\n            \"127.0.0.1\",\n            port,\n        )\n\n        await tcp_server.connect()\n        await tcp_client.connect()\n\n        with unittest.mock.patch.object(tcp_client.logger, \"debug\") as mock_logger:\n            task = asyncio.ensure_future(tcp_client.receive())\n            await asyncio.sleep(0.1)\n            task.cancel()\n            await asyncio.sleep(0.1)\n            mock_logger.assert_called_with(\n                \"[{}] Read cancelled.\".format(\"address_client\")\n            )\n            assert task.result() is None\n\n        await tcp_client.disconnect()\n        await tcp_server.disconnect()\n\n    @pytest.mark.asyncio\n    async def test_receive_raises_struct_error(self):\n        \"\"\"Test the case when a receive raises a struct error.\"\"\"\n        port = get_unused_tcp_port()\n        tcp_server = _make_tcp_server_connection(\n            \"address_server\",\n            \"public_key_server\",\n            \"127.0.0.1\",\n            port,\n        )\n        tcp_client = _make_tcp_client_connection(\n            \"address_client\",\n            \"public_key_client\",\n            \"127.0.0.1\",\n            port,\n        )\n\n        await tcp_server.connect()\n        await tcp_client.connect()\n\n        with unittest.mock.patch.object(tcp_client.logger, \"debug\") as mock_logger:\n            with unittest.mock.patch.object(\n                tcp_client, \"_recv\", side_effect=struct.error\n            ):\n                task = asyncio.ensure_future(tcp_client.receive())\n                await asyncio.sleep(0.1)\n                mock_logger.assert_called_with(\"Struct error: \")\n                assert task.result() is None\n\n        await tcp_client.disconnect()\n        await tcp_server.disconnect()\n\n    @pytest.mark.asyncio\n    async def test_receive_raises_exception(self):\n        \"\"\"Test the case when a receive raises a generic exception.\"\"\"\n        port = get_unused_tcp_port()\n        tcp_server = _make_tcp_server_connection(\n            \"address_server\",\n            \"public_key_server\",\n            \"127.0.0.1\",\n            port,\n        )\n        tcp_client = _make_tcp_client_connection(\n            \"address_client\",\n            \"public_key_client\",\n            \"127.0.0.1\",\n            port,\n        )\n\n        await tcp_server.connect()\n        await tcp_client.connect()\n\n        with pytest.raises(Exception, match=\"generic exception\"):\n            with unittest.mock.patch.object(\n                tcp_client, \"_recv\", side_effect=Exception(\"generic exception\")\n            ):\n                task = asyncio.ensure_future(tcp_client.receive())\n                await asyncio.sleep(0.1)\n                assert task.result() is None\n\n        await tcp_client.disconnect()\n        await tcp_server.disconnect()\n\n\nclass TestTCPServerConnection:\n    \"\"\"Test TCP Server code.\"\"\"\n\n    @pytest.mark.asyncio\n    async def test_receive_raises_exception(self):\n        \"\"\"Test the case when a receive raises a generic exception.\"\"\"\n        port = get_unused_tcp_port()\n        tcp_server = _make_tcp_server_connection(\n            \"address_server\",\n            \"public_key_server\",\n            \"127.0.0.1\",\n            port,\n        )\n        tcp_client = _make_tcp_client_connection(\n            \"address_client\",\n            \"public_key_client\",\n            \"127.0.0.1\",\n            port,\n        )\n\n        await tcp_server.connect()\n        await tcp_client.connect()\n        await asyncio.sleep(0.1)\n\n        with unittest.mock.patch.object(tcp_server.logger, \"error\") as mock_logger:\n            with unittest.mock.patch(\n                \"asyncio.wait\", side_effect=Exception(\"generic exception\")\n            ):\n                result = await tcp_server.receive()\n                assert result is None\n                mock_logger.assert_any_call(\n                    \"Error in the receiving loop: generic exception\"\n                )\n\n        await tcp_client.disconnect()\n        await tcp_server.disconnect()\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_protocols/test_acn.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests of the messages module.\"\"\"\n\nfrom typing import Type\nfrom unittest import mock\nfrom unittest.mock import patch\n\nimport pytest\n\nfrom aea.common import Address\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\nfrom aea.protocols.dialogue.base import DialogueLabel\n\nfrom packages.fetchai.protocols.acn.dialogues import AcnDialogue as BaseAcnDialogue\nfrom packages.fetchai.protocols.acn.dialogues import AcnDialogues as BaseAcnDialogues\nfrom packages.fetchai.protocols.acn.message import AcnMessage\n\n\ndef test_acn_aea_envelope_serialization():\n    \"\"\"Test that the serialization for the 'simple' protocol works for the AEA_ENVELOPE message.\"\"\"\n    expected_msg = AcnMessage(\n        dialogue_reference=(\"\", \"\"),\n        message_id=1,\n        target=0,\n        performative=AcnMessage.Performative.AEA_ENVELOPE,\n        envelope=b\"envelope\",\n        record=AcnMessage.AgentRecord(\n            address=\"address\",\n            public_key=\"pbk\",\n            peer_public_key=\"peerpbk\",\n            signature=\"sign\",\n            service_id=\"acn\",\n            ledger_id=\"fetchai\",\n        ),\n    )\n    msg_bytes = AcnMessage.serializer.encode(expected_msg)\n    actual_msg = AcnMessage.serializer.decode(msg_bytes)\n    assert expected_msg == actual_msg\n\n\ndef test_acn_lookup_request_serialization():\n    \"\"\"Test that the serialization for the 'simple' protocol works for the LOOKUP_REQUEST message.\"\"\"\n    msg = AcnMessage(\n        dialogue_reference=(\"\", \"\"),\n        message_id=1,\n        target=0,\n        performative=AcnMessage.Performative.LOOKUP_REQUEST,\n        agent_address=\"some_address\",\n    )\n    msg_bytes = AcnMessage.serializer.encode(msg)\n    actual_msg = AcnMessage.serializer.decode(msg_bytes)\n    expected_msg = msg\n    assert expected_msg == actual_msg\n\n\ndef test_acn_lookup_response_serialization():\n    \"\"\"Test that the serialization for the 'simple' protocol works for the LOOKUP_RESPONSE message.\"\"\"\n    msg = AcnMessage(\n        dialogue_reference=(\"\", \"\"),\n        message_id=1,\n        target=0,\n        performative=AcnMessage.Performative.LOOKUP_RESPONSE,\n        record=AcnMessage.AgentRecord(\n            address=\"address\",\n            public_key=\"pbk\",\n            peer_public_key=\"peerpbk\",\n            signature=\"sign\",\n            service_id=\"acn\",\n            ledger_id=\"fetchai\",\n        ),\n    )\n    msg_bytes = AcnMessage.serializer.encode(msg)\n    actual_msg = AcnMessage.serializer.decode(msg_bytes)\n    expected_msg = msg\n    assert expected_msg == actual_msg\n\n\ndef test_acn_record_serialization():\n    \"\"\"Test that the serialization for the 'simple' protocol works for the REGISTER message.\"\"\"\n    msg = AcnMessage(\n        dialogue_reference=(\"\", \"\"),\n        message_id=1,\n        target=0,\n        performative=AcnMessage.Performative.REGISTER,\n        record=AcnMessage.AgentRecord(\n            address=\"address\",\n            public_key=\"pbk\",\n            peer_public_key=\"peerpbk\",\n            signature=\"sign\",\n            service_id=\"acn\",\n            ledger_id=\"fetchai\",\n        ),\n    )\n    msg_bytes = AcnMessage.serializer.encode(msg)\n    actual_msg = AcnMessage.serializer.decode(msg_bytes)\n    expected_msg = msg\n    assert expected_msg == actual_msg\n\n\ndef test_acn_status_serialization():\n    \"\"\"Test that the serialization for the 'simple' protocol works for the STATUS message.\"\"\"\n    msg = AcnMessage(\n        dialogue_reference=(\"\", \"\"),\n        message_id=1,\n        target=0,\n        performative=AcnMessage.Performative.STATUS,\n        body=AcnMessage.StatusBody(\n            status_code=AcnMessage.StatusBody.StatusCode.ERROR_UNSUPPORTED_VERSION,\n            msgs=[\"pbk\"],\n        ),\n    )\n    msg_bytes = AcnMessage.serializer.encode(msg)\n    actual_msg = AcnMessage.serializer.decode(msg_bytes)\n    expected_msg = msg\n    assert expected_msg == actual_msg\n\n\ndef test_acn_message_str_values():\n    \"\"\"Tests the returned string values of acn Message.\"\"\"\n    assert (\n        str(AcnMessage.Performative.LOOKUP_REQUEST) == \"lookup_request\"\n    ), \"AcnMessage.Performative.LOOKUP_REQUEST must be lookup_request\"\n\n\ndef test_encoding_unknown_performative():\n    \"\"\"Test that we raise an exception when the performative is unknown during encoding.\"\"\"\n    msg = AcnMessage(\n        performative=AcnMessage.Performative.LOOKUP_REQUEST,\n        agent_address=\"address\",\n    )\n\n    with pytest.raises(ValueError, match=\"Performative not valid:\"):\n        with mock.patch.object(AcnMessage.Performative, \"__eq__\", return_value=False):\n            AcnMessage.serializer.encode(msg)\n\n\ndef test_check_consistency_raises_exception_when_type_not_recognized():\n    \"\"\"Test that we raise exception when the type of the message is not recognized.\"\"\"\n    message = AcnMessage(\n        dialogue_reference=(\"\", \"\"),\n        message_id=1,\n        target=0,\n        performative=AcnMessage.Performative.LOOKUP_REQUEST,\n        agent_address=\"address\",\n    )\n    # mock the __eq__ method such that any kind of matching is going to fail.\n    with mock.patch.object(AcnMessage.Performative, \"__eq__\", return_value=False):\n        assert not message._is_consistent()\n\n\ndef test_acn_valid_performatives():\n    \"\"\"Test 'valid_performatives' getter.\"\"\"\n    msg = AcnMessage(AcnMessage.Performative.LOOKUP_REQUEST, agent_address=\"address\")\n    assert msg.valid_performatives == set(\n        map(lambda x: x.value, iter(AcnMessage.Performative))\n    )\n\n\ndef test_serializer_performative_not_found():\n    \"\"\"Test the serializer when the performative is not found.\"\"\"\n    message = AcnMessage(\n        message_id=1,\n        target=0,\n        performative=AcnMessage.Performative.LOOKUP_REQUEST,\n        agent_address=\"address\",\n    )\n    message_bytes = message.serializer.encode(message)\n    with patch.object(AcnMessage.Performative, \"__eq__\", return_value=False):\n        with pytest.raises(ValueError, match=\"Performative not valid: .*\"):\n            message.serializer.decode(message_bytes)\n\n\ndef test_dialogues():\n    \"\"\"Test intiaontiation of dialogues.\"\"\"\n    acn_dialogues = AcnDialogues(\"agent_addr\")\n    msg, dialogue = acn_dialogues.create(\n        counterparty=\"abc\",\n        performative=AcnMessage.Performative.LOOKUP_REQUEST,\n        agent_address=\"address\",\n    )\n    assert dialogue is not None\n\n\nclass AcnDialogue(BaseAcnDialogue):\n    \"\"\"The dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    def __init__(\n        self,\n        dialogue_label: DialogueLabel,\n        self_address: Address,\n        role: BaseDialogue.Role,\n        message_class: Type[AcnMessage],\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n\n        :return: None\n        \"\"\"\n        BaseAcnDialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            self_address=self_address,\n            role=role,\n            message_class=message_class,\n        )\n\n\nclass AcnDialogues(BaseAcnDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, self_address: Address) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :return: None\n        \"\"\"\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return AcnDialogue.Role.NODE\n\n        BaseAcnDialogues.__init__(\n            self,\n            self_address=self_address,\n            role_from_first_message=role_from_first_message,\n            dialogue_class=AcnDialogue,\n        )\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_protocols/test_contract_api.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests of the contract_api protocol package.\"\"\"\n\nimport logging\nimport sys\nfrom typing import Type\nfrom unittest import mock\n\nimport pytest\n\nfrom aea.common import Address\nfrom aea.exceptions import AEAEnforceError\nfrom aea.mail.base import Envelope\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\nfrom aea.protocols.dialogue.base import DialogueLabel\n\nimport packages\nfrom packages.fetchai.protocols.contract_api.dialogues import (\n    ContractApiDialogue,\n    ContractApiDialogues,\n)\nfrom packages.fetchai.protocols.contract_api.message import ContractApiMessage\nfrom packages.fetchai.protocols.contract_api.message import (\n    _default_logger as contract_api_message_logger,\n)\n\nfrom tests.conftest import ROOT_DIR\n\n\nlogger = logging.getLogger(__name__)\nsys.path.append(ROOT_DIR)\n\n\ndef test_get_deploy_transaction_serialization():\n    \"\"\"Test the serialization for 'get_deploy_transaction' speech-act works.\"\"\"\n    kwargs_arg = ContractApiMessage.Kwargs({\"key_1\": 1, \"key_2\": 2})\n    msg = ContractApiMessage(\n        message_id=1,\n        dialogue_reference=(str(0), \"\"),\n        target=0,\n        performative=ContractApiMessage.Performative.GET_DEPLOY_TRANSACTION,\n        ledger_id=\"some_ledger_id\",\n        contract_id=\"some_contract_id\",\n        callable=\"some_callable\",\n        kwargs=kwargs_arg,\n    )\n    msg.to = \"receiver\"\n    envelope = Envelope(\n        to=msg.to,\n        sender=\"sender\",\n        message=msg,\n    )\n    envelope_bytes = envelope.encode()\n\n    actual_envelope = Envelope.decode(envelope_bytes)\n    expected_envelope = envelope\n    assert expected_envelope.to == actual_envelope.to\n    assert expected_envelope.sender == actual_envelope.sender\n    assert (\n        expected_envelope.protocol_specification_id\n        == actual_envelope.protocol_specification_id\n    )\n    assert expected_envelope.message != actual_envelope.message\n\n    actual_msg = ContractApiMessage.serializer.decode(actual_envelope.message)\n    actual_msg.to = actual_envelope.to\n    actual_msg.sender = actual_envelope.sender\n    expected_msg = msg\n    assert expected_msg == actual_msg\n\n\ndef test_get_raw_transaction_serialization():\n    \"\"\"Test the serialization for 'get_raw_transaction' speech-act works.\"\"\"\n    kwargs_arg = ContractApiMessage.Kwargs({\"key_1\": 1, \"key_2\": 2})\n    msg = ContractApiMessage(\n        message_id=1,\n        dialogue_reference=(str(0), \"\"),\n        target=0,\n        performative=ContractApiMessage.Performative.GET_RAW_TRANSACTION,\n        ledger_id=\"some_ledger_id\",\n        contract_id=\"some_contract_id\",\n        contract_address=\"some_contract_address\",\n        callable=\"some_callable\",\n        kwargs=kwargs_arg,\n    )\n    msg.to = \"receiver\"\n    envelope = Envelope(\n        to=msg.to,\n        sender=\"sender\",\n        message=msg,\n    )\n    envelope_bytes = envelope.encode()\n\n    actual_envelope = Envelope.decode(envelope_bytes)\n    expected_envelope = envelope\n    assert expected_envelope.to == actual_envelope.to\n    assert expected_envelope.sender == actual_envelope.sender\n    assert (\n        expected_envelope.protocol_specification_id\n        == actual_envelope.protocol_specification_id\n    )\n    assert expected_envelope.message != actual_envelope.message\n\n    actual_msg = ContractApiMessage.serializer.decode(actual_envelope.message)\n    actual_msg.to = actual_envelope.to\n    actual_msg.sender = actual_envelope.sender\n    expected_msg = msg\n    assert expected_msg == actual_msg\n\n\ndef test_get_raw_message_serialization():\n    \"\"\"Test the serialization for 'get_raw_message' speech-act works.\"\"\"\n    kwargs_arg = ContractApiMessage.Kwargs({\"key_1\": 1, \"key_2\": 2})\n    msg = ContractApiMessage(\n        message_id=1,\n        dialogue_reference=(str(0), \"\"),\n        target=0,\n        performative=ContractApiMessage.Performative.GET_RAW_MESSAGE,\n        ledger_id=\"some_ledger_id\",\n        contract_id=\"some_contract_id\",\n        contract_address=\"some_contract_address\",\n        callable=\"some_callable\",\n        kwargs=kwargs_arg,\n    )\n    msg.to = \"receiver\"\n    envelope = Envelope(\n        to=msg.to,\n        sender=\"sender\",\n        message=msg,\n    )\n    envelope_bytes = envelope.encode()\n\n    actual_envelope = Envelope.decode(envelope_bytes)\n    expected_envelope = envelope\n    assert expected_envelope.to == actual_envelope.to\n    assert expected_envelope.sender == actual_envelope.sender\n    assert (\n        expected_envelope.protocol_specification_id\n        == actual_envelope.protocol_specification_id\n    )\n    assert expected_envelope.message != actual_envelope.message\n\n    actual_msg = ContractApiMessage.serializer.decode(actual_envelope.message)\n    actual_msg.to = actual_envelope.to\n    actual_msg.sender = actual_envelope.sender\n    expected_msg = msg\n    assert expected_msg == actual_msg\n\n\ndef test_get_state_serialization():\n    \"\"\"Test the serialization for 'get_state' speech-act works.\"\"\"\n    kwargs_arg = ContractApiMessage.Kwargs({\"key_1\": 1, \"key_2\": 2})\n    msg = ContractApiMessage(\n        message_id=1,\n        dialogue_reference=(str(0), \"\"),\n        target=0,\n        performative=ContractApiMessage.Performative.GET_STATE,\n        ledger_id=\"some_ledger_id\",\n        contract_id=\"some_contract_id\",\n        contract_address=\"some_contract_address\",\n        callable=\"some_callable\",\n        kwargs=kwargs_arg,\n    )\n    msg.to = \"receiver\"\n    envelope = Envelope(\n        to=msg.to,\n        sender=\"sender\",\n        message=msg,\n    )\n    envelope_bytes = envelope.encode()\n\n    actual_envelope = Envelope.decode(envelope_bytes)\n    expected_envelope = envelope\n    assert expected_envelope.to == actual_envelope.to\n    assert expected_envelope.sender == actual_envelope.sender\n    assert (\n        expected_envelope.protocol_specification_id\n        == actual_envelope.protocol_specification_id\n    )\n    assert expected_envelope.message != actual_envelope.message\n\n    actual_msg = ContractApiMessage.serializer.decode(actual_envelope.message)\n    actual_msg.to = actual_envelope.to\n    actual_msg.sender = actual_envelope.sender\n    expected_msg = msg\n    assert expected_msg == actual_msg\n\n\ndef test_state_serialization():\n    \"\"\"Test the serialization for 'state' speech-act works.\"\"\"\n    state_arg = ContractApiMessage.State(\"some_ledger_id\", {\"key\": \"some_body\"})\n    msg = ContractApiMessage(\n        message_id=1,\n        dialogue_reference=(str(0), \"\"),\n        target=0,\n        performative=ContractApiMessage.Performative.STATE,\n        state=state_arg,\n    )\n    msg.to = \"receiver\"\n    envelope = Envelope(\n        to=msg.to,\n        sender=\"sender\",\n        message=msg,\n    )\n    envelope_bytes = envelope.encode()\n\n    actual_envelope = Envelope.decode(envelope_bytes)\n    expected_envelope = envelope\n    assert expected_envelope.to == actual_envelope.to\n    assert expected_envelope.sender == actual_envelope.sender\n    assert (\n        expected_envelope.protocol_specification_id\n        == actual_envelope.protocol_specification_id\n    )\n    assert expected_envelope.message != actual_envelope.message\n\n    actual_msg = ContractApiMessage.serializer.decode(actual_envelope.message)\n    actual_msg.to = actual_envelope.to\n    actual_msg.sender = actual_envelope.sender\n    expected_msg = msg\n    assert expected_msg == actual_msg\n\n\ndef test_raw_transaction_serialization():\n    \"\"\"Test the serialization for 'raw_transaction' speech-act works.\"\"\"\n    raw_transaction_arg = ContractApiMessage.RawTransaction(\n        \"some_ledger_id\", {\"body\": \"some_body\"}\n    )\n    msg = ContractApiMessage(\n        message_id=2,\n        target=1,\n        performative=ContractApiMessage.Performative.RAW_TRANSACTION,\n        raw_transaction=raw_transaction_arg,\n    )\n    msg.to = \"receiver\"\n    envelope = Envelope(\n        to=msg.to,\n        sender=\"sender\",\n        message=msg,\n    )\n    envelope_bytes = envelope.encode()\n\n    actual_envelope = Envelope.decode(envelope_bytes)\n    expected_envelope = envelope\n    assert expected_envelope.to == actual_envelope.to\n    assert expected_envelope.sender == actual_envelope.sender\n    assert (\n        expected_envelope.protocol_specification_id\n        == actual_envelope.protocol_specification_id\n    )\n    assert expected_envelope.message != actual_envelope.message\n\n    actual_msg = ContractApiMessage.serializer.decode(actual_envelope.message)\n    actual_msg.to = actual_envelope.to\n    actual_msg.sender = actual_envelope.sender\n    expected_msg = msg\n    assert expected_msg == actual_msg\n\n\ndef test_raw_message_serialization():\n    \"\"\"Test the serialization for 'raw_message' speech-act works.\"\"\"\n    raw_message_arg = ContractApiMessage.RawMessage(\"some_ledger_id\", b\"some_body\")\n    msg = ContractApiMessage(\n        performative=ContractApiMessage.Performative.RAW_MESSAGE,\n        raw_message=raw_message_arg,\n    )\n    msg.to = \"receiver\"\n    envelope = Envelope(\n        to=msg.to,\n        sender=\"sender\",\n        message=msg,\n    )\n    envelope_bytes = envelope.encode()\n\n    actual_envelope = Envelope.decode(envelope_bytes)\n    expected_envelope = envelope\n    assert expected_envelope.to == actual_envelope.to\n    assert expected_envelope.sender == actual_envelope.sender\n    assert (\n        expected_envelope.protocol_specification_id\n        == actual_envelope.protocol_specification_id\n    )\n    assert expected_envelope.message != actual_envelope.message\n\n    actual_msg = ContractApiMessage.serializer.decode(actual_envelope.message)\n    actual_msg.to = actual_envelope.to\n    actual_msg.sender = actual_envelope.sender\n    expected_msg = msg\n    assert expected_msg == actual_msg\n\n\ndef test_error_serialization():\n    \"\"\"Test the serialization for 'error' speech-act works.\"\"\"\n    msg = ContractApiMessage(\n        performative=ContractApiMessage.Performative.ERROR,\n        code=7,\n        message=\"some_error_message\",\n        data=b\"some_error_data\",\n    )\n    msg.to = \"receiver\"\n    envelope = Envelope(\n        to=msg.to,\n        sender=\"sender\",\n        message=msg,\n    )\n    envelope_bytes = envelope.encode()\n\n    actual_envelope = Envelope.decode(envelope_bytes)\n    expected_envelope = envelope\n    assert expected_envelope.to == actual_envelope.to\n    assert expected_envelope.sender == actual_envelope.sender\n    assert (\n        expected_envelope.protocol_specification_id\n        == actual_envelope.protocol_specification_id\n    )\n    assert expected_envelope.message != actual_envelope.message\n\n    actual_msg = ContractApiMessage.serializer.decode(actual_envelope.message)\n    actual_msg.to = actual_envelope.to\n    actual_msg.sender = actual_envelope.sender\n    expected_msg = msg\n    assert expected_msg == actual_msg\n\n\ndef test_performative_string_value():\n    \"\"\"Test the string value of the performatives.\"\"\"\n    assert (\n        str(ContractApiMessage.Performative.GET_DEPLOY_TRANSACTION)\n        == \"get_deploy_transaction\"\n    ), \"The str value must be get_deploy_transaction\"\n    assert (\n        str(ContractApiMessage.Performative.GET_RAW_TRANSACTION)\n        == \"get_raw_transaction\"\n    ), \"The str value must be get_raw_transaction\"\n    assert (\n        str(ContractApiMessage.Performative.GET_RAW_MESSAGE) == \"get_raw_message\"\n    ), \"The str value must be get_raw_message\"\n    assert (\n        str(ContractApiMessage.Performative.GET_STATE) == \"get_state\"\n    ), \"The str value must be get_state\"\n    assert (\n        str(ContractApiMessage.Performative.STATE) == \"state\"\n    ), \"The str value must be state\"\n    assert (\n        str(ContractApiMessage.Performative.RAW_TRANSACTION) == \"raw_transaction\"\n    ), \"The str value must be raw_transaction\"\n    assert (\n        str(ContractApiMessage.Performative.RAW_MESSAGE) == \"raw_message\"\n    ), \"The str value must be raw_message\"\n    assert (\n        str(ContractApiMessage.Performative.ERROR) == \"error\"\n    ), \"The str value must be error\"\n\n\ndef test_encoding_unknown_performative():\n    \"\"\"Test that we raise an exception when the performative is unknown during encoding.\"\"\"\n    msg = ContractApiMessage(\n        message_id=1,\n        dialogue_reference=(str(0), \"\"),\n        target=0,\n        performative=ContractApiMessage.Performative.RAW_MESSAGE,\n        raw_message=ContractApiMessage.RawMessage(\"some_ledger_id\", b\"some_body\"),\n    )\n\n    with pytest.raises(ValueError, match=\"Performative not valid:\"):\n        with mock.patch.object(\n            ContractApiMessage.Performative, \"__eq__\", return_value=False\n        ):\n            ContractApiMessage.serializer.encode(msg)\n\n\ndef test_decoding_unknown_performative():\n    \"\"\"Test that we raise an exception when the performative is unknown during decoding.\"\"\"\n    msg = ContractApiMessage(\n        message_id=1,\n        dialogue_reference=(str(0), \"\"),\n        target=0,\n        performative=ContractApiMessage.Performative.RAW_MESSAGE,\n        raw_message=ContractApiMessage.RawMessage(\"some_ledger_id\", b\"some_body\"),\n    )\n\n    encoded_msg = ContractApiMessage.serializer.encode(msg)\n    with pytest.raises(ValueError, match=\"Performative not valid:\"):\n        with mock.patch.object(\n            ContractApiMessage.Performative, \"__eq__\", return_value=False\n        ):\n            ContractApiMessage.serializer.decode(encoded_msg)\n\n\n@mock.patch.object(\n    packages.fetchai.protocols.contract_api.message,\n    \"enforce\",\n    side_effect=AEAEnforceError(\"some error\"),\n)\ndef test_incorrect_message(mocked_enforce):\n    \"\"\"Test that we raise an exception when the message is incorrect.\"\"\"\n    with mock.patch.object(contract_api_message_logger, \"error\") as mock_logger:\n        ContractApiMessage(\n            message_id=1,\n            dialogue_reference=(str(0), \"\"),\n            target=0,\n            performative=ContractApiMessage.Performative.RAW_MESSAGE,\n            raw_message=ContractApiMessage.RawMessage(\"some_ledger_id\", b\"some_body\"),\n        )\n\n        mock_logger.assert_any_call(\"some error\")\n\n\ndef test_kwargs():\n    \"\"\"Test the kwargs custom type.\"\"\"\n    body = {\"key_1\": 1, \"key_2\": 2}\n    kwargs = ContractApiMessage.Kwargs(body)\n    assert str(kwargs) == \"Kwargs: body={}\".format(body)\n\n\nclass TestDialogues:\n    \"\"\"Tests contract_api dialogues.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set up the test.\"\"\"\n        cls.agent_addr = \"agent address\"\n        cls.ledger_addr = \"ledger address\"\n        cls.agent_dialogues = AgentDialogues(cls.agent_addr)\n        cls.ledger_dialogues = LedgerDialogues(cls.ledger_addr)\n\n    def test_create_self_initiated(self):\n        \"\"\"Test the self initialisation of a dialogue.\"\"\"\n        result = self.agent_dialogues._create_self_initiated(\n            dialogue_opponent_addr=self.ledger_addr,\n            dialogue_reference=(str(0), \"\"),\n            role=ContractApiDialogue.Role.AGENT,\n        )\n        assert isinstance(result, ContractApiDialogue)\n        assert result.role == ContractApiDialogue.Role.AGENT, \"The role must be Agent.\"\n\n    def test_create_opponent_initiated(self):\n        \"\"\"Test the opponent initialisation of a dialogue.\"\"\"\n        result = self.agent_dialogues._create_opponent_initiated(\n            dialogue_opponent_addr=self.ledger_addr,\n            dialogue_reference=(str(0), \"\"),\n            role=ContractApiDialogue.Role.AGENT,\n        )\n        assert isinstance(result, ContractApiDialogue)\n        assert result.role == ContractApiDialogue.Role.AGENT, \"The role must be agent.\"\n\n\nclass AgentDialogue(ContractApiDialogue):\n    \"\"\"The dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    def __init__(\n        self,\n        dialogue_label: DialogueLabel,\n        self_address: Address,\n        role: BaseDialogue.Role,\n        message_class: Type[ContractApiMessage],\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n\n        :return: None\n        \"\"\"\n        ContractApiDialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            self_address=self_address,\n            role=role,\n            message_class=message_class,\n        )\n\n\nclass AgentDialogues(ContractApiDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, self_address: Address) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :return: None\n        \"\"\"\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return ContractApiDialogue.Role.AGENT\n\n        ContractApiDialogues.__init__(\n            self,\n            self_address=self_address,\n            role_from_first_message=role_from_first_message,\n            dialogue_class=AgentDialogue,\n        )\n\n\nclass LedgerDialogue(ContractApiDialogue):\n    \"\"\"The dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    def __init__(\n        self,\n        dialogue_label: DialogueLabel,\n        self_address: Address,\n        role: BaseDialogue.Role,\n        message_class: Type[ContractApiMessage],\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n\n        :return: None\n        \"\"\"\n        ContractApiDialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            self_address=self_address,\n            role=role,\n            message_class=message_class,\n        )\n\n\nclass LedgerDialogues(ContractApiDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, self_address: Address) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :return: None\n        \"\"\"\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return ContractApiDialogue.Role.LEDGER\n\n        ContractApiDialogues.__init__(\n            self,\n            self_address=self_address,\n            role_from_first_message=role_from_first_message,\n            dialogue_class=LedgerDialogue,\n        )\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_protocols/test_default.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests of the messages module.\"\"\"\n\nfrom typing import Type\nfrom unittest import mock\nfrom unittest.mock import patch\n\nimport pytest\n\nfrom aea.common import Address\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\nfrom aea.protocols.dialogue.base import DialogueLabel\n\nfrom packages.fetchai.protocols.default.dialogues import (\n    DefaultDialogue as BaseDefaultDialogue,\n)\nfrom packages.fetchai.protocols.default.dialogues import (\n    DefaultDialogues as BaseDefaultDialogues,\n)\nfrom packages.fetchai.protocols.default.message import DefaultMessage\n\n\ndef test_default_bytes_serialization():\n    \"\"\"Test that the serialization for the 'simple' protocol works for the BYTES message.\"\"\"\n    expected_msg = DefaultMessage(\n        dialogue_reference=(\"\", \"\"),\n        message_id=1,\n        target=0,\n        performative=DefaultMessage.Performative.BYTES,\n        content=b\"hello\",\n    )\n    msg_bytes = DefaultMessage.serializer.encode(expected_msg)\n    actual_msg = DefaultMessage.serializer.decode(msg_bytes)\n    assert expected_msg == actual_msg\n\n\ndef test_default_error_serialization():\n    \"\"\"Test that the serialization for the 'simple' protocol works for the ERROR message.\"\"\"\n    msg = DefaultMessage(\n        dialogue_reference=(\"\", \"\"),\n        message_id=1,\n        target=0,\n        performative=DefaultMessage.Performative.ERROR,\n        error_code=DefaultMessage.ErrorCode.UNSUPPORTED_PROTOCOL,\n        error_msg=\"An error\",\n        error_data={\"error\": b\"Some error data\"},\n    )\n    msg_bytes = DefaultMessage.serializer.encode(msg)\n    actual_msg = DefaultMessage.serializer.decode(msg_bytes)\n    expected_msg = msg\n    assert expected_msg == actual_msg\n\n\ndef test_default_end_serialization():\n    \"\"\"Test that the serialization for the 'simple' protocol works for the END message.\"\"\"\n    msg = DefaultMessage(\n        dialogue_reference=(\"\", \"\"),\n        message_id=1,\n        target=0,\n        performative=DefaultMessage.Performative.END,\n    )\n    msg_bytes = DefaultMessage.serializer.encode(msg)\n    actual_msg = DefaultMessage.serializer.decode(msg_bytes)\n    expected_msg = msg\n    assert expected_msg == actual_msg\n\n\ndef test_default_message_str_values():\n    \"\"\"Tests the returned string values of default Message.\"\"\"\n    assert (\n        str(DefaultMessage.Performative.BYTES) == \"bytes\"\n    ), \"DefaultMessage.Performative.BYTES must be bytes\"\n    assert (\n        str(DefaultMessage.Performative.ERROR) == \"error\"\n    ), \"DefaultMessage.Performative.ERROR must be error\"\n\n\ndef test_encoding_unknown_performative():\n    \"\"\"Test that we raise an exception when the performative is unknown during encoding.\"\"\"\n    msg = DefaultMessage(\n        performative=DefaultMessage.Performative.BYTES, content=b\"hello\"\n    )\n\n    with pytest.raises(ValueError, match=\"Performative not valid:\"):\n        with mock.patch.object(\n            DefaultMessage.Performative, \"__eq__\", return_value=False\n        ):\n            DefaultMessage.serializer.encode(msg)\n\n\ndef test_check_consistency_raises_exception_when_type_not_recognized():\n    \"\"\"Test that we raise exception when the type of the message is not recognized.\"\"\"\n    message = DefaultMessage(\n        dialogue_reference=(\"\", \"\"),\n        message_id=1,\n        target=0,\n        performative=DefaultMessage.Performative.BYTES,\n        content=b\"hello\",\n    )\n    # mock the __eq__ method such that any kind of matching is going to fail.\n    with mock.patch.object(DefaultMessage.Performative, \"__eq__\", return_value=False):\n        assert not message._is_consistent()\n\n\ndef test_default_valid_performatives():\n    \"\"\"Test 'valid_performatives' getter.\"\"\"\n    msg = DefaultMessage(DefaultMessage.Performative.BYTES, content=b\"\")\n    assert msg.valid_performatives == set(\n        map(lambda x: x.value, iter(DefaultMessage.Performative))\n    )\n\n\ndef test_serializer_performative_not_found():\n    \"\"\"Test the serializer when the performative is not found.\"\"\"\n    message = DefaultMessage(\n        message_id=1,\n        target=0,\n        performative=DefaultMessage.Performative.BYTES,\n        content=b\"\",\n    )\n    message_bytes = message.serializer.encode(message)\n    with patch.object(DefaultMessage.Performative, \"__eq__\", return_value=False):\n        with pytest.raises(ValueError, match=\"Performative not valid: .*\"):\n            message.serializer.decode(message_bytes)\n\n\ndef test_dialogues():\n    \"\"\"Test intiaontiation of dialogues.\"\"\"\n    default_dialogues = DefaultDialogues(\"agent_addr\")\n    msg, dialogue = default_dialogues.create(\n        counterparty=\"abc\",\n        performative=DefaultMessage.Performative.BYTES,\n        content=b\"hello\",\n    )\n    assert dialogue is not None\n\n\nclass DefaultDialogue(BaseDefaultDialogue):\n    \"\"\"The dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    def __init__(\n        self,\n        dialogue_label: DialogueLabel,\n        self_address: Address,\n        role: BaseDialogue.Role,\n        message_class: Type[DefaultMessage],\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n\n        :return: None\n        \"\"\"\n        BaseDefaultDialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            self_address=self_address,\n            role=role,\n            message_class=message_class,\n        )\n\n\nclass DefaultDialogues(BaseDefaultDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, self_address: Address) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :return: None\n        \"\"\"\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return DefaultDialogue.Role.AGENT\n\n        BaseDefaultDialogues.__init__(\n            self,\n            self_address=self_address,\n            role_from_first_message=role_from_first_message,\n            dialogue_class=DefaultDialogue,\n        )\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_protocols/test_fipa.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests of the fipa protocol package.\"\"\"\n\nimport logging\nimport sys\nfrom typing import Any, Optional, Type\nfrom unittest import mock\n\nimport pytest\n\nfrom aea.common import Address\nfrom aea.exceptions import AEAEnforceError\nfrom aea.helpers.search.models import Constraint, ConstraintType, Description, Query\nfrom aea.mail.base import Envelope\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\nfrom aea.protocols.dialogue.base import DialogueLabel\n\nimport packages\nfrom packages.fetchai.protocols.fipa.dialogues import FipaDialogue, FipaDialogues\nfrom packages.fetchai.protocols.fipa.message import FipaMessage\nfrom packages.fetchai.protocols.fipa.message import (\n    _default_logger as fipa_message_logger,\n)\n\nfrom tests.conftest import ROOT_DIR\n\n\nlogger = logging.getLogger(__name__)\nsys.path.append(ROOT_DIR)\n\n\ndef test_cfp_serialization():\n    \"\"\"Test that the serialization for the 'fipa' protocol works.\"\"\"\n    msg = FipaMessage(\n        message_id=1,\n        dialogue_reference=(str(0), \"\"),\n        target=0,\n        performative=FipaMessage.Performative.CFP,\n        query=Query([Constraint(\"something\", ConstraintType(\">\", 1))]),\n    )\n    msg.to = \"receiver\"\n    envelope = Envelope(\n        to=msg.to,\n        sender=\"sender\",\n        message=msg,\n    )\n    envelope_bytes = envelope.encode()\n\n    actual_envelope = Envelope.decode(envelope_bytes)\n    expected_envelope = envelope\n    assert expected_envelope.to == actual_envelope.to\n    assert expected_envelope.sender == actual_envelope.sender\n    assert (\n        expected_envelope.protocol_specification_id\n        == actual_envelope.protocol_specification_id\n    )\n    assert expected_envelope.message != actual_envelope.message\n\n    actual_msg = FipaMessage.serializer.decode(actual_envelope.message)\n    actual_msg.to = actual_envelope.to\n    actual_msg.sender = actual_envelope.sender\n    expected_msg = msg\n    assert expected_msg == actual_msg\n\n\ndef test_propose_serialization():\n    \"\"\"Test that the serialization for the 'fipa' protocol works.\"\"\"\n    msg = FipaMessage(\n        message_id=1,\n        dialogue_reference=(str(0), \"\"),\n        target=0,\n        performative=FipaMessage.Performative.PROPOSE,\n        proposal=Description({\"foo1\": 1, \"bar1\": 2}),\n    )\n    msg.to = \"receiver\"\n    envelope = Envelope(\n        to=msg.to,\n        sender=\"sender\",\n        message=msg,\n    )\n    envelope_bytes = envelope.encode()\n\n    actual_envelope = Envelope.decode(envelope_bytes)\n    expected_envelope = envelope\n    assert expected_envelope.to == actual_envelope.to\n    assert expected_envelope.sender == actual_envelope.sender\n    assert (\n        expected_envelope.protocol_specification_id\n        == actual_envelope.protocol_specification_id\n    )\n    assert expected_envelope.message != actual_envelope.message\n\n    actual_msg = FipaMessage.serializer.decode(actual_envelope.message)\n    actual_msg.to = actual_envelope.to\n    actual_msg.sender = actual_envelope.sender\n    expected_msg = msg\n    assert expected_msg == actual_msg\n\n\ndef test_accept_serialization():\n    \"\"\"Test that the serialization for the 'fipa' protocol works.\"\"\"\n    msg = FipaMessage(\n        message_id=1,\n        dialogue_reference=(str(0), \"\"),\n        target=0,\n        performative=FipaMessage.Performative.ACCEPT,\n    )\n    msg.to = \"receiver\"\n    envelope = Envelope(\n        to=msg.to,\n        sender=\"sender\",\n        message=msg,\n    )\n    envelope_bytes = envelope.encode()\n\n    actual_envelope = Envelope.decode(envelope_bytes)\n    expected_envelope = envelope\n    assert expected_envelope.to == actual_envelope.to\n    assert expected_envelope.sender == actual_envelope.sender\n    assert (\n        expected_envelope.protocol_specification_id\n        == actual_envelope.protocol_specification_id\n    )\n    assert expected_envelope.message != actual_envelope.message\n\n    actual_msg = FipaMessage.serializer.decode(actual_envelope.message)\n    actual_msg.to = actual_envelope.to\n    actual_msg.sender = actual_envelope.sender\n    expected_msg = msg\n    assert expected_msg == actual_msg\n\n\ndef test_decline_serialization():\n    \"\"\"Test that the serialization for the 'fipa' protocol works.\"\"\"\n    msg = FipaMessage(\n        message_id=1,\n        dialogue_reference=(str(0), \"\"),\n        target=0,\n        performative=FipaMessage.Performative.DECLINE,\n    )\n    msg.to = \"receiver\"\n    envelope = Envelope(\n        to=msg.to,\n        sender=\"sender\",\n        message=msg,\n    )\n    envelope_bytes = envelope.encode()\n\n    actual_envelope = Envelope.decode(envelope_bytes)\n    expected_envelope = envelope\n    assert expected_envelope.to == actual_envelope.to\n    assert expected_envelope.sender == actual_envelope.sender\n    assert (\n        expected_envelope.protocol_specification_id\n        == actual_envelope.protocol_specification_id\n    )\n    assert expected_envelope.message != actual_envelope.message\n\n    actual_msg = FipaMessage.serializer.decode(actual_envelope.message)\n    actual_msg.to = actual_envelope.to\n    actual_msg.sender = actual_envelope.sender\n    expected_msg = msg\n    assert expected_msg == actual_msg\n\n\ndef test_match_accept_serialization():\n    \"\"\"Test the serialization - deserialization of the match_accept performative.\"\"\"\n    msg = FipaMessage(\n        message_id=1,\n        dialogue_reference=(str(0), \"\"),\n        target=0,\n        performative=FipaMessage.Performative.MATCH_ACCEPT,\n    )\n    msg.to = \"receiver\"\n    envelope = Envelope(\n        to=msg.to,\n        sender=\"sender\",\n        message=msg,\n    )\n    envelope_bytes = envelope.encode()\n\n    actual_envelope = Envelope.decode(envelope_bytes)\n    expected_envelope = envelope\n    assert expected_envelope.to == actual_envelope.to\n    assert expected_envelope.sender == actual_envelope.sender\n    assert (\n        expected_envelope.protocol_specification_id\n        == actual_envelope.protocol_specification_id\n    )\n    assert expected_envelope.message != actual_envelope.message\n\n    actual_msg = FipaMessage.serializer.decode(actual_envelope.message)\n    actual_msg.to = actual_envelope.to\n    actual_msg.sender = actual_envelope.sender\n    expected_msg = msg\n    assert expected_msg == actual_msg\n\n\ndef test_accept_with_inform_serialization():\n    \"\"\"Test the serialization - deserialization of the accept_with_address performative.\"\"\"\n    msg = FipaMessage(\n        message_id=1,\n        dialogue_reference=(str(0), \"\"),\n        target=0,\n        performative=FipaMessage.Performative.ACCEPT_W_INFORM,\n        info={\"address\": \"dummy_address\"},\n    )\n    msg.to = \"receiver\"\n    envelope = Envelope(\n        to=msg.to,\n        sender=\"sender\",\n        message=msg,\n    )\n    envelope_bytes = envelope.encode()\n\n    actual_envelope = Envelope.decode(envelope_bytes)\n    expected_envelope = envelope\n    assert expected_envelope.to == actual_envelope.to\n    assert expected_envelope.sender == actual_envelope.sender\n    assert (\n        expected_envelope.protocol_specification_id\n        == actual_envelope.protocol_specification_id\n    )\n    assert expected_envelope.message != actual_envelope.message\n\n    actual_msg = FipaMessage.serializer.decode(actual_envelope.message)\n    actual_msg.to = actual_envelope.to\n    actual_msg.sender = actual_envelope.sender\n    expected_msg = msg\n    assert expected_msg == actual_msg\n\n\ndef test_match_accept_with_inform_serialization():\n    \"\"\"Test the serialization - deserialization of the match_accept_with_address performative.\"\"\"\n    msg = FipaMessage(\n        message_id=1,\n        dialogue_reference=(str(0), \"\"),\n        target=0,\n        performative=FipaMessage.Performative.MATCH_ACCEPT_W_INFORM,\n        info={\"address\": \"dummy_address\", \"signature\": \"my_signature\"},\n    )\n    msg.to = \"receiver\"\n    envelope = Envelope(\n        to=msg.to,\n        sender=\"sender\",\n        message=msg,\n    )\n    envelope_bytes = envelope.encode()\n\n    actual_envelope = Envelope.decode(envelope_bytes)\n    expected_envelope = envelope\n    assert expected_envelope.to == actual_envelope.to\n    assert expected_envelope.sender == actual_envelope.sender\n    assert (\n        expected_envelope.protocol_specification_id\n        == actual_envelope.protocol_specification_id\n    )\n    assert expected_envelope.message != actual_envelope.message\n\n    actual_msg = FipaMessage.serializer.decode(actual_envelope.message)\n    actual_msg.to = actual_envelope.to\n    actual_msg.sender = actual_envelope.sender\n    expected_msg = msg\n    assert expected_msg == actual_msg\n\n\ndef test_inform_serialization():\n    \"\"\"Test the serialization-deserialization of the inform performative.\"\"\"\n    msg = FipaMessage(\n        message_id=1,\n        dialogue_reference=(str(0), \"\"),\n        target=0,\n        performative=FipaMessage.Performative.INFORM,\n        info={\"foo\": \"bar\"},\n    )\n    msg.to = \"receiver\"\n    envelope = Envelope(\n        to=msg.to,\n        sender=\"sender\",\n        message=msg,\n    )\n    envelope_bytes = envelope.encode()\n\n    actual_envelope = Envelope.decode(envelope_bytes)\n    expected_envelope = envelope\n    assert expected_envelope.to == actual_envelope.to\n    assert expected_envelope.sender == actual_envelope.sender\n    assert (\n        expected_envelope.protocol_specification_id\n        == actual_envelope.protocol_specification_id\n    )\n    assert expected_envelope.message != actual_envelope.message\n\n    actual_msg = FipaMessage.serializer.decode(actual_envelope.message)\n    actual_msg.to = actual_envelope.to\n    actual_msg.sender = actual_envelope.sender\n    expected_msg = msg\n    assert expected_msg == actual_msg\n\n\ndef test_end_serialization():\n    \"\"\"Test the serialization-deserialization of the end performative.\"\"\"\n    msg = FipaMessage(\n        message_id=1,\n        dialogue_reference=(str(0), \"\"),\n        target=0,\n        performative=FipaMessage.Performative.END,\n    )\n    msg.to = \"receiver\"\n    envelope = Envelope(\n        to=msg.to,\n        sender=\"sender\",\n        message=msg,\n    )\n    envelope_bytes = envelope.encode()\n\n    actual_envelope = Envelope.decode(envelope_bytes)\n    expected_envelope = envelope\n    assert expected_envelope.to == actual_envelope.to\n    assert expected_envelope.sender == actual_envelope.sender\n    assert (\n        expected_envelope.protocol_specification_id\n        == actual_envelope.protocol_specification_id\n    )\n    assert expected_envelope.message != actual_envelope.message\n\n    actual_msg = FipaMessage.serializer.decode(actual_envelope.message)\n    actual_msg.to = actual_envelope.to\n    actual_msg.sender = actual_envelope.sender\n    expected_msg = msg\n    assert expected_msg == actual_msg\n\n\ndef test_performative_string_value():\n    \"\"\"Test the string value of the performatives.\"\"\"\n    assert str(FipaMessage.Performative.CFP) == \"cfp\", \"The str value must be cfp\"\n    assert (\n        str(FipaMessage.Performative.PROPOSE) == \"propose\"\n    ), \"The str value must be propose\"\n    assert (\n        str(FipaMessage.Performative.DECLINE) == \"decline\"\n    ), \"The str value must be decline\"\n    assert (\n        str(FipaMessage.Performative.ACCEPT) == \"accept\"\n    ), \"The str value must be accept\"\n    assert (\n        str(FipaMessage.Performative.MATCH_ACCEPT) == \"match_accept\"\n    ), \"The str value must be match_accept\"\n    assert (\n        str(FipaMessage.Performative.ACCEPT_W_INFORM) == \"accept_w_inform\"\n    ), \"The str value must be accept_w_inform\"\n    assert (\n        str(FipaMessage.Performative.MATCH_ACCEPT_W_INFORM) == \"match_accept_w_inform\"\n    ), \"The str value must be match_accept_w_inform\"\n    assert (\n        str(FipaMessage.Performative.INFORM) == \"inform\"\n    ), \"The str value must be inform\"\n\n\ndef test_encoding_unknown_performative():\n    \"\"\"Test that we raise an exception when the performative is unknown during encoding.\"\"\"\n    msg = FipaMessage(\n        performative=FipaMessage.Performative.ACCEPT,\n    )\n\n    with pytest.raises(ValueError, match=\"Performative not valid:\"):\n        with mock.patch.object(FipaMessage.Performative, \"__eq__\", return_value=False):\n            FipaMessage.serializer.encode(msg)\n\n\ndef test_decoding_unknown_performative():\n    \"\"\"Test that we raise an exception when the performative is unknown during decoding.\"\"\"\n    msg = FipaMessage(\n        performative=FipaMessage.Performative.ACCEPT,\n    )\n\n    encoded_msg = FipaMessage.serializer.encode(msg)\n    with pytest.raises(ValueError, match=\"Performative not valid:\"):\n        with mock.patch.object(FipaMessage.Performative, \"__eq__\", return_value=False):\n            FipaMessage.serializer.decode(encoded_msg)\n\n\n@mock.patch.object(\n    packages.fetchai.protocols.fipa.message,\n    \"enforce\",\n    side_effect=AEAEnforceError(\"some error\"),\n)\ndef test_incorrect_message(mocked_enforce):\n    \"\"\"Test that we raise an exception when the fipa message is incorrect.\"\"\"\n    with mock.patch.object(fipa_message_logger, \"error\") as mock_logger:\n        FipaMessage(\n            message_id=1,\n            dialogue_reference=(str(0), \"\"),\n            target=0,\n            performative=FipaMessage.Performative.ACCEPT,\n        )\n\n        mock_logger.assert_any_call(\"some error\")\n\n\nclass TestDialogues:\n    \"\"\"Tests fipa dialogues.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set up the test.\"\"\"\n        cls.buyer_addr = \"buyer address\"\n        cls.seller_addr = \"seller address\"\n        cls.buyer_dialogues = BuyerDialogues(cls.buyer_addr)\n        cls.seller_dialogues = SellerDialogues(cls.seller_addr)\n\n    def test_create_self_initiated(self):\n        \"\"\"Test the self initialisation of a dialogue.\"\"\"\n        result = self.buyer_dialogues._create_self_initiated(\n            dialogue_opponent_addr=self.seller_addr,\n            dialogue_reference=(str(0), \"\"),\n            role=FipaDialogue.Role.SELLER,\n        )\n        assert isinstance(result, FipaDialogue)\n        assert result.role == FipaDialogue.Role.SELLER, \"The role must be seller.\"\n\n    def test_create_opponent_initiated(self):\n        \"\"\"Test the opponent initialisation of a dialogue.\"\"\"\n        result = self.buyer_dialogues._create_opponent_initiated(\n            dialogue_opponent_addr=self.seller_addr,\n            dialogue_reference=(str(0), \"\"),\n            role=FipaDialogue.Role.BUYER,\n        )\n        assert isinstance(result, FipaDialogue)\n        assert result.role == FipaDialogue.Role.BUYER, \"The role must be buyer.\"\n\n    def test_dialogue_endstates(self):\n        \"\"\"Test the end states of a dialogue.\"\"\"\n        assert self.buyer_dialogues.dialogue_stats is not None\n        self.buyer_dialogues.dialogue_stats.add_dialogue_endstate(\n            FipaDialogue.EndState.SUCCESSFUL, is_self_initiated=True\n        )\n        self.buyer_dialogues.dialogue_stats.add_dialogue_endstate(\n            FipaDialogue.EndState.DECLINED_CFP, is_self_initiated=False\n        )\n        assert self.buyer_dialogues.dialogue_stats.self_initiated == {\n            FipaDialogue.EndState.SUCCESSFUL: 1,\n            FipaDialogue.EndState.DECLINED_PROPOSE: 0,\n            FipaDialogue.EndState.DECLINED_ACCEPT: 0,\n            FipaDialogue.EndState.DECLINED_CFP: 0,\n        }\n        assert self.buyer_dialogues.dialogue_stats.other_initiated == {\n            FipaDialogue.EndState.SUCCESSFUL: 0,\n            FipaDialogue.EndState.DECLINED_PROPOSE: 0,\n            FipaDialogue.EndState.DECLINED_ACCEPT: 0,\n            FipaDialogue.EndState.DECLINED_CFP: 1,\n        }\n\n    def test_dialogues_self_initiated(self):\n        \"\"\"Test an end to end scenario of client-seller dialogue.\"\"\"\n\n        # Create a message destined for the seller.\n        cfp_msg, buyer_dialogue = self.buyer_dialogues.create(\n            counterparty=self.seller_addr,\n            performative=FipaMessage.Performative.CFP,\n            query=Query([Constraint(\"something\", ConstraintType(\">\", 1))]),\n        )\n\n        # Checking that I can retrieve the dialogue.\n        retrieved_dialogue = self.buyer_dialogues.get_dialogue(cfp_msg)\n        assert (\n            retrieved_dialogue == buyer_dialogue\n        ), \"Should have found correct dialogue\"\n\n        assert (\n            cfp_msg.dialogue_reference[0] != \"\" and cfp_msg.dialogue_reference[1] == \"\"\n        ), \"The dialogue_reference is not set correctly.\"\n\n        # MESSAGE BEING SENT BETWEEN AGENTS\n\n        # Creates a new dialogue for the seller side based on the income message.\n        seller_dialogue = self.seller_dialogues.update(cfp_msg)\n\n        # Check that both fields in the dialogue_reference are set.\n        last_msg = seller_dialogue.last_incoming_message\n        assert last_msg == cfp_msg, \"The messages must be equal\"\n\n        # Generate a proposal message to send to the buyer.\n        proposal = Description({\"foo1\": 1, \"bar1\": 2})\n        proposal_msg = seller_dialogue.reply(\n            target_message=cfp_msg,\n            performative=FipaMessage.Performative.PROPOSE,\n            proposal=proposal,\n        )\n\n        # MESSAGE BEING SENT BETWEEN AGENTS\n\n        # Client received the message and we extend the incoming messages list.\n        buyer_dialogue = self.buyer_dialogues.update(proposal_msg)\n\n        # Check that both fields in the dialogue_reference are set.\n        last_msg = buyer_dialogue.last_incoming_message\n        assert last_msg == proposal_msg, \"The two messages must be equal.\"\n\n        # Retrieve the dialogue based on the received message.\n        retrieved_dialogue = self.buyer_dialogues.get_dialogue(proposal_msg)\n        assert retrieved_dialogue == buyer_dialogue, \"Should have found dialogue\"\n\n        # Create an accept_w_inform message to send seller.\n        accept_msg = buyer_dialogue.reply(\n            target_message=proposal_msg,\n            performative=FipaMessage.Performative.ACCEPT_W_INFORM,\n            info={\"address\": \"dummy_address\"},\n        )\n        # MESSAGE BEING SENT BETWEEN AGENTS\n\n        # Adds the message to the seller incoming message list.\n        seller_dialogue = self.seller_dialogues.update(accept_msg)\n\n        retrieved_dialogue = self.seller_dialogues.get_dialogue(accept_msg)\n        assert seller_dialogue == retrieved_dialogue, \"Should have found dialogue\"\n\n    def test_update(self):\n        \"\"\"Test the `update` functionality.\"\"\"\n        cfp_msg, buyer_dialogue = self.buyer_dialogues.create(\n            counterparty=self.seller_addr,\n            performative=FipaMessage.Performative.CFP,\n            query=Query([Constraint(\"something\", ConstraintType(\">\", 1))]),\n        )\n\n        assert len(buyer_dialogue._outgoing_messages) == 1, \"No outgoing message.\"\n        assert len(buyer_dialogue._incoming_messages) == 0, \"Some incoming messages.\"\n        assert (\n            buyer_dialogue.last_outgoing_message == cfp_msg\n        ), \"Wrong outgoing message.\"\n        assert (\n            buyer_dialogue.dialogue_label.dialogue_reference[0] != \"\"\n        ), \"Dialogue reference incorrect.\"\n        assert (\n            buyer_dialogue.dialogue_label.dialogue_reference[1] == \"\"\n        ), \"Dialogue reference incorrect.\"\n        dialogue_reference_left_part = buyer_dialogue.dialogue_label.dialogue_reference[\n            0\n        ]\n\n        # message arrives at counterparty\n        seller_dialogue = self.seller_dialogues.update(cfp_msg)\n\n        assert len(seller_dialogue._outgoing_messages) == 0, \"Some outgoing message.\"\n        assert len(seller_dialogue._incoming_messages) == 1, \"No incoming messages.\"\n        assert (\n            seller_dialogue.last_incoming_message == cfp_msg\n        ), \"Wrong incoming message.\"\n        assert (\n            seller_dialogue.dialogue_label.dialogue_reference[0] != \"\"\n        ), \"Dialogue reference incorrect.\"\n        assert (\n            seller_dialogue.dialogue_label.dialogue_reference[1] != \"\"\n        ), \"Dialogue reference incorrect.\"\n\n        # seller creates response message\n        proposal_msg = seller_dialogue.reply(\n            target_message=cfp_msg,\n            performative=FipaMessage.Performative.PROPOSE,\n            proposal=Description({\"foo1\": 1, \"bar1\": 2}),\n        )\n\n        assert len(seller_dialogue._outgoing_messages) == 1, \"No outgoing messages.\"\n        assert len(seller_dialogue._incoming_messages) == 1, \"No incoming messages.\"\n        assert (\n            seller_dialogue.last_outgoing_message == proposal_msg\n        ), \"Wrong outgoing message.\"\n\n        # message arrives at counterparty\n        self.buyer_dialogues.update(proposal_msg)\n\n        assert len(buyer_dialogue._outgoing_messages) == 1, \"No outgoing messages.\"\n        assert len(buyer_dialogue._incoming_messages) == 1, \"No incoming messages.\"\n        assert (\n            buyer_dialogue.last_outgoing_message == cfp_msg\n        ), \"Wrong outgoing message.\"\n        assert (\n            buyer_dialogue.last_incoming_message == proposal_msg\n        ), \"Wrong incoming message.\"\n        assert (\n            buyer_dialogue.dialogue_label.dialogue_reference[0] != \"\"\n        ), \"Dialogue reference incorrect.\"\n        assert (\n            buyer_dialogue.dialogue_label.dialogue_reference[1] != \"\"\n        ), \"Dialogue reference incorrect.\"\n        assert (\n            dialogue_reference_left_part\n            == buyer_dialogue.dialogue_label.dialogue_reference[0]\n        ), \"Dialogue refernce changed unexpectedly.\"\n\n    def test_counter_proposing(self):\n        \"\"\"Test that fipa supports counter proposing.\"\"\"\n        cfp_msg, buyer_dialogue = self.buyer_dialogues.create(\n            counterparty=self.seller_addr,\n            performative=FipaMessage.Performative.CFP,\n            query=Query([Constraint(\"something\", ConstraintType(\">\", 1))]),\n        )\n\n        assert len(buyer_dialogue._outgoing_messages) == 1, \"No outgoing message.\"\n        assert len(buyer_dialogue._incoming_messages) == 0, \"Some incoming messages.\"\n        assert (\n            buyer_dialogue.last_outgoing_message == cfp_msg\n        ), \"wrong outgoing message in buyer dialogue after sending cfp.\"\n        assert (\n            buyer_dialogue.dialogue_label.dialogue_reference[0] != \"\"\n        ), \"Dialogue reference incorrect.\"\n        assert (\n            buyer_dialogue.dialogue_label.dialogue_reference[1] == \"\"\n        ), \"Dialogue reference incorrect.\"\n        dialogue_reference_left_part = buyer_dialogue.dialogue_label.dialogue_reference[\n            0\n        ]\n\n        # cfp arrives at seller\n\n        seller_dialogue = self.seller_dialogues.update(cfp_msg)\n\n        assert len(seller_dialogue._outgoing_messages) == 0, \"Some outgoing message.\"\n        assert len(seller_dialogue._incoming_messages) == 1, \"No incoming messages.\"\n        assert (\n            seller_dialogue.last_incoming_message == cfp_msg\n        ), \"wrong incoming message in seller dialogue after receiving cfp.\"\n        assert (\n            seller_dialogue.dialogue_label.dialogue_reference[0] != \"\"\n        ), \"Dialogue reference incorrect.\"\n        assert (\n            seller_dialogue.dialogue_label.dialogue_reference[1] != \"\"\n        ), \"Dialogue reference incorrect.\"\n\n        # seller creates proposal\n        proposal_msg = seller_dialogue.reply(\n            target_message=cfp_msg,\n            performative=FipaMessage.Performative.PROPOSE,\n            proposal=Description({\"foo1\": 1, \"bar1\": 2}),\n        )\n\n        assert len(seller_dialogue._outgoing_messages) == 1, \"No outgoing messages.\"\n        assert len(seller_dialogue._incoming_messages) == 1, \"No incoming messages.\"\n        assert (\n            seller_dialogue.last_outgoing_message == proposal_msg\n        ), \"wrong outgoing message in seller dialogue after sending proposal.\"\n\n        # proposal arrives at buyer\n\n        buyer_dialogue = self.buyer_dialogues.update(proposal_msg)\n\n        assert len(buyer_dialogue._outgoing_messages) == 1, \"No outgoing messages.\"\n        assert len(buyer_dialogue._incoming_messages) == 1, \"No incoming messages.\"\n        assert (\n            buyer_dialogue.last_incoming_message == proposal_msg\n        ), \"wrong incoming message in buyer dialogue after receiving proposal.\"\n        assert (\n            buyer_dialogue.last_incoming_message == proposal_msg\n        ), \"Wrong incoming message.\"\n        assert (\n            buyer_dialogue.dialogue_label.dialogue_reference[0] != \"\"\n        ), \"Dialogue reference incorrect.\"\n        assert (\n            buyer_dialogue.dialogue_label.dialogue_reference[1] != \"\"\n        ), \"Dialogue reference incorrect.\"\n        assert (\n            dialogue_reference_left_part\n            == buyer_dialogue.dialogue_label.dialogue_reference[0]\n        ), \"Dialogue refernce changed unexpectedly.\"\n\n        # buyer creates counter proposal 1\n        counter_proposal_msg_1 = buyer_dialogue.reply(\n            target_message=proposal_msg,\n            performative=FipaMessage.Performative.PROPOSE,\n            proposal=Description({\"foo1\": 3, \"bar1\": 3}),\n        )\n\n        assert (\n            len(buyer_dialogue._outgoing_messages) == 2\n        ), \"incorrect number of outgoing_messages in buyer dialogue after sending counter-proposal 1.\"\n        assert (\n            len(buyer_dialogue._incoming_messages) == 1\n        ), \"incorrect number of incoming_messages in buyer dialogue after sending counter-proposal 1.\"\n        assert (\n            buyer_dialogue.last_outgoing_message == counter_proposal_msg_1\n        ), \"wrong outgoing message in buyer dialogue after sending counter-proposal 1.\"\n\n        # counter-proposal 1 arrives at seller\n\n        seller_dialogue = self.seller_dialogues.update(counter_proposal_msg_1)\n\n        assert (\n            len(seller_dialogue._outgoing_messages) == 1\n        ), \"incorrect number of outgoing_messages in seller dialogue after receiving counter-proposal 1.\"\n        assert (\n            len(seller_dialogue._incoming_messages) == 2\n        ), \"incorrect number of incoming_messages in seller dialogue after receiving counter-proposal 1.\"\n        assert (\n            seller_dialogue.last_incoming_message == counter_proposal_msg_1\n        ), \"wrong incoming message in seller dialogue after receiving counter-proposal 1.\"\n\n        # seller creates counter-proposal 2\n        counter_proposal_msg_2 = seller_dialogue.reply(\n            target_message=counter_proposal_msg_1,\n            performative=FipaMessage.Performative.PROPOSE,\n            proposal=Description({\"foo1\": 2, \"bar1\": 2}),\n        )\n\n        assert (\n            len(seller_dialogue._outgoing_messages) == 2\n        ), \"incorrect number of outgoing_messages in seller dialogue after sending counter-proposal 2.\"\n        assert (\n            len(seller_dialogue._incoming_messages) == 2\n        ), \"incorrect number of incoming_messages in seller dialogue after sending counter-proposal 2.\"\n        assert (\n            seller_dialogue.last_outgoing_message == counter_proposal_msg_2\n        ), \"wrong outgoing message in seller dialogue after sending counter-proposal 2.\"\n\n        # counter-proposal 2 arrives at buyer\n\n        buyer_dialogue = self.buyer_dialogues.update(counter_proposal_msg_2)\n\n        assert (\n            len(buyer_dialogue._outgoing_messages) == 2\n        ), \"incorrect number of outgoing_messages in buyer dialogue after receiving counter-proposal 2.\"\n        assert (\n            len(buyer_dialogue._incoming_messages) == 2\n        ), \"incorrect number of incoming_messages in buyer dialogue after receiving counter-proposal 2.\"\n        assert (\n            buyer_dialogue.last_incoming_message == counter_proposal_msg_2\n        ), \"wrong incoming message in buyer dialogue after receiving counter-proposal 2.\"\n\n\nclass BuyerDialogue(FipaDialogue):\n    \"\"\"The dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    def __init__(\n        self,\n        dialogue_label: DialogueLabel,\n        self_address: Address,\n        role: BaseDialogue.Role,\n        message_class: Type[FipaMessage],\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n\n        :return: None\n        \"\"\"\n        FipaDialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            self_address=self_address,\n            role=role,\n            message_class=message_class,\n        )\n\n\nclass BuyerDialogues(FipaDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, self_address: Address) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :return: None\n        \"\"\"\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return FipaDialogue.Role.BUYER\n\n        FipaDialogues.__init__(\n            self,\n            self_address=self_address,\n            role_from_first_message=role_from_first_message,\n            dialogue_class=BuyerDialogue,\n        )\n\n\nclass SellerDialogue(FipaDialogue):\n    \"\"\"The dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    __slots__ = (\"some_object\",)\n\n    def __init__(\n        self,\n        dialogue_label: DialogueLabel,\n        self_address: Address,\n        role: BaseDialogue.Role,\n        message_class: Type[FipaMessage],\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n\n        :return: None\n        \"\"\"\n        FipaDialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            self_address=self_address,\n            role=role,\n            message_class=message_class,\n        )\n        self.some_object = None  # type: Optional[Any]\n\n\nclass SellerDialogues(FipaDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, self_address: Address) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :return: None\n        \"\"\"\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return FipaDialogue.Role.SELLER\n\n        FipaDialogues.__init__(\n            self,\n            self_address=self_address,\n            role_from_first_message=role_from_first_message,\n            dialogue_class=SellerDialogue,\n        )\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_protocols/test_gym.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests of the gym protocol package.\"\"\"\n\nimport sys\nfrom typing import Type\nfrom unittest import mock\n\nimport pytest\n\nfrom aea.common import Address\nfrom aea.exceptions import AEAEnforceError\nfrom aea.mail.base import Envelope\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\nfrom aea.protocols.dialogue.base import DialogueLabel\n\nimport packages\nfrom packages.fetchai.protocols.gym.dialogues import GymDialogue, GymDialogues\nfrom packages.fetchai.protocols.gym.message import GymMessage\nfrom packages.fetchai.protocols.gym.message import _default_logger as gym_message_logger\n\nfrom tests.conftest import ROOT_DIR\n\n\nsys.path.append(ROOT_DIR)\n\n\ndef test_act_serialization():\n    \"\"\"Test the serialization for 'act' speech-act works.\"\"\"\n    msg = GymMessage(\n        message_id=1,\n        dialogue_reference=(str(0), \"\"),\n        target=0,\n        performative=GymMessage.Performative.ACT,\n        action=GymMessage.AnyObject(\"some_action\"),\n        step_id=1,\n    )\n    msg.to = \"receiver\"\n    envelope = Envelope(\n        to=msg.to,\n        sender=\"sender\",\n        message=msg,\n    )\n    envelope_bytes = envelope.encode()\n\n    actual_envelope = Envelope.decode(envelope_bytes)\n    expected_envelope = envelope\n    assert expected_envelope.to == actual_envelope.to\n    assert expected_envelope.sender == actual_envelope.sender\n    assert (\n        expected_envelope.protocol_specification_id\n        == actual_envelope.protocol_specification_id\n    )\n    assert expected_envelope.message != actual_envelope.message\n\n    actual_msg = GymMessage.serializer.decode(actual_envelope.message)\n    actual_msg.to = actual_envelope.to\n    actual_msg.sender = actual_envelope.sender\n    expected_msg = msg\n    assert expected_msg == actual_msg\n\n\ndef test_percept_serialization():\n    \"\"\"Test the serialization for 'percept' speech-act works.\"\"\"\n    msg = GymMessage(\n        message_id=2,\n        dialogue_reference=(str(0), \"\"),\n        target=1,\n        performative=GymMessage.Performative.PERCEPT,\n        step_id=1,\n        observation=GymMessage.AnyObject(\"some_observation\"),\n        reward=10.0,\n        done=False,\n        info=GymMessage.AnyObject(\"some_info\"),\n    )\n    msg.to = \"receiver\"\n    envelope = Envelope(\n        to=msg.to,\n        sender=\"sender\",\n        message=msg,\n    )\n    envelope_bytes = envelope.encode()\n\n    actual_envelope = Envelope.decode(envelope_bytes)\n    expected_envelope = envelope\n    assert expected_envelope.to == actual_envelope.to\n    assert expected_envelope.sender == actual_envelope.sender\n    assert (\n        expected_envelope.protocol_specification_id\n        == actual_envelope.protocol_specification_id\n    )\n    assert expected_envelope.message != actual_envelope.message\n\n    actual_msg = GymMessage.serializer.decode(actual_envelope.message)\n    actual_msg.to = actual_envelope.to\n    actual_msg.sender = actual_envelope.sender\n    expected_msg = msg\n    assert expected_msg == actual_msg\n\n\ndef test_status_serialization():\n    \"\"\"Test the serialization for 'status' speech-act works.\"\"\"\n    content_arg = {\n        \"key_1\": \"value_1\",\n        \"key_2\": \"value_2\",\n    }\n    msg = GymMessage(\n        message_id=1,\n        dialogue_reference=(str(0), \"\"),\n        target=0,\n        performative=GymMessage.Performative.STATUS,\n        content=content_arg,\n    )\n    msg.to = \"receiver\"\n    envelope = Envelope(\n        to=msg.to,\n        sender=\"sender\",\n        message=msg,\n    )\n    envelope_bytes = envelope.encode()\n\n    actual_envelope = Envelope.decode(envelope_bytes)\n    expected_envelope = envelope\n    assert expected_envelope.to == actual_envelope.to\n    assert expected_envelope.sender == actual_envelope.sender\n    assert (\n        expected_envelope.protocol_specification_id\n        == actual_envelope.protocol_specification_id\n    )\n    assert expected_envelope.message != actual_envelope.message\n\n    actual_msg = GymMessage.serializer.decode(actual_envelope.message)\n    actual_msg.to = actual_envelope.to\n    actual_msg.sender = actual_envelope.sender\n    expected_msg = msg\n    assert expected_msg == actual_msg\n\n\ndef test_reset_serialization():\n    \"\"\"Test the serialization for 'reset' speech-act works.\"\"\"\n    msg = GymMessage(\n        message_id=1,\n        dialogue_reference=(str(0), \"\"),\n        target=0,\n        performative=GymMessage.Performative.RESET,\n    )\n    msg.to = \"receiver\"\n    envelope = Envelope(\n        to=msg.to,\n        sender=\"sender\",\n        message=msg,\n    )\n    envelope_bytes = envelope.encode()\n\n    actual_envelope = Envelope.decode(envelope_bytes)\n    expected_envelope = envelope\n    assert expected_envelope.to == actual_envelope.to\n    assert expected_envelope.sender == actual_envelope.sender\n    assert (\n        expected_envelope.protocol_specification_id\n        == actual_envelope.protocol_specification_id\n    )\n    assert expected_envelope.message != actual_envelope.message\n\n    actual_msg = GymMessage.serializer.decode(actual_envelope.message)\n    actual_msg.to = actual_envelope.to\n    actual_msg.sender = actual_envelope.sender\n    expected_msg = msg\n    assert expected_msg == actual_msg\n\n\ndef test_close_serialization():\n    \"\"\"Test the serialization for 'close' speech-act works.\"\"\"\n    msg = GymMessage(\n        message_id=1,\n        dialogue_reference=(str(0), \"\"),\n        target=0,\n        performative=GymMessage.Performative.CLOSE,\n    )\n    msg.to = \"receiver\"\n    envelope = Envelope(\n        to=msg.to,\n        sender=\"sender\",\n        message=msg,\n    )\n    envelope_bytes = envelope.encode()\n\n    actual_envelope = Envelope.decode(envelope_bytes)\n    expected_envelope = envelope\n    assert expected_envelope.to == actual_envelope.to\n    assert expected_envelope.sender == actual_envelope.sender\n    assert (\n        expected_envelope.protocol_specification_id\n        == actual_envelope.protocol_specification_id\n    )\n    assert expected_envelope.message != actual_envelope.message\n\n    actual_msg = GymMessage.serializer.decode(actual_envelope.message)\n    actual_msg.to = actual_envelope.to\n    actual_msg.sender = actual_envelope.sender\n    expected_msg = msg\n    assert expected_msg == actual_msg\n\n\ndef test_performative_string_value():\n    \"\"\"Test the string value of the performatives.\"\"\"\n    assert str(GymMessage.Performative.ACT) == \"act\", \"The str value must be act\"\n    assert (\n        str(GymMessage.Performative.PERCEPT) == \"percept\"\n    ), \"The str value must be percept\"\n    assert (\n        str(GymMessage.Performative.STATUS) == \"status\"\n    ), \"The str value must be status\"\n    assert str(GymMessage.Performative.RESET) == \"reset\", \"The str value must be reset\"\n    assert str(GymMessage.Performative.CLOSE) == \"close\", \"The str value must be close\"\n\n\ndef test_encoding_unknown_performative():\n    \"\"\"Test that we raise an exception when the performative is unknown during encoding.\"\"\"\n    msg = GymMessage(\n        message_id=1,\n        dialogue_reference=(str(0), \"\"),\n        target=0,\n        performative=GymMessage.Performative.RESET,\n    )\n\n    with pytest.raises(ValueError, match=\"Performative not valid:\"):\n        with mock.patch.object(GymMessage.Performative, \"__eq__\", return_value=False):\n            GymMessage.serializer.encode(msg)\n\n\ndef test_decoding_unknown_performative():\n    \"\"\"Test that we raise an exception when the performative is unknown during decoding.\"\"\"\n    msg = GymMessage(\n        message_id=1,\n        dialogue_reference=(str(0), \"\"),\n        target=0,\n        performative=GymMessage.Performative.RESET,\n    )\n\n    encoded_msg = GymMessage.serializer.encode(msg)\n    with pytest.raises(ValueError, match=\"Performative not valid:\"):\n        with mock.patch.object(GymMessage.Performative, \"__eq__\", return_value=False):\n            GymMessage.serializer.decode(encoded_msg)\n\n\n@mock.patch.object(\n    packages.fetchai.protocols.gym.message,\n    \"enforce\",\n    side_effect=AEAEnforceError(\"some error\"),\n)\ndef test_incorrect_message(mocked_enforce):\n    \"\"\"Test that we raise an exception when the message is incorrect.\"\"\"\n    with mock.patch.object(gym_message_logger, \"error\") as mock_logger:\n        GymMessage(\n            message_id=1,\n            dialogue_reference=(str(0), \"\"),\n            target=0,\n            performative=GymMessage.Performative.RESET,\n        )\n\n        mock_logger.assert_any_call(\"some error\")\n\n\nclass TestDialogues:\n    \"\"\"Tests gym dialogues.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set up the test.\"\"\"\n        cls.agent_addr = \"agent address\"\n        cls.env_addr = \"env address\"\n        cls.agent_dialogues = AgentDialogues(cls.agent_addr)\n        cls.env_dialogues = EnvironmentDialogues(cls.env_addr)\n\n    def test_create_self_initiated(self):\n        \"\"\"Test the self initialisation of a dialogue.\"\"\"\n        result = self.agent_dialogues._create_self_initiated(\n            dialogue_opponent_addr=self.env_addr,\n            dialogue_reference=(str(0), \"\"),\n            role=GymDialogue.Role.AGENT,\n        )\n        assert isinstance(result, GymDialogue)\n        assert result.role == GymDialogue.Role.AGENT, \"The role must be Agent.\"\n\n    def test_create_opponent_initiated(self):\n        \"\"\"Test the opponent initialisation of a dialogue.\"\"\"\n        result = self.agent_dialogues._create_opponent_initiated(\n            dialogue_opponent_addr=self.env_addr,\n            dialogue_reference=(str(0), \"\"),\n            role=GymDialogue.Role.AGENT,\n        )\n        assert isinstance(result, GymDialogue)\n        assert result.role == GymDialogue.Role.AGENT, \"The role must be agent.\"\n\n\nclass AgentDialogue(GymDialogue):\n    \"\"\"The dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    def __init__(\n        self,\n        dialogue_label: DialogueLabel,\n        self_address: Address,\n        role: BaseDialogue.Role,\n        message_class: Type[GymMessage],\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n\n        :return: None\n        \"\"\"\n        GymDialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            self_address=self_address,\n            role=role,\n            message_class=message_class,\n        )\n\n\nclass AgentDialogues(GymDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, self_address: Address) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :return: None\n        \"\"\"\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return GymDialogue.Role.AGENT\n\n        GymDialogues.__init__(\n            self,\n            self_address=self_address,\n            role_from_first_message=role_from_first_message,\n            dialogue_class=AgentDialogue,\n        )\n\n\nclass EnvironmentDialogue(GymDialogue):\n    \"\"\"The dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    def __init__(\n        self,\n        dialogue_label: DialogueLabel,\n        self_address: Address,\n        role: BaseDialogue.Role,\n        message_class: Type[GymMessage],\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n\n        :return: None\n        \"\"\"\n        GymDialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            self_address=self_address,\n            role=role,\n            message_class=message_class,\n        )\n\n\nclass EnvironmentDialogues(GymDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, self_address: Address) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :return: None\n        \"\"\"\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return GymDialogue.Role.ENVIRONMENT\n\n        GymDialogues.__init__(\n            self,\n            self_address=self_address,\n            role_from_first_message=role_from_first_message,\n            dialogue_class=EnvironmentDialogue,\n        )\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_protocols/test_http.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests of the http protocol package.\"\"\"\n\nimport sys\nfrom typing import Type\nfrom unittest import mock\n\nimport pytest\n\nfrom aea.common import Address\nfrom aea.exceptions import AEAEnforceError\nfrom aea.mail.base import Envelope\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\nfrom aea.protocols.dialogue.base import DialogueLabel\n\nimport packages\nfrom packages.fetchai.protocols.http.dialogues import HttpDialogue, HttpDialogues\nfrom packages.fetchai.protocols.http.message import HttpMessage\nfrom packages.fetchai.protocols.http.message import (\n    _default_logger as http_message_logger,\n)\n\nfrom tests.conftest import ROOT_DIR\n\n\nsys.path.append(ROOT_DIR)\n\n\ndef test_request_serialization():\n    \"\"\"Test the serialization for 'request' speech-act works.\"\"\"\n    msg = HttpMessage(\n        performative=HttpMessage.Performative.REQUEST,\n        method=\"some_method\",\n        url=\"url\",\n        version=\"some_version\",\n        headers=\"some_headers\",\n        body=b\"some_body\",\n    )\n    msg.to = \"receiver\"\n    envelope = Envelope(\n        to=msg.to,\n        sender=\"sender\",\n        message=msg,\n    )\n    envelope_bytes = envelope.encode()\n\n    actual_envelope = Envelope.decode(envelope_bytes)\n    expected_envelope = envelope\n    assert expected_envelope.to == actual_envelope.to\n    assert expected_envelope.sender == actual_envelope.sender\n    assert (\n        expected_envelope.protocol_specification_id\n        == actual_envelope.protocol_specification_id\n    )\n    assert expected_envelope.message != actual_envelope.message\n\n    actual_msg = HttpMessage.serializer.decode(actual_envelope.message)\n    actual_msg.to = actual_envelope.to\n    actual_msg.sender = actual_envelope.sender\n    expected_msg = msg\n    assert expected_msg == actual_msg\n\n\ndef test_response_serialization():\n    \"\"\"Test the serialization for 'response' speech-act works.\"\"\"\n    msg = HttpMessage(\n        message_id=2,\n        target=1,\n        performative=HttpMessage.Performative.RESPONSE,\n        version=\"some_version\",\n        status_code=1,\n        status_text=\"some_status_text\",\n        headers=\"some_headers\",\n        body=b\"some_body\",\n    )\n    msg.to = \"receiver\"\n    envelope = Envelope(\n        to=msg.to,\n        sender=\"sender\",\n        message=msg,\n    )\n    envelope_bytes = envelope.encode()\n\n    actual_envelope = Envelope.decode(envelope_bytes)\n    expected_envelope = envelope\n    assert expected_envelope.to == actual_envelope.to\n    assert expected_envelope.sender == actual_envelope.sender\n    assert (\n        expected_envelope.protocol_specification_id\n        == actual_envelope.protocol_specification_id\n    )\n    assert expected_envelope.message != actual_envelope.message\n\n    actual_msg = HttpMessage.serializer.decode(actual_envelope.message)\n    actual_msg.to = actual_envelope.to\n    actual_msg.sender = actual_envelope.sender\n    expected_msg = msg\n    assert expected_msg == actual_msg\n\n\ndef test_performative_string_value():\n    \"\"\"Test the string value of the performatives.\"\"\"\n    assert (\n        str(HttpMessage.Performative.REQUEST) == \"request\"\n    ), \"The str value must be request\"\n    assert (\n        str(HttpMessage.Performative.RESPONSE) == \"response\"\n    ), \"The str value must be response\"\n\n\ndef test_encoding_unknown_performative():\n    \"\"\"Test that we raise an exception when the performative is unknown during encoding.\"\"\"\n    msg = HttpMessage(\n        performative=HttpMessage.Performative.REQUEST,\n        method=\"some_method\",\n        url=\"url\",\n        version=\"some_version\",\n        headers=\"some_headers\",\n        body=b\"some_body\",\n    )\n\n    with pytest.raises(ValueError, match=\"Performative not valid:\"):\n        with mock.patch.object(HttpMessage.Performative, \"__eq__\", return_value=False):\n            HttpMessage.serializer.encode(msg)\n\n\ndef test_decoding_unknown_performative():\n    \"\"\"Test that we raise an exception when the performative is unknown during decoding.\"\"\"\n    msg = HttpMessage(\n        performative=HttpMessage.Performative.REQUEST,\n        method=\"some_method\",\n        url=\"url\",\n        version=\"some_version\",\n        headers=\"some_headers\",\n        body=b\"some_body\",\n    )\n\n    encoded_msg = HttpMessage.serializer.encode(msg)\n    with pytest.raises(ValueError, match=\"Performative not valid:\"):\n        with mock.patch.object(HttpMessage.Performative, \"__eq__\", return_value=False):\n            HttpMessage.serializer.decode(encoded_msg)\n\n\n@mock.patch.object(\n    packages.fetchai.protocols.http.message,\n    \"enforce\",\n    side_effect=AEAEnforceError(\"some error\"),\n)\ndef test_incorrect_message(mocked_enforce):\n    \"\"\"Test that we raise an exception when the message is incorrect.\"\"\"\n    with mock.patch.object(http_message_logger, \"error\") as mock_logger:\n        HttpMessage(\n            performative=HttpMessage.Performative.REQUEST,\n            method=\"some_method\",\n            url=\"url\",\n            version=\"some_version\",\n            headers=\"some_headers\",\n            body=b\"some_body\",\n        )\n\n        mock_logger.assert_any_call(\"some error\")\n\n\nclass TestDialogues:\n    \"\"\"Tests http dialogues.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set up the test.\"\"\"\n        cls.agent_addr = \"agent address\"\n        cls.server_addr = \"server address\"\n        cls.agent_dialogues = AgentDialogues(cls.agent_addr)\n        cls.server_dialogues = ServerDialogues(cls.server_addr)\n\n    def test_create_self_initiated(self):\n        \"\"\"Test the self initialisation of a dialogue.\"\"\"\n        result = self.agent_dialogues._create_self_initiated(\n            dialogue_opponent_addr=self.server_addr,\n            dialogue_reference=(str(0), \"\"),\n            role=HttpDialogue.Role.CLIENT,\n        )\n        assert isinstance(result, HttpDialogue)\n        assert result.role == HttpDialogue.Role.CLIENT, \"The role must be client.\"\n\n    def test_create_opponent_initiated(self):\n        \"\"\"Test the opponent initialisation of a dialogue.\"\"\"\n        result = self.agent_dialogues._create_opponent_initiated(\n            dialogue_opponent_addr=self.server_addr,\n            dialogue_reference=(str(0), \"\"),\n            role=HttpDialogue.Role.CLIENT,\n        )\n        assert isinstance(result, HttpDialogue)\n        assert result.role == HttpDialogue.Role.CLIENT, \"The role must be client.\"\n\n\nclass AgentDialogue(HttpDialogue):\n    \"\"\"The dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    def __init__(\n        self,\n        dialogue_label: DialogueLabel,\n        self_address: Address,\n        role: BaseDialogue.Role,\n        message_class: Type[HttpMessage],\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n\n        :return: None\n        \"\"\"\n        HttpDialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            self_address=self_address,\n            role=role,\n            message_class=message_class,\n        )\n\n\nclass AgentDialogues(HttpDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, self_address: Address) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :return: None\n        \"\"\"\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return HttpDialogue.Role.CLIENT\n\n        HttpDialogues.__init__(\n            self,\n            self_address=self_address,\n            role_from_first_message=role_from_first_message,\n            dialogue_class=AgentDialogue,\n        )\n\n\nclass ServerDialogue(HttpDialogue):\n    \"\"\"The dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    def __init__(\n        self,\n        dialogue_label: DialogueLabel,\n        self_address: Address,\n        role: BaseDialogue.Role,\n        message_class: Type[HttpMessage],\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n\n        :return: None\n        \"\"\"\n        HttpDialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            self_address=self_address,\n            role=role,\n            message_class=message_class,\n        )\n\n\nclass ServerDialogues(HttpDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, self_address: Address) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :return: None\n        \"\"\"\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return HttpDialogue.Role.SERVER\n\n        HttpDialogues.__init__(\n            self,\n            self_address=self_address,\n            role_from_first_message=role_from_first_message,\n            dialogue_class=ServerDialogue,\n        )\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_protocols/test_ledger_api.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests of the messages module.\"\"\"\n\nimport sys\nfrom typing import Type\nfrom unittest import mock\n\nimport pytest\n\nfrom aea.common import Address\nfrom aea.exceptions import AEAEnforceError\nfrom aea.helpers.transaction.base import State\nfrom aea.mail.base import Envelope\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\nfrom aea.protocols.dialogue.base import DialogueLabel\n\nimport packages\nfrom packages.fetchai.protocols.ledger_api.custom_types import Kwargs\nfrom packages.fetchai.protocols.ledger_api.dialogues import (\n    LedgerApiDialogue,\n    LedgerApiDialogues,\n)\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\nfrom packages.fetchai.protocols.ledger_api.message import (\n    _default_logger as ledger_api_message_logger,\n)\n\nfrom tests.conftest import ROOT_DIR\n\n\nsys.path.append(ROOT_DIR)\n\n\ndef test_get_balance_serialization():\n    \"\"\"Test the serialization for 'get_balance' speech-act works.\"\"\"\n    msg = LedgerApiMessage(\n        performative=LedgerApiMessage.Performative.GET_BALANCE,\n        ledger_id=\"some_ledger_id\",\n        address=\"some_address\",\n    )\n    msg.to = \"receiver\"\n    envelope = Envelope(\n        to=msg.to,\n        sender=\"sender\",\n        message=msg,\n    )\n    envelope_bytes = envelope.encode()\n\n    actual_envelope = Envelope.decode(envelope_bytes)\n    expected_envelope = envelope\n    assert expected_envelope.to == actual_envelope.to\n    assert expected_envelope.sender == actual_envelope.sender\n    assert (\n        expected_envelope.protocol_specification_id\n        == actual_envelope.protocol_specification_id\n    )\n    assert expected_envelope.message != actual_envelope.message\n\n    actual_msg = LedgerApiMessage.serializer.decode(actual_envelope.message)\n    actual_msg.to = actual_envelope.to\n    actual_msg.sender = actual_envelope.sender\n    expected_msg = msg\n    assert expected_msg == actual_msg\n\n\ndef test_get_state_serialization():\n    \"\"\"Test the serialization for 'get_state' speech-act works.\"\"\"\n\n    args = (\"arg1\", \"arg2\")\n    kwargs = Kwargs({\"key\": \"value\"})\n\n    assert str(kwargs) == \"Kwargs: body={'key': 'value'}\"\n\n    msg = LedgerApiMessage(\n        performative=LedgerApiMessage.Performative.GET_STATE,\n        ledger_id=\"some_ledger_id\",\n        callable=\"some_function\",\n        args=args,\n        kwargs=kwargs,\n    )\n    msg.to = \"receiver\"\n    envelope = Envelope(\n        to=msg.to,\n        sender=\"sender\",\n        message=msg,\n    )\n    envelope_bytes = envelope.encode()\n\n    actual_envelope = Envelope.decode(envelope_bytes)\n    expected_envelope = envelope\n    assert expected_envelope.to == actual_envelope.to\n    assert expected_envelope.sender == actual_envelope.sender\n    assert (\n        expected_envelope.protocol_specification_id\n        == actual_envelope.protocol_specification_id\n    )\n    assert expected_envelope.message != actual_envelope.message\n\n    actual_msg = LedgerApiMessage.serializer.decode(actual_envelope.message)\n    actual_msg.to = actual_envelope.to\n    actual_msg.sender = actual_envelope.sender\n    expected_msg = msg\n    assert expected_msg == actual_msg\n\n\ndef test_get_raw_transaction_serialization():\n    \"\"\"Test the serialization for 'get_raw_transaction' speech-act works.\"\"\"\n    terms_arg = LedgerApiMessage.Terms(\n        ledger_id=\"some_ledger_id\",\n        sender_address=\"some_sender_address\",\n        counterparty_address=\"some_counterparty_address\",\n        amount_by_currency_id={\"currency_id_1\": 1},\n        quantities_by_good_id={\"good_id_1\": -1, \"good_id_2\": -2},\n        nonce=\"some_nonce\",\n        is_sender_payable_tx_fee=False,\n        fee_by_currency_id={\"currency_id_1\": 1},\n        is_strict=True,\n    )\n    msg = LedgerApiMessage(\n        message_id=2,\n        target=1,\n        performative=LedgerApiMessage.Performative.GET_RAW_TRANSACTION,\n        terms=terms_arg,\n    )\n    msg.to = \"receiver\"\n    envelope = Envelope(\n        to=msg.to,\n        sender=\"sender\",\n        message=msg,\n    )\n    envelope_bytes = envelope.encode()\n\n    actual_envelope = Envelope.decode(envelope_bytes)\n    expected_envelope = envelope\n    assert expected_envelope.to == actual_envelope.to\n    assert expected_envelope.sender == actual_envelope.sender\n    assert (\n        expected_envelope.protocol_specification_id\n        == actual_envelope.protocol_specification_id\n    )\n    assert expected_envelope.message != actual_envelope.message\n\n    actual_msg = LedgerApiMessage.serializer.decode(actual_envelope.message)\n    actual_msg.to = actual_envelope.to\n    actual_msg.sender = actual_envelope.sender\n    expected_msg = msg\n    assert expected_msg == actual_msg\n\n\ndef test_send_signed_transaction_serialization():\n    \"\"\"Test the serialization for 'send_signed_transaction' speech-act works.\"\"\"\n    msg = LedgerApiMessage(\n        message_id=2,\n        target=1,\n        performative=LedgerApiMessage.Performative.SEND_SIGNED_TRANSACTION,\n        signed_transaction=LedgerApiMessage.SignedTransaction(\n            \"some_ledger_id\", {\"body\": \"some_body\"}\n        ),\n    )\n    msg.to = \"receiver\"\n    envelope = Envelope(\n        to=msg.to,\n        sender=\"sender\",\n        message=msg,\n    )\n    envelope_bytes = envelope.encode()\n\n    actual_envelope = Envelope.decode(envelope_bytes)\n    expected_envelope = envelope\n    assert expected_envelope.to == actual_envelope.to\n    assert expected_envelope.sender == actual_envelope.sender\n    assert (\n        expected_envelope.protocol_specification_id\n        == actual_envelope.protocol_specification_id\n    )\n    assert expected_envelope.message != actual_envelope.message\n\n    actual_msg = LedgerApiMessage.serializer.decode(actual_envelope.message)\n    actual_msg.to = actual_envelope.to\n    actual_msg.sender = actual_envelope.sender\n    expected_msg = msg\n    assert expected_msg == actual_msg\n\n\ndef test_get_transaction_receipt_serialization():\n    \"\"\"Test the serialization for 'get_transaction_receipt' speech-act works.\"\"\"\n    msg = LedgerApiMessage(\n        message_id=2,\n        target=1,\n        performative=LedgerApiMessage.Performative.GET_TRANSACTION_RECEIPT,\n        transaction_digest=LedgerApiMessage.TransactionDigest(\n            \"some_ledger_id\", \"some_body\"\n        ),\n    )\n    msg.to = \"receiver\"\n    envelope = Envelope(\n        to=msg.to,\n        sender=\"sender\",\n        message=msg,\n    )\n    envelope_bytes = envelope.encode()\n\n    actual_envelope = Envelope.decode(envelope_bytes)\n    expected_envelope = envelope\n    assert expected_envelope.to == actual_envelope.to\n    assert expected_envelope.sender == actual_envelope.sender\n    assert (\n        expected_envelope.protocol_specification_id\n        == actual_envelope.protocol_specification_id\n    )\n    assert expected_envelope.message != actual_envelope.message\n\n    actual_msg = LedgerApiMessage.serializer.decode(actual_envelope.message)\n    actual_msg.to = actual_envelope.to\n    actual_msg.sender = actual_envelope.sender\n    expected_msg = msg\n    assert expected_msg == actual_msg\n\n\ndef test_balance_serialization():\n    \"\"\"Test the serialization for 'balance' speech-act works.\"\"\"\n    msg = LedgerApiMessage(\n        message_id=2,\n        target=1,\n        performative=LedgerApiMessage.Performative.BALANCE,\n        ledger_id=\"some_ledger_id\",\n        balance=125,\n    )\n    msg.to = \"receiver\"\n    envelope = Envelope(\n        to=msg.to,\n        sender=\"sender\",\n        message=msg,\n    )\n    envelope_bytes = envelope.encode()\n\n    actual_envelope = Envelope.decode(envelope_bytes)\n    expected_envelope = envelope\n    assert expected_envelope.to == actual_envelope.to\n    assert expected_envelope.sender == actual_envelope.sender\n    assert (\n        expected_envelope.protocol_specification_id\n        == actual_envelope.protocol_specification_id\n    )\n    assert expected_envelope.message != actual_envelope.message\n\n    actual_msg = LedgerApiMessage.serializer.decode(actual_envelope.message)\n    actual_msg.to = actual_envelope.to\n    actual_msg.sender = actual_envelope.sender\n    expected_msg = msg\n    assert expected_msg == actual_msg\n\n\ndef test_state_serialization():\n    \"\"\"Test the serialization for 'state' speech-act works.\"\"\"\n\n    ledger_id = \"some_ledger_id\"\n    state = State(ledger_id, {\"key\": \"some_state\"})\n\n    msg = LedgerApiMessage(\n        message_id=2,\n        target=1,\n        performative=LedgerApiMessage.Performative.STATE,\n        ledger_id=ledger_id,\n        state=state,\n    )\n    msg.to = \"receiver\"\n    envelope = Envelope(\n        to=msg.to,\n        sender=\"sender\",\n        message=msg,\n    )\n    envelope_bytes = envelope.encode()\n\n    actual_envelope = Envelope.decode(envelope_bytes)\n    expected_envelope = envelope\n    assert expected_envelope.to == actual_envelope.to\n    assert expected_envelope.sender == actual_envelope.sender\n    assert (\n        expected_envelope.protocol_specification_id\n        == actual_envelope.protocol_specification_id\n    )\n    assert expected_envelope.message != actual_envelope.message\n\n    actual_msg = LedgerApiMessage.serializer.decode(actual_envelope.message)\n    actual_msg.to = actual_envelope.to\n    actual_msg.sender = actual_envelope.sender\n    expected_msg = msg\n    assert expected_msg == actual_msg\n\n\ndef test_raw_transaction_serialization():\n    \"\"\"Test the serialization for 'raw_transaction' speech-act works.\"\"\"\n    msg = LedgerApiMessage(\n        message_id=2,\n        target=1,\n        performative=LedgerApiMessage.Performative.RAW_TRANSACTION,\n        raw_transaction=LedgerApiMessage.RawTransaction(\n            \"some_ledger_id\", {\"body\": \"some_body\"}\n        ),\n    )\n    msg.to = \"receiver\"\n    envelope = Envelope(\n        to=msg.to,\n        sender=\"sender\",\n        message=msg,\n    )\n    envelope_bytes = envelope.encode()\n\n    actual_envelope = Envelope.decode(envelope_bytes)\n    expected_envelope = envelope\n    assert expected_envelope.to == actual_envelope.to\n    assert expected_envelope.sender == actual_envelope.sender\n    assert (\n        expected_envelope.protocol_specification_id\n        == actual_envelope.protocol_specification_id\n    )\n    assert expected_envelope.message != actual_envelope.message\n\n    actual_msg = LedgerApiMessage.serializer.decode(actual_envelope.message)\n    actual_msg.to = actual_envelope.to\n    actual_msg.sender = actual_envelope.sender\n    expected_msg = msg\n    assert expected_msg == actual_msg\n\n\ndef test_transaction_digest_serialization():\n    \"\"\"Test the serialization for 'transaction_digest' speech-act works.\"\"\"\n    msg = LedgerApiMessage(\n        message_id=2,\n        target=1,\n        performative=LedgerApiMessage.Performative.TRANSACTION_DIGEST,\n        transaction_digest=LedgerApiMessage.TransactionDigest(\n            \"some_ledger_id\", \"some_body\"\n        ),\n    )\n    msg.to = \"receiver\"\n    envelope = Envelope(\n        to=msg.to,\n        sender=\"sender\",\n        message=msg,\n    )\n    envelope_bytes = envelope.encode()\n\n    actual_envelope = Envelope.decode(envelope_bytes)\n    expected_envelope = envelope\n    assert expected_envelope.to == actual_envelope.to\n    assert expected_envelope.sender == actual_envelope.sender\n    assert (\n        expected_envelope.protocol_specification_id\n        == actual_envelope.protocol_specification_id\n    )\n    assert expected_envelope.message != actual_envelope.message\n\n    actual_msg = LedgerApiMessage.serializer.decode(actual_envelope.message)\n    actual_msg.to = actual_envelope.to\n    actual_msg.sender = actual_envelope.sender\n    expected_msg = msg\n    assert expected_msg == actual_msg\n\n\ndef test_transaction_receipt_serialization():\n    \"\"\"Test the serialization for 'transaction_receipt' speech-act works.\"\"\"\n    msg = LedgerApiMessage(\n        message_id=2,\n        target=1,\n        performative=LedgerApiMessage.Performative.TRANSACTION_RECEIPT,\n        transaction_receipt=LedgerApiMessage.TransactionReceipt(\n            \"some_ledger_id\", {\"key\": \"some_receipt\"}, {\"key\": \"some_transaction\"}\n        ),\n    )\n    msg.to = \"receiver\"\n    envelope = Envelope(\n        to=msg.to,\n        sender=\"sender\",\n        message=msg,\n    )\n    envelope_bytes = envelope.encode()\n\n    actual_envelope = Envelope.decode(envelope_bytes)\n    expected_envelope = envelope\n    assert expected_envelope.to == actual_envelope.to\n    assert expected_envelope.sender == actual_envelope.sender\n    assert (\n        expected_envelope.protocol_specification_id\n        == actual_envelope.protocol_specification_id\n    )\n    assert expected_envelope.message != actual_envelope.message\n\n    actual_msg = LedgerApiMessage.serializer.decode(actual_envelope.message)\n    actual_msg.to = actual_envelope.to\n    actual_msg.sender = actual_envelope.sender\n    expected_msg = msg\n    assert expected_msg == actual_msg\n\n\ndef test_error_serialization():\n    \"\"\"Test the serialization for 'error' speech-act works.\"\"\"\n    msg = LedgerApiMessage(\n        performative=LedgerApiMessage.Performative.ERROR,\n        code=7,\n        message=\"some_error_message\",\n        data=b\"some_error_data\",\n    )\n    msg.to = \"receiver\"\n    envelope = Envelope(\n        to=msg.to,\n        sender=\"sender\",\n        message=msg,\n    )\n    envelope_bytes = envelope.encode()\n\n    actual_envelope = Envelope.decode(envelope_bytes)\n    expected_envelope = envelope\n    assert expected_envelope.to == actual_envelope.to\n    assert expected_envelope.sender == actual_envelope.sender\n    assert (\n        expected_envelope.protocol_specification_id\n        == actual_envelope.protocol_specification_id\n    )\n    assert expected_envelope.message != actual_envelope.message\n\n    actual_msg = LedgerApiMessage.serializer.decode(actual_envelope.message)\n    actual_msg.to = actual_envelope.to\n    actual_msg.sender = actual_envelope.sender\n    expected_msg = msg\n    assert expected_msg == actual_msg\n\n\ndef test_performative_string_value():\n    \"\"\"Test the string value of the performatives.\"\"\"\n    assert (\n        str(LedgerApiMessage.Performative.GET_BALANCE) == \"get_balance\"\n    ), \"The str value must be get_balance\"\n    assert (\n        str(LedgerApiMessage.Performative.GET_RAW_TRANSACTION) == \"get_raw_transaction\"\n    ), \"The str value must be get_raw_transaction\"\n    assert (\n        str(LedgerApiMessage.Performative.SEND_SIGNED_TRANSACTION)\n        == \"send_signed_transaction\"\n    ), \"The str value must be send_signed_transaction\"\n    assert (\n        str(LedgerApiMessage.Performative.GET_TRANSACTION_RECEIPT)\n        == \"get_transaction_receipt\"\n    ), \"The str value must be get_transaction_receipt\"\n    assert (\n        str(LedgerApiMessage.Performative.BALANCE) == \"balance\"\n    ), \"The str value must be balance\"\n    assert (\n        str(LedgerApiMessage.Performative.RAW_TRANSACTION) == \"raw_transaction\"\n    ), \"The str value must be raw_transaction\"\n    assert (\n        str(LedgerApiMessage.Performative.TRANSACTION_DIGEST) == \"transaction_digest\"\n    ), \"The str value must be transaction_digest\"\n    assert (\n        str(LedgerApiMessage.Performative.TRANSACTION_RECEIPT) == \"transaction_receipt\"\n    ), \"The str value must be transaction_receipt\"\n    assert (\n        str(LedgerApiMessage.Performative.ERROR) == \"error\"\n    ), \"The str value must be error\"\n\n\ndef test_encoding_unknown_performative():\n    \"\"\"Test that we raise an exception when the performative is unknown during encoding.\"\"\"\n    msg = LedgerApiMessage(\n        performative=LedgerApiMessage.Performative.GET_BALANCE,\n        ledger_id=\"some_ledger_id\",\n        address=\"some_address\",\n    )\n\n    with pytest.raises(ValueError, match=\"Performative not valid:\"):\n        with mock.patch.object(\n            LedgerApiMessage.Performative, \"__eq__\", return_value=False\n        ):\n            LedgerApiMessage.serializer.encode(msg)\n\n\ndef test_decoding_unknown_performative():\n    \"\"\"Test that we raise an exception when the performative is unknown during decoding.\"\"\"\n    msg = LedgerApiMessage(\n        performative=LedgerApiMessage.Performative.GET_BALANCE,\n        ledger_id=\"some_ledger_id\",\n        address=\"some_address\",\n    )\n\n    encoded_msg = LedgerApiMessage.serializer.encode(msg)\n    with pytest.raises(ValueError, match=\"Performative not valid:\"):\n        with mock.patch.object(\n            LedgerApiMessage.Performative, \"__eq__\", return_value=False\n        ):\n            LedgerApiMessage.serializer.decode(encoded_msg)\n\n\n@mock.patch.object(\n    packages.fetchai.protocols.ledger_api.message,\n    \"enforce\",\n    side_effect=AEAEnforceError(\"some error\"),\n)\ndef test_incorrect_message(mocked_enforce):\n    \"\"\"Test that we raise an exception when the message is incorrect.\"\"\"\n    with mock.patch.object(ledger_api_message_logger, \"error\") as mock_logger:\n        LedgerApiMessage(\n            performative=LedgerApiMessage.Performative.GET_BALANCE,\n            ledger_id=\"some_ledger_id\",\n            address=\"some_address\",\n        )\n\n        mock_logger.assert_any_call(\"some error\")\n\n\nclass TestDialogues:\n    \"\"\"Tests ledger_api dialogues.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set up the test.\"\"\"\n        cls.agent_addr = \"agent address\"\n        cls.ledger_addr = \"ledger address\"\n        cls.agent_dialogues = AgentDialogues(cls.agent_addr)\n        cls.ledger_dialogues = LedgerDialogues(cls.ledger_addr)\n\n    def test_create_self_initiated(self):\n        \"\"\"Test the self initialisation of a dialogue.\"\"\"\n        result = self.agent_dialogues._create_self_initiated(\n            dialogue_opponent_addr=self.ledger_addr,\n            dialogue_reference=(str(0), \"\"),\n            role=LedgerApiDialogue.Role.AGENT,\n        )\n        assert isinstance(result, LedgerApiDialogue)\n        assert result.role == LedgerApiDialogue.Role.AGENT, \"The role must be agent.\"\n\n    def test_create_opponent_initiated(self):\n        \"\"\"Test the opponent initialisation of a dialogue.\"\"\"\n        result = self.agent_dialogues._create_opponent_initiated(\n            dialogue_opponent_addr=self.ledger_addr,\n            dialogue_reference=(str(0), \"\"),\n            role=LedgerApiDialogue.Role.AGENT,\n        )\n        assert isinstance(result, LedgerApiDialogue)\n        assert result.role == LedgerApiDialogue.Role.AGENT, \"The role must be agen t.\"\n\n\nclass AgentDialogue(LedgerApiDialogue):\n    \"\"\"The dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    def __init__(\n        self,\n        dialogue_label: DialogueLabel,\n        self_address: Address,\n        role: BaseDialogue.Role,\n        message_class: Type[LedgerApiMessage],\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n\n        :return: None\n        \"\"\"\n        LedgerApiDialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            self_address=self_address,\n            role=role,\n            message_class=message_class,\n        )\n\n\nclass AgentDialogues(LedgerApiDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, self_address: Address) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :return: None\n        \"\"\"\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return LedgerApiDialogue.Role.AGENT\n\n        LedgerApiDialogues.__init__(\n            self,\n            self_address=self_address,\n            role_from_first_message=role_from_first_message,\n            dialogue_class=AgentDialogue,\n        )\n\n\nclass LedgerDialogue(LedgerApiDialogue):\n    \"\"\"The dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    def __init__(\n        self,\n        dialogue_label: DialogueLabel,\n        self_address: Address,\n        role: BaseDialogue.Role,\n        message_class: Type[LedgerApiMessage],\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n\n        :return: None\n        \"\"\"\n        LedgerApiDialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            self_address=self_address,\n            role=role,\n            message_class=message_class,\n        )\n\n\nclass LedgerDialogues(LedgerApiDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, self_address: Address) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :return: None\n        \"\"\"\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return LedgerApiDialogue.Role.LEDGER\n\n        LedgerApiDialogues.__init__(\n            self,\n            self_address=self_address,\n            role_from_first_message=role_from_first_message,\n            dialogue_class=LedgerDialogue,\n        )\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_protocols/test_oef_search.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests of the oef_search protocol package.\"\"\"\n\nimport sys\nfrom typing import Type\nfrom unittest import mock\n\nimport pytest\n\nfrom aea.common import Address\nfrom aea.exceptions import AEAEnforceError\nfrom aea.helpers.search.models import Constraint, ConstraintType, Description, Query\nfrom aea.mail.base import Envelope\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\nfrom aea.protocols.dialogue.base import DialogueLabel\n\nimport packages\nfrom packages.fetchai.protocols.oef_search.dialogues import (\n    OefSearchDialogue,\n    OefSearchDialogues,\n)\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.protocols.oef_search.message import (\n    _default_logger as oef_search_message_logger,\n)\n\nfrom tests.conftest import ROOT_DIR\n\n\nsys.path.append(ROOT_DIR)\n\n\ndef test_register_service_serialization():\n    \"\"\"Test the serialization for 'register_service' speech-act works.\"\"\"\n    msg = OefSearchMessage(\n        performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n        service_description=Description({\"foo1\": 1, \"bar1\": 2}),\n    )\n    msg.to = \"receiver\"\n    envelope = Envelope(\n        to=msg.to,\n        sender=\"sender\",\n        message=msg,\n    )\n    envelope_bytes = envelope.encode()\n\n    actual_envelope = Envelope.decode(envelope_bytes)\n    expected_envelope = envelope\n    assert expected_envelope.to == actual_envelope.to\n    assert expected_envelope.sender == actual_envelope.sender\n    assert (\n        expected_envelope.protocol_specification_id\n        == actual_envelope.protocol_specification_id\n    )\n    assert expected_envelope.message != actual_envelope.message\n\n    actual_msg = OefSearchMessage.serializer.decode(actual_envelope.message)\n    actual_msg.to = actual_envelope.to\n    actual_msg.sender = actual_envelope.sender\n    expected_msg = msg\n    assert expected_msg == actual_msg\n\n\ndef test_unregister_service_serialization():\n    \"\"\"Test the serialization for 'unregister_service' speech-act works.\"\"\"\n    msg = OefSearchMessage(\n        message_id=2,\n        target=1,\n        performative=OefSearchMessage.Performative.UNREGISTER_SERVICE,\n        service_description=Description({\"foo1\": 1, \"bar1\": 2}),\n    )\n    msg.to = \"receiver\"\n    envelope = Envelope(\n        to=msg.to,\n        sender=\"sender\",\n        message=msg,\n    )\n    envelope_bytes = envelope.encode()\n\n    actual_envelope = Envelope.decode(envelope_bytes)\n    expected_envelope = envelope\n    assert expected_envelope.to == actual_envelope.to\n    assert expected_envelope.sender == actual_envelope.sender\n    assert (\n        expected_envelope.protocol_specification_id\n        == actual_envelope.protocol_specification_id\n    )\n    assert expected_envelope.message != actual_envelope.message\n\n    actual_msg = OefSearchMessage.serializer.decode(actual_envelope.message)\n    actual_msg.to = actual_envelope.to\n    actual_msg.sender = actual_envelope.sender\n    expected_msg = msg\n    assert expected_msg == actual_msg\n\n\ndef test_search_services_serialization():\n    \"\"\"Test the serialization for 'search_services' speech-act works.\"\"\"\n    msg = OefSearchMessage(\n        performative=OefSearchMessage.Performative.SEARCH_SERVICES,\n        query=Query([Constraint(\"something\", ConstraintType(\">\", 1))]),\n    )\n    msg.to = \"receiver\"\n    envelope = Envelope(\n        to=msg.to,\n        sender=\"sender\",\n        message=msg,\n    )\n    envelope_bytes = envelope.encode()\n\n    actual_envelope = Envelope.decode(envelope_bytes)\n    expected_envelope = envelope\n    assert expected_envelope.to == actual_envelope.to\n    assert expected_envelope.sender == actual_envelope.sender\n    assert (\n        expected_envelope.protocol_specification_id\n        == actual_envelope.protocol_specification_id\n    )\n    assert expected_envelope.message != actual_envelope.message\n\n    actual_msg = OefSearchMessage.serializer.decode(actual_envelope.message)\n    actual_msg.to = actual_envelope.to\n    actual_msg.sender = actual_envelope.sender\n    expected_msg = msg\n    assert expected_msg == actual_msg\n\n\ndef test_search_result_serialization():\n    \"\"\"Test the serialization for 'search_result' speech-act works.\"\"\"\n    msg = OefSearchMessage(\n        performative=OefSearchMessage.Performative.SEARCH_RESULT,\n        agents=(\"agent_1\", \"agent_2\", \"agent_3\"),\n        agents_info=OefSearchMessage.AgentsInfo(\n            {\n                \"key_1\": {\"key_1\": b\"value_1\", \"key_2\": b\"value_2\"},\n                \"key_2\": {\"key_3\": b\"value_3\", \"key_4\": b\"value_4\"},\n            }\n        ),\n    )\n    msg.to = \"receiver\"\n    envelope = Envelope(\n        to=msg.to,\n        sender=\"sender\",\n        message=msg,\n    )\n    envelope_bytes = envelope.encode()\n\n    actual_envelope = Envelope.decode(envelope_bytes)\n    expected_envelope = envelope\n    assert expected_envelope.to == actual_envelope.to\n    assert expected_envelope.sender == actual_envelope.sender\n    assert (\n        expected_envelope.protocol_specification_id\n        == actual_envelope.protocol_specification_id\n    )\n    assert expected_envelope.message != actual_envelope.message\n\n    actual_msg = OefSearchMessage.serializer.decode(actual_envelope.message)\n    actual_msg.to = actual_envelope.to\n    actual_msg.sender = actual_envelope.sender\n    expected_msg = msg\n    assert expected_msg == actual_msg\n\n\ndef test_success_serialization():\n    \"\"\"Test the serialization for 'success' speech-act works.\"\"\"\n    msg = OefSearchMessage(\n        performative=OefSearchMessage.Performative.SUCCESS,\n        agents_info=OefSearchMessage.AgentsInfo(\n            {\n                \"key_1\": {\"key_1\": b\"value_1\", \"key_2\": b\"value_2\"},\n                \"key_2\": {\"key_3\": b\"value_3\", \"key_4\": b\"value_4\"},\n            }\n        ),\n    )\n    msg.to = \"receiver\"\n    envelope = Envelope(\n        to=msg.to,\n        sender=\"sender\",\n        message=msg,\n    )\n    envelope_bytes = envelope.encode()\n\n    actual_envelope = Envelope.decode(envelope_bytes)\n    expected_envelope = envelope\n    assert expected_envelope.to == actual_envelope.to\n    assert expected_envelope.sender == actual_envelope.sender\n    assert (\n        expected_envelope.protocol_specification_id\n        == actual_envelope.protocol_specification_id\n    )\n    assert expected_envelope.message != actual_envelope.message\n\n    actual_msg = OefSearchMessage.serializer.decode(actual_envelope.message)\n    actual_msg.to = actual_envelope.to\n    actual_msg.sender = actual_envelope.sender\n    expected_msg = msg\n    assert expected_msg == actual_msg\n\n\ndef test_oef_error_serialization():\n    \"\"\"Test the serialization for 'oef_error' speech-act works.\"\"\"\n    msg = OefSearchMessage(\n        performative=OefSearchMessage.Performative.OEF_ERROR,\n        oef_error_operation=OefSearchMessage.OefErrorOperation.OTHER,\n    )\n    msg.to = \"receiver\"\n    envelope = Envelope(\n        to=msg.to,\n        sender=\"sender\",\n        message=msg,\n    )\n    envelope_bytes = envelope.encode()\n\n    actual_envelope = Envelope.decode(envelope_bytes)\n    expected_envelope = envelope\n    assert expected_envelope.to == actual_envelope.to\n    assert expected_envelope.sender == actual_envelope.sender\n    assert (\n        expected_envelope.protocol_specification_id\n        == actual_envelope.protocol_specification_id\n    )\n    assert expected_envelope.message != actual_envelope.message\n\n    actual_msg = OefSearchMessage.serializer.decode(actual_envelope.message)\n    actual_msg.to = actual_envelope.to\n    actual_msg.sender = actual_envelope.sender\n    expected_msg = msg\n    assert expected_msg == actual_msg\n\n\ndef test_oef_type_string_value():\n    \"\"\"Test the string value of the type.\"\"\"\n    assert (\n        str(OefSearchMessage.Performative.REGISTER_SERVICE) == \"register_service\"\n    ), \"The str value must be register_service\"\n    assert (\n        str(OefSearchMessage.Performative.UNREGISTER_SERVICE) == \"unregister_service\"\n    ), \"The str value must be unregister_service\"\n    assert (\n        str(OefSearchMessage.Performative.SEARCH_SERVICES) == \"search_services\"\n    ), \"The str value must be search_services\"\n    assert (\n        str(OefSearchMessage.Performative.OEF_ERROR) == \"oef_error\"\n    ), \"The str value must be oef_error\"\n    assert (\n        str(OefSearchMessage.Performative.SEARCH_RESULT) == \"search_result\"\n    ), \"The str value must be search_result\"\n\n\ndef test_oef_error_operation():\n    \"\"\"Test the string value of the error operation.\"\"\"\n    assert (\n        str(OefSearchMessage.OefErrorOperation.REGISTER_SERVICE) == \"0\"\n    ), \"The str value must be 0\"\n    assert (\n        str(OefSearchMessage.OefErrorOperation.UNREGISTER_SERVICE) == \"1\"\n    ), \"The str value must be 1\"\n    assert (\n        str(OefSearchMessage.OefErrorOperation.SEARCH_SERVICES) == \"2\"\n    ), \"The str value must be 2\"\n    assert (\n        str(OefSearchMessage.OefErrorOperation.SEND_MESSAGE) == \"3\"\n    ), \"The str value must be 3\"\n    assert (\n        str(OefSearchMessage.OefErrorOperation.OTHER) == \"10000\"\n    ), \"The str value must be 10000\"\n\n\ndef test_encoding_unknown_performative():\n    \"\"\"Test that we raise an exception when the performative is unknown during encoding.\"\"\"\n    msg = OefSearchMessage(\n        performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n        service_description=Description({\"foo1\": 1, \"bar1\": 2}),\n    )\n\n    with pytest.raises(ValueError, match=\"Performative not valid:\"):\n        with mock.patch.object(\n            OefSearchMessage.Performative, \"__eq__\", return_value=False\n        ):\n            OefSearchMessage.serializer.encode(msg)\n\n\ndef test_decoding_unknown_performative():\n    \"\"\"Test that we raise an exception when the performative is unknown during decoding.\"\"\"\n    msg = OefSearchMessage(\n        performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n        service_description=Description({\"foo1\": 1, \"bar1\": 2}),\n    )\n\n    encoded_msg = OefSearchMessage.serializer.encode(msg)\n    with pytest.raises(ValueError, match=\"Performative not valid:\"):\n        with mock.patch.object(\n            OefSearchMessage.Performative, \"__eq__\", return_value=False\n        ):\n            OefSearchMessage.serializer.decode(encoded_msg)\n\n\n@mock.patch.object(\n    packages.fetchai.protocols.oef_search.message,\n    \"enforce\",\n    side_effect=AEAEnforceError(\"some error\"),\n)\ndef test_incorrect_message(mocked_enforce):\n    \"\"\"Test that we raise an exception when the fipa message is incorrect.\"\"\"\n    with mock.patch.object(oef_search_message_logger, \"error\") as mock_logger:\n        OefSearchMessage(\n            performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n            service_description=Description({\"foo1\": 1, \"bar1\": 2}),\n        )\n\n        mock_logger.assert_any_call(\"some error\")\n\n\ndef test_agent_info():\n    \"\"\"Test the agent_info custom type.\"\"\"\n    agents_info = OefSearchMessage.AgentsInfo(\n        {\n            \"agent_address_1\": {\"key_1\": b\"value_1\", \"key_2\": b\"value_2\"},\n            \"agent_address_2\": {\"key_3\": b\"value_3\", \"key_4\": b\"value_4\"},\n        }\n    )\n    assert agents_info.get_info_for_agent(\"agent_address_1\") == {\n        \"key_1\": b\"value_1\",\n        \"key_2\": b\"value_2\",\n    }\n\n    with pytest.raises(ValueError, match=\"body must not be None\"):\n        OefSearchMessage.AgentsInfo(None)\n\n\nclass TestDialogues:\n    \"\"\"Tests oef_search dialogues.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set up the test.\"\"\"\n        cls.agent_addr = \"agent address\"\n        cls.oef_node_addr = \"oef_node address\"\n        cls.agent_dialogues = BuyerDialogues(cls.agent_addr)\n        cls.oef_node_dialogues = OEFNodeDialogues(cls.oef_node_addr)\n\n    def test_create_self_initiated(self):\n        \"\"\"Test the self initialisation of a dialogue.\"\"\"\n        result = self.agent_dialogues._create_self_initiated(\n            dialogue_opponent_addr=self.oef_node_addr,\n            dialogue_reference=(str(0), \"\"),\n            role=OefSearchDialogue.Role.AGENT,\n        )\n        assert isinstance(result, OefSearchDialogue)\n        assert result.role == OefSearchDialogue.Role.AGENT, \"The role must be agent.\"\n\n    def test_create_opponent_initiated(self):\n        \"\"\"Test the opponent initialisation of a dialogue.\"\"\"\n        result = self.agent_dialogues._create_opponent_initiated(\n            dialogue_opponent_addr=self.oef_node_addr,\n            dialogue_reference=(str(0), \"\"),\n            role=OefSearchDialogue.Role.AGENT,\n        )\n        assert isinstance(result, OefSearchDialogue)\n        assert result.role == OefSearchDialogue.Role.AGENT, \"The role must be agent.\"\n\n\nclass BuyerDialogue(OefSearchDialogue):\n    \"\"\"The dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    def __init__(\n        self,\n        dialogue_label: DialogueLabel,\n        self_address: Address,\n        role: BaseDialogue.Role,\n        message_class: Type[OefSearchMessage],\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n\n        :return: None\n        \"\"\"\n        OefSearchDialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            self_address=self_address,\n            role=role,\n            message_class=message_class,\n        )\n\n\nclass BuyerDialogues(OefSearchDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, self_address: Address) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :return: None\n        \"\"\"\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return OefSearchDialogue.Role.AGENT\n\n        OefSearchDialogues.__init__(\n            self,\n            self_address=self_address,\n            role_from_first_message=role_from_first_message,\n            dialogue_class=BuyerDialogue,\n        )\n\n\nclass OEFNodeDialogue(OefSearchDialogue):\n    \"\"\"The dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    def __init__(\n        self,\n        dialogue_label: DialogueLabel,\n        self_address: Address,\n        role: BaseDialogue.Role,\n        message_class: Type[OefSearchMessage],\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n\n        :return: None\n        \"\"\"\n        OefSearchDialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            self_address=self_address,\n            role=role,\n            message_class=message_class,\n        )\n\n\nclass OEFNodeDialogues(OefSearchDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, self_address: Address) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :return: None\n        \"\"\"\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return OefSearchDialogue.Role.OEF_NODE\n\n        OefSearchDialogues.__init__(\n            self,\n            self_address=self_address,\n            role_from_first_message=role_from_first_message,\n            dialogue_class=OEFNodeDialogue,\n        )\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_protocols/test_register.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains tests for the register protocol.\"\"\"\nfrom typing import Type\nfrom unittest.mock import patch\n\nimport pytest\n\nfrom aea.common import Address\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\nfrom aea.protocols.dialogue.base import DialogueLabel\n\nfrom packages.fetchai.protocols.register.dialogues import (\n    RegisterDialogue as BaseRegisterDialogue,\n)\nfrom packages.fetchai.protocols.register.dialogues import (\n    RegisterDialogues as BaseRegisterDialogues,\n)\nfrom packages.fetchai.protocols.register.message import RegisterMessage\n\n\nclass TestRegisterMessage:\n    \"\"\"Test the register message module.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Setup class for test case.\"\"\"\n        cls.info = {\"a\": \"b\", \"c\": \"d\"}\n\n    def test_register(self):\n        \"\"\"Test for an error for a register message.\"\"\"\n        tx_msg = RegisterMessage(\n            performative=RegisterMessage.Performative.REGISTER, info=self.info\n        )\n        assert tx_msg._is_consistent()\n        encoded_tx_msg = tx_msg.encode()\n        decoded_tx_msg = tx_msg.serializer.decode(encoded_tx_msg)\n        assert tx_msg == decoded_tx_msg\n\n    def test_success(self):\n        \"\"\"Test for an error for a success message.\"\"\"\n        tx_msg = RegisterMessage(\n            performative=RegisterMessage.Performative.SUCCESS,\n            info=self.info,\n            target=1,\n            message_id=2,\n        )\n        assert tx_msg._is_consistent()\n        encoded_tx_msg = tx_msg.encode()\n        decoded_tx_msg = tx_msg.serializer.decode(encoded_tx_msg)\n        assert tx_msg == decoded_tx_msg\n\n    def test_error(self):\n        \"\"\"Test for an error for a register error message.\"\"\"\n        some_error_code = 1\n        some_error_msg = \"Some error message\"\n        tx_msg = RegisterMessage(\n            performative=RegisterMessage.Performative.ERROR,\n            error_code=some_error_code,\n            error_msg=some_error_msg,\n            info=self.info,\n        )\n        assert tx_msg._is_consistent()\n        encoded_tx_msg = tx_msg.encode()\n        decoded_tx_msg = tx_msg.serializer.decode(encoded_tx_msg)\n        assert tx_msg == decoded_tx_msg\n\n\ndef test_consistency_check_negative():\n    \"\"\"Test the consistency check, negative case.\"\"\"\n    tx_msg = RegisterMessage(\n        performative=RegisterMessage.Performative.REGISTER,\n    )\n    assert not tx_msg._is_consistent()\n\n\ndef test_serialization_negative():\n    \"\"\"Test serialization when performative is not recognized.\"\"\"\n    tx_msg = RegisterMessage(\n        performative=RegisterMessage.Performative.REGISTER,\n        info={},\n    )\n\n    with patch.object(RegisterMessage.Performative, \"__eq__\", return_value=False):\n        with pytest.raises(\n            ValueError, match=f\"Performative not valid: {tx_msg.performative}\"\n        ):\n            tx_msg.serializer.encode(tx_msg)\n\n    encoded_tx_bytes = tx_msg.serializer.encode(tx_msg)\n    with patch.object(RegisterMessage.Performative, \"__eq__\", return_value=False):\n        with pytest.raises(\n            ValueError, match=f\"Performative not valid: {tx_msg.performative}\"\n        ):\n            tx_msg.serializer.decode(encoded_tx_bytes)\n\n\ndef test_dialogues():\n    \"\"\"Test instantiation of dialogues.\"\"\"\n    register_dialogues = RegisterDialogues(\"agent_addr\")\n    msg, dialogue = register_dialogues.create(\n        counterparty=\"abc\", performative=RegisterMessage.Performative.REGISTER, info={}\n    )\n    assert dialogue is not None\n\n\nclass RegisterDialogue(BaseRegisterDialogue):\n    \"\"\"The dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    def __init__(\n        self,\n        dialogue_label: DialogueLabel,\n        self_address: Address,\n        role: BaseDialogue.Role,\n        message_class: Type[RegisterMessage],\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n\n        :return: None\n        \"\"\"\n        BaseRegisterDialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            self_address=self_address,\n            role=role,\n            message_class=message_class,\n        )\n\n\nclass RegisterDialogues(BaseRegisterDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, self_address: Address) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :return: None\n        \"\"\"\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return RegisterDialogue.Role.AGENT\n\n        BaseRegisterDialogues.__init__(\n            self,\n            self_address=self_address,\n            role_from_first_message=role_from_first_message,\n            dialogue_class=RegisterDialogue,\n        )\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_protocols/test_signing.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains tests for transaction.\"\"\"\nfrom typing import Type\nfrom unittest.mock import patch\n\nimport pytest\nfrom aea_ledger_cosmos import CosmosCrypto\n\nfrom aea.common import Address\nfrom aea.helpers.transaction.base import (\n    RawMessage,\n    RawTransaction,\n    SignedMessage,\n    SignedTransaction,\n    Terms,\n)\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\nfrom aea.protocols.dialogue.base import DialogueLabel\n\nfrom packages.fetchai.protocols.signing.dialogues import (\n    SigningDialogue as BaseSigningDialogue,\n)\nfrom packages.fetchai.protocols.signing.dialogues import (\n    SigningDialogues as BaseSigningDialogues,\n)\nfrom packages.fetchai.protocols.signing.message import SigningMessage\n\n\nclass TestSigningMessage:\n    \"\"\"Test the signing message module.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Setup class for test case.\"\"\"\n        cls.ledger_id = CosmosCrypto.identifier\n        cls.terms = Terms(\n            ledger_id=cls.ledger_id,\n            sender_address=\"address1\",\n            counterparty_address=\"address2\",\n            amount_by_currency_id={\"FET\": -2},\n            quantities_by_good_id={\"good_id\": 10},\n            is_sender_payable_tx_fee=True,\n            nonce=\"transaction nonce\",\n        )\n\n    def test_sign_transaction(self):\n        \"\"\"Test for an error for a sign transaction message.\"\"\"\n        tx_msg = SigningMessage(\n            performative=SigningMessage.Performative.SIGN_TRANSACTION,\n            terms=self.terms,\n            raw_transaction=RawTransaction(self.ledger_id, {\"tx\": \"transaction\"}),\n        )\n        assert tx_msg._is_consistent()\n        encoded_tx_msg = tx_msg.encode()\n        decoded_tx_msg = tx_msg.serializer.decode(encoded_tx_msg)\n        assert tx_msg == decoded_tx_msg\n\n    def test_sign_message(self):\n        \"\"\"Test for an error for a sign transaction message.\"\"\"\n        tx_msg = SigningMessage(\n            performative=SigningMessage.Performative.SIGN_MESSAGE,\n            terms=self.terms,\n            raw_message=RawMessage(self.ledger_id, b\"message\"),\n        )\n        assert tx_msg._is_consistent()\n        encoded_tx_msg = tx_msg.encode()\n        decoded_tx_msg = tx_msg.serializer.decode(encoded_tx_msg)\n        assert tx_msg == decoded_tx_msg\n\n    def test_signed_transaction(self):\n        \"\"\"Test for an error for a signed transaction.\"\"\"\n        tx_msg = SigningMessage(\n            performative=SigningMessage.Performative.SIGNED_TRANSACTION,\n            message_id=2,\n            target=1,\n            signed_transaction=SignedTransaction(self.ledger_id, {\"sig\": \"signature\"}),\n        )\n        assert tx_msg._is_consistent()\n        encoded_tx_msg = tx_msg.encode()\n        decoded_tx_msg = tx_msg.serializer.decode(encoded_tx_msg)\n        assert tx_msg == decoded_tx_msg\n\n    def test_signed_message(self):\n        \"\"\"Test for an error for a signed message.\"\"\"\n        tx_msg = SigningMessage(\n            performative=SigningMessage.Performative.SIGNED_MESSAGE,\n            message_id=2,\n            target=1,\n            signed_message=SignedMessage(self.ledger_id, \"message\"),\n        )\n        assert tx_msg._is_consistent()\n        encoded_tx_msg = tx_msg.encode()\n        decoded_tx_msg = tx_msg.serializer.decode(encoded_tx_msg)\n        assert tx_msg == decoded_tx_msg\n\n    def test_error_message(self):\n        \"\"\"Test for an error for an error message.\"\"\"\n        tx_msg = SigningMessage(\n            performative=SigningMessage.Performative.ERROR,\n            message_id=2,\n            target=1,\n            error_code=SigningMessage.ErrorCode.UNSUCCESSFUL_MESSAGE_SIGNING,\n        )\n        assert tx_msg._is_consistent()\n        encoded_tx_msg = tx_msg.encode()\n        decoded_tx_msg = tx_msg.serializer.decode(encoded_tx_msg)\n        assert tx_msg == decoded_tx_msg\n        assert str(tx_msg.performative) == \"error\"\n        assert len(tx_msg.valid_performatives) == 5\n\n\ndef test_consistency_check_negative():\n    \"\"\"Test the consistency check, negative case.\"\"\"\n    tx_msg = SigningMessage(\n        performative=SigningMessage.Performative.SIGN_TRANSACTION,\n    )\n    assert not tx_msg._is_consistent()\n\n\ndef test_serialization_negative():\n    \"\"\"Test serialization when performative is not recognized.\"\"\"\n    tx_msg = SigningMessage(\n        performative=SigningMessage.Performative.ERROR,\n        message_id=2,\n        target=1,\n        error_code=SigningMessage.ErrorCode.UNSUCCESSFUL_MESSAGE_SIGNING,\n    )\n\n    with patch.object(SigningMessage.Performative, \"__eq__\", return_value=False):\n        with pytest.raises(\n            ValueError, match=f\"Performative not valid: {tx_msg.performative}\"\n        ):\n            tx_msg.serializer.encode(tx_msg)\n\n    encoded_tx_bytes = tx_msg.serializer.encode(tx_msg)\n    with patch.object(SigningMessage.Performative, \"__eq__\", return_value=False):\n        with pytest.raises(\n            ValueError, match=f\"Performative not valid: {tx_msg.performative}\"\n        ):\n            tx_msg.serializer.decode(encoded_tx_bytes)\n\n\ndef test_dialogues():\n    \"\"\"Test intiaontiation of dialogues.\"\"\"\n    signing_dialogues = SigningDialogues(\"agent_addr\")\n    msg, dialogue = signing_dialogues.create(\n        counterparty=\"abc\",\n        performative=SigningMessage.Performative.SIGN_TRANSACTION,\n        terms=Terms(\n            ledger_id=\"ledger_id\",\n            sender_address=\"address1\",\n            counterparty_address=\"address2\",\n            amount_by_currency_id={\"FET\": -2},\n            quantities_by_good_id={\"good_id\": 10},\n            is_sender_payable_tx_fee=True,\n            nonce=\"transaction nonce\",\n        ),\n        raw_transaction=RawTransaction(\"ledger_id\", {\"tx\": \"transaction\"}),\n    )\n    assert dialogue is not None\n\n\nclass SigningDialogue(BaseSigningDialogue):\n    \"\"\"The dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    def __init__(\n        self,\n        dialogue_label: DialogueLabel,\n        self_address: Address,\n        role: BaseDialogue.Role,\n        message_class: Type[SigningMessage],\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n\n        :return: None\n        \"\"\"\n        BaseSigningDialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            self_address=self_address,\n            role=role,\n            message_class=message_class,\n        )\n\n\nclass SigningDialogues(BaseSigningDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, self_address: Address) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :return: None\n        \"\"\"\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return SigningDialogue.Role.SKILL\n\n        BaseSigningDialogues.__init__(\n            self,\n            self_address=self_address,\n            role_from_first_message=role_from_first_message,\n            dialogue_class=SigningDialogue,\n        )\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_protocols/test_state_update.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains tests for transaction.\"\"\"\nfrom typing import Type\nfrom unittest.mock import patch\n\nimport pytest\n\nfrom aea.common import Address\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\nfrom aea.protocols.dialogue.base import DialogueLabel\n\nfrom packages.fetchai.protocols.state_update.dialogues import (\n    StateUpdateDialogue as BaseStateUpdateDialogue,\n)\nfrom packages.fetchai.protocols.state_update.dialogues import (\n    StateUpdateDialogues as BaseStateUpdateDialogues,\n)\nfrom packages.fetchai.protocols.state_update.message import StateUpdateMessage\n\n\nclass TestStateUpdateMessage:\n    \"\"\"Test the StateUpdateMessage.\"\"\"\n\n    def test_message_consistency(self):\n        \"\"\"Test for an error in consistency of a message.\"\"\"\n        currency_endowment = {\"FET\": 100}\n        good_endowment = {\"a_good\": 2}\n        exchange_params = {\"FET\": 10.0}\n        utility_params = {\"a_good\": 20.0}\n        assert StateUpdateMessage(\n            performative=StateUpdateMessage.Performative.INITIALIZE,\n            amount_by_currency_id=currency_endowment,\n            quantities_by_good_id=good_endowment,\n            exchange_params_by_currency_id=exchange_params,\n            utility_params_by_good_id=utility_params,\n        )\n        currency_change = {\"FET\": 10}\n        good_change = {\"a_good\": 1}\n        stum = StateUpdateMessage(\n            performative=StateUpdateMessage.Performative.APPLY,\n            amount_by_currency_id=currency_change,\n            quantities_by_good_id=good_change,\n        )\n        assert stum._is_consistent()\n        assert len(stum.valid_performatives) == 3\n        stum = StateUpdateMessage(\n            performative=StateUpdateMessage.Performative.END,\n        )\n        assert stum._is_consistent()\n\n    def test_message_inconsistency(self):\n        \"\"\"Test for an error in consistency of a message.\"\"\"\n        currency_endowment = {\"FET\": 100}\n        good_endowment = {\"a_good\": 2}\n        exchange_params = {\"UNKNOWN\": 10.0}\n        utility_params = {\"a_good\": 20.0}\n        with pytest.raises(ValueError, match=\"Field .* is not supported\"):\n            StateUpdateMessage(\n                performative=StateUpdateMessage.Performative.INITIALIZE,\n                amount_by_currency_id=currency_endowment,\n                quantities_by_good_id=good_endowment,\n                exchange_params_by_currency_id=exchange_params,\n                utility_params_by_good_id=utility_params,\n                non_exists_field=\"some value\",\n            )\n\n\nclass TestSerialization:\n    \"\"\"Test state update message serialization.\"\"\"\n\n    def test_serialization_initialize(self):\n        \"\"\"Test serialization of initialize message.\"\"\"\n        currency_endowment = {\"FET\": 100}\n        good_endowment = {\"a_good\": 2}\n        exchange_params = {\"FET\": 10.0}\n        utility_params = {\"a_good\": 20.0}\n        msg = StateUpdateMessage(\n            performative=StateUpdateMessage.Performative.INITIALIZE,\n            amount_by_currency_id=currency_endowment,\n            quantities_by_good_id=good_endowment,\n            exchange_params_by_currency_id=exchange_params,\n            utility_params_by_good_id=utility_params,\n        )\n        encoded_msg = msg.serializer.encode(msg)\n        decoded_msg = msg.serializer.decode(encoded_msg)\n        assert msg == decoded_msg\n\n    def test_serialization_apply(self):\n        \"\"\"Test serialization of apply message.\"\"\"\n        currency_change = {\"FET\": 10}\n        good_change = {\"a_good\": 1}\n        msg = StateUpdateMessage(\n            performative=StateUpdateMessage.Performative.APPLY,\n            amount_by_currency_id=currency_change,\n            quantities_by_good_id=good_change,\n        )\n        assert msg._is_consistent()\n        assert len(msg.valid_performatives) == 3\n        encoded_msg = msg.serializer.encode(msg)\n        decoded_msg = msg.serializer.decode(encoded_msg)\n        assert msg == decoded_msg\n\n    def test_serialization_end(self):\n        \"\"\"Test serialization of end message.\"\"\"\n        msg = StateUpdateMessage(\n            performative=StateUpdateMessage.Performative.END,\n        )\n        assert msg._is_consistent()\n        assert len(msg.valid_performatives) == 3\n        encoded_msg = msg.serializer.encode(msg)\n        decoded_msg = msg.serializer.decode(encoded_msg)\n        assert msg == decoded_msg\n\n\ndef test_serialization_negative():\n    \"\"\"Test serialization when performative is not recognized.\"\"\"\n    currency_change = {\"FET\": 10}\n    good_change = {\"a_good\": 1}\n    msg = StateUpdateMessage(\n        performative=StateUpdateMessage.Performative.APPLY,\n        amount_by_currency_id=currency_change,\n        quantities_by_good_id=good_change,\n    )\n\n    with patch.object(StateUpdateMessage.Performative, \"__eq__\", return_value=False):\n        with pytest.raises(\n            ValueError, match=f\"Performative not valid: {msg.performative}\"\n        ):\n            msg.serializer.encode(msg)\n\n    encoded_tx_bytes = msg.serializer.encode(msg)\n    with patch.object(StateUpdateMessage.Performative, \"__eq__\", return_value=False):\n        with pytest.raises(\n            ValueError, match=f\"Performative not valid: {msg.performative}\"\n        ):\n            msg.serializer.decode(encoded_tx_bytes)\n\n\ndef test_performative_str():\n    \"\"\"Test performative __str__.\"\"\"\n    assert str(StateUpdateMessage.Performative.INITIALIZE) == \"initialize\"\n    assert str(StateUpdateMessage.Performative.APPLY) == \"apply\"\n\n\ndef test_dialogues():\n    \"\"\"Test intiaontiation of dialogues.\"\"\"\n    state_update_dialogues = StateUpdateDialogues(\"agent_addr\")\n    msg, dialogue = state_update_dialogues.create(\n        counterparty=\"abc\",\n        performative=StateUpdateMessage.Performative.INITIALIZE,\n        amount_by_currency_id={},\n        quantities_by_good_id={},\n        exchange_params_by_currency_id={},\n        utility_params_by_good_id={},\n    )\n    assert dialogue is not None\n\n\nclass StateUpdateDialogue(BaseStateUpdateDialogue):\n    \"\"\"The dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    def __init__(\n        self,\n        dialogue_label: DialogueLabel,\n        self_address: Address,\n        role: BaseDialogue.Role,\n        message_class: Type[StateUpdateMessage],\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n\n        :return: None\n        \"\"\"\n        BaseStateUpdateDialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            self_address=self_address,\n            role=role,\n            message_class=message_class,\n        )\n\n\nclass StateUpdateDialogues(BaseStateUpdateDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, self_address: Address) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :return: None\n        \"\"\"\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return StateUpdateDialogue.Role.SKILL\n\n        BaseStateUpdateDialogues.__init__(\n            self,\n            self_address=self_address,\n            role_from_first_message=role_from_first_message,\n            dialogue_class=StateUpdateDialogue,\n        )\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_protocols/test_tac.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"This module contains the tests of the http protocol package.\"\"\"\n\nimport sys\nfrom typing import Type\nfrom unittest import mock\n\nimport pytest\n\nfrom aea.common import Address\nfrom aea.exceptions import AEAEnforceError\nfrom aea.mail.base import Envelope\nfrom aea.protocols.base import Message\nfrom aea.protocols.dialogue.base import Dialogue as BaseDialogue\nfrom aea.protocols.dialogue.base import DialogueLabel\n\nimport packages\nfrom packages.fetchai.protocols.tac.dialogues import TacDialogue, TacDialogues\nfrom packages.fetchai.protocols.tac.message import TacMessage\nfrom packages.fetchai.protocols.tac.message import _default_logger as tac_message_logger\n\nfrom tests.conftest import ROOT_DIR\n\n\nsys.path.append(ROOT_DIR)\n\n\ndef test_tac_message_instantiation():\n    \"\"\"Test instantiation of the tac message.\"\"\"\n    assert TacMessage(\n        performative=TacMessage.Performative.REGISTER, agent_name=\"some_name\"\n    )\n    assert TacMessage(performative=TacMessage.Performative.UNREGISTER)\n    assert TacMessage(\n        performative=TacMessage.Performative.TRANSACTION,\n        transaction_id=\"some_id\",\n        ledger_id=\"some_ledger\",\n        sender_address=\"some_address\",\n        counterparty_address=\"some_other_address\",\n        amount_by_currency_id={\"FET\": 10},\n        fee_by_currency_id={\"FET\": 1},\n        quantities_by_good_id={\"123\": 0, \"1234\": 10},\n        nonce=1,\n        sender_signature=\"some_signature\",\n        counterparty_signature=\"some_other_signature\",\n    )\n    assert TacMessage(performative=TacMessage.Performative.CANCELLED)\n    assert TacMessage(\n        performative=TacMessage.Performative.GAME_DATA,\n        amount_by_currency_id={\"FET\": 10},\n        exchange_params_by_currency_id={\"FET\": 10.0},\n        quantities_by_good_id={\"123\": 20, \"1234\": 15},\n        utility_params_by_good_id={\"123\": 30.0, \"1234\": 50.0},\n        fee_by_currency_id={\"FET\": 1},\n        agent_addr_to_name={\"agent_1\": \"Agent one\", \"agent_2\": \"Agent two\"},\n        currency_id_to_name={\"FET\": \"currency_name\"},\n        good_id_to_name={\"123\": \"First good\", \"1234\": \"Second good\"},\n        version_id=\"game_version_1\",\n    )\n    assert TacMessage(\n        performative=TacMessage.Performative.TRANSACTION_CONFIRMATION,\n        transaction_id=\"some_id\",\n        amount_by_currency_id={\"FET\": 10},\n        quantities_by_good_id={\"123\": 20, \"1234\": 15},\n    )\n    assert TacMessage(\n        performative=TacMessage.Performative.TAC_ERROR,\n        error_code=TacMessage.ErrorCode.GENERIC_ERROR,\n        info={\"msg\": \"This is info msg.\"},\n    )\n    assert str(TacMessage.Performative.REGISTER) == \"register\"\n\n\ndef test_register_serialization():\n    \"\"\"Test the serialization for 'register' speech-act works.\"\"\"\n    msg = TacMessage(\n        performative=TacMessage.Performative.REGISTER,\n        agent_name=\"some_agent_name\",\n    )\n    msg.to = \"receiver\"\n    envelope = Envelope(\n        to=msg.to,\n        sender=\"sender\",\n        message=msg,\n    )\n    envelope_bytes = envelope.encode()\n\n    actual_envelope = Envelope.decode(envelope_bytes)\n    expected_envelope = envelope\n    assert expected_envelope.to == actual_envelope.to\n    assert expected_envelope.sender == actual_envelope.sender\n    assert (\n        expected_envelope.protocol_specification_id\n        == actual_envelope.protocol_specification_id\n    )\n    assert expected_envelope.message != actual_envelope.message\n\n    actual_msg = TacMessage.serializer.decode(actual_envelope.message)\n    actual_msg.to = actual_envelope.to\n    actual_msg.sender = actual_envelope.sender\n    expected_msg = msg\n    assert expected_msg == actual_msg\n\n\ndef test_unregister_serialization():\n    \"\"\"Test the serialization for 'unregister' speech-act works.\"\"\"\n    msg = TacMessage(\n        message_id=2,\n        target=1,\n        performative=TacMessage.Performative.UNREGISTER,\n    )\n    msg.to = \"receiver\"\n    envelope = Envelope(\n        to=msg.to,\n        sender=\"sender\",\n        message=msg,\n    )\n    envelope_bytes = envelope.encode()\n\n    actual_envelope = Envelope.decode(envelope_bytes)\n    expected_envelope = envelope\n    assert expected_envelope.to == actual_envelope.to\n    assert expected_envelope.sender == actual_envelope.sender\n    assert (\n        expected_envelope.protocol_specification_id\n        == actual_envelope.protocol_specification_id\n    )\n    assert expected_envelope.message != actual_envelope.message\n\n    actual_msg = TacMessage.serializer.decode(actual_envelope.message)\n    actual_msg.to = actual_envelope.to\n    actual_msg.sender = actual_envelope.sender\n    expected_msg = msg\n    assert expected_msg == actual_msg\n\n\ndef test_transaction_serialization():\n    \"\"\"Test the serialization for 'transaction' speech-act works.\"\"\"\n    msg = TacMessage(\n        performative=TacMessage.Performative.TRANSACTION,\n        transaction_id=\"some_transaction_id\",\n        ledger_id=\"some_ledger_id\",\n        sender_address=\"some_sender_address\",\n        counterparty_address=\"some_counterparty_address\",\n        amount_by_currency_id={\"key_1\": 1, \"key_2\": 2},\n        fee_by_currency_id={\"key_1\": 1, \"key_2\": 2},\n        quantities_by_good_id={\"key_1\": 1, \"key_2\": 2},\n        nonce=\"some_nonce\",\n        sender_signature=\"some_sender_signature\",\n        counterparty_signature=\"some_counterparty_signature\",\n    )\n    msg.to = \"receiver\"\n    envelope = Envelope(\n        to=msg.to,\n        sender=\"sender\",\n        message=msg,\n    )\n    envelope_bytes = envelope.encode()\n\n    actual_envelope = Envelope.decode(envelope_bytes)\n    expected_envelope = envelope\n    assert expected_envelope.to == actual_envelope.to\n    assert expected_envelope.sender == actual_envelope.sender\n    assert (\n        expected_envelope.protocol_specification_id\n        == actual_envelope.protocol_specification_id\n    )\n    assert expected_envelope.message != actual_envelope.message\n\n    actual_msg = TacMessage.serializer.decode(actual_envelope.message)\n    actual_msg.to = actual_envelope.to\n    actual_msg.sender = actual_envelope.sender\n    expected_msg = msg\n    assert expected_msg == actual_msg\n\n\ndef test_cancelled_serialization():\n    \"\"\"Test the serialization for 'cancelled' speech-act works.\"\"\"\n    msg = TacMessage(\n        performative=TacMessage.Performative.CANCELLED,\n    )\n    msg.to = \"receiver\"\n    envelope = Envelope(\n        to=msg.to,\n        sender=\"sender\",\n        message=msg,\n    )\n    envelope_bytes = envelope.encode()\n\n    actual_envelope = Envelope.decode(envelope_bytes)\n    expected_envelope = envelope\n    assert expected_envelope.to == actual_envelope.to\n    assert expected_envelope.sender == actual_envelope.sender\n    assert (\n        expected_envelope.protocol_specification_id\n        == actual_envelope.protocol_specification_id\n    )\n    assert expected_envelope.message != actual_envelope.message\n\n    actual_msg = TacMessage.serializer.decode(actual_envelope.message)\n    actual_msg.to = actual_envelope.to\n    actual_msg.sender = actual_envelope.sender\n    expected_msg = msg\n    assert expected_msg == actual_msg\n\n\ndef test_game_data_serialization():\n    \"\"\"Test the serialization for 'game_data' speech-act works.\"\"\"\n    msg = TacMessage(\n        performative=TacMessage.Performative.GAME_DATA,\n        amount_by_currency_id={\"key_1\": 1, \"key_2\": 2},\n        exchange_params_by_currency_id={\"key_1\": 1.0, \"key_2\": 2.0},\n        quantities_by_good_id={\"key_1\": 1, \"key_2\": 2},\n        utility_params_by_good_id={\"key_1\": 1.0, \"key_2\": 2.0},\n        fee_by_currency_id={\"key_1\": 1, \"key_2\": 2},\n        agent_addr_to_name={\"key_1\": \"value_1\", \"key_2\": \"value_2\"},\n        currency_id_to_name={\"key_1\": \"value_1\", \"key_2\": \"value_2\"},\n        good_id_to_name={\"key_1\": \"value_1\", \"key_2\": \"value_2\"},\n        version_id=\"some_version_id\",\n        info={\"key_1\": \"value_1\", \"key_2\": \"value_2\"},\n    )\n    msg.to = \"receiver\"\n    envelope = Envelope(\n        to=msg.to,\n        sender=\"sender\",\n        message=msg,\n    )\n    envelope_bytes = envelope.encode()\n\n    actual_envelope = Envelope.decode(envelope_bytes)\n    expected_envelope = envelope\n    assert expected_envelope.to == actual_envelope.to\n    assert expected_envelope.sender == actual_envelope.sender\n    assert (\n        expected_envelope.protocol_specification_id\n        == actual_envelope.protocol_specification_id\n    )\n    assert expected_envelope.message != actual_envelope.message\n\n    actual_msg = TacMessage.serializer.decode(actual_envelope.message)\n    actual_msg.to = actual_envelope.to\n    actual_msg.sender = actual_envelope.sender\n    expected_msg = msg\n    assert expected_msg == actual_msg\n\n\ndef test_transaction_confirmation_serialization():\n    \"\"\"Test the serialization for 'transaction_confirmation' speech-act works.\"\"\"\n    msg = TacMessage(\n        performative=TacMessage.Performative.TRANSACTION_CONFIRMATION,\n        transaction_id=\"some_transaction_id\",\n        amount_by_currency_id={\"key_1\": 1, \"key_2\": 2},\n        quantities_by_good_id={\"key_1\": 1, \"key_2\": 2},\n    )\n    msg.to = \"receiver\"\n    envelope = Envelope(\n        to=msg.to,\n        sender=\"sender\",\n        message=msg,\n    )\n    envelope_bytes = envelope.encode()\n\n    actual_envelope = Envelope.decode(envelope_bytes)\n    expected_envelope = envelope\n    assert expected_envelope.to == actual_envelope.to\n    assert expected_envelope.sender == actual_envelope.sender\n    assert (\n        expected_envelope.protocol_specification_id\n        == actual_envelope.protocol_specification_id\n    )\n    assert expected_envelope.message != actual_envelope.message\n\n    actual_msg = TacMessage.serializer.decode(actual_envelope.message)\n    actual_msg.to = actual_envelope.to\n    actual_msg.sender = actual_envelope.sender\n    expected_msg = msg\n    assert expected_msg == actual_msg\n\n\ndef test_tac_error_serialization():\n    \"\"\"Test the serialization for 'tac_error' speech-act works.\"\"\"\n    msg = TacMessage(\n        performative=TacMessage.Performative.TAC_ERROR,\n        error_code=TacMessage.ErrorCode.GENERIC_ERROR,\n        info={\"key_1\": \"value_1\", \"key_2\": \"value_2\"},\n    )\n    msg.to = \"receiver\"\n    envelope = Envelope(\n        to=msg.to,\n        sender=\"sender\",\n        message=msg,\n    )\n    envelope_bytes = envelope.encode()\n\n    actual_envelope = Envelope.decode(envelope_bytes)\n    expected_envelope = envelope\n    assert expected_envelope.to == actual_envelope.to\n    assert expected_envelope.sender == actual_envelope.sender\n    assert (\n        expected_envelope.protocol_specification_id\n        == actual_envelope.protocol_specification_id\n    )\n    assert expected_envelope.message != actual_envelope.message\n\n    actual_msg = TacMessage.serializer.decode(actual_envelope.message)\n    actual_msg.to = actual_envelope.to\n    actual_msg.sender = actual_envelope.sender\n    expected_msg = msg\n    assert expected_msg == actual_msg\n\n\ndef test_oef_type_string_value():\n    \"\"\"Test the string value of the type.\"\"\"\n    assert (\n        str(TacMessage.Performative.REGISTER) == \"register\"\n    ), \"The str value must be register\"\n    assert (\n        str(TacMessage.Performative.UNREGISTER) == \"unregister\"\n    ), \"The str value must be unregister\"\n    assert (\n        str(TacMessage.Performative.TRANSACTION) == \"transaction\"\n    ), \"The str value must be transaction\"\n    assert (\n        str(TacMessage.Performative.CANCELLED) == \"cancelled\"\n    ), \"The str value must be cancelled\"\n    assert (\n        str(TacMessage.Performative.GAME_DATA) == \"game_data\"\n    ), \"The str value must be game_data\"\n    assert (\n        str(TacMessage.Performative.TRANSACTION_CONFIRMATION)\n        == \"transaction_confirmation\"\n    ), \"The str value must be transaction_confirmation\"\n    assert (\n        str(TacMessage.Performative.TAC_ERROR) == \"tac_error\"\n    ), \"The str value must be tac_error\"\n\n\ndef test_error_code_to_msg():\n    \"\"\"Test the serialization for 'tac_error' speech-act works.\"\"\"\n\n    assert (\n        str(TacMessage.ErrorCode.to_msg(0)) == \"Unexpected error.\"\n    ), 'The str value must be \"Unexpected error.\"'\n    assert (\n        str(TacMessage.ErrorCode.to_msg(1)) == \"Request not recognized\"\n    ), 'The str value must be \"Request not recognized\"'\n    assert (\n        str(TacMessage.ErrorCode.to_msg(2)) == \"Agent addr already registered.\"\n    ), 'The str value must be \"Agent addr already registered.\"'\n    assert (\n        str(TacMessage.ErrorCode.to_msg(3)) == \"Agent name already registered.\"\n    ), 'The str value must be \"Agent name already registered.\"'\n    assert (\n        str(TacMessage.ErrorCode.to_msg(4)) == \"Agent not registered.\"\n    ), 'The str value must be \"Agent not registered.\"'\n    assert (\n        str(TacMessage.ErrorCode.to_msg(5)) == \"Error in checking transaction\"\n    ), 'The str value must be \"Error in checking transaction\"'\n    assert (\n        str(TacMessage.ErrorCode.to_msg(6))\n        == \"The transaction request does not match with a previous transaction request with the same id.\"\n    ), 'The str value must be \"The transaction request does not match with a previous transaction request with the same id.\"'\n    assert (\n        str(TacMessage.ErrorCode.to_msg(7)) == \"Agent name not in whitelist.\"\n    ), 'The str value must be \"Agent name not in whitelist.\"'\n    assert (\n        str(TacMessage.ErrorCode.to_msg(8)) == \"The competition is not running yet.\"\n    ), 'The str value must be \"The competition is not running yet.\"'\n    assert (\n        str(TacMessage.ErrorCode.to_msg(9))\n        == \"The message is inconsistent with the dialogue.\"\n    ), 'The str value must be \"The message is inconsistent with the dialogue.\"'\n\n\ndef test_encoding_unknown_performative():\n    \"\"\"Test that we raise an exception when the performative is unknown during encoding.\"\"\"\n    msg = TacMessage(\n        performative=TacMessage.Performative.CANCELLED,\n    )\n\n    with pytest.raises(ValueError, match=\"Performative not valid:\"):\n        with mock.patch.object(TacMessage.Performative, \"__eq__\", return_value=False):\n            TacMessage.serializer.encode(msg)\n\n\ndef test_decoding_unknown_performative():\n    \"\"\"Test that we raise an exception when the performative is unknown during decoding.\"\"\"\n    msg = TacMessage(\n        performative=TacMessage.Performative.CANCELLED,\n    )\n\n    encoded_msg = TacMessage.serializer.encode(msg)\n    with pytest.raises(ValueError, match=\"Performative not valid:\"):\n        with mock.patch.object(TacMessage.Performative, \"__eq__\", return_value=False):\n            TacMessage.serializer.decode(encoded_msg)\n\n\n@mock.patch.object(\n    packages.fetchai.protocols.tac.message,\n    \"enforce\",\n    side_effect=AEAEnforceError(\"some error\"),\n)\ndef test_incorrect_message(mocked_enforce):\n    \"\"\"Test that we raise an exception when the message is incorrect.\"\"\"\n    with mock.patch.object(tac_message_logger, \"error\") as mock_logger:\n        TacMessage(\n            performative=TacMessage.Performative.CANCELLED,\n        )\n\n        mock_logger.assert_any_call(\"some error\")\n\n\nclass TestDialogues:\n    \"\"\"Tests tac dialogues.\"\"\"\n\n    @classmethod\n    def setup_class(cls):\n        \"\"\"Set up the test.\"\"\"\n        cls.agent_addr = \"agent address\"\n        cls.controller_addr = \"controller address\"\n        cls.agent_dialogues = AgentDialogues(cls.agent_addr)\n        cls.controller_dialogues = ControllerDialogues(cls.controller_addr)\n\n    def test_create_self_initiated(self):\n        \"\"\"Test the self initialisation of a dialogue.\"\"\"\n        result = self.agent_dialogues._create_self_initiated(\n            dialogue_opponent_addr=self.controller_addr,\n            dialogue_reference=(str(0), \"\"),\n            role=TacDialogue.Role.PARTICIPANT,\n        )\n        assert isinstance(result, TacDialogue)\n        assert (\n            result.role == TacDialogue.Role.PARTICIPANT\n        ), \"The role must be participant.\"\n\n    def test_create_opponent_initiated(self):\n        \"\"\"Test the opponent initialisation of a dialogue.\"\"\"\n        result = self.agent_dialogues._create_opponent_initiated(\n            dialogue_opponent_addr=self.controller_addr,\n            dialogue_reference=(str(0), \"\"),\n            role=TacDialogue.Role.PARTICIPANT,\n        )\n        assert isinstance(result, TacDialogue)\n        assert (\n            result.role == TacDialogue.Role.PARTICIPANT\n        ), \"The role must be participant.\"\n\n\nclass AgentDialogue(TacDialogue):\n    \"\"\"The dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    def __init__(\n        self,\n        dialogue_label: DialogueLabel,\n        self_address: Address,\n        role: BaseDialogue.Role,\n        message_class: Type[TacMessage],\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n\n        :return: None\n        \"\"\"\n        TacDialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            self_address=self_address,\n            role=role,\n            message_class=message_class,\n        )\n\n\nclass AgentDialogues(TacDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, self_address: Address) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :return: None\n        \"\"\"\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return TacDialogue.Role.PARTICIPANT\n\n        TacDialogues.__init__(\n            self,\n            self_address=self_address,\n            role_from_first_message=role_from_first_message,\n            dialogue_class=AgentDialogue,\n        )\n\n\nclass ControllerDialogue(TacDialogue):\n    \"\"\"The dialogue class maintains state of a dialogue and manages it.\"\"\"\n\n    def __init__(\n        self,\n        dialogue_label: DialogueLabel,\n        self_address: Address,\n        role: BaseDialogue.Role,\n        message_class: Type[TacMessage],\n    ) -> None:\n        \"\"\"\n        Initialize a dialogue.\n\n        :param dialogue_label: the identifier of the dialogue\n        :param self_address: the address of the entity for whom this dialogue is maintained\n        :param role: the role of the agent this dialogue is maintained for\n\n        :return: None\n        \"\"\"\n        TacDialogue.__init__(\n            self,\n            dialogue_label=dialogue_label,\n            self_address=self_address,\n            role=role,\n            message_class=message_class,\n        )\n\n\nclass ControllerDialogues(TacDialogues):\n    \"\"\"The dialogues class keeps track of all dialogues.\"\"\"\n\n    def __init__(self, self_address: Address) -> None:\n        \"\"\"\n        Initialize dialogues.\n\n        :return: None\n        \"\"\"\n\n        def role_from_first_message(  # pylint: disable=unused-argument\n            message: Message, receiver_address: Address\n        ) -> BaseDialogue.Role:\n            \"\"\"Infer the role of the agent from an incoming/outgoing first message\n\n            :param message: an incoming/outgoing first message\n            :param receiver_address: the address of the receiving agent\n            :return: The role of the agent\n            \"\"\"\n            return TacDialogue.Role.CONTROLLER\n\n        TacDialogues.__init__(\n            self,\n            self_address=self_address,\n            role_from_first_message=role_from_first_message,\n            dialogue_class=ControllerDialogue,\n        )\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_skills/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"The tests module contains the tests of the AEA package.\"\"\"\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_skills/test_echo/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"The tests module contains the tests of the packages/skills/echo dir.\"\"\"\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_skills/test_echo/test_behaviours.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the behaviour class of the echo skill.\"\"\"\n\nimport logging\nfrom pathlib import Path\nfrom typing import cast\nfrom unittest.mock import patch\n\nfrom aea.test_tools.test_skill import BaseSkillTestCase\n\nfrom packages.fetchai.skills.echo.behaviours import EchoBehaviour\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass TestEchoBehaviour(BaseSkillTestCase):\n    \"\"\"Test EchoBehaviour behaviour of echo.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"echo\")\n    is_agent_to_agent_messages = False\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.echo_behaviour = cast(\n            EchoBehaviour, cls._skill.skill_context.behaviours.echo\n        )\n        cls.logger = cls._skill.skill_context.logger\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the echo behaviour.\"\"\"\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            assert self.echo_behaviour.setup() is None\n\n        # after\n        self.assert_quantity_in_outbox(0)\n\n        mock_logger.assert_any_call(\n            logging.INFO, \"Echo Behaviour: setup method called.\"\n        )\n\n    def test_act(self):\n        \"\"\"Test the act method of the echo behaviour.\"\"\"\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            assert self.echo_behaviour.act() is None\n\n        # after\n        self.assert_quantity_in_outbox(0)\n\n        mock_logger.assert_any_call(logging.INFO, \"Echo Behaviour: act method called.\")\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the echo behaviour.\"\"\"\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            assert self.echo_behaviour.teardown() is None\n\n        # after\n        self.assert_quantity_in_outbox(0)\n\n        mock_logger.assert_any_call(\n            logging.INFO, \"Echo Behaviour: teardown method called.\"\n        )\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_skills/test_echo/test_dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the dialogue classes of the echo skill.\"\"\"\n\nfrom pathlib import Path\nfrom typing import cast\n\nfrom aea.test_tools.test_skill import BaseSkillTestCase, COUNTERPARTY_AGENT_ADDRESS\n\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.skills.echo.dialogues import DefaultDialogue, DefaultDialogues\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass TestDialogues(BaseSkillTestCase):\n    \"\"\"Test dialogue class of echo.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"echo\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.default_dialogues = cast(\n            DefaultDialogues, cls._skill.skill_context.default_dialogues\n        )\n\n    def test_default_dialogues(self):\n        \"\"\"Test the DefaultDialogues class.\"\"\"\n        _, dialogue = self.default_dialogues.create(\n            counterparty=COUNTERPARTY_AGENT_ADDRESS,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"some_content\",\n        )\n        assert dialogue.role == DefaultDialogue.Role.AGENT\n        assert dialogue.self_address == self.skill.skill_context.agent_name\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_skills/test_echo/test_handlers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the handler class of the echo skill.\"\"\"\n\nimport logging\nfrom pathlib import Path\nfrom typing import cast\nfrom unittest.mock import patch\n\nfrom aea.protocols.dialogue.base import DialogueMessage\nfrom aea.test_tools.test_skill import BaseSkillTestCase\n\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.skills.echo.dialogues import DefaultDialogues\nfrom packages.fetchai.skills.echo.handlers import EchoHandler\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass TestEchoHandler(BaseSkillTestCase):\n    \"\"\"Test EchoHandler of echo.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"echo\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.echo_handler = cast(EchoHandler, cls._skill.skill_context.handlers.echo)\n        cls.logger = cls._skill.skill_context.logger\n\n        cls.default_dialogues = cast(\n            DefaultDialogues, cls._skill.skill_context.default_dialogues\n        )\n\n        cls.content = b\"some_content\"\n        cls.list_of_messages = (\n            DialogueMessage(\n                DefaultMessage.Performative.BYTES, {\"content\": cls.content}\n            ),\n        )\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the echo handler.\"\"\"\n        with patch.object(self.logger, \"log\") as mock_logger:\n            assert self.echo_handler.setup() is None\n\n        # after\n        self.assert_quantity_in_outbox(0)\n\n        mock_logger.assert_any_call(logging.INFO, \"Echo Handler: setup method called.\")\n\n    def test_handle_unidentified_dialogue(self):\n        \"\"\"Test the _handle_unidentified_dialogue method of the oef_search handler.\"\"\"\n        # setup\n        incorrect_dialogue_reference = (\"\", \"\")\n        incoming_message = self.build_incoming_message(\n            message_type=DefaultMessage,\n            dialogue_reference=incorrect_dialogue_reference,\n            performative=DefaultMessage.Performative.BYTES,\n            content=self.content,\n            to=self.skill.skill_context.agent_name,\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.echo_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received invalid default message={incoming_message}, unidentified dialogue.\",\n        )\n\n    def test_handle_error(self):\n        \"\"\"Test the _handle_error method of the oef_search handler.\"\"\"\n        # setup\n        default_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.default_dialogues,\n            messages=self.list_of_messages[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=default_dialogue,\n            performative=DefaultMessage.Performative.ERROR,\n            error_code=DefaultMessage.ErrorCode.INVALID_DIALOGUE,\n            error_msg=\"Invalid dialogue.\",\n            error_data={\"default_message\": b\"some_bytes\"},\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.echo_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received default error message={incoming_message} in dialogue={default_dialogue}.\",\n        )\n\n    def test_handle_bytes(self):\n        \"\"\"Test the _handle_error method of the oef_search handler.\"\"\"\n        # setup\n        default_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.default_dialogues,\n            messages=self.list_of_messages[:1],\n        )\n        incoming_message = cast(\n            DefaultMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=default_dialogue,\n                performative=DefaultMessage.Performative.BYTES,\n                content=self.content,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.echo_handler.handle(incoming_message)\n\n        # after\n        self.assert_quantity_in_outbox(1)\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"Echo Handler: message={incoming_message}, sender={incoming_message.sender}\",\n        )\n\n        message = self.get_message_from_outbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=DefaultMessage,\n            performative=DefaultMessage.Performative.BYTES,\n            to=incoming_message.sender,\n            sender=self.skill.skill_context.agent_name,\n            target=incoming_message.message_id,\n            content=incoming_message.content,\n        )\n        assert has_attributes, error_str\n\n    def test_handle_invalid(self):\n        \"\"\"Test the _handle_invalid method of the echo handler.\"\"\"\n        # setup\n        default_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.default_dialogues,\n            messages=self.list_of_messages[:1],\n        )\n        incoming_message = cast(\n            DefaultMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=default_dialogue,\n                performative=DefaultMessage.Performative.END,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.echo_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received invalid message={incoming_message} in dialogue={self.default_dialogues.get_dialogue(incoming_message)}.\",\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the echo handler.\"\"\"\n        with patch.object(self.logger, \"log\") as mock_logger:\n            assert self.echo_handler.teardown() is None\n\n        # after\n        self.assert_quantity_in_outbox(0)\n\n        mock_logger.assert_any_call(\n            logging.INFO, \"Echo Handler: teardown method called.\"\n        )\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_skills/test_erc1155_client/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"The tests module contains the tests of the packages/skills/erc1155_client dir.\"\"\"\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_skills/test_erc1155_client/intermediate_class.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module sets up test environment for erc1155_client skill.\"\"\"\n\nfrom pathlib import Path\nfrom typing import cast\n\nfrom aea.helpers.search.models import (\n    Attribute,\n    Constraint,\n    ConstraintType,\n    DataModel,\n    Description,\n    Query,\n)\nfrom aea.helpers.transaction.base import RawMessage, RawTransaction, Terms\nfrom aea.protocols.dialogue.base import DialogueMessage\nfrom aea.test_tools.test_skill import BaseSkillTestCase\n\nfrom packages.fetchai.protocols.contract_api.custom_types import Kwargs\nfrom packages.fetchai.protocols.contract_api.message import ContractApiMessage\nfrom packages.fetchai.protocols.fipa.message import FipaMessage\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.protocols.signing.message import SigningMessage\nfrom packages.fetchai.skills.erc1155_client.behaviours import SearchBehaviour\nfrom packages.fetchai.skills.erc1155_client.dialogues import (\n    ContractApiDialogues,\n    DefaultDialogues,\n    FipaDialogues,\n    LedgerApiDialogues,\n    OefSearchDialogues,\n    SigningDialogues,\n)\nfrom packages.fetchai.skills.erc1155_client.handlers import (\n    ContractApiHandler,\n    FipaHandler,\n    LedgerApiHandler,\n    OefSearchHandler,\n    SigningHandler,\n)\nfrom packages.fetchai.skills.erc1155_client.strategy import Strategy\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass ERC1155ClientTestCase(BaseSkillTestCase):\n    \"\"\"Sets the erc1155_client class up for testing.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"erc1155_client\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        cls.location = {\"longitude\": 0.1270, \"latitude\": 51.5194}\n        cls.search_query = {\n            \"search_key\": \"seller_service\",\n            \"search_value\": \"erc1155_contract\",\n            \"constraint_type\": \"==\",\n        }\n        cls.search_radius = 5.0\n        config_overrides = {\n            \"models\": {\n                \"strategy\": {\n                    \"args\": {\n                        \"location\": cls.location,\n                        \"search_query\": cls.search_query,\n                        \"search_radius\": cls.search_radius,\n                    }\n                }\n            },\n        }\n\n        super().setup(config_overrides=config_overrides)\n\n        # behaviours\n        cls.search_behaviour = cast(\n            SearchBehaviour, cls._skill.skill_context.behaviours.search\n        )\n\n        # dialogues\n        cls.contract_api_dialogues = cast(\n            ContractApiDialogues, cls._skill.skill_context.contract_api_dialogues\n        )\n        cls.default_dialogues = cast(\n            DefaultDialogues, cls._skill.skill_context.default_dialogues\n        )\n        cls.fipa_dialogues = cast(\n            FipaDialogues, cls._skill.skill_context.fipa_dialogues\n        )\n        cls.ledger_api_dialogues = cast(\n            LedgerApiDialogues, cls._skill.skill_context.ledger_api_dialogues\n        )\n        cls.oef_search_dialogues = cast(\n            OefSearchDialogues, cls._skill.skill_context.oef_search_dialogues\n        )\n        cls.signing_dialogues = cast(\n            SigningDialogues, cls._skill.skill_context.signing_dialogues\n        )\n\n        # handlers\n        cls.fipa_handler = cast(FipaHandler, cls._skill.skill_context.handlers.fipa)\n        cls.oef_search_handler = cast(\n            OefSearchHandler, cls._skill.skill_context.handlers.oef_search\n        )\n        cls.contract_api_handler = cast(\n            ContractApiHandler, cls._skill.skill_context.handlers.contract_api\n        )\n        cls.signing_handler = cast(\n            SigningHandler, cls._skill.skill_context.handlers.signing\n        )\n        cls.ledger_api_handler = cast(\n            LedgerApiHandler, cls._skill.skill_context.handlers.ledger_api\n        )\n\n        # models\n        cls.strategy = cast(Strategy, cls._skill.skill_context.strategy)\n\n        cls.logger = cls._skill.skill_context.logger\n\n        # mocked objects\n        cls.ledger_id = \"some_ledger_id\"\n        cls.contract_id = \"some_contract_id\"\n        cls.contract_address = \"some_contract_address\"\n        cls.callable = \"some_callable\"\n        cls.body = {\"some_key\": \"some_value\"}\n        cls.kwargs = Kwargs(cls.body)\n        cls.address = \"some_address\"\n        cls.mocked_terms = Terms(\n            cls.ledger_id,\n            cls._skill.skill_context.agent_address,\n            \"counterprty\",\n            {\"currency_id\": 50},\n            {\"good_id\": -10},\n            \"some_nonce\",\n        )\n        cls.mocked_query = Query(\n            [Constraint(\"some_attribute_name\", ConstraintType(\"==\", \"some_value\"))],\n            DataModel(\n                \"some_data_model_name\",\n                [\n                    Attribute(\n                        \"some_attribute_name\",\n                        str,\n                        False,\n                        \"Some attribute descriptions.\",\n                    )\n                ],\n            ),\n        )\n        cls.mocked_proposal = Description(\n            {\n                \"contract_address\": \"some_contract_address\",\n                \"token_id\": \"123456\",\n                \"trade_nonce\": \"876438756348568\",\n                \"from_supply\": \"543\",\n                \"to_supply\": \"432\",\n                \"value\": \"67\",\n            }\n        )\n        cls.mocked_raw_tx = (RawTransaction(cls.ledger_id, {\"some_key\": \"some_value\"}),)\n        cls.mocked_raw_msg = RawMessage(cls.ledger_id, b\"some_body\")\n\n        # list of messages\n        cls.list_of_fipa_messages = (\n            DialogueMessage(FipaMessage.Performative.CFP, {\"query\": cls.mocked_query}),\n            DialogueMessage(\n                FipaMessage.Performative.PROPOSE, {\"proposal\": cls.mocked_proposal}\n            ),\n        )\n        cls.list_of_oef_search_messages = (\n            DialogueMessage(\n                OefSearchMessage.Performative.SEARCH_SERVICES,\n                {\"query\": cls.mocked_query},\n            ),\n        )\n        cls.list_of_contract_api_messages = (\n            DialogueMessage(\n                ContractApiMessage.Performative.GET_RAW_MESSAGE,\n                {\n                    \"ledger_id\": cls.ledger_id,\n                    \"contract_id\": cls.contract_id,\n                    \"contract_address\": cls.contract_address,\n                    \"callable\": cls.callable,\n                    \"kwargs\": cls.kwargs,\n                },\n            ),\n        )\n        cls.list_of_signing_messages = (\n            DialogueMessage(\n                SigningMessage.Performative.SIGN_MESSAGE,\n                {\"terms\": cls.mocked_terms, \"raw_message\": cls.mocked_raw_msg},\n            ),\n        )\n        cls.list_of_ledger_api_messages = (\n            DialogueMessage(\n                LedgerApiMessage.Performative.GET_BALANCE,\n                {\"ledger_id\": cls.ledger_id, \"address\": \"some_address\"},\n            ),\n        )\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_skills/test_erc1155_client/test_behaviours.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the behaviour classes of the erc1155_client skill.\"\"\"\n\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.skills.erc1155_client.behaviours import LEDGER_API_ADDRESS\n\nfrom tests.test_packages_for_aea_tests.test_skills.test_erc1155_client.intermediate_class import (\n    ERC1155ClientTestCase,\n)\n\n\nclass TestSearchBehaviour(ERC1155ClientTestCase):\n    \"\"\"Test search behaviour of erc1155_client.\"\"\"\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the search behaviour.\"\"\"\n        # operation\n        self.search_behaviour.setup()\n\n        # after\n        self.assert_quantity_in_outbox(1)\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=LedgerApiMessage,\n            performative=LedgerApiMessage.Performative.GET_BALANCE,\n            to=LEDGER_API_ADDRESS,\n            sender=str(self.skill.public_id),\n            ledger_id=self.strategy.ledger_id,\n            address=self.skill.skill_context.agent_address,\n        )\n        assert has_attributes, error_str\n\n    def test_act_is_searching(self):\n        \"\"\"Test the act method of the search behaviour where is_searching is True.\"\"\"\n        # setup\n        self.strategy._is_searching = True\n\n        # operation\n        self.search_behaviour.act()\n\n        # after\n        self.assert_quantity_in_outbox(1)\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=OefSearchMessage,\n            performative=OefSearchMessage.Performative.SEARCH_SERVICES,\n            to=self.skill.skill_context.search_service_address,\n            sender=str(self.skill.public_id),\n            query=self.skill.skill_context.strategy.get_location_and_service_query(),\n        )\n        assert has_attributes, error_str\n\n    def test_act_not_is_searching(self):\n        \"\"\"Test the act method of the search behaviour where is_searching is False.\"\"\"\n        # setup\n        self.strategy.is_searching = False\n\n        # operation\n        self.search_behaviour.act()\n\n        # after\n        self.assert_quantity_in_outbox(0)\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the search behaviour.\"\"\"\n        assert self.search_behaviour.teardown() is None\n        self.assert_quantity_in_outbox(0)\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_skills/test_erc1155_client/test_dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the dialogue classes of the erc1155_client skill.\"\"\"\n\nimport pytest\n\nfrom aea.exceptions import AEAEnforceError\nfrom aea.protocols.dialogue.base import DialogueLabel\nfrom aea.test_tools.test_skill import COUNTERPARTY_AGENT_ADDRESS\n\nfrom packages.fetchai.protocols.contract_api.message import ContractApiMessage\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.protocols.fipa.message import FipaMessage\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.protocols.signing.message import SigningMessage\nfrom packages.fetchai.skills.erc1155_client.dialogues import (\n    ContractApiDialogue,\n    DefaultDialogue,\n    FipaDialogue,\n    LedgerApiDialogue,\n    OefSearchDialogue,\n    SigningDialogue,\n)\n\nfrom tests.test_packages_for_aea_tests.test_skills.test_erc1155_client.intermediate_class import (\n    ERC1155ClientTestCase,\n)\n\n\nclass TestDialogues(ERC1155ClientTestCase):\n    \"\"\"Test dialogue classes of erc1155_client.\"\"\"\n\n    def test_contract_api_dialogue(self):\n        \"\"\"Test the ContractApiDialogue class.\"\"\"\n        contract_api_dialogue = ContractApiDialogue(\n            DialogueLabel(\n                (\"\", \"\"),\n                COUNTERPARTY_AGENT_ADDRESS,\n                self.skill.skill_context.agent_address,\n            ),\n            self.skill.skill_context.agent_address,\n            role=ContractApiDialogue.Role.AGENT,\n        )\n\n        # associated_fipa_dialogue\n        with pytest.raises(ValueError, match=\"Associated fipa dialogue not set!\"):\n            assert contract_api_dialogue.associated_fipa_dialogue\n        fipa_dialogue = FipaDialogue(\n            DialogueLabel(\n                (\"\", \"\"),\n                COUNTERPARTY_AGENT_ADDRESS,\n                self.skill.skill_context.agent_address,\n            ),\n            self.skill.skill_context.agent_address,\n            role=FipaDialogue.Role.BUYER,\n        )\n        contract_api_dialogue.associated_fipa_dialogue = fipa_dialogue\n        with pytest.raises(\n            AEAEnforceError, match=\"Associated fipa dialogue already set!\"\n        ):\n            contract_api_dialogue.associated_fipa_dialogue = fipa_dialogue\n        assert contract_api_dialogue.associated_fipa_dialogue == fipa_dialogue\n\n        # terms\n        with pytest.raises(ValueError, match=\"Terms not set!\"):\n            assert contract_api_dialogue.terms\n        contract_api_dialogue.terms = self.mocked_terms\n        with pytest.raises(AEAEnforceError, match=\"Terms already set!\"):\n            contract_api_dialogue.terms = self.mocked_terms\n        assert contract_api_dialogue.terms == self.mocked_terms\n\n    def test_contract_api_dialogues(self):\n        \"\"\"Test the ContractApiDialogues class.\"\"\"\n        _, dialogue = self.contract_api_dialogues.create(\n            counterparty=COUNTERPARTY_AGENT_ADDRESS,\n            performative=ContractApiMessage.Performative.GET_DEPLOY_TRANSACTION,\n            ledger_id=self.ledger_id,\n            contract_id=self.contract_id,\n            callable=self.callable,\n            kwargs=self.kwargs,\n        )\n        assert dialogue.role == ContractApiDialogue.Role.AGENT\n        assert dialogue.self_address == str(self.skill.skill_context.skill_id)\n\n    def test_default_dialogues(self):\n        \"\"\"Test the DefaultDialogues class.\"\"\"\n        _, dialogue = self.default_dialogues.create(\n            counterparty=COUNTERPARTY_AGENT_ADDRESS,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"some_content\",\n        )\n        assert dialogue.role == DefaultDialogue.Role.AGENT\n        assert dialogue.self_address == self.skill.skill_context.agent_address\n\n    def test_fipa_dialogues(self):\n        \"\"\"Test the FipaDialogues class.\"\"\"\n        _, dialogue = self.fipa_dialogues.create(\n            counterparty=COUNTERPARTY_AGENT_ADDRESS,\n            performative=FipaMessage.Performative.CFP,\n            query=self.mocked_query,\n        )\n        assert dialogue.role == FipaDialogue.Role.SELLER\n        assert dialogue.self_address == self.skill.skill_context.agent_address\n\n    def test_ledger_api_dialogues(self):\n        \"\"\"Test the LedgerApiDialogues class.\"\"\"\n        _, dialogue = self.ledger_api_dialogues.create(\n            counterparty=COUNTERPARTY_AGENT_ADDRESS,\n            performative=LedgerApiMessage.Performative.GET_BALANCE,\n            ledger_id=self.ledger_id,\n            address=self.address,\n        )\n        assert dialogue.role == LedgerApiDialogue.Role.AGENT\n        assert dialogue.self_address == str(self.skill.skill_context.skill_id)\n\n    def test_oef_search_dialogues(self):\n        \"\"\"Test the OefSearchDialogues class.\"\"\"\n        _, dialogue = self.oef_search_dialogues.create(\n            counterparty=COUNTERPARTY_AGENT_ADDRESS,\n            performative=OefSearchMessage.Performative.SEARCH_SERVICES,\n            query=self.mocked_query,\n        )\n        assert dialogue.role == OefSearchDialogue.Role.AGENT\n        assert dialogue.self_address == str(self.skill.skill_context.skill_id)\n\n    def test_signing_dialogue(self):\n        \"\"\"Test the SigningDialogue class.\"\"\"\n        signing_dialogue = SigningDialogue(\n            DialogueLabel(\n                (\"\", \"\"),\n                COUNTERPARTY_AGENT_ADDRESS,\n                self.skill.skill_context.agent_address,\n            ),\n            self.skill.skill_context.agent_address,\n            role=ContractApiDialogue.Role.AGENT,\n        )\n\n        # associated_contract_api_dialogue\n        with pytest.raises(\n            ValueError, match=\"Associated contract api dialogue not set!\"\n        ):\n            assert signing_dialogue.associated_contract_api_dialogue\n        contract_api_dialogue = ContractApiDialogue(\n            DialogueLabel(\n                (\"\", \"\"),\n                COUNTERPARTY_AGENT_ADDRESS,\n                self.skill.skill_context.agent_address,\n            ),\n            self.skill.skill_context.agent_address,\n            role=ContractApiDialogue.Role.AGENT,\n        )\n        signing_dialogue.associated_contract_api_dialogue = contract_api_dialogue\n        with pytest.raises(\n            AEAEnforceError, match=\"Associated contract api dialogue already set!\"\n        ):\n            signing_dialogue.associated_contract_api_dialogue = contract_api_dialogue\n        assert (\n            signing_dialogue.associated_contract_api_dialogue == contract_api_dialogue\n        )\n\n    def test_signing_dialogues(self):\n        \"\"\"Test the SigningDialogues class.\"\"\"\n        _, dialogue = self.signing_dialogues.create(\n            counterparty=COUNTERPARTY_AGENT_ADDRESS,\n            performative=SigningMessage.Performative.SIGN_TRANSACTION,\n            terms=self.mocked_terms,\n            raw_transaction=self.mocked_raw_tx,\n        )\n        assert dialogue.role == SigningDialogue.Role.SKILL\n        assert dialogue.self_address == str(self.skill.skill_context.skill_id)\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_skills/test_erc1155_client/test_handlers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the handler classes of the erc1155_client skill.\"\"\"\n\nimport logging\nfrom typing import cast\nfrom unittest.mock import patch\n\nfrom aea.helpers.search.models import Description\nfrom aea.helpers.transaction.base import RawMessage, State, Terms\nfrom aea.test_tools.test_skill import COUNTERPARTY_AGENT_ADDRESS\n\nfrom packages.fetchai.protocols.contract_api.message import ContractApiMessage\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.protocols.fipa.message import FipaMessage\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.protocols.signing.message import SigningMessage\nfrom packages.fetchai.skills.erc1155_client.dialogues import (\n    ContractApiDialogue,\n    FipaDialogue,\n    LedgerApiDialogue,\n    OefSearchDialogue,\n    SigningDialogue,\n)\nfrom packages.fetchai.skills.erc1155_client.handlers import LEDGER_API_ADDRESS\n\nfrom tests.test_packages_for_aea_tests.test_skills.test_erc1155_client.intermediate_class import (\n    ERC1155ClientTestCase,\n)\n\n\nclass TestFipaHandler(ERC1155ClientTestCase):\n    \"\"\"Test fipa handler of erc1155_client.\"\"\"\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the fipa handler.\"\"\"\n        assert self.fipa_handler.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle_unidentified_dialogue(self):\n        \"\"\"Test the _handle_unidentified_dialogue method of the fipa handler.\"\"\"\n        # setup\n        incorrect_dialogue_reference = (\"\", \"\")\n        incoming_message = cast(\n            FipaMessage,\n            self.build_incoming_message(\n                message_type=FipaMessage,\n                dialogue_reference=incorrect_dialogue_reference,\n                performative=FipaMessage.Performative.ACCEPT,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.fipa_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"unidentified dialogue for message={incoming_message}.\",\n        )\n\n        self.assert_quantity_in_outbox(1)\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=DefaultMessage,\n            performative=DefaultMessage.Performative.ERROR,\n            to=incoming_message.sender,\n            sender=self.skill.skill_context.agent_address,\n            error_code=DefaultMessage.ErrorCode.INVALID_DIALOGUE,\n            error_msg=\"Invalid dialogue.\",\n            error_data={\"fipa_message\": incoming_message.encode()},\n        )\n        assert has_attributes, error_str\n\n    def test_handle_propose_i(self):\n        \"\"\"Test the _handle_propose method of the fipa handler where all expected keys exist in the proposal.\"\"\"\n        # setup\n        fipa_dialogue = cast(\n            FipaDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.fipa_dialogues,\n                messages=self.list_of_fipa_messages[:1],\n            ),\n        )\n        incoming_message = cast(\n            FipaMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=fipa_dialogue,\n                performative=FipaMessage.Performative.PROPOSE,\n                proposal=self.mocked_proposal,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.fipa_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received valid PROPOSE from sender={COUNTERPARTY_AGENT_ADDRESS[-5:]}: proposal={incoming_message.proposal.values}\",\n        )\n\n        self.assert_quantity_in_outbox(1)\n        message = self.get_message_from_outbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=ContractApiMessage,\n            performative=ContractApiMessage.Performative.GET_RAW_MESSAGE,\n            to=LEDGER_API_ADDRESS,\n            sender=str(self.skill.skill_context.skill_id),\n            ledger_id=self.strategy.ledger_id,\n            contract_id=self.strategy.contract_id,\n            contract_address=incoming_message.proposal.values[\"contract_address\"],\n            callable=\"get_hash_single\",\n            kwargs=ContractApiMessage.Kwargs(\n                {\n                    \"from_address\": incoming_message.sender,\n                    \"to_address\": self.skill.skill_context.agent_address,\n                    \"token_id\": int(incoming_message.proposal.values[\"token_id\"]),\n                    \"from_supply\": int(incoming_message.proposal.values[\"from_supply\"]),\n                    \"to_supply\": int(incoming_message.proposal.values[\"to_supply\"]),\n                    \"value\": int(incoming_message.proposal.values[\"value\"]),\n                    \"trade_nonce\": int(incoming_message.proposal.values[\"trade_nonce\"]),\n                }\n            ),\n        )\n        assert has_attributes, error_str\n\n        contract_api_dialogue = cast(\n            ContractApiDialogue, self.contract_api_dialogues.get_dialogue(message)\n        )\n\n        expected_terms = Terms(\n            ledger_id=self.strategy.ledger_id,\n            sender_address=self.skill.skill_context.agent_address,\n            counterparty_address=incoming_message.sender,\n            amount_by_currency_id={},\n            quantities_by_good_id={\n                str(incoming_message.proposal.values[\"token_id\"]): int(\n                    incoming_message.proposal.values[\"from_supply\"]\n                )\n                - int(incoming_message.proposal.values[\"to_supply\"])\n            },\n            is_sender_payable_tx_fee=False,\n            nonce=str(incoming_message.proposal.values[\"trade_nonce\"]),\n        )\n        assert contract_api_dialogue.terms == expected_terms\n        assert contract_api_dialogue.associated_fipa_dialogue == fipa_dialogue\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            \"requesting single hash message from contract api...\",\n        )\n\n    def test_handle_propose_ii(self):\n        \"\"\"Test the _handle_propose method of the fipa handler where some expected keys do NOT exist in the proposal.\"\"\"\n        # setup\n        invalid_proposal = Description({\"some_key\": \"v1\", \"some_key_2\": \"12\"})\n\n        fipa_dialogue = cast(\n            FipaDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.fipa_dialogues,\n                messages=self.list_of_fipa_messages[:1],\n            ),\n        )\n        incoming_message = cast(\n            FipaMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=fipa_dialogue,\n                performative=FipaMessage.Performative.PROPOSE,\n                proposal=invalid_proposal,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.fipa_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received invalid PROPOSE from sender={COUNTERPARTY_AGENT_ADDRESS[-5:]}: proposal={incoming_message.proposal.values}\",\n        )\n\n    def test_handle_invalid(self):\n        \"\"\"Test the _handle_invalid method of the fipa handler.\"\"\"\n        # setup\n        fipa_dialogue = cast(\n            FipaDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.fipa_dialogues,\n                messages=self.list_of_fipa_messages[:2],\n            ),\n        )\n        incoming_message = cast(\n            FipaMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=fipa_dialogue,\n                performative=FipaMessage.Performative.ACCEPT,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.fipa_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"cannot handle fipa message of performative={incoming_message.performative} in dialogue={fipa_dialogue}.\",\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the fipa handler.\"\"\"\n        assert self.fipa_handler.teardown() is None\n        self.assert_quantity_in_outbox(0)\n\n\nclass TestOefSearchHandler(ERC1155ClientTestCase):\n    \"\"\"Test oef_search handler of erc1155_client.\"\"\"\n\n    is_agent_to_agent_messages = False\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the oef_search handler.\"\"\"\n        assert self.oef_search_handler.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle_unidentified_dialogue(self):\n        \"\"\"Test the _handle_unidentified_dialogue method of the oef_search handler.\"\"\"\n        # setup\n        incorrect_dialogue_reference = (\"\", \"\")\n        incoming_message = cast(\n            OefSearchMessage,\n            self.build_incoming_message(\n                message_type=OefSearchMessage,\n                dialogue_reference=incorrect_dialogue_reference,\n                performative=OefSearchMessage.Performative.OEF_ERROR,\n                oef_error_operation=OefSearchMessage.OefErrorOperation.REGISTER_SERVICE,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received invalid oef_search message={incoming_message}, unidentified dialogue.\",\n        )\n\n    def test_handle_error(self):\n        \"\"\"Test the _handle_error method of the oef_search handler.\"\"\"\n        # setup\n        oef_search_dialogue = cast(\n            OefSearchDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.oef_search_dialogues,\n                messages=self.list_of_oef_search_messages[:1],\n            ),\n        )\n        incoming_message = cast(\n            OefSearchMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=oef_search_dialogue,\n                performative=OefSearchMessage.Performative.OEF_ERROR,\n                oef_error_operation=OefSearchMessage.OefErrorOperation.REGISTER_SERVICE,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received oef_search error message={incoming_message} in dialogue={oef_search_dialogue}.\",\n        )\n\n    def test_handle_search_i(self):\n        \"\"\"Test the _handle_search method of the oef_search handler where the number of agents found is NOT 0.\"\"\"\n        # setup\n        agents = (\"agent_1\", \"agent_2\")\n        oef_search_dialogue = cast(\n            OefSearchDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.oef_search_dialogues,\n                messages=self.list_of_oef_search_messages[:1],\n            ),\n        )\n        incoming_message = cast(\n            OefSearchMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=oef_search_dialogue,\n                performative=OefSearchMessage.Performative.SEARCH_RESULT,\n                agents=agents,\n                agents_info=OefSearchMessage.AgentsInfo(\n                    {\n                        \"agent_1\": {\"key_1\": \"value_1\", \"key_2\": \"value_2\"},\n                        \"agent_2\": {\"key_3\": \"value_3\", \"key_4\": \"value_4\"},\n                    }\n                ),\n            ),\n        )\n\n        # before\n        assert self.strategy.is_searching is True\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"found agents={list(map(lambda x: x[-5:], incoming_message.agents))}, stopping search.\",\n        )\n\n        assert self.strategy.is_searching is False\n\n        self.assert_quantity_in_outbox(len(agents))\n        for agent in agents:\n            has_attributes, error_str = self.message_has_attributes(\n                actual_message=self.get_message_from_outbox(),\n                message_type=FipaMessage,\n                performative=FipaMessage.Performative.CFP,\n                to=agent,\n                sender=self.skill.skill_context.agent_address,\n                query=self.strategy.get_service_query(),\n            )\n            assert has_attributes, error_str\n            mock_logger.assert_any_call(\n                logging.INFO, f\"sending CFP to agent={agent[-5:]}\"\n            )\n\n    def test_handle_search_ii(self):\n        \"\"\"Test the _handle_search method of the oef_search handler where the number of agents found is 0.\"\"\"\n        # setup\n        agents = tuple()\n        oef_search_dialogue = cast(\n            OefSearchDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.oef_search_dialogues,\n                messages=self.list_of_oef_search_messages[:1],\n            ),\n        )\n        incoming_message = cast(\n            OefSearchMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=oef_search_dialogue,\n                performative=OefSearchMessage.Performative.SEARCH_RESULT,\n                agents=agents,\n                agents_info=OefSearchMessage.AgentsInfo({}),\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"found no agents in dialogue={oef_search_dialogue}, continue searching.\",\n        )\n\n    def test_handle_invalid(self):\n        \"\"\"Test the _handle_invalid method of the oef_search handler.\"\"\"\n        # setup\n        incoming_message = cast(\n            OefSearchMessage,\n            self.build_incoming_message(\n                message_type=OefSearchMessage,\n                performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n                service_description=self.mocked_proposal,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"cannot handle oef_search message of performative={incoming_message.performative} in dialogue={self.oef_search_dialogues.get_dialogue(incoming_message)}.\",\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the oef_search handler.\"\"\"\n        assert self.oef_search_handler.teardown() is None\n        self.assert_quantity_in_outbox(0)\n\n\nclass TestContractApiHandler(ERC1155ClientTestCase):\n    \"\"\"Test contract_api handler of erc1155_client.\"\"\"\n\n    is_agent_to_agent_messages = False\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the contract_api handler.\"\"\"\n        assert self.contract_api_handler.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle_unidentified_dialogue(self):\n        \"\"\"Test the _handle_unidentified_dialogue method of the signing handler.\"\"\"\n        # setup\n        incorrect_dialogue_reference = (\"\", \"\")\n        incoming_message = cast(\n            ContractApiMessage,\n            self.build_incoming_message(\n                message_type=ContractApiMessage,\n                dialogue_reference=incorrect_dialogue_reference,\n                performative=ContractApiMessage.Performative.STATE,\n                state=State(self.ledger_id, self.body),\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.contract_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received invalid contract_api message={incoming_message}, unidentified dialogue.\",\n        )\n\n    def test_handle_raw_message(self):\n        \"\"\"Test the _handle_raw_message method of the signing handler.\"\"\"\n        # setup\n        contract_api_dialogue = cast(\n            ContractApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.contract_api_dialogues,\n                messages=self.list_of_contract_api_messages[:1],\n            ),\n        )\n        contract_api_dialogue.terms = self.mocked_terms\n        incoming_message = cast(\n            ContractApiMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=contract_api_dialogue,\n                performative=ContractApiMessage.Performative.RAW_MESSAGE,\n                raw_message=self.mocked_raw_msg,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.contract_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO, f\"received raw message={incoming_message}\"\n        )\n\n        self.assert_quantity_in_decision_making_queue(1)\n        message = self.get_message_from_decision_maker_inbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=SigningMessage,\n            performative=SigningMessage.Performative.SIGN_MESSAGE,\n            to=self.skill.skill_context.decision_maker_address,\n            sender=str(self.skill.skill_context.skill_id),\n            raw_message=RawMessage(\n                incoming_message.raw_message.ledger_id,\n                incoming_message.raw_message.body,\n                is_deprecated_mode=True,\n            ),\n            terms=contract_api_dialogue.terms,\n        )\n        assert has_attributes, error_str\n\n        assert (\n            cast(\n                SigningDialogue, self.signing_dialogues.get_dialogue(message)\n            ).associated_contract_api_dialogue\n            == contract_api_dialogue\n        )\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            \"proposing the transaction to the decision maker. Waiting for confirmation ...\",\n        )\n\n    def test_handle_error(self):\n        \"\"\"Test the _handle_error method of the signing handler.\"\"\"\n        # setup\n        contract_api_dialogue = cast(\n            ContractApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.contract_api_dialogues,\n                messages=self.list_of_contract_api_messages[:1],\n            ),\n        )\n        incoming_message = cast(\n            ContractApiMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=contract_api_dialogue,\n                performative=ContractApiMessage.Performative.ERROR,\n                data=b\"some_data\",\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.contract_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received contract_api error message={incoming_message} in dialogue={contract_api_dialogue}.\",\n        )\n\n    def test_handle_invalid(self):\n        \"\"\"Test the _handle_invalid method of the signing handler.\"\"\"\n        # setup\n        invalid_performative = ContractApiMessage.Performative.GET_DEPLOY_TRANSACTION\n        incoming_message = cast(\n            ContractApiMessage,\n            self.build_incoming_message(\n                message_type=ContractApiMessage,\n                dialogue_reference=(\"1\", \"\"),\n                performative=invalid_performative,\n                ledger_id=self.ledger_id,\n                contract_id=self.contract_id,\n                callable=self.callable,\n                kwargs=self.kwargs,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.contract_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"cannot handle contract_api message of performative={invalid_performative} in dialogue={self.contract_api_dialogues.get_dialogue(incoming_message)}.\",\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the contract_api handler.\"\"\"\n        assert self.contract_api_handler.teardown() is None\n        self.assert_quantity_in_outbox(0)\n\n\nclass TestSigningHandler(ERC1155ClientTestCase):\n    \"\"\"Test signing handler of erc1155_client.\"\"\"\n\n    is_agent_to_agent_messages = False\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the signing handler.\"\"\"\n        assert self.signing_handler.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle_unidentified_dialogue(self):\n        \"\"\"Test the _handle_unidentified_dialogue method of the signing handler.\"\"\"\n        # setup\n        incorrect_dialogue_reference = (\"\", \"\")\n        incoming_message = cast(\n            SigningMessage,\n            self.build_incoming_message(\n                message_type=SigningMessage,\n                dialogue_reference=incorrect_dialogue_reference,\n                performative=SigningMessage.Performative.ERROR,\n                error_code=SigningMessage.ErrorCode.UNSUCCESSFUL_MESSAGE_SIGNING,\n                to=str(self.skill.skill_context.skill_id),\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.signing_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received invalid signing message={incoming_message}, unidentified dialogue.\",\n        )\n\n    def test_handle_signed_message(\n        self,\n    ):\n        \"\"\"Test the _handle_signed_message method of the signing handler.\"\"\"\n        # setup\n        signing_counterparty = self.skill.skill_context.decision_maker_address\n\n        fipa_dialogue = cast(\n            FipaDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.fipa_dialogues,\n                messages=self.list_of_fipa_messages[:2],\n                counterparty=COUNTERPARTY_AGENT_ADDRESS,\n            ),\n        )\n        signing_dialogue = cast(\n            SigningDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.signing_dialogues,\n                messages=self.list_of_signing_messages[:1],\n                counterparty=signing_counterparty,\n            ),\n        )\n        contract_api_dialogue = cast(\n            ContractApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.contract_api_dialogues,\n                messages=self.list_of_contract_api_messages[:4],\n            ),\n        )\n\n        signing_dialogue.associated_contract_api_dialogue = contract_api_dialogue\n        contract_api_dialogue.associated_fipa_dialogue = fipa_dialogue\n\n        incoming_message = cast(\n            SigningMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=signing_dialogue,\n                performative=SigningMessage.Performative.SIGNED_MESSAGE,\n                signed_message=SigningMessage.SignedMessage(\n                    self.ledger_id,\n                    \"some_body\",\n                ),\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.signing_handler.handle(incoming_message)\n\n        # after\n        fipa_dialogue_opponent = fipa_dialogue.dialogue_label.dialogue_opponent_addr\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"sending ACCEPT_W_INFORM to agent={fipa_dialogue_opponent[-5:]}: tx_signature={incoming_message.signed_message}\",\n        )\n\n        self.assert_quantity_in_outbox(1)\n        message = self.get_message_from_outbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=FipaMessage,\n            performative=FipaMessage.Performative.ACCEPT_W_INFORM,\n            to=fipa_dialogue_opponent,\n            sender=self.skill.skill_context.agent_address,\n            info={\"tx_signature\": incoming_message.signed_message.body},\n        )\n        assert has_attributes, error_str\n\n    def test_handle_error(self):\n        \"\"\"Test the _handle_error method of the signing handler.\"\"\"\n        # setup\n        signing_counterparty = self.skill.skill_context.decision_maker_address\n        signing_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.signing_dialogues,\n            messages=self.list_of_signing_messages[:1],\n            counterparty=signing_counterparty,\n        )\n        incoming_message = cast(\n            SigningMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=signing_dialogue,\n                performative=SigningMessage.Performative.ERROR,\n                error_code=SigningMessage.ErrorCode.UNSUCCESSFUL_TRANSACTION_SIGNING,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.signing_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"transaction signing was not successful. Error_code={incoming_message.error_code} in dialogue={signing_dialogue}\",\n        )\n\n    def test_handle_invalid(self):\n        \"\"\"Test the _handle_invalid method of the signing handler.\"\"\"\n        # setup\n        invalid_performative = SigningMessage.Performative.SIGN_TRANSACTION\n        incoming_message = self.build_incoming_message(\n            message_type=SigningMessage,\n            dialogue_reference=(\"1\", \"\"),\n            performative=invalid_performative,\n            terms=self.mocked_terms,\n            raw_transaction=SigningMessage.RawTransaction(\n                self.ledger_id, {\"some_key\": \"some_value\"}\n            ),\n            to=str(self.skill.skill_context.skill_id),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.signing_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"cannot handle signing message of performative={invalid_performative} in dialogue={self.signing_dialogues.get_dialogue(incoming_message)}.\",\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the signing handler.\"\"\"\n        assert self.signing_handler.teardown() is None\n        self.assert_quantity_in_outbox(0)\n\n\nclass TestLedgerApiHandler(ERC1155ClientTestCase):\n    \"\"\"Test ledger_api handler of erc1155_client.\"\"\"\n\n    is_agent_to_agent_messages = False\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the ledger_api handler.\"\"\"\n        assert self.ledger_api_handler.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle_unidentified_dialogue(self):\n        \"\"\"Test the _handle_unidentified_dialogue method of the ledger_api handler.\"\"\"\n        # setup\n        incorrect_dialogue_reference = (\"\", \"\")\n        incoming_message = cast(\n            LedgerApiMessage,\n            self.build_incoming_message(\n                message_type=LedgerApiMessage,\n                dialogue_reference=incorrect_dialogue_reference,\n                performative=LedgerApiMessage.Performative.BALANCE,\n                ledger_id=self.ledger_id,\n                balance=10,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received invalid ledger_api message={incoming_message}, unidentified dialogue.\",\n        )\n\n    def test_handle_balance(self):\n        \"\"\"Test the _handle_balance method of the ledger_api handler.\"\"\"\n        # setup\n        balance = 10\n        ledger_api_dialogue = cast(\n            LedgerApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.ledger_api_dialogues,\n                messages=self.list_of_ledger_api_messages[:1],\n                counterparty=LEDGER_API_ADDRESS,\n            ),\n        )\n        incoming_message = cast(\n            LedgerApiMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=ledger_api_dialogue,\n                performative=LedgerApiMessage.Performative.BALANCE,\n                ledger_id=self.ledger_id,\n                balance=balance,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"starting balance on {self.ledger_id} ledger={incoming_message.balance}.\",\n        )\n\n    def test_handle_error(self):\n        \"\"\"Test the _handle_error method of the ledger_api handler.\"\"\"\n        # setup\n        ledger_api_dialogue = cast(\n            LedgerApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.ledger_api_dialogues,\n                messages=self.list_of_ledger_api_messages[:1],\n            ),\n        )\n        incoming_message = cast(\n            LedgerApiMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=ledger_api_dialogue,\n                performative=LedgerApiMessage.Performative.ERROR,\n                code=1,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received ledger_api error message={incoming_message} in dialogue={ledger_api_dialogue}.\",\n        )\n\n    def test_handle_invalid(self):\n        \"\"\"Test the _handle_invalid method of the ledger_api handler.\"\"\"\n        # setup\n        invalid_performative = LedgerApiMessage.Performative.GET_BALANCE\n        incoming_message = cast(\n            LedgerApiMessage,\n            self.build_incoming_message(\n                message_type=LedgerApiMessage,\n                dialogue_reference=(\"1\", \"\"),\n                performative=invalid_performative,\n                ledger_id=self.ledger_id,\n                address=self.address,\n                to=str(self.skill.skill_context.skill_id),\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"cannot handle ledger_api message of performative={invalid_performative} in dialogue={self.ledger_api_dialogues.get_dialogue(incoming_message)}.\",\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the ledger_api handler.\"\"\"\n        assert self.ledger_api_handler.teardown() is None\n        self.assert_quantity_in_outbox(0)\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_skills/test_erc1155_client/test_strategy.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the strategy class of the erc1155_client skill.\"\"\"\n\nfrom aea.helpers.search.models import Constraint, ConstraintType, Query\n\nfrom packages.fetchai.skills.erc1155_client.strategy import (\n    CONTRACT_ID,\n    SIMPLE_SERVICE_MODEL,\n)\n\nfrom tests.test_packages_for_aea_tests.test_skills.test_erc1155_client.intermediate_class import (\n    ERC1155ClientTestCase,\n)\n\n\nclass TestStrategy(ERC1155ClientTestCase):\n    \"\"\"Test Strategy of erc1155_client.\"\"\"\n\n    def test_properties(self):\n        \"\"\"Test the properties of Strategy class.\"\"\"\n        assert self.strategy.ledger_id == self.skill.skill_context.default_ledger_id\n        assert self.strategy.contract_id == str(CONTRACT_ID)\n\n    def test_get_location_and_service_query(self):\n        \"\"\"Test the get_location_and_service_query method of the Strategy class.\"\"\"\n        query = self.strategy.get_location_and_service_query()\n\n        assert type(query) == Query\n        assert len(query.constraints) == 2\n        assert query.model is None\n\n        location_constraint = Constraint(\n            \"location\",\n            ConstraintType(\n                \"distance\", (self.strategy._agent_location, self.search_radius)\n            ),\n        )\n        assert query.constraints[0] == location_constraint\n\n        service_key_constraint = Constraint(\n            self.search_query[\"search_key\"],\n            ConstraintType(\n                self.search_query[\"constraint_type\"],\n                self.search_query[\"search_value\"],\n            ),\n        )\n        assert query.constraints[1] == service_key_constraint\n\n    def test_get_service_query(self):\n        \"\"\"Test the get_service_query method of the Strategy class.\"\"\"\n        query = self.strategy.get_service_query()\n\n        assert type(query) == Query\n        assert len(query.constraints) == 1\n\n        assert query.model == SIMPLE_SERVICE_MODEL\n\n        service_key_constraint = Constraint(\n            self.search_query[\"search_key\"],\n            ConstraintType(\n                self.search_query[\"constraint_type\"],\n                self.search_query[\"search_value\"],\n            ),\n        )\n        assert query.constraints[0] == service_key_constraint\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_skills/test_generic_buyer/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"The tests module contains the tests of the packages/skills/generic_buyer dir.\"\"\"\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_skills/test_generic_buyer/test_behaviours.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the behaviour classes of the generic buyer skill.\"\"\"\n\nimport logging\nfrom pathlib import Path\nfrom typing import Tuple, cast\nfrom unittest.mock import patch\n\nimport pytest\n\nfrom aea.protocols.dialogue.base import DialogueMessage\nfrom aea.test_tools.test_skill import BaseSkillTestCase\n\nfrom packages.fetchai.connections.ledger.base import CONNECTION_ID as LEDGER_PUBLIC_ID\nfrom packages.fetchai.protocols.fipa.message import FipaMessage\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.skills.generic_buyer.behaviours import (\n    GenericSearchBehaviour,\n    GenericTransactionBehaviour,\n    LEDGER_API_ADDRESS,\n)\nfrom packages.fetchai.skills.generic_buyer.dialogues import (\n    FipaDialogue,\n    FipaDialogues,\n    LedgerApiDialogue,\n    LedgerApiDialogues,\n)\nfrom packages.fetchai.skills.generic_buyer.strategy import GenericStrategy\n\nfrom tests.conftest import ROOT_DIR\n\n\nFETCHAI = \"fetchai\"\n\n\nclass TestSearchBehaviour(BaseSkillTestCase):\n    \"\"\"Test Search behaviour of generic buyer.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"generic_buyer\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.search_behaviour = cast(\n            GenericSearchBehaviour, cls._skill.skill_context.behaviours.search\n        )\n        cls.tx_behaviour = cast(\n            GenericTransactionBehaviour, cls._skill.skill_context.behaviours.transaction\n        )\n        cls.strategy = cast(GenericStrategy, cls._skill.skill_context.strategy)\n\n        cls.logger = cls._skill.skill_context.logger\n\n    def test_setup_is_ledger_tx(self):\n        \"\"\"Test the setup method of the search behaviour where is_ledger_tx is True.\"\"\"\n        # operation\n        self.search_behaviour.setup()\n\n        # after\n        self.assert_quantity_in_outbox(1)\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=LedgerApiMessage,\n            performative=LedgerApiMessage.Performative.GET_BALANCE,\n            to=str(LEDGER_PUBLIC_ID),\n            sender=str(self.skill.public_id),\n            ledger_id=FETCHAI,\n            address=self.skill.skill_context.agent_address,\n        )\n        assert has_attributes, error_str\n\n    def test_setup_not_is_ledger_tx(self):\n        \"\"\"Test the setup method of the search behaviour where is_ledger_tx is False.\"\"\"\n        # setup\n        self.strategy._is_ledger_tx = False\n\n        # before\n        assert not self.strategy.is_searching\n\n        # operation\n        self.search_behaviour.setup()\n\n        # after\n        assert self.strategy.is_searching\n\n    def test_act_is_searching(self):\n        \"\"\"Test the act method of the search behaviour where is_searching is True.\"\"\"\n        # setup\n        self.strategy._is_searching = True\n\n        # operation\n        self.search_behaviour.act()\n\n        # after\n        self.assert_quantity_in_outbox(1)\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=OefSearchMessage,\n            performative=OefSearchMessage.Performative.SEARCH_SERVICES,\n            to=self.skill.skill_context.search_service_address,\n            sender=str(self.skill.public_id),\n            query=self.skill.skill_context.strategy.get_location_and_service_query(),\n        )\n        assert has_attributes, error_str\n\n    def test_act_not_is_searching(self):\n        \"\"\"Test the act method of the search behaviour where is_searching is False.\"\"\"\n        # setup\n        self.strategy._is_searching = False\n\n        # operation\n        self.search_behaviour.act()\n\n        # after\n        self.assert_quantity_in_outbox(0)\n\n    def test_act_remaining_transactions(self):\n        \"\"\"Test the act method of the search behaviour where remaining_transactions_count > 0.\"\"\"\n        # setup\n        self.strategy._is_searching = True\n        self.tx_behaviour.waiting = [\"some_dialogue\"]\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.search_behaviour.act()\n\n        # after\n        self.assert_quantity_in_outbox(0)\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"Transaction behaviour has {len(self.tx_behaviour.waiting)} transactions remaining. Skipping search!\",\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the search behaviour.\"\"\"\n        assert self.search_behaviour.teardown() is None\n        self.assert_quantity_in_outbox(0)\n\n\nclass TestTransactionBehaviour(BaseSkillTestCase):\n    \"\"\"Test transaction behaviour of generic buyer.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"generic_buyer\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.transaction_behaviour = cast(\n            GenericTransactionBehaviour, cls._skill.skill_context.behaviours.transaction\n        )\n        cls.strategy = cast(GenericStrategy, cls._skill.skill_context.strategy)\n        cls.logger = cls._skill.skill_context.logger\n\n        cls.fipa_dialogues = cast(\n            FipaDialogues, cls._skill.skill_context.fipa_dialogues\n        )\n        cls.ledger_api_dialogues = cast(\n            LedgerApiDialogues, cls._skill.skill_context.ledger_api_dialogues\n        )\n\n        cls.list_of_messages = (\n            DialogueMessage(FipaMessage.Performative.CFP, {\"query\": \"some_query\"}),\n            DialogueMessage(\n                FipaMessage.Performative.PROPOSE, {\"proposal\": \"some_proposal\"}\n            ),\n            DialogueMessage(FipaMessage.Performative.ACCEPT),\n            DialogueMessage(\n                FipaMessage.Performative.MATCH_ACCEPT_W_INFORM,\n                {\"info\": {\"address\": \"some_term_sender_address\"}},\n            ),\n        )\n\n    @staticmethod\n    def _check_start_processing_effects(self_, fipa_dialogue, mock_logger) -> None:\n        \"\"\"Perform checks related to running _start_processing.\"\"\"\n        # _start_processing\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"Processing transaction, {len(self_.transaction_behaviour.waiting)} transactions remaining\",\n        )\n\n        message = self_.get_message_from_outbox()\n        has_attributes, error_str = self_.message_has_attributes(\n            actual_message=message,\n            message_type=LedgerApiMessage,\n            performative=LedgerApiMessage.Performative.GET_RAW_TRANSACTION,\n            to=LEDGER_API_ADDRESS,\n            sender=str(self_.skill.public_id),\n            terms=fipa_dialogue.terms,\n        )\n        assert has_attributes, error_str\n\n        ledger_api_dialogue = cast(\n            LedgerApiDialogue, self_.ledger_api_dialogues.get_dialogue(message)\n        )\n        assert ledger_api_dialogue.associated_fipa_dialogue == fipa_dialogue\n\n        assert self_.transaction_behaviour.processing_time == 0.0\n\n        assert self_.transaction_behaviour.processing == ledger_api_dialogue\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"requesting transfer transaction from ledger api for message={message}...\",\n        )\n\n    @staticmethod\n    def _setup_fipa_ledger_api_dialogues(\n        self_,\n    ) -> Tuple[LedgerApiDialogue, FipaDialogue]:\n        \"\"\"Setup fipa and ledger_api dialogues for some of the following tests.\"\"\"\n        fipa_dialogue = cast(\n            FipaDialogue,\n            self_.prepare_skill_dialogue(\n                dialogues=self_.fipa_dialogues,\n                messages=self_.list_of_messages,\n            ),\n        )\n        fipa_dialogue.terms = \"terms\"  # type: ignore\n\n        ledger_api_dialogue = cast(\n            LedgerApiDialogue,\n            self_.prepare_skill_dialogue(\n                dialogues=self_.ledger_api_dialogues,\n                messages=(\n                    DialogueMessage(\n                        LedgerApiMessage.Performative.GET_BALANCE,\n                        {\"ledger_id\": \"some_ledger_id\", \"address\": \"some_address\"},\n                    ),\n                ),\n            ),\n        )\n        ledger_api_dialogue.associated_fipa_dialogue = fipa_dialogue\n\n        return ledger_api_dialogue, fipa_dialogue\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the transaction behaviour.\"\"\"\n        assert self.transaction_behaviour.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_act_i(self):\n        \"\"\"Test the act method of the transaction behaviour where processing IS None and len(self.waiting) is NOT 0.\"\"\"\n        # setup\n        _, fipa_dialogue = self._setup_fipa_ledger_api_dialogues(self)\n\n        processing_time = 5.0\n        max_processing = 120\n        self.transaction_behaviour.processing = None\n        self.transaction_behaviour.max_processing = max_processing\n        self.transaction_behaviour.processing_time = processing_time\n        self.transaction_behaviour.waiting = [fipa_dialogue]\n\n        # before\n        assert self.transaction_behaviour.processing_time == processing_time\n        assert self.transaction_behaviour.processing is None\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.transaction_behaviour.act()\n\n        # after\n        self.assert_quantity_in_outbox(1)\n\n        # _start_processing\n        self._check_start_processing_effects(self, fipa_dialogue, mock_logger)\n\n    def test_act_ii(self):\n        \"\"\"Test the act method of the transaction behaviour where processing is NOT None and processing_time < max_processing.\"\"\"\n        # setup\n        processing_time = 5.0\n        self.transaction_behaviour.processing = \"some_dialogue\"\n        self.transaction_behaviour.max_processing = 120\n        self.transaction_behaviour.processing_time = processing_time\n\n        # operation\n        self.transaction_behaviour.act()\n\n        # after\n        self.assert_quantity_in_outbox(0)\n        assert (\n            self.transaction_behaviour.processing_time\n            == processing_time + self.transaction_behaviour.tick_interval\n        )\n\n    def test_act_iii(self):\n        \"\"\"Test the act method of the transaction behaviour where processing is NOT None and processing_time > max_processing.\"\"\"\n        # setup\n        ledger_api_dialogue, fipa_dialogue = self._setup_fipa_ledger_api_dialogues(self)\n\n        processing_time = 121.0\n        self.transaction_behaviour.processing = ledger_api_dialogue\n        self.transaction_behaviour.max_processing = 120\n        self.transaction_behaviour.processing_time = processing_time\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.transaction_behaviour.act()\n\n        # after\n        self.assert_quantity_in_outbox(1)\n\n        # _timeout_processing\n        assert ledger_api_dialogue.dialogue_label in self.transaction_behaviour.timedout\n        # below is overridden in _start_processing\n        # assert fipa_dialogue in self.transaction_behaviour.waiting\n        assert self.transaction_behaviour.processing_time == 0.0\n        # below is overridden in _start_processing\n        # assert self.transaction_behaviour.processing is None\n\n        # _start_processing\n        self._check_start_processing_effects(self, fipa_dialogue, mock_logger)\n\n    def test_timeout_processing(self):\n        \"\"\"Test the _timeout_processing method of the transaction behaviour where self.processing IS None.\"\"\"\n        # setup\n        self.transaction_behaviour.processing_time = None\n\n        # operation\n        self.transaction_behaviour._timeout_processing()\n\n        # after\n        self.assert_quantity_in_outbox(0)\n\n    def test_act_iv(self):\n        \"\"\"Test the act method of the transaction behaviour where len(waiting) == 0.\"\"\"\n        # setup\n        self.transaction_behaviour.processing = None\n        self.transaction_behaviour.waiting = []\n\n        # operation\n        self.transaction_behaviour.act()\n\n        # after\n        self.assert_quantity_in_outbox(0)\n\n    def test_failed_processing(self):\n        \"\"\"Test the failed_processing method of the transaction behaviour.\"\"\"\n        # setup\n        ledger_api_dialogue, fipa_dialogue = self._setup_fipa_ledger_api_dialogues(self)\n\n        self.transaction_behaviour.timedout.add(ledger_api_dialogue.dialogue_label)\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.transaction_behaviour.failed_processing(ledger_api_dialogue)\n\n        # after\n        self.assert_quantity_in_outbox(0)\n\n        # finish_processing\n        assert self.transaction_behaviour.timedout == set()\n\n        mock_logger.assert_any_call(\n            logging.DEBUG,\n            f\"Timeout dialogue in transaction processing: {ledger_api_dialogue}\",\n        )\n\n        # failed_processing\n        assert fipa_dialogue in self.transaction_behaviour.waiting\n\n    def test_finish_processing_i(self):\n        \"\"\"Test the finish_processing method of the transaction behaviour where self.processing == ledger_api_dialogue.\"\"\"\n        # setup\n        ledger_api_dialogue, fipa_dialogue = self._setup_fipa_ledger_api_dialogues(self)\n        self.transaction_behaviour.processing = ledger_api_dialogue\n\n        # operation\n        self.transaction_behaviour.failed_processing(ledger_api_dialogue)\n\n        # after\n        assert self.transaction_behaviour.processing_time == 0.0\n        assert self.transaction_behaviour.processing is None\n\n    def test_finish_processing_ii(self):\n        \"\"\"Test the finish_processing method of the transaction behaviour where ledger_api_dialogue's dialogue_label is NOT in self.timedout.\"\"\"\n        # setup\n        ledger_api_dialogue, fipa_dialogue = self._setup_fipa_ledger_api_dialogues(self)\n\n        # operation\n        with pytest.raises(ValueError) as err:\n            self.transaction_behaviour.finish_processing(ledger_api_dialogue)\n\n        # after\n        assert (\n            err.value.args[0]\n            == f\"Non-matching dialogues in transaction behaviour: {self.transaction_behaviour.processing} and {ledger_api_dialogue}\"\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the transaction behaviour.\"\"\"\n        assert self.transaction_behaviour.teardown() is None\n        self.assert_quantity_in_outbox(0)\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_skills/test_generic_buyer/test_dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the dialogue classes of the generic buyer skill.\"\"\"\n\nfrom pathlib import Path\nfrom typing import cast\n\nimport pytest\n\nfrom aea.exceptions import AEAEnforceError\nfrom aea.helpers.transaction.base import Terms\nfrom aea.protocols.dialogue.base import DialogueLabel\nfrom aea.test_tools.test_skill import BaseSkillTestCase, COUNTERPARTY_AGENT_ADDRESS\n\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.protocols.fipa.message import FipaMessage\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.protocols.signing.message import SigningMessage\nfrom packages.fetchai.skills.generic_buyer.dialogues import (\n    DefaultDialogue,\n    DefaultDialogues,\n    FipaDialogue,\n    FipaDialogues,\n    LedgerApiDialogue,\n    LedgerApiDialogues,\n    OefSearchDialogue,\n    OefSearchDialogues,\n    SigningDialogue,\n    SigningDialogues,\n)\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass TestDialogues(BaseSkillTestCase):\n    \"\"\"Test dialogue classes of generic buyer.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"generic_buyer\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.default_dialogues = cast(\n            DefaultDialogues, cls._skill.skill_context.default_dialogues\n        )\n        cls.fipa_dialogues = cast(\n            FipaDialogues, cls._skill.skill_context.fipa_dialogues\n        )\n        cls.ledger_api_dialogues = cast(\n            LedgerApiDialogues, cls._skill.skill_context.ledger_api_dialogues\n        )\n        cls.oef_search_dialogues = cast(\n            OefSearchDialogues, cls._skill.skill_context.oef_search_dialogues\n        )\n        cls.signing_dialogues = cast(\n            SigningDialogues, cls._skill.skill_context.signing_dialogues\n        )\n\n    def test_default_dialogues(self):\n        \"\"\"Test the DefaultDialogues class.\"\"\"\n        _, dialogue = self.default_dialogues.create(\n            counterparty=COUNTERPARTY_AGENT_ADDRESS,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"some_content\",\n        )\n        assert dialogue.role == DefaultDialogue.Role.AGENT\n        assert dialogue.self_address == self.skill.skill_context.agent_address\n\n    def test_fipa_dialogue(self):\n        \"\"\"Test the FipaDialogue class.\"\"\"\n        fipa_dialogue = FipaDialogue(\n            DialogueLabel(\n                (\"\", \"\"),\n                COUNTERPARTY_AGENT_ADDRESS,\n                self.skill.skill_context.agent_address,\n            ),\n            self.skill.skill_context.agent_address,\n            role=DefaultDialogue.Role.AGENT,\n        )\n\n        # terms\n        with pytest.raises(AEAEnforceError, match=\"Terms not set!\"):\n            assert fipa_dialogue.terms\n        terms = Terms(\n            \"some_ledger_id\",\n            self.skill.skill_context.agent_address,\n            \"counterprty\",\n            {\"currency_id\": 50},\n            {\"good_id\": -10},\n            \"some_nonce\",\n        )\n        fipa_dialogue.terms = terms\n        with pytest.raises(AEAEnforceError, match=\"Terms already set!\"):\n            fipa_dialogue.terms = terms\n        assert fipa_dialogue.terms == terms\n\n    def test_fipa_dialogues(self):\n        \"\"\"Test the FipaDialogues class.\"\"\"\n        _, dialogue = self.fipa_dialogues.create(\n            counterparty=COUNTERPARTY_AGENT_ADDRESS,\n            performative=FipaMessage.Performative.CFP,\n            query=\"some_query\",\n        )\n        assert dialogue.role == FipaDialogue.Role.BUYER\n        assert dialogue.self_address == self.skill.skill_context.agent_address\n\n    def test_ledger_api_dialogue(self):\n        \"\"\"Test the LedgerApiDialogue class.\"\"\"\n        ledger_api_dialogue = LedgerApiDialogue(\n            DialogueLabel(\n                (\"\", \"\"),\n                COUNTERPARTY_AGENT_ADDRESS,\n                self.skill.skill_context.agent_address,\n            ),\n            self.skill.skill_context.agent_address,\n            role=LedgerApiDialogue.Role.AGENT,\n        )\n\n        # associated_fipa_dialogue\n        with pytest.raises(AEAEnforceError, match=\"FipaDialogue not set!\"):\n            assert ledger_api_dialogue.associated_fipa_dialogue\n        fipa_dialogue = FipaDialogue(\n            DialogueLabel(\n                (\"\", \"\"),\n                COUNTERPARTY_AGENT_ADDRESS,\n                self.skill.skill_context.agent_address,\n            ),\n            self.skill.skill_context.agent_address,\n            role=FipaDialogue.Role.BUYER,\n        )\n        ledger_api_dialogue.associated_fipa_dialogue = fipa_dialogue\n        with pytest.raises(AEAEnforceError, match=\"FipaDialogue already set!\"):\n            ledger_api_dialogue.associated_fipa_dialogue = fipa_dialogue\n        assert ledger_api_dialogue.associated_fipa_dialogue == fipa_dialogue\n\n    def test_ledger_api_dialogues(self):\n        \"\"\"Test the LedgerApiDialogues class.\"\"\"\n        _, dialogue = self.ledger_api_dialogues.create(\n            counterparty=COUNTERPARTY_AGENT_ADDRESS,\n            performative=LedgerApiMessage.Performative.GET_BALANCE,\n            ledger_id=\"some_ledger_id\",\n            address=\"some_address\",\n        )\n        assert dialogue.role == LedgerApiDialogue.Role.AGENT\n        assert dialogue.self_address == str(self.skill.public_id)\n\n    def test_oef_search_dialogues(self):\n        \"\"\"Test the OefSearchDialogues class.\"\"\"\n        _, dialogue = self.oef_search_dialogues.create(\n            counterparty=COUNTERPARTY_AGENT_ADDRESS,\n            performative=OefSearchMessage.Performative.SEARCH_SERVICES,\n            query=\"some_query\",\n        )\n        assert dialogue.role == OefSearchDialogue.Role.AGENT\n        assert dialogue.self_address == str(self.skill.public_id)\n\n    def test_signing_dialogue(self):\n        \"\"\"Test the SigningDialogue class.\"\"\"\n        signing_dialogue = SigningDialogue(\n            DialogueLabel(\n                (\"\", \"\"),\n                COUNTERPARTY_AGENT_ADDRESS,\n                self.skill.skill_context.agent_address,\n            ),\n            self.skill.skill_context.agent_address,\n            role=SigningDialogue.Role.SKILL,\n        )\n\n        # associated_ledger_api_dialogue\n        with pytest.raises(AEAEnforceError, match=\"LedgerApiDialogue not set!\"):\n            assert signing_dialogue.associated_ledger_api_dialogue\n        ledger_api_dialogue = LedgerApiDialogue(\n            DialogueLabel(\n                (\"\", \"\"),\n                COUNTERPARTY_AGENT_ADDRESS,\n                self.skill.skill_context.agent_address,\n            ),\n            self.skill.skill_context.agent_address,\n            role=LedgerApiDialogue.Role.AGENT,\n        )\n        signing_dialogue.associated_ledger_api_dialogue = ledger_api_dialogue\n        with pytest.raises(AEAEnforceError, match=\"LedgerApiDialogue already set!\"):\n            signing_dialogue.associated_ledger_api_dialogue = ledger_api_dialogue\n        assert signing_dialogue.associated_ledger_api_dialogue == ledger_api_dialogue\n\n    def test_signing_dialogues(self):\n        \"\"\"Test the SigningDialogues class.\"\"\"\n        _, dialogue = self.signing_dialogues.create(\n            counterparty=COUNTERPARTY_AGENT_ADDRESS,\n            performative=SigningMessage.Performative.SIGN_TRANSACTION,\n            terms=\"some_terms\",\n            raw_transaction=\"some_raw_transaction\",\n        )\n        assert dialogue.role == SigningDialogue.Role.SKILL\n        assert dialogue.self_address == str(self.skill.public_id)\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_skills/test_generic_buyer/test_handlers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the handler classes of the generic buyer skill.\"\"\"\n\nimport logging\nfrom pathlib import Path\nfrom typing import cast\nfrom unittest.mock import patch\n\nimport pytest\n\nfrom aea.crypto.ledger_apis import LedgerApis\nfrom aea.helpers.search.models import Description\nfrom aea.helpers.transaction.base import (\n    RawTransaction,\n    SignedTransaction,\n    Terms,\n    TransactionDigest,\n    TransactionReceipt,\n)\nfrom aea.protocols.dialogue.base import DialogueMessage\nfrom aea.test_tools.test_skill import BaseSkillTestCase, COUNTERPARTY_AGENT_ADDRESS\n\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.protocols.fipa.message import FipaMessage\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.protocols.signing.message import SigningMessage\nfrom packages.fetchai.skills.generic_buyer.behaviours import GenericTransactionBehaviour\nfrom packages.fetchai.skills.generic_buyer.dialogues import (\n    FipaDialogue,\n    FipaDialogues,\n    LedgerApiDialogue,\n    LedgerApiDialogues,\n    OefSearchDialogues,\n    SigningDialogue,\n    SigningDialogues,\n)\nfrom packages.fetchai.skills.generic_buyer.handlers import (\n    GenericFipaHandler,\n    GenericLedgerApiHandler,\n    GenericOefSearchHandler,\n    GenericSigningHandler,\n    LEDGER_API_ADDRESS,\n)\nfrom packages.fetchai.skills.generic_buyer.strategy import GenericStrategy\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass TestGenericFipaHandler(BaseSkillTestCase):\n    \"\"\"Test fipa handler of generic buyer.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"generic_buyer\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.fipa_handler = cast(\n            GenericFipaHandler, cls._skill.skill_context.handlers.fipa\n        )\n        cls.strategy = cast(GenericStrategy, cls._skill.skill_context.strategy)\n        cls.fipa_dialogues = cast(\n            FipaDialogues, cls._skill.skill_context.fipa_dialogues\n        )\n        cls.list_of_messages = (\n            DialogueMessage(FipaMessage.Performative.CFP, {\"query\": \"some_query\"}),\n            DialogueMessage(\n                FipaMessage.Performative.PROPOSE, {\"proposal\": \"some_proposal\"}\n            ),\n            DialogueMessage(FipaMessage.Performative.ACCEPT),\n            DialogueMessage(\n                FipaMessage.Performative.MATCH_ACCEPT_W_INFORM,\n                {\"info\": {\"address\": \"some_term_sender_address\"}},\n            ),\n            DialogueMessage(\n                FipaMessage.Performative.INFORM,\n                {\"info\": {\"transaction_digest\": \"some_transaction_digest_body\"}},\n            ),\n        )\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the fipa handler.\"\"\"\n        assert self.fipa_handler.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle_unidentified_dialogue(self):\n        \"\"\"Test the _handle_unidentified_dialogue method of the fipa handler.\"\"\"\n        # setup\n        incorrect_dialogue_reference = (\"\", \"\")\n        incoming_message = self.build_incoming_message(\n            message_type=FipaMessage,\n            dialogue_reference=incorrect_dialogue_reference,\n            performative=FipaMessage.Performative.ACCEPT,\n        )\n\n        # operation\n        with patch.object(self.fipa_handler.context.logger, \"log\") as mock_logger:\n            self.fipa_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received invalid fipa message={incoming_message}, unidentified dialogue.\",\n        )\n\n        self.assert_quantity_in_outbox(1)\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=DefaultMessage,\n            performative=DefaultMessage.Performative.ERROR,\n            to=incoming_message.sender,\n            sender=self.skill.skill_context.agent_address,\n            error_code=DefaultMessage.ErrorCode.INVALID_DIALOGUE,\n            error_msg=\"Invalid dialogue.\",\n            error_data={\"fipa_message\": incoming_message.encode()},\n        )\n        assert has_attributes, error_str\n\n    def test_handle_propose_is_affordable_and_is_acceptable(self):\n        \"\"\"Test the _handle_propose method of the fipa handler.\"\"\"\n        # setup\n        proposal = Description(\n            {\n                \"ledger_id\": self.strategy.ledger_id,\n                \"price\": 100,\n                \"currency_id\": \"FET\",\n                \"service_id\": \"some_service_id\",\n                \"quantity\": 1,\n                \"tx_nonce\": \"some_tx_nonce\",\n            }\n        )\n        fipa_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.fipa_dialogues,\n            messages=self.list_of_messages[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=fipa_dialogue,\n            performative=FipaMessage.Performative.PROPOSE,\n            proposal=proposal,\n        )\n\n        # operation\n        with patch.object(\n            self.strategy,\n            \"is_acceptable_proposal\",\n            return_value=True,\n        ):\n            with patch.object(\n                self.strategy,\n                \"is_affordable_proposal\",\n                return_value=True,\n            ):\n                with patch.object(\n                    self.fipa_handler.context.logger, \"log\"\n                ) as mock_logger:\n                    self.fipa_handler.handle(incoming_message)\n\n        # after\n        incoming_message = cast(FipaMessage, incoming_message)\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received proposal={incoming_message.proposal.values} from sender={COUNTERPARTY_AGENT_ADDRESS[-5:]}\",\n        )\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"accepting the proposal from sender={COUNTERPARTY_AGENT_ADDRESS[-5:]}\",\n        )\n\n        self.assert_quantity_in_outbox(1)\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=FipaMessage,\n            performative=FipaMessage.Performative.ACCEPT,\n            to=incoming_message.sender,\n            sender=self.skill.skill_context.agent_address,\n            target=incoming_message.message_id,\n        )\n        assert has_attributes, error_str\n\n    def test_handle_propose_not_is_affordable_or_not_is_acceptable(self):\n        \"\"\"Test the _handle_propose method of the fipa handler.\"\"\"\n        # setup\n        proposal = Description(\n            {\n                \"ledger_id\": self.strategy.ledger_id,\n                \"price\": 100,\n                \"currency_id\": \"FET\",\n                \"service_id\": \"some_service_id\",\n                \"quantity\": 1,\n                \"tx_nonce\": \"some_tx_nonce\",\n            }\n        )\n        fipa_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.fipa_dialogues,\n            messages=self.list_of_messages[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=fipa_dialogue,\n            performative=FipaMessage.Performative.PROPOSE,\n            proposal=proposal,\n        )\n\n        # operation\n        with patch.object(\n            self.strategy,\n            \"is_acceptable_proposal\",\n            return_value=False,\n        ):\n            with patch.object(\n                self.strategy,\n                \"is_affordable_proposal\",\n                return_value=False,\n            ):\n                with patch.object(\n                    self.fipa_handler.context.logger, \"log\"\n                ) as mock_logger:\n                    self.fipa_handler.handle(incoming_message)\n\n        # after\n        incoming_message = cast(FipaMessage, incoming_message)\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received proposal={incoming_message.proposal.values} from sender={COUNTERPARTY_AGENT_ADDRESS[-5:]}\",\n        )\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"declining the proposal from sender={COUNTERPARTY_AGENT_ADDRESS[-5:]}\",\n        )\n\n        self.assert_quantity_in_outbox(1)\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=FipaMessage,\n            performative=FipaMessage.Performative.DECLINE,\n            to=incoming_message.sender,\n            sender=self.skill.skill_context.agent_address,\n            target=incoming_message.message_id,\n        )\n        assert has_attributes, error_str\n\n    def test_handle_decline_decline_cfp(self):\n        \"\"\"Test the _handle_decline method of the fipa handler where the end state is decline_cfp.\"\"\"\n        # setup\n        fipa_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.fipa_dialogues,\n            messages=self.list_of_messages[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=fipa_dialogue,\n            performative=FipaMessage.Performative.DECLINE,\n        )\n\n        # before\n        for (\n            end_state_numbers\n        ) in self.fipa_dialogues.dialogue_stats.self_initiated.values():\n            assert end_state_numbers == 0\n        for (\n            end_state_numbers\n        ) in self.fipa_dialogues.dialogue_stats.other_initiated.values():\n            assert end_state_numbers == 0\n\n        # operation\n        with patch.object(self.fipa_handler.context.logger, \"log\") as mock_logger:\n            self.fipa_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received DECLINE from sender={COUNTERPARTY_AGENT_ADDRESS[-5:]}\",\n        )\n\n        for (\n            end_state_numbers\n        ) in self.fipa_dialogues.dialogue_stats.other_initiated.values():\n            assert end_state_numbers == 0\n        for (\n            end_state,\n            end_state_numbers,\n        ) in self.fipa_dialogues.dialogue_stats.self_initiated.items():\n            if end_state == FipaDialogue.EndState.DECLINED_CFP:\n                assert end_state_numbers == 1\n            else:\n                assert end_state_numbers == 0\n\n    def test_handle_decline_decline_accept(self):\n        \"\"\"Test the _handle_decline method of the fipa handler where the end state is decline_accept.\"\"\"\n        # setup\n        fipa_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.fipa_dialogues,\n            messages=self.list_of_messages[:3],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=fipa_dialogue,\n            performative=FipaMessage.Performative.DECLINE,\n        )\n\n        # before\n        for end_state_numbers in list(\n            self.fipa_dialogues.dialogue_stats.self_initiated.values()\n        ) + list(self.fipa_dialogues.dialogue_stats.other_initiated.values()):\n            assert end_state_numbers == 0\n\n        # operation\n        with patch.object(self.fipa_handler.context.logger, \"log\") as mock_logger:\n            self.fipa_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received DECLINE from sender={COUNTERPARTY_AGENT_ADDRESS[-5:]}\",\n        )\n\n        for (\n            end_state_numbers\n        ) in self.fipa_dialogues.dialogue_stats.other_initiated.values():\n            assert end_state_numbers == 0\n        for (\n            end_state,\n            end_state_numbers,\n        ) in self.fipa_dialogues.dialogue_stats.self_initiated.items():\n            if end_state == FipaDialogue.EndState.DECLINED_ACCEPT:\n                assert end_state_numbers == 1\n            else:\n                assert end_state_numbers == 0\n\n    def test_handle_match_accept_is_ledger_tx(self):\n        \"\"\"Test the _handle_match_accept method of the fipa handler where is_ledger_tx is True.\"\"\"\n        # setup\n        self.strategy._is_ledger_tx = True\n\n        fipa_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.fipa_dialogues,\n            messages=self.list_of_messages[:3],\n        )\n        fipa_dialogue.terms = Terms(\n            \"some_ledger_id\",\n            self.skill.skill_context.agent_address,\n            \"counterprty\",\n            {\"currency_id\": 50},\n            {\"good_id\": -10},\n            \"some_nonce\",\n        )\n        incoming_message = cast(\n            FipaMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=fipa_dialogue,\n                performative=FipaMessage.Performative.MATCH_ACCEPT_W_INFORM,\n                info={\"info\": {\"address\": \"some_term_sender_address\"}},\n            ),\n        )\n\n        # operation\n        with patch.object(\n            self.fipa_handler.context.logger, \"log\"\n        ) as mock_logger_handler:\n            self.fipa_handler.handle(incoming_message)\n\n        # after\n        mock_logger_handler.assert_any_call(\n            logging.INFO,\n            f\"received MATCH_ACCEPT_W_INFORM from sender={COUNTERPARTY_AGENT_ADDRESS[-5:]} with info={incoming_message.info}\",\n        )\n\n        # operation\n        with patch.object(\n            self.fipa_handler.context.behaviours.transaction.context.logger, \"log\"\n        ) as _:\n            self.fipa_handler.context.behaviours.transaction.act()\n\n        self.assert_quantity_in_outbox(1)\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=LedgerApiMessage,\n            performative=LedgerApiMessage.Performative.GET_RAW_TRANSACTION,\n            to=LEDGER_API_ADDRESS,\n            sender=str(self.skill.skill_context.skill_id),\n            terms=fipa_dialogue.terms,\n        )\n        assert has_attributes, error_str\n\n    def test_handle_match_accept_not_is_ledger_tx(self):\n        \"\"\"Test the _handle_match_accept method of the fipa handler where is_ledger_tx is False.\"\"\"\n        # setup\n        self.strategy._is_ledger_tx = False\n\n        fipa_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.fipa_dialogues,\n            messages=self.list_of_messages[:3],\n        )\n        incoming_message = cast(\n            FipaMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=fipa_dialogue,\n                performative=FipaMessage.Performative.MATCH_ACCEPT_W_INFORM,\n                info={\"info\": {\"address\": \"some_term_sender_address\"}},\n            ),\n        )\n\n        # operation\n        with patch.object(self.fipa_handler.context.logger, \"log\") as mock_logger:\n            self.fipa_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received MATCH_ACCEPT_W_INFORM from sender={COUNTERPARTY_AGENT_ADDRESS[-5:]} with info={incoming_message.info}\",\n        )\n\n        self.assert_quantity_in_outbox(1)\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=FipaMessage,\n            performative=FipaMessage.Performative.INFORM,\n            to=incoming_message.sender,\n            sender=self.skill.skill_context.agent_address,\n            target=incoming_message.message_id,\n            info={\"Done\": \"Sending payment via bank transfer\"},\n        )\n        assert has_attributes, error_str\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"informing counterparty={COUNTERPARTY_AGENT_ADDRESS[-5:]} of payment.\",\n        )\n\n    def test_handle_inform_with_data(self):\n        \"\"\"Test the _handle_inform method of the fipa handler where info has data.\"\"\"\n        # setup\n        fipa_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.fipa_dialogues,\n            messages=self.list_of_messages[:4],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=fipa_dialogue,\n            performative=FipaMessage.Performative.INFORM,\n            info={\"data_name\": \"data\"},\n        )\n\n        # before\n        for end_state_numbers in list(\n            self.fipa_dialogues.dialogue_stats.self_initiated.values()\n        ) + list(self.fipa_dialogues.dialogue_stats.other_initiated.values()):\n            assert end_state_numbers == 0\n\n        # operation\n        with patch.object(self.fipa_handler.context.logger, \"log\") as mock_logger:\n            self.fipa_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received INFORM from sender={COUNTERPARTY_AGENT_ADDRESS[-5:]}\",\n        )\n        mock_logger.assert_any_call(\n            logging.INFO, \"received the following data={'data_name': 'data'}\"\n        )\n\n        for (\n            end_state_numbers\n        ) in self.fipa_dialogues.dialogue_stats.other_initiated.values():\n            assert end_state_numbers == 0\n        for (\n            end_state,\n            end_state_numbers,\n        ) in self.fipa_dialogues.dialogue_stats.self_initiated.items():\n            if end_state == FipaDialogue.EndState.SUCCESSFUL:\n                assert end_state_numbers == 1\n            else:\n                assert end_state_numbers == 0\n\n    def test_handle_inform_without_data(self):\n        \"\"\"Test the _handle_inform method of the fipa handler where info has NO data.\"\"\"\n        # setup\n        fipa_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.fipa_dialogues,\n            messages=self.list_of_messages[:4],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=fipa_dialogue,\n            performative=FipaMessage.Performative.INFORM,\n            info={},\n        )\n\n        # operation\n        with patch.object(self.fipa_handler.context.logger, \"log\") as mock_logger:\n            self.fipa_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received INFORM from sender={COUNTERPARTY_AGENT_ADDRESS[-5:]}\",\n        )\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received no data from sender={COUNTERPARTY_AGENT_ADDRESS[-5:]}\",\n        )\n\n    def test_handle_invalid(self):\n        \"\"\"Test the _handle_invalid method of the fipa handler.\"\"\"\n        # setup\n        fipa_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.fipa_dialogues,\n            messages=self.list_of_messages[:2],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=fipa_dialogue,\n            performative=FipaMessage.Performative.ACCEPT,\n        )\n\n        # operation\n        with patch.object(self.fipa_handler.context.logger, \"log\") as mock_logger:\n            self.fipa_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"cannot handle fipa message of performative={incoming_message.performative} in dialogue={fipa_dialogue}.\",\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the fipa handler.\"\"\"\n        assert self.fipa_handler.teardown() is None\n        self.assert_quantity_in_outbox(0)\n\n\nclass TestGenericOefSearchHandler(BaseSkillTestCase):\n    \"\"\"Test oef search handler of generic buyer.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"generic_buyer\")\n    is_agent_to_agent_messages = False\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.oef_search_handler = cast(\n            GenericOefSearchHandler, cls._skill.skill_context.handlers.oef_search\n        )\n        cls.strategy = cast(GenericStrategy, cls._skill.skill_context.strategy)\n        cls.oef_dialogues = cast(\n            OefSearchDialogues, cls._skill.skill_context.oef_search_dialogues\n        )\n        cls.list_of_messages = (\n            DialogueMessage(\n                OefSearchMessage.Performative.SEARCH_SERVICES, {\"query\": \"some_query\"}\n            ),\n        )\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the oef_search handler.\"\"\"\n        assert self.oef_search_handler.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle_unidentified_dialogue(self):\n        \"\"\"Test the _handle_unidentified_dialogue method of the oef_search handler.\"\"\"\n        # setup\n        incorrect_dialogue_reference = (\"\", \"\")\n        incoming_message = self.build_incoming_message(\n            message_type=OefSearchMessage,\n            dialogue_reference=incorrect_dialogue_reference,\n            performative=OefSearchMessage.Performative.SEARCH_SERVICES,\n        )\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received invalid oef_search message={incoming_message}, unidentified dialogue.\",\n        )\n\n    def test_handle_error(self):\n        \"\"\"Test the _handle_error method of the oef_search handler.\"\"\"\n        # setup\n        oef_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_dialogues,\n            messages=self.list_of_messages[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=oef_dialogue,\n            performative=OefSearchMessage.Performative.OEF_ERROR,\n            oef_error_operation=OefSearchMessage.OefErrorOperation.SEARCH_SERVICES,\n        )\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received oef_search error message={incoming_message} in dialogue={oef_dialogue}.\",\n        )\n\n    def test_handle_search_zero_agents(self):\n        \"\"\"Test the _handle_search method of the oef_search handler.\"\"\"\n        # setup\n        oef_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_dialogues,\n            messages=self.list_of_messages[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=oef_dialogue,\n            performative=OefSearchMessage.Performative.SEARCH_RESULT,\n            agents=tuple(),\n            agents_info=OefSearchMessage.AgentsInfo({}),\n        )\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"found no agents in dialogue={oef_dialogue}, continue searching.\",\n        )\n\n    def test_handle_search_i(self):\n        \"\"\"Test the _handle_search method of the oef_search handler where is_stop_searching_on_result is True.\"\"\"\n        # setup\n        self.strategy._max_negotiations = 3\n        self.strategy._is_stop_searching_on_result = True\n        self.strategy._is_searching = True\n\n        oef_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_dialogues,\n            messages=self.list_of_messages[:1],\n        )\n        agents = (\"agnt1\", \"agnt2\")\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=oef_dialogue,\n            performative=OefSearchMessage.Performative.SEARCH_RESULT,\n            agents=agents,\n            agents_info=OefSearchMessage.AgentsInfo(\n                {\"agent_1\": {\"key_1\": \"value_1\"}, \"agent_2\": {\"key_2\": \"value_2\"}}\n            ),\n        )\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO, f\"found agents={list(agents)}, stopping search.\"\n        )\n\n        assert self.strategy.is_searching is False\n\n        self.assert_quantity_in_outbox(len(agents))\n        for agent in agents:\n            has_attributes, error_str = self.message_has_attributes(\n                actual_message=self.get_message_from_outbox(),\n                message_type=FipaMessage,\n                performative=FipaMessage.Performative.CFP,\n                to=agent,\n                sender=self.skill.skill_context.agent_address,\n                target=0,\n                query=self.strategy.get_service_query(),\n            )\n            assert has_attributes, error_str\n            mock_logger.assert_any_call(logging.INFO, f\"sending CFP to agent={agent}\")\n\n    def test_handle_search_ii(self):\n        \"\"\"Test the _handle_search method of the oef_search handler where is_stop_searching_on_result is False.\"\"\"\n        # setup\n        self.strategy._max_negotiations = 3\n        self.strategy._is_stop_searching_on_result = False\n        self.strategy._is_searching = True\n\n        oef_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_dialogues,\n            messages=self.list_of_messages[:1],\n        )\n        agents = (\"agnt1\", \"agnt2\")\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=oef_dialogue,\n            performative=OefSearchMessage.Performative.SEARCH_RESULT,\n            agents=agents,\n            agents_info=OefSearchMessage.AgentsInfo(\n                {\"agent_1\": {\"key_1\": \"value_1\"}, \"agent_2\": {\"key_2\": \"value_2\"}}\n            ),\n        )\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(logging.INFO, f\"found agents={list(agents)}.\")\n\n        assert self.strategy.is_searching is True\n\n        self.assert_quantity_in_outbox(len(agents))\n        for agent in agents:\n            has_attributes, error_str = self.message_has_attributes(\n                actual_message=self.get_message_from_outbox(),\n                message_type=FipaMessage,\n                performative=FipaMessage.Performative.CFP,\n                to=agent,\n                sender=self.skill.skill_context.agent_address,\n                target=0,\n                query=self.strategy.get_service_query(),\n            )\n            assert has_attributes, error_str\n            mock_logger.assert_any_call(logging.INFO, f\"sending CFP to agent={agent}\")\n\n    def test_handle_search_more_than_max_negotiation(self):\n        \"\"\"Test the _handle_search method of the oef_search handler where number of agents is more than max_negotiation.\"\"\"\n        # setup\n        self.strategy._max_negotiations = 1\n        oef_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_dialogues,\n            messages=self.list_of_messages[:1],\n        )\n        agents = (\"agnt1\", \"agnt2\")\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=oef_dialogue,\n            performative=OefSearchMessage.Performative.SEARCH_RESULT,\n            agents=agents,\n            agents_info=OefSearchMessage.AgentsInfo(\n                {\"agent_1\": {\"key_1\": \"value_1\"}, \"agent_2\": {\"key_2\": \"value_2\"}}\n            ),\n        )\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO, f\"found agents={list(agents)}, stopping search.\"\n        )\n\n        assert not self.strategy.is_searching\n\n        self.assert_quantity_in_outbox(self.strategy._max_negotiations)\n        for idx in range(0, self.strategy._max_negotiations):\n            has_attributes, error_str = self.message_has_attributes(\n                actual_message=self.get_message_from_outbox(),\n                message_type=FipaMessage,\n                performative=FipaMessage.Performative.CFP,\n                to=agents[idx],\n                sender=self.skill.skill_context.agent_address,\n                target=0,\n                query=self.strategy.get_service_query(),\n            )\n            assert has_attributes, error_str\n            mock_logger.assert_any_call(\n                logging.INFO, f\"sending CFP to agent={agents[idx]}\"\n            )\n\n    def test_handle_invalid(self):\n        \"\"\"Test the _handle_invalid method of the oef_search handler.\"\"\"\n        # setup\n        invalid_performative = OefSearchMessage.Performative.UNREGISTER_SERVICE\n        incoming_message = self.build_incoming_message(\n            message_type=OefSearchMessage,\n            dialogue_reference=(\"1\", \"\"),\n            performative=invalid_performative,\n            service_description=\"some_service_description\",\n        )\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"cannot handle oef_search message of performative={invalid_performative} in dialogue={self.oef_dialogues.get_dialogue(incoming_message)}.\",\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the oef_search handler.\"\"\"\n        assert self.oef_search_handler.teardown() is None\n        self.assert_quantity_in_outbox(0)\n\n\nclass TestGenericSigningHandler(BaseSkillTestCase):\n    \"\"\"Test signing handler of generic buyer.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"generic_buyer\")\n    is_agent_to_agent_messages = False\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.signing_handler = cast(\n            GenericSigningHandler, cls._skill.skill_context.handlers.signing\n        )\n        cls.strategy = cast(GenericStrategy, cls._skill.skill_context.strategy)\n        cls.fipa_dialogues = cast(\n            FipaDialogues, cls._skill.skill_context.fipa_dialogues\n        )\n        cls.ledger_api_dialogues = cast(\n            LedgerApiDialogues, cls._skill.skill_context.ledger_api_dialogues\n        )\n        cls.signing_dialogues = cast(\n            SigningDialogues, cls._skill.skill_context.signing_dialogues\n        )\n        cls.terms = Terms(\n            \"some_ledger_id\",\n            cls._skill.skill_context.agent_address,\n            \"counterprty\",\n            {\"currency_id\": 50},\n            {\"good_id\": -10},\n            \"some_nonce\",\n        )\n        cls.list_of_fipa_messages = (\n            DialogueMessage(FipaMessage.Performative.CFP, {\"query\": \"some_query\"}),\n            DialogueMessage(\n                FipaMessage.Performative.PROPOSE, {\"proposal\": \"some_proposal\"}\n            ),\n            DialogueMessage(FipaMessage.Performative.ACCEPT),\n            DialogueMessage(\n                FipaMessage.Performative.MATCH_ACCEPT_W_INFORM,\n                {\"info\": {\"address\": \"some_term_sender_address\"}},\n            ),\n            DialogueMessage(\n                FipaMessage.Performative.INFORM,\n                {\"info\": {\"transaction_digest\": \"some_transaction_digest_body\"}},\n            ),\n        )\n        cls.list_of_signing_messages = (\n            DialogueMessage(\n                SigningMessage.Performative.SIGN_TRANSACTION,\n                {\n                    \"terms\": cls.terms,\n                    \"raw_transaction\": SigningMessage.RawTransaction(\n                        \"some_ledger_id\", {\"some_key\": \"some_value\"}\n                    ),\n                },\n            ),\n        )\n        cls.list_of_ledger_api_messages = (\n            DialogueMessage(LedgerApiMessage.Performative.GET_RAW_TRANSACTION, {}),\n            DialogueMessage(LedgerApiMessage.Performative.RAW_TRANSACTION, {}),\n            DialogueMessage(LedgerApiMessage.Performative.SEND_SIGNED_TRANSACTION, {}),\n            DialogueMessage(LedgerApiMessage.Performative.TRANSACTION_DIGEST, {}),\n        )\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the signing handler.\"\"\"\n        assert self.signing_handler.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle_unidentified_dialogue(self):\n        \"\"\"Test the _handle_unidentified_dialogue method of the signing handler.\"\"\"\n        # setup\n        incorrect_dialogue_reference = (\"\", \"\")\n        incoming_message = self.build_incoming_message(\n            message_type=SigningMessage,\n            dialogue_reference=incorrect_dialogue_reference,\n            performative=SigningMessage.Performative.ERROR,\n            error_code=SigningMessage.ErrorCode.UNSUCCESSFUL_MESSAGE_SIGNING,\n            to=str(self.skill.skill_context.skill_id),\n        )\n\n        # operation\n        with patch.object(self.signing_handler.context.logger, \"log\") as mock_logger:\n            self.signing_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received invalid signing message={incoming_message}, unidentified dialogue.\",\n        )\n\n    def test_handle_signed_transaction_last_ledger_api_message_is_none(\n        self,\n    ):\n        \"\"\"Test the _handle_signed_transaction method of the signing handler.\"\"\"\n        # setup\n        signing_dialogue = cast(\n            SigningDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.signing_dialogues,\n                messages=self.list_of_signing_messages[:1],\n            ),\n        )\n        ledger_api_dialogue = cast(\n            LedgerApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.ledger_api_dialogues,\n                messages=self.list_of_ledger_api_messages[:2],\n            ),\n        )\n        signing_dialogue.associated_ledger_api_dialogue = ledger_api_dialogue\n        signing_dialogue.associated_ledger_api_dialogue._incoming_messages = []\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=signing_dialogue,\n            performative=SigningMessage.Performative.SIGNED_TRANSACTION,\n            signed_transaction=SigningMessage.SignedTransaction(\n                \"some_ledger_id\", {\"some_key\": \"some_value\"}\n            ),\n        )\n\n        # operation\n        with pytest.raises(\n            ValueError, match=\"Could not retrieve last message in ledger api dialogue\"\n        ):\n            with patch.object(\n                self.signing_handler.context.logger, \"log\"\n            ) as mock_logger:\n                self.signing_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(logging.INFO, \"transaction signing was successful.\")\n\n    def test_handle_signed_transaction_last_ledger_api_message_is_not_none(\n        self,\n    ):\n        \"\"\"Test the _handle_signed_transaction method of the signing handler where the last ledger_api message is not None.\"\"\"\n        # setup\n        signing_counterparty = self.skill.skill_context.decision_maker_address\n        signing_dialogue = cast(\n            SigningDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.signing_dialogues,\n                messages=self.list_of_signing_messages[:1],\n                counterparty=signing_counterparty,\n            ),\n        )\n        ledger_api_dialogue = cast(\n            LedgerApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.ledger_api_dialogues,\n                messages=self.list_of_ledger_api_messages[:2],\n                counterparty=LEDGER_API_ADDRESS,\n            ),\n        )\n        signing_dialogue.associated_ledger_api_dialogue = ledger_api_dialogue\n        incoming_message = cast(\n            SigningMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=signing_dialogue,\n                performative=SigningMessage.Performative.SIGNED_TRANSACTION,\n                signed_transaction=SigningMessage.SignedTransaction(\n                    \"some_ledger_id\", {\"some_key\": \"some_value\"}\n                ),\n            ),\n        )\n        # operation\n        with patch.object(self.signing_handler.context.logger, \"log\") as mock_logger:\n            self.signing_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(logging.INFO, \"transaction signing was successful.\")\n\n        self.assert_quantity_in_outbox(1)\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=LedgerApiMessage,\n            performative=LedgerApiMessage.Performative.SEND_SIGNED_TRANSACTION,\n            to=LEDGER_API_ADDRESS,\n            sender=str(self.skill.skill_context.skill_id),\n            signed_transaction=incoming_message.signed_transaction,\n        )\n        assert has_attributes, error_str\n\n        mock_logger.assert_any_call(logging.INFO, \"sending transaction to ledger.\")\n\n    def test_handle_error(self):\n        \"\"\"Test the _handle_error method of the signing handler.\"\"\"\n        # setup\n        fipa_dialogue = cast(\n            FipaDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.fipa_dialogues,\n                messages=self.list_of_fipa_messages[:4],\n                counterparty=COUNTERPARTY_AGENT_ADDRESS,\n                is_agent_to_agent_messages=True,\n            ),\n        )\n\n        ledger_api_dialogue = cast(\n            LedgerApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.ledger_api_dialogues,\n                messages=self.list_of_ledger_api_messages[:4],\n                counterparty=LEDGER_API_ADDRESS,\n            ),\n        )\n        ledger_api_dialogue.associated_fipa_dialogue = fipa_dialogue\n\n        signing_counterparty = self.skill.skill_context.decision_maker_address\n        signing_dialogue = cast(\n            SigningDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.signing_dialogues,\n                messages=self.list_of_signing_messages[:1],\n                counterparty=signing_counterparty,\n            ),\n        )\n        signing_dialogue.associated_ledger_api_dialogue = ledger_api_dialogue\n\n        incoming_message = cast(\n            SigningMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=signing_dialogue,\n                performative=SigningMessage.Performative.ERROR,\n                error_code=SigningMessage.ErrorCode.UNSUCCESSFUL_TRANSACTION_SIGNING,\n            ),\n        )\n\n        # operation\n        with patch.object(\n            self.signing_handler.context.behaviours.transaction, \"failed_processing\"\n        ):\n            with patch.object(\n                self.signing_handler.context.logger, \"log\"\n            ) as mock_logger:\n                self.signing_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"transaction signing was not successful. Error_code={incoming_message.error_code} in dialogue={signing_dialogue}\",\n        )\n\n        behaviour = cast(\n            GenericTransactionBehaviour, self.skill.skill_context.behaviours.transaction\n        )\n\n        # finish_processing\n        assert behaviour.processing_time == 0.0\n        assert behaviour.processing is None\n\n    def test_handle_invalid(self):\n        \"\"\"Test the _handle_invalid method of the signing handler.\"\"\"\n        # setup\n        invalid_performative = SigningMessage.Performative.SIGN_TRANSACTION\n        incoming_message = self.build_incoming_message(\n            message_type=SigningMessage,\n            dialogue_reference=(\"1\", \"\"),\n            performative=invalid_performative,\n            terms=self.terms,\n            raw_transaction=SigningMessage.RawTransaction(\n                \"some_ledger_id\", {\"some_key\": \"some_value\"}\n            ),\n            to=str(self.skill.skill_context.skill_id),\n        )\n\n        # operation\n        with patch.object(self.signing_handler.context.logger, \"log\") as mock_logger:\n            self.signing_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"cannot handle signing message of performative={invalid_performative} in dialogue={self.signing_dialogues.get_dialogue(incoming_message)}.\",\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the signing handler.\"\"\"\n        assert self.signing_handler.teardown() is None\n        self.assert_quantity_in_outbox(0)\n\n\nclass TestGenericLedgerApiHandler(BaseSkillTestCase):\n    \"\"\"Test ledger_api handler of generic buyer.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"generic_buyer\")\n    is_agent_to_agent_messages = False\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.ledger_api_handler = cast(\n            GenericLedgerApiHandler, cls._skill.skill_context.handlers.ledger_api\n        )\n        cls.transaction_behaviour = cast(\n            GenericTransactionBehaviour, cls._skill.skill_context.behaviours.transaction\n        )\n        cls.strategy = cast(GenericStrategy, cls._skill.skill_context.strategy)\n        cls.logger = cls._skill.skill_context.logger\n\n        cls.fipa_dialogues = cast(\n            FipaDialogues, cls._skill.skill_context.fipa_dialogues\n        )\n        cls.ledger_api_dialogues = cast(\n            LedgerApiDialogues, cls._skill.skill_context.ledger_api_dialogues\n        )\n\n        cls.terms = Terms(\n            \"some_ledger_id\",\n            cls._skill.skill_context.agent_address,\n            \"counterprty\",\n            {\"currency_id\": 50},\n            {\"good_id\": -10},\n            \"some_nonce\",\n        )\n        cls.list_of_fipa_messages = (\n            DialogueMessage(FipaMessage.Performative.CFP, {\"query\": \"some_query\"}),\n            DialogueMessage(\n                FipaMessage.Performative.PROPOSE, {\"proposal\": \"some_proposal\"}\n            ),\n            DialogueMessage(FipaMessage.Performative.ACCEPT),\n            DialogueMessage(\n                FipaMessage.Performative.MATCH_ACCEPT_W_INFORM,\n                {\"info\": {\"address\": \"some_term_sender_address\"}},\n            ),\n            DialogueMessage(\n                FipaMessage.Performative.INFORM,\n                {\"info\": {\"transaction_digest\": \"some_transaction_digest_body\"}},\n            ),\n        )\n        cls.raw_transaction = RawTransaction(\n            \"some_ledger_id\", {\"some_key\": \"some_value\"}\n        )\n        cls.signed_transaction = SignedTransaction(\n            \"some_ledger_id\", {\"some_key\": \"some_value\"}\n        )\n        cls.transaction_digest = TransactionDigest(\"some_ledger_id\", \"some_body\")\n        cls.transaction_receipt = TransactionReceipt(\n            \"some_ledger_id\",\n            {\"receipt_key\": \"receipt_value\"},\n            {\"transaction_key\": \"transaction_value\"},\n        )\n        cls.list_of_ledger_api_messages = (\n            DialogueMessage(\n                LedgerApiMessage.Performative.GET_RAW_TRANSACTION, {\"terms\": cls.terms}\n            ),\n            DialogueMessage(\n                LedgerApiMessage.Performative.RAW_TRANSACTION,\n                {\"raw_transaction\": cls.raw_transaction},\n            ),\n            DialogueMessage(\n                LedgerApiMessage.Performative.SEND_SIGNED_TRANSACTION,\n                {\"signed_transaction\": cls.signed_transaction},\n            ),\n            DialogueMessage(\n                LedgerApiMessage.Performative.TRANSACTION_DIGEST,\n                {\"transaction_digest\": cls.transaction_digest},\n            ),\n            DialogueMessage(\n                LedgerApiMessage.Performative.GET_TRANSACTION_RECEIPT,\n                {\"transaction_digest\": cls.transaction_digest},\n            ),\n            DialogueMessage(\n                LedgerApiMessage.Performative.TRANSACTION_RECEIPT,\n                {\"transaction_receipt\": cls.transaction_receipt},\n            ),\n        )\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the ledger_api handler.\"\"\"\n        assert self.ledger_api_handler.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle_unidentified_dialogue(self):\n        \"\"\"Test the _handle_unidentified_dialogue method of the ledger_api handler.\"\"\"\n        # setup\n        incorrect_dialogue_reference = (\"\", \"\")\n        incoming_message = self.build_incoming_message(\n            message_type=LedgerApiMessage,\n            dialogue_reference=incorrect_dialogue_reference,\n            performative=LedgerApiMessage.Performative.GET_BALANCE,\n            ledger_id=\"some_ledger_id\",\n            address=\"some_address\",\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received invalid ledger_api message={incoming_message}, unidentified dialogue.\",\n        )\n\n    def test_handle_balance_positive_balance(self):\n        \"\"\"Test the _handle_balance method of the ledger_api handler where balance is positive.\"\"\"\n        # setup\n        balance = 10\n        ledger_api_dialogue = cast(\n            LedgerApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.ledger_api_dialogues,\n                messages=(\n                    DialogueMessage(\n                        LedgerApiMessage.Performative.GET_BALANCE,\n                        {\"ledger_id\": \"some_ledger_id\", \"address\": \"some_address\"},\n                    ),\n                ),\n                counterparty=LEDGER_API_ADDRESS,\n            ),\n        )\n        incoming_message = cast(\n            LedgerApiMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=ledger_api_dialogue,\n                performative=LedgerApiMessage.Performative.BALANCE,\n                ledger_id=\"some-Ledger_id\",\n                balance=balance,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"starting balance on {self.strategy.ledger_id} ledger={incoming_message.balance}.\",\n        )\n        assert self.strategy.balance == balance\n        assert self.strategy.is_searching\n\n    def test_handle_balance_zero_balance(self):\n        \"\"\"Test the _handle_balance method of the ledger_api handler where balance is zero.\"\"\"\n        # setup\n        balance = 0\n        ledger_api_dialogue = cast(\n            LedgerApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.ledger_api_dialogues,\n                messages=(\n                    DialogueMessage(\n                        LedgerApiMessage.Performative.GET_BALANCE,\n                        {\"ledger_id\": \"some_ledger_id\", \"address\": \"some_address\"},\n                    ),\n                ),\n                counterparty=LEDGER_API_ADDRESS,\n            ),\n        )\n        incoming_message = cast(\n            LedgerApiMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=ledger_api_dialogue,\n                performative=LedgerApiMessage.Performative.BALANCE,\n                ledger_id=\"some-Ledger_id\",\n                balance=balance,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"you have no starting balance on {self.strategy.ledger_id} ledger! Stopping skill {self.strategy.context.skill_id}.\",\n        )\n        assert not self.skill.skill_context.is_active\n\n    def test_handle_raw_transaction(self):\n        \"\"\"Test the _handle_raw_transaction method of the ledger_api handler.\"\"\"\n        # setup\n        ledger_api_dialogue = cast(\n            LedgerApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.ledger_api_dialogues,\n                messages=self.list_of_ledger_api_messages[:1],\n                counterparty=LEDGER_API_ADDRESS,\n            ),\n        )\n        fipa_dialogue = cast(\n            FipaDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.fipa_dialogues,\n                messages=self.list_of_fipa_messages[:4],\n                is_agent_to_agent_messages=True,\n            ),\n        )\n        ledger_api_dialogue.associated_fipa_dialogue = fipa_dialogue\n        fipa_dialogue.terms = self.terms\n        incoming_message = cast(\n            LedgerApiMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=ledger_api_dialogue,\n                performative=LedgerApiMessage.Performative.RAW_TRANSACTION,\n                raw_transaction=self.raw_transaction,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO, f\"received raw transaction={incoming_message}\"\n        )\n\n        message_quantity = self.get_quantity_in_decision_maker_inbox()\n        assert (\n            message_quantity == 1\n        ), f\"Invalid number of messages in decision maker queue. Expected {1}. Found {message_quantity}.\"\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_decision_maker_inbox(),\n            message_type=SigningMessage,\n            performative=SigningMessage.Performative.SIGN_TRANSACTION,\n            to=self.skill.skill_context.decision_maker_address,\n            sender=str(self.skill.skill_context.skill_id),\n            terms=self.terms,\n        )\n        assert has_attributes, error_str\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            \"proposing the transaction to the decision maker. Waiting for confirmation ...\",\n        )\n\n    def test_handle_transaction_digest(self):\n        \"\"\"Test the _handle_transaction_digest method of the ledger_api handler.\"\"\"\n        # setup\n        ledger_api_dialogue = cast(\n            LedgerApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.ledger_api_dialogues,\n                messages=self.list_of_ledger_api_messages[:3],\n                counterparty=LEDGER_API_ADDRESS,\n            ),\n        )\n        incoming_message = cast(\n            LedgerApiMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=ledger_api_dialogue,\n                performative=LedgerApiMessage.Performative.TRANSACTION_DIGEST,\n                transaction_digest=self.transaction_digest,\n            ),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"transaction was successfully submitted. Transaction digest={incoming_message.transaction_digest}\",\n        )\n\n        self.assert_quantity_in_outbox(1)\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=LedgerApiMessage,\n            performative=LedgerApiMessage.Performative.GET_TRANSACTION_RECEIPT,\n            to=incoming_message.sender,\n            sender=str(self.skill.skill_context.skill_id),\n            transaction_digest=self.transaction_digest,\n        )\n        assert has_attributes, error_str\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            \"checking transaction is settled.\",\n        )\n\n    def test_handle_transaction_receipt_i(self):\n        \"\"\"Test the _handle_transaction_receipt method of the ledger_api handler.\"\"\"\n        # setup\n        ledger_api_dialogue = cast(\n            LedgerApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.ledger_api_dialogues,\n                messages=self.list_of_ledger_api_messages[:5],\n                counterparty=LEDGER_API_ADDRESS,\n            ),\n        )\n        fipa_dialogue = cast(\n            FipaDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.fipa_dialogues,\n                messages=self.list_of_fipa_messages[:4],\n                is_agent_to_agent_messages=True,\n            ),\n        )\n        ledger_api_dialogue.associated_fipa_dialogue = fipa_dialogue\n        fipa_dialogue.terms = self.terms\n        incoming_message = cast(\n            LedgerApiMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=ledger_api_dialogue,\n                performative=LedgerApiMessage.Performative.TRANSACTION_RECEIPT,\n                transaction_receipt=self.transaction_receipt,\n            ),\n        )\n\n        # operation\n        with patch.object(\n            self.ledger_api_handler.context.behaviours.transaction, \"finish_processing\"\n        ):\n            with patch.object(LedgerApis, \"is_transaction_settled\", return_value=True):\n                with patch.object(self.logger, \"log\") as mock_logger:\n                    self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"transaction confirmed, informing counterparty={fipa_dialogue.dialogue_label.dialogue_opponent_addr[-5:]} of transaction digest.\",\n        )\n\n        self.assert_quantity_in_outbox(1)\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=FipaMessage,\n            performative=FipaMessage.Performative.INFORM,\n            to=COUNTERPARTY_AGENT_ADDRESS,\n            sender=self.skill.skill_context.agent_address,\n            info={\"transaction_digest\": self.transaction_digest.body},\n        )\n        assert has_attributes, error_str\n\n    def test_handle_transaction_receipt_ii(self):\n        \"\"\"Test the _handle_transaction_receipt method of the ledger_api handler where fipa dialogue's last_incoming_message is None.\"\"\"\n        # setup\n        ledger_api_dialogue = cast(\n            LedgerApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.ledger_api_dialogues,\n                messages=self.list_of_ledger_api_messages[:5],\n                counterparty=LEDGER_API_ADDRESS,\n            ),\n        )\n        fipa_dialogue = cast(\n            FipaDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.fipa_dialogues,\n                messages=self.list_of_fipa_messages[:4],\n                is_agent_to_agent_messages=True,\n            ),\n        )\n        ledger_api_dialogue.associated_fipa_dialogue = fipa_dialogue\n\n        fipa_dialogue._incoming_messages = []\n\n        fipa_dialogue.terms = self.terms\n        incoming_message = cast(\n            LedgerApiMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=ledger_api_dialogue,\n                performative=LedgerApiMessage.Performative.TRANSACTION_RECEIPT,\n                transaction_receipt=self.transaction_receipt,\n            ),\n        )\n\n        # operation\n        with patch.object(\n            self.ledger_api_handler.context.behaviours.transaction, \"finish_processing\"\n        ):\n            with patch.object(LedgerApis, \"is_transaction_settled\", return_value=True):\n                with patch.object(self.logger, \"log\"):\n                    with pytest.raises(\n                        ValueError, match=\"Could not retrieve last fipa message\"\n                    ):\n                        self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle_transaction_receipt_iii(self):\n        \"\"\"Test the _handle_transaction_receipt method of the ledger_api handler where tx is NOT settled.\"\"\"\n        # setup\n        ledger_api_dialogue = cast(\n            LedgerApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.ledger_api_dialogues,\n                messages=self.list_of_ledger_api_messages[:5],\n                counterparty=LEDGER_API_ADDRESS,\n            ),\n        )\n        fipa_dialogue = cast(\n            FipaDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.fipa_dialogues,\n                messages=self.list_of_fipa_messages[:4],\n                is_agent_to_agent_messages=True,\n            ),\n        )\n        ledger_api_dialogue.associated_fipa_dialogue = fipa_dialogue\n        fipa_dialogue.terms = self.terms\n        incoming_message = cast(\n            LedgerApiMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=ledger_api_dialogue,\n                performative=LedgerApiMessage.Performative.TRANSACTION_RECEIPT,\n                transaction_receipt=self.transaction_receipt,\n            ),\n        )\n\n        # operation\n        with patch.object(\n            self.ledger_api_handler.context.behaviours.transaction, \"failed_processing\"\n        ):\n            with patch.object(LedgerApis, \"is_transaction_settled\", return_value=False):\n                with patch.object(self.logger, \"log\") as mock_logger:\n                    self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        self.assert_quantity_in_outbox(0)\n        assert self.transaction_behaviour.processing is None\n        assert self.transaction_behaviour.processing_time == 0.0\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"transaction_receipt={self.transaction_receipt} not settled or not valid, aborting\",\n        )\n\n    def test_handle_error(self):\n        \"\"\"Test the _handle_error method of the ledger_api handler.\"\"\"\n        # setup\n        ledger_api_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.ledger_api_dialogues,\n            messages=self.list_of_ledger_api_messages[:1],\n        )\n        incoming_message = cast(\n            LedgerApiMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=ledger_api_dialogue,\n                performative=LedgerApiMessage.Performative.ERROR,\n                code=1,\n            ),\n        )\n        ledger_api_dialogue.associated_fipa_dialogue = \"mock\"\n        # operation\n        with patch.object(\n            self.ledger_api_handler.context.behaviours.transaction, \"failed_processing\"\n        ):\n            with patch.object(self.logger, \"log\") as mock_logger:\n                self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received ledger_api error message={incoming_message} in dialogue={ledger_api_dialogue}.\",\n        )\n\n    def test_handle_invalid(self):\n        \"\"\"Test the _handle_invalid method of the ledger_api handler.\"\"\"\n        # setup\n        invalid_performative = LedgerApiMessage.Performative.GET_BALANCE\n        incoming_message = self.build_incoming_message(\n            message_type=LedgerApiMessage,\n            dialogue_reference=(\"1\", \"\"),\n            performative=invalid_performative,\n            ledger_id=\"some_ledger_id\",\n            address=\"some_address\",\n            to=str(self.skill.public_id),\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"cannot handle ledger_api message of performative={invalid_performative} in dialogue={self.ledger_api_dialogues.get_dialogue(incoming_message)}.\",\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the ledger_api handler.\"\"\"\n        assert self.ledger_api_handler.teardown() is None\n        self.assert_quantity_in_outbox(0)\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_skills/test_generic_buyer/test_models.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the strategy class of the generic buyer skill.\"\"\"\n\nfrom pathlib import Path\n\nfrom aea.configurations.constants import DEFAULT_LEDGER\nfrom aea.helpers.search.models import Constraint, ConstraintType, Description, Query\nfrom aea.helpers.transaction.base import Terms\nfrom aea.test_tools.test_skill import BaseSkillTestCase, COUNTERPARTY_AGENT_ADDRESS\n\nfrom packages.fetchai.skills.generic_buyer.strategy import (\n    GenericStrategy,\n    SIMPLE_SERVICE_MODEL,\n)\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass TestGenericStrategy(BaseSkillTestCase):\n    \"\"\"Test GenericStrategy of generic buyer.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"generic_buyer\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.ledger_id = DEFAULT_LEDGER\n        cls.is_ledger_tx = True\n        cls.currency_id = \"some_currency_id\"\n        cls.max_unit_price = 20\n        cls.max_tx_fee = 1\n        cls.service_id = \"some_service_id\"\n        cls.search_query = {\n            \"constraint_type\": \"==\",\n            \"search_key\": \"seller_service\",\n            \"search_value\": \"some_search_value\",\n        }\n        cls.location = {\n            \"longitude\": 0.127,\n            \"latitude\": 51.5194,\n        }\n        cls.search_radius = 5.0\n        cls.max_negotiations = 2\n        cls.strategy = GenericStrategy(\n            ledger_id=cls.ledger_id,\n            is_ledger_tx=cls.is_ledger_tx,\n            currency_id=cls.currency_id,\n            max_unit_price=cls.max_unit_price,\n            max_tx_fee=cls.max_tx_fee,\n            service_id=cls.service_id,\n            search_query=cls.search_query,\n            location=cls.location,\n            search_radius=cls.search_radius,\n            max_negotiations=cls.max_negotiations,\n            name=\"strategy\",\n            skill_context=cls._skill.skill_context,\n        )\n\n    def test_properties(self):\n        \"\"\"Test the properties of GenericStrategy class.\"\"\"\n        assert self.strategy.ledger_id == self.ledger_id\n        assert self.strategy.is_ledger_tx == self.is_ledger_tx\n        assert self.strategy.is_searching is False\n\n        self.strategy.is_searching = True\n        assert self.strategy.is_searching is True\n\n        assert self.strategy.balance == 0\n\n        self.strategy.balance = 100\n        assert self.strategy.balance == 100\n\n        assert self.strategy.max_negotiations is self.max_negotiations\n\n    def test_get_location_and_service_query(self):\n        \"\"\"Test the get_location_and_service_query method of the GenericStrategy class.\"\"\"\n        query = self.strategy.get_location_and_service_query()\n\n        assert type(query) == Query\n        assert len(query.constraints) == 2\n        assert query.model is None\n\n        location_constraint = Constraint(\n            \"location\",\n            ConstraintType(\n                \"distance\", (self.strategy._agent_location, self.search_radius)\n            ),\n        )\n        assert query.constraints[0] == location_constraint\n\n        service_key_constraint = Constraint(\n            self.search_query[\"search_key\"],\n            ConstraintType(\n                self.search_query[\"constraint_type\"],\n                self.search_query[\"search_value\"],\n            ),\n        )\n        assert query.constraints[1] == service_key_constraint\n\n    def test_get_service_query(self):\n        \"\"\"Test the get_service_query method of the GenericStrategy class.\"\"\"\n        query = self.strategy.get_service_query()\n\n        assert type(query) == Query\n        assert len(query.constraints) == 1\n\n        assert query.model == SIMPLE_SERVICE_MODEL\n\n        service_key_constraint = Constraint(\n            self.search_query[\"search_key\"],\n            ConstraintType(\n                self.search_query[\"constraint_type\"],\n                self.search_query[\"search_value\"],\n            ),\n        )\n        assert query.constraints[0] == service_key_constraint\n\n    def test_is_acceptable_proposal(self):\n        \"\"\"Test the is_acceptable_proposal method of the GenericStrategy class.\"\"\"\n        acceptable_description = Description(\n            {\n                \"ledger_id\": self.ledger_id,\n                \"price\": 150,\n                \"currency_id\": self.currency_id,\n                \"service_id\": self.service_id,\n                \"quantity\": 10,\n                \"tx_nonce\": \"some_tx_nonce\",\n            }\n        )\n        is_acceptable = self.strategy.is_acceptable_proposal(acceptable_description)\n        assert is_acceptable\n\n        unacceptable_description = Description(\n            {\n                \"ledger_id\": self.ledger_id,\n                \"price\": 250,\n                \"currency_id\": self.currency_id,\n                \"service_id\": self.service_id,\n                \"quantity\": 10,\n                \"tx_nonce\": \"some_tx_nonce\",\n            }\n        )\n        is_acceptable = self.strategy.is_acceptable_proposal(unacceptable_description)\n        assert not is_acceptable\n\n    def test_is_affordable_proposal(self):\n        \"\"\"Test the is_affordable_proposal method of the GenericStrategy class.\"\"\"\n        description = Description(\n            {\n                \"ledger_id\": self.ledger_id,\n                \"price\": 150,\n                \"currency_id\": self.currency_id,\n                \"service_id\": self.service_id,\n                \"quantity\": 10,\n                \"tx_nonce\": \"some_tx_nonce\",\n            }\n        )\n        self.strategy.balance = 151\n        is_affordable = self.strategy.is_affordable_proposal(description)\n        assert is_affordable\n\n        self.strategy.balance = 150\n        is_affordable = self.strategy.is_affordable_proposal(description)\n        assert not is_affordable\n\n        self.strategy._is_ledger_tx = False\n        is_affordable = self.strategy.is_affordable_proposal(description)\n        assert is_affordable\n\n    def test_terms_from_proposal(self):\n        \"\"\"Test the terms_from_proposal method of the GenericStrategy class.\"\"\"\n        description = Description(\n            {\n                \"ledger_id\": self.ledger_id,\n                \"price\": 150,\n                \"currency_id\": self.currency_id,\n                \"service_id\": self.service_id,\n                \"quantity\": 10,\n                \"tx_nonce\": \"some_tx_nonce\",\n            }\n        )\n        terms = Terms(\n            ledger_id=self.ledger_id,\n            sender_address=self.skill.skill_context.agent_address,\n            counterparty_address=COUNTERPARTY_AGENT_ADDRESS,\n            amount_by_currency_id={self.currency_id: -150},\n            quantities_by_good_id={self.service_id: 10},\n            is_sender_payable_tx_fee=True,\n            nonce=\"some_tx_nonce\",\n            fee_by_currency_id={self.currency_id: self.max_tx_fee},\n        )\n        assert (\n            self.strategy.terms_from_proposal(description, COUNTERPARTY_AGENT_ADDRESS)\n            == terms\n        )\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_skills/test_generic_seller/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"The tests module contains the tests of the packages/skills/generic_seller dir.\"\"\"\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_skills/test_generic_seller/test_behaviours.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the behaviour classes of the generic seller skill.\"\"\"\n\nimport logging\nfrom pathlib import Path\nfrom typing import cast\nfrom unittest.mock import patch\n\nfrom aea.helpers.search.models import Description\nfrom aea.test_tools.test_skill import BaseSkillTestCase\n\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.skills.generic_seller.behaviours import (\n    GenericServiceRegistrationBehaviour,\n    LEDGER_API_ADDRESS,\n)\nfrom packages.fetchai.skills.generic_seller.strategy import GenericStrategy\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass TestSkillBehaviour(BaseSkillTestCase):\n    \"\"\"Test behaviours of generic seller.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"generic_seller\")\n    is_agent_to_agent_messages = False\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.service_registration = cast(\n            GenericServiceRegistrationBehaviour,\n            cls._skill.skill_context.behaviours.service_registration,\n        )\n        cls.strategy = cast(GenericStrategy, cls._skill.skill_context.strategy)\n        cls.logger = cls._skill.skill_context.logger\n\n        cls.registration_message = OefSearchMessage(\n            dialogue_reference=(\"\", \"\"),\n            performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n            service_description=\"some_service_description\",\n        )\n        cls.registration_message.sender = str(cls._skill.skill_context.skill_id)\n        cls.registration_message.to = cls._skill.skill_context.search_service_address\n\n        cls.mocked_description = Description({\"foo1\": 1, \"bar1\": 2})\n\n    def test_setup_is_ledger_tx(self):\n        \"\"\"Test the setup method of the service_registration behaviour where is_ledger_tx is True.\"\"\"\n        # setup\n        self.strategy._is_ledger_tx = True\n        mocked_description_1 = \"some_description_1\"\n\n        # operation\n        with patch.object(\n            self.strategy,\n            \"get_location_description\",\n            return_value=mocked_description_1,\n        ):\n            with patch.object(\n                self.service_registration.context.logger, \"log\"\n            ) as mock_logger:\n                self.service_registration.setup()\n\n        # after\n        self.assert_quantity_in_outbox(2)\n\n        # message 1\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=LedgerApiMessage,\n            performative=LedgerApiMessage.Performative.GET_BALANCE,\n            to=LEDGER_API_ADDRESS,\n            sender=str(self.skill.skill_context.skill_id),\n            ledger_id=self.strategy.ledger_id,\n            address=self.skill.skill_context.agent_address,\n        )\n        assert has_attributes, error_str\n\n        # _register_agent\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=OefSearchMessage,\n            performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n            to=self.skill.skill_context.search_service_address,\n            sender=str(self.skill.skill_context.skill_id),\n            service_description=mocked_description_1,\n        )\n        assert has_attributes, error_str\n\n        mock_logger.assert_any_call(logging.INFO, \"registering agent on SOEF.\")\n\n    def test_setup_not_is_ledger_tx(self):\n        \"\"\"Test the setup method of the service_registration behaviour: where is_ledger_tx is False.\"\"\"\n        # setup\n        self.strategy._is_ledger_tx = False\n        mocked_description_1 = \"some_description_1\"\n\n        # operation\n        with patch.object(\n            self.strategy,\n            \"get_location_description\",\n            return_value=mocked_description_1,\n        ):\n            with patch.object(\n                self.service_registration.context.logger, \"log\"\n            ) as mock_logger:\n                self.service_registration.setup()\n\n        # after\n        self.assert_quantity_in_outbox(1)\n\n        # _register_agent\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=OefSearchMessage,\n            performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n            to=self.skill.skill_context.search_service_address,\n            sender=str(self.skill.skill_context.skill_id),\n            service_description=mocked_description_1,\n        )\n        assert has_attributes, error_str\n\n        mock_logger.assert_any_call(logging.INFO, \"registering agent on SOEF.\")\n\n    def test_act_i(self):\n        \"\"\"Test the act method of the service_registration behaviour where failed_registration_msg IS None.\"\"\"\n        # setup\n        self.service_registration.failed_registration_msg = None\n\n        # operation\n        assert self.service_registration.act() is None\n\n        # after\n        self.assert_quantity_in_outbox(0)\n\n    def test_act_ii(self):\n        \"\"\"Test the act method of the service_registration behaviour where failed_registration_msg is NOT None.\"\"\"\n        # setup\n        self.service_registration.failed_registration_msg = self.registration_message\n\n        # operation\n        with patch.object(\n            self.service_registration.context.logger, \"log\"\n        ) as mock_logger:\n            self.service_registration.act()\n\n        # after\n        self.assert_quantity_in_outbox(1)\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=type(self.registration_message),\n            performative=self.registration_message.performative,\n            to=self.registration_message.to,\n            sender=str(self.skill.skill_context.skill_id),\n            service_description=self.registration_message.service_description,\n        )\n        assert has_attributes, error_str\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"Retrying registration on SOEF. Retry {self.service_registration._nb_retries} out of {self.service_registration._max_soef_registration_retries}.\",\n        )\n        assert self.service_registration.failed_registration_msg is None\n\n    def test_act_iii(self):\n        \"\"\"Test the act method of the service_registration behaviour where failed_registration_msg is NOT None and max retries is reached.\"\"\"\n        # setup\n        self.service_registration.failed_registration_msg = self.registration_message\n        self.service_registration._max_soef_registration_retries = 2\n        self.service_registration._nb_retries = 2\n\n        # operation\n        self.service_registration.act()\n\n        # after\n        self.assert_quantity_in_outbox(0)\n        assert self.skill.skill_context.is_active is False\n\n    def test_register_service(self):\n        \"\"\"Test the register_service method of the service_registration behaviour.\"\"\"\n        # operation\n        with patch.object(\n            self.strategy,\n            \"get_register_service_description\",\n            return_value=self.mocked_description,\n        ):\n            with patch.object(self.logger, \"log\") as mock_logger:\n                self.service_registration.register_service()\n\n        # after\n        self.assert_quantity_in_outbox(1)\n\n        message = self.get_message_from_outbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=OefSearchMessage,\n            performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n            to=self.skill.skill_context.search_service_address,\n            sender=str(self.skill.skill_context.skill_id),\n            service_description=self.mocked_description,\n        )\n        assert has_attributes, error_str\n        mock_logger.assert_any_call(\n            logging.INFO, \"registering agent's service on the SOEF.\"\n        )\n\n    def test_register_genus(self):\n        \"\"\"Test the register_genus method of the service_registration behaviour.\"\"\"\n        # operation\n        with patch.object(\n            self.strategy,\n            \"get_register_personality_description\",\n            return_value=self.mocked_description,\n        ):\n            with patch.object(self.logger, \"log\") as mock_logger:\n                self.service_registration.register_genus()\n\n        # after\n        self.assert_quantity_in_outbox(1)\n\n        message = self.get_message_from_outbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=OefSearchMessage,\n            performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n            to=self.skill.skill_context.search_service_address,\n            sender=str(self.skill.skill_context.skill_id),\n            service_description=self.mocked_description,\n        )\n        assert has_attributes, error_str\n        mock_logger.assert_any_call(\n            logging.INFO, \"registering agent's personality genus on the SOEF.\"\n        )\n\n    def test_register_classification(self):\n        \"\"\"Test the register_classification method of the service_registration behaviour.\"\"\"\n        # operation\n        with patch.object(\n            self.strategy,\n            \"get_register_classification_description\",\n            return_value=self.mocked_description,\n        ):\n            with patch.object(self.logger, \"log\") as mock_logger:\n                self.service_registration.register_classification()\n\n        # after\n        self.assert_quantity_in_outbox(1)\n\n        message = self.get_message_from_outbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=OefSearchMessage,\n            performative=OefSearchMessage.Performative.REGISTER_SERVICE,\n            to=self.skill.skill_context.search_service_address,\n            sender=str(self.skill.skill_context.skill_id),\n            service_description=self.mocked_description,\n        )\n        assert has_attributes, error_str\n        mock_logger.assert_any_call(\n            logging.INFO, \"registering agent's personality classification on the SOEF.\"\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the service_registration behaviour.\"\"\"\n        # setup\n        mocked_description_1 = \"some_description_1\"\n        mocked_description_2 = \"some_description_2\"\n\n        # operation\n        with patch.object(\n            self.strategy,\n            \"get_unregister_service_description\",\n            return_value=mocked_description_1,\n        ):\n            with patch.object(\n                self.strategy,\n                \"get_location_description\",\n                return_value=mocked_description_2,\n            ):\n                with patch.object(\n                    self.service_registration.context.logger, \"log\"\n                ) as mock_logger:\n                    self.service_registration.teardown()\n\n        # after\n        self.assert_quantity_in_outbox(2)\n\n        # message 1\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=OefSearchMessage,\n            performative=OefSearchMessage.Performative.UNREGISTER_SERVICE,\n            to=self.skill.skill_context.search_service_address,\n            sender=str(self.skill.skill_context.skill_id),\n            service_description=mocked_description_1,\n        )\n        assert has_attributes, error_str\n        mock_logger.assert_any_call(logging.INFO, \"unregistering service from SOEF.\")\n\n        # message 2\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=OefSearchMessage,\n            performative=OefSearchMessage.Performative.UNREGISTER_SERVICE,\n            to=self.skill.skill_context.search_service_address,\n            sender=str(self.skill.skill_context.skill_id),\n            service_description=mocked_description_2,\n        )\n        assert has_attributes, error_str\n        mock_logger.assert_any_call(logging.INFO, \"unregistering agent from SOEF.\")\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_skills/test_generic_seller/test_dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the dialogue classes of the generic seller skill.\"\"\"\n\nfrom pathlib import Path\nfrom typing import cast\n\nimport pytest\n\nfrom aea.exceptions import AEAEnforceError\nfrom aea.helpers.transaction.base import Terms\nfrom aea.protocols.dialogue.base import DialogueLabel\nfrom aea.test_tools.test_skill import BaseSkillTestCase, COUNTERPARTY_AGENT_ADDRESS\n\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.protocols.fipa.message import FipaMessage\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.skills.generic_seller.dialogues import (\n    DefaultDialogue,\n    DefaultDialogues,\n    FipaDialogue,\n    FipaDialogues,\n    LedgerApiDialogue,\n    LedgerApiDialogues,\n    OefSearchDialogue,\n    OefSearchDialogues,\n)\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass TestDialogues(BaseSkillTestCase):\n    \"\"\"Test dialogue classes of generic seller.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"generic_seller\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.default_dialogues = cast(\n            DefaultDialogues, cls._skill.skill_context.default_dialogues\n        )\n        cls.fipa_dialogues = cast(\n            FipaDialogues, cls._skill.skill_context.fipa_dialogues\n        )\n        cls.ledger_api_dialogues = cast(\n            LedgerApiDialogues, cls._skill.skill_context.ledger_api_dialogues\n        )\n        cls.oef_search_dialogues = cast(\n            OefSearchDialogues, cls._skill.skill_context.oef_search_dialogues\n        )\n\n    def test_default_dialogues(self):\n        \"\"\"Test the DefaultDialogues class.\"\"\"\n        _, dialogue = self.default_dialogues.create(\n            counterparty=COUNTERPARTY_AGENT_ADDRESS,\n            performative=DefaultMessage.Performative.BYTES,\n            content=b\"some_content\",\n        )\n        assert dialogue.role == DefaultDialogue.Role.AGENT\n        assert dialogue.self_address == self.skill.skill_context.agent_address\n\n    def test_fipa_dialogue(self):\n        \"\"\"Test the FipaDialogue class.\"\"\"\n        fipa_dialogue = FipaDialogue(\n            DialogueLabel(\n                (\"\", \"\"),\n                COUNTERPARTY_AGENT_ADDRESS,\n                self.skill.skill_context.agent_address,\n            ),\n            self.skill.skill_context.agent_address,\n            role=DefaultDialogue.Role.AGENT,\n        )\n\n        # terms\n        with pytest.raises(AEAEnforceError, match=\"Terms not set!\"):\n            assert fipa_dialogue.terms\n        terms = Terms(\n            \"some_ledger_id\",\n            self.skill.skill_context.agent_address,\n            \"counterprty\",\n            {\"currency_id\": 50},\n            {\"good_id\": -10},\n            \"some_nonce\",\n        )\n        fipa_dialogue.terms = terms\n        with pytest.raises(AEAEnforceError, match=\"Terms already set!\"):\n            fipa_dialogue.terms = terms\n        assert fipa_dialogue.terms == terms\n\n    def test_fipa_dialogues(self):\n        \"\"\"Test the FipaDialogues class.\"\"\"\n        _, dialogue = self.fipa_dialogues.create(\n            counterparty=COUNTERPARTY_AGENT_ADDRESS,\n            performative=FipaMessage.Performative.CFP,\n            query=\"some_query\",\n        )\n        assert dialogue.role == FipaDialogue.Role.SELLER\n        assert dialogue.self_address == self.skill.skill_context.agent_address\n\n    def test_ledger_api_dialogue(self):\n        \"\"\"Test the LedgerApiDialogue class.\"\"\"\n        ledger_api_dialogue = LedgerApiDialogue(\n            DialogueLabel(\n                (\"\", \"\"),\n                COUNTERPARTY_AGENT_ADDRESS,\n                self.skill.skill_context.agent_address,\n            ),\n            self.skill.skill_context.agent_address,\n            role=LedgerApiDialogue.Role.AGENT,\n        )\n\n        # associated_fipa_dialogue\n        with pytest.raises(AEAEnforceError, match=\"FipaDialogue not set!\"):\n            assert ledger_api_dialogue.associated_fipa_dialogue\n        fipa_dialogue = FipaDialogue(\n            DialogueLabel(\n                (\"\", \"\"),\n                COUNTERPARTY_AGENT_ADDRESS,\n                self.skill.skill_context.agent_address,\n            ),\n            self.skill.skill_context.agent_address,\n            role=FipaDialogue.Role.BUYER,\n        )\n        ledger_api_dialogue.associated_fipa_dialogue = fipa_dialogue\n        with pytest.raises(AEAEnforceError, match=\"FipaDialogue already set!\"):\n            ledger_api_dialogue.associated_fipa_dialogue = fipa_dialogue\n        assert ledger_api_dialogue.associated_fipa_dialogue == fipa_dialogue\n\n    def test_ledger_api_dialogues(self):\n        \"\"\"Test the LedgerApiDialogues class.\"\"\"\n        _, dialogue = self.ledger_api_dialogues.create(\n            counterparty=COUNTERPARTY_AGENT_ADDRESS,\n            performative=LedgerApiMessage.Performative.GET_BALANCE,\n            ledger_id=\"some_ledger_id\",\n            address=\"some_address\",\n        )\n        assert dialogue.role == LedgerApiDialogue.Role.AGENT\n        assert dialogue.self_address == str(self.skill.skill_context.skill_id)\n\n    def test_oef_search_dialogues(self):\n        \"\"\"Test the OefSearchDialogues class.\"\"\"\n        _, dialogue = self.oef_search_dialogues.create(\n            counterparty=COUNTERPARTY_AGENT_ADDRESS,\n            performative=OefSearchMessage.Performative.SEARCH_SERVICES,\n            query=\"some_query\",\n        )\n        assert dialogue.role == OefSearchDialogue.Role.AGENT\n        assert dialogue.self_address == str(self.skill.skill_context.skill_id)\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_skills/test_generic_seller/test_handlers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the handler classes of the generic seller skill.\"\"\"\n\nimport logging\nfrom pathlib import Path\nfrom typing import cast\nfrom unittest.mock import patch\n\nimport pytest\n\nimport aea\nfrom aea.helpers.search.models import Attribute, DataModel, Description, Location\nfrom aea.helpers.transaction.base import Terms, TransactionDigest, TransactionReceipt\nfrom aea.protocols.dialogue.base import DialogueMessage, Dialogues\nfrom aea.test_tools.test_skill import BaseSkillTestCase, COUNTERPARTY_AGENT_ADDRESS\n\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.protocols.fipa.message import FipaMessage\nfrom packages.fetchai.protocols.ledger_api.message import LedgerApiMessage\nfrom packages.fetchai.protocols.oef_search.message import OefSearchMessage\nfrom packages.fetchai.skills.generic_seller.behaviours import (\n    GenericServiceRegistrationBehaviour,\n)\nfrom packages.fetchai.skills.generic_seller.dialogues import (\n    FipaDialogue,\n    FipaDialogues,\n    LedgerApiDialogue,\n    LedgerApiDialogues,\n    OefSearchDialogues,\n)\nfrom packages.fetchai.skills.generic_seller.handlers import (\n    GenericFipaHandler,\n    GenericLedgerApiHandler,\n    GenericOefSearchHandler,\n    LEDGER_API_ADDRESS,\n)\nfrom packages.fetchai.skills.generic_seller.strategy import GenericStrategy\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass TestGenericFipaHandler(BaseSkillTestCase):\n    \"\"\"Test fipa handler of generic seller.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"generic_seller\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.fipa_handler = cast(\n            GenericFipaHandler, cls._skill.skill_context.handlers.fipa\n        )\n        cls.strategy = cast(GenericStrategy, cls._skill.skill_context.strategy)\n        cls.fipa_dialogues = cast(\n            FipaDialogues, cls._skill.skill_context.fipa_dialogues\n        )\n\n        cls.list_of_messages = (\n            DialogueMessage(\n                FipaMessage.Performative.CFP, {\"query\": \"some_query\"}, True\n            ),\n            DialogueMessage(\n                FipaMessage.Performative.PROPOSE, {\"proposal\": \"some_proposal\"}\n            ),\n            DialogueMessage(FipaMessage.Performative.ACCEPT),\n            DialogueMessage(\n                FipaMessage.Performative.MATCH_ACCEPT_W_INFORM,\n                {\"info\": {\"address\": \"some_term_sender_address\"}},\n            ),\n            DialogueMessage(\n                FipaMessage.Performative.INFORM,\n                {\"info\": {\"transaction_digest\": \"some_transaction_digest_body\"}},\n            ),\n        )\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the fipa handler.\"\"\"\n        assert self.fipa_handler.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle_unidentified_dialogue(self):\n        \"\"\"Test the _handle_unidentified_dialogue method of the fipa handler.\"\"\"\n        # setup\n        incorrect_dialogue_reference = (\"\", \"\")\n        incoming_message = self.build_incoming_message(\n            message_type=FipaMessage,\n            dialogue_reference=incorrect_dialogue_reference,\n            performative=FipaMessage.Performative.ACCEPT,\n        )\n\n        # operation\n        with patch.object(self.fipa_handler.context.logger, \"log\") as mock_logger:\n            self.fipa_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received invalid fipa message={incoming_message}, unidentified dialogue.\",\n        )\n        self.assert_quantity_in_outbox(1)\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=DefaultMessage,\n            performative=DefaultMessage.Performative.ERROR,\n            to=incoming_message.sender,\n            sender=self.skill.skill_context.agent_address,\n            error_code=DefaultMessage.ErrorCode.INVALID_DIALOGUE,\n            error_msg=\"Invalid dialogue.\",\n            error_data={\"fipa_message\": incoming_message.encode()},\n        )\n        assert has_attributes, error_str\n\n    def test_handle_cfp_is_matching_supply(self):\n        \"\"\"Test the _handle_cfp method of the fipa handler where is_matching_supply is True.\"\"\"\n        # setup\n        proposal = Description(\n            {\n                \"ledger_id\": \"some_ledger_id\",\n                \"price\": 100,\n                \"currency_id\": \"FET\",\n                \"service_id\": \"some_service_id\",\n                \"quantity\": 1,\n                \"tx_nonce\": \"some_tx_nonce\",\n            }\n        )\n        terms = \"some_terms\"\n        data = {\"data_type\": \"data\"}\n\n        incoming_message = self.build_incoming_message(\n            message_type=FipaMessage,\n            performative=FipaMessage.Performative.CFP,\n            dialogue_reference=Dialogues.new_self_initiated_dialogue_reference(),\n            query=\"some_query\",\n        )\n\n        # operation\n        with patch.object(\n            self.strategy,\n            \"is_matching_supply\",\n            return_value=True,\n        ):\n            with patch.object(\n                self.strategy,\n                \"generate_proposal_terms_and_data\",\n                return_value=(proposal, terms, data),\n            ):\n                with patch.object(\n                    self.fipa_handler.context.logger, \"log\"\n                ) as mock_logger:\n                    self.fipa_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO, f\"received CFP from sender={COUNTERPARTY_AGENT_ADDRESS[-5:]}\"\n        )\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"sending a PROPOSE with proposal={proposal.values} to sender={COUNTERPARTY_AGENT_ADDRESS[-5:]}\",\n        )\n\n        self.assert_quantity_in_outbox(1)\n\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=FipaMessage,\n            performative=FipaMessage.Performative.PROPOSE,\n            to=COUNTERPARTY_AGENT_ADDRESS,\n            sender=self.skill.skill_context.agent_address,\n            target=incoming_message.message_id,\n            proposal=proposal,\n        )\n        assert has_attributes, error_str\n\n    def test_handle_cfp_not_is_matching_supply(self):\n        \"\"\"Test the _handle_cfp method of the fipa handler where is_matching_supply is False.\"\"\"\n        # setup\n        incoming_message = self.build_incoming_message(\n            message_type=FipaMessage,\n            performative=FipaMessage.Performative.CFP,\n            dialogue_reference=Dialogues.new_self_initiated_dialogue_reference(),\n            query=\"some_query\",\n        )\n\n        # operation\n        with patch.object(self.strategy, \"is_matching_supply\", return_value=False):\n            with patch.object(self.fipa_handler.context.logger, \"log\") as mock_logger:\n                self.fipa_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO, f\"received CFP from sender={COUNTERPARTY_AGENT_ADDRESS[-5:]}\"\n        )\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"declined the CFP from sender={COUNTERPARTY_AGENT_ADDRESS[-5:]}\",\n        )\n\n        self.assert_quantity_in_outbox(1)\n\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=FipaMessage,\n            performative=FipaMessage.Performative.DECLINE,\n            to=COUNTERPARTY_AGENT_ADDRESS,\n            sender=self.skill.skill_context.agent_address,\n            target=incoming_message.message_id,\n        )\n        assert has_attributes, error_str\n\n    def test_handle_decline(self):\n        \"\"\"Test the _handle_decline method of the fipa handler.\"\"\"\n        # setup\n        fipa_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.fipa_dialogues,\n            messages=self.list_of_messages[:2],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=fipa_dialogue,\n            performative=FipaMessage.Performative.DECLINE,\n        )\n\n        # before\n        for (\n            end_state_numbers\n        ) in self.fipa_dialogues.dialogue_stats.self_initiated.values():\n            assert end_state_numbers == 0\n        for (\n            end_state_numbers\n        ) in self.fipa_dialogues.dialogue_stats.other_initiated.values():\n            assert end_state_numbers == 0\n\n        # operation\n        with patch.object(self.fipa_handler.context.logger, \"log\") as mock_logger:\n            self.fipa_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received DECLINE from sender={COUNTERPARTY_AGENT_ADDRESS[-5:]}\",\n        )\n\n        for (\n            end_state_numbers\n        ) in self.fipa_dialogues.dialogue_stats.self_initiated.values():\n            assert end_state_numbers == 0\n        for (\n            end_state,\n            end_state_numbers,\n        ) in self.fipa_dialogues.dialogue_stats.other_initiated.items():\n            if end_state == FipaDialogue.EndState.DECLINED_PROPOSE:\n                assert end_state_numbers == 1\n            else:\n                assert end_state_numbers == 0\n\n    def test_handle_accept(self):\n        \"\"\"Test the _handle_accept method of the fipa handler.\"\"\"\n        # setup\n        fipa_dialogue = cast(\n            FipaDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.fipa_dialogues,\n                messages=self.list_of_messages[:2],\n            ),\n        )\n        fipa_dialogue.terms = Terms(\n            \"some_ledger_id\",\n            self.skill.skill_context.agent_address,\n            \"counterprty\",\n            {\"currency_id\": 50},\n            {\"good_id\": -10},\n            \"some_nonce\",\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=fipa_dialogue,\n            performative=FipaMessage.Performative.ACCEPT,\n        )\n        info = {\"address\": fipa_dialogue.terms.sender_address}\n\n        # operation\n        with patch.object(self.fipa_handler.context.logger, \"log\") as mock_logger:\n            self.fipa_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received ACCEPT from sender={COUNTERPARTY_AGENT_ADDRESS[-5:]}\",\n        )\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"sending MATCH_ACCEPT_W_INFORM to sender={COUNTERPARTY_AGENT_ADDRESS[-5:]} with info={info}\",\n        )\n\n        self.assert_quantity_in_outbox(1)\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=FipaMessage,\n            performative=FipaMessage.Performative.MATCH_ACCEPT_W_INFORM,\n            to=COUNTERPARTY_AGENT_ADDRESS,\n            sender=self.skill.skill_context.agent_address,\n            info=info,\n        )\n        assert has_attributes, error_str\n\n    def test_handle_inform_is_ledger_tx_and_with_tx_digest(self):\n        \"\"\"Test the _handle_inform method of the fipa handler where is_ledger_tx is True and info contains transaction_digest.\"\"\"\n        # setup\n        self.strategy._is_ledger_tx = True\n        tx_digest = \"some_transaction_digest_body\"\n        ledger_id = \"some_ledger_id\"\n\n        fipa_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.fipa_dialogues,\n            messages=self.list_of_messages[:4],\n        )\n        fipa_dialogue.terms = Terms(\n            ledger_id,\n            self.skill.skill_context.agent_address,\n            \"counterprty\",\n            {\"currency_id\": 50},\n            {\"good_id\": -10},\n            \"some_nonce\",\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=fipa_dialogue,\n            performative=FipaMessage.Performative.INFORM,\n            info={\"transaction_digest\": tx_digest},\n        )\n\n        # operation\n        with patch.object(self.fipa_handler.context.logger, \"log\") as mock_logger:\n            self.fipa_handler.handle(incoming_message)\n        incoming_message = cast(FipaMessage, incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received INFORM from sender={COUNTERPARTY_AGENT_ADDRESS[-5:]}\",\n        )\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"checking whether transaction={incoming_message.info['transaction_digest']} has been received ...\",\n        )\n\n        self.assert_quantity_in_outbox(1)\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=LedgerApiMessage,\n            performative=LedgerApiMessage.Performative.GET_TRANSACTION_RECEIPT,\n            to=LEDGER_API_ADDRESS,\n            sender=str(self.skill.skill_context.skill_id),\n            target=0,\n            transaction_digest=TransactionDigest(ledger_id, tx_digest),\n        )\n        assert has_attributes, error_str\n\n    def test_handle_inform_is_ledger_tx_and_no_tx_digest(self):\n        \"\"\"Test the _handle_inform method of the fipa handler where is_ledger_tx is True and info does not have a transaction_digest.\"\"\"\n        # setup\n        self.strategy._is_ledger_tx = True\n\n        fipa_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.fipa_dialogues,\n            messages=self.list_of_messages[:4],\n        )\n        fipa_dialogue.terms = Terms(\n            \"some_ledger_id\",\n            self.skill.skill_context.agent_address,\n            \"counterprty\",\n            {\"currency_id\": 50},\n            {\"good_id\": -10},\n            \"some_nonce\",\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=fipa_dialogue,\n            performative=FipaMessage.Performative.INFORM,\n            info={},\n        )\n\n        # operation\n        with patch.object(self.fipa_handler.context.logger, \"log\") as mock_logger:\n            self.fipa_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received INFORM from sender={COUNTERPARTY_AGENT_ADDRESS[-5:]}\",\n        )\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"did not receive transaction digest from sender={COUNTERPARTY_AGENT_ADDRESS[-5:]}.\",\n        )\n\n    def test_handle_inform_not_is_ledger_tx_and_with_done(self):\n        \"\"\"Test the _handle_inform method of the fipa handler where is_ledger_tx is False and info contains done.\"\"\"\n        # setup\n        self.strategy._is_ledger_tx = False\n        data = {\n            \"data_type_1\": \"data_1\",\n            \"data_type_2\": \"data_2\",\n        }\n\n        fipa_dialogue = cast(\n            FipaDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.fipa_dialogues,\n                messages=self.list_of_messages[:4],\n            ),\n        )\n        fipa_dialogue.data_for_sale = data\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=fipa_dialogue,\n            performative=FipaMessage.Performative.INFORM,\n            info={\"Done\": \"Sending payment via bank transfer\"},\n        )\n\n        # before\n        for (\n            end_state_numbers\n        ) in self.fipa_dialogues.dialogue_stats.self_initiated.values():\n            assert end_state_numbers == 0\n        for (\n            end_state_numbers\n        ) in self.fipa_dialogues.dialogue_stats.other_initiated.values():\n            assert end_state_numbers == 0\n\n        # operation\n        with patch.object(self.fipa_handler.context.logger, \"log\") as mock_logger:\n            self.fipa_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received INFORM from sender={COUNTERPARTY_AGENT_ADDRESS[-5:]}\",\n        )\n\n        # check outgoing message\n        self.assert_quantity_in_outbox(1)\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=FipaMessage,\n            performative=FipaMessage.Performative.INFORM,\n            to=COUNTERPARTY_AGENT_ADDRESS,\n            sender=self.skill.skill_context.agent_address,\n            target=incoming_message.message_id,\n            info=fipa_dialogue.data_for_sale,\n        )\n        assert has_attributes, error_str\n\n        # check updated end_state\n        for (\n            end_state_numbers\n        ) in self.fipa_dialogues.dialogue_stats.self_initiated.values():\n            assert end_state_numbers == 0\n        for (\n            end_state,\n            end_state_numbers,\n        ) in self.fipa_dialogues.dialogue_stats.other_initiated.items():\n            if end_state == FipaDialogue.EndState.SUCCESSFUL:\n                assert end_state_numbers == 1\n            else:\n                assert end_state_numbers == 0\n\n        # check logger output\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"transaction confirmed, sending data={data} to buyer={COUNTERPARTY_AGENT_ADDRESS[-5:]}.\",\n        )\n\n    def test_handle_inform_not_is_ledger_tx_and_nothin_in_info(self):\n        \"\"\"Test the _handle_inform method of the fipa handler where is_ledger_tx is False and info does not contain done or transaction_digest.\"\"\"\n        # setup\n        self.strategy._is_ledger_tx = False\n\n        fipa_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.fipa_dialogues,\n            messages=self.list_of_messages[:4],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=fipa_dialogue,\n            performative=FipaMessage.Performative.INFORM,\n            info={},\n        )\n\n        # operation\n        with patch.object(self.fipa_handler.context.logger, \"log\") as mock_logger:\n            self.fipa_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received INFORM from sender={COUNTERPARTY_AGENT_ADDRESS[-5:]}\",\n        )\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"did not receive transaction confirmation from sender={COUNTERPARTY_AGENT_ADDRESS[-5:]}.\",\n        )\n\n    def test_handle_invalid(self):\n        \"\"\"Test the _handle_invalid method of the fipa handler.\"\"\"\n        # setup\n        fipa_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.fipa_dialogues,\n            messages=self.list_of_messages[:2],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=fipa_dialogue,\n            performative=FipaMessage.Performative.ACCEPT_W_INFORM,\n            info={},\n        )\n\n        # operation\n        with patch.object(self.fipa_handler.context.logger, \"log\") as mock_logger:\n            self.fipa_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"cannot handle fipa message of performative={incoming_message.performative} in dialogue={fipa_dialogue}.\",\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the fipa handler.\"\"\"\n        assert self.fipa_handler.teardown() is None\n        self.assert_quantity_in_outbox(0)\n\n\nclass TestGenericLedgerApiHandler(BaseSkillTestCase):\n    \"\"\"Test ledger_api handler of generic seller.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"generic_seller\")\n    is_agent_to_agent_messages = False\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.ledger_api_handler = cast(\n            GenericLedgerApiHandler, cls._skill.skill_context.handlers.ledger_api\n        )\n        cls.strategy = cast(GenericStrategy, cls._skill.skill_context.strategy)\n        cls.fipa_dialogues = cast(\n            FipaDialogues, cls._skill.skill_context.fipa_dialogues\n        )\n        cls.ledger_api_dialogues = cast(\n            LedgerApiDialogues, cls._skill.skill_context.ledger_api_dialogues\n        )\n        cls.terms = Terms(\n            \"some_ledger_id\",\n            cls._skill.skill_context.agent_address,\n            \"counterprty\",\n            {\"currency_id\": 50},\n            {\"good_id\": -10},\n            \"some_nonce\",\n        )\n        cls.list_of_fipa_messages = (\n            DialogueMessage(\n                FipaMessage.Performative.CFP, {\"query\": \"some_query\"}, True\n            ),\n            DialogueMessage(\n                FipaMessage.Performative.PROPOSE, {\"proposal\": \"some_proposal\"}\n            ),\n            DialogueMessage(FipaMessage.Performative.ACCEPT),\n            DialogueMessage(\n                FipaMessage.Performative.MATCH_ACCEPT_W_INFORM,\n                {\"info\": {\"address\": \"some_term_sender_address\"}},\n            ),\n            DialogueMessage(\n                FipaMessage.Performative.INFORM,\n                {\"info\": {\"transaction_digest\": \"some_transaction_digest_body\"}},\n            ),\n        )\n        cls.transaction_digest = TransactionDigest(\"some_ledger_id\", \"some_body\")\n        cls.transaction_receipt = TransactionReceipt(\n            \"some_ledger_id\", {\"some_key\": \"some_value\"}, {\"some_key\": \"some_value\"}\n        )\n        cls.list_of_ledger_api_messages = (\n            DialogueMessage(\n                LedgerApiMessage.Performative.GET_TRANSACTION_RECEIPT,\n                {\"transaction_digest\": cls.transaction_digest},\n            ),\n            DialogueMessage(\n                LedgerApiMessage.Performative.TRANSACTION_RECEIPT,\n                {\"transaction_receipt\": cls.transaction_receipt},\n            ),\n        )\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the ledger_api handler.\"\"\"\n        assert self.ledger_api_handler.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle_unidentified_dialogue(self):\n        \"\"\"Test the _handle_unidentified_dialogue method of the ledger_api handler.\"\"\"\n        # setup\n        incorrect_dialogue_reference = (\"\", \"\")\n        incoming_message = self.build_incoming_message(\n            message_type=LedgerApiMessage,\n            dialogue_reference=incorrect_dialogue_reference,\n            performative=LedgerApiMessage.Performative.GET_BALANCE,\n            ledger_id=\"some_ledger_id\",\n            address=\"some_address\",\n        )\n\n        # operation\n        with patch.object(self.ledger_api_handler.context.logger, \"log\") as mock_logger:\n            self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received invalid ledger_api message={incoming_message}, unidentified dialogue.\",\n        )\n\n    def test_handle_balance(self):\n        \"\"\"Test the _handle_balance method of the ledger_api handler.\"\"\"\n        # setup\n        ledger_id = \"some_Ledger_id\"\n        ledger_api_dialogue = cast(\n            LedgerApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.ledger_api_dialogues,\n                messages=(\n                    DialogueMessage(\n                        LedgerApiMessage.Performative.GET_BALANCE,\n                        {\"ledger_id\": \"some_ledger_id\", \"address\": \"some_address\"},\n                    ),\n                ),\n                counterparty=LEDGER_API_ADDRESS,\n            ),\n        )\n        incoming_message = cast(\n            LedgerApiMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=ledger_api_dialogue,\n                performative=LedgerApiMessage.Performative.BALANCE,\n                ledger_id=ledger_id,\n                balance=10,\n            ),\n        )\n\n        # operation\n        with patch.object(self.ledger_api_handler.context.logger, \"log\") as mock_logger:\n            self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"starting balance on {ledger_id} ledger={incoming_message.balance}.\",\n        )\n\n    def test_handle_transaction_receipt_is_settled_and_is_valid_last_incoming_fipa_message_is_none(\n        self,\n    ):\n        \"\"\"Test the _handle_transaction_receipt method of the ledger_api handler where is_settled and is_valid are True and the last incoming FipaMessage is None.\"\"\"\n        # setup\n        ledger_api_dialogue = cast(\n            LedgerApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.ledger_api_dialogues,\n                messages=self.list_of_ledger_api_messages[:1],\n                counterparty=LEDGER_API_ADDRESS,\n            ),\n        )\n        fipa_dialogue = cast(\n            FipaDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.fipa_dialogues,\n                messages=self.list_of_fipa_messages[:5],\n                is_agent_to_agent_messages=True,\n            ),\n        )\n        ledger_api_dialogue.associated_fipa_dialogue = fipa_dialogue\n        fipa_dialogue.terms = self.terms\n        fipa_dialogue.data_for_sale = {\"data_type_1\": \"data_1\"}\n        fipa_dialogue._incoming_messages = []\n        incoming_message = cast(\n            LedgerApiMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=ledger_api_dialogue,\n                performative=LedgerApiMessage.Performative.TRANSACTION_RECEIPT,\n                transaction_receipt=self.transaction_receipt,\n            ),\n        )\n\n        # operation\n        with patch.object(\n            aea.crypto.ledger_apis.LedgerApis,\n            \"is_transaction_settled\",\n            return_value=True,\n        ):\n            with patch.object(\n                aea.crypto.ledger_apis.LedgerApis,\n                \"is_transaction_valid\",\n                return_value=True,\n            ):\n                with pytest.raises(\n                    ValueError, match=\"Cannot retrieve last fipa message.\"\n                ):\n                    self.ledger_api_handler.handle(incoming_message)\n\n    def test_handle_transaction_receipt_is_settled_and_is_valid(self):\n        \"\"\"Test the _handle_transaction_receipt method of the ledger_api handler where is_settled and is_valid are True.\"\"\"\n        # setup\n        ledger_api_dialogue = cast(\n            LedgerApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.ledger_api_dialogues,\n                messages=self.list_of_ledger_api_messages[:1],\n                counterparty=LEDGER_API_ADDRESS,\n            ),\n        )\n        fipa_dialogue = cast(\n            FipaDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.fipa_dialogues,\n                messages=self.list_of_fipa_messages[:5],\n                is_agent_to_agent_messages=True,\n            ),\n        )\n        ledger_api_dialogue.associated_fipa_dialogue = fipa_dialogue\n        fipa_dialogue.terms = self.terms\n        fipa_dialogue.data_for_sale = {\"data_type_1\": \"data_1\"}\n        incoming_message = cast(\n            LedgerApiMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=ledger_api_dialogue,\n                performative=LedgerApiMessage.Performative.TRANSACTION_RECEIPT,\n                transaction_receipt=self.transaction_receipt,\n            ),\n        )\n\n        # before\n        for end_state_numbers in list(\n            self.fipa_dialogues.dialogue_stats.self_initiated.values()\n        ) + list(self.fipa_dialogues.dialogue_stats.other_initiated.values()):\n            assert end_state_numbers == 0\n\n        # operation\n        with patch.object(\n            aea.crypto.ledger_apis.LedgerApis,\n            \"is_transaction_settled\",\n            return_value=True,\n        ):\n            with patch.object(\n                aea.crypto.ledger_apis.LedgerApis,\n                \"is_transaction_valid\",\n                return_value=True,\n            ):\n                with patch.object(\n                    self.ledger_api_handler.context.logger, \"log\"\n                ) as mock_logger:\n                    self.ledger_api_handler.handle(incoming_message)\n\n        # after\n\n        # check outgoing message\n        self.assert_quantity_in_outbox(1)\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=self.get_message_from_outbox(),\n            message_type=FipaMessage,\n            performative=FipaMessage.Performative.INFORM,\n            to=COUNTERPARTY_AGENT_ADDRESS,\n            sender=self.skill.skill_context.agent_address,\n            target=fipa_dialogue.last_incoming_message.message_id,\n            info=fipa_dialogue.data_for_sale,\n        )\n        assert has_attributes, error_str\n\n        # check updated end_state\n        for (\n            end_state_numbers\n        ) in self.fipa_dialogues.dialogue_stats.self_initiated.values():\n            assert end_state_numbers == 0\n        for (\n            end_state,\n            end_state_numbers,\n        ) in self.fipa_dialogues.dialogue_stats.other_initiated.items():\n            if end_state == FipaDialogue.EndState.SUCCESSFUL:\n                assert end_state_numbers == 1\n            else:\n                assert end_state_numbers == 0\n\n        # check logger output\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"transaction confirmed, sending data={fipa_dialogue.data_for_sale} to buyer={COUNTERPARTY_AGENT_ADDRESS[-5:]}.\",\n        )\n\n    def test_handle_transaction_receipt_not_is_settled_or_not_is_valid(\n        self,\n    ):\n        \"\"\"Test the _handle_transaction_receipt method of the ledger_api handler where is_settled or is_valid is False.\"\"\"\n        # setup\n        ledger_api_dialogue = cast(\n            LedgerApiDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.ledger_api_dialogues,\n                messages=self.list_of_ledger_api_messages[:1],\n                counterparty=LEDGER_API_ADDRESS,\n            ),\n        )\n        fipa_dialogue = cast(\n            FipaDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.fipa_dialogues,\n                messages=self.list_of_fipa_messages[:5],\n                is_agent_to_agent_messages=True,\n            ),\n        )\n        ledger_api_dialogue.associated_fipa_dialogue = fipa_dialogue\n        fipa_dialogue.terms = self.terms\n        incoming_message = cast(\n            LedgerApiMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=ledger_api_dialogue,\n                performative=LedgerApiMessage.Performative.TRANSACTION_RECEIPT,\n                transaction_receipt=self.transaction_receipt,\n            ),\n        )\n\n        # operation\n        with patch.object(\n            aea.crypto.ledger_apis.LedgerApis,\n            \"is_transaction_settled\",\n            return_value=True,\n        ):\n            with patch.object(\n                aea.crypto.ledger_apis.LedgerApis,\n                \"is_transaction_valid\",\n                return_value=False,\n            ):\n                with patch.object(\n                    self.ledger_api_handler.context.logger, \"log\"\n                ) as mock_logger:\n                    self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"transaction_receipt={self.transaction_receipt} not settled or not valid, aborting\",\n        )\n\n    def test_handle_error(self):\n        \"\"\"Test the _handle_error method of the ledger_api handler.\"\"\"\n        # setup\n        ledger_api_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.ledger_api_dialogues,\n            messages=self.list_of_ledger_api_messages[:1],\n        )\n        incoming_message = cast(\n            LedgerApiMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=ledger_api_dialogue,\n                performative=LedgerApiMessage.Performative.ERROR,\n                code=1,\n            ),\n        )\n\n        # operation\n        with patch.object(self.ledger_api_handler.context.logger, \"log\") as mock_logger:\n            self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received ledger_api error message={incoming_message} in dialogue={ledger_api_dialogue}.\",\n        )\n\n    def test_handle_invalid(self):\n        \"\"\"Test the _handle_invalid method of the ledger_api handler.\"\"\"\n        # setup\n        invalid_performative = LedgerApiMessage.Performative.GET_BALANCE\n        incoming_message = self.build_incoming_message(\n            message_type=LedgerApiMessage,\n            dialogue_reference=(\"1\", \"\"),\n            performative=invalid_performative,\n            ledger_id=\"some_ledger_id\",\n            address=\"some_address\",\n            to=str(self.skill.skill_context.skill_id),\n        )\n\n        # operation\n        with patch.object(self.ledger_api_handler.context.logger, \"log\") as mock_logger:\n            self.ledger_api_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"cannot handle ledger_api message of performative={invalid_performative} in dialogue={self.ledger_api_dialogues.get_dialogue(incoming_message)}.\",\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the ledger_api handler.\"\"\"\n        assert self.ledger_api_handler.teardown() is None\n        self.assert_quantity_in_outbox(0)\n\n\nclass TestGenericOefSearchHandler(BaseSkillTestCase):\n    \"\"\"Test oef search handler of generic seller.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"generic_seller\")\n    is_agent_to_agent_messages = False\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.oef_search_handler = cast(\n            GenericOefSearchHandler, cls._skill.skill_context.handlers.oef_search\n        )\n        cls.strategy = cast(GenericStrategy, cls._skill.skill_context.strategy)\n        cls.oef_dialogues = cast(\n            OefSearchDialogues, cls._skill.skill_context.oef_search_dialogues\n        )\n        cls.service_registration_behaviour = cast(\n            GenericServiceRegistrationBehaviour,\n            cls._skill.skill_context.behaviours.service_registration,\n        )\n\n        cls.register_location_description = Description(\n            {\"location\": Location(51.5194, 0.1270)},\n            data_model=DataModel(\n                \"location_agent\", [Attribute(\"location\", Location, True)]\n            ),\n        )\n        cls.list_of_messages_register_location = (\n            DialogueMessage(\n                OefSearchMessage.Performative.REGISTER_SERVICE,\n                {\"service_description\": cls.register_location_description},\n                is_incoming=False,\n            ),\n        )\n\n        cls.register_service_description = Description(\n            {\"key\": \"some_key\", \"value\": \"some_value\"},\n            data_model=DataModel(\n                \"set_service_key\",\n                [Attribute(\"key\", str, True), Attribute(\"value\", str, True)],\n            ),\n        )\n        cls.list_of_messages_register_service = (\n            DialogueMessage(\n                OefSearchMessage.Performative.REGISTER_SERVICE,\n                {\"service_description\": cls.register_service_description},\n                is_incoming=False,\n            ),\n        )\n\n        cls.register_genus_description = Description(\n            {\"piece\": \"genus\", \"value\": \"some_value\"},\n            data_model=DataModel(\n                \"personality_agent\",\n                [Attribute(\"piece\", str, True), Attribute(\"value\", str, True)],\n            ),\n        )\n        cls.list_of_messages_register_genus = (\n            DialogueMessage(\n                OefSearchMessage.Performative.REGISTER_SERVICE,\n                {\"service_description\": cls.register_genus_description},\n                is_incoming=False,\n            ),\n        )\n\n        cls.register_classification_description = Description(\n            {\"piece\": \"classification\", \"value\": \"some_value\"},\n            data_model=DataModel(\n                \"personality_agent\",\n                [Attribute(\"piece\", str, True), Attribute(\"value\", str, True)],\n            ),\n        )\n        cls.list_of_messages_register_classification = (\n            DialogueMessage(\n                OefSearchMessage.Performative.REGISTER_SERVICE,\n                {\"service_description\": cls.register_classification_description},\n                is_incoming=False,\n            ),\n        )\n\n        cls.register_invalid_description = Description(\n            {\"piece\": \"classification\", \"value\": \"some_value\"},\n            data_model=DataModel(\n                \"some_different_name\",\n                [Attribute(\"piece\", str, True), Attribute(\"value\", str, True)],\n            ),\n        )\n        cls.list_of_messages_register_invalid = (\n            DialogueMessage(\n                OefSearchMessage.Performative.REGISTER_SERVICE,\n                {\"service_description\": cls.register_invalid_description},\n                is_incoming=False,\n            ),\n        )\n\n        cls.unregister_description = Description(\n            {\"key\": \"seller_service\"},\n            data_model=DataModel(\"remove\", [Attribute(\"key\", str, True)]),\n        )\n        cls.list_of_messages_unregister = (\n            DialogueMessage(\n                OefSearchMessage.Performative.UNREGISTER_SERVICE,\n                {\"service_description\": cls.unregister_description},\n                is_incoming=False,\n            ),\n        )\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the oef_search handler.\"\"\"\n        assert self.oef_search_handler.setup() is None\n        self.assert_quantity_in_outbox(0)\n\n    def test_handle_unidentified_dialogue(self):\n        \"\"\"Test the _handle_unidentified_dialogue method of the oef_search handler.\"\"\"\n        # setup\n        incorrect_dialogue_reference = (\"\", \"\")\n        incoming_message = self.build_incoming_message(\n            message_type=OefSearchMessage,\n            dialogue_reference=incorrect_dialogue_reference,\n            performative=OefSearchMessage.Performative.SEARCH_SERVICES,\n        )\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received invalid oef_search message={incoming_message}, unidentified dialogue.\",\n        )\n\n    def test_handle_success_i(self):\n        \"\"\"Test the _handle_success method of the oef_search handler where the oef success targets register_service WITH location_agent data model description.\"\"\"\n        # setup\n        oef_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_dialogues,\n            messages=self.list_of_messages_register_location[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=oef_dialogue,\n            performative=OefSearchMessage.Performative.SUCCESS,\n            agents_info=OefSearchMessage.AgentsInfo({\"address\": {\"key\": \"value\"}}),\n        )\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            with patch.object(\n                self.service_registration_behaviour,\n                \"register_service\",\n            ) as mock_reg:\n                self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received oef_search success message={incoming_message} in dialogue={oef_dialogue}.\",\n        )\n        mock_reg.assert_called_once()\n\n    def test_handle_success_ii(self):\n        \"\"\"Test the _handle_success method of the oef_search handler where the oef success targets register_service WITH set_service_key data model description.\"\"\"\n        # setup\n        oef_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_dialogues,\n            messages=self.list_of_messages_register_service[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=oef_dialogue,\n            performative=OefSearchMessage.Performative.SUCCESS,\n            agents_info=OefSearchMessage.AgentsInfo({\"address\": {\"key\": \"value\"}}),\n        )\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            with patch.object(\n                self.service_registration_behaviour,\n                \"register_genus\",\n            ) as mock_reg:\n                self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received oef_search success message={incoming_message} in dialogue={oef_dialogue}.\",\n        )\n        mock_reg.assert_called_once()\n\n    def test_handle_success_iii(self):\n        \"\"\"Test the _handle_success method of the oef_search handler where the oef success targets register_service WITH personality_agent data model and genus value description.\"\"\"\n        # setup\n        oef_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_dialogues,\n            messages=self.list_of_messages_register_genus[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=oef_dialogue,\n            performative=OefSearchMessage.Performative.SUCCESS,\n            agents_info=OefSearchMessage.AgentsInfo({\"address\": {\"key\": \"value\"}}),\n        )\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            with patch.object(\n                self.service_registration_behaviour,\n                \"register_classification\",\n            ) as mock_reg:\n                self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received oef_search success message={incoming_message} in dialogue={oef_dialogue}.\",\n        )\n        mock_reg.assert_called_once()\n\n    def test_handle_success_iv(self):\n        \"\"\"Test the _handle_success method of the oef_search handler where the oef success targets register_service WITH personality_agent data model and classification value description.\"\"\"\n        # setup\n        oef_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_dialogues,\n            messages=self.list_of_messages_register_classification[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=oef_dialogue,\n            performative=OefSearchMessage.Performative.SUCCESS,\n            agents_info=OefSearchMessage.AgentsInfo({\"address\": {\"key\": \"value\"}}),\n        )\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received oef_search success message={incoming_message} in dialogue={oef_dialogue}.\",\n        )\n        mock_logger.assert_any_call(\n            logging.INFO,\n            \"the agent, with its genus and classification, and its service are successfully registered on the SOEF.\",\n        )\n\n    def test_handle_success_v(self):\n        \"\"\"Test the _handle_success method of the oef_search handler where the oef success targets unregister_service.\"\"\"\n        # setup\n        oef_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_dialogues,\n            messages=self.list_of_messages_register_invalid[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=oef_dialogue,\n            performative=OefSearchMessage.Performative.SUCCESS,\n            agents_info=OefSearchMessage.AgentsInfo({\"address\": {\"key\": \"value\"}}),\n        )\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received oef_search success message={incoming_message} in dialogue={oef_dialogue}.\",\n        )\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"received soef SUCCESS message as a reply to the following unexpected message: {oef_dialogue.get_message_by_id(incoming_message.target)}\",\n        )\n\n    def test_handle_error_i(self):\n        \"\"\"Test the _handle_error method of the oef_search handler where the oef error targets register_service.\"\"\"\n        # setup\n        oef_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_dialogues,\n            messages=self.list_of_messages_register_location[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=oef_dialogue,\n            performative=OefSearchMessage.Performative.OEF_ERROR,\n            oef_error_operation=OefSearchMessage.OefErrorOperation.SEARCH_SERVICES,\n        )\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        self.assert_quantity_in_outbox(0)\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received oef_search error message={incoming_message} in dialogue={oef_dialogue}.\",\n        )\n        assert (\n            self.service_registration_behaviour.failed_registration_msg\n            == oef_dialogue.get_message_by_id(incoming_message.target)\n        )\n\n    def test_handle_error_ii(self):\n        \"\"\"Test the _handle_error method of the oef_search handler where the oef error does NOT target register_service.\"\"\"\n        # setup\n        oef_dialogue = self.prepare_skill_dialogue(\n            dialogues=self.oef_dialogues,\n            messages=self.list_of_messages_unregister[:1],\n        )\n        incoming_message = self.build_incoming_message_for_skill_dialogue(\n            dialogue=oef_dialogue,\n            performative=OefSearchMessage.Performative.OEF_ERROR,\n            oef_error_operation=OefSearchMessage.OefErrorOperation.SEARCH_SERVICES,\n        )\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        self.assert_quantity_in_outbox(0)\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received oef_search error message={incoming_message} in dialogue={oef_dialogue}.\",\n        )\n\n        assert self.service_registration_behaviour.failed_registration_msg is None\n\n    def test_handle_invalid(self):\n        \"\"\"Test the _handle_invalid method of the oef_search handler.\"\"\"\n        # setup\n        invalid_performative = OefSearchMessage.Performative.UNREGISTER_SERVICE\n        incoming_message = self.build_incoming_message(\n            message_type=OefSearchMessage,\n            dialogue_reference=(\"1\", \"\"),\n            performative=invalid_performative,\n            service_description=\"some_service_description\",\n        )\n\n        # operation\n        with patch.object(self.oef_search_handler.context.logger, \"log\") as mock_logger:\n            self.oef_search_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"cannot handle oef_search message of performative={invalid_performative} in dialogue={self.oef_dialogues.get_dialogue(incoming_message)}.\",\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the oef_search handler.\"\"\"\n        assert self.oef_search_handler.teardown() is None\n        self.assert_quantity_in_outbox(0)\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_skills/test_generic_seller/test_models.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the strategy class of the generic seller skill.\"\"\"\n\nfrom pathlib import Path\n\nimport pytest\n\nfrom aea.configurations.constants import DEFAULT_LEDGER\nfrom aea.crypto.ledger_apis import LedgerApis\nfrom aea.helpers.search.models import (\n    Constraint,\n    ConstraintType,\n    Description,\n    Location,\n    Query,\n)\nfrom aea.helpers.transaction.base import Terms\nfrom aea.test_tools.test_skill import BaseSkillTestCase, COUNTERPARTY_AGENT_ADDRESS\n\nfrom packages.fetchai.skills.generic_seller.strategy import (\n    AGENT_LOCATION_MODEL,\n    AGENT_PERSONALITY_MODEL,\n    AGENT_REMOVE_SERVICE_MODEL,\n    AGENT_SET_SERVICE_MODEL,\n    GenericStrategy,\n    SIMPLE_SERVICE_MODEL,\n)\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass TestGenericStrategy(BaseSkillTestCase):\n    \"\"\"Test GenericStrategy of generic seller.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"generic_seller\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.ledger_id = DEFAULT_LEDGER\n        cls.is_ledger_tx = True\n        cls.currency_id = \"some_currency_id\"\n        cls.unit_price = 20\n        cls.service_id = \"some_service_id\"\n        cls.location = {\n            \"longitude\": 0.127,\n            \"latitude\": 51.5194,\n        }\n        cls.service_data = {\"key\": \"seller_service\", \"value\": \"some_service\"}\n        cls.has_data_source = False\n        cls.data_for_sale = {\"some_data_type\": \"some_data\"}\n        cls.strategy = GenericStrategy(\n            ledger_id=cls.ledger_id,\n            is_ledger_tx=cls.is_ledger_tx,\n            currency_id=cls.currency_id,\n            unit_price=cls.unit_price,\n            service_id=cls.service_id,\n            location=cls.location,\n            service_data=cls.service_data,\n            has_data_source=cls.has_data_source,\n            data_for_sale=cls.data_for_sale,\n            name=\"strategy\",\n            skill_context=cls._skill.skill_context,\n        )\n\n    def test_properties(self):\n        \"\"\"Test the properties of GenericStrategy class.\"\"\"\n        assert self.strategy.ledger_id == self.ledger_id\n        assert self.strategy.is_ledger_tx == self.is_ledger_tx\n\n    def test_get_location_description(self):\n        \"\"\"Test the get_location_description method of the GenericStrategy class.\"\"\"\n        description = self.strategy.get_location_description()\n\n        assert type(description) == Description\n        assert description.data_model is AGENT_LOCATION_MODEL\n        assert description.values.get(\"location\", \"\") == Location(\n            latitude=self.location[\"latitude\"], longitude=self.location[\"longitude\"]\n        )\n\n    def test_get_register_service_description(self):\n        \"\"\"Test the get_register_service_description method of the GenericStrategy class.\"\"\"\n        description = self.strategy.get_register_service_description()\n\n        assert type(description) == Description\n        assert description.data_model is AGENT_SET_SERVICE_MODEL\n        assert description.values.get(\"key\", \"\") == \"seller_service\"\n        assert description.values.get(\"value\", \"\") == \"some_service\"\n\n    def test_get_register_personality_description(self):\n        \"\"\"Test the get_register_personality_description method of the GenericStrategy class.\"\"\"\n        description = self.strategy.get_register_personality_description()\n\n        assert type(description) == Description\n        assert description.data_model is AGENT_PERSONALITY_MODEL\n        assert description.values.get(\"piece\", \"\") == \"genus\"\n        assert description.values.get(\"value\", \"\") == \"data\"\n\n    def test_get_register_classification_description(self):\n        \"\"\"Test the get_register_classification_description method of the GenericStrategy class.\"\"\"\n        description = self.strategy.get_register_classification_description()\n\n        assert type(description) == Description\n        assert description.data_model is AGENT_PERSONALITY_MODEL\n        assert description.values.get(\"piece\", \"\") == \"classification\"\n        assert description.values.get(\"value\", \"\") == \"seller\"\n\n    def test_get_service_description(self):\n        \"\"\"Test the get_service_description method of the GenericStrategy class.\"\"\"\n        description = self.strategy.get_service_description()\n\n        assert type(description) == Description\n        assert description.data_model is SIMPLE_SERVICE_MODEL\n        assert description.values.get(\"seller_service\", \"\") == \"some_service\"\n\n    def test_get_unregister_service_description(self):\n        \"\"\"Test the get_unregister_service_description method of the GenericStrategy class.\"\"\"\n        description = self.strategy.get_unregister_service_description()\n\n        assert type(description) == Description\n        assert description.data_model is AGENT_REMOVE_SERVICE_MODEL\n        assert description.values.get(\"key\", \"\") == \"seller_service\"\n\n    def test_is_matching_supply(self):\n        \"\"\"Test the is_matching_supply method of the GenericStrategy class.\"\"\"\n        acceptable_constraint = Constraint(\n            \"seller_service\", ConstraintType(\"==\", \"some_service\")\n        )\n        matching_query = Query([acceptable_constraint])\n        is_matching_supply = self.strategy.is_matching_supply(matching_query)\n        assert is_matching_supply\n\n        unacceptable_constraint = Constraint(\n            \"seller_service\", ConstraintType(\"==\", \"some_other_service\")\n        )\n        unmatching_query = Query([unacceptable_constraint])\n        is_matching_supply = self.strategy.is_matching_supply(unmatching_query)\n        assert not is_matching_supply\n\n    def test_generate_proposal_terms_and_data(self):\n        \"\"\"Test the generate_proposal_terms_and_data method of the GenericStrategy class.\"\"\"\n        # setup\n        seller = self.skill.skill_context.agent_address\n        total_price = len(self.data_for_sale) * self.unit_price\n        sale_quantity = len(self.data_for_sale)\n        tx_nonce = LedgerApis.generate_tx_nonce(\n            identifier=self.ledger_id,\n            seller=seller,\n            client=COUNTERPARTY_AGENT_ADDRESS,\n        )\n        query = Query(\n            [Constraint(\"seller_service\", ConstraintType(\"==\", \"some_service\"))]\n        )\n\n        # expected returned values\n        expected_proposal = Description(\n            {\n                \"ledger_id\": self.ledger_id,\n                \"price\": total_price,\n                \"currency_id\": self.currency_id,\n                \"service_id\": self.service_id,\n                \"quantity\": sale_quantity,\n                \"tx_nonce\": tx_nonce,\n            }\n        )\n        expected_terms = Terms(\n            ledger_id=self.ledger_id,\n            sender_address=seller,\n            counterparty_address=COUNTERPARTY_AGENT_ADDRESS,\n            amount_by_currency_id={self.currency_id: total_price},\n            quantities_by_good_id={self.service_id: -sale_quantity},\n            is_sender_payable_tx_fee=False,\n            nonce=tx_nonce,\n            fee_by_currency_id={self.currency_id: 0},\n        )\n\n        # operation\n        proposal, terms, data = self.strategy.generate_proposal_terms_and_data(\n            query, COUNTERPARTY_AGENT_ADDRESS\n        )\n\n        # after\n        assert proposal == expected_proposal\n        assert terms == expected_terms\n        assert data == self.data_for_sale\n\n    def test_collect_from_data_source(self):\n        \"\"\"Test the collect_from_data_source method of the GenericStrategy class.\"\"\"\n        with pytest.raises(NotImplementedError):\n            self.strategy.collect_from_data_source()\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_skills/test_gym/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"The tests module contains the tests of the packages/skills/gym dir.\"\"\"\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_skills/test_gym/helpers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the handler classes of the ml_train skill.\"\"\"\nfrom typing import Tuple\n\nimport numpy as np\n\n\ndef produce_data(batch_size) -> Tuple:\n    \"\"\"Produce the data.\"\"\"\n    from tensorflow import keras  # pylint: disable=import-outside-toplevel\n\n    ((train_x, train_y), _) = keras.datasets.fashion_mnist.load_data()\n\n    idx = np.arange(train_x.shape[0])\n    mask = np.zeros_like(idx, dtype=bool)\n\n    selected = np.random.choice(idx, batch_size, replace=False)\n    mask[selected] = True\n\n    x_sample = train_x[mask]\n    y_sample = train_y[mask]\n    return x_sample, y_sample\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_skills/test_gym/intermediate_class.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module sets up test environment for gym skill.\"\"\"\n\nfrom pathlib import Path\nfrom typing import cast\n\nfrom aea.protocols.dialogue.base import DialogueLabel, DialogueMessage\nfrom aea.skills.tasks import TaskManager\nfrom aea.test_tools.test_skill import BaseSkillTestCase\n\nfrom packages.fetchai.protocols.gym.custom_types import AnyObject\nfrom packages.fetchai.protocols.gym.message import GymMessage\nfrom packages.fetchai.skills.gym.dialogues import (\n    DefaultDialogues,\n    GymDialogue,\n    GymDialogues,\n)\nfrom packages.fetchai.skills.gym.handlers import GymHandler\nfrom packages.fetchai.skills.gym.helpers import ProxyEnv\nfrom packages.fetchai.skills.gym.rl_agent import GoodPriceModel, MyRLAgent, PriceBandit\nfrom packages.fetchai.skills.gym.tasks import GymTask\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass GymTestCase(BaseSkillTestCase):\n    \"\"\"Sets the gym class up for testing.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"gym\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        cls.nb_steps = 4000\n        config_overrides = {\n            \"handlers\": {\"gym\": {\"args\": {\"nb_steps\": cls.nb_steps}}},\n        }\n\n        super().setup(config_overrides=config_overrides)\n\n        # dialogues\n        cls.default_dialogues = cast(\n            DefaultDialogues, cls._skill.skill_context.default_dialogues\n        )\n        cls.gym_dialogues = cast(GymDialogues, cls._skill.skill_context.gym_dialogues)\n\n        # handlers\n        cls.gym_handler = cast(GymHandler, cls._skill.skill_context.handlers.gym)\n\n        # models\n        cls.task = GymTask(\n            skill_context=cls._skill.skill_context,\n            nb_steps=cls.nb_steps,\n        )\n\n        cls.task_manager = cast(TaskManager, cls._skill.skill_context.task_manager)\n        cls.task_manager.start()\n\n        cls.logger = cls._skill.skill_context.logger\n\n        # mocked objects\n        cls.dict_str_str = {\"some_key\": \"some_value\"}\n        cls.mocked_task_id = 1\n        cls.content_bytes = b\"some_contents\"\n        cls.mocked_status_content = {\"reset\": \"success\"}\n        cls.mocked_action = AnyObject(\"some_action\")\n        cls.mocked_observation = AnyObject(\"some_observation\")\n        cls.mocked_info = AnyObject(\"some_info\")\n        cls.mocked_step_id = 123\n        cls.mocked_reward = 3242.23423\n\n        cls.mocked_price = 765.23\n        cls.mocked_beta_a = 2.876\n        cls.mocked_beta_b = 0.8\n        cls.mocked_bound = 78\n        cls.mocked_nb_goods = 10\n\n        cls.dummy_gym_dialogue = GymDialogue(\n            DialogueLabel(\n                (\"\", \"\"),\n                \"some_counterparty_address\",\n                cls._skill.skill_context.agent_address,\n            ),\n            cls._skill.skill_context.agent_address,\n            role=GymDialogue.Role.AGENT,\n        )\n\n        cls.price_bandit = PriceBandit(\n            cls.mocked_price, cls.mocked_beta_a, cls.mocked_beta_b\n        )\n        cls.good_price_model = GoodPriceModel(cls.mocked_bound)\n        cls.my_rl_agent = MyRLAgent(cls.mocked_nb_goods, cls.logger)\n        cls.proxy_env = ProxyEnv(cls._skill.skill_context)\n\n        # list of messages\n        cls.list_of_gym_messages = (\n            DialogueMessage(GymMessage.Performative.RESET, {}),\n            DialogueMessage(\n                GymMessage.Performative.STATUS, {\"content\": cls.mocked_status_content}\n            ),\n            DialogueMessage(\n                GymMessage.Performative.ACT,\n                {\"action\": cls.mocked_action, \"step_id\": cls.mocked_step_id},\n            ),\n            DialogueMessage(\n                GymMessage.Performative.PERCEPT,\n                {\n                    \"step_id\": cls.mocked_step_id,\n                    \"observation\": cls.mocked_observation,\n                    \"reward\": cls.mocked_reward,\n                    \"done\": True,\n                    \"info\": cls.mocked_info,\n                },\n            ),\n            DialogueMessage(GymMessage.Performative.CLOSE, {}),\n        )\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_skills/test_gym/test_dialogues.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the dialogue classes of the ml_train skill.\"\"\"\n\nfrom aea.test_tools.test_skill import COUNTERPARTY_AGENT_ADDRESS\n\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.protocols.gym.message import GymMessage\nfrom packages.fetchai.skills.gym.dialogues import DefaultDialogue, GymDialogue\n\nfrom tests.test_packages_for_aea_tests.test_skills.test_gym.intermediate_class import (\n    GymTestCase,\n)\n\n\nclass TestDialogues(GymTestCase):\n    \"\"\"Test dialogue classes of gym.\"\"\"\n\n    def test_default_dialogues(self):\n        \"\"\"Test the DefaultDialogues class.\"\"\"\n        _, dialogue = self.default_dialogues.create(\n            counterparty=COUNTERPARTY_AGENT_ADDRESS,\n            performative=DefaultMessage.Performative.BYTES,\n            content=self.content_bytes,\n        )\n        assert dialogue.role == DefaultDialogue.Role.AGENT\n        assert dialogue.self_address == str(self.skill.skill_context.skill_id)\n\n    def test_gym_dialogues(self):\n        \"\"\"Test the GymDialogues class.\"\"\"\n        _, dialogue = self.gym_dialogues.create(\n            counterparty=COUNTERPARTY_AGENT_ADDRESS,\n            performative=GymMessage.Performative.RESET,\n        )\n        assert dialogue.role == GymDialogue.Role.AGENT\n        assert dialogue.self_address == str(self.skill.skill_context.skill_id)\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_skills/test_gym/test_handlers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the handler classes of the gym skill.\"\"\"\nimport logging\nfrom multiprocessing.pool import ApplyResult\nfrom typing import cast\nfrom unittest.mock import Mock, patch\n\nfrom packages.fetchai.protocols.default.message import DefaultMessage\nfrom packages.fetchai.protocols.gym.message import GymMessage\nfrom packages.fetchai.skills.gym.dialogues import GymDialogue\n\nfrom tests.test_packages_for_aea_tests.test_skills.test_gym.intermediate_class import (\n    GymTestCase,\n)\n\n\nclass TestGymHandler(GymTestCase):\n    \"\"\"Test Gym handler of gym.\"\"\"\n\n    is_agent_to_agent_messages = False\n\n    def test__init__(self):\n        \"\"\"Test the __init__ method of the gym handler.\"\"\"\n        assert self.gym_handler._task_id is None\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the gym handler.\"\"\"\n        # operation\n        with patch.object(\n            self.task_manager, \"enqueue_task\", return_value=self.mocked_task_id\n        ) as mocked_enqueue_task:\n            with patch.object(self.logger, \"log\") as mock_logger:\n                assert self.gym_handler.setup() is None\n\n        # after\n        self.assert_quantity_in_outbox(0)\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            \"Gym handler: setup method called.\",\n        )\n        mocked_enqueue_task.assert_any_call(self.gym_handler.task)\n        assert self.gym_handler._task_id == self.mocked_task_id\n\n    def test_handle_unidentified_dialogue(self):\n        \"\"\"Test the _handle_unidentified_dialogue method of the gym handler.\"\"\"\n        # setup\n        incorrect_dialogue_reference = (\"\", \"\")\n        incoming_message = self.build_incoming_message(\n            message_type=GymMessage,\n            dialogue_reference=incorrect_dialogue_reference,\n            performative=GymMessage.Performative.RESET,\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.gym_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.INFO,\n            f\"received invalid gym message={incoming_message}, unidentified dialogue.\",\n        )\n\n        self.assert_quantity_in_outbox(1)\n\n        message = self.get_message_from_outbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=DefaultMessage,\n            performative=DefaultMessage.Performative.ERROR,\n            to=incoming_message.sender,\n            sender=str(self.skill.skill_context.skill_id),\n            error_code=DefaultMessage.ErrorCode.INVALID_DIALOGUE,\n            error_msg=\"Invalid dialogue.\",\n            error_data={\"gym_message\": incoming_message.encode()},\n        )\n        assert has_attributes, error_str\n\n    def test_handle_percept_i(self):\n        \"\"\"Test the _handle_percept method of the gym handler where active_gym_dialogue==gym_dialogeu.\"\"\"\n        # setup\n        gym_dialogue = cast(\n            GymDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.gym_dialogues,\n                messages=self.list_of_gym_messages[:3],\n            ),\n        )\n        incoming_message = cast(\n            GymMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=gym_dialogue,\n                performative=GymMessage.Performative.PERCEPT,\n                step_id=self.mocked_step_id,\n                observation=self.mocked_observation,\n                reward=self.mocked_reward,\n                done=True,\n                info=self.mocked_info,\n            ),\n        )\n\n        self.gym_handler.task.proxy_env._active_dialogue = gym_dialogue\n\n        # operation\n        with patch.object(\n            self.gym_handler.task.proxy_env_queue,\n            \"put\",\n        ) as mocked_put:\n            self.gym_handler.handle(incoming_message)\n\n        # after\n        mocked_put.assert_any_call(incoming_message)\n\n    def test_handle_percept_ii(self):\n        \"\"\"Test the _handle_percept method of the gym handler where active_gym_dialogue!=gym_dialogeu.\"\"\"\n        # setup\n        gym_dialogue = cast(\n            GymDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.gym_dialogues,\n                messages=self.list_of_gym_messages[:3],\n            ),\n        )\n        incoming_message = cast(\n            GymMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=gym_dialogue,\n                performative=GymMessage.Performative.PERCEPT,\n                step_id=self.mocked_step_id,\n                observation=self.mocked_observation,\n                reward=self.mocked_reward,\n                done=True,\n                info=self.mocked_info,\n            ),\n        )\n\n        gym_dialogue_ii = cast(\n            GymDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.gym_dialogues,\n                messages=self.list_of_gym_messages[:1],\n            ),\n        )\n        self.gym_handler.task.proxy_env._active_dialogue = gym_dialogue_ii\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.gym_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            \"gym dialogue not active dialogue.\",\n        )\n\n    def test_handle_status_i(self):\n        \"\"\"Test the _handle_status method of the gym handler where active_gym_dialogue==gym_dialogeu and reset == success.\"\"\"\n        # setup\n        gym_dialogue = cast(\n            GymDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.gym_dialogues,\n                messages=self.list_of_gym_messages[:1],\n            ),\n        )\n        incoming_message = cast(\n            GymMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=gym_dialogue,\n                performative=GymMessage.Performative.STATUS,\n                content=self.mocked_status_content,\n            ),\n        )\n\n        self.gym_handler.task.proxy_env._active_dialogue = gym_dialogue\n\n        # operation\n        with patch.object(\n            self.gym_handler.task.proxy_env_queue,\n            \"put\",\n        ) as mocked_put:\n            self.gym_handler.handle(incoming_message)\n\n        # after\n        mocked_put.assert_any_call(incoming_message)\n\n    def test_handle_status_ii(self):\n        \"\"\"Test the _handle_status method of the gym handler where active_gym_dialogue==gym_dialogeu and reset == success.\"\"\"\n        # setup\n        gym_dialogue = cast(\n            GymDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.gym_dialogues,\n                messages=self.list_of_gym_messages[:1],\n            ),\n        )\n        incoming_message = cast(\n            GymMessage,\n            self.build_incoming_message_for_skill_dialogue(\n                dialogue=gym_dialogue,\n                performative=GymMessage.Performative.STATUS,\n                content={\"reset\": \"failure\"},\n            ),\n        )\n\n        gym_dialogue_ii = cast(\n            GymDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.gym_dialogues,\n                messages=self.list_of_gym_messages[:1],\n            ),\n        )\n        self.gym_handler.task.proxy_env._active_dialogue = gym_dialogue_ii\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.gym_handler.handle(incoming_message)\n\n        # after\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            \"gym dialogue not active dialogue.\",\n        )\n\n    def test_handle_invalid(self):\n        \"\"\"Test the _handle_invalid method of the gym handler.\"\"\"\n        # setup\n        incoming_message = self.build_incoming_message(\n            message_type=GymMessage,\n            performative=GymMessage.Performative.RESET,\n        )\n\n        # operation\n        with patch.object(self.logger, \"log\") as mock_logger:\n            self.gym_handler.handle(incoming_message)\n\n        # after\n        gym_dialogue = cast(\n            GymDialogue, self.gym_dialogues.get_dialogue(incoming_message)\n        )\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            f\"cannot handle gym message of performative={incoming_message.performative} in dialogue={gym_dialogue}.\",\n        )\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the gym handler.\"\"\"\n        # setup\n        self.gym_handler._task_id = self.mocked_task_id\n\n        mock_task_result = Mock(wraps=ApplyResult)\n        mock_task_result.ready.return_value = True\n        mock_task_result.successful.return_value = False\n\n        # operation\n        with patch.object(\n            self.gym_handler.task, \"teardown\"\n        ) as mocked_gym_task_teardown:\n            with patch.object(\n                self.task_manager, \"get_task_result\", return_value=mock_task_result\n            ) as mocked_get_result:\n                with patch.object(self.logger, \"log\") as mock_logger:\n                    assert self.gym_handler.teardown() is None\n\n        # after\n        self.assert_quantity_in_outbox(0)\n\n        mock_logger.assert_any_call(\n            logging.INFO,\n            \"Gym handler: teardown method called.\",\n        )\n        mocked_gym_task_teardown.assert_called_once()\n        mocked_get_result.assert_any_call(self.mocked_task_id)\n        mock_logger.assert_any_call(\n            logging.WARNING,\n            \"Task not successful!\",\n        )\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_skills/test_gym/test_helpers.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests for the helpers module of the gym skill.\"\"\"\n\nfrom typing import cast\nfrom unittest.mock import patch\n\nimport pytest\n\nfrom packages.fetchai.protocols.gym.message import GymMessage\nfrom packages.fetchai.skills.gym.dialogues import GymDialogue\n\nfrom tests.test_packages_for_aea_tests.test_skills.test_gym.intermediate_class import (\n    GymTestCase,\n)\n\n\nclass TestProxyEnv(GymTestCase):\n    \"\"\"Test ProxyEnv of gym.\"\"\"\n\n    is_agent_to_agent_messages = False\n\n    def test__init__(self):\n        \"\"\"Test the __init__ method of the ProxyEnv class.\"\"\"\n        assert self.proxy_env._is_rl_agent_trained is False\n        assert self.proxy_env._step_count == 0\n        assert self.proxy_env._active_dialogue is None\n\n    def test_properties(self):\n        \"\"\"Test the properties of the ProxyEnv class.\"\"\"\n        assert self.proxy_env.gym_dialogues == self.gym_dialogues\n\n        with pytest.raises(ValueError, match=\"GymDialogue not set yet.\"):\n            assert self.proxy_env.active_gym_dialogue\n        self.proxy_env._active_dialogue = self.dummy_gym_dialogue\n        assert self.proxy_env.active_gym_dialogue == self.dummy_gym_dialogue\n\n        assert self.proxy_env.queue == self.proxy_env._queue\n        assert self.proxy_env.is_rl_agent_trained is False\n\n    def test_step_i(self):\n        \"\"\"Test the step method of the ProxyEnv class where no exception.\"\"\"\n        # setup\n        action = \"some_action\"\n        gym_dialogue = cast(\n            GymDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.gym_dialogues,\n                messages=self.list_of_gym_messages[:2],\n            ),\n        )\n        self.proxy_env._active_dialogue = gym_dialogue\n        percept_msg = self.build_incoming_message(\n            message_type=GymMessage,\n            performative=GymMessage.Performative.PERCEPT,\n            step_id=self.proxy_env._step_count + 1,\n            observation=self.mocked_observation,\n            reward=self.mocked_reward,\n            done=True,\n            info=self.mocked_info,\n        )\n\n        # operation\n        with patch.object(\n            self.proxy_env._queue, \"get\", return_value=percept_msg\n        ) as mocked_q_get:\n            (\n                actual_observation,\n                actual_reward,\n                actual_done,\n                actual_info,\n            ) = self.proxy_env.step(action)\n\n        # after\n\n        # _encode_and_send_action\n        self.assert_quantity_in_outbox(1)\n\n        message = self.get_message_from_outbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=GymMessage,\n            performative=GymMessage.Performative.ACT,\n            to=gym_dialogue.dialogue_label.dialogue_opponent_addr,\n            sender=str(self.skill.skill_context.skill_id),\n            action=GymMessage.AnyObject(action),\n            step_id=self.proxy_env._step_count,\n        )\n        assert has_attributes, error_str\n\n        mocked_q_get.assert_called_with(block=True, timeout=None)\n\n        assert actual_observation == self.mocked_observation.any\n        assert actual_reward == self.mocked_reward\n        assert actual_done is True\n        assert actual_info == self.mocked_info.any\n\n    def test_step_ii(self):\n        \"\"\"Test the step method of the ProxyEnv class where performative is NOT percept.\"\"\"\n        # setup\n        action = \"some_action\"\n        gym_dialogue = cast(\n            GymDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.gym_dialogues,\n                messages=self.list_of_gym_messages[:2],\n            ),\n        )\n        self.proxy_env._active_dialogue = gym_dialogue\n        invalid_percept_msg = self.build_incoming_message(\n            message_type=GymMessage,\n            performative=GymMessage.Performative.RESET,\n        )\n\n        # operation\n        with patch.object(\n            self.proxy_env._queue, \"get\", return_value=invalid_percept_msg\n        ) as mocked_q_get:\n            with pytest.raises(\n                ValueError,\n                match=f\"Unexpected performative. Expected={GymMessage.Performative.PERCEPT} got={invalid_percept_msg.performative}\",\n            ):\n                self.proxy_env.step(action)\n\n        # # after\n\n        # _encode_and_send_action\n        self.assert_quantity_in_outbox(1)\n\n        message = self.get_message_from_outbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=GymMessage,\n            performative=GymMessage.Performative.ACT,\n            to=gym_dialogue.dialogue_label.dialogue_opponent_addr,\n            sender=str(self.skill.skill_context.skill_id),\n            action=GymMessage.AnyObject(action),\n            step_id=self.proxy_env._step_count,\n        )\n        assert has_attributes, error_str\n\n        mocked_q_get.assert_called_with(block=True, timeout=None)\n\n    def test_step_iii(self):\n        \"\"\"Test the step method of the ProxyEnv class where performative is NOT percept.\"\"\"\n        # setup\n        action = \"some_action\"\n        gym_dialogue = cast(\n            GymDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.gym_dialogues,\n                messages=self.list_of_gym_messages[:2],\n            ),\n        )\n        self.proxy_env._active_dialogue = gym_dialogue\n        invalid_percept_msg = self.build_incoming_message(\n            message_type=GymMessage,\n            performative=GymMessage.Performative.PERCEPT,\n            step_id=self.proxy_env._step_count,\n            observation=self.mocked_observation,\n            reward=self.mocked_reward,\n            done=True,\n            info=self.mocked_info,\n        )\n\n        # operation\n        with patch.object(\n            self.proxy_env._queue, \"get\", return_value=invalid_percept_msg\n        ) as mocked_q_get:\n            with pytest.raises(\n                ValueError,\n                match=f\"Unexpected step id! expected={self.proxy_env._step_count+1}, actual={self.proxy_env._step_count}\",\n            ):\n                self.proxy_env.step(action)\n\n        # # after\n\n        # _encode_and_send_action\n        self.assert_quantity_in_outbox(1)\n\n        message = self.get_message_from_outbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=GymMessage,\n            performative=GymMessage.Performative.ACT,\n            to=gym_dialogue.dialogue_label.dialogue_opponent_addr,\n            sender=str(self.skill.skill_context.skill_id),\n            action=GymMessage.AnyObject(action),\n            step_id=self.proxy_env._step_count,\n        )\n        assert has_attributes, error_str\n\n        mocked_q_get.assert_called_with(block=True, timeout=None)\n\n    def test_reset_i(self):\n        \"\"\"Test the reset method of the ProxyEnv class where no exception.\"\"\"\n        # setup\n        status_msg = self.build_incoming_message(\n            message_type=GymMessage,\n            performative=GymMessage.Performative.STATUS,\n            content=self.mocked_status_content,\n        )\n\n        # operation\n        with patch.object(\n            self.proxy_env._queue, \"get\", return_value=status_msg\n        ) as mocked_q_get:\n            self.proxy_env.reset()\n\n        # after\n        assert self.proxy_env._step_count == 0\n        assert self.proxy_env._is_rl_agent_trained is False\n        assert self.proxy_env._active_dialogue is not None\n\n        self.assert_quantity_in_outbox(1)\n        message = self.get_message_from_outbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=GymMessage,\n            performative=GymMessage.Performative.RESET,\n            to=self.proxy_env.gym_address,\n            sender=str(self.skill.skill_context.skill_id),\n        )\n        assert has_attributes, error_str\n\n        mocked_q_get.assert_called_with(block=True, timeout=None)\n\n    def test_reset_ii(self):\n        \"\"\"Test the reset method of the ProxyEnv class where performative is NOT status.\"\"\"\n        # setup\n        invalid_msg = self.build_incoming_message(\n            message_type=GymMessage,\n            performative=GymMessage.Performative.RESET,\n        )\n\n        # operation\n        with patch.object(\n            self.proxy_env._queue, \"get\", return_value=invalid_msg\n        ) as mocked_q_get:\n            with pytest.raises(\n                ValueError,\n                match=f\"Unexpected performative. Expected={GymMessage.Performative.STATUS} got={invalid_msg.performative}\",\n            ):\n                self.proxy_env.reset()\n\n        # after\n        assert self.proxy_env._step_count == 0\n        assert self.proxy_env._is_rl_agent_trained is False\n        assert self.proxy_env._active_dialogue is not None\n\n        self.assert_quantity_in_outbox(1)\n        message = self.get_message_from_outbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=GymMessage,\n            performative=GymMessage.Performative.RESET,\n            to=self.proxy_env.gym_address,\n            sender=str(self.skill.skill_context.skill_id),\n        )\n        assert has_attributes, error_str\n\n        mocked_q_get.assert_called_with(block=True, timeout=None)\n\n    def test_close_i(self):\n        \"\"\"Test the close method of the ProxyEnv class.\"\"\"\n        # setup\n        self.proxy_env._is_rl_agent_trained = True\n        gym_dialogue = cast(\n            GymDialogue,\n            self.prepare_skill_dialogue(\n                dialogues=self.gym_dialogues,\n                messages=self.list_of_gym_messages[:4],\n            ),\n        )\n        self.proxy_env._active_dialogue = gym_dialogue\n\n        # operation\n        self.proxy_env.close()\n\n        # after\n        self.assert_quantity_in_outbox(1)\n\n        message = self.get_message_from_outbox()\n        has_attributes, error_str = self.message_has_attributes(\n            actual_message=message,\n            message_type=GymMessage,\n            performative=GymMessage.Performative.CLOSE,\n            to=gym_dialogue.dialogue_label.dialogue_opponent_addr,\n            sender=str(self.skill.skill_context.skill_id),\n        )\n        assert has_attributes, error_str\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_skills/test_gym/test_rl_agent.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests for the rl_agent module of the gym skill.\"\"\"\n\nimport copy\nfrom unittest.mock import patch\n\nfrom packages.fetchai.skills.gym.helpers import ProxyEnv\nfrom packages.fetchai.skills.gym.rl_agent import GoodPriceModel\n\nfrom tests.test_packages_for_aea_tests.test_skills.test_gym.intermediate_class import (\n    GymTestCase,\n)\n\n\nclass TestPriceBandit(GymTestCase):\n    \"\"\"Test PriceBandit of gym.\"\"\"\n\n    def test_sample(self):\n        \"\"\"Test the sample method of PriceBandit class.\"\"\"\n        sample = self.price_bandit.sample()\n        assert type(sample) == int\n\n    def test_update(self):\n        \"\"\"Test the update method of the PriceBandit class.\"\"\"\n        # before\n        assert self.price_bandit.beta_a == self.mocked_beta_a\n        assert self.price_bandit.beta_b == self.mocked_beta_b\n\n        # operation\n        self.price_bandit.update(True)\n\n        # after & before\n        assert self.price_bandit.beta_a == self.mocked_beta_a + 1\n        assert self.price_bandit.beta_b == self.mocked_beta_b\n\n        # operation\n        self.price_bandit.update(False)\n\n        # after\n        assert self.price_bandit.beta_a == self.mocked_beta_a + 1\n        assert self.price_bandit.beta_b == self.mocked_beta_b + 1\n\n\nclass TestGoodPriceModel(GymTestCase):\n    \"\"\"Test GoodPriceModel of gym.\"\"\"\n\n    def test_update_i(self):\n        \"\"\"Test the update method of the GoodPriceModel class where outcome is True.\"\"\"\n        # setup\n        outcome = True\n        mocked_price = 46\n        before_prices = copy.deepcopy(self.good_price_model.price_bandits)\n\n        # operation\n        self.good_price_model.update(outcome, mocked_price)\n\n        # after\n        assert (\n            self.good_price_model.price_bandits[mocked_price].beta_a\n            != before_prices[mocked_price].beta_a\n            and self.good_price_model.price_bandits[mocked_price].beta_b\n            == before_prices[mocked_price].beta_b\n        )\n        for price in range(self.mocked_bound + 1):\n            if price != mocked_price:\n                assert (\n                    self.good_price_model.price_bandits[price].beta_a\n                    == before_prices[price].beta_a\n                    and self.good_price_model.price_bandits[price].beta_b\n                    == before_prices[price].beta_b\n                )\n\n    def test_update_ii(self):\n        \"\"\"Test the update method of the GoodPriceModel class where outcome is False.\"\"\"\n        # setup\n        outcome = False\n        mocked_price = 12\n        before_prices = copy.deepcopy(self.good_price_model.price_bandits)\n\n        # operation\n        self.good_price_model.update(outcome, mocked_price)\n\n        # after\n        assert (\n            self.good_price_model.price_bandits[mocked_price].beta_a\n            == before_prices[mocked_price].beta_a\n            and self.good_price_model.price_bandits[mocked_price].beta_b\n            != before_prices[mocked_price].beta_b\n        )\n        for price in range(self.mocked_bound + 1):\n            if price != mocked_price:\n                assert (\n                    self.good_price_model.price_bandits[price].beta_a\n                    == before_prices[price].beta_a\n                    and self.good_price_model.price_bandits[price].beta_b\n                    == before_prices[price].beta_b\n                )\n\n    def test_get_price_expectation(self):\n        \"\"\"Test the get_price_expectation method of GoodPriceModel class.\"\"\"\n        expectation = self.good_price_model.get_price_expectation()\n        assert type(expectation) == int\n\n\nclass TestMyRLAgent(GymTestCase):\n    \"\"\"Test MyRLAgent of gym.\"\"\"\n\n    def test_fit(self):\n        \"\"\"Test the fit method of the MyRLAgent class.\"\"\"\n        # setup\n        step_result = (\"obs\", \"reward\", \"done\", \"info\")\n\n        # operation\n        with patch.object(ProxyEnv, \"reset\") as mocked_reset:\n            with patch.object(\n                ProxyEnv, \"step\", return_value=step_result\n            ) as mocked_step:\n                with patch.object(ProxyEnv, \"close\") as mocked_close:\n                    with patch.object(\n                        GoodPriceModel, \"get_price_expectation\"\n                    ) as mocked_price_exp:\n                        with patch.object(GoodPriceModel, \"update\") as mocked_update:\n                            with patch.object(self.logger, \"log\") as mock_logger:\n                                self.my_rl_agent.fit(self.proxy_env, self.nb_steps)\n\n        # after\n        # fit\n        mocked_reset.assert_called_once()\n\n        # _pick_an_action\n        mocked_price_exp.assert_called()\n        assert mocked_price_exp.call_count == self.nb_steps\n\n        # fit\n        mocked_step.assert_called()\n        assert mocked_step.call_count == self.nb_steps\n\n        # _update_model\n        mocked_update.assert_called()\n        assert mocked_update.call_count == self.nb_steps\n\n        # fit\n        mock_logger.assert_called()\n        mocked_close.assert_called()\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_skills/test_gym/test_task.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the task class of the gym skill.\"\"\"\n\nfrom unittest.mock import patch\n\nfrom tests.test_packages_for_aea_tests.test_skills.test_gym.intermediate_class import (\n    GymTestCase,\n)\n\n\nclass TestTask(GymTestCase):\n    \"\"\"Test Task of gym.\"\"\"\n\n    def test__init__(self):\n        \"\"\"Test the __init__ method of the GymTask class.\"\"\"\n        assert self.task.nb_steps == self.nb_steps\n        assert self.task.is_rl_agent_training is False\n\n    def test_properties(self):\n        \"\"\"Test the properties of the GymTask class.\"\"\"\n        assert self.task.proxy_env == self.task._proxy_env\n        assert self.task.proxy_env_queue == self.task._proxy_env.queue\n\n    def test_setup(self):\n        \"\"\"Test the setup method of the GymTask class.\"\"\"\n        # operation\n        with patch.object(self.logger, \"info\") as mock_logger:\n            self.task.setup()\n\n        # after\n        mock_logger.assert_any_call(\"Gym task: setup method called.\")\n\n    def test_execute_i(self):\n        \"\"\"Test the execute method of the GymTask class where agent is NOT trained/training.\"\"\"\n        # before\n        self.task.proxy_env._is_rl_agent_trained = False\n        self.task.is_rl_agent_training = False\n\n        # operation\n        with patch.object(self.task._rl_agent, \"fit\") as mock_fit:\n            with patch.object(self.logger, \"info\") as mock_logger:\n                self.task.execute()\n\n        # after\n        # _start_training\n        mock_logger.assert_any_call(\"Training starting ...\")\n        assert self.task.is_rl_agent_training is True\n\n        # _fit\n        mock_fit.assert_called_with(self.task.proxy_env, self.nb_steps)\n        mock_logger.assert_any_call(\"Training finished. You can exit now via CTRL+C.\")\n\n    def test_execute_ii(self):\n        \"\"\"Test the execute method of the GymTask class where agent IS trained/training.\"\"\"\n        # before\n        self.task.proxy_env._is_rl_agent_trained = True\n        self.task.is_rl_agent_training = True\n\n        # operation\n        with patch.object(self.task.proxy_env, \"close\") as mock_close:\n            self.task.execute()\n\n        # after\n        # _stop_training\n        assert self.task.is_rl_agent_training is False\n        mock_close.assert_called_once()\n\n    def test_teardown(self):\n        \"\"\"Test the teardown method of the GymTask class.\"\"\"\n        self.task.is_rl_agent_training = True\n\n        # operation\n        with patch.object(self.task.proxy_env, \"close\") as mock_close:\n            with patch.object(self.logger, \"info\") as mock_logger:\n                self.task.teardown()\n\n        # after\n        mock_logger.assert_any_call(\"Gym Task: teardown method called.\")\n\n        # _stop_training\n        assert self.task.is_rl_agent_training is False\n        mock_close.assert_called_once()\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_skills/test_weather_station/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\n\"\"\"The tests module contains the tests of the packages/skills/weather_station dir.\"\"\"\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_skills/test_weather_station/test_dummy_weather_station_data.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the dummy_weather_station_data class of the weather station skill.\"\"\"\nimport datetime\nimport sqlite3\nfrom pathlib import Path\nfrom unittest.mock import Mock, patch\n\nfrom aea.test_tools.test_skill import BaseSkillTestCase\n\nfrom packages.fetchai.skills.weather_station.dummy_weather_station_data import Forecast\nfrom packages.fetchai.skills.weather_station.dummy_weather_station_data import (\n    _default_logger as logger,\n)\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass TestDummyWeatherStationData(BaseSkillTestCase):\n    \"\"\"Test dummy_weather_station_data of weather station.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"weather_station\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.forecast = Forecast()\n\n    def test_generate(self):\n        \"\"\"Test the generate method of the Forecast class.\"\"\"\n        # operation\n        with patch.object(self.forecast, \"add_data\") as mock_add:\n            self.forecast.generate(2)\n\n        # after\n        assert mock_add.call_count == 2\n\n    def test_add_data(self):\n        \"\"\"Test the add_data method of the Forecast class.\"\"\"\n        # setup\n        tagged_data = {\n            \"abs_pressure\": 100,\n            \"delay\": 20,\n            \"hum_in\": 20,\n            \"hum_out\": 20,\n            int(\n                (\n                    datetime.datetime.now() - datetime.datetime.fromtimestamp(0)\n                ).total_seconds()\n            ): 20,\n            \"rain\": 20,\n            \"temp_in\": 20,\n            \"temp_out\": 20,\n            \"wind_ave\": 20,\n            \"wind_dir\": 20,\n            \"wind_gust\": 20,\n        }\n\n        mocked_conn = Mock(wrap=sqlite3.Connection)\n        mocked_cursor = Mock(wraps=sqlite3.Cursor)\n\n        # operation\n        with patch(\"sqlite3.connect\", return_value=mocked_conn) as mock_conn:\n            with patch.object(\n                mocked_conn, \"cursor\", return_value=mocked_cursor\n            ) as mock_curs:\n                with patch.object(mocked_cursor, \"execute\") as mock_exe:\n                    with patch.object(logger, \"info\") as mock_logger:\n                        with patch.object(mocked_cursor, \"close\") as mock_cur_close:\n                            with patch.object(mocked_conn, \"commit\") as mock_con_commit:\n                                with patch.object(\n                                    mocked_conn, \"close\"\n                                ) as mock_con_close:\n                                    self.forecast.add_data(tagged_data)\n\n        # after\n        mock_conn.assert_called_once()\n        mock_curs.assert_called_once()\n        mock_exe.assert_any_call(\n            \"\"\"INSERT INTO data(abs_pressure,\n                                       delay,\n                                       hum_in,\n                                       hum_out,\n                                       idx,\n                                       rain,\n                                       temp_in,\n                                       temp_out,\n                                       wind_ave,\n                                       wind_dir,\n                                       wind_gust) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\"\"\",\n            (\n                tagged_data[\"abs_pressure\"],\n                tagged_data[\"delay\"],\n                tagged_data[\"hum_in\"],\n                tagged_data[\"hum_out\"],\n                int(\n                    (\n                        datetime.datetime.now() - datetime.datetime.fromtimestamp(0)\n                    ).total_seconds()\n                ),\n                tagged_data[\"rain\"],\n                tagged_data[\"temp_in\"],\n                tagged_data[\"temp_out\"],\n                tagged_data[\"wind_ave\"],\n                tagged_data[\"wind_dir\"],\n                tagged_data[\"wind_gust\"],\n            ),\n        )\n        mock_logger.assert_any_call(\"Wheather station: I added data in the db!\")\n        mock_cur_close.assert_called_once()\n        mock_con_commit.assert_called_once()\n        mock_con_close.assert_called_once()\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_skills/test_weather_station/test_registration_db.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the RegistrationDB class of the weather station skill.\"\"\"\nimport datetime\nimport sqlite3\nfrom pathlib import Path\nfrom unittest.mock import Mock, patch\n\nfrom aea.test_tools.test_skill import BaseSkillTestCase\n\nfrom packages.fetchai.skills.weather_station.db_communication import (\n    DBCommunication,\n    DB_SOURCE,\n)\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass TestDBCommunication(BaseSkillTestCase):\n    \"\"\"Test RegistrationDB of weather station.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"weather_station\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.db = DBCommunication()\n\n    def test_db_connection(self):\n        \"\"\"Test the db_connection method of the DBCommunication class.\"\"\"\n        # setup\n        mocked_conn = Mock(wrap=sqlite3.Connection)\n\n        # operation\n        with patch(\"sqlite3.connect\", return_value=mocked_conn) as mock_conn:\n            actual_con = self.db.db_connection()\n\n        # after\n        mock_conn.assert_any_call(DB_SOURCE)\n        assert actual_con == mocked_conn\n\n    def test_get_data_for_specific_dates(self):\n        \"\"\"Test the get_data_for_specific_dates method of the DBCommunication class.\"\"\"\n        # setup\n        start_date = \"3/10/2019\"\n        end_date = \"15/10/2019\"\n        result = {\"abs_pressure\": 100, \"hum_in\": 20}\n\n        start_dt = datetime.datetime.strptime(start_date, \"%d/%m/%Y\")\n        end_dt = datetime.datetime.strptime(end_date, \"%d/%m/%Y\")\n\n        start = int((start_dt - datetime.datetime.fromtimestamp(0)).total_seconds())\n        end = int((end_dt - datetime.datetime.fromtimestamp(0)).total_seconds())\n\n        mocked_conn = Mock(wrap=sqlite3.Connection)\n        mocked_cursor = Mock(wraps=sqlite3.Cursor)\n\n        # operation\n        with patch.object(\n            self.db, \"db_connection\", return_value=mocked_conn\n        ) as mock_conn:\n            with patch.object(\n                mocked_conn, \"cursor\", return_value=mocked_cursor\n            ) as mock_curs:\n                with patch.object(mocked_cursor, \"execute\") as mock_exe:\n                    with patch.object(\n                        mocked_cursor, \"fetchall\", return_value=result\n                    ) as mock_fetchall:\n                        with patch.object(mocked_cursor, \"close\") as mock_cur_close:\n                            with patch.object(mocked_conn, \"close\") as mock_con_close:\n                                actual_result = self.db.get_data_for_specific_dates(\n                                    start_date, end_date\n                                )\n\n        # after\n        mock_conn.assert_called_once()\n        mock_curs.assert_called_once()\n        mock_fetchall.assert_called_once()\n        mock_exe.assert_any_call(\n            \"SELECT * FROM data WHERE idx BETWEEN ? AND ?\",\n            (str(start), str(end)),\n        )\n        mock_cur_close.assert_called_once()\n        mock_con_close.assert_called_once()\n        assert actual_result == result\n"
  },
  {
    "path": "tests/test_packages_for_aea_tests/test_skills/test_weather_station/test_strategy.py",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n#\n#   Copyright 2018-2023 Fetch.AI Limited\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n# ------------------------------------------------------------------------------\n\"\"\"This module contains the tests of the strategy class of the weather station skill.\"\"\"\n\nimport json\nimport time\nfrom pathlib import Path\nfrom unittest.mock import patch\n\nfrom aea.test_tools.test_skill import BaseSkillTestCase\n\nfrom packages.fetchai.skills.weather_station.strategy import (\n    DEFAULT_DATE_ONE,\n    DEFAULT_DATE_TWO,\n    Strategy,\n)\n\nfrom tests.conftest import ROOT_DIR\n\n\nclass TestStrategy(BaseSkillTestCase):\n    \"\"\"Test Strategy of weather station.\"\"\"\n\n    path_to_skill = Path(ROOT_DIR, \"packages\", \"fetchai\", \"skills\", \"weather_station\")\n\n    @classmethod\n    def setup(cls):\n        \"\"\"Setup the test class.\"\"\"\n        super().setup()\n        cls.strategy = Strategy(\n            date_one=DEFAULT_DATE_ONE,\n            date_two=DEFAULT_DATE_TWO,\n            name=\"strategy\",\n            skill_context=cls._skill.skill_context,\n        )\n\n    def test_collect_from_data_source(self):\n        \"\"\"Test the collect_from_data_source method of the Strategy class.\"\"\"\n        # setup\n        fetched_data = [\n            (1023, 4, 35, 70, 1615894962, 72, 23, 22, 5, 3, 4),\n            (1024, 3, 34, 50, 1615894961, 71, 19, 5, 2, 12, 2),\n            (1025, 5, 36, 40, 1615894963, 73, 28, 20, 6, 4, 7),\n            (1023, 7, 38, 75, 1615894964, 74, 25, 16, 9, 2, 5),\n            (1025, 6, 37, 80, 1615894965, 72, 22, 12, 3, 8, 3),\n        ]\n        counter = 0\n        row_data = {}\n        for items in fetched_data:\n            counter += 1\n            dict_of_data = {\n                \"abs_pressure\": items[0],\n                \"delay\": items[1],\n                \"hum_in\": items[2],\n                \"hum_out\": items[3],\n                \"idx\": time.ctime(int(items[4])),\n                \"rain\": items[5],\n                \"temp_in\": items[6],\n                \"temp_out\": items[7],\n                \"wind_ave\": items[8],\n                \"wind_dir\": items[9],\n                \"wind_gust\": items[10],\n            }\n            row_data[counter] = dict_of_data\n        expected_weather_data = {\"weather_data\": json.dumps(row_data)}\n\n        # operation\n        with patch.object(\n            self.strategy.db, \"get_data_for_specific_dates\", return_value=fetched_data\n        ) as mock_get_data:\n            weather_data = self.strategy.collect_from_data_source()\n\n        # after\n        mock_get_data.assert_any_call(DEFAULT_DATE_ONE, DEFAULT_DATE_TWO)\n        assert weather_data == expected_weather_data\n"
  },
  {
    "path": "tox.ini",
    "content": "; By default, testenvs are configured to:\n; - don't skip dist (skipsdist = False)\n; - don't skip the package installation (skip_install = False)\n; - don't use source installation (usedevelop = False)\n; where one of those steps is not necessary for the test,\n; we set the associated flag (e.g. for linting we don't need\n; the package installation).\n[tox]\nenvlist = bandit, black, black-check, isort, isort-check, copyright_check, docs, flake8, liccheck, mypy, py{3.8,3.9,3.10}, dependencies_check, plugins_deps\nisolated_build = True\n\n[testenv]\nbasepython = python3\nallowlist_externals =\n    /bin/sh\n    make\npassenv = *\nextras = all\ndeps = poetry\ncommands =\n    poetry install --only testing,main,packages -E all\n    poetry run pip install openapi-core==0.13.2\n    poetry run python ./install_packages.py jsonschema\n    poetry run python -m pip install file://{toxinidir}/plugins/aea-ledger-ethereum\n    poetry run python -m pip install file://{toxinidir}/plugins/aea-ledger-cosmos\n    poetry run python -m pip install file://{toxinidir}/plugins/aea-ledger-fetchai\n    poetry run python -m pip install file://{toxinidir}/plugins/aea-cli-ipfs\n    poetry run python ./install_packages.py black isort\n    poetry run pytest -rfE --cov=aea --cov-report=html --cov-report=term-missing --cov-config=pyproject.toml {posargs}\n\n[testenv:py3.8]\nbasepython = python3.8\n\n[testenv:py3.8-cov]\nbasepython = python3.8\nusedevelop = True\n\n[testenv:py3.9]\nbasepython = python3.9\n\n[testenv:py3.10]\nbasepython = python3.10\n\n[plugins]\ncommands =\n    poetry install --only main,testing -E all\n    poetry run python -m pip install file://{toxinidir}/plugins/aea-ledger-ethereum\n    poetry run python -m pip install file://{toxinidir}/plugins/aea-ledger-cosmos\n    poetry run python -m pip install file://{toxinidir}/plugins/aea-ledger-fetchai\n    poetry run python -m pip install file://{toxinidir}/plugins/aea-cli-ipfs\n    poetry run pytest -rfE plugins/aea-ledger-fetchai/tests --cov-report=html --cov-report=term-missing --cov=aea_ledger_fetchai --cov-config=pyproject.toml --suppress-no-test-exit-code {posargs}\n    poetry run pytest -rfE plugins/aea-ledger-ethereum/tests --cov-report=html --cov-report=term-missing --cov=aea_ledger_ethereum --cov-config=pyproject.toml --suppress-no-test-exit-code {posargs}\n    poetry run pytest -rfE plugins/aea-ledger-cosmos/tests --cov-report=html --cov-report=term-missing --cov=aea_ledger_cosmos --cov-config=pyproject.toml --suppress-no-test-exit-code {posargs}\n    poetry run pytest -rfE plugins/aea-cli-ipfs/tests --cov-report=html --cov-report=term-missing --cov=aea_cli_ipfs --cov-config=pyproject.toml --suppress-no-test-exit-code {posargs}\n\n[testenv:plugins-py3.8]\nbasepython = python3.8\ncommands = {[plugins]commands}\n\n[testenv:plugins-py3.9]\nbasepython = python3.9\ncommands = {[plugins]commands}\n\n[testenv:plugins-py3.10]\nbasepython = python3.10\ncommands = {[plugins]commands}\n\n[testenv:plugins-py3.8-cov]\nbasepython = python3.8\nusedevelop = True\ncommands = {[plugins]commands}\n\n[testenv:bandit]\nskipsdist = True\nskip_install = True\ncommands = \n    poetry run python ./install_packages.py bandit\n    make bandit\n\n[testenv:check_plugins_code_consistency]\nskipsdist = True\nskip_install = True\nallowlist_externals =\n    diff\ncommands = \n    make plugin-diffs\n\n[testenv:check_go_code_consistency]\nskipsdist = True\nskip_install = True\nallowlist_externals =\n    diff\ncommands = \n    make libp2p-diffs\n\n[testenv:black]\nskipsdist = True\nskip_install = True\ncommands = \n  poetry run python ./install_packages.py black\n  make black\n\n[testenv:black-check]\nskipsdist = True\nskip_install = True\ncommands = \n  poetry run python ./install_packages.py black\n  make black-check\n\n[testenv:isort]\nskipsdist = True\nskip_install = True\ncommands = \n  poetry run python ./install_packages.py isort\n  make isort\n\n[testenv:isort-check]\nskipsdist = True\nskip_install = True\ncommands = \n  poetry run python ./install_packages.py isort\n  make isort-check\n\n[testenv:copyright_check]\nskipsdist = True\nskip_install = True\ncommands = \n  python {toxinidir}/scripts/check_copyright_notice.py --directory {toxinidir}\n\n[testenv:hash_check]\nskipsdist = True\nusedevelop = True\ncommands = \n  poetry run python ./install_packages.py ipfshttpclient\n  poetry run python {toxinidir}/scripts/generate_ipfs_hashes.py --check {posargs}\n\n[testenv:package_version_checks]\nskipsdist = True\nusedevelop = True\ndeps =\ncommands = make check-package-versions-in-docs\n\n[testenv:package_dependencies_checks]\nskipsdist = True\nusedevelop = True\ndeps =\ncommands = make check-packages\n\n[testenv:docs]\nskipsdist = True\nskip_install = True\ncommands = \n  poetry install --only docs\n  make docs\n\n[testenv:docs-serve]\nskipsdist = True\nskip_install = True\ncommands = \n  poetry install --only docs\n  poetry run mkdocs serve -a localhost:8080\n\n[testenv:flake8]\nskipsdist = True\nskip_install = True\ncommands = \n  poetry run python ./install_packages.py \"flake8.*\" pydocstyle darglint\n  make flake8\n\n[testenv:liccheck]\nskipsdist = True\ncommands = \n  poetry install --only packages,main\n  poetry run python ./install_packages.py liccheck\n  make liccheck\n\n[testenv:mypy]\nskipsdist = True\nskip_install = True\ncommands = \n    poetry install --only packages,main,testing,types\n    poetry run python ./install_packages.py mypy\n    make mypy\n\n[testenv:pylint]\nskipsdist = True\ncommands =\n    poetry run python ./install_packages.py pylint pytest gitpython\n    # pytest gitpython installed for scripts and aea testing tools source code checks\n    poetry run python -m pip install --no-deps file://{toxinidir}/plugins/aea-ledger-ethereum\n    poetry run python -m pip install --no-deps file://{toxinidir}/plugins/aea-ledger-cosmos\n    poetry run python -m pip install --no-deps file://{toxinidir}/plugins/aea-ledger-fetchai\n    poetry run python -m pip install --no-deps file://{toxinidir}/plugins/aea-cli-ipfs\n    make pylint\n\n[testenv:safety]\nskipsdist = True\nskip_install = True\ncommands = \n    poetry run python ./install_packages.py safety\n    make safety\n\n[testenv:vulture]\nskipsdist = True\nskip_install = True\ncommands =\n    poetry run python ./install_packages.py vulture\n    make vulture\n\n[testenv:check-doc-links]\nskipsdist = True\nusedevelop = True\ndeps =\ncommands = make check-doc-links\n\n[testenv:check_api_docs]\nskipsdist = True\nusedevelop = True\ncommands =\n    poetry run python ./install_packages.py pydoc-markdown\n    poetry run {toxinidir}/scripts/generate_api_docs.py --check-clean\n\n[testenv:check_generate_all_protocols]\nskipsdist = True\nusedevelop = True\nsetenv =\n  PYTHONPATH = {toxinidir}\ncommands =\n    poetry run pip install .[all]\n    poetry run python ./install_packages.py black isort ipfshttpclient\n    poetry run ./scripts/generate_all_protocols.py --no-bump --check-clean\n\n[testenv:spell_check]\nskipsdist = True\nusedevelop = True\nallowlist_externals =\n    **/spell-check.sh\ndeps =\ncommands = {toxinidir}/scripts/spell-check.sh\n\n[testenv:dependencies_check]\nskipsdist = True\nskip_install = True\ncommands =\n\tpip install {toxinidir}[all]\n\tpip uninstall aea  -y\n\tpython {toxinidir}/scripts/check_imports_and_dependencies.py\n\n\n[testenv:plugins_env]\nskipsdist = True\nskip_install = True\npassenv = *\ndeps =\n\t.[all]\nallowlist_externals =\n    **/sh\ncommands =\n\t- /bin/sh -c \"rm -fr ./*private_key.txt\"\n\t{posargs}\n\t\n"
  },
  {
    "path": "user-image/Dockerfile",
    "content": "FROM ubuntu:18.04\n\nRUN apt-get update && apt-get upgrade -y\n\nRUN apt-get install sudo -y \n\nRUN adduser --disabled-password --gecos '' ubuntu\nRUN adduser ubuntu sudo\nRUN echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers\n\nRUN apt install -y python3 python3-pip\nRUN pip3 install --upgrade pip\n\n# utils\nRUN apt install -y wget \n\n# golang\nRUN wget https://dl.google.com/go/go1.13.8.linux-amd64.tar.gz && \\\n  tar -xzvf go1.13.8.linux-amd64.tar.gz -C /usr/local && \\\n  export PATH=$PATH:/usr/local/go/bin && echo 'export PATH=$PATH:/usr/local/go/bin' >> ~/.bashrc && \\\n  mkdir $HOME/go\n\nUSER ubuntu\n\nENV PATH=\"${PATH}:/usr/local/go/bin\"\nENV DEBIAN_FRONTEND noninteractive\nENV LC_ALL C.UTF-8\nENV LANG C.UTF-8\n\nRUN echo 'PATH=\"$(python3.6 -m site --user-base)/bin:${PATH}\"' >> ~/.bashrc\nRUN echo \"alias pip=pip3\" >> ~/.bashrc\n\nENTRYPOINT [ \"/bin/bash\"]\n\n"
  },
  {
    "path": "user-image/README.md",
    "content": "# Docker User image\n\nAll the commands must be executed from the parent directory, if not stated otherwise.\n\n## Build\n\nWe recommend using the following command for building:\n\n    ./user-image/scripts/docker-build-img.sh -t fetchai/aea-user:latest --\n\n## Publish\n\nFirst,\n\n    ./user-image/scripts/docker-publish-img.sh\n\nAnd then, in `docker-env.sh`, uncomment `DOCKER_IMAGE_TAG=fetchai/aea-user:latest` and comment the alternative line, then run the publish command again:\n\n    ./user-image/scripts/docker-publish-img.sh\n"
  },
  {
    "path": "user-image/docker-env.sh",
    "content": "#!/bin/bash\n\n# Swap the following lines if you want to work with 'latest'\nDOCKER_IMAGE_TAG=fetchai/aea-user:1.1.1\n# DOCKER_IMAGE_TAG=fetchai/aea-user:latest\n\nDOCKER_BUILD_CONTEXT_DIR=..\nDOCKERFILE=./Dockerfile\n"
  },
  {
    "path": "user-image/scripts/docker-build-img.sh",
    "content": "#!/bin/bash -e\n# Usage:\n#   ./docker-build-img.sh <IMMEDIATE_PARAMS> -- <TAIL_PARAMS>\n# Where:\n#  * resulting docker build commandline will be:\n#    docker build $IMMEDIATE_PARAMS -t $DOCKER_IMAGE_TAG $TAIL_PARAMS $DOCKER_BUILD_CONTEXT_DIR\n#  * DOCKER_IMAGE_TAG and DOCKER_BUILD_CONTEXT_DIR variables are defined in the `docker-env.sh` and/or `docker-env-common.sh`\n#\n# Examples:\n#  * the following example provides the `--cpus 4 --compress` parameters to `docker build` command as IMMEDIATE_PARAMS, **ommiting** the TAIL_PARAMS:\n#\n#    ./docker-build-img.sh --cpus 4 ---compress --\n#    # the the resulting docker process commandline will be:\n#    #   docker build --cpus 4 --compress -t $DOCKER_IMAGE_TAG $TAIL_PARAMS $DOCKER_BUILD_CONTEXT_DIR\n#\n#  * the following example provides the `--squash` parameters to `docker build` command as IMMEDIATE_PARAMS, and `../../` parameter as TAIL_PARAMS (what corresponds to the context directory, what also means that DOCKER_BUILD_CONTEXT_DIR variable needs to be unset or set to empty string in the `docker-env.sh`):\n#\n#    ./docker-build-img.sh --squash -- ../../\n#    # the the resulting docker process commandline will be:\n#    #   docker build --squash -t $DOCKER_IMAGE_TAG ../../ $DOCKER_BUILD_CONTEXT_DIR\n#    # the `DOCKER_BUILD_CONTEXT_DIR` shall be set to empty string in `docker-env.sh` file.\n# NOTE: For more details, please see description for the `split_params()` shell function in the `docker-common.sh` script.\n\nSCRIPTS_DIR=${0%/*}\n. \"$SCRIPTS_DIR\"/docker-env-common.sh\n\ndocker_build_callback() {\n    local IMMEDIATE_PARAMS=\"$1\"\n    local TAIL_PARAMS=\"$2\"\n\n    if [ -n \"${DOCKERFILE}\" ]; then\n        TAIL_PARAMS=\"-f $DOCKERFILE $TAIL_PARAMS\"\n    fi\n\n    local COMMAND=\"docker build $IMMEDIATE_PARAMS -t $DOCKER_IMAGE_TAG $TAIL_PARAMS $DOCKER_BUILD_CONTEXT_DIR\"\n\n    echo $COMMAND\n    $COMMAND\n}\n\nsplit_params docker_build_callback \"$@\"\n"
  },
  {
    "path": "user-image/scripts/docker-publish-img.sh",
    "content": "#!/bin/bash -e\n# NOTE: First docker needs to be authorized to push image to container registry.\n#       Normally this is done using 'docker login <registrey_url>', where the\n#       'registry_url' value is set in the $DOCKER_CONTAINER_REGISTRY environment\n#       variable which is defined in the 'docker-env-common.sh' script file.\n#       If you are using the Google cloud docker registry, please run the\n#       'gcloud auth configure-docker' instead.\n\nSCRIPTS_DIR=${0%/*}\n. \"$SCRIPTS_DIR\"/docker-env-common.sh\n\ndocker tag \"$DOCKER_IMAGE_TAG\" \"$REGISTRY_DOCKER_IMAGE_TAG\"\ndocker push \"$REGISTRY_DOCKER_IMAGE_TAG\"\n"
  }
]